From 72505ab8f3b71b8627133f742f5bf3de60e5f9f2 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 7 Aug 2010 22:07:17 -0700 Subject: [PATCH 001/400] moving to a new repository layout. step 1: shared folder. --- res/armor/chainmail.xml | 9 + res/armor/laenmail.xml | 9 + res/armor/laenshield.xml | 9 + res/armor/plate.xml | 10 + res/armor/rustychainmail.xml | 10 + res/armor/rustyshield.xml | 9 + res/armor/shield.xml | 9 + res/calendar.xml | 23 + res/common/armor.xml | 10 + res/common/buildings.xml | 171 + res/common/construction.xml | 10 + res/common/herbs.xml | 89 + res/common/items.xml | 156 + res/common/luxuries.xml | 26 + res/common/potions.xml | 197 + res/common/resources.xml | 15 + res/common/weapons.xml | 24 + res/de/strings.xml | 7482 +++++++++++++++++++++++++ res/en/strings.xml | 1680 ++++++ res/equipment.xml | 399 ++ res/fr/strings.xml | 2082 +++++++ res/messages.xml | 8518 +++++++++++++++++++++++++++++ res/prefixes.xml | 31 + res/resources/horse.xml | 11 + res/resources/hp.xml | 5 + res/resources/iron.xml | 12 + res/resources/laen.xml | 10 + res/resources/log.xml | 13 + res/resources/mallorn.xml | 13 + res/resources/mallornseed.xml | 6 + res/resources/peasant.xml | 5 + res/resources/seed.xml | 6 + res/resources/stone.xml | 11 + res/ships.xml | 83 + res/spells.xml | 204 + res/spoils.xml | 59 + res/terrains.xml | 84 + res/weapons/axe.xml | 14 + res/weapons/bow.xml | 13 + res/weapons/catapult.xml | 14 + res/weapons/crossbow.xml | 13 + res/weapons/firesword.xml | 10 + res/weapons/greatbow.xml | 18 + res/weapons/greatsword.xml | 13 + res/weapons/halberd.xml | 15 + res/weapons/laensword.xml | 12 + res/weapons/lance.xml | 13 + res/weapons/mallornbow.xml | 16 + res/weapons/mallorncrossbow.xml | 13 + res/weapons/mallornlance.xml | 13 + res/weapons/mallornspear.xml | 14 + res/weapons/rep_crossbow.xml | 16 + res/weapons/runesword.xml | 10 + res/weapons/rustyaxe.xml | 14 + res/weapons/rustygreatsword.xml | 12 + res/weapons/rustyhalberd.xml | 15 + res/weapons/rustysword.xml | 12 + res/weapons/spear.xml | 14 + res/weapons/sword.xml | 12 + scripts/callbacks.lua | 11 + scripts/default.lua | 121 + scripts/dumptable.lua | 95 + scripts/eventbus.lua | 0 scripts/gates.lua | 25 + scripts/init.lua | 43 + scripts/multis.lua | 101 + scripts/resources.lua | 89 + scripts/schema.sql | 6 + scripts/setup.lua | 16 + scripts/spells.lua | 151 + scripts/tests/common.lua | 643 +++ scripts/tests/spells.lua | 64 + src/attributes/aggressive.h | 33 + src/attributes/alliance.c | 34 + src/attributes/alliance.h | 31 + src/attributes/attributes.c | 81 + src/attributes/attributes.h | 31 + src/attributes/fleechance.c | 45 + src/attributes/fleechance.h | 33 + src/attributes/follow.c | 46 + src/attributes/follow.h | 35 + src/attributes/giveitem.c | 135 + src/attributes/giveitem.h | 36 + src/attributes/gm.c | 61 + src/attributes/gm.h | 36 + src/attributes/hate.c | 70 + src/attributes/hate.h | 35 + src/attributes/iceberg.c | 42 + src/attributes/iceberg.h | 33 + src/attributes/key.c | 59 + src/attributes/key.h | 35 + src/attributes/matmod.c | 40 + src/attributes/matmod.h | 37 + src/attributes/moved.c | 63 + src/attributes/moved.h | 37 + src/attributes/movement.c | 59 + src/attributes/movement.h | 33 + src/attributes/object.c | 267 + src/attributes/object.h | 38 + src/attributes/orcification.c | 40 + src/attributes/orcification.h | 28 + src/attributes/otherfaction.c | 80 + src/attributes/otherfaction.h | 33 + src/attributes/overrideroads.c | 29 + src/attributes/overrideroads.h | 31 + src/attributes/racename.c | 57 + src/attributes/racename.h | 37 + src/attributes/raceprefix.c | 60 + src/attributes/raceprefix.h | 33 + src/attributes/reduceproduction.c | 51 + src/attributes/reduceproduction.h | 32 + src/attributes/targetregion.c | 61 + src/attributes/targetregion.h | 34 + src/attributes/viewrange.c | 77 + src/attributes/viewrange.h | 35 + src/bindings/bind_attrib.c | 372 ++ src/bindings/bind_attrib.h | 24 + src/bindings/bind_building.c | 255 + src/bindings/bind_building.h | 23 + src/bindings/bind_faction.c | 561 ++ src/bindings/bind_faction.h | 24 + src/bindings/bind_gmtool.c | 266 + src/bindings/bind_gmtool.h | 10 + src/bindings/bind_hashtable.c | 187 + src/bindings/bind_hashtable.h | 24 + src/bindings/bind_message.c | 348 ++ src/bindings/bind_message.h | 22 + src/bindings/bind_region.c | 696 +++ src/bindings/bind_region.h | 23 + src/bindings/bind_ship.c | 182 + src/bindings/bind_ship.h | 23 + src/bindings/bind_sqlite.c | 100 + src/bindings/bind_storage.c | 144 + src/bindings/bind_storage.h | 22 + src/bindings/bind_unit.c | 1026 ++++ src/bindings/bind_unit.h | 26 + src/bindings/bindings.c | 1159 ++++ src/bindings/bindings.h | 27 + src/bindings/helpers.c | 664 +++ src/bindings/helpers.h | 23 + src/build/atoi36.c | 6 + src/build/external.c | 18 + src/build/gamecode.c | 80 + src/build/kernel.c | 53 + src/build/lib.c | 7 + src/build/stdafx.c | 1 + src/build/stdafx.h | 2 + src/build/util.c | 40 + src/eressea.c | 212 + src/eressea.h | 15 + src/gamecode.vcproj | 354 ++ src/gamecode.vcxproj | 141 + src/gamecode.vcxproj.filters | 131 + src/gamecode/archetype.c | 165 + src/gamecode/archetype.h | 51 + src/gamecode/creation.c | 73 + src/gamecode/creation.h | 30 + src/gamecode/creport.c | 1608 ++++++ src/gamecode/creport.h | 29 + src/gamecode/economy.c | 3463 ++++++++++++ src/gamecode/economy.h | 60 + src/gamecode/give.c | 438 ++ src/gamecode/give.h | 26 + src/gamecode/items.c | 263 + src/gamecode/items.h | 24 + src/gamecode/laws.c | 4223 ++++++++++++++ src/gamecode/laws.h | 47 + src/gamecode/laws_test.c | 148 + src/gamecode/market.c | 184 + src/gamecode/market.h | 25 + src/gamecode/market_test.c | 66 + src/gamecode/monster.c | 227 + src/gamecode/monster.h | 31 + src/gamecode/randenc.c | 1272 +++++ src/gamecode/randenc.h | 31 + src/gamecode/report.c | 2435 +++++++++ src/gamecode/report.h | 25 + src/gamecode/spy.c | 482 ++ src/gamecode/spy.h | 40 + src/gamecode/study.c | 793 +++ src/gamecode/study.h | 45 + src/gamecode/summary.c | 413 ++ src/gamecode/summary.h | 25 + src/gamecode/xmlreport.c | 748 +++ src/gamecode/xmlreport.h | 27 + src/gmtool.c | 1298 +++++ src/gmtool.h | 41 + src/gmtool.vcproj | 314 ++ src/gmtool_structs.h | 102 + src/items/artrewards.c | 157 + src/items/artrewards.h | 30 + src/items/demonseye.c | 64 + src/items/demonseye.h | 30 + src/items/itemtypes.c | 38 + src/items/itemtypes.h | 25 + src/items/phoenixcompass.c | 129 + src/items/phoenixcompass.h | 30 + src/items/seed.c | 100 + src/items/seed.h | 35 + src/items/speedsail.c | 73 + src/items/speedsail.h | 30 + src/items/studypotion.c | 58 + src/items/studypotion.h | 30 + src/items/weapons.c | 155 + src/items/weapons.h | 24 + src/items/xerewards.c | 91 + src/items/xerewards.h | 30 + src/kernel.vcproj | 948 ++++ src/kernel.vcxproj | 289 + src/kernel.vcxproj.filters | 598 ++ src/kernel/alchemy.c | 338 ++ src/kernel/alchemy.h | 70 + src/kernel/alliance.c | 548 ++ src/kernel/alliance.h | 68 + src/kernel/battle.c | 4371 +++++++++++++++ src/kernel/battle.h | 271 + src/kernel/binarystore.c | 291 + src/kernel/binarystore.h | 23 + src/kernel/build.c | 1350 +++++ src/kernel/build.h | 99 + src/kernel/building.c | 695 +++ src/kernel/building.h | 177 + src/kernel/calendar.c | 59 + src/kernel/calendar.h | 45 + src/kernel/command.c | 103 + src/kernel/command.h | 39 + src/kernel/config.c | 3275 +++++++++++ src/kernel/config.h | 460 ++ src/kernel/connection.c | 613 +++ src/kernel/connection.h | 141 + src/kernel/curse.c | 821 +++ src/kernel/curse.h | 330 ++ src/kernel/curse_test.c | 23 + src/kernel/equipment.c | 220 + src/kernel/equipment.h | 73 + src/kernel/faction.c | 507 ++ src/kernel/faction.h | 161 + src/kernel/group.c | 243 + src/kernel/group.h | 51 + src/kernel/item.c | 1185 ++++ src/kernel/item.h | 357 ++ src/kernel/magic.c | 2923 ++++++++++ src/kernel/magic.h | 395 ++ src/kernel/message.c | 283 + src/kernel/message.h | 61 + src/kernel/move.c | 2648 +++++++++ src/kernel/move.h | 71 + src/kernel/names.c | 483 ++ src/kernel/names.h | 37 + src/kernel/objtypes.h | 40 + src/kernel/order.c | 517 ++ src/kernel/order.h | 61 + src/kernel/pathfinder.c | 200 + src/kernel/pathfinder.h | 42 + src/kernel/plane.c | 326 ++ src/kernel/plane.h | 84 + src/kernel/player.c | 101 + src/kernel/player.h | 43 + src/kernel/pool.c | 262 + src/kernel/pool.h | 62 + src/kernel/race.c | 296 + src/kernel/race.h | 192 + src/kernel/region.c | 1608 ++++++ src/kernel/region.h | 300 + src/kernel/render.h | 28 + src/kernel/reports.c | 2186 ++++++++ src/kernel/reports.h | 140 + src/kernel/resources.c | 208 + src/kernel/resources.h | 63 + src/kernel/save.c | 1890 +++++++ src/kernel/save.h | 73 + src/kernel/ship.c | 338 ++ src/kernel/ship.h | 127 + src/kernel/skill.c | 315 ++ src/kernel/skill.h | 66 + src/kernel/spell.c | 184 + src/kernel/spell.h | 159 + src/kernel/spellid.h | 176 + src/kernel/sqlite.c | 257 + src/kernel/teleport.c | 228 + src/kernel/teleport.h | 41 + src/kernel/terrain.c | 158 + src/kernel/terrain.h | 83 + src/kernel/terrainid.h | 48 + src/kernel/textstore.c | 205 + src/kernel/textstore.h | 23 + src/kernel/types.h | 407 ++ src/kernel/unit.c | 1743 ++++++ src/kernel/unit.h | 237 + src/kernel/version.h | 71 + src/kernel/xmlkernel.h | 28 + src/kernel/xmlreader.c | 2180 ++++++++ src/kernel/xmlreader.h | 27 + src/lua-bindings.vcproj | 274 + src/lua-bindings.vcxproj | 125 + src/lua-bindings.vcxproj.filters | 95 + src/modules/arena.c | 527 ++ src/modules/arena.h | 39 + src/modules/autoseed.c | 1024 ++++ src/modules/autoseed.h | 50 + src/modules/dungeon.c | 268 + src/modules/dungeon.h | 36 + src/modules/gmcmd.c | 772 +++ src/modules/gmcmd.h | 48 + src/modules/museum.c | 396 ++ src/modules/museum.h | 53 + src/modules/oceannames.c | 126 + src/modules/oceannames.h | 32 + src/modules/score.c | 212 + src/modules/score.h | 36 + src/modules/weather.c | 141 + src/modules/weather.h | 54 + src/modules/wormhole.c | 221 + src/modules/wormhole.h | 31 + src/modules/xecmd.c | 111 + src/modules/xecmd.h | 27 + src/modules/xmas.c | 82 + src/modules/xmas.h | 29 + src/platform.h | 282 + src/settings.h | 63 + src/stdafx.h | 1 + src/tests.c | 127 + src/tests.h | 21 + src/triggers/changefaction.c | 114 + src/triggers/changefaction.h | 39 + src/triggers/changerace.c | 120 + src/triggers/changerace.h | 37 + src/triggers/clonedied.c | 95 + src/triggers/clonedied.h | 36 + src/triggers/createcurse.c | 157 + src/triggers/createcurse.h | 40 + src/triggers/createunit.c | 130 + src/triggers/createunit.h | 39 + src/triggers/gate.c | 117 + src/triggers/gate.h | 32 + src/triggers/giveitem.c | 124 + src/triggers/giveitem.h | 38 + src/triggers/killunit.c | 87 + src/triggers/killunit.h | 36 + src/triggers/removecurse.c | 114 + src/triggers/removecurse.h | 39 + src/triggers/shock.c | 148 + src/triggers/shock.h | 36 + src/triggers/timeout.c | 113 + src/triggers/timeout.h | 35 + src/triggers/triggers.c | 60 + src/triggers/triggers.h | 30 + src/triggers/unguard.c | 77 + src/triggers/unguard.h | 32 + src/triggers/unitmessage.c | 123 + src/triggers/unitmessage.h | 36 + src/util.vcproj | 418 ++ src/util.vcxproj | 159 + src/util.vcxproj.filters | 203 + src/util/argstack.c | 66 + src/util/argstack.h | 27 + src/util/attrib.c | 322 ++ src/util/attrib.h | 93 + src/util/base36.c | 115 + src/util/base36.h | 34 + src/util/base36_test.c | 27 + src/util/bsdstring.c | 88 + src/util/bsdstring.h | 23 + src/util/console.c | 247 + src/util/console.h | 37 + src/util/crmessage.c | 159 + src/util/crmessage.h | 39 + src/util/cvector.c | 97 + src/util/cvector.h | 61 + src/util/dice.c | 97 + src/util/event.c | 270 + src/util/event.h | 80 + src/util/eventbus.c | 56 + src/util/eventbus.h | 29 + src/util/filereader.c | 314 ++ src/util/filereader.h | 21 + src/util/functions.c | 74 + src/util/functions.h | 35 + src/util/goodies.c | 128 + src/util/goodies.h | 63 + src/util/graph.c | 203 + src/util/graph.h | 38 + src/util/language.c | 252 + src/util/language.h | 69 + src/util/language_struct.h | 28 + src/util/listbox.c | 191 + src/util/listbox.h | 16 + src/util/lists.c | 143 + src/util/lists.h | 55 + src/util/log.c | 288 + src/util/log.h | 45 + src/util/message.c | 237 + src/util/message.h | 71 + src/util/nrmessage.c | 174 + src/util/nrmessage.h | 56 + src/util/nrmessage_struct.h | 20 + src/util/parser.c | 195 + src/util/parser.h | 29 + src/util/patricia.c | 236 + src/util/patricia.h | 21 + src/util/rand.c | 72 + src/util/rand.h | 37 + src/util/resolve.c | 96 + src/util/resolve.h | 41 + src/util/rng.h | 45 + src/util/sql.c | 82 + src/util/sql.h | 35 + src/util/storage.h | 48 + src/util/strings.c | 132 + src/util/strncpy.c | 22 + src/util/translation.c | 488 ++ src/util/translation.h | 45 + src/util/umlaut.c | 160 + src/util/umlaut.h | 51 + src/util/unicode.c | 436 ++ src/util/unicode.h | 42 + src/util/variant.h | 24 + src/util/vmap.c | 146 + src/util/vmap.h | 47 + src/util/vset.c | 104 + src/util/vset.h | 43 + src/util/windir.c | 56 + src/util/windir.h | 50 + src/util/xml.c | 139 + src/util/xml.h | 36 + tools/atoi36.c | 35 + tools/gethash.c | 23 + tools/namegen.c | 218 + 428 files changed, 110511 insertions(+) create mode 100644 res/armor/chainmail.xml create mode 100644 res/armor/laenmail.xml create mode 100644 res/armor/laenshield.xml create mode 100644 res/armor/plate.xml create mode 100644 res/armor/rustychainmail.xml create mode 100644 res/armor/rustyshield.xml create mode 100644 res/armor/shield.xml create mode 100644 res/calendar.xml create mode 100644 res/common/armor.xml create mode 100644 res/common/buildings.xml create mode 100644 res/common/construction.xml create mode 100644 res/common/herbs.xml create mode 100644 res/common/items.xml create mode 100644 res/common/luxuries.xml create mode 100644 res/common/potions.xml create mode 100644 res/common/resources.xml create mode 100644 res/common/weapons.xml create mode 100644 res/de/strings.xml create mode 100644 res/en/strings.xml create mode 100644 res/equipment.xml create mode 100644 res/fr/strings.xml create mode 100644 res/messages.xml create mode 100644 res/prefixes.xml create mode 100644 res/resources/horse.xml create mode 100644 res/resources/hp.xml create mode 100644 res/resources/iron.xml create mode 100644 res/resources/laen.xml create mode 100644 res/resources/log.xml create mode 100644 res/resources/mallorn.xml create mode 100644 res/resources/mallornseed.xml create mode 100644 res/resources/peasant.xml create mode 100644 res/resources/seed.xml create mode 100644 res/resources/stone.xml create mode 100644 res/ships.xml create mode 100644 res/spells.xml create mode 100644 res/spoils.xml create mode 100644 res/terrains.xml create mode 100644 res/weapons/axe.xml create mode 100644 res/weapons/bow.xml create mode 100644 res/weapons/catapult.xml create mode 100644 res/weapons/crossbow.xml create mode 100644 res/weapons/firesword.xml create mode 100644 res/weapons/greatbow.xml create mode 100644 res/weapons/greatsword.xml create mode 100644 res/weapons/halberd.xml create mode 100644 res/weapons/laensword.xml create mode 100644 res/weapons/lance.xml create mode 100644 res/weapons/mallornbow.xml create mode 100644 res/weapons/mallorncrossbow.xml create mode 100644 res/weapons/mallornlance.xml create mode 100644 res/weapons/mallornspear.xml create mode 100644 res/weapons/rep_crossbow.xml create mode 100644 res/weapons/runesword.xml create mode 100644 res/weapons/rustyaxe.xml create mode 100644 res/weapons/rustygreatsword.xml create mode 100644 res/weapons/rustyhalberd.xml create mode 100644 res/weapons/rustysword.xml create mode 100644 res/weapons/spear.xml create mode 100644 res/weapons/sword.xml create mode 100644 scripts/callbacks.lua create mode 100644 scripts/default.lua create mode 100644 scripts/dumptable.lua create mode 100644 scripts/eventbus.lua create mode 100644 scripts/gates.lua create mode 100644 scripts/init.lua create mode 100644 scripts/multis.lua create mode 100644 scripts/resources.lua create mode 100644 scripts/schema.sql create mode 100644 scripts/setup.lua create mode 100644 scripts/spells.lua create mode 100644 scripts/tests/common.lua create mode 100644 scripts/tests/spells.lua create mode 100644 src/attributes/aggressive.h create mode 100644 src/attributes/alliance.c create mode 100644 src/attributes/alliance.h create mode 100644 src/attributes/attributes.c create mode 100644 src/attributes/attributes.h create mode 100644 src/attributes/fleechance.c create mode 100644 src/attributes/fleechance.h create mode 100644 src/attributes/follow.c create mode 100644 src/attributes/follow.h create mode 100644 src/attributes/giveitem.c create mode 100644 src/attributes/giveitem.h create mode 100644 src/attributes/gm.c create mode 100644 src/attributes/gm.h create mode 100644 src/attributes/hate.c create mode 100644 src/attributes/hate.h create mode 100644 src/attributes/iceberg.c create mode 100644 src/attributes/iceberg.h create mode 100644 src/attributes/key.c create mode 100644 src/attributes/key.h create mode 100644 src/attributes/matmod.c create mode 100644 src/attributes/matmod.h create mode 100644 src/attributes/moved.c create mode 100644 src/attributes/moved.h create mode 100644 src/attributes/movement.c create mode 100644 src/attributes/movement.h create mode 100644 src/attributes/object.c create mode 100644 src/attributes/object.h create mode 100644 src/attributes/orcification.c create mode 100644 src/attributes/orcification.h create mode 100644 src/attributes/otherfaction.c create mode 100644 src/attributes/otherfaction.h create mode 100644 src/attributes/overrideroads.c create mode 100644 src/attributes/overrideroads.h create mode 100644 src/attributes/racename.c create mode 100644 src/attributes/racename.h create mode 100644 src/attributes/raceprefix.c create mode 100644 src/attributes/raceprefix.h create mode 100644 src/attributes/reduceproduction.c create mode 100644 src/attributes/reduceproduction.h create mode 100644 src/attributes/targetregion.c create mode 100644 src/attributes/targetregion.h create mode 100644 src/attributes/viewrange.c create mode 100644 src/attributes/viewrange.h create mode 100644 src/bindings/bind_attrib.c create mode 100644 src/bindings/bind_attrib.h create mode 100644 src/bindings/bind_building.c create mode 100644 src/bindings/bind_building.h create mode 100644 src/bindings/bind_faction.c create mode 100644 src/bindings/bind_faction.h create mode 100644 src/bindings/bind_gmtool.c create mode 100644 src/bindings/bind_gmtool.h create mode 100644 src/bindings/bind_hashtable.c create mode 100644 src/bindings/bind_hashtable.h create mode 100644 src/bindings/bind_message.c create mode 100644 src/bindings/bind_message.h create mode 100644 src/bindings/bind_region.c create mode 100644 src/bindings/bind_region.h create mode 100644 src/bindings/bind_ship.c create mode 100644 src/bindings/bind_ship.h create mode 100644 src/bindings/bind_sqlite.c create mode 100644 src/bindings/bind_storage.c create mode 100644 src/bindings/bind_storage.h create mode 100644 src/bindings/bind_unit.c create mode 100644 src/bindings/bind_unit.h create mode 100644 src/bindings/bindings.c create mode 100644 src/bindings/bindings.h create mode 100644 src/bindings/helpers.c create mode 100644 src/bindings/helpers.h create mode 100644 src/build/atoi36.c create mode 100644 src/build/external.c create mode 100644 src/build/gamecode.c create mode 100644 src/build/kernel.c create mode 100644 src/build/lib.c create mode 100644 src/build/stdafx.c create mode 100644 src/build/stdafx.h create mode 100644 src/build/util.c create mode 100644 src/eressea.c create mode 100644 src/eressea.h create mode 100644 src/gamecode.vcproj create mode 100644 src/gamecode.vcxproj create mode 100644 src/gamecode.vcxproj.filters create mode 100644 src/gamecode/archetype.c create mode 100644 src/gamecode/archetype.h create mode 100644 src/gamecode/creation.c create mode 100644 src/gamecode/creation.h create mode 100644 src/gamecode/creport.c create mode 100644 src/gamecode/creport.h create mode 100644 src/gamecode/economy.c create mode 100644 src/gamecode/economy.h create mode 100644 src/gamecode/give.c create mode 100644 src/gamecode/give.h create mode 100644 src/gamecode/items.c create mode 100644 src/gamecode/items.h create mode 100644 src/gamecode/laws.c create mode 100644 src/gamecode/laws.h create mode 100644 src/gamecode/laws_test.c create mode 100644 src/gamecode/market.c create mode 100644 src/gamecode/market.h create mode 100644 src/gamecode/market_test.c create mode 100644 src/gamecode/monster.c create mode 100644 src/gamecode/monster.h create mode 100644 src/gamecode/randenc.c create mode 100644 src/gamecode/randenc.h create mode 100644 src/gamecode/report.c create mode 100644 src/gamecode/report.h create mode 100644 src/gamecode/spy.c create mode 100644 src/gamecode/spy.h create mode 100644 src/gamecode/study.c create mode 100644 src/gamecode/study.h create mode 100644 src/gamecode/summary.c create mode 100644 src/gamecode/summary.h create mode 100644 src/gamecode/xmlreport.c create mode 100644 src/gamecode/xmlreport.h create mode 100644 src/gmtool.c create mode 100644 src/gmtool.h create mode 100644 src/gmtool.vcproj create mode 100644 src/gmtool_structs.h create mode 100644 src/items/artrewards.c create mode 100644 src/items/artrewards.h create mode 100644 src/items/demonseye.c create mode 100644 src/items/demonseye.h create mode 100644 src/items/itemtypes.c create mode 100644 src/items/itemtypes.h create mode 100644 src/items/phoenixcompass.c create mode 100644 src/items/phoenixcompass.h create mode 100644 src/items/seed.c create mode 100644 src/items/seed.h create mode 100644 src/items/speedsail.c create mode 100644 src/items/speedsail.h create mode 100644 src/items/studypotion.c create mode 100644 src/items/studypotion.h create mode 100644 src/items/weapons.c create mode 100644 src/items/weapons.h create mode 100644 src/items/xerewards.c create mode 100644 src/items/xerewards.h create mode 100644 src/kernel.vcproj create mode 100644 src/kernel.vcxproj create mode 100644 src/kernel.vcxproj.filters create mode 100644 src/kernel/alchemy.c create mode 100644 src/kernel/alchemy.h create mode 100644 src/kernel/alliance.c create mode 100644 src/kernel/alliance.h create mode 100644 src/kernel/battle.c create mode 100644 src/kernel/battle.h create mode 100644 src/kernel/binarystore.c create mode 100644 src/kernel/binarystore.h create mode 100644 src/kernel/build.c create mode 100644 src/kernel/build.h create mode 100644 src/kernel/building.c create mode 100644 src/kernel/building.h create mode 100644 src/kernel/calendar.c create mode 100644 src/kernel/calendar.h create mode 100644 src/kernel/command.c create mode 100644 src/kernel/command.h create mode 100644 src/kernel/config.c create mode 100644 src/kernel/config.h create mode 100644 src/kernel/connection.c create mode 100644 src/kernel/connection.h create mode 100644 src/kernel/curse.c create mode 100644 src/kernel/curse.h create mode 100644 src/kernel/curse_test.c create mode 100644 src/kernel/equipment.c create mode 100644 src/kernel/equipment.h create mode 100644 src/kernel/faction.c create mode 100644 src/kernel/faction.h create mode 100644 src/kernel/group.c create mode 100644 src/kernel/group.h create mode 100644 src/kernel/item.c create mode 100644 src/kernel/item.h create mode 100644 src/kernel/magic.c create mode 100644 src/kernel/magic.h create mode 100644 src/kernel/message.c create mode 100644 src/kernel/message.h create mode 100644 src/kernel/move.c create mode 100644 src/kernel/move.h create mode 100644 src/kernel/names.c create mode 100644 src/kernel/names.h create mode 100644 src/kernel/objtypes.h create mode 100644 src/kernel/order.c create mode 100644 src/kernel/order.h create mode 100644 src/kernel/pathfinder.c create mode 100644 src/kernel/pathfinder.h create mode 100644 src/kernel/plane.c create mode 100644 src/kernel/plane.h create mode 100644 src/kernel/player.c create mode 100644 src/kernel/player.h create mode 100644 src/kernel/pool.c create mode 100644 src/kernel/pool.h create mode 100644 src/kernel/race.c create mode 100644 src/kernel/race.h create mode 100644 src/kernel/region.c create mode 100644 src/kernel/region.h create mode 100644 src/kernel/render.h create mode 100644 src/kernel/reports.c create mode 100644 src/kernel/reports.h create mode 100644 src/kernel/resources.c create mode 100644 src/kernel/resources.h create mode 100644 src/kernel/save.c create mode 100644 src/kernel/save.h create mode 100644 src/kernel/ship.c create mode 100644 src/kernel/ship.h create mode 100644 src/kernel/skill.c create mode 100644 src/kernel/skill.h create mode 100644 src/kernel/spell.c create mode 100644 src/kernel/spell.h create mode 100644 src/kernel/spellid.h create mode 100644 src/kernel/sqlite.c create mode 100644 src/kernel/teleport.c create mode 100644 src/kernel/teleport.h create mode 100644 src/kernel/terrain.c create mode 100644 src/kernel/terrain.h create mode 100644 src/kernel/terrainid.h create mode 100644 src/kernel/textstore.c create mode 100644 src/kernel/textstore.h create mode 100644 src/kernel/types.h create mode 100644 src/kernel/unit.c create mode 100644 src/kernel/unit.h create mode 100644 src/kernel/version.h create mode 100644 src/kernel/xmlkernel.h create mode 100644 src/kernel/xmlreader.c create mode 100644 src/kernel/xmlreader.h create mode 100644 src/lua-bindings.vcproj create mode 100644 src/lua-bindings.vcxproj create mode 100644 src/lua-bindings.vcxproj.filters create mode 100644 src/modules/arena.c create mode 100644 src/modules/arena.h create mode 100644 src/modules/autoseed.c create mode 100644 src/modules/autoseed.h create mode 100644 src/modules/dungeon.c create mode 100644 src/modules/dungeon.h create mode 100644 src/modules/gmcmd.c create mode 100644 src/modules/gmcmd.h create mode 100644 src/modules/museum.c create mode 100644 src/modules/museum.h create mode 100644 src/modules/oceannames.c create mode 100644 src/modules/oceannames.h create mode 100644 src/modules/score.c create mode 100644 src/modules/score.h create mode 100644 src/modules/weather.c create mode 100644 src/modules/weather.h create mode 100644 src/modules/wormhole.c create mode 100644 src/modules/wormhole.h create mode 100644 src/modules/xecmd.c create mode 100644 src/modules/xecmd.h create mode 100644 src/modules/xmas.c create mode 100644 src/modules/xmas.h create mode 100644 src/platform.h create mode 100644 src/settings.h create mode 100644 src/stdafx.h create mode 100644 src/tests.c create mode 100644 src/tests.h create mode 100644 src/triggers/changefaction.c create mode 100644 src/triggers/changefaction.h create mode 100644 src/triggers/changerace.c create mode 100644 src/triggers/changerace.h create mode 100644 src/triggers/clonedied.c create mode 100644 src/triggers/clonedied.h create mode 100644 src/triggers/createcurse.c create mode 100644 src/triggers/createcurse.h create mode 100644 src/triggers/createunit.c create mode 100644 src/triggers/createunit.h create mode 100644 src/triggers/gate.c create mode 100644 src/triggers/gate.h create mode 100644 src/triggers/giveitem.c create mode 100644 src/triggers/giveitem.h create mode 100644 src/triggers/killunit.c create mode 100644 src/triggers/killunit.h create mode 100644 src/triggers/removecurse.c create mode 100644 src/triggers/removecurse.h create mode 100644 src/triggers/shock.c create mode 100644 src/triggers/shock.h create mode 100644 src/triggers/timeout.c create mode 100644 src/triggers/timeout.h create mode 100644 src/triggers/triggers.c create mode 100644 src/triggers/triggers.h create mode 100644 src/triggers/unguard.c create mode 100644 src/triggers/unguard.h create mode 100644 src/triggers/unitmessage.c create mode 100644 src/triggers/unitmessage.h create mode 100644 src/util.vcproj create mode 100644 src/util.vcxproj create mode 100644 src/util.vcxproj.filters create mode 100644 src/util/argstack.c create mode 100644 src/util/argstack.h create mode 100644 src/util/attrib.c create mode 100644 src/util/attrib.h create mode 100644 src/util/base36.c create mode 100644 src/util/base36.h create mode 100644 src/util/base36_test.c create mode 100644 src/util/bsdstring.c create mode 100644 src/util/bsdstring.h create mode 100644 src/util/console.c create mode 100644 src/util/console.h create mode 100644 src/util/crmessage.c create mode 100644 src/util/crmessage.h create mode 100644 src/util/cvector.c create mode 100644 src/util/cvector.h create mode 100644 src/util/dice.c create mode 100644 src/util/event.c create mode 100644 src/util/event.h create mode 100644 src/util/eventbus.c create mode 100644 src/util/eventbus.h create mode 100644 src/util/filereader.c create mode 100644 src/util/filereader.h create mode 100644 src/util/functions.c create mode 100644 src/util/functions.h create mode 100644 src/util/goodies.c create mode 100644 src/util/goodies.h create mode 100644 src/util/graph.c create mode 100644 src/util/graph.h create mode 100644 src/util/language.c create mode 100644 src/util/language.h create mode 100644 src/util/language_struct.h create mode 100644 src/util/listbox.c create mode 100644 src/util/listbox.h create mode 100644 src/util/lists.c create mode 100644 src/util/lists.h create mode 100644 src/util/log.c create mode 100644 src/util/log.h create mode 100644 src/util/message.c create mode 100644 src/util/message.h create mode 100644 src/util/nrmessage.c create mode 100644 src/util/nrmessage.h create mode 100644 src/util/nrmessage_struct.h create mode 100644 src/util/parser.c create mode 100644 src/util/parser.h create mode 100644 src/util/patricia.c create mode 100644 src/util/patricia.h create mode 100644 src/util/rand.c create mode 100644 src/util/rand.h create mode 100644 src/util/resolve.c create mode 100644 src/util/resolve.h create mode 100644 src/util/rng.h create mode 100644 src/util/sql.c create mode 100644 src/util/sql.h create mode 100644 src/util/storage.h create mode 100644 src/util/strings.c create mode 100644 src/util/strncpy.c create mode 100644 src/util/translation.c create mode 100644 src/util/translation.h create mode 100644 src/util/umlaut.c create mode 100644 src/util/umlaut.h create mode 100644 src/util/unicode.c create mode 100644 src/util/unicode.h create mode 100644 src/util/variant.h create mode 100644 src/util/vmap.c create mode 100644 src/util/vmap.h create mode 100644 src/util/vset.c create mode 100644 src/util/vset.h create mode 100644 src/util/windir.c create mode 100644 src/util/windir.h create mode 100644 src/util/xml.c create mode 100644 src/util/xml.h create mode 100644 tools/atoi36.c create mode 100644 tools/gethash.c create mode 100644 tools/namegen.c diff --git a/res/armor/chainmail.xml b/res/armor/chainmail.xml new file mode 100644 index 000000000..81152f89e --- /dev/null +++ b/res/armor/chainmail.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/res/armor/laenmail.xml b/res/armor/laenmail.xml new file mode 100644 index 000000000..bdcf6b7e1 --- /dev/null +++ b/res/armor/laenmail.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/res/armor/laenshield.xml b/res/armor/laenshield.xml new file mode 100644 index 000000000..f5eb2d783 --- /dev/null +++ b/res/armor/laenshield.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/res/armor/plate.xml b/res/armor/plate.xml new file mode 100644 index 000000000..eb10f6359 --- /dev/null +++ b/res/armor/plate.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/res/armor/rustychainmail.xml b/res/armor/rustychainmail.xml new file mode 100644 index 000000000..a52b4db7b --- /dev/null +++ b/res/armor/rustychainmail.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/res/armor/rustyshield.xml b/res/armor/rustyshield.xml new file mode 100644 index 000000000..4c34f7ee1 --- /dev/null +++ b/res/armor/rustyshield.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/res/armor/shield.xml b/res/armor/shield.xml new file mode 100644 index 000000000..9a72baf9a --- /dev/null +++ b/res/armor/shield.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/res/calendar.xml b/res/calendar.xml new file mode 100644 index 000000000..42f83d58b --- /dev/null +++ b/res/calendar.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/common/armor.xml b/res/common/armor.xml new file mode 100644 index 000000000..58abae47f --- /dev/null +++ b/res/common/armor.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/res/common/buildings.xml b/res/common/buildings.xml new file mode 100644 index 000000000..5c52bfbb3 --- /dev/null +++ b/res/common/buildings.xml @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/common/construction.xml b/res/common/construction.xml new file mode 100644 index 000000000..95dcb6a33 --- /dev/null +++ b/res/common/construction.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/res/common/herbs.xml b/res/common/herbs.xml new file mode 100644 index 000000000..d7d0ef2e6 --- /dev/null +++ b/res/common/herbs.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/common/items.xml b/res/common/items.xml new file mode 100644 index 000000000..7c57a8184 --- /dev/null +++ b/res/common/items.xml @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/common/luxuries.xml b/res/common/luxuries.xml new file mode 100644 index 000000000..bdf9c110b --- /dev/null +++ b/res/common/luxuries.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/common/potions.xml b/res/common/potions.xml new file mode 100644 index 000000000..f444e5a94 --- /dev/null +++ b/res/common/potions.xml @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/common/resources.xml b/res/common/resources.xml new file mode 100644 index 000000000..bc39933e6 --- /dev/null +++ b/res/common/resources.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/res/common/weapons.xml b/res/common/weapons.xml new file mode 100644 index 000000000..e91b15e69 --- /dev/null +++ b/res/common/weapons.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/de/strings.xml b/res/de/strings.xml new file mode 100644 index 000000000..d3900f625 --- /dev/null +++ b/res/de/strings.xml @@ -0,0 +1,7482 @@ + + + + + Wirbel + vortex + remous + + + Ein Wirbel aus reinem Chaos zieht über die Region + A vortex of pure chaos energy pulls over the region + + + Wabernde grüne Schwaden treiben durch den Nebel und + verdichten sich zu einer unheimlichen Kreatur, die nur aus einem langen + Ruderschwanz und einem riesigen runden Maul zu bestehen scheint. + Wobbling green vapours drift through the mists to form an eldritch creature that seems to be entirely made up of huge jaws and a long tail. + + + + Keine Informationen über diese Rasse verfügbar. + No information available for this race. + + + Singdrachen sind von der Größe eines ausgewachsenden Tigers. Ihre Färbung reicht von schillerndem Rot, über dunkles Grün bis hin zu tiefem Schwarz. Alle bekannten Drachen dieser Art weisen eine hohe Intelligenz und ein hohes Maß an magischen Fähigkeiten auf. Wie Ihre großen Verwandten verfügen sie über einen Feuerodem. Sie lieben den Gesang und das üppige Mahl. Von Zeit zu Zeit gehen sie eine engen magisches Bund zu einem Magier ein. Wenn dies geschieht, so steht dem Magier ein äußerst loyaler und lohnender Vertrauter zur Seite. + + Song Dragons are roughly the size of a fully grown tiger. Their coloring ranges from bright red, through a dark green shade to a deep black. All known dragons of this species display a high level of intelligence and highly developed magical skills. Like their larger cousins, Song Dragons posess a firegland. They love singing and a good meal. From time to time one of these magnificent creatures will bond with a mage. When this happens, the mage is assured of a most loyal and useful familiar at his side. + + + Dieses mystische Wesen lebt bevorzugt in den tiefsten Wäldern und + vermag sich hervorragend vor den Augen anderer zu verbergen. Nur + selten schließt sich ein Einhorn einem Magier an, jedoch wenn das + geschieht ist es ein mächtiger Verbündeter, der auch über eigene Magie + verfügt. + + + Der Adler ist ein ausgezeichneter Späher, fliegend überquert er sogar + kurze Meerengen, doch ist er hoch oben am Himmel auch sehr exponiert, + was ihn beim Rasten zu einem leichten Ziel macht. + + + Der Luchs ist bekannt für seine Geschicklichkeit im Verbergen und + Beobachten. Mit ein wenig Geduld kann er zu einem hervorragenden + Späher ausgebildet werden. Im Kampf verteidigt er sich mit seinen + scharfen Krallen und weiß seine Gewandheit zu nutzen. + + + Diese großen Wölfe sind nicht alle so wild und böse wie in den + Legenden berichtet, und einige von ihnen schließen sich auch guten + Magiern bereitwillig an und sind ihnen dann treue Gefährten. + + + 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. + + + + + Das Horn eines Trolles. Kein Troll würde sich lebend davon trennen. + The horn of an adult troll. No troll would ever part with this while he's alive. + + + Beim Barte des Proheten! Ach nein, Zwergen. Irgendetwas riecht hier ranzig. + Sniff... Bleah. Don't they ever wash these? + + + Diese Amulett ist ein hervorragender Fokus für alle Heilzauber. Ein + mit diesem Fokus gewirkter Heilzauber wird mit größerer + Warscheinlichkeit Erfolgreich sein und doppelt so viele Leute heilen + können. + + + Der Kopf eines toten Drachens oder Wyrms. Man sagt, es ruhen magische Kräfte darin. + The head of a dead dragon or wyrm. They say that it has magical powers. + + + Munition für Katapulte. + Ammunition for catapults. + + + Ein Elfenpferd wird sich nur den wenigsten jemals anschließen. Hat es + jedoch seine Scheu überwunden ist es ein sehr wertvoller Gefährte. Ein + Elfenpferd ist schneller als ein Pferd. Zudem hilft es seinem Reiter + im Kampf und unterstützt ihn mit seiner Magie. Es sind schwarze + Elfenpferde bekannt, die sich sogar Orks angeschlossen haben. + + + Die rötlich glühende Klinge dieser furchterregenden magischen Waffe + ist mit dunklen Runen bedeckt. Nur die erfahrendsten Schwertkämpfer + vermögen ihre Kraft zu zähmen, doch in ihrer Hand vermag dem + Runenschwert nichts zu widerstehen - selbst magische Rüstungen + durchdringt es ohne Schwierigkeiten - und den Geist des Kämpfers füllt + es mit unterschütterlicher Zuversicht. + + + This enchanted dragon-eye has to be eaten by the leader of your forces + on the eve before battle. During the night he gains insight into the + dreams of the enemy leaders and may potentially glean a decisive + advantage. + Dieses verzauberte Drachenauge muß vor dem Abend einer Schlacht vom + Heerführer verzehrt werden. Während der Nacht wird er dann Einblick in + die Träume der feindlichen Heerführer erhalten und so möglicherweise + einen entscheidenden Vorteil im kommenden Gefecht erlangen. + + + This artifact grants its wearer the strength of a cavetroll. He will + be able to carry fifty times as much as normal and also in combat his + enhanced strength and tough troll skin will serve him well. + Dieses magische Artefakt verleiht seinem Träger die Stärke eines + ausgewachsenen Höhlentrolls. Seine Tragkraft erhöht sich auf das + 50fache und auch im Kampf werden sich die erhöhte Kraft und die + trollisch zähe Haut positiv auswirken. + + + It may look like just another quartz, but your magician will tell you + tha great power emenates from these crystals. Using it at the begining + of a week will release a strong negative energy that reduce the + power of all spells cast in the region during that week. + Für den ungeübten Betrachter mag der Antimagiekristall wie ein + gewöhnlicher Quarzkristall ausschauen, doch ein Magier spürt, das ihm + ganz besondere Kräfte innewohnen. Durch spezielle Rituale antimagisch + aufgeladen wird der Kristall, wenn er zu feinem Staub zermahlen und + verteilt wird, die beim Zaubern freigesetzten magischen Energien + aufsaugen und die Kraft aller Zauber reduzieren, welche in der betreffenden + Woche in der Region gezaubert werden. + + + A ring of power increases a magician's power. The level of all the + spells + he casts will be increased by one without increasing their costs. + Ein Ring der Macht verstärkt die Kraft des Magiers. Jeder Zauber wird, + ohne das sich die Kosten erhöhen, so gezaubert als hätte der Magier + eine Stufe mehr. + + + Herbs stored in this bag will be much better preserved. + Kräuter, die in diesem Beutelchen aufbewahrt werden, sind erheblich + besser konserviert. + + + This bag encloses a dimensional fold, which can store up to 200 + stones of weight without any extra burden on the bearer. Large items + such as horses or carts cannot be placed inside. + Dieser Beutel umschließt eine kleine Dimensionsfalte, in der bis + zu 200 Gewichtseinheiten transportiert werden können, ohne dass + sie auf das Traggewicht angerechnet werden. Pferde und andere + Lebewesen sowie besonders sperrige Dinge (Wagen und Katapulte) können + nicht in dem Beutel transportiert werden. Auch ist es nicht möglich, + einen Zauberbeutel in einem anderen zu transportieren. Der Beutel + selber wiegt 1 GE. + + + These leather boots are embroidere with unicorn hair and allow + their wearer to walk at twice his normal speed. + Diese aus Leder gefertigten und mit Einhornfell verzierten Stiefel + ermöglichen es ihrem Träger, sich mit der doppelten Geschwindigkeit + fortzubewegen, wenn er zu Fuß reist. + + + The flaming sword gives its bearer an attack of 3d6+10 plus + an additional fireball causing 2d6 damage to 1-10 victims. + Using a flaming sword requires a minimum skill of 7. It grants an + additional +1 to your skill and your resistance to magic will be + increased. + Ein Flammenschwert gibt dem Träger, der kein Magier sein muß, + zusätzlich zu seinem normalen Angriff (3d6+10) einen kleinen + Feuerballangriff, der bei 1-10 Opfern 2d6 magischen Schaden + verursacht. Um ein Flammenschwert führen zu können, muss man + mindestens Hiebwaffen 7 haben, dann verleiht es einem auch + einen zusätzlichen Kampfbonus von +1. Ein Flammenschwert + erhöht die Magieresistenz seines Trägers wie ein Laenschwert. + + + The magic in this ring makes the fingers ten times more nimble. a + craftsman can produce ten times his normal quota, and other abilities + might also be improved. + Der Zauber in diesem Ring bewirkt eine um das zehnfache verbesserte + Geschicklichkeit und Gewandheit der Finger. Handwerker können somit + das zehnfache produzieren, und bei einigen anderen Tätigkeiten könnte + dies ebenfalls von Nutzen sein. + + + This magical artifact has been used since ancient times by Elves to + conceal themselves from their enemies. Other races have also learned + the value of these rings after encountering Elves - after all the ring + makes its wearer invisible to normal eyes, and only magical methods + enable the wearer to be discovered. + Dieses magische Artefakt wurde seit Urzeiten von den Elfen benutzt, + auf der Jagd oder um sich vor Feinden zu verbergen. Doch auch andere + Rassen haben nach der Begegnung mit den Elfenvölkern den Wert des Rings + schnell schätzen gelernt - schließlich macht er den Träger für jedes + noch so scharfe Auge unsichtbar - nur mit magischen Mitteln ist der + Verborgene noch zu entdecken. + + + Das Amulett erlaubt es dem Träger, alle Einheiten, die durch einen + Ring der Unsichtbarkeit geschützt sind, zu sehen. Einheiten allerdings, + die sich mit ihrem Tarnungs-Talent verstecken, bleiben weiterhin + unentdeckt. Die Herstellung des Amulettes kostet 3000 Silber. + + + Dieser Tiegel enthält die seltenste alchemistische Substanz + Eresseas, den Krötenschleim. Angeblich soll der Krötenschleim eine + aussergewöhnlich hohe magische Absorbtionskraft besitzen und deswegen + in obskuren magischen Ritualen Verwendung finden. + + + Die Kröte ist eine der seltensten Rassen Eresseas. Man munkelt, + sie würde nur auf magische Weise entstehen. In einer uralten + Abhandlung über Magie aus der Bibliothek der Akademie von Xontormia + wird die Theorie aufgestellt, das die Kröte die ins morphische Feld + des Magiers übertragene Manifestation eines implodierten + Zauberfeldes sein könnte. Vieleicht deswegen ist die Kröte auch + gegen Zauber weitaus widerstandsfähiger als die normalen Rassen + Eresseas, leider aber auch weitaus unmagischer als diese. Die + Kröte kann schon aufgrund ihrer Größe und der fehlenden Hände + nur unter Schwierigkeiten normale Tätigkeiten ausüben. Der + einzige Vorteil ihrer geringen Größe ist, dass sie sich leichter + verstecken kann. + + + Dieses magische Szepter, ein Geschenk Igjarjuks, sorgt für große + Verwirrung und Gedächtnisverlust. Syntax: BENUTZE "Szepter der + Tränen" + + + Setzt eine Einheit dieses Segel auf einem Schiff, so erhöht + sich dessen Reichweite permanent um 1 Region. + A unit setting this sail on a ship temporarily will permanently + increase the ship's range by 1. + + + Im Mistelzweig ruht eine magische + Kraft der besonderer Art. Der Anwender wird von seinen + Feinden in Frieden gelassen, eine Woche lang läßt jeder + Kämpfer ihn unbeschadet seines Weges ziehen. + The magical misteltoe has a wonderous + property: It's use will make one person able to escape + unharmed from every conflict, no enemy will lay hand on + the bearer for one week. + + + + + + Kein Magiegebiet + no magic school + + + Illaun + Illaun + + + Tybied + Tybied + + + Cerddor + Cerddor + + + Gwyrrd + Gwyrrd + + + Draig + Draig + + + + + Tresen + counter + + + + wenige + few + + + + viele + many + + + + relativ viele + rather many + + + + sehr wenige + very few + + + + sehr viele + a great many + beaucoup de + + + + (trauernd) + (in mourning) + + + Beschreibung: + Description: + + + Art: + Type: + + + Komponenten: + Components: + + + Modifikationen: + Modifications: + + + Stufe: + Level: + + + Rang: + Rank: + + + Syntax: + Syntax: + + + + Geboten wird für + Traders can sell + + + und für + and + + + . + . + + + , für + , + + + + , im + , to the + + + und im + and to the + + + Einheit + Unit + + + Partei + Faction + + + hier_passwort_eintragen + insert_your_password_here + + + + Baum + tree + + + + Bäume + trees + + + + Mallornbaum + mallorn tree + + + + Mallornbäume + mallorn trees + + + + + + Nordwestküste + + + Nordostküste + + + Ostküste + + + Südostküste + + + Südwestküste + + + Westküste + + + + + AUSWERTUNG + + + COMPUTER + + + ZUGVORLAGE + + + SILBERPOOL + + + STATISTIK + + + DEBUG + + + ZIPPED + + + ZEITUNG + + + MATERIALPOOL + + + ADRESSEN + + + BZIP2 + + + PUNKTE + + + TALENTVERSCHIEBUNGEN + + + + + ein fliegender Teppich + + + ein Ballon + + + eine Karavelle + + + ein Boot + + + ein Langboot + + + ein Drachenschiff + + + eine Trireme + + + + fliegender Teppich + flying carpet + + + Ballon + + + Karavelle + + + Boot + + + Langboot + + + Drachenschiff + + + Trireme + + + + + Mahlstrom + + + Ozean + + + Ebene + + + Wald + + + Sumpf + + + Wüste + + + Hochland + + + Berge + + + Gletscher + + + Gletscher + + + Feuerwand + + + Vulkan + + + Nebel + + + Eisberg + + + Dichter Nebel + + + Ebene aus Feuer und Dunkelheit + + + Aktiver Vulkan + + + Halle + + + Gang + + + Wand + + + Magischer Sturm + + + + ein %s + + + %s + + + die Ebene von %s + + + der Wald von %s + + + der Sumpf von %s + + + die Wüste von %s + + + das Hochland von %s + + + das Bergland von %s + + + der Gletscher von %s + + + eine %s + + + der Vulkan von %s + + + ein %s + + + der Eisberg von %s + the glacier of %s + + + der Gletscher von %s + the glacier of %s + + + %s + + + eine %s + + + der Vulkan von %s + + + die %s + + + die %s + + + eine mächtige Mauer + + + ein %s + + + + Krater + + + Pforte + + + Kohlenstück + + + Kohlenstücke + + + + + Westen + + + Nordwesten + + + Nordosten + + + Osten + + + Südwesten + + + Südosten + + + + NW + + + NO + + + Ost + + + SO + + + SW + + + West + + + + + ein unbekanntes Gebäude + an unknown building + + + ein unbekannter zauber + an unknown spell + + + ein unbekanntes Schiff + an unknown ship + + + eine unbekannte Einheit + an unknown unit + + + einer unbekannten Einheit + an unknown unit + + + + + Ereignisse + + + Botschaften + + + Warnungen und Fehler + + + Wirtschaft und Handel + + + Rohstoffe und Produktion + + + Magie und Artefakte + + + Reisen und Bewegung + + + Lehren und Lernen + + + Kämpfe + + + Verschiedenes + + + Neue Zauber + + + Neue Tränke + New Potions + + + + + Burg + + + Leuchtturm + + + Wurmloch + wormhole + + + Bergwerk + + + Steinbruch + + + Hafen + + + Akademie + + + Magierturm + + + Schmiede + + + Sägewerk + + + Pferdezucht + + + Monument + + + Damm + + + Karawanserei + + + Tunnel + + + Taverne + + + Steinkreis + + + Gesegneter Steinkreis + + + Traumschlößchen + + + Struktur + + + Akademie der Künste + academy of arts + + + Skulptur + sculpture + + + + + Zauberstab + + + Zauberstäbe + + + + + Grundmauern + + + Handelsposten + + + Befestigung + + + Turm + + + Burg + + + Festung + + + Zitadelle + + + + + Pyramide + pyramid + + + Pyramide + pyramid + + + + + Sphäre der Unsichtbarkeit + sphere of invisibility + + + Sphären der Unsichtbarkeit + spheres of invisibility + + + Kraut + + + Kräuterbeutel + + + Kräuterbeutel + + + Phiole + + + Phiolen + + + Katapultmunition + ammunition + + + Katapultmunition + ammunition + + + Sonnensegel + solar sail + + + Sonnensegel + solar sails + + + Weihnachtsbaum + christmas tree + + + Weihnachtsbäume + christmas trees + + + Sternenstaub + stardust + + + Sternenstaub + stardust + + + Papyrus + papyrus + + + Papyri + papyri + + + Elfenohr + elven ear + + + Elfenohren + elven ears + + + Dämonenblut + demon blood + + + Dämonenblut + demon blood + + + Goblinkopf + goblin head + + + Goblinköpfe + goblinheads + + + Zwergenbart + dwarven beard + + + Zwergenbärte + dwarven beards + + + Halblingfuß + halfling foot + + + Halblingfüße + halfling feet + + + Menschenskalp + human scalp + + + Menschenskalpe + human scalps + + + Meermenschschuppe + aquarian scale + + + Meermenschschuppen + aquarian scales + + + Insektenfühler + insect antenna + + + Insektenfühler + insect antenna + + + Katzenschwanz + cat tail + + + Katzenschwänze + cat tails + + + Orkhauer + orc tusk + + + Orkhauer + orc tusks + + + Trollhorn + troll horn + + + Trollhörner + troll horns + + + Feder des Phönix + feather of the phoenix + + + Federn des Phönix + feathers of the phoenix + + + + + Silber + + + Silber + + + Trefferpunkt + + + Trefferpunkte + + + Aura + + + Aura + + + permanente Aura + + + permanente Aura + + + Bauer + + + Bauern + + + Einheit + + + Einheiten + + + Person + + + Personen + + + + + Runenschwert + + + Runenschwerter + + + Eisen + + + Eisen + + + Holz + + + Holz + + + Stein + + + Steine + + + Wagen + + + Wagen + + + Katapult + + + Katapulte + + + Schwert + + + Schwerter + + + Speer + + + Speere + + + Mallornspeer + + + Mallornspeere + + + Armbrust + + + Armbrüste + + + Mallornarmbrust + + + Mallornarmbrüste + + + Bogen + + + Bögen + + + Mallornbogen + + + Mallornbögen + + + + Kettenhemd + + + Kettenhemden + + + Schuppenpanzer + + + Schuppenpanzer + + + Plattenpanzer + + + Plattenpanzer + + + Balsam + + + Balsam + + + Gewürz + + + Gewürze + + + Juwel + + + Juwelen + + + Myrrhe + + + Myrrhe + + + Öl + + + Öl + + + Seide + + + Seide + + + Weihrauch + + + Weihrauch + + + Flammenschwert + + + Flammenschwerter + + + Bihänder + + + Bihänder + + + Kriegsaxt + axe + + + Kriegsäxte + axes + + + Elfenbogen + + + Elfenbögen + + + Laenschwert + + + Laenschwerter + + + Laenschild + + + Laenschilde + + + Laenkettenhemd + + + Laenkettenhemden + + + Laen + + + Laen + + + Schild + + + Schilde + + + Hellebarde + + + Hellebarden + + + Lanze + + + Lanzen + + + Mallornlanze + + + Mallornlanzen + + + Mallorn + + + Mallorn + + + Keks + + + Kekse + + + Apfel + + + Äpfel + + + Nuß + + + Nüsse + + + Mandelkern + + + Mandelkerne + + + Drachenblut + + + Drachenblut + + + Feenstiefel + + + Feenstiefel + + + Heiltrank + + + Heiltränke + + + Antimagiekristall + + + Antimagiekristalle + + + Tiegel mit Krötenschleim + + + Tiegel mit Krötenschleim + + + Amulett + + + Amulette + + + Amulett der Keuschheit + + + Amulette der Keuschheit + + + Amulett der Heilung + + + Amulette der Heilung + + + Amulett des Treffens + + + Amulette des Treffens + + + Amulett des wahren Sehens + + + Amulette des wahren Sehens + + + Katzenamulett + + + Katzenamulette + + + Ring der Unsichtbarkeit + + + Ringe der Unsichtbarkeit + + + Ring der Macht + + + Ringe der Macht + + + Ring der flinken Finger + + + Ringe der flinken Finger + + + Pferd + + + Pferde + + + Magischer Kräuterbeutel + + + Magische Kräuterbeutel + + + Silberbeutel + + + Silberkassette + + + Drachenhort + + + Drachenkopf + + + Drachenköpfe + + + Auge des Drachen + + + Augen des Drachen + + + Schartiges Schwert + + + Schartige Schwerter + + + Rostiger Schild + + + Rostige Schilde + + + Rostige Hellebarde + rusty halberd + + + Rostige Hellebarden + rusty halberds + + + Rostige Kriegsaxt + rusty axe + + + Rostige Kriegsäxte + rusty axes + + + Rostiger Zweihänder + rusty claymore + + + Rostige Zweihänder + rusty claymores + + + Rostiges Kettenhemd + + + Rostige Kettenhemden + + + Beutel des negativen Gewichts + + + Beutel des negativen Gewichts + + + Ring der Regeneration + + + Ringe der Regeneration + + + Amulett der Dunkelheit + + + Amulette der Dunkelheit + + + Zauberbeutel + + + Zauberbeutel + + + Traumauge + + + Traumaugen + + + Seeschlangenkopf + + + Seeschlangenköpfe + + + Aurafocus + + + Aurafocuse + + + Akkredition des Xontormia-Expreß + + + Akkreditionen des Xontormia-Expreß + + + Szepter der Tränen + wand of tears + + + Szepter der Tränen + wands of tears + + + Schneeball + snowball + + + Schneebälle + snowball + + + Schneemann + snowman + + + Schneemänner + snowmen + + + Gürtel der Trollstärke + + + Gürtel der Trollstärke + + + Elfenpferd + + + Elfenpferde + + + Pegasus + + + Pegasi + + + Delphin + + + Delphine + + + Eintrittskarte des Großen Museum + + + Eintrittskarten des Großen Museum + + + Rückkehrticket des Großen Museum + + + Rückkehrtickets des Großen Museum + + + Astralkristall + + + Astralkristalle + + + Talenttrunk + + + Talenttrünke + + + Same + + + Samen + + + Mallornsame + + + Mallornsamen + + + Feuerwerk + + + Feuerwerke + + + Lebkuchenherz mit der Aufschrift 'Erz und + Stein, das ist fein' + + + Lebkuchenherzen mit der Aufschrift 'Erz und + Stein, das ist fein' + + + Schlüssel + key + + + Schlüssel + keys + + + Achatener Schlüssel + agate key + + + Achatene Schlüssel + agate keys + + + Saphirner Schlüssel + sapphire key + + + Saphirne Schlüssel + sapphire keys + + + + + Flachwurz + + + Würziger Wagemut + + + Eulenauge + + + Grüner Spinnerich + + + Blauer Baumringel + + + Elfenlieb + + + Gurgelkraut + + + Knotiger Saugwurz + + + Blasenmorchel + + + Wasserfinder + + + Kakteenschwitz + + + Sandfäule + + + Windbeutel + + + Fjordwuchs + + + Alraune + + + Steinbeißer + + + Spaltwachs + + + Höhlenglimm + + + Eisblume + + + Weißer Wüterich + + + Schneekristall + + + + + Flachwurz + + + Würzige Wagemut + + + Eulenaugen + + + Grüne Spinneriche + + + Blaue Baumringel + + + Elfenlieb + + + Gurgelkräuter + + + Knotige Saugwurze + + + Blasenmorcheln + + + Wasserfinder + + + Kakteenschwitze + + + Sandfäulen + + + Windbeutel + + + Fjordwuchse + + + Alraunen + + + Steinbeißer + + + Spaltwachse + + + Höhlenglimme + + + Eisblumen + + + Weiße Wüteriche + + + Schneekristalle + + + + Siebenmeilentee + + + Goliathwasser + + + Wasser des Lebens + + + Schaffenstrunk + + + Wundsalbe + + + Bauernblut + + + Gehirnschmalz + + + Dumpfbackenbrot + + + Nestwärme + + + Pferdeglück + + + Berserkerblut + + + Bauernlieb + + + Trank der Wahrheit + + + Elixier der Macht + + + Heiltrank + + + + Siebenmeilentees + + + Goliathwasser + + + Wasser des Lebens + + + Schaffenstrünke + + + Wundsalben + + + Bauernblut + + + Gehirnschmalz + + + Dumpfbackenbrote + + + Nestwärme + + + Pferdeglück + + + Berserkerblut + + + Bauernlieb + + + Tränke der Wahrheit + + + Elixiere der Macht + + + Heiltränke + + + + + Gürtel der Heldentaten + + + Gürtel der Heldentaten + + + + + AGGRESSIV + + + JEDEM + + + ALLES + + + ANZAHL + + + AURA + + + BÄUME + + + BAUERN + + + BEISTAND + + + BEWACHEN + + + BURG + + + DEFENSIV + + + EINHEIT + + + ERESSEA + + + FLIEHE + + + FREMDES + + + GEBÄUDE + + + GEGENSTÄNDE + + + GIB + + + GNADE + + + HELFE + + + HINTEN + + + HINTER + + + KOMMANDO + + + KRÄUTER + + + DURCHREISE + TRAVEL + + + KÄMPFE + + + NICHT + + + NÄCHSTER + + + PARTEI + + + PARTEITARNUNG + + + PAUSE + + + PERSONEN + + + PRIVAT + + + REGION + + + SCHIFF + + + SILBER + + + STRAßEN + + + STUFE + + + TEMPORÄRE + + + TRÄNKE + + + UM + + + VOR + + + VORNE + + + ZAUBER + + + + XETRANK + XEPOTION + + + XEBALLON + XEBALLOON + + + XELAEN + XELAEN + + + + + Alchemie + + + Armbrustschießen + + + Ausdauer + + + Bergbau + + + Bogenschießen + + + Burgenbau + + + Handeln + + + Hiebwaffen + + + Holzfällen + + + Katapultbedienung + + + Kräuterkunde + + + Magie + + + Pferdedressur + + + Reiten + + + Rüstungsbau + + + Schiffbau + + + Segeln + + + Spionage + + + Stangenwaffen + + + Steinbau + + + Steuereintreiben + + + Straßenbau + + + Taktik + + + Tarnung + + + Unterhaltung + + + Waffenbau + + + Waffenloser Kampf + + + Wagenbau + + + Wahrnehmung + + + + + + // + + + BANNER + + + ARBEITEN + + + WARTEN + WAIT + + + ATTACKIEREN + + + BIETEN + + + BEANSPRUCHEN + CLAIM + + + BEKLAUEN + + + BELAGERE + + + BENENNEN + + + BENUTZEN + + + BESCHREIBEN + + + BETRETEN + + + BEWACHEN + + + BOTSCHAFT + + + ENDE + + + FAHREN + + + NUMMER + + + FRIEDEN + PEACE + + + KRIEG + WAR + + + FOLGEN + + + FORSCHEN + + + HELFEN + + + KÄMPFEN + + + KAMPFZAUBER + + + KAUFEN + + + KONTAKTIEREN + + + LEHREN + + + LERNEN + + + LIEFERE + + + MACHEN + + + NACH + + + XONTORMIA + XONTORMIA + + + ALLIANZ + ALLIANCE + + + BEFÖRDERUNG + PROMOTION + + + BEZAHLEN + PAY + + + PFLANZEN + + + PRÄFIX + + + SYNONYM + + + INFO + + + PASSWORT + + + REKRUTIEREN + + + RESERVIEREN + + + ROUTE + + + SABOTIEREN + + + OPTION + + + SPIONIEREN + + + STIRB + + + TARNEN + + + TRANSPORTIEREN + + + TREIBEN + + + UNTERHALTEN + + + VERKAUFEN + + + VERLASSEN + + + VERGESSEN + + + ZAUBERE + + + ZEIGEN + + + ZERSTÖREN + + + ZÜCHTEN + + + DEFAULT + + + REPORT + + + XML + XML + + + URSPRUNG + + + EMAIL + + + PIRATERIE + + + LOCALE + + + NEUSTART + + + GRUPPE + + + OPFERE + + + BETEN + + + SORTIEREN + + + JIHAD + + + GM + + + WERWESEN + + + + + Optionen + + + Stufe + + + Aktueller Status + + + Benötigte Kräuter + + + im Bau + + + beschädigt + + + Unglücklicherweise wurde deine Partei + ausgelöscht. Du kannst gerne an einer anderen Stelle wieder + einsteigen. Melde Dich einfach wieder an. + + + Talente + + + hat + + + Größe + + + Zauber + + + Kampfzauber + + + keiner + + + Liste aller Adressen + + + anonym + + + Angriff + + + Verteidigung + + + Rüstung + + + Schaden + + + + + Deine Partei hat letzte Runde keinen Zug + abgegeben! + + + + + Schneemann + snowman + + + Schneemänner + snowmen + + + Klon + clone + + + Klone + clones + + + Klonen + clones + + + Klonen + clone + + + + Schablone + template + + + Schablonen + templates + + + Schablonen + templates + + + Schablonen + template + + + + Gnom + gnome + + + Gnome + gnomes + + + Gnomen + gnomes + + + Gnomen + gnome + + + + Museumsgeist + museumghost + + + Museumsgeister + museumghosts + + + Museumsgeistern + museumghosts + + + Museumsgeister + museumghost + + + + Ghast + ghast + + + Ghaste + ghasts + + + Ghasten + ghasts + + + Ghast + ghast + + + + Ghoul + ghoul + + + Ghoule + ghouls + + + Ghoulen + ghouls + + + Ghoul + ghoul + + + + Juju-Zombie + juju-zombie + + + Juju-Zombies + juju-zombies + + + Juju-Zombies + juju-zombies + + + Juju-Zombie + juju-zombie + + + + Zombie + zombie + + + Zombies + zombies + + + Zombies + zombies + + + Zombie + zombie + + + + Skelettherr + skeleton lord + + + Skelettherren + skeleton lords + + + Skelettherren + skeleton lords + + + Skelettherren + skeleton lord + + + + Skelett + skeleton + + + Skelette + skeletons + + + Skeletten + skeletons + + + Skelett + skeleton + + + + Zentaur + centaur + + + Zentauren + centaurs + + + Zentauren + centaurs + + + Zentauren + centaur + + + + Schattenritter + shadow knight + + + Schattenritter + shadow knight + + + Schattenrittern + shadow knights + + + Schattenritter + shadow knight + + + + Seeschlange + sea serpent + + + Seeschlangen + sea serpents + + + Seeschlangen + sea serpents + + + Seeschlangen + sea serpent + + + + Krake + kraken + + + Kraken + krakens + + + Kraken + krakens + + + Kraken + kraken + + + + Riesenschildkröte + giant turtle + + + Riesenschildkröten + giant turtles + + + Riesenschildkröten + giant turtles + + + Riesenschildkröten + giant turtle + + + + Delphin + dolphin + + + Delphine + dolphins + + + Delphinen + dolphins + + + Delphin + dolphin + + + + Tiger + tiger + + + Tiger + tiger + + + Tigern + tigers + + + Tiger + tiger + + + + Höllenkatze + hellcat + + + Höllenkatzen + hellcats + + + Höllenkatzen + hellcats + + + Höllenkatzen + hellcat + + + + Eule + owl + + + Eulen + owls + + + Eulen + owls + + + Eulen + owl + + + + Fee + fairy + + + Feen + fairies + + + Feen + fairies + + + Feen + fairy + + + + Traumkatze + dreamcat + + + Traumkatzen + dreamcats + + + Traumkatzen + dreamcats + + + Traumkatzen + dreamcat + + + + Teufelchen + imp + + + Teufelchen + imps + + + Teufelchen + imps + + + Teufelchen- + imp + + + + Geist + ghost + + + Geister + ghosts + + + Geistern + ghosts + + + Geister + ghost + + + + Warg + direwolf + + + Warge + direwolves + + + Wargen + direwolves + + + Warg + direwolf + + + + Einhorn + unicorn + + + Einhörner + unicorns + + + Einhörnern + unicorns + + + Einhorn + unicorn + + + + Nymphe + nymph + + + Nymphen + nymphs + + + Nymphen + nymphs + + + Nymphen + nymph + + + + Singdrache + song dragon + + + Singdrachen + song dragons + + + Singdrachen + song dragons + + + Singdrachen + song dragon + + + + Ratte + rat + + + Ratten + rats + + + Ratten + rats + + + Ratten + rat + + + + Adler + eagle + + + Adler + eagles + + + Adlern + eagles + + + Adler + eagle + + + + Tunnelwurm + tunnelworm + + + Tunnelwürmer + tunnelworms + + + Tunnelwürmern + tunnelworms + + + Tunnelwurm + tunnelworm + + + + Luchs + lynx + + + Luchse + lynx + + + Luchsen + lynx + + + Luchs + lynx + + + + Wolf + wolf + + + Wölfe + wolves + + + Wölfen + wolves + + + Wolfs + wolf + + + + Bauer + peasant + + + Bauern + peasants + + + Bauern + peasants + + + Bauern + peasant + + + + Hirntöter + braineater + + + Hirntöter + braineaters + + + Hirntöter + braineaters + + + Hirntöter + braineater + + + + Schlumpf + smurf + + + Schlümpfe + smurfs + + + Schlumpf + smurf + + + Schlümpfen + smurfs + + + + Kröte + toad + + + Kröten + toads + + + Kröten + toads + + + Kröten + toad + + + + Alp + nightmare + + + Alps + nightmaress + + + Alps + nightmares + + + Alp + nightmare + + + + Bergwächter + mountainguard + + + Bergwächter + mountainguard + + + Bergwächtern + mountainguards + + + Bergwächter + mountainguard + + + + Schattenmeister + shadowmaster + + + Schattenmeister + shadowmaster + + + Schattenmeistern + shadowmasters + + + Schattenmeister + shadowmaster + + + + Schattendämon + shadowdemon + + + Schattendämonen + shadowdemons + + + Schattendämonen + shadowdemons + + + Schattendämon + shadowdemon + + + + Steingolem + stone golem + + + Steingolems + stone golems + + + Steingolems + stone golems + + + Steingolem + stone golem + + + + Eisengolem + irongolem + + + Eisengolems + irongolems + + + Eisengolems + irongolems + + + Eisengolem + irongolem + + + + Zauber + spell + + + Zauber + spell + + + Zauber + spell + + + Zauber + spell + + + + Spezial + special + + + Spezial + special + + + Spezial + special + + + Spezial + special + + + + Dracoid + dracoid + + + Dracoide + dracoids + + + Dracoiden + dracoids + + + Dracoiden + dracoid + + + + Katzendrache + catdragon + + + Katzendrachen + catdragons + + + Katzendrachen + catdragons + + + Katzendrachen + catdragon + + + + Ent + ent + + + Ents + ents + + + Ents + ents + + + Ent + ent + + + + Schattendrache + shadow dragon + + + Schattendrachen + shadow dragons + + + Schattendrachen + shadow dragons + + + Schattendrachen + shadow dragon + + + + Todesflatter + darkbat + + + Todesflattern + darkbats + + + Todesflattern + darkbats + + + Todesflatter + darkbat + + + + Alptraum + nightmare + + + Alpträume + nightmares + + + Alpträumen + nightmares + + + Alptraum + nightmare + + + + Nachteinhorn + vampiric unicorn + + + Nachteinhörner + vampiric unicorns + + + Nachteinhörnern + vampiric unicorns + + + Nachteinhorn + vampiric unicorn + + + + Wyrm + wyrm + + + Wyrme + wyrms + + + Wyrmen + wyrms + + + Wyrm + wyrm + + + + Drache + dragon + + + Drachen + dragons + + + Drachen + dragons + + + Drachen + dragon + + + + Jungdrache + young dragon + + + Jungdrachen + young dragons + + + Jungdrachen + young dragons + + + Jungdrachen + young dragon + + + + Phönix + phoenix + + + Phönixe + phoenixes + + + Phönixen + phoenixes + + + Phönix + phoenix + + + + Illusion + illusion + + + Illusionen + illusions + + + Illusions + illusions + + + Illusions + illusion + + + + Spinx + sphinx + + + Spinxen + sphinxs + + + Spinxen + sphinx + + + Spinx + sphinx + + + + kleiner Scarabäus + little scarab + + + kleine Scarabäen + little scarab + + + kleinen Scarabäen + little scarab + + + kleine Scarabäen + little scarab + + + + grüner Scarabäus + green scarab + + + grüne Scarabäen + green scarab + + + grünen Scarabäen + green scarab + + + grünen Scarabäen + green scarab + + + + blauer Scarabäus + blue scarab + + + blaue Scarabäen + blue scarabs + + + blauen Scarabäen + blue scarab + + + blaue Scarabäen + blue scarab + + + + roter Scarabäus + red scarab + + + rote Scarabäen + red scarabs + + + roten Scarabäen + red scarab + + + rote Scarabäen + red scarab + + + + Untoter Pharao + undead Pharaoh + + + Untoter Pharaonen + undead Pharaohs + + + Untoten Pharao + undead Pharaoh + + + Untote Pharaonen + undead Pharaoh + + + + Mumie + mummy + + + Mumien + mummys + + + Mumien + mummy + + + Mumien + mummy + + + + Untoter + undead + + + Untote + undead + + + Untoten + undead + + + Untoten + undead + + + + Apepschlange + apepsnake + + + Apepschlangen + apepsnakes + + + Apepschlangen + apepsnakes + + + Apepschlange + apepsnake + + + + Apophis + apophis + + + Apophis + apophis + + + Apophis + apophis + + + Apophis + apophis + + + + Meermensch + aquarian + + + Meermenschen + aquarians + + + Meermenschen + aquarians + + + Meermenschen + aquarian + + + + Katze + cat + + + Katzen + cats + + + Katzen + cats + + + Katzen + cats + + + + Halbling + halfling + + + Halblinge + halflings + + + Halblingen + halflings + + + Halblings + halfling + + + + Insekt + insect + + + Insekten + insects + + + Insekten + insects + + + Insekten + insect + + + + Dämon + demon + + + Dämonen + demons + + + Dämonen + demons + + + Dämonen + demon + + + + Troll + troll + + + Trolle + trolls + + + Trollen + trolls + + + Troll + troll + + + + Mensch + human + + + Menschen + humans + + + Menschen + humans + + + Menschen + human + + + + Goblin + goblin + + + Goblins + goblins + + + Goblins + goblins + + + Goblin + goblin + + + + Ork + orc + + + Orks + orcs + + + Orks + orcs + + + Ork + orc + + + + Snotling + snotling + + + Snotlinge + snotlings + + + Snotlingen + snotlings + + + Snotling + snotling + + + + Snotling + snotling + + + Snotlinge + snotlings + + + Snotlingen + snotlings + + + Snotling + snotling + + + + Elf + elf + + + Elfen + elves + + + Elfen + elves + + + Elfen + elves + + + + Zwerg + dwarf + + + Zwerge + dwarves + + + Zwergen + dwarves + + + Zwergen + dwarf + + + + + + sehr stark + critically wounded + + + stark + heavily wounded + + + schwer verwundet + badly wounded + + + verwundet + wounded + + + erschöpft + exhausted + + + + + For Seven Mile Tea, boil up a Cobalt Fungus and pour the resulting brew into a Windbag. Catch and filter the liquid that drips out and administer it. This tea allows up to ten men to move as fast as a horse. + Für den Siebenmeilentee koche man einen Blauen Baumringel auf und gieße dieses Gebräu in einen Windbeutel. Das heraustropfende Wasser fange man auf, filtere es und verabreiche es alsdann. Durch diesen Tee können bis zu zehn Menschen schnell wie ein Pferd laufen. + + + 'First roast the Gurgelkraut quickly and add some Fjordwuchs to spice it up. Let it all boil slowly until almost all liquid has evaporated. Leave the mash overnight and finally squeeze it the next morning until a thick fluid drips out.' The liquid thus produced, 'Goliath Water' as we call it, is enough for 10 men and gives each man the carrying capacity of a horse for one week. + Zuerst brate man das Gurgelkraut leicht an und würze das Zeug mit ein wenig Fjordwuchs. Man lasse alles so lange kochen, bis fast alle Flüssigkeit verdampft ist. Diesen Brei stelle man über Nacht raus. Am nächsten Morgen presse man den Brei aus. Die so gewonnene Flüssigkeit, Goliathwasser genannt, verleiht bis zu zehn Männern die Tragkraft eines Pferdes. + + + The "Water of Life" allows living trees to be created from logs. A Knotroot and Elvendear are heated until one can just still keep one's finger in. This is then poured into a jar and allowed to cool slowly. The extract is sufficient for 10 pieces of wood. + Das 'Wasser des Lebens' ist in der Lage, aus gefällten Baumstämmen wieder lebende Bäume zu machen. Dazu wird ein knotiger Saugwurz zusammen mit einem Elfenlieb erwärmt, so daß man gerade noch den Finger reinhalten kann. Dies gieße man in ein Gefäß und lasse es langsam abkühlen. Der Extrakt reicht für 10 Holzstämme. + + + Allow a Tangy Temerity to simmer for three hours in a litre of water, then add a grated Mandrake, and sprinkle in a Gapgrowth harvested at full moon. The whole brew should then be allowed to stew for three days in a warm place. This potion increases the strength and endurance of ten men so that they can achieve twice as much in a week. + Man lasse einen Würzigen Wagemut drei Stunden lang in einem Liter Wasser köcheln. Dann gebe man eine geriebene Alraune dazu und bestreue das ganze mit bei Vollmond geerntetem Spaltwachs. Nun lasse man den Sud drei Tage an einem dunklen und warmen Ort ziehen und seie dann die Flüssigkeit ab. Dieser Schaffenstrunk erhöht die Kraft und Ausdauer von zehn Männern, so daß sie doppelt soviel schaffen können wie sonst. + + + When one is severely wounded after a hard battle it is advisable to have some Ointment to hand. Applied to wounds, this magical paste closes them in the blink of an eye. For the preparation the alchemist requires a cobalt fungus, tangy temerity, and white hemlock. A dose of the potion heals up to 400 hitpoints. + Ist man nach einem einem harten Kampf schwer verwundet, ist es ratsam, etwas Wundsalbe parat zu haben. Streicht man diese magische Paste auf die Wunden, schließen sich diese augenblicklich. Für die Herstellung benötigt der Alchemist nebst einem Blauen Baumringel einen Würzigen Wagemut und einen Weißen Wüterich. Eine solche Portion heilt bis zu 400 Lebenspunkte. + + + Knowledge of this potion is amongst the most dangerous and secret wisdom of the alchemist. Snatched from the darkest hells, the knowledge of this formula enables the production of an elixer which serves Demons as nourishment. If used by normal beings it leads to a swift death and eternal undeath. The creation requires Fjord Fungus together with some Cave Lichen and Cobalt Fungus, and an unfortunate peasant from the region, who is killed in the bloody days-long ritual. One vial of the potion satisfies the hunger of 100 Demons for a week. + Zu den gefährlichsten und geheimsten Wissen der Alchemisten zählt die Kenntnis um diesen Trank. Den finstersten Höllen entrissen, ermöglicht die Kenntnis dieser Formel die Herstellung eines Elixiers, welches Dämonen als Nahrung dient. Von normalen Lebewesen eingenommen, führt es zu schnellem Tod und ewigen Nichtleben. Die Herstellung benötigt nebst Fjordwuchs, etwas Höhlenglimm und einem Blauen Baumringel auch einen Bauern aus der Region, welcher in einem tagelangen blutigen Ritual getötet wird. Ein Fläschchen des Tranks kann den Hunger von 100 Dämonen für eine Woche stillen. + + + To create the brain wax potion, mix the juice of a waterfinder with quite a bit of grated windbag and a pinch of bugleweed. Let this steep for just a minute. When the liquid is only lukewarm, add some rock weed. Using a large spoon, stirr exactly seven times clockwise and then seven times counterclockwise. Fill the vial when the liquid has gone still. The juice gives ten people a 33% chance of an additional attempt at learning a skill. + Für das Gehirnschmalz verrühre man den Saft eines Wasserfinders mit recht viel geriebenem Windbeutel und ein wenig Gurgelkraut. Dies lasse man kurz aufwallen. Wenn die Flüssigkeit nur noch handwarm ist, gebe man etwas Steinbeißer dazu. Das ganze muß genau siebenmal rechtsherum und siebenmal linksherum mit einem großen Löffel gerührt werden. Wenn keine Bewegung mehr zu erkennen ist, fülle man den Saft ab. Der Saft gibt mit einer Chance von 1/3 bis zu zehn Personen einen zusätzlichen Lernversuch. + + + A duncebun is a nasty piece of work, negating any attempt at learning a skill, or even causing the subject to forget things! For ten servings knead a rasped fjord fungus, an abraded owlsgaze and a finely sliced spider ivy to a smooth dough. Bake for an hour at moderate heat and brush the result with some cave lichen. Who eats this bread will not learn what he's attempting to learn, and, in case there is no attempt to learn anything, will forget a week's worth of study in his best skill. + Das Dumpfbackenbrot ist eine sehr gemeine Sache, macht es doch jeden Lernerfolg zunichte oder läßt einen gar Dinge vergessen! Für zehn Portionen verknete man einen geriebenen Fjordwuchs, einen zerstoßenes Eulenauge und einen kleingeschnittenen Grünen Spinnerich zu einem geschmeidigen Teig. Diesen backe man eine Stunde lang bei guter Hitze und bestreiche das Ergebnis mit etwas Höhlenglimm. Wer dieses Brot gegessen hat, kann eine Woche lang nichts lernen, und so er nichts zu lernen versucht, wird er gar eine Woche seiner besten Fähigkeit vergessen. + + + A potion of nest warmth allows an insect to recruit outside of a desert region in winter. The learned alchemist prepares this by taking a peyote, mixing it with a portion of gapgrowth which has been gathered during a clear, starry night. To dispell winter, add some blossoms of the ice begonia in the mix, and stirr everything together with a spider ivy until it turns a nice shade of violet. One vial supplies an entire region for a whole week. + Nestwärme erlaubt es einem Insekt, im Winter außerhalb von Wüsten neue Rekruten anzuwerben. Zur Zubereitung nimmt der geübte Alchemist einen Kakteenschwitz, vermischt ihn mit einer Portion Spaltwachs, die in einer sternklaren Nacht gesammelt wurde, gibt zur Vertreibung des Winters einige Blütenblätter der Eisblume in den Sud, und rührt alles mit einem grünen Spinnerich bis es eine violette Farbe annimmt. Ein Trank reicht eine Woche lang für eine ganze Region. + + + To make a horsepower potion, chop a peyote, a cobalt fungus and some knotroot, and boil it in a bucketful of water. Then add some sand reeker and let the mixture steep for three days. Finally one gives this to the horses to drink, to double their procreation. + Für das Pferdeglück zerhacke man einen Kakteenschwitz, einen blauen Baumringel und etwas knotigen Saugwurz und koche das ganze mit einem Eimer Wasser auf. Dann füge man etwas Sandfäule dazu und lasse diesen Sud drei Tage lang ziehen. Letztlich gebe man es den Pferden zu trinken, auf daß sie sich doppelt so schnell vermehren. + + + The use of the berserkers blood potion is advised to increase one's warriors abilities to new heights. To create this, one needs a white hemlock, some flatroot, sand reeker and a mandrake. All ingredients have to be sliced as finely as possible, after which it is boiled for two hours. The cooled brew is strained through a cloth. The resulting juice is enough to improve up to ten warriors. + Will man seine Krieger zu Höchstleistungen antreiben, sei das Berserkerblut empfohlen. Um es herzustellen, braucht man einen Weißen Wüterich, etwas Flachwurz, Sandfäule und eine Alraune. Alle Zutaten müssen möglichst klein geschnitten und anschließend zwei Stunden lang gekocht werden. Den abgekühlten Brei gebe man in ein Tuch und presse ihn aus. Der so gewonnene Saft reicht aus, um zehn Kämpfer besser angreifen zu lassen. + + + The peasant love potion enamors both Man and Woman to the same degree and results in a strong wish for children. For a big portion scoop out a mandrake, fill it with finely chopped bubblemorel, elvendear and snowcrystal petal, sprinkle grated rock weed on top and let it simmer on low heat for twenty hours. The potion can grant up to 1000 peasants the happiness of twins. + Das Bauernlieb betört Mann und Frau gleichwohl und läßt in ihnen den Wunsch nach Kindern anwachsen. Für eine große Portion höhle man eine Alraune aus, gebe kleingehackten Blasenmorchel, Elfenlieb und Schneekristall dazu, streue ein wenig geriebenen Steinbeißer darüber und lasse dieses zwanzig Stunden lang auf kleiner Flamme kochen. Bis zu 1000 Bauern vermag der Trank das Glück von Zwillinge zu bescheren. + + + This simple but very potent brew sharpens the senses of anyone that drinks of it and makes him able to see through even the most complex illusions for one week. + Dieses wirkungsvolle einfache Gebräu schärft die Sinne des Trinkenden derart, daß er in der Lage ist, eine Woche lang auch die komplexesten Illusionen zu durchschauen. + + + One of the most rare and prized of all alchemist elixers, this potion grants the user a dragon's power for a few weeks. The potion increases the life-energy of a maximum of ten people fivefold. The effect is strongest right after drinking and slowly decreases over time. To brew this potion the alchemist needs an elvendear, a windbag, a piece of waterfinder and a spider ivy. Finally he dusts it with some minced bubblemorel and stirrs the powder into some dragon's blood. + Eines der seltensten und wertvollsten alchemistischen Elixiere, verleiht dieser Trank dem Anwender für einige Wochen die Kraft eines Drachen. Der Trank erhöht die Lebensenergie von maximal zehn Personen auf das fünffache. Die Wirkung ist direkt nach der Einnahme am stärksten und klingt danach langsam ab. Zur Herstellung benötigt der Alchemist ein Elfenlieb, einen Windbeutel, ein Stück Wasserfinder und einen Grünen Spinnerich. Über dieses Mischung streue er schließlich einen zerriebenen Blasenmorchel und rühre dieses Pulver unter etwas Drachenblut. + + + For a healing potion one takes the peel of a windbag and some bugleweed, stirr in some chopped elvendear and sprinkle it with the blossoms of an ice begonia. This has to cook through for four days, while a gapgrowth has to be added on the second day. Then one carefully scoops off the top layer of liquid. One such potion gives four men (or one man four times) a 50% chance to survive otherwise lethal wounds. The potion is automatically used in case of injury. + Für einen Heiltrank nehme man die Schale eines Windbeutels und etwas Gurgelkraut, rühre eine kleingehacktes Elfenlieb dazu und bestreue alles mit den Blüten einer Eisblume. Dies muß vier Tage lang gären, wobei man am zweiten Tag einen Spaltwachs dazutun muß. Dann ziehe man vorsichtig den oben schwimmenden Saft ab. Ein solcher Trank gibt vier Männern (oder einem Mann vier mal) im Kampf eine Chance von 50%, sonst tödliche Wunden zu überleben. Der Trank wird von ihnen automatisch bei Verletzung angewandt. + + + + + Erschaffe einen Ring der Macht + Create A Ring Of Power + + + Schild des Fisches + Shield Of The Fish + + + Runen des Schutzes + Protective Runes + + + Ruf der Realität + Call Of Reality + + + Astraler Ruf + Astral Call + + + Magiefresser + Destroy Magic + + + Mauern der Ewigkeit + Eternal Walls + + + Stehle Aura + Steal Aura + + + Schutzzauber + Resist Magic + + + Astraler Blick + Astral Gaze + + + Auratransfer + Transfer Aura + + + Monster friedlich stimmen + Calm Monster + + + Luftschiff + Airship + + + Lied der Verführung + Song Of Seduction + + + Schaler Wein + Hangover + + + Aushorchen + sound_out + + + Kriegsgesang + Song Of War + + + Gesang der Angst + Song Of Fear + + + Lied des Ortes analysieren + Analysis + + + Schockwelle + Shockwave + + + Fluch brechen + Negate Curse + + + Erschaffe ein Amulett der Keuschheit + Create An Amulet Of Chastity + + + Beschleunigung + Acceleration + + + Großer Drachenodem + Powerful Dragonbreath + + + Opfere Kraft + Sacrifice Strength + + + Belebtes Gestein + Living Rock + + + Gesang der Melancholie + Song of Melancholy + + + Gesang des wachen Geistes + Song Of The Youthful Spirit + + + Gesang des schwachen Geistes + Song Of The Aging Spirit + + + Gesang der Friedfertigkeit + Song Of Peace + + + Gesang der Versklavung + Song Of Slavery + + + Hohe Kunst der Überzeugung + Song Of Slavery + + + Zeitdehnung + Double Time + + + Vertrauten rufen + Summon Familiar + + + Rüstschild + Shield Shine + + + Wyrmtransformation + Wyrmtransformation + + + Schattenodem + Shadowbreath + + + Feuersturm + Firestorm + + + Feuerwalze + Immolation + + + Eisnebel + Coldfront + + + Säurenebel + Acid Rain + + + Furchteinflößende Aura + Panic + + + Meteorregen + Meteor Shower + + + Schattenruf + Shadow Call + + + Erschaffe einen Ring der Regeneration + Create A Ring Of Regeneration + + + Mob aufwiegeln + Mob Rule + + + Aufruhr beschwichtigen + Calm Riot + + + Aufruhr verursachen + Riot + + + Blick in die Realität + Gaze Upon Reality + + + Störe Astrale Integrität + Astral Disruption + + + Eisiger Drachenodem + Icy Dragonbreath + + + Eisiger Drachenodem + Icy Dragonbreath + + + Erschaffe ein Runenschwert + Create A Runesword + + + Erschaffe einen Beutel des Negativen Gewichts + Create A Bag Of Holding + + + Erschaffe einen Aurafocus + Create An Aurafocus + + + Erschaffe Antimagiekristall + Create An Antimagic Crystal + + + Astrale Schwächezone + Antimagic + + + Astraler Ausgang + Astral Exit + + + Astraler Weg + Astral Path + + + Beute Bewahren + Save Spoils + + + Schutz vor Magie + Protection from Magic + + + Wunderdoktor + Miracle Doctor + + + Schleieraura + Concealing Aura + + + Magie analysieren + Analyze Magic + + + Hohes Lied der Gaukelei + Song of Generosity + + + Gesang des Werbens + Song of Courting + + + Schleieraura + Veil + + + Lied der Heilung + Blessed Harvest + + + Gesang der Furcht + Song of Terror + + + Segen der Erde + Blessed Harvest + + + Heldengesang + Epic Heroes + + + Gesang des Lebens analysieren + Analyze Song of Life + + + Bannlied + Countersong + + + Gesang des Auratransfers + Hymn of Aura Sharing + + + Gesang der Verwirrung + Song of Confusion + + + Plappermaul + Blabbermouth + + + Regentanz + Rain Dance + + + Gaukeleien + Jugglery + + + Friedenslied + Appeasing Song + + + Viehheilung + Cattle Healing + + + Erschaffe Steingolems + Create Stone Golems + + + Erschaffe Eisengolems + Create Iron Golems + + + Hainzauber + Grove Of Oak Trees + + + Rostregen + Rain Of Rust + + + Firuns Fell + Firun's Coat + + + Hagel + Hail + + + Seelenkopie + Doppelganger + + + Irrlichter + Wisps + + + Schlechte Träume + Bad Dreams + + + Bergwächter + Mountain Guardian + + + Magischer Pfad + Magic Path + + + Tor in die Ebene der Hitze + Great Drought + + + Wurzeln der Magie + Roots Of Magic + + + Mahlstrom + Maelstrom + + + Windschild + Air Shield + + + Segne Mallornstecken + Bless Mallorn Logs + + + Beschwörung eines + Wasserelementares + Summon Water Elemental + + + Heilung + Heal + + + Wirbelwind + Whirlwind + + + Astralschutzgeister + Astral Guardian Spirits + + + Meditation + Meditate + + + Beschwöre einen Erdelementar + Summon Earth Elemental + + + Beschwöre einen Sturmelementar + Summon Storm Elemental + + + Erschaffe ein Amulett des wahren + Sehens + Create An Amulet Of True Sight + + + Erschaffe einen Ring der + Unsichtbarkeit + Create A Ring Of Invisibility + + + Miriams flinke Finger + Quick Fingers + + + Heimstein + Homestone + + + Wolfsgeheul + Timber Wolves + + + Blick des Basilisken + Gaze Of The Basilisk + + + Starkes Tor und feste Mauer + Strong Wall And Sturdy Gate + + + Geister bannen + Banish Spirits + + + Lebenslied festigen + Silence Dissonance + + + Ritual der Aufnahme + Rit of Acceptance + + + Weg der Bäume + Path Of Trees + + + Sog des Lebens + Ties Of Life + + + Heiliger Boden + Sacred Ground + + + Erschaffe einen magischen + Kräuterbeutel + Create A Magical Herb Pouch + + + Erwecke Ents + Awakening Of The Ents + + + Vertrauten binden + Bind Familiar + + + Segne Steinkreis + Bless Stone Circle + + + Rindenhaut + Barkskin + + + Verwünschung + Hex + + + Kleine Flüche + Minor Curses + + + Feuerball + Fireball + + + Gabe des Chaos + Chaos Gift + + + Kleines Blutopfer + Lesser Sacrifice + + + Blutrausch + Blood Frenzy + + + Chaosfluch + Chaos Curse + + + Mächte des Todes + Animate Dead + + + Rosthauch + Winds Of Rust + + + Machtübertragung + Transfer Power + + + Feuerwand + Wall Of Fire + + + Fluch der Pestilenz + Curse Of Pestilence + + + Wahnsinn des Krieges + Madness of War + + + Beschwöre Schattendämonen + Summon Shadowdemons + + + Beschwörung eines Hitzeelementar + Summon Fire Elemental + + + Untote Helden + Undead Heroes + + + Erschaffe einen Gürtel der + Trollstärke + Create A Belt Of Troll + Strength + + + Astraler Riss + Astral Leak + + + Astrales Chaos + Astral Chaos + + + Feuerteufel + Fire Fiend + + + Pentagramm + Pentagram + + + Unheilige Kraft + Unholy Strength + + + Todeswolke + Death Cloud + + + Drachenruf + Call Dragons + + + Beschwöre Schattenmeister + Summon Shadowmasters + + + Erschaffe ein Flammenschwert + Create A Flamesword + + + Vertrauten rufen + Call Familiar + + + Chaossog + Chaos Gate + + + Traumsenden + Dream + + + Wahrsagen + Divination + + + Schattenritter + Shadow Knights + + + Grauen der Schlacht + Unspeakable Horrors + + + Seelenfrieden + Eternal Rest + + + Traumschlößchen + Castle Of Illusion + + + Traum der Magie + Dream Of Magic + + + Gestaltwandlung + Shapeshift + + + Traumlesen + Read Dreams + + + Schwere Glieder + Tiredness + + + Wiederbelebung + Resurrection + + + Traumbilder analysieren + Analyse Dreams + + + Schlechter Schlaf + Insomnia + + + Schlaf + Sleep + + + Traumdeuten + Mind Probe + + + Alp + Nightmare + + + Erschaffe ein Traumauge + Create a Visioneye + + + Erschaffe eine Sphäre der Unsichtbarkeit + Create a Sphere of Invisbility + + + Schöne Träume + Pleasant Dreams + + + Traumbilder entwirren + Remove Dreams + + + Vertrauten rufen + Call Familiar + + + Tod des Geistes + Mental Death + + + Süße Träume + Sweet Dreams + + + Traum von den Göttern + Dream of the gods + + + Göttliches Netz + Web of the Gods + + + Kraft der Natur + force of nature + + + Gesang der Götter + Song of the Gods + + + Göttliche Macht + Power of the Gods + + + + + Tötet die Feinde mit Säure. + Kills enemies with acid. + + + Tötet die Feinde mit Kälte. + Kills enemies with cold. + + + Tötet die Feinde mit Feuer. + Kills enemies with fire. + + + Verletzt alle Gegner. + Injures all enemies. + + + Ruft Schattenwesen. + Calls beings from shadow. + + + Panik. + Panic. + + + Entzieht Talentstufen und macht Schaden wie Großer Odem. + + + Dieser Zauber bewirkt eine schwere Störung des Astralraums. Innerhalb eines astralen Radius von Stufe/5 Regionen werden alle Astralwesen, die dem Zauber nicht wiederstehen können, aus der astralen Ebene geschleudert. Der astrale Kontakt mit allen betroffenen Regionen ist für Stufe/3 Wochen gestört. + + + + Diese vor dem Kampf zu zaubernde Ritual gibt den eigenen Truppen + einen zusätzlichen Bonus auf ihre Rüstung. Jeder Treffer + reduziert die Kraft des Zaubers, so dass der Schild sich irgendwann + im Kampf auflösen wird. + + + + + Dieser Zauber beschleunigt einige Kämpfer auf der eigenen Seite + so, dass sie während des gesamten Kampfes in einer Kampfrunde zweimal + angreifen können. + + + + + Dieser Zauber vermag dem Gegner ein geringfügig versetztes Bild der + eigenen Truppen vorzuspiegeln, so wie der Fisch im Wasser auch nicht + dort ist wo er zu sein scheint. Von jedem Treffer kann so die Hälfte + des Schadens unschädlich abgeleitet werden. Doch hält der Schild nur + einige Hundert Schwerthiebe aus, danach wird er sich auflösen. + Je stärker der Magier, desto mehr Schaden hält der Schild aus. + + + + + Zeichnet man diese Runen auf die Wände eines Gebäudes oder auf die + Planken eines Schiffes, so wird es schwerer durch Zauber zu + beeinflussen sein. Jedes Ritual erhöht die Widerstandskraft des + Gebäudes oder Schiffes gegen Verzauberung um 20%. + Werden mehrere Schutzzauber übereinander gelegt, so addiert + sich ihre Wirkung, doch ein hundertprozentiger Schutz läßt sich so + nicht erreichen. Der Zauber hält mindestens drei Wochen an, je nach + Talent des Magiers aber auch viel länger. + + + + + Mit Hilfe dieses Zauber kann der Magier eigene Aura im Verhältnis + 2:1 auf einen anderen Magier des gleichen Magiegebietes oder im + Verhältnis 3:1 auf einen Magier eines anderen Magiegebietes + übertragen. + + + + + Der Magier kann kurzzeitig in die Astralebene blicken und erfährt + so alle Einheiten innerhalb eines astralen Radius von Stufe/5 Regionen. + + + + + Mit Hilfe dieses magischen Gesangs kann der Magier eine Region in + Aufruhr wieder beruhigen. Die Bauernhorden werden sich verlaufen + und wieder auf ihre Felder zurückkehren. + + + + Aus 'Wanderungen' von Firudin dem Weisen: + 'In Weilersweide, nahe dem Wytharhafen, liegt ein kleiner Gasthof, der + nur wenig besucht ist. Niemanden bekannt ist, das dieser Hof + bis vor einigen Jahren die Bleibe des verbannten Wanderpredigers Grauwolf + war. Nachdem er bei einer seiner berüchtigten flammenden Reden fast die + gesammte Bauernschaft angeworben hatte, wurde er wegen Aufruhr verurteilt + und verbannt. Nur zögerlich war er bereit mir das Geheimniss seiner + Überzeugungskraft zu lehren.' + + + + Dieser mächtige Bann raubt dem Opfer seinen freien Willen + und unterwirft sie den Befehlen des Barden. Für einige Zeit wird das Opfer + sich völlig von seinen eigenen Leuten abwenden und der Partei des Barden + zugehörig fühlen. + + + + + Dieser mächtige Bann verhindert jegliche Attacken. Niemand in der + ganzen Region ist fähig seine Waffe gegen irgendjemanden zu erheben. + Die Wirkung kann etliche Wochen andauern. + + + + + Dieses Lied, das in die magische Essenz der Region gewoben wird, + schwächt die natürliche Widerstandskraft gegen eine + Verzauberung einmalig um 15%. Nur die Verbündeten des Barden + (HELFE BEWACHE) sind gegen die Wirkung des Gesangs gefeit. + + + + + Mit diesem Gesang verbreitet der Barde eine melancholische, traurige + Stimmung unter den Bauern. Einige Wochen lang werden sie sich in ihre + Hütten zurückziehen und kein Silber in den Theatern und Tavernen lassen. + + + + + Dieses magische Lied wird, einmal mit Inbrunst gesungen, sich in der + Region fortpflanzen, von Mund zu Mund springen und eine Zeitlang + überall zu vernehmen sein. Nach wie vielen Wochen der Gesang aus dem + Gedächnis der Region entschwunden ist, ist von dem Geschick des Barden + abhängig. Bis das Lied ganz verklungen ist, wird seine Magie allen + Verbündeten des Barden (HELFE BEWACHE), und natürlich auch seinen + eigenem Volk, einen einmaligen Bonus von 15% + auf die natürliche Widerstandskraft gegen eine Verzauberung + verleihen. + + + + + Mit Hilfe dieses magischen Gesangs überzeugt der Magier die Bauern + der Region, sich ihm anzuschließen. Die Bauern werden ihre Heimat jedoch + nicht verlassen, und keine ihrer Besitztümer fortgeben. Jede Woche + werden zudem einige der Bauern den Bann abwerfen und auf ihre Felder + zurückkehren. Wie viele Bauern sich dem Magier anschließen hängt von der + Kraft seines Gesangs ab. + + + + + Einem erfahrenen Magier wird irgendwann auf seinen Wanderungen ein + ungewöhnliches Exemplar einer Gattung begegnen, welches sich dem + Magier anschließen wird. + + + + + Dieses Ritual ermöglicht es, eine Einheit, egal welcher Art, in die + eigene Partei aufzunehmen. Der um Aufnahme Bittende muss dazu willig + und bereit sein, seiner alten Partei abzuschwören. Dies bezeugt er + durch KONTAKTIEREn des Magiers. Auch wird er die Woche über + ausschliesslich mit Vorbereitungen auf das Ritual beschäftigt sein. + Das Ritual wird fehlschlagen, wenn er zu stark an seine alte Partei + gebunden ist, dieser etwa Dienst für seine teuere Ausbildung + schuldet. Der das Ritual leitende Magier muss für die permanente + Bindung des Aufnahmewilligen an seine Partei naturgemäß auch + permanente Aura aufwenden. Pro Stufe und pro 1 permanente Aura kann + er eine Person aufnehmen. + + + + + Jede Verzauberung beeinflußt das Lebenslied, schwächt und verzerrt es. + Der kundige Barde kann versuchen, das Lebenslied aufzufangen und zu + verstärken und die Veränderungen aus dem Lied zu tilgen. + + + + + Wie Lebewesen, so haben auch Schiffe und Gebäude und sogar Regionen + ihr eigenes Lied, wenn auch viel schwächer und schwerer zu hören. + Und so, wie wie aus dem Lebenslied einer Person erkannt werden kann, + ob diese unter einem Zauber steht, so ist dies auch bei Burgen, + Schiffen oder Regionen möglich. + + + + + Dieser Kriegsgesang sät Panik in der Front der Gegner und schwächt + so ihre Kampfkraft erheblich. Angst wird ihren Schwertarm schwächen + und Furcht ihren Schildarm lähmen. + + + + + Wie viele magischen Gesänge, so entstammt auch dieser den altem + Wissen der Katzen, die schon immer um die machtvolle Wirkung der + Stimme wussten. Mit diesem Lied wird die Stimmung der Krieger + aufgepeitscht, sie gar in wilde Raserrei und Blutrausch versetzt. + Ungeachtet eigener Schmerzen werden sie kämpfen bis zum + Tode und niemals fliehen. Während ihre Attacke verstärkt ist + achten sie kaum auf sich selbst. + + + + + Erliegt die Einheit dem Zauber, so wird sie dem Magier alles erzählen, + was sie über die gefragte Region weiß. Ist in der Region niemand + ihrer Partei, so weiß sie nichts zu berichten. Auch kann sie nur das + erzählen, was sie selber sehen könnte. + + + + + Aufzeichung des Vortrags von Selen Ard'Ragorn in Bar'Glingal: + 'Es heiss, dieser Spruch wäre wohl in den Spelunken der Westgassen + entstanden, doch es kann genausogut in jedem andern verrufenen + Viertel gewesen sein. Seine wichtigste Zutat ist etwa ein Fass + schlechtesten Weines, je billiger und ungesunder, desto + wirkungsvoller wird die Essenz. Die Kunst, diesen Wein in pure + Essenz zu destillieren, die weitaus anspruchsvoller als das einfache + Rezeptmischen eines Alchemisten ist, und diese dergestalt zu binden + und konservieren, das sie sich nicht gleich wieder verflüchtigt, wie + es ihre Natur wäre, ja, dies ist etwas, das nur ein Meister des + Cerddor vollbringen kann. Nun besitzt Ihr eine kleine Phiola mit + einer rubinrotschimmernden - nun, nicht flüssig, doch auch nicht + ganz Dunst - nennen wir es einfach nur Elixier. Doch nicht dies ist + die wahre Herausforderung, sodann muss, da sich ihre Wirkung leicht + verflüchtigt, diese innerhalb weniger Tage unbemerkt in das Getränk + des Opfers geträufelt werden. Ihr Meister der Betöhrung und + Verführung, hier nun könnt Ihr Eure ganze Kunst unter Beweis + stellen. Doch gebt Acht, nicht unbedacht selbst von dem Elixier zu + kosten, denn wer einmal gekostet hat, der kann vom Weine nicht mehr + lassen, und er säuft sicherlich eine volle Woche lang. Jedoch nicht + die Verführung zum Trunke ist die wahre Gefahr, die dem Elixier + innewohnt, sondern das der Trunkenheit so sicher ein gar + fürchterliches Leid des Kopfes folgen wird, wie der Tag auf die + Nacht folgt. Und er wird gar sicherlich von seiner besten Fähigkeit + einige Tage bis hin zu den Studien zweier Wochen vergessen haben. + Noch ein Wort der Warnung: Dieses ist sehr aufwendig, und so Ihr + noch weitere Zauber in der selben Woche wirken wollt, so werden sie Euch + schwerer fallen.' + + + + + Mit diesem Lied kann eine Einheit derartig betört werden, so dass + sie dem Barden den größten Teil ihres Bargelds und ihres Besitzes + schenkt. Sie behält jedoch immer soviel, wie sie zum Überleben + braucht. + + + + + Dieser einschmeichelnde Gesang kann fast jedes intelligente Monster + zähmen. Es wird von Angriffen auf den Magier absehen und auch seine + Begleiter nicht anrühren. Doch sollte man sich nicht täuschen, es + wird dennoch ein unberechenbares Wesen bleiben. + + + + + Dieser Zauber ermöglicht es dem Träumer, den Schlaf aller nichtaliierten + Einheiten (HELFE BEWACHE) in der Region so stark zu stören, das sie + vorübergehend einen Teil ihrer Erinnerungen verlieren. + + + + + Dieser mächtige Zauber kann einen Magier vor dem sicheren Tod + bewahren. Der Magier erschafft anhand einer kleinen Blutprobe einen + Klon von sich, und legt diesen in ein Bad aus Drachenblut und verdünntem + Wasser des Lebens. + Anschließend transferiert er in einem aufwändigen Ritual einen Teil + seiner Seele in den Klon. Stirbt der Magier, reist seine Seele in den + Klon und der erschaffene Körper dient nun dem Magier als neues Gefäß. + Es besteht allerdings eine geringer Wahrscheinlichkeit, dass die Seele + nach dem Tod zu schwach ist, das neue Gefäß zu erreichen. + + + + + Der Zauberer spricht eine Beschwörung über einen Teil der Region, + und in der Folgewoche entstehen dort Irrlichter. + Wer durch diese Nebel wandert, wird von Visionen geplagt und + in die Irre geleitet. + + + + + Dieses mächtige Ritual öffnet ein Tor in die Elementarebene der + Hitze. Eine grosse Dürre kommt über das Land. Bauern, Tiere und + Pflanzen der Region kämpfen um das nackte Überleben, aber eine + solche Dürre überlebt wohl nur die Hälfte aller Lebewesen. + Der Landstrich kann über Jahre hinaus von den Folgen einer + solchen Dürre betroffen sein. + + + + + Mit Hilfe dieses aufwändigen Rituals läßt der Druide einen Teil seiner Kraft + dauerhaft in den Boden und die Wälder der Region fliessen. Dadurch wird + das Gleichgewicht der Natur in der Region für immer verändert, und in + Zukunft werden nur noch die anspruchsvollen, aber kräftigen + Mallorngewächse in der Region gedeihen. + + + + + Dieses Ritual beschört einen großen Wasserelementar aus den + Tiefen des Ozeans. Der Elementar erzeugt einen gewaltigen + Strudel, einen Mahlstrom, welcher alle Schiffe, die ihn passieren, + schwer beschädigen kann. + + + + + Mit Hilfe dieses Zaubers kann sich der Magier permanent in einen + mächtigen Wyrm verwandeln. Der Magier behält seine Talente und + Möglichkeiten, bekommt jedoch die Kampf- und Bewegungseigenschaften + eines Wyrms. Der Odem des Wyrms wird sich mit steigendem Magie-Talent + verbessern. Der Zauber ist sehr kraftraubend und der Wyrm wird einige + Zeit brauchen, um sich zu erholen. + + + + + Mit Hilfe dieses magischen Gesangs versetzt der Magier eine ganze + Region in Aufruhr. Rebellierende Bauernhorden machen jedes Besteuern + unmöglich, kaum jemand wird mehr für Gaukeleien Geld spenden und + es können keine neuen Leute angeworben werden. Nach einigen Wochen + beruhigt sich der Mob wieder. + + + + + Der Magier kann mit Hilfe dieses Zaubers aus der Astral- in die + materielle Ebene blicken und die Regionen und Einheiten genau + erkennen. + + + + + Einem erfahrenen Magier wird irgendwann auf seinen Wanderungen ein + ungewöhnliches Exemplar einer Gattung begegnen, welches sich dem + Magier anschließen wird. + + + + + Dieses kräftezehrende Ritual beschwört mit Hilfe einer Kugel aus + konzentriertem Laen einen gewaltigen Erdelementar und bannt ihn + in ein Gebäude. Dem Elementar kann dann befohlen werden, das + Gebäude mitsamt aller Bewohner in eine Nachbarregion zu tragen. + Die Stärke des beschworenen Elementars hängt vom Talent des + Magiers ab: Der Elementar kann maximal [Stufe-12]*250 Größeneinheiten + große Gebäude versetzen. Das Gebäude wird diese Prozedur nicht + unbeschädigt überstehen. + + + + Dieses Amulett in Gestalt einer orkischen Matrone + unterdrückt den Fortpflanzungstrieb eines einzelnen Orks sehr + zuverlässig. + Ein Ork mit Amulett der Keuschheit wird sich nicht mehr vermehren. + + + Dieser Zauber ermöglicht dem Magier, gezielt eine + bestimmte Verzauberung einer Einheit, eines Schiffes, Gebäudes oder auch + der Region aufzulösen. + This spell allows a magician to remove a specific + enchantment from a unit, ship, bulding or region. + + + Ein Schauer von Meteoren regnet über das Schlachtfeld. + A meteor shower rains down on the battlefield. + + + 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. + 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. + + + Mit dieser Formel bindet der Magier auf ewig die + Kräfte + der Erde in die Mauern des Gebäudes. Ein solchermaßen verzaubertes + Gebäude + ist gegen den Zahn der Zeit geschützt und benötigt keinen Unterhalt + mehr. + With this spell, the magician binds the power of the + earth into the walls of a building for all eternity. Such a building is + immune to the sands of time and needs no maintenance cost. + + + Ein Magier, der sich in der astralen Ebene befindet, + kann mit Hilfe dieses Zaubers andere Einheiten zu sich holen. Der Magier + kann (Stufe-3)*15 GE durch das kurzzeitig entstehende Tor schicken. Ist + der Magier erfahren genug, den Zauber auf Stufen von 13 oder mehr zu + zaubern, kann er andere Einheiten auch gegen ihren Willen auf die + andere + Ebene zwingen. + A magician in the astral plane can summon units from + the + material world. The magician can bring (level-3)*15 GE through the + temporary portal. If he is experienced enough to cast the spell at at + least level 13, he can even summon units against their will. + + + Ein Magier, welcher sich in der materiellen Welt + befindet, kann er mit Hilfe dieses Zaubers Einheiten aus der + angrenzenden + Astralwelt herbeiholen. Ist der Magier erfahren genug, den Zauber auf + Stufen von 13 oder mehr zu zaubern, kann er andere Einheiten auch gegen + ihren Willen in die materielle Welt zwingen. + A magician in the material world can summon units from + the adjacent part of the astral plane. If he is experienced enough to + cast + the spell at at least level 13, he can even summon units against their + will. + + + Mit Hilfe dieses Zaubers kann der Magier einem anderen + Magier seine Aura gegen dessen Willen entziehen und sich selber + zuführen. + Aided by this spell, a magician can steal another + magician's aura against his will. + + + Diese magischen Runen bringen ein Boot oder Langboot + für + eine Woche zum fliegen. Damit kann dann auch Land überquert werden. Die + Zuladung von Langbooten ist unter der Einwirkung dieses Zaubers auf 100 + Gewichtseinheiten begrenzt. Für die Farbe der Runen muss eine spezielle + Tinte aus einem Windbeutel und einem Schneekristall angerührt werden. + These magic runes allow a boat or longboat to fly for + a + week. The boat can only carry 100 weight units. The enchanted ink's + components include a windbag and a snowcrystal petal. + + + Diese praktische Anwendung des theoretischen Wissens um + Raum und Zeit ermöglicht es, den Zeitfluß für einige Personen zu + verändern. Auf diese Weise veränderte Personen bekommen für einige + Wochen doppelt soviele Bewegungspunkte und doppelt soviele Angriffe + pro Runde. + Abstract theories of space and time at last find + practical application in this spell which warps the very fabric of + time around a person. Such a person has twice as many movement points + and doubles their attacks per round for a few weeks. + + + Dieser Zauber läßt eine Welle aus purer Kraft über die + gegnerischen Reihen hinwegfegen. Viele Kämpfer wird der Schock so + benommen machen, daß sie für einen kurzen Moment nicht angreifen + können. + A wave of pure force spreads out from the magician, + crashing into the enemy ranks. Many warriors are thrown off balance and + are briefly unable to attack. + + + Mit diesem Zauber kann der Magier eine Zone der + astralen + Schwächung erzeugen, ein lokales Ungleichgewicht im Astralen Feld. + Dieses + Zone wird bestrebt sein, wieder in den Gleichgewichtszustand zu + gelangen. + Dazu wird sie jedem in dieser Region gesprochenen Zauber einen Teil + seiner Stärke entziehen, die schwächeren gar ganz absorbieren. + This spell allows a magician to create a local + instability in the astral field. This zone needs to return to its + equilibrium, soaking up part of the power of all spells cast in the + region + - or even all of some of the weaker ones. + + + Dieser Zauber ermöglicht dem Magier, Verzauberungen + einer Einheit, eines Schiffes, Gebäudes oder auch der Region aufzulösen. + This spell lets a magician destroy spells on a ship, + building or region. + + + Dieser Zauber verstärkt die natürliche + Widerstandskraft + gegen Magie. Eine so geschützte Einheit ist auch gegen Kampfmagie + weniger + empfindlich. Pro Stufe reicht die Kraft des Magiers aus, um 5 Personen + zu + schützen. + This spell enhances natural magic resistence. + Protected + units are less vulnerable to battle magic. The spell protects 5 people + per + level. + + + Alte arkane Formeln ermöglichen es dem Magier, sich + und + andere in die astrale Ebene zu schicken. Der Magier kann (Stufe-3)*15 GE + durch das kurzzeitig entstehende Tor schicken. Ist der Magier erfahren + genug, den Zauber auf Stufen von 11 oder mehr zu zaubern, kann er andere + Einheiten auch gegen ihren Willen auf die andere Ebene zwingen. + Ancient arcane formulae permit the magician to + transport + himself or other units into the astral plane. The magician can transport + (level-3) * 15 GE through the transient portal. If the magician is + experienced enough to cast level 11 spells, he can also transport units + against their will. + + + Der Magier konzentriert sich auf die Struktur der + Realität und kann so die astrale Ebene verlassen. Er kann insgesamt + (Stufe-3)*15 GE durch das kurzzeitig entstehende Tor schicken. Ist der + Magier erfahren genug, den Zauber auf Stufen von 11 oder mehr zu + zaubern, + kann er andere Einheiten auch gegen ihren Willen auf die andere Ebene + zwingen. + By concentrating on the structure of reality, the + magician can breach it and thus briefly make a gateway to leave the + astral + plane. He can transport up to (level-3)*15 GE through the portal. If the + magician is able to cast at at least level 11, he can even transport + other + units against their will. + + + Mit diesem Spruch kann der Magier versuchen, die + Verzauberungen + eines einzelnen angegebenen Objekts zu erkennen. Von + allen Sprüchen, + die seine eigenen Fähigkeiten nicht überschreiten, wird + er einen + Eindruck ihres Wirkens erhalten können. Bei stärkeren + Sprüchen + benötigt er ein wenig Glück für eine gelungene Analyse. + With this spell the magician can try to identify the + enchantments of + a single object. He will get an impression of the + operation of all + spells that don't exceed his own capabilities. For more + powerful + spells he will need some luck for a successful analysis. + + + Dieser Zauber wird die gesamte Ausrüstung der + Zieleinheit für + einige Zeit vor den Blicken anderer verschleiern. Der + Zauber + schützt nicht vor Dieben und Spionen. + This spell will hide the whole equipment of a target + unit from the + looks of others. It will not protect against thieves or + spies. + + + Dieser Zauber legt ein antimagisches Feld um die Magier der Feinde + und behindert ihre Zauber erheblich. Nur wenige werden die Kraft + besitzen, das Feld zu durchdringen und ihren Truppen in der Schlacht + zu helfen. + This spell creates an antimagic field around the mages of the enemies + and considerably hinders their spells. Only few will have the power to + break through the field and be able to help their troops in battle. + + + Dieser Zauber verhindert, dass ein Teil der sonst im Kampf zerstörten + Gegenstände beschädigt wird. Die Verluste reduzieren sich um 5% pro + Stufe des Zaubers bis zu einem Minimum von 25%. + This spell prevents damage to a portion of the items that would + otherwise be lost in battle. The loss of items is reduced by 5% for + every level of the spell, up to a minimum of 25%. + + + + Dieses Lied zähmt selbst den wildesten + Ork und macht ihn friedfertig und sanftmütig. Jeder + Gedanke, dem Sänger zu schaden, wird ihm entfallen. + Unbehelligt kann der Magier in eine Nachbarregion + ziehen. + This little melody calms even the + wildest orc to a gentle and serene creature who will not + even think about putting the singer to harm. The magician + may travel to a neighboring region without being + harassed by annoying troublemakers. + + + Nicht nur der Feldscher kann den + Verwundeten einer Schlacht helfen. Die Barden kennen + verschiedene Lieder, die die Selbstheilungskräfte des + Körpers unterstützen. Dieses Lied vermag Wunden zu + schließen, gebrochene Knochen zu richten und selbst + abgetrennte Glieder wieder zu regenerieren. + The field medic isn't the only one + capable of tending the wounds of battle. The bards know + a number of magic melodies to enhance the natural + healing process of the body. This song is able to close + wounds, mend fractured bones and even regenerate lost + lims. + + + Ein gar machtvoller Gesang aus den + Überlieferungen der Katzen, der tief in die Herzen der + Feinde dringt und ihnen Mut und Hoffnung raubt. Furcht + wird sie zittern lassen und Panik ihre Gedanken + beherrschen. Voller Angst werden sie versuchen, den + gräßlichen Gesängen zu entrinnen und fliehen. + This antique, powerful song, passed + down by the cats, will penetrate the hearts of the enemy + and bereave them of courage and hope. Both their minds + and bodies will be ruled by panic. Shivering with fear, + they will flee from the dreadful chants and try to make + their escape. + + + Aus den uralten Gesängen der Katzen + entstammt dieses magisches Lied, welches vor einem + Kampfe eingesetzt, einem entscheidende strategische + Vorteile bringen kann. Wer unter den Einfluss dieses + Gesangs gelangt, der wird seiner Umgebung nicht achtend + der Melodie folgen, sein Geist wird verwirrt und + sprunghaft plötzlichen Eingebungen nachgeben. So sollen + schon einst wohlgeordnete Heere plötzlich ihre Schützen + weit vorne und ihre Kavallerie bei den Lagerwachen + kartenspielend wiedergefunden haben (oder ihren Anführer + schlafend im lange verlassenen Lager, wie es in den + Großen Kriegen der Alten Welt wirklich geschehen sein + soll). + If is used before battle, this chant, + taken from the ancient tunes of the cats, might give you + the critical tactical advantage. Those under the spell's + influence will act uncoordinated and inconsequent due to + the nonsensical ideas planted into their minds through + the melody. So it is supposed to have come to pass that + well-organized armies found their archers up at the + front (while the cavalry was back at the camp playing + cards) or that even a famous general overslept a battle + in his tent, as tale-tellers claim it really happened + during the Great Wars in the Old World. + + + Dieser alte Schlachtengesang hebt die + Moral der eigenen Truppen und und hilft ihnen auch der + angsteinflößenden Aura dämonischer und untoter Wesen zu + widerstehen. Ein derartig gefestigter Krieger wird auch + in schwierigen Situationen nicht die Flucht ergreifen + und sein überlegtes Verhalten wird ihm manch Vorteil in + der Verteidigung geben. + This ancient battle chant lifts the + spirit of your troops and helps them withstand even the + fear-inspiring aura of demonic and undead beings. A + fighter thus fortified against evil will not flee even + in the face of terror, and his defenses will be strengthened. + + + Mit Hilfe dieses Zaubers kann der + Magier eigene Aura im Verhältnis 2:1 auf einen anderen + Magier des gleichen Magiegebietes übertragen. + This spell enables the wizard to + transfer aura at a rate of 2:1 to another sorcerer of + the same school of magic. + + + Alle lebenden Wesen haben ein eigenes + individuelles Lebenslied. Nicht zwei Lieder gleichen + sich, auch wenn sich alle Lieder einer Art ähneln. Jeder + Zauber verändert dieses Lied auf die eine oder andere + Art und gibt sich damit zu erkennen. Dieser Gesang + hilft, jene Veränderungen im Lebenslied einer Person zu + erlauschen, welche magischer Natur sind. Alle + Verzauberungen, die nicht stärker maskiert sind als Eure + Fähigkeit, werdet Ihr so entschlüsseln und demaskieren + können. + Each and every living being has its + own, individual 'life-song'. No two of these songs are + alike, even though songs of creatures of the same + species are similar. Every spell alters this song of + life in one way or the other and this can be identified. + By casting this spell, the bard can detect all those + magic variations in a person's 'life-song'. You will be + able to decipher all enchantments or spells, which + aren't disguised beyond your capability. + + + Dieser schrille Gesang hallt über das + ganze Schlachtfeld. Die besonderen Dissonanzen in den + Melodien machen es Magier fast unmöglich, sich auf ihre + Zauber zu konzentrieren. + The screeching sounds of this melody + can be heard across the whole battlefield. Wizards + exposed to these special dissonances find it nearly + impossible to concentrate on their spells. + + + Die verzauberte Einheit beginnt + hemmungslos zu plappern und erzählt welche Talente sie + kann, was für Gegenstände sie mit sich führt und sollte + sie magisch begabt sein, sogar welche Zauber sie + beherrscht. Leider beeinflußt dieser Zauber nicht das + Gedächnis, und so wird sie sich im nachhinein wohl + bewußt werden, dass sie zuviel erzählt hat. + The persons of the bewitched unit + starts to babble without control about what it is said, + speaking about their talents, the objects they carry or + wear and if the unit is a magician, he or she will even list + the spells they know. Unfortunately, this spell does not + influence the memory of the subjects and afterwards, the + enchanted will realize that they probably talked too + much. + + + Man befeuchte einen kluftfreien Block + aus feinkristallinen Gestein mit einer Phiole des + Lebenswassers bis dieses vollständig vom Gestein + aufgesogen wurde. Sodann richte man seine Kraft auf die + sich bildende feine Aura des Lebens und forme der + ungebundenen Kraft ein Gehäuse. Je mehr Kraft der Magier + investiert, desto mehr Golems können geschaffen werden, + bevor die Aura sich verflüchtigt. Jeder Golem hat jede + Runde eine Chance von 10 Prozent zu Staub zu zerfallen. + Gibt man den Golems die Befehle MACHE BURG oder MACHE + STRASSE, so werden pro Golem 4 Steine verbaut und der + Golem löst sich auf. + 'Take a flawless block of crystaline + stone and humidify it with a vial of Water Of Life until + the potion has been soaked up completely. Then focus + your power on the forming aura of life and shape a + container for the unbound forces'. The more power a magician + invests, the more golems can be created before the aura + dissipates. Every week, there is a 10 percent chance + that the golem will crumble to dust. If you command a + golem to 'MAKE CASTLE' or 'MAKE ROAD', it will turn + itself into 4 stones that it uses in construction, and + disintegrate afterwards. + + + Je mehr Kraft der Magier investiert, + desto mehr Golems können geschaffen werden. Jeder Golem + hat jede Runde eine Chance von 15 Prozent zu Staub zu + zerfallen. Gibt man den Golems den Befehl MACHE + SCHWERT/BIHÄNDER oder MACHE + SCHILD/KETTENHEMD/PLATTENPANZER, so werden pro Golem 4 + Eisenbarren verbaut und der Golem löst sich auf. + The more power a magician invests, the + more golems can be created before the aura dissipates. + Each golem has a 15% chance per week to turn to dust. If + you command a golem to 'MAKE SWORD/MAKE CLAYMORE' or + 'MAKE SHIELD/CHAINMAIL/PLATEMAIL',it will work 5 iron + ingots and disintegrate afterwards. + + + Wo sonst aus einem + Stecken nur ein Baum sprießen konnte, so treibt nun jeder + Ast Wurzeln. + Every branch becomes a sturdy + oak where before only one could be grown from a log. + + + Mit diesem Ritual wird eine dunkle + Gewitterfront beschworen, die sich + unheilverkündend über der Region auftürmt. Der + magische Regen wird alles Erz rosten lassen. + Eisenwaffen und Rüstungen werden schartig und rostig. + Die Zerstörungskraft des + Regens ist von der investierten Kraft des + Magiers abhängig. Für jede Stufe können bis zu + 10 Eisenwaffen betroffen werden. Ein Ring der + Macht verstärkt die Wirkung wie eine zusätzliche + Stufe. + This ritual conjurs up a dark + thunderstorm that affects a whole region. The + magic rain will let rust any ore. Iron weapons and + armor will get rusty. The exact number of + items affected by the rain depends on the + ammount of power invested by the magician. Up to ten + weapons can be destroyed per level - a Ring Of + Power increases the effect like an additional + level. + + + Dieser Zauber ermöglicht es dem Magier + Insekten auf magische Weise vor der lähmenden + Kälte der Gletscher zu bewahren. Sie können + Gletscher betreten und dort normal agieren. Der + Spruch wirkt auf Stufe*10 Insekten. Ein Ring der + Macht erhöht die Menge der verzauberbaren + Insekten zusätzlich um 10. + This spell enables the druid to + magically protect insects from the paralysing + cold of a glacier. Under the effect of this + spell, insects are able to enter glaciers and + act normally there. Ten insects per level can be + protected in this way. A Ring Of Power increases + the number by additional ten. + + + Im Kampf ruft der Magier die + Elementargeister der Kälte an und bindet sie an + sich. Sodann kann er ihnen befehlen, den Gegner + mit Hagelkörnern und Eisbrocken zuzusetzen. + During a battle the druid calls the + Elemental Spirits Of Cold and binds them to + himself. Then he commands them to attack his + foes with hail and ice missiles. + + + Erschafft einen Wächtergeist, der + in Gletschern und Bergen Eisen- und Laenabbau durch + nichtalliierte Parteien (HELFE BEWACHE) verhindert, + solange er die Region bewacht. Der Bergwächter ist + an den Ort der Beschwörung gebunden. + Creates a guardian spirit on a + mountain or glacier that keeps all factions that + are not allied (HELP GUARD) from mining iron or + laen as long as it guards the region. The + Mountain Guardian is bound to the location where + it has been summoned. + + + Durch Ausführung dieser Rituale ist + der Magier in der Lage einen mächtigen + Erdelementar zu beschwören. Solange dieser in + den Boden gebannt ist, wird kein Regen die Wege + aufweichen und kein Fluß Brücken zerstören + können. Alle Reisende erhalten damit die + gleichen Vorteile, die sonst nur ein ausgebautes + gepflastertes Straßennetz bietet. Selbst Sümpfe + und Gletscher können so verzaubert werden. Je + mehr Kraft der Magier in den Bann legt, desto + länger bleibt die Straße bestehen. + By performing these rituals the druid + is able to summon a powerful earth elemental. As + long as this elemental remains bound to a + region, no rain can turn a path into mud and no + river can destroy a bridge. All travelers in + this region gain the same advantages as if they + were travelling on a road. Even swamps and + glaciers can be enchanted in this way. The more + power the druid invests, the longer the roads + remain intact. + + + Die Anrufung der Elementargeister des + Windes beschwört plötzliche Windböen, kleine + Windhosen und Luftlöcher herauf, die die + gegnerischen Schützen behindern werden. + Calling the Elemental Spirits Of Wind + conjurs up sudden breezes, small whirlwinds and + minor turbulences that will hinder enemy + archers. + + + Diese Ritual verstärkt die Wirkung des + magischen Trankes um ein vielfaches. Wo sonst aus einem + Stecken nur ein Baum sprießen konnte, so treibt nun jeder + Ast Wurzeln. + This ritual greatly increases the + effect of the potion. Now every branch becomes a mallorn + tree where before only one could be grown from a log. + + + Der Magier zwingt mit diesem Ritual + die Elementargeister des Wassers in seinen + Dienst und bringt sie dazu, das angegebene + Schiff schneller durch das Wasser zu tragen. + Zudem wird das Schiff nicht durch ungünstige + Winde oder Strömungen beeinträchtigt. + While being aboard a ship, the druid + uses this ritual to force the Elemental Spirits + Of Water to serve him and commands them to carry + the ship across the water at a higher speed. In + addition, the ship will not be affected by + unfavourable winds or currents. + + + Nicht nur der Feldscher kann den + Verwundeten einer Schlacht helfen. Druiden + vermögen mittels einer Beschwörung der + Elementargeister des Lebens Wunden zu schließen, + gebrochene Knochen zu richten und selbst + abgetrennte Glieder wieder zu regenerieren. + Combat medics are not the only ones + who can help those who got injured during a + battle. Druids are, with the help of a summons + of + the Elemental Spirits Of Life, able to heal + wounds, mend broken bones or even regenerate + separated limbs as well. + + + Diese Beschwörung öffnet ein Tor in + die Ebene der Elementargeister des Windes. + Sofort erheben sich in der Umgebung des Tors + starke Winde oder gar Stürme und behindern alle + Schützen einer Schlacht. + This summons opens a gate to the plane + of Elemental Spirits Of Wind. Immediately, + strong winds or even storms will rise near the + gate and hinder all archers during a battle. + + + Dieses Ritual beschwört einige + Elementargeister der Magie und schickt sie in + die Reihen der feindlichen Magier. Diesen wird + das Zaubern für die Dauer des Kampfes deutlich + schwerer fallen. + This ritual summons some Elemental + Spirits Of Magic and sends them into the ranks + of the enemy mages. Casting spells will be much + harder for them during the battle. + + + Mit Hilfe dieses Zaubers kann der + Magier eigene Aura im Verhältnis 2:1 auf einen + anderen Magier des gleichen Magiegebietes + übertragen. + The caster can transfer aura at a + ratio of 2:1 to another member of the same + school of magic with the help of this spell. + + + Der Druide beschwört mit diesem Ritual + einen Elementargeist der Erde und bringt ihn + dazu, die Erde erbeben zu lassen. Dieses + Erdbeben wird alle Gebäude in der Region + beschädigen. + With this ritual the druid summons an + Elemental Spirit Of Earth that brings the ground + to shake. This earthquake damages all buildings + in the target region. + + + Die Beschwörung von Elementargeistern + der Stürme ist ein uraltes Ritual. Der Druide + bannt die Elementare in die Segel der Schiffe, + wo sie helfen, das Schiff mit hoher + Geschwindigkeit über die Wellen zu tragen. Je + mehr Kraft der Druide in den Zauber investiert, + desto größer ist die Zahl der Elementargeister, + die sich bannen lassen. Für jedes Schiff wird + ein Elementargeist benötigt. + Calling the Elemental Spirits Of Storm + is an ancient ritual. The druid binds the + elementals to a ship's sails where they can help + to carry the vessel across the waves at an + amazing speed. The more power the druid invests, + the greater is the number of spirits bound. Each + ship needs an own spirit. + + + Mit diesem Spruch erzeugt man ein Runenschwert. Die + Klinge des schwarzen Schwertes ist mit alten, magischen Runen verziert, + und ein seltsames Eigenleben erfüllt die warme Klinge. Um es zu + benutzen, + muss man ein Schwertkämpfer von beachtlichem Talent (7) sein. Der + Träger + des Runenschwertes erhält einen Talentbonus von +4 im Kampf und wird so + gut wie immun gegen alle Formen von Magie. + This spell creates a magical sword. It requires a + skill + of at least 7, but adds +4 to the combat skill of its' owner as well as + making them almost immune against magical attacks. + + + Dieser Beutel umschließt eine kleine Dimensionsfalte, + in + der bis zu 200 Gewichtseinheiten transportiert werden können, ohne dass + sie auf das Traggewicht angerechnet werden. Pferde und andere Lebewesen + sowie besonders sperrige Dinge (Wagen und Katapulte) können nicht in dem + Beutel transportiert werden. Auch ist es nicht möglich, einen + Zauberbeutel in einem anderen zu transportieren. Der Beutel selber wiegt + 1 + GE. + This bag encloses a dimensional rift in which up to + 200 + units of weight can be carries. Horses and other large objects cannot be + put into the bag. The bag itself has a weight of 1. + + + Dieses mächtige Ritual erschafft einen Ring der Macht. + Ein Ring der Macht erhöht die Stärke jedes Zaubers, den sein Träger + zaubert, als wäre der Magier eine Stufe besser. + A ring of power adds +1 to the power of each spell + cast + by its' wearer. + + + Der Spruch ermöglicht es einem Magier, + ein Amulett des Wahren Sehens zu erschaffen. Das + Amulett erlaubt es dem Träger, alle Einheiten, + die durch einen Ring der Unsichtbarkeit + geschützt sind, zu sehen. Einheiten allerdings, + die sich mit ihrem Tarnungs-Talent verstecken, + bleiben weiterhin unentdeckt. + This spell enables the caster to + create an Amulet Of True Sight. Wearing such an + amulet, a person can discover anyone wearing a + Ring of Invisibility. Anyway, units concealed by + the use of their stealth skill will remain + undiscovered. + + + Mit Hilfe dieses Zauber entzieht der Magier einem + Quarzkristall all seine magischen Energien. Der Kristall wird dann, wenn + er zu feinem Staub zermahlen und verteilt wird, die beim Zaubern + freigesetzten magischen Energien aufsaugen und die Kraft aller Zauber + reduzieren, welche in der betreffenden Woche in der Region gezaubert + werden. + This spell creates a portable crystal of antimagic + which can be used by anybody to reduce or even eliminate the power of + all spells cast in the region during the same week. + + + Die berühmte Bardin Miriam bhean'Meddaf war bekannt + für ihr außergewöhnliches Geschick mit der Harfe. Ihre Finger sollen + sich so schnell über die Saiten bewegt haben, das sie nicht mehr + erkennbar waren. Dieser Zauber, der recht einfach in einen Silberring + zu bannen ist, bewirkt eine um das zehnfache verbesserte + Geschicklichkeit und Gewandheit der Finger. (Das soll sie auch an + anderer Stelle ausgenutzt haben, ihr Ruf als Falschspielerin war + berüchtigt). Handwerker können somit das zehnfache produzieren, + und bei einigen anderen Tätigkeiten könnte dies ebenfalls von Nutzen + sein. + The famous bard Mirim was known for exceptionally + limber + play of the harp. Her spell, which is easy to ban into a little silver + ring, increases the wearer's dexterity by a factor of ten, which is siad + to be useful to both craftsmen and shady natures. + + + Mit diesem Spruch kann der Zauberer + einen Ring der Unsichtbarkeit erschaffen. Der + Träger des Ringes wird für alle Einheiten + anderer Parteien unsichtbar, egal wie gut ihre + Wahrnehmung auch sein mag. In einer unsichtbaren + Einheit muss jede Person einen Ring tragen. + With this spell the caster can create + a Ring Of Invisibility. The wearer of this ring + will be invisible to all units of other + factions, no matter how good their perception + skill may be. In an invisible unit, each person + must wear a Ring Of Invisibility. + + + Mit dieser Formel bindet der Magier + auf ewig die Kräfte der Erde in die Mauern der + Burg, in der er sich gerade befindet. Weder + magisch noch mit schwerem Geschütz können + derartig gestärkte Mauern zerstört werden, und + auch das Alter setzt ihnen weniger zu. Das + Gebäude bietet sodann auch einen besseren Schutz + gegen Angriffe mit dem Schwert wie mit Magie. + With this spell the druid eternally + binds the powers of earth to the walls of the + castle in which he currently is. No magic and no + ballistic attacks will ever be able to destroy a + wall that has been fortified in this way and the + castle will also be less affected by aging. In + addition, the building will provide a better + protection against attacks by sword or by magic. + + + Nicht wenige Druiden freunden sich im + Laufe ihres Lebens in der Natur mit den ältesten + Freunden der großen Völker an. Sie erlernen, mit + einem einzigen heulenden Ruf viele ihrer Freunde + herbeizurufen, um ihnen im Kampf beizustehen. + During their life in the wilderness, + many druids make friends with the wolves who are + the oldest friends of the great races. They + learn to call many of them with a single howl to + aid them in combat. + + + Dieser schwierige, aber effektive + Kampfzauber benutzt die Elementargeister des + Steins, um eine Reihe von Gegnern für die Dauer + des Kampfes in Stein zu verwandeln. Die + betroffenen Personen werden nicht mehr kämpfen, + können jedoch auch nicht verwundet werden. + This complicated but effective spell + uses the Elemental Spirits Of Stone to turn a + number of enemies to stone for the duration of + combat. The affected persons won't be able to + fight any more, but they can't be wounded + either. + + + Mit dieser Formel bindet der Magier zu + Beginn eines Kampfes einige Elementargeister des + Fels in die Mauern des Gebäudes, in dem er sich + gerade befindet. Das Gebäude bietet sodann einen + besseren Schutz gegen Angriffe mit dem Schwert + wie mit Magie. + At the beginning of a battle, the + magician binds some Elemental Spirits Of Rock to + the walls of the builing in which he currently + is. The structure will then provide a better + protection against attacks by sword or by magic. + + + Wie die alten Lehren der Druiden + berichten, besteht das, was die normalen Wesen + Magie nennen, aus Elementargeistern. Der Magier + beschwört und bannt diese in eine Form, um den + gewünschten Effekt zu erzielen. Dieses Ritual + nun vermag es, in diese Welt gerufene + Elementargeister zu vertreiben, um so ein Objekt + von Magie zu befreien. + Old legends of the druids say that + what normal people call 'magic' consists of + elemental spirits. A magician summons these + spirits and binds them to various forms to + achieve the desired effects. This ritual is able + to expel any elemental spirits that have been + summoned to this world and thereby dispels any + magic on the target. + + + Große Macht liegt in Orten, an denen + das Leben pulsiert. Der Druide kann diese Kraft + sammeln und so ein Tor in die Welt der + Geistwesen erschaffen. Der Druide kann dann + Stufe*5 Gewichtseinheiten durch das Tor + entsenden. + A great power lies within those places + that are pulsing with life. A druid can focus + this power and thereby create a gate into the + World Of Spirits. He can then send level*5 + weight units of living or dead matter through + the gate. + + + Ein Druide, den es in die Welt der + Geister verschlagen hat, kann mit Hilfe dieses + Zaubers Stufe*5 Gewichtseinheiten in einen Wald + auf der materiellen Welt zurückschicken. + A druid who has traveled to the World + Of Spirits can use this spell to send level*5 + weight units of living or dead matter back to a + forest in the material world. + + + Dieses Ritual beschwört verschiedene + Naturgeister in den Boden der Region, welche + diese fortan bewachen. In einer so gesegneten + Region werden niemals wieder die Toten ihre + Gräber verlassen, und anderswo entstandene + Untote werden sie wann immer möglich meiden. + This ritual binds various rural + spirits to a specific territory to guard the + land. In a region blessed in this way the dead + won't ever rise from their graves again. + Existing undead also shun the sacred grounds and + will avoid entering the protected area whenever + possible. + + + Der Druide nehme etwas präpariertes + Leder, welches er in einem großen Ritual der + Reinigung von allen unreinen Geistern befreie, + und binde dann einige kleine Geister der Luft + und des Wassers in das Material. Aus dem so + vorbereiteten Leder fertige er nun ein kleines + Beutelchen, welches in ihm aufbewahrte Kräuter + besser zu konservieren vermag. + The druid takes some specially + prepared leather and performes a great ritual + during which the leather is cleansed of all + impure spirits. Then he binds some minor spirits + of air and water to the material. After + completing this process, the druid works the + enchanted leather into a small pouch which is + suitable to contain herbs, for it is able to + preserve them for a long time and prevents rot. + + + Mit Hilfe dieses Zaubers weckt der + Druide die in den Wälder der Region + schlummernden Ents aus ihrem äonenlangen Schlaf. + Die wilden Baumwesen werden sich ihm anschließen + und ihm beistehen, jedoch nach einiger Zeit + wieder in Schlummer verfallen. + With the help of this spell the druid + awakens the ents who are slumbering in the + forests of a region from aeons of sleep. These + strange tree-creatures will join him and aid his + cause, but after a while they will sink back + into their slumber. + + + Einem erfahrenen Druidem wird + irgendwann auf seinen Wanderungen ein + ungewöhnliches Exemplar einer Gattung begegnen, + welches sich dem Druiden anschließen wird. + Once during his travels, the seasoned + druid will meet an extraordinary creature of its + species that will join him. + + + Dieses Ritual segnet einen Steinkreis, + der zuvor aus Steinen und etwas Holz gebaut + werden muss. Die Segnung des Druiden macht aus + dem Kreis eine mächtige Stätte magischen + Wirkens, die Schutz vor Magie und erhöhte Aura- + Regeneration bewirkt. Man sagt, Jungfrauen seien + in der Umgebung von Steinkreisen seltsame Wesen + begegnet. + This ritual blesses a circle of stones + that has to be constructed from stones and some + wood before. The druid's blessing turns the + circle into a place of great magic that is + suitable for rituals of all kinds. It protects + from hostile magic and improves aura + regeneration. Virgins are said to have been + visited by strange creatures in the vicinity of + these places. + + + Das Ziel des Zauberers wird von einer + harmlosen Verwünschung heimgesucht. + The target of this spell becomes + subject to a harmless curse. + + + Dieses vor dem Kampf zu zaubernde Ritual gibt den + eigenen Truppen einen zusätzlichen Bonus auf ihre Rüstung. Jeder + Treffer reduziert die Kraft des Zaubers, so dass der Schild sich + irgendwann im Kampf auflösen wird. + Performing this ritual before going into battle gives + your troups an additional bonus to their armor. Every hit reduces the + energy of the spell, dissolving it at some point during battle. + + + Der Zauberer schleudert fokussiertes + Chaos in die Reihen der Gegner. Das ballförmige + Chaos wird jeden verwunden, den es trifft. + The sorcerer hurls a ball of + concentrated chaos into the ranks of his + enemies. It will seriously hurt anyone who gets + hit. + + + Der Magier öffnet seinen Geist den + Sphären des Chaos und wird so für einige Zeit + über mehr magische Kraft verfügen. Doch die + Hilfe der Herren der Sphären hat seinen Preis, + und so wird die Phase der Macht abgelöst von + einer Phase der Schwäche. + The sorcerer opens his mind to the + Spheres Of Chaos so that he can access a greater + ammount of magical power for a while. But the + help of the Chaos Lords has its price - and so + the period of power will be followed by a period + of weakness. + + + Mit diesem Ritual kann der Magier + einen Teil seiner Lebensenergie opfern, um dafür + an magischer Kraft zu gewinnen. Erfahrene + Ritualmagier berichten, das sich das Ritual, + einmal initiiert, nur schlecht steuern ließe und + die Menge der so gewonnenen Kraft stark + schwankt. So steht im 'Buch des Blutes' + geschrieben: 'So richte Er aus das Zeichen der + vier Elemente im Kreis des Werdens und Vergehens + und Weihe ein jedes mit einem Tropfen Blut. + Sodann begebe Er in der Mitten der Ewigen Vierer + sich und lasse Leben verrinnen, auf das Kraft + geboren werde.' + With this ritual the sorcerer can + sacrifice part of his life force in order to + gain raw astral power. Experienced mages report + that this ritual, once started, is hard to + control and that the ammount of power gained in + this way varies. + + + In diesem blutigen Ritual opfert der + Magier vor der Schlacht ein Neugeborenes vor den + Augen seiner Armee. Die so gerufenen Blutgeister + werden von den Soldaten Besitz ergreifen und sie + in einen Blutrausch versetzen. + During this bloody ritual the sorcerer + sacrifices a newborn child before a battle right + in front of his army. In this way he attracts + spirits of blood that will take control of the + soldiers who are present and force them into a + blood frenzy. + + + Dieser heimtückische Fluch + beeinträchtigt die magischen Fähigkeiten des + Opfers erheblich. Eine chaosmagische Zone um das + Opfer vermindert seine Konzentrationsfähigkeit + und macht es ihm sehr schwer Zauber zu wirken. + This wicked curse affects the magical + abilities of the target. A field of raw chaos + magic around the target lessens its + concentration and makes it very hard to cast any + spells. + + + Nächtelang muss der Schwarzmagier + durch die Friedhöfe und Gräberfelder der Region + ziehen um dann die ausgegrabenen Leichen beleben + zu können. Die Untoten werden ihm zu Diensten + sein, doch sei der Unkundige gewarnt, dass die + Beschwörung der Mächte des Todes ein + zweischneidiges Schwert sein kann. + For many nights the sorcerer has to + roam the graveyards and former battlefields of a + region in order to find corpses to animate. The + Undead will serve his will, but beware! Dealing + with the mysteries of unlife can be a dangerous + thing. + + + Mit diesem Ritual wird eine dunkle + Gewitterfront beschworen, die sich + unheilverkündend über der Region auftürmt. Der + magische Regen wird alles Erz rosten lassen und + so viele Waffen des Gegners zerstören. + This ritual conjurs up a dark + thunderstorm that affects a whole region. The + magic rain will let rust any ore and thus + destroy many weapons of the enemy. + + + Mit Hilfe dieses Zaubers kann der + Magier eigene Aura im Verhältnis 2:1 auf einen + anderen Magier des gleichen Magiegebietes + übertragen. + With the help of this spell, the + caster can transfer aura at a ratio of 2:1 to + another member of the same school of magic. + + + Der Zauberer erschafft eine Wand aus + Feuer in der angegebenen Richtung. Sie verletzt + jeden, der sie durchschreitet. + The spell creates an opaque wall of + fire in the gives direction that will harm + anyone passing through it. + + + In einem aufwendigen Ritual opfert der + Schwarzmagier einige Bauern und verteilt dann + die Leichen auf magische Weise in den Brunnen + der Region. + In a complicated ritual the sorcerer + sacrifices the lives of ten peasants and + magically spreads their corpses within the wells + of a region. + + + Vor den Augen der feindlichen Soldaten + opfert der Schwarzmagier die zehn Bauern in + einem blutigen, grausamen Ritual und beschwört + auf diese Weise Geister des Wahnsinns über die + feindlichen Truppen. Diese werden im Kampf + verwirrt reagieren und nicht in der Lage sein, + den Anweisungen ihrer Offiziere zu folgen. + Before the eyes of the enemy soldiers + the sorcerer sacrifices ten peasants in a bloody + ritual and thereby summons spirits of madness + upon the enemy troops. The enemy soldiers will + be in confusion during battle and no more be + able to follow the commands of their leaders. + + + Mit Hilfe dunkler Rituale beschwört + der Zauberer Dämonen aus der Sphäre der + Schatten. Diese gefürchteten Wesen können sich + fast unsichtbar unter den Lebenden bewegen, ihre + finstere Aura ist jedoch für jeden spürbar. Im + Kampf sind Schattendämonen gefürchtete Gegner. + Sie sind schwer zu treffen und entziehen ihrem + Gegner Kraft. + With the help of dark rituals the + sorcerer summons demons from the Sphere Of + Shadows. These fearsome creatures can walk + almost unseen among the living, but their dark + aura can be sensed by everyone. Shadow demons + are feared in combat for they are hard to hit + and have the ability to drain strength from + their victims. + + + Dieses Ritual beschwört wütende Elementargeister der + Hitze. Eine Dürre sucht das Land heim. Bäume verdorren, Tiere + verenden, und die Ernte fällt aus. Für Tagelöhner gibt es kaum noch + Arbeit in der Landwirtschaft zu finden. + This Ritual summons an angry elemental spirit that + puts a drought on the entire region. Trees wither, animals die of + thirst and the harvest is destroyed. Workers find little to no work + in farming. + + + Dieses Ritual bindet die bereits + entfliehenden Seelen einiger Kampfopfer an ihren + toten Körper, wodurch sie zu untoten Leben + wiedererweckt werden. Ob sie ehemals auf der + Seite des Feindes oder der eigenen kämpften, ist + für das Ritual ohne belang. + This ritual binds the escaping souls + of some casualties back to their dead bodies and + thus condemns them to an undead existance under + the control of the sorcerer. The ritual affects + the corpses of allies and foes alike - no matter + on which side of the battle the soldiers fought + before their death. + + + Dieses magische Artefakt verleiht dem + Träger die Stärke eines ausgewachsenen + Höhlentrolls. Seine Tragkraft erhöht sich auf + das 50fache und auch im Kampf werden sich die + erhöhte Kraft und die trollisch zähe Haut + positiv auswirken. + This artifact gives the one wearing it + the strength of a cavetroll. He will be able to + carry fifty times as much as normal and also in + combat his enhanced strength and tough troll + skin will serve him well. + + + Der Schwarzmagier kann mit diesem + dunklen Ritual einen Riss in das Gefüge der + Magie bewirken, der alle magische Kraft aus der + Region reißen wird. Alle magisch begabten in der + Region werden einen Großteil ihrer Aura + verlieren. + With this dark ritual the + chaossorcerer causes a deep rift to appear in + the astral balance that will tear all magical + power from a region. All spellcasters in that + region will lose most of their aura. + + + Dieses Ritual, ausgeführt vor einem + Kampf, verwirbelt die astralen Energien auf dem + Schlachtfeld und macht es so feindlichen Magier + schwieriger, ihre Zauber zu wirken. + This ritual, performed before a + battle, causes the astral energies on the + battlefield to whirl and churn and thereby makes + spellcasting more difficult for the enemy mages. + + + Diese Elementarbeschwörung ruft einen + Feuerteufel herbei, ein Wesen aus den tiefsten + Niederungen der Flammenhöllen. Der Feuerteufel + wird sich begierig auf die Wälder der Region + stürzen und sie in Flammen setzen. + This elemental summoning calls a fire + fiend, a creature from the deepest hell. The + demon will eagerly rush into the forests of a + region and set them ablaze. + + + Genau um Mitternacht, wenn die Kräfte + der Finsternis am größten sind, kann auch ein + Schwarzmagier seine Kräfte nutzen um + Verzauberungen aufzuheben. Dazu zeichnet er ein + Pentagramm in das verzauberte Objekt und beginnt + mit einer Anrufung der Herren der Finsternis. + Die Herren werden ihm beistehen, doch ob es ihm + gelingt, den Zauber zu lösen, hängt allein von + seiner eigenen Kraft ab. + At midnight, when the Powers of + Darkness are at their peak, the sorcerer can use + his powers to destroy enchantments. In order to + do so, he draws a pentagram on a surface of the + enchanted object and begins calling the Lords Of + Darkness. The Lords will aid him, but whether he + is able to undo the target spell or not depends + upon his own power. + + + Nur geflüstert wird dieses Ritual an + den dunklen Akademien an die Adepten + weitergegeben, gehört es doch zu den + finstersten, die je niedergeschrieben wurden. + Durch die Anrufung unheiliger Dämonen wird die + Kraft der lebenden Toten verstärkt und sie + verwandeln sich in untote Monster großer Kraft. + Only whispered the knowledge of + performing this ritual is passed to the adepts + of the dark academies, for it is one of the + darkest that has ever been written down. By + calling unholy demons the strength of the living + dead is greatly increased and they are turned + into undead monsters of immense power. + + + Mit einem düsteren Ritual und unter + Opferung seines eigenen Blutes beschwört der + Schwarzmagier einen großen Geist von der + Elementarebene der Gifte. Der Geist manifestiert + sich als giftgrüner Schwaden über der Region und + wird allen, die mit ihm in Kontakt kommen, + Schaden zufügen. + By performing a gruesome ritual and + sacrificing his own blood the Sorcerer conjurs + up a spirit from the Elemental Plane Of Poison. + It will take the form of a green cloud of toxic + gases that envelops a whole region and that will + harm anyone within. + + + Mit diesem dunklen Ritual erzeugt der + Magier einen Köder, der für Drachen einfach + unwiderstehlich riecht. Ob die Drachen aus der + Umgebung oder aus der Sphäre des Chaos stammen, + konnte noch nicht erforscht werden. Es soll + beides bereits vorgekommen sein. Der Köder hält + etwa 6 Wochen, muss aber in einem + drachengenehmen Terrain platziert werden. + Performing this dark ritual, the + sorcerer creates a bait that exhales an + irresistable scent to dragons. It is not known + whether the dragons come from surrounding + regions or if they have their origin in the + Sphere Of Chaos. The bait will exist for about + six weeks, but it must be placed in a tarrain + that is suitable for dragons. + + + Mit Hilfe dunkler Rituale beschwört + der Zauberer Dämonen aus der Sphäre der + Schatten. Diese gefürchteten Wesen können sich + fast unsichtbar unter den Lebenden bewegen, ihre + finstere Aura ist jedoch für jeden spürbar. Im + Kampf sind Schattenmeister gefürchtete Gegner. + Sie sind schwer zu treffen und entziehen ihrem + Gegner Kraft und Leben. + With the help of dark rituals the + sorcerer summons demons from the Sphere Of + Shadows. These fearsome creatures can walk + almost unseen among the living, but their dark + aura can be sensed by everyone. Shadowmasters + are feared in combat for they are hard to hit + and have the ability to drain strength and life + force from their victims. + + + 'Und so reibe das Blut eines wilden + Kämpfers in den Stahl der Klinge und beginne die + Anrufung der Sphären des Chaos. Und hast du + alles zu ihrem Wohlgefallen getan, so werden sie + einen niederen der ihren senden, das Schwert mit + seiner Macht zu beseelen...' + 'So take the blood of a fierce warrior + and apply it to the steel of the blade. Then + start calling the Spheres Of Chaos. If you did + everything to their pleasure, they will send a + minor one of their kind to fulfill the sword + with his power.' + + + Einem erfahrenen Magier wird + irgendwann auf seinen Wanderungen ein + ungewöhnliches Exemplar einer Gattung begegnen, + welches sich dem Magier anschließen wird. + During their travel, seasoned + magicians will occasionally befriend an extraordinary + creature of an unusual species that will join them. + + + Durch das Opfern von 200 Bauern kann + der Chaosmagier ein Tor zur astralen Welt + öffnen. Das Tor kann in der Folgewoche verwendet + werden, es löst sich am Ende der Folgewoche auf. + By sacrificing the lives of 200 + peasants, the chaossorcerer is able to open a + planar gate. This gate can be used during the + following week to transfer units to the astral + plane. It dissipates at the end of the following + week. + + + Der Zauberer sendet dem Ziel des + Spruches einen Traum. + The mentalist sends a dream to the + target of the spell. + Le mentaliste envoie un rêve à la + cible du sort. + + + Dieser Zauber vermag dem Gegner ein + geringfügig versetztes Bild der eigenen Truppen + vorzuspiegeln. Die Schattenritter haben keinen + effektiven Angriff und Verwundungen im Kampf + zerstören sie sofort. + This spell creates illusionary + duplicates of allied troops. The shadow knights + can't do real damage and are instantly destroyed + if wounded. + Ce sort crée des copies illusoires de + troupes alliées. Les guerriers illusoires ne + peuvent faire de dégats réels et sont + instantanément détruits lorsqu'ils sont blessés. + + + Der Traumweber beschwört vor dem + Kampf grauenerregende Trugbilder herauf, die + viele Gegner in Panik versetzen. Die Betroffenen + werden versuchen, vor den Trugbildern zu + fliehen. + Before a battle the mentalist creates + terrifying illusions of hideous creatures that + will cause panic among the enemies. Those who + believe in the illusions will try to flee from + battle. + + + Dieses magische Ritual beruhigt die + gequälten Seelen der gewaltsam zu Tode + gekommenen und ermöglicht es ihnen so, ihre + letzte Reise in die Anderlande zu beginnen. Je + Stufe des Zaubers werden ungefähr 50 Seelen ihre + Ruhe finden. Der Zauber vermag nicht, bereits + wieder auferstandene lebende Tote zu erlösen, da + deren Bindung an diese Welt zu stark ist. + This ritual calms the tortured souls + of those who died a violent death and finally + releases them to the Otherlands. About 50 souls + per level of the spell will be released. The + spell will not affect existing undead, because + they are too strongly tied to the Material + World. + + + Mit Hilfe dieses Zaubers kann der + Traumweber die Illusion eines beliebigen + Gebäudes erzeugen. Die Illusion kann betreten + werden, ist aber ansonsten funktionslos und + benötigt auch keinen Unterhalt. Sie wird einige + Wochen bestehen bleiben. + With this spell the mentalist can + create the illusion of any building. The + illusion can be entered, but it has no function + and requires no maintenance. It will remain + existing for several weeks. + + + Mit Hilfe dieses Zaubers kann der + Traumweber eigene Aura im Verhältnis 2:1 auf + einen anderen Traumweber übertragen. + With the help of this spell the + mentalist can transfer aura at a ratio of 2:1 to + another mentalist. + + + Mit Hilfe dieses arkanen Rituals + vermag der Traumweber die wahre Gestalt einer + Gruppe + zu verschleiern. Unbedarften Beobachtern + erscheint + sie dann als einer anderen Rasse zugehörig. + With the help of this ritual the + mentalist is able to conceal the true form of a + target unit. To unknowing observers all persons + in the target unit appear to be of a different + race. + + + Dieser Zauber ermöglicht es dem + Traumweber, in die Träume einer Einheit + einzudringen und so einen Bericht über die + Umgebung zu erhalten. + This spell enables the mentalist to + penetrate the dreams of a target unit and gather + information about that unit's surroundings. He + will receive a report from the corresponding + region. + + + Dieser Kampfzauber führt dazu, dass + einige Gegner im Kampf unter schwerer Müdigkeit + leiden. Die Soldaten verschlafen manchmal ihren + Angriff und verteidigen sich schlechter. + This combat spell causes several + enemies to suffer from an unnatural tiredness + during combat. The soldiers will defend + themselves worse than normal and sometimes sink + into a slumber instead of attacking. + + + Stirbt ein Krieger im Kampf so macht + sich seine Seele auf die lange Wanderung zu den + Sternen. Mit Hilfe eines Rituals kann ein + Traumweber versuchen, die Seele wieder + einzufangen und in den Körper des Verstorbenen + zurückzubringen. Zwar heilt der Zauber keine + körperlichen Verwundungen, doch ein Behandelter + wird den Kampf überleben. + When a warrior dies in a battle, his + soul begins its long journey to the stars. With + the help of this ritual, the mentalist can try + to catch those escaping souls and bring them + back to their bodies. The spell does not heal + physical injuries, but an affected person will + survive the battle. + + + Mit diesem Spruch kann der Traumweber + versuchen, die Verzauberungen einer einzelnen + Einheit zu erkennen. Von allen Sprüchen, die + seine eigenen Fähigkeiten nicht überschreiten, + wird er einen Eindruck ihres Wirkens erhalten + können. Bei stärkeren Sprüchen benötigt er ein + wenig Glück für eine gelungene Analyse. + With this spell the mentalist can + attempt to detect enchantments on a target unit. + He will get an idea of the effect of all spells + that don't exceed his own abilities. If a spell + is stronger, it takes a little luck for a + successful analysis. + + + Dieser Zauber führt in der betroffenen + Region für einige Wochen zu Schlaflosigkeit und + Unruhe. Den Betroffenen fällt das Lernen + deutlich schwerer. + This spell causes insomnia and + restlessness in a whole region for several + weeks. All affected persons will learn much + slower than normal. + + + Dieser Zauber läßt einige feindliche + Kämpfer einschlafen. Schlafende Kämpfer greifen + nicht an und verteidigen sich schlechter, sie + wachen jedoch auf, sobald sie im Kampf getroffen + werden. + This spell causes several enemies to + fall asleep. Sleeping warriors don't attack and + defend themselves worse than normal, but they'll + wake up if they get hit during combat. + + + Mit diesem Zauber dringt der + Traumweber in die Gedanken und Traumwelt seines + Opfers ein und kann so seine intimsten + Geheimnisse ausspähen. Seine Fähigkeiten, seinen + Besitz und seine Parteizugehörigkeit wird nicht + länger ungewiss sein. + With this spell the mentalist + penetrates the thoughts and dreams of his victim + to reveal his most intimate secrets. The + target's faction, skills and possessions will no + longer be unknown. + + + Der Magier beschwört ein kleines Monster, einen Alp. Dieses bewegt sich + langsam auf sein Opfer zu (das sich an einem beliebigen Ort an der Welt + befinden kann, der Magier oder seine Partei braucht es nicht zu sehen). + Sobald das Opfer erreicht ist, wird es gnadenlos gequält, und nur durch + einen starken Gegenzauber oder den Tod des beschwörenden Magiers kann + das Opfer wieder Frieden finden. Bei der Beschwörung des Alps verliert + der Magier einen kleinen Teil seiner Aura für immer. + The magician spawns a little monster, a nightmare. The nightmare slowly + approaches its victim (which may be at an arbitrary place in eressea, it + is not needed for the magician or his party to see the victim). As soon + as + the victim is reached the nightmare starts to torment it without mercy, + only a powerfull counter spell or the death of the casting magician can + redeem + the victim. When spawning the nightmare the magician loses a small amount + of + his aura forever. + + + Ein mit diesem Zauber belegtes Drachenauge, welches zum Abendmahle + verzehrt wird, erlaubt es dem Benutzer, in die Träume einer anderen + Person einzudringen und diese zu lesen. Lange Zeit wurde eine solche + Fähigkeit für nutzlos erachtet, bis die ehemalige waldelfische + Magistra für Kampfmagie, Liarana Sonnentau von der Akademie Thall, + eine besondere Anwendung vorstellte: Feldherren träumen vor großen + Kämpfen oft unruhig und verraten im Traum ihre Pläne. Dies kann dem + Anwender einen großen Vorteil im kommenden Kampf geben. Aber Vorsicht: + Die Interpretation von Träumen ist eine schwierige Angelegenheit. + An enchanted eye of a dragon gives the person who eats it for supper the + power to see + other people's dreams. For a long time this abillity was counted as + beeing + useless until + the former elfish mistress for theurgy of war, Liarana Sonnentau from + the + academy Thall, + presented a special appliance for this artefact: Before a battle + captains + often have an + uncomfortable sleep and betray their plans in their dreams. This might + give the user of + the artefact a small advantage in the upcoming battle, but be warned: + Interpreting dreams + is a difficult exercise. + + + Mit diesem Spruch kann der Zauberer eine Sphäre der + Unsichtbarkeit + erschaffen. Die Späre macht ihren Träger sowie neunundneunzig weitere + Personen in derselben Einheit unsichtbar. + Using this spell the magician can create a Sphere of + Invisibility. This artefact hides the person bearing it and one hundred + persons in the same unit. + + + Dieser Zauber ermöglicht es dem + Traumweber, den Schlaf aller aliierten Einheiten + in + der Region so zu beeinflussen, dass sie für + einige + Zeit einen Bonus in allen Talenten bekommen. + This spell allows the mentalist to + influence the sleep of all allied units in a + region + in such a way that they will gain a bonus to all + talents for some time. + + + Dieser Zauber ermöglicht es dem + Traumweber die natürlichen und aufgezwungenen + Traumbilder einer Person, eines Gebäudes, + Schiffes oder einer Region zu unterscheiden und + diese zu entwirren. + This spell allows the mentalist to + distinguish between the natural and unnatural + dreams of a person, a ship, a building or a + region and remove those that are of magical + origin. + + + Aus 'Die Gesänge der Alten' von + Firudin dem Weisen: 'Diese verführerische kleine Melodie + und einige einschmeichelnde Worte überwinden das + Misstrauen der Bauern im Nu. Begeistert werden sie sich + Euch anschliessen und selbst Haus und Hof in Stich + lassen.' + From the 'Songs of the Elder' by + Firudin the Sage: 'This enticing little melody and its + ingratiating words will lure the peasants in no time. + They will leave home and hearth to follow your lead.' + + + Dieser fröhliche Gesang wird sich wie + ein Gerücht in der Region ausbreiten und alle Welt in + Feierlaune versetzten. Überall werden Tavernen und + Theater gut gefüllt sein und selbst die Bettler satt + werden. + This joyous song will spread like + wildfire throughout the region and cause festive spirits + in all the population. All the taverns and theaters will + be packed to the brim and even the beggars will not go + hungry. + + + Einem erfahrenen Magier wird + irgendwann auf seinen Wanderungen ein ungewöhnliches + Exemplar einer Gattung begegnen, welches sich dem Magier + anschließen wird. + Once during his travels, the seasoned + magician will meet an extraordinary creature of its species + that will join him. + + + Mit diesem Zauber greift der Magier + direkt den Geist seiner Gegner an. Ein Schlag aus + astraler und elektrischer Energie trifft die Gegner, + wird die Magieresistenz durchbrochen, verliert ein Opfer + permanent einen Teil seiner Erinnerungen. Wird es zu oft + ein Opfer dieses Zaubers kann es daran sterben. + With this spell the mentalist directly + attacks his enemies' souls. A blast of astral and + electrical energy strikes the foes. If a victim fails to + resist the magic, he will permanently lose part of his + memories. Being the target of this spell for too many + times may result in death. + + + Dieser Zauber - dessen Anwendung in + den meisten Kulturen streng verboten ist - löst im Opfer + ein unkontrollierbares Verlangen nach körperlicher Liebe + aus. Die betroffenen Personen werden sich Hals über Kopf + in ein Liebesabenteuer stürzen, zu blind vor Verlangen, + um an etwas anderes zu denken. Meistens bereuen sie es + einige Wochen später... + This spell - whose use is forbidden in + most cultures - creates an uncontrollable desire for + physical love in the victim. The affected persons will + rush head over heels into a love affair, unable to think + of anything else. Most of them will regret this a few + months later... + + + + + + Winter + winter + + + Sommer + summer + + + Frühling + spring + + + Herbst + fall + + + die erste Woche + the first week + + + die zweite Woche + the second week + + + die letzte Woche + the last week + + + der ersten Woche + of the first week + + + der zweiten Woche + of the second week + + + der letzten Woche + of the third week + + + Feldsegen + harvest moon + + + Nebeltage + impenetrable fog + + + Sturmmond + storm moon + + + Herdfeuer + hearth fire + + + Eiswind + icewind + + + Schneebann + snowbane + + + Blütenregen + flowerrain + + + Mond der milden Winde + mild winds + + + Sonnenfeuer + sunfire + + + des zweiten Zeitalters + the second age + + + neuer Zeitrechnung + of the new age + + + + + + Gemein + common + + + Kein Magiegebiet + no magic school yet + + + Illaun + Illaun + + + Tybied + Tybied + + + Gwyrrd + Gwyrrd + + + Cerddor + Cerddor + + + Draig + Draig + + + + + Baum + tree + + + Bäume + trees + + + + Mallornbaum + mallorn tree + + + Mallornbäume + mallorn trees + + + ALLIANZ + ALLIANCE + + + AUSSTOSSEN + KICK + + + NEU + NEW + + + KOMMANDO + COMMAND + + + VERLASSEN + LEAVE + + + BEITRETEN + JOIN + + + EINLADEN + INVITE + + + Steine + stones + + + + Pferde + horses + + + Bauern + peasants + + + Silber + silver + + + Laen + laen + + + + Schößlinge + saplings + + + + Mallornschößlinge + mallorn saplings + + + + Bäume + trees + + + + Mallorn + mallorn + + + + Eisen + iron + + + + Winter + winter + + + + Frühling + spring + + + + Sommer + summer + + + + Herbst + autumn + + + + Vorlage für den nächsten Zug: + Template for the next turn: + + + + Wir schreiben %s des Monats %s im Jahre %d %s. + It is %s of the month of %s in the %d. year of %s. + + + + Wir schreiben %s des Monats %s im Jahre %d %s. Es ist + %s. + It is %s of the month of %s in the %d. year of %s. It is + %s. + + + + aggressiv + aggressive + + + + vorne + front + + + + hinten + rear + + + + defensiv + defensive + + + + flieht + fleeing + + + + kämpft nicht + not fighting + + + + bekommt keine Hilfe + gets no aid + + + + Attacke gegen: + Attacked against + + + + Kämpft gegen: + Fighting against + + + + Hilft: + Helping + + + + Heer + army + + + + Unbekannte Partei + unknown faction + + + einer unbekannten Partei + an unknown faction + + + und + and + + + + Das Schiff des Elfen hat ein rotes Segel + + + + Der Zwerg hat eine Nuss dabei + + + + Die Katze führt eine Hellebarde + + + + Das Schiff mit dem grünen Segel liegt links neben dem + mit + einem weissen Segel + + + + Auf dem Schiff mit grünen Segeln kam der Speerkämpfer + + + + Der Krieger mit dem Kreis im Wappen hat einen Keks + + + + Der Krieger des mittleren Schiffs hat ein Schwert + + + + Auf dem gelben Segel prankt ein Kreuz als Wappen + + + + Der Mensch kam mit dem ersten Schiff + + + + Das Schiff mit dem Stern im Wappen liegt neben dem der + einen Mandelkern hat + + + + Das Schiff des Kriegers, der ein Apfel hat, liegt neben + dem, der ein Kreuz als Wappen hat + + + + Der Krieger mit dem Turm im Wappen trägt eine Axt + + + + Das Schiff des Menschen liegt neben dem blauen Schiff + + + + Das Insekt trägt einen Baum als Wappen + + + + Das Schiff mit dem Stern im Wappen liegt neben dem des + Kriegers, der einen Zweihänder führt + + + + Held + hero + + + + Helden + heroes + + + + + + Dunkel + dark + + + + Schwarz + black + + + + Licht + light + + + + Flammen + flame + + + + Eis + ice + + + + Klein + gully + + + + Hoch + high + + + + Hügel + hill + + + + Berg + mountain + + + + Wald + wood + + + + Sumpf + swamp + + + + Schnee + snow + + + + Sonnen + sun + + + + Mond + moon + + + + See + sea + + + + Tal + valley + + + + Schatten + shadow + + + + Höhlen + cave + + + + Blut + blood + + + + Wild + wild + + + + Chaos + chaos + + + + Nacht + night + + + + Nebel + mist + + + + Grau + grey + + + + Frost + cold + + + + Finster + gloom + + + + Düster + black + + + + Sternen + star + + + + + 'Ho ho ho!' Ein dicker Gnom fliegt auf einem von + 8 Jungdrachen gezogenen Schlitten durch die Nacht und vermacht Deiner + Partei ein Sonnensegel. (Um das Segel einer Einheit zu geben, gib + ihr den Befehl 'BEANSPRUCHE 1 Sonnensegel'). + 'Ho ho ho!' A fat little gnome Gnom on a sled + pulled by 8 young dragons flies through the stary night and presents + your faction with a solar sail. (To claim this item, one of your units + must issue the order 'CLAIM 1 solar sail'. + + + + 'Ho ho ho!' Ein dicker Gnom fliegt auf einem von + 8 Jungdrachen gezogenen Schlitten durch die Nacht und vermacht Deiner + Partei eine Phiole mit Sternenstaub. (Informationen dazu gibt es mit + BEANSPRUCHE und ZEIGE). + 'Ho ho ho!' A fat little gnome Gnom on a sled + pulled by 8 young dragons flies through the stary night and presents + your faction with a vial of stardust. (To get more information about + this item, use the CLAIM and SHOW commands). + + + + 'Ho ho ho!' Ein dicker Gnom fliegt auf einem von + 8 Jungdrachen gezogenen Schlitten durch die Nacht und vermacht Deiner + Partei einen wundervoll geschmueckten Weihnachtsbaum. (Informationen dazu gibt es mit + BEANSPRUCHE und ZEIGE). + 'Ho ho ho!' A fat little gnome Gnom on a sled + pulled by 8 young dragons flies through the stary night and presents + your faction with a beautifully decorated tree. (To get more information about + this item, use the CLAIM and SHOW commands). + + + + Gral + grail + + + + Grale + grails + + + + Lerntrank + brain boost + + + + Lerntränke + brain boosts + + + + GE je + stone per + + + + GE je + stones per + + + + GE + stone + + + + GE + stones + + + + bewacht die Region + guards the region + + + + und + and + + + + Dorfbewohner + Villagers + + + + Bauernmob + Angry mob + + + + Aufgebrachte Bauern + Furious peasants + + + + Söldner + Mercenaries + + + + Sumpfbewohner + Swamp people + + + + Waldbewohner + Woodsmen + + + + Nomaden + Nomads + + + + Eisleute + Ice people + + + + Bergbewohner + Mountain people + + + + Magie der Elemente + Magic of the Elements + + + + Schwerter, Armbrüste, Langbögen + Swords, Crossbows and Longbows + + + + Gorms Almanach der Rationellen Kriegsführung + Gorm's Almanach of Rational War + + + + Katamarane, Koggen, Karavellen + The dragonship, the caravell and the longboat + + + + Wege der Sterne + Ways of the Start + + + + Nadishahs Kleine Gift- und Kräuterkunde + Nadishah's collected lore on poisonous and beneficial herbs + + + + Mandricks Kompendium der Alchemie + Mandrick's alchemistic compendium + + + + Die Konstruktion der Burgen und Schlösser von Zentralandune + + + + Die Esse + + + + Über die Gewinnung von Erzen + + + + Barinions Lieder, eine Einführung für Unbedarfte + + + + die Ruine eines alten Tempels + the ruins of an ancient temple + + + + eine alte Burgruine + the ruins of a castle + + + + ein zerfallenes Bauernhaus + a dilapitated farm + + + + eine Leiche am Wegesrand + a corpse by the wayside + + + + eine Leiche am Wegesrand + a corpse by the wayside + + + + Feuerdrache + fire dragon + + + + Ein Alp starb, ohne sein Ziel zu erreichen. + An alp died before it reached its target. + + + + unbewaffnet + unarmed + + + + Trefferpunkte + hitpoints + + + + Rüstung + armor + + + + Angriff + attack + + + + Angriffe + attacks + + + + Verteidigung + defense + + + + Kann Waffen benutzen. + May use weapons. + + + + Ist durch Stichwaffen, Bögen und Armbrüste schwer zu verwunden. + Is hard to hit by piercing weapons. + + + + Ist durch Hiebwaffen schwer zu verwunden. + Is hard to hit by slashing weapons. + + + + Ist durch Schlagwaffen und Katapulte schwer zu verwunden. + Is hard to hit by blunt weapons and catapults. + + + + ein Angriff mit der Waffe oder unbewaffnet + an attack with a weapon or an unarmed attack + + + + ein unbewaffneter Angriff + an unarmed attack + + + + ein magischer Angriff + a magical attack + + + + Klon von %s + Clone of %s + + + + ein Angriff, der Gebäudeschaden verursacht + an attack causing structural damage to buildings + + + + Präkampfzauber + pre-combat spell + + + + Postkampfzauber + post-combat spell + + + + Kampfzauber + combat spell + + + + Normaler Zauber + regular spell + + + + Es ist Winter, und Insekten können nur in Wüsten oder mit Hilfe des Nestwärme-Tranks Personen rekrutieren. + It is winter, and insects can only recruit in deserts or with the aid of nestwarmth potions. + + + + Es ist Spätherbst, und diese Woche ist die letzte vor dem Winter, in der Insekten rekrutieren können. + + + + Eigentümer + Owner + + + + + eine Straße + a road + + + + Straßen + roads + + + + Straße + road + + + + eine zu %d%% vollendete Straße + a road that is %d%% complete + + + + ein Straßenanschluß + a connection to another road + + + + eine unvollständige Straße + an incomplete road + + + + Wand + wall + + + + eine Wand + a wall + + + + Feuerwand + firewall + + + + eine Feuerwand + a firewall + + + + Nebelwand + wall of fog + + + + eine Nebelwand + a wall of fog + + + + Irrlichter + wisps + + + + eine Gruppe von Irrlichtern + a cloud of wisps + + + + gewaltiges offenes Tor + massive open door + + + + ein gewaltiges offenes Tor + a massive open door + + + + gewaltiges verschlossenes Tor + massive locked door + + + + ein gewaltiges verschlossenes Tor + a massive locked door + + + + Illusionswand + illusionary wall + + + + eine Illusionswand + an illusionary wall + + + + + + Die Region ist verwüstet, der Boden karg. + The region is ravaged, the ground infertile. + + + + Einheit-Nr + unitid + + + + Schiff-Nr + shipid + + + + völker + tribes + + + + Gebäude-Nr + buildingid + + + + + Aura + aura + + + + Rasse + race + + + + Zauber-ID + spellid + + + + Richtung + direction + + + + Gebäudetyp + buildingtype + + + + diff --git a/res/en/strings.xml b/res/en/strings.xml new file mode 100644 index 000000000..893007b43 --- /dev/null +++ b/res/en/strings.xml @@ -0,0 +1,1680 @@ + + + + + + + ADDRESSES + + + REPORT + + + BZIP2 + + + COMPUTER + + + DEBUG + + + ITEMPOOL + + + SCORE + + + SILVERPOOL + + + STATISTICS + + + EXPRESS + + + ZIPPED + + + TEMPLATE + + + SKILLCHANGES + + + + INFO + + + + + caravel + + + boat + + + longboat + + + dragonship + + + trireme + + + balloon + + + + + a caravel + + + a boat + + + a longboat + + + a balloon + + + a dragonship + + + a trireme + + + + + active volcano + + + corridor + + + desert + + + firewall + + + fog + + + forest + + + glacier + + + glacier + + + hallway + + + hell + + + highland + + + iceberg + + + maelstrom + + + mountain + + + ocean + + + plain + + + swamp + + + thick fog + + + volcano + + + magical storm + + + + the volcano of %s + + + a %s + + + the deserts of %s + + + a %s + + + fog_trail %s + + + the forests of %s + + + the glacier of %s + + + Wall + + + the %s + + + %s + + + the highlands of %s + + + a %s + + + the mountains of %s + + + the %s + + + the plain of %s + + + the swamps of %s + + + %s + + + the volcano of %s + + + a %s + + + + caldera + + + portal + + + + + NW + + + NE + + + East + + + SE + + + SW + + + West + + + + west + + + northwest + + + northeast + + + east + + + southwest + + + southeast + + + + an unknown unit + + + + Dispatches + + + Events + + + Warnings and Errors + + + Economy and Trade + + + Resources and Production + + + Magic and Artefacts + + + Movement and Travel + + + Learning and Teaching + + + Battles + + + Miscellaneous + + + New Spells + + + + + academy + + + blessed stonecircle + + + caravanserei + + + dam + + + structure + + + harbour + + + fairy castle + + + inn + + + lighthouse + + + mage tower + + + mine + + + monument + + + quarry + + + sawmill + + + smithy + + + stable + + + stonecircle + + + tunnel + + + + + foundation + + + tradepost + + + fortification + + + tower + + + castle + + + fortress + + + citadel + + + + + herb + + + vial + + + vials + + + + + silver + + + silver + + + hp + + + hps + + + aura + + + auras + + + permaura + + + permauras + + + peasant + + + peasants + + + + + almond + + + almonds + + + amulet + + + amulets + + + antimagic crystal + + + antimagic crystals + + + amulet of chastity + + + amulets of chastity + + + amulet of the kitten + + + amulets of the kitten + + + amulet of darkness + + + amulets of darkness + + + amulet of gathering + + + amulets of gathering + + + amulet of healing + + + amulets of healing + + + amulet of true seeing + + + amulets of true seeing + + + apple + + + apples + + + aurafocus + + + aurafocuses + + + axe + + + axes + + + bow + + + bows + + + cart + + + carts + + + catapult + + + catapults + + + chainmail + + + chainmails + + + cookie + + + cookies + + + crossbow + + + crossbows + + + dolphin + + + dolphins + + + dragonblood + + + dragonblood + + + dragonhead + + + dragonheads + + + dragonhoard + + + dreameye + + + dreameyes + + + elven horse + + + elven horses + + + eye of dragon + + + eye of dragons + + + fairy boots + + + fairy boots + + + flaming sword + + + flaming swords + + + elven bow + + + elven bows + + + claymore + + + claymores + + + halberd + + + halberds + + + healingpotion + + + healingpotions + + + herbbag + + + herbbags + + + horse + + + horses + + + iron + + + iron + + + laen + + + laen + + + laen chainmail + + + laen chainmails + + + laen shield + + + laen shields + + + laen sword + + + laen swords + + + lance + + + lances + + + wood + + + wood + + + magic bag + + + magic bags + + + bag of conservation + + + bags of conservation + + + mallorn + + + mallorn + + + mallorn bow + + + mallorn bows + + + mallorn crossbow + + + mallorn crossbows + + + mallorn lance + + + mallorn lances + + + mallorn spear + + + mallorn spear + + + silverbag + + + silverchest + + + returnticket for the grand museum + + + returntickets for the grand museum + + + ticket to the grand museum + + + tickets to the grand museum + + + nut + + + nuts + + + pegasus + + + pegasi + + + man + + + men + + + platemail + + + platemails + + + pangolin + + + pangolins + + + presspass + + + presspasses + + + ring of invisibility + + + rings of invisibility + + + ring of power + + + rings of power + + + ring of quick fingers + + + rings of quick fingers + + + ring of regeneration + + + rings of regeneration + + + runesword + + + runeswords + + + rustychainmail + + + rustychainmails + + + rusty shield + + + rusty shields + + + rusty sword + + + rusty swords + + + seaserpenthead + + + seaserpentheads + + + shield + + + shields + + + sack of holding + + + sacks of holding + + + spear + + + spears + + + stone + + + stones + + + sword + + + swords + + + pot of toadslime + + + pots of toadslime + + + trollbelt + + + trollbelts + + + unit + + + units + + + potion of skills + + + potions of skills + + + astralcrystal + + + astralcrystals + + + seed + + + seeds + + + mallorn seed + + + mallorn seeds + + + firework + + + fireworks + + + gingerbread heart + + + gingerbread hearts + + + + + balm + + + spice + + + gem + + + gems + + + myrrh + + + oil + + + silk + + + incense + + + balm + + + spice + + + myrrh + + + oil + + + silk + + + incense + + + + + Belt of Heroic Legends + + + Belts of Heroic Legends + + + + + flatroot + + + flatroots + + + tangy temerity + + + tangy temerities + + + owlsgaze + + + owlsgazes + + + spider ivy + + + spider ivies + + + cobalt fungus + + + cobalt fungi + + + elvendear + + + elvendears + + + bugleweed + + + bugleweeds + + + knotroot + + + knotroots + + + bubblemorel + + + bubblemorels + + + waterfinder + + + waterfinders + + + peyote + + + peyote + + + sand reeker + + + sand reekers + + + windbag + + + windbags + + + fjord fungus + + + fjord fungi + + + mandrake + + + mandrakes + + + rock weed + + + rock weed + + + gapgrowth + + + gapgrowths + + + cave lichen + + + cave lichen + + + ice begonia + + + ice begonias + + + white hemlock + + + white hemlocks + + + snowcrystal petal + + + snowcrystal petals + + + seven mile tea + + + seven mile teas + + + goliath water + + + goliath waters + + + water of life + + + waters of life + + + busybeer + + + busybeers + + + ointment + + + ointments + + + peasant blood + + + peasant bloods + + + brain wax + + + brain waxes + + + duncebun + + + duncebuns + + + potion of nest warmth + + + potions of nest warmth + + + horsepower potion + + + horsepower potions + + + berserkers blood potion + + + berserkers blood potions + + + peasant love potion + + + peasant love potion + + + potion of truth + + + potions of truth + + + elixir of power + + + elixirs of power + + + healing potion + + + healing potions + + + + + AGGRESSIVE + + + ALL + + + EACH + + + NUMBER + + + AURA + + + TREES + + + PEASANTS + + + AID + + + GUARD + + + CASTLE + + + DEFENSIVE + + + UNIT + + + ERESSEA + + + FLEE + + + FOREIGN + + + BUILDING + + + ITEMS + + + GIVE + + + MERCY + + + HELP + + + REAR + + + AFTER + + + CONTROL + + + HERBS + + + COMBAT + + + NOT + + + NEXT + + + FACTION + + + FACTIONSTEALTH + + + PAUSE + + + MEN + + + PRIVATE + + + REGION + + + SHIP + + + SILVER + + + ROADS + + + LEVEL + + + TEMPORARY + + + POTIONS + + + FOR + + + BEFORE + + + FRONT + + + SPELLS + + + + + alchemy + + + armoursmithing + + + bow + + + masonry + + + cartmaking + + + catapult + + + crossbow + + + entertainment + + + espionage + + + forestry + + + herbalism + + + magic + + + melee + + + mining + + + perception + + + polearm + + + quarrying + + + riding + + + roadwork + + + sailing + + + shipcraft + + + endurance + + + stealth + + + tactics + + + taxation + + + trade + + + taming + + + unarmed combat + + + weaponsmithing + + + + + + // + + + WORK + + + ATTACK + + + BANNER + + + STEAL + + + BESIEGE + + + NAME + + + USE + + + DESCRIBE + + + PRAY + + + ENTER + + + GUARD + + + BID + + + MESSAGE + + + DEFAULT + + + EMAIL + + + END + + + RIDE + + + FOLLOW + + + RESEARCH + + + GM + + + GROUP + + + HELP + + + JIHAD + + + COMBATSPELL + + + BUY + + + CONTACT + + + COMBAT + + + TEACH + + + LEARN + + + SUPPLY + + + LOCALE + + + MAKE + + + MOVE + + + RESTART + + + NUMBER + + + SACRIFICE + + + OPTION + + + PASSWORD + + + PLANT + + + PIRACY + + + PREFIX + + + RECRUIT + + + REPORT + + + RESERVE + + + ROUTE + + + SABOTAGE + + + SORT + + + SPY + + + QUIT + + + SYNONYM + + + HIDE + + + CARRY + + + TAX + + + ENTERTAIN + + + ORIGIN + + + FORGET + + + SELL + + + LEAVE + + + CAST + + + SHOW + + + DESTROY + + + GROW + + + LYCANTROPE + + + + + Options + + + Level + + + Political Status + + + Herbs required + + + under construction + + + damage + + + Your faction has been eliminated. We hope that you had a good time, and if you liked the game, you should sign up and play again. + + + + skills + + + has + + + size + + + spells + + + combat spells + + + none + + + Addresses + + + anonymous + + + attack + + + defense + + + armour + + + damage + + + + + wand + + + wands + + + + + + northwest coast + + + northeast coast + + + east coast + + + southeast coast + + + southwest coast + + + west coast + + + + + No orders were received for your faction! + + + + + Mistelzweig + mistletoe + + + Mistelzweige + mistletoes + + diff --git a/res/equipment.xml b/res/equipment.xml new file mode 100644 index 000000000..935de5806 --- /dev/null +++ b/res/equipment.xml @@ -0,0 +1,399 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/fr/strings.xml b/res/fr/strings.xml new file mode 100644 index 000000000..850085eaf --- /dev/null +++ b/res/fr/strings.xml @@ -0,0 +1,2082 @@ + + + + + + PASSAGE + + + XEPOTION + + + XEBALLON + + + XELAEN + + + GUERRE + + + PAIX + + + XONTORMIA + + + ALLIANCE + + + ADRESSES + + + RAPPORT + + + BZIP2 + + + ORDINATEUR + + + DEBOGUER + + + RESSOURCES COMMUNES + + + SCORE + + + ARGENT COMMUN + + + STATISTIQUES + + + EXPRESS + + + ZIPPE + + + MODELE + + + MODIFICATIONS + + + + INFO + + + + + nef + + + chaloupe + + + barge + + + drakkar + + + galère + + + ballon + + + + + une nef + + + une chaloupe + + + une barge + + + un ballon + + + un drakkar + + + une galère + + + + + volcan actif + + + couloir + + + désert + + + mur de feu + + + brume + + + forêt + + + glacier + + + vestibule + + + l'enfer + + + colline + + + iceberg + + + maelström + + + montagne + + + océan + + + plaine + + + marais + + + brouillard + + + volcan + + + tempête magique + + + + le volcan %s + + + un %s + + + le désert de %s + + + un %s + + + fog_trail %s + + + la forêt de %s + + + le glacier de %s + + + le %s + + + %s + + + les collines de %s + + + un %s + + + un %s + + + les montagnes de %s + + + l'%s + + + la plaine de %s + + + les marais de %s + + + %s + + + le volcan de %s + + + une %s + + + + caldera + + + portail + + + + + NO + + + NE + + + Est + + + SE + + + SO + + + Ouest + + + + ouest + + + nord-ouest + + + nord-est + + + est + + + sud-ouest + + + sud-est + + + + une unité inconnue + + + + Messages et Evénements + + + Avertissements et Erreurs + + + Economie et Commerce + + + Ressources et Production + + + Magie et Reliques + + + Déplacements et Voyages + + + Apprentissage et Enseignement + + + Batailles + + + Divers + + + Nouveaux Sorts + + + + + université + + + cromlech sacré + + + caravansérail + + + barrage + + + bâtiment + + + port + + + château illusoire + + + auberge + + + phare + + + donjon + + + mine + + + monument + + + carrière + + + scierie + + + forge + + + écurie + + + cromlech + + + tunnel + + + + + palissade + + + comptoir + + + rempart + + + tour + + + château + + + place-forte + + + citadelle + + + + + plante + + + fiole + + + fioles + + + + + écu + + + écus + + + point de vie + + + points de vie + + + aura + + + aura + + + aura permanente + + + aura permanente + + + paysan + + + paysans + + + + + amande + + + amandes + + + amulette + + + amulettes + + + cristal antimagie + + + cristaux antimagie + + + amulette de chasteté + + + amulettes de chasteté + + + amulette du chaton + + + amulettes du chaton + + + amulette de ténèbres + + + amulettes de ténèbres + + + amulette de rassemblement + + + amulettes de rassemblement + + + amulette de soin + + + amulettes de soin + + + amulette de vérité + + + amulettes de vérité + + + pomme + + + pommes + + + focus + + + foci + + + hache + + + haches + + + arc + + + arcs + + + chariot + + + chariots + + + catapulte + + + catapultes + + + cotte de mailles + + + cottes de mailles + + + gâteau + + + gâteaux + + + arbalète + + + arbalètes + + + dauphin + + + dauphins + + + sang de dragon + + + sang de dragon + + + tête de dragon + + + têtes de dragons + + + trésor de dragon + + + oniroeil + + + oniryeux + + + cheval elfique + + + chevaux elfiques + + + oeil de dragon + + + yeux de dragon + + + bottes elfiques + + + bottes elfiques + + + épée ardente + + + épées ardentes + + + grand arc + + + grands arcs + + + claymore + + + claymores + + + halebarde + + + halebardes + + + potion de soin + + + potions de soin + + + sac de plantes + + + sacs de plantes + + + cheval + + + chevaux + + + lingot + + + lingots + + + laen + + + laen + + + cotte en laen + + + cottes en laen + + + bouclier en laen + + + boucliers en laen + + + épée en laen + + + épées en laen + + + lance + + + lances + + + stère + + + stères + + + sac magique + + + sacs magiques + + + sac de conservation + + + sacs de conservation + + + mallorn + + + mallorn + + + arc en mallorn + + + arcs en mallorn + + + arbalète en mallorn + + + arbalètes en mallorn + + + lance en mallorn + + + lances en mallorn + + + épieu en mallorn + + + épieux en mallorn + + + bourse + + + cassette + + + returnticket for the grand museum + + + returntickets for the grand museum + + + ticket to the grand museum + + + tickets to the grand museum + + + noix + + + noix + + + pégase + + + pégases + + + homme + + + hommes + + + armure de plates + + + armures de plates + + + carte de presse + + + cartes de presse + + + anneau d'invisibilité + + + anneaux d'invisibilité + + + anneau de pouvoir + + + anneaux de pouvoir + + + anneau de dextérité + + + anneaux de dextérité + + + anneau de régénération + + + anneaux de régénération + + + épée runique + + + épées runiques + + + cotte de mailles rouillée + + + cottes de mailles rouillées + + + bouclier rouillé + + + boucliers rouillés + + + épée rouillée + + + épées rouillées + + + tête de serpent de mer + + + têtes de serpents de mer + + + bouclier + + + boucliers + + + sac de contenance + + + sacs de contenance + + + épieu + + + épieux + + + pierre + + + pierres + + + épée + + + épées + + + pot de bave de crapaud + + + pots de bave de crapaud + + + ceinture de troll + + + ceintures de trolls + + + unité + + + unités + + + potion de compétences + + + potions de compétences + + + cristal astral + + + cristaux astraux + + + graine + + + graines + + + graine de mallorn + + + graines de mallorn + + + feu d'artifice + + + feux d'artifice + + + coeur de pain d'épices + + + coeurs de pain d'épices + + + + + baume + + + épices + + + joyau + + + joyaux + + + myrrhe + + + huile + + + soie + + + encens + + + baume + + + épices + + + myrrhe + + + huile + + + soie + + + encens + + + + + Ceinture des Légendes + + + Ceintures des Légendes + + + + + astragale + + + astragales + + + méritoine + + + méritoines + + + oeil de hibou + + + yeux de hibou + + + soie d'araignée + + + soies d'araignée + + + obbadion + + + obbadions + + + cheveux d'elfe + + + cheveux d'elfe + + + ortigal + + + ortigals + + + tubercule de respiplante + + + tubercules de respiplante + + + oreille de morille + + + oreilles de morille + + + hydropousse + + + hydropousses + + + ossiphage + + + ossiphages + + + fleur de souffre + + + fleurs de souffre + + + feuille de Tshaï + + + feuilles de Tshaï + + + bélidane + + + bélidanes + + + racine de mandragore + + + racines de mandragore + + + percepierre + + + percepierres + + + tanemiel + + + tanemiels + + + boralme + + + boralmes + + + ficoïde à cristaux + + + ficoïdes à cristaux + + + blémissure + + + blémissures + + + rose des neiges + + + roses des neiges + + + thé de sept lieues + + + thé de sept lieues + + + breuvage de Goliath + + + breuvage de Goliath + + + élixir de vie + + + élixir de vie + + + vin du travail acharné + + + vin du travail acharné + + + onguent de soin + + + onguents de soin + + + fiole d'essence vitale + + + fioles d'essence vitale + + + huile de cogitation + + + huile de cogitation + + + petit pain rance + + + petits pains rances + + + extrait de canicule + + + extraits de canicule + + + fourrage de l'étalon + + + fourrage de l'étalon + + + vin de folie + + + vin de folie + + + philtre d'amour + + + philtres d'amour + + + sirop de claivoyance + + + sirops de claivoyance + + + elixir d'endurance + + + elixir d'endurance + + + potion de survie + + + potions de survie + + + + + AGRESSIF + + + TOUT + + + NOMBRE + + + AURA + + + ARBRES + + + PAYSANS + + + SOUTIEN + + + GUARDE + + + CHATEAU + + + DEFENSIF + + + UNITE + + + ERESSEA + + + FUITE + + + ETRANGER + + + BATIMENT + + + OBJETS + + + DONNER + + + PITIE + + + AIDE + + + DERRIERE + + + APRES + + + CONTROLE + + + PLANTES + + + COMBAT + + + NON + + + SUIVANT + + + FACTION + + + CAMOUFLAGE + + + PAUSE + + + HOMMES + + + PRIVE + + + REGION + + + BATEAU + + + ECUS + + + ROUTES + + + NIVEAU + + + TEMPORAIRE + + + POTIONS + + + POUR + + + AVANT + + + DEVANT + + + SORTS + + + + + alchimie + + + armurier + + + arc + + + maçon + + + charron + + + catapulte + + + arbalète + + + divertissement + + + espionnage + + + bucheron + + + herboriste + + + magie + + + mêlée + + + mineur + + + observation + + + hast + + + perrayeur + + + équitation + + + cantonnier + + + navigation + + + charpentier + + + endurance + + + discrétion + + + tactique + + + percepteur + + + commerce + + + dresseur + + + mains-nues + + + fourbisseur + + + + + + // + + + TRAVAILLER + + + ATTAQUER + + + ANNONCE + + + VOLER + + + ASSIEGER + + + NOMMER + + + UTILISER + + + DECRIRE + + + PRIER + + + ENTRER + + + GUARDER + + + OFFRIR + + + MESSAGE + + + DEFAUT + + + EMAIL + + + FIN + + + CHEVAUCHER + + + SUIVRE + + + CHERCHER + + + GM + + + GROUPER + + + AIDER + + + JIHAD + + + PREPARER + + + ACHETER + + + CONTACTER + + + COMBATTRE + + + ENSEIGNER + + + APPRENDRE + + + FOURNIR + + + LOCAL + + + FAIRE + + + ALLER + + + RECOMMENCER + + + NOMBRE + + + SACRIFIER + + + OPTION + + + PASSWORD + + + PLANTER + + + PIRATERIE + + + PREFIXE + + + RECRUTER + + + RAPPORT + + + RESERVER + + + TRAJET + + + SABOTER + + + TRIER + + + ESPIONNER + + + ABANDONNER + + + SYNONYME + + + CACHER + + + TRANSPORTER + + + TAXER + + + DIVERTIR + + + ORIGINE + + + OUBLIER + + + VENDRE + + + SORTIR + + + INCANTER + + + MONTRER + + + DETRUIRE + + + ACCROITRE + + + METAMORPHOSE + + + + + sangsunicornes + + + sangsunicorne + + + cauchemars + + + cauchemar + + + ombreillards + + + ombreillard + + + draco tenebrae + + + draco tenebrae + + + nains + + + nain + + + elfes + + + elfe + + + orques + + + orque + + + snotlings + + + snotling + + + gobelins + + + gobelin + + + humains + + + humain + + + trolls + + + troll + + + démons + + + démons + + + insectes + + + insecte + + + hobbits + + + hobbit + + + chats + + + chat + + + atlantes + + + atlante + + + morts-vivants + + + mort-vivant + + + illusions + + + illusion + + + dragonnets + + + dragonnet + + + dragons + + + dragon + + + wyrms + + + wyrm + + + ents + + + ent + + + dragons-chats + + + dragon-chat + + + draconiens + + + draconien + + + spéciaux + + + spécial + + + enchantements + + + enchantement + + + golems de fer + + + golem de fer + + + golems de pierre + + + golem de pierre + + + ombres + + + ombre + + + lémures + + + lémure + + + yétis + + + yéti + + + quauquemaires + + + quauquemaire + + + crapauds + + + crapaud + + + céphalophages + + + céphalophage + + + paysans + + + paysan + + + wargs + + + warg + + + lynx + + + lynx + + + vers des profondeurs + + + ver des profondeurs + + + rats + + + rat + + + dragons chinois + + + dragon chinois + + + loups + + + loup + + + fantômes + + + fantôme + + + chats des rêves + + + chat des rêves + + + chats de l'Enfer + + + chat de l'Enfer + + + tigres + + + tigre + + + dauphins + + + dauphin + + + tortues géantes + + + tortue géante + + + krakens + + + kraken + + + serpents de mer + + + serpent de mer + + + guerriers illusoires + + + guerrier illusoire + + + diablotins + + + diablotin + + + nymphes + + + nymphe + + + licornes + + + licorne + + + hiboux + + + hibou + + + fées + + + fée + + + aigles + + + aigle + + + centaures + + + centaure + + + squelettes + + + squelette + + + liches + + + liche + + + zombies + + + zombie + + + zombies juju + + + zombie juju + + + goules + + + goule + + + spectres + + + spectre + + + fantômes du musée + + + fantôme du musée + + + gnomes + + + gnome + + + modèles + + + modèle + + + métamorphes + + + métamorphe + + + + + + Options + + + Niveau + + + Statut Politique + + + Plantes nécessaires + + + en construction + + + de dégâts + + + Votre faction a été éliminée. Nous espérons que vous vous êtes bien amusé malgré tout, et vous encourageons à vous réincrire pour une nouvelle partie. + + + + compétences + + + possessions + + + taille + + + sorts + + + sorts de combat + + + aucun + + + Adresses + + + anonyme + + + attaque + + + défense + + + armure + + + dégâts + + + + + baguette + + + baguettes + + + + + + côte nord-ouest + + + côte nord-est + + + côte est + + + côte sud-est + + + côte sud-ouest + + + côte ouest + + + + Aucun ordre reçu pour votre faction ! + + diff --git a/res/messages.xml b/res/messages.xml new file mode 100644 index 000000000..533ec1418 --- /dev/null +++ b/res/messages.xml @@ -0,0 +1,8518 @@ + + + + + + + Ein Alp starb in $region($region), ohne sein Ziel zu erreichen. + An alp died in $region($region) before reaching its target. + + + + + + "Einheiten können die folgenden Gegenstände beanspruchen: $resources($items)" + "Units can claim the following items: $resources($items)" + + + + + + + + "$if($isnull($region),"Es","In $region($region)") wurde$if($eq($number,1),"","n") $int($number) $race($race,$number) gesichtet." + "$if($isnull($region),"","In $region($region), ")$int($number) $race($race,$number) were discovered." + + + + + + + "$unit($mage) läßt einen Teil seiner selbst in die Erde fliessen. Die Bäume, die Transformation überlebt haben, erscheinen nun viel kräftiger." + "The power of $unit($mage) flows into the region and the trees which survived the spell appear stronger now." + "The power of $unit($mage) flows into the region and the trees which survived the spell appear stronger now." + + + + + + + "$unit($mage) beschwört einen Luftgeist, der die $ship($ship) in die Wolken hebt." + "$unit($mage) summons a wind spirit that lifts the $ship($ship) into the clouds." + + + + + + "$unit($mage) beschwört einen Schleier der Verwirrung." + "$unit($mage) summons a fog of confusion." + + + + + Eine Feuerwand blockiert die Ein- und Ausreise. ($int36($id)) + + + + + Der Magier besitzt die Gabe des Chaos. ($int36($id)) + The magician possesses the gift of Chaos. ($int36($id)) + + + + Dieser mächtige Bann scheint die Einheit ihres freien Willens zu berauben. Solange der Zauber wirkt, wird sie nur den Befehlen ihres neuen Herrn gehorchen. ($int36($id)) + + + + Dieser Beeinflussungszauber scheint die Einheit einem ganz bestimmten Volk wohlgesonnen zu machen. ($int36($id)) + + + + Dieser Zauber verursacht einen gigantischen magischen Strudel. Der Mahlstrom wird alle Schiffe, die in seinen Sog geraten, schwer beschädigen. ($int36($id)) + + + + Heilung ist in dieser Region magisch beeinflusst. ($int36($id)) + + + + Dieses Schiff hat sich verfahren. ($int36($id)) + + + + + + + + "$unit($unit) ist im Traum eine Fee erschienen. ($int36($id))" + "In a dream, a fairy appears to $unit($unit). ($int36($id))" + + + + + + + "$unit($unit) wird von bösen Alpträumen geplagt. ($int36($id))" + "$unit($unit) is haunted by terrbile nightmares. ($int36($id))" + + + + + + + "$unit($unit) wird von einem glitzernden Funkenregen umgeben. ($int36($id))" + "$unit($unit) is surrounded by a shower of glittering sparkles. ($int36($id))" + + + + + + + "Ein schimmernder Lichterkranz umgibt $unit($unit). ($int36($id))" + "A circle of shimmering lights surrounds $unit($unit). ($int36($id))" + + + + + + + "Eine Melodie erklingt, und $unit($unit) tanzt bis spät in die Nacht hinein. ($int36($id))" + "A haunting melody fills the air, and $unit($unit) dances until late into the night. ($int36($id))" + + + + + + + "$unit($unit) findet eine kleine Flöte, die eine wundersame Melodie spielt. ($int36($id))" + "$unit($unit) finds a small flute that plays a beautiful melody. ($int36($id))" + + + + + + + "Die Frauen des nahegelegenen Dorfes bewundern $unit($unit) verstohlen. ($int36($id))" + "The women of the nearby village cast furtive looks at $unit($unit). ($int36($id))" + + + + + + + "Eine Gruppe vorbeiziehender Bergarbeiter rufen $unit($unit) eindeutig Zweideutiges nach. ($int36($id))" + "A group of passing miners makes passes at $unit($unit). ($int36($id))" + + + + + + + "$unit($unit) bekommt von einer Schlange einen Apfel angeboten. ($int36($id))" + "A large green snake offers $unit($unit) a fine-looking apple. ($int36($id))" + + + + + + "A spell is deflecting magical energies and weakening all other spells cast in the region. ($int36($id))" + "Dieser Zauber scheint magische Energien irgendwie abzuleiten und so alle in der Region gezauberten Sprüche in ihrer Wirkung zu schwächen oder ganz zu verhindern. ($int36($id))" + + + + + + + "Ein Einhorn berührt $unit($unit) mit seinem Horn und verschwindet kurz darauf im Unterholz. ($int36($id))" + "A unicorn touches $unit($unit) with its horn and vanishes into the forest quickly after. ($int36($id))" + + + + + + + "Vogelzwitschern begleitet $unit($unit) auf all seinen Wegen. ($int36($id))" + "Bird songs follow $unit($unit) on all his travels. ($int36($id))" + + + + + + + "Leuchtende Blumen erblühen rund um das Lager von $unit($unit). ($int36($id))" + "Brightly coloured flowers pop up all around $unit($unit)'s camp. ($int36($id))" + + + + + + + "Über $unit($unit) zieht eine Gruppe Geier ihre Kreise. ($int36($id))" + "A group of vultures circles above $unit($unit). ($int36($id))" + + + + + + + "Der Kopf von $unit($unit) hat sich in einen grinsenden Totenschädel verwandelt. ($int36($id))" + "The head of $unit($unit) has turned into a madly grinning skull. ($int36($id))" + + + + + + + "Ratten folgen $unit($unit) auf Schritt und Tritt. ($int36($id))" + "Rats follow $unit($unit)'s every step. ($int36($id))" + + + + + + + "Pestbeulen befallen den Körper von $unit($unit). ($int36($id))" + "The body of $unit($unit) is disfigured by hideous boils. ($int36($id))" + + + + + + + "Eine dunkle Fee erscheint $unit($unit) im Schlaf. Sie ist von schauriger Schönheit. ($int36($id))" + "A dark and mysterious fairy appears before $unit($unit). She is of bewitching beauty. ($int36($id))" + + + + + + + "Fäulnisgeruch dringt $unit($unit) aus allen Körperöffnungen. ($int36($id))" + "The stench of decay is poring from all the orifices of $unit($unit). ($int36($id))" + + + + + + + + "$unit($unit) mag $faction($faction) zu mögen. ($int36($id))" + "$unit($unit) likes $faction($faction). ($int36($id))" + + + + + + + + "$unit($unit) scheint $race($race, 0) zu mögen. ($int36($id))" + "$unit($unit) seems to like $race($race, 0). ($int36($id))" + + + + + + + + "$unit($unit) ist ungewöhnlich ungeschickt in $skill($skill). ($int36($id))" + "$unit($unit) has some troubles with $skill($skill). ($int36($id))" + + + + + + + + "$unit($unit) ist ungewöhnlich geschickt in $skill($skill). ($int36($id))" + "$unit($unit) is incredibly skilled at $skill($skill). ($int36($id))" + + + + + + + + "$unit($unit) wird noch $int($duration) $if($eq($duration,1), "Woche", "Wochen") unter unserem Bann stehen. ($int36($id))" + "$unit($unit) will be under our influence for $int($duration) more $if($eq($duration,1), "week", "weeks"). ($int36($id))" + + + + + + + + + "$int($number) $if($eq($number,1), "Person", "Personen") von $unit($unit) $if($eq($number,1), "ist", "sind") noch $int($duration) $if($eq($duration,1), "Woche", "Wochen") beschleunigt. ($int36($id))" + "$int($number) $if($eq($number,1), "member", "members") of $unit($unit) $if($eq($number,1), "is", "are") accelerated for $int($duration) more $if($eq($duration,1), "week", "weeks"). ($int36($id))" + + + + + + + + "$int($number) $if($eq($number,1), "Person", "Personen") von $unit($unit) $if($eq($number,1), "fühlt", "fühlen") sich vor Kälte geschützt. ($int36($id))" + "$int($number) $if($eq($number,1), "member", "members") of $unit($unit) $if($eq($number,1), "is", "are") protected from the cold. ($int36($id))" + + + + + + "Ein unbekannter Zauber liegt auf dem Schiff. ($int36($id))" + "An unknown spell lies on this ship. ($int36($id))" + + + + + + "Ein unbekannter Zauber liegt auf der Einheit. ($int36($id))" + "An unknown spell lies on this unit. ($int36($id))" + + + + + + "Ein unbekannter Zauber liegt auf dem Gebäude. ($int36($id))" + "An unknown spell lies on this building. ($int36($id))" + + + + + + "Ein unbekannter Zauber liegt auf der Region. ($int36($id))" + "An unknown spell lies on this region. ($int36($id))" + + + + + + "Eine Wolke negativer Energie liegt über der Region. ($int36($id))" + "A fog of negative energy enshrouds the region. ($int36($id))" + "A fog of negative energy enshrouds the region. ($int36($id))" + + + + + + "Die Leute strotzen nur so vor Kraft. ($int36($id))" + "Testosterone levels are at an all-time high. ($int36($id))" + + + + + + + "$unit($unit) wird von einem Alp geritten. ($int36($id))" + "$unit($unit) is chased by a nightmare. ($int36($id))" + + + + + + + "$unit($unit) stürzt sich von einem amourösen Abenteuer ins nächste. ($int36($id))" + "$unit($unit) goes from one amourous adventure to another. ($int36($id))" + "$unit($unit) goes from one amourous adventure to another. ($int36($id))" + + + + + + + "$unit($unit) kann sich kaum konzentrieren. ($int36($id))" + "$unit($unit) can hardly focus on anything. ($int36($id))" + "$unit($unit) can hardly focus on anything. ($int36($id))" + + + + + + + "Die Ausrüstung von $unit($unit) scheint unsichtbar. ($int36($id))" + "$unit($unit)'s equipment is invisible. ($int36($id))" + "$unit($unit)'s equipment is invisible. ($int36($id))" + + + + + + "Die natürliche Widerstandskraft gegen Verzauberung ist gestärkt. ($int36($id))" + "($int36($id))" + "The magical resistance has been strengthened. ($int36($id))" + + + + + + "Die natürliche Widerstandskraft gegen Verzauberung bestimmter Einheiten in dieser Region wurde gestärkt. ($int36($id))" + "($int36($id))" + "The magical resistance of some units in this region was boosted. ($int36($id))" + + + + + + "Die natürliche Widerstandskraft gegen Verzauberung bestimmter Einheiten in dieser Region wurde geschwächt. ($int36($id))" + "The magical resistance of some units in this region was weakened. ($int36($id))" + "($int36($id))" + + + + + + "Diese Mauern wirken, als wären sie direkt aus der Erde gewachsen und nicht erbaut. ($int36($id))" + "These walls appear to have grown straight out of the earth. ($int36($id))" + "($int36($id))" + + + + + + "Ein magischer Schimmer liegt auf diesen Mauern. ($int36($id))" + "A magical shimmer lies on these walls. ($int36($id))" + "($int36($id))" + + + + + + "Die Straßen sind erstaunlich trocken und gut begehbar, doch an manchen Stellen bilden sich wieder die erste Schlammlöcher. ($int36($id))" + "The roads are extremely dry and well-kept, but some areas show the first signs of potholes reappearing. ($int36($id))" + "($int36($id))" + + + + + + "Die Straßen sind erstaunlich trocken und gut begehbar. ($int36($id))" + "The roads are extremely dry and well-kept. ($int36($id))" + "($int36($id))" + + + + + + "Albträume plagen die Leute. ($int36($id))" + "Nightmares plague the population. ($int36($id))" + "($int36($id))" + + + + + + "Die Leute haben schöne Träume. ($int36($id))" + "($int36($id))" + "The people in this region have sweet dreams. ($int36($id))" + + + + + + "Diese Region wurde von den Göttern verflucht. Das Meer ist eine ekelige Brühe, braunschwarze, stinkende Gase steigen aus den unergründlichen Tiefen hervor, und untote Seeungeheuer, Schiffe zerfressend und giftige grüne Galle geifernd, sind der Schrecken aller Seeleute, die diese Gewässer durchqueren. Niemand kann hier lange überleben. ($int36($id))" + "($int36($id))" + "This region was cursed by the gods. The sea is a foul cesspool, noxious gases rise from the deep, undead seamonsters attack all ships. Noone can live here for long. ($int36($id))" + + + + + + "Diese Region wurde von den Göttern verflucht. Stinkende Nebel ziehen über die tote Erde und furchtbare Kreaturen ziehen über das Land. Die Brunnen sind vergiftet, und die wenigen essbaren Früchte sind von einem rosa Pilz überzogen. Niemand kann hier lange überleben. ($int36($id))" + "($int36($id))" + "This region was cursed by the gods. Noone can live here for long. ($int36($id))" + + + + + + "Ein Schleier der Verwirrung liegt über der Region. ($int36($id))" + "($int36($id))" + "A veil of confusion lies over the region. ($int36($id))" + + + + + + "In der Region treibt ein Giftelementar sein Unwesen. ($int36($id))" + "A poison elemental is spreading pestilence and death. ($int36($id))" + + + + + + "Die ganze Region ist von einer friedlichen Stimmung erfasst. ($int36($id))" + "($int36($id))" + "Everyone in this region seems to be in a peacful mood. ($int36($id))" + + + + + + "Es herrscht eine fröhliche und ausgelassene Stimmung. ($int36($id))" + "($int36($id))" + "Everyone in this region seems to be having a very good time. ($int36($id))" + + + + + + "Die Bauern sind unzufrieden. ($int36($id))" + "($int36($id))" + "The peasants are upset. ($int36($id))" + + + + + + "Alle Leute in der Region haben Schlafstörungen. ($int36($id))" + "($int36($id))" + "People in this region suffer from insomnia. ($int36($id))" + + + + + + "In dieser Gegend herrscht eine Dürre. ($int36($id))" + "($int36($id))" + "This region was hit by a drought. ($int36($id))" + + + + + + "In dieser Gegend steht das Korn besonders gut im Feld. ($int36($id))" + "($int36($id))" + "The grain in this region is especially healthy. ($int36($id))" + + + + + + "Die Winde scheinen dieses Schiff besonders zu beguenstigen. ($int36($id))" + "($int36($id))" + "The winds seem to favor this ship. ($int36($id))" + + + + + + "Untote schrecken vor dieser Region zurück. ($int36($id))" + "($int36($id))" + "The undead turn away from this region. ($int36($id))" + + + + + + "Der Zahn der Zeit kann diesen Mauern nichts anhaben. ($int36($id))" + "($int36($id))" + "Time cannot touch these walls. ($int36($id))" + + + + + + "Dichte Nebel bedecken diese Woche die Region. Keine Einheit schafft es, diese Nebel zu durchdringen und die Region zu verlassen. ($int36($id))" + "heavy fog makes it impossible to leave the region. ($int36($id))" + "heavy fog makes it impossible to leave the region. ($int36($id))" + + + + + + + "$unit($unit) setzt ein Sonnensegel. Die Geschwindigkeit des Schiffes erhöht um $int($speed)." + "$unit($unit) sets a solar sail. The ship's speed is increased by $int($speed)." + "$unit($unit) sets a solar sail. The ship's speed is increased by $int($speed)." + + + + + + "Interner Fehler: Meldung '$name' nicht definiert." + "Internal Error: Message '$name' is undefined." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Interner Fehler: Meldung '$name' nicht definiert." + "$unit($unit) in $region($region): '$order($command)' - Internal Error: Message '$name' is undefined." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier ist kein passendes Schloss." + "$unit($unit) in $region($region): '$order($command)' - No fitting lock can be found here." + "$unit($unit) in $region($region): '$order($command)' - No fitting lock can be found here." + + + + + + + + "$unit($unit) öffnet eines der Schlösser in $region($region) mit $if($eq($key,1),"dem Achatenen Schlüssel","dem Saphirnen Schlüssel")." + "$unit($unit) unlocks one of the locks in $region($region) with $if($eq($key,1),"the Agate Key","the Sapphire Key")." + "$unit($unit) unlocks one of the locks in $region($region) with $if($eq($key,1),"the Agate Key","the Sapphire Key")." + + + + + + + + "$unit($unit) verschließt eines der Schlösser in $region($region) mit $if($eq($key,1),"dem Achatenen Schlüssel","dem Saphirnen Schlüssel")." + "$unit($unit) locks one of the locks in $region($region) with $if($eq($key,1),"the Agate Key","the Sapphire Key")." + "$unit($unit) locks one of the locks in $region($region) with $if($eq($key,1),"the Agate Key","the Sapphire Key")." + + + + + + + "$unit($unit) in $region($region) verwandelt sich in ein Werwesen." + "$unit($unit) in $region($region) becomes a lycantrope." + "$unit($unit) in $region($region) becomes a lycantrope." + + + + + + + "SIEG! $if($eq($n,1), "Die Partei $winners hat", "Die Parteien $winners haben") die Siegbedingung für die erforderliche Zeit erfüllt. Das Spiel ist damit beendet." + "VICTORY! $if($eq($n,1), "The faction $winners has", "The factions $winners have") fulfilled the victory condition for the necessary time. The game is over." + "VICTORY! $if($eq($n,1), "The faction $winners has", "The factions $winners have") fulfilled the victory condition for the necessary time. The game is over." + + + + + + "Achtung: $faction($faction) hat die Siegbedingungen erfüllt und wird in $if($eq($remain,1),"einer Woche","$int($remain) Wochen") zum Sieger erklärt werden." + "Attention: $faction($faction) has fulfilled the victory condition and will be declared winner in $if($eq($remain,1),"one week","$int($remain) weeks")." + "Attention: $faction($faction) has fulfilled the victory condition and will be declared winner in $if($eq($remain,1),"one week","$int($remain) weeks")." + + + + + + + + "$unit($unit) wurde in $region($region) von einem GM gelöscht: \"$string\"." + "$unit($unit) in $region($region) was removed by a GM: \"$string\"." + "$unit($unit) in $region($region) was removed by a GM: \"$string\"." + + + + + + + + "$resource($item,1) (Gewicht: $weight($weight)): $description" + "$resource($item,1) (weight: $weight($weight)): $description" + + + + + "Ein Hauch des Lebens liegt über der Welt und alle Wesen fühlen sich frisch und erholt." + "Life itself touches the world and all beings are healed." + "Life itself touches the world and all beings are healed." + + + + + + + + "$unit($unit) hat Glück und findet einen Hort von $int($amount) $resource($item,$amount)." + "$unit($unit) luckily finds a cache of $int($amount) $resource($item,$amount)." + "$unit($unit) luckily finds a cache of $int($amount) $resource($item,$amount)." + + + + + + "$unit($unit) brennt ein großes Feuerwerk ab und Kaskaden bunter Sterne, leuchtende Wasserfälle aus Licht und strahlende Feuerdrachen erhellen den Himmel." + "A large firework is visible all over the sky." + "A large firework is visible all over the sky." + + + + + + + "In $region($region) wird ein großes Feuerwerk abgebrannt, welches noch hier zu bewundern ist. Kaskaden bunter Sterne, leuchtende Wasserfälle aus Licht und strahlende Feuerdrachen erhellen den Himmel." + "A large firework, visible all over the sky, has been started in $region($region)." + "A large firework, visible all over the sky, has been started in $region($region)." + + + + + + + "Zur Feier des Geburtstags von ${name} brennt $unit($unit) ein großes Feuerwerk ab. Kaskaden bunter Sterne, leuchtende Wasserfälle aus Licht und strahlende Feuerdrachen erhellen den Himmel." + "A large firework in honor of ${name} is visible all over the sky." + "A large firework in honor of ${name} is visible all over the sky." + + + + + + + + "Zur Feier des Geburtstags von ${name} wird in $region($region) ein großes Feuerwerk abgebrannt, welches noch hier zu bewundern ist. Kaskaden bunter Sterne, leuchtende Wasserfälle aus Licht und strahlende Feuerdrachen erhellen den Himmel." + "A large firework in honor of ${name}, visible all over the sky, has been started in $region($region)." + "A large firework in honor of ${name}, visible all over the sky, has been started in $region($region)." + + + + + + + "$int36($unit.id($unit))/$int($index) erzielt einen kritischen Treffer." + "$int36($unit.id($unit))/$int($index) does critical damage." + "$int36($unit.id($unit))/$int($index) does critical damage." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) muß mindestens 2 Stufen besser sein als $unit($student)." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) needs to be at least 2 levels better than $unit($student)." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) needs to be at least 2 levels better than $unit($student)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($student) lernt nicht." + "$unit($unit) in $region($region): '$order($command)' - $unit($student) is not learning." + "$unit($unit) in $region($region): '$order($command)' - $unit($student) is not learning." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dafür braucht die Einheit $resources($required)." + "$unit($unit) in $region($region): '$order($command)' - for this, the unit needs $resources($required)." + "$unit($unit) in $region($region): '$order($command)' - for this, the unit needs $resources($required)." + + + + + + $trailto($region) + $trailto($region) + + + + + + + "Deine Partei hat $int($units) Migranten und kann maximal $int($maxunits) Migranten aufnehmen." + "Your faction has $int($units) migrants out of a possible total of $int($maxunits)." + + + + + + + + + "Seit $int($age) Wochen Mitglied der Allianz '$name ($int36($id))', angeführt von $faction($leader)." + "Member of '$name ($int36($id))' for $int($age) weeks, led by $faction($leader)." + + + + + + + "Deine Partei hat $int($units) Helden und kann maximal $int($maxunits) Helden ernennen." + "Your faction has promoted $int($units) heroes out of a possible total of $int($maxunits)." + + + + + + + "Deine Partei hat $int($population) Personen in $int($units) Einheiten." + "Your faction has $int($population) people in $int($units) units." + + + + + + "Statistik für $region($region):" + "Statistics for $region($region):" + + + + + + "Unterhaltung: max. $int($max) Silber" + "Entertainment: max. $int($max) silver" + + + + + + "Moral der Bauern: $int($morale)" + "Peasant morale: $int($morale)" + + + + + + "Luxusgüter zum angegebenen Preis: $int($max)" + "Luxury goods at this price: $int($max)" + + + + + + "Lohn für Arbeit: $int($max) Silber" + "Worker salary: $int($max) silver" + + + + + + "Bauerneinnahmen: $int($max) Silber" + "Peasant wages: $int($max) silver" + + + + + + "Personen: $int($max)" + "People: $int($max)" + "People: $int($max)" + + + + + + "Rekruten: max. $int($max) Bauern" + "Recruits: $int($max) peasants" + "Recruits: $int($max) peasants" + + + + + + + "Deine Partei hat $int($score) Punkte. Der Durchschnitt für Parteien ähnlichen Alters ist $int($average) Punkte." + "Your faction has a score of $int($score). The average score for similar factions is $int($average)." + "Your faction has a score of $int($score). The average score for similar factions is $int($average)." + + + + + + + "Report für $game, $date" + "Report for $game, $date" + "Report for $game, $date" + + + + + + + "Im $direction($dir) der Region liegt $trailto($region)" + "To the $direction($dir) lies $trailto($region)" + + + + + + + "$resource($product,0) $int($price) Silber" + "$resource($product,0) for $int($price) silver" + "$resource($product,0) for $int($price) silver" + + + + + + + "Auf dem Markt wird für $resource($product,0) $int($price) Silber verlangt." + "Le marché local offre la $resource($product,0) au prix de $int($price) écus." + "The local market offers $resource($product,0) at a price of $int($price) silver." + + + + + + + "Auf dem Markt werden $resource($p1,0) und $resource($p2,0) feilgeboten." + "The local market offers $resource($p1,0) and $resource($p2,0)." + + + + + + "Auf dem Markt wird $resource($p1,0) feilgeboten." + "The local market offers $resource($p1,0)." + + + + + + "Dein Passwort lautet ${password}." + "Your password is ${password}." + "Your password is ${password}." + + + + + + "Die Mannschaft krank vom vergifteten Wasser, Planken, Ruder und Segel zerfressen von den Wassern des verfluchten Meeres, ergibt sich die $ship($ship) in ihr Schicksal und sinkt." + "Her sailors sick from the poisened ocean, planks, rudder und sails corroded by the waters of the cursed ocean, the $ship($ship) finally succumbs to her destiny and sinks." + + + + + + "$unit($unit) benutzt einen Talenttrunk und fühlt, wie sein Wissen zunimmt." + "$unit($unit) uses a potion of skills and feels his knowledge grow." + "$unit($unit) uses a potion of skills and feels his knowledge grow." + + + + + + + "$unit($unit) benutzt einen Astralkristall und gewinnt $int($aura) Aura hinzu." + "$unit($unit) uses an astralcrystal and gains $int($aura) aura." + "$unit($unit) uses an astralcrystal and gains $int($aura) aura." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Luxusgut wird hier nicht verkauft." + "$unit($unit) in $region($region): '$order($command)' - These goods are not on sale here." + "$unit($unit) in $region($region): '$order($command)' - These goods are not on sale here." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dazu benötigt man $resource($missing,0)." + "$unit($unit) in $region($region): '$order($command)' - This requires $resource($missing,0)." + "$unit($unit) in $region($region): '$order($command)' - This requires $resource($missing,0)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) nehmen nichts an." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) will not accept anything." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) will not accept anything." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können nicht neu gruppiert werden." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot be regrouped." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot be regrouped." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können nichts stehelen." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot steal anything." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot steal anything." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) geben nichts weg." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) do not give things away." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) do not give things away." + + + + + + + + "Eine Botschaft von $unit.dative($sender) aus $region($region): '$string'" + "A message by $unit($sender) from $region($region): '$string'" + + + + + + + + + "In $region($region) erhielt $unit($unit) eine Botschaft von $unit.dative($sender): '$string'" + "In $region($region), $unit($unit) received a message by $unit($sender): '$string'" + + + + + + + + + "In $region($region) erhielt $unit($unit) von $unit.dative($sender) $resources($items)" + "In $region($region), $unit($unit) received $resources($items) from $unit($sender)" + + + + + + "$building($building) hat diese Woche nicht funktioniert, da zu Beginn der Woche der Unterhalt nicht gezahlt werden konnte." + "$building($building) was nonfunctional because upkeep could not be paid at the beginning of the week." + + + + + + "Plötzlich löst sich $building($building) in kleine Traumwolken auf." + "$building($building) suddenly dissolves into small pink clouds." + + + + + + "Für das Gebäude $building($building) konnte die ganze Woche kein Unterhalt bezahlt werden." + "Upkeep for $building($building) could not be paid all week." + + + + + + + + + "In $region($region) stürzte $building($building) ein.$if($road," Beim Einsturz wurde die halbe Straße vernichtet.","")$if($opfer," $int($opfer) Opfer $if($eq($opfer,1),"ist","sind") zu beklagen.","")" + "$building($building) in $region($region) collapses.$if($opfer," There are $int($opfer) caualties.","")" + "$building($building) in $region($region) collapses.$if($opfer," There are $int($opfer) caualties.","")" + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In der Ebene der Herausforderung kann niemand rekrutiert werden." + "$unit($unit) in $region($region): '$order($command)' - You cannot recruit in this plane." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die einheit kann sich nicht so gut tarnen." + "$unit($unit) in $region($region): '$order($command)' -The unit cannot hide that well." + + + + + + + + "$ship($ship) was destroyed by $unit($unit)." + "$ship($ship) wurde von $unit($unit) zerstört." + + + + + + + + "$unit($unit) could not destroy $ship($ship)." + "$unit($unit) konnte $ship($ship) nicht zerstören." + + + + + + + + "$unit($unit) was detected while trying to destroy $ship($ship)." + "$unit($unit) wurde beim Versuch $ship($ship) zu zerstören entdeckt." + + + + + + + "Somebody attempted to destroy $ship($ship)." + "Es wurde versucht, $ship($ship) zu zerstören." + + + + + + + "$ship($ship) was destroyed." + "$ship($ship) wurde zerstört." + + + + + + + + + "$int($amount) Personen von $unit($unit) ertrinken.$if($isnull($region),""," Die Einheit rettet sich nach $region($region).")" + + + + + + + + "$unit($unit) ueberlebt unbeschadet und rettet sich nach $region($region)." + + + + + + + + "$ship($ship) versinkt in den Fluten von $region($region)." + + + + + + + + "$unit($unit) wurde beim versenken von $ship($ship) entdeckt." + + + + + + + + + "$unit($unit) entdeckte $unit($saboteur) beim versenken von $ship($ship)." + + + + + + + + "$unit($unit) ertrinkt in $region($region)." + "$unit($unit) drowns in in $region($region)." + + + + + + + + + "$int($amount) Personen in $unit($unit) in $region($region) ertrinken." + "$int($amount) people in $unit($unit) in $region($region) drown." + "$int($amount) people in $unit($unit) in $region($region) drown." + + + + + + + "$unit($unit) nimmt Schaden auf dem Wasser in $region($region)." + "$unit($unit) is taking damage on the water." + "$unit($unit) is taking damage on the water." + + + + + + "$unit($unit) schwenkt sein Szepter und sorgt für Verwirrung und Chaos in der Region." + + + + + + + + + "$unit($unit) stolpert bei der Erforschung der Region über $localize($location). Nähere Durchsuchung fördert ein zerfleddertes altes Buch mit dem Titel '$localize($book)' zu Tage. Der Wissensschub ist enorm." + + + + "Ein Alp hat sein Opfer gefunden und springt auf den Rücken von $unit($target)!" + + + + + + + + "$unit($unit) fühlt sich von starken magischen Energien durchströmt. ($int36($id))" + "Powerful magical energies are pulsing through $unit($unit). ($int36($id))" + + + + + + + + "$unit($unit) hat Schwierigkeiten seine magischen Energien zu sammeln. ($int36($id))" + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger sind für einen Moment benommen." + "$unit($mage) casts $spell($spell): $int($amount) fighters were momentarily stunned." + + + + + + + + "$unit($mage) besänftigt den Bauernaufstand in $region($region)." + "$unit($mage) quells the uprising in $region($region)." + + + + + + + + "$unit($mage) rief in $region($region) einen Riss in dem Gefüge der Magie hervor, der alle magische Kraft aus der Region riss." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden in Schlaf versetzt." + "$unit($mage) casts $spell($spell): $int($amount) fighters have fallen asleep." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Kriegern wurde ihre Lebenskraft entzogen." + "$unit($mage) casts $spell($spell): $int($amount) fighters had their life energy drained." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Kriegern wurden versteinert." + "$unit($mage) casts $spell($spell): $int($amount) fighters were petrified." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden in einen Blutrausch versetzt." + "$unit($mage) casts $spell($spell): $int($amount) fighters went into a mindless rage." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden eingeschüchtert." + "$unit($mage) casts $spell($spell): $int($amount) fighters were intimidated." + + + + + + + + "$unit($mage) zaubert $spell($spell), aber es gab niemanden, der beeinflusst werden konnte." + "$unit($mage) casts $spell($spell), but nobody is impressed." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden von Furcht gepackt." + "$unit($mage) casts $spell($spell): $int($amount) fighters were consumed by fear." + + + + + + + + "$unit($mage) zaubert $spell($spell): Das Kampfgetümmel erstirbt und er kann unbehelligt seines Weges ziehen." + "$unit($mage) casts $spell($spell): The noise of the battle dies down and he is able to slip away unharmed." + + + + + + + + "$unit($mage) zaubert $spell($spell): Ein Sturm kommt auf und die Schützen können kaum noch zielen." + "$unit($mage) casts $spell($spell): Strong stormwinds are blowing and the archers are having a hard time aiming." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger schleppten sich müde in den Kampf." + "$unit($mage) casts $spell($spell): $int($amount) fighters had trouble staying awake." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden moralisch gestärkt." + "$unit($mage) casts $spell($spell): $int($amount) fighters had their moral boosted." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden magisch beschleunigt." + "$unit($mage) casts $spell($spell): $int($amount) fighters were magically accelerated." + + + + + + + "$unit($mage) ruft ein fürchterliches Unwetter über seine Feinde, doch es gab niemanden mehr, den dies treffen konnte." + + + + + + + "$unit($mage) ruft ein fürchterliches Unwetter über seine Feinde, doch der magische Regen zeigt keinen Effekt." + + + + + + + "$unit($mage) ruft ein fürchterliches Unwetter über seine Feinde. Der magischen Regen lässt alles Eisen rosten." + + + + + + + + + "$unit($mage) beschwört den Alp $unit($alp) für $unit($target)." + "$unit($mage) summons the alp $unit($alp) for $unit($target)." + + + + + + + + "$unit($mage) kümmert sich um die Verletzten und heilt $int($amount) Verwundete." + "$unit($mage) sees after the wounded and heals $int($amount)." + + + + + + + + + "$unit($mage) kümmert sich um die Verletzten und benutzt ein $resource($item,1), um den Zauber zu verstärken. $int($amount) Verwundete werden geheilt." + "$unit($mage) sees after the wounded and heals $int($amount). A $resource($item,1) improves the spell." + + + + + + + + + "Mit einem Ritual bindet $unit($mage) die magischen Kräfte der Erde von $region($region) in die Mauern von $building($building)." + "$unit($mage) performs a ritual that binds the magical forces of $region($region) into the walls of $building($building)." + + + + + + + + + "$unit($mage) opfert $unit($target) $int($amount) Aura." + "$unit($mage) sacrifices $int($amount) aura for $unit($target)." + + + + + + + + "$unit($mage) beginnt ein Ritual der Wiederbelebung. $int($amount) Krieger stehen von den Toten auf." + "$unit($mage) begins a ritual of resurrection. $int($amount) warriors rise from the dead." + + + + + + + + + "$unit($mage) beginnt ein Ritual der Wiederbelebung und benutzt ein $resource($item,1), um den Zauber zu verstärken. $int($amount) Krieger stehen von den Toten auf." + "$unit($mage) begins a ritual of resurrection using a $resource($item,1). $int($amount) warriors rise from the dead." + + + + + + + "$unit($mage) öffnet ein Chaostor." + "$unit($mage) opens a chaos gate." + + + + "Ein Wirbel aus blendendem Licht erscheint." + "A vortex of blinding light appears." + + + + + + + + "$unit($mage) kann in $region($region) keine Untoten rufen." + "$unit($mage) cannot summon any undead in $region($region)." + + + + + + + + + "$unit($mage) erweckt in $region($region) $int($amount) Untote aus ihren Gräbern." + "$unit($mage) calls $int($amount) undead from their graves in $region($region)." + + + + + + + + "$unit($mage) stört in $region($region) die Ruhe der Toten." + "$unit($mage) communicates with the dead in $region($region)." + + + + + + + "$unit($unit) gelingt es, durch die Nebel auf die Realität zu blicken." + "$unit($unit) manages to catch a glimpse of reality through the fog." + + + + + + + + "$unit($mage) konnte $int($amount) $if($eq($amount,1),"Bauer","Bauern") anwerben." + "$unit($mage) managed to recruit $int($amount) $if($eq($amount,1),"peasant","peasants")." + + + + + + "Ein bohrender Schmerz durchzuckt $unit($unit), Verwirrung macht sich breit." + "Pain pulses through $unit($unit), confusion spreads." + + + + + + ""AAAAAAAGHHHHHH!" - Ein Schrei durchzieht die Region, $unit($unit) windet sich vor Schmerz." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Eine höhere Macht hindert $unit($unit) daran, das Objekt zu übergeben. 'ES IST DEINS, MEIN KIND. DEINS GANZ ALLEIN'." + + + + + + + "$unit($unit) sendet ein Stoßgebet an den Herrn der Schreie." + + + + + + + "Der Eisberg $region($region) schmilzt." + "The iceberg $region($region) melts." + "The iceberg $region($region) melts." + + + + + + "Der Gletscher von $region($region) bricht und treibt davon." + "The glacier in $region($region) breaks up and drifts away." + "The glacier in $region($region) breaks up and drifts away." + + + + + + "Der Eisberg $region($region) treibt an eine Küste." + "The iceberg $region($region) drifts onto a coast." + "The iceberg $region($region) drifts onto a coast." + + + + + + "Die $ship($ship) wird bei einer Kollision mit einem Eisberg zerstört." + "The $ship($ship) has been destroyed by a collision with an iceberg." + "The $ship($ship) has been destroyed by a collision with an iceberg." + + + + + + "Die $ship($ship) wird bei einer Kollision mit einem Eisberg beschädigt." + "The $ship($ship) has been damaged by a collision with an iceberg." + "The $ship($ship) has been damaged by a collision with an iceberg." + + + + + + + "Die $ship($ship) treibt nach $direction($dir)." + "The ship $ship($ship) drifts to the $direction($dir)." + "The ship $ship($ship) drifts to the $direction($dir)." + + + + + + + "Der Eisberg $region($region) treibt nach $direction($dir)." + "The iceberg $region($region) drifts $direction($dir)." + "The iceberg $region($region) drifts $direction($dir)." + + + + + + "Wir erklären allen $race($race,2) den heiligen Krieg." + "We declare jihad on all $race($race,2)." + + + + + + "Die Götter erhören $unit($unit)." + "The Gods have listened to $unit($unit)." + "The Gods have listened to $unit($unit)." + + + + + + + "Die Götter gewähren uns die Kraft eines $special($int($level))." + "The Gods grant us the powers of $special ($int($level))." + "The Gods grant us the powers of $special ($int($level))." + + + + + + "Die Götter gewähren uns die Kraft eines ${special}." + "The Gods grant us the powers of ${special}." + "The Gods grant us the powers of ${special}." + + + + + + + + + + "$unit($unit) verlor $int($fallen) Personen$if($alive,", $int($alive) überlebten","")$if($run," und $int($run) flohen$if($isnull($runto),""," nach $region($runto)")","")." + "$unit($unit) lost $int($fallen) people$if($alive,", $int($alive) survived","")$if($run," and $int($run) fled$if($isnull($runto),""," to $region($runto)")","")." + + + + + + + + "$unit($unit) erzielte $int($hits) Treffer und tötete $int($kills) Gegner." + "$unit($unit) hit $int($hits) times and killed $int($kills) enemies." + "$unit($unit) hit $int($hits) times and killed $int($kills) enemies." + + + + + + "$string" + "$string" + + + + + + + "Heer $int($index): $name" + "Army $int($index): $name" + + + + + + + "Verwundert blicken die Bauern von $region($region) auf ein neues Gebäude." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) gewinnt durch das Ritual $int($amount) Aura." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) receives $int($amount) aura." + + + + + + + + "$unit($mage) beschwört Naturgeister in den Boden von $region($region)." + "$unit($mage) summons natural spirits into the ground of $region($region)." + + + + + + + + + "$unit($mage) verwandelt $int($amount) aus $unit($target) in $race($race,0)." + "$unit($mage) transforms $int($amount) from $unit($target) into $race($race,0)." + + + + + + + + "$unit($mage) verwandelt $unit($target) in $race($race,0)." + "$unit($mage) tranforms $unit($target) to $race($race,0)." + + + + + + "$unit($mage) erlöst die gequälten Seelen der Toten." + "$unit($mage) redeems the tormented souls of the dead." + + + + + + "$unit($mage) verwandelt sich in einen Wyrm." + "$unit($mage) turns into a wyrm." + + + + + + + "$unit($mage) ruft Irrlichter in $region($region)." + "$unit($mage) summons wisps in $region($region)." + "$unit($mage) summons wisps in $region($region)." + + + + + + + "$unit($mage) erschafft in $region($region) eine Wand aus Feuer." + "$unit($mage) creates a wall of fire in $region($region)." + "$unit($mage) creates a wall of fire in $region($region)." + + + + + + + "$unit($mage) wiegelt in $region($region) die Bauern zum Aufstand auf." + "$unit($mage) incites a revolt among the peasants of $region($region)." + + + + + + + + + "$unit($mage) wiegelt in $region($region) $int($amount) Bauern zum Aufstand auf." + "$unit($mage) incites a revolt among $int($amount) peasants of $region($region)." + + + + + + + + "$unit($mage) sorgt in $region($region) für Trübsal unter den Bauern." + "$unit($mage) causes great sadness among the peasants of $region($region)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier erschafft ein Traumgebäude." + "$unit($unit) in $region($region): '$order($command)' - The magician creates an illusionary building." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) kann keine $race($race,1)-Gestalt annehmen." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Elementar ist zu klein, um das Gebäude zu tragen." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Elementar weigert sich, nach $direction($direction) zu gehen." + "$unit($unit) in $region($region): '$order($command)' - The elemental refuses to go $direction($direction)." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) ist von unserer Art, das Ritual wäre verschwendete Aura." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) is one of our kind, we should not waste aura on this." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) wird von uns aufgenommen." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) has become one of our kind." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) ruft Drachen nach $region($target)." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) calls dragons to $region($target)." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) erschafft $int($amount) ${object}." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) creates $int($amount) ${object}." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) creates $int($amount) ${object}." + + + + + + + + "Ein Beben erschüttert $building($building). Viele kleine Pseudopodien erheben das Gebäude und tragen es in Richtung $direction($direction)." + + + + + + + + "$unit($unit) benutzt in $region($region) ein Traumauge." + "$unit($unit) uses a dreameye in $region($region)." + + + + + + + "$unit($unit) benutzt in $region($region) einen Antimagiekristall." + "$unit($unit) uses an antimagic crystal in $region($region)." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Sphären des Chaos geben dem Magier einen Teil ihrer Kraft." + "$unit($unit) in $region($region): '$order($command)' - The sphere of chaos returns a part of his power to the magician." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier konnte keinen Fluch zerstören." + "$unit($unit) in $region($region): '$order($command)' - The magician could not destroy any magic." + + + + + + + + "In $region($region) dehnt $unit($unit) die Zeit für $int($amount) Personen." + "In $region($region), $unit($unit) bends time for $int($amount) men." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier zerstört $int($succ) Flüche auf ${target}." + "$unit($unit) in $region($region): '$order($command)' - The magician destroys $int($succ) spells on ${target}." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier zerstört den Fluch($id) auf ${target}." + "$unit($unit) in $region($region): '$order($command)' - The magician destroys the spell on ${target}." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Zauber ist nicht stark genug, um den Fluch auf ${target} zu zerstören." + "$unit($unit) in $region($region): '$order($command)' - The spell is not strong enough to destroy the curse on ${target}." + + + + + + + "$unit($mage) beschwört einen Giftelementar in $region($region)." + "$unit($mage) summons a poison elemental in $region($region)." + + + + + + + + "$unit($unit) in $region($region) wird von einem Unbekannten verflucht." + "$unit($unit) in $region($region) was cursed by an unknown magician." + + + + + + + + "$unit($mage) belegt $unit($target) mit einem Zauber." + "$unit($mage) puts a spell on $unit($target)." + + + + + + + "$unit($mage) belegt $unit($target) mit einem Kälteschutz." + "$unit($mage) puts protection from cold on $unit($target)." + + + + + + + "$unit($mage) legt einen Rosthauch auf $unit($target), doch der Rosthauch fand keine Nahrung." + "$unit($mage) puts a spell of rust on $unit($target), but it shows no effect." + + + + + + + + "$unit($mage) legt einen Rosthauch auf $unit($target). $int($amount) Waffen wurden vom Rost zerfressen." + "$unit($mage) puts a spell of rust on $unit($target). $int($amount) weapons are eaten by rust." + + + + + + + $if($isnull($mage),"Ein unentdeckter Magier",$unit($mage)) erschuf einen heiligen Hain von $int($amount) Schößlingen. + $if($isnull($mage),"An unknown magician ",$unit($mage)) created a holy forest of $int($amount) young trees. + + + + + + "$if($isnull($mage),"Ein unentdeckter Magier",$unit($mage)) segnet in einem kurzen Ritual die Felder." + "$if($isnull($mage),"an unseen magician",$unit($mage)) blesses the fields in a short ritual." + + + + + + "$unit($mage) beschwört die Mächte des Wassers und ein gigantischer Strudel bildet sich." + "$unit($mage) summons the power of the seas and a giant maelstrom forms." + + + + + + + "$unit($mage) belebt $int($amount) Bäume." + "$unit($mage) revives $int($amount) trees." + + + + + + + "$unit($mage) sorgt für trockene Straßen in $region($region)." + "$unit($mage) creates dry and well-repaired roads in $region($region)." + + + + + + + "$unit($mage) erfleht den Segen der Götter des Windes und des Wassers für $ship($ship)." + "$unit($mage) asks the gods of wind and water on behalf of the $ship($ship)." + + + + + + + + "$unit($unit) transferiert $int($aura) Aura auf $unit($target)." + "$unit($unit) transfers $int($aura) Aura to $unit($target)." + "$unit($unit) transfers $int($aura) Aura to $unit($target)." + + + + + + + + "$unit($mage) entzieht $unit($target) $int($aura) Aura." + "$unit($mage) draws $int($aura) aura from $unit($target)." + + + + + + + "$unit($unit) fühlt seine magischen Kräfte schwinden und verliert $int($aura) Aura." + "$unit($unit) feels the powers of magic fade and loses $int($aura) aura." + + + + + + "$unit($unit) fühlt sich einen Moment seltsam geschwächt." + "$unit($unit) fühlt strangely weakened." + + + + + + + "$unit($unit) konnte $unit($target) keine Aura entziehen." + "$unit($unit) could not draw aura from $unit($target)." + + + + + + + + "$unit($unit) wurde von $region($source) nach $unit($target) teleportiert." + "$unit($unit) was teleported from $region($source) to $unit($target)." + + + + + + + + + "$unit($mage) fand heraus, dass auf $ship($ship) der Zauber $curse($curse) liegt, der noch etwa $int($months) Wochen bestehen bleibt." + "$unit($mage) discovers that $ship($ship) is charmed with $curse($curse), which will last for, about $int($months) more weeks." + + + + + + + + + "$unit($mage) fand heraus, dass auf $building($building) der Zauber $curse($curse) liegt, der noch etwa $int($months) Wochen bestehen bleibt." + "$unit($mage) discovers that $building($building) is charmed with $curse($curse), which will last for, about $int($months) more weeks." + + + + + + + + + "$unit($mage) fand heraus, dass auf $unit($unit) der Zauber $curse($curse) liegt, der noch etwa $int($months) Wochen bestehen bleibt." + "$unit($mage) discovers that $unit($unit) is charmed with $curse($curse) that will last for about $int($months) more weeks." + + + + + + + + + "$unit($mage) fand heraus, dass auf $region($region) der Zauber $curse($curse) liegt, der noch etwa $int($months) Wochen bestehen bleibt." + "$unit($mage) discovers that $region($region) is charmed with $curse($curse), which will last for, about $int($months) more weeks." + + + + + + + + "$unit($mage) fand heraus, dass auf $ship($ship) der Zauber $curse($curse) liegt, dessen Kraft ausreicht, um noch Jahrhunderte bestehen zu bleiben." + "$unit($mage) discovers that $ship($ship) is charmed with $curse($curse), which will last for centuries." + + + + + + + + "$unit($mage) fand heraus, dass auf $building($building) der Zauber $curse($curse) liegt, dessen Kraft ausreicht, um noch Jahrhunderte bestehen zu bleiben." + "$unit($mage) discovers that $building($building) is charmed with $curse($curse), which will last for centuries." + + + + + + + + "$unit($mage) fand heraus, dass auf $unit($unit) der Zauber $curse($curse) liegt, dessen Kraft ausreicht, um noch Jahrhunderte bestehen zu bleiben." + "$unit($mage) discovers that $unit($unit) is charmed with $curse($curse), which will last for centuries." + + + + + + + + "$unit($mage) fand heraus, dass auf $region($region) der Zauber $curse($curse) liegt, dessen Kraft ausreicht, um noch Jahrhunderte bestehen zu bleiben." + "$unit($mage) discovers that $region($region) is charmed with $curse($curse), which will last for centuries." + + + + + + + "$unit($mage) meint, dass auf $ship($ship) ein Zauber liegt, konnte aber über den Zauber nichts herausfinden." + "It appears to $unit($mage) that $ship($ship) is charmed, but no details have been revealed." + "It appears to $unit($mage) that $ship($ship) is charmed, but no details have been revealed." + + + + + + + "$unit($mage) meint, dass auf $building($building) ein Zauber liegt, konnte aber über den Zauber nichts herausfinden." + "It appears to $unit($mage) that $building($building) is charmed, but no details have been revealed." + "It appears to $unit($mage) that $building($building) is charmed, but no details have been revealed." + + + + + + + "$unit($mage) meint, dass $unit($unit) verzaubert ist, konnte aber über den Zauber nichts herausfinden." + "It appears to $unit($mage) that $unit($unit) is charmed, but no details have been revealed." + "It appears to $unit($mage) that $unit($unit) is charmed, but no details have been revealed." + + + + + + + "$unit($mage) meint, dass auf $region($region) ein Zauber liegt, konnte aber über den Zauber nichts herausfinden." + "It appears to $unit($mage) that $region($region) is charmed, but no details have been revealed." + "It appears to $unit($mage) that $region($region) is charmed, but no details have been revealed." + + + + + + + "$unit($mage) meint, dass auf $ship($ship) kein Zauber liegt." + "It appears to $unit($mage) that $ship($ship) is not charmed." + "It appears to $unit($mage) that $ship($ship) is not charmed." + + + + + + + "$unit($mage) meint, dass auf $building($building) kein Zauber liegt." + "It appears to $unit($mage) that $building($building) is not charmed." + "It appears to $unit($mage) that $building($building) is not charmed." + + + + + + + "$unit($mage) meint, dass auf $unit($target) kein Zauber liegt." + "It appears to $unit($mage) that $unit($target) is not charmed." + "It appears to $unit($mage) that $unit($target) is not charmed." + + + + + + + "$unit($mage) meint, dass auf $region($region) kein Zauber liegt." + "It appears to $unit($mage) that $region($region) is not charmed." + "It appears to $unit($mage) that $region($region) is not charmed." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Region konnte nicht verzaubert werden." + "$unit($unit) in $region($region): '$order($command)' - The region could not be charmed." + "$unit($unit) in $region($region): '$order($command)' - The region could not be charmed." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $ship($ship) widersteht dem Zauber." + "$unit($unit) in $region($region): '$order($command)' - $ship($ship) resists the spell." + "$unit($unit) in $region($region): '$order($command)' - $ship($ship) resists the spell." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Gebäude $int36($id) konnte nicht verzaubert werden." + "$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be charmed." + "$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be charmed." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) widersteht dem Zauber." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) resists the spell." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) resists the spell." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Schiff $int36($id) wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - Ship $int36($id) could not be located." + "$unit($unit) in $region($region): '$order($command)' - Ship $int36($id) could not be located." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Gebäude $int36($id) wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be located." + "$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be located." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Einheit $id wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - Unit $id could not be located." + "$unit($unit) in $region($region): '$order($command)' - Unit $id could not be located." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es wurde kein Ziel gefunden." + "$unit($unit) in $region($region): '$order($command)' - The spell could not find a target." + + + + + + + "$unit($mage) erleidet durch den Tod seines Vertrauten einen Schock." + "$unit($mage) receives a shock when his familiar dies." + + + + + + + + "$unit($unit) schafft es nicht, genug Kraft aufzubringen, um $spell($spell) auf Stufe $int($level) zu zaubern." + "$unit($unit) cannot muster enough energy to cast $spell($spell) on level $level($level)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Für diesen Zauber fehlen noch $resources($list)." + "$unit($unit) in $region($region): '$order($command)' - Casting this spell requires an additional $resources($list)." + + + + + + + + "$unit($unit) hat nicht genügend Komponenten um $spell($spell) auf Stufe $int($level) zu zaubern." + "$unit($unit) has insufficient components to cast $spell($spell) on level $int($level)." + + + + + + + + "$unit($unit) unterläuft in $region($region) beim Zaubern von $spell($spell) ein Patzer." + "$unit($unit) fumbles while casting $spell($spell) in $region($region)." + + + + + + + + "Als $unit($unit) in $region($region) versucht, $spell($spell) zu zaubern, scheint plötzlich ein Beben durch die magische Essenz zu laufen und ein furchtbarer Sog versucht $unit($unit) in eine andere Dimension zu ziehen. Mit letzter Kraft gelingt es $unit($unit) sich zu retten." + "When $unit($unit) in $region($region) tries to cast $spell($spell), a sudden disturbance ripples through the magical realm and a terrible force attempts to drag the magician to another dimension. However, with a final effort of strength, $unit($unit) manages to save himself." + + + + + + + + "Als $unit($unit) in $region($region) versucht, $spell($spell) zu zaubern erhebt sich plötzlich ein dunkler Wind. Bizarre geisterhafte Gestalten kreisen um den Magier und scheinen sich von den magischen Energien des Zaubers zu ernähren. Mit letzter Kraft gelingt es $unit($unit) dennoch den Spruch zu zaubern." + "When $unit($unit) in $region($region) tries to cast $spell($spell), strong winds suddenly rise. Bizare ghostlike creatures circle around the magician and seem to be leeching his magical energy. However, with a final effort of strength, $unit($unit) manages to complete the spell." + + + + + + + + "Eine Botschaft von $unit.dative($unit) in $region($region): 'Ups! Quack, Quack!'" + "A message from $unit($unit) in $region($region): 'Oops! Croak, Croak!'" + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($mage) kann Zauber, die durch $unit($unit) gewirkt werden, nicht zusätzlich in die Ferne richten." + "$unit($unit) in $region($region): '$order($command)' - $unit($mage) cannot direct spells that are channeled through $unit($unit) into distant regions." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($mage) kann nicht genug Energie aufbringen, um diesen Spruch durch $unit($unit) zu wirken." + "$unit($unit) in $region($region): '$order($command)' - $unit($mage) cannot raise enough energy to channel the spell through $unit($unit)." + + + + + + + + "$unit($mage) ruft einen Vertrauten. $race($race, 0) können $skills lernen." + "$unit($mage) summons a familiar. $race($race, 0) can learn ${skills}." + + + + + + + + "$unit($unit) hat einen feuchtfröhlichen Abend in der Taverne verbracht. Ausser einem fürchterlichen Brummschädel ist da auch noch das dumme Gefühl $unit($mage) seine ganze Lebensgeschichte erzählt zu haben." + + + + + + + "$unit($unit) hat einen feuchtfröhlichen Abend in der + Taverne verbracht. Ausser einem fürchterlichen Brummschädel ist da auch + noch das dumme Gefühl die ganze Taverne mit seiner Lebensgeschichte + unterhalten zu haben." + + + + + + + + + "$unit($mage) gelingt es $unit($unit) zu verzaubern. $unit($unit) wird für etwa $int($duration) Wochen unseren Befehlen gehorchen." + + + + + + + + + "$unit($unit) gelingt es $spell($spell) zu zaubern, doch der Spruch zeigt keine Wirkung." + "$unit($unit) manages to cast $spell($spell), but the spell seems to have no effect." + + + + + + + + "$unit($unit) fühlt sich nach dem Zaubern von $spell($spell) viel erschöpfter als sonst und hat das Gefühl, dass alle weiteren Zauber deutlich mehr Kraft als normalerweise kosten werden." + "$unit($unit) feels far more exhausted than he should after casting $spell($spell) and assumes that any following spells will cost far more energy than usual." + + + + + + + "$unit($unit) in $region($region) hat rasende Kopfschmerzen und kann sich nicht mehr richtig konzentrieren. Irgendwas bei diesem Zauber ist fürchterlich schiefgelaufen." + "$unit($unit) in $region($region) is hit by a massive headacheand cannot concentrate on the spell. Some part of this ritual has gone very wrong indeed." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier verfängt sich in seinem eigenen Zauber." + + + "In der Region erstrahlen des Nachts bunte Lichter, Gloeckchen klingeln und frohes Kindergelaechter klingt durch den Wald." + "At night, colourful lights can be seen in this region, bells are a-ringing and the laughter of happy children seems to be everywhere in the forests." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Zauber von $unit.dative($unit) war viel zu schwach und löst sich gleich wieder auf." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) verzaubert ${target}." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) puts a spell on ${target}." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) gelingt es zwar die Region zu verzaubern, aber irgendwas ging schief." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) manages to put a spell on the region, but something went wrong nonetheless." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) gelingt es die Region zu verzaubern." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) puts a spell on the region." + + + + + + + "$unit($mage) erhöht die Körperkraft von $unit.dative($target) beträchtlich." + "$unit($mage) increases the strength of $unit($target) dramatically." + + + + + + + + "$unit($unit) in $region($region) regeneriert $int($amount) Aura." + "$unit($unit) régénère $int($amount) aura en $region($region)." + "$unit($unit) regenerates $int($amount) aura in $region($region)." + + + + + + "$string" + "$string" + + + + + + + + + "$unit($unit) in $region($region) verbraucht $int($cost) Silber für das Studium von $skill($skill)." + "$unit($unit) dépense $int($cost) écus en $region($region) pour apprendre $skill($skill)." + "$unit($unit) spends $int($cost) silver in $region($region) to study $skill($skill)." + + + + + + + "$unit($teacher) kann durch Dumpfbackenbrot nur $int($amount) Schüler lehren." + "Due to the effect of duncebuns, $unit($teacher) can only teach $int($amount) students." + + + + + + + + + "$unit($teacher) lehrt $unit($student) $skill($skill) auf Stufe $int($level)." + "$unit($teacher) teaches $unit($student) $skill($skill) to level $int($level)." + "$unit($teacher) teaches $unit($student) $skill($skill) to level $int($level)." + + + + + + + + "$unit($teacher) lehrt $unit($student) $skill($skill)." + "$unit($teacher) teaches $unit($student) $skill($skill)." + "$unit($teacher) teaches $unit($student) $skill($skill)." + + + + + + "$string" + "$string" + + + + + + + + "$unit($unit) verkauft $int($amount) $resource($resource,$amount)." + "$unit($unit) sells $int($amount) $resource($resource,$amount)." + "$unit($unit) sells $int($amount) $resource($resource,$amount)." + + + + + + + + "$unit($unit) kauft $int($amount) $resource($resource,$amount)." + "$unit($unit) buys $int($amount) $resource($resource,$amount)." + "$unit($unit) buys $int($amount) $resource($resource,$amount)." + + + + + + + "$unit($unit) bezahlt $int($money) Silber für den Kauf von Luxusgütern." + "$unit($unit) pays $int($money) silver for luxury items." + "$unit($unit) pays $int($money) silver for luxury items." + + + + + + + + "$unit($unit) verdient in $region($region) $int($amount) Silber durch den Verkauf von Luxusgütern." + "$unit($unit) earned $int($amount) silver in $region($region) by selling luxury items." + "$unit($unit) earned $int($amount) silver in $region($region) by selling luxury items." + + + + + + + + + "$unit($unit) arbeitet in $region($region) für einen Lohn von $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber." + "$unit($unit) works in $region($region) for a wage of $int($amount) $if($eq($wanted,$amount),""," out of $int($wanted)") silver." + "$unit($unit) works in $region($region) for a wage of $int($amount) $if($eq($wanted,$amount),""," out of $int($wanted)") silver." + + + + + + + + "$unit($unit) arbeitet in $region($region) für einen Lohn von $int($amount) Silber." + "In $region($region), $unit($unit) works for a wage of $int($amount) silver." + + + + + + + + + "$unit($unit) verdient in $region($region) $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber durch Unterhaltung." + "In $region($region), $unit($unit) earns only $int($amount) instead of$if($eq($wanted,$amount),""," of$if($eq($wanted,$amount),""," of $int($wanted)") ") with entertainment." + + + + + + + + "$unit($unit) fängt in $region($region) Fische im Wert von $int($amount) Silber." + "In $region($region), $unit($unit) catches fish worth $int($amount) silver." + + + + + + + + "$unit($unit) verdient in $region($region) $int($amount) Silber durch Unterhaltung." + "$unit($unit) earns $int($amount) in $region($region) with entertainment." + "$unit($unit) earns $int($amount) in $region($region) with entertainment." + + + + + + + + + "$unit($unit) verdient in $region($region) $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber durch Zauberei." + + + + + + + + "$unit($unit) verdient in $region($region) $int($amount) Silber durch Zauberei." + "$unit($unit) earns $int($amount) silver through simple magical services in $region($region)." + + + + + + + + + "$unit($unit) klaut in $region($region) $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber." + "$unit($unit) steals only $int($amount) silver instead of$if($eq($wanted,$amount),""," of$if($eq($wanted,$amount),""," of $int($wanted)") ") in $region($region)." + "$unit($unit) steals only $int($amount) silver instead of$if($eq($wanted,$amount),""," of$if($eq($wanted,$amount),""," of $int($wanted)") ") in $region($region)." + + + + + + + + "$unit($unit) klaut in $region($region) $int($amount) Silber." + "$unit($unit) steals $int($amount) silver in $region($region)." + + + + + + + + + "$unit($unit) treibt in $region($region) Steuern in Höhe von $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber ein." + "$unit($unit) collects taxes of only $int($amount) instead of$if($eq($wanted,$amount),""," of$if($eq($wanted,$amount),""," of $int($wanted)") ") silver in $region($region)." + + + + + + + + "$unit($unit) treibt in $region($region) Steuern in Höhe von $int($amount) Silber ein." + "$unit($unit) collects taxes of $int($amount) silver in $region($region)." + + + + + + + + + + "$unit($unit) verdient$if($eq($mode,4)," am Handel","") in $region($region) $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber$if($eq($mode,1)," durch Unterhaltung",$if($eq($mode,2)," durch Steuern",$if($eq($mode,3)," durch Handel",$if($eq($mode,5)," durch Diebstahl",$if($eq($mode,6)," durch Zauberei","")))))." + "$unit($unit) earns $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") in $region($region)." + "$unit($unit) earns $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") in $region($region)." + + + + + + + + + "$unit($unit) in $region($region) findet $int($amount) $resource($herb,$amount)." + "$unit($unit) in $region($region) finds $int($amount) $resource($herb,$amount)." + "$unit($unit) in $region($region) finds $int($amount) $resource($herb,$amount)." + + + + + + + "$unit($unit) züchtet $int($amount) Pferde." + "$unit($unit) breeds $int($amount) horses." + "$unit($unit) breeds $int($amount) horses." + + + + + + + + + "$unit($unit) pflanzt in $region($region) $int($amount) $resource($herb,$amount)." + "$unit($unit) plants $int($amount) $resource($herb,$amount) in $region($region)." + "$unit($unit) plants $int($amount) $resource($herb,$amount) in $region($region)." + + + + + + + "$unit($unit) in $region($region) entdeckt eine Laenader." + "$unit($unit) discovers laen in $region($region)." + + + + + + "Die Laenader in $region($region) ist erschöpft." + "There is no more laen in $region($region)." + + + + + + + + "$unit($unit) in $region($region) hat ein zu niedriges Talent, um $resource($resource,0) abzubauen." + "$unit($unit) in $region($region) is not proficient enough to produce $resource($resource,0)." + "$unit($unit) in $region($region) is not proficient enough to produce $resource($resource,0)." + + + + + + + + + + "$unit($unit) in $region($region) produziert $int($amount)$if($eq($wanted,$amount),""," von $int($wanted)") $resource($resource,$wanted)." + "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." + "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." + + + + + + + + + + "$unit($unit) in $region($region) produziert $int($amount)$if($eq($wanted,$amount),""," von $int($wanted)") $resource($resource,$wanted)." + "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." + "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." + + + + + + + + "$unit($unit) baut für $int($size) an $building($building) weiter." + "$unit($unit) builds $int($size) more on $building($building)." + "$unit($unit) builds $int($size) more on $building($building)." + + + + + + + + "$unit($unit) baut für $int($size) an $ship($ship) weiter." + "$unit($unit) builds $int($size) more on $ship($ship)." + "$unit($unit) builds $int($size) more on $ship($ship)." + + + + + + "$string" + "$string" + + + + + + + "$unit($unit) stirbt beim Versuch, die Feuerwand nach $region($region) zu durchqueren." + "$unit($unit) dies trying to cross the wall of fire into $region($region)." + "$unit($unit) dies trying to cross the wall of fire into $region($region)." + + + + + + + "$unit($unit) erleidet beim Durchqueren der Feuerwand nach $region($region) schwere Verbrennungen." + "$unit($unit) steps through the wall of fire into $region($region) and receives severe burn damage." + "$unit($unit) steps through the wall of fire into $region($region) and receives severe burn damage." + + + + + + + + + "$unit($unit) transportiert $unit($target) von $region($start) nach $region($end)." + "$unit($unit) transported $unit($target) from $region($start) to $region($end)." + "$unit($unit) transported $unit($target) from $region($start) to $region($end)." + + + + + + + + + + "$unit($unit) $if($eq($mode,1),"reitet", "wandert") von $region($start) nach $region($end).$if($isnull($regions),""," Dabei wurde $trail($regions) durchquert.")" + "$unit($unit) $if($eq($mode,1),"chevauche", "marche") de $region($start) vers $region($end) trans $trail($regions)" + "$unit($unit) $if($eq($mode,1),"rides", "walks") from $region($start) to $region($end)$if($isnull($regions),""," by way of $trail($regions)")." + + + + + + + "$unit($unit) entdeckt dass im $direction($direction) $terrain($region) ist." + "$unit($unit) discovered that an ocean lies in the $direction($direction)." + "$unit($unit) discovered that an ocean lies in the $direction($direction)." + + + + + + + "$unit($unit) entdeckt, dass $region($region) $terrain($region) ist." + "$unit($unit) discovered that $region($region) is $terrain($region)." + "$unit($unit) discovered that $region($region) is $terrain($region)." + + + + + + + "$unit($unit) ist in dieser Runde gelandet und kann nicht weiter ins Landesinnere nach $region($region) vorstossen." + "$unit($unit) has just landed and cannot continue moving to $region($region)." + "$unit($unit) has just landed and cannot continue moving to $region($region)." + + + + + + "Die Mannschaft der $ship($ship) kann in letzter Sekunde verhindern, dass das Schiff auf Land aufläuft." + "In the very last moment, the crew of the $ship($ship) saved the ship from grounding." + "In the very last moment, the crew of the $ship($ship) saved the ship from grounding." + + + + + + + "Die $ship($ship) konnte in $region($region) nicht einreisen, die Küste ist zu gefährlich für das Schiff." + "The $ship($ship) could not berth in $region($region). The coast is too dangerous for the vessel." + "The $ship($ship) could not berth in $region($region). The coast is too dangerous for the vessel." + + + + + + + "Die Mannschaft der $ship($ship) weigert sich, nach $direction($direction) zu reisen." + " The crew of the $ship($ship) refuses to travel to the$direction($direction)." + " The crew of the $ship($ship) refuses to travel to the$direction($direction)." + + + + + + + "Die Mannschaft der $ship($ship) weigert sich, nach $region($region) zu reisen." + "The crew of the $ship($ship) refuses to travel to $region($region)." + "The crew of the $ship($ship) refuses to travel to $region($region)." + + + + + + + "$unit($unit) weigert sich, nach $direction($direction) zu reisen." + "$unit($unit) refuses to travel to the$direction($direction)." + "$unit($unit) refuses to travel to the$direction($direction)." + + + + + + + "$unit($unit) weigert sich, nach $region($region) zu reisen." + "$unit($unit) refuses to travel to $region($region)." + "$unit($unit) refuses to travel to $region($region)." + + + + + + + "Die $ship($ship) konnte $region($region) nicht verlassen." + "The $ship($ship) could not leave $region($region)." + "The $ship($ship) could not leave $region($region)." + + + + + + + + "$unit($unit) wurde in $region($region) von $unit.dative($guard) aufgehalten." + "$unit($unit) was kept in $region($region) by $unit($guard)." + "$unit($unit) was kept in $region($region) by $unit($guard)." + + + + + + "Wir haben den Krieg mit $faction($faction) beendet." + "We declared peace with $faction($faction)." + "We declared peace with $faction($faction)." + + + + + + "$faction($faction) hat den Krieg mit uns beendet." + "$faction($faction) has declared peace with us." + "$faction($faction) has declared peace with us." + + + + + + "Wir haben $faction($faction) den Krieg erklärt." + "We declared war on $faction($faction)." + "We declared war on $faction($faction)." + + + + + + "$faction($faction) hat uns den Krieg erklärt." + "$faction($faction) has declared war on us." + "$faction($faction) has declared war on us." + + + + + + + + "$unit($unit) konnte nicht von $region($region) nach $region($target) reisen, da der Besitzer der Region es verhinderte." + "$unit($unit) could not travel from $region($region) to $region($target) because the owner denied entrance." + + + + + + + "$unit($unit) konnte aus $region($region) nicht ausreisen." + "$unit($unit) could not leave $region($region)." + "$unit($unit) could not leave $region($region)." + + + + + + + "$unit($follower) ist $unit($unit) gefolgt." + "$unit($follower) followed $unit($unit)." + "$unit($follower) followed $unit($unit)." + + + + + + + "$unit($follower) konnte $unit($unit) nicht folgen." + "$unit($follower) could not follow $unit($unit)." + "$unit($follower) could not follow $unit($unit)." + + + + + + + "$unit($unit) entdeckt, dass es keinen Weg nach $direction($direction) gibt." + "$unit($unit) discovers that there is no route going $direction($direction)." + "$unit($unit) discovers that there is no route going $direction($direction)." + + + + + + + + "$unit($unit) konnte von $region($region) nicht nach $direction($direction) ausreisen, der Nebel war zu dicht." + "$unit($unit) could not travel $direction($direction) from $region($region), the fog was too dense." + + + + + + "$string" + "$string" + + + + + + "In $region($region) erschienen die Herren der Bäume." + "In $region($region), the lords of the trees have risen." + "In $region($region), the lords of the trees have risen." + + + + + + "In $region($region) erhoben sich die Toten aus den Gräbern." + "The dead rise from their graves in $region($region)." + + + + + + + + "$unit($unit) vermehrt sich um $int($amount) $race($race,$amount)." + "$unit($unit) breeds $int($amount) new $race($race,$amount)." + "$unit($unit) breeds $int($amount) new $race($race,$amount)." + + + + + "Die Partei bekommt einen Spitznamen." + "Your faction received a nickname." + + + + + + + "Die Partei bekommt von $unit.dative($unit) in $region($region) einen Spitznamen." + "Your faction received a nickname from $unit($unit)." + + + + + + + "$building($building) in $region($region) bekommt einen Spitznamen." + "$building($building) in $region($region) received a nickname." + + + + + + + + "$building($building) in $region($region) bekommt von $unit.dative($renamer) einen Spitznamen." + "$building($building) in $region($region) received a nickname from $unit($renamer)." + + + + + + + "Die $ship($ship) in $region($region) bekommt einen Spitznamen." + "$ship($ship) in $region($region) received a nickname." + + + + + + + + "Die $ship($ship) in $region($region) bekommt von $unit.dative($renamer) einen Spitznamen." + "$ship($ship) in $region($region) received a nickname from $unit($renamer)." + + + + + + + "$unit($renamed) in $region($region) bekommt einen Spitznamen." + "$unit($renamed) in $region($region) received a nickname." + + + + + + + + "$unit($renamed) in $region($region) bekommt von $unit.dative($renamer) einen Spitznamen." + "$unit($renamed) in $region($region) received a nickname from $unit($renamer)." + + + + + + "$if($eq($dead,1),"Ein Bauer","$int($dead) Bauern") verhungert." + "$if($eq($dead,1),"One peasant starves","$int($dead) peasants starve")." + "$if($eq($dead,1),"One peasant starves","$int($dead) peasants starve")." + + + + + + "Der Vulkan in $region($region) bricht aus." + "The volcano in $region($region) breaks out." + "The volcano in $region($region) breaks out." + + + + + + + "Der Vulkan in $region($regionv) bricht aus. Die Lavamassen verwüsten $region($regionn)." + "The volcano in $region($regionv) breaks out. The lava devastates $region($regionn)." + "The volcano in $region($regionv) breaks out. The lava devastates $region($regionn)." + + + + + + + + "Beim Vulkanausbruch in $region($region) sterben $int($dead) Personen in $unit($unit)." + "$int($dead) people in $unit($unit) perisch when the volcano in $region($region) breaks out." + "$int($dead) people in $unit($unit) perisch when the volcano in $region($region) breaks out." + + + + + + "Aus dem Vulkankrater von $region($region) steigt kein Rauch mehr." + "The volcano of $region($region) stops releasing smoke." + "The volcano of $region($region) stops releasing smoke." + + + + + + "Aus dem Vulkankrater von $region($region) steigt plötzlich Rauch." + "Columns of smoke are released by the volcano of $region($region)." + "Columns of smoke are released by the volcano of $region($region)." + + + + + + + "$unit($unit) in $region($region) desertiert." + "$unit($unit) in $region($region) abandons your cause." + "$unit($unit) in $region($region) abandons your cause." + + + + + + + + "$unit($unit) reißt die Straße zwischen $region($from) und $region($to) ein." + "$unit($unit) demolishes the road between $region($from) and $region($to)." + "$unit($unit) demolishes the road between $region($from) and $region($to)." + + + + + + + "$unit($unit) in $region($region) kann keine Kräuter finden." + "$unit($unit) could not find any herbs in $region($region)." + "$unit($unit) could not find any herbs in $region($region)." + + + + + + + + + "$unit($unit) in $region($region) stellt fest, dass es hier $localize($amount) $resource($herb,0) gibt." + "$unit($unit) discovers that $localize($amount) $resource($herb,0) grow in $region($region)." + + + + + + + "$unit($unit) reißt einen Teil von $building($building) ein." + "$unit($unit) tears down parts of $building($building)." + + + + + + + "$unit($unit) zerstört $building($building)." + "$unit($unit) destroys $building($building)." + "$unit($unit) destroys $building($building)." + + + + + + + + "$unit($unit) erweitert in $region($region) das Straßennetz um $int($size)." + "$unit($unit) extends the road network in $region($region) by $int($size)." + "$unit($unit) extends the road network in $region($region) by $int($size)." + + + + + + + + "$unit($unit) $if($eq($amount,1),"schließt","schließen") sich $int($amount) $resource($rtype,$amount) an." + "$int($amount) $resource($rtype,$amount) $if($eq($amount,1),"joins","join") $unit($unit)." + + + + + + + "$unit($mage) legt einen Schleier um die Ausrüstung von $unit.dative($target)." + "$unit($mage) shrouds the equipment of $unit($target) in shadows." + + + + + + + + "Die $ship($ship) in $region($region) entdeckt ein Opfer im $direction($dir)." + "The $ship($ship) in $region($region) made $direction($dir) a target." + "The $ship($ship) in $region($region) made $direction($dir) a target." + + + + + + + "Die $ship($ship) in $region($region) kann keine Schiffe aufbringen." + "The $ship($ship) could not capture other ships in $region($region)." + "The $ship($ship) could not capture other ships in $region($region)." + + + + + + "Langsam kehren andere Völker nach $region($region) zurück." + "Little by little, people return to $region($region)." + "Little by little, people return to $region($region)." + + + + + + "Vor den vielen Orks in $region($region) fliehen die anderen Einwohner." + "People $region($region) flee from an Orc superiority." + "People $region($region) flee from an Orc superiority." + + + + + + + + "$unit($unit) in $region($region) beschädigt die $ship($ship)." + "$unit($unit) in $region($region) damages the $ship($ship)." + + + + + + + + "$unit($unit) in $region($region) versenkt die $ship($ship)." + "$unit($unit) sunk $ship($ship) in $region($region)." + "$unit($unit) sunk $ship($ship) in $region($region)." + + + + + + "$unit($unit) marschiert in eine Antimagiezone und löst sich auf." + "$unit($unit) walks into an antimagical zone and dissolves." + + + + + + "$unit($unit) hat sich unbemerkt verflüchtigt." + "$unit($unit) has dissolved without a trace." + "$unit($unit) has dissolved without a trace." + + + + + + "$unit($unit) wird sich bald verflüchtigen." + "$unit($unit) will dissolve soon." + "$unit($unit) will dissolve soon." + + + + + + + "$int($amount) Bauern flohen aus Furcht vor $unit($unit)." + "$int($amount) peasants fled in fear of $unit($unit)." + "$int($amount) peasants fled in fear of $unit($unit)." + + + + + + + + "$int($amount) Bauern werden zu $race($race,0) und schliessen sich $unit($unit) an." + "$int($amount) peasants become $race($race,0) and join the ranks of $unit($unit)." + + + + + + + "$unit($unit) verspeiste $int($amount) Pferde." + "$unit($unit) ate $int($amount) horses." + + + + + + + "$unit($unit) verspeiste $int($amount) Bauern." + "$unit($unit) ate $int($amount) peasants." + "$unit($unit) ate $int($amount) peasants." + + + + + + + "ERESSEA $int36($faction) \"${password}\" - Deine Befehle hatten ein falsches Passwort." + "ERESSEA $int36($faction) \"${password}\" - Your orders had the wrong password." + + + + + + "Das Passwort für diese Partei lautet ${value}." + "Le mot de passe de cette faction est '${value}'" + "The password of this faction is '$value'." + + + + + + "Die Reportadresse wurde nicht geändert, '${value}' ist keine gültige email." + " Address not changed, '$value' is an invalid email." + " Address not changed, '$value' is an invalid email." + + + + + + "Die Reportadresse wurde auf ${value} geändert." + " Address has been changed to '$value'." + " Address has been changed to '$value'." + + + + + + "Das Banner wurde auf '$value' geändert." + "Banner has been changed to '$value'." + "Banner has been changed to '$value'." + + + + + + + + + "Eine Partei muß mindestens $int($turns) Wochen alt sein, bevor sie angegriffen oder bestohlen werden kann." + "A faction must be at least $int($turns) weeks old before it can be attacked or stolen from." + + + + + + + + "$unit($unit) wurden in $region($region) $int($amount) Silberstücke geklaut." + "In $region($region), thieves stole $int($amount) silver from $unit($unit)." + "In $region($region), thieves stole $int($amount) silver from $unit($unit)." + + + + + + + "$unit($target) ertappte $unit($unit) beim versuchten Diebstahl." + "$unit($target) caught $unit($unit) in attempted theft." + "$unit($target) caught $unit($unit) in attempted theft." + + + + + + + "$unit($unit) wurde von $unit.dative($target) beim versuchten Diebstahl ertappt." + "$unit($unit) was caught by $unit($target) in attempted theft." + "$unit($unit) was caught by $unit($target) in attempted theft." + + + + + + "$unit($unit) fühlt sich beobachtet." + "$unit($unit) feels watched." + "$unit($unit) feels watched." + + + + + + + "$unit($unit) gelang es nicht, sich nahe genug an $unit($target) heranzuschleichen." + "$unit($unit) could not sneak close enough to $unit($target)." + "$unit($unit) could not sneak close enough to $unit($target)." + + + + + + + "$unit($spy) gelang es nicht, etwas über $unit($target) herauszufinden." + "$unit($spy) could not find out anything about $unit($target)." + "$unit($spy) could not find out anything about $unit($target)." + + + + + + + + "$unit($spy) gelang es, Informationen über $unit($target) ($status) herauszubekommen." + "$unit($spy) managed to gather information about $unit($target)." + + + + + + + "$unit($target) ist ein $type-Magier." + "$unit($target) is a $type-magician" + + + + + + + "$unit($target) beherrscht ${skills}." + "$unit($target) has the skills ${skills}." + + + + + + + "Im Gepäck von $unit($target) sind $resources($items)." + "$unit($target) carries $resources($items)" + + + + + + + "$unit($target) gehört der Partei $faction($faction) an." + "$unit($target) belongs to $faction($faction)." + + + + + + + "$unit($target) fühlt sich $if($isnull($spy),"","durch $unit($spy) ")beobachtet." + "$unit($target) feels watched by $unit($spy)." + "$unit($target) feels watched by $unit($spy)." + + + + + + + + "$faction($from) gibt ein Almosen von $int($amount) Silber an $faction($to)." + "$faction($from) donates $int($amount) silver to $faction($to)." + "$faction($from) donates $int($amount) silver to $faction($to)." + + + + + + + + "$unit($unit) vergißt durch Dumpfbackenbrot $int($weeks) Wochen des Talentes $skill($skill)." + "$unit($unit) eats a Dumpfbackenbrot and forgets $int($weeks) weeks worth of $skill($skill)." + "$unit($unit) eats a Dumpfbackenbrot and forgets $int($weeks) weeks worth of $skill($skill)." + + + + + + + "$unit($unit) in $region($region) wird durch unzureichende Nahrung geschwächt." + "$unit($unit) is weakened due to malnourishment." + "$unit($unit) is weakened due to malnourishment." + + + + + + + + + "$unit($unit) verliert in $region($region) $int($dead) von $int($add($live,$dead)) Personen durch Unterernährung." + "$unit($unit) loses $int($dead) of $int($add($live,$dead)) people due to starvation in $region($region)." + "$unit($unit) loses $int($dead) of $int($add($live,$dead)) people due to starvation in $region($region)." + + + + + + + + "$unit($unit): '$order($command)' - Die Einheit benutzt bereits $resource($using,0)." + "$unit($unit): '$order($command)' - The unit already uses $resource($using,0)." + "$unit($unit): '$order($command)' - The unit already uses $resource($using,0)." + + + + + + "Die $ship($ship) ist zu stark beschädigt und sinkt." + "The $ship($ship) suffers too heavy damage and sinks." + "The $ship($ship) suffers too heavy damage and sinks." + + + + + + + "Die $ship($ship) entdeckt, dass $region($region) Festland ist." + "The $ship($ship) discovers that $region($region) has no shore." + + + + + + + + "Die $ship($ship) fliegt von $region($from) nach $region($to)." + "The $ship($ship) flies from $region($from) to $region($to)." + + + + + + + + "Die $ship($ship) segelt von $region($from) nach $region($to)." + "The $ship($ship) sails from $region($from) to $region($to)." + + + + + + + + "Die $ship($ship) wird in $region($region) von Stürmen abgetrieben$if($sink," und sinkt","")." + "The $ship($ship) in $region($region) drifts in heavy storm$if($sink," and sinks","")." + "The $ship($ship) in $region($region) drifts in heavy storm$if($sink," and sinks","")." + + + + + + + + + "Die $ship($ship) fährt in den Mahlstrom von $region($region) und nimmt $int($damage) Schaden$if($sink," und sinkt","")." + "The $ship($ship) sails into the maelstrom of $region($region) and takes $int($damage) damage$if($sink,". The ship sinks","")." + + + + + + + "$unit($unit) vergißt $skill($skill)." + "$unit($unit) forgets $skill($skill)." + "$unit($unit) forgets $skill($skill)." + + + + + + + "$unit($unit) gibt das Kommando an $unit($recipient)." + "$unit($unit) gave control to $unit($recipient)." + "$unit($unit) gave control to $unit($recipient)." + + + + + + + + "$unit($unit) gibt $int($amount) Dumpfbackenbrot an $unit($recipient)." + "$unit($unit) administers $int($amount) duncebuns to $unit($recipient)." + + + + + + + + + "$unit($unit) in $region($region) rekrutiert $int($amount) von $int($want) Personen." + "$unit($unit) in $region($region) recruits $int($amount) $int($want) people." + "$unit($unit) in $region($region) recruits $int($amount) $int($want) people." + + + + + + + + "$unit($unit) belagert $building($building). Dabei richten die Katapulte Zerstörungen von $int($destruction) Größenpunkten an." + "$building($building) is under siege by $unit($unit). During siege, catapults caused $int($destruction) points destruction." + "$building($building) is under siege by $unit($unit). During siege, catapults caused $int($destruction) points destruction." + + + + + + + "$unit($unit) belagert $building($building)." + "$building($building) is under siege by $unit($unit)." + + + + + + + + "$unit($unit) ertrinkt beim Untergang der $ship($ship) in $region($region)." + "$unit($unit) drowns when $ship($ship) in $region($region) sinks." + "$unit($unit) drowns when $ship($ship) in $region($region) sinks." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht bewachen, da sie versucht zu fliehen." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot guard the region because it's trying to flee." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot guard the region because it's trying to flee." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann den Befehl in dieser Runde nicht ausführen, da sie an einem Kampf teilgenommen hat." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot execute this command because it has been in combat." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot execute this command because it has been in combat." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Gebäude kann nur einmal pro Runde erweitert werden." + "$unit($unit) in $region($region): '$order($command)' - Thhe building can be expanded only once per turn." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Objekt ist unzerstörbar." + "$unit($unit) in $region($region): '$order($command)' - This object is indestructible." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ohne Zutaten kann ein Alchemist nichts herstellen." + "$unit($unit) in $region($region): '$order($command)' - Ohne Zutaten kann ein Alchemist nichts herstellen." + "$unit($unit) in $region($region): '$order($command)' - Without ingredients an alchemist can not produce anything." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nicht alle Zutaten vorhanden." + "$unit($unit) in $region($region): '$order($command)' - Nicht alle Zutaten vorhanden." + "$unit($unit) in $region($region): '$order($command)' - Not all ingredients present." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Eine Partei kann nur einmal neu starten." + "$unit($unit) in $region($region): '$order($command)' - Restart can only be used once." + "$unit($unit) in $region($region): '$order($command)' - Restart can only be used once." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Werwesen können nicht arbeiten." + "$unit($unit) in $region($region): '$order($command)' - Lycantropes don't work." + "$unit($unit) in $region($region): '$order($command)' - Lycantropes don't work." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Werwesen können nicht mit anderen Personen gemischt werden." + "$unit($unit) in $region($region): '$order($command)' - Lycantropes may not be mixed with normal people." + "$unit($unit) in $region($region): '$order($command)' - Lycantropes may not be mixed with normal people." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann sich nicht verwandeln." + "$unit($unit) in $region($region): '$order($command)' - This unit can not change shape." + "$unit($unit) in $region($region): '$order($command)' - This unit can not change shape." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diese Einheit ist kein Werwesen." + "$unit($unit) in $region($region): '$order($command)' - This unit is not in lycantropic form." + "$unit($unit) in $region($region): '$order($command)' - This unit is not in lycantropic form." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diese Einheit ist schon ein Werwesen." + "$unit($unit) in $region($region): '$order($command)' - This unit already assumed lycantropic form." + "$unit($unit) in $region($region): '$order($command)' - This unit already assumed lycantropic form." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Talent kann nicht höher gelernt werden." + "$unit($unit) in $region($region): '$order($command)' - This skill cannot be raised any higher." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Snotlinge sind zu dumm, um auf den Feldern zu arbeiten." + "$unit($unit) in $region($region): '$order($command)' - We snotlings is too stupid fer dat!" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei muß mindestens 9 Wochen alt sein, um einen Neustart zu versuchen." + "$unit($unit) in $region($region): '$order($command)' - Your faction is not old enough to start over." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Optionen ZIP und BZIP2 können nur um, nicht ausgeschaltet werden." + "$unit($unit) in $region($region): '$order($command)' - options ZIP and BZIP2 can only be switched, not turned off." + "$unit($unit) in $region($region): '$order($command)' - options ZIP and BZIP2 can only be switched, not turned off." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Einheiten einer Partei, die noch immun gegen Angriffe ist, dürfen nicht bewachen." + "$unit($unit) in $region($region): '$order($command)' - units of a faction that can't be attacked may not guard." + "$unit($unit) in $region($region): '$order($command)' - units of a faction that can't be attacked may not guard." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In dieser Region kann man nichts verkaufen." + "$unit($unit) in $region($region): '$order($command)' - there is no trade in this region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Bereits ein Synonym gesetzt." + "$unit($unit) in $region($region): '$order($command)' - synonym already set." + "$unit($unit) in $region($region): '$order($command)' - synonym already set." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Kein Synonym angegeben." + "$unit($unit) in $region($region): '$order($command)' - synonym missing." + "$unit($unit) in $region($region): '$order($command)' - synonym missing." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ungültiges Synonym." + "$unit($unit) in $region($region): '$order($command)' - invalid synonym." + "$unit($unit) in $region($region): '$order($command)' - invalid synonym." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ungültiges Prefix." + "$unit($unit) in $region($region): '$order($command)' - invalid prefix." + "$unit($unit) in $region($region): '$order($command)' - invalid prefix." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier hat bereits einen Klon." + "$unit($unit) in $region($region): '$order($command)' - The magician already has a clone." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Gebäude auf dem Ozean können nicht betreten werden." + "$unit($unit) in $region($region): '$order($command)' - Buildings on the ocean may not be entered." + "$unit($unit) in $region($region): '$order($command)' - Buildings on the ocean may not be entered." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier werden niemals Bäume wachsen." + "$unit($unit) in $region($region): '$order($command)' - Trees won't grow here." + "$unit($unit) in $region($region): '$order($command)' - Trees won't grow here." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nur ein Magier kann einen Astralkristall benutzen." + "$unit($unit) in $region($region): '$order($command)' - Only mages may use an astralcrystal." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Verbände können nur zwischen Einheiten derselben Partei gebildet werden." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist in keinem Verband." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Eine Einheit kann nur in einem Verband Mitglied sein." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Wie sollen wir uns tarnen?" + "$unit($unit) in $region($region): '$order($command)' - What should we disguise us as?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Wieviel sollen wir einreißen?" + "$unit($unit) in $region($region): '$order($command)' - How much shall we tear down?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dorthin können wir die Einheit nicht transportieren." + "$unit($unit) in $region($region): '$order($command)' - We cannot transport this unit there." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit transportiert uns nicht." + "$unit($unit) in $region($region): '$order($command)' - the unit is not transporting us." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diese Einheit kennt keine Trankrezepte." + "$unit($unit) in $region($region): '$order($command)' - This unit knows no recipes for potions." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nur noch nicht gestärkte Untote können das Ziel dieses Zaubers sein." + "$unit($unit) in $region($region): '$order($command)' - Undead can only be affected once by this spell." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Passwort darf nur Buchstaben und Ziffern enthalten." + "$unit($unit) in $region($region): '$order($command)' - Your password may only contain alphanumeric symbols." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Gegen diese Rasse kann kein Jihad ausgerufen werden." + "$unit($unit) in $region($region): '$order($command)' - You cannot start a jihad against this race." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Gegen welche Rasse soll der Jihad ausgerufen werden?" + "$unit($unit) in $region($region): '$order($command)' - What race did you want the jihad to be against?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dazu muss erst die Spezialeigenschaft erworben werden." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Name und Beschreibung des Gebäudes können nicht geändert werden." + "$unit($unit) in $region($region): '$order($command)' - You cannot change the name and description of this building." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das kann die Einheit nicht." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man keine Schiffe bauen." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man keine Gebäude errichten." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht unterrichten." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man nicht unterrichten." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Pferde müssen leider draußen bleiben." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man niemanden angreifen." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man niemanden bestehlen." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man nicht zaubern." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man nichts übergeben." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nur eine Einzelperson kann das Ticket benutzen." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Gegenstand funktioniert nur in der Eingangshalle." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Gegenstand funktioniert nur in der normalen Welt." + "$unit($unit) in $region($region): '$order($command)' - This item only works in the normal world." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Gut hat die Einheit nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have this good." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Gut wird hier produziert." + "$unit($unit) in $region($region): '$order($command)' - This good is not produced here." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei kann keine weiteren Wyrme besitzen." + "$unit($unit) in $region($region): '$order($command)' - The faction cannot contain any more wyrms." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Vor den Besitzer eines Schiffes oder Gebäudes kann nicht sortiert werden." + "$unit($unit) in $region($region): '$order($command)' - You cannot sort before the owner of a ship or a building." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Besitzer eines Schiffes oder Gebäudes kann nicht neu sortiert werden." + "$unit($unit) in $region($region): '$order($command)' - The owner of a ship or a building cannot be sorted." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Befehl ist nur auf Einheiten innerhalb des selben Gebäudes oder Schiffes anwendbar." + "$unit($unit) in $region($region): '$order($command)' - That order only applies to units in the same building or ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Zieleinheit ist ungültig." + "$unit($unit) in $region($region): '$order($command)' - The target unit is invalid." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ungültiges Locale." + "$unit($unit) in $region($region): '$order($command)' - Invalid locale." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Um soetwas kann man nicht beten." + "$unit($unit) in $region($region): '$order($command)' - You cannot pray for this." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Soetwas kann man nicht opfern." + "$unit($unit) in $region($region): '$order($command)' - You cannot sacrifice this." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Auraangabe fehlerhaft oder zuwenig Aura." + "$unit($unit) in $region($region): '$order($command)' - Invalid aura specification or too little aura." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier ist nicht stark genug, sich den Göttern zu opfern." + "$unit($unit) in $region($region): '$order($command)' - This magician is not strong enough to be sacrificed to the gods." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Was und wieviel soll geopfert werden?" + "$unit($unit) in $region($region): '$order($command)' - What and how much should be sacrificed?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diese Kraft können selbst die Götter nicht mehr mächtiger machen." + "$unit($unit) in $region($region): '$order($command)' - Even the gods cannot improve this power." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nicht genug Karma." + "$unit($unit) in $region($region): '$order($command)' - Not enough karma." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff kann nicht aufs offene Meer hinaus segeln." + "$unit($unit) in $region($region): '$order($command)' - The ship cannot sail into the open seas." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei muß mindestens 10 Runden alt sein." + "$unit($unit) in $region($region): '$order($command)' - The faction has to be 10 turns old." + "$unit($unit) in $region($region): '$order($command)' - The faction has to be 10 turns old." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei hat schon einen Namen." + "$unit($unit) in $region($region): '$order($command)' - The faction is already named." + "$unit($unit) in $region($region): '$order($command)' - The faction is already named." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Gebäude hat schon einen Namen." + "$unit($unit) in $region($region): '$order($command)' - The building is already named." + "$unit($unit) in $region($region): '$order($command)' - The building is already named." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff hat schon einen Namen." + "$unit($unit) in $region($region): '$order($command)' - The ship is already named." + "$unit($unit) in $region($region): '$order($command)' - The ship is already named." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat schon einen Namen." + "$unit($unit) in $region($region): '$order($command)' - The unit is already named." + "$unit($unit) in $region($region): '$order($command)' - The unit is already named." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Keine gültige Rasse angegeben." + "$unit($unit) in $region($region): '$order($command)' - You did not specify a valid race." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit muß sich an Land befinden." + "$unit($unit) in $region($region): '$order($command)' - The unit must be on land." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $building($building) ist kein Steinkreis." + "$unit($unit) in $region($region): '$order($command)' - $building($building) is not a stonecircle." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $building($building) muss vor der Weihe fertiggestellt sein." + "$unit($unit) in $region($region): '$order($command)' - $building($building) has to be complete before it can be blessed." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In $region($target) sind keine Gräber." + "$unit($unit) in $region($region): '$order($command)' - There are no graves in $region($target)." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei muß mindestens 81 Wochen alt sein, um einen Neustart mit einer anderen Rasse zu versuchen." + "$unit($unit) in $region($region): '$order($command)' - The faction must be at least 81 weeks old to restart with a new race." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Soll eine Einheit oder ein Schiff verfolgt werden?" + "$unit($unit) in $region($region): '$order($command)' - Is this unit or ship supposed to be followed?" + "$unit($unit) in $region($region): '$order($command)' - Is this unit or ship supposed to be followed?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Soll eine Einheit oder ein Schiff eine neue Nummer bekommen?" + "$unit($unit) in $region($region): '$order($command)' - Is this unit or ship supposed to get a new number?" + "$unit($unit) in $region($region): '$order($command)' - Is this unit or ship supposed to get a new number?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier können nur Orks rekrutiert werden." + "$unit($unit) in $region($region): '$order($command)' - You can recruit only Orcs here." + "$unit($unit) in $region($region): '$order($command)' - You can recruit only Orcs here." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Region befindet sich in Aufruhr." + "$unit($unit) in $region($region): '$order($command)' - There are riots in this region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Gebäude ist noch nicht fertig gebaut." + "$unit($unit) in $region($region): '$order($command)' - The building is not finished yet." + "$unit($unit) in $region($region): '$order($command)' - The building is not finished yet." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Für das Gebäude wurde noch kein Unterhalt bezahlt." + "$unit($unit) in $region($region): '$order($command)' - Maintenance has not been paid yet." + "$unit($unit) in $region($region): '$order($command)' - Maintenance has not been paid yet." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist mit Ausschiffen beschäftigt.." + "$unit($unit) in $region($region): '$order($command)' - The unit is busy disembarking." + "$unit($unit) in $region($region): '$order($command)' - The unit is busy disembarking." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Typ Einheit kann keine Schiffe betreten." + "$unit($unit) in $region($region): '$order($command)' - Swimmers cannot enter ships." + "$unit($unit) in $region($region): '$order($command)' - Swimmers cannot enter ships." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Typ Einheit kann keine Gebäude betreten." + "$unit($unit) in $region($region): '$order($command)' - this type of unit cannot enter a building." + "$unit($unit) in $region($region): '$order($command)' - this type of unit cannot enter a building." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit oder ihre Tiere würden dort nicht überleben." + "$unit($unit) in $region($region): '$order($command)' - The unit or its animals would not survive there." + "$unit($unit) in $region($region): '$order($command)' - The unit or its animals would not survive there." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dorthin kann die Einheit uns nicht transportieren." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot transport us to this place." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot transport us to this place." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $building($building) wird belagert." + "$unit($unit) in $region($region): '$order($command)' - $building($building) is under siege." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Eintritt in $building($building) wurde verwehrt." + "$unit($unit) in $region($region): '$order($command)' - Entrance to $building($building) was denied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ein Vertrauter wird beschworen, verschwindet jedoch wieder, als er keine Verbindung zu seinem Element herstellen kann." + "$unit($unit) in $region($region): '$order($command)' - A familiar is summoned, but disappears again when it cannot get in contact with its natural element." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nur normale Personen können Steuern eintreiben." + "$unit($unit) in $region($region): '$order($command)' - Only normal characters can collect taxes." + "$unit($unit) in $region($region): '$order($command)' - Only normal characters can collect taxes." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dafür braucht ein Einheit mindestens Kräuterkunde 7." + "$unit($unit) in $region($region): '$order($command)' - A skill of herbalism 7 or higher is required." + "$unit($unit) in $region($region): '$order($command)' - A skill of herbalism 7 or higher is required." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Einheiten in den hinteren Reihen können nicht angreifen." + "$unit($unit) in $region($region): '$order($command)' - Units cannot attack from the second row." + "$unit($unit) in $region($region): '$order($command)' - Units cannot attack from the second row." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - unbekannter Kampfstatus." + "$unit($unit) in $region($region): '$order($command)' - unknown combat status." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht bewaffnet und kampffähig." + "$unit($unit) in $region($region): '$order($command)' - The unit is not armed and ready to fight." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei hat bereits ein Magiegebiet." + "$unit($unit) in $region($region): '$order($command)' - The faction has already chosen a magical school." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können nicht arbeiten." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot work." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot work." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hungernde Soldaten kämpfen nicht." + "$unit($unit) in $region($region): '$order($command)' - Starving units do not fight." + "$unit($unit) in $region($region): '$order($command)' - Starving units do not fight." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hungernde Einheiten können nicht zaubern." + "$unit($unit) in $region($region): '$order($command)' - Starving units cannot cast spells." + "$unit($unit) in $region($region): '$order($command)' - Starving units cannot cast spells." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hungernde Einheiten können nicht bewachen." + "$unit($unit) in $region($region): '$order($command)' - Starving units cannot guard." + "$unit($unit) in $region($region): '$order($command)' - Starving units cannot guard." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Zeige alle was?" + "$unit($unit) in $region($region): '$order($command)' - Show all what?" + "$unit($unit) in $region($region): '$order($command)' - Show all what?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht bauen." + "$unit($unit) in $region($region): '$order($command)' - You cannot build such a thing." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Im astralen Nebel konnte niemand entdeckt werden." + "$unit($unit) in $region($region): '$order($command)' - Noone could be seen in th astral fog." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ein Zauber in dieser Region verhindert das." + "$unit($unit) in $region($region): '$order($command)' - There is an active spell in this region that prevents this." + "$unit($unit) in $region($region): '$order($command)' - There is an active spell in this region that prevents this." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nur im Astralraum gezaubert werden." + "$unit($unit) in $region($region): '$order($command)' - This spell can only be cast in the astral plane." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier gibt es keine Verbindung zur astralen Welt." + "$unit($unit) in $region($region): '$order($command)' - There is no connection to the astral plane here." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Von hier aus kann man die astrale Ebene nicht erreichen." + "$unit($unit) in $region($region): '$order($command)' - You cannot reach the astral plane from here." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Einheit ist kein Magier." + "$unit($unit) in $region($region): '$order($command)' - Unit is not a magician." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Parameter nicht korrekt angegeben." + "$unit($unit) in $region($region): '$order($command)' - Incorrect parameter." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier befindet sich nicht auf einem Schiff." + "$unit($unit) in $region($region): '$order($command)' - The magician is not on board a ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Auf dem Schiff liegt bereits so ein Zauber." + "$unit($unit) in $region($region): '$order($command)' - The ship is already under this spell." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es ist zu gefährlich, ein sturmgepeitschtes Schiff fliegen zu lassen." + "$unit($unit) in $region($region): '$order($command)' - It is too dangerous to fly the ship in the storm." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Syntax Error." + "$unit($unit) in $region($region): '$order($command)' - Syntax Error." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Auraangabe fehlerhaft." + "$unit($unit) in $region($region): '$order($command)' - wrong Aura values." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Zu dieser Einheit kann keine Aura übertragen werden." + "$unit($unit) in $region($region): '$order($command)' - You cannot pass aura on to this unit." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Auf dem Gebäude liegt bereits so ein Zauber." + "$unit($unit) in $region($region): '$order($command)' - There is alrady a spell on that building." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nicht auf hoher See gezaubert werden." + "$unit($unit) in $region($region): '$order($command)' - This spell cannot be cast while you are on the ocean." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nicht auf Monster gezaubert werden." + "$unit($unit) in $region($region): '$order($command)' - This spell cannot be cast on monsters." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nicht auf Untote gezaubert werden." + "$unit($unit) in $region($region): '$order($command)' - This spell cannot be cast on undead." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Stimmung in der Region ist so schlecht, dass niemand auf den Zauber reagiert." + "$unit($unit) in $region($region): '$order($command)' - The mood in this region is so bad that nobody reacts t the spell." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) wusste trotz intensivem Verhör nichts über $region($tregion) zu berichten." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So viele Persoenen übersteigen die Kräfte des Magiers." + "$unit($unit) in $region($region): '$order($command)' -This many people exceed the powers of the magician." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) hat unaufkündbare Bindungen an seine alte Partei." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) have unbreakable prior commitments to their faction." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber gelingt nur in einer Ozeanregion." + "$unit($unit) in $region($region): '$order($command)' - This spell works only in an ocean region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In einer Region ohne Bäume kann man diesen Zauber nicht wirken." + "$unit($unit) in $region($region): '$order($command)' - You cannot cast this spell in a region without trees." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Ziel wurde vergessen." + "$unit($unit) in $region($region): '$order($command)' - No target has been supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das ist keine gültige Rasse." + "$unit($unit) in $region($region): '$order($command)' - This is not a valid race." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Rasse und Zieleinheit wurden vergessen." + "$unit($unit) in $region($region): '$order($command)' - Race and target unit have not been supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die maximale Aura reicht nicht für diesen Zauber." + "$unit($unit) in $region($region): '$order($command)' - Magician's maximum Aura is not high enough for this spell." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier hat bereits einen Vertrauten." + "$unit($unit) in $region($region): '$order($command)' - The magician already has a familiar." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Flammen finden keine Nahrung. Das Feuer erlischt, ohne Schaden anzurichten." + "$unit($unit) in $region($region): '$order($command)' - The flames find no kindling. The fire dies quickly, causing no damage whatsoever." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Um einen Heimstein zu erschaffen, muß der Zauberer in einer Burg sein." + "$unit($unit) in $region($region): '$order($command)' - The magician has to be in a castle to create a homestone." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das ist keine Waldregion." + "$unit($unit) in $region($region): '$order($command)' - This is not a forest region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dorthin führt kein Weg." + "$unit($unit) in $region($region): '$order($command)' - No way is leading in this direction." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Zielregion wurde nicht korrekt angegeben." + "$unit($unit) in $region($region): '$order($command)' - Target region was supplied incorrectly." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Zauber funktioniert nur in der Geisterwelt." + "$unit($unit) in $region($region): '$order($command)' - This spell will only work in the realm of spirits." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Wege zwischen Geisterwelt und Realität scheinen blockiert zu sein." + "$unit($unit) in $region($region): '$order($command)' - The paths to the spirit world seem to be blocked." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Zauber funktioniert nur in Wäldern." + "$unit($unit) in $region($region): '$order($command)' - This spell works only in forests." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Zauber funktioniert nur in der materiellen Welt." + "$unit($unit) in $region($region): '$order($command)' - This spell works only in the material world." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Selbst der mächtigste Magier der Welt könnte keinen Ozean austrocknen lassen." + "$unit($unit) in $region($region): '$order($command)' - Even the gods cannot dry out an entire ocean." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nicht im Sumpf gezaubert werden." + "$unit($unit) in $region($region): '$order($command)' - You cannot cast this spell in a swamp." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nur auf Land gelegt werden." + "$unit($unit) in $region($region): '$order($command)' - This spell works only ashore." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Zauber scheint ungewöhnlich schwach zu sein. Irgendetwas hat die magischen Energien abgeleitet." + "$unit($unit) in $region($region): '$order($command)' - the spell seems exceptionally weak. Something has interfred with the magical energies." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann den Befehl in dieser Runde nicht ausführen, da sie sich bewegt hat." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot execute this command because it has moved." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit bewegt sich nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not move." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier befindet sich nicht auf einem Schiff." + "$unit($unit) in $region($region): '$order($command)' - The magician is not on board a ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff kann in diese Richtung nicht ablegen." + "$unit($unit) in $region($region): '$order($command)' - The ship cannot leave in this direction." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dazu muß sich der Magier in der Burg oder an Bord des Schiffes befinden." + "$unit($unit) in $region($region): '$order($command)' - To do this, the magician has to be in a castle or on board a ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Zauber schlägt fehl." + "$unit($unit) in $region($region): '$order($command)' - The spell fails." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Magiegebiet kann die Einheit nicht lernen." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot learn this magic sphere." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es wurde kein Magiegebiet angegeben." + "$unit($unit) in $region($region): '$order($command)' - No magic sphere was supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diesen Spruch kann der Vertraute nicht zaubern." + "$unit($unit) in $region($region): '$order($command)' - the familiar cannot cast this spell." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diesen Spruch kann man nicht in die Ferne richten." + "$unit($unit) in $region($region): '$order($command)' - You cannot cast this spell on a distant target." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diesen Spruch kann man nicht auf einem sich bewegenden Schiff stehend zaubern." + "$unit($unit) in $region($region): '$order($command)' - You cannot cast this spell while standing on a moving ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber ist nur im Kampf sinnvoll." + "$unit($unit) in $region($region): '$order($command)' - this spell makes only sense in combat." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Selbst in der Bibliothek von Xontormia konnte dieser Spruch nicht gefunden werden." + "$unit($unit) in $region($region): '$order($command)' - Even in the Xontormia Library, this spell could not be found." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es wurde kein Zauber angegeben." + "$unit($unit) in $region($region): '$order($command)' - There was no spell supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diesen Kampfzauber gibt es nicht." + "$unit($unit) in $region($region): '$order($command)' - This combat spell does not exist." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Bauern nehmen dieses großzügige Geschenk nicht an." + "$unit($unit) in $region($region): '$order($command)' - The peasants did not accept this gracious gift." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diesen Zauber kennt die Einheit nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not know this spell." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es konnten keine Luxusgüter verkauft werden." + "$unit($unit) in $region($region): '$order($command)' - No luxury items could be sold." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit geht nicht zu den Bauern." + "$unit($unit) in $region($region): '$order($command)' - The unit does not go to the peasants." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diese Rasse kann eine Burg nicht belagern." + "$unit($unit) in $region($region): '$order($command)' - This race cannot siege a castle." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Trank bekommt der Einheit nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit disagreed with the potion." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Nestwärme kann nur von Insektenvölkern benutzt werden." + "$unit($unit) in $region($region): '$order($command)' - this potion can only be used by insects." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Heiltrank wird automatisch bei Bedarf benutzt." + "$unit($unit) in $region($region): '$order($command)' - This healing potion will be automatically used when needed." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit besitzt den Trank nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have this potion." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es konnten keine Luxusgüter gekauft werden." + "$unit($unit) in $region($region): '$order($command)' - No luxury items could be bought." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es konnten keine Personen übergeben werden." + "$unit($unit) in $region($region): '$order($command)' - No person could be handed over." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Magier arbeiten grundsätzlich nur alleine!" + "$unit($unit) in $region($region): '$order($command)' - Magicians always work alone!" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei hat ein anderes Magiegebiet." + "$unit($unit) in $region($region): '$order($command)' - The faction has a different magic sphere." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Zuviele Alchemisten in der Partei." + "$unit($unit) in $region($region): '$order($command)' - Too many alchemists in the faction." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Zuviele Magier in der Partei." + "$unit($unit) in $region($region): '$order($command)' - Too many magicians in the faction." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hochqualifizierte Personen weigern sich, für andere Parteien zu arbeiten." + "$unit($unit) in $region($region): '$order($command)' - Highly qualified people refuse to work for other parties." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit schließt sich den Bauern an." + "$unit($unit) in $region($region): '$order($command)' - The unit joins the local peasants." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit springt über Bord und ertrinkt." + "$unit($unit) in $region($region): '$order($command)' - The unit jumps over board and drowns." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Region wird bewacht." + "$unit($unit) in $region($region): '$order($command)' - The region is guarded." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Unbekannte Option." + "$unit($unit) in $region($region): '$order($command)' - Unknown Option." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit wird belagert." + "$unit($unit) in $region($region): '$order($command)' - The unit is under siege." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Zum Straßenbau braucht man Steine." + "$unit($unit) in $region($region): '$order($command)' - You need stones to build a road." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Wohin soll die Botschaft gehen?" + "$unit($unit) in $region($region): '$order($command)' - Who is supposed to get this message?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht der Burgherr." + "$unit($unit) in $region($region): '$order($command)' - The unit is not in command of a castle." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht Burgherr der größten Burg in der Region." + "$unit($unit) in $region($region): '$order($command)' - The unit is not in command of the largest castle in the region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht der Kapitän des Schiffes." + "$unit($unit) in $region($region): '$order($command)' - The unit is not captain of a ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist in keiner Burg." + "$unit($unit) in $region($region): '$order($command)' - The unit is not in a castle." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist auf keinem Schiff." + "$unit($unit) in $region($region): '$order($command)' - The unit is not on board a ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist auf einem Schiff." + "$unit($unit) in $region($region): '$order($command)' - The unit is on board a ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat zuwenig Silber, um zu rekrutieren." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough silver for recruiting." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht mehr genug Kristalle für so viele Personen." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough crystals left for this many people." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit befindet sich weder in einer Burg noch auf einem Schiff." + "$unit($unit) in $region($region): '$order($command)' - The unit is neither in a castle nor on board a ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Unterschiedliche Typen können nicht gemischt werden." + "$unit($unit) in $region($region): '$order($command)' - Different types do not mix." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Uns gehört nichts, was man abreißen oder versenken könnte." + "$unit($unit) in $region($region): '$order($command)' - We do not have anything that could be demolished." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Unbekannter Hilfe-Modus." + "$unit($unit) in $region($region): '$order($command)' - Unknown Help- Mode." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Unbekannte Meldungs-Option." + "$unit($unit) in $region($region): '$order($command)' - Unknown Report-Option." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Um in Wüsten Straßen bauen zu können, muß zuerst eine Karawanserei errichtet werden." + "$unit($unit) in $region($region): '$order($command)' - You've got to build a caravansary before building roads through deserts." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Um in Sümpfen Straßen bauen zu können, muß zuerst ein Damm errichtet werden." + "$unit($unit) in $region($region): '$order($command)' - You've got to build a dam before building roads through swamps." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So viele Leute kann die Partei nicht aufnehmen." + "$unit($unit) in $region($region): '$order($command)' - The faction cannot hire so many strangers." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So viele Fremde kann die Partei nicht aufnehmen." + "$unit($unit) in $region($region): '$order($command)' - The faction cannot hire so many strangers." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So viele Fremde kann Deine Partei nicht aufnehmen." + "$unit($unit) in $region($region): '$order($command)' - Your faction cannot hire so many strangers." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht verkaufen." + "$unit($unit) in $region($region): '$order($command)' - You cannot sell this." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht machen." + "$unit($unit) in $region($region): '$order($command)' - You cannot produce this." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht auf dem Markt kaufen." + "$unit($unit) in $region($region): '$order($command)' - You cannot buy that on a market place." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So etwas hat die Einheit nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have such a thing." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Pferde kann man nur in einer Pferdezucht züchten." + "$unit($unit) in $region($region): '$order($command)' - You can breed horses only in a stable." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So etwas gibt es hier nicht." + "$unit($unit) in $region($region): '$order($command)' - That resource does not exist in this region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Personen können nur an Menschen übergeben werden." + "$unit($unit) in $region($region): '$order($command)' - Characters can be given only to Human parties." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ohne einen Handelsposten gibt es keinen Markt." + "$unit($unit) in $region($region): '$order($command)' - There is no marketplace without at least a tradepost." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nur Elfen können diese Bögen herstellen." + "$unit($unit) in $region($region): '$order($command)' - Only Elves can make these bows." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nur die EMail-Adresse angeben!" + "$unit($unit) in $region($region): '$order($command)' - Submit only email-address, please!" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nummer kann nicht vergeben werden." + "$unit($unit) in $region($region): '$order($command)' - Number can not be assigned." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nummer ist schon belegt." + "$unit($unit) in $region($region): '$order($command)' - Number is already in use." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nummer ist nicht im gültigen Bereich." + "$unit($unit) in $region($region): '$order($command)' - Number is not valid." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nichts angegeben, was wir übergeben sollen." + "$unit($unit) in $region($region): '$order($command)' - Item to be handed over was not supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Namen dürfen keine Klammern enthalten." + "$unit($unit) in $region($region): '$order($command)' - Names may not contain parenthesis." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nachricht zu lang - gekürzt." + "$unit($unit) in $region($region): '$order($command)' - Message has been cut (too long).." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Man muß angeben, ob eine Burg, ein Schiff, eine Region oder eine Einheit beschrieben werden soll." + "$unit($unit) in $region($region): '$order($command)' - Specify if description is for a castle, a ship, a region or a unit." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Man muß angeben, ob eine Burg, ein Schiff, eine Einheit, eine Region oder eine Partei benannt werden soll." + "$unit($unit) in $region($region): '$order($command)' - Specify if a castle, a ship, a region or a unit is supposed to be named." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es sind keine Kräuter zu finden." + "$unit($unit) in $region($region): '$order($command)' - No herbs could be found." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Man braucht mindestens zwei Pferde, um sie zu züchten." + "$unit($unit) in $region($region): '$order($command)' - You need at least two horses to breed more." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Magier müssen zum studieren allein sein." + "$unit($unit) in $region($region): '$order($command)' - When studying, magicians need to be alone." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Leere Einheiten können nicht übergeben werden." + "$unit($unit) in $region($region): '$order($command)' - Empty units can not be handed over." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Laen kann nur in einem Bergwerk abgebaut werden." + "$unit($unit) in $region($region): '$order($command)' - Laen can be excavated only in a mine." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Keiner hier kann Straßen bauen." + "$unit($unit) in $region($region): '$order($command)' - Nobody here can build roads." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann keine weiteren Güter handeln." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot trade any more goods." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Keiner hier kann ein Gebäude errichten." + "$unit($unit) in $region($region): '$order($command)' - Nobody here can construct a building." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Keiner hier ist gelernter Schiffbauer." + "$unit($unit) in $region($region): '$order($command)' - Nobody here is a skilled ship builder." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit will nicht transportiert werden." + "$unit($unit) in $region($region): '$order($command)' - The unit doen not want to be transported." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Insekten können im Winter nur in Wüsten rekrutiert werden." + "$unit($unit) in $region($region): '$order($command)' - In winter, insects can be recruited only in deserts." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In Gletschern können keine Insekten rekrutiert werden." + "$unit($unit) in $region($region): '$order($command)' - Insects cannot be recruited in glaciers." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In dieser Einheit gibt es niemanden, den man transferieren könnte." + "$unit($unit) in $region($region): '$order($command)' - Nobody in this unit can be transferred." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Illusionen können eine Region nicht bewachen." + "$unit($unit) in $region($region): '$order($command)' - Illusions cannot guard a region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man keine Straße bauen." + "$unit($unit) in $region($region): '$order($command)' - You cannot build a road here." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier gibt es schon einen Hafen." + "$unit($unit) in $region($region): '$order($command)' - There is already a port in this region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier gibt es keine Bauern." + "$unit($unit) in $region($region): '$order($command)' - There are no peasants in this region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier gibt es keinen normalen Wald." + "$unit($unit) in $region($region): '$order($command)' - There is no normal forest in this region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier gibt es keine Mallornbäume." + "$unit($unit) in $region($region): '$order($command)' - There are no Mallorn trees here." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit fährt nicht mit uns." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have a RIDE-order." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Geldgebot fehlt." + "$unit($unit) in $region($region): '$order($command)' - Money offer is missing." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht genügend Materialien für den Schiffbau." + "$unit($unit) in $region($region): '$order($command)' - the unit is lacking materials to build the ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Für das Elixier benötigt man Drachenblut." + "$unit($unit) in $region($region): '$order($command)' - Dragon blood is required for this elixir." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Falsches Passwort." + "$unit($unit) in $region($region): '$order($command)' - Wrong password." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es wurde keine EMail-Adresse angegeben." + "$unit($unit) in $region($region): '$order($command)' - No email-address was supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es wurde kein Name angegeben." + "$unit($unit) in $region($region): '$order($command)' - No name was supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es konnte kein Bauer gefangen werden." + "$unit($unit) in $region($region): '$order($command)' - No peasant could be caught." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es gibt keine Abstimmung mit dieser Nummer." + "$unit($unit) in $region($region): '$order($command)' - There is no agreement with this number." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Einheit muß zuerst die Region bewachen." + "$unit($unit) in $region($region): '$order($command)' - first, the unit must guard the region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Einheit ist nicht bewaffnet und kampffähig." + "$unit($unit) in $region($region): '$order($command)' - The unit is not armed and fighting fit." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ein Schiff oder eine Burg muß angegeben werden." + "$unit($unit) in $region($region): '$order($command)' - A ship or a castle must be supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ein Fluch verhindert die Übergabe." + "$unit($unit) in $region($region): '$order($command)' - A curse prevented the transfer from happening." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Talent wurde nicht erkannt." + "$unit($unit) in $region($region): '$order($command)' - The skill could not be recognized." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Talent kann die Einheit nicht lernen." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot learn this skill." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diesen Gegenstand kann man nicht benutzen." + "$unit($unit) in $region($region): '$order($command)' - This item cannot be used." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit nimmt niemanden an." + "$unit($unit) in $region($region): '$order($command)' - This unit does not take anybody." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Eine hungernde Einheit kann niemanden weggeben." + "$unit($unit) in $region($region): '$order($command)' - Hungry units cannot give anybody away." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diese Einheit kann niemanden weggeben." + "$unit($unit) in $region($region): '$order($command)' - This unit cannot give anybody away." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) hat keinen Kontakt mit uns aufgenommen." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) did not contact us." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es kann hier kein Kontakt zur Astralwelt aufgenommen werden." + "$unit($unit) in $region($region): '$order($command)' - There is no connection to the astral plane." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) hat keinen Kontakt mit uns aufgenommen und widersteht dem Zauber." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) did not contact us, and resists the spell." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) hat keinen Kontakt mit uns aufgenommen, aber widersteht dem Zauber nicht." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) did not contact us, but cannot resist the spell." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Richtung wurde nicht erkannt." + "$unit($unit) in $region($region): '$order($command)' - Direction was not recognized." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Richtung '$dirname' wurde nicht erkannt." + "$unit($unit) in $region($region): '$order($command)' - Direction '$dirname' was not recognized." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Region wird von Nichtalliierten bewacht." + "$unit($unit) in $region($region): '$order($command)' - This region is guarded by a non allied faction." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Region wird von $unit($guard), einer nichtalliierten Einheit, bewacht." + "$unit($unit) in $region($region): '$order($command)' - This region is guarded by $unit($guard), a non-allied unit." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Pferde würden ertrinken." + "$unit($unit) in $region($region): '$order($command)' - The horses would drown." + "$unit($unit) in $region($region): '$order($command)' - The horses would drown." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - The faction could not be found." + "$unit($unit) in $region($region): '$order($command)' - The faction could not be found." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Lernkosten können nicht bezahlt werden." + "$unit($unit) in $region($region): '$order($command)' - Tuition was too high to be paid." + "$unit($unit) in $region($region): '$order($command)' - Tuition was too high to be paid." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Gegenstand kann nur in der realen Welt benutzt werden." + "$unit($unit) in $region($region): '$order($command)' - This object can only be used in the real world." + "$unit($unit) in $region($region): '$order($command)' - This object can only be used in the real world." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) ist nicht ausreichend getarnt." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) is not sufficiently stealthy." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) is not sufficiently stealthy." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - The unit could not be found." + "$unit($unit) in $region($region): '$order($command)' - The unit could not be found." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Einheit kann nichts gegeben werden." + "$unit($unit) in $region($region): '$order($command)' - You cannot give anything to this unit." + + + + + + + + + "$unit($mage) horcht $unit($unit) über $region($tregion) aus." + "$unit($mage) questions $unit($unit) about $region($tregion)." + + + + + + + + "$unit($mage) verschafft $unit($unit) einige feuchtfröhliche Stunden mit heftigen Nachwirkungen." + "$unit($mage) invites $unit($unit) for a few too many drinks and a massive hangover." + + + + + + + "$unit($unit) hat höllische Kopfschmerzen und kann sich an die vergangene Woche nicht mehr erinnern. Nur noch daran, wie alles mit einer fröhlichen Feier in irgendeiner Taverne anfing...." + "$unit($unit) has a splitting headache and can hardly remember last week. Except that it all started in the tavern..." + + + + + + + + "$unit($mage) besänftigt $unit($unit)." + "$unit($mage) calms $unit($unit)." + + + + + + + "$unit($unit) verfiel dem Glücksspiel und hat fast sein ganzes Hab und gut verspielt." + "$unit($unit) gambles for high stakes and loses almost everything." + + + + + + + + + "$unit($unit) schenkt $unit($mage) $resources($items)." + "$unit($unit) gives $unit($mage) $resources($items)." + + + + + + + + + "$unit($mage) läßt $unit($target) als $race($race,$unit.size($target)) erscheinen." + "$unit($mage) makes $unit($target) appear as $race($race,$unit.size($target))." + + + + + + + "$unit($unit) wird kurz von einem magischen Licht umhüllt." + "$unit($unit) is briefly surrounded by a magical light." + + + + + + + + "$unit($unit) konnte nur $int($ships) von $int($maxships) Schiffen verzaubern." + "$unit($unit) could only enchant $int($ships) of $int($maxships) ships." + + + + + + "$unit($unit) beschwört einen magischen Wind, der die Schiffe über das Wasser treibt." + "$unit($unit) calls up a magical storm that whips the ship over the waters." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit weiß nichts über Botanik." + "$unit($unit) in $region($region): '$order($command)' - The unit does not know anything about herbalism." + "$unit($unit) in $region($region): '$order($command)' - The unit does not know anything about herbalism." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit weiß nicht, wie man gaukelt." + "$unit($unit) in $region($region): '$order($command)' - The unit does not know how to entertain." + "$unit($unit) in $region($region): '$order($command)' - The unit does not know how to entertain." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit trägt zuviel Gewicht, um sich bewegen zu können." + "$unit($unit) in $region($region): '$order($command)' - The unit is too heavily loaded to move." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann soviele Pferde nicht bändigen." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot tame that many horses." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann sich nicht fortbewegen." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot move." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht handeln." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot trade." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann keine Tränke herstellen." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot make potions." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann keine weiteren langen Befehle ausführen." + "$unit($unit) in $region($region): '$order($command)' - The unit is exhausted from battle." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht genug Silber." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough silver." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough silver." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht erfahren genug dafür." + "$unit($unit) in $region($region): '$order($command)' - The unit is not experienced enough to do this." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht der Eigentümer." + "$unit($unit) in $region($region): '$order($command)' - The unit is not he owner." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht bewaffnet und kampffähig." + "$unit($unit) in $region($region): '$order($command)' - The unit is not armed and fighting fit." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist mit uns alliiert." + "$unit($unit) in $region($region): '$order($command)' - This unit is one of our allies." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist in keiner Taverne." + "$unit($unit) in $region($region): '$order($command)' - The unit is not in a tavern." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist eine der unsrigen." + "$unit($unit) in $region($region): '$order($command)' - This unit is one of our own." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist auf hoher See." + "$unit($unit) in $region($region): '$order($command)' - The unit is off shore." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat soetwas nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have this." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht genug Wagenlenker oder zuviel andere Fracht, um die Wagen aufzuladen." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough coachmen or too much freights to lad the wagons." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht genug Silber." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough silver." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat keinen Kontakt mit uns aufgenommen." + "$unit($unit) in $region($region): '$order($command)' - The unit did not contact us." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat keine Spionage gelernt." + "$unit($unit) in $region($region): '$order($command)' - The unit has not yet learned espionage." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat keine Kräuter." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have any herbs." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat diesen Trank nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have this potion." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat diesen Gegenstand nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have this item." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat diesen Gegenstand zwar, aber sämtliche $int($reservation) $resource($resource,$reservation) sind reserviert." + "$unit($unit) in $region($region): '$order($command)' - The unit has this item, but all $int($reservation) $resource($resource,$reservation) are reserved." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat diese Kräuter nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have these herbs." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Einheiten dürfen nicht mehr als $int($maxsize) Personen enthalten." + "$unit($unit) in $region($region): '$order($command)' - Units may not have more than $int($maxsize) members." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit darf nicht an Bord kommen, da sie das Schiff überladen würde." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot go aboard, the ship would be overloaded." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit darf nicht an Bord kommen." + "$unit($unit) in $region($region): '$order($command)' - This unit has no permission to come on board." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit befindet sich nicht in unserer Burg." + "$unit($unit) in $region($region): '$order($command)' - The unit is not in our castle." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit befindet sich nicht an Bord unseres Schiffes." + "$unit($unit) in $region($region): '$order($command)' - The unit is not on board our ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Burg wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - The castle could not be found." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Botschaft enthält keinen Text." + "$unit($unit) in $region($region): '$order($command)' - The message does not contain text." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Bauern sind schlecht gelaunt." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Anzahl zu verkaufender Produkte fehlt." + "$unit($unit) in $region($region): '$order($command)' - The amount of items for sale is missing." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Anzahl zu kaufender Produkte fehlt." + "$unit($unit) in $region($region): '$order($command)' - The amount of items to buy is missing." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Fluch verhindert das." + "$unit($unit) in $region($region): '$order($command)' - The escape prevented that from happening." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Belagerungszustand macht Spionage unmöglich." + "$unit($unit) in $region($region): '$order($command)' - Espionage was not possible due to siege." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Belagerungszustand macht die Kontaktaufnahme unmöglich." + "$unit($unit) in $region($region): '$order($command)' - Contact was not possible due to siege." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Befehl wurde nicht erkannt." + "$unit($unit) in $region($region): '$order($command)' - Unknown command." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dazu gibt es keine Informationen." + "$unit($unit) in $region($region): '$order($command)' - There is no information available for the request." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - The ship could not be found." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff muß erst verlassen werden." + "$unit($unit) in $region($region): '$order($command)' - First you have to leave the ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff ist zu schwer beladen, um in See zu stechen." + "$unit($unit) in $region($region): '$order($command)' - The ship is too heavily loaded to sail." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $ship($ship) ist zu groß, um fliegen zu können." + "$unit($unit) in $region($region): '$order($command)' - $ship($ship) is too bulky to fly." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff ist schon fertig." + "$unit($unit) in $region($region): '$order($command)' - The ship is already completed." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff ist noch nicht fertig gebaut." + "$unit($unit) in $region($region): '$order($command)' - The ship has not yet been completed." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff ist auf hoher See." + "$unit($unit) in $region($region): '$order($command)' - The ship is off shore." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff hat sich bereits bewegt." + "$unit($unit) in $region($region): '$order($command)' - The ship has moved already." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Besitzer muss das Gebäude zuerst verlassen." + "$unit($unit) in $region($region): '$order($command)' - The owner must first LEAVE the building." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff gehört uns nicht." + "$unit($unit) in $region($region): '$order($command)' - The ship is not ours." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Gebäude gehört uns nicht." + "$unit($unit) in $region($region): '$order($command)' - The building is not ours." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff befindet sich auf hoher See." + "$unit($unit) in $region($region): '$order($command)' - The ship is still off shore." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das macht wenig Sinn." + "$unit($unit) in $region($region): '$order($command)' - That does not make much sense." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das kann man nicht sabotieren." + "$unit($unit) in $region($region): '$order($command)' - That cannot be sabotaged." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das ist sinnlos." + "$unit($unit) in $region($region): '$order($command)' - That is useless." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das geht nicht mehr." + "$unit($unit) in $region($region): '$order($command)' - This is no longer possible." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Gebäude wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - Building could not be found." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Gebäude gehört uns nicht." + "$unit($unit) in $region($region): '$order($command)' - The building is not ours." + "$unit($unit) in $region($region): '$order($command)' - The building is not ours." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Gebäude ist bereits fertig." + "$unit($unit) in $region($region): '$order($command)' - The building is already completed." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht unterrichtet werden." + "$unit($unit) in $region($region): '$order($command)' - this unit cannot be taught." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Beschreibung zu lang - gekürzt." + "$unit($unit) in $region($region): '$order($command)' - Description has been cut (too long)." + "$unit($unit) in $region($region): '$order($command)' - Description has been cut (too long)." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Auf hoher See kann man nicht bewachen." + "$unit($unit) in $region($region): '$order($command)' - You cannot guard off shore." + "$unit($unit) in $region($region): '$order($command)' - You cannot guard off shore." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Auf dem Schiff befinden sich zuwenig erfahrene Seeleute." + "$unit($unit) in $region($region): '$order($command)' - There are not enough experienced sailors on board the ship." + "$unit($unit) in $region($region): '$order($command)' - There are not enough experienced sailors on board the ship." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - ${error}." + "$unit($unit) in $region($region): '$order($command)' - ${error}." + + + + + + + "$unit($unit) benutzt ein $resource($item,1)." + "$unit($unit) uses a $resource($item,1)." + "$unit($unit) uses a $resource($item,1)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $resource($item,0) können nur von Ein-Personen Einheiten benutzt werden." + "$unit($unit) in $region($region): '$order($command)' - $resource($item,0) can only be used by single-person units." + "$unit($unit) in $region($region): '$order($command)' - $resource($item,0) can only be used by single-person units." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist noch zu erschöpft vom Einmarsch um zu attackieren." + "'$order($command)' - $unit($unit) marched into $region($region) during the last turn and is too exhausted to attack." + "'$order($command)' - $unit($unit) marched into $region($region) during the last turn and is too exhausted to attack." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) sind friedliebend und attackieren niemand." + "'$order($command)' - $race($race,0) are peace-loving and will not attack anyone." + "'$order($command)' - $race($race,0) are peace-loving and will not attack anyone." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit steht nicht im benötigten Gebäude, $localize($building)." + "$unit($unit) in $region($region): '$order($command)' - The unit must be in a $localize($building) to produce this." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dazu braucht man das Talent $skill($skill)." + "$unit($unit) in $region($region): '$order($command)' - this requires the skill $skill($skill)." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Man benötigt mindestens $int($minskill) $skill($skill), um $resource($product,0) zu pflanzen." + "$unit($unit) in $region($region): '$order($command)' - At least $skill($skill) $int($minskill) is needed for planting $resource($product,0)." + "$unit($unit) in $region($region): '$order($command)' - At least $skill($skill) $int($minskill) is needed for planting $resource($product,0)." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Man benötigt mindestens $int($minskill) $skill($skill), um $resource($product,0) zu produzieren." + "$unit($unit) in $region($region): '$order($command)' - You need at least $int($minskill) $skill($skill), to produce $resource($product,0)." + + + + + + "$string" + "$string" + + + + + + "$string" + "$string" + + + + + + "$string" + "$string" + + + + + + + + "$unit($unit) übergibt $int($amount) Person$if($eq($amount,1),"","en") an $unit($target)." + "$unit($unit) transfers $int($amount) person$if($eq($amount,1),"","s") to $unit($target)." + + + + + + + + + + "$unit($unit) übergibt $int($amount) $resource($resource,$amount) an $unit($target)." + "$unit($unit) gives $int($amount) $resource($resource,$amount) to $unit($target)." + + + + + + + + + + "$unit($target) erhält $int($amount) $resource($resource,$amount) von $unit($unit)." + "$unit($target) receives $int($amount) $resource($resource,$amount) from $unit($unit)." + + + + + + + + "$unit($unit) übergibt $int($amount) Person$if($eq($amount,1),"","en") an die Bauern." + "$unit($unit) transfers $int($amount) person$if($eq($amount,1),"","s") to the local peasants." + + + + + + + + + "$unit($unit) übergibt $int($amount) $resource($resource,$amount) an die Bauern." + "$unit($unit) gives $int($amount) $resource($resource,$amount) to the local peasants." + + + + + + + + "$unit($unit) bezahlt den Unterhalt von $building($building)." + "$unit($unit) pays the maintenance for $building($building)." + "$unit($unit) pays the maintenance for $building($building)." + + + + + + + + "$unit($unit) fehlen $resource($item,0) für den Betrieb von $building($building)." + "$unit($unit) lacks $resource($item,0) to operate $building($building)." + + + + + + + "$unit($unit) kann den Unterhalt von $building($building) nicht bezahlen." + "$unit($unit) cannot pay the maintenance for $building($building)." + "$unit($unit) cannot pay the maintenance for $building($building)." + + + + + + "Der Unterhalt von $building($building) konnte nur verspätet gezahlt werden, das Gebäude war diese Woche nicht funktionstüchtig." + "The upkeep for $building($building) was paid late, the building was not operational this week." + "The upkeep for $building($building) was paid late, the building was not operational this week." + + + + + + + + "$unit($unit) verdient am Handel in $region($region) Steuern in Höhe von $int($amount) Silber." + "$unit($unit) collected $int($amount) silver trade tax in $region($region)." + "$unit($unit) collected $int($amount) silver trade tax in $region($region)." + + + + + + + "$unit($unit) benutzt $resource($potion,1)." + "$unit($unit) uses $resource($potion,1)." + "$unit($unit) uses $resource($potion,1)." + + + + + + "Hier wütete die Pest, und $int($dead) Bauern starben." + "The region is visited by the plague and $int($dead) peasants died." + "The region is visited by the plague and $int($dead) peasants died." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Um in Gletschern Straßen bauen zu können, muß zuerst ein Tunnel errichtet werden." + "$unit($unit) in $region($region): '$order($command)' - You've got to build a tunnel before building roads through glaciers." + "$unit($unit) in $region($region): '$order($command)' - You've got to build a tunnel before building roads through glaciers." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Syntax: MAGIEGEBIET [1-5]." + "$unit($unit) in $region($region): '$order($command)' - Syntax: MAGIC SPHERE [1-5]." + "$unit($unit) in $region($region): '$order($command)' - Syntax: MAGIC SPHERE [1-5]." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Deine Partei muss mindestens $int($turns) alt sein, um etwas an andere Parteien übergeben zu können." + "$unit($unit) in $region($region): '$order($command)' - Your faction must be at least $int($turns) weeks old to give something to another faction." + "$unit($unit) in $region($region): '$order($command)' - Your faction must be at least $int($turns) weeks old to give something to another faction." + + + + + + "Bitte sende die Befehle nächste Runde ein, wenn du weiterspielen möchtest." + "Merci d'envoyer vos ordres pour le tour suivant si vous désirez continuer à jouer." + "Please send in orders for the next turn if you want to continue playing." + + + + + + + "Deine Partei ist noch $int($turns) Wochen immun gegen Angriffe." + "Votre faction est immunisée contre les agressions durant $int($turns) semaines encore." + "Your faction is immune against assaults for $int($turns) more weeks." + + + + + + + + "$faction($member) ist mit $int($votes) Stimmen aus $alliance($alliance) ausgeschlossen worden." + "$faction($member) was kicked from $alliance($alliance) by $int($votes) of the alliance's members." + "$faction($member) was kicked from $alliance($alliance) by $int($votes) of the alliance's members." + + + + + + "$alliance($alliance) scheidet aus dem Spiel aus, nachdem alle Tempel verloren gingen." + "$alliance($alliance) has to leave the game after all their temples were lost." + "$alliance($alliance) has to leave the game after all their temples were lost." + + + + + + + "$int($votes) Mitglieder von $alliance($alliance) haben versucht, Deine Partei aus der Allianz auszuschliessen." + "$int($votes) members of $alliance($alliance) tried to kick you out of the alliance." + "$int($votes) members of $alliance($alliance) tried to kick you out of the alliance." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In dieser Regione können Pyramiden gebaut werden." + "$unit($unit) in $region($region): '$order($command)' - Pyramids may be build in this region." + "$unit($unit) in $region($region): '$order($command)' - Pyramids may be build in this region." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Auf $ship($ship) liegt beeits ein Zauber." + "$unit($unit) in $region($region): '$order($command)' - There is already a spell on $ship($ship)." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es ist zu gefährlich, diesen Zauber auf das fliegende Schiff $ship($ship) zu legen." + "$unit($unit) in $region($region): '$order($command)' - It is far too dangerous to put this spell on the flying ship $ship($ship)." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In dieser Region können keine Pyramiden gebaut werden. Die nächste Pyramidenregion ist zwischen $int($mindist) und $int($maxdist) Regionen entfernt." + "$unit($unit) in $region($region): '$order($command)' - No pyramids may be build in this region. The closest region to build a pyramid in is between $int($mindist) and $int($maxdist) regions away." + "$unit($unit) in $region($region): '$order($command)' - No pyramids may be build in this region. The closest region to build a pyramid in is between $int($mindist) and $int($maxdist) regions away." + + + + + + + + "$unit($unit) kann in $region($region) nicht durch das Wurmloch reisen, da die Einheit entweder zu gross ist oder teure Talente besitzt." + "$unit($unit) cannot travel through the wormhole in $region($region) because the unit is either too big or has restricted skills." + "$unit($unit) cannot travel through the wormhole in $region($region) because the unit is either too big or has restricted skills." + + + + + + + "$unit($unit) reist durch ein Wurmloch nach $region($region)." + "$unit($unit) travels through a wormhole to $region($region)." + "$unit($unit) travels through a wormhole to $region($region)." + + + + + + "In $region($region) erscheint ein Wurmloch." + "A wormhole appears in $region($region)." + "A wormhole appears in $region($region)." + + + + + + "Das Wurmloch in $region($region) schließt sich." + "The wormhole in $region($region) disappears." + "The wormhole in $region($region) disappears." + + + + + + + "$int($amount) Krieger von $unit($unit) benutzen ihre Flammenschwerter." + "$int($amount) fighters of $unit($unit) are using their flaming sword." + + + + + + + "$int($amount) Krieger von $unit($unit) feuern ihre Katapulte ab." + "$int($amount) fighters of $unit($unit) launch their catapults." + + + + + + "Der Kampf wurde ausgelöst von ${factions}." + "The battle was initiated by ${factions}." + + + + + + "$unit($unit) konnte durch einen Heiltrank überleben." + "$unit($unit) was saved by a haling potion." + + + + + + "$unit($unit) konnte dem Gegner eine Falle stellen." + "$unit($unit) lured the enemy into an ambush." + + + + + + "$unit($unit) überrascht den Gegner." + "$unit($unit) surprises the enemies." + + + + + + + "$unit($unit) versucht $spell($spell) zu zaubern, doch der Zauber schlägt fehl!" + "$unit($unit) tries to cast $spell($spell), but the spell fails!" + + + + + "Der Kampf wurde abgebrochen, da alle Verteidiger flohen." + "The battle was aborted because all enemies escaped." + + + + + + "... in der $int($row). Kampflinie:" + "... in combat rank $int($row):" + + + + + + + "$unit($mage) zaubert $spell($spell), aber niemand war in Reichweite." + "$unit($mage) casts $spell($spell), but nobody was in range." + + + + + + "Einheiten nach dem Kampf:" + "Units after the battle:" + + + + + + "" + "" + + + + + + + + + "$unit($mage) ruft $int($amount) $race($race, $amount) zu Hilfe." + "$unit($mage) calls for the help of $int($amount) $race($race, $amount)." + + + + + + + "$unit($mage) beschwört Trugbilder herauf." + "$unit($mage) summons a mirage." + + + + + + + "$unit($mage) murmelt eine düster klingende Formel. Ein plötzlicher Tumult entsteht, der sich jedoch schnell wieder legt." + + + + + + + "$unit($mage) murmelt eine düster klingende Formel. Ein plötzlicher Tumult entsteht und bringt die Kampfaufstellung durcheinander." + + + + + + + "$unit($mage) stimmt einen seltsamen Gesang an. Ein plötzlicher Tumult entsteht, der sich jedoch schnell wieder legt." + + + + + + + "$unit($mage) stimmt einen seltsamen Gesang an. Ein plötzlicher Tumult entsteht und bringt die Kampfaufstellung durcheinander." + "$unit($mage) begins a mysterious chant. great confusion sweeps through the ranks of the enemy." + + + + + + + + "$unit($mage) läßt die Mauern von $building($building) in einem unheimlichen magischen Licht erglühen." + + + + + + + "Einheiten vor der $int($turn). Runde:" + "Units before turn $int($turn):" + + + + + + "In $region($region) findet ein Kampf statt." + "There is a battle in $region($region)." + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($dead) $if($eq($dead,1),"Krieger wurde", "Krieger wurden") getötet." + "$unit($mage) casts $spell($spell): $int($dead) $if($eq($dead,1),"enemy was", "enemies were") killed." + + + + + + + + "$unit($mage) läßt die Erde in $region($region) erzittern." + "$unit($mage) shakes the earth in $region($region)." + + + + + + + + "$unit($mage) verflucht das Land in $region($region), und eine Dürreperiode beginnt." + "$unit($mage) puts a curse on the lands of $region($region) and a drought sets in." + + + + + + + "$unit($mage) erschafft einen Klon." + "$unit($mage) creates a clone." + + + + + + + + + "$unit($mage) verliert sich in die Träume von $unit($unit) und erhält einen Eindruck von $region($region)." + + + + + + + + + "$unit($mage) verschafft $unit($unit) ein schönes Nachtleben in $region($region)." + + + + + + + + "$unit($mage) sorgt für schlechten Schlaf in $region($region)." + + + + + + + + + "$unit($mage) beschwört $int($amount) $race($race,$amount)." + "$unit($mage) summons $int($amount) $race($race,$amount)." + + + + + + + + + "$unit($mage) erschafft in $region($region) eine verheerende Feuersbrunst. $int($amount) Bäume fallen den Flammen zum Opfer." + "$unit($mage) creates a flaming inferno in $region($region). $int($amount) trees fall vistim to the flames." + + + + + + + + "Mit einem Ritual bindet $unit($mage) die magischen Kräfte der Erde in die Mauern von $building($building)." + + + + + + + + "$unit($mage) weight $building($building)." + "$unit($mage) blesses $building($building)." + + + + + + + + "$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Eis schmilzt und verwandelt sich in Morast. Reißende Ströme spülen die mageren Felder weg und ersäufen Mensch und Tier. Was an Bauten nicht den Fluten zum Opfer fiel, verschlingt der Morast. Die sengende Hitze verändert die Region für immer." + + + + + + + + "$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Die Felder verdorren und Pferde verdursten. Die Hungersnot kostet vielen Bauern das Leben. Vertrocknete Bäume recken ihre kahlen Zweige in den blauen Himmel, von dem erbarmungslos die sengende Sonne brennt." + + + + + + + + "$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Die Felder verdorren und Pferde verdursten. Die Hungersnot kostet vielen Bauern das Leben. Vertrocknete Bäume recken ihre kahlen Zweige in den blauen Himmel, von dem erbarmungslos die sengende Sonne brennt. Die Dürre verändert die Region für immer." + + + + + + + + "$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Das Eis zerbricht und eine gewaltige Flutwelle verschlingt die Region." + + + + "Die Darbietungen eines fahrenden Gauklers begeistern die Leute. Die fröhliche und ausgelassene Stimmung seiner Lieder überträgt sich auf alle Zuhörer." + "A touring minstrel entertains the locals. The joyous and generous disposition of his songs prove infectious." + + + + + + + "Die Darbietungen von $unit($mage) begeistern die Leute. Die fröhliche und ausgelassene Stimmung seiner Lieder überträgt sich auf alle Zuhörer." + "$unit($mage) entertains the locals. The joyous and generous disposition of his songs prove infectious." + + + "In der Luft liegt ein wunderschönes Lied, dessen friedfertiger Stimmung sich niemand entziehen kann. Einige Leute werfen sogar ihre Waffen weg." + "A wondrous song fills the air and enchants the public. The song's peaceful melody makes several listeners drop their weapon." + + + + + + "Die Gesangskunst von $unit($mage) begeistert die Leute. Die friedfertige Stimmung des Lieds überträgt sich auf alle Zuhörer. Einige werfen ihre Waffen weg." + "The marvelous singing of $unit($mage) enchants the public. The song's peaceful melody makes several listeners drop their weapon." + + + + + + + "$unit($mage) beschwört $int($number) Dämonen aus dem Reich der Schatten." + "$unit($mage) summons $int($number) demons from the realm of shadows." + + + + + + + + "$unit($mage) zaubert $spell($spell)." + "$unit($mage) casts $spell($spell)." + + + + + + + + + + "$unit($mage) zaubert $spell($spell). $int($amount) Krieger verloren Erinnerungen, $int($dead) wurden getötet." + + + + + + + + + "$unit($mage) zaubert $spell($spell). $int($amount) Krieger verloren kurzzeitig ihr Gedächtnis." + "$unit($mage) casts $spell($spell). $int($amount) fighters are temporarily losing some of their memories." + + + + + + + + + "$unit($mage) ruft $int($amount) $race($race, 0) zu Hilfe." + + + + + + + + "$unit($unit) tötete $int($dead) Krieger." + "$unit($unit) killed $int($dead) opponents." + + + + + + + + + + "Heer $int($index)($abbrev): $int($dead) Tote, $int($fled) Geflohene, $int($survived) Überlebende." + "Army $int($index)($abbrev): $int($dead) dead, $int($fled) fled, $int($survived) survivors." + + + + + + + + "$unit($mage) in $region($region): '$order($command)' - Dieser Zauber kann nicht mit Stufenangabe gezaubert werden." + "$unit($mage) in $region($region): '$order($command)' - This spell cannot be cast with variable level." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dorthin führt kein Weg." + "$unit($unit) in $region($region): '$order($command)' - There is no way leading there." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Zu $region($target) kann kein Kontakt hergestellt werden." + "$unit($unit) in $region($region): '$order($command)' - $region($target) could not be contacted." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit $unit($target) hat keinen Kontakt mit uns aufgenommen." + "$unit($unit) in $region($region): '$order($command)' - The unit $unit($target) did not contact us." + + + + + + + + + "Antimagie von $unit.dative($self) blockiert in $region($region) einen Zauber von $unit.dative($mage)." + "In $region($region), anti-magic from $unit($self) blocks the spell of $unit($mage)." + + + + + + + + + "$unit($self) schwächt in $region($region) einen Zauber von $unit.dative($mage) durch Antimagie ab." + "In $region($region), anti-magic from $unit($self) reduces the effect of $unit($mage)'s spell." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $int($pacified) Regionen wurden befriedet." + "$unit($unit) in $region($region): '$order($command)' - $int($pacified) regions have been pacified." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Keine Region konnte befriedet werden." + "$unit($unit) in $region($region): '$order($command)' - No region could be pacified." + + + + + + + + "$unit($unit) in $region($region) bläst das Horn des Tanzes. In der ganzen Region breitet sich eine friedliche Feststimmmung aus." + "$unit($unit) in $region($region) blows the Horn of Dancing. Peaceful harmony spreads over the region." + + + + + + + + "$unit($unit) in $region($region) bläst das Horn des Tanzes, doch niemand hier lässt sich von Stimmung anstecken." + "$unit($unit) in $region($region) blows the Horn of Dancing, but nobody here gets into the mood." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die $ship($ship) wird jetzt schneller ihr Ziel erreichen." + "$unit($unit) in $region($region): '$order($command)' - The $ship($ship) will now be faster." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier fühlt sich durch den Trank magische gestärkt." + "$unit($unit) in $region($region): '$order($command)' - The mage is magically invigorated." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ausser sich vor Furcht geben die Bauern dem Barden $int($money) Silber." + "$unit($unit) in $region($region): '$order($command)' - Stricken with fear the peasants give the bard $int($money) silver." + + + + + + + + "$unit($unit) spielt einen Dudelsack. Ausser sich vor Furcht geben die Bauern $int($money) Silber." + "$unit($unit) plays the bagpipe. Stricken with fear the peasants give $int($money) silver." + + + + + + + + "$unit($unit) in $region($region) erschafft eine Akademie der Künste." + "$unit($unit) in $region($region) creates an academy of arts." + + + + + + + + "$unit($unit) in $region($region) erschafft eine Skulptur." + "$unit($unit) in $region($region) creates a sculpture." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Region ist zu weit entfernt." + "$unit($unit) in $region($region): '$order($command)' - That region is too far away." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Wege aus dieser Region sind blockiert." + "$unit($unit) in $region($region): '$order($command)' - The connections from to this regions are blocked." + + + + + + + "$unit($unit) erscheint plötzlich." + "$unit($unit) appears." + + + + + + + "$unit($unit) wird durchscheinend und verschwindet." + "$unit($unit) disappears." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) ist zu schwer." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) is too heavy." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei hat bereits $int($count) von $int($max) Helden." + "$unit($unit) in $region($region): '$order($command)' - The faction already has $int($count) of $int($max) heroes." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können keine Helden erwählen." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot be heroes." + + + + + + + + "$unit($unit) wird mit $int($cost) Silber zum Helden ernannt." + "$unit($unit) uses $int($cost) silber for a promotion." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nur $int($have) von $int($cost) benötigtem Silber." + "$unit($unit) in $region($region): '$order($command)' - The unit has $int($have) of $int($cost) silver required." + + + + + + + "Eine gewaltige Flutwelle verschlingt $region($region) und alle Bewohner." + "A tidal wave wipes out $region($region) and all who lived there." + + + + + + + + "Eine gewaltige Flutwelle verschlingt $unit($unit) in $region($region)." + "A tidal wave wipes out $region($region) and kills $unit($unit)." + + + + + + + + "$unit($unit) reaktiviert den astralen Schutzschild in $region($region)." + "$unit($unit) reactivates the astral protection shield in $region($region)." + + + + + + + + + + "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"kehrte auf seine", "kehrten auf ihre") Felder zurück." + "$unit($unit) in $region($region): $int($number) $race($race,$number) returned to the fields." + + + + + + + + + + "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"wurde zum Baum", "wurden zu Bäumen")." + "$unit($unit) in $region($region): $int($number) $race($race,$number) turned into $if($eq($number,1),"a tree", "trees")." + + + + + + + + + + "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"verfaulte", "verfaulten")." + "$unit($unit) in $region($region): $int($number) $race($race,$number) whithered and died." + + + + + + + + + + "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"zerfiel", "zerfielen") zu Staub." + "$unit($unit) in $region($region): $int($number) $race($race,$number) turned to dust." + + + + + + + + + + "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"verschwand", "verschwanden") über Nacht." + "$unit($unit) in $region($region): $int($number) $race($race,$number) disappearedin the night." + + + + + + + + + "Der Waldbrand in $region($region) griff auch auf $region($next) über, und $int($trees) verbrannten." + "The fire in $region($region) spread to $region($next) and $int($trees) were burnt." + + + + + + + + "$unit($mage) ruft in $region($region) eine Pest hervor." + "$unit($mage) sends the plague on $region($region)." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Eine Partei darf nicht aus mehr als $int($allowed) Einheiten bestehen." + "$unit($unit) in $region($region): '$order($command)' - A faction may not consist of more than $int($allowed) units." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Eine Allianz darf aus nicht mehr als $int($allowed) Einheiten bestehen." + "$unit($unit) in $region($region): '$order($command)' - An alliance may not consist of more than $int($allowed) units." + + + + + + + + + + "$unit($unit) in $region($region): $int($amount) $resource($item,$amount) zerfallen zu Staub." + "$unit($unit) in $region($region): $int($amount) $resource($item,$amount) turn to dust." + + + + + + + + + "Die $ship($ship) ist mit gutem Wind gesegnet$if($lt($duration,3),", doch der Zauber beginnt sich bereits aufzulösen",""). ($int36($id))" + "The $ship($ship) is blessed with favourable winds$if($lt($duration,3),", but the spell is starting to wear thin",""). ($int36($id))" + + + + + + + "Kräftige Stürme haben dieses Schiff in die Luft gehoben. ($int36($id))" + "Powerful storms have lifted this ship high into the air. ($int36($id))" + + + + + + + "Mächtige Magie verhindert den Kontakt zur Realität. ($int36($id))" + "Powerful magic disrupts our contact with reality. ($int36($id))" + + + + + + + + "Ein silberner Schimmer umgibt die $ship($ship). ($int36($id))" + "A silvery shimmer surrounds the $ship($ship). ($int36($id))" + + + + + + + + "Auf den Mauern von $building($building) erkennt man seltsame Runen. ($int36($id))" + "The walls of $building($building) are inscribed with strange runes. ($int36($id))" + + + + + + + + + "$unit($mage) erschafft $int($number) $resource($item,$number)." + "$unit($mage) creates $int($number) $resource($item,$number)." + + + + + + + + "Auf den Planken von $ship($ship) erkennt man seltsame Runen. ($int36($id))" + "The plank of $ship($ship) are inscribed with strange runes. ($int36($id))" + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Kompassnadel springt wild hin und her und es lässt sich keine Richtung erkennen." + "$unit($unit) in $region($region): '$order($command)' - The needle jumps wildly and there is no specific direction recognizable." + "$unit($unit) in $region($region): '$order($command)' - The needle jumps wildly and there is no specific direction recognizable." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Kompassnadel zeigt nach $direction($dir)." + "$unit($unit) in $region($region): '$order($command)' - The needle points $direction($dir)." + "$unit($unit) in $region($region): '$order($command)' - The needle points $direction($dir)." + + + + + + + + "$unit($unit) wird aus der astralen Ebene nach $region($region) geschleudert." + "$unit($unit) is sent from the astral plain to $region($region)." + "$unit($unit) is sent from the astral plain to $region($region)." + + + + + + + + "$unit($target) wird von $unit($unit) in eine andere Welt geschleudert." + "$unit($unit) sends $unit($target) to another world." + "$unit($unit) sends $unit($target) to another world." + + + + + + + + "$unit($unit) versuchte erfolglos, $unit($target) in eine andere Welt zu schleudern." + "$unit($unit) tried but failed to send $unit($target) to another world." + "$unit($unit) tried but failed to send $unit($target) to another world." + + + + + + + "NUMMER PARTEI $int36($id): Die Partei kann nicht mehr als einmal ihre Nummer wecheln." + "NUMBER FACTION $int36($id): Your faction can only change its number once." + + + + + + + "NUMMER PARTEI $int36($id): Diese Nummer wird von einer anderen Partei benutzt." + "NUMBER FACTION $int36($id): This number is being used by another faction." + + + + + + + + "Eine Botschaft von $unit($unit): '$message'" + "A message from $unit($unit): '$message'" + + + + + + + + "Plötzlich stolpert $unit($unit) über einige $localize($name). Nach kurzem Zögern entschließen die $localize($name), sich Deiner Partei anzuschließen." + + + + + + + "$unit($unit) entdeckt ein kleines Dorf. Die meisten Häuser wurden durch einen über die Ufer getretenen Fluß zerstört. Eine Gruppe der verzweifelten Menschen schließt sich deiner Partei an." + "$unit($unit) discovers a small village. Most of the houses have been destroyed by flooding, and a group of the distressed villagers join your faction." + + + + "Ein Bauernmob erhebt sich und macht Jagd auf Schwarzmagier." + "An angry mob forms and hunts practitioners of the dark arts." + + + + + + + "Vertrauter von $unit($unit)" + "Familiar of $unit($unit)" + + + + + + + + + "$unit($unit) rekrutiert $int($amount) $localize($archetype)." + "$unit($unit) recruits $int($amount) $localize($archetype)." + + + + + + + "Dein Passwort enthält Zeichen, die bei der Nachsendung von Reports Probleme bereiten können. Bitte beachte, dass Passwortenur aus Buchstaben von A bis Z und Zahlen bestehen dürfen. Dein neues Passwort ist '${newpass}'." + "Your password was changed because it contained illegal characters. Legal passwords may only contain numbers and letters from A to Z. Your new Password is '${newpass}'." + + + + "Miiauuuuuu..." + "Meeoooooow..." + + + + + + + "Die Götter segnen $unit($unit) mit der richtigen Rasse." + "The gods are blessing $unit($unit) with the correct race." + + + + + + + "Der Versuch, die Greifenschwingen zu benutzen, schlug fehl. $unit($unit) konnte die Ebene der Herausforderung nicht verlassen." + + + + + + + "$unit($unit) springt in die ewigen Feuer des Kraters." + + + + + + + + "$unit($unit) springt in die ewigen Feuer des Kraters." + + + + + + + + "In $region($region) erklingt die Stimme des Torwächters: 'Nur wer ohne materielle Güter und noch lernbegierig ist, der darf die Ebene der Herausforderung betreten. Und vergiß nicht mein Trinkgeld.'. $unit($unit) erhielt keinen Einlaß." + + + + + + + + "In $region($region) öffnet sich ein Portal. Eine Stimme ertönt, und spricht: 'Willkommen in der Ebene der Herausforderung'. $unit($unit) durchschreitet das Tor zu einer anderen Welt." + + + + + + + "$unit($unit) scheint von einer seltsamen Krankheit befallen." + "$unit($unit) is stricken by a strange disease." + + + + + + + + + "$unit($unit) erbeutet $int($amount) $resource($item,$amount)." + "$unit($unit) collects $int($amount) $resource($item,$amount)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es ist so schön friedlich, man möchte hier niemanden angreifen." + "$unit($unit) in $region($region): '$order($command)' - It's so quiet and peaceful, nobody wants to attack anybody right now." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können nichts lernen." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot study." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Migranten können keine kostenpflichtigen Talente lernen." + "$unit($unit) in $region($region): '$order($command)' - Migrants cannot study this." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es kann maximal $int($amount) Magier pro Partei geben." + "$unit($unit) in $region($region): '$order($command)' - There may not be more tha $int($amount) magicians in your faction." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es kann maximal $int($amount) Alchemisten pro Partei geben." + "$unit($unit) in $region($region): '$order($command)' - There may not be more tha $int($amount) alchemists in your faction." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) versteht unsere Art von Magie nicht." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) does not understand our kind of magic." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Kapitän muß ein Segeltalent von mindestens $int($value) haben, um $ship($ship) zu befehligen." + "$unit($unit) in $region($region): '$order($command)' - The captain needs a sailing skill of at least $int($value), to command $ship($ship)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In dieser Region gibt es keine Brücken und Straßen mehr zu bauen." + "$unit($unit) in $region($region): '$order($command)' - the roads and bridges in this region are complete." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Um $localize($name) zu bauen, braucht man ein Talent von mindestens $int($value)." + "$unit($unit) in $region($region): '$order($command)' - To build $localize($name) requires a skill of at least $int($value)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diese Einheit kämpft nicht." + "$unit($unit) in $region($region): '$order($command)' - This unit will not fight." + + + + + + + + + "$unit($unit) erhielt $resources($items) von der $ship($ship)." + "$unit($unit) received $resources($items) from the $ship($ship)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nciht auf Untote gezaubert werden." + + + + + + + + "Achtung: $faction($faction) hat seit $int($turns) Wochen keine + Züge eingeschickt und könnte dadurch in Kürze aus dem Spiel + ausscheiden." + "Warning: $faction($faction) has not been sending in + orders for $int($turns) turns and may be leaving the game soon." + + + diff --git a/res/prefixes.xml b/res/prefixes.xml new file mode 100644 index 000000000..0e8e9587a --- /dev/null +++ b/res/prefixes.xml @@ -0,0 +1,31 @@ + + + Dunkel + Licht + Klein + Hoch + Huegel + Berg + Wald + Sumpf + Schnee + Sonnen + Mond + See + Tal + Schatten + Hoehlen + Blut + Wild + Chaos + Nacht + Nebel + Grau + Frost + Finster + Duester + flame + ice + star + black + diff --git a/res/resources/horse.xml b/res/resources/horse.xml new file mode 100644 index 000000000..abf6d856d --- /dev/null +++ b/res/resources/horse.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/res/resources/hp.xml b/res/resources/hp.xml new file mode 100644 index 000000000..fb1b6e32f --- /dev/null +++ b/res/resources/hp.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/res/resources/iron.xml b/res/resources/iron.xml new file mode 100644 index 000000000..94dbc6390 --- /dev/null +++ b/res/resources/iron.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/res/resources/laen.xml b/res/resources/laen.xml new file mode 100644 index 000000000..efb13c5ed --- /dev/null +++ b/res/resources/laen.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/res/resources/log.xml b/res/resources/log.xml new file mode 100644 index 000000000..c017682fc --- /dev/null +++ b/res/resources/log.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/res/resources/mallorn.xml b/res/resources/mallorn.xml new file mode 100644 index 000000000..e5c01506b --- /dev/null +++ b/res/resources/mallorn.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/res/resources/mallornseed.xml b/res/resources/mallornseed.xml new file mode 100644 index 000000000..1c7c1a800 --- /dev/null +++ b/res/resources/mallornseed.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/resources/peasant.xml b/res/resources/peasant.xml new file mode 100644 index 000000000..32e1e1ca1 --- /dev/null +++ b/res/resources/peasant.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/res/resources/seed.xml b/res/resources/seed.xml new file mode 100644 index 000000000..2193fb8c8 --- /dev/null +++ b/res/resources/seed.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/resources/stone.xml b/res/resources/stone.xml new file mode 100644 index 000000000..eed2fd2df --- /dev/null +++ b/res/resources/stone.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/res/ships.xml b/res/ships.xml new file mode 100644 index 000000000..6c6821be4 --- /dev/null +++ b/res/ships.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/spells.xml b/res/spells.xml new file mode 100644 index 000000000..080365c55 --- /dev/null +++ b/res/spells.xml @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/spoils.xml b/res/spoils.xml new file mode 100644 index 000000000..952971cab --- /dev/null +++ b/res/spoils.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/terrains.xml b/res/terrains.xml new file mode 100644 index 000000000..edd8895ab --- /dev/null +++ b/res/terrains.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/weapons/axe.xml b/res/weapons/axe.xml new file mode 100644 index 000000000..7ee77b21e --- /dev/null +++ b/res/weapons/axe.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/res/weapons/bow.xml b/res/weapons/bow.xml new file mode 100644 index 000000000..c64392966 --- /dev/null +++ b/res/weapons/bow.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/res/weapons/catapult.xml b/res/weapons/catapult.xml new file mode 100644 index 000000000..2ea16d9a2 --- /dev/null +++ b/res/weapons/catapult.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/res/weapons/crossbow.xml b/res/weapons/crossbow.xml new file mode 100644 index 000000000..318628b81 --- /dev/null +++ b/res/weapons/crossbow.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/res/weapons/firesword.xml b/res/weapons/firesword.xml new file mode 100644 index 000000000..9e8284fe6 --- /dev/null +++ b/res/weapons/firesword.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/res/weapons/greatbow.xml b/res/weapons/greatbow.xml new file mode 100644 index 000000000..542bd41a8 --- /dev/null +++ b/res/weapons/greatbow.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/res/weapons/greatsword.xml b/res/weapons/greatsword.xml new file mode 100644 index 000000000..481ff680c --- /dev/null +++ b/res/weapons/greatsword.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/res/weapons/halberd.xml b/res/weapons/halberd.xml new file mode 100644 index 000000000..bf3fb4af7 --- /dev/null +++ b/res/weapons/halberd.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/res/weapons/laensword.xml b/res/weapons/laensword.xml new file mode 100644 index 000000000..31ec8b9e6 --- /dev/null +++ b/res/weapons/laensword.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/res/weapons/lance.xml b/res/weapons/lance.xml new file mode 100644 index 000000000..1271c48f9 --- /dev/null +++ b/res/weapons/lance.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/res/weapons/mallornbow.xml b/res/weapons/mallornbow.xml new file mode 100644 index 000000000..f61ea8e97 --- /dev/null +++ b/res/weapons/mallornbow.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/res/weapons/mallorncrossbow.xml b/res/weapons/mallorncrossbow.xml new file mode 100644 index 000000000..8d4a5027b --- /dev/null +++ b/res/weapons/mallorncrossbow.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/res/weapons/mallornlance.xml b/res/weapons/mallornlance.xml new file mode 100644 index 000000000..88973f3e0 --- /dev/null +++ b/res/weapons/mallornlance.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/res/weapons/mallornspear.xml b/res/weapons/mallornspear.xml new file mode 100644 index 000000000..8c3782e4c --- /dev/null +++ b/res/weapons/mallornspear.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/res/weapons/rep_crossbow.xml b/res/weapons/rep_crossbow.xml new file mode 100644 index 000000000..1e550a190 --- /dev/null +++ b/res/weapons/rep_crossbow.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/res/weapons/runesword.xml b/res/weapons/runesword.xml new file mode 100644 index 000000000..566fe1589 --- /dev/null +++ b/res/weapons/runesword.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/res/weapons/rustyaxe.xml b/res/weapons/rustyaxe.xml new file mode 100644 index 000000000..5399de62d --- /dev/null +++ b/res/weapons/rustyaxe.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/res/weapons/rustygreatsword.xml b/res/weapons/rustygreatsword.xml new file mode 100644 index 000000000..ac1385b11 --- /dev/null +++ b/res/weapons/rustygreatsword.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/res/weapons/rustyhalberd.xml b/res/weapons/rustyhalberd.xml new file mode 100644 index 000000000..4f237b989 --- /dev/null +++ b/res/weapons/rustyhalberd.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/res/weapons/rustysword.xml b/res/weapons/rustysword.xml new file mode 100644 index 000000000..f73dcd6e2 --- /dev/null +++ b/res/weapons/rustysword.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/res/weapons/spear.xml b/res/weapons/spear.xml new file mode 100644 index 000000000..c6479707a --- /dev/null +++ b/res/weapons/spear.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/res/weapons/sword.xml b/res/weapons/sword.xml new file mode 100644 index 000000000..0d3830e2e --- /dev/null +++ b/res/weapons/sword.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/scripts/callbacks.lua b/scripts/callbacks.lua new file mode 100644 index 000000000..33d34e4b5 --- /dev/null +++ b/scripts/callbacks.lua @@ -0,0 +1,11 @@ +callbacks = {} + +callbacks["attrib_init"] = function(attr) + if attr.name ~= nil then + local init = callbacks["init_" .. attr.name] + if init ~=nil then + init(attr) + end + end +end + diff --git a/scripts/default.lua b/scripts/default.lua new file mode 100644 index 000000000..7afd5fa8b --- /dev/null +++ b/scripts/default.lua @@ -0,0 +1,121 @@ +function change_locales(localechange) + for loc, flist in pairs(localechange) do + for index, name in pairs(flist) do + f = get_faction(atoi36(name)) + if f ~= nil then + f.locale = loc + print("LOCALECHANGE ", f, loc) + end + end + end +end + +function dbupdate() + update_scores() + edb = db.open(config.basepath.."/eressea.db") + if edb~=nil then + edb:update_factions() + edb:update_scores() + else + print("could no open "..config.basepath.."/eressea.db") + end +end + +function nmr_check(maxnmrs) + local nmrs = get_nmrs(1) + if nmrs >= maxnmrs then + print("Shit. More than " .. maxnmrs .. " factions with 1 NMR (" .. nmrs .. ")") + write_summary() + write_game("aborted.dat") + return -1 + end + print (nmrs .. " Factions with 1 NMR") + return 0 +end + +function open_game(turn) + file = "" .. get_turn() + if read_game(file .. ".dat", "binary")~=0 then + return read_game(file, "text") + end + return 0 +end + +function write_emails(locales) + local files = {} + local key + local locale + local file + for key, locale in pairs(locales) do + files[locale] = io.open(config.basepath .. "/emails." .. locale, "w") + end + + local faction + for faction in factions() do + if faction.email~="" then + files[faction.locale]:write(faction.email .. "\n") + end + end + + for key, file in pairs(files) do + file:close() + end +end + +function write_addresses() + local file + local faction + + file = io.open(config.basepath .. "/adressen", "w") + for faction in factions() do + -- print(faction.id .. " - " .. faction.locale) + file:write(tostring(faction) .. ":" .. faction.email .. ":" .. faction.info .. "\n") + end + + file:close() +end + +function write_aliases() + local file + local faction + + file = io.open(config.basepath .. "/aliases", "w") + for faction in factions() do + local unit + if faction.email ~= "" then + file:write("partei-" .. itoa36(faction.id) .. ": " .. faction.email .. "\n") + for unit in faction.units do + file:write("einheit-" .. itoa36(unit.id) .. ": " .. faction.email .. "\n") + end + end + end + + file:close() +end + +function write_files(locales) + write_passwords() + write_reports() + write_summary() + -- write_emails(locales) + -- write_aliases() + -- write_addresses() +end + +function write_scores() + scores = {} + for r in regions() do + f = r.owner + if f~=nil then + value = scores[f.id] + if value==nil then value=0 end + value = value + r:get_resource("money")/100 + scores[f.id] = value + end + end + for f in factions() do + score=scores[f.id] + if score==nil then score=0 end + print(math.floor(score)..":"..f.name..":"..itoa36(f.id)) + end +end diff --git a/scripts/dumptable.lua b/scripts/dumptable.lua new file mode 100644 index 000000000..58f10e8df --- /dev/null +++ b/scripts/dumptable.lua @@ -0,0 +1,95 @@ +--------------------------------------------- +-- Return indentation string for passed level +--------------------------------------------- +local function tabs(i) + return string.rep(".",i).." " -- Dots followed by a space +end + +----------------------------------------------------------- +-- Return string representation of parameter's value & type +----------------------------------------------------------- +local function toStrType(t) + local function fttu2hex(t) -- Grab hex value from tostring() output + local str = tostring(t); + if str == nil then + return "tostring() failure! \n" + else + local str2 = string.match(str,"[ :][ (](%x+)") + if str2 == nil then + return "string.match() failure: "..str.."\n" + else + return "0x"..str2 + end + end + end + -- Stringify a value of a given type using a table of functions keyed + -- by the name of the type (Lua's version of C's switch() statement). + local stringify = { + -- Keys are all possible strings that type() may return, + -- per http://www.lua.org/manual/5.1/manual.html#pdf-type. + ["nil"] = function(v) return "nil (nil)" end, + ["string"] = function(v) return '"'..v..'" (string)' end, + ["number"] = function(v) return v.." (number)" end, + ["boolean"] = function(v) return tostring(v).." (boolean)" end, + ["function"] = function(v) return fttu2hex(v).." (function)" end, + ["table"] = function(v) return fttu2hex(v).." (table)" end, + ["thread"] = function(v) return fttu2hex(v).." (thread)" end, + ["userdata"] = function(v) return fttu2hex(v).." (userdata)" end + } + return stringify[type(t)](t) +end + +------------------------------------- +-- Count elements in the passed table +------------------------------------- +local function lenTable(t) -- What Lua builtin does this simple thing? + local n=0 -- '#' doesn't work with mixed key types + if ("table" == type(t)) then + for key in pairs(t) do -- Just count 'em + n = n + 1 + end + return n + else + return nil + end +end + +-------------------------------- +-- Pretty-print the passed table +-------------------------------- +local function do_dumptable(t, indent, seen) + -- "seen" is an initially empty table used to track all tables + -- that have been dumped so far. No table is dumped twice. + -- This also keeps the code from following self-referential loops, + -- the need for which was found when first dumping "_G". + if ("table" == type(t)) then -- Dump passed table + seen[t] = 1 + if (indent == 0) then + print ("The passed table has "..lenTable(t).." entries:") + indent = 1 + end + for f,v in pairsByKeys(t) do + if ("table" == type(v)) and (seen[v] == nil) then -- Recurse + print( tabs(indent)..toStrType(f).." has "..lenTable(v).." entries: {") + do_dumptable(v, indent+1, seen) + print( tabs(indent).."}" ) + else + print( tabs(indent)..toStrType(f).." = "..toStrType(v)) + end + end + else + print (tabs(indent).."Not a table!") + end +end + +-------------------------------- +-- Wrapper to handle persistence +-------------------------------- +function dumptable(t) -- Only global declaration in the package + -- This wrapper exists only to set the environment for the first run: + -- The second param is the indentation level. + -- The third param is the list of tables dumped during this call. + -- Getting this list allocated and freed was a pain, and this + -- wrapper was the best solution I came up with... + return do_dumptable(t, 0, {}) +end diff --git a/scripts/eventbus.lua b/scripts/eventbus.lua new file mode 100644 index 000000000..e69de29bb diff --git a/scripts/gates.lua b/scripts/gates.lua new file mode 100644 index 000000000..aeb1e2a3c --- /dev/null +++ b/scripts/gates.lua @@ -0,0 +1,25 @@ +-- implements gates and travel between them +-- used in HSE and Eressea + +function gate_travel(b, units) + -- we've found which units we want to exchange, now swap them: + local u + for key, u in pairs(units) do + u.region = b.region + u.building = b + end +end + +function gate_units(b, maxsize) + local size = maxsize + local units = {} + local u + + for u in b.units do + if u.number<=size and u.weight<=u.capacity then + units[u] = u + size = size - u.number + end + end + return units +end diff --git a/scripts/init.lua b/scripts/init.lua new file mode 100644 index 000000000..ae39c50b2 --- /dev/null +++ b/scripts/init.lua @@ -0,0 +1,43 @@ +require(config.game .. ".modules") +require "default" +require "resources" + +function run_editor() + local turn = get_turn() + if turn==0 then + turn = read_turn() + set_turn(turn) + end + read_game(turn .. ".dat") + gmtool.editor() +end + +function run_tests() + print("running tests") + require "lunit" + lunit.clearstats() + local argv = tests or {} + local stats = lunit.main(argv) + if stats.errors > 0 or stats.failed > 0 then + return 1 + end + return 0 +end + +function run_turn() + require(config.game .. ".main") + + local turn = get_turn() + if turn==0 then + turn = read_turn() + set_turn(turn) + end + + orderfile = orderfile or config.basepath .. '/orders.' .. turn + print("executing turn " .. get_turn() .. " with " .. orderfile) + local result = process(orderfile) + if result==0 then + dbupdate() + end + return result +end diff --git a/scripts/multis.lua b/scripts/multis.lua new file mode 100644 index 000000000..ad0b77783 --- /dev/null +++ b/scripts/multis.lua @@ -0,0 +1,101 @@ +function kill_nonstarters() + for f in factions() do + if f.lastturn==1 then + kill_faction(f, true) + end + end +end + +function kill_multis(multis, destructive) + for idx, fno in ipairs(multis) do + local f = get_faction(fno) + if f~=nil and f.email=="doppelspieler@eressea.de" then + kill_faction(f, destructive) + end + end +end + +function mark_multis(multis, block) + if multis~=nil then + for idx, fno in ipairs(multis) do + local f = get_faction(fno) + if f~=nil and f.email~="doppelspieler@eressea.de" then + print("* multi-player " .. tostring(f)) + mark_multi(f, block) + end + end + end +end + +-- destroy a faction +-- destructive: kill all of its buildings and the home region, too. + +function kill_faction(f, destructive) + for u in f.units do + local r = u.region + local b = u.building + unit.destroy(u) + if destructive and b~=nil then + building.destroy(b) + local nuke = true + for v in r.units do + if v.faction.id~=f.id then + -- print("cannot nuke: " .. tostring(v.faction)) + nuke = false + break + end + end + r.terrain_name = nil + if nuke and num_oceans(r)<=1 then + -- print("nuke!") + r.terrain = "ocean" + else + -- print("cannot nuke: > 1 oceans") + r.terrain = "glacier" + r.peasants = 10 + r:set_resource("money", 100) + b = building.create(r, "monument") + b.size = 1 + b.name = "Memento Mori" + b.info = "Eine kleine " .. translate("race::" .. f.race .."_x") .. "-Statue erinnert hier an ein verschwundenes Volk" + end + end + end + faction.destroy(f) +end + +local function mark_multi(f, block) + f.password = "doppelspieler" + f.email = "doppelspieler@eressea.de" + f.banner = "Diese Partei steht wegen vermuteten Doppelspiels unter Beobachtung." + for u in f.units do + u.race_name = "toad" + if block and u.building~=nil then + local found = false + for u2 in u.region.units do + if u2.faction.id~=u.faction.id then + found = true + break + end + end + if not found then + u.region.terrain_name = "firewall" + u.region:set_flag(2) -- RF_BLOCKED + end + end + end +end + +local function num_oceans(r) + local oceans = 0 + local p = r:next(5) + for d = 0,5 do + local n = r:next(d) + if p.terrain~="ocean" and n.terrain=="ocean" then + oceans = oceans +1 + end + p = n + end + return oceans +end + diff --git a/scripts/resources.lua b/scripts/resources.lua new file mode 100644 index 000000000..688fe3d1d --- /dev/null +++ b/scripts/resources.lua @@ -0,0 +1,89 @@ +function peasant_getresource(u) + return u.region:get_resource("peasant") +end + +function peasant_changeresource(u, delta) + local p = u.region:get_resource("peasant") + p = p + delta + if p < 0 then + p = 0 + end + u.region:set_resource("peasant", p) + return p +end + +function hp_getresource(u) + return u.hp +end + +function hp_changeresource(u, delta) + local hp = u.hp + delta + + if hp < u.number then + if hp < 0 then + hp = 0 + end + u.number = hp + end + u.hp = hp + return hp +end + +function horse_limit(r) + return r:get_resource("horse") +end + +function horse_produce(r, n) + local horses = r:get_resource("horse") + if horses>=n then + r:set_resource("horse", horses-n) + else + r:set_resource("horse", 0) + end +end + +function log_limit(r) +-- if r:get_flag(1) then -- RF_MALLORN +-- return 0 +-- end + return r:get_resource("tree") + r:get_resource("sapling") +end + +function log_produce(r, n) + local trees = r:get_resource("tree") + if trees>=n then + r:set_resource("tree", trees-n) + else + r:set_resource("tree", 0) + n = n - trees + trees = r:get_resource("sapling") + if trees>=n then + r:set_resource("sapling", trees-n) + else + r:set_resource("sapling", 0) + end + end +end + +function mallorn_limit(r) + if not r:get_flag(1) then -- RF_MALLORN + return 0 + end + return r:get_resource("tree") + r:get_resource("sapling") +end + +function mallorn_produce(r, n) + local trees = r:get_resource("tree") + if trees>=n then + r:set_resource("tree", trees-n) + else + r:set_resource("tree", 0) + n = n - trees + trees = r:get_resource("sapling") + if trees>=n then + r:set_resource("sapling", trees-n) + else + r:set_resource("sapling", 0) + end + end +end diff --git a/scripts/schema.sql b/scripts/schema.sql new file mode 100644 index 000000000..f2b88d16e --- /dev/null +++ b/scripts/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE email(id INTEGER PRIMARY KEY, md5 VARCHAR(32) UNIQUE NOT NULL, email VARCHAR(32), bounces INT DEFAULT 0, confirmed TIMESTAMP DEFAULT NULL); +CREATE TABLE faction (id INTEGER PRIMARY KEY, user_id INTEGER REFERENCES user(id), no INTEGER, name VARCHAR(64), game_id INTEGER REFERENCES game(id), race VARCHAR(10), lang CHAR(2)); +CREATE TABLE faction_email (faction_id INTEGER REFERENCES faction(id), email_id INTEGER REFERENCES email(id)); +CREATE TABLE game (id INTEGER PRIMARY KEY, name VARCHAR(20), last_turn INTEGER); +CREATE TABLE score (turn INTEGER, faction_id INTEGER REFERENCES faction(id), value INTEGER, UNIQUE(turn, faction_id)); +CREATE TABLE user(id INTEGER PRIMARY KEY, email_id INTEGER REFERENCES email(id), creation TIMESTAMP DEFAULT CURRENT_TIMESTAMP); diff --git a/scripts/setup.lua b/scripts/setup.lua new file mode 100644 index 000000000..e4bfb726b --- /dev/null +++ b/scripts/setup.lua @@ -0,0 +1,16 @@ +local srcpath = config.source_dir +local respath = srcpath .. '/' .. config.game .. '/res/' +local paths = { config.game..'/scripts/?.lua';'lunit/?.lua','external/lunit/?.lua','scripts/?.lua';'scripts/?' } + +tests = {'common'} +for idx, test in pairs(tests) do + tests[idx] = srcpath .. '/scripts/tests/' .. test .. '.lua' +end + +for idx, path in pairs(paths) do + package.path = srcpath .. '/' .. path .. ';' .. package.path +end + +read_xml(respath..'config-'..config.game..'.xml', respath..'catalog-'..config.game..'.xml') + +require "init" diff --git a/scripts/spells.lua b/scripts/spells.lua new file mode 100644 index 000000000..8269e72e6 --- /dev/null +++ b/scripts/spells.lua @@ -0,0 +1,151 @@ +function creation_message(mage, type, number) + local msg = message.create("item_create_spell") + msg:set_unit("mage", mage) + msg:set_int("number", number) + msg:set_resource("item", type) + return msg +end + +local function create_item(mage, level, name, number) + local count = number or 1 + mage:add_item(name, count); + local msg = creation_message(mage, name, count) + msg:send_faction(mage.faction) + return level +end + +-- Wasser des Lebens +function create_potion_p2(r, mage, level, force) + return create_item(mage, level, "p2", level) +end + +-- Siebenmeilentee +function create_potion_p0(r, mage, level, force) + return create_item(mage, level, "p0", level) +end + +-- Wundsalbe +function create_potion_ointment(r, mage, level, force) + return create_item(mage, level, "ointment", level) +end + +-- Bauernblut +function create_potion_peasantblood(r, mage, level, force) + return create_item(mage, level, "peasantblood", level) +end + +-- Pferdeglück +function create_potion_p9(r, mage, level, force) + return create_item(mage, level, "p9", level) +end + +-- Schaffenstrunk +function create_potion_p3(r, mage, level, force) + return create_item(mage, level, "p3", level) +end + +-- Heiltrank +function create_potion_p14(r, mage, level, force) + return create_item(mage, level, "p14", level) +end + +-- Elixier der Macht +function create_potion_p13(r, mage, level, force) + return create_item(mage, level, "p13", level) +end + +-- Erschaffe ein Flammenschwert +function create_firesword(r, mage, level, force) + return create_item(mage, level, "firesword") +end + +-- Erschaffe einen Gürtel der Trollstärke +function create_trollbelt(r, mage, level, force) + return create_item(mage, level, "trollbelt") +end + +-- Erschaffe einen Ring der Unsichtbarkeit +function create_roi(r, mage, level, force) + return create_item(mage, level, "roi") +end + +-- Erschaffe einen Ring der flinken Finger +function create_roqf(r, mage, level, force) + return create_item(mage, level, "roqf") +end + +-- Erschaffe ein Amulett des wahren Sehens +function create_aots(r, mage, level, force) + return create_item(mage, level, "aots") +end + +-- Erschaffe einen magischen Kräuterbeutel +function create_magicherbbag(r, mage, level, force) + return create_item(mage, level, "magicherbbag") +end + +-- Erschaffe einen Taktikkristal +function create_dreameye(r, mage, level, force) + return create_item(mage, level, "dreameye") +end + +-- Erschaffe einen Antimagiekristall +function create_antimagic(r, mage, level, force) + return create_item(mage, level, "antimagic") +end + +-- Erschaffe eine Sphäre der Unsichtbarkeit +function create_invisibility_sphere(r, mage, level, force) + return create_item(mage, level, "sphereofinv") +end + +-- Erschaffe einen Gürtel der Keuschheit +function create_chastitybelt(r, mage, level, force) + return create_item(mage, level, "ao_chastity") +end + +-- Erschaffe ein Runenschwert +function create_runesword(r, mage, level, force) + return create_item(mage, level, "runesword") +end + +-- Erschaffe ein Aurafokus +function create_focus(r, mage, level, force) + return create_item(mage, level, "aurafocus") +end + +-- Erschaffe einen Ring der Macht +function create_rop(r, mage, level, force) + return create_item(mage, level, "rop") +end + +-- Erschaffe einen Ring der Regeneration +function create_ror(r, mage, level, force) + return create_item(mage, level, "ror") +end + +-- Erschaffe einen Zauberbeutel +function create_bagofholding(r, mage, level, force) + return create_item(mage, level, "magicbag") +end + +-- TODO: +function earn_silver(r, mage, level, force) + local money = r:get_resource("money") + local wanted = 50 * force + local amount = wanted + if wanted > money then + amount = money + end + r:set_resource("money", money - amount) + mage:add_item("money", amount) + + local msg = message.create("income") + msg:set_unit("unit", mage) + msg:set_region("region", r) + msg:set_int("mode", 6) + msg:set_int("wanted", wanted) + msg:set_int("amount", amount) + msg:send_faction(mage.faction) + return level +end diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua new file mode 100644 index 000000000..9e0ff43db --- /dev/null +++ b/scripts/tests/common.lua @@ -0,0 +1,643 @@ +require "lunit" + +function setup() + free_game() +end + +function one_unit(r, f) + local u = unit.create(f, r, 1) + u:add_item("money", u.number * 100) + u:clear_orders() + return u +end + +function two_units(r, f1, f2) + return one_unit(r, f1), one_unit(r, f2) +end + +function two_factions() + local f1 = faction.create("noreply@eressea.de", "human", "de") + f1.id = 1 + local f2 = faction.create("noreply@eressea.de", "orc", "de") + f2.id = 2 + return f1, f2 +end + +module( "common", package.seeall, lunit.testcase ) + +function DISABLE_test_eventbus_fire() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r) + + function compare_f(u, event, f) + assert_equal(u.faction, f) + end + eventbus.register(u, "weird", compare_f) + eventbus.fire(u, "weird", f) +end + +function test_fleeing_units_can_be_transported() + local r = region.create(0, 0, "plain") + local r1 = region.create(1, 0, "plain") + local f1, f2 = two_factions() + local u1, u2 = two_units(r, f1, f2) + local u3 = one_unit(r, f2) + u1.number = 100 + u1:add_order("ATTACKIEREN " .. itoa36(u2.id)) + u2.number = 100 + u2:add_order("FAHREN " .. itoa36(u3.id)) + u3.number = 100 + u3:add_order("KAEMPFE FLIEHE") + u3:add_order("TRANSPORT " .. itoa36(u2.id)) + u3:add_order("NACH O ") + u3:set_skill("riding", 2) + u3:add_item("horse", u2.number) + u3:add_order("KAEMPFE FLIEHE") + process_orders() + assert_equal(u3.region.id, r1.id, "transporter did not move") + assert_equal(u2.region.id, r1.id, "transported unit did not move") +end + +function test_plane() + local pl = plane.create(0, -3, -3, 7, 7) + local nx, ny = plane.normalize(pl, 4, 4) + assert_equal(nx, -3, "normalization failed") + assert_equal(ny, -3, "normalization failed") + local f = faction.create("noreply@eressea.de", "human", "de") + f.id = atoi36("tpla") + local r, x, y + for x = -3, 3 do for y = -3, 3 do + r = region.create(x, y, "plain") + if (x==y) then + local u = unit.create(f, r, 1) + end + end end +end + +function test_pure() + free_game() + local r = region.create(0, 0, "plain") + assert_not_equal(nil, r) + assert_equal(r, get_region(0, 0)) +end + +function test_read_write() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r) + u.number = 2 + local fno = f.id + local uno = u.id + local result = 0 + assert_equal(r.terrain, "plain") + result = write_game("test_read_write.dat", "binary") + assert_equal(result, 0) + assert_not_equal(get_region(0, 0), nil) + assert_not_equal(get_faction(fno), nil) + assert_not_equal(get_unit(uno), nil) + r = nil + f = nil + u = nil + free_game() + assert_equal(get_region(0, 0), nil) + assert_equal(nil, get_faction(fno)) + assert_equal(nil, get_unit(uno)) + result = read_game("test_read_write.dat", "binary") + assert_equal(0, result) + assert_not_equal(nil, get_region(0, 0)) + assert_not_equal(nil, get_faction(fno)) + assert_not_equal(nil, get_unit(uno)) + free_game() +end + +function test_gmtool() + free_game() + local r1 = region.create(1, 0, "plain") + local r2 = region.create(1, 1, "plain") + local r3 = region.create(1, 2, "plain") + gmtool.open() + gmtool.select(r1, true) + gmtool.select_at(0, 1, true) + gmtool.select(r2, true) + gmtool.select_at(0, 2, true) + gmtool.select(r3, false) + gmtool.select(r3, true) + gmtool.select_at(0, 3, false) + gmtool.select(r3, false) + + local selections = 0 + for r in gmtool.get_selection() do + selections=selections+1 + end + assert_equal(2, selections) + assert_equal(nil, gmtool.get_cursor()) + + gmtool.close() +end + +function test_faction() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + assert(f) + f.info = "Spazz" + assert(f.info=="Spazz") + f:add_item("donotwant", 42) + f:add_item("stone", 42) + f:add_item("sword", 42) + local items = 0 + for u in f.items do + items = items + 1 + end + assert(items==2) + unit.create(f, r) + unit.create(f, r) + local units = 0 + for u in f.units do + units = units + 1 + end + assert(units==2) +end + +function test_unit() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r) + u.number = 20 + u.name = "Enno" + assert(u.name=="Enno") + u.info = "Spazz" + assert(u.info=="Spazz") + u:add_item("sword", 4) + assert(u:get_item("sword")==4) + assert(u:get_pooled("sword")==4) + u:use_pooled("sword", 2) + assert(u:get_item("sword")==2) +end + +function test_region() + free_game() + local r = region.create(0, 0, "plain") + r:set_resource("horse", 42) + r:set_resource("money", 45) + r:set_resource("peasant", 200) + assert(r:get_resource("horse") == 42) + assert(r:get_resource("money") == 45) + assert(r:get_resource("peasant") == 200) + r.name = nil + r.info = nil + assert(r.name=="") + assert(r.info=="") + r.name = "Alabasterheim" + r.info = "Hier wohnen die siebzehn Zwerge" + assert(tostring(r) == "Alabasterheim (0,0)") +end + +function test_building() + free_game() + local u + local f = faction.create("noreply@eressea.de", "human", "de") + local r = region.create(0, 0, "plain") + local b = building.create(r, "castle") + u = unit.create(f, r) + u.number = 1 + u.building = b + u = unit.create(f, r) + u.number = 2 + -- u.building = b + u = unit.create(f, r) + u.number = 3 + u.building = b + local units = 0 + for u in b.units do + units = units + 1 + end + assert(units==2) + local r2 = region.create(0, 1, "plain") + assert(b.region==r) + b.region = r2 + assert(b.region==r2) + assert(r2.buildings()==b) +end + +function test_message() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r) + local msg = message.create("item_create_spell") + msg:set_unit("mage", u) + msg:set_int("number", 1) + msg:set_resource("item", "sword") + msg:send_region(r) + msg:send_faction(f) + + return msg +end + +function test_hashtable() + free_game() + local f = faction.create("noreply@eressea.de", "human", "de") + f.objects:set("enno", "smart guy") + f.objects:set("age", 10) + assert(f.objects:get("jesus") == nil) + assert(f.objects:get("enno") == "smart guy") + assert(f.objects:get("age") == 10) + f.objects:set("age", nil) + assert(f.objects:get("age") == nil) +end + +function test_events() + local fail = 1 + local function msg_handler(u, evt) + str = evt:get(0) + u2 = evt:get(1) + assert(u2~=nil) + assert(str=="Du Elf stinken") + message_unit(u, u2, "thanks unit, i got your message: " .. str) + message_faction(u, u2.faction, "thanks faction, i got your message: " .. str) + message_region(u, "thanks region, i got your message: " .. str) + fail = 0 + end + + plain = region.create(0, 0, "plain") + skill = 8 + + f = faction.create("noreply@eressea.de", "orc", "de") + f.age = 20 + + u = unit.create(f, plain) + u.number = 1 + u:add_item("money", u.number*100) + u:clear_orders() + u:add_order("NUMMER PARTEI test") + u:add_handler("message", msg_handler) + msg = "BOTSCHAFT EINHEIT " .. itoa36(u.id) .. " Du~Elf~stinken" + f = faction.create("noreply@eressea.de", "elf", "de") + f.age = 20 + + u = unit.create(f, plain) + u.number = 1 + u:add_item("money", u.number*100) + u:clear_orders() + u:add_order("NUMMER PARTEI eviL") + u:add_order(msg) + process_orders() + assert(fail==0) +end + +function test_recruit2() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r) + u.number = 1 + u:add_item("money", 2000) + u:clear_orders() + u:add_order("MACHE TEMP 1") + u:add_order("REKRUTIERE 1 Elf") + u:add_order("REKRUTIERE 1 mensch") + u:add_order("REKRUTIERE 1") + process_orders() +end + +function test_guard() + free_game() + region.create(1, 0, "plain") + local r = region.create(0, 0, "plain") + local f1 = faction.create("noreply@eressea.de", "human", "de") + f1.age = 20 + local u1 = unit.create(f1, r, 1) + u1:add_item("sword", 10) + u1:add_item("money", 10) + u1:set_skill("melee", 10) + u1:clear_orders() + u1:add_order("NACH O") + + local f2 = faction.create("noreply@eressea.de", "human", "de") + f2.age = 20 + local u2 = unit.create(f2, r, 1) + local u3 = unit.create(f2, r, 1) + local b = building.create(r, "castle") + b.size = 10 + u2.building = b + u3.building = b + u2:clear_orders() + u2:add_order("ATTACKIEREN " .. itoa36(u1.id)) -- you will die... + u2:add_item("money", 100) + u3:add_item("money", 100) + process_orders() + assert_equal(r.id, u1.region.id, "unit may not move after combat") +end + +function test_recruit() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r) + u.number = 1 + local n = 3 + r:set_resource("peasant", 200) + u:clear_orders() + u:add_item("money", 110*n+20) + u:add_order("REKRUTIERE " .. n) + process_orders() + assert(u.number == n+1) + local p = r:get_resource("peasant") + assert(p<200 and p>=200-n) + -- assert(u:get_item("money")==10) +end + +function test_produce() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u:clear_orders() + u:set_skill("weaponsmithing", 3) + u:add_item("iron", 2) + u:add_item("money", u.number * 10) + u:add_order("MACHE Schwert") + process_orders() + assert(u:get_item("iron")==1) + assert(u:get_item("sword")==1) +end + +function test_work() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + f.id = 42 + local u = unit.create(f, r, 1) + u:add_item("money", u.number * 10) -- humans cost 10 + u:set_skill("herbalism", 5) + u:clear_orders() + u:add_order("ARBEITEN") + process_orders() + assert(u:get_item("money")>=10) +end + +function test_upkeep() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + f.id = 42 + local u = unit.create(f, r, 5) + u:add_item("money", u.number * 11) + u:clear_orders() + u:add_order("LERNE Waffenbau") + process_orders() + assert(u:get_item("money")==u.number) +end + +function test_id() + free_game() + local r = region.create(0, 0, "plain") + + local f = faction.create("noreply@eressea.de", "human", "de") + f.id = atoi36("42") + assert(get_faction(42)~=f) + assert(get_faction("42")==f) + assert(get_faction(atoi36("42"))==f) + + local u = unit.create(f, r, 1) + u.id = atoi36("42") + assert(get_unit(42)~=u) + assert(get_unit("42")==u) + assert(get_unit(atoi36("42"))==u) + + local b = building.create(r, "castle") + -- b.id = atoi36("42") + local fortytwo = itoa36(b.id) + assert(get_building(fortytwo)==b) + assert(get_building(atoi36(fortytwo))==b) + + local s = ship.create(r, "canoe") + if (s==nil) then + s = ship.create(r, "boat") + end + -- s.id = atoi36("42") + local fortytwo = itoa36(s.id) + assert(get_ship(fortytwo)==s) + assert(get_ship(atoi36(fortytwo))==s) +end + +function test_herbalism() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + f.id = 42 + local u = unit.create(f, r, 1) + u:add_item("money", u.number * 100) + u:set_skill("herbalism", 5) + u:clear_orders() + u:add_order("MACHE Samen") + process_orders() +end + +function test_mallorn() + free_game() + local r = region.create(0, 0, "plain") + r:set_flag(1, false) -- not mallorn + r:set_resource("tree", 100) + assert(r:get_resource("tree")==100) + local m = region.create(0, 0, "plain") + m:set_flag(1, true) -- not mallorn + m:set_resource("tree", 100) + assert(m:get_resource("tree")==100) + + local f = faction.create("noreply@eressea.de", "human", "de") + + local u1 = unit.create(f, r, 1) + u1:add_item("money", u1.number * 100) + u1:set_skill("forestry", 2) + u1:clear_orders() + u1:add_order("MACHE HOLZ") + + local u2 = unit.create(f, m, 1) + u2:add_item("money", u2.number * 100) + u2:set_skill("forestry", 2) + u2:clear_orders() + u2:add_order("MACHE HOLZ") + + local u3 = unit.create(f, m, 1) + u3:add_item("money", u3.number * 100) + u3:set_skill("forestry", 2) + u3:clear_orders() + u3:add_order("MACHE Mallorn") + process_orders() + assert(u1:get_item("log")==2) + assert(u2:get_item("log")==2) + assert(u3:get_item("mallorn")==1) +end + +function test_coordinate_translation() + local pl = plane.create(1, 500, 500, 1001, 1001) -- astralraum + local pe = plane.create(1, -8761, 3620, 23, 23) -- eternath + local r = region.create(1000, 1000, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + assert_not_equal(nil, r) + assert_equal(r.x, 1000) + assert_equal(r.y, 1000) + local nx, ny = plane.normalize(pl, r.x, r.y) + assert_equal(nx, 1000) + assert_equal(ny, 1000) + local r1 = region.create(500, 500, "plain") + f:set_origin(r1) + nx, ny = f:normalize(r1) + assert_equal(0, nx) + assert_equal(0, ny) + local r0 = region.create(0, 0, "plain") + nx, ny = f:normalize(r0) + assert_equal(0, nx) + assert_equal(0, ny) + nx, ny = f:normalize(r) + assert_equal(500, nx) + assert_equal(500, ny) + local rn = region.create(1010, 1010, "plain") + nx, ny = f:normalize(rn) + assert_equal(-491, nx) + assert_equal(-491, ny) + + local re = region.create(-8760, 3541, "plain") -- eternath + nx, ny = f:normalize(rn) + assert_equal(-491, nx) + assert_equal(-491, ny) +end + +function test_control() + free_game() + local u1, u2 = two_units(region.create(0, 0, "plain"), two_factions()) + local r = u1.region + local b = building.create(r, "castle") + u1.building = b + u2.building = b + assert_equal(u1, b.owner) + u1:clear_orders() + u1:add_order("GIB " .. itoa36(u2.id) .. " KOMMANDO") + u1:add_order("VERLASSE") + process_orders() + assert_equal(u2, b.owner) +end + +function test_storage() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + f.id = 42 + local u = unit.create(f, r, 1) + u:add_item("money", u.number * 100) + store = storage.create("test.unit.dat", "wb") + assert_not_equal(store, nil) + store:write_unit(u) + store:close() + free_game() + -- recreate world: + r = region.create(0, 0, "plain") + f = faction.create("noreply@eressea.de", "human", "de") + f.id = 42 + store = storage.create("test.unit.dat", "rb") + assert(store) + u = store:read_unit() + store:close() + assert(u) + assert(u:get_item("money") == u.number * 100) +end + +function test_building_other() + local r = region.create(0,0, "plain") + local f1 = faction.create("noreply@eressea.de", "human", "de") + local f2 = faction.create("noreply@eressea.de", "human", "de") + local b = building.create(r, "castle") + b.size = 10 + local u1 = unit.create(f1, r, 3) + u1.building = b + u1:add_item("money", 100) + + local u2 = unit.create(f2, r, 3) + u2:set_skill("building", 10) + u2:add_item("money", 100) + u2:add_item("stone", 100) + u2:clear_orders() + u2:add_order("MACHEN BURG " .. itoa36(b.id)) + process_orders() + assert_not_equal(10, b.size) +end + +function test_config() + assert_not_equal(nil, config.basepath) + assert_not_equal(nil, config.locales) +end + +function test_guard_resources() + -- this is not quite http://bugs.eressea.de/view.php?id=1756 + local r = region.create(0,0, "mountain") + local f1 = faction.create("noreply@eressea.de", "human", "de") + f1.age=20 + local f2 = faction.create("noreply@eressea.de", "human", "de") + f2.age=20 + local u1 = unit.create(f1, r, 1) + u1:add_item("money", 100) + u1:set_skill("melee", 3) + u1:add_item("sword", 1) + u1:clear_orders() + u1:add_order("BEWACHEN") + + local u2 = unit.create(f2, r, 1) + u2:add_item("money", 100) + u2:set_skill("mining", 3) + u2:clear_orders() + u2:add_order("MACHEN EISEN") + + process_orders() + local iron = u2:get_item("iron") + process_orders() + assert_equal(iron, u2:get_item("iron")) +end + +local function is_flag_set(flags, flag) + return math.mod(flags, flag*2) - math.mod(flags, flag) == flag; +end + +function test_hero_hero_transfer() + local r = region.create(0,0, "mountain") + local f = faction.create("noreply@eressea.de", "human", "de") + f.age=20 + local UFL_HERO = 128 + + local u1 = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + u1:add_item("money", 10000) + u1.flags = u1.flags + UFL_HERO + u2.flags = u2.flags + UFL_HERO + u1:clear_orders() + u1:add_order("GIB " .. itoa36(u2.id) .. " 1 PERSONEN") + u1:add_order("REKRUTIEREN 1") + process_orders() + assert_equal(1, u1.number) + assert_equal(2, u2.number) + assert_false(is_flag_set(u1.flags, 128), 128, "recruiting into an empty hero unit should not create a hero") + assert_true(is_flag_set(u2.flags, 128), 128, "unit is not a hero?") +end + +function test_hero_normal_transfer() + local r = region.create(0,0, "mountain") + local f = faction.create("noreply@eressea.de", "human", "de") + f.age=20 + local UFL_HERO = 128 + + local u1 = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + u1:add_item("money", 10000) + u1.flags = u1.flags + UFL_HERO + u1:clear_orders() + u1:add_order("GIB " .. itoa36(u2.id) .. " 1 PERSONEN") + process_orders() + assert_equal(1, u1.number) + assert_equal(1, u2.number) + assert_true(is_flag_set(u1.flags, 128), "unit is not a hero?") + assert_false(is_flag_set(u2.flags, 128), "unit turned into a hero") +end diff --git a/scripts/tests/spells.lua b/scripts/tests/spells.lua new file mode 100644 index 000000000..e71935aa8 --- /dev/null +++ b/scripts/tests/spells.lua @@ -0,0 +1,64 @@ +require "lunit" + +module( "spells", package.seeall, lunit.testcase ) + +function setup() + free_game() +end + +function test_roi() + local r = region.create(0,0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u.race = "elf" + u:set_skill("magic", 10) + u:add_item("money", 3010) + u.magic = "tybied" + u.aura = 200 + u.ship = s1 + u:add_spell("create_roi") + u:clear_orders() + u:add_order("ZAUBERE 'Erschaffe einen Ring der Unsichtbarkeit' ") + process_orders() + write_reports() + assert_equal(1, u:get_item("roi")) +end + +function test_blessedharvest_lasts_n_turn() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "halfling", "de") + local u = unit.create(f, r) + r:set_resource("peasant", 100) + r:set_resource("money", 0) + u:add_item("money", 1000) + u.magic = "gwyrrd" + u.race = "dwarf" + u:set_skill("magic", 20) + u.aura = 200 + u:add_spell("raindance") + u:add_spell("blessedharvest") + u:clear_orders() + local level = 5 + u:add_order("ZAUBERE STUFE " .. level .. " Regentanz") + assert_equal(0, r:get_resource("money"), 0) + + local m = 0 + local p = 100 + for i=1,level+2 do + process_orders() + local income = p * 12 + p = r:get_resource("peasant") + income = income - p * 10 + m = m + income + -- print(i, m, p, r:get_resource("money")) + if (i>level+1) then + assert_not_equal(m, r:get_resource("money")) + else + assert_equal(m, r:get_resource("money")) + end + u:clear_orders() + u:add_order("ARBEITEN") +-- u:add_spell("raindance") + end +end diff --git a/src/attributes/aggressive.h b/src/attributes/aggressive.h new file mode 100644 index 000000000..dd6060637 --- /dev/null +++ b/src/attributes/aggressive.h @@ -0,0 +1,33 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_AGGRESSIVE +#define H_ATTRIBUTE_AGGRESSIVE +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_aggressive; +extern struct attrib * make_aggressive(double probability); +extern void init_aggressive(void); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/alliance.c b/src/attributes/alliance.c new file mode 100644 index 000000000..526ec18db --- /dev/null +++ b/src/attributes/alliance.c @@ -0,0 +1,34 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "alliance.h" + +#include +#include + +attrib_type at_alliance = { + "alliance", + NULL, + NULL, + NULL, + a_writeint, + a_readint, + ATF_UNIQUE +}; diff --git a/src/attributes/alliance.h b/src/attributes/alliance.h new file mode 100644 index 000000000..42336c47b --- /dev/null +++ b/src/attributes/alliance.h @@ -0,0 +1,31 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_ALLIANCE +#define H_ATTRIBUTE_ALLIANCE +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_alliance; + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/attributes.c b/src/attributes/attributes.c new file mode 100644 index 000000000..8e9d4a0cd --- /dev/null +++ b/src/attributes/attributes.c @@ -0,0 +1,81 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "attributes.h" + +/* attributes includes */ +#include "follow.h" +#include "gm.h" +#include "hate.h" +#include "iceberg.h" +#include "key.h" +#include "moved.h" +#include "movement.h" +#include "object.h" +#include "orcification.h" +#include "otherfaction.h" +#include "overrideroads.h" +#include "racename.h" +#include "raceprefix.h" +#include "reduceproduction.h" +#include "targetregion.h" +#ifdef WDW_PYRAMID +# include "alliance.h" +#endif + +/* kernel includes */ +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include + +attrib_type at_unitdissolve = { + "unitdissolve", NULL, NULL, NULL, a_writechars, a_readchars +}; + +void +register_attributes(void) +{ + at_register(&at_object); + at_register(&at_unitdissolve); + at_register(&at_overrideroads); + at_register(&at_raceprefix); + at_register(&at_iceberg); + at_register(&at_key); + at_register(&at_gm); + at_register(&at_follow); + at_register(&at_targetregion); + at_register(&at_orcification); + at_register(&at_hate); + at_register(&at_reduceproduction); + at_register(&at_otherfaction); + at_register(&at_racename); + at_register(&at_movement); + at_register(&at_moved); + +#ifdef WDW_PYRAMID + at_register(&at_alliance); +#endif /* WDW_PYRAMID */ +} diff --git a/src/attributes/attributes.h b/src/attributes/attributes.h new file mode 100644 index 000000000..594ecf3f3 --- /dev/null +++ b/src/attributes/attributes.h @@ -0,0 +1,31 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_ATTRIBUTES +#define H_ATTRIBUTE_ATTRIBUTES +#ifdef __cplusplus +extern "C" { +#endif + +extern void register_attributes(void); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/fleechance.c b/src/attributes/fleechance.c new file mode 100644 index 000000000..24062bd55 --- /dev/null +++ b/src/attributes/fleechance.c @@ -0,0 +1,45 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "fleechance.h" + +#include + +attrib_type at_fleechance = { + "fleechance", + NULL, + NULL, + NULL, + NULL, + NULL, +}; + +attrib * +make_fleechance(float fleechance) +{ + attrib * a = a_new(&at_fleechance); + a->data.flt = fleechance; + return a; +} + +void +init_fleechance(void) +{ + at_register(&at_fleechance); +} diff --git a/src/attributes/fleechance.h b/src/attributes/fleechance.h new file mode 100644 index 000000000..482b1ad64 --- /dev/null +++ b/src/attributes/fleechance.h @@ -0,0 +1,33 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_FLEECHANCE +#define H_ATTRIBUTE_FLEECHANCE +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_fleechance; + +extern struct attrib * make_fleechance(float fleechance); +extern void init_fleechance(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/attributes/follow.c b/src/attributes/follow.c new file mode 100644 index 000000000..d080a0d49 --- /dev/null +++ b/src/attributes/follow.c @@ -0,0 +1,46 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "follow.h" + +#include +#include + +#include +#include +#include + +static int +read_follow(attrib * a, void * owner, struct storage * store) +{ + read_unit_reference(store); /* skip it */ + return AT_READ_FAIL; +} + +attrib_type at_follow = { + "follow", NULL, NULL, NULL, NULL, read_follow +}; + +attrib * +make_follow(struct unit * u) +{ + attrib * a = a_new(&at_follow); + a->data.v = u; + return a; +} diff --git a/src/attributes/follow.h b/src/attributes/follow.h new file mode 100644 index 000000000..0328949cc --- /dev/null +++ b/src/attributes/follow.h @@ -0,0 +1,35 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_FOLLOW +#define H_ATTRIBUTE_FOLLOW +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_follow; + +struct unit; + +extern struct attrib * make_follow(struct unit * u); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/giveitem.c b/src/attributes/giveitem.c new file mode 100644 index 000000000..db0b136eb --- /dev/null +++ b/src/attributes/giveitem.c @@ -0,0 +1,135 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "giveitem.h" +#include + +/* kernel includes */ +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include + +typedef struct give_data { + struct building * building; + struct item * items; +} give_data; + +static void +a_writegive(const attrib * a, const void * owner, struct storage * store) +{ + give_data * gdata = (give_data*)a->data.v; + item * itm; + write_building_reference(gdata->building, store); + for (itm=gdata->items;itm;itm=itm->next) { + store->w_tok(store, resourcename(itm->type->rtype, 0)); + store->w_int(store, itm->number); + } + store->w_tok(store, "end"); +} + +static int +a_readgive(attrib * a, void * owner, struct storage * store) +{ + give_data * gdata = (give_data*)a->data.v; + variant var; + char zText[32]; + + var.i = store->r_id(store); + if (var.i>0) { + gdata->building = findbuilding(var.i); + if (gdata->building==NULL) { + ur_add(var, &gdata->building, resolve_building); + } + } else { + gdata->building=NULL; + } + for (;;) { + int i; + store->r_tok_buf(store, zText, sizeof(zText)); + if (!strcmp("end", zText)) break; + i = store->r_int(store); + if (i==0) i_add(&gdata->items, i_new(it_find(zText), i)); + } + return AT_READ_OK; +} + +static void +a_initgive(struct attrib * a) +{ + a->data.v = calloc(sizeof(give_data), 1); +} + +static void +a_finalizegive(struct attrib * a) +{ + free(a->data.v); +} + +static int +a_giveitem(attrib * a) +{ + give_data * gdata = (give_data*)a->data.v; + region * r; + unit * u; + if (gdata->building==NULL || gdata->items==NULL) return 0; + r = gdata->building->region; + u = building_owner(gdata->building); + if (u==NULL) return 1; + while (gdata->items) { + item * itm = gdata->items; + i_change(&u->items, itm->type, itm->number); + i_free(i_remove(&gdata->items, itm)); + } + return 0; +} + +attrib_type at_giveitem = { + "giveitem", + a_initgive, a_finalizegive, + a_giveitem, + a_writegive, a_readgive +}; + +attrib * +make_giveitem(struct building * b, struct item * ip) +{ + attrib * a = a_new(&at_giveitem); + give_data * gd = (give_data*)a->data.v; + gd->building = b; + gd->items = ip; + return a; +} + +void +init_giveitem(void) +{ + at_register(&at_giveitem); +} diff --git a/src/attributes/giveitem.h b/src/attributes/giveitem.h new file mode 100644 index 000000000..e45d3df56 --- /dev/null +++ b/src/attributes/giveitem.h @@ -0,0 +1,36 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_GIVEITEM +#define H_ATTRIBUTE_GIVEITEM +#ifdef __cplusplus +extern "C" { +#endif + +struct building; +struct item; + +extern struct attrib_type at_giveitem; + +extern struct attrib * make_giveitem(struct building * b, struct item * items); +extern void init_giveitem(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/attributes/gm.c b/src/attributes/gm.c new file mode 100644 index 000000000..bf062722a --- /dev/null +++ b/src/attributes/gm.c @@ -0,0 +1,61 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "gm.h" + +/* kernel includes */ +#include + +/* util includes */ +#include +#include + +static void +write_gm(const attrib * a, const void * owner, struct storage * store) +{ + write_plane_reference((plane*)a->data.v, store); +} + +static int +read_gm(attrib * a, void * owner, struct storage * store) +{ + plane * pl; + int result = read_plane_reference(&pl, store); + a->data.v = pl; + return result; +} + + +attrib_type at_gm = { + "gm", + NULL, + NULL, + NULL, + write_gm, + read_gm, +}; + +attrib * +make_gm(const struct plane * pl) +{ + attrib * a = a_new(&at_gm); + a->data.v = (void*)pl; + return a; +} diff --git a/src/attributes/gm.h b/src/attributes/gm.h new file mode 100644 index 000000000..341b4d76a --- /dev/null +++ b/src/attributes/gm.h @@ -0,0 +1,36 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_GM +#define H_ATTRIBUTE_GM +#ifdef __cplusplus +extern "C" { +#endif + +/* this is an attribute used by the kernel (isallied) */ + +struct plane; +extern struct attrib_type at_gm; + +extern struct attrib * make_gm(const struct plane *pl); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/hate.c b/src/attributes/hate.c new file mode 100644 index 000000000..545eec8e1 --- /dev/null +++ b/src/attributes/hate.c @@ -0,0 +1,70 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "hate.h" + +#include +#include + +#include +#include +#include + +static int +verify_hate(attrib * a) +{ + if (a->data.v==NULL) { + return 0; + } + return 1; +} + +static void +write_hate(const attrib * a, const void * owner, struct storage * store) +{ + write_unit_reference((unit*)a->data.v, store); +} + +static int +read_hate(attrib * a, void * owner, struct storage * store) +{ + int result = read_reference(&a->data.v, store, read_unit_reference, resolve_unit); + if (result==0 && !a->data.v) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +attrib_type at_hate = { + "hates", + NULL, + NULL, + verify_hate, + write_hate, + read_hate, +}; + +attrib * +make_hate(struct unit * u) +{ + attrib * a = a_new(&at_hate); + a->data.v = u; + return a; +} diff --git a/src/attributes/hate.h b/src/attributes/hate.h new file mode 100644 index 000000000..e58c6205b --- /dev/null +++ b/src/attributes/hate.h @@ -0,0 +1,35 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_HATE +#define H_ATTRIBUTE_HATE +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_hate; + +struct unit; + +extern struct attrib * make_hate(struct unit * u); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/iceberg.c b/src/attributes/iceberg.c new file mode 100644 index 000000000..cb0efc7f3 --- /dev/null +++ b/src/attributes/iceberg.c @@ -0,0 +1,42 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "iceberg.h" + +#include +#include + +attrib_type at_iceberg = { + "iceberg_drift", + NULL, + NULL, + NULL, + a_writeint, + a_readint, + ATF_UNIQUE +}; + +attrib * +make_iceberg(direction_t dir) +{ + attrib * a = a_new(&at_iceberg); + a->data.i = (int)dir; + return a; +} diff --git a/src/attributes/iceberg.h b/src/attributes/iceberg.h new file mode 100644 index 000000000..2f99d60dd --- /dev/null +++ b/src/attributes/iceberg.h @@ -0,0 +1,33 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_ICEBERG +#define H_ATTRIBUTE_ICEBERG +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_iceberg; + +extern struct attrib * make_iceberg(direction_t dir); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/key.c b/src/attributes/key.c new file mode 100644 index 000000000..ea612b01a --- /dev/null +++ b/src/attributes/key.c @@ -0,0 +1,59 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "key.h" + +#include +#include + +attrib_type at_key = { + "key", + NULL, + NULL, + NULL, + a_writeint, + a_readint, +}; + +attrib * +add_key(attrib ** alist, int key) +{ + attrib * a = find_key(*alist, key); + if (a==NULL) a = a_add(alist, make_key(key)); + return a; +} + +attrib * +make_key(int key) +{ + attrib * a = a_new(&at_key); + a->data.i = key; + return a; +} + +attrib * +find_key(attrib * alist, int key) +{ + attrib * a = a_find(alist, &at_key); + while (a && a->type==&at_key && a->data.i != key) { + a = a->next; + } + return (a && a->type==&at_key)?a:NULL; +} diff --git a/src/attributes/key.h b/src/attributes/key.h new file mode 100644 index 000000000..112bbe581 --- /dev/null +++ b/src/attributes/key.h @@ -0,0 +1,35 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_KEY +#define H_ATTRIBUTE_KEY +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_key; + +extern struct attrib * make_key(int key); +extern struct attrib * find_key(struct attrib * alist, int key); +extern struct attrib * add_key(struct attrib ** alist, int key); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/matmod.c b/src/attributes/matmod.c new file mode 100644 index 000000000..8f8f6bec8 --- /dev/null +++ b/src/attributes/matmod.c @@ -0,0 +1,40 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "matmod.h" + +#include + +attrib_type at_matmod = { + "matmod", + NULL, + NULL, + NULL, + NULL, + NULL, + ATF_PRESERVE +}; + +attrib * +make_matmod(mm_fun function) +{ + attrib * a = a_new(&at_matmod); + a->data.f = (void(*)(void))function; + return a; +} diff --git a/src/attributes/matmod.h b/src/attributes/matmod.h new file mode 100644 index 000000000..e32b6a94c --- /dev/null +++ b/src/attributes/matmod.h @@ -0,0 +1,37 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_MATMOD +#define H_ATTRIBUTE_MATMOD + +#ifdef __cplusplus +extern "C" { +#endif + +struct resource_type; +struct unit; +typedef int (*mm_fun)(const struct unit * u, const struct resource_type * rtype, int value); + +extern struct attrib_type at_matmod; +extern struct attrib * make_matmod(mm_fun function); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/attributes/moved.c b/src/attributes/moved.c new file mode 100644 index 000000000..08c11ac1e --- /dev/null +++ b/src/attributes/moved.c @@ -0,0 +1,63 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "moved.h" + +#include +#include + +static int +age_moved(attrib * a) +{ + --a->data.i; + return a->data.i > 0; +} + +static void +write_moved(const attrib * a, const void * owner, struct storage * store) +{ + store->w_int(store, a->data.i); +} + +static int +read_moved(attrib * a, void * owner, struct storage * store) +{ + a->data.i = store->r_int(store); + if (a->data.i !=0 ) return AT_READ_OK; + else return AT_READ_FAIL; +} + +attrib_type at_moved = { + "moved", NULL, NULL, age_moved, write_moved, read_moved +}; + +boolean +get_moved(attrib ** alist) +{ + return a_find(*alist, &at_moved) ? true : false; +} + +void +set_moved(attrib ** alist) +{ + attrib * a = a_find(*alist, &at_moved); + if (a==NULL) a = a_add(alist, a_new(&at_moved)); + a->data.i = 2; +} diff --git a/src/attributes/moved.h b/src/attributes/moved.h new file mode 100644 index 000000000..af84797ea --- /dev/null +++ b/src/attributes/moved.h @@ -0,0 +1,37 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_MOVED +#define H_ATTRIBUTE_MOVED +#ifdef __cplusplus +extern "C" { +#endif + +struct attrib; +struct attrib_type; + +extern boolean get_moved(struct attrib ** alist); +extern void set_moved(struct attrib ** alist); + +extern struct attrib_type at_moved; + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/movement.c b/src/attributes/movement.c new file mode 100644 index 000000000..125fbf779 --- /dev/null +++ b/src/attributes/movement.c @@ -0,0 +1,59 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "movement.h" + +#include +#include + +static void +write_movement(const attrib * a, const void * owner, struct storage * store) +{ + store->w_int(store, a->data.i); +} + +static int +read_movement(attrib * a, void * owner, struct storage * store) +{ + a->data.i = store->r_int(store); + if (a->data.i !=0 ) return AT_READ_OK; + else return AT_READ_FAIL; +} + +attrib_type at_movement = { + "movement", NULL, NULL, NULL, write_movement, read_movement +}; + +boolean +get_movement(attrib * const * alist, int type) +{ + const attrib * a = a_findc(*alist, &at_movement); + if (a==NULL) return false; + if (a->data.i & type) return true; + return false; +} + +void +set_movement(attrib ** alist, int type) +{ + attrib * a = a_find(*alist, &at_movement); + if (a==NULL) a = a_add(alist, a_new(&at_movement)); + a->data.i |= type; +} diff --git a/src/attributes/movement.h b/src/attributes/movement.h new file mode 100644 index 000000000..53ae8f923 --- /dev/null +++ b/src/attributes/movement.h @@ -0,0 +1,33 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_MOVEMENT +#define H_ATTRIBUTE_MOVEMENT +#ifdef __cplusplus +extern "C" { +#endif + +extern boolean get_movement(struct attrib * const * alist, int type); +extern void set_movement(struct attrib ** alist, int type); + +extern struct attrib_type at_movement; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/attributes/object.c b/src/attributes/object.c new file mode 100644 index 000000000..033fd8b32 --- /dev/null +++ b/src/attributes/object.c @@ -0,0 +1,267 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "object.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include + +/* stdc includes */ +#include +#include + +typedef struct object_data { + object_type type; + char * name; + union { + int i; + char * str; + double real; + struct unit * u; + struct region * r; + struct building * b; + struct ship * sh; + struct faction * f; + } data; +} object_data; + +static void +object_write(const attrib * a, const void * owner, struct storage * store) +{ + const object_data * data = (object_data *)a->data.v; + int type = (int)data->type; + store->w_tok(store, data->name); + store->w_int(store, type); + switch (data->type) { + case TINTEGER: + store->w_int(store, data->data.i); + break; + case TREAL: + store->w_flt(store, (float)data->data.real); + break; + case TSTRING: + store->w_str(store, data->data.str); + break; + case TUNIT: + write_unit_reference(data->data.u, store ); + break; + case TFACTION: + write_faction_reference(data->data.f, store); + break; + case TBUILDING: + write_building_reference(data->data.b, store); + break; + case TSHIP: + /* write_ship_reference(data->data.sh, store); */ + assert(!"not implemented"); + break; + case TREGION: + write_region_reference(data->data.r, store); + break; + case TNONE: + break; + default: + assert(!"illegal type in object-attribute"); + } +} + +static int +object_read(attrib *a, void * owner, struct storage * store) +{ + object_data * data = (object_data *)a->data.v; + int result; + + data->name = store->r_str(store); + data->type = (object_type)store->r_int(store); + switch (data->type) { + case TINTEGER: + data->data.i = store->r_int(store); + break; + case TREAL: + data->data.real = store->r_flt(store); + break; + case TSTRING: + data->data.str = store->r_str(store); + break; + case TBUILDING: + result = read_reference(&data->data.b, store, read_building_reference, resolve_building); + if (result==0 && !data->data.b) { + return AT_READ_FAIL; + } + break; + case TUNIT: + result = read_reference(&data->data.u, store, read_unit_reference, resolve_unit); + if (result==0 && !data->data.u) { + return AT_READ_FAIL; + } + break; + case TFACTION: + result = read_reference(&data->data.f, store, read_faction_reference, resolve_faction); + if (result==0 && !data->data.f) { + return AT_READ_FAIL; + } + break; + case TREGION: + result = read_reference(&data->data.r, store, read_region_reference, RESOLVE_REGION(store->version)); + if (result==0 && !data->data.r) { + return AT_READ_FAIL; + } + break; + case TSHIP: + /* return read_ship_reference(&data->data.sh, store); */ + assert(!"not implemented"); + break; + case TNONE: + break; + default: + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +static void +object_init(attrib * a) +{ + object_data * data; + a->data.v = malloc(sizeof(object_data)); + data = (object_data *)a->data.v; + data->type = TNONE; +} + +static void +object_done(attrib * a) +{ + object_data * data = (object_data *)a->data.v; + if (data->type == TSTRING) free(data->data.str); + free(data->name); + free(a->data.v); +} + +attrib_type at_object = { + "object", object_init, object_done, NULL, + object_write, object_read +}; + +const char * +object_name(const attrib * a) +{ + object_data * data = (object_data *)a->data.v; + return data->name; +} + +struct attrib * +object_create(const char * name, object_type type, variant value) +{ + attrib * a = a_new(&at_object); + object_data * data = (object_data *)a->data.v; + data->name = strdup(name); + + object_set(a, type, value); + return a; +} + +void +object_set(attrib * a, object_type type, variant value) +{ + object_data * data = (object_data *)a->data.v; + + if (data->type==TSTRING) free(data->data.str); + data->type = type; + switch (type) { + case TSTRING: + data->data.str = value.v?strdup(value.v):NULL; + break; + case TINTEGER: + data->data.i = value.i; + break; + case TREAL: + data->data.real = value.f; + break; + case TREGION: + data->data.r = (region*)value.v; + break; + case TBUILDING: + data->data.b = (building*)value.v; + break; + case TFACTION: + data->data.f = (faction*)value.v; + break; + case TUNIT: + data->data.u = (unit*)value.v; + break; + case TSHIP: + data->data.sh = (ship*)value.v; + break; + case TNONE: + break; + default: + assert(!"invalid object-type"); + break; + } +} + +void +object_get(const struct attrib * a, object_type * type, variant * value) +{ + object_data * data = (object_data *)a->data.v; + *type = data->type; + switch (data->type) { + case TSTRING: + value->v = data->data.str; + break; + case TINTEGER: + value->i = data->data.i; + break; + case TREAL: + value->f = (float)data->data.real; + break; + case TREGION: + value->v = data->data.r; + break; + case TBUILDING: + value->v = data->data.b; + break; + case TFACTION: + value->v = data->data.f; + break; + case TUNIT: + value->v = data->data.u; + break; + case TSHIP: + value->v = data->data.sh; + break; + case TNONE: + break; + default: + assert(!"invalid object-type"); + break; + } +} diff --git a/src/attributes/object.h b/src/attributes/object.h new file mode 100644 index 000000000..c0ebcab7e --- /dev/null +++ b/src/attributes/object.h @@ -0,0 +1,38 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_ATTRIBUTE_OBJECT +#define H_ATTRIBUTE_OBJECT + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + TNONE = 0, TINTEGER = 1, TREAL = 2, TSTRING = 3, + TUNIT = 10, TFACTION = 11, TREGION = 12, TBUILDING = 13, TSHIP = 14, +} object_type; + +extern struct attrib_type at_object; + +extern struct attrib * object_create(const char * name, object_type type, variant value); +extern void object_get(const struct attrib * a, object_type * type, variant * value); +extern void object_set(struct attrib * a, object_type type, variant value); +extern const char * object_name(const struct attrib * a); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/orcification.c b/src/attributes/orcification.c new file mode 100644 index 000000000..745d13e24 --- /dev/null +++ b/src/attributes/orcification.c @@ -0,0 +1,40 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "orcification.h" + +#include +#include + +/* + * simple attributes that do not yet have their own file + */ + +attrib_type at_orcification = { + "orcification", NULL, NULL, NULL, a_writeint, a_readint, ATF_UNIQUE +}; + +attrib * +make_orcification(int orcification) +{ + attrib * a = a_new(&at_orcification); + a->data.i = orcification; + return a; +} diff --git a/src/attributes/orcification.h b/src/attributes/orcification.h new file mode 100644 index 000000000..285e9414e --- /dev/null +++ b/src/attributes/orcification.h @@ -0,0 +1,28 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifdef __cplusplus +extern "C" { +#endif +extern struct attrib_type at_orcification; + +extern struct attrib * make_orcification(int orcification); + +#ifdef __cplusplus +} +#endif diff --git a/src/attributes/otherfaction.c b/src/attributes/otherfaction.c new file mode 100644 index 000000000..14c4a3d03 --- /dev/null +++ b/src/attributes/otherfaction.c @@ -0,0 +1,80 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "otherfaction.h" + +#include +#include +#include +#include +#include + +/* + * simple attributes that do not yet have their own file + */ + + +void +write_of(const struct attrib * a, const void * owner, struct storage * store) +{ + const faction * f = (faction*)a->data.v; + store->w_int(store, f->no); +} + +int +read_of(struct attrib * a, void * owner, struct storage * store) /* return 1 on success, 0 if attrib needs removal */ +{ + int of = store->r_int(store); + a->data.v = findfaction(of); + if (a->data.v) return AT_READ_OK; + return AT_READ_FAIL; +} + +attrib_type at_otherfaction = { + "otherfaction", NULL, NULL, NULL, write_of, read_of, ATF_UNIQUE +}; + +struct faction * + get_otherfaction(const struct attrib * a) +{ + return (faction*)(a->data.v); +} + +struct attrib * + make_otherfaction(struct faction * f) +{ + attrib * a = a_new(&at_otherfaction); + a->data.v = (void*)f; + return a; +} + +faction * +visible_faction(const faction *f, const unit * u) +{ + if (f==NULL || !alliedunit(u, f, HELP_FSTEALTH)) { + attrib *a = a_find(u->attribs, &at_otherfaction); + if (a) { + faction *fv = get_otherfaction(a); + assert (fv != NULL); /* fv should never be NULL! */ + return fv; + } + } + return u->faction; +} diff --git a/src/attributes/otherfaction.h b/src/attributes/otherfaction.h new file mode 100644 index 000000000..4fe99f295 --- /dev/null +++ b/src/attributes/otherfaction.h @@ -0,0 +1,33 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifdef __cplusplus +extern "C" { +#endif + +struct faction; +struct attrib; +extern struct attrib_type at_otherfaction; + +extern struct faction * get_otherfaction(const struct attrib * a); +extern struct attrib * make_otherfaction(struct faction * f); +extern struct faction * visible_faction(const struct faction *f, const struct unit * u); + +#ifdef __cplusplus +extern "C" { +#endif diff --git a/src/attributes/overrideroads.c b/src/attributes/overrideroads.c new file mode 100644 index 000000000..96803a2a9 --- /dev/null +++ b/src/attributes/overrideroads.c @@ -0,0 +1,29 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "overrideroads.h" + +#include +#include + +attrib_type at_overrideroads = { + "roads_override", NULL, NULL, NULL, &a_writestring, &a_readstring +}; + diff --git a/src/attributes/overrideroads.h b/src/attributes/overrideroads.h new file mode 100644 index 000000000..a9322c598 --- /dev/null +++ b/src/attributes/overrideroads.h @@ -0,0 +1,31 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_OVERRRIDEROADS +#define H_ATTRIBUTE_OVERRRIDEROADS +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_overrideroads; + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/racename.c b/src/attributes/racename.c new file mode 100644 index 000000000..39ba6b4fa --- /dev/null +++ b/src/attributes/racename.c @@ -0,0 +1,57 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "racename.h" + +#include +#include + +/* libc includes */ +#include +#include + +attrib_type at_racename = { + "racename", NULL, a_finalizestring, NULL, a_writestring, a_readstring +}; + +const char * +get_racename(attrib * alist) +{ + attrib * a = a_find(alist, &at_racename); + if (a) return (const char *)a->data.v; + return NULL; +} + +void +set_racename(attrib ** palist, const char * name) +{ + attrib * a = a_find(*palist, &at_racename); + if (!a && name) { + a = a_add(palist, a_new(&at_racename)); + a->data.v = strdup(name); + } else if (a && !name) { + a_remove(palist, a); + } else if (a) { + if (strcmp(a->data.v, name)!=0) { + free(a->data.v); + a->data.v = strdup(name); + } + } +} diff --git a/src/attributes/racename.h b/src/attributes/racename.h new file mode 100644 index 000000000..04b271e35 --- /dev/null +++ b/src/attributes/racename.h @@ -0,0 +1,37 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_RACENAME_H +#define H_ATTRIBUTE_RACENAME_H +#ifdef __cplusplus +extern "C" { +#endif + +struct attrib_type; +struct attrib; + +extern void set_racename(struct attrib ** palist, const char * name); +extern const char * get_racename(struct attrib * alist); + +extern struct attrib_type at_racename; + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/raceprefix.c b/src/attributes/raceprefix.c new file mode 100644 index 000000000..3c15a93a0 --- /dev/null +++ b/src/attributes/raceprefix.c @@ -0,0 +1,60 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "raceprefix.h" +#include + +#include + +#include +#include + +attrib_type at_raceprefix = { + "raceprefix", NULL, a_finalizestring, NULL, a_writestring, a_readstring, ATF_UNIQUE +}; + +void +set_prefix(attrib ** ap, const char * str) +{ + attrib * a = a_find(*ap, &at_raceprefix); + if (a==NULL) { + a = a_add(ap, a_new(&at_raceprefix)); + } else { + free(a->data.v); + } + assert(a->type==&at_raceprefix); + a->data.v = strdup(str); +} + +const char * +get_prefix(const attrib * a) +{ + char * str; + a = a_findc(a, &at_raceprefix); + if (a==NULL) return NULL; + str = (char *)a->data.v; + /* conversion of old prefixes */ + if (strncmp(str, "prefix_", 7)==0) { + ((attrib*)a)->data.v = strdup(str+7); + free(str); + str = (char *)a->data.v; + } + return str; +} diff --git a/src/attributes/raceprefix.h b/src/attributes/raceprefix.h new file mode 100644 index 000000000..f3fb85e7d --- /dev/null +++ b/src/attributes/raceprefix.h @@ -0,0 +1,33 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_RACEPREFIX +#define H_ATTRIBUTE_RACEPREFIX +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_raceprefix; +extern void set_prefix(struct attrib ** ap, const char * str); +extern const char * get_prefix(const struct attrib * a); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/reduceproduction.c b/src/attributes/reduceproduction.c new file mode 100644 index 000000000..3f1ef5ac9 --- /dev/null +++ b/src/attributes/reduceproduction.c @@ -0,0 +1,51 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "reduceproduction.h" +#include +#include + +static int +age_reduceproduction(attrib *a) +{ + int reduce = 100 - (5 * --a->data.sa[1]); + if (reduce < 10) reduce = 10; + a->data.sa[0] = (short)reduce; + return (a->data.sa[1]>0)?AT_AGE_KEEP:AT_AGE_REMOVE; +} + +attrib_type at_reduceproduction = { + "reduceproduction", + NULL, + NULL, + age_reduceproduction, + a_writeshorts, + a_readshorts, + ATF_UNIQUE +}; + +attrib * +make_reduceproduction(int percent, int time) +{ + attrib * a = a_new(&at_reduceproduction); + a->data.sa[0] = (short)percent; + a->data.sa[1] = (short)time; + return a; +} diff --git a/src/attributes/reduceproduction.h b/src/attributes/reduceproduction.h new file mode 100644 index 000000000..4bee20399 --- /dev/null +++ b/src/attributes/reduceproduction.h @@ -0,0 +1,32 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_REDUCEPRODUCTION +#define H_ATTRIBUTE_REDUCEPRODUCTION +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib * make_reduceproduction(int percent, int time); +extern struct attrib_type at_reduceproduction; + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/targetregion.c b/src/attributes/targetregion.c new file mode 100644 index 000000000..d182e7fff --- /dev/null +++ b/src/attributes/targetregion.c @@ -0,0 +1,61 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "targetregion.h" + +#include +#include +#include +#include + +#include +#include +#include + +static void +write_targetregion(const attrib * a, const void * owner, struct storage * store) +{ + write_region_reference((region*)a->data.v, store); +} + +static int +read_targetregion(attrib * a, void * owner, struct storage * store) +{ + int result = read_reference(&a->data.v, store, read_region_reference, RESOLVE_REGION(store->version)); + if (result==0 && !a->data.v) return AT_READ_FAIL; + return AT_READ_OK; +} + +attrib_type at_targetregion = { + "targetregion", + NULL, + NULL, + NULL, + write_targetregion, + read_targetregion, + ATF_UNIQUE +}; + +attrib * +make_targetregion(struct region * r) +{ + attrib * a = a_new(&at_targetregion); + a->data.v = r; + return a; +} diff --git a/src/attributes/targetregion.h b/src/attributes/targetregion.h new file mode 100644 index 000000000..d35aeba06 --- /dev/null +++ b/src/attributes/targetregion.h @@ -0,0 +1,34 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_TARGETREGION +#define H_ATTRIBUTE_TARGETREGION +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_targetregion; + +struct region; +extern struct attrib * make_targetregion(struct region *); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/viewrange.c b/src/attributes/viewrange.c new file mode 100644 index 000000000..e44f2ca00 --- /dev/null +++ b/src/attributes/viewrange.c @@ -0,0 +1,77 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "viewrange.h" + +/* util includes */ +#include +#include +#include + +/* libc includes */ +#include + +static void +a_writefunction(const struct attrib * a, const void * owner, struct storage * store) +{ + const char * str = get_functionname((pf_generic)a->data.f); + store->w_tok(store, str); +} + +static int +a_readfunction(struct attrib *a, void * owner, struct storage * store) +/* return 1 on success, 0 if attrib needs removal */ +{ + char buf[64]; + store->r_tok_buf(store, buf, sizeof(buf)); + a->data.f = get_function(buf); + return AT_READ_OK; +} + +attrib_type at_viewrange = { + "viewrange", + NULL, + NULL, + NULL, + a_writefunction, + a_readfunction, +}; + +attrib * +add_viewrange(attrib ** alist, const char *function) +{ + attrib * a = a_find(*alist, &at_viewrange); + if (a==NULL) a = a_add(alist, make_viewrange(function)); + return a; +} + +attrib * +make_viewrange(const char *function) +{ + attrib * a = a_new(&at_viewrange); + a->data.f = get_function(function); + assert(a->data.f); + return a; +} + +void +init_viewrange(void) +{ + at_register(&at_viewrange); +} diff --git a/src/attributes/viewrange.h b/src/attributes/viewrange.h new file mode 100644 index 000000000..8f8ec1c55 --- /dev/null +++ b/src/attributes/viewrange.h @@ -0,0 +1,35 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_VIEWRANGE +#define H_ATTRIBUTE_VIEWRANGE +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_viewrange; + +extern struct attrib * make_viewrange(const char *function); +extern struct attrib * add_viewrange(struct attrib ** alist, const char *function); +extern void init_viewrange(void); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/bindings/bind_attrib.c b/src/bindings/bind_attrib.c new file mode 100644 index 000000000..f92bcb99e --- /dev/null +++ b/src/bindings/bind_attrib.c @@ -0,0 +1,372 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2010 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bind_attrib.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +static void +init_ext(attrib * a) { + lua_State * L = (lua_State *)global.vm_state; + + lua_pushstring(L, "callbacks"); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_istable(L, -1)) { + lua_pushstring(L, "attrib_init"); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, -1)) { + lua_rawgeti(L, LUA_REGISTRYINDEX, a->data.i); + if (lua_pcall(L, 1, 0, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("attrib_init '%d': %s.\n", a->data.i, error)); + } + } + } +} + +static void +free_ext(attrib * a) { + lua_State * L = (lua_State *)global.vm_state; + if (a->data.i>0) { + luaL_unref(L, LUA_REGISTRYINDEX, a->data.i); + } +} + +static int +age_ext(attrib * a) { + return AT_AGE_KEEP; +} + +static void +write_ext_i(lua_State * L, const char * name, bson_buffer * bb) +{ + int type = lua_type(L, -1); + switch (type) { + case LUA_TNUMBER: + { + double value = tolua_tonumber(L, -1, 0); + bson_append_double(bb, name, value); + } + break; + case LUA_TSTRING: + { + const char * value = tolua_tostring(L, -1, 0); + bson_append_string(bb, name, value); + } + break; + case LUA_TTABLE: + { + int n = luaL_getn(L, -1); + if (n) { + bson_buffer * arr = bson_append_start_array(bb, name); + int i; + for (i=0;i!=n;++i) { + char num[12]; + bson_numstr(num, i); + lua_rawgeti(L, -1, i+1); + write_ext_i(L, num, arr); + lua_pop(L, 1); + } + bson_append_finish_object(arr); + } else { + bson_buffer * sub = bson_append_start_object(bb, name); + lua_pushnil(L); /* first key */ + while (lua_next(L, -2) != 0) { + const char * key; + /* uses 'key' (at index -2) and 'value' (at index -1) */ + lua_pushvalue(L, -2); + key = lua_tolstring(L, -1, 0); + lua_pushvalue(L, -2); + if (key) { + write_ext_i(L, key, sub); + } + /* removes 'value'; keeps 'key' for next iteration */ + lua_pop(L, 3); + } + bson_append_finish_object(sub); + } + } + break; + case LUA_TUSERDATA: + { + tolua_Error tolua_err; + if (tolua_isusertype(L, -1, "unit", 0, &tolua_err)) { + unit * u = (unit *)tolua_tousertype(L, -1, 0); + bson_oid_t oid; + oid.ints[0] = TYP_UNIT; + oid.ints[1] = u->no; + bson_append_oid(bb, name, &oid); + } else if (tolua_isusertype(L, -1, "region", 0, &tolua_err)) { + region * r = (region *)tolua_tousertype(L, -1, 0); + bson_oid_t oid; + oid.ints[0] = TYP_REGION; + oid.ints[1] = r->uid; + bson_append_oid(bb, name, &oid); + } else if (tolua_isusertype(L, -1, "ship", 0, &tolua_err)) { + ship * sh = (ship *)tolua_tousertype(L, -1, 0); + bson_oid_t oid; + oid.ints[0] = TYP_SHIP; + oid.ints[1] = sh->no; + bson_append_oid(bb, name, &oid); + } else if (tolua_isusertype(L, -1, "building", 0, &tolua_err)) { + building * b = (building *)tolua_tousertype(L, -1, 0); + bson_oid_t oid; + oid.ints[0] = TYP_BUILDING; + oid.ints[1] = b->no; + bson_append_oid(bb, name, &oid); + } else { + log_error(("unsuported type.\n")); + bson_append_null(bb, name); + } + } + break; + default: + bson_append_null(bb, name); + break; + } +} + +static void +write_ext(const attrib * a, const void * owner, struct storage * store) { + lua_State * L = (lua_State *)global.vm_state; + if (a->data.i>0) { + int handle = a->data.i; + bson_buffer bb; + bson b; + + bson_buffer_init( & bb ); + lua_rawgeti(L, LUA_REGISTRYINDEX, handle); + write_ext_i(L, "_data", &bb); + bson_from_buffer(&b, &bb); + store->w_int(store, bson_size(&b)); + store->w_bin(store, b.data, bson_size(&b)); + bson_destroy(&b); + } +} + +static int +read_ext_i(lua_State * L, bson_iterator * it, bson_type type) +{ + switch (type) { + case bson_double: + { + lua_pushnumber(L, bson_iterator_double(it)); + } + break; + case bson_string: + { + lua_pushstring(L, bson_iterator_string(it)); + } + break; + case bson_array: + { + bson_iterator sub; + int err; + bson_iterator_subiterator(it, &sub); + lua_newtable(L); + if (bson_iterator_more(&sub)) { + bson_type ctype; + for (ctype = bson_iterator_next(&sub); bson_iterator_more(&sub); ctype = bson_iterator_next(&sub)) { + int i = atoi(bson_iterator_key(&sub)); + err = read_ext_i(L, &sub, ctype); + if (err) { + lua_pop(L, 1); + return err; + } + lua_rawseti(L, -2, i+1); + } + } + } + break; + case bson_object: + { + bson_iterator sub; + int err; + bson_iterator_subiterator(it, &sub); + lua_newtable(L); + if (bson_iterator_more(&sub)) { + bson_type ctype; + for (ctype = bson_iterator_next(&sub); bson_iterator_more(&sub); ctype = bson_iterator_next(&sub)) { + lua_pushstring(L, bson_iterator_key(&sub)); + err = read_ext_i(L, &sub, ctype); + if (err) { + lua_pop(L, 1); + return err; + } + lua_rawset(L, -3); + } + } + } + break; + case bson_oid: + { + bson_oid_t * oid = bson_iterator_oid(it); + if (oid->ints[0]==TYP_UNIT) { + unit * u = findunit(oid->ints[1]); + if (u) tolua_pushusertype(L, u, "unit"); + else lua_pushnil(L); + } else if (oid->ints[0]==TYP_REGION) { + region * r = findregionbyid(oid->ints[1]); + if (r) tolua_pushusertype(L, r, "region"); + else lua_pushnil(L); + } else if (oid->ints[0]==TYP_SHIP) { + ship * sh = findship(oid->ints[1]); + if (sh) tolua_pushusertype(L, sh, "ship"); + else lua_pushnil(L); + } else if (oid->ints[0]==TYP_BUILDING) { + building * b = findbuilding(oid->ints[1]); + if (b) tolua_pushusertype(L, b, "building"); + else lua_pushnil(L); + } + else { + log_error(("unknown oid %d %d %d\n", oid->ints[0], oid->ints[3], oid->ints[2])); + lua_pushnil(L); + } + } + break; + case bson_null: + lua_pushnil(L); + break; + case bson_eoo: + return EFAULT; + default: + return EINVAL; + } + return 0; +} + +static int +resolve_bson(variant data, void * address) +{ + lua_State * L = (lua_State *)global.vm_state; + bson b; + int err; + bson_iterator it; + attrib * a = (attrib*)address; + char * buffer = data.v; + + bson_init(&b, buffer, 1); + bson_iterator_init(&it, b.data); + err = read_ext_i(L, &it, bson_iterator_next(&it)); + a->data.i = luaL_ref(L, LUA_REGISTRYINDEX); + bson_destroy(&b); + return err?AT_READ_FAIL:AT_READ_OK; +} + +static int +read_ext(attrib * a, void * owner, struct storage * store) { + variant data; + int len = store->r_int(store); + data.v = bson_malloc(len); + store->r_bin(store, data.v, (size_t)len); + a->data.v = 0; + ur_add(data, a, resolve_bson); + return AT_READ_OK; +}; + +attrib_type at_lua_ext = { + "lua", init_ext, free_ext, age_ext, write_ext, read_ext +}; + +static int +tolua_attrib_create(lua_State* L) +{ + attrib ** ap = NULL; + tolua_Error tolua_err; + + if (tolua_isusertype(L, 1, TOLUA_CAST "unit", 0, &tolua_err)) { + unit * u = (unit *)tolua_tousertype(L, 1, 0); + ap = &u->attribs; + } + if (ap) { + attrib * a = a_new(&at_lua_ext); + int handle; + + lua_pushvalue(L, 2); + handle = luaL_ref(L, LUA_REGISTRYINDEX); + a->data.i = handle; + + a_add(ap, a); + tolua_pushusertype(L, (void*)a, TOLUA_CAST "attrib"); + return 1; + } + return 0; +} + +int +tolua_attrib_data(lua_State * L) +{ + attrib * a = (attrib *)tolua_tousertype(L, 1, 0); + if (a && a->data.i) { + lua_rawgeti(L, LUA_REGISTRYINDEX, a->data.i); + return 1; + } + return 0; +} + +attrib * +tolua_get_lua_ext(struct attrib * alist) +{ + while (alist && alist->type!=&at_lua_ext) alist = alist->next; + return alist; +} + +int +tolua_attriblist_next(lua_State *L) +{ + attrib** attrib_ptr = (attrib **)lua_touserdata(L, lua_upvalueindex(1)); + attrib * a = *attrib_ptr; + if (a != NULL) { + tolua_pushusertype(L, (void*)a, TOLUA_CAST "attrib"); + *attrib_ptr = tolua_get_lua_ext(a->next); + return 1; + } + else return 0; /* no more values to return */ +} + + +void +tolua_attrib_open(lua_State* L) +{ + at_register(&at_lua_ext); + + tolua_usertype(L, TOLUA_CAST "attrib"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, TOLUA_CAST "attrib", TOLUA_CAST "attrib", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "attrib"); + { + tolua_function(L, TOLUA_CAST "create", &tolua_attrib_create); + tolua_variable(L, TOLUA_CAST "data", &tolua_attrib_data, NULL); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_attrib.h b/src/bindings/bind_attrib.h new file mode 100644 index 000000000..d4ce7bf95 --- /dev/null +++ b/src/bindings/bind_attrib.h @@ -0,0 +1,24 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2010 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct attrib; + void tolua_attrib_open(struct lua_State *L); + struct attrib * tolua_get_lua_ext(struct attrib * alist); + int tolua_attriblist_next(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_building.c b/src/bindings/bind_building.c new file mode 100644 index 000000000..e5c9efde3 --- /dev/null +++ b/src/bindings/bind_building.c @@ -0,0 +1,255 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bind_building.h" +#include "bind_unit.h" + +#include +#include +#include + +#include +#include + +int tolua_buildinglist_next(lua_State *L) +{ + building** building_ptr = (building **)lua_touserdata(L, lua_upvalueindex(1)); + building * u = *building_ptr; + if (u != NULL) { + tolua_pushusertype(L, (void*)u, TOLUA_CAST "building"); + *building_ptr = u->next; + return 1; + } + else return 0; /* no more values to return */ +} + + +static int +tolua_building_addaction(lua_State* L) +{ + building* self = (building*)tolua_tousertype(L, 1, 0); + const char * fname = tolua_tostring(L, 2, 0); + const char * param = tolua_tostring(L, 3, 0); + + building_addaction(self, fname, param); + + return 0; +} + +static int +tolua_building_get_objects(lua_State* L) +{ + building * self = (building *)tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); + return 1; +} + +static int tolua_building_get_region(lua_State* L) +{ + building* self = (building*) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, building_getregion(self), TOLUA_CAST "region"); + return 1; +} + +static int tolua_building_set_region(lua_State* L) +{ + building* self = (building*)tolua_tousertype(L, 1, 0); + building_setregion(self, (region*)tolua_tousertype(L, 2, 0)); + return 0; +} + + +static int tolua_building_get_info(lua_State* L) +{ + building* self = (building*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->display); + return 1; +} + +static int tolua_building_set_info(lua_State* L) +{ + building* self = (building*)tolua_tousertype(L, 1, 0); + const char * info = tolua_tostring(L, 2, 0); + free(self->display); + if (info) self->display = strdup(info); + else self->display = NULL; + return 0; +} + +static int tolua_building_get_name(lua_State* L) +{ + building* self = (building*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, building_getname(self)); + return 1; +} + +static int tolua_building_set_name(lua_State* L) +{ + building* self = (building*)tolua_tousertype(L, 1, 0); + building_setname(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int tolua_building_get_size(lua_State* L) +{ + building* self = (building*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, self->size); + return 1; +} + +static int tolua_building_set_size(lua_State* L) +{ + building* self = (building*)tolua_tousertype(L, 1, 0); + self->size = (int)tolua_tonumber(L, 2, 0); + return 0; +} + +static int +tolua_building_get_units(lua_State* L) +{ + building * self = (building *)tolua_tousertype(L, 1, 0); + unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); + unit * u = self->region->units; + + while (u && u->building!=self) u = u->next; + luaL_getmetatable(L, "unit"); + lua_setmetatable(L, -2); + + *unit_ptr = u; + + lua_pushcclosure(L, tolua_unitlist_nextb, 1); + return 1; +} + +static int +tolua_building_get_id(lua_State* L) +{ + building * self = (building *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->no); + return 1; +} + +static int +tolua_building_get_type(lua_State* L) +{ + building * self = (building *)tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->type->_name); + return 1; +} + +static int +tolua_building_get_typename(lua_State* L) +{ + building * b = (building *)tolua_tousertype(L, 1, 0); + if (b) { + int size = (int)tolua_tonumber(L, 2, b->size); + tolua_pushstring(L, buildingtype(b->type, b, size)); + return 1; + } + return 0; +} + +static int +tolua_building_get_owner(lua_State* L) +{ + building* b = (building*) tolua_tousertype(L, 1, 0); + unit * u = b?building_owner(b):NULL; + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + return 1; +} + +static int +tolua_building_set_owner(lua_State* L) +{ + building* b = (building*) tolua_tousertype(L, 1, 0); + unit * u = (unit *)tolua_tousertype(L, 2, 0); + unit * o = b?building_owner(b):NULL; + if (o && o!=u) { + freset(o, UFL_OWNER); + } + if (u) { + fset(u, UFL_OWNER); + } + return 0; +} + +static int +tolua_building_create(lua_State* L) +{ + region * r = (region *)tolua_tousertype(L, 1, 0); + const char * bname = tolua_tostring(L, 2, 0); + if (bname) { + const building_type * btype = bt_find(bname); + if (btype) { + building * b = new_building(btype, r, default_locale); + tolua_pushusertype(L, (void*)b, TOLUA_CAST "building"); + return 1; + } + } + return 0; +} + +static int +tolua_building_tostring(lua_State *L) +{ + building * self = (building *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, buildingname(self)); + return 1; +} + +static int +tolua_building_destroy(lua_State *L) +{ + building * self = (building *)tolua_tousertype(L, 1, 0); + remove_building(&self->region->buildings, self); + return 0; +} + +void +tolua_building_open(lua_State* L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "building"); + tolua_usertype(L, TOLUA_CAST "building_list"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, TOLUA_CAST "building", TOLUA_CAST "building", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "building"); + { + tolua_function(L, TOLUA_CAST "create", tolua_building_create); + tolua_function(L, TOLUA_CAST "destroy", tolua_building_destroy); + tolua_function(L, TOLUA_CAST "__tostring", tolua_building_tostring); + + tolua_variable(L, TOLUA_CAST "id", tolua_building_get_id, NULL); + tolua_variable(L, TOLUA_CAST "owner", tolua_building_get_owner, tolua_building_set_owner); + tolua_variable(L, TOLUA_CAST "type", tolua_building_get_type, NULL); + tolua_variable(L, TOLUA_CAST "name", tolua_building_get_name, tolua_building_set_name); + tolua_variable(L, TOLUA_CAST "info", tolua_building_get_info, tolua_building_set_info); + tolua_variable(L, TOLUA_CAST "units", tolua_building_get_units, NULL); + tolua_variable(L, TOLUA_CAST "region", tolua_building_get_region, tolua_building_set_region); + tolua_variable(L, TOLUA_CAST "size", tolua_building_get_size, tolua_building_set_size); + tolua_function(L, TOLUA_CAST "add_action", tolua_building_addaction); + tolua_function(L, TOLUA_CAST "get_typename", tolua_building_get_typename); +#ifdef TODO + .property("type", &building_gettype) + .def_readwrite("size", &building::size) +#endif + tolua_variable(L, TOLUA_CAST "objects", tolua_building_get_objects, 0); + + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_building.h b/src/bindings/bind_building.h new file mode 100644 index 000000000..a6168b66c --- /dev/null +++ b/src/bindings/bind_building.h @@ -0,0 +1,23 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + int tolua_buildinglist_next(struct lua_State *L); + void tolua_building_open(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_faction.c b/src/bindings/bind_faction.c new file mode 100644 index 000000000..44caf3618 --- /dev/null +++ b/src/bindings/bind_faction.c @@ -0,0 +1,561 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bind_faction.h" +#include "bind_unit.h" +#include "bindings.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +int tolua_factionlist_next(lua_State *L) +{ + faction** faction_ptr = (faction **)lua_touserdata(L, lua_upvalueindex(1)); + faction * f = *faction_ptr; + if (f != NULL) { + tolua_pushusertype(L, (void*)f, TOLUA_CAST "faction"); + *faction_ptr = f->next; + return 1; + } + else return 0; /* no more values to return */ +} + +int tolua_factionlist_iter(lua_State *L) +{ + faction_list** faction_ptr = (faction_list **)lua_touserdata(L, lua_upvalueindex(1)); + faction_list* flist = *faction_ptr; + if (flist != NULL) { + tolua_pushusertype(L, (void*)flist->data, TOLUA_CAST "faction"); + *faction_ptr = flist->next; + return 1; + } + else return 0; /* no more values to return */ +} + +static int tolua_faction_get_units(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); + + luaL_getmetatable(L, TOLUA_CAST "unit"); + lua_setmetatable(L, -2); + + *unit_ptr = self->units; + + lua_pushcclosure(L, tolua_unitlist_nextf, 1); + return 1; +} + +int tolua_faction_add_item(lua_State *L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + const char * iname = tolua_tostring(L, 2, 0); + int number = (int)tolua_tonumber(L, 3, 0); + int result = -1; + + if (iname!=NULL) { + const item_type * itype = it_find(iname); + if (itype!=NULL) { + item * i = i_change(&self->items, itype, number); + result = i?i->number:0; + } // if (itype!=NULL) + } + lua_pushnumber(L, result); + return 1; +} + +static int +tolua_faction_get_maxheroes(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)maxheroes(self)); + return 1; +} + +static int +tolua_faction_get_heroes(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)countheroes(self)); + return 1; +} + +static int +tolua_faction_get_score(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->score); + return 1; +} + +static int +tolua_faction_get_id(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->no); + return 1; +} + +static int +tolua_faction_set_id(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + int id = (int)tolua_tonumber(L, 2, 0); + if (findfaction(id)==NULL) { + renumber_faction(self, id); + lua_pushboolean(L, 1); + } else { + lua_pushboolean(L, 0); + } + return 1; +} + +static int +tolua_faction_get_age(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->age); + return 1; +} + +static int +tolua_faction_set_age(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + int age = (int)tolua_tonumber(L, 2, 0); + self->age = age; + return 0; +} + +static int +tolua_faction_get_flags(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->flags); + return 1; +} + +static int +tolua_faction_get_options(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->options); + return 1; +} + +static int +tolua_faction_set_options(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + int options = (int)tolua_tonumber(L, 2, self->options); + self->options = options; + return 1; +} + +static int +tolua_faction_get_lastturn(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->lastorders); + return 1; +} + +static int +tolua_faction_set_lastturn(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + if (self) { + self->lastorders = (int)tolua_tonumber(L, 2, self->lastorders); + } + return 0; +} + +static int +tolua_faction_renumber(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + int no = (int)tolua_tonumber(L, 2, 0); + + renumber_faction(self, no); + return 0; +} + +static int +tolua_faction_get_objects(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); + return 1; +} + +static int +tolua_faction_get_policy(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + faction * other = (faction *)tolua_tousertype(L, 2, 0); + const char * policy = tolua_tostring(L, 3, 0); + + int result = 0, mode; + for (mode=0;helpmodes[mode].name!=NULL;++mode) { + if (strcmp(policy, helpmodes[mode].name)==0) { + result = get_alliance(self, other) & mode; + break; + } + } + + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + + +static int +tolua_faction_set_policy(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + faction * other = (faction *)tolua_tousertype(L, 2, 0); + const char * policy = tolua_tostring(L, 3, 0); + int value = tolua_toboolean(L, 4, 0); + + int mode; + for (mode=0;helpmodes[mode].name!=NULL;++mode) { + if (strcmp(policy, helpmodes[mode].name)==0) { + if (value) { + set_alliance(self, other, get_alliance(self, other) | helpmodes[mode].status); + } else { + set_alliance(self, other, get_alliance(self, other) & ~helpmodes[mode].status); + } + break; + } + } + + return 0; +} + +static int +tolua_faction_normalize(lua_State* L) +{ + faction * f = (faction *)tolua_tousertype(L, 1, 0); + region * r = (region * )tolua_tousertype(L, 2, 0); + if (r) { + plane * pl = rplane(r); + int nx = r->x, ny = r->y; + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl, r); + tolua_pushnumber(L, (lua_Number)nx); + tolua_pushnumber(L, (lua_Number)ny); + return 2; + } + return 0; +} + +static int +tolua_faction_set_origin(lua_State* L) +{ + faction * f = (faction *)tolua_tousertype(L, 1, 0); + region * r = (region *)tolua_tousertype(L, 2, 0); + plane * pl = rplane(r); + int id = pl?pl->id:0; + + set_ursprung(f, id, r->x - plane_center_x(pl), r->y - plane_center_y(pl)); + return 0; +} + +static int +tolua_faction_get_origin(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + + ursprung * origin = self->ursprung; + int x, y; + while (origin!=NULL && origin->id!=0) { + origin = origin->next; + } + if (origin) { + x = origin->x; + y = origin->y; + } else { + x = 0; + y = 0; + } + + tolua_pushnumber(L, (lua_Number)x); + tolua_pushnumber(L, (lua_Number)y); + return 2; +} + +static int +tolua_faction_destroy(lua_State* L) +{ + faction* f = (faction*) tolua_tousertype(L, 1, 0); + destroyfaction(f); + return 0; +} + +static int +tolua_faction_create(lua_State* L) +{ + const char * email = tolua_tostring(L, 1, 0); + const char * racename = tolua_tostring(L, 2, 0); + const char * lang = tolua_tostring(L, 3, 0); + struct locale * loc = find_locale(lang); + faction * f = NULL; + const struct race * frace = rc_find(racename); + if (frace==NULL) frace = findrace(racename, find_locale("de")); + if (frace==NULL) frace = findrace(racename, find_locale("en")); + if (frace!=NULL) { + f = addfaction(email, NULL, frace, loc, 0); + } + if (!f) { + log_error(("faction.create(%s, %s, %s)\n", email, racename, lang)); + } + tolua_pushusertype(L, f, TOLUA_CAST "faction"); + return 1; +} + +static int tolua_faction_get_password(lua_State* L) +{ + faction* self = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, faction_getpassword(self)); + return 1; +} + +static int tolua_faction_set_password(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + faction_setpassword(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int tolua_faction_get_email(lua_State* L) +{ + faction* self = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, faction_getemail(self)); + return 1; +} + +static int tolua_faction_set_email(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + faction_setemail(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int tolua_faction_get_locale(lua_State* L) +{ + faction* self = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, locale_name(self->locale)); + return 1; +} + +static int tolua_faction_set_locale(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + self->locale = find_locale(name); + return 0; +} + +static int tolua_faction_get_race(lua_State* L) +{ + faction* self = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->race->_name[0]); + return 1; +} + +static int tolua_faction_set_race(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + race * rc = rc_find(name); + if (rc!=NULL) { + self->race = rc; + } + + return 0; +} + +static int tolua_faction_get_name(lua_State* L) +{ + faction* self = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, faction_getname(self)); + return 1; +} + +static int tolua_faction_set_name(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + faction_setname(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int tolua_faction_get_uid(lua_State* L) +{ + faction* f = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, f->subscription); + return 1; +} + +static int tolua_faction_set_uid(lua_State* L) +{ + faction* f = (faction*)tolua_tousertype(L, 1, 0); + f->subscription = (int)tolua_tonumber(L, 2, 0); + return 0; +} + +static int tolua_faction_get_info(lua_State* L) +{ + faction* self = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, faction_getbanner(self)); + return 1; +} + +static int tolua_faction_set_info(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + faction_setbanner(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int tolua_faction_get_alliance(lua_State* L) +{ + faction* self = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, f_get_alliance(self), TOLUA_CAST "alliance"); + return 1; +} + +static int tolua_faction_set_alliance(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + alliance* alli = (alliance*)tolua_tousertype(L, 2, 0); + + setalliance(self, alli); + + return 0; +} + +static int tolua_faction_get_items(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + item ** item_ptr = (item **)lua_newuserdata(L, sizeof(item *)); + + luaL_getmetatable(L, TOLUA_CAST "item"); + lua_setmetatable(L, -2); + + *item_ptr = self->items; + + lua_pushcclosure(L, tolua_itemlist_next, 1); + + return 1; +} + +static int +tolua_faction_tostring(lua_State *L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, factionname(self)); + return 1; +} + +static int tolua_faction_get_spells(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + spell_list * slist = self->spellbook; + if (slist) { + spell_list ** spell_ptr = (spell_list **)lua_newuserdata(L, sizeof(spell_list *)); + luaL_getmetatable(L, TOLUA_CAST "spell_list"); + lua_setmetatable(L, -2); + + *spell_ptr = slist; + lua_pushcclosure(L, tolua_spelllist_next, 1); + return 1; + } + + lua_pushnil(L); + return 1; +} + +void +tolua_faction_open(lua_State* L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "faction"); + tolua_usertype(L, TOLUA_CAST "faction_list"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, TOLUA_CAST "faction", TOLUA_CAST "faction", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "faction"); + { + tolua_function(L, TOLUA_CAST "__tostring", tolua_faction_tostring); + + tolua_variable(L, TOLUA_CAST "id", tolua_faction_get_id, tolua_faction_set_id); + tolua_variable(L, TOLUA_CAST "uid", &tolua_faction_get_uid, &tolua_faction_set_uid); + tolua_variable(L, TOLUA_CAST "name", &tolua_faction_get_name, &tolua_faction_set_name); + tolua_variable(L, TOLUA_CAST "info", &tolua_faction_get_info, &tolua_faction_set_info); + tolua_variable(L, TOLUA_CAST "units", tolua_faction_get_units, NULL); + tolua_variable(L, TOLUA_CAST "heroes", tolua_faction_get_heroes, NULL); + tolua_variable(L, TOLUA_CAST "spells", tolua_faction_get_spells, 0); + tolua_variable(L, TOLUA_CAST "maxheroes", tolua_faction_get_maxheroes, NULL); + tolua_variable(L, TOLUA_CAST "password", tolua_faction_get_password, tolua_faction_set_password); + tolua_variable(L, TOLUA_CAST "email", tolua_faction_get_email, tolua_faction_set_email); + tolua_variable(L, TOLUA_CAST "locale", tolua_faction_get_locale, tolua_faction_set_locale); + tolua_variable(L, TOLUA_CAST "race", tolua_faction_get_race, tolua_faction_set_race); + tolua_variable(L, TOLUA_CAST "alliance", tolua_faction_get_alliance, tolua_faction_set_alliance); + tolua_variable(L, TOLUA_CAST "score", tolua_faction_get_score, NULL); + tolua_variable(L, TOLUA_CAST "age", tolua_faction_get_age, tolua_faction_set_age); + tolua_variable(L, TOLUA_CAST "options", tolua_faction_get_options, tolua_faction_set_options); + tolua_variable(L, TOLUA_CAST "flags", tolua_faction_get_flags, NULL); + tolua_variable(L, TOLUA_CAST "lastturn", tolua_faction_get_lastturn, tolua_faction_set_lastturn); + + tolua_function(L, TOLUA_CAST "set_policy", &tolua_faction_set_policy); + tolua_function(L, TOLUA_CAST "get_policy", &tolua_faction_get_policy); + tolua_function(L, TOLUA_CAST "get_origin", &tolua_faction_get_origin); + tolua_function(L, TOLUA_CAST "set_origin", &tolua_faction_set_origin); + tolua_function(L, TOLUA_CAST "normalize", &tolua_faction_normalize); + + tolua_function(L, TOLUA_CAST "add_item", tolua_faction_add_item); + tolua_variable(L, TOLUA_CAST "items", tolua_faction_get_items, NULL); + + tolua_function(L, TOLUA_CAST "renumber", &tolua_faction_renumber); + tolua_function(L, TOLUA_CAST "create", &tolua_faction_create); + tolua_function(L, TOLUA_CAST "destroy", &tolua_faction_destroy); +#ifdef TODO + def("faction_origin", &faction_getorigin, pure_out_value(_2) + pure_out_value(_3)), + + .def_readwrite("subscription", &faction::subscription) + + .property("x", &faction_getorigin_x, &faction_setorigin_x) + .property("y", &faction_getorigin_y, &faction_setorigin_y) + + .def("add_notice", &faction_addnotice) +#endif + tolua_variable(L, TOLUA_CAST "objects", tolua_faction_get_objects, NULL); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_faction.h b/src/bindings/bind_faction.h new file mode 100644 index 000000000..c89750062 --- /dev/null +++ b/src/bindings/bind_faction.h @@ -0,0 +1,24 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + int tolua_factionlist_next(struct lua_State *L); + int tolua_factionlist_iter(struct lua_State *L); + void tolua_faction_open(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_gmtool.c b/src/bindings/bind_gmtool.c new file mode 100644 index 000000000..6b57d1740 --- /dev/null +++ b/src/bindings/bind_gmtool.c @@ -0,0 +1,266 @@ +#include +#include + +#include "bind_gmtool.h" +#include "../gmtool.h" +#include "../gmtool_structs.h" + +#include +#include +#include +#include + +#include +#include + +static int +tolua_run_mapper(lua_State* L) +{ + run_mapper(); + return 0; +} + +static int +tolua_highlight_region(lua_State* L) +{ + region * r = tolua_tousertype(L, 1, 0); + int select = tolua_toboolean(L, 2, 0); + highlight_region(r, select); + return 0; +} + +static int +tolua_current_region(lua_State* L) +{ + map_region * mr = cursor_region(¤t_state->display, ¤t_state->cursor); + tolua_pushusertype(L, mr?mr->r:NULL, TOLUA_CAST "region"); + return 1; +} + + +static int +tolua_select_coordinate(lua_State* L) +{ + int nx = (int)tolua_tonumber(L, 1, 0); + int ny = (int)tolua_tonumber(L, 2, 0); + int select = tolua_toboolean(L, 3, 0); + if (current_state) { + select_coordinate(current_state->selected, nx, ny, select); + } + return 0; +} + +static int +tolua_select_region(lua_State* L) +{ + region * r = tolua_tousertype(L, 1, 0); + int select = tolua_toboolean(L, 2, 0); + if (current_state && r) { + select_coordinate(current_state->selected, r->x, r->y, select); + } + return 0; +} + +typedef struct tag_iterator { + selection * list; + tag * node; + region * r; + int hash; +} tag_iterator; + +void +tag_advance(tag_iterator * iter) +{ + while (iter->hash!=MAXTHASH) { + if (iter->node) { + iter->node = iter->node->nexthash; + } + while (!iter->node && iter->hash != MAXTHASH) { + if (++iter->hash != MAXTHASH) { + iter->node = iter->list->tags[iter->hash]; + } + } + if (iter->node) { + iter->r = findregion(iter->node->coord.x, iter->node->coord.y); + if (iter->r) { + break; + } + } + } +} + +void +tag_rewind(tag_iterator * iter) +{ + if (iter->list) { + iter->r = NULL; + iter->node = iter->list->tags[0]; + iter->hash = 0; + if (iter->node) { + iter->r = findregion(iter->node->coord.x, iter->node->coord.y); + } + if (!iter->r) { + tag_advance(iter); + } + } else { + iter->node = 0; + iter->hash = MAXTHASH; + } +} + +static int +tolua_tags_next(lua_State *L) +{ + tag_iterator * iter = (tag_iterator *)lua_touserdata(L, lua_upvalueindex(1)); + if (iter->node) { + tolua_pushusertype(L, (void*)iter->r, TOLUA_CAST "region"); + tag_advance(iter); + return 1; + } + else { + return 0; /* no more values to return */ + } +} + +static int +tolua_selected_regions(lua_State* L) +{ + tag_iterator * iter = (tag_iterator*)lua_newuserdata(L, sizeof(tag_iterator)); + + luaL_getmetatable(L, "tag_iterator"); + lua_setmetatable(L, -2); + + iter->list = current_state->selected; + tag_rewind(iter); + + lua_pushcclosure(L, tolua_tags_next, 1); + return 1; +} + +static int +tolua_state_open(lua_State* L) +{ + unused(L); + state_open(); + return 0; +} + +static int +tolua_state_close(lua_State* L) +{ + unused(L); + state_close(current_state); + return 0; +} + +static int +tolua_make_island(lua_State * L) +{ + int x = (int)tolua_tonumber(L, 1, 0); + int y = (int)tolua_tonumber(L, 2, 0); + int s = (int)tolua_tonumber(L, 3, 0); + int n = (int)tolua_tonumber(L, 4, s / 3); + + n = build_island_e3(x, y, n, s); + tolua_pushnumber(L, n); + return 1; +} + +static int paint_handle; +static struct lua_State * paint_state; + +static void +lua_paint_info(struct window * wnd, const struct state * st) +{ + struct lua_State * L = paint_state; + int nx = st->cursor.x, ny = st->cursor.y; + pnormalize(&nx, &ny, st->cursor.pl); + lua_rawgeti(L, LUA_REGISTRYINDEX, paint_handle); + tolua_pushnumber(L, nx); + tolua_pushnumber(L, ny); + if (lua_pcall(L, 2, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("paint function failed: %s\n", error)); + lua_pop(L, 1); + tolua_error(L, TOLUA_CAST "event handler call failed", NULL); + } else { + const char* result = lua_tostring(L, -1); + WINDOW * win = wnd->handle; + int size = getmaxx(win)-2; + int line = 0, maxline = getmaxy(win)-2; + const char * str = result; + wxborder(win); + + while (*str && line +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bind_hashtable.h" + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include + +static int +tolua_hashtable_get(lua_State* L) +{ + hashtable self = (hashtable) tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + attrib * a = a_find(*self, &at_object); + + for (; a && a->type == &at_object; a = a->next) { + const char * obj_name = object_name(a); + if (obj_name && name && strcmp(obj_name, name) == 0) { + variant val; + object_type type; + + object_get(a, &type, &val); + switch (type) { + case TNONE: + lua_pushnil(L); + break; + case TINTEGER: + lua_pushnumber(L, (lua_Number)val.i); + break; + case TREAL: + lua_pushnumber(L, (lua_Number)val.f); + break; + case TREGION: + tolua_pushusertype(L, val.v, TOLUA_CAST "region"); + break; + case TBUILDING: + tolua_pushusertype(L, val.v, TOLUA_CAST "building"); + break; + case TUNIT: + tolua_pushusertype(L, val.v, TOLUA_CAST "unit"); + break; + case TSHIP: + tolua_pushusertype(L, val.v, TOLUA_CAST "ship"); + break; + case TSTRING: + tolua_pushstring(L, (const char*) val.v); + break; + default: + assert(!"not implemented"); + } + return 1; + } + } + lua_pushnil(L); + return 1; +} + +static int +tolua_hashtable_set_number(lua_State* L) +{ + hashtable self = (hashtable) tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + lua_Number value = tolua_tonumber(L, 3, 0); + attrib * a = a_find(*self, &at_object); + variant val; + + val.f = (float)value; + + for (; a && a->type == &at_object; a = a->next) { + if (strcmp(object_name(a), name) == 0) { + object_set(a, TREAL, val); + return 0; + } + } + + a = a_add(self, object_create(name, TREAL, val)); + return 0; +} + +static int +tolua_hashtable_set_string(lua_State* L) +{ + hashtable self = (hashtable) tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + const char * value = tolua_tostring(L, 3, 0); + attrib * a = a_find(*self, &at_object); + variant val; + + val.v = strdup(value); + + for (; a && a->type == &at_object; a = a->next) { + if (strcmp(object_name(a), name) == 0) { + object_set(a, TSTRING, val); + return 0; + } + } + + a = a_add(self, object_create(name, TSTRING, val)); + return 0; +} + +static int +tolua_hashtable_set_usertype(lua_State* L, int type) +{ + hashtable self = (hashtable) tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + unit * value = tolua_tousertype(L, 3, 0); + attrib * a = a_find(*self, &at_object); + variant val; + + val.v = value; + + for (; a && a->type == &at_object; a = a->next) { + if (strcmp(object_name(a), name) == 0) { + object_set(a, type, val); + return 0; + } + } + + a = a_add(self, object_create(name, type, val)); + return 0; +} + + +static int +tolua_hashtable_set(lua_State* L) +{ + tolua_Error tolua_err; + if (tolua_isnumber(L, 3, 0, &tolua_err)) { + return tolua_hashtable_set_number(L); + } else if (tolua_isusertype(L, 3, TOLUA_CAST "unit", 0, &tolua_err)) { + return tolua_hashtable_set_usertype(L, TUNIT); + } else if (tolua_isusertype(L, 3, TOLUA_CAST "faction", 0, &tolua_err)) { + return tolua_hashtable_set_usertype(L, TFACTION); + } else if (tolua_isusertype(L, 3, TOLUA_CAST "ship", 0, &tolua_err)) { + return tolua_hashtable_set_usertype(L, TSHIP); + } else if (tolua_isusertype(L, 3, TOLUA_CAST "building", 0, &tolua_err)) { + return tolua_hashtable_set_usertype(L, TBUILDING); + } else if (tolua_isusertype(L, 3, TOLUA_CAST "region", 0, &tolua_err)) { + return tolua_hashtable_set_usertype(L, TREGION); + } + return tolua_hashtable_set_string(L); +} + + + +void +tolua_hashtable_open(lua_State* L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "hashtable"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, TOLUA_CAST "hashtable", TOLUA_CAST "hashtable", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "hashtable"); + { + tolua_function(L, TOLUA_CAST "get", tolua_hashtable_get); + tolua_function(L, TOLUA_CAST "set", tolua_hashtable_set); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_hashtable.h b/src/bindings/bind_hashtable.h new file mode 100644 index 000000000..d137638f2 --- /dev/null +++ b/src/bindings/bind_hashtable.h @@ -0,0 +1,24 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + void tolua_hashtable_open(struct lua_State *L); + + typedef struct attrib ** hashtable; + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_message.c b/src/bindings/bind_message.c new file mode 100644 index 000000000..44c5eb0e7 --- /dev/null +++ b/src/bindings/bind_message.c @@ -0,0 +1,348 @@ +#include +#include + +// kernel includes +#include +#include +#include +#include +#include +#include + +// util includes +#include + +// lua includes +#include +#include + +#include + +#define E_OK 0 +#define E_INVALID_MESSAGE 1 +#define E_INVALID_PARAMETER_NAME 2 +#define E_INVALID_PARAMETER_TYPE 3 +#define E_INVALID_PARAMETER_VALUE 4 + +typedef struct lua_message { + const message_type * mtype; + message * msg; + variant * args; +} lua_message; + +int +mtype_get_param(const message_type * mtype, const char * param) +{ + int i; + for (i=0;i!=mtype->nparameters;++i) { + if (strcmp(mtype->pnames[i], param)==0) { + return i; + } + } + return mtype->nparameters; +} + +static lua_message * +msg_create_message(const char *type) +{ + lua_message * lmsg = malloc(sizeof(lua_message)); + lmsg->msg = 0; + lmsg->args = 0; + lmsg->mtype = mt_find(type); + if (lmsg->mtype) { + lmsg->args = (variant*)calloc(lmsg->mtype->nparameters, sizeof(variant)); + } + return lmsg; +} + +/* + static void +msg_destroy_message(lua_message * msg) +{ + if (msg->msg) msg_release(msg->msg); + if (msg->mtype) { + int i; + for (i=0;i!=msg->mtype->nparameters;++i) { + if (msg->mtype->types[i]->release) { + msg->mtype->types[i]->release(msg->args[i]); + } + } + } +} +*/ +int +msg_set_resource(lua_message * msg, const char * param, const char * resname) +{ + if (msg->mtype) { + int i = mtype_get_param(msg->mtype, param); + if (i==msg->mtype->nparameters) { + return E_INVALID_PARAMETER_NAME; + } + if (strcmp(msg->mtype->types[i]->name, "resource")!=0) { + return E_INVALID_PARAMETER_TYPE; + } + + msg->args[i].v = (void*)rt_find(resname); + + return E_OK; + } + return E_INVALID_MESSAGE; +} + +int +msg_set_unit(lua_message * msg, const char * param, const unit * u) +{ + if (msg->mtype) { + int i = mtype_get_param(msg->mtype, param); + + if (i==msg->mtype->nparameters) { + return E_INVALID_PARAMETER_NAME; + } + if (strcmp(msg->mtype->types[i]->name, "unit")!=0) { + return E_INVALID_PARAMETER_TYPE; + } + + msg->args[i].v = (void*)u; + + return E_OK; + } + return E_INVALID_MESSAGE; +} + +int +msg_set_region(lua_message * msg, const char * param, const region * r) +{ + if (msg->mtype) { + int i = mtype_get_param(msg->mtype, param); + + if (i==msg->mtype->nparameters) { + return E_INVALID_PARAMETER_NAME; + } + if (strcmp(msg->mtype->types[i]->name, "region")!=0) { + return E_INVALID_PARAMETER_TYPE; + } + + msg->args[i].v = (void*)r; + + return E_OK; + } + return E_INVALID_MESSAGE; +} + +int +msg_set_string(lua_message * msg, const char * param, const char * value) +{ + if (msg->mtype) { + int i = mtype_get_param(msg->mtype, param); + variant var; + + if (i==msg->mtype->nparameters) { + return E_INVALID_PARAMETER_NAME; + } + if (strcmp(msg->mtype->types[i]->name, "string")!=0) { + return E_INVALID_PARAMETER_TYPE; + } + + var.v = (void*)value; + msg->args[i] = msg->mtype->types[i]->copy(var); + + return E_OK; + } + return E_INVALID_MESSAGE; +} + +int +msg_set_int(lua_message * msg, const char * param, int value) +{ + if (msg->mtype) { + int i = mtype_get_param(msg->mtype, param); + if (i==msg->mtype->nparameters) { + return E_INVALID_PARAMETER_NAME; + } + if (strcmp(msg->mtype->types[i]->name, "int")!=0) { + return E_INVALID_PARAMETER_TYPE; + } + + msg->args[i].i = value; + + return E_OK; + } + return E_INVALID_MESSAGE; +} + +int +msg_send_faction(lua_message * msg, faction * f) +{ + assert(f); + assert(msg); + + if (msg->mtype) { + if (msg->msg==NULL) { + msg->msg = msg_create(msg->mtype, msg->args); + } + add_message(&f->msgs, msg->msg); + return E_OK; + } + return E_INVALID_MESSAGE; +} + +int +msg_send_region(lua_message * lmsg, region * r) +{ + if (lmsg->mtype) { + if (lmsg->msg==NULL) { + lmsg->msg = msg_create(lmsg->mtype, lmsg->args); + } + add_message(&r->msgs, lmsg->msg); + return E_OK; + } + return E_INVALID_MESSAGE; +} + + +static int +tolua_msg_create(lua_State * L) +{ + const char * type = tolua_tostring(L, 1, 0); + lua_message * lmsg = msg_create_message(type); + tolua_pushusertype(L, (void*)lmsg, TOLUA_CAST "message"); + return 1; +} +static int +tolua_msg_set_string(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + const char * param = tolua_tostring(L, 2, 0); + const char * value = tolua_tostring(L, 3, 0); + int result = msg_set_string(lmsg, param, value); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_msg_set_int(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + const char * param = tolua_tostring(L, 2, 0); + int value = (int)tolua_tonumber(L, 3, 0); + int result = msg_set_int(lmsg, param, value); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_msg_set_resource(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + const char * param = tolua_tostring(L, 2, 0); + const char * value = tolua_tostring(L, 3, 0); + int result = msg_set_resource(lmsg, param, value); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_msg_set_unit(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + const char * param = tolua_tostring(L, 2, 0); + unit * value = (unit *)tolua_tousertype(L, 3, 0); + int result = msg_set_unit(lmsg, param, value); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_msg_set_region(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + const char * param = tolua_tostring(L, 2, 0); + region * value = (region *)tolua_tousertype(L, 3, 0); + int result = msg_set_region(lmsg, param, value); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_msg_set(lua_State * L) +{ + tolua_Error err; + if (tolua_isnumber(L, 3, 0, &err)) { + return tolua_msg_set_int(L); + } else if (tolua_isusertype(L, 3, TOLUA_CAST "region", 0, &err)) { + return tolua_msg_set_region(L); + } else if (tolua_isusertype(L, 3, TOLUA_CAST "unit", 0, &err)) { + return tolua_msg_set_unit(L); + } + tolua_pushnumber(L, (lua_Number)-1); + return 1; +} + +static int +tolua_msg_send_region(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + region * r = (region *)tolua_tousertype(L, 2, 0); + int result = msg_send_region(lmsg, r); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_msg_report_action(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + region * r = (region *)tolua_tousertype(L, 2, 0); + unit * u = (unit *)tolua_tousertype(L, 3, 0); + int result, flags = (int)tolua_tonumber(L, 4, 0); + if (lmsg->msg==NULL) { + lmsg->msg = msg_create(lmsg->mtype, lmsg->args); + } + result = report_action(r, u, lmsg->msg, flags); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_msg_send_faction(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + faction * f = (faction *)tolua_tousertype(L, 2, 0); + if (f && lmsg) { + int result = msg_send_faction(lmsg, f); + tolua_pushnumber(L, (lua_Number)result); + return 1; + } + return 0; +} + +void +tolua_message_open(lua_State* L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "message"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_function(L, TOLUA_CAST "message", tolua_msg_create); + + tolua_cclass(L, TOLUA_CAST "message", TOLUA_CAST "message", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "message"); + { + tolua_function(L, TOLUA_CAST "set", tolua_msg_set); + tolua_function(L, TOLUA_CAST "set_unit", tolua_msg_set_unit); + tolua_function(L, TOLUA_CAST "set_region", tolua_msg_set_region); + tolua_function(L, TOLUA_CAST "set_resource", tolua_msg_set_resource); + tolua_function(L, TOLUA_CAST "set_int", tolua_msg_set_int); + tolua_function(L, TOLUA_CAST "set_string", tolua_msg_set_string); + tolua_function(L, TOLUA_CAST "send_faction", tolua_msg_send_faction); + tolua_function(L, TOLUA_CAST "send_region", tolua_msg_send_region); + tolua_function(L, TOLUA_CAST "report_action", tolua_msg_report_action); + + tolua_function(L, TOLUA_CAST "create", tolua_msg_create); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_message.h b/src/bindings/bind_message.h new file mode 100644 index 000000000..ed9aab133 --- /dev/null +++ b/src/bindings/bind_message.h @@ -0,0 +1,22 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + void tolua_message_open(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_region.c b/src/bindings/bind_region.c new file mode 100644 index 000000000..19ec1dedb --- /dev/null +++ b/src/bindings/bind_region.c @@ -0,0 +1,696 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bind_region.h" +#include "bind_unit.h" +#include "bind_ship.h" +#include "bind_building.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +int tolua_regionlist_next(lua_State *L) +{ + region** region_ptr = (region **)lua_touserdata(L, lua_upvalueindex(1)); + region * r = *region_ptr; + if (r != NULL) { + tolua_pushusertype(L, (void*)r, TOLUA_CAST "region"); + *region_ptr = r->next; + return 1; + } + else return 0; /* no more values to return */ +} + +static int +tolua_region_get_id(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->uid); + return 1; +} + +static int +tolua_region_get_x(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->x); + return 1; +} + +static int +tolua_region_get_y(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->y); + return 1; +} + +static int +tolua_region_get_plane(lua_State* L) +{ + region * r = (region *)tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, rplane(r), TOLUA_CAST "plane"); + return 1; +} + +static int +tolua_region_get_terrain(lua_State* L) +{ + region* self = (region*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->terrain->_name); + return 1; +} + +static int +tolua_region_set_terrain(lua_State* L) +{ + region* r = (region*) tolua_tousertype(L, 1, 0); + const char * tname = tolua_tostring(L, 2, 0); + if (tname) { + const terrain_type * terrain = get_terrain(tname); + if (terrain) { + terraform_region(r, terrain); + } + } + return 0; +} + +static int +tolua_region_get_terrainname(lua_State* L) +{ + region* self = (region*) tolua_tousertype(L, 1, 0); + attrib * a = a_find(self->attribs, &at_racename); + if (a) { + tolua_pushstring(L, get_racename(a)); + return 1; + } + return 0; +} + +static int +tolua_region_set_owner(lua_State* L) +{ + region* r = (region*) tolua_tousertype(L, 1, 0); + struct faction* f = (struct faction*) tolua_tousertype(L, 2, 0); + if (r) { + region_set_owner(r, f, turn); + } + return 0; +} + +static int +tolua_region_get_owner(lua_State* L) +{ + region* r = (region*) tolua_tousertype(L, 1, 0); + if (r) { + struct faction * f = region_get_owner(r); + tolua_pushusertype(L, f, TOLUA_CAST "faction"); + return 1; + } + return 0; +} + +static int +tolua_region_set_terrainname(lua_State* L) +{ + region* self = (region*) tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + if (name==NULL) { + a_removeall(&self->attribs, &at_racename); + } else { + set_racename(&self->attribs, name); + } + return 0; +} + +static int tolua_region_get_info(lua_State* L) +{ + region* self = (region*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, region_getinfo(self)); + return 1; +} + +static int tolua_region_set_info(lua_State* L) +{ + region* self = (region*)tolua_tousertype(L, 1, 0); + region_setinfo(self, tolua_tostring(L, 2, 0)); + return 0; +} + + +static int tolua_region_get_name(lua_State* L) +{ + region* self = (region*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, region_getname(self)); + return 1; +} + +static int tolua_region_set_name(lua_State* L) +{ + region* self = (region*)tolua_tousertype(L, 1, 0); + region_setname(self, tolua_tostring(L, 2, 0)); + return 0; +} + + +static int tolua_region_get_morale(lua_State* L) +{ + region* r = (region*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, region_get_morale(r)); + return 1; +} + +static int tolua_region_set_morale(lua_State* L) +{ + region* r = (region*)tolua_tousertype(L, 1, 0); + region_set_morale(r, (int)tolua_tonumber(L, 2, 0), turn); + return 0; +} + +static int tolua_region_get_flag(lua_State* L) +{ + region* self = (region*)tolua_tousertype(L, 1, 0); + int bit = (int)tolua_tonumber(L, 2, 0); + + lua_pushboolean(L, (self->flags & (1<land) { + const item_type * lux = r_luxury(r); + if (lux) { + const char * name = lux->rtype->_name[0]; + tolua_pushstring(L, name); + return 1; + } + } + return 0; +} + +static int tolua_region_set_luxury(lua_State* L) +{ + region* r = (region*)tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + if (r->land && name) { + const item_type * lux = r_luxury(r); + const item_type * itype = it_find(name); + if (lux && itype && lux!=itype) { + r_setdemand(r, lux->rtype->ltype, 1); + r_setdemand(r, itype->rtype->ltype, 0); + } + } + return 0; +} + +static int tolua_region_set_herb(lua_State* L) +{ + region* r = (region*)tolua_tousertype(L, 1, 0); + if (r->land) { + const char * name = tolua_tostring(L, 2, 0); + const item_type * itype = it_find(name); + if (itype && (itype->flags&ITF_HERB)) { + r->land->herbtype = itype; + } + } + return 0; +} + +static int tolua_region_get_herb(lua_State* L) +{ + region* r = (region*)tolua_tousertype(L, 1, 0); + if (r->land && r->land->herbtype) { + const char * name = r->land->herbtype->rtype->_name[0]; + tolua_pushstring(L, name); + return 1; + } + return 0; +} + +static int tolua_region_get_next(lua_State* L) +{ + region* self = (region*)tolua_tousertype(L, 1, 0); + direction_t dir = (direction_t)tolua_tonumber(L, 2, 0); + + if (dir>=0 && dirflags |= (1<flags &= ~(1<resources;rm;rm=rm->next) { + if (rm->type->rtype==rtype) { + tolua_pushnumber(L, (lua_Number)rm->level); + return 1; + } + } + } + return 0; +} + +#define LUA_ASSERT(c, s) if (!(c)) { log_error(("%s(%d): %s\n", __FILE__, __LINE__, (s))); return 0; } +static int +tolua_region_get_resource(lua_State* L) +{ + region * r; + const char * type; + const resource_type * rtype; + int result = 0; + + r = (region *)tolua_tousertype(L, 1, 0); + LUA_ASSERT(r!=NULL, "invalid parameter"); + type = tolua_tostring(L, 2, 0); + LUA_ASSERT(type!=NULL, "invalid parameter"); + rtype = rt_find(type); + + if (!rtype) { + if (strcmp(type, "seed")==0) result = rtrees(r, 0); + if (strcmp(type, "sapling")==0) result = rtrees(r, 1); + if (strcmp(type, "tree")==0) result = rtrees(r, 2); + if (strcmp(type, "grave")==0) result = deathcount(r); + if (strcmp(type, "chaos")==0) result = chaoscount(r); + } else { + result = region_getresource(r, rtype); + } + + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_region_set_resource(lua_State* L) +{ + region * r = (region *)tolua_tousertype(L, 1, 0); + const char * type = tolua_tostring(L, 2, 0); + int value = (int)tolua_tonumber(L, 3, 0); + const resource_type * rtype = rt_find(type); + + if (rtype!=NULL) { + region_setresource(r, rtype, value); + } else { + if (strcmp(type, "seed")==0) { + rsettrees(r, 0, value); + } else if (strcmp(type, "sapling")==0) { + rsettrees(r, 1, value); + } else if (strcmp(type, "tree")==0) { + rsettrees(r, 2, value); + } else if (strcmp(type, "grave")==0) { + int fallen = value-deathcount(r); + deathcounts(r, fallen); + } else if (strcmp(type, "chaos")==0) { + int fallen = value-chaoscount(r); + chaoscounts(r, fallen); + } + } + return 0; +} + +static int +tolua_region_get_objects(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); + return 1; +} + +static int +tolua_region_destroy(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + remove_region(®ions, self); + return 0; +} + +static int +tolua_region_create(lua_State* L) +{ + int x = (int)tolua_tonumber(L, 1, 0); + int y = (int)tolua_tonumber(L, 2, 0); + const char * tname = tolua_tostring(L, 3, 0); + if (tname) { + plane * pl = findplane(x, y); + const terrain_type * terrain = get_terrain(tname); + region * r, * result; + if (!terrain) { + return 0; + } + + assert(!pnormalize(&x, &y, pl)); + r = result = findregion(x, y); + + if (terrain==NULL && r!=NULL && r->units!=NULL) { + /* TODO: error message */ + result = NULL; + } else if (r==NULL) { + result = new_region(x, y, pl, 0); + } + if (result) { + terraform_region(result, terrain); + } + fix_demand(result); + + tolua_pushusertype(L, result, TOLUA_CAST "region"); + return 1; + } + return 0; +} + +static int tolua_region_get_units(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); + + luaL_getmetatable(L, "unit"); + lua_setmetatable(L, -2); + + *unit_ptr = self->units; + + lua_pushcclosure(L, tolua_unitlist_next, 1); + return 1; +} + +static int tolua_region_get_buildings(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + building ** building_ptr = (building**)lua_newuserdata(L, sizeof(building *)); + + luaL_getmetatable(L, "building"); + lua_setmetatable(L, -2); + + *building_ptr = self->buildings; + + lua_pushcclosure(L, tolua_buildinglist_next, 1); + return 1; +} + +static int tolua_region_get_ships(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + ship ** ship_ptr = (ship**)lua_newuserdata(L, sizeof(ship *)); + + luaL_getmetatable(L, "ship"); + lua_setmetatable(L, -2); + + *ship_ptr = self->ships; + + lua_pushcclosure(L, tolua_shiplist_next, 1); + return 1; +} + +static int tolua_region_get_age(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + + if (self) { + lua_pushnumber(L, self->age); + return 1; + } + return 0; +} + +static int +tolua_region_getkey(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + + int flag = atoi36(name); + attrib * a = find_key(self->attribs, flag); + lua_pushboolean(L, a!=NULL); + + return 1; +} + +static int +tolua_region_setkey(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + int value = tolua_toboolean(L, 3, 0); + + int flag = atoi36(name); + attrib * a = find_key(self->attribs, flag); + if (a==NULL && value) { + add_key(&self->attribs, flag); + } else if (a!=NULL && !value) { + a_remove(&self->attribs, a); + } + return 0; +} + +static int +tolua_region_tostring(lua_State *L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, regionname(self, NULL)); + return 1; +} + +static int +tolua_plane_get(lua_State* L) +{ + int id = (int)tolua_tonumber(L, 1, 0); + plane * pl = getplanebyid(id); + + tolua_pushusertype(L, pl, TOLUA_CAST "plane"); + return 1; +} + +static int +tolua_plane_create(lua_State* L) +{ + int id = (int)tolua_tonumber(L, 1, 0); + int x = (int)tolua_tonumber(L, 2, 0); + int y = (int)tolua_tonumber(L, 3, 0); + int width = (int)tolua_tonumber(L, 4, 0); + int height = (int)tolua_tonumber(L, 5, 0); + const char * name = tolua_tostring(L, 6, 0); + plane * pl; + + pl = create_new_plane(id, name, x, x+width-1, y, y+height-1, 0); + + tolua_pushusertype(L, pl, TOLUA_CAST "plane"); + return 1; +} + +static int tolua_plane_get_name(lua_State* L) +{ + plane* self = (plane*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->name); + return 1; +} + +static int tolua_plane_set_name(lua_State* L) +{ + plane* self = (plane*)tolua_tousertype(L, 1, 0); + const char * str = tolua_tostring(L, 2, 0); + free(self->name); + if (str) self->name = strdup(str); + else self->name = 0; + return 0; +} + +static int +tolua_plane_get_id(lua_State* L) +{ + plane * self = (plane *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->id); + return 1; +} + +static int +tolua_plane_normalize(lua_State* L) +{ + plane * self = (plane *)tolua_tousertype(L, 1, 0); + int x = (int)tolua_tonumber(L, 2, 0); + int y = (int)tolua_tonumber(L, 3, 0); + pnormalize(&x, &y, self); + tolua_pushnumber(L, (lua_Number)x); + tolua_pushnumber(L, (lua_Number)y); + return 2; +} + +static int +tolua_plane_tostring(lua_State *L) +{ + plane * self = (plane *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, self->name); + return 1; +} + +static int +tolua_plane_get_size(lua_State *L) +{ + plane * pl = (plane *)tolua_tousertype(L, 1, 0); + lua_pushnumber(L, plane_width(pl)); + lua_pushnumber(L, plane_height(pl)); + return 2; +} + +static int +tolua_distance(lua_State *L) +{ + int x1 = (int)tolua_tonumber(L, 1, 0); + int y1 = (int)tolua_tonumber(L, 2, 0); + int x2 = (int)tolua_tonumber(L, 3, 0); + int y2 = (int)tolua_tonumber(L, 4, 0); + plane * pl = (plane *)tolua_tousertype(L, 5, 0); + int result; + + if (!pl) pl = get_homeplane(); + pnormalize(&x1, &y1, pl); + pnormalize(&x2, &y2, pl); + result = koor_distance(x1, y1, x2, y2); + lua_pushnumber(L, result); + return 1; +} + +void +tolua_region_open(lua_State* L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "region"); + tolua_usertype(L, TOLUA_CAST "plane"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_function(L, TOLUA_CAST "distance", tolua_distance); + + tolua_cclass(L, TOLUA_CAST "region", TOLUA_CAST "region", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "region"); + { + tolua_function(L, TOLUA_CAST "create", tolua_region_create); + tolua_function(L, TOLUA_CAST "destroy", tolua_region_destroy); + tolua_function(L, TOLUA_CAST "__tostring", tolua_region_tostring); + + tolua_variable(L, TOLUA_CAST "id", tolua_region_get_id, NULL); + tolua_variable(L, TOLUA_CAST "x", tolua_region_get_x, NULL); + tolua_variable(L, TOLUA_CAST "y", tolua_region_get_y, NULL); + tolua_variable(L, TOLUA_CAST "plane", tolua_region_get_plane, NULL); + tolua_variable(L, TOLUA_CAST "name", tolua_region_get_name, tolua_region_set_name); + tolua_variable(L, TOLUA_CAST "morale", tolua_region_get_morale, tolua_region_set_morale); + tolua_variable(L, TOLUA_CAST "info", tolua_region_get_info, tolua_region_set_info); + tolua_variable(L, TOLUA_CAST "units", tolua_region_get_units, NULL); + tolua_variable(L, TOLUA_CAST "ships", tolua_region_get_ships, NULL); + tolua_variable(L, TOLUA_CAST "age", tolua_region_get_age, NULL); + tolua_variable(L, TOLUA_CAST "buildings", tolua_region_get_buildings, NULL); + tolua_variable(L, TOLUA_CAST "terrain", tolua_region_get_terrain, tolua_region_set_terrain); + tolua_function(L, TOLUA_CAST "get_resourcelevel", tolua_region_get_resourcelevel); + tolua_function(L, TOLUA_CAST "get_resource", tolua_region_get_resource); + tolua_function(L, TOLUA_CAST "set_resource", tolua_region_set_resource); + tolua_function(L, TOLUA_CAST "get_flag", tolua_region_get_flag); + tolua_function(L, TOLUA_CAST "set_flag", tolua_region_set_flag); + tolua_function(L, TOLUA_CAST "next", tolua_region_get_next); + tolua_variable(L, TOLUA_CAST "adj", tolua_region_get_adj, NULL); + + tolua_variable(L, TOLUA_CAST "luxury", &tolua_region_get_luxury, &tolua_region_set_luxury); + tolua_variable(L, TOLUA_CAST "herb", &tolua_region_get_herb, &tolua_region_set_herb); + + tolua_variable(L, TOLUA_CAST "terrain_name", &tolua_region_get_terrainname, &tolua_region_set_terrainname); + tolua_variable(L, TOLUA_CAST "owner", &tolua_region_get_owner, &tolua_region_set_owner); + + tolua_function(L, TOLUA_CAST "get_key", tolua_region_getkey); + tolua_function(L, TOLUA_CAST "set_key", tolua_region_setkey); +#if 0 + .def("add_notice", ®ion_addnotice) + .def("add_direction", ®ion_adddirection) + .def("move", ®ion_move) + .def("get_road", ®ion_getroad) + .def("set_road", ®ion_setroad) + .def("next", ®ion_next) + .def("add_item", ®ion_additem) + .property("items", ®ion_items, return_stl_iterator) + .property("plane_id", ®ion_plane) +#endif + tolua_variable(L, TOLUA_CAST "objects", tolua_region_get_objects, 0); + } + tolua_endmodule(L); + + tolua_cclass(L, TOLUA_CAST "plane", TOLUA_CAST "plane", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "plane"); + { + tolua_function(L, TOLUA_CAST "create", tolua_plane_create); + tolua_function(L, TOLUA_CAST "get", tolua_plane_get); + tolua_function(L, TOLUA_CAST "__tostring", tolua_plane_tostring); + + tolua_function(L, TOLUA_CAST "size", tolua_plane_get_size); + tolua_variable(L, TOLUA_CAST "id", tolua_plane_get_id, NULL); + tolua_function(L, TOLUA_CAST "normalize", tolua_plane_normalize); + tolua_variable(L, TOLUA_CAST "name", tolua_plane_get_name, tolua_plane_set_name); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_region.h b/src/bindings/bind_region.h new file mode 100644 index 000000000..f8d0c8e2a --- /dev/null +++ b/src/bindings/bind_region.h @@ -0,0 +1,23 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + void tolua_region_open(struct lua_State *L); + int tolua_regionlist_next(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_ship.c b/src/bindings/bind_ship.c new file mode 100644 index 000000000..b5a0e90a3 --- /dev/null +++ b/src/bindings/bind_ship.c @@ -0,0 +1,182 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bind_ship.h" +#include "bind_unit.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include + +int tolua_shiplist_next(lua_State *L) +{ + ship** ship_ptr = (ship **)lua_touserdata(L, lua_upvalueindex(1)); + ship * u = *ship_ptr; + if (u != NULL) { + tolua_pushusertype(L, (void*)u, TOLUA_CAST "ship"); + *ship_ptr = u->next; + return 1; + } + else return 0; /* no more values to return */ +} + +static int +tolua_ship_get_id(lua_State* L) +{ + ship * self = (ship *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->no); + return 1; +} + +static int tolua_ship_get_name(lua_State* L) +{ + ship* self = (ship*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, ship_getname(self)); + return 1; +} + +static int tolua_ship_get_region(lua_State* L) +{ + ship* self = (ship*) tolua_tousertype(L, 1, 0); + if (self) { + tolua_pushusertype(L, self->region, TOLUA_CAST "region"); + return 1; + } + return 0; +} + +static int tolua_ship_set_region(lua_State* L) +{ + ship* self = (ship*) tolua_tousertype(L, 1, 0); + region * r = (region*) tolua_tousertype(L, 1, 0); + if (self) { + move_ship(self, self->region, r, NULL); + } + return 0; +} + +static int tolua_ship_set_name(lua_State* L) +{ + ship* self = (ship*)tolua_tousertype(L, 1, 0); + ship_setname(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int +tolua_ship_get_units(lua_State* L) +{ + ship * self = (ship *)tolua_tousertype(L, 1, 0); + unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); + unit * u = self->region->units; + + while (u && u->ship!=self) u = u->next; + luaL_getmetatable(L, TOLUA_CAST "unit"); + lua_setmetatable(L, -2); + + *unit_ptr = u; + + lua_pushcclosure(L, tolua_unitlist_nexts, 1); + return 1; +} + +static int +tolua_ship_get_objects(lua_State* L) +{ + ship * self = (ship *)tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); + return 1; +} + +static int +tolua_ship_create(lua_State* L) +{ + region * r = (region *)tolua_tousertype(L, 1, 0); + const char * sname = tolua_tostring(L, 2, 0); + if (sname) { + const ship_type * stype = st_find(sname); + if (stype) { + ship * sh = new_ship(stype, default_locale, r); + sh->size = stype->construction->maxsize; + tolua_pushusertype(L, (void*)sh, TOLUA_CAST "ship"); + return 1; + } + } + return 0; +} + +static int + +tolua_ship_tostring(lua_State *L) +{ + ship * self = (ship *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, shipname(self)); + return 1; +} + +static int tolua_ship_get_flags(lua_State* L) +{ + ship* self = (ship*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->flags); + return 1; +} + +static int tolua_ship_set_flags(lua_State* L) +{ + ship* self = (ship*)tolua_tousertype(L, 1, 0); + self->flags = (int)tolua_tonumber(L, 2, 0); + return 0; +} + + +void +tolua_ship_open(lua_State* L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "ship"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, TOLUA_CAST "ship", TOLUA_CAST "ship", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "ship"); + { + tolua_function(L, TOLUA_CAST "__tostring", tolua_ship_tostring); + tolua_variable(L, TOLUA_CAST "id", tolua_ship_get_id, NULL); + tolua_variable(L, TOLUA_CAST "name", tolua_ship_get_name, tolua_ship_set_name); + tolua_variable(L, TOLUA_CAST "units", tolua_ship_get_units, NULL); + tolua_variable(L, TOLUA_CAST "flags", &tolua_ship_get_flags, tolua_ship_set_flags); + tolua_variable(L, TOLUA_CAST "region", tolua_ship_get_region, tolua_ship_set_region); +#ifdef TODO + .property("type", &ship_gettype) + .property("weight", &ship_getweight) + .property("capacity", &ship_getcapacity) + .property("maxsize", &ship_maxsize) + .def_readwrite("damage", &ship::damage) + .def_readwrite("size", &ship::size) + .def_readwrite("coast", &ship::coast) +#endif + tolua_variable(L, TOLUA_CAST "objects", tolua_ship_get_objects, 0); + + tolua_function(L, TOLUA_CAST "create", tolua_ship_create); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_ship.h b/src/bindings/bind_ship.h new file mode 100644 index 000000000..7c9426fce --- /dev/null +++ b/src/bindings/bind_ship.h @@ -0,0 +1,23 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + int tolua_shiplist_next(struct lua_State *L); + void tolua_ship_open(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_sqlite.c b/src/bindings/bind_sqlite.c new file mode 100644 index 000000000..ce7f1aed4 --- /dev/null +++ b/src/bindings/bind_sqlite.c @@ -0,0 +1,100 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include + +#include "bind_unit.h" +#include "bindings.h" + +#include +#include +#include + +#define LTYPE_DB TOLUA_CAST "db" + +extern int db_update_factions(sqlite3 * db, boolean force); +static int +tolua_db_update_factions(lua_State* L) +{ + sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); + db_update_factions(db, tolua_toboolean(L, 2, 0)); + return 0; +} + +extern int db_update_scores(sqlite3 * db, boolean force); +static int +tolua_db_update_scores(lua_State* L) +{ + sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); + db_update_scores(db, tolua_toboolean(L, 2, 0)); + return 0; +} + +static int +tolua_db_execute(lua_State* L) +{ + sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); + const char * sql = tolua_tostring(L, 2, 0); + + int res = sqlite3_exec(db, sql, 0, 0, 0); + + tolua_pushnumber(L, (LUA_NUMBER)res); + return 1; +} + +static int +tolua_db_close(lua_State* L) +{ + sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); + sqlite3_close(db); + return 0; +} + +static int +tolua_db_create(lua_State* L) +{ + sqlite3 * db; + const char * dbname = tolua_tostring(L, 1, 0); + int result = sqlite3_open_v2(dbname, &db, SQLITE_OPEN_READWRITE, 0); + if (result==SQLITE_OK) { + tolua_pushusertype(L, (void*)db, LTYPE_DB); + return 1; + } + return 0; +} + +int +tolua_sqlite_open(lua_State * L) +{ + /* register user types */ + + tolua_usertype(L, LTYPE_DB); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, LTYPE_DB, LTYPE_DB, TOLUA_CAST "", NULL); + tolua_beginmodule(L, LTYPE_DB); + { + tolua_function(L, TOLUA_CAST "open", &tolua_db_create); + tolua_function(L, TOLUA_CAST "close", &tolua_db_close); + + tolua_function(L, TOLUA_CAST "update_factions", &tolua_db_update_factions); + tolua_function(L, TOLUA_CAST "update_scores", &tolua_db_update_scores); + tolua_function(L, TOLUA_CAST "execute", &tolua_db_execute); + } + tolua_endmodule(L); + + } + tolua_endmodule(L); + return 0; +} diff --git a/src/bindings/bind_storage.c b/src/bindings/bind_storage.c new file mode 100644 index 000000000..23b9a0a5a --- /dev/null +++ b/src/bindings/bind_storage.c @@ -0,0 +1,144 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "bind_storage.h" + +#include +#include +#include +#include + +#include + +#include +#include + + +static int +tolua_storage_create(lua_State* L) +{ + const char * filename = tolua_tostring(L, 1, 0); + const char * type = tolua_tostring(L, 2, "rb"); + storage * store = 0; + int mode = IO_READ; + if (strchr(type, 't')) { + store = malloc(sizeof(text_store)); + memcpy(store, &text_store, sizeof(text_store)); + } else { + store = malloc(sizeof(binary_store)); + memcpy(store, &binary_store, sizeof(binary_store)); + } + if (strchr(type, 'r')) mode = IO_READ; + if (strchr(type, 'w')) mode = IO_WRITE; + store->open(store, filename, mode); + tolua_pushusertype(L, (void*)store, TOLUA_CAST "storage"); + return 1; +} + +static int +tolua_storage_read_unit(lua_State *L) +{ + storage * self = (storage *)tolua_tousertype(L, 1, 0); + struct unit * u = read_unit(self); + tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); + return 1; +} + +static int +tolua_storage_write_unit(lua_State *L) +{ + storage * self = (storage *)tolua_tousertype(L, 1, 0); + struct unit * u = (struct unit *)tolua_tousertype(L, 2, 0); + write_unit(self, u); + return 0; +} + + +static int +tolua_storage_read_float(lua_State *L) +{ + storage * self = (storage *)tolua_tousertype(L, 1, 0); + float num = self->r_flt(self); + tolua_pushnumber(L, (lua_Number)num); + return 1; +} + +static int +tolua_storage_read_int(lua_State *L) +{ + storage * self = (storage *)tolua_tousertype(L, 1, 0); + int num = self->r_int(self); + tolua_pushnumber(L, (lua_Number)num); + return 1; +} + +static int +tolua_storage_write(lua_State *L) +{ + storage * self = (storage *)tolua_tousertype(L, 1, 0); + if (tolua_isnumber(L, 2, 0, 0)) { + lua_Number num = tolua_tonumber(L, 2, 0); + double n; + if (modf(num, &n)==0.0) { + self->w_int(self, (int)num); + } else { + self->w_flt(self, (float)num); + } + } + return 0; +} + +static int +tolua_storage_tostring(lua_State *L) +{ + storage * self = (storage *)tolua_tousertype(L, 1, 0); + char name[64]; + snprintf(name, sizeof(name), "", self->encoding, self->version); + lua_pushstring(L, name); + return 1; +} + +static int +tolua_storage_close(lua_State *L) +{ + storage * self = (storage *)tolua_tousertype(L, 1, 0); + self->close(self); + return 0; +} + +void +tolua_storage_open(lua_State* L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "storage"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, TOLUA_CAST "storage", TOLUA_CAST "storage", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "storage"); + { + tolua_function(L, TOLUA_CAST "__tostring", tolua_storage_tostring); + tolua_function(L, TOLUA_CAST "write", tolua_storage_write); + tolua_function(L, TOLUA_CAST "read_int", tolua_storage_read_int); + tolua_function(L, TOLUA_CAST "read_float", tolua_storage_read_float); + tolua_function(L, TOLUA_CAST "write_unit", tolua_storage_write_unit); + tolua_function(L, TOLUA_CAST "read_unit", tolua_storage_read_unit); + tolua_function(L, TOLUA_CAST "close", tolua_storage_close); + tolua_function(L, TOLUA_CAST "create", tolua_storage_create); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_storage.h b/src/bindings/bind_storage.h new file mode 100644 index 000000000..fd79c7ca8 --- /dev/null +++ b/src/bindings/bind_storage.h @@ -0,0 +1,22 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + void tolua_storage_open(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c new file mode 100644 index 000000000..9de137d90 --- /dev/null +++ b/src/bindings/bind_unit.c @@ -0,0 +1,1026 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include + +#include "bind_unit.h" +#include "bind_attrib.h" +#include "bindings.h" + +// attributes includes +#include +#include + +// kernel includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// util includes +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +static int +tolua_unit_get_objects(lua_State* L) +{ + unit * self = (unit *)tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); + return 1; +} + + +static int +tolua_unit_get_attribs(lua_State* L) +{ + unit * self = (unit *)tolua_tousertype(L, 1, 0); + attrib ** attrib_ptr = (attrib**)lua_newuserdata(L, sizeof(attrib *)); + attrib * a = tolua_get_lua_ext(self->attribs); + + luaL_getmetatable(L, "attrib"); + lua_setmetatable(L, -2); + + *attrib_ptr = a; + + lua_pushcclosure(L, tolua_attriblist_next, 1); + return 1; +} + +int tolua_unitlist_nextf(lua_State *L) +{ + unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); + unit * u = *unit_ptr; + if (u != NULL) { + tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); + *unit_ptr = u->nextF; + return 1; + } + else return 0; /* no more values to return */ +} + +int tolua_unitlist_nextb(lua_State *L) +{ + unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); + unit * u = *unit_ptr; + if (u != NULL) { + unit * unext = u->next; + tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); + + while (unext && unext->building!=u->building) { + unext = unext->next; + } + *unit_ptr = unext; + + return 1; + } + else return 0; /* no more values to return */ +} + +int tolua_unitlist_nexts(lua_State *L) +{ + unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); + unit * u = *unit_ptr; + if (u != NULL) { + unit * unext = u->next; + tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); + + while (unext && unext->ship!=u->ship) { + unext = unext->next; + } + *unit_ptr = unext; + + return 1; + } + else return 0; /* no more values to return */ +} + +int tolua_unitlist_next(lua_State *L) +{ + unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); + unit * u = *unit_ptr; + if (u != NULL) { + tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); + *unit_ptr = u->next; + return 1; + } + else return 0; /* no more values to return */ +} + + +static int tolua_unit_get_name(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->name); + return 1; +} + +static int tolua_unit_set_name(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit_setname(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int tolua_unit_get_info(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, unit_getinfo(self)); + return 1; +} + +static int tolua_unit_set_info(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit_setinfo(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int tolua_unit_get_id(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)unit_getid(self)); + return 1; +} + +static int tolua_unit_set_id(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit_setid(self, (int)tolua_tonumber(L, 2, 0)); + return 0; +} + +static int tolua_unit_get_hpmax(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)unit_max_hp(self)); + return 1; +} + +static int tolua_unit_get_hp(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)unit_gethp(self)); + return 1; +} + +static int tolua_unit_set_hp(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit_sethp(self, (int)tolua_tonumber(L, 2, 0)); + return 0; +} + +static int tolua_unit_get_number(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->number); + return 1; +} + +static int tolua_unit_set_number(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + int number = (int)tolua_tonumber(L, 2, 0); + if (self->number==0) { + set_number(self, number); + self->hp = unit_max_hp(self) * number; + } else { + scale_number(self, number); + } + return 0; +} + +static int tolua_unit_get_flags(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->flags); + return 1; +} + +static int tolua_unit_set_flags(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + self->flags = (int)tolua_tonumber(L, 2, 0); + return 0; +} + +static const char * +unit_getmagic(const unit * u) +{ + sc_mage * mage = get_mage(u); + return mage?magic_school[mage->magietyp]:NULL; +} + +static int tolua_unit_get_magic(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + lua_pushstring(L, unit_getmagic(self)); + return 1; +} + +static void +unit_setmagic(unit * u, const char * type) +{ + sc_mage * mage = get_mage(u); + magic_t mtype; + for (mtype=0;mtype!=MAXMAGIETYP;++mtype) { + if (strcmp(magic_school[mtype], type)==0) break; + } + if (mtype==MAXMAGIETYP) return; + if (mage==NULL) { + mage = create_mage(u, mtype); + } +} + +static int tolua_unit_set_magic(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * type = tolua_tostring(L, 2, 0); + unit_setmagic(self, type); + return 0; +} + +static int tolua_unit_get_aura(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)get_spellpoints(self)); + return 1; +} + +static int tolua_unit_set_aura(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + set_spellpoints(self, (int)tolua_tonumber(L, 2, 0)); + return 0; +} + +static int tolua_unit_get_age(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->age); + return 1; +} + +static int tolua_unit_set_age(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + self->age = (short)tolua_tonumber(L, 2, 0); + return 0; +} + +static int tolua_unit_get_status(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)unit_getstatus(self)); + return 1; +} + +static int tolua_unit_set_status(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit_setstatus(self, (status_t)tolua_tonumber(L, 2, 0)); + return 0; +} + +static int +tolua_unit_get_item(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * iname = tolua_tostring(L, 2, 0); + int result = -1; + + if (iname!=NULL) { + const item_type * itype = it_find(iname); + if (itype!=NULL) { + result = i_get(self->items, itype); + } + } + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_unit_add_item(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * iname = tolua_tostring(L, 2, 0); + int number = (int)tolua_tonumber(L, 3, 0); + int result = -1; + + if (iname!=NULL) { + const item_type * itype = it_find(iname); + if (itype!=NULL) { + item * i = i_change(&self->items, itype, number); + result = i?i->number:0; + } + } + lua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_unit_getskill(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * skname = tolua_tostring(L, 2, 0); + skill_t sk = sk_find(skname); + int value = -1; + if (sk!=NOSKILL) { + skill * sv = get_skill(self, sk); + if (sv) { + value = sv->level; + } + else value = 0; + } + lua_pushnumber(L, (lua_Number)value); + return 1; +} + +static int +tolua_unit_effskill(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * skname = tolua_tostring(L, 2, 0); + skill_t sk = sk_find(skname); + int value = (sk==NOSKILL)?-1:eff_skill(self, sk, self->region); + lua_pushnumber(L, (lua_Number)value); + return 1; +} + +typedef struct fctr_data { + unit * target; + int fhandle; +} fctr_data; + +typedef struct event { + struct event_arg * args; + char * msg; +} event; + +int +fctr_handle(struct trigger * tp, void * data) +{ + trigger * t = tp; + event evt = { 0 }; + fctr_data * fd = (fctr_data*)t->data.v; + lua_State * L = (lua_State *)global.vm_state; + unit * u = fd->target; + + evt.args = (event_arg*)data; + lua_rawgeti(L, LUA_REGISTRYINDEX, fd->fhandle); + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + tolua_pushusertype(L, &evt, TOLUA_CAST "event"); + if (lua_pcall(L, 2, 0, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("event (%s): %s\n", unitname(u), error)); + lua_pop(L, 1); + tolua_error(L, TOLUA_CAST "event handler call failed", NULL); + } + + return 0; +} + +static void +fctr_init(trigger * t) +{ + t->data.v = calloc(sizeof(fctr_data), 1); +} + +static void +fctr_done(trigger * t) +{ + fctr_data * fd = (fctr_data*)t->data.v; + lua_State * L = (lua_State *)global.vm_state; + luaL_unref(L, LUA_REGISTRYINDEX, fd->fhandle); + free(fd); +} + +static struct trigger_type tt_lua = { + "lua_event", + fctr_init, + fctr_done, + fctr_handle +}; + +static trigger * +trigger_lua(struct unit * u, int handle) +{ + trigger * t = t_new(&tt_lua); + fctr_data * td = (fctr_data*)t->data.v; + td->target = u; + td->fhandle = handle; + return t; +} + +static int +tolua_unit_addhandler(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * ename = tolua_tostring(L, 2, 0); + int handle; + + lua_pushvalue(L, 3); + handle = luaL_ref(L, LUA_REGISTRYINDEX); + add_trigger(&self->attribs, ename, trigger_lua(self, handle)); + + return 0; +} + +static int +tolua_unit_addnotice(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * str = tolua_tostring(L, 2, 0); + + addmessage(self->region, self->faction, str, MSG_MESSAGE, ML_IMPORTANT); + return 0; +} + +static void +unit_castspell(unit * u, const char * name) +{ + spell_list * slist = spells; + while (slist!=NULL) { + spell * sp = slist->data; + if (strcmp(name, sp->sname)==0) { + castorder * co = (castorder*)malloc(sizeof(castorder)); + co->distance = 0; + co->familiar = NULL; + co->force = sp->level; + co->level = sp->level; + co->magician.u = u; + co->order = NULL; + co->par = NULL; + co->rt = u->region; + co->sp = sp; + if (sp->sp_function==NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + co->level = 0; + } else { + sp->sp_function(co); + } + free(co); + } + slist=slist->next; + } +} + +static int +tolua_unit_castspell(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * str = tolua_tostring(L, 2, 0); + unit_castspell(self, str); + return 0; +} + +static void +unit_addspell(unit * u, const char * name) +{ + int add = 0; + sc_mage * m = get_mage(u); + spell_list * slist = spells; + spell_list ** starget = NULL; + spell * spadd = NULL; + while (slist!=NULL) { + spell * sp = slist->data; + if (strcmp(name, sp->sname)==0) { + starget = get_spelllist(m, u->faction); + if (m->magietyp==sp->magietyp) spadd = sp; + else if (!spadd) spadd = sp; + add = 1; + } + slist=slist->next; + } + if (!spadd) log_error(("spell %s could not be found\n", name)); + else add_spell(starget, spadd); +} + +static int +tolua_unit_addspell(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * str = tolua_tostring(L, 2, 0); + unit_addspell(self, str); + return 0; +} + +static void +unit_removespell(unit * u, const spell * sp) +{ + spell_list ** isptr; + isptr = get_spelllist(get_mage(u), u->faction); + + while (*isptr && (*isptr)->data != sp) { + isptr = &(*isptr)->next; + } + if (*isptr) { + spell_list * sptr = *isptr; + *isptr = sptr->next; + free(sptr); + } +} + +static int +tolua_unit_removespell(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + spell * sp = (spell*)tolua_tousertype(L, 2, 0); + unit_removespell(self, sp); + return 0; +} + +static int +tolua_unit_set_racename(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * str = tolua_tostring(L, 2, 0); + + set_racename(&self->attribs, str); + return 0; +} + +static int +tolua_unit_get_racename(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + attrib * a = a_find(self->attribs, &at_racename); + if (a) { + tolua_pushstring(L, get_racename(a)); + return 1; + } + return 0; +} + +static int +tolua_unit_setskill(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * skname = tolua_tostring(L, 2, 0); + int level = (int)tolua_tonumber(L, 3, 0); + skill_t sk = sk_find(skname); + if (sk!=NOSKILL) { + set_level(self, sk, level); + } else { + level = -1; + } + lua_pushnumber(L, (lua_Number)level); + return 1; +} + +static int +tolua_unit_use_pooled(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * iname = tolua_tostring(L, 2, 0); + int number = (int)tolua_tonumber(L, 3, 0); + const resource_type * rtype = rt_find(iname); + int result = -1; + if (rtype!=NULL) { + result = use_pooled(self, rtype, GET_DEFAULT, number); + } + lua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_unit_get_pooled(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * iname = tolua_tostring(L, 2, 0); + const resource_type * rtype = rt_find(iname); + int result = -1; + if (rtype!=NULL) { + result = get_pooled(self, rtype, GET_DEFAULT, INT_MAX); + } + lua_pushnumber(L, (lua_Number)result); + return 1; +} + +static unit * +unit_getfamiliar(const unit * u) +{ + attrib * a = a_find(u->attribs, &at_familiar); + if (a!=NULL) { + return (unit*)a->data.v; + } + return NULL; +} + +static int tolua_unit_get_familiar(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, unit_getfamiliar(self), TOLUA_CAST "unit"); + return 1; +} + +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)); + return 0; +} + +static int tolua_unit_get_building(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, self->building, TOLUA_CAST "building"); + return 1; +} + +static void +unit_setbuilding(unit * u, building * b) +{ + leave(u, true); + if (b && u->region!=b->region) { + move_unit(u, b->region, NULL); + } + u->building = b; +} + +static int tolua_unit_set_building(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + if (self->faction) { + unit_setbuilding(self, (building *)tolua_tousertype(L, 2, 0)); + } + return 0; +} + +static int tolua_unit_get_ship(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, self->ship, TOLUA_CAST "ship"); + return 1; +} + +static void +unit_setship(unit * u, ship * s) +{ + leave(u, true); + if (s && u->region!=s->region) { + move_unit(u, s->region, NULL); + } + u->ship = s; +} + +static int tolua_unit_set_ship(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + if (self->faction) { + unit_setship(self, (ship *)tolua_tousertype(L, 2, 0)); + } + return 0; +} + +static int tolua_unit_get_region(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, self->region, TOLUA_CAST "region"); + return 1; +} + +static void +unit_setregion(unit * u, region * r) +{ + move_unit(u, r, NULL); +} + +static int tolua_unit_set_region(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit_setregion(self, (region *)tolua_tousertype(L, 2, 0)); + return 0; +} + +static int tolua_unit_add_order(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * str = tolua_tostring(L, 2, 0); + order * ord = parse_order(str, self->faction->locale); + unit_addorder(self, ord); + return 0; +} + +static int tolua_unit_clear_orders(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + free_orders(&self->orders); + return 0; +} + +static int tolua_unit_get_items(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + + item ** item_ptr = (item **)lua_newuserdata(L, sizeof(item *)); + + luaL_getmetatable(L, TOLUA_CAST "item"); + lua_setmetatable(L, -2); + + *item_ptr = self->items; + + lua_pushcclosure(L, tolua_itemlist_next, 1); + + return 1; +} + +static int tolua_unit_get_spells(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + sc_mage * mage = get_mage(self); + + if (mage) { + spell_list ** slist = get_spelllist(mage, self->faction); + assert(slist); + if (slist) { + spell_list ** spell_ptr = (spell_list **)lua_newuserdata(L, sizeof(spell_list *)); + luaL_getmetatable(L, TOLUA_CAST "spell_list"); + lua_setmetatable(L, -2); + + *spell_ptr = *slist; + lua_pushcclosure(L, tolua_spelllist_next, 1); + return 1; + } + } + + lua_pushnil(L); + return 1; +} + +static int tolua_unit_get_orders(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + + order ** order_ptr = (order **)lua_newuserdata(L, sizeof(order *)); + + luaL_getmetatable(L, TOLUA_CAST "order"); + lua_setmetatable(L, -2); + + *order_ptr = self->orders; + + lua_pushcclosure(L, tolua_orderlist_next, 1); + + return 1; +} + +static int tolua_unit_get_flag(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + int flag = atoi36(name); + attrib * a = find_key(self->attribs, flag); + lua_pushboolean(L, (a!=NULL)); + return 1; +} + +static int tolua_unit_set_flag(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + int value = (int)tolua_tonumber(L, 3, 0); + int flag = atoi36(name); + attrib * a = find_key(self->attribs, flag); + if (a==NULL && value) { + add_key(&self->attribs, flag); + } else if (a!=NULL && !value) { + a_remove(&self->attribs, a); + } + return 0; +} + +static int tolua_unit_get_weight(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)unit_getweight(self)); + return 1; +} + +static int tolua_unit_get_capacity(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)unit_getcapacity(self)); + return 1; +} + +static int tolua_unit_get_faction(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, (void*)self->faction, TOLUA_CAST "faction"); + return 1; +} + +static int tolua_unit_set_faction(lua_State* L) +{ + unit * self = (unit*) tolua_tousertype(L, 1, 0); + faction * f = (faction *)tolua_tousertype(L, 2, 0); + u_setfaction(self, f); + return 0; +} + +static int tolua_unit_get_race(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->race->_name[0]); + return 1; +} + +static int tolua_unit_set_race(lua_State* L) +{ + unit * self = (unit*) tolua_tousertype(L, 1, 0); + const char * rcname = tolua_tostring(L, 2, 0); + race * rc = rc_find(rcname); + if (rc!=NULL) { + if (count_unit(self)) --self->faction->no_units; + if (self->irace==self->race) self->irace = NULL; + self->race = rc; + if (count_unit(self)) --self->faction->no_units; + } + return 0; +} + +static int +tolua_unit_destroy(lua_State* L) +{ + unit * self = (unit *)tolua_tousertype(L, 1, 0); + if (self) { + remove_unit(&self->region->units, self); + } + return 0; +} + +static int +tolua_unit_create(lua_State* L) +{ + faction * f = (faction *)tolua_tousertype(L, 1, 0); + region * r = (region *)tolua_tousertype(L, 2, 0); + int num = (int)tolua_tonumber(L, 3, 1); + if (f && r) { + const race * rc = f->race; + const char * rcname = tolua_tostring(L, 4, NULL); + if (rcname) rc = rc_find(rcname); + if (rc) { + unit * u = create_unit(r, f, num, rc, 0, NULL, NULL); + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + return 1; + } + } + return 0; +} + +static int +tolua_unit_tostring(lua_State *L) +{ + unit * self = (unit *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, unitname(self)); + return 1; +} + +static int +tolua_event_gettype(lua_State *L) +{ + event * self = (event *)tolua_tousertype(L, 1, 0); + int index = (int)tolua_tonumber(L, 2, 0); + lua_pushstring(L, self->args[index].type); + return 1; +} + +static int +tolua_event_get(lua_State *L) +{ + struct event * self = (struct event *)tolua_tousertype(L, 1, 0); + int index = (int)tolua_tonumber(L, 2, 0); + + event_arg * arg = self->args+index; + + if (arg->type) { + if (strcmp(arg->type, "string")==0) { + tolua_pushstring(L, (const char *)arg->data.v); + } else if (strcmp(arg->type, "int")==0) { + tolua_pushnumber(L, (lua_Number)arg->data.i); + } else if (strcmp(arg->type, "float")==0) { + tolua_pushnumber(L, (lua_Number)arg->data.f); + } else { + /* this is pretty lazy */ + tolua_pushusertype(L, (void*)arg->data.v, TOLUA_CAST arg->type); + } + return 1; + } + tolua_error(L, TOLUA_CAST "invalid type argument for event", NULL); + return 0; +} + +void +tolua_unit_open(lua_State * L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "unit"); + tolua_usertype(L, TOLUA_CAST "unit_list"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, TOLUA_CAST "event", TOLUA_CAST "event", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "event"); + { + tolua_function(L, TOLUA_CAST "get_type", &tolua_event_gettype); + tolua_function(L, TOLUA_CAST "get", &tolua_event_get); + } + tolua_endmodule(L); + + tolua_cclass(L, TOLUA_CAST "unit", TOLUA_CAST "unit", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "unit"); + { + tolua_function(L, TOLUA_CAST "__tostring", &tolua_unit_tostring); + tolua_function(L, TOLUA_CAST "create", &tolua_unit_create); + tolua_function(L, TOLUA_CAST "destroy", &tolua_unit_destroy); + + tolua_variable(L, TOLUA_CAST "name", &tolua_unit_get_name, tolua_unit_set_name); + tolua_variable(L, TOLUA_CAST "faction", &tolua_unit_get_faction, tolua_unit_set_faction); + tolua_variable(L, TOLUA_CAST "id", &tolua_unit_get_id, tolua_unit_set_id); + tolua_variable(L, TOLUA_CAST "info", &tolua_unit_get_info, tolua_unit_set_info); + tolua_variable(L, TOLUA_CAST "hp", &tolua_unit_get_hp, tolua_unit_set_hp); + tolua_variable(L, TOLUA_CAST "status", &tolua_unit_get_status, tolua_unit_set_status); + tolua_variable(L, TOLUA_CAST "familiar", &tolua_unit_get_familiar, tolua_unit_set_familiar); + + tolua_variable(L, TOLUA_CAST "weight", &tolua_unit_get_weight, 0); + tolua_variable(L, TOLUA_CAST "capacity", &tolua_unit_get_capacity, 0); + + tolua_function(L, TOLUA_CAST "add_order", &tolua_unit_add_order); + tolua_function(L, TOLUA_CAST "clear_orders", &tolua_unit_clear_orders); + tolua_variable(L, TOLUA_CAST "orders", &tolua_unit_get_orders, 0); + + // key-attributes for named flags: + tolua_function(L, TOLUA_CAST "set_flag", &tolua_unit_set_flag); + tolua_function(L, TOLUA_CAST "get_flag", &tolua_unit_get_flag); + tolua_variable(L, TOLUA_CAST "flags", &tolua_unit_get_flags, &tolua_unit_set_flags); + tolua_variable(L, TOLUA_CAST "age", &tolua_unit_get_age, tolua_unit_set_age); + + // items: + tolua_function(L, TOLUA_CAST "get_item", &tolua_unit_get_item); + tolua_function(L, TOLUA_CAST "add_item", &tolua_unit_add_item); + tolua_variable(L, TOLUA_CAST "items", &tolua_unit_get_items, 0); + tolua_function(L, TOLUA_CAST "get_pooled", &tolua_unit_get_pooled); + tolua_function(L, TOLUA_CAST "use_pooled", &tolua_unit_use_pooled); + + // skills: + tolua_function(L, TOLUA_CAST "get_skill", &tolua_unit_getskill); + tolua_function(L, TOLUA_CAST "eff_skill", &tolua_unit_effskill); + tolua_function(L, TOLUA_CAST "set_skill", &tolua_unit_setskill); + + tolua_function(L, TOLUA_CAST "add_notice", &tolua_unit_addnotice); + + // npc logic: + tolua_function(L, TOLUA_CAST "add_handler", &tolua_unit_addhandler); + + tolua_variable(L, TOLUA_CAST "race_name", &tolua_unit_get_racename, &tolua_unit_set_racename); + tolua_function(L, TOLUA_CAST "add_spell", &tolua_unit_addspell); + tolua_function(L, TOLUA_CAST "remove_spell", &tolua_unit_removespell); + tolua_function(L, TOLUA_CAST "cast_spell", &tolua_unit_castspell); + + tolua_variable(L, TOLUA_CAST "magic", &tolua_unit_get_magic, tolua_unit_set_magic); + tolua_variable(L, TOLUA_CAST "aura", &tolua_unit_get_aura, tolua_unit_set_aura); + tolua_variable(L, TOLUA_CAST "building", &tolua_unit_get_building, tolua_unit_set_building); + tolua_variable(L, TOLUA_CAST "ship", &tolua_unit_get_ship, tolua_unit_set_ship); + tolua_variable(L, TOLUA_CAST "region", &tolua_unit_get_region, tolua_unit_set_region); + tolua_variable(L, TOLUA_CAST "spells", &tolua_unit_get_spells, 0); + tolua_variable(L, TOLUA_CAST "number", &tolua_unit_get_number, tolua_unit_set_number); + tolua_variable(L, TOLUA_CAST "race", &tolua_unit_get_race, tolua_unit_set_race); + tolua_variable(L, TOLUA_CAST "hp_max", &tolua_unit_get_hpmax, 0); + + tolua_variable(L, TOLUA_CAST "objects", &tolua_unit_get_objects, 0); + tolua_variable(L, TOLUA_CAST "attribs", &tolua_unit_get_attribs, 0); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_unit.h b/src/bindings/bind_unit.h new file mode 100644 index 000000000..767f4bfd6 --- /dev/null +++ b/src/bindings/bind_unit.h @@ -0,0 +1,26 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + int tolua_unitlist_nextb(struct lua_State *L); + int tolua_unitlist_nexts(struct lua_State *L); + int tolua_unitlist_nextf(struct lua_State *L); + int tolua_unitlist_next(struct lua_State *L); + void tolua_unit_open(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c new file mode 100644 index 000000000..fa1947c54 --- /dev/null +++ b/src/bindings/bindings.c @@ -0,0 +1,1159 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bindings.h" +#include "bind_unit.h" +#include "bind_faction.h" +#include "bind_region.h" +#include "helpers.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +int +log_lua_error(lua_State * L) +{ + const char* error = lua_tostring(L, -1); + + log_error(("LUA call failed.\n%s\n", error)); + lua_pop(L, 1); + + return 1; +} + +int tolua_orderlist_next(lua_State *L) +{ + order** order_ptr = (order **)lua_touserdata(L, lua_upvalueindex(1)); + order* ord = *order_ptr; + if (ord != NULL) { + char cmd[8192]; + write_order(ord, cmd, sizeof(cmd)); + tolua_pushstring(L, cmd); + *order_ptr = ord->next; + return 1; + } + else return 0; /* no more values to return */ +} + +int tolua_spelllist_next(lua_State *L) +{ + spell_list** spell_ptr = (spell_list **)lua_touserdata(L, lua_upvalueindex(1)); + spell_list* slist = *spell_ptr; + if (slist != NULL) { + tolua_pushusertype(L, slist->data, TOLUA_CAST "spell"); + *spell_ptr = slist->next; + return 1; + } + else return 0; /* no more values to return */ +} + +int tolua_itemlist_next(lua_State *L) +{ + item** item_ptr = (item **)lua_touserdata(L, lua_upvalueindex(1)); + item* itm = *item_ptr; + if (itm != NULL) { + tolua_pushstring(L, itm->type->rtype->_name[0]); + *item_ptr = itm->next; + return 1; + } + else return 0; /* no more values to return */ +} + +static int +tolua_autoseed(lua_State * L) +{ + const char * filename = tolua_tostring(L, 1, 0); + int new_island = tolua_toboolean(L, 2, 0); + newfaction * players = read_newfactions(filename); + + if (players!=NULL) { + while (players) { + int n = listlen(players); + int k = (n+ISLANDSIZE-1)/ISLANDSIZE; + k = n / k; + n = autoseed(&players, k, new_island?0:TURNS_PER_ISLAND); + if (n==0) { + break; + } + } + } + return 0; +} + + +static int +tolua_getkey(lua_State* L) +{ + const char * name = tolua_tostring(L, 1, 0); + + int flag = atoi36(name); + attrib * a = find_key(global.attribs, flag); + lua_pushboolean(L, a!=NULL); + + return 1; +} + +static int +tolua_translate(lua_State* L) +{ + const char * str = tolua_tostring(L, 1, 0); + const char * lang = tolua_tostring(L, 2, 0); + struct locale * loc = lang?find_locale(lang):default_locale; + if (loc) { + str = locale_string(loc, str); + tolua_pushstring(L, str); + return 1; + } + return 0; +} + +static int +tolua_setkey(lua_State* L) +{ + const char * name = tolua_tostring(L, 1, 0); + int value = tolua_toboolean(L, 2, 0); + + int flag = atoi36(name); + attrib * a = find_key(global.attribs, flag); + if (a==NULL && value) { + add_key(&global.attribs, flag); + } else if (a!=NULL && !value) { + a_remove(&global.attribs, a); + } + + return 0; +} + +static int +tolua_rng_int(lua_State* L) +{ + lua_pushnumber(L, (lua_Number)rng_int()); + return 1; +} + +static int +tolua_read_orders(lua_State* L) +{ + const char * filename = tolua_tostring(L, 1, 0); + int result = readorders(filename); + lua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_message_unit(lua_State* L) +{ + unit * sender = (unit *)tolua_tousertype(L, 1, 0); + unit * target = (unit *)tolua_tousertype(L, 2, 0); + const char * str = tolua_tostring(L, 3, 0); + if (!target) tolua_error(L, TOLUA_CAST "target is nil", NULL); + if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); + deliverMail(target->faction, sender->region, sender, str, target); + return 0; +} + +static int +tolua_message_faction(lua_State * L) +{ + unit * sender = (unit *)tolua_tousertype(L, 1, 0); + faction * target = (faction *)tolua_tousertype(L, 2, 0); + const char * str = tolua_tostring(L, 3, 0); + if (!target) tolua_error(L, TOLUA_CAST "target is nil", NULL); + if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); + + deliverMail(target, sender->region, sender, str, NULL); + return 0; +} + +static int +tolua_message_region(lua_State * L) +{ + unit * sender = (unit *)tolua_tousertype(L, 1, 0); + const char * str = tolua_tostring(L, 2, 0); + + if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); + ADDMSG(&sender->region->msgs, msg_message("mail_result", "unit message", sender, str)); + + return 0; +} + +static int +tolua_update_guards(lua_State * L) +{ + update_guards(); + return 0; +} + +static int +tolua_set_turn(lua_State * L) +{ + turn = (int)tolua_tonumber(L, 1, 0); + return 0; +} + +static int +tolua_get_turn(lua_State * L) +{ + tolua_pushnumber(L, (lua_Number)turn); + return 1; +} + +static int +tolua_atoi36(lua_State * L) +{ + const char * s = tolua_tostring(L, 1, 0); + tolua_pushnumber(L, (lua_Number)atoi36(s)); + return 1; +} + +static int +tolua_itoa36(lua_State * L) +{ + int i = (int)tolua_tonumber(L, 1, 0); + tolua_pushstring(L, itoa36(i)); + return 1; +} + +static int +tolua_dice_rand(lua_State * L) +{ + const char * s = tolua_tostring(L, 1, 0); + tolua_pushnumber(L, dice_rand(s)); + return 1; +} + +static int +tolua_addequipment(lua_State * L) +{ + const char * eqname = tolua_tostring(L, 1, 0); + const char * iname = tolua_tostring(L, 2, 0); + const char * value = tolua_tostring(L, 3, 0); + int result = -1; + if (iname!=NULL) { + const struct item_type * itype = it_find(iname); + if (itype!=NULL) { + equipment_setitem(create_equipment(eqname), itype, value); + result = 0; + } + } + lua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_get_season(lua_State * L) +{ + int turnno = (int)tolua_tonumber(L, 1, 0); + gamedate gd; + get_gamedate(turnno, &gd); + tolua_pushstring(L, seasonnames[gd.season]); + return 1; +} + +static int +tolua_create_curse(lua_State * L) +{ + unit * u = (unit *)tolua_tousertype(L, 1, 0); + tolua_Error tolua_err; + attrib ** ap = NULL; + + if (tolua_isusertype(L, 2, TOLUA_CAST "unit", 0, &tolua_err)) { + unit * target = (unit *)tolua_tousertype(L, 2, 0); + if (target) ap = &target->attribs; + } else if (tolua_isusertype(L, 2, TOLUA_CAST "region", 0, &tolua_err)) { + region * target = (region *)tolua_tousertype(L, 2, 0); + if (target) ap = &target->attribs; + } else if (tolua_isusertype(L, 2, TOLUA_CAST "ship", 0, &tolua_err)) { + ship * target = (ship *)tolua_tousertype(L, 2, 0); + if (target) ap = &target->attribs; + } else if (tolua_isusertype(L, 2, TOLUA_CAST "building", 0, &tolua_err)) { + building * target = (building *)tolua_tousertype(L, 2, 0); + if (target) ap = &target->attribs; + } + if (ap) { + const char * cname = tolua_tostring(L, 3, 0); + const curse_type * ctype = ct_find(cname); + if (ctype) { + double vigour = tolua_tonumber(L, 4, 0); + int duration = (int)tolua_tonumber(L, 5, 0); + double effect = tolua_tonumber(L, 6, 0); + int men = (int)tolua_tonumber(L, 7, 0); /* optional */ + curse * c = create_curse(u, ap, ctype, vigour, duration, effect, men); + + if (c) { + tolua_pushboolean(L, true); + return 1; + } + } + } + tolua_pushboolean(L, false); + return 1; +} + +static int +tolua_learn_skill(lua_State * L) +{ + unit * u = (unit *)tolua_tousertype(L, 1, 0); + const char * skname = tolua_tostring(L, 2, 0); + float chances = (float)tolua_tonumber(L, 3, 0); + skill_t sk = sk_find(skname); + if (sk!=NOSKILL) { + learn_skill(u, sk, chances); + } + return 0; +} + +static int +tolua_update_scores(lua_State * L) +{ + score(); + return 0; +} + +static int +tolua_update_owners(lua_State * L) +{ + region * r; + for (r=regions;r;r=r->next) { + update_owners(r); + } + return 0; +} + +static int +tolua_update_subscriptions(lua_State * L) +{ + update_subscriptions(); + return 0; +} + +static int +tolua_remove_empty_units(lua_State * L) +{ + remove_empty_units(); + return 0; +} + +static int +tolua_get_nmrs(lua_State * L) +{ + int result = -1; + int n = (int)tolua_tonumber(L, 1, 0); + if (n>=0 && n<=NMRTimeout()) { + if (nmrs==NULL) { + update_nmrs(); + } + result = nmrs[n]; + } + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_equipunit(lua_State * L) +{ + unit * u = (unit *)tolua_tousertype(L, 1, 0); + const char * eqname = tolua_tostring(L, 2, 0); + + equip_unit(u, get_equipment(eqname)); + + return 0; +} + +static int +tolua_equipment_setitem(lua_State * L) +{ + int result = -1; + const char * eqname = tolua_tostring(L, 1, 0); + const char * iname = tolua_tostring(L, 2, 0); + const char * value = tolua_tostring(L, 3, 0); + if (iname!=NULL) { + const struct item_type * itype = it_find(iname); + if (itype!=NULL) { + equipment_setitem(create_equipment(eqname), itype, value); + result = 0; + } + } + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +#ifdef TODO_FOSS +static int +tolua_levitate_ship(lua_State * L) +{ + ship * sh = (ship *)tolua_tousertype(L, 1, 0); + unit * mage = (unit *)tolua_tousertype(L, 2, 0); + double power = (double)tolua_tonumber(L, 3, 0); + int duration = (int)tolua_tonumber(L, 4, 0); + int cno = levitate_ship(sh, mage, power, duration); + tolua_pushnumber(L, (lua_Number)cno); + return 1; +} +#endif + +static int +tolua_spawn_braineaters(lua_State * L) +{ + float chance = (float)tolua_tonumber(L, 1, 0); + spawn_braineaters(chance); + return 0; +} + +static int +tolua_init_reports(lua_State* L) +{ + int result = init_reports(); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_write_report(lua_State* L) +{ + faction * f = (faction * )tolua_tousertype(L, 1, 0); + time_t ltime = time(0); + int result = write_reports(f, ltime); + + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_write_reports(lua_State* L) +{ + int result; + + init_reports(); + result = reports(); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static void +reset_game(void) +{ + region * r; + faction * f; + for (r=regions;r;r=r->next) { + unit * u; + building * b; + r->flags &= RF_SAVEMASK; + for (u=r->units;u;u=u->next) { + u->flags &= UFL_SAVEMASK; + } + for (b=r->buildings;b;b=b->next) { + b->flags &= BLD_SAVEMASK; + } + + if (r->land && r->land->ownership && r->land->ownership->owner) { + faction * owner = r->land->ownership->owner; + if (owner==get_monsters()) { + /* some compat-fix, i believe. */ + owner = update_owners(r); + } + if (owner) { + fset(r, RF_GUARDED); + } + } + } + for (f=factions;f;f=f->next) { + f->flags &= FFL_SAVEMASK; + } +} + +static int +tolua_process_orders(lua_State* L) +{ + ++turn; + reset_game(); + processorders(); + return 0; +} + +static int +tolua_write_passwords(lua_State* L) +{ + int result = writepasswd(); + lua_pushnumber(L, (lua_Number)result); + return 0; +} + +static struct summary * sum_begin = 0; + +static int +tolua_init_summary(lua_State* L) +{ + sum_begin = make_summary(); + return 0; +} + +static int +tolua_write_summary(lua_State* L) +{ + if (sum_begin) { + struct summary * sum_end = make_summary(); + report_summary(sum_end, sum_begin, false); + report_summary(sum_end, sum_begin, true); + return 0; + } + return 0; +} + +static int +tolua_free_game(lua_State* L) +{ + free_gamedata(); + return 0; +} + +static int +tolua_write_map(lua_State* L) +{ + const char * filename = tolua_tostring(L, 1, 0); + if (filename) { + crwritemap(filename); + } + return 0; +} + +static int +tolua_write_game(lua_State* L) +{ + const char * filename = tolua_tostring(L, 1, 0); + const char * mode = tolua_tostring(L, 2, 0); + + int result, m = IO_BINARY; + if (mode && strcmp(mode, "text")==0) m = IO_TEXT; + remove_empty_factions(); + result = writegame(filename, m); + + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_read_game(lua_State* L) +{ + const char * filename = tolua_tostring(L, 1, 0); + const char * mode = tolua_tostring(L, 2, 0); + + int rv, m = IO_BINARY; + if (mode && strcmp(mode, "text")==0) m = IO_TEXT; + rv = readgame(filename, m, false); + + tolua_pushnumber(L, (lua_Number)rv); + return 1; +} + +static int +tolua_read_turn(lua_State* L) +{ + int cturn = current_turn(); + tolua_pushnumber(L, (lua_Number)cturn); + return 1; +} + +static int +tolua_get_faction(lua_State* L) +{ + int no = tolua_toid(L, 1, 0); + faction * f = findfaction(no); + + tolua_pushusertype(L, f, TOLUA_CAST "faction"); + return 1; +} + +static int +tolua_get_region(lua_State* L) +{ + int x = (int)tolua_tonumber(L, 1, 0); + int y = (int)tolua_tonumber(L, 2, 0); + region * r; + + assert(!pnormalize(&x, &y, findplane(x, y))); + r = findregion(x, y); + + tolua_pushusertype(L, r, TOLUA_CAST "region"); + return 1; +} + +static int +tolua_get_region_byid(lua_State* L) +{ + int uid = (int)tolua_tonumber(L, 1, 0); + region * r = findregionbyid(uid); + + tolua_pushusertype(L, r, TOLUA_CAST "region"); + return 1; +} + +static int +tolua_get_building(lua_State* L) +{ + int no = tolua_toid(L, 1, 0); + building * b = findbuilding(no); + + tolua_pushusertype(L, b, TOLUA_CAST "building"); + return 1; +} + +static int +tolua_get_ship(lua_State* L) +{ + int no = tolua_toid(L, 1, 0); + ship * sh = findship(no); + + tolua_pushusertype(L, sh, TOLUA_CAST "ship"); + return 1; +} + +static int +tolua_get_alliance(lua_State* L) +{ + int no = tolua_toid(L, 1, 0); + alliance * f = findalliance(no); + + tolua_pushusertype(L, f, TOLUA_CAST "alliance"); + return 1; +} + +static int +tolua_get_unit(lua_State* L) +{ + int no = tolua_toid(L, 1, 0); + unit * u = findunit(no); + + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + return 1; +} + +static int +tolua_alliance_create(lua_State* L) +{ + int id = (int)tolua_tonumber(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + + alliance * alli = makealliance(id, name); + + tolua_pushusertype(L, alli, TOLUA_CAST "alliance"); + return 1; +} + +static int +tolua_get_regions(lua_State* L) +{ + region ** region_ptr = (region**)lua_newuserdata(L, sizeof(region *)); + + luaL_getmetatable(L, "region"); + lua_setmetatable(L, -2); + + *region_ptr = regions; + + lua_pushcclosure(L, tolua_regionlist_next, 1); + return 1; +} + +static int +tolua_get_factions(lua_State* L) +{ + faction ** faction_ptr = (faction**)lua_newuserdata(L, sizeof(faction *)); + + luaL_getmetatable(L, "faction"); + lua_setmetatable(L, -2); + + *faction_ptr = factions; + + lua_pushcclosure(L, tolua_factionlist_next, 1); + return 1; +} + +static int +tolua_get_alliance_factions(lua_State* L) +{ + alliance * self = (alliance *)tolua_tousertype(L, 1, 0); + faction_list ** faction_ptr = (faction_list**)lua_newuserdata(L, sizeof(faction_list *)); + + luaL_getmetatable(L, "faction_list"); + lua_setmetatable(L, -2); + + *faction_ptr = self->members; + + lua_pushcclosure(L, tolua_factionlist_iter, 1); + return 1; +} + +static int tolua_get_alliance_id(lua_State* L) +{ + alliance* self = (alliance*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->id); + return 1; +} + +static int tolua_get_alliance_name(lua_State* L) +{ + alliance* self = (alliance*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->name); + return 1; +} + +static int tolua_set_alliance_name(lua_State* L) +{ + alliance* self = (alliance*)tolua_tousertype(L, 1, 0); + alliance_setname(self, tolua_tostring(L, 2, 0)); + return 0; +} + +#include +#include +#include +#include + +static int +tolua_write_spells(lua_State* L) +{ + spell_f fun = (spell_f)get_function("lua_castspell"); + const char * filename = "magic.xml"; + xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); + xmlNodePtr root = xmlNewNode(NULL, BAD_CAST "spells"); + spell_list * splist; + + for (splist=spells; splist; splist=splist->next) { + spell * sp = splist->data; + if (sp->sp_function!=fun) { + int combat = 0; + xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "spell"); + xmlNewProp(node, BAD_CAST "name", BAD_CAST sp->sname); + xmlNewProp(node, BAD_CAST "type", BAD_CAST magic_school[sp->magietyp]); + xmlNewProp(node, BAD_CAST "rank", xml_i(sp->rank)); + xmlNewProp(node, BAD_CAST "level", xml_i(sp->level)); + xmlNewProp(node, BAD_CAST "index", xml_i(sp->id)); + if (sp->syntax) xmlNewProp(node, BAD_CAST "syntax", BAD_CAST sp->syntax); + if (sp->parameter) xmlNewProp(node, BAD_CAST "parameters", BAD_CAST sp->parameter); + if (sp->components) { + spell_component * comp = sp->components; + for (;comp->type!=0;++comp) { + static const char * costs[] = { "fixed", "level", "linear" }; + xmlNodePtr cnode = xmlNewNode(NULL, BAD_CAST "resource"); + xmlNewProp(cnode, BAD_CAST "name", BAD_CAST comp->type->_name[0]); + xmlNewProp(cnode, BAD_CAST "amount", xml_i(comp->amount)); + xmlNewProp(cnode, BAD_CAST "cost", BAD_CAST costs[comp->cost]); + xmlAddChild(node, cnode); + } + } + + if (sp->sptyp & TESTCANSEE) { + xmlNewProp(node, BAD_CAST "los", BAD_CAST "true"); + } + if (sp->sptyp & ONSHIPCAST) { + xmlNewProp(node, BAD_CAST "ship", BAD_CAST "true"); + } + if (sp->sptyp & OCEANCASTABLE) { + xmlNewProp(node, BAD_CAST "ocean", BAD_CAST "true"); + } + if (sp->sptyp & FARCASTING) { + xmlNewProp(node, BAD_CAST "far", BAD_CAST "true"); + } + if (sp->sptyp & SPELLLEVEL) { + xmlNewProp(node, BAD_CAST "variable", BAD_CAST "true"); + } + + if (sp->sptyp & POSTCOMBATSPELL) combat = 3; + else if (sp->sptyp & COMBATSPELL) combat = 2; + else if (sp->sptyp & PRECOMBATSPELL) combat = 1; + if (combat) { + xmlNewProp(node, BAD_CAST "combat", xml_i(combat)); + } + xmlAddChild(root, node); + } + } + xmlDocSetRootElement(doc, root); + xmlKeepBlanksDefault(0); + xmlSaveFormatFileEnc(filename, doc, "utf-8", 1); + xmlFreeDoc(doc); + return 0; +} + +static int +tolua_get_locales(lua_State *L) +{ + const struct locale * lang; + int i = 0, n = 0; + + for (lang = locales;lang;lang = nextlocale(lang)) ++n; + lua_createtable(L, n, 0); + + for (lang = locales;lang;lang = nextlocale(lang)) { + tolua_pushstring(L, TOLUA_CAST locale_name(lang)); + lua_rawseti(L, -2, ++i); + } + return 1; +} + +static int +tolua_get_spell_text(lua_State *L) +{ + const struct locale * loc = default_locale; + spell * self = (spell *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, spell_info(self, loc)); + return 1; +} + +static int +tolua_get_spell_school(lua_State *L) +{ + spell * self = (spell *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, magic_school[self->magietyp]); + return 1; +} + +static int +tolua_get_spell_level(lua_State *L) +{ + spell * self = (spell *)tolua_tousertype(L, 1, 0); + lua_pushnumber(L, self->level); + return 1; +} + +static int +tolua_get_spell_name(lua_State *L) +{ + const struct locale * lang = default_locale; + spell * self = (spell *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, spell_name(self, lang)); + return 1; +} + +static int tolua_get_spells(lua_State* L) +{ + spell_list * slist = spells; + if (slist) { + spell_list ** spell_ptr = (spell_list **)lua_newuserdata(L, sizeof(spell_list *)); + luaL_getmetatable(L, "spell_list"); + lua_setmetatable(L, -2); + + *spell_ptr = slist; + lua_pushcclosure(L, tolua_spelllist_next, 1); + return 1; + } + + lua_pushnil(L); + return 1; +} + +int +tolua_read_xml(lua_State* L) +{ + const char * filename = tolua_tostring(L, 1, 0); + const char * catalog = tolua_tostring(L, 2, 0); + init_data(filename, catalog); + return 0; +} + +int tolua_process_markets(lua_State* L) { + do_markets(); + return 0; +} + +int tolua_process_produce(lua_State* L) { + region * r; + for (r=regions;r;r=r->next) { + produce(r); + } + return 0; +} + +typedef struct event_args { + int hfunction; + int hargs; + const char * sendertype; +} event_args; + +static void args_free(void * udata) +{ + free(udata); +} + +static void event_cb(void * sender, const char * event, void * udata) { + lua_State * L = (lua_State *)global.vm_state; + event_args * args = (event_args *)udata; + int nargs = 2; + + lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); + if (sender && args->sendertype) { + tolua_pushusertype(L, sender, TOLUA_CAST args->sendertype); + } else { + lua_pushnil(L); + } + tolua_pushstring(L, event); + if (args->hargs) { + lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); + ++nargs; + } + lua_pcall(L, nargs, 0, 0); +} + +static int +tolua_eventbus_register(lua_State * L) +{ + /* parameters: + ** 1: sender (usertype) + ** 2: event (string) + ** 3: handler (function) + ** 4: arguments (any, *optional*) + */ + void * sender = tolua_tousertype(L, 1, 0); + const char * event = tolua_tostring(L, 2, 0); + event_args * args = malloc(sizeof(event_args)); + + args->sendertype = sender?tolua_typename(L, 1):NULL; + lua_pushvalue(L, 3); + args->hfunction = luaL_ref(L, LUA_REGISTRYINDEX); + if (lua_type(L, 4)!=LUA_TNONE) { + lua_pushvalue(L, 4); + args->hargs = luaL_ref(L, LUA_REGISTRYINDEX); + } else { + args->hargs = 0; + } + eventbus_register(sender, event, &event_cb, &args_free, args); + return 0; +} + +static int +tolua_eventbus_fire(lua_State * L) +{ + void * sender = tolua_tousertype(L, 1, 0); + const char * event = tolua_tostring(L, 2, 0); + void * args = NULL; + eventbus_fire(sender, event, args); + return 0; +} + +static void +parse_inifile(lua_State* L, dictionary * d, const char * section) +{ + int i; + size_t len = strlen(section); + for (i=0;d && i!=d->n;++i) { + const char * key = d->key[i]; + + if (strncmp(section, key, len)==0 && key[len]==':') { + const char * str_value = d->val[i]; + char * endp; + double num_value = strtod(str_value, &endp); + lua_pushstring(L, key + len + 1); + if (*endp) { + tolua_pushstring(L, str_value); + } else { + tolua_pushnumber(L, num_value); + } + lua_rawset(L,-3); + } + } + /* special case */ + lua_pushstring(L, "basepath"); + lua_pushstring(L, basepath()); + lua_rawset(L,-3); +} + +int +tolua_eressea_open(lua_State* L) +{ + tolua_open(L); + + /* register user types */ + tolua_usertype(L, TOLUA_CAST "spell"); + tolua_usertype(L, TOLUA_CAST "spell_list"); + tolua_usertype(L, TOLUA_CAST "order"); + tolua_usertype(L, TOLUA_CAST "item"); + tolua_usertype(L, TOLUA_CAST "alliance"); + tolua_usertype(L, TOLUA_CAST "event"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_module(L, "process", 0); + tolua_beginmodule(L, "process"); + { + tolua_function(L, "markets", &tolua_process_markets); + tolua_function(L, "produce", &tolua_process_produce); + } + tolua_endmodule(L); + + tolua_cclass(L, TOLUA_CAST "alliance", TOLUA_CAST "alliance", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "alliance"); + { + tolua_variable(L, TOLUA_CAST "name", tolua_get_alliance_name, tolua_set_alliance_name); + tolua_variable(L, TOLUA_CAST "id", tolua_get_alliance_id, NULL); + tolua_variable(L, TOLUA_CAST "factions", &tolua_get_alliance_factions, NULL); + tolua_function(L, TOLUA_CAST "create", tolua_alliance_create); + } + tolua_endmodule(L); + + tolua_cclass(L, TOLUA_CAST "spell", TOLUA_CAST "spell", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "spell"); + { + tolua_function(L, TOLUA_CAST "__tostring", tolua_get_spell_name); + tolua_variable(L, TOLUA_CAST "name", tolua_get_spell_name, 0); + tolua_variable(L, TOLUA_CAST "school", tolua_get_spell_school, 0); + tolua_variable(L, TOLUA_CAST "level", tolua_get_spell_level, 0); + tolua_variable(L, TOLUA_CAST "text", tolua_get_spell_text, 0); + } + tolua_endmodule(L); + + tolua_module(L, TOLUA_CAST "eventbus", 1); + tolua_beginmodule(L, TOLUA_CAST "eventbus"); + { + tolua_function(L, TOLUA_CAST "register", &tolua_eventbus_register); + tolua_function(L, TOLUA_CAST "fire", &tolua_eventbus_fire); + } + tolua_endmodule(L); + + tolua_module(L, TOLUA_CAST "config", 1); + tolua_beginmodule(L, TOLUA_CAST "config"); + { + parse_inifile(L, global.inifile, "config"); + tolua_variable(L, TOLUA_CAST "locales", &tolua_get_locales, 0); + } + tolua_endmodule(L); + + tolua_function(L, TOLUA_CAST "get_region_by_id", tolua_get_region_byid); + tolua_function(L, TOLUA_CAST "get_faction", tolua_get_faction); + tolua_function(L, TOLUA_CAST "get_unit", tolua_get_unit); + tolua_function(L, TOLUA_CAST "get_alliance", tolua_get_alliance); + tolua_function(L, TOLUA_CAST "get_ship", tolua_get_ship), + tolua_function(L, TOLUA_CAST "get_building", tolua_get_building), + tolua_function(L, TOLUA_CAST "get_region", tolua_get_region), + + // deprecated_function(L, TOLUA_CAST "add_faction"); + // deprecated_function(L, TOLUA_CAST "faction_origin"); + tolua_function(L, TOLUA_CAST "factions", tolua_get_factions); + tolua_function(L, TOLUA_CAST "regions", tolua_get_regions); + + tolua_function(L, TOLUA_CAST "read_turn", tolua_read_turn); + tolua_function(L, TOLUA_CAST "read_game", tolua_read_game); + tolua_function(L, TOLUA_CAST "write_game", tolua_write_game); + tolua_function(L, TOLUA_CAST "free_game", tolua_free_game); + tolua_function(L, TOLUA_CAST "write_map", &tolua_write_map); + + tolua_function(L, TOLUA_CAST "read_orders", tolua_read_orders); + tolua_function(L, TOLUA_CAST "process_orders", tolua_process_orders); + + tolua_function(L, TOLUA_CAST "init_reports", tolua_init_reports); + tolua_function(L, TOLUA_CAST "write_reports", tolua_write_reports); + tolua_function(L, TOLUA_CAST "write_report", tolua_write_report); + + tolua_function(L, TOLUA_CAST "init_summary", tolua_init_summary); + tolua_function(L, TOLUA_CAST "write_summary", tolua_write_summary); + tolua_function(L, TOLUA_CAST "write_passwords", tolua_write_passwords), + + tolua_function(L, TOLUA_CAST "message_unit", tolua_message_unit); + tolua_function(L, TOLUA_CAST "message_faction", tolua_message_faction); + tolua_function(L, TOLUA_CAST "message_region", tolua_message_region); + + /* scripted monsters */ + tolua_function(L, TOLUA_CAST "spawn_braineaters", tolua_spawn_braineaters); + +#ifdef TODO_FOSS + /* spells and stuff */ + tolua_function(L, TOLUA_CAST "levitate_ship", tolua_levitate_ship); +#endif + + tolua_function(L, TOLUA_CAST "update_guards", tolua_update_guards); + + tolua_function(L, TOLUA_CAST "set_turn", &tolua_set_turn); + tolua_function(L, TOLUA_CAST "get_turn", &tolua_get_turn); + tolua_function(L, TOLUA_CAST "get_season", tolua_get_season); + + tolua_function(L, TOLUA_CAST "equipment_setitem", tolua_equipment_setitem); + tolua_function(L, TOLUA_CAST "equip_unit", tolua_equipunit); + tolua_function(L, TOLUA_CAST "add_equipment", tolua_addequipment); + + tolua_function(L, TOLUA_CAST "atoi36", tolua_atoi36); + tolua_function(L, TOLUA_CAST "itoa36", tolua_itoa36); + tolua_function(L, TOLUA_CAST "dice_roll", tolua_dice_rand); + + tolua_function(L, TOLUA_CAST "get_nmrs", tolua_get_nmrs); + tolua_function(L, TOLUA_CAST "remove_empty_units", tolua_remove_empty_units); + + tolua_function(L, TOLUA_CAST "update_subscriptions", tolua_update_subscriptions); + tolua_function(L, TOLUA_CAST "update_scores", tolua_update_scores); + tolua_function(L, TOLUA_CAST "update_owners", tolua_update_owners); + + tolua_function(L, TOLUA_CAST "learn_skill", tolua_learn_skill); + tolua_function(L, TOLUA_CAST "create_curse", tolua_create_curse); + + tolua_function(L, TOLUA_CAST "autoseed", tolua_autoseed); + + tolua_function(L, TOLUA_CAST "get_key", tolua_getkey); + tolua_function(L, TOLUA_CAST "set_key", tolua_setkey); + + tolua_function(L, TOLUA_CAST "translate", &tolua_translate); + + tolua_function(L, TOLUA_CAST "rng_int", tolua_rng_int); + + tolua_function(L, TOLUA_CAST "spells", tolua_get_spells); + tolua_function(L, TOLUA_CAST "write_spells", tolua_write_spells); + + tolua_function(L, TOLUA_CAST "read_xml", tolua_read_xml); + + } + tolua_endmodule(L); + return 1; +} diff --git a/src/bindings/bindings.h b/src/bindings/bindings.h new file mode 100644 index 000000000..5ed8d6232 --- /dev/null +++ b/src/bindings/bindings.h @@ -0,0 +1,27 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + int tolua_sqlite_open(struct lua_State * L); + int tolua_eressea_open(struct lua_State* L); + int tolua_spelllist_next(struct lua_State *L); + int tolua_itemlist_next(struct lua_State *L); + int tolua_orderlist_next(struct lua_State *L); + + int log_lua_error(struct lua_State * L); +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/helpers.c b/src/bindings/helpers.c new file mode 100644 index 000000000..6395bce35 --- /dev/null +++ b/src/bindings/helpers.c @@ -0,0 +1,664 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include "helpers.h" +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +static int +lua_giveitem(unit * s, unit * d, const item_type * itype, int n, struct order * ord) +{ + lua_State * L = (lua_State *)global.vm_state; + char fname[64]; + int result = -1; + const char * iname = itype->rtype->_name[0]; + + assert(s!=NULL); + strcat(strcpy(fname, iname), "_give"); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, s, TOLUA_CAST "unit"); + tolua_pushusertype(L, d, TOLUA_CAST "unit"); + tolua_pushstring(L, iname); + tolua_pushnumber(L, (lua_Number)n); + + if (lua_pcall(L, 4, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("unit %s calling '%s': %s.\n", + unitname(s), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("unit %s trying to call '%s' : not a function.\n", + unitname(s), fname)); + lua_pop(L, 1); + } + + return result; +} + +static int +limit_resource(const region * r, const resource_type * rtype) +{ + char fname[64]; + int result = -1; + lua_State * L = (lua_State *)global.vm_state; + + snprintf(fname, sizeof(fname), "%s_limit", rtype->_name[0]); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); + + if (lua_pcall(L, 1, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("limit(%s) calling '%s': %s.\n", + regionname(r, NULL), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("limit(%s) calling '%s': not a function.\n", + regionname(r, NULL), fname)); + lua_pop(L, 1); + } + + return result; +} + +static void +produce_resource(region * r, const resource_type * rtype, int norders) +{ + lua_State * L = (lua_State *)global.vm_state; + char fname[64]; + snprintf(fname, sizeof(fname), "%s_produce", rtype->_name[0]); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); + tolua_pushnumber(L, (lua_Number)norders); + + if (lua_pcall(L, 2, 0, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("produce(%s) calling '%s': %s.\n", + regionname(r, NULL), fname, error)); + lua_pop(L, 1); + } + } else { + log_error(("produce(%s) calling '%s': not a function.\n", + regionname(r, NULL), fname)); + lua_pop(L, 1); + } +} + + +static int +lc_age(struct attrib * a) +{ + building_action * data = (building_action*)a->data.v; + const char * fname = data->fname; + const char * fparam = data->param; + building * b = data->b; + int result = -1; + + assert(b!=NULL); + if (fname!=NULL) { + lua_State * L = (lua_State *)global.vm_state; + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); + if (fparam) { + tolua_pushstring(L, fparam); + } + + if (lua_pcall(L, fparam?2:1, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("lc_age(%s) calling '%s': %s.\n", + buildingname(b), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("lc_age(%s) calling '%s': not a function.\n", + buildingname(b), fname)); + lua_pop(L, 1); + } + } + return (result!=0)?AT_AGE_KEEP:AT_AGE_REMOVE; +} + +static void push_param(lua_State * L, char c, spllprm * param) +{ + if (c=='u') tolua_pushusertype(L, param->data.u, "unit"); + else if (c=='b') tolua_pushusertype(L, param->data.b, "building"); + else if (c=='s') tolua_pushusertype(L, param->data.sh, "ship"); + else if (c=='r') tolua_pushusertype(L, param->data.sh, "region"); + else if (c=='c') tolua_pushstring(L, param->data.s); + else { + log_error(("unsupported syntax %c.\n", c)); + lua_pushnil(L); + } +} + +/** callback to use lua for spell functions */ +static int +lua_callspell(castorder *co) +{ + lua_State * L = (lua_State *)global.vm_state; + const char * fname = co->sp->sname; + unit * mage = co->familiar?co->familiar:co->magician.u; + int result = -1; + const char * hashpos = strchr(fname, '#'); + char fbuf[64]; + + if (hashpos!=NULL) { + ptrdiff_t len = hashpos - fname; + assert(len<(ptrdiff_t)sizeof(fbuf)); + strncpy(fbuf, fname, len); + fbuf[len] = '\0'; + fname = fbuf; + } + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + int nparam = 4; + tolua_pushusertype(L, co->rt, TOLUA_CAST "region"); + tolua_pushusertype(L, mage, TOLUA_CAST "unit"); + tolua_pushnumber(L, (lua_Number)co->level); + tolua_pushnumber(L, (lua_Number)co->force); + if (co->sp->parameter && co->par->length) { + const char * synp = co->sp->parameter; + int i = 0; + ++nparam; + lua_newtable(L); + while (*synp&&ipar->length) { + spllprm * param = co->par->param[i]; + char c = *synp; + if (c=='+') { + push_param(L, *(synp-1), param); + } else { + push_param(L, c, param); + ++synp; + } + lua_rawseti(L, -2, ++i); + } + } + + if (lua_pcall(L, nparam, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("spell(%s) calling '%s': %s.\n", + unitname(mage), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("spell(%s) calling '%s': not a function.\n", + unitname(mage), fname)); + lua_pop(L, 1); + } + + return result; +} + +/** callback to initialize a familiar from lua. */ +static void +lua_initfamiliar(unit * u) +{ + lua_State * L = (lua_State *)global.vm_state; + char fname[64]; + int result = -1; + snprintf(fname, sizeof(fname), "initfamiliar_%s", u->race->_name[0]); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + + if (lua_pcall(L, 1, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("familiar(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_warning(("familiar(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } + + create_mage(u, M_GRAY); + + snprintf(fname, sizeof(fname), "%s_familiar", u->race->_name[0]); + equip_unit(u, get_equipment(fname)); +} + +static int +lua_changeresource(unit * u, const struct resource_type * rtype, int delta) +{ + lua_State * L = (lua_State *)global.vm_state; + int result = -1; + char fname[64]; + snprintf(fname, sizeof(fname), "%s_changeresource", rtype->_name[0]); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + tolua_pushnumber(L, (lua_Number)delta); + + if (lua_pcall(L, 2, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("change(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("change(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } + + return result; +} + +static int +lua_getresource(unit * u, const struct resource_type * rtype) +{ + lua_State * L = (lua_State *)global.vm_state; + int result = -1; + char fname[64]; + snprintf(fname, sizeof(fname), "%s_getresource", rtype->_name[0]); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + + if (lua_pcall(L, 1, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("get(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("get(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } + + return result; +} + +static boolean +lua_canuse_item(const unit * u, const struct item_type * itype) +{ + static int function_exists = 1; + boolean result = true; + + if (function_exists) { + lua_State * L = (lua_State *)global.vm_state; + const char * fname = "item_canuse"; + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); + tolua_pushstring(L, itype->rtype->_name[0]); + + if (lua_pcall(L, 2, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("get(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = lua_toboolean(L, -1); + lua_pop(L, 1); + } + } else { + function_exists = 0; + log_error(("get(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } + } + return result; +} + +static int +lua_wage(const region * r, const faction * f, const race * rc, int in_turn) +{ + lua_State * L = (lua_State *)global.vm_state; + const char * fname = "wage"; + int result = -1; + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); + tolua_pushusertype(L, (void *)f, TOLUA_CAST "faction"); + tolua_pushstring(L, rc?rc->_name[0]:0); + tolua_pushnumber(L, (lua_Number)in_turn); + + if (lua_pcall(L, 3, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("wage(%s) calling '%s': %s.\n", + regionname(r, NULL), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("wage(%s) calling '%s': not a function.\n", + regionname(r, NULL), fname)); + lua_pop(L, 1); + } + + return result; +} + +static void +lua_agebuilding(building * b) +{ + lua_State * L = (lua_State *)global.vm_state; + char fname[64]; + + snprintf(fname, sizeof(fname), "age_%s", b->type->_name); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); + + if (lua_pcall(L, 1, 0, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("agebuilding(%s) calling '%s': %s.\n", + buildingname(b), fname, error)); + lua_pop(L, 1); + } + } else { + log_error(("agebuilding(%s) calling '%s': not a function.\n", + buildingname(b), fname)); + lua_pop(L, 1); + } +} + +static int +lua_building_protection(building * b, unit * u) +{ + lua_State * L = (lua_State *)global.vm_state; + const char * fname = "building_protection"; + int result = 0; + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); + + if (lua_pcall(L, 2, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("building_protection(%s, %s) calling '%s': %s.\n", + buildingname(b), unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("building_protection(%s, %s) calling '%s': not a function.\n", + buildingname(b), unitname(u), fname)); + lua_pop(L, 1); + } + return result; +} + +static double +lua_building_taxes(building * b, int level) +{ + lua_State * L = (lua_State *)global.vm_state; + const char * fname = "building_taxes"; + double result = 0.0F; + int type; + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + type=lua_type(L, 1); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); + tolua_pushnumber(L, level); + + if (lua_pcall(L, 2, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("building_taxes(%s) calling '%s': %s.\n", + buildingname(b), fname, error)); + lua_pop(L, 1); + } else { + result = (double)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("building_taxes(%s) calling '%s': not a function.\n", + buildingname(b), fname)); + lua_pop(L, 1); + } + return result; +} + +static int +lua_maintenance(const unit * u) +{ + lua_State * L = (lua_State *)global.vm_state; + const char * fname = "maintenance"; + int result = -1; + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); + + if (lua_pcall(L, 1, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("maintenance(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("maintenance(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } + + return result; +} + +static void +lua_equipmentcallback(const struct equipment * eq, unit * u) +{ + lua_State * L = (lua_State *)global.vm_state; + char fname[64]; + int result = -1; + snprintf(fname, sizeof(fname), "equip_%s", eq->name); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); + + if (lua_pcall(L, 1, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("equip(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("equip(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } +} + +/** callback for an item-use function written in lua. */ +int +lua_useitem(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + lua_State * L = (lua_State *)global.vm_state; + int result = 0; + char fname[64]; + snprintf(fname, sizeof(fname), "use_%s", itype->rtype->_name[0]); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); + tolua_pushnumber(L, (lua_Number)amount); + + if (lua_pcall(L, 2, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("use(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("use(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } + + return result; +} + +static int +lua_recruit(struct unit * u, const struct archetype * arch, int amount) +{ + lua_State * L = (lua_State *)global.vm_state; + int result = 0; + char fname[64]; + snprintf(fname, sizeof(fname), "recruit_%s", arch->name[0]); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); + tolua_pushnumber(L, (lua_Number)amount); + + if (lua_pcall(L, 2, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("use(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("use(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } + return result; +} + +int +tolua_toid(lua_State* L, int idx, int def) +{ + int no = 0; + int type = lua_type(L, idx); + if (type==LUA_TNUMBER) { + no = (int)tolua_tonumber(L, idx, def); + } else { + const char * str = tolua_tostring(L, idx, NULL); + no = str?atoi36(str):def; + } + return no; +} + +void +register_tolua_helpers(void) +{ + at_building_action.age = lc_age; + + register_function((pf_generic)&lua_building_protection, TOLUA_CAST "lua_building_protection"); + register_function((pf_generic)&lua_building_taxes, TOLUA_CAST "lua_building_taxes"); + register_function((pf_generic)&lua_agebuilding, TOLUA_CAST "lua_agebuilding"); + register_function((pf_generic)&lua_recruit, TOLUA_CAST "lua_recruit"); + register_function((pf_generic)&lua_callspell, TOLUA_CAST "lua_castspell"); + register_function((pf_generic)&lua_initfamiliar, TOLUA_CAST "lua_initfamiliar"); + register_item_use(&lua_useitem, TOLUA_CAST "lua_useitem"); + register_function((pf_generic)&lua_getresource, TOLUA_CAST "lua_getresource"); + register_function((pf_generic)&lua_canuse_item, TOLUA_CAST "lua_canuse_item"); + register_function((pf_generic)&lua_changeresource, TOLUA_CAST "lua_changeresource"); + register_function((pf_generic)&lua_equipmentcallback, TOLUA_CAST "lua_equip"); + + register_function((pf_generic)&lua_wage, TOLUA_CAST "lua_wage"); + register_function((pf_generic)&lua_maintenance, TOLUA_CAST "lua_maintenance"); + + + register_function((pf_generic)produce_resource, TOLUA_CAST "lua_produceresource"); + register_function((pf_generic)limit_resource, TOLUA_CAST "lua_limitresource"); + register_item_give(lua_giveitem, TOLUA_CAST "lua_giveitem"); +} diff --git a/src/bindings/helpers.h b/src/bindings/helpers.h new file mode 100644 index 000000000..8d3370650 --- /dev/null +++ b/src/bindings/helpers.h @@ -0,0 +1,23 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + void register_tolua_helpers(void); + int tolua_toid(struct lua_State* L, int idx, int def); + +#ifdef __cplusplus +} +#endif diff --git a/src/build/atoi36.c b/src/build/atoi36.c new file mode 100644 index 000000000..4f896a1e7 --- /dev/null +++ b/src/build/atoi36.c @@ -0,0 +1,6 @@ +#include "common/settings.h" +#include "common/config.h" +#include "stdafx.h" + +#include "common/util/base36.c" +#include "tools/atoi36.c" diff --git a/src/build/external.c b/src/build/external.c new file mode 100644 index 000000000..a882ce3fe --- /dev/null +++ b/src/build/external.c @@ -0,0 +1,18 @@ +#include +#include +#include "stdafx.h" + +#pragma warning(push) +#pragma warning(disable: 4244) +#pragma warning(disable: 4127) +#include +#pragma warning(pop) + +#include + +#include +#include + +#ifndef DISABLE_TESTS +#include +#endif diff --git a/src/build/gamecode.c b/src/build/gamecode.c new file mode 100644 index 000000000..63120bde0 --- /dev/null +++ b/src/build/gamecode.c @@ -0,0 +1,80 @@ +#include +#include +#include "stdafx.h" + +#ifdef BINDINGS_TOLUA +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/src/build/kernel.c b/src/build/kernel.c new file mode 100644 index 000000000..9ac333f94 --- /dev/null +++ b/src/build/kernel.c @@ -0,0 +1,53 @@ +#include +#include +#include "stdafx.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/src/build/lib.c b/src/build/lib.c new file mode 100644 index 000000000..18624376a --- /dev/null +++ b/src/build/lib.c @@ -0,0 +1,7 @@ +#include +#include +#include "stdafx.h" + +#include +#include +#include diff --git a/src/build/stdafx.c b/src/build/stdafx.c new file mode 100644 index 000000000..fd4f341c7 --- /dev/null +++ b/src/build/stdafx.c @@ -0,0 +1 @@ +#include "stdafx.h" diff --git a/src/build/stdafx.h b/src/build/stdafx.h new file mode 100644 index 000000000..b0d94063d --- /dev/null +++ b/src/build/stdafx.h @@ -0,0 +1,2 @@ +#include +#include diff --git a/src/build/util.c b/src/build/util.c new file mode 100644 index 000000000..dfae8d012 --- /dev/null +++ b/src/build/util.c @@ -0,0 +1,40 @@ +#include +#include +#include "stdafx.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef HAVE_INLINE +#include +#endif + +#ifdef __GNUC__ +#include +#endif diff --git a/src/eressea.c b/src/eressea.c new file mode 100644 index 000000000..3a8dd4740 --- /dev/null +++ b/src/eressea.c @@ -0,0 +1,212 @@ +#include +#include "settings.h" +#include "eressea.h" + +#include +#include +#include + +/* lua includes */ +#ifdef BINDINGS_TOLUA +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // BINDINGS_TOLUA + +#if MUSEUM_MODULE +#include +#endif +#if ARENA_MODULE +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static const struct { + const char * name; + int (*func)(lua_State *); +} lualibs[] = { + {"", luaopen_base}, + {LUA_TABLIBNAME, luaopen_table}, + {LUA_IOLIBNAME, luaopen_io}, + {LUA_STRLIBNAME, luaopen_string}, + {LUA_MATHLIBNAME, luaopen_math}, + {LUA_LOADLIBNAME, luaopen_package}, + {LUA_DBLIBNAME, luaopen_debug}, +#if LUA_VERSION_NUM>=501 + {LUA_OSLIBNAME, luaopen_os}, +#endif + { NULL, NULL } +}; + +static void +openlibs(lua_State * L) +{ + int i; + for (i=0;lualibs[i].func;++i) { + lua_pushcfunction(L, lualibs[i].func); + lua_pushstring(L, lualibs[i].name); + lua_call(L, 1, 0); + } +} + +static void +lua_done(lua_State * L) +{ + lua_close(L); +} + +static lua_State * +lua_init(void) +{ + lua_State * L = lua_open(); + + openlibs(L); +#ifdef BINDINGS_TOLUA + register_tolua_helpers(); + tolua_eressea_open(L); + tolua_sqlite_open(L); + tolua_unit_open(L); + tolua_building_open(L); + tolua_ship_open(L); + tolua_region_open(L); + tolua_faction_open(L); + tolua_attrib_open(L); + tolua_unit_open(L); + tolua_message_open(L); + tolua_hashtable_open(L); + tolua_gmtool_open(L); + tolua_storage_open(L); +#endif + return L; +} + +static void +game_done(void) +{ +#ifdef CLEANUP_CODE + /* Diese Routine enfernt allen allokierten Speicher wieder. Das ist nur + * zum Debugging interessant, wenn man Leak Detection hat, und nach + * nicht freigegebenem Speicher sucht, der nicht bis zum Ende benötigt + * wird (temporäre Hilsstrukturen) */ + + free_game(); + + creport_cleanup(); +#ifdef REPORT_FORMAT_NR + report_cleanup(); +#endif + calendar_cleanup(); +#endif +} + +static void +game_init(void) +{ + register_triggers(); + register_xmas(); + + register_reports(); + register_nr(); + register_cr(); + register_xr(); + + debug_language("locales.log"); + register_names(); + register_resources(); + register_buildings(); + register_itemfunctions(); +#if DUNGEON_MODULE + register_dungeon(); +#endif +#if MUSEUM_MODULE + register_museum(); +#endif +#if ARENA_MODULE + register_arena(); +#endif + register_wormholes(); + + register_itemtypes(); + register_xmlreader(); + register_archetypes(); + enable_xml_gamecode(); + + register_attributes(); + register_gmcmd(); + +} + +int eressea_init(void) +{ + global.vm_state = lua_init(); + kernel_init(); + game_init(); + + return 0; +} + +void eressea_done(void) +{ + game_done(); + kernel_done(); + lua_done((lua_State *)global.vm_state); +} + +int eressea_run(const char * luafile, const char * entry_point) +{ + int err; + lua_State * L = (lua_State *)global.vm_state; + /* run the main script */ + if (luafile) { + lua_getglobal(L, "dofile"); + lua_pushstring(L, luafile); + err = lua_pcall(L, 1, 0, 0); + if (err != 0) { + log_lua_error(L); + abort(); + return err; + } + } + if (entry_point) { + lua_getglobal(L, entry_point); + err = lua_pcall(L, 0, 1, 0); + if (err != 0) { + log_lua_error(L); + abort(); + return err; + } + } else { + err = lua_console(L); + } + return err; +} diff --git a/src/eressea.h b/src/eressea.h new file mode 100644 index 000000000..c2d15d458 --- /dev/null +++ b/src/eressea.h @@ -0,0 +1,15 @@ +#ifndef H_ERESSEA_LIB +#define H_ERESSEA_LIB +#ifdef __cplusplus +extern "C" { +#endif + +int eressea_init(void); +void eressea_done(void); +int eressea_run(const char * luafile, const char * entry_point); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/gamecode.vcproj b/src/gamecode.vcproj new file mode 100644 index 000000000..27c322ae1 --- /dev/null +++ b/src/gamecode.vcproj @@ -0,0 +1,354 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gamecode.vcxproj b/src/gamecode.vcxproj new file mode 100644 index 000000000..c955d12d1 --- /dev/null +++ b/src/gamecode.vcxproj @@ -0,0 +1,141 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {1E8BFF9E-3044-0742-992F-C5765B80FE65} + gamecode + Win32Proj + + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + + + + /MP %(AdditionalOptions) + Disabled + .;../../external;%(AdditionalIncludeDirectories) + WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + + + Level4 + true + EditAndContinue + + + WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + ..;.;%(AdditionalIncludeDirectories) + + + $(OutDir)gamecode.lib + + + + + Full + .;../../external;%(AdditionalIncludeDirectories) + WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + + + Level4 + + + + + WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) + ..;.;%(AdditionalIncludeDirectories) + + + $(OutDir)gamecode.lib + + + + + + + + + + + + + + true + true + + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/gamecode.vcxproj.filters b/src/gamecode.vcxproj.filters new file mode 100644 index 000000000..8eb7a6651 --- /dev/null +++ b/src/gamecode.vcxproj.filters @@ -0,0 +1,131 @@ + + + + + {d83e7c3e-0495-4145-86ea-a86b7d4d405b} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {7553a025-8a64-4b5a-90cb-a2eeae9190d3} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/src/gamecode/archetype.c b/src/gamecode/archetype.c new file mode 100644 index 000000000..8f82e7d31 --- /dev/null +++ b/src/gamecode/archetype.c @@ -0,0 +1,165 @@ +#include +#include +#include "archetype.h" + +/* kernel includes */ +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include + +/* libxml includes */ +#include +#include +#include + +/* libc includes */ +#include +#include + +static struct archetype * archetypes; + +struct attrib_type at_recruit = { + "recruit", NULL, NULL, NULL, NULL, NULL, ATF_UNIQUE +}; + +const struct archetype * +find_archetype(const char * s, const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_ARCHETYPES); + variant token; + + if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { + return (const struct archetype *)token.v; + } + return NULL; +} + +void +register_archetype(archetype * arch) +{ + arch->next = archetypes; + archetypes = arch; +} + +void +init_archetypes(void) +{ + const struct locale * lang = locales; + for (;lang;lang=nextlocale(lang)) { + variant var; + archetype * arch = archetypes; + struct tnode * tokens = get_translations(lang, UT_ARCHETYPES); + for (;arch;arch=arch->next) { + const char *s1, *s2; + var.v = arch; + + s1 = LOC(lang, arch->name[0]); + addtoken(tokens, s1, var); + s2 = LOC(lang, arch->name[1]); + if (strcmp(s2, s1)!=0) { + addtoken(tokens, s2, var); + } + } + } +} + +static int +parse_archetypes(xmlDocPtr doc) +{ + char zName[64]; + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr result = xmlXPathEvalExpression(BAD_CAST "/eressea/archetypes/archetype", xpath); + xmlNodeSetPtr nodes = result->nodesetval; + + xmlChar * propValue; + if (nodes) { + int i; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + xmlNodePtr child; + archetype * arch = calloc(1, sizeof(archetype)); + xmlXPathObjectPtr sub; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + arch->name[0] = strdup((const char *)propValue); + sprintf(zName, "%s_p", arch->name[0]); + arch->name[1] = strdup(zName); + xmlFree(propValue); + + propValue = xmlGetProp(node, BAD_CAST "equip"); + if (propValue!=NULL) { + arch->equip = get_equipment((const char*)propValue); + xmlFree(propValue); + } else { + arch->equip = get_equipment(arch->name[0]); + } + + propValue = xmlGetProp(node, BAD_CAST "building"); + if (propValue!=NULL) { + arch->btype = bt_find((const char*)propValue); + xmlFree(propValue); + } + + arch->size = xml_ivalue(node, "cost", 0); + + for (child=node->children;child;child=child->next) { + if (strcmp((const char *)child->name, "function")==0) { + xmlChar * propName = xmlGetProp(child, BAD_CAST "name"); + xmlChar * propValue = xmlGetProp(child, BAD_CAST "value"); + if (strcmp((const char *)propName, "create")) { + pf_generic foo = get_function((const char *)propValue); + arch->exec = (archetype_function)foo; + } + xmlFree(propValue); + xmlFree(propName); + } + } + xpath->node = node; + sub = xmlXPathEvalExpression(BAD_CAST "allow|deny", xpath); + if (sub->nodesetval && sub->nodesetval->nodeNr) { + int k; + arch->rules = calloc(sub->nodesetval->nodeNr+1, sizeof(rule)); + for (k=0;k!=sub->nodesetval->nodeNr;++k) { + xmlNodePtr rule = sub->nodesetval->nodeTab[k]; + arch->rules[k].allow = (rule->name[0]=='a'); + + propValue = xmlGetProp(rule, BAD_CAST "property"); + arch->rules[k].property = strdup((const char *)propValue); + xmlFree(propValue); + + propValue = xmlGetProp(rule, BAD_CAST "value"); + arch->rules[k].value = strdup((const char *)propValue); + xmlFree(propValue); + } + } + xmlXPathFreeObject(sub); + + xpath->node = node; + sub = xmlXPathEvalExpression(BAD_CAST "construction", xpath); + if (sub->nodesetval) { + xml_readconstruction(xpath, sub->nodesetval, &arch->ctype); + } + xmlXPathFreeObject(sub); + register_archetype(arch); + } + } + xmlXPathFreeObject(result); + + xmlXPathFreeContext(xpath); + return 0; +} + +void +register_archetypes(void) +{ + xml_register_callback(parse_archetypes); +} diff --git a/src/gamecode/archetype.h b/src/gamecode/archetype.h new file mode 100644 index 000000000..358946ccd --- /dev/null +++ b/src/gamecode/archetype.h @@ -0,0 +1,51 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2007 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifndef H_GC_ARCHETYPE +#define H_GC_ARCHETYPE + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct rule { + boolean allow; + char * property; + char * value; + } rule; + + struct archetype; + typedef int (*archetype_function)(struct unit * u, const struct archetype *, int); + + typedef struct archetype { + struct archetype * next; + char * name[2]; + int size; + struct building_type * btype; + struct equipment * equip; + struct construction * ctype; + struct rule * rules; + archetype_function exec; + } archetype; + + extern const struct archetype * find_archetype(const char * s, const struct locale * lang); + extern void init_archetypes(void); + extern void register_archetype(struct archetype * arch); + extern void register_archetypes(void); + + extern struct attrib_type at_recruit; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/gamecode/creation.c b/src/gamecode/creation.c new file mode 100644 index 000000000..b22dedaa8 --- /dev/null +++ b/src/gamecode/creation.c @@ -0,0 +1,73 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "creation.h" +#include "monster.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +faction * +createmonsters(int no) +{ + faction *f = findfaction(no); + + if (f) { + puts("* Fehler! Die Monster Partei gibt es schon."); + return f; + } + f = (faction *) calloc(1, sizeof(faction)); + f->no = no; + /* alles ist auf null gesetzt, ausser dem folgenden. achtung - partei + * no 0 muss keine orders einreichen! */ + + f->email = strdup("monsters@eressea.de"); + f->name = strdup("Monster"); + f->alive = 1; + f->options = (char)(1< + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_GC_CREATION +#define H_GC_CREATION +#ifdef __cplusplus +extern "C" { +#endif + +struct faction * createmonsters(int no); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c new file mode 100644 index 000000000..edef15247 --- /dev/null +++ b/src/gamecode/creport.c @@ -0,0 +1,1608 @@ +/* vi: set ts=2: ++-------------------+ Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel ++-------------------+ +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "creport.h" + +/* tweakable features */ +#define RENDER_CRMESSAGES +#define BUFFERSIZE 32768 +#define RESOURCECOMPAT + +/* modules include */ +#include + +/* attributes include */ +#include +#include +#include +#include +#include + +/* gamecode includes */ +#include "laws.h" +#include "economy.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include +#include + +/* imports */ +extern int verbosity; +boolean opt_cr_absolute_coords = false; + +/* globals */ +#define C_REPORT_VERSION 66 + +#define TAG_LOCALE "de" +#ifdef TAG_LOCALE +static const char * +crtag(const char * key) +{ + static const struct locale * lang = NULL; + if (!lang) lang = find_locale(TAG_LOCALE); + return locale_string(lang, key); +} +#else +#define crtag(x) (x) +#endif +/* + * translation table + */ +typedef struct translation { + struct translation * next; + char * key; + const char * value; +} translation; + +#define TRANSMAXHASH 257 +static translation * translation_table[TRANSMAXHASH]; +static translation * junkyard; + +static const char * +add_translation(const char * key, const char * value) +{ + int kk = ((key[0] << 5) + key[0]) % TRANSMAXHASH; + translation * t = translation_table[kk]; + while (t && strcmp(t->key, key)!=0) t=t->next; + if (!t) { + if (junkyard) { + t = junkyard; + junkyard = junkyard->next; + } else t = malloc(sizeof(translation)); + t->key = strdup(key); + t->value = value; + t->next = translation_table[kk]; + translation_table[kk] = t; + } + return crtag(key); +} + +static void +write_translations(FILE * F) +{ + int i; + fputs("TRANSLATION\n", F); + for (i=0;i!=TRANSMAXHASH;++i) { + translation * t = translation_table[i]; + while (t) { + fprintf(F, "\"%s\";%s\n", t->value, crtag(t->key)); + t = t->next; + } + } +} + +static void +reset_translations(void) +{ + int i; + for (i=0;i!=TRANSMAXHASH;++i) { + translation * t = translation_table[i]; + while (t) { + translation * c = t->next; + free(t->key); + t->next = junkyard; + junkyard = t; + t = c; + } + translation_table[i] = 0; + } +} + +#include + +static void +print_items(FILE * F, item * items, const struct locale * lang) +{ + item * itm; + + for (itm=items; itm; itm=itm->next) { + int in = itm->number; + const char * ic = resourcename(itm->type->rtype, 0); + if (itm==items) fputs("GEGENSTAENDE\n", F); + fprintf(F, "%d;%s\n", in, add_translation(ic, LOC(lang, ic))); + } +} + +static void +cr_output_curses(FILE * F, const faction * viewer, const void * obj, typ_t typ) +{ + boolean header = false; + attrib *a = NULL; + int self = 0; + region *r; + + /* Die Sichtbarkeit eines Zaubers und die Zaubermeldung sind bei + * Gebäuden und Schiffen je nach, ob man Besitzer ist, verschieden. + * Bei Einheiten sieht man Wirkungen auf eigene Einheiten immer. + * Spezialfälle (besonderes Talent, verursachender Magier usw. werde + * bei jedem curse gesondert behandelt. */ + if (typ == TYP_SHIP){ + ship * sh = (ship*)obj; + unit * owner = shipowner(sh); + a = sh->attribs; + r = sh->region; + if (owner != NULL) { + if (owner->faction == viewer){ + self = 2; + } else { /* steht eine person der Partei auf dem Schiff? */ + unit *u = NULL; + for (u = r->units; u; u = u->next) { + if (u->ship == sh) { + self = 1; + break; + } + } + } + } + } else if (typ == TYP_BUILDING) { + building * b = (building*)obj; + unit * owner = building_owner(b); + a = b->attribs; + r = b->region; + if (owner != NULL){ + if (owner->faction == viewer){ + self = 2; + } else { /* steht eine Person der Partei in der Burg? */ + unit *u = NULL; + for (u = r->units; u; u = u->next) { + if (u->building == b) { + self = 1; + break; + } + } + } + } + } else if (typ == TYP_UNIT) { + unit *u = (unit *)obj; + a = u->attribs; + r = u->region; + if (u->faction == viewer) { + self = 2; + } + } else if (typ == TYP_REGION) { + r = (region *)obj; + a = r->attribs; + } else { + /* fehler */ + } + + while (a) { + if (fval(a->type, ATF_CURSE)) { + curse * c = (curse *)a->data.v; + message * msg; + + if (c->type->cansee) { + self = c->type->cansee(viewer, obj, typ, c, self); + } + msg = msg_curse(c, obj, typ, self); + + if (msg) { + char buf[BUFFERSIZE]; + if (!header) { + header = 1; + fputs("EFFECTS\n", F); + } + nr_render(msg, viewer->locale, buf, sizeof(buf), viewer); + fprintf(F, "\"%s\"\n", buf); + msg_release(msg); + } + } else if (a->type==&at_effect && self) { + effect_data * data = (effect_data *)a->data.v; + if (data->value>0) { + const char * key = resourcename(data->type->itype->rtype, 0); + if (!header) { + header = 1; + fputs("EFFECTS\n", F); + } + fprintf(F, "\"%d %s\"\n", data->value, add_translation(key, locale_string(default_locale, key))); + } + } + a = a->next; + } +} + +static int +cr_unit(variant var, char * buffer, const void * userdata) +{ + unit * u = (unit *)var.v; + sprintf(buffer, "%d", u?u->no:-1); + return 0; +} + +static int +cr_ship(variant var, char * buffer, const void * userdata) +{ + ship * u = (ship *)var.v; + sprintf(buffer, "%d", u?u->no:-1); + return 0; +} + +static int +cr_building(variant var, char * buffer, const void * userdata) +{ + building * u = (building *)var.v; + sprintf(buffer, "%d", u?u->no:-1); + return 0; +} + +static int +cr_faction(variant var, char * buffer, const void * userdata) +{ + faction * f = (faction *)var.v; + sprintf(buffer, "%d", f?f->no:-1); + return 0; +} + +static int +cr_region(variant var, char * buffer, const void * userdata) +{ + const faction * report = (const faction*)userdata; + region * r = (region *)var.v; + if (r) { + plane * pl = rplane(r); + int nx = r->x, ny = r->y; + pnormalize(&nx, &ny, pl); + adjust_coordinates(report, &nx, &ny, pl, r); + sprintf(buffer, "%d %d %d", nx, ny, plane_id(pl)); + return 0; + } + return -1; +} + +static int +cr_resource(variant var, char * buffer, const void * userdata) +{ + const faction * report = (const faction*)userdata; + const resource_type * r = (const resource_type *)var.v; + if (r) { + const char * key = resourcename(r, 0); + sprintf(buffer, "\"%s\"", + add_translation(key, locale_string(report->locale, key))); + return 0; + } + return -1; +} + +static int +cr_race(variant var, char * buffer, const void * userdata) +{ + const faction * report = (const faction*)userdata; + const struct race * rc = (const race *)var.v; + const char * key = rc_name(rc, 0); + sprintf(buffer, "\"%s\"", + add_translation(key, locale_string(report->locale, key))); + return 0; +} + +static int +cr_alliance(variant var, char * buffer, const void * userdata) +{ + const alliance * al = (const alliance *)var.v; + if (al!=NULL) { + sprintf(buffer, "%d", al->id); + } + unused(userdata); + return 0; +} + +static int +cr_skill(variant var, char * buffer, const void * userdata) +{ + const faction * report = (const faction*)userdata; + skill_t sk = (skill_t)var.i; + if (sk!=NOSKILL) sprintf(buffer, "\"%s\"", + add_translation(mkname("skill", skillnames[sk]), skillname(sk, report->locale))); + else strcpy(buffer, "\"\""); + return 0; +} + +static int +cr_order(variant var, char * buffer, const void * userdata) +{ + order * ord = (order*)var.v; + if (ord!=NULL) { + char * wp = buffer; + char * cmd = getcommand(ord); + const char * rp = cmd; + + *wp++ = '\"'; + while (*rp) { + switch (*rp) { + case '\"': + case '\\': + *wp++ = '\\'; + default: + *wp++ = *rp++; + } + } + *wp++ = '\"'; + *wp++ = 0; + + free(cmd); + } + else strcpy(buffer, "\"\""); + return 0; +} + +static int +cr_resources(variant var, char * buffer, const void * userdata) +{ + faction * f = (faction*)userdata; + resource * rlist = (resource*)var.v; + char * wp = buffer; + if (rlist!=NULL) { + const char * name = resourcename(rlist->type, rlist->number!=1); + wp += sprintf(wp, "\"%d %s", rlist->number, add_translation(name, LOC(f->locale, name))); + for (;;) { + rlist = rlist->next; + if (rlist==NULL) break; + name = resourcename(rlist->type, rlist->number!=1); + wp += sprintf(wp, ", %d %s", rlist->number, add_translation(name, LOC(f->locale, name))); + } + strcat(wp, "\""); + } + return 0; +} + +static int +cr_regions(variant var, char * buffer, const void * userdata) +{ + faction * f = (faction*)userdata; + const arg_regions * rdata = (const arg_regions *)var.v; + + if (rdata!=NULL && rdata->nregions>0) { + region * r = rdata->regions[0]; + plane * pl = rplane(r); + int i, z = plane_id(pl); + char * wp = buffer; + int nx = r->x, ny = r->y; + + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl, r); + wp += sprintf(wp, "\"%d %d %d", nx, ny, z); + for (i=1;i!=rdata->nregions;++i) { + r = rdata->regions[i]; + pl = rplane(r); + z = plane_id(pl); + wp += sprintf(wp, ", %d %d %d", nx, ny, z); + } + strcat(wp, "\""); + } else { + strcpy(buffer, "\"\""); + } + return 0; +} + +static int +cr_spell(variant var, char * buffer, const void * userdata) +{ + const faction * report = (const faction*)userdata; + spell * sp = (spell*)var.v; + if (sp!=NULL) sprintf(buffer, "\"%s\"", spell_name(sp, report->locale)); + else strcpy(buffer, "\"\""); + return 0; +} + +static int +cr_curse(variant var, char * buffer, const void * userdata) +{ + const faction * report = (const faction*)userdata; + const curse_type * ctype = (const curse_type*)var.v; + if (ctype!=NULL) { + sprintf(buffer, "\"%s\"", curse_name(ctype, report->locale)); + } else strcpy(buffer, "\"\""); + return 0; +} + +/*static int msgno; */ + +#define MTMAXHASH 1021 + +static struct known_mtype { + const struct message_type * mtype; + struct known_mtype * nexthash; +} * mtypehash[MTMAXHASH]; + +static void +report_crtypes(FILE * F, const struct locale* lang) +{ + int i; + for (i=0;i!=MTMAXHASH;++i) { + struct known_mtype * kmt; + for (kmt=mtypehash[i];kmt;kmt=kmt->nexthash) { + const struct nrmessage_type * nrt = nrt_find(lang, kmt->mtype); + if (nrt) { + unsigned int hash = kmt->mtype->key; + fprintf(F, "MESSAGETYPE %d\n", hash); + fputc('\"', F); + fputs(escape_string(nrt_string(nrt), NULL, 0), F); + fputs("\";text\n", F); + fprintf(F, "\"%s\";section\n", nrt_section(nrt)); + } + } + while (mtypehash[i]) { + kmt = mtypehash[i]; + mtypehash[i] = mtypehash[i]->nexthash; + free(kmt); + } + } +} + +static unsigned int +messagehash(const struct message * msg) +{ + variant var; + var.v = (void *)msg; + return (unsigned int)var.i; +} + +static void +render_messages(FILE * F, faction * f, message_list *msgs) +{ + struct mlist* m = msgs->begin; + while (m) { + char crbuffer[BUFFERSIZE]; /* gross, wegen spionage-messages :-( */ + boolean printed = false; + const struct message_type * mtype = m->msg->type; + unsigned int hash = mtype->key; +#ifdef RENDER_CRMESSAGES + char nrbuffer[1024*32]; + nrbuffer[0] = '\0'; + if (nr_render(m->msg, f->locale, nrbuffer, sizeof(nrbuffer), f)>=0) { + fprintf(F, "MESSAGE %u\n", messagehash(m->msg)); + fprintf(F, "%d;type\n", hash); + fwritestr(F, nrbuffer); + fputs(";rendered\n", F); + printed = true; + } +#endif + crbuffer[0] = '\0'; + if (cr_render(m->msg, crbuffer, (const void*)f)==0) { + if (!printed) fprintf(F, "MESSAGE %u\n", messagehash(m->msg)); + if (crbuffer[0]) fputs(crbuffer, F); + } else { + log_error(("could not render cr-message %p: %s\n", m->msg, m->msg->type->name)); + } + if (printed) { + unsigned int ihash = hash % MTMAXHASH; + struct known_mtype * kmt = mtypehash[ihash]; + while (kmt && kmt->mtype != mtype) kmt = kmt->nexthash; + if (kmt==NULL) { + kmt = (struct known_mtype*)malloc(sizeof(struct known_mtype)); + kmt->nexthash = mtypehash[ihash]; + kmt->mtype = mtype; + mtypehash[ihash] = kmt; + } + } + m = m->next; + } +} + +static void +cr_output_messages(FILE * F, message_list *msgs, faction * f) +{ + if (msgs) render_messages(F, f, msgs); +} + +/* prints a building */ +static void +cr_output_building(FILE * F, building * b, const unit * owner, int fno, faction *f) +{ + const char * bname, * billusion; + + fprintf(F, "BURG %d\n", b->no); + + report_building(b, &bname, &billusion); + if (billusion) { + fprintf(F, "\"%s\";Typ\n", add_translation(billusion, LOC(f->locale, billusion))); + if (owner && owner->faction==f) { + fprintf(F, "\"%s\";wahrerTyp\n", add_translation(bname, LOC(f->locale, bname))); + } + } else { + fprintf(F, "\"%s\";Typ\n", add_translation(bname, LOC(f->locale, bname))); + } + 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 ? owner->no : -1); + if (fno >= 0) + fprintf(F, "%d;Partei\n", fno); + if (b->besieged) + fprintf(F, "%d;Belagerer\n", b->besieged); + cr_output_curses(F, f, b, TYP_BUILDING); +} +/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ + +/* prints a ship */ +static void +cr_output_ship(FILE * F, 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); + if (sh->display && sh->display[0]) + fprintf(F, "\"%s\";Beschr\n", sh->display); + fprintf(F, "\"%s\";Typ\n", add_translation(sh->type->name[0], locale_string(f->locale, sh->type->name[0]))); + fprintf(F, "%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); + } + if (u) + fprintf(F, "%d;Kapitaen\n", u ? u->no : -1); + 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)); + } + /* shore */ + w = NODIRECTION; + if (!fval(r->terrain, SEA_REGION)) w = sh->coast; + if (w != NODIRECTION) + fprintf(F, "%d;Kueste\n", w); + + cr_output_curses(F, f, sh, TYP_SHIP); +} + +static void +fwriteorder(FILE * F, const struct order * ord, const struct locale * lang, boolean escape) +{ + char ebuf[1024]; + char obuf[1024]; + const char * str = obuf; + fputc('"', F); + write_order(ord, obuf, sizeof(obuf)); + if (escape) { + str = escape_string(obuf, ebuf, sizeof(ebuf)); + } + if (str[0]) fputs(str, F); + fputc('"', F); +} + +static void cr_output_spells(FILE * F, spell_list * slist, const faction * f, int maxlevel) +{ + if (slist) { + fprintf(F, "SPRUECHE\n"); + for (;slist; slist = slist->next) { + spell * sp = slist->data; + if (sp->level <= maxlevel) { + const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, f->locale)); + fprintf(F, "\"%s\"\n", name); + } + } + } +} + +/* prints all that belongs to a unit */ +static void +cr_output_unit(FILE * F, const region * r, + const faction * f, /* observers faction */ + const unit * u, int mode) +{ + /* Race attributes are always plural and item attributes always + * singular */ + const char * str; + const item_type * lasttype; + int pr; + item *itm, *show; + building * b; + const char * pzTmp; + skill * sv; + const attrib *a_fshidden = NULL; + boolean itemcloak = false; + static const curse_type * itemcloak_ct = 0; + static boolean init = false; + item result[MAX_INVENTORY]; + + if (fval(u->race, RCF_INVISIBLE)) return; + + if (!init) { + init = true; + itemcloak_ct = ct_find("itemcloak"); + } + if (itemcloak_ct!=NULL) { + itemcloak = curse_active(get_curse(u->attribs, itemcloak_ct)); + } + + assert(u && u->number); + + fprintf(F, "EINHEIT %d\n", u->no); + fprintf(F, "\"%s\";Name\n", u->name); + str = u_description(u, f->locale); + if (str) { + fprintf(F, "\"%s\";Beschr\n", str); + } + { + /* print faction information */ + const faction * sf = visible_faction(f, u); + const char * prefix = raceprefix(u); + if (u->faction == f || omniscient(f)) { + const attrib * a_otherfaction = a_find(u->attribs, &at_otherfaction); + const faction * otherfaction = a_otherfaction?get_otherfaction(a_otherfaction):NULL; + /* my own faction, full info */ + const attrib *a = NULL; + unit * mage; + + if (fval(u, UFL_GROUP)) a = a_find(u->attribs, &at_group); + if (a!=NULL) { + const group * g = (const group*)a->data.v; + fprintf(F, "%d;gruppe\n", g->gid); + } + fprintf(F, "%d;Partei\n", u->faction->no); + if (sf!=u->faction) fprintf(F, "%d;Verkleidung\n", sf->no); + if (fval(u, UFL_ANON_FACTION)) + fprintf(F, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION))); + if (otherfaction) { + if (otherfaction!=u->faction) { + fprintf(F, "%d;Anderepartei\n", otherfaction->no); + } + } + mage = get_familiar_mage(u); + if (mage) { + fprintf(F, "%u;familiarmage\n", mage->no); + } + } else { + if (fval(u, UFL_ANON_FACTION)) { + /* faction info is hidden */ + fprintf(F, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION))); + } else { + const attrib * a_otherfaction = a_find(u->attribs, &at_otherfaction); + const faction * otherfaction = a_otherfaction?get_otherfaction(a_otherfaction):NULL; + /* other unit. show visible faction, not u->faction */ + fprintf(F, "%d;Partei\n", sf->no); + if (sf == f) { + fprintf(F, "1;Verraeter\n"); + } + if (a_otherfaction) { + if (otherfaction!=u->faction) { + if (alliedunit(u, f, HELP_FSTEALTH)) { + fprintf(F, "%d;Anderepartei\n", otherfaction->no); + } + } + } + } + } + if (prefix) { + prefix = mkname("prefix", prefix); + fprintf(F, "\"%s\";typprefix\n", add_translation(prefix, LOC(f->locale, prefix))); + } + } + if (u->faction != f && a_fshidden + && a_fshidden->data.ca[0] == 1 && effskill(u, SK_STEALTH) >= 6) { + fprintf(F, "-1;Anzahl\n"); + } else { + fprintf(F, "%d;Anzahl\n", u->number); + } + + pzTmp = get_racename(u->attribs); + if (pzTmp) { + fprintf(F, "\"%s\";Typ\n", pzTmp); + if (u->faction==f && fval(u->race, RCF_SHAPESHIFTANY)) { + const char * zRace = rc_name(u->race, 1); + fprintf(F, "\"%s\";wahrerTyp\n", + add_translation(zRace, locale_string(f->locale, zRace))); + } + } else { + const race * irace = u_irace(u); + const char * zRace = rc_name(irace, 1); + fprintf(F, "\"%s\";Typ\n", + add_translation(zRace, locale_string(f->locale, zRace))); + if (u->faction==f && irace!=u->race) { + assert(skill_enabled[SK_STEALTH] || !"we're resetting this on load, so.. ircase should never be used"); + zRace = rc_name(u->race, 1); + fprintf(F, "\"%s\";wahrerTyp\n", + add_translation(zRace, locale_string(f->locale, zRace))); + } + } + + if (u->building) { + assert(u->building->region); + fprintf(F, "%d;Burg\n", u->building->no); + } + if (u->ship) { + assert(u->ship->region); + fprintf(F, "%d;Schiff\n", u->ship->no); + } + if (is_guard(u, GUARD_ALL)!=0) { + fprintf(F, "%d;bewacht\n", 1); + } + if ((b=usiege(u))!=NULL) { + fprintf(F, "%d;belagert\n", b->no); + } + /* additional information for own units */ + if (u->faction == f || omniscient(f)) { + order * ord; + const char *xc; + const char * c; + int i; + + i = ualias(u); + if (i>0) + fprintf(F, "%d;temp\n", i); + else if (i<0) + fprintf(F, "%d;alias\n", -i); + i = get_money(u); + fprintf(F, "%d;Kampfstatus\n", u->status); + fprintf(F, "%d;weight\n", weight(u)); + if (fval(u, UFL_NOAID)) { + fputs("1;unaided\n", F); + } + if (fval(u, UFL_STEALTH)) { + i = u_geteffstealth(u); + if (i >= 0) { + fprintf(F, "%d;Tarnung\n", i); + } + } + xc = uprivate(u); + if (xc) { + fprintf(F, "\"%s\";privat\n", xc); + } + c = hp_status(u); + if (c && *c && (u->faction == f || omniscient(f))) { + fprintf(F, "\"%s\";hp\n", add_translation(c, locale_string(u->faction->locale, c))); + } + if (fval(u, UFL_HERO)) { + fputs("1;hero\n", F); + } + + if (fval(u, UFL_HUNGER) && (u->faction == f)) { + fputs("1;hunger\n", F); + } + if (is_mage(u)) { + fprintf(F, "%d;Aura\n", get_spellpoints(u)); + fprintf(F, "%d;Auramax\n", max_spellpoints(u->region,u)); + } + /* default commands */ + fprintf(F, "COMMANDS\n"); + for (ord = u->old_orders; ord; ord = ord->next) { + /* this new order will replace the old defaults */ + if (is_persistent(ord)) { + fwriteorder(F, ord, f->locale, true); + fputc('\n', F); + } + } + for (ord = u->orders; ord; ord = ord->next) { + if (u->old_orders && is_repeated(ord)) continue; /* unit has defaults */ + if (is_persistent(ord)) { + fwriteorder(F, ord, f->locale, true); + fputc('\n', F); + } + } + + /* talents */ + pr = 0; + for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { + if (sv->level>0) { + skill_t sk = sv->id; + int esk = eff_skill(u, sk, r); + if (!pr) { + pr = 1; + fprintf(F, "TALENTE\n"); + } + fprintf(F, "%d %d;%s\n", u->number*level_days(sv->level), esk, + add_translation(mkname("skill", skillnames[sk]), skillname(sk, f->locale))); + } + } + /* spells */ + if (is_mage(u)) { + sc_mage * mage = get_mage(u); + spell_list ** slistp = get_spelllist(mage, u->faction); + int i, maxlevel = effskill(u, SK_MAGIC); + + cr_output_spells(F, *slistp, f, maxlevel); + + for (i=0;i!=MAXCOMBATSPELLS;++i) { + const spell * sp = mage->combatspells[i].sp; + if (sp) { + const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, f->locale)); + fprintf(F, "KAMPFZAUBER %d\n", i); + fprintf(F, "\"%s\";name\n", name); + fprintf(F, "%d;level\n", mage->combatspells[i].level); + } + } + } + } + /* items */ + pr = 0; + if (f == u->faction || omniscient(u->faction)) { + show = u->items; + } else if (itemcloak==false && mode>=see_unit && !(a_fshidden + && a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) + { + int n = report_items(u->items, result, MAX_INVENTORY, u, f); + assert(n>=0); + if (n>0) show = result; + else show = NULL; + } else { + show = NULL; + } + lasttype = NULL; + for (itm=show; itm; itm=itm->next) { + const char * ic; + int in; + assert(itm->type!=lasttype || !"error: list contains two objects of the same item"); + report_item(u, itm, f, NULL, &ic, &in, true); + if (in==0) continue; + if (!pr) { + pr = 1; + fputs("GEGENSTAENDE\n", F); + } + fprintf(F, "%d;%s\n", in, add_translation(ic, locale_string(f->locale, ic))); + } + + cr_output_curses(F, f, u, TYP_UNIT); +} +/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ + +/* prints allies */ +static void +show_allies_cr(FILE * F, const faction * f, const ally * sf) +{ + for (; sf; sf = sf->next) if (sf->faction) { + int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); + if (mode!=0 && sf->status>0) { + fprintf(F, "ALLIANZ %d\n", sf->faction->no); + fprintf(F, "\"%s\";Parteiname\n", sf->faction->name); + fprintf(F, "%d;Status\n", sf->status & HELP_ALL); + } + } +} + +/* prints allies */ +static void +show_alliances_cr(FILE * F, const faction * f) +{ + alliance * al = f_get_alliance(f); + if (al) { + faction * lead = alliance_get_leader(al); + assert(lead); + fprintf(F, "ALLIANCE %d\n", al->id); + fprintf(F, "\"%s\";name\n", al->name); + fprintf(F, "%d;leader\n", lead->no); + } +} + +/* prints all visible spells in a region */ +static void +show_active_spells(const region * r) +{ + char fogwall[MAXDIRECTIONS]; +#ifdef TODO /* alte Regionszauberanzeigen umstellen */ + unit *u; + int env = 0; +#endif + memset(fogwall, 0, sizeof(char) * MAXDIRECTIONS); + +} +/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ + +/* this is a copy of laws.c->find_address output changed. */ +static void +cr_find_address(FILE * F, const faction * uf, const faction_list * addresses) +{ + const faction_list * flist = addresses; + while (flist!=NULL) { + const faction * f = flist->data; + if (uf!=f) { + fprintf(F, "PARTEI %d\n", f->no); + fprintf(F, "\"%s\";Parteiname\n", f->name); + if (f->email) fprintf(F, "\"%s\";email\n", f->email); + if (f->banner) fprintf(F, "\"%s\";banner\n", f->banner); + fprintf(F, "\"%s\";locale\n", locale_name(f->locale)); + if (f->alliance && f->alliance==uf->alliance) { + fprintf(F, "%d;alliance\n", f->alliance->id); + } + } + flist = flist->next; + } +} +/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ + +static void +cr_reportspell(FILE * F, spell *sp, const struct locale * lang) +{ + int k; + const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, lang)); + + fprintf(F, "ZAUBER %d\n", hashstring(sp->sname)); + fprintf(F, "\"%s\";name\n", name); + fprintf(F, "%d;level\n", sp->level); + fprintf(F, "%d;rank\n", sp->rank); + fprintf(F, "\"%s\";info\n", spell_info(sp, lang)); + if (sp->parameter) fprintf(F, "\"%s\";syntax\n", sp->parameter); + else fputs("\"\";syntax\n", F); + + if (sp->sptyp & PRECOMBATSPELL) fputs("\"precombat\";class\n", F); + else if (sp->sptyp & COMBATSPELL) fputs("\"combat\";class\n", F); + else if (sp->sptyp & POSTCOMBATSPELL) fputs("\"postcombat\";class\n", F); + else fputs("\"normal\";class\n", F); + + if (sp->sptyp & FARCASTING) fputs("1;far\n", F); + if (sp->sptyp & OCEANCASTABLE) fputs("1;ocean\n", F); + if (sp->sptyp & ONSHIPCAST) fputs("1;ship\n", F); + if (!(sp->sptyp & NOTFAMILIARCAST)) fputs("1;familiar\n", F); + fputs("KOMPONENTEN\n", F); + + for (k = 0; sp->components[k].type; ++k) { + const resource_type * rtype = sp->components[k].type; + int itemanz = sp->components[k].amount; + int costtyp = sp->components[k].cost; + if (itemanz > 0) { + const char * name = resourcename(rtype, 0); + fprintf(F, "%d %d;%s\n", itemanz, costtyp == SPC_LEVEL || costtyp == SPC_LINEAR, + add_translation(name, LOC(lang, name))); + } + } +} + +static char * +cr_output_resource(char * buf, const char * name, const struct locale * loc, int amount, int level) +{ + buf += sprintf(buf, "RESOURCE %u\n", hashstring(name)); + buf += sprintf(buf, "\"%s\";type\n", add_translation(name, LOC(loc, name))); + if (amount>=0) { + if (level>=0) buf += sprintf(buf, "%d;skill\n", level); + buf += sprintf(buf, "%d;number\n", amount); + } + return buf; +} + +static void +cr_borders(seen_region ** seen, const region * r, const faction * f, int seemode, FILE * F) +{ + direction_t d; + int g = 0; + for (d = 0; d != MAXDIRECTIONS; d++) + { /* Nachbarregionen, die gesehen werden, ermitteln */ + const region * r2 = rconnect(r, d); + const connection * b; + if (!r2) continue; + if (seemode==see_neighbour) { + seen_region * sr = find_seen(seen, r2); + if (sr==NULL || sr->mode<=see_neighbour) continue; + } + b = get_borders(r, r2); + while (b) { + boolean cs = b->type->fvisible(b, f, r); + + if (!cs) { + cs = b->type->rvisible(b, r); + if (!cs) { + unit * us = r->units; + while (us && !cs) { + if (us->faction==f) { + cs = b->type->uvisible(b, us); + if (cs) break; + } + us=us->next; + } + } + } + if (cs) { + const char * bname = mkname("border", b->type->name(b, r, f, GF_PURE)); + fprintf(F, "GRENZE %d\n", ++g); + fprintf(F, "\"%s\";typ\n", LOC(default_locale, bname)); + fprintf(F, "%d;richtung\n", d); + if (!b->type->transparent(b, f)) fputs("1;opaque\n", F); + /* hack: */ + if (b->type==&bt_road) { + int p = rroad(r, d)*100/r->terrain->max_road; + fprintf(F, "%d;prozent\n", p); + } + } + b = b->next; + } + } +} + +static void +cr_output_resources(FILE * F, report_context * ctx, seen_region * sr) +{ + char cbuf[BUFFERSIZE], *pos = cbuf; + region * r = sr->r; + faction * f = ctx->f; + resource_report result[MAX_RAWMATERIALS]; + int n, size = report_resources(sr, result, MAX_RAWMATERIALS, f); + +#ifdef RESOURCECOMPAT + int trees = rtrees(r, 2); + int saplings = rtrees(r, 1); + + if (trees > 0) fprintf(F, "%d;Baeume\n", trees); + if (saplings > 0) fprintf(F, "%d;Schoesslinge\n", saplings); + if (fval(r, RF_MALLORN) && (trees > 0 || saplings > 0)) + fprintf(F, "1;Mallorn\n"); + for (n=0;n=0 && result[n].number>=0) { + fprintf(F, "%d;%s\n", result[n].number, crtag(result[n].name)); + } + } +#endif + + for (n=0;n=0) { + pos = cr_output_resource(pos, result[n].name, f->locale, result[n].number, result[n].level); + } + } + if (pos!=cbuf) fputs(cbuf, F); +} + +static void +cr_region_header(FILE * F, int plid, int nx, int ny, unsigned int uid) +{ + if (plid==0) { + fprintf(F, "REGION %d %d\n", nx, ny); + } else { + fprintf(F, "REGION %d %d %d\n", nx, ny, plid); + } + if (uid) fprintf(F, "%d;id\n", uid); +} + +static void +cr_output_region(FILE * F, report_context * ctx, seen_region * sr) +{ + faction * f = ctx->f; + region * r = sr->r; + plane * pl = rplane(r); + int plid = plane_id(pl), nx, ny; + const char * tname; + int oc[4][2], o = 0; + int uid = r->uid; + +#ifdef OCEAN_NEIGHBORS_GET_NO_ID + if (sr->mode<=see_neighbour && !r->land) { + uid = 0; + } +#endif + + if (opt_cr_absolute_coords) { + nx = r->x; + ny = r->y; + } else { + nx = r->x, ny = r->y; + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl, r); + } + + if (pl) { + if (ny==pl->maxy) { + oc[o][0] = nx; + oc[o++][1] = pl->miny-1; + } + if (nx==pl->maxx) { + oc[o][0] = pl->minx-1; + oc[o++][1] = ny; + } + if (ny==pl->miny) { + oc[o][0] = nx; + oc[o++][1] = pl->maxy+1; + } + if (nx==pl->minx) { + oc[o][0] = pl->maxx+1; + oc[o++][1] = ny; + } + } + while (o--) { + cr_region_header(F, plid, oc[o][0], oc[o][1], uid); + fputs("\"wrap\";visibility\n", F); + } + + cr_region_header(F, plid, nx, ny, uid); + + if (r->land) { + const char * str = rname(r, f->locale); + if (str && str[0]) { + fprintf(F, "\"%s\";Name\n", str); + } + } + tname = terrain_name(r); + + fprintf(F, "\"%s\";Terrain\n", add_translation(tname, locale_string(f->locale, tname))); + if (sr->mode!=see_unit) fprintf(F, "\"%s\";visibility\n", visibility[sr->mode]); + if (sr->mode == see_neighbour) { + cr_borders(ctx->seen, r, f, sr->mode, F); + } else { + building * b; + ship * sh; + unit * u; + int stealthmod = stealth_modifier(sr->mode); + + if (r->display && r->display[0]) + fprintf(F, "\"%s\";Beschr\n", r->display); + if (fval(r->terrain, LAND_REGION)) { + fprintf(F, "%d;Bauern\n", rpeasants(r)); + if(fval(r, RF_ORCIFIED)) { + fprintf(F, "1;Verorkt\n"); + } + fprintf(F, "%d;Pferde\n", rhorses(r)); + + if (sr->mode>=see_unit) { + if (rule_region_owners()) { + faction * owner = region_get_owner(r); + if (owner) { + fprintf(F, "%d;owner\n", owner->no); + } + } + fprintf(F, "%d;Silber\n", rmoney(r)); + if (skill_enabled[SK_ENTERTAINMENT]) { + fprintf(F, "%d;Unterh\n", entertainmoney(r)); + } + if (is_cursed(r->attribs, C_RIOT, 0)){ + fputs("0;Rekruten\n", F); + } else { + fprintf(F, "%d;Rekruten\n", rpeasants(r) / RECRUITFRACTION); + } + if (production(r)) { + int p_wage = wage(r, NULL, NULL, turn+1); + fprintf(F, "%d;Lohn\n", p_wage); + if (is_mourning(r, turn+1)) { + fputs("1;mourning\n", F); + } + } + if (r->land->ownership) { + fprintf(F, "%d;morale\n", r->land->morale); + } + } + + /* this writes both some tags (RESOURCECOMPAT) and a block. + * must not write any blocks before it */ + cr_output_resources(F, ctx, sr); + + if (sr->mode>=see_unit) { + /* trade */ + if (markets_module() && r->land) { + const item_type * lux = r_luxury(r); + const item_type * herb = r->land->herbtype; + if (lux || herb) { + fputs("PREISE\n", F); + if (lux) { + const char * ch = resourcename(lux->rtype, 0); + fprintf(F, "%d;%s\n", 1, add_translation(ch, locale_string(f->locale, ch))); + } + if (herb) { + const char * ch = resourcename(herb->rtype, 0); + fprintf(F, "%d;%s\n", 1, add_translation(ch, locale_string(f->locale, ch))); + } + } + } else if (rpeasants(r)/TRADE_FRACTION > 0) { + struct demand * dmd = r->land->demands; + fputs("PREISE\n", F); + while (dmd) { + const char * ch = resourcename(dmd->type->itype->rtype, 0); + fprintf(F, "%d;%s\n", (dmd->value + ? dmd->value*dmd->type->price + : -dmd->type->price), + add_translation(ch, locale_string(f->locale, ch))); + dmd=dmd->next; + } + } + } + } + if (r->land) { + print_items(F, r->land->items, f->locale); + } + cr_output_curses(F, f, r, TYP_REGION); + cr_borders(ctx->seen, r, f, sr->mode, F); + if (sr->mode==see_unit && is_astral(r) && !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) + { + /* Sonderbehandlung Teleport-Ebene */ + region_list *rl = astralregions(r, inhabitable); + + if (rl) { + region_list *rl2 = rl; + while(rl2) { + region * r = rl2->data; + int nx = r->x, ny = r->y; + plane * plx = rplane(r); + + pnormalize(&nx, &ny, plx); + adjust_coordinates(f, &nx, &ny, plx, r); + fprintf(F, "SCHEMEN %d %d\n", nx, ny); + fprintf(F, "\"%s\";Name\n", rname(r, f->locale)); + rl2 = rl2->next; + } + free_regionlist(rl); + } + } + + /* describe both passed and inhabited regions */ + show_active_spells(r); + if (fval(r, RF_TRAVELUNIT)) { + boolean seeunits = false, seeships = false; + const attrib * ru; + /* show units pulled through region */ + for (ru = a_find(r->attribs, &at_travelunit); ru && ru->type==&at_travelunit; ru = ru->next) { + unit * u = (unit*)ru->data.v; + if (cansee_durchgezogen(f, r, u, 0) && r!=u->region) { + if (!u->ship || !fval(u, UFL_OWNER)) continue; + if (!seeships) fprintf(F, "DURCHSCHIFFUNG\n"); + seeships = true; + fprintf(F, "\"%s\"\n", shipname(u->ship)); + } + } + for (ru = a_find(r->attribs, &at_travelunit); ru && ru->type==&at_travelunit; ru = ru->next) { + unit * u = (unit*)ru->data.v; + if (cansee_durchgezogen(f, r, u, 0) && r!=u->region) { + if (u->ship) continue; + if (!seeunits) fprintf(F, "DURCHREISE\n"); + seeunits = true; + fprintf(F, "\"%s\"\n", unitname(u)); + } + } + } + cr_output_messages(F, r->msgs, f); + { + message_list * mlist = r_getmessages(r, f); + if (mlist) cr_output_messages(F, mlist, f); + } + /* buildings */ + for (b = rbuildings(r); b; b = b->next) { + int fno = -1; + u = building_owner(b); + if (u && !fval(u, UFL_ANON_FACTION)) { + const faction * sf = visible_faction(f,u); + fno = sf->no; + } + cr_output_building(F, b, u, fno, f); + } + + /* ships */ + for (sh = r->ships; sh; sh = sh->next) { + int fno = -1; + u = shipowner(sh); + if (u && !fval(u, UFL_ANON_FACTION)) { + const faction * sf = visible_faction(f,u); + fno = sf->no; + } + + cr_output_ship(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))) { + cr_output_unit(F, r, f, u, sr->mode); + } + } + } +} + +/* main function of the creport. creates the header and traverses all regions */ +static int +report_computer(const char * filename, report_context * ctx, const char * charset) +{ + static int era = -1; + int i; + faction * f = ctx->f; + const char * prefix; + region * r; + const char * mailto = locale_string(f->locale, "mailto"); + const attrib * a; + seen_region * sr = NULL; +#if SCORE_MODULE + int score = 0, avgscore = 0; +#endif + int enc = xmlParseCharEncoding(charset); + FILE * F = fopen(filename, "wt"); + + if (era<0) { + era = get_param_int(global.parameters, "world.era", 2); + } + if (F==NULL) { + perror(filename); + return -1; + } else if (enc==XML_CHAR_ENCODING_UTF8) { + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + fwrite(utf8_bom, 1, 3, F); + } + + /* must call this to get all the neighbour regions */ + /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ + /* initialisations, header and lists */ + + fprintf(F, "VERSION %d\n", C_REPORT_VERSION); + fprintf(F, "\"%s\";charset\n", charset); + fprintf(F, "\"%s\";locale\n", locale_name(f->locale)); + fprintf(F, "%d;noskillpoints\n", 1); + fprintf(F, "%ld;date\n", ctx->report_time); + fprintf(F, "\"%s\";Spiel\n", global.gamename); + fprintf(F, "\"%s\";Konfiguration\n", "Standard"); + fprintf(F, "\"%s\";Koordinaten\n", "Hex"); + fprintf(F, "%d;Basis\n", 36); + fprintf(F, "%d;Runde\n", turn); + fprintf(F, "%d;Zeitalter\n", era); + if (mailto!=NULL) { + fprintf(F, "\"%s\";mailto\n", mailto); + fprintf(F, "\"%s\";mailcmd\n", locale_string(f->locale, "mailcmd")); + } + + show_alliances_cr(F, f); + + fprintf(F, "PARTEI %d\n", f->no); + fprintf(F, "\"%s\";locale\n", locale_name(f->locale)); + if (f_get_alliance(f)) { + fprintf(F, "%d;alliance\n", f->alliance->id); + fprintf(F, "%d;joined\n", f->alliance_joindate); + } + fprintf(F, "%d;age\n", f->age); + fprintf(F, "%d;Optionen\n", f->options); +#if SCORE_MODULE + if (f->options & want(O_SCORE) && f->age>DISPLAYSCORE) { + score = f->score; + avgscore = average_score_of_age(f->age, f->age / 24 + 1); + } + fprintf(F, "%d;Punkte\n", score); + fprintf(F, "%d;Punktedurchschnitt\n", avgscore); +#endif + { + const char * zRace = rc_name(f->race, 1); + fprintf(F, "\"%s\";Typ\n", add_translation(zRace, LOC(f->locale, zRace))); + } + prefix = get_prefix(f->attribs); + if (prefix!=NULL) { + prefix = mkname("prefix", prefix); + fprintf(F, "\"%s\";typprefix\n", + add_translation(prefix, LOC(f->locale, prefix))); + } + fprintf(F, "%d;Rekrutierungskosten\n", f->race->recruitcost); + fprintf(F, "%d;Anzahl Personen\n", count_all(f)); + fprintf(F, "\"%s\";Magiegebiet\n", magic_school[f->magiegebiet]); + + if (f->race == new_race[RC_HUMAN]) { + fprintf(F, "%d;Anzahl Immigranten\n", count_migrants(f)); + fprintf(F, "%d;Max. Immigranten\n", count_maxmigrants(f)); + } + + i = countheroes(f); + if (i>0) fprintf(F, "%d;heroes\n", i); + i = maxheroes(f); + if (i>0) fprintf(F, "%d;max_heroes\n", i); + + if (f->age > 1 && f->lastorders != turn) { + fprintf(F, "%d;nmr\n", turn-f->lastorders); + } + + fprintf(F, "\"%s\";Parteiname\n", f->name); + fprintf(F, "\"%s\";email\n", f->email); + if (f->banner) fprintf(F, "\"%s\";banner\n", f->banner); + print_items(F, f->items, f->locale); + fputs("OPTIONEN\n", F); + for (i=0;i!=MAXOPTIONS;++i) { + int flag = want(i); + if (options[i]) { + fprintf(F, "%d;%s\n", (f->options&flag)?1:0, options[i]); + } else if (f->options&flag) { + f->options &= (~flag); + } + } + show_allies_cr(F, f, f->allies); + { + group * g; + for (g=f->groups;g;g=g->next) { + + fprintf(F, "GRUPPE %d\n", g->gid); + fprintf(F, "\"%s\";name\n", g->name); + prefix = get_prefix(g->attribs); + if (prefix!=NULL) { + prefix = mkname("prefix", prefix); + fprintf(F, "\"%s\";typprefix\n", + add_translation(prefix, LOC(f->locale, prefix))); + } + show_allies_cr(F, f, g->allies); + } + } + + cr_output_messages(F, f->msgs, f); + { + struct bmsg * bm; + for (bm=f->battles;bm;bm=bm->next) { + plane * pl = rplane(bm->r); + int plid = plane_id(pl); + region * r = bm->r; + int nx = r->x, ny = r->y; + + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl, r); + if (!plid) fprintf(F, "BATTLE %d %d\n", nx, ny); + else { + fprintf(F, "BATTLE %d %d %d\n", nx, ny, plid); + } + cr_output_messages(F, bm->msgs, f); + } + } + + cr_find_address(F, f, ctx->addresses); + a = a_find(f->attribs, &at_reportspell); + while (a && a->type==&at_reportspell) { + spell *sp = (spell *)a->data.v; + cr_reportspell(F, sp, f->locale); + a = a->next; + } + for (a=a_find(f->attribs, &at_showitem);a && a->type==&at_showitem;a=a->next) { + const potion_type * ptype = resource2potion(((const item_type*)a->data.v)->rtype); + const char * ch; + const char * description = NULL; + + if (ptype==NULL) continue; + ch = resourcename(ptype->itype->rtype, 0); + fprintf(F, "TRANK %d\n", hashstring(ch)); + fprintf(F, "\"%s\";Name\n", add_translation(ch, locale_string(f->locale, ch))); + fprintf(F, "%d;Stufe\n", ptype->level); + + if (description==NULL) { + const char * pname = resourcename(ptype->itype->rtype, 0); + const char * potiontext = mkname("potion", pname); + description = LOC(f->locale, potiontext); + } + + fprintf(F, "\"%s\";Beschr\n", description); + if (ptype->itype->construction) { + requirement * m = ptype->itype->construction->materials; + + fprintf(F, "ZUTATEN\n"); + + while (m->number) { + ch = resourcename(m->rtype, 0); + fprintf(F, "\"%s\"\n", add_translation(ch, locale_string(f->locale, ch))); + m++; + } + } + } + + /* traverse all regions */ + for (r=ctx->first;sr==NULL && r!=ctx->last;r=r->next) { + sr = find_seen(ctx->seen, r); + } + for (;sr!=NULL;sr=sr->next) { + cr_output_region(F, ctx, sr); + } + report_crtypes(F, f->locale); + write_translations(F); + reset_translations(); + fclose(F); + return 0; +} + +int +crwritemap(const char * filename) +{ + FILE * F = fopen(filename, "w"); + region * r; + + fprintf(F, "VERSION %d\n", C_REPORT_VERSION); + fputs("\"UTF-8\";charset\n", F); + + for (r=regions;r;r=r->next) { + plane * pl = rplane(r); + int plid = plane_id(pl); + if (plid) { + fprintf(F, "REGION %d %d %d\n", r->x, r->y, plid); + } else { + fprintf(F, "REGION %d %d\n", r->x, r->y); + } + fprintf(F, "\"%s\";Name\n\"%s\";Terrain\n", rname(r, default_locale), LOC(default_locale, terrain_name(r))); + } + fclose(F); + return 0; +} + +void +register_cr(void) +{ + tsf_register("report", &cr_ignore); + tsf_register("string", &cr_string); + tsf_register("order", &cr_order); + tsf_register("spell", &cr_spell); + tsf_register("curse", &cr_curse); + tsf_register("int", &cr_int); + tsf_register("unit", &cr_unit); + tsf_register("region", &cr_region); + tsf_register("faction", &cr_faction); + tsf_register("ship", &cr_ship); + tsf_register("building", &cr_building); + tsf_register("skill", &cr_skill); + tsf_register("resource", &cr_resource); + tsf_register("race", &cr_race); + tsf_register("direction", &cr_int); + tsf_register("alliance", &cr_alliance); + tsf_register("resources", &cr_resources); + tsf_register("items", &cr_resources); + tsf_register("regions", &cr_regions); + + if (!nocr) register_reporttype("cr", &report_computer, 1<next; + free(t); + } + junkyard = 0; +} + + diff --git a/src/gamecode/creport.h b/src/gamecode/creport.h new file mode 100644 index 000000000..473f1f0bc --- /dev/null +++ b/src/gamecode/creport.h @@ -0,0 +1,29 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#ifndef H_GC_CREPORT +#define H_GC_CREPORT +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern void creport_cleanup(void); +extern void register_cr(void); + +extern int crwritemap(const char * filename); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c new file mode 100644 index 000000000..53000af93 --- /dev/null +++ b/src/gamecode/economy.c @@ -0,0 +1,3463 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#pragma region includes + +#include +#include +#include "economy.h" + +/* gamecode includes */ +#include "archetype.h" +#include "give.h" +#include "laws.h" +#include "randenc.h" +#include "spy.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +/* libs includes */ +#include +#include +#include +#include +#include + +#pragma endregion + +typedef struct request { + struct request * next; + struct unit * unit; + struct order * ord; + int qty; + int no; + union { + boolean goblin; /* stealing */ + const struct luxury_type * ltype; /* trading */ + } type; +} request; + +static int working; + +static request entertainers[1024]; +static request *nextentertainer; +static int entertaining; + +static int norders; +static request *oa; + +#define RECRUIT_MERGE 1 +#define RECRUIT_CLASSIC 2 +#define RECRUIT_ARCHETYPES 4 +static int rules_recruit = -1; + +static void recruit_init(void) +{ + if (rules_recruit<0) { + rules_recruit = 0; + if (get_param_int(global.parameters, "recruit.allow_merge", 1)) { + rules_recruit |= RECRUIT_MERGE; + } + if (get_param_int(global.parameters, "recruit.classic", 1)) { + rules_recruit |= RECRUIT_CLASSIC; + } + if (get_param_int(global.parameters, "recruit.archetype", 0)) { + rules_recruit |= RECRUIT_ARCHETYPES; + } + } +} + +int +income(const unit * u) +{ + switch(old_race(u->race)) { + case RC_FIREDRAGON: + return 150 * u->number; + case RC_DRAGON: + return 1000 * u->number; + case RC_WYRM: + return 5000 * u->number; + } + return 20 * u->number; +} + +static void +scramble(void *data, int n, size_t width) +{ + int j; + char temp[64]; + assert(width<=sizeof(temp)); + for (j=0;j!=n;++j) { + int k = rng_int() % n; + if (k==j) continue; + memcpy(temp, (char*)data+j*width, width); + memcpy((char*)data+j*width, (char*)data+k*width, width); + memcpy((char*)data+k*width, temp, width); + } +} + +static void +expandorders(region * r, request * requests) +{ + unit *u; + request *o; + + /* Alle Units ohne request haben ein -1, alle units mit orders haben ein + * 0 hier stehen */ + + for (u = r->units; u; u = u->next) + u->n = -1; + + norders = 0; + + for (o = requests; o; o = o->next) { + if (o->qty > 0) { + norders += o->qty; + } + } + + if (norders > 0) { + int i = 0; + oa = (request *) calloc(norders, sizeof(request)); + for (o = requests; o; o = o->next) { + if (o->qty > 0) { + int j; + for (j = o->qty; j; j--) { + oa[i] = *o; + oa[i].unit->n = 0; + i++; + } + } + } + scramble(oa, norders, sizeof(request)); + } else { + oa = NULL; + } + while (requests) { + request * o = requests->next; + free_order(requests->ord); + free(requests); + requests = o; + } +} +/* ------------------------------------------------------------- */ + +static void +change_level(unit * u, skill_t sk, int bylevel) +{ + skill * sv = get_skill(u, sk); + assert(bylevel>0); + if (sv==0) sv = add_skill(u, sk); + sk_set(sv, sv->level+bylevel); +} + +typedef struct recruitment { + struct recruitment * next; + faction * f; + request * requests; + int total, assigned; +} recruitment; + +static recruitment * +select_recruitment(request ** rop, int (*quantify)(const struct race*, int), int * total) +{ + recruitment * recruits = NULL; + + while (*rop) { + recruitment * rec = recruits; + request * ro = *rop; + unit * u = ro->unit; + const race * rc = u->race; + int qty = quantify(rc, ro->qty); + + if (qty<0) { + rop = &ro->next; /* skip this one */ + } else { + *rop = ro->next; /* remove this one */ + while (rec && rec->f!=u->faction) rec = rec->next; + if (rec==NULL) { + rec = malloc(sizeof(recruitment)); + rec->f = u->faction; + rec->total = 0; + rec->assigned = 0; + rec->requests = NULL; + rec->next = recruits; + recruits = rec; + } + *total += qty; + rec->total += qty; + ro->next = rec->requests; + rec->requests = ro; + } + } + return recruits; +} + +static void +add_recruits(unit * u, int number, int wanted) +{ + region * r = u->region; + assert(number<=wanted); + if (number > 0) { + unit * unew; + char equipment[64]; + + if (u->number==0) { + set_number(u, number); + u->hp = number * unit_max_hp(u); + unew = u; + } else { + unew = create_unit(r, u->faction, number, u->race, 0, NULL, u); + } + + snprintf(equipment, sizeof(equipment), "new_%s_unit", u->race->_name[0]); + equip_unit(unew, get_equipment(equipment)); + + + if (unew->race->ec_flags & ECF_REC_HORSES) { + change_level(unew, SK_RIDING, 1); + } + + if (unew!=u) { + transfermen(unew, u, unew->number); + remove_unit(&r->units, unew); + } + } + if (number < wanted) { + ADDMSG(&u->faction->msgs, msg_message("recruit", + "unit region amount want", u, r, number, wanted)); + } +} + +static int +any_recruiters(const struct race * rc, int qty) +{ + return (int)(qty * 2 * rc->recruit_multi); +} + +static int +peasant_recruiters(const struct race * rc, int qty) +{ + if (rc->ec_flags & ECF_REC_ETHEREAL) return -1; + if (rc->ec_flags & ECF_REC_HORSES) return -1; + return (int)(qty * 2 * rc->recruit_multi); +} + +static int +horse_recruiters(const struct race * rc, int qty) +{ + if (rc->ec_flags & ECF_REC_ETHEREAL) return -1; + if (rc->ec_flags & ECF_REC_HORSES) return (int)(qty * 2 * rc->recruit_multi); + return -1; +} + +static int +do_recruiting(recruitment * recruits, int available) +{ + recruitment * rec; + int recruited = 0; + + while (available>0) { + int n = 0; + int rest, mintotal = INT_MAX; + + for (rec=recruits;rec!=NULL;rec=rec->next) { + int want = rec->total - rec->assigned; + if (want>0) { + if (mintotal>want) mintotal = want; + ++n; + } + } + if (n==0) break; + if (mintotal*n>available) { + mintotal = available/n; + } + rest = available - mintotal*n; + + for (rec=recruits;rec!=NULL;rec=rec->next) { + int want = rec->total - rec->assigned; + + if (want>0) { + int get = mintotal; + if (want>mintotal && restassigned += get; + } + } + } + + for (rec=recruits;rec!=NULL;rec=rec->next) { + request * req; + int get = rec->assigned; + + for (req=rec->requests;req;req=req->next) { + unit * u = req->unit; + const race * rc = u->race; /* race is set in recruit() */ + int number, dec; + float multi = 2.0F * rc->recruit_multi; + + number = MIN(req->qty, (int)(get / multi)); + if (rc->recruitcost) { + int afford = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, number*rc->recruitcost) / rc->recruitcost; + number = MIN(number, afford); + use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, rc->recruitcost*number); + } + if (u->number+number>UNIT_MAXSIZE) { + ADDMSG(&u->faction->msgs, msg_feedback(u, req->ord, "error_unit_size", "maxsize", UNIT_MAXSIZE)); + number = UNIT_MAXSIZE-u->number; + assert(number>=0); + } + add_recruits(u, number, req->qty); + dec = (int)(number * multi); + if ((rc->ec_flags & ECF_REC_ETHEREAL)==0) { + recruited += dec; + } + + get -= dec; + } + } + return recruited; +} + +static void +feedback_give_not_allowed(unit * u, order * ord) +{ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_give_forbidden", "")); +} + +static boolean check_give(unit * u, unit * u2, const item_type * itype, int mask) +{ + if (u2) { + if (u->faction!=u2->faction) { + int rule = rule_give(); + if (itype) { + assert(mask==0); + if (itype->rtype->ltype) mask |= GIVE_LUXURIES; + else if (fval(itype, ITF_HERB)) mask |= GIVE_HERBS; + else mask |= GIVE_GOODS; + } + return (rule&mask)!=0; + } + } else { + int rule = rule_give(); + return (rule & GIVE_PEASANTS)!=0; + } + return true; +} + +void +free_recruitments(recruitment * recruits) +{ + while (recruits) { + recruitment * rec = recruits; + recruits = rec->next; + while (rec->requests) { + request * req = rec->requests; + rec->requests = req->next; + free(req); + } + free(rec); + } +} + +/* Rekrutierung */ +static void +expandrecruit(region * r, request * recruitorders) +{ + recruitment * recruits = NULL; + + int orc_total = 0; + + /* centaurs: */ + recruits = select_recruitment(&recruitorders, horse_recruiters, &orc_total); + if (recruits) { + int recruited, horses = rhorses(r) * 2; + if (orc_total0) { + rsetpeasants(r, peasants - recruited/2); + } + free_recruitments(recruits); + } + + assert(recruitorders==NULL); +} + +static int +recruit_cost(const faction * f, const race * rc) +{ + if (is_monsters(f) || f->race==rc) { + return rc->recruitcost; + } else if (valid_race(f, rc)) { + return rc->recruitcost; +/* return get_param_int(f->race->parameters, "other_cost", -1); */ + } + return -1; +} + +static void +recruit(unit * u, struct order * ord, request ** recruitorders) +{ + int n; + region * r = u->region; + plane * pl; + request *o; + int recruitcost = -1; + const faction * f = u->faction; + const struct race * rc = u->race; + const char * str; + + init_tokens(ord); + skip_token(); + n = getuint(); + + if (u->number==0) { + str = getstrtoken(); + if (str && str[0]) { + /* Monster dürfen REKRUTIERE 15 dracoid machen + * also: secondary race */ + rc = findrace(str, f->locale); + if (rc!=NULL) { + recruitcost = recruit_cost(f, rc); + } + } + } + if (recruitcost<0) { + rc = u->race; + recruitcost = recruit_cost(f, rc); + } + u->race = rc; + assert(rc && recruitcost>=0); + +#if GUARD_DISABLES_RECRUIT + /* this is a very special case because the recruiting unit may be empty + * at this point and we have to look at the creating unit instead. This + * is done in cansee, which is called indirectly by is_guarded(). */ + if (is_guarded(r, u, GUARD_RECRUIT)) { + cmistake(u, ord, 70, MSG_EVENT); + return; + } +#endif + + if (rc == new_race[RC_INSECT]) { + gamedate date; + get_gamedate(turn, &date); + if (date.season == 0 && r->terrain != newterrain(T_DESERT)) { +#ifdef INSECT_POTION + boolean usepotion = false; + unit *u2; + + for (u2 = r->units; u2; u2 = u2->next) + if (fval(u2, UFL_WARMTH)) { + usepotion = true; + break; + } + if (!usepotion) +#endif + { + cmistake(u, ord, 98, MSG_EVENT); + return; + } + } + /* in Gletschern, Eisbergen gar nicht rekrutieren */ + if (r_insectstalled(r)) { + cmistake(u, ord, 97, MSG_EVENT); + return; + } + } + if (is_cursed(r->attribs, C_RIOT, 0)) { + /* Die Region befindet sich in Aufruhr */ + cmistake(u, ord, 237, MSG_EVENT); + return; + } + + if (!(rc->ec_flags & ECF_REC_HORSES) && fval(r, RF_ORCIFIED)) { + if (rc != new_race[RC_ORC]) + { + cmistake(u, ord, 238, MSG_EVENT); + return; + } + } + + if (recruitcost) { + pl = getplane(r); + if (pl && fval(pl, PFL_NORECRUITS)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "error_pflnorecruit", "")); + return; + } + + if (get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, recruitcost) < recruitcost) { + cmistake(u, ord, 142, MSG_EVENT); + return; + } + } + if (!playerrace(rc) || idle(u->faction)) { + cmistake(u, ord, 139, MSG_EVENT); + return; + } + + if (has_skill(u, SK_MAGIC)) { + /* error158;de;{unit} in {region}: '{command}' - Magier arbeiten + * grundsätzlich nur alleine! */ + cmistake(u, ord, 158, MSG_EVENT); + return; + } + if (has_skill(u, SK_ALCHEMY) + && count_skill(u->faction, SK_ALCHEMY) + n > + skill_limit(u->faction, SK_ALCHEMY)) + { + cmistake(u, ord, 156, MSG_EVENT); + return; + } + if (recruitcost>0) { + int pooled = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, recruitcost * n); + n = MIN(n, pooled / recruitcost); + } + + u->wants = n; + + if (!n) { + cmistake(u, ord, 142, MSG_EVENT); + return; + } + + o = (request *) calloc(1, sizeof(request)); + o->qty = n; + o->unit = u; + o->ord = copy_order(ord); + addlist(recruitorders, o); +} + +static void +friendly_takeover(region * r, faction * f) +{ + int morale = region_get_morale(r); + region_set_owner(r, f, turn); + if (morale>0) { + morale = MAX(0, morale-MORALE_TRANSFER); + region_set_morale(r, morale, turn); + } +} + +static void +give_control(unit * u, unit * u2) +{ + if (u->building && u->faction!=u2->faction && rule_region_owners()) { + region * r = u->region; + faction * f = region_get_owner(r); + if (f==u->faction) { + building * b = largestbuilding(r, &cmp_current_owner, false); + if (b==u->building) { + friendly_takeover(r, u2->faction); + } + } + } + freset(u, UFL_OWNER); + fset(u2, UFL_OWNER); +} + +int +give_control_cmd(unit * u, order * ord) +{ + region * r = u->region; + unit *u2; + const char * s; + param_t p; + + init_tokens(ord); + skip_token(); + u2 = getunit(r, u->faction); + s = getstrtoken(); + p = findparam(s, u->faction->locale); + + /* first, do all the ones that do not require HELP_GIVE or CONTACT */ + if (p == P_CONTROL) { + message * msg; + + if (!u2) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } + else if (!u->building && !u->ship) { + cmistake(u, ord, 140, MSG_EVENT); + } + else if (u->building && u2->building != u->building) { + cmistake(u, ord, 33, MSG_EVENT); + } + else if (u->ship && u2->ship != u->ship) { + cmistake(u, ord, 32, MSG_EVENT); + } + else if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 49, MSG_EVENT); + } + else { + give_control(u, u2); + + msg = msg_message("givecommand", "unit recipient", u, u2); + add_message(&u->faction->msgs, msg); + if (u->faction != u2->faction) { + add_message(&u2->faction->msgs, msg); + } + msg_release(msg); + } + } + return 0; +} + +static void +give_cmd(unit * u, order * ord) +{ + region * r = u->region; + unit *u2; + const char *s; + int i, n; + const item_type * itype; + param_t p; + plane * pl; + + init_tokens(ord); + skip_token(); + u2 = getunit(r, u->faction); + s = getstrtoken(); + p = findparam(s, u->faction->locale); + + /* first, do all the ones that do not require HELP_GIVE or CONTACT */ + if (p == P_CONTROL) { + /* handled in give_control_cmd */ + return; + } + + if (!u2 && !getunitpeasants) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + + if (!check_give(u, u2, NULL, GIVE_ALLITEMS)) { + feedback_give_not_allowed(u, ord); + return; + } + + /* Damit Tarner nicht durch die Fehlermeldung enttarnt werden können */ + if (u2 && !alliedunit(u2, u->faction, HELP_GIVE) && !cansee(u->faction,r,u2,0) && !ucontact(u2, u) && !fval(u2, UFL_TAKEALL)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + if (u == u2) { + cmistake(u, ord, 8, MSG_COMMERCE); + return; + } + + /* UFL_TAKEALL ist ein grober Hack. Generalisierung tut not, ist aber nicht + * wirklich einfach. */ + pl = rplane(r); + if (pl && fval(pl, PFL_NOGIVE) && (!u2 || !fval(u2, UFL_TAKEALL))) { + cmistake(u, ord, 268, MSG_COMMERCE); + return; + } + + if (u2 && u2->race == new_race[RC_SPELL]) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + + else if (u2 && !alliedunit(u2, u->faction, HELP_GIVE) && !ucontact(u2, u)) { + cmistake(u, ord, 40, MSG_COMMERCE); + return; + } + + else if (p == P_HERBS) { + boolean given = false; + if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_nogive", "race", u->race)); + return; + } + if (!check_give(u, u2, NULL, GIVE_HERBS)) { + feedback_give_not_allowed(u, ord); + return; + } + if (u2 && !(u2->race->ec_flags & GETITEM)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_notake", "race", u2->race)); + return; + } + if (!u2) { + if (!getunitpeasants) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + } + if (u->items) { + item **itmp=&u->items; + while (*itmp) { + item * itm = *itmp; + const item_type * itype = itm->type; + if (fval(itype, ITF_HERB) && itm->number>0) { + /* give_item ändert im fall,das man alles übergibt, die + * item-liste der unit, darum continue vor pointerumsetzten */ + if (give_item(itm->number, itm->type, u, u2, ord)==0) { + given = true; + if (*itmp!=itm) continue; + continue; + } + } + itmp = &itm->next; + } + } + if (!given) cmistake(u, ord, 38, MSG_COMMERCE); + return; + } + + else if (p == P_ZAUBER) { + cmistake(u, ord, 7, MSG_COMMERCE); + /* geht nimmer */ + return; + } + + else if (p == P_UNIT) { /* Einheiten uebergeben */ + if (!(u->race->ec_flags & GIVEUNIT)) { + cmistake(u, ord, 167, MSG_COMMERCE); + return; + } + + give_unit(u, u2, ord); + return; + } + + else if (p==P_ANY) { + const char * s = getstrtoken(); + + if (!check_give(u, u2, NULL, GIVE_ALLITEMS)) { + feedback_give_not_allowed(u, ord); + return; + } + if (*s == 0) { /* Alle Gegenstände übergeben */ + + /* do these checks once, not for each item we have: */ + if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_nogive", "race", u->race)); + return; + } + if (u2 && !(u2->race->ec_flags & GETITEM)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_notake", "race", u2->race)); + return; + } + + /* für alle items einmal prüfen, ob wir mehr als von diesem Typ + * reserviert ist besitzen und diesen Teil dann übergeben */ + if (u->items) { + item **itmp=&u->items; + while (*itmp) { + item * itm = *itmp; + const item_type * itype = itm->type; + if (itm->number > 0 && itm->number - get_reservation(u, itype->rtype) > 0) { + n = itm->number - get_reservation(u, itype->rtype); + if (give_item(n, itype, u, u2, ord)==0) { + if (*itmp!=itm) continue; + } + } + itmp = &itm->next; + } + } + return; + } + else { + param_t p2 = findparam(s, u->faction->locale); + + if (p2 == P_PERSON) { + if (!(u->race->ec_flags & GIVEPERSON)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_noregroup", "race", u->race)); + return; + } + n = u->number; + give_men(n, u, u2, ord); + return; + } + + if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_nogive", "race", u->race)); + return; + } + if (u2 && !(u2->race->ec_flags & GETITEM)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_notake", "race", u2->race)); + return; + } + + itype = finditemtype(s, u->faction->locale); + if (itype!=NULL) { + item * i = *i_find(&u->items, itype); + if (i!=NULL) { + if (check_give(u, u2, itype, 0)) { + n = i->number - get_reservation(u, itype->rtype); + give_item(n, itype, u, u2, ord); + } else { + feedback_give_not_allowed(u, ord); + } + return; + } + } + } + } else if (p==P_EACH) { + if (u2==NULL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "peasants_give_invalid", "")); + return; + } + s = getstrtoken(); /* skip one ahead to get the amount. */ + } + + n = atoip((const char *)s); /* n: Anzahl */ + if (p==P_EACH) { + n *= u2->number; + } + s = getstrtoken(); + + if (s == NULL) { + cmistake(u, ord, 113, MSG_COMMERCE); + return; + } + + i = findparam(s, u->faction->locale); + if (i == P_PERSON) { + if (!(u->race->ec_flags & GIVEPERSON)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_noregroup", "race", u->race)); + return; + } + give_men(n, u, u2, ord); + return; + } + + if (u2!=NULL) { + if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_nogive", "race", u->race)); + return; + } + if (!(u2->race->ec_flags & GETITEM)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_notake", "race", u2->race)); + return; + } + } + + itype = finditemtype(s, u->faction->locale); + if (itype!=NULL) { + if (check_give(u, u2, itype, 0)) { + give_item(n, itype, u, u2, ord); + } else { + feedback_give_not_allowed(u, ord); + } + return; + } + cmistake(u, ord, 123, MSG_COMMERCE); +} + +static int +forget_cmd(unit * u, order * ord) +{ + skill_t sk; + const char *s; + + if (is_cursed(u->attribs, C_SLAVE, 0)) { + /* charmed units shouldn't be losing their skills */ + return 0; + } + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + if ((sk = findskill(s, u->faction->locale)) != NOSKILL) { + ADDMSG(&u->faction->msgs, + msg_message("forget", "unit skill", u, sk)); + set_level(u, sk, 0); + } + return 0; +} + +void +add_spende(faction * f1, faction * f2, int amount, region * r) +{ + donation *sp; + + sp = r->donations; + + while (sp) { + if (sp->f1 == f1 && sp->f2 == f2) { + sp->amount += amount; + return; + } + sp = sp->next; + } + + sp = calloc(1, sizeof(donation)); + sp->f1 = f1; + sp->f2 = f2; + sp->amount = amount; + sp->next = r->donations; + r->donations = sp; +} + +static boolean +maintain(building * b, boolean first) +/* first==false -> take money from wherever you can */ +{ + int c; + region * r = b->region; + boolean paid = true, work = first; + unit * u; + if (fval(b, BLD_MAINTAINED) || b->type==NULL || b->type->maintenance==NULL || is_cursed(b->attribs, C_NOCOST, 0)) { + fset(b, BLD_MAINTAINED); + fset(b, BLD_WORKING); + return true; + } + if (fval(b, BLD_DONTPAY)) { + return false; + } + u = building_owner(b); + if (u==NULL) return false; + for (c=0;b->type->maintenance[c].number;++c) { + const maintenance * m = b->type->maintenance+c; + int need = m->number; + + if (fval(m, MTF_VARIABLE)) need = need * b->size; + if (u) { + /* first ist im ersten versuch true, im zweiten aber false! Das + * bedeutet, das in der Runde in die Region geschafften Resourcen + * nicht genutzt werden können, weil die reserviert sind! */ + if (!first) need -= get_pooled(u, m->rtype, GET_ALL, need); + else need -= get_pooled(u, m->rtype, GET_DEFAULT, need); + if (!first && need > 0) { + unit * ua; + for (ua=r->units;ua;ua=ua->next) freset(ua->faction, FFL_SELECT); + fset(u->faction, FFL_SELECT); /* hat schon */ + for (ua=r->units;ua;ua=ua->next) { + if (!fval(ua->faction, FFL_SELECT) && (ua->faction == u->faction || alliedunit(ua, u->faction, HELP_MONEY))) { + need -= get_pooled(ua, m->rtype, GET_ALL, need); + fset(ua->faction, FFL_SELECT); + if (need<=0) break; + } + } + } + if (need > 0) { + if (!fval(m, MTF_VITAL)) work = false; + else { + paid = false; + break; + } + } + } + } + if (paid && c>0) { + /* TODO: wieviel von was wurde bezahlt */ + if (first) { + ADDMSG(&u->faction->msgs, msg_message("maintenance", "unit building", u, b)); + } else { + ADDMSG(&u->faction->msgs, msg_message("maintenance_late", "building", b)); + } + fset(b, BLD_MAINTAINED); + if (work) { + fset(b, BLD_WORKING); + } + for (c=0;b->type->maintenance[c].number;++c) { + const maintenance * m = b->type->maintenance+c; + int cost = m->number; + + if (!fval(m, MTF_VITAL) && !work) continue; + if (fval(m, MTF_VARIABLE)) cost = cost * b->size; + + if (!first) cost -= use_pooled(u, m->rtype, GET_ALL, cost); + else cost -= use_pooled(u, m->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, cost); + if (!first && cost > 0) { + unit * ua; + for (ua=r->units;ua;ua=ua->next) freset(ua->faction, FFL_SELECT); + fset(u->faction, FFL_SELECT); /* hat schon */ + for (ua=r->units;ua;ua=ua->next) { + if (!fval(ua->faction, FFL_SELECT) && alliedunit(ua, u->faction, HELP_MONEY)) { + int give = use_pooled(ua, m->rtype, GET_ALL, cost); + if (!give) continue; + cost -= give; + fset(ua->faction, FFL_SELECT); + if (m->rtype==r_silver) add_spende(ua->faction, u->faction, give, r); + if (cost<=0) break; + } + } + } + assert(cost==0); + } + } else { + ADDMSG(&u->faction->msgs, + msg_message("maintenancefail", "unit building", u, b)); + return false; + } + return true; +} + +#ifdef COLLAPSE_CHANCE +static void +gebaeude_stuerzt_ein(region * r, building * b) +{ + unit *u; + int n, i; + int opfer = 0; + int road = 0; + struct message * msg; + + for (u = r->units; u; u = u->next) { + if (u->building == b) { + int loss = 0; + + fset(u->faction, FFL_MARK); + freset(u, UFL_OWNER); + leave(r,u); + n = u->number; +#ifdef COLLAPSE_SURVIVAL + for (i = 0; i < n; i++) { + if (rng_double() >= COLLAPSE_SURVIVAL) { + ++loss; + } + } +#endif + scale_number(u, u->number - loss); + opfer += loss; + } + } + + msg = msg_message("buildingcrash", "region building opfer road", r, b, opfer, road); + add_message(&r->msgs, msg); + for (u=r->units; u; u=u->next) { + faction * f = u->faction; + if (fval(f, FFL_MARK)) { + freset(u->faction, FFL_MARK); + add_message(&f->msgs, msg); + } + } + msg_release(msg); + remove_building(&r->buildings, b); +} +#endif + +void +maintain_buildings(region * r, boolean crash) +{ + building **bp = &r->buildings; + while (*bp) { + building * b = *bp; + boolean maintained = maintain(b, !crash); + + /* the second time, send a message */ + if (crash) { +#ifdef COLLAPSE_CHANCE + if (!maintained && (rng_double() < COLLAPSE_CHANCE)) { + gebaeude_stuerzt_ein(r, b); + continue; + } +#endif + if (!fval(b, BLD_WORKING)) { + unit * u = building_owner(b); + const char * msgtype = maintained?"maintenance_nowork":"maintenance_none"; + struct message * msg = msg_message(msgtype, "building", b); + + if (u) { + add_message(&u->faction->msgs, msg); + r_addmessage(r, u->faction, msg); + } else { + add_message(&r->msgs, msg); + } + msg_release(msg); + } + } + bp=&b->next; + } +} + +static int +recruit_archetype(unit * u, order * ord) +{ + boolean merge = (u->number>0); + int want; + const char * s; + + if (rules_recruit<0) recruit_init(); + + init_tokens(ord); + skip_token(); + want = getuint(); + s = getstrtoken(); + if (want>0 && s && s[0]) { + int n = want; + const archetype * arch = find_archetype(s, u->faction->locale); + attrib * a = NULL; + + if ((rules_recruit&RECRUIT_MERGE)==0 && merge) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_must_be_new", "")); + /* TODO: error message */ + return 0; + } + + if (arch==NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unknown_archetype", "name", s)); + /* TODO: error message */ + return 0; + } + if (arch->rules) { + /* Simple allow/deny style restrictions for archetypes (let only humans + * recruit gamedesigners, etc). These need to be more powerful to be + * useful, and the current way they are implemented is not, but the + * general idea strikes me as good. Also, feedback should be configurable + * for each failed rule. + */ + int k; + for (k=0;arch->rules[k].property;++k) { + boolean match = false; + if (arch->rules[k].value[0]=='*') match = true; + else if (strcmp(arch->rules[k].property, "race")==0) { + const race * rc = rc_find(arch->rules[k].value); + assert(rc); + if (rc==u->race) match = true; + } else if (strcmp(arch->rules[k].property, "building")==0) { + const building_type * btype = bt_find(arch->rules[k].value); + assert(btype); + if (u->building && u->building->type==btype) match = true; + } + if (match) { + if (arch->rules[k].allow) break; + else { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "recruit_rule_fail", + "property value", arch->rules[k].property, arch->rules[k].value)); + /* TODO: error message */ + return 0; + } + } + } + } + if (arch->btype) { + if (u->building==NULL || u->building->type!=arch->btype) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_must_be_in_building", "type", arch->btype)); + /* TODO: error message */ + return 0; + } + if (arch->size) { + int maxsize = u->building->size; + attrib * a = a_find(u->building->attribs, &at_recruit); + if (a!=NULL) { + maxsize -= a->data.i; + } + n = MIN(maxsize/arch->size, n); + if (n<=0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "recruit_capacity_exhausted", "building", u->building)); + /* TODO: error message */ + return 0; + } + } + } + + n = build(u, arch->ctype, 0, n); + if (n>0) { + unit * u2; + if (merge) { + u2 = create_unit(u->region, u->faction, 0, u->race, 0, 0, u); + } else { + u2 = u; + } + if (arch->exec) { + n = arch->exec(u2, arch, n); + } + else { + set_number(u2, n); + equip_unit(u2, arch->equip); + u2->hp = n * unit_max_hp(u2); + if (arch->size) { + if (a==NULL) a = a_add(&u->building->attribs, a_new(&at_recruit)); + a->data.i += n*arch->size; + } + } + ADDMSG(&u->faction->msgs, msg_message("recruit_archetype", + "unit amount archetype", u, n, arch->name[n==1])); + if (u!=u2 && u->race==u2->race) { + transfermen(u2, u, u2->number); + } + return n; + } else switch(n) { + case ENOMATERIALS: + ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, arch->ctype, want)); + break; + case ELOWSKILL: + case ENEEDSKILL: + /* no skill, or not enough skill points to build */ + cmistake(u, ord, 50, MSG_PRODUCE); + break; + case EBUILDINGREQ: + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "building_needed", "building", arch->ctype->btype->_name)); + break; + default: + assert(!"unhandled return value from build() in recruit_archetype"); + } + return 0; + } + return -1; +} + +int recruit_archetypes(void) +{ + if (rules_recruit<0) recruit_init(); + return (rules_recruit&RECRUIT_ARCHETYPES)!=0; +} + +void +economics(region *r) +{ + unit *u; + request *recruitorders = NULL; + + /* Geben vor Selbstmord (doquit)! Hier alle unmittelbaren Befehle. + * Rekrutieren vor allen Einnahmequellen. Bewachen JA vor Steuern + * eintreiben. */ + + for (u = r->units; u; u = u->next) { + order * ord; + boolean destroyed = false; + if (u->number>0) { + for (ord = u->orders; ord; ord = ord->next) { + switch (get_keyword(ord)) { + case K_DESTROY: + if (!destroyed) { + if (destroy_cmd(u, ord)!=0) ord = NULL; + destroyed = true; + } + break; + + case K_GIVE: + case K_LIEFERE: + give_cmd(u, ord); + break; + + case K_FORGET: + forget_cmd(u, ord); + break; + + } + if (u->orders==NULL) break; + } + } + } + /* RECRUIT orders */ + + if (rules_recruit<0) recruit_init(); + for (u = r->units; u; u = u->next) { + order * ord; + + if ((rules_recruit&RECRUIT_MERGE) || u->number==0) { + for (ord = u->orders; ord; ord = ord->next) { + if (get_keyword(ord) == K_RECRUIT) { + if (rules_recruit&RECRUIT_ARCHETYPES) { + if (recruit_archetype(u, ord)>=0) { + continue; + } + } + if (rules_recruit&RECRUIT_CLASSIC) { + recruit(u, ord, &recruitorders); + } + break; + } + } + } + } + + if (recruitorders) expandrecruit(r, recruitorders); + remove_empty_units_in_region(r); +} +/* ------------------------------------------------------------- */ + + +static void +manufacture(unit * u, const item_type * itype, int want) +{ + int n; + int skill; + int minskill = itype->construction->minskill; + skill_t sk = itype->construction->skill; + + skill = effskill(u, sk); + skill = skillmod(itype->rtype->attribs, u, u->region, sk, skill, SMF_PRODUCTION); + + if (skill < 0) { + /* an error occured */ + int err = -skill; + cmistake(u, u->thisorder, err, MSG_PRODUCE); + return; + } + + if (want==0) { + want = maxbuild(u, itype->construction); + } + n = build(u, itype->construction, 0, want); + switch (n) { + case ENEEDSKILL: + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "skill_needed", "skill", sk)); + return; + case EBUILDINGREQ: + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "building_needed", "building", itype->construction->btype->_name)); + return; + case ELOWSKILL: + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "manufacture_skills", "skill minskill product", + sk, minskill, itype->rtype, 1)); + return; + case ENOMATERIALS: + ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, itype->construction, want)); + return; + } + if (n>0) { + i_change(&u->items, itype, n); + if (want==INT_MAX) want = n; + ADDMSG(&u->faction->msgs, msg_message("manufacture", + "unit region amount wanted resource", u, u->region, n, want, itype->rtype)); + } else { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_cannotmake", "")); + } +} + +typedef struct allocation { + struct allocation * next; + int want, get; + double save; + unsigned int flags; + unit * unit; +} allocation; +#define new_allocation() calloc(sizeof(allocation), 1) +#define free_allocation(a) free(a) + +typedef struct allocation_list { + struct allocation_list * next; + allocation * data; + const resource_type * type; +} allocation_list; + +static allocation_list * allocations; + +static boolean +can_guard(const unit * guard, const unit * u) +{ + if (fval(guard, UFL_ISNEW)) return false; + if (guard->number<=0 || !cansee(guard->faction, guard->region, u, 0)) return false; + if (besieged(guard) || !(fval(guard->race, RCF_UNARMEDGUARD) || armedmen(guard, true))) return false; + + return !alliedunit(guard, u->faction, HELP_GUARD); +} + +enum { + AFL_DONE = 1<<0, + AFL_LOWSKILL = 1<<1 +}; + +static void +allocate_resource(unit * u, const resource_type * rtype, int want) +{ + const item_type * itype = resource2item(rtype); + region * r = u->region; + int busy = u->number; + int dm = 0; + allocation_list * alist; + allocation * al; + attrib * a = a_find(rtype->attribs, &at_resourcelimit); + resource_limit * rdata = (resource_limit*)a->data.v; + int amount, skill; + + /* momentan kann man keine ressourcen abbauen, wenn man dafür + * Materialverbrauch hat: */ + assert(itype!=NULL && (itype->construction==NULL || itype->construction->materials==NULL)); + assert(rdata!=NULL); + + if (rdata->limit!=NULL) { + int avail = rdata->limit(r, rtype); + if (avail<=0) { + cmistake(u, u->thisorder, 121, MSG_PRODUCE); + return; + } + } + + if (besieged(u)) { + cmistake(u, u->thisorder, 60, MSG_PRODUCE); + return; + } + + if (rdata->modifiers) { + resource_mod * mod = rdata->modifiers; + for (;mod->flags!=0;++mod) { + if (mod->flags & RMF_REQUIREDBUILDING) { + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + if (mod->btype && mod->btype!=btype) { + cmistake(u, u->thisorder, 104, MSG_PRODUCE); + return; + } + } + } + } + + if (rdata->guard!=0) { + unit * u2; + for (u2 = r->units; u2; u2 = u2->next) { + if (is_guard(u2, rdata->guard)!=0 && can_guard(u2, u)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "region_guarded", "guard", u2)); + return; + } + } + } + + /* Bergwächter können Abbau von Eisen/Laen durch Bewachen verhindern. + * Als magische Wesen 'sehen' Bergwächter alles und werden durch + * Belagerung nicht aufgehalten. (Ansonsten wie oben bei Elfen anpassen). + */ + if (itype == olditemtype[I_IRON] || itype == olditemtype[I_LAEN]) { + unit * u2; + for (u2 = r->units; u2; u2 = u2->next ) { + if (is_guard(u, GUARD_MINING) + && !fval(u2, UFL_ISNEW) + && u2->number + && !alliedunit(u2, u->faction, HELP_GUARD)) + { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "region_guarded", "guard", u2)); + return; + } + } + } + + assert(itype->construction->skill!=0 || "limited resource needs a required skill for making it"); + skill = eff_skill(u, itype->construction->skill, u->region); + if (skill == 0) { + skill_t sk = itype->construction->skill; + add_message(&u->faction->msgs, + msg_feedback(u, u->thisorder, "skill_needed", "skill", sk)); + return; + } + if (skill < itype->construction->minskill) { + skill_t sk = itype->construction->skill; + add_message(&u->faction->msgs, + msg_feedback(u, u->thisorder, "manufacture_skills", "skill minskill product", + sk, itype->construction->minskill, itype->rtype)); + return; + } else { + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + + if (rdata->modifiers) { + resource_mod * mod = rdata->modifiers; + for (;mod->flags!=0;++mod) { + if (mod->flags & RMF_SKILL) { + if (mod->btype==NULL || mod->btype==btype) { + if (mod->race==NULL || mod->race==u->race) { + skill += mod->value.i; + } + } + } + } + } + } + amount = skill * u->number; + /* nun ist amount die Gesamtproduktion der Einheit (in punkten) */ + + /* mit Flinkfingerring verzehnfacht sich die Produktion */ + amount += skill * MIN(u->number, get_item(u, I_RING_OF_NIMBLEFINGER)) * (roqf_factor()-1); + + /* Schaffenstrunk: */ + if ((dm = get_effect(u, oldpotiontype[P_DOMORE])) != 0) { + dm = MIN(dm, u->number); + change_effect(u, oldpotiontype[P_DOMORE], -dm); + amount += dm * skill; /* dm Personen produzieren doppelt */ + } + + amount /= itype->construction->minskill; + + /* Limitierung durch Parameter m. */ + if (want > 0 && want < amount) amount = want; + + busy = (amount + skill - 1) / skill; /* wieviel leute tun etwas? */ + + alist = allocations; + while (alist && alist->type!=rtype) alist = alist->next; + if (!alist) { + alist = calloc(sizeof(struct allocation_list), 1); + alist->next = allocations; + alist->type = rtype; + allocations = alist; + } + al = new_allocation(); + al->want = amount; + al->save = 1.0; + al->next = alist->data; + al->unit = u; + alist->data = al; + + if (rdata->modifiers) { + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + + resource_mod * mod = rdata->modifiers; + for (;mod->flags!=0;++mod) { + if (mod->flags & RMF_SAVEMATERIAL) { + if (mod->btype==NULL || mod->btype==btype) { + if (mod->race==NULL || mod->race==u->race) { + al->save *= mod->value.f; + } + } + } + } + } +} + +static int +required(int want, double save) +{ + int norders = (int)(want * save); + if (norders < want*save) ++norders; + return norders; +} + +static void +leveled_allocation(const resource_type * rtype, region * r, allocation * alist) +{ + const item_type * itype = resource2item(rtype); + rawmaterial * rm = rm_get(r, rtype); + int need; + boolean first = true; + + if (rm!=NULL) { + do { + int avail = rm->amount; + int norders = 0; + allocation * al; + + if(avail <= 0) { + for (al=alist;al;al=al->next) { + al->get = 0; + } + break; + } + + assert(avail>0); + + for (al=alist;al;al=al->next) if (!fval(al, AFL_DONE)) { + int req = required(al->want-al->get, al->save); + assert(al->get<=al->want && al->get >= 0); + if (eff_skill(al->unit, itype->construction->skill, r) + >= rm->level+itype->construction->minskill-1) { + if (req) { + norders += req; + } else { + fset(al, AFL_DONE); + } + } else { + fset(al, AFL_DONE); + if (first) fset(al, AFL_LOWSKILL); + } + } + need = norders; + + avail = MIN(avail, norders); + if (need>0) { + int use = 0; + for (al=alist;al;al=al->next) if (!fval(al, AFL_DONE)) { + if (avail > 0) { + int want = required(al->want-al->get, al->save); + int x = avail*want/norders; + /* Wenn Rest, dann würfeln, ob ich was bekomme: */ + if (rng_int() % norders < (avail*want) % norders) + ++x; + avail -= x; + use += x; + norders -= want; + need -= x; + al->get = MIN(al->want, al->get+(int)(x/al->save)); + } + } + if (use) { + assert(use<=rm->amount); + rm->type->use(rm, r, use); + } + assert(avail==0 || norders==0); + } + first = false; + } while (need>0); + } +} + +static void +attrib_allocation(const resource_type * rtype, region * r, allocation * alist) +{ + allocation * al; + int norders = 0; + attrib * a = a_find(rtype->attribs, &at_resourcelimit); + resource_limit * rdata = (resource_limit*)a->data.v; + int avail = rdata->value; + + for (al=alist;al;al=al->next) { + norders += required(al->want, al->save); + } + + if (rdata->limit) { + avail = rdata->limit(r, rtype); + if (avail < 0) avail = 0; + } + + avail = MIN(avail, norders); + for (al=alist;al;al=al->next) { + if (avail > 0) { + int want = required(al->want, al->save); + int x = avail*want/norders; + /* Wenn Rest, dann würfeln, ob ich was bekomme: */ + if (rng_int() % norders < (avail*want) % norders) + ++x; + avail -= x; + norders -= want; + al->get = MIN(al->want, (int)(x/al->save)); + if (rdata->produce) { + int use = required(al->get, al->save); + if (use) rdata->produce(r, rtype, use); + } + } + } + assert(avail==0 || norders==0); +} + +typedef void (*allocate_function)(const resource_type *, struct region *, struct allocation *); + +static allocate_function +get_allocator(const struct resource_type * rtype) +{ + attrib * a = a_find(rtype->attribs, &at_resourcelimit); + + if (a!=NULL) { + resource_limit * rdata = (resource_limit*)a->data.v; + if (rdata->value>0 || rdata->limit!=NULL) { + return attrib_allocation; + } + return leveled_allocation; + } + return NULL; +} + +void +split_allocations(region * r) +{ + allocation_list ** p_alist=&allocations; + freset(r, RF_SELECT); + while (*p_alist) { + allocation_list * alist = *p_alist; + const resource_type * rtype = alist->type; + allocate_function alloc = get_allocator(rtype); + const item_type * itype = resource2item(rtype); + allocation ** p_al = &alist->data; + + freset(r, RF_SELECT); + alloc(rtype, r, alist->data); + + while (*p_al) { + allocation * al = *p_al; + if (al->get) { + assert(itype || !"not implemented for non-items"); + i_change(&al->unit->items, itype, al->get); + produceexp(al->unit, itype->construction->skill, al->unit->number); + fset(r, RF_SELECT); + } + if (al->want==INT_MAX) al->want = al->get; + if (fval(al, AFL_LOWSKILL)) { + ADDMSG(&al->unit->faction->msgs, + msg_message("produce_lowskill", "unit region resource", + al->unit, al->unit->region, rtype)); + } else { + ADDMSG(&al->unit->faction->msgs, msg_message("produce", + "unit region amount wanted resource", + al->unit, al->unit->region, al->get, al->want, rtype)); + } + *p_al=al->next; + free_allocation(al); + } + *p_alist=alist->next; + free(alist); + } + allocations = NULL; +} + +static void +create_potion(unit * u, const potion_type * ptype, int want) +{ + int built; + + if (want==0) { + want = maxbuild(u, ptype->itype->construction); + } + built = build(u, ptype->itype->construction, 0, want); + switch (built) { + case ELOWSKILL: + case ENEEDSKILL: + /* no skill, or not enough skill points to build */ + cmistake(u, u->thisorder, 50, MSG_PRODUCE); + break; + case EBUILDINGREQ: + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "building_needed", "building", ptype->itype->construction->btype->_name)); + break; + case ECOMPLETE: + assert(0); + break; + case ENOMATERIALS: + /* something missing from the list of materials */ + ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, ptype->itype->construction, want)); + return; + break; + default: + i_change(&u->items, ptype->itype, built); + if (want==INT_MAX) want = built; + ADDMSG(&u->faction->msgs, msg_message("manufacture", + "unit region amount wanted resource", u, u->region, built, want, ptype->itype->rtype)); + break; + } +} + +static void +create_item(unit * u, const item_type * itype, int want) +{ + if (itype->construction && fval(itype->rtype, RTF_LIMITED)) { +#if GUARD_DISABLES_PRODUCTION == 1 + if (is_guarded(u->region, u, GUARD_PRODUCE)) { + cmistake(u, u->thisorder, 70, MSG_EVENT); + return; + } +#endif + allocate_resource(u, itype->rtype, want); + } else { + const potion_type * ptype = resource2potion(itype->rtype); + if (ptype!=NULL) create_potion(u, ptype, want); + else if (itype->construction && itype->construction->materials) manufacture(u, itype, want); + else { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_cannotmake", "")); + } + } +} + +int +make_cmd(unit * u, struct order * ord) +{ + region * r = u->region; + const building_type * btype; + const ship_type * stype; + param_t p; + int m; + const item_type * itype; + const char *s; + const struct locale * lang = u->faction->locale; + char ibuf[16]; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + m = atoi((const char *)s); + sprintf(ibuf, "%d", m); + if (!strcmp(ibuf, (const char *)s)) { + /* first came a want-paramter */ + s = getstrtoken(); + } else { + m = INT_MAX; + } + + p = findparam(s, u->faction->locale); + + /* MACHE TEMP kann hier schon gar nicht auftauchen, weil diese nicht in + * thisorder abgespeichert werden - und auf den ist getstrtoken() beim + * aufruf von make geeicht */ + + if (p == P_ROAD) { + plane * pl = rplane(r); + if (pl && fval(pl, PFL_NOBUILD)) { + cmistake(u, ord, 275, MSG_PRODUCE); + } else { + direction_t d = finddirection(getstrtoken(), u->faction->locale); + if (d!=NODIRECTION) { + build_road(r, u, m, d); + } else { + /* Die Richtung wurde nicht erkannt */ + cmistake(u, ord, 71, MSG_PRODUCE); + } + } + return 0; + } else if (p == P_SHIP) { + plane * pl = rplane(r); + if (pl && fval(pl, PFL_NOBUILD)) { + cmistake(u, ord, 276, MSG_PRODUCE); + } else { + continue_ship(r, u, m); + } + return 0; + } else if (p == P_HERBS) { + herbsearch(r, u, m); + return 0; + } + + /* since the string can match several objects, like in 'academy' and + * 'academy of arts', we need to figure out what the player meant. + * This is not 100% safe. + */ + stype = findshiptype(s, lang); + btype = findbuildingtype(s, lang); + itype = finditemtype(s, lang); + + if (itype!=NULL && (btype!=NULL || stype!=NULL)) { + if (itype->construction==NULL) { + /* if the item cannot be made, we probably didn't mean to make it */ + itype = NULL; + } else if (stype!=NULL) { + const char * sname = LOC(lang, stype->name[0]); + const char * iname = LOC(lang, resourcename(itype->rtype, 0)); + if (strlen(iname)_name); + const char * iname = LOC(lang, resourcename(itype->rtype, 0)); + if (strlen(iname)_name); + const char * sname = LOC(lang, stype->name[0]); + if (strlen(sname)faction->msgs, msg_feedback(u, ord, "error_cannotmake", "")); + } + + return 0; +} +/* ------------------------------------------------------------- */ + +static void +free_luxuries(struct attrib * a) +{ + item * itm = (item*)a->data.v; + a->data.v = NULL; + i_freeall(&itm); +} + +const attrib_type at_luxuries = { + "luxuries", NULL, free_luxuries, NULL, NULL, NULL +}; + +static void +expandbuying(region * r, request * buyorders) +{ + int max_products; + unit *u; + static struct trade { + const luxury_type * type; + int number; + int multi; + } *trades, *trade; + static int ntrades=0; + int i, j; + const luxury_type * ltype; + + if (ntrades==0) { + for (ltype=luxurytypes;ltype;ltype=ltype->next) + ++ntrades; + trades = gc_add(calloc(sizeof(struct trade), ntrades)); + for (i=0, ltype=luxurytypes;i!=ntrades;++i, ltype=ltype->next) + trades[i].type = ltype; + } + for (i=0;i!=ntrades;++i) { + trades[i].number = 0; + trades[i].multi = 1; + } + + if (!buyorders) return; + + /* Initialisation. multiplier ist der Multiplikator auf den + * Verkaufspreis. Für max_products Produkte kauft man das Produkt zum + * einfachen Verkaufspreis, danach erhöht sich der Multiplikator um 1. + * counter ist ein Zähler, der die gekauften Produkte zählt. money + * wird für die debug message gebraucht. */ + + max_products = rpeasants(r) / TRADE_FRACTION; + + /* Kauf - auch so programmiert, daß er leicht erweiterbar auf mehrere + * Güter pro Monat ist. j sind die Befehle, i der Index des + * gehandelten Produktes. */ + if (max_products>0) { + expandorders(r, buyorders); + if (!norders) return; + + for (j = 0; j != norders; j++) { + int price, multi; + ltype = oa[j].type.ltype; + trade = trades; + while (trade->type!=ltype) ++trade; + multi = trade->multi; + price = ltype->price * multi; + + if (get_pooled(oa[j].unit, oldresourcetype[R_SILVER], GET_DEFAULT, price) >= price) { + unit * u = oa[j].unit; + item * items; + + /* litems zählt die Güter, die verkauft wurden, u->n das Geld, das + * verdient wurde. Dies muß gemacht werden, weil der Preis ständig sinkt, + * man sich also das verdiente Geld und die verkauften Produkte separat + * merken muß. */ + attrib * a = a_find(u->attribs, &at_luxuries); + if (a==NULL) a = a_add(&u->attribs, a_new(&at_luxuries)); + + items = a->data.v; + i_change(&items, ltype->itype, 1); + a->data.v = items; + i_change(&oa[j].unit->items, ltype->itype, 1); + use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, price); + if (u->n < 0) + u->n = 0; + u->n += price; + + rsetmoney(r, rmoney(r) + price); + + /* Falls mehr als max_products Bauern ein Produkt verkauft haben, steigt + * der Preis Multiplikator für das Produkt um den Faktor 1. Der Zähler + * wird wieder auf 0 gesetzt. */ + if (++trade->number == max_products) { + trade->number = 0; + ++trade->multi; + } + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + } + } + free(oa); + + /* Ausgabe an Einheiten */ + + for (u = r->units; u; u = u->next) { + attrib * a = a_find(u->attribs, &at_luxuries); + item * itm; + if (a==NULL) continue; + ADDMSG(&u->faction->msgs, msg_message("buy", "unit money", u, u->n)); + for (itm=(item*)a->data.v; itm; itm=itm->next) { + if (itm->number) { + ADDMSG(&u->faction->msgs, msg_message("buyamount", + "unit amount resource", u, itm->number, itm->type->rtype)); + } + } + a_remove(&u->attribs, a); + } + } +} + +attrib_type at_trades = { + "trades", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +static void +buy(unit * u, request ** buyorders, struct order * ord) +{ + region * r = u->region; + int n, k; + request *o; + attrib * a; + const item_type * itype = NULL; + const luxury_type * ltype = NULL; + if (u->ship && is_guarded(r, u, GUARD_CREWS)) { + cmistake(u, ord, 69, MSG_INCOME); + return; + } + if (u->ship && is_guarded(r, u, GUARD_CREWS)) { + cmistake(u, ord, 69, MSG_INCOME); + return; + } + /* Im Augenblick kann man nur 1 Produkt kaufen. expandbuying ist aber + * schon dafür ausgerüstet, mehrere Produkte zu kaufen. */ + + init_tokens(ord); + skip_token(); + n = getuint(); + if (!n) { + cmistake(u, ord, 26, MSG_COMMERCE); + return; + } + if (besieged(u)) { + /* Belagerte Einheiten können nichts kaufen. */ + cmistake(u, ord, 60, MSG_COMMERCE); + return; + } + + if (u->race == new_race[RC_INSECT]) { + /* entweder man ist insekt, oder... */ + if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT) && !rbuildings(r)) { + cmistake(u, ord, 119, MSG_COMMERCE); + return; + } + } else { + /* ...oder in der Region muß es eine Burg geben. */ + building * b; + static const struct building_type * bt_castle; + if (!bt_castle) bt_castle = bt_find("castle"); + for (b=r->buildings;b;b=b->next) { + if (b->type==bt_castle && b->size>=2) break; + } + if (b==NULL) { + cmistake(u, ord, 119, MSG_COMMERCE); + return; + } + } + + /* Ein Händler kann nur 10 Güter pro Talentpunkt handeln. */ + k = u->number * 10 * eff_skill(u, SK_TRADE, r); + + /* hat der Händler bereits gehandelt, muss die Menge der bereits + * verkauften/gekauften Güter abgezogen werden */ + a = a_find(u->attribs, &at_trades); + if (!a) { + a = a_add(&u->attribs, a_new(&at_trades)); + } else { + k -= a->data.i; + } + + n = MIN(n, k); + + if (!n) { + cmistake(u, ord, 102, MSG_COMMERCE); + return; + } + + assert(n>=0); + /* die Menge der verkauften Güter merken */ + a->data.i += n; + + itype = finditemtype(getstrtoken(), u->faction->locale); + if (itype!=NULL) { + ltype = resource2luxury(itype->rtype); + if (ltype==NULL) { + cmistake(u, ord, 124, MSG_COMMERCE); + return; + } + } + if (r_demand(r, ltype)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "luxury_notsold", "")); + return; + } + o = (request *) calloc(1, sizeof(request)); + o->type.ltype = ltype; /* sollte immer gleich sein */ + + o->unit = u; + o->qty = n; + addlist(buyorders, o); +} +/* ------------------------------------------------------------- */ + +/* Steuersätze in % bei Burggröße */ +static int tax_per_size[7] = +{0, 6, 12, 18, 24, 30, 36}; + +static void +expandselling(region * r, request * sellorders, int limit) +{ + int money, price, j, max_products; + /* int m, n = 0; */ + int maxsize = 0, maxeffsize = 0; + int taxcollected = 0; + int hafencollected = 0; + unit *maxowner = (unit *) NULL; + building *maxb = (building *) NULL; + building *b; + unit *u; + unit *hafenowner; + static int *counter; + static int ncounter = 0; + + if (ncounter==0) { + const luxury_type * ltype; + for (ltype=luxurytypes;ltype;ltype=ltype->next) ++ncounter; + counter=(int*)gc_add(calloc(sizeof(int), ncounter)); + } else { + memset(counter, 0, sizeof(int)*ncounter); + } + + if (!sellorders) { /* NEIN, denn Insekten können in || !r->buildings) */ + return; /* Sümpfen und Wüsten auch so handeln */ + } + /* Stelle Eigentümer der größten Burg fest. Bekommt Steuern aus jedem + * Verkauf. Wenn zwei Burgen gleicher Größe bekommt gar keiner etwas. */ + + for (b = rbuildings(r); b; b = b->next) { + if (b->size > maxsize && building_owner(b) != NULL + && b->type == bt_find("castle")) { + maxb = b; + maxsize = b->size; + maxowner = building_owner(b); + } else if (b->size == maxsize && b->type == bt_find("castle")) { + maxb = (building *) NULL; + maxowner = (unit *) NULL; + } + } + + hafenowner = owner_buildingtyp(r, bt_find("harbour")); + + if (maxb != (building *) NULL && maxowner != (unit *) NULL) { + maxeffsize = buildingeffsize(maxb, false); + if (maxeffsize == 0) { + maxb = (building *) NULL; + maxowner = (unit *) NULL; + } + } + /* Die Region muss genug Geld haben, um die Produkte kaufen zu können. */ + + money = rmoney(r); + + /* max_products sind 1/100 der Bevölkerung, falls soviele Produkte + * verkauft werden - counter[] - sinkt die Nachfrage um 1 Punkt. + * multiplier speichert r->demand für die debug message ab. */ + + max_products = rpeasants(r) / TRADE_FRACTION; + if (max_products <= 0) return; + + if (r->terrain == newterrain(T_DESERT) && buildingtype_exists(r, bt_find("caravan"), true)) { + max_products = rpeasants(r) * 2 / TRADE_FRACTION; + } + /* Verkauf: so programmiert, dass er leicht auf mehrere Gueter pro + * Runde erweitert werden kann. */ + + expandorders(r, sellorders); + if (!norders) return; + + for (j = 0; j != norders; j++) { + static const luxury_type * search=NULL; + const luxury_type * ltype = oa[j].type.ltype; + int multi = r_demand(r, ltype); + static int i=-1; + int use = 0; + if (search!=ltype) { + i=0; + for (search=luxurytypes;search!=ltype;search=search->next) ++i; + } + if (counter[i]>=limit) continue; + if (counter[i]+1 > max_products && multi > 1) --multi; + price = ltype->price * multi; + + if (money >= price) { + int abgezogenhafen = 0; + int abgezogensteuer = 0; + unit * u = oa[j].unit; + item * itm; + attrib * a = a_find(u->attribs, &at_luxuries); + if (a==NULL) a = a_add(&u->attribs, a_new(&at_luxuries)); + itm = (item *)a->data.v; + i_change(&itm, ltype->itype, 1); + a->data.v = itm; + ++use; + if (u->n < 0) + u->n = 0; + + if (hafenowner != NULL) { + if (hafenowner->faction != u->faction) { + abgezogenhafen = price / 10; + hafencollected += abgezogenhafen; + price -= abgezogenhafen; + money -= abgezogenhafen; + } + } + if (maxb != NULL) { + if (maxowner->faction != u->faction) { + abgezogensteuer = price * tax_per_size[maxeffsize] / 100; + taxcollected += abgezogensteuer; + price -= abgezogensteuer; + money -= abgezogensteuer; + } + } + u->n += price; + change_money(u, price); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + + /* r->money -= price; --- dies wird eben nicht ausgeführt, denn die + * Produkte können auch als Steuern eingetrieben werden. In der Region + * wurden Silberstücke gegen Luxusgüter des selben Wertes eingetauscht! + * Falls mehr als max_products Kunden ein Produkt gekauft haben, sinkt + * die Nachfrage für das Produkt um 1. Der Zähler wird wieder auf 0 + * gesetzt. */ + + if (++counter[i] > max_products) { + int d = r_demand(r, ltype); + if (d > 1) { + r_setdemand(r, ltype, d-1); + } + counter[i] = 0; + } + } + if (use>0) { +#ifdef NDEBUG + use_pooled(oa[j].unit, ltype->itype->rtype, GET_DEFAULT, use); +#else + /* int i = */ use_pooled(oa[j].unit, ltype->itype->rtype, GET_DEFAULT, use); + /* assert(i==use); */ +#endif + } + } + free(oa); + + /* Steuern. Hier werden die Steuern dem Besitzer der größten Burg gegeben. */ + + if (maxowner) { + if (taxcollected > 0) { + change_money(maxowner, (int) taxcollected); + add_income(maxowner, IC_TRADETAX, taxcollected, taxcollected); + /* TODO: Meldung + * "%s verdient %d Silber durch den Handel in %s.", + * unitname(maxowner), (int) taxcollected, regionname(r)); */ + } + } + if (hafenowner) { + if (hafencollected > 0) { + change_money(hafenowner, (int) hafencollected); + add_income(hafenowner, IC_TRADETAX, hafencollected, hafencollected); + } + } + /* Berichte an die Einheiten */ + + for (u = r->units; u; u = u->next) { + + attrib * a = a_find(u->attribs, &at_luxuries); + item * itm; + if (a==NULL) continue; + for (itm=(item*)a->data.v; itm; itm=itm->next) { + if (itm->number) { + ADDMSG(&u->faction->msgs, msg_message("sellamount", + "unit amount resource", u, itm->number, itm->type->rtype)); + } + } + a_remove(&u->attribs, a); + add_income(u, IC_TRADE, u->n, u->n); + } +} + +static boolean + sell(unit * u, request ** sellorders, struct order * ord) +{ + boolean unlimited = true; + const item_type * itype; + const luxury_type * ltype=NULL; + int n; + region * r = u->region; + const char *s; + + if (u->ship && is_guarded(r, u, GUARD_CREWS)) { + cmistake(u, ord, 69, MSG_INCOME); + return false; + } + /* sellorders sind KEIN array, weil für alle items DIE SELBE resource + * (das geld der region) aufgebraucht wird. */ + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + if (findparam(s, u->faction->locale) == P_ANY) { + unlimited = false; + n = rpeasants(r) / TRADE_FRACTION; + if (r->terrain == newterrain(T_DESERT) && buildingtype_exists(r, bt_find("caravan"), true)) + n *= 2; + if (n==0) { + cmistake(u, ord, 303, MSG_COMMERCE); + return false; + } + } else { + n = atoi((const char *)s); + if (n==0) { + cmistake(u, ord, 27, MSG_COMMERCE); + return false; + } + } + /* Belagerte Einheiten können nichts verkaufen. */ + + if (besieged(u)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "error60", "")); + return false; + } + /* In der Region muß es eine Burg geben. */ + + if (u->race == new_race[RC_INSECT]) { + if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT) && !rbuildings(r)) { + cmistake(u, ord, 119, MSG_COMMERCE); + return false; + } + } else { + /* ...oder in der Region muß es eine Burg geben. */ + building * b; + static const struct building_type * bt_castle; + if (!bt_castle) bt_castle = bt_find("castle"); + for (b=r->buildings;b;b=b->next) { + if (b->type==bt_castle && b->size>=2) break; + } + if (b==NULL) { + cmistake(u, ord, 119, MSG_COMMERCE); + return false; + } + } + + /* Ein Händler kann nur 10 Güter pro Talentpunkt verkaufen. */ + + n = MIN(n, u->number * 10 * eff_skill(u, SK_TRADE, r)); + + if (!n) { + cmistake(u, ord, 54, MSG_COMMERCE); + return false; + } + s=getstrtoken(); + itype = finditemtype(s, u->faction->locale); + if (itype!=NULL) ltype = resource2luxury(itype->rtype); + if (ltype==NULL) { + cmistake(u, ord, 126, MSG_COMMERCE); + return false; + } + else { + attrib * a; + request *o; + int k, available; + + if (!r_demand(r, ltype)) { + cmistake(u, ord, 263, MSG_COMMERCE); + return false; + } + available = get_pooled(u, itype->rtype, GET_DEFAULT, INT_MAX); + + /* Wenn andere Einheiten das selbe verkaufen, muß ihr Zeug abgezogen + * werden damit es nicht zweimal verkauft wird: */ + for (o=*sellorders;o;o=o->next) { + if (o->type.ltype==ltype && o->unit->faction == u->faction) { + int fpool = o->qty - get_pooled(o->unit, itype->rtype, GET_RESERVE, INT_MAX); + available -= MAX(0, fpool); + } + } + + n = MIN(n, available); + + if (n <= 0) { + cmistake(u, ord, 264, MSG_COMMERCE); + return false; + } + /* Hier wird request->type verwendet, weil die obere limit durch + * das silber gegeben wird (region->money), welches für alle + * (!) produkte als summe gilt, als nicht wie bei der + * produktion, wo für jedes produkt einzeln eine obere limite + * existiert, so dass man arrays von orders machen kann. */ + + /* Ein Händler kann nur 10 Güter pro Talentpunkt handeln. */ + k = u->number * 10 * eff_skill(u, SK_TRADE, r); + + /* hat der Händler bereits gehandelt, muss die Menge der bereits + * verkauften/gekauften Güter abgezogen werden */ + a = a_find(u->attribs, &at_trades); + if (!a) { + a = a_add(&u->attribs, a_new(&at_trades)); + } else { + k -= a->data.i; + } + + n = MIN(n, k); + assert(n>=0); + /* die Menge der verkauften Güter merken */ + a->data.i += n; + o = (request *) calloc(1, sizeof(request)); + o->unit = u; + o->qty = n; + o->type.ltype = ltype; + addlist(sellorders, o); + + return unlimited; + } +} +/* ------------------------------------------------------------- */ + +static void +expandstealing(region * r, request * stealorders) +{ + int i; + + expandorders(r, stealorders); + if (!norders) return; + + /* Für jede unit in der Region wird Geld geklaut, wenn sie Opfer eines + * Beklauen-Orders ist. Jedes Opfer muß einzeln behandelt werden. + * + * u ist die beklaute unit. oa.unit ist die klauende unit. + */ + + for (i = 0; i != norders && oa[i].unit->n <= oa[i].unit->wants; i++) { + unit *u = findunitg(oa[i].no, r); + int n = 0; + if (u && u->region==r) { + n = get_pooled(u, r_silver, GET_ALL, INT_MAX); + } +#ifndef GOBLINKILL + if (oa[i].type.goblin) { /* Goblin-Spezialklau */ + int uct = 0; + unit *u2; + assert(effskill(oa[i].unit, SK_STEALTH)>=4 || !"this goblin\'s skill is too low"); + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->faction == u->faction) { + uct += maintenance_cost(u2); + } + } + n -= uct * 2; + } +#endif + if (n>10 && rplane(r) && (rplane(r)->flags & PFL_NOALLIANCES)) { + /* In Questen nur reduziertes Klauen */ + n = 10; + } + if (n > 0) { + n = MIN(n, oa[i].unit->wants); + use_pooled(u, r_silver, GET_ALL, n); + oa[i].unit->n = n; + change_money(oa[i].unit, n); + ADDMSG(&u->faction->msgs, msg_message("stealeffect", "unit region amount", u, u->region, n)); + } + add_income(oa[i].unit, IC_STEAL, oa[i].unit->wants, oa[i].unit->n); + fset(oa[i].unit, UFL_LONGACTION|UFL_NOTMOVING); + } + free(oa); +} + +/* ------------------------------------------------------------- */ +static void +plant(region *r, unit *u, int raw) +{ + int n, i, skill, planted = 0; + const item_type * itype; + static const resource_type * rt_water = NULL; + if (rt_water==NULL) rt_water = rt_find("p2"); + + assert(rt_water!=NULL); + if (!fval(r->terrain, LAND_REGION)) { + return; + } + if (rherbtype(r) == NULL) { + cmistake(u, u->thisorder, 108, MSG_PRODUCE); + return; + } + + /* Skill prüfen */ + skill = eff_skill(u, SK_HERBALISM, r); + itype = rherbtype(r); + if (skill < 6) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "plant_skills", + "skill minskill product", SK_HERBALISM, 6, itype->rtype, 1)); + return; + } + /* Wasser des Lebens prüfen */ + if (get_pooled(u, rt_water, GET_DEFAULT, 1) == 0) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "resource_missing", "missing", rt_water)); + return; + } + n = get_pooled(u, itype->rtype, GET_DEFAULT, skill*u->number); + /* Kräuter prüfen */ + if (n==0) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "resource_missing", "missing", + itype->rtype)); + return; + } + + n = MIN(skill*u->number, n); + n = MIN(raw, n); + /* Für jedes Kraut Talent*10% Erfolgschance. */ + for(i = n; i>0; i--) { + if (rng_int()%10 < skill) planted++; + } + produceexp(u, SK_HERBALISM, u->number); + + /* Alles ok. Abziehen. */ + use_pooled(u, rt_water, GET_DEFAULT, 1); + use_pooled(u, itype->rtype, GET_DEFAULT, n); + rsetherbs(r, rherbs(r)+planted); + ADDMSG(&u->faction->msgs, msg_message("plant", "unit region amount herb", + u, r, planted, itype->rtype)); +} + +static void +planttrees(region *r, unit *u, int raw) +{ + int n, i, skill, planted = 0; + const resource_type * rtype; + + if (!fval(r->terrain, LAND_REGION)) { + return; + } + + /* Mallornbäume kann man nur in Mallornregionen züchten */ + if (fval(r, RF_MALLORN)) { + rtype = rt_mallornseed; + } else { + rtype = rt_seed; + } + + /* Skill prüfen */ + skill = eff_skill(u, SK_HERBALISM, r); + if (skill < 6) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "plant_skills", + "skill minskill product", SK_HERBALISM, 6, rtype, 1)); + return; + } + if (fval(r, RF_MALLORN) && skill < 7 ) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "plant_skills", + "skill minskill product", SK_HERBALISM, 7, rtype, 1)); + return; + } + + /* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */ + raw = MIN(raw, skill*u->number); + n = get_pooled(u, rtype, GET_DEFAULT, raw); + if (n==0) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype)); + return; + } + n = MIN(raw, n); + + /* Für jeden Samen Talent*10% Erfolgschance. */ + for(i = n; i>0; i--) { + if (rng_int()%10 < skill) planted++; + } + rsettrees(r, 0, rtrees(r, 0)+planted); + + /* Alles ok. Abziehen. */ + produceexp(u, SK_HERBALISM, u->number); + use_pooled(u, rtype, GET_DEFAULT, n); + + ADDMSG(&u->faction->msgs, msg_message("plant", + "unit region amount herb", u, r, planted, rtype)); +} + +/* züchte bäume */ +static void +breedtrees(region *r, unit *u, int raw) +{ + int n, i, skill, planted = 0; + const resource_type * rtype; + static int gamecookie = -1; + static int current_season; + + if (gamecookie!=global.cookie) { + gamedate date; + get_gamedate(turn, &date); + current_season = date.season; + gamecookie = global.cookie; + } + + /* Bäume züchten geht nur im Frühling */ + if (current_season != SEASON_SPRING){ + planttrees(r, u, raw); + return; + } + + if (!fval(r->terrain, LAND_REGION)) { + return; + } + + /* Mallornbäume kann man nur in Mallornregionen züchten */ + if (fval(r, RF_MALLORN)) { + rtype = rt_mallornseed; + } else { + rtype = rt_seed; + } + + /* Skill prüfen */ + skill = eff_skill(u, SK_HERBALISM, r); + if (skill < 12) { + planttrees(r, u, raw); + return; + } + + /* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */ + raw = MIN(skill*u->number, raw); + n = get_pooled(u, rtype, GET_DEFAULT, raw); + /* Samen prüfen */ + if (n==0) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype)); + return; + } + n = MIN(raw, n); + + /* Für jeden Samen Talent*5% Erfolgschance. */ + for(i = n; i>0; i--) { + if (rng_int()%100 < skill*5) planted++; + } + rsettrees(r, 1, rtrees(r, 1)+planted); + + /* Alles ok. Abziehen. */ + produceexp(u, SK_HERBALISM, u->number); + use_pooled(u, rtype, GET_DEFAULT, n); + + ADDMSG(&u->faction->msgs, msg_message("plant", + "unit region amount herb", u, r, planted, rtype)); +} + +/* züchte pferde */ +static void +breedhorses(region *r, unit *u) +{ + int n, c; + int gezuechtet = 0; + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + + if (btype!=bt_find("stables")) { + cmistake(u, u->thisorder, 122, MSG_PRODUCE); + return; + } + if (get_item(u, I_HORSE) < 2) { + cmistake(u, u->thisorder, 107, MSG_PRODUCE); + return; + } + n = MIN(u->number * eff_skill(u, SK_HORSE_TRAINING, r), get_item(u, I_HORSE)); + + for (c = 0; c < n; c++) { + if (rng_int() % 100 < eff_skill(u, SK_HORSE_TRAINING, r)) { + i_change(&u->items, olditemtype[I_HORSE], 1); + gezuechtet++; + } + } + + produceexp(u, SK_HORSE_TRAINING, u->number); + + ADDMSG(&u->faction->msgs, msg_message("raised", + "unit amount", u, gezuechtet)); +} + +static void +breed_cmd(unit *u, struct order * ord) +{ + int m; + const char *s; + param_t p; + region *r = u->region; + const resource_type * rtype = NULL; + + if (r->land==NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); + return; + } + + /* züchte [] */ + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + m = atoi((const char *)s); + if (m!=0) { + /* first came a want-paramter */ + s = getstrtoken(); + } else { + m = INT_MAX; + } + + if (!s[0]) { + p = P_ANY; + } else { + p = findparam(s, u->faction->locale); + } + + switch (p) { + case P_HERBS: + plant(r, u, m); + break; + case P_TREES: + breedtrees(r, u, m); + break; + default: + if (p!=P_ANY) { + rtype = findresourcetype(s, u->faction->locale); + if (rtype==rt_mallornseed || rtype==rt_seed) { + breedtrees(r, u, m); + break; + } else if (rtype!=oldresourcetype[R_HORSE]) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_cannotmake", "")); + break; + } + } + breedhorses(r, u); + break; + } +} + +static const char * +rough_amount(int a, int m) + +{ + int p = (a * 100)/m; + + if (p < 10) { + return "sehr wenige"; + } else if (p < 30) { + return "wenige"; + } else if (p < 60) { + return "relativ viele"; + } else if (p < 90) { + return "viele"; + } + return "sehr viele"; +} + +static void +research_cmd(unit *u, struct order * ord) +{ + region *r = u->region; + + init_tokens(ord); + skip_token(); + /* + const char *s = getstrtoken(); + + if (findparam(s, u->faction->locale) == P_HERBS) { */ + + if (eff_skill(u, SK_HERBALISM, r) < 7) { + cmistake(u, ord, 227, MSG_EVENT); + return; + } + + produceexp(u, SK_HERBALISM, u->number); + + if (rherbs(r) > 0) { + const item_type *itype = rherbtype(r); + + if (itype != NULL) { + ADDMSG(&u->faction->msgs, msg_message("researchherb", + "unit region amount herb", + u, r, rough_amount(rherbs(r), 100), itype->rtype)); + } else { + ADDMSG(&u->faction->msgs, msg_message("researchherb_none", + "unit region", u, r)); + } + } else { + ADDMSG(&u->faction->msgs, msg_message("researchherb_none", + "unit region", u, r)); + } +} + +static int +max_skill(region * r, faction * f, skill_t sk) +{ + unit *u; + int w = 0; + + for (u = r->units; u; u = u->next) { + if (u->faction == f) { + if (eff_skill(u, sk, r) > w) { + w = eff_skill(u, sk, r); + } + } + } + + return w; +} + +static void +steal_cmd(unit * u, struct order * ord, request ** stealorders) +{ + int n, i, id; + boolean goblin = false; + request * o; + unit * u2 = NULL; + region * r = u->region; + faction * f = NULL; + plane * pl; + + assert(skill_enabled[SK_PERCEPTION] && skill_enabled[SK_STEALTH]); + + if (!fval(u->race, RCF_CANSTEAL)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_nosteal", "race", u->race)); + return; + } + + if (fval(r->terrain, SEA_REGION) && u->race != new_race[RC_AQUARIAN]) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); + return; + } + + pl = rplane(r); + if (pl && fval(pl, PFL_NOATTACK)) { + cmistake(u, ord, 270, MSG_INCOME); + return; + } + + init_tokens(ord); + skip_token(); + id = read_unitid(u->faction, r); + u2 = findunitr(r, id); + + if (u2 && u2->region==u->region) { + f = u2->faction; + } else { + f = dfindhash(id); + } + + for (u2=r->units;u2;u2=u2->next) { + if (u2->faction == f && cansee(u->faction, r, u2, 0)) break; + } + + if (!u2) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + + if (IsImmune(u2->faction)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "newbie_immunity_error", + "turns", NewbieImmunity())); + return; + } + + if (u->faction->alliance && u->faction->alliance == u2->faction->alliance) { + cmistake(u, ord, 47, MSG_INCOME); + return; + } + + assert(u->region==u2->region); + if (!can_contact(r, u, u2)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error60", "")); + return; + } + + n = eff_skill(u, SK_STEALTH, r) - max_skill(r, f, SK_PERCEPTION); + + if (n <= 0) { + /* Wahrnehmung == Tarnung */ + if (u->race != new_race[RC_GOBLIN] || eff_skill(u, SK_STEALTH, r) <= 3) { + ADDMSG(&u->faction->msgs, msg_message("stealfail", "unit target", u, u2)); + if (n==0) { + ADDMSG(&u2->faction->msgs, msg_message("stealdetect", "unit", u2)); + } else { + ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target", u, u2)); + } + return; + } else { + ADDMSG(&u->faction->msgs, msg_message("stealfatal", "unit target", u, u2)); + ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target", u, u2)); + n = 1; + goblin = true; + } + } + + i = MIN(u->number, get_item(u, I_RING_OF_NIMBLEFINGER)); + if (i > 0) { + n *= STEALINCOME * (u->number + i * (roqf_factor()-1)); + } else { + n *= u->number * STEALINCOME; + } + + u->wants = n; + + /* wer dank unsichtbarkeitsringen klauen kann, muss nicht unbedingt ein + * guter dieb sein, schliesslich macht man immer noch sehr viel laerm */ + + o = (request *) calloc(1, sizeof(request)); + o->unit = u; + o->qty = 1; /* Betrag steht in u->wants */ + o->no = u2->no; + o->type.goblin = goblin; /* Merken, wenn Goblin-Spezialklau */ + addlist(stealorders, o); + + /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ + + produceexp(u, SK_STEALTH, MIN(n, u->number)); +} +/* ------------------------------------------------------------- */ + + +static void +expandentertainment(region * r) +{ + unit *u; + int m = entertainmoney(r); + request *o; + + for (o = &entertainers[0]; o != nextentertainer; ++o) { + double part = m / (double) entertaining; + u = o->unit; + if (entertaining <= m) + u->n = o->qty; + else + u->n = (int) (o->qty * part); + change_money(u, u->n); + rsetmoney(r, rmoney(r) - u->n); + m -= u->n; + entertaining -= o->qty; + + /* Nur soviel PRODUCEEXP wie auch tatsächlich gemacht wurde */ + produceexp(u, SK_ENTERTAINMENT, MIN(u->n, u->number)); + add_income(u, IC_ENTERTAIN, o->qty, u->n); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + } +} + +void +entertain_cmd(unit * u, struct order * ord) +{ + region * r = u->region; + int max_e; + request *o; + static int entertainbase = 0; + static int entertainperlevel = 0; + + if (!entertainbase) { + const char * str = get_param(global.parameters, "entertain.base"); + entertainbase = str?atoi(str):0; + } + if (!entertainperlevel) { + const char * str = get_param(global.parameters, "entertain.perlevel"); + entertainperlevel = str?atoi(str):0; + } + if (fval(u, UFL_WERE)) { + cmistake(u, ord, 58, MSG_INCOME); + return; + } + if (!effskill(u, SK_ENTERTAINMENT)) { + cmistake(u, ord, 58, MSG_INCOME); + return; + } + if (besieged(u)) { + cmistake(u, ord, 60, MSG_INCOME); + return; + } + if (u->ship && is_guarded(r, u, GUARD_CREWS)) { + cmistake(u, ord, 69, MSG_INCOME); + return; + } + if (is_cursed(r->attribs, C_DEPRESSION, 0)) { + cmistake(u, ord, 28, MSG_INCOME); + return; + } + + u->wants = u->number * (entertainbase + effskill(u, SK_ENTERTAINMENT) + * entertainperlevel); + + init_tokens(ord); + skip_token(); + max_e = getuint(); + if (max_e != 0) { + u->wants = MIN(u->wants,max_e); + } + o = nextentertainer++; + o->unit = u; + o->qty = u->wants; + entertaining += o->qty; +} + +/** + * \return number of working spaces taken by players + */ +static void +expandwork(region * r, request * work_begin, request * work_end, int maxwork) +{ + int earnings; + /* n: verbleibende Einnahmen */ + /* fishes: maximale Arbeiter */ + int jobs = maxwork; + int p_wage = wage(r, NULL, NULL, turn); + int money = rmoney(r); + request *o; + + for (o = work_begin; o != work_end; ++o) { + unit * u = o->unit; + int workers; + + if (u->number == 0) continue; + + if (jobs>=working) workers = u->number; + else { + workers = u->number * jobs / working; + if (rng_int() % working < (u->number * jobs) % working) workers++; + } + + assert(workers>=0); + + u->n = workers * wage(u->region, u->faction, u->race, turn); + + jobs -= workers; + assert(jobs>=0); + + change_money(u, u->n); + working -= o->unit->number; + add_income(u, IC_WORK, o->qty, u->n); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + } + + if (jobs>rpeasants(r)) { + jobs = rpeasants(r); + } + earnings = jobs * p_wage; + if (rule_blessed_harvest()==HARVEST_TAXES) { + /* E3 rules */ + static const curse_type * blessedharvest_ct; + if (!blessedharvest_ct) { + blessedharvest_ct = ct_find("blessedharvest"); + } + if (blessedharvest_ct && r->attribs) { + int happy = (int)curse_geteffect(get_curse(r->attribs, blessedharvest_ct)); + happy = MIN(happy, jobs); + earnings += happy; + } + } + rsetmoney(r, money + earnings); +} + +static int +do_work(unit * u, order * ord, request * o) +{ + if (playerrace(u->race)) { + region * r = u->region; + int w; + + if (fval(u, UFL_WERE)) { + if (ord) cmistake(u, ord, 313, MSG_INCOME); + return -1; + } + if (besieged(u)) { + if (ord) cmistake(u, ord, 60, MSG_INCOME); + return -1; + } + if (u->ship && is_guarded(r, u, GUARD_CREWS)) { + if (ord) cmistake(u, ord, 69, MSG_INCOME); + return -1; + } + w = wage(r, u->faction, u->race, turn); + u->wants = u->number * w; + o->unit = u; + o->qty = u->number * w; + working += u->number; + return 0; + } + else if (ord && !is_monsters(u->faction)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_cantwork", "race", u->race)); + } + return -1; +} + +static void +expandtax(region * r, request * taxorders) +{ + unit *u; + int i; + + expandorders(r, taxorders); + if (!norders) return; + + for (i = 0; i != norders && rmoney(r) > TAXFRACTION; i++) { + change_money(oa[i].unit, TAXFRACTION); + oa[i].unit->n += TAXFRACTION; + rsetmoney(r, rmoney(r) -TAXFRACTION); + } + free(oa); + + for (u = r->units; u; u = u->next) { + if (u->n >= 0) { + add_income(u, IC_TAX, u->wants, u->n); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + } + } +} + +void +tax_cmd(unit * u, struct order * ord, request ** taxorders) +{ + /* Steuern werden noch vor der Forschung eingetrieben */ + region * r = u->region; + unit *u2; + int n; + request *o; + int max; + + if (!humanoidrace(u->race) && !is_monsters(u->faction)) { + cmistake(u, ord, 228, MSG_INCOME); + return; + } + + if (fval(u, UFL_WERE)) { + cmistake(u, ord, 228, MSG_INCOME); + return; + } + + if (besieged(u)) { + cmistake(u, ord, 60, MSG_INCOME); + return; + } + n = armedmen(u, false); + + if (!n) { + cmistake(u, ord, 48, MSG_INCOME); + return; + } + + init_tokens(ord); + skip_token(); + max = getuint(); + + if (max == 0) max = INT_MAX; + if (!playerrace(u->race)) { + u->wants = MIN(income(u), max); + } else { + u->wants = MIN(n * eff_skill(u, SK_TAXING, r) * 20, max); + } + + u2 = is_guarded(r, u, GUARD_TAX); + if (u2) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "region_guarded", "guard", u2)); + return; + } + + /* die einnahmen werden in fraktionen von 10 silber eingeteilt: diese + * fraktionen werden dann bei eintreiben unter allen eintreibenden + * einheiten aufgeteilt. */ + + o = (request *) calloc(1, sizeof(request)); + o->qty = u->wants / TAXFRACTION; + o->unit = u; + addlist(taxorders, o); + return; +} + +#define MAX_WORKERS 2048 +void +auto_work(region * r) +{ + request workers[MAX_WORKERS]; + request * nextworker = workers; + unit * u; + + for (u=r->units;u;u=u->next) { + if (!(u->flags & UFL_LONGACTION) && !is_monsters(u->faction)) { + if (do_work(u, NULL, nextworker)==0) { + assert(nextworker-workersfaction!=f) return; + + maxsize = buildingeffsize(b, false); + if (maxsize>0) { + double taxfactor = money * b->type->taxes(b, maxsize); + double morale = money * region_get_morale(r) * MORALE_TAX_FACTOR; + if (taxfactor>morale) taxfactor = morale; + if (taxfactor>0) { + int taxmoney = (int)taxfactor; + change_money(u, taxmoney); + rsetmoney(r, money - taxmoney); + ADDMSG(&u->faction->msgs, msg_message("income_tax", + "unit region amount", u, r, taxmoney)); + } + } +} + +void +produce(struct region *r) +{ + request workers[MAX_WORKERS]; + request *taxorders, *sellorders, *stealorders, *buyorders; + unit *u; + int todo; + static int rule_autowork = -1; + boolean limited = true; + request * nextworker = workers; + assert(r); + + /* das sind alles befehle, die 30 tage brauchen, und die in thisorder + * stehen! von allen 30-tage befehlen wird einfach der letzte verwendet + * (dosetdefaults). + * + * kaufen vor einnahmequellen. da man in einer region dasselbe produkt + * nicht kaufen und verkaufen kann, ist die reihenfolge wegen der + * produkte egal. nicht so wegen dem geld. + * + * lehren vor lernen. */ + + if (rule_autowork<0) { + rule_autowork = get_param_int(global.parameters, "work.auto", 0); + } + + assert(rmoney(r) >= 0); + assert(rpeasants(r) >= 0); + + if (r->land && rule_auto_taxation()) { + /* new taxation rules, region owners make money based on morale and building */ + peasant_taxes(r); + } + + buyorders = 0; + sellorders = 0; + working = 0; + nextentertainer = &entertainers[0]; + entertaining = 0; + taxorders = 0; + stealorders = 0; + + for (u = r->units; u; u = u->next) { + order * ord; + boolean trader = false; + + if (u->race == new_race[RC_SPELL] || fval(u, UFL_LONGACTION)) + continue; + + if (u->race == new_race[RC_INSECT] && r_insectstalled(r) && + !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) + continue; + + if (fval(u, UFL_LONGACTION) && u->thisorder==NULL) { + cmistake(u, u->thisorder, 52, MSG_PRODUCE); + continue; + } + + for (ord = u->orders;ord;ord=ord->next) { + switch (get_keyword(ord)) { + case K_BUY: + buy(u, &buyorders, ord); + trader = true; + break; + case K_SELL: + /* sell returns true if the sale is not limited + * by the region limit */ + limited &= !sell(u, &sellorders, ord); + trader = true; + break; + } + } + if (trader) { + attrib * a = a_find(u->attribs, &at_trades); + if (a && a->data.i) { + produceexp(u, SK_TRADE, u->number); + } + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + continue; + } + + todo = get_keyword(u->thisorder); + if (todo == NOKEYWORD) continue; + + if (fval(r->terrain, SEA_REGION) && u->race != new_race[RC_AQUARIAN] + && !(u->race->flags & RCF_SWIM) + && todo != K_STEAL && todo != K_SPY && todo != K_SABOTAGE) + continue; + + switch (todo) { + + case K_ENTERTAIN: + entertain_cmd(u, u->thisorder); + break; + + case K_WORK: + if (!rule_autowork && do_work(u, u->thisorder, nextworker)==0) { + assert(nextworker-workersthisorder, &taxorders); + break; + + case K_STEAL: + steal_cmd(u, u->thisorder, &stealorders); + break; + + case K_SPY: + spy_cmd(u, u->thisorder); + break; + + case K_SABOTAGE: + sabotage_cmd(u, u->thisorder); + break; + + case K_PLANT: + case K_BREED: + breed_cmd(u, u->thisorder); + break; + + case K_RESEARCH: + research_cmd(u, u->thisorder); + break; + } + } + + /* Entertainment (expandentertainment) und Besteuerung (expandtax) vor den + * Befehlen, die den Bauern mehr Geld geben, damit man aus den Zahlen der + * letzten Runde berechnen kann, wieviel die Bauern für Unterhaltung + * auszugeben bereit sind. */ + if (entertaining) expandentertainment(r); + if (!rule_autowork) { + expandwork(r, workers, nextworker, maxworkingpeasants(r)); + } + if (taxorders) expandtax(r, taxorders); + + /* An erster Stelle Kaufen (expandbuying), die Bauern so Geld bekommen, um + * nachher zu beim Verkaufen (expandselling) den Spielern abkaufen zu + * können. */ + + if (buyorders) expandbuying(r, buyorders); + + if (sellorders) { + int limit = rpeasants(r) / TRADE_FRACTION; + if (r->terrain == newterrain(T_DESERT) && buildingtype_exists(r, bt_find("caravan"), true)) + limit *= 2; + expandselling(r, sellorders, limited?limit:INT_MAX); + } + + /* Die Spieler sollen alles Geld verdienen, bevor sie beklaut werden + * (expandstealing). */ + + if (stealorders) expandstealing(r, stealorders); + + assert(rmoney(r) >= 0); + assert(rpeasants(r) >= 0); +} diff --git a/src/gamecode/economy.h b/src/gamecode/economy.h new file mode 100644 index 000000000..db8359a63 --- /dev/null +++ b/src/gamecode/economy.h @@ -0,0 +1,60 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_GC_ECONOMY +#define H_GC_ECONOMY +#ifdef __cplusplus +extern "C" { +#endif + +/* Welchen Teil des Silbers die Bauern fuer Unterhaltung ausgeben (1/20), und + * wiviel Silber ein Unterhalter pro Talentpunkt bekommt. */ + +/* Wieviele Silbermuenzen jeweils auf einmal "getaxed" werden. */ + +#define TAXFRACTION 10 + +/* Wieviel Silber pro Talentpunkt geklaut wird. */ + +#define STEALINCOME 50 + +/* Teil der Bauern, welche Luxusgueter kaufen und verkaufen (1/100). */ + +#define TRADE_FRACTION 100 + +extern int income(const struct unit * u); + +/* Wieviel Fremde eine Partei pro Woche aufnehmen kann */ +#define MAXNEWBIES 5 + +void economics(struct region *r); +void produce(struct region *r); +void auto_work(struct region * r); + +enum { IC_WORK, IC_ENTERTAIN, IC_TAX, IC_TRADE, IC_TRADETAX, IC_STEAL, IC_MAGIC }; +void maintain_buildings(struct region * r, boolean crash); +extern void add_spende(struct faction * f1, struct faction * f2, int betrag, struct region * r); +extern int make_cmd(struct unit * u, struct order * ord); +extern void split_allocations(struct region * r); +extern int recruit_archetypes(void); +extern int give_control_cmd(struct unit * u, struct order * ord); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/give.c b/src/gamecode/give.c new file mode 100644 index 000000000..0bc783645 --- /dev/null +++ b/src/gamecode/give.c @@ -0,0 +1,438 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ +#include +#include +#include "give.h" + +#include "economy.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* attributes includes */ +#include +#include + +/* util includes */ +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +/* Wieviel Fremde eine Partei pro Woche aufnehmen kangiven */ +#define MAXNEWBIES 5 +#define RESERVE_DONATIONS /* shall we reserve objects given to us by other factions? */ +#define RESERVE_GIVE /* reserve anything that's given from one unit to another? */ + + +static int +GiveRestriction(void) { + static int value = -1; + if (value<0) { + const char * str = get_param(global.parameters, "GiveRestriction"); + value = str?atoi(str):0; + } + return value; +} + +static void +add_give(unit * u, unit * u2, int given, int received, const resource_type * rtype, struct order * ord, int error) +{ + if (error) { + cmistake(u, ord, error, MSG_COMMERCE); + } + else if (u2==NULL) { + ADDMSG(&u->faction->msgs, + msg_message("give_peasants", "unit resource amount", + u, rtype, given)); + } else if (u2->faction!=u->faction) { + message * msg; + + msg = msg_message("give", "unit target resource amount", u, u2, rtype, given); + add_message(&u->faction->msgs, msg); + msg_release(msg); + + msg = msg_message("receive", "unit target resource amount", u, u2, rtype, received); + add_message(&u2->faction->msgs, msg); + msg_release(msg); + } +} + +static boolean +limited_give(const item_type * type) +{ + /* trade only money 2:1, if at all */ + return (type == i_silver); +} + +int give_quota(const unit * src, const unit * dst, const item_type * type, int n) +{ + static float divisor = -1; + + if (divisor==0 || !limited_give(type)) { + return n; + } + if (dst && src && src->faction!=dst->faction) { + if (divisor<0) { + divisor = get_param_flt(global.parameters, "rules.items.give_divisor", 1); + assert(divisor==0 || divisor>=1); + } + if (divisor>=1) { + /* predictable > correct: */ + int x = (int)(n/divisor); + return x; + } + } + return n; +} + +int +give_item(int want, const item_type * itype, unit * src, unit * dest, struct order * ord) +{ + short error = 0; + int n, r; + + assert(itype!=NULL); + n = get_pooled(src, item2resource(itype), GET_DEFAULT, want); + n = MIN(want, n); + r = n; + if (dest && src->faction != dest->faction && src->faction->age < GiveRestriction()) { + if (ord!=NULL) { + ADDMSG(&src->faction->msgs, msg_feedback(src, ord, "giverestriction", + "turns", GiveRestriction())); + } + return -1; + } else if (n == 0) { + int reserve = get_reservation(src, itype->rtype); + if (reserve) { + msg_feedback(src, ord, "nogive_reserved", "resource reservation", + itype->rtype, reserve); + return -1; + } + error = 36; + } else if (itype->flags & ITF_CURSED) { + error = 25; + } else if (itype->give==NULL || itype->give(src, dest, itype, n, ord)!=0) { + int use = use_pooled(src, item2resource(itype), GET_SLACK, n); + if (useitems, itype, r); +#ifdef RESERVE_GIVE +#ifdef RESERVE_DONATIONS + change_reservation(dest, item2resource(itype), r); +#else + if (src->faction==dest->faction) { + change_reservation(dest, item2resource(itype), r); + } +#endif +#endif +#if MUSEUM_MODULE && defined(TODO) + /* TODO: use a trigger for the museum warden! */ + if (a_find(dest->attribs, &at_warden)) { + warden_add_give(src, dest, itype, r); + } +#endif + handle_event(dest->attribs, "receive", src); + } + handle_event(src->attribs, "give", dest); + } + add_give(src, dest, n, r, item2resource(itype), ord, error); + if (error) return -1; + return 0; +} + +void +give_men(int n, unit * u, unit * u2, struct order * ord) +{ + ship *sh; + int k = 0; + int error = 0; + + if (u2 && u->faction != u2->faction && u->faction->age < GiveRestriction()) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "giverestriction", + "turns", GiveRestriction())); + return; + } else if (u == u2) { + error = 10; + } else if (!u2 && u->race == new_race[RC_SNOTLING]) { + /* snotlings may not be given to the peasants. */ + error = 307; + } else if (u2 && u2->number && (fval(u, UFL_HERO) != fval(u2, UFL_HERO))) { + /* heroes may not be given to non-heroes and vice versa*/ + error = 75; + } else if (unit_has_cursed_item(u) || (u2 && unit_has_cursed_item(u2))) { + error = 78; + } else if (fval(u, UFL_LOCKED) || is_cursed(u->attribs, C_SLAVE, 0)) { + error = 74; + } else if (u2 && fval(u, UFL_HUNGER)) { + /* hungry people cannot be given away */ + error = 73; + } else if (u2 && (fval(u2, UFL_LOCKED)|| is_cursed(u2->attribs, C_SLAVE, 0))) { + error = 75; + } else if (u2 && !ucontact(u2, u)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", "target", u2)); + error = -1; + } else if (u2 && (has_skill(u, SK_MAGIC) || has_skill(u2, SK_MAGIC))) { + /* cannot give units to and from magicians */ + error = 158; + } else if (u2 && (fval(u, UFL_WERE) != fval(u2, UFL_WERE))) { + /* werewolves can't be given to non-werewolves and vice-versa */ + error = 312; + } else if (u2 && u2->number!=0 && u2->race != u->race) { + log_warning(("faction %s attempts to give %s to %s.\n", + itoa36(u->faction->no), u->race->_name[0], + u2->race->_name[1])); + error = 139; + } else if (u2!=NULL && (get_racename(u2->attribs) || get_racename(u->attribs))) { + error = 139; + } else if (u2 && u2->faction!=u->faction && !rule_transfermen()) { + error = 74; + } else { + if (n > u->number) n = u->number; + if (u2 && n+u2->number > UNIT_MAXSIZE) { + n = UNIT_MAXSIZE-u2->number; + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_unit_size", "maxsize", UNIT_MAXSIZE)); + assert(n>=0); + } + if (n == 0) { + error = 96; + } else if (u2 && u->faction != u2->faction) { + if (u2->faction->newbies + n > MAXNEWBIES) { + error = 129; + } else if (u->race != u2->faction->race) { + if (u2->faction->race != new_race[RC_HUMAN]) { + error = 120; + } else if (count_migrants(u2->faction) + n > count_maxmigrants(u2->faction)) { + error = 128; + } + else if (has_limited_skills(u) || has_limited_skills(u2)) { + error = 154; + } else if (u2->number!=0) { + error = 139; + } + } + } + } + + if (u2 && (has_skill(u, SK_ALCHEMY) || has_skill(u2, SK_ALCHEMY))) { + k = count_skill(u2->faction, SK_ALCHEMY); + + /* Falls die Zieleinheit keine Alchemisten sind, werden sie nun + * welche. */ + if (!has_skill(u2, SK_ALCHEMY) && has_skill(u, SK_ALCHEMY)) + k += u2->number; + + /* Wenn in eine Alchemisteneinheit Personen verschoben werden */ + if (has_skill(u2, SK_ALCHEMY) && !has_skill(u, SK_ALCHEMY)) + k += n; + + /* Wenn Parteigrenzen überschritten werden */ + if (u2->faction != u->faction) + k += n; + + /* wird das Alchemistenmaximum ueberschritten ? */ + + if (k > skill_limit(u2->faction, SK_ALCHEMY)) { + error = 156; + } + } + + if (error==0) { + if (u2 && u2->number == 0) { + set_racename(&u2->attribs, get_racename(u->attribs)); + u2->race = u->race; + u2->irace = u->irace; + if (fval(u, UFL_HERO)) fset(u2, UFL_HERO); + else freset(u2, UFL_HERO); + } + + if (u2) { + if (u2->number!=0 && recruit_archetypes()) { + /* must have same set of skills */ + boolean okay = false; + if (u->skill_size==u2->skill_size) { + int i; + for (i=0;i!=u->skill_size;++i) { + int j; + for (j=0;j!=u2->skill_size;++j) { + if (u->skills[i].id==u2->skills[j].id) break; + } + if (j!=u2->skill_size) break; + } + if (i==u->skill_size) okay = true; + } + if (!okay) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "give_cannot_merge", "")); + } + } + + + /* Einheiten von Schiffen können nicht NACH in von + * Nicht-alliierten bewachten Regionen ausführen */ + sh = leftship(u); + if (sh) set_leftship(u2, sh); + + transfermen(u, u2, n); + if (u->faction != u2->faction) { + u2->faction->newbies += n; + } + } else { + if (getunitpeasants) { +#ifdef ORCIFICATION + if (u->race == new_race[RC_SNOTLING] && !fval(u->region, RF_ORCIFIED)) { + attrib *a = a_find(u->region->attribs, &at_orcification); + if (!a) a = a_add(&u->region->attribs, a_new(&at_orcification)); + a->data.i += n; + } +#endif + transfermen(u, NULL, n); + } else { + error = 159; + } + } + } + if (error>0) { + cmistake(u, ord, error, MSG_COMMERCE); + } else if (!u2) { + ADDMSG(&u->faction->msgs, + msg_message("give_person_peasants", "unit amount", u, n)); + } else if (u2->faction!=u->faction) { + message * msg = msg_message("give_person", "unit target amount", u, u2, n); + add_message(&u->faction->msgs, msg); + add_message(&u2->faction->msgs, msg); + msg_release(msg); + } +} + +void +give_unit(unit * u, unit * u2, order * ord) +{ + region * r = u->region; + int n = u->number; + + if (!rule_transfermen() && u->faction!=u2->faction) { + cmistake(u, ord, 74, MSG_COMMERCE); + return; + } + + if (u && unit_has_cursed_item(u)) { + cmistake(u, ord, 78, MSG_COMMERCE); + return; + } + + if (fval(u, UFL_HERO)) { + cmistake(u, ord, 75, MSG_COMMERCE); + return; + } + if (fval(u, UFL_LOCKED) || fval(u, UFL_HUNGER)) { + cmistake(u, ord, 74, MSG_COMMERCE); + return; + } + + if (u2 == NULL) { + if (fval(r->terrain, SEA_REGION)) { + cmistake(u, ord, 152, MSG_COMMERCE); + } else if (getunitpeasants) { + unit *u3; + + for(u3 = r->units; u3; u3 = u3->next) + if(u3->faction == u->faction && u != u3) break; + + if(u3) { + while (u->items) { + item * iold = i_remove(&u->items, u->items); + item * inew = *i_find(&u3->items, iold->type); + if (inew==NULL) i_add(&u3->items, iold); + else { + inew->number += iold->number; + i_free(iold); + } + } + } + give_men(u->number, u, NULL, ord); + cmistake(u, ord, 153, MSG_COMMERCE); + } else { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } + return; + } + + if (!alliedunit(u2, u->faction, HELP_GIVE) && ucontact(u2, u) == 0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", "target", u2)); + return; + } + if (u->number == 0) { + cmistake(u, ord, 105, MSG_COMMERCE); + return; + } + if (u2->faction->newbies + n > MAXNEWBIES) { + cmistake(u, ord, 129, MSG_COMMERCE); + return; + } + if (u->race != u2->faction->race) { + if (u2->faction->race != new_race[RC_HUMAN]) { + cmistake(u, ord, 120, MSG_COMMERCE); + return; + } + if (count_migrants(u2->faction) + u->number > count_maxmigrants(u2->faction)) { + cmistake(u, ord, 128, MSG_COMMERCE); + return; + } + if (has_limited_skills(u)) { + cmistake(u, ord, 154, MSG_COMMERCE); + return; + } + } + if (has_skill(u, SK_MAGIC)) { + sc_mage * mage; + if (count_skill(u2->faction, SK_MAGIC) + u->number > + skill_limit(u2->faction, SK_MAGIC)) + { + cmistake(u, ord, 155, MSG_COMMERCE); + return; + } + mage = get_mage(u); + if (!mage || u2->faction->magiegebiet != mage->magietyp) { + cmistake(u, ord, 157, MSG_COMMERCE); + return; + } + } + if (has_skill(u, SK_ALCHEMY) + && count_skill(u2->faction, SK_ALCHEMY) + u->number > + skill_limit(u2->faction, SK_ALCHEMY)) + { + cmistake(u, ord, 156, MSG_COMMERCE); + return; + } + add_give(u, u2, 1, 1, r_unit, ord, 0); + u_setfaction(u, u2->faction); + u2->faction->newbies += n; +} diff --git a/src/gamecode/give.h b/src/gamecode/give.h new file mode 100644 index 000000000..9f4e16a64 --- /dev/null +++ b/src/gamecode/give.h @@ -0,0 +1,26 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ +#ifndef H_GC_GIVE +#define H_GC_GIVE +#ifdef __cplusplus +extern "C" { +#endif + + extern int give_item(int want, const struct item_type * itype, struct unit * src, struct unit * dest, struct order * ord); + extern void give_men(int n, struct unit * u, struct unit * u2, struct order * ord); + extern void give_unit(struct unit * u, struct unit * u2, struct order * ord); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/items.c b/src/gamecode/items.c new file mode 100644 index 000000000..0a6d00a65 --- /dev/null +++ b/src/gamecode/items.c @@ -0,0 +1,263 @@ +#include +#include +#include "items.h" + +#include "study.h" +#include "curses.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +/* BEGIN studypotion */ +#define MAXGAIN 15 +static int +use_studypotion(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + if (get_keyword(u->thisorder) == K_STUDY) { + skill_t sk; + skill * sv; + + init_tokens(u->thisorder); + skip_token(); + sk = findskill(getstrtoken(), u->faction->locale); + sv = get_skill(u, sk); + + if (sv && sv->level > 2) { + /* TODO: message */ + } else if (study_cost(u, sk)>0) { + /* TODO: message */ + } else { + attrib * a = a_find(u->attribs, &at_learning); + teaching_info * teach; + if (a==NULL) { + a = a_add(&u->attribs, a_new(&at_learning)); + } + teach = (teaching_info*) a->data.v; + if (amount>MAXGAIN) amount = MAXGAIN; + teach->value += amount * 30; + if (teach->value > MAXGAIN * 30) { + teach->value = MAXGAIN * 30; + } + i_change(&u->items, itype, -amount); + return 0; + } + } + return EUNUSABLE; +} +/* END studypotion */ + +/* BEGIN speedsail */ +#define SPEEDSAIL_EFFECT 1 +static int +use_speedsail(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + curse *c; + double effect; + ship * sh = u->ship; + if (!sh) { + cmistake(u, ord, 20, MSG_MOVE); + return -1; + } + + effect = SPEEDSAIL_EFFECT; + c = create_curse(u, &sh->attribs, ct_find("shipspeedup"), 20, INT_MAX, effect, 0); + c_setflag(c, CURSE_NOAGE); + + ADDMSG(&u->faction->msgs, msg_message("use_speedsail", "unit speed", u, SPEEDSAIL_EFFECT)); + use_pooled(u, itype->rtype, GET_DEFAULT, 1); + + return 0; +} +/* END speedsail */ + +/* ------------------------------------------------------------- */ +/* Kann auch von Nichtmagiern benutzt werden, erzeugt eine +* Antimagiezone, die zwei Runden bestehen bleibt */ +static int +use_antimagiccrystal(unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + region * r = u->region; + const resource_type * rt_crystal = NULL; + int i; + + if (rt_crystal == NULL) { + rt_crystal = rt_find("antimagic"); + assert(rt_crystal!=NULL); + } + for (i=0;i!=amount;++i) { + int effect, duration = 2; + double force; + spell *sp = find_spell(M_NONE, "antimagiczone"); + attrib ** ap = &r->attribs; + unused(ord); + assert(sp); + + /* Reduziert die Stärke jedes Spruchs um effect */ + effect = sp->level; + + /* Hält Sprüche bis zu einem summierten Gesamtlevel von power aus. + * Jeder Zauber reduziert die 'Lebenskraft' (vigour) der Antimagiezone + * um seine Stufe */ + force = sp->level * 20; /* Stufe 5 =~ 100 */ + + /* Regionszauber auflösen */ + while (*ap && force > 0) { + curse * c; + attrib * a = *ap; + if (!fval(a->type, ATF_CURSE)) { + do { ap = &(*ap)->next; } while (*ap && a->type==(*ap)->type); + continue; + } + c = (curse*)a->data.v; + + /* Immunität prüfen */ + if (c_flags(c) & CURSE_IMMUNE) { + do { ap = &(*ap)->next; } while (*ap && a->type==(*ap)->type); + continue; + } + + force = destr_curse(c, effect, force); + if(c->vigour <= 0) { + a_remove(&r->attribs, a); + } + if(*ap) ap = &(*ap)->next; + } + + if (force > 0) { + create_curse(u, &r->attribs, ct_find("antimagiczone"), force, duration, effect, 0); + } + } + use_pooled(u, rt_crystal, GET_DEFAULT, amount); + ADDMSG(&u->faction->msgs, msg_message("use_antimagiccrystal", + "unit region", u, r)); + return 0; +} + +static int +use_instantartsculpture(struct unit * u, const struct item_type * itype, + int amount, struct order * ord) +{ + building *b; + + if(u->region->land == NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); + return -1; + } + + b = new_building(bt_find("artsculpture"), u->region, u->faction->locale); + b->size = 100; + + ADDMSG(&u->region->msgs, msg_message("artsculpture_create", "unit region", + u, u->region)); + + use_pooled(u, itype->rtype, GET_DEFAULT, 1); + + return 0; +} + +static int +use_instantartacademy(struct unit * u, const struct item_type * itype, + int amount, struct order * ord) +{ + building *b; + + if(u->region->land == NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); + return -1; + } + + b = new_building(bt_find("artacademy"), u->region, u->faction->locale); + b->size = 100; + + ADDMSG(&u->region->msgs, msg_message( + "artacademy_create", "unit region", u, u->region)); + + use_pooled(u, itype->rtype, GET_DEFAULT, 1); + + return 0; +} + +#define BAGPIPEFRACTION dice_rand("2d4+2") +#define BAGPIPEDURATION dice_rand("2d10+4") + +static int +use_bagpipeoffear(struct unit * u, const struct item_type * itype, + int amount, struct order * ord) +{ + int money; + + if (get_curse(u->region->attribs, ct_find("depression"))) { + cmistake(u, ord, 58, MSG_MAGIC); + return -1; + } + + money = entertainmoney(u->region)/BAGPIPEFRACTION; + change_money(u, money); + rsetmoney(u->region, rmoney(u->region) - money); + + create_curse(u, &u->region->attribs, ct_find("depression"), + 20, BAGPIPEDURATION, 0.0, 0); + + ADDMSG(&u->faction->msgs, msg_message("bagpipeoffear_faction", + "unit region command money", u, u->region, ord, money)); + + ADDMSG(&u->region->msgs, msg_message("bagpipeoffear_region", + "unit money", u, money)); + + return 0; +} + +static int +use_aurapotion50(struct unit * u, const struct item_type * itype, + int amount, struct order * ord) +{ + if (!is_mage(u)) { + cmistake(u, ord, 214, MSG_MAGIC); + return -1; + } + + change_spellpoints(u, 50); + + ADDMSG(&u->faction->msgs, msg_message("aurapotion50", + "unit region command", u, u->region, ord)); + + use_pooled(u, itype->rtype, GET_DEFAULT, 1); + + return 0; +} + + +void +register_itemfunctions(void) +{ + register_demonseye(); + register_item_use(use_antimagiccrystal, "use_antimagiccrystal"); + register_item_use(use_instantartsculpture, "use_instantartsculpture"); + register_item_use(use_studypotion, "use_studypotion"); + register_item_use(use_speedsail, "use_speedsail"); + register_item_use(use_instantartacademy, "use_instantartacademy"); + register_item_use(use_bagpipeoffear, "use_bagpipeoffear"); + register_item_use(use_aurapotion50, "use_aurapotion50"); +} diff --git a/src/gamecode/items.h b/src/gamecode/items.h new file mode 100644 index 000000000..5de50e512 --- /dev/null +++ b/src/gamecode/items.h @@ -0,0 +1,24 @@ +/* vi: set ts=2: ++-------------------+ Christian Schlittchen +| | Enno Rehling +| Eressea PBEM host | Katja Zedel +| (c) 1998 - 2003 | Henning Peters +| | Ingo Wilken ++-------------------+ Stefan Reich + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifndef H_KRNL_ITEMS +#define H_KRNL_ITEMS +#ifdef __cplusplus +extern "C" { +#endif + + extern void register_itemfunctions(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c new file mode 100644 index 000000000..c5cb1173e --- /dev/null +++ b/src/gamecode/laws.c @@ -0,0 +1,4223 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#pragma region includes + +#include +#include +#include "laws.h" + +#include +#include + +/* gamecode includes */ +#include "economy.h" +#include "archetype.h" +#include "monster.h" +#include "randenc.h" +#include "spy.h" +#include "study.h" +#include "market.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for volcanoes in emigration (needs a flag) */ +#include + +/* attributes includes */ +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#pragma endregion + +/* chance that a peasant dies of starvation: */ +#define PEASANT_STARVATION_CHANCE 0.9F +/* Pferdevermehrung */ +#define HORSEGROWTH 4 +/* Wanderungschance pro Pferd */ +#define HORSEMOVE 3 +/* Vermehrungschance pro Baum */ +#define FORESTGROWTH 10000 /* In Millionstel */ + +/** Ausbreitung und Vermehrung */ +#define MAXDEMAND 25 +#define DMRISE 0.1F /* weekly chance that demand goes up */ +#define DMRISEHAFEN 0.2F /* weekly chance that demand goes up with harbor */ + + +/* - exported global symbols ----------------------------------- */ +boolean nobattle = false; +boolean nomonsters = false; +/* ------------------------------------------------------------- */ + +static int +RemoveNMRNewbie(void) { + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "nmr.removenewbie", 0); + } + return value; +} + +static void +restart_race(unit *u, const race * rc) +{ + faction * oldf = u->faction; + faction *f = addfaction(oldf->email, oldf->passw, rc, oldf->locale, oldf->subscription); + unit * nu = addplayer(u->region, f); + order ** ordp = &u->orders; + f->subscription = u->faction->subscription; + f->age = u->faction->age; + fset(f, FFL_RESTART); + if (f->subscription) { + sql_print(("UPDATE subscriptions set faction='%s', race='%s' where id=%u;\n", + itoa36(f->no), dbrace(rc), f->subscription)); + } + f->magiegebiet = u->faction->magiegebiet; + f->options = u->faction->options; + free_orders(&nu->orders); + nu->orders = u->orders; + u->orders = NULL; + while (*ordp) { + order * ord = *ordp; + if (get_keyword(ord) != K_RESTART) { + *ordp = ord->next; + ord->next = NULL; + if (u->thisorder == ord) set_order(&u->thisorder, NULL); + } else { + ordp = &ord->next; + } + } + destroyfaction(u->faction); +} + +static void +checkorders(void) +{ + faction *f; + + if (verbosity>=1) puts(" - Warne spaete Spieler..."); + for (f = factions; f; f = f->next) + if (!is_monsters(f) && turn - f->lastorders == NMRTimeout() - 1) + ADDMSG(&f->msgs, msg_message("turnreminder", "")); +} + +static boolean +help_money(const unit * u) +{ + if (u->race->ec_flags & GIVEITEM) return true; + return false; +} + +static void +help_feed(unit * donor, unit * u, int * need_p) +{ + int need = *need_p; + int give = get_money(donor) - lifestyle(donor); + give = MIN(need, give); + + if (give>0) { + change_money(donor, -give); + change_money(u, give); + need -= give; + add_spende(donor->faction, u->faction, give, donor->region); + } + *need_p = need; +} + +static void +get_food(region *r) +{ + plane * pl = rplane(r); + unit *u; + int peasantfood = rpeasants(r)*10; + static int food_rules = -1; + + if (food_rules<0) { + food_rules = get_param_int(global.parameters, "rules.economy.food", 0); + } + + /* 1. Versorgung von eigenen Einheiten. Das vorhandene Silber + * wird zunächst so auf die Einheiten aufgeteilt, dass idealerweise + * jede Einheit genug Silber für ihren Unterhalt hat. */ + + for (u = r->units; u; u = u->next) { + int need = lifestyle(u); + + /* Erstmal zurücksetzen */ + freset(u, UFL_HUNGER); + + if (u->ship && (u->ship->flags&SF_FISHING)) { + unit * v; + int c = 2; + for (v=u;c>0 && v;v=v->next) { + if (v->ship==u->ship) { + int get = 0; + if (v->number<=c) { + get = lifestyle(v); + } else { + get = lifestyle(v) * c / v->number; + } + if (get) { + change_money(v, get); + } + } + c -= v->number; + } + u->ship->flags -= SF_FISHING; + } + + if (food_rules&1) { + faction * owner = region_get_owner(r); + /* if the region is owned, and the owner is nice, then we'll get + * food from the peasants - should not be used with WORK */ + if (owner!=NULL && (get_alliance(owner, u->faction) & HELP_MONEY)) { + int rm = rmoney(r); + int use = MIN(rm, need); + rsetmoney(r, rm-use); + need -= use; + } + } + + need -= get_money(u); + if (need > 0) { + unit *v; + + for (v = r->units; need && v; v = v->next) { + if (v->faction == u->faction && help_money(v)) { + int give = get_money(v) - lifestyle(v); + give = MIN(need, give); + if (give>0) { + change_money(v, -give); + change_money(u, give); + need -= give; + } + } + } + } + } + + /* 2. Versorgung durch Fremde. Das Silber alliierter Einheiten wird + * entsprechend verteilt. */ + for (u = r->units; u; u = u->next) { + int need = lifestyle(u); + faction * f = u->faction; + + need -= MAX(0, get_money(u)); + + if (need > 0) { + unit *v; + + if (food_rules&2) { + /* the owner of the region is the first faction to help out when you're hungry */ + faction * owner = region_get_owner(r); + if (owner && owner!=u->faction) { + for (v=r->units;v;v=v->next) { + if (v->faction==owner && alliedunit(v, f, HELP_MONEY) && help_money(v)) { + help_feed(v, u, &need); + break; + } + } + } + } + for (v = r->units; need && v; v = v->next) { + if (v->faction != f && alliedunit(v, f, HELP_MONEY) && help_money(v)) { + help_feed(v, u, &need); + } + } + + /* Die Einheit hat nicht genug Geld zusammengekratzt und + * nimmt Schaden: */ + if (need > 0) { + int lspp = lifestyle(u)/u->number; + if (lspp > 0) { + int number = (need+lspp-1)/lspp; + if (hunger(number, u)) fset(u, UFL_HUNGER); + } + } + } + } + + /* 3. bestimmen, wie viele Bauern gefressen werden. + * bei fehlenden Bauern den Dämon hungern lassen + */ + for (u = r->units; u; u = u->next) { + if (u->race == new_race[RC_DAEMON]) { + unit * donor = r->units; + int hungry = u->number; + + while (donor!=NULL && hungry>0) { + /* always start with the first known unit that may have some blood */ + static const struct potion_type * pt_blood; + if (pt_blood==NULL) { + const item_type * it_blood = it_find("peasantblood"); + if (it_blood) pt_blood = it_blood->rtype->ptype; + } + if (pt_blood!=NULL) { + while (donor!=NULL) { + if (donor->race==new_race[RC_DAEMON]) { + if (get_effect(donor, pt_blood)) { + /* if he's in our faction, drain him: */ + if (donor->faction==u->faction) break; + } + } + donor = donor->next; + } + if (donor != NULL) { + int blut = get_effect(donor, pt_blood); + blut = MIN(blut, hungry); + change_effect(donor, pt_blood, -blut); + hungry -= blut; + } + } + } + if (pl == NULL || !fval(pl, PFL_NOFEED)) { + if (peasantfood>=hungry) { + peasantfood -= hungry; + hungry = 0; + } else { + hungry -= peasantfood; + peasantfood = 0; + } + if (hungry > 0) { + static int demon_hunger = -1; + if (demon_hunger<0) { + demon_hunger = get_param_int(global.parameters, "hunger.demons", 0); + } + if (demon_hunger==0) { + /* nicht gefütterte dämonen hungern */ +#ifdef PEASANT_HUNGRY_DAEMONS_HAVE_FULL_SKILLS + /* wdw special rule */ + hunger(hungry, u); +#else + if (hunger(hungry, u)) fset(u, UFL_HUNGER); +#endif + /* used to be: hunger(hungry, u); */ + } else { + /* no damage, but set the hungry-flag */ + fset(u, UFL_HUNGER); + } + } + } + } + } + rsetpeasants(r, peasantfood/10); + + /* 3. Von den überlebenden das Geld abziehen: */ + for (u = r->units; u; u = u->next) { + int need = MIN(get_money(u), lifestyle(u)); + change_money(u, -need); + } +} + +static void +age_unit(region * r, unit * u) +{ + if (u->race == new_race[RC_SPELL]) { + if (--u->age <= 0) { + remove_unit(&r->units, u); + } + } else { + ++u->age; + if (u->number>0 && u->race->age) { + u->race->age(u); + } + } +#ifdef ASTRAL_ITEM_RESTRICTIONS + if (u->region && is_astral(u->region)) { + item ** itemp = &u->items; + while (*itemp) { + item * itm = *itemp; + if ((itm->type->flags & ITF_NOTLOST) == 0) { + if (itm->type->flags & (ITF_BIG|ITF_ANIMAL|ITF_CURSED)) { + ADDMSG(&u->faction->msgs, msg_message("itemcrumble", "unit region item amount", + u, u->region, itm->type->rtype, itm->number)); + i_free(i_remove(itemp, itm)); + continue; + } + } + itemp=&itm->next; + } + } +#endif +} + + +static void +live(region * r) +{ + unit **up = &r->units; + + get_food(r); + + while (*up) { + unit * u = *up; + /* IUW: age_unit() kann u loeschen, u->next ist dann + * undefiniert, also muessen wir hier schon das nächste + * Element bestimmen */ + + int effect = get_effect(u, oldpotiontype[P_FOOL]); + if (effect > 0) { /* Trank "Dumpfbackenbrot" */ + skill * sv = u->skills, * sb = NULL; + while (sv!=u->skills+u->skill_size) { + if (sb==NULL || skill_compare(sv, sb)>0) { + sb = sv; + } + ++sv; + } + /* bestes Talent raussuchen */ + if (sb!=NULL) { + int weeks = MIN(effect, u->number); + reduce_skill(u, sb, weeks); + ADDMSG(&u->faction->msgs, msg_message("dumbeffect", + "unit weeks skill", u, weeks, (skill_t)sb->id)); + } /* sonst Glück gehabt: wer nix weiß, kann nix vergessen... */ + change_effect(u, oldpotiontype[P_FOOL], -effect); + } + age_unit(r, u); + if (*up==u) up=&u->next; + } +} + +/* + * This procedure calculates the number of emigrating peasants for the given + * region r. There are two incentives for peasants to emigrate: + * 1) They prefer the less crowded areas. + * Example: mountains, 700 peasants (max 1000), 70% inhabited + * plain, 5000 peasants (max 10000), 50% inhabited + * 700*(PEASANTSWANDER_WEIGHT/100)*((70-50)/100) peasants wander + * from mountains to plain. + * Effect : peasents will leave densely populated regions. + * 2) Peasants prefer richer neighbour regions. + * Example: region A, 700 peasants, wealth $10500, $15 per head + * region B, 2500 peasants, wealth $25000, $10 per head + * Some peasants will emigrate from B to A because $15 > $10 + * exactly: 2500*(PEASANTSGREED_WEIGHT1/100)*((15-10)/100) + * Not taken in consideration: + * - movement because of monsters. + * - movement because of wars + * - movement because of low loyalty relating to present parties. + */ + +#define MAX_EMIGRATION(p) ((p)/MAXDIRECTIONS) +#define MAX_IMMIGRATION(p) ((p)*2/3) + +static void +calculate_emigration(region *r) +{ + int i; + int maxp = maxworkingpeasants(r); + int rp = rpeasants(r); + int max_immigrants = MAX_IMMIGRATION(maxp-rp); + + if (r->terrain == newterrain(T_VOLCANO) || r->terrain == newterrain(T_VOLCANO_SMOKING)) { + max_immigrants = max_immigrants/10; + } + + for (i = 0; max_immigrants>0 && i != MAXDIRECTIONS; i++) { + int dir = (turn+i) % MAXDIRECTIONS; + region *rc = rconnect(r, (direction_t)dir); + + if (rc != NULL && fval(rc->terrain, LAND_REGION)) { + int rp2 = rpeasants(rc); + int maxp2 = maxworkingpeasants(rc); + int max_emigration = MAX_EMIGRATION(rp2-maxp2); + + if (max_emigration>0) { + max_emigration = MIN(max_emigration, max_immigrants); + r->land->newpeasants += max_emigration; + rc->land->newpeasants -= max_emigration; + max_immigrants -= max_emigration; + } + } + } +} + +/** Bauern vermehren sich */ + +static void +peasants(region * r) +{ + int peasants = rpeasants(r); + int money = rmoney(r); + int maxp = production(r) * MAXPEASANTS_PER_AREA; + int n, satiated; + int dead = 0; + + /* Bis zu 1000 Bauern können Zwillinge bekommen oder 1000 Bauern + * wollen nicht! */ + + if (peasants>0) { + int glueck = 0; + double fraction = peasants * 0.0001F * PEASANTGROWTH; + int births = (int)fraction; + attrib * a = a_find(r->attribs, &at_peasantluck); + + if (rng_double()<(fraction-births)) { + /* because we don't want regions that never grow pga. rounding. */ + ++births; + } + if (a!=NULL) { + glueck = a->data.i * 1000; + } + + for (n = peasants; n; --n) { + int chances = 0; + + if (glueck>0) { + --glueck; + chances += PEASANTLUCK; + } + + while (chances--) { + if (rng_int() % 10000 < PEASANTGROWTH) { + /* Only raise with 75% chance if peasants have + * reached 90% of maxpopulation */ + if (peasants/(float)maxp < 0.9 || chance(PEASANTFORCE)) { + ++births; + } + } + } + } + peasants += births; + } + + /* Alle werden satt, oder halt soviele für die es auch Geld gibt */ + + satiated = MIN(peasants, money / maintenance_cost(NULL)); + rsetmoney(r, money - satiated * maintenance_cost(NULL)); + + /* Von denjenigen, die nicht satt geworden sind, verhungert der + * Großteil. dead kann nie größer als rpeasants(r) - satiated werden, + * so dass rpeasants(r) >= 0 bleiben muß. */ + + /* Es verhungert maximal die unterernährten Bevölkerung. */ + + n = MIN(peasants - satiated, rpeasants(r)); + dead += (int)(0.5F + n * PEASANT_STARVATION_CHANCE); + + if (dead > 0) { + message * msg = add_message(&r->msgs, msg_message("phunger", "dead", dead)); + msg_release(msg); + peasants -= dead; + } + + rsetpeasants(r, peasants); +} + +/* ------------------------------------------------------------- */ + +typedef struct migration { + struct migration * next; + region * r; + int horses; + int trees; +} migration; + +#define MSIZE 1023 +migration * migrants[MSIZE]; +migration * free_migrants; + +static migration * +get_migrants(region * r) +{ + int key = reg_hashkey(r); + int index = key % MSIZE; + migration * m = migrants[index]; + while (m && m->r != r) + m = m->next; + if (m == NULL) { + /* Es gibt noch keine Migration. Also eine erzeugen + */ + m = free_migrants; + if (!m) m = calloc(1, sizeof(migration)); + else { + free_migrants = free_migrants->next; + m->horses = 0; + m->trees = 0; + } + m->r = r; + m->next = migrants[index]; + migrants[index] = m; + } + return m; +} + +static void +migrate(region * r) +{ + int key = reg_hashkey(r); + int index = key % MSIZE; + migration ** hp = &migrants[index]; + fset(r, RF_MIGRATION); + while (*hp && (*hp)->r != r) hp = &(*hp)->next; + if (*hp) { + migration * m = *hp; + rsethorses(r, rhorses(r) + m->horses); + /* Was macht das denn hier? + * Baumwanderung wird in trees() gemacht. + * wer fragt das? Die Baumwanderung war abhängig von der + * Auswertungsreihenfolge der regionen, + * das hatte ich geändert. jemand hat es wieder gelöscht, toll. + * ich habe es wieder aktiviert, muß getestet werden. + */ + *hp = m->next; + m->next = free_migrants; + free_migrants = m; + } +} + +static void +horses(region * r) +{ + int horses, maxhorses; + direction_t n; + + /* Logistisches Wachstum, Optimum bei halbem Maximalbesatz. */ + maxhorses = maxworkingpeasants(r)/10; + maxhorses = MAX(0, maxhorses); + horses = rhorses(r); + if (horses > 0) { + if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { + rsethorses(r, (int)(horses*0.9F)); + } else if (maxhorses) { + int i; + double growth = (RESOURCE_QUANTITY * HORSEGROWTH * 200 * (maxhorses-horses))/maxhorses; + + if (growth>0) { + if (a_find(r->attribs, &at_horseluck)) growth *= 2; + /* printf("Horses: <%d> %d -> ", growth, horses); */ + i = (int)(0.5F + (horses * 0.0001F) * growth); + /* printf("%d\n", horses); */ + rsethorses(r, horses + i); + } + } + } + + /* Pferde wandern in Nachbarregionen. + * Falls die Nachbarregion noch berechnet + * werden muß, wird eine migration-Struktur gebildet, + * die dann erst in die Berechnung der Nachbarstruktur einfließt. + */ + + for(n = 0; n != MAXDIRECTIONS; n++) { + region * r2 = rconnect(r, n); + if (r2 && fval(r2->terrain, WALK_INTO)) { + int pt = (rhorses(r) * HORSEMOVE)/100; + pt = (int)normalvariate(pt, pt/4.0); + pt = MAX(0, pt); + if (fval(r2, RF_MIGRATION)) + rsethorses(r2, rhorses(r2) + pt); + else { + migration * nb; + /* haben wir die Migration schonmal benutzt? + * wenn nicht, müssen wir sie suchen. + * Wandernde Pferde vermehren sich nicht. + */ + nb = get_migrants(r2); + nb->horses += pt; + } + /* Wandernde Pferde sollten auch abgezogen werden */ + rsethorses(r, rhorses(r) - pt); + } + } + assert(rhorses(r) >= 0); +} + +static int +count_race(const region *r, const race *rc) +{ + unit *u; + int c = 0; + + for(u = r->units; u; u=u->next) + if(u->race == rc) c += u->number; + + return c; +} + +extern struct attrib_type at_germs; + +static void +growing_trees_e3(region * r, const int current_season, const int last_weeks_season) +{ + const static int transform[4][3] = { + { -1, -1, 0 }, + { TREE_SEED, TREE_SAPLING, 2 }, + { TREE_SAPLING, TREE_TREE, 2 }, + { TREE_TREE, TREE_SEED, 2 } + }; + + if (r->land && current_season!=last_weeks_season && transform[current_season][2]) { + int src_type = transform[current_season][0]; + int dst_type = transform[current_season][1]; + int src = rtrees(r, src_type); + int dst = rtrees(r, dst_type); + int grow = src/transform[current_season][2]; + if (grow>0) { + if (src_type!=TREE_TREE) { + rsettrees(r, src_type, src-grow); + } + rsettrees(r, dst_type, dst+grow); + + if (dst_type==TREE_SEED && r->terrain->size) { + region * rn[MAXDIRECTIONS]; + int d; + double fgrow = grow/(double)MAXDIRECTIONS; + + get_neighbours(r, rn); + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rx = rn[d]; + if (rx && rx->land) { + double scale = 1.0; + int g; + double fg, ch; + int seeds = rtrees(rx, dst_type); + + if (r->terrain->size>rx->terrain->size) { + scale = (scale * rx->terrain->size)/r->terrain->size; + } + fg = scale * fgrow; + g = (int)fg; + ch = fg - g; + if (chance(ch)) ++g; + if (g>0) { + rsettrees(rx, dst_type, seeds + g); + } + } + } + } + } + } +} + +static void +growing_trees(region * r, const int current_season, const int last_weeks_season) +{ + int growth, grownup_trees, i, seeds, sprout; + direction_t d; + attrib *a; + + if(current_season == SEASON_SUMMER || current_season == SEASON_AUTUMN) { + double seedchance = 0.01F * RESOURCE_QUANTITY; + int elves = count_race(r, new_race[RC_ELF]); + + a = a_find(r->attribs, &at_germs); + if(a && last_weeks_season == SEASON_SPRING) { + /* ungekeimte Samen bleiben erhalten, Sprößlinge wachsen */ + sprout = MIN(a->data.sa[1], rtrees(r, 1)); + /* aus dem gesamt Sprößlingepool abziehen */ + rsettrees(r, 1, rtrees(r, 1) - sprout); + /* zu den Bäumen hinzufügen */ + rsettrees(r, 2, rtrees(r, 2) + sprout); + + a_removeall(&r->attribs, &at_germs); + } + + if(is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { + rsettrees(r, 1, (int)(rtrees(r, 1) * 0.9)); + rsettrees(r, 2, (int)(rtrees(r, 2) * 0.9)); + return; + } + + if (production(r) <= 0) return; + + /* Grundchance 1.0% */ + /* Jeder Elf in der Region erhöht die Chance marginal */ + elves = MIN(elves, (production(r)*MAXPEASANTS_PER_AREA)/8); + if (elves) { + seedchance += 1.0-pow(0.99999, elves * RESOURCE_QUANTITY); + } + grownup_trees = rtrees(r, 2); + seeds = 0; + + if (grownup_trees>0) { + double remainder = seedchance*grownup_trees; + seeds = (int)(remainder); + remainder -= seeds; + if (chance(remainder)) { + ++seeds; + } + if (seeds>0) { + seeds += rtrees(r, 0); + rsettrees(r, 0, seeds); + } + } + + /* Bäume breiten sich in Nachbarregionen aus. */ + + /* Gesamtzahl der Samen: + * bis zu 6% (FORESTGROWTH*3) der Bäume samen in die Nachbarregionen */ + seeds = (rtrees(r, 2) * FORESTGROWTH * 3)/1000000; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * r2 = rconnect(r, d); + if (r2 && fval(r2->terrain, LAND_REGION) && r2->terrain->size) { + /* Eine Landregion, wir versuchen Samen zu verteilen: + * Die Chance, das Samen ein Stück Boden finden, in dem sie + * keimen können, hängt von der Bewuchsdichte und der + * verfügbaren Fläche ab. In Gletschern gibt es weniger + * Möglichkeiten als in Ebenen. */ + sprout = 0; + seedchance = (1000 * maxworkingpeasants(r2)) / r2->terrain->size; + for(i=0; iattribs, C_CURSED_BY_THE_GODS, 0)) return; + + /* in at_germs merken uns die Zahl der Samen und Sprößlinge, die + * dieses Jahr älter werden dürfen, damit nicht ein Same im selben + * Zyklus zum Baum werden kann */ + a = a_find(r->attribs, &at_germs); + if(!a) { + a = a_add(&r->attribs, a_new(&at_germs)); + a->data.sa[0] = (short)rtrees(r, 0); + a->data.sa[1] = (short)rtrees(r, 1); + } + /* wir haben 6 Wochen zum wachsen, jeder Same/Sproß hat 18% Chance + * zu wachsen, damit sollten nach 5-6 Wochen alle gewachsen sein */ + growth = 1800; + + /* Samenwachstum */ + + /* Raubbau abfangen, es dürfen nie mehr Samen wachsen, als aktuell + * in der Region sind */ + seeds = MIN(a->data.sa[0], rtrees(r, 0)); + sprout = 0; + + for(i=0;idata.sa[0] = (short)(seeds - sprout); + /* aus dem gesamt Samenpool abziehen */ + rsettrees(r, 0, rtrees(r, 0) - sprout); + /* zu den Sprößlinge hinzufügen */ + rsettrees(r, 1, rtrees(r, 1) + sprout); + + /* Baumwachstum */ + + /* hier gehen wir davon aus, das Jungbäume nicht ohne weiteres aus + * der Region entfernt werden können, da Jungbäume in der gleichen + * Runde nachwachsen, wir also nicht mehr zwischen diesjährigen und + * 'alten' Jungbäumen unterscheiden könnten */ + sprout = MIN(a->data.sa[1], rtrees(r, 1)); + grownup_trees = 0; + + for(i=0;idata.sa[1] = (short)(sprout - grownup_trees); + /* aus dem gesamt Sprößlingepool abziehen */ + rsettrees(r, 1, rtrees(r, 1) - grownup_trees); + /* zu den Bäumen hinzufügen */ + rsettrees(r, 2, rtrees(r, 2) + grownup_trees); + } +} + +static void +growing_herbs(region * r, const int current_season, const int last_weeks_season) +{ + /* Jetzt die Kräutervermehrung. Vermehrt wird logistisch: + * + * Jedes Kraut hat eine Wahrscheinlichkeit von (100-(vorhandene + * Kräuter))% sich zu vermehren. */ + if (current_season != SEASON_WINTER) { + int i; + for (i = rherbs(r); i > 0; i--) { + if (rng_int()%100 < (100-rherbs(r))) rsetherbs(r, (short)(rherbs(r)+1)); + } + } +} + +void +demographics(void) +{ + region *r; + static int last_weeks_season = -1; + static int current_season = -1; + + if (current_season<0) { + gamedate date; + get_gamedate(turn, &date); + current_season = date.season; + get_gamedate(turn-1, &date); + last_weeks_season = date.season; + } + + for (r = regions; r; r = r->next) { + ++r->age; /* also oceans. no idea why we didn't always do that */ + live(r); + /* check_split_dragons(); */ + + if (!fval(r->terrain, SEA_REGION)) { + /* die Nachfrage nach Produkten steigt. */ + struct demand * dmd; + if (r->land) { + static int plant_rules = -1; + + if (plant_rules<0) { + plant_rules = get_param_int(global.parameters, "rules.economy.grow", 0); + } + for (dmd=r->land->demands;dmd;dmd=dmd->next) { + if (dmd->value>0 && dmd->value < MAXDEMAND) { + float rise = DMRISE; + if (buildingtype_exists(r, bt_find("harbour"), true)) rise = DMRISEHAFEN; + if (rng_double()value; + } + } + /* Seuchen erst nachdem die Bauern sich vermehrt haben + * und gewandert sind */ + + calculate_emigration(r); + peasants(r); + if (r->age>20) { + plagues(r, false); + } + horses(r); + if (plant_rules==0) { /* E1 */ + growing_trees(r, current_season, last_weeks_season); + growing_herbs(r, current_season, last_weeks_season); + } else { /* E3 */ + growing_trees_e3(r, current_season, last_weeks_season); + } + } + + update_resources(r); + if (r->land) migrate(r); + } + } + while (free_migrants) { + migration * m = free_migrants->next; + free(free_migrants); + free_migrants = m; + }; + if (verbosity>=1) putchar('\n'); + + remove_empty_units(); + + if (verbosity>=1) puts(" - Einwanderung..."); + for (r = regions; r; r = r->next) { + if (r->land && r->land->newpeasants) { + int rp = rpeasants(r) + r->land->newpeasants; + rsetpeasants(r, MAX(0, rp)); + } + } + + checkorders(); +} +/* ------------------------------------------------------------- */ + +static int +modify(int i) +{ + int c; + + c = i * 2 / 3; + + if (c >= 1) { + return (c + rng_int() % c); + } else { + return (i); + } +} + +static void +inactivefaction(faction * f) +{ + FILE *inactiveFILE; + char zText[128]; + + sprintf(zText, "%s/%s", datapath(), "inactive"); + inactiveFILE = fopen(zText, "a"); + + if (inactiveFILE) { + fprintf(inactiveFILE, "%s:%s:%d:%d\n", + factionid(f), + LOC(default_locale, rc_name(f->race, 1)), + modify(count_all(f)), + turn - f->lastorders); + + fclose(inactiveFILE); + } +} + +static void +transfer_faction(faction *f, faction *f2) +{ + unit *u, *un; + + for (u = f->units; u;) { + un = u->nextF; + if(!unit_has_cursed_item(u) + && !has_skill(u, SK_MAGIC) + && !has_skill(u, SK_ALCHEMY)) { + u_setfaction(u, f2); + } + u = un; + } +} + +static int +restart_cmd(unit * u, struct order * ord) +{ + init_tokens(ord); + skip_token(); /* skip keyword */ + + if (!fval(u->region->terrain, LAND_REGION)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); + } else { + const char * s_race = getstrtoken(), * s_pass; + const race * frace = findrace(s_race, u->faction->locale); + + if (!frace) { + frace = u->faction->race; + s_pass = s_race; + } else { + s_pass = getstrtoken(); + } + + if (u->faction->age > 3 && fval(u->faction, FFL_RESTART)) { + cmistake(u, ord, 314, MSG_EVENT); + return 0; + } + + if (/* frace != u->faction->race && */ u->faction->age < 81) { + cmistake(u, ord, 241, MSG_EVENT); + return 0; + } + + if (!playerrace(frace)) { + cmistake(u, ord, 243, MSG_EVENT); + return 0; + } + + if (!checkpasswd(u->faction, (const char *)s_pass, false)) { + cmistake(u, ord, 86, MSG_EVENT); + log_warning(("RESTART with wrong password, faction %s, pass %s\n", + factionid(u->faction), s_pass)); + return 0; + } + restart_race(u, frace); + return -1; + } + return 0; +} + +static boolean +EnhancedQuit(void) +{ + static int value = -1; + if (value<0) { + const char * str = get_param(global.parameters, "alliance.transferquit"); + value = (str!=0 && strcmp(str, "true")==0); + } + return value; +} + +static int +quit_cmd(unit * u, struct order * ord) +{ + faction * f = u->faction; + const char * passwd; + + init_tokens(ord); + skip_token(); /* skip keyword */ + + passwd = getstrtoken(); + if (checkpasswd(f, (const char *)passwd, false)) { + if (EnhancedQuit()) { + int f2_id = getid(); + if (f2_id>0) { + faction *f2 = findfaction(f2_id); + + if(f2 == NULL) { + cmistake(u, ord, 66, MSG_EVENT); + return 0; + } else if (!u->faction->alliance || u->faction->alliance != f2->alliance) { + cmistake(u, ord, 315, MSG_EVENT); + return 0; + } else if(!alliedfaction(NULL, f, f2, HELP_MONEY)) { + cmistake(u, ord, 316, MSG_EVENT); + return 0; + } else { + variant var; + var.i = f2_id; + a_add(&f->attribs, object_create("quit", TINTEGER, var)); + } + } + } + fset(f, FFL_QUIT); + } else { + char buffer[64]; + write_order(ord, buffer, sizeof(buffer)); + cmistake(u, ord, 86, MSG_EVENT); + log_warning(("QUIT with illegal password for faction %s: %s\n", + factionid(f), buffer)); + } + return 0; +} + +static void +quit(void) +{ + faction ** fptr = &factions; + while (*fptr) { + faction * f = *fptr; + if (f->flags & FFL_QUIT) { + if (EnhancedQuit()) { + /* this doesn't work well (use object_name()) */ + attrib * a = a_find(f->attribs, &at_object); + if (a) { + variant var; + object_type type; + var.i = 0; + object_get(a, &type, &var); + assert(var.i && type==TINTEGER); + if (var.i) { + int f2_id = var.i; + faction *f2 = findfaction(f2_id); + + assert(f2_id>0); + assert(f2!=NULL); + transfer_faction(f, f2); + } + } + } + destroyfaction(f); + } + if (*fptr==f) fptr=&f->next; + } +} + +int dropouts[2]; +int * age = NULL; + +static void +nmr_death(faction * f) +{ + static int rule = -1; + if (rule<0) rule = get_param_int(global.parameters, "rules.nmr.destroy", 0); + if (rule) { + unit * u; + for (u=f->units;u;u=u->nextF) { + if (u->building && fval(u, UFL_OWNER)) { + remove_building(&u->region->buildings, u->building); + } + } + } +} + +static void +parse_restart(void) +{ + region *r; + faction *f; + + /* Sterben erst nachdem man allen anderen gegeben hat - bzw. man kann + * alles machen, was nicht ein dreißigtägiger Befehl ist. */ + + for (r = regions; r; r = r->next) { + unit * u, * un; + for (u = r->units; u;) { + order * ord; + + un = u->next; + for (ord = u->orders; ord!=NULL; ord = ord->next) { + if (get_keyword(ord) == K_RESTART) { + if (u->number > 0) { + if (restart_cmd(u, ord)!=0) { + break; + } + } + } + } + u = un; + } + } + + if (verbosity>=1) puts(" - beseitige Spieler, die sich zu lange nicht mehr gemeldet haben..."); + + for (f = factions; f; f = f->next) { + if(fval(f, FFL_NOIDLEOUT)) f->lastorders = turn; + if (NMRTimeout()>0 && turn - f->lastorders >= NMRTimeout()) { + nmr_death(f); + destroyfaction(f); + continue; + } + if (fval(f, FFL_OVERRIDE)) { + free(f->override); + f->override = strdup(itoa36(rng_int())); + freset(f, FFL_OVERRIDE); + } + if (turn!=f->lastorders) { + char info[256]; + sprintf(info, "%d Einheiten, %d Personen, %d Silber", + f->no_units, f->num_total, f->money); + if (f->subscription) { + sql_print(("UPDATE subscriptions SET lastturn=%d, password='%s', info='%s' WHERE id=%u;\n", + f->lastorders, f->override, info, f->subscription)); + } + } else { + if (f->subscription) { + sql_print(("UPDATE subscriptions SET status='ACTIVE', lastturn=%d, firstturn=greatest(firstturn,%d), password='%s' WHERE id=%u;\n", + f->lastorders, f->lastorders-f->age, + f->override, f->subscription)); + } + } + + if (NMRTimeout()>0 && turn - f->lastorders >= (NMRTimeout() - 1)) { + inactivefaction(f); + continue; + } + } + if (verbosity>=1) { + puts(" - beseitige Spieler, die sich nach der Anmeldung nicht " + "gemeldet haben..."); + } + + age = calloc(MAX(4,turn+1), sizeof(int)); + for (f = factions; f; f = f->next) if (!is_monsters(f)) { + if (RemoveNMRNewbie() && !fval(f, FFL_NOIDLEOUT)) { + if (f->age>=0 && f->age <= turn) ++age[f->age]; + if (f->age == 2 || f->age == 3) { + if (f->lastorders == turn - 2) { + destroyfaction(f); + ++dropouts[f->age-2]; + continue; + } + } + } + } + + if (verbosity>=1) puts(" - beseitige leere Einheiten und leere Parteien..."); + remove_empty_units(); +} +/* ------------------------------------------------------------- */ + +/* HELFE partei [] [NICHT] */ + +static int +ally_cmd(unit * u, struct order * ord) +{ + ally * sf, ** sfp; + faction *f; + int keyword, not_kw; + const char *s; + + init_tokens(ord); + skip_token(); + f = getfaction(); + + if (f==NULL || is_monsters(f)) { + cmistake(u, ord, 66, MSG_EVENT); + return 0; + } + if (f == u->faction) return 0; + + s = getstrtoken(); + + if (!s[0]) + keyword = P_ANY; + else + keyword = findparam(s, u->faction->locale); + + sfp = &u->faction->allies; + if (fval(u, UFL_GROUP)) { + attrib * a = a_find(u->attribs, &at_group); + if (a) sfp = &((group*)a->data.v)->allies; + } + for (sf=*sfp; sf; sf = sf->next) + if (sf->faction == f) + break; /* Gleich die passende raussuchen, wenn vorhanden */ + + not_kw = getparam(u->faction->locale); /* HELFE partei [modus] NICHT */ + + if (!sf) { + if (keyword == P_NOT || not_kw == P_NOT) { + /* Wir helfen der Partei gar nicht... */ + return 0; + } else { + sf = calloc(1, sizeof(ally)); + sf->faction = f; + sf->status = 0; + addlist(sfp, sf); + } + } + switch (keyword) { + case P_NOT: + sf->status = 0; + break; + + case NOPARAM: + cmistake(u, ord, 137, MSG_EVENT); + return 0; + + case P_ANY: + if (not_kw == P_NOT) + sf->status = 0; + else + sf->status = HELP_ALL; + break; + + case P_TRAVEL: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_TRAVEL); + else + sf->status = sf->status | HELP_TRAVEL; + break; + + case P_GIVE: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_GIVE); + else + sf->status = sf->status | HELP_GIVE; + break; + + case P_MONEY: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_MONEY); + else + sf->status = sf->status | HELP_MONEY; + break; + + case P_FIGHT: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_FIGHT); + else + sf->status = sf->status | HELP_FIGHT; + break; + + case P_FACTIONSTEALTH: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_FSTEALTH); + else + sf->status = sf->status | HELP_FSTEALTH; + break; + + case P_GUARD: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_GUARD); + else + sf->status = sf->status | HELP_GUARD; + break; + } + + sf->status &= HelpMask(); + + if (sf->status == 0) { /* Alle HELPs geloescht */ + removelist(sfp, sf); + } + return 0; +} + +static struct local_names * pnames; + +static void +init_prefixnames(void) +{ + int i; + for (i=0;localenames[i];++i) { + const struct locale * lang = find_locale(localenames[i]); + boolean exist = false; + struct local_names * in = pnames; + + while (in!=NULL) { + if (in->lang==lang) { + exist = true; + break; + } + in = in->next; + } + if (in==NULL) in = calloc(sizeof(local_names), 1); + in->next = pnames; + in->lang = lang; + + if (!exist) { + int key; + for (key=0;race_prefixes[key];++key) { + variant var; + const char * pname = locale_string(lang, mkname("prefix", race_prefixes[key])); + if (findtoken(&in->names, pname, &var)==E_TOK_NOMATCH || var.i!=key) { + var.i = key; + addtoken(&in->names, pname, var); + addtoken(&in->names, locale_string(lang, mkname("prefix", race_prefixes[key])), var); + } + } + } + pnames = in; + } +} + +static int +prefix_cmd(unit * u, struct order * ord) +{ + attrib **ap; + const char *s; + local_names * in = pnames; + variant var; + const struct locale * lang = u->faction->locale; + + while (in!=NULL) { + if (in->lang==lang) break; + in = in->next; + } + if (in==NULL) { + init_prefixnames(); + for (in=pnames;in->lang!=lang;in=in->next) ; + } + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + if (!*s) { + attrib *a = NULL; + if (fval(u, UFL_GROUP)) { + a = a_find(u->attribs, &at_group); + } + if (a) { + group * g = (group*)a->data.v; + a_removeall(&g->attribs, &at_raceprefix); + } else { + a_removeall(&u->faction->attribs, &at_raceprefix); + } + return 0; + } + + if (findtoken(&in->names, s, &var)==E_TOK_NOMATCH) { + return 0; + } else if (race_prefixes[var.i] == NULL) { + cmistake(u, ord, 299, MSG_EVENT); + } else { + ap = &u->faction->attribs; + if (fval(u, UFL_GROUP)) { + attrib * a = a_find(u->attribs, &at_group); + group * g = (group*)a->data.v; + if (a) ap = &g->attribs; + } + set_prefix(ap, race_prefixes[var.i]); + } + return 0; +} + + +static cmp_building_cb +get_cmp_region_owner(void) +{ + if (rule_region_owners()) { + return &cmp_current_owner; + } else { + return &cmp_wage; + } +} + +static int +display_cmd(unit * u, struct order * ord) +{ + building * b = u->building; + char **s = NULL; + region * r = u->region; + + init_tokens(ord); + skip_token(); + + switch (getparam(u->faction->locale)) { + case P_BUILDING: + case P_GEBAEUDE: + if (!b) { + cmistake(u, ord, 145, MSG_PRODUCE); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 5, MSG_PRODUCE); + break; + } + if (!fval(b->type, BTF_NAMECHANGE) && b->display && b->display[0] != 0) { + cmistake(u, ord, 278, MSG_EVENT); + break; + } + s = &b->display; + break; + + case P_SHIP: + if (!u->ship) { + cmistake(u, ord, 144, MSG_PRODUCE); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 12, MSG_PRODUCE); + break; + } + s = &u->ship->display; + break; + + case P_UNIT: + s = &u->display; + break; + + case P_PRIVAT: + { + const char *d = getstrtoken(); + if(d == NULL || *d == 0) { + usetprivate(u, NULL); + } else { + usetprivate(u, d); + } + } + break; + + case P_REGION: + if (!b) { + cmistake(u, ord, 145, MSG_EVENT); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 148, MSG_EVENT); + break; + } + if (b != largestbuilding(r, get_cmp_region_owner(), false)) { + cmistake(u, ord, 147, MSG_EVENT); + break; + } + s = &r->display; + break; + + default: + cmistake(u, ord, 110, MSG_EVENT); + break; + } + + if (s!=NULL) { + const char * s2 = getstrtoken(); + + free(*s); + *s = strdup(s2); + if (strlen(s2)>=DISPLAYSIZE) { + (*s)[DISPLAYSIZE] = 0; + } + } + + return 0; +} + +static boolean +renamed_building(const building * b) +{ + const struct locale * lang = locales; + for (;lang;lang=nextlocale(lang)) { + const char * bdname = LOC(lang, b->type->_name); + size_t bdlen = strlen(bdname); + if (strlen(b->name)>=bdlen && strncmp(b->name, bdname, bdlen)==0) { + return false; + } + } + return true; +} + +static int +rename_cmd(unit * u, order * ord, char **s, const char * s2) +{ + if (!s2[0]) { + cmistake(u, ord, 84, MSG_EVENT); + return 0; + } + + /* TODO: Validate to make sure people don't have illegal characters in + * names, phishing-style? () come to mind. */ + + free(*s); + *s = strdup(s2); + if (strlen(s2)>=NAMESIZE) { + (*s)[NAMESIZE] = 0; + } + return 0; +} + +static int +rename_building(unit * u, order * ord, building * b, const char * name) { + unit * owner = b?building_owner(b):0; + boolean foreign = owner && owner->faction==u->faction; + + if (!b) { + cmistake(u, ord, u->building?6:145, MSG_EVENT); + return -1; + } + + if (!fval(b->type, BTF_NAMECHANGE) && renamed_building(b)) { + cmistake(u, ord, 278, MSG_EVENT); + return -1; + } + + if (foreign) { + unit *uo; + + if (renamed_building(b)) { + cmistake(u, ord, 246, MSG_EVENT); + return -1; + } + + uo = building_owner(b); + if (uo) { + if (cansee(uo->faction, u->region, u, 0)) { + ADDMSG(&uo->faction->msgs, msg_message("renamed_building_seen", + "building renamer region", b, u, u->region)); + } else { + ADDMSG(&uo->faction->msgs, msg_message("renamed_building_notseen", + "building region", b, u->region)); + } + } + } else { + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 148, MSG_PRODUCE); + return -1; + } + } + + return rename_cmd(u, ord, &b->name, getstrtoken()); +} + +static int +name_cmd(unit * u, struct order * ord) +{ + building * b = u->building; + region * r = u->region; + char **s = NULL; + param_t p; + boolean foreign = false; + + init_tokens(ord); + skip_token(); + p = getparam(u->faction->locale); + + if (p == P_FOREIGN) { + foreign = true; + p = getparam(u->faction->locale); + } + + switch (p) { + case P_ALLIANCE: + if (foreign==false && f_get_alliance(u->faction)) { + alliance * al = u->faction->alliance; + faction * lead = alliance_get_leader(al); + if (lead==u->faction) { + s = &al->name; + } + } + break; + case P_BUILDING: + case P_GEBAEUDE: + if (foreign) { + b = getbuilding(u->region); + } + + return rename_building(u, ord, b, getstrtoken()); + + case P_FACTION: + if (foreign == true) { + faction *f; + + f = getfaction(); + if (!f) { + cmistake(u, ord, 66, MSG_EVENT); + break; + } + if (f->age < 10) { + cmistake(u, ord, 248, MSG_EVENT); + break; + } else { + const struct locale * lang = locales; + for (;lang;lang=nextlocale(lang)) { + const char * fdname = LOC(lang, "factiondefault"); + size_t fdlen = strlen(fdname); + if (strlen(f->name)>=fdlen && strncmp(f->name, fdname, fdlen)==0) { + break; + } + } + if (lang==NULL) { + cmistake(u, ord, 247, MSG_EVENT); + break; + } + } + if (cansee(f, r, u, 0)) { + ADDMSG(&f->msgs, msg_message("renamed_faction_seen", "unit region", u, r)); + } else { + ADDMSG(&f->msgs, msg_message("renamed_faction_notseen", "", r)); + } + s = &f->name; + } else { + s = &u->faction->name; + } + break; + + case P_SHIP: + if (foreign == true) { + ship *sh = getship(r); + unit *uo; + + if (!sh) { + cmistake(u, ord, 20, MSG_EVENT); + break; + } else { + const struct locale * lang = locales; + for (;lang;lang=nextlocale(lang)) { + const char * sdname = LOC(lang, sh->type->name[0]); + size_t sdlen = strlen(sdname); + if (strlen(sh->name)>=sdlen && strncmp(sh->name, sdname, sdlen)==0) { + break; + } + + sdname = LOC(lang, parameters[P_SHIP]); + sdlen = strlen(sdname); + if (strlen(sh->name)>=sdlen && strncmp(sh->name, sdname, sdlen)==0) { + break; + } + + } + if (lang==NULL) { + cmistake(u, ord, 245, MSG_EVENT); + break; + } + } + uo = shipowner(sh); + if (uo) { + if (cansee(uo->faction, r, u, 0)) { + ADDMSG(&uo->faction->msgs, msg_message("renamed_ship_seen", + "ship renamer region", sh, u, r)); + } else { + ADDMSG(&uo->faction->msgs, msg_message("renamed_ship_notseen", + "ship region", sh, r)); + } + } + s = &sh->name; + } else { + if (!u->ship) { + cmistake(u, ord, 144, MSG_PRODUCE); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 12, MSG_PRODUCE); + break; + } + s = &u->ship->name; + } + break; + + case P_UNIT: + if (foreign == true) { + unit *u2 = getunit(r, u->faction); + + if (!u2 || !cansee(u->faction, r, u2, 0)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + break; + } else { + const char * udefault = LOC(u2->faction->locale, "unitdefault"); + size_t udlen = strlen(udefault); + size_t unlen = strlen(u2->name); + if (unlen>=udlen && strncmp(u2->name, udefault, udlen)!=0) { + cmistake(u2, ord, 244, MSG_EVENT); + break; + } + } + if (cansee(u2->faction, r, u, 0)) { + ADDMSG(&u2->faction->msgs, msg_message("renamed_seen", + "renamer renamed region", u, u2, r)); + } else { + ADDMSG(&u2->faction->msgs, msg_message("renamed_notseen", + "renamed region", u2, r)); + } + s = &u2->name; + } else { + s = &u->name; + } + break; + + case P_REGION: + if (!b) { + cmistake(u, ord, 145, MSG_EVENT); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 148, MSG_EVENT); + break; + } + + if (b != largestbuilding(r, get_cmp_region_owner(), false)) { + cmistake(u, ord, 147, MSG_EVENT); + break; + } + s = &r->land->name; + break; + + case P_GROUP: + { + attrib * a = NULL; + if (fval(u, UFL_GROUP)) a = a_find(u->attribs, &at_group); + if (a) { + group * g = (group*)a->data.v; + s = &g->name; + break; + } else { + cmistake(u, ord, 109, MSG_EVENT); + break; + } + } + break; + default: + cmistake(u, ord, 109, MSG_EVENT); + break; + } + + if (s!=NULL) { + return rename_cmd(u, ord, s, getstrtoken()); + } + + return 0; +} +/* ------------------------------------------------------------- */ + +void +deliverMail(faction * f, region * r, unit * u, const char *s, unit * receiver) +{ + if (!cansee(f, r, u, 0)) { + u = NULL; + } + if (!receiver) { /* BOTSCHAFT an PARTEI */ + ADDMSG(&f->msgs, msg_message("regionmessage", "region sender string", r, u, s)); + } else { /* BOTSCHAFT an EINHEIT */ + ADDMSG(&f->msgs, msg_message("unitmessage", "region unit sender string", r, receiver, u, s)); + } +} + +static void +mailunit(region * r, unit * u, int n, struct order * ord, const char * s) +{ + unit * u2 = findunitr(r,n); + + if (u2 && cansee(u->faction, r, u2, 0)) { + deliverMail(u2->faction, r, u, s, u2); + /* now done in prepare_mail_cmd */ + } + else { + /* Immer eine Meldung - sonst könnte man so getarnte EHs enttarnen: + * keine Meldung -> EH hier. */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } +} + +static void +mailfaction(unit * u, int n, struct order * ord, const char * s) +{ + faction *f; + + f = findfaction(n); + if (f && n>0) + deliverMail(f, u->region, u, s, NULL); + else + cmistake(u, ord, 66, MSG_MESSAGE); +} + +static int +mail_cmd(unit * u, struct order * ord) +{ + region * r = u->region; + unit *u2; + const char *s; + int n, cont; + + init_tokens(ord); + skip_token(); /* skip the keyword */ + s = getstrtoken(); + + /* Falls kein Parameter, ist das eine Einheitsnummer; + * das Füllwort "AN" muß wegfallen, da gültige Nummer! */ + + do { + cont = 0; + switch (findparam(s, u->faction->locale)) { + case P_REGION: + /* können alle Einheiten in der Region sehen */ + s = getstrtoken(); + if (!s[0]) { + cmistake(u, ord, 30, MSG_MESSAGE); + break; + } else { + ADDMSG(&r->msgs, msg_message("mail_result", "unit message", u, s)); + return 0; + } + + case P_FACTION: + { + boolean see = false; + + n = getfactionid(); + + for(u2=r->units; u2; u2=u2->next) { + if(u2->faction->no == n && seefaction(u->faction, r, u2, 0)) { + see = true; + break; + } + } + + if(see == false) { + cmistake(u, ord, 66, MSG_MESSAGE); + break; + } + + s = getstrtoken(); + if (!s[0]) { + cmistake(u, ord, 30, MSG_MESSAGE); + break; + } + mailfaction(u, n, ord, s); + return 0; + } + + case P_UNIT: + { + boolean see = false; + n = getid(); + + for (u2=r->units; u2; u2=u2->next) { + if (u2->no == n && cansee(u->faction, r, u2, 0)) { + see = true; + break; + } + } + + if (see == false) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return 0; + } + + s = getstrtoken(); + if (!s[0]) { + cmistake(u, ord, 30, MSG_MESSAGE); + break; + } else { + attrib * a = a_find(u2->attribs, &at_eventhandler); + if (a!=NULL) { + event_arg args[3]; + args[0].data.v = (void*)s; + args[0].type = "string"; + args[1].data.v = (void*)u; + args[1].type = "unit"; + args[2].type = NULL; + handle_event(a, "message", args); + } + + mailunit(r, u, n, ord, s); + } + return 0; + } + + case P_BUILDING: + case P_GEBAEUDE: + { + building *b = getbuilding(r); + + if(!b) { + cmistake(u, ord, 6, MSG_MESSAGE); + break; + } + + s = getstrtoken(); + + if (!s[0]) { + cmistake(u, ord, 30, MSG_MESSAGE); + break; + } + + for (u2 = r->units; u2; u2 = u2->next) freset(u2->faction, FFL_SELECT); + + for (u2=r->units; u2; u2=u2->next) { + if(u2->building == b && !fval(u2->faction, FFL_SELECT) + && cansee(u->faction, r, u2, 0)) { + mailunit(r, u, u2->no, ord, s); + fset(u2->faction, FFL_SELECT); + } + } + return 0; + } + + case P_SHIP: + { + ship *sh = getship(r); + + if(!sh) { + cmistake(u, ord, 20, MSG_MESSAGE); + break; + } + + s = getstrtoken(); + + if (!s[0]) { + cmistake(u, ord, 30, MSG_MESSAGE); + break; + } + + for (u2 = r->units; u2; u2 = u2->next) freset(u2->faction, FFL_SELECT); + + for(u2=r->units; u2; u2=u2->next) { + if(u2->ship == sh && !fval(u2->faction, FFL_SELECT) && cansee(u->faction, r, u2, 0)) { + mailunit(r, u, u2->no, ord, s); + fset(u2->faction, FFL_SELECT); + } + } + return 0; + } + + default: + /* possibly filler token? */ + s = getstrtoken(); + if (s && *s) cont = 1; + break; + } + } while (cont); + cmistake(u, ord, 149, MSG_MESSAGE); + return 0; +} +/* ------------------------------------------------------------- */ + +static int +banner_cmd(unit * u, struct order * ord) +{ + init_tokens(ord); + skip_token(); + + free(u->faction->banner); + u->faction->banner = strdup(getstrtoken()); + add_message(&u->faction->msgs, msg_message("changebanner", "value", + u->faction->banner)); + + return 0; +} + +static int +email_cmd(unit * u, struct order * ord) +{ + const char * s; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + if (!s[0]) { + cmistake(u, ord, 85, MSG_EVENT); + } else { + faction * f = u->faction; + if (set_email(&f->email, (const char *)s)!=0) { + log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), s)); + ADDMSG(&f->msgs, msg_message("changemail_invalid", "value", s)); + } else { + ADDMSG(&f->msgs, msg_message("changemail", "value", f->email)); + } + } + return 0; +} + +static int +password_cmd(unit * u, struct order * ord) +{ + char pwbuf[32]; + int i; + const char * s; + boolean pwok = true; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + if (!s || !*s) { + for(i=0; i<6; i++) pwbuf[i] = (char)(97 + rng_int() % 26); + pwbuf[6] = 0; + } else { + char *c; + + strlcpy(pwbuf, (const char *)s, 31); + pwbuf[31] = 0; + c = pwbuf; + while (*c && pwok) { + if (!isalnum(*(unsigned char*)c)) pwok = false; + c++; + } + } + free(u->faction->passw); + if (pwok == false) { + cmistake(u, ord, 283, MSG_EVENT); + u->faction->passw = strdup(itoa36(rng_int())); + } else { + u->faction->passw = strdup(pwbuf); + } + fset(u->faction, FFL_OVERRIDE); + ADDMSG(&u->faction->msgs, msg_message("changepasswd", + "value", u->faction->passw)); + return 0; +} + +static int +send_cmd(unit * u, struct order * ord) +{ + const char * s; + int option; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + option = findoption(s, u->faction->locale); + + if (option == -1) { + cmistake(u, ord, 135, MSG_EVENT); + } else { + if (getparam(u->faction->locale) == P_NOT) { + if (option == O_COMPRESS || option == O_BZIP2) { + cmistake(u, ord, 305, MSG_EVENT); + } else { + u->faction->options = u->faction->options & ~(1<faction->options = u->faction->options | (1<faction->options &= ~(1<faction->options &= ~(1<items, itype); + if (i==0) { + if (u->region->land!=NULL) { + i = i_get(u->region->land->items, itype); + } + if (i==0) { + i = i_get(u->faction->items, itype); + if (i==0) return false; + } + } + } + + name = resourcename(itype->rtype, 0); + key = mkname("iteminfo", name); + info = locale_getstring(f->locale, key); + + if (info==NULL) { + info = locale_string(f->locale, mkname("iteminfo", "no_info")); + } + ADDMSG(&f->msgs, msg_message("displayitem", "weight item description", + itype->weight, itype->rtype, info)); + + return true; +} + +static boolean +display_potion(faction *f, unit *u, const potion_type * ptype) +{ + attrib *a; + + if (ptype==NULL) return false; + else { + int i = i_get(u->items, ptype->itype); + if (i==0 && 2*ptype->level > effskill(u,SK_ALCHEMY)) { + return false; + } + } + + a = a_find(f->attribs, &at_showitem); + while (a && a->data.v != ptype) a=a->next; + if (!a) { + a = a_add(&f->attribs, a_new(&at_showitem)); + a->data.v = (void*) ptype->itype; + } + + return true; +} + +static boolean +display_race(faction *f, unit *u, const race * rc) +{ + const char *name, *key; + const char *info; + int a, at_count; + char buf[2048], * bufp = buf; + size_t size = sizeof(buf) - 1; + int bytes; + + if (u && u->race != rc) return false; + name = rc_name(rc, 0); + + bytes = slprintf(bufp, size, "%s: ", LOC(f->locale, name)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + key = mkname("raceinfo", rc->_name[0]); + info = locale_getstring(f->locale, key); + if (info==NULL) { + info = locale_string(f->locale, mkname("raceinfo", "no_info")); + } + + bytes = (int)strlcpy(bufp, info, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + /* hp_p : Trefferpunkte */ + bytes = snprintf(bufp, size, " %d %s", rc->hitpoints, LOC(f->locale, "stat_hitpoints")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + /* b_attacke : Angriff */ + bytes = snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_attack"), (rc->at_default+rc->at_bonus)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + /* b_defense : Verteidigung */ + bytes = snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_defense"), (rc->df_default+rc->df_bonus)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + /* b_armor : Rüstung */ + if (rc->armor > 0) { + bytes = snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_armor"), rc->armor); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + if (size>1) { + *bufp++ ='.'; + --size; + } else WARN_STATIC_BUFFER(); + + /* b_damage : Schaden */ + at_count=0; + for (a = 0; a < 6; a++) { + if (rc->attack[a].type != AT_NONE){ + at_count++; + } + } + if (rc->battle_flags & BF_EQUIPMENT) { + bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_equipment")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (rc->battle_flags & BF_RES_PIERCE) { + bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_pierce")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (rc->battle_flags & BF_RES_CUT) { + bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_cut")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (rc->battle_flags & BF_RES_BASH) { + bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_bash")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + bytes = snprintf(bufp, size, " %d %s", at_count, LOC(f->locale, (at_count==1)?"stat_attack":"stat_attacks")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + for (a = 0; a < 6; a++) { + if (rc->attack[a].type != AT_NONE){ + if (a!=0) bytes = (int)strlcpy(bufp, ", ", size); + else bytes = (int)strlcpy(bufp, ": ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + switch(rc->attack[a].type) { + case AT_STANDARD: + bytes = snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_standard"), rc->def_damage); + break; + case AT_NATURAL: + bytes = snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_natural"), rc->attack[a].data.dice); + break; + case AT_SPELL: + case AT_COMBATSPELL: + case AT_DRAIN_ST: + case AT_DAZZLE: + bytes = snprintf(bufp, size, "%s", LOC(f->locale, "attack_magical")); + break; + case AT_STRUCTURAL: + bytes = snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_structural"), rc->attack[a].data.dice); + break; + default: + bytes = 0; + } + + if (bytes && wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + + if (size>1) { + *bufp++ = '.'; + --size; + } else WARN_STATIC_BUFFER(); + + *bufp = 0; + addmessage(0, f, buf, MSG_EVENT, ML_IMPORTANT); + + return true; +} + +static void +reshow(unit * u, struct order * ord, const char * s, param_t p) +{ + int skill, c; + const potion_type * ptype; + const item_type * itype; + const spell * sp; + const race * rc; + + switch (p) { + case P_ZAUBER: + a_removeall(&u->faction->attribs, &at_seenspell); + break; + case P_POTIONS: + skill = effskill(u, SK_ALCHEMY); + c = 0; + for (ptype = potiontypes; ptype!=NULL; ptype=ptype->next) { + if (ptype->level * 2 <= skill) { + c += display_potion(u->faction, u, ptype); + } + } + if (c == 0) cmistake(u, ord, 285, MSG_EVENT); + break; + case NOPARAM: + /* check if it's an item */ + itype = finditemtype(s, u->faction->locale); + if (itype!=NULL) { + ptype = resource2potion(item2resource(itype)); + if (ptype!=NULL) { + if (display_potion(u->faction, u, ptype)) break; + } else { + if (display_item(u->faction, u, itype)) break; + } + } + /* try for a spell */ + sp = get_spellfromtoken(u, s, u->faction->locale); + if (sp!=NULL && u_hasspell(u, sp)) { + attrib *a = a_find(u->faction->attribs, &at_seenspell); + while (a!=NULL && a->type==&at_seenspell && a->data.v!=sp) a = a->next; + if (a!=NULL) a_remove(&u->faction->attribs, a); + break; + } + /* last, check if it's a race. */ + rc = findrace(s, u->faction->locale); + if (rc != NULL) { + if (display_race(u->faction, u, rc)) break; + } + cmistake(u, ord, 21, MSG_EVENT); + break; + default: + cmistake(u, ord, 222, MSG_EVENT); + break; + } +} + +static int +promotion_cmd(unit * u, struct order * ord) +{ + int money, people; + + if (fval(u, UFL_HERO)) { + /* TODO: message "is already a hero" */ + return 0; + } + + if (maxheroes(u->faction) < countheroes(u->faction)+u->number) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_maxed", "max count", + maxheroes(u->faction), countheroes(u->faction))); + return 0; + } + if (!valid_race(u->faction, u->race)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_race", "race", + u->race)); + return 0; + } + people = count_all(u->faction) * u->number; + money = get_pooled(u, i_silver->rtype, GET_ALL, people); + + if (people>money) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_cost", "cost have", + people, money)); + return 0; + } + use_pooled(u, i_silver->rtype, GET_ALL, people); + fset(u, UFL_HERO); + ADDMSG(&u->faction->msgs, msg_message("hero_promotion", "unit cost", + u, people)); + return 0; +} + +static int +group_cmd(unit * u, struct order * ord) +{ + const char * s; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + join_group(u, s); + return 0; +} + +static int +origin_cmd(unit * u, struct order * ord) +{ + short px, py; + + init_tokens(ord); + skip_token(); + + px = (short)getint(); + py = (short)getint(); + + set_ursprung(u->faction, getplaneid(u->region), px, py); + return 0; +} + +static int +guard_off_cmd(unit * u, struct order * ord) +{ + assert(get_keyword(ord)==K_GUARD); + init_tokens(ord); + skip_token(); + + if (getparam(u->faction->locale) == P_NOT) { + setguard(u, GUARD_NONE); + } + return 0; +} + +static int +reshow_cmd(unit * u, struct order * ord) +{ + const char * s; + param_t p = NOPARAM; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + if (findparam(s, u->faction->locale) == P_ANY) { + p = getparam(u->faction->locale); + s = NULL; + } + + reshow(u, ord, s, p); + return 0; +} + +static int +status_cmd(unit * u, struct order * ord) +{ + const char * param; + + init_tokens(ord); + skip_token(); + + param = getstrtoken(); + switch (findparam(param, u->faction->locale)) { + case P_NOT: + setstatus(u, ST_AVOID); + break; + case P_BEHIND: + setstatus(u, ST_BEHIND); + break; + case P_FLEE: + setstatus(u, ST_FLEE); + break; + case P_CHICKEN: + setstatus(u, ST_CHICKEN); + break; + case P_AGGRO: + setstatus(u, ST_AGGRO); + break; + case P_VORNE: + setstatus(u, ST_FIGHT); + break; + case P_HELP: + if (getparam(u->faction->locale) == P_NOT) { + fset(u, UFL_NOAID); + } else { + freset(u, UFL_NOAID); + } + break; + default: + if (param[0]) { + add_message(&u->faction->msgs, + msg_feedback(u, ord, "unknown_status", "")); + } else { + setstatus(u, ST_FIGHT); + } + } + return 0; +} + +static int +combatspell_cmd(unit * u, struct order * ord) +{ + const char * s; + int level = 0; + spell * spell; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + /* KAMPFZAUBER [NICHT] löscht alle gesetzten Kampfzauber */ + if (!s || *s == 0 || findparam(s, u->faction->locale) == P_NOT) { + unset_combatspell(u, 0); + return 0; + } + + /* Optional: STUFE n */ + if (findparam(s, u->faction->locale) == P_LEVEL) { + /* Merken, setzen kommt erst später */ + level = getint(); + level = MAX(0, level); + s = getstrtoken(); + } + + spell = get_spellfromtoken(u, s, u->faction->locale); + + if(!spell){ + cmistake(u, ord, 173, MSG_MAGIC); + return 0; + } + + s = getstrtoken(); + + if (findparam(s, u->faction->locale) == P_NOT) { + /* KAMPFZAUBER "" NICHT löscht diesen speziellen + * Kampfzauber */ + unset_combatspell(u, spell); + return 0; + } else { + /* KAMPFZAUBER "" setzt diesen Kampfzauber */ + set_combatspell(u, spell, ord, level); + } + + return 0; +} + +/* ------------------------------------------------------------- */ +/* Beachten: einige Monster sollen auch unbewaffent die Region bewachen + * können */ + +enum { E_GUARD_OK, E_GUARD_UNARMED, E_GUARD_NEWBIE, E_GUARD_FLEEING }; + +static int +can_start_guarding(const unit * u) +{ + if (u->status>=ST_FLEE) return E_GUARD_FLEEING; + if (fval(u->race, RCF_UNARMEDGUARD)) return E_GUARD_OK; + if (!armedmen(u, true)) return E_GUARD_UNARMED; + if (IsImmune(u->faction)) return E_GUARD_NEWBIE; + return E_GUARD_OK; +} + +void +update_guards(void) +{ + const region *r; + + for (r = regions; r; r = r->next) { + unit *u; + for (u = r->units; u; u = u->next) { + if (fval(u, UFL_GUARD)) { + if (can_start_guarding(u)!=E_GUARD_OK) { + setguard(u, GUARD_NONE); + } else { + attrib * a = a_find(u->attribs, &at_guard); + if (a && a->data.i==(int)guard_flags(u)) { + /* this is really rather not necessary */ + a_remove(&u->attribs, a); + } + } + } + } + } +} + +static int +guard_on_cmd(unit * u, struct order * ord) +{ + assert(get_keyword(ord)==K_GUARD); + + init_tokens(ord); + skip_token(); + + /* GUARD NOT is handled in goard_off_cmd earlier in the turn */ + if (getparam(u->faction->locale) == P_NOT) return 0; + + if (fval(u->region->terrain, SEA_REGION)) { + cmistake(u, ord, 2, MSG_EVENT); + } else { + if (fval(u, UFL_MOVED)) { + cmistake(u, ord, 187, MSG_EVENT); + } else if (fval(u->race, RCF_ILLUSIONARY) || u->race == new_race[RC_SPELL]) { + cmistake(u, ord, 95, MSG_EVENT); + } else { + /* Monster der Monsterpartei dürfen immer bewachen */ + if (is_monsters(u->faction)) { + guard(u, GUARD_ALL); + } else { + int err = can_start_guarding(u); + if (err==E_GUARD_OK) { + guard(u, GUARD_ALL); + } else if (err==E_GUARD_UNARMED) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_unarmed", "")); + } else if (err==E_GUARD_FLEEING) { + cmistake(u, ord, 320, MSG_EVENT); + } else if (err==E_GUARD_NEWBIE) { + cmistake(u, ord, 304, MSG_EVENT); + } + } + } + } + return 0; +} + +static void +sinkships(region * r) +{ + ship **shp = &r->ships; + + while (*shp) { + ship * sh = *shp; + if (fval(r->terrain, SEA_REGION) && (!enoughsailors(sh, r) || get_captain(sh)==NULL)) { + /* Schiff nicht seetüchtig */ + damage_ship(sh, 0.30); + } + if (shipowner(sh)==NULL) { + damage_ship(sh, 0.05); + } + if (sh->damage >= sh->size * DAMAGE_SCALE) { + remove_ship(shp, sh); + } + if (*shp==sh) shp=&sh->next; + } +} + +/* The following functions do not really belong here: */ +#include +#include + +static attrib_type at_number = { + "faction_renum", + NULL, NULL, NULL, NULL, NULL, + ATF_UNIQUE +}; + +static void +renumber_factions(void) + /* gibt parteien neue nummern */ +{ + struct renum { + struct renum * next; + int want; + faction * faction; + attrib * attrib; + } * renum = NULL, * rp; + faction * f; + for (f=factions;f;f=f->next) { + attrib * a = a_find(f->attribs, &at_number); + int want; + struct renum ** rn; + faction * old; + + if (!a) continue; + want = a->data.i; + if (fval(f, FFL_NEWID)) { + ADDMSG(&f->msgs, msg_message("renumber_twice", "id", want)); + continue; + } + old = findfaction(want); + if (old) { + a_remove(&f->attribs, a); + ADDMSG(&f->msgs, msg_message("renumber_inuse", "id", want)); + continue; + } + if (!faction_id_is_unused(want)) { + a_remove(&f->attribs, a); + ADDMSG(&f->msgs, msg_message("renumber_inuse", "id", want)); + continue; + } + for (rn=&renum; *rn; rn=&(*rn)->next) { + if ((*rn)->want>=want) break; + } + if (*rn && (*rn)->want==want) { + ADDMSG(&f->msgs, msg_message("renumber_inuse", "id", want)); + } else { + struct renum * r = calloc(sizeof(struct renum), 1); + r->next = *rn; + r->attrib = a; + r->faction = f; + r->want = want; + *rn = r; + } + } + for (rp=renum;rp;rp=rp->next) { + f = rp->faction; + a_remove(&f->attribs, rp->attrib); + renumber_faction(f, rp->want); + } + while (renum) { + rp = renum->next; + free(renum); + renum = rp; + } +} + +static void +reorder(void) +{ + region * r; + for (r=regions;r;r=r->next) { + unit ** up=&r->units; + boolean sorted=false; + while (*up) { + unit * u = *up; + if (!fval(u, UFL_MARK)) { + struct order * ord; + for (ord = u->orders;ord;ord=ord->next) { + if (get_keyword(ord)==K_SORT) { + const char * s; + param_t p; + int id; + unit *v; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + p = findparam(s, u->faction->locale); + id = getid(); + v = findunit(id); + + if (v==NULL || v->faction!=u->faction || v->region!=r) { + cmistake(u, ord, 258, MSG_EVENT); + } else if (v->building != u->building || v->ship!=u->ship) { + cmistake(u, ord, 259, MSG_EVENT); + } else if (fval(u, UFL_OWNER)) { + cmistake(u, ord, 260, MSG_EVENT); + } else if (v == u) { + cmistake(u, ord, 10, MSG_EVENT); + } else { + switch(p) { + case P_AFTER: + *up = u->next; + u->next = v->next; + v->next = u; + break; + case P_BEFORE: + if (fval(v, UFL_OWNER)) { + cmistake(v, ord, 261, MSG_EVENT); + } else { + unit ** vp=&r->units; + while (*vp!=v) vp=&(*vp)->next; + *vp = u; + *up = u->next; + u->next = v; + } + break; + } + fset(u, UFL_MARK); + sorted = true; + } + break; + } + } + } + if (u==*up) up=&u->next; + } + if (sorted) { + unit * u; + for (u=r->units;u;u=u->next) freset(u, UFL_MARK); + } + } +} + +#if 0 +/* Aus Gebäude weisen, VERBANNE */ +static void +evict(void) +{ + region *r; + strlist *S; + unit * u; + + for (r=regions;r;r=r->next) { + for (u=r->units;u;u=u->next) { + for (S = u->orders; S; S = S->next) if (get_keyword(ord)==K_EVICT) { + int id; + unit *u2; + /* Nur der Kapitän bzw Burgherr kann jemanden rausschmeißen */ + if(!fval(u, UFL_OWNER)) { + /* Die Einheit ist nicht der Eigentümer */ + cmistake(u,ord,49,MSG_EVENT); + continue; + } + init_tokens(ord); + skip_token(); + id = getid(); + u2 = findunit(id); + + if (u2==NULL) { + /* Einheit nicht gefunden */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + continue; + } + + if (u->building){ + /* in der selben Burg? */ + if (u->building != u2->building){ + /* nicht in Burg */ + cmistake(u,ord,33,MSG_EVENT); + continue; + } + leave_building(u2); + /* meldung an beide */ + } + + if (u->ship){ + if (u->ship != u2->ship){ + /* nicht an Bord */ + cmistake(u, ord, 32, MSG_EVENT); + continue; + } + leave_ship(u2); + /* meldung an beide */ + } + } + } + } +} +#endif + + +static int +renumber_cmd(unit * u, order * ord) +{ + const char * s; + int i; + faction * f = u->faction; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + switch(findparam(s, u->faction->locale)) { + + case P_FACTION: + s = getstrtoken(); + if (s && *s) { + int id = atoi36((const char *)s); + attrib * a = a_find(f->attribs, &at_number); + if (!a) a = a_add(&f->attribs, a_new(&at_number)); + a->data.i = id; + } + break; + + case P_UNIT: + s = getstrtoken(); + if (s == NULL || *s == 0) { + i = newunitid(); + } else { + i = atoi36((const char *)s); + if (i<=0 || i>MAX_UNIT_NR) { + cmistake(u, ord, 114, MSG_EVENT); + break; + } + + if (forbiddenid(i)) { + cmistake(u, ord, 116, MSG_EVENT); + break; + } + + if (findunitg(i, u->region)) { + cmistake(u, ord, 115, MSG_EVENT); + break; + } + } + uunhash(u); + if (!ualias(u)) { + attrib *a = a_add(&u->attribs, a_new(&at_alias)); + a->data.i = -u->no; + } + u->no = i; + uhash(u); + break; + + case P_SHIP: + if (!u->ship) { + cmistake(u, ord, 144, MSG_EVENT); + break; + } + if (u->ship->coast != NODIRECTION) { + cmistake(u, ord, 116, MSG_EVENT); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 146, MSG_EVENT); + break; + } + s = getstrtoken(); + if (s == NULL || *s == 0) { + i = newcontainerid(); + } else { + i = atoi36((const char *)s); + if (i<=0 || i>MAX_CONTAINER_NR) { + cmistake(u,ord,114,MSG_EVENT); + break; + } + if (findship(i) || findbuilding(i)) { + cmistake(u, ord, 115, MSG_EVENT); + break; + } + } + sunhash(u->ship); + u->ship->no = i; + shash(u->ship); + break; + case P_BUILDING: + case P_GEBAEUDE: + if (!u->building) { + cmistake(u,ord,145,MSG_EVENT); + break; + } + if(!fval(u, UFL_OWNER)) { + cmistake(u,ord,148,MSG_EVENT); + break; + } + s = getstrtoken(); + if(*s == 0) { + i = newcontainerid(); + } else { + i = atoi36((const char *)s); + if (i<=0 || i>MAX_CONTAINER_NR) { + cmistake(u,ord,114,MSG_EVENT); + break; + } + if(findship(i) || findbuilding(i)) { + cmistake(u,ord,115,MSG_EVENT); + break; + } + } + bunhash(u->building); + u->building->no = i; + bhash(u->building); + break; + + default: + cmistake(u, ord, 239, MSG_EVENT); + } + return 0; +} + +static building * +age_building(building * b) +{ + static boolean init = false; + static const building_type * bt_blessed; + static const curse_type * ct_astralblock; + if (!init) { + init = true; + bt_blessed = bt_find("blessedstonecircle"); + ct_astralblock = ct_find("astralblock"); + } + + /* blesses stone circles create an astral protection in the astral region + * above the shield, which prevents chaos suction and other spells. + * The shield is created when a magician enters the blessed stone circle, + * and lasts for as long as his skill level / 2 is, at no mana cost. + * + * TODO: this would be nicer in a btype->age function, but we don't have it. + */ + if (ct_astralblock && bt_blessed && b->type==bt_blessed) { + region * r = b->region; + region * rt = r_standard_to_astral(r); + unit * u, * mage = NULL; + + if (fval(rt->terrain, FORBIDDEN_REGION)) rt = NULL; + /* step 1: give unicorns to people in the building, + * find out if there's a magician in there. */ + for (u=r->units;u;u=u->next) { + if (b==u->building && inside_building(u)) { + if (!(u->race->ec_flags & GIVEITEM)==0) { + int n, unicorns = 0; + for (n=0; n!=u->number; ++n) { + if (chance(0.02)) { + i_change(&u->items, olditemtype[I_ELVENHORSE], 1); + ++unicorns; + } + if (unicorns) { + ADDMSG(&u->faction->msgs, msg_message("scunicorn", + "unit amount rtype", u, unicorns, + olditemtype[I_ELVENHORSE]->rtype)); + } + } + } + if (mage==NULL && is_mage(u)) { + mage = u; + } + } + } + + /* if there's a magician, and a connection to astral space, create the + * curse. */ + if (rt!=NULL && mage!=NULL) { + curse * c = get_curse(rt->attribs, ct_astralblock); + if (c==NULL) { + if (mage!=NULL) { + int sk = effskill(mage, SK_MAGIC); + double effect; + effect = 100; + /* the mage reactivates the circle */ + c = create_curse(mage, &rt->attribs, ct_astralblock, + (float)MAX(1, sk), MAX(1, sk/2), effect, 0); + ADDMSG(&r->msgs, msg_message("astralshield_activate", + "region unit", r, mage)); + } + } else if (mage!=NULL) { + int sk = effskill(mage, SK_MAGIC); + c->duration = MAX(c->duration, sk/2); + c->vigour = MAX(c->vigour, sk); + } + } + } + + a_age(&b->attribs); + handle_event(b->attribs, "timer", b); + + if (b->type->age) { + b->type->age(b); + } + + return b; +} + +static double rc_popularity(const struct race * rc) +{ + int pop = get_param_int(rc->parameters, "morale", MORALE_AVERAGE); + return 1.0/(pop-MORALE_COOLDOWN); /* 10 turns average */ +} + +static void age_region(region * r) +{ + a_age(&r->attribs); + handle_event(r->attribs, "timer", r); + + if (!r->land) return; + + if (r->land->ownership && r->land->ownership->owner) { + int stability = turn - r->land->ownership->morale_turn; + int maxmorale = MORALE_DEFAULT; + building * b = largestbuilding(r, &cmp_taxes, false); + if (b) { + int bsize = buildingeffsize(b, false); + maxmorale = (int)(0.5 + b->type->taxes(b, bsize+1) / MORALE_TAX_FACTOR); + } + if (r->land->moraleMORALE_COOLDOWN && r->land->ownership->owner && r->land->moraleland->ownership->owner->race); + if (is_cursed(r->attribs, C_GENEROUS, 0)) { + ch *= 1.2; /* 20% improvement */ + } + if (stability>=MORALE_AVERAGE*2 || chance(ch)) { + region_set_morale(r, r->land->morale+1, turn); + } + } + } else if (r->land->morale>maxmorale) { + region_set_morale(r, r->land->morale-1, turn); + } + } else if (r->land->morale>MORALE_DEFAULT) { + region_set_morale(r, r->land->morale-1, turn); + } +} + +static void +ageing(void) +{ + faction *f; + region *r; + + /* altern spezieller Attribute, die eine Sonderbehandlung brauchen? */ + for(r=regions;r;r=r->next) { + unit *u; + + for (u=r->units;u;u=u->next) { + /* Goliathwasser */ + int i = get_effect(u, oldpotiontype[P_STRONG]); + if (i > 0){ + change_effect(u, oldpotiontype[P_STRONG], -1 * MIN(u->number, i)); + } + /* Berserkerblut*/ + i = get_effect(u, oldpotiontype[P_BERSERK]); + if (i > 0){ + change_effect(u, oldpotiontype[P_BERSERK], -1 * MIN(u->number, i)); + } + + if (is_cursed(u->attribs, C_OLDRACE, 0)){ + curse *c = get_curse(u->attribs, ct_find("oldrace")); + if (c->duration == 1 && !(c_flags(c) & CURSE_NOAGE)) { + u->race = new_race[curse_geteffect_int(c)]; + u->irace = NULL; + } + } + } + } + + /* Borders */ + age_borders(); + + /* Factions */ + for (f=factions;f;f=f->next) { + a_age(&f->attribs); + handle_event(f->attribs, "timer", f); + } + + /* Regionen */ + for (r=regions;r;r=r->next) { + building ** bp; + unit ** up; + ship ** sp; + + age_region(r); + + /* Einheiten */ + for (up=&r->units;*up;) { + unit * u = *up; + a_age(&u->attribs); + if (u==*up) handle_event(u->attribs, "timer", u); + if (u==*up) up = &(*up)->next; + } + + /* Schiffe */ + for (sp=&r->ships;*sp;) { + ship * s = *sp; + a_age(&s->attribs); + if (s==*sp) handle_event(s->attribs, "timer", s); + if (s==*sp) sp = &(*sp)->next; + } + + /* Gebäude */ + for (bp=&r->buildings;*bp;) { + building * b = *bp; + age_building(b); + if (b==*bp) bp = &b->next; + } + + if (rule_region_owners()) { + update_owners(r); + } + } +} + +static int +maxunits(const faction *f) +{ + int flimit = rule_faction_limit(); + int alimit = rule_alliance_limit(); + if (alimit==0) { + return flimit; + } + if (flimit==0) { + return alimit; + } + return MIN(alimit, flimit); +} + +int +checkunitnumber(const faction *f, int add) +{ + int alimit, flimit; + + alimit = rule_alliance_limit(); + if (alimit) { + /* if unitsperalliance is true, maxunits returns the + number of units allowed in an alliance */ + faction *f2; + int unitsinalliance = add; + + for (f2 = factions; f2; f2 = f2->next) { + if (f->alliance == f2->alliance) { + unitsinalliance += f2->no_units; + } + if (unitsinalliance > alimit) { + return 1; + } + } + } + + flimit = rule_faction_limit(); + if (flimit) { + if (f->no_units + add > flimit) { + return 2; + } + } + + return 0; +} + +static void +new_units(void) +{ + region *r; + unit *u, *u2; + + /* neue einheiten werden gemacht und ihre befehle (bis zum "ende" zu + * ihnen rueberkopiert, damit diese einheiten genauso wie die alten + * einheiten verwendet werden koennen. */ + + for (r = regions; r; r = r->next) { + for (u = r->units; u; u = u->next) { + order ** ordp = &u->orders; + + /* this needs to happen very early in the game somewhere. since this is + ** pretty much the first function called per turn, and I am lazy, I + ** decree that it goes here */ + if (u->flags&UFL_GUARD) { + fset(r, RF_GUARDED); + } + + while (*ordp) { + order * makeord = *ordp; + if (get_keyword(makeord) == K_MAKE) { + init_tokens(makeord); + skip_token(); + if (getparam(u->faction->locale) == P_TEMP) { + const char * token; + char * name = NULL; + 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 (get_keyword(ord) == K_END) break; + *ordp = ord->next; + ord->next = NULL; + free_order(ord); + } + continue; + } + alias = getid(); + + token = getstrtoken(); + if (token && token[0]) { + name = strdup(token); + } + u2 = create_unit(r, u->faction, 0, u->faction->race, alias, name, u); + if (name!=NULL) free(name); + 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 (get_keyword(ord) == K_END) break; + *ordp = ord->next; + ord->next = NULL; + *newordersp = ord; + newordersp = &ord->next; + } + } + } + if (*ordp==makeord) ordp=&makeord->next; + } + } + } +} + +static void +setdefaults(unit *u) +{ + order *ord; + boolean trade = false; + boolean hunger = LongHunger(u); + + freset(u, UFL_LONGACTION); + if (hunger) { + /* Hungernde Einheiten führen NUR den default-Befehl aus */ + set_order(&u->thisorder, default_order(u->faction->locale)); + } + /* check all orders for a potential new long order this round: */ + for (ord = u->orders; ord; ord = ord->next) { + if (u->old_orders && is_repeated(ord)) { + /* this new order will replace the old defaults */ + free_orders(&u->old_orders); + if (hunger) break; + } + if (hunger) continue; + + if (is_exclusive(ord)) { + /* Über dieser Zeile nur Befehle, die auch eine idle Faction machen darf */ + if (idle(u->faction)) { + set_order(&u->thisorder, default_order(u->faction->locale)); + } else { + set_order(&u->thisorder, copy_order(ord)); + } + break; + } else { + keyword_t keyword = get_keyword(ord); + switch (keyword) { + /* Wenn gehandelt wird, darf kein langer Befehl ausgeführt + * werden. Da Handel erst nach anderen langen Befehlen kommt, + * muß das vorher abgefangen werden. Wir merken uns also + * hier, ob die Einheit handelt. */ + case NOKEYWORD: + cmistake(u, ord, 22, MSG_EVENT); + break; + case K_BUY: + case K_SELL: + /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht + * werden. */ + trade = true; + break; + + case K_CAST: + /* dient dazu, das neben Zaubern kein weiterer Befehl + * ausgeführt werden kann, Zaubern ist ein kurzer Befehl */ + set_order(&u->thisorder, NULL); + break; + + case K_WEREWOLF: + set_order(&u->thisorder, copy_order(ord)); + break; + + /* Wird je diese Ausschliesslichkeit aufgehoben, muss man aufpassen + * mit der Reihenfolge von Kaufen, Verkaufen etc., damit es Spielern + * nicht moeglich ist, Schulden zu machen. */ + } + } + } + + if (hunger) return; + + /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht + * werden. */ + + if (trade == true) { + /* fset(u, UFL_LONGACTION|UFL_NOTMOVING); */ + set_order(&u->thisorder, NULL); + } +} + +static int +use_item(unit * u, const item_type * itype, int amount, struct order * ord) +{ + int i; + int target = read_unitid(u->faction, u->region); + + i = get_pooled(u, itype->rtype, GET_DEFAULT, amount); + + if (amount>i) { + amount = i; + } + if (amount==0) { + cmistake(u, ord, 43, MSG_PRODUCE); + return ENOITEM; + } + + if (target==-1) { + if (itype->use==NULL) { + cmistake(u, ord, 76, MSG_PRODUCE); + return EUNUSABLE; + } + return itype->use(u, itype, amount, ord); + } else { + if (itype->useonother==NULL) { + cmistake(u, ord, 76, MSG_PRODUCE); + return EUNUSABLE; + } + return itype->useonother(u, target, itype, amount, ord); + } +} + + +static double +heal_factor(const unit * u) +{ + static float elf_regen = -1; + switch(old_race(u->race)) { + case RC_TROLL: + case RC_DAEMON: + return 1.5; + case RC_GOBLIN: + return 2.0; + case RC_ELF: + if (elf_regen<0) elf_regen = get_param_flt(u->race->parameters, "regen.forest", 1.0F); + if (elf_regen!=1.0 && r_isforest(u->region)) { + return elf_regen; + } + return 1.0; + } + return 1.0; +} + +static void +monthly_healing(void) +{ + region *r; + static const curse_type * heal_ct = NULL; + if (heal_ct==NULL) heal_ct = ct_find("healingzone"); + + for (r = regions; r; r = r->next) { + unit *u; + double healingcurse = 0; + + if (heal_ct!=NULL) { + /* bonus zurücksetzen */ + curse * c = get_curse(r->attribs, heal_ct); + if (c!=NULL) { + healingcurse = curse_geteffect(c); + } + } + for (u = r->units; u; u = u->next) { + int umhp = unit_max_hp(u) * u->number; + double p = 1.0; + + /* hp über Maximum bauen sich ab. Wird zb durch Elixier der Macht + * oder verändertes Ausdauertalent verursacht */ + if (u->hp > umhp) { + u->hp -= (int) ceil((u->hp - umhp) / 2.0); + if (u->hp < umhp) u->hp = umhp; + continue; + } + + if (u->race->flags & RCF_NOHEAL) continue; + if (fval(u, UFL_HUNGER)) continue; + + if (fval(r->terrain, SEA_REGION) && u->ship==NULL && !(canswim(u) || canfly(u))) { + continue; + } + + p *= heal_factor(u); + if (u->hp < umhp) { +#ifdef NEW_DAEMONHUNGER_RULE + double maxheal = MAX(u->number, umhp/20.0); +#else + double maxheal = MAX(u->number, umhp/10.0); +#endif + int addhp; + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + if (btype == bt_find("inn")) { + p *= 1.5; + } + /* pro punkt 5% höher */ + p *= (1.0 + healingcurse * 0.05); + + maxheal = p * maxheal; + addhp = (int)maxheal; + maxheal -= addhp; + if (maxheal>0.0 && chance(maxheal)) ++addhp; + + /* Aufaddieren der geheilten HP. */ + u->hp = MIN(u->hp + addhp, umhp); + + /* soll man an negativer regeneration sterben können? */ + assert(u->hp > 0); + } + } + } +} + +static void +remove_exclusive(order ** ordp) +{ + while (*ordp) { + order * ord = *ordp; + if (is_exclusive(ord)) { + *ordp = ord->next; + ord->next = NULL; + free_order(ord); + } else { + ordp = &ord->next; + } + } +} + +static void +defaultorders (void) +{ + region *r; + for (r=regions;r;r=r->next) { + unit *u; + for (u=r->units;u;u=u->next) { + boolean neworders = false; + order ** ordp = &u->orders; + while (*ordp!=NULL) { + order * ord = *ordp; + if (get_keyword(ord)==K_DEFAULT) { + char lbuf[8192]; + order * new_order; + init_tokens(ord); + skip_token(); /* skip the keyword */ + strcpy(lbuf, getstrtoken()); + new_order = parse_order(lbuf, u->faction->locale); + *ordp = ord->next; + ord->next = NULL; + free_order(ord); + if (!neworders) { + /* lange Befehle aus orders und old_orders löschen zu gunsten des neuen */ + remove_exclusive(&u->orders); + remove_exclusive(&u->old_orders); + neworders = true; + ordp = &u->orders; /* we could have broken ordp */ + } + if (new_order) addlist(&u->old_orders, new_order); + } + else ordp = &ord->next; + } + } + } +} + +/* ************************************************************ */ +/* GANZ WICHTIG! ALLE GEÄNDERTEN SPRÜCHE NEU ANZEIGEN */ +/* GANZ WICHTIG! FÜGT AUCH NEUE ZAUBER IN DIE LISTE DER BEKANNTEN EIN */ +/* ************************************************************ */ +#define MAXMAGES 128 /* should be enough */ +static void +update_spells(void) +{ + faction * f; + + for (f=factions;f;f=f->next) { + if (f->magiegebiet!=M_NONE && !is_monsters(f)) { + unit * mages[MAXMAGES]; + unit *u; + int maxlevel = 0, n = 0, i; + + for (u=f->units;u;u=u->nextF) { + if (u->number>0) { + sc_mage *mage = get_mage(u); + if (mage) { + int level = eff_skill(u, SK_MAGIC, u->region); + if (level>maxlevel) maxlevel = level; + assert(nf->max_spelllevel) { + update_spellbook(f, maxlevel); + for (i=0;i!=n;++i) { + sc_mage *mage = get_mage(mages[i]); + while (mage->spells) { + spell_list * slist = mage->spells; + mage->spells = slist->next; + free(slist); + } + } + } + for (i=0;i!=n;++i) { + updatespelllist(mages[i]); + } + } + } +} + +static void +age_factions(void) +{ + faction *f; + + for (f = factions; f; f = f->next) { + ++f->age; + if (f->age+1 < NewbieImmunity()) { + ADDMSG(&f->msgs, msg_message("newbieimmunity", "turns", + NewbieImmunity() - f->age - 1)); + } + } +} + +static int +use_cmd(unit * u, struct order * ord) +{ + const char * t; + int n; + const item_type * itype; + + init_tokens(ord); + skip_token(); + + t = getstrtoken(); + n = atoi((const char *)t); + if (n==0) { + if (findparam(t, u->faction->locale) == P_ANY) { + /* BENUTZE ALLES Yanxspirit */ + n = INT_MAX; + t = getstrtoken(); + } else { + /* BENUTZE Yanxspirit */ + n = 1; + } + } else { + /* BENUTZE 42 Yanxspirit */ + t = getstrtoken(); + } + itype = finditemtype(t, u->faction->locale); + + if (itype!=NULL) { + int i = use_item(u, itype, n, ord); + assert(i<=0 || !"use_item should not return positive values."); + if (i>0) { + log_error(("use_item returned a value>0 for %s\n", resourcename(itype->rtype, 0))); + } + } else { + cmistake(u, ord, 43, MSG_PRODUCE); + } + return 0; +} + +static int +pay_cmd(unit * u, struct order * ord) +{ + if (!u->building) { + cmistake(u, ord, 6, MSG_EVENT); + } else { + param_t p; + init_tokens(ord); + skip_token(); + p = getparam(u->faction->locale); + if (p==P_NOT) { + unit * owner = building_owner(u->building); + if (owner->faction!=u->faction) { + cmistake(u, ord, 1222, MSG_EVENT); + } else { + u->building->flags |= BLD_DONTPAY; + } + } + } + return 0; +} + +static int +claim_cmd(unit * u, struct order * ord) +{ + const char * t; + int n; + const item_type * itype; + + init_tokens(ord); + skip_token(); + + t = getstrtoken(); + n = atoi((const char *)t); + if (n==0) { + n = 1; + } else { + t = getstrtoken(); + } + itype = finditemtype(t, u->faction->locale); + + if (itype!=NULL) { + item ** iclaim = i_find(&u->faction->items, itype); + if (iclaim!=NULL && *iclaim!=NULL) { + n = MIN(n, (*iclaim)->number); + i_change(iclaim, itype, -n); + i_change(&u->items, itype, n); + } + } else { + cmistake(u, ord, 43, MSG_PRODUCE); + } + return 0; +} + +enum { + PROC_THISORDER = 1<<0, + PROC_LONGORDER = 1<<1 +}; +typedef struct processor { + struct processor * next; + int priority; + enum { PR_GLOBAL, PR_REGION_PRE, PR_UNIT, PR_ORDER, PR_REGION_POST } type; + unsigned int flags; + union { + struct { + keyword_t kword; + int (*process)(struct unit *, struct order *); + } per_order; + struct { + void (*process)(struct unit *); + } per_unit; + struct { + void (*process)(struct region *); + } per_region; + struct { + void (*process)(void); + } global; + } data; + const char * name; +} processor; + +static processor * processors; + +processor * +add_proc(int priority, const char * name, int type) +{ + processor **pproc = &processors; + processor *proc; + + while (*pproc) { + proc = *pproc; + if (proc->priority>priority) break; + else if (proc->priority==priority && proc->type>=type) break; + pproc = &proc->next; + } + + proc = malloc(sizeof(processor)); + proc->priority = priority; + proc->type = type; + proc->name = name; + proc->next = *pproc; + *pproc = proc; + return proc; +} + +void +add_proc_order(int priority, keyword_t kword, int (*parser)(struct unit *, struct order *), unsigned int flags, const char * name) +{ + if (!global.disabled[kword]) { + processor * proc = add_proc(priority, name, PR_ORDER); + if (proc) { + proc->data.per_order.process = parser; + proc->data.per_order.kword = kword; + proc->flags = flags; + } + } +} + +void +add_proc_global(int priority, void (*process)(void), const char * name) +{ + processor * proc = add_proc(priority, name, PR_GLOBAL); + if (proc) { + proc->data.global.process = process; + } +} + +void +add_proc_region(int priority, void (*process)(region *), const char * name) +{ + processor * proc = add_proc(priority, name, PR_REGION_PRE); + if (proc) { + proc->data.per_region.process = process; + } +} + +void +add_proc_postregion(int priority, void (*process)(region *), const char * name) +{ + processor * proc = add_proc(priority, name, PR_REGION_POST); + if (proc) { + proc->data.per_region.process = process; + } +} + +void +add_proc_unit(int priority, void (*process)(unit *), const char * name) +{ + processor * proc = add_proc(priority, name, PR_UNIT); + if (proc) { + proc->data.per_unit.process = process; + } +} + +/* per priority, execute processors in order from PR_GLOBAL down to PR_ORDER */ +void +process(void) +{ + processor *proc = processors; + faction * f; + + while (proc) { + int prio = proc->priority; + region *r; + processor *pglobal = proc; + + if (verbosity>=3) printf("- Step %u\n", prio); + while (proc && proc->priority==prio) { + if (proc->name && verbosity>=1) log_stdio(stdout, " - %s\n", proc->name); + proc = proc->next; + } + + while (pglobal && pglobal->priority==prio && pglobal->type==PR_GLOBAL) { + pglobal->data.global.process(); + pglobal = pglobal->next; + } + if (pglobal==NULL || pglobal->priority!=prio) continue; + + for (r = regions; r; r = r->next) { + unit *u; + processor *pregion = pglobal; + + while (pregion && pregion->priority==prio && pregion->type==PR_REGION_PRE) { + pregion->data.per_region.process(r); + pregion = pregion->next; + } + if (pregion==NULL || pregion->priority!=prio) continue; + + if (r->units) { + for (u=r->units;u;u=u->next) { + processor *porder, *punit = pregion; + + while (punit && punit->priority==prio && punit->type==PR_UNIT) { + punit->data.per_unit.process(u); + punit = punit->next; + } + if (punit==NULL || punit->priority!=prio) continue; + + porder = punit; + while (porder && porder->priority==prio && porder->type==PR_ORDER) { + order ** ordp = &u->orders; + if (porder->flags & PROC_THISORDER) ordp = &u->thisorder; + while (*ordp) { + order * ord = *ordp; + if (get_keyword(ord) == porder->data.per_order.kword) { + if (porder->flags & PROC_LONGORDER) { + if (u->number==0) { + ord = NULL; + } else if (u->race == new_race[RC_INSECT] && r_insectstalled(r) && !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) { + ord = NULL; + } else if (LongHunger(u)) { + cmistake(u, ord, 224, MSG_MAGIC); + ord = NULL; + } else if (fval(u, UFL_LONGACTION)) { + cmistake(u, ord, 52, MSG_PRODUCE); + ord = NULL; + } else if (fval(r->terrain, SEA_REGION) && u->race != new_race[RC_AQUARIAN] && !(u->race->flags & RCF_SWIM)) { + /* error message disabled by popular demand */ + ord = NULL; + } + } + if (ord) { + porder->data.per_order.process(u, ord); + } + } + if (!ord || *ordp==ord) ordp=&(*ordp)->next; + } + porder = porder->next; + } + } + } + + while (pregion && pregion->priority==prio && pregion->type!=PR_REGION_POST) { + pregion = pregion->next; + } + + while (pregion && pregion->priority==prio && pregion->type==PR_REGION_POST) { + pregion->data.per_region.process(r); + pregion = pregion->next; + } + if (pregion==NULL || pregion->priority!=prio) continue; + + } + } + + if (verbosity>=3) printf("\n - Leere Gruppen loeschen...\n"); + for (f=factions; f; f=f->next) { + group ** gp = &f->groups; + while (*gp) { + group * g = *gp; + if (g->members==0) { + *gp = g->next; + free_group(g); + } else + gp = &g->next; + } + } + +} + +static void enter_1(region * r) { do_misc(r, false); } +static void enter_2(region * r) { do_misc(r, true); } +static void maintain_buildings_1(region * r) { maintain_buildings(r, false); } +#ifdef COLLAPSE_CHANCE +static void maintain_buildings_2(region * r) { maintain_buildings(r,true); } +#endif +static void reset_moved(unit * u) { freset(u, UFL_MOVED); } + +/** warn about passwords that are not US ASCII. + * even though passwords are technically UTF8 strings, the server receives + * them as part of the Subject of an email when reports are requested. + * This means that we need to limit them to ASCII characters until that + * mechanism has been changed. + */ +static int +warn_password(void) +{ + faction * f = factions; + while (f) { + boolean pwok = true; + const char * c = f->passw; + while (*c && pwok) { + if (!isalnum((unsigned char)*c)) pwok = false; + c++; + } + if (!pwok) { + free(f->passw); + f->passw = strdup(itoa36(rng_int())); + ADDMSG(&f->msgs, msg_message("illegal_password", "newpass", f->passw)); + } + f = f->next; + } + return 0; +} + +void +init_processor(void) +{ + int p; + + p = 10; + add_proc_global(p, &new_units, "Neue Einheiten erschaffen"); + + p+=10; + add_proc_unit(p, &setdefaults, "Default-Befehle"); + add_proc_order(p, K_BANNER, &banner_cmd, 0, NULL); + add_proc_order(p, K_EMAIL, &email_cmd, 0, NULL); + add_proc_order(p, K_PASSWORD, &password_cmd, 0, NULL); + add_proc_order(p, K_SEND, &send_cmd, 0, NULL); + add_proc_order(p, K_GROUP, &group_cmd, 0, NULL); + + p+=10; + add_proc_unit(p, &reset_moved, "Instant-Befehle"); + add_proc_order(p, K_QUIT, &quit_cmd, 0, NULL); + add_proc_order(p, K_URSPRUNG, &origin_cmd, 0, NULL); + add_proc_order(p, K_ALLY, &ally_cmd, 0, NULL); + add_proc_order(p, K_PREFIX, &prefix_cmd, 0, NULL); + add_proc_order(p, K_SETSTEALTH, &setstealth_cmd, 0, NULL); + add_proc_order(p, K_STATUS, &status_cmd, 0, NULL); + add_proc_order(p, K_COMBATSPELL, &combatspell_cmd, 0, NULL); + add_proc_order(p, K_DISPLAY, &display_cmd, 0, NULL); + add_proc_order(p, K_NAME, &name_cmd, 0, NULL); + add_proc_order(p, K_GUARD, &guard_off_cmd, 0, NULL); + add_proc_order(p, K_RESHOW, &reshow_cmd, 0, NULL); + + if (get_param_int(global.parameters, "rules.alliances", 0)==1) { + p+=10; + add_proc_global(p, &alliance_cmd, NULL); + } + + p+=10; + add_proc_global(p, &age_factions, "Parteienalter++"); + add_proc_order(p, K_MAIL, &mail_cmd, 0, "Botschaften"); + + p+=10; /* all claims must be done before we can USE */ + add_proc_region(p, &enter_1, "Kontaktieren & Betreten (1. Versuch)"); + add_proc_order(p, K_USE, &use_cmd, 0, "Benutzen"); + + if (!global.disabled[K_GM]) { + add_proc_global(p, &gmcommands, "GM Kommandos"); + } + + p += 10; /* in case it has any effects on alliance victories */ + add_proc_order(p, K_GIVE, &give_control_cmd, 0, "GIB KOMMANDO"); + + p += 10; /* in case it has any effects on alliance victories */ + add_proc_order(p, K_LEAVE, &leave_cmd, 0, "Verlassen"); + + if (!nobattle) { + add_proc_region(p, &do_battle, "Attackieren"); + } + + if (!global.disabled[K_BESIEGE]) { + p+=10; + add_proc_region(p, &do_siege, "Belagern"); + } + + p+=10; /* can't allow reserve before siege (weapons) */ + add_proc_region(p, &enter_1, "Kontaktieren & Betreten (2. Versuch)"); + add_proc_order(p, K_RESERVE, &reserve_cmd, 0, "Reservieren"); + add_proc_order(p, K_CLAIM, &claim_cmd, 0, NULL); + add_proc_unit(p, &follow_unit, "Folge auf Einheiten setzen"); + + p+=10; /* rest rng again before economics */ + add_proc_region(p, &economics, "Zerstoeren, Geben, Rekrutieren, Vergessen"); + + p+=10; + if (!global.disabled[K_PAY]) { + add_proc_order(p, K_PAY, &pay_cmd, 0, "Gebaeudeunterhalt (disable)"); + } + add_proc_postregion(p, &maintain_buildings_1, "Gebaeudeunterhalt (1. Versuch)"); + + p+=10; /* QUIT fuer sich alleine */ + add_proc_global(p, &quit, "Sterben"); + if (!global.disabled[K_RESTART]) { + add_proc_global(p, &parse_restart, "Neustart"); + } + + if (!global.disabled[K_CAST]) { + p+=10; + add_proc_global(p, &magic, "Zaubern"); + } + + p+=10; + add_proc_order(p, K_TEACH, &teach_cmd, PROC_THISORDER|PROC_LONGORDER, "Lehren"); + p+=10; + add_proc_order(p, K_STUDY, &learn_cmd, PROC_THISORDER|PROC_LONGORDER, "Lernen"); + + p+=10; + add_proc_order(p, K_MAKE, &make_cmd, PROC_THISORDER|PROC_LONGORDER, "Produktion"); + add_proc_postregion(p, &produce, "Arbeiten, Handel, Rekruten"); + add_proc_postregion(p, &split_allocations, "Produktion II"); + + p+=10; + add_proc_region(p, &enter_2, "Kontaktieren & Betreten (3. Versuch)"); + + p+=10; + add_proc_region(p, &sinkships, "Schiffe sinken"); + + p+=10; + add_proc_global(p, &movement, "Bewegungen"); + + if (get_param_int(global.parameters, "work.auto", 0)) { + p+=10; + add_proc_region(p, &auto_work, "Arbeiten (auto)"); + } + + p+=10; + add_proc_order(p, K_GUARD, &guard_on_cmd, 0, "Bewache (an)"); +#if XECMD_MODULE + /* can do together with guard */ + add_proc_order(p, K_XE, &xecmd, 0, "Zeitung"); +#endif + + p+=10; + add_proc_global(p, &encounters, "Zufallsbegegnungen"); + p+=10; + add_proc_unit(p, &monster_kills_peasants, "Monster fressen und vertreiben Bauern"); + + p+=10; + add_proc_global(p, &randomevents, "Zufallsereignisse"); + + p+=10; + + add_proc_global(p, &monthly_healing, "Regeneration (HP)"); + add_proc_global(p, ®eneration_magiepunkte, "Regeneration (Aura)"); + if (!global.disabled[K_DEFAULT]) { + add_proc_global(p, &defaultorders, "Defaults setzen"); + } + add_proc_global(p, &demographics, "Nahrung, Seuchen, Wachstum, Wanderung"); + +#ifdef COLLAPSE_CHANCE + p+=10; + add_proc_region(p, &maintain_buildings_2, "Gebaeudeunterhalt (2. Versuch)"); +#endif + + if (!global.disabled[K_SORT]) { + p+=10; + add_proc_global(p, &reorder, "Einheiten sortieren"); + } + add_proc_order(p, K_PROMOTION, &promotion_cmd, 0, "Heldenbefoerderung"); + if (!global.disabled[K_NUMBER]) { + add_proc_order(p, K_NUMBER, &renumber_cmd, 0, "Neue Nummern (Einheiten)"); + p+=10; + add_proc_global(p, &renumber_factions, "Neue Nummern"); + } +} + +void +processorders (void) +{ + static int init = 0; + + if (!init) { + init_processor(); + init = 1; + } + update_spells(); + process(); + /*************************************************/ + + if (get_param_int(global.parameters, "modules.markets", 0)) { + do_markets(); + } + + if (verbosity>=1) puts(" - Attribute altern"); + ageing(); + remove_empty_units(); + + /* must happen AFTER age, because that would destroy them right away */ + if (get_param_int(global.parameters, "modules.wormholes", 0)) { + create_wormholes(); + } + + /* immer ausführen, wenn neue Sprüche dazugekommen sind, oder sich + * Beschreibungen geändert haben */ + update_spells(); + warn_password(); +} + +int +writepasswd(void) +{ + FILE * F; + char zText[128]; + + sprintf(zText, "%s/passwd", basepath()); + F = cfopen(zText, "w"); + if (F) { + faction *f; + puts("writing passwords..."); + + for (f = factions; f; f = f->next) { + fprintf(F, "%s:%s:%s:%s:%u\n", + factionid(f), f->email, f->passw, f->override, f->subscription); + } + fclose(F); + return 0; + } + return 1; +} + +void +update_subscriptions(void) +{ + FILE * F; + char zText[MAX_PATH]; + faction * f; + strcat(strcpy(zText, basepath()), "/subscriptions"); + F = fopen(zText, "r"); + if (F==NULL) { + log_warning((0, "could not open %s.\n", zText)); + return; + } + for (;;) { + char zFaction[5]; + int subscription, fno; + if (fscanf(F, "%d %s", &subscription, zFaction)<=0) break; + fno = atoi36(zFaction); + f = findfaction(fno); + if (f!=NULL) { + f->subscription=subscription; + } + } + fclose(F); + + sprintf(zText, "subscriptions.%u", turn); + F = fopen(zText, "w"); + for (f=factions;f!=NULL;f=f->next) { + fprintf(F, "%s:%u:%s:%s:%s:%u:\n", + itoa36(f->no), f->subscription, f->email, f->override, + dbrace(f->race), f->lastorders); + } + fclose(F); +} + +int +init_data(const char * filename, const char * catalog) +{ + int l; + + l = read_xml(filename, catalog); + if (l) return l; + + init_locales(); + init_archetypes(); + + if (turn<0) { + turn = first_turn; + } + return 0; +} + +#ifndef DISABLE_TESTS +#include "laws_test.c" +#endif diff --git a/src/gamecode/laws.h b/src/gamecode/laws.h new file mode 100644 index 000000000..5aa7d6f94 --- /dev/null +++ b/src/gamecode/laws.h @@ -0,0 +1,47 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_GC_LAWS +#define H_GC_LAWS +#ifdef __cplusplus +extern "C" { +#endif + +extern int writepasswd(void); +int getoption(void); +int wanderoff(struct region * r, int p); +void demographics(void); +void last_orders(void); +void find_address(void); +void update_guards(void); +void update_subscriptions(void); +void deliverMail(struct faction * f, struct region * r, struct unit * u, const char *s, struct unit * receiver); +int init_data(const char * filename, const char * catalog); + +/* eressea-specific. put somewhere else, please. */ +void processorders(void); +extern struct attrib_type at_germs; + +extern int dropouts[2]; +extern int * age; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/gamecode/laws_test.c b/src/gamecode/laws_test.c new file mode 100644 index 000000000..2bc958813 --- /dev/null +++ b/src/gamecode/laws_test.c @@ -0,0 +1,148 @@ +/* this file should only be included by laws.c, never compiled on its own + * (it does not even include all the headers needed to do so). +**/ +#include + +static void test_new_building_can_be_renamed(CuTest * tc) { + region * r; + building * b; + building_type * btype = bt_find("castle"); + + test_cleanup(); + test_create_world(); + r = findregion(-1, 0); + + b = new_building(btype, r, default_locale); + CuAssertTrue(tc, !renamed_building(b)); +} + +static void test_fishing_feeds_2_people(CuTest * tc) { + region * r; + faction * f; + unit * u; + ship * sh; + + test_cleanup(); + test_create_world(); + r = findregion(-1, 0); + CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ + f = test_create_faction(rc_find("human")); + u = test_create_unit(f, r); + sh = new_ship(st_find("boat"), NULL, r); + u->ship = sh; + i_change(&u->items, it_find("money"), 42); + + scale_number(u, 1); + sh->flags |= SF_FISHING; + get_food(r); + CuAssertIntEquals(tc, 42, i_get(u->items, it_find("money"))); + + scale_number(u, 2); + sh->flags |= SF_FISHING; + get_food(r); + CuAssertIntEquals(tc, 42, i_get(u->items, it_find("money"))); + + scale_number(u, 3); + sh->flags |= SF_FISHING; + get_food(r); + CuAssertIntEquals(tc, 32, i_get(u->items, it_find("money"))); + +} + +static int not_so_hungry(const unit * u) { + return 6 * u->number; +} + +static void test_fishing_does_not_give_goblins_money(CuTest * tc) { + region * r; + faction * f; + unit * u; + ship * sh; + + test_cleanup(); + test_create_world(); + + r = findregion(-1, 0); + CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ + f = test_create_faction(rc_find("human")); + u = test_create_unit(f, r); + sh = new_ship(st_find("boat"), NULL, r); + u->ship = sh; + i_change(&u->items, it_find("money"), 42); + + global.functions.maintenance = not_so_hungry; + scale_number(u, 2); + sh->flags |= SF_FISHING; + get_food(r); + CuAssertIntEquals(tc, 42, i_get(u->items, it_find("money"))); + +} + +static void test_fishing_gets_reset(CuTest * tc) { + region * r; + faction * f; + unit * u; + ship * sh; + + test_cleanup(); + test_create_world(); + r = findregion(-1, 0); + CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ + f = test_create_faction(rc_find("human")); + u = test_create_unit(f, r); + sh = new_ship(st_find("boat"), NULL, r); + u->ship = sh; + i_change(&u->items, it_find("money"), 42); + + scale_number(u, 1); + sh->flags |= SF_FISHING; + get_food(r); + CuAssertIntEquals(tc, 42, i_get(u->items, it_find("money"))); + + scale_number(u, 1); + get_food(r); + CuAssertIntEquals(tc, 32, i_get(u->items, it_find("money"))); + +} + +static void test_unit_limit(CuTest * tc) { + set_param(&global.parameters, "rules.limit.faction", "250"); + CuAssertIntEquals(tc, 250, rule_faction_limit()); + + set_param(&global.parameters, "rules.limit.faction", "200"); + CuAssertIntEquals(tc, 200, rule_faction_limit()); + + set_param(&global.parameters, "rules.limit.alliance", "250"); + CuAssertIntEquals(tc, 250, rule_alliance_limit()); + +} + +extern int checkunitnumber(const faction *f, int add); +static void test_cannot_create_unit_above_limit(CuTest * tc) { + faction * f; + + test_cleanup(); + test_create_world(); + f = test_create_faction(rc_find("human")); + set_param(&global.parameters, "rules.limit.faction", "4"); + + CuAssertIntEquals(tc, 0, checkunitnumber(f, 4)); + CuAssertIntEquals(tc, 2, checkunitnumber(f, 5)); + + set_param(&global.parameters, "rules.limit.alliance", "3"); + CuAssertIntEquals(tc, 0, checkunitnumber(f, 3)); + CuAssertIntEquals(tc, 1, checkunitnumber(f, 4)); +} + + +CuSuite* get_laws_suite(void) +{ + CuSuite* suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, &test_new_building_can_be_renamed); + SUITE_ADD_TEST(suite, &test_fishing_feeds_2_people); + SUITE_ADD_TEST(suite, &test_fishing_does_not_give_goblins_money); + SUITE_ADD_TEST(suite, &test_fishing_gets_reset); + SUITE_ADD_TEST(suite, &test_unit_limit); + SUITE_ADD_TEST(suite, &test_cannot_create_unit_above_limit); + return suite; +} diff --git a/src/gamecode/market.c b/src/gamecode/market.c new file mode 100644 index 000000000..34d13172e --- /dev/null +++ b/src/gamecode/market.c @@ -0,0 +1,184 @@ +/* vi: set ts=2: ++-------------------+ Christian Schlittchen +| | Enno Rehling +| Eressea PBEM host | Katja Zedel +| (c) 1998 - 2003 | Henning Peters +| | Ingo Wilken ++-------------------+ Stefan Reich + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. + +*/ +#include +#include +#include "market.h" + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +static unsigned int +get_markets(region * r, unit ** results, size_t size) +{ + unsigned int n = 0; + building * b; + static building_type * btype; + if (!btype) btype = bt_find("market"); + if (!btype) return 0; + for (b=r->buildings;nnext) { + if (b->type==btype && (b->flags&BLD_WORKING) && b->size>=b->type->maxsize) { + unit * u = building_owner(b); + unsigned int i; + for (i=0;u && i!=n;++i) { + /* only one market per faction */ + if (results[i]->faction==u->faction) u = NULL; + } + if (u) { + results[n++] = u; + } + } + } + return n; +} + + +static void +free_market(attrib * a) +{ + item * items = (item *)a->data.v; + i_freeall(&items); + a->data.v = 0; +} + +attrib_type at_market = { + "script", + NULL, free_market, NULL, + NULL, NULL, ATF_UNIQUE +}; + +static int rc_luxury_trade(const struct race * rc) +{ + if (rc) { + return get_param_int(rc->parameters, "luxury_trade", 1000); + } + return 1000; +} + +static int rc_herb_trade(const struct race * rc) +{ + if (rc) { + return get_param_int(rc->parameters, "herb_trade", 500); + } + return 500; +} + +#define MAX_MARKETS 128 +#define MIN_PEASANTS 50 /* if there are at least this many peasants, you will get 1 good */ + +void do_markets(void) +{ + unit_list * traders = 0; + unit * markets[MAX_MARKETS]; + region * r; + for (r=regions;r;r=r->next) { + if (r->land) { + faction * f = region_get_owner(r); + const struct race * rc = f?f->race:NULL; + int p = rpeasants(r); + int numlux = rc_luxury_trade(rc), numherbs = rc_herb_trade(rc); + numlux = (p+numlux-MIN_PEASANTS)/numlux; + numherbs = (p+numherbs-MIN_PEASANTS)/numherbs; + if (numlux>0 || numherbs>0) { + int d, nmarkets = 0; + const item_type * lux = r_luxury(r); + const item_type * herb = r->land->herbtype; + + nmarkets += get_markets(r, markets+nmarkets, MAX_MARKETS-nmarkets); + for (d=0;d!=MAXDIRECTIONS;++d) { + region * r2 = rconnect(r, d); + if (r2 && r2->buildings) { + nmarkets += get_markets(r2, markets+nmarkets, MAX_MARKETS-nmarkets); + } + } + if (nmarkets) { + while (lux && numlux--) { + int n = rng_int() % nmarkets; + unit * u = markets[n]; + item * items; + attrib * a = a_find(u->attribs, &at_market); + if (a==NULL) { + unit_list * ulist = malloc(sizeof(unit_list)); + a = a_add(&u->attribs, a_new(&at_market)); + ulist->next = traders; + ulist->data = u; + traders = ulist; + } + items = (item *)a->data.v; + i_change(&items, lux, 1); + a->data.v = items; + /* give 1 luxury */ + } + while (herb && numherbs--) { + int n = rng_int() % nmarkets; + unit * u = markets[n]; + item * items; + attrib * a = a_find(u->attribs, &at_market); + if (a==NULL) { + unit_list * ulist = malloc(sizeof(unit_list)); + a = a_add(&u->attribs, a_new(&at_market)); + ulist->next = traders; + ulist->data = u; + traders = ulist; + } + items = (item *)a->data.v; + i_change(&items, herb, 1); + a->data.v = items; + /* give 1 herb */ + } + } + } + } + } + + while (traders) { + unit_list * trade = traders; + unit * u = trade->data; + attrib * a = a_find(u->attribs, &at_market); + item * items = a->data.v; + + a->data.v = NULL; + while (items) { + item * itm = items; + items = itm->next; + + if (itm->number) { + ADDMSG(&u->faction->msgs, msg_message("buyamount", + "unit amount resource", u, itm->number, itm->type->rtype)); + itm->next = NULL; + i_add(&u->items, itm); + } else { + i_free(itm); + } + } + + traders = trade->next; + + a_remove(&u->attribs, a); + free(trade); + } +} +#ifndef DISABLE_TESTS +#include "market_test.c" +#endif diff --git a/src/gamecode/market.h b/src/gamecode/market.h new file mode 100644 index 000000000..e45fbb7a1 --- /dev/null +++ b/src/gamecode/market.h @@ -0,0 +1,25 @@ +/* vi: set ts=2: ++-------------------+ Christian Schlittchen +| | Enno Rehling +| Eressea PBEM host | Katja Zedel +| (c) 1998 - 2003 | Henning Peters +| | Ingo Wilken ++-------------------+ Stefan Reich + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. + +*/ +#ifndef H_GC_MARKET +#define H_GC_MARKET +#ifdef __cplusplus +extern "C" { +#endif + struct building; + + extern void do_markets(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/market_test.c b/src/gamecode/market_test.c new file mode 100644 index 000000000..6b993dc83 --- /dev/null +++ b/src/gamecode/market_test.c @@ -0,0 +1,66 @@ +#include + +#include +#include + +static void market_curse(CuTest * tc) { + region * r; + building * b; + unit * u; + faction * f; + int x, y; + const char * names[4] = { "herb", "herbs", "balm", "balms" }; + terrain_type * terrain; + resource_type * hres = new_resourcetype(names, 0, RTF_ITEM|RTF_POOLED); + item_type * htype = new_itemtype(hres, ITF_HERB, 0, 0); + resource_type * lres = new_resourcetype(names+2, 0, RTF_ITEM|RTF_POOLED); + item_type * ltype = new_itemtype(lres, ITF_NONE, 0, 0); + luxury_type * lux = new_luxurytype(ltype, 0); + building_type * btype; + race * rc = rc_add(rc_new("human")); + struct locale * lang = make_locale("en"); + + free_gamedata(); + + set_param(&global.parameters, "rules.region_owners", "1"); + + btype = calloc(sizeof(building_type), 1); + btype->_name = "market"; + bt_register(btype); + + terrain = calloc(1, sizeof(terrain_type)); + terrain->_name = strdup("plain"); + register_terrain(terrain); + terrain->flags = LAND_REGION|WALK_INTO; + + for (x=0;x!=3;++x) { + for (y=0;y!=3;++y) { + r = new_region(x, y, NULL, 0); + terraform_region(r, terrain); + rsetpeasants(r, 5000); + r_setdemand(r, lux, 0); + rsetherbtype(r, htype); + } + } + r = findregion(1, 1); + b = new_building(btype, r, lang); + b->flags |= BLD_WORKING; + b->size = b->type->maxsize; + + f = addfaction("nobody@eressea.de", NULL, rc, default_locale, 0); + u = create_unit(r, f, 1, f->race, 0, 0, 0); + u->building = b; + u->flags |= UFL_OWNER; + + do_markets(); + + CuAssertIntEquals(tc, 70, i_get(u->items, htype)); + CuAssertIntEquals(tc, 35, i_get(u->items, ltype)); +} + +CuSuite* get_market_suite(void) +{ + CuSuite* suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, market_curse); + return suite; +} diff --git a/src/gamecode/monster.c b/src/gamecode/monster.c new file mode 100644 index 000000000..50436a947 --- /dev/null +++ b/src/gamecode/monster.c @@ -0,0 +1,227 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "monster.h" + +/* gamecode includes */ +#include "economy.h" +#include "give.h" + +/* triggers includes */ +#include + +/* attributes includes */ +#include +#include + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +#define MOVECHANCE 25 /* chance fuer bewegung */ + +#define MAXILLUSION_TEXTS 3 + +boolean +monster_is_waiting(const unit * u) +{ + if (fval(u, UFL_ISNEW|UFL_MOVED)) return true; + return false; +} + +static void +eaten_by_monster(unit * u) +{ + /* adjustment for smaller worlds */ + static double multi = 0.0; + int n = 0; + int horse = 0; + + if (multi==0.0) { + multi = RESOURCE_QUANTITY * newterrain(T_PLAIN)->size / 10000.0; + } + + switch (old_race(u->race)) { + case RC_FIREDRAGON: + n = rng_int()%80 * u->number; + horse = get_item(u, I_HORSE); + break; + case RC_DRAGON: + n = rng_int()%200 * u->number; + horse = get_item(u, I_HORSE); + break; + case RC_WYRM: + n = rng_int()%500 * u->number; + horse = get_item(u, I_HORSE); + break; + default: + n = rng_int()%(u->number/20+1); + } + + n = (int)(n * multi); + if (n > 0) { + n = lovar(n); + n = MIN(rpeasants(u->region), n); + + if (n > 0) { + deathcounts(u->region, n); + rsetpeasants(u->region, rpeasants(u->region) - n); + ADDMSG(&u->region->msgs, msg_message("eatpeasants", "unit amount", u, n)); + } + } + if (horse > 0) { + set_item(u, I_HORSE, 0); + ADDMSG(&u->region->msgs, msg_message("eathorse", "unit amount", u, horse)); + } +} + +static void +absorbed_by_monster(unit * u) +{ + int n; + + switch (old_race(u->race)) { + default: + n = rng_int()%(u->number/20+1); + } + + if(n > 0) { + n = lovar(n); + n = MIN(rpeasants(u->region), n); + if (n > 0){ + rsetpeasants(u->region, rpeasants(u->region) - n); + scale_number(u, u->number + n); + ADDMSG(&u->region->msgs, msg_message("absorbpeasants", + "unit race amount", u, u->race, n)); + } + } +} + +static int +scareaway(region * r, int anzahl) +{ + int n, p, diff = 0, emigrants[MAXDIRECTIONS]; + direction_t d; + + anzahl = MIN(MAX(1, anzahl),rpeasants(r)); + + /* Wandern am Ende der Woche (normal) oder wegen Monster. Die + * Wanderung wird erst am Ende von demographics () ausgefuehrt. + * emigrants[] ist local, weil r->newpeasants durch die Monster + * vielleicht schon hochgezaehlt worden ist. */ + + for (d = 0; d != MAXDIRECTIONS; d++) + emigrants[d] = 0; + + p = rpeasants(r); + assert(p >= 0 && anzahl >= 0); + for (n = MIN(p, anzahl); n; n--) { + direction_t dir = (direction_t)(rng_int() % MAXDIRECTIONS); + region * rc = rconnect(r, dir); + + if (rc && fval(rc->terrain, LAND_REGION)) { + ++diff; + rc->land->newpeasants++; + emigrants[dir]++; + } + } + rsetpeasants(r, p-diff); + assert(p >= diff); + return diff; +} + +static void +scared_by_monster(unit * u) +{ + int n; + + switch (old_race(u->race)) { + case RC_FIREDRAGON: + n = rng_int()%160 * u->number; + break; + case RC_DRAGON: + n = rng_int()%400 * u->number; + break; + case RC_WYRM: + n = rng_int()%1000 * u->number; + break; + default: + n = rng_int()%(u->number/4+1); + } + + if(n > 0) { + n = lovar(n); + n = MIN(rpeasants(u->region), n); + if(n > 0) { + n = scareaway(u->region, n); + if(n > 0) { + ADDMSG(&u->region->msgs, msg_message("fleescared", + "amount unit", n, u)); + } + } + } +} + +void +monster_kills_peasants(unit * u) +{ + if (!monster_is_waiting(u)) { + if (u->race->flags & RCF_SCAREPEASANTS) { + scared_by_monster(u); + } + if (u->race->flags & RCF_KILLPEASANTS) { + eaten_by_monster(u); + } + if (u->race->flags & RCF_ABSORBPEASANTS) { + absorbed_by_monster(u); + } + } +} diff --git a/src/gamecode/monster.h b/src/gamecode/monster.h new file mode 100644 index 000000000..54e5fec10 --- /dev/null +++ b/src/gamecode/monster.h @@ -0,0 +1,31 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_GC_MONSTER +#define H_GC_MONSTER +#ifdef __cplusplus +extern "C" { +#endif + +void monster_kills_peasants(struct unit * u); +boolean monster_is_waiting(const struct unit * u); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/randenc.c b/src/gamecode/randenc.c new file mode 100644 index 000000000..a80eddea0 --- /dev/null +++ b/src/gamecode/randenc.c @@ -0,0 +1,1272 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "randenc.h" + +#include "economy.h" +#include "monster.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* attributes includes */ +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +#include +extern struct attrib_type at_unitdissolve; +extern struct attrib_type at_orcification; + +/* In a->data.ca[1] steht der Prozentsatz mit dem sich die Einheit + * auflöst, in a->data.ca[0] kann angegeben werden, wohin die Personen + * verschwinden. Passiert bereits in der ersten Runde! */ +static void +dissolve_units(void) +{ + region *r; + unit *u; + int n; + int i; + + for (r=regions;r;r=r->next) { + for (u=r->units;u;u=u->next) { + attrib * a = a_find(u->attribs, &at_unitdissolve); + if (a) { + message * msg; + + if (u->age == 0 && a->data.ca[1] < 100) continue; + + /* TODO: Durch einzelne Berechnung ersetzen */ + if (a->data.ca[1] == 100) { + n = u->number; + } else { + n = 0; + for (i=0;inumber;i++) { + if (rng_int()%100 < a->data.ca[1]) n++; + } + } + + /* wenn keiner verschwindet, auch keine Meldung */ + if (n == 0) { + continue; + } + + scale_number(u, u->number - n); + + switch(a->data.ca[0]) { + case 1: + rsetpeasants(r, rpeasants(r) + n); + msg = msg_message("dissolve_units_1", "unit region number race", u, r, n, u->race); + break; + case 2: + if (r->land && !fval(r, RF_MALLORN)) { + rsettrees(r, 2, rtrees(r,2) + n); + msg = msg_message("dissolve_units_2", "unit region number race", u, r, n, u->race); + } else { + msg = msg_message("dissolve_units_3", "unit region number race", u, r, n, u->race); + } + break; + default: + if (u->race == new_race[RC_STONEGOLEM] || u->race == new_race[RC_IRONGOLEM]) { + msg = msg_message("dissolve_units_4", "unit region number race", u, r, n, u->race); + } else { + msg = msg_message("dissolve_units_5", "unit region number race", u, r, n, u->race); + } + break; + } + + add_message(&u->faction->msgs, msg); + msg_release(msg); + } + } + } + + remove_empty_units(); +} + +static int +improve_all(faction * f, skill_t sk, int by_weeks) +{ + unit *u; + boolean ret = by_weeks; + + for (u = f->units; u; u = u->nextF) { + if (has_skill(u, sk)) { + int weeks = 0; + for (;weeks!=by_weeks;++weeks) { + learn_skill(u, sk, 1.0); + ret = 0; + } + } + } + + return ret; +} + +void +find_manual(region * r, unit * u) +{ + char zLocation[32]; + char zBook[32]; + skill_t skill = NOSKILL; + message * msg; + + switch (rng_int() % 36) { + case 0: + skill = SK_MAGIC; + break; + case 1: + case 2: + case 3: + case 4: + skill = SK_WEAPONSMITH; + break; + case 5: + case 6: + skill = SK_TACTICS; + break; + case 7: + case 8: + case 9: + case 10: + skill = SK_SHIPBUILDING; + break; + case 11: + case 12: + case 13: + case 14: + skill = SK_SAILING; + break; + case 15: + case 16: + case 17: + skill = SK_HERBALISM; + break; + case 18: + case 19: + skill = SK_ALCHEMY; + break; + case 20: + case 21: + case 22: + case 23: + skill = SK_BUILDING; + break; + case 24: + case 25: + case 26: + case 27: + skill = SK_ARMORER; + break; + case 28: + case 29: + case 30: + case 31: + skill = SK_MINING; + break; + case 32: + case 33: + case 34: + case 35: + skill = SK_ENTERTAINMENT; + break; + } + + snprintf(zLocation, sizeof(zLocation), "manual_location_%d", (int)(rng_int() % 4)); + snprintf(zBook, sizeof(zLocation), "manual_title_%s", skillnames[skill]); + + msg = msg_message("find_manual", "unit location book", u, zLocation, zBook); + r_addmessage(r, u->faction, msg); + msg_release(msg); + + if (improve_all(u->faction, skill, 3) == 3) { + int i; + for (i=0;i!=9;++i) learn_skill(u, skill, 1.0); + } +} + +static void +get_villagers(region * r, unit * u) +{ + unit *newunit; + message * msg = msg_message("encounter_villagers", "unit", u); + const char * name = LOC(u->faction->locale, "villagers"); + + r_addmessage(r, u->faction, msg); + msg_release(msg); + + newunit = create_unit(r, u->faction, rng_int() % 20 + 3, u->faction->race, 0, name, u); + leave(newunit, true); + fset(newunit, UFL_ISNEW|UFL_MOVED); + equip_unit(newunit, get_equipment("random_villagers")); +} + +static void +get_allies(region * r, unit * u) +{ + unit *newunit = NULL; + const char * name; + const char * equip; + int number; + message * msg; + + assert(u->number); + + switch (rterrain(r)) { + case T_PLAIN: + if (!r_isforest(r)) { + if (get_money(u) / u->number < 100 + rng_int() % 200) + return; + name = "random_plain_men"; + equip = "random_plain"; + number = rng_int() % 8 + 2; + break; + } else { + if (eff_skill(u, SK_LONGBOW, r) < 3 + && eff_skill(u, SK_HERBALISM, r) < 2 + && eff_skill(u, SK_MAGIC, r) < 2) { + return; + } + name = "random_forest_men"; + equip = "random_forest"; + number = rng_int() % 6 + 2; + } + break; + + case T_SWAMP: + if (eff_skill(u, SK_MELEE, r) <= 1) { + return; + } + name = "random_swamp_men"; + equip = "random_swamp"; + number = rng_int() % 6 + 2; + break; + + case T_DESERT: + if (eff_skill(u, SK_RIDING, r) <= 2) { + return; + } + name = "random_desert_men"; + equip = "random_desert"; + number = rng_int() % 12 + 2; + break; + + case T_HIGHLAND: + if (eff_skill(u, SK_MELEE, r) <= 1) { + return; + } + name = "random_highland_men"; + equip = "random_highland"; + number = rng_int() % 8 + 2; + break; + + case T_MOUNTAIN: + if (eff_skill(u, SK_MELEE, r) <= 1 || eff_skill(u, SK_TRADE, r) <= 2) { + return; + } + name = "random_mountain_men"; + equip = "random_mountain"; + number = rng_int() % 6 + 2; + break; + + case T_GLACIER: + if (eff_skill(u, SK_MELEE, r) <= 1 || eff_skill(u, SK_TRADE, r) <= 1) { + return; + } + name = "random_glacier_men"; + equip = "random_glacier"; + number = rng_int() % 4 + 2; + break; + + default: + return; + } + + newunit = create_unit(r, u->faction, number, u->faction->race, 0, LOC(u->faction->locale, name), u); + equip_unit(newunit, get_equipment(equip)); + + u_setfaction(newunit, u->faction); + set_racename(&newunit->attribs, get_racename(u->attribs)); + if (u->race->flags & RCF_SHAPESHIFT) { + newunit->irace = u->irace; + } + if (fval(u, UFL_ANON_FACTION)) fset(newunit, UFL_ANON_FACTION); + fset(newunit, UFL_ISNEW); + + msg = msg_message("encounter_allies", "unit name", u, name); + r_addmessage(r, u->faction, msg); + msg_release(msg); +} + +static void +encounter(region * r, unit * u) +{ + if (!fval(r, RF_ENCOUNTER)) return; + freset(r, RF_ENCOUNTER); + if (rng_int() % 100>=ENCCHANCE) return; + switch (rng_int() % 3) { + case 0: + find_manual(r, u); + break; + case 1: + get_villagers(r, u); + break; + case 2: + get_allies(r, u); + break; + } +} + +void +encounters(void) +{ + region *r; + + for (r = regions; r; r = r->next) { + if (!fval(r->terrain, SEA_REGION) && fval(r, RF_ENCOUNTER)) { + int c = 0; + unit * u; + for (u = r->units; u; u = u->next) { + c += u->number; + } + + if (c > 0) { + int i = 0; + int n = rng_int() % c; + + for (u = r->units; u; u = u->next) { + if (i+u->number>n) break; + i+=u->number; + } + assert(u && u->number); + encounter(r, u); + } + } + } +} + +static const terrain_type * +chaosterrain(void) +{ + static const terrain_type ** types; + static int numtypes; + + if (numtypes==0) { + const terrain_type * terrain; + for (terrain=terrains();terrain!=NULL;terrain=terrain->next) { + if (fval(terrain, LAND_REGION) && terrain->herbs) { + ++numtypes; + } + } + types = malloc(sizeof(terrain_type)*numtypes); + numtypes = 0; + for (terrain=terrains();terrain!=NULL;terrain=terrain->next) { + if (fval(terrain, LAND_REGION) && terrain->herbs) { + types[numtypes++] = terrain; + } + } + } + return types[rng_int() % numtypes]; +} + + +static unit * +random_unit(const region * r) +{ + int c = 0; + int n; + unit *u; + + for (u = r->units; u; u = u->next) { + if (u->race != new_race[RC_SPELL]) { + c += u->number; + } + } + + if (c == 0) { + return NULL; + } + n = rng_int() % c; + c = 0; + u = r->units; + + while (u && c < n) { + if (u->race != new_race[RC_SPELL]) { + c += u->number; + } + u = u->next; + } + + return u; +} + +void +chaos(region * r) +{ + if (rng_int() % 100 < 8) { + switch (rng_int() % 3) { + case 0: /* Untote */ + if (!fval(r->terrain, SEA_REGION)) { + unit * u = random_unit(r); + if (u && playerrace(u->race)) { + ADDMSG(&u->faction->msgs, msg_message("chaos_disease", "unit", u)); + u_setfaction(u, get_monsters()); + u->race = new_race[RC_GHOUL]; + } + } + break; + case 1: /* Drachen */ + if (random_unit(r)) { + int mfac = 0; + unit * u; + switch (rng_int() % 3) { + case 0: + mfac = 100; + u = createunit(r, get_monsters(), rng_int() % 8 + 1, new_race[RC_FIREDRAGON]); + break; + case 1: + mfac = 500; + u = createunit(r, get_monsters(), rng_int() % 4 + 1, new_race[RC_DRAGON]); + break; + default: + mfac = 1000; + u = createunit(r, get_monsters(), rng_int() % 2 + 1, new_race[RC_WYRM]); + break; + } + if (mfac) set_money(u, u->number * (rng_int() % mfac)); + fset(u, UFL_ISNEW|UFL_MOVED); + } + case 2: /* Terrainveränderung */ + if (!fval(r->terrain, FORBIDDEN_REGION)) { + if (!fval(r->terrain, SEA_REGION)) { + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * rn = rconnect(r, dir); + if (rn && fval(rn->terrain, SEA_REGION)) break; + } + if (dir!=MAXDIRECTIONS) { + ship * sh = r->ships; + unit ** up; + + while (sh) { + ship * nsh = sh->next; + damage_ship(sh, 0.50); + if (sh->damage >= sh->size * DAMAGE_SCALE) { + remove_ship(&sh->region->ships, sh); + } + sh = nsh; + } + + for (up = &r->units; *up;) { + unit * u = *up; + if (u->race != new_race[RC_SPELL] && u->ship == 0 && !canfly(u)) { + ADDMSG(&u->faction->msgs, msg_message("tidalwave_kill", "region unit", r, u)); + remove_unit(up, u); + } + if (*up==u) up = &u->next; + } + ADDMSG(&r->msgs, msg_message("tidalwave", "region", r)); + + while (r->buildings) { + remove_building(&r->buildings, r->buildings); + } + terraform_region(r, newterrain(T_OCEAN)); + } + } else { + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * rn = rconnect(r, dir); + if (rn && fval(rn->terrain, SEA_REGION)) break; + } + if (dir!=MAXDIRECTIONS) { + terraform_region(r, chaosterrain()); + } + } + } + } + } +} + + +static int +nb_armor(const unit *u, int index) +{ + const item * itm; + int av = 0; + int s = 0, a = 0; + + if (!(u->race->battle_flags & BF_EQUIPMENT)) return 0; + + /* Normale Rüstung */ + + for (itm=u->items;itm;itm=itm->next) { + const armor_type * atype = itm->type->rtype->atype; + if (atype!=NULL) { + int * schutz = &a; + if (atype->flags & ATF_SHIELD) schutz = &s; + if (*schutz <= index) { + *schutz += itm->number; + if (*schutz > index) { + av += atype->prot; + } + } + } + } + return av; +} + +static int +damage_unit(unit *u, const char *dam, boolean physical, boolean magic) +{ + int *hp = malloc(u->number * sizeof(int)); + int h; + int i, dead = 0, hp_rem = 0, heiltrank; + double magres = magic_resistance(u); + + assert(u->number); + if (fval(u->race, RCF_ILLUSIONARY) || u->race == new_race[RC_SPELL]) { + return 0; + } + + h = u->hp/u->number; + /* HP verteilen */ + for (i=0; inumber; i++) hp[i] = h; + h = u->hp - (u->number * h); + for (i=0; inumber; i++) { + int damage = dice_rand(dam); + if (magic) damage = (int)(damage * (1.0 - magres)); + if (physical) damage -= nb_armor(u, i); + hp[i] -= damage; + } + + /* Auswirkungen */ + for (i=0; inumber; i++) { + if (hp[i] <= 0){ + heiltrank = 0; + + /* Sieben Leben */ + if (old_race(u->race) == RC_CAT && (chance(1.0 / 7))) { + hp[i] = u->hp/u->number; + hp_rem += hp[i]; + continue; + } + + /* Heiltrank */ + if (oldpotiontype[P_HEAL]) { + if (get_effect(u, oldpotiontype[P_HEAL]) > 0) { + change_effect(u, oldpotiontype[P_HEAL], -1); + heiltrank = 1; + } else if (i_get(u->items, oldpotiontype[P_HEAL]->itype) > 0) { + i_change(&u->items, oldpotiontype[P_HEAL]->itype, -1); + change_effect(u, oldpotiontype[P_HEAL], 3); + heiltrank = 1; + } + if (heiltrank && (chance(0.50))) { + hp[i] = u->hp/u->number; + hp_rem += hp[i]; + continue; + } + } + dead++; + } else { + hp_rem += hp[i]; + } + } + + scale_number(u, u->number - dead); + u->hp = hp_rem; + + free(hp); + + return dead; +} + +void +drown(region *r) +{ + if (fval(r->terrain, SEA_REGION)) { + unit ** up = up=&r->units; + while (*up) { + unit *u = *up; + int amphibian_level = 0; + if (u->ship || u->race == new_race[RC_SPELL] || u->number==0) { + up=&u->next; + continue; + } + + if (amphibian_level) { + int dead = damage_unit(u, "5d1", false, false); + if (dead) { + ADDMSG(&u->faction->msgs, msg_message("drown_amphibian_dead", + "amount unit region", dead, u, r)); + } else { + ADDMSG(&u->faction->msgs, msg_message("drown_amphibian_nodead", + "unit region",u, r)); + } + } else if (!(canswim(u) || canfly(u))) { + scale_number(u, 0); + ADDMSG(&u->faction->msgs, msg_message("drown", "unit region", u, r)); + } + if (*up==u) up=&u->next; + } + remove_empty_units_in_region(r); + } +} + +region * +rrandneighbour(region *r) +{ + direction_t i; + region *rc = NULL; + int rr, c = 0; + + /* Nachsehen, wieviele Regionen in Frage kommen */ + + for (i = 0; i != MAXDIRECTIONS; i++) { + c++; + } + /* Zufällig eine auswählen */ + + rr = rng_int() % c; + + /* Durchzählen */ + + c = -1; + for (i = 0; i != MAXDIRECTIONS; i++) { + rc = rconnect(r, i); + c++; + if (c == rr) break; + } + assert(i!=MAXDIRECTIONS); + return rc; +} + +static void +volcano_destruction(region * volcano, region * r, region * rn, const char * damage) +{ + attrib * a; + unit ** up; + int percent = 25, time = 6 + rng_int()%12; + + rsettrees(r, 2, 0); + rsettrees(r, 1, 0); + rsettrees(r, 0, 0); + + a = a_find(r->attribs, &at_reduceproduction); + if (!a) { + a = make_reduceproduction(percent, time); + } else { + /* Produktion vierteln ... */ + a->data.sa[0] = (short)percent; + /* Für 6-17 Runden */ + a->data.sa[1] = (short)(a->data.sa[1] + time); + } + + /* Personen bekommen 4W10 Punkte Schaden. */ + + for (up=&r->units; *up;) { + unit * u = *up; + if (u->number) { + int dead = damage_unit(u, damage, true, false); + if (dead) { + ADDMSG(&u->faction->msgs, msg_message("volcano_dead", + "unit region dead", u, volcano, dead)); + } + if (r==volcano && !fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + if (rn) { + ADDMSG(&u->faction->msgs, msg_message("volcanooutbreak", + "regionv regionn", r, rn)); + } else { + ADDMSG(&u->faction->msgs, msg_message("volcanooutbreaknn", + "region", r)); + } + } + } + if (u==*up) up=&u->next; + } + + remove_empty_units_in_region(r); +} + +void +volcano_outbreak(region *r) +{ + region *rn; + unit *u; + faction *f; + + for (f=NULL,u=r->units; u; u=u->next) { + if (f!=u->faction) { + f = u->faction; + freset(f, FFL_SELECT); + } + } + + /* Zufällige Nachbarregion verwüsten */ + rn = rrandneighbour(r); + + volcano_destruction(r, r, rn, "4d10"); + if (rn) { + volcano_destruction(r, rn, NULL, "3d10"); + } +} + +static void +melt_iceberg(region *r) +{ + attrib *a; + unit *u; + + for (u=r->units; u; u=u->next) freset(u->faction, FFL_SELECT); + for (u=r->units; u; u=u->next) if (!fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + ADDMSG(&u->faction->msgs, msg_message("iceberg_melt", "region", r)); + } + + /* driftrichtung löschen */ + a = a_find(r->attribs, &at_iceberg); + if (a) a_remove(&r->attribs, a); + + /* Gebäude löschen */ + while (r->buildings) { + remove_building(&r->buildings, r->buildings); + } + + /* in Ozean wandeln */ + terraform_region(r, newterrain(T_OCEAN)); + + /* Einheiten, die nicht schwimmen können oder in Schiffen sind, + * ertrinken */ + drown(r); +} + +static void +move_iceberg(region *r) +{ + attrib *a; + direction_t dir; + region *rc; + + a = a_find(r->attribs, &at_iceberg); + if (!a) { + dir = (direction_t)(rng_int()%MAXDIRECTIONS); + a = a_add(&r->attribs, make_iceberg(dir)); + } else { + if (rng_int()%100 < 20) { + dir = (direction_t)(rng_int()%MAXDIRECTIONS); + a->data.i = dir; + } else { + dir = (direction_t)a->data.i; + } + } + + rc = rconnect(r, dir); + + if (rc && !fval(rc->terrain, ARCTIC_REGION)) { + if (fval(rc->terrain, SEA_REGION)) { /* Eisberg treibt */ + ship *sh, *shn; + unit *u; + int x, y; + + + for (u=r->units; u; u=u->next) freset(u->faction, FFL_SELECT); + for (u=r->units; u; u=u->next) if (!fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + ADDMSG(&u->faction->msgs, msg_message("iceberg_drift", + "region dir", r, dir)); + } + + x = r->x; + y = r->y; + + runhash(r); + runhash(rc); + r->x = rc->x; + r->y = rc->y; + rc->x = x; + rc->y = y; + rhash(rc); + rhash(r); + + /* rc ist der Ozean (Ex-Eisberg), r der Eisberg (Ex-Ozean) */ + + /* Schiffe aus dem Zielozean werden in den Eisberg transferiert + * und nehmen Schaden. */ + + for (sh = r->ships; sh; sh=sh->next) freset(sh, SF_SELECT); + + for (sh = r->ships; sh; sh = sh->next) { + /* Meldung an Kapitän */ + damage_ship(sh, 0.10); + fset(sh, SF_SELECT); + } + + /* Personen, Schiffe und Gebäude verschieben */ + while (rc->buildings) { + rc->buildings->region = r; + translist(&rc->buildings, &r->buildings, rc->buildings); + } + while (rc->ships) { + fset(rc->ships, SF_SELECT); + damage_ship(rc->ships, 0.10); + move_ship(rc->ships, rc, r, NULL); + } + while (rc->units) { + building * b = rc->units->building; + u = rc->units; + move_unit(rc->units, r, NULL); + u->building = b; /* move_unit macht ein leave() */ + } + + /* Beschädigte Schiffe können sinken */ + + for (sh = r->ships; sh;) { + shn = sh->next; + if (fval(sh, SF_SELECT)) { + u = captain(sh); + if (sh->damage>=sh->size * DAMAGE_SCALE) { + if (u!=NULL) { + ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg_des", + "ship", sh)); + } + remove_ship(&sh->region->ships, sh); + } else if (u!=NULL) { + ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg", + "ship", sh)); + } + } + sh = shn; + } + + } else if (rng_int()%100 < 20) { /* Eisberg bleibt als Gletscher liegen */ + unit *u; + + rsetterrain(r, T_GLACIER); + a_remove(&r->attribs, a); + + for (u=r->units; u; u=u->next) freset(u->faction, FFL_SELECT); + for (u=r->units; u; u=u->next) if (!fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + ADDMSG(&u->faction->msgs, msg_message("iceberg_land", "region", r)); + } + } + } +} + +static void +move_icebergs(void) +{ + region *r; + + for (r=regions; r; r=r->next) { + if (r->terrain == newterrain(T_ICEBERG) && !fval(r, RF_SELECT)) { + int select = rng_int() % 10; + if (select < 4) { + /* 4% chance */ + fset(r, RF_SELECT); + melt_iceberg(r); + } else if (select<64) { + /* 60% chance */ + fset(r, RF_SELECT); + move_iceberg(r); + } + } + } +} + +void +create_icebergs(void) +{ + region *r; + + for (r=regions; r; r=r->next) { + if (r->terrain == newterrain(T_ICEBERG_SLEEP) && chance(0.05)) { + boolean has_ocean_neighbour = false; + direction_t dir; + region *rc; + unit *u; + + freset(r, RF_SELECT); + for (dir=0; dir < MAXDIRECTIONS; dir++) { + rc = rconnect(r, dir); + if (rc && fval(rc->terrain, SEA_REGION)) { + has_ocean_neighbour = true; + break; + } + } + if (!has_ocean_neighbour) continue; + + rsetterrain(r, T_ICEBERG); + + fset(r, RF_SELECT); + move_iceberg(r); + + for (u=r->units; u; u=u->next) { + freset(u->faction, FFL_SELECT); + } + for (u=r->units; u; u=u->next) { + if (!fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + ADDMSG(&u->faction->msgs, msg_message("iceberg_create", "region", r)); + } + } + } + } +} + +static void +godcurse(void) +{ + region *r; + + for (r=regions; r; r=r->next) { + if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { + unit * u; + for(u=r->units; u; u=u->next) { + skill * sv = u->skills; + while (sv!=u->skills+u->skill_size) { + int weeks = 1+rng_int()%3; + reduce_skill(u, sv, weeks); + ++sv; + } + } + if (fval(r->terrain, SEA_REGION)) { + ship *sh; + for (sh = r->ships; sh;) { + ship *shn = sh->next; + damage_ship(sh, 0.10); + if (sh->damage>=sh->size * DAMAGE_SCALE) { + unit * u = shipowner(sh); + if (u) ADDMSG(&u->faction->msgs, + msg_message("godcurse_destroy_ship", "ship", sh)); + remove_ship(&sh->region->ships, sh); + } + sh = shn; + } + } + } + } + +} + +/** handles the "orcish" curse that makes units grow like old orks + * This would probably be better handled in an age-function for the curse, + * but it's now being called by randomevents() + */ +static void +orc_growth(void) +{ + region * r; + for (r = regions; r; r = r->next) { + unit *u; + for (u = r->units; u; u = u->next) { + static boolean init = false; + static const curse_type *ct_orcish = 0; + curse *c = 0; + if (!init) { + init = true; + ct_orcish = ct_find("orcish"); + } + if (ct_orcish) c = get_curse(u->attribs, ct_orcish); + + if (c && !has_skill(u, SK_MAGIC) && !has_skill(u, SK_ALCHEMY) && !fval(u, UFL_HERO)) { + int n; + int increase = 0; + int num = get_cursedmen(u, c); + double prob = curse_geteffect(c); + + for (n = (num - get_item(u, I_CHASTITY_BELT)); n > 0; n--) { + if (chance(prob)) { + ++increase; + } + } + if (increase) { + unit * u2 = create_unit(r, u->faction, increase, u->race, 0, NULL, u); + transfermen(u2, u, u2->number); + + ADDMSG(&u->faction->msgs, msg_message("orcgrowth", + "unit amount race", u, increase, u->race)); + } + } + } + } +} + +/** Talente von Dämonen verschieben sich. + */ +static void +demon_skillchanges(void) +{ + region * r; + + for (r = regions; r; r = r->next) { + unit * u; + for (u = r->units; u; u = u->next) { + if (u->race == new_race[RC_DAEMON]) { + skill * sv = u->skills; + int upchance = 15; + int downchance = 10; + + if (fval(u, UFL_HUNGER)) { + /* hungry demons only go down, never up in skill */ + static int rule_hunger = -1; + if (rule_hunger<0) { + rule_hunger = get_param_int(global.parameters, "hunger.demon.skill", 0); + } + if (rule_hunger) { + upchance = 0; + downchance = 15; + } + } + + while (sv!=u->skills+u->skill_size) { + int roll = rng_int() % 100; + if (sv->level>0 && roll < upchance+downchance) { + int weeks = 1+rng_int()%3; + if (roll < downchance) { + reduce_skill(u, sv, weeks); + if (sv->level<1) { + /* demons should never forget below 1 */ + set_level(u, sv->id, 1); + } + } else { + while (weeks--) learn_skill(u, sv->id, 1.0); + } + if (sv->old>sv->level) { + if (verbosity>=3) { + log_printf("%s dropped from %u to %u:%u in %s\n", + unitname(u), sv->old, sv->level, sv->weeks, skillname(sv->id, NULL)); + } + } + } + ++sv; + } + } + } + } +} + +/** Eisberge entstehen und bewegen sich. + * Einheiten die im Wasser landen, ertrinken. + */ +static void +icebergs(void) +{ + region * r; + create_icebergs(); + move_icebergs(); + for (r=regions; r; r=r->next) { + drown(r); + } +} + +#ifdef HERBS_ROT +static void +rotting_herbs(void) +{ + static int rule_rot = -1; + region * r; + + if (rule_rot<0) { + rule_rot = get_param_int(global.parameters, "rules.economy.herbrot", HERBROTCHANCE); + } + if (rule_rot==0) return; + + for (r = regions; r; r = r->next) { + unit * u; + for (u = r->units; u; u=u->next) { + item **itmp = &u->items, *hbag = *i_find(itmp, olditemtype[I_SACK_OF_CONSERVATION]); + int rot_chance = rule_rot; + + if (hbag) rot_chance = (rot_chance*2)/5; + while (*itmp) { + item * itm = *itmp; + int n = itm->number; + double k = n*rot_chance/100.0; + if (fval(itm->type, ITF_HERB)) { + double nv = normalvariate(k, k/4); + int inv = (int)nv; + int delta = MIN(n, inv); + if (i_change(itmp, itm->type, -delta)==NULL) { + continue; + } + } + itmp = &itm->next; + } + } + } +} +#endif + +void +randomevents(void) +{ + region *r; + + icebergs(); + godcurse(); + orc_growth(); + demon_skillchanges(); + + /* Orkifizierte Regionen mutieren und mutieren zurück */ + + for (r = regions; r; r = r->next) { + if (fval(r, RF_ORCIFIED)) { + direction_t dir; + double probability = 0.0; + for (dir = 0; dir < MAXDIRECTIONS; dir++) { + region *rc = rconnect(r, dir); + if (rc && rpeasants(rc) > 0 && !fval(rc, RF_ORCIFIED)) probability += 0.02; + } + if (chance(probability)) { + ADDMSG(&r->msgs, msg_message("deorcified", "region", r)); + freset(r, RF_ORCIFIED); + } + } else { + attrib *a = a_find(r->attribs, &at_orcification); + if (a!=NULL) { + double probability = 0.0; + if (rpeasants(r) <= 0) continue; + probability = a->data.i/(double)rpeasants(r); + if (chance(probability)) { + fset(r, RF_ORCIFIED); + a_remove(&r->attribs, a); + ADDMSG(&r->msgs, msg_message("orcified", "region", r)); + } else { + a->data.i -= MAX(10,a->data.i/10); + if (a->data.i <= 0) a_remove(&r->attribs, a); + } + } + } + } + + /* Vulkane qualmen, brechen aus ... */ + for (r = regions; r; r = r->next) { + if (r->terrain == newterrain(T_VOLCANO_SMOKING)) { + if (a_find(r->attribs, &at_reduceproduction)) { + ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r)); + rsetterrain(r, T_VOLCANO); + } else { + if (rng_int()%100 < 12) { + ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r)); + rsetterrain(r, T_VOLCANO); + } else if (r->age>20 && rng_int()%100 < 8) { + volcano_outbreak(r); + } + } + } else if (r->terrain == newterrain(T_VOLCANO)) { + if (rng_int()%100 < 4) { + ADDMSG(&r->msgs, msg_message("volcanostartsmoke", "region", r)); + rsetterrain(r, T_VOLCANO_SMOKING); + } + } + } + + /* Monumente zerfallen, Schiffe verfaulen */ + + for (r = regions; r; r = r->next) { + building ** blist = &r->buildings; + while (*blist) { + building * b = *blist; + if (fval(b->type, BTF_DECAY) && !building_owner(b)) { + b->size -= MAX(1, (b->size * 20) / 100); + if (b->size == 0) { + remove_building(blist, r->buildings); + } + } + if (*blist==b) blist=&b->next; + } + } + + /* monster-einheiten desertieren */ + for (r = regions; r; r=r->next) { + unit *u; + + for (u=r->units; u; u=u->next) { + if (u->faction && !is_monsters(u->faction) + && (u->race->flags & RCF_DESERT)) { + if (fval(u, UFL_ISNEW)) continue; + if (rng_int()%100 < 5) { + ADDMSG(&u->faction->msgs, msg_message("desertion", + "unit region", u, r)); + u_setfaction(u, get_monsters()); + } + } + } + } + + /* Chaos */ + for (r = regions; r; r = r->next) { + int i; + + if (fval(r, RF_CHAOTIC)) { + chaos(r); + } + i = chaoscount(r); + if (i) { + chaoscounts(r, -(int) (i * ((double) (rng_int() % 10)) / 100.0)); + } + } +#ifdef HERBS_ROT + rotting_herbs(); +#endif + + dissolve_units(); +} diff --git a/src/gamecode/randenc.h b/src/gamecode/randenc.h new file mode 100644 index 000000000..31eb0f57f --- /dev/null +++ b/src/gamecode/randenc.h @@ -0,0 +1,31 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_GC_RANDENC +#define H_GC_RANDENC +#ifdef __cplusplus +extern "C" { +#endif + +extern void encounters(void); +extern void randomevents(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/report.c b/src/gamecode/report.c new file mode 100644 index 000000000..4d9308a41 --- /dev/null +++ b/src/gamecode/report.c @@ -0,0 +1,2435 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#define ECHECK_VERSION "4.01" + +#include +#include + +/* modules includes */ +#include + +/* attributes includes */ +#include +#include +#include +#include +#include + +/* gamecode includes */ +#include "creport.h" +#include "economy.h" +#include "monster.h" +#include "laws.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_STAT +#include +#include +#endif + +extern int verbosity; +extern int *storms; +extern int weeks_per_month; +extern int months_per_year; + +static char * +gamedate_season(const struct locale * lang) +{ + static char buf[256]; + gamedate gd; + + get_gamedate(turn, &gd); + + sprintf(buf, (const char *)LOC(lang, "nr_calendar_season"), + LOC(lang, weeknames[gd.week]), + LOC(lang, monthnames[gd.month]), + gd.year, + agename?LOC(lang, agename):"", + LOC(lang, seasonnames[gd.season])); + + return buf; +} + +void +rpc(FILE * F, char c, size_t num) +{ + while(num > 0) { + putc(c, F); + num--; + } +} + +void +rnl(FILE * F) +{ + fputc('\n', F); +} + +static void +centre(FILE * F, const char *s, boolean breaking) +{ + /* Bei Namen die genau 80 Zeichen lang sind, kann es hier Probleme + * geben. Seltsamerweise wird i dann auf MAXINT oder aehnlich + * initialisiert. Deswegen keine Strings die laenger als REPORTWIDTH + * sind! */ + + if (breaking && REPORTWIDTH < strlen(s)) { + strlist *T, *SP = 0; + sparagraph(&SP, s, 0, 0); + T = SP; + while (SP) { + centre(F, SP->s, false); + SP = SP->next; + } + freestrlist(T); + } else { + rpc(F, ' ', (REPORTWIDTH - strlen(s)+1) / 2); + fputs(s, F); + putc('\n', F); + } +} + +static void +rparagraph(FILE *F, const char *str, ptrdiff_t indent, int hanging_indent, char mark) +{ + static const char * spaces = " "; + size_t length = REPORTWIDTH; + const char * end, * begin; + + /* find out if there's a mark + indent already encoded in the string. */ + if (!mark) { + const char * x = str; + while (*x == ' ') ++x; + indent += x - str; + if (x[0] && indent && x[1]==' ') { + indent += 2; + mark = x[0]; + str = x + 2; + hanging_indent -= 2; + } + } + begin = end = str; + + do { + const char * last_space = begin; + + if (mark && indent>=2) { + fwrite(spaces, sizeof(char), indent-2, F); + fputc(mark, F); + fputc(' ', F); + mark = 0; + } else if (begin==str) { + fwrite(spaces, sizeof(char), indent, F); + } else { + fwrite(spaces, sizeof(char), indent+ hanging_indent, F); + } + while (*end && end<=begin+length-indent) { + if (*end==' ') { + last_space = end; + } + ++end; + } + if (*end==0) last_space = end; + if (last_space==begin) { + /* there was no space in this line. clip it */ + last_space = end; + } + fwrite(begin, sizeof(char), last_space-begin, F); + begin = last_space; + while (*begin==' ') { + ++begin; + } + if (begin>end) begin = end; + fputc('\n', F); + } while (*begin); +} + +static void +nr_spell(FILE * F, spell *sp, const struct locale * lang) +{ + int bytes, k, itemanz, costtyp; + int dh = 0; + char buf[4096]; + char * bufp = buf; + size_t size = sizeof(buf) - 1; + const char * params = sp->parameter; + + rnl(F); + centre(F, spell_name(sp, lang), true); + rnl(F); + rparagraph(F, LOC(lang, "nr_spell_description"), 0, 0, 0); + rparagraph(F, spell_info(sp, lang), 2, 0, 0); + + bytes = (int)strlcpy(bufp, LOC(lang, "nr_spell_type"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (size) { *bufp++ = ' '; --size; } + if (sp->sptyp & PRECOMBATSPELL) { + bytes = (int)strlcpy(bufp, LOC(lang, "sptype_precombat"), size); + } else if (sp->sptyp & COMBATSPELL) { + bytes = (int)strlcpy(bufp, LOC(lang, "sptype_combat"), size); + } else if (sp->sptyp & POSTCOMBATSPELL) { + bytes = (int)strlcpy(bufp, LOC(lang, "sptype_postcombat"), size); + } else { + bytes = (int)strlcpy(bufp, LOC(lang, "sptype_normal"), size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + *bufp = 0; + rparagraph(F, buf, 0, 0, 0); + + sprintf(buf, "%s %d", LOC(lang, "nr_spell_level"), sp->level); + rparagraph(F, buf, 0, 0, 0); + + sprintf(buf, "%s %d", LOC(lang, "nr_spell_rank"), sp->rank); + rparagraph(F, buf, 0, 0, 0); + + rparagraph(F, LOC(lang, "nr_spell_components"), 0, 0, 0); + for (k = 0; sp->components[k].type; ++k) { + const resource_type * rtype = sp->components[k].type; + itemanz = sp->components[k].amount; + costtyp = sp->components[k].cost; + if (itemanz > 0) { + size = sizeof(buf) - 1; + bufp = buf; + if (sp->sptyp & SPELLLEVEL) { + bytes = snprintf(bufp, size, " %d %s", itemanz, LOC(lang, resourcename(rtype, itemanz!=1))); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR ) { + bytes = snprintf(bufp, size, " * %s", LOC(lang, "nr_level")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } else { + if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR ) { + itemanz *= sp->level; + } + bytes = snprintf(bufp, size, "%d %s", itemanz, LOC(lang, resourcename(rtype, itemanz!=1))); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + *bufp = 0; + rparagraph(F, buf, 2, 2, '-'); + } + } + + size = sizeof(buf) - 1; + bufp = buf; + bytes = (int)strlcpy(buf, LOC(lang, "nr_spell_modifiers"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (sp->sptyp & FARCASTING) { + bytes = (int)strlcpy(bufp, " Fernzauber", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + dh = 1; + } + if (sp->sptyp & OCEANCASTABLE) { + if (dh == 1) { + bytes = (int)strlcpy(bufp, ",", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + bytes = (int)strlcpy(bufp, " Seezauber", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + dh = 1; + } + if (sp->sptyp & ONSHIPCAST) { + if (dh == 1){ + bytes = (int)strlcpy(bufp, ",", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + bytes = (int)strlcpy(bufp, " Schiffszauber", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + dh = 1; + } + if (sp->sptyp & NOTFAMILIARCAST) { + if (dh == 1) { + bytes = (int)strlcpy(bufp, ", k", size); + } else { + bytes = (int)strlcpy(bufp, " K", size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, "ann nicht vom Vertrauten gezaubert werden", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + dh = 1; + } + if (dh == 0) { + bytes = (int)strlcpy(bufp, " Keine", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + *bufp = 0; + rparagraph(F, buf, 0, 0, 0); + + rparagraph(F, LOC(lang, "nr_spell_syntax"), 0, 0, 0); + + bufp = buf; + size = sizeof(buf) - 1; + + if (sp->sptyp & ISCOMBATSPELL) { + bytes = (int)strlcpy(bufp, LOC(lang, keywords[K_COMBATSPELL]), size); + } else { + bytes = (int)strlcpy(bufp, LOC(lang, keywords[K_CAST]), size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + /* Reihenfolge beachten: Erst REGION, dann STUFE! */ + if (sp->sptyp & FARCASTING) { + bytes = snprintf(bufp, size, " [%s x y]", LOC(lang, parameters[P_REGION])); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (sp->sptyp & SPELLLEVEL) { + bytes = snprintf(bufp, size, " [%s n]", LOC(lang, parameters[P_LEVEL])); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + bytes = (int)snprintf(bufp, size, " \"%s\"", spell_name(sp, lang)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + while (params && *params) { + typedef struct starget { + param_t param; + int flag; + const char * vars; + } starget; + starget targets[] = { + { P_REGION, REGIONSPELL, NULL }, + { P_UNIT, UNITSPELL, "par_unit" }, + { P_SHIP, SHIPSPELL, "par_ship" }, + { P_BUILDING, BUILDINGSPELL, "par_building" }, + { 0, 0, NULL } + }; + starget * targetp; + char cp = *params++; + int i, maxparam = 0; + const char * locp; + const char * syntaxp = sp->syntax; + + if (cp=='u') { + targetp = targets+1; + locp = LOC(lang, targetp->vars); + bytes = (int)snprintf(bufp, size, " <%s>", locp); + if (*params=='+') { + ++params; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else if (cp=='s') { + targetp = targets+2; + locp = LOC(lang, targetp->vars); + bytes = (int)snprintf(bufp, size, " <%s>", locp); + if (*params=='+') { + ++params; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else if (cp=='r') { + bytes = (int)strlcpy(bufp, " ", size); + if (*params=='+') { + ++params; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " [ ...]", size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else if (cp=='b') { + targetp = targets+3; + locp = LOC(lang, targetp->vars); + bytes = (int)snprintf(bufp, size, " <%s>", locp); + if (*params=='+') { + ++params; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else if (cp=='k') { + if (*params=='c') { + /* skip over a potential id */ + ++params; + } + for (targetp=targets;targetp->flag;++targetp) { + if (sp->sptyp&targetp->flag) ++maxparam; + } + if (maxparam>1) { + bytes = (int)strlcpy(bufp, " (", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + i = 0; + for (targetp=targets;targetp->flag;++targetp) { + if (sp->sptyp&targetp->flag) { + if (i++!=0) { + bytes = (int)strlcpy(bufp, " |", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (targetp->param) { + locp = LOC(lang, targetp->vars); + bytes = (int)snprintf(bufp, size, " %s <%s>", parameters[targetp->param], locp); + if (*params=='+') { + ++params; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); + } + } else { + bytes = (int)snprintf(bufp, size, " %s", parameters[targetp->param]); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + if (maxparam>1) { + bytes = (int)strlcpy(bufp, " )", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } else if (cp=='i' || cp=='c') { + const char * cstr; + assert(syntaxp); + cstr = strchr(syntaxp, ':'); + if (!cstr) { + locp = LOC(lang, mkname("spellpar", syntaxp)); + } else { + char substr[32]; + strncpy(substr, syntaxp, cstr-syntaxp); + substr[cstr-syntaxp] = 0; + locp = LOC(lang, mkname("spellpar", substr)); + syntaxp = substr + 1; + } + bytes = (int)snprintf(bufp, size, " <%s>", locp); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + *bufp = 0; + rparagraph(F, buf, 2, 0, 0); + rnl(F); +} + +void +sparagraph(strlist ** SP, const char *s, int indent, char mark) +{ + + /* Die Liste SP wird mit dem String s aufgefuellt, mit indent und einer + * mark, falls angegeben. SP wurde also auf 0 gesetzt vor dem Aufruf. + * Vgl. spunit (). */ + + int i, j, width; + int firstline; + static char buf[REPORTWIDTH + 1]; + + width = REPORTWIDTH - indent; + firstline = 1; + + for (;;) { + i = 0; + + do { + j = i; + while (s[j] && s[j] != ' ') + j++; + if (j > width) { + + /* j zeigt auf das ende der aktuellen zeile, i zeigt auf den anfang der + * nächsten zeile. existiert ein wort am anfang der zeile, welches + * länger als eine zeile ist, muss dieses hier abgetrennt werden. */ + + if (i == 0) + i = width - 1; + break; + } + i = j + 1; + } + while (s[j]); + + for (j = 0; j != indent; j++) + buf[j] = ' '; + + if (firstline && mark) + buf[indent - 2] = mark; + + for (j = 0; j != i - 1; j++) + buf[indent + j] = s[j]; + buf[indent + j] = 0; + + addstrlist(SP, buf); + + if (s[i - 1] == 0) + break; + + s += i; + firstline = 0; + } +} + +int +hat_in_region(item_t it, region * r, faction * f) +{ + unit *u; + + for (u = r->units; u; u = u->next) { + if (u->faction == f && get_item(u, it) > 0) { + return 1; + } + } + return 0; +} + +static void +nr_curses(FILE *F, const faction *viewer, const void * obj, typ_t typ, int indent) +{ + attrib *a = NULL; + int self = 0; + region *r; + + /* Die Sichtbarkeit eines Zaubers und die Zaubermeldung sind bei + * Gebäuden und Schiffen je nach, ob man Besitzer ist, verschieden. + * Bei Einheiten sieht man Wirkungen auf eigene Einheiten immer. + * Spezialfälle (besonderes Talent, verursachender Magier usw. werde + * bei jedem curse gesondert behandelt. */ + if (typ == TYP_SHIP){ + ship * sh = (ship*)obj; + unit * owner = shipowner(sh); + a = sh->attribs; + r = sh->region; + if (owner) { + if (owner->faction == viewer){ + self = 2; + } else { /* steht eine person der Partei auf dem Schiff? */ + unit *u = NULL; + for (u = r->units; u; u = u->next) { + if (u->ship == sh) { + self = 1; + break; + } + } + } + } + } else if (typ == TYP_BUILDING) { + building * b = (building*)obj; + unit * owner; + a = b->attribs; + r = b->region; + if ((owner = building_owner(b)) != NULL){ + if (owner->faction == viewer){ + self = 2; + } else { /* steht eine Person der Partei in der Burg? */ + unit *u = NULL; + for (u = r->units; u; u = u->next) { + if (u->building == b) { + self = 1; + break; + } + } + } + } + } else if (typ == TYP_UNIT) { + unit *u = (unit *)obj; + a = u->attribs; + r = u->region; + if (u->faction == viewer){ + self = 2; + } + } else if (typ == TYP_REGION) { + r = (region *)obj; + a = r->attribs; + } else { + /* fehler */ + } + + for (;a;a=a->next) { + char buf[4096]; + + if (fval(a->type, ATF_CURSE)) { + curse *c = (curse *)a->data.v; + message * msg; + + if (c->type->cansee) { + self = c->type->cansee(viewer, obj, typ, c, self); + } + msg = msg_curse(c, obj, typ, self); + + if (msg) { + rnl(F); + nr_render(msg, viewer->locale, buf, sizeof(buf), viewer); + rparagraph(F, buf, indent, 2, 0); + msg_release(msg); + } + } else if (a->type==&at_effect && self) { + effect_data * data = (effect_data *)a->data.v; + if (data->value>0) { + sprintf(buf, "Auf der Einheit lieg%s %d Wirkung%s %s.", + (data->value==1 ? "t" : "en"), + data->value, + (data->value==1 ? "" : "en"), + LOC(default_locale, resourcename(data->type->itype->rtype, 0))); + rnl(F); + rparagraph(F, buf, indent, 2, 0); + } + } + } +} + +static void +rps_nowrap(FILE * F, const char *s) +{ + const char *x = s; + size_t indent = 0; + + while (*x++ == ' '); + indent = x - s - 1; + if (*(x - 1) && indent && *x == ' ') + indent += 2; + x = s; + while (*s) { + if (s == x) { + x = strchr(x + 1, ' '); + if (!x) + x = s + strlen(s); + } + rpc(F, *s++, 1); + } +} + +static void +nr_unit(FILE * F, const faction * f, const unit * u, int indent, int mode) +{ + attrib *a_otherfaction; + char marker; + int dh; + boolean isbattle = (boolean)(mode == see_battle); + char buf[8192]; + + if (fval(u->race, RCF_INVISIBLE)) return; + + { + rnl(F); + dh = bufunit(f, u, indent, mode, buf, sizeof(buf)); + } + + a_otherfaction = a_find(u->attribs, &at_otherfaction); + + if (u->faction == f) { + marker = '*'; + } else if ALLIED(u->faction, f) { + marker = 'o'; + } else if (a_otherfaction && f != u->faction && get_otherfaction(a_otherfaction) == f + && !fval(u, UFL_ANON_FACTION)) { + marker = '!'; + } else { + if (dh && !fval(u, UFL_ANON_FACTION)) { + marker = '+'; + } else { + marker = '-'; + } + } + rparagraph(F, buf, indent, 0, marker); + + if (!isbattle) { + nr_curses(F, f, u, TYP_UNIT, indent); + } +} + +static void +rp_messages(FILE * F, message_list * msgs, faction * viewer, int indent, boolean categorized) +{ + nrsection * section; + if (!msgs) return; + for (section = sections; section; section=section->next) { + int k = 0; + struct mlist * m = msgs->begin; + while (m) { + /* messagetype * mt = m->type; */ + if (!categorized || strcmp(nr_section(m->msg), section->name)==0) { + char lbuf[8192]; + + if (!k && categorized) { + const char * section_title; + char cat_identifier[24]; + + rnl(F); + sprintf(cat_identifier, "section_%s", section->name); + section_title = LOC(viewer->locale, cat_identifier); + centre(F, section_title, true); + rnl(F); + k = 1; + } + nr_render(m->msg, viewer->locale, lbuf, sizeof(lbuf), viewer); + rparagraph(F, lbuf, indent, 2, 0); + } + m = m->next; + } + if (!categorized) break; + } +} + +static void +rp_battles(FILE * F, faction * f) +{ + if (f->battles!=NULL) { + struct bmsg * bm = f->battles; + rnl(F); + centre(F, LOC(f->locale, "section_battle"), false); + rnl(F); + + while (bm) { + char buf[256]; + RENDER(f, buf, sizeof(buf), ("battle::header", "region", bm->r)); + rnl(F); + centre(F, buf, true); + rnl(F); + rp_messages(F, bm->msgs, f, 0, false); + bm = bm->next; + } + } +} + +static void +prices(FILE * F, const region * r, const faction * f) +{ + const luxury_type *sale=NULL; + struct demand * dmd; + message * m; + int bytes, n = 0; + char buf[4096], * bufp = buf; + size_t size = sizeof(buf) - 1; + + if (r->land==NULL || r->land->demands==NULL) return; + for (dmd=r->land->demands;dmd;dmd=dmd->next) { + if (dmd->value==0) sale = dmd->type; + else if (dmd->value > 0) n++; + } + assert(sale!=NULL); + + m = msg_message("nr_market_sale", "product price", + sale->itype->rtype, sale->price); + + bytes = (int)nr_render(m, f->locale, bufp, size, f); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + msg_release(m); + + if (n > 0) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_intro"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + for (dmd=r->land->demands;dmd;dmd=dmd->next) if(dmd->value > 0) { + m = msg_message("nr_market_price", "product price", + dmd->type->itype->rtype, dmd->value * dmd->type->price); + bytes = (int)nr_render(m, f->locale, bufp, size, f); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + msg_release(m); + n--; + if (n == 0) { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_end"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + else if (n == 1) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_final"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_next"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + } + /* Schreibe Paragraphen */ + *bufp = 0; + rparagraph(F, buf, 0, 0, 0); + +} + +boolean +see_border(const connection * b, const faction * f, const region * r) +{ + boolean cs = b->type->fvisible(b, f, r); + if (!cs) { + cs = b->type->rvisible(b, r); + if (!cs) { + const unit * us = r->units; + while (us && !cs) { + if (us->faction==f) { + cs = b->type->uvisible(b, us); + if (cs) break; + } + us=us->next; + } + } + } + return cs; +} + +static void +describe(FILE * F, const seen_region * sr, faction * f) +{ + const region * r = sr->r; + int n; + boolean dh; + direction_t d; + int trees; + int saplings; + attrib *a; + const char *tname; + struct edge { + struct edge * next; + char * name; + boolean transparent; + boolean block; + boolean exist[MAXDIRECTIONS]; + direction_t lastd; + } * edges = NULL, * e; + boolean see[MAXDIRECTIONS]; + char buf[8192]; + char * bufp = buf; + size_t size = sizeof(buf); + int bytes; + + for (d = 0; d != MAXDIRECTIONS; d++) { + /* Nachbarregionen, die gesehen werden, ermitteln */ + region *r2 = rconnect(r, d); + connection *b; + see[d] = true; + if (!r2) continue; + for (b=get_borders(r, r2);b;) { + struct edge * e = edges; + boolean transparent = b->type->transparent(b, f); + const char * name = b->type->name(b, r, f, GF_DETAILED|GF_ARTICLE); + + if (!transparent) see[d] = false; + if (!see_border(b, f, r)) { + b = b->next; + continue; + } + while (e && (e->transparent != transparent || strcmp(name,e->name))) e = e->next; + if (!e) { + e = calloc(sizeof(struct edge), 1); + e->name = strdup(name); + e->transparent = transparent; + e->next = edges; + edges = e; + } + e->lastd=d; + e->exist[d] = true; + b = b->next; + } + } + + bytes = (int)f_regionid(r, f, bufp, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (sr->mode==see_travel) { + bytes = (int)strlcpy(bufp, " (durchgereist)", size); + } + else if (sr->mode==see_neighbour) { + bytes = (int)strlcpy(bufp, " (benachbart)", size); + } + else if (sr->mode==see_lighthouse) { + bytes = (int)strlcpy(bufp, " (vom Turm erblickt)", size); + } else { + bytes = 0; + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + /* Terrain */ + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + tname = terrain_name(r); + bytes = (int)strlcpy(bufp, LOC(f->locale, tname), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + /* Trees */ + trees = rtrees(r,2); + saplings = rtrees(r,1); + if (production(r)) { + if (trees > 0 || saplings > 0) { + bytes = snprintf(bufp, size, ", %d/%d ", trees, saplings); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (fval(r, RF_MALLORN)) { + if (trees == 1) { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_mallorntree"), size); + } else { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_mallorntree_p"), size); + } + } + else if (trees == 1) { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_tree"), size); + } else { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_tree_p"), size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + + /* iron & stone */ + if (sr->mode==see_unit && f != (faction *) NULL) { + resource_report result[MAX_RAWMATERIALS]; + int n, numresults = report_resources(sr, result, MAX_RAWMATERIALS, f); + + for (n=0;n=0 && result[n].level>=0) { + bytes = snprintf(bufp, size, ", %d %s/%d", result[n].number, + LOC(f->locale, result[n].name), result[n].level); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + } + + /* peasants & silver */ + if (rpeasants(r)) { + int n = rpeasants(r); + bytes = snprintf(bufp, size, ", %d", n); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (r->land->ownership) { + const char * str = locale_string(f->locale, mkname("morale", itoa10(r->land->morale))); + bytes = snprintf(bufp, size, " %s", str); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (fval(r, RF_ORCIFIED)) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + bytes = (int)strlcpy(bufp, LOC(f->locale, n==1?"rc_orc":"rc_orc_p"), size); + } else { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, n==1?"peasant":"peasant_p"), size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (is_mourning(r, turn+1)) { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_mourning"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + if (rmoney(r) && sr->mode>=see_travel) { + bytes = snprintf(bufp, size, ", %d ", rmoney(r)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, resourcename(oldresourcetype[R_SILVER], rmoney(r)!=1)), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + /* Pferde */ + + if (rhorses(r)) { + bytes = snprintf(bufp, size, ", %d ", rhorses(r)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, resourcename(oldresourcetype[R_HORSE], (rhorses(r)>1)?GR_PLURAL:0)), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + + if (r->display && r->display[0]) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, r->display, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + n = r->display[strlen(r->display) - 1]; + if (n != '!' && n != '?' && n != '.') { + bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + + if (rule_region_owners()) { + const faction * owner = region_get_owner(r); + if (owner!=NULL) { + bytes = snprintf(bufp, size, " Die Region ist im Besitz von %s.", + factionname(owner)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + a = a_find(r->attribs, &at_overrideroads); + + if (a) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, (char *)a->data.v, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else { + int nrd = 0; + + /* Nachbarregionen, die gesehen werden, ermitteln */ + for (d = 0; d != MAXDIRECTIONS; d++) { + if (see[d] && rconnect(r, d)) nrd++; + } + /* list directions */ + + dh = false; + for (d = 0; d != MAXDIRECTIONS; d++) if (see[d]) { + region * r2 = rconnect(r, d); + if(!r2) continue; + nrd--; + if (dh) { + char regname[4096]; + if (nrd == 0) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nb_final"), size); + } else { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nb_next"), size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, directions[d]), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + f_regionid(r2, f, regname, sizeof(regname)); + bytes = snprintf(bufp, size, trailinto(r2, f->locale), regname); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + else { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + MSG(("nr_vicinitystart", "dir region", d, r2), bufp, size, f->locale, f); + bufp += strlen(bufp); + dh = true; + } + } + /* Spezielle Richtungen */ + for (a = a_find(r->attribs, &at_direction);a && a->type==&at_direction;a=a->next) { + spec_direction * d = (spec_direction *)(a->data.v); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, d->desc), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " (\"", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, d->keyword), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, "\")", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + dh = 1; + } + } + rnl(F); + *bufp = 0; + rparagraph(F, buf, 0, 0, 0); + + if (sr->mode==see_unit && is_astral(r) && + !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) { + /* Sonderbehandlung Teleport-Ebene */ + region_list *rl = astralregions(r, inhabitable); + region_list *rl2; + + if (rl) { + bufp = buf; + size = sizeof(buf) - 1; + bytes = (int)strlcpy(bufp, "Schemen der Regionen ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + rl2 = rl; + while (rl2) { + bytes = (int)f_regionid(rl2->data, f, bufp, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + rl2 = rl2->next; + if (rl2) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + bytes = (int)strlcpy(bufp, " sind erkennbar.", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + free_regionlist(rl); + /* Schreibe Paragraphen */ + rnl(F); + *bufp = 0; + rparagraph(F, buf, 0, 0, 0); + } + } + + n = 0; + + /* Wirkungen permanenter Sprüche */ + nr_curses(F, f, r, TYP_REGION,0); + + /* Produktionsreduktion */ + a = a_find(r->attribs, &at_reduceproduction); + if (a) { + const char * str = LOC(f->locale, "nr_reduced_production"); + rparagraph(F, str, 0, 0, 0); + } + + if (edges) rnl(F); + for (e=edges;e;e=e->next) { + boolean first = true; + bufp = buf; + size = sizeof(buf) - 1; + for (d=0;d!=MAXDIRECTIONS;++d) { + if (!e->exist[d]) continue; + if (first) bytes = (int)strlcpy(bufp, "Im ", size); + else if (e->lastd==d) bytes = (int)strlcpy(bufp, " und im ", size); + else bytes = (int)strlcpy(bufp, ", im ", size ); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, directions[d]), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + first = false; + } + if (!e->transparent) bytes = (int)strlcpy(bufp, " versperrt ", size); + else bytes = (int)strlcpy(bufp, " befindet sich ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, e->name, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (!e->transparent) bytes = (int)strlcpy(bufp, " die Sicht.", size); + else bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + *bufp = 0; + rparagraph(F, buf, 0, 0, 0); + } + if (edges) { + while (edges) { + e = edges->next; + free(edges->name); + free(edges); + edges = e; + } + } +} + +static void +statistics(FILE * F, const region * r, const faction * f) +{ + const unit *u; + int number = 0, p = rpeasants(r); + message * m; + item *itm, *items = NULL; + char buf[4096]; + + /* count */ + for (u = r->units; u; u = u->next) { + if (u->faction == f && !fval(u->race, RCF_INVISIBLE)) { + for (itm=u->items;itm;itm=itm->next) { + i_change(&items, itm->type, itm->number); + } + number += u->number; + } + } + /* print */ + rnl(F); + m = msg_message("nr_stat_header", "region", r); + nr_render(m, f->locale, buf, sizeof(buf), f); + msg_release(m); + rparagraph(F, buf, 0, 0, 0); + rnl(F); + + /* Region */ + if (skill_enabled[SK_ENTERTAINMENT] && fval(r->terrain, LAND_REGION) && rmoney(r)) { + m = msg_message("nr_stat_maxentertainment", "max", entertainmoney(r)); + nr_render(m, f->locale, buf, sizeof(buf), f); + rparagraph(F, buf, 2, 2, 0); + msg_release(m); + } + if (production(r) && (!fval(r->terrain, SEA_REGION) || f->race == new_race[RC_AQUARIAN])) { + if (markets_module()) { /* hack */ + m = msg_message("nr_stat_salary_new", "max", wage(r, NULL, NULL, turn+1)); + } else { + m = msg_message("nr_stat_salary", "max", wage(r, f, f->race, turn+1)); + } + nr_render(m, f->locale, buf, sizeof(buf), f); + rparagraph(F, buf, 2, 2, 0); + msg_release(m); + } + + if (p) { + m = msg_message("nr_stat_recruits", "max", p / RECRUITFRACTION); + nr_render(m, f->locale, buf, sizeof(buf), f); + rparagraph(F, buf, 2, 2, 0); + msg_release(m); + + if (!markets_module()) { + if (buildingtype_exists(r, bt_find("caravan"), true)) { + m = msg_message("nr_stat_luxuries", "max", + (p * 2) / TRADE_FRACTION); + } else { + m = msg_message("nr_stat_luxuries", "max", + p / TRADE_FRACTION); + } + nr_render(m, f->locale, buf, sizeof(buf), f); + rparagraph(F, buf, 2, 2, 0); + msg_release(m); + } + + if (r->land->ownership) { + m = msg_message("nr_stat_morale", "morale", r->land->morale); + nr_render(m, f->locale, buf, sizeof(buf), f); + rparagraph(F, buf, 2, 2, 0); + msg_release(m); + } + + + } + /* info about units */ + + m = msg_message("nr_stat_people", "max", number); + nr_render(m, f->locale, buf, sizeof(buf), f); + rparagraph(F, buf, 2, 2, 0); + msg_release(m); + + for (itm = items; itm; itm=itm->next) { + sprintf(buf, "%s: %d", + LOC(f->locale, resourcename(itm->type->rtype, GR_PLURAL)), + itm->number); + rparagraph(F, buf, 2, 2, 0); + } + while (items) i_free(i_remove(&items, items)); +} + +static void +durchreisende(FILE * F, const region * r, const faction * f) +{ + if (fval(r, RF_TRAVELUNIT)) { + attrib *abegin = a_find(r->attribs, &at_travelunit), *a; + int counter = 0, maxtravel = 0; + char buf[8192]; + char * bufp = buf; + int bytes; + size_t size = sizeof(buf) - 1; + + /* How many are we listing? For grammar. */ + for (a = abegin; a && a->type==&at_travelunit; a = a->next) { + unit * u = (unit*)a->data.v; + + if (r!=u->region && (u->ship==NULL || fval(u, UFL_OWNER))) { + if (cansee_durchgezogen(f, r, u, 0)) { + ++maxtravel; + } + } + } + + if (maxtravel==0) { + return; + } + + /* Auflisten. */ + rnl(F); + + for (a = abegin; a && a->type==&at_travelunit; a = a->next) { + unit * u = (unit*)a->data.v; + + if (r!=u->region && (u->ship==NULL || fval(u, UFL_OWNER))) { + if (cansee_durchgezogen(f, r, u, 0)) { + ++counter; + if (u->ship != NULL) { + if (counter == 1) { + bytes = (int)strlcpy(bufp, "Die ", size); + } else { + bytes = (int)strlcpy(bufp, "die ", size); + } + if (wrptr(&bufp, &size, bytes)!=0) { + WARN_STATIC_BUFFER(); + break; + } + bytes = (int)strlcpy(bufp, shipname(u->ship), size); + } else { + bytes = (int)strlcpy(bufp, unitname(u), size); + } + if (wrptr(&bufp, &size, bytes)!=0) { + WARN_STATIC_BUFFER(); + break; + } + + if (counter + 1 < maxtravel) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) { + WARN_STATIC_BUFFER(); + break; + } + } else if (counter + 1 == maxtravel) { + bytes = (int)strlcpy(bufp, LOC(f->locale, "list_and"), size); + if (wrptr(&bufp, &size, bytes)!=0) { + WARN_STATIC_BUFFER(); + break; + } + } + } + } + } + /* TODO: finish localization */ + if (maxtravel == 1) { + bytes = (int)strlcpy(bufp, " hat die Region durchquert.", size); + } else { + bytes = (int)strlcpy(bufp, " haben die Region durchquert.", size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + *bufp = 0; + rparagraph(F, buf, 0, 0, 0); + } +} + +static int +buildingmaintenance(const building * b, const resource_type * rtype) +{ + const building_type * bt = b->type; + int c, cost=0; + static boolean init = false; + static const curse_type * nocost_ct; + if (!init) { init = true; nocost_ct = ct_find("nocostbuilding"); } + if (curse_active(get_curse(b->attribs, nocost_ct))) { + return 0; + } + for (c=0;bt->maintenance && bt->maintenance[c].number;++c) { + const maintenance * m = bt->maintenance + c; + if (m->rtype==rtype) { + if (fval(m, MTF_VARIABLE)) + cost += (b->size * m->number); + else + cost += m->number; + } + } + return cost; +} + +static int +report_template(const char * filename, report_context * ctx, const char * charset) +{ + faction * f = ctx->f; + region *r; + FILE * F = fopen(filename, "wt"); + seen_region * sr = NULL; + char buf[8192], * bufp; + size_t size; + int bytes; + + int enc = xmlParseCharEncoding(charset); + + if (F==NULL) { + perror(filename); + return -1; + } + + if (enc==XML_CHAR_ENCODING_UTF8) { + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + fwrite(utf8_bom, 1, 3, F); + } + + rps_nowrap(F, ""); + rnl(F); + rps_nowrap(F, LOC(f->locale, "nr_template")); + rnl(F); + rps_nowrap(F, ""); + rnl(F); + + sprintf(buf, "%s %s \"%s\"", LOC(f->locale, "ERESSEA"), factionid(f), LOC(f->locale, "enterpasswd")); + rps_nowrap(F, buf); + rnl(F); + + rps_nowrap(F, ""); + rnl(F); + sprintf(buf, "; ECHECK -l -w4 -r%d -v%s", f->race->recruitcost, ECHECK_VERSION); + /* -v3.4: ECheck Version 3.4.x */ + rps_nowrap(F, buf); + rnl(F); + + for (r=ctx->first; sr==NULL && r!=ctx->last; r=r->next) { + sr = find_seen(ctx->seen, r); + } + + for (;sr!=NULL;sr=sr->next) { + region * r = sr->r; + unit *u; + int dh = 0; + + if (sr->modeunits; u; u = u->next) { + if (u->faction == f && !fval(u->race, RCF_INVISIBLE)) { + order * ord; + if (!dh) { + plane * pl = getplane(r); + int nx = r->x, ny = r->y; + + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl, r); + rps_nowrap(F, ""); + rnl(F); + if (pl && pl->id != 0) { + sprintf(buf, "%s %d,%d,%d ; %s", LOC(f->locale, parameters[P_REGION]), + nx, ny, pl->id, rname(r, f->locale)); + } else { + sprintf(buf, "%s %d,%d ; %s", LOC(f->locale, parameters[P_REGION]), + nx, ny, rname(r, f->locale)); + } + rps_nowrap(F, buf); + rnl(F); + sprintf(buf,"; ECheck Lohn %d", wage(r, f, f->race, turn+1)); + rps_nowrap(F, buf); + rnl(F); + rps_nowrap(F, ""); + rnl(F); + } + dh = 1; + + bufp = buf; + size = sizeof(buf) - 1; + bytes = snprintf(bufp, size, "%s %s; %s [%d,%d$", + LOC(u->faction->locale, parameters[P_UNIT]), + unitid(u), u->name, u->number, get_money(u)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (u->building != NULL && fval(u, UFL_OWNER)) { + building * b = u->building; + int cost = buildingmaintenance(b, r_silver); + + if (cost > 0) { + bytes = (int)strlcpy(bufp, ",U", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, itoa10(cost), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } else if (u->ship) { + if (fval(u, UFL_OWNER)) { + bytes = (int)strlcpy(bufp, ",S", size); + } else { + bytes = (int)strlcpy(bufp, ",s", size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, shipid(u->ship), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (lifestyle(u) == 0) { + bytes = (int)strlcpy(bufp, ",I", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + bytes = (int)strlcpy(bufp, "]", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + *bufp = 0; + rps_nowrap(F, buf); + rnl(F); + + for (ord = u->old_orders; ord; ord = ord->next) { + /* this new order will replace the old defaults */ + strcpy(buf, " "); + write_order(ord, buf+2, sizeof(buf)-2); + rps_nowrap(F, buf); + rnl(F); + } + for (ord = u->orders; ord; ord = ord->next) { + if (u->old_orders && is_repeated(ord)) continue; /* unit has defaults */ + if (is_persistent(ord)) { + strcpy(buf, " "); + write_order(ord, buf+2, sizeof(buf)-2); + rps_nowrap(F, buf); + rnl(F); + } + } + + /* If the lastorder begins with an @ it should have + * been printed in the loop before. */ + } + } + } + rps_nowrap(F, ""); + rnl(F); + strcpy(buf, LOC(f->locale, parameters[P_NEXT])); + rps_nowrap(F, buf); + rnl(F); + fclose(F); + return 0; +} + +static void +show_allies(const faction * f, const ally * allies, char * buf, size_t size) +{ + int allierte = 0; + int i=0, h, hh = 0; + int bytes, dh = 0; + const ally * sf; + char * bufp = buf; /* buf already contains data */ + + --size; /* leave room for a null-terminator */ + + for (sf = allies; sf; sf = sf->next) { + int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); + if (mode > 0) ++allierte; + } + + for (sf = allies; sf; sf = sf->next) { + int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); + if (mode <= 0) continue; + i++; + if (dh) { + if (i == allierte) { + bytes = (int)strlcpy(bufp, LOC(f->locale, "list_and"), size); + } else { + bytes = (int)strlcpy(bufp, ", ", size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + dh = 1; + hh = 0; + bytes = (int)strlcpy(bufp, factionname(sf->faction), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " (", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if ((mode & HELP_ALL) == HELP_ALL) { + bytes = (int)strlcpy(bufp, "Alles", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else { + for (h = 1; h < HELP_ALL; h *= 2) { + int p = MAXPARAMS; + if ((mode & h) == h) { + switch (h) { + case HELP_TRAVEL: + p = P_TRAVEL; + break; + case HELP_MONEY: + p = P_MONEY; + break; + case HELP_FIGHT: + p = P_FIGHT; + break; + case HELP_GIVE: + p = P_GIVE; + break; + case HELP_GUARD: + p = P_GUARD; + break; + case HELP_FSTEALTH: + p = P_FACTIONSTEALTH; + break; + } + } + if (p!=MAXPARAMS) { + if (hh) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + bytes = (int)strlcpy(bufp, parameters[p], size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + hh = 1; + } + } + } + bytes = (int)strlcpy(bufp, ")", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + *bufp = 0; +} + +static void +allies(FILE * F, const faction * f) +{ + const group * g = f->groups; + char buf[16384]; + + if (f->allies) { + int bytes; + size_t size = sizeof(buf); + if (!f->allies->next) { + bytes = (int)strlcpy(buf, "Wir helfen der Partei ", size); + } else { + bytes = (int)strlcpy(buf, "Wir helfen den Parteien ", size); + } + size -= bytes; + show_allies(f, f->allies, buf + bytes, size); + rparagraph(F, buf, 0, 0, 0); + rnl(F); + } + + while (g) { + if (g->allies) { + int bytes; + size_t size = sizeof(buf); + if (!g->allies->next) { + bytes = snprintf(buf, size, "%s hilft der Partei ", g->name); + } else { + bytes = snprintf(buf, size, "%s hilft den Parteien ", g->name); + } + size -= bytes; + show_allies(f, g->allies, buf + bytes, size); + rparagraph(F, buf, 0, 0, 0); + rnl(F); + } + g = g->next; + } +} + +static void +guards(FILE * F, const region * r, const faction * see) +{ + /* die Partei see sieht dies; wegen + * "unbekannte Partei", wenn man es selbst ist... */ + + faction* guardians[512]; + + int nextguard = 0; + + unit *u; + int i; + + boolean tarned = false; + /* Bewachung */ + + for (u = r->units; u; u = u->next) { + if (is_guard(u, GUARD_ALL)!=0) { + faction *f = u->faction; + faction *fv = visible_faction(see, u); + + if(fv != f && see != fv) { + f = fv; + } + + if (f != see && fval(u, UFL_ANON_FACTION)) { + tarned=true; + } else { + for (i=0;i!=nextguard;++i) if (guardians[i]==f) break; + if (i==nextguard) { + guardians[nextguard++] = f; + } + } + } + } + + if (nextguard || tarned) { + char buf[8192]; + char * bufp = buf; + size_t size = sizeof(buf) - 1; + int bytes; + + bytes = (int)strlcpy(bufp, "Die Region wird von ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + for (i = 0; i!=nextguard+(tarned?1:0); ++i) { + if (i!=0) { + if (i == nextguard-(tarned?0:1)) { + bytes = (int)strlcpy(bufp, LOC(see->locale, "list_and"), size); + } else { + bytes = (int)strlcpy(bufp, ", ", size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (ilocale, "nr_addresses"), false); + rnl(F); + + while (flist!=NULL) { + const faction * f = flist->data; + if (!is_monsters(f)) { + char buf[8192]; + char label = '-'; + + sprintf(buf, "%s: %s; %s", factionname(f), f->email, f->banner?f->banner:""); + if (uf==f) label = '*'; + else if (ALLIED(uf, f)) label = 'o'; + else if (alliedfaction(NULL, uf, f, HELP_ALL)) label = '+'; + rparagraph(F, buf, 4, 0, label); + + } + flist = flist->next; + } + rnl(F); + rpline(F); +} + +static void +nr_ship(FILE * F, const seen_region * sr, const ship * sh, const faction * f, const unit * captain) +{ + const region * r = sr->r; + char buffer[8192], * bufp = buffer; + size_t size = sizeof(buffer) - 1; + int bytes; + char ch; + + rnl(F); + + if (captain && captain->faction == f) { + int n = 0, p = 0; + getshipweight(sh, &n, &p); + n = (n+99) / 100; /* 1 Silber = 1 GE */ + + bytes = snprintf(bufp, size, "%s, %s, (%d/%d)", shipname(sh), + LOC(f->locale, sh->type->name[0]), n, shipcapacity(sh) / 100); + } else { + bytes = snprintf(bufp, size, "%s, %s", shipname(sh), LOC(f->locale, sh->type->name[0])); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + assert(sh->type->construction->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (sh->size!=sh->type->construction->maxsize) { + bytes = snprintf(bufp, size, ", %s (%d/%d)", + LOC(f->locale, "nr_undercons"), sh->size, + sh->type->construction->maxsize); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (sh->damage) { + int percent = (sh->damage*100+DAMAGE_SCALE-1)/(sh->size*DAMAGE_SCALE); + bytes = snprintf(bufp, size, ", %d%% %s", percent, LOC(f->locale, "nr_damaged")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (!fval(r->terrain, SEA_REGION)) { + if (sh->coast != NODIRECTION) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, coasts[sh->coast]), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + ch = 0; + if (sh->display && sh->display[0]) { + bytes = (int)strlcpy(bufp, "; ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, sh->display, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + ch = sh->display[strlen(sh->display) - 1]; + } + if (ch != '!' && ch != '?' && ch != '.') { + bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + *bufp = 0; + rparagraph(F, buffer, 2, 0, 0); + + nr_curses(F, f, sh, TYP_SHIP, 4); +} + +static void +nr_building(FILE *F, const seen_region * sr, const building * b, const faction * f) +{ + int i, bytes; + const char * name, * bname, * billusion = NULL; + const struct locale * lang = NULL; + char buffer[8192], * bufp = buffer; + size_t size = sizeof(buffer) - 1; + + rnl(F); + + if (f) lang = f->locale; + + bytes = snprintf(bufp, size, "%s, %s %d, ", buildingname(b), LOC(f->locale, "nr_size"), b->size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + report_building(b, &bname, &billusion); + name = LOC(lang, billusion?billusion:bname); + bytes = (int)strlcpy(bufp, name, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (billusion) { + unit * owner = building_owner(b); + if (owner && owner->faction==f) { + /* illusion. report real type */ + name = LOC(lang, bname); + bytes = snprintf(bufp, size, " (%s)", name); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + + if (b->size < b->type->maxsize) { + bytes = (int)strlcpy(bufp, " (im Bau)", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + if (b->besieged > 0 && sr->mode>=see_lighthouse) { + bytes = (int)strlcpy(bufp, ", belagert von ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, itoa10(b->besieged), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " Personen ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (b->besieged >= b->size * SIEGEFACTOR) { + bytes = (int)strlcpy(bufp, "(abgeschnitten)", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + i = 0; + if (b->display && b->display[0]) { + bytes = (int)strlcpy(bufp, "; ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, b->display, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + i = b->display[strlen(b->display) - 1]; + } + +#ifdef WDW_PYRAMID + + if (i != '!' && i != '?' && i != '.') { + scat(", "); + } + + if (b->type == bt_find("pyramid")) { + unit * owner = building_owner(b); + scat("Größenstufe "); + icat(wdw_pyramid_level(b)); + scat("."); + + if (owner && owner->faction==f) { + const construction *ctype = b->type->construction; + int completed = b->size; + int c; + + scat(" Baukosten pro Größenpunkt: "); + + while(ctype->improvement != NULL && + ctype->improvement != ctype && + ctype->maxsize > 0 && + ctype->maxsize <= completed) + { + completed -= ctype->maxsize; + ctype = ctype->improvement; + } + + assert(ctype->materials != NULL); + + for (c=0;ctype->materials[c].number;c++) { + const resource_type * rtype = ctype->materials[c].rtype; + int number = ctype->materials[c].number; + + if(c > 0) { + scat(", "); + } + icat(number); + scat(" "); + scat(locale_string(lang, resourcename(rtype, number!=1?GR_PLURAL:0))); + } + + scat("."); + + scat(" Erforderlicher Talentwert: "); + icat(b->type->construction->minskill); + scat("."); + } + } + +#else + + if (i != '!' && i != '?' && i != '.') { + bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + +#endif + *bufp = 0; + rparagraph(F, buffer, 2, 0, 0); + + if (sr->modelocale, bufp, size, f); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + msg_release(m); + + rparagraph(F, buf, 0, 0, 0); +} + +int +report_plaintext(const char * filename, report_context * ctx, const char * charset) +{ + int flag = 0; + char ch; + int anyunits, no_units, no_people; + const struct region *r; + faction * f = ctx->f; + unit *u; + char pzTime[64]; + attrib *a; + message * m; + unsigned char op; + int bytes, ix = want(O_STATISTICS); + int wants_stats = (f->options & ix); + FILE * F = fopen(filename, "wt"); + seen_region * sr = NULL; + char buf[8192]; + char * bufp; + int enc = xmlParseCharEncoding(charset); + size_t size; + + /* static variables can cope with writing for different turns */ + static int thisseason = -1; + static int nextseason = -1; + static int gamecookie = -1; + if (gamecookie!=global.cookie) { + gamedate date; + get_gamedate(turn+1, &date); + thisseason = date.season; + get_gamedate(turn+2, &date); + nextseason = date.season; + gamecookie = global.cookie; + } + + if (F==NULL) { + perror(filename); + return -1; + } + if (enc==XML_CHAR_ENCODING_UTF8) { + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + fwrite(utf8_bom, 1, 3, F); + } + + strftime(pzTime, 64, "%A, %d. %B %Y, %H:%M", localtime(&ctx->report_time)); + m = msg_message("nr_header_date", "game date", global.gamename, pzTime); + nr_render(m, f->locale, buf, sizeof(buf), f); + msg_release(m); + centre(F, buf, true); + + centre(F, gamedate_season(f->locale), true); + rnl(F); + sprintf(buf, "%s, %s/%s (%s)", factionname(f), + LOC(f->locale, rc_name(f->race, 1)), + LOC(f->locale, mkname("school", magic_school[f->magiegebiet])), + f->email); + centre(F, buf, true); + if (f_get_alliance(f)) { + centre(F, alliancename(f->alliance), true); + } + + if (f->age <= 2) { + const char * s; + if (f->age <= 1) { + ADDMSG(&f->msgs, msg_message("changepasswd", + "value", f->passw)); + } + RENDER(f, buf, sizeof(buf), ("newbie_password", "password", f->passw)); + rnl(F); + centre(F, buf, true); + s = locale_getstring(f->locale, "newbie_info_1"); + if (s) { + rnl(F); + centre(F, s, true); + } + s = locale_getstring(f->locale, "newbie_info_2"); + if (s) { + rnl(F); + centre(F, s, true); + } + if ((f->options & want(O_COMPUTER)) == 0) { + f->options |= want(O_COMPUTER); + s = locale_getstring(f->locale, "newbie_info_3"); + if (s) { + rnl(F); + centre(F, s, true); + } + } + } + rnl(F); +#if SCORE_MODULE + if (f->options & want(O_SCORE) && f->age > DISPLAYSCORE) { + RENDER(f, buf, sizeof(buf), ("nr_score", "score average", f->score, average_score_of_age(f->age, f->age / 24 + 1))); + centre(F, buf, true); + } +#endif +#ifdef COUNT_AGAIN + no_units = 0; + no_people = 0; + for (u=f->units;u;u=u->nextF) { + if (playerrace(u->race)) { + ++no_people; + no_units += u->number; + assert(f==u->faction); + } + } + if (no_units!=f->no_units) { + f->no_units = no_units; + } + if (no_people!=f->num_people) { + f->num_people = no_people; + } +#else + no_units = f->no_units; + no_people = f->num_people; +#endif + m = msg_message("nr_population", "population units", no_people, no_units); + nr_render(m, f->locale, buf, sizeof(buf), f); + msg_release(m); + centre(F, buf, true); + if (f->race == new_race[RC_HUMAN]) { + int maxmig = count_maxmigrants(f); + if (maxmig>0) { + m = msg_message("nr_migrants", "units maxunits", count_migrants(f), maxmig); + nr_render(m, f->locale, buf, sizeof(buf), f); + msg_release(m); + centre(F, buf, true); + } + } + if (f_get_alliance(f)) { + m = msg_message("nr_alliance", "leader name id age", alliance_get_leader(f->alliance), f->alliance->name, f->alliance->id, turn-f->alliance_joindate); + nr_render(m, f->locale, buf, sizeof(buf), f); + msg_release(m); + centre(F, buf, true); + } + { + int maxh = maxheroes(f); + if (maxh) { + message * msg = msg_message("nr_heroes", "units maxunits", countheroes(f), maxh); + nr_render(msg, f->locale, buf, sizeof(buf), f); + msg_release(msg); + centre(F, buf, true); + } + } + + if (f->items!=NULL) { + message * msg = msg_message("nr_claims", "items", f->items); + nr_render(msg, f->locale, buf, sizeof(buf), f); + msg_release(msg); + rnl(F); + centre(F, buf, true); + } + + /* Insekten-Winter-Warnung */ + if (f->race == new_race[RC_INSECT]) { + if (thisseason == 0) { + centre(F, LOC(f->locale, "nr_insectwinter"), true); + rnl(F); + } else { + if (nextseason == 0) { + centre(F, LOC(f->locale, "nr_insectfall"), true); + rnl(F); + } + } + } + + bufp = buf; + size = sizeof(buf) - 1; + bytes = snprintf(buf, size,"%s:", LOC(f->locale, "nr_options")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + for (op = 0; op != MAXOPTIONS; op++) { + if (f->options & want(op) && options[op]) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, options[op]), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + flag++; + } + } + if (flag > 0) { + rnl(F); + *bufp = 0; + centre(F, buf, true); + } + + rp_messages(F, f->msgs, f, 0, true); + rp_battles(F, f); + a = a_find(f->attribs, &at_reportspell); + if (a) { + rnl(F); + centre(F, LOC(f->locale, "section_newspells"), true); + while (a && a->type==&at_reportspell) { + spell *sp = (spell *)a->data.v; + nr_spell(F, sp, f->locale); + a = a->next; + } + } + + ch = 0; + for (a=a_find(f->attribs, &at_showitem);a && a->type==&at_showitem;a=a->next) { + const potion_type * ptype = resource2potion(((const item_type*)a->data.v)->rtype); + const char * description = NULL; + if (ptype!=NULL) { + const char * pname = resourcename(ptype->itype->rtype, 0); + + if (ch==0) { + rnl(F); + centre(F, LOC(f->locale, "section_newpotions"), true); + ch = 1; + } + + rnl(F); + centre(F, LOC(f->locale, pname), true); + snprintf(buf, sizeof(buf), "%s %d", LOC(f->locale, "nr_level"), ptype->level); + centre(F, buf, true); + rnl(F); + + bufp = buf; + size = sizeof(buf) - 1; + bytes = snprintf(bufp, size, "%s: ", LOC(f->locale, "nr_herbsrequired")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (ptype->itype->construction) { + requirement * m = ptype->itype->construction->materials; + while (m->number) { + bytes = (int)strlcpy(bufp, LOC(f->locale, resourcename(m->rtype, 0)), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + ++m; + if (m->number) + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + *bufp = 0; + centre(F, buf, true); + rnl(F); + if (description==NULL) { + const char * potiontext = mkname("potion", pname); + description = LOC(f->locale, potiontext); + } + centre(F, description, true); + } + } + rnl(F); + centre(F, LOC(f->locale, "nr_alliances"), false); + rnl(F); + + allies(F, f); + + rpline(F); + + anyunits = 0; + + for (r=ctx->first;sr==NULL && r!=ctx->last;r=r->next) { + sr = find_seen(ctx->seen, r); + } + for (;sr!=NULL;sr=sr->next) { + region * r = sr->r; + int stealthmod = stealth_modifier(sr->mode); + building * b = r->buildings; + ship * sh = r->ships; + + if (sr->modemode==see_unit) { + anyunits = 1; + describe(F, sr, f); + if (markets_module() && r->land) { + const item_type * lux = r_luxury(r); + const item_type * herb = r->land->herbtype; + message * m = 0; + if (herb && lux) { + m = msg_message("nr_market_info_p", "p1 p2", + lux?lux->rtype:0, herb?herb->rtype:0); + } else if (lux || herb) { + m = msg_message("nr_market_info_s", "p1", + lux?lux->rtype:herb->rtype); + } + if (m) { + rnl(F); + nr_paragraph(F, m, f); + } + // + } else { + if (!fval(r->terrain, SEA_REGION) && rpeasants(r)/TRADE_FRACTION > 0) { + rnl(F); + prices(F, r, f); + } + } + guards(F, r, f); + durchreisende(F, r, f); + } + else { + if (sr->mode==see_far) { + describe(F, sr, f); + guards(F, r, f); + durchreisende(F, r, f); + } + else if (sr->mode==see_lighthouse) { + describe(F, sr, f); + durchreisende(F, r, f); + } else { + describe(F, sr, f); + durchreisende(F, r, f); + } + } + /* Statistik */ + + if (wants_stats && sr->mode==see_unit) + statistics(F, r, f); + + /* Nachrichten an REGION in der Region */ + + if (sr->mode==see_unit || sr->mode==see_travel) { + message_list * mlist = r_getmessages(r, f); + rp_messages(F, r->msgs, f, 0, true); + if (mlist) rp_messages(F, mlist, f, 0, true); + } + + /* report all units. they are pre-sorted in an efficient manner */ + u = r->units; + while (b) { + while (b && (!u || u->building!=b)) { + nr_building(F, sr, b, f); + b = b->next; + } + if (b) { + nr_building(F, sr, b, f); + while (u && u->building==b) { + nr_unit(F, f, u, 6, sr->mode); + u = u->next; + } + b = b->next; + } + } + while (u && !u->ship) { + if (stealthmod>INT_MIN) { + if (u->faction == f || cansee(f, r, u, stealthmod)) { + nr_unit(F, f, u, 4, sr->mode); + } + } + assert(!u->building); + u = u->next; + } + while (sh) { + while (sh && (!u || u->ship!=sh)) { + nr_ship(F, sr, sh, f, NULL); + sh = sh->next; + } + if (sh) { + nr_ship(F, sr, sh, f, u); + while (u && u->ship==sh) { + nr_unit(F, f, u, 6, sr->mode); + u = u->next; + } + sh = sh->next; + } + } + + assert(!u); + + rnl(F); + rpline(F); + } + if (!is_monsters(f)) { + if (!anyunits) { + rnl(F); + rparagraph(F, LOC(f->locale, "nr_youaredead"), 0, 2, 0); + } else { + list_address(F, f, ctx->addresses); + } + } + fclose(F); + return 0; +} + +void +base36conversion(void) +{ + region * r; + for (r=regions;r;r=r->next) { + unit * u; + for (u=r->units;u;u=u->next) { + if (forbiddenid(u->no)) { + uunhash(u); + u->no = newunitid(); + uhash(u); + } + } + } +} + +#define FMAXHASH 1021 + +struct fsee { + struct fsee * nexthash; + faction * f; + struct see { + struct see * next; + faction * seen; + unit * proof; + } * see; +} * fsee[FMAXHASH]; + +#define REPORT_NR (1 << O_REPORT) +#define REPORT_CR (1 << O_COMPUTER) +#define REPORT_ZV (1 << O_ZUGVORLAGE) +#define REPORT_ZIP (1 << O_COMPRESS) +#define REPORT_BZIP2 (1 << O_BZIP2) + + +unit * +can_find(faction * f, faction * f2) +{ + int key = f->no % FMAXHASH; + struct fsee * fs = fsee[key]; + struct see * ss; + if (f==f2) return f->units; + while (fs && fs->f!=f) fs=fs->nexthash; + if (!fs) return NULL; + ss=fs->see; + while (ss && ss->seen!=f2) ss=ss->next; + if (ss) { + /* bei TARNE PARTEI yxz muss die Partei von unit proof nicht + * wirklich Partei f2 sein! */ + /* assert(ss->proof->faction==f2); */ + return ss->proof; + } + return NULL; +} + +static void +add_find(faction * f, unit * u, faction *f2) +{ + /* faction f sees f2 through u */ + int key = f->no % FMAXHASH; + struct fsee ** fp = &fsee[key]; + struct fsee * fs; + struct see ** sp; + struct see * ss; + while (*fp && (*fp)->f!=f) fp=&(*fp)->nexthash; + if (!*fp) { + fs = *fp = calloc(sizeof(struct fsee), 1); + fs->f = f; + } else fs = *fp; + sp = &fs->see; + while (*sp && (*sp)->seen!=f2) sp=&(*sp)->next; + if (!*sp) { + ss = *sp = calloc(sizeof(struct see), 1); + ss->proof = u; + ss->seen = f2; + } else ss = *sp; + ss->proof = u; +} + +static void +update_find(void) +{ + region * r; + static boolean initial = true; + + if (initial) for (r=regions;r;r=r->next) { + unit * u; + for (u=r->units;u;u=u->next) { + faction * lastf = u->faction; + unit * u2; + for (u2=r->units;u2;u2=u2->next) { + if (u2->faction==lastf || u2->faction==u->faction) + continue; + if (seefaction(u->faction, r, u2, 0)) { + faction *fv = visible_faction(u->faction, u2); + lastf = fv; + add_find(u->faction, u2, fv); + } + } + } + } + initial = false; +} + +boolean +kann_finden(faction * f1, faction * f2) +{ + update_find(); + return (boolean)(can_find(f1, f2)!=NULL); +} + +/******* end summary ******/ + +void +register_nr(void) +{ + if (!nocr) register_reporttype("nr", &report_plaintext, 1<nexthash; + free(fsee[i]); + fsee[i] = fs; + } + } +} + diff --git a/src/gamecode/report.h b/src/gamecode/report.h new file mode 100644 index 000000000..e294adf6d --- /dev/null +++ b/src/gamecode/report.h @@ -0,0 +1,25 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#ifndef H_GC_REPORT +#define H_GC_REPORT +#ifdef __cplusplus +extern "C" { +#endif + + extern void register_nr(void); + extern void report_cleanup(void); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/gamecode/spy.c b/src/gamecode/spy.c new file mode 100644 index 000000000..fe665bda8 --- /dev/null +++ b/src/gamecode/spy.c @@ -0,0 +1,482 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "spy.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* attributes includes */ +#include + +/* util includes */ +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +#include + +/* in spy steht der Unterschied zwischen Wahrnehmung des Opfers und +* Spionage des Spions */ +void +spy_message(int spy, const unit *u, const unit *target) +{ + const char * str = report_kampfstatus(target, u->faction->locale); + + ADDMSG(&u->faction->msgs, msg_message("spyreport", "spy target status", u, target, str)); + if (spy > 20) { + sc_mage * mage = get_mage(target); + /* bei Magiern Zaubersprüche und Magiegebiet */ + if (mage) { + ADDMSG(&u->faction->msgs, msg_message("spyreport_mage", "target type", target, magic_school[mage->magietyp])); + } + } + if (spy > 6) { + faction * fv = visible_faction(u->faction,target); + if (fv && fv!=target->faction) { + /* wahre Partei */ + ADDMSG(&u->faction->msgs, msg_message("spyreport_faction", "target faction", target, target->faction)); + } + } + if (spy > 0) { + int first = 1; + int found = 0; + skill * sv; + char buf[4096]; + + buf[0] = 0; + for (sv = target->skills;sv!=target->skills+target->skill_size;++sv) { + if (sv->level>0) { + found++; + if (first == 1) { + first = 0; + } else { + strncat(buf, ", ", sizeof(buf)); + } + strncat(buf, (const char *)skillname(sv->id, u->faction->locale), sizeof(buf)); + strncat(buf, " ", sizeof(buf)); + strncat(buf, itoa10(eff_skill(target, sv->id, target->region)), sizeof(buf)); + } + } + if (found) { + ADDMSG(&u->faction->msgs, msg_message("spyreport_skills", "target skills", target, buf)); + } + + if (target->items) { + ADDMSG(&u->faction->msgs, msg_message("spyreport_items", "target items", target, target->items)); + } + } +} + + +int +spy_cmd(unit * u, struct order * ord) +{ + unit *target; + int spy, observe; + double spychance, observechance; + region * r = u->region; + + init_tokens(ord); + skip_token(); + target = getunit(r, u->faction); + + if (!target) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); + return 0; + } + if (!can_contact(r, u, target)) { + cmistake(u, u->thisorder, 24, MSG_EVENT); + return 0; + } + if (eff_skill(u, SK_SPY, r) < 1) { + cmistake(u, u->thisorder, 39, MSG_EVENT); + return 0; + } + /* Die Grundchance für einen erfolgreichen Spionage-Versuch ist 10%. + * Für jeden Talentpunkt, den das Spionagetalent das Tarnungstalent + * des Opfers übersteigt, erhöht sich dieses um 5%*/ + spy = eff_skill(u, SK_SPY, r) - eff_skill(target, SK_STEALTH, r); + spychance = 0.1 + MAX(spy*0.05, 0.0); + + if (chance(spychance)) { + produceexp(u, SK_SPY, u->number); + spy_message(spy, u, target); + } else { + ADDMSG(&u->faction->msgs, msg_message("spyfail", "spy target", u, target)); + } + + /* der Spion kann identifiziert werden, wenn das Opfer bessere + * Wahrnehmung als das Ziel Tarnung + Spionage/2 hat */ + observe = eff_skill(target, SK_PERCEPTION, r) + - (effskill(u, SK_STEALTH) + eff_skill(u, SK_SPY, r)/2); + + if (invisible(u, target) >= u->number) { + observe = MIN(observe, 0); + } + + /* Anschließend wird - unabhängig vom Erfolg - gewürfelt, ob der + * Spionageversuch bemerkt wurde. Die Wahrscheinlich dafür ist (100 - + * SpionageSpion*5 + WahrnehmungOpfer*2)%. */ + observechance = 1.0 - (eff_skill(u, SK_SPY, r) * 0.05) + + (eff_skill(target, SK_PERCEPTION, r) * 0.02); + + if (chance(observechance)) { + ADDMSG(&target->faction->msgs, msg_message("spydetect", + "spy target", observe>0?u:NULL, target)); + } + return 0; +} + +void +set_factionstealth(unit * u, faction * f) +{ + region * lastr = NULL; + /* for all units mu of our faction, check all the units in the region + * they are in, if their visible faction is f, it's ok. use lastr to + * avoid testing the same region twice in a row. */ + unit * mu = u->faction->units; + while (mu!=NULL) { + if (mu->number && mu->region!=lastr) { + unit * ru = mu->region->units; + lastr = mu->region; + while (ru!=NULL) { + if (ru->number) { + faction * fv = visible_faction(f, ru); + if (fv==f) { + if (cansee(f, lastr, ru, 0)) break; + } + } + ru = ru->next; + } + if (ru!=NULL) break; + } + mu = mu->nextF; + } + if (mu!=NULL) { + attrib * a = a_find(u->attribs, &at_otherfaction); + if (!a) a = a_add(&u->attribs, make_otherfaction(f)); + else a->data.v = f; + } +} + +int +setstealth_cmd(unit * u, struct order * ord) +{ + const char *s; + int level; + const race * trace; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + /* Tarne ohne Parameter: Setzt maximale Tarnung */ + + if (s == NULL || *s == 0) { + u_seteffstealth(u, -1); + return 0; + } + + trace = findrace(s, u->faction->locale); + if (trace) { + /* Dämonen können sich nur als andere Spielerrassen tarnen */ + if (u->race == new_race[RC_DAEMON]) { + race_t allowed[] = { RC_DWARF, RC_ELF, RC_ORC, RC_GOBLIN, RC_HUMAN, + RC_TROLL, RC_DAEMON, RC_INSECT, RC_HALFLING, RC_CAT, RC_AQUARIAN, + NORACE }; + int i; + for (i=0;allowed[i]!=NORACE;++i) if (new_race[allowed[i]]==trace) break; + if (new_race[allowed[i]]==trace) { + u->irace = trace; + if (u->race->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs)) + set_racename(&u->attribs, NULL); + } + return 0; + } + + /* Singdrachen können sich nur als Drachen tarnen */ + if (u->race == new_race[RC_SONGDRAGON] || u->race == new_race[RC_BIRTHDAYDRAGON]) { + if (trace==new_race[RC_SONGDRAGON]||trace==new_race[RC_FIREDRAGON]||trace==new_race[RC_DRAGON]||trace==new_race[RC_WYRM]) { + u->irace = trace; + if (u->race->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs)) + set_racename(&u->attribs, NULL); + } + return 0; + } + + /* Dämomen und Illusionsparteien können sich als andere race tarnen */ + if (u->race->flags & RCF_SHAPESHIFT) { + if (playerrace(trace)) { + u->irace = trace; + if ((u->race->flags & RCF_SHAPESHIFTANY) && get_racename(u->attribs)) + set_racename(&u->attribs, NULL); + } + } + return 0; + } + + switch(findparam(s, u->faction->locale)) { + case P_FACTION: + /* TARNE PARTEI [NICHT|NUMMER abcd] */ + if (!rule_stealth_faction()) break; + s = getstrtoken(); + if(!s || *s == 0) { + fset(u, UFL_ANON_FACTION); + } else if (findparam(s, u->faction->locale) == P_NOT) { + freset(u, UFL_ANON_FACTION); + } else if (findkeyword(s, u->faction->locale) == K_NUMBER) { + const char *s2 = (const char *)getstrtoken(); + int nr = -1; + + if (s2) nr = atoi36(s2); + if (!s2 || *s2 == 0 || nr == u->faction->no) { + a_removeall(&u->attribs, &at_otherfaction); + } else { + struct faction * f = findfaction(nr); + if (f==NULL) { + cmistake(u, ord, 66, MSG_EVENT); + } else { + set_factionstealth(u, f); + } + } + } else { + cmistake(u, ord, 289, MSG_EVENT); + } + break; + case P_ANY: + /* TARNE ALLES (was nicht so alles geht?) */ + u_seteffstealth(u, -1); + break; + case P_NOT: + u_seteffstealth(u, -1); + break; + default: + if (isdigit(s[0])) { + /* Tarnungslevel setzen */ + level = atoi((const char *)s); + if (level > effskill(u, SK_STEALTH)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_lowstealth", "")); + return 0; + } + u_seteffstealth(u, level); + } else if (u->race->flags & RCF_SHAPESHIFTANY) { + set_racename(&u->attribs, s); + } + } + return 0; +} + +static int +crew_skill(region * r, faction * f, ship * sh, skill_t sk) +{ + int value = 0; + unit *u; + + for (u=r->units;u;u=u->next) { + if (u->ship == sh && u->faction == f) { + int s = eff_skill(u, sk, r); + value = MAX(s, value); + } + } + return value; +} + +static int +try_destruction(unit * u, unit * u2, const ship *sh, int skilldiff) +{ + const char *destruction_success_msg = "destroy_ship_0"; + const char *destruction_failed_msg = "destroy_ship_1"; + const char *destruction_detected_msg = "destroy_ship_2"; + const char *detect_failure_msg = "destroy_ship_3"; + const char *object_destroyed_msg = "destroy_ship_4"; + + if (skilldiff == 0) { + /* tell the unit that the attempt failed: */ + ADDMSG(&u->faction->msgs, msg_message(destruction_failed_msg, "ship unit", sh, u)); + /* tell the enemy about the attempt: */ + if (u2) { + ADDMSG(&u2->faction->msgs, msg_message(detect_failure_msg, "ship", sh)); + } + return 0; + } else if (skilldiff < 0) { + /* tell the unit that the attempt was detected: */ + ADDMSG(&u2->faction->msgs, msg_message(destruction_detected_msg, "ship unit", sh, u)); + /* tell the enemy whodunit: */ + if (u2) { + ADDMSG(&u2->faction->msgs, msg_message(detect_failure_msg, "ship", sh)); + } + return 0; + } else { + /* tell the unit that the attempt succeeded */ + ADDMSG(&u->faction->msgs, msg_message(destruction_success_msg, "ship unit", sh, u)); + if (u2) { + ADDMSG(&u2->faction->msgs, msg_message(object_destroyed_msg, "ship", sh)); + } + } + return 1; /* success */ +} + +static void +sink_ship(region * r, ship * sh, const char *name, unit * saboteur) +{ + unit **ui, *u; + region *safety = r; + int i; + direction_t d; + double probability = 0.0; + message * sink_msg = NULL; + faction * f; + + for (f=NULL,u=r->units;u;u=u->next) { + /* slight optimization to avoid dereferencing u->faction each time */ + if (f!=u->faction) { + f = u->faction; + freset(f, FFL_SELECT); + } + } + + /* figure out what a unit's chances of survival are: */ + if (!fval(r->terrain, SEA_REGION)) { + probability = CANAL_SWIMMER_CHANCE; + } else { + for (d = 0; d != MAXDIRECTIONS; ++d) { + region * rn = rconnect(r, d); + if (!fval(rn->terrain, SEA_REGION) && !move_blocked(NULL, r, rn)) { + safety = rn; + probability = OCEAN_SWIMMER_CHANCE; + break; + } + } + } + for (ui = &r->units; *ui; ui = &(*ui)->next) { + unit *u = *ui; + + /* inform this faction about the sinking ship: */ + if (!fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + if (sink_msg==NULL) { + sink_msg = msg_message("sink_msg", "ship region", sh, r); + } + add_message(&f->msgs, sink_msg); + } + + if (u->ship == sh) { + int dead = 0; + message * msg; + + /* if this fails, I misunderstood something: */ + for (i = 0; i != u->number; ++i) + if (chance(probability)) + ++dead; + + if (dead != u->number) { + /* she will live. but her items get stripped */ + if (dead > 0) { + msg = msg_message("sink_lost_msg", "dead region unit", dead, safety, u); + } else { + msg = msg_message("sink_saved_msg", "region unit", safety, u); + } + set_leftship(u, u->ship); + u->ship = 0; + if (r != safety) { + setguard(u, GUARD_NONE); + } + while (u->items) { + i_remove(&u->items, u->items); + } + move_unit(u, safety, NULL); + } else { + msg = msg_message("sink_lost_msg", "dead region unit", dead, NULL, u); + } + add_message(&u->faction->msgs, msg); + msg_release(msg); + if (dead == u->number) { + /* the poor creature, she dies */ + if (remove_unit(ui, u)!=0) { + ui = &u->next; + } + } + } + } + if (sink_msg) msg_release(sink_msg); + /* finally, get rid of the ship */ + remove_ship(&sh->region->ships, sh); +} + +int +sabotage_cmd(unit * u, struct order * ord) +{ + const char *s; + int i; + ship *sh; + unit *u2; + char buffer[DISPLAYSIZE]; + region * r = u->region; + int skdiff; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + i = findparam(s, u->faction->locale); + + switch (i) { + case P_SHIP: + sh = u->ship; + if (!sh) { + cmistake(u, u->thisorder, 144, MSG_EVENT); + return 0; + } + u2 = shipowner(sh); + skdiff = eff_skill(u, SK_SPY, r)-crew_skill(r, u2->faction, sh, SK_PERCEPTION); + if (try_destruction(u, u2, sh, skdiff)) { + sink_ship(r, sh, buffer, u); + } + break; + default: + cmistake(u, u->thisorder, 9, MSG_EVENT); + return 0; + } + + return 0; +} + diff --git a/src/gamecode/spy.h b/src/gamecode/spy.h new file mode 100644 index 000000000..6c56eaa53 --- /dev/null +++ b/src/gamecode/spy.h @@ -0,0 +1,40 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_SPY +#define H_KRNL_SPY +#ifdef __cplusplus +extern "C" { +#endif + +struct unit; +struct region; +struct strlist; + +extern int setstealth_cmd(struct unit * u, struct order * ord); +extern int spy_cmd(struct unit * u, struct order * ord); +extern int sabotage_cmd(struct unit * u, struct order * ord); +extern void spy_message(int spy, const struct unit *u, const struct unit *target); + +#define OCEAN_SWIMMER_CHANCE 0.1 +#define CANAL_SWIMMER_CHANCE 0.9 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/study.c b/src/gamecode/study.c new file mode 100644 index 000000000..32911c286 --- /dev/null +++ b/src/gamecode/study.c @@ -0,0 +1,793 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#define TEACH_ALL 1 +#define TEACH_FRIENDS + +#include +#include +#include "study.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include + +#define TEACHNUMBER 10 + +static skill_t +getskill(const struct locale * lang) +{ + return findskill(getstrtoken(), lang); +} + +magic_t +getmagicskill(const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_MAGIC); + variant token; + const char * s = getstrtoken(); + + if (s && s[0]) { + if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { + return (magic_t)token.i; + } else { + char buffer[3]; + buffer[0] = s[0]; + buffer[1] = s[1]; + buffer[2] = '\0'; + if (findtoken(tokens, buffer, &token)==E_TOK_SUCCESS) { + return (magic_t)token.i; + } + } + } + return M_NONE; +} + +/* ------------------------------------------------------------- */ +/* Vertraute und Kröten sind keine Migranten */ +boolean +is_migrant(unit *u) +{ + if (u->race == u->faction->race) return false; + + if (fval(u->race, RCF_UNDEAD|RCF_ILLUSIONARY)) return false; + if (is_familiar(u)) return false; + if (u->race == new_race[RC_TOAD]) return false; + + return true; +} + +/* ------------------------------------------------------------- */ +boolean +magic_lowskill(unit *u) +{ + if (u->race == new_race[RC_TOAD]) return true; + return false; +} + +/* ------------------------------------------------------------- */ + +int +study_cost(unit *u, skill_t sk) +{ + static int cost[MAXSKILLS]; + int stufe, k = 50; + + if (cost[sk]==0) { + char buffer[256]; + sprintf(buffer, "skills.cost.%s", skillnames[sk]); + cost[sk] = get_param_int(global.parameters, buffer, -1); + } + if (cost[sk]>=0) return cost[sk]; + + switch (sk) { + case SK_SPY: + return 100; + break; + case SK_TACTICS: + case SK_HERBALISM: + case SK_ALCHEMY: + return 200; + break; + case SK_MAGIC: /* Die Magiekosten betragen 50+Summe(50*Stufe) */ + /* 'Stufe' ist dabei die nächste zu erreichende Stufe */ + stufe = 1 + get_level(u, SK_MAGIC); + return k*(1+((stufe+1)*stufe/2)); + break; + } + return 0; +} + +/* ------------------------------------------------------------- */ + +static void +init_learning(struct attrib * a) +{ + a->data.v = calloc(sizeof(teaching_info), 1); +} + +static void +done_learning(struct attrib * a) +{ + free(a->data.v); +} + +const attrib_type at_learning = { + "learning", + init_learning, done_learning, NULL, NULL, NULL, + ATF_UNIQUE +}; + +static int +study_days(unit * student, skill_t sk) +{ + int speed = 30; + if (student->race->study_speed) { + speed += student->race->study_speed[sk]; + if (speed<30) { + skill * sv = get_skill(student, sk); + if (sv==0) { + speed = 30; + } + } + } + return student->number * speed; +} + +static int +teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, + boolean report, int * academy) +{ + teaching_info * teach = NULL; + attrib * a; + int n; + + /* learning sind die Tage, die sie schon durch andere Lehrer zugute + * geschrieben bekommen haben. Total darf dies nicht über 30 Tage pro Mann + * steigen. + * + * n ist die Anzahl zusätzlich gelernter Tage. n darf max. die Differenz + * von schon gelernten Tagen zum MAX(30 Tage pro Mann) betragen. */ + + if (magic_lowskill(student)){ + cmistake(teacher, teacher->thisorder, 292, MSG_EVENT); + return 0; + } + + n = 30; + a = a_find(student->attribs, &at_learning); + if (a!=NULL) { + teach = (teaching_info*)a->data.v; + n -= teach->value; + } + + n = MIN(n, nteaching); + + if (n != 0) { + struct building * b = inside_building(teacher); + const struct building_type * btype = b?b->type:NULL; + int index = 0; + + if (teach==NULL) { + a = a_add(&student->attribs, a_new(&at_learning)); + teach = (teaching_info*)a->data.v; + } else { + while (teach->teachers[index] && index!=MAXTEACHERS) ++index; + } + if (indexteachers[index++] = teacher; + if (indexteachers[index] = NULL; + teach->value += n; + + /* Solange Akademien größenbeschränkt sind, sollte Lehrer und + * Student auch in unterschiedlichen Gebäuden stehen dürfen */ + if (btype == bt_find("academy") + && student->building && student->building->type == bt_find("academy")) + { + int j = study_cost(student, sk); + j = MAX(50, j * 2); + /* kann Einheit das zahlen? */ + if (get_pooled(student, oldresourcetype[R_SILVER], GET_DEFAULT, j) >= j) { + /* Jeder Schüler zusätzlich +10 Tage wenn in Uni. */ + teach->value += (n / 30) * 10; /* learning erhöhen */ + /* Lehrer zusätzlich +1 Tag pro Schüler. */ + if (academy) *academy += n; + } /* sonst nehmen sie nicht am Unterricht teil */ + } + + /* Teaching ist die Anzahl Leute, denen man noch was beibringen kann. Da + * hier nicht n verwendet wird, werden die Leute gezählt und nicht die + * effektiv gelernten Tage. -> FALSCH ? (ENNO) + * + * Eine Einheit A von 11 Mann mit Talent 0 profitiert vom ersten Lehrer B + * also 10x30=300 tage, und der zweite Lehrer C lehrt für nur noch 1x30=30 + * Tage (damit das Maximum von 11x30=330 nicht überschritten wird). + * + * Damit es aber in der Ausführung nicht auf die Reihenfolge drauf ankommt, + * darf der zweite Lehrer C keine weiteren Einheiten D mehr lehren. Also + * wird student 30 Tage gutgeschrieben, aber teaching sinkt auf 0 (300-11x30 <= + * 0). + * + * Sonst träte dies auf: + * + * A: lernt B: lehrt A C: lehrt A D D: lernt + * + * Wenn B vor C dran ist, lehrt C nur 30 Tage an A (wie oben) und + * 270 Tage an D. + * + * Ist C aber vor B dran, lehrt C 300 tage an A, und 0 tage an D, + * und B lehrt auch 0 tage an A. + * + * Deswegen darf C D nie lehren dürfen. + * + * -> Das ist wirr. wer hat das entworfen? + * Besser wäre, man macht erst vorab alle zuordnungen, und dann + * die Talentänderung (enno). + */ + + nteaching = MAX(0, nteaching - student->number * 30); + + } + return n; +} + +int +teach_cmd(unit * u, struct order * ord) +{ + static const curse_type * gbdream_ct = NULL; + plane * pl; + region * r = u->region; + int teaching, i, j, count, academy=0; + unit *u2; + skill_t sk = NOSKILL; + + if (gbdream_ct==0) gbdream_ct = ct_find("gbdream"); + if (gbdream_ct) { + if (get_curse(u->region->attribs, gbdream_ct)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "gbdream_noteach", "")); + return 0; + } + } + + if ((u->race->flags & RCF_NOTEACH) || fval(u, UFL_WERE)) { + cmistake(u, ord, 274, MSG_EVENT); + return 0; + } + + pl = rplane(r); + if (pl && fval(pl, PFL_NOTEACH)) { + cmistake(u, ord, 273, MSG_EVENT); + return 0; + } + + teaching = u->number * 30 * TEACHNUMBER; + + if ((i = get_effect(u, oldpotiontype[P_FOOL])) > 0) { /* Trank "Dumpfbackenbrot" */ + i = MIN(i, u->number * TEACHNUMBER); + /* Trank wirkt pro Schüler, nicht pro Lehrer */ + teaching -= i * 30; + change_effect(u, oldpotiontype[P_FOOL], -i); + j = teaching / 30; + ADDMSG(&u->faction->msgs, msg_message("teachdumb", + "teacher amount", u, j)); + } + if (teaching == 0) return 0; + + + u2 = 0; + count = 0; + + init_tokens(ord); + skip_token(); + +#if TEACH_ALL + if (getparam(u->faction->locale)==P_ANY) { + unit * student = r->units; + skill_t teachskill[MAXSKILLS]; + int i = 0; + do { + sk = getskill(u->faction->locale); + teachskill[i++]=sk; + } while (sk!=NOSKILL); + while (teaching && student) { + if (student->faction == u->faction) { +#ifdef NEW_DAEMONHUNGER_RULE + if (LongHunger(student)) continue; +#else + if (fval(student, UFL_HUNGER)) continue; +#endif + if (get_keyword(student->thisorder) == K_STUDY) { + /* Input ist nun von student->thisorder !! */ + init_tokens(student->thisorder); + skip_token(); + sk = getskill(student->faction->locale); + if (sk!=NOSKILL && teachskill[0]!=NOSKILL) { + for (i=0;teachskill[i]!=NOSKILL;++i) if (sk==teachskill[i]) break; + sk = teachskill[i]; + } + if (sk != NOSKILL && eff_skill_study(u, sk, r)-TEACHDIFFERENCE > eff_skill_study(student, sk, r)) { + teaching -= teach_unit(u, student, teaching, sk, true, &academy); + } + } + } + student = student->next; + } +#ifdef TEACH_FRIENDS + while (teaching && student) { + if (student->faction != u->faction && alliedunit(u, student->faction, HELP_GUARD)) { +#ifdef NEW_DAEMONHUNGER_RULE + if (LongHunger(student)) continue; +#else + if (fval(student, UFL_HUNGER)) continue; +#endif + if (get_keyword(student->thisorder) == K_STUDY) { + /* Input ist nun von student->thisorder !! */ + init_tokens(student->thisorder); + skip_token(); + sk = getskill(student->faction->locale); + if (sk != NOSKILL && eff_skill_study(u, sk, r)-TEACHDIFFERENCE >= eff_skill(student, sk, r)) { + teaching -= teach_unit(u, student, teaching, sk, true, &academy); + } + } + } + student = student->next; + } +#endif + } + else +#endif + { + char zOrder[4096]; + order * new_order; + + zOrder[0] = '\0'; + init_tokens(ord); + skip_token(); + + while (!parser_end()) { + unit * u2 = getunit(r, u->faction); + boolean feedback; + ++count; + + /* Falls die Unit nicht gefunden wird, Fehler melden */ + + if (!u2) { + char tbuf[20]; + const char * uid; + const char * token; + /* Finde den string, der den Fehler verursacht hat */ + parser_pushstate(); + init_tokens(ord); + skip_token(); + + for (j=0; j!=count-1; ++j) { + /* skip over the first 'count' units */ + getunit(r, u->faction); + } + + token = getstrtoken(); + + /* Beginne die Fehlermeldung */ + if (findparam(token, u->faction->locale) != P_TEMP) { + uid = token; + } else { + token = getstrtoken(); + sprintf(tbuf, "%s %s", LOC(u->faction->locale, + parameters[P_TEMP]), token); + uid = tbuf; + } + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unitnotfound_id", + "id", uid)); + + parser_popstate(); + continue; + } + + feedback = u->faction==u2->faction || alliedunit(u2, u->faction, HELP_GUARD); + + /* Neuen Befehl zusammenbauen. TEMP-Einheiten werden automatisch in + * ihre neuen Nummern übersetzt. */ + if (zOrder[0]) strcat(zOrder, " "); + strcat(zOrder, unitid(u2)); + + if (get_keyword(u2->thisorder) != K_STUDY) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "teach_nolearn", "student", u2)); + continue; + } + + /* Input ist nun von u2->thisorder !! */ + parser_pushstate(); + init_tokens(u2->thisorder); + skip_token(); + sk = getskill(u2->faction->locale); + parser_popstate(); + + if (sk == NOSKILL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "teach_nolearn", "student", u2)); + continue; + } + + /* u is teacher, u2 is student */ + if (eff_skill_study(u2, sk, r) > eff_skill_study(u, sk, r)-TEACHDIFFERENCE) { + if (feedback) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "teach_asgood", "student", u2)); + } + continue; + } + if (sk == SK_MAGIC) { + /* ist der Magier schon spezialisiert, so versteht er nur noch + * Lehrer seines Gebietes */ + sc_mage * mage1 = get_mage(u); + sc_mage * mage2 = get_mage(u2); + if (!mage2 || !mage1 || (mage2->magietyp!=M_GRAY && mage1->magietyp!=mage2->magietyp)) { + if (feedback) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_different_magic", "target", u2)); + } + continue; + } + } + + teaching -= teach_unit(u, u2, teaching, sk, false, &academy); + } + new_order = create_order(K_TEACH, u->faction->locale, "%s", zOrder); + replace_order(&u->orders, ord, new_order); + free_order(new_order); /* parse_order & set_order have each increased the refcount */ + } + if (academy && sk!=NOSKILL) { + academy = academy/30; /* anzahl gelehrter wochen, max. 10 */ + learn_skill(u, sk, academy/30.0/TEACHNUMBER); + } + return 0; +} + +static double +study_speedup(unit * u) +{ +#define MINTURN 5 /* 5 */ +#define OFSTURN 2 /* 2 */ + if (turn>MINTURN) { + static int speed_rule = -1; + if (speed_rule<0) { + speed_rule = get_param_int(global.parameters, "study.speedup", 0); + } + if (speed_rule==1) { + double learn_age = OFSTURN; + int i; + for (i=0;i!=u->skill_size;++i) { + skill * sv = u->skills+i; + double learn_time = sv->level*(sv->level+1)/2.0; + learn_age += learn_time; + } + if (learn_age < turn) { + return 2.0-learn_age/turn; + } + } + } + return 1.0; +} + +int +learn_cmd(unit * u, order * ord) +{ + region *r = u->region; + int p; + magic_t mtyp; + int l; + int studycost, days; + double multi = 1.0; + attrib * a = NULL; + teaching_info * teach = NULL; + int money = 0; + skill_t sk; + int maxalchemy = 0; + static int learn_newskills = -1; + if (learn_newskills<0) { + const char * str = get_param(global.parameters, "study.newskills"); + if (str && strcmp(str, "false")==0) learn_newskills = 0; + else learn_newskills = 1; + } + + if ((u->race->flags & RCF_NOLEARN) || fval(u, UFL_WERE)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_race_nolearn", "race", u->race)); + return 0; + } + + init_tokens(ord); + skip_token(); + sk = getskill(u->faction->locale); + + if (sk < 0) { + cmistake(u, ord, 77, MSG_EVENT); + return 0; + } + if (SkillCap(sk) && SkillCap(sk) <= effskill(u, sk)) { + cmistake(u, ord, 771, MSG_EVENT); + return 0; + } + /* Hack: Talente mit Malus -99 können nicht gelernt werden */ + if (u->race->bonus[sk] == -99) { + cmistake(u, ord, 771, MSG_EVENT); + return 0; + } + if (learn_newskills==0) { + skill * sv = get_skill(u, sk); + if (sv==NULL) { + /* we can only learn skills we already have */ + cmistake(u, ord, 771, MSG_EVENT); + return 0; + } + } + + /* snotlings können Talente nur bis T8 lernen */ + if (u->race == new_race[RC_SNOTLING]){ + if (get_level(u, sk) >= 8){ + cmistake(u, ord, 308, MSG_EVENT); + return 0; + } + } + + p = studycost = study_cost(u, sk); + a = a_find(u->attribs, &at_learning); + if (a!=NULL) { + teach = (teaching_info*)a->data.v; + } + + /* keine kostenpflichtigen Talente für Migranten. Vertraute sind + * keine Migranten, wird in is_migrant abgefangen. Vorsicht, + * studycost darf hier noch nicht durch Akademie erhöht sein */ + if (studycost > 0 && !ExpensiveMigrants() && is_migrant(u)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_migrants_nolearn", "")); + return 0; + } + /* Akademie: */ + { + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + + if (btype == bt_find("academy")) { + studycost = MAX(50, studycost * 2); + } + } + + if (sk == SK_MAGIC) { + if (u->number > 1){ + cmistake(u, ord, 106, MSG_MAGIC); + return 0; + } + if (is_familiar(u)){ + /* Vertraute zählen nicht zu den Magiern einer Partei, + * können aber nur Graue Magie lernen */ + mtyp = M_GRAY; + if (!is_mage(u)) create_mage(u, mtyp); + } else if (!has_skill(u, SK_MAGIC)) { + int mmax = skill_limit(u->faction, SK_MAGIC); + /* Die Einheit ist noch kein Magier */ + if (count_skill(u->faction, SK_MAGIC) + u->number > mmax) + { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_magicians", "amount", mmax)); + return 0; + } + mtyp = getmagicskill(u->faction->locale); + if (mtyp == M_NONE || mtyp == M_GRAY) { + /* wurde kein Magiegebiet angegeben, wird davon + * ausgegangen, daß das normal gelernt werden soll */ + if(u->faction->magiegebiet != 0) { + mtyp = u->faction->magiegebiet; + } else { + /* Es wurde kein Magiegebiet angegeben und die Partei + * hat noch keins gewählt. */ + mtyp = getmagicskill(u->faction->locale); + if (mtyp==M_NONE) { + cmistake(u, ord, 178, MSG_MAGIC); + return 0; + } + } + } + if (mtyp != u->faction->magiegebiet){ + /* Es wurde versucht, ein anderes Magiegebiet zu lernen + * als das der Partei */ + if (u->faction->magiegebiet != 0){ + cmistake(u, ord, 179, MSG_MAGIC); + return 0; + } else { + /* Lernt zum ersten mal Magie und legt damit das + * Magiegebiet der Partei fest */ + u->faction->magiegebiet = mtyp; + } + } + if (!is_mage(u)) create_mage(u, mtyp); + } else { + /* ist schon ein Magier und kein Vertrauter */ + if (u->faction->magiegebiet == 0) { + /* die Partei hat noch kein Magiegebiet gewählt. */ + mtyp = getmagicskill(u->faction->locale); + if (mtyp == M_NONE){ + mtyp = getmagicskill(u->faction->locale); + if (mtyp==M_NONE) { + cmistake(u, ord, 178, MSG_MAGIC); + return 0; + } + } + /* Legt damit das Magiegebiet der Partei fest */ + u->faction->magiegebiet = mtyp; + } + } + } + if (sk == SK_ALCHEMY) { + maxalchemy = eff_skill(u, SK_ALCHEMY, r); + if (!has_skill(u, SK_ALCHEMY)) { + int amax = skill_limit(u->faction, SK_ALCHEMY); + if (count_skill(u->faction, SK_ALCHEMY) + u->number > amax) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_alchemists", "amount", amax)); + return 0; + } + } + } + if (studycost) { + int cost = studycost * u->number; + money = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, cost); + money = MIN(money, cost); + } + if (money < studycost * u->number) { + studycost = p; /* Ohne Univertreurung */ + money = MIN(money, studycost); + if (p>0 && money < studycost * u->number) { + cmistake(u, ord, 65, MSG_EVENT); + multi = money / (double)(studycost * u->number); + } + } + + if (teach==NULL) { + a = a_add(&u->attribs, a_new(&at_learning)); + teach = (teaching_info*)a->data.v; + teach->teachers[0] = 0; + } + if (money>0) { + use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, money); + ADDMSG(&u->faction->msgs, msg_message("studycost", + "unit region cost skill", u, u->region, money, sk)); + } + + if (get_effect(u, oldpotiontype[P_WISE])) { + l = MIN(u->number, get_effect(u, oldpotiontype[P_WISE])); + teach->value += l * 10; + change_effect(u, oldpotiontype[P_WISE], -l); + } + if (get_effect(u, oldpotiontype[P_FOOL])) { + l = MIN(u->number, get_effect(u, oldpotiontype[P_FOOL])); + teach->value -= l * 30; + change_effect(u, oldpotiontype[P_FOOL], -l); + } + + if (p != studycost) { + /* ist_in_gebaeude(r, u, BT_UNIVERSITAET) == 1) { */ + /* p ist Kosten ohne Uni, studycost mit; wenn + * p!=studycost, ist die Einheit zwangsweise + * in einer Uni */ + teach->value += u->number * 10; + } + + if (is_cursed(r->attribs, C_BADLEARN,0)) { + teach->value -= u->number * 10; + } + + multi *= study_speedup(u); + days = study_days(u, sk); + days = (int)((days + teach->value) * multi); + + /* the artacademy currently improves the learning of entertainment + of all units in the region, to be able to make it cumulative with + with an academy */ + + if (sk == SK_ENTERTAINMENT && buildingtype_exists(r, bt_find("artacademy"), false)) { + days *= 2; + } + + if (fval(u, UFL_HUNGER)) days /= 2; + + while (days) { + if (days>=u->number*30) { + learn_skill(u, sk, 1.0); + days -= u->number*30; + } else { + double chance = (double)days/u->number/30; + learn_skill(u, sk, chance); + days = 0; + } + } + if (a!=NULL) { + if (teach!=NULL) { + int index = 0; + while (teach->teachers[index] && index!=MAXTEACHERS) { + unit * teacher = teach->teachers[index++]; + if (teacher->faction != u->faction) { + boolean feedback = alliedunit(u, teacher->faction, HELP_GUARD); + if (feedback) { + ADDMSG(&teacher->faction->msgs, msg_message("teach_teacher", + "teacher student skill level", teacher, u, sk, + effskill(u, sk))); + } + ADDMSG(&u->faction->msgs, msg_message("teach_student", + "teacher student skill", teacher, u, sk)); + } + } + } + a_remove(&u->attribs, a); + a = NULL; + } + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + + /* Anzeigen neuer Tränke */ + /* Spruchlistenaktualiesierung ist in Regeneration */ + + if (sk == SK_ALCHEMY) { + const potion_type * ptype; + faction * f = u->faction; + int skill = eff_skill(u, SK_ALCHEMY, r); + if (skill>maxalchemy) { + for (ptype=potiontypes; ptype; ptype=ptype->next) { + if (skill == ptype->level * 2) { + attrib * a = a_find(f->attribs, &at_showitem); + while (a && a->type==&at_showitem && a->data.v != ptype) a=a->next; + if (a==NULL || a->type!=&at_showitem) { + a = a_add(&f->attribs, a_new(&at_showitem)); + a->data.v = (void*) ptype->itype; + } + } + } + } + } + else if (sk==SK_MAGIC) { + sc_mage * mage = get_mage(u); + if (!mage) { + mage = create_mage(u, u->faction->magiegebiet); + } + } + + return 0; +} diff --git a/src/gamecode/study.h b/src/gamecode/study.h new file mode 100644 index 000000000..6ea695a26 --- /dev/null +++ b/src/gamecode/study.h @@ -0,0 +1,45 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_STUDY +#define H_KRNL_STUDY + +#ifdef __cplusplus +extern "C" { +#endif + +extern int teach_cmd(struct unit * u, struct order * ord); +extern int learn_cmd(struct unit * u, struct order * ord); + +extern magic_t getmagicskill(const struct locale * lang); +extern boolean is_migrant(struct unit *u); +extern int study_cost(struct unit *u, skill_t talent); + +#define MAXTEACHERS 4 +typedef struct teaching_info { + struct unit * teachers[MAXTEACHERS]; + int value; +} teaching_info; + +extern const struct attrib_type at_learning; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/gamecode/summary.c b/src/gamecode/summary.c new file mode 100644 index 000000000..5e16a53c4 --- /dev/null +++ b/src/gamecode/summary.c @@ -0,0 +1,413 @@ +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2007 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +/* wenn platform.h nicht vor curses included wird, kompiliert es unter windows nicht */ +#include +#include + +#include "summary.h" + +#include "laws.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#undef SUMMARY_BOM /* write a BOM in the summary file */ + +typedef struct summary { + int waffen; + int factions; + int ruestungen; + int schiffe; + int gebaeude; + int maxskill; + int heroes; + int inhabitedregions; + int peasants; + int nunits; + int playerpop; + double playermoney; + double peasantmoney; + int armed_men; + int poprace[MAXRACES]; + int factionrace[MAXRACES]; + int landregionen; + int regionen_mit_spielern; + int landregionen_mit_spielern; + int orkifizierte_regionen; + int inactive_volcanos; + int active_volcanos; + int spielerpferde; + int pferde; + struct language { + struct language * next; + int number; + const struct locale * locale; + } * languages; +} summary; + +static char * +pcomp(double i, double j) +{ + static char buf[32]; + sprintf(buf, "%.0f (%s%.0f)", i, (i>=j)?"+":"", i-j); + return buf; +} + +static char * +rcomp(int i, int j) +{ + static char buf[32]; + sprintf(buf, "%d (%s%d,%s%d%%)", + i, (i>=j)?"+":"", i-j, (i>=j)?"+":"",j?((i-j)*100)/j:0); + return buf; +} + + +static void +out_faction(FILE *file, const struct faction *f) +{ + if (alliances!=NULL) { + fprintf(file, "%s (%s/%d) (%.3s/%.3s), %d Einh., %d Pers., $%d, %d NMR\n", + f->name, itoa36(f->no), f_get_alliance(f)?f->alliance->id:0, + LOC(default_locale, rc_name(f->race, 0)), magic_school[f->magiegebiet], + f->no_units, f->num_total, f->money, turn - f->lastorders); + } else { + fprintf(file, "%s (%.3s/%.3s), %d Einh., %d Pers., $%d, %d NMR\n", + factionname(f), LOC(default_locale, rc_name(f->race, 0)), + magic_school[f->magiegebiet], f->no_units, f->num_total, f->money, + turn - f->lastorders); + } +} + +static char * +gamedate2(const struct locale * lang) +{ + static char buf[256]; + gamedate gd; + + get_gamedate(turn, &gd); + sprintf(buf, "in %s des Monats %s im Jahre %d %s.", + LOC(lang, weeknames2[gd.week]), + LOC(lang, monthnames[gd.month]), + gd.year, + agename?LOC(lang, agename):""); + return buf; +} + +static void +writeturn(void) +{ + char zText[MAX_PATH]; + FILE *f; + + sprintf(zText, "%s/datum", basepath()); + f = cfopen(zText, "w"); + if (!f) return; + fputs(gamedate2(default_locale), f); + fclose(f); + sprintf(zText, "%s/turn", basepath()); + f = cfopen(zText, "w"); + if (!f) return; + fprintf(f, "%d\n", turn); + fclose(f); +} + +void +report_summary(summary * s, summary * o, boolean full) +{ + FILE * F = NULL; + int i, newplayers = 0; + faction * f; + char zText[MAX_PATH]; + + if (full) { + sprintf(zText, "%s/parteien.full", basepath()); + } else { + sprintf(zText, "%s/parteien", basepath()); + } + F = cfopen(zText, "w"); + if (!F) return; +#ifdef SUMMARY_BOM + else { + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + fwrite(utf8_bom, 1, 3, F); + } +#endif + printf("Schreibe Zusammenfassung (parteien)...\n"); + fprintf(F, "%s\n%s\n\n", global.gamename, gamedate2(default_locale)); + fprintf(F, "Auswertung Nr: %d\n\n", turn); + fprintf(F, "Parteien: %s\n", pcomp(s->factions, o->factions)); + fprintf(F, "Einheiten: %s\n", pcomp(s->nunits, o->nunits)); + fprintf(F, "Spielerpopulation: %s\n", + pcomp(s->playerpop, o->playerpop)); + fprintf(F, " davon bewaffnet: %s\n", + pcomp(s->armed_men, o->armed_men)); + fprintf(F, " Helden: %s\n", pcomp(s->heroes, o->heroes)); + + if (full) { + fprintf(F, "Regionen: %d\n", listlen(regions)); + fprintf(F, "Bewohnte Regionen: %d\n", s->inhabitedregions); + fprintf(F, "Landregionen: %d\n", s->landregionen); + fprintf(F, "Spielerregionen: %d\n", s->regionen_mit_spielern); + fprintf(F, "Landspielerregionen: %d\n", s->landregionen_mit_spielern); + fprintf(F, "Orkifizierte Regionen: %d\n", s->orkifizierte_regionen); + fprintf(F, "Inaktive Vulkane: %d\n", s->inactive_volcanos); + fprintf(F, "Aktive Vulkane: %d\n\n", s->active_volcanos); + } + + for (i = 0; i < MAXRACES; i++) { + const race * rc = new_race[i]; + if (s->factionrace[i] && rc && playerrace(rc) + && i != RC_TEMPLATE && i != RC_CLONE) { + fprintf(F, "%13s%s: %s\n", LOC(default_locale, rc_name(rc, 3)), LOC(default_locale, "stat_tribe_p"), + pcomp(s->factionrace[i], o->factionrace[i])); + } + } + + if(full) { + fprintf(F, "\n"); + { + struct language * plang = s->languages; + while (plang!=NULL) { + struct language * olang = o->languages; + int nold = 0; + while (olang && olang->locale!=plang->locale) olang=olang->next; + if (olang) nold = olang->number; + fprintf(F, "Sprache %12s: %s\n", locale_name(plang->locale), + rcomp(plang->number, nold)); + plang=plang->next; + } + } + } + + fprintf(F, "\n"); + if (full) { + for (i = 0; i < MAXRACES; i++) { + const race * rc = new_race[i]; + if (s->poprace[i]) { + fprintf(F, "%20s: %s\n", LOC(default_locale, rc_name(rc, 1)), + rcomp(s->poprace[i], o->poprace[i])); + } + } + } else { + for (i = 0; i < MAXRACES; i++) { + const race * rc = new_race[i]; + if (s->poprace[i] && playerrace(rc) + && i != RC_TEMPLATE && i != RC_CLONE) { + fprintf(F, "%20s: %s\n", LOC(default_locale, rc_name(rc, 1)), + rcomp(s->poprace[i], o->poprace[i])); + } + } + } + + if (full) { + fprintf(F, "\nWaffen: %s\n", pcomp(s->waffen,o->waffen)); + fprintf(F, "Ruestungen: %s\n", + pcomp(s->ruestungen,o->ruestungen)); + fprintf(F, "ungezaehmte Pferde: %s\n", pcomp(s->pferde, o->pferde)); + fprintf(F, "gezaehmte Pferde: %s\n", + pcomp(s->spielerpferde,o->spielerpferde)); + fprintf(F, "Schiffe: %s\n", pcomp(s->schiffe, o->schiffe)); + fprintf(F, "Gebaeude: %s\n", pcomp(s->gebaeude, o->gebaeude)); + + fprintf(F, "\nBauernpopulation: %s\n", pcomp(s->peasants,o->peasants)); + + fprintf(F, "Population gesamt: %d\n\n", s->playerpop+s->peasants); + + fprintf(F, "Reichtum Spieler: %s Silber\n", + pcomp(s->playermoney,o->playermoney)); + fprintf(F, "Reichtum Bauern: %s Silber\n", + pcomp(s->peasantmoney, o->peasantmoney)); + fprintf(F, "Reichtum gesamt: %s Silber\n\n", + pcomp(s->playermoney+s->peasantmoney, o->playermoney+o->peasantmoney)); + } + + fprintf(F, "\n\n"); + + newplayers = update_nmrs(); + + for (i = 0; i <= NMRTimeout(); ++i) { + if (i == NMRTimeout()) { + fprintf(F, "+ NMR:\t\t %d\n", nmrs[i]); + } else { + fprintf(F, "%d NMR:\t\t %d\n", i, nmrs[i]); + } + } + if (age) { + if (age[2] != 0) { + fprintf(F, "Erstabgaben:\t %d%%\n", 100 - (dropouts[0] * 100 / age[2])); + } + if (age[3] != 0) { + fprintf(F, "Zweitabgaben:\t %d%%\n", 100 - (dropouts[1] * 100 / age[3])); + } + } + fprintf(F, "Neue Spieler:\t %d\n", newplayers); + + if (full) { + if (factions) + fprintf(F, "\nParteien:\n\n"); + + for (f = factions; f; f = f->next) { + out_faction(F, f); + } + + if (NMRTimeout() && full) { + fprintf(F, "\n\nFactions with NMRs:\n"); + for (i = NMRTimeout(); i > 0; --i) { + for(f=factions; f; f=f->next) { + if(i == NMRTimeout()) { + if(turn - f->lastorders >= i) { + out_faction(F, f); + } + } else { + if(turn - f->lastorders == i) { + out_faction(F, f); + } + } + } + } + } + } + + fclose(F); + + if (full) { + printf("writing date & turn\n"); + writeturn(); + } + free(nmrs); + nmrs = NULL; +} + +summary * +make_summary(void) +{ + faction *f; + region *r; + unit *u; + summary * s = calloc(1, sizeof(summary)); + + for (f = factions; f; f = f->next) { + const struct locale * lang = f->locale; + struct language * plang = s->languages; + while (plang && plang->locale != lang) plang=plang->next; + if (!plang) { + plang = calloc(sizeof(struct language), 1); + plang->next = s->languages; + s->languages = plang; + plang->locale = lang; + } + ++plang->number; + f->nregions = 0; + f->num_total = 0; + f->money = 0; + if (f->alive && f->units) { + s->factions++; + /* Problem mit Monsterpartei ... */ + if (!is_monsters(f)) { + s->factionrace[old_race(f->race)]++; + } + } + } + + /* Alles zählen */ + + for (r = regions; r; r = r->next) { + s->pferde += rhorses(r); + s->schiffe += listlen(r->ships); + s->gebaeude += listlen(r->buildings); + if (!fval(r->terrain, SEA_REGION)) { + s->landregionen++; + if (r->units) { + s->landregionen_mit_spielern++; + } + if (fval(r, RF_ORCIFIED)) { + s->orkifizierte_regionen++; + } + if (r->terrain == newterrain(T_VOLCANO)) { + s->inactive_volcanos++; + } else if (r->terrain == newterrain(T_VOLCANO_SMOKING)) { + s->active_volcanos++; + } + } + if (r->units) { + s->regionen_mit_spielern++; + } + if (rpeasants(r) || r->units) { + s->inhabitedregions++; + s->peasants += rpeasants(r); + s->peasantmoney += rmoney(r); + + /* Einheiten Info. nregions darf nur einmal pro Partei + * incrementiert werden. */ + + for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT); + for (u = r->units; u; u = u->next) { + f = u->faction; + if (!is_monsters(u->faction)) { + skill * sv; + item * itm; + + s->nunits++; + s->playerpop += u->number; + if (u->flags & UFL_HERO) { + s->heroes += u->number; + } + s->spielerpferde += get_item(u, I_HORSE); + s->playermoney += get_money(u); + s->armed_men += armedmen(u, true); + for (itm=u->items;itm;itm=itm->next) { + if (itm->type->rtype->wtype) { + s->waffen += itm->number; + } + if (itm->type->rtype->atype) { + s->ruestungen += itm->number; + } + } + + s->spielerpferde += get_item(u, I_HORSE); + + for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { + skill_t sk = sv->id; + int aktskill = eff_skill(u, sk, r); + if (aktskill > s->maxskill) s->maxskill = aktskill; + } + if (!fval(f, FFL_SELECT)) { + f->nregions++; + fset(f, FFL_SELECT); + } + } + + f->num_total += u->number; + f->money += get_money(u); + s->poprace[old_race(u->race)] += u->number; + } + } + } + + return s; +} diff --git a/src/gamecode/summary.h b/src/gamecode/summary.h new file mode 100644 index 000000000..f7419a30b --- /dev/null +++ b/src/gamecode/summary.h @@ -0,0 +1,25 @@ +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2007 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +#ifndef H_GC_SUMMARY +#define H_GC_SUMMARY + +#ifdef __cplusplus +extern "C" { +#endif + + struct summary; + extern void report_summary(struct summary * n, struct summary * o, boolean full); + extern struct summary * make_summary(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/xmlreport.c b/src/gamecode/xmlreport.c new file mode 100644 index 000000000..f428f9417 --- /dev/null +++ b/src/gamecode/xmlreport.c @@ -0,0 +1,748 @@ +/* vi: set ts=2: ++-------------------+ Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel ++-------------------+ +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "xmlreport.h" + +#define XML_ATL_NAMESPACE (const xmlChar *) "http://www.eressea.de/XML/2008/atlantis" +#define XML_XML_LANG (const xmlChar *) "lang" + +/* modules include */ +#include + +/* attributes include */ +#include +#include +#include +#include +#include + +/* gamecode includes */ +#include "laws.h" +#include "economy.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include + +/* libxml2 includes */ +#include +#include +#ifdef USE_ICONV +#include +#endif + +/* libc includes */ +#include +#include +#include +#include +#include +#include + +#define L10N(x) x + +typedef struct xml_context { + xmlDocPtr doc; + xmlNsPtr ns_atl; + xmlNsPtr ns_xml; +} xml_context; + +static xmlNodePtr +xml_link(report_context * ctx, const xmlChar * rel, const xmlChar * ref) +{ + xml_context* xct = (xml_context*)ctx->userdata; + xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "link"); + + xmlNewNsProp(node, xct->ns_atl, BAD_CAST "rel", rel); + xmlNewNsProp(node, xct->ns_atl, BAD_CAST "ref", ref); + + return node; +} + +static const xmlChar * +xml_ref_unit(const unit * u) +{ + static char idbuf[20]; + snprintf(idbuf, sizeof(idbuf), "unit_%d", u->no); + return (const xmlChar *)idbuf; +} + +static const xmlChar * +xml_ref_faction(const faction * f) +{ + static char idbuf[20]; + snprintf(idbuf, sizeof(idbuf), "fctn_%d", f->no); + return (const xmlChar *)idbuf; +} + +static const xmlChar * +xml_ref_group(const group * g) +{ + static char idbuf[20]; + snprintf(idbuf, sizeof(idbuf), "grp_%d", g->gid); + return (const xmlChar *)idbuf; +} + +static const xmlChar * +xml_ref_prefix(const char * str) +{ + static char idbuf[20]; + snprintf(idbuf, sizeof(idbuf), "pref_%s", str); + return (const xmlChar *)idbuf; +} + +static const xmlChar * +xml_ref_building(const building * b) +{ + static char idbuf[20]; + snprintf(idbuf, sizeof(idbuf), "bldg_%d", b->no); + return (const xmlChar *)idbuf; +} + +static const xmlChar * +xml_ref_ship(const ship * sh) +{ + static char idbuf[20]; + snprintf(idbuf, sizeof(idbuf), "shp_%d", sh->no); + return (const xmlChar *)idbuf; +} + +static const xmlChar * +xml_ref_region(const region * r) +{ + static char idbuf[20]; + snprintf(idbuf, sizeof(idbuf), "rgn_%d", r->uid); + return (const xmlChar *)idbuf; +} + +static xmlNodePtr +xml_inventory(report_context * ctx, item * items, unit * u) +{ + xml_context* xct = (xml_context*)ctx->userdata; + xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "items"); + item * itm; + + for (itm=items;itm;itm=itm->next) { + xmlNodePtr child; + const char * name; + int n; + + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "item")); + report_item(u, itm, ctx->f, NULL, &name, &n, true); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (xmlChar *)name); + xmlNodeAddContent(child, (xmlChar*)itoab(n, 10)); + } + return node; +} + +static xmlNodePtr +xml_spells(report_context * ctx, spell_list * slist, int maxlevel) +{ + xml_context* xct = (xml_context*)ctx->userdata; + xmlNodePtr child, node = xmlNewNode(xct->ns_atl, BAD_CAST "spells"); + + for (;slist; slist = slist->next) { + spell * sp = slist->data; + + if (sp->level <= maxlevel) { + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "spell")); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "name", BAD_CAST sp->sname); + } + } + return node; +} + +static xmlNodePtr +xml_skills(report_context * ctx, unit * u) +{ + xml_context* xct = (xml_context*)ctx->userdata; + xmlNodePtr child, node = xmlNewNode(xct->ns_atl, BAD_CAST "skills"); + skill * sv; + + for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { + if (sv->level>0) { + skill_t sk = sv->id; + int esk = eff_skill(u, sk, u->region); + + child = xmlNewTextChild(node, xct->ns_atl, BAD_CAST "skill", BAD_CAST itoab(esk, 10)); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", BAD_CAST skillnames[sk]); + } + } + + return node; +} + +static xmlNodePtr +xml_unit(report_context * ctx, unit * u, int mode) +{ + xml_context* xct = (xml_context*)ctx->userdata; + xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "unit"); + static const curse_type * itemcloak_ct = 0; + static boolean init = false; + xmlNodePtr child; + const char * str, * rcname, * rcillusion; + boolean disclosure = (ctx->f == u->faction || omniscient(ctx->f)); + + /* TODO: hitpoints, aura, combatspells, curses */ + + xmlNewNsProp(node, xct->ns_xml, XML_XML_ID, xml_ref_unit(u)); + xmlNewNsProp(node, xct->ns_atl, BAD_CAST "key", BAD_CAST itoa36(u->no)); + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "name", (const xmlChar *)u->name); + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "number", (const xmlChar *)itoab(u->number, 10)); + + /* optional description */ + str = u_description(u, ctx->f->locale); + if (str) { + child = xmlNewTextChild(node, xct->ns_atl, BAD_CAST "text", (const xmlChar *)str); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "public"); + if (str!=u->display) { + xmlNewNsProp(child, xct->ns_atl, XML_XML_LANG, BAD_CAST locale_name(ctx->f->locale)); + } + } + + /* possible info */ + if (is_guard(u, GUARD_ALL)!=0) { + xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "guard")); + } + + /* siege */ + if (fval(u, UFL_SIEGE)) { + building * b = usiege(u); + if (b) { + xmlAddChild(node, xml_link(ctx, BAD_CAST "siege", xml_ref_building(b))); + } + } + + /* TODO: temp/alias */ + + /* race information */ + report_race(u, &rcname, &rcillusion); + if (disclosure) { + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "race")); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "true"); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (const xmlChar *)rcname); + if (rcillusion) { + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "race")); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "stealth"); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (const xmlChar *)rcillusion); + } + } else { + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "race")); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (const xmlChar *)(rcillusion?rcillusion:rcname)); + } + + /* group and prefix information. we only write the prefix if we really must */ + if (fval(u, UFL_GROUP)) { + attrib * a = a_find(u->attribs, &at_group); + if (a!=NULL) { + const group * g = (const group*)a->data.v; + if (disclosure) { + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "group")); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", xml_ref_group(g)); + } else { + const char * prefix = get_prefix(g->attribs); + if (prefix) { + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "prefix")); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", xml_ref_prefix(prefix)); + } + } + } + } + + if (disclosure) { + unit * mage; + + str = uprivate(u); + if (str) { + child = xmlNewTextChild(node, xct->ns_atl, BAD_CAST "text", (const xmlChar *)str); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "private"); + } + + /* familiar info */ + mage = get_familiar_mage(u); + if (mage) xmlAddChild(node, xml_link(ctx, BAD_CAST "familiar_of", xml_ref_unit(mage))); + + /* combat status */ + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "status")); + xmlSetNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "combat"); + xmlSetNsProp(child, xct->ns_atl, BAD_CAST "value", BAD_CAST combatstatus[u->status]); + + if (fval(u, UFL_NOAID)) { + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "status")); + xmlSetNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "aid"); + xmlSetNsProp(child, xct->ns_atl, BAD_CAST "value", BAD_CAST "false"); + } + + if (fval(u, UFL_STEALTH)) { + int i = u_geteffstealth(u); + if (i>=0) { + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "status")); + xmlSetNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "stealth"); + xmlSetNsProp(child, xct->ns_atl, BAD_CAST "value", BAD_CAST itoab(i, 10)); + } + } + if (fval(u, UFL_HERO)) { + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "status")); + xmlSetNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "hero"); + xmlSetNsProp(child, xct->ns_atl, BAD_CAST "value", BAD_CAST "true"); + } + + if (fval(u, UFL_HUNGER)) { + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "status")); + xmlSetNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "hunger"); + xmlSetNsProp(child, xct->ns_atl, BAD_CAST "value", BAD_CAST "true"); + } + + /* skills */ + if (u->skill_size) { + xmlAddChild(node, xml_skills(ctx, u)); + } + + /* spells */ + if (is_mage(u)) { + sc_mage * mage = get_mage(u); + spell_list * slist = mage->spells; + if (slist) { + xmlAddChild(node, xml_spells(ctx, slist, effskill(u, SK_MAGIC))); + } + } + } + + /* faction information w/ visibiility */ + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "faction")); + if (disclosure) { + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "true"); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", xml_ref_faction(u->faction)); + + if (fval(u, UFL_ANON_FACTION)) { + const faction * sf = visible_faction(NULL, u); + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "faction")); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "stealth"); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", xml_ref_faction(sf)); + } + } else { + const faction * sf = visible_faction(ctx->f, u); + if (sf==ctx->f) { + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "stealth"); + } + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", xml_ref_faction(sf)); + } + + /* the inventory */ + if (u->items) { + item result[MAX_INVENTORY]; + item * show = NULL; + + if (!init) { + init = true; + itemcloak_ct = ct_find("itemcloak"); + } + + if (disclosure) { + show = u->items; + } else { + boolean see_items = (mode >= see_unit); + if (see_items) { + if (itemcloak_ct && curse_active(get_curse(u->attribs, itemcloak_ct))) { + see_items = false; + } else { + see_items = effskill(u, SK_STEALTH) < 3; + } + } + if (see_items) { + int n = report_items(u->items, result, MAX_INVENTORY, u, ctx->f); + assert(n>=0); + if (n>0) show = result; + else show = NULL; + } else { + show = NULL; + } + } + + if (show) { + xmlAddChild(node, xml_inventory(ctx, show, u)); + } + } + + return node; +} + +static xmlNodePtr +xml_resources(report_context * ctx, const seen_region * sr) +{ + xml_context* xct = (xml_context*)ctx->userdata; + xmlNodePtr node = NULL; + resource_report result[MAX_RAWMATERIALS]; + int n, size = report_resources(sr, result, MAX_RAWMATERIALS, ctx->f); + + if (size) { + node = xmlNewNode(xct->ns_atl, BAD_CAST "resources"); + for (n=0;n=0) { + xmlNodePtr child; + + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "resource")); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (xmlChar*)result[n].name); + if (result[n].level>=0) { + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "level", (xmlChar*)itoab(result[n].level, 10)); + } + xmlNodeAddContent(child, (xmlChar*)itoab(result[n].number, 10)); + } + } + } + return node; +} + +static xmlNodePtr +xml_diplomacy(report_context * ctx, const struct ally * allies) +{ + xml_context* xct = (xml_context*)ctx->userdata; + xmlNodePtr child, node = xmlNewNode(xct->ns_atl, BAD_CAST "diplomacy"); + const struct ally * sf; + + for (sf=allies;sf;sf=sf->next) { + int i, status = sf->status; + for (i=0;helpmodes[i].name;++i) { + if (sf->faction && (status & helpmodes[i].status)==helpmodes[i].status) { + status -= helpmodes[i].status; + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "status")); + xmlNewNsProp(child, xct->ns_xml, BAD_CAST "faction", xml_ref_faction(sf->faction)); + xmlNewNsProp(child, xct->ns_xml, BAD_CAST "status", (xmlChar*)helpmodes[i].name); + } + } + } + return node; +} + +static xmlNodePtr +xml_groups(report_context * ctx, const group * groups) +{ + xml_context* xct = (xml_context*)ctx->userdata; + xmlNodePtr child, node = xmlNewNode(xct->ns_atl, BAD_CAST "faction"); + const group * g; + + for (g=groups;g;g=g->next) { + const char * prefix = get_prefix(g->attribs); + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "group")); + xmlNewNsProp(child, xct->ns_xml, XML_XML_ID, xml_ref_group(g)); + xmlNewTextChild(child, xct->ns_atl, BAD_CAST "name", (const xmlChar *)g->name); + + if (g->allies) xmlAddChild(child, xml_diplomacy(ctx, g->allies)); + + if (prefix) { + child = xmlAddChild(child, xmlNewNode(xct->ns_atl, BAD_CAST "prefix")); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", xml_ref_prefix(prefix)); + } + } + + return node; +} + +static xmlNodePtr +xml_faction(report_context * ctx, faction * f) +{ + xml_context* xct = (xml_context*)ctx->userdata; + xmlNodePtr child, node = xmlNewNode(xct->ns_atl, BAD_CAST "faction"); + + /* TODO: alliance, locale */ + + xmlNewNsProp(node, xct->ns_xml, XML_XML_ID, xml_ref_faction(f)); + xmlNewNsProp(node, xct->ns_atl, BAD_CAST "key", BAD_CAST itoa36(f->no)); + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "name", (const xmlChar *)f->name); + if (f->email) xmlNewTextChild(node, xct->ns_atl, BAD_CAST "email", (const xmlChar *)f->email); + if (f->banner) { + child = xmlNewTextChild(node, xct->ns_atl, BAD_CAST "text", (const xmlChar *)f->banner); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "public"); + } + + if (ctx->f==f) { + xmlAddChild(node, xml_link(ctx, BAD_CAST "race", BAD_CAST f->race->_name[0])); + + if (f->items) xmlAddChild(node, xml_inventory(ctx, f->items, NULL)); + if (f->allies) xmlAddChild(node, xml_diplomacy(ctx, f->allies)); + if (f->groups) xmlAddChild(node, xml_groups(ctx, f->groups)); + + /* TODO: age, options, score, prefix, magic, immigrants, heroes, nmr, groups */ + } + return node; +} + +static xmlNodePtr +xml_building(report_context * ctx, seen_region * sr, const building * b, const unit * owner) +{ + xml_context* xct = (xml_context*)ctx->userdata; + xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "building"); + xmlNodePtr child; + const char * bname, * billusion; + + xmlNewNsProp(node, xct->ns_xml, XML_XML_ID, xml_ref_building(b)); + xmlNewNsProp(node, xct->ns_atl, BAD_CAST "key", BAD_CAST itoa36(b->no)); + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "name", (const xmlChar *)b->name); + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "size", (const xmlChar *)itoab(b->size, 10)); + if (b->display && b->display[0]) { + child = xmlNewTextChild(node, xct->ns_atl, BAD_CAST "text", (const xmlChar *)b->display); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "public"); + } + if (b->besieged) { + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "siege", (const xmlChar *)itoab(b->besieged, 10)); + } + if (owner) xmlAddChild(node, xml_link(ctx, BAD_CAST "owner", xml_ref_unit(owner))); + + report_building(b, &bname, &billusion); + if (owner && owner->faction==ctx->f) { + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "type")); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "true"); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (const xmlChar *)bname); + if (billusion) { + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "type")); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "illusion"); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (const xmlChar *)billusion); + } + } else { + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "type")); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (const xmlChar *)(billusion?billusion:bname)); + } + + return node; +} + +static xmlNodePtr +xml_ship(report_context * ctx, const seen_region * sr, const ship * sh, const unit * owner) +{ + xml_context* xct = (xml_context*)ctx->userdata; + xmlNodePtr child, node = xmlNewNode(xct->ns_atl, BAD_CAST "ship"); + + xmlNewNsProp(node, xct->ns_xml, XML_XML_ID, xml_ref_ship(sh)); + xmlNewNsProp(node, xct->ns_atl, BAD_CAST "key", BAD_CAST itoa36(sh->no)); + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "name", (const xmlChar *)sh->name); + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "size", (const xmlChar *)itoab(sh->size, 10)); + + if (sh->damage) { + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "damage", (const xmlChar *)itoab(sh->damage, 10)); + } + + if (fval(sr->r->terrain, SEA_REGION) && sh->coast!=NODIRECTION) { + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "coast", BAD_CAST directions[sh->coast]); + } + + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "type")); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (const xmlChar *)sh->type->name[0]); + + if (sh->display && sh->display[0]) { + child = xmlNewTextChild(node, xct->ns_atl, BAD_CAST "text", (const xmlChar *)sh->display); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "public"); + } + + if (owner) xmlAddChild(node, xml_link(ctx, BAD_CAST "owner", xml_ref_unit(owner))); + + if ((owner && owner->faction == ctx->f) || omniscient(ctx->f)) { + int n = 0, p = 0; + getshipweight(sh, &n, &p); + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "cargo", (const xmlChar *)itoab(n, 10)); + } + return node; +} + +static xmlNodePtr +xml_region(report_context * ctx, seen_region * sr) +{ + xml_context* xct = (xml_context*)ctx->userdata; + const region * r = sr->r; + xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "region"); + xmlNodePtr child; + int stealthmod = stealth_modifier(sr->mode); + unit * u; + ship * sh = r->ships; + building * b = r->buildings; + plane * pl = rplane(r); + int nx = r->x, ny = r->y; + + pnormalize(&nx, &ny, pl); + adjust_coordinates(ctx->f, &nx, &ny, pl, r); + + /* TODO: entertain-quota, recruits, salary, prices, curses, borders, apparitions (Schemen), spells, travelthru, messages */ + xmlNewNsProp(node, xct->ns_xml, XML_XML_ID, xml_ref_region(r)); + + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "coordinate")); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "x", xml_i(nx)); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "y", xml_i(ny)); + if (pl && pl->name) { + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "plane", (xmlChar *)pl->name); + } + + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "terrain")); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (xmlChar *)terrain_name(r)); + + if (r->land!=NULL) { + child = xmlNewTextChild(node, xct->ns_atl, BAD_CAST "name", (const xmlChar *)r->land->name); + if (r->land->items) { + xmlAddChild(node, xml_inventory(ctx, r->land->items, NULL)); + } + } + if (r->display && r->display[0]) { + child = xmlNewTextChild(node, xct->ns_atl, BAD_CAST "text", (const xmlChar *)r->display); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "public"); + } + child = xml_resources(ctx, sr); + if (child) xmlAddChild(node, child); + + child = xmlNewNode(xct->ns_atl, BAD_CAST "terrain"); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (const xmlChar *)terrain_name(r)); + + if (sr->mode>see_neighbour) { + /* report all units. they are pre-sorted in an efficient manner */ + u = r->units; + while (b) { + while (b && (!u || u->building!=b)) { + xmlAddChild(node, xml_building(ctx, sr, b, NULL)); + b = b->next; + } + if (b) { + child = xmlAddChild(node, xml_building(ctx, sr, b, u)); + while (u && u->building==b) { + xmlAddChild(child, xml_unit(ctx, u, sr->mode)); + u = u->next; + } + b = b->next; + } + } + while (u && !u->ship) { + if (stealthmod>INT_MIN) { + if (u->faction == ctx->f || cansee(ctx->f, r, u, stealthmod)) { + xmlAddChild(node, xml_unit(ctx, u, sr->mode)); + } + } + u = u->next; + } + while (sh) { + while (sh && (!u || u->ship!=sh)) { + xmlAddChild(node, xml_ship(ctx, sr, sh, NULL)); + sh = sh->next; + } + if (sh) { + child = xmlAddChild(node, xml_ship(ctx, sr, sh, u)); + while (u && u->ship==sh) { + xmlAddChild(child, xml_unit(ctx, u, sr->mode)); + u = u->next; + } + sh = sh->next; + } + } + } + return node; +} + +static xmlNodePtr +report_root(report_context * ctx) +{ + const faction_list * address; + region * r = ctx->first, * rend = ctx->last; + xml_context* xct = (xml_context*)ctx->userdata; + xmlNodePtr node, child, xmlReport = xmlNewNode(NULL, BAD_CAST "atlantis"); + const char * mailto = locale_string(ctx->f->locale, "mailto"); + const char * mailcmd = locale_string(ctx->f->locale, "mailcmd"); + char zText[128]; + /* TODO: locale, age, options, messages */ + + xct->ns_xml = xmlNewNs(xmlReport, XML_XML_NAMESPACE, BAD_CAST "xml"); + xct->ns_atl = xmlNewNs(xmlReport, XML_ATL_NAMESPACE, NULL); + xmlSetNs(xmlReport, xct->ns_atl); + + node = xmlAddChild(xmlReport, xmlNewNode(xct->ns_atl, BAD_CAST "server")); + if (mailto) { + snprintf(zText, sizeof(zText), "mailto:%s?subject=%s", mailto, mailcmd); + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "delivery")); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "method", BAD_CAST "mail"); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "href", BAD_CAST zText); + } + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "game", (xmlChar *)global.gamename); + strftime(zText, sizeof(zText), "%Y-%m-%dT%H:%M:%SZ", gmtime(&ctx->report_time)); + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "time", (xmlChar *)zText); + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "turn", (xmlChar *)itoab(turn, 10)); + + + for (address=ctx->addresses;address;address=address->next) { + xmlAddChild(xmlReport, xml_faction(ctx, address->data)); + } + + for (;r!=rend;r=r->next) { + seen_region * sr = find_seen(ctx->seen, r); + if (sr!=NULL) xmlAddChild(xmlReport, xml_region(ctx, sr)); + } + return xmlReport; +}; + +/* main function of the xmlreport. creates the header and traverses all regions */ +static int +report_xml(const char * filename, report_context * ctx, const char * encoding) +{ + xml_context xct; + xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); + + xct.doc = doc; + assert(ctx->userdata==NULL); + ctx->userdata = &xct; + + xmlDocSetRootElement(doc, report_root(ctx)); + xmlKeepBlanksDefault(0); + xmlSaveFormatFileEnc(filename, doc, "utf-8", 1); + xmlFreeDoc(doc); + + ctx->userdata = NULL; + + return 0; +} + +void +register_xr(void) +{ + register_reporttype("xml", &report_xml, 1< + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2005 | Enno Rehling + +-------------------+ + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#ifndef H_GC_XMLREPORT +#define H_GC_XMLREPORT +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern void xmlreport_cleanup(void); +extern void register_xr(void); + +extern int crwritemap(const char * filename); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/gmtool.c b/src/gmtool.c new file mode 100644 index 000000000..5d1ce1227 --- /dev/null +++ b/src/gmtool.c @@ -0,0 +1,1298 @@ +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2006 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +/* wenn platform.h nicht vor curses included wird, kompiliert es unter windows nicht */ +#include +#include +#include + +#include "gmtool.h" +#include "gmtool_structs.h" + +#include +#include +#if MUSEUM_MODULE +#include +#endif +#if ARENA_MODULE +#include +#endif +#include +#include +#if DUNGEON_MODULE +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +static int g_quit; +int force_color = 0; + +state * current_state = NULL; + +#define IFL_SHIPS (1<<0) +#define IFL_UNITS (1<<1) +#define IFL_FACTIONS (1<<2) +#define IFL_BUILDINGS (1<<3) + +static WINDOW * hstatus; + +static void +init_curses(void) +{ + short fg, bg; + initscr(); + + if (has_colors() || force_color) { + short bcol = COLOR_BLACK; + short hcol = COLOR_MAGENTA; + start_color(); +#ifdef WIN32 + /* looks crap on putty with TERM=linux */ + if (can_change_color()) { + init_color(COLOR_YELLOW, 1000, 1000, 0); + } +#endif + + for (fg=0;fg!=8;++fg) { + for (bg=0;bg!=2;++bg) { + init_pair(fg+8*bg, fg, bg?hcol:bcol); + } + } + + attrset(COLOR_PAIR(COLOR_BLACK)); + bkgd(' ' | COLOR_PAIR(COLOR_BLACK)); + bkgdset(' ' | COLOR_PAIR(COLOR_BLACK)); + } + + keypad(stdscr, TRUE); /* enable keyboard mapping */ + meta(stdscr, TRUE); + nonl(); /* tell curses not to do NL->CR/NL on output */ + cbreak(); /* take input chars one at a time, no wait for \n */ + noecho(); /* don't echo input */ + scrollok(stdscr, FALSE); + refresh(); +} + +void cnormalize(const coordinate * c, int * x, int * y) +{ + *x = c->x; + *y = c->y; + pnormalize(x, y, c->pl); +} + +map_region * +mr_get(const view * vi, int xofs, int yofs) +{ + return vi->regions + xofs + yofs * vi->size.width; +} + +static point * +coor2point(const coordinate * c, point * p) +{ + assert(c && p); + p->x = c->x * TWIDTH + c->y * TWIDTH / 2; + p->y = c->y * THEIGHT; + return p; +} + +static window * wnd_first, * wnd_last; + +static window * +win_create(WINDOW * hwin) +{ + window * wnd = calloc(1, sizeof(window)); + wnd->handle = hwin; + if (wnd_first!=NULL) { + wnd->next = wnd_first; + wnd_first->prev = wnd; + wnd_first = wnd; + } else { + wnd_first = wnd; + wnd_last = wnd; + } + return wnd; +} + +static void +untag_region(selection * s, int nx, int ny) +{ + unsigned int key = ((nx << 12) ^ ny); + tag ** tp = &s->tags[key & (MAXTHASH-1)]; + tag * t = NULL; + while (*tp) { + t = *tp; + if (t->coord.x==nx && t->coord.y==ny) break; + tp=&t->nexthash; + } + if (!*tp) return; + *tp = t->nexthash; + free(t); + return; +} + +static void +tag_region(selection * s, int nx, int ny) +{ + unsigned int key = ((nx << 12) ^ ny); + tag ** tp = &s->tags[key & (MAXTHASH-1)]; + while (*tp) { + tag * t = *tp; + if (t->coord.x==nx && t->coord.y==ny) return; + tp=&t->nexthash; + } + *tp = calloc(1, sizeof(tag)); + (*tp)->coord.x = nx; + (*tp)->coord.y = ny; + (*tp)->coord.pl = findplane(nx, ny); + return; +} + +static int +tagged_region(selection * s, int nx, int ny) +{ + unsigned int key = ((nx << 12) ^ ny); + tag ** tp = &s->tags[key & (MAXTHASH-1)]; + while (*tp) { + tag * t = *tp; + if (t->coord.x==nx && t->coord.y==ny) return 1; + tp=&t->nexthash; + } + return 0; +} + +static int +mr_tile(const map_region * mr, int highlight) +{ + int hl = 8 * highlight; + if (mr!=NULL && mr->r!=NULL) { + const region * r = mr->r; + switch (r->terrain->_name[0]) { + case 'o' : + return '.' | COLOR_PAIR(hl + COLOR_CYAN); + case 'd' : + return 'D' | COLOR_PAIR(hl + COLOR_YELLOW) | A_BOLD; + case 't' : + return '%' | COLOR_PAIR(hl + COLOR_YELLOW) | A_BOLD; + case 'f' : + if (r->terrain->_name[1]=='o') { /* fog */ + return '.' | COLOR_PAIR(hl + COLOR_YELLOW) | A_NORMAL; + } else if (r->terrain->_name[1]=='i') { /* firewall */ + return '%' | COLOR_PAIR(hl + COLOR_RED) | A_BOLD; + } + case 'h' : + return 'H' | COLOR_PAIR(hl + COLOR_YELLOW) | A_NORMAL; + case 'm' : + return '^' | COLOR_PAIR(hl + COLOR_WHITE) | A_NORMAL; + case 'p' : + if (r_isforest(r)) return '#' | COLOR_PAIR(hl + COLOR_GREEN) | A_NORMAL; + return '+' | COLOR_PAIR(hl + COLOR_GREEN) | A_BOLD; + case 'g' : + return '*' | COLOR_PAIR(hl + COLOR_WHITE) | A_BOLD; + case 's' : + return 'S' | COLOR_PAIR(hl + COLOR_MAGENTA) | A_NORMAL; + } + return r->terrain->_name[0] | COLOR_PAIR(hl + COLOR_RED); + } + return ' ' | COLOR_PAIR(hl + COLOR_WHITE); +} + +static void +paint_map(window * wnd, const state * st) +{ + WINDOW * win = wnd->handle; + int lines = getmaxy(win); + int cols = getmaxx(win); + int vx, vy; + + lines = lines/THEIGHT; + cols = cols/TWIDTH; + for (vy = 0; vy!=lines; ++vy) { + int yp = (lines - vy - 1) * THEIGHT; + for (vx = 0; vx!=cols; ++vx) { + map_region * mr = mr_get(&st->display, vx, vy); + int attr = 0; + int hl = 0; + int xp = vx * TWIDTH + (vy & 1) * TWIDTH/2; + int nx, ny; + if (mr) { + if (st) { + cnormalize(&mr->coord, &nx, &ny); + if (tagged_region(st->selected, nx, ny)) { + attr |= A_REVERSE; + } + } + if (mr->r && mr->r->flags & RF_MAPPER_HIGHLIGHT) hl = 1; + mvwaddch(win, yp, xp, mr_tile(mr, hl) | attr); + } + } + } +} + +map_region * +cursor_region(const view * v, const coordinate * c) +{ + coordinate relpos; + int cx, cy; + + if (c) { + relpos.x = c->x - v->topleft.x; + relpos.y = c->y - v->topleft.y; + cy = relpos.y; + cx = relpos.x + cy/2; + return mr_get(v, cx, cy); + } + return NULL; +} + +static void +draw_cursor(WINDOW * win, selection * s, const view * v, const coordinate * c, int show) +{ + int lines = getmaxy(win)/THEIGHT; + int xp, yp, nx, ny; + int attr = 0; + map_region * mr = cursor_region(v, c); + coordinate relpos; + int cx, cy; + + if (!mr) return; + + relpos.x = c->x - v->topleft.x; + relpos.y = c->y - v->topleft.y; + cy = relpos.y; + cx = relpos.x + cy/2; + + yp = (lines - cy - 1) * THEIGHT; + xp = cx * TWIDTH + (cy & 1) * TWIDTH/2; + cnormalize(&mr->coord, &nx, &ny); + if (s && tagged_region(s, nx, ny)) attr = A_REVERSE; + if (mr->r) { + int hl = 0; + if (mr->r->flags & RF_MAPPER_HIGHLIGHT) hl = 1; + mvwaddch(win, yp, xp, mr_tile(mr, hl) | attr); + } + else mvwaddch(win, yp, xp, ' ' | attr | COLOR_PAIR(COLOR_YELLOW)); + if (show) { + attr = A_BOLD; + mvwaddch(win, yp, xp-1, '<' | attr | COLOR_PAIR(COLOR_YELLOW)); + mvwaddch(win, yp, xp+1, '>' | attr | COLOR_PAIR(COLOR_YELLOW)); + } else { + attr = A_NORMAL; + mvwaddch(win, yp, xp-1, ' ' | attr | COLOR_PAIR(COLOR_WHITE)); + mvwaddch(win, yp, xp+1, ' ' | attr | COLOR_PAIR(COLOR_WHITE)); + } + wmove(win, yp, xp); + wnoutrefresh(win); +} + + + +static void +paint_status(window * wnd, const state * st) +{ + WINDOW * win = wnd->handle; + const char * name = ""; + int nx, ny, uid = 0; + const char * terrain = "----"; + map_region * mr = cursor_region(&st->display, &st->cursor); + if (mr && mr->r) { + uid = mr->r->uid; + if (mr->r->land) { + name = (const char *)mr->r->land->name; + } else { + name = mr->r->terrain->_name; + } + terrain = mr->r->terrain->_name; + } + cnormalize(&st->cursor, &nx, &ny); + mvwprintw(win, 0, 0, "%4d %4d | %.4s | %.20s (%d)", nx, ny, terrain, name, uid); + wclrtoeol(win); +} + +static boolean +handle_info_region(window * wnd, state * st, int c) +{ + return false; +} + +static void +paint_info_region(window * wnd, const state * st) +{ + WINDOW * win = wnd->handle; + int size = getmaxx(win)-2; + int line = 0, maxline = getmaxy(win)-2; + map_region * mr = cursor_region(&st->display, &st->cursor); + + unused(st); + werase(win); + wxborder(win); + if (mr && mr->r) { + const region * r = mr->r; + if (r->land) { + mvwaddnstr(win, line++, 1, (char *)r->land->name, size); + } else { + mvwaddnstr(win, line++, 1, r->terrain->_name, size); + } + line++; + mvwprintw(win, line++, 1, "%s, age %d", r->terrain->_name, r->age); + if (r->land) { + mvwprintw(win, line++, 1, "$:%6d P:%5d", r->land->money, r->land->peasants); + mvwprintw(win, line++, 1, "H:%6d %s:%5d", r->land->horses, (r->flags&RF_MALLORN)?"M":"T", r->land->trees[1]+r->land->trees[2]); + } + line++; + if (r->ships && (st->info_flags & IFL_SHIPS)) { + ship * sh; + wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + mvwaddnstr(win, line++, 1, "* ships:", size-5); + wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + for (sh=r->ships;sh && linenext) { + mvwprintw(win, line, 1, "%.4s ", itoa36(sh->no)); + mvwaddnstr(win, line++, 6, (char*)sh->type->name[0], size-5); + } + } + if (r->units && (st->info_flags & IFL_FACTIONS)) { + unit * u; + wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + mvwaddnstr(win, line++, 1, "* factions:", size-5); + wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + for (u=r->units;u && linenext) { + if (!fval(u->faction, FFL_MARK)) { + mvwprintw(win, line, 1, "%.4s ", itoa36(u->faction->no)); + mvwaddnstr(win, line++, 6, (char *)u->faction->name, size-5); + fset(u->faction, FFL_MARK); + } + } + for (u=r->units;u && linenext) { + freset(u->faction, FFL_MARK); + } + } + if (r->units && (st->info_flags & IFL_UNITS)) { + unit * u; + wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + mvwaddnstr(win, line++, 1, "* units:", size-5); + wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + for (u=r->units;u && linenext) { + mvwprintw(win, line, 1, "%.4s ", itoa36(u->no)); + mvwaddnstr(win, line++, 6, (char *)u->name, size-5); + } + } + } +} + +static void (*paint_info)(struct window * wnd, const struct state * st); + +static void +paint_info_default(window * wnd, const state * st) +{ + if (paint_info) paint_info(wnd, st); + else paint_info_region(wnd, st); +} + +void set_info_function(void (*callback)(struct window *, const struct state *)) +{ + paint_info = callback; +} + +static char * +askstring(WINDOW * win, const char * q, char * buffer, size_t size) +{ + werase(win); + mvwaddstr(win, 0, 0, (char*)q); + wmove(win, 0, (int)(strlen(q)+1)); + echo(); + wgetnstr(win, buffer, (int)size); + noecho(); + return buffer; +} + +static void +statusline(WINDOW * win, const char * str) +{ + mvwaddstr(win, 0, 0, (char*)str); + wclrtoeol(win); + wnoutrefresh(win); +} + +static void +terraform_at(coordinate * c, const terrain_type *terrain) +{ + if (terrain!=NULL) { + region * r; + int nx = c->x, ny = c->y; + pnormalize(&nx, &ny, c->pl); + r = findregion(nx, ny); + if (r==NULL) { + r = new_region(nx, ny, c->pl, 0); + } + terraform_region(r, terrain); + } +} + +static void +terraform_selection(selection * selected, const terrain_type *terrain) +{ + int i; + + if (terrain==NULL) return; + for (i=0;i!=MAXTHASH;++i) { + tag ** tp = &selected->tags[i]; + while (*tp) { + region * r; + tag * t = *tp; + int nx = t->coord.x, ny = t->coord.y; + plane * pl = t->coord.pl; + + pnormalize(&nx, &ny, pl); + r = findregion(nx, ny); + if (r==NULL) { + r = new_region(nx, ny, pl, 0); + } + terraform_region(r, terrain); + tp = &t->nexthash; + } + } +} + +static faction * +select_faction(state * st) +{ + list_selection *prev, *ilist = NULL, **iinsert; + list_selection *selected = NULL; + faction * f = factions; + + if (!f) return NULL; + iinsert = &ilist; + prev = ilist; + + while (f) { + char buffer[32]; + sprintf(buffer, "%.4s %.26s", itoa36(f->no), f->name); + insert_selection(iinsert, NULL, buffer, (void*)f); + f = f->next; + } + selected = do_selection(ilist, "Select Faction", NULL, NULL); + st->wnd_info->update |= 1; + st->wnd_map->update |= 1; + st->wnd_status->update |= 1; + + if (selected==NULL) return NULL; + return (faction*)selected->data; +} + +static const terrain_type * +select_terrain(state * st, const terrain_type * default_terrain) +{ + list_selection *prev, *ilist = NULL, **iinsert; + list_selection *selected = NULL; + const terrain_type * terrain = terrains(); + + if (!terrain) return NULL; + iinsert = &ilist; + prev = ilist; + + while (terrain) { + insert_selection(iinsert, NULL, terrain->_name, (void*)terrain); + terrain = terrain->next; + } + selected = do_selection(ilist, "Terrain", NULL, NULL); + st->wnd_info->update |= 1; + st->wnd_map->update |= 1; + st->wnd_status->update |= 1; + + if (selected==NULL) return NULL; + return (const terrain_type*)selected->data; +} + +static coordinate * +region2coord(const region * r, coordinate * c) +{ + c->x = r->x; + c->y = r->y; + c->pl = rplane(r); + return c; +} + +#ifdef __PDCURSES__ +#define FAST_UP CTL_UP +#define FAST_DOWN CTL_DOWN +#define FAST_LEFT CTL_LEFT +#define FAST_RIGHT CTL_RIGHT +#else +#define FAST_UP KEY_PPAGE +#define FAST_DOWN KEY_NPAGE +#define FAST_LEFT KEY_SLEFT +#define FAST_RIGHT KEY_SRIGHT +#endif + +void +highlight_region(region *r, int toggle) +{ + if (r!=NULL) { + if (toggle) r->flags |= RF_MAPPER_HIGHLIGHT; + else r->flags &= ~RF_MAPPER_HIGHLIGHT; + } +} + +void +select_coordinate(struct selection * selected, int nx, int ny, int toggle) +{ + if (toggle) tag_region(selected, nx, ny); + else untag_region(selected, nx, ny); +} + +enum { MODE_MARK, MODE_SELECT, MODE_UNMARK, MODE_UNSELECT }; + +static void +select_regions(state * st, int selectmode) +{ + char sbuffer[80]; + int findmode; + const char * statustext[] = { + "mark-", "select-", "unmark-", "deselect-" + }; + const char * status = statustext[selectmode]; + statusline(st->wnd_status->handle, status); + doupdate(); + findmode = getch(); + if (findmode=='n') { /* none */ + int i; + sprintf(sbuffer, "%snone", status); + statusline(st->wnd_status->handle, sbuffer); + if (selectmode&MODE_SELECT) { + for (i=0;i!=MAXTHASH;++i) { + tag ** tp = &st->selected->tags[i]; + while (*tp) { + tag * t = *tp; + *tp = t->nexthash; + free(t); + } + } + } else { + region * r; + for (r=regions;r;r=r->next) { + r->flags &= ~RF_MAPPER_HIGHLIGHT; + } + } + } + else if (findmode=='m') { + region * r; + sprintf(sbuffer, "%smonsters", status); + statusline(st->wnd_status->handle, sbuffer); + for (r=regions;r;r=r->next) { + unit * u = r->units; + for (;u;u=u->next) { + if (fval(u->faction, FFL_NPC)!=0) break; + } + if (u) { + 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=='p') { + region * r; + sprintf(sbuffer, "%splayers", status); + statusline(st->wnd_status->handle, sbuffer); + for (r=regions;r;r=r->next) { + unit * u = r->units; + for (;u;u=u->next) { + if (fval(u->faction, FFL_NPC)==0) break; + } + if (u) { + 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=='u') { + region * r; + sprintf(sbuffer, "%sunits", status); + statusline(st->wnd_status->handle, sbuffer); + for (r=regions;r;r=r->next) { + if (r->units) { + 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=='s') { + region * r; + sprintf(sbuffer, "%sships", status); + statusline(st->wnd_status->handle, sbuffer); + for (r=regions;r;r=r->next) { + if (r->ships) { + 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=='f') { + char fbuffer[12]; + sprintf(sbuffer, "%sfaction:", status); + askstring(st->wnd_status->handle, sbuffer, fbuffer, 12); + if (fbuffer[0]) { + faction * f = findfaction(atoi36(fbuffer)); + + if (f!=NULL) { + unit * u; + + sprintf(sbuffer, "%sfaction: %s", status, itoa36(f->no)); + statusline(st->wnd_status->handle, sbuffer); + for (u=f->units;u;u=u->nextF) { + region * r = u->region; + if (selectmode&MODE_SELECT) { + select_coordinate(st->selected, r->x, r->y, selectmode==MODE_SELECT); + } else { + highlight_region(r, selectmode==MODE_MARK); + } + } + } else { + statusline(st->wnd_status->handle, "faction not found."); + beep(); + return; + } + } + } + else if (findmode=='t') { + const struct terrain_type * terrain; + sprintf(sbuffer, "%sterrain: ", status); + statusline(st->wnd_status->handle, sbuffer); + terrain = select_terrain(st, NULL); + if (terrain!=NULL) { + region * r; + sprintf(sbuffer, "%sterrain: %s", status, terrain->_name); + statusline(st->wnd_status->handle, sbuffer); + for (r=regions;r;r=r->next) { + if (r->terrain==terrain) { + if (selectmode&MODE_SELECT) { + select_coordinate(st->selected, r->x, r->y, selectmode==MODE_SELECT); + } else { + highlight_region(r, selectmode==MODE_MARK); + } + } + } + } + } else { + statusline(st->wnd_status->handle, "unknown command."); + beep(); + return; + } + st->wnd_info->update |= 3; + st->wnd_status->update |= 3; + st->wnd_map->update |= 3; +} + +static void +handlekey(state * st, int c) +{ + window * wnd; + coordinate * cursor = &st->cursor; + static char locate[80]; + static int findmode = 0; + region *r; + char sbuffer[80]; + static char kbuffer[80]; + int n, nx, ny; + + switch(c) { + case FAST_RIGHT: + cursor->x+=10; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case FAST_LEFT: + cursor->x-=10; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case FAST_UP: + cursor->y+=10; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case FAST_DOWN: + cursor->y-=10; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case KEY_UP: + cursor->y++; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case KEY_DOWN: + cursor->y--; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case KEY_RIGHT: + cursor->x++; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case KEY_LEFT: + cursor->x--; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case 'S': + case KEY_SAVE: + case KEY_F(2): + /* if (st->modified) */ { + char datafile[MAX_PATH]; + + askstring(st->wnd_status->handle, "save as:", datafile, sizeof(datafile)); + if (strlen(datafile)>0) { + create_backup(datafile); + remove_empty_units(); + writegame(datafile, IO_DEFAULT); + st->modified = 0; + } + } + break; + case 'B': + /* + make_block(st->cursor.x, st->cursor.y, 6, select_terrain(st, NULL)); + */ + cnormalize(&st->cursor, &nx, &ny); + n = rng_int() % 8 + 8; + build_island_e3(nx, ny, n, n*3); + st->modified = 1; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + break; + case 0x02: /* CTRL+b */ + cnormalize(&st->cursor, &nx, &ny); + make_block(nx, ny, 6, newterrain(T_OCEAN)); + st->modified = 1; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + break; + case 0x09: /* tab = next selected*/ + if (regions!=NULL) { + map_region * mr = cursor_region(&st->display, cursor); + if (mr) { + region * first = mr->r; + region * cur = (first&&first->next)?first->next:regions; + + while (cur!=first) { + coordinate coord; + region2coord(cur, &coord); + cnormalize(&coord, &nx, &ny); + if (tagged_region(st->selected, nx, ny)) { + st->cursor = coord; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + } + cur = cur->next; + if (!cur && first) cur = regions; + } + } + } + break; + + case 'p': + if (planes) { + plane * pl = planes; + if (cursor->pl) { + while (pl && pl!=cursor->pl) { + pl = pl->next; + } + if (pl && pl->next) { + cursor->pl = pl->next; + } else { + cursor->pl = get_homeplane(); + } + } else { + cursor->pl = planes; + } + } + break; + + case 'a': + if (regions!=NULL) { + map_region * mr = cursor_region(&st->display, cursor); + if (mr && mr->r) { + region * cur = mr->r; + plane * pl = rplane(cur); + if (pl==NULL) { + cur = r_standard_to_astral(cur); + } else if (is_astral(cur)) { + cur = r_astral_to_standard(cur); + } else { + cur = NULL; + } + if (cur!=NULL) { + region2coord(cur, &st->cursor); + } else { + beep(); + } + } + } + break; + case 'g': + askstring(st->wnd_status->handle, "goto-x:", sbuffer, 12); + if (sbuffer[0]) { + askstring(st->wnd_status->handle, "goto-y:", sbuffer+16, 12); + if (sbuffer[16]) { + st->cursor.x = atoi(sbuffer); + st->cursor.y = atoi(sbuffer+16); + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + } + } + break; + case 0x14: /* C-t */ + terraform_at(&st->cursor, select_terrain(st, NULL)); + st->modified = 1; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + break; + case 'I': + statusline(st->wnd_status->handle, "info-"); + doupdate(); + do { + c = getch(); + switch (c) { + case 's': + st->info_flags ^= IFL_SHIPS; + if (st->info_flags & IFL_SHIPS) statusline(st->wnd_status->handle, "info-ships true"); + else statusline(st->wnd_status->handle, "info-ships false"); + break; + case 'b': + st->info_flags ^= IFL_BUILDINGS; + if (st->info_flags & IFL_BUILDINGS) statusline(st->wnd_status->handle, "info-buildings true"); + else statusline(st->wnd_status->handle, "info-buildings false"); + case 'f': + st->info_flags ^= IFL_FACTIONS; + if (st->info_flags & IFL_FACTIONS) statusline(st->wnd_status->handle, "info-factions true"); + else statusline(st->wnd_status->handle, "info-factions false"); + break; + case 'u': + st->info_flags ^= IFL_UNITS; + if (st->info_flags & IFL_UNITS) statusline(st->wnd_status->handle, "info-units true"); + else statusline(st->wnd_status->handle, "info-units false"); + break; + case 27: /* esc */ + break; + default: + beep(); + c = 0; + } + } while (c==0); + break; + case 'L': + if (global.vm_state) { + move(0, 0); + refresh(); + lua_do((struct lua_State*)global.vm_state); + /* todo: do this from inside the script */ + clear(); + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + } + break; + case 12: /* Ctrl-L */ + clear(); + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + break; + case 'h': + select_regions(st, MODE_MARK); + break; + case 'H': + select_regions(st, MODE_UNMARK); + break; + case 't': + select_regions(st, MODE_SELECT); + break; + case 'T': + select_regions(st, MODE_UNSELECT); + break; + case ';': + statusline(st->wnd_status->handle, "tag-"); + doupdate(); + switch (getch()) { + case 't': + terraform_selection(st->selected, select_terrain(st, NULL)); + st->modified = 1; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + break; + case 'm': + break; + default: + statusline(st->wnd_status->handle, "unknown command."); + beep(); + } + break; + case ' ': + cnormalize(cursor, &nx, &ny); + if (tagged_region(st->selected, nx, ny)) untag_region(st->selected, nx, ny); + else tag_region(st->selected, nx, ny); + break; + case 'A': + sprintf(sbuffer, "%s/newfactions", basepath()); + seed_players(sbuffer, false); + st->wnd_map->update |= 1; + break; + case '/': + statusline(st->wnd_status->handle, "find-"); + doupdate(); + findmode = getch(); + if (findmode=='r') { + askstring(st->wnd_status->handle, "find-region:", locate, sizeof(locate)); + } else if (findmode=='u') { + askstring(st->wnd_status->handle, "find-unit:", locate, sizeof(locate)); + } else if (findmode=='f') { + askstring(st->wnd_status->handle, "find-faction:", locate, sizeof(locate)); + } else if (findmode=='F') { + faction * f = select_faction(st); + if (f!=NULL) { + strcpy(locate, itoa36(f->no)); + findmode='f'; + } else { + break; + } + } else { + statusline(st->wnd_status->handle, "unknown command."); + beep(); + break; + } + /* achtung: fall-through ist absicht: */ + if (!strlen(locate)) break; + case 'n': + if (findmode=='u') { + unit * u = findunit(atoi36(locate)); + r = u?u->region:NULL; + } else if (findmode && regions!=NULL) { + struct faction * f = NULL; + map_region * mr = cursor_region(&st->display, cursor); + region * first = (mr && mr->r && mr->r->next)?mr->r->next:regions; + + if (findmode=='f') { + sprintf(sbuffer, "find-faction: %s", locate); + statusline(st->wnd_status->handle, sbuffer); + f = findfaction(atoi36(locate)); + if (f==NULL) { + statusline(st->wnd_status->handle, "faction not found."); + beep(); + break; + } + } + for (r=first;;) { + if (findmode=='r' && r->land && r->land->name && strstr((const char*)r->land->name, locate)) { + break; + } else if (findmode=='f') { + unit * u; + for (u=r->units;u;u=u->next) { + if (u->faction==f) { + break; + } + } + if (u) break; + } + r = r->next; + if (r==NULL) r = regions; + if (r==first) { + r = NULL; + statusline(st->wnd_status->handle, "not found."); + beep(); + break; + } + } + } else { + r = NULL; + } + if (r!=NULL) { + region2coord(r, &st->cursor); + } + break; + case 'Q': + g_quit = 1; + break; + default: + for (wnd=wnd_first;wnd!=NULL;wnd=wnd->next) { + if (wnd->handlekey) { + if (wnd->handlekey(wnd, st, c)) break; + } + } + if (wnd==NULL) { + if (kbuffer[0]==0) { + strcpy(kbuffer, "getch:"); + } + sprintf(sbuffer, " 0x%x", c); + strncat(kbuffer, sbuffer, sizeof(kbuffer)); + statusline(st->wnd_status->handle, kbuffer); + if (strlen(kbuffer)>70) kbuffer[0]=0; + } + break; + } +} + +static void +init_view(view * display, WINDOW * win) +{ + display->topleft.x = 1; + display->topleft.y = 1; + display->topleft.pl = get_homeplane(); + display->pl = get_homeplane(); + display->size.width = getmaxx(win)/TWIDTH; + display->size.height = getmaxy(win)/THEIGHT; + display->regions = calloc(display->size.height * display->size.width, sizeof(map_region)); +} + +static void +update_view(view * vi) +{ + int i, j; + for (i=0;i!=vi->size.width;++i) { + for (j=0;j!=vi->size.height;++j) { + map_region * mr = mr_get(vi, i, j); + mr->coord.x = vi->topleft.x + i - j/2; + mr->coord.y = vi->topleft.y + j; + mr->coord.pl = vi->pl; + pnormalize(&mr->coord.x, &mr->coord.y, mr->coord.pl); + mr->r = findregion(mr->coord.x, mr->coord.y); + } + } +} + +state * +state_open(void) +{ + state * st = calloc(sizeof(state), 1); + st->display.pl = get_homeplane(); + st->cursor.pl = get_homeplane(); + st->cursor.x = 0; + st->cursor.y = 0; + st->selected = calloc(1, sizeof(struct selection)); + st->modified = 0; + st->info_flags = 0xFFFFFFFF; + st->prev = current_state; + current_state = st; + return st; +} + +void +state_close(state * st) +{ + assert(st==current_state); + current_state = st->prev; + free(st); +} + +void +run_mapper(void) +{ + WINDOW * hwinstatus; + WINDOW * hwininfo; + WINDOW * hwinmap; + int width, height, x, y; + int split = 20, old_flags = log_flags; + state * st; + point tl; + + log_flags &= ~(LOG_CPERROR|LOG_CPWARNING); + init_curses(); + curs_set(1); + + set_readline(curses_readline); + + getbegyx(stdscr, x, y); + width = getmaxx(stdscr); + height = getmaxy(stdscr); + + hwinmap = subwin(stdscr, getmaxy(stdscr)-1, getmaxx(stdscr)-split, y, x); + hwininfo = subwin(stdscr, getmaxy(stdscr)-1, split, y, x+getmaxx(stdscr)-split); + hwinstatus = subwin(stdscr, 1, width, height-1, x); + + st = state_open(); + st->wnd_map = win_create(hwinmap); + st->wnd_map->paint = &paint_map; + st->wnd_map->update = 1; + st->wnd_info = win_create(hwininfo); + st->wnd_info->paint = &paint_info_default; + st->wnd_info->handlekey = &handle_info_region; + st->wnd_info->update = 1; + st->wnd_status = win_create(hwinstatus); + st->wnd_status->paint = &paint_status; + st->wnd_status->update = 1; + + init_view(&st->display, hwinmap); + coor2point(&st->display.topleft, &tl); + + hstatus = st->wnd_status->handle; /* the lua console needs this */ + + while (!g_quit) { + int c; + point p; + window * wnd; + view * vi = &st->display; + + getbegyx(hwinmap, x, y); + width = getmaxx(hwinmap)-x; + height = getmaxy(hwinmap)-y; + coor2point(&st->cursor, &p); + + if (st->cursor.pl != vi->pl) { + vi->pl = st->cursor.pl; + st->wnd_map->update |= 1; + } + if (p.y < tl.y) { + vi->topleft.y = st->cursor.y-vi->size.height/2; + st->wnd_map->update |= 1; + } + else if (p.y >= tl.y + vi->size.height * THEIGHT) { + vi->topleft.y = st->cursor.y-vi->size.height/2; + st->wnd_map->update |= 1; + } + if (p.x <= tl.x) { + vi->topleft.x = st->cursor.x+(st->cursor.y-vi->topleft.y)/2-vi->size.width / 2; + st->wnd_map->update |= 1; + } + else if (p.x >= tl.x + vi->size.width * TWIDTH-1) { + vi->topleft.x = st->cursor.x+(st->cursor.y-vi->topleft.y)/2-vi->size.width / 2; + st->wnd_map->update |= 1; + } + + if (st->wnd_map->update) { + update_view(vi); + coor2point(&vi->topleft, &tl); + } + for (wnd=wnd_last;wnd!=NULL;wnd=wnd->prev) { + if (wnd->update && wnd->paint) { + if (wnd->update & 1) { + wnd->paint(wnd, st); + wnoutrefresh(wnd->handle); + } + if (wnd->update & 2) { + touchwin(wnd->handle); + } + wnd->update = 0; + } + } + draw_cursor(st->wnd_map->handle, st->selected, vi, &st->cursor, 1); + doupdate(); + c = getch(); + draw_cursor(st->wnd_map->handle, st->selected, vi, &st->cursor, 0); + handlekey(st, c); + } + g_quit = 0; + set_readline(NULL); + curs_set(1); + endwin(); + log_flags = old_flags; + state_close(st); +} + +int +curses_readline(struct lua_State * L, char * buffer, size_t size, const char * prompt) +{ + unused(L); + askstring(hstatus, prompt, buffer, size); + return buffer[0]!=0; +} + + +void +seed_players(const char * filename, boolean new_island) +{ + newfaction * players = read_newfactions(filename); + if (players!=NULL) { + while (players) { + int n = listlen(players); + int k = (n+ISLANDSIZE-1)/ISLANDSIZE; + k = n / k; + n = autoseed(&players, k, new_island?0:TURNS_PER_ISLAND); + if (n==0) { + break; + } + } + } +} + +void +make_block(int x, int y, int radius, const struct terrain_type * terrain) +{ + int cx, cy; + region *r; + plane * pl = findplane(x, y); + + if (terrain==NULL) return; + + for (cx = x - radius; cx != x+radius; ++cx) { + for (cy = y - radius; cy != y+radius; ++cy) { + int nx = cx, ny = cy; + pnormalize(&nx, &ny, pl); + if (koor_distance(nx, ny, x, y) < radius) { + if (!findregion(nx, ny)) { + r = new_region(nx, ny, pl, 0); + terraform_region(r, terrain); + } + } + } + } +} diff --git a/src/gmtool.h b/src/gmtool.h new file mode 100644 index 000000000..1912e03ee --- /dev/null +++ b/src/gmtool.h @@ -0,0 +1,41 @@ +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2006 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +#ifndef H_GMTOOL +#define H_GMTOOL + +#ifdef __cplusplus +extern "C" { +#endif + struct lua_State; + struct selection; + struct state; + struct region; + + int gmmain(int argc, char *argv[]); + int curses_readline(struct lua_State * L, char * buffer, size_t size, const char * prompt); + + void highlight_region(struct region *r, int on); + void select_coordinate(struct selection * selected, int x, int y, int on); + void run_mapper(void); + + int force_color; + + struct state * state_open(void); + void state_close(struct state * ); + + void make_block(int x, int y, int radius, const struct terrain_type * terrain); + void seed_players(const char * filename, boolean new_island); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/gmtool.vcproj b/src/gmtool.vcproj new file mode 100644 index 000000000..b2d178c58 --- /dev/null +++ b/src/gmtool.vcproj @@ -0,0 +1,314 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gmtool_structs.h b/src/gmtool_structs.h new file mode 100644 index 000000000..129be7775 --- /dev/null +++ b/src/gmtool_structs.h @@ -0,0 +1,102 @@ +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2006 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +#ifndef H_GMTOOL_STRUCTS +#define H_GMTOOL_STRUCTS + +#ifdef __cplusplus +extern "C" { +#endif + +/* types imported from eressea: */ +struct region; + +typedef struct extent { + /* Ein Vektor */ + int width, height; +} extent; + +typedef struct point { + /* Eine Koordinate in einer Ascii-Karte */ + int x, y; +} point; + +typedef struct coordinate { + /* Eine Koordinate im Editor, nicht normalisiert */ + int x, y; + struct plane * pl; +} coordinate; + +typedef struct map_region { + struct region * r; + coordinate coord; +} map_region; + +typedef struct view { + struct map_region * regions; + struct plane * pl; + coordinate topleft; /* upper left corner in map. */ + extent size; /* dimensions. */ +} view; + +typedef struct tag { + coordinate coord; + struct tag * nexthash; +} tag; + +#define MAXTHASH 512 + +typedef struct selection { + tag * tags[MAXTHASH]; +} selection; + +typedef struct state { + coordinate cursor; + selection * selected; + struct state * prev; + view display; + int modified; + unsigned int info_flags; + struct window * wnd_info; + struct window * wnd_map; + struct window * wnd_status; +} state; + +typedef struct window { + boolean (*handlekey)(struct window * win, struct state * st, int key); + void (*paint)(struct window * win, const struct state * st); + + WINDOW * handle; + struct window * next; + struct window * prev; + boolean initialized; + int update; +} window; + +extern map_region * cursor_region(const view * v, const coordinate * c); +extern void cnormalize(const coordinate * c, int * x, int * y); +extern state * current_state; + +extern void set_info_function(void (*callback)(struct window *, const struct state *)); + +#define TWIDTH 2 /* width of tile */ +#define THEIGHT 1 /* height of tile */ + +#ifdef WIN32 +#define wxborder(win) wborder(win, 0, 0, 0, 0, 0, 0, 0, 0) +#else +#define wxborder(win) wborder(win, '|', '|', '-', '-', '+', '+', '+', '+') +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/items/artrewards.c b/src/items/artrewards.c new file mode 100644 index 000000000..06b152f6b --- /dev/null +++ b/src/items/artrewards.c @@ -0,0 +1,157 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "artrewards.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +#define HORNRANGE 10 +#define HORNDURATION 3 +#define HORNIMMUNITY 30 + +static int +age_peaceimmune(attrib * a) +{ + return (--a->data.i>0)?AT_AGE_KEEP:AT_AGE_REMOVE; +} + +static attrib_type at_peaceimmune = { + "peaceimmune", + NULL, NULL, + age_peaceimmune, + a_writeint, + a_readint +}; + +static int +use_hornofdancing(struct unit * u, const struct item_type * itype, + int amount, struct order * ord) +{ + region *r; + int regionsPacified = 0; + + for(r=regions; r; r=r->next) { + if(distance(u->region, r) < HORNRANGE) { + if(a_find(r->attribs, &at_peaceimmune) == NULL) { + attrib *a; + + create_curse(u, &r->attribs, ct_find("peacezone"), + 20, HORNDURATION, 1.0, 0); + + a = a_add(&r->attribs, a_new(&at_peaceimmune)); + a->data.i = HORNIMMUNITY; + + ADDMSG(&r->msgs, msg_message("hornofpeace_r_success", + "unit region", u, u->region)); + + regionsPacified++; + } else { + ADDMSG(&r->msgs, msg_message("hornofpeace_r_nosuccess", + "unit region", u, u->region)); + } + } + } + + if(regionsPacified > 0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "hornofpeace_u_success", + "pacified", regionsPacified)); + } else { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "hornofpeace_u_nosuccess", "")); + } + + return 0; +} + +#define SPEEDUP 2 + + +static int +useonother_trappedairelemental(struct unit * u, int shipId, + const struct item_type * itype, + int amount, struct order * ord) +{ + curse *c; + ship *sh; + + if (shipId <= 0) { + cmistake(u, ord, 20, MSG_MOVE); + return -1; + } + + sh = findshipr(u->region, shipId); + if(!sh) { + cmistake(u, ord, 20, MSG_MOVE); + return -1; + } + + c = create_curse(u, &sh->attribs, ct_find("shipspeedup"), 20, INT_MAX, SPEEDUP, 0); + c_setflag(c, CURSE_NOAGE); + + ADDMSG(&u->faction->msgs, msg_message("trappedairelemental_success", + "unit region command ship", u, u->region, ord, sh)); + + use_pooled(u, itype->rtype, GET_DEFAULT, 1); + + return 0; +} + +static int +use_trappedairelemental(struct unit * u, + const struct item_type * itype, + int amount, struct order * ord) +{ + ship *sh = u->ship; + + if(sh == NULL) { + cmistake(u, ord, 20, MSG_MOVE); + return -1; + } + return useonother_trappedairelemental(u, sh->no, itype, amount,ord); +} + +void +register_artrewards(void) +{ + at_register(&at_peaceimmune); + register_item_use(use_hornofdancing, "use_hornofdancing"); + register_item_use(use_trappedairelemental, "use_trappedairelemental"); + register_item_useonother(useonother_trappedairelemental, "useonother_trappedairelemental"); +} diff --git a/src/items/artrewards.h b/src/items/artrewards.h new file mode 100644 index 000000000..552a3b27a --- /dev/null +++ b/src/items/artrewards.h @@ -0,0 +1,30 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ITM_ARTREWARDS +#define H_ITM_ARTREWARDS +#ifdef __cplusplus +extern "C" { +#endif + +extern void register_artrewards(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/demonseye.c b/src/items/demonseye.c new file mode 100644 index 000000000..6c6ddee15 --- /dev/null +++ b/src/items/demonseye.c @@ -0,0 +1,64 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "demonseye.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include + +/* libc includes */ +#include + +static int +summon_igjarjuk(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + struct plane * p = rplane(u->region); + unused(amount); + unused(itype); + if (p!=NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "use_realworld_only", "")); + return EUNUSABLE; + } else { + assert(!"not implemented"); + return EUNUSABLE; + } +} + +static int +give_igjarjuk(struct unit * src, struct unit * d, const struct item_type * itype, int n, struct order * ord) +{ + ADDMSG(&src->faction->msgs, msg_feedback(src, ord, "error_giveeye", "")); + return 0; +} + +void +register_demonseye(void) +{ + register_item_use(summon_igjarjuk, "useigjarjuk"); + register_item_give(give_igjarjuk, "giveigjarjuk"); +} diff --git a/src/items/demonseye.h b/src/items/demonseye.h new file mode 100644 index 000000000..be802d6dc --- /dev/null +++ b/src/items/demonseye.h @@ -0,0 +1,30 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ITM_DEMONSEYE +#define H_ITM_DEMONSEYE +#ifdef __cplusplus +extern "C" { +#endif + +extern void register_demonseye(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/itemtypes.c b/src/items/itemtypes.c new file mode 100644 index 000000000..af0efe305 --- /dev/null +++ b/src/items/itemtypes.c @@ -0,0 +1,38 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "itemtypes.h" + +#include "xerewards.h" +#include "artrewards.h" +#include "phoenixcompass.h" +#include "weapons.h" +#include "seed.h" + +void +register_itemtypes(void) +{ + /* registering misc. functions */ + register_weapons(); + register_xerewards(); + register_artrewards(); + register_phoenixcompass(); +} + +void +init_itemtypes(void) +{ + init_seed(); + init_mallornseed(); +} diff --git a/src/items/itemtypes.h b/src/items/itemtypes.h new file mode 100644 index 000000000..1cc8fecec --- /dev/null +++ b/src/items/itemtypes.h @@ -0,0 +1,25 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_ITM_ITEMS +#define H_ITM_ITEMS +#ifdef __cplusplus +extern "C" { +#endif + +extern void init_itemtypes(void); +extern void register_itemtypes(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/phoenixcompass.c b/src/items/phoenixcompass.c new file mode 100644 index 000000000..ffe208797 --- /dev/null +++ b/src/items/phoenixcompass.c @@ -0,0 +1,129 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "phoenixcompass.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +static int +use_phoenixcompass(struct unit * u, const struct item_type * itype, + int amount, struct order * ord) +{ + region *r; + unit *closest_phoenix = NULL; + int closest_phoenix_distance = INT_MAX; + boolean confusion = false; + direction_t direction; + unit *u2; + direction_t closest_neighbour_direction = 0; + static race * rc_phoenix = NULL; + + if (rc_phoenix==NULL) { + rc_phoenix = rc_find("phoenix"); + if (rc_phoenix==NULL) return 0; + } + + /* find the closest phoenix. */ + + for(r=regions; r; r=r->next) { + for(u2=r->units; u2; u2=u2->next) { + if (u2->race == rc_phoenix) { + if(closest_phoenix == NULL) { + closest_phoenix = u2; + closest_phoenix_distance = distance(u->region, closest_phoenix->region); + } else { + int dist = distance(u->region, r); + if(dist < closest_phoenix_distance) { + closest_phoenix = u2; + closest_phoenix_distance = dist; + confusion = false; + } else if(dist == closest_phoenix_distance) { + confusion = true; + } + } + } + } + } + + /* no phoenix found at all.* if confusion == true more than one phoenix + * at the same distance was found and the device is confused */ + + if(closest_phoenix == NULL + || closest_phoenix->region == u->region + || confusion == true) { + add_message(&u->faction->msgs, msg_message("phoenixcompass_confusion", + "unit region command", u, u->region, ord)); + return 0; + } + + /* else calculate the direction. this is tricky. we calculate the + * neighbouring region which is closest to the phoenix found. hardcoded + * for readability. */ + + for(direction = 0; direction < MAXDIRECTIONS; ++direction) { + region *neighbour; + int closest_neighbour_distance = INT_MAX; + + neighbour = r_connect(u->region, direction); + if(neighbour != NULL) { + int dist = distance(neighbour, closest_phoenix->region); + if(dist < closest_neighbour_distance) { + closest_neighbour_direction = direction; + closest_neighbour_distance = dist; + } else if(dist == closest_neighbour_distance && rng_int()%100 < 50) { + /* there can never be more than two neighbours with the same + * distance (except when you are standing in the same region + * as the phoenix, but that case has already been handled). + * therefore this simple solution is correct */ + closest_neighbour_direction = direction; + closest_neighbour_distance = dist; + } + } + } + + add_message(&u->faction->msgs, msg_message("phoenixcompass_success", + "unit region command dir", + u, u->region, ord, closest_neighbour_direction)); + + return 0; +} + +void +register_phoenixcompass(void) +{ + register_item_use(use_phoenixcompass, "use_phoenixcompass"); +} + diff --git a/src/items/phoenixcompass.h b/src/items/phoenixcompass.h new file mode 100644 index 000000000..b99876056 --- /dev/null +++ b/src/items/phoenixcompass.h @@ -0,0 +1,30 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ITM_PHOENIXCOMPASS +#define H_ITM_PHOENIXCOMPASS +#ifdef __cplusplus +extern "C" { +#endif + +extern void register_phoenixcompass(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/seed.c b/src/items/seed.c new file mode 100644 index 000000000..3ad84e0c7 --- /dev/null +++ b/src/items/seed.c @@ -0,0 +1,100 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include + +#include "seed.h" + +/* kernel includes */ +#include +#include +#include +#include + +/* util includes */ +#include +#include + +/* libc includes */ +#include + +resource_type * rt_seed = 0; +resource_type * rt_mallornseed = 0; + +static void +produce_seeds(region * r, const resource_type * rtype, int norders) +{ + assert(rtype==rt_seed && r->land && r->land->trees[0] >= norders); + r->land->trees[0] -= norders; +} + +static int +limit_seeds(const region * r, const resource_type * rtype) +{ + assert(rtype==rt_seed); + if(fval(r, RF_MALLORN)) return 0; + return r->land?r->land->trees[0]:0; +} + +void +init_seed(void) +{ + attrib * a; + resource_limit * rdata; + + rt_seed = rt_find("seed"); + if (rt_seed!=NULL) { + a = a_add(&rt_seed->attribs, a_new(&at_resourcelimit)); + rdata = (resource_limit*)a->data.v; + rdata->limit = limit_seeds; + rdata->produce = produce_seeds; + } +} + +/* mallorn */ + +static void +produce_mallornseeds(region * r, const resource_type * rtype, int norders) +{ + assert(rtype==rt_mallornseed && r->land && r->land->trees[0] >= norders); + assert(fval(r, RF_MALLORN)); + r->land->trees[0] -= norders; +} + +static int +limit_mallornseeds(const region * r, const resource_type * rtype) +{ + assert(rtype==rt_mallornseed); + if (!fval(r, RF_MALLORN)) { + return 0; + } + return r->land?r->land->trees[0]:0; +} + +void +init_mallornseed(void) +{ + attrib * a; + resource_limit * rdata; + + rt_mallornseed = rt_find("mallornseed"); + if (rt_mallornseed!=NULL) { + rt_mallornseed->flags |= RTF_LIMITED; + rt_mallornseed->flags |= RTF_POOLED; + + a = a_add(&rt_mallornseed->attribs, a_new(&at_resourcelimit)); + rdata = (resource_limit*)a->data.v; + rdata->limit = limit_mallornseeds; + rdata->produce = produce_mallornseeds; + } +} diff --git a/src/items/seed.h b/src/items/seed.h new file mode 100644 index 000000000..7905d8887 --- /dev/null +++ b/src/items/seed.h @@ -0,0 +1,35 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ITM_SEED +#define H_ITM_SEED +#ifdef __cplusplus +extern "C" { +#endif + + +extern struct resource_type * rt_seed; +extern void init_seed(void); + +extern struct resource_type * rt_mallornseed; +extern void init_mallornseed(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/speedsail.c b/src/items/speedsail.c new file mode 100644 index 000000000..0d80e9158 --- /dev/null +++ b/src/items/speedsail.c @@ -0,0 +1,73 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "speedsail.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include + +/* libc includes */ +#include + +static int +use_speedsail(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + struct plane * p = rplane(u->region); + unused(amount); + unused(itype); + if (p!=NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "use_realworld_only", "")); + } else { + if (u->ship) { + attrib * a = a_find(u->ship->attribs, &at_speedup); + if (a==NULL) { + a = a_add(&u->ship->attribs, a_new(&at_speedup)); + a->data.sa[0] = 50; /* speed */ + a->data.sa[1] = 50; /* decay */ + ADDMSG(&u->faction->msgs, msg_message("use_speedsail", "unit", u)); + /* Ticket abziehen */ + i_change(&u->items, itype, -1); + return 0; + } else { + cmistake(u, ord, 211, MSG_EVENT); + } + } else { + cmistake(u, ord, 144, MSG_EVENT); + } + } + return EUNUSABLE; +} + +void +register_speedsail(void) +{ + register_item_use(use_speedsail, "use_speedsail"); +} diff --git a/src/items/speedsail.h b/src/items/speedsail.h new file mode 100644 index 000000000..2539571a4 --- /dev/null +++ b/src/items/speedsail.h @@ -0,0 +1,30 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ITM_SPEEDVIAL +#define H_ITM_SPEEDVIAL +#ifdef __cplusplus +extern "C" { +#endif + +extern void register_speedsail(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/studypotion.c b/src/items/studypotion.c new file mode 100644 index 000000000..91f7b84f3 --- /dev/null +++ b/src/items/studypotion.c @@ -0,0 +1,58 @@ +#include +#include +#include "studypotion.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* BEGIN it_studypotion */ +#define MAXGAIN 15 +static int +use_studypotion(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + if (get_keyword(u->thisorder) == K_STUDY) { + skill_t sk; + skill * sv; + + init_tokens(u->thisorder); + skip_token(); + sk = findskill(getstrtoken(), u->faction->locale); + sv = get_skill(u, sk); + + if (sv && sv->level > 2) { + /* TODO: message */ + } else if (study_cost(u, sk)>0) { + /* TODO: message */ + } else { + attrib * a = a_find(u->attribs, &at_learning); + teaching_info * teach; + if (a==NULL) { + a = a_add(&u->attribs, a_new(&at_learning)); + } + teach = (teaching_info*) a->data.v; + if (amount>MAXGAIN) amount = MAXGAIN; + teach->value += amount * 30; + if (teach->value > MAXGAIN * 30) { + teach->value = MAXGAIN * 30; + } + i_change(&u->items, itype, -amount); + return 0; + } + } + return EUNUSABLE; +} + +void +register_studypotion(void) +{ + register_function((pf_generic)use_studypotion, "use_studypotion"); +} + +/* END it_studypotion */ diff --git a/src/items/studypotion.h b/src/items/studypotion.h new file mode 100644 index 000000000..454f137c2 --- /dev/null +++ b/src/items/studypotion.h @@ -0,0 +1,30 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ITM_STUDYPOTION +#define H_ITM_STUDYPOTION +#ifdef __cplusplus +extern "C" { +#endif + + extern void register_studypotion(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/weapons.c b/src/items/weapons.c new file mode 100644 index 000000000..11c0379c8 --- /dev/null +++ b/src/items/weapons.c @@ -0,0 +1,155 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "weapons.h" + +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include + +/* libc includes */ +#include +#include + +/* damage types */ + +static boolean +attack_firesword(const troop * at, const struct weapon_type * wtype, int *casualties) +{ + fighter *fi = at->fighter; + troop dt; + int killed = 0; + const char *damage = "2d8"; + int force = 1+rng_int()%10; + int enemies = count_enemies(fi->side->battle, fi, 0, 1, SELECT_ADVANCE|SELECT_DISTANCE); + + if (!enemies) { + if (casualties) *casualties = 0; + return true; /* if no enemy found, no use doing standarad attack */ + } + + if (fi->catmsg == -1) { + int i, k=0; + message * msg; + for (i=0;i<=at->index;++i) { + struct weapon * wp = fi->person[i].melee; + if (wp!=NULL && wp->type == wtype) ++k; + } + msg = msg_message("battle::useflamingsword", "amount unit", k, fi->unit); + message_all(fi->side->battle, msg); + msg_release(msg); + fi->catmsg = 0; + } + + do { + dt = select_enemy(fi, 0, 1, SELECT_ADVANCE|SELECT_DISTANCE); + assert(dt.fighter); + --force; + killed += terminate(dt, *at, AT_SPELL, damage, 1); + } while (force && killed < enemies); + if (casualties) *casualties = killed; + return true; +} + +#define CATAPULT_ATTACKS 6 + +static boolean +attack_catapult(const troop * at, const struct weapon_type * wtype, int * casualties) +{ + fighter *af = at->fighter; + unit *au = af->unit; + battle * b = af->side->battle; + troop dt; + int d = 0, enemies; + weapon * wp = af->person[at->index].missile; + static item_type * it_catapultammo = NULL; + if (it_catapultammo==NULL) { + it_catapultammo = it_find("catapultammo"); + } + + assert(wp->type==wtype); + assert(af->person[at->index].reload==0); + + if (it_catapultammo!=NULL) { + if (get_pooled(au, it_catapultammo->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, 1) <= 0) { + /* No ammo. Use other weapon if available. */ + return true; + } + } + + enemies = count_enemies(b, af, FIGHT_ROW, FIGHT_ROW, SELECT_ADVANCE); + enemies = MIN(enemies, CATAPULT_ATTACKS); + if (enemies==0) { + return true; /* allow further attacks */ + } + + if (af->catmsg == -1) { + int i, k=0; + message * msg; + + for (i=0;i<=at->index;++i) { + if (af->person[i].reload==0 && af->person[i].missile == wp) ++k; + } + msg = msg_message("battle::usecatapult", "amount unit", k, au); + message_all(b, msg); + msg_release(msg); + af->catmsg = 0; + } + + if (it_catapultammo!=NULL) { + use_pooled(au, it_catapultammo->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, 1); + } + + while (--enemies >= 0) { + /* Select defender */ + dt = select_enemy(af, FIGHT_ROW, FIGHT_ROW, SELECT_ADVANCE); + if (!dt.fighter) + break; + + /* If battle succeeds */ + if (hits(*at, dt, wp)) { + d += terminate(dt, *at, AT_STANDARD, wp->type->damage[0], true); +#ifdef CATAPULT_STRUCTURAL_DAMAGE + if (dt.fighter->unit->building && rng_int()%100 < 5) { + damage_building(b, dt.fighter->unit->building, 1); + } else if (dt.fighter->unit->ship && rng_int()%100 < 5) { + dt.fighter->unit->ship->damage+=DAMAGE_SCALE; + } +#endif + } + } + + if (casualties) *casualties = d; + return false; /* keine weitren attacken */ +} +void +register_weapons(void) +{ + register_function((pf_generic)attack_catapult, "attack_catapult"); + register_function((pf_generic)attack_firesword, "attack_firesword"); +} diff --git a/src/items/weapons.h b/src/items/weapons.h new file mode 100644 index 000000000..cc44aa390 --- /dev/null +++ b/src/items/weapons.h @@ -0,0 +1,24 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_ITM_WEAPONS +#define H_ITM_WEAPONS +#ifdef __cplusplus +extern "C" { +#endif + +extern void register_weapons(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/xerewards.c b/src/items/xerewards.c new file mode 100644 index 000000000..c7cda363a --- /dev/null +++ b/src/items/xerewards.c @@ -0,0 +1,91 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "xerewards.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include + +/* libc includes */ +#include +#include +#include + +static int +use_skillpotion(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + /* the problem with making this a lua function is that there's no way + * to get the list of skills for a unit. and with the way skills are + * currently saved, it doesn't look likely (can't make eressea::list + * from them) + */ + int n; + for (n=0;n!=amount;++n) { + skill * sv = u->skills; + while (sv!=u->skills+u->skill_size) { + int i; + for (i=0;i!=3;++i) learn_skill(u, sv->id, 1.0); + ++sv; + } + } + ADDMSG(&u->faction->msgs, msg_message("skillpotion_use", "unit", u)); + + res_changeitem(u, itype->rtype, -amount); + return 0; +} + +static int +use_manacrystal(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + int i, sp = 0; + + if(!is_mage(u)) { + cmistake(u, u->thisorder, 295, MSG_EVENT); + return -1; + } + + for (i=0;i!=amount;++i) { + sp += MAX(25, max_spellpoints(u->region, u)/2); + change_spellpoints(u, sp); + } + + ADDMSG(&u->faction->msgs, msg_message("manacrystal_use", "unit aura", u, sp)); + + res_changeitem(u, itype->rtype, -amount); + return 0; +} + +void +register_xerewards(void) +{ + register_item_use(use_skillpotion, "use_skillpotion"); + register_item_use(use_manacrystal, "use_manacrystal"); +} + diff --git a/src/items/xerewards.h b/src/items/xerewards.h new file mode 100644 index 000000000..c914c5ed4 --- /dev/null +++ b/src/items/xerewards.h @@ -0,0 +1,30 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ITM_XEREWARDS +#define H_ITM_XEREWARDS +#ifdef __cplusplus +extern "C" { +#endif + +extern void register_xerewards(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel.vcproj b/src/kernel.vcproj new file mode 100644 index 000000000..43f2c50a0 --- /dev/null +++ b/src/kernel.vcproj @@ -0,0 +1,948 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/kernel.vcxproj b/src/kernel.vcxproj new file mode 100644 index 000000000..31a4ee968 --- /dev/null +++ b/src/kernel.vcxproj @@ -0,0 +1,289 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {6F104C0A-DDF5-A34B-A89C-0DC278DCEF6D} + kernel + Win32Proj + + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + + + + /MP %(AdditionalOptions) + Disabled + .;../../external;%(AdditionalIncludeDirectories) + WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + + + Level4 + true + EditAndContinue + + + WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + ..;.;%(AdditionalIncludeDirectories) + + + $(OutDir)kernel.lib + + + + + Full + .;../../external;%(AdditionalIncludeDirectories) + WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + + + Level4 + + + + + WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) + ..;.;%(AdditionalIncludeDirectories) + + + $(OutDir)kernel.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/kernel.vcxproj.filters b/src/kernel.vcxproj.filters new file mode 100644 index 000000000..65b46ba39 --- /dev/null +++ b/src/kernel.vcxproj.filters @@ -0,0 +1,598 @@ + + + + + {0d7b749c-a7f2-4791-b356-6ae450020131} + + + {0ebbe376-a35f-44f6-97c6-9b449a839ddb} + + + {0f293992-e32e-49fb-a5f2-74686b0d042e} + + + {e12969f3-9de3-4f65-812d-1e120875a15c} + + + {c10dd4f8-3a6a-470b-8a04-bb652854e228} + + + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + items + + + items + + + items + + + items + + + items + + + items + + + items + + + items + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + items + + + items + + + items + + + items + + + items + + + items + + + items + + + items + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + \ No newline at end of file diff --git a/src/kernel/alchemy.c b/src/kernel/alchemy.c new file mode 100644 index 000000000..05f06471a --- /dev/null +++ b/src/kernel/alchemy.c @@ -0,0 +1,338 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "alchemy.h" + +#include "item.h" +#include "faction.h" +#include "message.h" +#include "build.h" +#include "magic.h" +#include "region.h" +#include "pool.h" +#include "race.h" +#include "unit.h" +#include "skill.h" +#include "move.h" + +/* util includes */ +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +/* ------------------------------------------------------------- */ + +void +herbsearch(region * r, unit * u, int max) +{ + int herbsfound; + const item_type * whichherb; + + if (eff_skill(u, SK_HERBALISM, r) == 0) { + cmistake(u, u->thisorder, 59, MSG_PRODUCE); + return; + } + + if(is_guarded(r, u, GUARD_PRODUCE)) { + cmistake(u, u->thisorder, 70, MSG_EVENT); + return; + } + + whichherb = rherbtype(r); + if (whichherb == NULL) { + cmistake(u, u->thisorder, 108, MSG_PRODUCE); + return; + } + + if (max) max = MIN(max, rherbs(r)); + else max = rherbs(r); + herbsfound = ntimespprob(eff_skill(u, SK_HERBALISM, r) * u->number, + (double)rherbs(r)/100.0F, -0.01F); + herbsfound = MIN(herbsfound, max); + rsetherbs(r, rherbs(r)-herbsfound); + + if (herbsfound) { + produceexp(u, SK_HERBALISM, u->number); + i_change(&u->items, whichherb, herbsfound); + ADDMSG(&u->faction->msgs, msg_message("herbfound", + "unit region amount herb", u, r, herbsfound, whichherb->rtype)); + } else { + ADDMSG(&u->faction->msgs, msg_message("researchherb_none", + "unit region", u, u->region)); + } +} + +static int +begin_potion(unit * u, const potion_type * ptype, struct order *ord) +{ + static int rule_multipotion = -1; + assert(ptype!=NULL); + + if (rule_multipotion<0) { + /* should we allow multiple different potions to be used the same turn? */ + rule_multipotion = get_param_int(global.parameters, "rules.magic.multipotion", 0); + } + if (!rule_multipotion) { + const potion_type * use = ugetpotionuse(u); + if (use != NULL && use!=ptype) { + ADDMSG(&u->faction->msgs, + msg_message("errusingpotion", "unit using command", + u, use->itype->rtype, ord)); + return ECUSTOM; + } + } + return 0; +} + +static void +end_potion(unit * u, const potion_type * ptype, int amount) +{ + use_pooled(u, ptype->itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); + usetpotionuse(u, ptype); + + ADDMSG(&u->faction->msgs, msg_message("usepotion", + "unit potion", u, ptype->itype->rtype)); +} + +void +do_potion(unit * u, const potion_type * ptype, int amount) +{ + if (ptype==oldpotiontype[P_LIFE]) { + region * r = u->region; + int holz = 0; + static int tree_type = -1; + static int tree_count = -1; + if (tree_type<0) { + tree_type = get_param_int(global.parameters, "rules.magic.wol_type", 1); + tree_count = get_param_int(global.parameters, "rules.magic.wol_effect", 10); + } + /* mallorn is required to make mallorn forests, wood for regular ones */ + if (fval(r, RF_MALLORN)) { + holz = use_pooled(u, rt_find("mallorn"), + GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, tree_count*amount); + } else { + holz = use_pooled(u, rt_find("log"), + GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, tree_count*amount); + } + if (r->land==0) holz = 0; + if (holzfaction->msgs, msg_message("growtree_effect", + "mage amount", u, holz)); + } else if (ptype==oldpotiontype[P_HEILWASSER]) { + u->hp = MIN(unit_max_hp(u) * u->number, u->hp + 400 * amount); + } else if (ptype==oldpotiontype[P_PEOPLE]) { + region * r = u->region; + attrib * a = (attrib*)a_find(r->attribs, &at_peasantluck); + if (!a) a = a_add(&r->attribs, a_new(&at_peasantluck)); + a->data.i+=amount; + } else if (ptype==oldpotiontype[P_HORSE]) { + region * r = u->region; + attrib * a = (attrib*)a_find(r->attribs, &at_horseluck); + if (!a) a = a_add(&r->attribs, a_new(&at_horseluck)); + a->data.i+=amount; + } else if (ptype==oldpotiontype[P_WAHRHEIT]) { + fset(u, UFL_DISBELIEVES); + amount=1; + } else if (ptype==oldpotiontype[P_MACHT]) { + /* Verfünffacht die HP von max. 10 Personen in der Einheit */ + u->hp += MIN(u->number, 10*amount) * unit_max_hp(u) * 4; + } else { + change_effect(u, ptype, 10*amount); + } +} + +int +use_potion(unit * u, const item_type * itype, int amount, struct order *ord) +{ + const potion_type * ptype = resource2potion(itype->rtype); + + if (oldpotiontype[P_HEAL] && ptype==oldpotiontype[P_HEAL]) { + return EUNUSABLE; + } else { + int result = begin_potion(u, ptype, ord); + if (result) return result; + do_potion(u, ptype, amount); + end_potion(u, ptype, amount); + } + return 0; +} + +typedef struct potiondelay { + unit * u; + const potion_type * ptype; + int amount; +} potiondelay; + +static void init_potiondelay(attrib * a) { + a->data.v = malloc(sizeof(potiondelay)); +} + +static void free_potiondelay(attrib * a) { + free(a->data.v); +} + +static int age_potiondelay(attrib * a) { + potiondelay * pd = (potiondelay *)a->data.v; + do_potion(pd->u, pd->ptype, pd->amount); + return AT_AGE_REMOVE; +} + +/* TODO: + * - this should be a more general item_delay + * - it should not just happen in age(), but be done with eventhandling + */ +attrib_type at_potiondelay = { + "potiondelay", + init_potiondelay, + free_potiondelay, + age_potiondelay, 0, 0 +}; + +static attrib * +make_potiondelay(unit * u, const potion_type* ptype, int amount) +{ + attrib * a = a_new(&at_potiondelay); + potiondelay * pd = (potiondelay *)a->data.v; + pd->u = u; + pd->ptype = ptype; + pd->amount = amount; + return a; +} + +int +use_potion_delayed(unit * u, const item_type * itype, int amount, struct order *ord) +{ + const potion_type * ptype = resource2potion(itype->rtype); + int result = begin_potion(u, ptype, ord); + if (result) return result; + + a_add(&u->attribs, make_potiondelay(u, ptype, amount)); + + end_potion(u, ptype, amount); + return 0; +} + +/*****************/ +/* at_effect */ +/*****************/ + +static void +a_initeffect(attrib *a) +{ + a->data.v = calloc(sizeof(effect_data), 1); +} + +static void +a_finalizeeffect(attrib * a) +{ + free(a->data.v); +} + +static void +a_writeeffect(const attrib * a, const void * owner, struct storage * store) +{ + effect_data * edata = (effect_data*)a->data.v; + store->w_tok(store, resourcename(edata->type->itype->rtype, 0)); + store->w_int(store, edata->value); +} + +static int +a_readeffect(attrib *a, void * owner, struct storage * store) +{ + int power; + const item_type * itype; + effect_data * edata = (effect_data*)a->data.v; + char zText[32]; + + store->r_tok_buf(store, zText, sizeof(zText)); + itype = it_find(zText); + + power = store->r_int(store); + if (itype==NULL || itype->rtype==NULL || itype->rtype->ptype==NULL || power<=0) { + return AT_READ_FAIL; + } + edata->type = itype->rtype->ptype; + edata->value = power; + return AT_READ_OK; +} + +attrib_type at_effect = { + "effect", + a_initeffect, + a_finalizeeffect, + DEFAULT_AGE, + a_writeeffect, + a_readeffect, +}; + +int +get_effect(const unit * u, const potion_type * effect) +{ + const attrib * a; + for (a=a_find(u->attribs, &at_effect); a!=NULL && a->type==&at_effect; a=a->next) { + const effect_data * data = (const effect_data *)a->data.v; + if (data->type==effect) return data->value; + } + return 0; +} + +int +change_effect (unit * u, const potion_type * effect, int delta) +{ + if (delta!=0) { + attrib * a = a_find(u->attribs, &at_effect); + effect_data * data = NULL; + + while (a && a->type==&at_effect) { + data = (effect_data *)a->data.v; + if (data->type==effect) { + if (data->value+delta==0) { + a_remove(&u->attribs, a); + return 0; + } else { + data->value += delta; + return data->value; + } + } + a = a->next; + } + + a = a_add(&u->attribs, a_new(&at_effect)); + data = (effect_data*)a->data.v; + data->type = effect; + data->value = delta; + return data->value; + } + log_error(("change effect with delta==0 for unit %s\n", itoa36(u->no))); + return 0; +} diff --git a/src/kernel/alchemy.h b/src/kernel/alchemy.h new file mode 100644 index 000000000..128286cd1 --- /dev/null +++ b/src/kernel/alchemy.h @@ -0,0 +1,70 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_ALCHEMY_H +#define H_KRNL_ALCHEMY_H +#ifdef __cplusplus +extern "C" { +#endif + +enum { + /* Stufe 1 */ + P_FAST, + P_STRONG, + P_LIFE, + /* Stufe 2 */ + P_DOMORE, + P_HEILWASSER, + P_BAUERNBLUT, + /* Stufe 3 */ + P_WISE, /* 6 */ + P_FOOL, +#ifdef INSECT_POTION + P_WARMTH, +#else + P_STEEL, +#endif + P_HORSE, + P_BERSERK, /* 10 */ + /* Stufe 4 */ + P_PEOPLE, + P_WAHRHEIT, + P_MACHT, + P_HEAL, + MAX_POTIONS +}; + +extern void herbsearch(struct region * r, struct unit * u, int max); +extern int use_potion(struct unit * u, const struct item_type * itype, int amount, struct order *); +extern int use_potion_delayed(struct unit * u, const struct item_type * itype, int amount, struct order *); +extern void init_potions(void); + +extern int get_effect(const struct unit * u, const struct potion_type * effect); +extern int change_effect(struct unit * u, const struct potion_type * effect, int value); +extern struct attrib_type at_effect; + +/* rausnehmen, sobald man attribute splitten kann: */ +typedef struct effect_data { + const struct potion_type * type; + int value; +} effect_data; + +#ifdef __cplusplus +} +#endif +#endif /* ALCHEMY_H */ diff --git a/src/kernel/alliance.c b/src/kernel/alliance.c new file mode 100644 index 000000000..cec763793 --- /dev/null +++ b/src/kernel/alliance.c @@ -0,0 +1,548 @@ +/* vi: set ts=2: ++-------------------+ Christian Schlittchen +| | Enno Rehling +| Eressea PBEM host | Katja Zedel +| (c) 1998 - 2003 | Henning Peters +| | Ingo Wilken ++-------------------+ Stefan Reich + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#pragma region includes + +#include +#include +#include "alliance.h" + +#include + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +#pragma endregion + +alliance * alliances = NULL; + +void +free_alliance(alliance * al) +{ + free(al->name); + while (al->members) { + faction_list * m = al->members; + al->members = m->next; + free(m); + } + free(al); +} + +alliance * +makealliance(int id, const char * name) +{ + alliance * al;; + + for (;;) { + if (id>0) { + for (al=alliances;al;al=al->next) { + if (al->id==id) { + id = 0; + break; + } + } + if (id>0) break; + } + id = id?id:(1 + (rng_int() % MAX_UNIT_NR)); + } + al = calloc(1, sizeof(alliance)); + al->id = id; + if (name) { + al->name = strdup(name); + } else { + al->flags |= ALF_NON_ALLIED; + } + al->next = alliances; + return alliances=al; +} + +alliance * +findalliance(int id) +{ + alliance * al; + for (al=alliances;al;al=al->next) { + if (al->id==id) return al; + } + return NULL; +} + +typedef struct alliance_transaction { + struct alliance_transaction * next; + unit * u; + order * ord; +// alliance * al; +// variant userdata; +} alliance_transaction; + +static struct alliance_transaction * transactions[ALLIANCE_MAX]; + + +faction * +alliance_get_leader(alliance * al) +{ + if (!al->_leader) { + if (al->members) { + al->_leader = al->members->data; + } + } + return al->_leader; +} + +static void +create_transaction(int type, unit * u, order * ord) +{ + alliance_transaction * tr = calloc(1, sizeof(alliance_transaction)); + tr->ord = ord; + tr->u = u; + tr->next = transactions[type]; + transactions[type] = tr; +} + +static void +cmd_kick(const tnode * tnext, void * data, struct order * ord) +{ + create_transaction(ALLIANCE_KICK, (unit*)data, ord); +} + +static void +cmd_leave(const tnode * tnext, void * data, struct order * ord) +{ + create_transaction(ALLIANCE_LEAVE, (unit*)data, ord); +} + +static void +cmd_transfer(const tnode * tnext, void * data, struct order * ord) +{ + create_transaction(ALLIANCE_TRANSFER, (unit*)data, ord); +} + +static void +cmd_new(const tnode * tnext, void * data, struct order * ord) +{ + create_transaction(ALLIANCE_NEW, (unit*)data, ord); +} + +static void +cmd_invite(const tnode * tnext, void * data, struct order * ord) +{ + create_transaction(ALLIANCE_INVITE, (unit*)data, ord); +} + +static void +cmd_join(const tnode * tnext, void * data, struct order * ord) +{ + create_transaction(ALLIANCE_JOIN, (unit*)data, ord); +} + +static void +perform_kick(void) +{ + alliance_transaction ** tap = transactions+ALLIANCE_KICK; + while (*tap) { + alliance_transaction * ta = *tap; + alliance * al = f_get_alliance(ta->u->faction); + + if (al && alliance_get_leader(al)==ta->u->faction) { + faction * f; + init_tokens(ta->ord); + skip_token(); + skip_token(); + f = getfaction(); + if (f && f_get_alliance(f)==al) { + setalliance(f, NULL); + } + } + *tap = ta->next; + free(ta); + } +} + +static void +perform_new(void) +{ + alliance_transaction ** tap = transactions+ALLIANCE_NEW; + while (*tap) { + alliance_transaction * ta = *tap; + alliance * al; + int id; + faction * f = ta->u->faction; + + init_tokens(ta->ord); + skip_token(); + skip_token(); + id = getid(); + + al = makealliance(id, itoa36(id)); + setalliance(f, al); + + *tap = ta->next; + free(ta); + } +} + +static void +perform_leave(void) +{ + alliance_transaction ** tap = transactions+ALLIANCE_LEAVE; + while (*tap) { + alliance_transaction * ta = *tap; + faction * f = ta->u->faction; + + setalliance(f, NULL); + + *tap = ta->next; + free(ta); + } +} + +static void +perform_transfer(void) +{ + alliance_transaction ** tap = transactions+ALLIANCE_TRANSFER; + while (*tap) { + alliance_transaction * ta = *tap; + alliance * al = f_get_alliance(ta->u->faction); + + if (al && alliance_get_leader(al)==ta->u->faction) { + faction * f; + init_tokens(ta->ord); + skip_token(); + skip_token(); + f = getfaction(); + if (f && f_get_alliance(f)==al) { + al->_leader = f; + } + } + *tap = ta->next; + free(ta); + } +} + +static void +perform_join(void) +{ + alliance_transaction ** tap = transactions+ALLIANCE_JOIN; + while (*tap) { + alliance_transaction * ta = *tap; + faction * fj = ta->u->faction; + int aid; + + init_tokens(ta->ord); + skip_token(); + skip_token(); + aid = getid(); + if (aid) { + alliance * al = findalliance(aid); + if (al && f_get_alliance(fj)!=al) { + alliance_transaction ** tip = transactions+ALLIANCE_INVITE; + alliance_transaction * ti = *tip; + while (ti) { + faction * fi = ti->u->faction; + if (fi && f_get_alliance(fi)==al) { + int fid; + init_tokens(ti->ord); + skip_token(); + skip_token(); + fid = getid(); + if (fid==fj->no) { + break; + } + } + tip = &ti->next; + ti = *tip; + } + if (ti) { + setalliance(fj, al); + *tip = ti->next; + free(ti); + } else { + /* TODO: error message */ + } + } + } + *tap = ta->next; + free(ta); + } +} + +static void +execute(const struct syntaxtree * syntax, keyword_t kwd) +{ + int run = 0; + + region ** rp = ®ions; + while (*rp) { + region * r = *rp; + unit **up = &r->units; + while (*up) { + unit * u = *up; + if (u->number) { + const struct locale * lang = u->faction->locale; + tnode * root = stree_find(syntax, lang); + order * ord; + for (ord = u->orders; ord; ord = ord->next) { + if (get_keyword(ord) == kwd) { + do_command(root, u, ord); + run = 1; + } + } + } + if (u==*up) up = &u->next; + } + if (*rp==r) rp = &r->next; + } + + if (run) { + perform_kick(); + perform_leave(); + perform_transfer(); + perform_new(); + perform_join(); + } +} + +void +alliance_cmd(void) +{ + static syntaxtree * stree = NULL; + if (stree==NULL) { + syntaxtree * slang = stree = stree_create(); + while (slang) { + // struct tnode * root = calloc(sizeof(tnode), 1); + struct tnode * leaf = calloc(sizeof(tnode), 1); + // add_command(root, leaf, LOC(slang->lang, "alliance"), NULL); + add_command(leaf, NULL, LOC(slang->lang, "new"), &cmd_new); + add_command(leaf, NULL, LOC(slang->lang, "invite"), &cmd_invite); + add_command(leaf, NULL, LOC(slang->lang, "join"), &cmd_join); + add_command(leaf, NULL, LOC(slang->lang, "kick"), &cmd_kick); + add_command(leaf, NULL, LOC(slang->lang, "leave"), &cmd_leave); + add_command(leaf, NULL, LOC(slang->lang, "command"), &cmd_transfer); + slang->root = leaf; + slang = slang->next; + } + } + execute(stree, K_ALLIANCE); + /* some may have been kicked, must remove f->alliance==NULL */ +} + +void +alliancejoin(void) +{ + static syntaxtree * stree = NULL; + if (stree==NULL) { + syntaxtree * slang = stree = stree_create(); + while (slang) { + struct tnode * root = calloc(sizeof(tnode), 1); + struct tnode * leaf = calloc(sizeof(tnode), 1); + add_command(root, leaf, LOC(slang->lang, "alliance"), NULL); + add_command(leaf, NULL, LOC(slang->lang, "join"), &cmd_join); + slang = slang->next; + } + } + execute(stree, K_ALLIANCE); +} + +void +setalliance(struct faction * f, alliance * al) +{ + faction_list * flist = NULL; + if (f->alliance==al) return; + if (f->alliance!=NULL) { + faction_list ** flistp = &f->alliance->members; + while (*flistp) { + faction_list * flist = *flistp; + if ((*flistp)->data==f) { + *flistp = flist->next; + break; + } + flistp = &flist->next; + } + + if (f->alliance->_leader==f) { + if (f->alliance->members) { + f->alliance->_leader = f->alliance->members->data; + } else { + f->alliance->_leader = NULL; + } + } + } + f->alliance = al; + f->alliance_joindate = turn; + if (al!=NULL) { + faction_list ** flistp = &al->members; + while (*flistp) { + flistp = &(*flistp)->next; + } + if (flist==NULL) { + flist = malloc(sizeof(faction_list)); + flist->data = f; + } + *flistp = flist; + flist->next = NULL; + if (al->_leader==NULL) { + al->_leader = f; + } + flist = NULL; + } + free(flist); +} + +const char * +alliancename(const alliance * al) +{ + typedef char name[OBJECTIDSIZE + 1]; + static name idbuf[8]; + static int nextbuf = 0; + + char *ibuf = idbuf[(++nextbuf) % 8]; + + if (al && al->name) { + snprintf(ibuf, sizeof(name), "%s (%s)", al->name, itoa36(al->id)); + ibuf[sizeof(name)-1] = 0; + } else { + return NULL; + } + return ibuf; +} + +void +alliancevictory(void) +{ + const struct building_type * btype = bt_find("stronghold"); + region * r = regions; + alliance * al = alliances; + if (btype==NULL) return; + while (r!=NULL) { + building * b = r->buildings; + while (b!=NULL) { + if (b->type==btype) { + unit * u = building_owner(b); + if (u) { + fset(u->faction->alliance, FFL_MARK); + } + } + b = b->next; + } + r=r->next; + } + while (al!=NULL) { + if (!fval(al, FFL_MARK)) { + faction_list * flist = al->members; + while (flist!=0) { + faction * f = flist->data; + if (f->alliance==al) { + ADDMSG(&f->msgs, msg_message("alliance::lost", + "alliance", al)); + destroyfaction(f); + } + flist = flist->next; + } + } else { + freset(al, FFL_MARK); + } + al = al->next; + } +} + +int +victorycondition(const alliance * al, const char * name) +{ + const char * gems[] = { "opal", "diamond", "zaphire", "topaz", "beryl", "agate", "garnet", "emerald", NULL }; + if (strcmp(name, "gems")==0) { + const char ** igem = gems; + + for (;*igem;++igem) { + const struct item_type * itype = it_find(*igem); + faction_list * flist = al->members; + boolean found = false; + + assert(itype!=NULL); + for (;flist && !found;flist=flist->next) { + unit * u = flist->data->units; + + for (;u;u=u->nextF) { + if (i_get(u->items, itype)>0) { + found = true; + break; + } + } + } + if (!found) return 0; + } + return 1; + + } else if (strcmp(name, "phoenix")==0) { + faction_list * flist = al->members; + for (;flist;flist=flist->next) { + faction * f = flist->data; + if (find_key(f->attribs, atoi36("phnx"))) { + return 1; + } + } + return 0; + + } else if (strcmp(name, "pyramid")==0) { + + /* Logik: + * - if (pyr > last_passed_size && pyr > all_others) { + * pyr->passed->counter++; + * for(all_other_pyrs) { + * pyr->passed->counter=0; + * } + * + * if(pyr->passed->counter >= 3) { + * set(pyr, passed); + * pyr->owner->set_attrib(pyra); + * } + * last_passed_size = pyr->size; + * } + */ + + faction_list * flist = al->members; + for (;flist;flist=flist->next) { + faction * f = flist->data; + if (find_key(f->attribs, atoi36("pyra"))) { + return 1; + } + } + return 0; + } + return -1; +} + +void alliance_setname(alliance * self, const char * name) +{ + free(self->name); + if (name) self->name = strdup(name); + else self->name = NULL; +} diff --git a/src/kernel/alliance.h b/src/kernel/alliance.h new file mode 100644 index 000000000..e9cab8b66 --- /dev/null +++ b/src/kernel/alliance.h @@ -0,0 +1,68 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_ALLIANCE +#define H_KRNL_ALLIANCE +#ifdef __cplusplus +extern "C" { +#endif + +struct plane; +struct attrib; +struct unit; +struct faction; +struct region; +struct faction_list; + +enum { + ALLIANCE_KICK, + ALLIANCE_LEAVE, + ALLIANCE_TRANSFER, + ALLIANCE_NEW, + ALLIANCE_INVITE, + ALLIANCE_JOIN, + ALLIANCE_MAX +}; + +#define ALF_NON_ALLIED (1<<0) /* this alliance is just a default for a non-allied faction */ + +typedef struct alliance { + struct alliance * next; + struct faction * _leader; + struct faction_list * members; + unsigned int flags; + int id; + char * name; +} alliance; + +extern alliance * alliances; +extern alliance * findalliance(int id); +extern alliance * makealliance(int id, const char * name); +extern const char * alliancename(const struct alliance * al); +extern void setalliance(struct faction * f, alliance * al); +void free_alliance(struct alliance * al); +extern struct faction * alliance_get_leader(struct alliance * al); +extern void alliance_cmd(void); + +void alliance_setname(alliance * self, const char * name); +/* execute commands */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/battle.c b/src/kernel/battle.c new file mode 100644 index 000000000..a4eadfcda --- /dev/null +++ b/src/kernel/battle.c @@ -0,0 +1,4371 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#pragma region includes + +#include +#include +#include "battle.h" + +#include "alchemy.h" +#include "alliance.h" +#include "build.h" +#include "building.h" +#include "curse.h" +#include "equipment.h" +#include "faction.h" +#include "group.h" +#include "item.h" +#include "magic.h" +#include "message.h" +#include "move.h" +#include "names.h" +#include "order.h" +#include "plane.h" +#include "race.h" +#include "region.h" +#include "reports.h" +#include "ship.h" +#include "skill.h" +#include "terrain.h" +#include "unit.h" + +/* attributes includes */ +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include + +#pragma endregion + +static FILE *bdebug; + +#define TACTICS_BONUS 1 /* when undefined, we have a tactics round. else this is the bonus tactics give */ +#define TACTICS_MODIFIER 1 /* modifier for generals in the fromt/rear */ + +#define CATAPULT_INITIAL_RELOAD 4 /* erster schuss in runde 1 + rng_int() % INITIAL */ +#define CATAPULT_STRUCTURAL_DAMAGE + +#define BASE_CHANCE 70 /* 70% Basis-Überlebenschance */ +#ifdef NEW_COMBATSKILLS_RULE +#define TDIFF_CHANGE 5 /* 5% höher pro Stufe */ +#define DAMAGE_QUOTIENT 2 /* damage += skilldiff/DAMAGE_QUOTIENT */ +#else +#define TDIFF_CHANGE 10 +# define DAMAGE_QUOTIENT 1 /* damage += skilldiff/DAMAGE_QUOTIENT */ +#endif + +#undef DEBUG_FAST /* should be disabled when b->fast and b->rowcache works */ +#define DEBUG_SELECT /* should be disabled if select_enemy works */ + +typedef enum combatmagic { + DO_PRECOMBATSPELL, + DO_POSTCOMBATSPELL +} combatmagic_t; + +/* globals */ +static int obs_count = 0; + +#define MINSPELLRANGE 1 +#define MAXSPELLRANGE 7 + +#ifndef ROW_FACTOR +# define ROW_FACTOR 10 +#endif +static const double EFFECT_PANIC_SPELL = 0.25; +static const double TROLL_REGENERATION = 0.10; + +/* Nach dem alten System: */ +static int missile_range[2] = {FIGHT_ROW, BEHIND_ROW}; +static int melee_range[2] = {FIGHT_ROW, FIGHT_ROW}; +static message * msg_separator; + +const troop no_troop = {0, 0}; + +static int max_turns = 0; +static int damage_rules = 0; +static int loot_rules = 0; +static int skill_formula = 0; + +#define FORMULA_ORIG 0 +#define FORMULA_NEW 1 + +#define LOOT_MONSTERS (1<<0) +#define LOOT_SELF (1<<1) /* code is mutually exclusive with LOOT_OTHERS */ +#define LOOT_OTHERS (1<<2) +#define LOOT_KEEPLOOT (1<<4) + +#define DAMAGE_CRITICAL (1<<0) +#define DAMAGE_MELEE_BONUS (1<<1) +#define DAMAGE_MISSILE_BONUS (1<<2) +#define DAMAGE_UNARMED_BONUS (1<<3) +#define DAMAGE_SKILL_BONUS (1<<4) +/** initialize rules from configuration. + */ +static void +static_rules(void) +{ + loot_rules = get_param_int(global.parameters, "rules.combat.loot", LOOT_MONSTERS|LOOT_OTHERS|LOOT_KEEPLOOT); + /* new formula to calculate to-hit-chance */ + skill_formula = get_param_int(global.parameters, "rules.combat.skill_formula", FORMULA_ORIG); + /* maximum number of combat turns */ + max_turns = get_param_int(global.parameters, "rules.combat.turns", COMBAT_TURNS); + /* damage calculation */ + if (get_param_int(global.parameters, "rules.combat.critical", 1)) { + damage_rules |= DAMAGE_CRITICAL; + } + if (get_param_int(global.parameters, "rules.combat.melee_bonus", 1)) { + damage_rules |= DAMAGE_MELEE_BONUS; + } + if (get_param_int(global.parameters, "rules.combat.missile_bonus", 1)) { + damage_rules |= DAMAGE_MISSILE_BONUS; + } + if (get_param_int(global.parameters, "rules.combat.unarmed_bonus", 1)) { + damage_rules |= DAMAGE_UNARMED_BONUS; + } + if (get_param_int(global.parameters, "rules.combat.skill_bonus", 1)) { + damage_rules |= DAMAGE_SKILL_BONUS; + } +} + +static int +army_index(side * s) +{ + return s->index; +} + +#ifndef SIMPLE_ESCAPE +region * +fleeregion(const unit * u) +{ + region *r = u->region; + region *neighbours[MAXDIRECTIONS]; + int c = 0; + direction_t i; + + if (u->ship && !fval(r->terrain, SEA_REGION)) + return NULL; + + if (u->ship && + !(u->race->flags & RCF_SWIM) && + !(u->race->flags & RCF_FLY)) { + return NULL; + } + + for (i = 0; i != MAXDIRECTIONS; ++i) { + region * r2 = rconnect(r, i); + if (r2) { + if (can_survive(u,r2) && !move_blocked(u, r, r2)) + neighbours[c++] = r2; + } + } + + if (!c) + return NULL; + return neighbours[rng_int() % c]; +} +#endif /* SIMPLE_ESCAPE */ + +static char * +sidename(side * s) +{ +#define SIDENAMEBUFLEN 256 + static int bufno; /* STATIC_XCALL: used across calls */ + static char sidename_buf[4][SIDENAMEBUFLEN]; /* STATIC_RESULT: used for return, not across calls */ + + bufno = bufno % 4; + if (s->stealthfaction) { + snprintf(sidename_buf[bufno], SIDENAMEBUFLEN, + "%s", factionname(s->stealthfaction)); + } else { + snprintf(sidename_buf[bufno], SIDENAMEBUFLEN, + "%s", factionname(s->faction)); + } + return sidename_buf[bufno++]; +} + +static const char * +sideabkz(side *s, boolean truename) +{ + static char sideabkz_buf[8]; /* STATIC_RESULT: used for return, not across calls */ + const faction * f = (s->stealthfaction && !truename)?s->stealthfaction:s->faction; + +#undef SIDE_ABKZ +#ifdef SIDE_ABKZ + abkz(f->name, sideabkz_buf, sizeof(sideabkz_buf), 3); +#else + strcpy(sideabkz_buf, itoa36(f->no)); +#endif + return sideabkz_buf; +} + +static void +message_faction(battle * b, faction * f, struct message * m) +{ + region * r = b->region; + + if (f->battles==NULL || f->battles->r!=r) { + struct bmsg * bm = calloc(1, sizeof(struct bmsg)); + bm->next = f->battles; + f->battles = bm; + bm->r = r; + } + add_message(&f->battles->msgs, m); +} + +int +armedmen(const unit * u, boolean siege_weapons) +{ + item * itm; + int n = 0; + if (!(urace(u)->flags & RCF_NOWEAPONS)) { + if (effskill(u, SK_WEAPONLESS)>=1) { + /* kann ohne waffen bewachen: fuer drachen */ + n = u->number; + } else { + /* alle Waffen werden gezaehlt, und dann wird auf die Anzahl + * Personen minimiert */ + for (itm=u->items;itm;itm=itm->next) { + const weapon_type * wtype = resource2weapon(itm->type->rtype); + if (wtype==NULL || (!siege_weapons && (wtype->flags & WTF_SIEGE))) continue; + if (effskill(u, wtype->skill) >= 1) n += itm->number; + /* if (effskill(u, wtype->skill) >= wtype->minskill) n += itm->number; */ + if (n>u->number) break; + } + n = MIN(n, u->number); + } + } + return n; +} + +void +message_all(battle * b, message * m) +{ + bfaction * bf; + plane * p = rplane(b->region); + watcher * w; + + for (bf = b->factions;bf;bf=bf->next) { + message_faction(b, bf->faction, m); + } + if (p) for (w=p->watchers;w;w=w->next) { + for (bf = b->factions;bf;bf=bf->next) if (bf->faction==w->faction) break; + if (bf==NULL) message_faction(b, w->faction, m); + } +} + +static void +fbattlerecord(battle * b, faction * f, const char *s) +{ + message * m = msg_message("battle_msg", "string", s); + message_faction(b, f, m); + msg_release(m); +} + +/* being an enemy or a friend is (and must always be!) symmetrical */ +#define enemy_i(as, di) (as->relations[di]&E_ENEMY) +#define friendly_i(as, di) (as->relations[di]&E_FRIEND) +#define enemy(as, ds) (as->relations[ds->index]&E_ENEMY) +#define friendly(as, ds) (as->relations[ds->index]&E_FRIEND) + +static boolean +set_enemy(side * as, side * ds, boolean attacking) +{ + int i; + for (i=0;i!=MAXSIDES;++i) { + if (ds->enemies[i]==NULL) ds->enemies[i]=as; + if (ds->enemies[i]==as) break; + } + for (i=0;i!=MAXSIDES;++i) { + if (as->enemies[i]==NULL) as->enemies[i]=ds; + if (as->enemies[i]==ds) break; + } + assert(i!=MAXSIDES); + if (attacking) as->relations[ds->index] |= E_ATTACKING; + if ((ds->relations[as->index] & E_ENEMY)==0) { + /* enemy-relation are always symmetrical */ + assert((as->relations[ds->index] & (E_ENEMY|E_FRIEND))==0); + ds->relations[as->index] |= E_ENEMY; + as->relations[ds->index] |= E_ENEMY; + return true; + } + return false; +} + +static void +set_friendly(side * as, side * ds) +{ + assert((as->relations[ds->index] & E_ENEMY)==0); + ds->relations[as->index] |= E_FRIEND; + as->relations[ds->index] |= E_FRIEND; +} + +static int +allysfm(const side * s, const faction * f, int mode) +{ + if (s->faction==f) return mode; + if (s->group) { + return alliedgroup(s->battle->plane, s->faction, f, s->group->allies, mode); + } + return alliedfaction(s->battle->plane, s->faction, f, mode); +} + +static int +allysf(const side * s, const faction * f) +{ + return allysfm(s, f, HELP_FIGHT); +} + +static int +dead_fighters(const fighter * df) +{ + return df->unit->number - df->alive - df->run.number; +} + +fighter * +select_corpse(battle * b, fighter * af) +/* Wählt eine Leiche aus, der af hilft. casualties ist die Anzahl der + * Toten auf allen Seiten (im Array). Wenn af == NULL, wird die + * Parteizugehörigkeit ignoriert, und irgendeine Leiche genommen. + * + * Untote werden nicht ausgewählt (casualties, not dead) */ +{ + int si, di, maxcasualties = 0; + fighter *df; + side *s; + + for (si=0;si!=b->nsides;++si) { + side * s = b->sides+si; + if (af==NULL || (!enemy_i(af->side, si) && allysf(af->side, s->faction))) { + maxcasualties += s->casualties; + } + } + di = rng_int() % maxcasualties; + for (s=b->sides;s!=b->sides+b->nsides;++s) { + for (df=s->fighters;df;df=df->next) { + /* Geflohene haben auch 0 hp, dürfen hier aber nicht ausgewählt + * werden! */ + int dead = dead_fighters(df); + if (!playerrace(df->unit->race)) continue; + + if (af && !helping(af->side, df->side)) + continue; + if (di < dead) { + return df; + } + di -= dead; + } + } + + return NULL; +} + +boolean +helping(const side * as, const side * ds) +{ + if (as->faction==ds->faction) return true; + return (boolean)(!enemy(as, ds) && allysf(as, ds->faction)); +} + +int +statusrow(int status) +{ + switch (status) { + case ST_AGGRO: + case ST_FIGHT: + return FIGHT_ROW; + case ST_BEHIND: + case ST_CHICKEN: + return BEHIND_ROW; + case ST_AVOID: + return AVOID_ROW; + case ST_FLEE: + return FLEE_ROW; + default: + assert(!"unknown combatrow"); + } + return FIGHT_ROW; +} + +static double +hpflee(int status) + /* if hp drop below this percentage, run away */ +{ + switch (status) { + case ST_AGGRO: + return 0.0; + case ST_FIGHT: + case ST_BEHIND: + return 0.2; + case ST_CHICKEN: + case ST_AVOID: + return 0.9; + case ST_FLEE: + return 1.0; + default: + assert(!"unknown combatrow"); + } + return 0.0; +} + +static int +get_row(const side * s, int row, const side * vs) +{ + boolean counted[MAXSIDES]; + int enemyfront = 0; + int line, result; + int retreat = 0; + int size[NUMROWS]; + int front = 0; + battle * b = s->battle; + + memset(counted, 0, sizeof(counted)); + memset(size, 0, sizeof(size)); + for (line=FIRST_ROW;line!=NUMROWS;++line) { + int si, sa_i; + /* how many enemies are there in the first row? */ + for (si=0;s->enemies[si];++si) { + side *se = s->enemies[si]; + if (se->size[line]>0) { + enemyfront += se->size[line]; + /* - s->nonblockers[line] (nicht, weil angreifer) */ + } + } + for (sa_i=0; sa_i!=b->nsides; ++sa_i) { + side * sa = b->sides+sa_i; + /* count people that like me, but don't like my enemy */ + if (friendly_i(s, sa_i) && enemy_i(vs, sa_i)) { + if (!counted[sa_i]) { + int i; + + for (i=0;i!=NUMROWS;++i) { + size[i] += sa->size[i] - sa->nonblockers[i]; + } + counted[sa_i] = true; + } + } + } + if (enemyfront) break; + } + if (enemyfront) { + for (line=FIRST_ROW;line!=NUMROWS;++line) { + front += size[line]; + if (!front || frontstatus); + if (vs==NULL) { + int i; + for (i=FIGHT_ROW;i!=row;++i) if (af->side->size[i]) break; + return FIGHT_ROW+(row-i); + } else { +#ifdef FASTROW + battle * b = vs->battle; + if (row!=b->rowcache.row || b->alive!=b->rowcache.alive || af->side!=b->rowcache.as || vs!=b->rowcache.vs) { + b->rowcache.alive = b->alive; + b->rowcache.as = af->side; + b->rowcache.vs = vs; + b->rowcache.row = row; + b->rowcache.result = get_row(af->side, row, vs); + return b->rowcache.result; + } +#ifdef DEBUG_FAST /* validation code */ + { + int i = get_row(af->side, row, vs); + assert(i==b->rowcache.result); + } +#endif + return b->rowcache.result; +#else + return get_row(af->side, row, vs); +#endif + } +} + +static void +reportcasualties(battle * b, fighter * fig, int dead) +{ + struct message * m; + region * r = NULL; + if (fig->alive == fig->unit->number) return; +#ifndef SIMPLE_ESCAPE + if (fig->run.region == NULL) { + fig->run.region = fleeregion(fig->unit); + if (fig->run.region == NULL) fig->run.region = b->region; + } + r = fig->run.region; +#endif /* SIMPLE_ESCAPE */ + m = msg_message("casualties", "unit runto run alive fallen", + fig->unit, r, fig->run.number, fig->alive, dead); + message_all(b, m); + msg_release(m); +} + +static int +contest_classic(int skilldiff, const armor_type * ar, const armor_type * sh) +{ + int p, vw = BASE_CHANCE - TDIFF_CHANGE * skilldiff; + double mod = 1.0; + + if (ar != NULL) + mod *= (1 + ar->penalty); + if (sh != NULL) + mod *= (1 + sh->penalty); + vw = (int)(100 - ((100 - vw) * mod)); + + do { + p = rng_int() % 100; + vw -= p; + } + while (vw >= 0 && p >= 90); + return (vw <= 0); +} + +/** new rule for Eressea 1.5 + * \param skilldiff - the attack skill with every modifier applied + */ +static int +contest_new(int skilldiff, const troop dt, const armor_type * ar, const armor_type * sh) +{ + double tohit = 0.5 + skilldiff * 0.1; + if (tohit<0.5) tohit = 0.5; + if (chance(tohit)) { + int defense = effskill(dt.fighter->unit, SK_STAMINA); + double tosave = defense * 0.05; + return !chance(tosave); + } + return 0; +} + +static int +contest(int skdiff, const troop dt, const armor_type * ar, const armor_type * sh) +{ + if (skill_formula==FORMULA_ORIG) { + return contest_classic(skdiff, ar, sh); + } else { + return contest_new(skdiff, dt, ar, sh); + } +} + +static boolean +is_riding(const troop t) { + if (t.fighter->building!=NULL) return false; + if (t.fighter->horses + t.fighter->elvenhorses > t.index) return true; + return false; +} + +static weapon * +preferred_weapon(const troop t, boolean attacking) +{ + weapon * missile = t.fighter->person[t.index].missile; + weapon * melee = t.fighter->person[t.index].melee; + if (attacking) { + if (melee==NULL || (missile && missile->attackskill>melee->attackskill)) { + return missile; + } + } else { + if (melee==NULL || (missile && missile->defenseskill>melee->defenseskill)) { + return missile; + } + } + return melee; +} + +static weapon * +select_weapon(const troop t, boolean attacking, boolean ismissile) + /* select the primary weapon for this trooper */ +{ + if (attacking) { + if (ismissile) { + /* from the back rows, have to use your missile weapon */ + return t.fighter->person[t.index].missile; + } + } else { + if (!ismissile) { + /* have to use your melee weapon if it's melee */ + return t.fighter->person[t.index].melee; + } + } + return preferred_weapon(t, attacking); +} + +static boolean +i_canuse(const unit * u, const item_type * itype) +{ + if (itype->canuse) { + return itype->canuse(u, itype); + } + return true; +} + +static int +weapon_skill(const weapon_type * wtype, const unit * u, boolean attacking) + /* the 'pure' skill when using this weapon to attack or defend. + * only undiscriminate modifiers (not affected by troops or enemies) + * are taken into account, e.g. no horses, magic, etc. */ +{ + int skill; + + if (wtype==NULL) { + skill = effskill(u, SK_WEAPONLESS); + if (skill<=0) { + /* wenn kein waffenloser kampf, dann den rassen-defaultwert */ + if (u->race == new_race[RC_ORC]) { + int sword = effskill(u, SK_MELEE); + int spear = effskill(u, SK_SPEAR); + skill = MAX(sword, spear) - 3; + if (attacking) { + skill = MAX(skill, u->race->at_default); + } else { + skill = MAX(skill, u->race->df_default); + } + } else { + if (attacking) { + skill = u->race->at_default; + } else { + skill = u->race->df_default; + } + } + } else { + /* der rassen-defaultwert kann höher sein als der Talentwert von + * waffenloser kampf */ + if (attacking) { + if (skill < u->race->at_default) skill = u->race->at_default; + } else { + if (skill < u->race->df_default) skill = u->race->df_default; + } + } + if (attacking) { + skill += u->race->at_bonus; + if (fval(u->region->terrain, SEA_REGION) && u->ship) skill += u->ship->type->at_bonus; + } else { + skill += u->race->df_bonus; + if (fval(u->region->terrain, SEA_REGION) && u->ship) skill += u->ship->type->df_bonus; + } + } else { + /* changed: if we own a weapon, we have at least a skill of 0 */ + if (!i_canuse(u, wtype->itype)) return -1; + skill = effskill(u, wtype->skill); + if (skill < wtype->minskill) skill = 0; + if (skill > 0) { + if (attacking) { + skill += u->race->at_bonus; + } else { + skill += u->race->df_bonus; + } + } + if (attacking) { + skill += wtype->offmod; + } else { + skill += wtype->defmod; + } + } + + return skill; +} + +static int CavalrySkill(void) +{ + static int skill = -1; + + if (skill<0) { + skill = get_param_int(global.parameters, "rules.cavalry.skill", 2); + } + return skill; +} + +#define BONUS_SKILL 1 +#define BONUS_DAMAGE 2 +static int +CavalryBonus(const unit * u, troop enemy, int type) +{ + static int mode = -1; + + if (mode<0) { + mode = get_param_int(global.parameters, "rules.cavalry.mode", 1); + } + if (mode==0) { + /* old rule, Eressea 1.0 compat */ + return (type==BONUS_SKILL)?2:0; + } else { + /* new rule, chargers in Eressea 1.1 */ + int skl = effskill(u, SK_RIDING); + /* only half against trolls */ + if (skl>0) { + if (type==BONUS_DAMAGE) { + int dmg = MIN(skl, 8); + if (enemy.fighter->unit->race==new_race[RC_TROLL]) { + dmg = dmg/4; + } else { + dmg = dmg/2; + } + return dmg; + } else { + skl = skl/2; + return MIN(skl, 4); + } + } + } + return 0; +} + +static int +weapon_effskill(troop t, troop enemy, const weapon * w, boolean attacking, boolean missile) + /* effektiver Waffenskill während des Kampfes */ +{ + /* In dieser Runde alle die Modifier berechnen, die fig durch die + * Waffen bekommt. */ + fighter * tf = t.fighter; + unit * tu = t.fighter->unit; + int skill; + const weapon_type * wtype = w?w->type:NULL; + + if (wtype==NULL) { + /* Ohne Waffe: Waffenlose Angriffe */ + skill = weapon_skill(NULL, tu, attacking); + } else { + if (attacking) { + skill = w->attackskill; + } else { + skill = w->defenseskill; + } + if (wtype->modifiers!=NULL) { + /* Pferdebonus, Lanzenbonus, usw. */ + int m; + unsigned int flags = WMF_SKILL|(attacking?WMF_OFFENSIVE:WMF_DEFENSIVE); + + if (is_riding(t)) flags |= WMF_RIDING; + else flags |= WMF_WALKING; + if (is_riding(enemy)) flags |= WMF_AGAINST_RIDING; + else flags |= WMF_AGAINST_WALKING; + + for (m=0;wtype->modifiers[m].value;++m) { + if ((wtype->modifiers[m].flags & flags) == flags) { + race_list * rlist = wtype->modifiers[m].races; + if (rlist!=NULL) { + while (rlist) { + if (rlist->data == tu->race) break; + rlist = rlist->next; + } + if (rlist==NULL) continue; + } + skill += wtype->modifiers[m].value; + } + } + } + } + + /* Burgenbonus, Pferdebonus */ + if (is_riding(t) && (wtype==NULL || (fval(wtype, WTF_HORSEBONUS) && !fval(wtype, WTF_MISSILE)))) { + skill += CavalryBonus(tu, enemy, BONUS_SKILL); + if (wtype) skill = skillmod(urace(tu)->attribs, tu, tu->region, wtype->skill, skill, SMF_RIDING); + } + + if (t.indexelvenhorses) { + /* Elfenpferde: Helfen dem Reiter, egal ob und welche Waffe. Das ist + * eleganter, und vor allem einfacher, sonst muß man noch ein + * WMF_ELVENHORSE einbauen. */ + skill += 2; + } + + if (skill>0 && !attacking && missile) { + /* + * Wenn ich verteidige, und nicht direkt meinem Feind gegenüberstehe, + * halbiert sich mein Skill: (z.B. gegen Fernkämpfer. Nahkämpfer + * können mich eh nicht treffen) + */ + skill /= 2; + } + return skill; +} + +static const armor_type * +select_armor(troop t, boolean shield) +{ + unsigned int type = shield?ATF_SHIELD:0; + unit * u = t.fighter->unit; + const armor * a = t.fighter->armors; + int geschuetzt = 0; + + /* some monsters should not use armor (dragons in chainmail? ha!) */ + if (!(u->race->battle_flags & BF_EQUIPMENT)) + return NULL; + + /* ... neither do werewolves */ + if (fval(u, UFL_WERE)) { + return NULL; + } + + for (;a;a=a->next) { + if ((a->atype->flags & ATF_SHIELD)==type) { + geschuetzt += a->count; + if (geschuetzt > t.index) { + /* unser Kandidat wird geschuetzt */ + return a->atype; + } + } + } + return NULL; +} + + +/* Hier ist zu beachten, ob und wie sich Zauber und Artefakte, die + * Rüstungschutz geben, addieren. + * - Artefakt I_TROLLBELT gibt Rüstung +1 + * - Zauber Rindenhaut gibt Rüstung +3 + */ +int +select_magicarmor(troop t) +{ + unit *u = t.fighter->unit; + int geschuetzt = 0; + int ma = 0; + + geschuetzt = MIN(get_item(u, I_TROLLBELT), u->number); + + if (geschuetzt > t.index) /* unser Kandidat wird geschuetzt */ + ma += 1; + + return ma; +} + +/* Sind side ds und Magier des meffect verbündet, dann return 1*/ +boolean +meffect_protection(battle * b, meffect * s, side * ds) +{ + if (!s->magician->alive) return false; + if (s->duration <= 0) return false; + if (enemy(s->magician->side, ds)) return false; + if (allysf(s->magician->side, ds->faction)) return true; + return false; +} + +/* Sind side as und Magier des meffect verfeindet, dann return 1*/ +boolean +meffect_blocked(battle *b, meffect *s, side *as) +{ + if (!s->magician->alive) return false; + if (s->duration <= 0) return false; + if (enemy(s->magician->side, as)) return true; + return false; +} + +/* rmfighter wird schon im PRAECOMBAT gebraucht, da gibt es noch keine + * troops */ +void +rmfighter(fighter *df, int i) +{ + side *ds = df->side; + + /* nicht mehr personen abziehen, als in der Einheit am Leben sind */ + assert(df->alive >= i); + assert(df->alive <= df->unit->number); + + /* erst ziehen wir die Anzahl der Personen von den Kämpfern in der + * Schlacht, dann von denen auf dieser Seite ab*/ + df->side->alive -= i; + df->side->battle->alive -= i; + + /* Dann die Kampfreihen aktualisieren */ + ds->size[SUM_ROW] -= i; + ds->size[statusrow(df->status)] -= i; + + /* Spezialwirkungen, z.B. Schattenritter */ + if (df->unit->race->battle_flags & BF_NOBLOCK) { + ds->nonblockers[SUM_ROW] -= i; + ds->nonblockers[statusrow(df->status)] -= i; + } + + /* und die Einheit selbst aktualisieren */ + df->alive -= i; +} + + +static void +rmtroop(troop dt) +{ + fighter *df = dt.fighter; + + /* troop ist immer eine einzele Person */ + rmfighter(df, 1); + + assert(dt.index >= 0 && dt.index < df->unit->number); + df->person[dt.index] = df->person[df->alive - df->removed]; + if (df->removed) { + df->person[df->alive - df->removed] = df->person[df->alive]; + } + df->person[df->alive].hp = 0; +} + +void +remove_troop(troop dt) +{ + fighter * df = dt.fighter; + struct person p = df->person[dt.index]; + battle * b = df->side->battle; +#ifdef FASTCOUNT + b->fast.alive = -1; /* invalidate cached value */ +#endif +#ifdef FASTROW + b->rowcache.alive = -1; /* invalidate cached value */ +#endif + ++df->removed; + ++df->side->removed; + df->person[dt.index] = df->person[df->alive-df->removed]; + df->person[df->alive - df->removed] = p; +} + +void +kill_troop(troop dt) +{ + fighter * df = dt.fighter; + unit * du = df->unit; + + rmtroop(dt); + if (!df->alive) { + char eqname[64]; + const struct equipment * eq; + if (du->race->itemdrop) { + item * drops = du->race->itemdrop(du->race, du->number-df->run.number); + + if (drops != NULL){ + i_merge(&du->items, &drops); + } + } + sprintf(eqname, "%s_spoils", du->race->_name[0]); + eq = get_equipment(eqname); + if (eq!=NULL) { + equip_items(&du->items, eq); + } + } +} + +/** reduces the target's exp by an equivalent of n points learning + * 30 points = 1 week + */ +void +drain_exp(struct unit *u, int n) +{ + skill_t sk = (skill_t)(rng_int() % MAXSKILLS); + skill_t ssk; + + ssk = sk; + + while (get_level(u, sk)==0) { + sk++; + if (sk == MAXSKILLS) + sk = 0; + if (sk == ssk) { + sk = NOSKILL; + break; + } + } + if (sk != NOSKILL) { + skill * sv = get_skill(u, sk); + while (n>0) { + if (n>=30*u->number) { + reduce_skill(u, sv, 1); + n-=30; + } else { + if (rng_int()%(30*u->number) 0.75) { + return "eine klaffende Wunde"; + } else if (q > 0.5) { + return "eine schwere Wunde"; + } else if (q > 0.25) { + return "eine Wunde"; + } + return "eine kleine Wunde"; +} + +static void vampirism(troop at, int damage) +{ + static int vampire = -1; + if (vampire<0) vampire = get_param_int(global.parameters, "rules.combat.demon_vampire", 0); + if (vampire>0) { + int gain = damage/vampire; + int chance = damage - vampire * gain; + if (chance>0 && (rng_int() % vampire < chance)) ++gain; + if (gain>0) { + int maxhp = unit_max_hp(at.fighter->unit); + at.fighter->person[at.index].hp = MIN(gain+at.fighter->person[at.index].hp, maxhp); + } + } +} + +static int +natural_armor(unit * du) +{ + static int * bonus = 0; + int an = du->race->armor; + if (bonus==0) { + bonus = calloc(sizeof(int), num_races); + } + if (bonus[du->race->index]==0) { + bonus[du->race->index] = get_param_int(du->race->parameters, "armor.stamina", -1); + if (bonus[du->race->index]==0) bonus[du->race->index] = -1; + } + if (bonus[du->race->index]>0) { + int sk = effskill(du, SK_STAMINA); + sk /= bonus[du->race->index]; + an += sk; + } + return an; +} + +boolean +terminate(troop dt, troop at, int type, const char *damage, boolean missile) +{ + item ** pitm; + fighter *df = dt.fighter; + fighter *af = at.fighter; + unit *au = af->unit; + unit *du = df->unit; + battle *b = df->side->battle; + int heiltrank = 0; + static int rule_armor = -1; + + /* Schild */ + void **si; + side *ds = df->side; + int hp; + + int ar = 0, an, am; + const armor_type * armor = select_armor(dt, true); + const armor_type * shield = select_armor(dt, false); + + const weapon_type *dwtype = NULL; + const weapon_type *awtype = NULL; + const weapon * weapon; + + int rda, sk = 0, sd; + boolean magic = false; + int da = dice_rand(damage); + + assert(du->number>0); +#ifdef SHOW_KILLS + ++at.fighter->hits; +#endif + + switch (type) { + case AT_STANDARD: + weapon = select_weapon(at, true, missile); + sk = weapon_effskill(at, dt, weapon, true, missile); + if (weapon) awtype = weapon->type; + if (awtype && fval(awtype, WTF_MAGICAL)) magic = true; + break; + case AT_NATURAL: + sk = weapon_effskill(at, dt, NULL, true, missile); + break; + case AT_SPELL: + case AT_COMBATSPELL: + magic = true; + break; + default: + break; + } + weapon = select_weapon(dt, false, true); /* missile=true to get the unmodified best weapon she has */ + sd = weapon_effskill(dt, at, weapon, false, false); + if (weapon!=NULL) dwtype=weapon->type; + + if (is_riding(at) && (awtype==NULL || (fval(awtype, WTF_HORSEBONUS) && !fval(awtype, WTF_MISSILE)))) { + da += CavalryBonus(au, dt, BONUS_DAMAGE); + } + + if (armor) { + ar += armor->prot; + if (armor->projectile>0 && chance(armor->projectile)) { + return false; + } + } + if (shield) { + ar += shield->prot; + if (shield->projectile>0 && chance(shield->projectile)) { + return false; + } + } + + /* natürliche Rüstung */ + an = natural_armor(du); + + /* magische Rüstung durch Artefakte oder Sprüche */ + /* Momentan nur Trollgürtel und Werwolf-Eigenschaft */ + am = select_magicarmor(dt); + +#if CHANGED_CROSSBOWS + if (awtype && fval(awtype, WTF_ARMORPIERCING)) { + /* crossbows */ + ar /= 2; + an /= 2; + } +#endif + + if (rule_armor<0) { + rule_armor = get_param_int(global.parameters, "rules.combat.nat_armor", 0); + } + if (rule_armor==0) { + /* natürliche Rüstung ist halbkumulativ */ + if (ar>0) { + ar += an/2; + } else { + ar = an; + } + } else { + /* use the higher value, add half the other value */ + ar = (ar>an)?(ar+an/2):(an+ar/2); + } + ar += am; + + if (type!=AT_COMBATSPELL && type!=AT_SPELL) { + if (damage_rules&DAMAGE_CRITICAL) { + double kritchance = (sk * 3 - sd) / 200.0; + + kritchance = MAX(kritchance, 0.005); + kritchance = MIN(0.9, kritchance); + + while (chance(kritchance)) { + if (bdebug) { + fprintf(bdebug, "%s/%d lands a critical hit\n", unitid(au), at.index); + } + da += dice_rand(damage); + } + } + + da += rc_specialdamage(au->race, du->race, awtype); + + if (awtype!=NULL && fval(awtype, WTF_MISSILE)) { + /* missile weapon bonus */ + if (damage_rules&DAMAGE_MISSILE_BONUS) { + da += af->person[at.index].damage_rear; + } + } else if (awtype==NULL) { + /* skill bonus for unarmed combat */ + if (damage_rules&DAMAGE_UNARMED_BONUS) { + da += effskill(au, SK_WEAPONLESS); + } + } else { + /* melee bonus */ + if (damage_rules&DAMAGE_MELEE_BONUS) { + da += af->person[at.index].damage; + } + } + + /* Skilldifferenzbonus */ + if (damage_rules&DAMAGE_SKILL_BONUS) { + da += MAX(0, (sk-sd)/DAMAGE_QUOTIENT); + } + } + + + if (magic) { + /* Magischer Schaden durch Spruch oder magische Waffe */ + double res = 1.0; + + /* magic_resistance gib x% Resistenzbonus zurück */ + res -= magic_resistance(du)*3.0; + + if (du->race->battle_flags & BF_EQUIPMENT) { +#ifdef TODO_RUNESWORD + /* Runenschwert gibt im Kampf 80% Resistenzbonus */ + if (dwp == WP_RUNESWORD) res -= 0.80; +#endif + /* der Effekt von Laen steigt nicht linear */ + if (armor && fval(armor, ATF_LAEN)) res *= (1-armor->magres); + if (shield && fval(shield, ATF_LAEN)) res *= (1-shield->magres); + if (dwtype) res *= (1-dwtype->magres); + } + + if (res > 0) { + da = (int) (MAX(da * res, 0)); + } + /* gegen Magie wirkt nur natürliche und magische Rüstung */ + ar = an+am; + } + + rda = MAX(da - ar,0); + + if ((du->race->battle_flags & BF_INV_NONMAGIC) && !magic) rda = 0; + else { + unsigned int i = 0; + if (du->race->battle_flags & BF_RES_PIERCE) i |= WTF_PIERCE; + if (du->race->battle_flags & BF_RES_CUT) i |= WTF_CUT; + if (du->race->battle_flags & BF_RES_BASH) i |= WTF_BLUNT; + + if (i && awtype && fval(awtype, i)) rda /= 2; + + /* Schilde */ + for (si = b->meffects.begin; si != b->meffects.end; ++si) { + meffect *meffect = *si; + if (meffect_protection(b, meffect, ds) != 0) { + assert(0 <= rda); /* rda sollte hier immer mindestens 0 sein */ + /* jeder Schaden wird um effect% reduziert bis der Schild duration + * Trefferpunkte aufgefangen hat */ + if (meffect->typ == SHIELD_REDUCE) { + hp = rda * (meffect->effect/100); + rda -= hp; + meffect->duration -= hp; + } + /* gibt Rüstung +effect für duration Treffer */ + if (meffect->typ == SHIELD_ARMOR) { + rda = MAX(rda - meffect->effect, 0); + meffect->duration--; + } + } + } + } + + assert(dt.indexnumber); + df->person[dt.index].hp -= rda; + if (au->race==new_race[RC_DAEMON]) { + vampirism(at, rda); + } + + if (df->person[dt.index].hp > 0) { /* Hat überlebt */ + if (bdebug) { + fprintf(bdebug, "Damage %d, armor %d: %d -> %d HP\n", + da, ar, df->person[dt.index].hp + rda, df->person[dt.index].hp); + } + if (au->race == new_race[RC_DAEMON]) { +#ifdef TODO_RUNESWORD + if (select_weapon(dt, 0, -1) == WP_RUNESWORD) continue; +#endif + if (!(df->person[dt.index].flags & (FL_COURAGE|FL_DAZZLED))) { + df->person[dt.index].flags |= FL_DAZZLED; + df->person[dt.index].defence--; + } + } + df->person[dt.index].flags = (df->person[dt.index].flags & ~FL_SLEEPING); + return false; + } + + /* Sieben Leben */ + if (du->race == new_race[RC_CAT] && (chance(1.0 / 7))) { + assert(dt.index>=0 && dt.indexnumber); + df->person[dt.index].hp = unit_max_hp(du); + return false; + } + + /* Heiltrank schluerfen und hoffen */ + if (oldpotiontype[P_HEAL]) { + if (get_effect(du, oldpotiontype[P_HEAL]) > 0) { + change_effect(du, oldpotiontype[P_HEAL], -1); + heiltrank = 1; + } else if (i_get(du->items, oldpotiontype[P_HEAL]->itype) > 0) { + i_change(&du->items, oldpotiontype[P_HEAL]->itype, -1); + change_effect(du, oldpotiontype[P_HEAL], 3); + heiltrank = 1; + } + if (heiltrank && (chance(0.50))) { + { + message * m = msg_message("battle::potionsave", "unit", du); + message_faction(b, du->faction, m); + msg_release(m); + } + assert(dt.index>=0 && dt.indexnumber); + df->person[dt.index].hp = du->race->hitpoints; + return false; + } + } +#ifdef SHOW_KILLS + ++at.fighter->kills; +#endif + + if (bdebug) { + fprintf(bdebug, "Damage %d, armor %d, type %d: %d -> %d HP, tot.\n", + da, ar, type, df->person[dt.index].hp + rda, df->person[dt.index].hp); + } + for (pitm=&du->items; *pitm; ) { + item * itm = *pitm; + const item_type * itype = itm->type; + if (!(itype->flags & ITF_CURSED) && dt.index < itm->number) { + /* 25% Grundchance, das ein Item kaputtgeht. */ + if (rng_int() % 4 < 1) { + i_change(pitm, itype, -1); + } + } + if (*pitm==itm) { + pitm = &itm->next; + } + } + kill_troop(dt); + + return true; +} + +static int +count_side(const side * s, const side * vs, int minrow, int maxrow, int select) +{ + fighter * fig; + int people = 0; + int unitrow[NUMROWS]; + + if (maxrowfighters; fig; fig = fig->next) { + if (fig->alive - fig->removed > 0) { + int row = statusrow(fig->status); + if (select&SELECT_ADVANCE) { + if (unitrow[row] == -1) { + unitrow[row] = get_unitrow(fig, vs); + } + row = unitrow[row]; + } + if (row >= minrow && row <= maxrow) { + people += fig->alive - fig->removed; + if (people>0 && (select&SELECT_FIND)) break; + } + } + } + return people; +} + +/* return the number of live allies warning: this function only considers +* troops that are still alive, not those that are still fighting although +* dead. */ +int +count_allies(const side * as, int minrow, int maxrow, int select, int allytype) +{ + battle *b = as->battle; + side *ds; + int count = 0; + + for (ds=b->sides;ds!=b->sides+b->nsides;++ds) { + if ((allytype==ALLY_ANY && helping(as, ds)) || (allytype==ALLY_SELF && as->faction==ds->faction)) { + count += count_side(ds, NULL, minrow, maxrow, select); + if (count>0 && (select&SELECT_FIND)) break; + } + } + return count; +} + +static int +count_enemies_i(battle * b, const fighter * af, int minrow, int maxrow, int select) +{ + side *es, *as = af->side; + int i = 0; + + for (es=b->sides;es!=b->sides+b->nsides;++es) { + if (as==NULL || enemy(es, as)) { + int offset = 0; + if (select&SELECT_DISTANCE) { + offset = get_unitrow(af, es) - FIGHT_ROW; + } + i += count_side(es, as, minrow-offset, maxrow-offset, select); + if (i>0 && (select&SELECT_FIND)) break; + } + } + return i; +} + +int +count_enemies(battle * b, const fighter * af, int minrow, int maxrow, int select) +{ +#ifdef FASTCOUNT + int sr = statusrow(af->status); + side *as = af->side; + + if (b->alive==b->fast.alive && as==b->fast.side && sr==b->fast.status && minrow==b->fast.minrow && maxrow==b->fast.maxrow) { + if (b->fast.enemies[select]>=0) { +#ifdef DEBUG_FAST + int i = count_enemies_i(b, af, minrow, maxrow, select); + assert(i==b->fast.enemies[select]); +#endif + return b->fast.enemies[select]; + } else if (select&SELECT_FIND) { + if (b->fast.enemies[select-SELECT_FIND]>=0) { +#ifdef DEBUG_FAST + int i = count_enemies_i(b, af, minrow, maxrow, select); + assert((i>0)==(b->fast.enemies[select-SELECT_FIND]>0)); +#endif + return b->fast.enemies[select-SELECT_FIND]; + } + } + } else if (select!=SELECT_FIND || b->alive!=b->fast.alive) { + b->fast.side = as; + b->fast.status = sr; + b->fast.minrow = minrow; + b->fast.alive=b->alive; + b->fast.maxrow = maxrow; + memset(b->fast.enemies, -1, sizeof(b->fast.enemies)); + } +#endif + if (maxrow>=FIRST_ROW) { + int i = count_enemies_i(b, af, minrow, maxrow, select); +#ifdef FASTCOUNT + b->fast.enemies[select] = i; +#endif + return i; + } + return 0; +} + +troop +select_enemy(fighter * af, int minrow, int maxrow, int select) +{ + side *as = af->side; + battle * b = as->battle; + int si, selected; + int enemies; +#ifdef DEBUG_SELECT + troop result = no_troop; +#endif + if (af->unit->race->flags & RCF_FLY) { + /* flying races ignore min- and maxrow and can attack anyone fighting + * them */ + minrow = FIGHT_ROW; + maxrow = BEHIND_ROW; + } + minrow = MAX(minrow, FIGHT_ROW); + + enemies = count_enemies(b, af, minrow, maxrow, select); + + /* Niemand ist in der angegebenen Entfernung? */ + if (enemies<=0) return no_troop; + + selected = rng_int() % enemies; + for (si=0;as->enemies[si];++si) { + side *ds = as->enemies[si]; + fighter * df; + int unitrow[NUMROWS]; + int offset = 0; + + if (select&SELECT_DISTANCE) offset = get_unitrow(af, ds) - FIGHT_ROW; + + if (select&SELECT_ADVANCE) { + int ui; + for (ui=0;ui!=NUMROWS;++ui) unitrow[ui] = -1; + } + + for (df=ds->fighters; df ; df = df->next) { + int dr; + + dr = statusrow(df->status); + if (select&SELECT_ADVANCE) { + if (unitrow[dr]<0) { + unitrow[dr] = get_unitrow(df, as); + } + dr = unitrow[dr]; + } + + if (select&SELECT_DISTANCE) dr += offset; + if (dr < minrow || dr > maxrow) continue; + if (df->alive - df->removed > selected) { +#ifdef DEBUG_SELECT + if (result.fighter==NULL) { + result.index = selected; + result.fighter = df; + } +#else + troop dt; + dt.index = selected; + dt.fighter = df; + return dt; +#endif + } + selected -= (df->alive - df->removed); + enemies -= (df->alive - df->removed); + } + } + if (enemies!=0) { + log_error(("select_enemies has a bug.\n")); + } +#ifdef DEBUG_SELECT + return result; +#else + assert(!selected); + return no_troop; +#endif +} + +static int +get_tactics(const side * as, const side * ds) +{ + battle * b = as->battle; + side *stac; + int result = 0; + int defense = 0; + + if (b->max_tactics > 0) { + for (stac=b->sides;stac!=b->sides+b->nsides;++stac) { + if (stac->leader.value > result && helping(stac, as)) { + assert(ds==NULL || !helping(stac, ds)); + result = stac->leader.value; + } + if (ds && stac->leader.value > defense && helping(stac, ds)) { + assert(!helping(stac, as)); + defense = stac->leader.value; + } + } + } + return result - defense; +} + +static troop +select_opponent(battle * b, troop at, int mindist, int maxdist) +{ + fighter * af = at.fighter; + troop dt; + + if (af->unit->race->flags & RCF_FLY) { + /* flying races ignore min- and maxrow and can attack anyone fighting + * them */ + dt = select_enemy(at.fighter, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); + } else { + mindist = MAX(mindist, FIGHT_ROW); + dt = select_enemy(at.fighter, mindist, maxdist, SELECT_ADVANCE); + } + + if (b->turn==0 && dt.fighter) { + int tactics_formula = -1; + + if (tactics_formula<0) { + tactics_formula = get_param_int(global.parameters, "rules.tactics.formula", 0); + } + if (tactics_formula==1) { + int tactics = get_tactics(at.fighter->side, dt.fighter->side); + + /* percentage chance to get this attack */ + if (tactics>0) { + double tacch = 0.1 * tactics; + if (fval(b->region->terrain, SEA_REGION)) { + ship * sh = at.fighter->unit->ship; + if (sh) tacch *= sh->type->tac_bonus; + } + if (!chance(tacch)) { + dt.fighter = NULL; + } + } else { + dt.fighter = NULL; + } + } + } + + return dt; +} + +/* + * Abfrage mit + * + * cvector *fgs=fighters(b,af,FIGHT_ROW,BEHIND_ROW, FS_HELP|FS_ENEMY); + * fighter *fig; + * + * Optional: Verwirbeln. Vorsicht: Aufwändig! + * v_scramble(fgs->begin, fgs->end); + * + * for (fig = fgs->begin; fig != fgs->end; ++fig) { + * fighter *df = *fig; + * + * } + * + * cv_kill(fgs); free(fgs); Nicht vergessen + */ + +cvector * +fighters(battle *b, const side * vs, int minrow, int maxrow, int mask) +{ + side * s; + cvector *fightervp = malloc(sizeof(cvector)); + + assert(vs!=NULL); + cv_init(fightervp); + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *fig; + + if (mask==FS_ENEMY) { + if (!enemy(s, vs)) continue; + } else if (mask==FS_HELP) { + if (enemy(s, vs) || !allysf(s, vs->faction)) { + continue; + } + } else { + assert(mask==(FS_HELP|FS_ENEMY) || !"invalid alliance state"); + } + for (fig = s->fighters; fig; fig = fig->next) { + int row = get_unitrow(fig, vs); + if (row >= minrow && row <= maxrow) { + cv_pushback(fightervp, fig); + } + } + } + + return fightervp; +} + +static void +report_failed_spell(battle * b, unit * mage, const spell * sp) +{ + message * m = msg_message("battle::spell_failed", "unit spell", mage, sp); + message_all(b, m); + msg_release(m); +} + +void +do_combatmagic(battle *b, combatmagic_t was) +{ + side * s; + region *r = b->region; + castorder *co; + int level, rank, sl; + spellrank spellranks[MAX_SPELLRANK]; + + memset(spellranks, 0, sizeof(spellranks)); + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter * fig; + for (fig = s->fighters; fig; fig = fig->next) { + unit * mage = fig->unit; + + if (fig->alive <= 0) continue; /* fighter kann im Kampf getötet worden sein */ + + level = eff_skill(mage, SK_MAGIC, r); + if (level > 0) { + double power; + const spell *sp; + const struct locale * lang = mage->faction->locale; + order * ord; + + switch(was) { + case DO_PRECOMBATSPELL: + sp = get_combatspell(mage, 0); + sl = get_combatspelllevel(mage, 0); + break; + case DO_POSTCOMBATSPELL: + sp = get_combatspell(mage, 2); + sl = get_combatspelllevel(mage, 2); + break; + default: + /* Fehler! */ + return; + } + if (sp == NULL) + continue; + + ord = create_order(K_CAST, lang, "'%s'", spell_name(sp, lang)); + if (cancast(mage, sp, 1, 1, ord) == false) { + free_order(ord); + continue; + } + + level = eff_spelllevel(mage, sp, level, 1); + if (sl > 0) level = MIN(sl, level); + if (level < 0) { + report_failed_spell(b, mage, sp); + free_order(ord); + continue; + } + + power = spellpower(r, mage, sp, level, ord); + free_order(ord); + if (power <= 0) { /* Effekt von Antimagie */ + report_failed_spell(b, mage, sp); + pay_spell(mage, sp, level, 1); + } else if (fumble(r, mage, sp, sp->level) == true) { + report_failed_spell(b, mage, sp); + pay_spell(mage, sp, level, 1); + } else { + co = new_castorder(fig, 0, sp, r, level, power, 0, 0, 0); + add_castorder(&spellranks[sp->rank], co); + } + } + } + } + for (rank = 0; rank < MAX_SPELLRANK; rank++) { + for (co = spellranks[rank].begin; co; co = co->next) { + fighter * fig = co->magician.fig; + const spell * sp = co->sp; + int level = co->level; + double power = co->force; + + if (sp->sp_function==NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + } else { + level = ((cspell_f)sp->sp_function)(fig, level, power, sp); + if (level > 0) { + pay_spell(fig->unit, sp, level, 1); + } + } + } + } + for (rank = 0; rank < MAX_SPELLRANK; rank++) { + free_castorders(spellranks[rank].begin); + } +} + +static void +combat_action(fighter * af, int turn) +{ +#ifndef SIMPLE_COMBAT + af->action_counter++; + af->side->bf->lastturn = turn; +#endif +} + + +static void +do_combatspell(troop at) +{ + const spell *sp; + fighter *fi = at.fighter; + unit *mage = fi->unit; + battle *b = fi->side->battle; + region *r = b->region; + int level; + double power; + int fumblechance = 0; + void **mg; + order * ord; + int sl; + const struct locale * lang = mage->faction->locale; + + sp = get_combatspell(mage, 1); + if (sp == NULL) { + fi->magic = 0; /* Hat keinen Kampfzauber, kämpft nichtmagisch weiter */ + return; + } + ord = create_order(K_CAST, lang, "'%s'", spell_name(sp, lang)); + if (cancast(mage, sp, 1, 1, ord) == false) { + fi->magic = 0; /* Kann nicht mehr Zaubern, kämpft nichtmagisch weiter */ + return; + } + + level = eff_spelllevel(mage, sp, fi->magic, 1); + if ((sl = get_combatspelllevel(mage, 1)) > 0) level = MIN(level, sl); + + if (fumble(r, mage, sp, sp->level) == true) { + report_failed_spell(b, mage, sp); + pay_spell(mage, sp, level, 1); + return; + } + + for (mg = b->meffects.begin; mg != b->meffects.end; ++mg) { + meffect *mblock = *mg; + if (mblock->typ == SHIELD_BLOCK) { + if (meffect_blocked(b, mblock, fi->side) != 0) { + fumblechance += mblock->duration; + mblock->duration -= mblock->effect; + } + } + } + + /* Antimagie die Fehlschlag erhöht */ + if (rng_int()%100 < fumblechance) { + report_failed_spell(b, mage, sp); + pay_spell(mage, sp, level, 1); + free_order(ord); + return; + } + power = spellpower(r, mage, sp, level, ord); + free_order(ord); + if (power <= 0) { /* Effekt von Antimagie */ + report_failed_spell(b, mage, sp); + pay_spell(mage, sp, level, 1); + return; + } + + if (sp->sp_function==NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + } else { + level = ((cspell_f)sp->sp_function)(fi, level, power, sp); + if (level > 0) { + pay_spell(mage, sp, level, 1); + combat_action(at.fighter, b->turn); + } + } +} + + +/* Sonderattacken: Monster patzern nicht und zahlen auch keine + * Spruchkosten. Da die Spruchstärke direkt durch den Level bestimmt + * wird, wirkt auch keine Antimagie (wird sonst in spellpower + * gemacht) */ + +static void +do_extra_spell(troop at, const att *a) +{ + const spell *sp = a->data.sp; + fighter *fi = at.fighter; + double power; + + power = sp->level * MagicPower(); + if (sp->sp_function==NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + } else { + ((cspell_f)sp->sp_function)(fi, sp->level, power, sp); + } +} + +static int +skilldiff(troop at, troop dt, int dist) +{ + fighter *af = at.fighter, *df = dt.fighter; + unit *au = af->unit, *du = df->unit; + int is_protected = 0, skdiff = 0; + weapon * awp = select_weapon(at, true, dist>1); + + skdiff += af->person[at.index].attack; + skdiff -= df->person[dt.index].defence; + + if (df->person[dt.index].flags & FL_SLEEPING) + skdiff += 2; + + /* Effekte durch Rassen */ + if (awp!=NULL && au->race == new_race[RC_HALFLING] && dragonrace(du->race)) { + skdiff += 5; + } + + if (au->race == new_race[RC_GOBLIN]) { + static int goblin_bonus = -1; + if (goblin_bonus<0) goblin_bonus = get_param_int(global.parameters, "rules.combat.goblinbonus", 10); + if (af->side->size[SUM_ROW] >= df->side->size[SUM_ROW] * goblin_bonus) { + skdiff += 1; + } + } + + if (df->building) { + boolean init = false; + static const curse_type * strongwall_ct, * magicwalls_ct; + if (!init) { + strongwall_ct = ct_find("strongwall"); + magicwalls_ct = ct_find("magicwalls"); + init=true; + } + if (df->building->type->protection) { + int beff = df->building->type->protection(df->building, du); + if (beff) { + skdiff -= beff; + is_protected = 2; + } + } + if (strongwall_ct) { + curse * c = get_curse(df->building->attribs, strongwall_ct); + if (curse_active(c)) { + /* wirkt auf alle Gebäude */ + skdiff -= curse_geteffect_int(c); + is_protected = 2; + } + } + if (magicwalls_ct && curse_active(get_curse(df->building->attribs, magicwalls_ct))) { + /* Verdoppelt Burgenbonus */ + skdiff -= buildingeffsize(df->building, false); + } + } + /* Goblin-Verteidigung + * ist direkt in der Rassentabelle als df_default + */ + + /* Effekte der Waffen */ + skdiff += weapon_effskill(at, dt, awp, true, dist>1); + if (awp && fval(awp->type, WTF_MISSILE)) { + skdiff -= is_protected; + if (awp->type->modifiers) { + int w; + for (w=0;awp->type->modifiers[w].value!=0;++w) { + if (awp->type->modifiers[w].flags & WMF_MISSILE_TARGET) { + /* skill decreases by targeting difficulty (bow -2, catapult -4) */ + skdiff -= awp->type->modifiers[w].value; + break; + } + } + } + } + if (skill_formula==FORMULA_ORIG) { + weapon * dwp = select_weapon(dt, false, dist>1); + skdiff -= weapon_effskill(dt, at, dwp, false, dist>1); + } + return skdiff; +} + +static int +setreload(troop at) +{ + fighter * af = at.fighter; + const weapon_type * wtype = af->person[at.index].missile->type; + if (wtype->reload == 0) return 0; + return af->person[at.index].reload = wtype->reload; +} + +int +getreload(troop at) +{ + return at.fighter->person[at.index].reload; +} + +static void +debug_hit(troop at, const weapon * awp, troop dt, const weapon * dwp, int skdiff, int dist, boolean success) +{ + fprintf(bdebug, "%.4s/%d [%6s/%d] %s %.4s/%d [%6s/%d] with %d, distance %d\n", + unitid(at.fighter->unit), at.index, + LOC(default_locale, awp ? resourcename(awp->type->itype->rtype, 0) : "unarmed"), + weapon_effskill(at, dt, awp, true, dist>1), + success?"hits":"misses", + unitid(dt.fighter->unit), dt.index, + LOC(default_locale, dwp ? resourcename(dwp->type->itype->rtype, 0) : "unarmed"), + weapon_effskill(dt, at, dwp, false, dist>1), + skdiff, dist); +} + +int +hits(troop at, troop dt, weapon * awp) +{ + fighter *af = at.fighter, *df = dt.fighter; + const armor_type * armor, * shield = 0; + int skdiff = 0; + int dist = get_unitrow(af, df->side) + get_unitrow(df, af->side) - 1; + weapon * dwp = select_weapon(dt, false, dist>1); + + if (!df->alive) return 0; + if (getreload(at)) return 0; + if (dist>1 && (awp == NULL || !fval(awp->type, WTF_MISSILE))) return 0; + + /* mark this person as hit. */ + df->person[dt.index].flags |= FL_HIT; + + if (af->person[at.index].flags & FL_STUNNED) { + af->person[at.index].flags &= ~FL_STUNNED; + return 0; + } + if ((af->person[at.index].flags & FL_TIRED && rng_int()%100 < 50) + || (af->person[at.index].flags & FL_SLEEPING)) + return 0; + + /* effect of sp_reeling_arrows combatspell */ + if (af->side->battle->reelarrow && awp && fval(awp->type, WTF_MISSILE) && rng_double() < 0.5) { + return 0; + } + + skdiff = skilldiff(at, dt, dist); + /* Verteidiger bekommt eine Rüstung */ + armor = select_armor(dt, true); + if (dwp==NULL || (dwp->type->flags & WTF_USESHIELD)) { + shield = select_armor(dt, false); + } + if (contest(skdiff, dt, armor, shield)) { + if (bdebug) { + debug_hit(at, awp, dt, dwp, skdiff, dist, true); + } + return 1; + } + if (bdebug) { + debug_hit(at, awp, dt, dwp, skdiff, dist, false); + } + return 0; +} + +void +dazzle(battle *b, troop *td) +{ + /* Nicht kumulativ ! */ + if(td->fighter->person[td->index].flags & FL_DAZZLED) return; + +#ifdef TODO_RUNESWORD + if (td->fighter->weapon[WP_RUNESWORD].count > td->index) { + return; + } +#endif + if (td->fighter->person[td->index].flags & FL_COURAGE) { + return; + } + + if (td->fighter->person[td->index].flags & FL_DAZZLED) { + return; + } + + td->fighter->person[td->index].flags |= FL_DAZZLED; + td->fighter->person[td->index].defence--; +} + +/* TODO: Gebäude/Schiffe sollten auch zerstörbar sein. Schwierig im Kampf, + * besonders bei Schiffen. */ + +void +damage_building(battle *b, building *bldg, int damage_abs) +{ + bldg->size = MAX(1, bldg->size-damage_abs); + + /* Wenn Burg, dann gucken, ob die Leute alle noch in das Gebäude passen. */ + + if (bldg->type->protection) { + side * s; + + bldg->sizeleft = bldg->size; + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter * fig; + for (fig=s->fighters;fig;fig=fig->next) { + if (fig->building == bldg) { + if (bldg->sizeleft >= fig->unit->number) { + fig->building = bldg; + bldg->sizeleft -= fig->unit->number; + } else { + fig->building = NULL; + } + } + } + } + } +} + +static int +attacks_per_round(troop t) +{ + return t.fighter->person[t.index].speed; +} + +static void +make_heroes(battle * b) +{ + side * s; + static int hero_speed = 0; + if (hero_speed==0) { + hero_speed = get_param_int(global.parameters, "rules.combat.herospeed", 10); + } + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter * fig; + for (fig=s->fighters;fig;fig=fig->next) { + unit * u = fig->unit; + if (fval(u, UFL_HERO)) { + int i; + assert(playerrace(u->race)); + for (i=0;i!=u->number;++i) { + fig->person[i].speed += (hero_speed-1); + } + } + } + } +} + +static void +attack(battle *b, troop ta, const att *a, int numattack) +{ + fighter *af = ta.fighter; + troop td; + unit *au = af->unit; + + switch(a->type) { + case AT_COMBATSPELL: + /* Magier versuchen immer erstmal zu zaubern, erst wenn das + * fehlschlägt, wird af->magic == 0 und der Magier kämpft + * konventionell weiter */ + if (numattack==0 && af->magic > 0) { + /* wenn der magier in die potenzielle Reichweite von Attacken des + * Feindes kommt, beginnt er auch bei einem Status von KAEMPFE NICHT, + * Kampfzauber zu schleudern: */ + if (count_enemies(b, af, melee_range[0], missile_range[1], SELECT_ADVANCE|SELECT_DISTANCE|SELECT_FIND)) { + do_combatspell(ta); + } + } + break; + case AT_STANDARD: /* Waffen, mag. Gegenstände, Kampfzauber */ + if (numattack > 0 || af->magic <= 0) { + weapon * wp = ta.fighter->person[ta.index].missile; + int melee = count_enemies(b, af, melee_range[0], melee_range[1], SELECT_ADVANCE|SELECT_DISTANCE|SELECT_FIND); + if (melee) wp = preferred_weapon(ta, true); + /* Sonderbehandlungen */ + + if (getreload(ta)) { + ta.fighter->person[ta.index].reload--; + } else { + boolean standard_attack = true; + boolean reload = false; + /* spezialattacken der waffe nur, wenn erste attacke in der runde. + * sonst helden mit feuerschwertern zu mächtig */ + if (numattack==0 && wp && wp->type->attack) { + int dead = 0; + standard_attack = wp->type->attack(&ta, wp->type, &dead); + if (!standard_attack) reload = true; + af->catmsg += dead; + if (!standard_attack && af->person[ta.index].last_action < b->turn) { + af->person[ta.index].last_action = b->turn; + combat_action(af, b->turn); + } + } + if (standard_attack) { + boolean missile = false; + if (wp && fval(wp->type, WTF_MISSILE)) missile = true; + if (missile) { + td = select_opponent(b, ta, missile_range[0], missile_range[1]); + } + else { + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + } + if (!td.fighter) return; + if (ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + reload = true; + if (hits(ta, td, wp)) { + const char * d; + if (wp == NULL) d = au->race->def_damage; + else if (is_riding(ta)) d = wp->type->damage[1]; + else d = wp->type->damage[0]; + terminate(td, ta, a->type, d, missile); + } + } + if (reload && wp && wp->type->reload && !getreload(ta)) { + int i = setreload(ta); + if (bdebug) { + fprintf(bdebug, "%s/%d reloading %d turns\n", unitid(au), ta.index, i); + } + } + } + } + break; + case AT_SPELL: /* Extra-Sprüche. Kampfzauber in AT_COMBATSPELL! */ + do_extra_spell(ta, a); + break; + case AT_NATURAL: + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + if (!td.fighter) return; + if(ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + if (hits(ta, td, NULL)) { + terminate(td, ta, a->type, a->data.dice, false); + } + break; + case AT_DRAIN_ST: + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + if (!td.fighter) return; + if(ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + if (hits(ta, td, NULL)) { + int c = dice_rand(a->data.dice); + while(c > 0) { + if (rng_int()%2) { + td.fighter->person[td.index].attack -= 1; + } else { + td.fighter->person[td.index].defence -= 1; + } + c--; + } + } + break; + case AT_DRAIN_EXP: + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + if (!td.fighter) return; + if(ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + if (hits(ta, td, NULL)) { + drain_exp(td.fighter->unit, dice_rand(a->data.dice)); + } + break; + case AT_DAZZLE: + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + if (!td.fighter) return; + if(ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + if (hits(ta, td, NULL)) { + dazzle(b, &td); + } + break; + case AT_STRUCTURAL: + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + if (!td.fighter) return; + if(ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + if (td.fighter->unit->ship) { + td.fighter->unit->ship->damage += DAMAGE_SCALE * dice_rand(a->data.dice); + } else if (td.fighter->unit->building) { + damage_building(b, td.fighter->unit->building, dice_rand(a->data.dice)); + } + } +} + +void +do_attack(fighter * af) +{ + troop ta; + unit *au = af->unit; + side *side = af->side; + battle *b = side->battle; + + ta.fighter = af; + + assert(au && au->number); + /* Da das Zuschlagen auf Einheiten und nicht auf den einzelnen + * Kämpfern beruht, darf die Reihenfolge und Größe der Einheit keine + * Rolle spielen, Das tut sie nur dann, wenn jeder, der am Anfang der + * Runde lebte, auch zuschlagen darf. Ansonsten ist der, der zufällig + * mit einer großen Einheit zuerst drankommt, extrem bevorteilt. */ + ta.index = af->fighting; + + while (ta.index--) { + /* Wir suchen eine beliebige Feind-Einheit aus. An der können + * wir feststellen, ob noch jemand da ist. */ + int apr, attacks = attacks_per_round(ta); + if (!count_enemies(b, af, FIGHT_ROW, LAST_ROW, SELECT_FIND)) break; + + for (apr=0;apr!=attacks;++apr) { + int a; + for (a=0; a!=10 && au->race->attack[a].type!=AT_NONE; ++a) { + if (apr>0) { + /* Wenn die Waffe nachladen muss, oder es sich nicht um einen + * Waffen-Angriff handelt, dann gilt der Speed nicht. */ + if (au->race->attack[a].type!=AT_STANDARD) continue; + else { + weapon * wp = preferred_weapon(ta, true); + if (wp!=NULL && wp->type->reload) continue; + } + } + attack(b, ta, &(au->race->attack[a]), apr); + } + } + } + /* Der letzte Katapultschütze setzt die + * Ladezeit neu und generiert die Meldung. */ + if (af->catmsg>=0) { + struct message * m = msg_message("battle::killed", "unit dead", au, af->catmsg); + message_all(b, m); + msg_release(m); + af->catmsg = -1; + } +} + +void +do_regenerate(fighter *af) +{ + troop ta; + unit *au = af->unit; + + ta.fighter = af; + ta.index = af->fighting; + + while(ta.index--) { + af->person[ta.index].hp += effskill(au, SK_STAMINA); + af->person[ta.index].hp = MIN(unit_max_hp(au), af->person[ta.index].hp); + } +} + +static void +add_tactics(tactics * ta, fighter * fig, int value) +{ + if (value == 0 || value < ta->value) + return; + if (value > ta->value) + cv_kill(&ta->fighters); + cv_pushback(&ta->fighters, fig); + cv_pushback(&fig->side->battle->leaders, fig); + ta->value = value; +} + +static double horsebonus(const unit * u) +{ + static const item_type * it_horse = 0; + static const item_type * it_elvenhorse = 0; + static const item_type * it_charger = 0; + region * r = u->region; + int n1 = 0, n2 = 0, n3 = 0; + item * itm = u->items; + int skl = eff_skill(u, SK_RIDING, r); + + if (skl<1) return 0.0; + + if (it_horse==0) { + it_horse = it_find("horse"); + it_elvenhorse = it_find("elvenhorse"); + it_charger = it_find("charger"); + } + + for (;itm;itm=itm->next) { + if (itm->type->flags&ITF_ANIMAL) { + if (itm->type==it_elvenhorse) n3 +=itm->number; + else if (itm->type==it_charger) n2 +=itm->number; + else if (itm->type==it_horse) n1 +=itm->number; + } + } + if (skl >= 5 && n3>=u->number) return 0.30; + if (skl >= 3 && n2+n3>=u->number) return 0.20; + if (skl >= 1 && n1+n2+n3>=u->number) return 0.10; + return 0.0F; +} + +double +fleechance(unit * u) +{ + double c = 0.20; /* Fluchtwahrscheinlichkeit in % */ + region * r = u->region; + attrib * a = a_find(u->attribs, &at_fleechance); + /* Einheit u versucht, dem Getümmel zu entkommen */ + + c += (eff_skill(u, SK_STEALTH, r) * 0.05); + c += horsebonus(u); + + if (u->race == new_race[RC_HALFLING]) { + c += 0.20; + c = MIN(c, 0.90); + } else { + c = MIN(c, 0.75); + } + + if (a!=NULL) c += a->data.flt; + + return c; +} + +/** add a new army to the conflict + * beware: armies need to be added _at the beginning_ of the list because + * otherwise join_allies() will get into trouble */ +static side * +make_side(battle * b, const faction * f, const group * g, unsigned int flags, const faction *stealthfaction) +{ + side *s1 = b->sides+b->nsides; + bfaction * bf; + +#ifdef SIMPLE_COMBAT + if (fval(b->region->terrain, SEA_REGION)) { + /* every fight in an ocean is short */ + flags |= SIDE_HASGUARDS; + } else { + unit * u; + for (u = b->region->units; u; u = u->next) { + if (is_guard(u, HELP_ALL)) { + if (alliedunit(u, f, HELP_GUARD)) { + flags |= SIDE_HASGUARDS; + break; + } + } + } + } +#endif + + s1->battle = b; + s1->group = g; + s1->flags = flags; + s1->stealthfaction = stealthfaction; + for (bf = b->factions;bf;bf=bf->next) { + faction * f2 = bf->faction; + + if (f2 == f) { + s1->bf = bf; + s1->faction = f2; + s1->index = b->nsides++; + s1->nextF = bf->sides; + bf->sides = s1; + assert(b->nsides<=MAXSIDES); + break; + } + } + assert(bf); + return s1; +} + +troop +select_ally(fighter * af, int minrow, int maxrow, int allytype) +{ + side *as = af->side; + battle *b = as->battle; + side * ds; + int allies = count_allies(as, minrow, maxrow, SELECT_ADVANCE, allytype); + + if (!allies) { + return no_troop; + } + allies = rng_int() % allies; + + for (ds=b->sides;ds!=b->sides+b->nsides;++ds) { + if ((allytype==ALLY_ANY && helping(as, ds)) || (allytype==ALLY_SELF && as->faction==ds->faction)) { + fighter * df; + for (df=ds->fighters; df; df=df->next) { + int dr = get_unitrow(df, NULL); + if (dr >= minrow && dr <= maxrow) { + if (df->alive - df->removed > allies) { + troop dt; + assert(allies>=0); + dt.index = allies; + dt.fighter = df; + return dt; + } + allies -= df->alive; + } + } + } + } + assert(!"we should never have gotten here"); + return no_troop; +} + + +static int loot_quota(const unit * src, const unit * dst, const item_type * type, int n) +{ + static float divisor = -1; + if (dst && src && src->faction!=dst->faction) { + if (divisor<0) { + divisor = get_param_flt(global.parameters, "rules.items.loot_divisor", 1); + assert(divisor==0 || divisor>=1); + } + if (divisor>=1) { + double r = n / divisor; + int x = (int)r; + + r = r - x; + if (chance(r)) ++x; + + return x; + } + } + return n; +} + +static void +loot_items(fighter * corpse) +{ + unit * u = corpse->unit; + item * itm = u->items; + battle * b = corpse->side->battle; + int dead = dead_fighters(corpse); + + if (dead<=0) return; + + while (itm) { + float lootfactor = dead/(float)u->number; /* only loot the dead! */ + int maxloot = (int)(itm->number*lootfactor); + if (maxloot>0) { + int i = MIN(10, maxloot); + for (; i != 0; --i) { + int loot = maxloot/i; + + if (loot>0) { + fighter *fig = NULL; + int looting = 0; + int maxrow = 0; + /* mustloot: we absolutely, positively must have somebody loot this thing */ + int mustloot = itm->type->flags & (ITF_CURSED|ITF_NOTLOST); + + itm->number -= loot; + maxloot -= loot; + + if (is_monsters(u->faction) && (loot_rules & LOOT_MONSTERS)) { + looting = 1; + } else if (loot_rules&LOOT_OTHERS) { + looting = 1; + } else if (loot_rules&LOOT_SELF) { + looting = 2; + } + if (looting) { + if (mustloot) { + maxrow = LAST_ROW; + } else if (loot_rules&LOOT_KEEPLOOT) { + int lootchance = 50 + b->keeploot; + if (rng_int() % 100 < lootchance) { + maxrow = BEHIND_ROW; + } + } else { + maxrow = LAST_ROW; + } + } + if (maxrow>0) { + if (looting==1) { + /* enemies get dibs */ + fig = select_enemy(corpse, FIGHT_ROW, maxrow, 0).fighter; + } + if (!fig) { + /* self and allies get second pick */ + fig = select_ally(corpse, FIGHT_ROW, LAST_ROW, ALLY_SELF).fighter; + } + } + + if (fig) { + int trueloot = mustloot?loot:loot_quota(corpse->unit, fig->unit, itm->type, loot); + if (trueloot>0) { + item * l = fig->loot; + while (l && l->type!=itm->type) l=l->next; + if (!l) { + l = calloc(sizeof(item), 1); + l->next = fig->loot; + fig->loot = l; + l->type = itm->type; + } + l->number += trueloot; + } + } + } + } + } + itm = itm->next; + } +} + +#ifndef SIMPLE_ESCAPE +static void +loot_fleeing(fighter* fig, unit* runner) +{ + /* TODO: Vernünftig fixen */ + runner->items = NULL; + assert(runner->items == NULL); + runner->items = fig->run.items; + fig->run.items = NULL; +} + +static void +merge_fleeloot(fighter* fig, unit* u) +{ + i_merge(&u->items, &fig->run.items); +} +#endif /* SIMPLE_ESCAPE */ + +static boolean +seematrix(const faction * f, const side * s) +{ + if (f==s->faction) return true; + if (s->flags & SIDE_STEALTH) return false; + return true; +} + +static double +PopulationDamage(void) +{ + static double value = -1.0; + if (value<0) { + int damage = get_param_int(global.parameters, "rules.combat.populationdamage", BATTLE_KILLS_PEASANTS); + value = damage/100.0; + } + return value; +} + + +static void +battle_effects(battle * b, int dead_players) +{ + region * r = b->region; + int dead_peasants = MIN(rpeasants(r), (int)(dead_players*PopulationDamage())); + if (dead_peasants) { + deathcounts(r, dead_peasants + dead_players); + chaoscounts(r, dead_peasants / 2); + rsetpeasants(r, rpeasants(r) - dead_peasants); + } +} + +static void +reorder_fleeing(region * r) +{ + unit **usrc = &r->units; + unit **udst = &r->units; + unit *ufirst = NULL; + unit *u; + + for (;*udst;udst=&u->next) { + u = *udst; + } + + for (u=*usrc;u!=ufirst;u=*usrc) { + if (u->next && fval(u, UFL_FLEEING)) { + *usrc = u->next; + *udst = u; + udst = &u->next; + if (!ufirst) ufirst = u; + } else { + usrc = &u->next; + } + } + *udst = NULL; +} + +static void +aftermath(battle * b) +{ + int i; + region *r = b->region; + ship *sh; + side *s; + int dead_players = 0; + bfaction * bf; + boolean ships_damaged = (boolean)(b->turn+(b->has_tactics_turn?1:0)>2); /* only used for ship damage! */ + +#ifdef TROLLSAVE + int *trollsave = calloc(2 * cv_size(&b->factions), sizeof(int)); +#endif + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter * df; + for (df = s->fighters; df; df=df->next) { + unit *du = df->unit; + int dead = dead_fighters(df); + int pr_mercy = 0; + +#ifdef TROLLSAVE + /* Trolle können regenerieren */ + if (df->alive > 0 && dead>0 && du->race == new_race[RC_TROLL]) { + for (i = 0; i != dead; ++i) { + if (chance(TROLL_REGENERATION)) { + ++df->alive; + ++s->alive; + ++s->battle->alive; + ++trollsave[s->index]; + /* do not change dead here, or loop will not terminate! recalculate later */ + } + } + dead = dead_fighters(df); + } +#endif + /* Regeneration durch PR_MERCY */ + if (dead>0 && pr_mercy) { + for (i = 0; i != dead; ++i) { + if (rng_int()%100 < pr_mercy) { + ++df->alive; + ++s->alive; + ++s->battle->alive; + /* do not change dead here, or loop will not terminate! recalculate later */ + } + } + dead = dead_fighters(df); + } + + /* tote insgesamt: */ + s->dead += dead; + /* Tote, die wiederbelebt werde können: */ + if (playerrace(df->unit->race)) { + s->casualties += dead; + } +#ifdef SHOW_KILLS + if (df->hits + df->kills) { + struct message * m = msg_message("killsandhits", "unit hits kills", du, df->hits, df->kills); + message_faction(b, du->faction, m); + msg_release(m); + } +#endif + } + } + + /* POSTCOMBAT */ + do_combatmagic(b, DO_POSTCOMBATSPELL); + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + int snumber = 0; + fighter *df; + boolean relevant = false; /* Kampf relevant für diese Partei? */ +#ifdef SIMPLE_COMBAT + if (fval(s, SIDE_HASGUARDS) == 0) relevant = true; +#else + if (s->bf->lastturn>1) { + relevant = true; + } else if (s->bf->lastturn==1 && b->has_tactics_turn) { + side * stac; + for (stac=b->sides; stac; stac=stac->next) { + if (stac->leader.value == b->max_tactics && helping(stac, s)) { + relevant = true; + break; + } + } + } +#endif + s->flee = 0; + + for (df=s->fighters;df;df=df->next) { + unit *du = df->unit; + int dead = dead_fighters(df); + int sum_hp = 0; + int n; + + for (n = 0; n != df->alive; ++n) { + if (df->person[n].hp > 0) { + sum_hp += df->person[n].hp; + } + } + snumber += du->number; +#ifdef SIMPLE_COMBAT + if (relevant) { + int flags = UFL_LONGACTION|UFL_NOTMOVING; +#ifdef SIMPLE_ESCAPE + if (du->status==ST_FLEE) flags -= UFL_NOTMOVING; +#endif /* SIMPLE_ESCAPE */ + fset(du, flags); + } + if (sum_hp+df->run.hphp) { + /* someone on the ship got damaged, damage the ship */ + ship * sh = du->ship?du->ship:leftship(du); + if (sh) fset(sh, SF_DAMAGED); + } +#else + if (relevant) { + fset(du, UFL_NOTMOVING); /* unit cannot move this round */ + if (df->action_counter >= du->number) { + ship * sh = du->ship?du->ship:leftship(du); + if (sh) fset(sh, SF_DAMAGED); + fset(du, UFL_LONGACTION); + } + } +#endif + + if (df->alive == du->number) { + du->hp = sum_hp; + continue; /* nichts passiert */ + } else if (df->run.hp) { + if (df->alive == 0) { + /* Report the casualties */ + reportcasualties(b, df, dead); + + /* Zuerst dürfen die Feinde plündern, die mitgenommenen Items + * stehen in fig->run.items. Dann werden die Fliehenden auf + * die leere (tote) alte Einheit gemapt */ +#ifdef SIMPLE_ESCAPE + if (!fval(df, FIG_NOLOOT)) { + loot_items(df); + } +#else + if (fval(df, FIG_NOLOOT)){ + merge_fleeloot(df, du); + } else { + loot_items(df); + loot_fleeing(df, du); + } +#endif /* SIMPLE_ESCAPE */ + scale_number(du, df->run.number); + du->hp = df->run.hp; + setguard(du, GUARD_NONE); + /* must leave ships or buildings, or a stealthy hobbit + * can hold castles indefinitely */ + if (!fval(r->terrain, SEA_REGION)) { + leave(du, true); /* even region owners have to flee */ + } +#ifndef SIMPLE_ESCAPE + if (df->run.region) { + run_to(du, df->run.region); + df->run.region = du->region; + } + fset(du, UFL_LONGACTION|UFL_NOTMOVING); +#endif /* SIMPLE_ESCAPE */ + fset(du, UFL_FLEEING); + } else { + /* nur teilweise geflohene Einheiten mergen sich wieder */ + df->alive += df->run.number; + s->size[0] += df->run.number; + s->size[statusrow(df->status)] += df->run.number; + s->alive += df->run.number; + sum_hp += df->run.hp; +#ifndef SIMPLE_ESCAPE + merge_fleeloot(df, du); +#endif /* SIMPLE_ESCAPE */ + df->run.number = 0; + df->run.hp = 0; + /* df->run.region = NULL;*/ + + reportcasualties(b, df, dead); + + scale_number(du, df->alive); + du->hp = sum_hp; + } + } else { + if (df->alive==0) { + /* alle sind tot, niemand geflohen. Einheit auflösen */ + df->run.number = 0; + df->run.hp = 0; +#ifndef SIMPLE_ESCAPE + df->run.region = NULL; +#endif /* SIMPLE_ESCAPE */ + + /* Report the casualties */ + reportcasualties(b, df, dead); + + /* Distribute Loot */ + loot_items(df); + + setguard(du, GUARD_NONE); + scale_number(du, 0); + } else { + df->run.number = 0; + df->run.hp = 0; + + reportcasualties(b, df, dead); + + scale_number(du, df->alive); + du->hp = sum_hp; + } + } + s->flee += df->run.number; + + if (playerrace(du->race)) { + /* tote im kampf werden zu regionsuntoten: + * for each of them, a peasant will die as well */ + dead_players += dead; + } + if (du->hp < du->number) { + log_error(("%s has less hitpoints (%u) than people (%u)\n", + itoa36(du->no), du->hp, du->number)); + du->hp = du->number; + } + } + s->alive+=s->healed; + assert(snumber==s->flee+s->alive+s->dead); + } + + battle_effects(b, dead_players); + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + message * seen = msg_message("battle::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", + "index abbrev dead fled survived", + army_index(s), "-?-", s->dead, s->flee, s->alive); + + for (bf=b->factions;bf;bf=bf->next) { + faction * f = bf->faction; + message * m = seematrix(f, s)?seen:unseen; + + message_faction(b, f, m); + } + + msg_release(seen); + msg_release(unseen); + } + + /* Wir benutzen drifted, um uns zu merken, ob ein Schiff + * schonmal Schaden genommen hat. (moved und drifted + * sollten in flags überführt werden */ + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *df; + + for (df=s->fighters; df; df=df->next) { + unit *du = df->unit; + item * l; + + /* Beute verteilen */ + for (l=df->loot; l; l=l->next) { + const item_type * itype = l->type; + message * m = msg_message("battle_loot", "unit amount item", du, l->number, itype->rtype); + message_faction(b, du->faction, m); + msg_release(m); + i_change(&du->items, itype, l->number); + } + + /* Wenn sich die Einheit auf einem Schiff befindet, wird + * dieses Schiff beschädigt. Andernfalls ein Schiff, welches + * evt. zuvor verlassen wurde. */ + if (ships_damaged) { + if (du->ship) sh = du->ship; + else sh = leftship(du); + + if (sh && fval(sh, SF_DAMAGED)) { + int n = b->turn - 2; + if (n>0) { + damage_ship(sh, 0.05 * n); + freset(sh, SF_DAMAGED); + } + } + } + } + } + + if (ships_damaged) { + ship **sp = &r->ships; + + while (*sp) { + ship * sh = *sp; + freset(sh, SF_DAMAGED); + if (sh->damage >= sh->size * DAMAGE_SCALE) { + remove_ship(sp, sh); + } + if (*sp==sh) sp=&sh->next; + } + } +#ifdef TROLLSAVE + free(trollsave); +#endif + + reorder_fleeing(r); + + if (bdebug) { + fprintf(bdebug, "The battle lasted %d turns, %s and %s.\n", + b->turn, + b->has_tactics_turn?"had a tactic turn":"had no tactic turn", + ships_damaged?"was relevant":"was not relevant."); + } +} + +static void +battle_punit(unit * u, battle * b) +{ + bfaction * bf; + strlist *S, *x; + + for (bf = b->factions;bf;bf=bf->next) { + faction *f = bf->faction; + + S = 0; + spunit(&S, f, u, 4, see_battle); + for (x = S; x; x = x->next) { + fbattlerecord(b, f, x->s); + if (bdebug && u->faction == f) { + fputs(x->s, bdebug); + fputc('\n', bdebug); + } + } + if (S) + freestrlist(S); + } +} + +static void +print_fighters(battle * b, const side * s) +{ + fighter *df; + int row; + + for (row=1;row!=NUMROWS;++row) { + message * m = NULL; + + for (df=s->fighters; df; df=df->next) { + unit *du = df->unit; + int thisrow = statusrow(df->unit->status); + + if (row == thisrow) { + if (m==NULL) { + m = msg_message("battle::row_header", "row", row); + message_all(b, m); + } + battle_punit(du, b); + } + } + if (m!=NULL) msg_release(m); + } +} + +boolean +is_attacker(const fighter * fig) +{ + return fval(fig, FIG_ATTACKER)!=0; +} + +static void +set_attacker(fighter * fig) +{ + fset(fig, FIG_ATTACKER); +} + +static void +print_header(battle * b) +{ + bfaction * bf; + char zText[32*MAXSIDES]; + + for (bf=b->factions;bf;bf=bf->next) { + message * m; + faction * f = bf->faction; + const char * lastf = NULL; + boolean first = false; + side * s; + char * bufp = zText; + size_t size = sizeof(zText) - 1; + int bytes; + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *df; + for (df=s->fighters;df;df=df->next) { + if (is_attacker(df)) { + if (first) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (lastf) { + bytes = (int)strlcpy(bufp, (const char *)lastf, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + first = true; + } + if (seematrix(f, s) == true) + lastf = sidename(s); + else + lastf = LOC(f->locale, "unknown_faction_dative"); + break; + } + } + } + if (first) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, (const char *)LOC(f->locale, "and"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (lastf) { + bytes = (int)strlcpy(bufp, (const char *)lastf, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + m = msg_message("battle::starters", "factions", zText); + message_faction(b, f, m); + msg_release(m); + } +} + +static void +print_stats(battle * b) +{ + side *s2; + side *s; + int i = 0; + for (s=b->sides;s!=b->sides+b->nsides;++s) { + bfaction *bf; + + ++i; + + for (bf=b->factions;bf;bf=bf->next) { + faction * f = bf->faction; + const char * loc_army = LOC(f->locale, "battle_army"); + char * bufp; + const char * header; + size_t rsize, size; + int komma; + const char * sname = seematrix(f, s) ? sidename(s) : LOC(f->locale, "unknown_faction"); + message * msg; + char buf[1024]; + + message_faction(b, f, msg_separator); + + msg = msg_message("battle_army", "index name", army_index(s), sname); + message_faction(b, f, msg); + msg_release(msg); + + bufp = buf; + size = sizeof(buf); + komma = 0; + header = LOC(f->locale, "battle_opponents"); + + for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { + if (enemy(s2, s)) { + const char * abbrev = seematrix(f, s2)?sideabkz(s2, false):"-?-"; + rsize = slprintf(bufp, size, "%s %s %d(%s)", + komma++ ? "," : (const char*)header, loc_army, army_index(s2), abbrev); + if (rsize>size) rsize = size-1; + size -= rsize; + bufp += rsize; + } + } + if (komma) fbattlerecord(b, f, buf); + + bufp = buf; + size = sizeof(buf); + komma = 0; + header = LOC(f->locale, "battle_helpers"); + + for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { + if (friendly(s2, s)) { + const char * abbrev = seematrix(f, s2)?sideabkz(s2, false):"-?-"; + rsize = slprintf(bufp, size, "%s %s %d(%s)", + komma++ ? "," : (const char*)header, loc_army, army_index(s2), abbrev); + if (rsize>size) rsize = size-1; + size -= rsize; + bufp += rsize; + } + } + if (komma) fbattlerecord(b, f, buf); + + bufp = buf; + size = sizeof(buf); + komma = 0; + header = LOC(f->locale, "battle_attack"); + + for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { + if (s->relations[s2->index] & E_ATTACKING) { + const char * abbrev = seematrix(f, s2)?sideabkz(s2, false):"-?-"; + rsize = slprintf(bufp, size, "%s %s %d(%s)", komma++ ? "," : (const char*)header, loc_army, + army_index(s2), abbrev); + if (rsize>size) rsize = size-1; + size -= rsize; + bufp += rsize; + } + } + if (komma) fbattlerecord(b, f, buf); + } + + if (bdebug && s->faction) { + if (f_get_alliance(s->faction)) { + fprintf(bdebug, "##### %s (%s/%d)\n", s->faction->name, itoa36(s->faction->no), + s->faction->alliance?s->faction->alliance->id:0); + } else { + fprintf(bdebug, "##### %s (%s)\n", s->faction->name, itoa36(s->faction->no)); + } + } + print_fighters(b, s); + } + + message_all(b, msg_separator); + + /* Besten Taktiker ermitteln */ + + b->max_tactics = 0; + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + if (cv_size(&s->leader.fighters)) { + b->max_tactics = MAX(b->max_tactics, s->leader.value); + } + } + + if (b->max_tactics > 0) { + for (s=b->sides;s!=b->sides+b->nsides;++s) { + if (s->leader.value == b->max_tactics) { + fighter *tf; + cv_foreach(tf, s->leader.fighters) { + unit *u = tf->unit; + message * m = NULL; + if (!is_attacker(tf)) { + m = msg_message("battle::tactics_lost", "unit", u); + } else { + m = msg_message("battle::tactics_won", "unit", u); + } + message_all(b, m); + msg_release(m); + } cv_next(tf); + } + } + } +} + +static int +weapon_weight(const weapon * w, boolean missile) +{ + if (missile == i2b(fval(w->type, WTF_MISSILE))) { + return w->attackskill + w->defenseskill; + } + return 0; +} + +fighter * +make_fighter(battle * b, unit * u, side * s1, boolean attack) +{ +#define WMAX 20 + weapon weapons[WMAX]; + int owp[WMAX]; + int dwp[WMAX]; + int w = 0; + region *r = b->region; + item * itm; + fighter *fig = NULL; + int i, tactics = eff_skill(u, SK_TACTICS, r); + side *s2; + int h; + int berserk; + int strongmen; + int speeded = 0, speed = 1; + boolean pr_aid = false; + int rest; + const group * g = NULL; + const attrib *a = a_find(u->attribs, &at_otherfaction); + const faction *stealthfaction = a?get_otherfaction(a):NULL; + unsigned int flags = 0; + + assert(u->number); + if (fval(u, UFL_ANON_FACTION)!=0) flags |= SIDE_STEALTH; + + if (!(AllianceAuto() & HELP_FIGHT) && fval(u, UFL_GROUP)) { + const attrib * agroup = a_find(u->attribs, &at_group); + if (agroup!=NULL) g = (const group*)agroup->data.v; + } + + /* Illusionen und Zauber kaempfen nicht */ + if (fval(u->race, RCF_ILLUSIONARY) || idle(u->faction) || u->number==0) + return NULL; + + if (s1==NULL) { + for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { + if (s2->faction == u->faction && s2->group==g) { +#ifdef SIMPLE_COMBAT + int s1flags = flags|SIDE_HASGUARDS; + int s2flags = s2->flags|SIDE_HASGUARDS; +#else + int s1flags = flags; + int s2flags = s2->flags; +#endif + if (s1flags==s2flags && s2->stealthfaction==stealthfaction) { + s1 = s2; + break; + } + } + } + + /* aliances are moved out of make_fighter and will be handled later */ + if (!s1) { + s1 = make_side(b, u->faction, g, flags, stealthfaction); + } + /* Zu diesem Zeitpunkt ist attacked noch 0, da die Einheit für noch + * keinen Kampf ausgewählt wurde (sonst würde ein fighter existieren) */ + } + fig = calloc(1, sizeof(struct fighter)); + + fig->next = s1->fighters; + s1->fighters = fig; + + fig->unit = u; + /* In einer Burg muß man a) nicht Angreifer sein, und b) drin sein, und + * c) noch Platz finden. d) menschanähnlich sein */ + if (attack) { + set_attacker(fig); + } else { + building * b = u->building; + if (b && b->sizeleft>=u->number && playerrace(u->race)) { + fig->building = b; + fig->building->sizeleft -= u->number; + } + } + fig->status = u->status; + fig->side = s1; + fig->alive = u->number; + fig->side->alive += u->number; + fig->side->battle->alive += u->number; + fig->catmsg = -1; + + /* Freigeben nicht vergessen! */ + fig->person = calloc(fig->alive, sizeof(struct person)); + + h = u->hp / u->number; + assert(h); + rest = u->hp % u->number; + + /* Effekte von Sprüchen */ + + { + static const curse_type * speed_ct; + speed_ct = ct_find("speed"); + if (speed_ct) { + curse *c = get_curse(u->attribs, speed_ct); + if (c) { + speeded = get_cursedmen(u, c); + speed = curse_geteffect_int(c); + } + } + } + + /* Effekte von Alchemie */ + berserk = get_effect(u, oldpotiontype[P_BERSERK]); + /* change_effect wird in ageing gemacht */ + + /* Effekte von Artefakten */ + strongmen = MIN(fig->unit->number, get_item(u, I_TROLLBELT)); + + /* Hitpoints, Attack- und Defence-Boni für alle Personen */ + for (i = 0; i < fig->alive; i++) { + assert(i < fig->unit->number); + fig->person[i].hp = h; + if (i < rest) + fig->person[i].hp++; + + if (i < speeded) + fig->person[i].speed = speed; + else + fig->person[i].speed = 1; + + if (i < berserk) { + fig->person[i].attack++; + } + /* Leute mit einem Aid-Prayer bekommen +1 auf fast alles. */ + if (pr_aid) { + fig->person[i].attack++; + fig->person[i].defence++; + fig->person[i].damage++; + fig->person[i].damage_rear++; + fig->person[i].flags |= FL_COURAGE; + } + /* Leute mit Kraftzauber machen +2 Schaden im Nahkampf. */ + if (i < strongmen) { + fig->person[i].damage += 2; + } + } + + /* Für alle Waffengattungne wird bestimmt, wie viele der Personen mit + * ihr kämpfen könnten, und was ihr Wert darin ist. */ + if (u->race->battle_flags & BF_EQUIPMENT) { + int oi=0, di=0; + for (itm=u->items;itm && w!=WMAX;itm=itm->next) { + const weapon_type * wtype = resource2weapon(itm->type->rtype); + if (wtype==NULL || itm->number==0) continue; + weapons[w].attackskill = weapon_skill(wtype, u, true); + weapons[w].defenseskill = weapon_skill(wtype, u, false); + if (weapons[w].attackskill>=0 || weapons[w].defenseskill>=0) { + weapons[w].type = wtype; + weapons[w].used = 0; + weapons[w].count = itm->number; + ++w; + } + assert(w!=WMAX); + } + fig->weapons = calloc(sizeof(weapon), w+1); + memcpy(fig->weapons, weapons, w*sizeof(weapon)); + + for (i=0; i!=w; ++i) { + int j, o=0, d=0; + for (j=0; j!=i; ++j) { + if (weapon_weight(fig->weapons+j, true)>=weapon_weight(fig->weapons+i, true)) ++d; + if (weapon_weight(fig->weapons+j, false)>=weapon_weight(fig->weapons+i, false)) ++o; + } + for (j=i+1; j!=w; ++j) { + if (weapon_weight(fig->weapons+j, true)>weapon_weight(fig->weapons+i, true)) ++d; + if (weapon_weight(fig->weapons+j, false)>weapon_weight(fig->weapons+i, false)) ++o; + } + owp[o] = i; + dwp[d] = i; + } + /* jetzt enthalten owp und dwp eine absteigend schlechter werdende Liste der Waffen + * oi and di are the current index to the sorted owp/dwp arrays + * owp, dwp contain indices to the figther::weapons array */ + + /* hand out melee weapons: */ + for (i=0; i!=fig->alive; ++i) { + int wpless = weapon_skill(NULL, u, true); + while (oi!=w && (fig->weapons[owp[oi]].used==fig->weapons[owp[oi]].count || fval(fig->weapons[owp[oi]].type, WTF_MISSILE))) { + ++oi; + } + if (oi==w) break; /* no more weapons available */ + if (weapon_weight(fig->weapons+owp[oi], false)<=wpless) { + continue; /* we fight better with bare hands */ + } + fig->person[i].melee = &fig->weapons[owp[oi]]; + ++fig->weapons[owp[oi]].used; + } + /* hand out missile weapons (from back to front, in case of mixed troops). */ + for (di=0, i=fig->alive; i--!=0;) { + while (di!=w && (fig->weapons[dwp[di]].used==fig->weapons[dwp[di]].count || !fval(fig->weapons[dwp[di]].type, WTF_MISSILE))) { + ++di; + } + if (di==w) break; /* no more weapons available */ + if (weapon_weight(fig->weapons+dwp[di], true)>0) { + fig->person[i].missile = &fig->weapons[dwp[di]]; + ++fig->weapons[dwp[di]].used; + } + } + } + + s1->size[statusrow(fig->status)] += u->number; + s1->size[SUM_ROW] += u->number; + if (u->race->battle_flags & BF_NOBLOCK) { + s1->nonblockers[statusrow(fig->status)] += u->number; + } + + if (fig->unit->race->flags & RCF_HORSE) { + fig->horses = fig->unit->number; + fig->elvenhorses = 0; + } else { + static const item_type * it_charger = 0; + if (it_charger==0) { + it_charger = it_find("charger"); + if (!it_charger) { + it_charger = it_find("horse"); + } + } + fig->horses = i_get(u->items, it_charger); + fig->elvenhorses = get_item(u, I_ELVENHORSE); + } + + if (u->race->battle_flags & BF_EQUIPMENT) { + for (itm=u->items; itm; itm=itm->next) { + if (itm->type->rtype->atype) { + if (i_canuse(u, itm->type)) { + struct armor * adata = malloc(sizeof(armor)), **aptr; + adata->atype = itm->type->rtype->atype; + adata->count = itm->number; + for (aptr=&fig->armors;*aptr;aptr=&(*aptr)->next) { + if (adata->atype->prot > (*aptr)->atype->prot) break; + } + adata->next = *aptr; + *aptr = adata; + } + } + } + } + + + /* Jetzt muß noch geschaut werden, wo die Einheit die jeweils besten + * Werte hat, das kommt aber erst irgendwo später. Ich entscheide + * wärend des Kampfes, welche ich nehme, je nach Gegner. Deswegen auch + * keine addierten boni. */ + + /* Zuerst mal die Spezialbehandlung gewisser Sonderfälle. */ + fig->magic = eff_skill(u, SK_MAGIC, r); + + if (fig->horses) { + if (!fval(r->terrain, CAVALRY_REGION) || r_isforest(r) + || eff_skill(u, SK_RIDING, r) < CavalrySkill() || u->race == new_race[RC_TROLL] || fval(u, UFL_WERE)) + fig->horses = 0; + } + + if (fig->elvenhorses) { + if (eff_skill(u, SK_RIDING, r) < 5 || u->race == new_race[RC_TROLL] || fval(u, UFL_WERE)) + fig->elvenhorses = 0; + } + + /* Schauen, wie gut wir in Taktik sind. */ + if (tactics > 0 && u->race == new_race[RC_INSECT]) + tactics -= 1 - (int) log10(fig->side->size[SUM_ROW]); +#ifdef TACTICS_MODIFIER + if (tactics > 0 && statusrow(fig->status) == FIGHT_ROW) + tactics += TACTICS_MODIFIER; + if (tactics > 0 && statusrow(fig->status) > BEHIND_ROW) { + tactics -= TACTICS_MODIFIER; + } +#endif + + if (tactics > 0) { + int bonus = 0; + + for (i = 0; i < fig->alive; i++) { + int p_bonus = 0; + int rnd; + + do { + rnd = rng_int()%100; + if (rnd >= 40 && rnd <= 69) + p_bonus += 1; + else if (rnd <= 89) + p_bonus += 2; + else + p_bonus += 3; + } while(rnd >= 97); + bonus = MAX(p_bonus, bonus); + } + tactics += bonus; + } + + add_tactics(&fig->side->leader, fig, tactics); + ++b->nfighters; + return fig; +} + + +static int +join_battle(battle * b, unit * u, boolean attack, fighter ** cp) +{ + side * s; + fighter *c = NULL; + + if (!attack) { + attrib * a = a_find(u->attribs, &at_fleechance); + if (a!=NULL) { + if (rng_double()<=a->data.flt) { + *cp = NULL; + return false; + } + } + } + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *fig; + if (s->faction==u->faction) { + for (fig=s->fighters;fig;fig=fig->next) { + if (fig->unit == u) { + c = fig; + if (attack) { + set_attacker(fig); + } + break; + } + } + } + } + if (!c) { + *cp = make_fighter(b, u, NULL, attack); + return *cp!=NULL; + } + *cp = c; + return false; +} + +static const char * +simplename(region * r) +{ + int i; + static char name[17]; + const char * cp = rname(r, default_locale); + for (i=0;*cp && i!=16;++i, ++cp) { + int c = *(unsigned char *)cp; + while (c && !isalpha(c) && !isxspace(c)) { + ++cp; + c = *(unsigned char*)cp; + } + if (isxspace(c)) name[i] = '_'; + else name[i] = *cp; + if (c==0) break; + } + name[i]=0; + return name; +} + +static battle * +make_battle(region * r) +{ + battle *b = calloc(1, sizeof(struct battle)); + unit *u; + bfaction * bf; + static int max_fac_no = 0; /* need this only once */ + + if (battledebug) { + char zText[MAX_PATH]; + char zFilename[MAX_PATH]; + sprintf(zText, "%s/battles", basepath()); + makedir(zText, 0700); + sprintf(zFilename, "%s/battle-%d-%s.log", zText, obs_count, simplename(r)); + bdebug = fopen(zFilename, "w"); + if (!bdebug) log_error(("battles cannot be debugged\n")); + else { + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + fwrite(utf8_bom, 1, 3, bdebug); + fprintf(bdebug, "In %s findet ein Kampf stattactics:\n", rname(r, default_locale)); + } + obs_count++; + } + + b->region = r; + b->plane = getplane(r); + /* Finde alle Parteien, die den Kampf beobachten können: */ + for (u = r->units; u; u=u->next) { + if (u->number > 0) { + if (!fval(u->faction, FFL_MARK)) { + fset(u->faction, FFL_MARK); + for (bf=b->factions;bf;bf=bf->next) { + if (bf->faction==u->faction) break; + } + if (!bf) { + bf = calloc(sizeof(bfaction), 1); + ++b->nfactions; + bf->faction = u->faction; + bf->next = b->factions; + b->factions = bf; + } + } + } + } + + for (bf=b->factions;bf;bf=bf->next) { + faction * f = bf->faction; + max_fac_no = MAX(max_fac_no, f->no); + freset(f, FFL_MARK); + } + return b; +} + +static void +free_side(side * si) +{ + cv_kill(&si->leader.fighters); +} + +static void +free_fighter(fighter * fig) +{ + while (fig->loot) { + i_free(i_remove(&fig->loot, fig->loot)); + } + while (fig->armors) { + armor * a = fig->armors; + fig->armors = a->next; + free(a); + } + free(fig->person); + free(fig->weapons); + +} + +static void +free_battle(battle * b) +{ + side *s; + meffect *meffect; + int max_fac_no = 0; + + if (bdebug) { + fclose(bdebug); + } + + while (b->factions) { + bfaction * bf = b->factions; + faction * f = bf->faction; + b->factions = bf->next; + max_fac_no = MAX(max_fac_no, f->no); + free(bf); + } + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *fnext = s->fighters; + while (fnext) { + fighter *fig = fnext; + fnext = fig->next; + free_fighter(fig); + free(fig); + } + free_side(s); + } + cv_kill(&b->leaders); + cv_foreach(meffect, b->meffects) { + free(meffect); + } + cv_next(meffect); + cv_kill(&b->meffects); +} + +static int * +get_alive(side * s) +{ +#if 0 + static int alive[NUMROWS]; + fighter *fig; + memset(alive, 0, NUMROWS * sizeof(int)); + for (fig=s->fighters;fig;fig=fig->next) { + if (fig->alive>0) { + int row = statusrow(fig); + alive[row] += fig->alive; + } + } + return alive; +#endif + return s->size; +} + +static int +battle_report(battle * b) +{ + side *s, *s2; + boolean cont = false; + boolean komma; + bfaction *bf; + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + if (s->alive-s->removed > 0) { + for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { + if (s2->alive-s2->removed > 0 && enemy(s, s2)) { + cont = true; + break; + } + } + if (cont) break; + } + } + + if (verbosity>0) log_stdio(stdout, " %d", b->turn); + fflush(stdout); + + for (bf=b->factions;bf;bf=bf->next) { + faction * fac = bf->faction; + char buf[32*MAXSIDES]; + char * bufp = buf; + int bytes; + size_t size = sizeof(buf) - 1; + message * m; + + message_faction(b, fac, msg_separator); + + if (cont) m = msg_message("battle::lineup", "turn", b->turn); + else m = msg_message("battle::after", ""); + message_faction(b, fac, m); + msg_release(m); + + komma = false; + for (s=b->sides;s!=b->sides+b->nsides;++s) { + if (s->alive) { + int r, k = 0, * alive = get_alive(s); + int l = FIGHT_ROW; + const char * abbrev = seematrix(fac, s)?sideabkz(s, false):"-?-"; + const char * loc_army = LOC(fac->locale, "battle_army"); + char buffer[32]; + + if (komma) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + snprintf(buffer, sizeof(buffer), "%s %2d(%s): ", + loc_army, army_index(s), abbrev); + buffer[sizeof(buffer)-1] = 0; + + bytes = (int)strlcpy(bufp, buffer, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + for (r=FIGHT_ROW;r!=NUMROWS;++r) { + if (alive[r]) { + if (l!=FIGHT_ROW) { + bytes = (int)strlcpy(bufp, "+", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + while (k--) { + bytes = (int)strlcpy(bufp, "0+", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + sprintf(buffer, "%d", alive[r]); + + bytes = (int)strlcpy(bufp, buffer, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + k = 0; + l = r+1; + } else ++k; + } + + komma = true; + } + } + *bufp = 0; + fbattlerecord(b, fac, buf); + } + return cont; +} + +static void +join_allies(battle * b) +{ + region *r = b->region; + unit *u; + side *s, *s_end = b->sides+b->nsides; + /* make_side might be adding a new faction, but it adds them to the end + * of the list, so we're safe in our iteration here if we remember the end + * up front. */ + for (u=r->units;u;u=u->next) { + /* Was ist mit Schiffen? */ + if (u->status != ST_FLEE && u->status != ST_AVOID && !fval(u, UFL_LONGACTION|UFL_ISNEW) && u->number > 0) { + faction * f = u->faction; + fighter * c = NULL; + + for (s=b->sides;s!=s_end;++s) { + side * se; + /* Wenn alle attackierten noch FFL_NOAID haben, dann kämpfe nicht mit. */ + if (fval(s->faction, FFL_NOAID)) continue; + if (s->faction!=f) { + /* Wenn wir attackiert haben, kommt niemand mehr hinzu: */ + if (s->bf->attacker) continue; + /* alliiert müssen wir schon sein, sonst ist's eh egal : */ + if (!alliedunit(u, s->faction, HELP_FIGHT)) continue; + /* wenn die partei verborgen ist, oder gar eine andere + * vorgespiegelt wird, und er sich uns gegenüber nicht zu + * erkennen gibt, helfen wir ihm nicht */ + if (s->stealthfaction){ + if(!allysfm(s, u->faction, HELP_FSTEALTH)) { + continue; + } + } + } + /* einen alliierten angreifen dürfen sie nicht, es sei denn, der + * ist mit einem alliierten verfeindet, der nicht attackiert + * hat: */ + for (se=b->sides;se!=s_end;++se) { + if (u->faction==se->faction) continue; + if (alliedunit(u, se->faction, HELP_FIGHT) && !se->bf->attacker) { + continue; + } + if (enemy(s, se)) break; + } + if (se==s_end) continue; + /* Wenn die Einheit belagert ist, muß auch einer der Alliierten belagert sein: */ + if (besieged(u)) { + fighter *ally; + for (ally = s->fighters; ally; ally=ally->next) { + if (besieged(ally->unit)) { + break; + } + } + if (ally==NULL) continue; + } + /* keine Einwände, also soll er mitmachen: */ + if (c==NULL) { + if (join_battle(b, u, false, &c)) { + if (battledebug) { + fprintf(bdebug, "%s joins to help %s against %s.\n", + unitname(u), factionname(s->faction), + factionname(se->faction)); + } + } else if (c==NULL) { + continue; + } + } + + /* the enemy of my friend is my enemy: */ + for (se=b->sides;se!=s_end;++se) { + if (se->faction!=u->faction && enemy(s, se)) { + if (set_enemy(se, c->side, false) && battledebug) { + fprintf(bdebug, "%u/%s hates %u/%s because they are enemies with %u/%s.\n", + c->side->index, sidename(c->side), + se->index, sidename(se), + s->index, sidename(s)); + } + } + } + } + } + } + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + int si; + side * sa; + faction * f = s->faction; + + /* Den Feinden meiner Feinde gebe ich Deckung (gegen gemeinsame Feinde): */ + for (si=0; s->enemies[si]; ++si) { + side * se = s->enemies[si]; + int ai; + for (ai=0; se->enemies[ai]; ++ai) { + side * as = se->enemies[ai]; + if (as==s || !enemy(as, s)) { + set_friendly(as, s); + } + } + } + + for (sa=s+1;sa!=b->sides+b->nsides;++sa) { + plane * pl = rplane(r); + if (enemy(s, sa)) continue; + if (friendly(s, sa)) continue; + if (!alliedgroup(pl, f, sa->faction, f->allies, HELP_FIGHT)) continue; + if (!alliedgroup(pl, sa->faction, f, sa->faction->allies, HELP_FIGHT)) continue; + + set_friendly(s, sa); + } + } +} + +static void +flee(const troop dt) +{ + fighter * fig = dt.fighter; + unit * u = fig->unit; + +#ifndef SIMPLE_ESCAPE + int carry = personcapacity(u) - u->race->weight; + int money; + + item ** ip = &u->items; + + while (*ip) { + item * itm = *ip; + const item_type * itype = itm->type; + int keep = 0; + + if (fval(itype, ITF_ANIMAL)) { + /* Regeländerung: Man muß das Tier nicht reiten können, + * um es vom Schlachtfeld mitzunehmen, ist ja nur + * eine Region weit. * */ + keep = MIN(1, itm->number); + /* da ist das weight des tiers mit drin */ + carry += itype->capacity - itype->weight; + } else if (itm->type->weight <= 0) { + /* if it doesn'tactics weigh anything, it won'tactics slow us down */ + keep = itm->number; + } + /* jeder troop nimmt seinen eigenen Teil der Sachen mit */ + if (keep>0){ + if (itm->number==keep) { + i_add(&fig->run.items, i_remove(ip, itm)); + } else { + item *run_itm = i_new(itype, keep); + i_add(&fig->run.items, run_itm); + i_change(ip, itype, -keep); + } + } + if (*ip==itm) ip = &itm->next; + } + + /* we will take money with us */ + money = get_money(u); + /* nur ganzgeflohene/resttote Einheiten verlassen die Region */ + if (money > carry) money = carry; + if (money > 0) { + i_change(&u->items, i_silver, -money); + i_change(&fig->run.items, i_silver, +money); + } +#endif /* SIMPLE_ESCAPE */ + + fig->run.hp += fig->person[dt.index].hp; + ++fig->run.number; + + setguard(u, GUARD_NONE); + + kill_troop(dt); +} + +static boolean +init_battle(region * r, battle **bp) +{ + battle * b = NULL; + unit * u; + boolean fighting = false; + + /* list_foreach geht nicht, wegen flucht */ + for (u = r->units; u != NULL; u = u->next) { + if (fval(u, UFL_LONGACTION)) continue; + if (u->number > 0) { + order * ord; + + for (ord=u->orders;ord;ord=ord->next) { + static boolean init = false; + static const curse_type * peace_ct, * slave_ct, * calm_ct; + + if (!init) { + init = true; + peace_ct = ct_find("peacezone"); + slave_ct = ct_find("slavery"); + calm_ct = ct_find("calmmonster"); + } + if (get_keyword(ord) == K_ATTACK) { + unit *u2; + fighter *c1, *c2; + ship * lsh = NULL; + plane * pl = rplane(r); + + if (pl && fval(pl, PFL_NOATTACK)) { + cmistake(u, ord, 271, MSG_BATTLE); + continue; + } + + if ((u->race->battle_flags&BF_CANATTACK) == 0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_no_attack", "race", u->race)); + continue; + } + /** + ** Fehlerbehandlung Angreifer + **/ + if (LongHunger(u)) { + cmistake(u, ord, 225, MSG_BATTLE); + continue; + } + + if (u->status == ST_AVOID || u->status == ST_FLEE) { + cmistake(u, ord, 226, MSG_BATTLE); + continue; + } + + /* ist ein Flüchtling aus einem andern Kampf */ + if (fval(u, UFL_LONGACTION)) continue; + + if (peace_ct && curse_active(get_curse(r->attribs, peace_ct))) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "peace_active", "")); + continue; + } + + if (slave_ct && curse_active(get_curse(u->attribs, slave_ct))) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "slave_active", "")); + continue; + } + + if ((u->ship != NULL && !fval(r->terrain, SEA_REGION)) || (lsh = leftship(u))!=NULL) { + if (is_guarded(r, u, GUARD_TRAVELTHRU)) { + if (lsh) { + cmistake(u, ord, 234, MSG_BATTLE); + } else { + /* Fehler: "Das Schiff muß erst verlassen werden" */ + cmistake(u, ord, 19, MSG_BATTLE); + } + continue; + } + } + + /* Ende Fehlerbehandlung Angreifer */ + + init_tokens(ord); + skip_token(); + /* attackierte Einheit ermitteln */ + u2 = getunit(r, u->faction); + + /* Beginn Fehlerbehandlung */ + /* Fehler: "Die Einheit wurde nicht gefunden" */ + if (!u2 || u2->number == 0 || !cansee(u->faction, u->region, u2, 0)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + continue; + } + /* Fehler: "Die Einheit ist eine der unsrigen" */ + if (u2->faction == u->faction) { + cmistake(u, ord, 45, MSG_BATTLE); + continue; + } + /* Fehler: "Die Einheit ist mit uns alliert" */ + if (alliedunit(u, u2->faction, HELP_FIGHT)) { + cmistake(u, ord, 47, MSG_BATTLE); + continue; + } + if (IsImmune(u2->faction)) { + add_message(&u->faction->msgs, + msg_feedback(u, u->thisorder, "newbie_immunity_error", "turns", NewbieImmunity())); + continue; + } + /* Fehler: "Die Einheit ist mit uns alliert" */ + + if (calm_ct) { + attrib * a = a_find(u->attribs, &at_curse); + boolean calm = false; + while (a && a->type==&at_curse) { + curse * c = (curse *)a->data.v; + if (c->type==calm_ct && curse_geteffect(c)==u2->faction->subscription) { + if (curse_active(c)) { + calm = true; + break; + } + } + a = a->next; + } + if (calm) { + cmistake(u, ord, 47, MSG_BATTLE); + continue; + } + } + /* Ende Fehlerbehandlung */ + if (b==NULL) { + unit * utmp; + for (utmp=r->units; utmp!=NULL; utmp=utmp->next) { + fset(utmp->faction, FFL_NOAID); + } + b = make_battle(r); + } + if (join_battle(b, u, true, &c1)) { + if (battledebug) { + fprintf(bdebug, "%s joins by attacking %s.\n", + unitname(u), unitname(u2)); + } + } + if (join_battle(b, u2, false, &c2)) { + if (battledebug) { + fprintf(bdebug, "%s joins because of an attack from %s.\n", + unitname(u2), unitname(u)); + } + } + + /* Hat die attackierte Einheit keinen Noaid-Status, + * wird das Flag von der Faction genommen, andere + * Einheiten greifen ein. */ + if (!fval(u2, UFL_NOAID)) freset(u2->faction, FFL_NOAID); + + if (c1!=NULL && c2!=NULL) { + /* Merken, wer Angreifer ist, für die Rückzahlung der + * Präcombataura bei kurzem Kampf. */ + c1->side->bf->attacker = true; + + if (set_enemy(c1->side, c2->side, true) && battledebug) { + fprintf(bdebug, "%u/%s hates %u/%s because they attacked them.\n", + c2->side->index, sidename(c2->side), + c1->side->index, sidename(c1->side)); + } + fighting = true; + } + } + } + } + } + *bp = b; + return fighting; +} + +static void +battle_stats(FILE * F, battle * b) +{ + typedef struct stat_info { + struct stat_info * next; + const weapon_type * wtype; + int level; + int number; + } stat_info; + side * s; + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter * df; + stat_info * stats = NULL, * stat; + + for (df = s->fighters; df; df = df->next) { + unit *du = df->unit; + troop dt; + stat_info * slast = NULL; + + dt.fighter = df; + for (dt.index=0;dt.index!=du->number;++dt.index) { + weapon * wp = preferred_weapon(dt, true); + int level = wp?wp->attackskill:0; + const weapon_type * wtype = wp?wp->type:NULL; + stat_info ** slist = &stats; + + if (slast && slast->wtype==wtype && slast->level==level) { + ++slast->number; + continue; + } + while (*slist && (*slist)->wtype!=wtype) { + slist = &(*slist)->next; + } + while (*slist && (*slist)->wtype==wtype && (*slist)->level>level) { + slist = &(*slist)->next; + } + stat = *slist; + if (stat==NULL || stat->wtype!=wtype || stat->level!=level) { + stat = calloc(1, sizeof(stat_info)); + stat->wtype = wtype; + stat->level = level; + stat->next = *slist; + *slist = stat; + } + slast = stat; + ++slast->number; + } + } + + fprintf(F, "##STATS## Heer %u - %s:\n", army_index(s), factionname(s->faction)); + for (stat=stats;stat!=NULL;stat=stat->next) { + fprintf(F, "%s %u : %u\n", stat->wtype?stat->wtype->itype->rtype->_name[0]:"none", stat->level, stat->number); + } + freelist(stats); + } +} + +/** execute one round of attacks + * fig->fighting is used to determine who attacks, not fig->alive, since + * the latter may be influenced by attacks that already took place. + */ +static void +battle_attacks(battle * b) +{ + side * s; + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *fig; + + if (b->turn!=0 || (b->max_tactics > 0 && get_tactics(s, NULL) == b->max_tactics)) { + for (fig=s->fighters;fig;fig=fig->next) { + + /* ist in dieser Einheit noch jemand handlungsfähig? */ + if (fig->fighting <= 0) continue; + + /* Handle the unit's attack on someone */ + do_attack(fig); + } + } + } +} + +/** updates the number of attacking troops in each fighter struct. + * this has to be calculated _before_ the actual attacks take + * place because otherwise dead troops would not strike in the + * round they die. */ +static void +battle_update(battle * b) +{ + side * s; + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *fig; + for (fig=s->fighters;fig;fig=fig->next) { + fig->fighting = fig->alive - fig->removed; + } + } +} + +/** attempt to flee from battle before the next round begins + * there's a double attempt before the first round, but only + * one attempt before round zero, the potential tactics round. */ +static void +battle_flee(battle * b) +{ + int attempt, flee_ops = 1; + + if (b->turn==1) + flee_ops = 2; + + for (attempt=1;attempt<=flee_ops;++attempt) { + side * s; + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *fig; + for (fig=s->fighters;fig;fig=fig->next) { + unit *u = fig->unit; + troop dt; + int runners = 0; + /* Flucht nicht bei mehr als 600 HP. Damit Wyrme tötbar bleiben. */ + int runhp = MIN(600,(int)(0.9+unit_max_hp(u)*hpflee(u->status))); + + if (u->ship && fval(u->region->terrain, SEA_REGION)) { + /* keine Flucht von Schiffen auf hoher See */ + continue; + } + if (fval(u->race, RCF_UNDEAD) || u->race == new_race[RC_SHADOWKNIGHT]) { + /* Untote fliehen nicht. Warum eigentlich? */ + continue; + } + + dt.fighter = fig; +#ifndef SIMPLE_ESCAPE + if (!fig->run.region) fig->run.region = fleeregion(u); + if (!fig->run.region) continue; +#endif /* SIMPLE_ESCAPE */ + dt.index = fig->alive - fig->removed; + while (s->size[SUM_ROW] && dt.index != 0) { + double ispaniced = 0.0; + --dt.index; + assert(dt.index>=0 && dt.indexunit->number); + assert(fig->person[dt.index].hp > 0); + + /* Versuche zu fliehen, wenn + * - Kampfstatus fliehe + * - schwer verwundet und nicht erste kampfrunde + * - in panik (Zauber) + * aber nicht, wenn der Zaubereffekt Held auf dir liegt! + */ + switch (u->status) { + case ST_FLEE: + break; + default: + if ((fig->person[dt.index].flags & FL_HIT) == 0) continue; + if (b->turn<=1) continue; + if (fig->person[dt.index].hp <= runhp) break; + if (fig->person[dt.index].flags & FL_PANICED) { + if ((fig->person[dt.index].flags & FL_COURAGE)==0) break; + } + continue; + } + + if (fig->person[dt.index].flags & FL_PANICED) { + ispaniced = EFFECT_PANIC_SPELL; + } + if (chance(MIN(fleechance(u)+ispaniced, 0.90))) { + ++runners; + flee(dt); + } + } + if (bdebug && runners > 0) { + fprintf(bdebug, "Fleeing: %d from %s\n", runners, itoa36(fig->unit->no)); + } + } + } + } +} + +void +do_battle(region * r) +{ + battle *b = NULL; + boolean fighting = false; + ship * sh; + building *bu; + static int init_rules = 0; + + if (!init_rules) { + static_rules(); + init_rules = 1; + } + if (msg_separator==NULL) { + msg_separator = msg_message("battle::section", ""); + } + + fighting = init_battle(r, &b); + + if (b==NULL) return; + + /* Bevor wir die alliierten hineinziehen, sollten wir schauen, * + * Ob jemand fliehen kann. Dann erübrigt sich das ganze ja + * vielleicht schon. */ + print_header(b); + if (!fighting) { + /* Niemand mehr da, Kampf kann nicht stattfinden. */ + message * m = msg_message("battle::aborted", ""); + message_all(b, m); + msg_release(m); + free_battle(b); + free(b); + return; + } + join_allies(b); + make_heroes(b); + + /* Alle Mann raus aus der Burg! */ + for (bu=r->buildings; bu!=NULL; bu=bu->next) bu->sizeleft = bu->size; + + /* make sure no ships are damaged initially */ + for (sh=r->ships; sh; sh=sh->next) freset(sh, SF_DAMAGED); + + /* Gibt es eine Taktikrunde ? */ + if (cv_size(&b->leaders)) { + b->turn = 0; + b->has_tactics_turn = true; + } else { + b->turn = 1; + b->has_tactics_turn = false; + } + + if (b->region->flags & RF_COMBATDEBUG) battle_stats(bdebug, b); + + /* PRECOMBATSPELLS */ + do_combatmagic(b, DO_PRECOMBATSPELL); + + print_stats(b); /* gibt die Kampfaufstellung aus */ + if (verbosity>0) log_stdio(stdout, "%s (%d, %d) : ", rname(r, default_locale), r->x, r->y); + + for (;battle_report(b) && b->turn<=max_turns;++b->turn) { + if (bdebug) { + fprintf(bdebug, "*** Turn: %d\n", b->turn); + } + battle_flee(b); + battle_update(b); + battle_attacks(b); + + } + + if (verbosity>0) log_stdio(stdout, "\n"); + + /* Auswirkungen berechnen: */ + aftermath(b); + /* Hier ist das Gefecht beendet, und wir können die + * Hilfsstrukturen * wieder löschen: */ + + if (b) { + free_battle(b); + free(b); + } +} diff --git a/src/kernel/battle.h b/src/kernel/battle.h new file mode 100644 index 000000000..4bc054818 --- /dev/null +++ b/src/kernel/battle.h @@ -0,0 +1,271 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_BATTLE +#define H_KRNL_BATTLE +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define SHOW_KILLS +#undef SMALL_BATTLE_MESSAGES + + /** more defines **/ +#define FS_ENEMY 1 +#define FS_HELP 2 + + /***** Verteidigungslinien. + * Eressea hat 4 Verteidigungslinien. 1 ist vorn, 5. enthält Summen + */ + +#define NUMROWS 5 +#define SUM_ROW 0 +#define FIGHT_ROW 1 +#define BEHIND_ROW 2 +#define AVOID_ROW 3 +#define FLEE_ROW 4 +#define LAST_ROW (NUMROWS-1) +#define FIRST_ROW FIGHT_ROW +#define MAXSIDES 192 /* if there are ever more than this, we're fucked. */ + + struct message; + + typedef struct bfaction { + struct bfaction * next; + struct side * sides; + struct faction *faction; +#ifndef SIMPLE_COMBAT + int lastturn; /* last time this struct faction was involved in combat */ +#endif + boolean attacker; + } bfaction; + + typedef struct tactics { + cvector fighters; + int value; + } tactics; + +#define SIDE_STEALTH 1<<0 +#ifdef SIMPLE_COMBAT +#define SIDE_HASGUARDS 1<<1 +#endif + typedef struct side { + struct side * nextF; /* next army of same faction */ + struct battle * battle; + struct bfaction * bf; /* battle info that goes with the faction */ + struct faction * faction; /* cache optimization for bf->faction */ + const struct group * group; + struct tactics leader; /* this army's best tactician */ +# define E_ENEMY 1 +# define E_FRIEND 2 +# define E_ATTACKING 4 + unsigned char relations[MAXSIDES]; + struct side * enemies[MAXSIDES]; + struct fighter * fighters; + int index; /* Eintrag der Fraktion in b->matrix/b->enemies */ + int size[NUMROWS]; /* Anzahl Personen in Reihe X. 0 = Summe */ + int nonblockers[NUMROWS]; /* Anzahl nichtblockierender Kämpfer, z.B. Schattenritter. */ + int alive; /* Die Partei hat den Kampf verlassen */ + int removed; /* stoned */ + int flee; + int dead; + int casualties; /* those dead that were real people, not undead! */ + int healed; + unsigned int flags; + const struct faction *stealthfaction; + } side; + + typedef struct battle { + cvector leaders; + struct region *region; + struct plane *plane; + bfaction * factions; + int nfactions; + int nfighters; + side sides[MAXSIDES]; + int nsides; + cvector meffects; + int max_tactics; + int turn; + boolean has_tactics_turn; + int keeploot; + boolean reelarrow; + int alive; +#ifdef SMALL_BATTLE_MESSAGES + boolean small; +#endif +#define FASTROW +#ifdef FASTROW + struct { + const struct side * as; + const struct side * vs; + int alive; + int row; + int result; + } rowcache; +#endif +#define FASTCOUNT +#ifdef FASTCOUNT + struct { + struct side * side; + int status; + int alive; + int minrow, maxrow; + int enemies[8]; + } fast; +#endif + } battle; + + typedef struct weapon { + int count, used; + const struct weapon_type * type; + int attackskill : 8; + int defenseskill : 8; + } weapon; + + /*** fighter::person::flags ***/ +#define FL_TIRED 1 +#define FL_DAZZLED 2 /* durch Untote oder Dämonen eingeschüchtert */ +#define FL_PANICED 4 +#define FL_COURAGE 8 /* Helden fliehen nie */ +#define FL_SLEEPING 16 +#define FL_STUNNED 32 /* eine Runde keinen Angriff */ +#define FL_HIT 64 /* the person at attacked */ + + typedef struct troop { + struct fighter *fighter; + int index; + } troop; + + typedef struct armor { + struct armor * next; + const struct armor_type * atype; + int count; + } armor; + + /*** fighter::flags ***/ +#define FIG_ATTACKER 1<<0 +#define FIG_NOLOOT 1<<1 + typedef struct fighter { + struct fighter * next; + struct side *side; + struct unit *unit; /* Die Einheit, die hier kämpft */ + struct building *building; /* Gebäude, in dem die Einheit evtl. steht */ + status_t status; /* Kampfstatus */ + struct weapon * weapons; + struct armor *armors; /* Anzahl Rüstungen jeden Typs */ + int alive; /* Anzahl der noch nicht Toten in der Einheit */ + int fighting; /* Anzahl der Kämpfer in der aktuellen Runde */ + int removed; /* Anzahl Kaempfer, die nicht tot sind, aber + aus dem Kampf raus sind (zB weil sie + versteinert wurden). Diese werden auch + in alive noch mitgezählt! */ + int magic; /* Magietalent der Einheit */ + int horses; /* Anzahl brauchbarer Pferde der Einheit */ + int elvenhorses; /* Anzahl brauchbarer Elfenpferde der Einheit */ + struct item * loot; + int catmsg; /* Merkt sich, ob Katapultmessage schon generiert. */ + struct person { + int hp; /* Trefferpunkte der Personen */ + int attack : 8; /* (Magie) Attackenbonus der Personen */ + int defence : 8; /* (Magie) Paradenbonus der Personen */ + int damage : 8; /* (Magie) Schadensbonus der Personen im Nahkampf */ + int damage_rear : 8; /* (Magie) Schadensbonus der Personen im Fernkampf */ + int flags : 8; /* (Magie) Diverse Flags auf Kämpfern */ + int speed : 8; /* (Magie) Geschwindigkeitsmultiplkator. */ + int reload : 4; /* Anzahl Runden, die die Waffe x noch laden muss. + * dahinter steckt ein array[RL_MAX] wenn er min. eine hat. */ + int last_action : 4; /* In welcher Runde haben wir zuletzt etwas getan */ + struct weapon * missile; /* missile weapon */ + struct weapon * melee; /* melee weapon */ + } * person; + unsigned int flags; + struct { + int number; /* number of people who fled */ + int hp; /* accumulated hp of fleeing people */ +#ifndef SIMPLE_ESCAPE + struct region *region; /* destination of fleeing people */ + struct item * items; /* items they take */ +#endif /* SIMPLE_ESCAPE */ + } run; +#ifndef SIMPLE_COMBAT + int action_counter; /* number of active actions the struct unit did in the fight */ +#endif /* SIMPLE_COMBAT */ +#ifdef SHOW_KILLS + int kills; + int hits; +#endif + } fighter; + + + /* schilde */ + + enum { + SHIELD_REDUCE, + SHIELD_ARMOR, + SHIELD_WIND, + SHIELD_BLOCK, + SHIELD_MAX + }; + + typedef struct meffect { + fighter *magician; /* Der Zauberer, der den Schild gezaubert hat */ + int typ; /* Wirkungsweise des Schilds */ + int effect; + int duration; + } meffect; + + extern const troop no_troop; + + extern void do_battle(struct region * r); + + /* for combat spells and special attacks */ + enum { SELECT_ADVANCE = 0x1, SELECT_DISTANCE = 0x2, SELECT_FIND = 0x4 }; + enum { ALLY_SELF, ALLY_ANY }; + + extern troop select_enemy(struct fighter * af, int minrow, int maxrow, int select); + extern troop select_ally(struct fighter * af, int minrow, int maxrow, int allytype); + + extern int count_enemies(struct battle * b, const struct fighter * af, int minrow, int maxrow, int select); + extern boolean terminate(troop dt, troop at, int type, const char *damage, boolean missile); + extern void message_all(battle * b, struct message * m); + extern int hits(troop at, troop dt, weapon * awp); + extern void damage_building(struct battle *b, struct building *bldg, int damage_abs); + extern struct cvector * fighters(struct battle *b, const struct side * vs, int minrow, int maxrow, int mask); + extern int count_allies(const struct side * as, int minrow, int maxrow, int select, int allytype); + extern int get_unitrow(const struct fighter * af, const struct side * vs); + extern boolean helping(const struct side * as, const struct side * ds); + extern void rmfighter(fighter *df, int i); +#ifndef SIMPLE_ESCAPE + extern struct region * fleeregion(const struct unit * u); +#endif + extern struct fighter * select_corpse(struct battle * b, struct fighter * af); + extern fighter * make_fighter(struct battle * b, struct unit * u, side * s, boolean attack); + extern int statusrow(int status); + extern void drain_exp(struct unit *u, int d); + extern void kill_troop(troop dt); + extern void remove_troop(troop dt); /* not the same as the badly named rmtroop */ + extern boolean is_attacker(const fighter * fig); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/kernel/binarystore.c b/src/kernel/binarystore.c new file mode 100644 index 000000000..13780c981 --- /dev/null +++ b/src/kernel/binarystore.c @@ -0,0 +1,291 @@ +/* vi: set ts=2: ++-------------------+ Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel ++-------------------+ +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ +#include +#include "config.h" +#include "textstore.h" + +#include "save.h" +#include "version.h" +#include +#include + +#include +#include +#include +#include + +#define file(store) (FILE *)((store)->userdata) + +#define STREAM_VERSION 2 + +INLINE_FUNCTION size_t +pack_int(int v, char * buffer) +{ + int sign = (v<0); + + if (sign) { + v = ~v + 1; + sign = 0x40; + } + if (v<0x40) { + buffer[0] = (char)(v | sign); + return 1; + } else if (v<0x2000) { + buffer[0] = (char)((v>> 6) | 0x80); + buffer[1] = (char)((v & 0x3F) | sign); + return 2; + } else if (v<0x100000) { + buffer[0] = (char)(((v>>13) & 0x7f) | 0x80); + buffer[1] = (char)(((v>> 6) & 0x7f) | 0x80); + buffer[2] = (char)((v & 0x3F) | sign); + return 3; + } else if (v<0x8000000) { + buffer[0] = (char)(((v>>20) & 0x7f) | 0x80); + buffer[1] = (char)(((v>>13) & 0x7f) | 0x80); + buffer[2] = (char)(((v>> 6) & 0x7f) | 0x80); + buffer[3] = (char)((v & 0x3F) | sign); + return 4; + } + buffer[0] = (char)(((v>>27) & 0x7f) | 0x80); + buffer[1] = (char)(((v>>20) & 0x7f) | 0x80); + buffer[2] = (char)(((v>>13) & 0x7f) | 0x80); + buffer[3] = (char)(((v>> 6) & 0x7f) | 0x80); + buffer[4] = (char)((v & 0x3F) | sign); + return 5; +} + +INLINE_FUNCTION int +unpack_int(const char * buffer) +{ + int i = 0, v = 0; + + while (buffer[i] & 0x80) { + v = (v << 7) | (buffer[i++] & 0x7f); + } + v = (v << 6) | (buffer[i] & 0x3f); + + if (buffer[i] & 0x40) { + v = ~v + 1; + } + return v; +} + +static int +bin_w_brk(struct storage * store) +{ + return 0; +} + +static int +bin_w_int_pak(struct storage * store, int arg) +{ + char buffer[5]; + size_t size = pack_int(arg, buffer); + return (int)fwrite(buffer, sizeof(char), size, file(store)); +} + +static int +bin_r_int_pak(struct storage * store) +{ + int v = 0; + char ch; + + fread(&ch, sizeof(char), 1, file(store)); + while (ch & 0x80) { + v = (v << 7) | (ch & 0x7f); + fread(&ch, sizeof(char), 1, file(store)); + } + v = (v << 6) | (ch & 0x3f); + + if (ch & 0x40) { + v = ~v + 1; + } + return v; +} + +static int +bin_w_int(struct storage * store, int arg) +{ + return (int)fwrite(&arg, sizeof(arg), 1, file(store)); +} + +static int +bin_r_int(struct storage * store) +{ + int result; + fread(&result, sizeof(result), 1, file(store)); + return result; +} + +static int +bin_w_flt(struct storage * store, float arg) +{ + return (int)fwrite(&arg, sizeof(arg), 1, file(store)); +} + +static float +bin_r_flt(struct storage * store) +{ + float result; + fread(&result, sizeof(result), 1, file(store)); + return result; +} + +static int +bin_w_str(struct storage * store, const char * tok) +{ + int result; + if (tok==NULL || tok[0]==0) { + result = store->w_int(store, 0); + } else { + int size = (int)strlen(tok); + result = store->w_int(store, size); + result += (int)fwrite(tok, size, 1, file(store)); + } + return result; +} + +#define FIX_INVALID_CHARS /* required for data pre-574 */ +static char * +bin_r_str(struct storage * store) +{ + int len; + + len = store->r_int(store); + if (len>=0) { + char * result = malloc(len+1); + + fread(result, sizeof(char), len, file(store)); + result[len] = 0; +#ifdef FIX_INVALID_CHARS + { + char * p = strpbrk(result, "\n\r"); + while (p) { + log_error(("Invalid character %d in input string \"%s\".\n", *p, result)); + strcpy(p, p+1); + p = strpbrk(p, "\n\r"); + } + } +#endif + return result; + } else if (len<0) { + log_error(("invalid string-length %d in input.\n", len)); + } + return NULL; +} + +static void +bin_r_str_buf(struct storage * store, char * result, size_t size) +{ + int i; + size_t rd, len; + + i = store->r_int(store); + assert(i>=0); + if (i==0) { + result[0] = 0; + } else { + len = (size_t)i; + rd = MIN(len, size-1); + fread(result, sizeof(char), rd, file(store)); + if (rdw_int(store, len); + if (len>0) { + result += (int)fwrite(arg, len, 1, file(store)); + } + return result; +} + +static void +bin_r_bin(struct storage * store, void * result, size_t size) +{ + int len = store->r_int(store); + if (len>0) { + if ((size_t)len>size) { + log_error(("destination buffer too small %d %u.\n", len, size)); + fseek(file(store), len, SEEK_CUR); + } else { + fread(result, len, 1, file(store)); + } + } +} + + +static int +bin_open(struct storage * store, const char * filename, int mode) +{ + const char * modes[] = { 0, "rb", "wb", "ab" }; + FILE * F = fopen(filename, modes[mode]); + store->userdata = F; + store->encoding=XML_CHAR_ENCODING_UTF8; /* always utf8 it is */ + if (F) { + if (mode==IO_READ) { + int stream_version = 0; + store->version = bin_r_int(store); + if (store->version>=INTPAK_VERSION) { + stream_version = bin_r_int(store); + } + if (stream_version<=1) { + store->r_id = bin_r_int; + store->w_id = bin_w_int; + } + if (stream_version==0) { + store->r_int = bin_r_int; + store->w_int = bin_w_int; + } + } else if (store->encoding==XML_CHAR_ENCODING_UTF8) { + bin_w_int(store, RELEASE_VERSION); + bin_w_int(store, STREAM_VERSION); + } + } + return (F==NULL); +} + +static int +bin_close(struct storage * store) +{ + return fclose(file(store)); +} + +const storage binary_store = { + bin_w_brk, /* newline (ignore) */ + bin_w_int_pak, bin_r_int_pak, /* int storage */ + bin_w_flt, bin_r_flt, /* float storage */ + bin_w_int_pak, bin_r_int_pak, /* id storage */ + bin_w_str, bin_r_str, bin_r_str_buf, /* token storage */ + bin_w_str, bin_r_str, bin_r_str_buf, /* string storage */ + bin_w_bin, bin_r_bin, /* binary storage */ + bin_open, bin_close, + 0, 0, NULL +}; + diff --git a/src/kernel/binarystore.h b/src/kernel/binarystore.h new file mode 100644 index 000000000..8ba979667 --- /dev/null +++ b/src/kernel/binarystore.h @@ -0,0 +1,23 @@ +/* vi: set ts=2: ++-------------------+ Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel ++-------------------+ +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifndef H_KERNEL_BINSTORE +#define H_KERNEL_BINSTORE +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern const storage binary_store; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/build.c b/src/kernel/build.c new file mode 100644 index 000000000..50ab584c4 --- /dev/null +++ b/src/kernel/build.c @@ -0,0 +1,1350 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "build.h" + +/* kernel includes */ +#include "alchemy.h" +#include "alliance.h" +#include "connection.h" +#include "building.h" +#include "curse.h" +#include "faction.h" +#include "group.h" +#include "item.h" +#include "magic.h" +#include "message.h" +#include "move.h" +#include "order.h" +#include "pool.h" +#include "race.h" +#include "region.h" +#include "ship.h" +#include "skill.h" +#include "terrain.h" +#include "terrainid.h" +#include "unit.h" + +/* from libutil */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* from libc */ +#include +#include +#include +#include +#include +#include + +/* attributes inclues */ +#include +#include + +#define STONERECYCLE 50 +/* Name, MaxGroesse, MinBauTalent, Kapazitaet, {Eisen, Holz, Stein, BauSilber, + * Laen, Mallorn}, UnterSilber, UnterSpezialTyp, UnterSpezial */ + + +static boolean +CheckOverload(void) +{ + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "rules.check_overload", 0); + } + return value; +} + +/* test if the unit can slip through a siege undetected. + * returns 0 if siege is successful, or 1 if the building is either + * not besieged or the unit can slip through the siege due to better stealth. + */ +static int +slipthru(const region * r, const unit * u, const building * b) +{ + unit *u2; + int n, o; + + /* b ist die burg, in die man hinein oder aus der man heraus will. */ + if (b==NULL || b->besieged < b->size * SIEGEFACTOR) { + return 1; + } + + /* u wird am hinein- oder herausschluepfen gehindert, wenn STEALTH <= + * OBSERVATION +2 der belagerer u2 ist */ + n = eff_skill(u, SK_STEALTH, r); + + for (u2 = r->units; u2; u2 = u2->next) { + if (usiege(u2) == b) { + + if (invisible(u, u2) >= u->number) continue; + + o = eff_skill(u2, SK_PERCEPTION, r); + + if (o + 2 >= n) { + return 0; /* entdeckt! */ + } + } + } + return 1; +} + +boolean +can_contact(const region * r, const unit * u, const unit * u2) +{ + + /* hier geht es nur um die belagerung von burgen */ + + if (u->building == u2->building) + return true; + + /* unit u is trying to contact u2 - unasked for contact. wenn u oder u2 + * nicht in einer burg ist, oder die burg nicht belagert ist, ist + * slipthru () == 1. ansonsten ist es nur 1, wenn man die belagerer */ + + if (slipthru(u->region, u, u->building) + && slipthru(u->region, u2, u2->building)) + return true; + + if (alliedunit(u, u2->faction, HELP_GIVE)) + return true; + + return false; +} + + +static void +contact_cmd(unit * u, order * ord, boolean tries) +{ + /* unit u kontaktiert unit u2. Dies setzt den contact einfach auf 1 - + * ein richtiger toggle ist (noch?) nicht noetig. die region als + * parameter ist nur deswegen wichtig, weil er an getunit () + * weitergegeben wird. dies wird fuer das auffinden von tempunits in + * getnewunit () verwendet! */ + unit *u2; + region * r = u->region; + + init_tokens(ord); + skip_token(); + u2 = getunitg(r, u->faction); + + if (u2!=NULL) { + if (!can_contact(r, u, u2)) { + if (tries) cmistake(u, u->thisorder, 23, MSG_EVENT); + return; + } + usetcontact(u, u2); + } +} +/* ------------------------------------------------------------- */ + +/* ------------------------------------------------------------- */ + + +/* ------------------------------------------------------------- */ + +struct building * +getbuilding(const struct region * r) +{ + building * b = findbuilding(getid()); + if (b==NULL || r!=b->region) return NULL; + return b; +} + +ship * +getship(const struct region * r) +{ + ship *sh, *sx = findship(getshipid()); + for (sh = r->ships; sh; sh = sh->next) { + if (sh == sx) return sh; + } + return NULL; +} + +/* ------------------------------------------------------------- */ + +static void +siege_cmd(unit * u, order * ord) +{ + region * r = u->region; + building *b; + int d, pooled; + int bewaffnete, katapultiere = 0; + static boolean init = false; + static const curse_type * magicwalls_ct; + static item_type * it_catapultammo = NULL; + static item_type * it_catapult = NULL; + if (!init) { + init = true; + magicwalls_ct = ct_find("magicwalls"); + it_catapultammo = it_find("catapultammo"); + it_catapult = it_find("catapult"); + } + /* gibt es ueberhaupt Burgen? */ + + init_tokens(ord); + skip_token(); + b = getbuilding(r); + + if (!b) { + cmistake(u, ord, 31, MSG_BATTLE); + return; + } + + if (!playerrace(u->race)) { + /* keine Drachen, Illusionen, Untote etc */ + cmistake(u, ord, 166, MSG_BATTLE); + return; + } + /* schaden durch katapulte */ + + d = i_get(u->items, it_catapult); + d = MIN(u->number, d); + pooled = get_pooled(u, it_catapultammo->rtype, GET_DEFAULT, d); + d = MIN(pooled, d); + if (eff_skill(u, SK_CATAPULT, r) >= 1) { + katapultiere = d; + d *= eff_skill(u, SK_CATAPULT, r); + } else { + d = 0; + } + + bewaffnete = armedmen(u, true); + if (d == 0 && bewaffnete == 0) { + /* abbruch, falls unbewaffnet oder unfaehig, katapulte zu benutzen */ + cmistake(u, ord, 80, MSG_EVENT); + return; + } + + if (!is_guard(u, GUARD_TRAVELTHRU)) { + /* abbruch, wenn die einheit nicht vorher die region bewacht - als + * warnung fuer alle anderen! */ + cmistake(u, ord, 81, MSG_EVENT); + return; + } + /* einheit und burg markieren - spart zeit beim behandeln der einheiten + * in der burg, falls die burg auch markiert ist und nicht alle + * einheiten wieder abgesucht werden muessen! */ + + usetsiege(u, b); + b->besieged += MAX(bewaffnete, katapultiere); + + /* definitiver schaden eingeschraenkt */ + + d = MIN(d, b->size - 1); + + /* meldung, schaden anrichten */ + if (d && !curse_active(get_curse(b->attribs, magicwalls_ct))) { + b->size -= d; + use_pooled(u, it_catapultammo->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, d); + /* send message to the entire region */ + ADDMSG(&r->msgs, msg_message("siege_catapults", + "unit building destruction", u, b, d)); + } else { + /* send message to the entire region */ + ADDMSG(&r->msgs, msg_message("siege", + "unit building", u, b)); + } +} + +void +do_siege(region *r) +{ + if (fval(r->terrain, LAND_REGION)) { + unit *u; + + for (u = r->units; u; u = u->next) { + if (get_keyword(u->thisorder) == K_BESIEGE) { + siege_cmd(u, u->thisorder); + } + } + } +} +/* ------------------------------------------------------------- */ + +static void +destroy_road(unit *u, int nmax, struct order * ord) +{ + direction_t d = getdirection(u->faction->locale); + unit *u2; + region *r = u->region; + short n = (short)nmax; + + if (nmax>SHRT_MAX) n = SHRT_MAX; + else if (nmax<0) n = 0; + + for (u2=r->units;u2;u2=u2->next) { + if (u2->faction!=u->faction && is_guard(u2, GUARD_TAX) + && cansee(u2->faction, u->region, u, 0) + && !alliedunit(u, u2->faction, HELP_GUARD)) { + cmistake(u, ord, 70, MSG_EVENT); + return; + } + } + + if (d==NODIRECTION) { + /* Die Richtung wurde nicht erkannt */ + cmistake(u, ord, 71, MSG_PRODUCE); + } else { + short road = rroad(r, d); + n = MIN(n, road); + if (n!=0) { + region * r2 = rconnect(r,d); + int willdo = eff_skill(u, SK_ROAD_BUILDING, r)*u->number; + willdo = MIN(willdo, n); + if (willdo==0) { + /* TODO: error message */ + } + if (willdo>SHRT_MAX) road = 0; + else road = road - (short)willdo; + rsetroad(r, d, road); + ADDMSG(&u->faction->msgs, msg_message("destroy_road", + "unit from to", u, r, r2)); + } + } +} + +int +destroy_cmd(unit * u, struct order * ord) +{ + ship *sh; + unit *u2; + region * r = u->region; + const construction * con = NULL; + int size = 0; + const char *s; + int n = INT_MAX; + + if (u->number < 1) + return 0; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + if (findparam(s, u->faction->locale)==P_ROAD) { + destroy_road(u, INT_MAX, ord); + return 0; + } + + if (s && *s) { + n = atoi((const char *)s); + if (n <= 0) { + cmistake(u, ord, 288, MSG_PRODUCE); + return 0; + } + } + + if (getparam(u->faction->locale) == P_ROAD) { + destroy_road(u, n, ord); + return 0; + } + + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 138, MSG_PRODUCE); + return 0; + } + + if (u->building) { + building *b = u->building; + + if (n >= b->size) { + /* destroy completly */ + /* all units leave the building */ + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->building == b) { + u2->building = 0; + freset(u2, UFL_OWNER); + } + } + ADDMSG(&u->faction->msgs, msg_message("destroy", + "building unit", b, u)); + con = b->type->construction; + remove_building(&r->buildings, b); + } else { + /* partial destroy */ + b->size -= n; + ADDMSG(&u->faction->msgs, msg_message("destroy_partial", + "building unit", b, u)); + } + } else if (u->ship) { + sh = u->ship; + + if (fval(r->terrain, SEA_REGION)) { + cmistake(u, ord, 14, MSG_EVENT); + return 0; + } + + if (n >= (sh->size*100)/sh->type->construction->maxsize) { + /* destroy completly */ + /* all units leave the ship */ + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->ship == sh) { + u2->ship = 0; + freset(u2, UFL_OWNER); + } + } + ADDMSG(&u->faction->msgs, msg_message("shipdestroy", + "unit region ship", u, r, sh)); + con = sh->type->construction; + remove_ship(&sh->region->ships, sh); + } else { + /* partial destroy */ + sh->size -= (sh->type->construction->maxsize * n)/100; + ADDMSG(&u->faction->msgs, msg_message("shipdestroy_partial", + "unit region ship", u, r, sh)); + } + } else { + log_error(("Die Einheit %s von %s war owner eines objects, war aber weder in einer Burg noch in einem Schiff.\n", + unitname(u), u->faction->name, u->faction->email)); + } + + if (con) { + /* TODO: Nicht an ZERSTÖRE mit Punktangabe angepaßt! */ + int c; + for (c=0;con->materials[c].number;++c) { + const requirement * rq = con->materials+c; + int recycle = (int)(rq->recycle * rq->number * size/con->reqsize); + if (recycle) { + change_resource(u, rq->rtype, recycle); + } + } + } + return 0; +} +/* ------------------------------------------------------------- */ + +void +build_road(region * r, unit * u, int size, direction_t d) +{ + int n, left; + region * rn = rconnect(r,d); + + assert(u->number); + if (!eff_skill(u, SK_ROAD_BUILDING, r)) { + cmistake(u, u->thisorder, 103, MSG_PRODUCE); + return; + } + if (besieged(u)) { + cmistake(u, u->thisorder, 60, MSG_PRODUCE); + return; + } + + if (rn==NULL || rn->terrain->max_road < 0) { + cmistake(u, u->thisorder, 94, MSG_PRODUCE); + return; + } + + if (r->terrain->max_road < 0) { + cmistake(u, u->thisorder, 94, MSG_PRODUCE); + return; + } + + if (r->terrain == newterrain(T_SWAMP)) { + /* wenn kein Damm existiert */ + static const struct building_type * bt_dam; + if (!bt_dam) bt_dam = bt_find("dam"); + assert(bt_dam); + if (!buildingtype_exists(r, bt_dam, true)) { + cmistake(u, u->thisorder, 132, MSG_PRODUCE); + return; + } + } else if (r->terrain == newterrain(T_DESERT)) { + static const struct building_type * bt_caravan; + if (!bt_caravan) bt_caravan = bt_find("caravan"); + assert(bt_caravan); + /* wenn keine Karawanserei existiert */ + if (!buildingtype_exists(r, bt_caravan, true)) { + cmistake(u, u->thisorder, 133, MSG_PRODUCE); + return; + } + } else if (r->terrain == newterrain(T_GLACIER)) { + static const struct building_type * bt_tunnel; + if (!bt_tunnel) bt_tunnel = bt_find("tunnel"); + assert(bt_tunnel); + /* wenn kein Tunnel existiert */ + if (!buildingtype_exists(r, bt_tunnel, true)) { + cmistake(u, u->thisorder, 131, MSG_PRODUCE); + return; + } + } + + /* left kann man noch bauen */ + left = r->terrain->max_road - rroad(r, d); + + /* hoffentlich ist r->road <= r->terrain->max_road, n also >= 0 */ + if (left <= 0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_roads_finished", "")); + return; + } + + if (size>0) left = MIN(size, left); + /* baumaximum anhand der rohstoffe */ + if (u->race == new_race[RC_STONEGOLEM]){ + n = u->number * GOLEM_STONE; + } else { + n = get_pooled(u, oldresourcetype[R_STONE], GET_DEFAULT, left); + if (n==0) { + cmistake(u, u->thisorder, 151, MSG_PRODUCE); + return; + } + } + left = MIN(n, left); + + /* n = maximum by skill. try to maximize it */ + n = u->number * eff_skill(u, SK_ROAD_BUILDING, r); + if (n < left) { + item * itm = *i_find(&u->items, olditemtype[I_RING_OF_NIMBLEFINGER]); + if (itm!=NULL && itm->number>0) { + int rings = MIN(u->number, itm->number); + n = n * ((roqf_factor()-1)*rings+u->number) / u->number; + } + } + if (n < left) { + int dm = get_effect(u, oldpotiontype[P_DOMORE]); + if (dm != 0) { + int sk = eff_skill(u, SK_ROAD_BUILDING, r); + int todo = (left - n + sk - 1) / sk; + todo = MIN(todo, u->number); + dm = MIN(dm, todo); + change_effect(u, oldpotiontype[P_DOMORE], -dm); + n += dm * sk; + } /* Auswirkung Schaffenstrunk */ + } + + /* make minimum of possible and available: */ + n = MIN(left, n); + + /* n is now modified by several special effects, so we have to + * minimize it again to make sure the road will not grow beyond + * maximum. */ + rsetroad(r, d, rroad(r, d) + (short)n); + + if (u->race == new_race[RC_STONEGOLEM]) { + int golemsused = n / GOLEM_STONE; + if (n%GOLEM_STONE != 0){ + ++golemsused; + } + scale_number(u, u->number - golemsused); + } else { + use_pooled(u, oldresourcetype[R_STONE], GET_DEFAULT, n); + /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ + produceexp(u, SK_ROAD_BUILDING, MIN(n, u->number)); + } + ADDMSG(&u->faction->msgs, msg_message("buildroad", + "region unit size", r, u, n)); +} +/* ------------------------------------------------------------- */ + +/* ** ** ** ** ** ** * + * new build rules * + * ** ** ** ** ** ** */ + +static int +required(int size, int msize, int maxneed) + /* um size von msize Punkten zu bauen, + * braucht man required von maxneed resourcen */ +{ + int used; + + used = size * maxneed / msize; + if (size * maxneed % msize) + ++used; + return used; +} + +static int +matmod(const attrib * a, const unit * u, const resource_type * material, int value) +{ + for (a=a_find((attrib*)a, &at_matmod);a && a->type==&at_matmod;a=a->next) { + mm_fun fun = (mm_fun)a->data.f; + value = fun(u, material, value); + if (value<0) return value; /* pass errors to caller */ + } + return value; +} + +int roqf_factor(void) +{ + int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "rules.economy.roqf", 10); + } + return value; +} + +/** Use up resources for building an object. +* Build up to 'size' points of 'type', where 'completed' +* of the first object have already been finished. return the +* actual size that could be built. +*/ +int +build(unit * u, const construction * ctype, int completed, int want) +{ + const construction * type = ctype; + int skills = INT_MAX; /* number of skill points remainig */ + int basesk = 0; + int made = 0; + + if (want<=0) return 0; + if (type==NULL) return 0; + if (type->improvement==NULL && completed==type->maxsize) + return ECOMPLETE; + if (type->btype!=NULL) { + building * b; + if (!u->building || u->building->type!=type->btype) { + return EBUILDINGREQ; + } + b = inside_building(u); + if (b==NULL) return EBUILDINGREQ; + } + + if (type->skill!=NOSKILL) { + int effsk; + int dm = get_effect(u, oldpotiontype[P_DOMORE]); + + assert(u->number); + basesk = effskill(u, type->skill); + if (basesk==0) return ENEEDSKILL; + + effsk = basesk; + if (inside_building(u)) { + effsk = skillmod(u->building->type->attribs, u, u->region, type->skill, + effsk, SMF_PRODUCTION); + } + effsk = skillmod(type->attribs, u, u->region, type->skill, + effsk, SMF_PRODUCTION); + if (effsk<0) return effsk; /* pass errors to caller */ + if (effsk==0) return ENEEDSKILL; + + skills = effsk * u->number; + + /* technically, nimblefinge and domore should be in a global set of + * "game"-attributes, (as at_skillmod) but for a while, we're leaving + * them in here. */ + + if (dm != 0) { + /* Auswirkung Schaffenstrunk */ + dm = MIN(dm, u->number); + change_effect(u, oldpotiontype[P_DOMORE], -dm); + skills += dm * effsk; + } + } + for (;want>0 && skills>0;) { + int c, n; + + /* skip over everything that's already been done: + * type->improvement==NULL means no more improvements, but no size limits + * type->improvement==type means build another object of the same time + * while material lasts type->improvement==x means build x when type + * is finished */ + while (type->improvement!=NULL && + type->improvement!=type && + type->maxsize>0 && + type->maxsize<=completed) + { + completed -= type->maxsize; + type = type->improvement; + } + if (type==NULL) { + if (made==0) return ECOMPLETE; + break; /* completed */ + } + + /* Hier ist entweder maxsize == -1, oder completed < maxsize. + * Andernfalls ist das Datenfile oder sonstwas kaputt... + * (enno): Nein, das ist für Dinge, bei denen die nächste Ausbaustufe + * die gleiche wie die vorherige ist. z.b. gegenstände. + */ + if (type->maxsize>1) { + completed = completed % type->maxsize; + } + else { + completed = 0; assert(type->reqsize>=1); + } + + if (basesk < type->minskill) { + if (made==0) return ELOWSKILL; /* not good enough to go on */ + } + + /* n = maximum buildable size */ + if (type->minskill > 1) { + n = skills / type->minskill; + } else { + n = skills; + } + /* Flinkfingerring wirkt nicht auf Mengenbegrenzte (magische) + * Talente */ + if (skill_limit(u->faction, type->skill)==INT_MAX) { + int i = 0; + item * itm = *i_find(&u->items, olditemtype[I_RING_OF_NIMBLEFINGER]); + if (itm!=NULL) i = itm->number; + if (i>0) { + int rings = MIN(u->number, i); + n = n * ((roqf_factor()-1)*rings+u->number) / u->number; + } + } + + if (want>0) { + n = MIN(want, n); + } + + if (type->maxsize>0) { + n = MIN(type->maxsize-completed, n); + if (type->improvement==NULL) { + want = n; + } + } + + if (type->materials) for (c=0;n>0 && type->materials[c].number;c++) { + const struct resource_type * rtype = type->materials[c].rtype; + int need, prebuilt; + int canuse = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); + + if (inside_building(u)) { + canuse = matmod(u->building->type->attribs, u, rtype, canuse); + } + + if (canuse<0) return canuse; /* pass errors to caller */ + canuse = matmod(type->attribs, u, rtype, canuse); + if (type->reqsize>1) { + prebuilt = required(completed, type->reqsize, type->materials[c].number); + for (;n;) { + need = required(completed + n, type->reqsize, type->materials[c].number); + if (need-prebuilt<=canuse) break; + --n; /* TODO: optimieren? */ + } + } else { + int maxn = canuse / type->materials[c].number; + if (maxn < n) n = maxn; + } + } + if (n<=0) { + if (made==0) return ENOMATERIALS; + else break; + } + if (type->materials) for (c=0;type->materials[c].number;c++) { + const struct resource_type * rtype = type->materials[c].rtype; + int prebuilt = required(completed, type->reqsize, type->materials[c].number); + int need = required(completed + n, type->reqsize, type->materials[c].number); + int multi = 1; + int canuse = 100; /* normalization */ + if (inside_building(u)) canuse = matmod(u->building->type->attribs, u, rtype, canuse); + if (canuse<0) return canuse; /* pass errors to caller */ + canuse = matmod(type->attribs, u, rtype, canuse); + + assert(canuse % 100 == 0 || !"only constant multipliers are implemented in build()"); + multi = canuse/100; + if (canuse<0) return canuse; /* pass errors to caller */ + + use_pooled(u, rtype, GET_DEFAULT, (need-prebuilt+multi-1)/multi); + } + made += n; + skills -= n * type->minskill; + want -= n; + completed = completed + n; + } + /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ + produceexp(u, ctype->skill, MIN(made, u->number)); + + return made; +} + +message * +msg_materials_required(unit * u, order * ord, const construction * ctype, int multi) +{ + int c; + /* something missing from the list of materials */ + resource * reslist = NULL; + + if (multi<=0 || multi==INT_MAX) multi = 1; + for (c=0;ctype->materials[c].number; ++c) { + resource * res = malloc(sizeof(resource)); + res->number = multi * ctype->materials[c].number / ctype->reqsize; + res->type = ctype->materials[c].rtype; + res->next = reslist; + reslist = res; + } + return msg_feedback(u, ord, "build_required", "required", reslist); +} + +int +maxbuild(const unit * u, const construction * cons) + /* calculate maximum size that can be built from available material */ + /* !! ignores maximum objectsize and improvements...*/ +{ + int c; + int maximum = INT_MAX; + for (c=0;cons->materials[c].number;c++) { + const resource_type * rtype = cons->materials[c].rtype; + int have = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); + int need = required(1, cons->reqsize, cons->materials[c].number); + if (haveregion; + boolean newbuilding = false; + int n = want, built = 0, id; + building * b = NULL; + /* einmalige Korrektur */ + const char * btname; + order * new_order = NULL; + const struct locale * lang = u->faction->locale; + static int rule_other = -1; + + assert(u->number); + if (eff_skill(u, SK_BUILDING, r) == 0) { + cmistake(u, ord, 101, MSG_PRODUCE); + return; + } + + /* Falls eine Nummer angegeben worden ist, und ein Gebaeude mit der + * betreffenden Nummer existiert, ist b nun gueltig. Wenn keine Burg + * gefunden wurde, dann wird nicht einfach eine neue erbaut. Ansonsten + * baut man an der eigenen burg weiter. */ + + /* Wenn die angegebene Nummer falsch ist, KEINE Burg bauen! */ + id = getid(); + if (id>0) { /* eine Nummer angegeben, keine neue Burg bauen */ + b = findbuilding(id); + if (!b || b->region != u->region) { /* eine Burg mit dieser Nummer gibt es hier nicht */ + /* vieleicht Tippfehler und die eigene Burg ist gemeint? */ + if (u->building && u->building->type==btype) { + b = u->building; + } else { + /* keine neue Burg anfangen wenn eine Nummer angegeben war */ + cmistake(u, ord, 6, MSG_PRODUCE); + return; + } + } + } else if (u->building && u->building->type==btype) { + b = u->building; + } + + if (b) btype = b->type; + + if (b && fval(btype, BTF_UNIQUE) && buildingtype_exists(r, btype, false)) { + /* only one of these per region */ + cmistake(u, ord, 93, MSG_PRODUCE); + return; + } + if (besieged(u)) { + /* units under siege can not build */ + cmistake(u, ord, 60, MSG_PRODUCE); + return; + } + if (btype->flags & BTF_NOBUILD) { + /* special building, cannot be built */ + cmistake(u, ord, 221, MSG_PRODUCE); + return; + } + if (btype->flags & BTF_ONEPERTURN) { + if(b && fval(b, BLD_EXPANDED)) { + cmistake(u, ord, 318, MSG_PRODUCE); + return; + } + n = 1; + } + if (b) { + if (rule_other<0) { + rule_other = get_param_int(global.parameters, "rules.build.other_buildings", 1); + } + if (!rule_other) { + unit * owner = building_owner(b); + if (!owner || owner->faction!=u->faction) { + cmistake(u, ord, 1222, MSG_PRODUCE); + return; + } + } + } + + if (b) built = b->size; + if (n<=0 || n == INT_MAX) { + if(b == NULL) { + if(btype->maxsize > 0) { + n = btype->maxsize - built; + } else { + n = INT_MAX; + } + } else { + if (b->type->maxsize > 0) { + n = b->type->maxsize - built; + } else { + n = INT_MAX; + } + } + } + built = build(u, btype->construction, built, n); + + switch (built) { + case ECOMPLETE: + /* the building is already complete */ + cmistake(u, ord, 4, MSG_PRODUCE); + return; + case ENOMATERIALS: + ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, btype->construction, want)); + return; + case ELOWSKILL: + case ENEEDSKILL: + /* no skill, or not enough skill points to build */ + cmistake(u, ord, 50, MSG_PRODUCE); + return; + } + + + /* at this point, the building size is increased. */ + if (b==NULL) { + /* build a new building */ + b = new_building(btype, r, lang); + b->type = btype; + fset(b, BLD_MAINTAINED); + + /* Die Einheit befindet sich automatisch im Inneren der neuen Burg. */ + if (leave(u, false)) { + u->building = b; + fset(u, UFL_OWNER); + } + +#ifdef WDW_PYRAMID + if(b->type == bt_find("pyramid") && f_get_alliance(u->faction) != NULL) { + attrib * a = a_add(&b->attribs, a_new(&at_alliance)); + a->data.i = u->faction->alliance->id; + } +#endif + + newbuilding = true; + } + + btname = LOC(lang, btype->_name); + + if (want-built <= 0) { + /* gebäude fertig */ + new_order = default_order(lang); + } else if (want!=INT_MAX) { + /* reduzierte restgröße */ + const char * hasspace = strchr(btname, ' '); + if (hasspace) { + new_order = create_order(K_MAKE, lang, "%d \"%s\" %i", n-built, btname, b->no); + } else { + new_order = create_order(K_MAKE, lang, "%d %s %i", n-built, btname, b->no); + } + } else if (btname) { + /* Neues Haus, Befehl mit Gebäudename */ + const char * hasspace = strchr(btname, ' '); + if (hasspace) { + new_order = create_order(K_MAKE, lang, "\"%s\" %i", btname, b->no); + } else { + new_order = create_order(K_MAKE, lang, "%s %i", btname, b->no); + } + } + + if (new_order) { + replace_order(&u->orders, ord, new_order); + free_order(new_order); + } + + b->size += built; + fset(b, BLD_EXPANDED); + + update_lighthouse(b); + + + ADDMSG(&u->faction->msgs, msg_message("buildbuilding", + "building unit size", b, u, built)); +} + +static void +build_ship(unit * u, ship * sh, int want) +{ + const construction * construction = sh->type->construction; + int size = (sh->size * DAMAGE_SCALE - sh->damage) / DAMAGE_SCALE; + int n; + int can = build(u, construction, size, want); + + if ((n=construction->maxsize - sh->size)>0 && can>0) { + if (can>=n) { + sh->size += n; + can -= n; + } + else { + sh->size += can; + n=can; + can = 0; + } + } + + if (sh->damage && can) { + int repair = MIN(sh->damage, can * DAMAGE_SCALE); + n += repair / DAMAGE_SCALE; + if (repair % DAMAGE_SCALE) ++n; + sh->damage = sh->damage - repair; + } + + if (n) ADDMSG(&u->faction->msgs, + msg_message("buildship", "ship unit size", sh, u, n)); +} + +void +create_ship(region * r, unit * u, const struct ship_type * newtype, int want, order * ord) +{ + ship *sh; + int msize; + const construction * cons = newtype->construction; + order * new_order; + + if (!eff_skill(u, SK_SHIPBUILDING, r)) { + cmistake(u, ord, 100, MSG_PRODUCE); + return; + } + if (besieged(u)) { + cmistake(u, ord, 60, MSG_PRODUCE); + return; + } + + /* check if skill and material for 1 size is available */ + if (eff_skill(u, cons->skill, r) < cons->minskill) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_build_skill_low", "value name", + cons->minskill, newtype->name[1])); + return; + } + + msize = maxbuild(u, cons); + if (msize==0) { + cmistake(u, ord, 88, MSG_PRODUCE); + return; + } + if (want>0) want = MIN(want, msize); + else want = msize; + + sh = new_ship(newtype, u->faction->locale, r); + + if (leave(u, false)) { + if (fval(u->race, RCF_CANSAIL)) { + u->ship = sh; + fset(u, UFL_OWNER); + } + } + new_order = create_order(K_MAKE, u->faction->locale, "%s %i", LOC(u->faction->locale, parameters[P_SHIP]), sh->no); + replace_order(&u->orders, ord, new_order); + free_order(new_order); + + build_ship(u, sh, want); +} + +void +continue_ship(region * r, unit * u, int want) +{ + const construction * cons; + ship *sh; + int msize; + + if (!eff_skill(u, SK_SHIPBUILDING, r)) { + cmistake(u, u->thisorder, 100, MSG_PRODUCE); + return; + } + + /* Die Schiffsnummer bzw der Schiffstyp wird eingelesen */ + sh = getship(r); + + if (!sh) sh = u->ship; + + if (!sh) { + cmistake(u, u->thisorder, 20, MSG_PRODUCE); + return; + } + cons = sh->type->construction; + assert(cons->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (sh->size==cons->maxsize && !sh->damage) { + cmistake(u, u->thisorder, 16, MSG_PRODUCE); + return; + } + if (eff_skill(u, cons->skill, r) < cons->minskill) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_build_skill_low", "value name", + cons->minskill, sh->type->name[1])); + return; + } + msize = maxbuild(u, cons); + if (msize==0) { + cmistake(u, u->thisorder, 88, MSG_PRODUCE); + return; + } + if (want > 0) want = MIN(want, msize); + else want = msize; + + build_ship(u, sh, want); +} +/* ------------------------------------------------------------- */ + +static boolean +mayenter(region * r, unit * u, building * b) +{ + unit *u2; + if (fval(b, BLD_UNGUARDED)) return true; + u2 = building_owner(b); + + if (u2==NULL || ucontact(u2, u) + || alliedunit(u2, u->faction, HELP_GUARD)) return true; + + return false; +} + +static int +mayboard(const unit * u, const ship * sh) +{ + unit *u2 = shipowner(sh); + + return (!u2 || ucontact(u2, u) || alliedunit(u2, u->faction, HELP_GUARD)); +} + +int +leave_cmd(unit * u, struct order * ord) +{ + region * r = u->region; + + if (fval(u, UFL_ENTER)) { + /* if we just entered this round, then we don't leave again */ + return 0; + } + + if (fval(r->terrain, SEA_REGION) && u->ship) { + if(!fval(u->race, RCF_SWIM)) { + cmistake(u, ord, 11, MSG_MOVE); + return 0; + } + if (has_horses(u)) { + cmistake(u, ord, 231, MSG_MOVE); + return 0; + } + } + if (!slipthru(r, u, u->building)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "entrance_besieged", "building", u->building)); + } else { + leave(u, true); + } + return 0; +} + +static boolean +enter_ship(unit * u, struct order * ord, int id, boolean report) +{ + region * r = u->region; + ship * sh; + + /* Muß abgefangen werden, sonst könnten Schwimmer an + * Bord von Schiffen an Land gelangen. */ + if (!fval(u->race, RCF_CANSAIL) || (!fval(u->race, RCF_WALK) && !fval(u->race, RCF_FLY))) { + cmistake(u, ord, 233, MSG_MOVE); + return false; + } + + sh = findship(id); + if (sh == NULL || sh->region!=r) { + if (report) cmistake(u, ord, 20, MSG_MOVE); + return false; + } + if (sh==u->ship) return true; + if (!mayboard(u, sh)) { + if (report) cmistake(u, ord, 34, MSG_MOVE); + return false; + } + if (CheckOverload()) { + int sweight, scabins; + int mweight = shipcapacity(sh); + int mcabins = sh->type->cabins; + + if (mweight>0) { + getshipweight(sh, &sweight, &scabins); + sweight += weight(u); + if (mcabins) { + int pweight = u->number * u->race->weight; + /* weight goes into number of cabins, not cargo */ + scabins += pweight; + sweight -= pweight; + } + + if (sweight > mweight || (mcabins && (scabins > mcabins))) { + if (report) cmistake(u, ord, 34, MSG_MOVE); + return false; + } + } + } + + if (leave(u, false)) { + u->ship = sh; + + if (shipowner(sh) == NULL) { + fset(u, UFL_OWNER); + } + fset(u, UFL_ENTER); + } + return true; +} + +static boolean +enter_building(unit * u, order * ord, int id, boolean report) +{ + region * r = u->region; + building * b; + + /* Schwimmer können keine Gebäude betreten, außer diese sind + * auf dem Ozean */ + if (!fval(u->race, RCF_WALK) && !fval(u->race, RCF_FLY)) { + if (!fval(r->terrain, SEA_REGION)) { + if (report) { + cmistake(u, ord, 232, MSG_MOVE); + } + return false; + } + } + + b = findbuilding(id); + if (b==NULL || b->region!=r) { + if (report) { + cmistake(u, ord, 6, MSG_MOVE); + } + return false; + } + if (!mayenter(r, u, b)) { + if (report) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "entrance_denied", "building", b)); + } + return false; + } + if (!slipthru(r, u, b)) { + if (report) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "entrance_besieged", "building", b)); + } + return false; + } + + if (leave(u, false)) { + if (building_owner(b) == 0) { + fset(u, UFL_OWNER); + } + fset(u, UFL_ENTER); + u->building = b; + return true; + } + return false; +} + +void +do_misc(region * r, boolean lasttry) +{ + unit **uptr, *uc; + + for (uc = r->units; uc; uc = uc->next) { + order * ord; + for (ord = uc->orders; ord; ord = ord->next) { + switch (get_keyword(ord)) { + case K_CONTACT: + contact_cmd(uc, ord, lasttry); + break; + } + } + } + + for (uptr = &r->units; *uptr;) { + unit * u = *uptr; + order ** ordp = &u->orders; + + while (*ordp) { + order * ord = *ordp; + if (get_keyword(ord) == K_ENTER) { + param_t p; + int id; + unit * ulast = NULL; + + init_tokens(ord); + skip_token(); + p = getparam(u->faction->locale); + id = getid(); + + switch (p) { + case P_BUILDING: + case P_GEBAEUDE: + if (u->building && u->building->no==id) break; + if (enter_building(u, ord, id, lasttry)) { + unit *ub; + for (ub=u;ub;ub=ub->next) { + if (ub->building==u->building) { + ulast = ub; + } + } + } + break; + + case P_SHIP: + if (u->ship && u->ship->no==id) break; + if (enter_ship(u, ord, id, lasttry)) { + unit *ub; + ulast = u; + for (ub=u;ub;ub=ub->next) { + if (ub->ship==u->ship) { + ulast = ub; + } + } + } + break; + + default: + if (lasttry) cmistake(u, ord, 79, MSG_MOVE); + + } + if (ulast!=NULL) { + /* Wenn wir hier angekommen sind, war der Befehl + * erfolgreich und wir löschen ihn, damit er im + * zweiten Versuch nicht nochmal ausgeführt wird. */ + *ordp = ord->next; + ord->next = NULL; + free_order(ord); + + if (ulast!=u) { + /* put u behind ulast so it's the last unit in the building */ + *uptr = u->next; + u->next = ulast->next; + ulast->next = u; + } + break; + } + } + if (*ordp==ord) ordp = &ord->next; + } + if (*uptr==u) uptr = &u->next; + } +} diff --git a/src/kernel/build.h b/src/kernel/build.h new file mode 100644 index 000000000..012f06000 --- /dev/null +++ b/src/kernel/build.h @@ -0,0 +1,99 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_BUILD +#define H_KRNL_BUILD + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Die enums fuer Gebauede werden nie gebraucht, nur bei der Bestimmung + * des Schutzes durch eine Burg wird die Reihenfolge und MAXBUILDINGS + * wichtig + */ + +struct xml_tag; + +typedef struct requirement { + const struct resource_type * rtype; + int number; + double recycle; /* recycling quota */ +} requirement; + +typedef struct construction { + skill_t skill; /* skill req'd per point of size */ + int minskill; /* skill req'd per point of size */ + + int maxsize; /* maximum size of this type */ + int reqsize; /* size of object using up 1 set of requirement. */ + requirement * materials; /* material req'd to build one object */ + const struct building_type * btype; + /* building type required to make this thing */ + + struct construction * improvement; + /* next level, if upgradable. if more than one of these items + * can be built (weapons, armour) per turn, must not be NULL, + * but point to the same type again: + * const_sword.improvement = &const_sword + * last level of a building points to NULL, as do objects of + * an unlimited size. + */ + struct attrib * attribs; + /* stores skill modifiers and other attributes */ + +} construction; + +extern int destroy_cmd(struct unit * u, struct order * ord); +extern int leave_cmd(struct unit * u, struct order * ord); + +extern boolean can_contact(const struct region *r, const struct unit *u, const struct unit *u2); + +void do_siege(struct region *r); +void build_road(struct region * r, struct unit * u, int size, direction_t d); +void create_ship(struct region * r, struct unit * u, const struct ship_type * newtype, int size, struct order * ord); +void continue_ship(struct region * r, struct unit * u, int size); + +struct building * getbuilding(const struct region * r); +struct ship *getship(const struct region * r); + +void do_misc(struct region *r, boolean tries); + +void reportevent(struct region * r, char *s); + +void shash(struct ship * sh); +void sunhash(struct ship * sh); +extern int roqf_factor(void); + +extern int build(struct unit * u, const construction * ctype, int completed, int want); +extern int maxbuild(const struct unit *u, const construction *cons); +extern struct message * msg_materials_required(struct unit * u, struct order * ord, const struct construction * ctype, int multi); +/** error messages that build may return: */ +#define ELOWSKILL -1 +#define ENEEDSKILL -2 +#define ECOMPLETE -3 +#define ENOMATERIALS -4 +#define EBUILDINGREQ -5 + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/kernel/building.c b/src/kernel/building.c new file mode 100644 index 000000000..3b2553812 --- /dev/null +++ b/src/kernel/building.c @@ -0,0 +1,695 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include + +#include +#include "building.h" + +/* kernel includes */ +#include "item.h" +#include "curse.h" /* für C_NOCOST */ +#include "unit.h" +#include "faction.h" +#include "region.h" +#include "skill.h" +#include "magic.h" +#include "save.h" +#include "version.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +/* attributes includes */ +#include + +static const char * NULLSTRING = "(null)"; + +static void +lc_init(struct attrib *a) +{ + a->data.v = calloc(1, sizeof(building_action)); +} + +static void +lc_done(struct attrib *a) +{ + building_action * data = (building_action*)a->data.v; + if (data->fname) free(data->fname); + if (data->param) free(data->param); + free(data); +} + +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; + const char * fparam = data->param; + building * b = data->b; + + write_building_reference(b, store); + store->w_tok(store, fname); + store->w_tok(store, fparam?fparam:NULLSTRING); +} + +static int +lc_read(struct attrib * a, void * owner, struct storage * store) +{ + building_action * data = (building_action*)a->data.v; + int result = read_reference(&data->b, store, read_building_reference, resolve_building); + if (store->versionfname = store->r_str(store); + } else { + data->fname = store->r_tok(store); + } + if (store->version>=BACTION_VERSION) { + char lbuf[256]; + if (store->versionr_str_buf(store, lbuf, sizeof(lbuf)); + } else { + store->r_tok_buf(store, lbuf, sizeof(lbuf)); + } + if (strcmp(lbuf, NULLSTRING)==0) data->param = NULL; + else data->param = strdup(lbuf); + } else { + data->param = strdup(NULLSTRING); + } + if (result==0 && !data->b) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +attrib_type at_building_action = { + "lcbuilding", + lc_init, lc_done, + NULL, + lc_write, lc_read +}; + +typedef struct building_typelist { + struct building_typelist * next; + building_type * type; +} building_typelist; + +static building_typelist *buildingtypes; + +building_type * +bt_find(const char* name) +{ + const struct building_typelist * btl = buildingtypes; + assert(name); + while (btl && strcmp(btl->type->_name, name)) btl = btl->next; + if (btl==NULL) { + return NULL; + } + return btl->type; +} + +void +bt_register(building_type * type) +{ + struct building_typelist * btl = malloc(sizeof(building_type)); + if (type->init) type->init(type); + btl->type = type; + btl->next = buildingtypes; + buildingtypes = btl; +} + +int +buildingcapacity(const building * b) +{ + if (b->type->capacity>=0) { + if (b->type->maxcapacity>=0) { + return MIN(b->type->maxcapacity, b->size * b->type->capacity); + } + return b->size * b->type->capacity; + } + if (b->size>=b->type->maxsize) { + if (b->type->maxcapacity>=0) { + return b->type->maxcapacity; + } + } + return 0; +} + +attrib_type at_building_generic_type = { + "building_generic_type", NULL, NULL, NULL, a_writestring, a_readstring, ATF_UNIQUE +}; + +const char * +buildingtype(const building_type * btype, const building * b, int bsize) +{ + const char * s = NULL; + static boolean init_generic = false; + static const struct building_type * bt_generic; + + if (!init_generic) { + init_generic = true; + bt_generic = bt_find("generic"); + } + + if (btype == bt_generic) { + const attrib *a = a_find(b->attribs, &at_building_generic_type); + if (a) s = (const char*)a->data.v; + } + + if (btype->name) s = btype->name(btype, b, bsize); + if (s==NULL) s = btype->_name; + return s; +} + +#define BMAXHASH 7919 +static building *buildhash[BMAXHASH]; +void +bhash(building * b) +{ + building *old = buildhash[b->no % BMAXHASH]; + + buildhash[b->no % BMAXHASH] = b; + b->nexthash = old; +} + +void +bunhash(building * b) +{ + building **show; + + for (show = &buildhash[b->no % BMAXHASH]; *show; show = &(*show)->nexthash) { + if ((*show)->no == b->no) + break; + } + if (*show) { + assert(*show == b); + *show = (*show)->nexthash; + b->nexthash = 0; + } +} + +static building * +bfindhash(int i) +{ + building *old; + + for (old = buildhash[i % BMAXHASH]; old; old = old->nexthash) + if (old->no == i) + return old; + return 0; +} + +building * +findbuilding(int i) +{ + return bfindhash(i); +} +/* ** old building types ** */ + + +static int +sm_smithy(const unit * u, const region * r, skill_t sk, int value) /* skillmod */ +{ + if (sk==SK_WEAPONSMITH || sk==SK_ARMORER) { + if (u->region == r) return value + 1; + } + return value; +} +static int +mm_smithy(const unit * u, const resource_type * rtype, int value) /* material-mod */ +{ + if (rtype == oldresourcetype[R_IRON]) return value * 2; + return value; +} +static void +init_smithy(struct building_type * bt) +{ + a_add(&bt->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION, sm_smithy, 1.0, 0)); + a_add(&bt->attribs, make_matmod(mm_smithy)); +} + +static const char * +castle_name_i(const struct building_type* btype, const struct building * b, int bsize, const char * fname[]) +{ + int i = bt_effsize(btype, b, bsize); + + return fname[i]; +} + +static const char * +castle_name_2(const struct building_type* btype, const struct building * b, int bsize) +{ + const char * fname[] = { + "site", + "fortification", + "tower", + "castle", + "fortress", + "citadel" + }; + return castle_name_i(btype, b, bsize, fname); +} + +static const char * +castle_name(const struct building_type* btype, const struct building * b, int bsize) +{ + const char * fname[] = { + "site", + "tradepost", + "fortification", + "tower", + "castle", + "fortress", + "citadel" + }; + return castle_name_i(btype, b, bsize, fname); +} + +static const char * +fort_name(const struct building_type* btype, const struct building * b, int bsize) +{ + const char * fname[] = { + "scaffolding", + "guardhouse", + "guardtower", + }; + return castle_name_i(btype, b, bsize, fname); +} + +#ifdef WDW_PYRAMID + +static const char * +pyramid_name(const struct building_type* btype, int bsize) +{ + static char p_name_buf[32]; + int level=0; + const construction * ctype; + + ctype = btype->construction; + + while (ctype && ctype->maxsize != -1 && ctype->maxsize<=bsize) { + bsize-=ctype->maxsize; + ctype=ctype->improvement; + ++level; + } + + sprintf(p_name_buf, "pyramid%d", level); + + return p_name_buf; +} + +int +wdw_pyramid_level(const struct building *b) +{ + const construction *ctype = b->type->construction; + int completed = b->size; + int level = 0; + + while(ctype->improvement != NULL && + ctype->improvement != ctype && + ctype->maxsize > 0 && + ctype->maxsize <= completed) + { + ++level; + completed-=ctype->maxsize; + ctype = ctype->improvement; + } + + return level; +} +#endif + +/* for finding out what was meant by a particular building string */ + +static local_names * bnames; + +const building_type * +findbuildingtype(const char * name, const struct locale * lang) +{ + variant type; + local_names * bn = bnames; + + while (bn) { + if (bn->lang==lang) break; + bn=bn->next; + } + if (!bn) { + struct building_typelist * btl = buildingtypes; + bn = calloc(sizeof(local_names), 1); + bn->next = bnames; + bn->lang = lang; + while (btl) { + const char * n = locale_string(lang, btl->type->_name); + type.v = (void*)btl->type; + addtoken(&bn->names, n, type); + btl=btl->next; + } + bnames = bn; + } + if (findtoken(&bn->names, name, &type)==E_TOK_NOMATCH) return NULL; + return (const building_type*)type.v; +} + +static int eressea_building_protection(building * b, unit * u) +{ + int beff = buildingeffsize(b, false)-1; + /* -1 because the tradepost has no protection value */ + + return beff; +} + +void +register_buildings(void) +{ + register_function((pf_generic)&eressea_building_protection, "eressea_building_protection"); + register_function((pf_generic)&init_smithy, "init_smithy"); + register_function((pf_generic)&castle_name, "castle_name"); + register_function((pf_generic)&castle_name_2, "castle_name_2"); + register_function((pf_generic)&fort_name, "fort_name"); +#ifdef WDW_PYRAMID + register_function((pf_generic)&pyramid_name, "pyramid_name"); +#endif +} + +void +write_building_reference(const struct building * b, struct storage * store) +{ + store->w_id(store, (b && b->region)?b->no:0); +} + + +int +resolve_building(variant id, void * address) +{ + int result = 0; + building * b = NULL; + if (id.i!=0) { + b = findbuilding(id.i); + if (b==NULL) { + result = -1; + } + } + *(building**)address = b; + return result; +} + +variant +read_building_reference(struct storage * store) +{ + variant result; + result.i = store->r_id(store); + return result; +} + +void +free_buildinglist(building_list *blist) +{ + while (blist) { + building_list * rl2 = blist->next; + free(blist); + blist = rl2; + } +} + +void +add_buildinglist(building_list **blist, building *b) +{ + building_list *rl2 = (building_list*)malloc(sizeof(building_list)); + + rl2->data = b; + rl2->next = *blist; + + *blist = rl2; +} + +building * +new_building(const struct building_type * btype, region * r, const struct locale * lang) +{ + building *b = (building *) calloc(1, sizeof(building)); + static boolean init_lighthouse = false; + static const struct building_type * bt_lighthouse = 0; + + if (!init_lighthouse) { + bt_lighthouse = bt_find("lighthouse"); + init_lighthouse = true; + } + + b->flags = BLD_WORKING|BLD_MAINTAINED; + b->no = newcontainerid(); + bhash(b); + + b->type = btype; + b->region = r; + addlist(&r->buildings, b); + + if (b->type==bt_lighthouse) { + r->flags |= RF_LIGHTHOUSE; + } + { + const char * bname; + if (b->type->name==NULL) { + bname = LOC(lang, btype->_name); + } else { + bname = LOC(lang, buildingtype(btype, b, 0)); + } + b->name = strdup(bname); + } + return b; +} + +static building * deleted_buildings; + +/** remove a building from the region. + * remove_building lets units leave the building + */ +void +remove_building(building ** blist, building * b) +{ + unit *u; + direction_t d; + static const struct building_type * bt_caravan, * bt_dam, * bt_tunnel; + static boolean init = false; + + if (!init) { + init = true; + bt_caravan = bt_find("caravan"); + bt_dam = bt_find("dam"); + bt_tunnel = bt_find("tunnel"); + } + + assert(bfindhash(b->no)); + + handle_event(b->attribs, "destroy", b); + for (u=b->region->units; u; u=u->next) { + if (u->building == b) leave(u, true); + } + + b->size = 0; + update_lighthouse(b); + bunhash(b); + + /* Falls Karawanserei, Damm oder Tunnel einstürzen, wird die schon + * gebaute Straße zur Hälfte vernichtet */ + if (b->type == bt_caravan || b->type == bt_dam || b->type == bt_tunnel) { + region * r = b->region; + for (d=0;d!=MAXDIRECTIONS;++d) if (rroad(r, d) > 0) { + rsetroad(r, d, rroad(r, d) / 2); + } + } + + /* Stattdessen nur aus Liste entfernen, aber im Speicher halten. */ + while (*blist && *blist!=b) blist = &(*blist)->next; + *blist = b->next; + b->region = NULL; + b->next = deleted_buildings; + deleted_buildings = b; +} + +void +free_building(building * b) +{ + while (b->attribs) a_remove (&b->attribs, b->attribs); + free(b->name); + free(b->display); + free(b); +} + +void +free_buildings(void) +{ + while (deleted_buildings) { + building * b = deleted_buildings; + deleted_buildings = b->next; + } +} + +extern struct attrib_type at_icastle; + +/** returns the building's build stage (NOT size in people). + * only makes sense for castles or similar buildings with multiple + * stages */ +int +buildingeffsize(const building * b, boolean img) +{ + const struct building_type * btype = NULL; + + if (b==NULL) return 0; + + btype = b->type; + if (img) { + const attrib * a = a_find(b->attribs, &at_icastle); + if (a) { + btype = (const struct building_type *)a->data.v; + } + } + return bt_effsize(btype, b, b->size); +} + +int bt_effsize(const building_type * btype, const building * b, int bsize) +{ + int i = bsize, n = 0; + const construction * cons = btype->construction; + + /* TECH DEBT: simplest thing that works for E3 dwarf/halfling faction rules */ + if (b && get_param_int(global.parameters, "rules.dwarf_castles", 1) && strcmp(btype->_name, "castle")==0) { + unit * u = building_owner(b); + if (u && u->faction->race == new_race[RC_HALFLING]) { + i = bsize * 10 / 8; + } + } + + if (!cons || !cons->improvement) { + return 0; + } + + while (cons && cons->maxsize != -1 && i>=cons->maxsize) { + i -= cons->maxsize; + cons = cons->improvement; + ++n; + } + + return n; +} + +const char * +write_buildingname(const building * b, char * ibuf, size_t size) +{ + snprintf((char*)ibuf, size, "%s (%s)", b->name, itoa36(b->no)); + ibuf[size-1] = 0; + return ibuf; +} + +const char * +buildingname(const building * b) +{ + typedef char name[OBJECTIDSIZE + 1]; + static name idbuf[8]; + static int nextbuf = 0; + char *ibuf = idbuf[(++nextbuf) % 8]; + return write_buildingname(b, ibuf, sizeof(name)); +} + +unit * +building_owner(const building * b) +{ + unit *u = NULL; + unit *first = NULL; + region * r = b->region; + /* Prüfen ob Eigentümer am leben. */ + + for (u = r->units; u; u = u->next) { + if (u->building == b) { + if (!first && u->number > 0) + first = u; + if (fval(u, UFL_OWNER) && u->number > 0) + return u; + if (u->number == 0) + freset(u, UFL_OWNER); + } + } + + /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit + * nehmen. */ + + if (first) { + fset(first, UFL_OWNER); + } + return first; +} + +const char * building_getname(const building * self) +{ + return self->name; +} + +void building_setname(building * self, const char * name) +{ + free(self->name); + if (name) self->name = strdup(name); + else self->name = NULL; +} + +void +building_addaction(building * b, const char * fname, const char * param) +{ + attrib * a = a_add(&b->attribs, a_new(&at_building_action)); + building_action * data = (building_action*)a->data.v; + data->b = b; + data->fname = strdup(fname); + if (param) { + data->param = strdup(param); + } +} + +region * +building_getregion(const building * b) +{ + return b->region; +} + +void +building_setregion(building * b, region * r) +{ + building ** blist = &b->region->buildings; + while (*blist && *blist!=b) { + blist = &(*blist)->next; + } + *blist = b->next; + b->next = NULL; + + blist = &r->buildings; + while (*blist && *blist!=b) blist = &(*blist)->next; + *blist = b; + + b->region = r; +} + diff --git a/src/kernel/building.h b/src/kernel/building.h new file mode 100644 index 000000000..7aea49bd1 --- /dev/null +++ b/src/kernel/building.h @@ -0,0 +1,177 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_BUILDING +#define H_KRNL_BUILDING + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* maintenance::flags */ +#define MTF_NONE 0x00 +#define MTF_VARIABLE 0x01 /* resource usage scales with size */ +#define MTF_VITAL 0x02 /* if resource missing, building may crash */ + +typedef struct maintenance { + const struct resource_type * rtype; /* type of resource required */ + int number; /* amount of resources */ + unsigned int flags; /* misc. flags */ +} maintenance; + +/* building_type::flags */ +#define BTF_NONE 0x00 +#define BTF_INDESTRUCTIBLE 0x01 /* cannot be torm down */ +#define BTF_NOBUILD 0x02 /* special, can't be built */ +#define BTF_UNIQUE 0x04 /* only one per struct region (harbour) */ +#define BTF_DECAY 0x08 /* decays when not occupied */ +#define BTF_DYNAMIC 0x10 /* dynamic type, needs bt_write */ +#define BTF_MAGIC 0x40 /* magical effect */ +#define BTF_ONEPERTURN 0x80 /* one one sizepoint can be added per turn */ +#define BTF_NAMECHANGE 0x100 /* name and description can be changed more than once */ + +typedef struct building_type { + const char * _name; + + int flags; /* flags */ + int capacity; /* Kapazität pro Größenpunkt */ + int maxcapacity; /* Max. Kapazität */ + int maxsize; /* how big can it get, with all the extensions? */ + int magres; /* how well it resists against spells */ + int magresbonus; /* bonus it gives the target against spells */ + int fumblebonus; /* bonus that reduces fumbling */ + double auraregen; /* modifier for aura regeneration inside building */ + struct maintenance * maintenance; /* array of requirements */ + struct construction * construction; /* construction of 1 building-level */ + + const char * (*name)(const struct building_type*, const struct building * b, int size); + void (*init)(struct building_type*); + void (*age)(struct building *); + int (*protection)(struct building *, struct unit *); + double (*taxes)(const struct building *, int size); + struct attrib * attribs; +} building_type; + +extern building_type * bt_find(const char* name); +extern void register_buildings(void); +extern void bt_register(struct building_type * type); +extern int bt_effsize(const struct building_type * btype, const struct building * b, int bsize); + +/* buildingt => building_type + * Name => locale_string(name) + * MaxGroesse => levels + * MinBauTalent => construction->minskill + * Kapazitaet => capacity, maxcapacity + * Materialien => construction->materials + * UnterSilber, UnterSpezialTyp, UnterSpezial => maintenance + * per_size => !maintenance->fixed + */ +#define BFL_NONE 0x00 +#define BLD_MAINTAINED 0x01 /* vital maintenance paid for */ +#define BLD_WORKING 0x02 /* full maintenance paid, it works */ +#define BLD_UNGUARDED 0x04 /* you can enter this building anytime */ +#define BLD_EXPANDED 0x08 /* has been expanded this turn */ +#define BLD_SELECT 0x10 /* formerly FL_DH */ +#define BLD_DONTPAY 0x20 /* PAY NOT */ + +#define BLD_SAVEMASK 0x00 /* mask for persistent flags */ + +typedef struct building { + struct building *next; + struct building *nexthash; + + const struct building_type * type; + struct region *region; + char *name; + char *display; + struct attrib * attribs; + int no; + int size; + int sizeleft; /* is only used during battle. should be a temporary attribute */ + int besieged; /* should be an attribute */ + unsigned int flags; +} building; + +typedef struct building_list { + struct building_list * next; + building * data; +} building_list; + +extern void free_buildinglist(building_list *bl); +extern void add_buildinglist(building_list **bl, struct building *b); + +extern struct attrib_type at_building_generic_type; +extern const char * buildingtype(const building_type * btype, const struct building * b, int bsize); +extern const char * write_buildingname(const building * b, char * ibuf, size_t size); +extern int buildingcapacity(const struct building * b); +extern struct building *new_building(const struct building_type * typ, struct region * r, const struct locale * lang); +void build_building(struct unit * u, const struct building_type * typ, int size, struct order * ord); + +/* Alte Gebäudetypen: */ + +/* old functions, still in build.c: */ +int buildingeffsize(const building * b, boolean img); +void bhash(struct building * b); +void bunhash(struct building * b); +int buildingcapacity(const struct building * b); + +extern void remove_building(struct building * *blist, struct building * b); +extern void free_building(struct building * b); +extern void free_buildings(void); + +const struct building_type * findbuildingtype(const char * name, const struct locale * lang); + +#include "build.h" +#define NOBUILDING NULL + +extern int resolve_building(variant data, void * address); +extern void write_building_reference(const struct building * b, struct storage * store); +extern variant read_building_reference(struct storage * store); + +extern struct building *findbuilding(int n); + +extern struct unit * building_owner(const struct building * b); + +extern struct attrib_type at_building_action; +void building_addaction(struct building * b, const char * fname, const char * param); + +#ifdef WDW_PYRAMID +extern int wdw_pyramid_level(const struct building *b); +#endif + +typedef struct building_action { + building * b; + char * fname; + char * param; +} building_action; + +extern const char * buildingname(const struct building * b); + +extern const char * building_getname(const struct building * b); +extern void building_setname(struct building * self, const char * name); + +struct region * building_getregion(const struct building * b); +void building_setregion(struct building * bld, struct region * r); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/calendar.c b/src/kernel/calendar.c new file mode 100644 index 000000000..8a4efccca --- /dev/null +++ b/src/kernel/calendar.c @@ -0,0 +1,59 @@ +#include +#include "calendar.h" + +#include + +int first_turn = 0; +int first_month = 0; +int weeks_per_month = 0; +int months_per_year = 0; +char **seasonnames = NULL; +char **weeknames = NULL; +char **weeknames2 = NULL; +char **monthnames = NULL; +int *month_season = NULL; +char *agename = NULL; +int seasons = 0; + +const gamedate * +get_gamedate(int turn, gamedate * gd) +{ + int weeks_per_year = months_per_year * weeks_per_month; + int t = turn - first_turn; + + assert(gd); + if (t<0) t = turn; + + gd->week = t%weeks_per_month; /* 0 - weeks_per_month-1 */ + gd->month = (t/weeks_per_month + first_month)%months_per_year; /* 0 - months_per_year-1 */ + gd->year = t/(weeks_per_year) + 1; + gd->season = month_season[gd->month]; + return gd; +} + +void +calendar_cleanup(void) +{ + int i; + + free(agename); + + for (i=0;i!=seasons;++i) { + free(seasonnames[i]); + } + free(seasonnames); + + for (i=0;i!=months_per_year;++i) { + free(monthnames[i]); + } + free(storms); + free(month_season); + free(monthnames); + + for (i=0;i!=weeks_per_month;++i) { + free(weeknames[i]); + free(weeknames2[i]); + } + free(weeknames); + free(weeknames2); +} diff --git a/src/kernel/calendar.h b/src/kernel/calendar.h new file mode 100644 index 000000000..ae4306d28 --- /dev/null +++ b/src/kernel/calendar.h @@ -0,0 +1,45 @@ +#ifndef KRNL_CALENDAR_H +#define KRNL_CALENDAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + SEASON_WINTER, + SEASON_SPRING, + SEASON_SUMMER, + SEASON_AUTUMN +}; + + +extern char *agename; +extern int first_turn; +extern int first_month; + +extern int seasons; +extern char **seasonnames; + +extern int months_per_year; +extern char **monthnames; +extern int *month_season; +extern int *storms; /* in movement.c */ + +extern char **weeknames; +extern char **weeknames2; +extern int weeks_per_month; + +typedef struct gamedate { + int year; + int season; + int month; + int week; +} gamedate; + +extern const gamedate * get_gamedate(int turn, gamedate * gd); +extern void calendar_cleanup(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/command.c b/src/kernel/command.c new file mode 100644 index 000000000..93741e4c2 --- /dev/null +++ b/src/kernel/command.c @@ -0,0 +1,103 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ +#include +#include +#include "command.h" + +#include + +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +typedef struct command { + parser fun; + struct tnode * nodes; +} command; + +tnode * +stree_find(const syntaxtree * stree, const struct locale * lang) +{ + while (stree) { + if (stree->lang==lang) return stree->root; + stree = stree->next; + } + return NULL; +} + +syntaxtree * +stree_create(void) +{ + syntaxtree * sroot = NULL; + const struct locale * lang = locales; + while (lang) { + syntaxtree * stree = (syntaxtree *)malloc(sizeof(syntaxtree)); + stree->lang = lang; + stree->next = sroot; + sroot=stree; + lang=nextlocale(lang); + } + return sroot; +} + +void +add_command(struct tnode * keys, struct tnode * tnext, + const char * str, parser fun) +{ + command * cmd = (command *)malloc(sizeof(command)); + variant var; + + cmd->fun = fun; + cmd->nodes = tnext; + var.v = cmd; + addtoken(keys, str, var); +} + +static int +do_command_i(const struct tnode * keys, void * u, struct order * ord) +{ + const char * c; + variant var; + + c = getstrtoken(); + if (findtoken(keys, c, &var)==E_TOK_SUCCESS) { + command * cmd = (command *)var.v; + if (cmd->nodes && *c) { + assert(!cmd->fun); + return do_command_i(cmd->nodes, u, ord); + } else if (cmd->fun) { + cmd->fun(cmd->nodes, u, ord); + return E_TOK_SUCCESS; + } + } + return E_TOK_NOMATCH; +} + +void +do_command(const struct tnode * keys, void * u, struct order * ord) +{ + init_tokens(ord); + skip_token(); + if (do_command_i(keys, u, ord)!=E_TOK_SUCCESS) { + char * cmd = getcommand(ord); + log_warning(("%s failed command '%s'\n", unitname(u), cmd)); + free(cmd); + } +} diff --git a/src/kernel/command.h b/src/kernel/command.h new file mode 100644 index 000000000..401b9e8bc --- /dev/null +++ b/src/kernel/command.h @@ -0,0 +1,39 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ +#ifndef H_UTIL_COMMAND_H +#define H_UTIL_COMMAND_H +#ifdef __cplusplus +extern "C" { +#endif + +struct tnode; +struct locale; +struct order; + +typedef struct syntaxtree { + const struct locale * lang; + struct tnode * root; + struct syntaxtree * next; +} syntaxtree; + +typedef void (*parser)(const struct tnode *, void *, struct order*); +extern void add_command(struct tnode * troot, struct tnode * tnext, const char * str, parser fun); +extern void do_command(const struct tnode * troot, void * u, struct order *); + +extern struct syntaxtree * stree_create(void); +extern struct tnode * stree_find(const struct syntaxtree * stree, const struct locale * lang); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/config.c b/src/kernel/config.c new file mode 100644 index 000000000..814bc45d5 --- /dev/null +++ b/src/kernel/config.c @@ -0,0 +1,3275 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include + +/* attributes includes */ +#include +#include + +/* kernel includes */ +#include "alliance.h" +#include "alchemy.h" +#include "battle.h" +#include "connection.h" +#include "building.h" +#include "calendar.h" +#include "curse.h" +#include "faction.h" +#include "group.h" +#include "item.h" +#include "magic.h" +#include "message.h" +#include "move.h" +#include "names.h" +#include "objtypes.h" +#include "order.h" +#include "plane.h" +#include "pool.h" +#include "race.h" +#include "region.h" +#include "save.h" +#include "ship.h" +#include "skill.h" +#include "terrain.h" +#include "unit.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libxml includes */ +#include +#include + +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define PTRIES 0 /* it turns out they are slow :-( */ +#if PTRIES +#include +#endif + +struct settings global = { + "Eressea", /* gamename */ +}; +FILE *logfile; +FILE *updatelog; +const struct race * new_race[MAXRACES]; +boolean sqlpatch = false; +boolean battledebug = false; +int turn = 0; + +#if XECMD_MODULE +attrib_type at_xontormiaexpress = { + "xontormiaexpress", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + a_writeint, + a_readint, + ATF_UNIQUE +}; +#endif + +int +NewbieImmunity(void) { + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "NewbieImmunity", 0); + } + return value; +} + +boolean +IsImmune(const faction * f) +{ + return !fval(f, FFL_NPC) && f->age < NewbieImmunity(); +} + +static int +MaxAge(void) { + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "MaxAge", 0); + } + return value; +} + +static int +ally_flag(const char * s, int help_mask) +{ + if ((help_mask&HELP_MONEY) && strcmp(s, "money")==0) return HELP_MONEY; + if ((help_mask&HELP_FIGHT) && strcmp(s, "fight")==0) return HELP_FIGHT; + if ((help_mask&HELP_GIVE) && strcmp(s, "give")==0) return HELP_GIVE; + if ((help_mask&HELP_GUARD) && strcmp(s, "guard")==0) return HELP_GUARD; + if ((help_mask&HELP_FSTEALTH) && strcmp(s, "stealth")==0) return HELP_FSTEALTH; + if ((help_mask&HELP_TRAVEL) && strcmp(s, "travel")==0) return HELP_TRAVEL; + return 0; +} + +boolean +ExpensiveMigrants(void) +{ + int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "study.expensivemigrants", 0); + } + return value; +} +/** Specifies automatic alliance modes. + * If this returns a value then the bits set are immutable between alliance + * partners (faction::alliance) and cannot be changed with the HELP command. + */ +int +AllianceAuto(void) +{ + static int value = -1; + if (value<0) { + const char * str = get_param(global.parameters, "alliance.auto"); + value = 0; + if (str!=NULL) { + char * sstr = strdup(str); + char * tok = strtok(sstr, " "); + while (tok) { + value |= ally_flag(tok, -1); + tok = strtok(NULL, " "); + } + free(sstr); + } + } + return value & HelpMask(); +} + +/** Limits the available help modes + * The bitfield returned by this function specifies the available help modes + * in this game (so you can, for example, disable HELP GIVE globally). + * Disabling a status will disable the command sequence entirely (order parsing + * uses this function). + */ +int +HelpMask(void) +{ + static int value = -1; + if (value<0) { + const char * str = get_param(global.parameters, "rules.help.mask"); + value = 0; + if (str!=NULL) { + char * sstr = strdup(str); + char * tok = strtok(sstr, " "); + while (tok) { + value |= ally_flag(tok, -1); + tok = strtok(NULL, " "); + } + free(sstr); + } else { + value = HELP_ALL; + } + } + return value; +} + +int +AllianceRestricted(void) +{ + static int value = -1; + if (value<0) { + const char * str = get_param(global.parameters, "alliance.restricted"); + value = 0; + if (str!=NULL) { + char * sstr = strdup(str); + char * tok = strtok(sstr, " "); + while (tok) { + value |= ally_flag(tok, -1); + tok = strtok(NULL, " "); + } + free(sstr); + } + value &= HelpMask(); + } + return value; +} + +int +LongHunger(const struct unit * u) { + static int value = -1; + if (u!=NULL) { + if (!fval(u, UFL_HUNGER)) return false; +#ifdef NEW_DAEMONHUNGER_RULE + if (u->race==new_race[RC_DAEMON]) return false; +#endif + } + if (value<0) { + value = get_param_int(global.parameters, "hunger.long", 0); + } + return value; +} + +int +SkillCap(skill_t sk) { + static int value = -1; + if (sk==SK_MAGIC) return 0; /* no caps on magic */ + if (value<0) { + value = get_param_int(global.parameters, "skill.maxlevel", 0); + } + return value; +} + +int +NMRTimeout(void) { + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "nmr.timeout", 0); + } + return value; +} + +race_t +old_race(const struct race * rc) +{ + race_t i; + for (i=0;i!=MAXRACES;++i) { + if (new_race[i]==rc) return i; + } + return NORACE; +} + +helpmode helpmodes[] = { + { "all", HELP_ALL }, + { "money", HELP_MONEY }, + { "fight", HELP_FIGHT }, + { "observe", HELP_OBSERVE }, + { "give", HELP_GIVE }, + { "guard", HELP_GUARD }, + { "stealth", HELP_FSTEALTH }, + { "travel", HELP_TRAVEL }, + { NULL, 0 } +}; + +const char *directions[MAXDIRECTIONS+2] = +{ + "northwest", + "northeast", + "east", + "southeast", + "southwest", + "west", + "", + "pause" +}; + +/** Returns the English name of the race, which is what the database uses. + */ +const char * +dbrace(const struct race * rc) +{ + static char zText[32]; + char * zPtr = zText; + + /* the english names are all in ASCII, so we don't need to worry about UTF8 */ + strcpy(zText, (const char*)LOC(find_locale("en"), rc_name(rc, 0))); + while (*zPtr) { + *zPtr = (char)(toupper(*zPtr)); + ++zPtr; + } + return zText; +} + +const char *parameters[MAXPARAMS] = +{ + "LOCALE", + "ALLES", + "JEDEM", + "BAUERN", + "BURG", + "EINHEIT", + "PRIVAT", + "HINTEN", + "KOMMANDO", + "KRAEUTER", + "NICHT", + "NAECHSTER", + "PARTEI", + "ERESSEA", + "PERSONEN", + "REGION", + "SCHIFF", + "SILBER", + "STRASSEN", + "TEMPORAERE", + "FLIEHE", + "GEBAEUDE", + "GIB", /* Für HELFE */ + "KAEMPFE", + "DURCHREISE", + "BEWACHE", + "ZAUBER", + "PAUSE", + "VORNE", + "AGGRESSIV", + "DEFENSIV", + "STUFE", + "HELFE", + "FREMDES", + "AURA", + "UM", + "BEISTAND", + "GNADE", + "HINTER", + "VOR", + "ANZAHL", + "GEGENSTAENDE", + "TRAENKE", + "GRUPPE", + "PARTEITARNUNG", + "BAEUME", + "XEPOTION", + "XEBALLOON", + "XELAEN", + "ALLIANZ" +}; + + +const char *keywords[MAXKEYWORDS] = +{ + "//", + "BANNER", + "ARBEITEN", + "ATTACKIEREN", + "BEKLAUEN", + "BELAGERE", + "BENENNEN", + "BENUTZEN", + "BESCHREIBEN", + "BETRETEN", + "BEWACHEN", + "BOTSCHAFT", + "ENDE", + "FAHREN", + "NUMMER", + "KRIEG", + "FRIEDEN", + "FOLGEN", + "FORSCHEN", + "GIB", + "HELFEN", + "KAEMPFEN", + "KAMPFZAUBER", + "KAUFEN", + "KONTAKTIEREN", + "LEHREN", + "LERNEN", + "LIEFERE", + "MACHEN", + "NACH", + "PASSWORT", + "REKRUTIEREN", + "RESERVIEREN", + "ROUTE", + "SABOTIEREN", + "OPTION", + "SPIONIEREN", + "STIRB", + "TARNEN", + "TRANSPORTIEREN", + "TREIBEN", + "UNTERHALTEN", + "VERKAUFEN", + "VERLASSEN", + "VERGESSEN", + "ZAUBERE", + "ZEIGEN", + "ZERSTOEREN", + "ZUECHTEN", + "DEFAULT", + "URSPRUNG", + "EMAIL", + "PIRATERIE", + "NEUSTART", + "GRUPPE", + "OPFERE", + "BETEN", + "SORTIEREN", + "JIHAD", + "GM", + "INFO", + "PRAEFIX", + "PFLANZEN", + "WERWESEN", + "XONTORMIA", + "ALLIANZ", + "BEANSPRUCHEN", + "PROMOTION", + "BEZAHLEN", +}; + +const char *report_options[MAX_MSG] = +{ + "Kampf", + "Ereignisse", + "Bewegung", + "Einkommen", + "Handel", + "Produktion", + "Orkvermehrung", + "Zauber", + "", + "" +}; + +const char *message_levels[ML_MAX] = +{ + "Wichtig", + "Debug", + "Fehler", + "Warnungen", + "Infos" +}; + +const char *options[MAXOPTIONS] = +{ + "AUSWERTUNG", + "COMPUTER", + "ZUGVORLAGE", + NULL, + "STATISTIK", + "DEBUG", + "ZIPPED", + "ZEITUNG", /* Option hat Sonderbehandlung! */ + NULL, + "ADRESSEN", + "BZIP2", + "PUNKTE", + "SHOWSKCHANGE", + "XML" +}; + +static int +allied_skillcount(const faction * f, skill_t sk) +{ + int num = 0; + alliance * a = f_get_alliance(f); + faction_list * members = a->members; + while (members!=NULL) { + num += count_skill(members->data, sk); + members=members->next; + } + return num; +} + +static int +allied_skilllimit(const faction * f, skill_t sk) +{ + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "alliance.skilllimit", 0); + } + return value; +} + +static void +init_maxmagicians(struct attrib *a) +{ + a->data.i = MAXMAGICIANS; +} + +static attrib_type at_maxmagicians = { + "maxmagicians", + init_maxmagicians, + NULL, + NULL, + a_writeint, + a_readint, + ATF_UNIQUE +}; + +static void +init_npcfaction(struct attrib *a) +{ + a->data.i = 1; +} + + +static attrib_type at_npcfaction = { + "npcfaction", + init_npcfaction, + NULL, + NULL, + a_writeint, + a_readint, + ATF_UNIQUE +}; + +int +max_magicians(const faction * f) +{ + int m = MAXMAGICIANS; + attrib * a; + + if ((a = a_find(f->attribs, &at_maxmagicians)) != NULL) { + m = a->data.i; + } + if (f->race == new_race[RC_ELF]) ++m; + return m; +} + +int +skill_limit(faction * f, skill_t sk) +{ + int m = INT_MAX; + int al = allied_skilllimit(f, sk); + if (al>0) { + if (sk!=SK_ALCHEMY && sk!=SK_MAGIC) return INT_MAX; + if (f_get_alliance(f)) { + int ac = listlen(f->alliance->members); /* number of factions */ + int fl = (al+ac-1)/ac; /* faction limit, rounded up */ + /* the faction limit may not be achievable because it would break the alliance-limit */ + int sc = al - allied_skillcount(f, sk); + if (sc<=0) return 0; + return fl; + } + } + switch (sk) { + case SK_MAGIC: + m = max_magicians(f); + break; + case SK_ALCHEMY: + m = MAXALCHEMISTS; + break; + } + return m; +} + +int +count_skill(faction * f, skill_t sk) +{ + int n = 0; + unit *u; + + for (u = f->units; u; u = u->nextF) { + if (has_skill(u, sk)) { + if (!is_familiar(u)) n += u->number; + } + } + return n; +} + +int verbosity = 0; + +FILE *debug; + +static int +ShipSpeedBonus(const unit * u) +{ + static int level = -1; + if (level==-1) { + level = get_param_int(global.parameters, "movement.shipspeed.skillbonus", 0); + } + if (level>0) { + ship * sh = u->ship; + int skl = effskill(u, SK_SAILING); + int minsk = (sh->type->cptskill+1)/2; + return (skl-minsk)/level; + } + return 0; +} + +int +shipspeed(const ship * sh, const unit * u) +{ + double k = sh->type->range; + static const curse_type * stormwind_ct, * nodrift_ct; + static boolean init; + attrib *a; + curse *c; + + if (!init) { + init = true; + stormwind_ct = ct_find("stormwind"); + nodrift_ct = ct_find("nodrift"); + } + + assert(u->ship==sh); + assert(sh->type->construction->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (sh->size!=sh->type->construction->maxsize) return 0; + + if( curse_active(get_curse(sh->attribs, stormwind_ct))) + k *= 2; + if( curse_active(get_curse(sh->attribs, nodrift_ct))) + k += 1; + + if (u->faction->race == u->race) { + /* race bonus for this faction? */ + if (fval(u->race, RCF_SHIPSPEED)) { + k += 1; + } + } + + k += ShipSpeedBonus(u); + + a = a_find(sh->attribs, &at_speedup); + while (a != NULL && a->type==&at_speedup) { + k += a->data.sa[0]; + a = a->next; + } + + c = get_curse(sh->attribs, ct_find("shipspeedup")); + while(c) { + k += curse_geteffect(c); + c = c->nexthash; + } + +#ifdef SHIPSPEED + k *= SHIPSPEED; +#endif + +#ifdef SHIPDAMAGE + if (sh->damage) k = (k * (sh->size * DAMAGE_SCALE - sh->damage) + sh->size * DAMAGE_SCALE- 1) / (sh->size*DAMAGE_SCALE); +#endif + + return (int)k; +} + +#define FMAXHASH 2039 +faction * factionhash[FMAXHASH]; + +void +fhash(faction * f) +{ + int index = f->no % FMAXHASH; + f->nexthash = factionhash[index]; + factionhash[index] = f; +} + +void +funhash(faction * f) +{ + int index = f->no % FMAXHASH; + faction ** fp = factionhash+index; + while (*fp && (*fp)!=f) fp = &(*fp)->nexthash; + *fp = f->nexthash; +} + +static faction * +ffindhash(int no) +{ + int index = no % FMAXHASH; + faction * f = factionhash[index]; + while (f && f->no!=no) f = f->nexthash; + return f; +} +/* ----------------------------------------------------------------------- */ + +void +verify_data(void) +{ +#ifndef NDEBUG + int lf = -1; + faction *f; + unit *u; + int mage, alchemist; + + if (verbosity>=1) puts(" - Überprüfe Daten auf Korrektheit..."); + + list_foreach(faction, factions, f) { + mage = 0; + alchemist = 0; + for (u=f->units;u;u=u->nextF) { + if (eff_skill(u, SK_MAGIC, u->region)) { + mage += u->number; + } + if (eff_skill(u, SK_ALCHEMY, u->region)) + alchemist += u->number; + if (u->number > UNIT_MAXSIZE) { + if (lf != f->no) { + lf = f->no; + log_stdio(stdout, "Partei %s:\n", factionid(f)); + } + log_warning(("Einheit %s hat %d Personen\n", unitid(u), u->number)); + } + } + if (f->no != 0 && ((mage > 3 && f->race != new_race[RC_ELF]) || mage > 4)) + log_error(("Partei %s hat %d Magier.\n", factionid(f), mage)); + if (alchemist > 3) + log_error(("Partei %s hat %d Alchemisten.\n", factionid(f), alchemist)); + } + list_next(f); +#endif +} + +int +distribute(int old, int new_value, int n) +{ + int i; + int t; + assert(new_value <= old); + + if (old == 0) + return 0; + + t = (n / old) * new_value; + for (i = (n % old); i; i--) + if (rng_int() % old < new_value) + t++; + + return t; +} + +int +change_hitpoints (unit * u, int value) +{ + int hp = u->hp; + + hp += value; + + /* Jede Person benötigt mindestens 1 HP */ + if (hp < u->number){ + if (hp < 0){ /* Einheit tot */ + hp = 0; + } + scale_number(u, hp); + } + u->hp = hp; + return hp; +} + +unsigned int +atoip(const char *s) +{ + int n; + + n = atoi (s); + + if (n < 0) + n = 0; + + return n; +} + +region * +findunitregion (const unit * su) +{ +#ifndef SLOW_REGION + return su->region; +#else + region *r; + const unit *u; + + for (r = regions; r; r = r->next) { + for (u = r->units; u; u = u->next) { + if (su == u) { + return r; + } + } + } + + /* This should never happen */ + assert (!"Die unit wurde nicht gefunden"); + + return (region *) NULL; +#endif +} + +int +effskill(const unit * u, skill_t sk) +{ + return eff_skill(u, sk, u->region); +} + +int +eff_stealth(const unit * u, const region * r) +{ + int e = 0; + + /* Auf Schiffen keine Tarnung! */ + if (!u->ship && skill_enabled[SK_STEALTH]) { + e = eff_skill (u, SK_STEALTH, r); + + if (fval(u, UFL_STEALTH)) { + int es = u_geteffstealth(u); + if (es >=0 && es < e) return es; + } + } + return e; +} + +boolean +unit_has_cursed_item(unit *u) +{ + item * itm = u->items; + while (itm) { + if (fval(itm->type, ITF_CURSED) && itm->number>0) return true; + itm=itm->next; + } + return false; +} + +static void +init_gms(void) +{ + faction * f; + + for (f=factions;f;f=f->next) { + const attrib * a = a_findc(f->attribs, &at_gm); + + if (a!=NULL) fset(f, FFL_GM); + } +} + +static int +autoalliance(const plane * pl, const faction * sf, const faction * f2) +{ + static boolean init = false; + if (!init) { + init_gms(); + init = true; + } + if (pl && (pl->flags & PFL_FRIENDLY)) return HELP_ALL; + /* if f2 is a gm in this plane, everyone has an auto-help to it */ + if (fval(f2, FFL_GM)) { + attrib * a = a_find(f2->attribs, &at_gm); + + while (a) { + const plane * p = (const plane*)a->data.v; + if (p==pl) return HELP_ALL; + a=a->next; + } + } + + if (f_get_alliance(sf)!=NULL && AllianceAuto()) { + if (sf->alliance==f2->alliance) return AllianceAuto(); + } + + return 0; +} + +static int +ally_mode(const ally * sf, int mode) +{ + if (sf==NULL) return 0; + return sf->status & mode; +} + +int +alliedgroup(const struct plane * pl, const struct faction * f, + const struct faction * f2, const struct ally * sf, int mode) +{ + while (sf && sf->faction!=f2) sf=sf->next; + if (sf==NULL) { + mode = mode & autoalliance(pl, f, f2); + } + mode = ally_mode(sf, mode) | (mode & autoalliance(pl, f, f2)); + if (AllianceRestricted()) { + if (a_findc(f->attribs, &at_npcfaction)) { + return mode; + } + if (a_findc(f2->attribs, &at_npcfaction)) { + return mode; + } + if (f->alliance!=f2->alliance) { + mode &= ~AllianceRestricted(); + } + } + return mode; +} + +int +alliedfaction(const struct plane * pl, const struct faction * f, + const struct faction * f2, int mode) +{ + return alliedgroup(pl, f, f2, f->allies, mode); +} + +/* Die Gruppe von Einheit u hat helfe zu f2 gesetzt. */ +int +alliedunit(const unit * u, const faction * f2, int mode) +{ + ally * sf; + int automode; + + assert(u->region); /* the unit should be in a region, but it's possible that u->number==0 (TEMP units) */ + if (u->faction == f2) return mode; + if (u->faction != NULL && f2!=NULL) { + plane * pl; + + if (mode&HELP_FIGHT) { + if ((u->flags&UFL_DEFENDER) || (u->faction->flags&FFL_DEFENDER)) { + faction * owner = region_get_owner(u->region); + /* helps the owner of the region */ + if (owner==f2) { + return HELP_FIGHT; + } + } + } + + pl = rplane(u->region); + automode = mode & autoalliance(pl, u->faction, f2); + + if (pl!=NULL && (pl->flags & PFL_NOALLIANCES)) + mode = (mode & automode) | (mode & HELP_GIVE); + + sf = u->faction->allies; + if (fval(u, UFL_GROUP)) { + const attrib * a = a_findc(u->attribs, &at_group); + if (a!=NULL) sf = ((group*)a->data.v)->allies; + } + return alliedgroup(pl, u->faction, f2, sf, mode); + } + return 0; +} + +boolean +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)) + return true; + return false; +} + +boolean +cansee(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 */ +{ + int stealth, rings; + unit *u2 = r->units; + static const item_type * itype_grail; + static boolean init; + + if (!init) { + init = true; + itype_grail = it_find("grail"); + } + + if (u->faction == f || omniscient(f)) { + return true; + } else if (fval(u->race, RCF_INVISIBLE)) { + return false; + } else if (u->number == 0) { + 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. */ + u = (unit *)a->data.v; + } else { + return false; + } + } + + if (leftship(u)) return true; + if (itype_grail!=NULL && i_get(u->items, itype_grail)) 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, GUARD_ALL)!=0 || usiege(u) || u->building || u->ship) { + return true; + } + + rings = invisible(u, NULL); + stealth = eff_stealth(u, r) - modifier; + + while (u2) { + if (ringsnumber || invisible(u, u2) < u->number) { + if (skill_enabled[SK_PERCEPTION]) { + int observation = eff_skill(u2, SK_PERCEPTION, r); + + if (observation >= stealth) { + return true; + } + } else { + return true; + } + } + + /* find next unit in our faction */ + do { + u2=u2->next; + } while (u2 && u2->faction != f); + } + return false; +} + +boolean +cansee_unit(const unit * u, const unit * target, int modifier) +/* target->region kann != u->region sein, wenn es um durchreisen geht */ +{ + if (fval(target->race, RCF_INVISIBLE) || target->number == 0) return false; + else if (target->faction == u->faction) return true; + else { + int n, rings, o; + + if (is_guard(target, GUARD_ALL)!=0 || usiege(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]) { + o = eff_skill(u, SK_PERCEPTION, target->region); + if (o >= n) { + return true; + } + } else { + return true; + } + } + return false; +} + +boolean +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 */ +{ + int n; + unit *u2; + + if (fval(u->race, RCF_INVISIBLE) || u->number == 0) return false; + else if (u->faction == f) return true; + else { + int rings; + + if (is_guard(u, GUARD_ALL)!=0 || usiege(u) || u->building || u->ship) { + return true; + } + + n = eff_stealth(u, r) - modifier; + rings = invisible(u, NULL); + if (rings==0 && n<=0) { + return true; + } + + for (u2 = r->units; u2; u2 = u2->next){ + if (u2->faction == f) { + int o; + + if (rings && invisible(u, u2) >= u->number) continue; + + o = eff_skill(u2, SK_PERCEPTION, r); + + if (o >= n) { + return true; + } + } + } + } + return false; +} + +#ifndef NDEBUG +const char * +strcheck (const char *s, size_t maxlen) +{ + static char buffer[16 * 1024]; + if (strlen(s) > maxlen) { + assert(maxlen < 16 * 1024); + log_warning(("[strcheck] String wurde auf %d Zeichen verkürzt:\n%s\n", + (int)maxlen, s)); + strlcpy(buffer, s, maxlen); + return buffer; + } + return s; +} +#endif + +static attrib_type at_lighthouse = { + "lighthouse" + /* Rest ist NULL; temporäres, nicht alterndes Attribut */ +}; + +/* update_lighthouse: call this function whenever the size of a lighthouse changes + * it adds temporary markers to the surrounding regions. + * The existence of markers says nothing about the quality of the observer in + * the lighthouse, for this may change more frequently. + */ +void +update_lighthouse(building * lh) +{ + static boolean init_lighthouse = false; + static const struct building_type * bt_lighthouse = 0; + + if (!init_lighthouse) { + bt_lighthouse = bt_find("lighthouse"); + if (bt_lighthouse==NULL) return; + init_lighthouse = true; + } + + if (lh->type==bt_lighthouse) { + region * r = lh->region; + int d = (int)log10(lh->size) + 1; + int x; + + if (lh->size>0) { + r->flags |= RF_LIGHTHOUSE; + } + + for (x=-d;x<=d;++x) { + int y; + for (y=-d;y<=d;++y) { + attrib * a; + region * r2; + int px = r->x+x, py = r->y+y; + pnormalize(&px, &py, rplane(r)); + r2 = findregion(px, py); + if (r2==NULL) continue; + if (!fval(r2->terrain, SEA_REGION)) continue; + if (distance(r, r2) > d) continue; + a = a_find(r2->attribs, &at_lighthouse); + while (a && a->type==&at_lighthouse) { + building * b = (building*)a->data.v; + if (b==lh) break; + a = a->next; + } + if (!a) { + a = a_add(&r2->attribs, a_new(&at_lighthouse)); + a->data.v = (void*)lh; + } + } + } + } +} + +int +count_all(const faction * f) +{ +#ifndef NDEBUG + int n = 0; + unit *u; + for (u=f->units;u;u=u->nextF) { + if (playerrace(u->race)) { + n += u->number; + assert(f==u->faction); + } + } + if (f->num_people != n) { + log_error(("# of people in %s is != num_people: %d should be %d.\n", + factionid(f), f->num_people, n)); + } +#endif + return f->num_people; +} + +int +count_migrants (const faction * f) +{ + unit *u = f->units; + int n = 0; + while (u) { + assert(u->faction == f); + if (u->race != f->race && u->race != new_race[RC_ILLUSION] && u->race != new_race[RC_SPELL] + && !!playerrace(u->race) && !(is_cursed(u->attribs, C_SLAVE, 0))) + { + n += u->number; + } + u = u->nextF; + } + return n; +} + +int +count_maxmigrants(const faction * f) +{ + static int migrants = -1; + + if (migrants<0) { + migrants = get_param_int(global.parameters, "rules.migrants", INT_MAX); + } + if (migrants==INT_MAX) { + int x = 0; + if (f->race == new_race[RC_HUMAN]) { + int nsize = count_all(f); + if (nsize>0) { + x = (int)(log10(nsize / 50.0) * 20); + if (x < 0) x = 0; + } + } + return x; + } + return migrants; +} + +void +init_tokens(const struct order * ord) +{ + char * cmd = getcommand(ord); + init_tokens_str(cmd, cmd); +} + +void +parse(keyword_t kword, int (*dofun)(unit *, struct order *), boolean thisorder) +{ + region *r; + + for (r = regions; r; r = r->next) { + unit **up = &r->units; + while (*up) { + unit * u = *up; + order ** ordp = &u->orders; + if (thisorder) ordp = &u->thisorder; + while (*ordp) { + order * ord = *ordp; + if (get_keyword(ord) == kword) { + if (dofun(u, ord)!=0) break; + if (u->orders==NULL) break; + } + if (thisorder) break; + if (*ordp==ord) ordp=&ord->next; + } + if (*up==u) up=&u->next; + } + } +} + +const char * +igetstrtoken(const char * initstr) +{ + if (initstr!=NULL) { + init_tokens_str(initstr, NULL); + } + + return getstrtoken(); +} + +unsigned int +getuint (void) +{ + return atoip((const char *)getstrtoken()); +} + +int +getint (void) +{ + return atoi((const char *)getstrtoken()); +} + +const struct race * +findrace(const char * s, const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_RACES); + variant token; + + assert(lang); + if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { + return (const struct race *)token.v; + } + return NULL; +} + +int +findoption(const char *s, const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_OPTIONS); + variant token; + + if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { + return (direction_t)token.i; + } + return NODIRECTION; +} + +#if PTRIES +static struct trie_node * ptries[UT_MAX][4]; + +static struct trie_node ** +get_ptrie(const struct locale * lang, int type) +{ + int index = (strcmp(locale_name(lang), "de")==0); + return &(ptries[type][index]); +} + +static int +umlaut_substitution(const char * ip, char * op, size_t outlen) +{ +#define UMAX 7 + static struct replace { + ucs4_t ucs; + const char str[3]; + } replace[UMAX] = { + /* match lower-case (!) umlauts and others to transcriptions */ + { 223, "ss"}, /* szlig */ + { 228, "ae"}, /* auml */ + { 229, "aa"}, /* norsk */ + { 230, "ae"}, /* norsk */ + { 246, "oe"}, /* ouml */ + { 248, "oe"}, /* norsk */ + { 252, "ue"}, /* uuml */ + }; + int subs = 0; + while (*ip) { + ucs4_t ucs = *ip; + size_t size = 1; + size_t cpsize = 1; + + if (ucs & 0x80) { + int ret = unicode_utf8_to_ucs4(&ucs, ip, &size); + if (ret!=0) { + return ret; + } + cpsize = size; + if (ucs >= replace[0].ucs && ucs <= replace[UMAX-1].ucs) { + int i; + for (i=0;i!=UMAX;++i) { + if (replace[i].ucs==ucs) { + cpsize = 0; + memcpy(op, replace[i].str, 2); + op+=2; + ++subs; + break; + } + } + } + } + if (cpsize) { + if (cpsize>outlen) { + return -1; + } + memcpy(op, ip, cpsize); + } + + ip += size; + op += cpsize; + outlen -= cpsize; + } + + if (outlen<=0) { + return -1; + } + *op = 0; + return subs; +} + +static int +ptrie_find(struct trie_node *ptrie, const char * key, void * data, size_t size) +{ + trie_node * node = trie_find_prefix(ptrie, key); + if (node) { + void * result = trie_getdata(node); + memcpy(data, result, size); + return 0; + } + return -1; +} + +static int +ptrie_insert(struct trie_node **ptrie, const char * name, void * data, size_t size) +{ + char converted[256]; + char simple[256]; + int ret = unicode_utf8_tolower(converted, 256, name); + if (ret==0) { + int subs = umlaut_substitution(converted, simple, sizeof(simple)); + if (subs>0) { + trie_insert(ptrie, simple, data, size); + } + trie_insert(ptrie, converted, data, size); + } + return ret; +} +#endif + +skill_t +findskill(const char *s, const struct locale * lang) +{ +#if PTRIES + char lowercase[256]; + int res = unicode_utf8_tolower(lowercase, sizeof(lowercase), s); + if (res==0) { + trie_node ** ptrie = get_ptrie(lang, UT_SKILLS); + skill_t sk; + int result = ptrie_find(*ptrie, lowercase, &sk, sizeof(sk)); + if (result==0) return sk; + } + return NOSKILL; +#else + struct tnode * tokens = get_translations(lang, UT_SKILLS); + variant token; + + if (findtoken(tokens, s, &token)==E_TOK_NOMATCH) return NOSKILL; + return (skill_t)token.i; +#endif +} + +keyword_t +findkeyword(const char *s, const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_KEYWORDS); + variant token; + + if (*s == '@') s++; + if (findtoken(tokens, s, &token)==E_TOK_NOMATCH) return NOKEYWORD; + if (global.disabled[token.i]) return NOKEYWORD; + return (keyword_t) token.i; +} + +param_t +findparam(const char *s, const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_PARAMS); + variant token; + + if (findtoken(tokens, s, &token)==E_TOK_NOMATCH) { + const building_type * btype = findbuildingtype(s, lang); + if (btype!=NULL) return (param_t) P_GEBAEUDE; + return NOPARAM; + } + if (token.i==P_BUILDING) return P_GEBAEUDE; + return (param_t)token.i; +} + +param_t +getparam (const struct locale * lang) +{ + return findparam (getstrtoken (), lang); +} + +faction * +findfaction (int n) +{ + faction * f = ffindhash(n); + return f; +} + +faction * +getfaction (void) +{ + return findfaction (getid()); +} + +unit * +findunitr (const region * r, int n) +{ + unit *u; + + /* findunit regional! */ + + for (u = r->units; u; u = u->next) + if (u->no == n) + return u; + + return 0; +} + +unit *findunit(int n) +{ + if (n <= 0) { + return NULL; + } + return ufindhash(n); +} + +unit * +findunitg (int n, const region * hint) +{ + + /* Abfangen von Syntaxfehlern. */ + if (n <= 0) + return NULL; + + /* findunit global! */ + hint = 0; + return ufindhash(n); +} + +unit * +getnewunit (const region * r, const faction * f) +{ + int n; + n = getid(); + + return findnewunit (r, f, n); +} + +static int +read_newunitid (const faction * f, const region * r) +{ + int n; + unit *u2; + n = getid(); + if (n == 0) + return -1; + + u2 = findnewunit(r, f, n); + if (u2) return u2->no; + + return -1; +} + +int +read_unitid (const faction * f, const region * r) +{ + const char * s = getstrtoken(); + + /* Da s nun nur einen string enthaelt, suchen wir ihn direkt in der + * paramliste. machen wir das nicht, dann wird getnewunit in s nach der + * nummer suchen, doch dort steht bei temp-units nur "temp" drinnen! */ + + switch (findparam(s, f->locale)) { + case P_TEMP: + return read_newunitid(f, r); + } + if (!s || *s == 0) + return -1; + return atoi36((const char *)s); +} + +/* exported symbol */ +boolean getunitpeasants; +unit * +getunitg(const region * r, const faction * f) +{ + int n = read_unitid(f, r); + + if (n == 0) { + getunitpeasants = 1; + return NULL; + } + getunitpeasants = 0; + if (n < 0) return 0; + + return findunit(n); +} + +unit * +getunit(const region * r, const faction * f) +{ + int n = read_unitid(f, r); + unit *u2; + + if (n == 0) { + getunitpeasants = 1; + return NULL; + } + getunitpeasants = 0; + if (n < 0) return 0; + + u2 = findunit(n); + if (u2!=NULL && u2->region==r) { + /* there used to be a 'u2->flags & UFL_ISNEW || u2->number>0' condition + * here, but it got removed because of a bug that made units disappear: + * http://eressea.upb.de/mantis/bug_view_page.php?bug_id=0000172 + */ + return u2; + } + + return NULL; +} + +/* - String Listen --------------------------------------------- */ +void +addstrlist (strlist ** SP, const char *s) +{ + strlist * slist = malloc(sizeof(strlist)); + slist->next = NULL; + slist->s = strdup(s); + addlist(SP, slist); +} + +void +freestrlist (strlist * s) +{ + strlist *q, *p = s; + while (p) { + q = p->next; + free(p->s); + free(p); + p = q; + } +} + +/* - Meldungen und Fehler ------------------------------------------------- */ + +boolean lomem = false; + +/* - Namen der Strukturen -------------------------------------- */ +typedef char name[OBJECTIDSIZE+1]; +static name idbuf[8]; +static int nextbuf = 0; + +char * +estring_i(char *ibuf) +{ + char *p = ibuf; + + while (*p) { + if (isxspace(*(unsigned*)p) == ' ') { + *p = '~'; + } + ++p; + } + return ibuf; +} + +char * +estring(const char *s) +{ + char *ibuf = idbuf[(++nextbuf) % 8]; + + strlcpy(ibuf, s, sizeof(name)); + return estring_i(ibuf); +} + +char * +cstring_i(char *ibuf) +{ + char *p = ibuf; + + while (*p) { + if (*p == '~') { + *p = ' '; + } + ++p; + } + return ibuf; +} + +char * +cstring(const char *s) +{ + char *ibuf = idbuf[(++nextbuf) % 8]; + + strlcpy(ibuf, s, sizeof(name)); + return cstring_i(ibuf); +} + +building * +largestbuilding(const region * r, cmp_building_cb cmp_gt, boolean imaginary) +{ + building *b, *best = NULL; + + for (b = rbuildings(r); b; b = b->next) { + if (cmp_gt(b, best)<=0) continue; + if (!imaginary) { + const attrib * a = a_find(b->attribs, &at_icastle); + if (a) continue; + } + best = b; + } + return best; +} + +char * +write_unitname(const unit * u, char * buffer, size_t size) +{ + snprintf((char*)buffer, size, "%s (%s)", (const char*)u->name, itoa36(u->no)); + buffer[size-1] = 0; + return buffer; +} + +const char * +unitname(const unit * u) +{ + char *ubuf = idbuf[(++nextbuf) % 8]; + return write_unitname(u, ubuf, sizeof(name)); +} + +/* -- Erschaffung neuer Einheiten ------------------------------ */ + +extern faction * dfindhash(int i); + +static const char* forbidden[] = { "t", "te", "tem", "temp", NULL }; + +int +forbiddenid(int id) +{ + static int * forbid = NULL; + static size_t len; + size_t i; + if (id<=0) return 1; + if (!forbid) { + while (forbidden[len]) ++len; + forbid = calloc(len, sizeof(int)); + for (i=0;i!=len;++i) { + forbid[i] = strtol(forbidden[i], NULL, 36); + } + } + for (i=0;i!=len;++i) if (id==forbid[i]) return 1; + return 0; +} + +/* ID's für Einheiten und Zauber */ +int +newunitid(void) +{ + int random_unit_no; + int start_random_no; + random_unit_no = 1 + (rng_int() % MAX_UNIT_NR); + start_random_no = random_unit_no; + + while (ufindhash(random_unit_no) || dfindhash(random_unit_no) + || cfindhash(random_unit_no) + || forbiddenid(random_unit_no)) + { + random_unit_no++; + if (random_unit_no == MAX_UNIT_NR + 1) { + random_unit_no = 1; + } + if (random_unit_no == start_random_no) { + random_unit_no = (int) MAX_UNIT_NR + 1; + } + } + return random_unit_no; +} + +int +newcontainerid(void) +{ + int random_no; + int start_random_no; + + random_no = 1 + (rng_int() % MAX_CONTAINER_NR); + start_random_no = random_no; + + while (findship(random_no) || findbuilding(random_no)) { + random_no++; + if (random_no == MAX_CONTAINER_NR + 1) { + random_no = 1; + } + if (random_no == start_random_no) { + random_no = (int) MAX_CONTAINER_NR + 1; + } + } + return random_no; +} + +unit * +createunit(region * r, faction * f, int number, const struct race * rc) +{ + assert(rc); + return create_unit(r, f, number, rc, 0, NULL, NULL); +} + +boolean +idle (faction * f) +{ + return (boolean) (f ? false : true); +} + + +int +maxworkingpeasants(const struct region * r) +{ + int i = production(r) * MAXPEASANTS_PER_AREA + - ((rtrees(r,2)+rtrees(r,1)/2) * TREESIZE); + return MAX(i, 0); +} + +int +lighthouse_range(const building * b, const faction * f) +{ + int d = 0; + if (fval(b, BLD_WORKING) && b->size >= 10) { + int maxd = (int)log10(b->size) + 1; + + if (skill_enabled[SK_PERCEPTION]) { + region * r = b->region; + int c = 0; + unit *u; + for (u = r->units; u; u = u->next) { + if (u->building == b) { + c += u->number; + if (c > buildingcapacity(b)) break; + if (f==NULL || u->faction == f) { + int sk = eff_skill(u, SK_PERCEPTION, r) / 3; + d = MAX(d, sk); + d = MIN(maxd, d); + if (d==maxd) break; + } + } else if (c) break; /* first unit that's no longer in the house ends the search */ + } + } else { + /* E3A rule: no perception req'd */ + return maxd; + } + } + return d; +} + +boolean +check_leuchtturm(region * r, faction * f) +{ + attrib * a; + + if (!fval(r->terrain, SEA_REGION)) return false; + + for (a = a_find(r->attribs, &at_lighthouse);a && a->type==&at_lighthouse;a=a->next) { + building *b = (building *)a->data.v; + + assert(b->type == bt_find("lighthouse")); + if (fval(b, BLD_WORKING) && b->size >= 10) { + int maxd = (int)log10(b->size) + 1; + + if (skill_enabled[SK_PERCEPTION]) { + region *r2 = b->region; + unit *u; + int c = 0; + int d = 0; + + for (u = r2->units; u; u = u->next) { + if (u->building == b) { + c += u->number; + if (c > buildingcapacity(b)) break; + if (f==NULL || u->faction == f) { + if (!d) d = distance(r, r2); + if (maxd < d) break; + if (eff_skill(u, SK_PERCEPTION, r) >= d * 3) return true; + } + } else if (c) break; /* first unit that's no longer in the house ends the search */ + } + } else { + /* E3A rule: no perception req'd */ + return maxd; + } + } + } + + return false; +} + +region * +lastregion (faction * f) +{ +#ifdef SMART_INTERVALS + unit * u = f->units; + region *r = f->last; + + if (u==NULL) return NULL; + if (r!=NULL) return r->next; + + /* it is safe to start in the region of the first unit. */ + f->last = u->region; + /* if regions have indices, we can skip ahead: */ + for (u=u->nextF; u!=NULL; u=u->nextF) { + r = u->region; + if (r->index > f->last->index) f->last = r; + } + + /* we continue from the best region and look for travelthru etc. */ + for (r = f->last->next; r; r = r->next) { + plane * p = rplane(r); + + /* search the region for travelthru-attributes: */ + if (fval(r, RF_TRAVELUNIT)) { + attrib * ru = a_find(r->attribs, &at_travelunit); + while (ru && ru->type==&at_travelunit) { + u = (unit*)ru->data.v; + if (u->faction == f) { + f->last = r; + break; + } + ru = ru->next; + } + } + if (f->last == r) continue; + if (check_leuchtturm(r, f)) + f->last = r; + if (p && is_watcher(p, f)) { + f->last = r; + } + } + return f->last->next; +#else + return NULL; +#endif +} + +region * +firstregion (faction * f) +{ +#ifdef SMART_INTERVALS + region *r = f->first; + + if (f->units==NULL) return NULL; + if (r!=NULL) return r; + + return f->first = regions; +#else + return regions; +#endif +} + +void ** blk_list[1024]; +int list_index; +int blk_index; + +static void +gc_done(void) +{ + int i, k; + for (i=0;i!=list_index;++i) + { + for (k=0;k!=1024;++k) free(blk_list[i][k]); + free(blk_list[i]); + } + for (k=0;k!=blk_index;++k) free(blk_list[list_index][k]); + free(blk_list[list_index]); + +} + +void * +gc_add(void * p) +{ + if (blk_index==0) { + blk_list[list_index] = (void**)malloc(1024 * sizeof(void*)); + } + blk_list[list_index][blk_index] = p; + blk_index = (blk_index+1) % 1024; + if (!blk_index) ++ list_index; + return p; +} + +static void +init_directions(tnode * root, const struct locale * lang) +{ + /* mit dieser routine kann man mehrere namen für eine direction geben, + * das ist für die hexes ideal. */ + const struct { + const char* name; + int direction; + } dirs [] = { + { "dir_ne", D_NORTHEAST}, + { "dir_nw", D_NORTHWEST}, + { "dir_se", D_SOUTHEAST}, + { "dir_sw", D_SOUTHWEST}, + { "dir_east", D_EAST}, + { "dir_west", D_WEST}, + { "northeast", D_NORTHEAST}, + { "northwest", D_NORTHWEST}, + { "southeast", D_SOUTHEAST}, + { "southwest", D_SOUTHWEST}, + { "east", D_EAST }, + { "west",D_WEST }, + { "PAUSE", D_PAUSE }, + { NULL, NODIRECTION} + }; + int i; + struct tnode * tokens = get_translations(lang, UT_DIRECTIONS); + + for (i=0; dirs[i].direction!=NODIRECTION;++i) { + variant token; + token.i = dirs[i].direction; + addtoken(tokens, LOC(lang, dirs[i].name), token); + } +} + +direction_t +finddirection(const char *s, const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_DIRECTIONS); + variant token; + + if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { + return (direction_t)token.i; + } + return NODIRECTION; +} + +static void +init_locale(const struct locale * lang) +{ + variant var; + int i; + const struct race * rc; + struct tnode * tokens; + const terrain_type * terrain; +#if PTRIES + trie_node ** ptrie; +#endif + + tokens = get_translations(lang, UT_MAGIC); + if (tokens) { + const char * str = get_param(global.parameters, "rules.magic.playerschools"); + char * sstr, * tok; + if (str==NULL) { + str = "gwyrrd illaun draig cerddor tybied"; + } + + sstr = strdup(str); + tok = strtok(sstr, " "); + while (tok) { + for (i=0;i!=MAXMAGIETYP;++i) { + if (strcmp(tok, magic_school[i])==0) break; + } + assert(i!=MAXMAGIETYP); + var.i = i; + addtoken(tokens, LOC(lang, mkname("school", tok)), var); + tok = strtok(NULL, " "); + } + free(sstr); + } + + tokens = get_translations(lang, UT_DIRECTIONS); + init_directions(tokens, lang); + + tokens = get_translations(lang, UT_RACES); + for (rc=races;rc;rc=rc->next) { + var.v = (void*)rc; + addtoken(tokens, LOC(lang, rc_name(rc, 1)), var); + addtoken(tokens, LOC(lang, rc_name(rc, 0)), var); + } + + tokens = get_translations(lang, UT_PARAMS); + for (i=0;i!=MAXPARAMS;++i) { + var.i = i; + addtoken(tokens, LOC(lang, parameters[i]), var); + } +#if PTRIES + ptrie = get_ptrie(lang, UT_SKILLS); + for (i=0;i!=MAXSKILLS;++i) { + skill_t sk = (skill_t)i; + const char * skname = skillname(sk, lang); + if (skname!=NULL) { + ptrie_insert(ptrie, skname, &sk, sizeof(sk)); + } + } +#else + tokens = get_translations(lang, UT_SKILLS); + for (i=0;i!=MAXSKILLS;++i) { + const char * skname = skillname((skill_t)i, lang); + if (skname!=NULL) { + var.i = i; + addtoken(tokens, skname, var); + } + } +#endif + + tokens = get_translations(lang, UT_KEYWORDS); + for (i=0;i!=MAXKEYWORDS;++i) { + var.i = i; + if (keywords[i]) addtoken(tokens, LOC(lang, keywords[i]), var); + } + + tokens = get_translations(lang, UT_OPTIONS); + for (i=0;i!=MAXOPTIONS;++i) { + var.i = i; + if (options[i]) addtoken(tokens, LOC(lang, options[i]), var); + } + + tokens = get_translations(lang, UT_TERRAINS); + for (terrain=terrains();terrain!=NULL;terrain=terrain->next) { + var.v = (void*)terrain; + addtoken(tokens, LOC(lang, terrain->_name), var); + } +} + +typedef struct param { + struct param * next; + char * name; + char * data; +} param; + +int +getid(void) +{ + const char * str = (const char *)getstrtoken(); + int i = atoi36(str); + if (i<0) { + return -1; + } + return i; +} + +const char * +get_param(const struct param * p, const char * key) +{ + while (p!=NULL) { + if (strcmp(p->name, key)==0) return p->data; + p = p->next; + } + return NULL; +} + +int +get_param_int(const struct param * p, const char * key, int def) +{ + while (p!=NULL) { + if (strcmp(p->name, key)==0) return atoi(p->data); + p = p->next; + } + return def; +} + +static const char * g_datadir; +const char * +datapath(void) +{ + static char zText[MAX_PATH]; + if (g_datadir) return g_datadir; + return strcat(strcpy(zText, basepath()), "/data"); +} + +void +set_datapath(const char * path) +{ + g_datadir = path; +} + + +static const char * g_reportdir; +const char * +reportpath(void) +{ + static char zText[MAX_PATH]; + if (g_reportdir) return g_reportdir; + return strcat(strcpy(zText, basepath()), "/reports"); +} + +void +set_reportpath(const char * path) +{ + g_reportdir = path; +} + +static const char * g_basedir; +const char * +basepath(void) +{ + if (g_basedir) return g_basedir; + return "."; +} + + +void +set_basepath(const char * path) +{ + g_basedir = path; +} + +float +get_param_flt(const struct param * p, const char * key, float def) +{ + while (p!=NULL) { + if (strcmp(p->name, key)==0) return (float)atof(p->data); + p = p->next; + } + return def; +} + +void +set_param(struct param ** p, const char * key, const char * data) +{ + ++global.cookie; + while (*p!=NULL) { + if (strcmp((*p)->name, key)==0) { + free((*p)->data); + (*p)->data = strdup(data); + return; + } + p=&(*p)->next; + } + *p = malloc(sizeof(param)); + (*p)->name = strdup(key); + (*p)->data = strdup(data); + (*p)->next = NULL; +} + +void +kernel_done(void) +{ + /* calling this function releases memory assigned to static variables, etc. + * calling it is optional, e.g. a release server will most likely not do it. + */ + translation_done(); + gc_done(); + sql_done(); +} + +const char * localenames[] = { + "de", "en", + NULL +}; + +void +init_locales(void) +{ + int l; + for (l=0;localenames[l];++l) { + const struct locale * lang = find_locale(localenames[l]); + if (lang) init_locale(lang); + } +} + +/* TODO: soll hier weg */ +extern struct attrib_type at_shiptrail; + +attrib_type at_germs = { + "germs", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + a_writeshorts, + a_readshorts, + ATF_UNIQUE +}; + +/*********************/ +/* at_guard */ +/*********************/ +attrib_type at_guard = { + "guard", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + a_writeint, + a_readint, + ATF_UNIQUE +}; + +void +setstatus(struct unit * u, int status) +{ + assert(status>=ST_AGGRO && status<=ST_FLEE); + if (u->status!=status) { + u->status = (status_t)status; + } +} + +void +setguard(unit * u, unsigned int flags) +{ + /* setzt die guard-flags der Einheit */ + attrib * a = NULL; + assert(flags==0 || !fval(u, UFL_MOVED)); + assert(flags==0 || u->statusattribs, &at_guard); + } + if (flags == GUARD_NONE) { + freset(u, UFL_GUARD); + if (a) a_remove(&u->attribs, a); + return; + } + fset(u, UFL_GUARD); + fset(u->region, RF_GUARDED); + if ((int)flags==guard_flags(u)) { + if (a) a_remove(&u->attribs, a); + } else { + if (!a) a = a_add(&u->attribs, a_new(&at_guard)); + a->data.i = (int)flags; + } +} + +unsigned int +getguard(const unit * u) +{ + attrib * a; + + assert((u->building && fval(u, UFL_OWNER)) || fval(u, UFL_GUARD) || !"you're doing it wrong! check is_guard first"); + a = a_find(u->attribs, &at_guard); + if (a) { + return (unsigned int)a->data.i; + } + return guard_flags(u); +} + +#ifndef HAVE_STRDUP +char * +strdup(const char *s) +{ + return strcpy((char*)malloc(sizeof(char)*(strlen(s)+1)), s); +} +#endif + +void +remove_empty_factions(void) +{ + faction **fp, *f3; + + for (fp = &factions; *fp;) { + faction * f = *fp; + /* monster (0) werden nicht entfernt. alive kann beim readgame + * () auf 0 gesetzt werden, wenn monsters keine einheiten mehr + * haben. */ + if ((f->units==NULL || f->alive == 0) && !is_monsters(f)) { + ursprung * ur = f->ursprung; + while (ur && ur->id!=0) ur=ur->next; + if (verbosity>=2) log_stdio(stdout, "\t%s\n", factionname(f)); + + /* Einfach in eine Datei schreiben und später vermailen */ + + if (updatelog) fprintf(updatelog, "dropout %s\n", itoa36(f->no)); + + for (f3 = factions; f3; f3 = f3->next) { + ally * sf; + group * g; + ally ** sfp = &f3->allies; + while (*sfp) { + sf = *sfp; + if (sf->faction == f || sf->faction == NULL) { + *sfp = sf->next; + free(sf); + } + else sfp = &(*sfp)->next; + } + for (g = f3->groups; g; g=g->next) { + sfp = &g->allies; + while (*sfp) { + sf = *sfp; + if (sf->faction == f || sf->faction == NULL) { + *sfp = sf->next; + free(sf); + } + else sfp = &(*sfp)->next; + } + } + } + if (f->subscription) { + sql_print(("UPDATE subscriptions set status='DEAD' where id=%u;\n", + f->subscription)); + } + + *fp = f->next; + funhash(f); + free_faction(f); + free(f); + } + else fp = &(*fp)->next; + } +} + +void +remove_empty_units_in_region(region *r) +{ + unit **up = &r->units; + + while (*up) { + unit * u = *up; + + if (u->number) { + faction * f = u->faction; + if (f==NULL || !f->alive) { + set_number(u, 0); + } + if (MaxAge()>0) { + if ((!fval(f, FFL_NOTIMEOUT) && f->age > MaxAge())) { + set_number(u, 0); + } + } + } + if ((u->number == 0 && u->race != new_race[RC_SPELL]) || (u->age <= 0 && u->race == new_race[RC_SPELL])) { + remove_unit(up, u); + } + if (*up==u) up=&u->next; + } +} + +void +remove_empty_units(void) +{ + region *r; + + for (r = regions; r; r = r->next) { + remove_empty_units_in_region(r); + } +} + +boolean +faction_id_is_unused(int id) +{ + return findfaction(id)==NULL; +} + +int +weight(const unit * u) +{ + int w, n = 0, in_bag = 0; + + item * itm; + for (itm=u->items;itm;itm=itm->next) { + w = itm->type->weight * itm->number; + n += w; + if( !fval(itm->type, ITF_BIG)) + in_bag += w; + } + + n += u->number * u->race->weight; + + w = get_item(u, I_BAG_OF_HOLDING) * BAGCAPACITY; + if( w > in_bag ) + w = in_bag; + n -= w; + + return n; +} + +void +make_undead_unit(unit * u) +{ + free_orders(&u->orders); + name_unit(u); + fset(u, UFL_ISNEW); +} + +unsigned int guard_flags(const unit * u) +{ + unsigned int flags = GUARD_CREWS | GUARD_LANDING | GUARD_TRAVELTHRU | GUARD_TAX; +#if GUARD_DISABLES_PRODUCTION == 1 + flags |= GUARD_PRODUCE; +#endif +#if GUARD_DISABLES_RECRUIT == 1 + flags |= GUARD_RECRUIT; +#endif + switch (old_race(u->race)) { + case RC_ELF: + if (u->faction->race != u->race) break; + /* else fallthrough */ + case RC_TREEMAN: + flags |= GUARD_TREES; + break; + case RC_IRONKEEPER: + flags = GUARD_MINING; + break; + } + return flags; +} + +void +guard(unit * u, unsigned int mask) +{ + unsigned int flags = guard_flags(u); + setguard(u, flags & mask); +} + +int +besieged(const unit * u) +{ + /* belagert kann man in schiffen und burgen werden */ + return (u && !global.disabled[K_BESIEGE] + && u->building && u->building->besieged + && u->building->besieged >= u->building->size * SIEGEFACTOR); +} + +int +lifestyle(const unit * u) +{ + int need; + plane * pl; + static int gamecookie = -1; + if (gamecookie!=global.cookie) { + gamecookie = global.cookie; + } + + if (is_monsters(u->faction)) return 0; + + need = maintenance_cost(u); + + pl = rplane(u->region); + if (pl && fval(pl, PFL_NOFEED)) + return 0; + + return need; +} + +boolean has_horses(const struct unit * u) +{ + item * itm = u->items; + for (;itm;itm=itm->next) { + if (itm->type->flags&ITF_ANIMAL) return true; + } + return false; +} + +boolean +hunger(int number, unit * u) +{ + region * r = u->region; + int dead = 0, hpsub = 0; + int hp = u->hp / u->number; + static const char * damage = 0; + static const char * rcdamage = 0; + static const race * rc = 0; + + if (!damage) { + damage = get_param(global.parameters, "hunger.damage"); + if (damage==NULL) damage = "1d12+12"; + } + if (rc!=u->race) { + rcdamage = get_param(u->race->parameters, "hunger.damage"); + rc = u->race; + } + + while (number--) { + int dam = dice_rand(rcdamage?rcdamage:damage); + if (dam >= hp) { + ++dead; + } else { + hpsub += dam; + } + } + + if (dead) { + /* Gestorbene aus der Einheit nehmen, + * Sie bekommen keine Beerdingung. */ + ADDMSG(&u->faction->msgs, msg_message("starvation", + "unit region dead live", u, r, dead, u->number-dead)); + + scale_number(u, u->number - dead); + deathcounts(r, dead); + } + if (hpsub > 0) { + /* Jetzt die Schäden der nicht gestorbenen abziehen. */ + u->hp -= hpsub; + /* Meldung nur, wenn noch keine für Tote generiert. */ + if (dead == 0) { + /* Durch unzureichende Ernährung wird %s geschwächt */ + ADDMSG(&u->faction->msgs, msg_message("malnourish", + "unit region", u, r)); + } + } + return (dead || hpsub); +} + +void +plagues(region * r, boolean ismagic) +{ + int peasants; + int i; + int dead = 0; + + /* Seuchenwahrscheinlichkeit in % */ + + if (!ismagic) { + double mwp = MAX(maxworkingpeasants(r), 1); + double prob = pow(rpeasants(r) / (mwp * wage(r, NULL, NULL, turn) * 0.13), 4.0) + * PLAGUE_CHANCE; + + if (rng_double() >= prob) return; + } + + peasants = rpeasants(r); + dead = (int)(0.5F + PLAGUE_VICTIMS * peasants); + for (i = dead; i != 0; i--) { + if (rng_double() < PLAGUE_HEALCHANCE && rmoney(r) >= PLAGUE_HEALCOST) { + rsetmoney(r, rmoney(r) - PLAGUE_HEALCOST); + } else { + --dead; + } + } + + if (dead > 0) { + message * msg = add_message(&r->msgs, msg_message("pest", "dead", dead)); + msg_release(msg); + deathcounts(r, dead); + rsetpeasants(r, peasants - dead); + } +} + +/* Lohn bei den einzelnen Burgstufen für Normale Typen, Orks, Bauern, + * Modifikation für Städter. */ + +static const int wagetable[7][4] = { + {10, 10, 11, -7}, /* Baustelle */ + {10, 10, 11, -5}, /* Handelsposten */ + {11, 11, 12, -3}, /* Befestigung */ + {12, 11, 13, -1}, /* Turm */ + {13, 12, 14, 0}, /* Burg */ + {14, 12, 15, 1}, /* Festung */ + {15, 13, 16, 2} /* Zitadelle */ +}; + +int +cmp_wage(const struct building * b, const building * a) +{ + static const struct building_type * bt_castle; + if (!bt_castle) bt_castle = bt_find("castle"); + if (b->type==bt_castle) { + if (!a) return 1; + if (b->size>a->size) return 1; + if (b->size==a->size) return 0; + } + return -1; +} + +boolean is_owner_building(const struct building * b) +{ + region * r = b->region; + if (b->type->taxes && r->land && r->land->ownership) { + unit * u = building_owner(b); + return u && u->faction == r->land->ownership->owner; + } + return false; +} + +int +cmp_taxes(const building * b, const building * a) +{ + faction * f = region_get_owner(b->region); + if (b->type->taxes) { + unit * u = building_owner(b); + if (!u) { + return -1; + } else if (a) { + int newsize = buildingeffsize(b, false); + double newtaxes = b->type->taxes(b, newsize); + int oldsize = buildingeffsize(a, false); + double oldtaxes = a->type->taxes(a, oldsize); + + if (newtaxesoldtaxes) return 1; + else if (b->sizesize) return -1; + else if (b->size>a->size) return 1; + else { + if (u && u->faction==f) { + u = building_owner(a); + if (u && u->faction==f) return -1; + return 1; + } + } + } else { + return 1; + } + } + return -1; +} + +int +cmp_current_owner(const building * b, const building * a) +{ + faction * f = region_get_owner(b->region); + + assert(rule_region_owners()); + if (f && b->type->taxes) { + unit * u = building_owner(b); + if (!u || u->faction!=f) return -1; + if (a) { + int newsize = buildingeffsize(b, false); + double newtaxes = b->type->taxes(b, newsize); + int oldsize = buildingeffsize(a, false); + double oldtaxes = a->type->taxes(a, oldsize); + + if (newtaxes!=oldtaxes) return (newtaxes>oldtaxes)?1:-1; + if (newsize!=oldsize) return newsize-oldsize; + return (b->size-a->size); + } else { + return 1; + } + } + return -1; +} + +int rule_stealth_faction(void) +{ + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + rule = get_param_int(global.parameters, "rules.stealth.faction", 1); + gamecookie = global.cookie; + assert(rule>=0); + } + return rule; +} + +int rule_region_owners(void) +{ + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + rule = get_param_int(global.parameters, "rules.region_owners", 0); + gamecookie = global.cookie; + assert(rule>=0); + } + return rule; +} + +int rule_auto_taxation(void) +{ + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + rule = get_param_int(global.parameters, "rules.economy.taxation", TAX_ORDER); + gamecookie = global.cookie; + assert(rule>=0); + } + return rule; +} + +int rule_blessed_harvest(void) +{ + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + rule = get_param_int(global.parameters, "rules.magic.blessed_harvest", HARVEST_WORK); + gamecookie = global.cookie; + assert(rule>=0); + } + return rule; +} + +int rule_alliance_limit(void) +{ + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + rule = get_param_int(global.parameters, "rules.limit.alliance", 0); + gamecookie = global.cookie; + assert(rule>=0); + } + return rule; +} + +int rule_faction_limit(void) +{ + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + rule = get_param_int(global.parameters, "rules.limit.faction", 0); + gamecookie = global.cookie; + assert(rule>=0); + } + return rule; +} + +int rule_transfermen(void) +{ + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + rule = get_param_int(global.parameters, "rules.transfermen", 1); + gamecookie = global.cookie; + assert(rule>=0); + } + return rule; +} + +static int +default_wage(const region *r, const faction * f, const race * rc, int in_turn) +{ + building *b = largestbuilding(r, &cmp_wage, false); + int esize = 0; + curse * c; + double wage; + attrib *a; + const building_type *artsculpture_type = bt_find("artsculpture"); + static const curse_type * drought_ct, * blessedharvest_ct; + static boolean init; + + if (!init) { + init = true; + drought_ct = ct_find("drought"); + blessedharvest_ct = ct_find("blessedharvest"); + } + + if (b!=NULL) { + /* TODO: this reveals imaginary castles */ + esize = buildingeffsize(b, false); + } + + if (f!=NULL) { + int index = 0; + if (rc==new_race[RC_ORC] || rc==new_race[RC_SNOTLING]) { + index = 1; + } + wage = wagetable[esize][index]; + } else { + if (is_mourning(r, in_turn)) { + wage = 10; + } else if (fval(r->terrain, SEA_REGION)) { + wage = 11; + } else if (fval(r, RF_ORCIFIED)) { + wage = wagetable[esize][1]; + } else { + wage = wagetable[esize][2]; + } + if (rule_blessed_harvest()==HARVEST_WORK) { + /* E1 rules */ + wage += curse_geteffect(get_curse(r->attribs, blessedharvest_ct)); + } + } + + /* Artsculpture: Income +5 */ + for(b=r->buildings; b; b=b->next) { + if(b->type == artsculpture_type) { + wage += 5; + } + } + + /* Godcurse: Income -10 */ + if (curse_active(get_curse(r->attribs, ct_find("godcursezone")))) { + wage = MAX(0,wage-10); + } + + /* Bei einer Dürre verdient man nur noch ein Viertel */ + if (drought_ct) { + c = get_curse(r->attribs, drought_ct); + if (curse_active(c)) wage /= curse_geteffect(c); + } + + a = a_find(r->attribs, &at_reduceproduction); + if (a) wage = (wage * a->data.sa[0])/100; + + return (int)wage; +} + +static int +minimum_wage(const region *r, const faction * f, const race * rc, int in_turn) +{ + if (f && rc) { + return rc->maintenance; + } + return default_wage(r, f, rc, in_turn); +} + +/* Gibt Arbeitslohn für entsprechende Rasse zurück, oder für +* die Bauern wenn f == NULL. */ +int +wage(const region *r, const faction * f, const race * rc, int in_turn) +{ + if (global.functions.wage) { + return global.functions.wage(r, f, rc, in_turn); + } + return default_wage(r, f, rc, in_turn); +} + + +#define MAINTENANCE 10 +int +maintenance_cost(const struct unit * u) +{ + if (u==NULL) return MAINTENANCE; + if (global.functions.maintenance) { + int retval = global.functions.maintenance(u); + if (retval>=0) return retval; + } + return u->race->maintenance * u->number; +} + +message * +movement_error(unit * u, const char * token, order * ord, int error_code) +{ + direction_t d; + switch (error_code) { + case E_MOVE_BLOCKED: + d = finddirection(token, u->faction->locale); + return msg_message("moveblocked", "unit direction", u, d); + case E_MOVE_NOREGION: + return msg_feedback(u, ord, "unknowndirection", "dirname", token); + } + return NULL; +} + +int +movewhere(const unit *u, const char * token, region * r, region** resultp) +{ + region * r2; + direction_t d; + + if (*token == '\0') { + *resultp = NULL; + return E_MOVE_OK; + } + + d = finddirection(token, u->faction->locale); + switch (d) { + case D_PAUSE: + *resultp = r; + break; + + case NODIRECTION: + r2 = find_special_direction(r, token, u->faction->locale); + if (r2==NULL) { + return E_MOVE_NOREGION; + } + *resultp = r2; + break; + + default: + r2 = rconnect(r, d); + if (r2==NULL || move_blocked(u, r, r2)) { + return E_MOVE_BLOCKED; + } + *resultp = r2; + } + return E_MOVE_OK; +} + +boolean +move_blocked(const unit * u, const region *r, const region *r2) +{ + connection * b; + curse * c; + static const curse_type * fogtrap_ct = NULL; + + if (r2==NULL) return true; + b = get_borders(r, r2); + while (b) { + if (b->type->block && b->type->block(b, u, r)) return true; + b = b->next; + } + + if (fogtrap_ct==NULL) fogtrap_ct = ct_find("fogtrap"); + c = get_curse(r->attribs, fogtrap_ct); + if (curse_active(c)) return true; + return false; +} + +void +add_income(unit * u, int type, int want, int qty) +{ + if (want==INT_MAX) want = qty; + ADDMSG(&u->faction->msgs, msg_message("income", "unit region mode wanted amount", + u, u->region, type, want, qty)); +} + +void +reorder_units(region * r) +{ + unit ** unext = &r->units; + + if (r->buildings) { + building * b = r->buildings; + while (*unext && b) { + unit ** ufirst = unext; /* where the first unit in the building should go */ + unit ** umove = unext; /* a unit we consider moving */ + unit * owner = NULL; + while (*umove) { + unit * u = *umove; + if (u->number && u->building==b) { + unit ** uinsert = unext; + if (fval(u, UFL_OWNER)) { + uinsert = ufirst; + owner = u; + } + if (umove!=uinsert) { + *umove = u->next; + u->next = *uinsert; + *uinsert = u; + } else { + /* no need to move, skip ahead */ + umove = &u->next; + } + if (unext==uinsert) { + /* we have a new well-placed unit. jump over it */ + unext = &u->next; + } + } else { + umove = &u->next; + } + } + if (!owner && ufirst!=unext) { + owner = *ufirst; + fset(owner, UFL_OWNER); + } + b = b->next; + } + } + + if (r->ships) { + ship * sh = r->ships; + /* first, move all units up that are not on ships */ + unit ** umove = unext; /* a unit we consider moving */ + while (*umove) { + unit * u = *umove; + if (u->number && !u->ship) { + if (umove!=unext) { + *umove = u->next; + u->next = *unext; + *unext = u; + } else { + /* no need to move, skip ahead */ + umove = &u->next; + } + /* we have a new well-placed unit. jump over it */ + unext = &u->next; + } else { + umove = &u->next; + } + } + + while (*unext && sh) { + unit ** ufirst = unext; /* where the first unit in the building should go */ + unit ** umove = unext; /* a unit we consider moving */ + unit * owner = NULL; + while (*umove) { + unit * u = *umove; + if (u->number && u->ship==sh) { + unit ** uinsert = unext; + if (fval(u, UFL_OWNER)) { + uinsert = ufirst; + owner = u; + } + if (umove!=uinsert) { + *umove = u->next; + u->next = *uinsert; + *uinsert = u; + } else { + /* no need to move, skip ahead */ + umove = &u->next; + } + if (unext==uinsert) { + /* we have a new well-placed unit. jump over it */ + unext = &u->next; + } + } else { + umove = &u->next; + } + } + if (!owner && ufirst!=unext) { + owner = *ufirst; + fset(owner, UFL_OWNER); + } + sh = sh->next; + } + } +} + +int +produceexp(struct unit * u, skill_t sk, int n) +{ + if (global.producexpchance>0.0F) { + if (n==0 || !playerrace(u->race)) return 0; + learn_skill(u, sk, global.producexpchance); + } + return 0; +} + +int +lovar(double xpct_x2) +{ + int n = (int)(xpct_x2 * 500)+1; + if (n==0) return 0; + return (rng_int() % n + rng_int() % n)/1000; +} + +boolean +has_limited_skills (const struct unit * u) +{ + if (has_skill(u, SK_MAGIC) || has_skill(u, SK_ALCHEMY) || + has_skill(u, SK_TACTICS) || has_skill(u, SK_HERBALISM) || + has_skill(u, SK_SPY)) { + return true; + } else { + return false; + } +} + +void +attrib_init(void) +{ + /* Alle speicherbaren Attribute müssen hier registriert werden */ + at_register(&at_shiptrail); + at_register(&at_familiar); + at_register(&at_familiarmage); + at_register(&at_clone); + at_register(&at_clonemage); + at_register(&at_eventhandler); + at_register(&at_stealth); + at_register(&at_mage); + at_register(&at_countdown); + at_register(&at_curse); + + at_register(&at_seenspell); + + /* neue REGION-Attribute */ + at_register(&at_direction); + at_register(&at_moveblock); + at_register(&at_deathcount); + at_register(&at_chaoscount); + at_register(&at_woodcount); + + /* neue UNIT-Attribute */ + at_register(&at_siege); + at_register(&at_effect); + at_register(&at_private); + + at_register(&at_icastle); + at_register(&at_guard); + at_register(&at_group); + + at_register(&at_building_generic_type); + at_register(&at_maxmagicians); + at_register(&at_npcfaction); + + /* connection-typen */ + register_bordertype(&bt_noway); + register_bordertype(&bt_fogwall); + register_bordertype(&bt_wall); + register_bordertype(&bt_illusionwall); + register_bordertype(&bt_road); + register_bordertype(&bt_questportal); + + register_function((pf_generic)&minimum_wage, "minimum_wage"); + + at_register(&at_germs); +#if XECMD_MODULE + at_register(&at_xontormiaexpress); /* required for old datafiles */ +#endif + at_register(&at_speedup); + at_register(&at_building_action); +} + +void +kernel_init(void) +{ + char zBuffer[MAX_PATH]; + attrib_init(); + translation_init(); + + if (sqlpatch) { + sprintf(zBuffer, "%s/patch-%d.sql", datapath(), turn); + sql_init(zBuffer); + } +} + +order * +default_order(const struct locale * lang) +{ + return parse_order(locale_string(lang, "defaultorder"), lang); +} + +int +entertainmoney(const region *r) +{ + double n; + + if (is_cursed(r->attribs, C_DEPRESSION, 0)) { + return 0; + } + + n = rmoney(r) / ENTERTAINFRACTION; + + if (is_cursed(r->attribs, C_GENEROUS, 0)) { + n *= get_curseeffect(r->attribs, C_GENEROUS, 0); + } + + return (int)n; +} + +int rule_give(void) +{ + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "rules.give", GIVE_DEFAULT); + } + return value; +} + +int markets_module(void) +{ + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "modules.markets", 0); + } + return value; +} + +/** releases all memory associated with the game state. + * call this function before calling read_game() to load a new game + * if you have a previously loaded state in memory. + */ +void +free_gamedata(void) +{ + free_units(); + free_regions(); + free_borders(); + + while (alliances) { + alliance * al = alliances; + alliances = al->next; + free_alliance(al); + } + while (factions) { + faction * f = factions; + factions = f->next; + funhash(f); + free_faction(f); + free(f); + } + + while (planes) { + plane * pl = planes; + planes = planes->next; + free(pl->name); + free(pl); + } + + while (global.attribs) { + a_remove(&global.attribs, global.attribs); + } + ++global.cookie; /* readgame() already does this, but sjust in case */ +} + + +void +load_inifile(dictionary * d) +{ + const char * reportdir = reportpath(); + const char * datadir = datapath(); + const char * basedir = basepath(); + const char * str; + + assert(d); + + str = iniparser_getstring(d, "eressea:base", basedir); + if (str!=basedir) set_basepath(str); + str = iniparser_getstring(d, "eressea:report", reportdir); + if (str!=reportdir) set_reportpath(str); + str = iniparser_getstring(d, "eressea:data", datadir); + if (str!=datadir) set_datapath(str); + + lomem = iniparser_getint(d, "eressea:lomem", lomem)?1:0; + + str = iniparser_getstring(d, "eressea:encoding", NULL); + if (str) enc_gamedata = xmlParseCharEncoding(str); + + verbosity = iniparser_getint(d, "eressea:verbose", 2); + sqlpatch = iniparser_getint(d, "eressea:sqlpatch", false); + battledebug = iniparser_getint(d, "eressea:debug", battledebug)?1:0; + + str = iniparser_getstring(d, "eressea:locales", "de,en"); + make_locales(str); + + /* excerpt from [config] (the rest is used in bindings.c) */ + game_name = iniparser_getstring(d, "config:game", game_name); + + global.inifile = d; +} diff --git a/src/kernel/config.h b/src/kernel/config.h new file mode 100644 index 000000000..22544a78b --- /dev/null +++ b/src/kernel/config.h @@ -0,0 +1,460 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef ERESSEA_H +#define ERESSEA_H + +#ifdef __cplusplus +extern "C" { +#endif + + /* this should always be the first thing included after platform.h */ +#include "types.h" + +struct _dictionary_; + + /* experimental gameplay features (that don't affect the savefile) */ + /* TODO: move these settings to settings.h or into configuration files */ +#define GOBLINKILL /* Goblin-Spezialklau kann tödlich enden */ +#define HERBS_ROT /* herbs owned by units have a chance to rot. */ +#define SHIPDAMAGE /* Schiffsbeschädigungen */ +#define INSECT_POTION /* Spezialtrank für Insekten */ +#define ORCIFICATION /* giving snotlings to the peasants gets counted */ +#undef TROLLSAVE /* saving throw for dead trolls */ + +#define ALLIED(f1, f2) (f1==f2 || (f1->alliance && f1->alliance==f2->alliance)) + +/* for some good prime numbers, check http://www.math.niu.edu/~rusin/known-math/98/pi_x */ +#ifndef MAXREGIONS +# define MAXREGIONS 524287 /* must be prime for hashing. 262139 was a little small */ +#endif +#ifndef MAXUNITS +# define MAXUNITS 1048573 /* must be prime for hashing. 524287 was >90% full */ +#endif + +#define MAXPEASANTS_PER_AREA 10 /* number of peasants per region-size */ +#define TREESIZE (MAXPEASANTS_PER_AREA-2) /* space used by trees (in #peasants) */ + +#define PEASANTFORCE 0.75 /* Chance einer Vermehrung trotz 90% Auslastung */ +#define HERBROTCHANCE 5 /* Verrottchance für Kräuter (ifdef HERBS_ROT) */ + +/* Gebäudegröße = Minimalbelagerer */ +#define SIEGEFACTOR 2 + +/** Magic */ +#define MAXMAGICIANS 3 +#define MAXALCHEMISTS 3 + +/** Plagues **/ +#define PLAGUE_CHANCE 0.1F /* Seuchenwahrscheinlichkeit (siehe plagues()) */ +#define PLAGUE_VICTIMS 0.2F /* % Betroffene */ +#define PLAGUE_HEALCHANCE 0.25F /* Wahrscheinlichkeit Heilung */ +#define PLAGUE_HEALCOST 30 /* Heilkosten */ + +/* Chance of a monster attack */ +#define MONSTERATTACK 0.4F + +/** Chance of an unmaintained building crashing */ +/* #define COLLAPSE_CHANCE 0.4F */ +#undef COLLAPSE_CHANCE +/** chance to survive the crash of a building */ +/* #define COLLAPSE_SURVIVAL 0.5F */ +#undef COLLAPSE_SURVIVAL + +/* 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 + +#define PERSON_WEIGHT 1000 /* weight of a "normal" human unit */ +#define STAMINA_AFFECTS_HP 1<<0 + +/** + * Hier endet der Teil von config.h, der die defines für die + * Spielwelt Eressea enthält, und beginnen die allgemeinen Routinen + */ + +#define ENCCHANCE 10 /* %-Chance für einmalige Zufallsbegegnung */ + +#define DISPLAYSIZE 8191 /* max. Länge einer Beschreibung, ohne trailing 0 */ +#define NAMESIZE 127 /* max. Länge eines Namens, ohne trailing 0 */ +#define IDSIZE 15 /* max. Länge einer no (als String), ohne trailing 0 */ +#define KEYWORDSIZE 15 /* max. Länge eines Keyword, ohne trailing 0 */ +#define OBJECTIDSIZE (NAMESIZE+5+IDSIZE) /* max. Länge der Strings, die + * von struct unitname, etc. zurückgegeben werden. ohne die 0 */ + +#define BAGCAPACITY 20000 /* soviel paßt in einen Bag of Holding */ +#define STRENGTHCAPACITY 50000 /* zusätzliche Tragkraft beim Kraftzauber (deprecated) */ +#define STRENGTHMULTIPLIER 50 /* multiplier for trollbelt */ + +/* ----------------- Befehle ----------------------------------- */ + +extern const char *keywords[MAXKEYWORDS]; +extern const char *parameters[MAXPARAMS]; + +/** report options **/ +#define want(option) (1<flags & (i)) +#define fset(u, i) ((u)->flags |= (i)) +#define freset(u, i) ((u)->flags &= ~(i)) + +extern int turn; +extern int verbosity; + +/* parteinummern */ +extern boolean faction_id_is_unused(int); + +/* leuchtturm */ +extern boolean check_leuchtturm(struct region * r, struct faction * f); +extern void update_lighthouse(struct building * lh); +extern int lighthouse_range(const struct building * b, const struct faction * f); + +/* skills */ +extern int skill_limit(struct faction * f, skill_t sk); +extern int count_skill(struct faction * f, skill_t sk); + +/* direction, geography */ +extern const char *directions[]; +extern direction_t finddirection(const char *s, const struct locale *); + +extern int findoption(const char *s, const struct locale * lang); + +/* special units */ +void make_undead_unit(struct unit *); + +void addstrlist(strlist ** SP, const char *s); + +int armedmen(const struct unit * u, boolean siege_weapons); + +unsigned int atoip(const char *s); +unsigned int getuint(void); +int getint(void); + +extern const char *igetstrtoken(const char *s); + +extern void init_tokens(const struct order * ord); /* initialize token parsing */ +extern skill_t findskill(const char *s, const struct locale * lang); + +extern keyword_t findkeyword(const char *s, const struct locale * lang); + +extern param_t findparam(const char *s, const struct locale * lang); +extern param_t getparam(const struct locale * lang); + +extern int getid(void); +#define unitid(x) itoa36((x)->no) + +#define getshipid() getid() +#define getfactionid() getid() + +#define buildingid(x) itoa36((x)->no) +#define shipid(x) itoa36((x)->no) +#define factionid(x) itoa36((x)->no) +#define curseid(x) itoa36((x)->no) + +extern boolean cansee(const struct faction * f, const struct region * r, const struct unit * u, int modifier); +boolean cansee_durchgezogen(const struct faction * f, const struct region * r, const struct unit * u, int modifier); +extern boolean cansee_unit(const struct unit * u, const struct unit * target, int modifier); +boolean seefaction(const struct faction * f, const struct region * r, const struct unit * u, int modifier); +extern int effskill(const struct unit * u, skill_t sk); + +extern int lovar(double xpct_x2); + /* returns a value between [0..xpct_2], generated with two dice */ + +int distribute(int old, int new_value, int n); + +int newunitid(void); +int forbiddenid(int id); +int newcontainerid(void); + +extern struct unit *createunit(struct region * r, struct faction * f, int number, const struct race * rc); +extern void create_unitid(struct unit *u, int id); +extern boolean getunitpeasants; +extern struct unit *getunitg(const struct region * r, const struct faction * f); +extern struct unit *getunit(const struct region * r, const struct faction * f); + +extern int read_unitid(const struct faction * f, const struct region * r); + +extern int alliedunit(const struct unit * u, const struct faction * f2, int mode); +extern int alliedfaction(const struct plane * pl, const struct faction * f, + const struct faction * f2, int mode); +extern int alliedgroup(const struct plane * pl, const struct faction * f, + const struct faction * f2, const struct ally * sf, + int mode); + +struct faction *findfaction(int n); +struct faction *getfaction(void); + +struct unit *findunitg(int n, const struct region * hint); +struct unit *findunit(int n); + +struct unit *findunitr(const struct region * r, int n); +struct region *findunitregion(const struct unit * su); + +extern char *estring(const char *s); +extern char *estring_i(char *s); +extern char *cstring(const char *s); +extern char *cstring_i(char *s); +extern const char *unitname(const struct unit * u); +extern char * write_unitname(const struct unit * u, char * buffer, size_t size); + +typedef int (*cmp_building_cb)(const struct building * b, const struct building * a); +struct building *largestbuilding(const struct region * r, cmp_building_cb, boolean imaginary); +int cmp_wage(const struct building * b, const struct building * bother); +int cmp_taxes(const struct building * b, const struct building * bother); +int cmp_current_owner(const struct building * b, const struct building * bother); + +#define TAX_ORDER 0x00 +#define TAX_OWNER 0x01 +int rule_auto_taxation(void); +int rule_transfermen(void); +int rule_region_owners(void); +int rule_stealth_faction(void); +#define HARVEST_WORK 0x00 +#define HARVEST_TAXES 0x01 +int rule_blessed_harvest(void); +extern int rule_give(void); +extern int rule_alliance_limit(void); +extern int rule_faction_limit(void); + +extern int count_all(const struct faction * f); +extern int count_migrants (const struct faction * f); +extern int count_maxmigrants(const struct faction * f); + +extern boolean has_limited_skills(const struct unit * u); +extern const struct race * findrace(const char *, const struct locale *); + +int eff_stealth(const struct unit * u, const struct region * r); +int ispresent(const struct faction * f, const struct region * r); + +int check_option(struct faction * f, int option); +extern void parse(keyword_t kword, int (*dofun)(struct unit *, struct order *), boolean thisorder); + +/* Anzahl Personen in einer Einheit festlegen. NUR (!) mit dieser Routine, + * sonst großes Unglück. Durch asserts an ein paar Stellen abgesichert. */ +void verify_data(void); + +void freestrlist(strlist * s); + +int change_hitpoints(struct unit *u, int value); + +int weight(const struct unit * u); +void changeblockchaos(void); + +/* intervall, in dem die regionen der partei zu finden sind */ +extern struct region *firstregion(struct faction * f); +extern struct region *lastregion(struct faction * f); + +void fhash(struct faction * f); +void funhash(struct faction * f); + +boolean idle(struct faction * f); +boolean unit_has_cursed_item(struct unit *u); + +/* simple garbage collection: */ +void * gc_add(void * p); + +/* grammatik-flags: */ +#define GF_NONE 0 + /* singular, ohne was dran */ +#define GF_PLURAL 1 + /* Angaben in Mehrzahl */ +#define GF_ARTICLE 8 + /* der, die, eine */ +#define GF_SPECIFIC 16 + /* der, die, das vs. ein, eine */ +#define GF_DETAILED 32 + /* mehr Informationen. z.b. straße zu 50% */ +#define GF_PURE 64 + /* untranslated */ + +#define GUARD_NONE 0 +#define GUARD_TAX 1 + /* Verhindert Steuereintreiben */ +#define GUARD_MINING 2 + /* Verhindert Bergbau */ +#define GUARD_TREES 4 + /* Verhindert Waldarbeiten */ +#define GUARD_TRAVELTHRU 8 + /* Blockiert Durchreisende */ +#define GUARD_LANDING 16 + /* Verhindert Ausstieg + Weiterreise */ +#define GUARD_CREWS 32 + /* Verhindert Unterhaltung auf Schiffen */ +#define GUARD_RECRUIT 64 + /* Verhindert Rekrutieren */ +#define GUARD_PRODUCE 128 + /* Verhindert Abbau von Resourcen mit RTF_LIMITED */ +#define GUARD_ALL 0xFFFF + +extern void setstatus(struct unit * u, int status); +/* !< sets combatstatus of a unit */ +extern void setguard(struct unit * u, unsigned int flags); +/* !< setzt die guard-flags der Einheit */ +extern unsigned int getguard(const struct unit * u); + /* liest die guard-flags der Einheit */ +extern void guard(struct unit * u, unsigned int mask); + /* Einheit setzt "BEWACHE", rassenspezifzisch. + * 'mask' kann einzelne flags zusätzlich und-maskieren. + */ +unsigned int guard_flags(const struct unit * u); + +extern boolean hunger(int number, struct unit * u); +extern int lifestyle(const struct unit*); +extern int besieged(const struct unit * u); +extern int maxworkingpeasants(const struct region * r); +extern boolean has_horses(const struct unit * u); +extern int markets_module(void); +extern int wage(const struct region *r, const struct faction *f, const struct race * rc, int in_turn); +extern int maintenance_cost(const struct unit * u); +extern struct message * movement_error(struct unit * u, const char * token, struct order * ord, int error_code); +extern boolean move_blocked(const struct unit * u, const struct region *src, const struct region *dest); +extern void add_income(struct unit * u, int type, int want, int qty); + +/* movewhere error codes */ +enum { + E_MOVE_OK = 0, /* possible to move */ + E_MOVE_NOREGION, /* no region exists in this direction */ + E_MOVE_BLOCKED /* cannot see this region, there is a blocking connection. */ +}; +extern int movewhere(const struct unit *u, const char * token, struct region * r, struct region** resultp); + +extern const char * datapath(void); +extern void set_datapath(const char * path); + +extern const char * basepath(void); +extern void set_basepath(const char *); +void load_inifile(struct _dictionary_ * d); + +extern const char * reportpath(void); +extern void set_reportpath(const char *); + +extern void kernel_init(void); +extern void kernel_done(void); + +extern void reorder_units(struct region * r); + +extern const char *localenames[]; + +/** compatibility: **/ +extern race_t old_race(const struct race *); +extern const struct race * new_race[]; + +/* globale settings des Spieles */ +typedef struct settings { + const char *gamename; + struct attrib *attribs; + unsigned int data_turn; + boolean disabled[MAXKEYWORDS]; + struct param * parameters; + void * vm_state; + float producexpchance; + int cookie; + struct _dictionary_ * inifile; + + struct global_functions { + int (*wage)(const struct region *r, const struct faction * f, const struct race * rc, int in_turn); + int (*maintenance)(const struct unit * u); + } functions; +} settings; +extern settings global; + +extern int produceexp(struct unit * u, skill_t sk, int n); + +extern boolean battledebug; +extern boolean sqlpatch; +extern boolean lomem; /* save memory */ + +extern const char * dbrace(const struct race * rc); + +extern void set_param(struct param ** p, const char * name, const char * data); +extern const char* get_param(const struct param * p, const char * name); +extern int get_param_int(const struct param * p, const char * name, int def); +extern float get_param_flt(const struct param * p, const char * name, float def); + +extern boolean ExpensiveMigrants(void); +extern int NMRTimeout(void); +extern int LongHunger(const struct unit * u); +extern int SkillCap(skill_t sk); +extern int NewbieImmunity(void); +extern boolean IsImmune(const struct faction * f); +extern int AllianceAuto(void); /* flags that allied factions get automatically */ +extern int AllianceRestricted(void); /* flags restricted to allied factions */ +extern int HelpMask(void); /* flags restricted to allied factions */ +extern struct order * default_order(const struct locale * lang); +extern int entertainmoney(const struct region * r); + +extern void plagues(struct region * r, boolean ismagic); +typedef struct helpmode { + const char * name; + int status; +} helpmode; + +extern struct helpmode helpmodes[]; + +#define GIVE_SELF 1 +#define GIVE_PEASANTS 2 +#define GIVE_LUXURIES 4 +#define GIVE_HERBS 8 +#define GIVE_GOODS 16 +#define GIVE_ONDEATH 32 +#define GIVE_ALLITEMS (GIVE_GOODS|GIVE_HERBS|GIVE_LUXURIES) +#define GIVE_DEFAULT (GIVE_SELF|GIVE_PEASANTS|GIVE_LUXURIES|GIVE_HERBS|GIVE_GOODS) + +extern struct attrib_type at_guard; +extern void free_gamedata(void); +#if 1 /* disable to count all units */ +# define count_unit(u) playerrace(u->race) +#else +# define count_unit(u) 1 +#endif + +#if XECMD_MODULE +extern struct attrib_type at_xontormiaexpress; +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/connection.c b/src/kernel/connection.c new file mode 100644 index 000000000..0dc4a3753 --- /dev/null +++ b/src/kernel/connection.c @@ -0,0 +1,613 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "connection.h" + +#include "region.h" +#include "save.h" +#include "terrain.h" +#include "unit.h" +#include "version.h" + +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +unsigned int nextborder = 0; + +#define BORDER_MAXHASH 8191 +connection * borders[BORDER_MAXHASH]; +border_type * bordertypes; + +void (*border_convert_cb)(struct connection * con, struct attrib * attr) = 0; + +void +free_borders(void) +{ + int i; + for (i=0;i!=BORDER_MAXHASH;++i) { + while (borders[i]) { + connection * b = borders[i]; + borders[i] = b->nexthash; + while (b) { + connection * bf = b; + b = b->next; + assert(b==NULL || b->nexthash==NULL); + if (bf->type->destroy) { + bf->type->destroy(bf); + } + free(bf); + } + } + } +} + +connection * +find_border(unsigned int id) +{ + int key; + for (key=0;key!=BORDER_MAXHASH;key++) { + connection * bhash; + for (bhash=borders[key];bhash!=NULL;bhash=bhash->nexthash) { + connection * b; + for (b=bhash;b;b=b->next) { + if (b->id==id) return b; + } + } + } + return NULL; +} + +int +resolve_borderid(variant id, void * addr) +{ + int result = 0; + connection * b = NULL; + if (id.i!=0) { + b = find_border(id.i); + if (b==NULL) { + result = -1; + } + } + *(connection**)addr = b; + return result; +} + +static connection ** +get_borders_i(const region * r1, const region * r2) +{ + connection ** bp; + int key = reg_hashkey(r1); + int k2 = reg_hashkey(r2); + + key = MIN(k2, key) % BORDER_MAXHASH; + bp = &borders[key]; + while (*bp) { + connection * b = *bp; + if ((b->from==r1 && b->to==r2) || (b->from==r2 && b->to==r1)) break; + bp = &b->nexthash; + } + return bp; +} + +connection * +get_borders(const region * r1, const region * r2) +{ + connection ** bp = get_borders_i(r1, r2); + return *bp; +} + +connection * +new_border(border_type * type, region * from, region * to) +{ + connection * b = calloc(1, sizeof(struct connection)); + + if (from && to) { + connection ** bp = get_borders_i(from, to); + while (*bp) bp = &(*bp)->next; + *bp = b; + } + b->type = type; + b->from = from; + b->to = to; + b->id = ++nextborder; + + if (type->init) type->init(b); + return b; +} + +void +erase_border(connection * b) +{ + if (b->from && b->to) { + connection ** bp = get_borders_i(b->from, b->to); + assert(*bp!=NULL || !"error: connection is not registered"); + if (*bp==b) { + /* it is the first in the list, so it is in the nexthash list */ + if (b->next) { + *bp = b->next; + (*bp)->nexthash = b->nexthash; + } else { + *bp = b->nexthash; + } + } else { + while (*bp && *bp != b) { + bp = &(*bp)->next; + } + assert(*bp==b || !"error: connection is not registered"); + *bp = b->next; + } + } + if (b->type->destroy) { + b->type->destroy(b); + } + free(b); +} + +void +register_bordertype(border_type * type) +{ + border_type ** btp = &bordertypes; + + while (*btp && *btp!=type) btp = &(*btp)->next; + if (*btp) return; + *btp = type; +} + + +border_type * +find_bordertype(const char * name) +{ + border_type * bt = bordertypes; + + while (bt && strcmp(bt->__name, name)) bt = bt->next; + return bt; +} + +void +b_read(connection * b, storage * store) +{ + int result = 0; + switch (b->type->datatype) { + case VAR_NONE: + case VAR_INT: + b->data.i = store->r_int(store); + break; + case VAR_SHORTA: + b->data.sa[0] = (short)store->r_int(store); + b->data.sa[1] = (short)store->r_int(store); + break; + case VAR_VOIDPTR: + default: + assert(!"invalid variant type in connection"); + result = 0; + } + assert(result>=0 || "EOF encountered?"); +} + +void +b_write(const connection * b, storage * store) +{ + switch (b->type->datatype) { + case VAR_NONE: + case VAR_INT: + store->w_int(store, b->data.i); + break; + case VAR_SHORTA: + store->w_int(store, b->data.sa[0]); + store->w_int(store, b->data.sa[1]); + break; + case VAR_VOIDPTR: + default: + assert(!"invalid variant type in connection"); + } +} + +boolean b_transparent(const connection * b, const struct faction * f) { unused(b); unused(f); return true; } +boolean b_opaque(const connection * b, const struct faction * f) { unused(b); unused(f); return false; } +boolean b_blockall(const connection * b, const unit * u, const region * r) { unused(u); unused(r); unused(b); return true; } +boolean b_blocknone(const connection * b, const unit * u, const region * r) { unused(u); unused(r); unused(b); return false; } +boolean b_rvisible(const connection * b, const region * r) { return (boolean)(b->to==r || b->from==r); } +boolean b_fvisible(const connection * b, const struct faction * f, const region * r) { unused(r); unused(f); unused(b); return true; } +boolean b_uvisible(const connection * b, const unit * u) { unused(u); unused(b); return true; } +boolean b_rinvisible(const connection * b, const region * r) { unused(r); unused(b); return false; } +boolean b_finvisible(const connection * b, const struct faction * f, const region * r) { unused(r); unused(f); unused(b); return false; } +boolean b_uinvisible(const connection * b, const unit * u) { unused(u); unused(b); return false; } + +/**************************************/ +/* at_countdown - legacy, do not use */ +/**************************************/ + +attrib_type at_countdown = { + "countdown", + DEFAULT_INIT, + DEFAULT_FINALIZE, + NULL, + NULL, + a_readint +}; + +void +age_borders(void) +{ + border_list * deleted = NULL; + int i; + + for (i=0;i!=BORDER_MAXHASH;++i) { + connection * bhash = borders[i]; + for (;bhash;bhash=bhash->nexthash) { + connection * b = bhash; + for (;b;b=b->next) { + if (b->type->age) { + if (b->type->age(b)==AT_AGE_REMOVE) { + border_list * kill = malloc(sizeof(border_list)); + kill->data = b; + kill->next = deleted; + deleted = kill; + } + } + } + } + } + while (deleted) { + border_list * blist = deleted->next; + connection * b = deleted->data; + erase_border(b); + free(deleted); + deleted = blist; + } +} + +/******** + * implementation of a couple of borders. this shouldn't really be in here, so + * let's keep it separate from the more general stuff above + ********/ + +#include "faction.h" + +static const char * +b_namewall(const connection * b, const region * r, const struct faction * f, int gflags) +{ + const char * bname = "wall"; + + unused(f); + unused(r); + unused(b); + if (gflags & GF_ARTICLE) bname = "a_wall"; + if (gflags & GF_PURE) return bname; + return LOC(f->locale, mkname("border", bname)); +} + +border_type bt_wall = { + "wall", VAR_INT, + b_opaque, + NULL, /* init */ + NULL, /* destroy */ + b_read, /* read */ + b_write, /* write */ + b_blockall, /* block */ + b_namewall, /* name */ + b_rvisible, /* rvisible */ + b_fvisible, /* fvisible */ + b_uvisible, /* uvisible */ +}; + +border_type bt_noway = { + "noway", VAR_INT, + b_transparent, + NULL, /* init */ + NULL, /* destroy */ + b_read, /* read */ + b_write, /* write */ + b_blockall, /* block */ + NULL, /* name */ + b_rinvisible, /* rvisible */ + b_finvisible, /* fvisible */ + b_uinvisible, /* uvisible */ +}; + +static const char * +b_namefogwall(const connection * b, const region * r, const struct faction * f, int gflags) +{ + unused(f); + unused(b); + unused(r); + if (gflags & GF_PURE) return "fogwall"; + if (gflags & GF_ARTICLE) return LOC(f->locale, mkname("border", "a_fogwall")); + return LOC(f->locale, mkname("border", "fogwall")); +} + +static boolean +b_blockfogwall(const connection * b, const unit * u, const region * r) +{ + unused(b); + unused(r); + if (!u) return true; + return (boolean)(effskill(u, SK_PERCEPTION) > 4); /* Das ist die alte Nebelwand */ +} + +/** Legacy type used in old Eressea games, no longer in use. */ +border_type bt_fogwall = { + "fogwall", VAR_INT, + b_transparent, /* transparent */ + NULL, /* init */ + NULL, /* destroy */ + b_read, /* read */ + b_write, /* write */ + b_blockfogwall, /* block */ + b_namefogwall, /* name */ + b_rvisible, /* rvisible */ + b_fvisible, /* fvisible */ + b_uvisible, /* uvisible */ +}; + +static const char * +b_nameillusionwall(const connection * b, const region * r, const struct faction * f, int gflags) +{ + int fno = b->data.i; + unused(b); + unused(r); + if (gflags & GF_PURE) return (f && fno==f->no)?"illusionwall":"wall"; + if (gflags & GF_ARTICLE) { + return LOC(f->locale, mkname("border", (f && fno==f->subscription)?"an_illusionwall":"a_wall")); + } + return LOC(f->locale, mkname("border", (f && fno==f->no)?"illusionwall":"wall")); +} + +border_type bt_illusionwall = { + "illusionwall", VAR_INT, + b_opaque, + NULL, /* init */ + NULL, /* destroy */ + b_read, /* read */ + b_write, /* write */ + b_blocknone, /* block */ + b_nameillusionwall, /* name */ + b_rvisible, /* rvisible */ + b_fvisible, /* fvisible */ + b_uvisible, /* uvisible */ +}; + +/*** + * special quest door + ***/ + +boolean b_blockquestportal(const connection * b, const unit * u, const region * r) { + if(b->data.i > 0) return true; + return false; +} + +static const char * +b_namequestportal(const connection * b, const region * r, const struct faction * f, int gflags) +{ + const char * bname; + int lock = b->data.i; + unused(b); + unused(r); + + if (gflags & GF_ARTICLE) { + if (lock > 0) { + bname = "a_gate_locked"; + } else { + bname = "a_gate_open"; + } + } else { + if (lock > 0) { + bname = "gate_locked"; + } else { + bname = "gate_open"; + } + } + if (gflags & GF_PURE) return bname; + return LOC(f->locale, mkname("border", bname)); +} + +border_type bt_questportal = { + "questportal", VAR_INT, + b_opaque, + NULL, /* init */ + NULL, /* destroy */ + b_read, /* read */ + b_write, /* write */ + b_blockquestportal, /* block */ + b_namequestportal, /* name */ + b_rvisible, /* rvisible */ + b_fvisible, /* fvisible */ + b_uvisible, /* uvisible */ +}; + +/*** + * roads. meant to replace the old at_road or r->road attribute + ***/ + +static const char * +b_nameroad(const connection * b, const region * r, const struct faction * f, int gflags) +{ + region * r2 = (r==b->to)?b->from:b->to; + int local = (r==b->from)?b->data.sa[0]:b->data.sa[1]; + static char buffer[64]; + + unused(f); + if (gflags & GF_PURE) return "road"; + if (gflags & GF_ARTICLE) { + if (!(gflags & GF_DETAILED)) return LOC(f->locale, mkname("border", "a_road")); + else if (r->terrain->max_road<=local) { + int remote = (r2==b->from)?b->data.sa[0]:b->data.sa[1]; + if (r2->terrain->max_road<=remote) { + return LOC(f->locale, mkname("border", "a_road")); + } else { + return LOC(f->locale, mkname("border", "an_incomplete_road")); + } + } else { + int percent = MAX(1, 100*local/r->terrain->max_road); + if (local) { + snprintf(buffer, sizeof(buffer), LOC(f->locale, mkname("border", "a_road_percent")), percent); + } else { + return LOC(f->locale, mkname("border", "a_road_connection")); + } + } + } + else if (gflags & GF_PLURAL) return LOC(f->locale, mkname("border", "roads")); + else return LOC(f->locale, mkname("border", "road")); + return buffer; +} + +static void +b_readroad(connection * b, storage * store) +{ + b->data.sa[0] = (short)store->r_int(store); + b->data.sa[1] = (short)store->r_int(store); +} + +static void +b_writeroad(const connection * b, storage * store) +{ + store->w_int(store, b->data.sa[0]); + store->w_int(store, b->data.sa[1]); +} + +static boolean +b_validroad(const connection * b) +{ + if (b->data.sa[0]==SHRT_MAX) return false; + return true; +} + +static boolean +b_rvisibleroad(const connection * b, const region * r) +{ + int x = b->data.i; + x = (r==b->from)?b->data.sa[0]:b->data.sa[1]; + if (x==0) { + return false; + } + if (b->to!=r && b->from!=r) { + return false; + } + return true; +} + +border_type bt_road = { + "road", VAR_INT, + b_transparent, + NULL, /* init */ + NULL, /* destroy */ + b_readroad, /* read */ + b_writeroad, /* write */ + b_blocknone, /* block */ + b_nameroad, /* name */ + b_rvisibleroad, /* rvisible */ + b_finvisible, /* fvisible */ + b_uinvisible, /* uvisible */ + b_validroad /* valid */ +}; + +void +write_borders(struct storage * store) +{ + int i; + for (i=0;i!=BORDER_MAXHASH;++i) { + connection * bhash; + for (bhash=borders[i];bhash;bhash=bhash->nexthash) { + connection * b; + for (b=bhash;b!=NULL;b=b->next) { + if (b->type->valid && !b->type->valid(b)) continue; + store->w_tok(store, b->type->__name); + store->w_int(store, b->id); + store->w_int(store, b->from->uid); + store->w_int(store, b->to->uid); + + if (b->type->write) b->type->write(b, store); + store->w_brk(store); + } + } + } + store->w_tok(store, "end"); +} + +int +read_borders(struct storage * store) +{ + for (;;) { + unsigned int bid = 0; + char zText[32]; + connection * b; + region * from, * to; + border_type * type; + + store->r_tok_buf(store, zText, sizeof(zText)); + if (!strcmp(zText, "end")) break; + bid = store->r_int(store); + if (store->versionr_int(store); + fy = (short)store->r_int(store); + tx = (short)store->r_int(store); + ty = (short)store->r_int(store); + from = findregion(fx, fy); + to = findregion(tx, ty); + } else { + unsigned int fid = (unsigned int)store->r_int(store); + unsigned int tid = (unsigned int)store->r_int(store); + from = findregionbyid(fid); + to = findregionbyid(tid); + } + + type = find_bordertype(zText); + if (type==NULL) { + log_error(("[read_borders] unknown connection type %s in %s\n", zText, + regionname(from, NULL))); + assert(type || !"connection type not registered"); + } + + if (to==from && type && from) { + direction_t dir = (direction_t) (rng_int() % MAXDIRECTIONS); + region * r = rconnect(from, dir); + log_error(("[read_borders] invalid %s in %s\n", type->__name, + regionname(from, NULL))); + if (r!=NULL) to = r; + } + b = new_border(type, from, to); + nextborder--; /* new_border erhöht den Wert */ + b->id = bid; + assert(bid<=nextborder); + if (type->read) type->read(b, store); + if (store->version + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_BORDER +#define H_KRNL_BORDER + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + extern unsigned int nextborder; + + typedef struct connection { + struct border_type * type; /* the type of this connection */ + struct connection * next; /* next connection between these regions */ + struct connection * nexthash; /* next connection between these regions */ + struct region * from, * to; /* borders can be directed edges */ + variant data; + unsigned int id; /* unique id */ + } connection; + + typedef struct border_list { + struct border_list * next; + struct connection * data; + } border_list; + + typedef struct border_type { + const char* __name; /* internal use only */ + variant_type datatype; + boolean (*transparent)(const connection *, const struct faction *); + /* is it possible to see through this? */ + void (*init)(connection *); + /* constructor: initialize the connection. allocate extra memory if needed */ + void (*destroy)(connection *); + /* destructor: remove all extra memory for destruction */ + void (*read)(connection *, struct storage *); + void (*write)(const connection *, struct storage *); + boolean (*block)(const connection *, const struct unit *, const struct region * r); + /* return true if it blocks movement of u from + * r to the opposite struct region. + * warning: struct unit may be NULL. + */ + const char *(*name)(const connection * b, const struct region * r, const struct faction * f, int gflags); + /* for example "a wall of fog" or "a doorway from r1 to r2" + * may depend on the struct faction, for example "a wall" may + * turn out to be "an illusionary wall" + */ + boolean (*rvisible)(const connection *, const struct region *); + /* is it visible to everyone in r ? + * if not, it may still be fvisible() for some f. + */ + boolean (*fvisible)(const connection *, const struct faction *, const struct region *); + /* is it visible to units of f in r? + * the function shall not check for + * existence of a struct unit in r. Example: a spell + * may be visible only to the struct faction that created it and thus + * appear in it's report (if there is a struct unit of f in r, which + * the reporting function will have to assure). + * if not true, it may still be uvisible() for some u. + */ + boolean (*uvisible)(const connection *, const struct unit *); + /* is it visible to u ? + * a doorway may only be visible to a struct unit with perception > 5 + */ + boolean (*valid)(const connection *); + /* is the connection in a valid state, + * or should it be erased at the end of this turn to save space? + */ + struct region * (*move)(const connection *, struct unit * u, struct region * from, struct region * to, boolean routing); + /* executed when the units traverses this connection */ + int (*age)(struct connection *); + /* return 0 if connection needs to be removed. >0 if still aging, <0 if not aging */ + struct border_type * next; /* for internal use only */ + } border_type; + + + extern connection * find_border(unsigned int id); + int resolve_borderid(variant data, void * addr); + extern void free_borders(void); + + extern connection * get_borders(const struct region * r1, const struct region * r2); + /* returns the list of borders between r1 and r2 or r2 and r1 */ + extern connection * new_border(border_type * type, struct region * from, struct region * to); + /* creates a connection of the specified type */ + extern void erase_border(connection * b); + /* remove the connection from memory */ + extern border_type * find_bordertype(const char * name); + extern void register_bordertype(border_type * type); + /* register a new bordertype */ + + extern int read_borders(struct storage * store); + extern void write_borders(struct storage * store); + extern void age_borders(void); + + /* provide default implementations for some member functions: */ + extern void b_read(connection * b, struct storage * store); + extern void b_write(const connection * b, struct storage * store); + extern boolean b_blockall(const connection *, const struct unit *, const struct region *); + extern boolean b_blocknone(const connection *, const struct unit *, const struct region *); + extern boolean b_rvisible(const connection *, const struct region * r); + extern boolean b_fvisible(const connection *, const struct faction * f, const struct region *); + extern boolean b_uvisible(const connection *, const struct unit * u); + extern boolean b_rinvisible(const connection *, const struct region * r); + extern boolean b_finvisible(const connection *, const struct faction * f, const struct region *); + extern boolean b_uinvisible(const connection *, const struct unit * u); + extern boolean b_transparent(const connection *, const struct faction *); + extern boolean b_opaque(const connection *, const struct faction *); /* !transparent */ + + extern border_type bt_fogwall; + extern border_type bt_noway; + extern border_type bt_wall; + extern border_type bt_illusionwall; + extern border_type bt_road; + extern border_type bt_questportal; + + extern struct attrib_type at_countdown; + + /* game-specific callbacks */ + extern void (*border_convert_cb)(struct connection * con, struct attrib * attr); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/curse.c b/src/kernel/curse.c new file mode 100644 index 000000000..415308d2c --- /dev/null +++ b/src/kernel/curse.c @@ -0,0 +1,821 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "curse.h" + +/* kernel includes */ +#include "building.h" +#include "faction.h" +#include "magic.h" +#include "message.h" +#include "objtypes.h" +#include "race.h" +#include "region.h" +#include "ship.h" +#include "skill.h" +#include "unit.h" +#include "version.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include + +#include + +#define MAXENTITYHASH 7919 +curse *cursehash[MAXENTITYHASH]; + +void +c_setflag(curse *c, unsigned int flags) +{ + assert(c); + c->flags = (c->flags & ~flags) | (flags & (c->type->flags ^ flags)); +} +/* -------------------------------------------------------------------------- */ +void +c_clearflag(curse *c, unsigned int flags) +{ + assert(c); + c->flags = (c->flags & ~flags) | (c->type->flags & flags); +} + +void +chash(curse *c) +{ + curse *old = cursehash[c->no %MAXENTITYHASH]; + + cursehash[c->no %MAXENTITYHASH] = c; + c->nexthash = old; +} + +static void +cunhash(curse *c) +{ + curse **show; + + for (show = &cursehash[c->no % MAXENTITYHASH]; *show; show = &(*show)->nexthash) { + if ((*show)->no == c->no) + break; + } + if (*show) { + assert(*show == c); + *show = (*show)->nexthash; + c->nexthash = 0; + } +} + +curse * +cfindhash(int i) +{ + curse *old; + + for (old = cursehash[i % MAXENTITYHASH]; old; old = old->nexthash) + if (old->no == i) + return old; + return NULL; +} + +/* ------------------------------------------------------------- */ +/* at_curse */ +void +curse_init(attrib * a) { + a->data.v = calloc(1, sizeof(curse)); +} + +int +curse_age(attrib * a) +{ + curse * c = (curse*)a->data.v; + int result = 0; + + if (c_flags(c) & CURSE_NOAGE) { + c->duration = INT_MAX; + } + if (c->type->age) { + result = c->type->age(c); + } + if (result!=0) { + c->duration = 0; + } else if (c->duration!=INT_MAX) { + c->duration = MAX(0, c->duration-1); + } + return c->duration; +} + +void +destroy_curse(curse * c) +{ + cunhash(c); + free(c); +} + +void +curse_done(attrib * a) { + destroy_curse((curse *)a->data.v); +} + +/** reads curses that have been removed from the code */ +static int +read_ccompat(const char * cursename, struct storage * store) +{ + struct compat { + const char * name; + const char * tokens; + } * seek, old_curses[] = { {"disorientationzone", ""}, {"shipdisorientation", ""}, { NULL, NULL } } ; + for (seek=old_curses;seek->name;++seek) { + if (strcmp(seek->tokens, cursename)==0) { + const char * p; + for (p=seek->name;p;++p) { + switch (*p) { + case 'd': store->r_int(store); break; + case 's': store->r_str(store); break; + case 't': store->r_tok(store); break; + case 'i': store->r_id(store); break; + case 'f': store->r_flt(store); break; + } + } + return 0; + } + } + return -1; +} + +int +curse_read(attrib * a, void * owner, struct storage * store) +{ + curse * c = (curse*)a->data.v; + int ur; + char cursename[64]; + unsigned int flags; + + c->no = store->r_int(store); + chash(c); + store->r_tok_buf(store, cursename, sizeof(cursename)); + flags = store->r_int(store); + c->duration = store->r_int(store); + if (store->version >= CURSEVIGOURISFLOAT_VERSION) { + c->vigour = store->r_flt(store); + } else { + int vigour = store->r_int(store); + c->vigour = vigour; + } + if (store->versionmagician, store, read_int, resolve_unit); + } else { + ur = read_reference(&c->magician, store, read_unit_reference, resolve_unit); + } + if (store->versioneffect = (double)store->r_int(store); + } else { + c->effect = store->r_flt(store); + } + c->type = ct_find(cursename); + if (c->type==NULL) { + int result = read_ccompat(cursename, store); + if (result!=0) { + log_error(("missing curse %s, no compatibility code either.\n", cursename)); + } + assert(result==0); + return AT_READ_FAIL; + } + if (store->version < CURSEFLAGS_VERSION) { + c_setflag(c, flags); + } else { + c->flags = flags; + } + c_clearflag(c, CURSE_ISNEW); + + if (c->type->read) c->type->read(store, c, owner); + else if (c->type->typ==CURSETYP_UNIT) { + c->data.i = store->r_int(store); + } + if (c->type->typ == CURSETYP_REGION) { + int rr = read_reference(&c->data.v, store, read_region_reference, RESOLVE_REGION(store->version)); + if (ur==0 && rr==0 && !c->data.v) { + return AT_READ_FAIL; + } + } + + return AT_READ_OK; +} + +void +curse_write(const attrib * a, const void * owner, struct storage * store) +{ + unsigned int flags; + curse * c = (curse*)a->data.v; + const curse_type * ct = c->type; + unit * mage = (c->magician && c->magician->number)?c->magician:NULL; + + /* copied from c_clearflag */ + flags = (c->flags & ~CURSE_ISNEW) | (c->type->flags & CURSE_ISNEW); + + store->w_int(store, c->no); + store->w_tok(store, ct->cname); + store->w_int(store, flags); + store->w_int(store, c->duration); + store->w_flt(store, (float)c->vigour); + write_unit_reference(mage, store); + store->w_flt(store, (float)c->effect); + + if (c->type->write) c->type->write(store, c, owner); + else if (c->type->typ == CURSETYP_UNIT) { + store->w_int(store, c->data.i); + } + if (c->type->typ == CURSETYP_REGION) { + write_region_reference((region*)c->data.v, store); + } +} + +attrib_type at_curse = +{ + "curse", + curse_init, + curse_done, + curse_age, + curse_write, + curse_read, + ATF_CURSE +}; +/* ------------------------------------------------------------- */ +/* Spruch identifizieren */ + +#include + +typedef struct cursetype_list { + struct cursetype_list * next; + const curse_type * type; +} cursetype_list; + +cursetype_list * cursetypes[256]; + +void +ct_register(const curse_type * ct) +{ + unsigned int hash = tolower(ct->cname[0]); + cursetype_list ** ctlp = &cursetypes[hash]; + + while (*ctlp) { + cursetype_list * ctl = *ctlp; + if (ctl->type==ct) return; + ctlp=&ctl->next; + } + *ctlp = calloc(1, sizeof(cursetype_list)); + (*ctlp)->type = ct; +} + +const curse_type * +ct_find(const char *c) +{ + unsigned int hash = tolower(c[0]); + cursetype_list * ctl = cursetypes[hash]; + while (ctl) { + if (strcmp(c, ctl->type->cname)==0) { + return ctl->type; + } else { + size_t k = MIN(strlen(c), strlen(ctl->type->cname)); + if (!strncasecmp(c, ctl->type->cname, k)) { + return ctl->type; + } + } + ctl = ctl->next; + } + return NULL; +} + +/* ------------------------------------------------------------- */ +/* get_curse identifiziert eine Verzauberung über die ID und gibt + * einen pointer auf die struct zurück. + */ + +boolean +cmp_curse(const attrib * a, const void * data) { + const curse * c = (const curse*)data; + if (a->type->flags & ATF_CURSE) { + if (!data || c == (curse*)a->data.v) return true; + } + return false; +} + +boolean +cmp_cursetype(const attrib * a, const void * data) +{ + const curse_type * ct = (const curse_type *)data; + if (a->type->flags & ATF_CURSE) { + if (!data || ct == ((curse*)a->data.v)->type) return true; + } + return false; +} + +curse * +get_cursex(attrib *ap, const curse_type * ctype, variant data, boolean(*compare)(const curse *, variant)) +{ + attrib * a = a_select(ap, ctype, cmp_cursetype); + while (a) { + curse * c = (curse*)a->data.v; + if (compare(c, data)) return c; + a = a_select(a->next, ctype, cmp_cursetype); + } + return NULL; +} + +curse * +get_curse(attrib *ap, const curse_type * ctype) +{ + attrib * a = ap; + while (a) { + if (a->type->flags & ATF_CURSE) { + const attrib_type * at = a->type; + while (a && a->type==at) { + curse* c = (curse *)a->data.v; + if (c->type==ctype) return c; + a = a->next; + } + } else { + a = a->nexttype; + } + } + return NULL; +} + +/* ------------------------------------------------------------- */ +/* findet einen curse global anhand seiner 'curse-Einheitnummer' */ + +curse * +findcurse(int cid) +{ + return cfindhash(cid); +} + +/* ------------------------------------------------------------- */ +void +remove_curse(attrib **ap, const curse *c) +{ + attrib *a = a_select(*ap, c, cmp_curse); + if (a) a_remove(ap, a); +} + +/* gibt die allgemeine Stärke der Verzauberung zurück. id2 wird wie + * oben benutzt. Dies ist nicht die Wirkung, sondern die Kraft und + * damit der gegen Antimagie wirkende Widerstand einer Verzauberung */ +static double +get_cursevigour(const curse *c) +{ + if (c) return c->vigour; + return 0; +} + +/* setzt die Stärke der Verzauberung auf i */ +static void +set_cursevigour(curse *c, double vigour) +{ + assert(c && vigour > 0); + c->vigour = vigour; +} + +/* verändert die Stärke der Verzauberung um +i und gibt die neue + * Stärke zurück. Sollte die Zauberstärke unter Null sinken, löst er + * sich auf. + */ +double +curse_changevigour(attrib **ap, curse *c, double vigour) +{ + vigour += get_cursevigour(c); + + if (vigour <= 0) { + remove_curse(ap, c); + vigour = 0; + } else { + set_cursevigour(c, vigour); + } + return vigour; +} + +/* ------------------------------------------------------------- */ + +double +curse_geteffect(const curse *c) +{ + if (c==NULL) return 0; + if (c_flags(c) & CURSE_ISNEW) return 0; + return c->effect; +} + +int +curse_geteffect_int(const curse *c) +{ + double effect = curse_geteffect(c); + assert(effect-(int)effect == 0); + return (int)effect; +} + +/* ------------------------------------------------------------- */ +static void +set_curseingmagician(struct unit *magician, struct attrib *ap_target, const curse_type *ct) +{ + curse * c = get_curse(ap_target, ct); + if (c) { + c->magician = magician; + } +} + +/* ------------------------------------------------------------- */ +/* gibt bei Personenbeschränkten Verzauberungen die Anzahl der + * betroffenen Personen zurück. Ansonsten wird 0 zurückgegeben. */ +int +get_cursedmen(unit *u, const curse *c) +{ + int cursedmen = u->number; + + if (!c) return 0; + + /* je nach curse_type andere data struct */ + if (c->type->typ == CURSETYP_UNIT) { + cursedmen = c->data.i; + } + + return MIN(u->number, cursedmen); +} + +/* setzt die Anzahl der betroffenen Personen auf cursedmen */ +static void +set_cursedmen(curse *c, int cursedmen) +{ + if (!c) return; + + /* je nach curse_type andere data struct */ + if (c->type->typ == CURSETYP_UNIT) { + c->data.i = cursedmen; + } +} + +/* ------------------------------------------------------------- */ +/* Legt eine neue Verzauberung an. Sollte es schon einen Zauber + * dieses Typs geben, gibt es den bestehenden zurück. + */ +static curse * +make_curse(unit *mage, attrib **ap, const curse_type *ct, double vigour, + int duration, double effect, int men) +{ + curse *c; + attrib * a; + + a = a_new(&at_curse); + a_add(ap, a); + c = (curse*)a->data.v; + + c->type = ct; + c->flags = 0; + c->vigour = vigour; + c->duration = duration; + c->effect = effect; + c->magician = mage; + + c->no = newunitid(); + chash(c); + + switch (c->type->typ) { + case CURSETYP_NORM: + break; + + case CURSETYP_UNIT: + { + c->data.i = men; + break; + } + + } + return c; +} + + +/* Mapperfunktion für das Anlegen neuer curse. Automatisch wird zum + * passenden Typ verzweigt und die relevanten Variablen weitergegeben. + */ +curse * +create_curse(unit *magician, attrib **ap, const curse_type *ct, double vigour, + int duration, double effect, int men) +{ + curse *c; + + /* die Kraft eines Spruchs darf nicht 0 sein*/ + assert(vigour > 0); + + c = get_curse(*ap, ct); + + if (c && (c_flags(c) & CURSE_ONLYONE)){ + return NULL; + } + assert(c==NULL || ct==c->type); + + /* es gibt schon eins diese Typs */ + if (c && ct->mergeflags != NO_MERGE) { + if(ct->mergeflags & M_DURATION){ + c->duration = MAX(c->duration, duration); + } + if(ct->mergeflags & M_SUMDURATION){ + c->duration += duration; + } + if(ct->mergeflags & M_SUMEFFECT){ + c->effect += effect; + } + if(ct->mergeflags & M_MAXEFFECT){ + c->effect = MAX(c->effect, effect); + } + if(ct->mergeflags & M_VIGOUR){ + c->vigour = MAX(vigour, c->vigour); + } + if(ct->mergeflags & M_VIGOUR_ADD){ + c->vigour = vigour + c->vigour; + } + if(ct->mergeflags & M_MEN){ + switch (ct->typ) { + case CURSETYP_UNIT: + { + c->data.i += men; + } + } + } + set_curseingmagician(magician, *ap, ct); + } else { + c = make_curse(magician, ap, ct, vigour, duration, effect, men); + } + return c; +} + +/* ------------------------------------------------------------- */ +/* hier müssen alle c-typen, die auf Einheiten gezaubert werden können, + * berücksichtigt werden */ + +static void +do_transfer_curse(curse *c, unit * u, unit * u2, int n) +{ + int cursedmen = 0; + int men = get_cursedmen(u, c); + boolean dogive = false; + const curse_type *ct = c->type; + + switch ((ct->flags | c->flags) & CURSE_SPREADMASK) { + case CURSE_SPREADALWAYS: + dogive = true; + men = u2->number + n; + break; + + case CURSE_SPREADMODULO: + { + int i; + int u_number = u->number; + for (i=0;i0;i++){ + if (rng_int()%u_number < cursedmen){ + ++men; + --cursedmen; + dogive = true; + } + --u_number; + } + break; + } + case CURSE_SPREADCHANCE: + if (chance(u2->number/(double)(u2->number + n))) { + men = u2->number + n; + dogive = true; + } + break; + case CURSE_SPREADNEVER: + break; + } + + if (dogive == true) { + curse * cnew = make_curse(c->magician, &u2->attribs, c->type, c->vigour, + c->duration, c->effect, men); + cnew->flags = c->flags; + + if (ct->typ == CURSETYP_UNIT) set_cursedmen(cnew, men); + } +} + +void +transfer_curse(unit * u, unit * u2, int n) +{ + attrib * a; + + a = a_find(u->attribs, &at_curse); + while (a && a->type==&at_curse) { + curse *c = (curse*)a->data.v; + do_transfer_curse(c, u, u2, n); + a = a->next; + } +} + +/* ------------------------------------------------------------- */ + +boolean +curse_active(const curse *c) +{ + if (!c) return false; + if (c_flags(c) & CURSE_ISNEW) return false; + if (c->vigour <= 0) return false; + + return true; +} + +boolean +is_cursed_internal(attrib *ap, const curse_type *ct) +{ + curse *c = get_curse(ap, ct); + + if (!c) + return false; + + return true; +} + + +boolean +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)) { + return true; + } + a = a->next; + } + + return false; +} +/* ------------------------------------------------------------- */ +/* cursedata */ +/* ------------------------------------------------------------- */ +/* + * typedef struct curse_type { + * const char *cname; (Name der Zauberwirkung, Identifizierung des curse) + * int typ; + * spread_t spread; + * unsigned int mergeflags; + * int (*curseinfo)(const struct locale*, const void*, int, curse*, int); + * void (*change_vigour)(curse*, double); + * int (*read)(struct storage * store, curse * c); + * int (*write)(struct storage * store, const curse * c); + * } curse_type; + */ + +int +resolve_curse(variant id, void * address) +{ + int result = 0; + curse * c = NULL; + if (id.i!=0) { + c = cfindhash(id.i); + if (c==NULL) { + result = -1; + } + } + *(curse**)address = c; + return result; +} + +static const char * oldnames[MAXCURSE] = { + /* OBS: when removing curses, remember to update read_ccompat() */ + "fogtrap", + "antimagiczone", + "farvision", + "gbdream", + "auraboost", + "maelstrom", + "blessedharvest", + "drought", + "badlearn", + "stormwind", + "flyingship", + "nodrift", + "depression", + "magicwalls", + "strongwall", + "astralblock", + "generous", + "peacezone", + "magicstreet", + "magicrunes", + "badmagicresistancezone", + "goodmagicresistancezone", + "slavery", + "calmmonster", + "oldrace", + "fumble", + "riotzone", + "nocostbuilding", + "godcursezone", + "speed", + "orcish", + "magicboost", + "insectfur", + "strength", + "worse", + "magicresistance", + "itemcloak", + "sparkle", + "skillmod" +}; + +const char * +oldcursename(int id) +{ + return oldnames[id]; +} + +/* ------------------------------------------------------------- */ +message * +cinfo_simple(const void * obj, typ_t typ, const struct curse *c, int self) +{ + struct message * msg; + + unused(typ); + unused(self); + unused(obj); + + msg = msg_message(mkname("curseinfo", c->type->cname), "id", c->no); + if (msg==NULL) { + log_error(("There is no curseinfo for %s.\n", c->type->cname)); + } + return msg; +} + + +/* ------------------------------------------------------------- */ +/* Antimagie - curse auflösen */ +/* ------------------------------------------------------------- */ + +/* Wenn der Curse schwächer ist als der cast_level, dann wird er +* aufgelöst, bzw seine Kraft (vigour) auf 0 gesetzt. +* Ist der cast_level zu gering, hat die Antimagie nur mit einer Chance +* von 100-20*Stufenunterschied % eine Wirkung auf den Curse. Dann wird +* die Kraft des Curse um die halbe Stärke der Antimagie reduziert. +* Zurückgegeben wird der noch unverbrauchte Rest von force. +*/ +double +destr_curse(curse* c, int cast_level, double force) +{ + if (cast_level < c->vigour) { /* Zauber ist nicht stark genug */ + double probability = 0.1 + (cast_level - c->vigour)*0.2; + /* pro Stufe Unterschied -20% */ + if (chance(probability)) { + force -= c->vigour; + if (c->type->change_vigour) { + c->type->change_vigour(c, -(cast_level+1/2)); + } else { + c->vigour -= cast_level+1/2; + } + } + } else { /* Zauber ist stärker als curse */ + if (force >= c->vigour) { /* reicht die Kraft noch aus? */ + force -= c->vigour; + if (c->type->change_vigour) { + c->type->change_vigour(c, -c->vigour); + } else { + c->vigour = 0; + } + + } + } + return force; +} + +#ifndef DISABLE_TESTS +#include "curse_test.c" +#endif diff --git a/src/kernel/curse.h b/src/kernel/curse.h new file mode 100644 index 000000000..7adb53477 --- /dev/null +++ b/src/kernel/curse.h @@ -0,0 +1,330 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CURSE_H +#define CURSE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Sprueche in der struct region und auf Einheiten, Schiffen oder Burgen + * (struct attribute) + */ + +/* Brainstorming Überarbeitung curse + * + * Ziel: Keine Enum-Liste, flexible, leicht erweiterbare Curse-Objekte + * + * Was wird gebraucht? + * - Eindeutige Kennung für globale Suche + * - eine Wirkung, die sich einfach 'anwenden' läßt, dabei flexibel ist, + * Raum läßt für variable Boni, Anzahl betroffener Personen, + * spezielle Effekte oder anderes + * - einfacher Zugriff auf allgemeine Funktionen wie zb Alterung, aber + * auch Antimagieverhalten + * - Ausgabe von Beschreibungen in verschiedenen Sprachen + * - definiertes gekapseltes Verhalten zb bei Zusammenlegung von + * Einheiten, Übergabe von Personen, Mehrfachverzauberung + * - (Rück-)Referenzen auf Objekt, Verursacher (Magier), ? + * + * Vieleicht wäre ein Wirkungsklassensystem sinnvoll, so das im übrigen + * source einfach alle curse-attribs abgefragt werden können und bei + * gewünschter Wirkungsklasse angewendet, also nicht für jeden curse + * spezielle Änderungen im übrigen source notwendig sind. + * + * Die (Wirkungs-)Typen sollten die wichtigen Funktionen speziell + * belegen können, zb Alterung, Ausgabetexte, Merge-Verhalten + * + * Was sind wichtige individuelle Eigenschaften? + * - Referenzen auf Objekt und Verursacher + * - Referenzen für globale Liste + * > die Wirkung: + * - Dauer + * - Widerstandskraft, zb gegen Antimagie + * - Seiteneffekte zb Flag ONLYONE, Unverträglichkeiten + * - Alterungsverhalten zb Flag NOAGE + * - Effektverhalten, zb Bonus (variabel) + * - bei Einheitenzaubern die Zahl der betroffenen Personen + * + * Dabei sind nur die beiden letzten Punkte wirklich reine individuelle + * Wirkung, die anderen sind eher allgemeine Kennzeichen eines jeden + * Curse, die individuell belegt sind. + * ONLYONE und NOAGE könnten auch Eigenschaften des Typs sein, nicht des + * individuellen curse. Allgemein ist Alterung wohl eher eine + * Typeigenschaft als die eines individuellen curse. + * Dagegen ist der Widerstand gegen Antimagie sowohl abhängig von der + * Güte des Verursachers, also des Magiers zum Zeitpunkt des Zaubers, + * als auch vom Typ, der gegen bestimmte Arten des 'Fluchbrechens' immun + * sein könnte. + * + * Was sind wichtige Typeigenschaften? + * - Verhalten bei Personenübergaben + * - allgemeine Wirkung + * - Beschreibungstexte + * - Verhalten bei Antimagie + * - Alterung + * - Speicherung des C-Objekts + * - Laden des C-Objekts + * - Erzeugen des C-Objekts + * - Löschen und Aufräumen des C-Objekts + * - Funktionen zur Änderung der Werte + * + * */ + +#include + +/* ------------------------------------------------------------- */ +/* Zauberwirkungen */ +/* nicht vergessen curse_type zu aktualisieren und Reihenfolge beachten! + */ + +enum { +/* struct's vom typ curse: */ + C_FOGTRAP, + C_ANTIMAGICZONE, + C_FARVISION, + C_GBDREAM, + C_AURA, + C_MAELSTROM, + C_BLESSEDHARVEST, + C_DROUGHT, + C_BADLEARN, + C_SHIP_SPEEDUP, /* 9 - Sturmwind-Zauber */ + C_SHIP_FLYING, /* 10 - Luftschiff-Zauber */ + C_SHIP_NODRIFT, /* 11 - GünstigeWinde-Zauber */ + C_DEPRESSION, + C_MAGICWALLS, /* 13 - Heimstein */ + C_STRONGWALL, /* 14 - Feste Mauer - Precombat*/ + C_ASTRALBLOCK, /* 15 - Astralblock */ + C_GENEROUS, /* 16 - Unterhaltung vermehren */ + C_PEACE, /* 17 - Regionsweit Attacken verhindern */ + C_MAGICSTREET, /* 19 - magisches Straßennetz */ + C_RESIST_MAGIC, /* 20 - verändert Magieresistenz von Objekten */ + C_SONG_BADMR, /* 21 - verändert Magieresistenz */ + C_SONG_GOODMR, /* 22 - verändert Magieresistenz */ + C_SLAVE, /* 23 - dient fremder Partei */ + C_CALM, /* 25 - Beinflussung */ + C_OLDRACE, + C_FUMBLE, + C_RIOT, /*region in Aufruhr */ + C_NOCOST, + C_CURSED_BY_THE_GODS, +/* struct's vom untertyp curse_unit: */ + C_SPEED, /* Beschleunigt */ + C_ORC, + C_MBOOST, + C_KAELTESCHUTZ, + C_STRENGTH, + C_ALLSKILLS, + C_MAGICRESISTANCE, /* 44 - verändert Magieresistenz */ + C_ITEMCLOAK, + C_SPARKLE, +/* struct's vom untertyp curse_skill: */ + C_SKILL, + MAXCURSE /* OBS: when removing curses, remember to update read_ccompat() */ +}; + +/* ------------------------------------------------------------- */ +/* Flags */ + + +/* Verhalten von Zaubern auf Units beim Übergeben von Personen */ +typedef enum { + CURSE_ISNEW = 0x01, /* wirkt in der zauberrunde nicht (default)*/ + CURSE_NOAGE = 0x02, /* wirkt ewig */ + CURSE_IMMUNE = 0x04, /* ignoriert Antimagie */ + CURSE_ONLYONE = 0x08, /* Verhindert, das ein weiterer Zauber dieser Art auf das Objekt gezaubert wird */ + + /* the following are mutually exclusive */ + CURSE_SPREADNEVER = 0x00, /* wird nie mit übertragen */ + CURSE_SPREADALWAYS = 0x10, /* wird immer mit übertragen */ + CURSE_SPREADMODULO = 0x20, /* personenweise weitergabe */ + CURSE_SPREADCHANCE = 0x30 /* Ansteckungschance je nach Mengenverhältnis*/ +} curseflags; + +#define CURSE_FLAGSMASK 0x0F +#define CURSE_SPREADMASK 0x30 + +/* typ von struct */ +enum { + CURSETYP_NORM, + CURSETYP_UNIT, + CURSETYP_REGION, /* stores the region in c->data.v */ + MAXCURSETYP +}; + +/* Verhalten beim Zusammenfassen mit einem schon bestehenden Zauber + * gleichen Typs */ + +#define NO_MERGE 0 /* erzeugt jedesmal einen neuen Zauber */ +#define M_DURATION 1 /* Die Zauberdauer ist die maximale Dauer beider */ +#define M_SUMDURATION 2 /* die Dauer des Zaubers wird summiert */ +#define M_MAXEFFECT 4 /* der Effekt ist der maximale Effekt beider */ +#define M_SUMEFFECT 8 /* der Effekt summiert sich */ +#define M_MEN 16 /* die Anzahl der betroffenen Personen summiert + sich */ +#define M_VIGOUR 32 /* das Maximum der beiden Stärken wird die + Stärke des neuen Zaubers */ +#define M_VIGOUR_ADD 64 /* Vigour wird addiert */ + +/* ------------------------------------------------------------- */ +/* Allgemeine Zauberwirkungen */ + +typedef struct curse { + struct curse *nexthash; + int no; /* 'Einheitennummer' dieses Curse */ + const struct curse_type * type; /* Zeiger auf ein curse_type-struct */ + unsigned int flags; /* WARNING: these are XORed with type->flags! */ + int duration; /* Dauer der Verzauberung. Wird jede Runde vermindert */ + double vigour; /* Stärke der Verzauberung, Widerstand gegen Antimagie */ + struct unit *magician; /* Pointer auf den Magier, der den Spruch gewirkt hat */ + double effect; + variant data; /* pointer auf spezielle curse-unterstructs*/ +} curse; + +#define c_flags(c) ((c)->type->flags ^ (c)->flags) + +/* ------------------------------------------------------------- */ + +typedef struct curse_type { + const char *cname; /* Name der Zauberwirkung, Identifizierung des curse */ + int typ; + unsigned int flags; + unsigned int mergeflags; + struct message * (*curseinfo)(const void*, typ_t, const struct curse*, int); + void (*change_vigour)(curse*, double); + int (*read)(struct storage * store, curse * c, void * target); + int (*write)(struct storage * store, const struct curse * c, const void * target); + int (*cansee)(const struct faction*, const void*, typ_t, const struct curse *, int); + int (*age)(curse *); +} curse_type; + +extern struct attrib_type at_curse; +void curse_write(const struct attrib * a, const void * owner, struct storage * store); +int curse_read(struct attrib * a, void * owner, struct storage * store); + + +/* ------------------------------------------------------------- */ +/* Kommentare: + * Bei einigen Typen von Verzauberungen (z.B.Skillmodif.) muss neben + * der curse-id noch ein weiterer Identifizierer angegeben werden (id2). + * + * Wenn der Typ korrekt definiert wurde, erfolgt die Verzweigung zum + * korrekten Typus automatisch, und die unterschiedlichen struct-typen + * sind nach aussen unsichtbar. + * +* allgemeine Funktionen * +*/ + +curse * create_curse(struct unit *magician, struct attrib**ap, const curse_type * ctype, + double vigour, int duration, double ceffect, int men); + /* Verzweigt automatisch zum passenden struct-typ. Sollte es schon + * einen Zauber dieses Typs geben, so wird der neue dazuaddiert. Die + * Zahl der verzauberten Personen sollte beim Aufruf der Funktion + * nochmal gesondert auf min(get_cursedmen, u->number) gesetzt werden. + */ + +extern void destroy_curse(curse * c); + + +boolean is_cursed_internal(struct attrib *ap, const curse_type * ctype); + /* ignoriert CURSE_ISNEW */ + +extern void remove_curse(struct attrib **ap, const struct curse * c); + /* löscht einen konkreten Spruch auf einem Objekt. + */ + +extern int curse_geteffect_int(const struct curse * c); +extern double curse_geteffect(const struct curse * c); + /* gibt die Auswirkungen der Verzauberungen zurück. zB bei + * Skillmodifiziernden Verzauberungen ist hier der Modifizierer + * gespeichert. Wird automatisch beim Anlegen eines neuen curse + * gesetzt. Gibt immer den ersten Treffer von ap aus zurück. + */ + + +extern double curse_changevigour(struct attrib **ap, curse * c, double i); + /* verändert die Stärke der Verzauberung um i */ + +extern int get_cursedmen(struct unit *u, const struct curse *c); + /* gibt bei Personenbeschränkten Verzauberungen die Anzahl der + * betroffenen Personen zurück. Ansonsten wird 0 zurückgegeben. */ + +extern void c_setflag(curse * c, unsigned int flag); +extern void c_clearflag(curse *c, unsigned int flags); + /* setzt/loescht Spezialflag einer Verzauberung (zB 'dauert ewig') */ + +void transfer_curse(struct unit * u, struct unit * u2, int n); + /* sorgt dafür, das bei der Übergabe von Personen die curse-attribute + * korrekt gehandhabt werden. Je nach internen Flag kann dies + * unterschiedlich gewünscht sein + * */ + +extern struct curse * get_cursex(struct attrib *ap, const curse_type * ctype, variant data, + boolean(*compare)(const struct curse *, variant)); + /* gibt pointer auf die erste curse-struct zurück, deren Typ ctype ist, + * und für die compare() true liefert, oder einen NULL-pointer. + * */ +extern struct curse * get_curse(struct attrib *ap, const curse_type * ctype); + /* gibt pointer auf die erste curse-struct zurück, deren Typ ctype ist, + * oder einen NULL-pointer + * */ + +int find_cursebyname(const char *c); +const curse_type * ct_find(const char *c); +void ct_register(const curse_type *); +/* Regionszauber */ + +curse * cfindhash(int i); + +curse * findcurse(int curseid); + +extern void curse_init(struct attrib * a); +extern void curse_done(struct attrib * a); +extern int curse_age(struct attrib * a); + +extern boolean cmp_curse(const struct attrib * a, const void * data); +extern boolean cmp_cursetype(const struct attrib * a, const void * data); + +extern double destr_curse(struct curse* c, int cast_level, double force); + +extern int resolve_curse(variant data, void * address); +extern boolean is_cursed_with(const struct attrib *ap, const struct curse *c); + +extern boolean curse_active(const struct curse * c); + /* gibt true, wenn der Curse nicht NULL oder inaktiv ist */ + +/*** COMPATIBILITY MACROS. DO NOT USE FOR NEW CODE, REPLACE IN OLD CODE: */ +extern const char * oldcursename(int id); +extern struct message * cinfo_simple(const void * obj, typ_t typ, const struct curse *c, int self); + +#define is_cursed(a, id, id2) \ + curse_active(get_curse(a, ct_find(oldcursename(id)))) +#define get_curseeffect(a, id, id2) \ + curse_geteffect(get_curse(a, ct_find(oldcursename(id)))) + +/* eressea-defined attribute-type flags */ +#define ATF_CURSE ATF_USER_DEFINED + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/curse_test.c b/src/kernel/curse_test.c new file mode 100644 index 000000000..0445995bc --- /dev/null +++ b/src/kernel/curse_test.c @@ -0,0 +1,23 @@ +#include + +static void test_curse(CuTest * tc) { + attrib * attrs = NULL; + curse * c, * result; + int cid; + + curse_type ct_dummy = { "dummy", CURSETYP_NORM, 0, M_SUMEFFECT, NULL }; + c = create_curse(NULL, &attrs, &ct_dummy, 1.0, 1, 1, 1); + cid = c->no; + result = findcurse(cid); + CuAssertPtrEquals(tc, c, result); + destroy_curse(c); + result = findcurse(cid); + CuAssertPtrEquals(tc, NULL, result); +} + +CuSuite* get_curse_suite(void) +{ + CuSuite* suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_curse); + return suite; +} diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c new file mode 100644 index 000000000..9b7e0393b --- /dev/null +++ b/src/kernel/equipment.c @@ -0,0 +1,220 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "equipment.h" + +/* kernel includes */ +#include "item.h" +#include "unit.h" +#include "race.h" + +/* util includes */ +#include +#include + +/* libc includes */ +#include +#include + +static equipment * equipment_sets; + +equipment * +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 = malloc(sizeof(equipment)); + eq->name = strdup(eqname); + eq->next = *eqp; + eq->items = NULL; + eq->spells = NULL; + eq->subsets = NULL; + eq->callback = NULL; + 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) { + if (value!=NULL) { + eq->skills[sk] = strdup(value); + } else if (eq->skills[sk]) { + free(eq->skills[sk]); + } + } +} + +void +equipment_addspell(equipment * eq, spell * sp) +{ + if (eq!=NULL) { + spelllist_add(&eq->spells, sp); + } +} + +void +equipment_setitem(equipment * eq, const item_type * itype, const char * value) +{ + if (eq!=NULL) { + if (itype!=NULL) { + itemdata * idata = eq->items; + while (idata &&idata->itype!=itype) { + idata = idata->next; + } + if (idata==NULL) { + idata = malloc(sizeof(itemdata)); + idata->itype = itype; + idata->value = strdup(value); + idata->next = eq->items; + eq->items = idata; + } + } + } +} + +void +equipment_setcallback(struct equipment * eq, void (*callback)(const struct equipment *, struct unit *)) +{ + eq->callback = callback; +} + +void +equip_unit(struct unit * u, const struct equipment * eq) +{ + equip_unit_mask(u, eq, EQUIP_ALL); +} + +void +equip_unit_mask(struct unit * u, const struct equipment * eq, int mask) +{ + if (eq) { + + if (mask&EQUIP_SKILLS) { + skill_t sk; + for (sk=0;sk!=MAXSKILLS;++sk) { + if (eq->skills[sk]!=NULL) { + int i = dice_rand(eq->skills[sk]); + if (i>0) set_level(u, sk, i); + } + } + } + + if (mask&EQUIP_SPELLS) { + spell_list * sp = eq->spells; + if (sp!=NULL) { + sc_mage * m = get_mage(u); + if (m==NULL) { + assert(!"trying to equip spells on a non-mage!"); + } else { + while (sp) { + add_spell(get_spelllist(m, u->faction), sp->data); + sp = sp->next; + } + } + } + } + + if (mask&EQUIP_ITEMS) { + itemdata * idata; + for (idata=eq->items;idata!=NULL;idata=idata->next) { + int i = u->number * dice_rand(idata->value); + if (i>0) { + i_add(&u->items, i_new(idata->itype, i)); + } + } + } + + if (eq->subsets) { + int i; + for (i=0;eq->subsets[i].sets;++i) { + if (chance(eq->subsets[i].chance)) { + float rnd = (1+rng_int() % 1000) / 1000.0f; + int k; + for (k=0;eq->subsets[i].sets[k].set;++k) { + if (rnd<=eq->subsets[i].sets[k].chance) { + equip_unit_mask(u, eq->subsets[i].sets[k].set, mask); + break; + } + rnd -= eq->subsets[i].sets[k].chance; + } + } + } + } + + if (mask&EQUIP_SPECIAL) { + if (eq->callback) eq->callback(eq, u); + } + } +} + +void +equip_items(struct item ** items, const struct equipment * eq) +{ + if (eq) { + itemdata * idata; + + for (idata=eq->items;idata!=NULL;idata=idata->next) { + int i = dice_rand(idata->value); + if (i>0) { + i_add(items, i_new(idata->itype, i)); + } + } + if (eq->subsets) { + int i; + for (i=0;eq->subsets[i].sets;++i) { + if (chance(eq->subsets[i].chance)) { + float rnd = (1+rng_int() % 1000) / 1000.0f; + int k; + for (k=0;eq->subsets[i].sets[k].set;++k) { + if (rnd<=eq->subsets[i].sets[k].chance) { + equip_items(items, eq->subsets[i].sets[k].set); + break; + } + rnd -= eq->subsets[i].sets[k].chance; + } + } + } + } + } +} diff --git a/src/kernel/equipment.h b/src/kernel/equipment.h new file mode 100644 index 000000000..174aad7f4 --- /dev/null +++ b/src/kernel/equipment.h @@ -0,0 +1,73 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_EQUIPMENT_H +#define H_KRNL_EQUIPMENT_H +#ifdef __cplusplus +extern "C" { +#endif + struct spell; + + typedef struct itemdata { + const struct item_type * itype; + char * value; + struct itemdata * next; + } itemdata; + + typedef struct subsetitem { + struct equipment * set; + float chance; + } subsetitem; + + typedef struct subset { + float chance; + subsetitem * sets; + } subset; + + typedef struct equipment { + char * name; + struct itemdata * items; + char * skills[MAXSKILLS]; + struct spell_list * spells; + struct subset * subsets; + struct equipment * next; + void (*callback)(const struct equipment *, struct unit *); + } equipment; + + + extern struct equipment * create_equipment(const char * eqname); + extern struct equipment * get_equipment(const char * eqname); + + extern void equipment_setitem(struct equipment * eq, const struct item_type * itype, const char * value); + extern void equipment_setskill(struct equipment * eq, skill_t sk, const char * value); + extern void equipment_addspell(struct equipment * eq, struct spell * sp); + extern void equipment_setcallback(struct equipment * eq, void (*callback)(const struct equipment *, struct unit *)); + + extern void equip_unit(struct unit * u, const struct equipment * eq); +#define EQUIP_SKILLS (1<<1) +#define EQUIP_SPELLS (1<<2) +#define EQUIP_ITEMS (1<<3) +#define EQUIP_SPECIAL (1<<4) +#define EQUIP_ALL (0xFF) + extern void equip_unit_mask(struct unit * u, const struct equipment * eq, int mask); + extern void equip_items(struct item ** items, const struct equipment * eq); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/faction.c b/src/kernel/faction.c new file mode 100644 index 000000000..f5ac32f3c --- /dev/null +++ b/src/kernel/faction.c @@ -0,0 +1,507 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "faction.h" + +#include "alliance.h" +#include "equipment.h" +#include "group.h" +#include "item.h" +#include "message.h" +#include "plane.h" +#include "race.h" +#include "region.h" +#include "terrain.h" +#include "unit.h" +#include "version.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +faction *factions; + +/** remove the faction from memory. + * this frees all memory that's only accessible through the faction, + * but you should still call funhash and remove the faction from the + * global list. + */ +void +free_faction (faction * f) +{ + if (f->msgs) free_messagelist(f->msgs); + while (f->battles) { + struct bmsg * bm = f->battles; + f->battles = bm->next; + if (bm->msgs) free_messagelist(bm->msgs); + free(bm); + } + + while (f->groups) { + group * g = f->groups; + f->groups = g->next; + free_group(g); + } + freelist(f->allies); + + free(f->email); + free(f->banner); + free(f->passw); + free(f->override); + free(f->name); + + while (f->attribs) { + a_remove (&f->attribs, f->attribs); + } + + i_freeall(&f->items); + + freelist(f->ursprung); +} + +faction * +get_monsters(void) +{ + static faction * monsters; + static int gamecookie = -1; + + if (gamecookie!=global.cookie) { + monsters = NULL; + gamecookie = global.cookie; + } + + if (!monsters) { + faction * f; + for (f=factions;f;f=f->next) { + if (f->flags&FFL_NPC) { + return monsters=f; + } + } + if (!monsters) { + /* shit! */ + monsters = findfaction(666); + } + if (monsters) { + fset(monsters, FFL_NPC|FFL_NOIDLEOUT); + } + } + return monsters; +} + +const unit * +random_unit_in_faction(const faction *f) +{ + unit *u; + int c = 0, u_nr; + + for(u = f->units; u; u=u->next) c++; + + u_nr = rng_int()%c; + c = 0; + + for(u = f->units; u; u=u->next) + if(u_nr == c) return u; + + /* Hier sollte er nie ankommen */ + return NULL; +} + +const char * +factionname(const faction * f) +{ + typedef char name[OBJECTIDSIZE+1]; + static name idbuf[8]; + static int nextbuf = 0; + + char *ibuf = idbuf[(++nextbuf) % 8]; + + if (f && f->name) { + snprintf(ibuf, sizeof(name), "%s (%s)", f->name, itoa36(f->no)); + ibuf[sizeof(name)-1] = 0; + } else { + strcpy(ibuf, "Unbekannte Partei (?)"); + } + 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; + } + } + *(faction**)address = f; + return result; +} + +#define MAX_FACTION_ID (36*36*36*36) + +static int +unused_faction_id(void) +{ + int id = rng_int()%MAX_FACTION_ID; + + while (!faction_id_is_unused(id)) { + id++; if(id == MAX_FACTION_ID) id = 0; + } + + return id; +} + +faction * +addfaction(const char *email, const char * password, + const struct race * frace, const struct locale *loc, + int subscription) +{ + faction * f = calloc(sizeof(faction), 1); + char buf[128]; + + assert(frace); + + if (set_email(&f->email, email)!=0) { + log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), email)); + } + + f->override = strdup(itoa36(rng_int())); + faction_setpassword(f, password); + + f->alliance_joindate = turn; + f->lastorders = turn; + f->alive = 1; + f->age = 0; + f->race = frace; + f->magiegebiet = 0; + f->locale = loc; + f->subscription = subscription; + + f->options = want(O_REPORT) | want(O_ZUGVORLAGE) | want(O_COMPUTER) | want(O_COMPRESS) | want(O_ADRESSEN) | want(O_STATISTICS); + + f->no = unused_faction_id(); + if (rule_region_owners()) { + alliance * al = makealliance(f->no, NULL); + setalliance(f, al); + } + addlist(&factions, f); + fhash(f); + + snprintf(buf, sizeof(buf), "%s %s", LOC(loc, "factiondefault"), factionid(f)); + f->name = strdup(buf); + + return f; +} + +unit * +addplayer(region *r, faction * f) +{ + unit *u; + char buffer[32]; + + assert(f->units==NULL); + set_ursprung(f, 0, r->x, r->y); + u = createunit(r, f, 1, f->race); + equip_items(&u->faction->items, get_equipment("new_faction")); + equip_unit(u, get_equipment("first_unit")); + sprintf(buffer, "first_%s", u->race->_name[0]); + equip_unit(u, get_equipment(buffer)); + u->hp = unit_max_hp(u) * u->number; + fset(u, UFL_ISNEW); + if (f->race == new_race[RC_DAEMON]) { + race_t urc; + do { + urc = (race_t)(rng_int() % MAXRACES); + } while (new_race[urc]==NULL || urc == RC_DAEMON || !playerrace(new_race[urc])); + u->irace = new_race[urc]; + } + + return u; +} + +boolean +checkpasswd(const faction * f, const char * passwd, boolean shortp) +{ + if (unicode_utf8_strcasecmp(f->passw, passwd)==0) return true; + if (unicode_utf8_strcasecmp(f->override, passwd)==0) return true; + return false; +} + + +variant +read_faction_reference(struct storage * store) +{ + variant id; + id.i = store->r_id(store); + return id; +} + +void +write_faction_reference(const faction * f, struct storage * store) +{ + store->w_id(store, f?f->no:0); +} + +void +destroyfaction(faction * f) +{ + unit *u = f->units; + faction *ff; + + if (!f->alive) return; + fset(f, FFL_QUIT); + + freelist(f->spellbook); + f->spellbook = NULL; + + while (f->battles) { + struct bmsg * bm = f->battles; + f->battles = bm->next; + if (bm->msgs) free_messagelist(bm->msgs); + free(bm); + } + + while (u) { + /* give away your stuff, make zombies if you cannot (quest items) */ + int result = gift_items(u, GIFT_FRIENDS|GIFT_PEASANTS); + if (result!=0) { + unit * zombie = u; + u = u->nextF; + make_zombie(zombie); + } else { + region * r = u->region; + + if (!fval(r->terrain, SEA_REGION) && !!playerrace(u->race)) { + const race * rc = u->race; + int m = rmoney(r); + + if ((rc->ec_flags & ECF_REC_ETHEREAL)==0) { + int p = rpeasants(u->region); + int h = rhorses(u->region); + item * itm; + + /* Personen gehen nur an die Bauern, wenn sie auch von dort + * stammen */ + if (rc->ec_flags & ECF_REC_HORSES) { /* Zentauren an die Pferde */ + h += u->number; + } else { /* Orks zählen nur zur Hälfte */ + p += (int)(u->number * rc->recruit_multi); + } + for (itm=u->items;itm;itm=itm->next) { + if (itm->type->flags&ITF_ANIMAL) { + h += itm->number; + } + } + rsetpeasants(r, p); + rsethorses(r, h); + } + m += get_money(u); + rsetmoney(r, m); + } + set_number(u, 0); + u=u->nextF; + } + } + f->alive = 0; +/* no way! f->units = NULL; */ + handle_event(f->attribs, "destroy", f); + for (ff = factions; ff; ff = ff->next) { + group *g; + ally *sf, *sfn; + + /* Alle HELFE für die Partei löschen */ + for (sf = ff->allies; sf; sf = sf->next) { + if (sf->faction == f) { + removelist(&ff->allies, sf); + break; + } + } + for(g=ff->groups; g; g=g->next) { + for (sf = g->allies; sf;) { + sfn = sf->next; + if (sf->faction == f) { + removelist(&g->allies, sf); + break; + } + sf = sfn; + } + } + } + + /* units of other factions that were disguised as this faction + * have their disguise replaced by ordinary faction hiding. */ + if (rule_stealth_faction()) { + region * rc; + for (rc=regions; rc; rc=rc->next) { + for(u=rc->units; u; u=u->next) { + attrib *a = a_find(u->attribs, &at_otherfaction); + if(!a) continue; + if (get_otherfaction(a) == f) { + a_removeall(&u->attribs, &at_otherfaction); + fset(u, UFL_ANON_FACTION); + } + } + } + } +} + +int +get_alliance(const faction * a, const faction * b) +{ + const ally * sf = a->allies; + for (;sf!=NULL;sf=sf->next) { + if (sf->faction==b) { + return sf->status; + } + } + return 0; +} + +void +set_alliance(faction * a, faction * b, int status) +{ + ally ** sfp; + sfp = &a->allies; + while (*sfp) { + ally * sf = *sfp; + if (sf->faction==b) break; + sfp = &sf->next; + } + if (*sfp==NULL) { + ally * sf = *sfp = malloc(sizeof(ally)); + sf->next = NULL; + sf->status = status; + sf->faction = b; + return; + } + (*sfp)->status |= status; +} + +void +renumber_faction(faction * f, int no) +{ + if (f->subscription) { + sql_print(("UPDATE subscriptions set faction='%s' where id=%u;\n", + itoa36(no), f->subscription)); + } + funhash(f); + f->no = no; + fhash(f); + fset(f, FFL_NEWID); +} + +#ifdef SMART_INTERVALS +void +update_interval(struct faction * f, struct region * r) +{ + if (r==NULL || f==NULL) return; + if (f->first==NULL || f->first->index>r->index) { + f->first = r; + } + if (f->last==NULL || f->last->index<=r->index) { + f->last = r; + } +} +#endif + +const char * faction_getname(const faction * self) +{ + return self->name?self->name:""; +} + +void faction_setname(faction * self, const char * name) +{ + free(self->name); + if (name) self->name = strdup(name); +} + +const char * faction_getemail(const faction * self) +{ + return self->email?self->email:""; +} + +void faction_setemail(faction * self, const char * email) +{ + free(self->email); + if (email) self->email = strdup(email); +} + +const char * faction_getbanner(const faction * self) +{ + return self->banner?self->banner:""; +} + +void faction_setbanner(faction * self, const char * banner) +{ + free(self->banner); + if (banner) self->banner = strdup(banner); +} + +void +faction_setpassword(faction * f, const char * passw) +{ + free(f->passw); + if (passw) f->passw = strdup(passw); + else f->passw = strdup(itoa36(rng_int())); +} + +boolean valid_race(const struct faction * f, const struct race * rc) +{ + if (f->race==rc) return true; + else { + const char * str = get_param(f->race->parameters, "other_race"); + if (str) return (boolean)(rc_find(str)==rc); + return false; + } +} + +const char * +faction_getpassword(const faction * f) +{ + return f->passw; +} + +struct alliance * +f_get_alliance(const struct faction * f) +{ + if (f->alliance && !(f->alliance->flags&ALF_NON_ALLIED)) { + return f->alliance; + } + return NULL; +} diff --git a/src/kernel/faction.h b/src/kernel/faction.h new file mode 100644 index 000000000..faa552581 --- /dev/null +++ b/src/kernel/faction.h @@ -0,0 +1,161 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_FACTION +#define H_KRNL_FACTION +#ifdef __cplusplus +extern "C" { +#endif + +struct player; +struct alliance; +struct item; +struct seen_region; + +/* SMART_INTERVALS: define to speed up finding the interval of regions that a + faction is in. defining this speeds up the turn by 30-40% */ +#define SMART_INTERVALS + +/* faction flags */ +#define FFL_NEWID (1<<0) /* Die Partei hat bereits einmal ihre no gewechselt */ +#define FFL_ISNEW (1<<1) +#define FFL_RESTART (1<<2) +#define FFL_QUIT (1<<3) +#define FFL_DEFENDER (1<<10) +#define FFL_SELECT (1<<18) /* ehemals f->dh, u->dh, r->dh, etc... */ +#define FFL_NOAID (1<<21) /* Hilfsflag Kampf */ +#define FFL_MARK (1<<23) /* für markierende algorithmen, die das + * hinterher auch wieder löschen müssen! + * (FFL_SELECT muss man vorher initialisieren, + * FL_MARK hinterher löschen) */ +#define FFL_NOIDLEOUT (1<<24) /* Partei stirbt nicht an NMRs */ +#define FFL_OVERRIDE (1<<27) /* Override-Passwort wurde benutzt */ +#define FFL_DBENTRY (1<<28) /* Partei ist in Datenbank eingetragen */ +#define FFL_NOTIMEOUT (1<<29) /* ignore MaxAge() */ +#define FFL_GM (1<<30) /* eine Partei mit Sonderrechten */ +#define FFL_NPC (1<<31) /* eine Partei mit Monstern */ + +#define FFL_SAVEMASK (FFL_DEFENDER|FFL_NEWID|FFL_GM|FFL_NPC|FFL_NOTIMEOUT|FFL_DBENTRY|FFL_NOTIMEOUT) + +struct faction * get_monsters(void); +#define is_monsters(f) ((f)->flags&FFL_NPC) + +typedef struct faction { + struct faction *next; + struct faction *nexthash; + + struct player *owner; +#ifdef SMART_INTERVALS + struct region *first; + struct region *last; +#endif + int no; + int subscription; + unsigned int flags; + char *name; + char *banner; + char *email; + char *passw; + char *override; + int max_spelllevel; + struct spell_list * spellbook; + const struct locale * locale; + int lastorders; /* enno: short? */ + int age; /* enno: short? */ + struct ursprung *ursprung; + const struct race * race; + magic_t magiegebiet; + int newbies; + int num_people; /* Anzahl Personen ohne Monster */ + int num_total; /* Anzahl Personen mit Monstern */ + int options; + int no_units; + struct ally *allies; + struct group *groups; + boolean alive; /* enno: sollte ein flag werden */ + int nregions; + int money; +#if SCORE_MODULE + int score; +#endif + struct alliance * alliance; + int alliance_joindate; /* the turn on which the faction joined its current alliance (or left the last one) */ +#ifdef VICTORY_DELAY + unsigned char victory_delay; +#endif + struct unit * units; + struct attrib *attribs; + struct message_list * msgs; + struct bmsg { + struct bmsg * next; + struct region * r; + struct message_list * msgs; + } * battles; + struct item * items; /* items this faction can claim */ + struct seen_region ** seen; +} faction; + +extern struct faction *factions; + +typedef struct faction_list { + struct faction_list * next; + struct faction * data; +} faction_list; + +extern const struct unit * random_unit_in_faction(const struct faction *f); +extern const char * factionname(const struct faction * f); +extern struct unit * addplayer(struct region *r, faction * f); +extern struct faction * addfaction(const char *email, const char* password, + const struct race * frace, + const struct locale *loc, int subscription); +extern boolean checkpasswd(const faction * f, const char * passwd, boolean shortp); +extern void destroyfaction(faction * f); + +extern void set_alliance(struct faction * a, struct faction * b, int status); +extern int get_alliance(const struct faction * a, const struct faction * b); + +extern struct alliance * f_get_alliance(const struct faction * a); + +extern void write_faction_reference(const struct faction * f, struct storage * store); +extern variant read_faction_reference(struct storage * store); +extern int resolve_faction(variant data, void * addr); + +extern void renumber_faction(faction * f, int no); +void free_faction(struct faction * f); + +#ifdef SMART_INTERVALS +extern void update_interval(struct faction * f, struct region * r); +#endif + +const char * faction_getbanner(const struct faction * self); +void faction_setbanner(struct faction * self, const char * name); + +const char * faction_getname(const struct faction * self); +void faction_setname(struct faction * self, const char * name); + +const char * faction_getemail(const struct faction * self); +void faction_setemail(struct faction * self, const char * email); + +const char * faction_getpassword(const struct faction * self); +void faction_setpassword(struct faction * self, const char * password); +boolean valid_race(const struct faction * f, const struct race * rc); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/group.c b/src/kernel/group.c new file mode 100644 index 000000000..4838e26fc --- /dev/null +++ b/src/kernel/group.c @@ -0,0 +1,243 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "group.h" + +/* kernel includes */ +#include "unit.h" +#include "faction.h" +#include "save.h" +#include "version.h" + +/* attrib includes */ +#include + +/* util includes */ +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +#define GMAXHASH 2039 +static group * ghash[GMAXHASH]; +static int maxgid; + +static group * +new_group(faction * f, const char * name, int gid) +{ + group ** gp = &f->groups; + int index = gid % GMAXHASH; + group * g = calloc(sizeof(group), 1); + + while (*gp) gp = &(*gp)->next; + *gp = g; + + maxgid = MAX(gid, maxgid); + g->name = strdup(name); + g->gid = gid; + + g->nexthash = ghash[index]; + return ghash[index] = g; +} + +static void +init_group(faction * f, group * g) +{ + ally * a, ** an; + + an = &g->allies; + for (a=f->allies;a;a=a->next) if (a->faction) { + ally * ga = calloc(sizeof(ally), 1); + *ga = *a; + *an = ga; + an = &ga->next; + } +} + +static group * +find_groupbyname(group * g, const char * name) +{ + while (g && unicode_utf8_strcasecmp(name, g->name)!=0) g = g->next; + return g; +} + +static group * +find_group(int gid) +{ + int index = gid % GMAXHASH; + group * g = ghash[index]; + while (g && g->gid!=gid) g = g->nexthash; + return g; +} + +static int +read_group(attrib * a, void * owner, struct storage * store) +{ + group * g; + int gid = store->r_int(store); + a->data.v = g = find_group(gid); + if (g!=0) { + g->members++; + return AT_READ_OK; + } + return AT_READ_FAIL; +} + +static void +write_group(const attrib * a, const void * owner, struct storage * store) +{ + group * g = (group*)a->data.v; + store->w_int(store, g->gid); +} + +attrib_type +at_group = { /* attribute for units assigned to a group */ + "grp", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + write_group, + read_group, + ATF_UNIQUE +}; + +void +free_group(group * g) +{ + int index = g->gid % GMAXHASH; + group ** g_ptr = ghash+index; + while (*g_ptr && (*g_ptr)->gid!=g->gid) g_ptr = &(*g_ptr)->nexthash; + assert(*g_ptr==g); + *g_ptr = g->nexthash; + + while (g->allies) { + ally * a = g->allies; + g->allies = a->next; + free(a); + } + free(g->name); + free(g); +} + +void +set_group(struct unit * u, struct group * g) +{ + attrib * a = NULL; + + if (fval(u, UFL_GROUP)) { + a = a_find(u->attribs, &at_group); + } + + if (a) { + group * og = (group *)a->data.v; + if (og==g) return; + --og->members; + } + + if (g) { + if (!a) { + a = a_add(&u->attribs, a_new(&at_group)); + fset(u, UFL_GROUP); + } + a->data.v = g; + g->members++; + } else if (a) { + a_remove(&u->attribs, a); + freset(u, UFL_GROUP); + } +} + +boolean +join_group(unit * u, const char * name) +{ + group * g = NULL; + + if (name && name[0]) { + g = find_groupbyname(u->faction->groups, name); + if (g==NULL) { + g = new_group(u->faction, name, ++maxgid); + init_group(u->faction, g); + } + } + + set_group(u, g); + return true; +} + +void +write_groups(struct storage * store, group * g) +{ + while (g) { + ally * a; + store->w_int(store, g->gid); + store->w_str(store, g->name); + for (a=g->allies;a;a=a->next) { + if (a->faction) { + write_faction_reference(a->faction, store); + store->w_int(store, a->status); + } + } + store->w_id(store, 0); + a_write(store, g->attribs, g); + store->w_brk(store); + g=g->next; + } + store->w_int(store, 0); +} + +void +read_groups(struct storage * store, faction * f) +{ + for(;;) { + ally ** pa; + group * g; + int gid; + char buf[1024]; + + gid = store->r_int(store); + if (gid==0) break; + store->r_str_buf(store, buf, sizeof(buf)); + g = new_group(f, buf, gid); + pa = &g->allies; + for (;;) { + ally * a; + variant fid; + fid.i = store->r_id(store); + if (fid.i<=0) break; + if (store->versionnext; + a->status = store->r_int(store); + + a->faction = findfaction(fid.i); + if (!a->faction) ur_add(fid, &a->faction, resolve_faction); + } + *pa = 0; + a_read(store, &g->attribs, g); + } +} diff --git a/src/kernel/group.h b/src/kernel/group.h new file mode 100644 index 000000000..63f8c0ba8 --- /dev/null +++ b/src/kernel/group.h @@ -0,0 +1,51 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KERNEL_GROUP +#define H_KERNEL_GROUP +#ifdef __cplusplus +extern "C" { +#endif + +/* bitfield value for group::flags */ +#define GFL_ALIVE 0x01 /* There is at least one struct unit in the group */ + +typedef struct group { + struct group * next; + struct group * nexthash; + struct faction * f; + struct attrib *attribs; + char * name; + struct ally * allies; + int flags; + int gid; + int members; +} group; + +extern struct attrib_type at_group; /* attribute for units assigned to a group */ +extern boolean join_group(struct unit * u, const char * name); +extern void set_group(struct unit * u, struct group * g); +extern void free_group(struct group * g); + +extern void write_groups(struct storage * F, struct group * g); +extern void read_groups(struct storage * F, struct faction * f); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/item.c b/src/kernel/item.c new file mode 100644 index 000000000..02e110f93 --- /dev/null +++ b/src/kernel/item.c @@ -0,0 +1,1185 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "item.h" + +#include + +#include "alchemy.h" +#include "build.h" +#include "faction.h" +#include "message.h" +#include "pool.h" +#include "race.h" +#include "region.h" +#include "save.h" +#include "skill.h" +#include "terrain.h" +#include "unit.h" + +/* triggers includes */ +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +resource_type * resourcetypes; +luxury_type * luxurytypes; +potion_type * potiontypes; + +#define IMAXHASH 127 +static item_type * itemtypes[IMAXHASH]; + +static int +res_changeaura(unit * u, const resource_type * rtype, int delta) +{ + assert(rtype!=NULL); + change_spellpoints(u, delta); + return 0; +} + +static int +res_changeperson(unit * u, const resource_type * rtype, int delta) +{ + assert(rtype!=NULL || !"not implemented"); + scale_number(u, u->number+delta); + return 0; +} + +static int +res_changepermaura(unit * u, const resource_type * rtype, int delta) +{ + assert(rtype!=NULL); + change_maxspellpoints(u, delta); + return 0; +} + +static int +res_changehp(unit * u, const resource_type * rtype, int delta) +{ + assert(rtype!=NULL); + u->hp+=delta; + return 0; +} + +static int +res_changepeasants(unit * u, const resource_type * rtype, int delta) +{ + assert(rtype!=NULL && u->region->land); + u->region->land->peasants+=delta; + return 0; +} + +int +res_changeitem(unit * u, const resource_type * rtype, int delta) +{ + int num; + if (rtype == oldresourcetype[R_STONE] && u->race==new_race[RC_STONEGOLEM] && delta<=0) { + int reduce = delta / GOLEM_STONE; + if (delta % GOLEM_STONE != 0) --reduce; + scale_number(u, u->number+reduce); + num = u->number; + } else if (rtype == oldresourcetype[R_IRON] && u->race==new_race[RC_IRONGOLEM] && delta<=0) { + int reduce = delta / GOLEM_IRON; + if (delta % GOLEM_IRON != 0) --reduce; + scale_number(u, u->number+reduce); + num = u->number; + } else { + const item_type * itype = resource2item(rtype); + item * i; + assert(itype!=NULL); + i = i_change(&u->items, itype, delta); + if (i==NULL) return 0; + num = i->number; + } + return num; +} + +const char * +resourcename(const resource_type * rtype, int flags) +{ + int i = 0; + + if (rtype) { + if (rtype->name) return rtype->name(rtype, flags); + + if (flags & NMF_PLURAL) i = 1; + if (flags & NMF_APPEARANCE && rtype->_appearance[i]) { + return rtype->_appearance[i]; + } + return rtype->_name[i]; + } + return "none"; +} + +resource_type * +new_resourcetype(const char ** names, const char ** appearances, int flags) +{ + resource_type * rtype = rt_find(names[0]); + + if (rtype==NULL) { + int i; + rtype = calloc(sizeof(resource_type), 1); + + for (i=0; i!=2; ++i) { + rtype->_name[i] = strdup(names[i]); + if (appearances) rtype->_appearance[i] = strdup(appearances[i]); + else rtype->_appearance[i] = NULL; + } + rt_register(rtype); + } +#ifndef NDEBUG + else { + /* TODO: check that this is the same type */ + } +#endif + rtype->flags |= flags; + return rtype; +} + +void +it_register(item_type * itype) +{ + int hash = hashstring(itype->rtype->_name[0]); + int key = hash % IMAXHASH; + item_type ** p_itype = &itemtypes[key]; + while (*p_itype && *p_itype != itype) p_itype = &(*p_itype)->next; + if (*p_itype==NULL) { + itype->rtype->itype = itype; + *p_itype = itype; + rt_register(itype->rtype); + } +} + +item_type * +new_itemtype(resource_type * rtype, + int iflags, int weight, int capacity) +{ + item_type * itype; + assert(resource2item(rtype) == NULL); + assert(rtype->flags & RTF_ITEM); + + itype = calloc(sizeof(item_type), 1); + + itype->rtype = rtype; + itype->weight = weight; + itype->capacity = capacity; + itype->flags |= iflags; + it_register(itype); + + rtype->uchange = res_changeitem; + + return itype; +} + +static void +lt_register(luxury_type * ltype) +{ + ltype->itype->rtype->ltype = ltype; + ltype->next = luxurytypes; + luxurytypes = ltype; +} + +luxury_type * +new_luxurytype(item_type * itype, int price) +{ + luxury_type * ltype; + + assert(resource2luxury(itype->rtype) == NULL); + + ltype = calloc(sizeof(luxury_type), 1); + ltype->itype = itype; + ltype->price = price; + lt_register(ltype); + + return ltype; +} + +weapon_type * +new_weapontype(item_type * itype, + int wflags, double magres, const char* damage[], int offmod, int defmod, int reload, skill_t sk, int minskill) +{ + weapon_type * wtype; + + assert(resource2weapon(itype->rtype)==NULL); + + wtype = calloc(sizeof(weapon_type), 1); + if (damage) { + wtype->damage[0] = strdup(damage[0]); + wtype->damage[1] = strdup(damage[1]); + } + wtype->defmod = defmod; + wtype->flags |= wflags; + wtype->itype = itype; + wtype->magres = magres; + wtype->minskill = minskill; + wtype->offmod = offmod; + wtype->reload = reload; + wtype->skill = sk; + itype->rtype->wtype = wtype; + + return wtype; +} + + +armor_type * +new_armortype(item_type * itype, double penalty, double magres, int prot, unsigned int flags) +{ + armor_type * atype; + + assert(itype->rtype->atype==NULL); + + atype = calloc(sizeof(armor_type), 1); + + atype->itype = itype; + atype->penalty = penalty; + atype->magres = magres; + atype->prot = prot; + atype->flags = flags; + itype->rtype->atype = atype; + + return atype; +} + +static void +pt_register(potion_type * ptype) +{ + ptype->itype->rtype->ptype = ptype; + ptype->next = potiontypes; + potiontypes = ptype; +} + +potion_type * +new_potiontype(item_type * itype, + int level) +{ + potion_type * ptype; + + assert(resource2potion(itype->rtype)==NULL); + + ptype = calloc(sizeof(potion_type), 1); + ptype->itype = itype; + ptype->level = level; + pt_register(ptype); + + return ptype; +} + + +void +rt_register(resource_type * rtype) +{ + resource_type ** prtype = &resourcetypes; + + if (!rtype->hashkey) { + rtype->hashkey = hashstring(rtype->_name[0]); + } + while (*prtype && *prtype!=rtype) prtype=&(*prtype)->next; + if (*prtype == NULL) { + *prtype = rtype; + } +} + +const resource_type * +item2resource(const item_type * itype) +{ + return itype?itype->rtype:NULL; +} + +const item_type * +resource2item(const resource_type * rtype) +{ + return rtype?rtype->itype:NULL; +} + +const weapon_type * +resource2weapon(const resource_type * rtype) { + return rtype->wtype; +} + +const luxury_type * +resource2luxury(const resource_type * rtype) +{ +#ifdef AT_LTYPE + attrib * a = a_find(rtype->attribs, &at_ltype); + if (a) return (const luxury_type *)a->data.v; + return NULL; +#else + return rtype->ltype; +#endif +} + +const potion_type * +resource2potion(const resource_type * rtype) +{ +#ifdef AT_PTYPE + attrib * a = a_find(rtype->attribs, &at_ptype); + if (a) return (const potion_type *)a->data.v; + return NULL; +#else + return rtype->ptype; +#endif +} + +resource_type * +rt_find(const char * name) +{ + unsigned int hash = hashstring(name); + resource_type * rtype; + + for (rtype=resourcetypes; rtype; rtype=rtype->next) { + if (rtype->hashkey==hash && !strcmp(rtype->_name[0], name)) break; + } + + return rtype; +} + +static const char * it_aliases[][2] = { + { "Runenschwert", "runesword" }, + { "p12", "truthpotion" }, + { "p1", "goliathwater" }, + { "p4", "ointment" }, + { "p5", "peasantblood" }, + { "p8", "nestwarmth" }, + { "diamond", "adamantium" }, + { "diamondaxe", "adamantiumaxe" }, + { "diamondplate", "adamantiumplate" }, + { "aoh", "ao_healing" }, + { NULL, NULL }, +}; + +static const char * +it_alias(const char * zname) +{ + int i; + for (i=0;it_aliases[i][0];++i) { + if (strcmp(it_aliases[i][0], zname)==0) return it_aliases[i][1]; + } + return zname; +} + +item_type * +it_find(const char * zname) +{ + const char * name = it_alias(zname); + unsigned int hash = hashstring(name); + item_type * itype; + unsigned int key = hash % IMAXHASH; + + for (itype=itemtypes[key]; itype; itype=itype->next) { + if (itype->rtype->hashkey==hash && strcmp(itype->rtype->_name[0], name) == 0) { + break; + } + } + if (itype==NULL) { + for (itype=itemtypes[key]; itype; itype=itype->next) { + if (strcmp(itype->rtype->_name[1], name) == 0) break; + } + } + return itype; +} + +item ** +i_find(item ** i, const item_type * it) +{ + while (*i && (*i)->type!=it) i = &(*i)->next; + return i; +} + +item * const * +i_findc(item * const * i, const item_type * it) +{ + while (*i && (*i)->type!=it) { + i = &(*i)->next; + } + return i; +} + +int +i_get(const item * i, const item_type * it) +{ + i = *i_find((item**)&i, it); + if (i) return i->number; + return 0; +} + +item * +i_add(item ** pi, item * i) +{ + assert(i && i->type && !i->next); + while (*pi) { + int d = strcmp((*pi)->type->rtype->_name[0], i->type->rtype->_name[0]); + if (d>=0) break; + pi = &(*pi)->next; + } + if (*pi && (*pi)->type==i->type) { + (*pi)->number += i->number; + assert((*pi)->number>=0); + i_free(i); + } else { + i->next = *pi; + *pi = i; + } + return *pi; +} + +void +i_merge(item ** pi, item ** si) +{ + item * i = *si; + while (i) { + item * itmp; + while (*pi) { + int d = strcmp((*pi)->type->rtype->_name[0], i->type->rtype->_name[0]); + if (d>=0) break; + pi=&(*pi)->next; + } + if (*pi && (*pi)->type==i->type) { + (*pi)->number += i->number; + assert((*pi)->number>=0); + i_free(i_remove(&i, i)); + } else { + itmp = i->next; + i->next=*pi; + *pi = i; + i = itmp; + } + } + *si=NULL; +} + +item * +i_change(item ** pi, const item_type * itype, int delta) +{ + assert(itype); + while (*pi) { + int d = strcmp((*pi)->type->rtype->_name[0], itype->rtype->_name[0]); + if (d>=0) break; + pi=&(*pi)->next; + } + if (!*pi || (*pi)->type!=itype) { + item * i; + if (delta==0) return NULL; + i = i_new(itype, delta); + i->next = *pi; + *pi = i; + } else { + item * i = *pi; + i->number+=delta; + if (i->number<0) { + log_error(("serious accounting error. number of items is %d.\n", i->number)); + assert(i>=0); + i->number = 0; + } + if (i->number==0) { + *pi = i->next; + i_free(i); + return NULL; + } + } + return *pi; +} + +item * +i_remove(item ** pi, item * i) +{ + assert(i); + while ((*pi)->type!=i->type) pi = &(*pi)->next; + assert(*pi); + *pi = i->next; + i->next = NULL; + return i; +} + +static item * icache; +static int icache_size; +#define ICACHE_MAX 100 + +void +i_free(item * i) +{ + if (icache_size>=ICACHE_MAX) { + free(i); + } else { + i->next = icache; + icache = i; + ++icache_size; + } +} + +void +i_freeall(item **i) { + item *in; + + while(*i) { + in = (*i)->next; + i_free(*i); + *i = in; + } +} + + +item * +i_new(const item_type * itype, int size) +{ + item * i; + if (icache_size>0) { + i = icache; + icache = i->next; + --icache_size; + } else { + i = malloc(sizeof(item)); + } + assert(itype); + i->next = NULL; + i->type = itype; + i->number = size; + assert(i->number>=0); + return i; +} + +#include "region.h" + +static int +give_horses(unit * s, unit * d, const item_type * itype, int n, struct order * ord) +{ + if (d==NULL) { + int use = use_pooled(s, item2resource(itype), GET_SLACK, n); + if (useregion, rhorses(s->region) + use); + return 0; + } + return -1; /* use the mechanism */ +} + +static int +give_money(unit * s, unit * d, const item_type * itype, int n, struct order * ord) +{ + if (d==NULL) { + int use = use_pooled(s, item2resource(itype), GET_SLACK, n); + if (useregion, rmoney(s->region) + use); + return 0; + } + return -1; /* use the mechanism */ +} + +#define R_MINOTHER R_SILVER +#define R_MINHERB R_PLAIN_1 +#define R_MINPOTION R_FAST +#define R_MINITEM R_IRON +#define MAXITEMS MAX_ITEMS +#define MAXRESOURCES MAX_RESOURCES +#define MAXHERBS MAX_HERBS +#define MAXPOTIONS MAX_POTIONS +#define MAXHERBSPERPOTION 6 +#define FIRSTLUXURY (I_BALM) +#define LASTLUXURY (I_INCENSE +1) +#define MAXLUXURIES (LASTLUXURY - FIRSTLUXURY) + +const item_type * olditemtype[MAXITEMS+1]; +const resource_type * oldresourcetype[MAXRESOURCES+1]; +const potion_type * oldpotiontype[MAXPOTIONS+1]; + +/*** alte items ***/ + +int +get_item(const unit * u, item_t it) +{ + const item_type * type = olditemtype[it]; + const item * i = *i_findc(&u->items, type); + if (i) assert(i->number>=0); + return i?i->number:0; +} + +int +set_item(unit * u, item_t it, int value) +{ + const item_type * type = olditemtype[it]; + item * i = *i_find(&u->items, type); + if (!i) { + i = i_add(&u->items, i_new(type, value)); + } else { + i->number = value; + assert(i->number>=0); + } + return value; +} + +static int +use_birthdayamulet(unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + direction_t d; + message * msg = msg_message("meow", ""); + + unused(ord); + unused(amount); + unused(itype); + + add_message(&u->region->msgs, msg); + for(d=0;dregion, d); + if (tr) add_message(&tr->msgs, msg); + } + msg_release(msg); + return 0; +} + + +/* t_item::flags */ +#define FL_ITEM_CURSED (1<<0) +#define FL_ITEM_NOTLOST (1<<1) +#define FL_ITEM_NOTINBAG (1<<2) /* nicht im Bag Of Holding */ +#define FL_ITEM_ANIMAL (1<<3) /* ist ein Tier */ +#define FL_ITEM_MOUNT ((1<<4) | FL_ITEM_ANIMAL) /* ist ein Reittier */ + +/* ------------------------------------------------------------- */ +/* Kann auch von Nichtmagier benutzt werden, modifiziert Taktik für diese + * Runde um -1 - 4 Punkte. */ +static int +use_tacticcrystal(unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + int i; + for (i=0;i!=amount;++i) { + int duration = 1; /* wirkt nur eine Runde */ + float power = 5; /* Widerstand gegen Antimagiesprüche, ist in diesem + Fall egal, da der curse für den Kampf gelten soll, + der vor den Antimagiezaubern passiert */ + curse * c; + double effect; + + effect = rng_int()%6 - 1; + c = create_curse(u, &u->attribs, ct_find("skillmod"), power, + duration, effect, u->number); + c->data.i = SK_TACTICS; + unused(ord); + } + use_pooled(u, itype->rtype, GET_DEFAULT, amount); + ADDMSG(&u->faction->msgs, msg_message("use_tacticcrystal", + "unit region", u, u->region)); + return 0; +} + +typedef struct t_item { + const char *name; + /* [0]: Einzahl für eigene; [1]: Mehrzahl für eigene; + * [2]: Einzahl für Fremde; [3]: Mehrzahl für Fremde */ + boolean is_resource; + skill_t skill; + int minskill; + int gewicht; + int preis; + unsigned int flags; + void (*benutze_funktion) (struct region *, struct unit *, int amount, struct order *); +} t_item; + +const char * itemnames[MAXITEMS] = { + "iron", "stone", "horse", "ao_healing", + "aots", "roi", "rop", "ao_chastity", + "laen", "fairyboot", "aoc", "pegasus", + "elvenhorse", "dolphin", "roqf", "trollbelt", + "presspass", "aurafocus", "sphereofinv", "magicbag", + "magicherbbag", "dreameye" +}; + +#include "move.h" + +static int +mod_elves_only(const unit * u, const region * r, skill_t sk, int value) +{ + if (u->race == new_race[RC_ELF]) return value; + unused(r); + return -118; +} + +static int +mod_dwarves_only(const unit * u, const region * r, skill_t sk, int value) +{ + if (u->race == new_race[RC_DWARF]) return value; + unused(r); + return -118; +} + +static void +init_olditems(void) +{ + item_t i; +#if 0 + resource_type * rtype; + const struct locale * lang = find_locale("de"); + assert(lang); +#endif + + for (i=0; i!=MAXITEMS; ++i) { + /* item is defined in XML file, but IT_XYZ enum still in use */ + const item_type * itype = it_find(itemnames[i]); + + if (itype) { + olditemtype[i] = itype; + oldresourcetype[i] = itype->rtype; + } + } +} + +static int +heal(unit * user, int effect) +{ + int req = unit_max_hp(user) * user->number - user->hp; + if (req>0) { + req = MIN(req, effect); + effect -= req; + user->hp += req; + } + return effect; +} + +void +register_item_give(int (*foo) (struct unit *, struct unit *, const struct item_type *, int, struct order *), const char * name) +{ + register_function((pf_generic)foo, name); +} + +void +register_item_use(int (*foo) (struct unit *, const struct item_type *, int, struct order *), const char * name) +{ + register_function((pf_generic)foo, name); +} + +void +register_item_useonother(int (*foo) (struct unit *, int, const struct item_type *, int, struct order *), const char * name) +{ + register_function((pf_generic)foo, name); +} + +static int +use_healingpotion(struct unit *user, const struct item_type *itype, int amount, struct order * ord) +{ + int effect = amount * 400; + unit * u = user->region->units; + effect = heal(user, effect); + while (effect>0 && u!=NULL) { + if (u->faction==user->faction) { + effect = heal(u, effect); + } + u = u->next; + } + use_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); + usetpotionuse(user, itype->rtype->ptype); + + ADDMSG(&user->faction->msgs, msg_message("usepotion", + "unit potion", user, itype->rtype)); + return 0; +} + +static int +use_warmthpotion(struct unit *u, const struct item_type *itype, int amount, struct order * ord) +{ + if (u->faction->race == new_race[RC_INSECT]) { + fset(u, UFL_WARMTH); + } else { + /* nur für insekten: */ + cmistake(u, ord, 163, MSG_EVENT); + return ECUSTOM; + } + use_pooled(u, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); + usetpotionuse(u, itype->rtype->ptype); + + ADDMSG(&u->faction->msgs, msg_message("usepotion", + "unit potion", u, itype->rtype)); + return 0; +} + +static int +use_foolpotion(struct unit *u, int targetno, const struct item_type *itype, int amount, struct order * ord) +{ + unit * target = findunit(targetno); + if (target==NULL || u->region!=target->region) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return ECUSTOM; + } + if (effskill(u, SK_STEALTH)<=effskill(target, SK_PERCEPTION)) { + cmistake(u, ord, 64, MSG_EVENT); + return ECUSTOM; + } + ADDMSG(&u->faction->msgs, msg_message("givedumb", + "unit recipient amount", u, target, amount)); + + change_effect(target, itype->rtype->ptype, amount); + use_pooled(u, itype->rtype, GET_DEFAULT, amount); + return 0; +} + +static int +use_bloodpotion(struct unit *u, const struct item_type *itype, int amount, struct order * ord) +{ + if (u->race == new_race[RC_DAEMON]) { + change_effect(u, itype->rtype->ptype, 100*amount); + } else { + const race * irace = u_irace(u); + if (irace == u->race) { + static race * rcfailure; + if (!rcfailure) { + rcfailure = rc_find("smurf"); + if (!rcfailure) rcfailure = rc_find("toad"); + } + if (rcfailure) { + trigger * trestore = trigger_changerace(u, u->race, irace); + if (trestore) { + int duration = 2 + rng_int() % 8; + + add_trigger(&u->attribs, "timer", trigger_timeout(duration, trestore)); + u->irace = NULL; + u->race = rcfailure; + } + } + } + } + use_pooled(u, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); + usetpotionuse(u, itype->rtype->ptype); + + ADDMSG(&u->faction->msgs, msg_message("usepotion", + "unit potion", u, itype->rtype)); + return 0; +} + +#include +static int +use_mistletoe(struct unit * user, const struct item_type * itype, int amount, struct order * ord) +{ + int mtoes = get_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); + + if (user->number>mtoes) { + ADDMSG(&user->faction->msgs, msg_message("use_singleperson", + "unit item region command", user, itype->rtype, user->region, ord)); + return -1; + } + use_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); + a_add(&user->attribs, make_fleechance((float)1.0)); + ADDMSG(&user->faction->msgs, + msg_message("use_item", "unit item", user, itype->rtype)); + + return 0; +} + +static int +use_magicboost(struct unit * user, const struct item_type * itype, int amount, struct order * ord) +{ + int mtoes = get_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); + faction * f = user->faction; + if (user->number>mtoes) { + ADDMSG(&user->faction->msgs, msg_message("use_singleperson", + "unit item region command", user, itype->rtype, user->region, ord)); + return -1; + } + if (!is_mage(user) || find_key(f->attribs, atoi36("mbst"))!=NULL) { + cmistake(user, user->thisorder, 214, MSG_EVENT); + return -1; + } + use_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); + + a_add(&f->attribs, make_key(atoi36("mbst"))); + set_level(user, sk_find("magic"), 3); + + ADDMSG(&user->faction->msgs, msg_message("use_item", + "unit item", user, itype->rtype)); + + return 0; +} + +static int +use_snowball(struct unit * user, const struct item_type * itype, int amount, struct order * ord) +{ + return 0; +} + +static void +init_oldpotions(void) +{ + const char * potionnames[MAX_POTIONS] = { + "p0", "goliathwater", "p2", "p3", "ointment", "peasantblood", "p6", + "p7", "nestwarmth", "p9", "p10", "p11", "truthpotion", "p13", "p14" + }; + int p; + + for (p=0;p!=MAXPOTIONS;++p) { + item_type * itype = it_find(potionnames[p]); + if (itype!=NULL) { + oldpotiontype[p] = itype->rtype->ptype; + } + } +} + +resource_type * r_silver; +resource_type * r_aura; +resource_type * r_permaura; +resource_type * r_unit; +resource_type * r_hp; + +resource_type * r_silver; +item_type * i_silver; + +static const char * names[] = { + "money", "money_p", + "person", "person_p", + "permaura", "permaura_p", + "hp", "hp_p", + "peasant", "peasant_p", + "aura", "aura_p", + "unit", "unit_p" +}; + +void +init_resources(void) +{ + static boolean initialized = false; + if (initialized) return; + initialized = true; + + /* silver was never an item: */ + r_silver = new_resourcetype(&names[0], NULL, RTF_ITEM|RTF_POOLED); + i_silver = new_itemtype(r_silver, ITF_NONE, 1/*weight*/, 0); + r_silver->uchange = res_changeitem; + i_silver->give = give_money; + + r_permaura = new_resourcetype(&names[4], NULL, RTF_NONE); + r_permaura->uchange = res_changepermaura; + + r_hp = new_resourcetype(&names[6], NULL, RTF_NONE); + r_hp->uchange = res_changehp; + + r_aura = new_resourcetype(&names[10], NULL, RTF_NONE); + r_aura->uchange = res_changeaura; + + r_unit = new_resourcetype(&names[12], NULL, RTF_NONE); + r_unit->uchange = res_changeperson; + + oldresourcetype[R_SILVER] = r_silver; + oldresourcetype[R_AURA] = r_aura; + oldresourcetype[R_PERMAURA] = r_permaura; + + /* alte typen registrieren: */ + init_olditems(); + init_oldpotions(); +} + +int +get_money(const unit * u) +{ + const item * i = u->items; + while (i && i->type!=i_silver) i=i->next; + if (i==NULL) return 0; + return i->number; +} + +int +set_money(unit * u, int v) +{ + item ** ip = &u->items; + while (*ip && (*ip)->type!=i_silver) ip = &(*ip)->next; + if ((*ip)==NULL && v) { + i_add(&u->items, i_new(i_silver, v)); + return v; + } + if ((*ip)!=NULL) { + if (v) { + (*ip)->number = v; + assert((*ip)->number>=0); + } + else i_remove(ip, *ip); + } + return v; +} + +int +change_money(unit * u, int v) +{ + item ** ip = &u->items; + while (*ip && (*ip)->type!=i_silver) ip = &(*ip)->next; + if ((*ip)==NULL && v) { + i_add(&u->items, i_new(i_silver, v)); + return v; + } + if ((*ip)!=NULL) { + item * i = *ip; + if (i->number + v != 0) { + i->number += v; + assert(i->number>=0); + return i->number; + } + else i_free(i_remove(ip, *ip)); + } + return 0; +} + + +static local_names * rnames; + +const resource_type * +findresourcetype(const char * name, const struct locale * lang) +{ + local_names * rn = rnames; + variant token; + + while (rn) { + if (rn->lang==lang) break; + rn = rn->next; + } + if (!rn) { + const resource_type * rtl = resourcetypes; + rn = calloc(sizeof(local_names), 1); + rn->next = rnames; + rn->lang = lang; + while (rtl) { + token.v = (void*)rtl; + addtoken(&rn->names, locale_string(lang, rtl->_name[0]), token); + addtoken(&rn->names, locale_string(lang, rtl->_name[1]), token); + rtl=rtl->next; + } + rnames = rn; + } + + if (findtoken(&rn->names, name, &token)==E_TOK_NOMATCH) return NULL; + return (const resource_type*)token.v; +} + +attrib_type at_showitem = { + "showitem" +}; + +static local_names * inames; + +void +init_itemnames(void) +{ + int i; + for (i=0;localenames[i];++i) { + const struct locale * lang = find_locale(localenames[i]); + boolean exist = false; + local_names * in = inames; + + while (in!=NULL) { + if (in->lang==lang) { + exist = true; + break; + } + in = in->next; + } + if (in==NULL) in = calloc(sizeof(local_names), 1); + in->next = inames; + in->lang = lang; + + if (!exist) { + int key; + for (key=0;key!=IMAXHASH;++key) { + const item_type * itl; + for (itl=itemtypes[key];itl;itl=itl->next) { + variant var; + const char * iname = locale_string(lang, itl->rtype->_name[0]); + if (findtoken(&in->names, iname, &var)==E_TOK_NOMATCH || var.v!=itl) { + var.v = (void*)itl; + addtoken(&in->names, iname, var); + addtoken(&in->names, locale_string(lang, itl->rtype->_name[1]), var); + } + } + } + } + inames = in; + } +} + +const item_type * +finditemtype(const char * name, const struct locale * lang) +{ + local_names * in = inames; + variant var; + + while (in!=NULL) { + if (in->lang==lang) break; + in=in->next; + } + if (in==NULL) { + init_itemnames(); + for (in=inames;in->lang!=lang;in=in->next) ; + } + if (findtoken(&in->names, name, &var)==E_TOK_NOMATCH) return NULL; + return (const item_type*)var.v; +} + +static void +init_resourcelimit(attrib * a) +{ + a->data.v = calloc(sizeof(resource_limit), 1); +} + +static void +finalize_resourcelimit(attrib * a) +{ + free(a->data.v); +} + +attrib_type at_resourcelimit = { + "resourcelimit", + init_resourcelimit, + finalize_resourcelimit, +}; + +void +register_resources(void) +{ + register_function((pf_generic)mod_elves_only, "mod_elves_only"); + register_function((pf_generic)mod_dwarves_only, "mod_dwarves_only"); + register_function((pf_generic)res_changeitem, "changeitem"); + register_function((pf_generic)res_changeperson, "changeperson"); + register_function((pf_generic)res_changepeasants, "changepeasants"); + register_function((pf_generic)res_changepermaura, "changepermaura"); + register_function((pf_generic)res_changehp, "changehp"); + register_function((pf_generic)res_changeaura, "changeaura"); + + register_item_use(use_potion, "usepotion"); + register_item_use(use_potion_delayed, "usepotion_delayed"); + register_item_use(use_tacticcrystal, "use_tacticcrystal"); + register_item_use(use_birthdayamulet, "use_birthdayamulet"); + register_item_use(use_warmthpotion, "usewarmthpotion"); + register_item_use(use_bloodpotion, "usebloodpotion"); + register_item_use(use_healingpotion, "usehealingpotion"); + register_item_useonother(use_foolpotion, "usefoolpotion"); + register_item_use(use_mistletoe, "usemistletoe"); + register_item_use(use_magicboost, "usemagicboost"); + register_item_use(use_snowball, "usesnowball"); + + register_item_give(give_horses, "givehorses"); + + /* make sure noone has deleted an I_ tpe without deleting the R_ type that goes with it! */ + assert((int)I_TACTICCRYSTAL == (int)R_TACTICCRYSTAL); +} diff --git a/src/kernel/item.h b/src/kernel/item.h new file mode 100644 index 000000000..516d0856d --- /dev/null +++ b/src/kernel/item.h @@ -0,0 +1,357 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_ITEM +#define H_KRNL_ITEM +#ifdef __cplusplus +extern "C" { +#endif + +struct unit; +struct attrib; +struct attrib_type; +struct region; +struct resource_type; +struct locale; +struct troop; + +typedef struct item { + struct item * next; + const struct item_type * type; + int number; +} item; + +typedef struct resource { + const struct resource_type * type; + int number; + struct resource * next; +} resource; + +/* bitfield values for resource_type::flags */ +#define RTF_NONE 0 +#define RTF_ITEM (1<<0) /* this resource is an item */ +#define RTF_LIMITED (1<<1) /* a resource that's freely available, but in + * limited supply */ +#define RTF_POOLED (1<<2) /* resource is available in pool */ + +/* flags for resource_type::name() */ +#define NMF_PLURAL 0x01 +#define NMF_APPEARANCE 0x02 + +typedef int (*rtype_uchange)(struct unit * user, const struct resource_type * rtype, int delta); +typedef int (*rtype_uget)(const struct unit * user, const struct resource_type * rtype); +typedef char * (*rtype_name)(const struct resource_type * rtype, int flags); +typedef struct resource_type { + /* --- constants --- */ + char * _name[2]; /* wie es heißt */ + char * _appearance[2]; /* wie es für andere aussieht */ + unsigned int flags; + /* --- functions --- */ + rtype_uchange uchange; + rtype_uget uget; + rtype_name name; + /* --- pointers --- */ + struct attrib * attribs; + struct resource_type * next; + unsigned int hashkey; + struct item_type * itype; + struct potion_type * ptype; + struct luxury_type * ltype; + struct weapon_type * wtype; + struct armor_type * atype; +} resource_type; +extern resource_type * resourcetypes; +extern const char* resourcename(const resource_type * rtype, int flags); +extern const resource_type * findresourcetype(const char * name, const struct locale * lang); + +/* resource-limits for regions */ +#define RMF_SKILL 0x01 /* int, bonus on resource production skill */ +#define RMF_SAVEMATERIAL 0x02 /* float, multiplier on resource usage */ +#define RMF_SAVERESOURCE 0x03 /* int, bonus on resource production skill */ +#define RMF_REQUIREDBUILDING 0x04 /* building, required to build */ + +typedef struct resource_mod { + variant value; + const struct building_type * btype; + const struct race * race; + unsigned int flags; +} resource_mod; + +extern struct attrib_type at_resourcelimit; +typedef int (*rlimit_limit)(const struct region * r, const struct resource_type * rtype); +typedef void (*rlimit_produce)(struct region * r, const struct resource_type * rtype, int n); +typedef struct resource_limit { + rlimit_limit limit; + rlimit_produce produce; + unsigned int guard; /* how to guard against theft */ + int value; + resource_mod * modifiers; +} resource_limit; + + +/* bitfield values for item_type::flags */ +#define ITF_NONE 0x0000 +#define ITF_HERB 0x0001 /* this item is a herb */ +#define ITF_CURSED 0x0010 /* cursed object, cannot be given away */ +#define ITF_NOTLOST 0x0020 /* special object (quests), cannot be lost through death etc. */ +#define ITF_BIG 0x0040 /* big item, e.g. does not fit in a bag of holding */ +#define ITF_ANIMAL 0x0080 /* an animal */ +#define ITF_VEHICLE 0x0100 /* a vehicle, drawn by two animals */ + +/* error codes for item_type::use */ +#define ECUSTOM -1; +#define ENOITEM -2; +#define ENOSKILL -3; +#define EUNUSABLE -4; + +typedef struct itemtype_list { + struct itemtype_list * next; + const struct item_type * type; +} itemtype_list; + +typedef struct item_type { + resource_type * rtype; + /* --- constants --- */ + unsigned int flags; + int weight; + int capacity; + struct construction * construction; + /* --- functions --- */ + boolean (*canuse)(const struct unit * user, const struct item_type * itype); + int (*use)(struct unit * user, const struct item_type * itype, int amount, struct order * ord); + int (*useonother)(struct unit * user, int targetno, const struct item_type * itype, int amount, struct order * ord); + int (*give)(struct unit * src, struct unit * dest, const struct item_type * itm, int number, struct order * ord); +#if SCORE_MODULE + int score; +#endif + struct item_type * next; +} item_type; + +extern const item_type * finditemtype(const char * name, const struct locale * lang); +extern void init_itemnames(void); + +typedef struct luxury_type { + struct luxury_type * next; + const item_type * itype; + int price; +} luxury_type; +extern luxury_type * luxurytypes; + +typedef struct potion_type { + struct potion_type * next; + const item_type * itype; + int level; +} potion_type; +extern potion_type * potiontypes; + +#define WMF_WALKING 0x0001 +#define WMF_RIDING 0x0002 +#define WMF_ANYONE 0x000F /* convenience */ + +#define WMF_AGAINST_RIDING 0x0010 +#define WMF_AGAINST_WALKING 0x0020 +#define WMF_AGAINST_ANYONE 0x00F0 /* convenience */ + +#define WMF_OFFENSIVE 0x0100 +#define WMF_DEFENSIVE 0x0200 +#define WMF_ANYTIME 0x0F00 /* convenience */ + +#define WMF_DAMAGE 0x1000 +#define WMF_SKILL 0x2000 +#define WMF_MISSILE_TARGET 0x4000 + +struct race_list; +typedef struct weapon_mod { + int value; + unsigned int flags; + struct race_list * races; +} weapon_mod; + +#define ATF_NONE 0x00 +#define ATF_SHIELD 0x01 +#define ATF_LAEN 0x02 + +typedef struct armor_type { + const item_type * itype; + double penalty; + double magres; + int prot; + float projectile; /* chance, dass ein projektil abprallt */ + unsigned int flags; +} armor_type; + +#define WTF_NONE 0x00 +#define WTF_MISSILE 0x01 +#define WTF_MAGICAL 0x02 +#define WTF_PIERCE 0x04 +#define WTF_CUT 0x08 +#define WTF_BLUNT 0x10 +#define WTF_SIEGE 0x20 +#define WTF_ARMORPIERCING 0x40 /* armor has only half value */ +#define WTF_HORSEBONUS 0x80 +#define WTF_USESHIELD 0x100 + +typedef struct weapon_type { + const item_type * itype; + const char * damage[2]; + unsigned int flags; + skill_t skill; + int minskill; + int offmod; + int defmod; + double magres; + int reload; /* time to reload this weapon */ + weapon_mod * modifiers; + /* --- functions --- */ + boolean (*attack)(const struct troop *, const struct weapon_type *, int *deaths); +} weapon_type; + +extern void rt_register(resource_type * it); +extern resource_type * rt_find(const char * name); +extern item_type * it_find(const char * name); + +extern void it_register(item_type * it); +extern void wt_register(weapon_type * wt); + +extern const item_type * resource2item(const resource_type * rtype); +extern const resource_type * item2resource(const item_type * i); + +extern const weapon_type * resource2weapon(const resource_type * i); +extern const potion_type * resource2potion(const resource_type * i); +extern const luxury_type * resource2luxury(const resource_type * i); + +extern item ** i_find(item ** pi, const item_type * it); +extern item * const * i_findc(item * const * pi, const item_type * it); +extern item * i_add(item ** pi, item * it); +extern void i_merge(item ** pi, item ** si); +extern item * i_remove(item ** pi, item * it); +extern void i_free(item * i); +extern void i_freeall(item ** i); +extern item * i_new(const item_type * it, int number); + +/* convenience: */ +extern item * i_change(item ** items, const item_type * it, int delta); +extern int i_get(const item * i, const item_type * it); + +/* creation */ +extern resource_type * new_resourcetype(const char ** names, const char ** appearances, int flags); +extern item_type * new_itemtype(resource_type * rtype, int iflags, int weight, int capacity); +extern luxury_type * new_luxurytype(item_type * itype, int price); +extern weapon_type * new_weapontype(item_type * itype, int wflags, double magres, const char* damage[], int offmod, int defmod, int reload, skill_t sk, int minskill); +extern armor_type * new_armortype(item_type * itype, double penalty, double magres, int prot, unsigned int flags); +extern potion_type * new_potiontype(item_type * itype, int level); + +/* for lack of another file: */ + +/* sonstige resourcen */ +extern resource_type * r_silver; +extern resource_type * r_aura; +extern resource_type * r_permaura; +extern resource_type * r_unit; +extern resource_type * r_hp; + +enum { + I_IRON, /* 0 */ + I_STONE, + I_HORSE, + /* alte Artefakte */ + I_AMULET_OF_HEALING, + I_AMULET_OF_TRUE_SEEING, + I_RING_OF_INVISIBILITY, + I_RING_OF_POWER, + I_CHASTITY_BELT, /* bleibt */ + I_LAEN, + I_FEENSTIEFEL, + I_BIRTHDAYAMULET, + I_PEGASUS, + I_ELVENHORSE, + I_DOLPHIN, + I_RING_OF_NIMBLEFINGER, + I_TROLLBELT, + I_PRESSCARD, + I_AURAKULUM, + I_SPHERE_OF_INVISIBILITY, + I_BAG_OF_HOLDING, + I_SACK_OF_CONSERVATION, + I_TACTICCRYSTAL, + MAX_ITEMS /* do not use outside item.c ! */ +}; + +enum { + /* ITEMS: */ + R_IRON, + R_STONE, + R_HORSE, + /**/ + R_AMULET_OF_HEALING, + R_AMULET_OF_TRUE_SEEING, + R_RING_OF_INVISIBILITY, + R_RING_OF_POWER, + R_CHASTITY_BELT, + R_EOG, + R_FEENSTIEFEL, + R_BIRTHDAYAMULET, + R_PEGASUS, + R_UNICORN, + R_DOLPHIN, + R_RING_OF_NIMBLEFINGER, + R_TROLLBELT, + R_PRESSCARD, + R_AURAKULUM, + R_SPHERE_OF_INVISIBILITY, + R_BAG_OF_HOLDING, + R_SACK_OF_CONSERVATION, + R_TACTICCRYSTAL, + + /* SONSTIGE */ + R_SILVER, + R_AURA, /* Aura */ + R_PERMAURA, /* Permanente Aura */ + + MAX_RESOURCES, /* do not use outside item.c ! */ + NORESOURCE = -1 +}; + +extern const struct potion_type * oldpotiontype[]; +extern const struct item_type * olditemtype[]; +extern const struct resource_type * oldresourcetype[]; + +int get_item(const struct unit *, item_t); +int set_item(struct unit *, item_t, int); + +int get_money(const struct unit *); +int set_money(struct unit *, int); +int change_money(struct unit *, int); +int res_changeitem(struct unit * u, const resource_type * rtype, int delta); + +extern struct attrib_type at_showitem; /* show this potion's description */ + +extern void register_resources(void); +extern void init_resources(void); +extern void init_itemtypes(void); + +extern void register_item_give(int (*foo) (struct unit *, struct unit *, const struct item_type *, int, struct order *), const char * name); +extern void register_item_use(int (*foo) (struct unit *, const struct item_type *, int, struct order *), const char * name); +extern void register_item_useonother(int (*foo) (struct unit *, int, const struct item_type *, int, struct order *), const char * name); + +extern struct item_type *i_silver; + +#ifdef __cplusplus +} +#endif +#endif /* _ITEM_H */ diff --git a/src/kernel/magic.c b/src/kernel/magic.c new file mode 100644 index 000000000..a1e1251b6 --- /dev/null +++ b/src/kernel/magic.c @@ -0,0 +1,2923 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "magic.h" + +#include "building.h" +#include "curse.h" +#include "faction.h" +#include "item.h" +#include "message.h" +#include "objtypes.h" +#include "order.h" +#include "pathfinder.h" +#include "plane.h" +#include "pool.h" +#include "race.h" +#include "region.h" +#include "ship.h" +#include "skill.h" +#include "spell.h" +#include "teleport.h" +#include "terrain.h" +#include "unit.h" +#include "version.h" + +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include +#include + +/* ------------------------------------------------------------- */ + +const char *magic_school[MAXMAGIETYP] = +{ + "gray", + "illaun", + "tybied", + "cerddor", + "gwyrrd", + "draig", + "common" +}; + +attrib_type at_reportspell = { + "reportspell", NULL, NULL, NULL, NO_WRITE, NO_READ +}; + +/** + ** at_icastle + ** TODO: separate castle-appearance from illusion-effects + **/ + +static double +MagicRegeneration(void) +{ + static double value = -1.0; + if (value<0) { + const char * str = get_param(global.parameters, "magic.regeneration"); + value = str?atof(str):1.0; + } + return value; +} + +double +MagicPower(void) +{ + static double value = -1.0; + if (value<0) { + const char * str = get_param(global.parameters, "magic.power"); + value = str?atof(str):1.0; + } + return value; +} + +static int +a_readicastle(attrib * a, void * owner, struct storage * store) +{ + icastle_data * data = (icastle_data*)a->data.v; + variant bno; + char token[32]; + store->r_tok_buf(store, token, sizeof(token)); + bno.i = store->r_int(store); + data->time = store->r_int(store); + data->building = findbuilding(bno.i); + if (!data->building) { + /* this shouldn't happen, but just in case it does: */ + ur_add(bno, &data->building, resolve_building); + } + data->type = bt_find(token); + return AT_READ_OK; +} + +static void +a_writeicastle(const attrib * a, const void * owner, struct storage * store) +{ + icastle_data * data = (icastle_data*)a->data.v; + store->w_tok(store, data->type->_name); + store->w_int(store, data->building->no); + store->w_int(store, data->time); +} + +static int +a_ageicastle(struct attrib * a) +{ + icastle_data * data = (icastle_data*)a->data.v; + if (data->time<=0) { + building * b = data->building; + region * r = b->region; + ADDMSG(&r->msgs, msg_message("icastle_dissolve", "building", b)); + /* remove_building lets units leave the building */ + remove_building(&r->buildings, b); + return AT_AGE_REMOVE; + } + else data->time--; + return AT_AGE_KEEP; +} + +static void +a_initicastle(struct attrib * a) +{ + a->data.v = calloc(sizeof(icastle_data), 1); +} + +static void +a_finalizeicastle(struct attrib * a) +{ + free(a->data.v); +} + +attrib_type at_icastle = { + "zauber_icastle", + a_initicastle, + a_finalizeicastle, + a_ageicastle, + a_writeicastle, + a_readicastle +}; + +/* ------------------------------------------------------------- */ + +extern int dice(int count, int value); + +/* ------------------------------------------------------------- */ +/* aus dem alten System übriggebliegene Funktionen, die bei der + * Umwandlung von alt nach neu gebraucht werden */ +/* ------------------------------------------------------------- */ + +static void +init_mage(attrib * a) { + a->data.v = calloc(sizeof(sc_mage), 1); +} + +static void +free_mage(attrib * a) +{ + sc_mage * mage = (sc_mage*)a->data.v; + freelist(mage->spells); + free(mage); +} + +int FactionSpells(void) +{ + static int rules_factionspells = -1; + if (rules_factionspells<0) { + rules_factionspells = get_param_int(global.parameters, "rules.magic.factionlist", 0); + } + return rules_factionspells; +} + +void read_spellist(struct spell_list ** slistp, magic_t mtype, struct storage * store) +{ + for (;;) { + spell * sp; + char spname[64]; + + if (store->versionr_int(store); + if (i < 0) break; + sp = find_spellbyid(M_NONE, (spellid_t)i); + } else { + store->r_tok_buf(store, spname, sizeof(spname)); + if (strcmp(spname, "end")==0) break; + sp = find_spell(mtype, spname); + } + if (sp!=NULL) { + add_spell(slistp, sp); + } + } +} + +static int +read_mage(attrib * a, void * owner, struct storage * store) +{ + int i, mtype; + sc_mage * mage = (sc_mage*)a->data.v; + char spname[64]; + + mtype = store->r_int(store); + mage->spellpoints = store->r_int(store); + mage->spchange = store->r_int(store); + mage->magietyp = (magic_t)mtype; + for (i=0;i!=MAXCOMBATSPELLS;++i) { + spell * sp = NULL; + int level = 0; + if (store->versionr_int(store); + level = store->r_int(store); + if (spid>=0) { + sp = find_spellbyid(mage->magietyp, (spellid_t)spid); + } + } else { + store->r_tok_buf(store, spname, sizeof(spname)); + level = store->r_int(store); + + if (strcmp("none", spname)!=0) { + sp = find_spell(mage->magietyp, spname); + } + } + if (sp && level>=0) { + int slot = -1; + if (sp->sptyp & PRECOMBATSPELL) slot = 0; + else if (sp->sptyp & COMBATSPELL) slot = 1; + else if (sp->sptyp & POSTCOMBATSPELL) slot = 2; + if (slot>=0) { + mage->combatspells[slot].level = level; + mage->combatspells[slot].sp = sp; + } + } + } + read_spellist(&mage->spells, mage->magietyp, store); + return AT_READ_OK; +} + +void write_spelllist(const spell_list * slist, struct storage * store) +{ + while (slist!=NULL) { + spell * sp = slist->data; + store->w_tok(store, sp->sname); + slist = slist->next; + } + store->w_tok(store, "end"); +} + +static void +write_mage(const attrib * a, const void * owner, struct storage * store) +{ + int i; + sc_mage *mage = (sc_mage*)a->data.v; + + store->w_int(store, mage->magietyp); + store->w_int(store, mage->spellpoints); + store->w_int(store, mage->spchange); + for (i=0;i!=MAXCOMBATSPELLS;++i) { + store->w_tok(store, mage->combatspells[i].sp?mage->combatspells[i].sp->sname:"none"); + store->w_int(store, mage->combatspells[i].level); + } + write_spelllist(mage->spells, store); +} + +attrib_type at_mage = { + "mage", + init_mage, + free_mage, + NULL, + write_mage, + read_mage, + ATF_UNIQUE +}; + +boolean +is_mage(const unit * u) +{ + return i2b(get_mage(u) != NULL); +} + +sc_mage * +get_mage(const unit * u) +{ + if (has_skill(u, SK_MAGIC)) { + attrib * a = a_find(u->attribs, &at_mage); + if (a) return a->data.v; + } + return (sc_mage *) NULL; +} + +/* ------------------------------------------------------------- */ +/* Ausgabe der Spruchbeschreibungen +* Anzeige des Spruchs nur, wenn die Stufe des besten Magiers vorher +* kleiner war (u->faction->seenspells). Ansonsten muss nur geprüft +* werden, ob dieser Magier den Spruch schon kennt, und andernfalls der +* Spruch zu seiner List-of-known-spells hinzugefügt werden. +*/ + + +static int +read_seenspell(attrib * a, void * owner, struct storage * store) +{ + int i; + spell * sp = NULL; + char token[32]; + + store->r_tok_buf(store, token, sizeof(token)); + i = atoi(token); + if (i!=0) { + sp = find_spellbyid(M_NONE, (spellid_t)i); + } else { + int mtype; + mtype = store->r_int(store); + sp = find_spell((magic_t)mtype, token); + } + if (sp==NULL) { + /* log_error(("could not find seenspell '%s'\n", buf)); */ + return AT_READ_FAIL; + } + a->data.v = sp; + return AT_READ_OK; +} + +static void +write_seenspell(const attrib * a, const void * owner, struct storage * store) +{ + const spell * sp = (const spell*)a->data.v; + store->w_tok(store, sp->sname); + store->w_int(store, sp->magietyp); +} + +attrib_type at_seenspell = { + "seenspell", NULL, NULL, NULL, write_seenspell, read_seenspell +}; + +static boolean +already_seen(const faction * f, const spell * sp) +{ + attrib *a; + + for (a = a_find(f->attribs, &at_seenspell); a && a->type==&at_seenspell; a=a->next) { + if (a->data.v==sp) return true; + } + return false; +} + +static boolean know_school(const faction * f, magic_t school) +{ + static int common = MAXMAGIETYP; + if (f->magiegebiet==school) return true; + if (common==MAXMAGIETYP) { + const char * common_school = get_param(global.parameters, "rules.magic.common"); + if (common_school) { + for (common=0;common!=MAXMAGIETYP;++common) { + if (strcmp(common_school, magic_school[common])==0) break; + } + if (common==MAXMAGIETYP) { + common = M_NONE; + } + } else { + return false; + } + } + return school==common; +} + +#define COMMONSPELLS 1 /* number of new common spells per level */ +#define MAXSPELLS 256 + +/** update the spellbook with a new level +* Written for Eressea 1.1 +*/ +void +update_spellbook(faction * f, int level) +{ + spell * commonspells[MAXSPELLS]; + int numspells = 0; + spell_list * slist; + + for (slist=spells;slist!=NULL;slist=slist->next) { + spell * sp = slist->data; + if (sp->magietyp == M_COMMON && level>f->max_spelllevel && sp->level<=level) { + commonspells[numspells++] = sp; + } else { + if (know_school(f, sp->magietyp) && sp->level <= level) { + if (!has_spell(f->spellbook, sp)) { + add_spell(&f->spellbook, sp); + } + } + } + } + while (numspells>0 && level>f->max_spelllevel) { + int i; + for (i=0;i!=COMMONSPELLS;++i) { + int maxspell = numspells; + int spellno = -1; + spell * sp; + do { + if (spellno==maxspell) { + --maxspell; + } + spellno = rng_int() % maxspell; + sp = commonspells[spellno]; + } + while (maxspell>0 && sp && sp->level<=f->max_spelllevel && !has_spell(f->spellbook, sp)); + + if (sp) { + add_spell(&f->spellbook, sp); + commonspells[spellno] = 0; + } + } + ++f->max_spelllevel; + } +} + +void +updatespelllist(unit * u) +{ + int sk = eff_skill(u, SK_MAGIC, u->region); + spell_list * slist = spells; + struct sc_mage * mage = get_mage(u); + boolean ismonster = is_monsters(u->faction); + + if (mage->magietyp==M_GRAY) { + /* Magier mit M_GRAY bekommen weder Sprüche angezeigt noch + * neue Sprüche in ihre List-of-known-spells. Das sind zb alle alten + * Drachen, die noch den Skill Magie haben, und alle familiars */ + return; + } + + if (FactionSpells()) { + slist = u->faction->spellbook; + } + + for (;slist!=NULL;slist=slist->next) { + spell * sp = slist->data; + if (sp->level<=sk) { + boolean know = u_hasspell(u, sp); + + if (know || sp->magietyp==M_COMMON || know_school(u->faction, sp->magietyp)) { + faction * f = u->faction; + + if (!know) add_spell(get_spelllist(mage, u->faction), sp); + if (!ismonster && !already_seen(u->faction, sp)) { + a_add(&f->attribs, a_new(&at_reportspell))->data.v = sp; + a_add(&f->attribs, a_new(&at_seenspell))->data.v = sp; + } + } + } + } + +} + +/* ------------------------------------------------------------- */ +/* Erzeugen eines neuen Magiers */ +sc_mage * +create_mage(unit * u, magic_t mtyp) +{ + sc_mage *mage; + attrib *a; + + a = a_find(u->attribs, &at_mage); + if (a!=NULL) { + a_remove(&u->attribs, a); + } + a = a_add(&u->attribs, a_new(&at_mage)); + mage = a->data.v; + + mage->magietyp = mtyp; + return mage; +} + +/* ------------------------------------------------------------- */ +/* Funktionen für die Bearbeitung der List-of-known-spells */ + +void +add_spell(spell_list ** slistp, spell * sp) +{ + if (slistp==NULL) { + log_error(("add_spell: unit is not a mage.\n")); + } else { + spell_list ** slist = spelllist_find(slistp, sp); + if (*slist) { + spell * psp = (*slist)->data; + if (psp==sp) { + log_error(("add_spell: unit already has spell '%s'.\n", sp->sname)); + return; + } + } + spelllist_add(slist, sp); + } +} + +boolean +has_spell(spell_list * slist, const spell * sp) +{ + if (slist!=NULL) { + spell_list * sfind = *spelllist_find(&slist, sp); + return sfind!=NULL && sfind->data==sp; + } + return false; +} + +boolean +u_hasspell(const struct unit *u, const struct spell * sp) +{ + sc_mage * mage = get_mage(u); + if (mage) return has_spell(mage->spells, sp); + return false; +} + +/* ------------------------------------------------------------- */ +/* Eingestellte Kampfzauberstufe ermitteln */ + +int +get_combatspelllevel(const unit *u, int nr) +{ + sc_mage *m = get_mage(u); + + assert(nr < MAXCOMBATSPELLS); + if (m) { + int level = eff_skill(u, SK_MAGIC, u->region); + return MIN(m->combatspells[nr].level, level); + } + return -1; +} + +/* ------------------------------------------------------------- */ +/* Kampfzauber ermitteln, setzen oder löschen */ + +const spell* +get_combatspell(const unit *u, int nr) +{ + sc_mage *m; + + assert(nr < MAXCOMBATSPELLS); + m = get_mage(u); + if (m) { + return m->combatspells[nr].sp; + } else if (u->race->precombatspell != NULL) { + return u->race->precombatspell; + } + + return NULL; +} + +void +set_combatspell(unit *u, spell *sp, struct order * ord, int level) +{ + sc_mage *m = get_mage(u); + int i = -1; + if (!m) return; + + /* knowsspell prüft auf ist_magier, ist_spruch, kennt_spruch */ + if (knowsspell(u->region, u, sp) == false){ + /* Fehler 'Spell not found' */ + cmistake(u, ord, 173, MSG_MAGIC); + return; + } + if (!u_hasspell(u, sp)) { + /* Diesen Zauber kennt die Einheit nicht */ + cmistake(u, ord, 169, MSG_MAGIC); + return; + } + if (!(sp->sptyp & ISCOMBATSPELL)) { + /* Diesen Kampfzauber gibt es nicht */ + cmistake(u, ord, 171, MSG_MAGIC); + return; + } + + if (sp->sptyp & PRECOMBATSPELL) i = 0; + else if (sp->sptyp & COMBATSPELL) i = 1; + else if (sp->sptyp & POSTCOMBATSPELL) i = 2; + assert(i>=0); + m->combatspells[i].sp = sp; + m->combatspells[i].level = level; + return; +} + +void +unset_combatspell(unit *u, spell *sp) +{ + sc_mage *m; + int nr = 0; + int i; + + m = get_mage(u); + if (!m) return; + + if (!sp) { + for (i=0;icombatspells[i].sp = NULL; + } + } + else if (sp->sptyp & PRECOMBATSPELL) { + if (sp != get_combatspell(u,0)) + return; + } else if (sp->sptyp & COMBATSPELL) { + if (sp != get_combatspell(u,1)) { + return; + } + nr = 1; + } else if (sp->sptyp & POSTCOMBATSPELL) { + if (sp != get_combatspell(u,2)) { + return; + } + nr = 2; + } + m->combatspells[nr].sp = NULL; + m->combatspells[nr].level = 0; + return; +} + +/* ------------------------------------------------------------- */ +/* Gibt die aktuelle Anzahl der Magiepunkte der Einheit zurück */ +int +get_spellpoints(const unit * u) +{ + sc_mage *m; + + m = get_mage(u); + if (!m) return 0; + + return m->spellpoints; +} + +void +set_spellpoints(unit * u, int sp) +{ + sc_mage *m; + + m = get_mage(u); + if (!m) return; + + m->spellpoints = sp; + + return; +} + +/* + * verändert die Anzahl der Magiepunkte der Einheit um +mp + */ +int +change_spellpoints(unit * u, int mp) +{ + sc_mage *m; + int sp; + + m = get_mage(u); + if (!m) return 0; + + /* verhindere negative Magiepunkte */ + sp = MAX(m->spellpoints + mp, 0); + m->spellpoints = sp; + + return sp; +} + +/* bietet die Möglichkeit, die maximale Anzahl der Magiepunkte mit + * Regionszaubern oder Attributen zu beinflussen + */ +static int +get_spchange(const unit * u) +{ + sc_mage *m; + + m = get_mage(u); + if (!m) return 0; + + return m->spchange; +} + +/* ein Magier kann normalerweise maximal Stufe^2.1/1.2+1 Magiepunkte + * haben. + * Manche Rassen haben einen zusätzlichen Multiplikator + * Durch Talentverlust (zB Insekten im Berg) können negative Werte + * entstehen + */ + +/* Artefakt der Stärke + * Ermöglicht dem Magier mehr Magiepunkte zu 'speichern' + */ +/** TODO: at_skillmod daraus machen */ +static int +use_item_aura(const region * r, const unit * u) +{ + int sk, n; + + sk = eff_skill(u, SK_MAGIC, r); + n = (int)(sk * sk * u->race->maxaura / 4); + + return n; +} + +int +max_spellpoints(const region * r, const unit * u) +{ + int sk; + double n, msp; + double potenz = 2.1; + double divisor = 1.2; + + sk = eff_skill(u, SK_MAGIC, r); + msp = u->race->maxaura*(pow(sk, potenz)/divisor+1) + get_spchange(u); + + if (get_item(u, I_AURAKULUM) > 0) { + msp += use_item_aura(r, u); + } + n = get_curseeffect(u->attribs, C_AURA, 0); + if (n>0) msp = (msp*n)/100; + + return MAX((int)msp, 0); +} + +int +change_maxspellpoints(unit * u, int csp) +{ + sc_mage *m; + + m = get_mage(u); + if (!m) return 0; + + m->spchange += csp; + return max_spellpoints(u->region, u); +} + +/* ------------------------------------------------------------- */ +/* Counter für die bereits gezauberte Anzahl Sprüche pro Runde. + * Um nur die Zahl der bereits gezauberten Sprüche zu ermitteln mit + * step = 0 aufrufen. + */ +int +countspells(unit *u, int step) +{ + sc_mage *m; + int count; + + m = get_mage(u); + if (!m) + return 0; + + if (step == 0) + return m->spellcount; + + count = m->spellcount + step; + + /* negative Werte abfangen. */ + m->spellcount = MAX(0,count); + + return m->spellcount; +} + +/* ------------------------------------------------------------- */ +/* Die für den Spruch benötigte Aura pro Stufe. + * Die Grundkosten pro Stufe werden hier um 2^count erhöht. Der + * Parameter count ist dabei die Anzahl der bereits gezauberten Sprüche + */ +int +spellcost(unit *u, const spell * sp) +{ + int k, aura = 0; + int count = countspells(u, 0); + + for (k = 0; sp->components[k].type; k++) { + if (sp->components[k].type == r_aura) { + aura = sp->components[k].amount; + } + } + aura *= (1<components[k].type; k++) { + if (costtyp == SPC_LINEAR) return SPC_LINEAR; + + if (sp->components[k].cost == SPC_LINEAR) { + return SPC_LINEAR; + } + + /* wenn keine Fixkosten, Typ übernehmen */ + if (sp->components[k].cost != SPC_FIX) { + costtyp = sp->components[k].cost; + } + } + return costtyp; +} + +/* ------------------------------------------------------------- */ +/* durch Komponenten und cast_level begrenzter maximal möglicher + * Level + * Da die Funktion nicht alle Komponenten durchprobiert sondern beim + * ersten Fehler abbricht, muss die Fehlermeldung später mit cancast() + * generiert werden. + * */ +int +eff_spelllevel(unit *u, const spell * sp, int cast_level, int range) +{ + int k, maxlevel, needplevel; + int costtyp = SPC_FIX; + + for (k = 0; sp->components[k].type; k++) { + if (cast_level == 0) + return 0; + + if (sp->components[k].amount > 0) { + /* Die Kosten für Aura sind auch von der Zahl der bereits + * gezauberten Sprüche abhängig */ + if (sp->components[k].type == r_aura) { + needplevel = spellcost(u, sp) * range; + } else { + needplevel = sp->components[k].amount * range; + } + maxlevel = get_pooled(u, sp->components[k].type, GET_DEFAULT, needplevel*cast_level)/needplevel; + + /* sind die Kosten fix, so muss die Komponente nur einmal vorhanden + * sein und der cast_level ändert sich nicht */ + if (sp->components[k].cost == SPC_FIX) { + if (maxlevel < 1) cast_level = 0; + /* ansonsten wird das Minimum aus maximal möglicher Stufe und der + * gewünschten gebildet */ + } else if (sp->components[k].cost == SPC_LEVEL) { + costtyp = SPC_LEVEL; + cast_level = MIN(cast_level, maxlevel); + /* bei Typ Linear müssen die Kosten in Höhe der Stufe vorhanden + * sein, ansonsten schlägt der Spruch fehl */ + } else if (sp->components[k].cost == SPC_LINEAR) { + costtyp = SPC_LINEAR; + if (maxlevel < cast_level) cast_level = 0; + } + } + } + /* Ein Spruch mit Fixkosten wird immer mit der Stufe des Spruchs und + * nicht auf der Stufe des Magiers gezaubert */ + if (costtyp == SPC_FIX) { + cast_level = MIN(cast_level, sp->level); + } + + return cast_level; +} + +/* ------------------------------------------------------------- */ +/* Die Spruchgrundkosten werden mit der Entfernung (Farcasting) + * multipliziert, wobei die Aurakosten ein Sonderfall sind, da sie sich + * auch durch die Menge der bereits gezauberten Sprüche erhöht. + * Je nach Kostenart werden dann die Komponenten noch mit cast_level + * multipliziert. + */ +void +pay_spell(unit * u, const spell * sp, int cast_level, int range) +{ + int k; + int resuse; + + for (k = 0; sp->components[k].type; k++) { + if (sp->components[k].type == r_aura) { + resuse = spellcost(u, sp) * range; + } else { + resuse = sp->components[k].amount * range; + } + + if (sp->components[k].cost == SPC_LINEAR + || sp->components[k].cost == SPC_LEVEL) + { + resuse *= cast_level; + } + + use_pooled(u, sp->components[k].type, GET_DEFAULT, resuse); + } +} + + +/* ------------------------------------------------------------- */ +/* Ein Magier kennt den Spruch und kann sich die Beschreibung anzeigen + * lassen, wenn diese in seiner Spruchliste steht. Zaubern muss er ihn + * aber dann immer noch nicht können, vieleicht ist seine Stufe derzeit + * nicht ausreichend oder die Komponenten fehlen. + */ +boolean +knowsspell(const region * r, const unit * u, const spell * sp) +{ + sc_mage * mage; + /* Ist überhaupt ein gültiger Spruch angegeben? */ + if (!sp || sp->id == 0) { + return false; + } + /* Magier? */ + mage = get_mage(u); + if (mage == NULL) { + log_warning(("%s ist kein Magier, versucht aber zu zaubern.\n", + unitname(u))); + return false; + } + /* steht der Spruch in der Spruchliste? */ + if (!u_hasspell(u, sp)) { + /* ist der Spruch aus einem anderen Magiegebiet? */ + if (know_school(u->faction, sp->magietyp)) { + return false; + } + if (eff_skill(u, SK_MAGIC, u->region) >= sp->level) { + log_warning(("%s ist hat die erforderliche Stufe, kennt aber %s nicht.\n", + unitname(u), spell_name(sp, default_locale))); + } + return false; + } + + /* hier sollten alle potentiellen Fehler abgefangen sein */ + return true; +} + +/* Um einen Spruch zu beherrschen, muss der Magier die Stufe des + * Spruchs besitzen, nicht nur wissen, das es ihn gibt (also den Spruch + * in seiner Spruchliste haben). + * Kosten für einen Spruch können Magiepunkte, Silber, Kraeuter + * und sonstige Gegenstaende sein. + */ + +boolean +cancast(unit * u, const spell * sp, int level, int range, struct order * ord) +{ + int k; + int itemanz; + resource * reslist = NULL; + + if (knowsspell(u->region, u, sp) == false) { + /* Diesen Zauber kennt die Einheit nicht */ + cmistake(u, ord, 173, MSG_MAGIC); + return false; + } + /* reicht die Stufe aus? */ + if (eff_skill(u, SK_MAGIC, u->region) < sp->level) { + /* die Einheit ist nicht erfahren genug für diesen Zauber */ + cmistake(u, ord, 169, MSG_MAGIC); + return false; + } + + for (k = 0; sp->components[k].type; ++k) { + if (sp->components[k].amount > 0) { + const resource_type * rtype = sp->components[k].type; + int itemhave; + + /* Die Kosten für Aura sind auch von der Zahl der bereits + * gezauberten Sprüche abhängig */ + if (rtype == r_aura) { + itemanz = spellcost(u, sp) * range; + } else { + itemanz = sp->components[k].amount * range; + } + + /* sind die Kosten stufenabhängig, so muss itemanz noch mit dem + * level multipliziert werden */ + switch(sp->components[k].cost) { + case SPC_LEVEL: + case SPC_LINEAR: + itemanz *= level; + break; + case SPC_FIX: + default: + break; + } + + itemhave = get_pooled(u, rtype, GET_DEFAULT, itemanz); + if (itemhave < itemanz) { + resource * res = malloc(sizeof(resource)); + res->number = itemanz-itemhave; + res->type = rtype; + res->next = reslist; + reslist = res; + } + } + } + if (reslist!=NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "missing_components_list", "list", reslist)); + return false; + } + return true; +} + +/* ------------------------------------------------------------- */ +/* generische Spruchstaerke, + * + * setzt sich derzeit aus der Stufe des Magiers, Magieturmeffekt, + * Spruchitems und Antimagiefeldern zusammen. Es koennen noch die + * Stufe des Spruchs und Magiekosten mit einfliessen. + * + * Die effektive Spruchstärke und ihre Auswirkungen werden in der + * Spruchfunktionsroutine ermittelt. + */ + +double +spellpower(region * r, unit * u, const spell * sp, int cast_level, struct order * ord) +{ + curse * c; + double force = cast_level; + int elf_power = -1; + + if (sp==NULL) { + return 0; + } else { + /* Bonus durch Magieturm und gesegneten Steinkreis */ + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + if (btype && btype->flags & BTF_MAGIC) ++force; + } + + if (get_item(u, I_RING_OF_POWER) > 0) ++force; + if (elf_power<0) { + elf_power = get_param_int(global.parameters, "rules.magic.elfpower", 0); + } + if (elf_power && u->race==new_race[RC_ELF] && r_isforest(r)) { + ++force; + } + + /* Antimagie in der Zielregion */ + c = get_curse(r->attribs, ct_find("antimagiczone")); + if (curse_active(c)) { + unit * mage = c->magician; + force -= curse_geteffect(c); + curse_changevigour(&r->attribs, c, (float)-cast_level); + cmistake(u, ord, 185, MSG_MAGIC); + if (mage!=NULL && mage->faction!=NULL) { + if (force>0) { + ADDMSG(&mage->faction->msgs, msg_message("reduce_spell", "self mage region", mage, u, r)); + } else { + ADDMSG(&mage->faction->msgs, msg_message("block_spell", "self mage region", mage, u, r)); + } + } + } + + /* Patzerfluch-Effekt: */ + c = get_curse(r->attribs, ct_find("fumble")); + if (curse_active(c)) { + unit * mage = c->magician; + force -= curse_geteffect(c); + curse_changevigour(&u->attribs, c, -1); + cmistake(u, ord, 185, MSG_MAGIC); + if (mage!=NULL && mage->faction!=NULL) { + if (force>0) { + ADDMSG(&mage->faction->msgs, msg_message("reduce_spell", "self mage region", mage, u, r)); + } else { + ADDMSG(&mage->faction->msgs, msg_message("block_spell", "self mage region", mage, u, r)); + } + } + } + + force = force * MagicPower(); + + return MAX(force, 0); +} + +/* ------------------------------------------------------------- */ +/* farcasting() == 1 -> gleiche Region, da man mit Null nicht vernünfigt + * rechnen kann */ +static int +farcasting(unit *magician, region *r) +{ + int dist; + int mult; + + if (!r) { + return INT_MAX; + } + + dist = koor_distance(r->x, r->y, magician->region->x, magician->region->y); + + if (dist > 24) return INT_MAX; + + mult = 1 << dist; + if (dist > 1) { + if (!path_exists(magician->region, r, dist*2, allowed_fly)) mult = INT_MAX; + } + + return mult; +} + + +/* ------------------------------------------------------------- */ +/* Antimagie - Magieresistenz */ +/* ------------------------------------------------------------- */ + +/* allgemeine Magieresistenz einer Einheit, + * reduziert magischen Schaden */ +double +magic_resistance(unit *target) +{ + attrib * a; + curse *c; + int n; + + /* Bonus durch Rassenmagieresistenz */ + double probability = target->race->magres; + assert(target->number>0); + + /* Magier haben einen Resistenzbonus vom Magietalent * 5%*/ + probability += effskill(target, SK_MAGIC)*0.05; + + /* Auswirkungen von Zaubern auf der Einheit */ + c = get_curse(target->attribs, ct_find("magicresistance")); + if (c) { + probability += 0.01 * curse_geteffect(c) * get_cursedmen(target, c); + } + + /* Unicorn +10 */ + n = get_item(target, I_ELVENHORSE); + if (n) probability += n*0.1/target->number; + + /* Auswirkungen von Zaubern auf der Region */ + a = a_find(target->region->attribs, &at_curse); + while (a && a->type==&at_curse) { + curse *c = (curse*)a->data.v; + unit *mage = c->magician; + + if (mage!=NULL) { + if (c->type == ct_find("goodmagicresistancezone")) { + if (alliedunit(mage, target->faction, HELP_GUARD)) { + probability += curse_geteffect(c)*0.01; + break; + } + } + else if (c->type == ct_find("badmagicresistancezone")) { + if (alliedunit(mage, target->faction, HELP_GUARD)) { + /* TODO: hier sollte doch sicher was passieren? */ + a = a->next; + continue; + } + } + } + a = a->next; + } + /* Bonus durch Artefakte */ + /* TODO (noch gibs keine)*/ + + /* Bonus durch Gebäude */ + { + struct building * b = inside_building(target); + const struct building_type * btype = b?b->type:NULL; + + /* gesegneter Steinkreis gibt 30% dazu */ + if (btype) probability += btype->magresbonus * 0.01; + } + return probability; +} + +/* ------------------------------------------------------------- */ +/* Prüft, ob das Objekt dem Zauber widerstehen kann. + * Objekte können Regionen, Units, Gebäude oder Schiffe sein. + * TYP_UNIT: + * Das höchste Talent des Ziels ist sein 'Magieresistenz-Talent', Magier + * bekommen einen Bonus. Grundchance ist 50%, für jede Stufe + * Unterschied gibt es 5%, minimalchance ist 5% für jeden (5-95%) + * Scheitert der Spruch an der Magieresistenz, so gibt die Funktion + * true zurück + */ + +boolean +target_resists_magic(unit *magician, void *obj, int objtyp, int t_bonus) +{ + double probability = 0.0; + + if (magician == NULL) return true; + if (obj == NULL) return true; + + switch(objtyp) { + case TYP_UNIT: + { + int at, pa = 0; + skill * sv; + unit * u = (unit*)obj; + + at = effskill(magician, SK_MAGIC); + + for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { + int sk = effskill(u, sv->id); + if (pa < sk) pa = sk; + } + + /* Contest */ + probability = 0.05 * (10 + pa - at); + + probability += magic_resistance((unit *)obj); + break; + } + + case TYP_REGION: + /* Bonus durch Zauber */ + probability += 0.01 * get_curseeffect(((region *)obj)->attribs, C_RESIST_MAGIC, 0); + break; + + case TYP_BUILDING: + /* Bonus durch Zauber */ + probability += 0.01 * get_curseeffect(((building *)obj)->attribs, C_RESIST_MAGIC, 0); + + /* Bonus durch Typ */ + probability += 0.01 * ((building *)obj)->type->magres; + + break; + + case TYP_SHIP: + /* Bonus durch Zauber */ + probability += 0.01 * get_curseeffect(((ship *)obj)->attribs, C_RESIST_MAGIC, 0); + break; + } + + probability = MAX(0.02, probability + t_bonus*0.01); + probability = MIN(0.98, probability); + + /* gibt true, wenn die Zufallszahl kleiner als die chance ist und + * false, wenn sie gleich oder größer ist, dh je größer die + * Magieresistenz (chance) desto eher gibt die Funktion true zurück */ + return chance(probability); +} + +/* ------------------------------------------------------------- */ + +boolean +is_magic_resistant(unit *magician, unit *target, int resist_bonus) +{ + return (boolean)target_resists_magic(magician, target, TYP_UNIT, resist_bonus); +} + +/* ------------------------------------------------------------- */ +/* Patzer */ +/* ------------------------------------------------------------- */ +/* allgemeine Zauberpatzer: + * Treten auf, wenn die Stufe des Magieres zu niedrig ist. + * Abhaengig von Staerke des Spruchs. + * + * Die Warscheinlichkeit reicht von 20% (beherrscht den Spruch gerade + * eben) bis zu etwa 1% bei doppelt so gut wie notwendig + */ + +boolean +fumble(region * r, unit * u, const spell * sp, int cast_grade) +{ +/* X ergibt Zahl zwischen 1 und 0, je kleiner, desto besser der Magier. + * 0,5*40-20=0, dh wenn der Magier doppelt so gut ist, wie der Spruch + * benötigt, gelingt er immer, ist er gleich gut, gelingt der Spruch mit + * 20% Warscheinlichkeit nicht + * */ + + int rnd = 0; + double x = (double) cast_grade / (double) eff_skill(u, SK_MAGIC, r); + int patzer = (int) (((double) x * 40.0) - 20.0); + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + + if (btype) patzer -= btype->fumblebonus; + /* CHAOSPATZERCHANCE 10 : +10% Chance zu Patzern */ + if (sp->magietyp == M_DRAIG) { + patzer += CHAOSPATZERCHANCE; + } + if (is_cursed(u->attribs, C_MBOOST, 0) == true) { + patzer += CHAOSPATZERCHANCE; + } + if (is_cursed(u->attribs, C_FUMBLE, 0) == true) { + patzer += CHAOSPATZERCHANCE; + } + + /* wenn die Chance kleiner als 0 ist, können wir gleich false + * zurückgeben */ + if (patzer <= 0) { + return false; + } + rnd = rng_int()%100; + + if (rnd > patzer) { + /* Glück gehabt, kein Patzer */ + return false; + } + return true; +} + +/* ------------------------------------------------------------- */ +/* Dummy-Zauberpatzer, Platzhalter für speziel auf die Sprüche +* zugeschnittene Patzer */ +static void +patzer(castorder *co) +{ + unit *mage = co->magician.u; + + cmistake(mage, co->order, 180, MSG_MAGIC); + + return; +} +/* Die normalen Spruchkosten müssen immer bezahlt werden, hier noch + * alle weiteren Folgen eines Patzers + */ + +static void +do_fumble(castorder *co) +{ + curse * c; + region * r = co->rt; + unit * u = co->magician.u; + const spell *sp = co->sp; + int level = co->level; + int duration; + double effect; + + ADDMSG(&u->faction->msgs, msg_message("patzer", "unit region spell", + u, r, sp)); + switch (rng_int() % 10) { + case 0: + /* wenn vorhanden spezieller Patzer, ansonsten nix */ + if (sp->patzer) sp->patzer(co); + else patzer(co); + break; + + case 1: + /* Kröte */ + { + /* 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 triggerlit of the mage gone toad. + */ + trigger * trestore = trigger_changerace(u, u->race, u->irace); + + if (chance(0.7)) { + const item_type * it_toadslime = it_find("toadslime"); + if (it_toadslime!=NULL) { + t_add(&trestore, trigger_giveitem(u, it_toadslime, 1)); + } + } + + duration = rng_int()%level/2; + if (duration<2) duration = 2; + add_trigger(&u->attribs, "timer", trigger_timeout(duration, trestore)); + u->race = new_race[RC_TOAD]; + u->irace = NULL; + ADDMSG(&r->msgs, msg_message("patzer6", "unit region spell", + u, r, sp)); + break; + } + /* fall-through is intentional! */ + + case 2: + /* temporärer Stufenverlust */ + duration = MAX(rng_int()%level/2, 2); + effect = -0.5*level; + c = create_curse(u, &u->attribs, ct_find("skillmod"), (float)level, duration, + effect, 1); + c->data.i = SK_MAGIC; + ADDMSG(&u->faction->msgs, msg_message("patzer2", "unit region", u, r)); + break; + case 3: + case 4: + /* Spruch schlägt fehl, alle Magiepunkte weg */ + set_spellpoints(u, 0); + ADDMSG(&u->faction->msgs, msg_message("patzer3", "unit region spell", + u, r, sp)); + break; + + case 5: + case 6: + /* Spruch gelingt, aber alle Magiepunkte weg */ + if (sp->sp_function==NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + } else { + ((nspell_f)sp->sp_function)(co); + } + set_spellpoints(u, 0); + ADDMSG(&u->faction->msgs, msg_message("patzer4", "unit region spell", + u, r, sp)); + break; + + case 7: + case 8: + case 9: + default: + /* Spruch gelingt, alle nachfolgenden Sprüche werden 2^4 so teuer */ + if (sp->sp_function==NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + } else { + ((nspell_f)sp->sp_function)(co); + } + ADDMSG(&u->faction->msgs, msg_message("patzer5", "unit region spell", + u, r, sp)); + countspells(u, 3); + } + + return; +} + +/* ------------------------------------------------------------- */ +/* Regeneration von Aura */ +/* ------------------------------------------------------------- */ + +/* Ein Magier regeneriert pro Woche W(Stufe^1.5/2+1), mindestens 1 + * Zwerge nur die Hälfte + */ +static double +regeneration(unit * u) +{ + int sk; + double aura, d; + double potenz = 1.5; + double divisor = 2.0; + + sk = effskill(u, SK_MAGIC); + /* Rassenbonus/-malus */ + d = pow(sk, potenz) * u->race->regaura / divisor; + d++; + + /* Einfluss von Artefakten */ + /* TODO (noch gibs keine)*/ + + /* Würfeln */ + aura = (rng_double() * d + rng_double() * d)/2 + 1; + + aura *= MagicRegeneration(); + + return aura; +} + +void +regeneration_magiepunkte(void) +{ + region *r; + unit *u; + int aura, auramax; + double reg_aura; + int regen; + double mod; + + for (r = regions; r; r = r->next) { + for (u = r->units; u; u = u->next) { + if (u->number && is_mage(u)) { + aura = get_spellpoints(u); + auramax = max_spellpoints(r, u); + if (aura < auramax) { + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + reg_aura = regeneration(u); + + /* Magierturm erhöht die Regeneration um 75% */ + /* Steinkreis erhöht die Regeneration um 50% */ + if (btype) reg_aura *= btype->auraregen; + + /* Bonus/Malus durch Zauber */ + mod = get_curseeffect(u->attribs, C_AURA, 0); + if (mod>0) { + reg_aura = (reg_aura*mod)/100.0; + } + + /* Einfluss von Artefakten */ + /* TODO (noch gibs keine)*/ + + /* maximal Differenz bis Maximale-Aura regenerieren + * mindestens 1 Aura pro Monat */ + regen = (int)reg_aura; + reg_aura -= regen; + if (chance(reg_aura)) ++regen; + regen = MAX(1, regen); + regen = MIN((auramax - aura), regen); + + aura += regen; + ADDMSG(&u->faction->msgs, msg_message( + "regenaura", "unit region amount", + u, r, regen)); + } + set_spellpoints(u, MIN(aura, auramax)); + + /* Zum letzten Mal Spruchliste aktualisieren */ + /*updatespelllist(u);*/ + } + } + } +} + +static boolean +verify_ship(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) +{ + ship *sh = findship(spobj->data.i); + + if (sh!=NULL && sh->region!=r && (sp->sptyp & SEARCHLOCAL)) { + /* Burg muss in gleicher Region sein */ + sh = NULL; + } + + if (sh==NULL) { + /* Burg nicht gefunden */ + spobj->flag = TARGET_NOTFOUND; + ADDMSG(&mage->faction->msgs, msg_message("spellshipnotfound", + "unit region command id", mage, mage->region, ord, spobj->data.i)); + return false; + } + spobj->flag = 0; + spobj->data.sh = sh; + return true; +} + +static boolean +verify_building(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) +{ + building *b = findbuilding(spobj->data.i); + + if (b!=NULL && b->region!=r && (sp->sptyp & SEARCHLOCAL)) { + /* Burg muss in gleicher Region sein */ + b = NULL; + } + + if (b==NULL) { + /* Burg nicht gefunden */ + spobj->flag = TARGET_NOTFOUND; + ADDMSG(&mage->faction->msgs, msg_message("spellbuildingnotfound", + "unit region command id", mage, mage->region, ord, spobj->data.i)); + return false; + } + spobj->flag = 0; + spobj->data.b = b; + return true; +} + +message * +msg_unitnotfound(const struct unit * mage, struct order * ord, const struct spllprm * spobj) +{ + /* Einheit nicht gefunden */ + char tbuf[20]; + const char * uid; + + if (spobj->typ==SPP_UNIT) { + uid = itoa36(spobj->data.i); + } else { + sprintf(tbuf, "%s %s", LOC(mage->faction->locale, + parameters[P_TEMP]), itoa36(spobj->data.i)); + uid = tbuf; + } + return msg_message("unitnotfound_id", + "unit region command id", mage, mage->region, ord, uid); +} + +static boolean +verify_unit(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) +{ + unit *u = NULL; + switch (spobj->typ) { + case SPP_UNIT: + u = findunit(spobj->data.i); + break; + case SPP_TEMP: + u = findnewunit(r, mage->faction, spobj->data.i); + if (u==NULL) u = findnewunit(mage->region, mage->faction, spobj->data.i); + break; + default: + assert(!"shouldn't happen, this"); + } + if (u!=NULL && (sp->sptyp & SEARCHLOCAL)) { + if (u->region!=r) u = NULL; + else if (sp->sptyp & TESTCANSEE) { + if (!cansee(mage->faction, r, u, 0) && !ucontact(u, mage)) { + u = NULL; + } + } + } + + if (u==NULL) { + /* Einheit nicht gefunden */ + spobj->flag = TARGET_NOTFOUND; + ADDMSG(&mage->faction->msgs, msg_unitnotfound(mage, ord, spobj)); + return false; + } + /* Einheit wurde gefunden, pointer setzen */ + spobj->flag = 0; + spobj->data.u = u; + return true; +} + +/* ------------------------------------------------------------- */ +/* Zuerst wird versucht alle noch nicht gefundenen Objekte zu finden + * oder zu prüfen, ob das gefundene Objekt wirklich hätte gefunden + * werden dürfen (nicht alle Zauber wirken global). Dabei zählen wir die + * Misserfolge (failed). + * Dann folgen die Tests der gefundenen Objekte auf Magieresistenz und + * Sichtbarkeit. Dabei zählen wir die magieresistenten (resists) + * Objekte. Alle anderen werten wir als Erfolge (success) */ + +/* gibt bei Misserfolg 0 zurück, bei Magieresistenz zumindeste eines + * Objektes 1 und bei Erfolg auf ganzer Linie 2 */ +static void +verify_targets(castorder *co, int * invalid, int * resist, int * success) +{ + unit *mage = co->magician.u; + const spell *sp = co->sp; + region *target_r = co->rt; + spellparameter *sa = co->par; + int i; + + *invalid = 0; + *resist = 0; + *success = 0; + + if (sa && sa->length) { + /* zuerst versuchen wir vorher nicht gefundene Objekte zu finden. + * Wurde ein Objekt durch globalsuche gefunden, obwohl der Zauber + * gar nicht global hätte suchen dürften, setzen wir das Objekt + * zurück. */ + for (i=0;ilength;i++) { + spllprm * spobj = sa->param[i]; + + switch(spobj->typ) { + case SPP_TEMP: + case SPP_UNIT: + if (!verify_unit(target_r, mage, sp, spobj, co->order)) ++*invalid; + break; + case SPP_BUILDING: + if (!verify_building(target_r, mage, sp, spobj, co->order)) ++*invalid; + break; + case SPP_SHIP: + if (!verify_ship(target_r, mage, sp, spobj, co->order)) ++*invalid; + break; + default: + break; + } + } + + /* Nun folgen die Tests auf cansee und Magieresistenz */ + for (i=0;ilength;i++) { + spllprm * spobj = sa->param[i]; + unit * u; + building * b; + ship * sh; + region * tr; + + if (spobj->flag == TARGET_NOTFOUND) continue; + switch(spobj->typ) { + case SPP_TEMP: + case SPP_UNIT: + u = spobj->data.u; + + if ((sp->sptyp & TESTRESISTANCE) + && target_resists_magic(mage, u, TYP_UNIT, 0)) + { + /* Fehlermeldung */ + spobj->data.i = u->no; + spobj->flag = TARGET_RESISTS; + ++*resist; + ADDMSG(&mage->faction->msgs, msg_message("spellunitresists", + "unit region command target", + mage, mage->region, co->order, u)); + break; + } + + /* TODO: Test auf Parteieigenschaft Magieresistsenz */ + ++*success; + break; + case SPP_BUILDING: + b = spobj->data.b; + + if ((sp->sptyp & TESTRESISTANCE) + && target_resists_magic(mage, b, TYP_BUILDING, 0)) + { /* Fehlermeldung */ + spobj->data.i = b->no; + spobj->flag = TARGET_RESISTS; + ++*resist; + ADDMSG(&mage->faction->msgs, msg_message("spellbuildingresists", + "unit region command id", + mage, mage->region, co->order, spobj->data.i)); + break; + } + ++*success; + break; + case SPP_SHIP: + sh = spobj->data.sh; + + if ((sp->sptyp & TESTRESISTANCE) + && target_resists_magic(mage, sh, TYP_SHIP, 0)) + { /* Fehlermeldung */ + spobj->data.i = sh->no; + spobj->flag = TARGET_RESISTS; + ++*resist; + ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + "spellshipresists", "ship", sh)); + break; + } + ++*success; + break; + + case SPP_REGION: + /* haben wir ein Regionsobjekt, dann wird auch dieses und + nicht target_r überprüft. */ + tr = spobj->data.r; + + if ((sp->sptyp & TESTRESISTANCE) + && target_resists_magic(mage, tr, TYP_REGION, 0)) + { /* Fehlermeldung */ + spobj->flag = TARGET_RESISTS; + ++*resist; + ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", + "unit region command", mage, mage->region, co->order)); + break; + } + ++*success; + break; + case SPP_INT: + case SPP_STRING: + ++*success; + break; + + default: + break; + } + } + } else { + /* der Zauber hat keine expliziten Parameter/Ziele, es kann sich + * aber um einen Regionszauber handeln. Wenn notwendig hier die + * Magieresistenz der Region prüfen. */ + if ((sp->sptyp & REGIONSPELL)) { + /* Zielobjekt Region anlegen */ + spllprm * spobj = malloc(sizeof(spllprm)); + spobj->flag = 0; + spobj->typ = SPP_REGION; + spobj->data.r = target_r; + + sa = calloc(1, sizeof(spellparameter)); + sa->length = 1; + sa->param = calloc(sa->length, sizeof(spllprm *)); + sa->param[0] = spobj; + co->par = sa; + + if ((sp->sptyp & TESTRESISTANCE)) { + if (target_resists_magic(mage, target_r, TYP_REGION, 0)) { + /* Fehlermeldung */ + ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", + "unit region command", mage, mage->region, co->order)); + spobj->flag = TARGET_RESISTS; + ++*resist; + } else { + ++*success; + } + } else { + ++*success; + } + } else { + ++*success; + } + } +} + +/* ------------------------------------------------------------- */ +/* Hilfsstrukturen für ZAUBERE */ +/* ------------------------------------------------------------- */ + +static void +free_spellparameter(spellparameter *pa) +{ + int i; + + /* Elemente free'en */ + for (i=0; i < pa->length; i++) { + + switch(pa->param[i]->typ) { + case SPP_STRING: + free(pa->param[i]->data.s); + break; + default: + break; + } + free(pa->param[i]); + } + + if (pa->param) free(pa->param); + /* struct free'en */ + free(pa); +} + +static int +addparam_string(const char * const param[], spllprm ** spobjp) +{ + spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); + assert(param[0]); + + spobj->flag = 0; + spobj->typ = SPP_STRING; + spobj->data.xs = strdup(param[0]); + return 1; +} + +static int +addparam_int(const char * const param[], spllprm ** spobjp) +{ + spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); + assert(param[0]); + + spobj->flag = 0; + spobj->typ = SPP_INT; + spobj->data.i = atoi((char*)param[0]); + return 1; +} + +static int +addparam_ship(const char * const param[], spllprm ** spobjp) +{ + spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); + int id = atoi36((const char *)param[0]); + + spobj->flag = 0; + spobj->typ = SPP_SHIP; + spobj->data.i = id; + return 1; +} + +static int +addparam_building(const char * const param[], spllprm ** spobjp) +{ + spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); + int id = atoi36((const char *)param[0]); + + spobj->flag = 0; + spobj->typ = SPP_BUILDING; + spobj->data.i = id; + return 1; +} + +static int +addparam_region(const char * const param[], spllprm ** spobjp, const unit * u, order * ord, plane * pl) +{ + assert(param[0]); + if (param[1]==0) { + /* Fehler: Zielregion vergessen */ + cmistake(u, ord, 194, MSG_MAGIC); + return -1; + } else { + int tx = atoi((const char*)param[0]), ty = atoi((const char*)param[1]); + int x = rel_to_abs(pl, u->faction, tx, 0); + int y = rel_to_abs(pl, u->faction, ty, 1); + region *rt; + + pnormalize(&x, &y, pl); + rt = findregion(x,y); + + if (rt!=NULL) { + spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); + + spobj->flag = 0; + spobj->typ = SPP_REGION; + spobj->data.r = rt; + } else { + /* Fehler: Zielregion vergessen */ + cmistake(u, ord, 194, MSG_MAGIC); + return -1; + } + return 2; + } +} + + +static int +addparam_unit(const char * const param[], spllprm ** spobjp, const unit * u, order * ord) +{ + spllprm *spobj; + int i = 0; + sppobj_t otype = SPP_UNIT; + + *spobjp = NULL; + if (findparam(param[0], u->faction->locale)==P_TEMP) { + if (param[1]==NULL) { + /* Fehler: Ziel vergessen */ + cmistake(u, ord, 203, MSG_MAGIC); + return -1; + } + ++i; + otype = SPP_TEMP; + } + + spobj = *spobjp = malloc(sizeof(spllprm)); + spobj->flag = 0; + spobj->typ = otype; + spobj->data.i = atoi36((const char*)param[i]); + + return i+1; +} + +static spellparameter * +add_spellparameter(region *target_r, unit *u, const char *syntax, const char * const param[], int size, struct order * ord) +{ + boolean fail = false; + int i = 0; + int p = 0; + const char * c; + spellparameter *par; + int minlen = 0; + + for (c=syntax;*c!=0;++c) { + /* this makes sure that: + * minlen("kc?") = 0 + * minlen("kc+") = 1 + * minlen("cccc+c?") = 4 + */ + if (*c=='?') --minlen; + else if (*c!='+' && *c!='k') ++minlen; + } + c = syntax; + + /* mindestens ein Ziel (Ziellose Zauber werden nicht + * geparst) */ + if (minlen && size==0) { + /* Fehler: Ziel vergessen */ + cmistake(u, ord, 203, MSG_MAGIC); + return 0; + } + + par = malloc(sizeof(spellparameter)); + par->length = size; + if (!size) { + par->param = NULL; + return par; + } + par->param = malloc(size * sizeof(spllprm *)); + + while (!fail && *c && ifaction->locale); + switch (pword) { + case P_REGION: + spobj = malloc(sizeof(spllprm)); + spobj->flag = 0; + spobj->typ = SPP_REGION; + spobj->data.r = u->region; + j = 0; + ++c; + break; + case P_UNIT: + if (iparam[p++] = spobj; + i += j; + } + } + + /* im Endeffekt waren es evtl. nur p parameter (wegen TEMP) */ + par->length = p; + if (fail || par->lengthmagician.u = u; + corder->familiar = u2; + corder->sp = sp; + corder->level = lev; + corder->force = force; + corder->rt = r; + corder->distance = range; + corder->order = copy_order(ord); + corder->par = p; + + return corder; +} + +/* Hänge c-order co an die letze c-order von cll an */ +void +add_castorder(spellrank *cll, castorder *co) +{ + if (cll->begin==NULL) { + cll->end = &cll->begin; + } + + *cll->end = co; + cll->end = &co->next; + + return; +} + +void +free_castorders(castorder *co) +{ + castorder *co2; + + while (co) { + co2 = co; + co = co->next; + if (co2->par) { + free_spellparameter(co2->par); + } + if (co2->order) free_order(co2->order); + free(co2); + } + return; +} + +/* ------------------------------------------------------------- */ +/*** + ** at_familiarmage + **/ + +typedef struct familiar_data { + unit * mage; + unit * familiar; +} famililar_data; + +boolean +is_familiar(const unit *u) +{ + attrib * a = a_find(u->attribs, &at_familiarmage); + return i2b(a!=NULL); +} + +static void +a_write_unit(const attrib * a, const void * owner, struct storage * store) +{ + unit * u = (unit*)a->data.v; + write_unit_reference(u, store); +} + +static int +sm_familiar(const unit * u, const region * r, skill_t sk, int value) /* skillmod */ +{ + if (sk==SK_MAGIC) return value; + else { + int mod; + unit * familiar = get_familiar(u); + if (familiar==NULL) { + /* the familiar is dead */ + return value; + } + mod = eff_skill(familiar, sk, r)/2; + if (r != familiar->region) { + mod /= distance(r, familiar->region); + } + return value + mod; + } +} + +static 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); + 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; + } + + a = a_find(mage->attribs, &at_familiar); + if (a==NULL) { + a = a_add(&mage->attribs, a_new(&at_familiar)); + a->data.v = familiar; + } else assert(!a->data.v || a->data.v == familiar); + /* 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 assert(!a->data.v || a->data.v == mage); +} + +void +remove_familiar(unit *mage) +{ + attrib *a = a_find(mage->attribs, &at_familiar); + attrib *an; + skillmod_data *smd; + + if (a!=NULL) { + a_remove(&mage->attribs, a); + } + a = a_find(mage->attribs, &at_skillmod); + while (a && a->type==&at_skillmod) { + an = a->next; + smd = (skillmod_data *)a->data.v; + if (smd->special==sm_familiar) a_remove(&mage->attribs, a); + a = an; + } +} + +boolean +create_newfamiliar(unit * mage, unit * familiar) +{ + /* 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); + + 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; + + /* TODO: Diese Attribute beim Tod des Familiars entfernen: */ + /* Wenn der Magier stirbt, dann auch der Vertraute */ + add_trigger(&mage->attribs, "destroy", trigger_killunit(familiar)); + /* 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; +} + +static int +resolve_familiar(variant data, void * addr) +{ + unit * familiar; + int result = resolve_unit(data, &familiar); + if (result==0 && familiar) { + 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; +} + +static int +read_familiar(attrib * a, void * owner, struct storage * store) +{ + int result = read_reference(&a->data.v, store, read_unit_reference, resolve_familiar); + if (result==0 && a->data.v==NULL) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +/* clones */ + +void +create_newclone(unit * mage, unit * clone) +{ + attrib *a; + + a = a_find(mage->attribs, &at_clone); + if (a == NULL) { + a = a_add(&mage->attribs, a_new(&at_clone)); + a->data.v = clone; + } else assert(!a->data.v || a->data.v == clone); + /* TODO: Diese Attribute beim Tod des Klons entfernen: */ + + a = a_find(clone->attribs, &at_clonemage); + if (a == NULL) { + a = a_add(&clone->attribs, a_new(&at_clonemage)); + a->data.v = mage; + } else assert(!a->data.v || a->data.v == mage); + + /* Wenn der Magier stirbt, wird das in destroy_unit abgefangen. + * Kein Trigger, zu kompliziert. */ + + /* Wenn der Klon stirbt, dann bekommt der Magier einen Schock */ + add_trigger(&clone->attribs, "destroy", trigger_clonedied(mage)); +} + +static void +set_clone(unit * mage, unit * clone) +{ + attrib *a; + + a = a_find(mage->attribs, &at_clone); + if (a==NULL) { + a = a_add(&mage->attribs, a_new(&at_clone)); + a->data.v = clone; + } else assert(!a->data.v || a->data.v == clone); + + a = a_find(clone->attribs, &at_clonemage); + if (a==NULL) { + a = a_add(&clone->attribs, a_new(&at_clonemage)); + a->data.v = mage; + } else assert(!a->data.v || a->data.v == mage); +} + +unit * +has_clone(unit *mage) +{ + attrib *a = a_find(mage->attribs, &at_clone); + if(a) return (unit *)a->data.v; + return NULL; +} + +static int +resolve_clone(variant data, void * addr) +{ + unit * clone; + int result = resolve_unit(data, &clone); + if (result==0 && clone) { + 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; +} + +static int +read_clone(attrib * a, void * owner, struct storage * store) +{ + int result = read_reference(&a->data.v, store, read_unit_reference, resolve_clone); + if (result==0 && a->data.v==NULL) { + 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) { + 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; +} + +static int +read_magician(attrib * a, void * owner, struct storage * store) +{ + int result = read_reference(&a->data.v, store, read_unit_reference, resolve_mage); + if (result==0 && a->data.v==NULL) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +static int +age_unit(attrib * a) +/* if unit is gone or dead, remove the attribute */ +{ + unit * u = (unit*)a->data.v; + return (u!=NULL && u->number>0)?AT_AGE_KEEP:AT_AGE_REMOVE; +} + +attrib_type at_familiarmage = { + "familiarmage", + NULL, + NULL, + age_unit, + a_write_unit, + read_magician, + ATF_UNIQUE +}; + +attrib_type at_familiar = { + "familiar", + NULL, + NULL, + age_unit, + a_write_unit, + read_familiar, + ATF_UNIQUE +}; + +attrib_type at_clonemage = { + "clonemage", + NULL, + NULL, + age_unit, + a_write_unit, + read_magician, + ATF_UNIQUE +}; + +attrib_type at_clone = { + "clone", + NULL, + NULL, + age_unit, + a_write_unit, + read_clone, + ATF_UNIQUE +}; + +unit * +get_familiar(const unit *u) +{ + attrib * a = a_find(u->attribs, &at_familiar); + if (a!=NULL) { + unit * u = (unit*)a->data.v; + if (u->number>0) return u; + } + return NULL; +} + +unit * +get_familiar_mage(const unit *u) +{ + attrib * a = a_find(u->attribs, &at_familiarmage); + if (a!=NULL) { + unit * u = (unit*)a->data.v; + if (u->number>0) return u; + } + return NULL; +} + +unit * +get_clone(const unit *u) +{ + attrib * a = a_find(u->attribs, &at_clone); + if (a!=NULL) { + unit * u = (unit*)a->data.v; + if (u->number>0) return u; + } + return NULL; +} + +unit * +get_clone_mage(const unit *u) +{ + attrib * a = a_find(u->attribs, &at_clonemage); + if (a!=NULL) { + unit * u = (unit*)a->data.v; + if (u->number>0) return u; + } + return NULL; +} + +static boolean +is_moving_ship(const region * r, const ship *sh) +{ + const unit *u = shipowner(sh); + + if (u) switch (get_keyword(u->thisorder)) { + case K_ROUTE: + case K_MOVE: + case K_FOLLOW: + return true; + } + return false; +} + +static castorder * +cast_cmd(unit * u, order * ord) +{ + region * r = u->region; + region * target_r = r; + int level, range; + unit *familiar = NULL, *mage = u; + const char * s; + spell * sp; + plane * pl; + spellparameter *args = NULL; + + if (LongHunger(u)) { + cmistake(u, ord, 224, MSG_MAGIC); + return 0; + } + pl = rplane(r); + if (pl && fval(pl, PFL_NOMAGIC)) { + cmistake(u, ord, 269, MSG_MAGIC); + return 0; + } + level = eff_skill(u, SK_MAGIC, r); + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + /* für Syntax ' STUFE x REGION y z ' */ + if (findparam(s, u->faction->locale) == P_LEVEL) { + int p = getint(); + level = MIN(p, level); + if (level < 1) { + /* Fehler "Das macht wenig Sinn" */ + cmistake(u, ord, 10, MSG_MAGIC); + return 0; + } + s = getstrtoken(); + } + if (findparam(s, u->faction->locale) == P_REGION) { + int t_x = getint(); + int t_y = getint(); + plane * pl = getplane(u->region); + t_x = rel_to_abs(pl, u->faction, t_x,0); + t_y = rel_to_abs(pl, u->faction, t_y,1); + pnormalize(&t_x, &t_y, pl); + target_r = findregion(t_x, t_y); + if (!target_r) { + /* Fehler "Die Region konnte nicht verzaubert werden" */ + ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", + "unit region command", mage, mage->region, ord)); + return 0; + } + s = getstrtoken(); + } + /* für Syntax ' REGION x y STUFE z ' + * hier nach REGION nochmal auf STUFE prüfen */ + if (findparam(s, u->faction->locale) == P_LEVEL) { + int p = getint(); + level = MIN(p, level); + if (level < 1) { + /* Fehler "Das macht wenig Sinn" */ + cmistake(u, ord, 10, MSG_MAGIC); + return 0; + } + s = getstrtoken(); + } + if (!s[0] || strlen(s) == 0) { + /* Fehler "Es wurde kein Zauber angegeben" */ + cmistake(u, ord, 172, MSG_MAGIC); + return 0; + } + sp = get_spellfromtoken(u, s, u->faction->locale); + + /* Vertraute können auch Zauber sprechen, die sie selbst nicht + * können. get_spellfromtoken findet aber nur jene Sprüche, die + * die Einheit beherrscht. */ + if (sp == NULL && is_familiar(u)) { + familiar = u; + mage = get_familiar_mage(u); + if (mage!=NULL) sp = get_spellfromtoken(mage, s, mage->faction->locale); + } + + if (sp == NULL) { + /* Fehler 'Spell not found' */ + cmistake(u, ord, 173, MSG_MAGIC); + return 0; + } + /* um testen auf spruchnamen zu unterbinden sollte vor allen + * fehlermeldungen die anzeigen das der magier diesen Spruch + * nur in diese Situation nicht anwenden kann, noch eine + * einfache Sicherheitsprüfung kommen */ + if (!knowsspell(r, u, sp)) { + /* vorsicht! u kann der familiar sein */ + if (!familiar) { + cmistake(u, ord, 173, MSG_MAGIC); + return 0; + } + } + if (sp->sptyp & ISCOMBATSPELL) { + /* Fehler: "Dieser Zauber ist nur im Kampf sinnvoll" */ + cmistake(u, ord, 174, MSG_MAGIC); + return 0; + } + /* Auf dem Ozean Zaubern als quasi-langer Befehl können + * normalerweise nur Meermenschen, ausgenommen explizit als + * OCEANCASTABLE deklarierte Sprüche */ + if (fval(r->terrain, SEA_REGION)) { + if (u->race != new_race[RC_AQUARIAN] + && !fval(u->race, RCF_SWIM) + && !(sp->sptyp & OCEANCASTABLE)) { + /* Fehlermeldung */ + ADDMSG(&u->faction->msgs, msg_message("spellfail_onocean", + "unit region command", u, u->region, ord)); + return 0; + } + /* Auf bewegenden Schiffen kann man nur explizit als + * ONSHIPCAST deklarierte Zauber sprechen */ + } else if (u->ship) { + if (is_moving_ship(r, u->ship)) { + if (!(sp->sptyp & ONSHIPCAST)) { + /* Fehler: "Diesen Spruch kann man nicht auf einem sich + * bewegenden Schiff stehend zaubern" */ + cmistake(u, ord, 175, MSG_MAGIC); + return 0; + } + } + } + /* Farcasting bei nicht farcastbaren Sprüchen abfangen */ + range = farcasting(u, target_r); + if (range > 1) { + if (!(sp->sptyp & FARCASTING)) { + /* Fehler "Diesen Spruch kann man nicht in die Ferne + * richten" */ + cmistake(u, ord, 176, MSG_MAGIC); + return 0; + } + if (range > 1024) { /* (2^10) weiter als 10 Regionen entfernt */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "spellfail::nocontact", + "target", target_r)); + return 0; + } + } + /* Stufenangabe bei nicht Stufenvariierbaren Sprüchen abfangen */ + if (!(sp->sptyp & SPELLLEVEL)) { + int ilevel = eff_skill(u, SK_MAGIC, u->region); + if (ilevel!=level) { + level = ilevel; + ADDMSG(&u->faction->msgs, msg_message("spellfail::nolevel", + "mage region command", u, u->region, ord)); + } + } + /* Vertrautenmagie */ + /* Kennt der Vertraute den Spruch, so zaubert er ganz normal. + * Ansonsten zaubert der Magier durch seinen Vertrauten, dh + * zahlt Komponenten und Aura. Dabei ist die maximale Stufe + * die des Vertrauten! + * Der Spruch wirkt dann auf die Region des Vertrauten und + * gilt nicht als Farcasting. */ + if (familiar || is_familiar(u)) { + if ((sp->sptyp & NOTFAMILIARCAST)) { + /* Fehler: "Diesen Spruch kann der Vertraute nicht zaubern" */ + cmistake(u, ord, 177, MSG_MAGIC); + return 0; + } + if (!knowsspell(r, u, sp)) { /* Magier zaubert durch Vertrauten */ + mage = get_familiar_mage(u); + if (range > 1) { /* Fehler! Versucht zu Farcasten */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_farcast", + "mage", mage)); + return 0; + } + if (distance(mage->region, r) > eff_skill(mage, SK_MAGIC, mage->region)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_toofar", + "mage", mage)); + return 0; + } + /* mage auf magier setzen, level anpassen, range für Erhöhung + * der Spruchkosten nutzen, langen Befehl des Magiers + * löschen, zaubern kann er noch */ + range *= 2; + set_order(&mage->thisorder, NULL); + level = MIN(level, eff_skill(mage, SK_MAGIC, mage->region)/2); + familiar = u; + } + } + /* Weitere Argumente zusammenbasteln */ + if (sp->parameter) { + char ** params = malloc(2*sizeof(char*)); + int p = 0, size = 2; + for (;;) { + s = getstrtoken(); + if (*s==0) break; + if (p+1>=size) { + size*=2; + params = realloc(params, sizeof(char*)*size); + } + params[p++] = strdup(s); + } + params[p] = 0; + args = add_spellparameter(target_r, mage, sp->parameter, (const char * const *)params, p, ord); + for (p=0;params[p];++p) free(params[p]); + free(params); + if (args==NULL) { + /* Syntax war falsch */ + return 0; + } + } + return new_castorder(mage, familiar, sp, target_r, level, 0, range, ord, args); +} + +/* ------------------------------------------------------------- */ +/* Damit man keine Rituale in fremden Gebiet machen kann, diese vor + * Bewegung zaubern. Magier sind also in einem fremden Gebiet eine Runde + * lang verletzlich, da sie es betreten, und angegriffen werden können, + * bevor sie ein Ritual machen können. + * + * Syntax: ZAUBER [REGION X Y] [STUFE ] "Spruchname" [Einheit-1 + * Einheit-2 ..] + * + * Nach Priorität geordnet die Zauber global auswerten. + * + * Die Kosten für Farcasting multiplizieren sich mit der Entfernung, + * cast_level gibt die virtuelle Stufe an, die den durch das Farcasten + * entstandenen Spruchkosten entspricht. Sind die Spruchkosten nicht + * levelabhängig, so sind die Kosten nur von der Entfernung bestimmt, + * die Stärke/Level durch den realen Skill des Magiers + */ + +void +magic(void) +{ + region *r; + int rank; + castorder *co; + spellrank spellranks[MAX_SPELLRANK]; + + memset(spellranks, 0, sizeof(spellranks)); + + for (r = regions; r; r = r->next) { + unit *u; + for (u = r->units; u; u = u->next) { + order * ord; + + if (u->number<=0 || u->race == new_race[RC_SPELL]) + continue; + + if (u->race == new_race[RC_INSECT] && r_insectstalled(r) && + !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) + continue; + + if (fval(u, UFL_WERE|UFL_LONGACTION)) { + continue; + } + + for (ord = u->orders; ord; ord = ord->next) { + if (get_keyword(ord) == K_CAST) { + castorder * co = cast_cmd(u, ord); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + if (co) { + const spell * sp = co->sp; + add_castorder(&spellranks[sp->rank], co); + } + } + } + } + } + + /* Da sich die Aura und Komponenten in der Zwischenzeit verändert + * haben können und sich durch vorherige Sprüche das Zaubern + * erschwert haben kann, muss beim zaubern erneut geprüft werden, ob der + * Spruch überhaupt gezaubert werden kann. + * (level) die effektive Stärke des Spruchs (= Stufe, auf der der + * Spruch gezaubert wird) */ + + for (rank = 0; rank < MAX_SPELLRANK; rank++) { + for (co = spellranks[rank].begin; co; co = co->next) { + order * ord = co->order; + int invalid, resist, success, cast_level = co->level; + boolean fumbled = false; + unit * u = co->magician.u; + const spell *sp = co->sp; + region * target_r = co->rt; + + /* reichen die Komponenten nicht, wird der Level reduziert. */ + co->level = eff_spelllevel(u, sp, cast_level, co->distance); + + if (co->level < 1) { + /* Fehlermeldung mit Komponenten generieren */ + cancast(u, sp, cast_level, co->distance, ord); + continue; + } + + if (cast_level > co->level) { + /* Sprüche mit Fixkosten werden immer auf Stufe des Spruchs + * gezaubert, co->level ist aber defaultmäßig Stufe des Magiers */ + if (spl_costtyp(sp) != SPC_FIX) { + ADDMSG(&u->faction->msgs, msg_message("missing_components", + "unit spell level", u, sp, cast_level)); + } + } + + /* Prüfen, ob die realen Kosten für die gewünschten Stufe bezahlt + * werden können */ + if (cancast(u, sp, co->level, co->distance, ord) == false) { + /* die Fehlermeldung wird in cancast generiert */ + continue; + } + + co->force = spellpower(target_r, u, sp, co->level, ord); + /* die Stärke kann durch Antimagie auf 0 sinken */ + if (co->force <= 0) { + co->force = 0; + ADDMSG(&u->faction->msgs, msg_message("missing_force", + "unit spell level", u, sp, co->level)); + } + + /* Ziele auf Existenz prüfen und Magieresistenz feststellen. Wurde + * kein Ziel gefunden, so ist verify_targets=0. Scheitert der + * Spruch an der Magieresistenz, so ist verify_targets = 1, bei + * Erfolg auf ganzer Linie ist verify_targets= 2 + */ + verify_targets(co, &invalid, &resist, &success); + if (success+resist==0) { + /* kein Ziel gefunden, Fehlermeldungen sind in verify_targets */ + /* keine kosten für den zauber */ + continue; /* äußere Schleife, nächster Zauberer */ + } else if (co->force>0 && resist>0) { + /* einige oder alle Ziele waren magieresistent */ + if (success==0) { + co->force = 0; + /* zwar wurde mindestens ein Ziel gefunden, das widerstand + * jedoch dem Zauber. Kosten abziehen und abbrechen. */ + ADDMSG(&u->faction->msgs, msg_message("spell_resist", "unit region spell", + u, r, sp)); + } + } + + /* Auch für Patzer gibt es Erfahrung, müssen die Spruchkosten + * bezahlt werden und die nachfolgenden Sprüche werden teurer */ + if (co->force>0) { + if (fumble(target_r, u, sp, co->level)) { + /* zuerst bezahlen, dann evt in do_fumble alle Aura verlieren */ + fumbled = true; + } else { + if (sp->sp_function==NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + co->level = 0; + } else { + co->level = ((nspell_f)sp->sp_function)(co); + } + if (co->level <= 0) { + /* Kosten nur für real benötige Stufe berechnen */ + continue; + } + } + } + pay_spell(u, sp, co->level, co->distance); + /* erst bezahlen, dann Kostenzähler erhöhen */ + if (fumbled) do_fumble(co); + countspells(u, 1); + } + } + + /* Sind alle Zauber gesprochen gibts Erfahrung */ + for (r = regions; r; r = r->next) { + unit *u; + for (u = r->units; u; u = u->next) { + if (is_mage(u) && countspells(u, 0) > 0) { + produceexp(u, SK_MAGIC, u->number); + /* Spruchlistenaktualiesierung ist in Regeneration */ + } + } + } + for (rank = 0; rank < MAX_SPELLRANK; rank++) { + free_castorders(spellranks[rank].begin); + } + remove_empty_units(); +} + +const char * +spell_info(const spell * sp, const struct locale * lang) +{ + return LOC(lang, mkname("spellinfo", sp->sname)); +} + +const char * +spell_name(const spell * sp, const struct locale * lang) +{ + return LOC(lang, mkname("spell", sp->sname)); +} + +const char * +curse_name(const curse_type * ctype, const struct locale * lang) +{ + return LOC(lang, mkname("spell", ctype->cname)); +} + +void +spelllist_add(spell_list ** lspells, spell * sp) +{ + spell_list * entry; + + while (*lspells) { + spell_list * slist = *lspells; + if (slist->data->id==sp->id) { + if (slist->data==sp) { + log_error(("trying to add spell '%s' to a list twice.\n", sp->sname)); + return; + } + } + if (slist->data->id>sp->id) break; + lspells = &slist->next; + } + entry = malloc(sizeof(spell_list)); + entry->data = sp; + entry->next = *lspells; + *lspells = entry; +} + +spell_list ** +spelllist_find(spell_list ** lspells, const spell * sp) +{ + while (*lspells) { + spell_list * slist = *lspells; + if (slist->data->id>=sp->id) break; + lspells = &slist->next; + } + return lspells; +} + +extern struct spell_list ** get_spelllist(struct sc_mage * mage, struct faction * f) +{ + if (mage) { + return &mage->spells; + } + return NULL; +} diff --git a/src/kernel/magic.h b/src/kernel/magic.h new file mode 100644 index 000000000..623c5f516 --- /dev/null +++ b/src/kernel/magic.h @@ -0,0 +1,395 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_MAGIC +#define H_KRNL_MAGIC +#ifdef __cplusplus +extern "C" { +#endif + +#include "curse.h" +struct fighter; +struct building; + +/* ------------------------------------------------------------- */ + +#define MAXCOMBATSPELLS 3 /* PRECOMBAT COMBAT POSTCOMBAT */ +#define MAX_SPELLRANK 9 /* Standard-Rank 5 */ +#define MAXINGREDIENT 5 /* bis zu 5 Komponenten pro Zauber */ +#define CHAOSPATZERCHANCE 10 /* +10% Chance zu Patzern */ + +/* ------------------------------------------------------------- */ + +#define IRONGOLEM_CRUMBLE 15 /* monatlich Chance zu zerfallen */ +#define STONEGOLEM_CRUMBLE 10 /* monatlich Chance zu zerfallen */ + +/* ------------------------------------------------------------- */ +/* Spruchparameter + * Wir suchen beim Parsen des Befehls erstmal nach lokalen Objekten, + * erst in verify_targets wird dann global gesucht, da in den meisten + * Fällen das Zielobjekt lokal sein dürfte */ + +/* siehe auch typ_t in objtypes.h */ +typedef enum { + SPP_REGION, /* "r" : findregion(x,y) -> *region */ + SPP_UNIT, /* - : atoi36() -> int */ + SPP_TEMP, /* - : temp einheit */ + SPP_BUILDING, /* - : atoi() -> int */ + SPP_SHIP, /* - : atoi() -> int */ + SPP_STRING, /* "c" */ + SPP_INT, /* "i" : atoi() -> int */ +} sppobj_t; + +typedef struct spllprm{ + sppobj_t typ; + int flag; + union { + struct region *r; + struct unit *u; + struct building *b; + struct ship *sh; + char *s; + char * xs; + int i; + } data; +} spllprm; + +typedef struct spellparameter{ + int length; /* Anzahl der Elemente */ + struct spllprm **param; +} spellparameter; + +typedef struct strarray { + int length; /* Anzahl der Elemente */ + char **strings; +} strarray; + +#define TARGET_RESISTS (1<<0) +#define TARGET_NOTFOUND (1<<1) + +/* ------------------------------------------------------------- */ +/* Magierichtungen */ + +/* typedef unsigned char magic_t; */ +enum { + M_GRAY = 0, /* Gray */ + M_ILLAUN = 1, /* Illaun */ + M_TYBIED = 2, /* Tybied */ + M_CERDDOR = 3, /* Cerddor */ + M_GWYRRD = 4, /* Gwyrrd */ + M_DRAIG = 5, /* Draig */ + M_COMMON = 6, /* common spells */ + MAXMAGIETYP, + /* this enum is stored in the datafile, so do not change the numbers around */ + M_NONE = (magic_t) -1 +}; +extern const char *magic_school[MAXMAGIETYP]; + +/* ------------------------------------------------------------- */ +/* Magier: + * - Magierichtung + * - Magiepunkte derzeit + * - Malus (neg. Wert)/ Bonus (pos. Wert) auf maximale Magiepunkte + * (können sich durch Questen absolut verändern und durch Gegenstände + * temporär). Auch für Artefakt benötigt man permanente MP + * - Anzahl bereits gezauberte Sprüche diese Runde + * - Kampfzauber (3) (vor/während/nach) + * - Spruchliste + */ + +typedef struct combatspell { + int level; + const struct spell * sp; +} combatspell; + +typedef struct sc_mage { + magic_t magietyp; + int spellpoints; + int spchange; + int spellcount; + combatspell combatspells[MAXCOMBATSPELLS]; + struct spell_list * spells; +} sc_mage; + +/* ------------------------------------------------------------- */ +/* Zauberliste */ + +typedef struct castorder { + struct castorder *next; + union { + struct unit * u; + struct fighter * fig; + } magician; /* Magier (kann vom Typ struct unit oder fighter sein) */ + struct unit *familiar; /* Vertrauter, gesetzt, wenn der Spruch durch + den Vertrauten gezaubert wird */ + const struct spell *sp; /* Spruch */ + int level; /* gewünschte Stufe oder Stufe des Magiers */ + double force; /* Stärke des Zaubers */ + struct region *rt; /* Zielregion des Spruchs */ + int distance; /* Entfernung zur Zielregion */ + struct order * order; /* Befehl */ + struct spellparameter *par; /* für weitere Parameter */ +} castorder; + +/* irgendwelche zauber: */ +typedef void (*spell_f) (void*); +/* normale zauber: */ +typedef int (*nspell_f)(castorder*); +/* kampfzauber: */ +typedef int (*cspell_f) (struct fighter*, int, double, const struct spell * sp); +/* zauber-patzer: */ +typedef void (*pspell_f) (castorder *); + +typedef struct spell_component { + const struct resource_type * type; + int amount; + int cost; +} spell_component; + +typedef struct spell { + spellid_t id; + char *sname; + char *syntax; + char *parameter; + magic_t magietyp; + int sptyp; + int rank; /* Reihenfolge der Zauber */ + int level; /* Stufe des Zaubers */ + struct spell_component * components; + spell_f sp_function; + void (*patzer) (castorder*); +} spell; + +typedef struct spell_list { + struct spell_list * next; + spell * data; /* TODO: should be const */ +} spell_list; + +extern void spelllist_add(spell_list ** lspells, struct spell * sp); +extern spell_list ** spelllist_find(spell_list ** lspells, const struct spell * sp); +/* ------------------------------------------------------------- */ + +/* besondere Spruchtypen */ +#define FARCASTING (1<<0) /* ZAUBER [struct region x y] */ +#define SPELLLEVEL (1<<1) /* ZAUBER [STUFE x] */ + +/* ID's können zu drei unterschiedlichen Entitäten gehören: Einheiten, + * Gebäuden und Schiffen. */ +#define UNITSPELL (1<<2) /* ZAUBER .. [ ..] */ +#define SHIPSPELL (1<<3) /* ZAUBER .. [ ..] */ +#define BUILDINGSPELL (1<<4) /* ZAUBER .. [ ..] */ +#define REGIONSPELL (1<<5) /* wirkt auf struct region */ + +#define PRECOMBATSPELL (1<<7) /* PRÄKAMPFZAUBER .. */ +#define COMBATSPELL (1<<8) /* KAMPFZAUBER .. */ +#define POSTCOMBATSPELL (1<<9) /* POSTKAMPFZAUBER .. */ +#define ISCOMBATSPELL (PRECOMBATSPELL|COMBATSPELL|POSTCOMBATSPELL) + +#define OCEANCASTABLE (1<<10) /* Können auch nicht-Meermenschen auf + hoher See zaubern */ +#define ONSHIPCAST (1<<11) /* kann auch auf von Land ablegenden + Schiffen stehend gezaubert werden */ +/* */ +#define NOTFAMILIARCAST (1<<12) +#define TESTRESISTANCE (1<<13) /* alle Zielobjekte (u, s, b, r) auf + Magieresistenz prüfen */ +#define SEARCHLOCAL (1<<14) /* Ziel muss in der target_region sein */ +#define TESTCANSEE (1<<15) /* alle Zielunits auf cansee prüfen */ +#define ANYTARGET (UNITSPELL|REGIONSPELL|BUILDINGSPELL|SHIPSPELL) /* wirkt auf alle objekttypen (unit, ship, building, region) */ + +/* Flag Spruchkostenberechnung: */ +enum{ + SPC_FIX, /* Fixkosten */ + SPC_LEVEL, /* Komponenten pro Level */ + SPC_LINEAR /* Komponenten pro Level und müssen vorhanden sein */ +}; + +enum { + RS_DUMMY, + RS_FARVISION, + MAX_REGIONSPELLS +}; + +/* ------------------------------------------------------------- */ +/* Prototypen */ + +void magic(void); + +void regeneration_magiepunkte(void); + +extern struct attrib_type at_seenspell; +extern struct attrib_type at_mage; +extern struct attrib_type at_familiarmage; +extern struct attrib_type at_familiar; +extern struct attrib_type at_clonemage; +extern struct attrib_type at_clone; +extern struct attrib_type at_reportspell; +extern struct attrib_type at_icastle; + +typedef struct icastle_data { + const struct building_type * type; + struct building * building; /* reverse pointer to dissolve the object */ + int time; +} icastle_data; + + +/* ------------------------------------------------------------- */ +/* Kommentare: + * + * Spruchzauberrei und Gegenstandszauberrei werden getrennt behandelt. + * Das macht u.a. bestimmte Fehlermeldungen einfacher, das + * identifizieren der Komponennten über den Missversuch ist nicht + * möglich + * Spruchzauberrei: 'ZAUBER [struct region x y] [STUFE a] "Spruchname" [Ziel]' + * Gegenstandszauberrei: 'BENUTZE "Gegenstand" [Ziel]' + * + * Die Funktionen: + */ + +/* Magier */ +sc_mage * create_mage(struct unit *u, magic_t mtyp); + /* macht die struct unit zu einem neuen Magier: legt die struct u->mage an + * und initialisiert den Magiertypus mit mtyp. */ +sc_mage * get_mage(const struct unit *u); + /* gibt u->mage zurück, bei nicht-Magiern *NULL */ +boolean is_mage(const struct unit *u); + /* gibt true, wenn u->mage gesetzt. */ +boolean is_familiar(const struct unit *u); + /* gibt true, wenn eine Familiar-Relation besteht. */ + +/* Sprüche */ +int get_combatspelllevel(const struct unit *u, int nr); + /* versucht, eine eingestellte maximale Kampfzauberstufe + * zurückzugeben. 0 = Maximum, -1 u ist kein Magier. */ +const spell *get_combatspell(const struct unit *u, int nr); + /* gibt den Kampfzauber nr [pre/kampf/post] oder NULL zurück */ +void set_combatspell(struct unit *u, spell *sp, struct order * ord, int level); + /* setzt Kampfzauber */ +void unset_combatspell(struct unit *u, spell *sp); + /* löscht Kampfzauber */ +void add_spell(spell_list ** slistp, spell *sp); + /* fügt den Spruch mit der Id spellid der Spruchliste der Einheit hinzu. */ +boolean has_spell(struct spell_list *slist, const struct spell * sp); + /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ +boolean u_hasspell(const struct unit * u, const struct spell * sp); + /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ +void update_spellbook(struct faction * f, int level); +void updatespelllist(struct unit *u); + /* fügt alle Zauber des Magiegebietes der Einheit, deren Stufe kleiner + * als das aktuelle Magietalent ist, in die Spruchliste der Einheit + * ein */ +boolean knowsspell(const struct region * r, const struct unit * u, const spell * sp); + /* prüft, ob die Einheit diesen Spruch gerade beherrscht, dh + * mindestens die erforderliche Stufe hat. Hier können auch Abfragen + * auf spezielle Antimagiezauber auf Regionen oder Einheiten eingefügt + * werden + */ + + +/* Magiepunkte */ +int get_spellpoints(const struct unit *u); + /* Gibt die aktuelle Anzahl der Magiepunkte der Einheit zurück */ +void set_spellpoints(struct unit * u, int sp); + /* setzt die Magiepunkte auf sp */ +int change_spellpoints(struct unit *u, int mp); + /* verändert die Anzahl der Magiepunkte der Einheit um +mp */ +int max_spellpoints(const struct region *r, const struct unit *u); + /* gibt die aktuell maximal möglichen Magiepunkte der Einheit zurück */ +int change_maxspellpoints(struct unit * u, int csp); + /* verändert die maximalen Magiepunkte einer Einheit */ + +/* Zaubern */ +extern double spellpower(struct region *r, struct unit *u, const spell *sp, int cast_level, struct order * ord); + /* ermittelt die Stärke eines Spruchs */ +boolean fumble (struct region *r, struct unit *u, const spell *sp, int cast_level); + /* true, wenn der Zauber misslingt, bei false gelingt der Zauber */ + + +typedef struct spellrank { + struct castorder * begin; + struct castorder ** end; +} spellrank; + +castorder *new_castorder(void *u, struct unit *familiar, const spell *sp, struct region *r, + int lev, double force, int distance, struct order * ord, spellparameter *p); + /* Zwischenspreicher für Zauberbefehle, notwendig für Prioritäten */ +void add_castorder(struct spellrank *cll, struct castorder *co); + /* Hänge c-order co an die letze c-order von cll an */ +void free_castorders(struct castorder *co); + /* Speicher wieder freigeben */ + +/* Prüfroutinen für Zaubern */ +int countspells(struct unit *u, int step); + /* erhöht den Counter für Zaubersprüche um 'step' und gibt die neue + * Anzahl der gezauberten Sprüche zurück. */ +int spellcost(struct unit *u, const spell *sp); + /* gibt die für diesen Spruch derzeit notwendigen Magiepunkte auf der + * geringstmöglichen Stufe zurück, schon um den Faktor der bereits + * zuvor gezauberten Sprüche erhöht */ +boolean cancast (struct unit *u, const spell *spruch, int eff_stufe, int distance, struct order * ord); + /* true, wenn Einheit alle Komponenten des Zaubers (incl. MP) für die + * geringstmögliche Stufe hat und den Spruch beherrscht */ +void pay_spell(struct unit *u, const spell *sp, int eff_stufe, int distance); + /* zieht die Komponenten des Zaubers aus dem Inventory der Einheit + * ab. Die effektive Stufe des gezauberten Spruchs ist wichtig für + * die korrekte Bestimmung der Magiepunktkosten */ +int eff_spelllevel(struct unit *u, const spell * sp, int cast_level, int distance); + /* ermittelt die effektive Stufe des Zaubers. Dabei ist cast_level + * die gewünschte maximale Stufe (im Normalfall Stufe des Magiers, + * bei Farcasting Stufe*2^Entfernung) */ +boolean is_magic_resistant(struct unit *magician, struct unit *target, int + resist_bonus); + /* Mapperfunktion für target_resists_magic() vom Typ struct unit. */ +extern double magic_resistance(struct unit *target); + /* gibt die Chance an, mit der einem Zauber widerstanden wird. Je + * größer, desto resistenter ist da Opfer */ +boolean target_resists_magic(struct unit *magician, void *obj, int objtyp, + int resist_bonus); + /* gibt false zurück, wenn der Zauber gelingt, true, wenn das Ziel + * widersteht */ + + +/* 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 boolean 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); + +extern const char * spell_info(const struct spell * sp, const struct locale * lang); +extern const char * spell_name(const struct spell * sp, const struct locale * lang); +extern const char * curse_name(const struct curse_type * ctype, const struct locale * lang); + +extern struct message * msg_unitnotfound(const struct unit * mage, struct order * ord, const struct spllprm * spobj); +extern int FactionSpells(void); +extern struct spell_list ** get_spelllist(struct sc_mage * mage, struct faction * f); + +extern void write_spelllist(const struct spell_list * slist, struct storage * store); +extern void read_spellist(struct spell_list ** slistp, magic_t mtype, struct storage * store); +extern double MagicPower(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/message.c b/src/kernel/message.c new file mode 100644 index 000000000..67ccadfa3 --- /dev/null +++ b/src/kernel/message.c @@ -0,0 +1,283 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "message.h" + +/* kernel includes */ +#include "building.h" +#include "faction.h" +#include "item.h" +#include "order.h" +#include "plane.h" +#include "region.h" +#include "unit.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include + +typedef struct msg_setting { + struct msg_setting *next; + const struct message_type *type; + int level; +} msg_setting; + +/************ Compatibility function *************/ +#define MAXSTRLEN (4*DISPLAYSIZE+3) +#include "region.h" +#include + +static void +arg_set(variant args[], const message_type * mtype, const char * buffer, variant v) +{ + int i; + for (i=0;i!=mtype->nparameters;++i) { + if (!strcmp(buffer, mtype->pnames[i])) break; + } + if (i!=mtype->nparameters) { + args[i] = v; + } else { + fprintf(stderr, "invalid parameter %s for message type %s\n", buffer, mtype->name); + assert(!"program aborted."); + } +} + +struct message * +msg_feedback(const struct unit * u, struct order * ord, const char * name, const char* sig, ...) +{ + va_list marker; + const message_type * mtype = mt_find(name); + char paramname[64]; + const char *ic = sig; + variant args[16]; + variant var; + memset(args, 0, sizeof(args)); + + if (ord==NULL) ord = u->thisorder; + + if (!mtype) { + log_error(("trying to create message of unknown type \"%s\"\n", name)); + return msg_message("missing_feedback", "unit region command name", u, u->region, ord, name); + } + + var.v = (void*)u; + arg_set(args, mtype, "unit", var); + var.v = (void*)u->region; + arg_set(args, mtype, "region", var); + var.v = (void*)ord; + arg_set(args, mtype, "command", var); + + va_start(marker, sig); + while (*ic && !isalnum(*ic)) ic++; + while (*ic) { + char * oc = paramname; + int i; + + while (isalnum(*ic)) *oc++ = *ic++; + *oc = '\0'; + + for (i=0;i!=mtype->nparameters;++i) { + if (!strcmp(paramname, mtype->pnames[i])) break; + } + if (i!=mtype->nparameters) { + if (mtype->types[i]->vtype==VAR_VOIDPTR) { + args[i].v = va_arg(marker, void*); + } else if (mtype->types[i]->vtype==VAR_INT) { + args[i].i = va_arg(marker, int); + } else { + assert(!"unknown variant type"); + } + } else { + log_error(("invalid parameter %s for message type %s\n", paramname, mtype->name)); + assert(!"program aborted."); + } + while (*ic && !isalnum(*ic)) ic++; + } + va_end(marker); + + return msg_create(mtype, args); +} + +message * +msg_message(const char * name, const char* sig, ...) + /* msg_message("oops_error", "unit region command", u, r, cmd) */ +{ + va_list marker; + const message_type * mtype = mt_find(name); + char paramname[64]; + const char *ic = sig; + variant args[16]; + memset(args, 0, sizeof(args)); + + if (!mtype) { + log_error(("trying to create message of unknown type \"%s\"\n", name)); + if (strcmp(name, "missing_message")!=0) { + return msg_message("missing_message", "name", name); + } + return NULL; + } + + va_start(marker, sig); + while (*ic && !isalnum(*ic)) ic++; + while (*ic) { + char * oc = paramname; + int i; + + while (isalnum(*ic)) *oc++ = *ic++; + *oc = '\0'; + + for (i=0;i!=mtype->nparameters;++i) { + if (!strcmp(paramname, mtype->pnames[i])) break; + } + if (i!=mtype->nparameters) { + if (mtype->types[i]->vtype==VAR_VOIDPTR) { + args[i].v = va_arg(marker, void*); + } else if (mtype->types[i]->vtype==VAR_INT) { + args[i].i = va_arg(marker, int); + } else { + assert(!"unknown variant type"); + } + } else { + log_error(("invalid parameter %s for message type %s\n", paramname, mtype->name)); + assert(!"program aborted."); + } + while (*ic && !isalnum(*ic)) ic++; + } + va_end(marker); + + return msg_create(mtype, args); +} + +static void +caddmessage(region * r, faction * f, const char *s, msg_t mtype, int level) +{ + message * m = NULL; + +#define LOG_ENGLISH +#ifdef LOG_ENGLISH + if (f && f->locale!=default_locale) { + log_warning(("message for locale \"%s\": %s\n", locale_name(f->locale), s)); + } +#endif + unused(level); + switch (mtype) { + case MSG_INCOME: + assert(f); + m = add_message(&f->msgs, msg_message("msg_economy", "string", s)); + break; + case MSG_BATTLE: + assert(0 || !"battle-meldungen nicht über addmessage machen"); + break; + case MSG_MOVE: + assert(f); + m = add_message(&f->msgs, msg_message("msg_movement", "string", s)); + break; + case MSG_COMMERCE: + assert(f); + m = add_message(&f->msgs, msg_message("msg_economy", "string", s)); + break; + case MSG_PRODUCE: + assert(f); + m = add_message(&f->msgs, msg_message("msg_production", "string", s)); + break; + case MSG_MAGIC: + case MSG_COMMENT: + case MSG_MESSAGE: + case MSG_ORCVERMEHRUNG: + case MSG_EVENT: + /* Botschaften an REGION oder einzelne PARTEI */ + m = msg_message("msg_event", "string", s); + if (!r) { + assert(f); + m = add_message(&f->msgs, m); + } else { + if (f==NULL) add_message(&r->msgs, m); + else r_addmessage(r, f, m); + } + break; + default: + assert(!"Ungültige Msg-Klasse!"); + } + if (m) msg_release(m); +} + +void +addmessage(region * r, faction * f, const char *s, msg_t mtype, int level) +{ + caddmessage(r, f, s, mtype, level); +} + +void +cmistake(const unit * u, struct order *ord, int mno, int mtype) +{ + static char msgname[20]; + unused(mtype); + + if (is_monsters(u->faction)) return; + sprintf(msgname, "error%d", mno); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, msgname, "")); +} + +extern unsigned int new_hashstring(const char* s); + +void +free_messagelist(message_list * msgs) +{ + struct mlist ** mlistptr = &msgs->begin; + while (*mlistptr) { + struct mlist * ml = *mlistptr; + *mlistptr = ml->next; + msg_release(ml->msg); + free(ml); + } + free(msgs); +} + +message * +add_message(message_list** pm, message * m) +{ + if (!lomem && m!=NULL) { + struct mlist * mnew = malloc(sizeof(struct mlist)); + if (*pm==NULL) { + *pm = malloc(sizeof(message_list)); + (*pm)->end=&(*pm)->begin; + } + mnew->msg = msg_addref(m); + mnew->next = NULL; + *((*pm)->end) = mnew; + (*pm)->end=&mnew->next; + } + return m; +} + + diff --git a/src/kernel/message.h b/src/kernel/message.h new file mode 100644 index 000000000..c3e6e3fbe --- /dev/null +++ b/src/kernel/message.h @@ -0,0 +1,61 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_MESSAGE +#define H_KRNL_MESSAGE +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct message; +struct faction; +struct msglevel; + +struct message_type; + +typedef struct message_list { + struct mlist { + struct mlist * next; + struct message *msg; + } * begin, **end; +} message_list; + +extern void free_messagelist(message_list * msgs); + +typedef struct msglevel { + /* used to set specialized msg-levels */ + struct msglevel *next; + const struct message_type *type; + 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, + const char * name, const char* sig, ...); +extern 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); + +#define ADDMSG(msgs, mcreate) { message * m = mcreate; if (m) { assert(m->refcount>=1); add_message(msgs, m); msg_release(m); } } + +extern void cmistake(const struct unit * u, struct order *ord, int mno, int mtype); +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/move.c b/src/kernel/move.c new file mode 100644 index 000000000..137d3c35d --- /dev/null +++ b/src/kernel/move.c @@ -0,0 +1,2648 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "move.h" + +#include "alchemy.h" +#include "connection.h" +#include "build.h" +#include "building.h" +#include "calendar.h" +#include "curse.h" +#include "faction.h" +#include "item.h" +#include "magic.h" +#include "message.h" +#include "order.h" +#include "plane.h" +#include "race.h" +#include "region.h" +#include "render.h" +#include "reports.h" +#include "save.h" +#include "ship.h" +#include "skill.h" +#include "terrain.h" +#include "teleport.h" +#include "unit.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* attributes includes */ +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +int * storms; + +typedef struct traveldir { + int no; + direction_t dir; + int age; +} traveldir; + +static attrib_type at_traveldir = { + "traveldir", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, /* Weil normales Aging an ungünstiger Stelle */ + a_writechars, + a_readchars +}; + +typedef struct follower { + struct follower * next; + unit * uf; + unit * ut; + const region_list * route_end; +} follower; + +static void +get_followers(unit * target, region * r, const region_list * route_end, follower ** followers) +{ + unit * uf; + for (uf=r->units;uf;uf=uf->next) { + if (fval(uf, UFL_FOLLOWING) && !fval(uf, UFL_NOTMOVING)) { + const attrib * a = a_findc(uf->attribs, &at_follow); + if (a && a->data.v == target) { + follower * fnew = malloc(sizeof(follower)); + fnew->uf = uf; + fnew->ut = target; + fnew->route_end = route_end; + fnew->next = *followers; + *followers = fnew; + } + } + } +} + +static void +shiptrail_init(attrib *a) +{ + a->data.v = calloc(1, sizeof(traveldir)); +} + +static void +shiptrail_finalize(attrib *a) +{ + free(a->data.v); +} + +static int +shiptrail_age(attrib *a) +{ + traveldir *t = (traveldir *)(a->data.v); + + t->age--; + return (t->age>0)?AT_AGE_KEEP:AT_AGE_REMOVE; +} + +static int +shiptrail_read(attrib *a, void * owner, struct storage * store) +{ + traveldir *t = (traveldir *)(a->data.v); + + t->no = store->r_int(store); + t->dir = (direction_t)store->r_int(store); + t->age = store->r_int(store); + return AT_READ_OK; +} + +static void +shiptrail_write(const attrib * a, const void * owner, struct storage * store) +{ + traveldir *t = (traveldir *)(a->data.v); + store->w_int(store, t->no); + store->w_int(store, t->dir); + store->w_int(store, t->age); +} + +attrib_type at_shiptrail = { + "traveldir_new", + shiptrail_init, + shiptrail_finalize, + shiptrail_age, + shiptrail_write, + shiptrail_read +}; + +static int +age_speedup(attrib *a) +{ + if (a->data.sa[0] > 0) { + a->data.sa[0] = a->data.sa[0] - a->data.sa[1]; + } + return (a->data.sa[0]>0)?AT_AGE_KEEP:AT_AGE_REMOVE; +} + +attrib_type at_speedup = { + "speedup", + NULL, NULL, + age_speedup, + a_writeint, + a_readint +}; + +/* ------------------------------------------------------------- */ + +direction_t +getdirection(const struct locale * lang) +{ + return finddirection(getstrtoken(), lang); +} +/* ------------------------------------------------------------- */ + +static attrib_type at_driveweight = { + "driveweight", NULL, NULL, NULL, NULL, NULL +}; + +static boolean +entrance_allowed(const struct unit * u, const struct region * r) +{ +#ifdef REGIONOWNERS + faction * owner = region_get_owner(r); + if (owner == NULL || u->faction == owner) return true; + if (alliedfaction(rplane(r), owner, u->faction, HELP_TRAVEL)) return true; + return false; +#else + return true; +#endif +} + +int +personcapacity(const unit *u) +{ + int cap = u->race->weight+u->race->capacity; + return cap; +} + +static int +eff_weight(const unit *u) +{ + attrib *a = a_find(u->attribs, &at_driveweight); + + if (a) return weight(u) + a->data.i; + + return weight(u); +} + +static void +get_transporters(const item * itm, int * p_animals, int *p_acap, int * p_vehicles, int * p_vcap) +{ + int vehicles = 0, vcap = 0; + int animals = 0, acap = 0; + + for (;itm!=NULL;itm=itm->next) { + const item_type * itype = itm->type; + if (itype->capacity>0) { + if (itype->flags & ITF_ANIMAL) { + animals += itm->number; + if (acap==0) acap = itype->capacity; + assert(acap==itype->capacity || !"animals with different capacity not supported"); + } + if (itype->flags & ITF_VEHICLE) { + vehicles += itm->number; + if (vcap==0) vcap = itype->capacity; + assert(vcap==itype->capacity || !"vehicles with different capacity not supported"); + } + } + } + *p_vehicles = vehicles; + *p_animals = animals; + *p_vcap = vcap; + *p_acap = acap; +} + +static int +ridingcapacity(unit * u) +{ + int vehicles = 0, vcap = 0; + int animals = 0, acap = 0; + + get_transporters(u->items, &animals, &acap, &vehicles, &vcap); + + /* Man trägt sein eigenes Gewicht plus seine Kapazität! Die Menschen + ** tragen nichts (siehe walkingcapacity). Ein Wagen zählt nur, wenn er + ** von zwei Pferden gezogen wird */ + + animals = MIN(animals, effskill(u, SK_RIDING) * u->number * 2); + if (fval(u->race, RCF_HORSE)) animals += u->number; + + /* maximal diese Pferde können zum Ziehen benutzt werden */ + vehicles = MIN(animals / HORSESNEEDED, vehicles); + + return vehicles * vcap + animals * acap; +} + +int +walkingcapacity(const struct unit * u) +{ + int n, tmp, people, pferde_fuer_wagen; + int wagen_ohne_pferde, wagen_mit_pferden, wagen_mit_trollen; + int vehicles = 0, vcap = 0; + int animals = 0, acap = 0; + + get_transporters(u->items, &animals, &acap, &vehicles, &vcap); + + /* Das Gewicht, welches die Pferde tragen, plus das Gewicht, welches + * die Leute tragen */ + + pferde_fuer_wagen = MIN(animals, effskill(u, SK_RIDING) * u->number * 4); + if (fval(u->race, RCF_HORSE)) { + animals += u->number; + people = 0; + } else { + people = u->number; + } + + /* maximal diese Pferde können zum Ziehen benutzt werden */ + wagen_mit_pferden = MIN(vehicles, pferde_fuer_wagen / HORSESNEEDED); + + n = wagen_mit_pferden * vcap; + + if (u->race == new_race[RC_TROLL]) { + /* 4 Trolle ziehen einen Wagen. */ + /* Unbesetzte Wagen feststellen */ + wagen_ohne_pferde = vehicles - wagen_mit_pferden; + + /* Genug Trolle, um die Restwagen zu ziehen? */ + wagen_mit_trollen = MIN(u->number / 4, wagen_ohne_pferde); + + /* Wagenkapazität hinzuzählen */ + n += wagen_mit_trollen * vcap; + wagen_ohne_pferde -= wagen_mit_trollen; + } + + n += animals * acap; + n += people * personcapacity(u); + /* Goliathwasser */ + tmp = get_effect(u, oldpotiontype[P_STRONG]); + if (tmp>0) { + int horsecap = olditemtype[I_HORSE]->capacity; + if (tmp>people) tmp = people; + n += tmp * (horsecap - personcapacity(u)); + } + /* change_effect wird in ageing gemacht */ + tmp = get_item(u, I_TROLLBELT); + n += MIN(people, tmp) * (STRENGTHMULTIPLIER-1) * personcapacity(u); + + return n; +} + +enum { + E_CANWALK_OK = 0, + E_CANWALK_TOOMANYHORSES, + E_CANWALK_TOOMANYCARTS, + E_CANWALK_TOOHEAVY +}; + +static int +canwalk(unit * u) +{ + int maxwagen, maxpferde; + int vehicles = 0, vcap = 0; + int animals = 0, acap = 0; + + /* workaround: monsters are too stupid to drop items, therefore they have + * infinite carrying capacity */ + + if (is_monsters(u->faction)) return E_CANWALK_OK; + + get_transporters(u->items, &animals, &acap, &vehicles, &vcap); + + maxwagen = effskill(u, SK_RIDING) * u->number * 2; + if (u->race == new_race[RC_TROLL]) { + maxwagen = MAX(maxwagen, u->number / 4); + } + maxpferde = effskill(u, SK_RIDING) * u->number * 4 + u->number; + + if (animals > maxpferde) + return E_CANWALK_TOOMANYHORSES; + + if (walkingcapacity(u) - eff_weight(u) >= 0) + return E_CANWALK_OK; + + /* Stimmt das Gewicht, impliziert dies hier, daß alle Wagen ohne + * Zugpferde/-trolle als Fracht aufgeladen wurden: zu viele Pferde hat + * die Einheit nicht zum Ziehen benutzt, also nicht mehr Wagen gezogen + * als erlaubt. */ + + if (vehicles > maxwagen) + return E_CANWALK_TOOMANYCARTS; + /* Es muß nicht zwingend an den Wagen liegen, aber egal... (man + * könnte z.B. auch 8 Eisen abladen, damit ein weiterer Wagen als + * Fracht draufpaßt) */ + + return E_CANWALK_TOOHEAVY; +} + +boolean +canfly(unit *u) +{ + if (get_item(u, I_PEGASUS) >= u->number && effskill(u, SK_RIDING) >= 4) + return true; + + if (fval(u->race, RCF_FLY)) return true; + + if (get_movement(&u->attribs, MV_FLY)) return true; + + return false; +} + +boolean +canswim(unit *u) +{ + if (get_item(u, I_DOLPHIN) >= u->number && effskill(u, SK_RIDING) >= 4) + return true; + + if (u->race->flags & RCF_FLY) return true; + + if (u->race->flags & RCF_SWIM) return true; + + if (get_movement(&u->attribs, MV_FLY)) return true; + + if (get_movement(&u->attribs, MV_SWIM)) return true; + + return false; +} + +static int +canride(unit * u) +{ + int horses = 0, maxhorses, unicorns = 0, maxunicorns; + int skill = effskill(u, SK_RIDING); + item * itm; + static const item_type * it_horse = 0; + static const item_type * it_elvenhorse = 0; + static const item_type * it_charger = 0; + + if (it_horse==0) { + it_horse = it_find("horse"); + it_elvenhorse = it_find("elvenhorse"); + it_charger = it_find("charger"); + } + + for (itm=u->items;itm;itm=itm->next) { + if (itm->type==it_horse || itm->type==it_charger) { + horses += itm->number; + } else if (itm->type==it_elvenhorse) { + unicorns += itm->number; + } + } + + maxunicorns = (skill/5) * u->number; + maxhorses = skill * u->number * 2; + + if(!(u->race->flags & RCF_HORSE) + && ((horses == 0 && unicorns == 0) + || horses > maxhorses || unicorns > maxunicorns)) { + return 0; + } + + if (ridingcapacity(u) - eff_weight(u) >= 0) { + if (horses == 0 && unicorns >= u->number && !(u->race->flags & RCF_HORSE)) { + return 2; + } + return 1; + } + + return 0; +} + +static boolean +cansail(const region * r, ship * sh) +{ + /* sonst ist construction:: size nicht ship_type::maxsize */ + assert(!sh->type->construction || sh->type->construction->improvement == NULL); + + if (sh->type->construction && sh->size!=sh->type->construction->maxsize) { + return false; + } else { + int n = 0, p = 0; + int mweight = shipcapacity(sh); + int mcabins = sh->type->cabins; + + getshipweight(sh, &n, &p); + + if (n > mweight) return false; + if (mcabins && p > mcabins) return false; + } + return true; +} + +int +enoughsailors(const ship * sh, const region * r) +{ + int n; + unit *u; + + n = 0; + + for (u = r->units; u; u = u->next) { + if (u->ship == sh) + n += eff_skill(u, SK_SAILING, r) * u->number; + } + return n >= sh->type->sumskill; +} +/* ------------------------------------------------------------- */ + +static ship * +do_maelstrom(region *r, unit *u) +{ + int damage; + ship * sh = u->ship; + + damage = rng_int()%75 + rng_int()%75 - eff_skill(u, SK_SAILING, r)*4; + + if (damage <= 0) { + return sh; + } + + damage_ship(u->ship, 0.01*damage); + + if (sh->damage >= sh->size * DAMAGE_SCALE) { + ADDMSG(&u->faction->msgs, msg_message("entermaelstrom", + "region ship damage sink", r, sh, damage, 1)); + remove_ship(&sh->region->ships, sh); + return NULL; + } + ADDMSG(&u->faction->msgs, msg_message("entermaelstrom", + "region ship damage sink", r, sh, damage, 0)); + return u->ship; +} + +/** sets a marker in the region telling that the unit has travelled through it + * this is used for two distinctly different purposes: + * - to report that a unit has travelled through. the report function + * makes sure to only report the ships of travellers, not the travellers + * themselves + * - to report the region to the traveller + */ +void +travelthru(const unit * u, region * r) +{ + attrib *ru = a_add(&r->attribs, a_new(&at_travelunit)); + + fset(r, RF_TRAVELUNIT); + + ru->data.v = (void*)u; + + /* the first and last region of the faction gets reset, because travelthrough + * could be in regions that are located before the [first, last] interval, + * and recalculation is needed */ +#ifdef SMART_INTERVALS + update_interval(u->faction, r); +#endif +} + +static void +leave_trail(ship * sh, region * from, region_list *route) +{ + region * r = from; + + while (route!=NULL) { + region * rn = route->data; + direction_t dir = reldirection(r, rn); + + /* TODO: we cannot leave a trail into special directions + * if we use this kind of direction-attribute */ + if (dir=0) { + traveldir * td = NULL; + attrib * a = a_find(r->attribs, &at_shiptrail); + + while (a!=NULL && a->type==&at_shiptrail) { + td = (traveldir *)a->data.v; + if (td->no == sh->no) break; + a = a->next; + } + + if (a == NULL || a->type!=&at_shiptrail) { + a = a_add(&(r->attribs), a_new(&at_shiptrail)); + td = (traveldir *)a->data.v; + td->no = sh->no; + } + td->dir = dir; + td->age = 2; + } + route = route->next; + r = rn; + } +} + +static void +mark_travelthru(const unit * u, region * r, const region_list * route, const region_list * route_end) +{ + /* kein travelthru in der letzten region! */ + while (route!=route_end) { + travelthru(u, r); + r = route->data; + route = route->next; + } +} + +ship * +move_ship(ship * sh, region * from, region * to, region_list * route) +{ + unit **iunit = &from->units; + unit **ulist = &to->units; + boolean trail = (route == NULL); + + if (from!=to) { + translist(&from->ships, &to->ships, sh); + sh->region = to; + } + if (!trail) { + leave_trail(sh, from, route); + trail = true; + } + + while (*iunit!=NULL) { + unit *u = *iunit; + assert(u->region == from); + + if (u->ship == sh) { + if (route!=NULL) mark_travelthru(u, from, route, NULL); + if (from!=to) { + u->ship = NULL; /* damit move_unit() kein leave() macht */ + move_unit(u, to, ulist); + ulist = &u->next; + u->ship = sh; + } + if (route && eff_skill(u, SK_SAILING, from) >= 1) { + produceexp(u, SK_SAILING, u->number); + } + } + if (*iunit == u) iunit=&u->next; + } + + return sh; +} + +static boolean +is_freezing(const unit * u) +{ + if (u->race!=new_race[RC_INSECT]) return false; + if (is_cursed(u->attribs, C_KAELTESCHUTZ, 0)) return false; + return true; +} + +static boolean +ship_allowed(const struct ship * sh, const region * r) +{ + int c = 0; + static const building_type * bt_harbour=NULL; + + if (bt_harbour == NULL) bt_harbour=bt_find("harbour"); + + if (r_insectstalled(r)) { + /* insekten dürfen nicht hier rein. haben wir welche? */ + unit * u; + + for (u=sh->region->units;u!=NULL;u=u->next) { + if (u->ship!=sh) continue; + + if (is_freezing(u)) { + unit * captain = shipowner(sh); + if (captain) { + ADDMSG(&captain->faction->msgs, msg_message("detectforbidden", + "unit region", u, r)); + } + + return false; + } + } + } + + if (buildingtype_exists(r, bt_harbour, true)) return true; + for (c=0;sh->type->coasts[c]!=NULL;++c) { + if (sh->type->coasts[c] == r->terrain) return true; + } + + return false; +} + +static boolean +flying_ship(const ship * sh) +{ + if (sh->type->flags & SFL_FLY) return true; + if (sh->flags & SF_FLYING) return true; + return false; +} + +static void +set_coast(ship * sh, region * r, region * rnext) +{ + if (sh->type->flags & SFL_NOCOAST) { + sh->coast = NODIRECTION; + } else if (!fval(rnext->terrain, SEA_REGION) && !flying_ship(sh)) { + sh->coast = reldirection(rnext, r); + assert(fval(r->terrain, SEA_REGION)); + } else { + sh->coast = NODIRECTION; + } +} + +static float +damage_drift(void) +{ + static float value = -1.0F; + if (value<0) { + value = get_param_flt(global.parameters, "rules.ship.damage_drift", 0.02F); + } + return value; +} + +static void +drifting_ships(region * r) +{ + direction_t d; + + if (fval(r->terrain, SEA_REGION)) { + ship** shp = &r->ships; + while (*shp) { + ship * sh = *shp; + region * rnext = NULL; + region_list * route = NULL; + unit *firstu = NULL, *captain; + int d_offset; + direction_t dir = 0; + + if (sh->type->fishing>0) { + sh->flags |= SF_FISHING; + } + + /* Schiff schon abgetrieben oder durch Zauber geschützt? */ + if (fval(sh, SF_DRIFTED) || is_cursed(sh->attribs, C_SHIP_NODRIFT, 0)) { + shp = &sh->next; + continue; + } + + /* Kapitän bestimmen */ + for (captain = r->units; captain; captain = captain->next) { + if (captain->ship != sh) continue; + if (firstu==NULL) firstu = captain; + if (eff_skill(captain, SK_SAILING, r) >= sh->type->cptskill) { + break; + } + } + /* Kapitän da? Beschädigt? Genügend Matrosen? + * Genügend leicht? Dann ist alles OK. */ + + assert(sh->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (captain && sh->size == sh->type->construction->maxsize && enoughsailors(sh, r) && cansail(r, sh)) { + shp = &sh->next; + continue; + } + + /* Auswahl einer Richtung: Zuerst auf Land, dann + * zufällig. Falls unmögliches Resultat: vergiß es. */ + d_offset = rng_int() % MAXDIRECTIONS; + for (d = 0; d != MAXDIRECTIONS; ++d) { + region * rn; + dir = (direction_t)((d + d_offset) % MAXDIRECTIONS); + rn = rconnect(r, dir); + if (rn!=NULL && fval(rn->terrain, SAIL_INTO) && ship_allowed(sh, rn)) { + rnext = rn; + if (!fval(rnext->terrain, SEA_REGION)) break; + } + } + + if (rnext == NULL) { + shp = &sh->next; + continue; + } + + /* Das Schiff und alle Einheiten darin werden nun von r + * nach rnext verschoben. Danach eine Meldung. */ + add_regionlist(&route, rnext); + + set_coast(sh, r, rnext); + sh = move_ship(sh, r, rnext, route); + free_regionlist(route); + + if (firstu!=NULL) { + unit *u, *lastu = NULL; + message * msg = msg_message("ship_drift", "ship dir", sh, dir); + for (u=firstu;u;u=u->next) { + if (u->ship==sh && !fval(u->faction, FFL_MARK)) { + fset(u->faction, FFL_MARK); + add_message(&u->faction->msgs, msg); + lastu = u->next; + } + } + for (u=firstu;u!=lastu;u=u->next) { + freset(u->faction, FFL_MARK); + } + msg_release(msg); + } + + if (sh!=NULL) { + fset(sh, SF_DRIFTED); + + damage_ship(sh, damage_drift()); + if (sh->damage>=sh->size * DAMAGE_SCALE) { + remove_ship(&sh->region->ships, sh); + } + } + + if (*shp == sh) shp = &sh->next; + } + } +} + +static boolean +present(region * r, unit * u) +{ + return (boolean) (u && u->region == r); +} + +static void +caught_target(region * r, unit * u) +{ + attrib * a = a_find(u->attribs, &at_follow); + + /* Verfolgungen melden */ + /* Misserfolgsmeldung, oder bei erfolgreichem Verfolgen unter + * Umstaenden eine Warnung. */ + + if (a) { + unit * target = (unit*)a->data.v; + + if (!present(r, target)) { + ADDMSG(&u->faction->msgs, msg_message("followfail", "unit follower", + target, u)); + } else if (!alliedunit(target, u->faction, HELP_ALL) + && cansee(target->faction, r, u, 0)) + { + ADDMSG(&target->faction->msgs, msg_message("followdetect", + "unit follower", target, u)); + } + } +} + +/* TODO: Unsichtbarkeit bedenken ! */ + +static unit * +bewegung_blockiert_von(unit * reisender, region * r) +{ + unit *u; + int perception = 0; + boolean contact = false; + unit * guard = NULL; + + if (fval(reisender->race, RCF_ILLUSIONARY)) return NULL; + for (u=r->units;u && !contact;u=u->next) { + if (is_guard(u, GUARD_TRAVELTHRU)) { + int sk = eff_skill(u, SK_PERCEPTION, r); + if (invisible(reisender, u) >= reisender->number) continue; + if (u->faction == reisender->faction) contact = true; + else if (ucontact(u, reisender)) contact = true; + else if (alliedunit(u, reisender->faction, HELP_GUARD)) contact = true; + else if (sk>=perception) { + perception = sk; + guard = u; + } + } + } + if (!contact && guard) { + double prob = 0.3; /* 30% base chance */ + prob += 0.1 * (perception - eff_stealth(reisender, r)); + prob += 0.1 * MIN(guard->number, get_item(guard, I_AMULET_OF_TRUE_SEEING)); + + if (chance(prob)) { + return guard; + } + } + return NULL; +} + +static boolean +is_guardian_u(const unit * guard, unit *u, unsigned int mask) +{ + if (guard->faction == u->faction) return false; + if (is_guard(guard, mask) == 0) return false; + if (alliedunit(guard, u->faction, HELP_GUARD)) return false; + if (ucontact(guard, u)) return false; + if (!cansee(guard->faction, u->region, u, 0)) return false; + + return true; +} + +static boolean +is_guardian_r(const unit * guard) +{ + if (guard->number == 0) return false; + if (besieged(guard)) return false; + + /* if region_owners exist then they may be guardians: */ + if (guard->building && rule_region_owners() && fval(guard, UFL_OWNER)) { + faction * owner = region_get_owner(guard->region); + if (owner==guard->faction) { + building * bowner = largestbuilding(guard->region, &cmp_taxes, false); + if (bowner==guard->building) { + return true; + } + } + } + + if ((guard->flags&UFL_GUARD)==0) return false; + if (!armedmen(guard, true) && !fval(guard->race, RCF_UNARMEDGUARD)) return false; + return true; +} + +boolean is_guard(const struct unit * u, int mask) +{ + return is_guardian_r(u) && (getguard(u) & mask)!=0; +} + +#define MAXGUARDCACHE 16 +/** returns the guard which prevents 'u' from doing 'mask' actions in 'r'. +*/ +unit * +is_guarded(region * r, unit * u, unsigned int mask) +{ + unit *u2 = NULL; + int i, noguards = 1; + static unit * guardcache[MAXGUARDCACHE], * lastguard; /* STATIC_XCALL: used across calls */ + static int gamecookie = -1; + + if (!fval(r, RF_GUARDED)) { + return NULL; + } + + if (gamecookie!=global.cookie) { + if (gamecookie>=0) { + /* clear the previous turn's cache */ + memset(guardcache, 0, sizeof(guardcache)); + lastguard = NULL; + } + gamecookie = global.cookie; + } + + if (lastguard && lastguard->region==r) { + if (is_guardian_u(lastguard, u, mask)) { + return lastguard; + } + } + + for (i=0;i!=MAXGUARDCACHE;++i) { + unit * guard = guardcache[i]; + if (guard && guard!=lastguard && guard->region==r) { + noguards = 0; + if (is_guardian_u(guard, u, mask)) { + lastguard = guard; + return guard; + } + if (u2==guard) { + /* same guard twice signals we've tested everyone */ + return NULL; + } + u2 = guard; + } else { + /* exhausted all the guards in the cache, but maybe we'll find one later? */ + break; + } + } + + /* at this point, u2 is the last unit we tested to + * be a guard (and failed), or NULL + * i is the position of the first free slot in the cache */ + + for (u2 = (u2?u2->next:r->units); u2; u2=u2->next) { + if (is_guardian_r(u2)) { + noguards = 0; + /* u2 is a guard, so worth remembering */ + if (i0 && ifaction->locale; + pause = false; + token = getstrtoken(); + d = finddirection(token, lang); + if(d == D_PAUSE) { + pause = true; + } else if (d == NODIRECTION) { + break; + } + if (cmsizeof(neworder)/2) break; + else if (cm == gereist && !paused && pause) { + const char * loc = LOC(lang, parameters[P_PAUSE]); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, loc, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + paused = true; + } + else if (pause) { + /* da PAUSE nicht in ein shortdirections[d] umgesetzt wird (ist + * hier keine normale direction), muss jede PAUSE einzeln + * herausgefiltert und explizit gesetzt werden */ + if (neworder[0]) strcat(neworder, " "); + strcat(neworder, LOC(lang, parameters[P_PAUSE])); + } else { + if (neworder[0]) strcat(neworder, " "); + strcat(neworder, LOC(lang, shortdirections[d])); + } + } + + if (neworder[0]) { + norder = create_order(K_ROUTE, u->faction->locale, "%s %s", neworder, tail); + } else { + norder = create_order(K_ROUTE, u->faction->locale, "%s", tail); + } + replace_order(&u->orders, ord, norder); + free_order(norder); +} + +static boolean +transport(unit * ut, unit * u) +{ + order * ord; + + if (LongHunger(u) || fval(ut->region->terrain, SEA_REGION)) { + return false; + } + + for (ord = ut->orders; ord; ord = ord->next) { + if (get_keyword(ord) == K_TRANSPORT) { + init_tokens(ord); + skip_token(); + if (getunit(ut->region, ut->faction) == u) { + return true; + } + } + } + return false; +} + +static boolean +can_move(const unit * u) +{ + if (u->race->flags & RCF_CANNOTMOVE) return false; + if (get_movement(&u->attribs, MV_CANNOTMOVE)) return false; + return true; +} + +static void +init_transportation(void) +{ + region *r; + + for (r=regions; r; r=r->next) { + unit *u; + + /* This is just a simple check for non-corresponding K_TRANSPORT/ + * K_DRIVE. This is time consuming for an error check, but there + * doesn't seem to be an easy way to speed this up. */ + for (u=r->units; u; u=u->next) { + if (get_keyword(u->thisorder) == K_DRIVE && can_move(u) && !fval(u, UFL_NOTMOVING) && !LongHunger(u)) { + unit * ut; + + init_tokens(u->thisorder); + skip_token(); + ut = getunit(r, u->faction); + if (ut == NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); + continue; + } + if (!transport(ut, u)) { + if (cansee(u->faction, r, ut, 0)) { + cmistake(u, u->thisorder, 286, MSG_MOVE); + } else { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); + } + } + } + } + + /* This calculates the weights of all transported units and + * adds them to an internal counter which is used by travel () to + * calculate effective weight and movement. */ + + if (!fval(r->terrain, SEA_REGION)) { + for (u=r->units; u; u=u->next) { + order * ord; + int w = 0; + + for (ord = u->orders; ord; ord = ord->next) { + if (get_keyword(ord) == K_TRANSPORT) { + init_tokens(ord); + skip_token(); + for (;;) { + unit * ut = getunit(r, u->faction); + + if (ut == NULL) break; + if (get_keyword(ut->thisorder) == K_DRIVE && can_move(ut) && !fval(ut, UFL_NOTMOVING) && !LongHunger(ut)) { + init_tokens(ut->thisorder); + skip_token(); + if (getunit(r, ut->faction) == u) { + w += weight(ut); + } + } + } + } + } + if (w > 0) a_add(&u->attribs, a_new(&at_driveweight))->data.i = w; + } + } + } +} + +static boolean +roadto(const region * r, direction_t dir) +{ + /* wenn es hier genug strassen gibt, und verbunden ist, und es dort + * genug strassen gibt, dann existiert eine strasse in diese richtung */ + region * r2; + static const curse_type * roads_ct = NULL; + + if (dir>=MAXDIRECTIONS || dir<0) return false; + r2 = rconnect(r, dir); + if (r == NULL || r2 == NULL) return false; + + if (roads_ct == NULL) roads_ct = ct_find("magicstreet"); + if (roads_ct!=NULL) { + if (get_curse(r->attribs, roads_ct)!=NULL) return true; + if (get_curse(r2->attribs, roads_ct)!=NULL) return true; + } + + if (r->terrain->max_road <= 0) return false; + if (r2->terrain->max_road <= 0) return false; + if (rroad(r, dir) < r->terrain->max_road) return false; + if (rroad(r2, dir_invert(dir)) < r2->terrain->max_road) return false; + return true; +} + +static const region_list * +cap_route(region * r, const region_list * route, const region_list * route_end, int speed) +{ + region * current = r; + int moves = speed; + const region_list * iroute = route; + while (iroute!=route_end) { + region * next = iroute->data; + direction_t reldir = reldirection(current, next); + + /* adjust the range of the unit */ + if (roadto(current, reldir)) moves -= BP_ROAD; + else moves -= BP_NORMAL; + if (moves<0) break; + iroute = iroute->next; + current = next; + } + return iroute; +} + +static region * +next_region(unit * u, region * current, region * next) +{ + connection * b; + + b = get_borders(current, next); + while (b!=NULL) { + if (b->type->move) { + region * rto = b->type->move(b, u, current, next, true); + if (rto!=next) { + /* the target region was changed (wisps, for example). check the + * new target region for borders */ + next = rto; + b = get_borders(current, next); + continue; + } + } + b = b->next; + } + return next; +} + +static const region_list * +reroute(unit * u, const region_list * route, const region_list * route_end) +{ + region * current = u->region; + while (route!=route_end) { + region * next = next_region(u, current, route->data); + if (next!=route->data) break; + route = route->next; + } + return route; +} + +static void +make_route(unit * u, order * ord, region_list ** routep) +{ + region_list **iroute = routep; + region * current = u->region; + region * next = NULL; + const char * token = getstrtoken(); + int error = movewhere(u, token, current, &next); + + if (error!=E_MOVE_OK) { + message * msg = movement_error(u, token, ord, error); + if (msg!=NULL) { + add_message(&u->faction->msgs, msg); + msg_release(msg); + } + next = NULL; + } + + while (next!=NULL) { + direction_t reldir; + + if (current == next) { + /* PAUSE */ + break; + } + next = next_region(u, current, next); + reldir = reldirection(current, next); + + add_regionlist(iroute, next); + iroute = &(*iroute)->next; + + current = next; + token = getstrtoken(); + error = movewhere(u, token, current, &next); + if (error) { + message * msg = movement_error(u, token, ord, error); + if (msg!=NULL) { + add_message(&u->faction->msgs, msg); + msg_release(msg); + } + next = NULL; + } + } +} + +/** calculate the speed of a unit + * + * zu Fuß reist man 1 Region, zu Pferd 2 Regionen. Mit Straßen reist + * man zu Fuß 2, mit Pferden 3 weit. + * + * Berechnet wird das mit BPs. Zu Fuß hat man 4 BPs, zu Pferd 6. + * 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 mp; + static const curse_type * speed_ct; + static boolean init = false; + double dk = u->race->speed; + + assert(u->number); + /* dragons have a fixed speed, and no other effects work on them: */ + switch (old_race(u->race)) { + case RC_DRAGON: + case RC_WYRM: + case RC_FIREDRAGON: + case RC_BIRTHDAYDRAGON: + case RC_SONGDRAGON: + return BP_DRAGON; + } + + if (!init) { + init = true; + speed_ct = ct_find("speed"); + } + if (speed_ct) { + curse *c = get_curse(u->attribs, speed_ct); + if (c!=NULL) { + int men = get_cursedmen(u, c); + dk *= 1.0 + (double)men/(double)u->number; + } + } + + switch (canride(u)) { + + case 1: /* Pferd */ + mp = BP_RIDING; + break; + + case 2: /* Einhorn */ + mp = BP_UNICORN; + break; + + default: + mp = BP_WALKING; + + /* 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 <= get_item(u, I_FEENSTIEFEL)) { + mp *= 2; + } + + /* Im Astralraum sind Tyb und Ill-Magier doppelt so schnell. + * Nicht kumulativ mit anderen Beschleunigungen! */ + if (mp*dk <= BP_WALKING*u->race->speed && is_astral(u->region) && is_mage(u)) { + sc_mage * mage = get_mage(u); + if (mage->magietyp == M_TYBIED || mage->magietyp == M_ILLAUN) { + mp *= 2; + } + } + break; + } + return (int)(dk*mp); +} + +enum { + TRAVEL_NORMAL, + TRAVEL_FOLLOWING, + TRAVEL_TRANSPORTED, + TRAVEL_RUNNING +}; + +static arg_regions * +var_copy_regions(const region_list * begin, int size) +{ + const region_list * rsrc; + + if (size>0) { + int i = 0; + arg_regions * dst = (arg_regions *)malloc(sizeof(arg_regions) + sizeof(region*) * size); + dst->nregions = size; + dst->regions = (region**)(dst+1); + for (rsrc = begin; i!=size; rsrc=rsrc->next) { + dst->regions[i++] = rsrc->data; + } + return dst; + } + return NULL; +} + + +static const region_list * +travel_route(unit * u, const region_list * route_begin, const region_list * route_end, order * ord, int mode) +{ + region * r = u->region; + region * current = u->region; + const region_list * iroute = route_begin; + int steps = 0; + boolean landing = false; /* aquarians have landed */ + + while (iroute && iroute!=route_end) { + region * next = iroute->data; + direction_t reldir = reldirection(current, next); + connection * b = get_borders(current, next); + + /* check if we are caught by guarding units */ + if (iroute!=route_begin && mode!=TRAVEL_RUNNING && mode!=TRAVEL_TRANSPORTED) { + unit * wache = bewegung_blockiert_von(u, current); + if (wache!=NULL) { + ADDMSG(&u->faction->msgs, msg_message("moveblockedbyguard", + "unit region guard", u, current, wache)); + break; + } + } + + /* check movement from/to oceans. + * aquarian special, flying units, horses, the works */ + if ((u->race->flags & RCF_FLY) == 0) { + if (!fval(next->terrain, SEA_REGION)) { + /* next region is land */ + if (fval(current->terrain, SEA_REGION)) { + int moving = u->race->flags & (RCF_SWIM|RCF_WALK|RCF_COASTAL); + /* Die Einheit kann nicht fliegen, ist im Ozean, und will an Land */ + if (moving != (RCF_SWIM|RCF_WALK) && (moving&RCF_COASTAL) == 0) { + /* can't swim+walk and isn't allowed to enter coast from sea */ + if (ord!=NULL) cmistake(u, ord, 44, MSG_MOVE); + break; + } + landing = true; + } else if ((u->race->flags & RCF_WALK) == 0) { + /* Spezialeinheiten, die nicht laufen können. */ + ADDMSG(&u->faction->msgs, msg_message("detectocean", + "unit region", u, next)); + break; + } else if (landing) { + /* wir sind diese woche angelandet */ + ADDMSG(&u->faction->msgs, msg_message("detectocean", + "unit region", u, next)); + break; + } + } else { + /* Ozeanfelder können nur von Einheiten mit Schwimmen und ohne + * Pferde betreten werden. */ + if (!(canswim(u) || canfly(u))) { + ADDMSG(&u->faction->msgs, msg_message("detectocean", + "unit region", u, next)); + break; + } + } + + if (fval(current->terrain, SEA_REGION) || fval(next->terrain, SEA_REGION)) { + /* trying to enter or exit ocean with horses, are we? */ + if (has_horses(u)) { + /* tries to do it with horses */ + if (ord!=NULL) cmistake(u, ord, 67, MSG_MOVE); + break; + } + } + + } + + /* movement blocked by a wall */ + if (reldir>=0 && move_blocked(u, current, next)) { + ADDMSG(&u->faction->msgs, msg_message("leavefail", + "unit region", u, next)); + break; + } + + /* region ownership only: region owned by enemies */ + if (!entrance_allowed(u, next)) { + ADDMSG(&u->faction->msgs, msg_message("regionowned", + "unit region target", u, current, next)); + break; + } + + /* illusionary units disappear in antimagic zones */ + if (fval(u->race, RCF_ILLUSIONARY)) { + curse * c = get_curse(next->attribs, ct_find("antimagiczone")); + if (curse_active(c)) { + curse_changevigour(&next->attribs, c, (float)-u->number); + ADDMSG(&u->faction->msgs, msg_message("illusionantimagic", "unit", u)); + set_number(u, 0); + break; + } + } + + /* terrain is marked as forbidden (curse, etc) */ + if (fval(next, RF_BLOCKED) || fval(next->terrain, FORBIDDEN_REGION)) { + ADDMSG(&u->faction->msgs, msg_message("detectforbidden", + "unit region", u, next)); + break; + } + + /* unit is an insect and cannot move into a glacier */ + if (u->race == new_race[RC_INSECT]) { + if (r_insectstalled(next) && is_freezing(u)) { + ADDMSG(&u->faction->msgs, msg_message("detectforbidden", + "unit region", u, next)); + break; + } + } + + /* effect of borders */ + while (b!=NULL) { + if (b->type->move) { + b->type->move(b, u, current, next, false); + } + b = b->next; + } + + current = next; + iroute = iroute->next; + ++steps; + if (u->number == 0) break; + } + + if (iroute!=route_begin) { + /* the unit has moved at least one region */ + int walkmode; + + setguard(u, GUARD_NONE); + cycle_route(ord, u, steps); + + if (mode == TRAVEL_RUNNING) { + walkmode = 0; + } if (canride(u)) { + walkmode = 1; + produceexp(u, SK_RIDING, u->number); + } else { + walkmode = 2; + } + + /* Berichte über Durchreiseregionen */ + + if (mode!=TRAVEL_TRANSPORTED) { + arg_regions * ar = var_copy_regions(route_begin, steps-1); + ADDMSG(&u->faction->msgs, msg_message("travel", + "unit mode start end regions", u, walkmode, r, current, ar)); + } + + mark_travelthru(u, r, route_begin, iroute); + move_unit(u, current, NULL); + + /* make orders for the followers */ + } + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + setguard(u, GUARD_NONE); + assert(u->region == current); + return iroute; +} + +static boolean +ship_ready(const region * r, unit * u) +{ + if (!fval(u, UFL_OWNER)) { + cmistake(u, u->thisorder, 146, MSG_MOVE); + return false; + } + if (eff_skill(u, SK_SAILING, r) < u->ship->type->cptskill) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_captain_skill_low", + "value ship", u->ship->type->cptskill, u->ship)); + return false; + } + assert(u->ship->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (u->ship->size!=u->ship->type->construction->maxsize) { + cmistake(u, u->thisorder, 15, MSG_MOVE); + return false; + } + if (!enoughsailors(u->ship, r)) { + cmistake(u, u->thisorder, 1, MSG_MOVE); +/* mistake(u, u->thisorder, + "Auf dem Schiff befinden sich zuwenig erfahrene Seeleute.", MSG_MOVE); */ + return false; + } + if (!cansail(r, u->ship)) { + cmistake(u, u->thisorder, 18, MSG_MOVE); + return false; + } + return true; +} + +unit * +owner_buildingtyp(const region * r, const building_type * bt) +{ + building *b; + unit *owner; + + for (b = rbuildings(r); b; b = b->next) { + owner = building_owner(b); + if (b->type == bt && owner != NULL) { + if (b->size >= bt->maxsize) { + return owner; + } + } + } + + return NULL; +} + +boolean +buildingtype_exists(const region * r, const building_type * bt, boolean working) +{ + building *b; + + for (b = rbuildings(r); b; b = b->next) { + if (b->type == bt) { + if (b->size >= bt->maxsize) { + return true; + } + } + } + + return false; +} + +/* Prüft, ob Ablegen von einer Küste in eine der erlaubten Richtungen erfolgt. */ + +static boolean +check_takeoff(ship *sh, region *from, region *to) +{ + if (!fval(from->terrain, SEA_REGION) && sh->coast != NODIRECTION) { + direction_t coast = sh->coast; + direction_t dir = reldirection(from, to); + direction_t coastr = (direction_t)((coast+1) % MAXDIRECTIONS); + direction_t coastl = (direction_t)((coast+MAXDIRECTIONS-1) % MAXDIRECTIONS); + + if (dir!=coast && dir!=coastl && dir!=coastr + && !buildingtype_exists(from, bt_find("harbour"), true)) + { + return false; + } + } + + return true; +} + +static void +sail(unit * u, order * ord, boolean move_on_land, region_list **routep) +{ + region *starting_point = u->region; + region *current_point, *last_point; + int k, step = 0; + region_list **iroute = routep; + ship * sh = u->ship; + faction * f = u->faction; + region * next_point = NULL; + int error; + const char * token = getstrtoken(); + + if (routep) *routep = NULL; + + error = movewhere(u, token, starting_point, &next_point); + if (error) { + message * msg = movement_error(u, token, ord, error); + if (msg!=NULL) { + add_message(&u->faction->msgs, msg); + msg_release(msg); + } + return; + } + + if (!ship_ready(starting_point, u)) return; + + /* Wir suchen so lange nach neuen Richtungen, wie es geht. Diese werden + * dann nacheinander ausgeführt. */ + + k = shipspeed(sh, u); + + last_point = starting_point; + current_point = starting_point; + + /* die nächste Region, in die man segelt, wird durch movewhere () aus der + * letzten Region bestimmt. + * + * Anfangen tun wir bei starting_point. next_point ist beim ersten + * Durchlauf schon gesetzt (Parameter!). current_point ist die letzte gültige, + * befahrene Region. */ + + while (next_point && current_point!=next_point && step < k) { + const char * token; + int error; + const terrain_type * tthis = current_point->terrain; + /* these values need to be updated if next_point changes (due to storms): */ + const terrain_type * tnext = next_point->terrain; + direction_t dir = reldirection(current_point, next_point); + + assert(sh == u->ship || !"ship has sunk, but we didn't notice it"); + + if (fval(next_point->terrain, FORBIDDEN_REGION)) { + ADDMSG(&f->msgs, msg_message("sailforbidden", + "ship region", sh, next_point)); + break; + } + + if (!flying_ship(sh)) { + int stormchance; + static int stormyness; + static int gamecookie = -1; + + if (gamecookie != global.cookie) { + gamedate date; + get_gamedate(turn, &date); + stormyness = storms[date.month] * 5; + gamecookie = global.cookie; + } + + /* storms should be the first thing we do. */ + stormchance = stormyness / shipspeed(sh, u); + if (check_leuchtturm(next_point, NULL)) stormchance /= 3; + + if (rng_int()%10000 < stormchance*sh->type->storm && fval(current_point->terrain, SEA_REGION)) { + if (!is_cursed(sh->attribs, C_SHIP_NODRIFT, 0)) { + region * rnext = NULL; + boolean storm = true; + int d_offset = rng_int() % MAXDIRECTIONS; + direction_t d; + /* Sturm nur, wenn nächste Region Hochsee ist. */ + for (d=0;d!=MAXDIRECTIONS;++d) { + direction_t dnext = (direction_t)((d + d_offset) % MAXDIRECTIONS); + region * rn = rconnect(current_point, dnext); + + if (rn!=NULL) { + if (fval(rn->terrain, FORBIDDEN_REGION)) continue; + if (!fval(rn->terrain, SEA_REGION)) { + storm = false; + break; + } + if (rn!=next_point) rnext = rn; + } + } + if (storm && rnext!=NULL) { + ADDMSG(&f->msgs, msg_message("storm", "ship region sink", + sh, current_point, sh->damage>=sh->size * DAMAGE_SCALE)); + + /* damage the ship. we handle destruction in the end */ + damage_ship(sh, damage_drift()); + if (sh->damage>=sh->size * DAMAGE_SCALE) break; + + next_point = rnext; + /* these values need to be updated if next_point changes (due to storms): */ + tnext = next_point->terrain; + dir = reldirection(current_point, next_point); + } + } + } + + if (!fval(tthis, SEA_REGION)) { + if (!fval(tnext, SEA_REGION)) { + if (!move_on_land) { + /* check that you're not traveling from one land region to another. */ + ADDMSG(&u->faction->msgs, msg_message("shipnoshore", + "ship region", sh, next_point)); + break; + } + } else { + if (check_takeoff(sh, current_point, next_point) == false) { + /* Schiff kann nicht ablegen */ + cmistake(u, ord, 182, MSG_MOVE); + break; + } + } + } else if (fval(tnext, SEA_REGION)) { + /* target region is an ocean, and we're not leaving a shore */ + if (!(sh->type->flags & SFL_OPENSEA)) { + /* ship can only stay close to shore */ + direction_t d; + + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rc = rconnect(next_point, d); + if (rc==NULL || !fval(rc->terrain, SEA_REGION)) break; + } + if (d == MAXDIRECTIONS) { + /* Schiff kann nicht aufs offene Meer */ + cmistake(u, ord, 249, MSG_MOVE); + break; + } + } + } + + if (!ship_allowed(sh, next_point)) { + /* for some reason or another, we aren't allowed in there.. */ + if (check_leuchtturm(current_point, NULL)) { + ADDMSG(&f->msgs, msg_message("sailnolandingstorm", "ship", sh)); + } else { + ADDMSG(&f->msgs, msg_message("sailnolanding", "ship region", sh, next_point)); + damage_ship(sh, 0.10); + /* we handle destruction at the end */ + } + break; + } + + + if (curse_active(get_curse(next_point->attribs, ct_find("maelstrom")))) { + if (do_maelstrom(next_point, u) == NULL) break; + } + + } /* !flying_ship */ + + /* Falls Blockade, endet die Seglerei hier */ + if (move_blocked(u, current_point, next_point)) { + ADDMSG(&u->faction->msgs, msg_message("sailfail", "ship region", sh, current_point)); + break; + } + + /* Falls kein Problem, eines weiter ziehen */ + fset(sh, SF_MOVED); + if (iroute) { + add_regionlist(iroute, next_point); + iroute = &(*iroute)->next; + } + step++; + + last_point = current_point; + current_point = next_point; + + if (!fval(current_point->terrain, SEA_REGION) && !is_cursed(sh->attribs, C_SHIP_FLYING, 0)) break; + token = getstrtoken(); + error = movewhere(u, token, current_point, &next_point); + if (error || next_point == NULL) { + message * msg = movement_error(u, token, ord, error); + if (msg!=NULL) { + add_message(&u->faction->msgs, msg); + msg_release(msg); + } + next_point = current_point; + break; + } + } + + if (sh->damage>=sh->size * DAMAGE_SCALE) { + if (sh->region) { + ADDMSG(&f->msgs, msg_message("shipsink", "ship", sh)); + remove_ship(&sh->region->ships, sh); + } + sh = NULL; + } + + /* Nun enthält current_point die Region, in der das Schiff seine Runde + * beendet hat. Wir generieren hier ein Ereignis für den Spieler, das + * ihm sagt, bis wohin er gesegelt ist, falls er überhaupt vom Fleck + * gekommen ist. Das ist nicht der Fall, wenn er von der Küste ins + * Inland zu segeln versuchte */ + + if (sh!=NULL && fval(sh, SF_MOVED)) { + unit * hafenmeister; + /* nachdem alle Richtungen abgearbeitet wurden, und alle Einheiten + * transferiert wurden, kann der aktuelle Befehl gelöscht werden. */ + cycle_route(ord, u, step); + set_order(&u->thisorder, NULL); + set_coast(sh, last_point, current_point); + + if( is_cursed(sh->attribs, C_SHIP_FLYING, 0) ) { + ADDMSG(&f->msgs, msg_message("shipfly", "ship from to", sh, starting_point, current_point)); + } else { + ADDMSG(&f->msgs, msg_message("shipsail", "ship from to", sh, starting_point, current_point)); + } + + /* Das Schiff und alle Einheiten darin werden nun von + * starting_point nach current_point verschoben */ + + /* Verfolgungen melden */ + if (fval(u, UFL_FOLLOWING)) caught_target(current_point, u); + + sh = move_ship(sh, starting_point, current_point, *routep); + + /* Hafengebühren ? */ + + hafenmeister = owner_buildingtyp(current_point, bt_find("harbour")); + if (sh && hafenmeister != NULL) { + item * itm; + unit * u2; + item * trans = NULL; + + for (u2 = current_point->units; u2; u2 = u2->next) { + if (u2->ship == sh && + !alliedunit(hafenmeister, u->faction, HELP_GUARD)) { + + + if (effskill(hafenmeister, SK_PERCEPTION) > effskill(u2, SK_STEALTH)) { + for (itm=u2->items; itm; itm=itm->next) { + const luxury_type * ltype = resource2luxury(itm->type->rtype); + if (ltype!=NULL && itm->number>0) { + int st = itm->number * effskill(hafenmeister, SK_TRADE) / 50; + st = MIN(itm->number, st); + + if (st > 0) { + i_change(&u2->items, itm->type, -st); + i_change(&hafenmeister->items, itm->type, st); + i_add(&trans, i_new(itm->type, st)); + } + } + } + } + } + } + if (trans) { + message * msg = msg_message("harbor_trade", "unit items ship", hafenmeister, trans, u->ship); + add_message(&u->faction->msgs, msg); + add_message(&hafenmeister->faction->msgs, msg); + msg_release(msg); + while (trans) i_remove(&trans, trans); + } + } + } +} + +unit * +get_captain(const ship * sh) +{ + const region * r = sh->region; + unit *u; + + for (u = r->units; u; u = u->next) { + if (u->ship == sh && eff_skill(u, SK_SAILING, r) >= sh->type->cptskill) + return u; + } + + return NULL; +} + +/* Segeln, Wandern, Reiten +* when this routine returns a non-zero value, movement for the region needs +* to be done again because of followers that got new MOVE orders. +* Setting FL_LONGACTION will prevent a unit from being handled more than once +* by this routine +* +* the token parser needs to be initialized before calling this function! +*/ + +/** fleeing units use this function +*/ +void +run_to(unit * u, region * to) +{ + region_list * route = NULL; + add_regionlist(&route, to); + travel_route(u, route, NULL, NULL, TRAVEL_RUNNING); + free_regionlist(route); + /* weder transport noch follow */ +} + +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; + + if (u->building && !can_leave(u)) { + cmistake(u, u->thisorder, 150, MSG_MOVE); + return route_begin; + } + switch (canwalk(u)) { + case E_CANWALK_TOOHEAVY: + cmistake(u, ord, 57, MSG_MOVE); + return route_begin; + case E_CANWALK_TOOMANYHORSES: + cmistake(u, ord, 56, MSG_MOVE); + return route_begin; + case E_CANWALK_TOOMANYCARTS: + cmistake(u, ord, 42, MSG_MOVE); + return route_begin; + } + route_end = cap_route(r, route_begin, route_end, movement_speed(u)); + + route_end = travel_route(u, route_begin, route_end, ord, mode); + get_followers(u, r, route_end, followers); + + /* transportation */ + for (ord = u->orders; ord; ord = ord->next) { + unit * ut; + + if (get_keyword(ord) != K_TRANSPORT) continue; + + init_tokens(ord); + skip_token(); + ut = getunit(r, u->faction); + if (ut!=NULL) { + if (get_keyword(ut->thisorder) == K_DRIVE) { + if (ut->building && !can_leave(ut)) { + cmistake(ut, ut->thisorder, 150, MSG_MOVE); + cmistake(u, ord, 99, MSG_MOVE); + } else if (!can_move(ut)) { + cmistake(u, ord, 99, MSG_MOVE); + } else { + boolean found = false; + + if (!fval(ut, UFL_NOTMOVING) && !LongHunger(ut)) { + init_tokens(ut->thisorder); + skip_token(); + if (getunit(u->region, ut->faction) == u) { + const region_list * route_to = travel_route(ut, route_begin, route_end, ord, TRAVEL_TRANSPORTED); + + if (route_to!=route_begin) { + get_followers(ut, r, route_to, followers); + } + ADDMSG(&ut->faction->msgs, msg_message("transport", + "unit target start end", u, ut, r, ut->region)); + found = true; + } + } + if (!found) { + if (cansee(u->faction, u->region, ut, 0)) { + cmistake(u, ord, 90, MSG_MOVE); + } else { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } + } + } + } + } else { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } + } + return route_end; +} + +/** traveling without ships + * walking, flying or riding units use this function + */ +static void +travel(unit * u, region_list ** routep) +{ + region * r = u->region; + region_list * route_begin = NULL; + follower * followers = NULL; + + if (routep) *routep = NULL; + + /* a few pre-checks that need not be done for each step: */ + if (!fval(r->terrain, SEA_REGION)) { + ship * sh = u->ship; + + if (!can_leave(u)) { + cmistake(u, u->thisorder, 150, MSG_MOVE); + return; + } + + /* An Land kein NACH wenn in dieser Runde Schiff VERLASSEN! */ + if (sh == NULL) { + sh = leftship(u); + if (sh && sh->region!=u->region) sh = NULL; + } + if (sh) { + unit * guard = is_guarded(r, u, GUARD_LANDING); + if (guard) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "region_guarded", "guard", guard)); + return; + } + } + if (u->ship && u->race->flags & RCF_SWIM) { + cmistake(u, u->thisorder, 143, MSG_MOVE); + return; + } + } + else if (u->ship && fval(u->ship, SF_MOVED)) { + /* die Einheit ist auf einem Schiff, das sich bereits bewegt hat */ + cmistake(u, u->thisorder, 13, MSG_MOVE); + return; + } + + make_route(u, u->thisorder, routep); + route_begin = *routep; + + /* und ab die post: */ + travel_i(u, route_begin, NULL, u->thisorder, TRAVEL_NORMAL, &followers); + + /* followers */ + while (followers!=NULL) { + follower * fnext = followers->next; + unit * uf = followers->uf; + unit * ut = followers->ut; + const region_list * route_end = followers->route_end; + + free(followers); + followers = fnext; + + if (uf->region == r) { + order * follow_order; + const struct locale * lang = u->faction->locale; + + /* construct an order */ + follow_order = create_order(K_FOLLOW, lang, "%s %i", + LOC(uf->faction->locale, parameters[P_UNIT]), ut->no); + + route_end = reroute(uf, route_begin, route_end); + travel_i(uf, route_begin, route_end, follow_order, TRAVEL_FOLLOWING, &followers); + caught_target(uf->region, uf); + free_order(follow_order); + } + } + +} + +static void +move(unit * u, boolean move_on_land) +{ + region_list * route = NULL; + + assert(u->number); + if (u->ship && fval(u, UFL_OWNER)) { + sail(u, u->thisorder, move_on_land, &route); + } else { + travel(u, &route); + } + + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + set_order(&u->thisorder, NULL); + + if (route!=NULL) free_regionlist(route); +} + +typedef struct piracy_data { + const struct faction * pirate; + const struct faction * target; + direction_t dir; +} piracy_data; + +static void +piracy_init(struct attrib * a) +{ + a->data.v = calloc(1, sizeof(piracy_data)); +} + +static void +piracy_done(struct attrib * a) +{ + free(a->data.v); +} + +static attrib_type at_piracy_direction = { + "piracy_direction", + piracy_init, + piracy_done, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +static attrib * +mk_piracy(const faction * pirate, const faction * target, direction_t target_dir) +{ + attrib * a = a_new(&at_piracy_direction); + piracy_data * data = a->data.v; + data->pirate = pirate; + data->target = target; + data->dir = target_dir; + return a; +} + +static void +piracy_cmd(unit *u, struct order * ord) +{ + region *r = u->region; + ship *sh = u->ship, *sh2; + direction_t dir, target_dir = NODIRECTION; + struct { + const faction * target; + int value; + } aff[MAXDIRECTIONS]; + int saff = 0; + int *il = NULL; + const char *s; + attrib *a; + + if (!sh) { + cmistake(u, ord, 144, MSG_MOVE); + return; + } + + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 146, MSG_MOVE); + return; + } + + /* Feststellen, ob schon ein anderer alliierter Pirat ein + * Ziel gefunden hat. */ + + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + if (s!=NULL && *s) { + il = intlist_init(); + while (s && *s) { + il = intlist_add(il, atoi36(s)); + s = getstrtoken(); + } + } + + for (a = a_find(r->attribs, &at_piracy_direction); a && a->type==&at_piracy_direction; a=a->next) { + piracy_data * data = a->data.v; + const faction * p = data->pirate; + const faction * t = data->target; + + if (alliedunit(u, p, HELP_FIGHT)) { + if (il == 0 || (t && intlist_find(il, t->no))) { + target_dir = data->dir; + break; + } + } + } + + /* Wenn nicht, sehen wir, ob wir ein Ziel finden. */ + + if (target_dir == NODIRECTION) { + /* Einheit ist also Kapitän. Jetzt gucken, in wievielen + * Nachbarregionen potentielle Opfer sind. */ + + for(dir = 0; dir < MAXDIRECTIONS; dir++) { + region *rc = rconnect(r, dir); + aff[dir].value = 0; + aff[dir].target = 0; + if (rc && fval(rc->terrain, SWIM_INTO) + && check_takeoff(sh, r, rc) == true) { + + for (sh2 = rc->ships; sh2; sh2 = sh2->next) { + unit * cap = shipowner(sh2); + if (cap) { + faction * f = visible_faction(cap->faction, cap); + if (alliedunit(u, f, HELP_FIGHT)) continue; + if (il == 0 || intlist_find(il, cap->faction->no)) { + ++aff[dir].value; + if (rng_int() % aff[dir].value == 0) { + aff[dir].target = f; + } + } + } + } + + /* Und aufaddieren. */ + saff += aff[dir].value; + } + } + + if (saff != 0) { + saff = rng_int() % saff; + for (dir=0; dir!=MAXDIRECTIONS; ++dir) { + if (saff!=aff[dir].value) break; + saff -= aff[dir].value; + } + target_dir = dir; + a = a_add(&r->attribs, mk_piracy(u->faction, aff[dir].target, target_dir)); + } + } + + free(il); + + /* Wenn kein Ziel gefunden, entsprechende Meldung generieren */ + if (target_dir == NODIRECTION) { + ADDMSG(&u->faction->msgs, msg_message("piratenovictim", + "ship region", sh, r)); + return; + } + + /* Meldung generieren */ + ADDMSG(&u->faction->msgs, msg_message("piratesawvictim", + "ship region dir", sh, r, target_dir)); + + /* Befehl konstruieren */ + set_order(&u->thisorder, create_order(K_MOVE, u->faction->locale, "%s", + LOC(u->faction->locale, directions[target_dir]))); + + /* Bewegung ausführen */ + init_tokens(u->thisorder); + skip_token(); + move(u, true); +} + +static void +age_traveldir(region *r) +{ + attrib *a = a_find(r->attribs, &at_traveldir); + + while(a && a->type==&at_traveldir) { + attrib *an = a->next; + a->data.ca[3]--; + if(a->data.ca[3] <= 0) { + a_remove(&r->attribs, a); + } + a = an; + } +} + +static direction_t +hunted_dir(attrib *at, int id) +{ + attrib *a = a_find(at, &at_shiptrail); + direction_t d = NODIRECTION; + + while (a!=NULL && a->type==&at_shiptrail) { + traveldir *t = (traveldir *)(a->data.v); + if (t->no == id) { + d = t->dir; + /* do not break, because we want the last one for this ship */ + } + a = a->next; + } + + return d; +} + +static int +hunt(unit *u, order * ord) +{ + region *rc = u->region; + int bytes, moves, id, speed; + char command[256], * bufp = command; + size_t size = sizeof(command); + direction_t dir; + + if (fval(u, UFL_NOTMOVING)) { + return 0; + } else if (u->ship == NULL) { + cmistake(u, ord, 144, MSG_MOVE); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ + return 0; + } else if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 146, MSG_MOVE); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ + return 0; + } else if (!can_move(u)) { + cmistake(u, ord, 55, MSG_MOVE); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ + return 0; + } + + id = getshipid(); + + if (id <= 0) { + cmistake(u, ord, 20, MSG_MOVE); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ + return 0; + } + + dir = hunted_dir(rc->attribs, id); + + if (dir == NODIRECTION) { + ship * sh = findship(id); + if (sh == NULL || sh->region!=rc) { + cmistake(u, ord, 20, MSG_MOVE); + } + fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ + return 0; + } + + bufp = command; + bytes = snprintf(bufp, size, "%s %s", LOC(u->faction->locale, keywords[K_MOVE]), + LOC(u->faction->locale, directions[dir])); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + moves = 1; + + speed = getuint(); + if (speed==0) { + speed = shipspeed(u->ship, u); + } else { + int maxspeed = shipspeed(u->ship, u); + if (maxspeedattribs, id)) != NODIRECTION) + { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(u->faction->locale, directions[dir]), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + moves++; + rc = rconnect(rc, dir); + } + + /* In command steht jetzt das NACH-Kommando. */ + + /* NACH ignorieren und Parsing initialisieren. */ + igetstrtoken(command); + /* NACH ausführen */ + move(u, false); + return 1; /* true -> Einheitenliste von vorne durchgehen */ +} + +void +destroy_damaged_ships(void) +{ + region *r; + ship *sh,*shn; + + for(r=regions;r;r=r->next) { + for(sh=r->ships;sh;) { + shn = sh->next; + if (sh->damage>=sh->size * DAMAGE_SCALE) { + remove_ship(&sh->region->ships, sh); + } + sh = shn; + } + } +} + +/* Bewegung, Verfolgung, Piraterie */ + +/** ships that folow other ships + * Dann generieren die jagenden Einheiten ihre Befehle und + * bewegen sich. + * Following the trails of other ships. + */ +static void +move_hunters(void) +{ + region *r; + + for (r = regions; r; r = r->next) { + unit ** up = &r->units; + + while (*up!=NULL) { + unit * u = *up; + + if (!fval(u, UFL_MOVED|UFL_NOTMOVING)) { + order * ord; + + for (ord=u->orders;ord;ord=ord->next) { + if (get_keyword(ord) == K_FOLLOW) { + param_t p; + + init_tokens(ord); + skip_token(); + p = getparam(u->faction->locale); + if (p != P_SHIP) { + if (p != P_UNIT) { + cmistake(u, ord, 240, MSG_MOVE); + } + break; + } + + /* wir folgen definitiv einem Schiff. */ + + if (fval(u, UFL_NOTMOVING)) { + cmistake(u, ord, 52, MSG_MOVE); + break; + } else if (!can_move(u)) { + cmistake(u, ord, 55, MSG_MOVE); + break; + } + + if (!fval(u, UFL_NOTMOVING) && !LongHunger(u) && hunt(u, ord)) { + up = &r->units; + break; + } + } + } + } + if (*up == u) up=&u->next; + } + } +} + +/** Piraten and Drift + * + */ +static void +move_pirates(void) +{ + region * r; + + for (r = regions; r; r = r->next) { + unit ** up = &r->units; + + while (*up) { + unit *u = *up; + + if (!fval(u, UFL_NOTMOVING) && get_keyword(u->thisorder) == K_PIRACY) { + piracy_cmd(u, u->thisorder); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + } + + if (*up == u) { + /* not moved, use next unit */ + up = &u->next; + } else if (*up && (*up)->region!=r) { + /* moved the previous unit along with u (units on same ship) + * must start from the beginning again */ + up = &r->units; + } + /* else *up is already the next unit */ + } + + a_removeall(&r->attribs, &at_piracy_direction); + age_traveldir(r); + } +} + +void +movement(void) +{ + int ships; + + /* Initialize the additional encumbrance by transported units */ + init_transportation(); + + /* Move ships in last phase, others first + * This is to make sure you can't land someplace and then get off the ship + * in the same turn. + */ + for (ships=0;ships<=1;++ships) { + region * r = regions; + while (r!=NULL) { + unit ** up = &r->units; + boolean repeat = false; + + while (*up) { + unit *u = *up; + keyword_t kword; + + if (u->ship && fval(u->ship, SF_DRIFTED)) { + up = &u->next; + continue; + } + kword = get_keyword(u->thisorder); + + switch (kword) { + case K_ROUTE: + case K_MOVE: + /* after moving, the unit has no thisorder. this prevents + * it from moving twice (or getting error messages twice). + * UFL_NOTMOVING is set in combat if the unit is not allowed + * to move because it was involved in a battle. + */ + if (fval(u, UFL_NOTMOVING)) { + if (fval(u, UFL_LONGACTION)) { + cmistake(u, u->thisorder, 52, MSG_MOVE); + set_order(&u->thisorder, NULL); + } else { + cmistake(u, u->thisorder, 319, MSG_MOVE); + set_order(&u->thisorder, NULL); + } + } else if (fval(u, UFL_MOVED)) { + cmistake(u, u->thisorder, 187, MSG_MOVE); + set_order(&u->thisorder, NULL); + } else if (!can_move(u)) { + cmistake(u, u->thisorder, 55, MSG_MOVE); + set_order(&u->thisorder, NULL); + } else { + if (ships) { + if (u->ship && fval(u, UFL_OWNER)) { + init_tokens(u->thisorder); + skip_token(); + move(u, false); + } + } else { + if (u->ship == NULL || !fval(u, UFL_OWNER)) { + init_tokens(u->thisorder); + skip_token(); + move(u, false); + } + } + } + break; + } + if (u->region == r) { + /* not moved, use next unit */ + up = &u->next; + } else { + if (*up && (*up)->region!=r) { + /* moved the upcoming unit along with u (units on ships or followers, + * for example). must start from the beginning again immediately */ + up = &r->units; + repeat = false; + } else { + repeat = true; + } + } + /* else *up is already the next unit */ + } + if (repeat) continue; + if (ships == 0) { + /* Abtreiben von beschädigten, unterbemannten, überladenen Schiffen */ + drifting_ships(r); + } + r = r->next; + } + } + + move_hunters(); + move_pirates(); +} + +/** Overrides long orders with a FOLLOW order if the target is moving. + * FOLLOW SHIP is a long order, and doesn't need to be treated in here. + * BUGS: http://bugs.eressea.de/view.php?id=1444 (A folgt B folgt C) + */ +void +follow_unit(unit * u) +{ + region * r = u->region; + attrib * a = NULL; + order * ord; + + if (fval(u, UFL_NOTMOVING) || LongHunger(u)) return; + + for (ord=u->orders;ord;ord=ord->next) { + const struct locale * lang = u->faction->locale; + + if (get_keyword(ord) == K_FOLLOW) { + init_tokens(ord); + skip_token(); + if (getparam(lang) == P_UNIT) { + int id = read_unitid(u->faction, r); + + if (a!=NULL) { + a = a_find(u->attribs, &at_follow); + } + + if (id>0) { + unit * uf = findunit(id); + if (!a) { + a = a_add(&u->attribs, make_follow(uf)); + } else { + a->data.v = uf; + } + } else if (a) { + a_remove(&u->attribs, a); + a = NULL; + } + } + } + } + + if (a && !fval(u, UFL_MOVED|UFL_NOTMOVING)) { + unit * u2 = a->data.v; + boolean follow = false; + + if (!u2 || u2->region!=r || !cansee(u->faction, r, u2, 0)) { + return; + } + + switch (get_keyword(u2->thisorder)) { + case K_MOVE: + case K_ROUTE: + case K_DRIVE: + follow = true; + break; + default: + for (ord=u2->orders;ord;ord=ord->next) { + switch (get_keyword(ord)) { + case K_FOLLOW: + case K_PIRACY: + follow = true; + break; + default: + continue; + } + break; + } + break; + } + if (!follow) { + attrib * a2 = a_find(u2->attribs, &at_follow); + if (a2!=NULL) { + unit * u3 = a2->data.v; + follow = (u3 && u2->region == u2->region); + } + } + if (follow) { + fset(u, UFL_FOLLOWING); + fset(u2, UFL_FOLLOWED); + set_order(&u->thisorder, NULL); + } + } +} diff --git a/src/kernel/move.h b/src/kernel/move.h new file mode 100644 index 000000000..2b5b7bdd1 --- /dev/null +++ b/src/kernel/move.h @@ -0,0 +1,71 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_MOVEMENT +#define H_KRNL_MOVEMENT +#ifdef __cplusplus +extern "C" { +#endif + +struct unit; +struct ship; +struct building_type; + +/* die Zahlen sind genau äquivalent zu den race Flags */ +#define MV_CANNOTMOVE (1<<5) +#define MV_FLY (1<<7) /* kann fliegen */ +#define MV_SWIM (1<<8) /* kann schwimmen */ +#define MV_WALK (1<<9) /* kann über Land gehen */ + +/* Die tragekapaz. ist hardcodiert mit defines, da es bis jetzt sowieso nur 2 +** objekte gibt, die etwas tragen. */ +#define SILVERWEIGHT 1 +#define SCALEWEIGHT 100 /* Faktor, um den die Anzeige von gewichten + * * skaliert wird */ +#define HORSECAPACITY 7000 +#define WAGONCAPACITY 14000 + +#define HORSESNEEDED 2 + +/* ein mensch wiegt 10, traegt also 5, ein pferd wiegt 50, traegt also 20. ein +** wagen wird von zwei pferden gezogen und traegt total 140, davon 40 die +** pferde, macht nur noch 100, aber samt eigenem gewicht (40) macht also 140. */ + +int personcapacity(const struct unit *u); +direction_t getdirection(const struct locale *); +void movement(void); +void run_to(struct unit * u, struct region * to); +struct unit *is_guarded(struct region * r, struct unit * u, unsigned int mask); +boolean is_guard(const struct unit * u, int mask); +int enoughsailors(const struct ship * sh, const struct region * r); +boolean canswim(struct unit *u); +boolean canfly(struct unit *u); +struct unit *get_captain(const struct ship * sh); +void travelthru(const struct unit * u, struct region * r); +struct ship * move_ship(struct ship * sh, struct region * from, struct region * to, struct region_list * route); +int walkingcapacity(const struct unit * u); +void follow_unit(struct unit * u); +boolean buildingtype_exists(const struct region * r, const struct building_type * bt, boolean working); +struct unit* owner_buildingtyp(const struct region * r, const struct building_type * bt); + +extern struct attrib_type at_speedup; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/names.c b/src/kernel/names.c new file mode 100644 index 000000000..9d617cc0b --- /dev/null +++ b/src/kernel/names.c @@ -0,0 +1,483 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "names.h" + +/* kernel includes */ +#include "unit.h" +#include "region.h" +#include "faction.h" +#include "magic.h" +#include "race.h" +#include "terrain.h" +#include "terrainid.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +const char * +describe_braineater(unit * u, const struct locale * lang) +{ + return LOC(lang, "describe_braineater"); +} + +static const char * +make_names(const char * monster, int * num_postfix, int pprefix, int * num_name, int * num_prefix, int ppostfix) +{ + int uv, uu, un; + static char name[NAMESIZE + 1]; + char zText[32]; + const char * str; + + if (*num_prefix==0) { + + for (*num_prefix=0;;++*num_prefix) { + sprintf(zText, "%s_prefix_%d", monster, *num_prefix); + str = locale_getstring(default_locale, zText); + if (str==NULL) break; + } + + for (*num_name=0;;++*num_name) { + sprintf(zText, "%s_name_%d", monster, *num_name); + str = locale_getstring(default_locale, zText); + if (str==NULL) break; + } + + for (*num_postfix=0;;++*num_postfix) { + sprintf(zText, "%s_postfix_%d", monster, *num_postfix); + str = locale_getstring(default_locale, zText); + if (str==NULL) break; + } + } + + if (*num_name==0) { + return NULL; + } + + /* nur 50% aller Namen haben "Vor-Teil" */ + uv = rng_int() % (*num_prefix * pprefix); + + uu = rng_int() % *num_name; + + /* nur 50% aller Namen haben "Nach-Teil", wenn kein Vor-Teil */ + if (uv>=*num_prefix) { + un = rng_int() % *num_postfix; + } else { + un = rng_int() % (*num_postfix * ppostfix); + } + + name[0] = 0; + if (uv < *num_prefix) { + sprintf(zText, "%s_prefix_%d", monster, uv); + str = locale_getstring(default_locale, zText); + if (str) { + strcat(name, (const char *)str); + strcat(name, " "); + } + } + + sprintf(zText, "%s_name_%d", monster, uu); + str = locale_getstring(default_locale, zText); + if (str) strcat(name, (const char *)str); + + if (un < *num_postfix) { + sprintf(zText, "%s_postfix_%d", monster, un); + str = locale_getstring(default_locale, zText); + if (str) { + strcat(name, " "); + strcat(name, (const char *)str); + } + } + return name; +} + +const char * +undead_name(const unit * u) +{ + static int num_postfix, num_name, num_prefix; + return make_names("undead", &num_postfix, 2, &num_name, &num_prefix, 2); +} + +const char * +skeleton_name(const unit * u) +{ + static int num_postfix, num_name, num_prefix; + return make_names("skeleton", &num_postfix, 5, &num_name, &num_prefix, 2); +} + +const char * +zombie_name(const unit * u) +{ + static int num_postfix, num_name, num_prefix; + return make_names("zombie", &num_postfix, 5, &num_name, &num_prefix, 2); +} + +const char * +ghoul_name(const unit * u) +{ + static int num_postfix, num_name, num_prefix; + return make_names("ghoul", &num_postfix, 5, &num_name, &num_prefix, 4); +} + + +/* Drachen */ + +#define SIL1 15 + +const char *silbe1[SIL1] = { + "Tar", + "Ter", + "Tor", + "Pan", + "Par", + "Per", + "Nim", + "Nan", + "Nun", + "Gor", + "For", + "Fer", + "Kar", + "Kur", + "Pen", +}; + +#define SIL2 19 + +const char *silbe2[SIL2] = { + "da", + "do", + "dil", + "di", + "dor", + "dar", + "ra", + "ran", + "ras", + "ro", + "rum", + "rin", + "ten", + "tan", + "ta", + "tor", + "gur", + "ga", + "gas", +}; + +#define SIL3 14 + +const char *silbe3[SIL3] = { + "gul", + "gol", + "dol", + "tan", + "tar", + "tur", + "sur", + "sin", + "kur", + "kor", + "kar", + "dul", + "dol", + "bus", +}; + +const char * +generic_name(const unit *u) +{ + if (u->no == 1) { + return LOC(u->faction->locale, mkname("race", u->race->_name[0])); + } + return LOC(u->faction->locale, mkname("race", u->race->_name[1])); +} + +const char * +dragon_name(const unit *u) +{ + static char name[NAMESIZE + 1]; + int rnd, ter = 0; + int anzahl = 1; + static int num_postfix; + char zText[32]; + const char * str; + + if (num_postfix==0) { + for (num_postfix=0;;++num_postfix) { + sprintf(zText, "dragon_postfix_%d", num_postfix); + str = locale_getstring(default_locale, zText); + if (str==NULL) break; + } + if (num_postfix==0) num_postfix = -1; + } + if (num_postfix<=0) { + return NULL; + } + + if (u) { + region *r = u->region; + anzahl = u->number; + switch (rterrain(r)) { + case T_PLAIN: + ter = 1; + break; + case T_MOUNTAIN: + ter = 2; + break; + case T_DESERT: + ter = 3; + break; + case T_SWAMP: + ter = 4; + break; + case T_GLACIER: + ter = 5; + break; + } + } + + rnd = num_postfix / 6; + rnd = (rng_int() % rnd) + ter * rnd; + + sprintf(zText, "dragon_postfix_%d", rnd); + + str = locale_getstring(default_locale, zText); + assert(str!=NULL); + + if (anzahl > 1) { + const char * no_article = strchr((const char *)str, ' '); + assert(no_article); + /* TODO: GERMAN */ + sprintf(name, "Die %sn von %s", no_article, rname(u->region, default_locale)); + } else { + char n[32]; + + strcpy(n, silbe1[rng_int() % SIL1]); + strcat(n, silbe2[rng_int() % SIL2]); + strcat(n, silbe3[rng_int() % SIL3]); + if (rng_int() % 5 > 2) { + sprintf(name, "%s, %s", n, str); /* "Name, der Titel" */ + } else { + strcpy(name, (const char *)str); /* "Der Titel Name" */ + name[0] = (char)toupper(name[0]); /* TODO: UNICODE - should use towupper() */ + strcat(name, " "); + strcat(name, n); + } + if (u && (rng_int() % 3 == 0)) { + strcat(name, " von "); + strcat(name, (const char *)rname(u->region, default_locale)); + } + } + + return name; +} + +/* Dracoide */ + +#define DRAC_PRE 13 +static const char *drac_pre[DRAC_PRE] = { + "Siss", + "Xxaa", + "Shht", + "X'xixi", + "Xar", + "X'zish", + "X", + "Sh", + "R", + "Z", + "Y", + "L", + "Ck", +}; + +#define DRAC_MID 12 +static const char *drac_mid[DRAC_MID] = { + "siss", + "xxaa", + "shht", + "xxi", + "xar", + "x'zish", + "x", + "sh", + "r", + "z'ck", + "y", + "rl" +}; + +#define DRAC_SUF 10 +static const char *drac_suf[DRAC_SUF] = { + "xil", + "shh", + "s", + "x", + "arr", + "lll", + "lll", + "shack", + "ck", + "k" +}; + +const char * +dracoid_name(const unit *u) +{ + static char name[NAMESIZE + 1]; + int mid_syllabels; + + u=u; + /* Wieviele Mittelteile? */ + + mid_syllabels = rng_int()%4; + + strcpy(name, drac_pre[rng_int()%DRAC_PRE]); + while(mid_syllabels > 0) { + mid_syllabels--; + if(rng_int()%10 < 4) strcat(name,"'"); + strcat(name, drac_mid[rng_int()%DRAC_MID]); + } + strcat(name, drac_suf[rng_int()%DRAC_SUF]); + return name; +} + +/** returns an abbreviation of a string. + * TODO: buflen is being ignored */ + +const char * +abkz(const char *s, char * buf, size_t buflen, size_t maxchars) +{ + const char *p = s; + char * bufp; + unsigned int c = 0; + size_t bpt, i; + ucs4_t ucs; + size_t size; + int result; + + /* Prüfen, ob Kurz genug */ + + if (strlen(s) <= maxchars) { + return s; + } + /* Anzahl der Wörter feststellen */ + + while (*p != 0) { + + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result==0 || "damnit, we're not handling invalid input here!"); + + /* Leerzeichen überspringen */ + while (*p != 0 && !iswalnum((wint_t)ucs)) { + p += size; + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result==0 || "damnit, we're not handling invalid input here!"); + } + + /* Counter erhöhen */ + if (*p != 0) ++c; + + /* alnums überspringen */ + while (*p != 0 && iswalnum((wint_t)ucs)) { + p+=size; + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result==0 || "damnit, we're not handling invalid input here!"); + } + } + + /* Buchstaben pro Teilkürzel = MAX(1,max/AnzWort) */ + + bpt = MAX(1, maxchars / c); + + /* Einzelne Wörter anspringen und jeweils die ersten BpT kopieren */ + + p = s; + c = 0; + bufp = buf; + + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result==0 || "damnit, we're not handling invalid input here!"); + + while (*p != 0 && c < maxchars) { + /* Leerzeichen überspringen */ + + while (*p != 0 && !iswalnum((wint_t)ucs)) { + p+=size; + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result==0 || "damnit, we're not handling invalid input here!"); + } + + /* alnums übertragen */ + + for (i = 0; i < bpt && *p != 0 && iswalnum((wint_t)ucs); ++i) { + memcpy(bufp, p, size); + p += size; + bufp += size; + ++c; + + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result==0 || "damnit, we're not handling invalid input here!"); + } + + /* Bis zum nächsten Leerzeichen */ + + while (c < maxchars && *p != 0 && iswalnum((wint_t)ucs)) { + p+=size; + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result==0 || "damnit, we're not handling invalid input here!"); + } + } + + *bufp = 0; + + return buf; +} + +void +register_names(void) +{ + register_function((pf_generic)describe_braineater, "describe_braineater"); + /* function name + * generate a name for a nonplayerunit + * race->generate_name() */ + register_function((pf_generic)undead_name, "nameundead"); + register_function((pf_generic)skeleton_name, "nameskeleton"); + register_function((pf_generic)zombie_name, "namezombie"); + register_function((pf_generic)ghoul_name, "nameghoul"); + register_function((pf_generic)dragon_name, "namedragon"); + register_function((pf_generic)dracoid_name, "namedracoid"); + register_function((pf_generic)generic_name, "namegeneric"); +} + + diff --git a/src/kernel/names.h b/src/kernel/names.h new file mode 100644 index 000000000..d689197d2 --- /dev/null +++ b/src/kernel/names.h @@ -0,0 +1,37 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_NAMES +#define H_KRNL_NAMES +#ifdef __cplusplus +extern "C" { +#endif +extern void register_names(void); +const char *undead_name(const struct unit * u); +const char *skeleton_name(const struct unit * u); +const char *zombie_name(const struct unit * u); +const char *ghoul_name(const struct unit * u); +const char *dragon_name(const struct unit *u); +const char *dracoid_name(const struct unit *u); +const char *generic_name(const struct unit *u); +const char *abkz(const char *s, char * buf, size_t size, size_t maxchars); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/objtypes.h b/src/kernel/objtypes.h new file mode 100644 index 000000000..789ef0c5d --- /dev/null +++ b/src/kernel/objtypes.h @@ -0,0 +1,40 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_OBJTYPES +#define H_KRNL_OBJTYPES +#ifdef __cplusplus +extern "C" { +#endif + +enum { + TYP_UNIT, + TYP_REGION, + TYP_BUILDING, + TYP_SHIP, + TYP_FACTION, + TYP_ACTION, + TYP_TRIGGER, + TYP_TIMEOUT +}; + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/kernel/order.c b/src/kernel/order.c new file mode 100644 index 000000000..690cd0181 --- /dev/null +++ b/src/kernel/order.c @@ -0,0 +1,517 @@ +/* vi: set ts=2: + +-------------------+ + | | Christian Schlittchen + | Eressea PBEM host | Enno Rehling + | (c) 1998 - 2004 | Katja Zedel + | | + +-------------------+ + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "order.h" + +#include "skill.h" + +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +# define ORD_KEYWORD(ord) (ord)->data->_keyword +# 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 * study_orders[MAXSKILLS]; + const struct locale * lang; +} locale_data; + +static struct locale_data * locale_array[16]; +static int nlocales = 0; + +typedef struct order_data { + char * _str; + int _refcount : 20; + int _lindex : 4; + keyword_t _keyword; +} order_data; + +static void +release_data(order_data * data) +{ + if (data) { + if (--data->_refcount == 0) { + if (data->_str) free(data->_str); + free(data); + } + } +} + +void +replace_order(order ** dlist, order * orig, const order * src) +{ + while (*dlist!=NULL) { + order * dst = *dlist; + if (dst->data==orig->data) { + order * cpy = copy_order(src); + *dlist = cpy; + cpy->next = dst->next; + dst->next = 0; + free_order(dst); + } + dlist = &(*dlist)->next; + } +} + +keyword_t +get_keyword(const order * ord) +{ + if (ord==NULL) { + return NOKEYWORD; + } + return ORD_KEYWORD(ord); +} + +/** returns a plain-text representation of the order. + * This is the inverse function to the parse_order command. Note that + * keywords are expanded to their full length. + */ +static char * +get_command(const order * ord, char * sbuffer, size_t size) +{ + char * bufp = sbuffer; + const char * text = ORD_STRING(ord); + keyword_t kwd = ORD_KEYWORD(ord); + int bytes; + + if (ord->_persistent) { + if (size>0) { + *bufp++ = '@'; + --size; + } else { + WARN_STATIC_BUFFER(); + } + } + if (kwd!=NOKEYWORD) { + const struct locale * lang = ORD_LOCALE(ord); + if (size>0) { + if (text) --size; + bytes = (int)strlcpy(bufp, (const char*)LOC(lang, keywords[kwd]), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (text) *bufp++ = ' '; + } else WARN_STATIC_BUFFER(); + } + if (text) { + bytes = (int)strlcpy(bufp, (const char *)text, size); + if (wrptr(&bufp, &size, bytes)!=0) { + WARN_STATIC_BUFFER(); + if (bufp-sbuffer>=6) { + bufp -= 6; + while (bufp>sbuffer&& (*bufp&0x80)!=0) { + ++size; + --bufp; + } + memcpy(bufp+1, "[...]", 6); /* TODO: make sure this only happens in eval_command */ + bufp += 6; + } + } + } + if (size>0) *bufp = 0; + return sbuffer; +} + +char * +getcommand(const order * ord) +{ + char sbuffer[DISPLAYSIZE*2]; + return strdup(get_command(ord, sbuffer, sizeof(sbuffer))); +} + +void +free_order(order * ord) +{ + if (ord!=NULL) { + assert(ord->next==0); + + release_data(ord->data); + free(ord); + } +} + +order * +copy_order(const order * src) +{ + if (src!=NULL) { + order * ord = (order*)malloc(sizeof(order)); + ord->next = NULL; + ord->_persistent = src->_persistent; + ord->data = src->data; + ++ord->data->_refcount; + return ord; + } + return NULL; +} + +void +set_order(struct order ** destp, struct order * src) +{ + if (*destp==src) return; + free_order(*destp); + *destp = src; +} + +void +free_orders(order ** olist) +{ + while (*olist) { + order * ord = *olist; + *olist = ord->next; + ord->next = NULL; + free_order(ord); + } +} + +static order_data * +create_data(keyword_t kwd, const char * sptr, int lindex) +{ + const char * s = sptr; + order_data * data; + const struct locale * lang = locale_array[lindex]->lang; + + if (kwd!=NOKEYWORD) s = (*sptr)?sptr:NULL; + + /* learning, only one order_data per skill required */ + if (kwd==K_STUDY) { + skill_t sk = findskill(parse_token(&sptr), lang); + switch (sk) { + case NOSKILL: /* fehler */ + break; + case SK_MAGIC: /* kann parameter haben */ + if (*sptr != 0) break; + default: /* nur skill als Parameter, keine extras */ + data = locale_array[lindex]->study_orders[sk]; + if (data==NULL) { + const char * skname = skillname(sk, lang); + data = (order_data*)malloc(sizeof(order_data)); + locale_array[lindex]->study_orders[sk] = data; + data->_keyword = kwd; + data->_lindex = lindex; + if (strchr(skname, ' ')!=NULL) { + size_t len = strlen(skname); + data->_str = malloc(len+3); + data->_str[0]='\"'; + memcpy(data->_str+1, skname, len); + data->_str[len+1]='\"'; + data->_str[len+2]='\0'; + } else { + data->_str = strdup(skname); + } + data->_refcount = 1; + } + ++data->_refcount; + return data; + } + } + + /* orders with no parameter, only one order_data per order required */ + else if (kwd!=NOKEYWORD && *sptr == 0) { + data = locale_array[lindex]->short_orders[kwd]; + if (data == NULL) { + data = (order_data*)malloc(sizeof(order_data)); + locale_array[lindex]->short_orders[kwd] = data; + data->_keyword = kwd; + data->_lindex = lindex; + data->_str = NULL; + data->_refcount = 1; + } + ++data->_refcount; + return data; + } + data = (order_data*)malloc(sizeof(order_data)); + data->_keyword = kwd; + data->_lindex = lindex; + data->_str = s?strdup(s):NULL; + data->_refcount = 1; + return data; +} + +static order * +create_order_i(keyword_t kwd, const char * sptr, int persistent, const struct locale * lang) +{ + order * ord = NULL; + int lindex; + + /* if this is just nonsense, then we skip it. */ + if (lomem) { + switch (kwd) { + case K_KOMMENTAR: + case NOKEYWORD: + return NULL; + case K_LIEFERE: + kwd = K_GIVE; + persistent = 1; + break; + default: + break; + } + } + + for (lindex=0;lindex!=nlocales;++lindex) { + if (locale_array[lindex]->lang==lang) break; + } + if (lindex==nlocales) { + locale_array[nlocales] = (locale_data*)calloc(1, sizeof(locale_data)); + locale_array[nlocales]->lang = lang; + ++nlocales; + } + + ord = (order*)malloc(sizeof(order)); + ord->_persistent = persistent; + ord->next = NULL; + + ord->data = create_data(kwd, sptr, lindex); + + return ord; +} + +order * +create_order(keyword_t kwd, const struct locale * lang, const char * params, ...) +{ + char zBuffer[DISPLAYSIZE]; + if (params) { + char * bufp = zBuffer; + int bytes; + size_t size = sizeof(zBuffer) - 1; + va_list marker; + + va_start(marker, params); + while (*params) { + if (*params=='%') { + int i; + const char * s; + ++params; + switch (*params) { + case 's': + s = va_arg(marker, const char *); + bytes = (int)strlcpy(bufp, s, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + break; + case 'd': + i = va_arg(marker, int); + bytes = (int)strlcpy(bufp, itoa10(i), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + break; + case 'i': + i = va_arg(marker, int); + bytes = (int)strlcpy(bufp, itoa36(i), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + break; + default: + assert(!"unknown format-character in create_order"); + } + } else if (size>0) { + *bufp++ = *params; + --size; + } + ++params; + } + va_end(marker); + *bufp = 0; + } else { + zBuffer[0] = 0; + } + return create_order_i(kwd, zBuffer, 0, lang); +} + +order * +parse_order(const char * s, const struct locale * lang) +{ + while (*s && !isalnum(*(unsigned char*)s) && !ispunct(*(unsigned char*)s)) ++s; + if (*s!=0) { + keyword_t kwd; + const char * sptr; + int persistent = 0; + + while (*s=='@') { + persistent = 1; + ++s; + } + sptr = s; + kwd = findkeyword(parse_token(&sptr), lang); + if (kwd!=NOKEYWORD) { + while (isxspace(*(unsigned char*)sptr)) ++sptr; + s = sptr; + } + return create_order_i(kwd, s, persistent, lang); + } + return NULL; +} + +boolean +is_repeated(const order * ord) +{ + keyword_t kwd = ORD_KEYWORD(ord); + const struct locale * lang = ORD_LOCALE(ord); + param_t param; + + switch (kwd) { + case K_CAST: + case K_BUY: + case K_SELL: + case K_ROUTE: + case K_DRIVE: + case K_WORK: + case K_BESIEGE: + case K_ENTERTAIN: + case K_TAX: + case K_RESEARCH: + case K_SPY: + case K_STEAL: + case K_SABOTAGE: + case K_STUDY: + case K_TEACH: + case K_BREED: + case K_PIRACY: + return true; + + case K_PLANT: + return true; + + case K_FOLLOW: + /* FOLLOW is only a long order if we are following a ship. */ + parser_pushstate(); + init_tokens(ord); + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param == P_SHIP) return true; + break; + + case K_MAKE: + /* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen + * Arten von MACHE zaehlen aber als neue defaults und werden + * behandelt wie die anderen (deswegen kein break nach case + * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) + * abgespeichert). */ + parser_pushstate(); + init_tokens(ord); /* initialize token-parser */ + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param != P_TEMP) return true; + break; + } + return false; +} + +boolean +is_exclusive(const order * ord) +{ + keyword_t kwd = ORD_KEYWORD(ord); + const struct locale * lang = ORD_LOCALE(ord); + param_t param; + + switch (kwd) { + case K_MOVE: + case K_WEREWOLF: + /* these should not become persistent */ + case K_ROUTE: + case K_DRIVE: + case K_WORK: + case K_BESIEGE: + case K_ENTERTAIN: + case K_TAX: + case K_RESEARCH: + case K_SPY: + case K_STEAL: + case K_SABOTAGE: + case K_STUDY: + case K_TEACH: + case K_BREED: + case K_PIRACY: + return true; + + case K_PLANT: + return true; + + case K_FOLLOW: + /* FOLLOW is only a long order if we are following a ship. */ + parser_pushstate(); + init_tokens(ord); + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param == P_SHIP) return true; + break; + + case K_MAKE: + /* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen + * Arten von MACHE zaehlen aber als neue defaults und werden + * behandelt wie die anderen (deswegen kein break nach case + * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) + * abgespeichert). */ + parser_pushstate(); + init_tokens(ord); /* initialize token-parser */ + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param != P_TEMP) return true; + break; + } + return false; +} + +boolean +is_persistent(const order * ord) +{ + keyword_t kwd = ORD_KEYWORD(ord); + boolean persist = ord->_persistent!=0; + switch (kwd) { + case K_MOVE: + case K_WEREWOLF: + case NOKEYWORD: + /* lang, aber niemals persistent! */ + return false; + + case K_KOMMENTAR: + case K_LIEFERE: + return true; + } + + return persist || is_repeated(ord); +} + +char * +write_order(const order * ord, char * buffer, size_t size) +{ + if (ord==0) { + buffer[0]=0; + } else { + keyword_t kwd = ORD_KEYWORD(ord); + if (kwd==NOKEYWORD) { + const char * text = ORD_STRING(ord); + strlcpy(buffer, (const char *)text, size); + } else { + get_command(ord, buffer, size); + } + } + return buffer; +} diff --git a/src/kernel/order.h b/src/kernel/order.h new file mode 100644 index 000000000..29f273863 --- /dev/null +++ b/src/kernel/order.h @@ -0,0 +1,61 @@ +/* vi: set ts=2: + +-------------------+ + | | Christian Schlittchen + | Eressea PBEM host | Enno Rehling + | (c) 1998 - 2004 | Katja Zedel + | | + +-------------------+ + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef KRNL_ORDER_H +#define KRNL_ORDER_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Encapsulation of an order + * + * This structure contains one order given by a unit. These used to be + * stored in string lists, but by storing them in order-structures, + * it is possible to use reference-counting on them, reduce string copies, + * and reduce overall memory usage by sharing strings between orders (not + * implemented yet) saving approx. 50% of all string-related memory. + */ + +struct order_data; + +typedef struct order { + struct order * next; + /* do not access this data: */ + struct order_data * data; + int _persistent : 1; +} order; + +/* constructor */ +extern 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); + +/* reference counted copies of orders: */ +extern order * copy_order(const order * ord); +extern void free_order(order * ord); +extern void free_orders(order ** olist); + +/* access functions for orders */ +extern keyword_t get_keyword(const order * ord); +extern void set_order(order ** destp, order * src); +extern char * getcommand(const order * ord); +extern boolean is_persistent(const order *ord); +extern boolean is_exclusive(const order *ord); +extern boolean is_repeated(const order * ord); + +extern char * write_order(const order * ord, char * buffer, size_t size); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/pathfinder.c b/src/kernel/pathfinder.c new file mode 100644 index 000000000..29c52ed8b --- /dev/null +++ b/src/kernel/pathfinder.c @@ -0,0 +1,200 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "pathfinder.h" + +#include "region.h" +#include "terrain.h" + +#include +#include +#include + +boolean +allowed_swim(const region * src, const region * r) +{ + if (fval(r->terrain, SWIM_INTO)) return true; + return false; +} + +boolean +allowed_walk(const region * src, const region * r) +{ + if (fval(r->terrain, WALK_INTO)) return true; + return false; +} + +boolean +allowed_fly(const region * src, const region * r) +{ + if (fval(r->terrain, FLY_INTO)) return true; + return false; +} + +typedef struct node { + struct node * next; + region * r; + struct node * prev; + int distance; +} node; + +static node * node_garbage; + +void +pathfinder_cleanup(void) +{ + while (node_garbage) { + node * n = node_garbage; + node_garbage = n->next; + free(n); + } +} + +static node * +new_node(region * r, int distance, node * prev) +{ + node * n; + if (node_garbage!=NULL) { + n = node_garbage; + node_garbage = n->next; + } + else n = malloc(sizeof(node)); + n->next = NULL; + n->prev = prev; + n->r= r; + n->distance= distance; + return n; +} + +static node * +free_node(node * n) +{ + node * s = n->next; + n->next = node_garbage; + node_garbage = n; + return s; +} + +static void +free_nodes(node * root) +{ + while (root!=NULL) { + region * r = root->r; + freset(r, RF_MARK); + root = free_node(root); + } +} + +struct region_list * +regions_in_range(struct region * start, int maxdist, boolean (*allowed)(const struct region*, const struct region*)) +{ + region_list * rlist = NULL; + node * root = new_node(start, 0, NULL); + node ** end = &root->next; + node * n = root; + + while (n!=NULL) { + region * r = n->r; + int depth = n->distance+1; + direction_t d; + + if (n->distance >= maxdist) break; + for (d=0;d!=MAXDIRECTIONS; ++d) { + region * rn = rconnect(r, d); + if (rn==NULL) continue; + if (fval(rn, RF_MARK)) continue; /* already been there */ + if (allowed && !allowed(r, rn)) continue; /* can't go there */ + + /* add the region to the list of available ones. */ + add_regionlist(&rlist, rn); + + /* make sure we don't go here again, and put the region into the set for + further BFS'ing */ + fset(rn, RF_MARK); + *end = new_node(rn, depth, n); + end = &(*end)->next; + } + n = n->next; + } + free_nodes(root); + + return rlist; +} + +static region ** +internal_path_find(region *start, const region *target, int maxlen, boolean (*allowed)(const region*, const region*)) +{ + static region * path[MAXDEPTH+2]; /* STATIC_RETURN: used for return, not across calls */ + direction_t d; + node * root = new_node(start, 0, NULL); + node ** end = &root->next; + node * n = root; + boolean found = false; + assert(maxlen<=MAXDEPTH); + fset(start, RF_MARK); + + while (n!=NULL) { + region * r = n->r; + int depth = n->distance+1; + if (n->distance >= maxlen) break; + for (d=0;d!=MAXDIRECTIONS; ++d) { + region * rn = rconnect(r, d); + if (rn==NULL) continue; + if (fval(rn, RF_MARK)) continue; /* already been there */ + if (!allowed(r, rn)) continue; /* can't go there */ + if (rn==target) { + int i = depth; + path[i+1] = NULL; + path[i] = rn; + while (n) { + path[--i] = n->r; + n = n->prev; + } + found = true; + break; + } else { + fset(rn, RF_MARK); + *end = new_node(rn, depth, n); + end = &(*end)->next; + } + } + if (found) break; + n = n->next; + } + free_nodes(root); + if (found) return path; + return NULL; +} + +boolean +path_exists(region *start, const region *target, int maxlen, boolean (*allowed)(const region*, const region*)) +{ + assert((!fval(start, RF_MARK) && !fval(target, RF_MARK)) || !"Some Algorithm did not clear its RF_MARKs!"); + if (start==target) return true; + if (internal_path_find(start, target, maxlen, allowed)!=NULL) return true; + return false; +} + +region ** +path_find(region *start, const region *target, int maxlen, boolean (*allowed)(const region*, const region*)) +{ + assert((!fval(start, RF_MARK) && !fval(target, RF_MARK)) || !"Did you call path_init()?"); + return internal_path_find(start, target, maxlen, allowed); +} diff --git a/src/kernel/pathfinder.h b/src/kernel/pathfinder.h new file mode 100644 index 000000000..5ae704509 --- /dev/null +++ b/src/kernel/pathfinder.h @@ -0,0 +1,42 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_PATHFINDER +#define H_KRNL_PATHFINDER +#ifdef __cplusplus +extern "C" { +#endif + +#define MAXDEPTH 1024 + +extern int search[MAXDEPTH][2]; +extern int search_len; + +extern struct region ** path_find(struct region *start, const struct region *target, int maxlen, boolean (*allowed)(const struct region*, const struct region*)); +extern boolean path_exists(struct region *start, const struct region *target, int maxlen, boolean (*allowed)(const struct region*, const struct region*)); +extern boolean allowed_swim(const struct region * src, const struct region * target); +extern boolean allowed_fly(const struct region * src, const struct region * target); +extern boolean allowed_walk(const struct region * src, const struct region * target); +extern struct region_list * regions_in_range(struct region * src, int maxdist, boolean (*allowed)(const struct region*, const struct region*)); + +extern void pathfinder_cleanup(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/plane.c b/src/kernel/plane.c new file mode 100644 index 000000000..8ab941838 --- /dev/null +++ b/src/kernel/plane.c @@ -0,0 +1,326 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "plane.h" + +/* kernel includes */ +#include "region.h" +#include "faction.h" + +/* util includes */ +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +struct plane *planes; + +int plane_width(const plane * pl) +{ + if (pl) { + return pl->maxx-pl->minx+1; + } + return 0; +} + +int plane_height(const plane * pl) +{ + if (pl) { + return pl->maxy-pl->miny+1; + } + return 0; +} + +static plane * home_plane = NULL; + +plane * +get_homeplane(void) +{ + return getplanebyid(0); +} + + +plane * +getplane(const region *r) +{ + if (r) { + return r->_plane; + } + return get_homeplane(); +} + +plane * +getplanebyid(int id) +{ + plane *p; + + for (p=planes; p; p=p->next) { + if (p->id == id) { + return p; + } + } + return NULL; +} + +plane * +getplanebyname(const char * name) +{ + plane *p; + + for (p=planes; p; p=p->next) + if (p->name && !strcmp(p->name, name)) + return p; + return NULL; +} + +plane * +findplane(int x, int y) +{ + plane *pl; + + for(pl=planes;pl;pl=pl->next) { + if(x >= pl->minx && x <= pl->maxx + && y >= pl->miny && y <= pl->maxy) { + return pl; + } + } + return NULL; +} + +int +getplaneid(const region *r) + +{ + if(r) { + plane * pl = getplane(r); + if (pl) return pl->id; + + for(pl=planes;pl;pl=pl->next) { + if(r->x >= pl->minx && r->x <= pl->maxx + && r->y >= pl->miny && r->y <= pl->maxy) { + return pl->id; + } + } + } + return 0; +} + +static int +ursprung_x(const faction *f, const plane *pl, const region * rdefault) +{ + ursprung *ur; + int id = 0; + + if(!f) + return 0; + + if(pl) + id = pl->id; + + for(ur = f->ursprung; ur; ur = ur->next) { + if(ur->id == id) + return ur->x; + } + if (!rdefault) return 0; + set_ursprung((faction*)f, id, rdefault->x - plane_center_x(pl), rdefault->y - plane_center_y(pl)); + return rdefault->x - plane_center_x(pl); +} + +static int +ursprung_y(const faction *f, const plane *pl, const region * rdefault) +{ + ursprung *ur; + int id = 0; + + if(!f) + return 0; + + if(pl) + id = pl->id; + + for(ur = f->ursprung; ur; ur = ur->next) { + if(ur->id == id) + return ur->y; + } + if (!rdefault) return 0; + set_ursprung((faction*)f, id, rdefault->x - plane_center_x(pl), rdefault->y - plane_center_y(pl)); + return rdefault->y - plane_center_y(pl); +} + +int +plane_center_x(const plane *pl) +{ + if(pl == NULL) + return 0; + + return(pl->minx + pl->maxx)/2; +} + +int +plane_center_y(const plane *pl) +{ + if(pl == NULL) + return 0; + + return(pl->miny + pl->maxy)/2; +} + +void +adjust_coordinates(const faction *f, int *x, int *y, const plane * pl, const region * r) +{ + int nx = *x; + int ny = *y; + if (f) { + nx -= ursprung_x(f, pl, r); + ny -= ursprung_y(f, pl, r); + } + if (pl) { + nx -= plane_center_x(pl); + ny -= plane_center_y(pl); + } + + if (pl) { + int width = plane_width(pl); + int height = plane_height(pl); + int width_2 = width/2; + int height_2 = height/2; + + if (nx<0) nx = (width-(-nx)%width); + if (nx>width_2) nx -= width; + if (ny<0) ny = (height-(-ny)%height); + if (ny>height_2) ny -= height; + } + + assert(!pl || nx<=pl->maxx - plane_center_x(pl)); + assert(!pl || nx>=pl->minx - plane_center_x(pl)); + assert(!pl || ny<=pl->maxy - plane_center_y(pl)); + assert(!pl || ny>=pl->miny - plane_center_y(pl)); + + *x = nx; + *y = ny; +} + +void +set_ursprung(faction *f, int id, int x, int y) +{ + ursprung *ur; + assert(f!=NULL); + for(ur=f->ursprung;ur;ur=ur->next) { + if (ur->id == id) { + ur->x = ur->x + x; + ur->y = ur->y + y; + return; + } + } + + ur = calloc(1, sizeof(ursprung)); + ur->id = id; + ur->x = x; + ur->y = y; + + addlist(&f->ursprung, ur); +} + +plane * +create_new_plane(int id, const char *name, int minx, int maxx, int miny, int maxy, int flags) +{ + plane *pl = getplanebyid(id); + + if (pl) return pl; + pl = calloc(1, sizeof(plane)); + + pl->next = NULL; + pl->id = id; + if (name) pl->name = strdup(name); + pl->minx = minx; + pl->maxx = maxx; + pl->miny = miny; + pl->maxy = maxy; + pl->flags = flags; + + addlist(&planes, pl); + if (id==0) { + home_plane = pl; + } + return pl; +} + +/* Umrechnung Relative-Absolute-Koordinaten */ +int +rel_to_abs(const struct plane *pl, const struct faction * f, int rel, unsigned char index) +{ + assert(index == 0 || index == 1); + + if(index == 0) + return (rel + ursprung_x(f, pl, NULL) + plane_center_x(pl)); + + return (rel + ursprung_y(f, pl, NULL) + plane_center_y(pl)); +} + + +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) +{ + store->w_int(store, u?(u->id):0); +} + +int +read_plane_reference(plane ** pp, struct storage * store) +{ + variant id; + id.i = store->r_int(store); + 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; +} + +boolean +is_watcher(const struct plane * p, const struct faction * f) +{ + struct watcher * w; + if (!p) return false; + w = p->watchers; + while (w && w->faction!=f) w=w->next; + return (w!=NULL); +} diff --git a/src/kernel/plane.h b/src/kernel/plane.h new file mode 100644 index 000000000..f7827679f --- /dev/null +++ b/src/kernel/plane.h @@ -0,0 +1,84 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_PLANES +#define H_KRNL_PLANES +#ifdef __cplusplus +extern "C" { +#endif + +#define PFL_NOCOORDS 1 /* not in use */ +#define PFL_NORECRUITS 2 +#define PFL_NOALLIANCES 4 +#define PFL_LOWSTEALING 8 +#define PFL_NOGIVE 16 /* Übergaben sind unmöglich */ +#define PFL_NOATTACK 32 /* Angriffe und Diebstähle sind unmöglich */ +#define PFL_NOTERRAIN 64 /* Terraintyp wird nicht angezeigt TODO? */ +#define PFL_NOMAGIC 128 /* Zaubern ist unmöglich */ +#define PFL_NOSTEALTH 256 /* Tarnung außer Betrieb */ +#define PFL_NOTEACH 512 /* Lehre außer Betrieb */ +#define PFL_NOBUILD 1024 /* Bauen außer Betrieb */ +#define PFL_NOFEED 2048 /* Kein Unterhalt nötig */ +#define PFL_FRIENDLY 4096 /* everyone is your ally */ +#define PFL_NOORCGROWTH 8192 /* orcs don't grow */ +#define PFL_NOMONSTERS 16384 /* no monster randenc */ +#define PFL_SEESPECIAL 32768 /* far seeing */ + +typedef struct watcher { + struct watcher * next; + struct faction * faction; + unsigned char mode; +} watcher; + +typedef struct plane { + struct plane *next; + struct watcher * watchers; + int id; + char *name; + int minx, maxx, miny, maxy; + unsigned int flags; + struct attrib *attribs; +} plane; + +#define plane_id(pl) ( (pl) ? (pl)->id : 0 ) + +extern struct plane *planes; + +struct plane *getplane(const struct region *r); +struct plane *findplane(int x, int y); +void init_planes(void); +int getplaneid(const struct region *r); +struct plane * getplanebyid(int id); +int plane_center_x(const struct plane *pl); +int plane_center_y(const struct plane *pl); +void set_ursprung(struct faction *f, int id, int x, int y); +struct plane * create_new_plane(int id, const char *name, int minx, int maxx, int miny, int maxy, int flags); +struct plane * getplanebyname(const char *); +struct plane * get_homeplane(void); +extern int rel_to_abs(const struct plane *pl, const struct faction * f, int rel, unsigned char index); +extern boolean is_watcher(const struct plane * p, const struct faction * f); +extern int resolve_plane(variant data, void * addr); +extern void write_plane_reference(const plane * p, struct storage * store); +extern int read_plane_reference(plane ** pp, struct storage * store); +extern int plane_width(const plane * pl); +extern int plane_height(const plane * pl); +void adjust_coordinates(const struct faction *f, int *x, int *y, const struct plane * pl, const struct region * r); +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/player.c b/src/kernel/player.c new file mode 100644 index 000000000..c8076f640 --- /dev/null +++ b/src/kernel/player.c @@ -0,0 +1,101 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ +#include +#include "player.h" + +#include +#include + +#include +#include + +#define PMAXHASH 1021 + +typedef struct player_hash { + struct player * entries; +} player_hash; + +static player_hash * players[PMAXHASH]; + +player * +make_player(const struct faction * f) +{ + player * p = calloc(sizeof(player), 1); + unsigned int hash; + + for (p->id = rng_int();;p->id++) { + /* if there is a hashing conflict, resolve it */ + player * pi = get_player(p->id); + if (pi) p->id++; + else break; + } + hash = p->id % PMAXHASH; + p->faction = f; + p->nexthash = players[hash]->entries; + players[hash]->entries = p; + + return p; +} + +player * +next_player(player * p) +{ + if (p->nexthash) return p->nexthash; + else { + unsigned int hash = p->id % PMAXHASH; + p = NULL; + while (++hash!=PMAXHASH) { + if (players[hash]->entries!=NULL) { + p = players[hash]->entries; + break; + } + } + return p; + } +} + +player * +get_player(unsigned int id) +{ + unsigned int hash = id % PMAXHASH; + struct player * p = players[hash]->entries; + + while (p && p->id!=id) p = p->nexthash; + return p; +} + +player * +get_players(void) +{ + struct player * p = NULL; + unsigned int hash = 0; + + while (p!=NULL && hash!=PMAXHASH) { + p = players[hash++]->entries; + } + return p; +} + +void +players_done(void) +{ + int i; + for (i=0;i!=PMAXHASH;++i) { + player * p = players[i]->entries; + players[i]->entries = p->nexthash; + free(p->name); + if (p->email) free(p->email); + if (p->name) free(p->name); + free(p); + } +} diff --git a/src/kernel/player.h b/src/kernel/player.h new file mode 100644 index 000000000..74fb8c4a5 --- /dev/null +++ b/src/kernel/player.h @@ -0,0 +1,43 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ +#ifndef H_KRNL_PLAYER +#define H_KRNL_PLAYER +#ifdef __cplusplus +extern "C" { +#endif + +struct faction; + +typedef struct player { + unsigned int id; + char * name; + char * email; + char * address; + struct vacation { + int weeks; + char * email; + } * vacation; + const struct faction * faction; + + struct player * nexthash; /* don't use! */ +} player; + +extern struct player * get_players(void); +extern struct player * get_player(unsigned int id); +extern struct player * make_player(const struct faction * f); +extern struct player * next_player(struct player * p); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/pool.c b/src/kernel/pool.c new file mode 100644 index 000000000..a7a1e6b02 --- /dev/null +++ b/src/kernel/pool.c @@ -0,0 +1,262 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "pool.h" + +#include "faction.h" +#include "item.h" +#include "magic.h" +#include "order.h" +#include "region.h" +#include "race.h" +#include "unit.h" + +#include +#include + +#include +#include + +#define TODO_POOL +#undef TODO_RESOURCES + +int +get_resource(const unit * u, const resource_type * rtype) +{ + const item_type * itype = resource2item(rtype); + + if (rtype->uget) { + /* this resource is probably special */ + int i = rtype->uget(u, rtype); + if (i>=0) return i; + } + if (itype!=NULL) { + if (itype == olditemtype[R_STONE] && (u->race->flags&RCF_STONEGOLEM)) { + return u->number*GOLEM_STONE; + } else if (itype==olditemtype[R_IRON] && (u->race->flags&RCF_IRONGOLEM)) { + return u->number*GOLEM_IRON; + } else { + const item * i = *i_findc(&u->items, itype); + if (i) return i->number; + return 0; + } + } + if (rtype == oldresourcetype[R_AURA]) + return get_spellpoints(u); + if (rtype == oldresourcetype[R_PERMAURA]) + return max_spellpoints(u->region, u); + log_error(("trying to get unknown resource '%s'.\n", rtype->_name[0])); + return 0; +} + +int +change_resource(unit * u, const resource_type * rtype, int change) +{ + int i = 0; + + if (rtype->uchange) + i = rtype->uchange(u, rtype, change); + else if (rtype == oldresourcetype[R_AURA]) + i = change_spellpoints(u, change); + else if (rtype == oldresourcetype[R_PERMAURA]) + i = change_maxspellpoints(u, change); + else + assert(!"undefined resource detected. rtype->uchange not initialized."); + assert(i >= 0 && (i < 100000000)); /* soft test to catch mischief */ + return i; +} + +int +get_reservation(const unit * u, const resource_type * rtype) +{ + struct reservation * res = u->reservations; + + if (rtype==oldresourcetype[R_STONE] && (u->race->flags&RCF_STONEGOLEM)) + return (u->number * GOLEM_STONE); + if (rtype==oldresourcetype[R_IRON] && (u->race->flags&RCF_IRONGOLEM)) + return (u->number * GOLEM_IRON); + while (res && res->type!=rtype) res=res->next; + if (res) return res->value; + return 0; +} + +int +change_reservation(unit * u, const resource_type * rtype, int value) +{ + struct reservation *res, ** rp = &u->reservations; + + if (!value) return 0; + + while (*rp && (*rp)->type!=rtype) rp=&(*rp)->next; + res = *rp; + if (!res) { + *rp = res = calloc(sizeof(struct reservation), 1); + res->type = rtype; + res->value = value; + } else if (res && res->value+value<=0) { + *rp = res->next; + free(res); + return 0; + } else { + res->value += value; + } + return res->value; +} + +static int +new_set_resvalue(unit * u, const resource_type * rtype, int value) +{ + struct reservation *res, ** rp = &u->reservations; + + while (*rp && (*rp)->type!=rtype) rp=&(*rp)->next; + res = *rp; + if (!res) { + if (!value) return 0; + *rp = res = calloc(sizeof(struct reservation), 1); + res->type = rtype; + res->value = value; + } else if (res && value<=0) { + *rp = res->next; + free(res); + return 0; + } else { + res->value = value; + } + return res->value; +} + +int +get_pooled(const unit * u, const resource_type * rtype, unsigned int mode, int count) +{ + const faction * f = u->faction; + unit *v; + int use = 0; + region * r = u->region; + int have = get_resource(u, rtype); + + if ((u->race->ec_flags & GETITEM) == 0) { + mode &= (GET_SLACK|GET_RESERVE); + } + + if ((mode & GET_SLACK) && (mode & GET_RESERVE)) use = have; + else { + int reserve = get_reservation(u, rtype); + int slack = MAX(0, have-reserve); + if (mode & GET_RESERVE) use = have-slack; + else if (mode & GET_SLACK) use = slack; + } + if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK|GET_RESERVE)) { + for (v = r->units; v && usenext) if (u!=v) { + int mask; + + if (v->items==NULL && rtype->uget==NULL) continue; + if ((urace(v)->ec_flags & GIVEITEM) == 0) continue; + + if (v->faction == f) { + mask = (mode >> 3) & (GET_SLACK|GET_RESERVE); + } + else if (alliedunit(v, f, HELP_MONEY)) mask = (mode >> 6) & (GET_SLACK|GET_RESERVE); + else continue; + use += get_pooled(v, rtype, mask, count-use); + } + } + return use; +} + +int +use_pooled(unit * u, const resource_type * rtype, unsigned int mode, int count) +{ + const faction *f = u->faction; + unit *v; + int use = count; + region * r = u->region; + int n = 0, have = get_resource(u, rtype); + + if ((u->race->ec_flags & GETITEM) == 0) { + mode &= (GET_SLACK|GET_RESERVE); + } + + if ((mode & GET_SLACK) && (mode & GET_RESERVE)) { + n = MIN(use, have); + } else { + int reserve = get_reservation(u, rtype); + int slack = MAX(0, have-reserve); + if (mode & GET_RESERVE) { + n = have-slack; + n = MIN(use, n); + change_reservation(u, rtype, -n); + } + else if (mode & GET_SLACK) { + n = MIN(use, slack); + } + } + if (n>0) { + change_resource(u, rtype, -n); + use -= n; + } + + if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK|GET_RESERVE)) { + for (v = r->units; use>0 && v!=NULL; v = v->next) if (u!=v) { + int mask; + if ((urace(v)->ec_flags & GIVEITEM) == 0) continue; + if (v->items==NULL && rtype->uget==NULL) continue; + + if (v->faction == f) { + mask = (mode >> 3) & (GET_SLACK|GET_RESERVE); + } + else if (alliedunit(v, f, HELP_MONEY)) mask = (mode >> 6) & (GET_SLACK|GET_RESERVE); + else continue; + use -= use_pooled(v, rtype, mask, use); + } + } + return count-use; +} + + +int +reserve_cmd(unit * u, struct order *ord) +{ + if (u->number > 0 && (urace(u)->ec_flags & GETITEM)) { + int use, count; + const resource_type * rtype; + const char * s; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + count = atoip((const char *)s); + + if (count == 0 && findparam(s, u->faction->locale)==P_EACH) { + count = getint() * u->number; + } + + rtype = findresourcetype(getstrtoken(), u->faction->locale); + if (rtype == NULL) return 0; + + new_set_resvalue(u, rtype, 0); /* make sure the pool is empty */ + use = use_pooled(u, rtype, GET_DEFAULT, count); + if (use) { + new_set_resvalue(u, rtype, use); + change_resource(u, rtype, use); + } + } + return 0; +} + diff --git a/src/kernel/pool.h b/src/kernel/pool.h new file mode 100644 index 000000000..124bcb432 --- /dev/null +++ b/src/kernel/pool.h @@ -0,0 +1,62 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_POOL_H +#define H_KRNL_POOL_H +#ifdef __cplusplus +extern "C" { +#endif + +/* bitfield values for get/use/change operations */ +#define GET_SLACK 0x01 +#define GET_RESERVE 0x02 + +#define GET_POOLED_SLACK 0x08 +#define GET_POOLED_RESERVE 0x10 +#define GET_POOLED_FORCE 0x20 /* ignore f->options pools */ +#define GET_ALLIED_SLACK 0x30 +#define GET_ALLIED_RESERVE 0x40 + +/* for convenience: */ +#define GET_DEFAULT (GET_RESERVE|GET_SLACK|GET_POOLED_SLACK) +#define GET_ALL (GET_SLACK|GET_RESERVE|GET_POOLED_SLACK|GET_POOLED_RESERVE|GET_POOLED_FORCE) + +int get_pooled(const struct unit * u, const struct resource_type * res, unsigned int mode, int count); +int use_pooled(struct unit * u, const struct resource_type * res, unsigned int mode, int count); + /** use_pooled + * verbraucht 'count' Objekte der resource 'itm' + * unter zuhilfenahme des Pools der struct region und Aufbrauch des + * von der Einheit reservierten Resourcen + */ + +int get_resource(const struct unit * u, const struct resource_type * res); +int change_resource(struct unit * u, const struct resource_type * res, int change); + +int get_reservation(const struct unit * u, const struct resource_type * res); +int change_reservation(struct unit * u, const struct resource_type * res, int value); + +int reserve_cmd(struct unit *u, struct order *ord); + +/** init_pool + * initialisiert den regionalen Pool. + */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/race.c b/src/kernel/race.c new file mode 100644 index 000000000..bc2977b0a --- /dev/null +++ b/src/kernel/race.c @@ -0,0 +1,296 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "race.h" + +#include "alchemy.h" +#include "build.h" +#include "building.h" +#include "equipment.h" +#include "faction.h" +#include "group.h" +#include "item.h" +#include "magic.h" +#include "names.h" +#include "pathfinder.h" +#include "region.h" +#include "ship.h" +#include "skill.h" +#include "terrain.h" +#include "unit.h" +#include "version.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include + +/* attrib includes */ +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +/** external variables **/ +race * races; +int num_races = 0; + +race_list * +get_familiarraces(void) +{ + static int init = 0; + static race_list * familiarraces; + + if (!init) { + race * rc = races; + for (;rc!=NULL;rc=rc->next) { + if (rc->init_familiar!=NULL) { + racelist_insert(&familiarraces, rc); + } + } + init = false; + } + return familiarraces; +} + +void +racelist_clear(struct race_list **rl) +{ + while (*rl) { + race_list * rl2 = (*rl)->next; + free(*rl); + *rl = rl2; + } +} + +void +racelist_insert(struct race_list **rl, const struct race *r) +{ + race_list *rl2 = (race_list*)malloc(sizeof(race_list)); + + rl2->data = r; + rl2->next = *rl; + + *rl = rl2; +} + +race * +rc_new(const char * zName) +{ + char zBuffer[80]; + race * rc = calloc(sizeof(race), 1); + if (strchr(zName, ' ')!=NULL) { + log_error(("race '%s' has an invalid name. remove spaces\n", zName)); + assert(strchr(zName, ' ')==NULL); + } + strcpy(zBuffer, zName); + rc->_name[0] = strdup(zBuffer); + sprintf(zBuffer, "%s_p", zName); + rc->_name[1] = strdup(zBuffer); + sprintf(zBuffer, "%s_d", zName); + rc->_name[2] = strdup(zBuffer); + sprintf(zBuffer, "%s_x", zName); + rc->_name[3] = strdup(zBuffer); + rc->precombatspell = NULL; + + rc->attack[0].type = AT_COMBATSPELL; + rc->attack[1].type = AT_NONE; + return rc; +} + +race * +rc_add(race * rc) +{ + rc->index = num_races++; + rc->next = races; + return races = rc; +} + +static const char * racealias[][2] = { + { "uruk", "orc" }, /* there was a time when the orc race was called uruk (and there were other orcs). That was really confusing */ + { "skeletton lord", "skeleton lord" }, /* we once had a typo here. it is fixed */ + { NULL, NULL } +}; + +race * +rc_find(const char * name) +{ + const char * rname = name; + race * rc = races; + int i; + + for (i=0;racealias[i][0];++i) { + if (strcmp(racealias[i][0], name)==0) { + rname = racealias[i][1]; + break; + } + } + while (rc && !strcmp(rname, rc->_name[0])==0) rc = rc->next; + return rc; +} + +/** dragon movement **/ +boolean +allowed_dragon(const region * src, const region * target) +{ + if (fval(src->terrain, ARCTIC_REGION) && fval(target->terrain, SEA_REGION)) return false; + return allowed_fly(src, target); +} + +char ** race_prefixes = NULL; + +extern void +add_raceprefix(const char * prefix) +{ + static size_t size = 4; + static unsigned int next = 0; + if (race_prefixes==NULL) race_prefixes = malloc(size * sizeof(char*)); + if (next+1==size) { + size *= 2; + race_prefixes = realloc(race_prefixes, size * sizeof(char*)); + } + race_prefixes[next++] = strdup(prefix); + race_prefixes[next] = NULL; +} + +/* Die Bezeichnungen dürfen wegen der Art des Speicherns keine + * Leerzeichen enthalten! */ + +/* "den Zwergen", "Halblingsparteien" */ + +void +set_show_item(faction *f, item_t i) +{ + attrib *a = a_add(&f->attribs, a_new(&at_showitem)); + a->data.v = (void*)olditemtype[i]; +} + +boolean +r_insectstalled(const region * r) +{ + return fval(r->terrain, ARCTIC_REGION); +} + +const char * +rc_name(const race * rc, int n) +{ + return rc?mkname("race", rc->_name[n]):NULL; +} + +const char * +raceprefix(const unit *u) +{ + const attrib * asource = u->faction->attribs; + + if (fval(u, UFL_GROUP)) { + const attrib * agroup = agroup = a_findc(u->attribs, &at_group); + if (agroup!=NULL) asource = ((const group *)(agroup->data.v))->attribs; + } + return get_prefix(asource); +} + +const char * +racename(const struct locale *loc, const unit *u, const race * rc) +{ + const char * prefix = raceprefix(u); + + if (prefix!=NULL) { + static char lbuf[80]; + char * bufp = lbuf; + size_t size = sizeof(lbuf) - 1; + int ch, bytes; + + bytes = (int)strlcpy(bufp, LOC(loc, mkname("prefix", prefix)), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + bytes = (int)strlcpy(bufp, LOC(loc, rc_name(rc, u->number != 1)), size); + assert(~bufp[0] & 0x80|| !"unicode/not implemented"); + ch = tolower(*(unsigned char *)bufp); + bufp[0] = (char)ch; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + *bufp = 0; + + return lbuf; + } + return LOC(loc, rc_name(rc, u->number != 1)); +} + +int +rc_specialdamage(const race * ar, const race * dr, const struct weapon_type * wtype) +{ + race_t art = old_race(ar); + int m, modifier = 0; + + if (wtype!=NULL && wtype->modifiers!=NULL) for (m=0;wtype->modifiers[m].value;++m) { + /* weapon damage for this weapon, possibly by race */ + if (wtype->modifiers[m].flags & WMF_DAMAGE) { + race_list * rlist = wtype->modifiers[m].races; + if (rlist!=NULL) { + while (rlist) { + if (rlist->data == ar) break; + rlist = rlist->next; + } + if (rlist==NULL) continue; + } + modifier += wtype->modifiers[m].value; + } + } + switch (art) { + case RC_HALFLING: + if (wtype!=NULL && dragonrace(dr)) { + modifier += 5; + } + break; + default: + break; + } + return modifier; +} + +void +write_race_reference(const race * rc, struct storage * store) +{ + store->w_tok(store, rc?rc->_name[0]:"none"); +} + +variant +read_race_reference(struct storage * store) +{ + variant result; + char zName[20]; + store->r_tok_buf(store, zName, sizeof(zName)); + + if (strcmp(zName, "none")==0) { + result.v = NULL; + return result; + } else { + result.v = rc_find(zName); + } + assert(result.v!=NULL); + return result; +} diff --git a/src/kernel/race.h b/src/kernel/race.h new file mode 100644 index 000000000..321eb4826 --- /dev/null +++ b/src/kernel/race.h @@ -0,0 +1,192 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_RACE_H +#define H_KRNL_RACE_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "magic.h" /* wegen MAXMAGIETYP */ + +#define AT_NONE 0 +#define AT_STANDARD 1 +#define AT_DRAIN_EXP 2 +#define AT_DRAIN_ST 3 +#define AT_NATURAL 4 +#define AT_DAZZLE 5 +#define AT_SPELL 6 +#define AT_COMBATSPELL 7 +#define AT_STRUCTURAL 8 + +#define GOLEM_IRON 4 /* Anzahl Eisen in einem Eisengolem */ +#define GOLEM_STONE 4 /* Anzahl Steine in einem Steingolem */ + +#define RACESPOILCHANCE 5 /* Chance auf rassentypische Beute */ + +typedef struct att { + int type; + union { + const char * dice; + const struct spell * sp; + } data; + int flags; +} att; + +struct param; + +extern int num_races; + +typedef struct race { + struct param * parameters; + const char *_name[4]; /* neu: name[4]völker */ + float magres; + float maxaura; /* Faktor auf Maximale Aura */ + float regaura; /* Faktor auf Regeneration */ + float recruit_multi; /* Faktor für Bauernverbrauch */ + int index; + int recruitcost; + int maintenance; + int splitsize; + int weight; + int capacity; + float speed; + float aggression; /* chance that a monster will attack */ + int hitpoints; + const char *def_damage; + char armor; + int at_default; /* Angriffsskill Unbewaffnet (default: -2)*/ + int df_default; /* Verteidigungsskill Unbewaffnet (default: -2)*/ + int at_bonus; /* Verändert den Angriffsskill (default: 0)*/ + int df_bonus; /* Verändert den Verteidigungskill (default: 0)*/ + const spell * precombatspell; + struct att attack[10]; + char bonus[MAXSKILLS]; + signed char * study_speed; /* study-speed-bonus in points/turn (0=30 Tage) */ + boolean __remove_me_nonplayer; + int flags; + int battle_flags; + int ec_flags; + race_t oldfamiliars[MAXMAGIETYP]; + + const char *(*generate_name) (const struct unit *); + const char *(*describe) (const struct unit *, const struct locale *); + void (*age)(struct unit *u); + boolean (*move_allowed)(const struct region *, const struct region *); + struct item * (*itemdrop)(const struct race *, int size); + void (*init_familiar)(struct unit *); + + const struct race * familiars[MAXMAGIETYP]; + struct attrib * attribs; + struct race * next; +} race; + +typedef struct race_list { + struct race_list * next; + const struct race * data; +} race_list; + +extern void racelist_clear(struct race_list **rl); +extern void racelist_insert(struct race_list **rl, const struct race *r); + +extern struct race_list * get_familiarraces(void); +extern struct race * races; + +extern struct race * rc_find(const char *); +extern const char * rc_name(const struct race *, int); +extern struct race * rc_add(struct race *); +extern struct race * rc_new(const char * zName); +extern int rc_specialdamage(const race *, const race *, const struct weapon_type *); + +/* Flags */ +#define RCF_PLAYERRACE (1<<0) /* can be played by a player. */ +#define RCF_KILLPEASANTS (1<<1) /* Töten Bauern. Dämonen werden nicht über dieses Flag, sondern in randenc() behandelt. */ +#define RCF_SCAREPEASANTS (1<<2) +#define RCF_CANSTEAL (1<<3) +#define RCF_MOVERANDOM (1<<4) +#define RCF_CANNOTMOVE (1<<5) +#define RCF_LEARN (1<<6) /* Lernt automatisch wenn struct faction == 0 */ +#define RCF_FLY (1<<7) /* kann fliegen */ +#define RCF_SWIM (1<<8) /* kann schwimmen */ +#define RCF_WALK (1<<9) /* kann über Land gehen */ +#define RCF_NOLEARN (1<<10) /* kann nicht normal lernen */ +#define RCF_NOTEACH (1<<11) /* kann nicht lehren */ +#define RCF_HORSE (1<<12) /* Einheit ist Pferd, sozusagen */ +#define RCF_DESERT (1<<13) /* 5% Chance, das Einheit desertiert */ +#define RCF_ILLUSIONARY (1<<14) /* (Illusion & Spell) Does not drop items. */ +#define RCF_ABSORBPEASANTS (1<<15) /* Tötet und absorbiert Bauern */ +#define RCF_NOHEAL (1<<16) /* Einheit kann nicht geheilt werden */ +#define RCF_NOWEAPONS (1<<17) /* Einheit kann keine Waffen benutzen */ +#define RCF_SHAPESHIFT (1<<18) /* Kann TARNE RASSE benutzen. */ +#define RCF_SHAPESHIFTANY (1<<19) /* Kann TARNE RASSE "string" benutzen. */ +#define RCF_UNDEAD (1<<20) /* Undead. */ +#define RCF_DRAGON (1<<21) /* Drachenart (für Zauber)*/ +#define RCF_COASTAL (1<<22) /* kann in Landregionen an der Küste sein */ +#define RCF_UNARMEDGUARD (1<<23) /* kann ohne Waffen bewachen */ +#define RCF_CANSAIL (1<<24) /* Einheit darf Schiffe betreten */ +#define RCF_INVISIBLE (1<<25) /* not visible in any report */ +#define RCF_SHIPSPEED (1<<26) /* race gets +1 on shipspeed */ +#define RCF_STONEGOLEM (1<<27) /* race gets stonegolem properties */ +#define RCF_IRONGOLEM (1<<28) /* race gets irongolem properties */ + +/* Economic flags */ +#define GIVEITEM (1<<1) /* gibt Gegenstände weg */ +#define GIVEPERSON (1<<2) /* übergibt Personen */ +#define GIVEUNIT (1<<3) /* Einheiten an andere Partei übergeben */ +#define GETITEM (1<<4) /* nimmt Gegenstände an */ +#define ECF_REC_HORSES (1<<6) /* Rekrutiert aus Pferden */ +#define ECF_REC_ETHEREAL (1<<7) /* Rekrutiert aus dem Nichts */ +#define ECF_REC_UNLIMITED (1<<8) /* Rekrutiert ohne Limit */ + +/* Battle-Flags */ +#define BF_EQUIPMENT (1<<0) /* Kann Ausrüstung benutzen */ +#define BF_NOBLOCK (1<<1) /* Wird in die Rückzugsberechnung nicht einbezogen */ +#define BF_RES_PIERCE (1<<2) /* Halber Schaden durch PIERCE */ +#define BF_RES_CUT (1<<3) /* Halber Schaden durch CUT */ +#define BF_RES_BASH (1<<4) /* Halber Schaden durch BASH */ +#define BF_INV_NONMAGIC (1<<5) /* Immun gegen nichtmagischen Schaden */ +#define BF_CANATTACK (1<<6) /* Kann keine ATTACKIERE Befehle ausfuehren */ + +extern int unit_old_max_hp(struct unit * u); +extern const char * racename(const struct locale *lang, const struct unit *u, const race * rc); + +#define omniscient(f) (((f)->race)==new_race[RC_ILLUSION] || ((f)->race)==new_race[RC_TEMPLATE]) + +#define playerrace(rc) (fval((rc), RCF_PLAYERRACE)) +#define dragonrace(rc) ((rc) == new_race[RC_FIREDRAGON] || (rc) == new_race[RC_DRAGON] || (rc) == new_race[RC_WYRM] || (rc) == new_race[RC_BIRTHDAYDRAGON]) +#define humanoidrace(rc) (fval((rc), RCF_UNDEAD) || (rc)==new_race[RC_DRACOID] || playerrace(rc)) +#define illusionaryrace(rc) (fval(rc, RCF_ILLUSIONARY)) + +extern boolean allowed_dragon(const struct region * src, const struct region * target); + +extern boolean r_insectstalled(const struct region *r); + +extern void add_raceprefix(const char *); +extern char ** race_prefixes; + +extern void write_race_reference(const struct race * rc, struct storage * store); +extern variant read_race_reference(struct storage * store); + +extern const char * raceprefix(const struct unit *u); + +extern void give_starting_equipment(const struct equipment * eq, struct unit *u); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/region.c b/src/kernel/region.c new file mode 100644 index 000000000..7935691f5 --- /dev/null +++ b/src/kernel/region.c @@ -0,0 +1,1608 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "region.h" + +/* kernel includes */ +#include "alliance.h" +#include "building.h" +#include "connection.h" +#include "curse.h" +#include "equipment.h" +#include "faction.h" +#include "item.h" +#include "message.h" +#include "plane.h" +#include "region.h" +#include "resources.h" +#include "save.h" +#include "ship.h" +#include "terrain.h" +#include "terrainid.h" +#include "unit.h" +#include "version.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +extern int dice_rand(const char *s); + +region *regions; + +int +get_maxluxuries() +{ + static int maxluxuries = -1; + if (maxluxuries==-1) { + const luxury_type * ltype; + maxluxuries = 0; + for (ltype = luxurytypes;ltype;ltype=ltype->next) ++maxluxuries; + } + return maxluxuries; +} +const int delta_x[MAXDIRECTIONS] = +{ + -1, 0, 1, 1, 0, -1 +}; + +const int delta_y[MAXDIRECTIONS] = +{ + 1, 1, 0, -1, -1, 0 +}; + +static const direction_t back[MAXDIRECTIONS] = +{ + D_SOUTHEAST, + D_SOUTHWEST, + D_WEST, + D_NORTHWEST, + D_NORTHEAST, + D_EAST, +}; + +direction_t +dir_invert(direction_t dir) +{ + switch (dir) { + case D_PAUSE: + case D_SPECIAL: + return dir; + break; + default: + if (dir>=0 && dirlocale : 0; + if (r==NULL) { + strcpy(buf, "(null)"); + } else { + plane * pl = rplane(r); + int nx = r->x, ny = r->y; + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl, r); + snprintf(buf, size, "%s (%d,%d)", rname(r, lang), nx, ny); + } + buf[size-1] = 0; + return buffer; +} + +const char * +regionname(const region * r, const faction * f) +{ + static char buf[NAMESIZE]; + return write_regionname(r, f, buf, sizeof(buf)); +} + +int +deathcount(const region * r) +{ + attrib * a = a_find(r->attribs, &at_deathcount); + if (!a) return 0; + return a->data.i; +} + +int +chaoscount(const region * r) +{ + attrib * a = a_find(r->attribs, &at_chaoscount); + if (!a) return 0; + return a->data.i; +} + +void +deathcounts (region * r, int fallen) +{ + attrib * a; + static const curse_type * ctype = NULL; + + if (fallen==0) return; + if (!ctype) ctype = ct_find("holyground"); + if (ctype && curse_active(get_curse(r->attribs, ctype))) return; + + a = a_find(r->attribs, &at_deathcount); + if (!a) a = a_add(&r->attribs, a_new(&at_deathcount)); + a->data.i += fallen; + + if (a->data.i<=0) a_remove(&r->attribs, a); +} + +void +chaoscounts(region * r, int fallen) +{ + attrib * a; + + if (fallen==0) return; + + a = a_find(r->attribs, &at_chaoscount); + if (!a) a = a_add(&r->attribs, a_new(&at_chaoscount)); + a->data.i += fallen; + + if (a->data.i<=0) a_remove(&r->attribs, a); +} + + + +/********************/ +/* at_direction */ +/********************/ +static void +a_initdirection(attrib *a) +{ + a->data.v = calloc(1, sizeof(spec_direction)); +} + +static void +a_freedirection(attrib *a) +{ + free(a->data.v); +} + +static int +a_agedirection(attrib *a) +{ + spec_direction *d = (spec_direction *)(a->data.v); + --d->duration; + return (d->duration>0)?AT_AGE_KEEP:AT_AGE_REMOVE; +} + +typedef struct dir_lookup { + char * name; + const char * oldname; + struct dir_lookup * next; +} dir_lookup; + +static dir_lookup * dir_name_lookup; + +void +register_special_direction(const char * name) +{ + struct locale * lang; + char * str = strdup(name); + + for (lang=locales;lang;lang=nextlocale(lang)) { + tnode * tokens = get_translations(lang, UT_SPECDIR); + const char * token = LOC(lang, name); + + if (token) { + variant var; + + var.v = str; + addtoken(tokens, token, var); + + if (lang==default_locale) { + dir_lookup * dl = malloc(sizeof(dir_lookup)); + dl->name = str; + dl->oldname = token; + dl->next = dir_name_lookup; + dir_name_lookup = dl; + } + } else { + log_error(("no translation for spec_direction '%s' in locale '%s'\n", + name, locale_name(lang))); + } + } +} + +static int +a_readdirection(attrib *a, void * owner, struct storage * store) +{ + spec_direction *d = (spec_direction *)(a->data.v); + + d->x = (short)store->r_int(store); + d->y = (short)store->r_int(store); + d->duration = store->r_int(store); + if (store->versionr_tok_buf(store, NULL, 0); + store->r_tok_buf(store, lbuf, sizeof(lbuf)); + + cstring_i(lbuf); + for (;dl;dl=dl->next) { + if (strcmp(lbuf, dl->oldname)==0) { + d->keyword=strdup(dl->name); + sprintf(lbuf, "%s_desc", d->keyword); + d->desc=strdup(dl->name); + break; + } + } + if (dl==NULL) { + log_error(("unknown spec_direction '%s'\n", lbuf)); + assert(!"not implemented"); + } + } + else { + d->desc = store->r_tok(store); + d->keyword = store->r_tok(store); + } + d->active = true; + return AT_READ_OK; +} + +static void +a_writedirection(const attrib * a, const void * owner, struct storage * store) +{ + spec_direction *d = (spec_direction *)(a->data.v); + + store->w_int(store, d->x); + store->w_int(store, d->y); + store->w_int(store, d->duration); + store->w_tok(store, d->desc); + store->w_tok(store, d->keyword); +} + +attrib_type at_direction = { + "direction", + a_initdirection, + a_freedirection, + a_agedirection, + a_writedirection, + a_readdirection +}; + +region * +find_special_direction(const region *r, const char *token, const struct locale * lang) +{ + attrib *a; + spec_direction *d; + + if (strlen(token)==0) return NULL; + for (a = a_find(r->attribs, &at_direction);a && a->type==&at_direction;a=a->next) { + d = (spec_direction *)(a->data.v); + + if (d->active) { + tnode * tokens = get_translations(lang, UT_SPECDIR); + variant var; + if (findtoken(tokens, token, &var)==E_TOK_SUCCESS) { + if (strcmp((const char *)var.v, d->keyword)==0) { + return findregion(d->x, d->y); + } + } + } + } + + return NULL; +} + +attrib * +create_special_direction(region *r, region * rt, int duration, + const char *desc, const char *keyword) + +{ + attrib *a = a_add(&r->attribs, a_new(&at_direction)); + spec_direction *d = (spec_direction *)(a->data.v); + + d->active = false; + d->x = rt->x; + d->y = rt->y; + d->duration = duration; + d->desc = strdup(desc); + d->keyword = strdup(keyword); + + return a; +} + +/* Moveblock wird zur Zeit nicht über Attribute, sondern ein Bitfeld + r->moveblock gemacht. Sollte umgestellt werden, wenn kompliziertere + Dinge gefragt werden. */ + +/********************/ +/* at_moveblock */ +/********************/ +void +a_initmoveblock(attrib *a) +{ + a->data.v = calloc(1, sizeof(moveblock)); +} + +int +a_readmoveblock(attrib *a, void * owner, struct storage * store) +{ + moveblock *m = (moveblock *)(a->data.v); + int i; + + i = store->r_int(store); + m->dir = (direction_t)i; + return AT_READ_OK; +} + +void +a_writemoveblock(const attrib * a, const void * owner, struct storage * store) +{ + moveblock *m = (moveblock *)(a->data.v); + store->w_int(store, (int)m->dir); +} + +attrib_type at_moveblock = { + "moveblock", a_initmoveblock, NULL, NULL, a_writemoveblock, a_readmoveblock +}; + +#define coor_hashkey(x, y) (unsigned int)((x<<16) + y) +#define RMAXHASH MAXREGIONS +static region * regionhash[RMAXHASH]; +static int dummy_data; +static region * dummy_ptr = (region*)&dummy_data; /* a funny hack */ + +typedef struct uidhashentry { + unsigned int uid; + region * r; +} uidhashentry; +static uidhashentry uidhash[MAXREGIONS]; + +struct region * +findregionbyid(unsigned int uid) +{ + int key = uid % MAXREGIONS; + while (uidhash[key].uid!=0 && uidhash[key].uid!=uid) ++key; + return uidhash[key].r; +} + +#define DELMARKER dummy_ptr + +static void +unhash_uid(region * r) +{ + int key = r->uid % MAXREGIONS; + assert(r->uid); + while (uidhash[key].uid!=0 && uidhash[key].uid!=r->uid) ++key; + assert(uidhash[key].r==r); + uidhash[key].r = NULL; +} + +static void +hash_uid(region * r) +{ + unsigned int uid = r->uid; + for (;;) { + if (uid!=0) { + int key = uid % MAXREGIONS; + while (uidhash[key].uid!=0 && uidhash[key].uid!=uid) ++key; + if (uidhash[key].uid==0) { + uidhash[key].uid = uid; + uidhash[key].r = r; + break; + } + assert(uidhash[key].r!=r || !"duplicate registration"); + } + r->uid = uid = rng_int(); + } +} + +#define HASH_STATISTICS 1 +#if HASH_STATISTICS +static int hash_requests; +static int hash_misses; +#endif + +boolean pnormalize(int * x, int * y, const plane * pl) +{ + if (pl) { + if (x) { + int width = pl->maxx - pl->minx + 1; + int nx = *x - pl->minx; + nx = (nx>0)?nx:(width-(-nx)%width); + *x = nx % width+ pl->minx; + } + if (y) { + int height = pl->maxy - pl->miny + 1; + int ny = *y - pl->miny; + ny = (ny>0)?ny:(height-(-ny)%height); + *y = ny % height + pl->miny; + } + } + return false; /* TBD */ +} + +static region * +rfindhash(int x, int y) +{ + unsigned int rid; + + rid = coor_hashkey(x, y); +#if HASH_STATISTICS + ++hash_requests; +#endif + if (rid>=0) { + int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); + while (regionhash[key]!=NULL && (regionhash[key]==DELMARKER || regionhash[key]->x!=x || regionhash[key]->y!=y)) { + key = (key + gk) % RMAXHASH; +#if HASH_STATISTICS + ++hash_misses; +#endif + } + return regionhash[key]; + } + return NULL; +} + +void +rhash(region * r) +{ + unsigned int rid = coor_hashkey(r->x, r->y); + int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); + while (regionhash[key]!=NULL && regionhash[key]!=DELMARKER && regionhash[key]!=r) { + key = (key + gk) % RMAXHASH; + } + assert(regionhash[key]!=r || !"trying to add the same region twice"); + regionhash[key] = r; +} + +void +runhash(region * r) +{ + unsigned int rid = coor_hashkey(r->x, r->y); + int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); + +#ifdef FAST_CONNECT + int d, di; + for (d=0,di=MAXDIRECTIONS/2;d!=MAXDIRECTIONS;++d,++di) { + region * rc = r->connect[d]; + if (rc!=NULL) { + if (di>=MAXDIRECTIONS) di-=MAXDIRECTIONS; + rc->connect[di] = NULL; + r->connect[d] = NULL; + } + } +#endif + while (regionhash[key]!=NULL && regionhash[key]!=r) { + key = (key + gk) % RMAXHASH; + } + assert(regionhash[key]==r || !"trying to remove a unit that is not hashed"); + regionhash[key] = DELMARKER; +} + +region * +r_connect(const region * r, direction_t dir) +{ + region * result; + int x, y; +#ifdef FAST_CONNECT + region * rmodify = (region*)r; + assert (dir>=0 && dirconnect[dir]) return r->connect[dir]; +#endif + assert(dirx + delta_x[dir]; + y = r->y + delta_y[dir]; + pnormalize(&x, &y, rplane(r)); + result = rfindhash(x, y); +#ifdef FAST_CONNECT + if (result) { + rmodify->connect[dir] = result; + result->connect[back[dir]] = rmodify; + } +#endif + return result; +} + +region * +findregion(int x, int y) +{ + return rfindhash(x, y); +} + +/* Contributed by Hubert Mackenberg. Thanks. + * x und y Abstand zwischen x1 und x2 berechnen + */ +static int +koor_distance_orig(int x1, int y1, int x2, int y2) +{ + int dx = x1 - x2; + int dy = y1 - y2; + + /* Bei negativem dy am Ursprung spiegeln, das veraendert + * den Abstand nicht + */ + if ( dy < 0 ) { + dy = -dy; + dx = -dx; + } + + /* + * dy ist jetzt >=0, fuer dx sind 3 Faelle zu untescheiden + */ + if ( dx >= 0 ) { + int result = dx + dy; + return result; + } + else if (-dx >= dy) { + int result = -dx; + return result; + } + else { + return dy; + } +} + +static int +koor_distance_wrap_xy(int x1, int y1, int x2, int y2, int width, int height) +{ + int dx = x1 - x2; + int dy = y1 - y2; + int result, dist; + int mindist = MIN(width, height) >> 1; + + /* Bei negativem dy am Ursprung spiegeln, das veraendert + * den Abstand nicht + */ + if ( dy < 0 ) { + dy = -dy; + dx = -dx; + } + if (dx<0) { + dx = width + dx; + } + /* dx,dy is now pointing northeast */ + result = dx + dy; + if (result<=mindist) return result; + + dist = (width-dx) + (height-dy); /* southwest */ + if (dist>=0 && dist=0 && dist=0 && distx, r1->y, r2->x, r2->y); +} + +static direction_t +koor_reldirection(int ax, int ay, int bx, int by, const struct plane * pl) +{ + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + int x = ax + delta_x[dir]; + int y = ay + delta_y[dir]; + pnormalize(&x, &y, pl); + if (bx == x && by == y) return dir; + } + return NODIRECTION; +} + +spec_direction * +special_direction(const region * from, const region * to) +{ + const attrib *a = a_findc(from->attribs, &at_direction); + + while (a!=NULL && a->type==&at_direction) { + spec_direction * sd = (spec_direction *)a->data.v; + if (sd->x==to->x && sd->y==to->y) return sd; + a = a->next; + } + return NULL; +} + +direction_t +reldirection(const region * from, const region * to) +{ + plane * pl = rplane(from); + if (pl == rplane(to)) { + direction_t dir = koor_reldirection(from->x, from->y, to->x, to->y, pl); + + if (dir==NODIRECTION) { + spec_direction *sd = special_direction(from, to); + if (sd!=NULL && sd->active) return D_SPECIAL; + } + return dir; + } + return NODIRECTION; +} + +void +free_regionlist(region_list *rl) +{ + while (rl) { + region_list * rl2 = rl->next; + free(rl); + rl = rl2; + } +} + +void +add_regionlist(region_list **rl, region *r) +{ + region_list *rl2 = (region_list*)malloc(sizeof(region_list)); + + rl2->data = r; + rl2->next = *rl; + + *rl = rl2; +} + +/********************/ +/* at_horseluck */ +/********************/ +attrib_type at_horseluck = { + "horseluck", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ, + ATF_UNIQUE +}; + + +/**********************/ +/* at_peasantluck */ +/**********************/ +attrib_type at_peasantluck = { + "peasantluck", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ, + ATF_UNIQUE +}; + +/*********************/ +/* at_chaoscount */ +/*********************/ +attrib_type at_chaoscount = { + "chaoscount", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + a_writeint, + a_readint, + ATF_UNIQUE +}; + +/*********************/ +/* at_deathcount */ +/*********************/ +attrib_type at_deathcount = { + "deathcount", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + a_writeint, + a_readint, + ATF_UNIQUE +}; + +/*********************/ +/* at_woodcount */ +/*********************/ +attrib_type at_woodcount = { + "woodcount", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + a_readint, + ATF_UNIQUE +}; + +/*********************/ +/* at_travelunit */ +/*********************/ +attrib_type at_travelunit = { + "travelunit", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +void +rsetroad(region * r, direction_t d, short val) +{ + connection * b; + region * r2 = rconnect(r, d); + + if (!r2) return; + b = get_borders(r, r2); + while (b && b->type!=&bt_road) b = b->next; + if (!b) b = new_border(&bt_road, r, r2); + if (r==b->from) b->data.sa[0] = val; + else b->data.sa[1] = val; +} + +short +rroad(const region * r, direction_t d) +{ + int rval; + connection * b; + region * r2 = rconnect(r, d); + + if (!r2) return 0; + b = get_borders(r, r2); + while (b && b->type!=&bt_road) b = b->next; + if (!b) return 0; + rval = b->data.i; + if (r==b->from) return b->data.sa[0]; + return b->data.sa[1]; +} + +boolean +r_isforest(const region * r) +{ + if (fval(r->terrain, FOREST_REGION)) { + /* needs to be covered with at leas 48% trees */ + int mincover = (int)(r->terrain->size * 0.48); + int trees = rtrees(r, 2) + rtrees(r, 1); + return (trees*TREESIZE >= mincover); + } + return false; +} + +int +is_coastregion(region *r) +{ + direction_t i; + int res = 0; + + for(i=0;iterrain, SEA_REGION)) res++; + } + return res; +} + +int +rpeasants(const region * r) +{ + return ((r)->land?(r)->land->peasants:0); +} + +void +rsetpeasants(region * r, int value) +{ + ((r)->land?((r)->land->peasants=(value)):(assert((value)>=0), (value)),0); +} + +int +rmoney(const region * r) +{ + return ((r)->land?(r)->land->money:0); +} + +void +rsethorses(const region *r, int value) +{ + assert(value >= 0); + if(r->land) + r->land->horses = value; +} + +int +rhorses(const region *r) +{ + return r->land?r->land->horses:0; +} + +void +rsetmoney(region * r, int value) +{ + ((r)->land?((r)->land->money=(value)):(assert((value)>=0), (value)),0); +} + +void +r_setdemand(region * r, const luxury_type * ltype, int value) +{ + struct demand * d, ** dp = &r->land->demands; + + if (ltype==NULL) return; + + while (*dp && (*dp)->type != ltype) dp = &(*dp)->next; + d = *dp; + if (!d) { + d = *dp = malloc(sizeof(struct demand)); + d->next = NULL; + d->type = ltype; + } + d->value = value; +} + +const item_type * +r_luxury(region * r) +{ + struct demand * dmd; + if (r->land) { + if (!r->land->demands) { + fix_demand(r); + } + for (dmd=r->land->demands;dmd;dmd=dmd->next) { + if (dmd->value==0) return dmd->type->itype; + } + } + return NULL; +} + +int +r_demand(const region * r, const luxury_type * ltype) +{ + struct demand * d = r->land->demands; + while (d && d->type != ltype) d = d->next; + if (!d) return -1; + return d->value; +} + +const char * +rname(const region * r, const struct locale * lang) +{ + if (r->land) { + return r->land->name; + } + return LOC(lang, terrain_name(r)); +} + +int +rtrees(const region *r, int ageclass) +{ + return ((r)->land?(r)->land->trees[ageclass]:0); +} + +int +rsettrees(const region *r, int ageclass, int value) +{ + if (!r->land) assert(value==0); + else { + assert(value>=0); + return r->land->trees[ageclass]=value; + } + return 0; +} + +static region *last; + +static unsigned int max_index = 0; + +region * +new_region(int x, int y, struct plane * pl, unsigned int uid) +{ + region *r; + + pnormalize(&x, &y, pl); + r = rfindhash(x, y); + + if (r) { + log_error(("duplicate region discovered: %s(%d,%d)\n", regionname(r, NULL), x, y)); + if (r->units) + log_error(("duplicate region contains units\n")); + return r; + } + r = calloc(1, sizeof(region)); + r->x = x; + r->y = y; + r->uid = uid; + r->age = 1; + r->_plane = pl; + rhash(r); + hash_uid(r); + if (last) + addlist(&last, r); + else + addlist(®ions, r); + last = r; + assert(r->next==NULL); + r->index = ++max_index; + return r; +} + +static region * deleted_regions; + +void +remove_region(region ** rlist, region * r) +{ + + while (r->units) { + unit * u = r->units; + i_freeall(&u->items); + remove_unit(&r->units, u); + } + + runhash(r); + unhash_uid(r); + while (*rlist && *rlist!=r) rlist=&(*rlist)->next; + assert(*rlist==r); + *rlist = r->next; + r->next = deleted_regions; + deleted_regions = r; +} + +static void +freeland(land_region * lr) +{ + while (lr->demands) { + struct demand * d = lr->demands; + lr->demands = d->next; + free(d); + } + if (lr->name) free(lr->name); + free(lr); +} + +void +region_setresource(region * r, const resource_type * rtype, int value) +{ + rawmaterial * rm = r->resources; + while (rm) { + if (rm->type->rtype==rtype) { + rm->amount = value; + break; + } + rm=rm->next; + } + if (!rm) { + if (rtype==rt_find("money")) rsetmoney(r, value); + else if (rtype==rt_find("peasant")) rsetpeasants(r, value); + else if (rtype==rt_find("horse")) rsethorses(r, value); + } +} + +int +region_getresource(const region * r, const resource_type * rtype) +{ + const rawmaterial * rm; + for (rm=r->resources;rm;rm=rm->next) { + if (rm->type->rtype==rtype) { + return rm->amount; + } + } + if (rtype==rt_find("money")) return rmoney(r); + if (rtype==rt_find("horse")) return rhorses(r); + if (rtype==rt_find("peasant")) return rpeasants(r); + return 0; +} + +void +free_region(region * r) +{ + if (last == r) last = NULL; + free(r->display); + if (r->land) freeland(r->land); + + if (r->msgs) { + free_messagelist(r->msgs); + r->msgs = 0; + } + + while (r->individual_messages) { + struct individual_message * msg = r->individual_messages; + r->individual_messages = msg->next; + if (msg->msgs) free_messagelist(msg->msgs); + free(msg); + } + + while (r->attribs) a_remove (&r->attribs, r->attribs); + while (r->resources) { + rawmaterial * res = r->resources; + r->resources = res->next; + free(res); + } + + while (r->donations) { + donation * don = r->donations; + r->donations = don->next; + free(don); + } + + while (r->units) { + unit * u = r->units; + r->units = u->next; + uunhash(u); + free_unit(u); + free(u); + } + + while (r->buildings) { + building * b = r->buildings; + assert(b->region==r); + r->buildings = b->next; + bunhash(b); /* must be done here, because remove_building does it, and wasn't called */ + free_building(b); + } + + while (r->ships) { + ship * s = r->ships; + assert(s->region==r); + r->ships = s->next; + sunhash(s); + free_ship(s); + } + + free(r); +} + +void +free_regions(void) +{ + memset(uidhash, 0, sizeof(uidhash)); + while (deleted_regions) { + region * r = deleted_regions; + deleted_regions = r->next; + free_region(r); + } + while (regions) { + region * r = regions; + regions = r->next; + runhash(r); + free_region(r); + } + max_index = 0; + last = NULL; +} + +/** creates a name for a region + * TODO: Make vowels XML-configurable and allow non-ascii characters again. + * - that will probably require a wchar_t * string to pick from. + */ +static char * +makename(void) +{ + int s, v, k, e, p = 0, x = 0; + size_t nk, ne, nv, ns; + static char name[16]; + const char *kons = "bcdfghklmnprstvwz", + *start = "bcdgtskpvfr", + *end = "nlrdst", + *vowels = "aaaaaaaaaaaeeeeeeeeeeeeiiiiiiiiiiioooooooooooouuuuuuuuuuyy"; + + /* const char * vowels_latin1 = "aaaaaaaaaàâeeeeeeeeeéèêiiiiiiiiiíîoooooooooóòôuuuuuuuuuúyy"; */ + + nk = strlen(kons); + ne = strlen(end); + nv = strlen(vowels); + ns = strlen(start); + + for (s = rng_int() % 3 + 2; s > 0; s--) { + if (x > 0) { + k = rng_int() % (int)nk; + name[p] = kons[k]; + p++; + } else { + k = rng_int() % (int)ns; + name[p] = start[k]; + p++; + } + v = rng_int() % (int)nv; + name[p] = vowels[v]; + p++; + if (rng_int() % 3 == 2 || s == 1) { + e = rng_int() % (int)ne; + name[p] = end[e]; + p++; + x = 1; + } else + x = 0; + } + name[p] = '\0'; + name[0] = (char) toupper(name[0]); + return name; +} + +void +setluxuries(region * r, const luxury_type * sale) +{ + const luxury_type * ltype; + + assert(r->land); + + if(r->land->demands) freelist(r->land->demands); + + for (ltype=luxurytypes; ltype; ltype=ltype->next) { + struct demand * dmd = malloc(sizeof(struct demand)); + dmd->type = ltype; + if (ltype!=sale) dmd->value = 1 + rng_int() % 5; + else dmd->value = 0; + dmd->next = r->land->demands; + r->land->demands = dmd; + } +} + +void +terraform_region(region * r, const terrain_type * terrain) +{ + /* Resourcen, die nicht mehr vorkommen können, löschen */ + const terrain_type * oldterrain = r->terrain; + rawmaterial **lrm = &r->resources; + + assert(terrain); + + while (*lrm) { + rawmaterial *rm = *lrm; + const resource_type * rtype = NULL; + + if (terrain->production!=NULL) { + int i; + for (i=0;terrain->production[i].type;++i) { + if (rm->type->rtype == terrain->production[i].type) { + rtype = rm->type->rtype; + break; + } + } + } + if (rtype==NULL) { + *lrm = rm->next; + free(rm); + } else { + lrm = &rm->next; + } + } + + r->terrain = terrain; + terraform_resources(r); + + if (!fval(terrain, LAND_REGION)) { + region_setinfo(r, NULL); + if (r->land!=NULL) { + i_freeall(&r->land->items); + freeland(r->land); + r->land = NULL; + } + rsettrees(r, 0, 0); + rsettrees(r, 1, 0); + rsettrees(r, 2, 0); + rsethorses(r, 0); + rsetpeasants(r, 0); + rsetmoney(r, 0); + freset(r, RF_ENCOUNTER); + freset(r, RF_MALLORN); + /* Beschreibung und Namen löschen */ + return; + } + + if (r->land) { + i_freeall(&r->land->items); + } else { + static struct surround { + struct surround * next; + const luxury_type * type; + int value; + } *trash =NULL, *nb = NULL; + const luxury_type * ltype = NULL; + direction_t d; + int mnr = 0; + + r->land = calloc(1, sizeof(land_region)); + r->land->ownership = NULL; + region_set_morale(r, MORALE_DEFAULT, -1); + region_setname(r, makename()); + for (d=0;d!=MAXDIRECTIONS;++d) { + region * nr = rconnect(r, d); + if (nr && nr->land) { + struct demand * sale = r->land->demands; + while (sale && sale->value!=0) sale=sale->next; + if (sale) { + struct surround * sr = nb; + while (sr && sr->type!=sale->type) sr=sr->next; + if (!sr) { + if (trash) { + sr = trash; + trash = trash->next; + } else { + sr = calloc(1, sizeof(struct surround)); + } + sr->next = nb; + sr->type = sale->type; + sr->value = 1; + nb = sr; + } else sr->value++; + ++mnr; + } + } + } + if (!nb) { + int i = get_maxluxuries(); + if (i>0) { + i = rng_int() % i; + ltype = luxurytypes; + while (i--) ltype=ltype->next; + } + } else { + int i = rng_int() % mnr; + struct surround * srd = nb; + while (i>srd->value) { + i-=srd->value; + srd=srd->next; + } + if (srd->type) setluxuries(r, srd->type); + while (srd->next!=NULL) srd=srd->next; + srd->next=trash; + trash = nb; + nb = NULL; + } + } + + if (fval(terrain, LAND_REGION)) { + const item_type * itype = NULL; + char equip_hash[64]; + + /* TODO: put the equipment in struct terrain, faster */ + sprintf(equip_hash, "terrain_%s", terrain->_name); + equip_items(&r->land->items, get_equipment(equip_hash)); + + if (r->terrain->herbs) { + int len=0; + while (r->terrain->herbs[len]) ++len; + if (len) itype = r->terrain->herbs[rng_int()%len]; + } + if (itype!=NULL) { + rsetherbtype(r, itype); + rsetherbs(r, (short)(50+rng_int()%31)); + } + else { + rsetherbtype(r, NULL); + } + if (oldterrain==NULL || !fval(oldterrain, LAND_REGION)) { + if (rng_int() % 100 < 3) fset(r, RF_MALLORN); + else freset(r, RF_MALLORN); + if (rng_int() % 100 < ENCCHANCE) { + fset(r, RF_ENCOUNTER); + } + } + } + + if (oldterrain==NULL || terrain->size!=oldterrain->size) { + if (terrain==newterrain(T_PLAIN)) { + rsethorses(r, rng_int() % (terrain->size / 50)); + if(rng_int()%100 < 40) { + rsettrees(r, 2, terrain->size * (30+rng_int()%40)/1000); + } + } else if (chance(0.2)) { + rsettrees(r, 2, terrain->size * (30 + rng_int() % 40) / 1000); + } else { + rsettrees(r, 2, 0); + } + rsettrees(r, 1, rtrees(r, 2)/4); + rsettrees(r, 0, rtrees(r, 2)/8); + + if (!fval(r, RF_CHAOTIC)) { + int peasants; + peasants = (maxworkingpeasants(r) * (20+dice_rand("6d10")))/100; + rsetpeasants(r, MAX(100, peasants)); + rsetmoney(r, rpeasants(r) * ((wage(r, NULL, NULL, INT_MAX)+1) + rng_int() % 5)); + } + } +} + +/** ENNO: + * ich denke, das das hier nicht sein sollte. + * statt dessen sollte ein attribut an der region sein, das das erledigt, + * egal ob durch den spell oder anderes angelegt. + **/ +#include "curse.h" +int +production(const region *r) +{ + /* muß rterrain(r) sein, nicht rterrain() wegen rekursion */ + int p = r->terrain->size / MAXPEASANTS_PER_AREA; + if (curse_active(get_curse(r->attribs, ct_find("drought")))) p /= 2; + + return p; +} + +int +resolve_region_coor(variant id, void * address) { + region * r = findregion(id.sa[0], id.sa[1]); + if (r) { + *(region**)address = r; + return 0; + } + *(region**)address = NULL; + return -1; +} + +int +resolve_region_id(variant id, void * address) +{ + region * r = NULL; + if (id.i!=0) { + r = findregionbyid((unsigned int)id.i); + if (r==NULL) { + *(region**)address = NULL; + return -1; + } + } + *(region**)address = r; + return 0; +} + +variant +read_region_reference(struct storage * store) +{ + variant result; + if (store->versionr_int(store); + result.sa[1] = (short)store->r_int(store); + } else { + result.i = store->r_int(store); + } + return result; +} + +void +write_region_reference(const region * r, struct storage * store) +{ + if (r) { + store->w_int(store, r->uid); + } else { + store->w_int(store, 0); + } +} + +struct message_list * +r_getmessages(const struct region * r, const struct faction * viewer) +{ + struct individual_message * imsg = r->individual_messages; + while (imsg && (imsg)->viewer!=viewer) imsg = imsg->next; + if (imsg) return imsg->msgs; + return NULL; +} + +struct message * +r_addmessage(struct region * r, const struct faction * viewer, struct message * msg) +{ + assert(r); + if (viewer) { + struct individual_message * imsg; + imsg = r->individual_messages; + while (imsg && imsg->viewer!=viewer) imsg = imsg->next; + if (imsg==NULL) { + imsg = malloc(sizeof(struct individual_message)); + imsg->next = r->individual_messages; + imsg->msgs = NULL; + r->individual_messages = imsg; + imsg->viewer = viewer; + } + return add_message(&imsg->msgs, msg); + } + return add_message(&r->msgs, msg); +} + +struct faction * +region_get_owner(const struct region * r) +{ + assert(rule_region_owners()); + if (r->land && r->land->ownership) { + return r->land->ownership->owner; + } + return NULL; +} + +struct alliance * +region_get_alliance(const struct region * r) +{ + assert(rule_region_owners()); + if (r->land && r->land->ownership) { + region_owner * own = r->land->ownership; + return own->owner?own->owner->alliance:own->alliance; + } + return NULL; +} + +void +region_set_owner(struct region * r, struct faction * owner, int turn) +{ + assert(rule_region_owners()); + if (r->land) { + if (!r->land->ownership) { + r->land->ownership = malloc(sizeof(region_owner)); + assert(region_get_morale(r)==MORALE_DEFAULT); + r->land->ownership->owner = NULL; + r->land->ownership->alliance = NULL; + r->land->ownership->flags = 0; + } + r->land->ownership->since_turn = turn; + r->land->ownership->morale_turn = turn; + assert(r->land->ownership->owner != owner); + r->land->ownership->owner = owner; + if (owner) { + r->land->ownership->alliance = owner->alliance; + } + } +} + + +faction * update_owners(region * r) +{ + faction * f = NULL; + assert(rule_region_owners()); + if (r->land) { + building * bowner = largestbuilding(r, &cmp_current_owner, false); + building * blargest = largestbuilding(r, &cmp_taxes, false); + if (blargest) { + if (!bowner || bowner->sizesize) { + /* region owners update? */ + unit * u = building_owner(blargest); + f = region_get_owner(r); + if (u==NULL) { + if (f) { + region_set_owner(r, NULL, turn); + r->land->ownership->flags |= OWNER_MOURNING; + f = NULL; + } + } else if (u->faction!=f) { + if (!r->land->ownership) { + /* there has never been a prior owner */ + region_set_morale(r, MORALE_DEFAULT, turn); + } else { + alliance * al = region_get_alliance(r); + if (al && u->faction->alliance==al) { + int morale = MAX(0, r->land->morale-MORALE_TRANSFER); + region_set_morale(r, morale, turn); + } else { + region_set_morale(r, MORALE_TAKEOVER, turn); + if (f) { + r->land->ownership->flags |= OWNER_MOURNING; + } + } + } + region_set_owner(r, u->faction, turn); + f = u->faction; + } + } + } else if (r->land->ownership && r->land->ownership->owner) { + r->land->ownership->flags |= OWNER_MOURNING; + region_set_owner(r, NULL, turn); + f = NULL; + } + } + return f; +} + +void +region_setinfo(struct region * r, const char * info) +{ + free(r->display); + r->display = info?strdup(info):0; +} + +const char * +region_getinfo(const region * r) { + return r->display?r->display:""; +} + +void +region_setname(struct region * r, const char * name) +{ + if (r->land) { + free(r->land->name); + r->land->name = name?strdup(name):0; + } +} + +const char * +region_getname(const region * r) { + if (r->land && r->land->name) { + return r->land->name; + } + return ""; +} + +int region_get_morale(const region * r) +{ + if (r->land) { + assert(r->land->morale>=0 && r->land->morale<=MORALE_MAX); + return r->land->morale; + } + return -1; +} + +void region_set_morale(region * r, int morale, int turn) +{ + if (r->land) { + r->land->morale = (short)morale; + if (turn>=0 && r->land->ownership) { + r->land->ownership->morale_turn = turn; + } + assert(r->land->morale>=0 && r->land->morale<=MORALE_MAX); + } +} + +void get_neighbours(const region * r, region ** list) +{ + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + list[dir] = rconnect(r, dir); + } +} + +int owner_change(const region * r) +{ + if (r->land && r->land->ownership) { + return r->land->ownership->since_turn; + } + return -1; +} + +boolean is_mourning(const region * r, int in_turn) +{ + int change = owner_change(r); + return (change==in_turn-1 && (r->land->ownership->flags&OWNER_MOURNING)); +} diff --git a/src/kernel/region.h b/src/kernel/region.h new file mode 100644 index 000000000..5c226fd2a --- /dev/null +++ b/src/kernel/region.h @@ -0,0 +1,300 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_REGION +#define H_KRNL_REGION +#ifdef __cplusplus +extern "C" { +#endif + +#include "types.h" + +/* FAST_CONNECT: regions are directly connected to neighbours, saves doing + a hash-access each time a neighbour is needed */ +#define FAST_CONNECT + +#define RF_CHAOTIC (1<<0) +#define RF_MALLORN (1<<1) +#define RF_BLOCKED (1<<2) + +#define RF_BLOCK_NORTHWEST (1<<3) +#define RF_BLOCK_NORTHEAST (1<<4) +#define RF_BLOCK_EAST (1<<5) +#define RF_BLOCK_SOUTHEAST (1<<6) +#define RF_BLOCK_SOUTHWEST (1<<7) +#define RF_BLOCK_WEST (1<<8) + +#define RF_ENCOUNTER (1<<9) +#define RF_MIGRATION (1<<10) +#define RF_UNUSED_1 (1<<11) +#define RF_ORCIFIED (1<<12) +#define RF_CURSED (1<<13) + + /* debug flags */ +#define RF_COMBATDEBUG (1<<14) +#define RF_MAPPER_HIGHLIGHT (1<<14) /* only used by mapper, not stored */ +#define RF_LIGHTHOUSE (1<<15) /* this region may contain a lighthouse */ + +#define RF_SELECT (1<<17) +#define RF_MARK (1<<18) + +/* flags that speed up attribute access: */ +#define RF_TRAVELUNIT (1<<19) +#define RF_GUARDED (1<<20) + +#define RF_ALL 0xFFFFFF + +#define RF_SAVEMASK (RF_GUARDED|RF_CHAOTIC|RF_MALLORN|RF_BLOCKED|RF_BLOCK_NORTHWEST|RF_BLOCK_NORTHEAST|RF_BLOCK_EAST|RF_BLOCK_SOUTHEAST|RF_BLOCK_SOUTHWEST|RF_BLOCK_WEST|RF_ENCOUNTER|RF_ORCIFIED) +struct message; +struct message_list; +struct rawmaterial; +struct donation; +struct item; + +#define MORALE_TAX_FACTOR 0.005 /* 0.5% tax per point of morale */ +#define MORALE_MAX 10 /* Maximum morale allowed */ +#define MORALE_DEFAULT 1 /* Morale of peasants when they are conquered for the first time */ +#define MORALE_TAKEOVER 0 /* Morale of peasants after they lose their lord */ +#define MORALE_COOLDOWN 2 /* minimum cooldown before a morale change occurs */ +#define MORALE_AVERAGE 6 /* default average time for morale to change */ +#define MORALE_TRANSFER 2 /* points of morale lost when GIVE COMMAND */ + +#define OWNER_MOURNING 0x01 +typedef struct region_owner { + struct faction * owner; + struct alliance * alliance; + int since_turn; /* turn the region changed owners */ + int morale_turn; /* turn when morale has changed most recently */ + unsigned int flags; +} region_owner; + +typedef struct demand { + struct demand * next; + const struct luxury_type * type; + int value; +} demand; + +typedef struct land_region { + char *name; + /* TODO: demand kann nach Konvertierung entfernt werden. */ + demand * demands; + const struct item_type * herbtype; + short herbs; + short morale; + int trees[3]; /* 0 -> seeds, 1 -> shoots, 2 -> trees */ + int horses; + int peasants; + int newpeasants; + int money; + struct item * items; /* items that can be claimed */ + struct region_owner * ownership; +} land_region; + +typedef struct donation { + struct donation *next; + struct faction *f1, *f2; + int amount; +} donation; + +typedef struct region { + struct region *next; + struct land_region *land; + struct unit *units; + struct ship *ships; + struct building *buildings; + unsigned int index; + /* an ascending number, to improve the speed of determining the interval in + which a faction has its units. See the implementations of firstregion + and lastregion */ + unsigned int uid; /* a unique id */ + int x, y; + struct plane * _plane; /* to access, use rplane(r) */ + char *display; + unsigned int flags; + unsigned short age; + struct message_list *msgs; + struct individual_message { + struct individual_message * next; + const struct faction * viewer; + struct message_list *msgs; + } * individual_messages; + struct attrib *attribs; + struct donation * donations; + const struct terrain_type * terrain; + struct rawmaterial * resources; +#ifdef FAST_CONNECT + struct region * connect[MAXDIRECTIONS]; /* use rconnect(r, dir) to access */ +#endif +} region; + +extern struct region *regions; + +typedef struct region_list { + struct region_list * next; + struct region * data; +} region_list; + +struct message_list * r_getmessages(const struct region * r, const struct faction * viewer); +struct message * r_addmessage(struct region * r, const struct faction * viewer, struct message * msg); + +typedef struct spec_direction { + int x, y; + int duration; + boolean active; + char *desc; + char *keyword; +} spec_direction; + +typedef struct { + direction_t dir; +} moveblock; + +#define reg_hashkey(r) (r->index) + +int distance(const struct region*, const struct region*); +int koor_distance(int ax, int ay, int bx, int by) ; +direction_t reldirection(const struct region * from, const struct region * to); +struct region * findregion(int x, int y); +struct region * findregionbyid(unsigned int uid); + +extern struct attrib_type at_direction; +extern struct attrib_type at_moveblock; +extern struct attrib_type at_peasantluck; +extern struct attrib_type at_horseluck; +extern struct attrib_type at_chaoscount; +extern struct attrib_type at_woodcount; +extern struct attrib_type at_deathcount; +extern struct attrib_type at_travelunit; + +void initrhash(void); +void rhash(struct region * r); +void runhash(struct region * r); + +void free_regionlist(region_list *rl); +void add_regionlist(region_list **rl, struct region *r); + +struct region * find_special_direction(const struct region *r, const char *token, const struct locale * lang); +void register_special_direction(const char * name); +struct spec_direction * special_direction(const region * from, const region * to); +struct attrib *create_special_direction(struct region *r, struct region *rt, + int duration, const char *desc, + const char *keyword); + +int deathcount(const struct region * r); +int chaoscount(const struct region * r); + +void deathcounts(struct region * r, int delta); +void chaoscounts(struct region * r, int delta); + +void setluxuries(struct region * r, const struct luxury_type * sale); +int get_maxluxuries(void); + +short rroad(const struct region * r, direction_t d); +void rsetroad(struct region * r, direction_t d, short value); + +int is_coastregion(struct region *r); + +int rtrees(const struct region * r, int ageclass); +enum { + TREE_SEED = 0, + TREE_SAPLING = 1, + TREE_TREE = 2 +}; + +int rsettrees(const struct region *r, int ageclass, int value); + +int rpeasants(const struct region * r); +void rsetpeasants(struct region * r, int value); +int rmoney(const struct region * r); +void rsetmoney(struct region * r, int value); +int rhorses(const struct region * r); +void rsethorses(const struct region * r, int value); + +#define rbuildings(r) ((r)->buildings) + +#define rherbtype(r) ((r)->land?(r)->land->herbtype:0) +#define rsetherbtype(r, value) if ((r)->land) (r)->land->herbtype=(value) + +#define rherbs(r) ((r)->land?(r)->land->herbs:0) +#define rsetherbs(r, value) if ((r)->land) ((r)->land->herbs=(short)(value)) + +boolean r_isforest(const struct region * r); + +#define rterrain(r) (oldterrain((r)->terrain)) +#define rsetterrain(r, t) ((r)->terrain = newterrain(t)) + +const char * rname(const struct region * r, const struct locale * lang); + +#define rplane(r) getplane(r) + +void r_setdemand(struct region * r, const struct luxury_type * ltype, int value); +int r_demand(const struct region * r, const struct luxury_type * ltype); + +const char * write_regionname(const struct region * r, const struct faction * f, char * buffer, size_t size); + +struct region * new_region(int x, int y, struct plane * pl, unsigned int uid); +void remove_region(region ** rlist, region * r); +void terraform_region(struct region * r, const struct terrain_type * terrain); +boolean pnormalize(int * x, int * y, const struct plane * pl); + +extern const int delta_x[MAXDIRECTIONS]; +extern const int delta_y[MAXDIRECTIONS]; +direction_t dir_invert(direction_t dir); +int production(const struct region *r); + +void region_set_owner(struct region * r, struct faction * owner, int turn); +struct faction * region_get_owner(const struct region * r); +struct alliance * region_get_alliance(const struct region * r); + +struct region * r_connect(const struct region *, direction_t dir); +#ifdef FAST_CONNECT +# define rconnect(r, dir) ((r)->connect[dir]?(r)->connect[dir]:r_connect(r, (direction_t)dir)) +#else +# define rconnect(r, dir) r_connect(r, (direction_t)dir) +#endif + +void free_regions(void); + +int region_get_morale(const region * r); +void region_set_morale(region * r, int morale, int turn); + +void write_region_reference(const struct region * r, struct storage * store); +variant read_region_reference(struct storage * store); +int resolve_region_coor(variant id, void * address); +int resolve_region_id(variant id, void * address); +#define RESOLVE_REGION(version) ((version + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include + +struct message; + +/* TODO: this could be nicer and faster + * call with MSG(("msg_name", "param", p), buf, faction). */ +#define MSG(makemsg, buf, size, loc, ud) { struct message * m = msg_message makemsg; nr_render(m, loc, buf, size, ud); msg_release(m); } +#define RENDER(f, buf, size, mcreate) { struct message * m = msg_message mcreate; nr_render(m, f->locale, buf, size, f); msg_release(m); } diff --git a/src/kernel/reports.c b/src/kernel/reports.c new file mode 100644 index 000000000..dadad6481 --- /dev/null +++ b/src/kernel/reports.c @@ -0,0 +1,2186 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "reports.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include +#include + +/* attributes includes */ +#include +#include +#include +#include + +boolean nocr = false; +boolean nonr = false; +boolean noreports = false; + +const char * visibility[] = { + "none", + "neighbour", + "lighthouse", + "travel", + "far", + "unit", + "battle" +}; + +const char *coasts[MAXDIRECTIONS] = +{ + "coast::nw", + "coast::ne", + "coast::e", + "coast::se", + "coast::sw", + "coast::w" +}; + +static char * +groupid(const struct group * g, const struct faction * f) +{ + typedef char name[OBJECTIDSIZE + 1]; + static name idbuf[8]; + static int nextbuf = 0; + char *buf = idbuf[(++nextbuf) % 8]; + sprintf(buf, "%s (%s)", g->name, factionid(f)); + return buf; +} + +const char * combatstatus[] = { + "status_aggressive", "status_front", + "status_rear", "status_defensive", + "status_avoid", "status_flee" +}; + +const char * +report_kampfstatus(const unit * u, const struct locale * lang) +{ + static char fsbuf[64]; + + strlcpy(fsbuf, LOC(lang, combatstatus[u->status]), sizeof(fsbuf)); + if (fval(u, UFL_NOAID)) { + strcat(fsbuf, ", "); + strcat(fsbuf, LOC(lang, "status_noaid")); + } + + return fsbuf; +} + +const char * +hp_status(const unit * u) +{ + double p = (double) ((double) u->hp / (double) (u->number * unit_max_hp(u))); + + if (p > 2.00) return mkname("damage", "critical"); + if (p > 1.50) return mkname("damage", "heavily"); + if (p < 0.50) return mkname("damage", "badly"); + if (p < 0.75) return mkname("damage", "wounded"); + if (p < 0.99) return mkname("damage", "exhausted"); + + return NULL; +} + +void +report_item(const unit * owner, const item * i, const faction * viewer, const char ** name, const char ** basename, int * number, boolean singular) +{ + assert(!owner || owner->number); + if (owner && owner->faction == viewer) { + if (name) *name = locale_string(viewer->locale, resourcename(i->type->rtype, ((i->number!=1 && !singular)?GR_PLURAL:0))); + if (basename) *basename = resourcename(i->type->rtype, 0); + if (number) *number = i->number; + } else if (owner && i->type->rtype==r_silver) { + int pp = i->number/owner->number; + if (number) *number = 1; + if (pp > 50000 && dragonrace(owner->race)) { + if (name) *name = locale_string(viewer->locale, "dragonhoard"); + if (basename) *basename = "dragonhoard"; + } else if (pp > 5000) { + if (name) *name = locale_string(viewer->locale, "moneychest"); + if (basename) *basename = "moneychest"; + } else if (pp > 500) { + if (name) *name = locale_string(viewer->locale, "moneybag"); + if (basename) *basename = "moneybag"; + } else { + if (number) *number = 0; + if (name) *name = NULL; + if (basename) *basename = NULL; + } + } else { + if (name) *name = locale_string(viewer->locale, resourcename(i->type->rtype, NMF_APPEARANCE|((i->number!=1 && !singular)?GR_PLURAL:0))); + if (basename) *basename = resourcename(i->type->rtype, NMF_APPEARANCE); + if (number) { + if (fval(i->type, ITF_HERB)) *number = 1; + else *number = i->number; + } + } +} + + +int * nmrs = NULL; + +int +update_nmrs(void) +{ + int i, newplayers =0; + faction *f; + int turn = global.data_turn; + + if (nmrs==NULL) nmrs = malloc(sizeof(int)*(NMRTimeout()+1)); + for (i = 0; i <= NMRTimeout(); ++i) { + nmrs[i] = 0; + } + + for (f = factions; f; f = f->next) { + if (fval(f, FFL_ISNEW)) { + ++newplayers; + } else if (!is_monsters(f) && f->alive) { + int nmr = turn-f->lastorders+1; + if (nmr<0 || nmr>NMRTimeout()) { + log_error(("faction %s has %d NMRS\n", factionid(f), nmr)); + nmr = MAX(0, nmr); + nmr = MIN(nmr, NMRTimeout()); + } + ++nmrs[nmr]; + } + } + return newplayers; +} + +#define ORDERS_IN_NR 1 +static size_t +buforder(char * bufp, size_t size, const order * ord, int mode) +{ + size_t tsize = 0; + int bytes; + + bytes = (int)strlcpy(bufp, ", \"", size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (mode1) { + *bufp++ ='\"'; + --size; + } else { + WARN_STATIC_BUFFER(); + } + ++tsize; + + return tsize; +} + +/** create a report of a list of items to a non-owner. + * \param result: an array of size items. + * \param size: maximum number of items to return + * \param owner: the owner of the items, or NULL for faction::items etc. + * \param viewer: the faction looking at the items + */ +int +report_items(const item * items, item * result, int size, const unit * owner, const faction * viewer) +{ + const item * itm; + int n = 0; /* number of results */ + + assert(owner==NULL || viewer!=owner->faction || !"not required for owner=viewer!"); + assert(size); + + for (itm=items;itm;itm=itm->next) { + item * ishow; + const char * ic; + + report_item(owner, itm, viewer, NULL, &ic, NULL, false); + if (ic && *ic) { + for (ishow = result; ishow!=result+n; ++ishow) { + const char * sc; + + if (ishow->type==itm->type) sc = ic; + else report_item(owner, ishow, viewer, NULL, &sc, NULL, false); + if (sc==ic || strcmp(sc, ic)==0) { + ishow->number+=itm->number; + break; + } + } + if (ishow==result+n) { + if (n==size) { + log_error(("too many items to report, increase buffer size.\n")); + return -1; + } + result[n].number = itm->number; + result[n].type = itm->type; + result[n].next = (n+1==size)?NULL:result+n+1; + ++n; + } + } + } + if (n>0) result[n-1].next = NULL; + return n; +} + +static void +report_resource(resource_report * result, const char * name, int number, int level) +{ + result->name = name; + result->number = number; + result->level = level; +} + +void +report_race(const struct unit * u, const char ** name, const char ** illusion) +{ + if (illusion) { + const race * irace = u_irace(u); + if (irace && irace!=u->race) { + *illusion = irace->_name[0]; + } + else { + *illusion = NULL; + } + } + if (name) { + *name = u->race->_name[0]; + if (fval(u->race, RCF_SHAPESHIFTANY)) { + const char * str = get_racename(u->attribs); + if (str) *name = str; + } + } +} + +void +report_building(const struct building * b, const char ** name, const char ** illusion) +{ + static int init; + static const struct building_type * bt_illusion; + + if (name) { + *name = buildingtype(b->type, b, b->size); + } + if (illusion) { + *illusion = NULL; + + if (!init) { + bt_illusion = bt_find("illusioncastle"); + init = 1; + } + if (bt_illusion && b->type==bt_illusion) { + const attrib * a = a_findc(b->attribs, &at_icastle); + if (a!=NULL) { + icastle_data * icastle = (icastle_data*)a->data.v; + *illusion = buildingtype(icastle->type, b, b->size); + } + } + } +} + +int +report_resources(const seen_region * sr, resource_report * result, int size, const faction * viewer) +{ + const region * r = sr->r; + int n = 0; + + if (r->land) { + int peasants = rpeasants(r); + int money = rmoney(r); + int horses = rhorses(r); + int trees = rtrees(r, 2); + int saplings = rtrees(r, 1); + boolean mallorn = fval(r, RF_MALLORN)!=0; + + if (money) { + if (n>=size) return -1; + report_resource(result+n, "rm_money", money, -1); + ++n; + } + if (peasants) { + if (n>=size) return -1; + report_resource(result+n, "rm_peasant", peasants, -1); + ++n; + } + if (horses) { + if (n>=size) return -1; + report_resource(result+n, "rm_horse", horses, -1); + ++n; + } + if (saplings) { + if (n>=size) return -1; + report_resource(result+n, mallorn?"rm_mallornsapling":"rm_sapling", saplings, -1); + ++n; + } + if (trees) { + if (n>=size) return -1; + report_resource(result+n, mallorn?"rm_mallorn":"rm_tree", trees, -1); + ++n; + } + } + + if (sr->mode>=see_unit) { + rawmaterial * res = r->resources; + while (res) { + int maxskill = 0; + const item_type * itype = resource2item(res->type->rtype); + int level = res->level + itype->construction->minskill - 1; + int visible = -1; + if (res->type->visible==NULL) { + visible = res->amount; + level = res->level + itype->construction->minskill - 1; + } else { + const unit * u; + for (u=r->units; visible!=res->amount && u!=NULL; u=u->next) { + if (u->faction == viewer) { + int s = eff_skill(u, itype->construction->skill, r); + if (s>maxskill) { + maxskill = s; + visible = res->type->visible(res, maxskill); + } + } + } + } + if (level>=0 && visible>=0) { + if (n>=size) return -1; + report_resource(result+n, res->type->name, visible, level); + n++; + } + res = res->next; + } + } + return n; +} + +int +bufunit(const faction * f, const unit * u, int indent, int mode, char * buf, size_t size) +{ + int i, dh; + int getarnt = fval(u, UFL_ANON_FACTION); + const char *pzTmp, *str; + building * b; + boolean isbattle = (boolean)(mode == see_battle); + int telepath_see = 0; + attrib *a_fshidden = NULL; + item * itm; + item * show; + faction *fv = visible_faction(f, u); + char * bufp = buf; + boolean itemcloak = false; + static const curse_type * itemcloak_ct = 0; + static boolean init = false; + int bytes; + item result[MAX_INVENTORY]; + + if (!init) { + init = true; + itemcloak_ct = ct_find("itemcloak"); + } + if (itemcloak_ct!=NULL) { + itemcloak = curse_active(get_curse(u->attribs, itemcloak_ct)); + } + + bytes = (int)strlcpy(bufp, unitname(u), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (!isbattle) { + attrib *a_otherfaction = a_find(u->attribs, &at_otherfaction); + if (u->faction == f) { + if (fval(u, UFL_GROUP)) { + attrib *a = a_find(u->attribs, &at_group); + if (a) { + group * g = (group*)a->data.v; + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, groupid(g, f), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + if (getarnt) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "anonymous"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else if (a_otherfaction) { + faction * otherfaction = get_otherfaction(a_otherfaction); + if (otherfaction) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, factionname(otherfaction), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + } else { + if (getarnt) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "anonymous"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else { + if (a_otherfaction && alliedunit(u, f, HELP_FSTEALTH)) { + faction * f = get_otherfaction(a_otherfaction); + bytes = snprintf(bufp, size, ", %s (%s)", factionname(f), factionname(u->faction)); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, factionname(fv), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + } + } + + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (u->faction != f && a_fshidden && a_fshidden->data.ca[0] == 1 && effskill(u, SK_STEALTH) >= 6) { + bytes = (int)strlcpy(bufp, "? ", size); + } else { + bytes = snprintf(bufp, size, "%d ", u->number); + } + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + pzTmp = get_racename(u->attribs); + if (pzTmp) { + bytes = (int)strlcpy(bufp, pzTmp, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (u->faction==f && fval(u->race, RCF_SHAPESHIFTANY)) { + bytes = (int)strlcpy(bufp, " (", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, racename(f->locale, u, u->race), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (size>1) { + strcpy(bufp++, ")"); + --size; + } + } + } else { + const race * irace = u_irace(u); + bytes = (int)strlcpy(bufp, racename(f->locale, u, irace), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (u->faction==f && irace!=u->race) { + bytes = (int)strlcpy(bufp, " (", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, racename(f->locale, u, u->race), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (size>1) { + strcpy(bufp++, ")"); + --size; + } + } + } + + if (fval(u, UFL_HERO) && (u->faction == f || omniscient(f))) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "hero"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + /* status */ + + if (u->number && (u->faction == f || telepath_see || isbattle)) { + const char * c = locale_string(f->locale, hp_status(u)); + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, report_kampfstatus(u, f->locale), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (c || fval(u, UFL_HUNGER)) { + bytes = (int)strlcpy(bufp, " (", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (c) { + bytes = (int)strlcpy(bufp, c, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (fval(u, UFL_HUNGER)) { + if (c) bytes = (int)strlcpy(bufp, ", hungert", size); + else bytes = (int)strlcpy(bufp, "hungert", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (size>1) { + strcpy(bufp++, ")"); + --size; + } + } + } + if (is_guard(u, GUARD_ALL)!=0) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "unit_guards"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + if ((b = usiege(u))!=NULL) { + bytes = (int)strlcpy(bufp, ", belagert ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, buildingname(b), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + dh = 0; + if (u->faction == f || telepath_see) { + skill * sv; + for (sv = u->skills;sv!=u->skills+u->skill_size;++sv) { + bytes = (int)spskill(bufp, size, f->locale, u, sv, &dh, 1); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + + dh = 0; + if (f == u->faction || telepath_see || omniscient(f)) { + show = u->items; + } else if (!itemcloak && mode >= see_unit && !(a_fshidden + && a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) + { + int n = report_items(u->items, result, MAX_INVENTORY, u, f); + assert(n>=0); + if (n>0) show = result; + else show = NULL; + } else { + show = NULL; + } + for (itm=show; itm; itm=itm->next) { + const char * ic; + int in, bytes; + report_item(u, itm, f, &ic, NULL, &in, false); + if (in==0 || ic==NULL) continue; + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (!dh) { + bytes = snprintf(bufp, size, "%s: ", LOC(f->locale, "nr_inventory")); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + dh = 1; + } + if (in == 1) { + bytes = (int)strlcpy(bufp, ic, size); + } else { + bytes = snprintf(bufp, size, "%d %s", in, ic); + } + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + if (u->faction == f || telepath_see) { + sc_mage * m = get_mage(u); + + if (m!=NULL) { + spell_list *slist = m->spells; + int t = effskill(u, SK_MAGIC); + int bytes = snprintf(bufp, size, ". Aura %d/%d", get_spellpoints(u), max_spellpoints(u->region,u)); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + for (dh=0; slist; slist=slist->next) { + spell * sp = slist->data; + if (sp->level > t) continue; + if (!dh) { + bytes = snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_spells")); + dh = 1; + } else { + bytes = (int)strlcpy(bufp, ", ", size); + } + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, spell_name(sp, f->locale), size); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + for (i=0; i!=MAXCOMBATSPELLS; ++i) { + if (get_combatspell(u, i)) break; + } + if (i!=MAXCOMBATSPELLS) { + bytes = snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_combatspells")); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + dh = 0; + for (i = 0; i < MAXCOMBATSPELLS; i++){ + const spell *sp; + if (!dh){ + dh = 1; + } else { + bytes = (int)strlcpy(bufp, ", ", size); + if (bytes && wrptr(&bufp, &size, bytes)!=0) { + WARN_STATIC_BUFFER(); + } + } + sp = get_combatspell(u,i); + if (sp) { + int sl = get_combatspelllevel(u, i); + bytes = (int)strlcpy(bufp, spell_name(sp, u->faction->locale), size); + if (bytes && wrptr(&bufp, &size, bytes)!=0) { + WARN_STATIC_BUFFER(); + } + + if (sl > 0) { + bytes = snprintf(bufp, size, " (%d)", sl); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } else { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nospells"), size); + if (bytes && wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + } + } + if (!isbattle) { + boolean printed = 0; + order * ord;; + for (ord=u->old_orders;ord;ord=ord->next) { + if (is_repeated(ord)) { + if (printedorders;ord;ord=ord->next) { + if (is_repeated(ord)) { + if (printedlocale); + if (str) { + bytes = (int)strlcpy(bufp, "; ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + bytes = (int)strlcpy(bufp, str, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + i = str[strlen(str) - 1]; + } + if (i != '!' && i != '?' && i != '.') { + if (size>1) { + strcpy(bufp++, "."); + --size; + } + } + pzTmp = uprivate(u); + if (u->faction == f && pzTmp) { + bytes = (int)strlcpy(bufp, " (Bem: ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, pzTmp, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, ")", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + dh=0; + if (!getarnt && f) { + if (alliedfaction(rplane(u->region), f, fv, HELP_ALL)) { + dh = 1; + } + } + if (size<=1) { + log_warning(("bufunit ran out of space after writing %u bytes.\n", (bufp-buf))); + } + return dh; +} + +/* TODO: telepath_see wird nicht berücksichtigt: Parteien mit + * telepath_see sollten immer einzelne Einheiten zu sehen + * bekommen, alles andere ist darstellungsteschnisch kompliziert. + */ + +size_t +spskill(char * buffer, size_t size, const struct locale * lang, const struct unit * u, struct skill * sv, int *dh, int days) +{ + char * bufp = buffer; + int i, effsk; + int bytes; + size_t tsize = 0; + + if (!u->number) return 0; + if (sv->level<=0) { + if (sv->old<=0 || (u->faction->options & want(O_SHOWSKCHANGE))==0) { + return 0; + } + } + + bytes = (int)strlcpy(bufp, ", ", size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (!*dh) { + bytes = (int)strlcpy(bufp, LOC(lang, "nr_skills"), size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + bytes = (int)strlcpy(bufp, ": ", size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + *dh = 1; + } + bytes = (int)strlcpy(bufp, skillname(sv->id, lang), size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + bytes = (int)strlcpy(bufp, " ", size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (sv->id == SK_MAGIC){ + sc_mage * mage = get_mage(u); + if (mage && mage->magietyp != M_GRAY) { + bytes = (int)strlcpy(bufp, LOC(lang, mkname("school", magic_school[mage->magietyp])), size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + bytes = (int)strlcpy(bufp, " ", size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + + if (sv->id == SK_STEALTH && fval(u, UFL_STEALTH)) { + i = u_geteffstealth(u); + if (i>=0) { + bytes = slprintf(bufp, size, "%d/", i); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + + effsk = effskill(u, sv->id); + bytes = slprintf(bufp, size, "%d", effsk); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (u->faction->options & want(O_SHOWSKCHANGE)) { + int oldeff = 0; + int diff; + + if (sv->old > 0) { + oldeff = sv->old + get_modifier(u, sv->id, sv->old, u->region, false); + } + + oldeff = MAX(0, oldeff); + diff = effsk - oldeff; + + if (diff != 0) { + bytes = slprintf(bufp, size, " (%s%d)", (diff>0)?"+":"", diff); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + return tsize; +} + +void +lparagraph(struct strlist ** SP, char *s, int indent, char mark) +{ + + /* Die Liste SP wird mit dem String s aufgefuellt, mit indent und einer + * mark, falls angegeben. SP wurde also auf 0 gesetzt vor dem Aufruf. + * Vgl. spunit (). */ + + char *buflocal = calloc(strlen(s) + indent + 1, sizeof(char)); + + if (indent) { + memset(buflocal, ' ', indent); + if (mark) + buflocal[indent - 2] = mark; + } + strcpy(buflocal + indent, s); + addstrlist(SP, buflocal); + free(buflocal); +} + +void +spunit(struct strlist ** SP, const struct faction * f, const unit * u, int indent, + int mode) +{ + char buf[DISPLAYSIZE]; + int dh = bufunit(f, u, indent, mode, buf, sizeof(buf)); + lparagraph(SP, buf, indent, (char) ((u->faction == f) ? '*' : (dh ? '+' : '-'))); +} + +struct message * +msg_curse(const struct curse * c, const void * obj, typ_t typ, int self) +{ + if (c->type->curseinfo) { + /* if curseinfo returns NULL, then we don't want to tell the viewer anything. */ + return c->type->curseinfo(obj, typ, c, self); + } else { + message * msg = cinfo_simple(obj, typ, c, self); + if (msg==NULL) { + const char * unknown[] = { "unit_unknown", "region_unknown", "building_unknown", "ship_unknown" }; + msg = msg_message(mkname("curseinfo", unknown[typ]), "id", c->no); + log_error(("no curseinfo function for %s and no fallback either.\n", c->type->cname)); + } else { + log_error(("no curseinfo function for %s, using cinfo_simple fallback.\n", c->type->cname)); + } + return msg; + } +} + +const struct unit * +ucansee(const struct faction *f, const struct unit *u, const struct unit *x) +{ + if (cansee(f, u->region, u, 0)) return u; + return x; +} + +static void +add_faction(faction_list ** flist, faction * sf) +{ + faction_list ** fnew = flist; + while (*fnew && (*fnew)->data->no < sf->no) { + fnew =&(*fnew)->next; + } + if ((*fnew==NULL) || (*fnew)->data!=sf) { + faction_list * finsert = malloc(sizeof(faction_list)); + finsert->next = *fnew; + *fnew = finsert; + finsert->data = sf; + } +} + +int +stealth_modifier(int seen_mode) +{ + switch (seen_mode) { + case see_unit: + return 0; + case see_far: + case see_lighthouse: + return -2; + case see_travel: + return -1; + default: + return INT_MIN; + } +} + +static void +get_addresses(report_context * ctx) +{ +/* "TODO: travelthru" */ + seen_region * sr = NULL; + region *r; + const faction * lastf = NULL; + faction_list * flist = calloc(1, sizeof(faction_list)); + + flist->data = ctx->f; + + if (f_get_alliance(ctx->f)) { + faction_list * member = ctx->f->alliance->members; + for (;member;member=member->next) { + add_faction(&flist, member->data); + } + } + + for (r=ctx->first;sr==NULL && r!=ctx->last;r=r->next) { + sr = find_seen(ctx->seen, r); + } + + for (;sr!=NULL;sr=sr->next) { + int stealthmod = stealth_modifier(sr->mode); + r = sr->r; + if (sr->mode==see_lighthouse) { + unit * u = r->units; + for (;u;u=u->next) { + faction * sf = visible_faction(ctx->f, u); + if (lastf!=sf) { + if (u->building || u->ship || (stealthmod>INT_MIN && cansee(ctx->f, r, u, stealthmod))) { + add_faction(&flist, sf); + lastf = sf; + } + } + } + } else if (sr->mode==see_travel) { + unit * u = r->units; + while (u) { + faction * sf = visible_faction(ctx->f, u); + assert(u->faction!=ctx->f); /* if this is see_travel only, then I shouldn't be here. */ + if (lastf!=sf) { + attrib * a = a_find(r->attribs, &at_travelunit); + while (a && a->type==&at_travelunit) { + unit * u2 = (unit*)a->data.v; + if (u2->faction==ctx->f) { + if (cansee_unit(u2, u, stealthmod)) { + add_faction(&flist, sf); + lastf = sf; + break; + } + } + a = a->next; + } + } + u = u->next; + } + } else if (sr->mode>see_travel) { + const unit * u = r->units; + while (u!=NULL) { + if (u->faction!=ctx->f) { + faction * sf = visible_faction(ctx->f, u); + boolean ballied = sf && sf!=ctx->f && sf!=lastf + && !fval(u, UFL_ANON_FACTION) && cansee(ctx->f, r, u, stealthmod); + if (ballied || ALLIED(ctx->f, sf)) { + add_faction(&flist, sf); + lastf = sf; + } + } + u = u->next; + } + } + } + + if (f_get_alliance(ctx->f)) { + faction *f2; + for (f2 = factions; f2; f2 = f2->next) { + if (f2->alliance == ctx->f->alliance) { + add_faction(&flist, f2); + } + } + } + ctx->addresses = flist; +} + +#define MAXSEEHASH 0x1000 +seen_region * reuse; + +seen_region ** +seen_init(void) +{ + return (seen_region **)calloc(MAXSEEHASH, sizeof(seen_region*)); +} + +void +seen_done(seen_region * seehash[]) +{ + int i; + for (i=0;i!=MAXSEEHASH;++i) { + seen_region * sd = seehash[i]; + if (sd==NULL) continue; + while (sd->nextHash!=NULL) sd = sd->nextHash; + sd->nextHash = reuse; + reuse = seehash[i]; + seehash[i] = NULL; + } + // free(seehash); +} + +void +free_seen(void) +{ + while (reuse) { + seen_region * r = reuse; + reuse = reuse->nextHash; + free(r); + } +} + +void +link_seen(seen_region * seehash[], const region * first, const region * last) +{ + const region * r = first; + seen_region * sr = NULL; + + if (first==last) return; + + do { + sr = find_seen(seehash, r); + r = r->next; + } while (sr==NULL && r!=last); + + while (r!=last) { + seen_region * sn = find_seen(seehash, r); + if (sn!=NULL) { + sr->next = sn; + sr = sn; + } + r = r->next; + } + sr->next = 0; +} + +seen_region * +find_seen(struct seen_region * seehash[], const region * r) +{ + unsigned int index = reg_hashkey(r) & (MAXSEEHASH-1); + seen_region * find = seehash[index]; + while (find) { + if (find->r==r) return find; + find=find->nextHash; + } + return NULL; +} + +static void +get_seen_interval(report_context * ctx) +{ + /* this is required to find the neighbour regions of the ones we are in, + * which may well be outside of [firstregion, lastregion) */ + int i; + for (i=0;i!=MAXSEEHASH;++i) { + seen_region * sr = ctx->seen[i]; + while (sr!=NULL) { + if (ctx->first==NULL || sr->r->indexfirst->index) { + ctx->first = sr->r; + } + if (ctx->last!=NULL && sr->r->index>=ctx->last->index) { + ctx->last = sr->r->next; + } + sr = sr->nextHash; + } + } + link_seen(ctx->seen, ctx->first, ctx->last); +} + +boolean +add_seen(struct seen_region * seehash[], struct region * r, unsigned char mode, boolean dis) +{ + seen_region * find = find_seen(seehash, r); + if (find==NULL) { + unsigned int index = reg_hashkey(r) & (MAXSEEHASH-1); + if (!reuse) reuse = (seen_region*)calloc(1, sizeof(struct seen_region)); + find = reuse; + reuse = reuse->nextHash; + find->nextHash = seehash[index]; + seehash[index] = find; + find->r = r; + } else if (find->mode >= mode) { + return false; + } + find->mode = mode; + find->disbelieves |= dis; + return true; +} + +typedef struct report_type { + struct report_type * next; + report_fun write; + const char * extension; + int flag; +} report_type; + +static report_type * report_types; + +void +register_reporttype(const char * extension, report_fun write, int flag) +{ + report_type * type = malloc(sizeof(report_type)); + type->extension = extension; + type->write = write; + type->flag = flag; + type->next = report_types; + report_types = type; +} + +static region_list * +get_regions_distance(region * root, int radius) +{ + region_list * rptr, * rlist = NULL; + region_list ** rp = &rlist; + add_regionlist(rp, root); + fset(root, RF_MARK); + while (*rp) { + region_list * r = *rp; + direction_t d; + rp = &r->next; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(r->data, d); + if (rn!=NULL && !fval(rn, RF_MARK) && distance(rn, root)<=radius) { + add_regionlist(rp, rn); + fset(rn, RF_MARK); + } + } + } + for (rptr=rlist;rptr;rptr=rptr->next) { + freset(rptr->data, RF_MARK); + } + return rlist; +} + +static void +view_default(struct seen_region ** seen, region *r, faction *f) +{ + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * r2 = rconnect(r, dir); + if (r2) { + connection * b = get_borders(r, r2); + while (b) { + if (!b->type->transparent(b, f)) break; + b = b->next; + } + if (!b) add_seen(seen, r2, see_neighbour, false); + } + } +} + +static void +view_neighbours(struct seen_region ** seen, region * r, faction * f) +{ + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * r2 = rconnect(r, dir); + if (r2) { + connection * b = get_borders(r, r2); + while (b) { + if (!b->type->transparent(b, f)) break; + b = b->next; + } + if (!b) { + if (add_seen(seen, r2, see_far, false)) { + if (!(fval(r2->terrain, FORBIDDEN_REGION))) { + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * r3 = rconnect(r2, dir); + if (r3) { + connection * b = get_borders(r2, r3); + while (b) { + if (!b->type->transparent(b, f)) break; + b = b->next; + } + if (!b) add_seen(seen, r3, see_neighbour, false); + } + } + } + } + } + } + } +} + +static void +recurse_regatta(struct seen_region ** seen, region *center, region *r, faction *f, int maxdist) +{ + direction_t dir; + int dist = distance(center, r); + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * r2 = rconnect(r, dir); + if (r2) { + int ndist = distance(center, r2); + if (ndist>dist && fval(r2->terrain, SEA_REGION)) { + connection * b = get_borders(r, r2); + while (b) { + if (!b->type->transparent(b, f)) break; + b = b->next; + } + if (!b) { + if (ndistunits; u; u=u->next) { + if (u->faction==f) { + int es = effskill(u, SK_PERCEPTION); + if (es>skill) skill=es; + } + } + recurse_regatta(seen, r, r, f, skill/2); +} + +static void +prepare_reports(void) +{ + region * r; + faction * f; + static const struct building_type * bt_lighthouse = NULL; + if (bt_lighthouse==NULL) bt_lighthouse = bt_find("lighthouse"); + + for (f = factions; f ; f = f->next) { + if (f->seen) seen_done(f->seen); + f->seen = seen_init(); + } + + for (r = regions; r ; r = r->next) { + attrib *ru; + unit * u; + plane * p = rplane(r); + + reorder_units(r); + + if (p) { + watcher * w = p->watchers; + for (;w;w=w->next) { + add_seen(w->faction->seen, r, w->mode, false); +#ifdef SMART_INTERVALS + update_interval(w->faction, r); +#endif + } + } + + for (u = r->units; u; u = u->next) { + if (u->building && u->building->type==bt_lighthouse) { + /* we are in a lighthouse. add the regions we can see from here! */ + int range = lighthouse_range(u->building, u->faction); + region_list * rlist = get_regions_distance(r, range); + region_list * rp = rlist; + + while (rp) { + region * rl = rp->data; + if (fval(rl->terrain, SEA_REGION)) { + direction_t d; + add_seen(u->faction->seen, rl, see_lighthouse, false); + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(rl, d); + if (rn!=NULL) { + add_seen(u->faction->seen, rn, see_neighbour, false); + } + } + } + rp = rp->next; + } + free_regionlist(rlist); + } + + if (u->race != new_race[RC_SPELL] || u->number == RS_FARVISION) { + if (fval(u, UFL_DISBELIEVES)) { + add_seen(u->faction->seen, r, see_unit, true); + } else { + add_seen(u->faction->seen, r, see_unit, false); + } + } + } + + if (fval(r, RF_TRAVELUNIT)) { + for (ru = a_find(r->attribs, &at_travelunit); ru && ru->type==&at_travelunit; ru = ru->next) { + unit * u = (unit*)ru->data.v; + + /* make sure the faction has not been removed this turn: */ + if (u->faction) { + add_seen(u->faction->seen, r, see_travel, false); + } + } + } + } +} + +static seen_region ** +prepare_report(faction * f) +{ + struct seen_region * sr; + region * r = firstregion(f); + region * last = lastregion(f); + + link_seen(f->seen, r, last); + + for (sr=NULL; sr==NULL && r!=last; r=r->next) { + sr = find_seen(f->seen, r); + } + + for (;sr!=NULL;sr=sr->next) { + if (sr->mode>see_neighbour) { + region * r = sr->r; + plane * p = rplane(r); + + void (*view)(struct seen_region **, region *, faction *) = view_default; + if (p && fval(p, PFL_SEESPECIAL)) { + attrib * a = a_find(p->attribs, &at_viewrange); + if (a) view = (void (*)(struct seen_region **, region *, faction *))a->data.f; + } + view(f->seen, r, f); + } + } + return f->seen; +} + +int +write_reports(faction * f, time_t ltime) +{ + int backup = 1, maxbackup = 128; + boolean gotit = false; + struct report_context ctx; + const char * encoding = "UTF-8"; + + if (noreports) { + return false; + } + ctx.f = f; + ctx.report_time = time(NULL); + ctx.seen = prepare_report(f); + ctx.first = firstregion(f); + ctx.last = lastregion(f); + ctx.addresses = NULL; + ctx.userdata = NULL; + get_seen_interval(&ctx); + get_addresses(&ctx); + + do { + report_type * rtype = report_types; + + errno = 0; + if (verbosity>=2) { + log_stdio(stdout, "Reports for %s:", factionname(f)); + } + for (;rtype!=NULL;rtype=rtype->next) { + if (f->options & rtype->flag) { + char filename[MAX_PATH]; + sprintf(filename, "%s/%d-%s.%s", reportpath(), turn, factionid(f), rtype->extension); + if (rtype->write(filename, &ctx, encoding)==0) { + gotit = true; + } + } + } + + if (errno) { + char zText[64]; + puts(" ERROR"); + sprintf(zText, "Waiting %u seconds before retry", backup); + perror(zText); + sleep(backup); + if (backup=2) { + puts(" DONE"); + } + } while (errno); + if (!gotit) { + log_warning(("No report for faction %s!\n", factionid(f))); + } + freelist(ctx.addresses); + seen_done(ctx.seen); + return 0; +} + +static void +nmr_warnings(void) +{ + faction *f,*fa; +#define FRIEND (HELP_GUARD|HELP_MONEY) + for (f=factions;f;f=f->next) { + if (!is_monsters(f) && (turn-f->lastorders) >= 2) { + message * msg = NULL; + for (fa=factions;fa;fa=fa->next) { + int warn = 0; + if (get_param_int(global.parameters, "rules.alliances", 0)!=0) { + if (f->alliance && f->alliance==fa->alliance) { + warn = 1; + } + } else if (alliedfaction(NULL, f, fa, FRIEND) && alliedfaction(NULL, fa, f, FRIEND)) { + warn = 1; + } + if (warn) { + if (msg==NULL) { + msg = msg_message("warn_dropout", "faction turns", f, turn - f->lastorders); + } + add_message(&fa->msgs, msg); + } + } + if (msg!=NULL) msg_release(msg); + } + } +} + +static void +report_donations(void) +{ + region * r; + for (r=regions;r;r=r->next) { + while (r->donations) { + donation * sp = r->donations; + if (sp->amount > 0) { + struct message * msg = msg_message("donation", + "from to amount", sp->f1, sp->f2, sp->amount); + r_addmessage(r, sp->f1, msg); + r_addmessage(r, sp->f2, msg); + msg_release(msg); + } + r->donations = sp->next; + free(sp); + } + } +} + +static void +write_script(FILE * F, const faction * f) +{ + report_type * rtype; + char buf[1024]; + + fprintf(F, "faction=%s:email=%s:lang=%s", factionid(f), f->email, locale_name(f->locale)); + if (f->options & (1<extension); + } + } + fputs(buf, F); + fputc('\n', F); +} + +int +init_reports(void) +{ + prepare_reports(); +#ifdef HAVE_STAT + { + stat_type st; + if (stat(reportpath(), &st)==0) return 0; + } +#endif + if (makedir(reportpath(), 0700)!=0) { + if (errno!=EEXIST) { + perror("could not create reportpath"); + return -1; + } + } + return 0; +} + +int +reports(void) +{ + faction *f; + FILE *mailit; + time_t ltime = time(NULL); + const char * str; + int retval = 0; + char path[MAX_PATH]; + + if (verbosity>=1) { + log_stdio(stdout, "Writing reports for turn %d:", turn); + } + nmr_warnings(); + report_donations(); + remove_empty_units(); + + sprintf(path, "%s/reports.txt", reportpath()); + mailit = fopen(path, "w"); + if (mailit == NULL) { + log_error(("%s could not be opened!\n", path)); + } + + for (f = factions; f; f = f->next) { + int error = write_reports(f, ltime); + if (error) retval = error; + if (mailit) write_script(mailit, f); + } + if (mailit) fclose(mailit); + free_seen(); + str = get_param(global.parameters, "globalreport"); +#ifdef GLOBAL_REPORT + if (str!=NULL) { + sprintf(path, "%s/%s.%u.cr", reportpath(), str, turn); + global_report(path); + } +#endif + return retval; +} + +static variant +var_copy_string(variant x) +{ + x.v = strdup((const char*)x.v); + return x; +} + +static void +var_free_string(variant x) +{ + free(x.v); +} + +static variant +var_copy_order(variant x) +{ + x.v = copy_order((order*)x.v); + return x; +} + +static void +var_free_order(variant x) +{ + free_order(x.v); +} + +static variant +var_copy_items(variant x) +{ + item * isrc; + resource * rdst = NULL, ** rptr = &rdst; + + for (isrc = (item*)x.v; isrc!=NULL; isrc=isrc->next) { + resource * res = malloc(sizeof(resource)); + res->number = isrc->number; + res->type = isrc->type->rtype; + *rptr = res; + rptr = &res->next; + } + *rptr = NULL; + x.v = rdst; + return x; +} + +static void +var_free_resources(variant x) +{ + resource * rsrc = (resource*)x.v; + while (rsrc) { + resource * res = rsrc->next; + free(rsrc); + rsrc = res; + } + x.v = 0; +} + +static void +var_free_regions(variant x) +{ + free(x.v); +} + +const char * +trailinto(const region * r, const struct locale * lang) +{ + char ref[32]; + const char * s; + if (r) { + const char * tname = terrain_name(r); + strcat(strcpy(ref, tname), "_trail"); + s = locale_string(lang, ref); + if (s && *s) { + if (strstr(s, "%s")) return s; + } + } + return "%s"; +} + +size_t +f_regionid(const region * r, const faction * f, char * buffer, size_t size) +{ + if (!r) { + strncpy(buffer, "(Chaos)", size); + } else { + plane * pl = rplane(r); + const char * name = pl?pl->name:0; + int nx = r->x, ny = r->y; + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl, r); + strncpy(buffer, rname(r, f->locale), size); + buffer[size-1]=0; + sprintf(buffer+strlen(buffer), " (%d,%d%s%s)", nx, ny, name?",":"", (name)?name:""); + } + return strlen(buffer); +} + +static char * +f_regionid_s(const region * r, const faction * f) +{ + static int i = 0; + static char bufs[4][NAMESIZE + 20]; + char * buf = bufs[(++i)%4]; + + f_regionid(r, f, buf, NAMESIZE + 20); + return buf; +} + +/*** BEGIN MESSAGE RENDERING ***/ +static void +eval_localize(struct opstack ** stack, const void * userdata) /* (string, locale) -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct locale * lang = f?f->locale:default_locale; + const char *c = (const char *)opop_v(stack); + c = locale_string(lang, c); + opush_v(stack, strcpy(balloc(strlen(c)+1), c)); +} + +static void +eval_trailto(struct opstack ** stack, const void * userdata) /* (int, int) -> int */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct locale * lang = f?f->locale:default_locale; + const struct region * r = (const struct region*)opop(stack).v; + const char * trail = trailinto(r, lang); + const char * rn = f_regionid_s(r, f); + variant var; + char * x = var.v = balloc(strlen(trail)+strlen(rn)); + sprintf(x, trail, rn); + opush(stack, var); +} + +static void +eval_unit(struct opstack ** stack, const void * userdata) /* unit -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct unit * u = (const struct unit *)opop(stack).v; + const char * c = u?unitname(u):LOC(f->locale, "an_unknown_unit"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_unit_dative(struct opstack ** stack, const void * userdata) /* unit -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct unit * u = (const struct unit *)opop(stack).v; + const char * c = u?unitname(u):LOC(f->locale, "unknown_unit_dative"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_spell(struct opstack ** stack, const void * userdata) /* unit -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct spell * sp = (const struct spell *)opop(stack).v; + const char * c = sp?spell_name(sp, f->locale):LOC(f->locale, "an_unknown_spell"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_curse(struct opstack ** stack, const void * userdata) /* unit -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct curse_type * sp = (const struct curse_type *)opop(stack).v; + const char * c = sp?curse_name(sp, f->locale):LOC(f->locale, "an_unknown_curse"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_unitname(struct opstack ** stack, const void * userdata) /* unit -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct unit * u = (const struct unit *)opop(stack).v; + const char * c = u?u->name:LOC(f->locale, "an_unknown_unit"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + + +static void +eval_unitid(struct opstack ** stack, const void * userdata) /* unit -> int */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct unit * u = (const struct unit *)opop(stack).v; + const char * c = u?u->name:LOC(f->locale, "an_unknown_unit"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_unitsize(struct opstack ** stack, const void * userdata) /* unit -> int */ +{ + const struct unit * u = (const struct unit *)opop(stack).v; + variant var; + + var.i = u->number; + opush(stack, var); +} + +static void +eval_faction(struct opstack ** stack, const void * userdata) /* faction -> string */ +{ + const struct faction * f = (const struct faction *)opop(stack).v; + const char * c = factionname(f); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_alliance(struct opstack ** stack, const void * userdata) /* faction -> string */ +{ + const struct alliance * al = (const struct alliance *)opop(stack).v; + const char * c = alliancename(al); + variant var; + if (c!=NULL) { + size_t len = strlen(c); + var.v = strcpy(balloc(len+1), c); + } + else var.v = NULL; + opush(stack, var); +} + +static void +eval_region(struct opstack ** stack, const void * userdata) /* region -> string */ +{ + char name[NAMESIZE+32]; + const struct faction * f = (const struct faction *)userdata; + const struct region * r = (const struct region *)opop(stack).v; + const char * c = write_regionname(r, f, name, sizeof(name)); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_terrain(struct opstack ** stack, const void * userdata) /* region -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct region * r = (const struct region *)opop(stack).v; + const char * c = LOC(f->locale, terrain_name(r)); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_ship(struct opstack ** stack, const void * userdata) /* ship -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct ship * u = (const struct ship *)opop(stack).v; + const char * c = u?shipname(u):LOC(f->locale, "an_unknown_ship"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_building(struct opstack ** stack, const void * userdata) /* building -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct building * u = (const struct building *)opop(stack).v; + const char * c = u?buildingname(u):LOC(f->locale, "an_unknown_building"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_weight(struct opstack ** stack, const void * userdata) /* region -> string */ +{ + char buffer[32]; + const struct faction * f = (const struct faction *)userdata; + const struct locale * lang = f->locale; + int weight = opop_i(stack); + variant var; + + if (weight % SCALEWEIGHT == 0) { + if (weight==SCALEWEIGHT) { + sprintf(buffer, "1 %s", LOC(lang, "weight_unit")); + } else { + sprintf(buffer, "%u %s", weight/SCALEWEIGHT, LOC(lang, "weight_unit_p")); + } + } else { + if (weight==1) { + sprintf(buffer, "1 %s %u", LOC(lang, "weight_per"), SCALEWEIGHT); + } else { + sprintf(buffer, "%u %s %u", weight, LOC(lang, "weight_per_p"), SCALEWEIGHT); + } + } + + var.v = strcpy(balloc(strlen(buffer)+1), buffer); + opush(stack, var); +} + +static void +eval_resource(struct opstack ** stack, const void * userdata) +{ + const faction * report = (const faction*)userdata; + const struct locale * lang = report?report->locale:default_locale; + int j = opop(stack).i; + const struct resource_type * res = (const struct resource_type *)opop(stack).v; + const char * c = LOC(lang, resourcename(res, j!=1)); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_race(struct opstack ** stack, const void * userdata) +{ + const faction * report = (const faction*)userdata; + const struct locale * lang = report?report->locale:default_locale; + int j = opop(stack).i; + const race * r = (const race *)opop(stack).v; + const char * c = LOC(lang, rc_name(r, j!=1)); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_order(struct opstack ** stack, const void * userdata) /* order -> string */ +{ + const struct order * ord = (const struct order *)opop(stack).v; + static char buf[256]; + size_t len; + variant var; + + unused(userdata); + write_order(ord, buf, sizeof(buf)); + len = strlen(buf); + var.v = strcpy(balloc(len+1), buf); + opush(stack, var); +} + +static void +eval_resources(struct opstack ** stack, const void * userdata) /* order -> string */ +{ + const faction * report = (const faction*)userdata; + const struct locale * lang = report?report->locale:default_locale; + const struct resource * res = (const struct resource *)opop(stack).v; + static char buf[1024]; /* but we only use about half of this */ + size_t size = sizeof(buf) - 1; + variant var; + + char * bufp = buf; + while (res!=NULL && size > 4) { + const char * rname = resourcename(res->type, (res->number!=1)?NMF_PLURAL:0); + int bytes = snprintf(bufp, size, "%d %s", res->number, LOC(lang, rname)); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0 || sizenext; + if (res!=NULL && size>2) { + strcat(bufp, ", "); + bufp += 2; + size -= 2; + } + } + *bufp = 0; + var.v = strcpy(balloc(bufp-buf+1), buf); + opush(stack, var); +} + +static void +eval_regions(struct opstack ** stack, const void * userdata) /* order -> string */ +{ + const faction * report = (const faction*)userdata; + int i = opop(stack).i; + int end, begin = opop(stack).i; + const arg_regions * regions = (const arg_regions *)opop(stack).v; + static char buf[256]; + size_t size = sizeof(buf) - 1; + variant var; + char * bufp = buf; + + if (regions==NULL) { + end = begin; + } else { + if (i>=0) end = begin+i; + else end = regions->nregions+i; + } + for (i=begin;iregions[i], report); + int bytes = (int)strlcpy(bufp, rname, size); + if (bytes && wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (i+12) { + strcat(bufp, ", "); + bufp += 2; + size -= 2; + } + } + *bufp = 0; + var.v = strcpy(balloc(bufp-buf+1), buf); + opush(stack, var); +} + +static void +eval_trail(struct opstack ** stack, const void * userdata) /* order -> string */ +{ + const faction * report = (const faction*)userdata; + const struct locale * lang = report?report->locale:default_locale; + int i, end = 0, begin = 0; + const arg_regions * regions = (const arg_regions *)opop(stack).v; + static char buf[512]; + size_t size = sizeof(buf) - 1; + variant var; + char * bufp = buf; +#ifdef _SECURECRT_ERRCODE_VALUES_DEFINED + /* stupid MS broke snprintf */ + int eold = errno; +#endif + + if (regions!=NULL) { + end = regions->nregions; + for (i=begin;iregions[i]; + const char * trail = trailinto(r, lang); + const char * rn = f_regionid_s(r, report); + int bytes = snprintf(bufp, size, trail, rn); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (i+2locale:default_locale; + int i = opop(stack).i; + const char * c = LOC(lang, (i>=0)?directions[i]:"unknown_direction"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_skill(struct opstack ** stack, const void * userdata) +{ + const faction * report = (const faction*)userdata; + const struct locale * lang = report?report->locale:default_locale; + skill_t sk = (skill_t)opop(stack).i; + const char * c = skillname(sk, lang); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_int36(struct opstack ** stack, const void * userdata) +{ + int i = opop(stack).i; + const char * c = itoa36(i); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); + unused(userdata); +} +/*** END MESSAGE RENDERING ***/ + +#include + +static void log_orders(const struct message * msg) +{ + faction * f = get_monsters(); + char buffer[4096]; + int i; + + for (i=0;i!=msg->type->nparameters;++i) { + if (msg->type->types[i]->copy==&var_copy_order) { + const char * section = nr_section(msg); + nr_render(msg, f?f->locale:default_locale, buffer, sizeof(buffer), f); + log_printf("MESSAGE [%s]: %s\n", section, buffer); + break; + } + } +} + +int +report_action(region * r, unit * actor, message * msg, int flags) +{ + int result = 0; + unit * u; + int view = flags&(ACTION_CANSEE|ACTION_CANNOTSEE); + + /* melden, 1x pro Partei */ + if (flags&ACTION_RESET) { + freset(actor->faction, FFL_SELECT); + for (u = r->units; u; u = u->next ) freset(u->faction, FFL_SELECT); + } + if (view) { + for (u = r->units; u; u = u->next ) { + if (!fval(u->faction, FFL_SELECT) ) { + boolean show = u->faction == actor->faction; + fset(u->faction, FFL_SELECT); + if (view==ACTION_CANSEE) { + /* Bei Fernzaubern sieht nur die eigene Partei den Magier */ + show = show || (r==actor->region && cansee(u->faction, r, actor, 0)); + } else if (view==ACTION_CANNOTSEE) { + show = !show && !(r==actor->region && cansee(u->faction, r, actor, 0)); + } else { + /* the unliely (or lazy) case */ + show = true; + } + + if (show) { + r_addmessage(r, u->faction, msg); + } else { /* Partei des Magiers, sieht diesen immer */ + result = 1; + } + } + } + /* Ist niemand von der Partei des Magiers in der Region, dem Magier + * nochmal gesondert melden */ + if ((flags&ACTION_CANSEE) && !fval(actor->faction, FFL_SELECT)) { + add_message(&actor->faction->msgs, msg); + } + } + return result; +} + + +void +register_reports(void) +{ + /* register datatypes for the different message objects */ + register_argtype("alliance", NULL, NULL, VAR_VOIDPTR); + register_argtype("building", NULL, NULL, VAR_VOIDPTR); + register_argtype("direction", NULL, NULL, VAR_INT); + register_argtype("faction", NULL, NULL, VAR_VOIDPTR); + register_argtype("race", NULL, NULL, VAR_VOIDPTR); + register_argtype("region", NULL, NULL, VAR_VOIDPTR); + register_argtype("resource", NULL, NULL, VAR_VOIDPTR); + register_argtype("ship", NULL, NULL, VAR_VOIDPTR); + register_argtype("skill", NULL, NULL, VAR_VOIDPTR); + register_argtype("spell", NULL, NULL, VAR_VOIDPTR); + register_argtype("curse", NULL, NULL, VAR_VOIDPTR); + register_argtype("unit", NULL, NULL, VAR_VOIDPTR); + register_argtype("int", NULL, NULL, VAR_INT); + register_argtype("string", var_free_string, var_copy_string, VAR_VOIDPTR); + register_argtype("order", var_free_order, var_copy_order, VAR_VOIDPTR); + register_argtype("resources", var_free_resources, NULL, VAR_VOIDPTR); + register_argtype("items", var_free_resources, var_copy_items, VAR_VOIDPTR); + register_argtype("regions", var_free_regions, NULL, VAR_VOIDPTR); + + + msg_log_create = &log_orders; + + /* register functions that turn message contents to readable strings */ + add_function("alliance", &eval_alliance); + add_function("region", &eval_region); + add_function("terrain", &eval_terrain); + add_function("weight", &eval_weight); + add_function("resource", &eval_resource); + add_function("race", &eval_race); + add_function("faction", &eval_faction); + add_function("ship", &eval_ship); + add_function("unit", &eval_unit); + add_function("unit.dative", &eval_unit_dative); + add_function("unit.name", &eval_unitname); + add_function("unit.id", &eval_unitid); + add_function("unit.size", &eval_unitsize); + add_function("building", &eval_building); + add_function("skill", &eval_skill); + add_function("order", &eval_order); + add_function("direction", &eval_direction); + add_function("int36", &eval_int36); + add_function("trailto", &eval_trailto); + add_function("localize", &eval_localize); + add_function("spell", &eval_spell); + add_function("curse", &eval_curse); + add_function("resources", &eval_resources); + add_function("regions", &eval_regions); + add_function("trail", &eval_trail); + + /* register alternative visibility functions */ + register_function((pf_generic)view_neighbours, "view_neighbours"); + register_function((pf_generic)view_regatta, "view_regatta"); +} diff --git a/src/kernel/reports.h b/src/kernel/reports.h new file mode 100644 index 000000000..f4082f91c --- /dev/null +++ b/src/kernel/reports.h @@ -0,0 +1,140 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_REPORTS +#define H_KRNL_REPORTS +#ifdef __cplusplus +extern "C" { +#endif + +/* Alter, ab dem der Score angezeigt werden soll: */ +#define DISPLAYSCORE 12 +/* Breite einer Reportzeile: */ +#define REPORTWIDTH 78 + +extern const char *directions[]; +extern const char *coasts[]; +extern boolean nonr; +extern boolean nocr; +extern boolean noreports; + +/* kann_finden speedups */ +extern boolean kann_finden(struct faction * f1, struct faction * f2); +extern struct unit * can_find(struct faction *, struct faction *); + +/* funktionen zum schreiben eines reports */ +void sparagraph(struct strlist ** SP, const char *s, int indent, char mark); +void lparagraph(struct strlist ** SP, char *s, int indent, char mark); +const char *hp_status(const struct unit * u); +extern size_t spskill(char * pbuf, size_t siz, const struct locale * lang, const struct unit * u, struct skill * sv, int *dh, int days); /* mapper */ +extern void spunit(struct strlist ** SP, const struct faction * f, const struct unit * u, int indent, int mode); + +extern int reports(void); +extern int write_reports(struct faction * f, time_t ltime); +extern int init_reports(void); + +extern const struct unit *ucansee(const struct faction *f, const struct unit *u, const struct unit *x); + +int hat_in_region(item_t itm, struct region * r, struct faction * f); + +/* für fast_region und neuen CR: */ + +enum { + see_none, + see_neighbour, + see_lighthouse, + see_travel, + see_far, + see_unit, + see_battle +}; +extern int stealth_modifier(int seen_mode); + +typedef struct seen_region { + struct seen_region * nextHash; + struct seen_region * next; + struct region *r; + unsigned char mode; + boolean disbelieves; +} seen_region; + +extern struct seen_region * find_seen(struct seen_region * seehash[], const struct region * r); +extern boolean add_seen(struct seen_region * seehash[], struct region * r, unsigned char mode, boolean dis); +extern struct seen_region ** seen_init(void); +extern void seen_done(struct seen_region * seehash[]); +extern void free_seen(void); +extern void link_seen(seen_region * seehash[], const struct region * first, const struct region * last); +extern const char * visibility[]; + +typedef struct report_context { + struct faction * f; + struct faction_list * addresses; + struct seen_region ** seen; + struct region * first, * last; + void * userdata; + time_t report_time; +} report_context; + +typedef int (*report_fun)(const char * filename, report_context * ctx, const char * charset); +extern void register_reporttype(const char * extension, report_fun write, int flag); + + +extern int bufunit(const struct faction * f, const struct unit * u, int indent, int mode, char * buf, size_t size); + +extern const char * trailinto(const struct region * r, const struct locale * lang); +extern const char * report_kampfstatus(const struct unit * u, const struct locale * lang); + + extern void register_reports(void); + + extern int update_nmrs(void); + extern int * nmrs; + + extern struct message * msg_curse(const struct curse * c, const void * obj, typ_t typ, int slef); + + typedef struct arg_regions { + int nregions; + struct region ** regions; + } arg_regions; + + typedef struct resource_report { + const char * name; + int number; + int level; + } resource_report; + int report_resources(const struct seen_region * sr, struct resource_report * result, int size, const struct faction * viewer); + int report_items(const struct item * items, struct item * result, int size, const struct unit * owner, const struct faction * viewer); + void report_item(const struct unit * owner, const struct item * i, const struct faction * viewer, const char ** name, const char ** basename, int * number, boolean singular); + void report_building(const struct building * b, const char ** btype, const char ** billusion); + void report_race(const struct unit * u, const char ** rcname, const char ** rcillusion); + +#define ACTION_RESET 0x01 /* reset the one-time-flag FFL_SELECT (on first pass) */ +#define ACTION_CANSEE 0x02 /* to people who can see the actor */ +#define ACTION_CANNOTSEE 0x04 /* to people who can not see the actor */ +extern int report_action(struct region * r, struct unit * actor, struct message * msg, int flags); + + extern size_t f_regionid(const struct region * r, const struct faction * f, char * buffer, size_t size); + + extern const char * combatstatus[]; +#define GR_PLURAL 0x01 /* grammar: plural */ +#define MAX_INVENTORY 128 /* maimum number of different items in an inventory */ +#define MAX_RAWMATERIALS 8 /* maximum kinds of raw materials in a regions */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/resources.c b/src/kernel/resources.c new file mode 100644 index 000000000..999ff1671 --- /dev/null +++ b/src/kernel/resources.c @@ -0,0 +1,208 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "resources.h" + +/* kernel includes */ +#include "build.h" +#include "item.h" +#include "region.h" +#include "terrain.h" + +#include +#include + +#include +#include +#include + +static double +ResourceFactor(void) +{ + static double value = -1.0; + if (value<0) { + const char * str = get_param(global.parameters, "resource.factor"); + value = str?atof(str):1.0; + } + return value; +} + +void +update_resources(region * r) +{ + struct rawmaterial * res = r->resources; + while (res) { + if (res->type->update) res->type->update(res, r); + res = res->next; + } +} + +extern int dice_rand(const char *s); + +static void +update_resource(struct rawmaterial * res, double modifier) +{ + double amount = 1 + (res->level-res->startlevel) * res->divisor/100.0; + amount = ResourceFactor() * res->base * amount * modifier; + if (amount<1.0) res->amount = 1; + else res->amount = (int)amount; + assert(res->amount>0); +} + +void +add_resource(region * r, int level, int base, int divisor, const resource_type * rtype) +{ + struct rawmaterial * rm = calloc(sizeof(struct rawmaterial), 1); + + rm->next = r->resources; + r->resources = rm; + rm->level = level; + rm->startlevel = level; + rm->base = base; + rm->divisor = divisor; + rm->flags = 0; + rm->type = rmt_get(rtype); + update_resource(rm, 1.0); + rm->type->terraform(rm, r); +} + +void +terraform_resources(region * r) +{ + int i; + const terrain_type * terrain = r->terrain; + + if (terrain->production==NULL) return; + for (i=0;terrain->production[i].type; ++i) { + rawmaterial *rm; + const terrain_production * production = terrain->production+i; + const resource_type * rtype = production->type; + + for (rm=r->resources; rm; rm=rm->next) { + if (rm->type->rtype == rtype) break; + } + if (rm) continue; + + if (chance(production->chance)) { + add_resource(r, dice_rand(production->startlevel), dice_rand(production->base), dice_rand(production->divisor), production->type); + } + } +} + +static void +terraform_default(struct rawmaterial * res, const region * r) +{ +#define SHIFT 70 + double modifier = 1.0 + ((rng_int() % (SHIFT*2+1)) - SHIFT) * ((rng_int() % (SHIFT*2+1)) - SHIFT) / 10000.0; + res->amount = (int)(res->amount*modifier); /* random adjustment, +/- 91% */ + if (res->amount<1) res->amount=1; + unused(r); +} + +#ifdef RANDOM_CHANGE +static void +resource_random_change(int *pvalue, boolean used) +{ + int split = 5; + int rnd = rng_int()%100; + + if (pvalue==0 || rnd %10 >= 10) return; + if (used) split = 4; + /* if a resource was mined this round, there is a 6% probability + * of a decline and a 4% probability of a raise. */ + /* if it wasn't mined this round, there is an equal probability + * of 5% for a decline or a raise. */ + if(rnd < split) { + (*pvalue)++; + } else { + (*pvalue)--; + } + if ((*pvalue) < 0) (*pvalue) = 0; +} +#endif + +static int +visible_default(const rawmaterial *res, int skilllevel) +/* resources are visible, if skill equals minimum skill to mine them + * plus current level of difficulty */ +{ + const struct item_type * itype = res->type->rtype->itype; + if (res->level<=1 && res->level + itype->construction->minskill <= skilllevel+1) { + assert (res->amount>0); + return res->amount; + } else if (res->level + itype->construction->minskill <= skilllevel+2) { + assert (res->amount>0); + return res->amount; + } + return -1; +} + +static void +use_default(rawmaterial *res, const region * r, int amount) +{ + assert(res->amount>0 && amount>=0 && amount <= res->amount); + res->amount-=amount; + while (res->amount==0) { + double modifier = 1.0 + ((rng_int() % (SHIFT*2+1)) - SHIFT) * ((rng_int() % (SHIFT*2+1)) - SHIFT) / 10000.0; + int i; + + for (i=0;r->terrain->production[i].type;++i) { + if (res->type->rtype == r->terrain->production[i].type) break; + } + + ++res->level; + update_resource(res, modifier); + } +} + +struct rawmaterial * +rm_get(region * r, const struct resource_type * rtype) +{ + struct rawmaterial * rm = r->resources; + while (rm && rm->type->rtype!=rtype) rm = rm->next; + return rm; +} + +struct rawmaterial_type * rawmaterialtypes = 0; + +struct rawmaterial_type * +rmt_find(const char * str) +{ + rawmaterial_type * rmt = rawmaterialtypes; + while (rmt && strcmp(rmt->name, str)!=0) rmt = rmt->next; + return rmt; +} + +struct rawmaterial_type * +rmt_get(const struct resource_type * rtype) +{ + rawmaterial_type * rmt = rawmaterialtypes; + while (rmt && rmt->rtype!=rtype) rmt = rmt->next; + return rmt; +} + +struct rawmaterial_type * +rmt_create(const struct resource_type * rtype, const char * name) +{ + rawmaterial_type * rmtype = malloc(sizeof(rawmaterial_type)); + rmtype->name = strdup(name); + rmtype->rtype = rtype; + rmtype->terraform = terraform_default; + rmtype->update = NULL; + rmtype->use = use_default; + rmtype->visible = visible_default; + rmtype->next = rawmaterialtypes; + rawmaterialtypes = rmtype; + return rmtype; +} diff --git a/src/kernel/resources.h b/src/kernel/resources.h new file mode 100644 index 000000000..9c99ad6f8 --- /dev/null +++ b/src/kernel/resources.h @@ -0,0 +1,63 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#ifndef H_KRNL_RESOURCES +#define H_KRNL_RESOURCES +#ifdef __cplusplus +extern "C" { +#endif + +enum { + RM_USED = 1<<0, /* resource has been used */ + RM_MALLORN = 1<<1 /* this is not wood. it's mallorn */ +}; + +typedef struct rawmaterial { + const struct rawmaterial_type * type; + int amount : 16; + int level : 8; + int flags : 8; + int base : 8; + int divisor : 8; + int startlevel : 8; + struct rawmaterial * next; +} rawmaterial; + +typedef struct rawmaterial_type { + char * name; + const struct resource_type * rtype; + + void (*terraform) (struct rawmaterial *, const struct region *); + void (*update) (struct rawmaterial *, const struct region *); + void (*use) (struct rawmaterial *, const struct region *, int amount); + int (*visible) (const struct rawmaterial *, int skilllevel); + + /* no initialization required */ + struct rawmaterial_type * next; +} rawmaterial_type; + +extern struct rawmaterial_type * rawmaterialtypes; + +extern void update_resources(struct region * r); +extern void terraform_resources(struct region * r); +extern void read_resources(struct region * r); +extern void write_resources(struct region * r); +extern struct rawmaterial * rm_get(struct region *, const struct resource_type *); +extern struct rawmaterial_type * rmt_find(const char * str); +extern struct rawmaterial_type * rmt_get(const struct resource_type *); + +extern void add_resource(struct region * r, int level, int base, int divisor, const struct resource_type * rtype); +extern struct rawmaterial_type * rmt_create(const struct resource_type * rtype, const char * name); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/save.c b/src/kernel/save.c new file mode 100644 index 000000000..67c268d45 --- /dev/null +++ b/src/kernel/save.c @@ -0,0 +1,1890 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "save.h" + +#include "alchemy.h" +#include "alliance.h" +#include "connection.h" +#include "building.h" +#include "faction.h" +#include "group.h" +#include "item.h" +#include "magic.h" +#include "message.h" +#include "move.h" +#include "objtypes.h" +#include "order.h" +#include "pathfinder.h" +#include "plane.h" +#include "race.h" +#include "region.h" +#include "resources.h" +#include "ship.h" +#include "skill.h" +#include "spell.h" +#include "terrain.h" +#include "terrainid.h" /* only for conversion code */ +#include "unit.h" +#include "version.h" + +#include "textstore.h" +#include "binarystore.h" + +/* attributes includes */ +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +#define xisdigit(c) (((c) >= '0' && (c) <= '9') || (c) == '-') + +#define ESCAPE_FIX +#define MAXORDERS 256 +#define MAXPERSISTENT 128 + +/* exported symbols symbols */ +const char * game_name = "eressea"; +int firstx = 0, firsty = 0; +int enc_gamedata = 0; + +/* local symbols */ +static region * current_region; + +char * +rns(FILE * f, char *c, size_t size) +{ + char * s = c; + do { + *s = (char) getc(f); + } while (*s!='"'); + + for (;;) { + *s = (char) getc(f); + if (*s=='"') break; + if (s0) str+=ret; + else { + log_error(("input data was not iso-8859-1! assuming utf-8\n")); + encoding = XML_CHAR_ENCODING_ERROR; + *str++ = (char)c; + } + } else { + *str++ = (char)c; + } + } + } + break; + default: + if ((size_t)(str-start+1)0) str+=ret; + else { + log_error(("input data was not iso-8859-1! assuming utf-8\n")); + encoding = XML_CHAR_ENCODING_ERROR; + *str++ = (char)c; + } + } else { + *str++ = (char)c; + } + } + } + } +} + + +/** writes a quoted string to the file +* no trailing space, since this is used to make the creport. +*/ +int +fwritestr(FILE * F, const char * str) +{ + int nwrite = 0; + fputc('\"', F); + if (str) while (*str) { + int c = (int)(unsigned char)*str++; + switch (c) { + case '"': + case '\\': + fputc('\\', F); + fputc(c, F); + nwrite+=2; + break; + case '\n': + fputc('\\', F); + fputc('n', F); + nwrite+=2; + break; + default: + fputc(c, F); + ++nwrite; + } + } + fputc('\"', F); + return nwrite + 2; +} + +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->race == new_race[RC_SPELL]) return 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; + if (!is_repeated(ord)) { + *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]) { + const char * stok = s; + stok = parse_token(&stok); + + if (stok) { + boolean 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; + } + } + if (quit) break; + } + /* Nun wird der Befehl erzeut und eingehängt */ + *ordp = parse_order(s, u->faction->locale); + if (*ordp) ordp = &(*ordp)->next; + } + } + + } else { + /* cmistake(?, buf, 160, MSG_EVENT); */ + return NULL; + } + return u; +} + +static faction * +factionorders(void) +{ + faction * f = NULL; + int fid = getid(); + + f = findfaction(fid); + + if (f!=NULL && !is_monsters(f)) { + const char * pass = getstrtoken(); + + if (!checkpasswd(f, (const char *)pass, true)) { + log_warning(("Invalid password for faction %s\n", itoa36(fid))); + ADDMSG(&f->msgs, msg_message("wrongpasswd", "faction password", + f->no, pass)); + return 0; + } + /* Die Partei hat sich zumindest gemeldet, so daß sie noch + * nicht als untätig gilt */ + + /* TODO: +1 ist ein Workaround, weil cturn erst in process_orders + * incrementiert wird. */ + f->lastorders = global.data_turn+1; + + } else { + log_warning(("orders for invalid faction %s\n", itoa36(fid))); + } + return f; +} + +double +version(void) +{ + return RELEASE_VERSION * 0.1; +} +/* ------------------------------------------------------------- */ + +static param_t +igetparam (const char *s, const struct locale *lang) +{ + return findparam (igetstrtoken (s), lang); +} + +int +readorders(const char *filename) +{ + FILE * F = NULL; + const char *b; + int nfactions=0; + struct faction *f = NULL; + + if (filename) F = cfopen(filename, "rb"); + if (F==NULL) return 0; + + if (verbosity>=1) puts(" - lese Befehlsdatei...\n"); + + /* TODO: recognize UTF8 BOM */ + b = getbuf(F, enc_gamedata); + + /* Auffinden der ersten Partei, und danach abarbeiten bis zur letzten + * Partei */ + + while (b) { + const struct locale * lang = f?f->locale:default_locale; + int p; + const char * s; + + switch (igetparam(b, lang)) { + case P_LOCALE: + s = getstrtoken(); +#undef LOCALE_CHANGE +#ifdef LOCALE_CHANGE + if (f && find_locale(s)) { + f->locale = find_locale(s); + } +#endif + + b = getbuf(F, enc_gamedata); + break; + 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; + p = igetparam(b, lang); + } 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 + * muß buf erneut gefüllt werden, da die betreffende Information in nur + * einer Zeile steht, und nun die nächste gelesen werden muß. */ + + case P_NEXT: + f = NULL; + b = getbuf(F, enc_gamedata); + break; + + default: + b = getbuf(F, enc_gamedata); + break; + } + } + + fclose(F); + puts("\n"); + log_printf(" %d Befehlsdateien gelesen\n", nfactions); + return 0; +} +/* ------------------------------------------------------------- */ + +/* #define INNER_WORLD */ +/* fürs debuggen nur den inneren Teil der Welt laden */ +/* -9;-27;-1;-19;Sumpfloch */ +int +inner_world(region * r) +{ + static int xy[2] = + {18, -45}; + static int size[2] = + {27, 27}; + + if (r->x >= xy[0] && r->x < xy[0] + size[0] && r->y >= xy[1] && r->y < xy[1] + size[1]) + return 2; + if (r->x >= xy[0] - 9 && r->x < xy[0] + size[0] + 9 && r->y >= xy[1] - 9 && r->y < xy[1] + size[1] + 9) + return 1; + return 0; +} + +int maxregions = -1; +int loadplane = 0; + +enum { + U_MAN, + U_UNDEAD, + U_ILLUSION, + U_FIREDRAGON, + U_DRAGON, + U_WYRM, + U_SPELL, + U_TAVERNE, + U_MONSTER, + U_BIRTHDAYDRAGON, + U_TREEMAN, + MAXTYPES +}; + +race_t +typus2race(unsigned char typus) +{ + if (typus>0 && typus <=11) return (race_t)(typus-1); + return NORACE; +} + +void +create_backup(char *file) +{ +#ifdef HAVE_LINK + char bfile[MAX_PATH]; + int c = 1; + + if (access(file, R_OK) == 0) return; + do { + sprintf(bfile, "%s.backup%d", file, c); + c++; + } while(access(bfile, R_OK) == 0); + link(file, bfile); +#endif +} + +void +read_items(struct storage * store, item **ilist) +{ + for (;;) { + char ibuf[32]; + const item_type * itype; + int i; + store->r_str_buf(store, ibuf, sizeof(ibuf)); + if (!strcmp("end", ibuf)) break; + itype = it_find(ibuf); + i = store->r_int(store); + if (i<=0) { + log_error(("data contains an entry with %d %s\n", i, itype->rtype->_name[1])); + } else { + assert(itype!=NULL); + if (itype!=NULL) { + i_change(ilist, itype, i); + } + } + } +} + +static void +read_alliances(struct storage * store) +{ + char pbuf[8]; + int id, terminator = 0; + if (store->versionversionr_str_buf(store, pbuf, sizeof(pbuf)); + id = atoi36(pbuf); + } else { + id = store->r_id(store); + } + while (id!=terminator) { + char aname[128]; + alliance * al; + store->r_str_buf(store, aname, sizeof(aname)); + al = makealliance(id, aname); + if (store->version>=OWNER_2_VERSION) { + al->flags = store->r_int(store); + } + if (store->version>=ALLIANCELEADER_VERSION) { + read_reference(&al->_leader, store, read_faction_reference, resolve_faction); + id = store->r_id(store); + } else{ + store->r_str_buf(store, pbuf, sizeof(pbuf)); + id = atoi36(pbuf); + } + } +} + +void +write_alliances(struct storage * store) +{ + alliance * al = alliances; + while (al) { + if (al->_leader) { + store->w_id(store, al->id); + store->w_str(store, al->name); + store->w_int(store, (int)al->flags); + write_faction_reference(al->_leader, store); + store->w_brk(store); + } + al = al->next; + } + store->w_id(store, 0); + store->w_brk(store); +} + +void +write_items(struct storage * store, item *ilist) +{ + item * itm; + for (itm=ilist;itm;itm=itm->next) { + assert(itm->number>=0); + if (itm->number) { + store->w_tok(store, resourcename(itm->type->rtype, 0)); + store->w_int(store, itm->number); + } + } + store->w_tok(store, "end"); +} + +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)\n", itoa36(id.i))); + f = get_monsters(); + } + } + owner->owner = f; + if (f) { + owner->alliance = f->alliance; + } + return result; +} + +static void +read_owner(struct storage * store, region_owner **powner) +{ + int since_turn = store->r_int(store); + if (since_turn>=0) { + region_owner * owner = malloc(sizeof(region_owner)); + owner->since_turn = since_turn; + owner->morale_turn = store->r_int(store); + if (store->version>=MOURNING_VERSION) { + owner->flags = store->r_int(store); + } else { + owner->flags = 0; + } + if (store->version>=OWNER_2_VERSION) { + int id = store->r_int(store); + owner->alliance = id?findalliance(id):NULL; + } else { + owner->alliance = NULL; + } + read_reference(owner, store, &read_faction_reference, &resolve_owner); + *powner = owner; + } else { + *powner = 0; + } +} + +static void +write_owner(struct storage * store, region_owner *owner) +{ + if (owner) { + store->w_int(store, owner->since_turn); + store->w_int(store, owner->morale_turn); + store->w_int(store, owner->flags); + store->w_id(store, owner->alliance?owner->alliance->id:0); + write_faction_reference(owner->owner, store); + } else { + store->w_int(store, -1); + } +} + +int +current_turn(void) +{ + char zText[MAX_PATH]; + int cturn = 0; + FILE * f; + + sprintf(zText, "%s/turn", basepath()); + f = cfopen(zText, "r"); + if (f) { + fscanf(f, "%d\n", &cturn); + fclose(f); + } + return cturn; +} + +static void +writeorder(struct storage * store, const struct order * ord, const struct locale * lang) +{ + char obuf[1024]; + write_order(ord, obuf, sizeof(obuf)); + if (obuf[0]) store->w_str(store, obuf); +} + +unit * +read_unit(struct storage * store) +{ + skill_t sk; + unit * u; + int number, n, p; + order ** orderp; + char obuf[1024]; + faction * f; + char rname[32]; + + n = store->r_id(store); + if (n<=0) return NULL; + u = findunit(n); + if (u==NULL) { + u = calloc(sizeof(unit), 1); + u->no = n; + uhash(u); + } else { + while (u->attribs) a_remove(&u->attribs, u->attribs); + while (u->items) i_free(i_remove(&u->items, u->items)); + free(u->skills); + u->skills = 0; + u->skill_size = 0; + u_setfaction(u, NULL); + } + + n = store->r_id(store); + f = findfaction(n); + if (f!=u->faction) u_setfaction(u, f); + + u->name = store->r_str(store); + if (lomem) { + store->r_str_buf(store, NULL, 0); + } else { + u->display = store->r_str(store); + } + number = store->r_int(store); + u->age = (short)store->r_int(store); + + if (store->versionr_str_buf(store, rname, sizeof(rname)); + space = strchr(rname, ' '); + if (space!=NULL) { + char * inc = space+1; + char * outc = space; + do { + while (*inc==' ') ++inc; + while (*inc) { + *outc++ = *inc++; + if (*inc==' ') break; + } + } while (*inc); + *outc = 0; + } + } else { + store->r_tok_buf(store, rname, sizeof(rname)); + } + u->race = rc_find(rname); + assert(u->race); + if (store->versionr_str_buf(store, rname, sizeof(rname)); + } else { + store->r_tok_buf(store, rname, sizeof(rname)); + } + if (rname[0] && skill_enabled[SK_STEALTH]) u->irace = rc_find(rname); + else u->irace = NULL; + + if (u->race->describe) { + const char * rcdisp = u->race->describe(u, u->faction->locale); + if (u->display && rcdisp) { + /* see if the data file contains old descriptions */ + if (strcmp(rcdisp, u->display)==0) { + free(u->display); + u->display = NULL; + } + } + } + if (u->faction == NULL) { + log_error(("unit %s has faction == NULL\n", unitname(u))); + u_setfaction(u, get_monsters()); + set_number(u, 0); + } + + if (count_unit(u) && u->faction) u->faction->no_units++; + + set_number(u, number); + + n = store->r_id(store); + if (n>0) u->building = findbuilding(n); + + n = store->r_id(store); + if (n>0) u->ship = findship(n); + + setstatus(u, store->r_int(store)); + u->flags = store->r_int(store); + u->flags &= UFL_SAVEMASK; + if ((u->flags&UFL_ANON_FACTION) && !rule_stealth_faction()) { + /* if this rule is broken, then fix broken units */ + u->flags -= UFL_ANON_FACTION; + log_warning(("%s was anonymous.\n", unitname(u))); + } + /* Persistente Befehle einlesen */ + free_orders(&u->orders); + store->r_str_buf(store, obuf, sizeof(obuf)); + p = n = 0; + orderp = &u->orders; + while (obuf[0]) { + if (!lomem) { + order * ord = parse_order(obuf, u->faction->locale); + if (ord!=NULL) { + if (++nnext; + ord = NULL; + } else if (p==MAXPERSISTENT) { + log_warning(("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT)); + } + } else if (n==MAXORDERS) { + log_warning(("%s had %d or more orders\n", unitname(u), MAXORDERS)); + } + if (ord!=NULL) free_order(ord); + } + } + store->r_str_buf(store, obuf, sizeof(obuf)); + } + if (store->versionr_str_buf(store, obuf, sizeof(obuf)); + ord = parse_order(obuf, u->faction->locale); + if (ord!=NULL) { + addlist(&u->orders, ord); + } + } + set_order(&u->thisorder, NULL); + + assert(u->race); + while ((sk = (skill_t) store->r_int(store)) != NOSKILL) { + int level = store->r_int(store); + int weeks = store->r_int(store); + if (level) { + skill * sv = add_skill(u, sk); + sv->level = sv->old = (unsigned char)level; + sv->weeks = (unsigned char)weeks; + } + } + read_items(store, &u->items); + u->hp = store->r_int(store); + if (u->hp < u->number) { + log_error(("Einheit %s hat %u Personen, und %u Trefferpunkte\n", itoa36(u->no), + u->number, u->hp)); + u->hp=u->number; + } + + a_read(store, &u->attribs, u); + return u; +} + +void +write_unit(struct storage * store, const unit * u) +{ + order * ord; + int i, p = 0; + const race * irace = u_irace(u); + write_unit_reference(u, store); + write_faction_reference(u->faction, store); + store->w_str(store, (const char *)u->name); + store->w_str(store, u->display?(const char *)u->display:""); + store->w_int(store, u->number); + store->w_int(store, u->age); + store->w_tok(store, u->race->_name[0]); + store->w_tok(store, (irace && irace!=u->race)?irace->_name[0]:""); + write_building_reference(u->building, store); + write_ship_reference(u->ship, store); + store->w_int(store, u->status); + store->w_int(store, u->flags & UFL_SAVEMASK); + store->w_brk(store); + for (ord = u->old_orders; ord; ord=ord->next) { + if (++pfaction->locale); + } else { + log_error(("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT)); + break; + } + } + for (ord = u->orders; ord; ord=ord->next) { + if (u->old_orders && is_repeated(ord)) continue; /* has new defaults */ + if (is_persistent(ord)) { + if (++pfaction->locale); + } else { + log_error(("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT)); + break; + } + } + } + /* write an empty string to terminate the list */ + store->w_str(store, ""); + store->w_brk(store); + + assert(u->race); + + for (i=0;i!=u->skill_size;++i) { + skill * sv = u->skills+i; + assert(sv->weeks<=sv->level*2+1); + if (sv->level>0) { + store->w_int(store, sv->id); + store->w_int(store, sv->level); + store->w_int(store, sv->weeks); + } + } + store->w_int(store, -1); + store->w_brk(store); + write_items(store, u->items); + store->w_brk(store); + if (u->hp == 0) { + log_error(("unit %s has 0 hitpoints, adjusting.\n", itoa36(u->no))); + ((unit*)u)->hp = u->number; + } + store->w_int(store, u->hp); + store->w_brk(store); + a_write(store, u->attribs, u); + store->w_brk(store); +} + +static region * +readregion(struct storage * store, int x, int y) +{ + region * r = findregion(x, y); + const terrain_type * terrain; + char token[32]; + unsigned int uid = 0; + + if (store->version>=UID_VERSION) { + uid = store->r_int(store); + } + + if (r==NULL) { + plane * pl = findplane(x, y); + r = new_region(x, y, pl, uid); + } else { + assert(uid==0 || r->uid==uid); + current_region = r; + while (r->attribs) a_remove(&r->attribs, r->attribs); + if (r->land) { + free(r->land); /* mem leak */ + r->land->demands = 0; /* mem leak */ + } + while (r->resources) { + rawmaterial * rm = r->resources; + r->resources = rm->next; + free(rm); + } + r->land = 0; + } + if (lomem) { + store->r_str_buf(store, NULL, 0); + } else { + char info[DISPLAYSIZE]; + store->r_str_buf(store, info, sizeof(info)); + region_setinfo(r, info); + } + + if (store->version < TERRAIN_VERSION) { + int ter = store->r_int(store); + terrain = newterrain((terrain_t)ter); + if (terrain==NULL) { + log_error(("while reading datafile from pre-TERRAIN_VERSION, could not find terrain #%d.\n", ter)); + terrain = newterrain(T_PLAIN); + } + } else { + char name[64]; + store->r_str_buf(store, name, sizeof(name)); + terrain = get_terrain(name); + if (terrain==NULL) { + log_error(("Unknown terrain '%s'\n", name)); + assert(!"unknown terrain"); + } + } + r->terrain = terrain; + r->flags = (char) store->r_int(store); + + r->age = (unsigned short) store->r_int(store); + + if (fval(r->terrain, LAND_REGION)) { + r->land = calloc(1, sizeof(land_region)); + r->land->name = store->r_str(store); + } + if (r->land) { + int i; + rawmaterial ** pres = &r->resources; + + i = store->r_int(store); + if (i<0) { + log_error(("number of trees in %s is %d.\n", + regionname(r, NULL), i)); + i=0; + } + rsettrees(r, 0, i); + i = store->r_int(store); + if (i<0) { + log_error(("number of young trees in %s is %d.\n", + regionname(r, NULL), i)); + i=0; + } + rsettrees(r, 1, i); + i = store->r_int(store); + if (i<0) { + log_error(("number of seeds in %s is %d.\n", + regionname(r, NULL), i)); + i=0; + } + rsettrees(r, 2, i); + + i = store->r_int(store); rsethorses(r, i); + assert(*pres==NULL); + for (;;) { + rawmaterial * res; + store->r_str_buf(store, token, sizeof(token)); + if (strcmp(token, "end")==0) break; + res = malloc(sizeof(rawmaterial)); + res->type = rmt_find(token); + if (res->type==NULL) { + log_error(("invalid resourcetype %s in data.\n", token)); + } + assert(res->type!=NULL); + res->level = store->r_int(store); + res->amount = store->r_int(store); + res->flags = 0; + + res->startlevel = store->r_int(store); + res->base = store->r_int(store); + res->divisor = store->r_int(store); + + *pres = res; + pres=&res->next; + } + *pres = NULL; + + store->r_str_buf(store, token, sizeof(token)); + if (strcmp(token, "noherb") != 0) { + const resource_type * rtype = rt_find(token); + assert(rtype && rtype->itype && fval(rtype->itype, ITF_HERB)); + rsetherbtype(r, rtype->itype); + } else { + rsetherbtype(r, NULL); + } + rsetherbs(r, (short)store->r_int(store)); + rsetpeasants(r, store->r_int(store)); + rsetmoney(r, store->r_int(store)); + } + + assert(r->terrain!=NULL); + assert(rhorses(r) >= 0); + assert(rpeasants(r) >= 0); + assert(rmoney(r) >= 0); + + if (r->land) { + for (;;) { + const struct item_type * itype; + store->r_str_buf(store, token, sizeof(token)); + if (!strcmp(token, "end")) break; + itype = it_find(token); + assert(itype->rtype->ltype); + r_setdemand(r, itype->rtype->ltype, store->r_int(store)); + } + if (store->version>=REGIONITEMS_VERSION) { + read_items(store, &r->land->items); + } + if (store->version>=REGIONOWNER_VERSION) { + r->land->morale = (short)store->r_int(store); + if (r->land->morale<0) r->land->morale = 0; + read_owner(store, &r->land->ownership); + } + } + a_read(store, &r->attribs, r); + + return r; +} + +void +writeregion(struct storage * store, const region * r) +{ + store->w_int(store, r->uid); + store->w_str(store, region_getinfo(r)); + store->w_tok(store, r->terrain->_name); + store->w_int(store, r->flags & RF_SAVEMASK); + store->w_int(store, r->age); + store->w_brk(store); + if (fval(r->terrain, LAND_REGION)) { + const item_type *rht; + struct demand * demand; + rawmaterial * res = r->resources; + store->w_str(store, (const char *)r->land->name); + assert(rtrees(r,0)>=0); + assert(rtrees(r,1)>=0); + assert(rtrees(r,2)>=0); + store->w_int(store, rtrees(r,0)); + store->w_int(store, rtrees(r,1)); + store->w_int(store, rtrees(r,2)); + store->w_int(store, rhorses(r)); + + while (res) { + store->w_tok(store, res->type->name); + store->w_int(store, res->level); + store->w_int(store, res->amount); + store->w_int(store, res->startlevel); + store->w_int(store, res->base); + store->w_int(store, res->divisor); + res = res->next; + } + store->w_tok(store, "end"); + + rht = rherbtype(r); + if (rht) { + store->w_tok(store, resourcename(rht->rtype, 0)); + } else { + store->w_tok(store, "noherb"); + } + store->w_int(store, rherbs(r)); + store->w_int(store, rpeasants(r)); + store->w_int(store, rmoney(r)); + if (r->land) for (demand=r->land->demands; demand; demand=demand->next) { + store->w_tok(store, resourcename(demand->type->itype->rtype, 0)); + store->w_int(store, demand->value); + } + store->w_tok(store, "end"); +#if RELEASE_VERSION>=REGIONITEMS_VERSION + write_items(store, r->land->items); + store->w_brk(store); +#endif +#if RELEASE_VERSION>=REGIONOWNER_VERSION + store->w_int(store, r->land->morale); + write_owner(store, r->land->ownership); + store->w_brk(store); +#endif + } + a_write(store, r->attribs, r); + store->w_brk(store); +} + +static ally ** +addally(const faction * f, ally ** sfp, int aid, int state) +{ + struct faction * af = findfaction(aid); + ally * sf; + + state &= ~HELP_OBSERVE; +#ifndef REGIONOWNERS + state &= ~HELP_TRAVEL; +#endif + state &= HelpMask(); + + if (state==0) return sfp; + + sf = calloc(1, sizeof(ally)); + sf->faction = af; + if (!sf->faction) { + variant id; + id.i = aid; + ur_add(id, &sf->faction, resolve_faction); + } + sf->status = state & HELP_ALL; + + while (*sfp) sfp=&(*sfp)->next; + *sfp = sf; + return &sf->next; +} + +/** Reads a faction from a file. + * This function requires no context, can be called in any state. The + * faction may not already exist, however. + */ +faction * +readfaction(struct storage * store) +{ + ally **sfp; + int planes; + int i = store->r_id(store); + faction * f = findfaction(i); + char email[128]; + char token[32]; + + if (f==NULL) { + f = (faction *) calloc(1, sizeof(faction)); + f->no = i; + } else { + f->allies = NULL; /* mem leak */ + while (f->attribs) a_remove(&f->attribs, f->attribs); + } + f->subscription = store->r_int(store); + + if (alliances || store->version>=OWNER_2_VERSION) { + int allianceid = store->r_id(store); + if (allianceid>0) f->alliance = findalliance(allianceid); + if (f->alliance) { + alliance * al = f->alliance; + faction_list * flist = malloc(sizeof(faction_list)); + if (al->flags&ALF_NON_ALLIED) { + assert(!al->members || !"non-allied dummy-alliance has more than one member"); + } + flist->data = f; + flist->next = al->members; + al->members = flist; + } else if (rule_region_owners()){ + /* compat fix for non-allied factions */ + alliance * al = makealliance(0, NULL); + setalliance(f, al); + } + if (store->version>=OWNER_2_VERSION) { + f->alliance_joindate = store->r_int(store); + } else { + f->alliance_joindate = turn - 10; /* we're guessing something safe here */ + } + } + + f->name = store->r_str(store); + f->banner = store->r_str(store); + + log_info((3, " - Lese Partei %s (%s)\n", f->name, factionid(f))); + + store->r_str_buf(store, email, sizeof(email)); + if (set_email(&f->email, email)!=0) { + log_warning(("Invalid email address for faction %s: %s\n", itoa36(f->no), email)); + set_email(&f->email, ""); + } + + f->passw = store->r_str(store); + if (store->version >= OVERRIDE_VERSION) { + f->override = store->r_str(store); + } else { + f->override = strdup(itoa36(rng_int())); + } + + store->r_str_buf(store, token, sizeof(token)); + f->locale = find_locale(token); + f->lastorders = store->r_int(store); + f->age = store->r_int(store); + store->r_str_buf(store, token, sizeof(token)); + f->race = rc_find(token); + assert(f->race); + f->magiegebiet = (magic_t)store->r_int(store); + + if (store->versionr_int(store); + } + + f->flags = store->r_int(store); + if (f->no==0) { + f->flags |= FFL_NPC; + } + + a_read(store, &f->attribs, f); + if (store->version>=CLAIM_VERSION) { + read_items(store, &f->items); + } + for (;;) { + int level; + store->r_tok_buf(store, token, sizeof(token)); + if (strcmp("end", token)==0) break; + level = store->r_int(store); + } + planes = store->r_int(store); + while(--planes >= 0) { + int id = store->r_int(store); + int ux = store->r_int(store); + int uy = store->r_int(store); + set_ursprung(f, id, ux, uy); + } + f->newbies = 0; + + i = f->options = store->r_int(store); + + if ((i & (want(O_REPORT)|want(O_COMPUTER)))==0 && !is_monsters(f)) { + /* Kein Report eingestellt, Fehler */ + f->options = f->options | want(O_REPORT) | want(O_ZUGVORLAGE); + } + + sfp = &f->allies; + if (store->versionr_int(store); + while (--p >= 0) { + int aid = store->r_id(store); + int state = store->r_int(store); + sfp = addally(f, sfp, aid, state); + } + } else { + for (;;) { + int aid = 0; + if (store->versionr_tok_buf(store, token, sizeof(token)); + if (strcmp(token, "end")!=0) { + aid = atoi36(token); + } + } else { + aid = store->r_id(store); + } + if (aid>0) { + int state = store->r_int(store); + sfp = addally(f, sfp, aid, state); + } else { + break; + } + } + } + read_groups(store, f); + f->spellbook = NULL; + if (store->version>=REGIONOWNER_VERSION) { + read_spellist(&f->spellbook, f->magiegebiet, store); + } + return f; +} + +void +writefaction(struct storage * store, const faction * f) +{ + ally *sf; + ursprung *ur; + + write_faction_reference(f, store); + store->w_int(store, f->subscription); + if (f->alliance) { + store->w_id(store, f->alliance->id); + if (f->alliance->flags&ALF_NON_ALLIED) { + assert(f==f->alliance->_leader || !"non-allied faction is not leader of its own dummy-alliance."); + } + } + else { + store->w_id(store, 0); + } + store->w_int(store, f->alliance_joindate); + + store->w_str(store, (const char *)f->name); + store->w_str(store, (const char *)f->banner); + store->w_str(store, f->email); + store->w_tok(store, (const char *)f->passw); + store->w_tok(store, (const char *)f->override); + store->w_tok(store, locale_name(f->locale)); + store->w_int(store, f->lastorders); + store->w_int(store, f->age); + store->w_tok(store, f->race->_name[0]); + store->w_brk(store); + store->w_int(store, f->magiegebiet); + + store->w_int(store, f->flags&FFL_SAVEMASK); + a_write(store, f->attribs, f); + store->w_brk(store); + write_items(store, f->items); + store->w_brk(store); + store->w_tok(store, "end"); + store->w_brk(store); + store->w_int(store, listlen(f->ursprung)); + for (ur = f->ursprung;ur;ur=ur->next) { + store->w_int(store, ur->id); + store->w_int(store, ur->x); + store->w_int(store, ur->y); + } + store->w_brk(store); + store->w_int(store, f->options & ~want(O_DEBUG)); + store->w_brk(store); + + for (sf = f->allies; sf; sf = sf->next) { + int no = (sf->faction!=NULL)?sf->faction->no:0; + int status = alliedfaction(NULL, f, sf->faction, HELP_ALL); + if (status!=0) { + store->w_id(store, no); + store->w_int(store, sf->status); + } + } + store->w_id(store, 0); + store->w_brk(store); + write_groups(store, f->groups); + write_spelllist(f->spellbook, store); +} + +int +readgame(const char * filename, int mode, int backup) +{ + int i, n, p; + faction *f, **fp; + region *r; + building *b, **bp; + ship **shp; + unit *u; + int rmax = maxregions; + char path[MAX_PATH]; + char token[32]; + const struct building_type * bt_lighthouse = bt_find("lighthouse"); + storage my_store = (mode==IO_BINARY)?binary_store:text_store; + storage * store = &my_store; + + sprintf(path, "%s/%s", datapath(), filename); + log_printf("- reading game data from %s\n", filename); + if (backup) create_backup(path); + + store->encoding = enc_gamedata; + if (store->open(store, path, IO_READ)!=0) { + return -1; + } + enc_gamedata = store->encoding; + + assert(store->version>=MIN_VERSION || !"unsupported data format"); + assert(store->version<=RELEASE_VERSION || !"unsupported data format"); + + if (store->version >= SAVEXMLNAME_VERSION) { + char basefile[1024]; + + store->r_str_buf(store, basefile, sizeof(basefile)); + if (strcmp(game_name, basefile)!=0) { + char buffer[64]; + snprintf(buffer, sizeof(buffer), "%s.xml", game_name); + if (strcmp(basefile, buffer)!=0) { + log_warning(("game mismatch: datafile contains %s, game is %s\n", basefile, game_name)); + printf("WARNING: any key to continue, Ctrl-C to stop\n"); + getchar(); + } + } + } + a_read(store, &global.attribs, NULL); + global.data_turn = turn = store->r_int(store); + log_info((1, " - reading turn %d\n", turn)); + rng_init(turn); + ++global.cookie; + store->r_int(store); /* max_unique_id = */ + nextborder = store->r_int(store); + + /* Planes */ + planes = NULL; + n = store->r_int(store); + while(--n >= 0) { + int id = store->r_int(store); + plane *pl = getplanebyid(id); + if (pl==NULL) { + pl = calloc(1, sizeof(plane)); + } else { + log_warning(("the plane with id=%d already exists.\n", id)); + } + pl->id = id; + pl->name = store->r_str(store); + pl->minx = store->r_int(store); + pl->maxx = store->r_int(store); + pl->miny = store->r_int(store); + pl->maxy = store->r_int(store); + pl->flags = store->r_int(store); + + /* read watchers */ + store->r_str_buf(store, token, sizeof(token)); + while (strcmp(token, "end")!=0) { + watcher * w = calloc(sizeof(watcher),1); + variant fno; + fno.i = atoi36(token); + w->mode = (unsigned char)store->r_int(store); + w->next = pl->watchers; + pl->watchers = w; + ur_add(fno, &w->faction, resolve_faction); + store->r_str_buf(store, token, sizeof(token)); + } + + a_read(store, &pl->attribs, pl); + addlist(&planes, pl); + } + + /* Read factions */ + if (store->version>=ALLIANCES_VERSION) { + read_alliances(store); + } + n = store->r_int(store); + log_info((1, " - Einzulesende Parteien: %d\n", n)); + fp = &factions; + while (*fp) fp=&(*fp)->next; + + while (--n >= 0) { + faction * f = readfaction(store); + + *fp = f; + fp = &f->next; + fhash(f); + } + *fp = 0; + + /* Benutzte Faction-Ids */ + if (store->versionr_int(store); + while (i--) { + store->r_int(store); /* used faction ids. ignore. */ + } + } + + /* Regionen */ + + n = store->r_int(store); + assert(n= 0) { + unit **up; + int x = store->r_int(store); + int y = store->r_int(store); + + if ((n & 0x3FF) == 0) { /* das spart extrem Zeit */ + log_info((2, " - Einzulesende Regionen: %d/%d * %d,%d \r", rmax, n, x, y)); + } + --rmax; + + r = readregion(store, x, y); + + /* Burgen */ + p = store->r_int(store); + bp = &r->buildings; + + while (--p >= 0) { + + b = (building *) calloc(1, sizeof(building)); + b->no = store->r_id(store); + *bp = b; + bp = &b->next; + bhash(b); + b->name = store->r_str(store); + if (lomem) { + store->r_str_buf(store, NULL, 0); + } + else { + b->display = store->r_str(store); + } + b->size = store->r_int(store); + store->r_str_buf(store, token, sizeof(token)); + b->type = bt_find(token); + b->region = r; + a_read(store, &b->attribs, b); + if (b->type==bt_lighthouse) { + r->flags |= RF_LIGHTHOUSE; + } + } + /* Schiffe */ + + p = store->r_int(store); + shp = &r->ships; + + while (--p >= 0) { + ship * sh = (ship *) calloc(1, sizeof(ship)); + sh->region = r; + sh->no = store->r_id(store); + *shp = sh; + shp = &sh->next; + shash(sh); + sh->name = store->r_str(store); + if (lomem) { + store->r_str_buf(store, NULL, 0); + } + else { + sh->display = store->r_str(store); + } + store->r_str_buf(store, token, sizeof(token)); + sh->type = st_find(token); + if (sh->type==NULL) { + /* old datafiles */ + sh->type = st_find((const char *)locale_string(default_locale, token)); + } + assert(sh->type || !"ship_type not registered!"); + sh->size = store->r_int(store); + sh->damage = store->r_int(store); + if (store->version>=FOSS_VERSION) { + sh->flags = store->r_int(store); + } + + /* Attribute rekursiv einlesen */ + + sh->coast = (direction_t)store->r_int(store); + if (sh->type->flags & SFL_NOCOAST) { + sh->coast = NODIRECTION; + } + a_read(store, &sh->attribs, sh); + } + + *shp = 0; + + /* Einheiten */ + + p = store->r_int(store); + up = &r->units; + + while (--p >= 0) { + unit * u = read_unit(store); + sc_mage * mage; + + assert(u->region==NULL); + u->region = r; + *up = u; + up = &u->next; + + update_interval(u->faction, u->region); + mage = get_mage(u); + if (mage) { + faction * f = u->faction; + int skl = effskill(u, SK_MAGIC); + if (!is_monsters(f) && f->magiegebiet==M_GRAY) { + log_error(("faction %s had magic=gray, fixing (%s)\n", + factionname(f), magic_school[mage->magietyp])); + f->magiegebiet = mage->magietyp; + } + if (f->max_spelllevelmax_spelllevel = skl; + } + if (mage->spellcount<0) { + mage->spellcount = 0; + updatespelllist(u); + } + } + } + } + log_info((1, "\n")); + read_borders(store); + + store->close(store); + + /* Unaufgeloeste Zeiger initialisieren */ + log_info((1, "fixing unresolved references.\n")); + resolve(); + + log_info((1, "updating area information for lighthouses.\n")); + for (r=regions;r;r=r->next) { + if (r->flags & RF_LIGHTHOUSE) { + building * b; + for (b=r->buildings;b;b=b->next) update_lighthouse(b); + } + } + log_info((1, "marking factions as alive.\n")); + for (f = factions; f; f = f->next) { + if (f->flags & FFL_NPC) { + f->alive = 1; + if (f->no==0) { + int no=666; + while (findfaction(no)) ++no; + log_warning(("renum(monsters, %d)\n", no)); + renumber_faction(f, no); + } + } else { + for (u = f->units; u; u = u->nextF) { + if (u->number>0) { + f->alive = 1; + break; + } + } + } + } + if (loadplane || maxregions>=0) { + remove_empty_factions(); + } + log_info((1, "Done loading turn %d.\n", turn)); + return 0; +} + +static void +clear_monster_orders(void) +{ + faction * f = get_monsters(); + if (f) { + unit * u; + for (u=f->units;u;u=u->nextF) { + free_orders(&u->orders); + } + } +} + +int +writegame(const char *filename, int mode) +{ + char *base; + int n; + faction *f; + region *r; + building *b; + ship *sh; + unit *u; + plane *pl; + char path[MAX_PATH]; + storage my_store = (mode==IO_BINARY)?binary_store:text_store; + storage * store = &my_store; + store->version = RELEASE_VERSION; + + clear_monster_orders(); + sprintf(path, "%s/%s", datapath(), filename); +#ifdef HAVE_UNISTD_H + if (access(path, R_OK) == 0) { + /* make sure we don't overwrite some hardlinkedfile */ + unlink(path); + } +#endif + + store->encoding = enc_gamedata; + if (store->open(store, path, IO_WRITE)!=0) { + return -1; + } + + /* globale Variablen */ + + base = strrchr(game_name, '/'); + if (base) { + store->w_str(store, base+1); + } else { + store->w_str(store, game_name); + } + store->w_brk(store); + + a_write(store, global.attribs, NULL); + store->w_brk(store); + + store->w_int(store, turn); + store->w_int(store, 0/*max_unique_id*/); + store->w_int(store, nextborder); + + /* Write planes */ + store->w_brk(store); + store->w_int(store, listlen(planes)); + store->w_brk(store); + + for(pl = planes; pl; pl=pl->next) { + watcher * w; + store->w_int(store, pl->id); + store->w_str(store, pl->name); + store->w_int(store, pl->minx); + store->w_int(store, pl->maxx); + store->w_int(store, pl->miny); + store->w_int(store, pl->maxy); + store->w_int(store, pl->flags); + w = pl->watchers; + while (w) { + if (w->faction) { + write_faction_reference(w->faction, store); + store->w_int(store, w->mode); + } + w = w->next; + } + store->w_tok(store, "end"); + a_write(store, pl->attribs, pl); + store->w_brk(store); + } + + + /* Write factions */ +#if RELEASE_VERSION>=ALLIANCES_VERSION + write_alliances(store); +#endif + n = listlen(factions); + store->w_int(store, n); + store->w_brk(store); + + log_info((1, " - Schreibe %d Parteien...\n", n)); + for (f = factions; f; f = f->next) { + writefaction(store, f); + store->w_brk(store); + } + + /* Write regions */ + + n=listlen(regions); + store->w_int(store, n); + store->w_brk(store); + log_info((1, " - Schreibe Regionen: %d \r", n)); + + for (r = regions; r; r = r->next, --n) { + /* plus leerzeile */ + if ((n%1024)==0) { /* das spart extrem Zeit */ + log_info((2, " - Schreibe Regionen: %d \r", n)); + fflush(stdout); + } + store->w_brk(store); + store->w_int(store, r->x); + store->w_int(store, r->y); + writeregion(store, r); + + store->w_int(store, listlen(r->buildings)); + store->w_brk(store); + for (b = r->buildings; b; b = b->next) { + write_building_reference(b, store); + store->w_str(store, b->name); + store->w_str(store, b->display?b->display:""); + store->w_int(store, b->size); + store->w_tok(store, b->type->_name); + store->w_brk(store); + a_write(store, b->attribs, b); + store->w_brk(store); + } + + store->w_int(store, listlen(r->ships)); + store->w_brk(store); + for (sh = r->ships; sh; sh = sh->next) { + assert(sh->region == r); + write_ship_reference(sh, store); + store->w_str(store, (const char *)sh->name); + store->w_str(store, sh->display?(const char *)sh->display:""); + store->w_tok(store, sh->type->name[0]); + store->w_int(store, sh->size); + store->w_int(store, sh->damage); + store->w_int(store, sh->flags & SFL_SAVEMASK); + assert((sh->type->flags & SFL_NOCOAST)==0 || sh->coast == NODIRECTION); + store->w_int(store, sh->coast); + store->w_brk(store); + a_write(store, sh->attribs, sh); + store->w_brk(store); + } + + store->w_int(store, listlen(r->units)); + store->w_brk(store); + for (u = r->units; u; u = u->next) { + write_unit(store, u); + } + } + store->w_brk(store); + write_borders(store); + store->w_brk(store); + + store->close(store); + + log_info((1, "\nOk.\n")); + return 0; +} + +int +a_readint(attrib * a, void * owner, struct storage * store) +{ + /* assert(sizeof(int)==sizeof(a->data)); */ + a->data.i = store->r_int(store); + return AT_READ_OK; +} + +void +a_writeint(const attrib * a, const void * owner, struct storage * store) +{ + store->w_int(store, a->data.i); +} + +int +a_readshorts(attrib * a, void * owner, struct storage * store) +{ + if (store->versiondata.sa[0] = (short)store->r_int(store); + a->data.sa[1] = (short)store->r_int(store); + return AT_READ_OK; +} + +void +a_writeshorts(const attrib * a, const void * owner, struct storage * store) +{ + store->w_int(store, a->data.sa[0]); + store->w_int(store, a->data.sa[1]); +} + +int +a_readchars(attrib * a, void * owner, struct storage * store) +{ + int i; + if (store->versiondata.ca[i] = (char)store->r_int(store); + } + return AT_READ_OK; +} + +void +a_writechars(const attrib * a, const void * owner, struct storage * store) +{ + int i; + + for (i=0;i!=4;++i) { + store->w_int(store, a->data.ca[i]); + } +} + +int +a_readvoid(attrib * a, void * owner, struct storage * store) +{ + if (store->versiondata.v = store->r_str(store); + return AT_READ_OK; +} + +void +a_writestring(const attrib * a, const void * owner, struct storage * store) +{ + assert(a->data.v); + store->w_str(store, (const char *)a->data.v); +} + +void +a_finalizestring(attrib * a) +{ + free(a->data.v); +} diff --git a/src/kernel/save.h b/src/kernel/save.h new file mode 100644 index 000000000..4f10e7090 --- /dev/null +++ b/src/kernel/save.h @@ -0,0 +1,73 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_SAVE +#define H_KRNL_SAVE +#ifdef __cplusplus +extern "C" { +#endif + +double version(void); + +#define MAX_INPUT_SIZE DISPLAYSIZE*2 +/* Nach MAX_INPUT_SIZE brechen wir das Einlesen der Zeile ab und nehmen an, + * dass hier ein Fehler (fehlende ") vorliegt */ + +FILE * cfopen(const char *filename, const char *mode); +int readorders(const char *filename); +int creategame(void); +extern int readgame(const char * filename, int mode, int backup); +int writegame(const char *filename, int mode); + +extern void rsf(FILE * F, char *s, size_t len); + +/* Versionsänderungen: */ +extern int data_version; +extern const char *game_name; +extern int enc_gamedata; + +extern void init_locales(void); +extern int current_turn(void); + +extern void read_items(struct storage * store, struct item **it); +extern void write_items(struct storage * store, struct item *it); + +extern void write_unit(struct storage * store, const struct unit * u); +extern struct unit * read_unit(struct storage * store); + +extern int a_readint(struct attrib * a, void * owner, struct storage * store); +extern void a_writeint(const struct attrib * a, const void * owner, struct storage * store); +extern int a_readshorts(struct attrib * a, void * owner, struct storage * store); +extern void a_writeshorts(const struct attrib * a, const void * owner, struct storage * store); +extern int a_readchars(struct attrib * a, void * owner, struct storage * store); +extern void a_writechars(const struct attrib * a, const void * owner, struct storage * store); +extern int a_readvoid(struct attrib * a, void * owner, struct storage * store); +extern void a_writevoid(const struct attrib * a, const void * owner, struct storage * store); +extern int a_readstring(struct attrib * a, void * owner, struct storage * store); +extern void a_writestring(const struct attrib * a, const void * owner, struct storage * store); +extern void a_finalizestring(struct attrib * a); + +extern int freadstr(FILE * F, int encoding, char * str, size_t size); +extern int fwritestr(FILE * F, const char * str); + +extern void create_backup(char *file); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/ship.c b/src/kernel/ship.c new file mode 100644 index 000000000..5cf96aa3c --- /dev/null +++ b/src/kernel/ship.c @@ -0,0 +1,338 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "ship.h" + +/* kernel includes */ +#include "build.h" +#include "unit.h" +#include "item.h" +#include "race.h" +#include "region.h" +#include "skill.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + + +ship_typelist *shiptypes = NULL; + +static local_names * snames; + +const ship_type * +findshiptype(const char * name, const struct locale * lang) +{ + local_names * sn = snames; + variant var; + + while (sn) { + if (sn->lang==lang) break; + sn=sn->next; + } + if (!sn) { + struct ship_typelist * stl = shiptypes; + sn = calloc(sizeof(local_names), 1); + sn->next = snames; + sn->lang = lang; + while (stl) { + variant var; + const char * n = locale_string(lang, stl->type->name[0]); + var.v = (void*)stl->type; + addtoken(&sn->names, n, var); + stl = stl->next; + } + snames = sn; + } + if (findtoken(&sn->names, name, &var)==E_TOK_NOMATCH) return NULL; + return (const ship_type*)var.v; +} + +const ship_type * +st_find(const char* name) +{ + const struct ship_typelist * stl = shiptypes; + while (stl && strcmp(stl->type->name[0], name)) stl = stl->next; + return stl?stl->type:NULL; +} + +void +st_register(const ship_type * type) { + struct ship_typelist * stl = malloc(sizeof(ship_type)); + stl->type = type; + stl->next = shiptypes; + shiptypes = stl; +} + +#define SMAXHASH 7919 +ship *shiphash[SMAXHASH]; +void +shash(ship * s) +{ + ship *old = shiphash[s->no % SMAXHASH]; + + shiphash[s->no % SMAXHASH] = s; + s->nexthash = old; +} + +void +sunhash(ship * s) +{ + ship **show; + + for (show = &shiphash[s->no % SMAXHASH]; *show; show = &(*show)->nexthash) { + if ((*show)->no == s->no) + break; + } + if (*show) { + assert(*show == s); + *show = (*show)->nexthash; + s->nexthash = 0; + } +} + +static ship * +sfindhash(int i) +{ + ship *old; + + for (old = shiphash[i % SMAXHASH]; old; old = old->nexthash) + if (old->no == i) + return old; + return 0; +} + +struct ship * +findship(int i) +{ + return sfindhash(i); +} + +struct ship * +findshipr(const region *r, int n) +{ + ship * sh; + + for (sh = r->ships; sh; sh = sh->next) { + if (sh->no == n) { + assert(sh->region == r); + return sh; + } + } + return 0; +} + +void +damage_ship(ship * sh, double percent) +{ + double damage = DAMAGE_SCALE * sh->type->damage * percent * sh->size + sh->damage; + sh->damage = (int)damage; +} + +unit * +captain(ship *sh) +{ + unit *u; + + for(u = sh->region->units; u; u = u->next) + if(u->ship == sh && fval(u, UFL_OWNER)) return u; + + return NULL; +} + +/* Alte Schiffstypen: */ +static ship * deleted_ships; + +ship * +new_ship(const ship_type * stype, const struct locale * lang, region * r) +{ + static char buffer[7 + IDSIZE + 1]; + ship *sh = (ship *) calloc(1, sizeof(ship)); + + assert(stype); + sh->no = newcontainerid(); + sh->coast = NODIRECTION; + sh->type = stype; + sh->region = r; + + sprintf(buffer, "%s %s", LOC(lang, stype->name[0]), shipid(sh)); + sh->name = strdup(buffer); + shash(sh); + addlist(&r->ships, sh); + return sh; +} + +void +remove_ship(ship ** slist, ship * sh) +{ + region * r = sh->region; + unit * u = r->units; + + handle_event(sh->attribs, "destroy", sh); + while (u) { + if (u->ship == sh) { + leave_ship(u); + } + u = u->next; + } + sunhash(sh); + while (*slist && *slist!=sh) slist = &(*slist)->next; + assert(*slist); + *slist = sh->next; + sh->next = deleted_ships; + deleted_ships = sh; + sh->region = NULL; +} + +void +free_ship(ship * s) +{ + while (s->attribs) a_remove(&s->attribs, s->attribs); + free(s->name); + free(s->display); + free(s); +} + +void +free_ships(void) +{ + while (deleted_ships) { + ship * s = deleted_ships; + deleted_ships = s->next; + } +} + +const char * +write_shipname(const ship * sh, char * ibuf, size_t size) +{ + snprintf(ibuf, size, "%s (%s)", sh->name, itoa36(sh->no)); + ibuf[size-1] = 0; + return ibuf; +} + +const char * +shipname(const ship * sh) +{ + typedef char name[OBJECTIDSIZE + 1]; + static name idbuf[8]; + static int nextbuf = 0; + char *ibuf = idbuf[(++nextbuf) % 8]; + return write_shipname(sh, ibuf, sizeof(name)); +} + +int +shipcapacity (const ship * sh) +{ + int i = sh->type->cargo; + + /* sonst ist construction:: size nicht ship_type::maxsize */ + assert(!sh->type->construction || sh->type->construction->improvement==NULL); + + if (sh->type->construction && sh->size!=sh->type->construction->maxsize) + return 0; + +#ifdef SHIPDAMAGE + if (sh->damage) { + i = (int)ceil(i * (1.0 - sh->damage / sh->size / (double)DAMAGE_SCALE)); + } +#endif + return i; +} + +void +getshipweight(const ship * sh, int *sweight, int *scabins) +{ + unit * u; + + *sweight = 0; + *scabins = 0; + + for (u = sh->region->units; u; u = u->next) { + if (u->ship == sh) { + *sweight += weight(u); + if (sh->type->cabins) { + int pweight = u->number * u->race->weight; + /* weight goes into number of cabins, not cargo */ + *scabins += pweight; + *sweight -= pweight; + } + } + } +} + +unit * +shipowner(const ship * sh) +{ + unit *u; + unit *first = NULL; + + const region * r = sh->region; + + /* Prüfen ob Eigentümer am leben. */ + for (u = r->units; u; u = u->next) { + if (u->ship == sh) { + if (!first && u->number > 0) + first = u; + if (fval(u, UFL_OWNER) && u->number > 0) + return u; + if (u->number == 0) + freset(u, UFL_OWNER); + } + } + + /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit + * nehmen. */ + + if (first) + fset(first, UFL_OWNER); + return first; +} + +void +write_ship_reference(const struct ship * sh, struct storage * store) +{ + store->w_id(store, (sh && sh->region)?sh->no:0); +} + +void +ship_setname(ship * self, const char * name) +{ + free(self->name); + if (name) self->name = strdup(name); + else self->name = NULL; +} + +const char * +ship_getname(const ship * self) +{ + return self->name; +} diff --git a/src/kernel/ship.h b/src/kernel/ship.h new file mode 100644 index 000000000..0bc8ee9d4 --- /dev/null +++ b/src/kernel/ship.h @@ -0,0 +1,127 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_SHIP +#define H_KRNL_SHIP +#ifdef __cplusplus +extern "C" { +#endif + +#include "types.h" + +#define DAMAGE_SCALE 100 /* multiplier for sh->damage */ + +/* ship_type::flags */ +#define SFL_OPENSEA 0x01 +#define SFL_FLY 0x02 +#define SFL_NOCOAST 0x04 + +typedef struct ship_type { + const char * name[2]; + + int range; /* range in regions */ + int flags; /* flags */ + int combat; /* modifier for combat */ + + double storm; /* multiplier for chance to drift in storm */ + double damage; /* multiplier for damage taken by the ship */ + + int cabins; /* max. cabins (weight) */ + int cargo; /* max. cargo (weight) */ + + int cptskill; /* min. skill of captain */ + int minskill; /* min. skill to sail this (crew) */ + int sumskill; /* min. sum of crew+captain */ + + int fishing; /* weekly income from fishing */ + + int at_bonus; /* Verändert den Angriffsskill (default: 0)*/ + int df_bonus; /* Verändert den Verteidigungskill (default: 0)*/ + float tac_bonus; + + const struct terrain_type ** coasts; /* coast that this ship can land on */ + + struct construction * construction; /* how to build a ship */ +} ship_type; + +typedef struct ship_typelist { + struct ship_typelist * next; + const ship_type * type; +} ship_typelist; + +extern ship_typelist *shiptypes; + +/* Alte Schiffstypen: */ + +extern const ship_type * st_find(const char* name); +extern void st_register(const ship_type * type); + +#define NOSHIP NULL + +#define SF_DRIFTED 1<<0 +#define SF_MOVED 1<<1 +#define SF_DAMAGED 1<<2 /* for use in combat */ +#define SF_SELECT 1<<3 /* previously FL_DH */ +#define SF_FISHING 1<<4 /* was on an ocean, can fish */ +#define SF_FLYING 1<<5 /* the ship can fly */ + +#define SFL_SAVEMASK (SF_FLYING) +#define INCOME_FISHING 10 + +typedef struct ship { + struct ship *next; + struct ship *nexthash; + int no; + struct region *region; + char *name; + char *display; + struct attrib * attribs; + int size; + int damage; /* damage in 100th of a point of size */ + unsigned int flags; + const struct ship_type * type; + direction_t coast; +} ship; + +extern void damage_ship(ship *sh, double percent); +extern struct unit *captain(ship *sh); +extern struct unit *shipowner(const struct ship * sh); +extern const char * shipname(const struct ship * self); +extern int shipcapacity(const struct ship * sh); +extern void getshipweight(const struct ship * sh, int *weight, int *cabins); + +extern ship *new_ship(const struct ship_type * stype, const struct locale * lang, struct region * r); +extern const char *write_shipname(const struct ship * sh, char * buffer, size_t size); +extern struct ship *findship(int n); +extern struct ship *findshipr(const struct region *r, int n); + +extern const struct ship_type * findshiptype(const char *s, const struct locale * lang); + +extern void write_ship_reference(const struct ship * sh, struct storage * store); + +extern void remove_ship(struct ship ** slist, struct ship * s); +extern void free_ship(struct ship * s); +extern void free_ships(void); + +extern const char * ship_getname(const struct ship * self); +extern void ship_setname(struct ship * self, const char * name); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/skill.c b/src/kernel/skill.c new file mode 100644 index 000000000..5f8d053d4 --- /dev/null +++ b/src/kernel/skill.c @@ -0,0 +1,315 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "skill.h" + +#include "curse.h" +#include "item.h" +#include "magic.h" +#include "race.h" +#include "region.h" +#include "terrain.h" +#include "terrainid.h" +#include "unit.h" + +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +const char *skillnames[MAXSKILLS] = +{ + "alchemy", + "crossbow", + "mining", + "bow", + "building", + "trade", + "forestry", + "catapult", + "herbalism", + "magic", + "training", + "riding", + "armorer", + "shipcraft", + "melee", + "sailing", + "polearm", + "espionage", + "quarrying", + "roadwork", + "tactics", + "stealth", + "entertainment", + "weaponsmithing", + "cartmaking", + "perception", + "taxation", + "stamina", + "unarmed" +}; + +boolean skill_enabled[MAXSKILLS]; + +const char * +skillname(skill_t sk, const struct locale * lang) +{ + if (skill_enabled[sk]) { + return locale_string(lang, mkname("skill", skillnames[sk])); + } + return NULL; +} + +void +enable_skill(const char * skname, boolean value) +{ + skill_t sk; + for (sk=0;sk!=MAXSKILLS;++sk) { + if (strcmp(skillnames[sk], skname)==0) { + skill_enabled[sk] = value; + return; + } + } + log_error(("Trying to set unknown skill %s to %u", skname, value)); +} + +skill_t +sk_find(const char * name) +{ + skill_t i; + if (name==NULL) return NOSKILL; + if (strncmp(name, "sk_", 3)==0) name+=3; + for (i=0;i!=MAXSKILLS;++i) { + if (skill_enabled[i]) { + if (strcmp(name, skillnames[i])==0) return i; + } + } + return NOSKILL; +} + +/** skillmod attribut **/ +static void +init_skillmod(attrib * a) { + a->data.v = calloc(sizeof(skillmod_data), 1); +} + +static void +finalize_skillmod(attrib * a) +{ + free(a->data.v); +} + +/** temporary skill modification (NOT SAVED!). */ +attrib_type at_skillmod = { + "skillmod", + init_skillmod, + finalize_skillmod, + NULL, + NULL, /* can't write function pointers */ + NULL, /* can't read function pointers */ + ATF_PRESERVE +}; + +attrib * +make_skillmod(skill_t sk, unsigned int flags, skillmod_fun special, double multiplier, int bonus) +{ + attrib * a = a_new(&at_skillmod); + skillmod_data * smd = (skillmod_data*)a->data.v; + + smd->skill=sk; + smd->special=special; + smd->bonus=bonus; + smd->multiplier=multiplier; + smd->flags=flags; + + return a; +} + +int +skillmod(const attrib * a, const unit * u, const region * r, skill_t sk, int value, int flags) +{ + for (a = a_find((attrib*)a, &at_skillmod); a && a->type==&at_skillmod; a=a->next) { + skillmod_data * smd = (skillmod_data *)a->data.v; + if (smd->skill!=NOSKILL && smd->skill!=sk) continue; + if (flags!=SMF_ALWAYS && (smd->flags & flags) == 0) continue; + if (smd->special) { + value = smd->special(u, r, sk, value); + if (value<0) return value; /* pass errors back to caller */ + } + if (smd->multiplier) value = (int)(value*smd->multiplier); + value += smd->bonus; + } + return value; +} + +int +skill_mod(const race * rc, skill_t sk, const struct terrain_type * terrain) +{ + int result = 0; + + result = rc->bonus[sk]; + + if (rc == new_race[RC_DWARF]) { + if (sk==SK_TACTICS) { + if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION)) + ++result; + } + } + else if (rc == new_race[RC_INSECT]) { + if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION)) + --result; + else if (terrain == newterrain(T_DESERT) || terrain == newterrain(T_SWAMP)) + ++result; + } + + return result; +} + +#define RCMODMAXHASH 31 +#ifdef FASTER_SKILLMOD +static struct skillmods { + struct skillmods * next; + const struct race * race; + struct modifiers { + int value[MAXSKILLS]; + } mod[MAXTERRAINS]; +} * modhash[RCMODMAXHASH]; + +static struct skillmods * +init_skills(const race * rc) +{ + terrain_t t; + struct skillmods *mods = (struct skillmods*)calloc(1, sizeof(struct skillmods)); + mods->race = rc; + + for (t=0;t!=MAXTERRAINS;++t) { + skill_t sk; + for (sk=0;sk!=MAXSKILLS;++sk) { + mods->mod[t].value[sk] = skill_mod(rc, sk, newterrain(t)); + } + } + return mods; +} +#endif + +int +rc_skillmod(const struct race * rc, const region *r, skill_t sk) +{ + int mods; + + if (!skill_enabled[sk]) return 0; +#ifdef FASTER_SKILLMOD + unsigned int index = hashstring(rc->_name[0]) % RCMODMAXHASH; + struct skillmods **imods = &modhash[index]; + while (*imods && (*imods)->race!=rc) imods = &(*imods)->next; + if (*imods==NULL) { + *imods = init_skills(rc); + } + mods = (*imods)->mod[rterrain(r)].value[sk]; +#else + mods = skill_mod(rc, sk, r->terrain); +#endif + if (rc == new_race[RC_ELF] && r_isforest(r)) switch (sk) { + case SK_PERCEPTION: + ++mods; + break; + case SK_STEALTH: + if (r_isforest(r)) ++mods; + break; + case SK_TACTICS: + if (r_isforest(r)) mods += 2; + break; + } + + return mods; +} + +int +level_days(int level) +{ + return 30 * ((level+1) * level / 2); +} + +int +level(int days) +{ + int i; + static int ldays[64]; + static boolean init = false; + if (!init) { + init = true; + for (i=0;i!=64;++i) ldays[i] = level_days(i+1); + } + for (i=0;i!=64;++i) if (ldays[i]>days) return i; + return i; +} + +void +sk_set(skill * sv, int level) +{ + assert(level!=0); + sv->weeks = (unsigned char)skill_weeks(level); + sv->level = (unsigned char)level; +} + +int +skill_weeks(int level) +/* how many weeks must i study to get from level to level+1 */ +{ + int coins = 2*level; + int heads = 1; + while (coins--) { + heads += rng_int() % 2; + } + return heads; +} + +void +reduce_skill(unit * u, skill * sv, unsigned int weeks) +{ + sv->weeks+=weeks; + while (sv->level>0 && sv->level*2+1weeks) { + sv->weeks -= sv->level; + --sv->level; + } + if (sv->level==0) { + /* reroll */ + sv->weeks = (unsigned char)skill_weeks(sv->level); + } +} + + +int +skill_compare(const skill * sk, const skill * sc) +{ + if (sk->level > sc->level) return 1; + if (sk->level < sc->level) return -1; + if (sk->weeks < sc->weeks) return 1; + if (sk->weeks > sc->weeks) return -1; + return 0; +} diff --git a/src/kernel/skill.h b/src/kernel/skill.h new file mode 100644 index 000000000..1ed5c6ad6 --- /dev/null +++ b/src/kernel/skill.h @@ -0,0 +1,66 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + */ + +#ifndef H_KRNL_SKILL +#define H_KRNL_SKILL +#ifdef __cplusplus +extern "C" { +#endif + +extern signed char skill_bonus(struct unit * u, struct region * r); + +/* skillmod_data::flags -- wann gilt der modifier? */ +#define SMF_ALWAYS (1<<0) /* immer */ +#define SMF_PRODUCTION (1<<1) /* für Produktion - am gebäude, an der einheit */ +#define SMF_RIDING (1<<2) /* Bonus für berittene - an der rasse*/ + +typedef struct skill { + unsigned char id; + unsigned int level : 8; + unsigned int weeks : 8; + unsigned int old : 8; +} skill; + +typedef int (*skillmod_fun)(const struct unit*, const struct region*, skill_t, int); +typedef struct skillmod_data { + skill_t skill; + skillmod_fun special; + double multiplier; + int number; + int bonus; + int flags; +} skillmod_data; +extern struct attrib_type at_skillmod; +extern int rc_skillmod(const struct race * rc, const struct region *r, skill_t sk); +extern int skillmod(const struct attrib * a, const struct unit * u, const struct region * r, skill_t sk, int value, int flags); +extern struct attrib * make_skillmod(skill_t sk, unsigned int flags, skillmod_fun special, double multiplier, int bonus); + +extern const char * skillname(skill_t, const struct locale *); +extern skill_t sk_find(const char * name); +extern void enable_skill(const char * name, boolean value); +extern int level_days(int level); +extern int level(int days); + +#define skill_level(level) (level) +extern void reduce_skill(struct unit *u, skill * sv, unsigned int change); +extern int skill_weeks(int level); +extern int skill_compare(const skill * sk, const skill * sc); + +extern void sk_set(skill * sv, int level); + +extern const char *skillnames[]; +extern boolean skill_enabled[]; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/spell.c b/src/kernel/spell.c new file mode 100644 index 000000000..7bd05cf15 --- /dev/null +++ b/src/kernel/spell.c @@ -0,0 +1,184 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "spell.h" + +/* kernel includes */ +#include "magic.h" +#include "unit.h" + +/* libc includes */ +#include +#include + +/* util includes */ +#include +#include +#include +#include + + /* Bitte die Sprüche nach Gebieten und Stufe ordnen, denn in derselben + * Reihenfolge wie in Spelldaten tauchen sie auch im Report auf + */ + +spell_list * spells = NULL; + +void +register_spell(spell * sp) +{ + if (sp->id==0) { + sp->id = hashstring(sp->sname); + } + spelllist_add(&spells, sp); +} + +/** versucht einen Spruch über gebiet + name zu identifizieren. + * gibt ansonsten NULL zurück */ +spell * +find_spell(magic_t mtype, const char * name) +{ + spell_list * slist = spells; + spell * spx = NULL; + while (slist) { + spell * sp = slist->data; + if (strcmp(name, sp->sname)==0) { + if (mtype==M_NONE || sp->magietyp==mtype) return sp; + spx = sp; + } + slist = slist->next; + } + if (spx==NULL) { + log_error(("cannot find spell by name: %s\n", name)); + } + return spx; +} + + +/* ------------------------------------------------------------- */ +/* Spruch identifizieren */ + +typedef struct spell_names { + struct spell_names * next; + const struct locale * lang; + magic_t mtype; + struct tnode names; +} spell_names; + +static spell_names * spellnames; + +static spell_names * +init_spellnames(const struct locale * lang, magic_t mtype) +{ + spell_list * slist; + spell_names * sn = calloc(sizeof(spell_names), 1); + sn->next = spellnames; + sn->lang = lang; + sn->mtype = mtype; + for (slist=spells;slist!=NULL;slist=slist->next) { + spell * sp = slist->data; + if (sp->magietyp==mtype) { + const char * n = spell_name(sp, lang); + variant token; + token.v = sp; + addtoken(&sn->names, n, token); + } + } + return spellnames = sn; +} + +static spell_names * +get_spellnames(const struct locale * lang, magic_t mtype) +{ + spell_names * sn = spellnames; + while (sn) { + if (sn->mtype==mtype && sn->lang==lang) break; + sn=sn->next; + } + if (!sn) return init_spellnames(lang, mtype); + return sn; +} + +static spell * +get_spellfromtoken_i(const char *name, const struct locale * lang, magic_t mtype) +{ + variant token = { 0 }; + spell_names * sn; + + sn = get_spellnames(lang, mtype); + if (findtoken(&sn->names, name, &token)==E_TOK_NOMATCH) { + magic_t mt; + /* if we could not find it in the main magic type, we look through all the others */ + for (mt=0;mt!=MAXMAGIETYP;++mt) { + if (mt!=mtype) { + sn = get_spellnames(lang, mt); + if (findtoken(&sn->names, name, &token)!=E_TOK_NOMATCH) break; + } + } + } + + if (token.v!=NULL) return (spell*)token.v; + if (lang==default_locale) return NULL; + return get_spellfromtoken_i(name, default_locale, mtype); +} + +spell * +get_spellfromtoken(unit *u, const char *name, const struct locale * lang) +{ + sc_mage * m = get_mage(u); + spell * sp; + + if (m==NULL) return NULL; + sp = get_spellfromtoken_i(name, lang, m->magietyp); + if (sp!=NULL) { + spell_list * slist = m->spells; + + while (slist && slist->data->id<=sp->id) { + if (sp==slist->data) return sp; + slist = slist->next; + } + } + return NULL; +} + +spell * +find_spellbyid(magic_t mtype, spellid_t id) +{ + spell_list * slist; + + assert(id>=0); + if (id==0) return NULL; + for (slist=spells;slist!=NULL;slist=slist->next) { + spell* sp = slist->data; + if (sp->id == id) return sp; + } + for (slist=spells;slist!=NULL;slist=slist->next) { + spell* sp = slist->data; + unsigned int hashid = hashstring(sp->sname); + if (hashid==id) { + if (sp->magietyp==mtype || mtype==M_NONE) { + return sp; + } + } + } + + log_warning(("cannot find spell by id: %u\n", id)); + return NULL; +} + diff --git a/src/kernel/spell.h b/src/kernel/spell.h new file mode 100644 index 000000000..9a250deb0 --- /dev/null +++ b/src/kernel/spell.h @@ -0,0 +1,159 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_SPELL +#define H_KRNL_SPELL +#ifdef __cplusplus +extern "C" { +#endif + + struct fighter; + struct spell; + struct border_type; + struct attrib_type; + struct curse_type; + struct castorder; + struct curse; + + /* Prototypen */ + + int use_item_power(struct region * r, struct unit * u); + int use_item_regeneration(struct region * r, struct unit * u); + void showspells(struct region *r, struct unit *u); + int sp_antimagiczone(struct castorder *co); + + /* ------------------------------------------------------------- */ + + extern struct attrib_type at_unitdissolve; + extern struct attrib_type at_wdwpyramid; + + extern struct spell_list * spells; + extern void register_spell(struct spell * sp); + extern struct spell * find_spell(magic_t mtype, const char * name); + extern struct spell * find_spellbyid(magic_t mtype, spellid_t i); + extern struct spell *get_spellfromtoken(struct unit *u, const char *s, const struct locale * lang); + +#ifdef __cplusplus +} +#endif +#endif + +/* ------------------------------------------------------------- */ +/* Erläuterungen zu den Spruchdefinitionen + * + * Spruchstukturdefinition: + * spell{ + * id, name, + * beschreibung, + * syntax, + * parameter, + * magietyp, + * sptyp, + * rank,level, + * costtyp, aura, + * komponenten[5][2][faktorart], + * &funktion, patzer} + * + * id: + * SPL_NOSPELL muss der letzte Spruch in der Liste spelldaten sein, + * denn nicht auf die Reihenfolge in der Liste sondern auf die id wird + * geprüft + * + * sptyp: + * besondere Spruchtypen und Flags + * (Regionszauber, Kampfzauber, Farcastbar, Stufe variable, ..) + * + * rank: + * gibt die Priorität und damit die Reihenfolge an, in der der Spruch + * gezaubert wird. + * 1: Aura übertragen + * 2: Antimagie + * 3: Magierverändernde Sprüche (Magic Boost, ..) + * 4: Monster erschaffen + * 5: Standartlevel + * 7: Teleport + * + * Komponenten[Anzahl mögl. Items][Art:Anzahl:Kostentyp] + * + * R_AURA: + * Grundkosten für einen Zauber. Soviel Mp müssen mindestens investiert + * werden, um den Spruch zu wirken. Zusätzliche Mp können unterschiedliche + * Auswirkungen haben, die in der Spruchfunktionsroutine definiert werden. + * + * R_PERMAURA: + * Kosten an permantenter Aura + * + * Komponenten Kostentyp: + * SPC_LEVEL == Spruch mit Levelabhängigen Magiekosten. Die angegeben + * Kosten müssen für Stufe 1 berechnet sein. + * SPC_FIX == Feste Kosten + * + * Wenn keine spezielle Syntax angegeben ist, wird die + * Syntaxbeschreibung aus sptyp generiert: + * FARCASTING: ZAUBER [REGION x y] + * SPELLLEVEL: ZAUBER [STUFE n] + * UNITSPELL : ZAUBER [ ..] + * SHIPSPELL : ZAUBER [ ..] + * BUILDINGSPELL: ZAUBER [ ..] + * PRECOMBATSPELL : KAMPFZAUBER [STUFE n] + * COMBATSPELL : KAMPFZAUBER [STUFE n] + * POSTCOMBATSPELL: KAMPFZAUBER [STUFE n] + * + * Das Parsing + * + * Der String spell->parameter gibt die Syntax an, nach der die + * Parameter des Spruches in add_spellparameter() geparst werden sollen. + * + * u : eine Einheitennummer + * r : hier kommen zwei Regionskoordinaten x y + * b : Gebäude- oder Burgnummer + * s : Schiffsnummer + * c : String, wird ohne Weiterverarbeitung übergeben + * i : Zahl (int), wird ohne Weiterverarbeitung übergeben + * k : Keywort - dieser String gibt den Paramter an, der folgt. Der + * Parameter wird mit findparam() identifiziert. + * k muss immer von einem c als Platzhalter für das Objekt gefolgt + * werden. + * Ein gutes Beispiel sind hierfür die Sprüche zur Magieanalyse. + * + : gibt an, das der vorherige Parameter mehrfach vorkommen kann. Da + * ein Ende nicht definiert werden kann, muss dies immer am Schluss + * kommen. + * + * Flags für das Parsing: + * TESTRESISTANCE : alle Zielobjekte, also alle Parameter vom Typ Unit, + * Burg, Schiff oder Region, werden auf ihre + * Magieresistenz überprüft + * TESTCANSEE : jedes Objekt vom Typ Einheit wird auf seine + * Sichtbarkeit überprüft + * SEARCHLOCAL : die Zielobjekte werden nur regional gesucht + * REGIONSPELL : Ziel ist die Region, auch wenn kein Zielobjekt + * angegeben wird. Ist TESTRESISTANCE gesetzt, so wird + * die Magieresistenz der Region überprüft + * + * Bei fehlendem Ziel oder wenn dieses dem Zauber widersteht, wird die + * Spruchfunktion nicht aufgerufen. + * Sind zu wenig Parameter vorhanden, wird der Zauber ebenfalls nicht + * ausgeführt. + * Ist eins von mehreren Zielobjekten resistent, so wird das Flag + * pa->param[n]->flag == TARGET_RESISTS + * Ist eins von mehreren Zielobjekten nicht gefunden worden, so ist + * pa->param[n]->flag == TARGET_NOTFOUND + * + */ +/* ------------------------------------------------------------- */ + diff --git a/src/kernel/spellid.h b/src/kernel/spellid.h new file mode 100644 index 000000000..ffdc411f0 --- /dev/null +++ b/src/kernel/spellid.h @@ -0,0 +1,176 @@ +/* vi: set ts=2: +* +-------------------+ Christian Schlittchen +* | | Enno Rehling +* | Eressea PBEM host | Katja Zedel +* | (c) 1998 - 2005 | +* | | This program may not be used, modified or distributed +* +-------------------+ without prior permission by the authors of Eressea. +* +*/ + +#ifndef H_KRNL_SPELLID +#define H_KRNL_SPELLID + +/* Sprüche. Neue NUR hinten anfügen, oder das Datenfile geht kaputt */ +enum { + SPL_NOSPELL = 0, + SPL_FIREBALL = 4, + SPL_HAGEL, + SPL_RUSTWEAPON, + SPL_COMBATRUST, + SPL_TREEGROW, + SPL_HEALING, + SPL_HEALINGSONG, + SPL_BADDREAMS, + SPL_GOODDREAMS, + SPL_DREAMREADING, + SPL_SWEETDREAMS, + SPL_TIREDSOLDIERS, + SPL_PLAGUE, + SPL_MAGICBOOST, + SPL_CHAOSROW, + SPL_SONG_OF_CONFUSION, + SPL_FLEE, + SPL_SONG_OF_FEAR, + SPL_BERSERK, + SPL_BLOODTHIRST, + SPL_MAELSTROM, + SPL_TRANSFERAURA_DRUIDE = 27, + SPL_TRANSFERAURA_BARDE, + SPL_TRANSFERAURA_CHAOS, + SPL_TRANSFERAURA_TRAUM, + SPL_TRANSFERAURA_ASTRAL, + SPL_STONEGOLEM, + SPL_IRONGOLEM, + SPL_SUMMONSHADOW, + SPL_SUMMONSHADOWLORDS, + SPL_REELING_ARROWS, + SPL_ANTIMAGICZONE = 37, + SPL_KAELTESCHUTZ = 39, + SPL_STEALAURA, + SPL_SUMMONUNDEAD, + SPL_AURALEAK, + SPL_GREAT_DROUGHT, + SPL_STRONG_WALL, + SPL_HOMESTONE, + SPL_DROUGHT, + SPL_FOREST_FIRE = 47, + SPL_SUMMONENT = 49, + SPL_DISTURBINGDREAMS, + SPL_DENYATTACK, + SPL_SLEEP, + SPL_EARTHQUAKE, + SPL_IRONKEEPER, + SPL_STORMWINDS, + SPL_GOODWINDS, + SPL_FLYING_SHIP, + SPL_SUMMON_ALP, + SPL_WINDSHIELD, + SPL_RAISEPEASANTS, + SPL_DEPRESSION, + SPL_HEADACHE = 62, + SPL_ENTERASTRAL = 64, + SPL_LEAVEASTRAL, + SPL_SHOWASTRAL, + SPL_VERSTEINERN, + SPL_TREEWALKENTER, + SPL_TREEWALKEXIT, + SPL_CHAOSSUCTION, + SPL_VIEWREALITY, + SPL_DISRUPTASTRAL, + SPL_SEDUCE, + SPL_PUMP, + SPL_CALM_MONSTER, + SPL_HERO, + SPL_FRIGHTEN, + SPL_MINDBLAST, + SPL_SPEED, + SPL_SPEED2, + SPL_FIREDRAGONODEM, + SPL_DRAGONODEM, + SPL_WYRMODEM, /* 83 */ + SPL_MAGICSTREET, + SPL_REANIMATE, + SPL_RECRUIT, + SPL_GENEROUS, + SPL_PERMTRANSFER, + SPL_SONG_OF_PEACE, + SPL_MIGRANT, + SPL_RALLYPEASANTMOB, + SPL_RAISEPEASANTMOB, + SPL_ILL_SHAPESHIFT, + SPL_WOLFHOWL, + SPL_FOG_OF_CONFUSION, + SPL_DREAM_OF_CONFUSION, + SPL_RESISTMAGICBONUS, + SPL_KEEPLOOT, + SPL_SCHILDRUNEN, + SPL_SONG_RESISTMAGIC, + SPL_SONG_SUSCEPTMAGIC, + SPL_ANALYSEMAGIC, + SPL_ANALYSEDREAM, + SPL_UNIT_ANALYSESONG, + SPL_OBJ_ANALYSESONG, + SPL_TYBIED_DESTROY_MAGIC, + SPL_DESTROY_MAGIC, + SPL_METEORRAIN, + SPL_REDUCESHIELD, + SPL_ARMORSHIELD, + SPL_DEATHCLOUD, + SPL_ORKDREAM, + SPL_SUMMONDRAGON = 113, + SPL_MOVECASTLE = 116, + SPL_BLESSSTONECIRCLE, + SPL_ILLAUN_FAMILIAR, + SPL_GWYRRD_FAMILIAR, + SPL_DRAIG_FAMILIAR, + SPL_CERDDOR_FAMILIAR, + SPL_TYBIED_FAMILIAR, + SPL_SONG_OF_ENSLAVE = 123, + SPL_FUMBLECURSE = 136, + SPL_ICASTLE, + SPL_GWYRRD_DESTROY_MAGIC, + SPL_DRAIG_DESTROY_MAGIC, + SPL_ILLAUN_DESTROY_MAGIC, + SPL_CERDDOR_DESTROY_MAGIC, + SPL_GWYRRD_ARMORSHIELD, + SPL_DRAIG_FUMBLESHIELD, + SPL_GWYRRD_FUMBLESHIELD, + SPL_CERRDOR_FUMBLESHIELD, + SPL_TYBIED_FUMBLESHIELD, + SPL_SHADOWKNIGHTS = 147, + SPL_ITEMCLOAK = 150, + SPL_FIREWALL, + SPL_WISPS, + SPL_SPARKLE_CHAOS, + SPL_SPARKLE_DREAM = 154, + SPL_PULLASTRAL = 156, + SPL_FETCHASTRAL = 157, + SPL_SHOCKWAVE = 163, + SPL_UNDEADHERO = 164, + SPL_BECOMEWYRM = 166, + SPL_ETERNIZEWALL, + SPL_PUTTOREST, + SPL_UNHOLYPOWER, + SPL_HOLYGROUND, + SPL_BLOODSACRIFICE, + SPL_MALLORN, + SPL_CLONECOPY, + SPL_DRAINODEM, + SPL_AURA_OF_FEAR, + SPL_SHADOWCALL, + SPL_MALLORNTREEGROW = 177, + SPL_BIGRECRUIT = 179, + SPL_IMMOLATION, + SPL_FIREODEM, /* 181 */ + SPL_ICEODEM, + SPL_ACIDODEM, + /* no longer used, but kept for reference: */ + XMLSPL_WDWPYRAMID_TRAUM = 184, + XMLSPL_WDWPYRAMID_ASTRAL = 185, + XMLSPL_WDWPYRAMID_DRUIDE = 186, + XMLSPL_WDWPYRAMID_BARDE = 187, + XMLSPL_WDWPYRAMID_CHAOS = 188, +}; + +#endif diff --git a/src/kernel/sqlite.c b/src/kernel/sqlite.c new file mode 100644 index 000000000..eba6f3b3e --- /dev/null +++ b/src/kernel/sqlite.c @@ -0,0 +1,257 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +faction * get_faction_by_id(int uid) +{ + faction * f; + for (f=factions;f;f=f->next) { + if (f->subscription==uid) { + return f; + } + } + return NULL; +} + +#define SQL_EXPECT(res, val) if (res!=val) { return val; } +#define MAX_EMAIL_LENGTH 64 +#define MD5_LENGTH 32 +#define MD5_LENGTH_0 (MD5_LENGTH+1) /* MD5 + zero-terminator */ +#define MAX_FACTION_NAME 64 +#define MAX_FACTION_NAME_0 (MAX_FACTION_NAME+1) +typedef struct stmt_cache { + sqlite3 * db; + sqlite3_stmt * stmt; + const char * sql; + int inuse; +} stmt_cache; + +#define MAX_STMT_CACHE 64 +static stmt_cache cache[MAX_STMT_CACHE]; +static int cache_insert; + +static sqlite3_stmt * +stmt_cache_get(sqlite3 * db, const char * sql) +{ + int i, res; + + for (i=0;i!=MAX_STMT_CACHE && cache[i].db;++i) { + if (cache[i].sql==sql && cache[i].db==db) { + cache[i].inuse = 1; + res = sqlite3_reset(cache[i].stmt); + return cache[i].stmt; + } + } + if (i==MAX_STMT_CACHE) { + while (cache[cache_insert].inuse) { + cache[cache_insert].inuse = 0; + cache_insert = (cache_insert+1)&(MAX_STMT_CACHE-1); + } + i = cache_insert; + res = sqlite3_finalize(cache[i].stmt); + } + cache[i].inuse = 1; + cache[i].db = db; + cache[i].sql = sql; + res = sqlite3_prepare_v2(db, sql, -1, &cache[i].stmt, NULL); + return cache[i].stmt; +} + + +typedef struct db_faction { + sqlite3_uint64 id_faction; + sqlite3_uint64 id_email; + int no; + const char * email; + const char * passwd_md5; + const char * name; +} db_faction; + +static int +db_update_email(sqlite3 * db, const faction * f, const db_faction * dbstate, boolean force, /* [OUT] */ sqlite3_uint64 * id_email) +{ + boolean update = force; + int res = SQLITE_OK; + char email_lc[MAX_EMAIL_LENGTH]; + + if (update) { + unicode_utf8_tolower(email_lc, sizeof(email_lc), f->email); + } else { + if (strcmp(dbstate->email, f->email)!=0) { + unicode_utf8_tolower(email_lc, sizeof(email_lc), f->email); + if (strcmp(dbstate->email, email_lc)!=0) { + update = true; + } + } + } + + if (update) { + char email_md5[MD5_LENGTH_0]; + int i; + md5_state_t ms; + md5_byte_t digest[16]; + const char sql_insert_email[] = + "INSERT OR FAIL INTO email (email,md5) VALUES (?,?)"; + const char sql_select_email[] = + "SELECT id FROM email WHERE md5=?"; + sqlite3_stmt *stmt_insert_email = stmt_cache_get(db, sql_insert_email); + sqlite3_stmt *stmt_select_email = stmt_cache_get(db, sql_select_email); + + md5_init(&ms); + md5_append(&ms, (md5_byte_t*)email_lc, (int)strlen(email_lc)); + md5_finish(&ms, digest); + for (i=0;i!=16;++i) sprintf(email_md5+2*i, "%.02x", digest[i]); + + res = sqlite3_bind_text(stmt_insert_email, 1, email_lc, -1, SQLITE_TRANSIENT); + res = sqlite3_bind_text(stmt_insert_email, 2, email_md5, MD5_LENGTH, SQLITE_TRANSIENT); + res = sqlite3_step(stmt_insert_email); + + if (res==SQLITE_DONE) { + *id_email = sqlite3_last_insert_rowid(db); + } else { + res = sqlite3_bind_text(stmt_select_email, 1, email_md5, MD5_LENGTH, SQLITE_TRANSIENT); + res = sqlite3_step(stmt_select_email); + SQL_EXPECT(res, SQLITE_ROW); + *id_email = sqlite3_column_int64(stmt_select_email, 0); + } + } + + return SQLITE_OK; +} + +int +db_update_factions(sqlite3 * db, boolean force) +{ + int game_id = 6; + const char sql_select[] = + "SELECT faction.id, faction.email_id, faction.code, email.email, faction.password_md5, faction.name, faction.lastturn FROM email, faction" + " WHERE email.id=faction.email_id AND faction.game_id=? AND (lastturn IS NULL OR lastturn>?)"; + sqlite3_stmt *stmt_select = stmt_cache_get(db, sql_select); + faction * f; + int res; + + res = sqlite3_bind_int(stmt_select, 1, game_id); + SQL_EXPECT(res, SQLITE_OK); + res = sqlite3_bind_int(stmt_select, 2, turn-2); + SQL_EXPECT(res, SQLITE_OK); + for (;;) { + sqlite3_uint64 id_faction; + int lastturn; + + res = sqlite3_step(stmt_select); + if (res!=SQLITE_ROW) break; + + id_faction = sqlite3_column_int64(stmt_select, 0); + lastturn = sqlite3_column_int(stmt_select, 6); + f = get_faction_by_id((int)id_faction); + + if (f==NULL || !f->alive) { + if (lastturn==0) { + const char sql_update[] = "UPDATE faction SET lastturn=? WHERE id=?"; + sqlite3_stmt *stmt = stmt_cache_get(db, sql_update); + + lastturn = f?f->lastorders:turn-1; + sqlite3_bind_int(stmt, 1, lastturn); + sqlite3_bind_int64(stmt, 2, id_faction); + res = sqlite3_step(stmt); + SQL_EXPECT(res, SQLITE_DONE); + } + } else { + md5_state_t ms; + md5_byte_t digest[16]; + int i; + char passwd_md5[MD5_LENGTH_0]; + sqlite3_uint64 id_email; + boolean update = force; + db_faction dbstate; + const char * no_b36; + + fset(f, FFL_MARK); + dbstate.id_faction = id_faction; + dbstate.id_email = sqlite3_column_int64(stmt_select, 1); + no_b36 = (const char *)sqlite3_column_text(stmt_select, 2); + dbstate.no = no_b36?atoi36(no_b36):-1; + dbstate.email = (const char *)sqlite3_column_text(stmt_select, 3); + dbstate.passwd_md5 = (const char *)sqlite3_column_text(stmt_select, 4); + dbstate.name = (const char *)sqlite3_column_text(stmt_select, 5); + + id_email = dbstate.id_email; + res = db_update_email(db, f, &dbstate, force, &id_email); + SQL_EXPECT(res, SQLITE_OK); + + md5_init(&ms); + md5_append(&ms, (md5_byte_t*)f->passw, (int)strlen(f->passw)); + md5_finish(&ms, digest); + for (i=0;i!=16;++i) sprintf(passwd_md5+2*i, "%.02x", digest[i]); + + if (!update) { + update = ((id_email!=0 && dbstate.id_email!=id_email) || dbstate.no!=f->no + || dbstate.passwd_md5==NULL || strcmp(passwd_md5, dbstate.passwd_md5)!=0 + || dbstate.name==NULL || strncmp(f->name, dbstate.name, MAX_FACTION_NAME)!=0); + } + if (update) { + const char sql_update_faction[] = + "UPDATE faction SET email_id=?, password_md5=?, code=?, name=?, firstturn=? WHERE id=?"; + sqlite3_stmt *stmt_update_faction = stmt_cache_get(db, sql_update_faction); + + res = sqlite3_bind_int64(stmt_update_faction, 1, id_email); + SQL_EXPECT(res, SQLITE_OK); + res = sqlite3_bind_text(stmt_update_faction, 2, passwd_md5, MD5_LENGTH, SQLITE_TRANSIENT); + SQL_EXPECT(res, SQLITE_OK); + res = sqlite3_bind_text(stmt_update_faction, 3, no_b36, -1, SQLITE_TRANSIENT); + SQL_EXPECT(res, SQLITE_OK); + res = sqlite3_bind_text(stmt_update_faction, 4, f->name, -1, SQLITE_TRANSIENT); + SQL_EXPECT(res, SQLITE_OK); + res = sqlite3_bind_int(stmt_update_faction, 5, turn-f->age); + SQL_EXPECT(res, SQLITE_OK); + res = sqlite3_bind_int64(stmt_update_faction, 6, f->subscription); + SQL_EXPECT(res, SQLITE_OK); + res = sqlite3_step(stmt_update_faction); + SQL_EXPECT(res, SQLITE_DONE); + } + } + } + + for (f=factions;f;f=f->next) { + if (!fval(f, FFL_MARK)) { + log_error(("%s (sub=%d, email=%s) has no entry in the database\n", factionname(f), f->subscription, f->email)); + } else { + freset(f, FFL_MARK); + } + } + return SQLITE_OK; +} + +int +db_update_scores(sqlite3 * db, boolean force) +{ + const char * sql_ins = "INSERT OR FAIL INTO score (value,faction_id,turn) VALUES (?,?,?)"; + sqlite3_stmt * stmt_ins = stmt_cache_get(db, sql_ins); + const char * sql_upd = "UPDATE score set value=? WHERE faction_id=? AND turn=?"; + sqlite3_stmt * stmt_upd = stmt_cache_get(db, sql_upd); + faction * f; + sqlite3_exec(db, "BEGIN", 0, 0, 0); + for (f=factions;f;f=f->next) { + int res; + sqlite3_bind_int(stmt_ins, 1, f->score); + sqlite3_bind_int64(stmt_ins, 2, f->subscription); + sqlite3_bind_int(stmt_ins, 3, turn); + res = sqlite3_step(stmt_ins); + if (res==SQLITE_CONSTRAINT) { + sqlite3_bind_int(stmt_upd, 1, f->score); + sqlite3_bind_int64(stmt_upd, 2, f->subscription); + sqlite3_bind_int(stmt_upd, 3, turn); + res = sqlite3_step(stmt_upd); + sqlite3_reset(stmt_upd); + } + sqlite3_reset(stmt_ins); + } + sqlite3_exec(db, "COMMIT", 0, 0, 0); + return SQLITE_OK; +} diff --git a/src/kernel/teleport.c b/src/kernel/teleport.c new file mode 100644 index 000000000..40fc7b8ae --- /dev/null +++ b/src/kernel/teleport.c @@ -0,0 +1,228 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "teleport.h" + +/* kernel includes */ +#include "equipment.h" +#include "unit.h" +#include "region.h" +#include "race.h" +#include "skill.h" +#include "terrain.h" +#include "faction.h" +#include "plane.h" + +/* util includes */ +#include +#include + +/* libc includes */ +#include + +#define TE_CENTER_X 1000 +#define TE_CENTER_Y 1000 +#define TP_RADIUS 2 +#define TP_DISTANCE 4 + +static int +real2tp(int rk) { + /* in C: + * -4 / 5 = 0; + * +4 / 5 = 0; + * !!!!!!!!!!; + */ + return (rk + (TP_DISTANCE*5000)) / TP_DISTANCE - 5000; +} + +static region * +tpregion(const region *r) { + region * rt = findregion(TE_CENTER_X+real2tp(r->x), TE_CENTER_Y+real2tp(r->y)); + if (!is_astral(rt)) return NULL; + return rt; +} + +region_list * +astralregions(const region * r, boolean (*valid)(const region *)) +{ + region_list * rlist = NULL; + int x, y; + + assert(is_astral(r)); + if (!is_astral(r)) { + log_error(("astralregions was called with a non-astral region.\n")); + return NULL; + } + r = r_astral_to_standard(r); + if (r==NULL) return NULL; + + for (x=-TP_RADIUS;x<=+TP_RADIUS;++x) { + for (y=-TP_RADIUS;y<=+TP_RADIUS;++y) { + region * rn; + int dist = koor_distance(0, 0, x, y); + int nx = r->x+x, ny = r->y+y; + + if (dist > TP_RADIUS) continue; + pnormalize(&nx, &ny, rplane(r)); + rn = findregion(nx, ny); + if (rn!=NULL && (valid==NULL || valid(rn))) add_regionlist(&rlist, rn); + } + } + return rlist; +} + +region * +r_standard_to_astral(const region *r) +{ + if (rplane(r) != get_normalplane()) return NULL; + return tpregion(r); +} + +region * +r_astral_to_standard(const region *r) +{ + int x, y; + region *r2; + + assert(is_astral(r)); + x = (r->x-TE_CENTER_X)*TP_DISTANCE; + y = (r->y-TE_CENTER_Y)*TP_DISTANCE; + pnormalize(&x, &y, get_normalplane()); + r2 = findregion(x, y); + if (r2==NULL || rplane(r2)!=get_normalplane()) return NULL; + + return r2; +} + +region_list * +all_in_range(const region *r, int n, boolean (*valid)(const region *)) +{ + int x, y; + region_list *rlist = NULL; + plane * pl = rplane(r); + + if (r == NULL) return NULL; + + for (x = r->x-n; x <= r->x+n; x++) { + for (y = r->y-n; y <= r->y+n; y++) { + if (koor_distance(r->x, r->y, x, y) <= n) { + region * r2; + int nx = x, ny = y; + pnormalize(&nx, &ny, pl); + r2 = findregion(nx, ny); + if (r2!=NULL && (valid==NULL || valid(r2))) add_regionlist(&rlist, r2); + } + } + } + + return rlist; +} + +void +spawn_braineaters(float chance) +{ + region *r; + faction *f0 = get_monsters(); + int next = rng_int() % (int)(chance*100); + + if (f0==NULL) return; + + for (r = regions; r; r = r->next) { + if (!is_astral(r) || fval(r->terrain, FORBIDDEN_REGION)) continue; + + /* Neues Monster ? */ + if (next-- == 0) { + unit *u = createunit(r, f0, 1+rng_int()%10+rng_int()%10, new_race[RC_HIRNTOETER]); + equip_unit(u, get_equipment("monster_braineater")); + + next = rng_int() % (int)(chance*100); + } + } +} + +plane * +get_normalplane(void) +{ + return NULL; +} + +boolean +is_astral(const region * r) +{ + plane * pl = get_astralplane(); + return (pl && rplane(r) == pl); +} + +plane * +get_astralplane(void) +{ + static plane * astralspace; + static int rule_astralplane = -1; + static int gamecookie = -1; + if (rule_astralplane<0) { + rule_astralplane = get_param_int(global.parameters, "modules.astralspace", 1); + } + if (!rule_astralplane) { + return NULL; + } + if (gamecookie!=global.cookie) { + astralspace = getplanebyname("Astralraum"); + gamecookie = global.cookie; + } + + if (astralspace==NULL) { + astralspace = create_new_plane(1, "Astralraum", + TE_CENTER_X-500, TE_CENTER_X+500, + TE_CENTER_Y-500, TE_CENTER_Y+500, 0); + } + return astralspace; +} + +void +create_teleport_plane(void) +{ + region *r; + plane * hplane = get_homeplane(); + plane * aplane = get_astralplane(); + + const terrain_type * fog = get_terrain("fog"); + + for (r=regions;r;r=r->next) { + plane * pl = rplane(r); + if (pl == hplane) { + region *ra = tpregion(r); + + if (ra==NULL) { + int x = TE_CENTER_X+real2tp(r->x); + int y = TE_CENTER_Y+real2tp(r->y); + pnormalize(&x, &y, aplane); + + ra = new_region(x, y, aplane, 0); + terraform_region(ra, fog); + } + } + } +} + +boolean +inhabitable(const region * r) +{ + return fval(r->terrain, LAND_REGION); +} diff --git a/src/kernel/teleport.h b/src/kernel/teleport.h new file mode 100644 index 000000000..83f777899 --- /dev/null +++ b/src/kernel/teleport.h @@ -0,0 +1,41 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef TELEPORT_H +#define TELEPORT_H +#ifdef __cplusplus +extern "C" { +#endif + + struct region *r_standard_to_astral(const struct region *r); + struct region *r_astral_to_standard(const struct region *); + extern struct region_list *astralregions(const struct region * rastral, boolean (*valid)(const struct region *)); + extern struct region_list *all_in_range(const struct region *r, int n, boolean (*valid)(const struct region *)); + extern boolean inhabitable(const struct region * r); + extern boolean is_astral(const struct region * r); + extern struct plane * get_astralplane(void); + extern struct plane * get_normalplane(void); + + void create_teleport_plane(void); + void set_teleport_plane_regiontypes(void); + void spawn_braineaters(float chance); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/terrain.c b/src/kernel/terrain.c new file mode 100644 index 000000000..15ef6b58f --- /dev/null +++ b/src/kernel/terrain.c @@ -0,0 +1,158 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include +#include "terrain.h" +#include "terrainid.h" + +/* kernel includes */ +#include "curse.h" +#include "region.h" +#include "resources.h" + +#include +#include + +/* libc includes */ +#include +#include +#include + +#define MAXTERRAINS 20 + +const char * terraindata[MAXTERRAINS] = { + "ocean", + "plain", + "swamp", + "desert", + "highland", + "mountain", + "glacier", + "firewall", + NULL, /* dungeon module */ + NULL, /* former grassland */ + "fog", + "thickfog", + "volcano", + "activevolcano", + "iceberg_sleep", + "iceberg", + + NULL, /* museum module */ + NULL, /* museum module */ + NULL, /* former magicstorm */ + NULL /* museum module */ +}; + +static terrain_type * registered_terrains; + +const terrain_type * +terrains(void) +{ + return registered_terrains; +} + +static const char * +plain_name(const struct region * r) +{ + /* TODO: xml defined */ + if (r_isforest(r)) return "forest"; + return r->terrain->_name; +} + +void +register_terrain(struct terrain_type * terrain) +{ + assert(terrain->next==NULL), + terrain->next = registered_terrains; + registered_terrains = terrain; + if (strcmp("plain", terrain->_name)==0) + terrain->name = &plain_name; +} + +const struct terrain_type * +get_terrain(const char * name) +{ + const struct terrain_type * terrain; + for (terrain=registered_terrains;terrain;terrain=terrain->next) { + if (strcmp(terrain->_name, name)==0) break; + } + return terrain; +} + +static const terrain_type * newterrains[MAXTERRAINS]; + +const struct terrain_type * +newterrain(terrain_t t) +{ + if (t==NOTERRAIN) return NULL; + assert(t>=0); + assert(t_name)); + return NOTERRAIN; +} + +const char * +terrain_name(const struct region * r) +{ + if (r->attribs) { + attrib * a = a_find(r->attribs, &at_racename); + if (a) { + const char * str = get_racename(a); + if (str) return str; + } + } + + if (r->terrain->name!=NULL) { + return r->terrain->name(r); + } else if (fval(r->terrain, SEA_REGION)) { + if (curse_active(get_curse(r->attribs, ct_find("maelstrom")))) { + return "maelstrom"; + } + } + return r->terrain->_name; +} + +void +init_terrains(void) +{ + terrain_t t; + for (t=0;t!=MAXTERRAINS;++t) { + const terrain_type * newterrain = newterrains[t]; + if (newterrain!=NULL) continue; + if (terraindata[t]!=NULL) { + newterrain = get_terrain(terraindata[t]); + if (newterrain!=NULL) { + newterrains[t] = newterrain; + } + } + } +} diff --git a/src/kernel/terrain.h b/src/kernel/terrain.h new file mode 100644 index 000000000..644a0e329 --- /dev/null +++ b/src/kernel/terrain.h @@ -0,0 +1,83 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef TERRAIN_H +#define TERRAIN_H +#ifdef __cplusplus +extern "C" { +#endif + +/* diverse Flags */ +/* Strassen können gebaut werden, wenn max_road > 0 */ +#define LAND_REGION (1<<0) /* Standard-Land-struct region */ +#define SEA_REGION (1<<1) /* hier braucht man ein Boot */ +#define FOREST_REGION (1<<2) /* Elfen- und Kampfvorteil durch Bäume */ +#define ARCTIC_REGION (1<<3) /* Gletscher & co = Keine Insekten! */ +#define CAVALRY_REGION (1<<4) /* Gletscher & co = Keine Insekten! */ +/* Achtung: SEA_REGION ist nicht das Gegenteil von LAND_REGION. Die zwei schliessen sich nichtmal aus! */ +#define FORBIDDEN_REGION (1<<5) /* unpassierbare Blockade-struct region */ +#define SAIL_INTO (1<<6) /* man darf hierhin segeln */ +#define FLY_INTO (1<<7) /* man darf hierhin fliegen */ +#define SWIM_INTO (1<<8) /* man darf hierhin schwimmen */ +#define WALK_INTO (1<<9) /* man darf hierhin laufen */ +#define LARGE_SHIPS (1<<10) /* grosse Schiffe dürfen hinfahren */ + +typedef struct production_rule { + char * name; + const struct resource_type * rtype; + + void (*terraform) (struct production_rule *, const struct region *); + void (*update) (struct production_rule *, const struct region *); + void (*use) (struct production_rule *, const struct region *, int amount); + int (*visible) (const struct production_rule *, int skilllevel); + + /* no initialization required */ + struct production_rule * next; +} production_rule; + +typedef struct terrain_production { + const struct resource_type * type; + const char *startlevel; + const char *base; + const char *divisor; + float chance; +} terrain_production; + +typedef struct terrain_type { + char * _name; + int size; /* how many peasants can work? */ + unsigned int flags; + short max_road; /* this many stones make a full road */ + short distribution; /* multiplier used for seeding */ + struct terrain_production * production; + const struct item_type ** herbs; /* zero-terminated array of herbs */ + const char * (*name)(const struct region * r); + const struct terrain_type * next; +} terrain_type; + +extern const terrain_type * terrains(void); +extern void register_terrain(struct terrain_type * terrain); +extern const struct terrain_type * get_terrain(const char * name); +extern const char * terrain_name(const struct region * r); + +extern void init_terrains(void); + +#ifdef __cplusplus +} +#endif +#endif /* TERRAIN_H */ diff --git a/src/kernel/terrainid.h b/src/kernel/terrainid.h new file mode 100644 index 000000000..fb2e40dd0 --- /dev/null +++ b/src/kernel/terrainid.h @@ -0,0 +1,48 @@ +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2005 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + */ + +#ifndef H_KRNL_TERRAINID_H +#define H_KRNL_TERRAINID_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + T_OCEAN = 0, + T_PLAIN = 1, + T_SWAMP = 2, + T_DESERT = 3, /* kann aus T_PLAIN entstehen */ + T_HIGHLAND = 4, + T_MOUNTAIN = 5, + T_GLACIER = 6, /* kann aus T_MOUNTAIN entstehen */ + T_FIREWALL = 7, /* Unpassierbar */ + /* T_HELL = 8, Hölle */ + /* T_GRASSLAND = 9, */ + T_ASTRAL = 10, + T_ASTRALB = 11, + T_VOLCANO = 12, + T_VOLCANO_SMOKING = 13, + T_ICEBERG_SLEEP = 14, + T_ICEBERG = 15, + /* T_HALL1 = 16, */ + /* T_CORRIDOR1 = 17, */ + /* T_MAGICSTORM = 18, */ + /* T_WALL1 = 19, */ + NOTERRAIN = (terrain_t) - 1 +}; + +extern const struct terrain_type * newterrain(terrain_t t); +extern terrain_t oldterrain(const struct terrain_type * terrain); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/kernel/textstore.c b/src/kernel/textstore.c new file mode 100644 index 000000000..391038f0f --- /dev/null +++ b/src/kernel/textstore.c @@ -0,0 +1,205 @@ +/* vi: set ts=2: ++-------------------+ Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel ++-------------------+ +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ +#include +#include "config.h" +#include "textstore.h" + +#include "save.h" +#include "version.h" +#include +#include + +#include +#include +#include +#include + +#define NULL_TOKEN '@' + +static int +txt_w_brk(struct storage * store) +{ + putc('\n', (FILE *)store->userdata); + return 1; +} + +static int +txt_w_id(struct storage * store, int arg) +{ + return fprintf((FILE *)store->userdata, "%s ", itoa36(arg)); +} + +static int +txt_r_id(struct storage * store) +{ + char id[8]; + fscanf((FILE *)store->userdata, "%7s", id); + return atoi36(id); +} + +static int +txt_w_int(struct storage * store, int arg) +{ + return fprintf((FILE *)store->userdata, "%d ", arg); +} + +static int +txt_r_int(struct storage * store) +{ + int result; + fscanf((FILE *)store->userdata, "%d", &result); + return result; +} + +static int +txt_w_flt(struct storage * store, float arg) +{ + return fprintf((FILE *)store->userdata, "%f ", arg); +} + +static float +txt_r_flt(struct storage * store) +{ + double result; + fscanf((FILE *)store->userdata, "%lf", &result); + return (float)result; +} + +static int +txt_w_tok(struct storage * store, const char * tok) +{ + int result; + if (tok==NULL || tok[0]==0) { + result = fputc(NULL_TOKEN, (FILE *)store->userdata); + } else { +#ifndef NDEBUG + const char * find = strchr(tok, ' '); + if (!find) find = strchr(tok, NULL_TOKEN); + assert(!find || !"reserved character in token"); +#endif + assert(tok[0]!=' '); + result = fputs(tok, (FILE *)store->userdata); + } + fputc(' ', (FILE *)store->userdata); + return result; +} +static char * +txt_r_tok(struct storage * store) +{ + char result[256]; + fscanf((FILE *)store->userdata, "%256s", result); + if (result[0]==NULL_TOKEN || result[0]==0) { + return NULL; + } + return strdup(result); +} +static void +txt_r_tok_buf(struct storage * store, char * result, size_t size) +{ + char format[16]; + if (result && size>0) { + format[0]='%'; + sprintf(format+1, "%us", size); + fscanf((FILE *)store->userdata, format, result); + if (result[0]==NULL_TOKEN) { + result[0] = 0; + } + } else { + /* trick to skip when no result expected */ + fscanf((FILE *)store->userdata, "%*s"); + } +} + +static int +txt_w_str(struct storage * store, const char * str) +{ + int result = fwritestr((FILE *)store->userdata, str); + fputc(' ', (FILE *)store->userdata); + return result+1; +} + +static char * +txt_r_str(struct storage * store) +{ + char buffer[DISPLAYSIZE]; + /* you should not use this */ + freadstr((FILE *)store->userdata, store->encoding, buffer, sizeof(buffer)); + return strdup(buffer); +} + +static void +txt_r_str_buf(struct storage * store, char * result, size_t size) +{ + freadstr((FILE *)store->userdata, store->encoding, result, size); +} + +static int +txt_open(struct storage * store, const char * filename, int mode) +{ + const char * modes[] = { 0, "rt", "wt", "at" }; + FILE * F = fopen(filename, modes[mode]); + store->userdata = F; + if (F) { + const char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + if (mode==IO_READ) { + char token[8]; + /* recognize UTF8 BOM */ + store->r_tok_buf(store, token, sizeof(token)); + if (memcmp(token, utf8_bom, 3)==0) { + if (enc_gamedata!=XML_CHAR_ENCODING_UTF8) { + log_warning(("Found UTF-8 BOM, assuming unicode game data.\n")); + store->encoding = XML_CHAR_ENCODING_UTF8; + } + store->version = atoi(token+3); + } else { + if (store->encoding==XML_CHAR_ENCODING_NONE) { + store->encoding = XML_CHAR_ENCODING_8859_1; + log_warning(("No BOM, assuming 8859-1 game data.\n")); + } + store->version = atoi(token); + } + } else if (store->encoding==XML_CHAR_ENCODING_UTF8) { + fputs(utf8_bom, F); + fprintf(F, "%d\n", RELEASE_VERSION); + } + } + return (F==NULL); +} + +static int +txt_w_bin(struct storage * store, void * arg, size_t size) +{ + assert(!"not implemented!"); + return 0; +} + +static void +txt_r_bin(struct storage * store, void * result, size_t size) +{ + assert(!"not implemented!"); +} + +static int +txt_close(struct storage * store) +{ + return fclose((FILE *)store->userdata); +} + +const storage text_store = { + txt_w_brk, + txt_w_int, txt_r_int, + txt_w_flt, txt_r_flt, + txt_w_id, txt_r_id, + txt_w_tok, txt_r_tok, txt_r_tok_buf, + txt_w_str, txt_r_str, txt_r_str_buf, + txt_w_bin, txt_r_bin, + txt_open, txt_close, + 0, 0, NULL +}; + diff --git a/src/kernel/textstore.h b/src/kernel/textstore.h new file mode 100644 index 000000000..134a8da7e --- /dev/null +++ b/src/kernel/textstore.h @@ -0,0 +1,23 @@ +/* vi: set ts=2: ++-------------------+ Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel ++-------------------+ +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifndef H_KERNEL_TEXTSTORE +#define H_KERNEL_TEXTSTORE +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern const storage text_store; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/types.h b/src/kernel/types.h new file mode 100644 index 000000000..9c16e63ac --- /dev/null +++ b/src/kernel/types.h @@ -0,0 +1,407 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef ERESSEA_TYPES_H +#define ERESSEA_TYPES_H + +/* + * Features enabled: + * If you are lacking the settings.h, create a new file common/settings.h, + * and write #include (or whatever settings you want + * your game to use) in there. + * !!! DO NOT COMMIT THE SETTINGS.H FILE TO CVS !!! + * settings.h should always be the first thing you include (after platform.h). + */ +#include +#include + +typedef short terrain_t; +typedef short direction_t; +typedef short race_t; +typedef short magic_t; +typedef short skill_t; +typedef short typ_t; +typedef short item_t; +typedef unsigned int spellid_t; + +struct attrib; +struct attrib_type; +struct building; +struct building_type; +struct curse; +struct equipment; +struct faction; +struct fighter; +struct item; +struct item_type; +struct locale; +struct luxury_type; +struct order; +struct plane; +struct potion_type; +struct race; +struct region; +struct region_list; +struct resource_type; +struct ship; +struct ship_type; +struct skill; +struct spell; +struct storage; +struct strlist; +struct terrain_type; +struct unit; +struct unit_list; +struct weapon_type; + +typedef struct ursprung { + struct ursprung *next; + int id; + int x, y; +} ursprung; + +/* ----------------- Befehle ----------------------------------- */ + +typedef unsigned char keyword_t; +enum { + K_KOMMENTAR, + K_BANNER, + K_WORK, + K_ATTACK, + K_STEAL, + K_BESIEGE, + K_NAME, + K_USE, + K_DISPLAY, + K_ENTER, + K_GUARD, + K_MAIL, + K_END, + K_DRIVE, + K_NUMBER, + K_WAR, + K_PEACE, + K_FOLLOW, + K_RESEARCH, + K_GIVE, + K_ALLY, + K_STATUS, + K_COMBATSPELL, + K_BUY, + K_CONTACT, + K_TEACH, + K_STUDY, + K_LIEFERE, + K_MAKE, + K_MOVE, + K_PASSWORD, + K_RECRUIT, + K_RESERVE, + K_ROUTE, + K_SABOTAGE, + K_SEND, + K_SPY, + K_QUIT, + K_SETSTEALTH, + K_TRANSPORT, + K_TAX, + K_ENTERTAIN, + K_SELL, + K_LEAVE, + K_FORGET, + K_CAST, + K_RESHOW, + K_DESTROY, + K_BREED, + K_DEFAULT, + K_URSPRUNG, + K_EMAIL, + K_PIRACY, + K_RESTART, + K_GROUP, + K_SACRIFICE, + K_PRAY, + K_SORT, + K_SETJIHAD, + K_GM, /* perform GM commands */ + K_INFO, /* set player-info */ + K_PREFIX, + K_PLANT, + K_WEREWOLF, + K_XE, + K_ALLIANCE, + K_CLAIM, + K_PROMOTION, + K_PAY, + MAXKEYWORDS, + NOKEYWORD = (keyword_t) - 1 +}; + +/* ------------------ Status von Einheiten --------------------- */ + +typedef unsigned char status_t; +enum { + ST_AGGRO, + ST_FIGHT, + ST_BEHIND, + ST_CHICKEN, + ST_AVOID, + ST_FLEE +}; + +/* ----------------- Parameter --------------------------------- */ + +typedef unsigned char param_t; +enum { + P_LOCALE, + P_ANY, + P_EACH, + P_PEASANT, + P_BUILDING, + P_UNIT, + P_PRIVAT, + P_BEHIND, + P_CONTROL, + P_HERBS, + P_NOT, + P_NEXT, + P_FACTION, + P_GAMENAME, + P_PERSON, + P_REGION, + P_SHIP, + P_MONEY, + P_ROAD, + P_TEMP, + P_FLEE, + P_GEBAEUDE, + P_GIVE, + P_FIGHT, + P_TRAVEL, + P_GUARD, + P_ZAUBER, + P_PAUSE, + P_VORNE, + P_AGGRO, + P_CHICKEN, + P_LEVEL, + P_HELP, + P_FOREIGN, + P_AURA, + P_FOR, + P_AID, + P_MERCY, + P_AFTER, + P_BEFORE, + P_NUMBER, + P_ITEMS, + P_POTIONS, + P_GROUP, + P_FACTIONSTEALTH, + P_TREES, + P_XEPOTION, + P_XEBALLOON, + P_XELAEN, + P_ALLIANCE, + MAXPARAMS, + NOPARAM = (param_t) - 1 +}; + +typedef enum { /* Fehler und Meldungen im Report */ + MSG_BATTLE, + MSG_EVENT, + MSG_MOVE, + MSG_INCOME, + MSG_COMMERCE, + MSG_PRODUCE, + MSG_ORCVERMEHRUNG, + MSG_MESSAGE, + MSG_COMMENT, + MSG_MAGIC, + MAX_MSG +} msg_t; + +enum { /* Message-Level */ + ML_IMPORTANT, /* Sachen, die IMO erscheinen _muessen_ */ + ML_DEBUG, + ML_MISTAKE, + ML_WARN, + ML_INFO, + ML_MAX +}; + +extern const char *parameters[MAXPARAMS]; + +/* --------------- Reports Typen ------------------------------- */ + +enum { + O_REPORT, /* 1 */ + O_COMPUTER, /* 2 */ + O_ZUGVORLAGE, /* 4 */ + O_UNUSED_3, + O_STATISTICS, /* 16 */ + O_DEBUG, /* 32 */ + O_COMPRESS, /* 64 */ + O_NEWS, /* 128 */ + O_UNUSED_8, + O_ADRESSEN, /* 512 */ + O_BZIP2, /* 1024 - compress as bzip2 */ + O_SCORE, /* 2048 - punkte anzeigen? */ + O_SHOWSKCHANGE, /* 4096 - Skillveränderungen anzeigen? */ + O_XML, /* 8192 - XML report versenden */ + MAXOPTIONS +}; + +/* ------------------ Talente ---------------------------------- */ + +enum { + SK_ALCHEMY, + SK_CROSSBOW, + SK_MINING, + SK_LONGBOW, + SK_BUILDING, + SK_TRADE, + SK_LUMBERJACK, + SK_CATAPULT, + SK_HERBALISM, + SK_MAGIC, + SK_HORSE_TRAINING, /* 10 */ + SK_RIDING, + SK_ARMORER, + SK_SHIPBUILDING, + SK_MELEE, + SK_SAILING, + SK_SPEAR, + SK_SPY, + SK_QUARRYING, + SK_ROAD_BUILDING, + SK_TACTICS, /* 20 */ + SK_STEALTH, + SK_ENTERTAINMENT, + SK_WEAPONSMITH, + SK_CARTMAKER, + SK_PERCEPTION, + SK_TAXING, + SK_STAMINA, + SK_WEAPONLESS, + MAXSKILLS, + NOSKILL = (skill_t) -1 +}; + +/* ------------- Typ von Einheiten ----------------------------- */ + +enum { + RC_DWARF, /* 0 - Zwerg */ + RC_ELF, + RC_GOBLIN = 3, + RC_HUMAN, + + RC_TROLL, + RC_DAEMON, + RC_INSECT, + RC_HALFLING, + RC_CAT, + + RC_AQUARIAN, + RC_ORC, + RC_SNOTLING, + RC_UNDEAD, + RC_ILLUSION, + + RC_FIREDRAGON, + RC_DRAGON, + RC_WYRM, + RC_TREEMAN, + RC_BIRTHDAYDRAGON, + + RC_DRACOID, + RC_SPECIAL, + RC_SPELL, + RC_IRONGOLEM, + RC_STONEGOLEM, + + RC_SHADOW, + RC_SHADOWLORD, + RC_IRONKEEPER, + RC_ALP, + RC_TOAD, + + RC_HIRNTOETER, + RC_PEASANT, + RC_WOLF = 32, + + RC_SONGDRAGON = 37, + + RC_SEASERPENT = 51, + RC_SHADOWKNIGHT, + RC_CENTAUR, + RC_SKELETON, + + RC_SKELETON_LORD, + RC_ZOMBIE, + RC_ZOMBIE_LORD, + RC_GHOUL, + RC_GHOUL_LORD, + + RC_MUS_SPIRIT, + RC_GNOME, + RC_TEMPLATE, + RC_CLONE, + + MAXRACES, + NORACE = (race_t) - 1 +}; + +/* Richtungen */ +enum { + D_NORTHWEST, + D_NORTHEAST, + D_EAST, + D_SOUTHEAST, + D_SOUTHWEST, + D_WEST, + MAXDIRECTIONS, + D_PAUSE, + D_SPECIAL, + NODIRECTION = (direction_t) - 1 +}; + +#define DONT_HELP 0 +#define HELP_MONEY 1 /* Mitversorgen von Einheiten */ +#define HELP_FIGHT 2 /* Bei Verteidigung mithelfen */ +#define HELP_OBSERVE 4 /* Bei Wahrnehmung mithelfen */ +#define HELP_GIVE 8 /* Dinge annehmen ohne KONTAKTIERE */ +#define HELP_GUARD 16 /* Laesst Steuern eintreiben etc. */ +#define HELP_FSTEALTH 32 /* Parteitarnung anzeigen. */ +#define HELP_TRAVEL 64 /* Laesst Regionen betreten. */ +#define HELP_ALL (127-HELP_TRAVEL-HELP_OBSERVE) /* Alle "positiven" HELPs zusammen */ +/* HELP_OBSERVE deaktiviert */ +/* ------------------------------------------------------------- */ +/* Prototypen */ + + +#define ALLIED_TAX 1 +#define ALLIED_NOBLOCK 2 +#define ALLIED_HELP 4 + +/* alle vierstelligen zahlen: */ +#define MAX_UNIT_NR (36*36*36*36-1) +#define MAX_CONTAINER_NR (36*36*36*36-1) + + +#endif diff --git a/src/kernel/unit.c b/src/kernel/unit.c new file mode 100644 index 000000000..e8ab947f7 --- /dev/null +++ b/src/kernel/unit.c @@ -0,0 +1,1743 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "unit.h" + +#include "building.h" +#include "faction.h" +#include "group.h" +#include "connection.h" +#include "item.h" +#include "move.h" +#include "order.h" +#include "plane.h" +#include "race.h" +#include "region.h" +#include "save.h" +#include "ship.h" +#include "skill.h" +#include "terrain.h" + +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +#define FIND_FOREIGN_TEMP + +attrib_type at_creator = { + "creator" + /* Rest ist NULL; temporäres, nicht alterndes Attribut */ +}; + +#define UMAXHASH MAXUNITS +static unit * unithash[UMAXHASH]; +static unit * delmarker = (unit*)unithash; /* a funny hack */ + +#define HASH_STATISTICS 1 +#if HASH_STATISTICS +static int hash_requests; +static int hash_misses; +#endif + +void +uhash(unit * u) +{ + int key = HASH1(u->no, UMAXHASH), gk = HASH2(u->no, UMAXHASH); + while (unithash[key]!=NULL && unithash[key]!=delmarker && unithash[key]!=u) { + key = (key + gk) % UMAXHASH; + } + assert(unithash[key]!=u || !"trying to add the same unit twice"); + unithash[key] = u; +} + +void +uunhash(unit * u) +{ + int key = HASH1(u->no, UMAXHASH), gk = HASH2(u->no, UMAXHASH); + while (unithash[key]!=NULL && unithash[key]!=u) { + key = (key + gk) % UMAXHASH; + } + assert(unithash[key]==u || !"trying to remove a unit that is not hashed"); + unithash[key] = delmarker; +} + +unit * +ufindhash(int uid) +{ + assert(uid>=0); +#if HASH_STATISTICS + ++hash_requests; +#endif + if (uid>=0) { + int key = HASH1(uid, UMAXHASH), gk = HASH2(uid, UMAXHASH); + while (unithash[key]!=NULL && (unithash[key]==delmarker || unithash[key]->no!=uid)) { + key = (key + gk) % UMAXHASH; +#if HASH_STATISTICS + ++hash_misses; +#endif + } + return unithash[key]; + } + return NULL; +} + +#define DMAXHASH 7919 +typedef struct dead { + struct dead * nexthash; + faction * f; + int no; +} dead; + +static dead* deadhash[DMAXHASH]; + +static void +dhash(int no, faction * f) +{ + dead * hash = (dead*)calloc(1, sizeof(dead)); + dead * old = deadhash[no % DMAXHASH]; + hash->no = no; + hash->f = f; + deadhash[no % DMAXHASH] = hash; + hash->nexthash = old; +} + +faction * +dfindhash(int no) +{ + dead * old; + + if(no < 0) return 0; + + for (old = deadhash[no % DMAXHASH]; old; old = old->nexthash) { + if (old->no == no) { + return old->f; + } + } + return 0; +} + +typedef struct friend { + struct friend * next; + int number; + faction * faction; + unit * unit; +} friend; + +static friend * +get_friends(const unit * u, int * numfriends) +{ + friend * friends = 0; + faction * f = u->faction; + region * r = u->region; + int number = 0; + unit * u2; + + for (u2=r->units;u2;u2=u2->next) { + if (u2->faction!=f && u2->number>0) { + int allied = 0; + if (get_param_int(global.parameters, "rules.alliances", 0)!=0) { + allied = (f->alliance && f->alliance==u2->faction->alliance); + } + else if (alliedunit(u, u2->faction, HELP_MONEY) && alliedunit(u2, f, HELP_GIVE)) { + allied = 1; + } + if (allied) { + friend * nf, ** fr = &friends; + + /* some units won't take stuff: */ + if (u2->race->ec_flags & GETITEM) { + while (*fr && (*fr)->faction->nofaction->no) fr = &(*fr)->next; + nf = *fr; + if (nf==NULL || nf->faction!=u2->faction) { + nf = malloc(sizeof(friend)); + nf->next = *fr; + nf->faction = u2->faction; + nf->unit = u2; + nf->number = 0; + *fr = nf; + } else if (nf->faction==u2->faction && (u2->race->ec_flags & GIVEITEM)) { + /* we don't like to gift it to units that won't give it back */ + if ((nf->unit->race->ec_flags & GIVEITEM) == 0) { + nf->unit = u2; + } + } + nf->number += u2->number; + number += u2->number; + } + } + } + } + if (numfriends) *numfriends = number; + return friends; +} + +/** give all items to friends or peasants. + * this function returns 0 on success, or 1 if there are items that + * could not be destroyed. + */ +int +gift_items(unit * u, int flags) +{ + region * r = u->region; + item ** itm_p = &u->items; + int retval = 0; + int rule = rule_give(); + + if ((u->faction->flags&FFL_QUIT)==0 || (rule&GIVE_ONDEATH)==0) { + if ((rule&GIVE_ALLITEMS)==0 && (flags&GIFT_FRIENDS)) flags-=GIFT_FRIENDS; + if ((rule&GIVE_PEASANTS)==0 && (flags&GIFT_PEASANTS)) flags-=GIFT_PEASANTS; + if ((rule&GIVE_SELF)==0 && (flags&GIFT_SELF)) flags-=GIFT_SELF; + } + + if (u->items==NULL || fval(u->race, RCF_ILLUSIONARY)) return 0; + if ((u->race->ec_flags & GIVEITEM) == 0) return 0; + + /* at first, I should try giving my crap to my own units in this region */ + if (u->faction && (u->faction->flags&FFL_QUIT)==0 && (flags & GIFT_SELF)) { + unit * u2, * u3 = NULL; + for (u2 = r->units; u2; u2 = u2->next) { + if (u2 != u && u2->faction == u->faction && u2->number>0) { + /* some units won't take stuff: */ + if (u2->race->ec_flags & GETITEM) { + /* we don't like to gift it to units that won't give it back */ + if (u2->race->ec_flags & GIVEITEM) { + i_merge(&u2->items, &u->items); + u->items = NULL; + break; + } else { + u3 = u2; + } + } + } + } + if (u->items && u3) { + /* if nobody else takes it, we give it to a unit that has issues */ + i_merge(&u3->items, &u->items); + u->items = NULL; + } + if (u->items==NULL) return 0; + } + + /* if I have friends, I'll try to give my stuff to them */ + if (u->faction && (flags & GIFT_FRIENDS)) { + int number = 0; + friend * friends = get_friends(u, &number); + + while (friends) { + struct friend * nf = friends; + unit * u2 = nf->unit; + item * itm = u->items; + while (itm!=NULL) { + const item_type * itype = itm->type; + item * itn = itm->next; + int n = itm->number; + n = n * nf->number / number; + if (n>0) { + i_change(&u->items, itype, -n); + i_change(&u2->items, itype, n); + } + itm = itn; + } + number -= nf->number; + friends = nf->next; + free(nf); + } + if (u->items==NULL) return 0; + } + + /* last, but not least, give money and horses to peasants */ + while (*itm_p) { + item * itm = *itm_p; + + if (flags & GIFT_PEASANTS) { + if (!fval(u->region->terrain, SEA_REGION)) { + if (itm->type==olditemtype[I_HORSE]) { + rsethorses(r, rhorses(r) + itm->number); + itm->number = 0; + } else if (itm->type==i_silver) { + rsetmoney(r, rmoney(r) + itm->number); + itm->number = 0; + } + } + } + if (itm->number>0 && (itm->type->flags & ITF_NOTLOST)) { + itm_p = &itm->next; + retval = -1; + } else { + i_remove(itm_p, itm); + i_free(itm); + } + } + return retval; +} + +void +make_zombie(unit * u) +{ + u_setfaction(u, get_monsters()); + scale_number(u, 1); + u->race = new_race[RC_ZOMBIE]; + u->irace = NULL; +} + +/** remove the unit from the list of active units. + * the unit is not actually freed, because there may still be references + * dangling to it (from messages, for example). To free all removed units, + * call free_units(). + * returns 0 on success, or -1 if unit could not be removed. + */ + +static unit * deleted_units = NULL; + +int +remove_unit(unit ** ulist, unit * u) +{ + int result; + + assert(ufindhash(u->no)); + handle_event(u->attribs, "destroy", u); + + result = gift_items(u, GIFT_SELF|GIFT_FRIENDS|GIFT_PEASANTS); + if (result!=0) { + make_zombie(u); + return -1; + } + + if (u->number) set_number(u, 0); + leave(u, true); + u->region = NULL; + + uunhash(u); + if (ulist) { + while (*ulist!=u) { + ulist = &(*ulist)->next; + } + assert(*ulist==u); + *ulist = u->next; + } + + u->next = deleted_units; + deleted_units = u; + dhash(u->no, u->faction); + + u_setfaction(u, NULL); + u->region = NULL; + + return 0; +} + +unit * +findnewunit (const region * r, const faction *f, int n) +{ + unit *u2; + + if (n == 0) + return 0; + + for (u2 = r->units; u2; u2 = u2->next) + if (u2->faction == f && ualias(u2) == n) + return u2; +#ifdef FIND_FOREIGN_TEMP + for (u2 = r->units; u2; u2 = u2->next) + if (ualias(u2) == n) + return u2; +#endif + return 0; +} + +/* ------------------------------------------------------------- */ + + +/*********************/ +/* at_alias */ +/*********************/ +attrib_type at_alias = { + "alias", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +int +ualias(const unit * u) +{ + attrib * a = a_find(u->attribs, &at_alias); + if (!a) return 0; + return a->data.i; +} + +int +a_readprivate(attrib * a, void * owner, struct storage * store) +{ + a->data.v = store->r_str(store); + if (a->data.v) return AT_READ_OK; + return AT_READ_FAIL; +} + +/*********************/ +/* at_private */ +/*********************/ +attrib_type at_private = { + "private", + DEFAULT_INIT, + a_finalizestring, + DEFAULT_AGE, + a_writestring, + a_readprivate +}; + +const char * +u_description(const unit * u, const struct locale * lang) +{ + if (u->display && u->display[0]) { + return u->display; + } else if (u->race->describe) { + return u->race->describe(u, lang); + } + return NULL; +} + +const char * +uprivate(const unit * u) +{ + attrib * a = a_find(u->attribs, &at_private); + if (!a) return NULL; + return a->data.v; +} + +void +usetprivate(unit * u, const char * str) +{ + attrib * a = a_find(u->attribs, &at_private); + + if (str == NULL) { + if (a) a_remove(&u->attribs, a); + return; + } + if (!a) a = a_add(&u->attribs, a_new(&at_private)); + if (a->data.v) free(a->data.v); + a->data.v = strdup((const char*)str); +} + +/*********************/ +/* at_potionuser */ +/*********************/ +/* Einheit BENUTZT einen Trank */ +attrib_type at_potionuser = { + "potionuser", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +void +usetpotionuse(unit * u, const potion_type * ptype) +{ + attrib * a = a_find(u->attribs, &at_potionuser); + if (!a) a = a_add(&u->attribs, a_new(&at_potionuser)); + a->data.v = (void*)ptype; +} + +const potion_type * +ugetpotionuse(const unit * u) { + attrib * a = a_find(u->attribs, &at_potionuser); + if (!a) return NULL; + return (const potion_type *)a->data.v; +} + +/*********************/ +/* at_target */ +/*********************/ +attrib_type at_target = { + "target", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +unit * +utarget(const unit * u) { + attrib * a; + if (!fval(u, UFL_TARGET)) return NULL; + a = a_find(u->attribs, &at_target); + assert (a || !"flag set, but no target found"); + return (unit*)a->data.v; +} + +void +usettarget(unit * u, const unit * t) +{ + attrib * a = a_find(u->attribs, &at_target); + if (!a && t) a = a_add(&u->attribs, a_new(&at_target)); + if (a) { + if (!t) { + a_remove(&u->attribs, a); + freset(u, UFL_TARGET); + } + else { + a->data.v = (void*)t; + fset(u, UFL_TARGET); + } + } +} + +/*********************/ +/* at_siege */ +/*********************/ + +void +a_writesiege(const attrib * a, const void * owner, struct storage * store) +{ + struct building * b = (struct building*)a->data.v; + write_building_reference(b, store); +} + +int +a_readsiege(attrib * a, void * owner, struct storage * store) +{ + int result = read_reference(&a->data.v, store, read_building_reference, resolve_building); + if (result==0 && !a->data.v) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +attrib_type at_siege = { + "siege", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + a_writesiege, + a_readsiege +}; + +struct building * + usiege(const unit * u) { + attrib * a; + if (!fval(u, UFL_SIEGE)) return NULL; + a = a_find(u->attribs, &at_siege); + assert (a || !"flag set, but no siege found"); + return (struct building *)a->data.v; +} + +void +usetsiege(unit * u, const struct building * t) +{ + attrib * a = a_find(u->attribs, &at_siege); + if (!a && t) a = a_add(&u->attribs, a_new(&at_siege)); + if (a) { + if (!t) { + a_remove(&u->attribs, a); + freset(u, UFL_SIEGE); + } + else { + a->data.v = (void*)t; + fset(u, UFL_SIEGE); + } + } +} + +/*********************/ +/* at_contact */ +/*********************/ +attrib_type at_contact = { + "contact", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +void +usetcontact(unit * u, const unit * u2) +{ + attrib * a = a_find(u->attribs, &at_contact); + while (a && a->type==&at_contact && a->data.v!=u2) a = a->next; + if (a && a->type==&at_contact) return; + a_add(&u->attribs, a_new(&at_contact))->data.v = (void*)u2; +} + +boolean +ucontact(const unit * u, const unit * u2) +/* Prüft, ob u den Kontaktiere-Befehl zu u2 gesetzt hat. */ +{ + attrib *ru; + if (u->faction==u2->faction) return true; + + /* Explizites KONTAKTIERE */ + for (ru = a_find(u->attribs, &at_contact); ru && ru->type==&at_contact; ru = ru->next) { + if (((unit*)ru->data.v) == u2) { + return true; + } + } + + return false; +} + +/*** +** init & cleanup module +**/ + +void +free_units(void) +{ + while (deleted_units) { + unit * u = deleted_units; + deleted_units = deleted_units->next; + free_unit(u); + free(u); + } +} + + +void +write_unit_reference(const unit * u, struct storage * store) +{ + store->w_id(store, (u && u->region)?u->no:0); +} + +int +resolve_unit(variant id, void * address) +{ + unit * u = NULL; + if (id.i!=0) { + u = findunit(id.i); + if (u==NULL) { + *(unit**)address = NULL; + return -1; + } + } + *(unit**)address = u; + return 0; +} + +variant +read_unit_reference(struct storage * store) +{ + variant var; + var.i = store->r_id(store); + return var; +} + +attrib_type at_stealth = { + "stealth", NULL, NULL, NULL, a_writeint, a_readint +}; + +void +u_seteffstealth(unit * u, int value) +{ + if (skill_enabled[SK_STEALTH]) { + attrib * a = NULL; + if (fval(u, UFL_STEALTH)) { + a = a_find(u->attribs, &at_stealth); + } + if (value<0) { + if (a!=NULL) { + freset(u, UFL_STEALTH); + a_remove(&u->attribs, a); + } + return; + } + if (a==NULL) { + a = a_add(&u->attribs, a_new(&at_stealth)); + fset(u, UFL_STEALTH); + } + a->data.i = value; + } +} + +int +u_geteffstealth(const struct unit * u) +{ + if (skill_enabled[SK_STEALTH]) { + if (fval(u, UFL_STEALTH)) { + attrib * a = a_find(u->attribs, &at_stealth); + if (a!=NULL) return a->data.i; + } + } + return -1; +} + +int +get_level(const unit * u, skill_t id) +{ + if (skill_enabled[id]) { + skill * sv = u->skills; + while (sv != u->skills + u->skill_size) { + if (sv->id == id) { + return sv->level; + } + ++sv; + } + } + return 0; +} + +void +set_level(unit * u, skill_t sk, int value) +{ + skill * sv = u->skills; + + if (!skill_enabled[sk]) return; + + if (value==0) { + remove_skill(u, sk); + return; + } + while (sv != u->skills + u->skill_size) { + if (sv->id == sk) { + sk_set(sv, value); + return; + } + ++sv; + } + sk_set(add_skill(u, sk), value); +} + +static int +leftship_age(struct attrib * a) +{ + /* must be aged, so it doesn't affect report generation (cansee) */ + unused(a); + return AT_AGE_REMOVE; /* remove me */ +} + +static attrib_type at_leftship = { + "leftship", NULL, NULL, leftship_age +}; + +static attrib * +make_leftship(struct ship * leftship) +{ + attrib * a = a_new(&at_leftship); + a->data.v = leftship; + return a; +} + +void +set_leftship(unit *u, ship *sh) +{ + a_add(&u->attribs, make_leftship(sh)); +} + +ship * +leftship(const unit *u) +{ + attrib * a = a_find(u->attribs, &at_leftship); + + /* Achtung: Es ist nicht garantiert, daß der Rückgabewert zu jedem + * Zeitpunkt noch auf ein existierendes Schiff zeigt! */ + + if (a) return (ship *)(a->data.v); + + return NULL; +} + +void +leave_ship(unit * u) +{ + struct ship * sh = u->ship; + if (sh==NULL) return; + u->ship = NULL; + set_leftship(u, sh); + + if (fval(u, UFL_OWNER)) { + unit *u2, *owner = NULL; + freset(u, UFL_OWNER); + + for (u2 = u->region->units; u2; u2 = u2->next) { + if (u2->ship == sh) { + if (u2->faction == u->faction) { + owner = u2; + break; + } + else if (owner==NULL) owner = u2; + } + } + if (owner!=NULL) fset(owner, UFL_OWNER); + } +} + +void +leave_building(unit * u) +{ + struct building * b = u->building; + if (!b) return; + u->building = NULL; + + if (fval(u, UFL_OWNER)) { + unit *u2, *owner = NULL; + freset(u, UFL_OWNER); + + for (u2 = u->region->units; u2; u2 = u2->next) { + if (u2->building == b) { + if (u2->faction == u->faction) { + owner = u2; + break; + } + else if (owner==NULL) owner = u2; + } + } + if (owner!=NULL) { + fset(owner, UFL_OWNER); + } + } +} + +boolean +can_leave(unit * u) +{ + static int rule_leave = -1; + + if (!u->building) { + return true; + } + if (rule_leave<0) { + rule_leave = get_param_int(global.parameters, "rules.move.owner_leave", 0); + } + if (rule_leave && u->building && u==building_owner(u->building)) { + return false; + } + return true; +} + +boolean +leave(unit * u, boolean force) +{ + if (!force) { + if (!can_leave(u)) { + return false; + } + } + if (u->building) leave_building(u); + else if (u->ship) leave_ship(u); + return true; +} + +const struct race * +urace(const struct unit * u) +{ + return u->race; +} + +boolean +can_survive(const unit *u, const region *r) +{ + if ((fval(r->terrain, WALK_INTO) && (u->race->flags & RCF_WALK)) + || (fval(r->terrain, SWIM_INTO) && (u->race->flags & RCF_SWIM)) + || (fval(r->terrain, FLY_INTO) && (u->race->flags & RCF_FLY))) + { + static const curse_type * ctype = NULL; + + if (has_horses(u) && !fval(r->terrain, WALK_INTO)) + return false; + + if (!ctype) ctype = ct_find("holyground"); + if (fval(u->race, RCF_UNDEAD) && curse_active(get_curse(r->attribs, ctype))) + return false; + + return true; + } + return false; +} + +void +move_unit(unit * u, region * r, unit ** ulist) +{ + int maxhp = 0; + assert(u && r); + + assert(u->faction || !"this unit is dead"); + if (u->region == r) return; + if (u->region!=NULL) maxhp = unit_max_hp(u); + if (!ulist) ulist = (&r->units); + if (u->region) { + setguard(u, GUARD_NONE); + fset(u, UFL_MOVED); + if (u->ship || u->building) { + /* can_leave must be checked in travel_i */ +#ifndef NDEBUG + boolean result = leave(u, false); + assert(result); +#else + leave(u, false); +#endif + } + translist(&u->region->units, ulist, u); + } else { + addlist(ulist, u); + } + +#ifdef SMART_INTERVALS + update_interval(u->faction, r); +#endif + u->region = r; + /* keine automatische hp reduzierung bei bewegung */ + /* if (maxhp>0) u->hp = u->hp * unit_max_hp(u) / maxhp; */ +} + +/* ist mist, aber wegen nicht skalierender attribute notwendig: */ +#include "alchemy.h" + +void +transfermen(unit * u, unit * u2, int n) +{ + const attrib * a; + int hp = u->hp; + region * r = u->region; + + if (n==0) return; + assert(n > 0); + /* "hat attackiert"-status wird übergeben */ + + if (u2) { + skill *sv, *sn; + skill_t sk; + ship * sh; + + assert(u2->number+n>0); + + for (sk=0; sk!=MAXSKILLS; ++sk) { + int weeks, level = 0; + + sv = get_skill(u, sk); + sn = get_skill(u2, sk); + + if (sv==NULL && sn==NULL) continue; + if (sn==NULL && u2->number==0) { + /* new unit, easy to solve */ + level = sv->level; + weeks = sv->weeks; + } else { + double dlevel = 0.0; + + if (sv && sv->level) { + dlevel += (sv->level + 1 - sv->weeks/(sv->level+1.0)) * n; + level += sv->level * n; + } + if (sn && sn->level) { + dlevel += (sn->level + 1 - sn->weeks/(sn->level+1.0)) * u2->number; + level += sn->level * u2->number; + } + + dlevel = dlevel / (n + u2->number); + level = level / (n + u2->number); + if (level<=dlevel) { + /* apply the remaining fraction to the number of weeks to go. + * subtract the according number of weeks, getting closer to the + * next level */ + level = (int)dlevel; + weeks = (level+1) - (int)((dlevel - level) * (level+1)); + } else { + /* make it harder to reach the next level. + * weeks+level is the max difficulty, 1 - the fraction between + * level and dlevel applied to the number of weeks between this + * and the previous level is the added difficutly */ + level = (int)dlevel+1; + weeks = 1 + 2 * level - (int)((1 + dlevel - level) * level); + } + } + if (level) { + if (sn==NULL) sn = add_skill(u2, sk); + sn->level = (unsigned char)level; + sn->weeks = (unsigned char)weeks; + assert(sn->weeks>0 && sn->weeks<=sn->level*2+1); + assert(u2->number!=0 || (sn->level==sv->level && sn->weeks==sv->weeks)); + } else if (sn) { + remove_skill(u2, sk); + sn = NULL; + } + } + a = a_find(u->attribs, &at_effect); + while (a && a->type==&at_effect) { + effect_data * olde = (effect_data*)a->data.v; + if (olde->value) change_effect(u2, olde->type, olde->value); + a = a->next; + } + sh = leftship(u); + if (sh!=NULL) set_leftship(u2, sh); + u2->flags |= u->flags&(UFL_LONGACTION|UFL_NOTMOVING|UFL_HUNGER|UFL_MOVED|UFL_ENTER); + if (u->attribs) { + transfer_curse(u, u2, n); + } + } + scale_number(u, u->number - n); + if (u2) { + set_number(u2, u2->number + n); + hp -= u->hp; + u2->hp += hp; + /* TODO: Das ist schnarchlahm! und gehört nicht hierhin */ + a = a_find(u2->attribs, &at_effect); + while (a && a->type==&at_effect) { + attrib * an = a->next; + effect_data * olde = (effect_data*)a->data.v; + int e = get_effect(u, olde->type); + if (e!=0) change_effect(u2, olde->type, -e); + a = an; + } + } + else if (r->land) { + if ((u->race->ec_flags & ECF_REC_ETHEREAL)==0) { + const race * rc = u->race; + if (rc->ec_flags & ECF_REC_HORSES) { /* Zentauren an die Pferde */ + int h = rhorses(r) + n; + rsethorses(r, h); + } else { + int p = rpeasants(r); + p += (int)(n * rc->recruit_multi); + rsetpeasants(r, p); + } + } + } +} + +struct building * + inside_building(const struct unit * u) +{ + if (u->building==NULL) return NULL; + + if (!fval(u->building, BLD_WORKING)) { + /* Unterhalt nicht bezahlt */ + return NULL; + } else if (u->building->size < u->building->type->maxsize) { + /* Gebäude noch nicht fertig */ + return NULL; + } else { + int p = 0, cap = buildingcapacity(u->building); + const unit * u2; + for (u2 = u->region->units; u2; u2 = u2->next) { + if (u2->building == u->building) { + p += u2->number; + if (u2 == u) { + if (p <= cap) return u->building; + return NULL; + } + if (p > cap) return NULL; + } + } + } + return NULL; +} + +void +u_setfaction(unit * u, faction * f) +{ + int cnt = u->number; + + if (u->faction==f) return; + if (u->faction) { + set_number(u, 0); + if (count_unit(u)) --u->faction->no_units; + join_group(u, NULL); + free_orders(&u->orders); + set_order(&u->thisorder, NULL); + + if (u->nextF) u->nextF->prevF = u->prevF; + if (u->prevF) u->prevF->nextF = u->nextF; + else u->faction->units = u->nextF; + } + + if (f!=NULL) { + if (f->units) f->units->prevF=u; + u->prevF = NULL; + u->nextF = f->units; + f->units = u; + } + else u->nextF = NULL; + + u->faction = f; + if (u->region) update_interval(f, u->region); + if (cnt && f) { + set_number(u, cnt); + if (count_unit(u)) ++f->no_units; + } +} + +/* vorsicht Sprüche können u->number == RS_FARVISION haben! */ +void +set_number(unit * u, int count) +{ + assert (count >= 0); + assert (count <= UNIT_MAXSIZE); + +#ifndef NDEBUG + assert(u->faction || count==0); +#endif + + if (count == 0) { + u->flags &= ~(UFL_HERO); + } + if (u->faction) { + if (playerrace(u->race)) { + u->faction->num_people += count - u->number; + } + u->number = (unsigned short)count; + } else if (u->number>0) { + assert(!"why doesn't this unit have a faction? this will fuck up num_people"); + } +} + +boolean +learn_skill(unit * u, skill_t sk, double chance) +{ + skill * sv = u->skills; + if (chance < 1.0 && rng_int()%10000>=chance*10000) return false; + while (sv != u->skills + u->skill_size) { + assert (sv->weeks>0); + if (sv->id == sk) { + if (sv->weeks<=1) { + sk_set(sv, sv->level+1); + } else { + sv->weeks--; + } + return true; + } + ++sv; + } + sv = add_skill(u, sk); + sk_set(sv, 1); + return true; +} + +void +remove_skill(unit *u, skill_t sk) +{ + skill * sv = u->skills; + for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { + if (sv->id==sk) { + skill * sl = u->skills + u->skill_size - 1; + if (sl!=sv) { + *sv = *sl; + } + --u->skill_size; + return; + } + } +} + +skill * +add_skill(unit * u, skill_t id) +{ + skill * sv = u->skills; +#ifndef NDEBUG + for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { + assert(sv->id != id); + } +#endif + ++u->skill_size; + u->skills = realloc(u->skills, u->skill_size * sizeof(skill)); + sv = (u->skills + u->skill_size - 1); + sv->level = (unsigned char)0; + sv->weeks = (unsigned char)1; + sv->old = (unsigned char)0; + sv->id = (unsigned char)id; + return sv; +} + +skill * +get_skill(const unit * u, skill_t sk) +{ + skill * sv = u->skills; + while (sv!=u->skills+u->skill_size) { + if (sv->id==sk) return sv; + ++sv; + } + return NULL; +} + +boolean +has_skill(const unit * u, skill_t sk) +{ + skill * sv = u->skills; + while (sv!=u->skills+u->skill_size) { + if (sv->id==sk) { + return (sv->level>0); + } + ++sv; + } + return false; +} + +static int +item_modification(const unit *u, skill_t sk, int val) +{ + /* Presseausweis: *2 Spionage, 0 Tarnung */ + if(sk == SK_SPY && get_item(u, I_PRESSCARD) >= u->number) { + val = val * 2; + } else if(sk == SK_STEALTH) { +#if NEWATSROI == 1 + if (get_item(u, I_RING_OF_INVISIBILITY) + + 100 * get_item(u, I_SPHERE_OF_INVISIBILITY) >= u->number) { + val += ROIBONUS; + } +#endif + if(get_item(u, I_PRESSCARD) >= u->number) { + val = 0; + } + } +#if NEWATSROI == 1 + if(sk == SK_PERCEPTION) { + if(get_item(u, I_AMULET_OF_TRUE_SEEING) >= u->number) { + val += ATSBONUS; + } + } +#endif + return val; +} + +static int +att_modification(const unit *u, skill_t sk) +{ + double bonus = 0, malus = 0; + attrib * a; + double result = 0; + static boolean init = false; + static const curse_type * skillmod_ct, * gbdream_ct, * worse_ct; + curse * c; + + if (!init) { + init = true; + skillmod_ct = ct_find("skillmod"); + gbdream_ct = ct_find("gbdream"); + worse_ct = ct_find("worse"); + } + + c = get_curse(u->attribs, worse_ct); + if (c!=NULL) result += curse_geteffect(c); + if (skillmod_ct) { + attrib * a = a_find(u->attribs, &at_curse); + while (a && a->type==&at_curse) { + curse * c = (curse *)a->data.v; + if (c->type==skillmod_ct && c->data.i==sk) { + result += curse_geteffect(c); + break; + } + a = a->next; + } + } + + /* TODO hier kann nicht mit get/iscursed gearbeitet werden, da nur der + * jeweils erste vom Typ C_GBDREAM zurückgegen wird, wir aber alle + * durchsuchen und aufaddieren müssen */ + a = a_find(u->region->attribs, &at_curse); + while (a && a->type==&at_curse) { + curse * c = (curse*)a->data.v; + if (curse_active(c) && c->type==gbdream_ct) { + double mod = curse_geteffect(c); + unit * mage = c->magician; + /* wir suchen jeweils den größten Bonus und den größten Malus */ + if (mod>bonus) { + if (mage==NULL || mage->number==0 || alliedunit(mage, u->faction, HELP_GUARD)) { + bonus = mod; + } + } else if (mod < malus) { + if (mage == NULL || !alliedunit(mage, u->faction, HELP_GUARD)) { + malus = mod; + } + } + } + a = a->next; + } + result = result + bonus + malus; + + return (int)result; +} + +int +get_modifier(const unit *u, skill_t sk, int level, const region *r, boolean noitem) +{ + int bskill = level; + int skill = bskill; + + assert(r); + if (sk == SK_STEALTH) { + plane * pl = rplane(r); + if (pl &&fval(pl, PFL_NOSTEALTH)) return 0; + } + + skill += rc_skillmod(u->race, r, sk); + skill += att_modification(u, sk); + + if (noitem == false) { + skill = item_modification(u, sk, skill); + } + skill = skillmod(u->attribs, u, r, sk, skill, SMF_ALWAYS); + +#ifdef HUNGER_REDUCES_SKILL + if (fval(u, UFL_HUNGER)) { + skill = skill/2; + } +#endif + return skill - bskill; +} + +int +eff_skill(const unit * u, skill_t sk, const region * r) +{ + if (skill_enabled[sk]) { + int level = get_level(u, sk); + if (level>0) { + int mlevel = level + get_modifier(u, sk, level, r, false); + + if (mlevel>0) { + int skillcap = SkillCap(sk); + if (skillcap && mlevel>skillcap) { + return skillcap; + } + return mlevel; + } + } + } + return 0; +} + +int +eff_skill_study(const unit * u, skill_t sk, const region * r) +{ + int level = get_level(u, sk); + if (level>0) { + int mlevel = level + get_modifier(u, sk, level, r, true); + + if (mlevel>0) return mlevel; + } + return 0; +} + +int +invisible(const unit *target, const unit * viewer) +{ +#if NEWATSROI == 1 + return 0; +#else + if (viewer && viewer->faction==target->faction) return 0; + else { + int hidden = get_item(target, I_RING_OF_INVISIBILITY) + 100 * get_item(target, I_SPHERE_OF_INVISIBILITY); + if (hidden) { + hidden = MIN(hidden, target->number); + if (viewer) hidden -= get_item(viewer, I_AMULET_OF_TRUE_SEEING); + } + return hidden; + } +#endif +} + +/** remove the unit from memory. + * this frees all memory that's only accessible through the unit, + * and you should already have called uunhash and removed the unit from the + * region. + */ +void +free_unit(unit * u) +{ + free(u->name); + free(u->display); + free_order(u->thisorder); + free_orders(&u->orders); + if (u->skills) free(u->skills); + while (u->items) { + item * it = u->items->next; + u->items->next = NULL; + i_free(u->items); + u->items = it; + } + while (u->attribs) a_remove (&u->attribs, u->attribs); + while (u->reservations) { + struct reservation *res = u->reservations; + u->reservations = res->next; + free(res); + } +} + + +void +unitlist_clear(struct unit_list **ul) +{ + while (*ul) { + unit_list * rl2 = (*ul)->next; + free(*ul); + *ul = rl2; + } +} + +void +unitlist_insert(struct unit_list **ul, struct unit *u) +{ + unit_list *rl2 = (unit_list*)malloc(sizeof(unit_list)); + + rl2->data = u; + rl2->next = *ul; + + *ul = rl2; +} + + +static void +createunitid(unit *u, int id) +{ + if (id<=0 || id > MAX_UNIT_NR || ufindhash(id) || dfindhash(id) || forbiddenid(id)) + u->no = newunitid(); + else + u->no = id; + uhash(u); +} + +void +name_unit(unit *u) +{ + if (u->race->generate_name) { + const char * gen_name = u->race->generate_name(u); + if (gen_name) { + unit_setname(u, gen_name); + } else { + unit_setname(u, racename(u->faction->locale, u, u->race)); + } + } else { + char name[32]; + snprintf(name, sizeof(name), "%s %s", LOC(u->faction->locale, "unitdefault"), itoa36(u->no)); + unit_setname(u, name); + } +} + +/** creates a new unit. +* +* @param dname: name, set to NULL to get a default. +* @param creator: unit to inherit stealth, group, building, ship, etc. from +*/ +unit * +create_unit(region * r, faction * f, int number, const struct race *urace, int id, const char * dname, unit *creator) +{ + unit * u = calloc(1, sizeof(unit)); + + assert(urace); + assert(f->alive); + u_setfaction(u, f); + + if (f->locale) { + order * deford = default_order(f->locale); + if (deford) { + set_order(&u->thisorder, NULL); + addlist(&u->orders, deford); + } + } + u_seteffstealth(u, -1); + u->race = urace; + u->irace = NULL; + + set_number(u, number); + + /* die nummer der neuen einheit muss vor name_unit generiert werden, + * da der default name immer noch 'Nummer u->no' ist */ + createunitid(u, id); + + /* zuerst in die Region setzen, da zb Drachennamen den Regionsnamen + * enthalten */ + if (r) move_unit(u, r, NULL); + + /* u->race muss bereits gesetzt sein, wird für default-hp gebraucht */ + /* u->region auch */ + u->hp = unit_max_hp(u) * number; + + if (!dname) { + name_unit(u); + } else { + u->name = strdup(dname); + } + if (count_unit(u)) f->no_units++; + + if (creator) { + attrib * a; + + /* erbt Kampfstatus */ + setstatus(u, creator->status); + + /* erbt Gebäude/Schiff*/ + if (creator->region==r) { + u->building = creator->building; + if (creator->ship!=NULL && fval(u->race, RCF_CANSAIL)) { + u->ship = creator->ship; + } + } + + /* Tarnlimit wird vererbt */ + if (fval(creator, UFL_STEALTH)) { + attrib * a = a_find(creator->attribs, &at_stealth); + if (a) { + int stealth = a->data.i; + a = a_add(&u->attribs, a_new(&at_stealth)); + a->data.i = stealth; + } + } + + /* Temps von parteigetarnten Einheiten sind wieder parteigetarnt */ + if (fval(creator, UFL_ANON_FACTION)) { + fset(u, UFL_ANON_FACTION); + } + /* Daemonentarnung */ + set_racename(&u->attribs, get_racename(creator->attribs)); + if (fval(u->race, RCF_SHAPESHIFT) && fval(creator->race, RCF_SHAPESHIFT)) { + u->irace = creator->irace; + } + + /* Gruppen */ + if (creator->faction==f && fval(creator, UFL_GROUP)) { + a = a_find(creator->attribs, &at_group); + if (a) { + group * g = (group*)a->data.v; + set_group(u, g); + } + } + a = a_find(creator->attribs, &at_otherfaction); + if (a) { + a_add(&u->attribs, make_otherfaction(get_otherfaction(a))); + } + + a = a_add(&u->attribs, a_new(&at_creator)); + a->data.v = creator; + } + + return u; +} + +int +maxheroes(const struct faction * f) +{ + int nsize = count_all(f); + if (nsize==0) return 0; + else { + int nmax = (int)(log10(nsize / 50.0) * 20); + return (nmax<0)?0:nmax; + } +} + +int +countheroes(const struct faction * f) +{ + const unit * u = f->units; + int n = 0; + + while (u) { + if (fval(u, UFL_HERO)) n+= u->number; + u = u->nextF; + } +#ifdef DEBUG_MAXHEROES + int m = maxheroes(f); + if (n>m) { + log_warning(("%s has %d of %d heroes\n", factionname(f), n, m)); + } +#endif + return n; +} + +const char * +unit_getname(const unit * u) +{ + return (const char *)u->name; +} + +void +unit_setname(unit * u, const char * name) +{ + free(u->name); + if (name) u->name = strdup(name); + else u->name = NULL; +} + +const char * +unit_getinfo(const unit * u) +{ + return (const char *)u->display; +} + +void +unit_setinfo(unit * u, const char * info) +{ + free(u->display); + if (info) u->display = strdup(info); + else u->display = NULL; +} + +int +unit_getid(const unit * u) +{ + return u->no; +} + +void +unit_setid(unit * u, int id) +{ + unit * nu = findunit(id); + if (nu==NULL) { + uunhash(u); + u->no = id; + uhash(u); + } +} + +int +unit_gethp(const unit * u) +{ + return u->hp; +} + +void +unit_sethp(unit * u, int hp) +{ + u->hp = hp; +} + +status_t +unit_getstatus(const unit * u) +{ + return u->status; +} + +void +unit_setstatus(unit * u, status_t status) +{ + u->status = status; +} + +int +unit_getweight(const unit * u) +{ + return weight(u); +} + +int +unit_getcapacity(const unit * u) +{ + return walkingcapacity(u); +} + +void +unit_addorder(unit * u, order * ord) +{ + order ** ordp = &u->orders; + while (*ordp) ordp = &(*ordp)->next; + *ordp = ord; + u->faction->lastorders = turn; +} + +int +unit_max_hp(const unit * u) +{ + static int rules_stamina = -1; + int h; + double p; + static const curse_type * heal_ct = NULL; + + if (rules_stamina<0) { + rules_stamina = get_param_int(global.parameters, "rules.stamina", STAMINA_AFFECTS_HP); + } + h = u->race->hitpoints; + if (heal_ct==NULL) heal_ct = ct_find("healingzone"); + + if (rules_stamina & 1) { + p = pow(effskill(u, SK_STAMINA) / 2.0, 1.5) * 0.2; + h += (int) (h * p + 0.5); + } + /* der healing curse verändert die maximalen hp */ + if (heal_ct) { + curse *c = get_curse(u->region->attribs, heal_ct); + if (c) { + h = (int) (h * (1.0+(curse_geteffect(c)/100))); + } + } + + return h; +} + +void +scale_number (unit * u, int n) +{ + skill_t sk; + const attrib * a; + int remain; + + if (n == u->number) return; + if (n && u->number>0) { + int full; + remain = ((u->hp%u->number) * (n % u->number)) % u->number; + + full = u->hp/u->number; /* wieviel kriegt jede person mindestens */ + u->hp = full * n + (u->hp-full*u->number) * n / u->number; + assert(u->hp>=0); + if ((rng_int() % u->number) < remain) + ++u->hp; /* Nachkommastellen */ + } else { + remain = 0; + u->hp = 0; + } + if (u->number>0) { + for (a = a_find(u->attribs, &at_effect);a && a->type==&at_effect;a=a->next) { + effect_data * data = (effect_data *)a->data.v; + int snew = data->value / u->number * n; + if (n) { + remain = data->value - snew / n * u->number; + snew += remain * n / u->number; + remain = (remain * n) % u->number; + if ((rng_int() % u->number) < remain) + ++snew; /* Nachkommastellen */ + } + data->value = snew; + } + } + if (u->number==0 || n==0) { + for (sk = 0; sk < MAXSKILLS; sk++) { + remove_skill(u, sk); + } + } + + set_number(u, n); +} + +const struct race * u_irace(const struct unit * u) +{ + if (u->irace && skill_enabled[SK_STEALTH]) { + return u->irace; + } + return u->race; +} diff --git a/src/kernel/unit.h b/src/kernel/unit.h new file mode 100644 index 000000000..86af46741 --- /dev/null +++ b/src/kernel/unit.h @@ -0,0 +1,237 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_UNIT_H +#define H_KRNL_UNIT_H + +#include +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct skill; +struct item; +#define UFL_DEBUG (1<<0) +#define UFL_ISNEW (1<<1) /* 2 */ +#define UFL_LONGACTION (1<<2) /* 4 */ +#define UFL_OWNER (1<<3) /* 8 */ +#define UFL_ANON_FACTION (1<<4) /* 16 */ +#define UFL_DISBELIEVES (1<<5) /* 32 */ +#define UFL_WARMTH (1<<6) /* 64 */ +#define UFL_HERO (1<<7) +#define UFL_MOVED (1<<8) +#define UFL_NOTMOVING (1<<9) /* Die Einheit kann sich wg. langen Kampfes nicht bewegen */ +#define UFL_DEFENDER (1<<10) +#define UFL_HUNGER (1<<11) /* kann im Folgemonat keinen langen Befehl außer ARBEITE ausführen */ +#define UFL_SIEGE (1<<12) /* speedup: belagert eine burg, siehe attribut */ +#define UFL_TARGET (1<<13) /* speedup: hat ein target, siehe attribut */ +#define UFL_WERE (1<<14) +#define UFL_ENTER (1<<15) /* unit has entered a ship/building and will not leave it */ + +/* warning: von 512/1024 gewechslet, wegen konflikt mit NEW_FOLLOW */ +#define UFL_LOCKED (1<<16) /* Einheit kann keine Personen aufnehmen oder weggeben, nicht rekrutieren. */ +#define UFL_FLEEING (1<<17) /* unit was in a battle, fleeing. */ +#define UFL_STORM (1<<19) /* Kapitän war in einem Sturm */ +#define UFL_FOLLOWING (1<<20) +#define UFL_FOLLOWED (1<<21) + +#define UFL_NOAID (1<<22) /* Einheit hat Noaid-Status */ +#define UFL_MARK (1<<23) /* same as FL_MARK */ +#define UFL_ORDERS (1<<24) /* Einheit hat Befehle erhalten */ +#define UFL_TAKEALL (1<<25) /* Einheit nimmt alle Gegenstände an */ + +/* flags that speed up attribute access: */ +#define UFL_STEALTH (1<<26) +#define UFL_GUARD (1<<27) +#define UFL_GROUP (1<<28) + +/* Flags, die gespeichert werden sollen: */ +#define UFL_SAVEMASK (UFL_DEFENDER|UFL_MOVED|UFL_NOAID|UFL_OWNER|UFL_ANON_FACTION|UFL_LOCKED|UFL_HUNGER|UFL_TAKEALL|UFL_GUARD|UFL_STEALTH|UFL_GROUP|UFL_HERO) + +#define UNIT_MAXSIZE 50000 +extern int maxheroes(const struct faction * f); +extern int countheroes(const struct faction * f); + +typedef struct unit { + struct unit *next; /* needs to be first entry, for region's unitlist */ + struct unit *nextF; /* nächste Einheit der Partei */ + struct unit *prevF; /* vorherige Einheit der Partei */ + struct region *region; + int no; + int hp; + char *name; + char *display; + struct faction *faction; + struct building *building; + struct ship *ship; + unsigned short number; + short age; + + /* skill data */ + short skill_size; + struct skill *skills; + struct item * items; + struct reservation { + struct reservation * next; + const struct resource_type * type; + int value; + } * reservations; + + /* orders */ + struct order * orders; + struct order * thisorder; + struct order * old_orders; + + /* race and illusionary race */ + const struct race * race; + const struct race * irace; + + unsigned int flags; + struct attrib * attribs; + status_t status; + int n; /* enno: attribut? */ + int wants; /* enno: attribut? */ +} unit; + +typedef struct unit_list { + struct unit_list * next; + struct unit * data; +} unit_list; + +extern void unitlist_clear(struct unit_list **ul); +extern void unitlist_insert(struct unit_list **ul, struct unit *u); + +extern struct attrib_type at_alias; +extern struct attrib_type at_siege; +extern struct attrib_type at_target; +extern struct attrib_type at_potionuser; +extern struct attrib_type at_contact; +extern struct attrib_type at_effect; +extern struct attrib_type at_private; +extern struct attrib_type at_showskchange; + +int ualias(const struct unit * u); + +extern struct attrib_type at_stealth; + +void u_seteffstealth(struct unit * u, int value); +int u_geteffstealth(const struct unit * u); +const struct race * u_irace(const struct unit * u); +struct building * usiege(const struct unit * u); +void usetsiege(struct unit * u, const struct building * b); + +struct unit * utarget(const struct unit * u); +void usettarget(struct unit * u, const struct unit * b); + +struct unit * utarget(const struct unit * u); +void usettarget(struct unit * u, const struct unit * b); + +extern const struct race * urace(const struct unit * u); + +const char * uprivate(const struct unit * u); +void usetprivate(struct unit * u, const char * c); + +const struct potion_type * ugetpotionuse(const struct unit * u); /* benutzt u einein trank? */ +void usetpotionuse(struct unit * u, const struct potion_type * p); /* u benutzt trank p (es darf halt nur einer pro runde) */ + +boolean ucontact(const struct unit * u, const struct unit * u2); +void usetcontact(struct unit * u, const struct unit * c); + +struct unit * findnewunit (const struct region * r, const struct faction *f, int alias); + +extern const char * u_description(const unit * u, const struct locale * lang); +extern struct skill * add_skill(struct unit * u, skill_t id); +extern void remove_skill(struct unit *u, skill_t sk); +extern struct skill * get_skill(const struct unit * u, skill_t id); +extern boolean has_skill(const unit* u, skill_t sk); + +extern void set_level(struct unit * u, skill_t id, int level); +extern int get_level(const struct unit * u, skill_t id); +extern void transfermen(struct unit * u, struct unit * u2, int n); + +extern int eff_skill(const struct unit * u, skill_t sk, const struct region * r); +extern int eff_skill_study(const struct unit * u, skill_t sk, const struct region * r); + +extern int get_modifier(const struct unit * u, skill_t sk, int lvl, const struct region * r, boolean noitem); +extern int remove_unit(struct unit ** ulist, struct unit * u); + +#define GIFT_SELF 1<<0 +#define GIFT_FRIENDS 1<<1 +#define GIFT_PEASANTS 1<<2 +int gift_items(struct unit * u, int flags); +void make_zombie(unit * u); + +/* see resolve.h */ +extern int resolve_unit(variant data, void * address); +extern void write_unit_reference(const struct unit * u, struct storage * store); +extern variant read_unit_reference(struct storage * store); + +extern boolean leave(struct unit * u, boolean force); +extern boolean can_leave(struct unit * u); + +extern void leave_ship(unit * u); +extern void leave_building(unit * u); + +extern void set_leftship(struct unit *u, struct ship *sh); +extern struct ship * leftship(const struct unit *); +extern boolean can_survive(const struct unit *u, const struct region *r); +extern void move_unit(struct unit * u, struct region * target, struct unit ** ulist); + +extern struct building * inside_building(const struct unit * u); + +/* cleanup code for this module */ +extern void free_units(void); +extern struct faction * dfindhash(int no); +extern void u_setfaction(struct unit * u, struct faction * f); +extern void set_number(struct unit * u, int count); + +extern boolean learn_skill(struct unit * u, skill_t sk, double chance); + +extern int invisible(const struct unit *target, const struct unit * viewer); +extern void free_unit(struct unit * u); + +extern void name_unit(struct unit *u); +extern struct unit * create_unit(struct region * r1, struct faction * f, int number, const struct race * rc, int id, const char * dname, struct unit *creator); + +extern void uhash(struct unit * u); +extern void uunhash(struct unit * u); +extern struct unit *ufindhash(int i); + +const char * unit_getname(const struct unit * u); +void unit_setname(struct unit * u, const char * name); +const char * unit_getinfo(const struct unit * u); +void unit_setinfo(struct unit * u, const char * name); +int unit_getid(const unit * u); +void unit_setid(unit * u, int id); +int unit_gethp(const unit * u); +void unit_sethp(unit * u, int id); +status_t unit_getstatus(const unit * u); +void unit_setstatus(unit * u, status_t status); +int unit_getweight(const unit * u); +int unit_getcapacity(const unit * u); +void unit_addorder(unit * u, struct order * ord); +int unit_max_hp(const struct unit * u); +void scale_number(struct unit * u, int n); + +extern struct attrib_type at_creator; +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/version.h b/src/kernel/version.h new file mode 100644 index 000000000..a07ea3e52 --- /dev/null +++ b/src/kernel/version.h @@ -0,0 +1,71 @@ +/* vi: set ts=2: + +-------------------+ + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2007 | Christian Schlittchen + | | + +-------------------+ + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ + +/* changes from->to: 72->73: struct unit::lock entfernt. + * 73->74: struct unit::flags eingeführt. + * 74->75: parteitarnung als flag. + * 75->76: #ifdef NEW_HP: hp + * 76->77: ship->damage + * 77->78: neue Message-Option "Orkvermehrung" (MAX_MSG +1) + * 78->79: showdata nicht mehr speichern + * 79->HEX_VERSION: hex + * 80->82: ATTRIB_VERSION + * 90: Ebenen + * 92: Magiegebiet-Auswahl f->magiegebiet + * 94: f->attribs wird gespeichert + * 100: NEWMAGIC, neue Message-Option "Zauber" (MAX_MSG +1) + * 108: Speichern von Timeouts + * 193: curse bekommen id aus struct unit-nummernraum + */ + +/* +#define HEX_VERSION 81 +#define GROWTREE_VERSION 305 +#define RANDOMIZED_RESOURCES_VERSION 306 +#define NEWRACE_VERSION 307 +#define INTERIM_VERSION 309 +#define NEWSKILL_VERSION 309 +#define WATCHERS_VERSION 310 +*/ +#define OVERRIDE_VERSION 311 +#define CURSETYPE_VERSION 312 /* turn 287 */ +#define ALLIANCES_VERSION 313 +#define DBLINK_VERSION 314 +#define CURSEVIGOURISFLOAT_VERSION 315 +#define SAVEXMLNAME_VERSION 316 +#define SAVEALLIANCE_VERSION 317 +#define CLAIM_VERSION 318 +/* 319 is the HSE4 data version */ +#define BACTION_VERSION 319 /* building action gets a param string */ +#define NOLASTORDER_VERSION 320 /* do not use lastorder */ +#define SPELLNAME_VERSION 321 /* reference spells by name */ +#define TERRAIN_VERSION 322 /* terrains are a full type and saved by name */ +#define REGIONITEMS_VERSION 323 /* regions have items */ +#define ATTRIBREAD_VERSION 324 /* remove a_readint */ +#define CURSEFLAGS_VERSION 325 /* remove a_readint */ +#define UNICODE_VERSION 326 /* 2007-06-27 everything is stored as UTF8 */ +#define UID_VERSION 327 /* regions have a unique id */ +#define STORAGE_VERSION 328 /* with storage.h, some things are stored smarter (ids as base36, fractions as float) */ +#define INTPAK_VERSION 329 /* in binary, ints can get packed */ +#define NOZEROIDS_VERSION 330 /* 2008-05-16 zero is not a valid ID for anything (including factions) */ +#define NOBORDERATTRIBS_VERSION 331 /* 2008-05-17 connection::attribs has been moved to userdata */ +#define UIDHASH_VERSION 332 /* 2008-05-22 borders use the region.uid to store */ +#define REGIONOWNER_VERSION 333 /* 2009-05-14 regions have owners and morale */ +#define ALLIANCELEADER_VERSION 333 /* alliances have a leader */ +#define CURSEFLOAT_VERSION 334 /* all curse-effects are float */ +#define MOURNING_VERSION 335 /* mourning peasants */ +#define FOSS_VERSION 336 /* the open source release */ +#define OWNER_2_VERSION 337 /* region owners contain an alliance */ + +#define MIN_VERSION CURSETYPE_VERSION /* minimal datafile we support */ +#define RELEASE_VERSION OWNER_2_VERSION /* current datafile */ diff --git a/src/kernel/xmlkernel.h b/src/kernel/xmlkernel.h new file mode 100644 index 000000000..b2cb331c4 --- /dev/null +++ b/src/kernel/xmlkernel.h @@ -0,0 +1,28 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2007 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifndef H_KRNL_XML +#define H_KRNL_XML + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern void xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, struct construction ** consPtr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c new file mode 100644 index 000000000..829f3736d --- /dev/null +++ b/src/kernel/xmlreader.c @@ -0,0 +1,2180 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2004 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "xmlreader.h" + +/* kernel includes */ +#include "building.h" +#include "equipment.h" +#include "item.h" +#include "message.h" +#include "race.h" +#include "region.h" +#include "resources.h" +#include "ship.h" +#include "terrain.h" +#include "skill.h" +#include "spell.h" +#include "calendar.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include + + +/* libxml includes */ +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +static boolean gamecode_enabled = false; + +void (*set_spelldata_cb)(struct spell * sp) = 0; +static building_type * bt_get_or_create(const char * name) +{ + if (name!=NULL) { + building_type * btype = bt_find(name); + if (btype==NULL) { + btype = calloc(sizeof(building_type), 1); + btype->_name = strdup(name); + bt_register(btype); + } + return btype; + } + return NULL; +} + +void +enable_xml_gamecode(void) +{ + gamecode_enabled = true; +} + +static void +xml_readtext(xmlNodePtr node, struct locale ** lang, xmlChar **text) +{ + xmlChar * propValue = xmlGetProp(node, BAD_CAST "locale"); + assert(propValue!=NULL); + *lang = find_locale((const char*)propValue); +#ifdef MAKE_LOCALES + if (*lang==NULL) *lang = make_locale((const char*)propValue); +#endif + xmlFree(propValue); + + *text = xmlNodeListGetString(node->doc, node->children, 1); +} + +static const spell * +xml_spell(xmlNode * node, const char * name) +{ + const spell * sp = NULL; + xmlChar * propValue = xmlGetProp(node, BAD_CAST name); + if (propValue!=NULL) { + sp = find_spell(M_NONE, (const char *)propValue); + assert(sp); + xmlFree(propValue); + } + return sp; +} + +static xmlChar * +xml_cleanup_string(xmlChar * str) +{ + xmlChar * read = str; + xmlChar * write = str; + + while (*read) { + /* eat leading whitespace */ + if (*read && isxspace(*read)) { + while (*read && isxspace(*read)) { + ++read; + } + *write++ = ' '; + } + while (*read) { + if (*read== '\n') break; + if (*read== '\r') break; + *write++ = *read++; + } + } + *write = 0; + return str; +} + +static const resource_type * +rt_findorcreate(const char * name) +{ + resource_type * rtype = rt_find(name); + if (rtype==NULL) { + const char * names[2]; + char * namep = strcat(strcpy((char*)malloc(strlen(name)+3), name), "_p"); + /* we'll make a placeholder */ + names[0] = name; + names[1] = namep; + rtype = new_resourcetype(names, NULL, RTF_NONE); + free(namep); + } + return rtype; +} + +static void +xml_readrequirements(xmlNodePtr * nodeTab, int nodeNr, requirement ** reqArray) +{ + int req; + requirement * radd = *reqArray; + + assert (radd==NULL); + if (nodeNr==0) return; + + radd = *reqArray = calloc(sizeof(requirement), nodeNr+1); + + for (req=0;req!=nodeNr;++req) { + xmlNodePtr node = nodeTab[req]; + xmlChar * propValue; + + radd->number = xml_ivalue(node, "quantity", 1); + radd->recycle = xml_fvalue(node, "recycle", 0.5); + + propValue = xmlGetProp(node, BAD_CAST "type"); + radd->rtype = rt_findorcreate((const char*)propValue); + xmlFree(propValue); + + ++radd; + } +} + +void +xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, construction ** consPtr) +{ + xmlNodePtr pushNode = xpath->node; + int k; + for (k=0;k!=nodeSet->nodeNr;++k) { + xmlNodePtr node = nodeSet->nodeTab[k]; + xmlChar * propValue; + construction * con; + xmlXPathObjectPtr req; + int m; + skill_t sk = NOSKILL; + + propValue = xmlGetProp(node, BAD_CAST "skill"); + if (propValue!=NULL) { + sk = sk_find((const char*)propValue); + if (sk==NOSKILL) { + log_error(("construction requires skill '%s' that does not exist.\n", (const char *)propValue)); + xmlFree(propValue); + continue; + } + xmlFree(propValue); + } + + assert(*consPtr==NULL); + + *consPtr = con = calloc(sizeof(construction), 1); + consPtr = &con->improvement; + + con->skill = sk; + con->maxsize = xml_ivalue(node, "maxsize", -1); + con->minskill = xml_ivalue(node, "minskill", -1); + con->reqsize = xml_ivalue(node, "reqsize", -1); + + propValue = xmlGetProp(node, BAD_CAST "building"); + if (propValue!=NULL) { + con->btype = bt_get_or_create((const char*)propValue); + xmlFree(propValue); + } + + /* read construction/requirement */ + xpath->node = node; + req = xmlXPathEvalExpression(BAD_CAST "requirement", xpath); + xml_readrequirements(req->nodesetval->nodeTab, + req->nodesetval->nodeNr, &con->materials); + xmlXPathFreeObject(req); + + /* read construction/modifier */ + xpath->node = node; + req = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); + for (m=0;m!=req->nodesetval->nodeNr;++m) { + xmlNodePtr node = req->nodesetval->nodeTab[m]; + + propValue = xmlGetProp(node, BAD_CAST "function"); + if (propValue!=NULL) { + pf_generic foo = get_function((const char*)propValue); + a_add(&con->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION, (skillmod_fun)foo, 1.0, 0)); + xmlFree(propValue); + } + + } + xmlXPathFreeObject(req); + } + xpath->node = pushNode; +} + +static int +parse_function(xmlNodePtr node, pf_generic * funPtr, xmlChar ** namePtr) +{ + pf_generic fun; + xmlChar * propValue = xmlGetProp(node, BAD_CAST "value"); + assert(propValue!=NULL); + fun = get_function((const char*)propValue); + if (fun!=NULL) { + xmlFree(propValue); + + propValue = xmlGetProp(node, BAD_CAST "name"); + } + *namePtr = propValue; + *funPtr = fun; + return 0; +} + +static int +parse_buildings(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr buildings; + int i; + + /* reading eressea/buildings/building */ + buildings = xmlXPathEvalExpression(BAD_CAST "/eressea/buildings/building", xpath); + if (buildings->nodesetval!=NULL) { + xmlNodeSetPtr nodes = buildings->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + xmlChar * propValue; + building_type * btype; + xmlXPathObjectPtr result; + int k; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + btype = bt_get_or_create((const char*)propValue); + xmlFree(propValue); + + btype->capacity = xml_ivalue(node, "capacity", -1); + btype->maxcapacity = xml_ivalue(node, "maxcapacity", -1); + btype->maxsize = xml_ivalue(node, "maxsize", -1); + + btype->magres = xml_ivalue(node, "magres", 0); + btype->magresbonus = xml_ivalue(node, "magresbonus", 0); + btype->fumblebonus = xml_ivalue(node, "fumblebonus", 0); + btype->auraregen = xml_fvalue(node, "auraregen", 1.0); + + if (xml_bvalue(node, "nodestroy", false)) btype->flags |= BTF_INDESTRUCTIBLE; + if (xml_bvalue(node, "oneperturn", false)) btype->flags |= BTF_ONEPERTURN; + if (xml_bvalue(node, "nobuild", false)) btype->flags |= BTF_NOBUILD; + if (xml_bvalue(node, "namechange", true)) btype->flags |= BTF_NAMECHANGE; + if (xml_bvalue(node, "unique", false)) btype->flags |= BTF_UNIQUE; + if (xml_bvalue(node, "decay", false)) btype->flags |= BTF_DECAY; + if (xml_bvalue(node, "magic", false)) btype->flags |= BTF_MAGIC; + + /* reading eressea/buildings/building/construction */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); + xml_readconstruction(xpath, result->nodesetval, &btype->construction); + xmlXPathFreeObject(result); + + if (gamecode_enabled) { + /* reading eressea/buildings/building/function */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "function", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + pf_generic fun; + parse_function(node, &fun, &propValue); + + if (fun==NULL) { + log_error(("unknown function name '%s' for building %s\n", + (const char*)propValue, btype->_name)); + xmlFree(propValue); + continue; + } + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "name")==0) { + btype->name = (const char * (*)(const struct building_type*, const struct building *, int))fun; + } else if (strcmp((const char*)propValue, "init")==0) { + btype->init = (void (*)(struct building_type*))fun; + } else if (strcmp((const char*)propValue, "age")==0) { + btype->age = (void (*)(struct building*))fun; + } else if (strcmp((const char*)propValue, "protection")==0) { + btype->protection = (int (*)(struct building*, struct unit *))fun; + } else if (strcmp((const char*)propValue, "taxes")==0) { + btype->taxes = (double (*)(const struct building*, int))fun; + } else if (strcmp((const char*)propValue, "age")==0) { + btype->age = (void (*)(struct building*))fun; + } else { + log_error(("unknown function type '%s' for building %s\n", + (const char*)propValue, btype->_name)); + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + } + + /* reading eressea/buildings/building/maintenance */ + result = xmlXPathEvalExpression(BAD_CAST "maintenance", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + maintenance * mt; + + if (btype->maintenance==NULL) { + btype->maintenance = calloc(sizeof(struct maintenance), result->nodesetval->nodeNr+1); + } + mt = btype->maintenance + k; + mt->number = xml_ivalue(node, "amount", 0); + + propValue = xmlGetProp(node, BAD_CAST "type"); + assert(propValue!=NULL); + mt->rtype = rt_find((const char*)propValue); + assert(mt->rtype!=NULL); + xmlFree(propValue); + + if (xml_bvalue(node, "variable", false)) mt->flags |= MTF_VARIABLE; + if (xml_bvalue(node, "vital", false)) mt->flags |= MTF_VITAL; + + } + xmlXPathFreeObject(result); + + /* finally, initialize the new building type */ + if (btype->init) btype->init(btype); + } + } + xmlXPathFreeObject(buildings); + + xmlXPathFreeContext(xpath); + return 0; +} + +static int +parse_calendar(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr xpathCalendars; + xmlNodeSetPtr nsetCalendars; + int c, rv = 0; + + /* reading eressea/buildings/building */ + xpathCalendars = xmlXPathEvalExpression(BAD_CAST "/eressea/calendar", xpath); + nsetCalendars = xpathCalendars->nodesetval; + months_per_year = 0; + if (nsetCalendars==NULL || nsetCalendars->nodeNr==0) { + rv = -1; + } else for (c=0;c!=nsetCalendars->nodeNr;++c) { + xmlNodePtr calendar = nsetCalendars->nodeTab[c]; + xmlXPathObjectPtr xpathWeeks, xpathMonths, xpathSeasons; + xmlNodeSetPtr nsetWeeks, nsetMonths, nsetSeasons; + xmlChar * propValue = xmlGetProp(calendar, BAD_CAST "name"); + xmlChar * newyear = xmlGetProp(calendar, BAD_CAST "newyear"); + + first_turn = xml_ivalue(calendar, "start", first_turn); + if (propValue) { + free(agename); + agename = strdup(mkname("calendar", (const char*)propValue)); + xmlFree(propValue); + } + + xpath->node = calendar; + xpathWeeks = xmlXPathEvalExpression(BAD_CAST "week", xpath); + nsetWeeks = xpathWeeks->nodesetval; + if (nsetWeeks!=NULL && nsetWeeks->nodeNr) { + int i; + + weeks_per_month = nsetWeeks->nodeNr; + assert(!weeknames); + weeknames = malloc(sizeof(char *) * weeks_per_month); + weeknames2 = malloc(sizeof(char *) * weeks_per_month); + for (i=0;i!=nsetWeeks->nodeNr;++i) { + xmlNodePtr week = nsetWeeks->nodeTab[i]; + xmlChar * propValue = xmlGetProp(week, BAD_CAST "name"); + if (propValue) { + weeknames[i] = strdup(mkname("calendar", (const char*)propValue)); + weeknames2[i] = malloc(strlen(weeknames[i])+3); + sprintf(weeknames2[i], "%s_d", weeknames[i]); + xmlFree(propValue); + } + } + } + xmlXPathFreeObject(xpathWeeks); + + xpathSeasons = xmlXPathEvalExpression(BAD_CAST "season", xpath); + nsetSeasons = xpathSeasons->nodesetval; + if (nsetSeasons!=NULL && nsetSeasons->nodeNr) { + int i; + + seasons = nsetSeasons->nodeNr; + assert(!seasonnames); + seasonnames = malloc(sizeof(char *) * seasons); + + for (i=0;i!=nsetSeasons->nodeNr;++i) { + xmlNodePtr season = nsetSeasons->nodeTab[i]; + xmlChar * propValue = xmlGetProp(season, BAD_CAST "name"); + if (propValue) { + seasonnames[i] = strdup(mkname("calendar", (const char*)propValue)); + xmlFree(propValue); + } + } + } + + xpathMonths = xmlXPathEvalExpression(BAD_CAST "season/month", xpath); + nsetMonths = xpathMonths->nodesetval; + if (nsetMonths!=NULL && nsetMonths->nodeNr) { + int i; + + months_per_year = nsetMonths->nodeNr; + assert(!monthnames); + monthnames = malloc(sizeof(char *) * months_per_year); + month_season = malloc(sizeof(int) * months_per_year); + storms = malloc(sizeof(int) * months_per_year); + + for (i=0;i!=nsetMonths->nodeNr;++i) { + xmlNodePtr month = nsetMonths->nodeTab[i]; + xmlChar * propValue = xmlGetProp(month, BAD_CAST "name"); + int j; + + if (propValue) { + if (newyear && strcmp((const char*)newyear, (const char*)propValue)==0) { + first_month = i; + xmlFree(newyear); + newyear = NULL; + } + monthnames[i] = strdup(mkname("calendar", (const char*)propValue)); + xmlFree(propValue); + } + for (j=0;j!=seasons;++j) { + xmlNodePtr season = month->parent; + if (season==nsetSeasons->nodeTab[j]) { + month_season[i] = j; + break; + } + } + assert(j!=seasons); + storms[i] = xml_ivalue(nsetMonths->nodeTab[i], "storm", 0); + } + } + xmlXPathFreeObject(xpathMonths); + xmlXPathFreeObject(xpathSeasons); + } + xmlXPathFreeObject(xpathCalendars); + xmlXPathFreeContext(xpath); + + return rv; +} + +static int +parse_directions(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr xpathDirections; + xmlNodeSetPtr nsetDirections; + int rv = 0; + + /* reading eressea/directions/dir */ + xpathDirections = xmlXPathEvalExpression(BAD_CAST "/eressea/directions/dir", xpath); + nsetDirections = xpathDirections->nodesetval; + if (nsetDirections!=NULL) { + int k; + for (k=0;k!=nsetDirections->nodeNr;++k) { + xmlNodePtr dir = nsetDirections->nodeTab[k]; + xmlChar * propValue = xmlGetProp(dir, BAD_CAST "name"); + + register_special_direction((const char *)propValue); + xmlFree(propValue); + } + } + xmlXPathFreeObject(xpathDirections); + xmlXPathFreeContext(xpath); + + return rv; +} + +static int +parse_ships(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr ships; + int i; + + /* reading eressea/ships/ship */ + ships = xmlXPathEvalExpression(BAD_CAST "/eressea/ships/ship", xpath); + if (ships->nodesetval!=NULL) { + xmlNodeSetPtr nodes = ships->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr child, node = nodes->nodeTab[i]; + xmlChar * propValue; + ship_type * st = calloc(sizeof(ship_type), 1); + xmlXPathObjectPtr result; + int k, c; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + st->name[0] = strdup((const char *)propValue); + st->name[1] = strcat(strcpy(malloc(strlen(st->name[0])+3), st->name[0]),"_a"); + xmlFree(propValue); + + st->cabins = xml_ivalue(node, "cabins", 0) * PERSON_WEIGHT; + st->cargo = xml_ivalue(node, "cargo", 0); + st->combat = xml_ivalue(node, "combat", 0); + st->cptskill = xml_ivalue(node, "cptskill", 0); + st->damage = xml_fvalue(node, "damage", 0.0); + if (xml_bvalue(node, "nocoast", false)) st->flags |= SFL_NOCOAST; + if (xml_bvalue(node, "fly", false)) st->flags |= SFL_FLY; + if (xml_bvalue(node, "opensea", false)) st->flags |= SFL_OPENSEA; + st->fishing = xml_ivalue(node, "fishing", 0); + st->minskill = xml_ivalue(node, "minskill", 0); + st->range = xml_ivalue(node, "range", 0); + st->storm = xml_fvalue(node, "storm", 1.0); + st->sumskill = xml_ivalue(node, "sumskill", 0); + + /* reading eressea/ships/ship/construction */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); + xml_readconstruction(xpath, result->nodesetval, &st->construction); + xmlXPathFreeObject(result); + + for (child=node->children;child;child=child->next) { + if (strcmp((const char *)child->name, "modifier")==0) { + double value = xml_fvalue(child, "value", 0.0); + propValue = xmlGetProp(child, BAD_CAST "type"); + if (strcmp((const char *)propValue, "tactics")==0) st->tac_bonus = (float)value; + else if (strcmp((const char *)propValue, "attack")==0) st->at_bonus = (int)value; + else if (strcmp((const char *)propValue, "defense")==0) st->df_bonus = (int)value; + xmlFree(propValue); + } + } + /* reading eressea/ships/ship/coast */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "coast", xpath); + for (c=0,k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + + if (k==0) { + assert(st->coasts==NULL); + st->coasts = (const terrain_type**)malloc(sizeof(const terrain_type*) * (result->nodesetval->nodeNr+1)); + st->coasts[result->nodesetval->nodeNr] = NULL; + } + + propValue = xmlGetProp(node, BAD_CAST "terrain"); + assert(propValue!=NULL); + st->coasts[c] = get_terrain((const char*)propValue); + if (st->coasts[c]!=NULL) ++c; + else { + log_warning(("ship %s mentions a non-existing terrain %s.\n", st->name[0], propValue)); + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + + /* finally, register the new building type */ + st_register(st); + } + } + xmlXPathFreeObject(ships); + + xmlXPathFreeContext(xpath); + return 0; +} + +static void +race_compat(void) +{ + /* required for old_race, do not change order! */ + const char * oldracenames[MAXRACES] = { + "dwarf", "elf", NULL, "goblin", "human", "troll", "demon", "insect", + "halfling", "cat", "aquarian", "orc", "snotling", "undead", "illusion", + "youngdragon", "dragon", "wyrm", "ent", "catdragon", "dracoid", + "special", "spell", "irongolem", "stonegolem", "shadowdemon", + "shadowmaster", "mountainguard", "alp", "toad", "braineater", "peasant", + "wolf", NULL, NULL, NULL, NULL, "songdragon", NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, "seaserpent", + "shadowknight", "centaur", "skeleton", "skeletonlord", "zombie", + "juju-zombie", "ghoul", "ghast", "museumghost", "gnome", "template", + "clone" + }; + int i; + + for (i=0;i!=MAXRACES;++i) { + const char * rcname = oldracenames[i]; + if (rcname==NULL) { + new_race[i] = NULL; + } else { + race * rc = rc_find(oldracenames[i]); + if (rc) { + new_race[i] = rc; + if (rc == new_race[RC_TROLL]) { + a_add(&rc->attribs, make_skillmod(NOSKILL, SMF_RIDING, NULL, 0.0, -1)); + } + } + } + } +} + +static potion_type * +xml_readpotion(xmlXPathContextPtr xpath, item_type * itype) +{ + int level = xml_ivalue(xpath->node, "level", 0); + + assert(level>0); + return new_potiontype(itype, level); +} + +static luxury_type * +xml_readluxury(xmlXPathContextPtr xpath, item_type * itype) +{ + int price = xml_ivalue(xpath->node, "price", 0); + return new_luxurytype(itype, price); +} + + +static armor_type * +xml_readarmor(xmlXPathContextPtr xpath, item_type * itype) +{ + xmlNodePtr node = xpath->node; + armor_type * atype = NULL; + unsigned int flags = ATF_NONE; + int ac = xml_ivalue(node, "ac", 0); + double penalty = xml_fvalue(node, "penalty", 0.0); + double magres = xml_fvalue(node, "magres", 0.0); + + if (xml_bvalue(node, "laen", false)) flags |= ATF_LAEN; + if (xml_bvalue(node, "shield", false)) flags |= ATF_SHIELD; + + atype = new_armortype(itype, penalty, magres, ac, flags); + atype->projectile = (float)xml_fvalue(node, "projectile", 0.0); + return atype; +} + +static weapon_type * +xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) +{ + xmlNodePtr node = xpath->node; + weapon_type * wtype = NULL; + unsigned int flags = WTF_NONE; + xmlXPathObjectPtr result; + xmlChar * propValue; + int k; + skill_t sk; + int minskill = xml_ivalue(node, "minskill", 0); + int offmod = xml_ivalue(node, "offmod", 0); + int defmod = xml_ivalue(node, "defmod", 0); + int reload = xml_ivalue(node, "reload", 0); + double magres = xml_fvalue(node, "magres", 0.0); + + if (xml_bvalue(node, "armorpiercing", false)) flags |= WTF_ARMORPIERCING; + if (xml_bvalue(node, "magical", false)) flags |= WTF_MAGICAL; + if (xml_bvalue(node, "missile", false)) flags |= WTF_MISSILE; + if (xml_bvalue(node, "pierce", false)) flags |= WTF_PIERCE; + if (xml_bvalue(node, "cut", false)) flags |= WTF_CUT; + if (xml_bvalue(node, "blunt", false)) flags |= WTF_BLUNT; + if (xml_bvalue(node, "siege", false)) flags |= WTF_SIEGE; + if (xml_bvalue(node, "horse", (flags&WTF_MISSILE)==0)) flags |= WTF_HORSEBONUS; + if (xml_bvalue(node, "useshield", true)) flags |= WTF_USESHIELD; + + propValue = xmlGetProp(node, BAD_CAST "skill"); + assert(propValue!=NULL); + sk = sk_find((const char*)propValue); + assert(sk!=NOSKILL); + xmlFree(propValue); + + wtype = new_weapontype(itype, flags, magres, NULL, offmod, defmod, reload, sk, minskill); + + /* reading weapon/damage */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "damage", xpath); + assert(result->nodesetval->nodeNr<=2); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + int pos = 0; + + propValue = xmlGetProp(node, BAD_CAST "type"); + if (strcmp((const char *)propValue, "footman")!=0) { + pos = 1; + } + xmlFree(propValue); + + propValue = xmlGetProp(node, BAD_CAST "value"); + wtype->damage[pos] = gc_add(strdup((const char*)propValue)); + if (k==0) wtype->damage[1-pos] = wtype->damage[pos]; + xmlFree(propValue); + } + xmlXPathFreeObject(result); + + /* reading weapon/modifier */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); + assert(wtype->modifiers==NULL); + wtype->modifiers = calloc(result->nodesetval->nodeNr+1, sizeof(weapon_mod)); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + xmlXPathObjectPtr races; + int r, flags = 0; + + if (xml_bvalue(node, "walking", false)) flags|=WMF_WALKING; + if (xml_bvalue(node, "riding", false)) flags|=WMF_RIDING; + if (xml_bvalue(node, "against_walking", false)) flags|=WMF_AGAINST_WALKING; + if (xml_bvalue(node, "against_riding", false)) flags|=WMF_AGAINST_RIDING; + if (xml_bvalue(node, "offensive", false)) flags|=WMF_OFFENSIVE; + if (xml_bvalue(node, "defensive", false)) flags|=WMF_DEFENSIVE; + + propValue = xmlGetProp(node, BAD_CAST "type"); + if (strcmp((const char*)propValue, "damage")==0) flags|=WMF_DAMAGE; + else if (strcmp((const char*)propValue, "skill")==0) flags|=WMF_SKILL; + else if (strcmp((const char*)propValue, "missile_target")==0) flags|=WMF_MISSILE_TARGET; + xmlFree(propValue); + + wtype->modifiers[k].flags = flags; + wtype->modifiers[k].value = xml_ivalue(node, "value", 0); + + xpath->node = node; + races = xmlXPathEvalExpression(BAD_CAST "race", xpath); + for (r=0;r!=races->nodesetval->nodeNr;++r) { + xmlNodePtr node = races->nodesetval->nodeTab[r]; + + propValue = xmlGetProp(node, BAD_CAST "name"); + if (propValue!=NULL) { + const race * rc = rc_find((const char*)propValue); + if (rc==NULL) rc = rc_add(rc_new((const char*)propValue)); + racelist_insert(&wtype->modifiers[k].races, rc); + xmlFree(propValue); + } + } + xmlXPathFreeObject(races); + } + xmlXPathFreeObject(result); + + if (gamecode_enabled) { + /* reading weapon/function */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "function", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + xmlChar * propValue; + pf_generic fun; + + parse_function(node, &fun, &propValue); + if (fun==NULL) { + log_error(("unknown function name '%s' for item '%s'\n", + (const char*)propValue, itype->rtype->_name[0])); + xmlFree(propValue); + continue; + } + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "attack")==0) { + wtype->attack = (boolean (*)(const struct troop*, const struct weapon_type *, int*))fun; + } else { + log_error(("unknown function type '%s' for item '%s'\n", + (const char*)propValue, itype->rtype->_name[0])); + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + } + + xpath->node = node; + return wtype; +} + +static item_type * +xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) +{ + xmlNodePtr node = xpath->node; + item_type * itype = NULL; + unsigned int flags = ITF_NONE; + xmlXPathObjectPtr result; + int k; + + int weight = xml_ivalue(node, "weight", 0); + int capacity = xml_ivalue(node, "capacity", 0); + + if (xml_bvalue(node, "cursed", false)) flags |= ITF_CURSED; + if (xml_bvalue(node, "notlost", false)) flags |= ITF_NOTLOST; + if (xml_bvalue(node, "herb", false)) flags |= ITF_HERB; + if (xml_bvalue(node, "big", false)) flags |= ITF_BIG; + if (xml_bvalue(node, "animal", false)) flags |= ITF_ANIMAL; + if (xml_bvalue(node, "vehicle", false)) flags |= ITF_VEHICLE; + itype = new_itemtype(rtype, flags, weight, capacity); +#if SCORE_MODULE + itype->score = xml_ivalue(node, "score", 0); +#endif + + /* reading item/construction */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); + xml_readconstruction(xpath, result->nodesetval, &itype->construction); + xmlXPathFreeObject(result); + + /* reading item/weapon */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "weapon", xpath); + assert(result->nodesetval->nodeNr<=1); + if (result->nodesetval->nodeNr!=0) { + xpath->node = result->nodesetval->nodeTab[0]; + rtype->wtype = xml_readweapon(xpath, itype); + } + xmlXPathFreeObject(result); + + /* reading item/potion */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "potion", xpath); + assert(result->nodesetval->nodeNr<=1); + if (result->nodesetval->nodeNr!=0) { + xpath->node = result->nodesetval->nodeTab[0]; + rtype->ptype = xml_readpotion(xpath, itype); + } + xmlXPathFreeObject(result); + + /* reading item/luxury */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "luxury", xpath); + assert(result->nodesetval->nodeNr<=1); + if (result->nodesetval->nodeNr!=0) { + xpath->node = result->nodesetval->nodeTab[0]; + rtype->ltype = xml_readluxury(xpath, itype); + } + xmlXPathFreeObject(result); + + /* reading item/armor */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "armor", xpath); + assert(result->nodesetval->nodeNr<=1); + if (result->nodesetval->nodeNr!=0) { + xpath->node = result->nodesetval->nodeTab[0]; + rtype->atype = xml_readarmor(xpath, itype); + } + xmlXPathFreeObject(result); + + if (gamecode_enabled) { + /* reading item/function */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "function", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + xmlChar * propValue; + pf_generic fun; + + parse_function(node, &fun, &propValue); + if (fun==NULL) { + log_error(("unknown function name '%s' for item '%s'\n", + (const char*)propValue, rtype->_name[0])); + xmlFree(propValue); + continue; + } + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "give")==0) { + itype->give = (int (*)(struct unit*, struct unit*, const struct item_type *, int, struct order *))fun; + } else if (strcmp((const char*)propValue, "use")==0) { + itype->use = (int (*)(struct unit *, const struct item_type *, int, struct order *))fun; + } else if (strcmp((const char*)propValue, "canuse")==0) { + itype->canuse = (boolean (*)(const struct unit *, const struct item_type *))fun; + } else if (strcmp((const char*)propValue, "useonother")==0) { + itype->useonother = (int (*)(struct unit *, int, const struct item_type *, int, struct order *))fun; + } else { + log_error(("unknown function type '%s' for item '%s'\n", + (const char*)propValue, rtype->_name[0])); + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + } + + return itype; +} + +static int +parse_rules(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr functions; + xmlNodeSetPtr nodes; + int i; + + /* reading eressea/resources/resource */ + functions = xmlXPathEvalExpression(BAD_CAST "/eressea/rules/function", xpath); + nodes = functions->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + xmlChar *propValue; + pf_generic fun; + + parse_function(node, &fun, &propValue); + + if (fun==NULL) { + log_error(("unknown function for rule '%s' %s\n", (const char*)propValue)); + xmlFree(propValue); + continue; + } + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "wage")==0) { + global.functions.wage = (int (*)(const struct region*, const struct faction*, const struct race*, int))fun; + } else if (strcmp((const char*)propValue, "maintenance")==0) { + global.functions.maintenance = (int (*)(const struct unit*))fun; + } else { + log_error(("unknown function for rule '%s'\n", + (const char*)propValue)); + } + xmlFree(propValue); + } + xmlXPathFreeObject(functions); + xmlXPathFreeContext(xpath); + return 0; +} + +static int +parse_resources(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr resources; + xmlNodeSetPtr nodes; + int i; + + /* reading eressea/resources/resource */ + resources = xmlXPathEvalExpression(BAD_CAST "/eressea/resources/resource", xpath); + nodes = resources->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + xmlChar *propValue, *name, *appearance; + const char *names[2], *appearances[2]; + char * namep = NULL, * appearancep = NULL; + resource_type * rtype; + unsigned int flags = RTF_NONE; + xmlXPathObjectPtr result; + int k; + + if (xml_bvalue(node, "pooled", true)) flags |= RTF_POOLED; + if (xml_bvalue(node, "limited", false)) flags |= RTF_LIMITED; + + name = xmlGetProp(node, BAD_CAST "name"); + appearance = xmlGetProp(node, BAD_CAST "appearance"); + assert(name!=NULL); + + if (appearance!=NULL) { + appearancep = strcat(strcpy((char*)malloc(strlen((char*)appearance)+3), (char*)appearance), "_p"); + } + + rtype = rt_find((const char *)name); + if (rtype!=NULL) { + /* dependency from another item, was created earlier */ + rtype->flags |= flags; + if (appearance) { + rtype->_appearance[0] = strdup((const char*)appearance); + rtype->_appearance[1] = appearancep; + free(appearancep); + } + } else { + namep = strcat(strcpy((char*)malloc(strlen((char*)name)+3), (char*)name), "_p"); + names[0] = (const char*)name; + names[1] = namep; + if (appearance) { + appearances[0] = (const char*)appearance; + appearances[1] = appearancep; + rtype = new_resourcetype((const char**)names, (const char**)appearances, flags); + free(appearancep); + } else { + rtype = new_resourcetype(names, NULL, flags); + } + free(namep); + } + + if (name) xmlFree(name); + if (appearance) xmlFree(appearance); + + name = xmlGetProp(node, BAD_CAST "material"); + if (name) { + rmt_create(rtype, (const char *)name); + xmlFree(name); + } + + + if (gamecode_enabled) { + /* reading eressea/resources/resource/function */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "function", xpath); + if (result->nodesetval!=NULL) for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + pf_generic fun; + + parse_function(node, &fun, &propValue); + if (fun==NULL) { + log_error(("unknown function name '%s' for resource %s\n", + (const char*)propValue, rtype->_name[0])); + xmlFree(propValue); + continue; + } + + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "change")==0) { + rtype->uchange = (rtype_uchange)fun; + } else if (strcmp((const char*)propValue, "get")==0) { + rtype->uget = (rtype_uget)fun; + } else if (strcmp((const char*)propValue, "name")==0) { + rtype->name = (rtype_name)fun; + } else { + log_error(("unknown function type '%s' for resource %s\n", + (const char*)propValue, rtype->_name[0])); + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + } + + /* reading eressea/resources/resource/resourcelimit */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "resourcelimit", xpath); + assert(result->nodesetval->nodeNr<=1); + if (result->nodesetval->nodeNr!=0) { + resource_limit * rdata; + attrib * a = a_find(rtype->attribs, &at_resourcelimit); + xmlNodePtr limit = result->nodesetval->nodeTab[0]; + + if (a==NULL) a = a_add(&rtype->attribs, a_new(&at_resourcelimit)); + rdata = (resource_limit*)a->data.v; + rtype->flags |= RTF_LIMITED; + xpath->node = limit; + xmlXPathFreeObject(result); + + result = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); + if (result->nodesetval!=NULL) { + rdata->modifiers = calloc(result->nodesetval->nodeNr+1, sizeof(resource_mod)); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + building_type * btype = NULL; + const race * rc = NULL; + + propValue = xmlGetProp(node, BAD_CAST "race"); + if (propValue!=NULL) { + rc = rc_find((const char*)propValue); + if (rc==NULL) rc = rc_add(rc_new((const char*)propValue)); + xmlFree(propValue); + } + rdata->modifiers[k].race = rc; + + propValue = xmlGetProp(node, BAD_CAST "building"); + if (propValue!=NULL) { + btype = bt_get_or_create((const char*)propValue); + xmlFree(propValue); + } + rdata->modifiers[k].btype = btype; + + propValue = xmlGetProp(node, BAD_CAST "type"); + assert(propValue!=NULL); + if (strcmp((const char *)propValue, "skill")==0) { + rdata->modifiers[k].value.i = xml_ivalue(node, "value", 0); + rdata->modifiers[k].flags = RMF_SKILL; + } else if (strcmp((const char *)propValue, "material")==0) { + rdata->modifiers[k].value.f = (float)xml_fvalue(node, "value", 0); + rdata->modifiers[k].flags = RMF_SAVEMATERIAL; + } else if (strcmp((const char *)propValue, "resource")==0) { + rdata->modifiers[k].value.f = (float)xml_fvalue(node, "value", 0); + rdata->modifiers[k].flags = RMF_SAVERESOURCE; + } else if (strcmp((const char *)propValue, "require")==0) { + xmlChar * propBldg = xmlGetProp(node, BAD_CAST "building"); + if (propBldg!=NULL) { + btype = bt_get_or_create((const char*)propBldg); + rdata->modifiers[k].btype = btype; + rdata->modifiers[k].flags = RMF_REQUIREDBUILDING; + xmlFree(propBldg); + } + } else { + log_error(("unknown type '%s' for resourcelimit-modifier '%s'\n", + (const char*)propValue, rtype->_name[0])); + } + xmlFree(propValue); + } + } + xmlXPathFreeObject(result); + + result = xmlXPathEvalExpression(BAD_CAST "guard", xpath); + if (result->nodesetval!=NULL) for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + xmlChar * propFlag = xmlGetProp(node, BAD_CAST "flag"); + + if (propFlag!=NULL) { + if (strcmp((const char *)propFlag, "logging")==0) { + rdata->guard |= GUARD_TREES; + } else if (strcmp((const char *)propFlag, "mining")==0) { + rdata->guard |= GUARD_MINING; + } + xmlFree(propFlag); + } + } + xmlXPathFreeObject(result); + + /* reading eressea/resources/resource/resourcelimit/function */ + result = xmlXPathEvalExpression(BAD_CAST "function", xpath); + if (result->nodesetval!=NULL) for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + pf_generic fun; + + propValue = xmlGetProp(node, BAD_CAST "value"); + assert(propValue!=NULL); + fun = get_function((const char*)propValue); + if (fun==NULL) { + log_error(("unknown limit '%s' for resource %s\n", + (const char*)propValue, rtype->_name[0])); + xmlFree(propValue); + continue; + } + xmlFree(propValue); + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "produce")==0) { + rdata->produce = (rlimit_produce)fun; + } else if (strcmp((const char*)propValue, "limit")==0) { + rdata->limit = (rlimit_limit)fun; + } else { + log_error(("unknown limit '%s' for resource %s\n", + (const char*)propValue, rtype->_name[0])); + } + xmlFree(propValue); + } + } + xmlXPathFreeObject(result); + + /* reading eressea/resources/resource/resourcelimit/function */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "resourcelimit/function", xpath); + xmlXPathFreeObject(result); + + /* reading eressea/resources/resource/item */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "item", xpath); + assert(result->nodesetval->nodeNr<=1); + if (result->nodesetval->nodeNr!=0) { + rtype->flags |= RTF_ITEM; + xpath->node = result->nodesetval->nodeTab[0]; + rtype->itype = xml_readitem(xpath, rtype); + } + xmlXPathFreeObject(result); + } + xmlXPathFreeObject(resources); + + xmlXPathFreeContext(xpath); + + /* make sure old items (used in requirements) are available */ + init_resources(); + init_itemtypes(); + + return 0; +} + +static void +add_items(equipment * eq, xmlNodeSetPtr nsetItems) +{ + if (nsetItems!=NULL && nsetItems->nodeNr>0) { + int i; + for (i=0;i!=nsetItems->nodeNr;++i) { + xmlNodePtr node = nsetItems->nodeTab[i]; + xmlChar * propValue; + const struct item_type * itype; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + itype = it_find((const char*)propValue); + xmlFree(propValue); + if (itype!=NULL) { + propValue = xmlGetProp(node, BAD_CAST "amount"); + if (propValue!=NULL) { + equipment_setitem(eq, itype, (const char*)propValue); + xmlFree(propValue); + } + } + } + } +} + +static void +add_callbacks(equipment * eq, xmlNodeSetPtr nsetItems) +{ + if (nsetItems!=NULL && nsetItems->nodeNr>0) { + int i; + for (i=0;i!=nsetItems->nodeNr;++i) { + xmlNodePtr node = nsetItems->nodeTab[i]; + xmlChar * propValue; + pf_generic fun; + + propValue = xmlGetProp(node, BAD_CAST "name"); + if (propValue!=NULL) { + fun = get_function((const char*)propValue); + if (fun) { + equipment_setcallback(eq, (void (*)(const struct equipment *, struct unit *))fun); + } + xmlFree(propValue); + } + } + } +} + +static void +add_spells(equipment * eq, xmlNodeSetPtr nsetItems) +{ + if (nsetItems!=NULL && nsetItems->nodeNr>0) { + int i; + for (i=0;i!=nsetItems->nodeNr;++i) { + xmlNodePtr node = nsetItems->nodeTab[i]; + xmlChar * propValue; + magic_t mtype = M_NONE; + struct spell * sp; + + propValue = xmlGetProp(node, BAD_CAST "school"); + if (propValue!=NULL) { + for (mtype=0;mtype!=MAXMAGIETYP;++mtype) { + if (strcmp((const char*)propValue, magic_school[mtype])==0) break; + } + assert(mtype!=MAXMAGIETYP); + xmlFree(propValue); + } + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + sp = find_spell(mtype, (const char*)propValue); + assert(sp); + xmlFree(propValue); + if (sp!=NULL) { + equipment_addspell(eq, sp); + } + } + } +} + +static void +add_skills(equipment * eq, xmlNodeSetPtr nsetSkills) +{ + if (nsetSkills!=NULL && nsetSkills->nodeNr>0) { + int i; + for (i=0;i!=nsetSkills->nodeNr;++i) { + xmlNodePtr node = nsetSkills->nodeTab[i]; + xmlChar * propValue; + skill_t sk; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + sk = sk_find((const char*)propValue); + xmlFree(propValue); + if (sk!=NOSKILL) { + propValue = xmlGetProp(node, BAD_CAST "level"); + if (propValue!=NULL) { + equipment_setskill(eq, sk, (const char*)propValue); + xmlFree(propValue); + } + } + } + } +} + +static void +add_subsets(xmlDocPtr doc, equipment * eq, xmlNodeSetPtr nsetSubsets) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + if (nsetSubsets!=NULL && nsetSubsets->nodeNr>0) { + int i; + + eq->subsets = calloc(nsetSubsets->nodeNr+1, sizeof(subset)); + for (i=0;i!=nsetSubsets->nodeNr;++i) { + xmlXPathObjectPtr xpathResult; + xmlNodePtr node = nsetSubsets->nodeTab[i]; + xmlChar * propValue; + + eq->subsets[i].chance = 1.0f; + propValue = xmlGetProp(node, BAD_CAST "chance"); + if (propValue!=NULL) { + eq->subsets[i].chance = (float)atof((const char *)propValue); + xmlFree(propValue); + } + xpath->node = node; + xpathResult = xmlXPathEvalExpression(BAD_CAST "set", xpath); + if (xpathResult->nodesetval) { + xmlNodeSetPtr nsetSets = xpathResult->nodesetval; + float totalChance = 0.0f; + + if (nsetSets->nodeNr>0) { + int set; + eq->subsets[i].sets = calloc(nsetSets->nodeNr+1, sizeof(subsetitem)); + for (set=0;set!=nsetSets->nodeNr;++set) { + xmlNodePtr nodeSet = nsetSets->nodeTab[set]; + float chance = 1.0f; + + propValue = xmlGetProp(nodeSet, BAD_CAST "chance"); + if (propValue!=NULL) { + chance = (float)atof((const char *)propValue); + xmlFree(propValue); + } + totalChance += chance; + + propValue = xmlGetProp(nodeSet, BAD_CAST "name"); + assert(propValue!=NULL); + eq->subsets[i].sets[set].chance = chance; + eq->subsets[i].sets[set].set = create_equipment((const char*)propValue); + xmlFree(propValue); + } + } + if (totalChance>1.0f) { + log_error(("total chance exceeds 1.0: %f in equipment set %s.\n", + totalChance, eq->name)); + } + } + xmlXPathFreeObject(xpathResult); + } + } + xmlXPathFreeContext(xpath); +} + +static int +parse_equipment(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr xpathRaces; + + /* reading eressea/equipment/set */ + xpathRaces = xmlXPathEvalExpression(BAD_CAST "/eressea/equipment/set", xpath); + if (xpathRaces->nodesetval) { + xmlNodeSetPtr nsetRaces = xpathRaces->nodesetval; + int i; + + for (i=0;i!=nsetRaces->nodeNr;++i) { + xmlNodePtr node = nsetRaces->nodeTab[i]; + xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); + + if (propName!=NULL) { + equipment * eq = create_equipment((const char*)propName); + xmlXPathObjectPtr xpathResult; + + xpath->node = node; + + xpathResult = xmlXPathEvalExpression(BAD_CAST "callback", xpath); + assert(!eq->callback); + add_callbacks(eq, xpathResult->nodesetval); + xmlXPathFreeObject(xpathResult); + + xpathResult = xmlXPathEvalExpression(BAD_CAST "item", xpath); + assert(!eq->items); + add_items(eq, xpathResult->nodesetval); + xmlXPathFreeObject(xpathResult); + + xpathResult = xmlXPathEvalExpression(BAD_CAST "spell", xpath); + assert(!eq->spells); + add_spells(eq, xpathResult->nodesetval); + xmlXPathFreeObject(xpathResult); + + xpathResult = xmlXPathEvalExpression(BAD_CAST "skill", xpath); + add_skills(eq, xpathResult->nodesetval); + xmlXPathFreeObject(xpathResult); + + xpathResult = xmlXPathEvalExpression(BAD_CAST "subset", xpath); + assert(!eq->subsets); + add_subsets(doc, eq, xpathResult->nodesetval); + xmlXPathFreeObject(xpathResult); + + xmlFree(propName); + } + } + } + + xmlXPathFreeObject(xpathRaces); + xmlXPathFreeContext(xpath); + + return 0; +} + +static int +parse_spells(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr spells; + + /* reading eressea/spells/spell */ + spells = xmlXPathEvalExpression(BAD_CAST "/eressea/spells/spell", xpath); + if (spells->nodesetval!=NULL) { + xmlNodeSetPtr nodes = spells->nodesetval; + int i; + + for (i=0;i!=nodes->nodeNr;++i) { + xmlXPathObjectPtr result; + xmlNodePtr node = nodes->nodeTab[i]; + xmlChar * propValue; + int k; + spell * sp = calloc(1, sizeof(spell)); + static int modes[] = { 0, PRECOMBATSPELL, COMBATSPELL, POSTCOMBATSPELL }; + + /* spellname */ + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + sp->sname = strdup((const char*)propValue); + xmlFree(propValue); + + propValue = xmlGetProp(node, BAD_CAST "parameters"); + if (propValue) { + sp->parameter=strdup((const char *)propValue); + xmlFree(propValue); + } + + propValue = xmlGetProp(node, BAD_CAST "syntax"); + if (propValue) { + sp->syntax=strdup((const char *)propValue); + xmlFree(propValue); + } + + /* magic type */ + propValue = xmlGetProp(node, BAD_CAST "type"); + assert(propValue!=NULL); + for (sp->magietyp=0;sp->magietyp!=MAXMAGIETYP;++sp->magietyp) { + if (strcmp(magic_school[sp->magietyp], (const char *)propValue)==0) break; + } + assert(sp->magietyp!=MAXMAGIETYP); + xmlFree(propValue); + + /* level, rank and flags */ + sp->id = xml_ivalue(node, "index", 0); + sp->level = xml_ivalue(node, "level", -1); + sp->rank = (char)xml_ivalue(node, "rank", -1); + if (xml_bvalue(node, "los", false)) sp->sptyp |= TESTCANSEE; /* must see or have contact */ + if (!xml_bvalue(node, "target_global", false)) sp->sptyp |= SEARCHLOCAL; /* must be in same region */ + if (xml_bvalue(node, "ship", false)) sp->sptyp |= ONSHIPCAST; + if (xml_bvalue(node, "ocean", false)) sp->sptyp |= OCEANCASTABLE; + if (xml_bvalue(node, "far", false)) sp->sptyp |= FARCASTING; + if (xml_bvalue(node, "variable", false)) sp->sptyp |= SPELLLEVEL; + k = xml_ivalue(node, "combat", 0); + if (k>=0 && k<=3) sp->sptyp |= modes[k]; + + if (gamecode_enabled) { + /* reading eressea/spells/spell/function */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "function", xpath); + + if (result->nodesetval->nodeNr==0) { + /* deprecated style: this spell gets its' function from a callback */ + if (set_spelldata_cb) set_spelldata_cb(sp); + } else { + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + pf_generic fun; + + parse_function(node, &fun, &propValue); + if (fun==NULL) { + log_error(("unknown function name '%s' for spell '%s'\n", + (const char*)propValue, sp->sname)); + xmlFree(propValue); + continue; + } + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "cast")==0) { + sp->sp_function = (spell_f)fun; + } else if (strcmp((const char*)propValue, "fumble")==0) { + sp->patzer = (pspell_f)fun; + } else { + log_error(("unknown function type '%s' for spell %s\n", + (const char*)propValue, sp->sname)); + } + xmlFree(propValue); + } + } + xmlXPathFreeObject(result); + } + + /* reading eressea/spells/spell/resource */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "resource", xpath); + if (result->nodesetval->nodeNr) { + sp->components = malloc(sizeof(spell_component)*(result->nodesetval->nodeNr+1)); + sp->components[result->nodesetval->nodeNr].type = 0; + } + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue); + sp->components[k].type = rt_find((const char *)propValue); + assert(sp->components[k].type); + xmlFree(propValue); + sp->components[k].amount = xml_ivalue(node, "amount", 1); + sp->components[k].cost = SPC_FIX; + propValue = xmlGetProp(node, BAD_CAST "cost"); + if (propValue!=NULL) { + if (strcmp((const char *)propValue, "linear")==0) { + sp->components[k].cost = SPC_LINEAR; + } else if (strcmp((const char *)propValue, "level")==0) { + sp->components[k].cost = SPC_LEVEL; + } + xmlFree(propValue); + } + } + xmlXPathFreeObject(result); + register_spell(sp); + } + } + + xmlXPathFreeObject(spells); + + xmlXPathFreeContext(xpath); + + return 0; +} + +static void +parse_param(struct param ** params, xmlNodePtr node) +{ + xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); + xmlChar * propValue = xmlGetProp(node, BAD_CAST "value"); + + set_param(params, (const char*)propName, (const char*)propValue); + + xmlFree(propName); + xmlFree(propValue); +} + +static void +parse_ai(race * rc, xmlNodePtr node) +{ + rc->splitsize = xml_ivalue(node, "splitsize", 0); + rc->aggression = (float)xml_fvalue(node, "aggression", 0.04); + if (xml_bvalue(node, "killpeasants", false)) rc->flags |= RCF_KILLPEASANTS; + if (xml_bvalue(node, "moverandom", false)) rc->flags |= RCF_MOVERANDOM; + if (xml_bvalue(node, "learn", false)) rc->flags |= RCF_LEARN; +} + +static int +parse_races(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr races; + xmlNodeSetPtr nodes; + int i; + + /* reading eressea/races/race */ + races = xmlXPathEvalExpression(BAD_CAST "/eressea/races/race", xpath); + nodes = races->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + xmlNodePtr child; + xmlChar * propValue; + race * rc; + xmlXPathObjectPtr result; + int k, study_speed_base; + struct att * attack; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + rc = rc_find((const char*)propValue); + if (rc==NULL) rc = rc_add(rc_new((const char*)propValue)); + xmlFree(propValue); + + propValue = xmlGetProp(node, BAD_CAST "damage"); + assert(propValue!=NULL); + rc->def_damage = strdup((const char*)propValue); + xmlFree(propValue); + + rc->magres = (float)xml_fvalue(node, "magres", 0.0); + rc->maxaura = (float)xml_fvalue(node, "maxaura", 0.0); + rc->regaura = (float)xml_fvalue(node, "regaura", 1.0); + rc->recruitcost = xml_ivalue(node, "recruitcost", 0); + rc->maintenance = xml_ivalue(node, "maintenance", 0); + rc->weight = xml_ivalue(node, "weight", PERSON_WEIGHT); + rc->capacity = xml_ivalue(node, "capacity", 540); + rc->speed = (float)xml_fvalue(node, "speed", 1.0F); + rc->hitpoints = xml_ivalue(node, "hp", 0); + rc->armor = (char)xml_ivalue(node, "ac", 0); + study_speed_base = xml_ivalue(node, "studyspeed", 0); + + rc->at_default = (char)xml_ivalue(node, "unarmedattack", -2); + rc->df_default = (char)xml_ivalue(node, "unarmeddefense", -2); + rc->at_bonus = (char)xml_ivalue(node, "attackmodifier", 0); + rc->df_bonus = (char)xml_ivalue(node, "defensemodifier", 0); + + if (xml_bvalue(node, "playerrace", false)) rc->flags |= RCF_PLAYERRACE; + if (xml_bvalue(node, "scarepeasants", false)) rc->flags |= RCF_SCAREPEASANTS; + if (xml_bvalue(node, "cansteal", true)) rc->flags |= RCF_CANSTEAL; + if (xml_bvalue(node, "cansail", true)) rc->flags |= RCF_CANSAIL; + if (xml_bvalue(node, "cannotmove", false)) rc->flags |= RCF_CANNOTMOVE; + if (xml_bvalue(node, "fly", false)) rc->flags |= RCF_FLY; + if (xml_bvalue(node, "invisible", false)) rc->flags |= RCF_INVISIBLE; + if (xml_bvalue(node, "coastal", false)) rc->flags |= RCF_COASTAL; + if (xml_bvalue(node, "unarmedguard", false)) rc->flags |= RCF_UNARMEDGUARD; + if (xml_bvalue(node, "swim", false)) rc->flags |= RCF_SWIM; + if (xml_bvalue(node, "walk", false)) rc->flags |= RCF_WALK; + if (!xml_bvalue(node, "canlearn", true)) rc->flags |= RCF_NOLEARN; + if (!xml_bvalue(node, "canteach", true)) rc->flags |= RCF_NOTEACH; + if (xml_bvalue(node, "horse", false)) rc->flags |= RCF_HORSE; + if (xml_bvalue(node, "desert", false)) rc->flags |= RCF_DESERT; + if (xml_bvalue(node, "absorbpeasants", false)) rc->flags |= RCF_ABSORBPEASANTS; + if (xml_bvalue(node, "noheal", false)) rc->flags |= RCF_NOHEAL; + if (xml_bvalue(node, "noweapons", false)) rc->flags |= RCF_NOWEAPONS; + if (xml_bvalue(node, "shapeshift", false)) rc->flags |= RCF_SHAPESHIFT; + if (xml_bvalue(node, "shapeshiftany", false)) rc->flags |= RCF_SHAPESHIFTANY; + if (xml_bvalue(node, "illusionary", false)) rc->flags |= RCF_ILLUSIONARY; + if (xml_bvalue(node, "undead", false)) rc->flags |= RCF_UNDEAD; + if (xml_bvalue(node, "dragon", false)) rc->flags |= RCF_DRAGON; + if (xml_bvalue(node, "shipspeed", false)) rc->flags |= RCF_SHIPSPEED; + if (xml_bvalue(node, "stonegolem", false)) rc->flags |= RCF_STONEGOLEM; + if (xml_bvalue(node, "irongolem", false)) rc->flags |= RCF_IRONGOLEM; + + if (xml_bvalue(node, "giveitem", false)) rc->ec_flags |= GIVEITEM; + if (xml_bvalue(node, "giveperson", false)) rc->ec_flags |= GIVEPERSON; + if (xml_bvalue(node, "giveunit", false)) rc->ec_flags |= GIVEUNIT; + if (xml_bvalue(node, "getitem", false)) rc->ec_flags |= GETITEM; + if (xml_bvalue(node, "recruithorses", false)) rc->ec_flags |= ECF_REC_HORSES; + if (xml_bvalue(node, "recruitethereal", false)) rc->ec_flags |= ECF_REC_ETHEREAL; + if (xml_bvalue(node, "recruitunlimited", false)) rc->ec_flags |= ECF_REC_UNLIMITED; + + if (xml_bvalue(node, "equipment", false)) rc->battle_flags |= BF_EQUIPMENT; + if (xml_bvalue(node, "noblock", false)) rc->battle_flags |= BF_NOBLOCK; + if (xml_bvalue(node, "invinciblenonmagic", false)) rc->battle_flags |= BF_INV_NONMAGIC; + if (xml_bvalue(node, "resistbash", false)) rc->battle_flags |= BF_RES_BASH; + if (xml_bvalue(node, "resistcut", false)) rc->battle_flags |= BF_RES_CUT; + if (xml_bvalue(node, "resistpierce", false)) rc->battle_flags |= BF_RES_PIERCE; + if (xml_bvalue(node, "canattack", true)) rc->battle_flags |= BF_CANATTACK; + + for (child=node->children;child;child=child->next) { + if (strcmp((const char *)child->name, "ai")==0) { + parse_ai(rc, child); + } else if (strcmp((const char *)child->name, "param")==0) { + parse_param(&rc->parameters, child); + } + } + rc->recruit_multi = get_param_flt(rc->parameters, "recruit_multi", 1.0); + + /* reading eressea/races/race/skill */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "skill", xpath); + memset(rc->bonus, 0, sizeof(rc->bonus)); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + int mod = xml_ivalue(node, "modifier", 0); + int speed = xml_ivalue(node, "speed", study_speed_base); + skill_t sk; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + sk = sk_find((const char*)propValue); + if (sk!=NOSKILL) { + rc->bonus[sk] = (char)mod; + if (speed) { + if (!rc->study_speed) rc->study_speed = calloc(1, MAXSKILLS); + rc->study_speed[sk] = (char)speed; + } + } else { + log_error(("unknown skill '%s' in race '%s'\n", + (const char*)propValue, rc->_name[0])); + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + + if (gamecode_enabled) { + /* reading eressea/races/race/function */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "function", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + pf_generic fun; + + parse_function(node, &fun, &propValue); + if (fun==NULL) { + log_error(("unknown function name '%s' for race %s\n", + (const char*)propValue, rc->_name[0])); + xmlFree(propValue); + continue; + } + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "name")==0) { + rc->generate_name = (const char * (*)(const struct unit*))fun; + } else if (strcmp((const char*)propValue, "describe")==0) { + rc->describe = (const char * (*)(const struct unit*, const struct locale *))fun; + } else if (strcmp((const char*)propValue, "age")==0) { + rc->age = (void(*)(struct unit*))fun; + } else if (strcmp((const char*)propValue, "move")==0) { + rc->move_allowed = (boolean(*)(const struct region *, const struct region *))fun; + } else if (strcmp((const char*)propValue, "itemdrop")==0) { + rc->itemdrop = (struct item *(*)(const struct race *, int))fun; + } else if (strcmp((const char*)propValue, "initfamiliar")==0) { + rc->init_familiar = (void(*)(struct unit *))fun; + } else { + log_error(("unknown function type '%s' for race %s\n", + (const char*)propValue, rc->_name[0])); + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + } + + /* reading eressea/races/race/familiar */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "familiar", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + race * frc; + + propValue = xmlGetProp(node, BAD_CAST "race"); + assert(propValue!=NULL); + frc = rc_find((const char *)propValue); + if (frc == NULL) { +// log_error(("%s not registered, is familiar for %s\n", +// (const char*)propValue, rc->_name[0])); +// assert(frc!=NULL); + frc = rc_add(rc_new((const char*)propValue)); + } + if (xml_bvalue(node, "default", false)) { + rc->familiars[k] = rc->familiars[0]; + rc->familiars[0] = frc; + } else { + rc->familiars[k] = frc; + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + + /* reading eressea/races/race/precombatspell */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "precombatspell", xpath); + assert(rc->precombatspell==NULL || !"precombatspell is already initialized"); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + rc->precombatspell = xml_spell(node, "spell"); + } + xmlXPathFreeObject(result); + + /* reading eressea/races/race/attack */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "attack", xpath); + attack = rc->attack; + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + while (attack->type!=AT_NONE) ++attack; + + propValue = xmlGetProp(node, BAD_CAST "damage"); + if (propValue!=NULL) { + attack->data.dice = strdup((const char*)propValue); + xmlFree(propValue); + } else { + attack->data.sp = xml_spell(node, "spell"); + } + attack->type = xml_ivalue(node, "type", 0); + attack->flags = xml_ivalue(node, "flags", 0); + } + xmlXPathFreeObject(result); + } + xmlXPathFreeObject(races); + + xmlXPathFreeContext(xpath); + + race_compat(); + return 0; +} + +static int +parse_terrains(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath; + xmlXPathObjectPtr terrains; + xmlNodeSetPtr nodes; + int i; + + xpath = xmlXPathNewContext(doc); + + /* reading eressea/terrains/terrain */ + terrains = xmlXPathEvalExpression(BAD_CAST "/eressea/terrains/terrain", xpath); + nodes = terrains->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + terrain_type * terrain = calloc(1, sizeof(terrain_type)); + xmlChar * propValue; + xmlXPathObjectPtr xpathChildren; + xmlNodeSetPtr children; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + terrain->_name = strdup((const char *)propValue); + xmlFree(propValue); + + terrain->max_road = (short)xml_ivalue(node, "road", 0); + assert(terrain->max_road>=0); + terrain->size = xml_ivalue(node, "size", 0); + + if (xml_bvalue(node, "forbidden", false)) terrain->flags |= FORBIDDEN_REGION; + else { + if (xml_bvalue(node, "fly", true)) terrain->flags |= FLY_INTO; + if (xml_bvalue(node, "sail", true)) terrain->flags |= SAIL_INTO; + if (xml_bvalue(node, "walk", true)) terrain->flags |= WALK_INTO; + if (xml_bvalue(node, "swim", false)) terrain->flags |= SWIM_INTO; + if (xml_bvalue(node, "shallow", true)) terrain->flags |= LARGE_SHIPS; + if (xml_bvalue(node, "cavalry", false)) terrain->flags |= CAVALRY_REGION; + } + if (xml_bvalue(node, "sea", false)) terrain->flags |= SEA_REGION; + if (xml_bvalue(node, "arctic", false)) terrain->flags |= ARCTIC_REGION; + if (xml_bvalue(node, "land", true)) terrain->flags |= LAND_REGION; + if (xml_bvalue(node, "forest", false)) terrain->flags |= FOREST_REGION; + + terrain->distribution = (short)xml_ivalue(node, "seed", 0); + + xpath->node = node; + xpathChildren = xmlXPathEvalExpression(BAD_CAST "herb", xpath); + children = xpathChildren->nodesetval; + if (children->nodeNr>0) { + int k; + + terrain->herbs = malloc((children->nodeNr+1) * sizeof(item_type*)); + terrain->herbs[children->nodeNr] = NULL; + for (k=0;k!=children->nodeNr;++k) { + xmlNodePtr nodeHerb = children->nodeTab[k]; + const struct resource_type * rtype; + + propValue = xmlGetProp(nodeHerb, BAD_CAST "name"); + assert(propValue!=NULL); + rtype = rt_find((const char*)propValue); + assert(rtype!=NULL && rtype->itype!=NULL && fval(rtype->itype, ITF_HERB)); + terrain->herbs[k] = rtype->itype; + xmlFree(propValue); + } + } + xmlXPathFreeObject(xpathChildren); + + xpath->node = node; + xpathChildren = xmlXPathEvalExpression(BAD_CAST "resource", xpath); + children = xpathChildren->nodesetval; + if (children->nodeNr>0) { + int k; + + terrain->production = malloc((children->nodeNr+1) * sizeof(terrain_production)); + terrain->production[children->nodeNr].type = NULL; + for (k=0;k!=children->nodeNr;++k) { + xmlNodePtr nodeProd = children->nodeTab[k]; + + propValue = xmlGetProp(nodeProd, BAD_CAST "name"); + assert(propValue!=NULL); + terrain->production[k].type = rt_find((const char*)propValue); + assert(terrain->production[k].type); + xmlFree(propValue); + + propValue = xmlGetProp(nodeProd, BAD_CAST "level"); + assert(propValue); + terrain->production[k].startlevel = strdup((const char *)propValue); + xmlFree(propValue); + + propValue = xmlGetProp(nodeProd, BAD_CAST "base"); + assert(propValue); + terrain->production[k].base = strdup((const char *)propValue); + xmlFree(propValue); + + propValue = xmlGetProp(nodeProd, BAD_CAST "div"); + assert(propValue); + terrain->production[k].divisor = strdup((const char *)propValue); + xmlFree(propValue); + + terrain->production[k].chance = (float)xml_fvalue(nodeProd, "chance", 1.0); + } + } + xmlXPathFreeObject(xpathChildren); + + register_terrain(terrain); + } + xmlXPathFreeObject(terrains); + + xmlXPathFreeContext(xpath); + + init_terrains(); + return 0; +} + +static int +parse_messages(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath; + xmlXPathObjectPtr messages; + xmlNodeSetPtr nodes; + int i; + + if (!gamecode_enabled) return 0; + + xpath = xmlXPathNewContext(doc); + + /* reading eressea/messages/message */ + messages = xmlXPathEvalExpression(BAD_CAST "/eressea/messages/message", xpath); + nodes = messages->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + const char * default_section = "events"; + xmlChar * propSection; + xmlChar * propValue; + xmlXPathObjectPtr result; + int k; + char ** argv = NULL; + const message_type * mtype; + + /* arguments */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "type/arg", xpath); + if (result->nodesetval && result->nodesetval->nodeNr>0) { + argv = malloc(sizeof(char*)*(result->nodesetval->nodeNr+1)); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + char zBuffer[128]; + xmlChar * propName, * propType; + + propName = xmlGetProp(node, BAD_CAST "name"); + propType = xmlGetProp(node, BAD_CAST "type"); + sprintf(zBuffer, "%s:%s", (const char*)propName, (const char*)propType); + xmlFree(propName); + xmlFree(propType); + argv[k] = strdup(zBuffer); + } + argv[result->nodesetval->nodeNr] = NULL; + } + xmlXPathFreeObject(result); + + /* add the messagetype */ + propValue = xmlGetProp(node, BAD_CAST "name"); + mtype = mt_find((const char *)propValue); + if (mtype==NULL) { + mtype = mt_register(mt_new((const char *)propValue, (const char**)argv)); + } else { + assert(argv!=NULL || !"cannot redefine arguments of message now"); + } + xmlFree(propValue); + + /* register the type for the CR */ + crt_register(mtype); + + /* let's clean up the mess */ + if (argv!=NULL) { + for (k=0;argv[k]!=NULL;++k) free(argv[k]); + free(argv); + } + + propSection = xmlGetProp(node, BAD_CAST "section"); + if (propSection==NULL) propSection = BAD_CAST default_section; + + /* strings */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "text", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + struct locale * lang; + xmlChar * propText; + + xml_readtext(node, &lang, &propText); + if (lang) { + xml_cleanup_string(propText); + nrt_register(mtype, lang, (const char *)propText, 0, (const char*)propSection); + } + xmlFree(propText); + + } + xmlXPathFreeObject(result); + + if (propSection != BAD_CAST default_section) xmlFree(propSection); + } + + xmlXPathFreeObject(messages); + + xmlXPathFreeContext(xpath); + return 0; +} + +static void +xml_readstrings(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, boolean names) +{ + int i; + + for (i=0;i!=nodeNr;++i) { + xmlNodePtr stringNode = nodeTab[i]; + xmlChar * propName = xmlGetProp(stringNode, BAD_CAST "name"); + xmlChar * propNamespace = NULL; + xmlXPathObjectPtr result; + int k; + char zName[128]; + + assert(propName!=NULL); + if (names) propNamespace = xmlGetProp(stringNode->parent, BAD_CAST "name"); + mkname_buf((const char*)propNamespace, (const char*)propName, zName); + if (propNamespace!=NULL) xmlFree(propNamespace); + xmlFree(propName); + + /* strings */ + xpath->node = stringNode; + result = xmlXPathEvalExpression(BAD_CAST "text", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr textNode = result->nodesetval->nodeTab[k]; + struct locale * lang; + xmlChar * propText; + + xml_readtext(textNode, &lang, &propText); + if (propText!=NULL) { + assert(strcmp(zName, (const char*)xml_cleanup_string(BAD_CAST zName))==0); + if (lang) { + xml_cleanup_string(propText); + locale_setstring(lang, zName, (const char *)propText); + } + xmlFree(propText); + } else { + log_warning(("string %s has no text in locale %s\n", + zName, locale_name(lang))); + } + } + xmlXPathFreeObject(result); + } +} + +static int +parse_strings(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr strings; + + /* reading eressea/strings/string */ + strings = xmlXPathEvalExpression(BAD_CAST "/eressea/strings/string", xpath); + xml_readstrings(xpath, strings->nodesetval->nodeTab, strings->nodesetval->nodeNr, false); + xmlXPathFreeObject(strings); + + strings = xmlXPathEvalExpression(BAD_CAST "/eressea/strings/namespace/string", xpath); + xml_readstrings(xpath, strings->nodesetval->nodeTab, strings->nodesetval->nodeNr, true); + xmlXPathFreeObject(strings); + + xmlXPathFreeContext(xpath); + return 0; +} + +static void +xml_readprefixes(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, boolean names) +{ + int i; + + for (i=0;i!=nodeNr;++i) { + xmlNodePtr node = nodeTab[i]; + xmlChar * propText = xmlNodeListGetString(node->doc, node->children, 1); + + if (propText!=NULL) { + add_raceprefix((const char*)propText); + xmlFree(propText); + } + } +} + +static int +parse_prefixes(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr strings; + + /* reading eressea/strings/string */ + strings = xmlXPathEvalExpression(BAD_CAST "/eressea/prefixes/prefix", xpath); + xml_readprefixes(xpath, strings->nodesetval->nodeTab, strings->nodesetval->nodeNr, false); + xmlXPathFreeObject(strings); + + xmlXPathFreeContext(xpath); + return 0; +} + +static int +parse_main(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr result = xmlXPathEvalExpression(BAD_CAST "/eressea/game", xpath); + xmlNodeSetPtr nodes = result->nodesetval; + int i; + + xmlChar * propValue; + if (nodes->nodeNr>0) { + xmlNodePtr node = nodes->nodeTab[0]; + + global.producexpchance = (float)xml_fvalue(node, "learningbydoing", 1.0/3); + + propValue = xmlGetProp(node, BAD_CAST "name"); + if (propValue!=NULL) { + global.gamename = strdup((const char*)propValue); + xmlFree(propValue); + } + + xmlXPathFreeObject(result); + + /* reading eressea/game/param */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "param", xpath); + nodes = result->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + parse_param(&global.parameters, node); + } + + xmlXPathFreeObject(result); + + /* reading eressea/game/order */ + result = xmlXPathEvalExpression(BAD_CAST "order", xpath); + nodes = result->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); + boolean disable = xml_bvalue(node, "disable", false); + + if (disable) { + int k; + for (k=0;k!=MAXKEYWORDS;++k) { + if (strcmp(keywords[k], (const char*)propName)==0) { + global.disabled[k]=1; + break; + } + } + if (k==MAXKEYWORDS) { + log_error(("trying to disable unknown comand %s\n", (const char*)propName)); + } + } + xmlFree(propName); + } + + xmlXPathFreeObject(result); + + /* reading eressea/game/skill */ + result = xmlXPathEvalExpression(BAD_CAST "skill", xpath); + nodes = result->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); + boolean enable = xml_bvalue(node, "enable", true); + enable_skill((const char*)propName, enable); + xmlFree(propName); + } + } + xmlXPathFreeObject(result); + + xmlXPathFreeContext(xpath); + return 0; +} + +void +register_xmlreader(void) +{ + xml_register_callback(parse_main); + + xml_register_callback(parse_strings); + xml_register_callback(parse_prefixes); + xml_register_callback(parse_messages); + xml_register_callback(parse_resources); + xml_register_callback(parse_rules); + + xml_register_callback(parse_terrains); /* requires resources */ + xml_register_callback(parse_buildings); /* requires resources */ + xml_register_callback(parse_ships); /* requires terrains */ + xml_register_callback(parse_spells); /* requires resources */ + xml_register_callback(parse_equipment); /* requires spells */ + xml_register_callback(parse_races); /* requires spells */ + xml_register_callback(parse_calendar); + xml_register_callback(parse_directions); +} diff --git a/src/kernel/xmlreader.h b/src/kernel/xmlreader.h new file mode 100644 index 000000000..4c4457da1 --- /dev/null +++ b/src/kernel/xmlreader.h @@ -0,0 +1,27 @@ +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2007 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifndef H_KRNL_XMLREADER_H +#define H_KRNL_XMLREADER_H +#ifdef __cplusplus +extern "C" { +#endif + extern void register_xmlreader(void); + extern void enable_xml_gamecode(void); + + /* game-specific callbacks */ + extern void (*set_spelldata_cb)(struct spell * sp); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lua-bindings.vcproj b/src/lua-bindings.vcproj new file mode 100644 index 000000000..73fec767d --- /dev/null +++ b/src/lua-bindings.vcproj @@ -0,0 +1,274 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/lua-bindings.vcxproj b/src/lua-bindings.vcxproj new file mode 100644 index 000000000..54e5c4332 --- /dev/null +++ b/src/lua-bindings.vcxproj @@ -0,0 +1,125 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {75501170-51C2-E641-BA8B-EDC008184192} + lua-bindings + Win32Proj + + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + + + + /MP %(AdditionalOptions) + Disabled + .;../../external;%(AdditionalIncludeDirectories) + WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + + + Level4 + true + EditAndContinue + + + WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + .;%(AdditionalIncludeDirectories) + + + $(OutDir)lua-bindings.lib + + + + + Full + .;../../external;%(AdditionalIncludeDirectories) + WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + + + Level4 + + + + + WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) + .;%(AdditionalIncludeDirectories) + + + $(OutDir)lua-bindings.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/lua-bindings.vcxproj.filters b/src/lua-bindings.vcxproj.filters new file mode 100644 index 000000000..e7b96c870 --- /dev/null +++ b/src/lua-bindings.vcxproj.filters @@ -0,0 +1,95 @@ + + + + + {1a17299b-610f-40df-864f-84b37b67ebe7} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {5135c52b-b087-4aab-8d89-2b06da54e8e7} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + + \ No newline at end of file diff --git a/src/modules/arena.c b/src/modules/arena.c new file mode 100644 index 000000000..84081797e --- /dev/null +++ b/src/modules/arena.c @@ -0,0 +1,527 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include + +#if ARENA_MODULE +#include "arena.h" + +/* modules include */ +#include "score.h" + +/* attributes include */ +#include + +/* items include */ +#include + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util include */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc include */ +#include +#include +#include + + +/* exports: */ +plane * arena = NULL; + + +/* local vars */ +#define CENTRAL_VOLCANO 1 + +#ifdef ARENA_CREATION +static unsigned int arena_id = 0; +static region * arena_center = NULL; +static int newarena = 0; +#endif +static region * tower_region[6]; +static region * start_region[6]; + +static region * +arena_region(int school) +{ + return tower_region[school]; +} + +static building * +arena_tower(int school) +{ + return arena_region(school)->buildings; +} + +static int +leave_fail(unit * u) +{ + ADDMSG(&u->faction->msgs, msg_message("arena_leave_fail", "unit", u)); + return 1; +} + +static int +leave_arena(struct unit * u, const struct item_type * itype, int amount, order * ord) +{ + if (!u->building && leave_fail(u)) return -1; + if (u->building!=arena_tower(u->faction->magiegebiet) && leave_fail(u)) return -1; + unused(amount); + unused(ord); + unused(itype); + assert(!"not implemented"); + return 0; +} + +static int +enter_fail(unit * u) +{ + ADDMSG(&u->faction->msgs, msg_message("arena_enter_fail", "region unit", u->region, u)); + return 1; +} + +static int +enter_arena(unit * u, const item_type * itype, int amount, order * ord) +{ + skill_t sk; + region * r = u->region; + unit * u2; + int fee = u->faction->score / 5; + unused(ord); + unused(amount); + unused(itype); + if (fee>2000) fee = 2000; + if (getplane(r)==arena) return -1; + if (u->number!=1 && enter_fail(u)) return -1; + if (get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, fee) < fee && enter_fail(u)) return -1; + for (sk=0;sk!=MAXSKILLS;++sk) { + if (get_level(u, sk)>1 && enter_fail(u)) return -1; + } + for (u2=r->units;u2;u2=u2->next) if (u2->faction==u->faction) break; + + assert(!"not implemented"); +/* + for (res=0;res!=MAXRESOURCES;++res) if (res!=R_SILVER && res!=R_ARENA_GATE && (is_item(res) || is_herb(res) || is_potion(res))) { + int x = get_resource(u, res); + if (x) { + if (u2) { + change_resource(u2, res, x); + change_resource(u, res, -x); + } + else if (enter_fail(u)) return -1; + } + } +*/ + if (get_money(u) > fee) { + if (u2) change_money(u2, get_money(u) - fee); + else if (enter_fail(u)) return -1; + } + ADDMSG(&u->faction->msgs, msg_message("arena_enter_fail", "region unit", u->region, u)); + use_pooled(u, itype->rtype, GET_SLACK|GET_RESERVE, 1); + use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, fee); + set_money(u, 109); + fset(u, UFL_ANON_FACTION); + move_unit(u, start_region[rng_int() % 6], NULL); + return 0; +} + +/*** + ** Szepter der Tränen, Demo-Item + ***/ + +static int +use_wand_of_tears(unit * user, const struct item_type * itype, int amount, order * ord) +{ + int n; + unused(ord); + for (n=0;n!=amount;++n) { + unit * u; + for (u=user->region->units;u;u=u->next) { + if (u->faction != user->faction) { + int i; + + for (i=0;i!=u->skill_size;++i) { + if (rng_int()%3) reduce_skill(u, u->skills+i, 1); + } + ADDMSG(&u->faction->msgs, msg_message("wand_of_tears_effect", + "unit", u)); + } + } + } + ADDMSG(&user->region->msgs, msg_message("wand_of_tears_usage", + "unit", user)); + return 0; +} + +/** + * Tempel der Schreie, Demo-Gebäude **/ + +static int +age_hurting(attrib * a) { + building * b = (building *)a->data.v; + unit * u; + int active = 0; + if (b==NULL) return AT_AGE_REMOVE; + for (u=b->region->units;u;u=u->next) { + if (u->building==b) { + if (u->faction->magiegebiet==M_DRAIG) { + active ++; + ADDMSG(&b->region->msgs, msg_message("praytoigjarjuk", "unit", u)); + } + } + } + if (active) for (u=b->region->units;u;u=u->next) if (playerrace(u->faction->race)) { + int i; + if (u->faction->magiegebiet!=M_DRAIG) { + for (i=0;i!=active;++i) u->hp = (u->hp+1) / 2; /* make them suffer, but not die */ + ADDMSG(&b->region->msgs, msg_message("cryinpain", "unit", u)); + } + } + return AT_AGE_KEEP; +} + +static void +write_hurting(const attrib * a, const void * owner, struct storage * store) { + building * b = a->data.v; + store->w_int(store, b->no); +} + +static int +read_hurting(attrib * a, void * owner, struct storage * store) { + int i; + i = store->r_int(store); + a->data.v = (void*)findbuilding(i); + if (a->data.v==NULL) { + log_error(("temple of pain is broken\n")); + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +static attrib_type at_hurting = { + "hurting", NULL, NULL, age_hurting, write_hurting, read_hurting +}; + +#ifdef ARENA_CREATION +static void +make_temple(region * r) +{ + const building_type * btype = bt_find("temple"); + building * b; + if (btype==NULL) { + log_error(("could not find buildingtype 'temple'\n")); + return; + } + + b = r->buildings; + while (b!=NULL && b->type!=btype) b = b->next; + if (b!=NULL) return; /* gibt schon einen */ + + b = new_building(btype, r, NULL); + b->size = btype->maxsize; + b->name = strdup("Igjarjuk's Tempel der Schreie"); + b->display = strdup("Ein Schrein aus spitzen Knochen und lodernden Flammen, gewidmet dem Wyrm der Wyrme"); + a_add(&b->attribs, a_new(&at_hurting))->data.v=b; +} +#endif + +/** + * Initialisierung Türme */ + +#ifdef ARENA_CREATION +static void +tower_init(void) +{ + int i, first = newarena; + item_type * it_demonseye = it_find("demonseye"); + item_type * it_griphonwing = it_find("griphonwing"); + assert(it_griphonwing && it_demonseye); + for (i=0;i!=6;++i) { + region * r = tower_region[i] = findregion(arena_center->x+delta_x[i]*3, arena_center->y+delta_y[i]*3); + if (r) { + start_region[i] = findregion(arena_center->x+delta_x[i]*2, arena_center->y+delta_y[i]*2); + if (rterrain(r)!=T_DESERT) terraform(r, T_DESERT); + if (!r->buildings) { + building * b = new_building(bt_find("castle"), r, NULL); + b->size = 10; + if (i!=0) { + sprintf(buf, "Turm des %s", + LOC(default_locale, mkname("school", magic_school[i]))); + } + else sprintf(buf, "Turm der Ahnungslosen"); + set_string(&b->name, buf); + } + } + } + if (first && !arena_center->buildings) { + building * b = new_building(bt_find("castle"), arena_center, NULL); + attrib * a; + item * items; + + i_add(&items, i_new(it_griphonwing, 1)); + i_add(&items, i_new(it_demonseye, 1)); + a = a_add(&b->attribs, make_giveitem(b, items)); + + b->size = 10; + set_string(&b->name, "Höhle des Greifen"); + } +} +#endif + +#ifdef ARENA_CREATION +static void +guardian_faction(plane * pl, int id) +{ + region * r; + faction * f = findfaction(id); + + if (!f) { + f = calloc(1, sizeof(faction)); + f->banner = strdup("Sie dienen dem großen Wyrm"); + f->passw = strdup(itoa36(rng_int())); + f->override = strdup(itoa36(rng_int())); + set_email(&f->email, "igjarjuk@eressea.de"); + f->name = strdup("Igjarjuks Kundschafter"); + f->race = new_race[RC_ILLUSION]; + f->age = turn; + f->locale = find_locale("de"); + f->options = want(O_COMPRESS) | want(O_REPORT) | want(O_COMPUTER) | want(O_ADRESSEN) | want(O_DEBUG); + + f->no = id; + addlist(&factions, f); + fhash(f); + } + if (f->race != new_race[RC_ILLUSION]) { + assert(!"guardian id vergeben"); + exit(0); + } + f->lastorders = turn; + f->alive = true; + for (r=regions;r;r=r->next) if (getplane(r)==pl && rterrain(r)!=T_FIREWALL) + { + unit * u; + freset(r, RF_ENCOUNTER); + for (u=r->units;u;u=u->next) { + if (u->faction==f) break; + } + if (u) continue; + u = createunit(r, f, 1, new_race[RC_GOBLIN]); + set_string(&u->name, "Igjarjuks Auge"); + set_item(u, I_RING_OF_INVISIBILITY, 1); + set_order(&u->thisorder, NULL); + fset(u, UFL_ANON_FACTION); + set_money(u, 1000); + } +} +#endif + +#define BLOCKSIZE 9 + +#ifdef ARENA_CREATION +static void +block_create(int x1, int y1, char terrain) +{ + int x, y; + for (x=0;x!=BLOCKSIZE;++x) { + for (y=0;y!=BLOCKSIZE;++y) { + region * r = new_region(x1 + x, y1 + y, 0); + terraform(r, terrain); + } + } +} +#endif + +#ifdef CENTRAL_VOLCANO + +static int +caldera_handle(trigger * t, void * data) +{ + /* call an event handler on caldera. + * data.v -> ( variant event, int timer ) + */ + building *b = (building *)t->data.v; + if (b!=NULL) { + unit ** up = &b->region->units; + while (*up) { + unit * u = *up; + if (u->building==b) { + message * msg; + if (u->items) { + item ** ip = &u->items; + msg = msg_message("caldera_handle_1", "unit items", u, u->items); + while (*ip) { + item * i = *ip; + i_remove(ip, i); + if (*ip==i) ip=&i->next; + } + } else { + msg = msg_message("caldera_handle_0", "unit", u); + } + add_message(&u->region->msgs, msg); + set_number(u, 0); + } + if (*up==u) up = &u->next; + } + } else { + log_error(("could not perform caldera::handle()\n")); + } + unused(data); + return 0; +} + +static void +caldera_write(const trigger * t, struct storage * store) +{ + building *b = (building *)t->data.v; + write_building_reference(b, store); +} + +static int +caldera_read(trigger * t, struct storage * store) +{ + int rb = read_reference(&t->data.v, store, read_building_reference, resolve_building); + if (rb==0 && !t->data.v) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +struct trigger_type tt_caldera = { + "caldera", + NULL, + NULL, + caldera_handle, + caldera_write, + caldera_read +}; + +#ifdef ARENA_CREATION +static trigger * +trigger_caldera(building * b) +{ + trigger * t = t_new(&tt_caldera); + t->data.v = b; + return t; +} +#endif + +#ifdef ARENA_CREATION +static void +init_volcano(void) +{ + building * b; + region * r = arena_center; + assert(arena_center); + if (rterrain(r)!=T_DESERT) return; /* been done before */ + terraform(arena_center, T_VOLCANO_SMOKING); + b = new_building(bt_find("caldera"), r, NULL); + b->size = 1; + b->name = strdup("Igjarjuk's Schlund"); + b->display = strdup("Feurige Lava fließt aus dem Krater des großen Vulkans. Alles wird von ihr verschlungen."); + add_trigger(&b->attribs, "timer", trigger_caldera(b)); + tt_register(&tt_caldera); +} +#endif +#endif + +#ifdef ARENA_CREATION +void +create_arena(void) +{ + int x; + arena_id = hashstring("arena"); + arena = getplanebyid(arena_id); + if (arena!=NULL) return; + score(); /* ist wichtig, damit alle Parteien einen score haben, wenn sie durchs Tor wollen. */ + guardian_faction(arena, 999); + if (arena) arena_center = findregion(plane_center_x(arena), plane_center_y(arena)); + if (!arena_center) { + newarena = 1; + arena = create_new_plane(arena_id, "Arena", -10000, -10000, 0, BLOCKSIZE-1, PFL_LOWSTEALING | PFL_NORECRUITS | PFL_NOALLIANCES); + block_create(arena->minx, arena->miny, T_OCEAN); + arena_center = findregion(plane_center_x(arena), plane_center_y(arena)); + for (x=0;x!=BLOCKSIZE;++x) { + int y; + for (y=0;y!=BLOCKSIZE;++y) { + region * r = findregion(arena->minx+x, arena->miny+y); + freset(r, RF_ENCOUNTER); + r->planep = arena; + switch (distance(r, arena_center)) { + case 4: + terraform(r, T_FIREWALL); + break; + case 0: + terraform(r, T_GLACIER); + break; + case 1: + terraform(r, T_SWAMP); + break; + case 2: + terraform(r, T_MOUNTAIN); + break; + } + } + } + } + make_temple(arena_center); +#ifdef CENTRAL_VOLCANO + init_volcano(); +#else + if (arena_center->terrain!=T_DESERT) terraform(arena_center, T_DESERT); +#endif + rsetmoney(arena_center, 0); + rsetpeasants(arena_center, 0); + tower_init(); +} +#endif +void +register_arena(void) +{ + at_register(&at_hurting); + register_item_use(use_wand_of_tears, "use_wand_of_tears"); + register_function((pf_generic)enter_arena, "enter_arena"); + register_function((pf_generic)leave_arena, "leave_arena"); + tt_register(&tt_caldera); +} + +#endif /* def ARENA_MODULE */ diff --git a/src/modules/arena.h b/src/modules/arena.h new file mode 100644 index 000000000..6dbec6e93 --- /dev/null +++ b/src/modules/arena.h @@ -0,0 +1,39 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef ARENA_H +#define ARENA_H +#ifdef __cplusplus +extern "C" { +#endif + +#if ARENA_MODULE == 0 +#error "must define ARENA_MODULE to use this module" +#endif +/* exports: */ +extern struct plane * arena; + +extern void register_arena(void); +#ifdef ARENA_CREATION +extern void create_arena(void); +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c new file mode 100644 index 000000000..c28a3f1bd --- /dev/null +++ b/src/modules/autoseed.c @@ -0,0 +1,1024 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "autoseed.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +const terrain_type * +random_terrain(const terrain_type * terrains[], int distribution[], int size) +{ + int ndistribution = size; + const terrain_type * terrain; + int n; + + if (distribution) { + ndistribution = 0; + for (n=0;n!=size;++n) { + ndistribution += distribution[n]; + } + } + + n = rng_int() % ndistribution; + if (distribution) { + int i; + for (i=0;i!=size;++i) { + n -= distribution[i]; + if (n<0) break; + } + assert(iresources;rm;rm=rm->next) { + if (rm->type->rtype==rtype) break; + } + if (!rm) { + add_resource(r, 1, base, 150, rtype); + } + return 0; +} + + +static int +count_demand(const region *r) +{ + struct demand *dmd; + int c = 0; + if (r->land) { + for (dmd=r->land->demands;dmd;dmd=dmd->next) c++; + } + return c; +} + +static int +recurse_regions(region *r, region_list **rlist, boolean(*fun)(const region *r)) +{ + if (!fun(r)) return 0; + else { + int len = 0; + direction_t d; + region_list * rl = calloc(sizeof(region_list), 1); + rl->next = *rlist; + rl->data = r; + (*rlist) = rl; + fset(r, RF_MARK); + for (d=0;d!=MAXDIRECTIONS;++d) { + region * nr = rconnect(r, d); + if (nr && !fval(nr, RF_MARK)) len += recurse_regions(nr, rlist, fun); + } + return len+1; + } +} + +static boolean +f_nolux(const region * r) +{ + if (r->land && count_demand(r) != get_maxluxuries()) return true; + return false; +} + +int +fix_demand(region *rd) +{ + region_list *rl, *rlist = NULL; + static const struct luxury_type **mlux = 0, ** ltypes; + const luxury_type *sale = NULL; + int maxlux = 0; + int maxluxuries = get_maxluxuries(); + + if (maxluxuries==0) return 0; + recurse_regions(rd, &rlist, f_nolux); + if (mlux==0) { + int i = 0; + mlux = (const luxury_type **)gc_add(calloc(maxluxuries, sizeof(const luxury_type *))); + ltypes = (const luxury_type **)gc_add(calloc(maxluxuries, sizeof(const luxury_type *))); + for (sale=luxurytypes;sale;sale=sale->next) { + ltypes[i++] = sale; + } + } + else { + int i; + for (i=0;i!=maxluxuries;++i) mlux[i] = 0; + } + for (rl=rlist;rl;rl=rl->next) { + region * r = rl->data; + direction_t d; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * nr = rconnect(r, d); + if (nr && nr->land && nr->land->demands) { + struct demand * dmd; + for (dmd = nr->land->demands;dmd;dmd=dmd->next) { + if (dmd->value == 0) { + int i; + for (i=0;i!=maxluxuries;++i) { + if (mlux[i]==NULL) { + maxlux = i; + mlux[i] = dmd->type; + break; + } else if (mlux[i]==dmd->type) { + break; + } + } + break; + } + } + } + } + freset(r, RF_MARK); /* undo recursive marker */ + } + if (maxlux<2) { + int i; + for (i=maxlux;i!=2;++i) { + int j; + do { + int k = rng_int() % maxluxuries; + mlux[i] = ltypes[k]; + for (j=0;j!=i;++j) { + if (mlux[j]==mlux[i]) break; + } + } while (j!=i); + } + maxlux = 2; + } + for (rl=rlist;rl;rl=rl->next) { + region * r = rl->data; + if (!fval(r, RF_CHAOTIC)) { + log_info((LOG_INFO1, "fixing demand in %s\n", regionname(r, NULL))); + } + sale = mlux[rng_int() % maxlux]; + if (sale) setluxuries(r, sale); + } + while (rlist) { + rl = rlist->next; + free(rlist); + rlist = rl; + } + return 0; +} + +/* nach 150 Runden ist Neustart erlaubt */ +#define MINAGE_MULTI 150 +newfaction * +read_newfactions(const char * filename) +{ + newfaction * newfactions = NULL; + FILE * F = fopen(filename, "r"); + char buf[1024]; + + if (F==NULL) return NULL; + for (;;) { + faction * f; + char race[20], email[64], lang[8], password[16]; + newfaction *nf, **nfi; + int bonus = 0, subscription = 0; + int alliance = 0; + + if (fgets(buf, sizeof(buf), F)==NULL) break; + + email[0] = '\0'; + password[0] = '\0'; + + if (sscanf(buf, "%54s %20s %8s %d %d %16s %d", email, race, lang, &bonus, &subscription, password, &alliance)<6) break; + if (email[0]=='\0') break; + if (password[0]=='\0') { + strcpy(password, itoa36(rng_int())); + strcat(password, itoa36(rng_int())); + } + for (f=factions;f;f=f->next) { + if (strcmp(f->email, email)==0 && f->subscription && f->ageunits) continue; /* skip the ones we've already got */ + for (nf=newfactions;nf;nf=nf->next) { + if (strcmp(nf->email, email)==0) break; + } + if (nf) continue; + nf = calloc(sizeof(newfaction), 1); + if (set_email(&nf->email, email)!=0) { + log_error(("Invalid email address for subscription %s: %s\n", + itoa36(subscription), email)); + continue; + } + nf->password = strdup(password); + nf->race = rc_find(race); + nf->subscription = subscription; + if (alliances!=NULL) { + struct alliance * al = findalliance(alliance); + if (al==NULL) { + char zText[64]; + sprintf(zText, "Allianz %d", alliance); + al = makealliance(alliance, zText); + } + nf->allies = al; + } else { + nf->allies = NULL; + } + if (nf->race==NULL) { + /* if the script didn't supply the race as a token, then it gives us a + * race in the default locale (which means that itis a UTF8 string) */ + nf->race = findrace(race, default_locale); + if (nf->race==NULL) { + char buffer[32]; + size_t outbytes = sizeof(buffer) - 1; + size_t inbytes = strlen(race); + unicode_latin1_to_utf8(buffer, &outbytes, race, &inbytes); + buffer[outbytes] = 0; + nf->race = findrace(buffer, default_locale); + if (nf->race==NULL) { + log_error(("new faction has unknown race '%s'.\n", race)); + free(nf); + continue; + } + } + } + nf->lang = find_locale(lang); + nf->bonus = bonus; + assert(nf->race && nf->email && nf->lang); + nfi = &newfactions; + while (*nfi) { + if ((*nfi)->race==nf->race) break; + nfi=&(*nfi)->next; + } + nf->next = *nfi; + *nfi = nf; + } + fclose(F); + return newfactions; +} + +extern int numnewbies; + +static const terrain_type * +preferred_terrain(const struct race * rc) +{ + terrain_t t = T_PLAIN; + if (rc==rc_find("dwarf")) t = T_MOUNTAIN; + if (rc==rc_find("insect")) t = T_DESERT; + if (rc==rc_find("halfling")) t = T_SWAMP; + if (rc==rc_find("troll")) t = T_MOUNTAIN; + return newterrain(t); +} + +#define REGIONS_PER_FACTION 2 +#define PLAYERS_PER_ISLAND 20 +#define MAXISLANDSIZE 50 +#define MINFACTIONS 1 +#define VOLCANO_CHANCE 100 + +static boolean +virgin_region(const region * r) +{ + direction_t d; + if (r==NULL) return true; + if (fval(r->terrain, FORBIDDEN_REGION)) return false; + if (r->units) return false; + for (d=0;d!=MAXDIRECTIONS;++d) { + const region * rn = rconnect(r, d); + if (rn) { + if (rn->age>r->age+1) return false; + if (rn->units) return false; + if (fval(rn->terrain, FORBIDDEN_REGION)) { + /* because it kinda sucks to have islands that are adjacent to a firewall */ + return false; + } + } + } + return true; +} + +void +get_island(region * root, region_list ** rlist) +{ + region_list ** rnext = rlist; + while (*rnext) rnext=&(*rnext)->next; + + fset(root, RF_MARK); + add_regionlist(rnext, root); + + while (*rnext) { + direction_t dir; + + region * rcurrent = (*rnext)->data; + rnext = &(*rnext)->next; + + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * r = rconnect(rcurrent, dir); + if (r!=NULL && r->land && !fval(r, RF_MARK)) { + fset(r, RF_MARK); + add_regionlist(rnext, r); + } + } + } + rnext=rlist; + while (*rnext) { + region_list * rptr = *rnext; + freset(rptr->data, RF_MARK); + rnext = &rptr->next; + } +} + +static void +get_island_info(region * root, int * size_p, int * inhabited_p, int * maxage_p) +{ + int size = 0, maxage = 0, inhabited = 0; + region_list * rlist = NULL; + region_list * island = NULL; + add_regionlist(&rlist, root); + island = rlist; + fset(root, RF_MARK); + while (rlist) { + direction_t d; + region * r = rlist->data; + if (r->units) { + unit * u; + for (u=r->units; u; u=u->next) { + if (!is_monsters(u->faction) && u->faction->age > maxage) { + maxage = u->faction->age; + } + } + ++inhabited; + } + ++size; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(r, d); + if (rn && !fval(rn, RF_MARK) && rn->land) { + region_list * rnew = malloc(sizeof(region_list)); + rnew->data = rn; + rnew->next = rlist->next; + rlist->next = rnew; + fset(rn, RF_MARK); + } + } + rlist = rlist->next; + } + for (rlist=island;rlist;rlist=rlist->next) { + freset(rlist->data, RF_MARK); + } + free_regionlist(island); + if (size_p) *size_p = size; + if (inhabited_p) *inhabited_p = inhabited; + if (maxage_p) *maxage_p = maxage; +} + +void +free_newfaction(newfaction * nf) +{ + free(nf->email); + free(nf->password); + free(nf); +} + +static void +frame_regions(int age, const terrain_type * terrain) +{ + plane * hplane = get_homeplane(); + region * r = regions; + for (r=regions;r;r=r->next) { + plane * pl = rplane(r); + direction_t d; + if (r->ageterrain == terrain) continue; + + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(r, d); + if (rn==NULL) { + int x = r->x + delta_x[d]; + int y = r->y + delta_y[d]; + pnormalize(&x, &y, pl); + rn = new_region(x, y, pl, 0); + terraform_region(rn, terrain); + rn->age=r->age; + } + } + } +} + +static void +prepare_starting_region(region * r) +{ + int n, t; + double p; + + assert(r->land); + + /* population between 30% and 60% of max */ + p = rng_double(); + n = (int)(r->terrain->size * (0.3 + p*0.3)); + rsetpeasants(r, n); + + /* trees: don't squash the peasants, and at least 5% should be forrest */ + t = (rtrees(r, 2) + rtrees(r, 1)/2) * TREESIZE; + if (t < r->terrain->size/20 || t+n > r->terrain->size) { + double p2 = 0.05 + rng_double()*(1.0-p-0.05); + int maxtrees = (int)(r->terrain->size/1.25/TREESIZE); /* 1.25 = each young tree will take 1/2 the space of old trees */ + int trees = (int)(p2 * maxtrees); + + rsettrees(r, 2, trees); + rsettrees(r, 1, trees/2); + rsettrees(r, 0, trees/4); + } + + /* horses: between 1% and 2% */ + p = rng_double(); + rsethorses(r, (int)(r->terrain->size * (0.01 + p*0.01))); + + if (!markets_module()) { + fix_demand(r); + } +} + +/** create new island with up to nsize players + * returns the number of players placed on the new island. + */ +int +autoseed(newfaction ** players, int nsize, int max_agediff) +{ + region * r = NULL; + region_list * rlist = NULL; + int rsize = 0, tsize = 0; + int isize = REGIONS_PER_FACTION; /* target size for the island */ + int psize = 0; /* players on this island */ + const terrain_type * volcano_terrain = get_terrain("volcano"); + static int nterrains = -1; + static const terrain_type ** terrainarr = 0; + static int * distribution; + + if (nterrains<0) { + int n = 0; + const terrain_type * terrain = terrains(); + for (nterrains=0;terrain;terrain=terrain->next) { + if (terrain->distribution) { + ++nterrains; + } + } + terrainarr = malloc(sizeof(terrain_type *) * nterrains); + distribution = malloc(sizeof(int) * nterrains); + for (terrain = terrains();terrain;terrain = terrain->next) { + if (terrain->distribution) { + terrainarr[n] = terrain; + distribution[n++] = terrain->distribution; + } + } + } + frame_regions(16, newterrain(T_FIREWALL)); + + if (listlen(*players)0) { + region * rmin = NULL; + plane * hplane = get_homeplane(); + /* find a spot that's adjacent to the previous island, but virgin. + * like the last land virgin ocean region adjacent to land. + */ + for (r=regions;r;r=r->next) { + struct plane * pl = rplane(r); + if (r->age<=max_agediff && r->terrain == newterrain(T_OCEAN) && pl==hplane && virgin_region(r)) { + direction_t d; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(r, d); + if (rn && rn->land && rn->age<=max_agediff && virgin_region(rn)) { + /* only expand islands that aren't single-islands and not too big already */ + int size, inhabitants, maxage; + get_island_info(rn, &size, &inhabitants, &maxage); + if (maxage<=max_agediff && size>=2 && sizenext) { + region * r = rlist->data; + unit * u; + for (u=r->units;u;u=u->next) { + f = u->faction; + if (!fval(f, FFL_MARK)) { + ++psize; + fset(f, FFL_MARK); + } + } + } + free_regionlist(rlist); + if (psize>0) for (f=factions;f;f=f->next) freset(f, FFL_MARK); + if (psizenext) { + struct plane * pl = rplane(r); + if (r->terrain == newterrain(T_OCEAN) && pl==hplane && (rmin==NULL || r->age<=max_agediff)) { + direction_t d; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(r, d); + if (rn==NULL) break; + } + if (d!=MAXDIRECTIONS) { + rmin=r; + dmin=d; + } + } + } + + /* create a new region where we found the empty spot, and make it the first + * in our island. island regions are kept in rlist, so only new regions can + * get populated, and old regions are not overwritten */ + if (rmin!=NULL) { + plane * pl = rplane(rmin); + int x = rmin->x + delta_x[dmin]; + int y = rmin->y + delta_y[dmin]; + pnormalize(&x, &y, pl); + assert(virgin_region(rconnect(rmin, dmin))); + r = new_region(x, y, pl, 0); + terraform_region(r, newterrain(T_OCEAN)); + } + } + if (r!=NULL) { + add_regionlist(&rlist, r); + fset(r, RF_MARK); + rsize = 1; + } + + while (rsize && (nsize || isize>=REGIONS_PER_FACTION)) { + int i = rng_int() % rsize; + region_list ** rnext = &rlist; + region_list * rfind; + direction_t d; + while (i--) rnext=&(*rnext)->next; + rfind = *rnext; + r = rfind->data; + freset(r, RF_MARK); + *rnext = rfind->next; + free(rfind); + --rsize; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(r, d); + if (rn && fval(rn, RF_MARK)) continue; + if (rn==NULL) { + plane * pl = rplane(r); + int x = r->x + delta_x[d]; + int y = r->y + delta_y[d]; + pnormalize(&x, &y, pl); + rn = new_region(x, y, pl, 0); + terraform_region(rn, newterrain(T_OCEAN)); + } + if (virgin_region(rn)) { + add_regionlist(&rlist, rn); + fset(rn, RF_MARK); + ++rsize; + } + } + if (volcano_terrain!=NULL && (rng_int() % VOLCANO_CHANCE == 0)) { + terraform_region(r, volcano_terrain); + } else if (nsize && (rng_int() % isize == 0 || rsize==0)) { + newfaction ** nfp, * nextf = *players; + faction * f; + unit * u; + + isize += REGIONS_PER_FACTION; + terraform_region(r, preferred_terrain(nextf->race)); + prepare_starting_region(r); + ++tsize; + assert(r->land && r->units==0); + u = addplayer(r, addfaction(nextf->email, nextf->password, nextf->race, + nextf->lang, nextf->subscription)); + f = u->faction; + fset(f, FFL_ISNEW); + f->alliance = nextf->allies; + log_printf("New faction (%s), %s at %s\n", itoa36(f->no), + f->email, regionname(r, NULL)); + if (f->subscription) { + sql_print(("UPDATE subscriptions SET status='ACTIVE', faction='%s', firstturn=%d, lastturn=%d, password='%s' WHERE id=%u;\n", + factionid(f), f->lastorders, f->lastorders, f->override, f->subscription)); + } + + /* remove duplicate email addresses */ + nfp = &nextf->next; + while (*nfp) { + newfaction * nf = *nfp; + if (strcmp(nextf->email, nf->email)==0) { + *nfp = nf->next; + free_newfaction(nf); + } + else nfp = &nf->next; + } + *players = nextf->next; + free_newfaction(nextf); + + ++psize; + --nsize; + --isize; + if (psize>=PLAYERS_PER_ISLAND) break; + } else { + terraform_region(r, random_terrain(terrainarr, distribution, nterrains)); + --isize; + } + } + + if (nsize!=0) { + log_error(("Could not place all factions on the same island as requested\n")); + } + + + if (rlist) { +#define MINOCEANDIST 3 +#define MAXOCEANDIST 6 +#define MAXFILLDIST 10 +#define SPECIALCHANCE 80 + region_list ** rbegin = &rlist; + int special = 1; + int oceandist = MINOCEANDIST + (rng_int() % (MAXOCEANDIST-MINOCEANDIST)); + while (oceandist--) { + region_list ** rend = rbegin; + while (*rend) rend=&(*rend)->next; + while (rbegin!=rend) { + direction_t d; + region * r = (*rbegin)->data; + rbegin=&(*rbegin)->next; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(r, d); + if (rn==NULL) { + const struct terrain_type * terrain = newterrain(T_OCEAN); + plane * pl = rplane(r); + int x = r->x + delta_x[d]; + int y = r->y + delta_y[d]; + pnormalize(&x, &y, pl); + rn = new_region(x, y, pl, 0); + if (rng_int() % SPECIALCHANCE < special) { + terrain = random_terrain(terrainarr, distribution, nterrains); + special = SPECIALCHANCE / 3; /* 33% chance auf noch eines */ + } else { + special = 1; + } + terraform_region(rn, terrain); + /* the new region has an extra 20% chance to have mallorn */ + if (rng_int() % 100 < 20) fset(r, RF_MALLORN); + add_regionlist(rend, rn); + } + } + } + + } + while (*rbegin) { + region * r = (*rbegin)->data; + plane * pl = rplane(r); + direction_t d; + rbegin=&(*rbegin)->next; + for (d=0;d!=MAXDIRECTIONS;++d) if (rconnect(r, d)==NULL) { + int i; + for (i=1;i!=MAXFILLDIST;++i) { + int x = r->x + delta_x[d]*i; + int y = r->y + delta_y[d]*i; + pnormalize(&x, &y, pl); + if (findregion(x, y)) { + break; + } + } + if (i!=MAXFILLDIST) { + while (--i) { + region * rn; + int x = r->x + delta_x[d]*i; + int y = r->y + delta_y[d]*i; + pnormalize(&x, &y, pl); + rn = new_region(x, y, pl, 0); + terraform_region(rn, newterrain(T_OCEAN)); + } + } + } + } + while (rlist) { + region_list * self = rlist; + rlist = rlist->next; + freset(self->data, RF_MARK); + free(self); + } + } + return tsize; +} + +region_list * regionqueue_push(region_list ** rlist, region * r) +{ + region_list * rnew = malloc(sizeof(region_list)); + rnew->data = r; + rnew->next = 0; + while (*rlist) { rlist = &(*rlist)->next; } + *rlist = rnew; + return rnew; +} + +region * regionqueue_pop(region_list ** rlist) +{ + if (*rlist) { + region * r = (*rlist)->data; + region_list * rpop = *rlist; + *rlist = rpop->next; + free(rpop); + return r; + } + return 0; +} + +#define GEOMAX 8 +static struct geo { + int distribution; + terrain_t type; +} geography_e3[GEOMAX] = { + { 8, T_OCEAN }, + { 3, T_SWAMP }, + { 1, T_VOLCANO }, + { 3, T_DESERT }, + { 4, T_HIGHLAND }, + { 3, T_MOUNTAIN }, + { 2, T_GLACIER }, + { 1, T_PLAIN } +}; + +const terrain_type * random_terrain_e3(direction_t dir) +{ + static const terrain_type ** terrainarr = 0; + static int * distribution = 0; + + if (!distribution) { + int n = 0; + + terrainarr = malloc(GEOMAX * sizeof(const terrain_type *)); + distribution = malloc(GEOMAX * sizeof(int)); + for (n=0;n!=GEOMAX;++n) { + terrainarr[n] = newterrain(geography_e3[n].type); + distribution[n] = geography_e3[n].distribution; + } + } + return random_terrain(terrainarr, distribution, GEOMAX); +} + +int +random_neighbours(region * r, region_list ** rlist, const terrain_type *(*terraformer)(direction_t)) +{ + int nsize = 0; + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * rn = rconnect(r, dir); + if (rn==NULL) { + const terrain_type * terrain = terraformer(dir); + plane * pl = rplane(r); + int x = r->x + delta_x[dir]; + int y = r->y + delta_y[dir]; + pnormalize(&x, &y, pl); + rn = new_region(x, y, pl, 0); + terraform_region(rn, terrain); + regionqueue_push(rlist, rn); + if (rn->land) { + ++nsize; + } + } + } + return nsize; +} + +const terrain_type * get_ocean(direction_t dir) +{ + return newterrain(T_OCEAN); +} + +int region_quality(const region * r, region * rn[]) +{ + int n, result = 0; + + for (n=0;n!=MAXDIRECTIONS;++n) { + if (rn[n] && rn[n]->land) { + if (rn[n]->terrain==newterrain(T_VOLCANO)) { + /* nobody likes volcanoes */ + result -= 2000; + } + result += rn[n]->land->peasants; + } + } + return result; +} + +static void +oceans_around(region * r, region * rn[]) +{ + int n; + for (n=0;n!=MAXDIRECTIONS;++n) { + region * rx = rn[n]; + if (rx==NULL) { + plane * pl = rplane(r); + int x = r->x + delta_x[n]; + int y = r->y + delta_y[n]; + pnormalize(&x, &y, pl); + rx = new_region(x, y, pl, 0); + terraform_region(rx, newterrain(T_OCEAN)); + rn[n] = rx; + } + } +} + +static void +smooth_island(region_list * island) +{ + region * rn[MAXDIRECTIONS]; + region_list * rlist = NULL; + for (rlist=island;rlist;rlist=rlist->next) { + region * r = rlist->data; + int n, nland = 0; + + if (r->land) { + get_neighbours(r, rn); + for (n=0;n!=MAXDIRECTIONS && nland<=1;++n) { + if (rn[n]->land) { + ++nland; + r = rn[n]; + } + } + + if (nland==1) { + get_neighbours(r, rn); + oceans_around(r, rn); + for (n=0;n!=MAXDIRECTIONS;++n) { + int n1 = (n+1)%MAXDIRECTIONS; + int n2 = (n+1+MAXDIRECTIONS)%MAXDIRECTIONS; + if (!rn[n]->land && rn[n1]!=r && rn[n2]!=r) { + r = rlist->data; + runhash(r); + runhash(rn[n]); + SWAP_VARS(int, r->x, rn[n]->x); + SWAP_VARS(int, r->y, rn[n]->y); + rhash(r); + rhash(rn[n]); + rlist->data = r; + oceans_around(r, rn); + break; + } + } + } + } + } +} + +static void +starting_region(region * r, region * rn[]) +{ + unit * u; + int n; + + oceans_around(r, rn); + freset(r, RF_MARK); + for (n=0;n!=MAXDIRECTIONS;++n) { + freset(rn[n], RF_MARK); + } + terraform_region(r, newterrain(T_PLAIN)); + prepare_starting_region(r); + u = addplayer(r, addfaction("enno@eressea.de", itoa36(rng_int()), races, + default_locale, 0)); +} +/* E3A island generation */ +int +build_island_e3(int x, int y, int numfactions, int minsize) +{ +#define MIN_QUALITY 1000 + int nfactions = 0; + region_list * rlist = NULL; + region_list * island = NULL; + plane * pl = findplane(x, y); + region * r = findregion(x, y); + int nsize = 1; + int q, maxq = INT_MIN, minq = INT_MAX; + + if (!r) r = new_region(x, y, pl, 0); + assert(!r->units); + do { + terraform_region(r, random_terrain_e3(NODIRECTION)); + } while (!r->land); + + while (r) { + fset(r, RF_MARK); + if (r->land) { + if (nsizeminsize/2) { + for (rlist=island;rlist;rlist=rlist->next) { + r = rlist->data; + if (r->land && fval(r, RF_MARK)) { + region *rn[MAXDIRECTIONS]; + + get_neighbours(r, rn); + q = region_quality(r,rn); + if (q>=MIN_QUALITY && nfactionsnext) { + r = rlist->data; + if (!r->land && fval(r, RF_MARK)) { + region *rn[MAXDIRECTIONS]; + get_neighbours(r, rn); + q = region_quality(r, rn); + if (q>=MIN_QUALITY*4/3 && nfactionsnext) { + r = rlist->data; + if (r->units) { + region *rn[MAXDIRECTIONS]; + get_neighbours(r, rn); + q = region_quality(r, rn); + if (q-minq > (maxq-minq)*2/3) { + terraform_region(r, newterrain(T_HIGHLAND)); + prepare_starting_region(r); + } + r->land->money = 50000; /* 2% = 1000 silver */ + } else if (r->land) { + r->land->money *= 4; + } + } + return nfactions; +} diff --git a/src/modules/autoseed.h b/src/modules/autoseed.h new file mode 100644 index 000000000..0fcb75da5 --- /dev/null +++ b/src/modules/autoseed.h @@ -0,0 +1,50 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef _REGIONLIST_H +#define _REGIONLIST_H +#ifdef __cplusplus +extern "C" { +#endif + + +struct region_list; +struct newfaction; + +typedef struct newfaction { + struct newfaction * next; + char * email; + char * password; + const struct locale * lang; + const struct race * race; + int bonus; + int subscription; + boolean oldregions; + struct alliance * allies; +} newfaction; + +#define ISLANDSIZE 20 +#define TURNS_PER_ISLAND 5 + +extern int autoseed(newfaction ** players, int nsize, int max_agediff); +extern newfaction * read_newfactions(const char * filename); +extern void get_island(struct region * root, struct region_list ** rlist); +extern int fix_demand(struct region *r); +extern const struct terrain_type * random_terrain(const struct terrain_type * terrains[], int distribution[], int size); + +extern int seed_adamantium(struct region * r, int base); +extern int build_island_e3(int x, int y, int numfactions, int minsize); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/dungeon.c b/src/modules/dungeon.c new file mode 100644 index 000000000..a8275bbda --- /dev/null +++ b/src/modules/dungeon.c @@ -0,0 +1,268 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include + +#if DUNGEON_MODULE +#include "dungeon.h" +#include "gmcmd.h" + +#include +#include + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include + +/* libc includes */ +#include +#include +#include + +typedef struct treasure { + const struct item_type * itype; + int amount; + struct treasure * next; +} treasure; + +typedef struct monster { + const struct race * race; + double chance; + int maxunits; + int avgsize; + struct treasure * treasures; + struct monster * next; + struct itemtype_list * weapons; +} monster; + +typedef struct skilllimit { + skill_t skill; + int minskill; + int maxskill; + struct skilllimit * next; +} skilllimit; + +typedef struct dungeon { + int level; + int radius; + int size; + int maxpeople; + struct skilllimit * limits; + double connect; + struct monster * boss; + struct monster * monsters; + struct dungeon * next; +} dungeon; + +dungeon * dungeonstyles; + +region * +make_dungeon(const dungeon * data) +{ + int nb[2][3][2] = { + { { -1, 0 }, { 0, 1 }, { 1, -1 } }, + { { 1, 0 }, { -1, 1 }, { 0, -1 } } + }; + const struct race * bossrace = data->boss->race; + char name[128]; + int size = data->size; + int iterations = size * size; + unsigned int flags = PFL_NORECRUITS; + int n = 0; + struct faction * fmonsters = get_monsters(); + plane * p; + region *r, *center; + region * rnext; + region_list * iregion, * rlist = NULL; + const terrain_type * terrain_hell = get_terrain("hell"); + + assert(terrain_hell!=NULL); + sprintf(name, "Die Höhlen von %s", bossrace->generate_name(NULL)); + p = gm_addplane(data->radius, flags, name); + + center = findregion(p->minx+(p->maxx-p->minx)/2, p->miny+(p->maxy-p->miny)/2); + assert(center); + terraform_region(center, terrain_hell); + add_regionlist(&rlist, center); + rnext = r = center; + while (size>0 && iterations--) { + int d, o = rng_int() % 3; + for (d=0;d!=3;++d) { + int index = (d+o) % 3; + region * rn = findregion(r->x+nb[n][index][0], r->y+nb[n][index][1]); + assert(r->terrain==terrain_hell); + if (rn) { + if (rn->terrain==terrain_hell) { + rnext = rn; + } else if (fval(rn->terrain, SEA_REGION)) { + if (rng_int() % 100 < data->connect*100) { + terraform_region(rn, terrain_hell); + --size; + rnext = rn; + add_regionlist(&rlist, rn); + } + else terraform(rn, T_FIREWALL); + } + if (size == 0) break; + } + rn = findregion(r->x+nb[(n+1)%2][index][0], r->y+nb[(n+1)%2][index][1]); + if (rn && fval(rn->terrain, SEA_REGION)) { + terraform(rn, T_FIREWALL); + } + } + if (size==0) break; + if (r==rnext) { + /* error */ + break; + } + r = rnext; + n = (n+1) % 2; + } + + for (iregion=rlist;iregion;iregion=iregion->next) { + monster * m = data->monsters; + region * r = iregion->data; + while (m) { + if ((rng_int() % 100) < (m->chance * 100)) { + /* TODO: check maxunits. */ + treasure * loot = m->treasures; + struct itemtype_list * weapon = m->weapons; + int size = 1 + (rng_int() % m->avgsize) + (rng_int() % m->avgsize); + unit * u = createunit(r, fmonsters, size, m->race); + while (weapon) { + i_change(&u->items, weapon->type, size); + weapon = weapon->next; + } + while (loot) { + i_change(&u->items, loot->itype, loot->amount*size); + loot = loot->next; + } + } + m = m->next; + } + } + return center; +} + +void +make_dungeongate(region * source, region * target, const struct dungeon * d) +{ + building *bsource, *btarget; + + if (source==NULL || target==NULL || d==NULL) return; + bsource = new_building(bt_find("castle"), source, default_locale); + set_string(&bsource->name, "Pforte zur Hölle"); + bsource->size = 50; + add_trigger(&bsource->attribs, "timer", trigger_gate(bsource, target)); + add_trigger(&bsource->attribs, "create", trigger_unguard(bsource)); + fset(bsource, BLD_UNGUARDED); + + btarget = new_building(bt_find("castle"), target, default_locale); + set_string(&btarget->name, "Pforte zur Außenwelt"); + btarget->size = 50; + add_trigger(&btarget->attribs, "timer", trigger_gate(btarget, source)); + add_trigger(&btarget->attribs, "create", trigger_unguard(btarget)); + fset(btarget, BLD_UNGUARDED); +} + +static int +tagbegin(xml_stack *stack) +{ + xml_tag * tag = stack->tag; + if (strcmp(tag->name, "dungeon")==0) { + dungeon * d = (dungeon*)calloc(sizeof(dungeon), 1); + d->maxpeople = xml_ivalue(tag, "maxpeople"); + if (d->maxpeople==0) d->maxpeople = INT_MAX; + d->level = xml_ivalue(tag, "level"); + d->radius = xml_ivalue(tag, "radius"); + d->connect = xml_fvalue(tag, "connect"); + d->size = xml_ivalue(tag, "size"); + stack->state = d; + } else { + dungeon * d = (dungeon*)stack->state; + if (strcmp(tag->name, "skilllimit")==0) { + skill_t sk = sk_find(xml_value(tag, "name")); + if (sk!=NOSKILL) { + skilllimit * skl = calloc(sizeof(skilllimit), 1); + skl->skill = sk; + if (xml_value(tag, "max")!=NULL) { + skl->maxskill = xml_ivalue(tag, "max"); + } else skl->maxskill = INT_MAX; + if (xml_value(tag, "min")!=NULL) { + skl->minskill = xml_ivalue(tag, "min"); + } else skl->maxskill = INT_MIN; + skl->next = d->limits; + d->limits = skl; + } + } else if (strcmp(tag->name, "monster")==0) { + monster * m = calloc(sizeof(monster), 1); + m->race = rc_find(xml_value(tag, "race")); + m->chance = xml_fvalue(tag, "chance"); + m->avgsize = MAX(1, xml_ivalue(tag, "size")); + m->maxunits = MIN(1, xml_ivalue(tag, "maxunits")); + + if (m->race) { + if (xml_bvalue(tag, "boss")) { + d->boss = m; + } else { + m->next = d->monsters; + d->monsters = m; + } + } + } else if (strcmp(tag->name, "weapon")==0) { + monster * m = d->monsters; + itemtype_list * w = calloc(sizeof(itemtype_list), 1); + w->type = it_find(xml_value(tag, "type")); + if (w->type) { + w->next = m->weapons; + m->weapons = w; + } + } + } + return XML_OK; +} + +static int +tagend(xml_stack * stack) +{ + xml_tag * tag = stack->tag; + if (strcmp(tag->name, "dungeon")) { + dungeon * d = (dungeon*)stack->state; + stack->state = NULL; + d->next = dungeonstyles; + dungeonstyles = d; + } + return XML_OK; +} + +xml_callbacks xml_dungeon = { + tagbegin, tagend, NULL +}; + +void +register_dungeon(void) +{ + xml_register(&xml_dungeon, "eressea dungeon", 0); +} + +#endif diff --git a/src/modules/dungeon.h b/src/modules/dungeon.h new file mode 100644 index 000000000..b0526e5a9 --- /dev/null +++ b/src/modules/dungeon.h @@ -0,0 +1,36 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_MOD_DUNGEON +#define H_MOD_DUNGEON +#ifdef __cplusplus +extern "C" { +#endif + +#if DUNGEON_MODULE == 0 +#error "must define DUNGEON_MODULE to use this module" +#endif + +struct region; +struct plane; +struct building; +struct dungeon; + +extern struct dungeon * dungeonstyles; +extern struct region * make_dungeon(const struct dungeon*); +extern void make_dungeongate(struct region * source, struct region * target, const struct dungeon *); +extern void register_dungeon(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/gmcmd.c b/src/modules/gmcmd.c new file mode 100644 index 000000000..61b216e4e --- /dev/null +++ b/src/modules/gmcmd.c @@ -0,0 +1,772 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "gmcmd.h" +#include + +/* misc includes */ +#include +#include +#include +#include + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +/** + ** at_permissions + **/ + +static void +mistake(const unit * u, struct order * ord, const char *comment) +{ + if (!is_monsters(u->faction)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "mistake", + "error", comment)); + } +} + +static void +write_permissions(const attrib * a, const void * owner, struct storage * store) +{ + a_write(store, (attrib*)a->data.v, owner); +} + +static int +read_permissions(attrib * a, void * owner, struct storage * store) +{ + attrib * attr = NULL; + a_read(store, &attr, NULL); + a->data.v = attr; + return AT_READ_OK; +} + +struct attrib_type at_permissions = { + "GM:permissions", + NULL, NULL, NULL, + write_permissions, read_permissions, + ATF_UNIQUE +}; + +attrib * +make_atpermissions(void) +{ + return a_new(&at_permissions); +} + +/** + ** GM: CREATE + **/ + +static void +write_gmcreate(const attrib * a, const void * owner, struct storage * store) +{ + const item_type * itype = (const item_type *)a->data.v; + assert(itype); + store->w_tok(store, resourcename(itype->rtype, 0)); +} + +static int +read_gmcreate(attrib * a, void * owner, struct storage * store) +{ + char zText[32]; + store->r_tok_buf(store, zText, sizeof(zText)); + a->data.v = it_find(zText); + if (a->data.v == NULL) { + log_error(("unknown itemtype %s in gmcreate attribute\n", zText)); + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +/* at_gmcreate specifies that the owner can create items of a particular type */ +attrib_type at_gmcreate = { + "GM:create", + NULL, NULL, NULL, + write_gmcreate, read_gmcreate +}; + +attrib * +make_atgmcreate(const struct item_type * itype) +{ + attrib * a = a_new(&at_gmcreate); + a->data.v = (void*)itype; + return a; +} + +static void +gm_create(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + int i; + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (permissions) permissions = (attrib*)permissions->data.v; + if (!permissions) return; + i = getint(); + + if (i>0) { + const char * iname = getstrtoken(); + const item_type * itype = finditemtype(iname, u->faction->locale); + if (itype==NULL) { + mistake(u, ord, "unknown item."); + } else { + attrib * a = a_find(permissions, &at_gmcreate); + + while (a && a->type==&at_gmcreate && a->data.v!=(void*)itype) a=a->next; + if (a) i_change(&u->items, itype, i); + else mistake(u, ord, "your faction cannot create this item."); + } + } +} + +static boolean +has_permission(const attrib * permissions, unsigned int key) +{ + return (find_key((attrib*)permissions->data.v, key) || + find_key((attrib*)permissions->data.v, atoi36("master"))); +} + +/** + ** GM: GATE + ** requires: permission-key "gmgate" + **/ +static void +gm_gate(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + const struct plane * pl = rplane(u->region); + int id = getid(); + int x = rel_to_abs(pl, u->faction, getint(), 0); + int y = rel_to_abs(pl, u->faction, getint(), 1); + building * b = findbuilding(id); + region * r; + + pnormalize(&x, &y, pl); + r = findregion(x, y); + if (b==NULL || r==NULL || pl!=rplane(b->region) || pl!=rplane(r)) { + mistake(u, ord, "the unit cannot transform this building."); + return; + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (permissions && has_permission(permissions, atoi36("gmgate"))) { + remove_triggers(&b->attribs, "timer", &tt_gate); + remove_triggers(&b->attribs, "create", &tt_unguard); + if (r!=b->region) { + add_trigger(&b->attribs, "timer", trigger_gate(b, r)); + add_trigger(&b->attribs, "create", trigger_unguard(b)); + fset(b, BLD_UNGUARDED); + } + } + } +} + + +/** + ** GM: TERRAFORM + ** requires: permission-key "gmterf" + **/ +static void +gm_terraform(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + const struct plane * p = rplane(u->region); + int x = rel_to_abs(p, u->faction, getint(), 0); + int y = rel_to_abs(p, u->faction, getint(), 1); + const char * c = getstrtoken(); + variant token; + tnode * tokens = get_translations(u->faction->locale, UT_TERRAINS); + region * r; + pnormalize(&x, &y, p); + r = findregion(x, y); + + if (r==NULL || p!=rplane(r)) { + mistake(u, ord, "region is in another plane."); + return; + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmterf"))) return; + } + + if (findtoken(tokens, c, &token)!=E_TOK_NOMATCH) { + const terrain_type * terrain = (const terrain_type *)token.v; + terraform_region(r, terrain); + } +} + +/** + ** GM: TELEPORT + ** requires: permission-key "gmtele" + **/ +static void +gm_teleport(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + const struct plane * p = rplane(u->region); + unit * to = findunit(getid()); + int x = rel_to_abs(p, u->faction, getint(), 0); + int y = rel_to_abs(p, u->faction, getint(), 1); + region * r = findregion(x, y); + + if (r==NULL || p!=rplane(r)) { + mistake(u, ord, "region is in another plane."); + } else if (to==NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } else if (rplane(to->region)!=rplane(r) && !ucontact(to, u)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", "target", to)); + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmtele"))) { + mistake(u, ord, "permission denied."); + } + else move_unit(to, r, NULL); + } +} + +/** + ** GM: TELL PLANE + ** requires: permission-key "gmmsgr" + **/ +static void +gm_messageplane(const tnode * tnext, void * data, struct order * ord) +{ + unit * gm = (unit*)data; + const struct plane * p = rplane(gm->region); + const char * zmsg = getstrtoken(); + if (p==NULL) { + mistake(gm, ord, "In diese Ebene kann keine Nachricht gesandt werden."); + } else { + /* checking permissions */ + attrib * permissions = a_find(gm->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { + mistake(gm, ord, "permission denied."); + } + else { + message * msg = msg_message("msg_event", "string", zmsg); + faction * f; + region * r; + for (f=factions;f;f=f->next) { + freset(f, FFL_SELECT); + } + for (r=regions;r;r=r->next) { + unit * u; + if (rplane(r)!=p) continue; + for (u=r->units;u;u=u->next) if (!fval(u->faction, FFL_SELECT)) { + f = u->faction; + fset(f, FFL_SELECT); + add_message(&f->msgs, msg); + } + } + msg_release(msg); + } + } +} + +static void +gm_messagefaction(const tnode * tnext, void * data, struct order * ord) +{ + unit * gm = (unit*)data; + int n = getid(); + faction * f = findfaction(n); + const char * msg = getstrtoken(); + plane * p = rplane(gm->region); + attrib * permissions = a_find(gm->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { + mistake(gm, ord, "permission denied."); + return; + } + if (f!=NULL) { + region * r; + for (r=regions;r;r=r->next) if (rplane(r)==p) { + unit * u; + for (u=r->units;u;u=u->next) if (u->faction==f) { + add_message(&f->msgs, msg_message("msg_event", "string", msg)); + return; + } + } + } + mistake(gm, ord, "cannot send messages to this faction."); +} + +/** + ** GM: TELL REGION + ** requires: permission-key "gmmsgr" + **/ +static void +gm_messageregion(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + const struct plane * p = rplane(u->region); + int x = rel_to_abs(p, u->faction, getint(), 0); + int y = rel_to_abs(p, u->faction, getint(), 1); + const char * msg = getstrtoken(); + region * r = findregion(x, y); + + if (r==NULL || p!=rplane(r)) { + mistake(u, ord, "region is in another plane."); + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { + mistake(u, ord, "permission denied."); + } + else { + add_message(&r->msgs, msg_message("msg_event", "string", msg)); + } + } +} + +/** + ** GM: KILL UNIT + ** requires: permission-key "gmkill" + **/ +static void +gm_killunit(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + const struct plane * p = rplane(u->region); + unit * target = findunit(getid()); + const char * msg = getstrtoken(); + region * r = target->region; + + if (r==NULL || p!=rplane(r)) { + mistake(u, ord, "region is in another plane."); + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmkill"))) { + mistake(u, ord, "permission denied."); + } + else { + scale_number(target, 0); + ADDMSG(&target->faction->msgs, msg_message("killedbygm", + "region unit string", r, target, msg)); + } + } +} + + +/** + ** GM: KILL FACTION + ** requires: permission-key "gmmsgr" + **/ +static void +gm_killfaction(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + int n = getid(); + faction * f = findfaction(n); + const char * msg = getstrtoken(); + plane * p = rplane(u->region); + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmkill"))) { + mistake(u, ord, "permission denied."); + return; + } + if (f!=NULL) { + region * r; + for (r=regions;r;r=r->next) if (rplane(r)==p) { + unit * target; + for (target=r->units;target;target=target->next) { + if (target->faction==f) { + scale_number(target, 0); + ADDMSG(&target->faction->msgs, msg_message("killedbygm", + "region unit string", r, target, msg)); + return; + } + } + } + } + mistake(u, ord, "cannot remove a unit from this faction."); +} + +/** + ** GM: TELL + ** requires: permission-key "gmmsgr" + **/ +static void +gm_messageunit(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + const struct plane * p = rplane(u->region); + unit * target = findunit(getid()); + const char * msg = getstrtoken(); + region * r; + + if (target == NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + + r = target->region; + + if (r==NULL || p!=rplane(r)) { + mistake(u, ord, "region is in another plane."); + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmmsgu"))) { + mistake(u, ord, "permission denied."); + } + else { + add_message(&target->faction->msgs, + msg_message("regionmessage", "region sender string", r, u, msg)); + } + } +} + +/** + ** GM: GIVE + ** requires: permission-key "gmgive" + **/ +static void +gm_give(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + unit * to = findunit(getid()); + int num = getint(); + const item_type * itype = finditemtype(getstrtoken(), u->faction->locale); + + if (to==NULL || rplane(to->region) != rplane(u->region)) { + /* unknown or in another plane */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } else if (itype==NULL || i_get(u->items, itype)==0) { + /* unknown or not enough */ + mistake(u, ord, "invalid item or item not found."); + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmgive"))) { + mistake(u, ord, "permission denied."); + } + else { + int i = i_get(u->items, itype); + if (iitems, itype, -num); + i_change(&to->items, itype, num); + } + } + } +} + +/** + ** GM: TAKE + ** requires: permission-key "gmtake" + **/ +static void +gm_take(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + unit * to = findunit(getid()); + int num = getint(); + const item_type * itype = finditemtype(getstrtoken(), u->faction->locale); + + if (to==NULL || rplane(to->region) != rplane(u->region)) { + /* unknown or in another plane */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } else if (itype==NULL || i_get(to->items, itype)==0) { + /* unknown or not enough */ + mistake(u, ord, "invalid item or item not found."); + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmtake"))) { + mistake(u, ord, "permission denied."); + } + else { + int i = i_get(to->items, itype); + if (iitems, itype, -num); + i_change(&u->items, itype, num); + } + } + } +} + +/** + ** GM: SKILL + ** requires: permission-key "gmskil" + **/ +static void +gm_skill(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + unit * to = findunit(getid()); + skill_t skill = findskill(getstrtoken(), u->faction->locale); + int num = getint(); + + if (to==NULL || rplane(to->region) != rplane(u->region)) { + /* unknown or in another plane */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } else if (skill==NOSKILL || skill==SK_MAGIC || skill==SK_ALCHEMY) { + /* unknown or not enough */ + mistake(u, ord, "unknown skill, or skill cannot be raised."); + } else if (num<0 || num>30) { + /* sanity check failed */ + mistake(u, ord, "invalid value."); + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmskil"))) { + mistake(u, ord, "permission denied."); + } + else { + set_level(to, skill, num); + } + } +} + +static tnode g_keys; +static tnode g_root; +static tnode g_tell; +static tnode g_kill; + +void +register_gmcmd(void) +{ + at_register(&at_gmcreate); + at_register(&at_permissions); + add_command(&g_root, &g_keys, "gm", NULL); + add_command(&g_keys, NULL, "terraform", &gm_terraform); + add_command(&g_keys, NULL, "create", &gm_create); + add_command(&g_keys, NULL, "gate", &gm_gate); + add_command(&g_keys, NULL, "give", &gm_give); + add_command(&g_keys, NULL, "take", &gm_take); + add_command(&g_keys, NULL, "teleport", &gm_teleport); + add_command(&g_keys, NULL, "skill", &gm_skill); + add_command(&g_keys, &g_tell, "tell", NULL); + add_command(&g_tell, NULL, "region", &gm_messageregion); + add_command(&g_tell, NULL, "unit", &gm_messageunit); + add_command(&g_tell, NULL, "plane", &gm_messageplane); + add_command(&g_tell, NULL, "faction", &gm_messagefaction); + add_command(&g_keys, &g_kill, "kill", NULL); + add_command(&g_kill, NULL, "unit", &gm_killunit); + add_command(&g_kill, NULL, "faction", &gm_killfaction); +} + +/* + * execute gm-commands for all units in the game + */ + +void +gmcommands(void) +{ + region ** rp = ®ions; + while (*rp) { + region * r = *rp; + unit **up = &r->units; + while (*up) { + unit * u = *up; + struct order * ord; + for (ord = u->orders; ord; ord = ord->next) { + if (get_keyword(ord) == K_GM) { + do_command(&g_root, u, ord); + } + } + if (u==*up) up = &u->next; + } + if (*rp==r) rp = &r->next; + } +} + +#define EXTENSION 10000 + +faction * +gm_addquest(const char * email, const char * name, int radius, unsigned int flags) +{ + plane * pl; + watcher * w = calloc(sizeof(watcher), 1); + region * center; + boolean invalid = false; + int minx, miny, maxx, maxy, cx, cy; + int x; + faction * f; + + /* GM playfield */ + do { + minx = ((rng_int() % (2*EXTENSION)) - EXTENSION); + miny = ((rng_int() % (2*EXTENSION)) - EXTENSION); + for (x=0;!invalid && x<=radius*2;++x) { + int y; + for (y=0;!invalid && y<=radius*2;++y) { + region * r = findregion(minx+x, miny+y); + if (r) invalid = true; + } + } + } while (invalid); + maxx = minx+2*radius; cx = minx+radius; + maxy = miny+2*radius; cy = miny+radius; + pl = create_new_plane(rng_int(), name, minx, maxx, miny, maxy, flags); + center = new_region(cx, cy, pl, 0); + for (x=0;x<=2*radius;++x) { + int y; + for (y=0;y<=2*radius;++y) { + region * r = findregion(minx+x, miny+y); + if (!r) { + r = new_region(minx+x, miny+y, pl, 0); + } + freset(r, RF_ENCOUNTER); + if (distance(r, center)==radius) { + terraform_region(r, newterrain(T_FIREWALL)); + } else if (r==center) { + terraform_region(r, newterrain(T_PLAIN)); + } else { + terraform_region(r, newterrain(T_OCEAN)); + } + } + } + + /* watcher: */ + f = gm_addfaction(email, pl, center); + w->faction = f; + w->mode = see_unit; + w->next = pl->watchers; + pl->watchers = w; + + return f; +} + +faction * +gm_addfaction(const char * email, plane * p, region * r) +{ + attrib * a; + unit * u; + faction * f = calloc(1, sizeof(faction)); + + assert(p!=NULL); + + /* GM faction */ + a_add(&f->attribs, make_key(atoi36("quest"))); + f->banner = strdup("quest faction"); + f->name = strdup("quest faction"); + f->passw = strdup(itoa36(rng_int())); + f->override = strdup(itoa36(rng_int())); + if (set_email(&f->email, email)!=0) { + log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), email)); + } + f->race = new_race[RC_TEMPLATE]; + f->age = 0; + f->lastorders = turn; + f->alive = true; + f->locale = default_locale; + f->options = want(O_COMPRESS) | want(O_REPORT) | want(O_COMPUTER) | want(O_ADRESSEN); + { + faction * xist; + int id = atoi36("gm00")-1; + do { + xist = findfaction(++id); + } while (xist); + + f->no = id; + addlist(&factions, f); + fhash(f); + } + + /* generic permissions */ + a = a_add(&f->attribs, a_new(&at_permissions)); + if (a) { + attrib * ap = (attrib*)a->data.v; + const char* keys[] = { "gmterf", "gmtele", "gmgive", "gmskil", "gmtake", "gmmsgr", "gmmsgu", "gmgate", 0 }; + const char ** key_p = keys; + while (*key_p) { + add_key(&ap, atoi36(*key_p)); + ++key_p; + } + a_add(&ap, make_atgmcreate(resource2item(r_silver))); + + a->data.v = ap; + } + + /* one initial unit */ + u = create_unit(r, f, 1, new_race[RC_TEMPLATE], 1, "quest master", NULL); + u->irace = new_race[RC_GNOME]; + + return f; +} + +plane * +gm_addplane(int radius, unsigned int flags, const char * name) +{ + region * center; + plane * pl; + boolean invalid = false; + int minx, miny, maxx, maxy, cx, cy; + int x; + + /* GM playfield */ + do { + minx = (rng_int() % (2*EXTENSION)) - EXTENSION; + miny = (rng_int() % (2*EXTENSION)) - EXTENSION; + for (x=0;!invalid && x<=radius*2;++x) { + int y; + for (y=0;!invalid && y<=radius*2;++y) { + region * r = findregion(minx+x, miny+y); + if (r) invalid = true; + } + } + } while (invalid); + maxx = minx+2*radius; cx = minx+radius; + maxy = miny+2*radius; cy = miny+radius; + pl = create_new_plane(rng_int(), name, minx, maxx, miny, maxy, flags); + center = new_region(cx, cy, pl, 0); + for (x=0;x<=2*radius;++x) { + int y; + for (y=0;y<=2*radius;++y) { + region * r = findregion(minx+x, miny+y); + if (!r) r = new_region(minx+x, miny+y, pl, 0); + freset(r, RF_ENCOUNTER); + if (distance(r, center)==radius) { + terraform_region(r, newterrain(T_FIREWALL)); + } else if (r==center) { + terraform_region(r, newterrain(T_PLAIN)); + } else { + terraform_region(r, newterrain(T_OCEAN)); + } + } + } + return pl; +} diff --git a/src/modules/gmcmd.h b/src/modules/gmcmd.h new file mode 100644 index 000000000..2e830b51c --- /dev/null +++ b/src/modules/gmcmd.h @@ -0,0 +1,48 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_MOD_GMCMD +#define H_MOD_GMCMD +#ifdef __cplusplus +extern "C" { +#endif + +struct plane; +struct attrib; +struct unit; +struct faction; +struct region; + +extern void register_gmcmd(void); +/* initialize this module */ + +extern void gmcommands(void); +/* execute commands */ + +extern struct faction * gm_addfaction(const char * email, struct plane * p, struct region * r); +extern struct plane * gm_addplane(int radius, unsigned int flags, const char * name); + +/* + * doesn't belong in here: + */ +struct attrib * find_key(struct attrib * attribs, int key); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/museum.c b/src/modules/museum.c new file mode 100644 index 000000000..7186f177d --- /dev/null +++ b/src/modules/museum.c @@ -0,0 +1,396 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include + +#include + +#if MUSEUM_MODULE +#include "museum.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +#define PFL_MUSEUM PFL_NOMONSTERS | PFL_NORECRUITS | PFL_NOGIVE | PFL_NOATTACK | PFL_NOTERRAIN | PFL_NOMAGIC | PFL_NOSTEALTH | PFL_NOTEACH | PFL_NOBUILD | PFL_NOFEED + +attrib_type at_museumexit = { + "museumexit", NULL, NULL, NULL, a_writeshorts, a_readshorts +}; + +static void +a_initmuseumgivebackcookie(attrib *a) +{ + a->data.v = calloc(1,sizeof(museumgivebackcookie)); +} + +static void +a_finalizemuseumgivebackcookie(attrib *a) +{ + free(a->data.v); +} + +static void +a_writemuseumgivebackcookie(const attrib * a, const void * owner, struct storage * store) +{ + museumgivebackcookie *gbc = (museumgivebackcookie *)a->data.v; + store->w_int(store, gbc->warden_no); + store->w_int(store, gbc->cookie); +} + +static int +a_readmuseumgivebackcookie(attrib *a, void * owner, struct storage * store) +{ + museumgivebackcookie *gbc = (museumgivebackcookie *)a->data.v; + gbc->warden_no = store->r_int(store); + gbc->cookie = store->r_int(store); + return AT_READ_OK; +} + +attrib_type at_museumgivebackcookie = { + "museumgivebackcookie", + a_initmuseumgivebackcookie, + a_finalizemuseumgivebackcookie, + NULL, + a_writemuseumgivebackcookie, + a_readmuseumgivebackcookie +}; + +attrib_type at_warden = { + "itemwarden", NULL, NULL, NULL, a_writeint, a_readint +}; + +static void +a_initmuseumgiveback(attrib *a) +{ + a->data.v = calloc(1, sizeof(museumgiveback)); +} + +static void +a_finalizemuseumgiveback(attrib *a) +{ + museumgiveback *gb = (museumgiveback *)a->data.v; + i_freeall(&gb->items); + free(a->data.v); +} + +static void +a_writemuseumgiveback(const attrib * a, const void * owner, struct storage * store) +{ + museumgiveback *gb = (museumgiveback *)a->data.v; + store->w_int(store, gb->cookie); + write_items(store, gb->items); +} + +static int +a_readmuseumgiveback(attrib *a, void * owner, struct storage * store) +{ + museumgiveback *gb = (museumgiveback *)a->data.v; + gb->cookie = store->r_int(store); + read_items(store, &gb->items); + return AT_READ_OK; +} + +attrib_type at_museumgiveback = { + "museumgiveback", + a_initmuseumgiveback, + a_finalizemuseumgiveback, + NULL, + a_writemuseumgiveback, + a_readmuseumgiveback +}; + +void +warden_add_give(unit *src, unit *u, const item_type *itype, int n) +{ + attrib *aw = a_find(u->attribs, &at_warden); + museumgiveback *gb = NULL; + museumgivebackcookie *gbc; + attrib *a; + + /* has the giver a cookie corresponding to the warden */ + for(a = a_find(src->attribs, &at_museumgivebackcookie); a && a->type==&at_museumgivebackcookie; a=a->next) { + if(((museumgivebackcookie *)(a->data.v))->warden_no == u->no) break; + } + + /* if not give it one */ + if (a==NULL || a->type!=&at_museumgivebackcookie) { + a = a_add(&src->attribs, a_new(&at_museumgivebackcookie)); + gbc = (museumgivebackcookie *)a->data.v; + gbc->warden_no = u->no; + gbc->cookie = aw->data.i; + assert(aw->data.i < INT_MAX); + aw->data.i++; + } else { + gbc = (museumgivebackcookie *)(a->data.v); + } + + /* now we search for the warden's corresponding item list */ + for (a = a_find(u->attribs, &at_museumgiveback); a && a->type==&at_museumgiveback; a=a->next) { + gb = (museumgiveback *)a->data.v; + if (gb->cookie == gbc->cookie) { + break; + } + } + + /* if there's none, give it one */ + if (!gb) { + a = a_add(&u->attribs, a_new(&at_museumgiveback)); + gb = (museumgiveback *)a->data.v; + gb->cookie = gbc->cookie; + } + + /* now register the items */ + i_change(&gb->items, itype, n); + + /* done */ + + /* this has a caveat: If the src-unit is destroyed while inside + * the museum, the corresponding itemlist of the warden will never + * be removed. to circumvent that in a generic way will be extremly + * difficult. */ +} + +void +create_museum(void) +{ +#if 0 /* TODO: move this to LUA. It should be possible. */ + unsigned int museum_id = hashstring("museum"); + plane *museum = getplanebyid(museum_id); + region *r; + building *b; + const terrain_type * terrain_hall = get_terrain("hall1"); + const terrain_type * terrain_corridor = get_terrain("corridor1"); + + assert(terrain_corridor && terrain_hall); + + if (!museum) { + museum = create_new_plane(museum_id, "Museum", 9500, 9550, + 9500, 9550, PFL_MUSEUM); + } + + if (findregion(9525, 9525) == NULL) { + /* Eingangshalle */ + r = new_region(9525, 9525, 0); + terraform_region(r, terrain_hall); + r->planep = museum; + rsetname(r, "Eingangshalle"); + rsethorses(r, 0); + rsetmoney(r, 0); + rsetpeasants(r, 0); + set_string(&r->display, "Die Eingangshalle des Großen Museum der 1. Welt ist bereits jetzt ein beeindruckender Anblick. Obwohl das Museum noch nicht eröffnet ist, vermittelt sie bereits einen Flair exotischer Welten. In den Boden ist ein großer Kompass eingelassen, der den Besuchern bei Orientierung helfen soll."); + } + + r = findregion(9526, 9525); + if(!r) { + /* Lounge */ + r = new_region(9526, 9525, 0); + terraform_region(r, terrain_hall); + r->planep = museum; + rsetname(r, "Lounge"); + rsethorses(r, 0); + rsetmoney(r, 0); + rsetpeasants(r, 0); + set_string(&r->display, "Die Lounge des großen Museums ist ein Platz, in dem sich die Besucher treffen, um die Eindrücke, die sie gewonnen haben, zu verarbeiten. Gemütliche Sitzgruppen laden zum Verweilen ein."); + } + + r = findregion(9526, 9525); + if(!r->buildings) { + const building_type * bt_generic = bt_find("generic"); + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im dämonischen Stil"); + set_string(&b->display, "Diese ganz im dämonischen Stil gehaltene Sitzgruppe ist ganz in dunklen Schwarztönen gehalten. Muster fremdartiger Runen bedecken das merkwürdig geformte Mobiliar, das unangenehm lebendig wirkt."); + + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im elfischen Stil"); + set_string(&b->display, "Ganz in Grün- und Brauntönen gehalten wirkt die Sitzgruppe fast lebendig. Bei näherer Betrachtung erschließt sich dem Betrachter, daß sie tatsächlich aus lebenden Pflanzen erstellt ist. So ist der Tisch aus einem eizigen Baum gewachsen, und die Polster bestehen aus weichen Grassoden. Ein wunderschön gemusterter Webteppich mit tausenden naturgetreu eingestickter Blumensarten bedeckt den Boden."); + + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im halblingschen Stil"); + set_string(&b->display, "Dieses rustikale Mobiliar ist aus einem einzigen, gewaltigen Baum hergestellt worden. Den Stamm haben fleißige Halblinge der Länge nach gevierteilt und aus den vier langen Viertelstämmen die Sitzbänke geschnitzt, während der verbleibende Stumpf als Tisch dient. Schon von weitem steigen dem Besucher die Gerüche der Köstlichkeiten entgegen, die auf dem Tisch stapeln."); + + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im orkischen Stil"); + set_string(&b->display, "Grobgeschreinerte, elfenhautbespannte Stühle und ein Tisch aus Knochen, über deren Herkunft man sich lieber keine Gedanken macht, bilden die Sitzgruppe im orkischen Stil. Überall haben Orks ihre Namen, und anderes wenig zitierenswertes in das Holz und Gebein geritzt."); + + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im Meermenschenstil"); + set_string(&b->display, "Ganz in Blau- und Grüntönen gehalten, mit Algen und Muscheln verziert wirken die aus altem Meerholz geschnitzten Stühle immer ein wenig feucht. Seltsammerweise hat der schwere aus alten Planken gezimmerte Tisch einen Mast mit kompletten Segel in der Mitte."); + + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im Katzenstil"); + set_string(&b->display, "Die Wände dieses Séparée sind aus dunklem Holz. Was aus der Ferne wie ein chaotisch durchbrochenes Flechtwerk wirkt, entpuppt sich bei näherer Betrachtung als eine bis in winzige Details gestaltete dschungelartige Landschaft, in die eine Vielzahl von kleinen Bildergeschichten eingewoben sind. Wie es scheint hat sich der Künstler Mühe gegeben wirklich jedes Katzenvolk Eresseas zu porträtieren. Das schummrige Innere wird von einem Kamin dominiert, vor dem einige Sessel und weiche Kissen zu einem gemütlichen Nickerchen einladen. Feiner Anduner Sisal bezieht die Lehnen der Sessel und verlockt dazu, seine Krallen hinein zu versenken. Auf einem kleinen Ecktisch steht ein großer Korb mit roten Wollknäulen und grauen und braunen Spielmäusen."); + } else { + for(b=r->buildings; b; b=b->next) { + b->size = b->type->maxsize; + } + } + + r = findregion(9524, 9526); + if(!r) { + r = new_region(9524, 9526, 0); + terraform_region(r, terrain_corridor); + r->planep = museum; + rsetname(r, "Nördliche Promenade"); + rsethorses(r, 0); + rsetmoney(r, 0); + rsetpeasants(r, 0); + set_string(&r->display, "Die Nördliche Promenade führt direkt in den naturgeschichtlichen Teil des Museums."); + } + r = findregion(9525, 9524); + if(!r) { + r = new_region(9525, 9524, 0); + terraform_region(r, terrain_corridor); + r->planep = museum; + rsetname(r, "Südliche Promenade"); + rsethorses(r, 0); + rsetmoney(r, 0); + rsetpeasants(r, 0); + set_string(&r->display, "Die Südliche Promenade führt den Besucher in den kulturgeschichtlichen Teil des Museums."); + } +#endif +} + +static int +use_museumexitticket(unit *u, const struct item_type *itype, int amount, order * ord) +{ + attrib *a; + region *r; + unit *warden = findunit(atoi36("mwar")); + int unit_cookie; + + unused(amount); + + /* Prüfen ob in Eingangshalle */ + if(u->region->x != 9525 || u->region->y != 9525) { + cmistake(u, ord, 266, MSG_MAGIC); + return 0; + } + + a = a_find(u->attribs, &at_museumexit); assert(a); + r = findregion(a->data.sa[0], a->data.sa[1]); assert(r); + a_remove(&u->attribs, a); + + /* Übergebene Gegenstände zurückgeben */ + + a = a_find(u->attribs, &at_museumgivebackcookie); + unit_cookie = a->data.i; + a_remove(&u->attribs, a); + + if (a) { + for(a = a_find(warden->attribs, &at_museumgiveback); a && a->type==&at_museumgiveback; a = a->next) { + if(((museumgiveback *)(a->data.v))->cookie == unit_cookie) break; + } + if (a && a->type==&at_museumgiveback) { + museumgiveback *gb = (museumgiveback *)(a->data.v); + item *it; + + for (it = gb->items; it; it = it->next) { + i_change(&u->items, it->type, it->number); + } + ADDMSG(&u->faction->msgs, msg_message("museumgiveback", "region unit sender items", r, u, warden, gb->items)); + a_remove(&warden->attribs, a); + } + } + + /* Benutzer zurück teleportieren */ + move_unit(u, r, NULL); + + /* Exitticket abziehen */ + i_change(&u->items, itype, -1); + + return 0; +} + +static int +use_museumticket(unit *u, const struct item_type *itype, int amount, order * ord) +{ + attrib *a; + region *r = u->region; + plane * pl = rplane(r); + + unused(amount); + + /* Prüfen ob in normaler Plane und nur eine Person */ + if (pl != get_homeplane()) { + cmistake(u, ord, 265, MSG_MAGIC); + return 0; + } + if(u->number != 1) { + cmistake(u, ord, 267, MSG_MAGIC); + return 0; + } + if (has_horses(u)) { + cmistake(u, ord, 272, MSG_MAGIC); + return 0; + } + + /* In diesem Attribut merken wir uns, wohin die Einheit zurückgesetzt + * wird, wenn sie das Museum verläßt. */ + + a = a_add(&u->attribs, a_new(&at_museumexit)); + a->data.sa[0] = (short)r->x; + a->data.sa[1] = (short)r->y; + + /* Benutzer in die Halle teleportieren */ + move_unit(u, findregion(9525, 9525), NULL); + + /* Ticket abziehen */ + i_change(&u->items, itype, -1); + + /* Benutzer ein Exitticket geben */ + i_change(&u->items, itype, 1); + + return 0; +} + +void +register_museum(void) +{ + at_register(&at_warden); + at_register(&at_museumexit); + at_register(&at_museumgivebackcookie); + at_register(&at_museumgiveback); + + register_item_use(use_museumticket, "use_museumticket"); + register_item_use(use_museumexitticket, "use_museumexitticket"); +} + +#endif diff --git a/src/modules/museum.h b/src/modules/museum.h new file mode 100644 index 000000000..bcf8457ef --- /dev/null +++ b/src/modules/museum.h @@ -0,0 +1,53 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef HEADER_MUSEUM_H +#define HEADER_MUSEUM_H +#ifdef __cplusplus +extern "C" { +#endif + +#if MUSEUM_MODULE == 0 +#error "must define MUSEUM_MODULE to use this module" +#endif + +extern struct attrib_type at_warden; +extern struct attrib_type at_museumexit; +extern struct attrib_type at_museumgivebackcookie; +extern struct attrib_type at_museumgiveback; + +typedef struct { + int warden_no; + int cookie; +} museumgivebackcookie; + +typedef struct { + int cookie; + struct item *items; +} museumgiveback; + +extern void register_museum(void); +extern void create_museum(void); +extern void warden_add_give(struct unit *src, struct unit *u, const struct item_type *itype, int n); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/src/modules/oceannames.c b/src/modules/oceannames.c new file mode 100644 index 000000000..b52eddec3 --- /dev/null +++ b/src/modules/oceannames.c @@ -0,0 +1,126 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "oceannames.h" + +/* kernel includes */ +#include +#include + +/* util includes */ +#include + +/* libc includes */ +#include +#include + +typedef struct namehash { + struct namehash * next; + const char * name; +} namehash; + +#define NMAXHASH 1023 +namehash names[NMAXHASH]; + +void nhash(const char * name); + +typedef struct oceanname { + struct oceanname * next; + struct faction_list * factions; + const char * name; +} oceanname; + +static void +free_names(attrib * a) +{ + oceanname * data = (oceanname*)a->data.v; + while (a->data.v) { + a->data.v = data->next; + free(data); + } +} + +struct attrib_type at_oceanname = { "names", NULL, free_names, NULL/*, write_names, read_names, ATF_UNIQUE */}; + +const char * +get_oceanname(const struct region * r, const struct faction * f) +{ + attrib * a = a_find(r->attribs, &at_oceanname); + if (a) { + oceanname * names = (oceanname*)a->data.v; + while (names) { + faction_list * fl = names->factions; + while (fl) { + if (fl->data==f) return names->name; + fl=fl->next; + } + names = names->next; + } + } + return NULL; +} + +void +nameocean(struct region *r, struct faction * f, const char * newname) +{ + attrib * a = a_find(r->attribs, &at_oceanname); + if (!a && newname) a = a_add(&r->attribs, a_new(&at_oceanname)); + if (a) { + faction_list **oldf = NULL, **newf = NULL; + faction_list * fl = NULL; + oceanname * names = (oceanname*)a->data.v; + while ((names && (!newf && newname)) || !oldf) { + faction_list ** fli = &names->factions; + if (oldf==NULL) while (*fli) { + if ((*fli)->data==f) { + oldf = fli; + break; + } + fli=&(*fli)->next; + } + if (newname && !newf && !strcmp(names->name, newname)) { + newf = fli; + } + names = names->next; + } + + if (oldf) { + fl = *oldf; + *oldf = fl->next; + } else if (newname) { + fl = calloc(1, sizeof(faction_list)); + } + + if (newf) { + fl->data = f; + fl->next = *newf; + *newf = fl; + } else if (newname) { + oceanname * nm = calloc(1, sizeof(oceanname)); + nm->factions = fl; + fl->data = f; + fl->next = NULL; + nm->next = (oceanname*)a->data.v; + a->data.v = nm; + } else if (fl) { + free(fl); + } + } +} diff --git a/src/modules/oceannames.h b/src/modules/oceannames.h new file mode 100644 index 000000000..ed5e4b5cc --- /dev/null +++ b/src/modules/oceannames.h @@ -0,0 +1,32 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_MOD_OCEANNAMES +#define H_MOD_OCEANNAMES +#ifdef __cplusplus +extern "C" { +#endif + +struct faction; +struct region; +extern const char * get_oceanname(const struct region * r, const struct faction * f); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/score.c b/src/modules/score.c new file mode 100644 index 000000000..46b61f418 --- /dev/null +++ b/src/modules/score.c @@ -0,0 +1,212 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#if SCORE_MODULE +#include "score.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include + +/* libc includes */ +#include + +int +average_score_of_age(int age, int a) +{ + faction *f; + int sum = 0, count = 0; + + for (f = factions; f; f = f->next) { + if (!is_monsters(f) && f->race != new_race[RC_TEMPLATE] && f->age <= age + a && f->age >= age - a) { + sum += f->score; + count++; + } + } + + if (count == 0) { + return 0; + } + return sum / count; +} + +void +score(void) +{ + FILE *scoreFP; + region *r; + faction *fc; + int allscores = 0; + char path[MAX_PATH]; + + for (fc = factions; fc; fc = fc->next) fc->score = 0; + + for (r = regions; r; r = r->next) { + unit * u; + building * b; + ship * s; + + if (rule_region_owners()) { + fc = region_get_owner(r); + if (fc) fc->score += 10; + } + + for (b = r->buildings; b; b = b->next) { + u = building_owner(b); + if (u!=NULL) { + faction * fbo = u->faction; + + if (fbo) { + fbo->score += b->size * 5; + } + } + } + + for (s = r->ships; s; s = s->next) { + unit * cap = shipowner(s); + if (cap && cap->faction) { + cap->faction->score += s->size * 2; + } + } + + for (u = r->units; u; u = u->next) { + item * itm; + int itemscore = 0; + int i; + faction * f = u->faction; + + if (f==NULL || u->race == new_race[RC_SPELL] || u->race == new_race[RC_BIRTHDAYDRAGON]) { + continue; + } + + if (old_race(u->race) <= RC_AQUARIAN) { + f->score += (u->race->recruitcost * u->number) / 50; + } + f->score += get_money(u) / 50; + for (itm=u->items; itm; itm=itm->next) { + itemscore += itm->number * itm->type->score; + } + f->score += itemscore / 10; + + for (i=0;i!=u->skill_size;++i) { + skill * sv = u->skills+i; + switch (sv->id) { + case SK_MAGIC: + f->score += (int)(u->number * pow(sv->level, 4)); + break; + case SK_TACTICS: + f->score += (int)(u->number * pow(sv->level, 3)); + break; + case SK_SPY: + case SK_ALCHEMY: + case SK_HERBALISM: + f->score += (int)(u->number * pow(sv->level, 2.5)); + break; + default: + f->score += (int)(u->number * pow(sv->level, 2.5) / 10); + break; + } + } + } + } + + for (fc = factions; fc; fc = fc->next) { + fc->score = fc->score / 5; + if (!is_monsters(fc) && fc->race != new_race[RC_TEMPLATE]) { + allscores += fc->score; + } + } + if (allscores == 0) { + allscores = 1; + } + + sprintf(path, "%s/score", basepath()); + scoreFP = fopen(path, "w"); + if (scoreFP) { + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + faction * f; + fwrite(utf8_bom, 1, 3, scoreFP); + for (f = factions; f; f = f->next) if (f->num_total != 0) { + fprintf(scoreFP, "%8d (%8d/%4.2f%%/%5.2f) %30.30s (%3.3s) %5s (%3d)\n", + f->score, f->score - average_score_of_age(f->age, f->age / 24 + 1), + ((float) f->score / (float) allscores) * 100.0, + (float) f->score / f->num_total, + f->name, LOC(default_locale, rc_name(f->race, 0)), factionid(f), f->age); + } + fclose(scoreFP); + } + if (alliances!=NULL) { + alliance *a; + const item_type * token = it_find("conquesttoken"); + + sprintf(path, "%s/score.alliances", basepath()); + scoreFP = fopen(path, "w"); + if (scoreFP) { + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + fwrite(utf8_bom, 1, 3, scoreFP); + + fprintf(scoreFP, "# alliance:factions:persons:score\n"); + + for (a = alliances; a; a = a->next) { + int alliance_score = 0, alliance_number = 0, alliance_factions = 0; + int grails = 0; + faction * f; + + for (f = factions; f; f = f->next) { + if (f->alliance && f->alliance == a) { + alliance_factions++; + alliance_score += f->score; + alliance_number += f->num_total; + if (token!=NULL) { + unit * u = f->units; + while (u!=NULL) { + item ** iitem = i_find(&u->items, token); + if (iitem!=NULL && *iitem!=NULL) { + grails += (*iitem)->number; + } + u=u->nextF; + } + } + } + } + + fprintf(scoreFP, "%d:%d:%d:%d", a->id, alliance_factions, alliance_number, alliance_score); + if (token!=NULL) fprintf(scoreFP, ":%d", grails); + fputc('\n', scoreFP); + } + fclose(scoreFP); + } + } +} + +#endif diff --git a/src/modules/score.h b/src/modules/score.h new file mode 100644 index 000000000..335afc23d --- /dev/null +++ b/src/modules/score.h @@ -0,0 +1,36 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef SCORE_H +#define SCORE_H +#ifdef __cplusplus +extern "C" { +#endif + +#if SCORE_MODULE == 0 +#error "must define SCORE_MODULE to use this module" +#endif + + +extern void score(void); +extern int average_score_of_age(int age, int a); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/weather.c b/src/modules/weather.c new file mode 100644 index 000000000..03b5b035c --- /dev/null +++ b/src/modules/weather.c @@ -0,0 +1,141 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifdef WEATHER + +#include +#include +#include "weather.h" + +/* libc includes */ +#include + +weather * +create_weather(region *r, weather_t type) + +{ + weather *w; + + w = calloc(1, sizeof(weather)); + w->center[0] = r->x; + w->center[1] = r->y; + w->type = type; + w->move[0] = (rng_int()%3) - 1; + w->move[1] = (rng_int()%3) - 1; + + switch(type) { + case WEATHER_STORM: + w->radius = rng_int()%2+1; + break; + case WEATHER_HURRICANE: + w->radius = 1; + break; + default: + w->radius = 0; + } + + addlist(&weathers, w); + + return w; +} + +double +distance(int x1, int y1, int x2, int y2) + +{ + return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); +} + +/* Diese Funktion ermittelt für jede Region, welches Wetter in ihr + herrscht. Die Wettertypen sind dabei nach ihrer Reihenfolge in der + enumeration priorisiert. + + - Einladen + set_weather(); + - Eigentliche Auswertung + - Veränderungen des Wetters + set_weather(); + - Report generieren + - Abspeichern + + Diese Routine ist sehr rechenaufwendig! +*/ + +void +set_weather(void) + +{ + weather_t i; + weather *w; + short x, y; + int d; + region *r; + + for(r=regions;r;r=r->next) { + r->weathertype = WEATHER_NONE; + } + + for(i = 0; i < MAXWEATHERS; i++) { + for(w = weathers; w; w = w->next) { + if(w->type == i) { + for(x=w->center[0]-w->radius; x<=w->center[0]+w->radius; x++) { + for(y=w->center[1]-w->radius; y<=w->center[1]+w->radius; y++) { + d = distance(w->center[0], w->center[1], x, y); + if(floor(d+0.5) <= w->radius) { + r = findregion(x,y); + if(r) { + r->weathertype = w->type; + } + } + } + } + } + } + } +} + +void +move_weather(void) + +{ + weather *w, *wnext; + region *r; + + for(w = weathers; w;) { + wnext = w->next; + w->center[0] = w->center[0] + w->move[0]; + w->center[1] = w->center[1] + w->move[1]; + r = findregion(w->center[0], w->center[1]); + if(!r || rng_int()%100 < 5) { + removelist(&weathers, w); + } + w = wnext; + } +} + +#else +#include +static const char* copyright = "(c) Eressea PBEM 2000"; + +void +init_weather(void) +{ + fputs(copyright, stderr); + /* TODO: Initialization */ +} +#endif diff --git a/src/modules/weather.h b/src/modules/weather.h new file mode 100644 index 000000000..6ec87dd14 --- /dev/null +++ b/src/modules/weather.h @@ -0,0 +1,54 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_MOD_WEATHER_H +#define H_MOD_WEATHER_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WEATHER +# error "the weather system is disabled" +#endif + +enum { + WEATHER_NONE, + WEATHER_STORM, + WEATHER_HURRICANE, + MAXWEATHERS +}; + +typedef unsigned char weather_t; + +typedef struct weather { + struct weather *next; + weather_t type; /* Typ der Wetterzone */ + int center[2]; /* Koordinaten des Zentrums */ + int radius; + int move[2]; +} weather; + +weather *weathers; + +void set_weather(void); +void move_weather(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/wormhole.c b/src/modules/wormhole.c new file mode 100644 index 000000000..1ad7c93bf --- /dev/null +++ b/src/modules/wormhole.c @@ -0,0 +1,221 @@ +/* vi: set ts=2: + +-------------------+ + | | Christian Schlittchen + | Eressea PBEM host | Enno Rehling + | (c) 1998 - 2004 | Katja Zedel + | | + +-------------------+ + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "settings.h" + +#include "wormhole.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include + +/* libc includes */ +#include +#include + +static boolean +good_region(const region * r) +{ + return (!fval(r, RF_CHAOTIC) && r->age>30 && rplane(r)==NULL && r->units!=NULL && r->land!=NULL); +} + +static int +cmp_age(const void * v1, const void *v2) +{ + const region * r1 = (const region*)v1; + const region * r2 = (const region*)v2; + if (r1->ageage) return -1; + if (r1->age>r2->age) return 1; + return 0; +} + +typedef struct wormhole_data { + building * entry; + region * exit; +} wormhole_data; + +static void +wormhole_init(struct attrib *a) +{ + a->data.v = calloc(1, sizeof(wormhole_data)); +} + +static void +wormhole_done(struct attrib * a) +{ + free(a->data.v); +} + +static int +wormhole_age(struct attrib * a) +{ + wormhole_data * data = (wormhole_data*)a->data.v; + int maxtransport = data->entry->size; + region * r = data->entry->region; + unit * u = r->units; + + for (;u!=NULL && maxtransport!=0;u=u->next) { + if (u->building==data->entry) { + message * m = NULL; + if (u->number>maxtransport || has_limited_skills(u)) { + m = msg_message("wormhole_requirements", "unit region", u, u->region); + } else if (data->exit!=NULL) { + move_unit(u, data->exit, NULL); + maxtransport -= u->number; + m = msg_message("wormhole_exit", "unit region", u, data->exit); + add_message(&data->exit->msgs, m); + } + if (m!=NULL) { + add_message(&u->faction->msgs, m); + msg_release(m); + } + } + } + + remove_building(&r->buildings, data->entry); + ADDMSG(&r->msgs, msg_message("wormhole_dissolve", "region", r)); + + /* age returns 0 if the attribute needs to be removed, !=0 otherwise */ + return AT_AGE_KEEP; +} + +static void +wormhole_write(const struct attrib * a, const void * owner, struct storage * store) +{ + wormhole_data * data = (wormhole_data*)a->data.v; + write_building_reference(data->entry, store); + write_region_reference(data->exit, store); +} + +/** conversion code, turn 573, 2008-05-23 */ +static int +resolve_exit(variant id, void * address) +{ + building * b = findbuilding(id.i); + region ** rp = address; + if (b) { + *rp = b->region; + return 0; + } + *rp = NULL; + return -1; +} + +static int +wormhole_read(struct attrib * a, void * owner, struct storage * store) +{ + wormhole_data * data = (wormhole_data*)a->data.v; + resolve_fun resolver = (store->versionversionentry, store, read_building_reference, resolve_building); + int rr = read_reference(&data->exit, store, reader, resolver); + if (rb==0 && rr==0) { + if (!data->exit || !data->entry) { + return AT_READ_FAIL; + } + } + return AT_READ_OK; +} + +static attrib_type at_wormhole = { + "wormhole", + wormhole_init, + wormhole_done, + wormhole_age, + wormhole_write, + wormhole_read, + ATF_UNIQUE +}; + +static void +make_wormhole(const building_type * bt_wormhole, region * r1, region * r2) +{ + building * b1 = new_building(bt_wormhole, r1, default_locale); + building * b2 = new_building(bt_wormhole, r2, default_locale); + attrib * a1 = a_add(&b1->attribs, a_new(&at_wormhole)); + attrib * a2 = a_add(&b2->attribs, a_new(&at_wormhole)); + wormhole_data * d1 = (wormhole_data*)a1->data.v; + wormhole_data * d2 = (wormhole_data*)a2->data.v; + d1->entry = b1; + d2->entry = b2; + d1->exit = b2->region; + d2->exit = b1->region; + b1->size = bt_wormhole->maxsize; + b2->size = bt_wormhole->maxsize; + ADDMSG(&r1->msgs, msg_message("wormhole_appear", "region", r1)); + ADDMSG(&r2->msgs, msg_message("wormhole_appear", "region", r2)); +} + +void +create_wormholes(void) +{ +#define WORMHOLE_CHANCE 10000 + const building_type * bt_wormhole = bt_find("wormhole"); + region_list *rptr, * rlist = NULL; + region * r = regions; + int i = 0, count = 0; + region ** match; + + if (bt_wormhole==NULL) return; + /* + * select a list of regions. we'll sort them by age later. + */ + while (r!=NULL) { + int next = rng_int() % (2*WORMHOLE_CHANCE); + while (r!=NULL && (next!=0 || !good_region(r))) { + if (good_region(r)) { + --next; + } + r=r->next; + } + if (r==NULL) break; + add_regionlist(&rlist, r); + ++count; + r=r->next; + } + + if (count<2) return; + + match = (region**)malloc(sizeof(region*) * count); + rptr = rlist; + while (i!=count) { + match[i++] = rptr->data; + rptr = rptr->next; + } + qsort(match, count, sizeof(region *), cmp_age); + free_regionlist(rlist); + + count /= 2; + for (i=0;i!=count;++i) { + make_wormhole(bt_wormhole, match[i], match[i+count]); + } +} + +void +register_wormholes(void) +{ + at_register(&at_wormhole); +} diff --git a/src/modules/wormhole.h b/src/modules/wormhole.h new file mode 100644 index 000000000..dea7a6aab --- /dev/null +++ b/src/modules/wormhole.h @@ -0,0 +1,31 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_MOD_WORMHOLE +#define H_MOD_WORMHOLE +#ifdef __cplusplus +extern "C" { +#endif + + extern void create_wormholes(void); + extern void register_wormholes(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/xecmd.c b/src/modules/xecmd.c new file mode 100644 index 000000000..b181766b2 --- /dev/null +++ b/src/modules/xecmd.c @@ -0,0 +1,111 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include + +#if XECMD_MODULE +#include "xecmd.h" + +#include + +#include "xecmd.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +static void +xe_givelaen(unit *u, struct order * ord) +{ + unit *u2 =getunitg(u->region, u->faction); + + if(!u2) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + i_change(&u2->items, olditemtype[I_LAEN], 5); +} + +static void +xe_givepotion(unit *u, struct order *ord) +{ + unit *u2 =getunitg(u->region, u->faction); + + if(!u2) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + i_change(&u2->items, it_find("skillpotion"), 1); +} + +static void +xe_giveballon(unit *u, struct order *ord) +{ + unit *u2 = getunitg(u->region, u->faction); + ship *sh; + + if (!u2) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + + sh = new_ship(st_find("balloon"), u2->faction->locale, u2->region); + sh->size = 5; + ship_setname(sh, "Xontormia-Ballon"); + leave(u2, false); + u2->ship = sh; + fset(u2, UFL_OWNER); +} + +int +xecmd(unit * u, order * ord) +{ + faction *f = u->faction; + + if (a_find(f->attribs, &at_xontormiaexpress)) { + if (get_keyword(ord) == K_XE) { + init_tokens(ord); + skip_token(); + switch(findparam(getstrtoken(),f->locale)) { + case P_XEPOTION: + xe_givepotion(u, ord); + break; + case P_XEBALLOON: + xe_giveballon(u, ord); + break; + case P_XELAEN: + xe_givelaen(u, ord); + break; + } + } + } + return 0; +} + +#endif diff --git a/src/modules/xecmd.h b/src/modules/xecmd.h new file mode 100644 index 000000000..a964d38da --- /dev/null +++ b/src/modules/xecmd.h @@ -0,0 +1,27 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_MOD_XECMD_H +#define H_MOD_XECMD_H +#ifdef __cplusplus +extern "C" { +#endif + +#if XECMD_MODULE +int xecmd(struct unit * u, struct order * ord); +#endif + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/modules/xmas.c b/src/modules/xmas.c new file mode 100644 index 000000000..01f0b4297 --- /dev/null +++ b/src/modules/xmas.c @@ -0,0 +1,82 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "xmas.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include + +static int +xmasgate_handle(trigger * t, void * data) +{ + return -1; +} + +static void +xmasgate_write(const trigger * t, struct storage * store) +{ + building *b = (building *)t->data.v; + store->w_tok(store, itoa36(b->no)); +} + +static int +xmasgate_read(trigger * t, struct storage * store) +{ + int bc = read_reference(&t->data.v, store, read_building_reference, resolve_building); + if (bc==0 && !t->data.v) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +struct trigger_type tt_xmasgate = { + "xmasgate", + NULL, + NULL, + xmasgate_handle, + xmasgate_write, + xmasgate_read +}; + +trigger * +trigger_xmasgate(building * b) +{ + trigger * t = t_new(&tt_xmasgate); + t->data.v = b; + return t; +} + +void +register_xmas(void) +{ + tt_register(&tt_xmasgate); +} + diff --git a/src/modules/xmas.h b/src/modules/xmas.h new file mode 100644 index 000000000..334ab8b38 --- /dev/null +++ b/src/modules/xmas.h @@ -0,0 +1,29 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_MOD_XMAS +#define H_MOD_XMAS +#ifdef __cplusplus +extern "C" { +#endif + +struct region; +struct unit; + +extern struct trigger *trigger_xmasgate(struct building * b); + +extern void register_xmas(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/platform.h b/src/platform.h new file mode 100644 index 000000000..721006b7b --- /dev/null +++ b/src/platform.h @@ -0,0 +1,282 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CONFIG_H +#define CONFIG_H + +#ifdef _MSC_VER +# define VC_EXTRALEAN +# define WIN32_LEAN_AND_MEAN +# include +# undef MOUSE_MOVED +# define STDIO_CP 1252 /* log.c, convert to console character set */ +# pragma warning (disable: 4201 4214 4514 4115 4711) +# pragma warning(disable: 4056) +/* warning C4056: overflow in floating point constant arithmetic */ +# pragma warning(disable: 4201) +/* warning C4201: nonstandard extension used : nameless struct/union */ +# pragma warning(disable: 4214) +/* warning C4214: nonstandard extension used : bit field types other than int */ +# pragma warning(disable: 4100) +/* warning C4100: : unreferenced formal parameter */ +# pragma warning(disable: 4996) + +/* warning C4100: was declared deprecated */ +#ifndef _CRT_SECURE_NO_DEPRECATE +# define _CRT_SECURE_NO_DEPRECATE +#endif + +/* http://msdn2.microsoft.com/en-us/library/ms235505(VS.80).aspx */ +#ifndef _CRT_DISABLE_PERFCRIT_LOCKS +# define _CRT_DISABLE_PERFCRIT_LOCKS +#endif + +#endif /* _MSC_VER_ */ + + +#ifdef __cplusplus +# include +# include +extern "C" { +#else +# include +# include +#endif + +/**** **** + ** Debugging Libraries ** + **** ****/ +#if defined __GNUC__ +# define HAVE_INLINE +# define INLINE_FUNCTION static __inline +#endif + +/* define USE_DMALLOC to enable use of the dmalloc library */ +#ifdef USE_DMALLOC +# include +# include +# include +#endif + +/* define CRTDBG to enable MSVC CRT Debug library functions */ +#if defined(_DEBUG) && defined(_MSC_VER) && defined(CRTDBG) +# include +# define _CRTDBG_MAP_ALLOC +#endif + +/**** **** + ** Architecture Dependent ** + **** ****/ + +/* für solaris: */ +#ifdef SOLARIS +# define _SYS_PROCSET_H +# define _XOPEN_SOURCE +#endif + +#ifdef __GNUC__ +# ifndef _BSD_SOURCE +# define _BSD_SOURCE +# define __USE_BSD +# endif +/* # include */ +# include /* strncasecmp-Prototyp */ +#endif + +#ifdef _BSD_SOURCE +# define __EXTENSIONS__ +#endif + +#ifdef WIN32 +# define HAVE__MKDIR_WITHOUT_PERMISSION +# define HAVE__SLEEP_MSEC +#endif + +#if defined(__USE_SVID) || defined(_BSD_SOURCE) || defined(__USE_XOPEN_EXTENDED) || defined(_BE_SETUP_H) || defined(CYGWIN) +# include +# define HAVE_UNISTD_H +# define HAVE_STRCASECMP +# define HAVE_STRNCASECMP +# define HAVE_ACCESS +# define HAVE_STAT +typedef struct stat stat_type; +# include +# define HAVE_STRDUP +# define HAVE_SNPRINTF +#ifdef _POSIX_SOURCE /* MINGW doesn't seem to have these */ +# define HAVE_EXECINFO +# define HAVE_MKDIR_WITH_PERMISSION +# define HAVE_SIGACTION +# define HAVE_LINK +# define HAVE_SLEEP +#endif +#endif + +/* egcpp 4 dos */ +#ifdef MSDOS +# include +# define HAVE_MKDIR_WITH_PERMISSION +#endif + +/* lcc-win32 */ +#ifdef __LCC__ +# include +# include +# include +# define HAVE_ACCESS +# define HAVE_STAT +typedef struct stat stat_type; +# define HAVE_STRICMP +# define HAVE_STRNICMP +# define HAVE_STRDUP +# define HAVE_SLEEP +# define snprintf _snprintf +# define HAVE_SNPRINTF +# undef HAVE_STRCASECMP +# undef HAVE_STRNCASECMP +# define R_OK 4 +#endif + +/* Microsoft Visual C */ +#ifdef _MSC_VER +# include /* must be included here so strdup is not redefined */ +# define R_OK 4 +# define HAVE_INLINE +# define INLINE_FUNCTION __inline + +# define snprintf _snprintf +# define HAVE_SNPRINTF + +/* MSVC has _access, not access */ +#ifndef access +# define access(f, m) _access(f, m) +#endif +#define HAVE_ACCESS + +/* MSVC has _stat, not stat */ +# define HAVE_STAT +#include +# define stat(a, b) _stat(a, b) +typedef struct _stat stat_type; + +/* MSVC has _strdup */ +# define strdup _strdup +# define HAVE_STRDUP + +# define stricmp(a, b) _stricmp(a, b) +# define HAVE_STRICMP + +# define strnicmp(a, b, c) _strnicmp(a, b, c) +# define HAVE_STRNICMP +# undef HAVE_STRCASECMP +# undef HAVE_STRNCASECMP +#endif + +/* replacements for missing functions: */ + +#ifndef HAVE_STRCASECMP +# if defined(HAVE_STRICMP) +# define strcasecmp stricmp +# elif defined(HAVE__STRICMP) +# define strcasecmp _stricmp +# endif +#endif + +#ifndef HAVE_STRNCASECMP +# if defined(HAVE_STRNICMP) +# define strncasecmp strnicmp +# elif defined(HAVE__STRNICMP) +# define strncasecmp _strnicmp +# endif +#endif + +#ifdef HAVE_MKDIR_WITH_PERMISSION +# define makedir(d, p) mkdir(d, p) +#elif defined(HAVE_MKDIR_WITHOUT_PERMISSION) +# define makedir(d, p) mkdir(d) +#elif defined(HAVE__MKDIR_WITHOUT_PERMISSION) +_CRTIMP int __cdecl _mkdir(const char *); +# define makedir(d, p) _mkdir(d) +#endif + +#ifndef HAVE_STRDUP +extern char * strdup(const char *s); +#endif + +#ifndef HAVE_SLEEP +#ifdef HAVE__SLEEP_MSEC +# define sleep(sec) _sleep(1000*sec) +#elif defined(HAVE__SLEEP) +# define sleep(sec) _sleep(sec) +#endif +#endif + +#if !defined(MAX_PATH) +# if defined(PATH_MAX) +# define MAX_PATH PATH_MAX +# else +# define MAX_PATH 1024 +# endif +#endif + +/**** **** + ** min/max macros ** + **** ****/ +#ifndef NOMINMAX +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef MAX +# define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif +#endif + +#if defined (__GNUC__) +# define unused(a) /* unused: a */ +#elif defined (ghs) || defined (__hpux) || defined (__sgi) || defined (__DECCXX) || defined (__KCC) || defined (__rational__) || defined (__USLC__) || defined (ACE_RM544) +# define unused(a) do {/* null */} while (&a == 0) +#else /* ghs || __GNUC__ || ..... */ +# define unused(a) (a) +#endif /* ghs || __GNUC__ || ..... */ + +/**** **** + ** The Eressea boolean type ** + **** ****/ +#if defined(BOOLEAN) +# define boolean BOOLEAN +#else + typedef int boolean; /* not bool! wrong size. */ +#endif +#ifndef __cplusplus +# define false ((boolean)0) +# define true ((boolean)!false) +#endif +#ifdef __cplusplus +} +#endif + +#ifndef INLINE_FUNCTION +# define INLINE_FUNCTION +#endif + +#define iswxspace(c) (c==160 || iswspace(c)) +#define isxspace(c) (c==160 || isspace(c)) + +#define TOLUA_CAST (char*) +#endif + diff --git a/src/settings.h b/src/settings.h new file mode 100644 index 000000000..c866d648e --- /dev/null +++ b/src/settings.h @@ -0,0 +1,63 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +/* + * Contains defines for the "free" game (Eressea) . + * Include this file from settings.h to make eressea work. + */ +#define ENTERTAINFRACTION 20 +#define TEACHDIFFERENCE 2 +#define GUARD_DISABLES_RECRUIT 1 +#define GUARD_DISABLES_PRODUCTION 1 +#define RESOURCE_QUANTITY 0.5 +#define RECRUITFRACTION 40 /* 100/RECRUITFRACTION% */ +#define COMBAT_TURNS 5 +#define NEWATSROI 0 + +/* Vermehrungsrate Bauern in 1/10000. +* Evt. Berechnungsfehler, reale Vermehrungsraten scheinen höher. */ +#define PEASANTGROWTH 10 +#define BATTLE_KILLS_PEASANTS 20 +#define PEASANTLUCK 10 + +#define HUNGER_REDUCES_SKILL /* Hunger reduziert den Talentwert + auf die Hälfte */ + +#define ASTRAL_ITEM_RESTRICTIONS /* keine grossen dinge im astralraum */ +#define NEW_DAEMONHUNGER_RULE +#define NEW_COMBATSKILLS_RULE +#define ROW_FACTOR 3 /* factor for combat row advancement rule */ + +/* optional game components. TODO: These should either be + * configuration variables (XML), script extensions (lua), + * or both. We don't want separate binaries for different games + */ +#define SCORE_MODULE 1 +#define MUSEUM_MODULE 1 +#define ARENA_MODULE 1 +#define XECMD_MODULE 1 +#define DUNGEON_MODULE 0 +#define CHANGED_CROSSBOWS 0 /* use the WTF_ARMORPIERCING flag */ +#undef GLOBAL_WARMING /* number of turns before global warming sets in */ + +#define SIMPLE_COMBAT +#define SIMPLE_ESCAPE + +#if defined(BINDINGS_LUABIND) +# undef BINDINGS_TOLUA +#elif defined(BINDINGS_TOLUA) +# undef BINDINGS_LUABIND +#else +# define BINDINGS_TOLUA /* new default */ +#endif + +#undef REGIONOWNERS /* (WIP) region-owner uses HELP_TRAVEL to control entry to region */ diff --git a/src/stdafx.h b/src/stdafx.h new file mode 100644 index 000000000..f6db3cac1 --- /dev/null +++ b/src/stdafx.h @@ -0,0 +1 @@ +/* empty, only used in non-msvc builds */ diff --git a/src/tests.c b/src/tests.c new file mode 100644 index 000000000..27f28b791 --- /dev/null +++ b/src/tests.c @@ -0,0 +1,127 @@ +#include +#include + +#include +#include "tests.h" + +CuSuite* get_base36_suite(void); +CuSuite* get_curse_suite(void); +CuSuite* get_market_suite(void); +CuSuite* get_laws_suite(void); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int RunAllTests(void) { + CuString *output = CuStringNew(); + CuSuite* suite = CuSuiteNew(); + + init_resources(); + + CuSuiteAddSuite(suite, get_base36_suite()); + CuSuiteAddSuite(suite, get_curse_suite()); + CuSuiteAddSuite(suite, get_market_suite()); + CuSuiteAddSuite(suite, get_laws_suite()); + + CuSuiteRun(suite); + CuSuiteSummary(suite, output); + CuSuiteDetails(suite, output); + printf("%s\n", output->buffer); + return suite->failCount; +} + +struct race * test_create_race(const char * name) +{ + race * rc = rc_add(rc_new("human")); + return rc; +} + +struct region * test_create_region(int x, int y, const struct terrain_type * terrain) +{ + region * r = new_region(x, y, NULL, 0); + terraform_region(r, terrain); + rsettrees(r, 0, 0); + rsettrees(r, 1, 0); + rsettrees(r, 2, 0); + rsethorses(r, 0); + rsetpeasants(r, terrain->size); + return r; +} + +struct faction * test_create_faction(const struct race * rc) +{ + faction * f = addfaction("nobody@eressea.de", NULL, rc, default_locale, 0); + return f; +} + +struct unit * test_create_unit(struct faction * f, struct region * r) +{ + unit * u = create_unit(r, f, 1, f->race, 0, 0, 0); + return u; +} + +void test_cleanup(void) { + global.functions.maintenance = NULL; + global.functions.wage = NULL; + free_gamedata(); +} + +/** creates a small world and some stuff in it. + * two terrains: 'plain' and 'ocean' + * one race: 'human' + * one ship_type: 'boat' + * one building_type: 'castle' + * in 0.0 and 1.0 is an island of two plains, around it is ocean. + */ +void test_create_world(void) +{ + terrain_type * t_plain, * t_ocean; + region * island[2]; + race * rc_human; + int i; + building_type * btype; + ship_type * stype; + + t_plain = calloc(1, sizeof(terrain_type)); + t_plain->_name = strdup("plain"); + t_plain->flags = LAND_REGION|FOREST_REGION|WALK_INTO; + register_terrain(t_plain); + + t_ocean = calloc(1, sizeof(terrain_type)); + t_ocean->_name = strdup("ocean"); + t_ocean->flags = SEA_REGION|SAIL_INTO|SWIM_INTO; + register_terrain(t_ocean); + + island[0] = test_create_region(0, 0, t_plain); + island[1] = test_create_region(1, 0, t_plain); + for (i=0;i!=2;++i) { + direction_t j; + region * r = island[i]; + for (j=0;j!=MAXDIRECTIONS;++j) { + region * rn = r_connect(r, j); + if (!rn) { + rn = test_create_region(r->x+delta_x[j], r->y+delta_y[j], t_ocean); + } + } + } + + rc_human = rc_add(rc_new("human")); + rc_human->maintenance = 10; + + btype = calloc(sizeof(building_type), 1); + btype->_name = strdup("castle"); + bt_register(btype); + + stype = calloc(sizeof(ship_type), 1); + stype->name[0] = strdup("boat"); + stype->name[1] = strdup("boat_p"); + st_register(stype); + +} diff --git a/src/tests.h b/src/tests.h new file mode 100644 index 000000000..1bf6a1304 --- /dev/null +++ b/src/tests.h @@ -0,0 +1,21 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DISABLE_TESTS +void test_cleanup(void); + +struct race * test_create_race(const char * name); +struct region * test_create_region(int x, int y, const struct terrain_type * terrain); +struct faction * test_create_faction(const struct race * rc); +struct unit * test_create_unit(struct faction * f, struct region * r); +void test_create_world(void); + +int RunAllTests(void); +#else +#define RunAllTests() 0 +#endif + +#ifdef __cplusplus +} +#endif diff --git a/src/triggers/changefaction.c b/src/triggers/changefaction.c new file mode 100644 index 000000000..e704dd241 --- /dev/null +++ b/src/triggers/changefaction.c @@ -0,0 +1,114 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "changefaction.h" + +/* kernel includes */ +#include +#include +#include /* FIXME: resolve_faction */ + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* ansi includes */ +#include +#include +#include + + +#include +/*** + ** restore a mage that was turned into a toad + **/ + +typedef struct changefaction_data { + struct unit * unit; + struct faction * faction; +} changefaction_data; + +static void +changefaction_init(trigger * t) +{ + t->data.v = calloc(sizeof(changefaction_data), 1); +} + +static void +changefaction_free(trigger * t) +{ + free(t->data.v); +} + +static int +changefaction_handle(trigger * t, void * data) +{ + /* call an event handler on changefaction. + * data.v -> ( variant event, int timer ) + */ + changefaction_data * td = (changefaction_data*)t->data.v; + if (td->unit && td->faction) { + u_setfaction(td->unit, td->faction); + } else { + log_error(("could not perform changefaction::handle()\n")); + } + unused(data); + return 0; +} + +static void +changefaction_write(const trigger * t, struct storage * store) +{ + changefaction_data * td = (changefaction_data*)t->data.v; + write_unit_reference(td->unit, store); + write_faction_reference(td->faction, store); +} + +static int +changefaction_read(trigger * t, struct storage * store) +{ + changefaction_data * td = (changefaction_data*)t->data.v; + read_reference(&td->unit, store, read_unit_reference, resolve_unit); + read_reference(&td->faction, store, read_faction_reference, resolve_faction); + return AT_READ_OK; +} + +trigger_type tt_changefaction = { + "changefaction", + changefaction_init, + changefaction_free, + changefaction_handle, + changefaction_write, + changefaction_read +}; + +trigger * +trigger_changefaction(unit * u, struct faction * f) +{ + trigger * t = t_new(&tt_changefaction); + changefaction_data * td = (changefaction_data*)t->data.v; + td->unit = u; + td->faction = f; + return t; +} diff --git a/src/triggers/changefaction.h b/src/triggers/changefaction.h new file mode 100644 index 000000000..dd2a302c5 --- /dev/null +++ b/src/triggers/changefaction.h @@ -0,0 +1,39 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CHANGEFACTION_H +#define CHANGEFACTION_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; + +struct unit; +struct faction; + +extern struct trigger_type tt_changefaction; + +extern struct trigger * trigger_changefaction(struct unit * u, struct faction * f); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/changerace.c b/src/triggers/changerace.c new file mode 100644 index 000000000..db5904d23 --- /dev/null +++ b/src/triggers/changerace.c @@ -0,0 +1,120 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "changerace.h" + +/* kernel includes */ +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* ansi includes */ +#include +#include +#include + + +#include +/*** + ** 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(sizeof(changerace_data), 1); +} + +static void +changerace_free(trigger * t) +{ + free(t->data.v); +} + +static int +changerace_handle(trigger * t, void * data) +{ + /* call an event handler on changerace. + * data.v -> ( variant event, int timer ) + */ + changerace_data * td = (changerace_data*)t->data.v; + if (td->u) { + if (td->race!=NULL) td->u->race = td->race; + if (td->irace!=NULL) td->u->irace = td->irace; + } else { + log_error(("could not perform changerace::handle()\n")); + } + unused(data); + return 0; +} + +static void +changerace_write(const trigger * t, struct storage * store) +{ + changerace_data * td = (changerace_data*)t->data.v; + write_unit_reference(td->u, store); + write_race_reference(td->race, store); + write_race_reference(td->irace, store); +} + +static int +changerace_read(trigger * t, struct storage * store) +{ + changerace_data * td = (changerace_data*)t->data.v; + read_reference(&td->u, store, read_unit_reference, resolve_unit); + td->race = (const struct race*)read_race_reference(store).v; + td->irace = (const struct race*)read_race_reference(store).v; + return AT_READ_OK; +} + +trigger_type tt_changerace = { + "changerace", + changerace_init, + changerace_free, + changerace_handle, + changerace_write, + changerace_read +}; + +trigger * +trigger_changerace(struct unit * u, const struct race * prace, const struct race * irace) +{ + trigger * t = t_new(&tt_changerace); + changerace_data * td = (changerace_data*)t->data.v; + + assert(u->race==u_irace(u) || "!changerace-triggers cannot stack!"); + td->u = u; + td->race = prace; + td->irace = irace; + return t; +} diff --git a/src/triggers/changerace.h b/src/triggers/changerace.h new file mode 100644 index 000000000..dc2c55111 --- /dev/null +++ b/src/triggers/changerace.h @@ -0,0 +1,37 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CHANGERACE_H +#define CHANGERACE_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; +struct unit; + +extern struct trigger_type tt_changerace; + +extern struct trigger * trigger_changerace(struct unit * u, const struct race *urace, const struct race *irace); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/clonedied.c b/src/triggers/clonedied.c new file mode 100644 index 000000000..98f156afd --- /dev/null +++ b/src/triggers/clonedied.c @@ -0,0 +1,95 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "clonedied.h" + +/* kernel includes */ +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +/** + clonedied. + + This trigger ist called when a clone of a mage dies. + It simply removes the clone-attribute from the mage. + */ + +static int +clonedied_handle(trigger * t, void * data) +{ + /* destroy the unit */ + unit * u = (unit*)t->data.v; + if (u) { + attrib *a = a_find(u->attribs, &at_clone); + if(a) a_remove(&u->attribs, a); + } else + log_error(("could not perform clonedied::handle()\n")); + unused(data); + return 0; +} + +static void +clonedied_write(const trigger * t, struct storage * store) +{ + unit * u = (unit*)t->data.v; + write_unit_reference(u, store); +} + +static int +clonedied_read(trigger * t, struct storage * store) +{ + int result = read_reference(&t->data.v, store, read_unit_reference, resolve_unit); + if (result==0 && t->data.v==NULL) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +trigger_type tt_clonedied = { + "clonedied", + NULL, + NULL, + clonedied_handle, + clonedied_write, + clonedied_read +}; + +trigger * +trigger_clonedied(unit * u) +{ + trigger * t = t_new(&tt_clonedied); + t->data.v = (void*)u; + return t; +} + diff --git a/src/triggers/clonedied.h b/src/triggers/clonedied.h new file mode 100644 index 000000000..607a1c415 --- /dev/null +++ b/src/triggers/clonedied.h @@ -0,0 +1,36 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CLONEDIED_H +#define CLONEDIED_H +#ifdef __cplusplus +extern "C" { +#endif + +struct trigger_type; +struct trigger; + +struct unit; + +extern struct trigger_type tt_clonedied; +extern struct trigger * trigger_clonedied(struct unit * u); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/createcurse.c b/src/triggers/createcurse.c new file mode 100644 index 000000000..085b08317 --- /dev/null +++ b/src/triggers/createcurse.c @@ -0,0 +1,157 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "createcurse.h" + +/* kernel includes */ +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* ansi includes */ +#include +#include +#include + + +#include +/*** + ** restore a mage that was turned into a toad + **/ + +typedef struct createcurse_data { + struct unit * mage; + struct unit * target; + const curse_type * type; + double vigour; + int duration; + double effect; + int men; +} createcurse_data; + +static void +createcurse_init(trigger * t) +{ + t->data.v = calloc(sizeof(createcurse_data), 1); +} + +static void +createcurse_free(trigger * t) +{ + free(t->data.v); +} + +static int +createcurse_handle(trigger * t, void * data) +{ + /* call an event handler on createcurse. + * data.v -> ( variant event, int timer ) + */ + createcurse_data * td = (createcurse_data*)t->data.v; + if (td->mage && td->target && td->mage->number && td->target->number) { + create_curse(td->mage, &td->target->attribs, + td->type, td->vigour, td->duration, td->effect, td->men); + } else { + log_error(("could not perform createcurse::handle()\n")); + } + unused(data); + return 0; +} + +static void +createcurse_write(const trigger * t, struct storage * store) +{ + createcurse_data * td = (createcurse_data*)t->data.v; + write_unit_reference(td->mage, store); + write_unit_reference(td->target, store); + store->w_tok(store, td->type->cname); + store->w_flt(store, (float)td->vigour); + store->w_int(store, td->duration); + store->w_flt(store, (float)td->effect); + store->w_int(store, td->men); +} + +static int +createcurse_read(trigger * t, struct storage * store) +{ + createcurse_data * td = (createcurse_data*)t->data.v; + char zText[128]; + + read_reference(&td->mage, store, read_unit_reference, resolve_unit); + read_reference(&td->target, store, read_unit_reference, resolve_unit); + + if (store->versionr_int(store); + id2 = store->r_int(store); + assert(id2==0); + td->vigour = store->r_flt(store); + td->duration = store->r_int(store); + td->effect = store->r_int(store); + td->men = store->r_int(store); + td->type = ct_find(oldcursename(id1)); + } else { + store->r_tok_buf(store, zText, sizeof(zText)); + td->type = ct_find(zText); + td->vigour = store->r_flt(store); + td->duration = store->r_int(store); + if (store->versioneffect = (double)store->r_int(store); + } else { + td->effect = store->r_flt(store); + } + td->men = store->r_int(store); + } + return AT_READ_OK; +} + +trigger_type tt_createcurse = { + "createcurse", + createcurse_init, + createcurse_free, + createcurse_handle, + createcurse_write, + createcurse_read +}; + +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); + createcurse_data * td = (createcurse_data*)t->data.v; + td->mage = mage; + td->target = target; + td->type = ct; + td->vigour = vigour; + td->duration = duration; + td->effect = effect; + td->men = men; + return t; +} diff --git a/src/triggers/createcurse.h b/src/triggers/createcurse.h new file mode 100644 index 000000000..bc3d2e797 --- /dev/null +++ b/src/triggers/createcurse.h @@ -0,0 +1,40 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CREATECURSE_H +#define CREATECURSE_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct curse_type; +struct trigger_type; +struct trigger; +struct region; +struct faction; +struct unit; + +extern struct trigger_type tt_createcurse; + +extern struct trigger * trigger_createcurse(struct unit * mage, struct unit * target, const struct curse_type * ct, double vigour, int duration, double effect, int men); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/createunit.c b/src/triggers/createunit.c new file mode 100644 index 000000000..48610c9d1 --- /dev/null +++ b/src/triggers/createunit.c @@ -0,0 +1,130 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "createunit.h" + +/* kernel includes */ +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* ansi includes */ +#include +#include +#include + + +#include +/*** + ** restore a mage that was turned into a toad + **/ + +typedef struct createunit_data { + struct region * r; + struct faction * f; + const struct race * race; + int number; +} createunit_data; + +static void +createunit_init(trigger * t) +{ + t->data.v = calloc(sizeof(createunit_data), 1); +} + +static void +createunit_free(trigger * t) +{ + free(t->data.v); +} + +static int +createunit_handle(trigger * t, void * data) +{ + /* call an event handler on createunit. + * data.v -> ( variant event, int timer ) + */ + createunit_data * td = (createunit_data*)t->data.v; + if (td->r!=NULL && td->f!=NULL) { + create_unit(td->r, td->f, td->number, td->race, 0, NULL, NULL); + } else { + log_error(("could not perform createunit::handle()\n")); + } + unused(data); + return 0; +} + +static void +createunit_write(const trigger * t, struct storage * store) +{ + createunit_data * td = (createunit_data*)t->data.v; + write_faction_reference(td->f, store); + write_region_reference(td->r, store); + write_race_reference(td->race, store); + store->w_int(store, td->number); +} + +static int +createunit_read(trigger * t, struct storage * store) +{ + createunit_data * td = (createunit_data*)t->data.v; + + int uc = read_reference(&td->f, store, read_faction_reference, resolve_faction); + int rc = read_reference(&td->r, store, read_region_reference, RESOLVE_REGION(store->version)); + td->race = (const struct race*)read_race_reference(store).v; + + if (uc==0 && rc==0) { + if (!td->f || !td->r) return AT_READ_FAIL; + } + td->number = store->r_int(store); + + return AT_READ_OK; +} + +trigger_type tt_createunit = { + "createunit", + createunit_init, + createunit_free, + createunit_handle, + createunit_write, + createunit_read +}; + +trigger * +trigger_createunit(region * r, struct faction * f, const struct race * rc, int number) +{ + trigger * t = t_new(&tt_createunit); + createunit_data * td = (createunit_data*)t->data.v; + td->r = r; + td->f = f; + td->race = rc; + td->number = number; + return t; +} diff --git a/src/triggers/createunit.h b/src/triggers/createunit.h new file mode 100644 index 000000000..7dd6894f2 --- /dev/null +++ b/src/triggers/createunit.h @@ -0,0 +1,39 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CREATEUNIT_H +#define CREATEUNIT_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; +struct region; +struct faction; +struct unit; + +extern struct trigger_type tt_createunit; + +extern struct trigger * trigger_createunit(struct region * r, struct faction * f, const struct race * rc, int number); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/gate.c b/src/triggers/gate.c new file mode 100644 index 000000000..ef1344495 --- /dev/null +++ b/src/triggers/gate.c @@ -0,0 +1,117 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#include +#include +#include "gate.h" + +/* kernel includes */ +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include + +/* libc includes */ +#include + +typedef struct gate_data { + struct building * gate; + struct region * target; +} gate_data; + +static int +gate_handle(trigger * t, void * data) +{ + /* call an event handler on gate. + * data.v -> ( variant event, int timer ) + */ + gate_data * gd = (gate_data*)t->data.v; + struct building * b = gd->gate; + struct region * r = gd->target; + + if (b && b->region && r) { + unit ** up = &b->region->units; + while (*up) { + unit * u = *up; + if (u->building==b) move_unit(u, r, NULL); + if (*up==u) up = &u->next; + } + } else { + log_error(("could not perform gate::handle()\n")); + return -1; + } + unused(data); + return 0; +} + +static void +gate_write(const trigger * t, struct storage * store) +{ + gate_data * gd = (gate_data*)t->data.v; + building * b = gd->gate; + region * r = gd->target; + + write_building_reference(b, store); + write_region_reference(r, store); +} + +static int +gate_read(trigger * t, struct storage * store) +{ + gate_data * gd = (gate_data*)t->data.v; + + int bc = read_reference(&gd->gate, store, read_building_reference, resolve_building); + int rc = read_reference(&gd->target, store, read_region_reference, RESOLVE_REGION(store->version)); + + if (bc==0 && rc==0) { + if (!gd->gate || !gd->target) return AT_READ_FAIL; + } + return AT_READ_OK; +} + +static void +gate_init(trigger * t) +{ + t->data.v = calloc(sizeof(gate_data), 1); +} + +static void +gate_done(trigger * t) +{ + free(t->data.v); +} + + +struct trigger_type tt_gate = { + "gate", + gate_init, + gate_done, + gate_handle, + gate_write, + gate_read +}; + +trigger * +trigger_gate(building * b, region * target) +{ + trigger * t = t_new(&tt_gate); + gate_data * td = (gate_data*)t->data.v; + td->gate = b; + td->target = target; + return t; +} diff --git a/src/triggers/gate.h b/src/triggers/gate.h new file mode 100644 index 000000000..677118330 --- /dev/null +++ b/src/triggers/gate.h @@ -0,0 +1,32 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef GATE_H +#define GATE_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; +struct region; +struct building; + +extern struct trigger_type tt_gate; + +extern struct trigger * trigger_gate(struct building * b, struct region * r); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/giveitem.c b/src/triggers/giveitem.c new file mode 100644 index 000000000..53a06f24b --- /dev/null +++ b/src/triggers/giveitem.c @@ -0,0 +1,124 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "giveitem.h" + +/* kernel includes */ +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* ansi includes */ +#include +#include +#include + +/*** + ** give an item to someone + **/ + +typedef struct giveitem_data { + struct unit * u; + const struct item_type * itype; + int number; +} giveitem_data; + +static void +giveitem_init(trigger * t) +{ + t->data.v = calloc(sizeof(giveitem_data), 1); +} + +static void +giveitem_free(trigger * t) +{ + free(t->data.v); +} + +static int +giveitem_handle(trigger * t, void * data) +{ + /* call an event handler on giveitem. + * data.v -> ( variant event, int timer ) + */ + giveitem_data * td = (giveitem_data*)t->data.v; + if (td->u && td->u->number) { + i_change(&td->u->items, td->itype, td->number); + } else { + log_error(("could not perform giveitem::handle()\n")); + } + unused(data); + return 0; +} + +static void +giveitem_write(const trigger * t, struct storage * store) +{ + giveitem_data * td = (giveitem_data*)t->data.v; + write_unit_reference(td->u, store); + store->w_int(store, td->number); + store->w_tok(store, td->itype->rtype->_name[0]); +} + +static int +giveitem_read(trigger * t, struct storage * store) +{ + giveitem_data * td = (giveitem_data*)t->data.v; + char zText[128]; + + int result = read_reference(&td->u, store, read_unit_reference, resolve_unit); + + td->number = store->r_int(store); + store->r_tok_buf(store, zText, sizeof(zText)); + td->itype = it_find(zText); + assert(td->itype); + + if (result==0 && td->u==NULL) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +trigger_type tt_giveitem = { + "giveitem", + giveitem_init, + giveitem_free, + giveitem_handle, + giveitem_write, + giveitem_read +}; + +trigger * +trigger_giveitem(unit * u, const item_type * itype, int number) +{ + trigger * t = t_new(&tt_giveitem); + giveitem_data * td = (giveitem_data*)t->data.v; + td->number = number; + td->u = u; + td->itype = itype; + return t; +} diff --git a/src/triggers/giveitem.h b/src/triggers/giveitem.h new file mode 100644 index 000000000..048b4a5cd --- /dev/null +++ b/src/triggers/giveitem.h @@ -0,0 +1,38 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef GIVEITEM_H +#define GIVEITEM_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; +struct unit; +struct item_type; + +extern struct trigger_type tt_giveitem; + +extern struct trigger * trigger_giveitem(struct unit * mage, const struct item_type * itype, int number); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/killunit.c b/src/triggers/killunit.c new file mode 100644 index 000000000..b1d5a4064 --- /dev/null +++ b/src/triggers/killunit.c @@ -0,0 +1,87 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "killunit.h" + +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +#include +#include +/*** + ** killunit + **/ + +static int +killunit_handle(trigger * t, void * data) +{ + /* call an event handler on killunit. + * data.v -> ( variant event, int timer ) + */ + unit * u = (unit*)t->data.v; + if (u) { + /* we can't remove_unit() here, because that's what's calling us. */ + set_number(u, 0); + } + unused(data); + return 0; +} + +static void +killunit_write(const trigger * t, struct storage * store) +{ + unit * u = (unit*)t->data.v; + write_unit_reference(u, store); +} + +static int +killunit_read(trigger * t, struct storage * store) +{ + int result = read_reference(&t->data.v, store, read_unit_reference, resolve_unit); + if (result==0 && t->data.v==NULL) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +trigger_type tt_killunit = { + "killunit", + NULL, + NULL, + killunit_handle, + killunit_write, + killunit_read +}; + +trigger * +trigger_killunit(unit * u) +{ + trigger * t = t_new(&tt_killunit); + t->data.v = (void*)u; + return t; +} diff --git a/src/triggers/killunit.h b/src/triggers/killunit.h new file mode 100644 index 000000000..f9aa652fa --- /dev/null +++ b/src/triggers/killunit.h @@ -0,0 +1,36 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef KILLUNIT_H +#define KILLUNIT_H +#ifdef __cplusplus +extern "C" { +#endif + +struct trigger_type; +struct trigger; + +struct unit; + +extern struct trigger_type tt_killunit; +extern struct trigger * trigger_killunit(struct unit * u); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/removecurse.c b/src/triggers/removecurse.c new file mode 100644 index 000000000..0377974cf --- /dev/null +++ b/src/triggers/removecurse.c @@ -0,0 +1,114 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "removecurse.h" + +/* kernel includes */ +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* ansi includes */ +#include +#include +#include + + +#include + +typedef struct removecurse_data { + curse * curse; + unit * target; +} removecurse_data; + +static void +removecurse_init(trigger * t) +{ + t->data.v = calloc(sizeof(removecurse_data), 1); +} + +static void +removecurse_free(trigger * t) +{ + free(t->data.v); +} + +static int +removecurse_handle(trigger * t, void * data) +{ + /* call an event handler on removecurse. + * data.v -> ( variant event, int timer ) + */ + removecurse_data * td = (removecurse_data*)t->data.v; + if (td->curse && td->target) { + attrib * a = a_select(td->target->attribs, td->curse, cmp_curse); + if (a) { + a_remove(&td->target->attribs, a); + } + else log_error(("could not perform removecurse::handle()\n")); + } + unused(data); + return 0; +} + +static void +removecurse_write(const trigger * t, struct storage * store) +{ + removecurse_data * td = (removecurse_data*)t->data.v; + store->w_tok(store, td->target?itoa36(td->target->no):0); + store->w_int(store, td->curse?td->curse->no:0); +} + +static int +removecurse_read(trigger * t, struct storage * store) +{ + removecurse_data * td = (removecurse_data*)t->data.v; + + read_reference(&td->target, store, read_unit_reference, resolve_unit); + read_reference(&td->curse, store, read_int, resolve_curse); + + return AT_READ_OK; +} + +trigger_type tt_removecurse = { + "removecurse", + removecurse_init, + removecurse_free, + removecurse_handle, + removecurse_write, + removecurse_read +}; + +trigger * +trigger_removecurse(curse * c, unit * target) +{ + trigger * t = t_new(&tt_removecurse); + removecurse_data * td = (removecurse_data*)t->data.v; + td->curse = c; + td->target = target; + return t; +} diff --git a/src/triggers/removecurse.h b/src/triggers/removecurse.h new file mode 100644 index 000000000..0a89a5e97 --- /dev/null +++ b/src/triggers/removecurse.h @@ -0,0 +1,39 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef REMOVECURSE_H +#define REMOVECURSE_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; + +struct unit; +struct curse; + +extern struct trigger_type tt_removecurse; + +extern struct trigger * trigger_removecurse(struct curse * c, struct unit * target); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/shock.c b/src/triggers/shock.c new file mode 100644 index 000000000..4cb361478 --- /dev/null +++ b/src/triggers/shock.c @@ -0,0 +1,148 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "shock.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +/*** + ** shock + **/ + +/* ------------------------------------------------------------- */ +/* do_shock - Schockt die Einheit, z.B. bei Verlust eines */ +/* Vertrauten. */ +/* ------------------------------------------------------------- */ + +static void +do_shock(unit *u, const char *reason) +{ + int i; + + if (u->number > 0) { + /* HP - Verlust */ + u->hp = (unit_max_hp(u) * u->number)/10; + u->hp = MAX(1, u->hp); + } + + /* Aura - Verlust */ + if (is_mage(u)) { + set_spellpoints(u, max_spellpoints(u->region,u)/10); + } + + /* Evt. Talenttageverlust */ + for (i=0;i!=u->skill_size;++i) if (rng_int()%5==0) { + skill * sv = u->skills+i; + int weeks = (sv->level * sv->level - sv->level) / 2; + int change = (weeks+9) / 10; + reduce_skill(u, sv, change); + } + + /* Dies ist ein Hack, um das skillmod und familiar-Attribut beim Mage + * zu löschen wenn der Familiar getötet wird. Da sollten wir über eine + * saubere Implementation nachdenken. */ + + if (strcmp(reason, "trigger")==0) { + remove_familiar(u); + } + if (u->faction!=NULL) { + ADDMSG(&u->faction->msgs, msg_message("shock", + "mage reason", u, strdup(reason))); + } +} + +static int +shock_handle(trigger * t, void * data) +{ + /* destroy the unit */ + unit * u = (unit*)t->data.v; + if (u && u->number) { + do_shock(u, "trigger"); + } + unused(data); + return 0; +} + +static void +shock_write(const trigger * t, struct storage * store) +{ + unit * u = (unit*)t->data.v; + trigger * next = t->next; + while (next) { + /* make sure it is unique! */ + if (next->type==t->type && next->data.v==t->data.v) break; + next=next->next; + } + if (next && u) { + log_error(("more than one shock-attribut for %s on a unit. FIXED.\n", + unitid(u))); + write_unit_reference(NULL, store); + } else { + write_unit_reference(u, store); + } +} + +static int +shock_read(trigger * t, struct storage * store) +{ + int result = read_reference(&t->data.v, store, read_unit_reference, resolve_unit); + if (result==0 && t->data.v==NULL) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +trigger_type tt_shock = { + "shock", + NULL, + NULL, + shock_handle, + shock_write, + shock_read +}; + +trigger * +trigger_shock(unit * u) +{ + trigger * t = t_new(&tt_shock); + t->data.v = (void*)u; + return t; +} diff --git a/src/triggers/shock.h b/src/triggers/shock.h new file mode 100644 index 000000000..07e59cb30 --- /dev/null +++ b/src/triggers/shock.h @@ -0,0 +1,36 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_TRG_SHOCK_H +#define H_TRG_SHOCK_H +#ifdef __cplusplus +extern "C" { +#endif + +struct trigger_type; +struct trigger; + +struct unit; + +extern struct trigger_type tt_shock; +extern struct trigger * trigger_shock(struct unit * u); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/timeout.c b/src/triggers/timeout.c new file mode 100644 index 000000000..e0770ed39 --- /dev/null +++ b/src/triggers/timeout.c @@ -0,0 +1,113 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "timeout.h" + +/* util includes */ +#include +#include +#include +#include + +#include +#include +/*** + ** timeout + **/ + +typedef struct timeout_data { + trigger * triggers; + int timer; + variant trigger_data; +} timeout_data; + +static void +timeout_init(trigger * t) +{ + t->data.v = calloc(sizeof(timeout_data), 1); +} + +static void +timeout_free(trigger * t) +{ + timeout_data * td = (timeout_data*)t->data.v; + free_triggers(td->triggers); + free(t->data.v); +} + +static int +timeout_handle(trigger * t, void * data) +{ + /* call an event handler on timeout. + * data.v -> ( variant event, int timer ) + */ + timeout_data * td = (timeout_data*)t->data.v; + if (--td->timer==0) { + handle_triggers(&td->triggers, NULL); + return -1; + } + unused(data); + return 0; +} + +static void +timeout_write(const trigger * t, struct storage * store) +{ + timeout_data * td = (timeout_data*)t->data.v; + store->w_int(store, td->timer); + write_triggers(store, td->triggers); +} + +static int +timeout_read(trigger * t, struct storage * store) +{ + timeout_data * td = (timeout_data*)t->data.v; + td->timer = store->r_int(store); + read_triggers(store, &td->triggers); + if (td->timer>20) { + trigger * tr = td->triggers; + log_warning(("there is a timeout lasting for another %d turns\n", td->timer)); + while (tr) { + log_warning((" timeout triggers: %s\n", tr->type->name)); + tr = tr->next; + } + } + if (td->triggers!=NULL && td->timer>0) return AT_READ_OK; + return AT_READ_FAIL; +} + +trigger_type tt_timeout = { + "timeout", + timeout_init, + timeout_free, + timeout_handle, + timeout_write, + timeout_read +}; + +trigger * +trigger_timeout(int time, trigger * callbacks) +{ + trigger * t = t_new(&tt_timeout); + timeout_data * td = (timeout_data*)t->data.v; + td->triggers = callbacks; + td->timer = time; + return t; +} diff --git a/src/triggers/timeout.h b/src/triggers/timeout.h new file mode 100644 index 000000000..3f9f122ef --- /dev/null +++ b/src/triggers/timeout.h @@ -0,0 +1,35 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_TRG_TIMEOUT_H +#define H_TRG_TIMEOUT_H +#ifdef __cplusplus +extern "C" { +#endif + +struct trigger_type; +struct trigger; + +extern struct trigger_type tt_timeout; + +extern struct trigger * trigger_timeout(int time, struct trigger * callbacks); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/triggers.c b/src/triggers/triggers.c new file mode 100644 index 000000000..7df6cffc1 --- /dev/null +++ b/src/triggers/triggers.c @@ -0,0 +1,60 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include + +/* triggers includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include + +/* libc includes */ +#include + +void +register_triggers(void) +{ + if (verbosity>=2) printf("- registering triggers\n"); + tt_register(&tt_changefaction); + tt_register(&tt_changerace); + tt_register(&tt_createcurse); + tt_register(&tt_createunit); + tt_register(&tt_gate); + tt_register(&tt_unguard); + tt_register(&tt_giveitem); + tt_register(&tt_killunit); + tt_register(&tt_removecurse); + tt_register(&tt_shock); + tt_register(&tt_unitmessage); + tt_register(&tt_timeout); + tt_register(&tt_clonedied); +} diff --git a/src/triggers/triggers.h b/src/triggers/triggers.h new file mode 100644 index 000000000..def5f4072 --- /dev/null +++ b/src/triggers/triggers.h @@ -0,0 +1,30 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_TRG_TRIGGERS +#define H_TRG_TRIGGERS +#ifdef __cplusplus +extern "C" { +#endif + +void register_triggers(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/unguard.c b/src/triggers/unguard.c new file mode 100644 index 000000000..1c4cb42ea --- /dev/null +++ b/src/triggers/unguard.c @@ -0,0 +1,77 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#include +#include +#include "unguard.h" + +/* kernel includes */ +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include + +/* libc includes */ +#include + +static int +unguard_handle(trigger * t, void * data) +{ + building * b = (building*)t->data.v; + + if (b) { + fset(b, BLD_UNGUARDED); + } else { + log_error(("could not perform unguard::handle()\n")); + return -1; + } + unused(data); + return 0; +} + +static void +unguard_write(const trigger * t, struct storage * store) +{ + write_building_reference((building*)t->data.v, store); +} + +static int +unguard_read(trigger * t, struct storage * store) +{ + int rb = read_reference(&t->data.v, store, read_building_reference, resolve_building); + if (rb==0 && !t->data.v) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +struct trigger_type tt_unguard = { + "building", + NULL, + NULL, + unguard_handle, + unguard_write, + unguard_read +}; + +trigger * +trigger_unguard(building * b) +{ + trigger * t = t_new(&tt_unguard); + t->data.v = (void*)b; + return t; +} diff --git a/src/triggers/unguard.h b/src/triggers/unguard.h new file mode 100644 index 000000000..7748e5a92 --- /dev/null +++ b/src/triggers/unguard.h @@ -0,0 +1,32 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef UNGUARD_H +#define UNGUARD_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; +struct region; +struct building; + +extern struct trigger_type tt_unguard; + +extern struct trigger * trigger_unguard(struct building * b); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/unitmessage.c b/src/triggers/unitmessage.c new file mode 100644 index 000000000..f1d7d7dbf --- /dev/null +++ b/src/triggers/unitmessage.c @@ -0,0 +1,123 @@ +/* vi: set ts=2: ++-------------------+ Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel ++-------------------+ +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "unitmessage.h" + +/* kernel includes */ +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* ansi includes */ +#include +#include +#include +#include + +/*** +** give an item to someone +**/ + +typedef struct unitmessage_data { + struct unit * target; + char * string; + int type; + int level; +} unitmessage_data; + +static void +unitmessage_init(trigger * t) +{ + t->data.v = calloc(sizeof(unitmessage_data), 1); +} + +static void +unitmessage_free(trigger * t) +{ + unitmessage_data * sd = (unitmessage_data*)t->data.v; + free(sd->string); + free(t->data.v); +} + +static int +unitmessage_handle(trigger * t, void * data) +{ + /* call an event handler on unitmessage. + * data.v -> ( variant event, int timer ) + */ + unitmessage_data * td = (unitmessage_data*)t->data.v; + if (td->target && td->target->no) { + struct faction * f = td->target->faction; + addmessage(td->target->region, f, LOC(f->locale, td->string), td->type, td->level); + } + unused(data); + return 0; +} + +static void +unitmessage_write(const trigger * t, struct storage * store) +{ + unitmessage_data * td = (unitmessage_data*)t->data.v; + write_unit_reference(td->target, store); + store->w_tok(store, td->string); + store->w_int(store, td->type); + store->w_int(store, td->level); +} + +static int +unitmessage_read(trigger * t, struct storage * store) +{ + unitmessage_data * td = (unitmessage_data*)t->data.v; + char zText[256]; + + int result = read_reference(&td->target, store, read_unit_reference, resolve_unit); + + td->string = store->r_tok(store); + td->type = store->r_int(store); + td->level = store->r_int(store); + td->string = strdup(zText); + + if (result==0 && td->target==NULL) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +trigger_type tt_unitmessage = { + "unitmessage", + unitmessage_init, + unitmessage_free, + unitmessage_handle, + unitmessage_write, + unitmessage_read +}; + +trigger * +trigger_unitmessage(unit * target, const char * string, int type, int level) +{ + trigger * t = t_new(&tt_unitmessage); + unitmessage_data * td = (unitmessage_data*)t->data.v; + td->target = target; + td->string = strdup(string); + td->type = type; + td->level = level; + return t; +} diff --git a/src/triggers/unitmessage.h b/src/triggers/unitmessage.h new file mode 100644 index 000000000..dcc8df47d --- /dev/null +++ b/src/triggers/unitmessage.h @@ -0,0 +1,36 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef UNITMESSAGE_H +#define UNITMESSAGE_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; +struct unit; + +extern struct trigger_type tt_unitmessage; +extern struct trigger * trigger_unitmessage(struct unit * target, const char * string, int type, int level); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util.vcproj b/src/util.vcproj new file mode 100644 index 000000000..b501b3566 --- /dev/null +++ b/src/util.vcproj @@ -0,0 +1,418 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/util.vcxproj b/src/util.vcxproj new file mode 100644 index 000000000..a86de3fc2 --- /dev/null +++ b/src/util.vcxproj @@ -0,0 +1,159 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {F70CFB27-8A2F-E447-B452-4E1C590EDA6D} + util + Win32Proj + + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + + + + /MP %(AdditionalOptions) + Disabled + .;../../external;%(AdditionalIncludeDirectories) + WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + + + Level4 + true + EditAndContinue + + + WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + ..;.;%(AdditionalIncludeDirectories) + + + $(OutDir)util.lib + + + + + Full + .;../../external;%(AdditionalIncludeDirectories) + WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + + + Level4 + + + + + WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) + ..;.;%(AdditionalIncludeDirectories) + + + $(OutDir)util.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/util.vcxproj.filters b/src/util.vcxproj.filters new file mode 100644 index 000000000..4f0d43ac5 --- /dev/null +++ b/src/util.vcxproj.filters @@ -0,0 +1,203 @@ + + + + + {93caffaa-508e-4e78-b1ba-5a8d6aa4ab9a} + h;hpp;hxx;hm;inl;inc;xsd + + + {77dd9146-7564-475b-a364-b1610046b1bb} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/src/util/argstack.c b/src/util/argstack.c new file mode 100644 index 000000000..614a18def --- /dev/null +++ b/src/util/argstack.c @@ -0,0 +1,66 @@ +#include "argstack.h" +#include + +#define ARGSTKSIZE 16 +typedef struct arguments { + int n; + struct value { + int type; + union { + double number; + const char * str; + void * data; + } value; + } stack[ARGSTKSIZE]; +} arguments; + +void arg_init(struct arguments * arg) { + arg->n = 0; +} + +void arg_done(struct arguments * arg) { + arg = arg; +} + +void arg_pushuserdata(struct arguments * arg, int type, void * data) { + assert(arg->nstack[arg->n].type = type; + arg->stack[arg->n].value.data = data; + ++arg->n; +} + +void arg_pushstring(struct arguments * arg, const char * str) { + assert(arg->nstack[arg->n].type = ARG_TSTRING; + arg->stack[arg->n].value.str = str; + ++arg->n; +} + +void arg_pushnumber(struct arguments * arg, double number) { + assert(arg->nstack[arg->n].type = ARG_TSTRING; + arg->stack[arg->n].value.number = number; + ++arg->n; +} + +int arg_size(struct arguments * arg) { + return arg->n; +} + +void * arg_touserdata(struct arguments * arg, int idx, int type) { + assert(arg->n>idx && idx>=0); + assert(arg->stack[arg->n].type==type); + return arg->stack[arg->n].value.data; +} + +double arg_tonumber(struct arguments * arg, int idx) { + assert(arg->n>idx && idx>=0); + assert(arg->stack[arg->n].type==ARG_TNUMBER); + return arg->stack[arg->n].value.number; +} + +const char * arg_tostring(struct arguments * arg, int idx) { + assert(arg->n>idx && idx>=0); + assert(arg->stack[arg->n].type==ARG_TSTRING); + return arg->stack[arg->n].value.str; +} diff --git a/src/util/argstack.h b/src/util/argstack.h new file mode 100644 index 000000000..b4a0dc420 --- /dev/null +++ b/src/util/argstack.h @@ -0,0 +1,27 @@ +#ifndef UTIL_ARG_H +#define UTIL_ARG_H +#ifdef __cplusplus +extern "C" { +#endif + +struct arguments; + +#define ARG_TNUMBER -1 +#define ARG_TSTRING -2 + +void arg_init(struct arguments * arg); +void arg_done(struct arguments * arg); + +void arg_push(struct arguments * arg, int type, void * data); +void arg_pushstring(struct arguments * arg, const char * str); +void arg_pushnumber(struct arguments * arg, double number); + +int arg_size(struct arguments * arg); +void * arg_touserdata(struct arguments * arg, int idx, int type); +double arg_tonumber(struct arguments * arg, int idx); +const char * arg_tostring(struct arguments * arg, int idx); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/attrib.c b/src/util/attrib.c new file mode 100644 index 000000000..97d3a0d97 --- /dev/null +++ b/src/util/attrib.c @@ -0,0 +1,322 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "attrib.h" + +#include "log.h" +#include "storage.h" + +#include +#include +#include + +#define MAXATHASH 61 +attrib_type * at_hash[MAXATHASH]; + +static unsigned int +__at_hashkey(const char* s) +{ + int key = 0; + size_t i = strlen(s); + + while (i>0) { + key = (s[--i] + key*37); + } + return key & 0x7fffffff; +} + +void +at_register(attrib_type * at) +{ + attrib_type * find; + + if (at->read==NULL) { + log_warning(("registering non-persistent attribute %s.\n", at->name)); + } + at->hashkey = __at_hashkey(at->name); + find = at_hash[at->hashkey % MAXATHASH]; + while (find && at->hashkey!=find->hashkey) find = find->nexthash; + if (find && find==at) { + log_warning(("attribute '%s' was registered more than once\n", at->name)); + return; + } else { + assert(!find || !"hashkey is already in use"); + } + at->nexthash = at_hash[at->hashkey % MAXATHASH]; + at_hash[at->hashkey % MAXATHASH] = at; +} + +static attrib_type * +at_find(unsigned int hk) +{ + const char* translate[3][2] = { + { "zielregion", "targetregion" }, /* remapping: from 'zielregion, heute targetregion */ + { "verzaubert", "curse" }, /* remapping: früher verzaubert, jetzt curse */ + { NULL, NULL } + }; + attrib_type * find = at_hash[hk % MAXATHASH]; + while (find && hk!=find->hashkey) find = find->nexthash; + if (!find) { + int i = 0; + while (translate[i][0]) { + if (__at_hashkey(translate[i][0])==hk) + return at_find(__at_hashkey(translate[i][1])); + ++i; + } + } + return find; +} + +attrib * +a_select(attrib * a, const void * data, boolean(*compare)(const attrib *, const void *)) +{ + while (a && !compare(a, data)) a = a->next; + return a; +} + +attrib * +a_find(attrib * a, const attrib_type * at) +{ + while (a && a->type!=at) a = a->nexttype; + return a; +} + +const attrib * +a_findc(const attrib * a, const attrib_type * at) +{ + while (a && a->type!=at) a = a->nexttype; + return a; +} + +static attrib * +a_insert(attrib * head, attrib * a) +{ + attrib ** pa=&head->next; + + assert(!(a->type->flags & ATF_UNIQUE)); + assert(head && head->type==a->type); + + while (*pa && (*pa)->type==a->type) { + pa = &(*pa)->next; + } + a->next = *pa; + return *pa = a; +} + +attrib * +a_add(attrib ** pa, attrib * a) +{ + attrib * first = *pa; + assert(a->next==NULL && a->nexttype==NULL); + + if (first==NULL) return *pa = a; + if (first->type==a->type) { + return a_insert(first, a); + } + for (;;) { + attrib * next = first->nexttype; + if (next==NULL) { + /* the type is not in the list, append it behind the last type */ + attrib ** insert = &first->next; + first->nexttype = a; + while (*insert) insert = &(*insert)->next; + *insert = a; + break; + } + if (next->type==a->type) { + return a_insert(next, a); + } + first = next; + } + return a; +} + +void +a_free(attrib * a) +{ + const attrib_type * at = a->type; + if (at->finalize) at->finalize(a); + free(a); +} + +static int +a_unlink(attrib ** pa, attrib * a) +{ + attrib ** pnexttype = pa; + attrib ** pnext = NULL; + + assert(a!=NULL); + while (*pnexttype) { + attrib * next = *pnexttype; + if (next->type==a->type) break; + pnexttype = &next->nexttype; + pnext = &next->next; + } + if (*pnexttype && (*pnexttype)->type==a->type) { + if (*pnexttype==a) { + *pnexttype = a->next; + if (a->next!=a->nexttype) { + a->next->nexttype = a->nexttype; + } + if (pnext==NULL) return 1; + while (*pnext && (*pnext)->type!=a->type) pnext = &(*pnext)->next; + } else { + pnext = &(*pnexttype)->next; + } + while (*pnext && (*pnext)->type==a->type) { + if (*pnext==a) { + *pnext = a->next; + return 1; + } + pnext = &(*pnext)->next; + } + } + return 0; +} + +int +a_remove(attrib ** pa, attrib * a) +{ + int ok; + assert(a!=NULL); + ok = a_unlink(pa, a); + if (ok) a_free(a); + return ok; +} + +void +a_removeall(attrib **pa, const attrib_type * at) +{ + attrib ** pnexttype = pa; + attrib ** pnext = NULL; + + while (*pnexttype) { + attrib * next = *pnexttype; + if (next->type==at) break; + pnexttype = &next->nexttype; + pnext = &next->next; + } + if (*pnexttype && (*pnexttype)->type==at) { + attrib * a = *pnexttype; + + *pnexttype = a->nexttype; + if (pnext) { + while (*pnext && (*pnext)->type!=at) pnext = &(*pnext)->next; + *pnext = a->nexttype; + } + while (a && a->type==at) { + attrib * ra = a; + a = a->next; + a_free(ra); + } + } +} + +attrib * +a_new(const attrib_type * at) +{ + attrib * a = (attrib*)calloc(1, sizeof(attrib)); + assert(at!=NULL); + a->type = at; + if (at->initialize) at->initialize(a); + return a; +} + +int +a_age(attrib ** p) +{ + attrib ** ap = p; + /* Attribute altern, und die Entfernung (age()==0) eines Attributs + * hat Einfluß auf den Besitzer */ + while(*ap) { + attrib * a = *ap; + if (a->type->age) { + int result = a->type->age(a); + assert(result>=0 || !"age() returned a negative value"); + if (result==0) { + a_remove(p, a); + continue; + } + } + ap = &a->next; + } + return (*p!=NULL); +} + +int +a_read(struct storage * store, attrib ** attribs, void * owner) +{ + int key, retval = AT_READ_OK; + char zText[128]; + strcpy(zText, "unknown"); + + key = -1; + store->r_tok_buf(store, zText, sizeof(zText)); + if (strcmp(zText, "end")==0) return retval; + else key = __at_hashkey(zText); + + while(key!=-1) { + attrib_type * at = at_find(key); + if (!at) { + fprintf(stderr, "attribute hash: %d (%s)\n", key, zText); + assert(at || !"attribute not registered"); + } + if (at->read) { + attrib * na = a_new(at); + int i = at->read(na, owner, store); + switch (i) { + case AT_READ_OK: + a_add(attribs, na); + break; + case AT_READ_FAIL: + retval = AT_READ_FAIL; + a_free(na); + break; + default: + assert(!"invalid return value"); + break; + } + } else { + assert(!"fehler: keine laderoutine für attribut"); + } + + store->r_tok_buf(store, zText, sizeof(zText)); + if (!strcmp(zText, "end")) break; + key = __at_hashkey(zText); + } + return retval; +} + +void +a_write(struct storage * store, const attrib * attribs, const void * owner) +{ + const attrib * na = attribs; + + while(na) { + if (na->type->write) { + assert(na->type->hashkey || !"attribute not registered"); + store->w_tok(store, na->type->name); + na->type->write(na, owner, store); + na = na->next; + } else { + na = na->nexttype; + } + } + store->w_tok(store, "end"); +} diff --git a/src/util/attrib.h b/src/util/attrib.h new file mode 100644 index 000000000..f5c6648fb --- /dev/null +++ b/src/util/attrib.h @@ -0,0 +1,93 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef ATTRIB_H +#define ATTRIB_H +#ifdef __cplusplus +extern "C" { +#endif + +struct storage; +typedef void (*afun)(void); + +typedef struct attrib { + const struct attrib_type * type; + union { + afun f; + void * v; + int i; + float flt; + char c; + short s; + short sa[2]; + char ca[4]; + } data; + /* internal data, do not modify: */ + struct attrib * next; /* next attribute in the list */ + struct attrib * nexttype; /* skip to attribute of a different type */ +} attrib; + +#define ATF_UNIQUE (1<<0) /* only one per attribute-list */ +#define ATF_PRESERVE (1<<1) /* preserve order in list. append to back */ +#define ATF_USER_DEFINED (1<<2) /* use this to make udf */ + +typedef struct attrib_type { + const char* name; + void (*initialize)(struct attrib *); + void (*finalize)(struct attrib *); + int (*age)(struct attrib *); + /* age returns 0 if the attribute needs to be removed, !=0 otherwise */ + void (*write)(const struct attrib *, const void * owner, struct storage *); + int (*read)(struct attrib *, void * owner, struct storage *); /* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */ + unsigned int flags; + /* ---- internal data, do not modify: ---- */ + struct attrib_type * nexthash; + unsigned int hashkey; +} attrib_type; + +extern void at_register(attrib_type * at); + +extern attrib * a_select(attrib * a, const void * data, boolean(*compare)(const attrib *, const void *)); +extern attrib * a_find(attrib * a, const attrib_type * at); +extern const attrib * a_findc(const attrib * a, const attrib_type * at); +extern attrib * a_add(attrib ** pa, attrib * at); +extern int a_remove(attrib ** pa, attrib * at); +extern void a_removeall(attrib ** a, const attrib_type * at); +extern attrib * a_new(const attrib_type * at); +extern void a_free(attrib * a); + +extern int a_age(attrib ** attribs); +extern int a_read(struct storage * store, attrib ** attribs, void * owner); +extern void a_write(struct storage * store, const attrib * attribs, const void * owner); + +#define DEFAULT_AGE NULL +#define DEFAULT_INIT NULL +#define DEFAULT_FINALIZE NULL +#define NO_WRITE NULL +#define NO_READ NULL + +#define AT_READ_OK 0 +#define AT_READ_FAIL -1 + +#define AT_AGE_REMOVE 0 /* remove the attribute after calling age() */ +#define AT_AGE_KEEP 1 /* keep the attribute for another turn */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/base36.c b/src/util/base36.c new file mode 100644 index 000000000..3c795077a --- /dev/null +++ b/src/util/base36.c @@ -0,0 +1,115 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "base36.h" + +#include +#include +#include + +int +atoi36(const char * str) +{ + /* cannot use strtol, because invalid strings will cause crash */ + const unsigned char * s = (const unsigned char *)str; + int i = 0, sign = 1; + assert(s); + if(!(*s)) return 0; + + while(isxspace(*(unsigned char*)s)) ++s; + if (*s == '-') { + sign = -1; + ++s; + } + while(isalnum(*(unsigned char*)s)) { + if (isupper(*(unsigned char*)s)) i = i*36 + (*s)-'A' + 10; + else if (islower(*(unsigned char*)s)) i=i*36 + (*s)-'a' + 10; + else if (isdigit(*(unsigned char*)s)) i=i*36 + (*s)-'0'; + else + break; + ++s; + } + if (i<0) return 0; + return i * sign; +} + +const char* +itoab(int i, int base) +{ + static char **as = NULL; /* STATIC_RETURN: used for return, not across calls */ + char * s, * dst; + static int index = 0; /* STATIC_XCALL: used across calls */ + int neg = 0; + + if (!as) { + int j; + char * x = (char*)calloc(sizeof(char), 8*4); /* STATIC_LEAK: malloc in static variable */ + as = (char **)calloc(sizeof(char*), 4); + for (j=0;j!=4;++j) as[j] = x+j*8; + } + s = as[index]; + index = (index+1) & 3; /* quick for % 4 */ + dst = s+7; + (*dst--)=0; + if (i!=0) { + if (i<0) { + i=-i; + neg = 1; + } + while (i) { + int x = i % base; + i = i / base; + if (x<10) *(dst--) = (char)('0' + x); + else if ('a' + x - 10 == 'l') *(dst--) = 'L'; + else *(dst--) = (char)('a' + (x-10)); + } + if (neg) *(dst) = '-'; + else ++dst; + } + else *dst = '0'; + + return dst; +} + +const char* +itoa36(int i) +{ + return itoab(i, 36); +} + +const char* +itoa10(int i) +{ + return itoab(i, 10); +} + +int +i10toi36(int i) +{ + int r = 0; + while(i) { + r = r*36 + i % 10; + i = i / 10; + } + return r; +} + +#ifndef DISABLE_TESTS +#include "base36_test.c" +#endif diff --git a/src/util/base36.h b/src/util/base36.h new file mode 100644 index 000000000..e11be7ec2 --- /dev/null +++ b/src/util/base36.h @@ -0,0 +1,34 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_UTIL_BASE36 +#define H_UTIL_BASE36 +#ifdef __cplusplus +extern "C" { +#endif + +extern int atoi36(const char * s); +extern const char* itoab(int i, int base); +extern const char* itoa36(int i); +extern const char* itoa10(int i); +extern int i10toi36(int i); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/base36_test.c b/src/util/base36_test.c new file mode 100644 index 000000000..c11847ad7 --- /dev/null +++ b/src/util/base36_test.c @@ -0,0 +1,27 @@ +#include + +static void test_atoi36(CuTest * tc) { + CuAssertIntEquals(tc, 0, atoi36("0")); + CuAssertIntEquals(tc, 666, atoi36("ii")); + CuAssertIntEquals(tc, -10, atoi36("-a")); + CuAssertIntEquals(tc, -1, atoi36("-1")); + CuAssertIntEquals(tc, -10, atoi("-10")); + CuAssertIntEquals(tc, -10, atoi("-10")); +} + +static void test_itoa36(CuTest * tc) { + CuAssertStrEquals(tc, itoa36(0), "0"); + CuAssertStrEquals(tc, itoa10(INT_MAX), "2147483647"); + CuAssertStrEquals(tc, itoab(-1, 5), "-1"); + CuAssertStrEquals(tc, itoa36(-1), "-1"); + CuAssertStrEquals(tc, itoa36(-10), "-a"); + CuAssertStrEquals(tc, itoa36(666), "ii"); +} + +CuSuite* get_base36_suite(void) +{ + CuSuite* suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_itoa36); + SUITE_ADD_TEST(suite, test_atoi36); + return suite; +} diff --git a/src/util/bsdstring.c b/src/util/bsdstring.c new file mode 100644 index 000000000..84802c70e --- /dev/null +++ b/src/util/bsdstring.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include + +#ifndef HAVE_INLINE +#include "bsdstring.h" +#endif + +INLINE_FUNCTION int +wrptr(char ** ptr, size_t * size, int bytes) +{ + assert(bytes>=0 || !"you're not using snprintf right, maybe?"); + + if (bytes==0) { + return 0; + } + if (bytes<0) { + *size = 0; + return EINVAL; + } + if (bytes<=*(int*)size) { + *ptr += bytes; + *size -= bytes; + return 0; + } + + *ptr += *size; + *size = 0; + return ENAMETOOLONG; +} + +#if !defined(HAVE_STRLCPY) +INLINE_FUNCTION size_t +strlcpy(char *dst, const char *src, size_t siz) /* copied from OpenBSD source code */ +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} + + +INLINE_FUNCTION size_t +strlcat(char * dst, const char * src, size_t siz) +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (*d != '\0' && n-- != 0) + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} +#endif diff --git a/src/util/bsdstring.h b/src/util/bsdstring.h new file mode 100644 index 000000000..ca0e94188 --- /dev/null +++ b/src/util/bsdstring.h @@ -0,0 +1,23 @@ +#ifndef UTIL_BSDSTRING_H +#define UTIL_BSDSTRING_H + +#ifdef HAVE_INLINE +# include "bsdstring.c" +#else + extern size_t strlcpy(char *dst, const char *src, size_t siz); + extern size_t strlcat(char * dst, const char * src, size_t siz); + extern int wrptr(char ** ptr, size_t * size, int bytes); +#endif + +#if !defined(HAVE_STRLCPY) +# define HAVE_STRLCPY +#endif + +#define WARN_STATIC_BUFFER() log_warning(("static buffer too small in %s:%d\n", __FILE__, __LINE__)) + +#if !defined(HAVE_STRLPRINTF) +# define HAVE_STRLPRINTF +# define slprintf snprintf +#endif + +#endif diff --git a/src/util/console.c b/src/util/console.c new file mode 100644 index 000000000..62353604a --- /dev/null +++ b/src/util/console.c @@ -0,0 +1,247 @@ +#include +#include "console.h" + +/* lua includes */ +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +/*** Lua Console ***/ +/* +** this macro defines a function to show the prompt and reads the +** next line for manual input +*/ +/* maximum length of an input line */ +#ifndef LUA_MAXINPUT +#define LUA_MAXINPUT 512 +#endif + +#if defined(LUA_USE_READLINE) +#include +#include +#include +#define default_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) +#define lua_saveline(L,idx) \ + if (lua_strlen(L,idx) > 0) /* non-empty line? */ \ + add_history(lua_tostring(L, idx)); /* add it to history */ +#define lua_freeline(L,b) ((void)L, free(b)) +#else +#define default_readline(L,b,p) \ + ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ + fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ +#define lua_saveline(L,idx) { (void)L; (void)idx; } +#define lua_freeline(L,b) { (void)L; (void)b; } +#endif + +static int (*my_readline)(lua_State *l, char *, size_t, const char *prompt) = NULL; +static int lua_readline(lua_State *l, char *b, const char *prompt) +{ + if (my_readline) { + return my_readline(l, b, LUA_MAXINPUT, prompt); + } else { + return default_readline(l, b, prompt); + } +} + +void set_readline(readline foo) { + my_readline = foo; +} + +#ifndef PROMPT +#define PROMPT "E> " +#endif + +#ifndef PROMPT2 +#define PROMPT2 ".. " +#endif + +/* BAD hack, all this action stuff. */ +#define STATESTACK_MAX 16 +static lua_State * state_stack[STATESTACK_MAX]; +int state_stack_top = -1; + +static const char *progname = "eressea"; + +static void +lstop(lua_State *l, lua_Debug *ar) +{ + (void)ar; /* unused arg. */ + lua_sethook(l, NULL, 0, 0); + luaL_error(l, "interrupted!"); +} + +static void +laction(int i) +{ + signal(i, SIG_DFL); /* if another SIGINT happens before lstop, + terminate process (default action) */ + assert(state_stack_top>=0 && state_stack_top'") == NULL) return 0; + + lua_pop(L, 1); + return 1; +} + + +static int pushline (lua_State *L, int firstline) { + char buffer[LUA_MAXINPUT]; + char *b = buffer; + size_t l; + const char *prmt = get_prompt(L, firstline); + if (lua_readline(L, b, prmt) == 0) + return 0; /* no input */ + l = strlen(b); + if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ + b[l-1] = '\0'; /* remove it */ + if (firstline && b[0] == '=') /* first line starts with `=' ? */ + lua_pushfstring(L, "return %s", b+1); /* change it to `return' */ + else + lua_pushstring(L, b); + lua_freeline(L, b); + return 1; +} + + +static int loadline (lua_State *L) { + int status; + lua_settop(L, 0); + if (!pushline(L, 1)) + return -1; /* no input */ + for (;;) { /* repeat until gets a complete line */ + status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); + if (!incomplete(L, status)) break; /* cannot try to add lines? */ + if (!pushline(L, 0)) /* no more input? */ + return -1; + lua_pushliteral(L, "\n"); /* add a new line... */ + lua_insert(L, -2); /* ...between the two lines */ + lua_concat(L, 3); /* join them */ + } + lua_saveline(L, 1); + lua_remove(L, 1); /* remove line */ + return status; +} + +static void dotty (lua_State *L) { + int status; + const char *oldprogname = progname; + progname = NULL; + while ((status = loadline(L)) != -1) { + if (status == 0) status = docall(L, 0, 0); + report(L, status); + if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ + lua_getglobal(L, "print"); + lua_insert(L, 1); + if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) + l_message(progname, lua_pushfstring(L, + "error calling " LUA_QL("print") " (%s)", + lua_tostring(L, -1))); + } + } + lua_settop(L, 0); /* clear stack */ + fputs("\n", stdout); + fflush(stdout); + progname = oldprogname; +} + +int +lua_console(lua_State * L) +{ + dotty(L); + return 0; +} + +int +lua_do(lua_State * L) +{ + int status = loadline(L); + if (status != -1) { + if (status == 0) status = docall(L, 0, 0); + report(L, status); + if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ + lua_getglobal(L, "print"); + lua_insert(L, 1); + if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) + l_message(NULL, lua_pushfstring(L, "error calling `print' (%s)", + lua_tostring(L, -1))); + } + } + lua_settop(L, 0); /* clear stack */ + return 0; +} diff --git a/src/util/console.h b/src/util/console.h new file mode 100644 index 000000000..d5821135b --- /dev/null +++ b/src/util/console.h @@ -0,0 +1,37 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_LUA_CONSOLE +#define H_LUA_CONSOLE +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + + extern int lua_console(struct lua_State * L); + extern int lua_do(struct lua_State * L); + + typedef int (*readline)(struct lua_State *, char *, size_t, const char *); + extern void set_readline(readline foo); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/util/crmessage.c b/src/util/crmessage.c new file mode 100644 index 000000000..6cb1ba349 --- /dev/null +++ b/src/util/crmessage.c @@ -0,0 +1,159 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + +*/ + +#include +#include "crmessage.h" + +#include "message.h" +#include "goodies.h" +#include "log.h" + +#include +#include +#include +#include + +/** type to string conversion **/ +typedef struct tsf_list { + struct tsf_list * next; + const char * name; + tostring_f fun; +} tsf_list; + +static tsf_list * tostringfs; + +static tostring_f +tsf_find(const char * name) +{ + if (name!=NULL) { + tsf_list * tsf; + for (tsf=tostringfs;tsf;tsf=tsf->next) { + if (!strcmp(tsf->name, name)) return tsf->fun; + } + } + return NULL; +} + +void +tsf_register(const char * name, tostring_f fun) +{ + tsf_list * tsf; + for (tsf=tostringfs;tsf;tsf=tsf->next) { + if (!strcmp(tsf->name, name)) break; + } + if (tsf==NULL) { + tsf = malloc(sizeof(tsf_list)); + tsf->fun = fun; + tsf->name = name; + tsf->next = tostringfs; + tostringfs = tsf; + } +} + +/** crmesssage **/ +typedef struct crmessage_type { + const struct message_type * mtype; + tostring_f * renderers; + struct crmessage_type * next; +} crmessage_type; + +#define CRMAXHASH 63 +static crmessage_type * crtypes[CRMAXHASH]; + +static crmessage_type * +crt_find(const struct message_type * mtype) +{ + unsigned int hash = hashstring(mtype->name) % CRMAXHASH; + crmessage_type * found = NULL; + crmessage_type * type = crtypes[hash]; + while (type) { + if (type->mtype==mtype) found = type; + type = type->next; + } + return found; +} + +void +crt_register(const struct message_type * mtype) +{ + unsigned int hash = hashstring(mtype->name) % CRMAXHASH; + crmessage_type * crt = crtypes[hash]; + while (crt && crt->mtype!=mtype) { + crt = crt->next; + } + if (!crt) { + int i; + crt = malloc(sizeof(crmessage_type)); + crt->mtype = mtype; + crt->next = crtypes[hash]; + crtypes[hash] = crt; + if(mtype->nparameters > 0) { + crt->renderers = malloc(sizeof(tostring_f)*mtype->nparameters); + } else { + crt->renderers = NULL; + } + + /* can be scrapped for memory vs. speed */ + for (i=0;i!=mtype->nparameters;++i) { + crt->renderers[i] = tsf_find(mtype->types[i]->name); + } + } +} + +int +cr_render(const message * msg, char * buffer, const void * userdata) +{ + int i; + char * c = buffer; + struct crmessage_type * crt = crt_find(msg->type); + + if (crt==NULL) return -1; + for (i=0;i!=msg->type->nparameters;++i) { + if (crt->renderers[i]==NULL) { + log_error(("No renderer for argument %s:%s of \"%s\"\n", + msg->type->pnames[i], msg->type->types[i]->name, msg->type->name)); + continue; /* strcpy(c, (const char*)msg->locale_string(u->faction->locale, parameters[i])); */ + } else { + if (crt->renderers[i](msg->parameters[i], c, userdata)!=0) continue; + } + c += strlen(c); + sprintf(c, ";%s\n", msg->type->pnames[i]); + c += strlen(c); + } + return 0; +} + +int +cr_string(variant var, char * buffer, const void * userdata) +{ + sprintf(buffer, "\"%s\"", (const char *)var.v); + unused(userdata); + return 0; +} + +int +cr_int(variant var, char * buffer, const void * userdata) +{ + sprintf(buffer, "%d", var.i); + unused(userdata); + return 0; +} + +int +cr_ignore(variant var, char * buffer, const void * userdata) +{ + unused(var); + unused(buffer); + unused(userdata); + return -1; +} diff --git a/src/util/crmessage.h b/src/util/crmessage.h new file mode 100644 index 000000000..7861aaffe --- /dev/null +++ b/src/util/crmessage.h @@ -0,0 +1,39 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_UTIL_CRMESSAGE +#define H_UTIL_CRMESSAGE + +#include "variant.h" +#ifdef __cplusplus +extern "C" { +#endif + +struct locale; +struct message; +struct message_type; + +typedef int (*tostring_f)(variant data, char * buffer, const void * userdata); +extern void tsf_register(const char * name, tostring_f fun); + /* registers a new type->string-function */ + +extern int cr_string(variant v, char * buffer, const void * userdata); +extern int cr_int(variant v, char * buffer, const void * userdata); +extern int cr_ignore(variant v, char * buffer, const void * userdata); + +extern void crt_register(const struct message_type * mtype); +extern int cr_render(const struct message * msg, char * buffer, const void * userdata); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/cvector.c b/src/util/cvector.c new file mode 100644 index 000000000..27c395908 --- /dev/null +++ b/src/util/cvector.c @@ -0,0 +1,97 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "cvector.h" +#include "rng.h" + +#include +#include +#include +#include + +void +cv_init(cvector * cv) +{ + cv->begin = 0; + cv->end = 0; + cv->space = 0; +} + +cvector * +cv_kill(cvector * cv) +{ + if (cv->begin) free(cv->begin); + cv_init(cv); + return cv; +} + +size_t +cv_size(cvector * cv) +{ + return cv->end - cv->begin; +} + +void +cv_reserve(cvector * cv, size_t size) +{ + size_t count = cv->end - cv->begin; + cv->begin = realloc(cv->begin, size * sizeof(void *)); + + cv->space = size; + cv->end = cv->begin + count; +} + +void +cv_pushback(cvector * cv, void *u) +{ + if (cv->space == cv_size(cv)) + cv_reserve(cv, cv->space ? cv->space * 2 : 2); + *(cv->end++) = u; +} + +int +__cv_scramblecmp(const void *p1, const void *p2) +{ + return *((long *) p1) - *((long *) p2); +} + +#define addptr(p,i) ((void *)(((char *)p) + i)) + +/** randomly shuffle an array + * for correctness, see Donald E. Knuth, The Art of Computer Programming + */ +static void +__cv_scramble(void *v1, size_t n, size_t width) +{ + size_t i; + void * temp = malloc(width); + for (i=0;i!=n;++i) { + size_t j = i + (rng_int() % (n-i)); + memcpy(temp, addptr(v1, i*width), width); + memcpy(addptr(v1, i*width), addptr(v1, j*width), width); + memcpy(addptr(v1, j*width), temp, width); + } + free(temp); +} + +void +v_scramble(void **begin, void **end) +{ + __cv_scramble(begin, end - begin, sizeof(void *)); +} diff --git a/src/util/cvector.h b/src/util/cvector.h new file mode 100644 index 000000000..c0e50944d --- /dev/null +++ b/src/util/cvector.h @@ -0,0 +1,61 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CVECTOR_H +#define CVECTOR_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WIN32 +#ifndef __cdecl +#define __cdecl +#endif +#endif + +#include +typedef struct cvector cvector; + +struct cvector { + void **begin; + void **end; + size_t space; +}; + +typedef int (__cdecl * v_sort_fun) (const void *, const void *); + +void cv_init(cvector * cv); +cvector *cv_kill(cvector * cv); +size_t cv_size(cvector * cv); +void cv_reserve(cvector * cv, size_t size); +void cv_pushback(cvector * cv, void *u); +void v_scramble(void **begin, void **end); + +#define cv_remove(c, i) { void** x = v_find((c)->begin, (c)->end, (i)); if (x) { *x = *(c)->end; (c)->end--; } } +#define cv_foreach(item, vector) \ +{ \ + void **iterator; \ + for (iterator = (vector).begin; iterator<(vector).end; ++iterator) \ + { \ + (item) = *iterator; +#define cv_next(item) } } + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/dice.c b/src/util/dice.c new file mode 100644 index 000000000..bf8593d0c --- /dev/null +++ b/src/util/dice.c @@ -0,0 +1,97 @@ +/* vi: set ts=2: + * + * + * Eressea PB(E)M host Copyright (C) 1998 + * Enno Rehling (rehling@usa.net) + * Christian Schlittchen (corwin@amber.kn-bremen.de) + * Katja Zedel (katze@felidae.kn-bremen.de) + * Henning Peters (faroul@beyond.kn-bremen.de) + * + * based on: + * + * Atlantis v1.0 13 September 1993 Copyright 1993 by Russell Wallace + * Atlantis v1.7 Copyright 1996 by Alex Schröder + * + * This program may not be used, modified or distributed. It may not be + * sold or used commercially without prior written permission from the + * authors. + */ + +#include +#include "rng.h" + +#include +#include +#include + +/** rolls a number of n-sided dice. + * Usage: 3d6-3d4+5 = dice(3,6)-dice(3,4)+5 */ +int +dice(int count, int value) +{ + int d = 0, c; + + if (value<=0) return 0; /* (enno) %0 geht nicht. echt wahr. */ + if (count >= 0) + for (c = count; c > 0; c--) + d += rng_int() % value + 1; + else + for (c = count; c < 0; c++) + d -= rng_int() % value + 1; + + return d; +} + +static int +term_eval(const char **sptr) +{ + const char *c = *sptr; + int m = 0, d = 0, k = 0, term = 1, multi = 1; + int state = 1; + + for (;;) { + if (isdigit(*(unsigned char*)c)) { + k = k*10+(*c-'0'); + } + else if (*c=='+' || *c=='-' || *c==0 || *c=='*' || *c==')' || *c=='(') { + if (state==1) /* konstante k addieren */ + m+=k*multi; + else if (state==2) { /* dDk */ + int i; + if (k == 0) k = 6; /* 3d == 3d6 */ + for (i=0;i!=d;++i) m += (1 + rng_int() % k)*multi; + } + else assert(!"dice_rand: illegal token"); + if (*c=='*') { + term *= m; + m = 0; + } + k = d = 0; + state = 1; + multi = (*c=='-')?-1:1; + + if (*c=='(') { + ++c; + k = term_eval(&c); + } + else if (*c==0 || *c==')') { + break; + } + } else if (*c=='d' || *c=='D') { + if (k==0) k = 1; /* d9 == 1d9 */ + assert(state==1 || !"dice_rand: illegal token"); + d = k; + k = 0; + state=2; + } + c++; + } + *sptr = c; + return m*term; +} + +int +dice_rand(const char *s) +{ + return term_eval(&s); +} diff --git a/src/util/event.c b/src/util/event.c new file mode 100644 index 000000000..50f652ec2 --- /dev/null +++ b/src/util/event.c @@ -0,0 +1,270 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "event.h" + +/* util includes */ +#include "attrib.h" +#include "log.h" +#include "storage.h" + +/* libc includes */ +#include +#include +#include +#include + +void +write_triggers(struct storage * store, const trigger * t) +{ + while (t) { + if (t->type->write) { + store->w_tok(store, t->type->name); + t->type->write(t, store); + } + t = t->next; + } + store->w_tok(store, "end"); +} + +int +read_triggers(struct storage * store, trigger ** tp) +{ + for (;;) { + trigger_type * ttype; + char zText[128]; + + store->r_tok_buf(store, zText, sizeof(zText)); + if (!strcmp(zText, "end")) break; + ttype = tt_find(zText); + assert(ttype || !"unknown trigger-type"); + *tp = t_new(ttype); + if (ttype->read) { + int i = ttype->read(*tp, store); + switch (i) { + case AT_READ_OK: + tp = &(*tp)->next; + break; + case AT_READ_FAIL: + t_free(*tp); + *tp = NULL; + break; + default: + assert(!"invalid return value"); + break; + } + } + } + return 0; +} + +trigger * +t_new(trigger_type * ttype) +{ + trigger * t = calloc(sizeof(trigger), 1); + t->type=ttype; + if (ttype->initialize) ttype->initialize(t); + return t; +} + +void +t_free(trigger * t) +{ + if (t->type->finalize) t->type->finalize(t); +} + +void +free_triggers(trigger * triggers) +{ + while (triggers) { + trigger * t = triggers; + triggers = t->next; + t_free(t); + } +} + +int +handle_triggers(trigger ** triggers, void * param) +{ + trigger ** tp = triggers; + while (*tp) { + trigger * t = *tp; + if (t->type->handle(t, param)!=0) { + *tp=t->next; + t_free(t); + } + else tp=&t->next; + } + return (*triggers!=NULL); +} + +/*** + ** at_eventhandler + **/ + +typedef struct handler_info { + char * event; + trigger * triggers; +} handler_info; + +static void +init_handler(attrib * a) { + a->data.v = calloc(sizeof(handler_info), 1); +} + +static void +free_handler(attrib * a) { + handler_info *hi = (handler_info*)a->data.v; + free_triggers(hi->triggers); + free(hi->event); + free(hi); +} + +static void +write_handler(const attrib * a, const void * owner, struct storage * store) +{ + handler_info *hi = (handler_info*)a->data.v; + store->w_tok(store, hi->event); + write_triggers(store, hi->triggers); +} + +static int +read_handler(attrib * a, void * owner, struct storage * store) +{ + char zText[128]; + handler_info *hi = (handler_info*)a->data.v; + + store->r_tok_buf(store, zText, sizeof(zText)); + hi->event = strdup(zText); + read_triggers(store, &hi->triggers); + if (hi->triggers!=NULL) { + return AT_READ_OK; + } + return AT_READ_FAIL; +} + +attrib_type at_eventhandler = { + "eventhandler", + init_handler, + free_handler, + NULL, + write_handler, + read_handler +}; + +struct trigger ** +get_triggers(struct attrib * ap, const char * eventname) +{ + handler_info * td = NULL; + attrib * a = a_find(ap, &at_eventhandler); + while (a!=NULL && a->type==&at_eventhandler) { + td = (handler_info *)a->data.v; + if (strcmp(td->event, eventname)==0) { + return &td->triggers; + } + a = a->next; + } + return NULL; +} + +void +add_trigger(struct attrib ** ap, const char * eventname, struct trigger * t) +{ + trigger ** tp; + handler_info * td = NULL; + attrib * a = a_find(*ap, &at_eventhandler); + assert(t->next==NULL); + while (a!=NULL && a->type==&at_eventhandler) { + td = (handler_info *)a->data.v; + if (!strcmp(td->event, eventname)) { + break; + } + a = a->next; + } + if (a==NULL || a->type!=&at_eventhandler) { + a = a_add(ap, a_new(&at_eventhandler)); + td = (handler_info *)a->data.v; + td->event = strdup(eventname); + } + tp = &td->triggers; + while (*tp) tp=&(*tp)->next; + *tp = t; +} + +void +handle_event(attrib * attribs, const char * eventname, void * data) +{ + while (attribs) { + if (attribs->type==&at_eventhandler) break; + attribs = attribs->nexttype; + } + while (attribs && attribs->type==&at_eventhandler) { + handler_info * tl = (handler_info*)attribs->data.v; + if (!strcmp(tl->event, eventname)) { + handler_info * tl = (handler_info*)attribs->data.v; + handle_triggers(&tl->triggers, data); + break; + } + attribs = attribs->next; + } +} + +void +t_add(struct trigger ** tlist, struct trigger * t) +{ + while (*tlist) tlist = &(*tlist)->next; + *tlist = t; +} + +static trigger_type * triggertypes; + +void +tt_register(trigger_type * tt) +{ + tt->next = triggertypes; + triggertypes = tt; +} + +trigger_type * +tt_find(const char * name) +{ + trigger_type * tt = triggertypes; + while (tt && strcmp(tt->name, name)) tt = tt->next; + return tt; +} + +void +remove_triggers(struct attrib ** ap, const char * eventname, const trigger_type * tt) +{ + trigger ** tp = get_triggers(*ap, eventname); + if(tp == NULL) return; + while (*tp) { + /* first, remove all gate-triggers */ + trigger * t = *tp; + if (t->type == tt) { + *tp = t->next; + t_free(t); + } else tp = &t->next; + } +} + +/*** + ** default events + **/ + diff --git a/src/util/event.h b/src/util/event.h new file mode 100644 index 000000000..23f272952 --- /dev/null +++ b/src/util/event.h @@ -0,0 +1,80 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef EVENT_H +#define EVENT_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "variant.h" + +struct attrib; +struct trigger; +struct storage; + +typedef struct trigger_type { + const char * name; + void (*initialize)(struct trigger *); + void (*finalize)(struct trigger *); + int (*handle)(struct trigger *, void *); + void (*write)(const struct trigger *, struct storage * store); + int (*read)(struct trigger *, struct storage * store); + + struct trigger_type * next; +} trigger_type; + +extern trigger_type * tt_find(const char * name); +extern void tt_register(trigger_type * ttype); + +typedef struct trigger { + struct trigger_type * type; + struct trigger * next; + + variant data; +} trigger; + +typedef struct event_arg { + const char * type; + variant data; +} event_arg; + +extern trigger * t_new(trigger_type * ttype); +extern void t_free(trigger * t); +extern void t_add(trigger ** tlist, trigger * t); +/** add and handle triggers **/ + +/* add a trigger to a list of attributes */ +extern void add_trigger(struct attrib ** ap, const char * eventname, struct trigger * t); +extern void remove_triggers(struct attrib ** ap, const char * eventname, const trigger_type * tt); +extern struct trigger ** get_triggers(struct attrib * ap, const char * eventname); +/* calls handle() for each of these. e.g. used in timeout */ +extern void handle_event(struct attrib * attribs, const char * eventname, void * data); + +/* functions for making complex triggers: */ +extern void free_triggers(trigger * triggers); /* release all these triggers */ +extern void write_triggers(struct storage * store, const trigger * t); +extern int read_triggers(struct storage * store, trigger ** tp); +extern int handle_triggers(trigger ** triggers, void * data); + +extern struct attrib_type at_eventhandler; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/eventbus.c b/src/util/eventbus.c new file mode 100644 index 000000000..77e81b578 --- /dev/null +++ b/src/util/eventbus.c @@ -0,0 +1,56 @@ +#include +#include "eventbus.h" + +/* +** first iteration. it is slow, and a proof of the concept - the simplest +** thing that would work, a.k.a. should be refectored when required. +*/ + +typedef struct listener { + struct listener * next; + event_handler callback; + event_arg_free destroy; + void * sender; + char * event; + void * arguments; +} listener; + +static listener * listeners; + +void +eventbus_fire(void * sender, const char * event, void * args) +{ + listener * lst = listeners; + while (lst) { + int i = strcmp(lst->event, event); + if (i>0) break; + if (i==0) { + if (!lst->sender || lst->sender==sender) { + lst->callback(sender, event, args); + } + } + lst = lst->next; + } +} + +void +eventbus_register(void * sender, const char * event, event_handler cb, event_arg_free arg_free, void * args) +{ + listener * lst; + listener ** lstp = &listeners; + while (*lstp) { + lst = *lstp; + if (strcmp(lst->event, event)>=0) { + break; + } + lstp=&lst->next; + } + lst = malloc(sizeof(listener)); + lst->sender = sender; + lst->arguments = args; + lst->callback = cb; + lst->destroy = arg_free; + lst->event = strdup(event); + lst->next = *lstp; + *lstp = lst; +} diff --git a/src/util/eventbus.h b/src/util/eventbus.h new file mode 100644 index 000000000..b217c686c --- /dev/null +++ b/src/util/eventbus.h @@ -0,0 +1,29 @@ +/* vi: set ts=2: + +-------------------+ + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2010 | Christian Schlittchen + | | + +-------------------+ + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_UTIL_EVTBUS +#define H_UTIL_EVTBUS + + +#ifdef __cplusplus +extern "C" { +#endif + + typedef void (*event_handler)(void *, const char *, void *); + typedef void (*event_arg_free)(void *); + void eventbus_fire(void * sender, const char * event, void * args); + void eventbus_register(void * sender, const char * event, event_handler callback, event_arg_free arg_free, void * args); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/filereader.c b/src/util/filereader.c new file mode 100644 index 000000000..26c745851 --- /dev/null +++ b/src/util/filereader.c @@ -0,0 +1,314 @@ +#include +#include "filereader.h" + +#include +#include + +#include + +#include +#include + +#define COMMENT_CHAR ';' +#define CONTINUE_CHAR '\\' +#define MAXLINE 4096*16 +static char lbuf[MAXLINE]; +static char fbuf[MAXLINE]; + +static void +unicode_warning(const char * bp) +{ + log_warning(("invalid sequence in UTF-8 string: %s\n", bp)); +} + +INLINE_FUNCTION int +eatwhite(const char * ptr, size_t * total_size) +{ + int ret = 0; + + *total_size = 0; + + while (*ptr) { + ucs4_t ucs; + size_t size = 0; + ret = unicode_utf8_to_ucs4(&ucs, ptr, &size); + if (ret!=0) break; + if (!iswxspace((wint_t)ucs)) break; + *total_size += size; + ptr += size; + } + return ret; +} + +static const char * +getbuf_latin1(FILE * F) +{ + boolean cont = false; + char quote = 0; + boolean comment = false; + char * cp = fbuf; + char * tail = lbuf+MAXLINE-2; + + tail[1] = '@'; /* if this gets overwritten by fgets then the line was very long. */ + do { + const char * bp = fgets(lbuf, MAXLINE, F); + + if (bp==NULL) return NULL; + while (*bp && isxspace(*(unsigned char*)bp)) ++bp; /* eatwhite */ + + comment = (boolean)(comment && cont); + + if (tail[1]==0) { + /* we read he maximum number of bytes! */ + if (tail[0]!='\n') { + /* it wasn't enough space to finish the line, eat the rest */ + for (;;) { + tail[1] = '@'; + bp = fgets(lbuf, MAXLINE, F); + if (bp==NULL) return NULL; + if (tail[1]) { + /* read enough this time to end the line */ + break; + } + } + comment = false; + cont = false; + bp = NULL; + continue; + } else { + tail[1] = '@'; + } + } + cont = false; + while (*bp && cp0) cp+=ret; + else { + log_error(("input data was not iso-8859-1! assuming utf-8\n")); + return NULL; + } + + ++bp; + continue; + } + } + if (cp==fbuf+MAXLINE) { + --cp; + } + *cp=0; + } while (cont || cp==fbuf); + return fbuf; +} + +static const char * +getbuf_utf8(FILE * F) +{ + boolean cont = false; + char quote = 0; + boolean comment = false; + char * cp = fbuf; + char * tail = lbuf+MAXLINE-2; + + tail[1] = '@'; /* if this gets overwritten by fgets then the line was very long. */ + do { + const char * bp = fgets(lbuf, MAXLINE, F); + size_t white; + if (bp==NULL) { + return NULL; + } + + eatwhite(bp, &white); /* decoding errors will get caught later on, don't have to check */ + bp += white; + + comment = (boolean)(comment && cont); + + if (tail[1]==0) { + /* we read he maximum number of bytes! */ + if (tail[0]!='\n') { + /* it wasn't enough space to finish the line, eat the rest */ + for (;;) { + tail[1] = '@'; + bp = fgets(lbuf, MAXLINE, F); + if (bp==NULL) return NULL; + if (tail[1]) { + /* read enough this time to end the line */ + break; + } + } + comment = false; + cont = false; + bp = NULL; + continue; + } else { + tail[1] = '@'; + } + } + cont = false; + while (*bp && cp +* | | Enno Rehling +* | Eressea PBEM host | Katja Zedel +* | (c) 1998 - 2005 | +* | | This program may not be used, modified or distributed +* +-------------------+ without prior permission by the authors of Eressea. +* +*/ +#ifndef UTIL_FILEREADER_H +#define UTIL_FILEREADER_H +#ifdef __cplusplus +extern "C" { +#endif + +const char * getbuf(FILE *, int encoding); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/functions.c b/src/util/functions.c new file mode 100644 index 000000000..81b9face6 --- /dev/null +++ b/src/util/functions.c @@ -0,0 +1,74 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "functions.h" + +/* libc includes */ +#include +#include + + + +typedef struct function_list { + struct function_list * next; + pf_generic fun; + const char * name; +} function_list; + +static function_list * functionlist; + +pf_generic +get_function(const char * name) +{ + function_list * fl = functionlist; + if (name==NULL) return NULL; + while (fl && strcmp(fl->name, name)!=0) fl=fl->next; + if (fl) return fl->fun; + return NULL; +} + +const char * +get_functionname(pf_generic fun) +{ + function_list * fl = functionlist; + while (fl && fl->fun!=fun) fl=fl->next; + if (fl) return fl->name; + return NULL; +} + +void +register_function(pf_generic fun, const char * name) +{ + function_list * fl = calloc(sizeof(function_list), 1); + fl->next = functionlist; + fl->fun = fun; + fl->name = strdup(name); + functionlist = fl; +} + +void +list_registered_functions(void) +{ + function_list * fl = functionlist; + + while(fl) { + printf("%s\n", fl->name); + fl = fl->next; + } +} diff --git a/src/util/functions.h b/src/util/functions.h new file mode 100644 index 000000000..f8fd090a6 --- /dev/null +++ b/src/util/functions.h @@ -0,0 +1,35 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef FUNCTIONS_H +#define FUNCTIONS_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*pf_generic)(void); + +extern const char *get_functionname(pf_generic fun); +extern pf_generic get_function(const char * name); +extern void register_function(pf_generic fun, const char * name); +extern void list_registered_functions(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/goodies.c b/src/util/goodies.c new file mode 100644 index 000000000..231bbd9e9 --- /dev/null +++ b/src/util/goodies.c @@ -0,0 +1,128 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "goodies.h" + +#include "unicode.h" + +/* libc includes */ +#include +#include +#include + +/* Simple Integer-Liste */ + +int * +intlist_init(void) +{ + return (calloc(1, sizeof(int))); +} + +int * +intlist_add(int *i_p, int i) +{ + i_p[0]++; + i_p = realloc(i_p, (i_p[0]+1) * sizeof(int)); + + i_p[i_p[0]] = i; + return (i_p); +} + +int * +intlist_find(int *i_p, int fi) +{ + int i; + + for(i=1; i <= i_p[0]; i++) { + if(i_p[i] == fi) return (&i_p[i]); + } + return NULL; +} + +char * +set_string (char **s, const char *neu) +{ + if (neu==NULL) { + free(*s); + *s = NULL; + } else if (*s == NULL) { + *s = malloc(strlen(neu)+1); + strcpy(*s, neu); + } else { + *s = realloc(*s, strlen(neu) + 1); + strcpy(*s, neu); + } + return *s; +} + + +static int +spc_email_isvalid(const char *address) +{ + int count = 0; + const char *c, *domain; + static const char *rfc822_specials = "()<>@,;:\\\"[]"; /* STATIC_CONST: contains a constant value */ + + /* first we validate the name portion (name@domain) */ + for (c = address; *c; c++) { + if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == + '\"')) { + while (*++c) { + if (*c == '\"') break; + if (*c == '\\' && (*++c == ' ')) continue; + if (*c <= ' ' || *c >= 127) return 0; + } + if (!*c++) return 0; + if (*c == '@') break; + if (*c != '.') return 0; + continue; + } + if (*c == '@') break; + if (*c <= ' ' || *c >= 127) return 0; + if (strchr(rfc822_specials, *c)) return 0; + } + if (c == address || *(c - 1) == '.') return 0; + + /* next we validate the domain portion (name@domain) */ + if (!*(domain = ++c)) return 0; + do { + if (*c == '.') { + if (c == domain || *(c - 1) == '.') return 0; + count++; + } + if (*c <= ' ' || *c >= 127) return 0; + if (strchr(rfc822_specials, *c)) return 0; + } while (*++c); + + return (count >= 1); +} + +int +set_email(char** pemail, const char *newmail) +{ + if (newmail && *newmail) { + if (spc_email_isvalid(newmail)<=0) return -1; + } + if (*pemail) free(*pemail); + *pemail = 0; + if (newmail) { + *pemail = strdup(newmail); + } + return 0; +} diff --git a/src/util/goodies.h b/src/util/goodies.h new file mode 100644 index 000000000..aabf0cb4b --- /dev/null +++ b/src/util/goodies.h @@ -0,0 +1,63 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef GOODIES_H +#define GOODIES_H +#ifdef __cplusplus +extern "C" { +#endif + +extern char * set_string(char **s, const char *neu); +extern int set_email(char** pemail, const char *newmail); + +extern int *intlist_init(void); +extern int *intlist_add(int *i_p, int i); +extern int *intlist_find(int *i_p, int i); + +#ifdef HAVE_INLINE +# include "strings.c" +#else +extern unsigned int hashstring(const char* s); +extern const char *escape_string(const char * str, char * buffer, unsigned int len); +extern unsigned int jenkins_hash(unsigned int a); +extern unsigned int wang_hash(unsigned int a); +#endif + +/* benchmark for units: + * JENKINS_HASH: 5.25 misses/hit (with good cache behavior) + * WANG_HASH: 5.33 misses/hit (with good cache behavior) + * KNUTH_HASH: 1.93 misses/hit (with bad cache behavior) + * CF_HASH: fucking awful! + */ +#define KNUTH_HASH1(a, m) ((a) % m) +#define KNUTH_HASH2(a, m) (m - 2 - a % (m-2)) +#define CF_HASH1(a, m) ((a) % m) +#define CF_HASH2(a, m) (8 - ((a) & 7)) +#define JENKINS_HASH1(a, m) (jenkins_hash(a) % m) +#define JENKINS_HASH2(a, m) 1 +#define WANG_HASH1(a, m) (wang_hash(a) % m) +#define WANG_HASH2(a, m) 1 + +#define HASH1 JENKINS_HASH1 +#define HASH2 JENKINS_HASH2 + +#define SWAP_VARS(T, a, b) { T x = a; a = b; b = x; } +#ifdef __cplusplus +} +#endif +#endif /* GOODIES_H */ diff --git a/src/util/graph.c b/src/util/graph.c new file mode 100644 index 000000000..9ea181466 --- /dev/null +++ b/src/util/graph.c @@ -0,0 +1,203 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + */ + +/* This is a very simple graph library. It is not optimized in any + way, and relies heavily on the vset and stack routines. */ + +#include +#include "vset.h" +#include "graph.h" + +void +graph_init(graph *g) +{ + vset_init(&g->nodes); + vset_init(&g->edges); +} + +void +graph_free(graph *g) +{ + vset_destroy(&g->nodes); + vset_destroy(&g->edges); +} + +void +graph_add_node(graph *g, node *n) +{ + vset_add(&g->nodes, n); +} + +void +graph_add_edge(graph *g, edge *v) +{ + vset_add(&g->nodes, v); +} + +void +graph_remove_node(graph *g, node *n) +{ + unsigned int i; + + for(i=0; i != g->edges.size; ++i) { + edge *v = g->edges.data[i]; + if(v->node1 == n || v->node2 == n) { + vset_erase(&g->nodes, v); + i--; + } + } + vset_erase(&g->nodes, n); +} + +node * +graph_find_node(graph *g, void *object) +{ + unsigned int i; + + for(i=0; i != g->nodes.size; ++i) { + node *node = g->nodes.data[i]; + if(node->object == object) { + return g->nodes.data[i]; + } + } + return NULL; +} + +/* The vset returned has to freed externally, else this will be a + memory leak. */ + +vset * +graph_neighbours(graph *g, node *n) +{ + unsigned int i; + vset * vs = malloc(sizeof(vs)); + vset_init(vs); + for(i=0; i != g->edges.size; ++i) { + edge *v = g->edges.data[i]; + if(v->node1 == n && vset_count(vs, v->node2) == 0) { + vset_add(vs, v->node2); + } else if(v->node2 == n && vset_count(vs, v->node1) == 0) { + vset_add(vs, v->node1); + } + } + + return vs; +} + +void +graph_resetmarkers(graph *g) +{ + unsigned int i; + + for(i=0; i != g->nodes.size; ++i) { + node *node = g->nodes.data[i]; + node->marker = 0; + } + for(i=0; i != g->edges.size; ++i) { + edge *edge = g->edges.data[i]; + edge->marker = 0; + } +} + +/* The vset returned has to freed externally, else this will be a + memory leak. */ + +vset * +graph_connected_nodes(graph *g, node *n) +{ + vset * vs = malloc(sizeof(vset)); + vset s; + + vset_init(vs); + vset_init(&s); + graph_resetmarkers(g); + vset_add(vs, n); + n->marker = 1; + vset_add(&s, n); + while(s.size > 0) { + node *n = vset_pop(&s); + vset *vs_nb = graph_neighbours(g, n); + unsigned int i; + for(i=0; i != vs_nb->size; ++i) { + node *nb = vs_nb->data[i]; + if(nb->marker == 0) { + nb->marker = 1; + vset_add(vs, nb); + vset_add(&s, nb); + } + } + vset_destroy(vs_nb); + free(vs_nb); + } + + vset_destroy(&s); + + return vs; +} + +/* The vset returned has to freed externally, else this will be a + memory leak. */ + +vset * +graph_disjunct_graphs(graph *g) +{ + vset * dg = malloc(sizeof(vset)); + vset nodes; + + vset_init(dg); + vset_init(&nodes); + vset_concat(&nodes, &g->nodes); + + while(nodes.size > 0) { + graph *gt = malloc(sizeof(graph)); + vset s; + unsigned int i; + node *start; + + graph_init(gt); + start = vset_pop(&nodes); + graph_resetmarkers(g); + graph_add_node(gt, start); + start->marker = 1; + vset_init(&s); + vset_add(&s,start); + while(s.size > 0) { + vset * nbs = graph_neighbours(g,vset_pop(&s)); + for(i=0; i != nbs->size; ++i) { + node *nb = nbs->data[i]; + if(nb->marker == 0) { + nb->marker = 1; + graph_add_node(gt,nb); + vset_erase(&nodes,nb); + vset_add(&s,nb); + } + } + vset_destroy(nbs); free(nbs); + } + + vset_destroy(&s); + + for(i=0;i != g->edges.size; ++i) { + edge *v = g->edges.data[i]; + if(vset_count(&g->nodes, v->node1)) { + graph_add_edge(gt, v); + } + } + + vset_add(dg, gt); + } + + vset_destroy(&nodes); + + return dg; +} + diff --git a/src/util/graph.h b/src/util/graph.h new file mode 100644 index 000000000..e5480d1ab --- /dev/null +++ b/src/util/graph.h @@ -0,0 +1,38 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + */ + +#ifndef GRAPH_H +#define GRAPH_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct node { + int marker; + void *object; +} node; + +typedef struct edge { + int marker; + node *node1; + node *node2; +} edge; + +typedef struct graph { + vset nodes; + vset edges; +} graph; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/language.c b/src/util/language.c new file mode 100644 index 000000000..298cf92b0 --- /dev/null +++ b/src/util/language.c @@ -0,0 +1,252 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "language.h" +#include "language_struct.h" + +#include "log.h" +#include "goodies.h" +#include "umlaut.h" + +#include +#include +#include +#include + +/** importing **/ + +locale * default_locale; +locale * locales; + +unsigned int +locale_hashkey(const locale * lang) +{ + assert(lang); + return lang->hashkey; +} + +locale * +find_locale(const char * name) +{ + unsigned int hkey = hashstring(name); + locale * l = locales; + while (l && l->hashkey!=hkey) l=l->next; + return l; +} + +static int nextlocaleindex = 0; + +locale * +make_locale(const char * name) +{ + unsigned int hkey = hashstring(name); + locale * l = (locale *)calloc(sizeof(locale), 1); + locale ** lp = &locales; + + while (*lp && (*lp)->hashkey!=hkey) lp=&(*lp)->next; + if (*lp) { + return *lp; + } + + l->hashkey = hkey; + l->name = strdup(name); + l->next = NULL; + l->index = nextlocaleindex++; + assert(nextlocaleindex<=MAXLOCALES); + *lp = l; + if (default_locale==NULL) default_locale = l; + return l; +} + +/** creates a list of locales + * This function takes a comma-delimited list of locale-names and creates + * the locales using the make_locale function (useful for ini-files). + * For maximum performance, locales should be created in order of popularity. + */ +void +make_locales(const char * str) +{ + const char * tok = str; + while (*tok) { + char zText[32]; + while (*tok && *tok !=',') ++tok; + strncpy(zText, str, tok-str); + zText[tok-str] = 0; + make_locale(zText); + if (*tok) { + str = ++tok; + } + } +} + +static FILE * s_debug = NULL; +static char * s_logfile = NULL; + +void +debug_language(const char * log) +{ + s_logfile = strdup(log); +} + +const char * +locale_getstring(const locale * lang, const char * key) +{ + unsigned int hkey = hashstring(key); + unsigned int id = hkey & (SMAXHASH-1); + const struct locale_str * find; + + assert(lang); + if (key==NULL || *key==0) return NULL; + find = lang->strings[id]; + while (find) { + if (find->hashkey == hkey) { + if (find->nexthash==NULL) { + /* if this is the only entry with this hash, fine. */ + assert(strcmp(key, find->key)==0); + return find->str; + } + if (strcmp(key, find->key)==0) { + return find->str; + } + } + find = find->nexthash; + } + return NULL; +} + +const char * +locale_string(const locale * lang, const char * key) +{ + assert(lang!=0); + + if (key!=NULL) { + unsigned int hkey = hashstring(key); + unsigned int id = hkey & (SMAXHASH-1); + struct locale_str * find; + + if (*key==0) return NULL; + if (lang == NULL) return key; + find = lang->strings[id]; + while (find) { + if (find->hashkey == hkey) { + if (find->nexthash==NULL) { + /* if this is the only entry with this hash, fine. */ + assert(strcmp(key, find->key)==0); + break; + } + if (strcmp(key, find->key)==0) break; + } + find = find->nexthash; + } + if (!find) { + const char * s = key; + log_warning(("missing translation for \"%s\" in locale %s\n", key, lang->name)); + if (lang!=default_locale) { + s = locale_string(default_locale, key); + } + if (s_logfile) { + s_debug = s_debug?s_debug:fopen(s_logfile, "w"); + if (s_debug) { + fprintf(s_debug, "%s;%s;%s\n", key, lang->name, s); + fflush(s_debug); + locale_setstring((struct locale*)lang, key, s); + } + } + return s; + } + return find->str; + } + return NULL; +} + +void +locale_setstring(locale * lang, const char * key, const char * value) +{ + unsigned int hkey = hashstring(key); + unsigned int id = hkey & (SMAXHASH-1); + struct locale_str * find; + if (lang==NULL) lang=default_locale; + find = lang->strings[id]; + while (find) { + if (find->hashkey==hkey && strcmp(key, find->key)==0) break; + find = find->nexthash; + } + if (!find) { + find = calloc(1, sizeof(struct locale_str)); + find->nexthash = lang->strings[id]; + lang->strings[id] = find; + find->hashkey = hkey; + find->key = strdup(key); + find->str = strdup(value); + } + else { + if (strcmp(find->str, value)!=0) { + log_error(("Duplicate key %s for '%s' and '%s'\n", key, value, find->str)); + } + assert(!strcmp(find->str, value) || !"duplicate string for key"); + } +} + +const char * +locale_name(const locale * lang) +{ + assert(lang); + return lang->name; +} + +char * +mkname_buf(const char * space, const char * name, char * buffer) +{ + if (space && *space) { + sprintf(buffer, "%s::%s", space, name); + } else { + strcpy(buffer, name); + } + return buffer; +} + +const char * +mkname(const char * space, const char * name) +{ + static char zBuffer[128]; /* STATIC_RESULT: used for return, not across calls */ + return mkname_buf(space, name, zBuffer); +} + +locale * +nextlocale(const struct locale * lang) +{ + return lang->next; +} + +typedef struct lstr { + tnode tokens[UT_MAX]; +} lstr; + +static lstr lstrs[MAXLOCALES]; + +struct tnode * +get_translations(const struct locale * lang, int index) +{ + assert(lang); + assert(lang->indexindexindex].tokens+index; + } + return lstrs[0].tokens+index; +} diff --git a/src/util/language.h b/src/util/language.h new file mode 100644 index 000000000..a051bc6f0 --- /dev/null +++ b/src/util/language.h @@ -0,0 +1,69 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef MY_LOCALE_H +#define MY_LOCALE_H +#ifdef __cplusplus +extern "C" { +#endif + +struct locale; + +/** managing multiple locales: **/ +extern struct locale * find_locale(const char * name); +extern struct locale * make_locale(const char * key); + +/** operations on locales: **/ +extern void locale_setstring(struct locale * lang, const char * key, const char * value); +extern const char * locale_getstring(const struct locale * lang, const char * key); +extern const char * locale_string(const struct locale * lang, const char * key); /* does fallback */ +extern unsigned int locale_hashkey(const struct locale * lang); +extern const char * locale_name(const struct locale * lang); + +extern const char * mkname(const char * namespc, const char * key); +extern char * mkname_buf(const char * namespc, const char * key, char * buffer); + +extern void debug_language(const char * log); +extern void make_locales(const char * str); + +#define LOC(lang, s) (lang?locale_string(lang, s):s) + +extern struct locale * default_locale; +extern struct locale * locales; +extern struct locale * nextlocale(const struct locale * lang); + +enum { + UT_PARAMS, + UT_KEYWORDS, + UT_SKILLS, + UT_RACES, + UT_OPTIONS, + UT_DIRECTIONS, + UT_ARCHETYPES, + UT_MAGIC, + UT_TERRAINS, + UT_SPECDIR, + UT_MAX +}; + +struct tnode * get_translations(const struct locale * lang, int index); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/language_struct.h b/src/util/language_struct.h new file mode 100644 index 000000000..1f09a071b --- /dev/null +++ b/src/util/language_struct.h @@ -0,0 +1,28 @@ +#ifndef CLASS_LANGUAGE_STRUCT +#define CLASS_LANGUAGE_STRUCT + +/* This file should not be included by anything in the server. If you + * feel that you need to include it, it's a sure sign that you're trying to + * do something BAD. */ + +#define MAXLOCALES 3 +#define SMAXHASH 2048 +typedef struct locale_str { + unsigned int hashkey; + struct locale_str * nexthash; + char * str; + char * key; +} locale_str; + +typedef struct locale { + int index; + struct locale * next; + unsigned int hashkey; + const char * name; + struct locale_str * strings[SMAXHASH]; +} locale; + +extern locale * default_locale; +extern locale * locales; + +#endif diff --git a/src/util/listbox.c b/src/util/listbox.c new file mode 100644 index 000000000..508d5bd3c --- /dev/null +++ b/src/util/listbox.c @@ -0,0 +1,191 @@ +/* vi: set ts=2: +* +-------------------+ Christian Schlittchen +* | | Enno Rehling +* | Eressea PBEM host | Katja Zedel +* | (c) 1998 - 2006 | +* | | This program may not be used, modified or distributed +* +-------------------+ without prior permission by the authors of Eressea. +* +*/ + +/* wenn platform.h nicht vor curses included wird, kompiliert es unter windows nicht */ +#include +#include + +#include "listbox.h" + +#include +#include + +void +insert_selection(list_selection ** p_sel, list_selection * prev, const char * str, void * payload) +{ + list_selection * sel = calloc(sizeof(list_selection), 1); + sel->str = strdup(str); + sel->data = payload; + if (*p_sel) { + list_selection * s; + sel->next = *p_sel; + sel->prev = sel->next->prev; + sel->next->prev=sel; + if (sel->prev) { + sel->prev->next = sel; + sel->index=sel->prev->index+1; + } + for (s=sel->next;s;s=s->next) { + s->index = s->prev->index+1; + } + *p_sel = sel; + } else { + *p_sel = sel; + sel->prev = prev; + if (prev) sel->index=prev->index+1; + } +} + +list_selection ** +push_selection(list_selection ** p_sel, char * str, void * payload) +{ + list_selection * sel = calloc(sizeof(list_selection), 1); + list_selection * prev = NULL; + sel->str = str; + sel->data = payload; + while (*p_sel) { + prev = *p_sel; + p_sel=&prev->next; + } + *p_sel = sel; + if (prev) { + sel->prev = prev; + sel->index = prev->index+1; + } + return p_sel; +} + +#define SX (stdscr->_maxx) +#define SY (stdscr->_maxy) + +list_selection * +do_selection(list_selection * sel, const char * title, void (*perform)(list_selection *, void *), void * data) +{ + WINDOW * wn; + boolean update = true; + list_selection *s; + list_selection *top = sel; + list_selection *current = top; + int i; + int height = 0, width = (int)strlen(title)+8; + for (s=sel;s;s=s->next) { + if ((int)strlen(s->str)>width) width = (int)strlen(s->str); + ++height; + } + if (height==0 || width==0) return NULL; + if (width+3>SX) width=SX-4; + if (height+2>SY) height=SY-2; + + wn = newwin(height+2, width+4, (SY - height - 2) / 2, (SX - width - 4) / 2); + + for (;;) { + int input; + if (update) { + for (s=top;s!=NULL && top->index+height!=s->index;s=s->next) { + i = s->index-top->index; + wmove(wn, i + 1, 4); + waddnstr(wn, s->str, -1); + wclrtoeol(wn); + } + wborder(wn, 0, 0, 0, 0, 0, 0, 0, 0); + mvwprintw(wn, 0, 2, "[ %s ]", title); + update = false; + } + i = current->index-top->index; + wattron(wn, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + wmove(wn, i + 1, 2); + waddstr(wn, "->"); + wmove(wn, i + 1, 4); + waddnstr(wn, current->str, -1); + wattroff(wn, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + + wrefresh(wn); + + input = getch(); + + wmove(wn, i + 1, 2); + waddstr(wn, " "); + wmove(wn, i + 1, 4); + waddnstr(wn, current->str, width); + + switch (input) { + case KEY_NPAGE: + for (i=0;i!=height/2;++i) { + if (current->next) { + current = current->next; + if (current->index-height>=top->index) { + top=current; + update = true; + } + } + } + break; + case KEY_PPAGE: + for (i=0;i!=height/2;++i) { + if (current->prev) { + if (current==top) { + top = sel; + while (top->index+heightindex) top=top->next; + update = true; + } + current = current->prev; + } + } + break; + case KEY_DOWN: + if (current->next) { + current = current->next; + if (current->index-height>=top->index) { + top=current; + update = true; + } + } + break; + case KEY_UP: + if (current->prev) { + if (current==top) { + top = sel; + while (top->index+heightindex) top=top->next; + update = true; + } + current = current->prev; + } + break; + case 27: + case 'q': + delwin(wn); + return NULL; + case 10: + case 13: + if (perform) perform(current, data); + else { + delwin(wn); + return current; + } + break; + default: + s = current->next; + if (s==NULL) s = top; + while (s!=current) { + if (tolower(s->str[0])==tolower(input)) { + current = s; + update = true; + } else { + s = s->next; + if (s==NULL) s = top; + } + } + if (current->index-height>=top->index) { + top=current; + update = true; + } + } + } +} diff --git a/src/util/listbox.h b/src/util/listbox.h new file mode 100644 index 000000000..ab2c7f9bc --- /dev/null +++ b/src/util/listbox.h @@ -0,0 +1,16 @@ +#ifndef CURSES_LISTBOX +#define CURSES_LISTBOX + +typedef struct list_selection { + struct list_selection * next; + struct list_selection * prev; + int index; + char * str; + void * data; +} list_selection; + +extern struct list_selection * do_selection(struct list_selection * sel, const char * title, void (*perform)(struct list_selection *, void *), void * data); +extern struct list_selection ** push_selection(struct list_selection ** p_sel, char * str, void * payload); +extern void insert_selection(struct list_selection ** p_sel, struct list_selection * prev, const char * str, void * payload); + +#endif /* CURSES_LISTBOX */ diff --git a/src/util/lists.c b/src/util/lists.c new file mode 100644 index 000000000..cff4b287c --- /dev/null +++ b/src/util/lists.c @@ -0,0 +1,143 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include + +#include +#include "lists.h" + +void +addlist(void *l1, void *p1) +{ + + /* add entry p to the end of list l */ + + void_list **l; + void_list *p, *q; + + l = (void_list **)l1; + p = (void_list *)p1; + assert(p->next == 0); + + if (*l) { + for (q = *l; q->next; q = q->next) + assert(q); + q->next = p; + } else + *l = p; +} + +void +choplist(void * a, void * b) +{ + void_list **l = (void_list**)a, *p = (void_list*)b; + /* remove entry p from list l - when called, a pointer to p must be + * kept in order to use (and free) p; if omitted, this will be a + * memory leak */ + + void_list **q; + + for (q = l; *q; q = &((*q)->next)) { + if (*q == p) { + *q = p->next; + p->next = 0; + break; + } + } +} + +void +translist(void *l1, void *l2, void *p) +{ + + /* remove entry p from list l1 and add it at the end of list l2 */ + + choplist(l1, p); + addlist(l2, p); +} + +void +insertlist(void_list ** l, void_list * p) +{ + + /* insert entry p at the beginning of list l */ + + p->next = *l; + *l = p; + +} + +void +removelist(void *l, void *p) +{ + + /* remove entry p from list l; free p */ + + choplist(l, p); + free(p); +} + +void +freelist(void *p1) +{ + + /* remove all entries following and including entry p from a listlist */ + + void_list *p, *p2; + + p = (void_list *)p1; + + while (p) { + p2 = p->next; + free(p); + p = p2; + } +} + +unsigned int +listlen(void *l) +{ + + /* count entries p in list l */ + + unsigned int i; + void_list *p; + + for (p = (void_list *)l, i = 0; p; p = p->next, i++); + return i; +} + +/* Hilfsfunktion, um das Debugging zu erleichtern. Statt print + * (cast)foo->next->next->next->next nur noch + * print (cast)listelem(foo, 3) */ + +void * +listelem(void *l, int n) +{ + int i=0; + + while(i < n && l != NULL) { + l = ((void_list *)l)->next; + i++; + } + + return l; +} + + diff --git a/src/util/lists.h b/src/util/lists.h new file mode 100644 index 000000000..588cc4878 --- /dev/null +++ b/src/util/lists.h @@ -0,0 +1,55 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef LISTS_H +#define LISTS_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef struct void_list { + struct void_list * next; + void * data; +} void_list; + +#define list_foreach(type, list, item) item=list; while (item!=NULL) { type* __next__=item->next; +#define list_continue(item) { item=__next__; continue; } +#define list_next(item) item=__next__; } + +void addlist(void *l1, void *p1); +void choplist(void * l, void * p); +void translist(void *l1, void *l2, void *p); +#ifndef MALLOCDBG +void freelist(void *p1); +void removelist(void *l, void *p); +#else +#define freelist(p) { while (p) { void * p2 = p->next; free(p); p = p2; } } +#define removelist(l,p) { choplist(l, p); free(p); } +#endif + +unsigned int listlen(void *l); +#define addlist2(l, p) (*l = p, l = &p->next) + +void *listelem(void *l, int n); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/log.c b/src/util/log.c new file mode 100644 index 000000000..7b5b22ff6 --- /dev/null +++ b/src/util/log.c @@ -0,0 +1,288 @@ +/* vi: set ts=2: ++-------------------+ Christian Schlittchen +| | Enno Rehling +| Eressea PBEM host | Katja Zedel +| (c) 1998 - 2003 | Henning Peters +| | Ingo Wilken ++-------------------+ Stefan Reich + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ +#include +#include "log.h" +#include "unicode.h" + +#include +#include +#include +#include +#include + +/* TODO: set from external function */ +int log_flags = LOG_FLUSH|LOG_CPERROR|LOG_CPWARNING; +#ifdef STDIO_CP +static int stdio_codepage = STDIO_CP; +#else +static int stdio_codepage = 0; +#endif +static FILE * logfile; + +#define MAXLENGTH 4096 /* because I am lazy, CP437 output is limited to this many chars */ +void +log_flush(void) +{ + fflush(logfile); +} + +void +log_puts(const char * str) +{ + fflush(stdout); + if (!logfile) logfile = stderr; + fputs(str, logfile); +} + +static int +cp_convert(const char * format, char * buffer, size_t length, int codepage) +{ + /* when console output on MSDOS, convert to codepage */ + const char * input = format; + char * pos = buffer; + + while (pos+1=level) { + fprintf(logfile, "INFO[%u]: ", level); + va_start(marker, format); + vfprintf(logfile, format, marker); + va_end(marker); + if (logfile!=stderr) { + if (stderr_level>=level) { + fprintf(stderr, "INFO[%u]: ", level); + va_start(marker, format); + if (stdio_codepage) { + char buffer[MAXLENGTH]; + char converted[MAXLENGTH]; + + vsnprintf(buffer, sizeof(buffer), format, marker); + if (cp_convert(buffer, converted, MAXLENGTH, stdio_codepage)==0) { + fputs(converted, stderr); + } else { + /* fall back to non-converted output */ + va_end(marker); + va_start(marker, format); + vfprintf(stderr, format, marker); + } + } else { + vfprintf(stderr, format, marker); + } + va_end(marker); + } + if (log_flags & LOG_FLUSH) { + log_flush(); + } + } + } +} diff --git a/src/util/log.h b/src/util/log.h new file mode 100644 index 000000000..87a35dfee --- /dev/null +++ b/src/util/log.h @@ -0,0 +1,45 @@ +/* vi: set ts=2: ++-------------------+ Christian Schlittchen +| | Enno Rehling +| Eressea PBEM host | Katja Zedel +| (c) 1998 - 2003 | Henning Peters +| | Ingo Wilken ++-------------------+ Stefan Reich + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ +#ifndef H_UTIL_LOG +#define H_UTIL_LOG +#ifdef __cplusplus +extern "C" { +#endif + + extern void log_open(const char * filename); + extern void log_printf(const char * str, ...); + extern void log_puts(const char * str); + extern void log_close(void); + extern void log_flush(void); + extern void log_stdio(FILE * io, const char * format, ...); + +#define log_warning(x) _log_warn x +#define log_error(x) _log_error x +#define log_info(x) _log_info x + + /* use macros above instead of these: */ + extern void _log_warn(const char * format, ...); + extern void _log_error(const char * format, ...); + extern void _log_info(unsigned int flag, const char * format, ...); + +#define LOG_FLUSH 0x01 +#define LOG_CPWARNING 0x02 +#define LOG_CPERROR 0x04 +#define LOG_INFO1 0x08 +#define LOG_INFO2 0x10 +#define LOG_INFO3 0x20 + + extern int log_flags; +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/message.c b/src/util/message.c new file mode 100644 index 000000000..243b6ba40 --- /dev/null +++ b/src/util/message.c @@ -0,0 +1,237 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + +*/ + +#include +#include "message.h" + +#include "goodies.h" +#include "log.h" + +/* libc includes */ +#include +#include +#include +#include +#include + +void (*msg_log_create)(const struct message * msg) = 0; + +const char * +mt_name(const message_type* mtype) +{ + return mtype->name; +} + +message_type * +mt_new(const char * name, const char * args[]) +{ + int i, nparameters = 0; + message_type * mtype = (message_type *)malloc(sizeof(message_type)); + + assert(name!=NULL); + if (name==NULL) { + log_error(("Trying to create message_type with name=0x0\n")); + return NULL; + } + if (args!=NULL) for (nparameters=0;args[nparameters];++nparameters); + + mtype->name = strdup(name); + mtype->nparameters = nparameters; + if (nparameters > 0) { + mtype->pnames = (const char**)malloc(sizeof(char*) * nparameters); + mtype->types = (const arg_type**)malloc(sizeof(arg_type*) * nparameters); + } else { + mtype->pnames = NULL; + mtype->types = NULL; + } + if (args!=NULL) for (i=0;args[i];++i) { + const char * x = args[i]; + const char * spos = strchr(x, ':'); + if (spos==NULL) { + mtype->pnames[i] = strdup(x); + mtype->types[i] = NULL; + } else { + char * cp = strncpy((char*)malloc(spos-x+1), x, spos-x); + cp[spos-x] = '\0'; + mtype->pnames[i] = cp; + mtype->types[i] = find_argtype(spos+1); + if (mtype->types[i]==NULL) { + log_error(("unknown argument type %s for message type %s\n", + spos+1, mtype->name)); + } + assert(mtype->types[i]); + } + } + return mtype; +} + +message_type * +mt_new_va(const char * name, ...) +{ + const char * args[16]; + int i = 0; + va_list marker; + + va_start(marker, name); + for (;;) { + const char * c = va_arg(marker, const char*); + args[i++] = c; + if (c==NULL) break; + } + va_end(marker); + return mt_new(name, args); +} + +arg_type * argtypes = NULL; + +void +register_argtype(const char * name, void(*free_arg)(variant), variant (*copy_arg)(variant), variant_type type) +{ + arg_type * atype = (arg_type *)malloc(sizeof(arg_type)); + atype->name = name; + atype->next = argtypes; + atype->release = free_arg; + atype->copy = copy_arg; + atype->vtype = type; + argtypes = atype; +} + +const arg_type * +find_argtype(const char * name) +{ + arg_type * atype = argtypes; + while (atype!=NULL) { + if (strcmp(atype->name, name)==0) return atype; + atype = atype->next; + } + return NULL; +} + +static variant +copy_arg(const arg_type * atype, variant data) +{ + assert(atype!=NULL); + if (atype->copy==NULL) return data; + return atype->copy(data); +} + +static void +free_arg(const arg_type * atype, variant data) +{ + assert(atype!=NULL); + if (atype->release) atype->release(data); +} + +message * +msg_create(const struct message_type * mtype, variant args[]) +{ + int i; + message * msg = (message *)malloc(sizeof(message)); + + assert(mtype!=NULL); + if (mtype==NULL) { + log_error(("Trying to create message with type=0x0\n")); + return NULL; + } + msg->type = mtype; + msg->parameters = (variant*)calloc(mtype->nparameters, sizeof(variant)); + msg->refcount=1; + for (i=0;i!=mtype->nparameters;++i) { + msg->parameters[i] = copy_arg(mtype->types[i], args[i]); + } + if (msg_log_create) msg_log_create(msg); + return msg; +} + +typedef struct messagetype_list { + struct messagetype_list * next; + const struct message_type * data; +} messagetype_list; + +#define MT_MAXHASH 1021 +static messagetype_list * messagetypes[MT_MAXHASH]; + +const message_type * +mt_find(const char * name) +{ + const struct message_type * found = NULL; + unsigned int hash = hashstring(name) % MT_MAXHASH; + messagetype_list * type = messagetypes[hash]; + while (type) { + if (strcmp(type->data->name, name)==0) { + if (found==NULL) found = type->data; + break; + } + type = type->next; + } + return found; +} + +static unsigned int +mt_id(const message_type * mtype) +{ + unsigned int key = 0; + size_t i = strlen(mtype->name); + + while (i>0) { + key = (mtype->name[--i] + key*37); + } + return key % 0x7FFFFFFF; +} + + +const message_type * +mt_register(message_type * type) +{ + unsigned int hash = hashstring(type->name) % MT_MAXHASH; + messagetype_list * mtl = messagetypes[hash]; + + while (mtl && mtl->data!=type) mtl=mtl->next; + if (mtl==NULL) { + mtl = (messagetype_list*)malloc(sizeof(messagetype_list)); + mtl->data = type; + mtl->next = messagetypes[hash]; + messagetypes[hash] = mtl; + type->key = mt_id(type); + } + return type; +} + +void +msg_free(message *msg) +{ + int i; + assert(msg->refcount==0); + for (i=0;i!=msg->type->nparameters;++i) { + free_arg(msg->type->types[i], msg->parameters[i]); + } + free((void*)msg->parameters); + free(msg); +} + +void +msg_release(struct message * msg) +{ + assert(msg->refcount>0); + if (--msg->refcount>0) return; + msg_free(msg); +} + +struct message * +msg_addref(struct message * msg) +{ + assert(msg->refcount>0); + ++msg->refcount; + return msg; +} + diff --git a/src/util/message.h b/src/util/message.h new file mode 100644 index 000000000..021283903 --- /dev/null +++ b/src/util/message.h @@ -0,0 +1,71 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#ifndef UTIL_MESSAGE_H +#define UTIL_MESSAGE_H + +#include "variant.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct locale; + +typedef struct arg_type { + struct arg_type * next; + variant_type vtype; + const char * name; + void (*release)(variant); + variant (*copy)(variant); +} arg_type; + +typedef struct message_type { + unsigned int key; + const char * name; + int nparameters; + const char ** pnames; + const struct arg_type ** types; +} message_type; + +typedef struct message { + const struct message_type * type; + variant * parameters; + int refcount; +} message; + +extern struct message_type * mt_new(const char * name, const char ** args); +extern struct message_type * mt_new_va(const char * name, ...); + /* mt_new("simple_sentence", "subject:string", "predicate:string", + * "object:string", "lang:locale", NULL); */ + +extern struct message * msg_create(const struct message_type * type, variant args[]); + /* msg_create(&mt_simplesentence, "enno", "eats", "chocolate", &locale_de); + * parameters must be in the same order as they were for mt_new! */ + +extern void msg_release(struct message * msg); +extern struct message * msg_addref(struct message * msg); + +extern const char * mt_name(const struct message_type* mtype); + +/** message_type registry (optional): **/ +extern const struct message_type * mt_register(struct message_type *); +extern const struct message_type * mt_find(const char *); + +extern void register_argtype(const char * name, void(*free_arg)(variant), variant (*copy_arg)(variant), variant_type); +extern const struct arg_type * find_argtype(const char * name); + +extern void (*msg_log_create)(const struct message * msg); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/nrmessage.c b/src/util/nrmessage.c new file mode 100644 index 000000000..0086159d5 --- /dev/null +++ b/src/util/nrmessage.c @@ -0,0 +1,174 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + +*/ + +#include +#include "nrmessage.h" +#include "nrmessage_struct.h" + +/* util includes */ +#include "bsdstring.h" +#include "log.h" +#include "message.h" +#include "language.h" +#include "translation.h" +#include "goodies.h" + +/* libc includes */ +#include +#include +#include + +#define NRT_MAXHASH 1021 +static nrmessage_type * nrtypes[NRT_MAXHASH]; + +const char * +nrt_string(const struct nrmessage_type *type) +{ + return type->string; +} + +nrmessage_type * +nrt_find(const struct locale * lang, const struct message_type * mtype) +{ + nrmessage_type * found = NULL; + unsigned int hash = hashstring(mtype->name) % NRT_MAXHASH; + nrmessage_type * type = nrtypes[hash]; + while (type) { + if (type->mtype==mtype) { + if (found==NULL) found = type; + else if (type->lang==NULL) found = type; + if (lang==type->lang) { + found = type; + break; + } + } + type = type->next; + } + if (!found) { + log_warning(("could not find nr-type %s for locale %s\n", + mtype->name, locale_name(lang))); + } + if (lang && found && found->lang!=lang) { + log_warning(("could not find nr-type %s for locale %s, using %s\n", + mtype->name, locale_name(lang), locale_name(found->lang))); + } + return found; +} + +nrsection * sections; + +const nrsection * +section_find(const char * name) +{ + nrsection ** mcp = §ions; + if (name==NULL) return NULL; + for (;*mcp;mcp=&(*mcp)->next) { + nrsection * mc = *mcp; + if (!strcmp(mc->name, name)) break; + } + return *mcp; +} + +const nrsection * +section_add(const char * name) +{ + nrsection ** mcp = §ions; + if (name==NULL) return NULL; + for (;*mcp;mcp=&(*mcp)->next) { + nrsection * mc = *mcp; + if (!strcmp(mc->name, name)) break; + } + if (!*mcp) { + nrsection * mc = calloc(sizeof(nrsection), 1); + mc->name = strdup(name); + *mcp = mc; + } + return *mcp; +} + +void +nrt_register(const struct message_type * mtype, const struct locale * lang, const char * string, int level, const char * section) +{ + unsigned int hash = hashstring(mtype->name) % NRT_MAXHASH; + nrmessage_type * nrt = nrtypes[hash]; + while (nrt && (nrt->lang!=lang || nrt->mtype!=mtype)) { + nrt = nrt->next; + } + if (nrt) { + log_error(("duplicate message-type %s\n", mtype->name)); + assert(!nrt || !"trying to register same nr-type twice"); + } else { + int i; + char zNames[256]; + char * c = zNames; + nrt = malloc(sizeof(nrmessage_type)); + nrt->lang = lang; + nrt->mtype = mtype; + nrt->next = nrtypes[hash]; + nrt->level=level; + if (section) { + const nrsection * s = section_find(section); + if (s==NULL) { + s = section_add(section); + } + nrt->section = s->name; + } + else nrt->section = NULL; + nrtypes[hash] = nrt; + assert(string && *string); + nrt->string = strdup(string); + *c = '\0'; + for (i=0;i!=mtype->nparameters;++i) { + if (i!=0) *c++ = ' '; + c+= strlen(strcpy(c, mtype->pnames[i])); + } + nrt->vars = strdup(zNames); + } +} + +size_t +nr_render(const struct message * msg, const struct locale * lang, char * buffer, size_t size, const void * userdata) +{ + struct nrmessage_type * nrt = nrt_find(lang, msg->type); + + if (nrt) { + const char * m = translate(nrt->string, userdata, nrt->vars, msg->parameters); + if (m) { + return strlcpy((char*)buffer, m, size); + } else { + log_error(("Couldn't render message %s\n", nrt->mtype->name)); + } + } + if (size>0 && buffer) buffer[0] = 0; + return 0; +} + +int +nr_level(const struct message *msg) +{ + nrmessage_type * nrt = nrt_find(NULL, msg->type); + return nrt?nrt->level:0; +} + +const char * +nr_section(const struct message *msg) +{ + nrmessage_type * nrt = nrt_find(default_locale, msg->type); + return nrt?nrt->section:NULL; +} + +const char * +nrt_section(const nrmessage_type * nrt) +{ + return nrt?nrt->section:NULL; +} diff --git a/src/util/nrmessage.h b/src/util/nrmessage.h new file mode 100644 index 000000000..f36d8e79f --- /dev/null +++ b/src/util/nrmessage.h @@ -0,0 +1,56 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_UTIL_NRMESSAGE +#define H_UTIL_NRMESSAGE +#ifdef __cplusplus +extern "C" { +#endif + +struct locale; +struct message; +struct message_type; +struct nrmessage_type; + +typedef struct nrsection { + char * name; + struct nrsection * next; +} nrsection; + +extern nrsection * sections; + +extern void nrt_register(const struct message_type * mtype, + const struct locale * lang, const char * script, + int level, const char * section); +extern struct nrmessage_type * nrt_find(const struct locale *, + const struct message_type *); +extern const char * nrt_string(const struct nrmessage_type *type); +extern const char * nrt_section(const struct nrmessage_type * mt); + +extern size_t nr_render(const struct message * msg, const struct locale * lang, + char * buffer, size_t size, const void * userdata); +extern int nr_level(const struct message *msg); +extern const char * nr_section(const struct message *msg); + + +/* before: + * fogblock;movement:0;de;{unit} konnte von {region} nicht nach {$dir direction} ausreisen, der Nebel war zu dicht. + * after: + * fogblock:movement:0 + * $unit($unit) konnte von $region($region) nicht nach $direction($direction) ausreisen, der Nebel war zu dicht. + * unit:unit region:region direction:int + */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/nrmessage_struct.h b/src/util/nrmessage_struct.h new file mode 100644 index 000000000..ac14bef82 --- /dev/null +++ b/src/util/nrmessage_struct.h @@ -0,0 +1,20 @@ +#ifndef CLASS_NRMESSAGE_STRUCT +#define CLASS_NRMESSAGE_STRUCT + +/* This file should not be included by anything in the server. If you + * feel that you need to include it, it's a sure sign that you're trying to + * do something BAD. */ + +typedef struct nrmessage_type { + const struct message_type * mtype; + const struct locale * lang; + const char * string; + const char * vars; + struct nrmessage_type * next; + int level; + const char * section; +} nrmessage_type; + +extern nrmessage_type * get_nrmessagetypes(void); + +#endif diff --git a/src/util/parser.c b/src/util/parser.c new file mode 100644 index 000000000..1dfff3798 --- /dev/null +++ b/src/util/parser.c @@ -0,0 +1,195 @@ +#include +#include "parser.h" +#include "unicode.h" +#include "log.h" + +#include +#include +#include + +#define SPACE_REPLACEMENT '~' +#define ESCAPE_CHAR '\\' +#define MAXTOKENSIZE 8192 + +typedef struct parser_state { + const char *current_token; + char * current_cmd; + struct parser_state * next; +} parser_state; + +static parser_state * state; + +static int +eatwhitespace_c(const char ** str_p) +{ + int ret = 0; + ucs4_t ucs; + size_t len; + const char * str = *str_p; + + /* skip over potential whitespace */ + for (;;) { + unsigned char utf8_character = (unsigned char)*str; + if (~utf8_character & 0x80) { + if (!iswxspace(utf8_character)) break; + ++str; + } else { + ret = unicode_utf8_to_ucs4(&ucs, str, &len); + if (ret!=0) { + log_warning(("illegal character sequence in UTF8 string: %s\n", str)); + break; + } + if (!iswxspace((wint_t)ucs)) break; + str+=len; + } + } + *str_p = str; + return ret; +} + +void +init_tokens_str(const char * initstr, char * cmd) +{ + if (state==NULL) { + state = malloc(sizeof(parser_state)); + } + else if (state->current_cmd) free(state->current_cmd); + state->current_cmd = cmd; + state->current_token = initstr; +} + +void +parser_pushstate(void) +{ + parser_state * new_state = malloc(sizeof(parser_state)); + new_state->current_cmd = NULL; + new_state->current_token = NULL; + new_state->next = state; + state = new_state; +} + +void +parser_popstate(void) +{ + parser_state * new_state = state->next; + if (state->current_cmd!=NULL) free(state->current_cmd); + free(state); + state = new_state; +} + +boolean +parser_end(void) +{ + eatwhitespace_c(&state->current_token); + return *state->current_token == 0; +} + +void +skip_token(void) +{ + char quotechar = 0; + eatwhitespace_c(&state->current_token); + + while (*state->current_token) { + ucs4_t ucs; + size_t len; + + unsigned char utf8_character = (unsigned char)state->current_token[0]; + if (~utf8_character & 0x80) { + ucs = utf8_character; + ++state->current_token; + } else { + int ret = unicode_utf8_to_ucs4(&ucs, state->current_token, &len); + if (ret==0) { + state->current_token+=len; + } else { + log_warning(("illegal character sequence in UTF8 string: %s\n", state->current_token)); + } + } + if (iswxspace((wint_t)ucs) && quotechar==0) { + return; + } else { + switch(utf8_character) { + case '"': + case '\'': + if (utf8_character==quotechar) return; + quotechar = utf8_character; + break; + case ESCAPE_CHAR: + ++state->current_token; + break; + } + } + } +} + +const char * +parse_token(const char ** str) +{ + static char lbuf[MAXTOKENSIZE]; /* STATIC_RESULT: used for return, not across calls */ + char * cursor = lbuf; + char quotechar = 0; + boolean escape = false; + const char * ctoken = *str; + + assert(ctoken); + + eatwhitespace_c(&ctoken); + while (*ctoken && cursor-lbuf < MAXTOKENSIZE-1) { + ucs4_t ucs; + size_t len; + boolean copy = false; + + unsigned char utf8_character = *(unsigned char *)ctoken; + if (~utf8_character & 0x80) { + ucs = utf8_character; + len = 1; + } else { + int ret = unicode_utf8_to_ucs4(&ucs, ctoken, &len); + if (ret!=0) { + log_warning(("illegal character sequence in UTF8 string: %s\n", ctoken)); + break; + } + } + if (escape) { + copy = true; + escape = false; + } else if (iswxspace((wint_t)ucs)) { + if (quotechar==0) break; + copy = true; + } else if (utf8_character=='"' || utf8_character=='\'') { + if (utf8_character==quotechar) { + ++ctoken; + break; + } else if (quotechar==0) { + quotechar = utf8_character; + ++ctoken; + } else { + *cursor++ = *ctoken++; + } + } else if (utf8_character==SPACE_REPLACEMENT) { + *cursor++ = ' '; + ++ctoken; + } else if (utf8_character==ESCAPE_CHAR) { + escape = true; + ++ctoken; + } else { + copy = true; + } + if (copy) { + memcpy(cursor, ctoken, len); + cursor+=len; + ctoken+=len; + } + } + + *cursor = '\0'; + *str = ctoken; + return lbuf; +} + +const char * +getstrtoken(void) +{ + return parse_token((const char **)&state->current_token); +} diff --git a/src/util/parser.h b/src/util/parser.h new file mode 100644 index 000000000..fecb5ff9f --- /dev/null +++ b/src/util/parser.h @@ -0,0 +1,29 @@ +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2007 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +#ifndef UTIL_PARSER_H +#define UTIL_PARSER_H +#ifdef __cplusplus +extern "C" { +#endif + +extern void init_tokens_str(const char * initstr, char * cmd); /* initialize token parsing, take ownership of cmd */ +extern void skip_token(void); +extern const char * parse_token(const char ** str); +extern void parser_pushstate(void); +extern void parser_popstate(void); +extern boolean parser_end(void); +extern const char *getstrtoken(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/util/patricia.c b/src/util/patricia.c new file mode 100644 index 000000000..4189f146b --- /dev/null +++ b/src/util/patricia.c @@ -0,0 +1,236 @@ +#include + +#include +#include +#include + +#include "patricia.h" + +#define MAXKEYLEN 128 + +/* TODO: custom memory management to optimize cache layout, or use arrays. */ + +/* NOTE: The structure saves an extra 0 delimiter for the key. Technically + * this wouldn't be necessary (because we know its' length from data[0]), + * but it makes it possible for trie_getkey to return a key without making + * a copy or have a cumbersome (const char**, size_t*) interface. + * +-----------+-------------+------+------------+ + * data: | keylen(1) | key(keylen) | 0(1) | data(size) | + * +-----------+-------------+------+------------+ + */ + +struct trie_node { + struct trie_node *l, *r; + char * data; + unsigned int bitpos; +}; + +#if 1 +#define get_bit(c, s, p) (unsigned int)((((p)>>3)>(unsigned int)(s))?0:((c)[(p)>>3]>>((p)&7)&1)) +#else +unsigned int get_bit(const char * c, size_t s, unsigned int p) +{ + if ((p>>3)>=(unsigned int)s) return 0; + return ((c)[p>>3]>>(p&7)&1); +} +#endif +#define node_bit(n, p) get_bit((n)->data+1, (n)->data[0], (p)) + +trie_node * trie_insert(trie_node **root_p, const char * key, const void * data, size_t size) +{ + trie_node * new_node; + size_t keylen = strlen(key); + trie_node ** insert_p = root_p, *node = *insert_p; + unsigned int p, bit=0; + + assert(keylenbitpos) { + insert_p = bit?&node->r:&node->l; + node = *insert_p; + if (node==NULL) { + continue; + } + } + + /* if we are looking at a back-node, we need to add our node before it. */ + if (p>=node->bitpos) { + /* find the point p where both differ. */ + if (keylen==(unsigned int)node->data[0] && strncmp(key, node->data+1, keylen)==0) { + /* we are trying to insert the same key again */ + + return node; + } + do { + ++p; + bit = get_bit(key, keylen, p); + } while (node_bit(node, p)==bit); + break; + } + + /* if instead we differ before reaching the end of the current prefix, we must split. + * we insert our node before the current one and re-attach it. */ + if (node_bit(node, p)!=bit) { + break; + } + } + + new_node = (trie_node *)malloc(sizeof(trie_node)); + new_node->bitpos = p; + new_node->data = malloc(keylen+2+size); + new_node->data[0] = (char)keylen; + memcpy(new_node->data+1, key, keylen+1); + if (data!=NULL && size>0) { + /* if data is NULL then the user only wanted some space that they're going to write to later */ + /* if size is 0 then the user is using the trie as a set, not a map */ + memcpy(new_node->data+2+keylen, data, size); + } + if (bit) { + new_node->l = node; + new_node->r = new_node; /* loop the 1-bit to ourselves, search will end */ + } else { + new_node->l = new_node; /* loop the 0-bit to ourselves, search will end */ + new_node->r = node; + } + *insert_p = new_node; + return new_node; +} + +void trie_remove(trie_node **root_p, trie_node *pos) +{ + if (pos!=NULL) { + const char * key = trie_getkey(pos); + size_t keylen = pos->data[0]; + trie_node ** node_p = root_p; + trie_node * node = *root_p; + + while (node) { + int bit; + trie_node ** next_p; + trie_node * next; + + if (node == pos) { + if (node->l==node) { + *node_p = node->r; + break; + } else if (node->r==node) { + *node_p = node->l; + break; + } + } + + bit = get_bit(key, keylen, node->bitpos); + next_p = bit?&node->r:&node->l; + next = *next_p; + if (next == pos && next->bitpos<=node->bitpos) { + /* the element that has a back-pointer to pos gets swapped with pos */ + char * data = pos->data; + pos->data = node->data; + node->data = data; + + /* finally, find the back-pointer to node and set it to pos */ + next_p = bit?&node->l:&node->r; /* NB: this is the OTHER child of node */ + next = *next_p; + key = trie_getkey(node); + keylen = (unsigned int)node->data[0]; + while (next) { + int new_bit; + if (next==node) { + *next_p = pos; + break; + } + new_bit = get_bit(key, keylen, next->bitpos); + next_p = new_bit?&next->r:&next->l; + next = *next_p; + } + *node_p = bit?node->l:node->r; + break; + } + node = *next_p; + node_p = next_p; + } + free(node->data); + free(node); + } +} + +void trie_debug(trie_node * root) +{ + const char * l = root->l?trie_getkey(root->l):"?"; + const char * r = root->r?trie_getkey(root->r):"?"; + printf("%s %d | %s | %s\n", trie_getkey(root), root->bitpos, l, r); + if (root->l && root->l->bitpos > root->bitpos) trie_debug(root->l); + if (root->r && root->r->bitpos > root->bitpos) trie_debug(root->r); +} + +trie_node * trie_find(trie_node *root, const char *key) +{ + trie_node * node = root; + size_t keylen = strlen(key); + + while (node) { + int bit = get_bit(key, keylen, node->bitpos); + trie_node * next = bit?node->r:node->l; + + if (next!=NULL) { + if (node->bitpos>=next->bitpos) { + if (keylen==(unsigned int)next->data[0] && strncmp(key, next->data+1, keylen)==0) { + return next; + } + next = NULL; + } + } + node = next; + } + return NULL; +} + +trie_node * trie_find_prefix(trie_node *root, const char *key) +{ + trie_node * node = root; + size_t keylen = strlen(key); + + while (node) { + int bit = get_bit(key, keylen, node->bitpos); + trie_node * next = bit?node->r:node->l; + + if (next!=NULL) { + if (node->bitpos>=next->bitpos) { + if (keylen<=(unsigned int)next->data[0] && strncmp(key, next->data+1, keylen)==0) { + return next; + } + next = NULL; + } + } + node = next; + } + return NULL; +} + +void * trie_getdata(trie_node * node) +{ + return node->data+2+node->data[0]; +} + +const char * trie_getkey(trie_node * node) +{ + return node->data+1; +} + +void trie_free(trie_node * root) +{ + if (root) { + if (root->l && root->l->bitpos>root->bitpos) trie_free(root->l); + if (root->r && root->r->bitpos>root->bitpos) trie_free(root->r); + free(root); + } +} diff --git a/src/util/patricia.h b/src/util/patricia.h new file mode 100644 index 000000000..f01be96be --- /dev/null +++ b/src/util/patricia.h @@ -0,0 +1,21 @@ +#ifndef H_PATRICIA +#define H_PATRICIA +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct trie_node trie_node; + +trie_node * trie_insert(trie_node **root, const char *key, const void *data, size_t size); +trie_node * trie_find(trie_node *root, const char *key); +void * trie_getdata(trie_node *node); +const char * trie_getkey(trie_node *node); +void trie_free(trie_node * root); +void trie_remove(trie_node **root_p, trie_node *pos); +void trie_debug(trie_node * root); +trie_node * trie_find_prefix(trie_node *root, const char *key); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/rand.c b/src/util/rand.c new file mode 100644 index 000000000..9694c182c --- /dev/null +++ b/src/util/rand.c @@ -0,0 +1,72 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "rand.h" +#include "rng.h" + +#include +#include +#include +#include +#include + +#define M_PIl 3.1415926535897932384626433832795029L /* pi */ + +/* NormalRand aus python, random.py geklaut, dort ist Referenz auf +* den Algorithmus. mu = Mittelwert, sigma = Standardabweichung. +* http://de.wikipedia.org/wiki/Standardabweichung#Diskrete_Gleichverteilung.2C_W.C3.BCrfel +*/ +double +normalvariate(double mu, double sigma) +{ + static const double NV_MAGICCONST = 1.7155277699214135; /* STATIC_CONST: a constant */ + double z; + for (;;) { + double u1 = rng_double(); + double u2 = 1.0 - rng_double(); + z = NV_MAGICCONST*(u1-0.5)/u2; + if (z*z/4.0 <= -log(u2)) { + break; + } + } + return mu+z*sigma; +} + +int +ntimespprob(int n, double p, double mod) +{ + int count = 0; + int i; + + for(i=0; i0; i++) { + if(rng_double() < p) { + count++; + p += mod; + } + } + return count; +} + +boolean +chance(double x) +{ + if (x>=1.0) return true; + return rng_double() < x; +} + diff --git a/src/util/rand.h b/src/util/rand.h new file mode 100644 index 000000000..2c9d6e96b --- /dev/null +++ b/src/util/rand.h @@ -0,0 +1,37 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef RAND_H +#define RAND_H +#ifdef __cplusplus +extern "C" { +#endif + + /* in dice.c: */ + extern int dice_rand(const char *str); + extern int dice(int count, int value); + + /* in rand.c: */ + extern double normalvariate(double mu, double sigma); + extern int ntimespprob(int n, double p, double mod); + extern boolean chance(double x); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/resolve.c b/src/util/resolve.c new file mode 100644 index 000000000..224fbff52 --- /dev/null +++ b/src/util/resolve.c @@ -0,0 +1,96 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include +#include "resolve.h" +#include "storage.h" +#include "variant.h" + +typedef struct unresolved { + void * ptrptr; + /* address to pass to the resolve-function */ + variant data; + /* information on how to resolve the missing object */ + resolve_fun resolve; + /* function to resolve the unknown object */ +} unresolved; + +#define BLOCKSIZE 1024 +static unresolved * ur_list; +static unresolved * ur_begin; +static unresolved * ur_current; + +variant +read_int(struct storage * store) +{ + variant var; + var.i = store->r_int(store); + return var; +} + +int +read_reference(void * address, storage * store, read_fun reader, resolve_fun resolver) +{ + variant var = reader(store); + int result = resolver(var, address); + if (result!=0) { + ur_add(var, address, resolver); + } + return result; +} + +void +ur_add(variant data, void * ptrptr, resolve_fun fun) +{ + if (ur_list==NULL) { + ur_list = malloc(BLOCKSIZE*sizeof(unresolved)); + ur_begin = ur_current = ur_list; + } + else if (ur_current-ur_begin==BLOCKSIZE-1) { + ur_begin = malloc(BLOCKSIZE*sizeof(unresolved)); + ur_current->data.v = ur_begin; + ur_current = ur_begin; + } + ur_current->data = data; + ur_current->resolve = fun; + ur_current->ptrptr = ptrptr; + + ++ur_current; + ur_current->resolve = NULL; + ur_current->data.v = NULL; +} + +void +resolve(void) +{ + unresolved * ur = ur_list; + while (ur) { + if (ur->resolve==NULL) { + ur = ur->data.v; + free(ur_list); + ur_list = ur; + continue; + } + ur->resolve(ur->data, ur->ptrptr); + ++ur; + } + free(ur_list); + ur_list = NULL; +} diff --git a/src/util/resolve.h b/src/util/resolve.h new file mode 100644 index 000000000..c6deb4f77 --- /dev/null +++ b/src/util/resolve.h @@ -0,0 +1,41 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef RESOLVE_H +#define RESOLVE_H + +#include "variant.h" +struct storage; + +#ifdef __cplusplus +extern "C" { +#endif + + typedef int (*resolve_fun)(variant data, void * address); + typedef variant (*read_fun)(struct storage* store); + extern int read_reference(void * address, struct storage * store, read_fun reader, resolve_fun resolver); + + extern void ur_add(variant data, void * address, resolve_fun fun); + extern void resolve(void); + + extern variant read_int(struct storage * store); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/rng.h b/src/util/rng.h new file mode 100644 index 000000000..3ef39d49e --- /dev/null +++ b/src/util/rng.h @@ -0,0 +1,45 @@ +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2005 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ +#ifndef UTIL_RNG_H +#define UTIL_RNG_H +#ifdef __cplusplus +extern "C" { +#endif + +#define RNG_MT + +#ifdef RNG_MT + /* initializes mt[N] with a seed */ + extern void init_genrand(unsigned long s); + + /* generates a random number on [0,0xffffffff]-interval */ + extern unsigned long genrand_int32(void); + + /* generates a random number on [0,1)-real-interval */ + extern double genrand_real2(void); + + /* generates a random number on [0,0x7fffffff]-interval */ + long genrand_int31(void); + +# define rng_init(seed) init_genrand(seed) +# define rng_int genrand_int31 +# define rng_double genrand_real2 +# define RNG_RAND_MAX 0x7fffffff +#else +# include +# define rng_init(seed) srand(seed) +# define rng_int rand() +# define rng_double ((rand()%RAND_MAX)/(double)RAND_MAX) +# define RNG_RAND_MAX RAND_MAX +#endif +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/sql.c b/src/util/sql.c new file mode 100644 index 000000000..9f653e8af --- /dev/null +++ b/src/util/sql.c @@ -0,0 +1,82 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "sql.h" + +#include "log.h" + +#include +#include +#include + +static FILE * sqlstream = NULL; +static char * sqlfilename = NULL; + +void +sql_init(const char * filename) +{ + if (sqlfilename!=NULL) free(sqlfilename); + sqlfilename = strdup(filename); +} + +void +_sql_print(const char * format, ...) +{ + if (!sqlstream && sqlfilename) { + sqlstream=fopen(sqlfilename, "wt+"); + free(sqlfilename); + sqlfilename=NULL; + } + if (sqlstream!=NULL) { + va_list marker; + va_start(marker, format); + vfprintf(sqlstream, format, marker); + va_end(marker); + } +} + +void +sql_done(void) +{ + if (sqlstream) fclose(sqlstream); + if (sqlfilename) free(sqlfilename); + sqlstream=NULL; + sqlfilename=NULL; +} + +const char * +sqlquote(const char * str) +{ +#define BUFFERS 4 +#define BUFSIZE 1024 + static char sqlstring[BUFSIZE*BUFFERS]; /* STATIC_RESULT: used for return, not across calls */ + static int index = 0; /* STATIC_XCALL: used across calls */ + char * start = sqlstring+index*BUFSIZE; + char * o = start; + const char * i = str; + while (*i && o-start < BUFSIZE-1) { + if (*i!='\'' && *i!='\"') { + *o++ = *i++; + } else ++i; + } + *o = '\0'; + index = (index+1) % BUFFERS; + return start; +} + diff --git a/src/util/sql.h b/src/util/sql.h new file mode 100644 index 000000000..b16fa7930 --- /dev/null +++ b/src/util/sql.h @@ -0,0 +1,35 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_UTIL_SQL +#define H_UTIL_SQL +#ifdef __cplusplus +extern "C" { +#endif + + extern void sql_init(const char * filename); + extern void sql_done(void); + extern const char * sqlquote(const char * str); + extern void _sql_print(const char * format, ...); + +#define sql_print(x) _sql_print x + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/storage.h b/src/util/storage.h new file mode 100644 index 000000000..96b62216b --- /dev/null +++ b/src/util/storage.h @@ -0,0 +1,48 @@ +#ifndef STORAGE_H +#define STORAGE_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct storage { + /* separator for readable files: */ + int (*w_brk)(struct storage *); + /* integer values: */ + int (*w_int)(struct storage *, int arg); + int (*r_int)(struct storage *); + /* float values: */ + int (*w_flt)(struct storage *, float arg); + float (*r_flt)(struct storage *); + /* id values: */ + int (*w_id)(struct storage *, int arg); + int (*r_id)(struct storage *); + /* tokens that contain no whitespace: */ + int (*w_tok)(struct storage *, const char * tok); + char *(*r_tok)(struct storage *); + void (*r_tok_buf)(struct storage *, char * result, size_t size); + /* strings that need to be quoted: */ + int (*w_str)(struct storage *, const char * tok); + char * (*r_str)(struct storage *); + void (*r_str_buf)(struct storage *, char * result, size_t size); + /* binary data: */ + int (*w_bin)(struct storage *, void * arg, size_t size); + void (*r_bin)(struct storage *, void * result, size_t size); + + int (*open)(struct storage *, const char * filename, int mode); + int (*close)(struct storage *); + + int encoding; + int version; + void * userdata; +} storage; + +#define IO_READ 0x01 +#define IO_WRITE 0x02 +#define IO_BINARY 0x04 +#define IO_TEXT 0x08 +#define IO_DEFAULT IO_BINARY + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/strings.c b/src/util/strings.c new file mode 100644 index 000000000..390bc5462 --- /dev/null +++ b/src/util/strings.c @@ -0,0 +1,132 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include + +/* libc includes */ +#include + +INLINE_FUNCTION unsigned int +hashstring(const char* s) +{ + unsigned int key = 0; + while (*s) { + key = key*37 + *s++; + } + return key & 0x7FFFFFFF; +} + +/* +static const char * +escape_string_inplace(char * buffer, unsigned int len, unsigned int offset) +{ +#define MAXQUOTES 32 + char * o; + char * d[MAXQUOTES+1]; + int i = 0; + + o = strchr(buffer, '"'); + if (!o) { + return buffer; + } + + while (*o && i0) { + const char * src = d[i]; + char * dst = d[i] + i + offset; + size_t mlen = d[i+1] - d[i]; + memmove(dst--, src, mlen); + *dst = '\\'; + } + return buffer; +} +*/ + +INLINE_FUNCTION const char * +escape_string(const char * str, char * buffer, unsigned int len) +{ + const char * start = strchr(str, '\"'); + if (start) { + static char s_buffer[4096]; /* STATIC_RESULT: used for return, not across calls */ + const char * p; + char * o; + size_t skip = start-str; + + if (buffer==NULL) { + buffer = s_buffer; + len = sizeof(s_buffer); + } + memcpy(buffer, str, skip); + o = buffer + skip; + p = str + skip; + do { + if (*p == '\"' || *p=='\\') { + if (len<2) { + *o = '\0'; + break; + } + (*o++) = '\\'; + len -= 2; + } else { + if (len<1) { + *o = '\0'; + break; + } + --len; + } + (*o++) = (*p); + } while (*p++); + return buffer; + } + return str; +} + +INLINE_FUNCTION unsigned int jenkins_hash(unsigned int a) +{ + a = (a+0x7ed55d16) + (a<<12); + a = (a^0xc761c23c) ^ (a>>19); + a = (a+0x165667b1) + (a<<5); + a = (a+0xd3a2646c) ^ (a<<9); + a = (a+0xfd7046c5) + (a<<3); + a = (a^0xb55a4f09) ^ (a>>16); + return a; +} + +INLINE_FUNCTION unsigned int wang_hash(unsigned int a) +{ + a = ~a + (a << 15); // a = (a << 15) - a - 1; + a = a ^ (a >> 12); + a = a + (a << 2); + a = a ^ (a >> 4); + a = a * 2057; // a = (a + (a << 3)) + (a << 11); + a = a ^ (a >> 16); + return a; +} diff --git a/src/util/strncpy.c b/src/util/strncpy.c new file mode 100644 index 000000000..8da32d488 --- /dev/null +++ b/src/util/strncpy.c @@ -0,0 +1,22 @@ + +/* + * Faster replacement for ISO-C strncpy, does not pad with zeros + */ + +#include + +char * +strncpy(char *to, const char *from, size_t size) +{ + char *t = to, *f = (char *)from; + int copied = 0; + + while(copied < size) { + *t = *f; + if(*f == '\0') break; + t++; f++; copied++; + } + + return to; +} + diff --git a/src/util/translation.c b/src/util/translation.c new file mode 100644 index 000000000..b92246a19 --- /dev/null +++ b/src/util/translation.c @@ -0,0 +1,488 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#include + +#include "translation.h" +#include "log.h" +#include "bsdstring.h" + +/* libc includes */ +#include +#include +#include +#include +#include + +/** + ** simple operand stack + **/ + +typedef struct opstack { + variant * begin; + variant * top; + int size; +} opstack; + +variant +opstack_pop(opstack ** stackp) +{ + opstack * stack = *stackp; + + assert(stack); + assert(stack->top>stack->begin); + return *(--stack->top); +} + +void +opstack_push(opstack ** stackp, variant data) +{ + opstack * stack = *stackp; + if (stack==NULL) { + stack = (opstack*)malloc(sizeof(opstack)); + stack->size = 1; + stack->begin = malloc(sizeof(variant) * stack->size); + stack->top = stack->begin; + *stackp = stack; + } + if (stack->top - stack->begin == stack->size) { + size_t pos = stack->top - stack->begin; + stack->size += stack->size; + stack->begin = realloc(stack->begin, sizeof(variant) * stack->size); + stack->top = stack->begin + pos; + } + *stack->top++ = data; +} + +/** + ** static buffer malloc + **/ + +#define BBUFSIZE 128*1024 +static struct { + char * begin; + char * end; + char * last; + char * current; +} buffer; + +char * +balloc(size_t size) +{ + static int init = 0; /* STATIC_XCALL: used across calls */ + if (!init) { + init = 1; + buffer.current = buffer.begin = malloc(BBUFSIZE); + buffer.end = buffer.begin + BBUFSIZE; + } + if (buffer.current + size > buffer.end) { + /* out of memory! */ + return NULL; + } + buffer.last = buffer.current; + buffer.current +=size; + return buffer.last; +} + +void +bfree(char * c) +/* only release this memory if it was part of the last allocation + * that's a joke, but who cares. + */ +{ + if (c>=buffer.last && cvalue = value; + var->symbol = symbol; + + var->next = variables; + variables = var; +} + +static variable * +find_variable(const char * symbol) +{ + variable * var = variables; + while (var) { + if (!strcmp(var->symbol, symbol)) break; + var = var->next; + } + return var; +} + +/** + ** constant values + **/ + +typedef struct function { + struct function * next; + const char * symbol; + evalfun parse; +} function; + +static function * functions; + +static void +free_functions(void) +{ + while (functions) { + function * fun = functions; + functions = fun->next; + free(fun); + } +} + +void +add_function(const char * symbol, evalfun parse) +{ + function * fun = (function*)malloc(sizeof(function)); + + fun->parse = parse; + fun->symbol = symbol; + + fun->next = functions; + functions = fun; +} + +static function * +find_function(const char * symbol) +{ + function * fun = functions; + while (fun) { + if (!strcmp(fun->symbol, symbol)) break; + fun = fun->next; + } + return fun; +} + +static const char * parse(opstack **, const char* in, const void *); +/* static const char * sample = "\"enno and $bool($if($eq($i,0),\"noone else\",\"$i other people\"))\""; */ + +static const char * +parse_symbol(opstack ** stack, const char* in, const void * userdata) +/* in is the symbol name and following text, starting after the $ + * result goes on the stack + */ +{ + boolean braces = false; + char symbol[32]; + char *cp = symbol; /* current position */ + + if (*in=='{') { + braces = true; + ++in; + } + while (isalnum(*in) || *in=='.') *cp++ = *in++; + *cp = '\0'; + /* symbol will now contain the symbol name */ + if (*in=='(') { + /* it's a function we need to parse, start by reading the parameters */ + function * foo; + while (*in != ')') { + in = parse(stack, ++in, userdata); /* will push the result on the stack */ + if (in==NULL) return NULL; + } + ++in; + foo = find_function(symbol); + if (foo==NULL) { + log_error(("parser does not know about \"%s\" function.\n", symbol)); + return NULL; + } + foo->parse(stack, userdata); /* will pop parameters from stack (reverse order!) and push the result */ + } else { + variable * var = find_variable(symbol); + if (braces && *in=='}') { + ++in; + } + /* it's a constant (variable is a misnomer, but heck, const was taken;)) */ + if (var==NULL) { + log_error(("parser does not know about \"%s\" variable.\n", symbol)); + return NULL; + } + opush(stack, var->value); + } + return in; +} + +#define TOKENSIZE 4096 +static const char * +parse_string(opstack ** stack, const char* in, const void * userdata) /* (char*) -> char* */ +{ + char * c; + char * buffer = balloc(TOKENSIZE); + size_t size = TOKENSIZE - 1; + const char * ic = in; + char * oc = buffer; + /* mode flags */ + boolean f_escape = false; + boolean bDone = false; + variant var; + + while (*ic && !bDone) { + if (f_escape) { + f_escape = false; + switch (*ic) { + case 'n': + if (size>0) { *oc++='\n'; --size; } + break; + case 't': + if (size>0) { *oc++='\t'; --size; } + break; + default: + if (size>0) { *oc++=*ic++; --size; } + } + } else { + int ch = (unsigned char)(*ic); + int bytes; + + switch (ch) { + case '\\': + f_escape = true; + ++ic; + break; + case '"': + bDone = true; + ++ic; + break; + case '$': + ic = parse_symbol(stack, ++ic, userdata); + if (ic==NULL) return NULL; + c = (char*)opop_v(stack); + bytes = (int)strlcpy(oc, c, size); + if (bytes<(int)size) oc += bytes; + else oc += size; + bfree(c); + break; + default: + if (size>0) { *oc++=*ic++; --size; } + else ++ic; + } + } + } + *oc++ = '\0'; + bfree(oc); + var.v = buffer; + opush(stack, var); + return ic; +} + +static const char * +parse_int(opstack ** stack, const char * in) +{ + int k = 0; + int vz = 1; + boolean ok = false; + variant var; + do { + switch (*in) { + case '+': + ++in; + break; + case '-': + ++in; + vz=vz*-1; + break; + default: + ok = true; + } + } while (!ok); + while (isdigit(*(unsigned char*)in)) { + k = k * 10 + (*in++)-'0'; + } + var.i = k*vz; + opush(stack, var); + return in; +} + + +static const char * +parse(opstack ** stack, const char* inn, const void * userdata) +{ + const char * b = inn; + while (*b) { + switch (*b) { + case '"': + return parse_string(stack, ++b, userdata); + break; + case '$': + return parse_symbol(stack, ++b, userdata); + break; + default: + if (isdigit(*(unsigned char*)b) || *b=='-' || *b=='+') { + return parse_int(stack, b); + } + else ++b; + } + } + log_error(("could not parse \"%s\". Probably invalid message syntax.", inn)); + return NULL; +} + +const char * +translate(const char* format, const void * userdata, const char* vars, variant args[]) +{ + int i = 0; + const char *ic = vars; + char symbol[32]; + char *oc = symbol; + opstack * stack = NULL; + const char * rv; + + brelease(); + free_variables(); + + assert(format); + assert(*ic == 0 || isalnum(*ic)); + while (*ic) { + *oc++ = *ic++; + if (!isalnum(*ic)) { + variant x = args[i++]; + *oc = '\0'; + oc = symbol; + add_variable(strcpy(balloc(strlen(symbol)+1), symbol), x); + while (*ic && !isalnum(*ic)) ++ic; + } + } + + if (format[0]=='"') { + rv = parse(&stack, format, userdata); + } + else { + rv = parse_string(&stack, format, userdata); + } + if (rv!=NULL) { + if (rv[0]) { + log_error(("residual data after parsing: %s\n", rv)); + } + rv = (const char*)opop(&stack).v; + free(stack->begin); + free(stack); + } + return rv; +} + +static void +eval_lt(opstack ** stack, const void * userdata) /* (int, int) -> int */ +{ + int a = opop_i(stack); + int b = opop_i(stack); + int rval = (b int */ +{ + int a = opop_i(stack); + int b = opop_i(stack); + int rval = (a==b)?1:0; + opush_i(stack, rval); + unused(userdata); +} + +static void +eval_add(opstack ** stack, const void * userdata) /* (int, int) -> int */ +{ + int a = opop_i(stack); + int b = opop_i(stack); + opush_i(stack, a+b); + unused(userdata); +} + +static void +eval_isnull(opstack ** stack, const void * userdata) /* (int, int) -> int */ +{ + void * a = opop_v(stack); + opush_i(stack, (a==NULL)?1:0); + unused(userdata); +} + +static void +eval_if(opstack ** stack, const void * userdata) /* (int, int) -> int */ +{ + void * a = opop_v(stack); + void * b = opop_v(stack); + int cond = opop_i(stack); + opush_v(stack, cond?b:a); + unused(userdata); +} + +static void +eval_strlen(opstack ** stack, const void * userdata) /* string -> int */ +{ + const char * c = (const char *)opop_v(stack); + opush_i(stack, c?(int)strlen(c):0); + unused(userdata); +} + +#include "base36.h" +static void +eval_int(opstack ** stack, const void * userdata) +{ + int i = opop_i(stack); + const char * c = itoa10(i); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +void +translation_init(void) +{ + add_function("lt", &eval_lt); + add_function("eq", &eval_eq); + add_function("int", &eval_int); + add_function("add", &eval_add); + add_function("strlen", &eval_strlen); + add_function("if", &eval_if); + add_function("isnull", &eval_isnull); +} + +void +translation_done(void) +{ + free_functions(); + free(buffer.begin); +} diff --git a/src/util/translation.h b/src/util/translation.h new file mode 100644 index 000000000..6aa6dd28d --- /dev/null +++ b/src/util/translation.h @@ -0,0 +1,45 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_UTIL_TRANSLATION +#define H_UTIL_TRANSLATION +#ifdef __cplusplus +extern "C" { +#endif + +#include "variant.h" +struct opstack; +extern void opstack_push(struct opstack ** stack, variant data); +#define opush_i(stack, x) { variant localvar; localvar.i = x; opstack_push(stack, localvar); } +#define opush_v(stack, x) { variant localvar; localvar.v = x; opstack_push(stack, localvar); } +#define opush(stack, i) opstack_push(stack, i) + +extern variant opstack_pop(struct opstack ** stack); +#define opop_v(stack) opstack_pop(stack).v +#define opop_i(stack) opstack_pop(stack).i +#define opop(stack) opstack_pop(stack) + +extern void translation_init(void); +extern void translation_done(void); +extern const char * translate(const char* format, const void * userdata, const char* vars, variant args[]); + +/* eval_x functions */ +typedef void (*evalfun)(struct opstack ** stack, const void *); +extern void add_function(const char * symbol, evalfun parse); + +/* transient memory blocks */ +extern char * balloc(size_t size); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/umlaut.c b/src/util/umlaut.c new file mode 100644 index 000000000..67bd03964 --- /dev/null +++ b/src/util/umlaut.c @@ -0,0 +1,160 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "umlaut.h" + +#include "log.h" +#include "unicode.h" + +#include +#include +#include +#include + +typedef struct tref { + struct tref * nexthash; + ucs4_t ucs; + struct tnode * node; +} tref; + +#define LEAF 1 /* leaf node for a word. always matches */ +#define SHARED 2 /* at least two words share the node */ + +void +addtoken(tnode * root, const char * str, variant id) +{ + static const struct replace { /* STATIC_CONST: constant value */ + ucs4_t ucs; + const char str[3]; + } replace[] = { + /* match lower-case (!) umlauts and others to transcriptions */ + { 228, "AE"}, /* auml */ + { 246, "OE"}, /* ouml */ + { 252, "UE"}, /* uuml */ + { 223, "SS"}, /* szlig */ + { 230, "AE"}, /* norsk */ + { 248, "OE"}, /* norsk */ + { 229, "AA"}, /* norsk */ + { 0, "" } + }; + + if (!*str) { + root->id = id; + root->flags |= LEAF; + } else { + tref * next; + int ret, index, i = 0; + ucs4_t ucs, lcs; + size_t len; + + ret = unicode_utf8_to_ucs4(&ucs, str, &len); + assert(ret==0 || !"invalid utf8 string"); + lcs = ucs; + +#if NODEHASHSIZE == 8 + index = ucs & 7; +#else + index = ucs % NODEHASHSIZE; +#endif + assert(index>=0); + next = root->next[index]; + if (!(root->flags & LEAF)) root->id = id; + while (next && next->ucs != ucs) next = next->nexthash; + if (!next) { + tref * ref; + tnode * node = calloc(1, sizeof(tnode)); + + if (ucs<'a' || ucs>'z') { + lcs = towlower((wint_t)ucs); + } + if (ucs==lcs) { + ucs = towupper((wint_t)ucs); + } + + ref = malloc(sizeof(tref)); + ref->ucs = ucs; + ref->node = node; + ref->nexthash=root->next[index]; + root->next[index] = ref; + + /* try lower/upper casing the character, and try again */ + if (ucs!=lcs) { +#if NODEHASHSIZE == 8 + index = lcs & 7; +#else + index = lcs % NODEHASHSIZE; +#endif + ref = malloc(sizeof(tref)); + ref->ucs = lcs; + ref->node = node; + ref->nexthash = root->next[index]; + root->next[index] = ref; + } + next=ref; + } else { + next->node->flags |= SHARED; + if ((next->node->flags & LEAF) == 0) next->node->id.v = NULL; /* why?*/ + } + addtoken(next->node, str+len, id); + while (replace[i].str[0]) { + if (lcs==replace[i].ucs) { + char zText[1024]; + memcpy(zText, replace[i].str, 3); + strcpy(zText+2, (const char*)str+len); + addtoken(root, zText, id); + break; + } + ++i; + } + } +} + +int +findtoken(const tnode * tk, const char * str, variant* result) +{ + if (!str || *str==0) return E_TOK_NOMATCH; + + do { + int index; + const tref * ref; + ucs4_t ucs; + size_t len; + int ret = unicode_utf8_to_ucs4(&ucs, str, &len); + + if (ret!=0) { + /* encoding is broken. youch */ + return E_TOK_NOMATCH; + } +#if NODEHASHSIZE == 8 + index = ucs & 7; +#else + index = ucs % NODEHASHSIZE; +#endif + ref = tk->next[index]; + while (ref && ref->ucs!=ucs) ref = ref->nexthash; + str+=len; + if (!ref) return E_TOK_NOMATCH; + tk = ref->node; + } while (*str); + if (tk) { + *result = tk->id; + return E_TOK_SUCCESS; + } + return E_TOK_NOMATCH; +} diff --git a/src/util/umlaut.h b/src/util/umlaut.h new file mode 100644 index 000000000..a89f3df77 --- /dev/null +++ b/src/util/umlaut.h @@ -0,0 +1,51 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef _UMLAUT_H +#define _UMLAUT_H + +#include "variant.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define E_TOK_NOMATCH (-1) +#define E_TOK_SUCCESS 0 +#define NODEHASHSIZE 8 +struct tref; + +typedef struct tnode { + struct tref * next[NODEHASHSIZE]; + unsigned char flags; + variant id; +} tnode; + +int findtoken(const struct tnode * tk, const char * str, variant* result); +void addtoken(struct tnode * root, const char * str, variant id); + +typedef struct local_names { + struct local_names * next; + const struct locale * lang; + struct tnode names; +} local_names; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/unicode.c b/src/util/unicode.c new file mode 100644 index 000000000..adda90870 --- /dev/null +++ b/src/util/unicode.c @@ -0,0 +1,436 @@ +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2007 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +#include +#include "unicode.h" + +#include +#include + +#define B00000000 0x00 +#define B10000000 0x80 +#define B11000000 0xC0 +#define B11100000 0xE0 +#define B11110000 0xF0 +#define B11111000 0xF8 +#define B11111100 0xFC +#define B11111110 0xFE + +#define B00111111 0x3F +#define B00011111 0x1F +#define B00001111 0x0F +#define B00000111 0x07 +#define B00000011 0x03 +#define B00000001 0x01 + +int +unicode_utf8_tolower(utf8_t *op, size_t outlen, const utf8_t *ip) +{ + while (*ip) { + ucs4_t ucs = *ip; + ucs4_t low; + size_t size = 1; + + if (ucs & 0x80) { + int ret = unicode_utf8_to_ucs4(&ucs, ip, &size); + if (ret!=0) { + return ret; + } + } + if (size>outlen) { + return ENOMEM; + } + low = towlower((wint_t)ucs); + if (low==ucs) { + memcpy(op, ip, size); + ip += size; + op += size; + outlen -=size; + } else { + ip += size; + unicode_ucs4_to_utf8(op, &size, low); + op += size; + outlen -=size; + } + } + + if (outlen<=0) { + return ENOMEM; + } + *op = 0; + return 0; +} + +int +unicode_latin1_to_utf8(utf8_t *out, size_t *outlen, const char *in, size_t *inlen) +{ + int is = (int)*inlen; + int os = (int)*outlen; + const char * ip = in; + utf8_t * op = out; + + while (ip-in 0xBF) { + if (op-out>=os-1) break; + *op++ = 0xC3; + *op++ = c-64; + } else if (c>0x7F) { + if (op-out>=os-1) break; + *op++ = 0xC2; + *op++ = c; + } else { + if (op-out>=os) break; + *op++ = c; + } + ++ip; + } + *outlen = op-out; + *inlen = ip-in; + return (int)*outlen; +} + +int +unicode_utf8_strcasecmp(const utf8_t * a, const char * b) +{ + while (*a && *b) { + int ret; + size_t size; + ucs4_t ucsa = *a, ucsb = *b; + + if (ucsa & 0x80) { + ret = unicode_utf8_to_ucs4(&ucsa, a, &size); + if (ret!=0) return -1; + a += size; + } else ++a; + if (ucsb & 0x80) { + ret = unicode_utf8_to_ucs4(&ucsb, b, &size); + if (ret!=0) return -1; + b += size; + } else ++b; + + if (ucsb!=ucsa) { + ucsb = towlower((wint_t)ucsb); + ucsa = towlower((wint_t)ucsa); + if (ucsbucsa) return -1; + } + } + if (*b) return -1; + if (*a) return 1; + return 0; +} + +/* Convert a UCS-4 character to UTF-8. */ +int +unicode_ucs4_to_utf8 (utf8_t *utf8_character, size_t *size, ucs4_t ucs4_character) +{ + int utf8_bytes; + + if (ucs4_character <= 0x0000007F) { + /* 0xxxxxxx */ + utf8_bytes = 1; + utf8_character[0] = (char) ucs4_character; + } + else if (ucs4_character <= 0x000007FF) { + /* 110xxxxx 10xxxxxx */ + utf8_bytes = 2; + utf8_character[0] = (char) ((ucs4_character >> 6) | B11000000); + utf8_character[1] = (char) ((ucs4_character & B00111111) | B10000000); + } + else if (ucs4_character <= 0x0000FFFF) { + /* 1110xxxx 10xxxxxx 10xxxxxx */ + utf8_bytes = 3; + utf8_character[0] = (char) ((ucs4_character >> 12) | B11100000); + utf8_character[1] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); + utf8_character[2] = (char) ((ucs4_character & B00111111) | B10000000); + } + else if (ucs4_character <= 0x001FFFFF) { + /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_bytes = 4; + utf8_character[0] = (char) ((ucs4_character >> 18) | B11110000); + utf8_character[1] = (char) (((ucs4_character >> 12) & B00111111) | B10000000); + utf8_character[2] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); + utf8_character[3] = (char) ((ucs4_character & B00111111) | B10000000); + } + else if (ucs4_character <= 0x03FFFFFF) { + /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_bytes = 5; + utf8_character[0] = (char) ((ucs4_character >> 24) | B11111000); + utf8_character[1] = (char) (((ucs4_character >> 18) & B00111111) | B10000000); + utf8_character[2] = (char) (((ucs4_character >> 12) & B00111111) | B10000000); + utf8_character[3] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); + utf8_character[4] = (char) ((ucs4_character & B00111111) | B10000000); + } + else if (ucs4_character <= 0x7FFFFFFF) { + /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_bytes = 6; + utf8_character[0] = (char) ((ucs4_character >> 30) | B11111100); + utf8_character[1] = (char) (((ucs4_character >> 24) & B00111111) | B10000000); + utf8_character[2] = (char) (((ucs4_character >> 18) & B00111111) | B10000000); + utf8_character[3] = (char) (((ucs4_character >> 12) & B00111111) | B10000000); + utf8_character[4] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); + utf8_character[5] = (char) ((ucs4_character & B00111111) | B10000000); + } + else { + return EILSEQ; + } + + *size = utf8_bytes; + + return 0; +} + + +/* Convert a UTF-8 encoded character to UCS-4. */ +int +unicode_utf8_to_ucs4(ucs4_t *ucs4_character, const utf8_t *utf8_string, + size_t *length) +{ + utf8_t utf8_character = utf8_string[0]; + + /* Is the character in the ASCII range? If so, just copy it to the + output. */ + if (~utf8_character & 0x80) + { + *ucs4_character = utf8_character; + *length = 1; + } + else if ((utf8_character & 0xE0) == 0xC0) + { + /* A two-byte UTF-8 sequence. Make sure the other byte is good. */ + if (utf8_string[1] != '\0' && + (utf8_string[1] & 0xC0) != 0x80) + { + return EILSEQ; + } + + *ucs4_character = + ((utf8_string[1] & 0x3F) << 0) + + ((utf8_character & 0x1F) << 6); + *length = 2; + } + else if ((utf8_character & 0xF0) == 0xE0) + { + /* A three-byte UTF-8 sequence. Make sure the other bytes are + good. */ + if ((utf8_string[1] != '\0') && + (utf8_string[1] & 0xC0) != 0x80 && + (utf8_string[2] != '\0') && + (utf8_string[2] & 0xC0) != 0x80) + { + return EILSEQ; + } + + *ucs4_character = + ((utf8_string[2] & 0x3F) << 0) + + ((utf8_string[1] & 0x3F) << 6) + + ((utf8_character & 0x0F) << 12); + *length = 3; + } + else if ((utf8_character & 0xF8) == 0xF0) + { + /* A four-byte UTF-8 sequence. Make sure the other bytes are + good. */ + if ((utf8_string[1] != '\0') && + (utf8_string[1] & 0xC0) != 0x80 && + (utf8_string[2] != '\0') && + (utf8_string[2] & 0xC0) != 0x80 && + (utf8_string[3] != '\0') && + (utf8_string[3] & 0xC0) != 0x80) + { + return EILSEQ; + } + + *ucs4_character = + ((utf8_string[3] & 0x3F) << 0) + + ((utf8_string[2] & 0x3F) << 6) + + ((utf8_string[1] & 0x3F) << 12) + + ((utf8_character & 0x07) << 18); + *length = 4; + } + else if ((utf8_character & 0xFC) == 0xF8) + { + /* A five-byte UTF-8 sequence. Make sure the other bytes are + good. */ + if ((utf8_string[1] != '\0') && + (utf8_string[1] & 0xC0) != 0x80 && + (utf8_string[2] != '\0') && + (utf8_string[2] & 0xC0) != 0x80 && + (utf8_string[3] != '\0') && + (utf8_string[3] & 0xC0) != 0x80 && + (utf8_string[4] != '\0') && + (utf8_string[4] & 0xC0) != 0x80) + { + return EILSEQ; + } + + *ucs4_character = + ((utf8_string[4] & 0x3F) << 0) + + ((utf8_string[3] & 0x3F) << 6) + + ((utf8_string[2] & 0x3F) << 12) + + ((utf8_string[1] & 0x3F) << 18) + + ((utf8_character & 0x03) << 24); + *length = 5; + } + else if ((utf8_character & 0xFE) == 0xFC) + { + /* A six-byte UTF-8 sequence. Make sure the other bytes are + good. */ + if ((utf8_string[1] != '\0') && + (utf8_string[1] & 0xC0) != 0x80 && + (utf8_string[2] != '\0') && + (utf8_string[2] & 0xC0) != 0x80 && + (utf8_string[3] != '\0') && + (utf8_string[3] & 0xC0) != 0x80 && + (utf8_string[4] != '\0') && + (utf8_string[4] & 0xC0) != 0x80 && + (utf8_string[5] != '\0') && + (utf8_string[5] & 0xC0) != 0x80) + { + return EILSEQ; + } + + *ucs4_character = + ((utf8_string[5] & 0x3F) << 0) + + ((utf8_string[4] & 0x3F) << 6) + + ((utf8_string[3] & 0x3F) << 12) + + ((utf8_string[2] & 0x3F) << 18) + + ((utf8_string[1] & 0x3F) << 24) + + ((utf8_character & 0x01) << 30); + *length = 6; + } + else + { + return EILSEQ; + } + + return 0; +} + +/** Convert a UTF-8 encoded character to CP437. */ +int +unicode_utf8_to_cp437(char *cp_character, const utf8_t *utf8_string, + size_t *length) +{ + ucs4_t ucs4_character; + int result; + + result = unicode_utf8_to_ucs4(&ucs4_character, utf8_string, length); + if (result!=0) { + /* pass decoding characters upstream */ + return result; + } + + if (ucs4_character<0x7F) { + *cp_character = (char)ucs4_character; + } else { + struct { ucs4_t ucs4; unsigned char cp437; } xref[160] = { + {0x00A0, 255}, {0x00A1, 173}, {0x00A2, 155}, {0x00A3, 156}, + {0x00A5, 157}, {0x00A7, 21}, {0x00AA, 166}, {0x00AB, 174}, + {0x00AC, 170}, {0x00B0, 248}, {0x00B1, 241}, {0x00B2, 253}, + {0x00B5, 230}, {0x00B6, 20}, {0x00B7, 250}, {0x00BA, 167}, + {0x00BB, 175}, {0x00BC, 172}, {0x00BD, 171}, {0x00BF, 168}, + {0x00C4, 142}, {0x00C5, 143}, {0x00C6, 146}, {0x00C7, 128}, + {0x00C9, 144}, {0x00D1, 165}, {0x00D6, 153}, {0x00DC, 154}, + {0x00DF, 225}, {0x00E0, 133}, {0x00E1, 160}, {0x00E2, 131}, + {0x00E4, 132}, {0x00E5, 134}, {0x00E6, 145}, {0x00E7, 135}, + {0x00E8, 138}, {0x00E9, 130}, {0x00EA, 136}, {0x00EB, 137}, + {0x00EC, 141}, {0x00ED, 161}, {0x00EE, 140}, {0x00EF, 139}, + {0x00F1, 164}, {0x00F2, 149}, {0x00F3, 162}, {0x00F4, 147}, + {0x00F6, 148}, {0x00F7, 246}, {0x00F9, 151}, {0x00FA, 163}, + {0x00FB, 150}, {0x00FC, 129}, {0x00FF, 152}, {0x0192, 159}, + {0x0393, 226}, {0x0398, 233}, {0x03A3, 228}, {0x03A6, 232}, + {0x03A9, 234}, {0x03B1, 224}, {0x03B4, 235}, {0x03B5, 238}, + {0x03C0, 227}, {0x03C3, 229}, {0x03C4, 231}, {0x03C6, 237}, + {0x2022, 7}, {0x203C, 19}, {0x207F, 252}, {0x20A7, 158}, + {0x2190, 27}, {0x2191, 24}, {0x2192, 26}, {0x2193, 25}, + {0x2194, 29}, {0x2195, 18}, {0x21A8, 23}, {0x2219, 249}, + {0x221A, 251}, {0x221E, 236}, {0x221F, 28}, {0x2229, 239}, + {0x2248, 247}, {0x2261, 240}, {0x2264, 243}, {0x2265, 242}, + {0x2302, 127}, {0x2310, 169}, {0x2320, 244}, {0x2321, 245}, + {0x2500, 196}, {0x2502, 179}, {0x250C, 218}, {0x2510, 191}, + {0x2514, 192}, {0x2518, 217}, {0x251C, 195}, {0x2524, 180}, + {0x252C, 194}, {0x2534, 193}, {0x253C, 197}, {0x2550, 205}, + {0x2551, 186}, {0x2552, 213}, {0x2553, 214}, {0x2554, 201}, + {0x2555, 184}, {0x2556, 183}, {0x2557, 187}, {0x2558, 212}, + {0x2559, 211}, {0x255A, 200}, {0x255B, 190}, {0x255C, 189}, + {0x255D, 188}, {0x255E, 198}, {0x255F, 199}, {0x2560, 204}, + {0x2561, 181}, {0x2562, 182}, {0x2563, 185}, {0x2564, 209}, + {0x2565, 210}, {0x2566, 203}, {0x2567, 207}, {0x2568, 208}, + {0x2569, 202}, {0x256A, 216}, {0x256B, 215}, {0x256C, 206}, + {0x2580, 223}, {0x2584, 220}, {0x2588, 219}, {0x258C, 221}, + {0x2590, 222}, {0x2591, 176}, {0x2592, 177}, {0x2593, 178}, + {0x25A0, 254}, {0x25AC, 22}, {0x25B2, 30}, {0x25BA, 16}, + {0x25BC, 31}, {0x25C4, 17}, {0x25CB, 9}, {0x25D8, 8}, + {0x25D9, 10}, {0x263A, 1}, {0x263B, 2}, {0x263C, 15}, + {0x2640, 12}, {0x2642, 11}, {0x2660, 6}, {0x2663, 5}, + {0x2665, 3}, {0x2666, 4}, {0x266A, 13}, {0x266B, 14} + }; + int l=0, r=160; + while (l!=r) { + int m = (l+r)/2; + if (xref[m].ucs4==ucs4_character) { + *cp_character = (char)xref[m].cp437; + break; + } + else if (xref[m].ucs4=0xA0) { + *cp_character = (char)ucs4_character; + } else { + struct { ucs4_t ucs4; unsigned char cp; } xref[] = { + {0x20ac, 0x80}, {0x0081, 0x81}, {0x201a, 0x82}, {0x0192, 0x83}, + {0x201e, 0x84}, {0x2026, 0x85}, {0x2020, 0x86}, {0x2021, 0x87}, + {0x02c6, 0x88}, {0x2030, 0x89}, {0x0160, 0x8a}, {0x2039, 0x8b}, + {0x0152, 0x8c}, {0x008d, 0x8d}, {0x017d, 0x8e}, {0x008f, 0x8f}, + {0x0090, 0x90}, {0x2018, 0x91}, {0x2019, 0x92}, {0x201c, 0x93}, + {0x201d, 0x94}, {0x2022, 0x95}, {0x2013, 0x96}, {0x2014, 0x97}, + {0x02dc, 0x98}, {0x2122, 0x99}, {0x0161, 0x9a}, {0x203a, 0x9b}, + {0x0153, 0x9c}, {0x009d, 0x9d}, {0x017e, 0x9e}, {0x0178, 0x9f} + }; + int l=0, r=sizeof(xref)/sizeof(xref[0]); + while (l!=r) { + int m = (l+r)/2; + if (xref[m].ucs4==ucs4_character) { + *cp_character = (char)xref[m].cp; + break; + } + else if (xref[m].ucs4 + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef _UNICODE_H +#define _UNICODE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#define USE_UNICODE + typedef unsigned long ucs4_t; + typedef char utf8_t; + + extern int unicode_utf8_to_cp437(char *result, const utf8_t *utf8_string, size_t *length); + extern int unicode_utf8_to_cp1252(char *result, const utf8_t *utf8_string, size_t *length); + extern int unicode_utf8_to_ucs4(ucs4_t *result, const utf8_t *utf8_string, size_t *length); + extern int unicode_ucs4_to_utf8 (utf8_t *result, size_t *size, ucs4_t ucs4_character); + extern int unicode_utf8_strcasecmp(const utf8_t * a, const utf8_t * b); + extern int unicode_latin1_to_utf8(utf8_t *out, size_t *outlen, const char *in, size_t *inlen); + extern int unicode_utf8_tolower(utf8_t *out, size_t outlen, const utf8_t *in); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/variant.h b/src/util/variant.h new file mode 100644 index 000000000..62fe323c6 --- /dev/null +++ b/src/util/variant.h @@ -0,0 +1,24 @@ +#ifndef STRUCT_VARIANT_H +#define STRUCT_VARIANT_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef union variant { + void *v; + int i; + char c; + short s; + short sa[2]; + char ca[4]; + float f; +} variant; + +typedef enum variant_type { + VAR_NONE, VAR_INT, VAR_VOIDPTR, VAR_CHAR, VAR_SHORT, VAR_SHORTA, VAR_CHARA, VAR_FLOAT +} variant_type; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/vmap.c b/src/util/vmap.c new file mode 100644 index 000000000..6ca8f473d --- /dev/null +++ b/src/util/vmap.c @@ -0,0 +1,146 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifdef _MSC_VER +#pragma warning (disable: 4711) +#endif + +#include +#include +#include +#include +#include "vmap.h" + +size_t +vmap_lowerbound(const vmap * vm, const int key) +/* returns the index of the entry which has the greatest key that is less or + * equal to 'key' */ +{ + vmapentry *first = vm->data, *middle; + unsigned int half, len = vm->size; + while (len > 0) { + half = len / 2; + middle = first; + middle += half; + if (middle->key < key) { + first = middle + 1; + len = len - half - 1; + } else + len = half; + } + return first - vm->data; +} + +void +vmap_init(vmap * map) +{ + map->size = 0; /* !! */ + map->maxsize = 4; + map->data = calloc(4, sizeof(vmapentry)); +} + +size_t +vmap_upperbound(const vmap * vm, const int key) +/* returns the index of the entry which has the smallest key that is greater + * or equal to 'key' */ +{ + unsigned int half, len = vm->size; + vmapentry *first = vm->data, *middle; + while (len > 0) { + half = len / 2; + middle = first; + middle += half; + if (key < middle->key) + len = half; + else { + first = middle + 1; + len = len - half - 1; + } + } + return first - vm->data; +} + +size_t +vmap_get(vmap * vm, const int key) +{ + size_t insert = vmap_lowerbound(vm, key); + vmapentry *at; + + /* make sure it's a unique key: */ + if (insert != vm->size && vm->data[insert].key == key) + return insert; + /* insert at this position: */ + if (vm->size == vm->maxsize) { + /* need more space */ + vm->maxsize *= 2; + vm->data = realloc(vm->data, vm->maxsize * sizeof(vmapentry)); + } + at = vm->data + insert; + memmove(at + 1, at, (vm->size - insert) * sizeof(vmapentry)); /* !1.3! */ + at->key = key; + at->value = 0; + ++vm->size; + return insert; +} + +size_t +vmap_insert(vmap * vm, const int key, void *data) +/* inserts an object into the vmap, identifies it with the 'key' which must be + * unique, and returns the vmapentry it created. */ +{ + size_t insert = vmap_lowerbound(vm, key); + vmapentry *at; + + /* make sure it's a unique key: */ + assert(insert == vm->size || vm->data[insert].key != key); + /* insert at this position: */ + if (vm->size == vm->maxsize) { + /* need more space */ + vm->maxsize = vm->maxsize ? (vm->maxsize * 2) : 4; + vm->data = realloc(vm->data, vm->maxsize * sizeof(vmapentry)); + } + at = vm->data + insert; + memmove(at + 1, at, (vm->size - insert) * sizeof(vmapentry)); + at->key = key; + at->value = data; + ++vm->size; + return insert; +} + +size_t +vmap_find(const vmap * vm, const int key) +/* returns the index of the vmapentry that's identified by the key or size (a + * past-the-end value) if it is not found. */ +{ + vmapentry *first = vm->data, *middle; + unsigned int half, len = vm->size; + while (len > 0) { + half = len / 2; + middle = first; + middle += half; + if (middle->key < key) { + first = middle + 1; + len = len - half - 1; + } else + len = half; + } + if (first != vm->data + vm->size && first->key == key) + return first - vm->data; + else + return vm->size; +} diff --git a/src/util/vmap.h b/src/util/vmap.h new file mode 100644 index 000000000..872d4db35 --- /dev/null +++ b/src/util/vmap.h @@ -0,0 +1,47 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef VMAP_H +#define VMAP_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct vmapentry vmapentry; +struct vmapentry { + int key; + void *value; +}; +typedef struct vmap vmap; +struct vmap { + vmapentry *data; + unsigned int size; + unsigned int maxsize; +}; + +size_t vmap_lowerbound(const vmap * vm, const int key); +size_t vmap_upperbound(const vmap * vm, const int key); +size_t vmap_insert(vmap * vm, const int key, void *data); +size_t vmap_find(const vmap * vm, const int key); +size_t vmap_get(vmap * vm, const int key); +void vmap_init(vmap * vm); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/vset.c b/src/util/vset.c new file mode 100644 index 000000000..f4bac1bb0 --- /dev/null +++ b/src/util/vset.c @@ -0,0 +1,104 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "vset.h" + +void +vset_init(vset * s) +{ + s->data = 0; + s->size = 0; + s->maxsize = 0; +} + +void +vset_destroy(vset * s) +{ + if (s->data) + free(s->data); +} + +int +vset_erase(vset * s, void *item) +{ + size_t i; + + for (i = 0; i != s->size; ++i) + if (s->data[i] == item) { + s->size--; + s->data[i] = s->data[s->size]; + return 1; + } + return 0; +} + +size_t +vset_add(vset * s, void *item) +{ + size_t i; + + if (!s->data) { + s->size = 0; + s->maxsize = 4; + s->data = calloc(4, sizeof(void *)); + } + for (i = 0; i != s->size; ++i) + if (s->data[i] == item) + return i; + if (s->size == s->maxsize) { + s->maxsize *= 2; + s->data = realloc(s->data, s->maxsize * sizeof(void *)); + } + s->data[s->size] = item; + ++s->size; + return s->size - 1; +} + +void * +vset_pop(vset *s) +{ + if(s->size == 0) return NULL; + s->size--; + return s->data[s->size+1]; +} + +int +vset_count(vset *s, void *item) +{ + size_t i; + int c = 0; + + for(i = 0; i != s->size; ++i) { + if(s->data[i] == item) c++; + } + + return c; +} + +void +vset_concat(vset *to, vset *from) +{ + size_t i; + + for(i=0; i != from->size; ++i) { + vset_add(to, from->data[i]); + } +} + diff --git a/src/util/vset.h b/src/util/vset.h new file mode 100644 index 000000000..30a045ceb --- /dev/null +++ b/src/util/vset.h @@ -0,0 +1,43 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef VOIDPTR_SETS +#define VOIDPTR_SETS +#ifdef __cplusplus +extern "C" { +#endif + +#include +typedef struct vset vset; +struct vset { + void **data; + size_t size; + size_t maxsize; +}; +extern void vset_init(vset * s); +extern void vset_destroy(vset * s); +extern size_t vset_add(vset * s, void *); +extern int vset_erase(vset * s, void *); +extern int vset_count(vset *s, void * i); +extern void *vset_pop(vset *s); +extern void vset_concat(vset *to, vset *from); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/windir.c b/src/util/windir.c new file mode 100644 index 000000000..9d62f8360 --- /dev/null +++ b/src/util/windir.c @@ -0,0 +1,56 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifdef _MSC_VER +#include + +#include +#include +#include "windir.h" + +DIR * +opendir(const char *name) +{ + static DIR direct; /* STATIC_RESULT: used for return, not across calls */ + + direct.first = 1; + _searchenv(name, "ERESSEA_PATH", direct.name); + if (*direct.name != '\0') + return &direct; + return NULL; +} + +struct dirent * +readdir(DIR * thedir) +{ + static struct _finddata_t ft; /* STATIC_RESULT: used for return, not across calls */ + static struct dirent de; /* STATIC_RESULT: used for return, not across calls */ + char where[_MAX_PATH]; + + strcat(strcpy(where, thedir->name), "/*"); + if (thedir->first) { + thedir->first = 0; + de.hnd = _findfirst(where, &ft); + } else { + if (_findnext(de.hnd, &ft) != 0) + return NULL; + } + _splitpath(ft.name, de.d_drive, de.d_dir, de.d_name, de.d_ext); + return &de; +} +#endif diff --git a/src/util/windir.h b/src/util/windir.h new file mode 100644 index 000000000..de9851aa9 --- /dev/null +++ b/src/util/windir.h @@ -0,0 +1,50 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef WINDIR_H +#define WINDIR_H + +#ifdef _MSC_VER +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +typedef struct DIR { + char name[_MAX_PATH]; + int first; +} DIR; + +typedef struct dirent { + char d_path[_MAX_PATH]; + char d_name[_MAX_FNAME]; + char d_drive[_MAX_DRIVE]; + char d_dir[_MAX_DIR]; + char d_ext[_MAX_EXT]; + intptr_t hnd; +} dirent; + +DIR *opendir(const char *name); +struct dirent *readdir(DIR * thedir); + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/src/util/xml.c b/src/util/xml.c new file mode 100644 index 000000000..e05019d7e --- /dev/null +++ b/src/util/xml.c @@ -0,0 +1,139 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#include +#include "xml.h" + +/* util includes */ +#include "log.h" + +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +const xmlChar * +xml_i(double number) +{ + static char buffer[128]; + snprintf(buffer, sizeof(buffer), "%.0lf", number); + return (const xmlChar *)buffer; +} + +int +xml_ivalue(xmlNodePtr node, const char * name, int dflt) +{ + int i = dflt; + xmlChar * propValue = xmlGetProp(node, BAD_CAST name); + if (propValue!=NULL) { + i = atoi((const char*)propValue); + xmlFree(propValue); + } + return i; +} + +boolean +xml_bvalue(xmlNodePtr node, const char * name, boolean dflt) +{ + boolean result = dflt; + xmlChar * propValue = xmlGetProp(node, BAD_CAST name); + if (propValue!=NULL) { + if (strcmp((const char*)propValue, "no")==0) result = false; + else if (strcmp((const char*)propValue, "yes")==0) result = true; + else if (strcmp((const char*)propValue, "false")==0) result = false; + else if (strcmp((const char*)propValue, "true")==0) result = true; + else if (strcmp((const char*)propValue, "1")==0) { + log_warning(("boolean value is '1': %s::%s\n", node->name, name)); + result = true; + } + else if (strcmp((const char*)propValue, "0")==0) { + log_warning(("boolean value is '0': %s::%s\n", node->name, name)); + result = false; + } + xmlFree(propValue); + } + return result; +} + +double +xml_fvalue(xmlNodePtr node, const char * name, double dflt) +{ + double result = dflt; + xmlChar * propValue = xmlGetProp(node, BAD_CAST name); + if (propValue!=NULL) { + result = atof((const char*)propValue); + xmlFree(propValue); + } + return result; +} + +/* new xml functions */ +/* libxml includes */ +#include +#include +#include + +typedef struct xml_reader { + struct xml_reader * next; + xml_callback callback; +} xml_reader; + +static xml_reader * xmlReaders; + +void +xml_register_callback(xml_callback callback) +{ + xml_reader * reader = (xml_reader *)malloc(sizeof(xml_reader)); + xml_reader ** insert = &xmlReaders; + reader->callback = callback; + reader->next = NULL; + + while (*insert) insert = &(*insert)->next; + *insert = reader; +} + +int +read_xml(const char * filename, const char * catalog) +{ + xml_reader * reader = xmlReaders; + xmlDocPtr doc; + + if (catalog) { + xmlLoadCatalog(catalog); + } +#ifdef XML_PARSE_XINCLUDE + doc = xmlReadFile(filename, NULL, XML_PARSE_XINCLUDE); +#else + doc = xmlParseFile(filename); +#endif + if (doc==NULL) { + log_error(("could not open %s\n", filename)); + return -1; + } + + xmlXIncludeProcess(doc); + + while (reader!=NULL) { + int i = reader->callback(doc); + if (i!=0) { + return i; + } + reader = reader->next; + } + xmlFreeDoc(doc); + return 0; +} + diff --git a/src/util/xml.h b/src/util/xml.h new file mode 100644 index 000000000..540b886e9 --- /dev/null +++ b/src/util/xml.h @@ -0,0 +1,36 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_UTIL_XML +#define H_UTIL_XML + + +#ifdef __cplusplus +extern "C" { +#endif + + /* new xml functions: */ +#include + + typedef int (*xml_callback)(xmlDocPtr); + extern void xml_register_callback(xml_callback callback); + extern int read_xml(const char * filename, const char * catalog); + extern double xml_fvalue(xmlNodePtr node, const char * name, double dflt); + extern int xml_ivalue(xmlNodePtr node, const char * name, int dflt); + extern boolean xml_bvalue(xmlNodePtr node, const char * name, boolean dflt); + + const xmlChar * xml_i(double number); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tools/atoi36.c b/tools/atoi36.c new file mode 100644 index 000000000..a935e7650 --- /dev/null +++ b/tools/atoi36.c @@ -0,0 +1,35 @@ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2001 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include +#include + +int main(int argc, char**argv) +{ + int i=1, reverse = 0; + if (strstr(argv[0], "itoa36")) reverse=1; + if (argc>1) { + if (strcmp(argv[1], "-r")==0) { + i=2; + reverse=1; + } + } + for (;i!=argc;++i) { + if (reverse) { + printf("%s -> %s\n", argv[i], itoa36(atoi(argv[i]))); + } + else printf("%s -> %d\n", argv[i], atoi36(argv[i])); + } + return 0; +} diff --git a/tools/gethash.c b/tools/gethash.c new file mode 100644 index 000000000..65fc1ef76 --- /dev/null +++ b/tools/gethash.c @@ -0,0 +1,23 @@ +#include +#include +#include + +int main(int argc, char ** argv) +{ + char key[4]; + char code[4]; + char result[4]; + int a, i, rot; + for (a=1;a + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2001 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ + +#include +#include +#include + +static char *dwarf_syllable1[] = +{ + "B", "D", "F", "G", "Gl", "H", "K", "L", "M", "N", "R", "S", "T", "Th", "V", +}; + +static char *dwarf_syllable2[] = +{ + "a", "e", "i", "o", "oi", "u", +}; + +static char *dwarf_syllable3[] = +{ + "bur", "fur", "gan", "gnus", "gnar", "li", "lin", "lir", "mli", "nar", "nus", "rin", "ran", "sin", "sil", "sur", +}; + +static char *elf_syllable1[] = +{ + "Al", "An", "Bal", "Bel", "Cal", "Cel", "El", "Elr", "Elv", "Eow", "Ear", "F", "Fal", "Fel", "Fin", "G", "Gal", "Gel", "Gl", "Is", "Lan", "Leg", "Lom", "N", "Nal", "Nel", "S", "Sal", "Sel", "T", "Tal", "Tel", "Thr", "Tin", +}; + +static char *elf_syllable2[] = +{ + "a", "adrie", "ara", "e", "ebri", "ele", "ere", "i", "io", "ithra", "ilma", "il-Ga", "ili", "o", "orfi", "u", "y", +}; + +static char *elf_syllable3[] = +{ + "l", "las", "lad", "ldor", "ldur", "linde", "lith", "mir", "n", "nd", "ndel", "ndil", "ndir", "nduil", "ng", "mbor", "r", "rith", "ril", "riand", "rion", "s", "thien", "viel", "wen", "wyn", +}; + +static char *gnome_syllable1[] = +{ + "Aar", "An", "Ar", "As", "C", "H", "Han", "Har", "Hel", "Iir", "J", "Jan", "Jar", "K", "L", "M", "Mar", "N", "Nik", "Os", "Ol", "P", "R", "S", "Sam", "San", "T", "Ter", "Tom", "Ul", "V", "W", "Y", +}; + +static char *gnome_syllable2[] = +{ + "a", "aa", "ai", "e", "ei", "i", "o", "uo", "u", "uu", +}; + +static char *gnome_syllable3[] = +{ + "ron", "re", "la", "ki", "kseli", "ksi", "ku", "ja", "ta", "na", "namari", "neli", "nika", "nikki", "nu", "nukka", "ka", "ko", "li", "kki", "rik", "po", "to", "pekka", "rjaana", "rjatta", "rjukka", "la", "lla", "lli", "mo", "nni", +}; + +static char *hobbit_syllable1[] = +{ + "B", "Ber", "Br", "D", "Der", "Dr", "F", "Fr", "G", "H", "L", "Ler", "M", "Mer", "N", "P", "Pr", "Per", "R", "S", "T", "W", +}; + +static char *hobbit_syllable2[] = +{ + "a", "e", "i", "ia", "o", "oi", "u", +}; + +static char *hobbit_syllable3[] = +{ + "bo", "ck", "decan", "degar", "do", "doc", "go", "grin", "lba", "lbo", "lda", "ldo", "lla", "ll", "lo", "m", "mwise", "nac", "noc", "nwise", "p", "ppin", "pper", "tho", "to", +}; + +static char *human_syllable1[] = +{ + "Ab", "Ac", "Ad", "Af", "Agr", "Ast", "As", "Al", "Adw", "Adr", "Ar", "B", "Br", "C", "Cr", "Ch", "Cad", "D", "Dr", "Dw", "Ed", "Eth", "Et", "Er", "El", "Eow", "F", "Fr", "G", "Gr", "Gw", "Gal", "Gl", "H", "Ha", "Ib", "Jer", "K", "Ka", "Ked", "L", "Loth", "Lar", "Leg", "M", "Mir", "N", "Nyd", "Ol", "Oc", "On", "P", "Pr", "R", "Rh", "S", "Sev", "T", "Tr", "Th", "V", "Y", "Z", "W", "Wic", +}; + +static char *human_syllable2[] = +{ + "a", "ae", "au", "ao", "are", "ale", "ali", "ay", "ardo", "e", "ei", "ea", "eri", "era", "ela", "eli", "enda", "erra", "i", "ia", "ie", "ire", "ira", "ila", "ili", "ira", "igo", "o", "oa", "oi", "oe", "ore", "u", "y", +}; + +static char *human_syllable3[] = +{ + "a", "and", "b", "bwyn", "baen", "bard", "c", "ctred", "cred", "ch", "can", "d", "dan", "don", "der", "dric", "dfrid", "dus", "f", "g", "gord", "gan", "l", "li", "lgrin", "lin", "lith", "lath", "loth", "ld", "ldric", "ldan", "m", "mas", "mos", "mar", "mond", "n", "nydd", "nidd", "nnon", "nwan", "nyth", "nad", "nn", "nnor", "nd", "p", "r", "ron", "rd", "s", "sh", "seth", "sean", "t", "th", "tha", "tlan", "trem", "tram", "v", "vudd", "w", "wan", "win", "wyn", "wyr", "wyr", "wyth", +}; + +static char *orc_syllable1[] = +{ + "B", "Er", "G", "Gr", "H", "P", "Pr", "R", "V", "Vr", "T", "Tr", "M", "Dr", +}; + +static char *orc_syllable2[] = +{ + "a", "i", "o", "oo", "u", "ui", +}; + +static char *orc_syllable3[] = +{ + "dash", "dish", "dush", "gar", "gor", "gdush", "lo", "gdish", "k", "lg", "nak", "rag", "rbag", "rg", "rk", "ng", "nk", "rt", "ol", "urk", "shnak", "mog", "mak", "rak", +}; + +static char *entish_syllable1[] = +{ + "Baum","Wurzel","Rinden","Ast","Blatt", +}; + +static char *entish_syllable2[] = +{ + "-", +}; + +static char *entish_syllable3[] = +{ + "Hüter","Pflanzer","Hirte","Wächter","Wachser","Beschützer", +}; + +static char *cthuloid_syllable1[] = +{ + "Cth","Az","Fth","Ts","Xo","Q'N","R'L","Ghata","L","Zz","Fl","Cl","S","Y", +}; + +static char *cthuloid_syllable2[] = +{ + "nar","loi","ul","lu","noth","thon","ath","'N","rhy","oth","aza","agn","oa","og", +}; + +static char *cthuloid_syllable3[] = +{ + "l","a","u","oa","oggua","oth","ath","aggua","lu","lo","loth","lotha","agn","axl", +}; + +static char * +create_random_name(race_t race) +{ + static char name[64]; + + switch (race) + { + case RC_DWARF: + strcpy(name, dwarf_syllable1[rng_int()%(sizeof(dwarf_syllable1) / sizeof(char*))]); + strcat(name, dwarf_syllable2[rand()%(sizeof(dwarf_syllable2) / sizeof(char*))]); + strcat(name, dwarf_syllable3[rand()%(sizeof(dwarf_syllable3) / sizeof(char*))]); + break; + case RC_ELF: + strcpy(name, elf_syllable1[rand()%(sizeof(elf_syllable1) / sizeof(char*))]); + strcat(name, elf_syllable2[rand()%(sizeof(elf_syllable2) / sizeof(char*))]); + strcat(name, elf_syllable3[rand()%(sizeof(elf_syllable3) / sizeof(char*))]); + break; +/* + case RACE_GNOME: + strcpy(name, gnome_syllable1[rand()%(sizeof(gnome_syllable1) / sizeof(char*))]); + strcat(name, gnome_syllable2[rand()%(sizeof(gnome_syllable2) / sizeof(char*))]); + strcat(name, gnome_syllable3[rand()%(sizeof(gnome_syllable3) / sizeof(char*))]); + break; +*/ + case RC_HALFLING: + strcpy(name, hobbit_syllable1[rand()%(sizeof(hobbit_syllable1) / sizeof(char*))]); + strcat(name, hobbit_syllable2[rand()%(sizeof(hobbit_syllable2) / sizeof(char*))]); + strcat(name, hobbit_syllable3[rand()%(sizeof(hobbit_syllable3) / sizeof(char*))]); + break; + case RC_HUMAN: + case RC_AQUARIAN: + case RC_CAT: + strcpy(name, human_syllable1[rand()%(sizeof(human_syllable1) / sizeof(char*))]); + strcat(name, human_syllable2[rand()%(sizeof(human_syllable2) / sizeof(char*))]); + strcat(name, human_syllable3[rand()%(sizeof(human_syllable3) / sizeof(char*))]); + break; + case RC_ORC: + case RC_TROLL: + case RC_GOBLIN: + strcpy(name, orc_syllable1[rand()%(sizeof(orc_syllable1) / sizeof(char*))]); + strcat(name, orc_syllable2[rand()%(sizeof(orc_syllable2) / sizeof(char*))]); + strcat(name, orc_syllable3[rand()%(sizeof(orc_syllable3) / sizeof(char*))]); + break; +/* + case RC_TREEMAN: + strcpy(name, entish_syllable1[rand()%(sizeof(entish_syllable1) / sizeof(char*))]); + strcat(name, entish_syllable2[rand()%(sizeof(entish_syllable2) / sizeof(char*))]); + strcat(name, entish_syllable3[rand()%(sizeof(entish_syllable3) / sizeof(char*))]); + break; +*/ + case RC_DAEMON: + case RC_INSECT: + strcpy(name, cthuloid_syllable1[rand()%(sizeof(cthuloid_syllable1) / sizeof(char*))]); + strcat(name, cthuloid_syllable2[rand()%(sizeof(cthuloid_syllable2) / sizeof(char*))]); + strcat(name, cthuloid_syllable3[rand()%(sizeof(cthuloid_syllable3) / sizeof(char*))]); + break; + default: + name[0] = 0; + break; + } + + return name; +} + +int +main(void) +{ + race_t race; + + for(race=0; race<11; race++) { + int i; + printf("%d:", (int)race); + for(i=0;i<20;i++) { + printf(" %s", create_random_name(race)); + } + printf("\n"); + } + + return 0; +} + From 14b3ed309fd4b3ca04268290cdafe0bb8fdfe4df Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 7 Aug 2010 23:05:54 -0700 Subject: [PATCH 002/400] use external folder for all libraries (VS2010) new repository structure --- res/armor/chainmail.xml | 18 +- res/armor/laenmail.xml | 18 +- res/armor/laenshield.xml | 18 +- res/armor/plate.xml | 20 +- res/armor/rustychainmail.xml | 20 +- res/armor/rustyshield.xml | 18 +- res/armor/shield.xml | 18 +- res/calendar.xml | 46 +- res/common/armor.xml | 20 +- res/common/buildings.xml | 342 +- res/common/construction.xml | 20 +- res/common/herbs.xml | 178 +- res/common/items.xml | 312 +- res/common/luxuries.xml | 52 +- res/common/potions.xml | 394 +- res/common/resources.xml | 30 +- res/common/weapons.xml | 48 +- res/de/strings.xml | 14964 ++++++++++++------------ res/en/strings.xml | 3360 +++--- res/equipment.xml | 798 +- res/fr/strings.xml | 4164 +++---- res/messages.xml | 17036 ++++++++++++++-------------- res/prefixes.xml | 62 +- res/resources/horse.xml | 22 +- res/resources/hp.xml | 10 +- res/resources/iron.xml | 24 +- res/resources/laen.xml | 20 +- res/resources/log.xml | 26 +- res/resources/mallorn.xml | 26 +- res/resources/mallornseed.xml | 12 +- res/resources/peasant.xml | 10 +- res/resources/seed.xml | 12 +- res/resources/stone.xml | 22 +- res/ships.xml | 166 +- res/spells.xml | 408 +- res/spoils.xml | 118 +- res/terrains.xml | 168 +- res/weapons/axe.xml | 28 +- res/weapons/bow.xml | 26 +- res/weapons/catapult.xml | 28 +- res/weapons/crossbow.xml | 26 +- res/weapons/firesword.xml | 20 +- res/weapons/greatbow.xml | 36 +- res/weapons/greatsword.xml | 26 +- res/weapons/halberd.xml | 30 +- res/weapons/laensword.xml | 24 +- res/weapons/lance.xml | 26 +- res/weapons/mallornbow.xml | 32 +- res/weapons/mallorncrossbow.xml | 26 +- res/weapons/mallornlance.xml | 26 +- res/weapons/mallornspear.xml | 28 +- res/weapons/rep_crossbow.xml | 32 +- res/weapons/runesword.xml | 20 +- res/weapons/rustyaxe.xml | 28 +- res/weapons/rustygreatsword.xml | 24 +- res/weapons/rustyhalberd.xml | 30 +- res/weapons/rustysword.xml | 24 +- res/weapons/spear.xml | 28 +- res/weapons/sword.xml | 24 +- scripts/callbacks.lua | 22 +- scripts/default.lua | 242 +- scripts/dumptable.lua | 190 +- scripts/gates.lua | 50 +- scripts/init.lua | 86 +- scripts/multis.lua | 202 +- scripts/resources.lua | 178 +- scripts/schema.sql | 12 +- scripts/setup.lua | 32 +- scripts/spells.lua | 302 +- scripts/tests/common.lua | 1286 +-- scripts/tests/spells.lua | 128 +- src/attributes/aggressive.h | 66 +- src/attributes/alliance.c | 68 +- src/attributes/alliance.h | 62 +- src/attributes/attributes.c | 162 +- src/attributes/attributes.h | 62 +- src/attributes/fleechance.c | 90 +- src/attributes/fleechance.h | 66 +- src/attributes/follow.c | 92 +- src/attributes/follow.h | 70 +- src/attributes/giveitem.c | 270 +- src/attributes/giveitem.h | 72 +- src/attributes/gm.c | 122 +- src/attributes/gm.h | 72 +- src/attributes/hate.c | 140 +- src/attributes/hate.h | 70 +- src/attributes/iceberg.c | 84 +- src/attributes/iceberg.h | 66 +- src/attributes/key.c | 118 +- src/attributes/key.h | 70 +- src/attributes/matmod.c | 80 +- src/attributes/matmod.h | 74 +- src/attributes/moved.c | 126 +- src/attributes/moved.h | 74 +- src/attributes/movement.c | 118 +- src/attributes/movement.h | 66 +- src/attributes/object.c | 534 +- src/attributes/object.h | 76 +- src/attributes/orcification.c | 80 +- src/attributes/orcification.h | 56 +- src/attributes/otherfaction.c | 160 +- src/attributes/otherfaction.h | 66 +- src/attributes/overrideroads.c | 58 +- src/attributes/overrideroads.h | 62 +- src/attributes/racename.c | 114 +- src/attributes/racename.h | 74 +- src/attributes/raceprefix.c | 120 +- src/attributes/raceprefix.h | 66 +- src/attributes/reduceproduction.c | 102 +- src/attributes/reduceproduction.h | 64 +- src/attributes/targetregion.c | 122 +- src/attributes/targetregion.h | 68 +- src/attributes/viewrange.c | 154 +- src/attributes/viewrange.h | 70 +- src/bindings/bind_attrib.c | 744 +- src/bindings/bind_attrib.h | 48 +- src/bindings/bind_building.c | 513 +- src/bindings/bind_building.h | 46 +- src/bindings/bind_faction.c | 1122 +- src/bindings/bind_faction.h | 48 +- src/bindings/bind_gmtool.c | 532 +- src/bindings/bind_gmtool.h | 20 +- src/bindings/bind_hashtable.c | 374 +- src/bindings/bind_hashtable.h | 48 +- src/bindings/bind_message.c | 696 +- src/bindings/bind_message.h | 44 +- src/bindings/bind_region.c | 1392 +-- src/bindings/bind_region.h | 46 +- src/bindings/bind_ship.c | 364 +- src/bindings/bind_ship.h | 46 +- src/bindings/bind_sqlite.c | 200 +- src/bindings/bind_storage.c | 288 +- src/bindings/bind_storage.h | 44 +- src/bindings/bind_unit.c | 2052 ++-- src/bindings/bind_unit.h | 52 +- src/bindings/bindings.c | 2322 ++-- src/bindings/bindings.h | 54 +- src/bindings/helpers.c | 1328 +-- src/bindings/helpers.h | 46 +- src/build/atoi36.c | 12 +- src/build/external.c | 36 +- src/build/gamecode.c | 160 +- src/build/kernel.c | 111 +- src/build/lib.c | 17 +- src/build/stdafx.c | 2 +- src/build/stdafx.h | 4 +- src/build/util.c | 80 +- src/eressea.c | 423 +- src/eressea.h | 30 +- src/gamecode.vcproj | 708 +- src/gamecode.vcxproj | 277 +- src/gamecode.vcxproj.filters | 254 +- src/gamecode/archetype.c | 336 +- src/gamecode/archetype.h | 102 +- src/gamecode/creation.c | 146 +- src/gamecode/creation.h | 60 +- src/gamecode/creport.c | 3215 +++--- src/gamecode/creport.h | 58 +- src/gamecode/economy.c | 6926 +++++------ src/gamecode/economy.h | 120 +- src/gamecode/give.c | 876 +- src/gamecode/give.h | 52 +- src/gamecode/items.c | 526 +- src/gamecode/items.h | 48 +- src/gamecode/laws.c | 8446 +++++++------- src/gamecode/laws.h | 94 +- src/gamecode/laws_test.c | 296 +- src/gamecode/market.c | 368 +- src/gamecode/market.h | 50 +- src/gamecode/market_test.c | 132 +- src/gamecode/monster.c | 454 +- src/gamecode/monster.h | 62 +- src/gamecode/randenc.c | 2544 ++--- src/gamecode/randenc.h | 62 +- src/gamecode/report.c | 4869 ++++---- src/gamecode/report.h | 50 +- src/gamecode/spy.c | 964 +- src/gamecode/spy.h | 80 +- src/gamecode/study.c | 1586 +-- src/gamecode/study.h | 90 +- src/gamecode/summary.c | 826 +- src/gamecode/summary.h | 50 +- src/gmtool.c | 2594 +++-- src/gmtool.h | 82 +- src/gmtool.vcproj | 628 +- src/gmtool_structs.h | 204 +- src/items/artrewards.c | 314 +- src/items/artrewards.h | 60 +- src/items/demonseye.c | 128 +- src/items/demonseye.h | 60 +- src/items/itemtypes.c | 76 +- src/items/itemtypes.h | 50 +- src/items/phoenixcompass.c | 258 +- src/items/phoenixcompass.h | 60 +- src/items/seed.c | 200 +- src/items/seed.h | 70 +- src/items/speedsail.c | 146 +- src/items/speedsail.h | 60 +- src/items/studypotion.c | 116 +- src/items/studypotion.h | 60 +- src/items/weapons.c | 310 +- src/items/weapons.h | 48 +- src/items/xerewards.c | 182 +- src/items/xerewards.h | 60 +- src/kernel.vcproj | 1896 ++-- src/kernel.vcxproj | 578 +- src/kernel.vcxproj.filters | 1194 +- src/kernel/alchemy.c | 676 +- src/kernel/alchemy.h | 140 +- src/kernel/alliance.c | 1096 +- src/kernel/alliance.h | 136 +- src/kernel/battle.c | 8742 +++++++------- src/kernel/battle.h | 542 +- src/kernel/binarystore.c | 585 +- src/kernel/binarystore.h | 46 +- src/kernel/build.c | 2699 +++-- src/kernel/build.h | 198 +- src/kernel/building.c | 1390 +-- src/kernel/building.h | 354 +- src/kernel/calendar.c | 118 +- src/kernel/calendar.h | 90 +- src/kernel/command.c | 206 +- src/kernel/command.h | 78 +- src/kernel/config.c | 6546 ++++++----- src/kernel/config.h | 920 +- src/kernel/connection.c | 1226 +- src/kernel/connection.h | 282 +- src/kernel/curse.c | 1642 +-- src/kernel/curse.h | 660 +- src/kernel/curse_test.c | 46 +- src/kernel/equipment.c | 440 +- src/kernel/equipment.h | 146 +- src/kernel/faction.c | 1014 +- src/kernel/faction.h | 322 +- src/kernel/group.c | 486 +- src/kernel/group.h | 102 +- src/kernel/item.c | 2371 ++-- src/kernel/item.h | 714 +- src/kernel/magic.c | 5846 +++++----- src/kernel/magic.h | 790 +- src/kernel/message.c | 566 +- src/kernel/message.h | 122 +- src/kernel/move.c | 5296 ++++----- src/kernel/move.h | 142 +- src/kernel/names.c | 966 +- src/kernel/names.h | 74 +- src/kernel/objtypes.h | 80 +- src/kernel/order.c | 1034 +- src/kernel/order.h | 122 +- src/kernel/pathfinder.c | 400 +- src/kernel/pathfinder.h | 84 +- src/kernel/plane.c | 652 +- src/kernel/plane.h | 168 +- src/kernel/player.c | 202 +- src/kernel/player.h | 86 +- src/kernel/pool.c | 524 +- src/kernel/pool.h | 124 +- src/kernel/race.c | 592 +- src/kernel/race.h | 384 +- src/kernel/region.c | 3216 +++--- src/kernel/region.h | 600 +- src/kernel/render.h | 56 +- src/kernel/reports.c | 4372 +++---- src/kernel/reports.h | 280 +- src/kernel/resources.c | 416 +- src/kernel/resources.h | 126 +- src/kernel/save.c | 3779 +++--- src/kernel/save.h | 146 +- src/kernel/ship.c | 675 +- src/kernel/ship.h | 254 +- src/kernel/skill.c | 630 +- src/kernel/skill.h | 132 +- src/kernel/spell.c | 368 +- src/kernel/spell.h | 318 +- src/kernel/spellid.h | 352 +- src/kernel/sqlite.c | 514 +- src/kernel/teleport.c | 456 +- src/kernel/teleport.h | 82 +- src/kernel/terrain.c | 316 +- src/kernel/terrain.h | 166 +- src/kernel/terrainid.h | 96 +- src/kernel/textstore.c | 413 +- src/kernel/textstore.h | 46 +- src/kernel/types.h | 814 +- src/kernel/unit.c | 3486 +++--- src/kernel/unit.h | 474 +- src/kernel/version.h | 142 +- src/kernel/xmlkernel.h | 58 +- src/kernel/xmlreader.c | 4360 +++---- src/kernel/xmlreader.h | 55 +- src/lua-bindings.vcproj | 548 +- src/lua-bindings.vcxproj | 247 +- src/lua-bindings.vcxproj.filters | 188 +- src/modules/arena.c | 1054 +- src/modules/arena.h | 78 +- src/modules/autoseed.c | 2046 ++-- src/modules/autoseed.h | 100 +- src/modules/dungeon.c | 536 +- src/modules/dungeon.h | 72 +- src/modules/gmcmd.c | 1544 +-- src/modules/gmcmd.h | 96 +- src/modules/museum.c | 792 +- src/modules/museum.h | 106 +- src/modules/oceannames.c | 252 +- src/modules/oceannames.h | 64 +- src/modules/score.c | 424 +- src/modules/score.h | 72 +- src/modules/weather.c | 282 +- src/modules/weather.h | 108 +- src/modules/wormhole.c | 443 +- src/modules/wormhole.h | 62 +- src/modules/xecmd.c | 222 +- src/modules/xecmd.h | 54 +- src/modules/xmas.c | 164 +- src/modules/xmas.h | 58 +- src/platform.h | 568 +- src/settings.h | 118 +- src/stdafx.h | 2 +- src/tests.c | 254 +- src/tests.h | 42 +- src/triggers/changefaction.c | 228 +- src/triggers/changefaction.h | 78 +- src/triggers/changerace.c | 240 +- src/triggers/changerace.h | 74 +- src/triggers/clonedied.c | 190 +- src/triggers/clonedied.h | 72 +- src/triggers/createcurse.c | 314 +- src/triggers/createcurse.h | 80 +- src/triggers/createunit.c | 260 +- src/triggers/createunit.h | 78 +- src/triggers/gate.c | 234 +- src/triggers/gate.h | 64 +- src/triggers/giveitem.c | 248 +- src/triggers/giveitem.h | 76 +- src/triggers/killunit.c | 174 +- src/triggers/killunit.h | 72 +- src/triggers/removecurse.c | 228 +- src/triggers/removecurse.h | 78 +- src/triggers/shock.c | 296 +- src/triggers/shock.h | 72 +- src/triggers/timeout.c | 226 +- src/triggers/timeout.h | 70 +- src/triggers/triggers.c | 120 +- src/triggers/triggers.h | 60 +- src/triggers/unguard.c | 154 +- src/triggers/unguard.h | 64 +- src/triggers/unitmessage.c | 246 +- src/triggers/unitmessage.h | 72 +- src/util.vcproj | 836 +- src/util.vcxproj | 317 +- src/util.vcxproj.filters | 404 +- src/util/argstack.c | 132 +- src/util/argstack.h | 54 +- src/util/attrib.c | 644 +- src/util/attrib.h | 186 +- src/util/base36.c | 230 +- src/util/base36.h | 68 +- src/util/base36_test.c | 54 +- src/util/bsdstring.c | 176 +- src/util/bsdstring.h | 46 +- src/util/console.c | 494 +- src/util/console.h | 74 +- src/util/crmessage.c | 318 +- src/util/crmessage.h | 78 +- src/util/cvector.c | 194 +- src/util/cvector.h | 122 +- src/util/dice.c | 194 +- src/util/encoding.h | 19 + src/util/event.c | 540 +- src/util/event.h | 160 +- src/util/eventbus.c | 112 +- src/util/eventbus.h | 58 +- src/util/filereader.c | 628 +- src/util/filereader.h | 42 +- src/util/functions.c | 148 +- src/util/functions.h | 70 +- src/util/goodies.c | 282 +- src/util/goodies.h | 126 +- src/util/graph.c | 406 +- src/util/graph.h | 76 +- src/util/language.c | 504 +- src/util/language.h | 138 +- src/util/language_struct.h | 56 +- src/util/listbox.c | 382 +- src/util/listbox.h | 32 +- src/util/lists.c | 286 +- src/util/lists.h | 110 +- src/util/log.c | 576 +- src/util/log.h | 90 +- src/util/message.c | 474 +- src/util/message.h | 142 +- src/util/nrmessage.c | 348 +- src/util/nrmessage.h | 112 +- src/util/nrmessage_struct.h | 40 +- src/util/parser.c | 390 +- src/util/parser.h | 58 +- src/util/patricia.c | 472 +- src/util/patricia.h | 42 +- src/util/rand.c | 144 +- src/util/rand.h | 74 +- src/util/resolve.c | 192 +- src/util/resolve.h | 82 +- src/util/rng.h | 90 +- src/util/sql.c | 164 +- src/util/sql.h | 70 +- src/util/storage.h | 96 +- src/util/strings.c | 264 +- src/util/strncpy.c | 44 +- src/util/translation.c | 976 +- src/util/translation.h | 90 +- src/util/umlaut.c | 320 +- src/util/umlaut.h | 102 +- src/util/unicode.c | 872 +- src/util/unicode.h | 84 +- src/util/variant.h | 48 +- src/util/vmap.c | 292 +- src/util/vmap.h | 94 +- src/util/vset.c | 208 +- src/util/vset.h | 86 +- src/util/windir.c | 112 +- src/util/windir.h | 100 +- src/util/xml.c | 284 +- src/util/xml.h | 72 +- tools/atoi36.c | 70 +- tools/gethash.c | 46 +- tools/namegen.c | 436 +- 426 files changed, 109786 insertions(+), 109728 deletions(-) create mode 100644 src/util/encoding.h diff --git a/res/armor/chainmail.xml b/res/armor/chainmail.xml index 81152f89e..a20c4f8ac 100644 --- a/res/armor/chainmail.xml +++ b/res/armor/chainmail.xml @@ -1,9 +1,9 @@ - - - - - - - - - + + + + + + + + + diff --git a/res/armor/laenmail.xml b/res/armor/laenmail.xml index bdcf6b7e1..ec70f3d29 100644 --- a/res/armor/laenmail.xml +++ b/res/armor/laenmail.xml @@ -1,9 +1,9 @@ - - - - - - - - - + + + + + + + + + diff --git a/res/armor/laenshield.xml b/res/armor/laenshield.xml index f5eb2d783..c24fe8884 100644 --- a/res/armor/laenshield.xml +++ b/res/armor/laenshield.xml @@ -1,9 +1,9 @@ - - - - - - - - - + + + + + + + + + diff --git a/res/armor/plate.xml b/res/armor/plate.xml index eb10f6359..414b96ff3 100644 --- a/res/armor/plate.xml +++ b/res/armor/plate.xml @@ -1,10 +1,10 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/res/armor/rustychainmail.xml b/res/armor/rustychainmail.xml index a52b4db7b..6cf2a7f47 100644 --- a/res/armor/rustychainmail.xml +++ b/res/armor/rustychainmail.xml @@ -1,10 +1,10 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/res/armor/rustyshield.xml b/res/armor/rustyshield.xml index 4c34f7ee1..d1f4fcbb6 100644 --- a/res/armor/rustyshield.xml +++ b/res/armor/rustyshield.xml @@ -1,9 +1,9 @@ - - - - - - - - - + + + + + + + + + diff --git a/res/armor/shield.xml b/res/armor/shield.xml index 9a72baf9a..ceff1f5b7 100644 --- a/res/armor/shield.xml +++ b/res/armor/shield.xml @@ -1,9 +1,9 @@ - - - - - - - - - + + + + + + + + + diff --git a/res/calendar.xml b/res/calendar.xml index 42f83d58b..9c99fd2dc 100644 --- a/res/calendar.xml +++ b/res/calendar.xml @@ -1,23 +1,23 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/common/armor.xml b/res/common/armor.xml index 58abae47f..69e9d2abe 100644 --- a/res/common/armor.xml +++ b/res/common/armor.xml @@ -1,10 +1,10 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/res/common/buildings.xml b/res/common/buildings.xml index 5c52bfbb3..a6c647417 100644 --- a/res/common/buildings.xml +++ b/res/common/buildings.xml @@ -1,171 +1,171 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/common/construction.xml b/res/common/construction.xml index 95dcb6a33..dbb718dad 100644 --- a/res/common/construction.xml +++ b/res/common/construction.xml @@ -1,10 +1,10 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/res/common/herbs.xml b/res/common/herbs.xml index d7d0ef2e6..7f15009a7 100644 --- a/res/common/herbs.xml +++ b/res/common/herbs.xml @@ -1,89 +1,89 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/common/items.xml b/res/common/items.xml index 7c57a8184..c3a7c7b7d 100644 --- a/res/common/items.xml +++ b/res/common/items.xml @@ -1,156 +1,156 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/common/luxuries.xml b/res/common/luxuries.xml index bdf9c110b..22479231c 100644 --- a/res/common/luxuries.xml +++ b/res/common/luxuries.xml @@ -1,26 +1,26 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/common/potions.xml b/res/common/potions.xml index f444e5a94..72246a6d0 100644 --- a/res/common/potions.xml +++ b/res/common/potions.xml @@ -1,197 +1,197 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/common/resources.xml b/res/common/resources.xml index bc39933e6..55563010e 100644 --- a/res/common/resources.xml +++ b/res/common/resources.xml @@ -1,15 +1,15 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/res/common/weapons.xml b/res/common/weapons.xml index e91b15e69..2988a830c 100644 --- a/res/common/weapons.xml +++ b/res/common/weapons.xml @@ -1,24 +1,24 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/de/strings.xml b/res/de/strings.xml index d3900f625..615cee645 100644 --- a/res/de/strings.xml +++ b/res/de/strings.xml @@ -1,7482 +1,7482 @@ - - - - - Wirbel - vortex - remous - - - Ein Wirbel aus reinem Chaos zieht über die Region - A vortex of pure chaos energy pulls over the region - - - Wabernde grüne Schwaden treiben durch den Nebel und - verdichten sich zu einer unheimlichen Kreatur, die nur aus einem langen - Ruderschwanz und einem riesigen runden Maul zu bestehen scheint. - Wobbling green vapours drift through the mists to form an eldritch creature that seems to be entirely made up of huge jaws and a long tail. - - - - Keine Informationen über diese Rasse verfügbar. - No information available for this race. - - - Singdrachen sind von der Größe eines ausgewachsenden Tigers. Ihre Färbung reicht von schillerndem Rot, über dunkles Grün bis hin zu tiefem Schwarz. Alle bekannten Drachen dieser Art weisen eine hohe Intelligenz und ein hohes Maß an magischen Fähigkeiten auf. Wie Ihre großen Verwandten verfügen sie über einen Feuerodem. Sie lieben den Gesang und das üppige Mahl. Von Zeit zu Zeit gehen sie eine engen magisches Bund zu einem Magier ein. Wenn dies geschieht, so steht dem Magier ein äußerst loyaler und lohnender Vertrauter zur Seite. - - Song Dragons are roughly the size of a fully grown tiger. Their coloring ranges from bright red, through a dark green shade to a deep black. All known dragons of this species display a high level of intelligence and highly developed magical skills. Like their larger cousins, Song Dragons posess a firegland. They love singing and a good meal. From time to time one of these magnificent creatures will bond with a mage. When this happens, the mage is assured of a most loyal and useful familiar at his side. - - - Dieses mystische Wesen lebt bevorzugt in den tiefsten Wäldern und - vermag sich hervorragend vor den Augen anderer zu verbergen. Nur - selten schließt sich ein Einhorn einem Magier an, jedoch wenn das - geschieht ist es ein mächtiger Verbündeter, der auch über eigene Magie - verfügt. - - - Der Adler ist ein ausgezeichneter Späher, fliegend überquert er sogar - kurze Meerengen, doch ist er hoch oben am Himmel auch sehr exponiert, - was ihn beim Rasten zu einem leichten Ziel macht. - - - Der Luchs ist bekannt für seine Geschicklichkeit im Verbergen und - Beobachten. Mit ein wenig Geduld kann er zu einem hervorragenden - Späher ausgebildet werden. Im Kampf verteidigt er sich mit seinen - scharfen Krallen und weiß seine Gewandheit zu nutzen. - - - Diese großen Wölfe sind nicht alle so wild und böse wie in den - Legenden berichtet, und einige von ihnen schließen sich auch guten - Magiern bereitwillig an und sind ihnen dann treue Gefährten. - - - 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. - - - - - Das Horn eines Trolles. Kein Troll würde sich lebend davon trennen. - The horn of an adult troll. No troll would ever part with this while he's alive. - - - Beim Barte des Proheten! Ach nein, Zwergen. Irgendetwas riecht hier ranzig. - Sniff... Bleah. Don't they ever wash these? - - - Diese Amulett ist ein hervorragender Fokus für alle Heilzauber. Ein - mit diesem Fokus gewirkter Heilzauber wird mit größerer - Warscheinlichkeit Erfolgreich sein und doppelt so viele Leute heilen - können. - - - Der Kopf eines toten Drachens oder Wyrms. Man sagt, es ruhen magische Kräfte darin. - The head of a dead dragon or wyrm. They say that it has magical powers. - - - Munition für Katapulte. - Ammunition for catapults. - - - Ein Elfenpferd wird sich nur den wenigsten jemals anschließen. Hat es - jedoch seine Scheu überwunden ist es ein sehr wertvoller Gefährte. Ein - Elfenpferd ist schneller als ein Pferd. Zudem hilft es seinem Reiter - im Kampf und unterstützt ihn mit seiner Magie. Es sind schwarze - Elfenpferde bekannt, die sich sogar Orks angeschlossen haben. - - - Die rötlich glühende Klinge dieser furchterregenden magischen Waffe - ist mit dunklen Runen bedeckt. Nur die erfahrendsten Schwertkämpfer - vermögen ihre Kraft zu zähmen, doch in ihrer Hand vermag dem - Runenschwert nichts zu widerstehen - selbst magische Rüstungen - durchdringt es ohne Schwierigkeiten - und den Geist des Kämpfers füllt - es mit unterschütterlicher Zuversicht. - - - This enchanted dragon-eye has to be eaten by the leader of your forces - on the eve before battle. During the night he gains insight into the - dreams of the enemy leaders and may potentially glean a decisive - advantage. - Dieses verzauberte Drachenauge muß vor dem Abend einer Schlacht vom - Heerführer verzehrt werden. Während der Nacht wird er dann Einblick in - die Träume der feindlichen Heerführer erhalten und so möglicherweise - einen entscheidenden Vorteil im kommenden Gefecht erlangen. - - - This artifact grants its wearer the strength of a cavetroll. He will - be able to carry fifty times as much as normal and also in combat his - enhanced strength and tough troll skin will serve him well. - Dieses magische Artefakt verleiht seinem Träger die Stärke eines - ausgewachsenen Höhlentrolls. Seine Tragkraft erhöht sich auf das - 50fache und auch im Kampf werden sich die erhöhte Kraft und die - trollisch zähe Haut positiv auswirken. - - - It may look like just another quartz, but your magician will tell you - tha great power emenates from these crystals. Using it at the begining - of a week will release a strong negative energy that reduce the - power of all spells cast in the region during that week. - Für den ungeübten Betrachter mag der Antimagiekristall wie ein - gewöhnlicher Quarzkristall ausschauen, doch ein Magier spürt, das ihm - ganz besondere Kräfte innewohnen. Durch spezielle Rituale antimagisch - aufgeladen wird der Kristall, wenn er zu feinem Staub zermahlen und - verteilt wird, die beim Zaubern freigesetzten magischen Energien - aufsaugen und die Kraft aller Zauber reduzieren, welche in der betreffenden - Woche in der Region gezaubert werden. - - - A ring of power increases a magician's power. The level of all the - spells - he casts will be increased by one without increasing their costs. - Ein Ring der Macht verstärkt die Kraft des Magiers. Jeder Zauber wird, - ohne das sich die Kosten erhöhen, so gezaubert als hätte der Magier - eine Stufe mehr. - - - Herbs stored in this bag will be much better preserved. - Kräuter, die in diesem Beutelchen aufbewahrt werden, sind erheblich - besser konserviert. - - - This bag encloses a dimensional fold, which can store up to 200 - stones of weight without any extra burden on the bearer. Large items - such as horses or carts cannot be placed inside. - Dieser Beutel umschließt eine kleine Dimensionsfalte, in der bis - zu 200 Gewichtseinheiten transportiert werden können, ohne dass - sie auf das Traggewicht angerechnet werden. Pferde und andere - Lebewesen sowie besonders sperrige Dinge (Wagen und Katapulte) können - nicht in dem Beutel transportiert werden. Auch ist es nicht möglich, - einen Zauberbeutel in einem anderen zu transportieren. Der Beutel - selber wiegt 1 GE. - - - These leather boots are embroidere with unicorn hair and allow - their wearer to walk at twice his normal speed. - Diese aus Leder gefertigten und mit Einhornfell verzierten Stiefel - ermöglichen es ihrem Träger, sich mit der doppelten Geschwindigkeit - fortzubewegen, wenn er zu Fuß reist. - - - The flaming sword gives its bearer an attack of 3d6+10 plus - an additional fireball causing 2d6 damage to 1-10 victims. - Using a flaming sword requires a minimum skill of 7. It grants an - additional +1 to your skill and your resistance to magic will be - increased. - Ein Flammenschwert gibt dem Träger, der kein Magier sein muß, - zusätzlich zu seinem normalen Angriff (3d6+10) einen kleinen - Feuerballangriff, der bei 1-10 Opfern 2d6 magischen Schaden - verursacht. Um ein Flammenschwert führen zu können, muss man - mindestens Hiebwaffen 7 haben, dann verleiht es einem auch - einen zusätzlichen Kampfbonus von +1. Ein Flammenschwert - erhöht die Magieresistenz seines Trägers wie ein Laenschwert. - - - The magic in this ring makes the fingers ten times more nimble. a - craftsman can produce ten times his normal quota, and other abilities - might also be improved. - Der Zauber in diesem Ring bewirkt eine um das zehnfache verbesserte - Geschicklichkeit und Gewandheit der Finger. Handwerker können somit - das zehnfache produzieren, und bei einigen anderen Tätigkeiten könnte - dies ebenfalls von Nutzen sein. - - - This magical artifact has been used since ancient times by Elves to - conceal themselves from their enemies. Other races have also learned - the value of these rings after encountering Elves - after all the ring - makes its wearer invisible to normal eyes, and only magical methods - enable the wearer to be discovered. - Dieses magische Artefakt wurde seit Urzeiten von den Elfen benutzt, - auf der Jagd oder um sich vor Feinden zu verbergen. Doch auch andere - Rassen haben nach der Begegnung mit den Elfenvölkern den Wert des Rings - schnell schätzen gelernt - schließlich macht er den Träger für jedes - noch so scharfe Auge unsichtbar - nur mit magischen Mitteln ist der - Verborgene noch zu entdecken. - - - Das Amulett erlaubt es dem Träger, alle Einheiten, die durch einen - Ring der Unsichtbarkeit geschützt sind, zu sehen. Einheiten allerdings, - die sich mit ihrem Tarnungs-Talent verstecken, bleiben weiterhin - unentdeckt. Die Herstellung des Amulettes kostet 3000 Silber. - - - Dieser Tiegel enthält die seltenste alchemistische Substanz - Eresseas, den Krötenschleim. Angeblich soll der Krötenschleim eine - aussergewöhnlich hohe magische Absorbtionskraft besitzen und deswegen - in obskuren magischen Ritualen Verwendung finden. - - - Die Kröte ist eine der seltensten Rassen Eresseas. Man munkelt, - sie würde nur auf magische Weise entstehen. In einer uralten - Abhandlung über Magie aus der Bibliothek der Akademie von Xontormia - wird die Theorie aufgestellt, das die Kröte die ins morphische Feld - des Magiers übertragene Manifestation eines implodierten - Zauberfeldes sein könnte. Vieleicht deswegen ist die Kröte auch - gegen Zauber weitaus widerstandsfähiger als die normalen Rassen - Eresseas, leider aber auch weitaus unmagischer als diese. Die - Kröte kann schon aufgrund ihrer Größe und der fehlenden Hände - nur unter Schwierigkeiten normale Tätigkeiten ausüben. Der - einzige Vorteil ihrer geringen Größe ist, dass sie sich leichter - verstecken kann. - - - Dieses magische Szepter, ein Geschenk Igjarjuks, sorgt für große - Verwirrung und Gedächtnisverlust. Syntax: BENUTZE "Szepter der - Tränen" - - - Setzt eine Einheit dieses Segel auf einem Schiff, so erhöht - sich dessen Reichweite permanent um 1 Region. - A unit setting this sail on a ship temporarily will permanently - increase the ship's range by 1. - - - Im Mistelzweig ruht eine magische - Kraft der besonderer Art. Der Anwender wird von seinen - Feinden in Frieden gelassen, eine Woche lang läßt jeder - Kämpfer ihn unbeschadet seines Weges ziehen. - The magical misteltoe has a wonderous - property: It's use will make one person able to escape - unharmed from every conflict, no enemy will lay hand on - the bearer for one week. - - - - - - Kein Magiegebiet - no magic school - - - Illaun - Illaun - - - Tybied - Tybied - - - Cerddor - Cerddor - - - Gwyrrd - Gwyrrd - - - Draig - Draig - - - - - Tresen - counter - - - - wenige - few - - - - viele - many - - - - relativ viele - rather many - - - - sehr wenige - very few - - - - sehr viele - a great many - beaucoup de - - - - (trauernd) - (in mourning) - - - Beschreibung: - Description: - - - Art: - Type: - - - Komponenten: - Components: - - - Modifikationen: - Modifications: - - - Stufe: - Level: - - - Rang: - Rank: - - - Syntax: - Syntax: - - - - Geboten wird für - Traders can sell - - - und für - and - - - . - . - - - , für - , - - - - , im - , to the - - - und im - and to the - - - Einheit - Unit - - - Partei - Faction - - - hier_passwort_eintragen - insert_your_password_here - - - - Baum - tree - - - - Bäume - trees - - - - Mallornbaum - mallorn tree - - - - Mallornbäume - mallorn trees - - - - - - Nordwestküste - - - Nordostküste - - - Ostküste - - - Südostküste - - - Südwestküste - - - Westküste - - - - - AUSWERTUNG - - - COMPUTER - - - ZUGVORLAGE - - - SILBERPOOL - - - STATISTIK - - - DEBUG - - - ZIPPED - - - ZEITUNG - - - MATERIALPOOL - - - ADRESSEN - - - BZIP2 - - - PUNKTE - - - TALENTVERSCHIEBUNGEN - - - - - ein fliegender Teppich - - - ein Ballon - - - eine Karavelle - - - ein Boot - - - ein Langboot - - - ein Drachenschiff - - - eine Trireme - - - - fliegender Teppich - flying carpet - - - Ballon - - - Karavelle - - - Boot - - - Langboot - - - Drachenschiff - - - Trireme - - - - - Mahlstrom - - - Ozean - - - Ebene - - - Wald - - - Sumpf - - - Wüste - - - Hochland - - - Berge - - - Gletscher - - - Gletscher - - - Feuerwand - - - Vulkan - - - Nebel - - - Eisberg - - - Dichter Nebel - - - Ebene aus Feuer und Dunkelheit - - - Aktiver Vulkan - - - Halle - - - Gang - - - Wand - - - Magischer Sturm - - - - ein %s - - - %s - - - die Ebene von %s - - - der Wald von %s - - - der Sumpf von %s - - - die Wüste von %s - - - das Hochland von %s - - - das Bergland von %s - - - der Gletscher von %s - - - eine %s - - - der Vulkan von %s - - - ein %s - - - der Eisberg von %s - the glacier of %s - - - der Gletscher von %s - the glacier of %s - - - %s - - - eine %s - - - der Vulkan von %s - - - die %s - - - die %s - - - eine mächtige Mauer - - - ein %s - - - - Krater - - - Pforte - - - Kohlenstück - - - Kohlenstücke - - - - - Westen - - - Nordwesten - - - Nordosten - - - Osten - - - Südwesten - - - Südosten - - - - NW - - - NO - - - Ost - - - SO - - - SW - - - West - - - - - ein unbekanntes Gebäude - an unknown building - - - ein unbekannter zauber - an unknown spell - - - ein unbekanntes Schiff - an unknown ship - - - eine unbekannte Einheit - an unknown unit - - - einer unbekannten Einheit - an unknown unit - - - - - Ereignisse - - - Botschaften - - - Warnungen und Fehler - - - Wirtschaft und Handel - - - Rohstoffe und Produktion - - - Magie und Artefakte - - - Reisen und Bewegung - - - Lehren und Lernen - - - Kämpfe - - - Verschiedenes - - - Neue Zauber - - - Neue Tränke - New Potions - - - - - Burg - - - Leuchtturm - - - Wurmloch - wormhole - - - Bergwerk - - - Steinbruch - - - Hafen - - - Akademie - - - Magierturm - - - Schmiede - - - Sägewerk - - - Pferdezucht - - - Monument - - - Damm - - - Karawanserei - - - Tunnel - - - Taverne - - - Steinkreis - - - Gesegneter Steinkreis - - - Traumschlößchen - - - Struktur - - - Akademie der Künste - academy of arts - - - Skulptur - sculpture - - - - - Zauberstab - - - Zauberstäbe - - - - - Grundmauern - - - Handelsposten - - - Befestigung - - - Turm - - - Burg - - - Festung - - - Zitadelle - - - - - Pyramide - pyramid - - - Pyramide - pyramid - - - - - Sphäre der Unsichtbarkeit - sphere of invisibility - - - Sphären der Unsichtbarkeit - spheres of invisibility - - - Kraut - - - Kräuterbeutel - - - Kräuterbeutel - - - Phiole - - - Phiolen - - - Katapultmunition - ammunition - - - Katapultmunition - ammunition - - - Sonnensegel - solar sail - - - Sonnensegel - solar sails - - - Weihnachtsbaum - christmas tree - - - Weihnachtsbäume - christmas trees - - - Sternenstaub - stardust - - - Sternenstaub - stardust - - - Papyrus - papyrus - - - Papyri - papyri - - - Elfenohr - elven ear - - - Elfenohren - elven ears - - - Dämonenblut - demon blood - - - Dämonenblut - demon blood - - - Goblinkopf - goblin head - - - Goblinköpfe - goblinheads - - - Zwergenbart - dwarven beard - - - Zwergenbärte - dwarven beards - - - Halblingfuß - halfling foot - - - Halblingfüße - halfling feet - - - Menschenskalp - human scalp - - - Menschenskalpe - human scalps - - - Meermenschschuppe - aquarian scale - - - Meermenschschuppen - aquarian scales - - - Insektenfühler - insect antenna - - - Insektenfühler - insect antenna - - - Katzenschwanz - cat tail - - - Katzenschwänze - cat tails - - - Orkhauer - orc tusk - - - Orkhauer - orc tusks - - - Trollhorn - troll horn - - - Trollhörner - troll horns - - - Feder des Phönix - feather of the phoenix - - - Federn des Phönix - feathers of the phoenix - - - - - Silber - - - Silber - - - Trefferpunkt - - - Trefferpunkte - - - Aura - - - Aura - - - permanente Aura - - - permanente Aura - - - Bauer - - - Bauern - - - Einheit - - - Einheiten - - - Person - - - Personen - - - - - Runenschwert - - - Runenschwerter - - - Eisen - - - Eisen - - - Holz - - - Holz - - - Stein - - - Steine - - - Wagen - - - Wagen - - - Katapult - - - Katapulte - - - Schwert - - - Schwerter - - - Speer - - - Speere - - - Mallornspeer - - - Mallornspeere - - - Armbrust - - - Armbrüste - - - Mallornarmbrust - - - Mallornarmbrüste - - - Bogen - - - Bögen - - - Mallornbogen - - - Mallornbögen - - - - Kettenhemd - - - Kettenhemden - - - Schuppenpanzer - - - Schuppenpanzer - - - Plattenpanzer - - - Plattenpanzer - - - Balsam - - - Balsam - - - Gewürz - - - Gewürze - - - Juwel - - - Juwelen - - - Myrrhe - - - Myrrhe - - - Öl - - - Öl - - - Seide - - - Seide - - - Weihrauch - - - Weihrauch - - - Flammenschwert - - - Flammenschwerter - - - Bihänder - - - Bihänder - - - Kriegsaxt - axe - - - Kriegsäxte - axes - - - Elfenbogen - - - Elfenbögen - - - Laenschwert - - - Laenschwerter - - - Laenschild - - - Laenschilde - - - Laenkettenhemd - - - Laenkettenhemden - - - Laen - - - Laen - - - Schild - - - Schilde - - - Hellebarde - - - Hellebarden - - - Lanze - - - Lanzen - - - Mallornlanze - - - Mallornlanzen - - - Mallorn - - - Mallorn - - - Keks - - - Kekse - - - Apfel - - - Äpfel - - - Nuß - - - Nüsse - - - Mandelkern - - - Mandelkerne - - - Drachenblut - - - Drachenblut - - - Feenstiefel - - - Feenstiefel - - - Heiltrank - - - Heiltränke - - - Antimagiekristall - - - Antimagiekristalle - - - Tiegel mit Krötenschleim - - - Tiegel mit Krötenschleim - - - Amulett - - - Amulette - - - Amulett der Keuschheit - - - Amulette der Keuschheit - - - Amulett der Heilung - - - Amulette der Heilung - - - Amulett des Treffens - - - Amulette des Treffens - - - Amulett des wahren Sehens - - - Amulette des wahren Sehens - - - Katzenamulett - - - Katzenamulette - - - Ring der Unsichtbarkeit - - - Ringe der Unsichtbarkeit - - - Ring der Macht - - - Ringe der Macht - - - Ring der flinken Finger - - - Ringe der flinken Finger - - - Pferd - - - Pferde - - - Magischer Kräuterbeutel - - - Magische Kräuterbeutel - - - Silberbeutel - - - Silberkassette - - - Drachenhort - - - Drachenkopf - - - Drachenköpfe - - - Auge des Drachen - - - Augen des Drachen - - - Schartiges Schwert - - - Schartige Schwerter - - - Rostiger Schild - - - Rostige Schilde - - - Rostige Hellebarde - rusty halberd - - - Rostige Hellebarden - rusty halberds - - - Rostige Kriegsaxt - rusty axe - - - Rostige Kriegsäxte - rusty axes - - - Rostiger Zweihänder - rusty claymore - - - Rostige Zweihänder - rusty claymores - - - Rostiges Kettenhemd - - - Rostige Kettenhemden - - - Beutel des negativen Gewichts - - - Beutel des negativen Gewichts - - - Ring der Regeneration - - - Ringe der Regeneration - - - Amulett der Dunkelheit - - - Amulette der Dunkelheit - - - Zauberbeutel - - - Zauberbeutel - - - Traumauge - - - Traumaugen - - - Seeschlangenkopf - - - Seeschlangenköpfe - - - Aurafocus - - - Aurafocuse - - - Akkredition des Xontormia-Expreß - - - Akkreditionen des Xontormia-Expreß - - - Szepter der Tränen - wand of tears - - - Szepter der Tränen - wands of tears - - - Schneeball - snowball - - - Schneebälle - snowball - - - Schneemann - snowman - - - Schneemänner - snowmen - - - Gürtel der Trollstärke - - - Gürtel der Trollstärke - - - Elfenpferd - - - Elfenpferde - - - Pegasus - - - Pegasi - - - Delphin - - - Delphine - - - Eintrittskarte des Großen Museum - - - Eintrittskarten des Großen Museum - - - Rückkehrticket des Großen Museum - - - Rückkehrtickets des Großen Museum - - - Astralkristall - - - Astralkristalle - - - Talenttrunk - - - Talenttrünke - - - Same - - - Samen - - - Mallornsame - - - Mallornsamen - - - Feuerwerk - - - Feuerwerke - - - Lebkuchenherz mit der Aufschrift 'Erz und - Stein, das ist fein' - - - Lebkuchenherzen mit der Aufschrift 'Erz und - Stein, das ist fein' - - - Schlüssel - key - - - Schlüssel - keys - - - Achatener Schlüssel - agate key - - - Achatene Schlüssel - agate keys - - - Saphirner Schlüssel - sapphire key - - - Saphirne Schlüssel - sapphire keys - - - - - Flachwurz - - - Würziger Wagemut - - - Eulenauge - - - Grüner Spinnerich - - - Blauer Baumringel - - - Elfenlieb - - - Gurgelkraut - - - Knotiger Saugwurz - - - Blasenmorchel - - - Wasserfinder - - - Kakteenschwitz - - - Sandfäule - - - Windbeutel - - - Fjordwuchs - - - Alraune - - - Steinbeißer - - - Spaltwachs - - - Höhlenglimm - - - Eisblume - - - Weißer Wüterich - - - Schneekristall - - - - - Flachwurz - - - Würzige Wagemut - - - Eulenaugen - - - Grüne Spinneriche - - - Blaue Baumringel - - - Elfenlieb - - - Gurgelkräuter - - - Knotige Saugwurze - - - Blasenmorcheln - - - Wasserfinder - - - Kakteenschwitze - - - Sandfäulen - - - Windbeutel - - - Fjordwuchse - - - Alraunen - - - Steinbeißer - - - Spaltwachse - - - Höhlenglimme - - - Eisblumen - - - Weiße Wüteriche - - - Schneekristalle - - - - Siebenmeilentee - - - Goliathwasser - - - Wasser des Lebens - - - Schaffenstrunk - - - Wundsalbe - - - Bauernblut - - - Gehirnschmalz - - - Dumpfbackenbrot - - - Nestwärme - - - Pferdeglück - - - Berserkerblut - - - Bauernlieb - - - Trank der Wahrheit - - - Elixier der Macht - - - Heiltrank - - - - Siebenmeilentees - - - Goliathwasser - - - Wasser des Lebens - - - Schaffenstrünke - - - Wundsalben - - - Bauernblut - - - Gehirnschmalz - - - Dumpfbackenbrote - - - Nestwärme - - - Pferdeglück - - - Berserkerblut - - - Bauernlieb - - - Tränke der Wahrheit - - - Elixiere der Macht - - - Heiltränke - - - - - Gürtel der Heldentaten - - - Gürtel der Heldentaten - - - - - AGGRESSIV - - - JEDEM - - - ALLES - - - ANZAHL - - - AURA - - - BÄUME - - - BAUERN - - - BEISTAND - - - BEWACHEN - - - BURG - - - DEFENSIV - - - EINHEIT - - - ERESSEA - - - FLIEHE - - - FREMDES - - - GEBÄUDE - - - GEGENSTÄNDE - - - GIB - - - GNADE - - - HELFE - - - HINTEN - - - HINTER - - - KOMMANDO - - - KRÄUTER - - - DURCHREISE - TRAVEL - - - KÄMPFE - - - NICHT - - - NÄCHSTER - - - PARTEI - - - PARTEITARNUNG - - - PAUSE - - - PERSONEN - - - PRIVAT - - - REGION - - - SCHIFF - - - SILBER - - - STRAßEN - - - STUFE - - - TEMPORÄRE - - - TRÄNKE - - - UM - - - VOR - - - VORNE - - - ZAUBER - - - - XETRANK - XEPOTION - - - XEBALLON - XEBALLOON - - - XELAEN - XELAEN - - - - - Alchemie - - - Armbrustschießen - - - Ausdauer - - - Bergbau - - - Bogenschießen - - - Burgenbau - - - Handeln - - - Hiebwaffen - - - Holzfällen - - - Katapultbedienung - - - Kräuterkunde - - - Magie - - - Pferdedressur - - - Reiten - - - Rüstungsbau - - - Schiffbau - - - Segeln - - - Spionage - - - Stangenwaffen - - - Steinbau - - - Steuereintreiben - - - Straßenbau - - - Taktik - - - Tarnung - - - Unterhaltung - - - Waffenbau - - - Waffenloser Kampf - - - Wagenbau - - - Wahrnehmung - - - - - - // - - - BANNER - - - ARBEITEN - - - WARTEN - WAIT - - - ATTACKIEREN - - - BIETEN - - - BEANSPRUCHEN - CLAIM - - - BEKLAUEN - - - BELAGERE - - - BENENNEN - - - BENUTZEN - - - BESCHREIBEN - - - BETRETEN - - - BEWACHEN - - - BOTSCHAFT - - - ENDE - - - FAHREN - - - NUMMER - - - FRIEDEN - PEACE - - - KRIEG - WAR - - - FOLGEN - - - FORSCHEN - - - HELFEN - - - KÄMPFEN - - - KAMPFZAUBER - - - KAUFEN - - - KONTAKTIEREN - - - LEHREN - - - LERNEN - - - LIEFERE - - - MACHEN - - - NACH - - - XONTORMIA - XONTORMIA - - - ALLIANZ - ALLIANCE - - - BEFÖRDERUNG - PROMOTION - - - BEZAHLEN - PAY - - - PFLANZEN - - - PRÄFIX - - - SYNONYM - - - INFO - - - PASSWORT - - - REKRUTIEREN - - - RESERVIEREN - - - ROUTE - - - SABOTIEREN - - - OPTION - - - SPIONIEREN - - - STIRB - - - TARNEN - - - TRANSPORTIEREN - - - TREIBEN - - - UNTERHALTEN - - - VERKAUFEN - - - VERLASSEN - - - VERGESSEN - - - ZAUBERE - - - ZEIGEN - - - ZERSTÖREN - - - ZÜCHTEN - - - DEFAULT - - - REPORT - - - XML - XML - - - URSPRUNG - - - EMAIL - - - PIRATERIE - - - LOCALE - - - NEUSTART - - - GRUPPE - - - OPFERE - - - BETEN - - - SORTIEREN - - - JIHAD - - - GM - - - WERWESEN - - - - - Optionen - - - Stufe - - - Aktueller Status - - - Benötigte Kräuter - - - im Bau - - - beschädigt - - - Unglücklicherweise wurde deine Partei - ausgelöscht. Du kannst gerne an einer anderen Stelle wieder - einsteigen. Melde Dich einfach wieder an. - - - Talente - - - hat - - - Größe - - - Zauber - - - Kampfzauber - - - keiner - - - Liste aller Adressen - - - anonym - - - Angriff - - - Verteidigung - - - Rüstung - - - Schaden - - - - - Deine Partei hat letzte Runde keinen Zug - abgegeben! - - - - - Schneemann - snowman - - - Schneemänner - snowmen - - - Klon - clone - - - Klone - clones - - - Klonen - clones - - - Klonen - clone - - - - Schablone - template - - - Schablonen - templates - - - Schablonen - templates - - - Schablonen - template - - - - Gnom - gnome - - - Gnome - gnomes - - - Gnomen - gnomes - - - Gnomen - gnome - - - - Museumsgeist - museumghost - - - Museumsgeister - museumghosts - - - Museumsgeistern - museumghosts - - - Museumsgeister - museumghost - - - - Ghast - ghast - - - Ghaste - ghasts - - - Ghasten - ghasts - - - Ghast - ghast - - - - Ghoul - ghoul - - - Ghoule - ghouls - - - Ghoulen - ghouls - - - Ghoul - ghoul - - - - Juju-Zombie - juju-zombie - - - Juju-Zombies - juju-zombies - - - Juju-Zombies - juju-zombies - - - Juju-Zombie - juju-zombie - - - - Zombie - zombie - - - Zombies - zombies - - - Zombies - zombies - - - Zombie - zombie - - - - Skelettherr - skeleton lord - - - Skelettherren - skeleton lords - - - Skelettherren - skeleton lords - - - Skelettherren - skeleton lord - - - - Skelett - skeleton - - - Skelette - skeletons - - - Skeletten - skeletons - - - Skelett - skeleton - - - - Zentaur - centaur - - - Zentauren - centaurs - - - Zentauren - centaurs - - - Zentauren - centaur - - - - Schattenritter - shadow knight - - - Schattenritter - shadow knight - - - Schattenrittern - shadow knights - - - Schattenritter - shadow knight - - - - Seeschlange - sea serpent - - - Seeschlangen - sea serpents - - - Seeschlangen - sea serpents - - - Seeschlangen - sea serpent - - - - Krake - kraken - - - Kraken - krakens - - - Kraken - krakens - - - Kraken - kraken - - - - Riesenschildkröte - giant turtle - - - Riesenschildkröten - giant turtles - - - Riesenschildkröten - giant turtles - - - Riesenschildkröten - giant turtle - - - - Delphin - dolphin - - - Delphine - dolphins - - - Delphinen - dolphins - - - Delphin - dolphin - - - - Tiger - tiger - - - Tiger - tiger - - - Tigern - tigers - - - Tiger - tiger - - - - Höllenkatze - hellcat - - - Höllenkatzen - hellcats - - - Höllenkatzen - hellcats - - - Höllenkatzen - hellcat - - - - Eule - owl - - - Eulen - owls - - - Eulen - owls - - - Eulen - owl - - - - Fee - fairy - - - Feen - fairies - - - Feen - fairies - - - Feen - fairy - - - - Traumkatze - dreamcat - - - Traumkatzen - dreamcats - - - Traumkatzen - dreamcats - - - Traumkatzen - dreamcat - - - - Teufelchen - imp - - - Teufelchen - imps - - - Teufelchen - imps - - - Teufelchen- - imp - - - - Geist - ghost - - - Geister - ghosts - - - Geistern - ghosts - - - Geister - ghost - - - - Warg - direwolf - - - Warge - direwolves - - - Wargen - direwolves - - - Warg - direwolf - - - - Einhorn - unicorn - - - Einhörner - unicorns - - - Einhörnern - unicorns - - - Einhorn - unicorn - - - - Nymphe - nymph - - - Nymphen - nymphs - - - Nymphen - nymphs - - - Nymphen - nymph - - - - Singdrache - song dragon - - - Singdrachen - song dragons - - - Singdrachen - song dragons - - - Singdrachen - song dragon - - - - Ratte - rat - - - Ratten - rats - - - Ratten - rats - - - Ratten - rat - - - - Adler - eagle - - - Adler - eagles - - - Adlern - eagles - - - Adler - eagle - - - - Tunnelwurm - tunnelworm - - - Tunnelwürmer - tunnelworms - - - Tunnelwürmern - tunnelworms - - - Tunnelwurm - tunnelworm - - - - Luchs - lynx - - - Luchse - lynx - - - Luchsen - lynx - - - Luchs - lynx - - - - Wolf - wolf - - - Wölfe - wolves - - - Wölfen - wolves - - - Wolfs - wolf - - - - Bauer - peasant - - - Bauern - peasants - - - Bauern - peasants - - - Bauern - peasant - - - - Hirntöter - braineater - - - Hirntöter - braineaters - - - Hirntöter - braineaters - - - Hirntöter - braineater - - - - Schlumpf - smurf - - - Schlümpfe - smurfs - - - Schlumpf - smurf - - - Schlümpfen - smurfs - - - - Kröte - toad - - - Kröten - toads - - - Kröten - toads - - - Kröten - toad - - - - Alp - nightmare - - - Alps - nightmaress - - - Alps - nightmares - - - Alp - nightmare - - - - Bergwächter - mountainguard - - - Bergwächter - mountainguard - - - Bergwächtern - mountainguards - - - Bergwächter - mountainguard - - - - Schattenmeister - shadowmaster - - - Schattenmeister - shadowmaster - - - Schattenmeistern - shadowmasters - - - Schattenmeister - shadowmaster - - - - Schattendämon - shadowdemon - - - Schattendämonen - shadowdemons - - - Schattendämonen - shadowdemons - - - Schattendämon - shadowdemon - - - - Steingolem - stone golem - - - Steingolems - stone golems - - - Steingolems - stone golems - - - Steingolem - stone golem - - - - Eisengolem - irongolem - - - Eisengolems - irongolems - - - Eisengolems - irongolems - - - Eisengolem - irongolem - - - - Zauber - spell - - - Zauber - spell - - - Zauber - spell - - - Zauber - spell - - - - Spezial - special - - - Spezial - special - - - Spezial - special - - - Spezial - special - - - - Dracoid - dracoid - - - Dracoide - dracoids - - - Dracoiden - dracoids - - - Dracoiden - dracoid - - - - Katzendrache - catdragon - - - Katzendrachen - catdragons - - - Katzendrachen - catdragons - - - Katzendrachen - catdragon - - - - Ent - ent - - - Ents - ents - - - Ents - ents - - - Ent - ent - - - - Schattendrache - shadow dragon - - - Schattendrachen - shadow dragons - - - Schattendrachen - shadow dragons - - - Schattendrachen - shadow dragon - - - - Todesflatter - darkbat - - - Todesflattern - darkbats - - - Todesflattern - darkbats - - - Todesflatter - darkbat - - - - Alptraum - nightmare - - - Alpträume - nightmares - - - Alpträumen - nightmares - - - Alptraum - nightmare - - - - Nachteinhorn - vampiric unicorn - - - Nachteinhörner - vampiric unicorns - - - Nachteinhörnern - vampiric unicorns - - - Nachteinhorn - vampiric unicorn - - - - Wyrm - wyrm - - - Wyrme - wyrms - - - Wyrmen - wyrms - - - Wyrm - wyrm - - - - Drache - dragon - - - Drachen - dragons - - - Drachen - dragons - - - Drachen - dragon - - - - Jungdrache - young dragon - - - Jungdrachen - young dragons - - - Jungdrachen - young dragons - - - Jungdrachen - young dragon - - - - Phönix - phoenix - - - Phönixe - phoenixes - - - Phönixen - phoenixes - - - Phönix - phoenix - - - - Illusion - illusion - - - Illusionen - illusions - - - Illusions - illusions - - - Illusions - illusion - - - - Spinx - sphinx - - - Spinxen - sphinxs - - - Spinxen - sphinx - - - Spinx - sphinx - - - - kleiner Scarabäus - little scarab - - - kleine Scarabäen - little scarab - - - kleinen Scarabäen - little scarab - - - kleine Scarabäen - little scarab - - - - grüner Scarabäus - green scarab - - - grüne Scarabäen - green scarab - - - grünen Scarabäen - green scarab - - - grünen Scarabäen - green scarab - - - - blauer Scarabäus - blue scarab - - - blaue Scarabäen - blue scarabs - - - blauen Scarabäen - blue scarab - - - blaue Scarabäen - blue scarab - - - - roter Scarabäus - red scarab - - - rote Scarabäen - red scarabs - - - roten Scarabäen - red scarab - - - rote Scarabäen - red scarab - - - - Untoter Pharao - undead Pharaoh - - - Untoter Pharaonen - undead Pharaohs - - - Untoten Pharao - undead Pharaoh - - - Untote Pharaonen - undead Pharaoh - - - - Mumie - mummy - - - Mumien - mummys - - - Mumien - mummy - - - Mumien - mummy - - - - Untoter - undead - - - Untote - undead - - - Untoten - undead - - - Untoten - undead - - - - Apepschlange - apepsnake - - - Apepschlangen - apepsnakes - - - Apepschlangen - apepsnakes - - - Apepschlange - apepsnake - - - - Apophis - apophis - - - Apophis - apophis - - - Apophis - apophis - - - Apophis - apophis - - - - Meermensch - aquarian - - - Meermenschen - aquarians - - - Meermenschen - aquarians - - - Meermenschen - aquarian - - - - Katze - cat - - - Katzen - cats - - - Katzen - cats - - - Katzen - cats - - - - Halbling - halfling - - - Halblinge - halflings - - - Halblingen - halflings - - - Halblings - halfling - - - - Insekt - insect - - - Insekten - insects - - - Insekten - insects - - - Insekten - insect - - - - Dämon - demon - - - Dämonen - demons - - - Dämonen - demons - - - Dämonen - demon - - - - Troll - troll - - - Trolle - trolls - - - Trollen - trolls - - - Troll - troll - - - - Mensch - human - - - Menschen - humans - - - Menschen - humans - - - Menschen - human - - - - Goblin - goblin - - - Goblins - goblins - - - Goblins - goblins - - - Goblin - goblin - - - - Ork - orc - - - Orks - orcs - - - Orks - orcs - - - Ork - orc - - - - Snotling - snotling - - - Snotlinge - snotlings - - - Snotlingen - snotlings - - - Snotling - snotling - - - - Snotling - snotling - - - Snotlinge - snotlings - - - Snotlingen - snotlings - - - Snotling - snotling - - - - Elf - elf - - - Elfen - elves - - - Elfen - elves - - - Elfen - elves - - - - Zwerg - dwarf - - - Zwerge - dwarves - - - Zwergen - dwarves - - - Zwergen - dwarf - - - - - - sehr stark - critically wounded - - - stark - heavily wounded - - - schwer verwundet - badly wounded - - - verwundet - wounded - - - erschöpft - exhausted - - - - - For Seven Mile Tea, boil up a Cobalt Fungus and pour the resulting brew into a Windbag. Catch and filter the liquid that drips out and administer it. This tea allows up to ten men to move as fast as a horse. - Für den Siebenmeilentee koche man einen Blauen Baumringel auf und gieße dieses Gebräu in einen Windbeutel. Das heraustropfende Wasser fange man auf, filtere es und verabreiche es alsdann. Durch diesen Tee können bis zu zehn Menschen schnell wie ein Pferd laufen. - - - 'First roast the Gurgelkraut quickly and add some Fjordwuchs to spice it up. Let it all boil slowly until almost all liquid has evaporated. Leave the mash overnight and finally squeeze it the next morning until a thick fluid drips out.' The liquid thus produced, 'Goliath Water' as we call it, is enough for 10 men and gives each man the carrying capacity of a horse for one week. - Zuerst brate man das Gurgelkraut leicht an und würze das Zeug mit ein wenig Fjordwuchs. Man lasse alles so lange kochen, bis fast alle Flüssigkeit verdampft ist. Diesen Brei stelle man über Nacht raus. Am nächsten Morgen presse man den Brei aus. Die so gewonnene Flüssigkeit, Goliathwasser genannt, verleiht bis zu zehn Männern die Tragkraft eines Pferdes. - - - The "Water of Life" allows living trees to be created from logs. A Knotroot and Elvendear are heated until one can just still keep one's finger in. This is then poured into a jar and allowed to cool slowly. The extract is sufficient for 10 pieces of wood. - Das 'Wasser des Lebens' ist in der Lage, aus gefällten Baumstämmen wieder lebende Bäume zu machen. Dazu wird ein knotiger Saugwurz zusammen mit einem Elfenlieb erwärmt, so daß man gerade noch den Finger reinhalten kann. Dies gieße man in ein Gefäß und lasse es langsam abkühlen. Der Extrakt reicht für 10 Holzstämme. - - - Allow a Tangy Temerity to simmer for three hours in a litre of water, then add a grated Mandrake, and sprinkle in a Gapgrowth harvested at full moon. The whole brew should then be allowed to stew for three days in a warm place. This potion increases the strength and endurance of ten men so that they can achieve twice as much in a week. - Man lasse einen Würzigen Wagemut drei Stunden lang in einem Liter Wasser köcheln. Dann gebe man eine geriebene Alraune dazu und bestreue das ganze mit bei Vollmond geerntetem Spaltwachs. Nun lasse man den Sud drei Tage an einem dunklen und warmen Ort ziehen und seie dann die Flüssigkeit ab. Dieser Schaffenstrunk erhöht die Kraft und Ausdauer von zehn Männern, so daß sie doppelt soviel schaffen können wie sonst. - - - When one is severely wounded after a hard battle it is advisable to have some Ointment to hand. Applied to wounds, this magical paste closes them in the blink of an eye. For the preparation the alchemist requires a cobalt fungus, tangy temerity, and white hemlock. A dose of the potion heals up to 400 hitpoints. - Ist man nach einem einem harten Kampf schwer verwundet, ist es ratsam, etwas Wundsalbe parat zu haben. Streicht man diese magische Paste auf die Wunden, schließen sich diese augenblicklich. Für die Herstellung benötigt der Alchemist nebst einem Blauen Baumringel einen Würzigen Wagemut und einen Weißen Wüterich. Eine solche Portion heilt bis zu 400 Lebenspunkte. - - - Knowledge of this potion is amongst the most dangerous and secret wisdom of the alchemist. Snatched from the darkest hells, the knowledge of this formula enables the production of an elixer which serves Demons as nourishment. If used by normal beings it leads to a swift death and eternal undeath. The creation requires Fjord Fungus together with some Cave Lichen and Cobalt Fungus, and an unfortunate peasant from the region, who is killed in the bloody days-long ritual. One vial of the potion satisfies the hunger of 100 Demons for a week. - Zu den gefährlichsten und geheimsten Wissen der Alchemisten zählt die Kenntnis um diesen Trank. Den finstersten Höllen entrissen, ermöglicht die Kenntnis dieser Formel die Herstellung eines Elixiers, welches Dämonen als Nahrung dient. Von normalen Lebewesen eingenommen, führt es zu schnellem Tod und ewigen Nichtleben. Die Herstellung benötigt nebst Fjordwuchs, etwas Höhlenglimm und einem Blauen Baumringel auch einen Bauern aus der Region, welcher in einem tagelangen blutigen Ritual getötet wird. Ein Fläschchen des Tranks kann den Hunger von 100 Dämonen für eine Woche stillen. - - - To create the brain wax potion, mix the juice of a waterfinder with quite a bit of grated windbag and a pinch of bugleweed. Let this steep for just a minute. When the liquid is only lukewarm, add some rock weed. Using a large spoon, stirr exactly seven times clockwise and then seven times counterclockwise. Fill the vial when the liquid has gone still. The juice gives ten people a 33% chance of an additional attempt at learning a skill. - Für das Gehirnschmalz verrühre man den Saft eines Wasserfinders mit recht viel geriebenem Windbeutel und ein wenig Gurgelkraut. Dies lasse man kurz aufwallen. Wenn die Flüssigkeit nur noch handwarm ist, gebe man etwas Steinbeißer dazu. Das ganze muß genau siebenmal rechtsherum und siebenmal linksherum mit einem großen Löffel gerührt werden. Wenn keine Bewegung mehr zu erkennen ist, fülle man den Saft ab. Der Saft gibt mit einer Chance von 1/3 bis zu zehn Personen einen zusätzlichen Lernversuch. - - - A duncebun is a nasty piece of work, negating any attempt at learning a skill, or even causing the subject to forget things! For ten servings knead a rasped fjord fungus, an abraded owlsgaze and a finely sliced spider ivy to a smooth dough. Bake for an hour at moderate heat and brush the result with some cave lichen. Who eats this bread will not learn what he's attempting to learn, and, in case there is no attempt to learn anything, will forget a week's worth of study in his best skill. - Das Dumpfbackenbrot ist eine sehr gemeine Sache, macht es doch jeden Lernerfolg zunichte oder läßt einen gar Dinge vergessen! Für zehn Portionen verknete man einen geriebenen Fjordwuchs, einen zerstoßenes Eulenauge und einen kleingeschnittenen Grünen Spinnerich zu einem geschmeidigen Teig. Diesen backe man eine Stunde lang bei guter Hitze und bestreiche das Ergebnis mit etwas Höhlenglimm. Wer dieses Brot gegessen hat, kann eine Woche lang nichts lernen, und so er nichts zu lernen versucht, wird er gar eine Woche seiner besten Fähigkeit vergessen. - - - A potion of nest warmth allows an insect to recruit outside of a desert region in winter. The learned alchemist prepares this by taking a peyote, mixing it with a portion of gapgrowth which has been gathered during a clear, starry night. To dispell winter, add some blossoms of the ice begonia in the mix, and stirr everything together with a spider ivy until it turns a nice shade of violet. One vial supplies an entire region for a whole week. - Nestwärme erlaubt es einem Insekt, im Winter außerhalb von Wüsten neue Rekruten anzuwerben. Zur Zubereitung nimmt der geübte Alchemist einen Kakteenschwitz, vermischt ihn mit einer Portion Spaltwachs, die in einer sternklaren Nacht gesammelt wurde, gibt zur Vertreibung des Winters einige Blütenblätter der Eisblume in den Sud, und rührt alles mit einem grünen Spinnerich bis es eine violette Farbe annimmt. Ein Trank reicht eine Woche lang für eine ganze Region. - - - To make a horsepower potion, chop a peyote, a cobalt fungus and some knotroot, and boil it in a bucketful of water. Then add some sand reeker and let the mixture steep for three days. Finally one gives this to the horses to drink, to double their procreation. - Für das Pferdeglück zerhacke man einen Kakteenschwitz, einen blauen Baumringel und etwas knotigen Saugwurz und koche das ganze mit einem Eimer Wasser auf. Dann füge man etwas Sandfäule dazu und lasse diesen Sud drei Tage lang ziehen. Letztlich gebe man es den Pferden zu trinken, auf daß sie sich doppelt so schnell vermehren. - - - The use of the berserkers blood potion is advised to increase one's warriors abilities to new heights. To create this, one needs a white hemlock, some flatroot, sand reeker and a mandrake. All ingredients have to be sliced as finely as possible, after which it is boiled for two hours. The cooled brew is strained through a cloth. The resulting juice is enough to improve up to ten warriors. - Will man seine Krieger zu Höchstleistungen antreiben, sei das Berserkerblut empfohlen. Um es herzustellen, braucht man einen Weißen Wüterich, etwas Flachwurz, Sandfäule und eine Alraune. Alle Zutaten müssen möglichst klein geschnitten und anschließend zwei Stunden lang gekocht werden. Den abgekühlten Brei gebe man in ein Tuch und presse ihn aus. Der so gewonnene Saft reicht aus, um zehn Kämpfer besser angreifen zu lassen. - - - The peasant love potion enamors both Man and Woman to the same degree and results in a strong wish for children. For a big portion scoop out a mandrake, fill it with finely chopped bubblemorel, elvendear and snowcrystal petal, sprinkle grated rock weed on top and let it simmer on low heat for twenty hours. The potion can grant up to 1000 peasants the happiness of twins. - Das Bauernlieb betört Mann und Frau gleichwohl und läßt in ihnen den Wunsch nach Kindern anwachsen. Für eine große Portion höhle man eine Alraune aus, gebe kleingehackten Blasenmorchel, Elfenlieb und Schneekristall dazu, streue ein wenig geriebenen Steinbeißer darüber und lasse dieses zwanzig Stunden lang auf kleiner Flamme kochen. Bis zu 1000 Bauern vermag der Trank das Glück von Zwillinge zu bescheren. - - - This simple but very potent brew sharpens the senses of anyone that drinks of it and makes him able to see through even the most complex illusions for one week. - Dieses wirkungsvolle einfache Gebräu schärft die Sinne des Trinkenden derart, daß er in der Lage ist, eine Woche lang auch die komplexesten Illusionen zu durchschauen. - - - One of the most rare and prized of all alchemist elixers, this potion grants the user a dragon's power for a few weeks. The potion increases the life-energy of a maximum of ten people fivefold. The effect is strongest right after drinking and slowly decreases over time. To brew this potion the alchemist needs an elvendear, a windbag, a piece of waterfinder and a spider ivy. Finally he dusts it with some minced bubblemorel and stirrs the powder into some dragon's blood. - Eines der seltensten und wertvollsten alchemistischen Elixiere, verleiht dieser Trank dem Anwender für einige Wochen die Kraft eines Drachen. Der Trank erhöht die Lebensenergie von maximal zehn Personen auf das fünffache. Die Wirkung ist direkt nach der Einnahme am stärksten und klingt danach langsam ab. Zur Herstellung benötigt der Alchemist ein Elfenlieb, einen Windbeutel, ein Stück Wasserfinder und einen Grünen Spinnerich. Über dieses Mischung streue er schließlich einen zerriebenen Blasenmorchel und rühre dieses Pulver unter etwas Drachenblut. - - - For a healing potion one takes the peel of a windbag and some bugleweed, stirr in some chopped elvendear and sprinkle it with the blossoms of an ice begonia. This has to cook through for four days, while a gapgrowth has to be added on the second day. Then one carefully scoops off the top layer of liquid. One such potion gives four men (or one man four times) a 50% chance to survive otherwise lethal wounds. The potion is automatically used in case of injury. - Für einen Heiltrank nehme man die Schale eines Windbeutels und etwas Gurgelkraut, rühre eine kleingehacktes Elfenlieb dazu und bestreue alles mit den Blüten einer Eisblume. Dies muß vier Tage lang gären, wobei man am zweiten Tag einen Spaltwachs dazutun muß. Dann ziehe man vorsichtig den oben schwimmenden Saft ab. Ein solcher Trank gibt vier Männern (oder einem Mann vier mal) im Kampf eine Chance von 50%, sonst tödliche Wunden zu überleben. Der Trank wird von ihnen automatisch bei Verletzung angewandt. - - - - - Erschaffe einen Ring der Macht - Create A Ring Of Power - - - Schild des Fisches - Shield Of The Fish - - - Runen des Schutzes - Protective Runes - - - Ruf der Realität - Call Of Reality - - - Astraler Ruf - Astral Call - - - Magiefresser - Destroy Magic - - - Mauern der Ewigkeit - Eternal Walls - - - Stehle Aura - Steal Aura - - - Schutzzauber - Resist Magic - - - Astraler Blick - Astral Gaze - - - Auratransfer - Transfer Aura - - - Monster friedlich stimmen - Calm Monster - - - Luftschiff - Airship - - - Lied der Verführung - Song Of Seduction - - - Schaler Wein - Hangover - - - Aushorchen - sound_out - - - Kriegsgesang - Song Of War - - - Gesang der Angst - Song Of Fear - - - Lied des Ortes analysieren - Analysis - - - Schockwelle - Shockwave - - - Fluch brechen - Negate Curse - - - Erschaffe ein Amulett der Keuschheit - Create An Amulet Of Chastity - - - Beschleunigung - Acceleration - - - Großer Drachenodem - Powerful Dragonbreath - - - Opfere Kraft - Sacrifice Strength - - - Belebtes Gestein - Living Rock - - - Gesang der Melancholie - Song of Melancholy - - - Gesang des wachen Geistes - Song Of The Youthful Spirit - - - Gesang des schwachen Geistes - Song Of The Aging Spirit - - - Gesang der Friedfertigkeit - Song Of Peace - - - Gesang der Versklavung - Song Of Slavery - - - Hohe Kunst der Überzeugung - Song Of Slavery - - - Zeitdehnung - Double Time - - - Vertrauten rufen - Summon Familiar - - - Rüstschild - Shield Shine - - - Wyrmtransformation - Wyrmtransformation - - - Schattenodem - Shadowbreath - - - Feuersturm - Firestorm - - - Feuerwalze - Immolation - - - Eisnebel - Coldfront - - - Säurenebel - Acid Rain - - - Furchteinflößende Aura - Panic - - - Meteorregen - Meteor Shower - - - Schattenruf - Shadow Call - - - Erschaffe einen Ring der Regeneration - Create A Ring Of Regeneration - - - Mob aufwiegeln - Mob Rule - - - Aufruhr beschwichtigen - Calm Riot - - - Aufruhr verursachen - Riot - - - Blick in die Realität - Gaze Upon Reality - - - Störe Astrale Integrität - Astral Disruption - - - Eisiger Drachenodem - Icy Dragonbreath - - - Eisiger Drachenodem - Icy Dragonbreath - - - Erschaffe ein Runenschwert - Create A Runesword - - - Erschaffe einen Beutel des Negativen Gewichts - Create A Bag Of Holding - - - Erschaffe einen Aurafocus - Create An Aurafocus - - - Erschaffe Antimagiekristall - Create An Antimagic Crystal - - - Astrale Schwächezone - Antimagic - - - Astraler Ausgang - Astral Exit - - - Astraler Weg - Astral Path - - - Beute Bewahren - Save Spoils - - - Schutz vor Magie - Protection from Magic - - - Wunderdoktor - Miracle Doctor - - - Schleieraura - Concealing Aura - - - Magie analysieren - Analyze Magic - - - Hohes Lied der Gaukelei - Song of Generosity - - - Gesang des Werbens - Song of Courting - - - Schleieraura - Veil - - - Lied der Heilung - Blessed Harvest - - - Gesang der Furcht - Song of Terror - - - Segen der Erde - Blessed Harvest - - - Heldengesang - Epic Heroes - - - Gesang des Lebens analysieren - Analyze Song of Life - - - Bannlied - Countersong - - - Gesang des Auratransfers - Hymn of Aura Sharing - - - Gesang der Verwirrung - Song of Confusion - - - Plappermaul - Blabbermouth - - - Regentanz - Rain Dance - - - Gaukeleien - Jugglery - - - Friedenslied - Appeasing Song - - - Viehheilung - Cattle Healing - - - Erschaffe Steingolems - Create Stone Golems - - - Erschaffe Eisengolems - Create Iron Golems - - - Hainzauber - Grove Of Oak Trees - - - Rostregen - Rain Of Rust - - - Firuns Fell - Firun's Coat - - - Hagel - Hail - - - Seelenkopie - Doppelganger - - - Irrlichter - Wisps - - - Schlechte Träume - Bad Dreams - - - Bergwächter - Mountain Guardian - - - Magischer Pfad - Magic Path - - - Tor in die Ebene der Hitze - Great Drought - - - Wurzeln der Magie - Roots Of Magic - - - Mahlstrom - Maelstrom - - - Windschild - Air Shield - - - Segne Mallornstecken - Bless Mallorn Logs - - - Beschwörung eines - Wasserelementares - Summon Water Elemental - - - Heilung - Heal - - - Wirbelwind - Whirlwind - - - Astralschutzgeister - Astral Guardian Spirits - - - Meditation - Meditate - - - Beschwöre einen Erdelementar - Summon Earth Elemental - - - Beschwöre einen Sturmelementar - Summon Storm Elemental - - - Erschaffe ein Amulett des wahren - Sehens - Create An Amulet Of True Sight - - - Erschaffe einen Ring der - Unsichtbarkeit - Create A Ring Of Invisibility - - - Miriams flinke Finger - Quick Fingers - - - Heimstein - Homestone - - - Wolfsgeheul - Timber Wolves - - - Blick des Basilisken - Gaze Of The Basilisk - - - Starkes Tor und feste Mauer - Strong Wall And Sturdy Gate - - - Geister bannen - Banish Spirits - - - Lebenslied festigen - Silence Dissonance - - - Ritual der Aufnahme - Rit of Acceptance - - - Weg der Bäume - Path Of Trees - - - Sog des Lebens - Ties Of Life - - - Heiliger Boden - Sacred Ground - - - Erschaffe einen magischen - Kräuterbeutel - Create A Magical Herb Pouch - - - Erwecke Ents - Awakening Of The Ents - - - Vertrauten binden - Bind Familiar - - - Segne Steinkreis - Bless Stone Circle - - - Rindenhaut - Barkskin - - - Verwünschung - Hex - - - Kleine Flüche - Minor Curses - - - Feuerball - Fireball - - - Gabe des Chaos - Chaos Gift - - - Kleines Blutopfer - Lesser Sacrifice - - - Blutrausch - Blood Frenzy - - - Chaosfluch - Chaos Curse - - - Mächte des Todes - Animate Dead - - - Rosthauch - Winds Of Rust - - - Machtübertragung - Transfer Power - - - Feuerwand - Wall Of Fire - - - Fluch der Pestilenz - Curse Of Pestilence - - - Wahnsinn des Krieges - Madness of War - - - Beschwöre Schattendämonen - Summon Shadowdemons - - - Beschwörung eines Hitzeelementar - Summon Fire Elemental - - - Untote Helden - Undead Heroes - - - Erschaffe einen Gürtel der - Trollstärke - Create A Belt Of Troll - Strength - - - Astraler Riss - Astral Leak - - - Astrales Chaos - Astral Chaos - - - Feuerteufel - Fire Fiend - - - Pentagramm - Pentagram - - - Unheilige Kraft - Unholy Strength - - - Todeswolke - Death Cloud - - - Drachenruf - Call Dragons - - - Beschwöre Schattenmeister - Summon Shadowmasters - - - Erschaffe ein Flammenschwert - Create A Flamesword - - - Vertrauten rufen - Call Familiar - - - Chaossog - Chaos Gate - - - Traumsenden - Dream - - - Wahrsagen - Divination - - - Schattenritter - Shadow Knights - - - Grauen der Schlacht - Unspeakable Horrors - - - Seelenfrieden - Eternal Rest - - - Traumschlößchen - Castle Of Illusion - - - Traum der Magie - Dream Of Magic - - - Gestaltwandlung - Shapeshift - - - Traumlesen - Read Dreams - - - Schwere Glieder - Tiredness - - - Wiederbelebung - Resurrection - - - Traumbilder analysieren - Analyse Dreams - - - Schlechter Schlaf - Insomnia - - - Schlaf - Sleep - - - Traumdeuten - Mind Probe - - - Alp - Nightmare - - - Erschaffe ein Traumauge - Create a Visioneye - - - Erschaffe eine Sphäre der Unsichtbarkeit - Create a Sphere of Invisbility - - - Schöne Träume - Pleasant Dreams - - - Traumbilder entwirren - Remove Dreams - - - Vertrauten rufen - Call Familiar - - - Tod des Geistes - Mental Death - - - Süße Träume - Sweet Dreams - - - Traum von den Göttern - Dream of the gods - - - Göttliches Netz - Web of the Gods - - - Kraft der Natur - force of nature - - - Gesang der Götter - Song of the Gods - - - Göttliche Macht - Power of the Gods - - - - - Tötet die Feinde mit Säure. - Kills enemies with acid. - - - Tötet die Feinde mit Kälte. - Kills enemies with cold. - - - Tötet die Feinde mit Feuer. - Kills enemies with fire. - - - Verletzt alle Gegner. - Injures all enemies. - - - Ruft Schattenwesen. - Calls beings from shadow. - - - Panik. - Panic. - - - Entzieht Talentstufen und macht Schaden wie Großer Odem. - - - Dieser Zauber bewirkt eine schwere Störung des Astralraums. Innerhalb eines astralen Radius von Stufe/5 Regionen werden alle Astralwesen, die dem Zauber nicht wiederstehen können, aus der astralen Ebene geschleudert. Der astrale Kontakt mit allen betroffenen Regionen ist für Stufe/3 Wochen gestört. - - - - Diese vor dem Kampf zu zaubernde Ritual gibt den eigenen Truppen - einen zusätzlichen Bonus auf ihre Rüstung. Jeder Treffer - reduziert die Kraft des Zaubers, so dass der Schild sich irgendwann - im Kampf auflösen wird. - - - - - Dieser Zauber beschleunigt einige Kämpfer auf der eigenen Seite - so, dass sie während des gesamten Kampfes in einer Kampfrunde zweimal - angreifen können. - - - - - Dieser Zauber vermag dem Gegner ein geringfügig versetztes Bild der - eigenen Truppen vorzuspiegeln, so wie der Fisch im Wasser auch nicht - dort ist wo er zu sein scheint. Von jedem Treffer kann so die Hälfte - des Schadens unschädlich abgeleitet werden. Doch hält der Schild nur - einige Hundert Schwerthiebe aus, danach wird er sich auflösen. - Je stärker der Magier, desto mehr Schaden hält der Schild aus. - - - - - Zeichnet man diese Runen auf die Wände eines Gebäudes oder auf die - Planken eines Schiffes, so wird es schwerer durch Zauber zu - beeinflussen sein. Jedes Ritual erhöht die Widerstandskraft des - Gebäudes oder Schiffes gegen Verzauberung um 20%. - Werden mehrere Schutzzauber übereinander gelegt, so addiert - sich ihre Wirkung, doch ein hundertprozentiger Schutz läßt sich so - nicht erreichen. Der Zauber hält mindestens drei Wochen an, je nach - Talent des Magiers aber auch viel länger. - - - - - Mit Hilfe dieses Zauber kann der Magier eigene Aura im Verhältnis - 2:1 auf einen anderen Magier des gleichen Magiegebietes oder im - Verhältnis 3:1 auf einen Magier eines anderen Magiegebietes - übertragen. - - - - - Der Magier kann kurzzeitig in die Astralebene blicken und erfährt - so alle Einheiten innerhalb eines astralen Radius von Stufe/5 Regionen. - - - - - Mit Hilfe dieses magischen Gesangs kann der Magier eine Region in - Aufruhr wieder beruhigen. Die Bauernhorden werden sich verlaufen - und wieder auf ihre Felder zurückkehren. - - - - Aus 'Wanderungen' von Firudin dem Weisen: - 'In Weilersweide, nahe dem Wytharhafen, liegt ein kleiner Gasthof, der - nur wenig besucht ist. Niemanden bekannt ist, das dieser Hof - bis vor einigen Jahren die Bleibe des verbannten Wanderpredigers Grauwolf - war. Nachdem er bei einer seiner berüchtigten flammenden Reden fast die - gesammte Bauernschaft angeworben hatte, wurde er wegen Aufruhr verurteilt - und verbannt. Nur zögerlich war er bereit mir das Geheimniss seiner - Überzeugungskraft zu lehren.' - - - - Dieser mächtige Bann raubt dem Opfer seinen freien Willen - und unterwirft sie den Befehlen des Barden. Für einige Zeit wird das Opfer - sich völlig von seinen eigenen Leuten abwenden und der Partei des Barden - zugehörig fühlen. - - - - - Dieser mächtige Bann verhindert jegliche Attacken. Niemand in der - ganzen Region ist fähig seine Waffe gegen irgendjemanden zu erheben. - Die Wirkung kann etliche Wochen andauern. - - - - - Dieses Lied, das in die magische Essenz der Region gewoben wird, - schwächt die natürliche Widerstandskraft gegen eine - Verzauberung einmalig um 15%. Nur die Verbündeten des Barden - (HELFE BEWACHE) sind gegen die Wirkung des Gesangs gefeit. - - - - - Mit diesem Gesang verbreitet der Barde eine melancholische, traurige - Stimmung unter den Bauern. Einige Wochen lang werden sie sich in ihre - Hütten zurückziehen und kein Silber in den Theatern und Tavernen lassen. - - - - - Dieses magische Lied wird, einmal mit Inbrunst gesungen, sich in der - Region fortpflanzen, von Mund zu Mund springen und eine Zeitlang - überall zu vernehmen sein. Nach wie vielen Wochen der Gesang aus dem - Gedächnis der Region entschwunden ist, ist von dem Geschick des Barden - abhängig. Bis das Lied ganz verklungen ist, wird seine Magie allen - Verbündeten des Barden (HELFE BEWACHE), und natürlich auch seinen - eigenem Volk, einen einmaligen Bonus von 15% - auf die natürliche Widerstandskraft gegen eine Verzauberung - verleihen. - - - - - Mit Hilfe dieses magischen Gesangs überzeugt der Magier die Bauern - der Region, sich ihm anzuschließen. Die Bauern werden ihre Heimat jedoch - nicht verlassen, und keine ihrer Besitztümer fortgeben. Jede Woche - werden zudem einige der Bauern den Bann abwerfen und auf ihre Felder - zurückkehren. Wie viele Bauern sich dem Magier anschließen hängt von der - Kraft seines Gesangs ab. - - - - - Einem erfahrenen Magier wird irgendwann auf seinen Wanderungen ein - ungewöhnliches Exemplar einer Gattung begegnen, welches sich dem - Magier anschließen wird. - - - - - Dieses Ritual ermöglicht es, eine Einheit, egal welcher Art, in die - eigene Partei aufzunehmen. Der um Aufnahme Bittende muss dazu willig - und bereit sein, seiner alten Partei abzuschwören. Dies bezeugt er - durch KONTAKTIEREn des Magiers. Auch wird er die Woche über - ausschliesslich mit Vorbereitungen auf das Ritual beschäftigt sein. - Das Ritual wird fehlschlagen, wenn er zu stark an seine alte Partei - gebunden ist, dieser etwa Dienst für seine teuere Ausbildung - schuldet. Der das Ritual leitende Magier muss für die permanente - Bindung des Aufnahmewilligen an seine Partei naturgemäß auch - permanente Aura aufwenden. Pro Stufe und pro 1 permanente Aura kann - er eine Person aufnehmen. - - - - - Jede Verzauberung beeinflußt das Lebenslied, schwächt und verzerrt es. - Der kundige Barde kann versuchen, das Lebenslied aufzufangen und zu - verstärken und die Veränderungen aus dem Lied zu tilgen. - - - - - Wie Lebewesen, so haben auch Schiffe und Gebäude und sogar Regionen - ihr eigenes Lied, wenn auch viel schwächer und schwerer zu hören. - Und so, wie wie aus dem Lebenslied einer Person erkannt werden kann, - ob diese unter einem Zauber steht, so ist dies auch bei Burgen, - Schiffen oder Regionen möglich. - - - - - Dieser Kriegsgesang sät Panik in der Front der Gegner und schwächt - so ihre Kampfkraft erheblich. Angst wird ihren Schwertarm schwächen - und Furcht ihren Schildarm lähmen. - - - - - Wie viele magischen Gesänge, so entstammt auch dieser den altem - Wissen der Katzen, die schon immer um die machtvolle Wirkung der - Stimme wussten. Mit diesem Lied wird die Stimmung der Krieger - aufgepeitscht, sie gar in wilde Raserrei und Blutrausch versetzt. - Ungeachtet eigener Schmerzen werden sie kämpfen bis zum - Tode und niemals fliehen. Während ihre Attacke verstärkt ist - achten sie kaum auf sich selbst. - - - - - Erliegt die Einheit dem Zauber, so wird sie dem Magier alles erzählen, - was sie über die gefragte Region weiß. Ist in der Region niemand - ihrer Partei, so weiß sie nichts zu berichten. Auch kann sie nur das - erzählen, was sie selber sehen könnte. - - - - - Aufzeichung des Vortrags von Selen Ard'Ragorn in Bar'Glingal: - 'Es heiss, dieser Spruch wäre wohl in den Spelunken der Westgassen - entstanden, doch es kann genausogut in jedem andern verrufenen - Viertel gewesen sein. Seine wichtigste Zutat ist etwa ein Fass - schlechtesten Weines, je billiger und ungesunder, desto - wirkungsvoller wird die Essenz. Die Kunst, diesen Wein in pure - Essenz zu destillieren, die weitaus anspruchsvoller als das einfache - Rezeptmischen eines Alchemisten ist, und diese dergestalt zu binden - und konservieren, das sie sich nicht gleich wieder verflüchtigt, wie - es ihre Natur wäre, ja, dies ist etwas, das nur ein Meister des - Cerddor vollbringen kann. Nun besitzt Ihr eine kleine Phiola mit - einer rubinrotschimmernden - nun, nicht flüssig, doch auch nicht - ganz Dunst - nennen wir es einfach nur Elixier. Doch nicht dies ist - die wahre Herausforderung, sodann muss, da sich ihre Wirkung leicht - verflüchtigt, diese innerhalb weniger Tage unbemerkt in das Getränk - des Opfers geträufelt werden. Ihr Meister der Betöhrung und - Verführung, hier nun könnt Ihr Eure ganze Kunst unter Beweis - stellen. Doch gebt Acht, nicht unbedacht selbst von dem Elixier zu - kosten, denn wer einmal gekostet hat, der kann vom Weine nicht mehr - lassen, und er säuft sicherlich eine volle Woche lang. Jedoch nicht - die Verführung zum Trunke ist die wahre Gefahr, die dem Elixier - innewohnt, sondern das der Trunkenheit so sicher ein gar - fürchterliches Leid des Kopfes folgen wird, wie der Tag auf die - Nacht folgt. Und er wird gar sicherlich von seiner besten Fähigkeit - einige Tage bis hin zu den Studien zweier Wochen vergessen haben. - Noch ein Wort der Warnung: Dieses ist sehr aufwendig, und so Ihr - noch weitere Zauber in der selben Woche wirken wollt, so werden sie Euch - schwerer fallen.' - - - - - Mit diesem Lied kann eine Einheit derartig betört werden, so dass - sie dem Barden den größten Teil ihres Bargelds und ihres Besitzes - schenkt. Sie behält jedoch immer soviel, wie sie zum Überleben - braucht. - - - - - Dieser einschmeichelnde Gesang kann fast jedes intelligente Monster - zähmen. Es wird von Angriffen auf den Magier absehen und auch seine - Begleiter nicht anrühren. Doch sollte man sich nicht täuschen, es - wird dennoch ein unberechenbares Wesen bleiben. - - - - - Dieser Zauber ermöglicht es dem Träumer, den Schlaf aller nichtaliierten - Einheiten (HELFE BEWACHE) in der Region so stark zu stören, das sie - vorübergehend einen Teil ihrer Erinnerungen verlieren. - - - - - Dieser mächtige Zauber kann einen Magier vor dem sicheren Tod - bewahren. Der Magier erschafft anhand einer kleinen Blutprobe einen - Klon von sich, und legt diesen in ein Bad aus Drachenblut und verdünntem - Wasser des Lebens. - Anschließend transferiert er in einem aufwändigen Ritual einen Teil - seiner Seele in den Klon. Stirbt der Magier, reist seine Seele in den - Klon und der erschaffene Körper dient nun dem Magier als neues Gefäß. - Es besteht allerdings eine geringer Wahrscheinlichkeit, dass die Seele - nach dem Tod zu schwach ist, das neue Gefäß zu erreichen. - - - - - Der Zauberer spricht eine Beschwörung über einen Teil der Region, - und in der Folgewoche entstehen dort Irrlichter. - Wer durch diese Nebel wandert, wird von Visionen geplagt und - in die Irre geleitet. - - - - - Dieses mächtige Ritual öffnet ein Tor in die Elementarebene der - Hitze. Eine grosse Dürre kommt über das Land. Bauern, Tiere und - Pflanzen der Region kämpfen um das nackte Überleben, aber eine - solche Dürre überlebt wohl nur die Hälfte aller Lebewesen. - Der Landstrich kann über Jahre hinaus von den Folgen einer - solchen Dürre betroffen sein. - - - - - Mit Hilfe dieses aufwändigen Rituals läßt der Druide einen Teil seiner Kraft - dauerhaft in den Boden und die Wälder der Region fliessen. Dadurch wird - das Gleichgewicht der Natur in der Region für immer verändert, und in - Zukunft werden nur noch die anspruchsvollen, aber kräftigen - Mallorngewächse in der Region gedeihen. - - - - - Dieses Ritual beschört einen großen Wasserelementar aus den - Tiefen des Ozeans. Der Elementar erzeugt einen gewaltigen - Strudel, einen Mahlstrom, welcher alle Schiffe, die ihn passieren, - schwer beschädigen kann. - - - - - Mit Hilfe dieses Zaubers kann sich der Magier permanent in einen - mächtigen Wyrm verwandeln. Der Magier behält seine Talente und - Möglichkeiten, bekommt jedoch die Kampf- und Bewegungseigenschaften - eines Wyrms. Der Odem des Wyrms wird sich mit steigendem Magie-Talent - verbessern. Der Zauber ist sehr kraftraubend und der Wyrm wird einige - Zeit brauchen, um sich zu erholen. - - - - - Mit Hilfe dieses magischen Gesangs versetzt der Magier eine ganze - Region in Aufruhr. Rebellierende Bauernhorden machen jedes Besteuern - unmöglich, kaum jemand wird mehr für Gaukeleien Geld spenden und - es können keine neuen Leute angeworben werden. Nach einigen Wochen - beruhigt sich der Mob wieder. - - - - - Der Magier kann mit Hilfe dieses Zaubers aus der Astral- in die - materielle Ebene blicken und die Regionen und Einheiten genau - erkennen. - - - - - Einem erfahrenen Magier wird irgendwann auf seinen Wanderungen ein - ungewöhnliches Exemplar einer Gattung begegnen, welches sich dem - Magier anschließen wird. - - - - - Dieses kräftezehrende Ritual beschwört mit Hilfe einer Kugel aus - konzentriertem Laen einen gewaltigen Erdelementar und bannt ihn - in ein Gebäude. Dem Elementar kann dann befohlen werden, das - Gebäude mitsamt aller Bewohner in eine Nachbarregion zu tragen. - Die Stärke des beschworenen Elementars hängt vom Talent des - Magiers ab: Der Elementar kann maximal [Stufe-12]*250 Größeneinheiten - große Gebäude versetzen. Das Gebäude wird diese Prozedur nicht - unbeschädigt überstehen. - - - - Dieses Amulett in Gestalt einer orkischen Matrone - unterdrückt den Fortpflanzungstrieb eines einzelnen Orks sehr - zuverlässig. - Ein Ork mit Amulett der Keuschheit wird sich nicht mehr vermehren. - - - Dieser Zauber ermöglicht dem Magier, gezielt eine - bestimmte Verzauberung einer Einheit, eines Schiffes, Gebäudes oder auch - der Region aufzulösen. - This spell allows a magician to remove a specific - enchantment from a unit, ship, bulding or region. - - - Ein Schauer von Meteoren regnet über das Schlachtfeld. - A meteor shower rains down on the battlefield. - - - 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. - 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. - - - Mit dieser Formel bindet der Magier auf ewig die - Kräfte - der Erde in die Mauern des Gebäudes. Ein solchermaßen verzaubertes - Gebäude - ist gegen den Zahn der Zeit geschützt und benötigt keinen Unterhalt - mehr. - With this spell, the magician binds the power of the - earth into the walls of a building for all eternity. Such a building is - immune to the sands of time and needs no maintenance cost. - - - Ein Magier, der sich in der astralen Ebene befindet, - kann mit Hilfe dieses Zaubers andere Einheiten zu sich holen. Der Magier - kann (Stufe-3)*15 GE durch das kurzzeitig entstehende Tor schicken. Ist - der Magier erfahren genug, den Zauber auf Stufen von 13 oder mehr zu - zaubern, kann er andere Einheiten auch gegen ihren Willen auf die - andere - Ebene zwingen. - A magician in the astral plane can summon units from - the - material world. The magician can bring (level-3)*15 GE through the - temporary portal. If he is experienced enough to cast the spell at at - least level 13, he can even summon units against their will. - - - Ein Magier, welcher sich in der materiellen Welt - befindet, kann er mit Hilfe dieses Zaubers Einheiten aus der - angrenzenden - Astralwelt herbeiholen. Ist der Magier erfahren genug, den Zauber auf - Stufen von 13 oder mehr zu zaubern, kann er andere Einheiten auch gegen - ihren Willen in die materielle Welt zwingen. - A magician in the material world can summon units from - the adjacent part of the astral plane. If he is experienced enough to - cast - the spell at at least level 13, he can even summon units against their - will. - - - Mit Hilfe dieses Zaubers kann der Magier einem anderen - Magier seine Aura gegen dessen Willen entziehen und sich selber - zuführen. - Aided by this spell, a magician can steal another - magician's aura against his will. - - - Diese magischen Runen bringen ein Boot oder Langboot - für - eine Woche zum fliegen. Damit kann dann auch Land überquert werden. Die - Zuladung von Langbooten ist unter der Einwirkung dieses Zaubers auf 100 - Gewichtseinheiten begrenzt. Für die Farbe der Runen muss eine spezielle - Tinte aus einem Windbeutel und einem Schneekristall angerührt werden. - These magic runes allow a boat or longboat to fly for - a - week. The boat can only carry 100 weight units. The enchanted ink's - components include a windbag and a snowcrystal petal. - - - Diese praktische Anwendung des theoretischen Wissens um - Raum und Zeit ermöglicht es, den Zeitfluß für einige Personen zu - verändern. Auf diese Weise veränderte Personen bekommen für einige - Wochen doppelt soviele Bewegungspunkte und doppelt soviele Angriffe - pro Runde. - Abstract theories of space and time at last find - practical application in this spell which warps the very fabric of - time around a person. Such a person has twice as many movement points - and doubles their attacks per round for a few weeks. - - - Dieser Zauber läßt eine Welle aus purer Kraft über die - gegnerischen Reihen hinwegfegen. Viele Kämpfer wird der Schock so - benommen machen, daß sie für einen kurzen Moment nicht angreifen - können. - A wave of pure force spreads out from the magician, - crashing into the enemy ranks. Many warriors are thrown off balance and - are briefly unable to attack. - - - Mit diesem Zauber kann der Magier eine Zone der - astralen - Schwächung erzeugen, ein lokales Ungleichgewicht im Astralen Feld. - Dieses - Zone wird bestrebt sein, wieder in den Gleichgewichtszustand zu - gelangen. - Dazu wird sie jedem in dieser Region gesprochenen Zauber einen Teil - seiner Stärke entziehen, die schwächeren gar ganz absorbieren. - This spell allows a magician to create a local - instability in the astral field. This zone needs to return to its - equilibrium, soaking up part of the power of all spells cast in the - region - - or even all of some of the weaker ones. - - - Dieser Zauber ermöglicht dem Magier, Verzauberungen - einer Einheit, eines Schiffes, Gebäudes oder auch der Region aufzulösen. - This spell lets a magician destroy spells on a ship, - building or region. - - - Dieser Zauber verstärkt die natürliche - Widerstandskraft - gegen Magie. Eine so geschützte Einheit ist auch gegen Kampfmagie - weniger - empfindlich. Pro Stufe reicht die Kraft des Magiers aus, um 5 Personen - zu - schützen. - This spell enhances natural magic resistence. - Protected - units are less vulnerable to battle magic. The spell protects 5 people - per - level. - - - Alte arkane Formeln ermöglichen es dem Magier, sich - und - andere in die astrale Ebene zu schicken. Der Magier kann (Stufe-3)*15 GE - durch das kurzzeitig entstehende Tor schicken. Ist der Magier erfahren - genug, den Zauber auf Stufen von 11 oder mehr zu zaubern, kann er andere - Einheiten auch gegen ihren Willen auf die andere Ebene zwingen. - Ancient arcane formulae permit the magician to - transport - himself or other units into the astral plane. The magician can transport - (level-3) * 15 GE through the transient portal. If the magician is - experienced enough to cast level 11 spells, he can also transport units - against their will. - - - Der Magier konzentriert sich auf die Struktur der - Realität und kann so die astrale Ebene verlassen. Er kann insgesamt - (Stufe-3)*15 GE durch das kurzzeitig entstehende Tor schicken. Ist der - Magier erfahren genug, den Zauber auf Stufen von 11 oder mehr zu - zaubern, - kann er andere Einheiten auch gegen ihren Willen auf die andere Ebene - zwingen. - By concentrating on the structure of reality, the - magician can breach it and thus briefly make a gateway to leave the - astral - plane. He can transport up to (level-3)*15 GE through the portal. If the - magician is able to cast at at least level 11, he can even transport - other - units against their will. - - - Mit diesem Spruch kann der Magier versuchen, die - Verzauberungen - eines einzelnen angegebenen Objekts zu erkennen. Von - allen Sprüchen, - die seine eigenen Fähigkeiten nicht überschreiten, wird - er einen - Eindruck ihres Wirkens erhalten können. Bei stärkeren - Sprüchen - benötigt er ein wenig Glück für eine gelungene Analyse. - With this spell the magician can try to identify the - enchantments of - a single object. He will get an impression of the - operation of all - spells that don't exceed his own capabilities. For more - powerful - spells he will need some luck for a successful analysis. - - - Dieser Zauber wird die gesamte Ausrüstung der - Zieleinheit für - einige Zeit vor den Blicken anderer verschleiern. Der - Zauber - schützt nicht vor Dieben und Spionen. - This spell will hide the whole equipment of a target - unit from the - looks of others. It will not protect against thieves or - spies. - - - Dieser Zauber legt ein antimagisches Feld um die Magier der Feinde - und behindert ihre Zauber erheblich. Nur wenige werden die Kraft - besitzen, das Feld zu durchdringen und ihren Truppen in der Schlacht - zu helfen. - This spell creates an antimagic field around the mages of the enemies - and considerably hinders their spells. Only few will have the power to - break through the field and be able to help their troops in battle. - - - Dieser Zauber verhindert, dass ein Teil der sonst im Kampf zerstörten - Gegenstände beschädigt wird. Die Verluste reduzieren sich um 5% pro - Stufe des Zaubers bis zu einem Minimum von 25%. - This spell prevents damage to a portion of the items that would - otherwise be lost in battle. The loss of items is reduced by 5% for - every level of the spell, up to a minimum of 25%. - - - - Dieses Lied zähmt selbst den wildesten - Ork und macht ihn friedfertig und sanftmütig. Jeder - Gedanke, dem Sänger zu schaden, wird ihm entfallen. - Unbehelligt kann der Magier in eine Nachbarregion - ziehen. - This little melody calms even the - wildest orc to a gentle and serene creature who will not - even think about putting the singer to harm. The magician - may travel to a neighboring region without being - harassed by annoying troublemakers. - - - Nicht nur der Feldscher kann den - Verwundeten einer Schlacht helfen. Die Barden kennen - verschiedene Lieder, die die Selbstheilungskräfte des - Körpers unterstützen. Dieses Lied vermag Wunden zu - schließen, gebrochene Knochen zu richten und selbst - abgetrennte Glieder wieder zu regenerieren. - The field medic isn't the only one - capable of tending the wounds of battle. The bards know - a number of magic melodies to enhance the natural - healing process of the body. This song is able to close - wounds, mend fractured bones and even regenerate lost - lims. - - - Ein gar machtvoller Gesang aus den - Überlieferungen der Katzen, der tief in die Herzen der - Feinde dringt und ihnen Mut und Hoffnung raubt. Furcht - wird sie zittern lassen und Panik ihre Gedanken - beherrschen. Voller Angst werden sie versuchen, den - gräßlichen Gesängen zu entrinnen und fliehen. - This antique, powerful song, passed - down by the cats, will penetrate the hearts of the enemy - and bereave them of courage and hope. Both their minds - and bodies will be ruled by panic. Shivering with fear, - they will flee from the dreadful chants and try to make - their escape. - - - Aus den uralten Gesängen der Katzen - entstammt dieses magisches Lied, welches vor einem - Kampfe eingesetzt, einem entscheidende strategische - Vorteile bringen kann. Wer unter den Einfluss dieses - Gesangs gelangt, der wird seiner Umgebung nicht achtend - der Melodie folgen, sein Geist wird verwirrt und - sprunghaft plötzlichen Eingebungen nachgeben. So sollen - schon einst wohlgeordnete Heere plötzlich ihre Schützen - weit vorne und ihre Kavallerie bei den Lagerwachen - kartenspielend wiedergefunden haben (oder ihren Anführer - schlafend im lange verlassenen Lager, wie es in den - Großen Kriegen der Alten Welt wirklich geschehen sein - soll). - If is used before battle, this chant, - taken from the ancient tunes of the cats, might give you - the critical tactical advantage. Those under the spell's - influence will act uncoordinated and inconsequent due to - the nonsensical ideas planted into their minds through - the melody. So it is supposed to have come to pass that - well-organized armies found their archers up at the - front (while the cavalry was back at the camp playing - cards) or that even a famous general overslept a battle - in his tent, as tale-tellers claim it really happened - during the Great Wars in the Old World. - - - Dieser alte Schlachtengesang hebt die - Moral der eigenen Truppen und und hilft ihnen auch der - angsteinflößenden Aura dämonischer und untoter Wesen zu - widerstehen. Ein derartig gefestigter Krieger wird auch - in schwierigen Situationen nicht die Flucht ergreifen - und sein überlegtes Verhalten wird ihm manch Vorteil in - der Verteidigung geben. - This ancient battle chant lifts the - spirit of your troops and helps them withstand even the - fear-inspiring aura of demonic and undead beings. A - fighter thus fortified against evil will not flee even - in the face of terror, and his defenses will be strengthened. - - - Mit Hilfe dieses Zaubers kann der - Magier eigene Aura im Verhältnis 2:1 auf einen anderen - Magier des gleichen Magiegebietes übertragen. - This spell enables the wizard to - transfer aura at a rate of 2:1 to another sorcerer of - the same school of magic. - - - Alle lebenden Wesen haben ein eigenes - individuelles Lebenslied. Nicht zwei Lieder gleichen - sich, auch wenn sich alle Lieder einer Art ähneln. Jeder - Zauber verändert dieses Lied auf die eine oder andere - Art und gibt sich damit zu erkennen. Dieser Gesang - hilft, jene Veränderungen im Lebenslied einer Person zu - erlauschen, welche magischer Natur sind. Alle - Verzauberungen, die nicht stärker maskiert sind als Eure - Fähigkeit, werdet Ihr so entschlüsseln und demaskieren - können. - Each and every living being has its - own, individual 'life-song'. No two of these songs are - alike, even though songs of creatures of the same - species are similar. Every spell alters this song of - life in one way or the other and this can be identified. - By casting this spell, the bard can detect all those - magic variations in a person's 'life-song'. You will be - able to decipher all enchantments or spells, which - aren't disguised beyond your capability. - - - Dieser schrille Gesang hallt über das - ganze Schlachtfeld. Die besonderen Dissonanzen in den - Melodien machen es Magier fast unmöglich, sich auf ihre - Zauber zu konzentrieren. - The screeching sounds of this melody - can be heard across the whole battlefield. Wizards - exposed to these special dissonances find it nearly - impossible to concentrate on their spells. - - - Die verzauberte Einheit beginnt - hemmungslos zu plappern und erzählt welche Talente sie - kann, was für Gegenstände sie mit sich führt und sollte - sie magisch begabt sein, sogar welche Zauber sie - beherrscht. Leider beeinflußt dieser Zauber nicht das - Gedächnis, und so wird sie sich im nachhinein wohl - bewußt werden, dass sie zuviel erzählt hat. - The persons of the bewitched unit - starts to babble without control about what it is said, - speaking about their talents, the objects they carry or - wear and if the unit is a magician, he or she will even list - the spells they know. Unfortunately, this spell does not - influence the memory of the subjects and afterwards, the - enchanted will realize that they probably talked too - much. - - - Man befeuchte einen kluftfreien Block - aus feinkristallinen Gestein mit einer Phiole des - Lebenswassers bis dieses vollständig vom Gestein - aufgesogen wurde. Sodann richte man seine Kraft auf die - sich bildende feine Aura des Lebens und forme der - ungebundenen Kraft ein Gehäuse. Je mehr Kraft der Magier - investiert, desto mehr Golems können geschaffen werden, - bevor die Aura sich verflüchtigt. Jeder Golem hat jede - Runde eine Chance von 10 Prozent zu Staub zu zerfallen. - Gibt man den Golems die Befehle MACHE BURG oder MACHE - STRASSE, so werden pro Golem 4 Steine verbaut und der - Golem löst sich auf. - 'Take a flawless block of crystaline - stone and humidify it with a vial of Water Of Life until - the potion has been soaked up completely. Then focus - your power on the forming aura of life and shape a - container for the unbound forces'. The more power a magician - invests, the more golems can be created before the aura - dissipates. Every week, there is a 10 percent chance - that the golem will crumble to dust. If you command a - golem to 'MAKE CASTLE' or 'MAKE ROAD', it will turn - itself into 4 stones that it uses in construction, and - disintegrate afterwards. - - - Je mehr Kraft der Magier investiert, - desto mehr Golems können geschaffen werden. Jeder Golem - hat jede Runde eine Chance von 15 Prozent zu Staub zu - zerfallen. Gibt man den Golems den Befehl MACHE - SCHWERT/BIHÄNDER oder MACHE - SCHILD/KETTENHEMD/PLATTENPANZER, so werden pro Golem 4 - Eisenbarren verbaut und der Golem löst sich auf. - The more power a magician invests, the - more golems can be created before the aura dissipates. - Each golem has a 15% chance per week to turn to dust. If - you command a golem to 'MAKE SWORD/MAKE CLAYMORE' or - 'MAKE SHIELD/CHAINMAIL/PLATEMAIL',it will work 5 iron - ingots and disintegrate afterwards. - - - Wo sonst aus einem - Stecken nur ein Baum sprießen konnte, so treibt nun jeder - Ast Wurzeln. - Every branch becomes a sturdy - oak where before only one could be grown from a log. - - - Mit diesem Ritual wird eine dunkle - Gewitterfront beschworen, die sich - unheilverkündend über der Region auftürmt. Der - magische Regen wird alles Erz rosten lassen. - Eisenwaffen und Rüstungen werden schartig und rostig. - Die Zerstörungskraft des - Regens ist von der investierten Kraft des - Magiers abhängig. Für jede Stufe können bis zu - 10 Eisenwaffen betroffen werden. Ein Ring der - Macht verstärkt die Wirkung wie eine zusätzliche - Stufe. - This ritual conjurs up a dark - thunderstorm that affects a whole region. The - magic rain will let rust any ore. Iron weapons and - armor will get rusty. The exact number of - items affected by the rain depends on the - ammount of power invested by the magician. Up to ten - weapons can be destroyed per level - a Ring Of - Power increases the effect like an additional - level. - - - Dieser Zauber ermöglicht es dem Magier - Insekten auf magische Weise vor der lähmenden - Kälte der Gletscher zu bewahren. Sie können - Gletscher betreten und dort normal agieren. Der - Spruch wirkt auf Stufe*10 Insekten. Ein Ring der - Macht erhöht die Menge der verzauberbaren - Insekten zusätzlich um 10. - This spell enables the druid to - magically protect insects from the paralysing - cold of a glacier. Under the effect of this - spell, insects are able to enter glaciers and - act normally there. Ten insects per level can be - protected in this way. A Ring Of Power increases - the number by additional ten. - - - Im Kampf ruft der Magier die - Elementargeister der Kälte an und bindet sie an - sich. Sodann kann er ihnen befehlen, den Gegner - mit Hagelkörnern und Eisbrocken zuzusetzen. - During a battle the druid calls the - Elemental Spirits Of Cold and binds them to - himself. Then he commands them to attack his - foes with hail and ice missiles. - - - Erschafft einen Wächtergeist, der - in Gletschern und Bergen Eisen- und Laenabbau durch - nichtalliierte Parteien (HELFE BEWACHE) verhindert, - solange er die Region bewacht. Der Bergwächter ist - an den Ort der Beschwörung gebunden. - Creates a guardian spirit on a - mountain or glacier that keeps all factions that - are not allied (HELP GUARD) from mining iron or - laen as long as it guards the region. The - Mountain Guardian is bound to the location where - it has been summoned. - - - Durch Ausführung dieser Rituale ist - der Magier in der Lage einen mächtigen - Erdelementar zu beschwören. Solange dieser in - den Boden gebannt ist, wird kein Regen die Wege - aufweichen und kein Fluß Brücken zerstören - können. Alle Reisende erhalten damit die - gleichen Vorteile, die sonst nur ein ausgebautes - gepflastertes Straßennetz bietet. Selbst Sümpfe - und Gletscher können so verzaubert werden. Je - mehr Kraft der Magier in den Bann legt, desto - länger bleibt die Straße bestehen. - By performing these rituals the druid - is able to summon a powerful earth elemental. As - long as this elemental remains bound to a - region, no rain can turn a path into mud and no - river can destroy a bridge. All travelers in - this region gain the same advantages as if they - were travelling on a road. Even swamps and - glaciers can be enchanted in this way. The more - power the druid invests, the longer the roads - remain intact. - - - Die Anrufung der Elementargeister des - Windes beschwört plötzliche Windböen, kleine - Windhosen und Luftlöcher herauf, die die - gegnerischen Schützen behindern werden. - Calling the Elemental Spirits Of Wind - conjurs up sudden breezes, small whirlwinds and - minor turbulences that will hinder enemy - archers. - - - Diese Ritual verstärkt die Wirkung des - magischen Trankes um ein vielfaches. Wo sonst aus einem - Stecken nur ein Baum sprießen konnte, so treibt nun jeder - Ast Wurzeln. - This ritual greatly increases the - effect of the potion. Now every branch becomes a mallorn - tree where before only one could be grown from a log. - - - Der Magier zwingt mit diesem Ritual - die Elementargeister des Wassers in seinen - Dienst und bringt sie dazu, das angegebene - Schiff schneller durch das Wasser zu tragen. - Zudem wird das Schiff nicht durch ungünstige - Winde oder Strömungen beeinträchtigt. - While being aboard a ship, the druid - uses this ritual to force the Elemental Spirits - Of Water to serve him and commands them to carry - the ship across the water at a higher speed. In - addition, the ship will not be affected by - unfavourable winds or currents. - - - Nicht nur der Feldscher kann den - Verwundeten einer Schlacht helfen. Druiden - vermögen mittels einer Beschwörung der - Elementargeister des Lebens Wunden zu schließen, - gebrochene Knochen zu richten und selbst - abgetrennte Glieder wieder zu regenerieren. - Combat medics are not the only ones - who can help those who got injured during a - battle. Druids are, with the help of a summons - of - the Elemental Spirits Of Life, able to heal - wounds, mend broken bones or even regenerate - separated limbs as well. - - - Diese Beschwörung öffnet ein Tor in - die Ebene der Elementargeister des Windes. - Sofort erheben sich in der Umgebung des Tors - starke Winde oder gar Stürme und behindern alle - Schützen einer Schlacht. - This summons opens a gate to the plane - of Elemental Spirits Of Wind. Immediately, - strong winds or even storms will rise near the - gate and hinder all archers during a battle. - - - Dieses Ritual beschwört einige - Elementargeister der Magie und schickt sie in - die Reihen der feindlichen Magier. Diesen wird - das Zaubern für die Dauer des Kampfes deutlich - schwerer fallen. - This ritual summons some Elemental - Spirits Of Magic and sends them into the ranks - of the enemy mages. Casting spells will be much - harder for them during the battle. - - - Mit Hilfe dieses Zaubers kann der - Magier eigene Aura im Verhältnis 2:1 auf einen - anderen Magier des gleichen Magiegebietes - übertragen. - The caster can transfer aura at a - ratio of 2:1 to another member of the same - school of magic with the help of this spell. - - - Der Druide beschwört mit diesem Ritual - einen Elementargeist der Erde und bringt ihn - dazu, die Erde erbeben zu lassen. Dieses - Erdbeben wird alle Gebäude in der Region - beschädigen. - With this ritual the druid summons an - Elemental Spirit Of Earth that brings the ground - to shake. This earthquake damages all buildings - in the target region. - - - Die Beschwörung von Elementargeistern - der Stürme ist ein uraltes Ritual. Der Druide - bannt die Elementare in die Segel der Schiffe, - wo sie helfen, das Schiff mit hoher - Geschwindigkeit über die Wellen zu tragen. Je - mehr Kraft der Druide in den Zauber investiert, - desto größer ist die Zahl der Elementargeister, - die sich bannen lassen. Für jedes Schiff wird - ein Elementargeist benötigt. - Calling the Elemental Spirits Of Storm - is an ancient ritual. The druid binds the - elementals to a ship's sails where they can help - to carry the vessel across the waves at an - amazing speed. The more power the druid invests, - the greater is the number of spirits bound. Each - ship needs an own spirit. - - - Mit diesem Spruch erzeugt man ein Runenschwert. Die - Klinge des schwarzen Schwertes ist mit alten, magischen Runen verziert, - und ein seltsames Eigenleben erfüllt die warme Klinge. Um es zu - benutzen, - muss man ein Schwertkämpfer von beachtlichem Talent (7) sein. Der - Träger - des Runenschwertes erhält einen Talentbonus von +4 im Kampf und wird so - gut wie immun gegen alle Formen von Magie. - This spell creates a magical sword. It requires a - skill - of at least 7, but adds +4 to the combat skill of its' owner as well as - making them almost immune against magical attacks. - - - Dieser Beutel umschließt eine kleine Dimensionsfalte, - in - der bis zu 200 Gewichtseinheiten transportiert werden können, ohne dass - sie auf das Traggewicht angerechnet werden. Pferde und andere Lebewesen - sowie besonders sperrige Dinge (Wagen und Katapulte) können nicht in dem - Beutel transportiert werden. Auch ist es nicht möglich, einen - Zauberbeutel in einem anderen zu transportieren. Der Beutel selber wiegt - 1 - GE. - This bag encloses a dimensional rift in which up to - 200 - units of weight can be carries. Horses and other large objects cannot be - put into the bag. The bag itself has a weight of 1. - - - Dieses mächtige Ritual erschafft einen Ring der Macht. - Ein Ring der Macht erhöht die Stärke jedes Zaubers, den sein Träger - zaubert, als wäre der Magier eine Stufe besser. - A ring of power adds +1 to the power of each spell - cast - by its' wearer. - - - Der Spruch ermöglicht es einem Magier, - ein Amulett des Wahren Sehens zu erschaffen. Das - Amulett erlaubt es dem Träger, alle Einheiten, - die durch einen Ring der Unsichtbarkeit - geschützt sind, zu sehen. Einheiten allerdings, - die sich mit ihrem Tarnungs-Talent verstecken, - bleiben weiterhin unentdeckt. - This spell enables the caster to - create an Amulet Of True Sight. Wearing such an - amulet, a person can discover anyone wearing a - Ring of Invisibility. Anyway, units concealed by - the use of their stealth skill will remain - undiscovered. - - - Mit Hilfe dieses Zauber entzieht der Magier einem - Quarzkristall all seine magischen Energien. Der Kristall wird dann, wenn - er zu feinem Staub zermahlen und verteilt wird, die beim Zaubern - freigesetzten magischen Energien aufsaugen und die Kraft aller Zauber - reduzieren, welche in der betreffenden Woche in der Region gezaubert - werden. - This spell creates a portable crystal of antimagic - which can be used by anybody to reduce or even eliminate the power of - all spells cast in the region during the same week. - - - Die berühmte Bardin Miriam bhean'Meddaf war bekannt - für ihr außergewöhnliches Geschick mit der Harfe. Ihre Finger sollen - sich so schnell über die Saiten bewegt haben, das sie nicht mehr - erkennbar waren. Dieser Zauber, der recht einfach in einen Silberring - zu bannen ist, bewirkt eine um das zehnfache verbesserte - Geschicklichkeit und Gewandheit der Finger. (Das soll sie auch an - anderer Stelle ausgenutzt haben, ihr Ruf als Falschspielerin war - berüchtigt). Handwerker können somit das zehnfache produzieren, - und bei einigen anderen Tätigkeiten könnte dies ebenfalls von Nutzen - sein. - The famous bard Mirim was known for exceptionally - limber - play of the harp. Her spell, which is easy to ban into a little silver - ring, increases the wearer's dexterity by a factor of ten, which is siad - to be useful to both craftsmen and shady natures. - - - Mit diesem Spruch kann der Zauberer - einen Ring der Unsichtbarkeit erschaffen. Der - Träger des Ringes wird für alle Einheiten - anderer Parteien unsichtbar, egal wie gut ihre - Wahrnehmung auch sein mag. In einer unsichtbaren - Einheit muss jede Person einen Ring tragen. - With this spell the caster can create - a Ring Of Invisibility. The wearer of this ring - will be invisible to all units of other - factions, no matter how good their perception - skill may be. In an invisible unit, each person - must wear a Ring Of Invisibility. - - - Mit dieser Formel bindet der Magier - auf ewig die Kräfte der Erde in die Mauern der - Burg, in der er sich gerade befindet. Weder - magisch noch mit schwerem Geschütz können - derartig gestärkte Mauern zerstört werden, und - auch das Alter setzt ihnen weniger zu. Das - Gebäude bietet sodann auch einen besseren Schutz - gegen Angriffe mit dem Schwert wie mit Magie. - With this spell the druid eternally - binds the powers of earth to the walls of the - castle in which he currently is. No magic and no - ballistic attacks will ever be able to destroy a - wall that has been fortified in this way and the - castle will also be less affected by aging. In - addition, the building will provide a better - protection against attacks by sword or by magic. - - - Nicht wenige Druiden freunden sich im - Laufe ihres Lebens in der Natur mit den ältesten - Freunden der großen Völker an. Sie erlernen, mit - einem einzigen heulenden Ruf viele ihrer Freunde - herbeizurufen, um ihnen im Kampf beizustehen. - During their life in the wilderness, - many druids make friends with the wolves who are - the oldest friends of the great races. They - learn to call many of them with a single howl to - aid them in combat. - - - Dieser schwierige, aber effektive - Kampfzauber benutzt die Elementargeister des - Steins, um eine Reihe von Gegnern für die Dauer - des Kampfes in Stein zu verwandeln. Die - betroffenen Personen werden nicht mehr kämpfen, - können jedoch auch nicht verwundet werden. - This complicated but effective spell - uses the Elemental Spirits Of Stone to turn a - number of enemies to stone for the duration of - combat. The affected persons won't be able to - fight any more, but they can't be wounded - either. - - - Mit dieser Formel bindet der Magier zu - Beginn eines Kampfes einige Elementargeister des - Fels in die Mauern des Gebäudes, in dem er sich - gerade befindet. Das Gebäude bietet sodann einen - besseren Schutz gegen Angriffe mit dem Schwert - wie mit Magie. - At the beginning of a battle, the - magician binds some Elemental Spirits Of Rock to - the walls of the builing in which he currently - is. The structure will then provide a better - protection against attacks by sword or by magic. - - - Wie die alten Lehren der Druiden - berichten, besteht das, was die normalen Wesen - Magie nennen, aus Elementargeistern. Der Magier - beschwört und bannt diese in eine Form, um den - gewünschten Effekt zu erzielen. Dieses Ritual - nun vermag es, in diese Welt gerufene - Elementargeister zu vertreiben, um so ein Objekt - von Magie zu befreien. - Old legends of the druids say that - what normal people call 'magic' consists of - elemental spirits. A magician summons these - spirits and binds them to various forms to - achieve the desired effects. This ritual is able - to expel any elemental spirits that have been - summoned to this world and thereby dispels any - magic on the target. - - - Große Macht liegt in Orten, an denen - das Leben pulsiert. Der Druide kann diese Kraft - sammeln und so ein Tor in die Welt der - Geistwesen erschaffen. Der Druide kann dann - Stufe*5 Gewichtseinheiten durch das Tor - entsenden. - A great power lies within those places - that are pulsing with life. A druid can focus - this power and thereby create a gate into the - World Of Spirits. He can then send level*5 - weight units of living or dead matter through - the gate. - - - Ein Druide, den es in die Welt der - Geister verschlagen hat, kann mit Hilfe dieses - Zaubers Stufe*5 Gewichtseinheiten in einen Wald - auf der materiellen Welt zurückschicken. - A druid who has traveled to the World - Of Spirits can use this spell to send level*5 - weight units of living or dead matter back to a - forest in the material world. - - - Dieses Ritual beschwört verschiedene - Naturgeister in den Boden der Region, welche - diese fortan bewachen. In einer so gesegneten - Region werden niemals wieder die Toten ihre - Gräber verlassen, und anderswo entstandene - Untote werden sie wann immer möglich meiden. - This ritual binds various rural - spirits to a specific territory to guard the - land. In a region blessed in this way the dead - won't ever rise from their graves again. - Existing undead also shun the sacred grounds and - will avoid entering the protected area whenever - possible. - - - Der Druide nehme etwas präpariertes - Leder, welches er in einem großen Ritual der - Reinigung von allen unreinen Geistern befreie, - und binde dann einige kleine Geister der Luft - und des Wassers in das Material. Aus dem so - vorbereiteten Leder fertige er nun ein kleines - Beutelchen, welches in ihm aufbewahrte Kräuter - besser zu konservieren vermag. - The druid takes some specially - prepared leather and performes a great ritual - during which the leather is cleansed of all - impure spirits. Then he binds some minor spirits - of air and water to the material. After - completing this process, the druid works the - enchanted leather into a small pouch which is - suitable to contain herbs, for it is able to - preserve them for a long time and prevents rot. - - - Mit Hilfe dieses Zaubers weckt der - Druide die in den Wälder der Region - schlummernden Ents aus ihrem äonenlangen Schlaf. - Die wilden Baumwesen werden sich ihm anschließen - und ihm beistehen, jedoch nach einiger Zeit - wieder in Schlummer verfallen. - With the help of this spell the druid - awakens the ents who are slumbering in the - forests of a region from aeons of sleep. These - strange tree-creatures will join him and aid his - cause, but after a while they will sink back - into their slumber. - - - Einem erfahrenen Druidem wird - irgendwann auf seinen Wanderungen ein - ungewöhnliches Exemplar einer Gattung begegnen, - welches sich dem Druiden anschließen wird. - Once during his travels, the seasoned - druid will meet an extraordinary creature of its - species that will join him. - - - Dieses Ritual segnet einen Steinkreis, - der zuvor aus Steinen und etwas Holz gebaut - werden muss. Die Segnung des Druiden macht aus - dem Kreis eine mächtige Stätte magischen - Wirkens, die Schutz vor Magie und erhöhte Aura- - Regeneration bewirkt. Man sagt, Jungfrauen seien - in der Umgebung von Steinkreisen seltsame Wesen - begegnet. - This ritual blesses a circle of stones - that has to be constructed from stones and some - wood before. The druid's blessing turns the - circle into a place of great magic that is - suitable for rituals of all kinds. It protects - from hostile magic and improves aura - regeneration. Virgins are said to have been - visited by strange creatures in the vicinity of - these places. - - - Das Ziel des Zauberers wird von einer - harmlosen Verwünschung heimgesucht. - The target of this spell becomes - subject to a harmless curse. - - - Dieses vor dem Kampf zu zaubernde Ritual gibt den - eigenen Truppen einen zusätzlichen Bonus auf ihre Rüstung. Jeder - Treffer reduziert die Kraft des Zaubers, so dass der Schild sich - irgendwann im Kampf auflösen wird. - Performing this ritual before going into battle gives - your troups an additional bonus to their armor. Every hit reduces the - energy of the spell, dissolving it at some point during battle. - - - Der Zauberer schleudert fokussiertes - Chaos in die Reihen der Gegner. Das ballförmige - Chaos wird jeden verwunden, den es trifft. - The sorcerer hurls a ball of - concentrated chaos into the ranks of his - enemies. It will seriously hurt anyone who gets - hit. - - - Der Magier öffnet seinen Geist den - Sphären des Chaos und wird so für einige Zeit - über mehr magische Kraft verfügen. Doch die - Hilfe der Herren der Sphären hat seinen Preis, - und so wird die Phase der Macht abgelöst von - einer Phase der Schwäche. - The sorcerer opens his mind to the - Spheres Of Chaos so that he can access a greater - ammount of magical power for a while. But the - help of the Chaos Lords has its price - and so - the period of power will be followed by a period - of weakness. - - - Mit diesem Ritual kann der Magier - einen Teil seiner Lebensenergie opfern, um dafür - an magischer Kraft zu gewinnen. Erfahrene - Ritualmagier berichten, das sich das Ritual, - einmal initiiert, nur schlecht steuern ließe und - die Menge der so gewonnenen Kraft stark - schwankt. So steht im 'Buch des Blutes' - geschrieben: 'So richte Er aus das Zeichen der - vier Elemente im Kreis des Werdens und Vergehens - und Weihe ein jedes mit einem Tropfen Blut. - Sodann begebe Er in der Mitten der Ewigen Vierer - sich und lasse Leben verrinnen, auf das Kraft - geboren werde.' - With this ritual the sorcerer can - sacrifice part of his life force in order to - gain raw astral power. Experienced mages report - that this ritual, once started, is hard to - control and that the ammount of power gained in - this way varies. - - - In diesem blutigen Ritual opfert der - Magier vor der Schlacht ein Neugeborenes vor den - Augen seiner Armee. Die so gerufenen Blutgeister - werden von den Soldaten Besitz ergreifen und sie - in einen Blutrausch versetzen. - During this bloody ritual the sorcerer - sacrifices a newborn child before a battle right - in front of his army. In this way he attracts - spirits of blood that will take control of the - soldiers who are present and force them into a - blood frenzy. - - - Dieser heimtückische Fluch - beeinträchtigt die magischen Fähigkeiten des - Opfers erheblich. Eine chaosmagische Zone um das - Opfer vermindert seine Konzentrationsfähigkeit - und macht es ihm sehr schwer Zauber zu wirken. - This wicked curse affects the magical - abilities of the target. A field of raw chaos - magic around the target lessens its - concentration and makes it very hard to cast any - spells. - - - Nächtelang muss der Schwarzmagier - durch die Friedhöfe und Gräberfelder der Region - ziehen um dann die ausgegrabenen Leichen beleben - zu können. Die Untoten werden ihm zu Diensten - sein, doch sei der Unkundige gewarnt, dass die - Beschwörung der Mächte des Todes ein - zweischneidiges Schwert sein kann. - For many nights the sorcerer has to - roam the graveyards and former battlefields of a - region in order to find corpses to animate. The - Undead will serve his will, but beware! Dealing - with the mysteries of unlife can be a dangerous - thing. - - - Mit diesem Ritual wird eine dunkle - Gewitterfront beschworen, die sich - unheilverkündend über der Region auftürmt. Der - magische Regen wird alles Erz rosten lassen und - so viele Waffen des Gegners zerstören. - This ritual conjurs up a dark - thunderstorm that affects a whole region. The - magic rain will let rust any ore and thus - destroy many weapons of the enemy. - - - Mit Hilfe dieses Zaubers kann der - Magier eigene Aura im Verhältnis 2:1 auf einen - anderen Magier des gleichen Magiegebietes - übertragen. - With the help of this spell, the - caster can transfer aura at a ratio of 2:1 to - another member of the same school of magic. - - - Der Zauberer erschafft eine Wand aus - Feuer in der angegebenen Richtung. Sie verletzt - jeden, der sie durchschreitet. - The spell creates an opaque wall of - fire in the gives direction that will harm - anyone passing through it. - - - In einem aufwendigen Ritual opfert der - Schwarzmagier einige Bauern und verteilt dann - die Leichen auf magische Weise in den Brunnen - der Region. - In a complicated ritual the sorcerer - sacrifices the lives of ten peasants and - magically spreads their corpses within the wells - of a region. - - - Vor den Augen der feindlichen Soldaten - opfert der Schwarzmagier die zehn Bauern in - einem blutigen, grausamen Ritual und beschwört - auf diese Weise Geister des Wahnsinns über die - feindlichen Truppen. Diese werden im Kampf - verwirrt reagieren und nicht in der Lage sein, - den Anweisungen ihrer Offiziere zu folgen. - Before the eyes of the enemy soldiers - the sorcerer sacrifices ten peasants in a bloody - ritual and thereby summons spirits of madness - upon the enemy troops. The enemy soldiers will - be in confusion during battle and no more be - able to follow the commands of their leaders. - - - Mit Hilfe dunkler Rituale beschwört - der Zauberer Dämonen aus der Sphäre der - Schatten. Diese gefürchteten Wesen können sich - fast unsichtbar unter den Lebenden bewegen, ihre - finstere Aura ist jedoch für jeden spürbar. Im - Kampf sind Schattendämonen gefürchtete Gegner. - Sie sind schwer zu treffen und entziehen ihrem - Gegner Kraft. - With the help of dark rituals the - sorcerer summons demons from the Sphere Of - Shadows. These fearsome creatures can walk - almost unseen among the living, but their dark - aura can be sensed by everyone. Shadow demons - are feared in combat for they are hard to hit - and have the ability to drain strength from - their victims. - - - Dieses Ritual beschwört wütende Elementargeister der - Hitze. Eine Dürre sucht das Land heim. Bäume verdorren, Tiere - verenden, und die Ernte fällt aus. Für Tagelöhner gibt es kaum noch - Arbeit in der Landwirtschaft zu finden. - This Ritual summons an angry elemental spirit that - puts a drought on the entire region. Trees wither, animals die of - thirst and the harvest is destroyed. Workers find little to no work - in farming. - - - Dieses Ritual bindet die bereits - entfliehenden Seelen einiger Kampfopfer an ihren - toten Körper, wodurch sie zu untoten Leben - wiedererweckt werden. Ob sie ehemals auf der - Seite des Feindes oder der eigenen kämpften, ist - für das Ritual ohne belang. - This ritual binds the escaping souls - of some casualties back to their dead bodies and - thus condemns them to an undead existance under - the control of the sorcerer. The ritual affects - the corpses of allies and foes alike - no matter - on which side of the battle the soldiers fought - before their death. - - - Dieses magische Artefakt verleiht dem - Träger die Stärke eines ausgewachsenen - Höhlentrolls. Seine Tragkraft erhöht sich auf - das 50fache und auch im Kampf werden sich die - erhöhte Kraft und die trollisch zähe Haut - positiv auswirken. - This artifact gives the one wearing it - the strength of a cavetroll. He will be able to - carry fifty times as much as normal and also in - combat his enhanced strength and tough troll - skin will serve him well. - - - Der Schwarzmagier kann mit diesem - dunklen Ritual einen Riss in das Gefüge der - Magie bewirken, der alle magische Kraft aus der - Region reißen wird. Alle magisch begabten in der - Region werden einen Großteil ihrer Aura - verlieren. - With this dark ritual the - chaossorcerer causes a deep rift to appear in - the astral balance that will tear all magical - power from a region. All spellcasters in that - region will lose most of their aura. - - - Dieses Ritual, ausgeführt vor einem - Kampf, verwirbelt die astralen Energien auf dem - Schlachtfeld und macht es so feindlichen Magier - schwieriger, ihre Zauber zu wirken. - This ritual, performed before a - battle, causes the astral energies on the - battlefield to whirl and churn and thereby makes - spellcasting more difficult for the enemy mages. - - - Diese Elementarbeschwörung ruft einen - Feuerteufel herbei, ein Wesen aus den tiefsten - Niederungen der Flammenhöllen. Der Feuerteufel - wird sich begierig auf die Wälder der Region - stürzen und sie in Flammen setzen. - This elemental summoning calls a fire - fiend, a creature from the deepest hell. The - demon will eagerly rush into the forests of a - region and set them ablaze. - - - Genau um Mitternacht, wenn die Kräfte - der Finsternis am größten sind, kann auch ein - Schwarzmagier seine Kräfte nutzen um - Verzauberungen aufzuheben. Dazu zeichnet er ein - Pentagramm in das verzauberte Objekt und beginnt - mit einer Anrufung der Herren der Finsternis. - Die Herren werden ihm beistehen, doch ob es ihm - gelingt, den Zauber zu lösen, hängt allein von - seiner eigenen Kraft ab. - At midnight, when the Powers of - Darkness are at their peak, the sorcerer can use - his powers to destroy enchantments. In order to - do so, he draws a pentagram on a surface of the - enchanted object and begins calling the Lords Of - Darkness. The Lords will aid him, but whether he - is able to undo the target spell or not depends - upon his own power. - - - Nur geflüstert wird dieses Ritual an - den dunklen Akademien an die Adepten - weitergegeben, gehört es doch zu den - finstersten, die je niedergeschrieben wurden. - Durch die Anrufung unheiliger Dämonen wird die - Kraft der lebenden Toten verstärkt und sie - verwandeln sich in untote Monster großer Kraft. - Only whispered the knowledge of - performing this ritual is passed to the adepts - of the dark academies, for it is one of the - darkest that has ever been written down. By - calling unholy demons the strength of the living - dead is greatly increased and they are turned - into undead monsters of immense power. - - - Mit einem düsteren Ritual und unter - Opferung seines eigenen Blutes beschwört der - Schwarzmagier einen großen Geist von der - Elementarebene der Gifte. Der Geist manifestiert - sich als giftgrüner Schwaden über der Region und - wird allen, die mit ihm in Kontakt kommen, - Schaden zufügen. - By performing a gruesome ritual and - sacrificing his own blood the Sorcerer conjurs - up a spirit from the Elemental Plane Of Poison. - It will take the form of a green cloud of toxic - gases that envelops a whole region and that will - harm anyone within. - - - Mit diesem dunklen Ritual erzeugt der - Magier einen Köder, der für Drachen einfach - unwiderstehlich riecht. Ob die Drachen aus der - Umgebung oder aus der Sphäre des Chaos stammen, - konnte noch nicht erforscht werden. Es soll - beides bereits vorgekommen sein. Der Köder hält - etwa 6 Wochen, muss aber in einem - drachengenehmen Terrain platziert werden. - Performing this dark ritual, the - sorcerer creates a bait that exhales an - irresistable scent to dragons. It is not known - whether the dragons come from surrounding - regions or if they have their origin in the - Sphere Of Chaos. The bait will exist for about - six weeks, but it must be placed in a tarrain - that is suitable for dragons. - - - Mit Hilfe dunkler Rituale beschwört - der Zauberer Dämonen aus der Sphäre der - Schatten. Diese gefürchteten Wesen können sich - fast unsichtbar unter den Lebenden bewegen, ihre - finstere Aura ist jedoch für jeden spürbar. Im - Kampf sind Schattenmeister gefürchtete Gegner. - Sie sind schwer zu treffen und entziehen ihrem - Gegner Kraft und Leben. - With the help of dark rituals the - sorcerer summons demons from the Sphere Of - Shadows. These fearsome creatures can walk - almost unseen among the living, but their dark - aura can be sensed by everyone. Shadowmasters - are feared in combat for they are hard to hit - and have the ability to drain strength and life - force from their victims. - - - 'Und so reibe das Blut eines wilden - Kämpfers in den Stahl der Klinge und beginne die - Anrufung der Sphären des Chaos. Und hast du - alles zu ihrem Wohlgefallen getan, so werden sie - einen niederen der ihren senden, das Schwert mit - seiner Macht zu beseelen...' - 'So take the blood of a fierce warrior - and apply it to the steel of the blade. Then - start calling the Spheres Of Chaos. If you did - everything to their pleasure, they will send a - minor one of their kind to fulfill the sword - with his power.' - - - Einem erfahrenen Magier wird - irgendwann auf seinen Wanderungen ein - ungewöhnliches Exemplar einer Gattung begegnen, - welches sich dem Magier anschließen wird. - During their travel, seasoned - magicians will occasionally befriend an extraordinary - creature of an unusual species that will join them. - - - Durch das Opfern von 200 Bauern kann - der Chaosmagier ein Tor zur astralen Welt - öffnen. Das Tor kann in der Folgewoche verwendet - werden, es löst sich am Ende der Folgewoche auf. - By sacrificing the lives of 200 - peasants, the chaossorcerer is able to open a - planar gate. This gate can be used during the - following week to transfer units to the astral - plane. It dissipates at the end of the following - week. - - - Der Zauberer sendet dem Ziel des - Spruches einen Traum. - The mentalist sends a dream to the - target of the spell. - Le mentaliste envoie un rêve à la - cible du sort. - - - Dieser Zauber vermag dem Gegner ein - geringfügig versetztes Bild der eigenen Truppen - vorzuspiegeln. Die Schattenritter haben keinen - effektiven Angriff und Verwundungen im Kampf - zerstören sie sofort. - This spell creates illusionary - duplicates of allied troops. The shadow knights - can't do real damage and are instantly destroyed - if wounded. - Ce sort crée des copies illusoires de - troupes alliées. Les guerriers illusoires ne - peuvent faire de dégats réels et sont - instantanément détruits lorsqu'ils sont blessés. - - - Der Traumweber beschwört vor dem - Kampf grauenerregende Trugbilder herauf, die - viele Gegner in Panik versetzen. Die Betroffenen - werden versuchen, vor den Trugbildern zu - fliehen. - Before a battle the mentalist creates - terrifying illusions of hideous creatures that - will cause panic among the enemies. Those who - believe in the illusions will try to flee from - battle. - - - Dieses magische Ritual beruhigt die - gequälten Seelen der gewaltsam zu Tode - gekommenen und ermöglicht es ihnen so, ihre - letzte Reise in die Anderlande zu beginnen. Je - Stufe des Zaubers werden ungefähr 50 Seelen ihre - Ruhe finden. Der Zauber vermag nicht, bereits - wieder auferstandene lebende Tote zu erlösen, da - deren Bindung an diese Welt zu stark ist. - This ritual calms the tortured souls - of those who died a violent death and finally - releases them to the Otherlands. About 50 souls - per level of the spell will be released. The - spell will not affect existing undead, because - they are too strongly tied to the Material - World. - - - Mit Hilfe dieses Zaubers kann der - Traumweber die Illusion eines beliebigen - Gebäudes erzeugen. Die Illusion kann betreten - werden, ist aber ansonsten funktionslos und - benötigt auch keinen Unterhalt. Sie wird einige - Wochen bestehen bleiben. - With this spell the mentalist can - create the illusion of any building. The - illusion can be entered, but it has no function - and requires no maintenance. It will remain - existing for several weeks. - - - Mit Hilfe dieses Zaubers kann der - Traumweber eigene Aura im Verhältnis 2:1 auf - einen anderen Traumweber übertragen. - With the help of this spell the - mentalist can transfer aura at a ratio of 2:1 to - another mentalist. - - - Mit Hilfe dieses arkanen Rituals - vermag der Traumweber die wahre Gestalt einer - Gruppe - zu verschleiern. Unbedarften Beobachtern - erscheint - sie dann als einer anderen Rasse zugehörig. - With the help of this ritual the - mentalist is able to conceal the true form of a - target unit. To unknowing observers all persons - in the target unit appear to be of a different - race. - - - Dieser Zauber ermöglicht es dem - Traumweber, in die Träume einer Einheit - einzudringen und so einen Bericht über die - Umgebung zu erhalten. - This spell enables the mentalist to - penetrate the dreams of a target unit and gather - information about that unit's surroundings. He - will receive a report from the corresponding - region. - - - Dieser Kampfzauber führt dazu, dass - einige Gegner im Kampf unter schwerer Müdigkeit - leiden. Die Soldaten verschlafen manchmal ihren - Angriff und verteidigen sich schlechter. - This combat spell causes several - enemies to suffer from an unnatural tiredness - during combat. The soldiers will defend - themselves worse than normal and sometimes sink - into a slumber instead of attacking. - - - Stirbt ein Krieger im Kampf so macht - sich seine Seele auf die lange Wanderung zu den - Sternen. Mit Hilfe eines Rituals kann ein - Traumweber versuchen, die Seele wieder - einzufangen und in den Körper des Verstorbenen - zurückzubringen. Zwar heilt der Zauber keine - körperlichen Verwundungen, doch ein Behandelter - wird den Kampf überleben. - When a warrior dies in a battle, his - soul begins its long journey to the stars. With - the help of this ritual, the mentalist can try - to catch those escaping souls and bring them - back to their bodies. The spell does not heal - physical injuries, but an affected person will - survive the battle. - - - Mit diesem Spruch kann der Traumweber - versuchen, die Verzauberungen einer einzelnen - Einheit zu erkennen. Von allen Sprüchen, die - seine eigenen Fähigkeiten nicht überschreiten, - wird er einen Eindruck ihres Wirkens erhalten - können. Bei stärkeren Sprüchen benötigt er ein - wenig Glück für eine gelungene Analyse. - With this spell the mentalist can - attempt to detect enchantments on a target unit. - He will get an idea of the effect of all spells - that don't exceed his own abilities. If a spell - is stronger, it takes a little luck for a - successful analysis. - - - Dieser Zauber führt in der betroffenen - Region für einige Wochen zu Schlaflosigkeit und - Unruhe. Den Betroffenen fällt das Lernen - deutlich schwerer. - This spell causes insomnia and - restlessness in a whole region for several - weeks. All affected persons will learn much - slower than normal. - - - Dieser Zauber läßt einige feindliche - Kämpfer einschlafen. Schlafende Kämpfer greifen - nicht an und verteidigen sich schlechter, sie - wachen jedoch auf, sobald sie im Kampf getroffen - werden. - This spell causes several enemies to - fall asleep. Sleeping warriors don't attack and - defend themselves worse than normal, but they'll - wake up if they get hit during combat. - - - Mit diesem Zauber dringt der - Traumweber in die Gedanken und Traumwelt seines - Opfers ein und kann so seine intimsten - Geheimnisse ausspähen. Seine Fähigkeiten, seinen - Besitz und seine Parteizugehörigkeit wird nicht - länger ungewiss sein. - With this spell the mentalist - penetrates the thoughts and dreams of his victim - to reveal his most intimate secrets. The - target's faction, skills and possessions will no - longer be unknown. - - - Der Magier beschwört ein kleines Monster, einen Alp. Dieses bewegt sich - langsam auf sein Opfer zu (das sich an einem beliebigen Ort an der Welt - befinden kann, der Magier oder seine Partei braucht es nicht zu sehen). - Sobald das Opfer erreicht ist, wird es gnadenlos gequält, und nur durch - einen starken Gegenzauber oder den Tod des beschwörenden Magiers kann - das Opfer wieder Frieden finden. Bei der Beschwörung des Alps verliert - der Magier einen kleinen Teil seiner Aura für immer. - The magician spawns a little monster, a nightmare. The nightmare slowly - approaches its victim (which may be at an arbitrary place in eressea, it - is not needed for the magician or his party to see the victim). As soon - as - the victim is reached the nightmare starts to torment it without mercy, - only a powerfull counter spell or the death of the casting magician can - redeem - the victim. When spawning the nightmare the magician loses a small amount - of - his aura forever. - - - Ein mit diesem Zauber belegtes Drachenauge, welches zum Abendmahle - verzehrt wird, erlaubt es dem Benutzer, in die Träume einer anderen - Person einzudringen und diese zu lesen. Lange Zeit wurde eine solche - Fähigkeit für nutzlos erachtet, bis die ehemalige waldelfische - Magistra für Kampfmagie, Liarana Sonnentau von der Akademie Thall, - eine besondere Anwendung vorstellte: Feldherren träumen vor großen - Kämpfen oft unruhig und verraten im Traum ihre Pläne. Dies kann dem - Anwender einen großen Vorteil im kommenden Kampf geben. Aber Vorsicht: - Die Interpretation von Träumen ist eine schwierige Angelegenheit. - An enchanted eye of a dragon gives the person who eats it for supper the - power to see - other people's dreams. For a long time this abillity was counted as - beeing - useless until - the former elfish mistress for theurgy of war, Liarana Sonnentau from - the - academy Thall, - presented a special appliance for this artefact: Before a battle - captains - often have an - uncomfortable sleep and betray their plans in their dreams. This might - give the user of - the artefact a small advantage in the upcoming battle, but be warned: - Interpreting dreams - is a difficult exercise. - - - Mit diesem Spruch kann der Zauberer eine Sphäre der - Unsichtbarkeit - erschaffen. Die Späre macht ihren Träger sowie neunundneunzig weitere - Personen in derselben Einheit unsichtbar. - Using this spell the magician can create a Sphere of - Invisibility. This artefact hides the person bearing it and one hundred - persons in the same unit. - - - Dieser Zauber ermöglicht es dem - Traumweber, den Schlaf aller aliierten Einheiten - in - der Region so zu beeinflussen, dass sie für - einige - Zeit einen Bonus in allen Talenten bekommen. - This spell allows the mentalist to - influence the sleep of all allied units in a - region - in such a way that they will gain a bonus to all - talents for some time. - - - Dieser Zauber ermöglicht es dem - Traumweber die natürlichen und aufgezwungenen - Traumbilder einer Person, eines Gebäudes, - Schiffes oder einer Region zu unterscheiden und - diese zu entwirren. - This spell allows the mentalist to - distinguish between the natural and unnatural - dreams of a person, a ship, a building or a - region and remove those that are of magical - origin. - - - Aus 'Die Gesänge der Alten' von - Firudin dem Weisen: 'Diese verführerische kleine Melodie - und einige einschmeichelnde Worte überwinden das - Misstrauen der Bauern im Nu. Begeistert werden sie sich - Euch anschliessen und selbst Haus und Hof in Stich - lassen.' - From the 'Songs of the Elder' by - Firudin the Sage: 'This enticing little melody and its - ingratiating words will lure the peasants in no time. - They will leave home and hearth to follow your lead.' - - - Dieser fröhliche Gesang wird sich wie - ein Gerücht in der Region ausbreiten und alle Welt in - Feierlaune versetzten. Überall werden Tavernen und - Theater gut gefüllt sein und selbst die Bettler satt - werden. - This joyous song will spread like - wildfire throughout the region and cause festive spirits - in all the population. All the taverns and theaters will - be packed to the brim and even the beggars will not go - hungry. - - - Einem erfahrenen Magier wird - irgendwann auf seinen Wanderungen ein ungewöhnliches - Exemplar einer Gattung begegnen, welches sich dem Magier - anschließen wird. - Once during his travels, the seasoned - magician will meet an extraordinary creature of its species - that will join him. - - - Mit diesem Zauber greift der Magier - direkt den Geist seiner Gegner an. Ein Schlag aus - astraler und elektrischer Energie trifft die Gegner, - wird die Magieresistenz durchbrochen, verliert ein Opfer - permanent einen Teil seiner Erinnerungen. Wird es zu oft - ein Opfer dieses Zaubers kann es daran sterben. - With this spell the mentalist directly - attacks his enemies' souls. A blast of astral and - electrical energy strikes the foes. If a victim fails to - resist the magic, he will permanently lose part of his - memories. Being the target of this spell for too many - times may result in death. - - - Dieser Zauber - dessen Anwendung in - den meisten Kulturen streng verboten ist - löst im Opfer - ein unkontrollierbares Verlangen nach körperlicher Liebe - aus. Die betroffenen Personen werden sich Hals über Kopf - in ein Liebesabenteuer stürzen, zu blind vor Verlangen, - um an etwas anderes zu denken. Meistens bereuen sie es - einige Wochen später... - This spell - whose use is forbidden in - most cultures - creates an uncontrollable desire for - physical love in the victim. The affected persons will - rush head over heels into a love affair, unable to think - of anything else. Most of them will regret this a few - months later... - - - - - - Winter - winter - - - Sommer - summer - - - Frühling - spring - - - Herbst - fall - - - die erste Woche - the first week - - - die zweite Woche - the second week - - - die letzte Woche - the last week - - - der ersten Woche - of the first week - - - der zweiten Woche - of the second week - - - der letzten Woche - of the third week - - - Feldsegen - harvest moon - - - Nebeltage - impenetrable fog - - - Sturmmond - storm moon - - - Herdfeuer - hearth fire - - - Eiswind - icewind - - - Schneebann - snowbane - - - Blütenregen - flowerrain - - - Mond der milden Winde - mild winds - - - Sonnenfeuer - sunfire - - - des zweiten Zeitalters - the second age - - - neuer Zeitrechnung - of the new age - - - - - - Gemein - common - - - Kein Magiegebiet - no magic school yet - - - Illaun - Illaun - - - Tybied - Tybied - - - Gwyrrd - Gwyrrd - - - Cerddor - Cerddor - - - Draig - Draig - - - - - Baum - tree - - - Bäume - trees - - - - Mallornbaum - mallorn tree - - - Mallornbäume - mallorn trees - - - ALLIANZ - ALLIANCE - - - AUSSTOSSEN - KICK - - - NEU - NEW - - - KOMMANDO - COMMAND - - - VERLASSEN - LEAVE - - - BEITRETEN - JOIN - - - EINLADEN - INVITE - - - Steine - stones - - - - Pferde - horses - - - Bauern - peasants - - - Silber - silver - - - Laen - laen - - - - Schößlinge - saplings - - - - Mallornschößlinge - mallorn saplings - - - - Bäume - trees - - - - Mallorn - mallorn - - - - Eisen - iron - - - - Winter - winter - - - - Frühling - spring - - - - Sommer - summer - - - - Herbst - autumn - - - - Vorlage für den nächsten Zug: - Template for the next turn: - - - - Wir schreiben %s des Monats %s im Jahre %d %s. - It is %s of the month of %s in the %d. year of %s. - - - - Wir schreiben %s des Monats %s im Jahre %d %s. Es ist - %s. - It is %s of the month of %s in the %d. year of %s. It is - %s. - - - - aggressiv - aggressive - - - - vorne - front - - - - hinten - rear - - - - defensiv - defensive - - - - flieht - fleeing - - - - kämpft nicht - not fighting - - - - bekommt keine Hilfe - gets no aid - - - - Attacke gegen: - Attacked against - - - - Kämpft gegen: - Fighting against - - - - Hilft: - Helping - - - - Heer - army - - - - Unbekannte Partei - unknown faction - - - einer unbekannten Partei - an unknown faction - - - und - and - - - - Das Schiff des Elfen hat ein rotes Segel - - - - Der Zwerg hat eine Nuss dabei - - - - Die Katze führt eine Hellebarde - - - - Das Schiff mit dem grünen Segel liegt links neben dem - mit - einem weissen Segel - - - - Auf dem Schiff mit grünen Segeln kam der Speerkämpfer - - - - Der Krieger mit dem Kreis im Wappen hat einen Keks - - - - Der Krieger des mittleren Schiffs hat ein Schwert - - - - Auf dem gelben Segel prankt ein Kreuz als Wappen - - - - Der Mensch kam mit dem ersten Schiff - - - - Das Schiff mit dem Stern im Wappen liegt neben dem der - einen Mandelkern hat - - - - Das Schiff des Kriegers, der ein Apfel hat, liegt neben - dem, der ein Kreuz als Wappen hat - - - - Der Krieger mit dem Turm im Wappen trägt eine Axt - - - - Das Schiff des Menschen liegt neben dem blauen Schiff - - - - Das Insekt trägt einen Baum als Wappen - - - - Das Schiff mit dem Stern im Wappen liegt neben dem des - Kriegers, der einen Zweihänder führt - - - - Held - hero - - - - Helden - heroes - - - - - - Dunkel - dark - - - - Schwarz - black - - - - Licht - light - - - - Flammen - flame - - - - Eis - ice - - - - Klein - gully - - - - Hoch - high - - - - Hügel - hill - - - - Berg - mountain - - - - Wald - wood - - - - Sumpf - swamp - - - - Schnee - snow - - - - Sonnen - sun - - - - Mond - moon - - - - See - sea - - - - Tal - valley - - - - Schatten - shadow - - - - Höhlen - cave - - - - Blut - blood - - - - Wild - wild - - - - Chaos - chaos - - - - Nacht - night - - - - Nebel - mist - - - - Grau - grey - - - - Frost - cold - - - - Finster - gloom - - - - Düster - black - - - - Sternen - star - - - - - 'Ho ho ho!' Ein dicker Gnom fliegt auf einem von - 8 Jungdrachen gezogenen Schlitten durch die Nacht und vermacht Deiner - Partei ein Sonnensegel. (Um das Segel einer Einheit zu geben, gib - ihr den Befehl 'BEANSPRUCHE 1 Sonnensegel'). - 'Ho ho ho!' A fat little gnome Gnom on a sled - pulled by 8 young dragons flies through the stary night and presents - your faction with a solar sail. (To claim this item, one of your units - must issue the order 'CLAIM 1 solar sail'. - - - - 'Ho ho ho!' Ein dicker Gnom fliegt auf einem von - 8 Jungdrachen gezogenen Schlitten durch die Nacht und vermacht Deiner - Partei eine Phiole mit Sternenstaub. (Informationen dazu gibt es mit - BEANSPRUCHE und ZEIGE). - 'Ho ho ho!' A fat little gnome Gnom on a sled - pulled by 8 young dragons flies through the stary night and presents - your faction with a vial of stardust. (To get more information about - this item, use the CLAIM and SHOW commands). - - - - 'Ho ho ho!' Ein dicker Gnom fliegt auf einem von - 8 Jungdrachen gezogenen Schlitten durch die Nacht und vermacht Deiner - Partei einen wundervoll geschmueckten Weihnachtsbaum. (Informationen dazu gibt es mit - BEANSPRUCHE und ZEIGE). - 'Ho ho ho!' A fat little gnome Gnom on a sled - pulled by 8 young dragons flies through the stary night and presents - your faction with a beautifully decorated tree. (To get more information about - this item, use the CLAIM and SHOW commands). - - - - Gral - grail - - - - Grale - grails - - - - Lerntrank - brain boost - - - - Lerntränke - brain boosts - - - - GE je - stone per - - - - GE je - stones per - - - - GE - stone - - - - GE - stones - - - - bewacht die Region - guards the region - - - - und - and - - - - Dorfbewohner - Villagers - - - - Bauernmob - Angry mob - - - - Aufgebrachte Bauern - Furious peasants - - - - Söldner - Mercenaries - - - - Sumpfbewohner - Swamp people - - - - Waldbewohner - Woodsmen - - - - Nomaden - Nomads - - - - Eisleute - Ice people - - - - Bergbewohner - Mountain people - - - - Magie der Elemente - Magic of the Elements - - - - Schwerter, Armbrüste, Langbögen - Swords, Crossbows and Longbows - - - - Gorms Almanach der Rationellen Kriegsführung - Gorm's Almanach of Rational War - - - - Katamarane, Koggen, Karavellen - The dragonship, the caravell and the longboat - - - - Wege der Sterne - Ways of the Start - - - - Nadishahs Kleine Gift- und Kräuterkunde - Nadishah's collected lore on poisonous and beneficial herbs - - - - Mandricks Kompendium der Alchemie - Mandrick's alchemistic compendium - - - - Die Konstruktion der Burgen und Schlösser von Zentralandune - - - - Die Esse - - - - Über die Gewinnung von Erzen - - - - Barinions Lieder, eine Einführung für Unbedarfte - - - - die Ruine eines alten Tempels - the ruins of an ancient temple - - - - eine alte Burgruine - the ruins of a castle - - - - ein zerfallenes Bauernhaus - a dilapitated farm - - - - eine Leiche am Wegesrand - a corpse by the wayside - - - - eine Leiche am Wegesrand - a corpse by the wayside - - - - Feuerdrache - fire dragon - - - - Ein Alp starb, ohne sein Ziel zu erreichen. - An alp died before it reached its target. - - - - unbewaffnet - unarmed - - - - Trefferpunkte - hitpoints - - - - Rüstung - armor - - - - Angriff - attack - - - - Angriffe - attacks - - - - Verteidigung - defense - - - - Kann Waffen benutzen. - May use weapons. - - - - Ist durch Stichwaffen, Bögen und Armbrüste schwer zu verwunden. - Is hard to hit by piercing weapons. - - - - Ist durch Hiebwaffen schwer zu verwunden. - Is hard to hit by slashing weapons. - - - - Ist durch Schlagwaffen und Katapulte schwer zu verwunden. - Is hard to hit by blunt weapons and catapults. - - - - ein Angriff mit der Waffe oder unbewaffnet - an attack with a weapon or an unarmed attack - - - - ein unbewaffneter Angriff - an unarmed attack - - - - ein magischer Angriff - a magical attack - - - - Klon von %s - Clone of %s - - - - ein Angriff, der Gebäudeschaden verursacht - an attack causing structural damage to buildings - - - - Präkampfzauber - pre-combat spell - - - - Postkampfzauber - post-combat spell - - - - Kampfzauber - combat spell - - - - Normaler Zauber - regular spell - - - - Es ist Winter, und Insekten können nur in Wüsten oder mit Hilfe des Nestwärme-Tranks Personen rekrutieren. - It is winter, and insects can only recruit in deserts or with the aid of nestwarmth potions. - - - - Es ist Spätherbst, und diese Woche ist die letzte vor dem Winter, in der Insekten rekrutieren können. - - - - Eigentümer - Owner - - - - - eine Straße - a road - - - - Straßen - roads - - - - Straße - road - - - - eine zu %d%% vollendete Straße - a road that is %d%% complete - - - - ein Straßenanschluß - a connection to another road - - - - eine unvollständige Straße - an incomplete road - - - - Wand - wall - - - - eine Wand - a wall - - - - Feuerwand - firewall - - - - eine Feuerwand - a firewall - - - - Nebelwand - wall of fog - - - - eine Nebelwand - a wall of fog - - - - Irrlichter - wisps - - - - eine Gruppe von Irrlichtern - a cloud of wisps - - - - gewaltiges offenes Tor - massive open door - - - - ein gewaltiges offenes Tor - a massive open door - - - - gewaltiges verschlossenes Tor - massive locked door - - - - ein gewaltiges verschlossenes Tor - a massive locked door - - - - Illusionswand - illusionary wall - - - - eine Illusionswand - an illusionary wall - - - - - - Die Region ist verwüstet, der Boden karg. - The region is ravaged, the ground infertile. - - - - Einheit-Nr - unitid - - - - Schiff-Nr - shipid - - - - völker - tribes - - - - Gebäude-Nr - buildingid - - - - - Aura - aura - - - - Rasse - race - - - - Zauber-ID - spellid - - - - Richtung - direction - - - - Gebäudetyp - buildingtype - - - - + + + + + Wirbel + vortex + remous + + + Ein Wirbel aus reinem Chaos zieht über die Region + A vortex of pure chaos energy pulls over the region + + + Wabernde grüne Schwaden treiben durch den Nebel und + verdichten sich zu einer unheimlichen Kreatur, die nur aus einem langen + Ruderschwanz und einem riesigen runden Maul zu bestehen scheint. + Wobbling green vapours drift through the mists to form an eldritch creature that seems to be entirely made up of huge jaws and a long tail. + + + + Keine Informationen über diese Rasse verfügbar. + No information available for this race. + + + Singdrachen sind von der Größe eines ausgewachsenden Tigers. Ihre Färbung reicht von schillerndem Rot, über dunkles Grün bis hin zu tiefem Schwarz. Alle bekannten Drachen dieser Art weisen eine hohe Intelligenz und ein hohes Maß an magischen Fähigkeiten auf. Wie Ihre großen Verwandten verfügen sie über einen Feuerodem. Sie lieben den Gesang und das üppige Mahl. Von Zeit zu Zeit gehen sie eine engen magisches Bund zu einem Magier ein. Wenn dies geschieht, so steht dem Magier ein äußerst loyaler und lohnender Vertrauter zur Seite. + + Song Dragons are roughly the size of a fully grown tiger. Their coloring ranges from bright red, through a dark green shade to a deep black. All known dragons of this species display a high level of intelligence and highly developed magical skills. Like their larger cousins, Song Dragons posess a firegland. They love singing and a good meal. From time to time one of these magnificent creatures will bond with a mage. When this happens, the mage is assured of a most loyal and useful familiar at his side. + + + Dieses mystische Wesen lebt bevorzugt in den tiefsten Wäldern und + vermag sich hervorragend vor den Augen anderer zu verbergen. Nur + selten schließt sich ein Einhorn einem Magier an, jedoch wenn das + geschieht ist es ein mächtiger Verbündeter, der auch über eigene Magie + verfügt. + + + Der Adler ist ein ausgezeichneter Späher, fliegend überquert er sogar + kurze Meerengen, doch ist er hoch oben am Himmel auch sehr exponiert, + was ihn beim Rasten zu einem leichten Ziel macht. + + + Der Luchs ist bekannt für seine Geschicklichkeit im Verbergen und + Beobachten. Mit ein wenig Geduld kann er zu einem hervorragenden + Späher ausgebildet werden. Im Kampf verteidigt er sich mit seinen + scharfen Krallen und weiß seine Gewandheit zu nutzen. + + + Diese großen Wölfe sind nicht alle so wild und böse wie in den + Legenden berichtet, und einige von ihnen schließen sich auch guten + Magiern bereitwillig an und sind ihnen dann treue Gefährten. + + + 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. + + + + + Das Horn eines Trolles. Kein Troll würde sich lebend davon trennen. + The horn of an adult troll. No troll would ever part with this while he's alive. + + + Beim Barte des Proheten! Ach nein, Zwergen. Irgendetwas riecht hier ranzig. + Sniff... Bleah. Don't they ever wash these? + + + Diese Amulett ist ein hervorragender Fokus für alle Heilzauber. Ein + mit diesem Fokus gewirkter Heilzauber wird mit größerer + Warscheinlichkeit Erfolgreich sein und doppelt so viele Leute heilen + können. + + + Der Kopf eines toten Drachens oder Wyrms. Man sagt, es ruhen magische Kräfte darin. + The head of a dead dragon or wyrm. They say that it has magical powers. + + + Munition für Katapulte. + Ammunition for catapults. + + + Ein Elfenpferd wird sich nur den wenigsten jemals anschließen. Hat es + jedoch seine Scheu überwunden ist es ein sehr wertvoller Gefährte. Ein + Elfenpferd ist schneller als ein Pferd. Zudem hilft es seinem Reiter + im Kampf und unterstützt ihn mit seiner Magie. Es sind schwarze + Elfenpferde bekannt, die sich sogar Orks angeschlossen haben. + + + Die rötlich glühende Klinge dieser furchterregenden magischen Waffe + ist mit dunklen Runen bedeckt. Nur die erfahrendsten Schwertkämpfer + vermögen ihre Kraft zu zähmen, doch in ihrer Hand vermag dem + Runenschwert nichts zu widerstehen - selbst magische Rüstungen + durchdringt es ohne Schwierigkeiten - und den Geist des Kämpfers füllt + es mit unterschütterlicher Zuversicht. + + + This enchanted dragon-eye has to be eaten by the leader of your forces + on the eve before battle. During the night he gains insight into the + dreams of the enemy leaders and may potentially glean a decisive + advantage. + Dieses verzauberte Drachenauge muß vor dem Abend einer Schlacht vom + Heerführer verzehrt werden. Während der Nacht wird er dann Einblick in + die Träume der feindlichen Heerführer erhalten und so möglicherweise + einen entscheidenden Vorteil im kommenden Gefecht erlangen. + + + This artifact grants its wearer the strength of a cavetroll. He will + be able to carry fifty times as much as normal and also in combat his + enhanced strength and tough troll skin will serve him well. + Dieses magische Artefakt verleiht seinem Träger die Stärke eines + ausgewachsenen Höhlentrolls. Seine Tragkraft erhöht sich auf das + 50fache und auch im Kampf werden sich die erhöhte Kraft und die + trollisch zähe Haut positiv auswirken. + + + It may look like just another quartz, but your magician will tell you + tha great power emenates from these crystals. Using it at the begining + of a week will release a strong negative energy that reduce the + power of all spells cast in the region during that week. + Für den ungeübten Betrachter mag der Antimagiekristall wie ein + gewöhnlicher Quarzkristall ausschauen, doch ein Magier spürt, das ihm + ganz besondere Kräfte innewohnen. Durch spezielle Rituale antimagisch + aufgeladen wird der Kristall, wenn er zu feinem Staub zermahlen und + verteilt wird, die beim Zaubern freigesetzten magischen Energien + aufsaugen und die Kraft aller Zauber reduzieren, welche in der betreffenden + Woche in der Region gezaubert werden. + + + A ring of power increases a magician's power. The level of all the + spells + he casts will be increased by one without increasing their costs. + Ein Ring der Macht verstärkt die Kraft des Magiers. Jeder Zauber wird, + ohne das sich die Kosten erhöhen, so gezaubert als hätte der Magier + eine Stufe mehr. + + + Herbs stored in this bag will be much better preserved. + Kräuter, die in diesem Beutelchen aufbewahrt werden, sind erheblich + besser konserviert. + + + This bag encloses a dimensional fold, which can store up to 200 + stones of weight without any extra burden on the bearer. Large items + such as horses or carts cannot be placed inside. + Dieser Beutel umschließt eine kleine Dimensionsfalte, in der bis + zu 200 Gewichtseinheiten transportiert werden können, ohne dass + sie auf das Traggewicht angerechnet werden. Pferde und andere + Lebewesen sowie besonders sperrige Dinge (Wagen und Katapulte) können + nicht in dem Beutel transportiert werden. Auch ist es nicht möglich, + einen Zauberbeutel in einem anderen zu transportieren. Der Beutel + selber wiegt 1 GE. + + + These leather boots are embroidere with unicorn hair and allow + their wearer to walk at twice his normal speed. + Diese aus Leder gefertigten und mit Einhornfell verzierten Stiefel + ermöglichen es ihrem Träger, sich mit der doppelten Geschwindigkeit + fortzubewegen, wenn er zu Fuß reist. + + + The flaming sword gives its bearer an attack of 3d6+10 plus + an additional fireball causing 2d6 damage to 1-10 victims. + Using a flaming sword requires a minimum skill of 7. It grants an + additional +1 to your skill and your resistance to magic will be + increased. + Ein Flammenschwert gibt dem Träger, der kein Magier sein muß, + zusätzlich zu seinem normalen Angriff (3d6+10) einen kleinen + Feuerballangriff, der bei 1-10 Opfern 2d6 magischen Schaden + verursacht. Um ein Flammenschwert führen zu können, muss man + mindestens Hiebwaffen 7 haben, dann verleiht es einem auch + einen zusätzlichen Kampfbonus von +1. Ein Flammenschwert + erhöht die Magieresistenz seines Trägers wie ein Laenschwert. + + + The magic in this ring makes the fingers ten times more nimble. a + craftsman can produce ten times his normal quota, and other abilities + might also be improved. + Der Zauber in diesem Ring bewirkt eine um das zehnfache verbesserte + Geschicklichkeit und Gewandheit der Finger. Handwerker können somit + das zehnfache produzieren, und bei einigen anderen Tätigkeiten könnte + dies ebenfalls von Nutzen sein. + + + This magical artifact has been used since ancient times by Elves to + conceal themselves from their enemies. Other races have also learned + the value of these rings after encountering Elves - after all the ring + makes its wearer invisible to normal eyes, and only magical methods + enable the wearer to be discovered. + Dieses magische Artefakt wurde seit Urzeiten von den Elfen benutzt, + auf der Jagd oder um sich vor Feinden zu verbergen. Doch auch andere + Rassen haben nach der Begegnung mit den Elfenvölkern den Wert des Rings + schnell schätzen gelernt - schließlich macht er den Träger für jedes + noch so scharfe Auge unsichtbar - nur mit magischen Mitteln ist der + Verborgene noch zu entdecken. + + + Das Amulett erlaubt es dem Träger, alle Einheiten, die durch einen + Ring der Unsichtbarkeit geschützt sind, zu sehen. Einheiten allerdings, + die sich mit ihrem Tarnungs-Talent verstecken, bleiben weiterhin + unentdeckt. Die Herstellung des Amulettes kostet 3000 Silber. + + + Dieser Tiegel enthält die seltenste alchemistische Substanz + Eresseas, den Krötenschleim. Angeblich soll der Krötenschleim eine + aussergewöhnlich hohe magische Absorbtionskraft besitzen und deswegen + in obskuren magischen Ritualen Verwendung finden. + + + Die Kröte ist eine der seltensten Rassen Eresseas. Man munkelt, + sie würde nur auf magische Weise entstehen. In einer uralten + Abhandlung über Magie aus der Bibliothek der Akademie von Xontormia + wird die Theorie aufgestellt, das die Kröte die ins morphische Feld + des Magiers übertragene Manifestation eines implodierten + Zauberfeldes sein könnte. Vieleicht deswegen ist die Kröte auch + gegen Zauber weitaus widerstandsfähiger als die normalen Rassen + Eresseas, leider aber auch weitaus unmagischer als diese. Die + Kröte kann schon aufgrund ihrer Größe und der fehlenden Hände + nur unter Schwierigkeiten normale Tätigkeiten ausüben. Der + einzige Vorteil ihrer geringen Größe ist, dass sie sich leichter + verstecken kann. + + + Dieses magische Szepter, ein Geschenk Igjarjuks, sorgt für große + Verwirrung und Gedächtnisverlust. Syntax: BENUTZE "Szepter der + Tränen" + + + Setzt eine Einheit dieses Segel auf einem Schiff, so erhöht + sich dessen Reichweite permanent um 1 Region. + A unit setting this sail on a ship temporarily will permanently + increase the ship's range by 1. + + + Im Mistelzweig ruht eine magische + Kraft der besonderer Art. Der Anwender wird von seinen + Feinden in Frieden gelassen, eine Woche lang läßt jeder + Kämpfer ihn unbeschadet seines Weges ziehen. + The magical misteltoe has a wonderous + property: It's use will make one person able to escape + unharmed from every conflict, no enemy will lay hand on + the bearer for one week. + + + + + + Kein Magiegebiet + no magic school + + + Illaun + Illaun + + + Tybied + Tybied + + + Cerddor + Cerddor + + + Gwyrrd + Gwyrrd + + + Draig + Draig + + + + + Tresen + counter + + + + wenige + few + + + + viele + many + + + + relativ viele + rather many + + + + sehr wenige + very few + + + + sehr viele + a great many + beaucoup de + + + + (trauernd) + (in mourning) + + + Beschreibung: + Description: + + + Art: + Type: + + + Komponenten: + Components: + + + Modifikationen: + Modifications: + + + Stufe: + Level: + + + Rang: + Rank: + + + Syntax: + Syntax: + + + + Geboten wird für + Traders can sell + + + und für + and + + + . + . + + + , für + , + + + + , im + , to the + + + und im + and to the + + + Einheit + Unit + + + Partei + Faction + + + hier_passwort_eintragen + insert_your_password_here + + + + Baum + tree + + + + Bäume + trees + + + + Mallornbaum + mallorn tree + + + + Mallornbäume + mallorn trees + + + + + + Nordwestküste + + + Nordostküste + + + Ostküste + + + Südostküste + + + Südwestküste + + + Westküste + + + + + AUSWERTUNG + + + COMPUTER + + + ZUGVORLAGE + + + SILBERPOOL + + + STATISTIK + + + DEBUG + + + ZIPPED + + + ZEITUNG + + + MATERIALPOOL + + + ADRESSEN + + + BZIP2 + + + PUNKTE + + + TALENTVERSCHIEBUNGEN + + + + + ein fliegender Teppich + + + ein Ballon + + + eine Karavelle + + + ein Boot + + + ein Langboot + + + ein Drachenschiff + + + eine Trireme + + + + fliegender Teppich + flying carpet + + + Ballon + + + Karavelle + + + Boot + + + Langboot + + + Drachenschiff + + + Trireme + + + + + Mahlstrom + + + Ozean + + + Ebene + + + Wald + + + Sumpf + + + Wüste + + + Hochland + + + Berge + + + Gletscher + + + Gletscher + + + Feuerwand + + + Vulkan + + + Nebel + + + Eisberg + + + Dichter Nebel + + + Ebene aus Feuer und Dunkelheit + + + Aktiver Vulkan + + + Halle + + + Gang + + + Wand + + + Magischer Sturm + + + + ein %s + + + %s + + + die Ebene von %s + + + der Wald von %s + + + der Sumpf von %s + + + die Wüste von %s + + + das Hochland von %s + + + das Bergland von %s + + + der Gletscher von %s + + + eine %s + + + der Vulkan von %s + + + ein %s + + + der Eisberg von %s + the glacier of %s + + + der Gletscher von %s + the glacier of %s + + + %s + + + eine %s + + + der Vulkan von %s + + + die %s + + + die %s + + + eine mächtige Mauer + + + ein %s + + + + Krater + + + Pforte + + + Kohlenstück + + + Kohlenstücke + + + + + Westen + + + Nordwesten + + + Nordosten + + + Osten + + + Südwesten + + + Südosten + + + + NW + + + NO + + + Ost + + + SO + + + SW + + + West + + + + + ein unbekanntes Gebäude + an unknown building + + + ein unbekannter zauber + an unknown spell + + + ein unbekanntes Schiff + an unknown ship + + + eine unbekannte Einheit + an unknown unit + + + einer unbekannten Einheit + an unknown unit + + + + + Ereignisse + + + Botschaften + + + Warnungen und Fehler + + + Wirtschaft und Handel + + + Rohstoffe und Produktion + + + Magie und Artefakte + + + Reisen und Bewegung + + + Lehren und Lernen + + + Kämpfe + + + Verschiedenes + + + Neue Zauber + + + Neue Tränke + New Potions + + + + + Burg + + + Leuchtturm + + + Wurmloch + wormhole + + + Bergwerk + + + Steinbruch + + + Hafen + + + Akademie + + + Magierturm + + + Schmiede + + + Sägewerk + + + Pferdezucht + + + Monument + + + Damm + + + Karawanserei + + + Tunnel + + + Taverne + + + Steinkreis + + + Gesegneter Steinkreis + + + Traumschlößchen + + + Struktur + + + Akademie der Künste + academy of arts + + + Skulptur + sculpture + + + + + Zauberstab + + + Zauberstäbe + + + + + Grundmauern + + + Handelsposten + + + Befestigung + + + Turm + + + Burg + + + Festung + + + Zitadelle + + + + + Pyramide + pyramid + + + Pyramide + pyramid + + + + + Sphäre der Unsichtbarkeit + sphere of invisibility + + + Sphären der Unsichtbarkeit + spheres of invisibility + + + Kraut + + + Kräuterbeutel + + + Kräuterbeutel + + + Phiole + + + Phiolen + + + Katapultmunition + ammunition + + + Katapultmunition + ammunition + + + Sonnensegel + solar sail + + + Sonnensegel + solar sails + + + Weihnachtsbaum + christmas tree + + + Weihnachtsbäume + christmas trees + + + Sternenstaub + stardust + + + Sternenstaub + stardust + + + Papyrus + papyrus + + + Papyri + papyri + + + Elfenohr + elven ear + + + Elfenohren + elven ears + + + Dämonenblut + demon blood + + + Dämonenblut + demon blood + + + Goblinkopf + goblin head + + + Goblinköpfe + goblinheads + + + Zwergenbart + dwarven beard + + + Zwergenbärte + dwarven beards + + + Halblingfuß + halfling foot + + + Halblingfüße + halfling feet + + + Menschenskalp + human scalp + + + Menschenskalpe + human scalps + + + Meermenschschuppe + aquarian scale + + + Meermenschschuppen + aquarian scales + + + Insektenfühler + insect antenna + + + Insektenfühler + insect antenna + + + Katzenschwanz + cat tail + + + Katzenschwänze + cat tails + + + Orkhauer + orc tusk + + + Orkhauer + orc tusks + + + Trollhorn + troll horn + + + Trollhörner + troll horns + + + Feder des Phönix + feather of the phoenix + + + Federn des Phönix + feathers of the phoenix + + + + + Silber + + + Silber + + + Trefferpunkt + + + Trefferpunkte + + + Aura + + + Aura + + + permanente Aura + + + permanente Aura + + + Bauer + + + Bauern + + + Einheit + + + Einheiten + + + Person + + + Personen + + + + + Runenschwert + + + Runenschwerter + + + Eisen + + + Eisen + + + Holz + + + Holz + + + Stein + + + Steine + + + Wagen + + + Wagen + + + Katapult + + + Katapulte + + + Schwert + + + Schwerter + + + Speer + + + Speere + + + Mallornspeer + + + Mallornspeere + + + Armbrust + + + Armbrüste + + + Mallornarmbrust + + + Mallornarmbrüste + + + Bogen + + + Bögen + + + Mallornbogen + + + Mallornbögen + + + + Kettenhemd + + + Kettenhemden + + + Schuppenpanzer + + + Schuppenpanzer + + + Plattenpanzer + + + Plattenpanzer + + + Balsam + + + Balsam + + + Gewürz + + + Gewürze + + + Juwel + + + Juwelen + + + Myrrhe + + + Myrrhe + + + Öl + + + Öl + + + Seide + + + Seide + + + Weihrauch + + + Weihrauch + + + Flammenschwert + + + Flammenschwerter + + + Bihänder + + + Bihänder + + + Kriegsaxt + axe + + + Kriegsäxte + axes + + + Elfenbogen + + + Elfenbögen + + + Laenschwert + + + Laenschwerter + + + Laenschild + + + Laenschilde + + + Laenkettenhemd + + + Laenkettenhemden + + + Laen + + + Laen + + + Schild + + + Schilde + + + Hellebarde + + + Hellebarden + + + Lanze + + + Lanzen + + + Mallornlanze + + + Mallornlanzen + + + Mallorn + + + Mallorn + + + Keks + + + Kekse + + + Apfel + + + Äpfel + + + Nuß + + + Nüsse + + + Mandelkern + + + Mandelkerne + + + Drachenblut + + + Drachenblut + + + Feenstiefel + + + Feenstiefel + + + Heiltrank + + + Heiltränke + + + Antimagiekristall + + + Antimagiekristalle + + + Tiegel mit Krötenschleim + + + Tiegel mit Krötenschleim + + + Amulett + + + Amulette + + + Amulett der Keuschheit + + + Amulette der Keuschheit + + + Amulett der Heilung + + + Amulette der Heilung + + + Amulett des Treffens + + + Amulette des Treffens + + + Amulett des wahren Sehens + + + Amulette des wahren Sehens + + + Katzenamulett + + + Katzenamulette + + + Ring der Unsichtbarkeit + + + Ringe der Unsichtbarkeit + + + Ring der Macht + + + Ringe der Macht + + + Ring der flinken Finger + + + Ringe der flinken Finger + + + Pferd + + + Pferde + + + Magischer Kräuterbeutel + + + Magische Kräuterbeutel + + + Silberbeutel + + + Silberkassette + + + Drachenhort + + + Drachenkopf + + + Drachenköpfe + + + Auge des Drachen + + + Augen des Drachen + + + Schartiges Schwert + + + Schartige Schwerter + + + Rostiger Schild + + + Rostige Schilde + + + Rostige Hellebarde + rusty halberd + + + Rostige Hellebarden + rusty halberds + + + Rostige Kriegsaxt + rusty axe + + + Rostige Kriegsäxte + rusty axes + + + Rostiger Zweihänder + rusty claymore + + + Rostige Zweihänder + rusty claymores + + + Rostiges Kettenhemd + + + Rostige Kettenhemden + + + Beutel des negativen Gewichts + + + Beutel des negativen Gewichts + + + Ring der Regeneration + + + Ringe der Regeneration + + + Amulett der Dunkelheit + + + Amulette der Dunkelheit + + + Zauberbeutel + + + Zauberbeutel + + + Traumauge + + + Traumaugen + + + Seeschlangenkopf + + + Seeschlangenköpfe + + + Aurafocus + + + Aurafocuse + + + Akkredition des Xontormia-Expreß + + + Akkreditionen des Xontormia-Expreß + + + Szepter der Tränen + wand of tears + + + Szepter der Tränen + wands of tears + + + Schneeball + snowball + + + Schneebälle + snowball + + + Schneemann + snowman + + + Schneemänner + snowmen + + + Gürtel der Trollstärke + + + Gürtel der Trollstärke + + + Elfenpferd + + + Elfenpferde + + + Pegasus + + + Pegasi + + + Delphin + + + Delphine + + + Eintrittskarte des Großen Museum + + + Eintrittskarten des Großen Museum + + + Rückkehrticket des Großen Museum + + + Rückkehrtickets des Großen Museum + + + Astralkristall + + + Astralkristalle + + + Talenttrunk + + + Talenttrünke + + + Same + + + Samen + + + Mallornsame + + + Mallornsamen + + + Feuerwerk + + + Feuerwerke + + + Lebkuchenherz mit der Aufschrift 'Erz und + Stein, das ist fein' + + + Lebkuchenherzen mit der Aufschrift 'Erz und + Stein, das ist fein' + + + Schlüssel + key + + + Schlüssel + keys + + + Achatener Schlüssel + agate key + + + Achatene Schlüssel + agate keys + + + Saphirner Schlüssel + sapphire key + + + Saphirne Schlüssel + sapphire keys + + + + + Flachwurz + + + Würziger Wagemut + + + Eulenauge + + + Grüner Spinnerich + + + Blauer Baumringel + + + Elfenlieb + + + Gurgelkraut + + + Knotiger Saugwurz + + + Blasenmorchel + + + Wasserfinder + + + Kakteenschwitz + + + Sandfäule + + + Windbeutel + + + Fjordwuchs + + + Alraune + + + Steinbeißer + + + Spaltwachs + + + Höhlenglimm + + + Eisblume + + + Weißer Wüterich + + + Schneekristall + + + + + Flachwurz + + + Würzige Wagemut + + + Eulenaugen + + + Grüne Spinneriche + + + Blaue Baumringel + + + Elfenlieb + + + Gurgelkräuter + + + Knotige Saugwurze + + + Blasenmorcheln + + + Wasserfinder + + + Kakteenschwitze + + + Sandfäulen + + + Windbeutel + + + Fjordwuchse + + + Alraunen + + + Steinbeißer + + + Spaltwachse + + + Höhlenglimme + + + Eisblumen + + + Weiße Wüteriche + + + Schneekristalle + + + + Siebenmeilentee + + + Goliathwasser + + + Wasser des Lebens + + + Schaffenstrunk + + + Wundsalbe + + + Bauernblut + + + Gehirnschmalz + + + Dumpfbackenbrot + + + Nestwärme + + + Pferdeglück + + + Berserkerblut + + + Bauernlieb + + + Trank der Wahrheit + + + Elixier der Macht + + + Heiltrank + + + + Siebenmeilentees + + + Goliathwasser + + + Wasser des Lebens + + + Schaffenstrünke + + + Wundsalben + + + Bauernblut + + + Gehirnschmalz + + + Dumpfbackenbrote + + + Nestwärme + + + Pferdeglück + + + Berserkerblut + + + Bauernlieb + + + Tränke der Wahrheit + + + Elixiere der Macht + + + Heiltränke + + + + + Gürtel der Heldentaten + + + Gürtel der Heldentaten + + + + + AGGRESSIV + + + JEDEM + + + ALLES + + + ANZAHL + + + AURA + + + BÄUME + + + BAUERN + + + BEISTAND + + + BEWACHEN + + + BURG + + + DEFENSIV + + + EINHEIT + + + ERESSEA + + + FLIEHE + + + FREMDES + + + GEBÄUDE + + + GEGENSTÄNDE + + + GIB + + + GNADE + + + HELFE + + + HINTEN + + + HINTER + + + KOMMANDO + + + KRÄUTER + + + DURCHREISE + TRAVEL + + + KÄMPFE + + + NICHT + + + NÄCHSTER + + + PARTEI + + + PARTEITARNUNG + + + PAUSE + + + PERSONEN + + + PRIVAT + + + REGION + + + SCHIFF + + + SILBER + + + STRAßEN + + + STUFE + + + TEMPORÄRE + + + TRÄNKE + + + UM + + + VOR + + + VORNE + + + ZAUBER + + + + XETRANK + XEPOTION + + + XEBALLON + XEBALLOON + + + XELAEN + XELAEN + + + + + Alchemie + + + Armbrustschießen + + + Ausdauer + + + Bergbau + + + Bogenschießen + + + Burgenbau + + + Handeln + + + Hiebwaffen + + + Holzfällen + + + Katapultbedienung + + + Kräuterkunde + + + Magie + + + Pferdedressur + + + Reiten + + + Rüstungsbau + + + Schiffbau + + + Segeln + + + Spionage + + + Stangenwaffen + + + Steinbau + + + Steuereintreiben + + + Straßenbau + + + Taktik + + + Tarnung + + + Unterhaltung + + + Waffenbau + + + Waffenloser Kampf + + + Wagenbau + + + Wahrnehmung + + + + + + // + + + BANNER + + + ARBEITEN + + + WARTEN + WAIT + + + ATTACKIEREN + + + BIETEN + + + BEANSPRUCHEN + CLAIM + + + BEKLAUEN + + + BELAGERE + + + BENENNEN + + + BENUTZEN + + + BESCHREIBEN + + + BETRETEN + + + BEWACHEN + + + BOTSCHAFT + + + ENDE + + + FAHREN + + + NUMMER + + + FRIEDEN + PEACE + + + KRIEG + WAR + + + FOLGEN + + + FORSCHEN + + + HELFEN + + + KÄMPFEN + + + KAMPFZAUBER + + + KAUFEN + + + KONTAKTIEREN + + + LEHREN + + + LERNEN + + + LIEFERE + + + MACHEN + + + NACH + + + XONTORMIA + XONTORMIA + + + ALLIANZ + ALLIANCE + + + BEFÖRDERUNG + PROMOTION + + + BEZAHLEN + PAY + + + PFLANZEN + + + PRÄFIX + + + SYNONYM + + + INFO + + + PASSWORT + + + REKRUTIEREN + + + RESERVIEREN + + + ROUTE + + + SABOTIEREN + + + OPTION + + + SPIONIEREN + + + STIRB + + + TARNEN + + + TRANSPORTIEREN + + + TREIBEN + + + UNTERHALTEN + + + VERKAUFEN + + + VERLASSEN + + + VERGESSEN + + + ZAUBERE + + + ZEIGEN + + + ZERSTÖREN + + + ZÜCHTEN + + + DEFAULT + + + REPORT + + + XML + XML + + + URSPRUNG + + + EMAIL + + + PIRATERIE + + + LOCALE + + + NEUSTART + + + GRUPPE + + + OPFERE + + + BETEN + + + SORTIEREN + + + JIHAD + + + GM + + + WERWESEN + + + + + Optionen + + + Stufe + + + Aktueller Status + + + Benötigte Kräuter + + + im Bau + + + beschädigt + + + Unglücklicherweise wurde deine Partei + ausgelöscht. Du kannst gerne an einer anderen Stelle wieder + einsteigen. Melde Dich einfach wieder an. + + + Talente + + + hat + + + Größe + + + Zauber + + + Kampfzauber + + + keiner + + + Liste aller Adressen + + + anonym + + + Angriff + + + Verteidigung + + + Rüstung + + + Schaden + + + + + Deine Partei hat letzte Runde keinen Zug + abgegeben! + + + + + Schneemann + snowman + + + Schneemänner + snowmen + + + Klon + clone + + + Klone + clones + + + Klonen + clones + + + Klonen + clone + + + + Schablone + template + + + Schablonen + templates + + + Schablonen + templates + + + Schablonen + template + + + + Gnom + gnome + + + Gnome + gnomes + + + Gnomen + gnomes + + + Gnomen + gnome + + + + Museumsgeist + museumghost + + + Museumsgeister + museumghosts + + + Museumsgeistern + museumghosts + + + Museumsgeister + museumghost + + + + Ghast + ghast + + + Ghaste + ghasts + + + Ghasten + ghasts + + + Ghast + ghast + + + + Ghoul + ghoul + + + Ghoule + ghouls + + + Ghoulen + ghouls + + + Ghoul + ghoul + + + + Juju-Zombie + juju-zombie + + + Juju-Zombies + juju-zombies + + + Juju-Zombies + juju-zombies + + + Juju-Zombie + juju-zombie + + + + Zombie + zombie + + + Zombies + zombies + + + Zombies + zombies + + + Zombie + zombie + + + + Skelettherr + skeleton lord + + + Skelettherren + skeleton lords + + + Skelettherren + skeleton lords + + + Skelettherren + skeleton lord + + + + Skelett + skeleton + + + Skelette + skeletons + + + Skeletten + skeletons + + + Skelett + skeleton + + + + Zentaur + centaur + + + Zentauren + centaurs + + + Zentauren + centaurs + + + Zentauren + centaur + + + + Schattenritter + shadow knight + + + Schattenritter + shadow knight + + + Schattenrittern + shadow knights + + + Schattenritter + shadow knight + + + + Seeschlange + sea serpent + + + Seeschlangen + sea serpents + + + Seeschlangen + sea serpents + + + Seeschlangen + sea serpent + + + + Krake + kraken + + + Kraken + krakens + + + Kraken + krakens + + + Kraken + kraken + + + + Riesenschildkröte + giant turtle + + + Riesenschildkröten + giant turtles + + + Riesenschildkröten + giant turtles + + + Riesenschildkröten + giant turtle + + + + Delphin + dolphin + + + Delphine + dolphins + + + Delphinen + dolphins + + + Delphin + dolphin + + + + Tiger + tiger + + + Tiger + tiger + + + Tigern + tigers + + + Tiger + tiger + + + + Höllenkatze + hellcat + + + Höllenkatzen + hellcats + + + Höllenkatzen + hellcats + + + Höllenkatzen + hellcat + + + + Eule + owl + + + Eulen + owls + + + Eulen + owls + + + Eulen + owl + + + + Fee + fairy + + + Feen + fairies + + + Feen + fairies + + + Feen + fairy + + + + Traumkatze + dreamcat + + + Traumkatzen + dreamcats + + + Traumkatzen + dreamcats + + + Traumkatzen + dreamcat + + + + Teufelchen + imp + + + Teufelchen + imps + + + Teufelchen + imps + + + Teufelchen- + imp + + + + Geist + ghost + + + Geister + ghosts + + + Geistern + ghosts + + + Geister + ghost + + + + Warg + direwolf + + + Warge + direwolves + + + Wargen + direwolves + + + Warg + direwolf + + + + Einhorn + unicorn + + + Einhörner + unicorns + + + Einhörnern + unicorns + + + Einhorn + unicorn + + + + Nymphe + nymph + + + Nymphen + nymphs + + + Nymphen + nymphs + + + Nymphen + nymph + + + + Singdrache + song dragon + + + Singdrachen + song dragons + + + Singdrachen + song dragons + + + Singdrachen + song dragon + + + + Ratte + rat + + + Ratten + rats + + + Ratten + rats + + + Ratten + rat + + + + Adler + eagle + + + Adler + eagles + + + Adlern + eagles + + + Adler + eagle + + + + Tunnelwurm + tunnelworm + + + Tunnelwürmer + tunnelworms + + + Tunnelwürmern + tunnelworms + + + Tunnelwurm + tunnelworm + + + + Luchs + lynx + + + Luchse + lynx + + + Luchsen + lynx + + + Luchs + lynx + + + + Wolf + wolf + + + Wölfe + wolves + + + Wölfen + wolves + + + Wolfs + wolf + + + + Bauer + peasant + + + Bauern + peasants + + + Bauern + peasants + + + Bauern + peasant + + + + Hirntöter + braineater + + + Hirntöter + braineaters + + + Hirntöter + braineaters + + + Hirntöter + braineater + + + + Schlumpf + smurf + + + Schlümpfe + smurfs + + + Schlumpf + smurf + + + Schlümpfen + smurfs + + + + Kröte + toad + + + Kröten + toads + + + Kröten + toads + + + Kröten + toad + + + + Alp + nightmare + + + Alps + nightmaress + + + Alps + nightmares + + + Alp + nightmare + + + + Bergwächter + mountainguard + + + Bergwächter + mountainguard + + + Bergwächtern + mountainguards + + + Bergwächter + mountainguard + + + + Schattenmeister + shadowmaster + + + Schattenmeister + shadowmaster + + + Schattenmeistern + shadowmasters + + + Schattenmeister + shadowmaster + + + + Schattendämon + shadowdemon + + + Schattendämonen + shadowdemons + + + Schattendämonen + shadowdemons + + + Schattendämon + shadowdemon + + + + Steingolem + stone golem + + + Steingolems + stone golems + + + Steingolems + stone golems + + + Steingolem + stone golem + + + + Eisengolem + irongolem + + + Eisengolems + irongolems + + + Eisengolems + irongolems + + + Eisengolem + irongolem + + + + Zauber + spell + + + Zauber + spell + + + Zauber + spell + + + Zauber + spell + + + + Spezial + special + + + Spezial + special + + + Spezial + special + + + Spezial + special + + + + Dracoid + dracoid + + + Dracoide + dracoids + + + Dracoiden + dracoids + + + Dracoiden + dracoid + + + + Katzendrache + catdragon + + + Katzendrachen + catdragons + + + Katzendrachen + catdragons + + + Katzendrachen + catdragon + + + + Ent + ent + + + Ents + ents + + + Ents + ents + + + Ent + ent + + + + Schattendrache + shadow dragon + + + Schattendrachen + shadow dragons + + + Schattendrachen + shadow dragons + + + Schattendrachen + shadow dragon + + + + Todesflatter + darkbat + + + Todesflattern + darkbats + + + Todesflattern + darkbats + + + Todesflatter + darkbat + + + + Alptraum + nightmare + + + Alpträume + nightmares + + + Alpträumen + nightmares + + + Alptraum + nightmare + + + + Nachteinhorn + vampiric unicorn + + + Nachteinhörner + vampiric unicorns + + + Nachteinhörnern + vampiric unicorns + + + Nachteinhorn + vampiric unicorn + + + + Wyrm + wyrm + + + Wyrme + wyrms + + + Wyrmen + wyrms + + + Wyrm + wyrm + + + + Drache + dragon + + + Drachen + dragons + + + Drachen + dragons + + + Drachen + dragon + + + + Jungdrache + young dragon + + + Jungdrachen + young dragons + + + Jungdrachen + young dragons + + + Jungdrachen + young dragon + + + + Phönix + phoenix + + + Phönixe + phoenixes + + + Phönixen + phoenixes + + + Phönix + phoenix + + + + Illusion + illusion + + + Illusionen + illusions + + + Illusions + illusions + + + Illusions + illusion + + + + Spinx + sphinx + + + Spinxen + sphinxs + + + Spinxen + sphinx + + + Spinx + sphinx + + + + kleiner Scarabäus + little scarab + + + kleine Scarabäen + little scarab + + + kleinen Scarabäen + little scarab + + + kleine Scarabäen + little scarab + + + + grüner Scarabäus + green scarab + + + grüne Scarabäen + green scarab + + + grünen Scarabäen + green scarab + + + grünen Scarabäen + green scarab + + + + blauer Scarabäus + blue scarab + + + blaue Scarabäen + blue scarabs + + + blauen Scarabäen + blue scarab + + + blaue Scarabäen + blue scarab + + + + roter Scarabäus + red scarab + + + rote Scarabäen + red scarabs + + + roten Scarabäen + red scarab + + + rote Scarabäen + red scarab + + + + Untoter Pharao + undead Pharaoh + + + Untoter Pharaonen + undead Pharaohs + + + Untoten Pharao + undead Pharaoh + + + Untote Pharaonen + undead Pharaoh + + + + Mumie + mummy + + + Mumien + mummys + + + Mumien + mummy + + + Mumien + mummy + + + + Untoter + undead + + + Untote + undead + + + Untoten + undead + + + Untoten + undead + + + + Apepschlange + apepsnake + + + Apepschlangen + apepsnakes + + + Apepschlangen + apepsnakes + + + Apepschlange + apepsnake + + + + Apophis + apophis + + + Apophis + apophis + + + Apophis + apophis + + + Apophis + apophis + + + + Meermensch + aquarian + + + Meermenschen + aquarians + + + Meermenschen + aquarians + + + Meermenschen + aquarian + + + + Katze + cat + + + Katzen + cats + + + Katzen + cats + + + Katzen + cats + + + + Halbling + halfling + + + Halblinge + halflings + + + Halblingen + halflings + + + Halblings + halfling + + + + Insekt + insect + + + Insekten + insects + + + Insekten + insects + + + Insekten + insect + + + + Dämon + demon + + + Dämonen + demons + + + Dämonen + demons + + + Dämonen + demon + + + + Troll + troll + + + Trolle + trolls + + + Trollen + trolls + + + Troll + troll + + + + Mensch + human + + + Menschen + humans + + + Menschen + humans + + + Menschen + human + + + + Goblin + goblin + + + Goblins + goblins + + + Goblins + goblins + + + Goblin + goblin + + + + Ork + orc + + + Orks + orcs + + + Orks + orcs + + + Ork + orc + + + + Snotling + snotling + + + Snotlinge + snotlings + + + Snotlingen + snotlings + + + Snotling + snotling + + + + Snotling + snotling + + + Snotlinge + snotlings + + + Snotlingen + snotlings + + + Snotling + snotling + + + + Elf + elf + + + Elfen + elves + + + Elfen + elves + + + Elfen + elves + + + + Zwerg + dwarf + + + Zwerge + dwarves + + + Zwergen + dwarves + + + Zwergen + dwarf + + + + + + sehr stark + critically wounded + + + stark + heavily wounded + + + schwer verwundet + badly wounded + + + verwundet + wounded + + + erschöpft + exhausted + + + + + For Seven Mile Tea, boil up a Cobalt Fungus and pour the resulting brew into a Windbag. Catch and filter the liquid that drips out and administer it. This tea allows up to ten men to move as fast as a horse. + Für den Siebenmeilentee koche man einen Blauen Baumringel auf und gieße dieses Gebräu in einen Windbeutel. Das heraustropfende Wasser fange man auf, filtere es und verabreiche es alsdann. Durch diesen Tee können bis zu zehn Menschen schnell wie ein Pferd laufen. + + + 'First roast the Gurgelkraut quickly and add some Fjordwuchs to spice it up. Let it all boil slowly until almost all liquid has evaporated. Leave the mash overnight and finally squeeze it the next morning until a thick fluid drips out.' The liquid thus produced, 'Goliath Water' as we call it, is enough for 10 men and gives each man the carrying capacity of a horse for one week. + Zuerst brate man das Gurgelkraut leicht an und würze das Zeug mit ein wenig Fjordwuchs. Man lasse alles so lange kochen, bis fast alle Flüssigkeit verdampft ist. Diesen Brei stelle man über Nacht raus. Am nächsten Morgen presse man den Brei aus. Die so gewonnene Flüssigkeit, Goliathwasser genannt, verleiht bis zu zehn Männern die Tragkraft eines Pferdes. + + + The "Water of Life" allows living trees to be created from logs. A Knotroot and Elvendear are heated until one can just still keep one's finger in. This is then poured into a jar and allowed to cool slowly. The extract is sufficient for 10 pieces of wood. + Das 'Wasser des Lebens' ist in der Lage, aus gefällten Baumstämmen wieder lebende Bäume zu machen. Dazu wird ein knotiger Saugwurz zusammen mit einem Elfenlieb erwärmt, so daß man gerade noch den Finger reinhalten kann. Dies gieße man in ein Gefäß und lasse es langsam abkühlen. Der Extrakt reicht für 10 Holzstämme. + + + Allow a Tangy Temerity to simmer for three hours in a litre of water, then add a grated Mandrake, and sprinkle in a Gapgrowth harvested at full moon. The whole brew should then be allowed to stew for three days in a warm place. This potion increases the strength and endurance of ten men so that they can achieve twice as much in a week. + Man lasse einen Würzigen Wagemut drei Stunden lang in einem Liter Wasser köcheln. Dann gebe man eine geriebene Alraune dazu und bestreue das ganze mit bei Vollmond geerntetem Spaltwachs. Nun lasse man den Sud drei Tage an einem dunklen und warmen Ort ziehen und seie dann die Flüssigkeit ab. Dieser Schaffenstrunk erhöht die Kraft und Ausdauer von zehn Männern, so daß sie doppelt soviel schaffen können wie sonst. + + + When one is severely wounded after a hard battle it is advisable to have some Ointment to hand. Applied to wounds, this magical paste closes them in the blink of an eye. For the preparation the alchemist requires a cobalt fungus, tangy temerity, and white hemlock. A dose of the potion heals up to 400 hitpoints. + Ist man nach einem einem harten Kampf schwer verwundet, ist es ratsam, etwas Wundsalbe parat zu haben. Streicht man diese magische Paste auf die Wunden, schließen sich diese augenblicklich. Für die Herstellung benötigt der Alchemist nebst einem Blauen Baumringel einen Würzigen Wagemut und einen Weißen Wüterich. Eine solche Portion heilt bis zu 400 Lebenspunkte. + + + Knowledge of this potion is amongst the most dangerous and secret wisdom of the alchemist. Snatched from the darkest hells, the knowledge of this formula enables the production of an elixer which serves Demons as nourishment. If used by normal beings it leads to a swift death and eternal undeath. The creation requires Fjord Fungus together with some Cave Lichen and Cobalt Fungus, and an unfortunate peasant from the region, who is killed in the bloody days-long ritual. One vial of the potion satisfies the hunger of 100 Demons for a week. + Zu den gefährlichsten und geheimsten Wissen der Alchemisten zählt die Kenntnis um diesen Trank. Den finstersten Höllen entrissen, ermöglicht die Kenntnis dieser Formel die Herstellung eines Elixiers, welches Dämonen als Nahrung dient. Von normalen Lebewesen eingenommen, führt es zu schnellem Tod und ewigen Nichtleben. Die Herstellung benötigt nebst Fjordwuchs, etwas Höhlenglimm und einem Blauen Baumringel auch einen Bauern aus der Region, welcher in einem tagelangen blutigen Ritual getötet wird. Ein Fläschchen des Tranks kann den Hunger von 100 Dämonen für eine Woche stillen. + + + To create the brain wax potion, mix the juice of a waterfinder with quite a bit of grated windbag and a pinch of bugleweed. Let this steep for just a minute. When the liquid is only lukewarm, add some rock weed. Using a large spoon, stirr exactly seven times clockwise and then seven times counterclockwise. Fill the vial when the liquid has gone still. The juice gives ten people a 33% chance of an additional attempt at learning a skill. + Für das Gehirnschmalz verrühre man den Saft eines Wasserfinders mit recht viel geriebenem Windbeutel und ein wenig Gurgelkraut. Dies lasse man kurz aufwallen. Wenn die Flüssigkeit nur noch handwarm ist, gebe man etwas Steinbeißer dazu. Das ganze muß genau siebenmal rechtsherum und siebenmal linksherum mit einem großen Löffel gerührt werden. Wenn keine Bewegung mehr zu erkennen ist, fülle man den Saft ab. Der Saft gibt mit einer Chance von 1/3 bis zu zehn Personen einen zusätzlichen Lernversuch. + + + A duncebun is a nasty piece of work, negating any attempt at learning a skill, or even causing the subject to forget things! For ten servings knead a rasped fjord fungus, an abraded owlsgaze and a finely sliced spider ivy to a smooth dough. Bake for an hour at moderate heat and brush the result with some cave lichen. Who eats this bread will not learn what he's attempting to learn, and, in case there is no attempt to learn anything, will forget a week's worth of study in his best skill. + Das Dumpfbackenbrot ist eine sehr gemeine Sache, macht es doch jeden Lernerfolg zunichte oder läßt einen gar Dinge vergessen! Für zehn Portionen verknete man einen geriebenen Fjordwuchs, einen zerstoßenes Eulenauge und einen kleingeschnittenen Grünen Spinnerich zu einem geschmeidigen Teig. Diesen backe man eine Stunde lang bei guter Hitze und bestreiche das Ergebnis mit etwas Höhlenglimm. Wer dieses Brot gegessen hat, kann eine Woche lang nichts lernen, und so er nichts zu lernen versucht, wird er gar eine Woche seiner besten Fähigkeit vergessen. + + + A potion of nest warmth allows an insect to recruit outside of a desert region in winter. The learned alchemist prepares this by taking a peyote, mixing it with a portion of gapgrowth which has been gathered during a clear, starry night. To dispell winter, add some blossoms of the ice begonia in the mix, and stirr everything together with a spider ivy until it turns a nice shade of violet. One vial supplies an entire region for a whole week. + Nestwärme erlaubt es einem Insekt, im Winter außerhalb von Wüsten neue Rekruten anzuwerben. Zur Zubereitung nimmt der geübte Alchemist einen Kakteenschwitz, vermischt ihn mit einer Portion Spaltwachs, die in einer sternklaren Nacht gesammelt wurde, gibt zur Vertreibung des Winters einige Blütenblätter der Eisblume in den Sud, und rührt alles mit einem grünen Spinnerich bis es eine violette Farbe annimmt. Ein Trank reicht eine Woche lang für eine ganze Region. + + + To make a horsepower potion, chop a peyote, a cobalt fungus and some knotroot, and boil it in a bucketful of water. Then add some sand reeker and let the mixture steep for three days. Finally one gives this to the horses to drink, to double their procreation. + Für das Pferdeglück zerhacke man einen Kakteenschwitz, einen blauen Baumringel und etwas knotigen Saugwurz und koche das ganze mit einem Eimer Wasser auf. Dann füge man etwas Sandfäule dazu und lasse diesen Sud drei Tage lang ziehen. Letztlich gebe man es den Pferden zu trinken, auf daß sie sich doppelt so schnell vermehren. + + + The use of the berserkers blood potion is advised to increase one's warriors abilities to new heights. To create this, one needs a white hemlock, some flatroot, sand reeker and a mandrake. All ingredients have to be sliced as finely as possible, after which it is boiled for two hours. The cooled brew is strained through a cloth. The resulting juice is enough to improve up to ten warriors. + Will man seine Krieger zu Höchstleistungen antreiben, sei das Berserkerblut empfohlen. Um es herzustellen, braucht man einen Weißen Wüterich, etwas Flachwurz, Sandfäule und eine Alraune. Alle Zutaten müssen möglichst klein geschnitten und anschließend zwei Stunden lang gekocht werden. Den abgekühlten Brei gebe man in ein Tuch und presse ihn aus. Der so gewonnene Saft reicht aus, um zehn Kämpfer besser angreifen zu lassen. + + + The peasant love potion enamors both Man and Woman to the same degree and results in a strong wish for children. For a big portion scoop out a mandrake, fill it with finely chopped bubblemorel, elvendear and snowcrystal petal, sprinkle grated rock weed on top and let it simmer on low heat for twenty hours. The potion can grant up to 1000 peasants the happiness of twins. + Das Bauernlieb betört Mann und Frau gleichwohl und läßt in ihnen den Wunsch nach Kindern anwachsen. Für eine große Portion höhle man eine Alraune aus, gebe kleingehackten Blasenmorchel, Elfenlieb und Schneekristall dazu, streue ein wenig geriebenen Steinbeißer darüber und lasse dieses zwanzig Stunden lang auf kleiner Flamme kochen. Bis zu 1000 Bauern vermag der Trank das Glück von Zwillinge zu bescheren. + + + This simple but very potent brew sharpens the senses of anyone that drinks of it and makes him able to see through even the most complex illusions for one week. + Dieses wirkungsvolle einfache Gebräu schärft die Sinne des Trinkenden derart, daß er in der Lage ist, eine Woche lang auch die komplexesten Illusionen zu durchschauen. + + + One of the most rare and prized of all alchemist elixers, this potion grants the user a dragon's power for a few weeks. The potion increases the life-energy of a maximum of ten people fivefold. The effect is strongest right after drinking and slowly decreases over time. To brew this potion the alchemist needs an elvendear, a windbag, a piece of waterfinder and a spider ivy. Finally he dusts it with some minced bubblemorel and stirrs the powder into some dragon's blood. + Eines der seltensten und wertvollsten alchemistischen Elixiere, verleiht dieser Trank dem Anwender für einige Wochen die Kraft eines Drachen. Der Trank erhöht die Lebensenergie von maximal zehn Personen auf das fünffache. Die Wirkung ist direkt nach der Einnahme am stärksten und klingt danach langsam ab. Zur Herstellung benötigt der Alchemist ein Elfenlieb, einen Windbeutel, ein Stück Wasserfinder und einen Grünen Spinnerich. Über dieses Mischung streue er schließlich einen zerriebenen Blasenmorchel und rühre dieses Pulver unter etwas Drachenblut. + + + For a healing potion one takes the peel of a windbag and some bugleweed, stirr in some chopped elvendear and sprinkle it with the blossoms of an ice begonia. This has to cook through for four days, while a gapgrowth has to be added on the second day. Then one carefully scoops off the top layer of liquid. One such potion gives four men (or one man four times) a 50% chance to survive otherwise lethal wounds. The potion is automatically used in case of injury. + Für einen Heiltrank nehme man die Schale eines Windbeutels und etwas Gurgelkraut, rühre eine kleingehacktes Elfenlieb dazu und bestreue alles mit den Blüten einer Eisblume. Dies muß vier Tage lang gären, wobei man am zweiten Tag einen Spaltwachs dazutun muß. Dann ziehe man vorsichtig den oben schwimmenden Saft ab. Ein solcher Trank gibt vier Männern (oder einem Mann vier mal) im Kampf eine Chance von 50%, sonst tödliche Wunden zu überleben. Der Trank wird von ihnen automatisch bei Verletzung angewandt. + + + + + Erschaffe einen Ring der Macht + Create A Ring Of Power + + + Schild des Fisches + Shield Of The Fish + + + Runen des Schutzes + Protective Runes + + + Ruf der Realität + Call Of Reality + + + Astraler Ruf + Astral Call + + + Magiefresser + Destroy Magic + + + Mauern der Ewigkeit + Eternal Walls + + + Stehle Aura + Steal Aura + + + Schutzzauber + Resist Magic + + + Astraler Blick + Astral Gaze + + + Auratransfer + Transfer Aura + + + Monster friedlich stimmen + Calm Monster + + + Luftschiff + Airship + + + Lied der Verführung + Song Of Seduction + + + Schaler Wein + Hangover + + + Aushorchen + sound_out + + + Kriegsgesang + Song Of War + + + Gesang der Angst + Song Of Fear + + + Lied des Ortes analysieren + Analysis + + + Schockwelle + Shockwave + + + Fluch brechen + Negate Curse + + + Erschaffe ein Amulett der Keuschheit + Create An Amulet Of Chastity + + + Beschleunigung + Acceleration + + + Großer Drachenodem + Powerful Dragonbreath + + + Opfere Kraft + Sacrifice Strength + + + Belebtes Gestein + Living Rock + + + Gesang der Melancholie + Song of Melancholy + + + Gesang des wachen Geistes + Song Of The Youthful Spirit + + + Gesang des schwachen Geistes + Song Of The Aging Spirit + + + Gesang der Friedfertigkeit + Song Of Peace + + + Gesang der Versklavung + Song Of Slavery + + + Hohe Kunst der Überzeugung + Song Of Slavery + + + Zeitdehnung + Double Time + + + Vertrauten rufen + Summon Familiar + + + Rüstschild + Shield Shine + + + Wyrmtransformation + Wyrmtransformation + + + Schattenodem + Shadowbreath + + + Feuersturm + Firestorm + + + Feuerwalze + Immolation + + + Eisnebel + Coldfront + + + Säurenebel + Acid Rain + + + Furchteinflößende Aura + Panic + + + Meteorregen + Meteor Shower + + + Schattenruf + Shadow Call + + + Erschaffe einen Ring der Regeneration + Create A Ring Of Regeneration + + + Mob aufwiegeln + Mob Rule + + + Aufruhr beschwichtigen + Calm Riot + + + Aufruhr verursachen + Riot + + + Blick in die Realität + Gaze Upon Reality + + + Störe Astrale Integrität + Astral Disruption + + + Eisiger Drachenodem + Icy Dragonbreath + + + Eisiger Drachenodem + Icy Dragonbreath + + + Erschaffe ein Runenschwert + Create A Runesword + + + Erschaffe einen Beutel des Negativen Gewichts + Create A Bag Of Holding + + + Erschaffe einen Aurafocus + Create An Aurafocus + + + Erschaffe Antimagiekristall + Create An Antimagic Crystal + + + Astrale Schwächezone + Antimagic + + + Astraler Ausgang + Astral Exit + + + Astraler Weg + Astral Path + + + Beute Bewahren + Save Spoils + + + Schutz vor Magie + Protection from Magic + + + Wunderdoktor + Miracle Doctor + + + Schleieraura + Concealing Aura + + + Magie analysieren + Analyze Magic + + + Hohes Lied der Gaukelei + Song of Generosity + + + Gesang des Werbens + Song of Courting + + + Schleieraura + Veil + + + Lied der Heilung + Blessed Harvest + + + Gesang der Furcht + Song of Terror + + + Segen der Erde + Blessed Harvest + + + Heldengesang + Epic Heroes + + + Gesang des Lebens analysieren + Analyze Song of Life + + + Bannlied + Countersong + + + Gesang des Auratransfers + Hymn of Aura Sharing + + + Gesang der Verwirrung + Song of Confusion + + + Plappermaul + Blabbermouth + + + Regentanz + Rain Dance + + + Gaukeleien + Jugglery + + + Friedenslied + Appeasing Song + + + Viehheilung + Cattle Healing + + + Erschaffe Steingolems + Create Stone Golems + + + Erschaffe Eisengolems + Create Iron Golems + + + Hainzauber + Grove Of Oak Trees + + + Rostregen + Rain Of Rust + + + Firuns Fell + Firun's Coat + + + Hagel + Hail + + + Seelenkopie + Doppelganger + + + Irrlichter + Wisps + + + Schlechte Träume + Bad Dreams + + + Bergwächter + Mountain Guardian + + + Magischer Pfad + Magic Path + + + Tor in die Ebene der Hitze + Great Drought + + + Wurzeln der Magie + Roots Of Magic + + + Mahlstrom + Maelstrom + + + Windschild + Air Shield + + + Segne Mallornstecken + Bless Mallorn Logs + + + Beschwörung eines + Wasserelementares + Summon Water Elemental + + + Heilung + Heal + + + Wirbelwind + Whirlwind + + + Astralschutzgeister + Astral Guardian Spirits + + + Meditation + Meditate + + + Beschwöre einen Erdelementar + Summon Earth Elemental + + + Beschwöre einen Sturmelementar + Summon Storm Elemental + + + Erschaffe ein Amulett des wahren + Sehens + Create An Amulet Of True Sight + + + Erschaffe einen Ring der + Unsichtbarkeit + Create A Ring Of Invisibility + + + Miriams flinke Finger + Quick Fingers + + + Heimstein + Homestone + + + Wolfsgeheul + Timber Wolves + + + Blick des Basilisken + Gaze Of The Basilisk + + + Starkes Tor und feste Mauer + Strong Wall And Sturdy Gate + + + Geister bannen + Banish Spirits + + + Lebenslied festigen + Silence Dissonance + + + Ritual der Aufnahme + Rit of Acceptance + + + Weg der Bäume + Path Of Trees + + + Sog des Lebens + Ties Of Life + + + Heiliger Boden + Sacred Ground + + + Erschaffe einen magischen + Kräuterbeutel + Create A Magical Herb Pouch + + + Erwecke Ents + Awakening Of The Ents + + + Vertrauten binden + Bind Familiar + + + Segne Steinkreis + Bless Stone Circle + + + Rindenhaut + Barkskin + + + Verwünschung + Hex + + + Kleine Flüche + Minor Curses + + + Feuerball + Fireball + + + Gabe des Chaos + Chaos Gift + + + Kleines Blutopfer + Lesser Sacrifice + + + Blutrausch + Blood Frenzy + + + Chaosfluch + Chaos Curse + + + Mächte des Todes + Animate Dead + + + Rosthauch + Winds Of Rust + + + Machtübertragung + Transfer Power + + + Feuerwand + Wall Of Fire + + + Fluch der Pestilenz + Curse Of Pestilence + + + Wahnsinn des Krieges + Madness of War + + + Beschwöre Schattendämonen + Summon Shadowdemons + + + Beschwörung eines Hitzeelementar + Summon Fire Elemental + + + Untote Helden + Undead Heroes + + + Erschaffe einen Gürtel der + Trollstärke + Create A Belt Of Troll + Strength + + + Astraler Riss + Astral Leak + + + Astrales Chaos + Astral Chaos + + + Feuerteufel + Fire Fiend + + + Pentagramm + Pentagram + + + Unheilige Kraft + Unholy Strength + + + Todeswolke + Death Cloud + + + Drachenruf + Call Dragons + + + Beschwöre Schattenmeister + Summon Shadowmasters + + + Erschaffe ein Flammenschwert + Create A Flamesword + + + Vertrauten rufen + Call Familiar + + + Chaossog + Chaos Gate + + + Traumsenden + Dream + + + Wahrsagen + Divination + + + Schattenritter + Shadow Knights + + + Grauen der Schlacht + Unspeakable Horrors + + + Seelenfrieden + Eternal Rest + + + Traumschlößchen + Castle Of Illusion + + + Traum der Magie + Dream Of Magic + + + Gestaltwandlung + Shapeshift + + + Traumlesen + Read Dreams + + + Schwere Glieder + Tiredness + + + Wiederbelebung + Resurrection + + + Traumbilder analysieren + Analyse Dreams + + + Schlechter Schlaf + Insomnia + + + Schlaf + Sleep + + + Traumdeuten + Mind Probe + + + Alp + Nightmare + + + Erschaffe ein Traumauge + Create a Visioneye + + + Erschaffe eine Sphäre der Unsichtbarkeit + Create a Sphere of Invisbility + + + Schöne Träume + Pleasant Dreams + + + Traumbilder entwirren + Remove Dreams + + + Vertrauten rufen + Call Familiar + + + Tod des Geistes + Mental Death + + + Süße Träume + Sweet Dreams + + + Traum von den Göttern + Dream of the gods + + + Göttliches Netz + Web of the Gods + + + Kraft der Natur + force of nature + + + Gesang der Götter + Song of the Gods + + + Göttliche Macht + Power of the Gods + + + + + Tötet die Feinde mit Säure. + Kills enemies with acid. + + + Tötet die Feinde mit Kälte. + Kills enemies with cold. + + + Tötet die Feinde mit Feuer. + Kills enemies with fire. + + + Verletzt alle Gegner. + Injures all enemies. + + + Ruft Schattenwesen. + Calls beings from shadow. + + + Panik. + Panic. + + + Entzieht Talentstufen und macht Schaden wie Großer Odem. + + + Dieser Zauber bewirkt eine schwere Störung des Astralraums. Innerhalb eines astralen Radius von Stufe/5 Regionen werden alle Astralwesen, die dem Zauber nicht wiederstehen können, aus der astralen Ebene geschleudert. Der astrale Kontakt mit allen betroffenen Regionen ist für Stufe/3 Wochen gestört. + + + + Diese vor dem Kampf zu zaubernde Ritual gibt den eigenen Truppen + einen zusätzlichen Bonus auf ihre Rüstung. Jeder Treffer + reduziert die Kraft des Zaubers, so dass der Schild sich irgendwann + im Kampf auflösen wird. + + + + + Dieser Zauber beschleunigt einige Kämpfer auf der eigenen Seite + so, dass sie während des gesamten Kampfes in einer Kampfrunde zweimal + angreifen können. + + + + + Dieser Zauber vermag dem Gegner ein geringfügig versetztes Bild der + eigenen Truppen vorzuspiegeln, so wie der Fisch im Wasser auch nicht + dort ist wo er zu sein scheint. Von jedem Treffer kann so die Hälfte + des Schadens unschädlich abgeleitet werden. Doch hält der Schild nur + einige Hundert Schwerthiebe aus, danach wird er sich auflösen. + Je stärker der Magier, desto mehr Schaden hält der Schild aus. + + + + + Zeichnet man diese Runen auf die Wände eines Gebäudes oder auf die + Planken eines Schiffes, so wird es schwerer durch Zauber zu + beeinflussen sein. Jedes Ritual erhöht die Widerstandskraft des + Gebäudes oder Schiffes gegen Verzauberung um 20%. + Werden mehrere Schutzzauber übereinander gelegt, so addiert + sich ihre Wirkung, doch ein hundertprozentiger Schutz läßt sich so + nicht erreichen. Der Zauber hält mindestens drei Wochen an, je nach + Talent des Magiers aber auch viel länger. + + + + + Mit Hilfe dieses Zauber kann der Magier eigene Aura im Verhältnis + 2:1 auf einen anderen Magier des gleichen Magiegebietes oder im + Verhältnis 3:1 auf einen Magier eines anderen Magiegebietes + übertragen. + + + + + Der Magier kann kurzzeitig in die Astralebene blicken und erfährt + so alle Einheiten innerhalb eines astralen Radius von Stufe/5 Regionen. + + + + + Mit Hilfe dieses magischen Gesangs kann der Magier eine Region in + Aufruhr wieder beruhigen. Die Bauernhorden werden sich verlaufen + und wieder auf ihre Felder zurückkehren. + + + + Aus 'Wanderungen' von Firudin dem Weisen: + 'In Weilersweide, nahe dem Wytharhafen, liegt ein kleiner Gasthof, der + nur wenig besucht ist. Niemanden bekannt ist, das dieser Hof + bis vor einigen Jahren die Bleibe des verbannten Wanderpredigers Grauwolf + war. Nachdem er bei einer seiner berüchtigten flammenden Reden fast die + gesammte Bauernschaft angeworben hatte, wurde er wegen Aufruhr verurteilt + und verbannt. Nur zögerlich war er bereit mir das Geheimniss seiner + Überzeugungskraft zu lehren.' + + + + Dieser mächtige Bann raubt dem Opfer seinen freien Willen + und unterwirft sie den Befehlen des Barden. Für einige Zeit wird das Opfer + sich völlig von seinen eigenen Leuten abwenden und der Partei des Barden + zugehörig fühlen. + + + + + Dieser mächtige Bann verhindert jegliche Attacken. Niemand in der + ganzen Region ist fähig seine Waffe gegen irgendjemanden zu erheben. + Die Wirkung kann etliche Wochen andauern. + + + + + Dieses Lied, das in die magische Essenz der Region gewoben wird, + schwächt die natürliche Widerstandskraft gegen eine + Verzauberung einmalig um 15%. Nur die Verbündeten des Barden + (HELFE BEWACHE) sind gegen die Wirkung des Gesangs gefeit. + + + + + Mit diesem Gesang verbreitet der Barde eine melancholische, traurige + Stimmung unter den Bauern. Einige Wochen lang werden sie sich in ihre + Hütten zurückziehen und kein Silber in den Theatern und Tavernen lassen. + + + + + Dieses magische Lied wird, einmal mit Inbrunst gesungen, sich in der + Region fortpflanzen, von Mund zu Mund springen und eine Zeitlang + überall zu vernehmen sein. Nach wie vielen Wochen der Gesang aus dem + Gedächnis der Region entschwunden ist, ist von dem Geschick des Barden + abhängig. Bis das Lied ganz verklungen ist, wird seine Magie allen + Verbündeten des Barden (HELFE BEWACHE), und natürlich auch seinen + eigenem Volk, einen einmaligen Bonus von 15% + auf die natürliche Widerstandskraft gegen eine Verzauberung + verleihen. + + + + + Mit Hilfe dieses magischen Gesangs überzeugt der Magier die Bauern + der Region, sich ihm anzuschließen. Die Bauern werden ihre Heimat jedoch + nicht verlassen, und keine ihrer Besitztümer fortgeben. Jede Woche + werden zudem einige der Bauern den Bann abwerfen und auf ihre Felder + zurückkehren. Wie viele Bauern sich dem Magier anschließen hängt von der + Kraft seines Gesangs ab. + + + + + Einem erfahrenen Magier wird irgendwann auf seinen Wanderungen ein + ungewöhnliches Exemplar einer Gattung begegnen, welches sich dem + Magier anschließen wird. + + + + + Dieses Ritual ermöglicht es, eine Einheit, egal welcher Art, in die + eigene Partei aufzunehmen. Der um Aufnahme Bittende muss dazu willig + und bereit sein, seiner alten Partei abzuschwören. Dies bezeugt er + durch KONTAKTIEREn des Magiers. Auch wird er die Woche über + ausschliesslich mit Vorbereitungen auf das Ritual beschäftigt sein. + Das Ritual wird fehlschlagen, wenn er zu stark an seine alte Partei + gebunden ist, dieser etwa Dienst für seine teuere Ausbildung + schuldet. Der das Ritual leitende Magier muss für die permanente + Bindung des Aufnahmewilligen an seine Partei naturgemäß auch + permanente Aura aufwenden. Pro Stufe und pro 1 permanente Aura kann + er eine Person aufnehmen. + + + + + Jede Verzauberung beeinflußt das Lebenslied, schwächt und verzerrt es. + Der kundige Barde kann versuchen, das Lebenslied aufzufangen und zu + verstärken und die Veränderungen aus dem Lied zu tilgen. + + + + + Wie Lebewesen, so haben auch Schiffe und Gebäude und sogar Regionen + ihr eigenes Lied, wenn auch viel schwächer und schwerer zu hören. + Und so, wie wie aus dem Lebenslied einer Person erkannt werden kann, + ob diese unter einem Zauber steht, so ist dies auch bei Burgen, + Schiffen oder Regionen möglich. + + + + + Dieser Kriegsgesang sät Panik in der Front der Gegner und schwächt + so ihre Kampfkraft erheblich. Angst wird ihren Schwertarm schwächen + und Furcht ihren Schildarm lähmen. + + + + + Wie viele magischen Gesänge, so entstammt auch dieser den altem + Wissen der Katzen, die schon immer um die machtvolle Wirkung der + Stimme wussten. Mit diesem Lied wird die Stimmung der Krieger + aufgepeitscht, sie gar in wilde Raserrei und Blutrausch versetzt. + Ungeachtet eigener Schmerzen werden sie kämpfen bis zum + Tode und niemals fliehen. Während ihre Attacke verstärkt ist + achten sie kaum auf sich selbst. + + + + + Erliegt die Einheit dem Zauber, so wird sie dem Magier alles erzählen, + was sie über die gefragte Region weiß. Ist in der Region niemand + ihrer Partei, so weiß sie nichts zu berichten. Auch kann sie nur das + erzählen, was sie selber sehen könnte. + + + + + Aufzeichung des Vortrags von Selen Ard'Ragorn in Bar'Glingal: + 'Es heiss, dieser Spruch wäre wohl in den Spelunken der Westgassen + entstanden, doch es kann genausogut in jedem andern verrufenen + Viertel gewesen sein. Seine wichtigste Zutat ist etwa ein Fass + schlechtesten Weines, je billiger und ungesunder, desto + wirkungsvoller wird die Essenz. Die Kunst, diesen Wein in pure + Essenz zu destillieren, die weitaus anspruchsvoller als das einfache + Rezeptmischen eines Alchemisten ist, und diese dergestalt zu binden + und konservieren, das sie sich nicht gleich wieder verflüchtigt, wie + es ihre Natur wäre, ja, dies ist etwas, das nur ein Meister des + Cerddor vollbringen kann. Nun besitzt Ihr eine kleine Phiola mit + einer rubinrotschimmernden - nun, nicht flüssig, doch auch nicht + ganz Dunst - nennen wir es einfach nur Elixier. Doch nicht dies ist + die wahre Herausforderung, sodann muss, da sich ihre Wirkung leicht + verflüchtigt, diese innerhalb weniger Tage unbemerkt in das Getränk + des Opfers geträufelt werden. Ihr Meister der Betöhrung und + Verführung, hier nun könnt Ihr Eure ganze Kunst unter Beweis + stellen. Doch gebt Acht, nicht unbedacht selbst von dem Elixier zu + kosten, denn wer einmal gekostet hat, der kann vom Weine nicht mehr + lassen, und er säuft sicherlich eine volle Woche lang. Jedoch nicht + die Verführung zum Trunke ist die wahre Gefahr, die dem Elixier + innewohnt, sondern das der Trunkenheit so sicher ein gar + fürchterliches Leid des Kopfes folgen wird, wie der Tag auf die + Nacht folgt. Und er wird gar sicherlich von seiner besten Fähigkeit + einige Tage bis hin zu den Studien zweier Wochen vergessen haben. + Noch ein Wort der Warnung: Dieses ist sehr aufwendig, und so Ihr + noch weitere Zauber in der selben Woche wirken wollt, so werden sie Euch + schwerer fallen.' + + + + + Mit diesem Lied kann eine Einheit derartig betört werden, so dass + sie dem Barden den größten Teil ihres Bargelds und ihres Besitzes + schenkt. Sie behält jedoch immer soviel, wie sie zum Überleben + braucht. + + + + + Dieser einschmeichelnde Gesang kann fast jedes intelligente Monster + zähmen. Es wird von Angriffen auf den Magier absehen und auch seine + Begleiter nicht anrühren. Doch sollte man sich nicht täuschen, es + wird dennoch ein unberechenbares Wesen bleiben. + + + + + Dieser Zauber ermöglicht es dem Träumer, den Schlaf aller nichtaliierten + Einheiten (HELFE BEWACHE) in der Region so stark zu stören, das sie + vorübergehend einen Teil ihrer Erinnerungen verlieren. + + + + + Dieser mächtige Zauber kann einen Magier vor dem sicheren Tod + bewahren. Der Magier erschafft anhand einer kleinen Blutprobe einen + Klon von sich, und legt diesen in ein Bad aus Drachenblut und verdünntem + Wasser des Lebens. + Anschließend transferiert er in einem aufwändigen Ritual einen Teil + seiner Seele in den Klon. Stirbt der Magier, reist seine Seele in den + Klon und der erschaffene Körper dient nun dem Magier als neues Gefäß. + Es besteht allerdings eine geringer Wahrscheinlichkeit, dass die Seele + nach dem Tod zu schwach ist, das neue Gefäß zu erreichen. + + + + + Der Zauberer spricht eine Beschwörung über einen Teil der Region, + und in der Folgewoche entstehen dort Irrlichter. + Wer durch diese Nebel wandert, wird von Visionen geplagt und + in die Irre geleitet. + + + + + Dieses mächtige Ritual öffnet ein Tor in die Elementarebene der + Hitze. Eine grosse Dürre kommt über das Land. Bauern, Tiere und + Pflanzen der Region kämpfen um das nackte Überleben, aber eine + solche Dürre überlebt wohl nur die Hälfte aller Lebewesen. + Der Landstrich kann über Jahre hinaus von den Folgen einer + solchen Dürre betroffen sein. + + + + + Mit Hilfe dieses aufwändigen Rituals läßt der Druide einen Teil seiner Kraft + dauerhaft in den Boden und die Wälder der Region fliessen. Dadurch wird + das Gleichgewicht der Natur in der Region für immer verändert, und in + Zukunft werden nur noch die anspruchsvollen, aber kräftigen + Mallorngewächse in der Region gedeihen. + + + + + Dieses Ritual beschört einen großen Wasserelementar aus den + Tiefen des Ozeans. Der Elementar erzeugt einen gewaltigen + Strudel, einen Mahlstrom, welcher alle Schiffe, die ihn passieren, + schwer beschädigen kann. + + + + + Mit Hilfe dieses Zaubers kann sich der Magier permanent in einen + mächtigen Wyrm verwandeln. Der Magier behält seine Talente und + Möglichkeiten, bekommt jedoch die Kampf- und Bewegungseigenschaften + eines Wyrms. Der Odem des Wyrms wird sich mit steigendem Magie-Talent + verbessern. Der Zauber ist sehr kraftraubend und der Wyrm wird einige + Zeit brauchen, um sich zu erholen. + + + + + Mit Hilfe dieses magischen Gesangs versetzt der Magier eine ganze + Region in Aufruhr. Rebellierende Bauernhorden machen jedes Besteuern + unmöglich, kaum jemand wird mehr für Gaukeleien Geld spenden und + es können keine neuen Leute angeworben werden. Nach einigen Wochen + beruhigt sich der Mob wieder. + + + + + Der Magier kann mit Hilfe dieses Zaubers aus der Astral- in die + materielle Ebene blicken und die Regionen und Einheiten genau + erkennen. + + + + + Einem erfahrenen Magier wird irgendwann auf seinen Wanderungen ein + ungewöhnliches Exemplar einer Gattung begegnen, welches sich dem + Magier anschließen wird. + + + + + Dieses kräftezehrende Ritual beschwört mit Hilfe einer Kugel aus + konzentriertem Laen einen gewaltigen Erdelementar und bannt ihn + in ein Gebäude. Dem Elementar kann dann befohlen werden, das + Gebäude mitsamt aller Bewohner in eine Nachbarregion zu tragen. + Die Stärke des beschworenen Elementars hängt vom Talent des + Magiers ab: Der Elementar kann maximal [Stufe-12]*250 Größeneinheiten + große Gebäude versetzen. Das Gebäude wird diese Prozedur nicht + unbeschädigt überstehen. + + + + Dieses Amulett in Gestalt einer orkischen Matrone + unterdrückt den Fortpflanzungstrieb eines einzelnen Orks sehr + zuverlässig. + Ein Ork mit Amulett der Keuschheit wird sich nicht mehr vermehren. + + + Dieser Zauber ermöglicht dem Magier, gezielt eine + bestimmte Verzauberung einer Einheit, eines Schiffes, Gebäudes oder auch + der Region aufzulösen. + This spell allows a magician to remove a specific + enchantment from a unit, ship, bulding or region. + + + Ein Schauer von Meteoren regnet über das Schlachtfeld. + A meteor shower rains down on the battlefield. + + + 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. + 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. + + + Mit dieser Formel bindet der Magier auf ewig die + Kräfte + der Erde in die Mauern des Gebäudes. Ein solchermaßen verzaubertes + Gebäude + ist gegen den Zahn der Zeit geschützt und benötigt keinen Unterhalt + mehr. + With this spell, the magician binds the power of the + earth into the walls of a building for all eternity. Such a building is + immune to the sands of time and needs no maintenance cost. + + + Ein Magier, der sich in der astralen Ebene befindet, + kann mit Hilfe dieses Zaubers andere Einheiten zu sich holen. Der Magier + kann (Stufe-3)*15 GE durch das kurzzeitig entstehende Tor schicken. Ist + der Magier erfahren genug, den Zauber auf Stufen von 13 oder mehr zu + zaubern, kann er andere Einheiten auch gegen ihren Willen auf die + andere + Ebene zwingen. + A magician in the astral plane can summon units from + the + material world. The magician can bring (level-3)*15 GE through the + temporary portal. If he is experienced enough to cast the spell at at + least level 13, he can even summon units against their will. + + + Ein Magier, welcher sich in der materiellen Welt + befindet, kann er mit Hilfe dieses Zaubers Einheiten aus der + angrenzenden + Astralwelt herbeiholen. Ist der Magier erfahren genug, den Zauber auf + Stufen von 13 oder mehr zu zaubern, kann er andere Einheiten auch gegen + ihren Willen in die materielle Welt zwingen. + A magician in the material world can summon units from + the adjacent part of the astral plane. If he is experienced enough to + cast + the spell at at least level 13, he can even summon units against their + will. + + + Mit Hilfe dieses Zaubers kann der Magier einem anderen + Magier seine Aura gegen dessen Willen entziehen und sich selber + zuführen. + Aided by this spell, a magician can steal another + magician's aura against his will. + + + Diese magischen Runen bringen ein Boot oder Langboot + für + eine Woche zum fliegen. Damit kann dann auch Land überquert werden. Die + Zuladung von Langbooten ist unter der Einwirkung dieses Zaubers auf 100 + Gewichtseinheiten begrenzt. Für die Farbe der Runen muss eine spezielle + Tinte aus einem Windbeutel und einem Schneekristall angerührt werden. + These magic runes allow a boat or longboat to fly for + a + week. The boat can only carry 100 weight units. The enchanted ink's + components include a windbag and a snowcrystal petal. + + + Diese praktische Anwendung des theoretischen Wissens um + Raum und Zeit ermöglicht es, den Zeitfluß für einige Personen zu + verändern. Auf diese Weise veränderte Personen bekommen für einige + Wochen doppelt soviele Bewegungspunkte und doppelt soviele Angriffe + pro Runde. + Abstract theories of space and time at last find + practical application in this spell which warps the very fabric of + time around a person. Such a person has twice as many movement points + and doubles their attacks per round for a few weeks. + + + Dieser Zauber läßt eine Welle aus purer Kraft über die + gegnerischen Reihen hinwegfegen. Viele Kämpfer wird der Schock so + benommen machen, daß sie für einen kurzen Moment nicht angreifen + können. + A wave of pure force spreads out from the magician, + crashing into the enemy ranks. Many warriors are thrown off balance and + are briefly unable to attack. + + + Mit diesem Zauber kann der Magier eine Zone der + astralen + Schwächung erzeugen, ein lokales Ungleichgewicht im Astralen Feld. + Dieses + Zone wird bestrebt sein, wieder in den Gleichgewichtszustand zu + gelangen. + Dazu wird sie jedem in dieser Region gesprochenen Zauber einen Teil + seiner Stärke entziehen, die schwächeren gar ganz absorbieren. + This spell allows a magician to create a local + instability in the astral field. This zone needs to return to its + equilibrium, soaking up part of the power of all spells cast in the + region + - or even all of some of the weaker ones. + + + Dieser Zauber ermöglicht dem Magier, Verzauberungen + einer Einheit, eines Schiffes, Gebäudes oder auch der Region aufzulösen. + This spell lets a magician destroy spells on a ship, + building or region. + + + Dieser Zauber verstärkt die natürliche + Widerstandskraft + gegen Magie. Eine so geschützte Einheit ist auch gegen Kampfmagie + weniger + empfindlich. Pro Stufe reicht die Kraft des Magiers aus, um 5 Personen + zu + schützen. + This spell enhances natural magic resistence. + Protected + units are less vulnerable to battle magic. The spell protects 5 people + per + level. + + + Alte arkane Formeln ermöglichen es dem Magier, sich + und + andere in die astrale Ebene zu schicken. Der Magier kann (Stufe-3)*15 GE + durch das kurzzeitig entstehende Tor schicken. Ist der Magier erfahren + genug, den Zauber auf Stufen von 11 oder mehr zu zaubern, kann er andere + Einheiten auch gegen ihren Willen auf die andere Ebene zwingen. + Ancient arcane formulae permit the magician to + transport + himself or other units into the astral plane. The magician can transport + (level-3) * 15 GE through the transient portal. If the magician is + experienced enough to cast level 11 spells, he can also transport units + against their will. + + + Der Magier konzentriert sich auf die Struktur der + Realität und kann so die astrale Ebene verlassen. Er kann insgesamt + (Stufe-3)*15 GE durch das kurzzeitig entstehende Tor schicken. Ist der + Magier erfahren genug, den Zauber auf Stufen von 11 oder mehr zu + zaubern, + kann er andere Einheiten auch gegen ihren Willen auf die andere Ebene + zwingen. + By concentrating on the structure of reality, the + magician can breach it and thus briefly make a gateway to leave the + astral + plane. He can transport up to (level-3)*15 GE through the portal. If the + magician is able to cast at at least level 11, he can even transport + other + units against their will. + + + Mit diesem Spruch kann der Magier versuchen, die + Verzauberungen + eines einzelnen angegebenen Objekts zu erkennen. Von + allen Sprüchen, + die seine eigenen Fähigkeiten nicht überschreiten, wird + er einen + Eindruck ihres Wirkens erhalten können. Bei stärkeren + Sprüchen + benötigt er ein wenig Glück für eine gelungene Analyse. + With this spell the magician can try to identify the + enchantments of + a single object. He will get an impression of the + operation of all + spells that don't exceed his own capabilities. For more + powerful + spells he will need some luck for a successful analysis. + + + Dieser Zauber wird die gesamte Ausrüstung der + Zieleinheit für + einige Zeit vor den Blicken anderer verschleiern. Der + Zauber + schützt nicht vor Dieben und Spionen. + This spell will hide the whole equipment of a target + unit from the + looks of others. It will not protect against thieves or + spies. + + + Dieser Zauber legt ein antimagisches Feld um die Magier der Feinde + und behindert ihre Zauber erheblich. Nur wenige werden die Kraft + besitzen, das Feld zu durchdringen und ihren Truppen in der Schlacht + zu helfen. + This spell creates an antimagic field around the mages of the enemies + and considerably hinders their spells. Only few will have the power to + break through the field and be able to help their troops in battle. + + + Dieser Zauber verhindert, dass ein Teil der sonst im Kampf zerstörten + Gegenstände beschädigt wird. Die Verluste reduzieren sich um 5% pro + Stufe des Zaubers bis zu einem Minimum von 25%. + This spell prevents damage to a portion of the items that would + otherwise be lost in battle. The loss of items is reduced by 5% for + every level of the spell, up to a minimum of 25%. + + + + Dieses Lied zähmt selbst den wildesten + Ork und macht ihn friedfertig und sanftmütig. Jeder + Gedanke, dem Sänger zu schaden, wird ihm entfallen. + Unbehelligt kann der Magier in eine Nachbarregion + ziehen. + This little melody calms even the + wildest orc to a gentle and serene creature who will not + even think about putting the singer to harm. The magician + may travel to a neighboring region without being + harassed by annoying troublemakers. + + + Nicht nur der Feldscher kann den + Verwundeten einer Schlacht helfen. Die Barden kennen + verschiedene Lieder, die die Selbstheilungskräfte des + Körpers unterstützen. Dieses Lied vermag Wunden zu + schließen, gebrochene Knochen zu richten und selbst + abgetrennte Glieder wieder zu regenerieren. + The field medic isn't the only one + capable of tending the wounds of battle. The bards know + a number of magic melodies to enhance the natural + healing process of the body. This song is able to close + wounds, mend fractured bones and even regenerate lost + lims. + + + Ein gar machtvoller Gesang aus den + Überlieferungen der Katzen, der tief in die Herzen der + Feinde dringt und ihnen Mut und Hoffnung raubt. Furcht + wird sie zittern lassen und Panik ihre Gedanken + beherrschen. Voller Angst werden sie versuchen, den + gräßlichen Gesängen zu entrinnen und fliehen. + This antique, powerful song, passed + down by the cats, will penetrate the hearts of the enemy + and bereave them of courage and hope. Both their minds + and bodies will be ruled by panic. Shivering with fear, + they will flee from the dreadful chants and try to make + their escape. + + + Aus den uralten Gesängen der Katzen + entstammt dieses magisches Lied, welches vor einem + Kampfe eingesetzt, einem entscheidende strategische + Vorteile bringen kann. Wer unter den Einfluss dieses + Gesangs gelangt, der wird seiner Umgebung nicht achtend + der Melodie folgen, sein Geist wird verwirrt und + sprunghaft plötzlichen Eingebungen nachgeben. So sollen + schon einst wohlgeordnete Heere plötzlich ihre Schützen + weit vorne und ihre Kavallerie bei den Lagerwachen + kartenspielend wiedergefunden haben (oder ihren Anführer + schlafend im lange verlassenen Lager, wie es in den + Großen Kriegen der Alten Welt wirklich geschehen sein + soll). + If is used before battle, this chant, + taken from the ancient tunes of the cats, might give you + the critical tactical advantage. Those under the spell's + influence will act uncoordinated and inconsequent due to + the nonsensical ideas planted into their minds through + the melody. So it is supposed to have come to pass that + well-organized armies found their archers up at the + front (while the cavalry was back at the camp playing + cards) or that even a famous general overslept a battle + in his tent, as tale-tellers claim it really happened + during the Great Wars in the Old World. + + + Dieser alte Schlachtengesang hebt die + Moral der eigenen Truppen und und hilft ihnen auch der + angsteinflößenden Aura dämonischer und untoter Wesen zu + widerstehen. Ein derartig gefestigter Krieger wird auch + in schwierigen Situationen nicht die Flucht ergreifen + und sein überlegtes Verhalten wird ihm manch Vorteil in + der Verteidigung geben. + This ancient battle chant lifts the + spirit of your troops and helps them withstand even the + fear-inspiring aura of demonic and undead beings. A + fighter thus fortified against evil will not flee even + in the face of terror, and his defenses will be strengthened. + + + Mit Hilfe dieses Zaubers kann der + Magier eigene Aura im Verhältnis 2:1 auf einen anderen + Magier des gleichen Magiegebietes übertragen. + This spell enables the wizard to + transfer aura at a rate of 2:1 to another sorcerer of + the same school of magic. + + + Alle lebenden Wesen haben ein eigenes + individuelles Lebenslied. Nicht zwei Lieder gleichen + sich, auch wenn sich alle Lieder einer Art ähneln. Jeder + Zauber verändert dieses Lied auf die eine oder andere + Art und gibt sich damit zu erkennen. Dieser Gesang + hilft, jene Veränderungen im Lebenslied einer Person zu + erlauschen, welche magischer Natur sind. Alle + Verzauberungen, die nicht stärker maskiert sind als Eure + Fähigkeit, werdet Ihr so entschlüsseln und demaskieren + können. + Each and every living being has its + own, individual 'life-song'. No two of these songs are + alike, even though songs of creatures of the same + species are similar. Every spell alters this song of + life in one way or the other and this can be identified. + By casting this spell, the bard can detect all those + magic variations in a person's 'life-song'. You will be + able to decipher all enchantments or spells, which + aren't disguised beyond your capability. + + + Dieser schrille Gesang hallt über das + ganze Schlachtfeld. Die besonderen Dissonanzen in den + Melodien machen es Magier fast unmöglich, sich auf ihre + Zauber zu konzentrieren. + The screeching sounds of this melody + can be heard across the whole battlefield. Wizards + exposed to these special dissonances find it nearly + impossible to concentrate on their spells. + + + Die verzauberte Einheit beginnt + hemmungslos zu plappern und erzählt welche Talente sie + kann, was für Gegenstände sie mit sich führt und sollte + sie magisch begabt sein, sogar welche Zauber sie + beherrscht. Leider beeinflußt dieser Zauber nicht das + Gedächnis, und so wird sie sich im nachhinein wohl + bewußt werden, dass sie zuviel erzählt hat. + The persons of the bewitched unit + starts to babble without control about what it is said, + speaking about their talents, the objects they carry or + wear and if the unit is a magician, he or she will even list + the spells they know. Unfortunately, this spell does not + influence the memory of the subjects and afterwards, the + enchanted will realize that they probably talked too + much. + + + Man befeuchte einen kluftfreien Block + aus feinkristallinen Gestein mit einer Phiole des + Lebenswassers bis dieses vollständig vom Gestein + aufgesogen wurde. Sodann richte man seine Kraft auf die + sich bildende feine Aura des Lebens und forme der + ungebundenen Kraft ein Gehäuse. Je mehr Kraft der Magier + investiert, desto mehr Golems können geschaffen werden, + bevor die Aura sich verflüchtigt. Jeder Golem hat jede + Runde eine Chance von 10 Prozent zu Staub zu zerfallen. + Gibt man den Golems die Befehle MACHE BURG oder MACHE + STRASSE, so werden pro Golem 4 Steine verbaut und der + Golem löst sich auf. + 'Take a flawless block of crystaline + stone and humidify it with a vial of Water Of Life until + the potion has been soaked up completely. Then focus + your power on the forming aura of life and shape a + container for the unbound forces'. The more power a magician + invests, the more golems can be created before the aura + dissipates. Every week, there is a 10 percent chance + that the golem will crumble to dust. If you command a + golem to 'MAKE CASTLE' or 'MAKE ROAD', it will turn + itself into 4 stones that it uses in construction, and + disintegrate afterwards. + + + Je mehr Kraft der Magier investiert, + desto mehr Golems können geschaffen werden. Jeder Golem + hat jede Runde eine Chance von 15 Prozent zu Staub zu + zerfallen. Gibt man den Golems den Befehl MACHE + SCHWERT/BIHÄNDER oder MACHE + SCHILD/KETTENHEMD/PLATTENPANZER, so werden pro Golem 4 + Eisenbarren verbaut und der Golem löst sich auf. + The more power a magician invests, the + more golems can be created before the aura dissipates. + Each golem has a 15% chance per week to turn to dust. If + you command a golem to 'MAKE SWORD/MAKE CLAYMORE' or + 'MAKE SHIELD/CHAINMAIL/PLATEMAIL',it will work 5 iron + ingots and disintegrate afterwards. + + + Wo sonst aus einem + Stecken nur ein Baum sprießen konnte, so treibt nun jeder + Ast Wurzeln. + Every branch becomes a sturdy + oak where before only one could be grown from a log. + + + Mit diesem Ritual wird eine dunkle + Gewitterfront beschworen, die sich + unheilverkündend über der Region auftürmt. Der + magische Regen wird alles Erz rosten lassen. + Eisenwaffen und Rüstungen werden schartig und rostig. + Die Zerstörungskraft des + Regens ist von der investierten Kraft des + Magiers abhängig. Für jede Stufe können bis zu + 10 Eisenwaffen betroffen werden. Ein Ring der + Macht verstärkt die Wirkung wie eine zusätzliche + Stufe. + This ritual conjurs up a dark + thunderstorm that affects a whole region. The + magic rain will let rust any ore. Iron weapons and + armor will get rusty. The exact number of + items affected by the rain depends on the + ammount of power invested by the magician. Up to ten + weapons can be destroyed per level - a Ring Of + Power increases the effect like an additional + level. + + + Dieser Zauber ermöglicht es dem Magier + Insekten auf magische Weise vor der lähmenden + Kälte der Gletscher zu bewahren. Sie können + Gletscher betreten und dort normal agieren. Der + Spruch wirkt auf Stufe*10 Insekten. Ein Ring der + Macht erhöht die Menge der verzauberbaren + Insekten zusätzlich um 10. + This spell enables the druid to + magically protect insects from the paralysing + cold of a glacier. Under the effect of this + spell, insects are able to enter glaciers and + act normally there. Ten insects per level can be + protected in this way. A Ring Of Power increases + the number by additional ten. + + + Im Kampf ruft der Magier die + Elementargeister der Kälte an und bindet sie an + sich. Sodann kann er ihnen befehlen, den Gegner + mit Hagelkörnern und Eisbrocken zuzusetzen. + During a battle the druid calls the + Elemental Spirits Of Cold and binds them to + himself. Then he commands them to attack his + foes with hail and ice missiles. + + + Erschafft einen Wächtergeist, der + in Gletschern und Bergen Eisen- und Laenabbau durch + nichtalliierte Parteien (HELFE BEWACHE) verhindert, + solange er die Region bewacht. Der Bergwächter ist + an den Ort der Beschwörung gebunden. + Creates a guardian spirit on a + mountain or glacier that keeps all factions that + are not allied (HELP GUARD) from mining iron or + laen as long as it guards the region. The + Mountain Guardian is bound to the location where + it has been summoned. + + + Durch Ausführung dieser Rituale ist + der Magier in der Lage einen mächtigen + Erdelementar zu beschwören. Solange dieser in + den Boden gebannt ist, wird kein Regen die Wege + aufweichen und kein Fluß Brücken zerstören + können. Alle Reisende erhalten damit die + gleichen Vorteile, die sonst nur ein ausgebautes + gepflastertes Straßennetz bietet. Selbst Sümpfe + und Gletscher können so verzaubert werden. Je + mehr Kraft der Magier in den Bann legt, desto + länger bleibt die Straße bestehen. + By performing these rituals the druid + is able to summon a powerful earth elemental. As + long as this elemental remains bound to a + region, no rain can turn a path into mud and no + river can destroy a bridge. All travelers in + this region gain the same advantages as if they + were travelling on a road. Even swamps and + glaciers can be enchanted in this way. The more + power the druid invests, the longer the roads + remain intact. + + + Die Anrufung der Elementargeister des + Windes beschwört plötzliche Windböen, kleine + Windhosen und Luftlöcher herauf, die die + gegnerischen Schützen behindern werden. + Calling the Elemental Spirits Of Wind + conjurs up sudden breezes, small whirlwinds and + minor turbulences that will hinder enemy + archers. + + + Diese Ritual verstärkt die Wirkung des + magischen Trankes um ein vielfaches. Wo sonst aus einem + Stecken nur ein Baum sprießen konnte, so treibt nun jeder + Ast Wurzeln. + This ritual greatly increases the + effect of the potion. Now every branch becomes a mallorn + tree where before only one could be grown from a log. + + + Der Magier zwingt mit diesem Ritual + die Elementargeister des Wassers in seinen + Dienst und bringt sie dazu, das angegebene + Schiff schneller durch das Wasser zu tragen. + Zudem wird das Schiff nicht durch ungünstige + Winde oder Strömungen beeinträchtigt. + While being aboard a ship, the druid + uses this ritual to force the Elemental Spirits + Of Water to serve him and commands them to carry + the ship across the water at a higher speed. In + addition, the ship will not be affected by + unfavourable winds or currents. + + + Nicht nur der Feldscher kann den + Verwundeten einer Schlacht helfen. Druiden + vermögen mittels einer Beschwörung der + Elementargeister des Lebens Wunden zu schließen, + gebrochene Knochen zu richten und selbst + abgetrennte Glieder wieder zu regenerieren. + Combat medics are not the only ones + who can help those who got injured during a + battle. Druids are, with the help of a summons + of + the Elemental Spirits Of Life, able to heal + wounds, mend broken bones or even regenerate + separated limbs as well. + + + Diese Beschwörung öffnet ein Tor in + die Ebene der Elementargeister des Windes. + Sofort erheben sich in der Umgebung des Tors + starke Winde oder gar Stürme und behindern alle + Schützen einer Schlacht. + This summons opens a gate to the plane + of Elemental Spirits Of Wind. Immediately, + strong winds or even storms will rise near the + gate and hinder all archers during a battle. + + + Dieses Ritual beschwört einige + Elementargeister der Magie und schickt sie in + die Reihen der feindlichen Magier. Diesen wird + das Zaubern für die Dauer des Kampfes deutlich + schwerer fallen. + This ritual summons some Elemental + Spirits Of Magic and sends them into the ranks + of the enemy mages. Casting spells will be much + harder for them during the battle. + + + Mit Hilfe dieses Zaubers kann der + Magier eigene Aura im Verhältnis 2:1 auf einen + anderen Magier des gleichen Magiegebietes + übertragen. + The caster can transfer aura at a + ratio of 2:1 to another member of the same + school of magic with the help of this spell. + + + Der Druide beschwört mit diesem Ritual + einen Elementargeist der Erde und bringt ihn + dazu, die Erde erbeben zu lassen. Dieses + Erdbeben wird alle Gebäude in der Region + beschädigen. + With this ritual the druid summons an + Elemental Spirit Of Earth that brings the ground + to shake. This earthquake damages all buildings + in the target region. + + + Die Beschwörung von Elementargeistern + der Stürme ist ein uraltes Ritual. Der Druide + bannt die Elementare in die Segel der Schiffe, + wo sie helfen, das Schiff mit hoher + Geschwindigkeit über die Wellen zu tragen. Je + mehr Kraft der Druide in den Zauber investiert, + desto größer ist die Zahl der Elementargeister, + die sich bannen lassen. Für jedes Schiff wird + ein Elementargeist benötigt. + Calling the Elemental Spirits Of Storm + is an ancient ritual. The druid binds the + elementals to a ship's sails where they can help + to carry the vessel across the waves at an + amazing speed. The more power the druid invests, + the greater is the number of spirits bound. Each + ship needs an own spirit. + + + Mit diesem Spruch erzeugt man ein Runenschwert. Die + Klinge des schwarzen Schwertes ist mit alten, magischen Runen verziert, + und ein seltsames Eigenleben erfüllt die warme Klinge. Um es zu + benutzen, + muss man ein Schwertkämpfer von beachtlichem Talent (7) sein. Der + Träger + des Runenschwertes erhält einen Talentbonus von +4 im Kampf und wird so + gut wie immun gegen alle Formen von Magie. + This spell creates a magical sword. It requires a + skill + of at least 7, but adds +4 to the combat skill of its' owner as well as + making them almost immune against magical attacks. + + + Dieser Beutel umschließt eine kleine Dimensionsfalte, + in + der bis zu 200 Gewichtseinheiten transportiert werden können, ohne dass + sie auf das Traggewicht angerechnet werden. Pferde und andere Lebewesen + sowie besonders sperrige Dinge (Wagen und Katapulte) können nicht in dem + Beutel transportiert werden. Auch ist es nicht möglich, einen + Zauberbeutel in einem anderen zu transportieren. Der Beutel selber wiegt + 1 + GE. + This bag encloses a dimensional rift in which up to + 200 + units of weight can be carries. Horses and other large objects cannot be + put into the bag. The bag itself has a weight of 1. + + + Dieses mächtige Ritual erschafft einen Ring der Macht. + Ein Ring der Macht erhöht die Stärke jedes Zaubers, den sein Träger + zaubert, als wäre der Magier eine Stufe besser. + A ring of power adds +1 to the power of each spell + cast + by its' wearer. + + + Der Spruch ermöglicht es einem Magier, + ein Amulett des Wahren Sehens zu erschaffen. Das + Amulett erlaubt es dem Träger, alle Einheiten, + die durch einen Ring der Unsichtbarkeit + geschützt sind, zu sehen. Einheiten allerdings, + die sich mit ihrem Tarnungs-Talent verstecken, + bleiben weiterhin unentdeckt. + This spell enables the caster to + create an Amulet Of True Sight. Wearing such an + amulet, a person can discover anyone wearing a + Ring of Invisibility. Anyway, units concealed by + the use of their stealth skill will remain + undiscovered. + + + Mit Hilfe dieses Zauber entzieht der Magier einem + Quarzkristall all seine magischen Energien. Der Kristall wird dann, wenn + er zu feinem Staub zermahlen und verteilt wird, die beim Zaubern + freigesetzten magischen Energien aufsaugen und die Kraft aller Zauber + reduzieren, welche in der betreffenden Woche in der Region gezaubert + werden. + This spell creates a portable crystal of antimagic + which can be used by anybody to reduce or even eliminate the power of + all spells cast in the region during the same week. + + + Die berühmte Bardin Miriam bhean'Meddaf war bekannt + für ihr außergewöhnliches Geschick mit der Harfe. Ihre Finger sollen + sich so schnell über die Saiten bewegt haben, das sie nicht mehr + erkennbar waren. Dieser Zauber, der recht einfach in einen Silberring + zu bannen ist, bewirkt eine um das zehnfache verbesserte + Geschicklichkeit und Gewandheit der Finger. (Das soll sie auch an + anderer Stelle ausgenutzt haben, ihr Ruf als Falschspielerin war + berüchtigt). Handwerker können somit das zehnfache produzieren, + und bei einigen anderen Tätigkeiten könnte dies ebenfalls von Nutzen + sein. + The famous bard Mirim was known for exceptionally + limber + play of the harp. Her spell, which is easy to ban into a little silver + ring, increases the wearer's dexterity by a factor of ten, which is siad + to be useful to both craftsmen and shady natures. + + + Mit diesem Spruch kann der Zauberer + einen Ring der Unsichtbarkeit erschaffen. Der + Träger des Ringes wird für alle Einheiten + anderer Parteien unsichtbar, egal wie gut ihre + Wahrnehmung auch sein mag. In einer unsichtbaren + Einheit muss jede Person einen Ring tragen. + With this spell the caster can create + a Ring Of Invisibility. The wearer of this ring + will be invisible to all units of other + factions, no matter how good their perception + skill may be. In an invisible unit, each person + must wear a Ring Of Invisibility. + + + Mit dieser Formel bindet der Magier + auf ewig die Kräfte der Erde in die Mauern der + Burg, in der er sich gerade befindet. Weder + magisch noch mit schwerem Geschütz können + derartig gestärkte Mauern zerstört werden, und + auch das Alter setzt ihnen weniger zu. Das + Gebäude bietet sodann auch einen besseren Schutz + gegen Angriffe mit dem Schwert wie mit Magie. + With this spell the druid eternally + binds the powers of earth to the walls of the + castle in which he currently is. No magic and no + ballistic attacks will ever be able to destroy a + wall that has been fortified in this way and the + castle will also be less affected by aging. In + addition, the building will provide a better + protection against attacks by sword or by magic. + + + Nicht wenige Druiden freunden sich im + Laufe ihres Lebens in der Natur mit den ältesten + Freunden der großen Völker an. Sie erlernen, mit + einem einzigen heulenden Ruf viele ihrer Freunde + herbeizurufen, um ihnen im Kampf beizustehen. + During their life in the wilderness, + many druids make friends with the wolves who are + the oldest friends of the great races. They + learn to call many of them with a single howl to + aid them in combat. + + + Dieser schwierige, aber effektive + Kampfzauber benutzt die Elementargeister des + Steins, um eine Reihe von Gegnern für die Dauer + des Kampfes in Stein zu verwandeln. Die + betroffenen Personen werden nicht mehr kämpfen, + können jedoch auch nicht verwundet werden. + This complicated but effective spell + uses the Elemental Spirits Of Stone to turn a + number of enemies to stone for the duration of + combat. The affected persons won't be able to + fight any more, but they can't be wounded + either. + + + Mit dieser Formel bindet der Magier zu + Beginn eines Kampfes einige Elementargeister des + Fels in die Mauern des Gebäudes, in dem er sich + gerade befindet. Das Gebäude bietet sodann einen + besseren Schutz gegen Angriffe mit dem Schwert + wie mit Magie. + At the beginning of a battle, the + magician binds some Elemental Spirits Of Rock to + the walls of the builing in which he currently + is. The structure will then provide a better + protection against attacks by sword or by magic. + + + Wie die alten Lehren der Druiden + berichten, besteht das, was die normalen Wesen + Magie nennen, aus Elementargeistern. Der Magier + beschwört und bannt diese in eine Form, um den + gewünschten Effekt zu erzielen. Dieses Ritual + nun vermag es, in diese Welt gerufene + Elementargeister zu vertreiben, um so ein Objekt + von Magie zu befreien. + Old legends of the druids say that + what normal people call 'magic' consists of + elemental spirits. A magician summons these + spirits and binds them to various forms to + achieve the desired effects. This ritual is able + to expel any elemental spirits that have been + summoned to this world and thereby dispels any + magic on the target. + + + Große Macht liegt in Orten, an denen + das Leben pulsiert. Der Druide kann diese Kraft + sammeln und so ein Tor in die Welt der + Geistwesen erschaffen. Der Druide kann dann + Stufe*5 Gewichtseinheiten durch das Tor + entsenden. + A great power lies within those places + that are pulsing with life. A druid can focus + this power and thereby create a gate into the + World Of Spirits. He can then send level*5 + weight units of living or dead matter through + the gate. + + + Ein Druide, den es in die Welt der + Geister verschlagen hat, kann mit Hilfe dieses + Zaubers Stufe*5 Gewichtseinheiten in einen Wald + auf der materiellen Welt zurückschicken. + A druid who has traveled to the World + Of Spirits can use this spell to send level*5 + weight units of living or dead matter back to a + forest in the material world. + + + Dieses Ritual beschwört verschiedene + Naturgeister in den Boden der Region, welche + diese fortan bewachen. In einer so gesegneten + Region werden niemals wieder die Toten ihre + Gräber verlassen, und anderswo entstandene + Untote werden sie wann immer möglich meiden. + This ritual binds various rural + spirits to a specific territory to guard the + land. In a region blessed in this way the dead + won't ever rise from their graves again. + Existing undead also shun the sacred grounds and + will avoid entering the protected area whenever + possible. + + + Der Druide nehme etwas präpariertes + Leder, welches er in einem großen Ritual der + Reinigung von allen unreinen Geistern befreie, + und binde dann einige kleine Geister der Luft + und des Wassers in das Material. Aus dem so + vorbereiteten Leder fertige er nun ein kleines + Beutelchen, welches in ihm aufbewahrte Kräuter + besser zu konservieren vermag. + The druid takes some specially + prepared leather and performes a great ritual + during which the leather is cleansed of all + impure spirits. Then he binds some minor spirits + of air and water to the material. After + completing this process, the druid works the + enchanted leather into a small pouch which is + suitable to contain herbs, for it is able to + preserve them for a long time and prevents rot. + + + Mit Hilfe dieses Zaubers weckt der + Druide die in den Wälder der Region + schlummernden Ents aus ihrem äonenlangen Schlaf. + Die wilden Baumwesen werden sich ihm anschließen + und ihm beistehen, jedoch nach einiger Zeit + wieder in Schlummer verfallen. + With the help of this spell the druid + awakens the ents who are slumbering in the + forests of a region from aeons of sleep. These + strange tree-creatures will join him and aid his + cause, but after a while they will sink back + into their slumber. + + + Einem erfahrenen Druidem wird + irgendwann auf seinen Wanderungen ein + ungewöhnliches Exemplar einer Gattung begegnen, + welches sich dem Druiden anschließen wird. + Once during his travels, the seasoned + druid will meet an extraordinary creature of its + species that will join him. + + + Dieses Ritual segnet einen Steinkreis, + der zuvor aus Steinen und etwas Holz gebaut + werden muss. Die Segnung des Druiden macht aus + dem Kreis eine mächtige Stätte magischen + Wirkens, die Schutz vor Magie und erhöhte Aura- + Regeneration bewirkt. Man sagt, Jungfrauen seien + in der Umgebung von Steinkreisen seltsame Wesen + begegnet. + This ritual blesses a circle of stones + that has to be constructed from stones and some + wood before. The druid's blessing turns the + circle into a place of great magic that is + suitable for rituals of all kinds. It protects + from hostile magic and improves aura + regeneration. Virgins are said to have been + visited by strange creatures in the vicinity of + these places. + + + Das Ziel des Zauberers wird von einer + harmlosen Verwünschung heimgesucht. + The target of this spell becomes + subject to a harmless curse. + + + Dieses vor dem Kampf zu zaubernde Ritual gibt den + eigenen Truppen einen zusätzlichen Bonus auf ihre Rüstung. Jeder + Treffer reduziert die Kraft des Zaubers, so dass der Schild sich + irgendwann im Kampf auflösen wird. + Performing this ritual before going into battle gives + your troups an additional bonus to their armor. Every hit reduces the + energy of the spell, dissolving it at some point during battle. + + + Der Zauberer schleudert fokussiertes + Chaos in die Reihen der Gegner. Das ballförmige + Chaos wird jeden verwunden, den es trifft. + The sorcerer hurls a ball of + concentrated chaos into the ranks of his + enemies. It will seriously hurt anyone who gets + hit. + + + Der Magier öffnet seinen Geist den + Sphären des Chaos und wird so für einige Zeit + über mehr magische Kraft verfügen. Doch die + Hilfe der Herren der Sphären hat seinen Preis, + und so wird die Phase der Macht abgelöst von + einer Phase der Schwäche. + The sorcerer opens his mind to the + Spheres Of Chaos so that he can access a greater + ammount of magical power for a while. But the + help of the Chaos Lords has its price - and so + the period of power will be followed by a period + of weakness. + + + Mit diesem Ritual kann der Magier + einen Teil seiner Lebensenergie opfern, um dafür + an magischer Kraft zu gewinnen. Erfahrene + Ritualmagier berichten, das sich das Ritual, + einmal initiiert, nur schlecht steuern ließe und + die Menge der so gewonnenen Kraft stark + schwankt. So steht im 'Buch des Blutes' + geschrieben: 'So richte Er aus das Zeichen der + vier Elemente im Kreis des Werdens und Vergehens + und Weihe ein jedes mit einem Tropfen Blut. + Sodann begebe Er in der Mitten der Ewigen Vierer + sich und lasse Leben verrinnen, auf das Kraft + geboren werde.' + With this ritual the sorcerer can + sacrifice part of his life force in order to + gain raw astral power. Experienced mages report + that this ritual, once started, is hard to + control and that the ammount of power gained in + this way varies. + + + In diesem blutigen Ritual opfert der + Magier vor der Schlacht ein Neugeborenes vor den + Augen seiner Armee. Die so gerufenen Blutgeister + werden von den Soldaten Besitz ergreifen und sie + in einen Blutrausch versetzen. + During this bloody ritual the sorcerer + sacrifices a newborn child before a battle right + in front of his army. In this way he attracts + spirits of blood that will take control of the + soldiers who are present and force them into a + blood frenzy. + + + Dieser heimtückische Fluch + beeinträchtigt die magischen Fähigkeiten des + Opfers erheblich. Eine chaosmagische Zone um das + Opfer vermindert seine Konzentrationsfähigkeit + und macht es ihm sehr schwer Zauber zu wirken. + This wicked curse affects the magical + abilities of the target. A field of raw chaos + magic around the target lessens its + concentration and makes it very hard to cast any + spells. + + + Nächtelang muss der Schwarzmagier + durch die Friedhöfe und Gräberfelder der Region + ziehen um dann die ausgegrabenen Leichen beleben + zu können. Die Untoten werden ihm zu Diensten + sein, doch sei der Unkundige gewarnt, dass die + Beschwörung der Mächte des Todes ein + zweischneidiges Schwert sein kann. + For many nights the sorcerer has to + roam the graveyards and former battlefields of a + region in order to find corpses to animate. The + Undead will serve his will, but beware! Dealing + with the mysteries of unlife can be a dangerous + thing. + + + Mit diesem Ritual wird eine dunkle + Gewitterfront beschworen, die sich + unheilverkündend über der Region auftürmt. Der + magische Regen wird alles Erz rosten lassen und + so viele Waffen des Gegners zerstören. + This ritual conjurs up a dark + thunderstorm that affects a whole region. The + magic rain will let rust any ore and thus + destroy many weapons of the enemy. + + + Mit Hilfe dieses Zaubers kann der + Magier eigene Aura im Verhältnis 2:1 auf einen + anderen Magier des gleichen Magiegebietes + übertragen. + With the help of this spell, the + caster can transfer aura at a ratio of 2:1 to + another member of the same school of magic. + + + Der Zauberer erschafft eine Wand aus + Feuer in der angegebenen Richtung. Sie verletzt + jeden, der sie durchschreitet. + The spell creates an opaque wall of + fire in the gives direction that will harm + anyone passing through it. + + + In einem aufwendigen Ritual opfert der + Schwarzmagier einige Bauern und verteilt dann + die Leichen auf magische Weise in den Brunnen + der Region. + In a complicated ritual the sorcerer + sacrifices the lives of ten peasants and + magically spreads their corpses within the wells + of a region. + + + Vor den Augen der feindlichen Soldaten + opfert der Schwarzmagier die zehn Bauern in + einem blutigen, grausamen Ritual und beschwört + auf diese Weise Geister des Wahnsinns über die + feindlichen Truppen. Diese werden im Kampf + verwirrt reagieren und nicht in der Lage sein, + den Anweisungen ihrer Offiziere zu folgen. + Before the eyes of the enemy soldiers + the sorcerer sacrifices ten peasants in a bloody + ritual and thereby summons spirits of madness + upon the enemy troops. The enemy soldiers will + be in confusion during battle and no more be + able to follow the commands of their leaders. + + + Mit Hilfe dunkler Rituale beschwört + der Zauberer Dämonen aus der Sphäre der + Schatten. Diese gefürchteten Wesen können sich + fast unsichtbar unter den Lebenden bewegen, ihre + finstere Aura ist jedoch für jeden spürbar. Im + Kampf sind Schattendämonen gefürchtete Gegner. + Sie sind schwer zu treffen und entziehen ihrem + Gegner Kraft. + With the help of dark rituals the + sorcerer summons demons from the Sphere Of + Shadows. These fearsome creatures can walk + almost unseen among the living, but their dark + aura can be sensed by everyone. Shadow demons + are feared in combat for they are hard to hit + and have the ability to drain strength from + their victims. + + + Dieses Ritual beschwört wütende Elementargeister der + Hitze. Eine Dürre sucht das Land heim. Bäume verdorren, Tiere + verenden, und die Ernte fällt aus. Für Tagelöhner gibt es kaum noch + Arbeit in der Landwirtschaft zu finden. + This Ritual summons an angry elemental spirit that + puts a drought on the entire region. Trees wither, animals die of + thirst and the harvest is destroyed. Workers find little to no work + in farming. + + + Dieses Ritual bindet die bereits + entfliehenden Seelen einiger Kampfopfer an ihren + toten Körper, wodurch sie zu untoten Leben + wiedererweckt werden. Ob sie ehemals auf der + Seite des Feindes oder der eigenen kämpften, ist + für das Ritual ohne belang. + This ritual binds the escaping souls + of some casualties back to their dead bodies and + thus condemns them to an undead existance under + the control of the sorcerer. The ritual affects + the corpses of allies and foes alike - no matter + on which side of the battle the soldiers fought + before their death. + + + Dieses magische Artefakt verleiht dem + Träger die Stärke eines ausgewachsenen + Höhlentrolls. Seine Tragkraft erhöht sich auf + das 50fache und auch im Kampf werden sich die + erhöhte Kraft und die trollisch zähe Haut + positiv auswirken. + This artifact gives the one wearing it + the strength of a cavetroll. He will be able to + carry fifty times as much as normal and also in + combat his enhanced strength and tough troll + skin will serve him well. + + + Der Schwarzmagier kann mit diesem + dunklen Ritual einen Riss in das Gefüge der + Magie bewirken, der alle magische Kraft aus der + Region reißen wird. Alle magisch begabten in der + Region werden einen Großteil ihrer Aura + verlieren. + With this dark ritual the + chaossorcerer causes a deep rift to appear in + the astral balance that will tear all magical + power from a region. All spellcasters in that + region will lose most of their aura. + + + Dieses Ritual, ausgeführt vor einem + Kampf, verwirbelt die astralen Energien auf dem + Schlachtfeld und macht es so feindlichen Magier + schwieriger, ihre Zauber zu wirken. + This ritual, performed before a + battle, causes the astral energies on the + battlefield to whirl and churn and thereby makes + spellcasting more difficult for the enemy mages. + + + Diese Elementarbeschwörung ruft einen + Feuerteufel herbei, ein Wesen aus den tiefsten + Niederungen der Flammenhöllen. Der Feuerteufel + wird sich begierig auf die Wälder der Region + stürzen und sie in Flammen setzen. + This elemental summoning calls a fire + fiend, a creature from the deepest hell. The + demon will eagerly rush into the forests of a + region and set them ablaze. + + + Genau um Mitternacht, wenn die Kräfte + der Finsternis am größten sind, kann auch ein + Schwarzmagier seine Kräfte nutzen um + Verzauberungen aufzuheben. Dazu zeichnet er ein + Pentagramm in das verzauberte Objekt und beginnt + mit einer Anrufung der Herren der Finsternis. + Die Herren werden ihm beistehen, doch ob es ihm + gelingt, den Zauber zu lösen, hängt allein von + seiner eigenen Kraft ab. + At midnight, when the Powers of + Darkness are at their peak, the sorcerer can use + his powers to destroy enchantments. In order to + do so, he draws a pentagram on a surface of the + enchanted object and begins calling the Lords Of + Darkness. The Lords will aid him, but whether he + is able to undo the target spell or not depends + upon his own power. + + + Nur geflüstert wird dieses Ritual an + den dunklen Akademien an die Adepten + weitergegeben, gehört es doch zu den + finstersten, die je niedergeschrieben wurden. + Durch die Anrufung unheiliger Dämonen wird die + Kraft der lebenden Toten verstärkt und sie + verwandeln sich in untote Monster großer Kraft. + Only whispered the knowledge of + performing this ritual is passed to the adepts + of the dark academies, for it is one of the + darkest that has ever been written down. By + calling unholy demons the strength of the living + dead is greatly increased and they are turned + into undead monsters of immense power. + + + Mit einem düsteren Ritual und unter + Opferung seines eigenen Blutes beschwört der + Schwarzmagier einen großen Geist von der + Elementarebene der Gifte. Der Geist manifestiert + sich als giftgrüner Schwaden über der Region und + wird allen, die mit ihm in Kontakt kommen, + Schaden zufügen. + By performing a gruesome ritual and + sacrificing his own blood the Sorcerer conjurs + up a spirit from the Elemental Plane Of Poison. + It will take the form of a green cloud of toxic + gases that envelops a whole region and that will + harm anyone within. + + + Mit diesem dunklen Ritual erzeugt der + Magier einen Köder, der für Drachen einfach + unwiderstehlich riecht. Ob die Drachen aus der + Umgebung oder aus der Sphäre des Chaos stammen, + konnte noch nicht erforscht werden. Es soll + beides bereits vorgekommen sein. Der Köder hält + etwa 6 Wochen, muss aber in einem + drachengenehmen Terrain platziert werden. + Performing this dark ritual, the + sorcerer creates a bait that exhales an + irresistable scent to dragons. It is not known + whether the dragons come from surrounding + regions or if they have their origin in the + Sphere Of Chaos. The bait will exist for about + six weeks, but it must be placed in a tarrain + that is suitable for dragons. + + + Mit Hilfe dunkler Rituale beschwört + der Zauberer Dämonen aus der Sphäre der + Schatten. Diese gefürchteten Wesen können sich + fast unsichtbar unter den Lebenden bewegen, ihre + finstere Aura ist jedoch für jeden spürbar. Im + Kampf sind Schattenmeister gefürchtete Gegner. + Sie sind schwer zu treffen und entziehen ihrem + Gegner Kraft und Leben. + With the help of dark rituals the + sorcerer summons demons from the Sphere Of + Shadows. These fearsome creatures can walk + almost unseen among the living, but their dark + aura can be sensed by everyone. Shadowmasters + are feared in combat for they are hard to hit + and have the ability to drain strength and life + force from their victims. + + + 'Und so reibe das Blut eines wilden + Kämpfers in den Stahl der Klinge und beginne die + Anrufung der Sphären des Chaos. Und hast du + alles zu ihrem Wohlgefallen getan, so werden sie + einen niederen der ihren senden, das Schwert mit + seiner Macht zu beseelen...' + 'So take the blood of a fierce warrior + and apply it to the steel of the blade. Then + start calling the Spheres Of Chaos. If you did + everything to their pleasure, they will send a + minor one of their kind to fulfill the sword + with his power.' + + + Einem erfahrenen Magier wird + irgendwann auf seinen Wanderungen ein + ungewöhnliches Exemplar einer Gattung begegnen, + welches sich dem Magier anschließen wird. + During their travel, seasoned + magicians will occasionally befriend an extraordinary + creature of an unusual species that will join them. + + + Durch das Opfern von 200 Bauern kann + der Chaosmagier ein Tor zur astralen Welt + öffnen. Das Tor kann in der Folgewoche verwendet + werden, es löst sich am Ende der Folgewoche auf. + By sacrificing the lives of 200 + peasants, the chaossorcerer is able to open a + planar gate. This gate can be used during the + following week to transfer units to the astral + plane. It dissipates at the end of the following + week. + + + Der Zauberer sendet dem Ziel des + Spruches einen Traum. + The mentalist sends a dream to the + target of the spell. + Le mentaliste envoie un rêve à la + cible du sort. + + + Dieser Zauber vermag dem Gegner ein + geringfügig versetztes Bild der eigenen Truppen + vorzuspiegeln. Die Schattenritter haben keinen + effektiven Angriff und Verwundungen im Kampf + zerstören sie sofort. + This spell creates illusionary + duplicates of allied troops. The shadow knights + can't do real damage and are instantly destroyed + if wounded. + Ce sort crée des copies illusoires de + troupes alliées. Les guerriers illusoires ne + peuvent faire de dégats réels et sont + instantanément détruits lorsqu'ils sont blessés. + + + Der Traumweber beschwört vor dem + Kampf grauenerregende Trugbilder herauf, die + viele Gegner in Panik versetzen. Die Betroffenen + werden versuchen, vor den Trugbildern zu + fliehen. + Before a battle the mentalist creates + terrifying illusions of hideous creatures that + will cause panic among the enemies. Those who + believe in the illusions will try to flee from + battle. + + + Dieses magische Ritual beruhigt die + gequälten Seelen der gewaltsam zu Tode + gekommenen und ermöglicht es ihnen so, ihre + letzte Reise in die Anderlande zu beginnen. Je + Stufe des Zaubers werden ungefähr 50 Seelen ihre + Ruhe finden. Der Zauber vermag nicht, bereits + wieder auferstandene lebende Tote zu erlösen, da + deren Bindung an diese Welt zu stark ist. + This ritual calms the tortured souls + of those who died a violent death and finally + releases them to the Otherlands. About 50 souls + per level of the spell will be released. The + spell will not affect existing undead, because + they are too strongly tied to the Material + World. + + + Mit Hilfe dieses Zaubers kann der + Traumweber die Illusion eines beliebigen + Gebäudes erzeugen. Die Illusion kann betreten + werden, ist aber ansonsten funktionslos und + benötigt auch keinen Unterhalt. Sie wird einige + Wochen bestehen bleiben. + With this spell the mentalist can + create the illusion of any building. The + illusion can be entered, but it has no function + and requires no maintenance. It will remain + existing for several weeks. + + + Mit Hilfe dieses Zaubers kann der + Traumweber eigene Aura im Verhältnis 2:1 auf + einen anderen Traumweber übertragen. + With the help of this spell the + mentalist can transfer aura at a ratio of 2:1 to + another mentalist. + + + Mit Hilfe dieses arkanen Rituals + vermag der Traumweber die wahre Gestalt einer + Gruppe + zu verschleiern. Unbedarften Beobachtern + erscheint + sie dann als einer anderen Rasse zugehörig. + With the help of this ritual the + mentalist is able to conceal the true form of a + target unit. To unknowing observers all persons + in the target unit appear to be of a different + race. + + + Dieser Zauber ermöglicht es dem + Traumweber, in die Träume einer Einheit + einzudringen und so einen Bericht über die + Umgebung zu erhalten. + This spell enables the mentalist to + penetrate the dreams of a target unit and gather + information about that unit's surroundings. He + will receive a report from the corresponding + region. + + + Dieser Kampfzauber führt dazu, dass + einige Gegner im Kampf unter schwerer Müdigkeit + leiden. Die Soldaten verschlafen manchmal ihren + Angriff und verteidigen sich schlechter. + This combat spell causes several + enemies to suffer from an unnatural tiredness + during combat. The soldiers will defend + themselves worse than normal and sometimes sink + into a slumber instead of attacking. + + + Stirbt ein Krieger im Kampf so macht + sich seine Seele auf die lange Wanderung zu den + Sternen. Mit Hilfe eines Rituals kann ein + Traumweber versuchen, die Seele wieder + einzufangen und in den Körper des Verstorbenen + zurückzubringen. Zwar heilt der Zauber keine + körperlichen Verwundungen, doch ein Behandelter + wird den Kampf überleben. + When a warrior dies in a battle, his + soul begins its long journey to the stars. With + the help of this ritual, the mentalist can try + to catch those escaping souls and bring them + back to their bodies. The spell does not heal + physical injuries, but an affected person will + survive the battle. + + + Mit diesem Spruch kann der Traumweber + versuchen, die Verzauberungen einer einzelnen + Einheit zu erkennen. Von allen Sprüchen, die + seine eigenen Fähigkeiten nicht überschreiten, + wird er einen Eindruck ihres Wirkens erhalten + können. Bei stärkeren Sprüchen benötigt er ein + wenig Glück für eine gelungene Analyse. + With this spell the mentalist can + attempt to detect enchantments on a target unit. + He will get an idea of the effect of all spells + that don't exceed his own abilities. If a spell + is stronger, it takes a little luck for a + successful analysis. + + + Dieser Zauber führt in der betroffenen + Region für einige Wochen zu Schlaflosigkeit und + Unruhe. Den Betroffenen fällt das Lernen + deutlich schwerer. + This spell causes insomnia and + restlessness in a whole region for several + weeks. All affected persons will learn much + slower than normal. + + + Dieser Zauber läßt einige feindliche + Kämpfer einschlafen. Schlafende Kämpfer greifen + nicht an und verteidigen sich schlechter, sie + wachen jedoch auf, sobald sie im Kampf getroffen + werden. + This spell causes several enemies to + fall asleep. Sleeping warriors don't attack and + defend themselves worse than normal, but they'll + wake up if they get hit during combat. + + + Mit diesem Zauber dringt der + Traumweber in die Gedanken und Traumwelt seines + Opfers ein und kann so seine intimsten + Geheimnisse ausspähen. Seine Fähigkeiten, seinen + Besitz und seine Parteizugehörigkeit wird nicht + länger ungewiss sein. + With this spell the mentalist + penetrates the thoughts and dreams of his victim + to reveal his most intimate secrets. The + target's faction, skills and possessions will no + longer be unknown. + + + Der Magier beschwört ein kleines Monster, einen Alp. Dieses bewegt sich + langsam auf sein Opfer zu (das sich an einem beliebigen Ort an der Welt + befinden kann, der Magier oder seine Partei braucht es nicht zu sehen). + Sobald das Opfer erreicht ist, wird es gnadenlos gequält, und nur durch + einen starken Gegenzauber oder den Tod des beschwörenden Magiers kann + das Opfer wieder Frieden finden. Bei der Beschwörung des Alps verliert + der Magier einen kleinen Teil seiner Aura für immer. + The magician spawns a little monster, a nightmare. The nightmare slowly + approaches its victim (which may be at an arbitrary place in eressea, it + is not needed for the magician or his party to see the victim). As soon + as + the victim is reached the nightmare starts to torment it without mercy, + only a powerfull counter spell or the death of the casting magician can + redeem + the victim. When spawning the nightmare the magician loses a small amount + of + his aura forever. + + + Ein mit diesem Zauber belegtes Drachenauge, welches zum Abendmahle + verzehrt wird, erlaubt es dem Benutzer, in die Träume einer anderen + Person einzudringen und diese zu lesen. Lange Zeit wurde eine solche + Fähigkeit für nutzlos erachtet, bis die ehemalige waldelfische + Magistra für Kampfmagie, Liarana Sonnentau von der Akademie Thall, + eine besondere Anwendung vorstellte: Feldherren träumen vor großen + Kämpfen oft unruhig und verraten im Traum ihre Pläne. Dies kann dem + Anwender einen großen Vorteil im kommenden Kampf geben. Aber Vorsicht: + Die Interpretation von Träumen ist eine schwierige Angelegenheit. + An enchanted eye of a dragon gives the person who eats it for supper the + power to see + other people's dreams. For a long time this abillity was counted as + beeing + useless until + the former elfish mistress for theurgy of war, Liarana Sonnentau from + the + academy Thall, + presented a special appliance for this artefact: Before a battle + captains + often have an + uncomfortable sleep and betray their plans in their dreams. This might + give the user of + the artefact a small advantage in the upcoming battle, but be warned: + Interpreting dreams + is a difficult exercise. + + + Mit diesem Spruch kann der Zauberer eine Sphäre der + Unsichtbarkeit + erschaffen. Die Späre macht ihren Träger sowie neunundneunzig weitere + Personen in derselben Einheit unsichtbar. + Using this spell the magician can create a Sphere of + Invisibility. This artefact hides the person bearing it and one hundred + persons in the same unit. + + + Dieser Zauber ermöglicht es dem + Traumweber, den Schlaf aller aliierten Einheiten + in + der Region so zu beeinflussen, dass sie für + einige + Zeit einen Bonus in allen Talenten bekommen. + This spell allows the mentalist to + influence the sleep of all allied units in a + region + in such a way that they will gain a bonus to all + talents for some time. + + + Dieser Zauber ermöglicht es dem + Traumweber die natürlichen und aufgezwungenen + Traumbilder einer Person, eines Gebäudes, + Schiffes oder einer Region zu unterscheiden und + diese zu entwirren. + This spell allows the mentalist to + distinguish between the natural and unnatural + dreams of a person, a ship, a building or a + region and remove those that are of magical + origin. + + + Aus 'Die Gesänge der Alten' von + Firudin dem Weisen: 'Diese verführerische kleine Melodie + und einige einschmeichelnde Worte überwinden das + Misstrauen der Bauern im Nu. Begeistert werden sie sich + Euch anschliessen und selbst Haus und Hof in Stich + lassen.' + From the 'Songs of the Elder' by + Firudin the Sage: 'This enticing little melody and its + ingratiating words will lure the peasants in no time. + They will leave home and hearth to follow your lead.' + + + Dieser fröhliche Gesang wird sich wie + ein Gerücht in der Region ausbreiten und alle Welt in + Feierlaune versetzten. Überall werden Tavernen und + Theater gut gefüllt sein und selbst die Bettler satt + werden. + This joyous song will spread like + wildfire throughout the region and cause festive spirits + in all the population. All the taverns and theaters will + be packed to the brim and even the beggars will not go + hungry. + + + Einem erfahrenen Magier wird + irgendwann auf seinen Wanderungen ein ungewöhnliches + Exemplar einer Gattung begegnen, welches sich dem Magier + anschließen wird. + Once during his travels, the seasoned + magician will meet an extraordinary creature of its species + that will join him. + + + Mit diesem Zauber greift der Magier + direkt den Geist seiner Gegner an. Ein Schlag aus + astraler und elektrischer Energie trifft die Gegner, + wird die Magieresistenz durchbrochen, verliert ein Opfer + permanent einen Teil seiner Erinnerungen. Wird es zu oft + ein Opfer dieses Zaubers kann es daran sterben. + With this spell the mentalist directly + attacks his enemies' souls. A blast of astral and + electrical energy strikes the foes. If a victim fails to + resist the magic, he will permanently lose part of his + memories. Being the target of this spell for too many + times may result in death. + + + Dieser Zauber - dessen Anwendung in + den meisten Kulturen streng verboten ist - löst im Opfer + ein unkontrollierbares Verlangen nach körperlicher Liebe + aus. Die betroffenen Personen werden sich Hals über Kopf + in ein Liebesabenteuer stürzen, zu blind vor Verlangen, + um an etwas anderes zu denken. Meistens bereuen sie es + einige Wochen später... + This spell - whose use is forbidden in + most cultures - creates an uncontrollable desire for + physical love in the victim. The affected persons will + rush head over heels into a love affair, unable to think + of anything else. Most of them will regret this a few + months later... + + + + + + Winter + winter + + + Sommer + summer + + + Frühling + spring + + + Herbst + fall + + + die erste Woche + the first week + + + die zweite Woche + the second week + + + die letzte Woche + the last week + + + der ersten Woche + of the first week + + + der zweiten Woche + of the second week + + + der letzten Woche + of the third week + + + Feldsegen + harvest moon + + + Nebeltage + impenetrable fog + + + Sturmmond + storm moon + + + Herdfeuer + hearth fire + + + Eiswind + icewind + + + Schneebann + snowbane + + + Blütenregen + flowerrain + + + Mond der milden Winde + mild winds + + + Sonnenfeuer + sunfire + + + des zweiten Zeitalters + the second age + + + neuer Zeitrechnung + of the new age + + + + + + Gemein + common + + + Kein Magiegebiet + no magic school yet + + + Illaun + Illaun + + + Tybied + Tybied + + + Gwyrrd + Gwyrrd + + + Cerddor + Cerddor + + + Draig + Draig + + + + + Baum + tree + + + Bäume + trees + + + + Mallornbaum + mallorn tree + + + Mallornbäume + mallorn trees + + + ALLIANZ + ALLIANCE + + + AUSSTOSSEN + KICK + + + NEU + NEW + + + KOMMANDO + COMMAND + + + VERLASSEN + LEAVE + + + BEITRETEN + JOIN + + + EINLADEN + INVITE + + + Steine + stones + + + + Pferde + horses + + + Bauern + peasants + + + Silber + silver + + + Laen + laen + + + + Schößlinge + saplings + + + + Mallornschößlinge + mallorn saplings + + + + Bäume + trees + + + + Mallorn + mallorn + + + + Eisen + iron + + + + Winter + winter + + + + Frühling + spring + + + + Sommer + summer + + + + Herbst + autumn + + + + Vorlage für den nächsten Zug: + Template for the next turn: + + + + Wir schreiben %s des Monats %s im Jahre %d %s. + It is %s of the month of %s in the %d. year of %s. + + + + Wir schreiben %s des Monats %s im Jahre %d %s. Es ist + %s. + It is %s of the month of %s in the %d. year of %s. It is + %s. + + + + aggressiv + aggressive + + + + vorne + front + + + + hinten + rear + + + + defensiv + defensive + + + + flieht + fleeing + + + + kämpft nicht + not fighting + + + + bekommt keine Hilfe + gets no aid + + + + Attacke gegen: + Attacked against + + + + Kämpft gegen: + Fighting against + + + + Hilft: + Helping + + + + Heer + army + + + + Unbekannte Partei + unknown faction + + + einer unbekannten Partei + an unknown faction + + + und + and + + + + Das Schiff des Elfen hat ein rotes Segel + + + + Der Zwerg hat eine Nuss dabei + + + + Die Katze führt eine Hellebarde + + + + Das Schiff mit dem grünen Segel liegt links neben dem + mit + einem weissen Segel + + + + Auf dem Schiff mit grünen Segeln kam der Speerkämpfer + + + + Der Krieger mit dem Kreis im Wappen hat einen Keks + + + + Der Krieger des mittleren Schiffs hat ein Schwert + + + + Auf dem gelben Segel prankt ein Kreuz als Wappen + + + + Der Mensch kam mit dem ersten Schiff + + + + Das Schiff mit dem Stern im Wappen liegt neben dem der + einen Mandelkern hat + + + + Das Schiff des Kriegers, der ein Apfel hat, liegt neben + dem, der ein Kreuz als Wappen hat + + + + Der Krieger mit dem Turm im Wappen trägt eine Axt + + + + Das Schiff des Menschen liegt neben dem blauen Schiff + + + + Das Insekt trägt einen Baum als Wappen + + + + Das Schiff mit dem Stern im Wappen liegt neben dem des + Kriegers, der einen Zweihänder führt + + + + Held + hero + + + + Helden + heroes + + + + + + Dunkel + dark + + + + Schwarz + black + + + + Licht + light + + + + Flammen + flame + + + + Eis + ice + + + + Klein + gully + + + + Hoch + high + + + + Hügel + hill + + + + Berg + mountain + + + + Wald + wood + + + + Sumpf + swamp + + + + Schnee + snow + + + + Sonnen + sun + + + + Mond + moon + + + + See + sea + + + + Tal + valley + + + + Schatten + shadow + + + + Höhlen + cave + + + + Blut + blood + + + + Wild + wild + + + + Chaos + chaos + + + + Nacht + night + + + + Nebel + mist + + + + Grau + grey + + + + Frost + cold + + + + Finster + gloom + + + + Düster + black + + + + Sternen + star + + + + + 'Ho ho ho!' Ein dicker Gnom fliegt auf einem von + 8 Jungdrachen gezogenen Schlitten durch die Nacht und vermacht Deiner + Partei ein Sonnensegel. (Um das Segel einer Einheit zu geben, gib + ihr den Befehl 'BEANSPRUCHE 1 Sonnensegel'). + 'Ho ho ho!' A fat little gnome Gnom on a sled + pulled by 8 young dragons flies through the stary night and presents + your faction with a solar sail. (To claim this item, one of your units + must issue the order 'CLAIM 1 solar sail'. + + + + 'Ho ho ho!' Ein dicker Gnom fliegt auf einem von + 8 Jungdrachen gezogenen Schlitten durch die Nacht und vermacht Deiner + Partei eine Phiole mit Sternenstaub. (Informationen dazu gibt es mit + BEANSPRUCHE und ZEIGE). + 'Ho ho ho!' A fat little gnome Gnom on a sled + pulled by 8 young dragons flies through the stary night and presents + your faction with a vial of stardust. (To get more information about + this item, use the CLAIM and SHOW commands). + + + + 'Ho ho ho!' Ein dicker Gnom fliegt auf einem von + 8 Jungdrachen gezogenen Schlitten durch die Nacht und vermacht Deiner + Partei einen wundervoll geschmueckten Weihnachtsbaum. (Informationen dazu gibt es mit + BEANSPRUCHE und ZEIGE). + 'Ho ho ho!' A fat little gnome Gnom on a sled + pulled by 8 young dragons flies through the stary night and presents + your faction with a beautifully decorated tree. (To get more information about + this item, use the CLAIM and SHOW commands). + + + + Gral + grail + + + + Grale + grails + + + + Lerntrank + brain boost + + + + Lerntränke + brain boosts + + + + GE je + stone per + + + + GE je + stones per + + + + GE + stone + + + + GE + stones + + + + bewacht die Region + guards the region + + + + und + and + + + + Dorfbewohner + Villagers + + + + Bauernmob + Angry mob + + + + Aufgebrachte Bauern + Furious peasants + + + + Söldner + Mercenaries + + + + Sumpfbewohner + Swamp people + + + + Waldbewohner + Woodsmen + + + + Nomaden + Nomads + + + + Eisleute + Ice people + + + + Bergbewohner + Mountain people + + + + Magie der Elemente + Magic of the Elements + + + + Schwerter, Armbrüste, Langbögen + Swords, Crossbows and Longbows + + + + Gorms Almanach der Rationellen Kriegsführung + Gorm's Almanach of Rational War + + + + Katamarane, Koggen, Karavellen + The dragonship, the caravell and the longboat + + + + Wege der Sterne + Ways of the Start + + + + Nadishahs Kleine Gift- und Kräuterkunde + Nadishah's collected lore on poisonous and beneficial herbs + + + + Mandricks Kompendium der Alchemie + Mandrick's alchemistic compendium + + + + Die Konstruktion der Burgen und Schlösser von Zentralandune + + + + Die Esse + + + + Über die Gewinnung von Erzen + + + + Barinions Lieder, eine Einführung für Unbedarfte + + + + die Ruine eines alten Tempels + the ruins of an ancient temple + + + + eine alte Burgruine + the ruins of a castle + + + + ein zerfallenes Bauernhaus + a dilapitated farm + + + + eine Leiche am Wegesrand + a corpse by the wayside + + + + eine Leiche am Wegesrand + a corpse by the wayside + + + + Feuerdrache + fire dragon + + + + Ein Alp starb, ohne sein Ziel zu erreichen. + An alp died before it reached its target. + + + + unbewaffnet + unarmed + + + + Trefferpunkte + hitpoints + + + + Rüstung + armor + + + + Angriff + attack + + + + Angriffe + attacks + + + + Verteidigung + defense + + + + Kann Waffen benutzen. + May use weapons. + + + + Ist durch Stichwaffen, Bögen und Armbrüste schwer zu verwunden. + Is hard to hit by piercing weapons. + + + + Ist durch Hiebwaffen schwer zu verwunden. + Is hard to hit by slashing weapons. + + + + Ist durch Schlagwaffen und Katapulte schwer zu verwunden. + Is hard to hit by blunt weapons and catapults. + + + + ein Angriff mit der Waffe oder unbewaffnet + an attack with a weapon or an unarmed attack + + + + ein unbewaffneter Angriff + an unarmed attack + + + + ein magischer Angriff + a magical attack + + + + Klon von %s + Clone of %s + + + + ein Angriff, der Gebäudeschaden verursacht + an attack causing structural damage to buildings + + + + Präkampfzauber + pre-combat spell + + + + Postkampfzauber + post-combat spell + + + + Kampfzauber + combat spell + + + + Normaler Zauber + regular spell + + + + Es ist Winter, und Insekten können nur in Wüsten oder mit Hilfe des Nestwärme-Tranks Personen rekrutieren. + It is winter, and insects can only recruit in deserts or with the aid of nestwarmth potions. + + + + Es ist Spätherbst, und diese Woche ist die letzte vor dem Winter, in der Insekten rekrutieren können. + + + + Eigentümer + Owner + + + + + eine Straße + a road + + + + Straßen + roads + + + + Straße + road + + + + eine zu %d%% vollendete Straße + a road that is %d%% complete + + + + ein Straßenanschluß + a connection to another road + + + + eine unvollständige Straße + an incomplete road + + + + Wand + wall + + + + eine Wand + a wall + + + + Feuerwand + firewall + + + + eine Feuerwand + a firewall + + + + Nebelwand + wall of fog + + + + eine Nebelwand + a wall of fog + + + + Irrlichter + wisps + + + + eine Gruppe von Irrlichtern + a cloud of wisps + + + + gewaltiges offenes Tor + massive open door + + + + ein gewaltiges offenes Tor + a massive open door + + + + gewaltiges verschlossenes Tor + massive locked door + + + + ein gewaltiges verschlossenes Tor + a massive locked door + + + + Illusionswand + illusionary wall + + + + eine Illusionswand + an illusionary wall + + + + + + Die Region ist verwüstet, der Boden karg. + The region is ravaged, the ground infertile. + + + + Einheit-Nr + unitid + + + + Schiff-Nr + shipid + + + + völker + tribes + + + + Gebäude-Nr + buildingid + + + + + Aura + aura + + + + Rasse + race + + + + Zauber-ID + spellid + + + + Richtung + direction + + + + Gebäudetyp + buildingtype + + + + diff --git a/res/en/strings.xml b/res/en/strings.xml index 893007b43..6d1a56ebe 100644 --- a/res/en/strings.xml +++ b/res/en/strings.xml @@ -1,1680 +1,1680 @@ - - - - - - - ADDRESSES - - - REPORT - - - BZIP2 - - - COMPUTER - - - DEBUG - - - ITEMPOOL - - - SCORE - - - SILVERPOOL - - - STATISTICS - - - EXPRESS - - - ZIPPED - - - TEMPLATE - - - SKILLCHANGES - - - - INFO - - - - - caravel - - - boat - - - longboat - - - dragonship - - - trireme - - - balloon - - - - - a caravel - - - a boat - - - a longboat - - - a balloon - - - a dragonship - - - a trireme - - - - - active volcano - - - corridor - - - desert - - - firewall - - - fog - - - forest - - - glacier - - - glacier - - - hallway - - - hell - - - highland - - - iceberg - - - maelstrom - - - mountain - - - ocean - - - plain - - - swamp - - - thick fog - - - volcano - - - magical storm - - - - the volcano of %s - - - a %s - - - the deserts of %s - - - a %s - - - fog_trail %s - - - the forests of %s - - - the glacier of %s - - - Wall - - - the %s - - - %s - - - the highlands of %s - - - a %s - - - the mountains of %s - - - the %s - - - the plain of %s - - - the swamps of %s - - - %s - - - the volcano of %s - - - a %s - - - - caldera - - - portal - - - - - NW - - - NE - - - East - - - SE - - - SW - - - West - - - - west - - - northwest - - - northeast - - - east - - - southwest - - - southeast - - - - an unknown unit - - - - Dispatches - - - Events - - - Warnings and Errors - - - Economy and Trade - - - Resources and Production - - - Magic and Artefacts - - - Movement and Travel - - - Learning and Teaching - - - Battles - - - Miscellaneous - - - New Spells - - - - - academy - - - blessed stonecircle - - - caravanserei - - - dam - - - structure - - - harbour - - - fairy castle - - - inn - - - lighthouse - - - mage tower - - - mine - - - monument - - - quarry - - - sawmill - - - smithy - - - stable - - - stonecircle - - - tunnel - - - - - foundation - - - tradepost - - - fortification - - - tower - - - castle - - - fortress - - - citadel - - - - - herb - - - vial - - - vials - - - - - silver - - - silver - - - hp - - - hps - - - aura - - - auras - - - permaura - - - permauras - - - peasant - - - peasants - - - - - almond - - - almonds - - - amulet - - - amulets - - - antimagic crystal - - - antimagic crystals - - - amulet of chastity - - - amulets of chastity - - - amulet of the kitten - - - amulets of the kitten - - - amulet of darkness - - - amulets of darkness - - - amulet of gathering - - - amulets of gathering - - - amulet of healing - - - amulets of healing - - - amulet of true seeing - - - amulets of true seeing - - - apple - - - apples - - - aurafocus - - - aurafocuses - - - axe - - - axes - - - bow - - - bows - - - cart - - - carts - - - catapult - - - catapults - - - chainmail - - - chainmails - - - cookie - - - cookies - - - crossbow - - - crossbows - - - dolphin - - - dolphins - - - dragonblood - - - dragonblood - - - dragonhead - - - dragonheads - - - dragonhoard - - - dreameye - - - dreameyes - - - elven horse - - - elven horses - - - eye of dragon - - - eye of dragons - - - fairy boots - - - fairy boots - - - flaming sword - - - flaming swords - - - elven bow - - - elven bows - - - claymore - - - claymores - - - halberd - - - halberds - - - healingpotion - - - healingpotions - - - herbbag - - - herbbags - - - horse - - - horses - - - iron - - - iron - - - laen - - - laen - - - laen chainmail - - - laen chainmails - - - laen shield - - - laen shields - - - laen sword - - - laen swords - - - lance - - - lances - - - wood - - - wood - - - magic bag - - - magic bags - - - bag of conservation - - - bags of conservation - - - mallorn - - - mallorn - - - mallorn bow - - - mallorn bows - - - mallorn crossbow - - - mallorn crossbows - - - mallorn lance - - - mallorn lances - - - mallorn spear - - - mallorn spear - - - silverbag - - - silverchest - - - returnticket for the grand museum - - - returntickets for the grand museum - - - ticket to the grand museum - - - tickets to the grand museum - - - nut - - - nuts - - - pegasus - - - pegasi - - - man - - - men - - - platemail - - - platemails - - - pangolin - - - pangolins - - - presspass - - - presspasses - - - ring of invisibility - - - rings of invisibility - - - ring of power - - - rings of power - - - ring of quick fingers - - - rings of quick fingers - - - ring of regeneration - - - rings of regeneration - - - runesword - - - runeswords - - - rustychainmail - - - rustychainmails - - - rusty shield - - - rusty shields - - - rusty sword - - - rusty swords - - - seaserpenthead - - - seaserpentheads - - - shield - - - shields - - - sack of holding - - - sacks of holding - - - spear - - - spears - - - stone - - - stones - - - sword - - - swords - - - pot of toadslime - - - pots of toadslime - - - trollbelt - - - trollbelts - - - unit - - - units - - - potion of skills - - - potions of skills - - - astralcrystal - - - astralcrystals - - - seed - - - seeds - - - mallorn seed - - - mallorn seeds - - - firework - - - fireworks - - - gingerbread heart - - - gingerbread hearts - - - - - balm - - - spice - - - gem - - - gems - - - myrrh - - - oil - - - silk - - - incense - - - balm - - - spice - - - myrrh - - - oil - - - silk - - - incense - - - - - Belt of Heroic Legends - - - Belts of Heroic Legends - - - - - flatroot - - - flatroots - - - tangy temerity - - - tangy temerities - - - owlsgaze - - - owlsgazes - - - spider ivy - - - spider ivies - - - cobalt fungus - - - cobalt fungi - - - elvendear - - - elvendears - - - bugleweed - - - bugleweeds - - - knotroot - - - knotroots - - - bubblemorel - - - bubblemorels - - - waterfinder - - - waterfinders - - - peyote - - - peyote - - - sand reeker - - - sand reekers - - - windbag - - - windbags - - - fjord fungus - - - fjord fungi - - - mandrake - - - mandrakes - - - rock weed - - - rock weed - - - gapgrowth - - - gapgrowths - - - cave lichen - - - cave lichen - - - ice begonia - - - ice begonias - - - white hemlock - - - white hemlocks - - - snowcrystal petal - - - snowcrystal petals - - - seven mile tea - - - seven mile teas - - - goliath water - - - goliath waters - - - water of life - - - waters of life - - - busybeer - - - busybeers - - - ointment - - - ointments - - - peasant blood - - - peasant bloods - - - brain wax - - - brain waxes - - - duncebun - - - duncebuns - - - potion of nest warmth - - - potions of nest warmth - - - horsepower potion - - - horsepower potions - - - berserkers blood potion - - - berserkers blood potions - - - peasant love potion - - - peasant love potion - - - potion of truth - - - potions of truth - - - elixir of power - - - elixirs of power - - - healing potion - - - healing potions - - - - - AGGRESSIVE - - - ALL - - - EACH - - - NUMBER - - - AURA - - - TREES - - - PEASANTS - - - AID - - - GUARD - - - CASTLE - - - DEFENSIVE - - - UNIT - - - ERESSEA - - - FLEE - - - FOREIGN - - - BUILDING - - - ITEMS - - - GIVE - - - MERCY - - - HELP - - - REAR - - - AFTER - - - CONTROL - - - HERBS - - - COMBAT - - - NOT - - - NEXT - - - FACTION - - - FACTIONSTEALTH - - - PAUSE - - - MEN - - - PRIVATE - - - REGION - - - SHIP - - - SILVER - - - ROADS - - - LEVEL - - - TEMPORARY - - - POTIONS - - - FOR - - - BEFORE - - - FRONT - - - SPELLS - - - - - alchemy - - - armoursmithing - - - bow - - - masonry - - - cartmaking - - - catapult - - - crossbow - - - entertainment - - - espionage - - - forestry - - - herbalism - - - magic - - - melee - - - mining - - - perception - - - polearm - - - quarrying - - - riding - - - roadwork - - - sailing - - - shipcraft - - - endurance - - - stealth - - - tactics - - - taxation - - - trade - - - taming - - - unarmed combat - - - weaponsmithing - - - - - - // - - - WORK - - - ATTACK - - - BANNER - - - STEAL - - - BESIEGE - - - NAME - - - USE - - - DESCRIBE - - - PRAY - - - ENTER - - - GUARD - - - BID - - - MESSAGE - - - DEFAULT - - - EMAIL - - - END - - - RIDE - - - FOLLOW - - - RESEARCH - - - GM - - - GROUP - - - HELP - - - JIHAD - - - COMBATSPELL - - - BUY - - - CONTACT - - - COMBAT - - - TEACH - - - LEARN - - - SUPPLY - - - LOCALE - - - MAKE - - - MOVE - - - RESTART - - - NUMBER - - - SACRIFICE - - - OPTION - - - PASSWORD - - - PLANT - - - PIRACY - - - PREFIX - - - RECRUIT - - - REPORT - - - RESERVE - - - ROUTE - - - SABOTAGE - - - SORT - - - SPY - - - QUIT - - - SYNONYM - - - HIDE - - - CARRY - - - TAX - - - ENTERTAIN - - - ORIGIN - - - FORGET - - - SELL - - - LEAVE - - - CAST - - - SHOW - - - DESTROY - - - GROW - - - LYCANTROPE - - - - - Options - - - Level - - - Political Status - - - Herbs required - - - under construction - - - damage - - - Your faction has been eliminated. We hope that you had a good time, and if you liked the game, you should sign up and play again. - - - - skills - - - has - - - size - - - spells - - - combat spells - - - none - - - Addresses - - - anonymous - - - attack - - - defense - - - armour - - - damage - - - - - wand - - - wands - - - - - - northwest coast - - - northeast coast - - - east coast - - - southeast coast - - - southwest coast - - - west coast - - - - - No orders were received for your faction! - - - - - Mistelzweig - mistletoe - - - Mistelzweige - mistletoes - - + + + + + + + ADDRESSES + + + REPORT + + + BZIP2 + + + COMPUTER + + + DEBUG + + + ITEMPOOL + + + SCORE + + + SILVERPOOL + + + STATISTICS + + + EXPRESS + + + ZIPPED + + + TEMPLATE + + + SKILLCHANGES + + + + INFO + + + + + caravel + + + boat + + + longboat + + + dragonship + + + trireme + + + balloon + + + + + a caravel + + + a boat + + + a longboat + + + a balloon + + + a dragonship + + + a trireme + + + + + active volcano + + + corridor + + + desert + + + firewall + + + fog + + + forest + + + glacier + + + glacier + + + hallway + + + hell + + + highland + + + iceberg + + + maelstrom + + + mountain + + + ocean + + + plain + + + swamp + + + thick fog + + + volcano + + + magical storm + + + + the volcano of %s + + + a %s + + + the deserts of %s + + + a %s + + + fog_trail %s + + + the forests of %s + + + the glacier of %s + + + Wall + + + the %s + + + %s + + + the highlands of %s + + + a %s + + + the mountains of %s + + + the %s + + + the plain of %s + + + the swamps of %s + + + %s + + + the volcano of %s + + + a %s + + + + caldera + + + portal + + + + + NW + + + NE + + + East + + + SE + + + SW + + + West + + + + west + + + northwest + + + northeast + + + east + + + southwest + + + southeast + + + + an unknown unit + + + + Dispatches + + + Events + + + Warnings and Errors + + + Economy and Trade + + + Resources and Production + + + Magic and Artefacts + + + Movement and Travel + + + Learning and Teaching + + + Battles + + + Miscellaneous + + + New Spells + + + + + academy + + + blessed stonecircle + + + caravanserei + + + dam + + + structure + + + harbour + + + fairy castle + + + inn + + + lighthouse + + + mage tower + + + mine + + + monument + + + quarry + + + sawmill + + + smithy + + + stable + + + stonecircle + + + tunnel + + + + + foundation + + + tradepost + + + fortification + + + tower + + + castle + + + fortress + + + citadel + + + + + herb + + + vial + + + vials + + + + + silver + + + silver + + + hp + + + hps + + + aura + + + auras + + + permaura + + + permauras + + + peasant + + + peasants + + + + + almond + + + almonds + + + amulet + + + amulets + + + antimagic crystal + + + antimagic crystals + + + amulet of chastity + + + amulets of chastity + + + amulet of the kitten + + + amulets of the kitten + + + amulet of darkness + + + amulets of darkness + + + amulet of gathering + + + amulets of gathering + + + amulet of healing + + + amulets of healing + + + amulet of true seeing + + + amulets of true seeing + + + apple + + + apples + + + aurafocus + + + aurafocuses + + + axe + + + axes + + + bow + + + bows + + + cart + + + carts + + + catapult + + + catapults + + + chainmail + + + chainmails + + + cookie + + + cookies + + + crossbow + + + crossbows + + + dolphin + + + dolphins + + + dragonblood + + + dragonblood + + + dragonhead + + + dragonheads + + + dragonhoard + + + dreameye + + + dreameyes + + + elven horse + + + elven horses + + + eye of dragon + + + eye of dragons + + + fairy boots + + + fairy boots + + + flaming sword + + + flaming swords + + + elven bow + + + elven bows + + + claymore + + + claymores + + + halberd + + + halberds + + + healingpotion + + + healingpotions + + + herbbag + + + herbbags + + + horse + + + horses + + + iron + + + iron + + + laen + + + laen + + + laen chainmail + + + laen chainmails + + + laen shield + + + laen shields + + + laen sword + + + laen swords + + + lance + + + lances + + + wood + + + wood + + + magic bag + + + magic bags + + + bag of conservation + + + bags of conservation + + + mallorn + + + mallorn + + + mallorn bow + + + mallorn bows + + + mallorn crossbow + + + mallorn crossbows + + + mallorn lance + + + mallorn lances + + + mallorn spear + + + mallorn spear + + + silverbag + + + silverchest + + + returnticket for the grand museum + + + returntickets for the grand museum + + + ticket to the grand museum + + + tickets to the grand museum + + + nut + + + nuts + + + pegasus + + + pegasi + + + man + + + men + + + platemail + + + platemails + + + pangolin + + + pangolins + + + presspass + + + presspasses + + + ring of invisibility + + + rings of invisibility + + + ring of power + + + rings of power + + + ring of quick fingers + + + rings of quick fingers + + + ring of regeneration + + + rings of regeneration + + + runesword + + + runeswords + + + rustychainmail + + + rustychainmails + + + rusty shield + + + rusty shields + + + rusty sword + + + rusty swords + + + seaserpenthead + + + seaserpentheads + + + shield + + + shields + + + sack of holding + + + sacks of holding + + + spear + + + spears + + + stone + + + stones + + + sword + + + swords + + + pot of toadslime + + + pots of toadslime + + + trollbelt + + + trollbelts + + + unit + + + units + + + potion of skills + + + potions of skills + + + astralcrystal + + + astralcrystals + + + seed + + + seeds + + + mallorn seed + + + mallorn seeds + + + firework + + + fireworks + + + gingerbread heart + + + gingerbread hearts + + + + + balm + + + spice + + + gem + + + gems + + + myrrh + + + oil + + + silk + + + incense + + + balm + + + spice + + + myrrh + + + oil + + + silk + + + incense + + + + + Belt of Heroic Legends + + + Belts of Heroic Legends + + + + + flatroot + + + flatroots + + + tangy temerity + + + tangy temerities + + + owlsgaze + + + owlsgazes + + + spider ivy + + + spider ivies + + + cobalt fungus + + + cobalt fungi + + + elvendear + + + elvendears + + + bugleweed + + + bugleweeds + + + knotroot + + + knotroots + + + bubblemorel + + + bubblemorels + + + waterfinder + + + waterfinders + + + peyote + + + peyote + + + sand reeker + + + sand reekers + + + windbag + + + windbags + + + fjord fungus + + + fjord fungi + + + mandrake + + + mandrakes + + + rock weed + + + rock weed + + + gapgrowth + + + gapgrowths + + + cave lichen + + + cave lichen + + + ice begonia + + + ice begonias + + + white hemlock + + + white hemlocks + + + snowcrystal petal + + + snowcrystal petals + + + seven mile tea + + + seven mile teas + + + goliath water + + + goliath waters + + + water of life + + + waters of life + + + busybeer + + + busybeers + + + ointment + + + ointments + + + peasant blood + + + peasant bloods + + + brain wax + + + brain waxes + + + duncebun + + + duncebuns + + + potion of nest warmth + + + potions of nest warmth + + + horsepower potion + + + horsepower potions + + + berserkers blood potion + + + berserkers blood potions + + + peasant love potion + + + peasant love potion + + + potion of truth + + + potions of truth + + + elixir of power + + + elixirs of power + + + healing potion + + + healing potions + + + + + AGGRESSIVE + + + ALL + + + EACH + + + NUMBER + + + AURA + + + TREES + + + PEASANTS + + + AID + + + GUARD + + + CASTLE + + + DEFENSIVE + + + UNIT + + + ERESSEA + + + FLEE + + + FOREIGN + + + BUILDING + + + ITEMS + + + GIVE + + + MERCY + + + HELP + + + REAR + + + AFTER + + + CONTROL + + + HERBS + + + COMBAT + + + NOT + + + NEXT + + + FACTION + + + FACTIONSTEALTH + + + PAUSE + + + MEN + + + PRIVATE + + + REGION + + + SHIP + + + SILVER + + + ROADS + + + LEVEL + + + TEMPORARY + + + POTIONS + + + FOR + + + BEFORE + + + FRONT + + + SPELLS + + + + + alchemy + + + armoursmithing + + + bow + + + masonry + + + cartmaking + + + catapult + + + crossbow + + + entertainment + + + espionage + + + forestry + + + herbalism + + + magic + + + melee + + + mining + + + perception + + + polearm + + + quarrying + + + riding + + + roadwork + + + sailing + + + shipcraft + + + endurance + + + stealth + + + tactics + + + taxation + + + trade + + + taming + + + unarmed combat + + + weaponsmithing + + + + + + // + + + WORK + + + ATTACK + + + BANNER + + + STEAL + + + BESIEGE + + + NAME + + + USE + + + DESCRIBE + + + PRAY + + + ENTER + + + GUARD + + + BID + + + MESSAGE + + + DEFAULT + + + EMAIL + + + END + + + RIDE + + + FOLLOW + + + RESEARCH + + + GM + + + GROUP + + + HELP + + + JIHAD + + + COMBATSPELL + + + BUY + + + CONTACT + + + COMBAT + + + TEACH + + + LEARN + + + SUPPLY + + + LOCALE + + + MAKE + + + MOVE + + + RESTART + + + NUMBER + + + SACRIFICE + + + OPTION + + + PASSWORD + + + PLANT + + + PIRACY + + + PREFIX + + + RECRUIT + + + REPORT + + + RESERVE + + + ROUTE + + + SABOTAGE + + + SORT + + + SPY + + + QUIT + + + SYNONYM + + + HIDE + + + CARRY + + + TAX + + + ENTERTAIN + + + ORIGIN + + + FORGET + + + SELL + + + LEAVE + + + CAST + + + SHOW + + + DESTROY + + + GROW + + + LYCANTROPE + + + + + Options + + + Level + + + Political Status + + + Herbs required + + + under construction + + + damage + + + Your faction has been eliminated. We hope that you had a good time, and if you liked the game, you should sign up and play again. + + + + skills + + + has + + + size + + + spells + + + combat spells + + + none + + + Addresses + + + anonymous + + + attack + + + defense + + + armour + + + damage + + + + + wand + + + wands + + + + + + northwest coast + + + northeast coast + + + east coast + + + southeast coast + + + southwest coast + + + west coast + + + + + No orders were received for your faction! + + + + + Mistelzweig + mistletoe + + + Mistelzweige + mistletoes + + diff --git a/res/equipment.xml b/res/equipment.xml index 935de5806..a175af7b9 100644 --- a/res/equipment.xml +++ b/res/equipment.xml @@ -1,399 +1,399 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/fr/strings.xml b/res/fr/strings.xml index 850085eaf..ff2bdf205 100644 --- a/res/fr/strings.xml +++ b/res/fr/strings.xml @@ -1,2082 +1,2082 @@ - - - - - - PASSAGE - - - XEPOTION - - - XEBALLON - - - XELAEN - - - GUERRE - - - PAIX - - - XONTORMIA - - - ALLIANCE - - - ADRESSES - - - RAPPORT - - - BZIP2 - - - ORDINATEUR - - - DEBOGUER - - - RESSOURCES COMMUNES - - - SCORE - - - ARGENT COMMUN - - - STATISTIQUES - - - EXPRESS - - - ZIPPE - - - MODELE - - - MODIFICATIONS - - - - INFO - - - - - nef - - - chaloupe - - - barge - - - drakkar - - - galère - - - ballon - - - - - une nef - - - une chaloupe - - - une barge - - - un ballon - - - un drakkar - - - une galère - - - - - volcan actif - - - couloir - - - désert - - - mur de feu - - - brume - - - forêt - - - glacier - - - vestibule - - - l'enfer - - - colline - - - iceberg - - - maelström - - - montagne - - - océan - - - plaine - - - marais - - - brouillard - - - volcan - - - tempête magique - - - - le volcan %s - - - un %s - - - le désert de %s - - - un %s - - - fog_trail %s - - - la forêt de %s - - - le glacier de %s - - - le %s - - - %s - - - les collines de %s - - - un %s - - - un %s - - - les montagnes de %s - - - l'%s - - - la plaine de %s - - - les marais de %s - - - %s - - - le volcan de %s - - - une %s - - - - caldera - - - portail - - - - - NO - - - NE - - - Est - - - SE - - - SO - - - Ouest - - - - ouest - - - nord-ouest - - - nord-est - - - est - - - sud-ouest - - - sud-est - - - - une unité inconnue - - - - Messages et Evénements - - - Avertissements et Erreurs - - - Economie et Commerce - - - Ressources et Production - - - Magie et Reliques - - - Déplacements et Voyages - - - Apprentissage et Enseignement - - - Batailles - - - Divers - - - Nouveaux Sorts - - - - - université - - - cromlech sacré - - - caravansérail - - - barrage - - - bâtiment - - - port - - - château illusoire - - - auberge - - - phare - - - donjon - - - mine - - - monument - - - carrière - - - scierie - - - forge - - - écurie - - - cromlech - - - tunnel - - - - - palissade - - - comptoir - - - rempart - - - tour - - - château - - - place-forte - - - citadelle - - - - - plante - - - fiole - - - fioles - - - - - écu - - - écus - - - point de vie - - - points de vie - - - aura - - - aura - - - aura permanente - - - aura permanente - - - paysan - - - paysans - - - - - amande - - - amandes - - - amulette - - - amulettes - - - cristal antimagie - - - cristaux antimagie - - - amulette de chasteté - - - amulettes de chasteté - - - amulette du chaton - - - amulettes du chaton - - - amulette de ténèbres - - - amulettes de ténèbres - - - amulette de rassemblement - - - amulettes de rassemblement - - - amulette de soin - - - amulettes de soin - - - amulette de vérité - - - amulettes de vérité - - - pomme - - - pommes - - - focus - - - foci - - - hache - - - haches - - - arc - - - arcs - - - chariot - - - chariots - - - catapulte - - - catapultes - - - cotte de mailles - - - cottes de mailles - - - gâteau - - - gâteaux - - - arbalète - - - arbalètes - - - dauphin - - - dauphins - - - sang de dragon - - - sang de dragon - - - tête de dragon - - - têtes de dragons - - - trésor de dragon - - - oniroeil - - - oniryeux - - - cheval elfique - - - chevaux elfiques - - - oeil de dragon - - - yeux de dragon - - - bottes elfiques - - - bottes elfiques - - - épée ardente - - - épées ardentes - - - grand arc - - - grands arcs - - - claymore - - - claymores - - - halebarde - - - halebardes - - - potion de soin - - - potions de soin - - - sac de plantes - - - sacs de plantes - - - cheval - - - chevaux - - - lingot - - - lingots - - - laen - - - laen - - - cotte en laen - - - cottes en laen - - - bouclier en laen - - - boucliers en laen - - - épée en laen - - - épées en laen - - - lance - - - lances - - - stère - - - stères - - - sac magique - - - sacs magiques - - - sac de conservation - - - sacs de conservation - - - mallorn - - - mallorn - - - arc en mallorn - - - arcs en mallorn - - - arbalète en mallorn - - - arbalètes en mallorn - - - lance en mallorn - - - lances en mallorn - - - épieu en mallorn - - - épieux en mallorn - - - bourse - - - cassette - - - returnticket for the grand museum - - - returntickets for the grand museum - - - ticket to the grand museum - - - tickets to the grand museum - - - noix - - - noix - - - pégase - - - pégases - - - homme - - - hommes - - - armure de plates - - - armures de plates - - - carte de presse - - - cartes de presse - - - anneau d'invisibilité - - - anneaux d'invisibilité - - - anneau de pouvoir - - - anneaux de pouvoir - - - anneau de dextérité - - - anneaux de dextérité - - - anneau de régénération - - - anneaux de régénération - - - épée runique - - - épées runiques - - - cotte de mailles rouillée - - - cottes de mailles rouillées - - - bouclier rouillé - - - boucliers rouillés - - - épée rouillée - - - épées rouillées - - - tête de serpent de mer - - - têtes de serpents de mer - - - bouclier - - - boucliers - - - sac de contenance - - - sacs de contenance - - - épieu - - - épieux - - - pierre - - - pierres - - - épée - - - épées - - - pot de bave de crapaud - - - pots de bave de crapaud - - - ceinture de troll - - - ceintures de trolls - - - unité - - - unités - - - potion de compétences - - - potions de compétences - - - cristal astral - - - cristaux astraux - - - graine - - - graines - - - graine de mallorn - - - graines de mallorn - - - feu d'artifice - - - feux d'artifice - - - coeur de pain d'épices - - - coeurs de pain d'épices - - - - - baume - - - épices - - - joyau - - - joyaux - - - myrrhe - - - huile - - - soie - - - encens - - - baume - - - épices - - - myrrhe - - - huile - - - soie - - - encens - - - - - Ceinture des Légendes - - - Ceintures des Légendes - - - - - astragale - - - astragales - - - méritoine - - - méritoines - - - oeil de hibou - - - yeux de hibou - - - soie d'araignée - - - soies d'araignée - - - obbadion - - - obbadions - - - cheveux d'elfe - - - cheveux d'elfe - - - ortigal - - - ortigals - - - tubercule de respiplante - - - tubercules de respiplante - - - oreille de morille - - - oreilles de morille - - - hydropousse - - - hydropousses - - - ossiphage - - - ossiphages - - - fleur de souffre - - - fleurs de souffre - - - feuille de Tshaï - - - feuilles de Tshaï - - - bélidane - - - bélidanes - - - racine de mandragore - - - racines de mandragore - - - percepierre - - - percepierres - - - tanemiel - - - tanemiels - - - boralme - - - boralmes - - - ficoïde à cristaux - - - ficoïdes à cristaux - - - blémissure - - - blémissures - - - rose des neiges - - - roses des neiges - - - thé de sept lieues - - - thé de sept lieues - - - breuvage de Goliath - - - breuvage de Goliath - - - élixir de vie - - - élixir de vie - - - vin du travail acharné - - - vin du travail acharné - - - onguent de soin - - - onguents de soin - - - fiole d'essence vitale - - - fioles d'essence vitale - - - huile de cogitation - - - huile de cogitation - - - petit pain rance - - - petits pains rances - - - extrait de canicule - - - extraits de canicule - - - fourrage de l'étalon - - - fourrage de l'étalon - - - vin de folie - - - vin de folie - - - philtre d'amour - - - philtres d'amour - - - sirop de claivoyance - - - sirops de claivoyance - - - elixir d'endurance - - - elixir d'endurance - - - potion de survie - - - potions de survie - - - - - AGRESSIF - - - TOUT - - - NOMBRE - - - AURA - - - ARBRES - - - PAYSANS - - - SOUTIEN - - - GUARDE - - - CHATEAU - - - DEFENSIF - - - UNITE - - - ERESSEA - - - FUITE - - - ETRANGER - - - BATIMENT - - - OBJETS - - - DONNER - - - PITIE - - - AIDE - - - DERRIERE - - - APRES - - - CONTROLE - - - PLANTES - - - COMBAT - - - NON - - - SUIVANT - - - FACTION - - - CAMOUFLAGE - - - PAUSE - - - HOMMES - - - PRIVE - - - REGION - - - BATEAU - - - ECUS - - - ROUTES - - - NIVEAU - - - TEMPORAIRE - - - POTIONS - - - POUR - - - AVANT - - - DEVANT - - - SORTS - - - - - alchimie - - - armurier - - - arc - - - maçon - - - charron - - - catapulte - - - arbalète - - - divertissement - - - espionnage - - - bucheron - - - herboriste - - - magie - - - mêlée - - - mineur - - - observation - - - hast - - - perrayeur - - - équitation - - - cantonnier - - - navigation - - - charpentier - - - endurance - - - discrétion - - - tactique - - - percepteur - - - commerce - - - dresseur - - - mains-nues - - - fourbisseur - - - - - - // - - - TRAVAILLER - - - ATTAQUER - - - ANNONCE - - - VOLER - - - ASSIEGER - - - NOMMER - - - UTILISER - - - DECRIRE - - - PRIER - - - ENTRER - - - GUARDER - - - OFFRIR - - - MESSAGE - - - DEFAUT - - - EMAIL - - - FIN - - - CHEVAUCHER - - - SUIVRE - - - CHERCHER - - - GM - - - GROUPER - - - AIDER - - - JIHAD - - - PREPARER - - - ACHETER - - - CONTACTER - - - COMBATTRE - - - ENSEIGNER - - - APPRENDRE - - - FOURNIR - - - LOCAL - - - FAIRE - - - ALLER - - - RECOMMENCER - - - NOMBRE - - - SACRIFIER - - - OPTION - - - PASSWORD - - - PLANTER - - - PIRATERIE - - - PREFIXE - - - RECRUTER - - - RAPPORT - - - RESERVER - - - TRAJET - - - SABOTER - - - TRIER - - - ESPIONNER - - - ABANDONNER - - - SYNONYME - - - CACHER - - - TRANSPORTER - - - TAXER - - - DIVERTIR - - - ORIGINE - - - OUBLIER - - - VENDRE - - - SORTIR - - - INCANTER - - - MONTRER - - - DETRUIRE - - - ACCROITRE - - - METAMORPHOSE - - - - - sangsunicornes - - - sangsunicorne - - - cauchemars - - - cauchemar - - - ombreillards - - - ombreillard - - - draco tenebrae - - - draco tenebrae - - - nains - - - nain - - - elfes - - - elfe - - - orques - - - orque - - - snotlings - - - snotling - - - gobelins - - - gobelin - - - humains - - - humain - - - trolls - - - troll - - - démons - - - démons - - - insectes - - - insecte - - - hobbits - - - hobbit - - - chats - - - chat - - - atlantes - - - atlante - - - morts-vivants - - - mort-vivant - - - illusions - - - illusion - - - dragonnets - - - dragonnet - - - dragons - - - dragon - - - wyrms - - - wyrm - - - ents - - - ent - - - dragons-chats - - - dragon-chat - - - draconiens - - - draconien - - - spéciaux - - - spécial - - - enchantements - - - enchantement - - - golems de fer - - - golem de fer - - - golems de pierre - - - golem de pierre - - - ombres - - - ombre - - - lémures - - - lémure - - - yétis - - - yéti - - - quauquemaires - - - quauquemaire - - - crapauds - - - crapaud - - - céphalophages - - - céphalophage - - - paysans - - - paysan - - - wargs - - - warg - - - lynx - - - lynx - - - vers des profondeurs - - - ver des profondeurs - - - rats - - - rat - - - dragons chinois - - - dragon chinois - - - loups - - - loup - - - fantômes - - - fantôme - - - chats des rêves - - - chat des rêves - - - chats de l'Enfer - - - chat de l'Enfer - - - tigres - - - tigre - - - dauphins - - - dauphin - - - tortues géantes - - - tortue géante - - - krakens - - - kraken - - - serpents de mer - - - serpent de mer - - - guerriers illusoires - - - guerrier illusoire - - - diablotins - - - diablotin - - - nymphes - - - nymphe - - - licornes - - - licorne - - - hiboux - - - hibou - - - fées - - - fée - - - aigles - - - aigle - - - centaures - - - centaure - - - squelettes - - - squelette - - - liches - - - liche - - - zombies - - - zombie - - - zombies juju - - - zombie juju - - - goules - - - goule - - - spectres - - - spectre - - - fantômes du musée - - - fantôme du musée - - - gnomes - - - gnome - - - modèles - - - modèle - - - métamorphes - - - métamorphe - - - - - - Options - - - Niveau - - - Statut Politique - - - Plantes nécessaires - - - en construction - - - de dégâts - - - Votre faction a été éliminée. Nous espérons que vous vous êtes bien amusé malgré tout, et vous encourageons à vous réincrire pour une nouvelle partie. - - - - compétences - - - possessions - - - taille - - - sorts - - - sorts de combat - - - aucun - - - Adresses - - - anonyme - - - attaque - - - défense - - - armure - - - dégâts - - - - - baguette - - - baguettes - - - - - - côte nord-ouest - - - côte nord-est - - - côte est - - - côte sud-est - - - côte sud-ouest - - - côte ouest - - - - Aucun ordre reçu pour votre faction ! - - + + + + + + PASSAGE + + + XEPOTION + + + XEBALLON + + + XELAEN + + + GUERRE + + + PAIX + + + XONTORMIA + + + ALLIANCE + + + ADRESSES + + + RAPPORT + + + BZIP2 + + + ORDINATEUR + + + DEBOGUER + + + RESSOURCES COMMUNES + + + SCORE + + + ARGENT COMMUN + + + STATISTIQUES + + + EXPRESS + + + ZIPPE + + + MODELE + + + MODIFICATIONS + + + + INFO + + + + + nef + + + chaloupe + + + barge + + + drakkar + + + galère + + + ballon + + + + + une nef + + + une chaloupe + + + une barge + + + un ballon + + + un drakkar + + + une galère + + + + + volcan actif + + + couloir + + + désert + + + mur de feu + + + brume + + + forêt + + + glacier + + + vestibule + + + l'enfer + + + colline + + + iceberg + + + maelström + + + montagne + + + océan + + + plaine + + + marais + + + brouillard + + + volcan + + + tempête magique + + + + le volcan %s + + + un %s + + + le désert de %s + + + un %s + + + fog_trail %s + + + la forêt de %s + + + le glacier de %s + + + le %s + + + %s + + + les collines de %s + + + un %s + + + un %s + + + les montagnes de %s + + + l'%s + + + la plaine de %s + + + les marais de %s + + + %s + + + le volcan de %s + + + une %s + + + + caldera + + + portail + + + + + NO + + + NE + + + Est + + + SE + + + SO + + + Ouest + + + + ouest + + + nord-ouest + + + nord-est + + + est + + + sud-ouest + + + sud-est + + + + une unité inconnue + + + + Messages et Evénements + + + Avertissements et Erreurs + + + Economie et Commerce + + + Ressources et Production + + + Magie et Reliques + + + Déplacements et Voyages + + + Apprentissage et Enseignement + + + Batailles + + + Divers + + + Nouveaux Sorts + + + + + université + + + cromlech sacré + + + caravansérail + + + barrage + + + bâtiment + + + port + + + château illusoire + + + auberge + + + phare + + + donjon + + + mine + + + monument + + + carrière + + + scierie + + + forge + + + écurie + + + cromlech + + + tunnel + + + + + palissade + + + comptoir + + + rempart + + + tour + + + château + + + place-forte + + + citadelle + + + + + plante + + + fiole + + + fioles + + + + + écu + + + écus + + + point de vie + + + points de vie + + + aura + + + aura + + + aura permanente + + + aura permanente + + + paysan + + + paysans + + + + + amande + + + amandes + + + amulette + + + amulettes + + + cristal antimagie + + + cristaux antimagie + + + amulette de chasteté + + + amulettes de chasteté + + + amulette du chaton + + + amulettes du chaton + + + amulette de ténèbres + + + amulettes de ténèbres + + + amulette de rassemblement + + + amulettes de rassemblement + + + amulette de soin + + + amulettes de soin + + + amulette de vérité + + + amulettes de vérité + + + pomme + + + pommes + + + focus + + + foci + + + hache + + + haches + + + arc + + + arcs + + + chariot + + + chariots + + + catapulte + + + catapultes + + + cotte de mailles + + + cottes de mailles + + + gâteau + + + gâteaux + + + arbalète + + + arbalètes + + + dauphin + + + dauphins + + + sang de dragon + + + sang de dragon + + + tête de dragon + + + têtes de dragons + + + trésor de dragon + + + oniroeil + + + oniryeux + + + cheval elfique + + + chevaux elfiques + + + oeil de dragon + + + yeux de dragon + + + bottes elfiques + + + bottes elfiques + + + épée ardente + + + épées ardentes + + + grand arc + + + grands arcs + + + claymore + + + claymores + + + halebarde + + + halebardes + + + potion de soin + + + potions de soin + + + sac de plantes + + + sacs de plantes + + + cheval + + + chevaux + + + lingot + + + lingots + + + laen + + + laen + + + cotte en laen + + + cottes en laen + + + bouclier en laen + + + boucliers en laen + + + épée en laen + + + épées en laen + + + lance + + + lances + + + stère + + + stères + + + sac magique + + + sacs magiques + + + sac de conservation + + + sacs de conservation + + + mallorn + + + mallorn + + + arc en mallorn + + + arcs en mallorn + + + arbalète en mallorn + + + arbalètes en mallorn + + + lance en mallorn + + + lances en mallorn + + + épieu en mallorn + + + épieux en mallorn + + + bourse + + + cassette + + + returnticket for the grand museum + + + returntickets for the grand museum + + + ticket to the grand museum + + + tickets to the grand museum + + + noix + + + noix + + + pégase + + + pégases + + + homme + + + hommes + + + armure de plates + + + armures de plates + + + carte de presse + + + cartes de presse + + + anneau d'invisibilité + + + anneaux d'invisibilité + + + anneau de pouvoir + + + anneaux de pouvoir + + + anneau de dextérité + + + anneaux de dextérité + + + anneau de régénération + + + anneaux de régénération + + + épée runique + + + épées runiques + + + cotte de mailles rouillée + + + cottes de mailles rouillées + + + bouclier rouillé + + + boucliers rouillés + + + épée rouillée + + + épées rouillées + + + tête de serpent de mer + + + têtes de serpents de mer + + + bouclier + + + boucliers + + + sac de contenance + + + sacs de contenance + + + épieu + + + épieux + + + pierre + + + pierres + + + épée + + + épées + + + pot de bave de crapaud + + + pots de bave de crapaud + + + ceinture de troll + + + ceintures de trolls + + + unité + + + unités + + + potion de compétences + + + potions de compétences + + + cristal astral + + + cristaux astraux + + + graine + + + graines + + + graine de mallorn + + + graines de mallorn + + + feu d'artifice + + + feux d'artifice + + + coeur de pain d'épices + + + coeurs de pain d'épices + + + + + baume + + + épices + + + joyau + + + joyaux + + + myrrhe + + + huile + + + soie + + + encens + + + baume + + + épices + + + myrrhe + + + huile + + + soie + + + encens + + + + + Ceinture des Légendes + + + Ceintures des Légendes + + + + + astragale + + + astragales + + + méritoine + + + méritoines + + + oeil de hibou + + + yeux de hibou + + + soie d'araignée + + + soies d'araignée + + + obbadion + + + obbadions + + + cheveux d'elfe + + + cheveux d'elfe + + + ortigal + + + ortigals + + + tubercule de respiplante + + + tubercules de respiplante + + + oreille de morille + + + oreilles de morille + + + hydropousse + + + hydropousses + + + ossiphage + + + ossiphages + + + fleur de souffre + + + fleurs de souffre + + + feuille de Tshaï + + + feuilles de Tshaï + + + bélidane + + + bélidanes + + + racine de mandragore + + + racines de mandragore + + + percepierre + + + percepierres + + + tanemiel + + + tanemiels + + + boralme + + + boralmes + + + ficoïde à cristaux + + + ficoïdes à cristaux + + + blémissure + + + blémissures + + + rose des neiges + + + roses des neiges + + + thé de sept lieues + + + thé de sept lieues + + + breuvage de Goliath + + + breuvage de Goliath + + + élixir de vie + + + élixir de vie + + + vin du travail acharné + + + vin du travail acharné + + + onguent de soin + + + onguents de soin + + + fiole d'essence vitale + + + fioles d'essence vitale + + + huile de cogitation + + + huile de cogitation + + + petit pain rance + + + petits pains rances + + + extrait de canicule + + + extraits de canicule + + + fourrage de l'étalon + + + fourrage de l'étalon + + + vin de folie + + + vin de folie + + + philtre d'amour + + + philtres d'amour + + + sirop de claivoyance + + + sirops de claivoyance + + + elixir d'endurance + + + elixir d'endurance + + + potion de survie + + + potions de survie + + + + + AGRESSIF + + + TOUT + + + NOMBRE + + + AURA + + + ARBRES + + + PAYSANS + + + SOUTIEN + + + GUARDE + + + CHATEAU + + + DEFENSIF + + + UNITE + + + ERESSEA + + + FUITE + + + ETRANGER + + + BATIMENT + + + OBJETS + + + DONNER + + + PITIE + + + AIDE + + + DERRIERE + + + APRES + + + CONTROLE + + + PLANTES + + + COMBAT + + + NON + + + SUIVANT + + + FACTION + + + CAMOUFLAGE + + + PAUSE + + + HOMMES + + + PRIVE + + + REGION + + + BATEAU + + + ECUS + + + ROUTES + + + NIVEAU + + + TEMPORAIRE + + + POTIONS + + + POUR + + + AVANT + + + DEVANT + + + SORTS + + + + + alchimie + + + armurier + + + arc + + + maçon + + + charron + + + catapulte + + + arbalète + + + divertissement + + + espionnage + + + bucheron + + + herboriste + + + magie + + + mêlée + + + mineur + + + observation + + + hast + + + perrayeur + + + équitation + + + cantonnier + + + navigation + + + charpentier + + + endurance + + + discrétion + + + tactique + + + percepteur + + + commerce + + + dresseur + + + mains-nues + + + fourbisseur + + + + + + // + + + TRAVAILLER + + + ATTAQUER + + + ANNONCE + + + VOLER + + + ASSIEGER + + + NOMMER + + + UTILISER + + + DECRIRE + + + PRIER + + + ENTRER + + + GUARDER + + + OFFRIR + + + MESSAGE + + + DEFAUT + + + EMAIL + + + FIN + + + CHEVAUCHER + + + SUIVRE + + + CHERCHER + + + GM + + + GROUPER + + + AIDER + + + JIHAD + + + PREPARER + + + ACHETER + + + CONTACTER + + + COMBATTRE + + + ENSEIGNER + + + APPRENDRE + + + FOURNIR + + + LOCAL + + + FAIRE + + + ALLER + + + RECOMMENCER + + + NOMBRE + + + SACRIFIER + + + OPTION + + + PASSWORD + + + PLANTER + + + PIRATERIE + + + PREFIXE + + + RECRUTER + + + RAPPORT + + + RESERVER + + + TRAJET + + + SABOTER + + + TRIER + + + ESPIONNER + + + ABANDONNER + + + SYNONYME + + + CACHER + + + TRANSPORTER + + + TAXER + + + DIVERTIR + + + ORIGINE + + + OUBLIER + + + VENDRE + + + SORTIR + + + INCANTER + + + MONTRER + + + DETRUIRE + + + ACCROITRE + + + METAMORPHOSE + + + + + sangsunicornes + + + sangsunicorne + + + cauchemars + + + cauchemar + + + ombreillards + + + ombreillard + + + draco tenebrae + + + draco tenebrae + + + nains + + + nain + + + elfes + + + elfe + + + orques + + + orque + + + snotlings + + + snotling + + + gobelins + + + gobelin + + + humains + + + humain + + + trolls + + + troll + + + démons + + + démons + + + insectes + + + insecte + + + hobbits + + + hobbit + + + chats + + + chat + + + atlantes + + + atlante + + + morts-vivants + + + mort-vivant + + + illusions + + + illusion + + + dragonnets + + + dragonnet + + + dragons + + + dragon + + + wyrms + + + wyrm + + + ents + + + ent + + + dragons-chats + + + dragon-chat + + + draconiens + + + draconien + + + spéciaux + + + spécial + + + enchantements + + + enchantement + + + golems de fer + + + golem de fer + + + golems de pierre + + + golem de pierre + + + ombres + + + ombre + + + lémures + + + lémure + + + yétis + + + yéti + + + quauquemaires + + + quauquemaire + + + crapauds + + + crapaud + + + céphalophages + + + céphalophage + + + paysans + + + paysan + + + wargs + + + warg + + + lynx + + + lynx + + + vers des profondeurs + + + ver des profondeurs + + + rats + + + rat + + + dragons chinois + + + dragon chinois + + + loups + + + loup + + + fantômes + + + fantôme + + + chats des rêves + + + chat des rêves + + + chats de l'Enfer + + + chat de l'Enfer + + + tigres + + + tigre + + + dauphins + + + dauphin + + + tortues géantes + + + tortue géante + + + krakens + + + kraken + + + serpents de mer + + + serpent de mer + + + guerriers illusoires + + + guerrier illusoire + + + diablotins + + + diablotin + + + nymphes + + + nymphe + + + licornes + + + licorne + + + hiboux + + + hibou + + + fées + + + fée + + + aigles + + + aigle + + + centaures + + + centaure + + + squelettes + + + squelette + + + liches + + + liche + + + zombies + + + zombie + + + zombies juju + + + zombie juju + + + goules + + + goule + + + spectres + + + spectre + + + fantômes du musée + + + fantôme du musée + + + gnomes + + + gnome + + + modèles + + + modèle + + + métamorphes + + + métamorphe + + + + + + Options + + + Niveau + + + Statut Politique + + + Plantes nécessaires + + + en construction + + + de dégâts + + + Votre faction a été éliminée. Nous espérons que vous vous êtes bien amusé malgré tout, et vous encourageons à vous réincrire pour une nouvelle partie. + + + + compétences + + + possessions + + + taille + + + sorts + + + sorts de combat + + + aucun + + + Adresses + + + anonyme + + + attaque + + + défense + + + armure + + + dégâts + + + + + baguette + + + baguettes + + + + + + côte nord-ouest + + + côte nord-est + + + côte est + + + côte sud-est + + + côte sud-ouest + + + côte ouest + + + + Aucun ordre reçu pour votre faction ! + + diff --git a/res/messages.xml b/res/messages.xml index 533ec1418..7e9822511 100644 --- a/res/messages.xml +++ b/res/messages.xml @@ -1,8518 +1,8518 @@ - - - - - - - Ein Alp starb in $region($region), ohne sein Ziel zu erreichen. - An alp died in $region($region) before reaching its target. - - - - - - "Einheiten können die folgenden Gegenstände beanspruchen: $resources($items)" - "Units can claim the following items: $resources($items)" - - - - - - - - "$if($isnull($region),"Es","In $region($region)") wurde$if($eq($number,1),"","n") $int($number) $race($race,$number) gesichtet." - "$if($isnull($region),"","In $region($region), ")$int($number) $race($race,$number) were discovered." - - - - - - - "$unit($mage) läßt einen Teil seiner selbst in die Erde fliessen. Die Bäume, die Transformation überlebt haben, erscheinen nun viel kräftiger." - "The power of $unit($mage) flows into the region and the trees which survived the spell appear stronger now." - "The power of $unit($mage) flows into the region and the trees which survived the spell appear stronger now." - - - - - - - "$unit($mage) beschwört einen Luftgeist, der die $ship($ship) in die Wolken hebt." - "$unit($mage) summons a wind spirit that lifts the $ship($ship) into the clouds." - - - - - - "$unit($mage) beschwört einen Schleier der Verwirrung." - "$unit($mage) summons a fog of confusion." - - - - - Eine Feuerwand blockiert die Ein- und Ausreise. ($int36($id)) - - - - - Der Magier besitzt die Gabe des Chaos. ($int36($id)) - The magician possesses the gift of Chaos. ($int36($id)) - - - - Dieser mächtige Bann scheint die Einheit ihres freien Willens zu berauben. Solange der Zauber wirkt, wird sie nur den Befehlen ihres neuen Herrn gehorchen. ($int36($id)) - - - - Dieser Beeinflussungszauber scheint die Einheit einem ganz bestimmten Volk wohlgesonnen zu machen. ($int36($id)) - - - - Dieser Zauber verursacht einen gigantischen magischen Strudel. Der Mahlstrom wird alle Schiffe, die in seinen Sog geraten, schwer beschädigen. ($int36($id)) - - - - Heilung ist in dieser Region magisch beeinflusst. ($int36($id)) - - - - Dieses Schiff hat sich verfahren. ($int36($id)) - - - - - - - - "$unit($unit) ist im Traum eine Fee erschienen. ($int36($id))" - "In a dream, a fairy appears to $unit($unit). ($int36($id))" - - - - - - - "$unit($unit) wird von bösen Alpträumen geplagt. ($int36($id))" - "$unit($unit) is haunted by terrbile nightmares. ($int36($id))" - - - - - - - "$unit($unit) wird von einem glitzernden Funkenregen umgeben. ($int36($id))" - "$unit($unit) is surrounded by a shower of glittering sparkles. ($int36($id))" - - - - - - - "Ein schimmernder Lichterkranz umgibt $unit($unit). ($int36($id))" - "A circle of shimmering lights surrounds $unit($unit). ($int36($id))" - - - - - - - "Eine Melodie erklingt, und $unit($unit) tanzt bis spät in die Nacht hinein. ($int36($id))" - "A haunting melody fills the air, and $unit($unit) dances until late into the night. ($int36($id))" - - - - - - - "$unit($unit) findet eine kleine Flöte, die eine wundersame Melodie spielt. ($int36($id))" - "$unit($unit) finds a small flute that plays a beautiful melody. ($int36($id))" - - - - - - - "Die Frauen des nahegelegenen Dorfes bewundern $unit($unit) verstohlen. ($int36($id))" - "The women of the nearby village cast furtive looks at $unit($unit). ($int36($id))" - - - - - - - "Eine Gruppe vorbeiziehender Bergarbeiter rufen $unit($unit) eindeutig Zweideutiges nach. ($int36($id))" - "A group of passing miners makes passes at $unit($unit). ($int36($id))" - - - - - - - "$unit($unit) bekommt von einer Schlange einen Apfel angeboten. ($int36($id))" - "A large green snake offers $unit($unit) a fine-looking apple. ($int36($id))" - - - - - - "A spell is deflecting magical energies and weakening all other spells cast in the region. ($int36($id))" - "Dieser Zauber scheint magische Energien irgendwie abzuleiten und so alle in der Region gezauberten Sprüche in ihrer Wirkung zu schwächen oder ganz zu verhindern. ($int36($id))" - - - - - - - "Ein Einhorn berührt $unit($unit) mit seinem Horn und verschwindet kurz darauf im Unterholz. ($int36($id))" - "A unicorn touches $unit($unit) with its horn and vanishes into the forest quickly after. ($int36($id))" - - - - - - - "Vogelzwitschern begleitet $unit($unit) auf all seinen Wegen. ($int36($id))" - "Bird songs follow $unit($unit) on all his travels. ($int36($id))" - - - - - - - "Leuchtende Blumen erblühen rund um das Lager von $unit($unit). ($int36($id))" - "Brightly coloured flowers pop up all around $unit($unit)'s camp. ($int36($id))" - - - - - - - "Über $unit($unit) zieht eine Gruppe Geier ihre Kreise. ($int36($id))" - "A group of vultures circles above $unit($unit). ($int36($id))" - - - - - - - "Der Kopf von $unit($unit) hat sich in einen grinsenden Totenschädel verwandelt. ($int36($id))" - "The head of $unit($unit) has turned into a madly grinning skull. ($int36($id))" - - - - - - - "Ratten folgen $unit($unit) auf Schritt und Tritt. ($int36($id))" - "Rats follow $unit($unit)'s every step. ($int36($id))" - - - - - - - "Pestbeulen befallen den Körper von $unit($unit). ($int36($id))" - "The body of $unit($unit) is disfigured by hideous boils. ($int36($id))" - - - - - - - "Eine dunkle Fee erscheint $unit($unit) im Schlaf. Sie ist von schauriger Schönheit. ($int36($id))" - "A dark and mysterious fairy appears before $unit($unit). She is of bewitching beauty. ($int36($id))" - - - - - - - "Fäulnisgeruch dringt $unit($unit) aus allen Körperöffnungen. ($int36($id))" - "The stench of decay is poring from all the orifices of $unit($unit). ($int36($id))" - - - - - - - - "$unit($unit) mag $faction($faction) zu mögen. ($int36($id))" - "$unit($unit) likes $faction($faction). ($int36($id))" - - - - - - - - "$unit($unit) scheint $race($race, 0) zu mögen. ($int36($id))" - "$unit($unit) seems to like $race($race, 0). ($int36($id))" - - - - - - - - "$unit($unit) ist ungewöhnlich ungeschickt in $skill($skill). ($int36($id))" - "$unit($unit) has some troubles with $skill($skill). ($int36($id))" - - - - - - - - "$unit($unit) ist ungewöhnlich geschickt in $skill($skill). ($int36($id))" - "$unit($unit) is incredibly skilled at $skill($skill). ($int36($id))" - - - - - - - - "$unit($unit) wird noch $int($duration) $if($eq($duration,1), "Woche", "Wochen") unter unserem Bann stehen. ($int36($id))" - "$unit($unit) will be under our influence for $int($duration) more $if($eq($duration,1), "week", "weeks"). ($int36($id))" - - - - - - - - - "$int($number) $if($eq($number,1), "Person", "Personen") von $unit($unit) $if($eq($number,1), "ist", "sind") noch $int($duration) $if($eq($duration,1), "Woche", "Wochen") beschleunigt. ($int36($id))" - "$int($number) $if($eq($number,1), "member", "members") of $unit($unit) $if($eq($number,1), "is", "are") accelerated for $int($duration) more $if($eq($duration,1), "week", "weeks"). ($int36($id))" - - - - - - - - "$int($number) $if($eq($number,1), "Person", "Personen") von $unit($unit) $if($eq($number,1), "fühlt", "fühlen") sich vor Kälte geschützt. ($int36($id))" - "$int($number) $if($eq($number,1), "member", "members") of $unit($unit) $if($eq($number,1), "is", "are") protected from the cold. ($int36($id))" - - - - - - "Ein unbekannter Zauber liegt auf dem Schiff. ($int36($id))" - "An unknown spell lies on this ship. ($int36($id))" - - - - - - "Ein unbekannter Zauber liegt auf der Einheit. ($int36($id))" - "An unknown spell lies on this unit. ($int36($id))" - - - - - - "Ein unbekannter Zauber liegt auf dem Gebäude. ($int36($id))" - "An unknown spell lies on this building. ($int36($id))" - - - - - - "Ein unbekannter Zauber liegt auf der Region. ($int36($id))" - "An unknown spell lies on this region. ($int36($id))" - - - - - - "Eine Wolke negativer Energie liegt über der Region. ($int36($id))" - "A fog of negative energy enshrouds the region. ($int36($id))" - "A fog of negative energy enshrouds the region. ($int36($id))" - - - - - - "Die Leute strotzen nur so vor Kraft. ($int36($id))" - "Testosterone levels are at an all-time high. ($int36($id))" - - - - - - - "$unit($unit) wird von einem Alp geritten. ($int36($id))" - "$unit($unit) is chased by a nightmare. ($int36($id))" - - - - - - - "$unit($unit) stürzt sich von einem amourösen Abenteuer ins nächste. ($int36($id))" - "$unit($unit) goes from one amourous adventure to another. ($int36($id))" - "$unit($unit) goes from one amourous adventure to another. ($int36($id))" - - - - - - - "$unit($unit) kann sich kaum konzentrieren. ($int36($id))" - "$unit($unit) can hardly focus on anything. ($int36($id))" - "$unit($unit) can hardly focus on anything. ($int36($id))" - - - - - - - "Die Ausrüstung von $unit($unit) scheint unsichtbar. ($int36($id))" - "$unit($unit)'s equipment is invisible. ($int36($id))" - "$unit($unit)'s equipment is invisible. ($int36($id))" - - - - - - "Die natürliche Widerstandskraft gegen Verzauberung ist gestärkt. ($int36($id))" - "($int36($id))" - "The magical resistance has been strengthened. ($int36($id))" - - - - - - "Die natürliche Widerstandskraft gegen Verzauberung bestimmter Einheiten in dieser Region wurde gestärkt. ($int36($id))" - "($int36($id))" - "The magical resistance of some units in this region was boosted. ($int36($id))" - - - - - - "Die natürliche Widerstandskraft gegen Verzauberung bestimmter Einheiten in dieser Region wurde geschwächt. ($int36($id))" - "The magical resistance of some units in this region was weakened. ($int36($id))" - "($int36($id))" - - - - - - "Diese Mauern wirken, als wären sie direkt aus der Erde gewachsen und nicht erbaut. ($int36($id))" - "These walls appear to have grown straight out of the earth. ($int36($id))" - "($int36($id))" - - - - - - "Ein magischer Schimmer liegt auf diesen Mauern. ($int36($id))" - "A magical shimmer lies on these walls. ($int36($id))" - "($int36($id))" - - - - - - "Die Straßen sind erstaunlich trocken und gut begehbar, doch an manchen Stellen bilden sich wieder die erste Schlammlöcher. ($int36($id))" - "The roads are extremely dry and well-kept, but some areas show the first signs of potholes reappearing. ($int36($id))" - "($int36($id))" - - - - - - "Die Straßen sind erstaunlich trocken und gut begehbar. ($int36($id))" - "The roads are extremely dry and well-kept. ($int36($id))" - "($int36($id))" - - - - - - "Albträume plagen die Leute. ($int36($id))" - "Nightmares plague the population. ($int36($id))" - "($int36($id))" - - - - - - "Die Leute haben schöne Träume. ($int36($id))" - "($int36($id))" - "The people in this region have sweet dreams. ($int36($id))" - - - - - - "Diese Region wurde von den Göttern verflucht. Das Meer ist eine ekelige Brühe, braunschwarze, stinkende Gase steigen aus den unergründlichen Tiefen hervor, und untote Seeungeheuer, Schiffe zerfressend und giftige grüne Galle geifernd, sind der Schrecken aller Seeleute, die diese Gewässer durchqueren. Niemand kann hier lange überleben. ($int36($id))" - "($int36($id))" - "This region was cursed by the gods. The sea is a foul cesspool, noxious gases rise from the deep, undead seamonsters attack all ships. Noone can live here for long. ($int36($id))" - - - - - - "Diese Region wurde von den Göttern verflucht. Stinkende Nebel ziehen über die tote Erde und furchtbare Kreaturen ziehen über das Land. Die Brunnen sind vergiftet, und die wenigen essbaren Früchte sind von einem rosa Pilz überzogen. Niemand kann hier lange überleben. ($int36($id))" - "($int36($id))" - "This region was cursed by the gods. Noone can live here for long. ($int36($id))" - - - - - - "Ein Schleier der Verwirrung liegt über der Region. ($int36($id))" - "($int36($id))" - "A veil of confusion lies over the region. ($int36($id))" - - - - - - "In der Region treibt ein Giftelementar sein Unwesen. ($int36($id))" - "A poison elemental is spreading pestilence and death. ($int36($id))" - - - - - - "Die ganze Region ist von einer friedlichen Stimmung erfasst. ($int36($id))" - "($int36($id))" - "Everyone in this region seems to be in a peacful mood. ($int36($id))" - - - - - - "Es herrscht eine fröhliche und ausgelassene Stimmung. ($int36($id))" - "($int36($id))" - "Everyone in this region seems to be having a very good time. ($int36($id))" - - - - - - "Die Bauern sind unzufrieden. ($int36($id))" - "($int36($id))" - "The peasants are upset. ($int36($id))" - - - - - - "Alle Leute in der Region haben Schlafstörungen. ($int36($id))" - "($int36($id))" - "People in this region suffer from insomnia. ($int36($id))" - - - - - - "In dieser Gegend herrscht eine Dürre. ($int36($id))" - "($int36($id))" - "This region was hit by a drought. ($int36($id))" - - - - - - "In dieser Gegend steht das Korn besonders gut im Feld. ($int36($id))" - "($int36($id))" - "The grain in this region is especially healthy. ($int36($id))" - - - - - - "Die Winde scheinen dieses Schiff besonders zu beguenstigen. ($int36($id))" - "($int36($id))" - "The winds seem to favor this ship. ($int36($id))" - - - - - - "Untote schrecken vor dieser Region zurück. ($int36($id))" - "($int36($id))" - "The undead turn away from this region. ($int36($id))" - - - - - - "Der Zahn der Zeit kann diesen Mauern nichts anhaben. ($int36($id))" - "($int36($id))" - "Time cannot touch these walls. ($int36($id))" - - - - - - "Dichte Nebel bedecken diese Woche die Region. Keine Einheit schafft es, diese Nebel zu durchdringen und die Region zu verlassen. ($int36($id))" - "heavy fog makes it impossible to leave the region. ($int36($id))" - "heavy fog makes it impossible to leave the region. ($int36($id))" - - - - - - - "$unit($unit) setzt ein Sonnensegel. Die Geschwindigkeit des Schiffes erhöht um $int($speed)." - "$unit($unit) sets a solar sail. The ship's speed is increased by $int($speed)." - "$unit($unit) sets a solar sail. The ship's speed is increased by $int($speed)." - - - - - - "Interner Fehler: Meldung '$name' nicht definiert." - "Internal Error: Message '$name' is undefined." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Interner Fehler: Meldung '$name' nicht definiert." - "$unit($unit) in $region($region): '$order($command)' - Internal Error: Message '$name' is undefined." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier ist kein passendes Schloss." - "$unit($unit) in $region($region): '$order($command)' - No fitting lock can be found here." - "$unit($unit) in $region($region): '$order($command)' - No fitting lock can be found here." - - - - - - - - "$unit($unit) öffnet eines der Schlösser in $region($region) mit $if($eq($key,1),"dem Achatenen Schlüssel","dem Saphirnen Schlüssel")." - "$unit($unit) unlocks one of the locks in $region($region) with $if($eq($key,1),"the Agate Key","the Sapphire Key")." - "$unit($unit) unlocks one of the locks in $region($region) with $if($eq($key,1),"the Agate Key","the Sapphire Key")." - - - - - - - - "$unit($unit) verschließt eines der Schlösser in $region($region) mit $if($eq($key,1),"dem Achatenen Schlüssel","dem Saphirnen Schlüssel")." - "$unit($unit) locks one of the locks in $region($region) with $if($eq($key,1),"the Agate Key","the Sapphire Key")." - "$unit($unit) locks one of the locks in $region($region) with $if($eq($key,1),"the Agate Key","the Sapphire Key")." - - - - - - - "$unit($unit) in $region($region) verwandelt sich in ein Werwesen." - "$unit($unit) in $region($region) becomes a lycantrope." - "$unit($unit) in $region($region) becomes a lycantrope." - - - - - - - "SIEG! $if($eq($n,1), "Die Partei $winners hat", "Die Parteien $winners haben") die Siegbedingung für die erforderliche Zeit erfüllt. Das Spiel ist damit beendet." - "VICTORY! $if($eq($n,1), "The faction $winners has", "The factions $winners have") fulfilled the victory condition for the necessary time. The game is over." - "VICTORY! $if($eq($n,1), "The faction $winners has", "The factions $winners have") fulfilled the victory condition for the necessary time. The game is over." - - - - - - "Achtung: $faction($faction) hat die Siegbedingungen erfüllt und wird in $if($eq($remain,1),"einer Woche","$int($remain) Wochen") zum Sieger erklärt werden." - "Attention: $faction($faction) has fulfilled the victory condition and will be declared winner in $if($eq($remain,1),"one week","$int($remain) weeks")." - "Attention: $faction($faction) has fulfilled the victory condition and will be declared winner in $if($eq($remain,1),"one week","$int($remain) weeks")." - - - - - - - - "$unit($unit) wurde in $region($region) von einem GM gelöscht: \"$string\"." - "$unit($unit) in $region($region) was removed by a GM: \"$string\"." - "$unit($unit) in $region($region) was removed by a GM: \"$string\"." - - - - - - - - "$resource($item,1) (Gewicht: $weight($weight)): $description" - "$resource($item,1) (weight: $weight($weight)): $description" - - - - - "Ein Hauch des Lebens liegt über der Welt und alle Wesen fühlen sich frisch und erholt." - "Life itself touches the world and all beings are healed." - "Life itself touches the world and all beings are healed." - - - - - - - - "$unit($unit) hat Glück und findet einen Hort von $int($amount) $resource($item,$amount)." - "$unit($unit) luckily finds a cache of $int($amount) $resource($item,$amount)." - "$unit($unit) luckily finds a cache of $int($amount) $resource($item,$amount)." - - - - - - "$unit($unit) brennt ein großes Feuerwerk ab und Kaskaden bunter Sterne, leuchtende Wasserfälle aus Licht und strahlende Feuerdrachen erhellen den Himmel." - "A large firework is visible all over the sky." - "A large firework is visible all over the sky." - - - - - - - "In $region($region) wird ein großes Feuerwerk abgebrannt, welches noch hier zu bewundern ist. Kaskaden bunter Sterne, leuchtende Wasserfälle aus Licht und strahlende Feuerdrachen erhellen den Himmel." - "A large firework, visible all over the sky, has been started in $region($region)." - "A large firework, visible all over the sky, has been started in $region($region)." - - - - - - - "Zur Feier des Geburtstags von ${name} brennt $unit($unit) ein großes Feuerwerk ab. Kaskaden bunter Sterne, leuchtende Wasserfälle aus Licht und strahlende Feuerdrachen erhellen den Himmel." - "A large firework in honor of ${name} is visible all over the sky." - "A large firework in honor of ${name} is visible all over the sky." - - - - - - - - "Zur Feier des Geburtstags von ${name} wird in $region($region) ein großes Feuerwerk abgebrannt, welches noch hier zu bewundern ist. Kaskaden bunter Sterne, leuchtende Wasserfälle aus Licht und strahlende Feuerdrachen erhellen den Himmel." - "A large firework in honor of ${name}, visible all over the sky, has been started in $region($region)." - "A large firework in honor of ${name}, visible all over the sky, has been started in $region($region)." - - - - - - - "$int36($unit.id($unit))/$int($index) erzielt einen kritischen Treffer." - "$int36($unit.id($unit))/$int($index) does critical damage." - "$int36($unit.id($unit))/$int($index) does critical damage." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) muß mindestens 2 Stufen besser sein als $unit($student)." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) needs to be at least 2 levels better than $unit($student)." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) needs to be at least 2 levels better than $unit($student)." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($student) lernt nicht." - "$unit($unit) in $region($region): '$order($command)' - $unit($student) is not learning." - "$unit($unit) in $region($region): '$order($command)' - $unit($student) is not learning." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dafür braucht die Einheit $resources($required)." - "$unit($unit) in $region($region): '$order($command)' - for this, the unit needs $resources($required)." - "$unit($unit) in $region($region): '$order($command)' - for this, the unit needs $resources($required)." - - - - - - $trailto($region) - $trailto($region) - - - - - - - "Deine Partei hat $int($units) Migranten und kann maximal $int($maxunits) Migranten aufnehmen." - "Your faction has $int($units) migrants out of a possible total of $int($maxunits)." - - - - - - - - - "Seit $int($age) Wochen Mitglied der Allianz '$name ($int36($id))', angeführt von $faction($leader)." - "Member of '$name ($int36($id))' for $int($age) weeks, led by $faction($leader)." - - - - - - - "Deine Partei hat $int($units) Helden und kann maximal $int($maxunits) Helden ernennen." - "Your faction has promoted $int($units) heroes out of a possible total of $int($maxunits)." - - - - - - - "Deine Partei hat $int($population) Personen in $int($units) Einheiten." - "Your faction has $int($population) people in $int($units) units." - - - - - - "Statistik für $region($region):" - "Statistics for $region($region):" - - - - - - "Unterhaltung: max. $int($max) Silber" - "Entertainment: max. $int($max) silver" - - - - - - "Moral der Bauern: $int($morale)" - "Peasant morale: $int($morale)" - - - - - - "Luxusgüter zum angegebenen Preis: $int($max)" - "Luxury goods at this price: $int($max)" - - - - - - "Lohn für Arbeit: $int($max) Silber" - "Worker salary: $int($max) silver" - - - - - - "Bauerneinnahmen: $int($max) Silber" - "Peasant wages: $int($max) silver" - - - - - - "Personen: $int($max)" - "People: $int($max)" - "People: $int($max)" - - - - - - "Rekruten: max. $int($max) Bauern" - "Recruits: $int($max) peasants" - "Recruits: $int($max) peasants" - - - - - - - "Deine Partei hat $int($score) Punkte. Der Durchschnitt für Parteien ähnlichen Alters ist $int($average) Punkte." - "Your faction has a score of $int($score). The average score for similar factions is $int($average)." - "Your faction has a score of $int($score). The average score for similar factions is $int($average)." - - - - - - - "Report für $game, $date" - "Report for $game, $date" - "Report for $game, $date" - - - - - - - "Im $direction($dir) der Region liegt $trailto($region)" - "To the $direction($dir) lies $trailto($region)" - - - - - - - "$resource($product,0) $int($price) Silber" - "$resource($product,0) for $int($price) silver" - "$resource($product,0) for $int($price) silver" - - - - - - - "Auf dem Markt wird für $resource($product,0) $int($price) Silber verlangt." - "Le marché local offre la $resource($product,0) au prix de $int($price) écus." - "The local market offers $resource($product,0) at a price of $int($price) silver." - - - - - - - "Auf dem Markt werden $resource($p1,0) und $resource($p2,0) feilgeboten." - "The local market offers $resource($p1,0) and $resource($p2,0)." - - - - - - "Auf dem Markt wird $resource($p1,0) feilgeboten." - "The local market offers $resource($p1,0)." - - - - - - "Dein Passwort lautet ${password}." - "Your password is ${password}." - "Your password is ${password}." - - - - - - "Die Mannschaft krank vom vergifteten Wasser, Planken, Ruder und Segel zerfressen von den Wassern des verfluchten Meeres, ergibt sich die $ship($ship) in ihr Schicksal und sinkt." - "Her sailors sick from the poisened ocean, planks, rudder und sails corroded by the waters of the cursed ocean, the $ship($ship) finally succumbs to her destiny and sinks." - - - - - - "$unit($unit) benutzt einen Talenttrunk und fühlt, wie sein Wissen zunimmt." - "$unit($unit) uses a potion of skills and feels his knowledge grow." - "$unit($unit) uses a potion of skills and feels his knowledge grow." - - - - - - - "$unit($unit) benutzt einen Astralkristall und gewinnt $int($aura) Aura hinzu." - "$unit($unit) uses an astralcrystal and gains $int($aura) aura." - "$unit($unit) uses an astralcrystal and gains $int($aura) aura." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieses Luxusgut wird hier nicht verkauft." - "$unit($unit) in $region($region): '$order($command)' - These goods are not on sale here." - "$unit($unit) in $region($region): '$order($command)' - These goods are not on sale here." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dazu benötigt man $resource($missing,0)." - "$unit($unit) in $region($region): '$order($command)' - This requires $resource($missing,0)." - "$unit($unit) in $region($region): '$order($command)' - This requires $resource($missing,0)." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) nehmen nichts an." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) will not accept anything." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) will not accept anything." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können nicht neu gruppiert werden." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot be regrouped." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot be regrouped." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können nichts stehelen." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot steal anything." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot steal anything." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) geben nichts weg." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) do not give things away." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) do not give things away." - - - - - - - - "Eine Botschaft von $unit.dative($sender) aus $region($region): '$string'" - "A message by $unit($sender) from $region($region): '$string'" - - - - - - - - - "In $region($region) erhielt $unit($unit) eine Botschaft von $unit.dative($sender): '$string'" - "In $region($region), $unit($unit) received a message by $unit($sender): '$string'" - - - - - - - - - "In $region($region) erhielt $unit($unit) von $unit.dative($sender) $resources($items)" - "In $region($region), $unit($unit) received $resources($items) from $unit($sender)" - - - - - - "$building($building) hat diese Woche nicht funktioniert, da zu Beginn der Woche der Unterhalt nicht gezahlt werden konnte." - "$building($building) was nonfunctional because upkeep could not be paid at the beginning of the week." - - - - - - "Plötzlich löst sich $building($building) in kleine Traumwolken auf." - "$building($building) suddenly dissolves into small pink clouds." - - - - - - "Für das Gebäude $building($building) konnte die ganze Woche kein Unterhalt bezahlt werden." - "Upkeep for $building($building) could not be paid all week." - - - - - - - - - "In $region($region) stürzte $building($building) ein.$if($road," Beim Einsturz wurde die halbe Straße vernichtet.","")$if($opfer," $int($opfer) Opfer $if($eq($opfer,1),"ist","sind") zu beklagen.","")" - "$building($building) in $region($region) collapses.$if($opfer," There are $int($opfer) caualties.","")" - "$building($building) in $region($region) collapses.$if($opfer," There are $int($opfer) caualties.","")" - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - In der Ebene der Herausforderung kann niemand rekrutiert werden." - "$unit($unit) in $region($region): '$order($command)' - You cannot recruit in this plane." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die einheit kann sich nicht so gut tarnen." - "$unit($unit) in $region($region): '$order($command)' -The unit cannot hide that well." - - - - - - - - "$ship($ship) was destroyed by $unit($unit)." - "$ship($ship) wurde von $unit($unit) zerstört." - - - - - - - - "$unit($unit) could not destroy $ship($ship)." - "$unit($unit) konnte $ship($ship) nicht zerstören." - - - - - - - - "$unit($unit) was detected while trying to destroy $ship($ship)." - "$unit($unit) wurde beim Versuch $ship($ship) zu zerstören entdeckt." - - - - - - - "Somebody attempted to destroy $ship($ship)." - "Es wurde versucht, $ship($ship) zu zerstören." - - - - - - - "$ship($ship) was destroyed." - "$ship($ship) wurde zerstört." - - - - - - - - - "$int($amount) Personen von $unit($unit) ertrinken.$if($isnull($region),""," Die Einheit rettet sich nach $region($region).")" - - - - - - - - "$unit($unit) ueberlebt unbeschadet und rettet sich nach $region($region)." - - - - - - - - "$ship($ship) versinkt in den Fluten von $region($region)." - - - - - - - - "$unit($unit) wurde beim versenken von $ship($ship) entdeckt." - - - - - - - - - "$unit($unit) entdeckte $unit($saboteur) beim versenken von $ship($ship)." - - - - - - - - "$unit($unit) ertrinkt in $region($region)." - "$unit($unit) drowns in in $region($region)." - - - - - - - - - "$int($amount) Personen in $unit($unit) in $region($region) ertrinken." - "$int($amount) people in $unit($unit) in $region($region) drown." - "$int($amount) people in $unit($unit) in $region($region) drown." - - - - - - - "$unit($unit) nimmt Schaden auf dem Wasser in $region($region)." - "$unit($unit) is taking damage on the water." - "$unit($unit) is taking damage on the water." - - - - - - "$unit($unit) schwenkt sein Szepter und sorgt für Verwirrung und Chaos in der Region." - - - - - - - - - "$unit($unit) stolpert bei der Erforschung der Region über $localize($location). Nähere Durchsuchung fördert ein zerfleddertes altes Buch mit dem Titel '$localize($book)' zu Tage. Der Wissensschub ist enorm." - - - - "Ein Alp hat sein Opfer gefunden und springt auf den Rücken von $unit($target)!" - - - - - - - - "$unit($unit) fühlt sich von starken magischen Energien durchströmt. ($int36($id))" - "Powerful magical energies are pulsing through $unit($unit). ($int36($id))" - - - - - - - - "$unit($unit) hat Schwierigkeiten seine magischen Energien zu sammeln. ($int36($id))" - - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($amount) Krieger sind für einen Moment benommen." - "$unit($mage) casts $spell($spell): $int($amount) fighters were momentarily stunned." - - - - - - - - "$unit($mage) besänftigt den Bauernaufstand in $region($region)." - "$unit($mage) quells the uprising in $region($region)." - - - - - - - - "$unit($mage) rief in $region($region) einen Riss in dem Gefüge der Magie hervor, der alle magische Kraft aus der Region riss." - - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden in Schlaf versetzt." - "$unit($mage) casts $spell($spell): $int($amount) fighters have fallen asleep." - - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($amount) Kriegern wurde ihre Lebenskraft entzogen." - "$unit($mage) casts $spell($spell): $int($amount) fighters had their life energy drained." - - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($amount) Kriegern wurden versteinert." - "$unit($mage) casts $spell($spell): $int($amount) fighters were petrified." - - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden in einen Blutrausch versetzt." - "$unit($mage) casts $spell($spell): $int($amount) fighters went into a mindless rage." - - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden eingeschüchtert." - "$unit($mage) casts $spell($spell): $int($amount) fighters were intimidated." - - - - - - - - "$unit($mage) zaubert $spell($spell), aber es gab niemanden, der beeinflusst werden konnte." - "$unit($mage) casts $spell($spell), but nobody is impressed." - - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden von Furcht gepackt." - "$unit($mage) casts $spell($spell): $int($amount) fighters were consumed by fear." - - - - - - - - "$unit($mage) zaubert $spell($spell): Das Kampfgetümmel erstirbt und er kann unbehelligt seines Weges ziehen." - "$unit($mage) casts $spell($spell): The noise of the battle dies down and he is able to slip away unharmed." - - - - - - - - "$unit($mage) zaubert $spell($spell): Ein Sturm kommt auf und die Schützen können kaum noch zielen." - "$unit($mage) casts $spell($spell): Strong stormwinds are blowing and the archers are having a hard time aiming." - - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($amount) Krieger schleppten sich müde in den Kampf." - "$unit($mage) casts $spell($spell): $int($amount) fighters had trouble staying awake." - - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden moralisch gestärkt." - "$unit($mage) casts $spell($spell): $int($amount) fighters had their moral boosted." - - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden magisch beschleunigt." - "$unit($mage) casts $spell($spell): $int($amount) fighters were magically accelerated." - - - - - - - "$unit($mage) ruft ein fürchterliches Unwetter über seine Feinde, doch es gab niemanden mehr, den dies treffen konnte." - - - - - - - "$unit($mage) ruft ein fürchterliches Unwetter über seine Feinde, doch der magische Regen zeigt keinen Effekt." - - - - - - - "$unit($mage) ruft ein fürchterliches Unwetter über seine Feinde. Der magischen Regen lässt alles Eisen rosten." - - - - - - - - - "$unit($mage) beschwört den Alp $unit($alp) für $unit($target)." - "$unit($mage) summons the alp $unit($alp) for $unit($target)." - - - - - - - - "$unit($mage) kümmert sich um die Verletzten und heilt $int($amount) Verwundete." - "$unit($mage) sees after the wounded and heals $int($amount)." - - - - - - - - - "$unit($mage) kümmert sich um die Verletzten und benutzt ein $resource($item,1), um den Zauber zu verstärken. $int($amount) Verwundete werden geheilt." - "$unit($mage) sees after the wounded and heals $int($amount). A $resource($item,1) improves the spell." - - - - - - - - - "Mit einem Ritual bindet $unit($mage) die magischen Kräfte der Erde von $region($region) in die Mauern von $building($building)." - "$unit($mage) performs a ritual that binds the magical forces of $region($region) into the walls of $building($building)." - - - - - - - - - "$unit($mage) opfert $unit($target) $int($amount) Aura." - "$unit($mage) sacrifices $int($amount) aura for $unit($target)." - - - - - - - - "$unit($mage) beginnt ein Ritual der Wiederbelebung. $int($amount) Krieger stehen von den Toten auf." - "$unit($mage) begins a ritual of resurrection. $int($amount) warriors rise from the dead." - - - - - - - - - "$unit($mage) beginnt ein Ritual der Wiederbelebung und benutzt ein $resource($item,1), um den Zauber zu verstärken. $int($amount) Krieger stehen von den Toten auf." - "$unit($mage) begins a ritual of resurrection using a $resource($item,1). $int($amount) warriors rise from the dead." - - - - - - - "$unit($mage) öffnet ein Chaostor." - "$unit($mage) opens a chaos gate." - - - - "Ein Wirbel aus blendendem Licht erscheint." - "A vortex of blinding light appears." - - - - - - - - "$unit($mage) kann in $region($region) keine Untoten rufen." - "$unit($mage) cannot summon any undead in $region($region)." - - - - - - - - - "$unit($mage) erweckt in $region($region) $int($amount) Untote aus ihren Gräbern." - "$unit($mage) calls $int($amount) undead from their graves in $region($region)." - - - - - - - - "$unit($mage) stört in $region($region) die Ruhe der Toten." - "$unit($mage) communicates with the dead in $region($region)." - - - - - - - "$unit($unit) gelingt es, durch die Nebel auf die Realität zu blicken." - "$unit($unit) manages to catch a glimpse of reality through the fog." - - - - - - - - "$unit($mage) konnte $int($amount) $if($eq($amount,1),"Bauer","Bauern") anwerben." - "$unit($mage) managed to recruit $int($amount) $if($eq($amount,1),"peasant","peasants")." - - - - - - "Ein bohrender Schmerz durchzuckt $unit($unit), Verwirrung macht sich breit." - "Pain pulses through $unit($unit), confusion spreads." - - - - - - ""AAAAAAAGHHHHHH!" - Ein Schrei durchzieht die Region, $unit($unit) windet sich vor Schmerz." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Eine höhere Macht hindert $unit($unit) daran, das Objekt zu übergeben. 'ES IST DEINS, MEIN KIND. DEINS GANZ ALLEIN'." - - - - - - - "$unit($unit) sendet ein Stoßgebet an den Herrn der Schreie." - - - - - - - "Der Eisberg $region($region) schmilzt." - "The iceberg $region($region) melts." - "The iceberg $region($region) melts." - - - - - - "Der Gletscher von $region($region) bricht und treibt davon." - "The glacier in $region($region) breaks up and drifts away." - "The glacier in $region($region) breaks up and drifts away." - - - - - - "Der Eisberg $region($region) treibt an eine Küste." - "The iceberg $region($region) drifts onto a coast." - "The iceberg $region($region) drifts onto a coast." - - - - - - "Die $ship($ship) wird bei einer Kollision mit einem Eisberg zerstört." - "The $ship($ship) has been destroyed by a collision with an iceberg." - "The $ship($ship) has been destroyed by a collision with an iceberg." - - - - - - "Die $ship($ship) wird bei einer Kollision mit einem Eisberg beschädigt." - "The $ship($ship) has been damaged by a collision with an iceberg." - "The $ship($ship) has been damaged by a collision with an iceberg." - - - - - - - "Die $ship($ship) treibt nach $direction($dir)." - "The ship $ship($ship) drifts to the $direction($dir)." - "The ship $ship($ship) drifts to the $direction($dir)." - - - - - - - "Der Eisberg $region($region) treibt nach $direction($dir)." - "The iceberg $region($region) drifts $direction($dir)." - "The iceberg $region($region) drifts $direction($dir)." - - - - - - "Wir erklären allen $race($race,2) den heiligen Krieg." - "We declare jihad on all $race($race,2)." - - - - - - "Die Götter erhören $unit($unit)." - "The Gods have listened to $unit($unit)." - "The Gods have listened to $unit($unit)." - - - - - - - "Die Götter gewähren uns die Kraft eines $special($int($level))." - "The Gods grant us the powers of $special ($int($level))." - "The Gods grant us the powers of $special ($int($level))." - - - - - - "Die Götter gewähren uns die Kraft eines ${special}." - "The Gods grant us the powers of ${special}." - "The Gods grant us the powers of ${special}." - - - - - - - - - - "$unit($unit) verlor $int($fallen) Personen$if($alive,", $int($alive) überlebten","")$if($run," und $int($run) flohen$if($isnull($runto),""," nach $region($runto)")","")." - "$unit($unit) lost $int($fallen) people$if($alive,", $int($alive) survived","")$if($run," and $int($run) fled$if($isnull($runto),""," to $region($runto)")","")." - - - - - - - - "$unit($unit) erzielte $int($hits) Treffer und tötete $int($kills) Gegner." - "$unit($unit) hit $int($hits) times and killed $int($kills) enemies." - "$unit($unit) hit $int($hits) times and killed $int($kills) enemies." - - - - - - "$string" - "$string" - - - - - - - "Heer $int($index): $name" - "Army $int($index): $name" - - - - - - - "Verwundert blicken die Bauern von $region($region) auf ein neues Gebäude." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) gewinnt durch das Ritual $int($amount) Aura." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) receives $int($amount) aura." - - - - - - - - "$unit($mage) beschwört Naturgeister in den Boden von $region($region)." - "$unit($mage) summons natural spirits into the ground of $region($region)." - - - - - - - - - "$unit($mage) verwandelt $int($amount) aus $unit($target) in $race($race,0)." - "$unit($mage) transforms $int($amount) from $unit($target) into $race($race,0)." - - - - - - - - "$unit($mage) verwandelt $unit($target) in $race($race,0)." - "$unit($mage) tranforms $unit($target) to $race($race,0)." - - - - - - "$unit($mage) erlöst die gequälten Seelen der Toten." - "$unit($mage) redeems the tormented souls of the dead." - - - - - - "$unit($mage) verwandelt sich in einen Wyrm." - "$unit($mage) turns into a wyrm." - - - - - - - "$unit($mage) ruft Irrlichter in $region($region)." - "$unit($mage) summons wisps in $region($region)." - "$unit($mage) summons wisps in $region($region)." - - - - - - - "$unit($mage) erschafft in $region($region) eine Wand aus Feuer." - "$unit($mage) creates a wall of fire in $region($region)." - "$unit($mage) creates a wall of fire in $region($region)." - - - - - - - "$unit($mage) wiegelt in $region($region) die Bauern zum Aufstand auf." - "$unit($mage) incites a revolt among the peasants of $region($region)." - - - - - - - - - "$unit($mage) wiegelt in $region($region) $int($amount) Bauern zum Aufstand auf." - "$unit($mage) incites a revolt among $int($amount) peasants of $region($region)." - - - - - - - - "$unit($mage) sorgt in $region($region) für Trübsal unter den Bauern." - "$unit($mage) causes great sadness among the peasants of $region($region)." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier erschafft ein Traumgebäude." - "$unit($unit) in $region($region): '$order($command)' - The magician creates an illusionary building." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) kann keine $race($race,1)-Gestalt annehmen." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Elementar ist zu klein, um das Gebäude zu tragen." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Elementar weigert sich, nach $direction($direction) zu gehen." - "$unit($unit) in $region($region): '$order($command)' - The elemental refuses to go $direction($direction)." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) ist von unserer Art, das Ritual wäre verschwendete Aura." - "$unit($unit) in $region($region): '$order($command)' - $unit($target) is one of our kind, we should not waste aura on this." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) wird von uns aufgenommen." - "$unit($unit) in $region($region): '$order($command)' - $unit($target) has become one of our kind." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) ruft Drachen nach $region($target)." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) calls dragons to $region($target)." - - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) erschafft $int($amount) ${object}." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) creates $int($amount) ${object}." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) creates $int($amount) ${object}." - - - - - - - - "Ein Beben erschüttert $building($building). Viele kleine Pseudopodien erheben das Gebäude und tragen es in Richtung $direction($direction)." - - - - - - - - "$unit($unit) benutzt in $region($region) ein Traumauge." - "$unit($unit) uses a dreameye in $region($region)." - - - - - - - "$unit($unit) benutzt in $region($region) einen Antimagiekristall." - "$unit($unit) uses an antimagic crystal in $region($region)." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Sphären des Chaos geben dem Magier einen Teil ihrer Kraft." - "$unit($unit) in $region($region): '$order($command)' - The sphere of chaos returns a part of his power to the magician." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier konnte keinen Fluch zerstören." - "$unit($unit) in $region($region): '$order($command)' - The magician could not destroy any magic." - - - - - - - - "In $region($region) dehnt $unit($unit) die Zeit für $int($amount) Personen." - "In $region($region), $unit($unit) bends time for $int($amount) men." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier zerstört $int($succ) Flüche auf ${target}." - "$unit($unit) in $region($region): '$order($command)' - The magician destroys $int($succ) spells on ${target}." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier zerstört den Fluch($id) auf ${target}." - "$unit($unit) in $region($region): '$order($command)' - The magician destroys the spell on ${target}." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Zauber ist nicht stark genug, um den Fluch auf ${target} zu zerstören." - "$unit($unit) in $region($region): '$order($command)' - The spell is not strong enough to destroy the curse on ${target}." - - - - - - - "$unit($mage) beschwört einen Giftelementar in $region($region)." - "$unit($mage) summons a poison elemental in $region($region)." - - - - - - - - "$unit($unit) in $region($region) wird von einem Unbekannten verflucht." - "$unit($unit) in $region($region) was cursed by an unknown magician." - - - - - - - - "$unit($mage) belegt $unit($target) mit einem Zauber." - "$unit($mage) puts a spell on $unit($target)." - - - - - - - "$unit($mage) belegt $unit($target) mit einem Kälteschutz." - "$unit($mage) puts protection from cold on $unit($target)." - - - - - - - "$unit($mage) legt einen Rosthauch auf $unit($target), doch der Rosthauch fand keine Nahrung." - "$unit($mage) puts a spell of rust on $unit($target), but it shows no effect." - - - - - - - - "$unit($mage) legt einen Rosthauch auf $unit($target). $int($amount) Waffen wurden vom Rost zerfressen." - "$unit($mage) puts a spell of rust on $unit($target). $int($amount) weapons are eaten by rust." - - - - - - - $if($isnull($mage),"Ein unentdeckter Magier",$unit($mage)) erschuf einen heiligen Hain von $int($amount) Schößlingen. - $if($isnull($mage),"An unknown magician ",$unit($mage)) created a holy forest of $int($amount) young trees. - - - - - - "$if($isnull($mage),"Ein unentdeckter Magier",$unit($mage)) segnet in einem kurzen Ritual die Felder." - "$if($isnull($mage),"an unseen magician",$unit($mage)) blesses the fields in a short ritual." - - - - - - "$unit($mage) beschwört die Mächte des Wassers und ein gigantischer Strudel bildet sich." - "$unit($mage) summons the power of the seas and a giant maelstrom forms." - - - - - - - "$unit($mage) belebt $int($amount) Bäume." - "$unit($mage) revives $int($amount) trees." - - - - - - - "$unit($mage) sorgt für trockene Straßen in $region($region)." - "$unit($mage) creates dry and well-repaired roads in $region($region)." - - - - - - - "$unit($mage) erfleht den Segen der Götter des Windes und des Wassers für $ship($ship)." - "$unit($mage) asks the gods of wind and water on behalf of the $ship($ship)." - - - - - - - - "$unit($unit) transferiert $int($aura) Aura auf $unit($target)." - "$unit($unit) transfers $int($aura) Aura to $unit($target)." - "$unit($unit) transfers $int($aura) Aura to $unit($target)." - - - - - - - - "$unit($mage) entzieht $unit($target) $int($aura) Aura." - "$unit($mage) draws $int($aura) aura from $unit($target)." - - - - - - - "$unit($unit) fühlt seine magischen Kräfte schwinden und verliert $int($aura) Aura." - "$unit($unit) feels the powers of magic fade and loses $int($aura) aura." - - - - - - "$unit($unit) fühlt sich einen Moment seltsam geschwächt." - "$unit($unit) fühlt strangely weakened." - - - - - - - "$unit($unit) konnte $unit($target) keine Aura entziehen." - "$unit($unit) could not draw aura from $unit($target)." - - - - - - - - "$unit($unit) wurde von $region($source) nach $unit($target) teleportiert." - "$unit($unit) was teleported from $region($source) to $unit($target)." - - - - - - - - - "$unit($mage) fand heraus, dass auf $ship($ship) der Zauber $curse($curse) liegt, der noch etwa $int($months) Wochen bestehen bleibt." - "$unit($mage) discovers that $ship($ship) is charmed with $curse($curse), which will last for, about $int($months) more weeks." - - - - - - - - - "$unit($mage) fand heraus, dass auf $building($building) der Zauber $curse($curse) liegt, der noch etwa $int($months) Wochen bestehen bleibt." - "$unit($mage) discovers that $building($building) is charmed with $curse($curse), which will last for, about $int($months) more weeks." - - - - - - - - - "$unit($mage) fand heraus, dass auf $unit($unit) der Zauber $curse($curse) liegt, der noch etwa $int($months) Wochen bestehen bleibt." - "$unit($mage) discovers that $unit($unit) is charmed with $curse($curse) that will last for about $int($months) more weeks." - - - - - - - - - "$unit($mage) fand heraus, dass auf $region($region) der Zauber $curse($curse) liegt, der noch etwa $int($months) Wochen bestehen bleibt." - "$unit($mage) discovers that $region($region) is charmed with $curse($curse), which will last for, about $int($months) more weeks." - - - - - - - - "$unit($mage) fand heraus, dass auf $ship($ship) der Zauber $curse($curse) liegt, dessen Kraft ausreicht, um noch Jahrhunderte bestehen zu bleiben." - "$unit($mage) discovers that $ship($ship) is charmed with $curse($curse), which will last for centuries." - - - - - - - - "$unit($mage) fand heraus, dass auf $building($building) der Zauber $curse($curse) liegt, dessen Kraft ausreicht, um noch Jahrhunderte bestehen zu bleiben." - "$unit($mage) discovers that $building($building) is charmed with $curse($curse), which will last for centuries." - - - - - - - - "$unit($mage) fand heraus, dass auf $unit($unit) der Zauber $curse($curse) liegt, dessen Kraft ausreicht, um noch Jahrhunderte bestehen zu bleiben." - "$unit($mage) discovers that $unit($unit) is charmed with $curse($curse), which will last for centuries." - - - - - - - - "$unit($mage) fand heraus, dass auf $region($region) der Zauber $curse($curse) liegt, dessen Kraft ausreicht, um noch Jahrhunderte bestehen zu bleiben." - "$unit($mage) discovers that $region($region) is charmed with $curse($curse), which will last for centuries." - - - - - - - "$unit($mage) meint, dass auf $ship($ship) ein Zauber liegt, konnte aber über den Zauber nichts herausfinden." - "It appears to $unit($mage) that $ship($ship) is charmed, but no details have been revealed." - "It appears to $unit($mage) that $ship($ship) is charmed, but no details have been revealed." - - - - - - - "$unit($mage) meint, dass auf $building($building) ein Zauber liegt, konnte aber über den Zauber nichts herausfinden." - "It appears to $unit($mage) that $building($building) is charmed, but no details have been revealed." - "It appears to $unit($mage) that $building($building) is charmed, but no details have been revealed." - - - - - - - "$unit($mage) meint, dass $unit($unit) verzaubert ist, konnte aber über den Zauber nichts herausfinden." - "It appears to $unit($mage) that $unit($unit) is charmed, but no details have been revealed." - "It appears to $unit($mage) that $unit($unit) is charmed, but no details have been revealed." - - - - - - - "$unit($mage) meint, dass auf $region($region) ein Zauber liegt, konnte aber über den Zauber nichts herausfinden." - "It appears to $unit($mage) that $region($region) is charmed, but no details have been revealed." - "It appears to $unit($mage) that $region($region) is charmed, but no details have been revealed." - - - - - - - "$unit($mage) meint, dass auf $ship($ship) kein Zauber liegt." - "It appears to $unit($mage) that $ship($ship) is not charmed." - "It appears to $unit($mage) that $ship($ship) is not charmed." - - - - - - - "$unit($mage) meint, dass auf $building($building) kein Zauber liegt." - "It appears to $unit($mage) that $building($building) is not charmed." - "It appears to $unit($mage) that $building($building) is not charmed." - - - - - - - "$unit($mage) meint, dass auf $unit($target) kein Zauber liegt." - "It appears to $unit($mage) that $unit($target) is not charmed." - "It appears to $unit($mage) that $unit($target) is not charmed." - - - - - - - "$unit($mage) meint, dass auf $region($region) kein Zauber liegt." - "It appears to $unit($mage) that $region($region) is not charmed." - "It appears to $unit($mage) that $region($region) is not charmed." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Region konnte nicht verzaubert werden." - "$unit($unit) in $region($region): '$order($command)' - The region could not be charmed." - "$unit($unit) in $region($region): '$order($command)' - The region could not be charmed." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $ship($ship) widersteht dem Zauber." - "$unit($unit) in $region($region): '$order($command)' - $ship($ship) resists the spell." - "$unit($unit) in $region($region): '$order($command)' - $ship($ship) resists the spell." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Gebäude $int36($id) konnte nicht verzaubert werden." - "$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be charmed." - "$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be charmed." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) widersteht dem Zauber." - "$unit($unit) in $region($region): '$order($command)' - $unit($target) resists the spell." - "$unit($unit) in $region($region): '$order($command)' - $unit($target) resists the spell." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Schiff $int36($id) wurde nicht gefunden." - "$unit($unit) in $region($region): '$order($command)' - Ship $int36($id) could not be located." - "$unit($unit) in $region($region): '$order($command)' - Ship $int36($id) could not be located." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Gebäude $int36($id) wurde nicht gefunden." - "$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be located." - "$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be located." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Einheit $id wurde nicht gefunden." - "$unit($unit) in $region($region): '$order($command)' - Unit $id could not be located." - "$unit($unit) in $region($region): '$order($command)' - Unit $id could not be located." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es wurde kein Ziel gefunden." - "$unit($unit) in $region($region): '$order($command)' - The spell could not find a target." - - - - - - - "$unit($mage) erleidet durch den Tod seines Vertrauten einen Schock." - "$unit($mage) receives a shock when his familiar dies." - - - - - - - - "$unit($unit) schafft es nicht, genug Kraft aufzubringen, um $spell($spell) auf Stufe $int($level) zu zaubern." - "$unit($unit) cannot muster enough energy to cast $spell($spell) on level $level($level)." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Für diesen Zauber fehlen noch $resources($list)." - "$unit($unit) in $region($region): '$order($command)' - Casting this spell requires an additional $resources($list)." - - - - - - - - "$unit($unit) hat nicht genügend Komponenten um $spell($spell) auf Stufe $int($level) zu zaubern." - "$unit($unit) has insufficient components to cast $spell($spell) on level $int($level)." - - - - - - - - "$unit($unit) unterläuft in $region($region) beim Zaubern von $spell($spell) ein Patzer." - "$unit($unit) fumbles while casting $spell($spell) in $region($region)." - - - - - - - - "Als $unit($unit) in $region($region) versucht, $spell($spell) zu zaubern, scheint plötzlich ein Beben durch die magische Essenz zu laufen und ein furchtbarer Sog versucht $unit($unit) in eine andere Dimension zu ziehen. Mit letzter Kraft gelingt es $unit($unit) sich zu retten." - "When $unit($unit) in $region($region) tries to cast $spell($spell), a sudden disturbance ripples through the magical realm and a terrible force attempts to drag the magician to another dimension. However, with a final effort of strength, $unit($unit) manages to save himself." - - - - - - - - "Als $unit($unit) in $region($region) versucht, $spell($spell) zu zaubern erhebt sich plötzlich ein dunkler Wind. Bizarre geisterhafte Gestalten kreisen um den Magier und scheinen sich von den magischen Energien des Zaubers zu ernähren. Mit letzter Kraft gelingt es $unit($unit) dennoch den Spruch zu zaubern." - "When $unit($unit) in $region($region) tries to cast $spell($spell), strong winds suddenly rise. Bizare ghostlike creatures circle around the magician and seem to be leeching his magical energy. However, with a final effort of strength, $unit($unit) manages to complete the spell." - - - - - - - - "Eine Botschaft von $unit.dative($unit) in $region($region): 'Ups! Quack, Quack!'" - "A message from $unit($unit) in $region($region): 'Oops! Croak, Croak!'" - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($mage) kann Zauber, die durch $unit($unit) gewirkt werden, nicht zusätzlich in die Ferne richten." - "$unit($unit) in $region($region): '$order($command)' - $unit($mage) cannot direct spells that are channeled through $unit($unit) into distant regions." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($mage) kann nicht genug Energie aufbringen, um diesen Spruch durch $unit($unit) zu wirken." - "$unit($unit) in $region($region): '$order($command)' - $unit($mage) cannot raise enough energy to channel the spell through $unit($unit)." - - - - - - - - "$unit($mage) ruft einen Vertrauten. $race($race, 0) können $skills lernen." - "$unit($mage) summons a familiar. $race($race, 0) can learn ${skills}." - - - - - - - - "$unit($unit) hat einen feuchtfröhlichen Abend in der Taverne verbracht. Ausser einem fürchterlichen Brummschädel ist da auch noch das dumme Gefühl $unit($mage) seine ganze Lebensgeschichte erzählt zu haben." - - - - - - - "$unit($unit) hat einen feuchtfröhlichen Abend in der - Taverne verbracht. Ausser einem fürchterlichen Brummschädel ist da auch - noch das dumme Gefühl die ganze Taverne mit seiner Lebensgeschichte - unterhalten zu haben." - - - - - - - - - "$unit($mage) gelingt es $unit($unit) zu verzaubern. $unit($unit) wird für etwa $int($duration) Wochen unseren Befehlen gehorchen." - - - - - - - - - "$unit($unit) gelingt es $spell($spell) zu zaubern, doch der Spruch zeigt keine Wirkung." - "$unit($unit) manages to cast $spell($spell), but the spell seems to have no effect." - - - - - - - - "$unit($unit) fühlt sich nach dem Zaubern von $spell($spell) viel erschöpfter als sonst und hat das Gefühl, dass alle weiteren Zauber deutlich mehr Kraft als normalerweise kosten werden." - "$unit($unit) feels far more exhausted than he should after casting $spell($spell) and assumes that any following spells will cost far more energy than usual." - - - - - - - "$unit($unit) in $region($region) hat rasende Kopfschmerzen und kann sich nicht mehr richtig konzentrieren. Irgendwas bei diesem Zauber ist fürchterlich schiefgelaufen." - "$unit($unit) in $region($region) is hit by a massive headacheand cannot concentrate on the spell. Some part of this ritual has gone very wrong indeed." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier verfängt sich in seinem eigenen Zauber." - - - "In der Region erstrahlen des Nachts bunte Lichter, Gloeckchen klingeln und frohes Kindergelaechter klingt durch den Wald." - "At night, colourful lights can be seen in this region, bells are a-ringing and the laughter of happy children seems to be everywhere in the forests." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Zauber von $unit.dative($unit) war viel zu schwach und löst sich gleich wieder auf." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) verzaubert ${target}." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) puts a spell on ${target}." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) gelingt es zwar die Region zu verzaubern, aber irgendwas ging schief." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) manages to put a spell on the region, but something went wrong nonetheless." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) gelingt es die Region zu verzaubern." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) puts a spell on the region." - - - - - - - "$unit($mage) erhöht die Körperkraft von $unit.dative($target) beträchtlich." - "$unit($mage) increases the strength of $unit($target) dramatically." - - - - - - - - "$unit($unit) in $region($region) regeneriert $int($amount) Aura." - "$unit($unit) régénère $int($amount) aura en $region($region)." - "$unit($unit) regenerates $int($amount) aura in $region($region)." - - - - - - "$string" - "$string" - - - - - - - - - "$unit($unit) in $region($region) verbraucht $int($cost) Silber für das Studium von $skill($skill)." - "$unit($unit) dépense $int($cost) écus en $region($region) pour apprendre $skill($skill)." - "$unit($unit) spends $int($cost) silver in $region($region) to study $skill($skill)." - - - - - - - "$unit($teacher) kann durch Dumpfbackenbrot nur $int($amount) Schüler lehren." - "Due to the effect of duncebuns, $unit($teacher) can only teach $int($amount) students." - - - - - - - - - "$unit($teacher) lehrt $unit($student) $skill($skill) auf Stufe $int($level)." - "$unit($teacher) teaches $unit($student) $skill($skill) to level $int($level)." - "$unit($teacher) teaches $unit($student) $skill($skill) to level $int($level)." - - - - - - - - "$unit($teacher) lehrt $unit($student) $skill($skill)." - "$unit($teacher) teaches $unit($student) $skill($skill)." - "$unit($teacher) teaches $unit($student) $skill($skill)." - - - - - - "$string" - "$string" - - - - - - - - "$unit($unit) verkauft $int($amount) $resource($resource,$amount)." - "$unit($unit) sells $int($amount) $resource($resource,$amount)." - "$unit($unit) sells $int($amount) $resource($resource,$amount)." - - - - - - - - "$unit($unit) kauft $int($amount) $resource($resource,$amount)." - "$unit($unit) buys $int($amount) $resource($resource,$amount)." - "$unit($unit) buys $int($amount) $resource($resource,$amount)." - - - - - - - "$unit($unit) bezahlt $int($money) Silber für den Kauf von Luxusgütern." - "$unit($unit) pays $int($money) silver for luxury items." - "$unit($unit) pays $int($money) silver for luxury items." - - - - - - - - "$unit($unit) verdient in $region($region) $int($amount) Silber durch den Verkauf von Luxusgütern." - "$unit($unit) earned $int($amount) silver in $region($region) by selling luxury items." - "$unit($unit) earned $int($amount) silver in $region($region) by selling luxury items." - - - - - - - - - "$unit($unit) arbeitet in $region($region) für einen Lohn von $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber." - "$unit($unit) works in $region($region) for a wage of $int($amount) $if($eq($wanted,$amount),""," out of $int($wanted)") silver." - "$unit($unit) works in $region($region) for a wage of $int($amount) $if($eq($wanted,$amount),""," out of $int($wanted)") silver." - - - - - - - - "$unit($unit) arbeitet in $region($region) für einen Lohn von $int($amount) Silber." - "In $region($region), $unit($unit) works for a wage of $int($amount) silver." - - - - - - - - - "$unit($unit) verdient in $region($region) $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber durch Unterhaltung." - "In $region($region), $unit($unit) earns only $int($amount) instead of$if($eq($wanted,$amount),""," of$if($eq($wanted,$amount),""," of $int($wanted)") ") with entertainment." - - - - - - - - "$unit($unit) fängt in $region($region) Fische im Wert von $int($amount) Silber." - "In $region($region), $unit($unit) catches fish worth $int($amount) silver." - - - - - - - - "$unit($unit) verdient in $region($region) $int($amount) Silber durch Unterhaltung." - "$unit($unit) earns $int($amount) in $region($region) with entertainment." - "$unit($unit) earns $int($amount) in $region($region) with entertainment." - - - - - - - - - "$unit($unit) verdient in $region($region) $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber durch Zauberei." - - - - - - - - "$unit($unit) verdient in $region($region) $int($amount) Silber durch Zauberei." - "$unit($unit) earns $int($amount) silver through simple magical services in $region($region)." - - - - - - - - - "$unit($unit) klaut in $region($region) $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber." - "$unit($unit) steals only $int($amount) silver instead of$if($eq($wanted,$amount),""," of$if($eq($wanted,$amount),""," of $int($wanted)") ") in $region($region)." - "$unit($unit) steals only $int($amount) silver instead of$if($eq($wanted,$amount),""," of$if($eq($wanted,$amount),""," of $int($wanted)") ") in $region($region)." - - - - - - - - "$unit($unit) klaut in $region($region) $int($amount) Silber." - "$unit($unit) steals $int($amount) silver in $region($region)." - - - - - - - - - "$unit($unit) treibt in $region($region) Steuern in Höhe von $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber ein." - "$unit($unit) collects taxes of only $int($amount) instead of$if($eq($wanted,$amount),""," of$if($eq($wanted,$amount),""," of $int($wanted)") ") silver in $region($region)." - - - - - - - - "$unit($unit) treibt in $region($region) Steuern in Höhe von $int($amount) Silber ein." - "$unit($unit) collects taxes of $int($amount) silver in $region($region)." - - - - - - - - - - "$unit($unit) verdient$if($eq($mode,4)," am Handel","") in $region($region) $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber$if($eq($mode,1)," durch Unterhaltung",$if($eq($mode,2)," durch Steuern",$if($eq($mode,3)," durch Handel",$if($eq($mode,5)," durch Diebstahl",$if($eq($mode,6)," durch Zauberei","")))))." - "$unit($unit) earns $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") in $region($region)." - "$unit($unit) earns $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") in $region($region)." - - - - - - - - - "$unit($unit) in $region($region) findet $int($amount) $resource($herb,$amount)." - "$unit($unit) in $region($region) finds $int($amount) $resource($herb,$amount)." - "$unit($unit) in $region($region) finds $int($amount) $resource($herb,$amount)." - - - - - - - "$unit($unit) züchtet $int($amount) Pferde." - "$unit($unit) breeds $int($amount) horses." - "$unit($unit) breeds $int($amount) horses." - - - - - - - - - "$unit($unit) pflanzt in $region($region) $int($amount) $resource($herb,$amount)." - "$unit($unit) plants $int($amount) $resource($herb,$amount) in $region($region)." - "$unit($unit) plants $int($amount) $resource($herb,$amount) in $region($region)." - - - - - - - "$unit($unit) in $region($region) entdeckt eine Laenader." - "$unit($unit) discovers laen in $region($region)." - - - - - - "Die Laenader in $region($region) ist erschöpft." - "There is no more laen in $region($region)." - - - - - - - - "$unit($unit) in $region($region) hat ein zu niedriges Talent, um $resource($resource,0) abzubauen." - "$unit($unit) in $region($region) is not proficient enough to produce $resource($resource,0)." - "$unit($unit) in $region($region) is not proficient enough to produce $resource($resource,0)." - - - - - - - - - - "$unit($unit) in $region($region) produziert $int($amount)$if($eq($wanted,$amount),""," von $int($wanted)") $resource($resource,$wanted)." - "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." - "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." - - - - - - - - - - "$unit($unit) in $region($region) produziert $int($amount)$if($eq($wanted,$amount),""," von $int($wanted)") $resource($resource,$wanted)." - "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." - "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." - - - - - - - - "$unit($unit) baut für $int($size) an $building($building) weiter." - "$unit($unit) builds $int($size) more on $building($building)." - "$unit($unit) builds $int($size) more on $building($building)." - - - - - - - - "$unit($unit) baut für $int($size) an $ship($ship) weiter." - "$unit($unit) builds $int($size) more on $ship($ship)." - "$unit($unit) builds $int($size) more on $ship($ship)." - - - - - - "$string" - "$string" - - - - - - - "$unit($unit) stirbt beim Versuch, die Feuerwand nach $region($region) zu durchqueren." - "$unit($unit) dies trying to cross the wall of fire into $region($region)." - "$unit($unit) dies trying to cross the wall of fire into $region($region)." - - - - - - - "$unit($unit) erleidet beim Durchqueren der Feuerwand nach $region($region) schwere Verbrennungen." - "$unit($unit) steps through the wall of fire into $region($region) and receives severe burn damage." - "$unit($unit) steps through the wall of fire into $region($region) and receives severe burn damage." - - - - - - - - - "$unit($unit) transportiert $unit($target) von $region($start) nach $region($end)." - "$unit($unit) transported $unit($target) from $region($start) to $region($end)." - "$unit($unit) transported $unit($target) from $region($start) to $region($end)." - - - - - - - - - - "$unit($unit) $if($eq($mode,1),"reitet", "wandert") von $region($start) nach $region($end).$if($isnull($regions),""," Dabei wurde $trail($regions) durchquert.")" - "$unit($unit) $if($eq($mode,1),"chevauche", "marche") de $region($start) vers $region($end) trans $trail($regions)" - "$unit($unit) $if($eq($mode,1),"rides", "walks") from $region($start) to $region($end)$if($isnull($regions),""," by way of $trail($regions)")." - - - - - - - "$unit($unit) entdeckt dass im $direction($direction) $terrain($region) ist." - "$unit($unit) discovered that an ocean lies in the $direction($direction)." - "$unit($unit) discovered that an ocean lies in the $direction($direction)." - - - - - - - "$unit($unit) entdeckt, dass $region($region) $terrain($region) ist." - "$unit($unit) discovered that $region($region) is $terrain($region)." - "$unit($unit) discovered that $region($region) is $terrain($region)." - - - - - - - "$unit($unit) ist in dieser Runde gelandet und kann nicht weiter ins Landesinnere nach $region($region) vorstossen." - "$unit($unit) has just landed and cannot continue moving to $region($region)." - "$unit($unit) has just landed and cannot continue moving to $region($region)." - - - - - - "Die Mannschaft der $ship($ship) kann in letzter Sekunde verhindern, dass das Schiff auf Land aufläuft." - "In the very last moment, the crew of the $ship($ship) saved the ship from grounding." - "In the very last moment, the crew of the $ship($ship) saved the ship from grounding." - - - - - - - "Die $ship($ship) konnte in $region($region) nicht einreisen, die Küste ist zu gefährlich für das Schiff." - "The $ship($ship) could not berth in $region($region). The coast is too dangerous for the vessel." - "The $ship($ship) could not berth in $region($region). The coast is too dangerous for the vessel." - - - - - - - "Die Mannschaft der $ship($ship) weigert sich, nach $direction($direction) zu reisen." - " The crew of the $ship($ship) refuses to travel to the$direction($direction)." - " The crew of the $ship($ship) refuses to travel to the$direction($direction)." - - - - - - - "Die Mannschaft der $ship($ship) weigert sich, nach $region($region) zu reisen." - "The crew of the $ship($ship) refuses to travel to $region($region)." - "The crew of the $ship($ship) refuses to travel to $region($region)." - - - - - - - "$unit($unit) weigert sich, nach $direction($direction) zu reisen." - "$unit($unit) refuses to travel to the$direction($direction)." - "$unit($unit) refuses to travel to the$direction($direction)." - - - - - - - "$unit($unit) weigert sich, nach $region($region) zu reisen." - "$unit($unit) refuses to travel to $region($region)." - "$unit($unit) refuses to travel to $region($region)." - - - - - - - "Die $ship($ship) konnte $region($region) nicht verlassen." - "The $ship($ship) could not leave $region($region)." - "The $ship($ship) could not leave $region($region)." - - - - - - - - "$unit($unit) wurde in $region($region) von $unit.dative($guard) aufgehalten." - "$unit($unit) was kept in $region($region) by $unit($guard)." - "$unit($unit) was kept in $region($region) by $unit($guard)." - - - - - - "Wir haben den Krieg mit $faction($faction) beendet." - "We declared peace with $faction($faction)." - "We declared peace with $faction($faction)." - - - - - - "$faction($faction) hat den Krieg mit uns beendet." - "$faction($faction) has declared peace with us." - "$faction($faction) has declared peace with us." - - - - - - "Wir haben $faction($faction) den Krieg erklärt." - "We declared war on $faction($faction)." - "We declared war on $faction($faction)." - - - - - - "$faction($faction) hat uns den Krieg erklärt." - "$faction($faction) has declared war on us." - "$faction($faction) has declared war on us." - - - - - - - - "$unit($unit) konnte nicht von $region($region) nach $region($target) reisen, da der Besitzer der Region es verhinderte." - "$unit($unit) could not travel from $region($region) to $region($target) because the owner denied entrance." - - - - - - - "$unit($unit) konnte aus $region($region) nicht ausreisen." - "$unit($unit) could not leave $region($region)." - "$unit($unit) could not leave $region($region)." - - - - - - - "$unit($follower) ist $unit($unit) gefolgt." - "$unit($follower) followed $unit($unit)." - "$unit($follower) followed $unit($unit)." - - - - - - - "$unit($follower) konnte $unit($unit) nicht folgen." - "$unit($follower) could not follow $unit($unit)." - "$unit($follower) could not follow $unit($unit)." - - - - - - - "$unit($unit) entdeckt, dass es keinen Weg nach $direction($direction) gibt." - "$unit($unit) discovers that there is no route going $direction($direction)." - "$unit($unit) discovers that there is no route going $direction($direction)." - - - - - - - - "$unit($unit) konnte von $region($region) nicht nach $direction($direction) ausreisen, der Nebel war zu dicht." - "$unit($unit) could not travel $direction($direction) from $region($region), the fog was too dense." - - - - - - "$string" - "$string" - - - - - - "In $region($region) erschienen die Herren der Bäume." - "In $region($region), the lords of the trees have risen." - "In $region($region), the lords of the trees have risen." - - - - - - "In $region($region) erhoben sich die Toten aus den Gräbern." - "The dead rise from their graves in $region($region)." - - - - - - - - "$unit($unit) vermehrt sich um $int($amount) $race($race,$amount)." - "$unit($unit) breeds $int($amount) new $race($race,$amount)." - "$unit($unit) breeds $int($amount) new $race($race,$amount)." - - - - - "Die Partei bekommt einen Spitznamen." - "Your faction received a nickname." - - - - - - - "Die Partei bekommt von $unit.dative($unit) in $region($region) einen Spitznamen." - "Your faction received a nickname from $unit($unit)." - - - - - - - "$building($building) in $region($region) bekommt einen Spitznamen." - "$building($building) in $region($region) received a nickname." - - - - - - - - "$building($building) in $region($region) bekommt von $unit.dative($renamer) einen Spitznamen." - "$building($building) in $region($region) received a nickname from $unit($renamer)." - - - - - - - "Die $ship($ship) in $region($region) bekommt einen Spitznamen." - "$ship($ship) in $region($region) received a nickname." - - - - - - - - "Die $ship($ship) in $region($region) bekommt von $unit.dative($renamer) einen Spitznamen." - "$ship($ship) in $region($region) received a nickname from $unit($renamer)." - - - - - - - "$unit($renamed) in $region($region) bekommt einen Spitznamen." - "$unit($renamed) in $region($region) received a nickname." - - - - - - - - "$unit($renamed) in $region($region) bekommt von $unit.dative($renamer) einen Spitznamen." - "$unit($renamed) in $region($region) received a nickname from $unit($renamer)." - - - - - - "$if($eq($dead,1),"Ein Bauer","$int($dead) Bauern") verhungert." - "$if($eq($dead,1),"One peasant starves","$int($dead) peasants starve")." - "$if($eq($dead,1),"One peasant starves","$int($dead) peasants starve")." - - - - - - "Der Vulkan in $region($region) bricht aus." - "The volcano in $region($region) breaks out." - "The volcano in $region($region) breaks out." - - - - - - - "Der Vulkan in $region($regionv) bricht aus. Die Lavamassen verwüsten $region($regionn)." - "The volcano in $region($regionv) breaks out. The lava devastates $region($regionn)." - "The volcano in $region($regionv) breaks out. The lava devastates $region($regionn)." - - - - - - - - "Beim Vulkanausbruch in $region($region) sterben $int($dead) Personen in $unit($unit)." - "$int($dead) people in $unit($unit) perisch when the volcano in $region($region) breaks out." - "$int($dead) people in $unit($unit) perisch when the volcano in $region($region) breaks out." - - - - - - "Aus dem Vulkankrater von $region($region) steigt kein Rauch mehr." - "The volcano of $region($region) stops releasing smoke." - "The volcano of $region($region) stops releasing smoke." - - - - - - "Aus dem Vulkankrater von $region($region) steigt plötzlich Rauch." - "Columns of smoke are released by the volcano of $region($region)." - "Columns of smoke are released by the volcano of $region($region)." - - - - - - - "$unit($unit) in $region($region) desertiert." - "$unit($unit) in $region($region) abandons your cause." - "$unit($unit) in $region($region) abandons your cause." - - - - - - - - "$unit($unit) reißt die Straße zwischen $region($from) und $region($to) ein." - "$unit($unit) demolishes the road between $region($from) and $region($to)." - "$unit($unit) demolishes the road between $region($from) and $region($to)." - - - - - - - "$unit($unit) in $region($region) kann keine Kräuter finden." - "$unit($unit) could not find any herbs in $region($region)." - "$unit($unit) could not find any herbs in $region($region)." - - - - - - - - - "$unit($unit) in $region($region) stellt fest, dass es hier $localize($amount) $resource($herb,0) gibt." - "$unit($unit) discovers that $localize($amount) $resource($herb,0) grow in $region($region)." - - - - - - - "$unit($unit) reißt einen Teil von $building($building) ein." - "$unit($unit) tears down parts of $building($building)." - - - - - - - "$unit($unit) zerstört $building($building)." - "$unit($unit) destroys $building($building)." - "$unit($unit) destroys $building($building)." - - - - - - - - "$unit($unit) erweitert in $region($region) das Straßennetz um $int($size)." - "$unit($unit) extends the road network in $region($region) by $int($size)." - "$unit($unit) extends the road network in $region($region) by $int($size)." - - - - - - - - "$unit($unit) $if($eq($amount,1),"schließt","schließen") sich $int($amount) $resource($rtype,$amount) an." - "$int($amount) $resource($rtype,$amount) $if($eq($amount,1),"joins","join") $unit($unit)." - - - - - - - "$unit($mage) legt einen Schleier um die Ausrüstung von $unit.dative($target)." - "$unit($mage) shrouds the equipment of $unit($target) in shadows." - - - - - - - - "Die $ship($ship) in $region($region) entdeckt ein Opfer im $direction($dir)." - "The $ship($ship) in $region($region) made $direction($dir) a target." - "The $ship($ship) in $region($region) made $direction($dir) a target." - - - - - - - "Die $ship($ship) in $region($region) kann keine Schiffe aufbringen." - "The $ship($ship) could not capture other ships in $region($region)." - "The $ship($ship) could not capture other ships in $region($region)." - - - - - - "Langsam kehren andere Völker nach $region($region) zurück." - "Little by little, people return to $region($region)." - "Little by little, people return to $region($region)." - - - - - - "Vor den vielen Orks in $region($region) fliehen die anderen Einwohner." - "People $region($region) flee from an Orc superiority." - "People $region($region) flee from an Orc superiority." - - - - - - - - "$unit($unit) in $region($region) beschädigt die $ship($ship)." - "$unit($unit) in $region($region) damages the $ship($ship)." - - - - - - - - "$unit($unit) in $region($region) versenkt die $ship($ship)." - "$unit($unit) sunk $ship($ship) in $region($region)." - "$unit($unit) sunk $ship($ship) in $region($region)." - - - - - - "$unit($unit) marschiert in eine Antimagiezone und löst sich auf." - "$unit($unit) walks into an antimagical zone and dissolves." - - - - - - "$unit($unit) hat sich unbemerkt verflüchtigt." - "$unit($unit) has dissolved without a trace." - "$unit($unit) has dissolved without a trace." - - - - - - "$unit($unit) wird sich bald verflüchtigen." - "$unit($unit) will dissolve soon." - "$unit($unit) will dissolve soon." - - - - - - - "$int($amount) Bauern flohen aus Furcht vor $unit($unit)." - "$int($amount) peasants fled in fear of $unit($unit)." - "$int($amount) peasants fled in fear of $unit($unit)." - - - - - - - - "$int($amount) Bauern werden zu $race($race,0) und schliessen sich $unit($unit) an." - "$int($amount) peasants become $race($race,0) and join the ranks of $unit($unit)." - - - - - - - "$unit($unit) verspeiste $int($amount) Pferde." - "$unit($unit) ate $int($amount) horses." - - - - - - - "$unit($unit) verspeiste $int($amount) Bauern." - "$unit($unit) ate $int($amount) peasants." - "$unit($unit) ate $int($amount) peasants." - - - - - - - "ERESSEA $int36($faction) \"${password}\" - Deine Befehle hatten ein falsches Passwort." - "ERESSEA $int36($faction) \"${password}\" - Your orders had the wrong password." - - - - - - "Das Passwort für diese Partei lautet ${value}." - "Le mot de passe de cette faction est '${value}'" - "The password of this faction is '$value'." - - - - - - "Die Reportadresse wurde nicht geändert, '${value}' ist keine gültige email." - " Address not changed, '$value' is an invalid email." - " Address not changed, '$value' is an invalid email." - - - - - - "Die Reportadresse wurde auf ${value} geändert." - " Address has been changed to '$value'." - " Address has been changed to '$value'." - - - - - - "Das Banner wurde auf '$value' geändert." - "Banner has been changed to '$value'." - "Banner has been changed to '$value'." - - - - - - - - - "Eine Partei muß mindestens $int($turns) Wochen alt sein, bevor sie angegriffen oder bestohlen werden kann." - "A faction must be at least $int($turns) weeks old before it can be attacked or stolen from." - - - - - - - - "$unit($unit) wurden in $region($region) $int($amount) Silberstücke geklaut." - "In $region($region), thieves stole $int($amount) silver from $unit($unit)." - "In $region($region), thieves stole $int($amount) silver from $unit($unit)." - - - - - - - "$unit($target) ertappte $unit($unit) beim versuchten Diebstahl." - "$unit($target) caught $unit($unit) in attempted theft." - "$unit($target) caught $unit($unit) in attempted theft." - - - - - - - "$unit($unit) wurde von $unit.dative($target) beim versuchten Diebstahl ertappt." - "$unit($unit) was caught by $unit($target) in attempted theft." - "$unit($unit) was caught by $unit($target) in attempted theft." - - - - - - "$unit($unit) fühlt sich beobachtet." - "$unit($unit) feels watched." - "$unit($unit) feels watched." - - - - - - - "$unit($unit) gelang es nicht, sich nahe genug an $unit($target) heranzuschleichen." - "$unit($unit) could not sneak close enough to $unit($target)." - "$unit($unit) could not sneak close enough to $unit($target)." - - - - - - - "$unit($spy) gelang es nicht, etwas über $unit($target) herauszufinden." - "$unit($spy) could not find out anything about $unit($target)." - "$unit($spy) could not find out anything about $unit($target)." - - - - - - - - "$unit($spy) gelang es, Informationen über $unit($target) ($status) herauszubekommen." - "$unit($spy) managed to gather information about $unit($target)." - - - - - - - "$unit($target) ist ein $type-Magier." - "$unit($target) is a $type-magician" - - - - - - - "$unit($target) beherrscht ${skills}." - "$unit($target) has the skills ${skills}." - - - - - - - "Im Gepäck von $unit($target) sind $resources($items)." - "$unit($target) carries $resources($items)" - - - - - - - "$unit($target) gehört der Partei $faction($faction) an." - "$unit($target) belongs to $faction($faction)." - - - - - - - "$unit($target) fühlt sich $if($isnull($spy),"","durch $unit($spy) ")beobachtet." - "$unit($target) feels watched by $unit($spy)." - "$unit($target) feels watched by $unit($spy)." - - - - - - - - "$faction($from) gibt ein Almosen von $int($amount) Silber an $faction($to)." - "$faction($from) donates $int($amount) silver to $faction($to)." - "$faction($from) donates $int($amount) silver to $faction($to)." - - - - - - - - "$unit($unit) vergißt durch Dumpfbackenbrot $int($weeks) Wochen des Talentes $skill($skill)." - "$unit($unit) eats a Dumpfbackenbrot and forgets $int($weeks) weeks worth of $skill($skill)." - "$unit($unit) eats a Dumpfbackenbrot and forgets $int($weeks) weeks worth of $skill($skill)." - - - - - - - "$unit($unit) in $region($region) wird durch unzureichende Nahrung geschwächt." - "$unit($unit) is weakened due to malnourishment." - "$unit($unit) is weakened due to malnourishment." - - - - - - - - - "$unit($unit) verliert in $region($region) $int($dead) von $int($add($live,$dead)) Personen durch Unterernährung." - "$unit($unit) loses $int($dead) of $int($add($live,$dead)) people due to starvation in $region($region)." - "$unit($unit) loses $int($dead) of $int($add($live,$dead)) people due to starvation in $region($region)." - - - - - - - - "$unit($unit): '$order($command)' - Die Einheit benutzt bereits $resource($using,0)." - "$unit($unit): '$order($command)' - The unit already uses $resource($using,0)." - "$unit($unit): '$order($command)' - The unit already uses $resource($using,0)." - - - - - - "Die $ship($ship) ist zu stark beschädigt und sinkt." - "The $ship($ship) suffers too heavy damage and sinks." - "The $ship($ship) suffers too heavy damage and sinks." - - - - - - - "Die $ship($ship) entdeckt, dass $region($region) Festland ist." - "The $ship($ship) discovers that $region($region) has no shore." - - - - - - - - "Die $ship($ship) fliegt von $region($from) nach $region($to)." - "The $ship($ship) flies from $region($from) to $region($to)." - - - - - - - - "Die $ship($ship) segelt von $region($from) nach $region($to)." - "The $ship($ship) sails from $region($from) to $region($to)." - - - - - - - - "Die $ship($ship) wird in $region($region) von Stürmen abgetrieben$if($sink," und sinkt","")." - "The $ship($ship) in $region($region) drifts in heavy storm$if($sink," and sinks","")." - "The $ship($ship) in $region($region) drifts in heavy storm$if($sink," and sinks","")." - - - - - - - - - "Die $ship($ship) fährt in den Mahlstrom von $region($region) und nimmt $int($damage) Schaden$if($sink," und sinkt","")." - "The $ship($ship) sails into the maelstrom of $region($region) and takes $int($damage) damage$if($sink,". The ship sinks","")." - - - - - - - "$unit($unit) vergißt $skill($skill)." - "$unit($unit) forgets $skill($skill)." - "$unit($unit) forgets $skill($skill)." - - - - - - - "$unit($unit) gibt das Kommando an $unit($recipient)." - "$unit($unit) gave control to $unit($recipient)." - "$unit($unit) gave control to $unit($recipient)." - - - - - - - - "$unit($unit) gibt $int($amount) Dumpfbackenbrot an $unit($recipient)." - "$unit($unit) administers $int($amount) duncebuns to $unit($recipient)." - - - - - - - - - "$unit($unit) in $region($region) rekrutiert $int($amount) von $int($want) Personen." - "$unit($unit) in $region($region) recruits $int($amount) $int($want) people." - "$unit($unit) in $region($region) recruits $int($amount) $int($want) people." - - - - - - - - "$unit($unit) belagert $building($building). Dabei richten die Katapulte Zerstörungen von $int($destruction) Größenpunkten an." - "$building($building) is under siege by $unit($unit). During siege, catapults caused $int($destruction) points destruction." - "$building($building) is under siege by $unit($unit). During siege, catapults caused $int($destruction) points destruction." - - - - - - - "$unit($unit) belagert $building($building)." - "$building($building) is under siege by $unit($unit)." - - - - - - - - "$unit($unit) ertrinkt beim Untergang der $ship($ship) in $region($region)." - "$unit($unit) drowns when $ship($ship) in $region($region) sinks." - "$unit($unit) drowns when $ship($ship) in $region($region) sinks." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht bewachen, da sie versucht zu fliehen." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot guard the region because it's trying to flee." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot guard the region because it's trying to flee." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann den Befehl in dieser Runde nicht ausführen, da sie an einem Kampf teilgenommen hat." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot execute this command because it has been in combat." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot execute this command because it has been in combat." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Gebäude kann nur einmal pro Runde erweitert werden." - "$unit($unit) in $region($region): '$order($command)' - Thhe building can be expanded only once per turn." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieses Objekt ist unzerstörbar." - "$unit($unit) in $region($region): '$order($command)' - This object is indestructible." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Ohne Zutaten kann ein Alchemist nichts herstellen." - "$unit($unit) in $region($region): '$order($command)' - Ohne Zutaten kann ein Alchemist nichts herstellen." - "$unit($unit) in $region($region): '$order($command)' - Without ingredients an alchemist can not produce anything." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nicht alle Zutaten vorhanden." - "$unit($unit) in $region($region): '$order($command)' - Nicht alle Zutaten vorhanden." - "$unit($unit) in $region($region): '$order($command)' - Not all ingredients present." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Eine Partei kann nur einmal neu starten." - "$unit($unit) in $region($region): '$order($command)' - Restart can only be used once." - "$unit($unit) in $region($region): '$order($command)' - Restart can only be used once." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Werwesen können nicht arbeiten." - "$unit($unit) in $region($region): '$order($command)' - Lycantropes don't work." - "$unit($unit) in $region($region): '$order($command)' - Lycantropes don't work." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Werwesen können nicht mit anderen Personen gemischt werden." - "$unit($unit) in $region($region): '$order($command)' - Lycantropes may not be mixed with normal people." - "$unit($unit) in $region($region): '$order($command)' - Lycantropes may not be mixed with normal people." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann sich nicht verwandeln." - "$unit($unit) in $region($region): '$order($command)' - This unit can not change shape." - "$unit($unit) in $region($region): '$order($command)' - This unit can not change shape." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diese Einheit ist kein Werwesen." - "$unit($unit) in $region($region): '$order($command)' - This unit is not in lycantropic form." - "$unit($unit) in $region($region): '$order($command)' - This unit is not in lycantropic form." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diese Einheit ist schon ein Werwesen." - "$unit($unit) in $region($region): '$order($command)' - This unit already assumed lycantropic form." - "$unit($unit) in $region($region): '$order($command)' - This unit already assumed lycantropic form." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieses Talent kann nicht höher gelernt werden." - "$unit($unit) in $region($region): '$order($command)' - This skill cannot be raised any higher." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Snotlinge sind zu dumm, um auf den Feldern zu arbeiten." - "$unit($unit) in $region($region): '$order($command)' - We snotlings is too stupid fer dat!" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Partei muß mindestens 9 Wochen alt sein, um einen Neustart zu versuchen." - "$unit($unit) in $region($region): '$order($command)' - Your faction is not old enough to start over." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Optionen ZIP und BZIP2 können nur um, nicht ausgeschaltet werden." - "$unit($unit) in $region($region): '$order($command)' - options ZIP and BZIP2 can only be switched, not turned off." - "$unit($unit) in $region($region): '$order($command)' - options ZIP and BZIP2 can only be switched, not turned off." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Einheiten einer Partei, die noch immun gegen Angriffe ist, dürfen nicht bewachen." - "$unit($unit) in $region($region): '$order($command)' - units of a faction that can't be attacked may not guard." - "$unit($unit) in $region($region): '$order($command)' - units of a faction that can't be attacked may not guard." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - In dieser Region kann man nichts verkaufen." - "$unit($unit) in $region($region): '$order($command)' - there is no trade in this region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Bereits ein Synonym gesetzt." - "$unit($unit) in $region($region): '$order($command)' - synonym already set." - "$unit($unit) in $region($region): '$order($command)' - synonym already set." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Kein Synonym angegeben." - "$unit($unit) in $region($region): '$order($command)' - synonym missing." - "$unit($unit) in $region($region): '$order($command)' - synonym missing." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Ungültiges Synonym." - "$unit($unit) in $region($region): '$order($command)' - invalid synonym." - "$unit($unit) in $region($region): '$order($command)' - invalid synonym." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Ungültiges Prefix." - "$unit($unit) in $region($region): '$order($command)' - invalid prefix." - "$unit($unit) in $region($region): '$order($command)' - invalid prefix." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier hat bereits einen Klon." - "$unit($unit) in $region($region): '$order($command)' - The magician already has a clone." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Gebäude auf dem Ozean können nicht betreten werden." - "$unit($unit) in $region($region): '$order($command)' - Buildings on the ocean may not be entered." - "$unit($unit) in $region($region): '$order($command)' - Buildings on the ocean may not be entered." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier werden niemals Bäume wachsen." - "$unit($unit) in $region($region): '$order($command)' - Trees won't grow here." - "$unit($unit) in $region($region): '$order($command)' - Trees won't grow here." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nur ein Magier kann einen Astralkristall benutzen." - "$unit($unit) in $region($region): '$order($command)' - Only mages may use an astralcrystal." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Verbände können nur zwischen Einheiten derselben Partei gebildet werden." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist in keinem Verband." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Eine Einheit kann nur in einem Verband Mitglied sein." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Wie sollen wir uns tarnen?" - "$unit($unit) in $region($region): '$order($command)' - What should we disguise us as?" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Wieviel sollen wir einreißen?" - "$unit($unit) in $region($region): '$order($command)' - How much shall we tear down?" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dorthin können wir die Einheit nicht transportieren." - "$unit($unit) in $region($region): '$order($command)' - We cannot transport this unit there." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit transportiert uns nicht." - "$unit($unit) in $region($region): '$order($command)' - the unit is not transporting us." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diese Einheit kennt keine Trankrezepte." - "$unit($unit) in $region($region): '$order($command)' - This unit knows no recipes for potions." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nur noch nicht gestärkte Untote können das Ziel dieses Zaubers sein." - "$unit($unit) in $region($region): '$order($command)' - Undead can only be affected once by this spell." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Passwort darf nur Buchstaben und Ziffern enthalten." - "$unit($unit) in $region($region): '$order($command)' - Your password may only contain alphanumeric symbols." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Gegen diese Rasse kann kein Jihad ausgerufen werden." - "$unit($unit) in $region($region): '$order($command)' - You cannot start a jihad against this race." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Gegen welche Rasse soll der Jihad ausgerufen werden?" - "$unit($unit) in $region($region): '$order($command)' - What race did you want the jihad to be against?" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dazu muss erst die Spezialeigenschaft erworben werden." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Name und Beschreibung des Gebäudes können nicht geändert werden." - "$unit($unit) in $region($region): '$order($command)' - You cannot change the name and description of this building." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das kann die Einheit nicht." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier kann man keine Schiffe bauen." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier kann man keine Gebäude errichten." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht unterrichten." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier kann man nicht unterrichten." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Pferde müssen leider draußen bleiben." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier kann man niemanden angreifen." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier kann man niemanden bestehlen." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier kann man nicht zaubern." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier kann man nichts übergeben." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nur eine Einzelperson kann das Ticket benutzen." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Gegenstand funktioniert nur in der Eingangshalle." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Gegenstand funktioniert nur in der normalen Welt." - "$unit($unit) in $region($region): '$order($command)' - This item only works in the normal world." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieses Gut hat die Einheit nicht." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have this good." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieses Gut wird hier produziert." - "$unit($unit) in $region($region): '$order($command)' - This good is not produced here." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Partei kann keine weiteren Wyrme besitzen." - "$unit($unit) in $region($region): '$order($command)' - The faction cannot contain any more wyrms." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Vor den Besitzer eines Schiffes oder Gebäudes kann nicht sortiert werden." - "$unit($unit) in $region($region): '$order($command)' - You cannot sort before the owner of a ship or a building." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Besitzer eines Schiffes oder Gebäudes kann nicht neu sortiert werden." - "$unit($unit) in $region($region): '$order($command)' - The owner of a ship or a building cannot be sorted." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Befehl ist nur auf Einheiten innerhalb des selben Gebäudes oder Schiffes anwendbar." - "$unit($unit) in $region($region): '$order($command)' - That order only applies to units in the same building or ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Zieleinheit ist ungültig." - "$unit($unit) in $region($region): '$order($command)' - The target unit is invalid." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Ungültiges Locale." - "$unit($unit) in $region($region): '$order($command)' - Invalid locale." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Um soetwas kann man nicht beten." - "$unit($unit) in $region($region): '$order($command)' - You cannot pray for this." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Soetwas kann man nicht opfern." - "$unit($unit) in $region($region): '$order($command)' - You cannot sacrifice this." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Auraangabe fehlerhaft oder zuwenig Aura." - "$unit($unit) in $region($region): '$order($command)' - Invalid aura specification or too little aura." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier ist nicht stark genug, sich den Göttern zu opfern." - "$unit($unit) in $region($region): '$order($command)' - This magician is not strong enough to be sacrificed to the gods." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Was und wieviel soll geopfert werden?" - "$unit($unit) in $region($region): '$order($command)' - What and how much should be sacrificed?" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diese Kraft können selbst die Götter nicht mehr mächtiger machen." - "$unit($unit) in $region($region): '$order($command)' - Even the gods cannot improve this power." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nicht genug Karma." - "$unit($unit) in $region($region): '$order($command)' - Not enough karma." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff kann nicht aufs offene Meer hinaus segeln." - "$unit($unit) in $region($region): '$order($command)' - The ship cannot sail into the open seas." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Partei muß mindestens 10 Runden alt sein." - "$unit($unit) in $region($region): '$order($command)' - The faction has to be 10 turns old." - "$unit($unit) in $region($region): '$order($command)' - The faction has to be 10 turns old." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Partei hat schon einen Namen." - "$unit($unit) in $region($region): '$order($command)' - The faction is already named." - "$unit($unit) in $region($region): '$order($command)' - The faction is already named." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Gebäude hat schon einen Namen." - "$unit($unit) in $region($region): '$order($command)' - The building is already named." - "$unit($unit) in $region($region): '$order($command)' - The building is already named." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff hat schon einen Namen." - "$unit($unit) in $region($region): '$order($command)' - The ship is already named." - "$unit($unit) in $region($region): '$order($command)' - The ship is already named." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat schon einen Namen." - "$unit($unit) in $region($region): '$order($command)' - The unit is already named." - "$unit($unit) in $region($region): '$order($command)' - The unit is already named." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Keine gültige Rasse angegeben." - "$unit($unit) in $region($region): '$order($command)' - You did not specify a valid race." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit muß sich an Land befinden." - "$unit($unit) in $region($region): '$order($command)' - The unit must be on land." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $building($building) ist kein Steinkreis." - "$unit($unit) in $region($region): '$order($command)' - $building($building) is not a stonecircle." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $building($building) muss vor der Weihe fertiggestellt sein." - "$unit($unit) in $region($region): '$order($command)' - $building($building) has to be complete before it can be blessed." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - In $region($target) sind keine Gräber." - "$unit($unit) in $region($region): '$order($command)' - There are no graves in $region($target)." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Partei muß mindestens 81 Wochen alt sein, um einen Neustart mit einer anderen Rasse zu versuchen." - "$unit($unit) in $region($region): '$order($command)' - The faction must be at least 81 weeks old to restart with a new race." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Soll eine Einheit oder ein Schiff verfolgt werden?" - "$unit($unit) in $region($region): '$order($command)' - Is this unit or ship supposed to be followed?" - "$unit($unit) in $region($region): '$order($command)' - Is this unit or ship supposed to be followed?" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Soll eine Einheit oder ein Schiff eine neue Nummer bekommen?" - "$unit($unit) in $region($region): '$order($command)' - Is this unit or ship supposed to get a new number?" - "$unit($unit) in $region($region): '$order($command)' - Is this unit or ship supposed to get a new number?" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier können nur Orks rekrutiert werden." - "$unit($unit) in $region($region): '$order($command)' - You can recruit only Orcs here." - "$unit($unit) in $region($region): '$order($command)' - You can recruit only Orcs here." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Region befindet sich in Aufruhr." - "$unit($unit) in $region($region): '$order($command)' - There are riots in this region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Gebäude ist noch nicht fertig gebaut." - "$unit($unit) in $region($region): '$order($command)' - The building is not finished yet." - "$unit($unit) in $region($region): '$order($command)' - The building is not finished yet." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Für das Gebäude wurde noch kein Unterhalt bezahlt." - "$unit($unit) in $region($region): '$order($command)' - Maintenance has not been paid yet." - "$unit($unit) in $region($region): '$order($command)' - Maintenance has not been paid yet." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist mit Ausschiffen beschäftigt.." - "$unit($unit) in $region($region): '$order($command)' - The unit is busy disembarking." - "$unit($unit) in $region($region): '$order($command)' - The unit is busy disembarking." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Typ Einheit kann keine Schiffe betreten." - "$unit($unit) in $region($region): '$order($command)' - Swimmers cannot enter ships." - "$unit($unit) in $region($region): '$order($command)' - Swimmers cannot enter ships." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Typ Einheit kann keine Gebäude betreten." - "$unit($unit) in $region($region): '$order($command)' - this type of unit cannot enter a building." - "$unit($unit) in $region($region): '$order($command)' - this type of unit cannot enter a building." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit oder ihre Tiere würden dort nicht überleben." - "$unit($unit) in $region($region): '$order($command)' - The unit or its animals would not survive there." - "$unit($unit) in $region($region): '$order($command)' - The unit or its animals would not survive there." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dorthin kann die Einheit uns nicht transportieren." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot transport us to this place." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot transport us to this place." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $building($building) wird belagert." - "$unit($unit) in $region($region): '$order($command)' - $building($building) is under siege." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Eintritt in $building($building) wurde verwehrt." - "$unit($unit) in $region($region): '$order($command)' - Entrance to $building($building) was denied." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Ein Vertrauter wird beschworen, verschwindet jedoch wieder, als er keine Verbindung zu seinem Element herstellen kann." - "$unit($unit) in $region($region): '$order($command)' - A familiar is summoned, but disappears again when it cannot get in contact with its natural element." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nur normale Personen können Steuern eintreiben." - "$unit($unit) in $region($region): '$order($command)' - Only normal characters can collect taxes." - "$unit($unit) in $region($region): '$order($command)' - Only normal characters can collect taxes." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dafür braucht ein Einheit mindestens Kräuterkunde 7." - "$unit($unit) in $region($region): '$order($command)' - A skill of herbalism 7 or higher is required." - "$unit($unit) in $region($region): '$order($command)' - A skill of herbalism 7 or higher is required." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Einheiten in den hinteren Reihen können nicht angreifen." - "$unit($unit) in $region($region): '$order($command)' - Units cannot attack from the second row." - "$unit($unit) in $region($region): '$order($command)' - Units cannot attack from the second row." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - unbekannter Kampfstatus." - "$unit($unit) in $region($region): '$order($command)' - unknown combat status." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht bewaffnet und kampffähig." - "$unit($unit) in $region($region): '$order($command)' - The unit is not armed and ready to fight." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Partei hat bereits ein Magiegebiet." - "$unit($unit) in $region($region): '$order($command)' - The faction has already chosen a magical school." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können nicht arbeiten." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot work." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot work." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hungernde Soldaten kämpfen nicht." - "$unit($unit) in $region($region): '$order($command)' - Starving units do not fight." - "$unit($unit) in $region($region): '$order($command)' - Starving units do not fight." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hungernde Einheiten können nicht zaubern." - "$unit($unit) in $region($region): '$order($command)' - Starving units cannot cast spells." - "$unit($unit) in $region($region): '$order($command)' - Starving units cannot cast spells." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hungernde Einheiten können nicht bewachen." - "$unit($unit) in $region($region): '$order($command)' - Starving units cannot guard." - "$unit($unit) in $region($region): '$order($command)' - Starving units cannot guard." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Zeige alle was?" - "$unit($unit) in $region($region): '$order($command)' - Show all what?" - "$unit($unit) in $region($region): '$order($command)' - Show all what?" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht bauen." - "$unit($unit) in $region($region): '$order($command)' - You cannot build such a thing." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Im astralen Nebel konnte niemand entdeckt werden." - "$unit($unit) in $region($region): '$order($command)' - Noone could be seen in th astral fog." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Ein Zauber in dieser Region verhindert das." - "$unit($unit) in $region($region): '$order($command)' - There is an active spell in this region that prevents this." - "$unit($unit) in $region($region): '$order($command)' - There is an active spell in this region that prevents this." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nur im Astralraum gezaubert werden." - "$unit($unit) in $region($region): '$order($command)' - This spell can only be cast in the astral plane." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier gibt es keine Verbindung zur astralen Welt." - "$unit($unit) in $region($region): '$order($command)' - There is no connection to the astral plane here." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Von hier aus kann man die astrale Ebene nicht erreichen." - "$unit($unit) in $region($region): '$order($command)' - You cannot reach the astral plane from here." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Einheit ist kein Magier." - "$unit($unit) in $region($region): '$order($command)' - Unit is not a magician." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Parameter nicht korrekt angegeben." - "$unit($unit) in $region($region): '$order($command)' - Incorrect parameter." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier befindet sich nicht auf einem Schiff." - "$unit($unit) in $region($region): '$order($command)' - The magician is not on board a ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Auf dem Schiff liegt bereits so ein Zauber." - "$unit($unit) in $region($region): '$order($command)' - The ship is already under this spell." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es ist zu gefährlich, ein sturmgepeitschtes Schiff fliegen zu lassen." - "$unit($unit) in $region($region): '$order($command)' - It is too dangerous to fly the ship in the storm." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Syntax Error." - "$unit($unit) in $region($region): '$order($command)' - Syntax Error." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Auraangabe fehlerhaft." - "$unit($unit) in $region($region): '$order($command)' - wrong Aura values." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Zu dieser Einheit kann keine Aura übertragen werden." - "$unit($unit) in $region($region): '$order($command)' - You cannot pass aura on to this unit." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Auf dem Gebäude liegt bereits so ein Zauber." - "$unit($unit) in $region($region): '$order($command)' - There is alrady a spell on that building." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nicht auf hoher See gezaubert werden." - "$unit($unit) in $region($region): '$order($command)' - This spell cannot be cast while you are on the ocean." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nicht auf Monster gezaubert werden." - "$unit($unit) in $region($region): '$order($command)' - This spell cannot be cast on monsters." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nicht auf Untote gezaubert werden." - "$unit($unit) in $region($region): '$order($command)' - This spell cannot be cast on undead." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Stimmung in der Region ist so schlecht, dass niemand auf den Zauber reagiert." - "$unit($unit) in $region($region): '$order($command)' - The mood in this region is so bad that nobody reacts t the spell." - - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) wusste trotz intensivem Verhör nichts über $region($tregion) zu berichten." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - So viele Persoenen übersteigen die Kräfte des Magiers." - "$unit($unit) in $region($region): '$order($command)' -This many people exceed the powers of the magician." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) hat unaufkündbare Bindungen an seine alte Partei." - "$unit($unit) in $region($region): '$order($command)' - $unit($target) have unbreakable prior commitments to their faction." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber gelingt nur in einer Ozeanregion." - "$unit($unit) in $region($region): '$order($command)' - This spell works only in an ocean region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - In einer Region ohne Bäume kann man diesen Zauber nicht wirken." - "$unit($unit) in $region($region): '$order($command)' - You cannot cast this spell in a region without trees." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Ziel wurde vergessen." - "$unit($unit) in $region($region): '$order($command)' - No target has been supplied." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das ist keine gültige Rasse." - "$unit($unit) in $region($region): '$order($command)' - This is not a valid race." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Rasse und Zieleinheit wurden vergessen." - "$unit($unit) in $region($region): '$order($command)' - Race and target unit have not been supplied." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die maximale Aura reicht nicht für diesen Zauber." - "$unit($unit) in $region($region): '$order($command)' - Magician's maximum Aura is not high enough for this spell." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier hat bereits einen Vertrauten." - "$unit($unit) in $region($region): '$order($command)' - The magician already has a familiar." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Flammen finden keine Nahrung. Das Feuer erlischt, ohne Schaden anzurichten." - "$unit($unit) in $region($region): '$order($command)' - The flames find no kindling. The fire dies quickly, causing no damage whatsoever." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Um einen Heimstein zu erschaffen, muß der Zauberer in einer Burg sein." - "$unit($unit) in $region($region): '$order($command)' - The magician has to be in a castle to create a homestone." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das ist keine Waldregion." - "$unit($unit) in $region($region): '$order($command)' - This is not a forest region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dorthin führt kein Weg." - "$unit($unit) in $region($region): '$order($command)' - No way is leading in this direction." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Zielregion wurde nicht korrekt angegeben." - "$unit($unit) in $region($region): '$order($command)' - Target region was supplied incorrectly." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Zauber funktioniert nur in der Geisterwelt." - "$unit($unit) in $region($region): '$order($command)' - This spell will only work in the realm of spirits." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Wege zwischen Geisterwelt und Realität scheinen blockiert zu sein." - "$unit($unit) in $region($region): '$order($command)' - The paths to the spirit world seem to be blocked." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Zauber funktioniert nur in Wäldern." - "$unit($unit) in $region($region): '$order($command)' - This spell works only in forests." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Zauber funktioniert nur in der materiellen Welt." - "$unit($unit) in $region($region): '$order($command)' - This spell works only in the material world." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Selbst der mächtigste Magier der Welt könnte keinen Ozean austrocknen lassen." - "$unit($unit) in $region($region): '$order($command)' - Even the gods cannot dry out an entire ocean." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nicht im Sumpf gezaubert werden." - "$unit($unit) in $region($region): '$order($command)' - You cannot cast this spell in a swamp." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nur auf Land gelegt werden." - "$unit($unit) in $region($region): '$order($command)' - This spell works only ashore." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Zauber scheint ungewöhnlich schwach zu sein. Irgendetwas hat die magischen Energien abgeleitet." - "$unit($unit) in $region($region): '$order($command)' - the spell seems exceptionally weak. Something has interfred with the magical energies." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann den Befehl in dieser Runde nicht ausführen, da sie sich bewegt hat." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot execute this command because it has moved." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit bewegt sich nicht." - "$unit($unit) in $region($region): '$order($command)' - The unit does not move." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier befindet sich nicht auf einem Schiff." - "$unit($unit) in $region($region): '$order($command)' - The magician is not on board a ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff kann in diese Richtung nicht ablegen." - "$unit($unit) in $region($region): '$order($command)' - The ship cannot leave in this direction." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dazu muß sich der Magier in der Burg oder an Bord des Schiffes befinden." - "$unit($unit) in $region($region): '$order($command)' - To do this, the magician has to be in a castle or on board a ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Zauber schlägt fehl." - "$unit($unit) in $region($region): '$order($command)' - The spell fails." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieses Magiegebiet kann die Einheit nicht lernen." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot learn this magic sphere." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es wurde kein Magiegebiet angegeben." - "$unit($unit) in $region($region): '$order($command)' - No magic sphere was supplied." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diesen Spruch kann der Vertraute nicht zaubern." - "$unit($unit) in $region($region): '$order($command)' - the familiar cannot cast this spell." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diesen Spruch kann man nicht in die Ferne richten." - "$unit($unit) in $region($region): '$order($command)' - You cannot cast this spell on a distant target." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diesen Spruch kann man nicht auf einem sich bewegenden Schiff stehend zaubern." - "$unit($unit) in $region($region): '$order($command)' - You cannot cast this spell while standing on a moving ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber ist nur im Kampf sinnvoll." - "$unit($unit) in $region($region): '$order($command)' - this spell makes only sense in combat." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Selbst in der Bibliothek von Xontormia konnte dieser Spruch nicht gefunden werden." - "$unit($unit) in $region($region): '$order($command)' - Even in the Xontormia Library, this spell could not be found." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es wurde kein Zauber angegeben." - "$unit($unit) in $region($region): '$order($command)' - There was no spell supplied." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diesen Kampfzauber gibt es nicht." - "$unit($unit) in $region($region): '$order($command)' - This combat spell does not exist." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Bauern nehmen dieses großzügige Geschenk nicht an." - "$unit($unit) in $region($region): '$order($command)' - The peasants did not accept this gracious gift." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diesen Zauber kennt die Einheit nicht." - "$unit($unit) in $region($region): '$order($command)' - The unit does not know this spell." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es konnten keine Luxusgüter verkauft werden." - "$unit($unit) in $region($region): '$order($command)' - No luxury items could be sold." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit geht nicht zu den Bauern." - "$unit($unit) in $region($region): '$order($command)' - The unit does not go to the peasants." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diese Rasse kann eine Burg nicht belagern." - "$unit($unit) in $region($region): '$order($command)' - This race cannot siege a castle." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Trank bekommt der Einheit nicht." - "$unit($unit) in $region($region): '$order($command)' - The unit disagreed with the potion." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Nestwärme kann nur von Insektenvölkern benutzt werden." - "$unit($unit) in $region($region): '$order($command)' - this potion can only be used by insects." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Heiltrank wird automatisch bei Bedarf benutzt." - "$unit($unit) in $region($region): '$order($command)' - This healing potion will be automatically used when needed." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit besitzt den Trank nicht." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have this potion." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es konnten keine Luxusgüter gekauft werden." - "$unit($unit) in $region($region): '$order($command)' - No luxury items could be bought." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es konnten keine Personen übergeben werden." - "$unit($unit) in $region($region): '$order($command)' - No person could be handed over." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Magier arbeiten grundsätzlich nur alleine!" - "$unit($unit) in $region($region): '$order($command)' - Magicians always work alone!" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Partei hat ein anderes Magiegebiet." - "$unit($unit) in $region($region): '$order($command)' - The faction has a different magic sphere." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Zuviele Alchemisten in der Partei." - "$unit($unit) in $region($region): '$order($command)' - Too many alchemists in the faction." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Zuviele Magier in der Partei." - "$unit($unit) in $region($region): '$order($command)' - Too many magicians in the faction." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hochqualifizierte Personen weigern sich, für andere Parteien zu arbeiten." - "$unit($unit) in $region($region): '$order($command)' - Highly qualified people refuse to work for other parties." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit schließt sich den Bauern an." - "$unit($unit) in $region($region): '$order($command)' - The unit joins the local peasants." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit springt über Bord und ertrinkt." - "$unit($unit) in $region($region): '$order($command)' - The unit jumps over board and drowns." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Region wird bewacht." - "$unit($unit) in $region($region): '$order($command)' - The region is guarded." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Unbekannte Option." - "$unit($unit) in $region($region): '$order($command)' - Unknown Option." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit wird belagert." - "$unit($unit) in $region($region): '$order($command)' - The unit is under siege." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Zum Straßenbau braucht man Steine." - "$unit($unit) in $region($region): '$order($command)' - You need stones to build a road." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Wohin soll die Botschaft gehen?" - "$unit($unit) in $region($region): '$order($command)' - Who is supposed to get this message?" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht der Burgherr." - "$unit($unit) in $region($region): '$order($command)' - The unit is not in command of a castle." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht Burgherr der größten Burg in der Region." - "$unit($unit) in $region($region): '$order($command)' - The unit is not in command of the largest castle in the region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht der Kapitän des Schiffes." - "$unit($unit) in $region($region): '$order($command)' - The unit is not captain of a ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist in keiner Burg." - "$unit($unit) in $region($region): '$order($command)' - The unit is not in a castle." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist auf keinem Schiff." - "$unit($unit) in $region($region): '$order($command)' - The unit is not on board a ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist auf einem Schiff." - "$unit($unit) in $region($region): '$order($command)' - The unit is on board a ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat zuwenig Silber, um zu rekrutieren." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough silver for recruiting." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht mehr genug Kristalle für so viele Personen." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough crystals left for this many people." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit befindet sich weder in einer Burg noch auf einem Schiff." - "$unit($unit) in $region($region): '$order($command)' - The unit is neither in a castle nor on board a ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Unterschiedliche Typen können nicht gemischt werden." - "$unit($unit) in $region($region): '$order($command)' - Different types do not mix." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Uns gehört nichts, was man abreißen oder versenken könnte." - "$unit($unit) in $region($region): '$order($command)' - We do not have anything that could be demolished." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Unbekannter Hilfe-Modus." - "$unit($unit) in $region($region): '$order($command)' - Unknown Help- Mode." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Unbekannte Meldungs-Option." - "$unit($unit) in $region($region): '$order($command)' - Unknown Report-Option." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Um in Wüsten Straßen bauen zu können, muß zuerst eine Karawanserei errichtet werden." - "$unit($unit) in $region($region): '$order($command)' - You've got to build a caravansary before building roads through deserts." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Um in Sümpfen Straßen bauen zu können, muß zuerst ein Damm errichtet werden." - "$unit($unit) in $region($region): '$order($command)' - You've got to build a dam before building roads through swamps." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - So viele Leute kann die Partei nicht aufnehmen." - "$unit($unit) in $region($region): '$order($command)' - The faction cannot hire so many strangers." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - So viele Fremde kann die Partei nicht aufnehmen." - "$unit($unit) in $region($region): '$order($command)' - The faction cannot hire so many strangers." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - So viele Fremde kann Deine Partei nicht aufnehmen." - "$unit($unit) in $region($region): '$order($command)' - Your faction cannot hire so many strangers." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht verkaufen." - "$unit($unit) in $region($region): '$order($command)' - You cannot sell this." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht machen." - "$unit($unit) in $region($region): '$order($command)' - You cannot produce this." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht auf dem Markt kaufen." - "$unit($unit) in $region($region): '$order($command)' - You cannot buy that on a market place." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - So etwas hat die Einheit nicht." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have such a thing." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Pferde kann man nur in einer Pferdezucht züchten." - "$unit($unit) in $region($region): '$order($command)' - You can breed horses only in a stable." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - So etwas gibt es hier nicht." - "$unit($unit) in $region($region): '$order($command)' - That resource does not exist in this region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Personen können nur an Menschen übergeben werden." - "$unit($unit) in $region($region): '$order($command)' - Characters can be given only to Human parties." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Ohne einen Handelsposten gibt es keinen Markt." - "$unit($unit) in $region($region): '$order($command)' - There is no marketplace without at least a tradepost." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nur Elfen können diese Bögen herstellen." - "$unit($unit) in $region($region): '$order($command)' - Only Elves can make these bows." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nur die EMail-Adresse angeben!" - "$unit($unit) in $region($region): '$order($command)' - Submit only email-address, please!" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nummer kann nicht vergeben werden." - "$unit($unit) in $region($region): '$order($command)' - Number can not be assigned." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nummer ist schon belegt." - "$unit($unit) in $region($region): '$order($command)' - Number is already in use." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nummer ist nicht im gültigen Bereich." - "$unit($unit) in $region($region): '$order($command)' - Number is not valid." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nichts angegeben, was wir übergeben sollen." - "$unit($unit) in $region($region): '$order($command)' - Item to be handed over was not supplied." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Namen dürfen keine Klammern enthalten." - "$unit($unit) in $region($region): '$order($command)' - Names may not contain parenthesis." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nachricht zu lang - gekürzt." - "$unit($unit) in $region($region): '$order($command)' - Message has been cut (too long).." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Man muß angeben, ob eine Burg, ein Schiff, eine Region oder eine Einheit beschrieben werden soll." - "$unit($unit) in $region($region): '$order($command)' - Specify if description is for a castle, a ship, a region or a unit." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Man muß angeben, ob eine Burg, ein Schiff, eine Einheit, eine Region oder eine Partei benannt werden soll." - "$unit($unit) in $region($region): '$order($command)' - Specify if a castle, a ship, a region or a unit is supposed to be named." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es sind keine Kräuter zu finden." - "$unit($unit) in $region($region): '$order($command)' - No herbs could be found." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Man braucht mindestens zwei Pferde, um sie zu züchten." - "$unit($unit) in $region($region): '$order($command)' - You need at least two horses to breed more." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Magier müssen zum studieren allein sein." - "$unit($unit) in $region($region): '$order($command)' - When studying, magicians need to be alone." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Leere Einheiten können nicht übergeben werden." - "$unit($unit) in $region($region): '$order($command)' - Empty units can not be handed over." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Laen kann nur in einem Bergwerk abgebaut werden." - "$unit($unit) in $region($region): '$order($command)' - Laen can be excavated only in a mine." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Keiner hier kann Straßen bauen." - "$unit($unit) in $region($region): '$order($command)' - Nobody here can build roads." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann keine weiteren Güter handeln." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot trade any more goods." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Keiner hier kann ein Gebäude errichten." - "$unit($unit) in $region($region): '$order($command)' - Nobody here can construct a building." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Keiner hier ist gelernter Schiffbauer." - "$unit($unit) in $region($region): '$order($command)' - Nobody here is a skilled ship builder." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit will nicht transportiert werden." - "$unit($unit) in $region($region): '$order($command)' - The unit doen not want to be transported." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Insekten können im Winter nur in Wüsten rekrutiert werden." - "$unit($unit) in $region($region): '$order($command)' - In winter, insects can be recruited only in deserts." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - In Gletschern können keine Insekten rekrutiert werden." - "$unit($unit) in $region($region): '$order($command)' - Insects cannot be recruited in glaciers." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - In dieser Einheit gibt es niemanden, den man transferieren könnte." - "$unit($unit) in $region($region): '$order($command)' - Nobody in this unit can be transferred." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Illusionen können eine Region nicht bewachen." - "$unit($unit) in $region($region): '$order($command)' - Illusions cannot guard a region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier kann man keine Straße bauen." - "$unit($unit) in $region($region): '$order($command)' - You cannot build a road here." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier gibt es schon einen Hafen." - "$unit($unit) in $region($region): '$order($command)' - There is already a port in this region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier gibt es keine Bauern." - "$unit($unit) in $region($region): '$order($command)' - There are no peasants in this region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier gibt es keinen normalen Wald." - "$unit($unit) in $region($region): '$order($command)' - There is no normal forest in this region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier gibt es keine Mallornbäume." - "$unit($unit) in $region($region): '$order($command)' - There are no Mallorn trees here." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit fährt nicht mit uns." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have a RIDE-order." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Geldgebot fehlt." - "$unit($unit) in $region($region): '$order($command)' - Money offer is missing." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht genügend Materialien für den Schiffbau." - "$unit($unit) in $region($region): '$order($command)' - the unit is lacking materials to build the ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Für das Elixier benötigt man Drachenblut." - "$unit($unit) in $region($region): '$order($command)' - Dragon blood is required for this elixir." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Falsches Passwort." - "$unit($unit) in $region($region): '$order($command)' - Wrong password." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es wurde keine EMail-Adresse angegeben." - "$unit($unit) in $region($region): '$order($command)' - No email-address was supplied." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es wurde kein Name angegeben." - "$unit($unit) in $region($region): '$order($command)' - No name was supplied." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es konnte kein Bauer gefangen werden." - "$unit($unit) in $region($region): '$order($command)' - No peasant could be caught." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es gibt keine Abstimmung mit dieser Nummer." - "$unit($unit) in $region($region): '$order($command)' - There is no agreement with this number." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Einheit muß zuerst die Region bewachen." - "$unit($unit) in $region($region): '$order($command)' - first, the unit must guard the region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Einheit ist nicht bewaffnet und kampffähig." - "$unit($unit) in $region($region): '$order($command)' - The unit is not armed and fighting fit." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Ein Schiff oder eine Burg muß angegeben werden." - "$unit($unit) in $region($region): '$order($command)' - A ship or a castle must be supplied." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Ein Fluch verhindert die Übergabe." - "$unit($unit) in $region($region): '$order($command)' - A curse prevented the transfer from happening." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieses Talent wurde nicht erkannt." - "$unit($unit) in $region($region): '$order($command)' - The skill could not be recognized." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieses Talent kann die Einheit nicht lernen." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot learn this skill." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diesen Gegenstand kann man nicht benutzen." - "$unit($unit) in $region($region): '$order($command)' - This item cannot be used." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit nimmt niemanden an." - "$unit($unit) in $region($region): '$order($command)' - This unit does not take anybody." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Eine hungernde Einheit kann niemanden weggeben." - "$unit($unit) in $region($region): '$order($command)' - Hungry units cannot give anybody away." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diese Einheit kann niemanden weggeben." - "$unit($unit) in $region($region): '$order($command)' - This unit cannot give anybody away." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) hat keinen Kontakt mit uns aufgenommen." - "$unit($unit) in $region($region): '$order($command)' - $unit($target) did not contact us." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es kann hier kein Kontakt zur Astralwelt aufgenommen werden." - "$unit($unit) in $region($region): '$order($command)' - There is no connection to the astral plane." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) hat keinen Kontakt mit uns aufgenommen und widersteht dem Zauber." - "$unit($unit) in $region($region): '$order($command)' - $unit($target) did not contact us, and resists the spell." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) hat keinen Kontakt mit uns aufgenommen, aber widersteht dem Zauber nicht." - "$unit($unit) in $region($region): '$order($command)' - $unit($target) did not contact us, but cannot resist the spell." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Richtung wurde nicht erkannt." - "$unit($unit) in $region($region): '$order($command)' - Direction was not recognized." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Richtung '$dirname' wurde nicht erkannt." - "$unit($unit) in $region($region): '$order($command)' - Direction '$dirname' was not recognized." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Region wird von Nichtalliierten bewacht." - "$unit($unit) in $region($region): '$order($command)' - This region is guarded by a non allied faction." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Region wird von $unit($guard), einer nichtalliierten Einheit, bewacht." - "$unit($unit) in $region($region): '$order($command)' - This region is guarded by $unit($guard), a non-allied unit." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Pferde würden ertrinken." - "$unit($unit) in $region($region): '$order($command)' - The horses would drown." - "$unit($unit) in $region($region): '$order($command)' - The horses would drown." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Partei wurde nicht gefunden." - "$unit($unit) in $region($region): '$order($command)' - The faction could not be found." - "$unit($unit) in $region($region): '$order($command)' - The faction could not be found." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Lernkosten können nicht bezahlt werden." - "$unit($unit) in $region($region): '$order($command)' - Tuition was too high to be paid." - "$unit($unit) in $region($region): '$order($command)' - Tuition was too high to be paid." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Gegenstand kann nur in der realen Welt benutzt werden." - "$unit($unit) in $region($region): '$order($command)' - This object can only be used in the real world." - "$unit($unit) in $region($region): '$order($command)' - This object can only be used in the real world." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) ist nicht ausreichend getarnt." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) is not sufficiently stealthy." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) is not sufficiently stealthy." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit wurde nicht gefunden." - "$unit($unit) in $region($region): '$order($command)' - The unit could not be found." - "$unit($unit) in $region($region): '$order($command)' - The unit could not be found." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Einheit kann nichts gegeben werden." - "$unit($unit) in $region($region): '$order($command)' - You cannot give anything to this unit." - - - - - - - - - "$unit($mage) horcht $unit($unit) über $region($tregion) aus." - "$unit($mage) questions $unit($unit) about $region($tregion)." - - - - - - - - "$unit($mage) verschafft $unit($unit) einige feuchtfröhliche Stunden mit heftigen Nachwirkungen." - "$unit($mage) invites $unit($unit) for a few too many drinks and a massive hangover." - - - - - - - "$unit($unit) hat höllische Kopfschmerzen und kann sich an die vergangene Woche nicht mehr erinnern. Nur noch daran, wie alles mit einer fröhlichen Feier in irgendeiner Taverne anfing...." - "$unit($unit) has a splitting headache and can hardly remember last week. Except that it all started in the tavern..." - - - - - - - - "$unit($mage) besänftigt $unit($unit)." - "$unit($mage) calms $unit($unit)." - - - - - - - "$unit($unit) verfiel dem Glücksspiel und hat fast sein ganzes Hab und gut verspielt." - "$unit($unit) gambles for high stakes and loses almost everything." - - - - - - - - - "$unit($unit) schenkt $unit($mage) $resources($items)." - "$unit($unit) gives $unit($mage) $resources($items)." - - - - - - - - - "$unit($mage) läßt $unit($target) als $race($race,$unit.size($target)) erscheinen." - "$unit($mage) makes $unit($target) appear as $race($race,$unit.size($target))." - - - - - - - "$unit($unit) wird kurz von einem magischen Licht umhüllt." - "$unit($unit) is briefly surrounded by a magical light." - - - - - - - - "$unit($unit) konnte nur $int($ships) von $int($maxships) Schiffen verzaubern." - "$unit($unit) could only enchant $int($ships) of $int($maxships) ships." - - - - - - "$unit($unit) beschwört einen magischen Wind, der die Schiffe über das Wasser treibt." - "$unit($unit) calls up a magical storm that whips the ship over the waters." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit weiß nichts über Botanik." - "$unit($unit) in $region($region): '$order($command)' - The unit does not know anything about herbalism." - "$unit($unit) in $region($region): '$order($command)' - The unit does not know anything about herbalism." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit weiß nicht, wie man gaukelt." - "$unit($unit) in $region($region): '$order($command)' - The unit does not know how to entertain." - "$unit($unit) in $region($region): '$order($command)' - The unit does not know how to entertain." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit trägt zuviel Gewicht, um sich bewegen zu können." - "$unit($unit) in $region($region): '$order($command)' - The unit is too heavily loaded to move." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann soviele Pferde nicht bändigen." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot tame that many horses." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann sich nicht fortbewegen." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot move." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht handeln." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot trade." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann keine Tränke herstellen." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot make potions." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann keine weiteren langen Befehle ausführen." - "$unit($unit) in $region($region): '$order($command)' - The unit is exhausted from battle." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht genug Silber." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough silver." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough silver." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht erfahren genug dafür." - "$unit($unit) in $region($region): '$order($command)' - The unit is not experienced enough to do this." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht der Eigentümer." - "$unit($unit) in $region($region): '$order($command)' - The unit is not he owner." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht bewaffnet und kampffähig." - "$unit($unit) in $region($region): '$order($command)' - The unit is not armed and fighting fit." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist mit uns alliiert." - "$unit($unit) in $region($region): '$order($command)' - This unit is one of our allies." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist in keiner Taverne." - "$unit($unit) in $region($region): '$order($command)' - The unit is not in a tavern." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist eine der unsrigen." - "$unit($unit) in $region($region): '$order($command)' - This unit is one of our own." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist auf hoher See." - "$unit($unit) in $region($region): '$order($command)' - The unit is off shore." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat soetwas nicht." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have this." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht genug Wagenlenker oder zuviel andere Fracht, um die Wagen aufzuladen." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough coachmen or too much freights to lad the wagons." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht genug Silber." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough silver." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat keinen Kontakt mit uns aufgenommen." - "$unit($unit) in $region($region): '$order($command)' - The unit did not contact us." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat keine Spionage gelernt." - "$unit($unit) in $region($region): '$order($command)' - The unit has not yet learned espionage." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat keine Kräuter." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have any herbs." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat diesen Trank nicht." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have this potion." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat diesen Gegenstand nicht." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have this item." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat diesen Gegenstand zwar, aber sämtliche $int($reservation) $resource($resource,$reservation) sind reserviert." - "$unit($unit) in $region($region): '$order($command)' - The unit has this item, but all $int($reservation) $resource($resource,$reservation) are reserved." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat diese Kräuter nicht." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have these herbs." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Einheiten dürfen nicht mehr als $int($maxsize) Personen enthalten." - "$unit($unit) in $region($region): '$order($command)' - Units may not have more than $int($maxsize) members." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit darf nicht an Bord kommen, da sie das Schiff überladen würde." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot go aboard, the ship would be overloaded." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit darf nicht an Bord kommen." - "$unit($unit) in $region($region): '$order($command)' - This unit has no permission to come on board." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit befindet sich nicht in unserer Burg." - "$unit($unit) in $region($region): '$order($command)' - The unit is not in our castle." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit befindet sich nicht an Bord unseres Schiffes." - "$unit($unit) in $region($region): '$order($command)' - The unit is not on board our ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Burg wurde nicht gefunden." - "$unit($unit) in $region($region): '$order($command)' - The castle could not be found." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Botschaft enthält keinen Text." - "$unit($unit) in $region($region): '$order($command)' - The message does not contain text." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Bauern sind schlecht gelaunt." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Anzahl zu verkaufender Produkte fehlt." - "$unit($unit) in $region($region): '$order($command)' - The amount of items for sale is missing." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Anzahl zu kaufender Produkte fehlt." - "$unit($unit) in $region($region): '$order($command)' - The amount of items to buy is missing." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Fluch verhindert das." - "$unit($unit) in $region($region): '$order($command)' - The escape prevented that from happening." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Belagerungszustand macht Spionage unmöglich." - "$unit($unit) in $region($region): '$order($command)' - Espionage was not possible due to siege." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Belagerungszustand macht die Kontaktaufnahme unmöglich." - "$unit($unit) in $region($region): '$order($command)' - Contact was not possible due to siege." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Befehl wurde nicht erkannt." - "$unit($unit) in $region($region): '$order($command)' - Unknown command." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dazu gibt es keine Informationen." - "$unit($unit) in $region($region): '$order($command)' - There is no information available for the request." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff wurde nicht gefunden." - "$unit($unit) in $region($region): '$order($command)' - The ship could not be found." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff muß erst verlassen werden." - "$unit($unit) in $region($region): '$order($command)' - First you have to leave the ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff ist zu schwer beladen, um in See zu stechen." - "$unit($unit) in $region($region): '$order($command)' - The ship is too heavily loaded to sail." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $ship($ship) ist zu groß, um fliegen zu können." - "$unit($unit) in $region($region): '$order($command)' - $ship($ship) is too bulky to fly." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff ist schon fertig." - "$unit($unit) in $region($region): '$order($command)' - The ship is already completed." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff ist noch nicht fertig gebaut." - "$unit($unit) in $region($region): '$order($command)' - The ship has not yet been completed." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff ist auf hoher See." - "$unit($unit) in $region($region): '$order($command)' - The ship is off shore." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff hat sich bereits bewegt." - "$unit($unit) in $region($region): '$order($command)' - The ship has moved already." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Besitzer muss das Gebäude zuerst verlassen." - "$unit($unit) in $region($region): '$order($command)' - The owner must first LEAVE the building." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff gehört uns nicht." - "$unit($unit) in $region($region): '$order($command)' - The ship is not ours." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Gebäude gehört uns nicht." - "$unit($unit) in $region($region): '$order($command)' - The building is not ours." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff befindet sich auf hoher See." - "$unit($unit) in $region($region): '$order($command)' - The ship is still off shore." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das macht wenig Sinn." - "$unit($unit) in $region($region): '$order($command)' - That does not make much sense." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das kann man nicht sabotieren." - "$unit($unit) in $region($region): '$order($command)' - That cannot be sabotaged." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das ist sinnlos." - "$unit($unit) in $region($region): '$order($command)' - That is useless." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das geht nicht mehr." - "$unit($unit) in $region($region): '$order($command)' - This is no longer possible." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Gebäude wurde nicht gefunden." - "$unit($unit) in $region($region): '$order($command)' - Building could not be found." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Gebäude gehört uns nicht." - "$unit($unit) in $region($region): '$order($command)' - The building is not ours." - "$unit($unit) in $region($region): '$order($command)' - The building is not ours." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Gebäude ist bereits fertig." - "$unit($unit) in $region($region): '$order($command)' - The building is already completed." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht unterrichtet werden." - "$unit($unit) in $region($region): '$order($command)' - this unit cannot be taught." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Beschreibung zu lang - gekürzt." - "$unit($unit) in $region($region): '$order($command)' - Description has been cut (too long)." - "$unit($unit) in $region($region): '$order($command)' - Description has been cut (too long)." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Auf hoher See kann man nicht bewachen." - "$unit($unit) in $region($region): '$order($command)' - You cannot guard off shore." - "$unit($unit) in $region($region): '$order($command)' - You cannot guard off shore." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Auf dem Schiff befinden sich zuwenig erfahrene Seeleute." - "$unit($unit) in $region($region): '$order($command)' - There are not enough experienced sailors on board the ship." - "$unit($unit) in $region($region): '$order($command)' - There are not enough experienced sailors on board the ship." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - ${error}." - "$unit($unit) in $region($region): '$order($command)' - ${error}." - - - - - - - "$unit($unit) benutzt ein $resource($item,1)." - "$unit($unit) uses a $resource($item,1)." - "$unit($unit) uses a $resource($item,1)." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $resource($item,0) können nur von Ein-Personen Einheiten benutzt werden." - "$unit($unit) in $region($region): '$order($command)' - $resource($item,0) can only be used by single-person units." - "$unit($unit) in $region($region): '$order($command)' - $resource($item,0) can only be used by single-person units." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist noch zu erschöpft vom Einmarsch um zu attackieren." - "'$order($command)' - $unit($unit) marched into $region($region) during the last turn and is too exhausted to attack." - "'$order($command)' - $unit($unit) marched into $region($region) during the last turn and is too exhausted to attack." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) sind friedliebend und attackieren niemand." - "'$order($command)' - $race($race,0) are peace-loving and will not attack anyone." - "'$order($command)' - $race($race,0) are peace-loving and will not attack anyone." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit steht nicht im benötigten Gebäude, $localize($building)." - "$unit($unit) in $region($region): '$order($command)' - The unit must be in a $localize($building) to produce this." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dazu braucht man das Talent $skill($skill)." - "$unit($unit) in $region($region): '$order($command)' - this requires the skill $skill($skill)." - - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Man benötigt mindestens $int($minskill) $skill($skill), um $resource($product,0) zu pflanzen." - "$unit($unit) in $region($region): '$order($command)' - At least $skill($skill) $int($minskill) is needed for planting $resource($product,0)." - "$unit($unit) in $region($region): '$order($command)' - At least $skill($skill) $int($minskill) is needed for planting $resource($product,0)." - - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Man benötigt mindestens $int($minskill) $skill($skill), um $resource($product,0) zu produzieren." - "$unit($unit) in $region($region): '$order($command)' - You need at least $int($minskill) $skill($skill), to produce $resource($product,0)." - - - - - - "$string" - "$string" - - - - - - "$string" - "$string" - - - - - - "$string" - "$string" - - - - - - - - "$unit($unit) übergibt $int($amount) Person$if($eq($amount,1),"","en") an $unit($target)." - "$unit($unit) transfers $int($amount) person$if($eq($amount,1),"","s") to $unit($target)." - - - - - - - - - - "$unit($unit) übergibt $int($amount) $resource($resource,$amount) an $unit($target)." - "$unit($unit) gives $int($amount) $resource($resource,$amount) to $unit($target)." - - - - - - - - - - "$unit($target) erhält $int($amount) $resource($resource,$amount) von $unit($unit)." - "$unit($target) receives $int($amount) $resource($resource,$amount) from $unit($unit)." - - - - - - - - "$unit($unit) übergibt $int($amount) Person$if($eq($amount,1),"","en") an die Bauern." - "$unit($unit) transfers $int($amount) person$if($eq($amount,1),"","s") to the local peasants." - - - - - - - - - "$unit($unit) übergibt $int($amount) $resource($resource,$amount) an die Bauern." - "$unit($unit) gives $int($amount) $resource($resource,$amount) to the local peasants." - - - - - - - - "$unit($unit) bezahlt den Unterhalt von $building($building)." - "$unit($unit) pays the maintenance for $building($building)." - "$unit($unit) pays the maintenance for $building($building)." - - - - - - - - "$unit($unit) fehlen $resource($item,0) für den Betrieb von $building($building)." - "$unit($unit) lacks $resource($item,0) to operate $building($building)." - - - - - - - "$unit($unit) kann den Unterhalt von $building($building) nicht bezahlen." - "$unit($unit) cannot pay the maintenance for $building($building)." - "$unit($unit) cannot pay the maintenance for $building($building)." - - - - - - "Der Unterhalt von $building($building) konnte nur verspätet gezahlt werden, das Gebäude war diese Woche nicht funktionstüchtig." - "The upkeep for $building($building) was paid late, the building was not operational this week." - "The upkeep for $building($building) was paid late, the building was not operational this week." - - - - - - - - "$unit($unit) verdient am Handel in $region($region) Steuern in Höhe von $int($amount) Silber." - "$unit($unit) collected $int($amount) silver trade tax in $region($region)." - "$unit($unit) collected $int($amount) silver trade tax in $region($region)." - - - - - - - "$unit($unit) benutzt $resource($potion,1)." - "$unit($unit) uses $resource($potion,1)." - "$unit($unit) uses $resource($potion,1)." - - - - - - "Hier wütete die Pest, und $int($dead) Bauern starben." - "The region is visited by the plague and $int($dead) peasants died." - "The region is visited by the plague and $int($dead) peasants died." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Um in Gletschern Straßen bauen zu können, muß zuerst ein Tunnel errichtet werden." - "$unit($unit) in $region($region): '$order($command)' - You've got to build a tunnel before building roads through glaciers." - "$unit($unit) in $region($region): '$order($command)' - You've got to build a tunnel before building roads through glaciers." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Syntax: MAGIEGEBIET [1-5]." - "$unit($unit) in $region($region): '$order($command)' - Syntax: MAGIC SPHERE [1-5]." - "$unit($unit) in $region($region): '$order($command)' - Syntax: MAGIC SPHERE [1-5]." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Deine Partei muss mindestens $int($turns) alt sein, um etwas an andere Parteien übergeben zu können." - "$unit($unit) in $region($region): '$order($command)' - Your faction must be at least $int($turns) weeks old to give something to another faction." - "$unit($unit) in $region($region): '$order($command)' - Your faction must be at least $int($turns) weeks old to give something to another faction." - - - - - - "Bitte sende die Befehle nächste Runde ein, wenn du weiterspielen möchtest." - "Merci d'envoyer vos ordres pour le tour suivant si vous désirez continuer à jouer." - "Please send in orders for the next turn if you want to continue playing." - - - - - - - "Deine Partei ist noch $int($turns) Wochen immun gegen Angriffe." - "Votre faction est immunisée contre les agressions durant $int($turns) semaines encore." - "Your faction is immune against assaults for $int($turns) more weeks." - - - - - - - - "$faction($member) ist mit $int($votes) Stimmen aus $alliance($alliance) ausgeschlossen worden." - "$faction($member) was kicked from $alliance($alliance) by $int($votes) of the alliance's members." - "$faction($member) was kicked from $alliance($alliance) by $int($votes) of the alliance's members." - - - - - - "$alliance($alliance) scheidet aus dem Spiel aus, nachdem alle Tempel verloren gingen." - "$alliance($alliance) has to leave the game after all their temples were lost." - "$alliance($alliance) has to leave the game after all their temples were lost." - - - - - - - "$int($votes) Mitglieder von $alliance($alliance) haben versucht, Deine Partei aus der Allianz auszuschliessen." - "$int($votes) members of $alliance($alliance) tried to kick you out of the alliance." - "$int($votes) members of $alliance($alliance) tried to kick you out of the alliance." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - In dieser Regione können Pyramiden gebaut werden." - "$unit($unit) in $region($region): '$order($command)' - Pyramids may be build in this region." - "$unit($unit) in $region($region): '$order($command)' - Pyramids may be build in this region." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Auf $ship($ship) liegt beeits ein Zauber." - "$unit($unit) in $region($region): '$order($command)' - There is already a spell on $ship($ship)." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es ist zu gefährlich, diesen Zauber auf das fliegende Schiff $ship($ship) zu legen." - "$unit($unit) in $region($region): '$order($command)' - It is far too dangerous to put this spell on the flying ship $ship($ship)." - - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - In dieser Region können keine Pyramiden gebaut werden. Die nächste Pyramidenregion ist zwischen $int($mindist) und $int($maxdist) Regionen entfernt." - "$unit($unit) in $region($region): '$order($command)' - No pyramids may be build in this region. The closest region to build a pyramid in is between $int($mindist) and $int($maxdist) regions away." - "$unit($unit) in $region($region): '$order($command)' - No pyramids may be build in this region. The closest region to build a pyramid in is between $int($mindist) and $int($maxdist) regions away." - - - - - - - - "$unit($unit) kann in $region($region) nicht durch das Wurmloch reisen, da die Einheit entweder zu gross ist oder teure Talente besitzt." - "$unit($unit) cannot travel through the wormhole in $region($region) because the unit is either too big or has restricted skills." - "$unit($unit) cannot travel through the wormhole in $region($region) because the unit is either too big or has restricted skills." - - - - - - - "$unit($unit) reist durch ein Wurmloch nach $region($region)." - "$unit($unit) travels through a wormhole to $region($region)." - "$unit($unit) travels through a wormhole to $region($region)." - - - - - - "In $region($region) erscheint ein Wurmloch." - "A wormhole appears in $region($region)." - "A wormhole appears in $region($region)." - - - - - - "Das Wurmloch in $region($region) schließt sich." - "The wormhole in $region($region) disappears." - "The wormhole in $region($region) disappears." - - - - - - - "$int($amount) Krieger von $unit($unit) benutzen ihre Flammenschwerter." - "$int($amount) fighters of $unit($unit) are using their flaming sword." - - - - - - - "$int($amount) Krieger von $unit($unit) feuern ihre Katapulte ab." - "$int($amount) fighters of $unit($unit) launch their catapults." - - - - - - "Der Kampf wurde ausgelöst von ${factions}." - "The battle was initiated by ${factions}." - - - - - - "$unit($unit) konnte durch einen Heiltrank überleben." - "$unit($unit) was saved by a haling potion." - - - - - - "$unit($unit) konnte dem Gegner eine Falle stellen." - "$unit($unit) lured the enemy into an ambush." - - - - - - "$unit($unit) überrascht den Gegner." - "$unit($unit) surprises the enemies." - - - - - - - "$unit($unit) versucht $spell($spell) zu zaubern, doch der Zauber schlägt fehl!" - "$unit($unit) tries to cast $spell($spell), but the spell fails!" - - - - - "Der Kampf wurde abgebrochen, da alle Verteidiger flohen." - "The battle was aborted because all enemies escaped." - - - - - - "... in der $int($row). Kampflinie:" - "... in combat rank $int($row):" - - - - - - - "$unit($mage) zaubert $spell($spell), aber niemand war in Reichweite." - "$unit($mage) casts $spell($spell), but nobody was in range." - - - - - - "Einheiten nach dem Kampf:" - "Units after the battle:" - - - - - - "" - "" - - - - - - - - - "$unit($mage) ruft $int($amount) $race($race, $amount) zu Hilfe." - "$unit($mage) calls for the help of $int($amount) $race($race, $amount)." - - - - - - - "$unit($mage) beschwört Trugbilder herauf." - "$unit($mage) summons a mirage." - - - - - - - "$unit($mage) murmelt eine düster klingende Formel. Ein plötzlicher Tumult entsteht, der sich jedoch schnell wieder legt." - - - - - - - "$unit($mage) murmelt eine düster klingende Formel. Ein plötzlicher Tumult entsteht und bringt die Kampfaufstellung durcheinander." - - - - - - - "$unit($mage) stimmt einen seltsamen Gesang an. Ein plötzlicher Tumult entsteht, der sich jedoch schnell wieder legt." - - - - - - - "$unit($mage) stimmt einen seltsamen Gesang an. Ein plötzlicher Tumult entsteht und bringt die Kampfaufstellung durcheinander." - "$unit($mage) begins a mysterious chant. great confusion sweeps through the ranks of the enemy." - - - - - - - - "$unit($mage) läßt die Mauern von $building($building) in einem unheimlichen magischen Licht erglühen." - - - - - - - "Einheiten vor der $int($turn). Runde:" - "Units before turn $int($turn):" - - - - - - "In $region($region) findet ein Kampf statt." - "There is a battle in $region($region)." - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($dead) $if($eq($dead,1),"Krieger wurde", "Krieger wurden") getötet." - "$unit($mage) casts $spell($spell): $int($dead) $if($eq($dead,1),"enemy was", "enemies were") killed." - - - - - - - - "$unit($mage) läßt die Erde in $region($region) erzittern." - "$unit($mage) shakes the earth in $region($region)." - - - - - - - - "$unit($mage) verflucht das Land in $region($region), und eine Dürreperiode beginnt." - "$unit($mage) puts a curse on the lands of $region($region) and a drought sets in." - - - - - - - "$unit($mage) erschafft einen Klon." - "$unit($mage) creates a clone." - - - - - - - - - "$unit($mage) verliert sich in die Träume von $unit($unit) und erhält einen Eindruck von $region($region)." - - - - - - - - - "$unit($mage) verschafft $unit($unit) ein schönes Nachtleben in $region($region)." - - - - - - - - "$unit($mage) sorgt für schlechten Schlaf in $region($region)." - - - - - - - - - "$unit($mage) beschwört $int($amount) $race($race,$amount)." - "$unit($mage) summons $int($amount) $race($race,$amount)." - - - - - - - - - "$unit($mage) erschafft in $region($region) eine verheerende Feuersbrunst. $int($amount) Bäume fallen den Flammen zum Opfer." - "$unit($mage) creates a flaming inferno in $region($region). $int($amount) trees fall vistim to the flames." - - - - - - - - "Mit einem Ritual bindet $unit($mage) die magischen Kräfte der Erde in die Mauern von $building($building)." - - - - - - - - "$unit($mage) weight $building($building)." - "$unit($mage) blesses $building($building)." - - - - - - - - "$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Eis schmilzt und verwandelt sich in Morast. Reißende Ströme spülen die mageren Felder weg und ersäufen Mensch und Tier. Was an Bauten nicht den Fluten zum Opfer fiel, verschlingt der Morast. Die sengende Hitze verändert die Region für immer." - - - - - - - - "$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Die Felder verdorren und Pferde verdursten. Die Hungersnot kostet vielen Bauern das Leben. Vertrocknete Bäume recken ihre kahlen Zweige in den blauen Himmel, von dem erbarmungslos die sengende Sonne brennt." - - - - - - - - "$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Die Felder verdorren und Pferde verdursten. Die Hungersnot kostet vielen Bauern das Leben. Vertrocknete Bäume recken ihre kahlen Zweige in den blauen Himmel, von dem erbarmungslos die sengende Sonne brennt. Die Dürre verändert die Region für immer." - - - - - - - - "$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Das Eis zerbricht und eine gewaltige Flutwelle verschlingt die Region." - - - - "Die Darbietungen eines fahrenden Gauklers begeistern die Leute. Die fröhliche und ausgelassene Stimmung seiner Lieder überträgt sich auf alle Zuhörer." - "A touring minstrel entertains the locals. The joyous and generous disposition of his songs prove infectious." - - - - - - - "Die Darbietungen von $unit($mage) begeistern die Leute. Die fröhliche und ausgelassene Stimmung seiner Lieder überträgt sich auf alle Zuhörer." - "$unit($mage) entertains the locals. The joyous and generous disposition of his songs prove infectious." - - - "In der Luft liegt ein wunderschönes Lied, dessen friedfertiger Stimmung sich niemand entziehen kann. Einige Leute werfen sogar ihre Waffen weg." - "A wondrous song fills the air and enchants the public. The song's peaceful melody makes several listeners drop their weapon." - - - - - - "Die Gesangskunst von $unit($mage) begeistert die Leute. Die friedfertige Stimmung des Lieds überträgt sich auf alle Zuhörer. Einige werfen ihre Waffen weg." - "The marvelous singing of $unit($mage) enchants the public. The song's peaceful melody makes several listeners drop their weapon." - - - - - - - "$unit($mage) beschwört $int($number) Dämonen aus dem Reich der Schatten." - "$unit($mage) summons $int($number) demons from the realm of shadows." - - - - - - - - "$unit($mage) zaubert $spell($spell)." - "$unit($mage) casts $spell($spell)." - - - - - - - - - - "$unit($mage) zaubert $spell($spell). $int($amount) Krieger verloren Erinnerungen, $int($dead) wurden getötet." - - - - - - - - - "$unit($mage) zaubert $spell($spell). $int($amount) Krieger verloren kurzzeitig ihr Gedächtnis." - "$unit($mage) casts $spell($spell). $int($amount) fighters are temporarily losing some of their memories." - - - - - - - - - "$unit($mage) ruft $int($amount) $race($race, 0) zu Hilfe." - - - - - - - - "$unit($unit) tötete $int($dead) Krieger." - "$unit($unit) killed $int($dead) opponents." - - - - - - - - - - "Heer $int($index)($abbrev): $int($dead) Tote, $int($fled) Geflohene, $int($survived) Überlebende." - "Army $int($index)($abbrev): $int($dead) dead, $int($fled) fled, $int($survived) survivors." - - - - - - - - "$unit($mage) in $region($region): '$order($command)' - Dieser Zauber kann nicht mit Stufenangabe gezaubert werden." - "$unit($mage) in $region($region): '$order($command)' - This spell cannot be cast with variable level." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dorthin führt kein Weg." - "$unit($unit) in $region($region): '$order($command)' - There is no way leading there." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Zu $region($target) kann kein Kontakt hergestellt werden." - "$unit($unit) in $region($region): '$order($command)' - $region($target) could not be contacted." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit $unit($target) hat keinen Kontakt mit uns aufgenommen." - "$unit($unit) in $region($region): '$order($command)' - The unit $unit($target) did not contact us." - - - - - - - - - "Antimagie von $unit.dative($self) blockiert in $region($region) einen Zauber von $unit.dative($mage)." - "In $region($region), anti-magic from $unit($self) blocks the spell of $unit($mage)." - - - - - - - - - "$unit($self) schwächt in $region($region) einen Zauber von $unit.dative($mage) durch Antimagie ab." - "In $region($region), anti-magic from $unit($self) reduces the effect of $unit($mage)'s spell." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $int($pacified) Regionen wurden befriedet." - "$unit($unit) in $region($region): '$order($command)' - $int($pacified) regions have been pacified." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Keine Region konnte befriedet werden." - "$unit($unit) in $region($region): '$order($command)' - No region could be pacified." - - - - - - - - "$unit($unit) in $region($region) bläst das Horn des Tanzes. In der ganzen Region breitet sich eine friedliche Feststimmmung aus." - "$unit($unit) in $region($region) blows the Horn of Dancing. Peaceful harmony spreads over the region." - - - - - - - - "$unit($unit) in $region($region) bläst das Horn des Tanzes, doch niemand hier lässt sich von Stimmung anstecken." - "$unit($unit) in $region($region) blows the Horn of Dancing, but nobody here gets into the mood." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die $ship($ship) wird jetzt schneller ihr Ziel erreichen." - "$unit($unit) in $region($region): '$order($command)' - The $ship($ship) will now be faster." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier fühlt sich durch den Trank magische gestärkt." - "$unit($unit) in $region($region): '$order($command)' - The mage is magically invigorated." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Ausser sich vor Furcht geben die Bauern dem Barden $int($money) Silber." - "$unit($unit) in $region($region): '$order($command)' - Stricken with fear the peasants give the bard $int($money) silver." - - - - - - - - "$unit($unit) spielt einen Dudelsack. Ausser sich vor Furcht geben die Bauern $int($money) Silber." - "$unit($unit) plays the bagpipe. Stricken with fear the peasants give $int($money) silver." - - - - - - - - "$unit($unit) in $region($region) erschafft eine Akademie der Künste." - "$unit($unit) in $region($region) creates an academy of arts." - - - - - - - - "$unit($unit) in $region($region) erschafft eine Skulptur." - "$unit($unit) in $region($region) creates a sculpture." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Region ist zu weit entfernt." - "$unit($unit) in $region($region): '$order($command)' - That region is too far away." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Wege aus dieser Region sind blockiert." - "$unit($unit) in $region($region): '$order($command)' - The connections from to this regions are blocked." - - - - - - - "$unit($unit) erscheint plötzlich." - "$unit($unit) appears." - - - - - - - "$unit($unit) wird durchscheinend und verschwindet." - "$unit($unit) disappears." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) ist zu schwer." - "$unit($unit) in $region($region): '$order($command)' - $unit($target) is too heavy." - - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Partei hat bereits $int($count) von $int($max) Helden." - "$unit($unit) in $region($region): '$order($command)' - The faction already has $int($count) of $int($max) heroes." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können keine Helden erwählen." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot be heroes." - - - - - - - - "$unit($unit) wird mit $int($cost) Silber zum Helden ernannt." - "$unit($unit) uses $int($cost) silber for a promotion." - - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nur $int($have) von $int($cost) benötigtem Silber." - "$unit($unit) in $region($region): '$order($command)' - The unit has $int($have) of $int($cost) silver required." - - - - - - - "Eine gewaltige Flutwelle verschlingt $region($region) und alle Bewohner." - "A tidal wave wipes out $region($region) and all who lived there." - - - - - - - - "Eine gewaltige Flutwelle verschlingt $unit($unit) in $region($region)." - "A tidal wave wipes out $region($region) and kills $unit($unit)." - - - - - - - - "$unit($unit) reaktiviert den astralen Schutzschild in $region($region)." - "$unit($unit) reactivates the astral protection shield in $region($region)." - - - - - - - - - - "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"kehrte auf seine", "kehrten auf ihre") Felder zurück." - "$unit($unit) in $region($region): $int($number) $race($race,$number) returned to the fields." - - - - - - - - - - "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"wurde zum Baum", "wurden zu Bäumen")." - "$unit($unit) in $region($region): $int($number) $race($race,$number) turned into $if($eq($number,1),"a tree", "trees")." - - - - - - - - - - "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"verfaulte", "verfaulten")." - "$unit($unit) in $region($region): $int($number) $race($race,$number) whithered and died." - - - - - - - - - - "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"zerfiel", "zerfielen") zu Staub." - "$unit($unit) in $region($region): $int($number) $race($race,$number) turned to dust." - - - - - - - - - - "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"verschwand", "verschwanden") über Nacht." - "$unit($unit) in $region($region): $int($number) $race($race,$number) disappearedin the night." - - - - - - - - - "Der Waldbrand in $region($region) griff auch auf $region($next) über, und $int($trees) verbrannten." - "The fire in $region($region) spread to $region($next) and $int($trees) were burnt." - - - - - - - - "$unit($mage) ruft in $region($region) eine Pest hervor." - "$unit($mage) sends the plague on $region($region)." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Eine Partei darf nicht aus mehr als $int($allowed) Einheiten bestehen." - "$unit($unit) in $region($region): '$order($command)' - A faction may not consist of more than $int($allowed) units." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Eine Allianz darf aus nicht mehr als $int($allowed) Einheiten bestehen." - "$unit($unit) in $region($region): '$order($command)' - An alliance may not consist of more than $int($allowed) units." - - - - - - - - - - "$unit($unit) in $region($region): $int($amount) $resource($item,$amount) zerfallen zu Staub." - "$unit($unit) in $region($region): $int($amount) $resource($item,$amount) turn to dust." - - - - - - - - - "Die $ship($ship) ist mit gutem Wind gesegnet$if($lt($duration,3),", doch der Zauber beginnt sich bereits aufzulösen",""). ($int36($id))" - "The $ship($ship) is blessed with favourable winds$if($lt($duration,3),", but the spell is starting to wear thin",""). ($int36($id))" - - - - - - - "Kräftige Stürme haben dieses Schiff in die Luft gehoben. ($int36($id))" - "Powerful storms have lifted this ship high into the air. ($int36($id))" - - - - - - - "Mächtige Magie verhindert den Kontakt zur Realität. ($int36($id))" - "Powerful magic disrupts our contact with reality. ($int36($id))" - - - - - - - - "Ein silberner Schimmer umgibt die $ship($ship). ($int36($id))" - "A silvery shimmer surrounds the $ship($ship). ($int36($id))" - - - - - - - - "Auf den Mauern von $building($building) erkennt man seltsame Runen. ($int36($id))" - "The walls of $building($building) are inscribed with strange runes. ($int36($id))" - - - - - - - - - "$unit($mage) erschafft $int($number) $resource($item,$number)." - "$unit($mage) creates $int($number) $resource($item,$number)." - - - - - - - - "Auf den Planken von $ship($ship) erkennt man seltsame Runen. ($int36($id))" - "The plank of $ship($ship) are inscribed with strange runes. ($int36($id))" - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Kompassnadel springt wild hin und her und es lässt sich keine Richtung erkennen." - "$unit($unit) in $region($region): '$order($command)' - The needle jumps wildly and there is no specific direction recognizable." - "$unit($unit) in $region($region): '$order($command)' - The needle jumps wildly and there is no specific direction recognizable." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Kompassnadel zeigt nach $direction($dir)." - "$unit($unit) in $region($region): '$order($command)' - The needle points $direction($dir)." - "$unit($unit) in $region($region): '$order($command)' - The needle points $direction($dir)." - - - - - - - - "$unit($unit) wird aus der astralen Ebene nach $region($region) geschleudert." - "$unit($unit) is sent from the astral plain to $region($region)." - "$unit($unit) is sent from the astral plain to $region($region)." - - - - - - - - "$unit($target) wird von $unit($unit) in eine andere Welt geschleudert." - "$unit($unit) sends $unit($target) to another world." - "$unit($unit) sends $unit($target) to another world." - - - - - - - - "$unit($unit) versuchte erfolglos, $unit($target) in eine andere Welt zu schleudern." - "$unit($unit) tried but failed to send $unit($target) to another world." - "$unit($unit) tried but failed to send $unit($target) to another world." - - - - - - - "NUMMER PARTEI $int36($id): Die Partei kann nicht mehr als einmal ihre Nummer wecheln." - "NUMBER FACTION $int36($id): Your faction can only change its number once." - - - - - - - "NUMMER PARTEI $int36($id): Diese Nummer wird von einer anderen Partei benutzt." - "NUMBER FACTION $int36($id): This number is being used by another faction." - - - - - - - - "Eine Botschaft von $unit($unit): '$message'" - "A message from $unit($unit): '$message'" - - - - - - - - "Plötzlich stolpert $unit($unit) über einige $localize($name). Nach kurzem Zögern entschließen die $localize($name), sich Deiner Partei anzuschließen." - - - - - - - "$unit($unit) entdeckt ein kleines Dorf. Die meisten Häuser wurden durch einen über die Ufer getretenen Fluß zerstört. Eine Gruppe der verzweifelten Menschen schließt sich deiner Partei an." - "$unit($unit) discovers a small village. Most of the houses have been destroyed by flooding, and a group of the distressed villagers join your faction." - - - - "Ein Bauernmob erhebt sich und macht Jagd auf Schwarzmagier." - "An angry mob forms and hunts practitioners of the dark arts." - - - - - - - "Vertrauter von $unit($unit)" - "Familiar of $unit($unit)" - - - - - - - - - "$unit($unit) rekrutiert $int($amount) $localize($archetype)." - "$unit($unit) recruits $int($amount) $localize($archetype)." - - - - - - - "Dein Passwort enthält Zeichen, die bei der Nachsendung von Reports Probleme bereiten können. Bitte beachte, dass Passwortenur aus Buchstaben von A bis Z und Zahlen bestehen dürfen. Dein neues Passwort ist '${newpass}'." - "Your password was changed because it contained illegal characters. Legal passwords may only contain numbers and letters from A to Z. Your new Password is '${newpass}'." - - - - "Miiauuuuuu..." - "Meeoooooow..." - - - - - - - "Die Götter segnen $unit($unit) mit der richtigen Rasse." - "The gods are blessing $unit($unit) with the correct race." - - - - - - - "Der Versuch, die Greifenschwingen zu benutzen, schlug fehl. $unit($unit) konnte die Ebene der Herausforderung nicht verlassen." - - - - - - - "$unit($unit) springt in die ewigen Feuer des Kraters." - - - - - - - - "$unit($unit) springt in die ewigen Feuer des Kraters." - - - - - - - - "In $region($region) erklingt die Stimme des Torwächters: 'Nur wer ohne materielle Güter und noch lernbegierig ist, der darf die Ebene der Herausforderung betreten. Und vergiß nicht mein Trinkgeld.'. $unit($unit) erhielt keinen Einlaß." - - - - - - - - "In $region($region) öffnet sich ein Portal. Eine Stimme ertönt, und spricht: 'Willkommen in der Ebene der Herausforderung'. $unit($unit) durchschreitet das Tor zu einer anderen Welt." - - - - - - - "$unit($unit) scheint von einer seltsamen Krankheit befallen." - "$unit($unit) is stricken by a strange disease." - - - - - - - - - "$unit($unit) erbeutet $int($amount) $resource($item,$amount)." - "$unit($unit) collects $int($amount) $resource($item,$amount)." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es ist so schön friedlich, man möchte hier niemanden angreifen." - "$unit($unit) in $region($region): '$order($command)' - It's so quiet and peaceful, nobody wants to attack anybody right now." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können nichts lernen." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot study." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Migranten können keine kostenpflichtigen Talente lernen." - "$unit($unit) in $region($region): '$order($command)' - Migrants cannot study this." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es kann maximal $int($amount) Magier pro Partei geben." - "$unit($unit) in $region($region): '$order($command)' - There may not be more tha $int($amount) magicians in your faction." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es kann maximal $int($amount) Alchemisten pro Partei geben." - "$unit($unit) in $region($region): '$order($command)' - There may not be more tha $int($amount) alchemists in your faction." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) versteht unsere Art von Magie nicht." - "$unit($unit) in $region($region): '$order($command)' - $unit($target) does not understand our kind of magic." - - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Kapitän muß ein Segeltalent von mindestens $int($value) haben, um $ship($ship) zu befehligen." - "$unit($unit) in $region($region): '$order($command)' - The captain needs a sailing skill of at least $int($value), to command $ship($ship)." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - In dieser Region gibt es keine Brücken und Straßen mehr zu bauen." - "$unit($unit) in $region($region): '$order($command)' - the roads and bridges in this region are complete." - - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Um $localize($name) zu bauen, braucht man ein Talent von mindestens $int($value)." - "$unit($unit) in $region($region): '$order($command)' - To build $localize($name) requires a skill of at least $int($value)." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diese Einheit kämpft nicht." - "$unit($unit) in $region($region): '$order($command)' - This unit will not fight." - - - - - - - - - "$unit($unit) erhielt $resources($items) von der $ship($ship)." - "$unit($unit) received $resources($items) from the $ship($ship)." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nciht auf Untote gezaubert werden." - - - - - - - - "Achtung: $faction($faction) hat seit $int($turns) Wochen keine - Züge eingeschickt und könnte dadurch in Kürze aus dem Spiel - ausscheiden." - "Warning: $faction($faction) has not been sending in - orders for $int($turns) turns and may be leaving the game soon." - - - + + + + + + + Ein Alp starb in $region($region), ohne sein Ziel zu erreichen. + An alp died in $region($region) before reaching its target. + + + + + + "Einheiten können die folgenden Gegenstände beanspruchen: $resources($items)" + "Units can claim the following items: $resources($items)" + + + + + + + + "$if($isnull($region),"Es","In $region($region)") wurde$if($eq($number,1),"","n") $int($number) $race($race,$number) gesichtet." + "$if($isnull($region),"","In $region($region), ")$int($number) $race($race,$number) were discovered." + + + + + + + "$unit($mage) läßt einen Teil seiner selbst in die Erde fliessen. Die Bäume, die Transformation überlebt haben, erscheinen nun viel kräftiger." + "The power of $unit($mage) flows into the region and the trees which survived the spell appear stronger now." + "The power of $unit($mage) flows into the region and the trees which survived the spell appear stronger now." + + + + + + + "$unit($mage) beschwört einen Luftgeist, der die $ship($ship) in die Wolken hebt." + "$unit($mage) summons a wind spirit that lifts the $ship($ship) into the clouds." + + + + + + "$unit($mage) beschwört einen Schleier der Verwirrung." + "$unit($mage) summons a fog of confusion." + + + + + Eine Feuerwand blockiert die Ein- und Ausreise. ($int36($id)) + + + + + Der Magier besitzt die Gabe des Chaos. ($int36($id)) + The magician possesses the gift of Chaos. ($int36($id)) + + + + Dieser mächtige Bann scheint die Einheit ihres freien Willens zu berauben. Solange der Zauber wirkt, wird sie nur den Befehlen ihres neuen Herrn gehorchen. ($int36($id)) + + + + Dieser Beeinflussungszauber scheint die Einheit einem ganz bestimmten Volk wohlgesonnen zu machen. ($int36($id)) + + + + Dieser Zauber verursacht einen gigantischen magischen Strudel. Der Mahlstrom wird alle Schiffe, die in seinen Sog geraten, schwer beschädigen. ($int36($id)) + + + + Heilung ist in dieser Region magisch beeinflusst. ($int36($id)) + + + + Dieses Schiff hat sich verfahren. ($int36($id)) + + + + + + + + "$unit($unit) ist im Traum eine Fee erschienen. ($int36($id))" + "In a dream, a fairy appears to $unit($unit). ($int36($id))" + + + + + + + "$unit($unit) wird von bösen Alpträumen geplagt. ($int36($id))" + "$unit($unit) is haunted by terrbile nightmares. ($int36($id))" + + + + + + + "$unit($unit) wird von einem glitzernden Funkenregen umgeben. ($int36($id))" + "$unit($unit) is surrounded by a shower of glittering sparkles. ($int36($id))" + + + + + + + "Ein schimmernder Lichterkranz umgibt $unit($unit). ($int36($id))" + "A circle of shimmering lights surrounds $unit($unit). ($int36($id))" + + + + + + + "Eine Melodie erklingt, und $unit($unit) tanzt bis spät in die Nacht hinein. ($int36($id))" + "A haunting melody fills the air, and $unit($unit) dances until late into the night. ($int36($id))" + + + + + + + "$unit($unit) findet eine kleine Flöte, die eine wundersame Melodie spielt. ($int36($id))" + "$unit($unit) finds a small flute that plays a beautiful melody. ($int36($id))" + + + + + + + "Die Frauen des nahegelegenen Dorfes bewundern $unit($unit) verstohlen. ($int36($id))" + "The women of the nearby village cast furtive looks at $unit($unit). ($int36($id))" + + + + + + + "Eine Gruppe vorbeiziehender Bergarbeiter rufen $unit($unit) eindeutig Zweideutiges nach. ($int36($id))" + "A group of passing miners makes passes at $unit($unit). ($int36($id))" + + + + + + + "$unit($unit) bekommt von einer Schlange einen Apfel angeboten. ($int36($id))" + "A large green snake offers $unit($unit) a fine-looking apple. ($int36($id))" + + + + + + "A spell is deflecting magical energies and weakening all other spells cast in the region. ($int36($id))" + "Dieser Zauber scheint magische Energien irgendwie abzuleiten und so alle in der Region gezauberten Sprüche in ihrer Wirkung zu schwächen oder ganz zu verhindern. ($int36($id))" + + + + + + + "Ein Einhorn berührt $unit($unit) mit seinem Horn und verschwindet kurz darauf im Unterholz. ($int36($id))" + "A unicorn touches $unit($unit) with its horn and vanishes into the forest quickly after. ($int36($id))" + + + + + + + "Vogelzwitschern begleitet $unit($unit) auf all seinen Wegen. ($int36($id))" + "Bird songs follow $unit($unit) on all his travels. ($int36($id))" + + + + + + + "Leuchtende Blumen erblühen rund um das Lager von $unit($unit). ($int36($id))" + "Brightly coloured flowers pop up all around $unit($unit)'s camp. ($int36($id))" + + + + + + + "Über $unit($unit) zieht eine Gruppe Geier ihre Kreise. ($int36($id))" + "A group of vultures circles above $unit($unit). ($int36($id))" + + + + + + + "Der Kopf von $unit($unit) hat sich in einen grinsenden Totenschädel verwandelt. ($int36($id))" + "The head of $unit($unit) has turned into a madly grinning skull. ($int36($id))" + + + + + + + "Ratten folgen $unit($unit) auf Schritt und Tritt. ($int36($id))" + "Rats follow $unit($unit)'s every step. ($int36($id))" + + + + + + + "Pestbeulen befallen den Körper von $unit($unit). ($int36($id))" + "The body of $unit($unit) is disfigured by hideous boils. ($int36($id))" + + + + + + + "Eine dunkle Fee erscheint $unit($unit) im Schlaf. Sie ist von schauriger Schönheit. ($int36($id))" + "A dark and mysterious fairy appears before $unit($unit). She is of bewitching beauty. ($int36($id))" + + + + + + + "Fäulnisgeruch dringt $unit($unit) aus allen Körperöffnungen. ($int36($id))" + "The stench of decay is poring from all the orifices of $unit($unit). ($int36($id))" + + + + + + + + "$unit($unit) mag $faction($faction) zu mögen. ($int36($id))" + "$unit($unit) likes $faction($faction). ($int36($id))" + + + + + + + + "$unit($unit) scheint $race($race, 0) zu mögen. ($int36($id))" + "$unit($unit) seems to like $race($race, 0). ($int36($id))" + + + + + + + + "$unit($unit) ist ungewöhnlich ungeschickt in $skill($skill). ($int36($id))" + "$unit($unit) has some troubles with $skill($skill). ($int36($id))" + + + + + + + + "$unit($unit) ist ungewöhnlich geschickt in $skill($skill). ($int36($id))" + "$unit($unit) is incredibly skilled at $skill($skill). ($int36($id))" + + + + + + + + "$unit($unit) wird noch $int($duration) $if($eq($duration,1), "Woche", "Wochen") unter unserem Bann stehen. ($int36($id))" + "$unit($unit) will be under our influence for $int($duration) more $if($eq($duration,1), "week", "weeks"). ($int36($id))" + + + + + + + + + "$int($number) $if($eq($number,1), "Person", "Personen") von $unit($unit) $if($eq($number,1), "ist", "sind") noch $int($duration) $if($eq($duration,1), "Woche", "Wochen") beschleunigt. ($int36($id))" + "$int($number) $if($eq($number,1), "member", "members") of $unit($unit) $if($eq($number,1), "is", "are") accelerated for $int($duration) more $if($eq($duration,1), "week", "weeks"). ($int36($id))" + + + + + + + + "$int($number) $if($eq($number,1), "Person", "Personen") von $unit($unit) $if($eq($number,1), "fühlt", "fühlen") sich vor Kälte geschützt. ($int36($id))" + "$int($number) $if($eq($number,1), "member", "members") of $unit($unit) $if($eq($number,1), "is", "are") protected from the cold. ($int36($id))" + + + + + + "Ein unbekannter Zauber liegt auf dem Schiff. ($int36($id))" + "An unknown spell lies on this ship. ($int36($id))" + + + + + + "Ein unbekannter Zauber liegt auf der Einheit. ($int36($id))" + "An unknown spell lies on this unit. ($int36($id))" + + + + + + "Ein unbekannter Zauber liegt auf dem Gebäude. ($int36($id))" + "An unknown spell lies on this building. ($int36($id))" + + + + + + "Ein unbekannter Zauber liegt auf der Region. ($int36($id))" + "An unknown spell lies on this region. ($int36($id))" + + + + + + "Eine Wolke negativer Energie liegt über der Region. ($int36($id))" + "A fog of negative energy enshrouds the region. ($int36($id))" + "A fog of negative energy enshrouds the region. ($int36($id))" + + + + + + "Die Leute strotzen nur so vor Kraft. ($int36($id))" + "Testosterone levels are at an all-time high. ($int36($id))" + + + + + + + "$unit($unit) wird von einem Alp geritten. ($int36($id))" + "$unit($unit) is chased by a nightmare. ($int36($id))" + + + + + + + "$unit($unit) stürzt sich von einem amourösen Abenteuer ins nächste. ($int36($id))" + "$unit($unit) goes from one amourous adventure to another. ($int36($id))" + "$unit($unit) goes from one amourous adventure to another. ($int36($id))" + + + + + + + "$unit($unit) kann sich kaum konzentrieren. ($int36($id))" + "$unit($unit) can hardly focus on anything. ($int36($id))" + "$unit($unit) can hardly focus on anything. ($int36($id))" + + + + + + + "Die Ausrüstung von $unit($unit) scheint unsichtbar. ($int36($id))" + "$unit($unit)'s equipment is invisible. ($int36($id))" + "$unit($unit)'s equipment is invisible. ($int36($id))" + + + + + + "Die natürliche Widerstandskraft gegen Verzauberung ist gestärkt. ($int36($id))" + "($int36($id))" + "The magical resistance has been strengthened. ($int36($id))" + + + + + + "Die natürliche Widerstandskraft gegen Verzauberung bestimmter Einheiten in dieser Region wurde gestärkt. ($int36($id))" + "($int36($id))" + "The magical resistance of some units in this region was boosted. ($int36($id))" + + + + + + "Die natürliche Widerstandskraft gegen Verzauberung bestimmter Einheiten in dieser Region wurde geschwächt. ($int36($id))" + "The magical resistance of some units in this region was weakened. ($int36($id))" + "($int36($id))" + + + + + + "Diese Mauern wirken, als wären sie direkt aus der Erde gewachsen und nicht erbaut. ($int36($id))" + "These walls appear to have grown straight out of the earth. ($int36($id))" + "($int36($id))" + + + + + + "Ein magischer Schimmer liegt auf diesen Mauern. ($int36($id))" + "A magical shimmer lies on these walls. ($int36($id))" + "($int36($id))" + + + + + + "Die Straßen sind erstaunlich trocken und gut begehbar, doch an manchen Stellen bilden sich wieder die erste Schlammlöcher. ($int36($id))" + "The roads are extremely dry and well-kept, but some areas show the first signs of potholes reappearing. ($int36($id))" + "($int36($id))" + + + + + + "Die Straßen sind erstaunlich trocken und gut begehbar. ($int36($id))" + "The roads are extremely dry and well-kept. ($int36($id))" + "($int36($id))" + + + + + + "Albträume plagen die Leute. ($int36($id))" + "Nightmares plague the population. ($int36($id))" + "($int36($id))" + + + + + + "Die Leute haben schöne Träume. ($int36($id))" + "($int36($id))" + "The people in this region have sweet dreams. ($int36($id))" + + + + + + "Diese Region wurde von den Göttern verflucht. Das Meer ist eine ekelige Brühe, braunschwarze, stinkende Gase steigen aus den unergründlichen Tiefen hervor, und untote Seeungeheuer, Schiffe zerfressend und giftige grüne Galle geifernd, sind der Schrecken aller Seeleute, die diese Gewässer durchqueren. Niemand kann hier lange überleben. ($int36($id))" + "($int36($id))" + "This region was cursed by the gods. The sea is a foul cesspool, noxious gases rise from the deep, undead seamonsters attack all ships. Noone can live here for long. ($int36($id))" + + + + + + "Diese Region wurde von den Göttern verflucht. Stinkende Nebel ziehen über die tote Erde und furchtbare Kreaturen ziehen über das Land. Die Brunnen sind vergiftet, und die wenigen essbaren Früchte sind von einem rosa Pilz überzogen. Niemand kann hier lange überleben. ($int36($id))" + "($int36($id))" + "This region was cursed by the gods. Noone can live here for long. ($int36($id))" + + + + + + "Ein Schleier der Verwirrung liegt über der Region. ($int36($id))" + "($int36($id))" + "A veil of confusion lies over the region. ($int36($id))" + + + + + + "In der Region treibt ein Giftelementar sein Unwesen. ($int36($id))" + "A poison elemental is spreading pestilence and death. ($int36($id))" + + + + + + "Die ganze Region ist von einer friedlichen Stimmung erfasst. ($int36($id))" + "($int36($id))" + "Everyone in this region seems to be in a peacful mood. ($int36($id))" + + + + + + "Es herrscht eine fröhliche und ausgelassene Stimmung. ($int36($id))" + "($int36($id))" + "Everyone in this region seems to be having a very good time. ($int36($id))" + + + + + + "Die Bauern sind unzufrieden. ($int36($id))" + "($int36($id))" + "The peasants are upset. ($int36($id))" + + + + + + "Alle Leute in der Region haben Schlafstörungen. ($int36($id))" + "($int36($id))" + "People in this region suffer from insomnia. ($int36($id))" + + + + + + "In dieser Gegend herrscht eine Dürre. ($int36($id))" + "($int36($id))" + "This region was hit by a drought. ($int36($id))" + + + + + + "In dieser Gegend steht das Korn besonders gut im Feld. ($int36($id))" + "($int36($id))" + "The grain in this region is especially healthy. ($int36($id))" + + + + + + "Die Winde scheinen dieses Schiff besonders zu beguenstigen. ($int36($id))" + "($int36($id))" + "The winds seem to favor this ship. ($int36($id))" + + + + + + "Untote schrecken vor dieser Region zurück. ($int36($id))" + "($int36($id))" + "The undead turn away from this region. ($int36($id))" + + + + + + "Der Zahn der Zeit kann diesen Mauern nichts anhaben. ($int36($id))" + "($int36($id))" + "Time cannot touch these walls. ($int36($id))" + + + + + + "Dichte Nebel bedecken diese Woche die Region. Keine Einheit schafft es, diese Nebel zu durchdringen und die Region zu verlassen. ($int36($id))" + "heavy fog makes it impossible to leave the region. ($int36($id))" + "heavy fog makes it impossible to leave the region. ($int36($id))" + + + + + + + "$unit($unit) setzt ein Sonnensegel. Die Geschwindigkeit des Schiffes erhöht um $int($speed)." + "$unit($unit) sets a solar sail. The ship's speed is increased by $int($speed)." + "$unit($unit) sets a solar sail. The ship's speed is increased by $int($speed)." + + + + + + "Interner Fehler: Meldung '$name' nicht definiert." + "Internal Error: Message '$name' is undefined." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Interner Fehler: Meldung '$name' nicht definiert." + "$unit($unit) in $region($region): '$order($command)' - Internal Error: Message '$name' is undefined." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier ist kein passendes Schloss." + "$unit($unit) in $region($region): '$order($command)' - No fitting lock can be found here." + "$unit($unit) in $region($region): '$order($command)' - No fitting lock can be found here." + + + + + + + + "$unit($unit) öffnet eines der Schlösser in $region($region) mit $if($eq($key,1),"dem Achatenen Schlüssel","dem Saphirnen Schlüssel")." + "$unit($unit) unlocks one of the locks in $region($region) with $if($eq($key,1),"the Agate Key","the Sapphire Key")." + "$unit($unit) unlocks one of the locks in $region($region) with $if($eq($key,1),"the Agate Key","the Sapphire Key")." + + + + + + + + "$unit($unit) verschließt eines der Schlösser in $region($region) mit $if($eq($key,1),"dem Achatenen Schlüssel","dem Saphirnen Schlüssel")." + "$unit($unit) locks one of the locks in $region($region) with $if($eq($key,1),"the Agate Key","the Sapphire Key")." + "$unit($unit) locks one of the locks in $region($region) with $if($eq($key,1),"the Agate Key","the Sapphire Key")." + + + + + + + "$unit($unit) in $region($region) verwandelt sich in ein Werwesen." + "$unit($unit) in $region($region) becomes a lycantrope." + "$unit($unit) in $region($region) becomes a lycantrope." + + + + + + + "SIEG! $if($eq($n,1), "Die Partei $winners hat", "Die Parteien $winners haben") die Siegbedingung für die erforderliche Zeit erfüllt. Das Spiel ist damit beendet." + "VICTORY! $if($eq($n,1), "The faction $winners has", "The factions $winners have") fulfilled the victory condition for the necessary time. The game is over." + "VICTORY! $if($eq($n,1), "The faction $winners has", "The factions $winners have") fulfilled the victory condition for the necessary time. The game is over." + + + + + + "Achtung: $faction($faction) hat die Siegbedingungen erfüllt und wird in $if($eq($remain,1),"einer Woche","$int($remain) Wochen") zum Sieger erklärt werden." + "Attention: $faction($faction) has fulfilled the victory condition and will be declared winner in $if($eq($remain,1),"one week","$int($remain) weeks")." + "Attention: $faction($faction) has fulfilled the victory condition and will be declared winner in $if($eq($remain,1),"one week","$int($remain) weeks")." + + + + + + + + "$unit($unit) wurde in $region($region) von einem GM gelöscht: \"$string\"." + "$unit($unit) in $region($region) was removed by a GM: \"$string\"." + "$unit($unit) in $region($region) was removed by a GM: \"$string\"." + + + + + + + + "$resource($item,1) (Gewicht: $weight($weight)): $description" + "$resource($item,1) (weight: $weight($weight)): $description" + + + + + "Ein Hauch des Lebens liegt über der Welt und alle Wesen fühlen sich frisch und erholt." + "Life itself touches the world and all beings are healed." + "Life itself touches the world and all beings are healed." + + + + + + + + "$unit($unit) hat Glück und findet einen Hort von $int($amount) $resource($item,$amount)." + "$unit($unit) luckily finds a cache of $int($amount) $resource($item,$amount)." + "$unit($unit) luckily finds a cache of $int($amount) $resource($item,$amount)." + + + + + + "$unit($unit) brennt ein großes Feuerwerk ab und Kaskaden bunter Sterne, leuchtende Wasserfälle aus Licht und strahlende Feuerdrachen erhellen den Himmel." + "A large firework is visible all over the sky." + "A large firework is visible all over the sky." + + + + + + + "In $region($region) wird ein großes Feuerwerk abgebrannt, welches noch hier zu bewundern ist. Kaskaden bunter Sterne, leuchtende Wasserfälle aus Licht und strahlende Feuerdrachen erhellen den Himmel." + "A large firework, visible all over the sky, has been started in $region($region)." + "A large firework, visible all over the sky, has been started in $region($region)." + + + + + + + "Zur Feier des Geburtstags von ${name} brennt $unit($unit) ein großes Feuerwerk ab. Kaskaden bunter Sterne, leuchtende Wasserfälle aus Licht und strahlende Feuerdrachen erhellen den Himmel." + "A large firework in honor of ${name} is visible all over the sky." + "A large firework in honor of ${name} is visible all over the sky." + + + + + + + + "Zur Feier des Geburtstags von ${name} wird in $region($region) ein großes Feuerwerk abgebrannt, welches noch hier zu bewundern ist. Kaskaden bunter Sterne, leuchtende Wasserfälle aus Licht und strahlende Feuerdrachen erhellen den Himmel." + "A large firework in honor of ${name}, visible all over the sky, has been started in $region($region)." + "A large firework in honor of ${name}, visible all over the sky, has been started in $region($region)." + + + + + + + "$int36($unit.id($unit))/$int($index) erzielt einen kritischen Treffer." + "$int36($unit.id($unit))/$int($index) does critical damage." + "$int36($unit.id($unit))/$int($index) does critical damage." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) muß mindestens 2 Stufen besser sein als $unit($student)." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) needs to be at least 2 levels better than $unit($student)." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) needs to be at least 2 levels better than $unit($student)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($student) lernt nicht." + "$unit($unit) in $region($region): '$order($command)' - $unit($student) is not learning." + "$unit($unit) in $region($region): '$order($command)' - $unit($student) is not learning." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dafür braucht die Einheit $resources($required)." + "$unit($unit) in $region($region): '$order($command)' - for this, the unit needs $resources($required)." + "$unit($unit) in $region($region): '$order($command)' - for this, the unit needs $resources($required)." + + + + + + $trailto($region) + $trailto($region) + + + + + + + "Deine Partei hat $int($units) Migranten und kann maximal $int($maxunits) Migranten aufnehmen." + "Your faction has $int($units) migrants out of a possible total of $int($maxunits)." + + + + + + + + + "Seit $int($age) Wochen Mitglied der Allianz '$name ($int36($id))', angeführt von $faction($leader)." + "Member of '$name ($int36($id))' for $int($age) weeks, led by $faction($leader)." + + + + + + + "Deine Partei hat $int($units) Helden und kann maximal $int($maxunits) Helden ernennen." + "Your faction has promoted $int($units) heroes out of a possible total of $int($maxunits)." + + + + + + + "Deine Partei hat $int($population) Personen in $int($units) Einheiten." + "Your faction has $int($population) people in $int($units) units." + + + + + + "Statistik für $region($region):" + "Statistics for $region($region):" + + + + + + "Unterhaltung: max. $int($max) Silber" + "Entertainment: max. $int($max) silver" + + + + + + "Moral der Bauern: $int($morale)" + "Peasant morale: $int($morale)" + + + + + + "Luxusgüter zum angegebenen Preis: $int($max)" + "Luxury goods at this price: $int($max)" + + + + + + "Lohn für Arbeit: $int($max) Silber" + "Worker salary: $int($max) silver" + + + + + + "Bauerneinnahmen: $int($max) Silber" + "Peasant wages: $int($max) silver" + + + + + + "Personen: $int($max)" + "People: $int($max)" + "People: $int($max)" + + + + + + "Rekruten: max. $int($max) Bauern" + "Recruits: $int($max) peasants" + "Recruits: $int($max) peasants" + + + + + + + "Deine Partei hat $int($score) Punkte. Der Durchschnitt für Parteien ähnlichen Alters ist $int($average) Punkte." + "Your faction has a score of $int($score). The average score for similar factions is $int($average)." + "Your faction has a score of $int($score). The average score for similar factions is $int($average)." + + + + + + + "Report für $game, $date" + "Report for $game, $date" + "Report for $game, $date" + + + + + + + "Im $direction($dir) der Region liegt $trailto($region)" + "To the $direction($dir) lies $trailto($region)" + + + + + + + "$resource($product,0) $int($price) Silber" + "$resource($product,0) for $int($price) silver" + "$resource($product,0) for $int($price) silver" + + + + + + + "Auf dem Markt wird für $resource($product,0) $int($price) Silber verlangt." + "Le marché local offre la $resource($product,0) au prix de $int($price) écus." + "The local market offers $resource($product,0) at a price of $int($price) silver." + + + + + + + "Auf dem Markt werden $resource($p1,0) und $resource($p2,0) feilgeboten." + "The local market offers $resource($p1,0) and $resource($p2,0)." + + + + + + "Auf dem Markt wird $resource($p1,0) feilgeboten." + "The local market offers $resource($p1,0)." + + + + + + "Dein Passwort lautet ${password}." + "Your password is ${password}." + "Your password is ${password}." + + + + + + "Die Mannschaft krank vom vergifteten Wasser, Planken, Ruder und Segel zerfressen von den Wassern des verfluchten Meeres, ergibt sich die $ship($ship) in ihr Schicksal und sinkt." + "Her sailors sick from the poisened ocean, planks, rudder und sails corroded by the waters of the cursed ocean, the $ship($ship) finally succumbs to her destiny and sinks." + + + + + + "$unit($unit) benutzt einen Talenttrunk und fühlt, wie sein Wissen zunimmt." + "$unit($unit) uses a potion of skills and feels his knowledge grow." + "$unit($unit) uses a potion of skills and feels his knowledge grow." + + + + + + + "$unit($unit) benutzt einen Astralkristall und gewinnt $int($aura) Aura hinzu." + "$unit($unit) uses an astralcrystal and gains $int($aura) aura." + "$unit($unit) uses an astralcrystal and gains $int($aura) aura." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Luxusgut wird hier nicht verkauft." + "$unit($unit) in $region($region): '$order($command)' - These goods are not on sale here." + "$unit($unit) in $region($region): '$order($command)' - These goods are not on sale here." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dazu benötigt man $resource($missing,0)." + "$unit($unit) in $region($region): '$order($command)' - This requires $resource($missing,0)." + "$unit($unit) in $region($region): '$order($command)' - This requires $resource($missing,0)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) nehmen nichts an." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) will not accept anything." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) will not accept anything." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können nicht neu gruppiert werden." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot be regrouped." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot be regrouped." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können nichts stehelen." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot steal anything." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot steal anything." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) geben nichts weg." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) do not give things away." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) do not give things away." + + + + + + + + "Eine Botschaft von $unit.dative($sender) aus $region($region): '$string'" + "A message by $unit($sender) from $region($region): '$string'" + + + + + + + + + "In $region($region) erhielt $unit($unit) eine Botschaft von $unit.dative($sender): '$string'" + "In $region($region), $unit($unit) received a message by $unit($sender): '$string'" + + + + + + + + + "In $region($region) erhielt $unit($unit) von $unit.dative($sender) $resources($items)" + "In $region($region), $unit($unit) received $resources($items) from $unit($sender)" + + + + + + "$building($building) hat diese Woche nicht funktioniert, da zu Beginn der Woche der Unterhalt nicht gezahlt werden konnte." + "$building($building) was nonfunctional because upkeep could not be paid at the beginning of the week." + + + + + + "Plötzlich löst sich $building($building) in kleine Traumwolken auf." + "$building($building) suddenly dissolves into small pink clouds." + + + + + + "Für das Gebäude $building($building) konnte die ganze Woche kein Unterhalt bezahlt werden." + "Upkeep for $building($building) could not be paid all week." + + + + + + + + + "In $region($region) stürzte $building($building) ein.$if($road," Beim Einsturz wurde die halbe Straße vernichtet.","")$if($opfer," $int($opfer) Opfer $if($eq($opfer,1),"ist","sind") zu beklagen.","")" + "$building($building) in $region($region) collapses.$if($opfer," There are $int($opfer) caualties.","")" + "$building($building) in $region($region) collapses.$if($opfer," There are $int($opfer) caualties.","")" + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In der Ebene der Herausforderung kann niemand rekrutiert werden." + "$unit($unit) in $region($region): '$order($command)' - You cannot recruit in this plane." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die einheit kann sich nicht so gut tarnen." + "$unit($unit) in $region($region): '$order($command)' -The unit cannot hide that well." + + + + + + + + "$ship($ship) was destroyed by $unit($unit)." + "$ship($ship) wurde von $unit($unit) zerstört." + + + + + + + + "$unit($unit) could not destroy $ship($ship)." + "$unit($unit) konnte $ship($ship) nicht zerstören." + + + + + + + + "$unit($unit) was detected while trying to destroy $ship($ship)." + "$unit($unit) wurde beim Versuch $ship($ship) zu zerstören entdeckt." + + + + + + + "Somebody attempted to destroy $ship($ship)." + "Es wurde versucht, $ship($ship) zu zerstören." + + + + + + + "$ship($ship) was destroyed." + "$ship($ship) wurde zerstört." + + + + + + + + + "$int($amount) Personen von $unit($unit) ertrinken.$if($isnull($region),""," Die Einheit rettet sich nach $region($region).")" + + + + + + + + "$unit($unit) ueberlebt unbeschadet und rettet sich nach $region($region)." + + + + + + + + "$ship($ship) versinkt in den Fluten von $region($region)." + + + + + + + + "$unit($unit) wurde beim versenken von $ship($ship) entdeckt." + + + + + + + + + "$unit($unit) entdeckte $unit($saboteur) beim versenken von $ship($ship)." + + + + + + + + "$unit($unit) ertrinkt in $region($region)." + "$unit($unit) drowns in in $region($region)." + + + + + + + + + "$int($amount) Personen in $unit($unit) in $region($region) ertrinken." + "$int($amount) people in $unit($unit) in $region($region) drown." + "$int($amount) people in $unit($unit) in $region($region) drown." + + + + + + + "$unit($unit) nimmt Schaden auf dem Wasser in $region($region)." + "$unit($unit) is taking damage on the water." + "$unit($unit) is taking damage on the water." + + + + + + "$unit($unit) schwenkt sein Szepter und sorgt für Verwirrung und Chaos in der Region." + + + + + + + + + "$unit($unit) stolpert bei der Erforschung der Region über $localize($location). Nähere Durchsuchung fördert ein zerfleddertes altes Buch mit dem Titel '$localize($book)' zu Tage. Der Wissensschub ist enorm." + + + + "Ein Alp hat sein Opfer gefunden und springt auf den Rücken von $unit($target)!" + + + + + + + + "$unit($unit) fühlt sich von starken magischen Energien durchströmt. ($int36($id))" + "Powerful magical energies are pulsing through $unit($unit). ($int36($id))" + + + + + + + + "$unit($unit) hat Schwierigkeiten seine magischen Energien zu sammeln. ($int36($id))" + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger sind für einen Moment benommen." + "$unit($mage) casts $spell($spell): $int($amount) fighters were momentarily stunned." + + + + + + + + "$unit($mage) besänftigt den Bauernaufstand in $region($region)." + "$unit($mage) quells the uprising in $region($region)." + + + + + + + + "$unit($mage) rief in $region($region) einen Riss in dem Gefüge der Magie hervor, der alle magische Kraft aus der Region riss." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden in Schlaf versetzt." + "$unit($mage) casts $spell($spell): $int($amount) fighters have fallen asleep." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Kriegern wurde ihre Lebenskraft entzogen." + "$unit($mage) casts $spell($spell): $int($amount) fighters had their life energy drained." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Kriegern wurden versteinert." + "$unit($mage) casts $spell($spell): $int($amount) fighters were petrified." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden in einen Blutrausch versetzt." + "$unit($mage) casts $spell($spell): $int($amount) fighters went into a mindless rage." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden eingeschüchtert." + "$unit($mage) casts $spell($spell): $int($amount) fighters were intimidated." + + + + + + + + "$unit($mage) zaubert $spell($spell), aber es gab niemanden, der beeinflusst werden konnte." + "$unit($mage) casts $spell($spell), but nobody is impressed." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden von Furcht gepackt." + "$unit($mage) casts $spell($spell): $int($amount) fighters were consumed by fear." + + + + + + + + "$unit($mage) zaubert $spell($spell): Das Kampfgetümmel erstirbt und er kann unbehelligt seines Weges ziehen." + "$unit($mage) casts $spell($spell): The noise of the battle dies down and he is able to slip away unharmed." + + + + + + + + "$unit($mage) zaubert $spell($spell): Ein Sturm kommt auf und die Schützen können kaum noch zielen." + "$unit($mage) casts $spell($spell): Strong stormwinds are blowing and the archers are having a hard time aiming." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger schleppten sich müde in den Kampf." + "$unit($mage) casts $spell($spell): $int($amount) fighters had trouble staying awake." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden moralisch gestärkt." + "$unit($mage) casts $spell($spell): $int($amount) fighters had their moral boosted." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden magisch beschleunigt." + "$unit($mage) casts $spell($spell): $int($amount) fighters were magically accelerated." + + + + + + + "$unit($mage) ruft ein fürchterliches Unwetter über seine Feinde, doch es gab niemanden mehr, den dies treffen konnte." + + + + + + + "$unit($mage) ruft ein fürchterliches Unwetter über seine Feinde, doch der magische Regen zeigt keinen Effekt." + + + + + + + "$unit($mage) ruft ein fürchterliches Unwetter über seine Feinde. Der magischen Regen lässt alles Eisen rosten." + + + + + + + + + "$unit($mage) beschwört den Alp $unit($alp) für $unit($target)." + "$unit($mage) summons the alp $unit($alp) for $unit($target)." + + + + + + + + "$unit($mage) kümmert sich um die Verletzten und heilt $int($amount) Verwundete." + "$unit($mage) sees after the wounded and heals $int($amount)." + + + + + + + + + "$unit($mage) kümmert sich um die Verletzten und benutzt ein $resource($item,1), um den Zauber zu verstärken. $int($amount) Verwundete werden geheilt." + "$unit($mage) sees after the wounded and heals $int($amount). A $resource($item,1) improves the spell." + + + + + + + + + "Mit einem Ritual bindet $unit($mage) die magischen Kräfte der Erde von $region($region) in die Mauern von $building($building)." + "$unit($mage) performs a ritual that binds the magical forces of $region($region) into the walls of $building($building)." + + + + + + + + + "$unit($mage) opfert $unit($target) $int($amount) Aura." + "$unit($mage) sacrifices $int($amount) aura for $unit($target)." + + + + + + + + "$unit($mage) beginnt ein Ritual der Wiederbelebung. $int($amount) Krieger stehen von den Toten auf." + "$unit($mage) begins a ritual of resurrection. $int($amount) warriors rise from the dead." + + + + + + + + + "$unit($mage) beginnt ein Ritual der Wiederbelebung und benutzt ein $resource($item,1), um den Zauber zu verstärken. $int($amount) Krieger stehen von den Toten auf." + "$unit($mage) begins a ritual of resurrection using a $resource($item,1). $int($amount) warriors rise from the dead." + + + + + + + "$unit($mage) öffnet ein Chaostor." + "$unit($mage) opens a chaos gate." + + + + "Ein Wirbel aus blendendem Licht erscheint." + "A vortex of blinding light appears." + + + + + + + + "$unit($mage) kann in $region($region) keine Untoten rufen." + "$unit($mage) cannot summon any undead in $region($region)." + + + + + + + + + "$unit($mage) erweckt in $region($region) $int($amount) Untote aus ihren Gräbern." + "$unit($mage) calls $int($amount) undead from their graves in $region($region)." + + + + + + + + "$unit($mage) stört in $region($region) die Ruhe der Toten." + "$unit($mage) communicates with the dead in $region($region)." + + + + + + + "$unit($unit) gelingt es, durch die Nebel auf die Realität zu blicken." + "$unit($unit) manages to catch a glimpse of reality through the fog." + + + + + + + + "$unit($mage) konnte $int($amount) $if($eq($amount,1),"Bauer","Bauern") anwerben." + "$unit($mage) managed to recruit $int($amount) $if($eq($amount,1),"peasant","peasants")." + + + + + + "Ein bohrender Schmerz durchzuckt $unit($unit), Verwirrung macht sich breit." + "Pain pulses through $unit($unit), confusion spreads." + + + + + + ""AAAAAAAGHHHHHH!" - Ein Schrei durchzieht die Region, $unit($unit) windet sich vor Schmerz." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Eine höhere Macht hindert $unit($unit) daran, das Objekt zu übergeben. 'ES IST DEINS, MEIN KIND. DEINS GANZ ALLEIN'." + + + + + + + "$unit($unit) sendet ein Stoßgebet an den Herrn der Schreie." + + + + + + + "Der Eisberg $region($region) schmilzt." + "The iceberg $region($region) melts." + "The iceberg $region($region) melts." + + + + + + "Der Gletscher von $region($region) bricht und treibt davon." + "The glacier in $region($region) breaks up and drifts away." + "The glacier in $region($region) breaks up and drifts away." + + + + + + "Der Eisberg $region($region) treibt an eine Küste." + "The iceberg $region($region) drifts onto a coast." + "The iceberg $region($region) drifts onto a coast." + + + + + + "Die $ship($ship) wird bei einer Kollision mit einem Eisberg zerstört." + "The $ship($ship) has been destroyed by a collision with an iceberg." + "The $ship($ship) has been destroyed by a collision with an iceberg." + + + + + + "Die $ship($ship) wird bei einer Kollision mit einem Eisberg beschädigt." + "The $ship($ship) has been damaged by a collision with an iceberg." + "The $ship($ship) has been damaged by a collision with an iceberg." + + + + + + + "Die $ship($ship) treibt nach $direction($dir)." + "The ship $ship($ship) drifts to the $direction($dir)." + "The ship $ship($ship) drifts to the $direction($dir)." + + + + + + + "Der Eisberg $region($region) treibt nach $direction($dir)." + "The iceberg $region($region) drifts $direction($dir)." + "The iceberg $region($region) drifts $direction($dir)." + + + + + + "Wir erklären allen $race($race,2) den heiligen Krieg." + "We declare jihad on all $race($race,2)." + + + + + + "Die Götter erhören $unit($unit)." + "The Gods have listened to $unit($unit)." + "The Gods have listened to $unit($unit)." + + + + + + + "Die Götter gewähren uns die Kraft eines $special($int($level))." + "The Gods grant us the powers of $special ($int($level))." + "The Gods grant us the powers of $special ($int($level))." + + + + + + "Die Götter gewähren uns die Kraft eines ${special}." + "The Gods grant us the powers of ${special}." + "The Gods grant us the powers of ${special}." + + + + + + + + + + "$unit($unit) verlor $int($fallen) Personen$if($alive,", $int($alive) überlebten","")$if($run," und $int($run) flohen$if($isnull($runto),""," nach $region($runto)")","")." + "$unit($unit) lost $int($fallen) people$if($alive,", $int($alive) survived","")$if($run," and $int($run) fled$if($isnull($runto),""," to $region($runto)")","")." + + + + + + + + "$unit($unit) erzielte $int($hits) Treffer und tötete $int($kills) Gegner." + "$unit($unit) hit $int($hits) times and killed $int($kills) enemies." + "$unit($unit) hit $int($hits) times and killed $int($kills) enemies." + + + + + + "$string" + "$string" + + + + + + + "Heer $int($index): $name" + "Army $int($index): $name" + + + + + + + "Verwundert blicken die Bauern von $region($region) auf ein neues Gebäude." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) gewinnt durch das Ritual $int($amount) Aura." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) receives $int($amount) aura." + + + + + + + + "$unit($mage) beschwört Naturgeister in den Boden von $region($region)." + "$unit($mage) summons natural spirits into the ground of $region($region)." + + + + + + + + + "$unit($mage) verwandelt $int($amount) aus $unit($target) in $race($race,0)." + "$unit($mage) transforms $int($amount) from $unit($target) into $race($race,0)." + + + + + + + + "$unit($mage) verwandelt $unit($target) in $race($race,0)." + "$unit($mage) tranforms $unit($target) to $race($race,0)." + + + + + + "$unit($mage) erlöst die gequälten Seelen der Toten." + "$unit($mage) redeems the tormented souls of the dead." + + + + + + "$unit($mage) verwandelt sich in einen Wyrm." + "$unit($mage) turns into a wyrm." + + + + + + + "$unit($mage) ruft Irrlichter in $region($region)." + "$unit($mage) summons wisps in $region($region)." + "$unit($mage) summons wisps in $region($region)." + + + + + + + "$unit($mage) erschafft in $region($region) eine Wand aus Feuer." + "$unit($mage) creates a wall of fire in $region($region)." + "$unit($mage) creates a wall of fire in $region($region)." + + + + + + + "$unit($mage) wiegelt in $region($region) die Bauern zum Aufstand auf." + "$unit($mage) incites a revolt among the peasants of $region($region)." + + + + + + + + + "$unit($mage) wiegelt in $region($region) $int($amount) Bauern zum Aufstand auf." + "$unit($mage) incites a revolt among $int($amount) peasants of $region($region)." + + + + + + + + "$unit($mage) sorgt in $region($region) für Trübsal unter den Bauern." + "$unit($mage) causes great sadness among the peasants of $region($region)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier erschafft ein Traumgebäude." + "$unit($unit) in $region($region): '$order($command)' - The magician creates an illusionary building." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) kann keine $race($race,1)-Gestalt annehmen." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Elementar ist zu klein, um das Gebäude zu tragen." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Elementar weigert sich, nach $direction($direction) zu gehen." + "$unit($unit) in $region($region): '$order($command)' - The elemental refuses to go $direction($direction)." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) ist von unserer Art, das Ritual wäre verschwendete Aura." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) is one of our kind, we should not waste aura on this." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) wird von uns aufgenommen." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) has become one of our kind." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) ruft Drachen nach $region($target)." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) calls dragons to $region($target)." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) erschafft $int($amount) ${object}." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) creates $int($amount) ${object}." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) creates $int($amount) ${object}." + + + + + + + + "Ein Beben erschüttert $building($building). Viele kleine Pseudopodien erheben das Gebäude und tragen es in Richtung $direction($direction)." + + + + + + + + "$unit($unit) benutzt in $region($region) ein Traumauge." + "$unit($unit) uses a dreameye in $region($region)." + + + + + + + "$unit($unit) benutzt in $region($region) einen Antimagiekristall." + "$unit($unit) uses an antimagic crystal in $region($region)." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Sphären des Chaos geben dem Magier einen Teil ihrer Kraft." + "$unit($unit) in $region($region): '$order($command)' - The sphere of chaos returns a part of his power to the magician." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier konnte keinen Fluch zerstören." + "$unit($unit) in $region($region): '$order($command)' - The magician could not destroy any magic." + + + + + + + + "In $region($region) dehnt $unit($unit) die Zeit für $int($amount) Personen." + "In $region($region), $unit($unit) bends time for $int($amount) men." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier zerstört $int($succ) Flüche auf ${target}." + "$unit($unit) in $region($region): '$order($command)' - The magician destroys $int($succ) spells on ${target}." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier zerstört den Fluch($id) auf ${target}." + "$unit($unit) in $region($region): '$order($command)' - The magician destroys the spell on ${target}." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Zauber ist nicht stark genug, um den Fluch auf ${target} zu zerstören." + "$unit($unit) in $region($region): '$order($command)' - The spell is not strong enough to destroy the curse on ${target}." + + + + + + + "$unit($mage) beschwört einen Giftelementar in $region($region)." + "$unit($mage) summons a poison elemental in $region($region)." + + + + + + + + "$unit($unit) in $region($region) wird von einem Unbekannten verflucht." + "$unit($unit) in $region($region) was cursed by an unknown magician." + + + + + + + + "$unit($mage) belegt $unit($target) mit einem Zauber." + "$unit($mage) puts a spell on $unit($target)." + + + + + + + "$unit($mage) belegt $unit($target) mit einem Kälteschutz." + "$unit($mage) puts protection from cold on $unit($target)." + + + + + + + "$unit($mage) legt einen Rosthauch auf $unit($target), doch der Rosthauch fand keine Nahrung." + "$unit($mage) puts a spell of rust on $unit($target), but it shows no effect." + + + + + + + + "$unit($mage) legt einen Rosthauch auf $unit($target). $int($amount) Waffen wurden vom Rost zerfressen." + "$unit($mage) puts a spell of rust on $unit($target). $int($amount) weapons are eaten by rust." + + + + + + + $if($isnull($mage),"Ein unentdeckter Magier",$unit($mage)) erschuf einen heiligen Hain von $int($amount) Schößlingen. + $if($isnull($mage),"An unknown magician ",$unit($mage)) created a holy forest of $int($amount) young trees. + + + + + + "$if($isnull($mage),"Ein unentdeckter Magier",$unit($mage)) segnet in einem kurzen Ritual die Felder." + "$if($isnull($mage),"an unseen magician",$unit($mage)) blesses the fields in a short ritual." + + + + + + "$unit($mage) beschwört die Mächte des Wassers und ein gigantischer Strudel bildet sich." + "$unit($mage) summons the power of the seas and a giant maelstrom forms." + + + + + + + "$unit($mage) belebt $int($amount) Bäume." + "$unit($mage) revives $int($amount) trees." + + + + + + + "$unit($mage) sorgt für trockene Straßen in $region($region)." + "$unit($mage) creates dry and well-repaired roads in $region($region)." + + + + + + + "$unit($mage) erfleht den Segen der Götter des Windes und des Wassers für $ship($ship)." + "$unit($mage) asks the gods of wind and water on behalf of the $ship($ship)." + + + + + + + + "$unit($unit) transferiert $int($aura) Aura auf $unit($target)." + "$unit($unit) transfers $int($aura) Aura to $unit($target)." + "$unit($unit) transfers $int($aura) Aura to $unit($target)." + + + + + + + + "$unit($mage) entzieht $unit($target) $int($aura) Aura." + "$unit($mage) draws $int($aura) aura from $unit($target)." + + + + + + + "$unit($unit) fühlt seine magischen Kräfte schwinden und verliert $int($aura) Aura." + "$unit($unit) feels the powers of magic fade and loses $int($aura) aura." + + + + + + "$unit($unit) fühlt sich einen Moment seltsam geschwächt." + "$unit($unit) fühlt strangely weakened." + + + + + + + "$unit($unit) konnte $unit($target) keine Aura entziehen." + "$unit($unit) could not draw aura from $unit($target)." + + + + + + + + "$unit($unit) wurde von $region($source) nach $unit($target) teleportiert." + "$unit($unit) was teleported from $region($source) to $unit($target)." + + + + + + + + + "$unit($mage) fand heraus, dass auf $ship($ship) der Zauber $curse($curse) liegt, der noch etwa $int($months) Wochen bestehen bleibt." + "$unit($mage) discovers that $ship($ship) is charmed with $curse($curse), which will last for, about $int($months) more weeks." + + + + + + + + + "$unit($mage) fand heraus, dass auf $building($building) der Zauber $curse($curse) liegt, der noch etwa $int($months) Wochen bestehen bleibt." + "$unit($mage) discovers that $building($building) is charmed with $curse($curse), which will last for, about $int($months) more weeks." + + + + + + + + + "$unit($mage) fand heraus, dass auf $unit($unit) der Zauber $curse($curse) liegt, der noch etwa $int($months) Wochen bestehen bleibt." + "$unit($mage) discovers that $unit($unit) is charmed with $curse($curse) that will last for about $int($months) more weeks." + + + + + + + + + "$unit($mage) fand heraus, dass auf $region($region) der Zauber $curse($curse) liegt, der noch etwa $int($months) Wochen bestehen bleibt." + "$unit($mage) discovers that $region($region) is charmed with $curse($curse), which will last for, about $int($months) more weeks." + + + + + + + + "$unit($mage) fand heraus, dass auf $ship($ship) der Zauber $curse($curse) liegt, dessen Kraft ausreicht, um noch Jahrhunderte bestehen zu bleiben." + "$unit($mage) discovers that $ship($ship) is charmed with $curse($curse), which will last for centuries." + + + + + + + + "$unit($mage) fand heraus, dass auf $building($building) der Zauber $curse($curse) liegt, dessen Kraft ausreicht, um noch Jahrhunderte bestehen zu bleiben." + "$unit($mage) discovers that $building($building) is charmed with $curse($curse), which will last for centuries." + + + + + + + + "$unit($mage) fand heraus, dass auf $unit($unit) der Zauber $curse($curse) liegt, dessen Kraft ausreicht, um noch Jahrhunderte bestehen zu bleiben." + "$unit($mage) discovers that $unit($unit) is charmed with $curse($curse), which will last for centuries." + + + + + + + + "$unit($mage) fand heraus, dass auf $region($region) der Zauber $curse($curse) liegt, dessen Kraft ausreicht, um noch Jahrhunderte bestehen zu bleiben." + "$unit($mage) discovers that $region($region) is charmed with $curse($curse), which will last for centuries." + + + + + + + "$unit($mage) meint, dass auf $ship($ship) ein Zauber liegt, konnte aber über den Zauber nichts herausfinden." + "It appears to $unit($mage) that $ship($ship) is charmed, but no details have been revealed." + "It appears to $unit($mage) that $ship($ship) is charmed, but no details have been revealed." + + + + + + + "$unit($mage) meint, dass auf $building($building) ein Zauber liegt, konnte aber über den Zauber nichts herausfinden." + "It appears to $unit($mage) that $building($building) is charmed, but no details have been revealed." + "It appears to $unit($mage) that $building($building) is charmed, but no details have been revealed." + + + + + + + "$unit($mage) meint, dass $unit($unit) verzaubert ist, konnte aber über den Zauber nichts herausfinden." + "It appears to $unit($mage) that $unit($unit) is charmed, but no details have been revealed." + "It appears to $unit($mage) that $unit($unit) is charmed, but no details have been revealed." + + + + + + + "$unit($mage) meint, dass auf $region($region) ein Zauber liegt, konnte aber über den Zauber nichts herausfinden." + "It appears to $unit($mage) that $region($region) is charmed, but no details have been revealed." + "It appears to $unit($mage) that $region($region) is charmed, but no details have been revealed." + + + + + + + "$unit($mage) meint, dass auf $ship($ship) kein Zauber liegt." + "It appears to $unit($mage) that $ship($ship) is not charmed." + "It appears to $unit($mage) that $ship($ship) is not charmed." + + + + + + + "$unit($mage) meint, dass auf $building($building) kein Zauber liegt." + "It appears to $unit($mage) that $building($building) is not charmed." + "It appears to $unit($mage) that $building($building) is not charmed." + + + + + + + "$unit($mage) meint, dass auf $unit($target) kein Zauber liegt." + "It appears to $unit($mage) that $unit($target) is not charmed." + "It appears to $unit($mage) that $unit($target) is not charmed." + + + + + + + "$unit($mage) meint, dass auf $region($region) kein Zauber liegt." + "It appears to $unit($mage) that $region($region) is not charmed." + "It appears to $unit($mage) that $region($region) is not charmed." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Region konnte nicht verzaubert werden." + "$unit($unit) in $region($region): '$order($command)' - The region could not be charmed." + "$unit($unit) in $region($region): '$order($command)' - The region could not be charmed." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $ship($ship) widersteht dem Zauber." + "$unit($unit) in $region($region): '$order($command)' - $ship($ship) resists the spell." + "$unit($unit) in $region($region): '$order($command)' - $ship($ship) resists the spell." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Gebäude $int36($id) konnte nicht verzaubert werden." + "$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be charmed." + "$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be charmed." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) widersteht dem Zauber." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) resists the spell." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) resists the spell." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Schiff $int36($id) wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - Ship $int36($id) could not be located." + "$unit($unit) in $region($region): '$order($command)' - Ship $int36($id) could not be located." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Gebäude $int36($id) wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be located." + "$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be located." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Einheit $id wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - Unit $id could not be located." + "$unit($unit) in $region($region): '$order($command)' - Unit $id could not be located." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es wurde kein Ziel gefunden." + "$unit($unit) in $region($region): '$order($command)' - The spell could not find a target." + + + + + + + "$unit($mage) erleidet durch den Tod seines Vertrauten einen Schock." + "$unit($mage) receives a shock when his familiar dies." + + + + + + + + "$unit($unit) schafft es nicht, genug Kraft aufzubringen, um $spell($spell) auf Stufe $int($level) zu zaubern." + "$unit($unit) cannot muster enough energy to cast $spell($spell) on level $level($level)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Für diesen Zauber fehlen noch $resources($list)." + "$unit($unit) in $region($region): '$order($command)' - Casting this spell requires an additional $resources($list)." + + + + + + + + "$unit($unit) hat nicht genügend Komponenten um $spell($spell) auf Stufe $int($level) zu zaubern." + "$unit($unit) has insufficient components to cast $spell($spell) on level $int($level)." + + + + + + + + "$unit($unit) unterläuft in $region($region) beim Zaubern von $spell($spell) ein Patzer." + "$unit($unit) fumbles while casting $spell($spell) in $region($region)." + + + + + + + + "Als $unit($unit) in $region($region) versucht, $spell($spell) zu zaubern, scheint plötzlich ein Beben durch die magische Essenz zu laufen und ein furchtbarer Sog versucht $unit($unit) in eine andere Dimension zu ziehen. Mit letzter Kraft gelingt es $unit($unit) sich zu retten." + "When $unit($unit) in $region($region) tries to cast $spell($spell), a sudden disturbance ripples through the magical realm and a terrible force attempts to drag the magician to another dimension. However, with a final effort of strength, $unit($unit) manages to save himself." + + + + + + + + "Als $unit($unit) in $region($region) versucht, $spell($spell) zu zaubern erhebt sich plötzlich ein dunkler Wind. Bizarre geisterhafte Gestalten kreisen um den Magier und scheinen sich von den magischen Energien des Zaubers zu ernähren. Mit letzter Kraft gelingt es $unit($unit) dennoch den Spruch zu zaubern." + "When $unit($unit) in $region($region) tries to cast $spell($spell), strong winds suddenly rise. Bizare ghostlike creatures circle around the magician and seem to be leeching his magical energy. However, with a final effort of strength, $unit($unit) manages to complete the spell." + + + + + + + + "Eine Botschaft von $unit.dative($unit) in $region($region): 'Ups! Quack, Quack!'" + "A message from $unit($unit) in $region($region): 'Oops! Croak, Croak!'" + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($mage) kann Zauber, die durch $unit($unit) gewirkt werden, nicht zusätzlich in die Ferne richten." + "$unit($unit) in $region($region): '$order($command)' - $unit($mage) cannot direct spells that are channeled through $unit($unit) into distant regions." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($mage) kann nicht genug Energie aufbringen, um diesen Spruch durch $unit($unit) zu wirken." + "$unit($unit) in $region($region): '$order($command)' - $unit($mage) cannot raise enough energy to channel the spell through $unit($unit)." + + + + + + + + "$unit($mage) ruft einen Vertrauten. $race($race, 0) können $skills lernen." + "$unit($mage) summons a familiar. $race($race, 0) can learn ${skills}." + + + + + + + + "$unit($unit) hat einen feuchtfröhlichen Abend in der Taverne verbracht. Ausser einem fürchterlichen Brummschädel ist da auch noch das dumme Gefühl $unit($mage) seine ganze Lebensgeschichte erzählt zu haben." + + + + + + + "$unit($unit) hat einen feuchtfröhlichen Abend in der + Taverne verbracht. Ausser einem fürchterlichen Brummschädel ist da auch + noch das dumme Gefühl die ganze Taverne mit seiner Lebensgeschichte + unterhalten zu haben." + + + + + + + + + "$unit($mage) gelingt es $unit($unit) zu verzaubern. $unit($unit) wird für etwa $int($duration) Wochen unseren Befehlen gehorchen." + + + + + + + + + "$unit($unit) gelingt es $spell($spell) zu zaubern, doch der Spruch zeigt keine Wirkung." + "$unit($unit) manages to cast $spell($spell), but the spell seems to have no effect." + + + + + + + + "$unit($unit) fühlt sich nach dem Zaubern von $spell($spell) viel erschöpfter als sonst und hat das Gefühl, dass alle weiteren Zauber deutlich mehr Kraft als normalerweise kosten werden." + "$unit($unit) feels far more exhausted than he should after casting $spell($spell) and assumes that any following spells will cost far more energy than usual." + + + + + + + "$unit($unit) in $region($region) hat rasende Kopfschmerzen und kann sich nicht mehr richtig konzentrieren. Irgendwas bei diesem Zauber ist fürchterlich schiefgelaufen." + "$unit($unit) in $region($region) is hit by a massive headacheand cannot concentrate on the spell. Some part of this ritual has gone very wrong indeed." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier verfängt sich in seinem eigenen Zauber." + + + "In der Region erstrahlen des Nachts bunte Lichter, Gloeckchen klingeln und frohes Kindergelaechter klingt durch den Wald." + "At night, colourful lights can be seen in this region, bells are a-ringing and the laughter of happy children seems to be everywhere in the forests." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Zauber von $unit.dative($unit) war viel zu schwach und löst sich gleich wieder auf." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) verzaubert ${target}." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) puts a spell on ${target}." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) gelingt es zwar die Region zu verzaubern, aber irgendwas ging schief." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) manages to put a spell on the region, but something went wrong nonetheless." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) gelingt es die Region zu verzaubern." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) puts a spell on the region." + + + + + + + "$unit($mage) erhöht die Körperkraft von $unit.dative($target) beträchtlich." + "$unit($mage) increases the strength of $unit($target) dramatically." + + + + + + + + "$unit($unit) in $region($region) regeneriert $int($amount) Aura." + "$unit($unit) régénère $int($amount) aura en $region($region)." + "$unit($unit) regenerates $int($amount) aura in $region($region)." + + + + + + "$string" + "$string" + + + + + + + + + "$unit($unit) in $region($region) verbraucht $int($cost) Silber für das Studium von $skill($skill)." + "$unit($unit) dépense $int($cost) écus en $region($region) pour apprendre $skill($skill)." + "$unit($unit) spends $int($cost) silver in $region($region) to study $skill($skill)." + + + + + + + "$unit($teacher) kann durch Dumpfbackenbrot nur $int($amount) Schüler lehren." + "Due to the effect of duncebuns, $unit($teacher) can only teach $int($amount) students." + + + + + + + + + "$unit($teacher) lehrt $unit($student) $skill($skill) auf Stufe $int($level)." + "$unit($teacher) teaches $unit($student) $skill($skill) to level $int($level)." + "$unit($teacher) teaches $unit($student) $skill($skill) to level $int($level)." + + + + + + + + "$unit($teacher) lehrt $unit($student) $skill($skill)." + "$unit($teacher) teaches $unit($student) $skill($skill)." + "$unit($teacher) teaches $unit($student) $skill($skill)." + + + + + + "$string" + "$string" + + + + + + + + "$unit($unit) verkauft $int($amount) $resource($resource,$amount)." + "$unit($unit) sells $int($amount) $resource($resource,$amount)." + "$unit($unit) sells $int($amount) $resource($resource,$amount)." + + + + + + + + "$unit($unit) kauft $int($amount) $resource($resource,$amount)." + "$unit($unit) buys $int($amount) $resource($resource,$amount)." + "$unit($unit) buys $int($amount) $resource($resource,$amount)." + + + + + + + "$unit($unit) bezahlt $int($money) Silber für den Kauf von Luxusgütern." + "$unit($unit) pays $int($money) silver for luxury items." + "$unit($unit) pays $int($money) silver for luxury items." + + + + + + + + "$unit($unit) verdient in $region($region) $int($amount) Silber durch den Verkauf von Luxusgütern." + "$unit($unit) earned $int($amount) silver in $region($region) by selling luxury items." + "$unit($unit) earned $int($amount) silver in $region($region) by selling luxury items." + + + + + + + + + "$unit($unit) arbeitet in $region($region) für einen Lohn von $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber." + "$unit($unit) works in $region($region) for a wage of $int($amount) $if($eq($wanted,$amount),""," out of $int($wanted)") silver." + "$unit($unit) works in $region($region) for a wage of $int($amount) $if($eq($wanted,$amount),""," out of $int($wanted)") silver." + + + + + + + + "$unit($unit) arbeitet in $region($region) für einen Lohn von $int($amount) Silber." + "In $region($region), $unit($unit) works for a wage of $int($amount) silver." + + + + + + + + + "$unit($unit) verdient in $region($region) $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber durch Unterhaltung." + "In $region($region), $unit($unit) earns only $int($amount) instead of$if($eq($wanted,$amount),""," of$if($eq($wanted,$amount),""," of $int($wanted)") ") with entertainment." + + + + + + + + "$unit($unit) fängt in $region($region) Fische im Wert von $int($amount) Silber." + "In $region($region), $unit($unit) catches fish worth $int($amount) silver." + + + + + + + + "$unit($unit) verdient in $region($region) $int($amount) Silber durch Unterhaltung." + "$unit($unit) earns $int($amount) in $region($region) with entertainment." + "$unit($unit) earns $int($amount) in $region($region) with entertainment." + + + + + + + + + "$unit($unit) verdient in $region($region) $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber durch Zauberei." + + + + + + + + "$unit($unit) verdient in $region($region) $int($amount) Silber durch Zauberei." + "$unit($unit) earns $int($amount) silver through simple magical services in $region($region)." + + + + + + + + + "$unit($unit) klaut in $region($region) $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber." + "$unit($unit) steals only $int($amount) silver instead of$if($eq($wanted,$amount),""," of$if($eq($wanted,$amount),""," of $int($wanted)") ") in $region($region)." + "$unit($unit) steals only $int($amount) silver instead of$if($eq($wanted,$amount),""," of$if($eq($wanted,$amount),""," of $int($wanted)") ") in $region($region)." + + + + + + + + "$unit($unit) klaut in $region($region) $int($amount) Silber." + "$unit($unit) steals $int($amount) silver in $region($region)." + + + + + + + + + "$unit($unit) treibt in $region($region) Steuern in Höhe von $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber ein." + "$unit($unit) collects taxes of only $int($amount) instead of$if($eq($wanted,$amount),""," of$if($eq($wanted,$amount),""," of $int($wanted)") ") silver in $region($region)." + + + + + + + + "$unit($unit) treibt in $region($region) Steuern in Höhe von $int($amount) Silber ein." + "$unit($unit) collects taxes of $int($amount) silver in $region($region)." + + + + + + + + + + "$unit($unit) verdient$if($eq($mode,4)," am Handel","") in $region($region) $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber$if($eq($mode,1)," durch Unterhaltung",$if($eq($mode,2)," durch Steuern",$if($eq($mode,3)," durch Handel",$if($eq($mode,5)," durch Diebstahl",$if($eq($mode,6)," durch Zauberei","")))))." + "$unit($unit) earns $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") in $region($region)." + "$unit($unit) earns $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") in $region($region)." + + + + + + + + + "$unit($unit) in $region($region) findet $int($amount) $resource($herb,$amount)." + "$unit($unit) in $region($region) finds $int($amount) $resource($herb,$amount)." + "$unit($unit) in $region($region) finds $int($amount) $resource($herb,$amount)." + + + + + + + "$unit($unit) züchtet $int($amount) Pferde." + "$unit($unit) breeds $int($amount) horses." + "$unit($unit) breeds $int($amount) horses." + + + + + + + + + "$unit($unit) pflanzt in $region($region) $int($amount) $resource($herb,$amount)." + "$unit($unit) plants $int($amount) $resource($herb,$amount) in $region($region)." + "$unit($unit) plants $int($amount) $resource($herb,$amount) in $region($region)." + + + + + + + "$unit($unit) in $region($region) entdeckt eine Laenader." + "$unit($unit) discovers laen in $region($region)." + + + + + + "Die Laenader in $region($region) ist erschöpft." + "There is no more laen in $region($region)." + + + + + + + + "$unit($unit) in $region($region) hat ein zu niedriges Talent, um $resource($resource,0) abzubauen." + "$unit($unit) in $region($region) is not proficient enough to produce $resource($resource,0)." + "$unit($unit) in $region($region) is not proficient enough to produce $resource($resource,0)." + + + + + + + + + + "$unit($unit) in $region($region) produziert $int($amount)$if($eq($wanted,$amount),""," von $int($wanted)") $resource($resource,$wanted)." + "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." + "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." + + + + + + + + + + "$unit($unit) in $region($region) produziert $int($amount)$if($eq($wanted,$amount),""," von $int($wanted)") $resource($resource,$wanted)." + "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." + "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." + + + + + + + + "$unit($unit) baut für $int($size) an $building($building) weiter." + "$unit($unit) builds $int($size) more on $building($building)." + "$unit($unit) builds $int($size) more on $building($building)." + + + + + + + + "$unit($unit) baut für $int($size) an $ship($ship) weiter." + "$unit($unit) builds $int($size) more on $ship($ship)." + "$unit($unit) builds $int($size) more on $ship($ship)." + + + + + + "$string" + "$string" + + + + + + + "$unit($unit) stirbt beim Versuch, die Feuerwand nach $region($region) zu durchqueren." + "$unit($unit) dies trying to cross the wall of fire into $region($region)." + "$unit($unit) dies trying to cross the wall of fire into $region($region)." + + + + + + + "$unit($unit) erleidet beim Durchqueren der Feuerwand nach $region($region) schwere Verbrennungen." + "$unit($unit) steps through the wall of fire into $region($region) and receives severe burn damage." + "$unit($unit) steps through the wall of fire into $region($region) and receives severe burn damage." + + + + + + + + + "$unit($unit) transportiert $unit($target) von $region($start) nach $region($end)." + "$unit($unit) transported $unit($target) from $region($start) to $region($end)." + "$unit($unit) transported $unit($target) from $region($start) to $region($end)." + + + + + + + + + + "$unit($unit) $if($eq($mode,1),"reitet", "wandert") von $region($start) nach $region($end).$if($isnull($regions),""," Dabei wurde $trail($regions) durchquert.")" + "$unit($unit) $if($eq($mode,1),"chevauche", "marche") de $region($start) vers $region($end) trans $trail($regions)" + "$unit($unit) $if($eq($mode,1),"rides", "walks") from $region($start) to $region($end)$if($isnull($regions),""," by way of $trail($regions)")." + + + + + + + "$unit($unit) entdeckt dass im $direction($direction) $terrain($region) ist." + "$unit($unit) discovered that an ocean lies in the $direction($direction)." + "$unit($unit) discovered that an ocean lies in the $direction($direction)." + + + + + + + "$unit($unit) entdeckt, dass $region($region) $terrain($region) ist." + "$unit($unit) discovered that $region($region) is $terrain($region)." + "$unit($unit) discovered that $region($region) is $terrain($region)." + + + + + + + "$unit($unit) ist in dieser Runde gelandet und kann nicht weiter ins Landesinnere nach $region($region) vorstossen." + "$unit($unit) has just landed and cannot continue moving to $region($region)." + "$unit($unit) has just landed and cannot continue moving to $region($region)." + + + + + + "Die Mannschaft der $ship($ship) kann in letzter Sekunde verhindern, dass das Schiff auf Land aufläuft." + "In the very last moment, the crew of the $ship($ship) saved the ship from grounding." + "In the very last moment, the crew of the $ship($ship) saved the ship from grounding." + + + + + + + "Die $ship($ship) konnte in $region($region) nicht einreisen, die Küste ist zu gefährlich für das Schiff." + "The $ship($ship) could not berth in $region($region). The coast is too dangerous for the vessel." + "The $ship($ship) could not berth in $region($region). The coast is too dangerous for the vessel." + + + + + + + "Die Mannschaft der $ship($ship) weigert sich, nach $direction($direction) zu reisen." + " The crew of the $ship($ship) refuses to travel to the$direction($direction)." + " The crew of the $ship($ship) refuses to travel to the$direction($direction)." + + + + + + + "Die Mannschaft der $ship($ship) weigert sich, nach $region($region) zu reisen." + "The crew of the $ship($ship) refuses to travel to $region($region)." + "The crew of the $ship($ship) refuses to travel to $region($region)." + + + + + + + "$unit($unit) weigert sich, nach $direction($direction) zu reisen." + "$unit($unit) refuses to travel to the$direction($direction)." + "$unit($unit) refuses to travel to the$direction($direction)." + + + + + + + "$unit($unit) weigert sich, nach $region($region) zu reisen." + "$unit($unit) refuses to travel to $region($region)." + "$unit($unit) refuses to travel to $region($region)." + + + + + + + "Die $ship($ship) konnte $region($region) nicht verlassen." + "The $ship($ship) could not leave $region($region)." + "The $ship($ship) could not leave $region($region)." + + + + + + + + "$unit($unit) wurde in $region($region) von $unit.dative($guard) aufgehalten." + "$unit($unit) was kept in $region($region) by $unit($guard)." + "$unit($unit) was kept in $region($region) by $unit($guard)." + + + + + + "Wir haben den Krieg mit $faction($faction) beendet." + "We declared peace with $faction($faction)." + "We declared peace with $faction($faction)." + + + + + + "$faction($faction) hat den Krieg mit uns beendet." + "$faction($faction) has declared peace with us." + "$faction($faction) has declared peace with us." + + + + + + "Wir haben $faction($faction) den Krieg erklärt." + "We declared war on $faction($faction)." + "We declared war on $faction($faction)." + + + + + + "$faction($faction) hat uns den Krieg erklärt." + "$faction($faction) has declared war on us." + "$faction($faction) has declared war on us." + + + + + + + + "$unit($unit) konnte nicht von $region($region) nach $region($target) reisen, da der Besitzer der Region es verhinderte." + "$unit($unit) could not travel from $region($region) to $region($target) because the owner denied entrance." + + + + + + + "$unit($unit) konnte aus $region($region) nicht ausreisen." + "$unit($unit) could not leave $region($region)." + "$unit($unit) could not leave $region($region)." + + + + + + + "$unit($follower) ist $unit($unit) gefolgt." + "$unit($follower) followed $unit($unit)." + "$unit($follower) followed $unit($unit)." + + + + + + + "$unit($follower) konnte $unit($unit) nicht folgen." + "$unit($follower) could not follow $unit($unit)." + "$unit($follower) could not follow $unit($unit)." + + + + + + + "$unit($unit) entdeckt, dass es keinen Weg nach $direction($direction) gibt." + "$unit($unit) discovers that there is no route going $direction($direction)." + "$unit($unit) discovers that there is no route going $direction($direction)." + + + + + + + + "$unit($unit) konnte von $region($region) nicht nach $direction($direction) ausreisen, der Nebel war zu dicht." + "$unit($unit) could not travel $direction($direction) from $region($region), the fog was too dense." + + + + + + "$string" + "$string" + + + + + + "In $region($region) erschienen die Herren der Bäume." + "In $region($region), the lords of the trees have risen." + "In $region($region), the lords of the trees have risen." + + + + + + "In $region($region) erhoben sich die Toten aus den Gräbern." + "The dead rise from their graves in $region($region)." + + + + + + + + "$unit($unit) vermehrt sich um $int($amount) $race($race,$amount)." + "$unit($unit) breeds $int($amount) new $race($race,$amount)." + "$unit($unit) breeds $int($amount) new $race($race,$amount)." + + + + + "Die Partei bekommt einen Spitznamen." + "Your faction received a nickname." + + + + + + + "Die Partei bekommt von $unit.dative($unit) in $region($region) einen Spitznamen." + "Your faction received a nickname from $unit($unit)." + + + + + + + "$building($building) in $region($region) bekommt einen Spitznamen." + "$building($building) in $region($region) received a nickname." + + + + + + + + "$building($building) in $region($region) bekommt von $unit.dative($renamer) einen Spitznamen." + "$building($building) in $region($region) received a nickname from $unit($renamer)." + + + + + + + "Die $ship($ship) in $region($region) bekommt einen Spitznamen." + "$ship($ship) in $region($region) received a nickname." + + + + + + + + "Die $ship($ship) in $region($region) bekommt von $unit.dative($renamer) einen Spitznamen." + "$ship($ship) in $region($region) received a nickname from $unit($renamer)." + + + + + + + "$unit($renamed) in $region($region) bekommt einen Spitznamen." + "$unit($renamed) in $region($region) received a nickname." + + + + + + + + "$unit($renamed) in $region($region) bekommt von $unit.dative($renamer) einen Spitznamen." + "$unit($renamed) in $region($region) received a nickname from $unit($renamer)." + + + + + + "$if($eq($dead,1),"Ein Bauer","$int($dead) Bauern") verhungert." + "$if($eq($dead,1),"One peasant starves","$int($dead) peasants starve")." + "$if($eq($dead,1),"One peasant starves","$int($dead) peasants starve")." + + + + + + "Der Vulkan in $region($region) bricht aus." + "The volcano in $region($region) breaks out." + "The volcano in $region($region) breaks out." + + + + + + + "Der Vulkan in $region($regionv) bricht aus. Die Lavamassen verwüsten $region($regionn)." + "The volcano in $region($regionv) breaks out. The lava devastates $region($regionn)." + "The volcano in $region($regionv) breaks out. The lava devastates $region($regionn)." + + + + + + + + "Beim Vulkanausbruch in $region($region) sterben $int($dead) Personen in $unit($unit)." + "$int($dead) people in $unit($unit) perisch when the volcano in $region($region) breaks out." + "$int($dead) people in $unit($unit) perisch when the volcano in $region($region) breaks out." + + + + + + "Aus dem Vulkankrater von $region($region) steigt kein Rauch mehr." + "The volcano of $region($region) stops releasing smoke." + "The volcano of $region($region) stops releasing smoke." + + + + + + "Aus dem Vulkankrater von $region($region) steigt plötzlich Rauch." + "Columns of smoke are released by the volcano of $region($region)." + "Columns of smoke are released by the volcano of $region($region)." + + + + + + + "$unit($unit) in $region($region) desertiert." + "$unit($unit) in $region($region) abandons your cause." + "$unit($unit) in $region($region) abandons your cause." + + + + + + + + "$unit($unit) reißt die Straße zwischen $region($from) und $region($to) ein." + "$unit($unit) demolishes the road between $region($from) and $region($to)." + "$unit($unit) demolishes the road between $region($from) and $region($to)." + + + + + + + "$unit($unit) in $region($region) kann keine Kräuter finden." + "$unit($unit) could not find any herbs in $region($region)." + "$unit($unit) could not find any herbs in $region($region)." + + + + + + + + + "$unit($unit) in $region($region) stellt fest, dass es hier $localize($amount) $resource($herb,0) gibt." + "$unit($unit) discovers that $localize($amount) $resource($herb,0) grow in $region($region)." + + + + + + + "$unit($unit) reißt einen Teil von $building($building) ein." + "$unit($unit) tears down parts of $building($building)." + + + + + + + "$unit($unit) zerstört $building($building)." + "$unit($unit) destroys $building($building)." + "$unit($unit) destroys $building($building)." + + + + + + + + "$unit($unit) erweitert in $region($region) das Straßennetz um $int($size)." + "$unit($unit) extends the road network in $region($region) by $int($size)." + "$unit($unit) extends the road network in $region($region) by $int($size)." + + + + + + + + "$unit($unit) $if($eq($amount,1),"schließt","schließen") sich $int($amount) $resource($rtype,$amount) an." + "$int($amount) $resource($rtype,$amount) $if($eq($amount,1),"joins","join") $unit($unit)." + + + + + + + "$unit($mage) legt einen Schleier um die Ausrüstung von $unit.dative($target)." + "$unit($mage) shrouds the equipment of $unit($target) in shadows." + + + + + + + + "Die $ship($ship) in $region($region) entdeckt ein Opfer im $direction($dir)." + "The $ship($ship) in $region($region) made $direction($dir) a target." + "The $ship($ship) in $region($region) made $direction($dir) a target." + + + + + + + "Die $ship($ship) in $region($region) kann keine Schiffe aufbringen." + "The $ship($ship) could not capture other ships in $region($region)." + "The $ship($ship) could not capture other ships in $region($region)." + + + + + + "Langsam kehren andere Völker nach $region($region) zurück." + "Little by little, people return to $region($region)." + "Little by little, people return to $region($region)." + + + + + + "Vor den vielen Orks in $region($region) fliehen die anderen Einwohner." + "People $region($region) flee from an Orc superiority." + "People $region($region) flee from an Orc superiority." + + + + + + + + "$unit($unit) in $region($region) beschädigt die $ship($ship)." + "$unit($unit) in $region($region) damages the $ship($ship)." + + + + + + + + "$unit($unit) in $region($region) versenkt die $ship($ship)." + "$unit($unit) sunk $ship($ship) in $region($region)." + "$unit($unit) sunk $ship($ship) in $region($region)." + + + + + + "$unit($unit) marschiert in eine Antimagiezone und löst sich auf." + "$unit($unit) walks into an antimagical zone and dissolves." + + + + + + "$unit($unit) hat sich unbemerkt verflüchtigt." + "$unit($unit) has dissolved without a trace." + "$unit($unit) has dissolved without a trace." + + + + + + "$unit($unit) wird sich bald verflüchtigen." + "$unit($unit) will dissolve soon." + "$unit($unit) will dissolve soon." + + + + + + + "$int($amount) Bauern flohen aus Furcht vor $unit($unit)." + "$int($amount) peasants fled in fear of $unit($unit)." + "$int($amount) peasants fled in fear of $unit($unit)." + + + + + + + + "$int($amount) Bauern werden zu $race($race,0) und schliessen sich $unit($unit) an." + "$int($amount) peasants become $race($race,0) and join the ranks of $unit($unit)." + + + + + + + "$unit($unit) verspeiste $int($amount) Pferde." + "$unit($unit) ate $int($amount) horses." + + + + + + + "$unit($unit) verspeiste $int($amount) Bauern." + "$unit($unit) ate $int($amount) peasants." + "$unit($unit) ate $int($amount) peasants." + + + + + + + "ERESSEA $int36($faction) \"${password}\" - Deine Befehle hatten ein falsches Passwort." + "ERESSEA $int36($faction) \"${password}\" - Your orders had the wrong password." + + + + + + "Das Passwort für diese Partei lautet ${value}." + "Le mot de passe de cette faction est '${value}'" + "The password of this faction is '$value'." + + + + + + "Die Reportadresse wurde nicht geändert, '${value}' ist keine gültige email." + " Address not changed, '$value' is an invalid email." + " Address not changed, '$value' is an invalid email." + + + + + + "Die Reportadresse wurde auf ${value} geändert." + " Address has been changed to '$value'." + " Address has been changed to '$value'." + + + + + + "Das Banner wurde auf '$value' geändert." + "Banner has been changed to '$value'." + "Banner has been changed to '$value'." + + + + + + + + + "Eine Partei muß mindestens $int($turns) Wochen alt sein, bevor sie angegriffen oder bestohlen werden kann." + "A faction must be at least $int($turns) weeks old before it can be attacked or stolen from." + + + + + + + + "$unit($unit) wurden in $region($region) $int($amount) Silberstücke geklaut." + "In $region($region), thieves stole $int($amount) silver from $unit($unit)." + "In $region($region), thieves stole $int($amount) silver from $unit($unit)." + + + + + + + "$unit($target) ertappte $unit($unit) beim versuchten Diebstahl." + "$unit($target) caught $unit($unit) in attempted theft." + "$unit($target) caught $unit($unit) in attempted theft." + + + + + + + "$unit($unit) wurde von $unit.dative($target) beim versuchten Diebstahl ertappt." + "$unit($unit) was caught by $unit($target) in attempted theft." + "$unit($unit) was caught by $unit($target) in attempted theft." + + + + + + "$unit($unit) fühlt sich beobachtet." + "$unit($unit) feels watched." + "$unit($unit) feels watched." + + + + + + + "$unit($unit) gelang es nicht, sich nahe genug an $unit($target) heranzuschleichen." + "$unit($unit) could not sneak close enough to $unit($target)." + "$unit($unit) could not sneak close enough to $unit($target)." + + + + + + + "$unit($spy) gelang es nicht, etwas über $unit($target) herauszufinden." + "$unit($spy) could not find out anything about $unit($target)." + "$unit($spy) could not find out anything about $unit($target)." + + + + + + + + "$unit($spy) gelang es, Informationen über $unit($target) ($status) herauszubekommen." + "$unit($spy) managed to gather information about $unit($target)." + + + + + + + "$unit($target) ist ein $type-Magier." + "$unit($target) is a $type-magician" + + + + + + + "$unit($target) beherrscht ${skills}." + "$unit($target) has the skills ${skills}." + + + + + + + "Im Gepäck von $unit($target) sind $resources($items)." + "$unit($target) carries $resources($items)" + + + + + + + "$unit($target) gehört der Partei $faction($faction) an." + "$unit($target) belongs to $faction($faction)." + + + + + + + "$unit($target) fühlt sich $if($isnull($spy),"","durch $unit($spy) ")beobachtet." + "$unit($target) feels watched by $unit($spy)." + "$unit($target) feels watched by $unit($spy)." + + + + + + + + "$faction($from) gibt ein Almosen von $int($amount) Silber an $faction($to)." + "$faction($from) donates $int($amount) silver to $faction($to)." + "$faction($from) donates $int($amount) silver to $faction($to)." + + + + + + + + "$unit($unit) vergißt durch Dumpfbackenbrot $int($weeks) Wochen des Talentes $skill($skill)." + "$unit($unit) eats a Dumpfbackenbrot and forgets $int($weeks) weeks worth of $skill($skill)." + "$unit($unit) eats a Dumpfbackenbrot and forgets $int($weeks) weeks worth of $skill($skill)." + + + + + + + "$unit($unit) in $region($region) wird durch unzureichende Nahrung geschwächt." + "$unit($unit) is weakened due to malnourishment." + "$unit($unit) is weakened due to malnourishment." + + + + + + + + + "$unit($unit) verliert in $region($region) $int($dead) von $int($add($live,$dead)) Personen durch Unterernährung." + "$unit($unit) loses $int($dead) of $int($add($live,$dead)) people due to starvation in $region($region)." + "$unit($unit) loses $int($dead) of $int($add($live,$dead)) people due to starvation in $region($region)." + + + + + + + + "$unit($unit): '$order($command)' - Die Einheit benutzt bereits $resource($using,0)." + "$unit($unit): '$order($command)' - The unit already uses $resource($using,0)." + "$unit($unit): '$order($command)' - The unit already uses $resource($using,0)." + + + + + + "Die $ship($ship) ist zu stark beschädigt und sinkt." + "The $ship($ship) suffers too heavy damage and sinks." + "The $ship($ship) suffers too heavy damage and sinks." + + + + + + + "Die $ship($ship) entdeckt, dass $region($region) Festland ist." + "The $ship($ship) discovers that $region($region) has no shore." + + + + + + + + "Die $ship($ship) fliegt von $region($from) nach $region($to)." + "The $ship($ship) flies from $region($from) to $region($to)." + + + + + + + + "Die $ship($ship) segelt von $region($from) nach $region($to)." + "The $ship($ship) sails from $region($from) to $region($to)." + + + + + + + + "Die $ship($ship) wird in $region($region) von Stürmen abgetrieben$if($sink," und sinkt","")." + "The $ship($ship) in $region($region) drifts in heavy storm$if($sink," and sinks","")." + "The $ship($ship) in $region($region) drifts in heavy storm$if($sink," and sinks","")." + + + + + + + + + "Die $ship($ship) fährt in den Mahlstrom von $region($region) und nimmt $int($damage) Schaden$if($sink," und sinkt","")." + "The $ship($ship) sails into the maelstrom of $region($region) and takes $int($damage) damage$if($sink,". The ship sinks","")." + + + + + + + "$unit($unit) vergißt $skill($skill)." + "$unit($unit) forgets $skill($skill)." + "$unit($unit) forgets $skill($skill)." + + + + + + + "$unit($unit) gibt das Kommando an $unit($recipient)." + "$unit($unit) gave control to $unit($recipient)." + "$unit($unit) gave control to $unit($recipient)." + + + + + + + + "$unit($unit) gibt $int($amount) Dumpfbackenbrot an $unit($recipient)." + "$unit($unit) administers $int($amount) duncebuns to $unit($recipient)." + + + + + + + + + "$unit($unit) in $region($region) rekrutiert $int($amount) von $int($want) Personen." + "$unit($unit) in $region($region) recruits $int($amount) $int($want) people." + "$unit($unit) in $region($region) recruits $int($amount) $int($want) people." + + + + + + + + "$unit($unit) belagert $building($building). Dabei richten die Katapulte Zerstörungen von $int($destruction) Größenpunkten an." + "$building($building) is under siege by $unit($unit). During siege, catapults caused $int($destruction) points destruction." + "$building($building) is under siege by $unit($unit). During siege, catapults caused $int($destruction) points destruction." + + + + + + + "$unit($unit) belagert $building($building)." + "$building($building) is under siege by $unit($unit)." + + + + + + + + "$unit($unit) ertrinkt beim Untergang der $ship($ship) in $region($region)." + "$unit($unit) drowns when $ship($ship) in $region($region) sinks." + "$unit($unit) drowns when $ship($ship) in $region($region) sinks." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht bewachen, da sie versucht zu fliehen." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot guard the region because it's trying to flee." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot guard the region because it's trying to flee." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann den Befehl in dieser Runde nicht ausführen, da sie an einem Kampf teilgenommen hat." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot execute this command because it has been in combat." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot execute this command because it has been in combat." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Gebäude kann nur einmal pro Runde erweitert werden." + "$unit($unit) in $region($region): '$order($command)' - Thhe building can be expanded only once per turn." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Objekt ist unzerstörbar." + "$unit($unit) in $region($region): '$order($command)' - This object is indestructible." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ohne Zutaten kann ein Alchemist nichts herstellen." + "$unit($unit) in $region($region): '$order($command)' - Ohne Zutaten kann ein Alchemist nichts herstellen." + "$unit($unit) in $region($region): '$order($command)' - Without ingredients an alchemist can not produce anything." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nicht alle Zutaten vorhanden." + "$unit($unit) in $region($region): '$order($command)' - Nicht alle Zutaten vorhanden." + "$unit($unit) in $region($region): '$order($command)' - Not all ingredients present." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Eine Partei kann nur einmal neu starten." + "$unit($unit) in $region($region): '$order($command)' - Restart can only be used once." + "$unit($unit) in $region($region): '$order($command)' - Restart can only be used once." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Werwesen können nicht arbeiten." + "$unit($unit) in $region($region): '$order($command)' - Lycantropes don't work." + "$unit($unit) in $region($region): '$order($command)' - Lycantropes don't work." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Werwesen können nicht mit anderen Personen gemischt werden." + "$unit($unit) in $region($region): '$order($command)' - Lycantropes may not be mixed with normal people." + "$unit($unit) in $region($region): '$order($command)' - Lycantropes may not be mixed with normal people." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann sich nicht verwandeln." + "$unit($unit) in $region($region): '$order($command)' - This unit can not change shape." + "$unit($unit) in $region($region): '$order($command)' - This unit can not change shape." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diese Einheit ist kein Werwesen." + "$unit($unit) in $region($region): '$order($command)' - This unit is not in lycantropic form." + "$unit($unit) in $region($region): '$order($command)' - This unit is not in lycantropic form." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diese Einheit ist schon ein Werwesen." + "$unit($unit) in $region($region): '$order($command)' - This unit already assumed lycantropic form." + "$unit($unit) in $region($region): '$order($command)' - This unit already assumed lycantropic form." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Talent kann nicht höher gelernt werden." + "$unit($unit) in $region($region): '$order($command)' - This skill cannot be raised any higher." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Snotlinge sind zu dumm, um auf den Feldern zu arbeiten." + "$unit($unit) in $region($region): '$order($command)' - We snotlings is too stupid fer dat!" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei muß mindestens 9 Wochen alt sein, um einen Neustart zu versuchen." + "$unit($unit) in $region($region): '$order($command)' - Your faction is not old enough to start over." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Optionen ZIP und BZIP2 können nur um, nicht ausgeschaltet werden." + "$unit($unit) in $region($region): '$order($command)' - options ZIP and BZIP2 can only be switched, not turned off." + "$unit($unit) in $region($region): '$order($command)' - options ZIP and BZIP2 can only be switched, not turned off." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Einheiten einer Partei, die noch immun gegen Angriffe ist, dürfen nicht bewachen." + "$unit($unit) in $region($region): '$order($command)' - units of a faction that can't be attacked may not guard." + "$unit($unit) in $region($region): '$order($command)' - units of a faction that can't be attacked may not guard." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In dieser Region kann man nichts verkaufen." + "$unit($unit) in $region($region): '$order($command)' - there is no trade in this region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Bereits ein Synonym gesetzt." + "$unit($unit) in $region($region): '$order($command)' - synonym already set." + "$unit($unit) in $region($region): '$order($command)' - synonym already set." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Kein Synonym angegeben." + "$unit($unit) in $region($region): '$order($command)' - synonym missing." + "$unit($unit) in $region($region): '$order($command)' - synonym missing." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ungültiges Synonym." + "$unit($unit) in $region($region): '$order($command)' - invalid synonym." + "$unit($unit) in $region($region): '$order($command)' - invalid synonym." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ungültiges Prefix." + "$unit($unit) in $region($region): '$order($command)' - invalid prefix." + "$unit($unit) in $region($region): '$order($command)' - invalid prefix." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier hat bereits einen Klon." + "$unit($unit) in $region($region): '$order($command)' - The magician already has a clone." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Gebäude auf dem Ozean können nicht betreten werden." + "$unit($unit) in $region($region): '$order($command)' - Buildings on the ocean may not be entered." + "$unit($unit) in $region($region): '$order($command)' - Buildings on the ocean may not be entered." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier werden niemals Bäume wachsen." + "$unit($unit) in $region($region): '$order($command)' - Trees won't grow here." + "$unit($unit) in $region($region): '$order($command)' - Trees won't grow here." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nur ein Magier kann einen Astralkristall benutzen." + "$unit($unit) in $region($region): '$order($command)' - Only mages may use an astralcrystal." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Verbände können nur zwischen Einheiten derselben Partei gebildet werden." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist in keinem Verband." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Eine Einheit kann nur in einem Verband Mitglied sein." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Wie sollen wir uns tarnen?" + "$unit($unit) in $region($region): '$order($command)' - What should we disguise us as?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Wieviel sollen wir einreißen?" + "$unit($unit) in $region($region): '$order($command)' - How much shall we tear down?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dorthin können wir die Einheit nicht transportieren." + "$unit($unit) in $region($region): '$order($command)' - We cannot transport this unit there." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit transportiert uns nicht." + "$unit($unit) in $region($region): '$order($command)' - the unit is not transporting us." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diese Einheit kennt keine Trankrezepte." + "$unit($unit) in $region($region): '$order($command)' - This unit knows no recipes for potions." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nur noch nicht gestärkte Untote können das Ziel dieses Zaubers sein." + "$unit($unit) in $region($region): '$order($command)' - Undead can only be affected once by this spell." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Passwort darf nur Buchstaben und Ziffern enthalten." + "$unit($unit) in $region($region): '$order($command)' - Your password may only contain alphanumeric symbols." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Gegen diese Rasse kann kein Jihad ausgerufen werden." + "$unit($unit) in $region($region): '$order($command)' - You cannot start a jihad against this race." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Gegen welche Rasse soll der Jihad ausgerufen werden?" + "$unit($unit) in $region($region): '$order($command)' - What race did you want the jihad to be against?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dazu muss erst die Spezialeigenschaft erworben werden." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Name und Beschreibung des Gebäudes können nicht geändert werden." + "$unit($unit) in $region($region): '$order($command)' - You cannot change the name and description of this building." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das kann die Einheit nicht." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man keine Schiffe bauen." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man keine Gebäude errichten." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht unterrichten." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man nicht unterrichten." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Pferde müssen leider draußen bleiben." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man niemanden angreifen." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man niemanden bestehlen." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man nicht zaubern." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man nichts übergeben." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nur eine Einzelperson kann das Ticket benutzen." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Gegenstand funktioniert nur in der Eingangshalle." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Gegenstand funktioniert nur in der normalen Welt." + "$unit($unit) in $region($region): '$order($command)' - This item only works in the normal world." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Gut hat die Einheit nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have this good." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Gut wird hier produziert." + "$unit($unit) in $region($region): '$order($command)' - This good is not produced here." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei kann keine weiteren Wyrme besitzen." + "$unit($unit) in $region($region): '$order($command)' - The faction cannot contain any more wyrms." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Vor den Besitzer eines Schiffes oder Gebäudes kann nicht sortiert werden." + "$unit($unit) in $region($region): '$order($command)' - You cannot sort before the owner of a ship or a building." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Besitzer eines Schiffes oder Gebäudes kann nicht neu sortiert werden." + "$unit($unit) in $region($region): '$order($command)' - The owner of a ship or a building cannot be sorted." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Befehl ist nur auf Einheiten innerhalb des selben Gebäudes oder Schiffes anwendbar." + "$unit($unit) in $region($region): '$order($command)' - That order only applies to units in the same building or ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Zieleinheit ist ungültig." + "$unit($unit) in $region($region): '$order($command)' - The target unit is invalid." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ungültiges Locale." + "$unit($unit) in $region($region): '$order($command)' - Invalid locale." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Um soetwas kann man nicht beten." + "$unit($unit) in $region($region): '$order($command)' - You cannot pray for this." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Soetwas kann man nicht opfern." + "$unit($unit) in $region($region): '$order($command)' - You cannot sacrifice this." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Auraangabe fehlerhaft oder zuwenig Aura." + "$unit($unit) in $region($region): '$order($command)' - Invalid aura specification or too little aura." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier ist nicht stark genug, sich den Göttern zu opfern." + "$unit($unit) in $region($region): '$order($command)' - This magician is not strong enough to be sacrificed to the gods." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Was und wieviel soll geopfert werden?" + "$unit($unit) in $region($region): '$order($command)' - What and how much should be sacrificed?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diese Kraft können selbst die Götter nicht mehr mächtiger machen." + "$unit($unit) in $region($region): '$order($command)' - Even the gods cannot improve this power." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nicht genug Karma." + "$unit($unit) in $region($region): '$order($command)' - Not enough karma." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff kann nicht aufs offene Meer hinaus segeln." + "$unit($unit) in $region($region): '$order($command)' - The ship cannot sail into the open seas." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei muß mindestens 10 Runden alt sein." + "$unit($unit) in $region($region): '$order($command)' - The faction has to be 10 turns old." + "$unit($unit) in $region($region): '$order($command)' - The faction has to be 10 turns old." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei hat schon einen Namen." + "$unit($unit) in $region($region): '$order($command)' - The faction is already named." + "$unit($unit) in $region($region): '$order($command)' - The faction is already named." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Gebäude hat schon einen Namen." + "$unit($unit) in $region($region): '$order($command)' - The building is already named." + "$unit($unit) in $region($region): '$order($command)' - The building is already named." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff hat schon einen Namen." + "$unit($unit) in $region($region): '$order($command)' - The ship is already named." + "$unit($unit) in $region($region): '$order($command)' - The ship is already named." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat schon einen Namen." + "$unit($unit) in $region($region): '$order($command)' - The unit is already named." + "$unit($unit) in $region($region): '$order($command)' - The unit is already named." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Keine gültige Rasse angegeben." + "$unit($unit) in $region($region): '$order($command)' - You did not specify a valid race." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit muß sich an Land befinden." + "$unit($unit) in $region($region): '$order($command)' - The unit must be on land." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $building($building) ist kein Steinkreis." + "$unit($unit) in $region($region): '$order($command)' - $building($building) is not a stonecircle." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $building($building) muss vor der Weihe fertiggestellt sein." + "$unit($unit) in $region($region): '$order($command)' - $building($building) has to be complete before it can be blessed." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In $region($target) sind keine Gräber." + "$unit($unit) in $region($region): '$order($command)' - There are no graves in $region($target)." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei muß mindestens 81 Wochen alt sein, um einen Neustart mit einer anderen Rasse zu versuchen." + "$unit($unit) in $region($region): '$order($command)' - The faction must be at least 81 weeks old to restart with a new race." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Soll eine Einheit oder ein Schiff verfolgt werden?" + "$unit($unit) in $region($region): '$order($command)' - Is this unit or ship supposed to be followed?" + "$unit($unit) in $region($region): '$order($command)' - Is this unit or ship supposed to be followed?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Soll eine Einheit oder ein Schiff eine neue Nummer bekommen?" + "$unit($unit) in $region($region): '$order($command)' - Is this unit or ship supposed to get a new number?" + "$unit($unit) in $region($region): '$order($command)' - Is this unit or ship supposed to get a new number?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier können nur Orks rekrutiert werden." + "$unit($unit) in $region($region): '$order($command)' - You can recruit only Orcs here." + "$unit($unit) in $region($region): '$order($command)' - You can recruit only Orcs here." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Region befindet sich in Aufruhr." + "$unit($unit) in $region($region): '$order($command)' - There are riots in this region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Gebäude ist noch nicht fertig gebaut." + "$unit($unit) in $region($region): '$order($command)' - The building is not finished yet." + "$unit($unit) in $region($region): '$order($command)' - The building is not finished yet." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Für das Gebäude wurde noch kein Unterhalt bezahlt." + "$unit($unit) in $region($region): '$order($command)' - Maintenance has not been paid yet." + "$unit($unit) in $region($region): '$order($command)' - Maintenance has not been paid yet." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist mit Ausschiffen beschäftigt.." + "$unit($unit) in $region($region): '$order($command)' - The unit is busy disembarking." + "$unit($unit) in $region($region): '$order($command)' - The unit is busy disembarking." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Typ Einheit kann keine Schiffe betreten." + "$unit($unit) in $region($region): '$order($command)' - Swimmers cannot enter ships." + "$unit($unit) in $region($region): '$order($command)' - Swimmers cannot enter ships." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Typ Einheit kann keine Gebäude betreten." + "$unit($unit) in $region($region): '$order($command)' - this type of unit cannot enter a building." + "$unit($unit) in $region($region): '$order($command)' - this type of unit cannot enter a building." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit oder ihre Tiere würden dort nicht überleben." + "$unit($unit) in $region($region): '$order($command)' - The unit or its animals would not survive there." + "$unit($unit) in $region($region): '$order($command)' - The unit or its animals would not survive there." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dorthin kann die Einheit uns nicht transportieren." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot transport us to this place." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot transport us to this place." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $building($building) wird belagert." + "$unit($unit) in $region($region): '$order($command)' - $building($building) is under siege." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Eintritt in $building($building) wurde verwehrt." + "$unit($unit) in $region($region): '$order($command)' - Entrance to $building($building) was denied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ein Vertrauter wird beschworen, verschwindet jedoch wieder, als er keine Verbindung zu seinem Element herstellen kann." + "$unit($unit) in $region($region): '$order($command)' - A familiar is summoned, but disappears again when it cannot get in contact with its natural element." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nur normale Personen können Steuern eintreiben." + "$unit($unit) in $region($region): '$order($command)' - Only normal characters can collect taxes." + "$unit($unit) in $region($region): '$order($command)' - Only normal characters can collect taxes." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dafür braucht ein Einheit mindestens Kräuterkunde 7." + "$unit($unit) in $region($region): '$order($command)' - A skill of herbalism 7 or higher is required." + "$unit($unit) in $region($region): '$order($command)' - A skill of herbalism 7 or higher is required." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Einheiten in den hinteren Reihen können nicht angreifen." + "$unit($unit) in $region($region): '$order($command)' - Units cannot attack from the second row." + "$unit($unit) in $region($region): '$order($command)' - Units cannot attack from the second row." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - unbekannter Kampfstatus." + "$unit($unit) in $region($region): '$order($command)' - unknown combat status." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht bewaffnet und kampffähig." + "$unit($unit) in $region($region): '$order($command)' - The unit is not armed and ready to fight." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei hat bereits ein Magiegebiet." + "$unit($unit) in $region($region): '$order($command)' - The faction has already chosen a magical school." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können nicht arbeiten." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot work." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot work." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hungernde Soldaten kämpfen nicht." + "$unit($unit) in $region($region): '$order($command)' - Starving units do not fight." + "$unit($unit) in $region($region): '$order($command)' - Starving units do not fight." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hungernde Einheiten können nicht zaubern." + "$unit($unit) in $region($region): '$order($command)' - Starving units cannot cast spells." + "$unit($unit) in $region($region): '$order($command)' - Starving units cannot cast spells." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hungernde Einheiten können nicht bewachen." + "$unit($unit) in $region($region): '$order($command)' - Starving units cannot guard." + "$unit($unit) in $region($region): '$order($command)' - Starving units cannot guard." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Zeige alle was?" + "$unit($unit) in $region($region): '$order($command)' - Show all what?" + "$unit($unit) in $region($region): '$order($command)' - Show all what?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht bauen." + "$unit($unit) in $region($region): '$order($command)' - You cannot build such a thing." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Im astralen Nebel konnte niemand entdeckt werden." + "$unit($unit) in $region($region): '$order($command)' - Noone could be seen in th astral fog." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ein Zauber in dieser Region verhindert das." + "$unit($unit) in $region($region): '$order($command)' - There is an active spell in this region that prevents this." + "$unit($unit) in $region($region): '$order($command)' - There is an active spell in this region that prevents this." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nur im Astralraum gezaubert werden." + "$unit($unit) in $region($region): '$order($command)' - This spell can only be cast in the astral plane." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier gibt es keine Verbindung zur astralen Welt." + "$unit($unit) in $region($region): '$order($command)' - There is no connection to the astral plane here." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Von hier aus kann man die astrale Ebene nicht erreichen." + "$unit($unit) in $region($region): '$order($command)' - You cannot reach the astral plane from here." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Einheit ist kein Magier." + "$unit($unit) in $region($region): '$order($command)' - Unit is not a magician." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Parameter nicht korrekt angegeben." + "$unit($unit) in $region($region): '$order($command)' - Incorrect parameter." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier befindet sich nicht auf einem Schiff." + "$unit($unit) in $region($region): '$order($command)' - The magician is not on board a ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Auf dem Schiff liegt bereits so ein Zauber." + "$unit($unit) in $region($region): '$order($command)' - The ship is already under this spell." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es ist zu gefährlich, ein sturmgepeitschtes Schiff fliegen zu lassen." + "$unit($unit) in $region($region): '$order($command)' - It is too dangerous to fly the ship in the storm." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Syntax Error." + "$unit($unit) in $region($region): '$order($command)' - Syntax Error." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Auraangabe fehlerhaft." + "$unit($unit) in $region($region): '$order($command)' - wrong Aura values." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Zu dieser Einheit kann keine Aura übertragen werden." + "$unit($unit) in $region($region): '$order($command)' - You cannot pass aura on to this unit." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Auf dem Gebäude liegt bereits so ein Zauber." + "$unit($unit) in $region($region): '$order($command)' - There is alrady a spell on that building." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nicht auf hoher See gezaubert werden." + "$unit($unit) in $region($region): '$order($command)' - This spell cannot be cast while you are on the ocean." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nicht auf Monster gezaubert werden." + "$unit($unit) in $region($region): '$order($command)' - This spell cannot be cast on monsters." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nicht auf Untote gezaubert werden." + "$unit($unit) in $region($region): '$order($command)' - This spell cannot be cast on undead." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Stimmung in der Region ist so schlecht, dass niemand auf den Zauber reagiert." + "$unit($unit) in $region($region): '$order($command)' - The mood in this region is so bad that nobody reacts t the spell." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) wusste trotz intensivem Verhör nichts über $region($tregion) zu berichten." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So viele Persoenen übersteigen die Kräfte des Magiers." + "$unit($unit) in $region($region): '$order($command)' -This many people exceed the powers of the magician." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) hat unaufkündbare Bindungen an seine alte Partei." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) have unbreakable prior commitments to their faction." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber gelingt nur in einer Ozeanregion." + "$unit($unit) in $region($region): '$order($command)' - This spell works only in an ocean region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In einer Region ohne Bäume kann man diesen Zauber nicht wirken." + "$unit($unit) in $region($region): '$order($command)' - You cannot cast this spell in a region without trees." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Ziel wurde vergessen." + "$unit($unit) in $region($region): '$order($command)' - No target has been supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das ist keine gültige Rasse." + "$unit($unit) in $region($region): '$order($command)' - This is not a valid race." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Rasse und Zieleinheit wurden vergessen." + "$unit($unit) in $region($region): '$order($command)' - Race and target unit have not been supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die maximale Aura reicht nicht für diesen Zauber." + "$unit($unit) in $region($region): '$order($command)' - Magician's maximum Aura is not high enough for this spell." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier hat bereits einen Vertrauten." + "$unit($unit) in $region($region): '$order($command)' - The magician already has a familiar." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Flammen finden keine Nahrung. Das Feuer erlischt, ohne Schaden anzurichten." + "$unit($unit) in $region($region): '$order($command)' - The flames find no kindling. The fire dies quickly, causing no damage whatsoever." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Um einen Heimstein zu erschaffen, muß der Zauberer in einer Burg sein." + "$unit($unit) in $region($region): '$order($command)' - The magician has to be in a castle to create a homestone." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das ist keine Waldregion." + "$unit($unit) in $region($region): '$order($command)' - This is not a forest region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dorthin führt kein Weg." + "$unit($unit) in $region($region): '$order($command)' - No way is leading in this direction." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Zielregion wurde nicht korrekt angegeben." + "$unit($unit) in $region($region): '$order($command)' - Target region was supplied incorrectly." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Zauber funktioniert nur in der Geisterwelt." + "$unit($unit) in $region($region): '$order($command)' - This spell will only work in the realm of spirits." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Wege zwischen Geisterwelt und Realität scheinen blockiert zu sein." + "$unit($unit) in $region($region): '$order($command)' - The paths to the spirit world seem to be blocked." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Zauber funktioniert nur in Wäldern." + "$unit($unit) in $region($region): '$order($command)' - This spell works only in forests." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Zauber funktioniert nur in der materiellen Welt." + "$unit($unit) in $region($region): '$order($command)' - This spell works only in the material world." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Selbst der mächtigste Magier der Welt könnte keinen Ozean austrocknen lassen." + "$unit($unit) in $region($region): '$order($command)' - Even the gods cannot dry out an entire ocean." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nicht im Sumpf gezaubert werden." + "$unit($unit) in $region($region): '$order($command)' - You cannot cast this spell in a swamp." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nur auf Land gelegt werden." + "$unit($unit) in $region($region): '$order($command)' - This spell works only ashore." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Zauber scheint ungewöhnlich schwach zu sein. Irgendetwas hat die magischen Energien abgeleitet." + "$unit($unit) in $region($region): '$order($command)' - the spell seems exceptionally weak. Something has interfred with the magical energies." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann den Befehl in dieser Runde nicht ausführen, da sie sich bewegt hat." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot execute this command because it has moved." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit bewegt sich nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not move." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier befindet sich nicht auf einem Schiff." + "$unit($unit) in $region($region): '$order($command)' - The magician is not on board a ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff kann in diese Richtung nicht ablegen." + "$unit($unit) in $region($region): '$order($command)' - The ship cannot leave in this direction." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dazu muß sich der Magier in der Burg oder an Bord des Schiffes befinden." + "$unit($unit) in $region($region): '$order($command)' - To do this, the magician has to be in a castle or on board a ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Zauber schlägt fehl." + "$unit($unit) in $region($region): '$order($command)' - The spell fails." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Magiegebiet kann die Einheit nicht lernen." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot learn this magic sphere." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es wurde kein Magiegebiet angegeben." + "$unit($unit) in $region($region): '$order($command)' - No magic sphere was supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diesen Spruch kann der Vertraute nicht zaubern." + "$unit($unit) in $region($region): '$order($command)' - the familiar cannot cast this spell." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diesen Spruch kann man nicht in die Ferne richten." + "$unit($unit) in $region($region): '$order($command)' - You cannot cast this spell on a distant target." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diesen Spruch kann man nicht auf einem sich bewegenden Schiff stehend zaubern." + "$unit($unit) in $region($region): '$order($command)' - You cannot cast this spell while standing on a moving ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber ist nur im Kampf sinnvoll." + "$unit($unit) in $region($region): '$order($command)' - this spell makes only sense in combat." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Selbst in der Bibliothek von Xontormia konnte dieser Spruch nicht gefunden werden." + "$unit($unit) in $region($region): '$order($command)' - Even in the Xontormia Library, this spell could not be found." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es wurde kein Zauber angegeben." + "$unit($unit) in $region($region): '$order($command)' - There was no spell supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diesen Kampfzauber gibt es nicht." + "$unit($unit) in $region($region): '$order($command)' - This combat spell does not exist." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Bauern nehmen dieses großzügige Geschenk nicht an." + "$unit($unit) in $region($region): '$order($command)' - The peasants did not accept this gracious gift." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diesen Zauber kennt die Einheit nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not know this spell." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es konnten keine Luxusgüter verkauft werden." + "$unit($unit) in $region($region): '$order($command)' - No luxury items could be sold." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit geht nicht zu den Bauern." + "$unit($unit) in $region($region): '$order($command)' - The unit does not go to the peasants." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diese Rasse kann eine Burg nicht belagern." + "$unit($unit) in $region($region): '$order($command)' - This race cannot siege a castle." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Trank bekommt der Einheit nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit disagreed with the potion." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Nestwärme kann nur von Insektenvölkern benutzt werden." + "$unit($unit) in $region($region): '$order($command)' - this potion can only be used by insects." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Heiltrank wird automatisch bei Bedarf benutzt." + "$unit($unit) in $region($region): '$order($command)' - This healing potion will be automatically used when needed." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit besitzt den Trank nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have this potion." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es konnten keine Luxusgüter gekauft werden." + "$unit($unit) in $region($region): '$order($command)' - No luxury items could be bought." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es konnten keine Personen übergeben werden." + "$unit($unit) in $region($region): '$order($command)' - No person could be handed over." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Magier arbeiten grundsätzlich nur alleine!" + "$unit($unit) in $region($region): '$order($command)' - Magicians always work alone!" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei hat ein anderes Magiegebiet." + "$unit($unit) in $region($region): '$order($command)' - The faction has a different magic sphere." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Zuviele Alchemisten in der Partei." + "$unit($unit) in $region($region): '$order($command)' - Too many alchemists in the faction." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Zuviele Magier in der Partei." + "$unit($unit) in $region($region): '$order($command)' - Too many magicians in the faction." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hochqualifizierte Personen weigern sich, für andere Parteien zu arbeiten." + "$unit($unit) in $region($region): '$order($command)' - Highly qualified people refuse to work for other parties." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit schließt sich den Bauern an." + "$unit($unit) in $region($region): '$order($command)' - The unit joins the local peasants." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit springt über Bord und ertrinkt." + "$unit($unit) in $region($region): '$order($command)' - The unit jumps over board and drowns." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Region wird bewacht." + "$unit($unit) in $region($region): '$order($command)' - The region is guarded." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Unbekannte Option." + "$unit($unit) in $region($region): '$order($command)' - Unknown Option." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit wird belagert." + "$unit($unit) in $region($region): '$order($command)' - The unit is under siege." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Zum Straßenbau braucht man Steine." + "$unit($unit) in $region($region): '$order($command)' - You need stones to build a road." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Wohin soll die Botschaft gehen?" + "$unit($unit) in $region($region): '$order($command)' - Who is supposed to get this message?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht der Burgherr." + "$unit($unit) in $region($region): '$order($command)' - The unit is not in command of a castle." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht Burgherr der größten Burg in der Region." + "$unit($unit) in $region($region): '$order($command)' - The unit is not in command of the largest castle in the region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht der Kapitän des Schiffes." + "$unit($unit) in $region($region): '$order($command)' - The unit is not captain of a ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist in keiner Burg." + "$unit($unit) in $region($region): '$order($command)' - The unit is not in a castle." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist auf keinem Schiff." + "$unit($unit) in $region($region): '$order($command)' - The unit is not on board a ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist auf einem Schiff." + "$unit($unit) in $region($region): '$order($command)' - The unit is on board a ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat zuwenig Silber, um zu rekrutieren." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough silver for recruiting." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht mehr genug Kristalle für so viele Personen." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough crystals left for this many people." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit befindet sich weder in einer Burg noch auf einem Schiff." + "$unit($unit) in $region($region): '$order($command)' - The unit is neither in a castle nor on board a ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Unterschiedliche Typen können nicht gemischt werden." + "$unit($unit) in $region($region): '$order($command)' - Different types do not mix." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Uns gehört nichts, was man abreißen oder versenken könnte." + "$unit($unit) in $region($region): '$order($command)' - We do not have anything that could be demolished." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Unbekannter Hilfe-Modus." + "$unit($unit) in $region($region): '$order($command)' - Unknown Help- Mode." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Unbekannte Meldungs-Option." + "$unit($unit) in $region($region): '$order($command)' - Unknown Report-Option." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Um in Wüsten Straßen bauen zu können, muß zuerst eine Karawanserei errichtet werden." + "$unit($unit) in $region($region): '$order($command)' - You've got to build a caravansary before building roads through deserts." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Um in Sümpfen Straßen bauen zu können, muß zuerst ein Damm errichtet werden." + "$unit($unit) in $region($region): '$order($command)' - You've got to build a dam before building roads through swamps." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So viele Leute kann die Partei nicht aufnehmen." + "$unit($unit) in $region($region): '$order($command)' - The faction cannot hire so many strangers." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So viele Fremde kann die Partei nicht aufnehmen." + "$unit($unit) in $region($region): '$order($command)' - The faction cannot hire so many strangers." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So viele Fremde kann Deine Partei nicht aufnehmen." + "$unit($unit) in $region($region): '$order($command)' - Your faction cannot hire so many strangers." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht verkaufen." + "$unit($unit) in $region($region): '$order($command)' - You cannot sell this." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht machen." + "$unit($unit) in $region($region): '$order($command)' - You cannot produce this." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht auf dem Markt kaufen." + "$unit($unit) in $region($region): '$order($command)' - You cannot buy that on a market place." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So etwas hat die Einheit nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have such a thing." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Pferde kann man nur in einer Pferdezucht züchten." + "$unit($unit) in $region($region): '$order($command)' - You can breed horses only in a stable." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So etwas gibt es hier nicht." + "$unit($unit) in $region($region): '$order($command)' - That resource does not exist in this region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Personen können nur an Menschen übergeben werden." + "$unit($unit) in $region($region): '$order($command)' - Characters can be given only to Human parties." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ohne einen Handelsposten gibt es keinen Markt." + "$unit($unit) in $region($region): '$order($command)' - There is no marketplace without at least a tradepost." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nur Elfen können diese Bögen herstellen." + "$unit($unit) in $region($region): '$order($command)' - Only Elves can make these bows." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nur die EMail-Adresse angeben!" + "$unit($unit) in $region($region): '$order($command)' - Submit only email-address, please!" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nummer kann nicht vergeben werden." + "$unit($unit) in $region($region): '$order($command)' - Number can not be assigned." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nummer ist schon belegt." + "$unit($unit) in $region($region): '$order($command)' - Number is already in use." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nummer ist nicht im gültigen Bereich." + "$unit($unit) in $region($region): '$order($command)' - Number is not valid." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nichts angegeben, was wir übergeben sollen." + "$unit($unit) in $region($region): '$order($command)' - Item to be handed over was not supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Namen dürfen keine Klammern enthalten." + "$unit($unit) in $region($region): '$order($command)' - Names may not contain parenthesis." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nachricht zu lang - gekürzt." + "$unit($unit) in $region($region): '$order($command)' - Message has been cut (too long).." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Man muß angeben, ob eine Burg, ein Schiff, eine Region oder eine Einheit beschrieben werden soll." + "$unit($unit) in $region($region): '$order($command)' - Specify if description is for a castle, a ship, a region or a unit." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Man muß angeben, ob eine Burg, ein Schiff, eine Einheit, eine Region oder eine Partei benannt werden soll." + "$unit($unit) in $region($region): '$order($command)' - Specify if a castle, a ship, a region or a unit is supposed to be named." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es sind keine Kräuter zu finden." + "$unit($unit) in $region($region): '$order($command)' - No herbs could be found." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Man braucht mindestens zwei Pferde, um sie zu züchten." + "$unit($unit) in $region($region): '$order($command)' - You need at least two horses to breed more." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Magier müssen zum studieren allein sein." + "$unit($unit) in $region($region): '$order($command)' - When studying, magicians need to be alone." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Leere Einheiten können nicht übergeben werden." + "$unit($unit) in $region($region): '$order($command)' - Empty units can not be handed over." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Laen kann nur in einem Bergwerk abgebaut werden." + "$unit($unit) in $region($region): '$order($command)' - Laen can be excavated only in a mine." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Keiner hier kann Straßen bauen." + "$unit($unit) in $region($region): '$order($command)' - Nobody here can build roads." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann keine weiteren Güter handeln." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot trade any more goods." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Keiner hier kann ein Gebäude errichten." + "$unit($unit) in $region($region): '$order($command)' - Nobody here can construct a building." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Keiner hier ist gelernter Schiffbauer." + "$unit($unit) in $region($region): '$order($command)' - Nobody here is a skilled ship builder." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit will nicht transportiert werden." + "$unit($unit) in $region($region): '$order($command)' - The unit doen not want to be transported." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Insekten können im Winter nur in Wüsten rekrutiert werden." + "$unit($unit) in $region($region): '$order($command)' - In winter, insects can be recruited only in deserts." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In Gletschern können keine Insekten rekrutiert werden." + "$unit($unit) in $region($region): '$order($command)' - Insects cannot be recruited in glaciers." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In dieser Einheit gibt es niemanden, den man transferieren könnte." + "$unit($unit) in $region($region): '$order($command)' - Nobody in this unit can be transferred." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Illusionen können eine Region nicht bewachen." + "$unit($unit) in $region($region): '$order($command)' - Illusions cannot guard a region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man keine Straße bauen." + "$unit($unit) in $region($region): '$order($command)' - You cannot build a road here." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier gibt es schon einen Hafen." + "$unit($unit) in $region($region): '$order($command)' - There is already a port in this region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier gibt es keine Bauern." + "$unit($unit) in $region($region): '$order($command)' - There are no peasants in this region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier gibt es keinen normalen Wald." + "$unit($unit) in $region($region): '$order($command)' - There is no normal forest in this region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier gibt es keine Mallornbäume." + "$unit($unit) in $region($region): '$order($command)' - There are no Mallorn trees here." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit fährt nicht mit uns." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have a RIDE-order." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Geldgebot fehlt." + "$unit($unit) in $region($region): '$order($command)' - Money offer is missing." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht genügend Materialien für den Schiffbau." + "$unit($unit) in $region($region): '$order($command)' - the unit is lacking materials to build the ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Für das Elixier benötigt man Drachenblut." + "$unit($unit) in $region($region): '$order($command)' - Dragon blood is required for this elixir." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Falsches Passwort." + "$unit($unit) in $region($region): '$order($command)' - Wrong password." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es wurde keine EMail-Adresse angegeben." + "$unit($unit) in $region($region): '$order($command)' - No email-address was supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es wurde kein Name angegeben." + "$unit($unit) in $region($region): '$order($command)' - No name was supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es konnte kein Bauer gefangen werden." + "$unit($unit) in $region($region): '$order($command)' - No peasant could be caught." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es gibt keine Abstimmung mit dieser Nummer." + "$unit($unit) in $region($region): '$order($command)' - There is no agreement with this number." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Einheit muß zuerst die Region bewachen." + "$unit($unit) in $region($region): '$order($command)' - first, the unit must guard the region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Einheit ist nicht bewaffnet und kampffähig." + "$unit($unit) in $region($region): '$order($command)' - The unit is not armed and fighting fit." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ein Schiff oder eine Burg muß angegeben werden." + "$unit($unit) in $region($region): '$order($command)' - A ship or a castle must be supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ein Fluch verhindert die Übergabe." + "$unit($unit) in $region($region): '$order($command)' - A curse prevented the transfer from happening." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Talent wurde nicht erkannt." + "$unit($unit) in $region($region): '$order($command)' - The skill could not be recognized." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Talent kann die Einheit nicht lernen." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot learn this skill." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diesen Gegenstand kann man nicht benutzen." + "$unit($unit) in $region($region): '$order($command)' - This item cannot be used." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit nimmt niemanden an." + "$unit($unit) in $region($region): '$order($command)' - This unit does not take anybody." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Eine hungernde Einheit kann niemanden weggeben." + "$unit($unit) in $region($region): '$order($command)' - Hungry units cannot give anybody away." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diese Einheit kann niemanden weggeben." + "$unit($unit) in $region($region): '$order($command)' - This unit cannot give anybody away." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) hat keinen Kontakt mit uns aufgenommen." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) did not contact us." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es kann hier kein Kontakt zur Astralwelt aufgenommen werden." + "$unit($unit) in $region($region): '$order($command)' - There is no connection to the astral plane." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) hat keinen Kontakt mit uns aufgenommen und widersteht dem Zauber." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) did not contact us, and resists the spell." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) hat keinen Kontakt mit uns aufgenommen, aber widersteht dem Zauber nicht." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) did not contact us, but cannot resist the spell." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Richtung wurde nicht erkannt." + "$unit($unit) in $region($region): '$order($command)' - Direction was not recognized." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Richtung '$dirname' wurde nicht erkannt." + "$unit($unit) in $region($region): '$order($command)' - Direction '$dirname' was not recognized." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Region wird von Nichtalliierten bewacht." + "$unit($unit) in $region($region): '$order($command)' - This region is guarded by a non allied faction." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Region wird von $unit($guard), einer nichtalliierten Einheit, bewacht." + "$unit($unit) in $region($region): '$order($command)' - This region is guarded by $unit($guard), a non-allied unit." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Pferde würden ertrinken." + "$unit($unit) in $region($region): '$order($command)' - The horses would drown." + "$unit($unit) in $region($region): '$order($command)' - The horses would drown." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - The faction could not be found." + "$unit($unit) in $region($region): '$order($command)' - The faction could not be found." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Lernkosten können nicht bezahlt werden." + "$unit($unit) in $region($region): '$order($command)' - Tuition was too high to be paid." + "$unit($unit) in $region($region): '$order($command)' - Tuition was too high to be paid." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Gegenstand kann nur in der realen Welt benutzt werden." + "$unit($unit) in $region($region): '$order($command)' - This object can only be used in the real world." + "$unit($unit) in $region($region): '$order($command)' - This object can only be used in the real world." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) ist nicht ausreichend getarnt." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) is not sufficiently stealthy." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) is not sufficiently stealthy." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - The unit could not be found." + "$unit($unit) in $region($region): '$order($command)' - The unit could not be found." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Einheit kann nichts gegeben werden." + "$unit($unit) in $region($region): '$order($command)' - You cannot give anything to this unit." + + + + + + + + + "$unit($mage) horcht $unit($unit) über $region($tregion) aus." + "$unit($mage) questions $unit($unit) about $region($tregion)." + + + + + + + + "$unit($mage) verschafft $unit($unit) einige feuchtfröhliche Stunden mit heftigen Nachwirkungen." + "$unit($mage) invites $unit($unit) for a few too many drinks and a massive hangover." + + + + + + + "$unit($unit) hat höllische Kopfschmerzen und kann sich an die vergangene Woche nicht mehr erinnern. Nur noch daran, wie alles mit einer fröhlichen Feier in irgendeiner Taverne anfing...." + "$unit($unit) has a splitting headache and can hardly remember last week. Except that it all started in the tavern..." + + + + + + + + "$unit($mage) besänftigt $unit($unit)." + "$unit($mage) calms $unit($unit)." + + + + + + + "$unit($unit) verfiel dem Glücksspiel und hat fast sein ganzes Hab und gut verspielt." + "$unit($unit) gambles for high stakes and loses almost everything." + + + + + + + + + "$unit($unit) schenkt $unit($mage) $resources($items)." + "$unit($unit) gives $unit($mage) $resources($items)." + + + + + + + + + "$unit($mage) läßt $unit($target) als $race($race,$unit.size($target)) erscheinen." + "$unit($mage) makes $unit($target) appear as $race($race,$unit.size($target))." + + + + + + + "$unit($unit) wird kurz von einem magischen Licht umhüllt." + "$unit($unit) is briefly surrounded by a magical light." + + + + + + + + "$unit($unit) konnte nur $int($ships) von $int($maxships) Schiffen verzaubern." + "$unit($unit) could only enchant $int($ships) of $int($maxships) ships." + + + + + + "$unit($unit) beschwört einen magischen Wind, der die Schiffe über das Wasser treibt." + "$unit($unit) calls up a magical storm that whips the ship over the waters." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit weiß nichts über Botanik." + "$unit($unit) in $region($region): '$order($command)' - The unit does not know anything about herbalism." + "$unit($unit) in $region($region): '$order($command)' - The unit does not know anything about herbalism." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit weiß nicht, wie man gaukelt." + "$unit($unit) in $region($region): '$order($command)' - The unit does not know how to entertain." + "$unit($unit) in $region($region): '$order($command)' - The unit does not know how to entertain." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit trägt zuviel Gewicht, um sich bewegen zu können." + "$unit($unit) in $region($region): '$order($command)' - The unit is too heavily loaded to move." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann soviele Pferde nicht bändigen." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot tame that many horses." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann sich nicht fortbewegen." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot move." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht handeln." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot trade." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann keine Tränke herstellen." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot make potions." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann keine weiteren langen Befehle ausführen." + "$unit($unit) in $region($region): '$order($command)' - The unit is exhausted from battle." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht genug Silber." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough silver." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough silver." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht erfahren genug dafür." + "$unit($unit) in $region($region): '$order($command)' - The unit is not experienced enough to do this." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht der Eigentümer." + "$unit($unit) in $region($region): '$order($command)' - The unit is not he owner." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht bewaffnet und kampffähig." + "$unit($unit) in $region($region): '$order($command)' - The unit is not armed and fighting fit." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist mit uns alliiert." + "$unit($unit) in $region($region): '$order($command)' - This unit is one of our allies." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist in keiner Taverne." + "$unit($unit) in $region($region): '$order($command)' - The unit is not in a tavern." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist eine der unsrigen." + "$unit($unit) in $region($region): '$order($command)' - This unit is one of our own." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist auf hoher See." + "$unit($unit) in $region($region): '$order($command)' - The unit is off shore." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat soetwas nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have this." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht genug Wagenlenker oder zuviel andere Fracht, um die Wagen aufzuladen." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough coachmen or too much freights to lad the wagons." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht genug Silber." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough silver." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat keinen Kontakt mit uns aufgenommen." + "$unit($unit) in $region($region): '$order($command)' - The unit did not contact us." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat keine Spionage gelernt." + "$unit($unit) in $region($region): '$order($command)' - The unit has not yet learned espionage." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat keine Kräuter." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have any herbs." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat diesen Trank nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have this potion." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat diesen Gegenstand nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have this item." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat diesen Gegenstand zwar, aber sämtliche $int($reservation) $resource($resource,$reservation) sind reserviert." + "$unit($unit) in $region($region): '$order($command)' - The unit has this item, but all $int($reservation) $resource($resource,$reservation) are reserved." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat diese Kräuter nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have these herbs." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Einheiten dürfen nicht mehr als $int($maxsize) Personen enthalten." + "$unit($unit) in $region($region): '$order($command)' - Units may not have more than $int($maxsize) members." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit darf nicht an Bord kommen, da sie das Schiff überladen würde." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot go aboard, the ship would be overloaded." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit darf nicht an Bord kommen." + "$unit($unit) in $region($region): '$order($command)' - This unit has no permission to come on board." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit befindet sich nicht in unserer Burg." + "$unit($unit) in $region($region): '$order($command)' - The unit is not in our castle." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit befindet sich nicht an Bord unseres Schiffes." + "$unit($unit) in $region($region): '$order($command)' - The unit is not on board our ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Burg wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - The castle could not be found." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Botschaft enthält keinen Text." + "$unit($unit) in $region($region): '$order($command)' - The message does not contain text." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Bauern sind schlecht gelaunt." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Anzahl zu verkaufender Produkte fehlt." + "$unit($unit) in $region($region): '$order($command)' - The amount of items for sale is missing." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Anzahl zu kaufender Produkte fehlt." + "$unit($unit) in $region($region): '$order($command)' - The amount of items to buy is missing." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Fluch verhindert das." + "$unit($unit) in $region($region): '$order($command)' - The escape prevented that from happening." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Belagerungszustand macht Spionage unmöglich." + "$unit($unit) in $region($region): '$order($command)' - Espionage was not possible due to siege." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Belagerungszustand macht die Kontaktaufnahme unmöglich." + "$unit($unit) in $region($region): '$order($command)' - Contact was not possible due to siege." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Befehl wurde nicht erkannt." + "$unit($unit) in $region($region): '$order($command)' - Unknown command." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dazu gibt es keine Informationen." + "$unit($unit) in $region($region): '$order($command)' - There is no information available for the request." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - The ship could not be found." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff muß erst verlassen werden." + "$unit($unit) in $region($region): '$order($command)' - First you have to leave the ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff ist zu schwer beladen, um in See zu stechen." + "$unit($unit) in $region($region): '$order($command)' - The ship is too heavily loaded to sail." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $ship($ship) ist zu groß, um fliegen zu können." + "$unit($unit) in $region($region): '$order($command)' - $ship($ship) is too bulky to fly." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff ist schon fertig." + "$unit($unit) in $region($region): '$order($command)' - The ship is already completed." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff ist noch nicht fertig gebaut." + "$unit($unit) in $region($region): '$order($command)' - The ship has not yet been completed." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff ist auf hoher See." + "$unit($unit) in $region($region): '$order($command)' - The ship is off shore." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff hat sich bereits bewegt." + "$unit($unit) in $region($region): '$order($command)' - The ship has moved already." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Besitzer muss das Gebäude zuerst verlassen." + "$unit($unit) in $region($region): '$order($command)' - The owner must first LEAVE the building." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff gehört uns nicht." + "$unit($unit) in $region($region): '$order($command)' - The ship is not ours." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Gebäude gehört uns nicht." + "$unit($unit) in $region($region): '$order($command)' - The building is not ours." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff befindet sich auf hoher See." + "$unit($unit) in $region($region): '$order($command)' - The ship is still off shore." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das macht wenig Sinn." + "$unit($unit) in $region($region): '$order($command)' - That does not make much sense." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das kann man nicht sabotieren." + "$unit($unit) in $region($region): '$order($command)' - That cannot be sabotaged." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das ist sinnlos." + "$unit($unit) in $region($region): '$order($command)' - That is useless." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das geht nicht mehr." + "$unit($unit) in $region($region): '$order($command)' - This is no longer possible." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Gebäude wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - Building could not be found." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Gebäude gehört uns nicht." + "$unit($unit) in $region($region): '$order($command)' - The building is not ours." + "$unit($unit) in $region($region): '$order($command)' - The building is not ours." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Gebäude ist bereits fertig." + "$unit($unit) in $region($region): '$order($command)' - The building is already completed." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht unterrichtet werden." + "$unit($unit) in $region($region): '$order($command)' - this unit cannot be taught." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Beschreibung zu lang - gekürzt." + "$unit($unit) in $region($region): '$order($command)' - Description has been cut (too long)." + "$unit($unit) in $region($region): '$order($command)' - Description has been cut (too long)." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Auf hoher See kann man nicht bewachen." + "$unit($unit) in $region($region): '$order($command)' - You cannot guard off shore." + "$unit($unit) in $region($region): '$order($command)' - You cannot guard off shore." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Auf dem Schiff befinden sich zuwenig erfahrene Seeleute." + "$unit($unit) in $region($region): '$order($command)' - There are not enough experienced sailors on board the ship." + "$unit($unit) in $region($region): '$order($command)' - There are not enough experienced sailors on board the ship." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - ${error}." + "$unit($unit) in $region($region): '$order($command)' - ${error}." + + + + + + + "$unit($unit) benutzt ein $resource($item,1)." + "$unit($unit) uses a $resource($item,1)." + "$unit($unit) uses a $resource($item,1)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $resource($item,0) können nur von Ein-Personen Einheiten benutzt werden." + "$unit($unit) in $region($region): '$order($command)' - $resource($item,0) can only be used by single-person units." + "$unit($unit) in $region($region): '$order($command)' - $resource($item,0) can only be used by single-person units." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist noch zu erschöpft vom Einmarsch um zu attackieren." + "'$order($command)' - $unit($unit) marched into $region($region) during the last turn and is too exhausted to attack." + "'$order($command)' - $unit($unit) marched into $region($region) during the last turn and is too exhausted to attack." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) sind friedliebend und attackieren niemand." + "'$order($command)' - $race($race,0) are peace-loving and will not attack anyone." + "'$order($command)' - $race($race,0) are peace-loving and will not attack anyone." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit steht nicht im benötigten Gebäude, $localize($building)." + "$unit($unit) in $region($region): '$order($command)' - The unit must be in a $localize($building) to produce this." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dazu braucht man das Talent $skill($skill)." + "$unit($unit) in $region($region): '$order($command)' - this requires the skill $skill($skill)." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Man benötigt mindestens $int($minskill) $skill($skill), um $resource($product,0) zu pflanzen." + "$unit($unit) in $region($region): '$order($command)' - At least $skill($skill) $int($minskill) is needed for planting $resource($product,0)." + "$unit($unit) in $region($region): '$order($command)' - At least $skill($skill) $int($minskill) is needed for planting $resource($product,0)." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Man benötigt mindestens $int($minskill) $skill($skill), um $resource($product,0) zu produzieren." + "$unit($unit) in $region($region): '$order($command)' - You need at least $int($minskill) $skill($skill), to produce $resource($product,0)." + + + + + + "$string" + "$string" + + + + + + "$string" + "$string" + + + + + + "$string" + "$string" + + + + + + + + "$unit($unit) übergibt $int($amount) Person$if($eq($amount,1),"","en") an $unit($target)." + "$unit($unit) transfers $int($amount) person$if($eq($amount,1),"","s") to $unit($target)." + + + + + + + + + + "$unit($unit) übergibt $int($amount) $resource($resource,$amount) an $unit($target)." + "$unit($unit) gives $int($amount) $resource($resource,$amount) to $unit($target)." + + + + + + + + + + "$unit($target) erhält $int($amount) $resource($resource,$amount) von $unit($unit)." + "$unit($target) receives $int($amount) $resource($resource,$amount) from $unit($unit)." + + + + + + + + "$unit($unit) übergibt $int($amount) Person$if($eq($amount,1),"","en") an die Bauern." + "$unit($unit) transfers $int($amount) person$if($eq($amount,1),"","s") to the local peasants." + + + + + + + + + "$unit($unit) übergibt $int($amount) $resource($resource,$amount) an die Bauern." + "$unit($unit) gives $int($amount) $resource($resource,$amount) to the local peasants." + + + + + + + + "$unit($unit) bezahlt den Unterhalt von $building($building)." + "$unit($unit) pays the maintenance for $building($building)." + "$unit($unit) pays the maintenance for $building($building)." + + + + + + + + "$unit($unit) fehlen $resource($item,0) für den Betrieb von $building($building)." + "$unit($unit) lacks $resource($item,0) to operate $building($building)." + + + + + + + "$unit($unit) kann den Unterhalt von $building($building) nicht bezahlen." + "$unit($unit) cannot pay the maintenance for $building($building)." + "$unit($unit) cannot pay the maintenance for $building($building)." + + + + + + "Der Unterhalt von $building($building) konnte nur verspätet gezahlt werden, das Gebäude war diese Woche nicht funktionstüchtig." + "The upkeep for $building($building) was paid late, the building was not operational this week." + "The upkeep for $building($building) was paid late, the building was not operational this week." + + + + + + + + "$unit($unit) verdient am Handel in $region($region) Steuern in Höhe von $int($amount) Silber." + "$unit($unit) collected $int($amount) silver trade tax in $region($region)." + "$unit($unit) collected $int($amount) silver trade tax in $region($region)." + + + + + + + "$unit($unit) benutzt $resource($potion,1)." + "$unit($unit) uses $resource($potion,1)." + "$unit($unit) uses $resource($potion,1)." + + + + + + "Hier wütete die Pest, und $int($dead) Bauern starben." + "The region is visited by the plague and $int($dead) peasants died." + "The region is visited by the plague and $int($dead) peasants died." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Um in Gletschern Straßen bauen zu können, muß zuerst ein Tunnel errichtet werden." + "$unit($unit) in $region($region): '$order($command)' - You've got to build a tunnel before building roads through glaciers." + "$unit($unit) in $region($region): '$order($command)' - You've got to build a tunnel before building roads through glaciers." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Syntax: MAGIEGEBIET [1-5]." + "$unit($unit) in $region($region): '$order($command)' - Syntax: MAGIC SPHERE [1-5]." + "$unit($unit) in $region($region): '$order($command)' - Syntax: MAGIC SPHERE [1-5]." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Deine Partei muss mindestens $int($turns) alt sein, um etwas an andere Parteien übergeben zu können." + "$unit($unit) in $region($region): '$order($command)' - Your faction must be at least $int($turns) weeks old to give something to another faction." + "$unit($unit) in $region($region): '$order($command)' - Your faction must be at least $int($turns) weeks old to give something to another faction." + + + + + + "Bitte sende die Befehle nächste Runde ein, wenn du weiterspielen möchtest." + "Merci d'envoyer vos ordres pour le tour suivant si vous désirez continuer à jouer." + "Please send in orders for the next turn if you want to continue playing." + + + + + + + "Deine Partei ist noch $int($turns) Wochen immun gegen Angriffe." + "Votre faction est immunisée contre les agressions durant $int($turns) semaines encore." + "Your faction is immune against assaults for $int($turns) more weeks." + + + + + + + + "$faction($member) ist mit $int($votes) Stimmen aus $alliance($alliance) ausgeschlossen worden." + "$faction($member) was kicked from $alliance($alliance) by $int($votes) of the alliance's members." + "$faction($member) was kicked from $alliance($alliance) by $int($votes) of the alliance's members." + + + + + + "$alliance($alliance) scheidet aus dem Spiel aus, nachdem alle Tempel verloren gingen." + "$alliance($alliance) has to leave the game after all their temples were lost." + "$alliance($alliance) has to leave the game after all their temples were lost." + + + + + + + "$int($votes) Mitglieder von $alliance($alliance) haben versucht, Deine Partei aus der Allianz auszuschliessen." + "$int($votes) members of $alliance($alliance) tried to kick you out of the alliance." + "$int($votes) members of $alliance($alliance) tried to kick you out of the alliance." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In dieser Regione können Pyramiden gebaut werden." + "$unit($unit) in $region($region): '$order($command)' - Pyramids may be build in this region." + "$unit($unit) in $region($region): '$order($command)' - Pyramids may be build in this region." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Auf $ship($ship) liegt beeits ein Zauber." + "$unit($unit) in $region($region): '$order($command)' - There is already a spell on $ship($ship)." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es ist zu gefährlich, diesen Zauber auf das fliegende Schiff $ship($ship) zu legen." + "$unit($unit) in $region($region): '$order($command)' - It is far too dangerous to put this spell on the flying ship $ship($ship)." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In dieser Region können keine Pyramiden gebaut werden. Die nächste Pyramidenregion ist zwischen $int($mindist) und $int($maxdist) Regionen entfernt." + "$unit($unit) in $region($region): '$order($command)' - No pyramids may be build in this region. The closest region to build a pyramid in is between $int($mindist) and $int($maxdist) regions away." + "$unit($unit) in $region($region): '$order($command)' - No pyramids may be build in this region. The closest region to build a pyramid in is between $int($mindist) and $int($maxdist) regions away." + + + + + + + + "$unit($unit) kann in $region($region) nicht durch das Wurmloch reisen, da die Einheit entweder zu gross ist oder teure Talente besitzt." + "$unit($unit) cannot travel through the wormhole in $region($region) because the unit is either too big or has restricted skills." + "$unit($unit) cannot travel through the wormhole in $region($region) because the unit is either too big or has restricted skills." + + + + + + + "$unit($unit) reist durch ein Wurmloch nach $region($region)." + "$unit($unit) travels through a wormhole to $region($region)." + "$unit($unit) travels through a wormhole to $region($region)." + + + + + + "In $region($region) erscheint ein Wurmloch." + "A wormhole appears in $region($region)." + "A wormhole appears in $region($region)." + + + + + + "Das Wurmloch in $region($region) schließt sich." + "The wormhole in $region($region) disappears." + "The wormhole in $region($region) disappears." + + + + + + + "$int($amount) Krieger von $unit($unit) benutzen ihre Flammenschwerter." + "$int($amount) fighters of $unit($unit) are using their flaming sword." + + + + + + + "$int($amount) Krieger von $unit($unit) feuern ihre Katapulte ab." + "$int($amount) fighters of $unit($unit) launch their catapults." + + + + + + "Der Kampf wurde ausgelöst von ${factions}." + "The battle was initiated by ${factions}." + + + + + + "$unit($unit) konnte durch einen Heiltrank überleben." + "$unit($unit) was saved by a haling potion." + + + + + + "$unit($unit) konnte dem Gegner eine Falle stellen." + "$unit($unit) lured the enemy into an ambush." + + + + + + "$unit($unit) überrascht den Gegner." + "$unit($unit) surprises the enemies." + + + + + + + "$unit($unit) versucht $spell($spell) zu zaubern, doch der Zauber schlägt fehl!" + "$unit($unit) tries to cast $spell($spell), but the spell fails!" + + + + + "Der Kampf wurde abgebrochen, da alle Verteidiger flohen." + "The battle was aborted because all enemies escaped." + + + + + + "... in der $int($row). Kampflinie:" + "... in combat rank $int($row):" + + + + + + + "$unit($mage) zaubert $spell($spell), aber niemand war in Reichweite." + "$unit($mage) casts $spell($spell), but nobody was in range." + + + + + + "Einheiten nach dem Kampf:" + "Units after the battle:" + + + + + + "" + "" + + + + + + + + + "$unit($mage) ruft $int($amount) $race($race, $amount) zu Hilfe." + "$unit($mage) calls for the help of $int($amount) $race($race, $amount)." + + + + + + + "$unit($mage) beschwört Trugbilder herauf." + "$unit($mage) summons a mirage." + + + + + + + "$unit($mage) murmelt eine düster klingende Formel. Ein plötzlicher Tumult entsteht, der sich jedoch schnell wieder legt." + + + + + + + "$unit($mage) murmelt eine düster klingende Formel. Ein plötzlicher Tumult entsteht und bringt die Kampfaufstellung durcheinander." + + + + + + + "$unit($mage) stimmt einen seltsamen Gesang an. Ein plötzlicher Tumult entsteht, der sich jedoch schnell wieder legt." + + + + + + + "$unit($mage) stimmt einen seltsamen Gesang an. Ein plötzlicher Tumult entsteht und bringt die Kampfaufstellung durcheinander." + "$unit($mage) begins a mysterious chant. great confusion sweeps through the ranks of the enemy." + + + + + + + + "$unit($mage) läßt die Mauern von $building($building) in einem unheimlichen magischen Licht erglühen." + + + + + + + "Einheiten vor der $int($turn). Runde:" + "Units before turn $int($turn):" + + + + + + "In $region($region) findet ein Kampf statt." + "There is a battle in $region($region)." + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($dead) $if($eq($dead,1),"Krieger wurde", "Krieger wurden") getötet." + "$unit($mage) casts $spell($spell): $int($dead) $if($eq($dead,1),"enemy was", "enemies were") killed." + + + + + + + + "$unit($mage) läßt die Erde in $region($region) erzittern." + "$unit($mage) shakes the earth in $region($region)." + + + + + + + + "$unit($mage) verflucht das Land in $region($region), und eine Dürreperiode beginnt." + "$unit($mage) puts a curse on the lands of $region($region) and a drought sets in." + + + + + + + "$unit($mage) erschafft einen Klon." + "$unit($mage) creates a clone." + + + + + + + + + "$unit($mage) verliert sich in die Träume von $unit($unit) und erhält einen Eindruck von $region($region)." + + + + + + + + + "$unit($mage) verschafft $unit($unit) ein schönes Nachtleben in $region($region)." + + + + + + + + "$unit($mage) sorgt für schlechten Schlaf in $region($region)." + + + + + + + + + "$unit($mage) beschwört $int($amount) $race($race,$amount)." + "$unit($mage) summons $int($amount) $race($race,$amount)." + + + + + + + + + "$unit($mage) erschafft in $region($region) eine verheerende Feuersbrunst. $int($amount) Bäume fallen den Flammen zum Opfer." + "$unit($mage) creates a flaming inferno in $region($region). $int($amount) trees fall vistim to the flames." + + + + + + + + "Mit einem Ritual bindet $unit($mage) die magischen Kräfte der Erde in die Mauern von $building($building)." + + + + + + + + "$unit($mage) weight $building($building)." + "$unit($mage) blesses $building($building)." + + + + + + + + "$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Eis schmilzt und verwandelt sich in Morast. Reißende Ströme spülen die mageren Felder weg und ersäufen Mensch und Tier. Was an Bauten nicht den Fluten zum Opfer fiel, verschlingt der Morast. Die sengende Hitze verändert die Region für immer." + + + + + + + + "$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Die Felder verdorren und Pferde verdursten. Die Hungersnot kostet vielen Bauern das Leben. Vertrocknete Bäume recken ihre kahlen Zweige in den blauen Himmel, von dem erbarmungslos die sengende Sonne brennt." + + + + + + + + "$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Die Felder verdorren und Pferde verdursten. Die Hungersnot kostet vielen Bauern das Leben. Vertrocknete Bäume recken ihre kahlen Zweige in den blauen Himmel, von dem erbarmungslos die sengende Sonne brennt. Die Dürre verändert die Region für immer." + + + + + + + + "$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Das Eis zerbricht und eine gewaltige Flutwelle verschlingt die Region." + + + + "Die Darbietungen eines fahrenden Gauklers begeistern die Leute. Die fröhliche und ausgelassene Stimmung seiner Lieder überträgt sich auf alle Zuhörer." + "A touring minstrel entertains the locals. The joyous and generous disposition of his songs prove infectious." + + + + + + + "Die Darbietungen von $unit($mage) begeistern die Leute. Die fröhliche und ausgelassene Stimmung seiner Lieder überträgt sich auf alle Zuhörer." + "$unit($mage) entertains the locals. The joyous and generous disposition of his songs prove infectious." + + + "In der Luft liegt ein wunderschönes Lied, dessen friedfertiger Stimmung sich niemand entziehen kann. Einige Leute werfen sogar ihre Waffen weg." + "A wondrous song fills the air and enchants the public. The song's peaceful melody makes several listeners drop their weapon." + + + + + + "Die Gesangskunst von $unit($mage) begeistert die Leute. Die friedfertige Stimmung des Lieds überträgt sich auf alle Zuhörer. Einige werfen ihre Waffen weg." + "The marvelous singing of $unit($mage) enchants the public. The song's peaceful melody makes several listeners drop their weapon." + + + + + + + "$unit($mage) beschwört $int($number) Dämonen aus dem Reich der Schatten." + "$unit($mage) summons $int($number) demons from the realm of shadows." + + + + + + + + "$unit($mage) zaubert $spell($spell)." + "$unit($mage) casts $spell($spell)." + + + + + + + + + + "$unit($mage) zaubert $spell($spell). $int($amount) Krieger verloren Erinnerungen, $int($dead) wurden getötet." + + + + + + + + + "$unit($mage) zaubert $spell($spell). $int($amount) Krieger verloren kurzzeitig ihr Gedächtnis." + "$unit($mage) casts $spell($spell). $int($amount) fighters are temporarily losing some of their memories." + + + + + + + + + "$unit($mage) ruft $int($amount) $race($race, 0) zu Hilfe." + + + + + + + + "$unit($unit) tötete $int($dead) Krieger." + "$unit($unit) killed $int($dead) opponents." + + + + + + + + + + "Heer $int($index)($abbrev): $int($dead) Tote, $int($fled) Geflohene, $int($survived) Überlebende." + "Army $int($index)($abbrev): $int($dead) dead, $int($fled) fled, $int($survived) survivors." + + + + + + + + "$unit($mage) in $region($region): '$order($command)' - Dieser Zauber kann nicht mit Stufenangabe gezaubert werden." + "$unit($mage) in $region($region): '$order($command)' - This spell cannot be cast with variable level." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dorthin führt kein Weg." + "$unit($unit) in $region($region): '$order($command)' - There is no way leading there." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Zu $region($target) kann kein Kontakt hergestellt werden." + "$unit($unit) in $region($region): '$order($command)' - $region($target) could not be contacted." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit $unit($target) hat keinen Kontakt mit uns aufgenommen." + "$unit($unit) in $region($region): '$order($command)' - The unit $unit($target) did not contact us." + + + + + + + + + "Antimagie von $unit.dative($self) blockiert in $region($region) einen Zauber von $unit.dative($mage)." + "In $region($region), anti-magic from $unit($self) blocks the spell of $unit($mage)." + + + + + + + + + "$unit($self) schwächt in $region($region) einen Zauber von $unit.dative($mage) durch Antimagie ab." + "In $region($region), anti-magic from $unit($self) reduces the effect of $unit($mage)'s spell." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $int($pacified) Regionen wurden befriedet." + "$unit($unit) in $region($region): '$order($command)' - $int($pacified) regions have been pacified." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Keine Region konnte befriedet werden." + "$unit($unit) in $region($region): '$order($command)' - No region could be pacified." + + + + + + + + "$unit($unit) in $region($region) bläst das Horn des Tanzes. In der ganzen Region breitet sich eine friedliche Feststimmmung aus." + "$unit($unit) in $region($region) blows the Horn of Dancing. Peaceful harmony spreads over the region." + + + + + + + + "$unit($unit) in $region($region) bläst das Horn des Tanzes, doch niemand hier lässt sich von Stimmung anstecken." + "$unit($unit) in $region($region) blows the Horn of Dancing, but nobody here gets into the mood." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die $ship($ship) wird jetzt schneller ihr Ziel erreichen." + "$unit($unit) in $region($region): '$order($command)' - The $ship($ship) will now be faster." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier fühlt sich durch den Trank magische gestärkt." + "$unit($unit) in $region($region): '$order($command)' - The mage is magically invigorated." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ausser sich vor Furcht geben die Bauern dem Barden $int($money) Silber." + "$unit($unit) in $region($region): '$order($command)' - Stricken with fear the peasants give the bard $int($money) silver." + + + + + + + + "$unit($unit) spielt einen Dudelsack. Ausser sich vor Furcht geben die Bauern $int($money) Silber." + "$unit($unit) plays the bagpipe. Stricken with fear the peasants give $int($money) silver." + + + + + + + + "$unit($unit) in $region($region) erschafft eine Akademie der Künste." + "$unit($unit) in $region($region) creates an academy of arts." + + + + + + + + "$unit($unit) in $region($region) erschafft eine Skulptur." + "$unit($unit) in $region($region) creates a sculpture." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Region ist zu weit entfernt." + "$unit($unit) in $region($region): '$order($command)' - That region is too far away." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Wege aus dieser Region sind blockiert." + "$unit($unit) in $region($region): '$order($command)' - The connections from to this regions are blocked." + + + + + + + "$unit($unit) erscheint plötzlich." + "$unit($unit) appears." + + + + + + + "$unit($unit) wird durchscheinend und verschwindet." + "$unit($unit) disappears." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) ist zu schwer." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) is too heavy." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei hat bereits $int($count) von $int($max) Helden." + "$unit($unit) in $region($region): '$order($command)' - The faction already has $int($count) of $int($max) heroes." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können keine Helden erwählen." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot be heroes." + + + + + + + + "$unit($unit) wird mit $int($cost) Silber zum Helden ernannt." + "$unit($unit) uses $int($cost) silber for a promotion." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nur $int($have) von $int($cost) benötigtem Silber." + "$unit($unit) in $region($region): '$order($command)' - The unit has $int($have) of $int($cost) silver required." + + + + + + + "Eine gewaltige Flutwelle verschlingt $region($region) und alle Bewohner." + "A tidal wave wipes out $region($region) and all who lived there." + + + + + + + + "Eine gewaltige Flutwelle verschlingt $unit($unit) in $region($region)." + "A tidal wave wipes out $region($region) and kills $unit($unit)." + + + + + + + + "$unit($unit) reaktiviert den astralen Schutzschild in $region($region)." + "$unit($unit) reactivates the astral protection shield in $region($region)." + + + + + + + + + + "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"kehrte auf seine", "kehrten auf ihre") Felder zurück." + "$unit($unit) in $region($region): $int($number) $race($race,$number) returned to the fields." + + + + + + + + + + "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"wurde zum Baum", "wurden zu Bäumen")." + "$unit($unit) in $region($region): $int($number) $race($race,$number) turned into $if($eq($number,1),"a tree", "trees")." + + + + + + + + + + "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"verfaulte", "verfaulten")." + "$unit($unit) in $region($region): $int($number) $race($race,$number) whithered and died." + + + + + + + + + + "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"zerfiel", "zerfielen") zu Staub." + "$unit($unit) in $region($region): $int($number) $race($race,$number) turned to dust." + + + + + + + + + + "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"verschwand", "verschwanden") über Nacht." + "$unit($unit) in $region($region): $int($number) $race($race,$number) disappearedin the night." + + + + + + + + + "Der Waldbrand in $region($region) griff auch auf $region($next) über, und $int($trees) verbrannten." + "The fire in $region($region) spread to $region($next) and $int($trees) were burnt." + + + + + + + + "$unit($mage) ruft in $region($region) eine Pest hervor." + "$unit($mage) sends the plague on $region($region)." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Eine Partei darf nicht aus mehr als $int($allowed) Einheiten bestehen." + "$unit($unit) in $region($region): '$order($command)' - A faction may not consist of more than $int($allowed) units." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Eine Allianz darf aus nicht mehr als $int($allowed) Einheiten bestehen." + "$unit($unit) in $region($region): '$order($command)' - An alliance may not consist of more than $int($allowed) units." + + + + + + + + + + "$unit($unit) in $region($region): $int($amount) $resource($item,$amount) zerfallen zu Staub." + "$unit($unit) in $region($region): $int($amount) $resource($item,$amount) turn to dust." + + + + + + + + + "Die $ship($ship) ist mit gutem Wind gesegnet$if($lt($duration,3),", doch der Zauber beginnt sich bereits aufzulösen",""). ($int36($id))" + "The $ship($ship) is blessed with favourable winds$if($lt($duration,3),", but the spell is starting to wear thin",""). ($int36($id))" + + + + + + + "Kräftige Stürme haben dieses Schiff in die Luft gehoben. ($int36($id))" + "Powerful storms have lifted this ship high into the air. ($int36($id))" + + + + + + + "Mächtige Magie verhindert den Kontakt zur Realität. ($int36($id))" + "Powerful magic disrupts our contact with reality. ($int36($id))" + + + + + + + + "Ein silberner Schimmer umgibt die $ship($ship). ($int36($id))" + "A silvery shimmer surrounds the $ship($ship). ($int36($id))" + + + + + + + + "Auf den Mauern von $building($building) erkennt man seltsame Runen. ($int36($id))" + "The walls of $building($building) are inscribed with strange runes. ($int36($id))" + + + + + + + + + "$unit($mage) erschafft $int($number) $resource($item,$number)." + "$unit($mage) creates $int($number) $resource($item,$number)." + + + + + + + + "Auf den Planken von $ship($ship) erkennt man seltsame Runen. ($int36($id))" + "The plank of $ship($ship) are inscribed with strange runes. ($int36($id))" + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Kompassnadel springt wild hin und her und es lässt sich keine Richtung erkennen." + "$unit($unit) in $region($region): '$order($command)' - The needle jumps wildly and there is no specific direction recognizable." + "$unit($unit) in $region($region): '$order($command)' - The needle jumps wildly and there is no specific direction recognizable." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Kompassnadel zeigt nach $direction($dir)." + "$unit($unit) in $region($region): '$order($command)' - The needle points $direction($dir)." + "$unit($unit) in $region($region): '$order($command)' - The needle points $direction($dir)." + + + + + + + + "$unit($unit) wird aus der astralen Ebene nach $region($region) geschleudert." + "$unit($unit) is sent from the astral plain to $region($region)." + "$unit($unit) is sent from the astral plain to $region($region)." + + + + + + + + "$unit($target) wird von $unit($unit) in eine andere Welt geschleudert." + "$unit($unit) sends $unit($target) to another world." + "$unit($unit) sends $unit($target) to another world." + + + + + + + + "$unit($unit) versuchte erfolglos, $unit($target) in eine andere Welt zu schleudern." + "$unit($unit) tried but failed to send $unit($target) to another world." + "$unit($unit) tried but failed to send $unit($target) to another world." + + + + + + + "NUMMER PARTEI $int36($id): Die Partei kann nicht mehr als einmal ihre Nummer wecheln." + "NUMBER FACTION $int36($id): Your faction can only change its number once." + + + + + + + "NUMMER PARTEI $int36($id): Diese Nummer wird von einer anderen Partei benutzt." + "NUMBER FACTION $int36($id): This number is being used by another faction." + + + + + + + + "Eine Botschaft von $unit($unit): '$message'" + "A message from $unit($unit): '$message'" + + + + + + + + "Plötzlich stolpert $unit($unit) über einige $localize($name). Nach kurzem Zögern entschließen die $localize($name), sich Deiner Partei anzuschließen." + + + + + + + "$unit($unit) entdeckt ein kleines Dorf. Die meisten Häuser wurden durch einen über die Ufer getretenen Fluß zerstört. Eine Gruppe der verzweifelten Menschen schließt sich deiner Partei an." + "$unit($unit) discovers a small village. Most of the houses have been destroyed by flooding, and a group of the distressed villagers join your faction." + + + + "Ein Bauernmob erhebt sich und macht Jagd auf Schwarzmagier." + "An angry mob forms and hunts practitioners of the dark arts." + + + + + + + "Vertrauter von $unit($unit)" + "Familiar of $unit($unit)" + + + + + + + + + "$unit($unit) rekrutiert $int($amount) $localize($archetype)." + "$unit($unit) recruits $int($amount) $localize($archetype)." + + + + + + + "Dein Passwort enthält Zeichen, die bei der Nachsendung von Reports Probleme bereiten können. Bitte beachte, dass Passwortenur aus Buchstaben von A bis Z und Zahlen bestehen dürfen. Dein neues Passwort ist '${newpass}'." + "Your password was changed because it contained illegal characters. Legal passwords may only contain numbers and letters from A to Z. Your new Password is '${newpass}'." + + + + "Miiauuuuuu..." + "Meeoooooow..." + + + + + + + "Die Götter segnen $unit($unit) mit der richtigen Rasse." + "The gods are blessing $unit($unit) with the correct race." + + + + + + + "Der Versuch, die Greifenschwingen zu benutzen, schlug fehl. $unit($unit) konnte die Ebene der Herausforderung nicht verlassen." + + + + + + + "$unit($unit) springt in die ewigen Feuer des Kraters." + + + + + + + + "$unit($unit) springt in die ewigen Feuer des Kraters." + + + + + + + + "In $region($region) erklingt die Stimme des Torwächters: 'Nur wer ohne materielle Güter und noch lernbegierig ist, der darf die Ebene der Herausforderung betreten. Und vergiß nicht mein Trinkgeld.'. $unit($unit) erhielt keinen Einlaß." + + + + + + + + "In $region($region) öffnet sich ein Portal. Eine Stimme ertönt, und spricht: 'Willkommen in der Ebene der Herausforderung'. $unit($unit) durchschreitet das Tor zu einer anderen Welt." + + + + + + + "$unit($unit) scheint von einer seltsamen Krankheit befallen." + "$unit($unit) is stricken by a strange disease." + + + + + + + + + "$unit($unit) erbeutet $int($amount) $resource($item,$amount)." + "$unit($unit) collects $int($amount) $resource($item,$amount)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es ist so schön friedlich, man möchte hier niemanden angreifen." + "$unit($unit) in $region($region): '$order($command)' - It's so quiet and peaceful, nobody wants to attack anybody right now." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können nichts lernen." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot study." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Migranten können keine kostenpflichtigen Talente lernen." + "$unit($unit) in $region($region): '$order($command)' - Migrants cannot study this." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es kann maximal $int($amount) Magier pro Partei geben." + "$unit($unit) in $region($region): '$order($command)' - There may not be more tha $int($amount) magicians in your faction." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es kann maximal $int($amount) Alchemisten pro Partei geben." + "$unit($unit) in $region($region): '$order($command)' - There may not be more tha $int($amount) alchemists in your faction." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) versteht unsere Art von Magie nicht." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) does not understand our kind of magic." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Kapitän muß ein Segeltalent von mindestens $int($value) haben, um $ship($ship) zu befehligen." + "$unit($unit) in $region($region): '$order($command)' - The captain needs a sailing skill of at least $int($value), to command $ship($ship)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In dieser Region gibt es keine Brücken und Straßen mehr zu bauen." + "$unit($unit) in $region($region): '$order($command)' - the roads and bridges in this region are complete." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Um $localize($name) zu bauen, braucht man ein Talent von mindestens $int($value)." + "$unit($unit) in $region($region): '$order($command)' - To build $localize($name) requires a skill of at least $int($value)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diese Einheit kämpft nicht." + "$unit($unit) in $region($region): '$order($command)' - This unit will not fight." + + + + + + + + + "$unit($unit) erhielt $resources($items) von der $ship($ship)." + "$unit($unit) received $resources($items) from the $ship($ship)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nciht auf Untote gezaubert werden." + + + + + + + + "Achtung: $faction($faction) hat seit $int($turns) Wochen keine + Züge eingeschickt und könnte dadurch in Kürze aus dem Spiel + ausscheiden." + "Warning: $faction($faction) has not been sending in + orders for $int($turns) turns and may be leaving the game soon." + + + diff --git a/res/prefixes.xml b/res/prefixes.xml index 0e8e9587a..596c16afe 100644 --- a/res/prefixes.xml +++ b/res/prefixes.xml @@ -1,31 +1,31 @@ - - - Dunkel - Licht - Klein - Hoch - Huegel - Berg - Wald - Sumpf - Schnee - Sonnen - Mond - See - Tal - Schatten - Hoehlen - Blut - Wild - Chaos - Nacht - Nebel - Grau - Frost - Finster - Duester - flame - ice - star - black - + + + Dunkel + Licht + Klein + Hoch + Huegel + Berg + Wald + Sumpf + Schnee + Sonnen + Mond + See + Tal + Schatten + Hoehlen + Blut + Wild + Chaos + Nacht + Nebel + Grau + Frost + Finster + Duester + flame + ice + star + black + diff --git a/res/resources/horse.xml b/res/resources/horse.xml index abf6d856d..b5498ab2a 100644 --- a/res/resources/horse.xml +++ b/res/resources/horse.xml @@ -1,11 +1,11 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/res/resources/hp.xml b/res/resources/hp.xml index fb1b6e32f..95ff2200b 100644 --- a/res/resources/hp.xml +++ b/res/resources/hp.xml @@ -1,5 +1,5 @@ - - - - - + + + + + diff --git a/res/resources/iron.xml b/res/resources/iron.xml index 94dbc6390..89ae30198 100644 --- a/res/resources/iron.xml +++ b/res/resources/iron.xml @@ -1,12 +1,12 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/res/resources/laen.xml b/res/resources/laen.xml index efb13c5ed..1814bbf1a 100644 --- a/res/resources/laen.xml +++ b/res/resources/laen.xml @@ -1,10 +1,10 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/res/resources/log.xml b/res/resources/log.xml index c017682fc..a1b719c33 100644 --- a/res/resources/log.xml +++ b/res/resources/log.xml @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/res/resources/mallorn.xml b/res/resources/mallorn.xml index e5c01506b..faddfde3e 100644 --- a/res/resources/mallorn.xml +++ b/res/resources/mallorn.xml @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/res/resources/mallornseed.xml b/res/resources/mallornseed.xml index 1c7c1a800..25b0c2cf8 100644 --- a/res/resources/mallornseed.xml +++ b/res/resources/mallornseed.xml @@ -1,6 +1,6 @@ - - - - - - + + + + + + diff --git a/res/resources/peasant.xml b/res/resources/peasant.xml index 32e1e1ca1..ab60d333e 100644 --- a/res/resources/peasant.xml +++ b/res/resources/peasant.xml @@ -1,5 +1,5 @@ - - - - - + + + + + diff --git a/res/resources/seed.xml b/res/resources/seed.xml index 2193fb8c8..62efedf4e 100644 --- a/res/resources/seed.xml +++ b/res/resources/seed.xml @@ -1,6 +1,6 @@ - - - - - - + + + + + + diff --git a/res/resources/stone.xml b/res/resources/stone.xml index eed2fd2df..2ea5401c1 100644 --- a/res/resources/stone.xml +++ b/res/resources/stone.xml @@ -1,11 +1,11 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/res/ships.xml b/res/ships.xml index 6c6821be4..763fee3f3 100644 --- a/res/ships.xml +++ b/res/ships.xml @@ -1,83 +1,83 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/spells.xml b/res/spells.xml index 080365c55..72f834bba 100644 --- a/res/spells.xml +++ b/res/spells.xml @@ -1,204 +1,204 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/spoils.xml b/res/spoils.xml index 952971cab..585372527 100644 --- a/res/spoils.xml +++ b/res/spoils.xml @@ -1,59 +1,59 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/terrains.xml b/res/terrains.xml index edd8895ab..d3896193b 100644 --- a/res/terrains.xml +++ b/res/terrains.xml @@ -1,84 +1,84 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/weapons/axe.xml b/res/weapons/axe.xml index 7ee77b21e..5f784865d 100644 --- a/res/weapons/axe.xml +++ b/res/weapons/axe.xml @@ -1,14 +1,14 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/res/weapons/bow.xml b/res/weapons/bow.xml index c64392966..0e57cfdf9 100644 --- a/res/weapons/bow.xml +++ b/res/weapons/bow.xml @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/res/weapons/catapult.xml b/res/weapons/catapult.xml index 2ea16d9a2..4ae3324da 100644 --- a/res/weapons/catapult.xml +++ b/res/weapons/catapult.xml @@ -1,14 +1,14 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/res/weapons/crossbow.xml b/res/weapons/crossbow.xml index 318628b81..76e7e36ff 100644 --- a/res/weapons/crossbow.xml +++ b/res/weapons/crossbow.xml @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/res/weapons/firesword.xml b/res/weapons/firesword.xml index 9e8284fe6..72dbb11d1 100644 --- a/res/weapons/firesword.xml +++ b/res/weapons/firesword.xml @@ -1,10 +1,10 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/res/weapons/greatbow.xml b/res/weapons/greatbow.xml index 542bd41a8..0af009a6b 100644 --- a/res/weapons/greatbow.xml +++ b/res/weapons/greatbow.xml @@ -1,18 +1,18 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/res/weapons/greatsword.xml b/res/weapons/greatsword.xml index 481ff680c..ed1ea5118 100644 --- a/res/weapons/greatsword.xml +++ b/res/weapons/greatsword.xml @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/res/weapons/halberd.xml b/res/weapons/halberd.xml index bf3fb4af7..0875f69c5 100644 --- a/res/weapons/halberd.xml +++ b/res/weapons/halberd.xml @@ -1,15 +1,15 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/res/weapons/laensword.xml b/res/weapons/laensword.xml index 31ec8b9e6..cc037f11a 100644 --- a/res/weapons/laensword.xml +++ b/res/weapons/laensword.xml @@ -1,12 +1,12 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/res/weapons/lance.xml b/res/weapons/lance.xml index 1271c48f9..31146f7ce 100644 --- a/res/weapons/lance.xml +++ b/res/weapons/lance.xml @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/res/weapons/mallornbow.xml b/res/weapons/mallornbow.xml index f61ea8e97..12c6e374b 100644 --- a/res/weapons/mallornbow.xml +++ b/res/weapons/mallornbow.xml @@ -1,16 +1,16 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/res/weapons/mallorncrossbow.xml b/res/weapons/mallorncrossbow.xml index 8d4a5027b..ddf501046 100644 --- a/res/weapons/mallorncrossbow.xml +++ b/res/weapons/mallorncrossbow.xml @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/res/weapons/mallornlance.xml b/res/weapons/mallornlance.xml index 88973f3e0..20ec02b93 100644 --- a/res/weapons/mallornlance.xml +++ b/res/weapons/mallornlance.xml @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/res/weapons/mallornspear.xml b/res/weapons/mallornspear.xml index 8c3782e4c..e0680bd6c 100644 --- a/res/weapons/mallornspear.xml +++ b/res/weapons/mallornspear.xml @@ -1,14 +1,14 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/res/weapons/rep_crossbow.xml b/res/weapons/rep_crossbow.xml index 1e550a190..98b64dc37 100644 --- a/res/weapons/rep_crossbow.xml +++ b/res/weapons/rep_crossbow.xml @@ -1,16 +1,16 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/res/weapons/runesword.xml b/res/weapons/runesword.xml index 566fe1589..9f99df003 100644 --- a/res/weapons/runesword.xml +++ b/res/weapons/runesword.xml @@ -1,10 +1,10 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/res/weapons/rustyaxe.xml b/res/weapons/rustyaxe.xml index 5399de62d..73905f0e7 100644 --- a/res/weapons/rustyaxe.xml +++ b/res/weapons/rustyaxe.xml @@ -1,14 +1,14 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/res/weapons/rustygreatsword.xml b/res/weapons/rustygreatsword.xml index ac1385b11..736a40172 100644 --- a/res/weapons/rustygreatsword.xml +++ b/res/weapons/rustygreatsword.xml @@ -1,12 +1,12 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/res/weapons/rustyhalberd.xml b/res/weapons/rustyhalberd.xml index 4f237b989..9c227ad62 100644 --- a/res/weapons/rustyhalberd.xml +++ b/res/weapons/rustyhalberd.xml @@ -1,15 +1,15 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/res/weapons/rustysword.xml b/res/weapons/rustysword.xml index f73dcd6e2..be139b8df 100644 --- a/res/weapons/rustysword.xml +++ b/res/weapons/rustysword.xml @@ -1,12 +1,12 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/res/weapons/spear.xml b/res/weapons/spear.xml index c6479707a..4f628408d 100644 --- a/res/weapons/spear.xml +++ b/res/weapons/spear.xml @@ -1,14 +1,14 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/res/weapons/sword.xml b/res/weapons/sword.xml index 0d3830e2e..0276acb39 100644 --- a/res/weapons/sword.xml +++ b/res/weapons/sword.xml @@ -1,12 +1,12 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/scripts/callbacks.lua b/scripts/callbacks.lua index 33d34e4b5..636607829 100644 --- a/scripts/callbacks.lua +++ b/scripts/callbacks.lua @@ -1,11 +1,11 @@ -callbacks = {} - -callbacks["attrib_init"] = function(attr) - if attr.name ~= nil then - local init = callbacks["init_" .. attr.name] - if init ~=nil then - init(attr) - end - end -end - +callbacks = {} + +callbacks["attrib_init"] = function(attr) + if attr.name ~= nil then + local init = callbacks["init_" .. attr.name] + if init ~=nil then + init(attr) + end + end +end + diff --git a/scripts/default.lua b/scripts/default.lua index 7afd5fa8b..fd6361db6 100644 --- a/scripts/default.lua +++ b/scripts/default.lua @@ -1,121 +1,121 @@ -function change_locales(localechange) - for loc, flist in pairs(localechange) do - for index, name in pairs(flist) do - f = get_faction(atoi36(name)) - if f ~= nil then - f.locale = loc - print("LOCALECHANGE ", f, loc) - end - end - end -end - -function dbupdate() - update_scores() - edb = db.open(config.basepath.."/eressea.db") - if edb~=nil then - edb:update_factions() - edb:update_scores() - else - print("could no open "..config.basepath.."/eressea.db") - end -end - -function nmr_check(maxnmrs) - local nmrs = get_nmrs(1) - if nmrs >= maxnmrs then - print("Shit. More than " .. maxnmrs .. " factions with 1 NMR (" .. nmrs .. ")") - write_summary() - write_game("aborted.dat") - return -1 - end - print (nmrs .. " Factions with 1 NMR") - return 0 -end - -function open_game(turn) - file = "" .. get_turn() - if read_game(file .. ".dat", "binary")~=0 then - return read_game(file, "text") - end - return 0 -end - -function write_emails(locales) - local files = {} - local key - local locale - local file - for key, locale in pairs(locales) do - files[locale] = io.open(config.basepath .. "/emails." .. locale, "w") - end - - local faction - for faction in factions() do - if faction.email~="" then - files[faction.locale]:write(faction.email .. "\n") - end - end - - for key, file in pairs(files) do - file:close() - end -end - -function write_addresses() - local file - local faction - - file = io.open(config.basepath .. "/adressen", "w") - for faction in factions() do - -- print(faction.id .. " - " .. faction.locale) - file:write(tostring(faction) .. ":" .. faction.email .. ":" .. faction.info .. "\n") - end - - file:close() -end - -function write_aliases() - local file - local faction - - file = io.open(config.basepath .. "/aliases", "w") - for faction in factions() do - local unit - if faction.email ~= "" then - file:write("partei-" .. itoa36(faction.id) .. ": " .. faction.email .. "\n") - for unit in faction.units do - file:write("einheit-" .. itoa36(unit.id) .. ": " .. faction.email .. "\n") - end - end - end - - file:close() -end - -function write_files(locales) - write_passwords() - write_reports() - write_summary() - -- write_emails(locales) - -- write_aliases() - -- write_addresses() -end - -function write_scores() - scores = {} - for r in regions() do - f = r.owner - if f~=nil then - value = scores[f.id] - if value==nil then value=0 end - value = value + r:get_resource("money")/100 - scores[f.id] = value - end - end - for f in factions() do - score=scores[f.id] - if score==nil then score=0 end - print(math.floor(score)..":"..f.name..":"..itoa36(f.id)) - end -end +function change_locales(localechange) + for loc, flist in pairs(localechange) do + for index, name in pairs(flist) do + f = get_faction(atoi36(name)) + if f ~= nil then + f.locale = loc + print("LOCALECHANGE ", f, loc) + end + end + end +end + +function dbupdate() + update_scores() + edb = db.open(config.basepath.."/eressea.db") + if edb~=nil then + edb:update_factions() + edb:update_scores() + else + print("could no open "..config.basepath.."/eressea.db") + end +end + +function nmr_check(maxnmrs) + local nmrs = get_nmrs(1) + if nmrs >= maxnmrs then + print("Shit. More than " .. maxnmrs .. " factions with 1 NMR (" .. nmrs .. ")") + write_summary() + write_game("aborted.dat") + return -1 + end + print (nmrs .. " Factions with 1 NMR") + return 0 +end + +function open_game(turn) + file = "" .. get_turn() + if read_game(file .. ".dat", "binary")~=0 then + return read_game(file, "text") + end + return 0 +end + +function write_emails(locales) + local files = {} + local key + local locale + local file + for key, locale in pairs(locales) do + files[locale] = io.open(config.basepath .. "/emails." .. locale, "w") + end + + local faction + for faction in factions() do + if faction.email~="" then + files[faction.locale]:write(faction.email .. "\n") + end + end + + for key, file in pairs(files) do + file:close() + end +end + +function write_addresses() + local file + local faction + + file = io.open(config.basepath .. "/adressen", "w") + for faction in factions() do + -- print(faction.id .. " - " .. faction.locale) + file:write(tostring(faction) .. ":" .. faction.email .. ":" .. faction.info .. "\n") + end + + file:close() +end + +function write_aliases() + local file + local faction + + file = io.open(config.basepath .. "/aliases", "w") + for faction in factions() do + local unit + if faction.email ~= "" then + file:write("partei-" .. itoa36(faction.id) .. ": " .. faction.email .. "\n") + for unit in faction.units do + file:write("einheit-" .. itoa36(unit.id) .. ": " .. faction.email .. "\n") + end + end + end + + file:close() +end + +function write_files(locales) + write_passwords() + write_reports() + write_summary() + -- write_emails(locales) + -- write_aliases() + -- write_addresses() +end + +function write_scores() + scores = {} + for r in regions() do + f = r.owner + if f~=nil then + value = scores[f.id] + if value==nil then value=0 end + value = value + r:get_resource("money")/100 + scores[f.id] = value + end + end + for f in factions() do + score=scores[f.id] + if score==nil then score=0 end + print(math.floor(score)..":"..f.name..":"..itoa36(f.id)) + end +end diff --git a/scripts/dumptable.lua b/scripts/dumptable.lua index 58f10e8df..ecddbdfa0 100644 --- a/scripts/dumptable.lua +++ b/scripts/dumptable.lua @@ -1,95 +1,95 @@ ---------------------------------------------- --- Return indentation string for passed level ---------------------------------------------- -local function tabs(i) - return string.rep(".",i).." " -- Dots followed by a space -end - ------------------------------------------------------------ --- Return string representation of parameter's value & type ------------------------------------------------------------ -local function toStrType(t) - local function fttu2hex(t) -- Grab hex value from tostring() output - local str = tostring(t); - if str == nil then - return "tostring() failure! \n" - else - local str2 = string.match(str,"[ :][ (](%x+)") - if str2 == nil then - return "string.match() failure: "..str.."\n" - else - return "0x"..str2 - end - end - end - -- Stringify a value of a given type using a table of functions keyed - -- by the name of the type (Lua's version of C's switch() statement). - local stringify = { - -- Keys are all possible strings that type() may return, - -- per http://www.lua.org/manual/5.1/manual.html#pdf-type. - ["nil"] = function(v) return "nil (nil)" end, - ["string"] = function(v) return '"'..v..'" (string)' end, - ["number"] = function(v) return v.." (number)" end, - ["boolean"] = function(v) return tostring(v).." (boolean)" end, - ["function"] = function(v) return fttu2hex(v).." (function)" end, - ["table"] = function(v) return fttu2hex(v).." (table)" end, - ["thread"] = function(v) return fttu2hex(v).." (thread)" end, - ["userdata"] = function(v) return fttu2hex(v).." (userdata)" end - } - return stringify[type(t)](t) -end - -------------------------------------- --- Count elements in the passed table -------------------------------------- -local function lenTable(t) -- What Lua builtin does this simple thing? - local n=0 -- '#' doesn't work with mixed key types - if ("table" == type(t)) then - for key in pairs(t) do -- Just count 'em - n = n + 1 - end - return n - else - return nil - end -end - --------------------------------- --- Pretty-print the passed table --------------------------------- -local function do_dumptable(t, indent, seen) - -- "seen" is an initially empty table used to track all tables - -- that have been dumped so far. No table is dumped twice. - -- This also keeps the code from following self-referential loops, - -- the need for which was found when first dumping "_G". - if ("table" == type(t)) then -- Dump passed table - seen[t] = 1 - if (indent == 0) then - print ("The passed table has "..lenTable(t).." entries:") - indent = 1 - end - for f,v in pairsByKeys(t) do - if ("table" == type(v)) and (seen[v] == nil) then -- Recurse - print( tabs(indent)..toStrType(f).." has "..lenTable(v).." entries: {") - do_dumptable(v, indent+1, seen) - print( tabs(indent).."}" ) - else - print( tabs(indent)..toStrType(f).." = "..toStrType(v)) - end - end - else - print (tabs(indent).."Not a table!") - end -end - --------------------------------- --- Wrapper to handle persistence --------------------------------- -function dumptable(t) -- Only global declaration in the package - -- This wrapper exists only to set the environment for the first run: - -- The second param is the indentation level. - -- The third param is the list of tables dumped during this call. - -- Getting this list allocated and freed was a pain, and this - -- wrapper was the best solution I came up with... - return do_dumptable(t, 0, {}) -end +--------------------------------------------- +-- Return indentation string for passed level +--------------------------------------------- +local function tabs(i) + return string.rep(".",i).." " -- Dots followed by a space +end + +----------------------------------------------------------- +-- Return string representation of parameter's value & type +----------------------------------------------------------- +local function toStrType(t) + local function fttu2hex(t) -- Grab hex value from tostring() output + local str = tostring(t); + if str == nil then + return "tostring() failure! \n" + else + local str2 = string.match(str,"[ :][ (](%x+)") + if str2 == nil then + return "string.match() failure: "..str.."\n" + else + return "0x"..str2 + end + end + end + -- Stringify a value of a given type using a table of functions keyed + -- by the name of the type (Lua's version of C's switch() statement). + local stringify = { + -- Keys are all possible strings that type() may return, + -- per http://www.lua.org/manual/5.1/manual.html#pdf-type. + ["nil"] = function(v) return "nil (nil)" end, + ["string"] = function(v) return '"'..v..'" (string)' end, + ["number"] = function(v) return v.." (number)" end, + ["boolean"] = function(v) return tostring(v).." (boolean)" end, + ["function"] = function(v) return fttu2hex(v).." (function)" end, + ["table"] = function(v) return fttu2hex(v).." (table)" end, + ["thread"] = function(v) return fttu2hex(v).." (thread)" end, + ["userdata"] = function(v) return fttu2hex(v).." (userdata)" end + } + return stringify[type(t)](t) +end + +------------------------------------- +-- Count elements in the passed table +------------------------------------- +local function lenTable(t) -- What Lua builtin does this simple thing? + local n=0 -- '#' doesn't work with mixed key types + if ("table" == type(t)) then + for key in pairs(t) do -- Just count 'em + n = n + 1 + end + return n + else + return nil + end +end + +-------------------------------- +-- Pretty-print the passed table +-------------------------------- +local function do_dumptable(t, indent, seen) + -- "seen" is an initially empty table used to track all tables + -- that have been dumped so far. No table is dumped twice. + -- This also keeps the code from following self-referential loops, + -- the need for which was found when first dumping "_G". + if ("table" == type(t)) then -- Dump passed table + seen[t] = 1 + if (indent == 0) then + print ("The passed table has "..lenTable(t).." entries:") + indent = 1 + end + for f,v in pairsByKeys(t) do + if ("table" == type(v)) and (seen[v] == nil) then -- Recurse + print( tabs(indent)..toStrType(f).." has "..lenTable(v).." entries: {") + do_dumptable(v, indent+1, seen) + print( tabs(indent).."}" ) + else + print( tabs(indent)..toStrType(f).." = "..toStrType(v)) + end + end + else + print (tabs(indent).."Not a table!") + end +end + +-------------------------------- +-- Wrapper to handle persistence +-------------------------------- +function dumptable(t) -- Only global declaration in the package + -- This wrapper exists only to set the environment for the first run: + -- The second param is the indentation level. + -- The third param is the list of tables dumped during this call. + -- Getting this list allocated and freed was a pain, and this + -- wrapper was the best solution I came up with... + return do_dumptable(t, 0, {}) +end diff --git a/scripts/gates.lua b/scripts/gates.lua index aeb1e2a3c..e02c0f326 100644 --- a/scripts/gates.lua +++ b/scripts/gates.lua @@ -1,25 +1,25 @@ --- implements gates and travel between them --- used in HSE and Eressea - -function gate_travel(b, units) - -- we've found which units we want to exchange, now swap them: - local u - for key, u in pairs(units) do - u.region = b.region - u.building = b - end -end - -function gate_units(b, maxsize) - local size = maxsize - local units = {} - local u - - for u in b.units do - if u.number<=size and u.weight<=u.capacity then - units[u] = u - size = size - u.number - end - end - return units -end +-- implements gates and travel between them +-- used in HSE and Eressea + +function gate_travel(b, units) + -- we've found which units we want to exchange, now swap them: + local u + for key, u in pairs(units) do + u.region = b.region + u.building = b + end +end + +function gate_units(b, maxsize) + local size = maxsize + local units = {} + local u + + for u in b.units do + if u.number<=size and u.weight<=u.capacity then + units[u] = u + size = size - u.number + end + end + return units +end diff --git a/scripts/init.lua b/scripts/init.lua index ae39c50b2..0b9c150c6 100644 --- a/scripts/init.lua +++ b/scripts/init.lua @@ -1,43 +1,43 @@ -require(config.game .. ".modules") -require "default" -require "resources" - -function run_editor() - local turn = get_turn() - if turn==0 then - turn = read_turn() - set_turn(turn) - end - read_game(turn .. ".dat") - gmtool.editor() -end - -function run_tests() - print("running tests") - require "lunit" - lunit.clearstats() - local argv = tests or {} - local stats = lunit.main(argv) - if stats.errors > 0 or stats.failed > 0 then - return 1 - end - return 0 -end - -function run_turn() - require(config.game .. ".main") - - local turn = get_turn() - if turn==0 then - turn = read_turn() - set_turn(turn) - end - - orderfile = orderfile or config.basepath .. '/orders.' .. turn - print("executing turn " .. get_turn() .. " with " .. orderfile) - local result = process(orderfile) - if result==0 then - dbupdate() - end - return result -end +require(config.game .. ".modules") +require "default" +require "resources" + +function run_editor() + local turn = get_turn() + if turn==0 then + turn = read_turn() + set_turn(turn) + end + read_game(turn .. ".dat") + gmtool.editor() +end + +function run_tests() + print("running tests") + require "lunit" + lunit.clearstats() + local argv = tests or {} + local stats = lunit.main(argv) + if stats.errors > 0 or stats.failed > 0 then + return 1 + end + return 0 +end + +function run_turn() + require(config.game .. ".main") + + local turn = get_turn() + if turn==0 then + turn = read_turn() + set_turn(turn) + end + + orderfile = orderfile or config.basepath .. '/orders.' .. turn + print("executing turn " .. get_turn() .. " with " .. orderfile) + local result = process(orderfile) + if result==0 then + dbupdate() + end + return result +end diff --git a/scripts/multis.lua b/scripts/multis.lua index ad0b77783..a090f8d3c 100644 --- a/scripts/multis.lua +++ b/scripts/multis.lua @@ -1,101 +1,101 @@ -function kill_nonstarters() - for f in factions() do - if f.lastturn==1 then - kill_faction(f, true) - end - end -end - -function kill_multis(multis, destructive) - for idx, fno in ipairs(multis) do - local f = get_faction(fno) - if f~=nil and f.email=="doppelspieler@eressea.de" then - kill_faction(f, destructive) - end - end -end - -function mark_multis(multis, block) - if multis~=nil then - for idx, fno in ipairs(multis) do - local f = get_faction(fno) - if f~=nil and f.email~="doppelspieler@eressea.de" then - print("* multi-player " .. tostring(f)) - mark_multi(f, block) - end - end - end -end - --- destroy a faction --- destructive: kill all of its buildings and the home region, too. - -function kill_faction(f, destructive) - for u in f.units do - local r = u.region - local b = u.building - unit.destroy(u) - if destructive and b~=nil then - building.destroy(b) - local nuke = true - for v in r.units do - if v.faction.id~=f.id then - -- print("cannot nuke: " .. tostring(v.faction)) - nuke = false - break - end - end - r.terrain_name = nil - if nuke and num_oceans(r)<=1 then - -- print("nuke!") - r.terrain = "ocean" - else - -- print("cannot nuke: > 1 oceans") - r.terrain = "glacier" - r.peasants = 10 - r:set_resource("money", 100) - b = building.create(r, "monument") - b.size = 1 - b.name = "Memento Mori" - b.info = "Eine kleine " .. translate("race::" .. f.race .."_x") .. "-Statue erinnert hier an ein verschwundenes Volk" - end - end - end - faction.destroy(f) -end - -local function mark_multi(f, block) - f.password = "doppelspieler" - f.email = "doppelspieler@eressea.de" - f.banner = "Diese Partei steht wegen vermuteten Doppelspiels unter Beobachtung." - for u in f.units do - u.race_name = "toad" - if block and u.building~=nil then - local found = false - for u2 in u.region.units do - if u2.faction.id~=u.faction.id then - found = true - break - end - end - if not found then - u.region.terrain_name = "firewall" - u.region:set_flag(2) -- RF_BLOCKED - end - end - end -end - -local function num_oceans(r) - local oceans = 0 - local p = r:next(5) - for d = 0,5 do - local n = r:next(d) - if p.terrain~="ocean" and n.terrain=="ocean" then - oceans = oceans +1 - end - p = n - end - return oceans -end - +function kill_nonstarters() + for f in factions() do + if f.lastturn==1 then + kill_faction(f, true) + end + end +end + +function kill_multis(multis, destructive) + for idx, fno in ipairs(multis) do + local f = get_faction(fno) + if f~=nil and f.email=="doppelspieler@eressea.de" then + kill_faction(f, destructive) + end + end +end + +function mark_multis(multis, block) + if multis~=nil then + for idx, fno in ipairs(multis) do + local f = get_faction(fno) + if f~=nil and f.email~="doppelspieler@eressea.de" then + print("* multi-player " .. tostring(f)) + mark_multi(f, block) + end + end + end +end + +-- destroy a faction +-- destructive: kill all of its buildings and the home region, too. + +function kill_faction(f, destructive) + for u in f.units do + local r = u.region + local b = u.building + unit.destroy(u) + if destructive and b~=nil then + building.destroy(b) + local nuke = true + for v in r.units do + if v.faction.id~=f.id then + -- print("cannot nuke: " .. tostring(v.faction)) + nuke = false + break + end + end + r.terrain_name = nil + if nuke and num_oceans(r)<=1 then + -- print("nuke!") + r.terrain = "ocean" + else + -- print("cannot nuke: > 1 oceans") + r.terrain = "glacier" + r.peasants = 10 + r:set_resource("money", 100) + b = building.create(r, "monument") + b.size = 1 + b.name = "Memento Mori" + b.info = "Eine kleine " .. translate("race::" .. f.race .."_x") .. "-Statue erinnert hier an ein verschwundenes Volk" + end + end + end + faction.destroy(f) +end + +local function mark_multi(f, block) + f.password = "doppelspieler" + f.email = "doppelspieler@eressea.de" + f.banner = "Diese Partei steht wegen vermuteten Doppelspiels unter Beobachtung." + for u in f.units do + u.race_name = "toad" + if block and u.building~=nil then + local found = false + for u2 in u.region.units do + if u2.faction.id~=u.faction.id then + found = true + break + end + end + if not found then + u.region.terrain_name = "firewall" + u.region:set_flag(2) -- RF_BLOCKED + end + end + end +end + +local function num_oceans(r) + local oceans = 0 + local p = r:next(5) + for d = 0,5 do + local n = r:next(d) + if p.terrain~="ocean" and n.terrain=="ocean" then + oceans = oceans +1 + end + p = n + end + return oceans +end + diff --git a/scripts/resources.lua b/scripts/resources.lua index 688fe3d1d..a861f53e4 100644 --- a/scripts/resources.lua +++ b/scripts/resources.lua @@ -1,89 +1,89 @@ -function peasant_getresource(u) - return u.region:get_resource("peasant") -end - -function peasant_changeresource(u, delta) - local p = u.region:get_resource("peasant") - p = p + delta - if p < 0 then - p = 0 - end - u.region:set_resource("peasant", p) - return p -end - -function hp_getresource(u) - return u.hp -end - -function hp_changeresource(u, delta) - local hp = u.hp + delta - - if hp < u.number then - if hp < 0 then - hp = 0 - end - u.number = hp - end - u.hp = hp - return hp -end - -function horse_limit(r) - return r:get_resource("horse") -end - -function horse_produce(r, n) - local horses = r:get_resource("horse") - if horses>=n then - r:set_resource("horse", horses-n) - else - r:set_resource("horse", 0) - end -end - -function log_limit(r) --- if r:get_flag(1) then -- RF_MALLORN --- return 0 --- end - return r:get_resource("tree") + r:get_resource("sapling") -end - -function log_produce(r, n) - local trees = r:get_resource("tree") - if trees>=n then - r:set_resource("tree", trees-n) - else - r:set_resource("tree", 0) - n = n - trees - trees = r:get_resource("sapling") - if trees>=n then - r:set_resource("sapling", trees-n) - else - r:set_resource("sapling", 0) - end - end -end - -function mallorn_limit(r) - if not r:get_flag(1) then -- RF_MALLORN - return 0 - end - return r:get_resource("tree") + r:get_resource("sapling") -end - -function mallorn_produce(r, n) - local trees = r:get_resource("tree") - if trees>=n then - r:set_resource("tree", trees-n) - else - r:set_resource("tree", 0) - n = n - trees - trees = r:get_resource("sapling") - if trees>=n then - r:set_resource("sapling", trees-n) - else - r:set_resource("sapling", 0) - end - end -end +function peasant_getresource(u) + return u.region:get_resource("peasant") +end + +function peasant_changeresource(u, delta) + local p = u.region:get_resource("peasant") + p = p + delta + if p < 0 then + p = 0 + end + u.region:set_resource("peasant", p) + return p +end + +function hp_getresource(u) + return u.hp +end + +function hp_changeresource(u, delta) + local hp = u.hp + delta + + if hp < u.number then + if hp < 0 then + hp = 0 + end + u.number = hp + end + u.hp = hp + return hp +end + +function horse_limit(r) + return r:get_resource("horse") +end + +function horse_produce(r, n) + local horses = r:get_resource("horse") + if horses>=n then + r:set_resource("horse", horses-n) + else + r:set_resource("horse", 0) + end +end + +function log_limit(r) +-- if r:get_flag(1) then -- RF_MALLORN +-- return 0 +-- end + return r:get_resource("tree") + r:get_resource("sapling") +end + +function log_produce(r, n) + local trees = r:get_resource("tree") + if trees>=n then + r:set_resource("tree", trees-n) + else + r:set_resource("tree", 0) + n = n - trees + trees = r:get_resource("sapling") + if trees>=n then + r:set_resource("sapling", trees-n) + else + r:set_resource("sapling", 0) + end + end +end + +function mallorn_limit(r) + if not r:get_flag(1) then -- RF_MALLORN + return 0 + end + return r:get_resource("tree") + r:get_resource("sapling") +end + +function mallorn_produce(r, n) + local trees = r:get_resource("tree") + if trees>=n then + r:set_resource("tree", trees-n) + else + r:set_resource("tree", 0) + n = n - trees + trees = r:get_resource("sapling") + if trees>=n then + r:set_resource("sapling", trees-n) + else + r:set_resource("sapling", 0) + end + end +end diff --git a/scripts/schema.sql b/scripts/schema.sql index f2b88d16e..e136bb822 100644 --- a/scripts/schema.sql +++ b/scripts/schema.sql @@ -1,6 +1,6 @@ -CREATE TABLE email(id INTEGER PRIMARY KEY, md5 VARCHAR(32) UNIQUE NOT NULL, email VARCHAR(32), bounces INT DEFAULT 0, confirmed TIMESTAMP DEFAULT NULL); -CREATE TABLE faction (id INTEGER PRIMARY KEY, user_id INTEGER REFERENCES user(id), no INTEGER, name VARCHAR(64), game_id INTEGER REFERENCES game(id), race VARCHAR(10), lang CHAR(2)); -CREATE TABLE faction_email (faction_id INTEGER REFERENCES faction(id), email_id INTEGER REFERENCES email(id)); -CREATE TABLE game (id INTEGER PRIMARY KEY, name VARCHAR(20), last_turn INTEGER); -CREATE TABLE score (turn INTEGER, faction_id INTEGER REFERENCES faction(id), value INTEGER, UNIQUE(turn, faction_id)); -CREATE TABLE user(id INTEGER PRIMARY KEY, email_id INTEGER REFERENCES email(id), creation TIMESTAMP DEFAULT CURRENT_TIMESTAMP); +CREATE TABLE email(id INTEGER PRIMARY KEY, md5 VARCHAR(32) UNIQUE NOT NULL, email VARCHAR(32), bounces INT DEFAULT 0, confirmed TIMESTAMP DEFAULT NULL); +CREATE TABLE faction (id INTEGER PRIMARY KEY, user_id INTEGER REFERENCES user(id), no INTEGER, name VARCHAR(64), game_id INTEGER REFERENCES game(id), race VARCHAR(10), lang CHAR(2)); +CREATE TABLE faction_email (faction_id INTEGER REFERENCES faction(id), email_id INTEGER REFERENCES email(id)); +CREATE TABLE game (id INTEGER PRIMARY KEY, name VARCHAR(20), last_turn INTEGER); +CREATE TABLE score (turn INTEGER, faction_id INTEGER REFERENCES faction(id), value INTEGER, UNIQUE(turn, faction_id)); +CREATE TABLE user(id INTEGER PRIMARY KEY, email_id INTEGER REFERENCES email(id), creation TIMESTAMP DEFAULT CURRENT_TIMESTAMP); diff --git a/scripts/setup.lua b/scripts/setup.lua index e4bfb726b..0c3603707 100644 --- a/scripts/setup.lua +++ b/scripts/setup.lua @@ -1,16 +1,16 @@ -local srcpath = config.source_dir -local respath = srcpath .. '/' .. config.game .. '/res/' -local paths = { config.game..'/scripts/?.lua';'lunit/?.lua','external/lunit/?.lua','scripts/?.lua';'scripts/?' } - -tests = {'common'} -for idx, test in pairs(tests) do - tests[idx] = srcpath .. '/scripts/tests/' .. test .. '.lua' -end - -for idx, path in pairs(paths) do - package.path = srcpath .. '/' .. path .. ';' .. package.path -end - -read_xml(respath..'config-'..config.game..'.xml', respath..'catalog-'..config.game..'.xml') - -require "init" +local srcpath = config.source_dir +local respath = srcpath .. '/' .. config.game .. '/res/' +local paths = { config.game..'/scripts/?.lua';'lunit/?.lua','external/lunit/?.lua','scripts/?.lua';'scripts/?' } + +tests = {'common'} +for idx, test in pairs(tests) do + tests[idx] = srcpath .. '/scripts/tests/' .. test .. '.lua' +end + +for idx, path in pairs(paths) do + package.path = srcpath .. '/' .. path .. ';' .. package.path +end + +read_xml(respath..'config-'..config.game..'.xml', respath..'catalog-'..config.game..'.xml') + +require "init" diff --git a/scripts/spells.lua b/scripts/spells.lua index 8269e72e6..4ab08459a 100644 --- a/scripts/spells.lua +++ b/scripts/spells.lua @@ -1,151 +1,151 @@ -function creation_message(mage, type, number) - local msg = message.create("item_create_spell") - msg:set_unit("mage", mage) - msg:set_int("number", number) - msg:set_resource("item", type) - return msg -end - -local function create_item(mage, level, name, number) - local count = number or 1 - mage:add_item(name, count); - local msg = creation_message(mage, name, count) - msg:send_faction(mage.faction) - return level -end - --- Wasser des Lebens -function create_potion_p2(r, mage, level, force) - return create_item(mage, level, "p2", level) -end - --- Siebenmeilentee -function create_potion_p0(r, mage, level, force) - return create_item(mage, level, "p0", level) -end - --- Wundsalbe -function create_potion_ointment(r, mage, level, force) - return create_item(mage, level, "ointment", level) -end - --- Bauernblut -function create_potion_peasantblood(r, mage, level, force) - return create_item(mage, level, "peasantblood", level) -end - --- Pferdeglück -function create_potion_p9(r, mage, level, force) - return create_item(mage, level, "p9", level) -end - --- Schaffenstrunk -function create_potion_p3(r, mage, level, force) - return create_item(mage, level, "p3", level) -end - --- Heiltrank -function create_potion_p14(r, mage, level, force) - return create_item(mage, level, "p14", level) -end - --- Elixier der Macht -function create_potion_p13(r, mage, level, force) - return create_item(mage, level, "p13", level) -end - --- Erschaffe ein Flammenschwert -function create_firesword(r, mage, level, force) - return create_item(mage, level, "firesword") -end - --- Erschaffe einen Gürtel der Trollstärke -function create_trollbelt(r, mage, level, force) - return create_item(mage, level, "trollbelt") -end - --- Erschaffe einen Ring der Unsichtbarkeit -function create_roi(r, mage, level, force) - return create_item(mage, level, "roi") -end - --- Erschaffe einen Ring der flinken Finger -function create_roqf(r, mage, level, force) - return create_item(mage, level, "roqf") -end - --- Erschaffe ein Amulett des wahren Sehens -function create_aots(r, mage, level, force) - return create_item(mage, level, "aots") -end - --- Erschaffe einen magischen Kräuterbeutel -function create_magicherbbag(r, mage, level, force) - return create_item(mage, level, "magicherbbag") -end - --- Erschaffe einen Taktikkristal -function create_dreameye(r, mage, level, force) - return create_item(mage, level, "dreameye") -end - --- Erschaffe einen Antimagiekristall -function create_antimagic(r, mage, level, force) - return create_item(mage, level, "antimagic") -end - --- Erschaffe eine Sphäre der Unsichtbarkeit -function create_invisibility_sphere(r, mage, level, force) - return create_item(mage, level, "sphereofinv") -end - --- Erschaffe einen Gürtel der Keuschheit -function create_chastitybelt(r, mage, level, force) - return create_item(mage, level, "ao_chastity") -end - --- Erschaffe ein Runenschwert -function create_runesword(r, mage, level, force) - return create_item(mage, level, "runesword") -end - --- Erschaffe ein Aurafokus -function create_focus(r, mage, level, force) - return create_item(mage, level, "aurafocus") -end - --- Erschaffe einen Ring der Macht -function create_rop(r, mage, level, force) - return create_item(mage, level, "rop") -end - --- Erschaffe einen Ring der Regeneration -function create_ror(r, mage, level, force) - return create_item(mage, level, "ror") -end - --- Erschaffe einen Zauberbeutel -function create_bagofholding(r, mage, level, force) - return create_item(mage, level, "magicbag") -end - --- TODO: -function earn_silver(r, mage, level, force) - local money = r:get_resource("money") - local wanted = 50 * force - local amount = wanted - if wanted > money then - amount = money - end - r:set_resource("money", money - amount) - mage:add_item("money", amount) - - local msg = message.create("income") - msg:set_unit("unit", mage) - msg:set_region("region", r) - msg:set_int("mode", 6) - msg:set_int("wanted", wanted) - msg:set_int("amount", amount) - msg:send_faction(mage.faction) - return level -end +function creation_message(mage, type, number) + local msg = message.create("item_create_spell") + msg:set_unit("mage", mage) + msg:set_int("number", number) + msg:set_resource("item", type) + return msg +end + +local function create_item(mage, level, name, number) + local count = number or 1 + mage:add_item(name, count); + local msg = creation_message(mage, name, count) + msg:send_faction(mage.faction) + return level +end + +-- Wasser des Lebens +function create_potion_p2(r, mage, level, force) + return create_item(mage, level, "p2", level) +end + +-- Siebenmeilentee +function create_potion_p0(r, mage, level, force) + return create_item(mage, level, "p0", level) +end + +-- Wundsalbe +function create_potion_ointment(r, mage, level, force) + return create_item(mage, level, "ointment", level) +end + +-- Bauernblut +function create_potion_peasantblood(r, mage, level, force) + return create_item(mage, level, "peasantblood", level) +end + +-- Pferdeglück +function create_potion_p9(r, mage, level, force) + return create_item(mage, level, "p9", level) +end + +-- Schaffenstrunk +function create_potion_p3(r, mage, level, force) + return create_item(mage, level, "p3", level) +end + +-- Heiltrank +function create_potion_p14(r, mage, level, force) + return create_item(mage, level, "p14", level) +end + +-- Elixier der Macht +function create_potion_p13(r, mage, level, force) + return create_item(mage, level, "p13", level) +end + +-- Erschaffe ein Flammenschwert +function create_firesword(r, mage, level, force) + return create_item(mage, level, "firesword") +end + +-- Erschaffe einen Gürtel der Trollstärke +function create_trollbelt(r, mage, level, force) + return create_item(mage, level, "trollbelt") +end + +-- Erschaffe einen Ring der Unsichtbarkeit +function create_roi(r, mage, level, force) + return create_item(mage, level, "roi") +end + +-- Erschaffe einen Ring der flinken Finger +function create_roqf(r, mage, level, force) + return create_item(mage, level, "roqf") +end + +-- Erschaffe ein Amulett des wahren Sehens +function create_aots(r, mage, level, force) + return create_item(mage, level, "aots") +end + +-- Erschaffe einen magischen Kräuterbeutel +function create_magicherbbag(r, mage, level, force) + return create_item(mage, level, "magicherbbag") +end + +-- Erschaffe einen Taktikkristal +function create_dreameye(r, mage, level, force) + return create_item(mage, level, "dreameye") +end + +-- Erschaffe einen Antimagiekristall +function create_antimagic(r, mage, level, force) + return create_item(mage, level, "antimagic") +end + +-- Erschaffe eine Sphäre der Unsichtbarkeit +function create_invisibility_sphere(r, mage, level, force) + return create_item(mage, level, "sphereofinv") +end + +-- Erschaffe einen Gürtel der Keuschheit +function create_chastitybelt(r, mage, level, force) + return create_item(mage, level, "ao_chastity") +end + +-- Erschaffe ein Runenschwert +function create_runesword(r, mage, level, force) + return create_item(mage, level, "runesword") +end + +-- Erschaffe ein Aurafokus +function create_focus(r, mage, level, force) + return create_item(mage, level, "aurafocus") +end + +-- Erschaffe einen Ring der Macht +function create_rop(r, mage, level, force) + return create_item(mage, level, "rop") +end + +-- Erschaffe einen Ring der Regeneration +function create_ror(r, mage, level, force) + return create_item(mage, level, "ror") +end + +-- Erschaffe einen Zauberbeutel +function create_bagofholding(r, mage, level, force) + return create_item(mage, level, "magicbag") +end + +-- TODO: +function earn_silver(r, mage, level, force) + local money = r:get_resource("money") + local wanted = 50 * force + local amount = wanted + if wanted > money then + amount = money + end + r:set_resource("money", money - amount) + mage:add_item("money", amount) + + local msg = message.create("income") + msg:set_unit("unit", mage) + msg:set_region("region", r) + msg:set_int("mode", 6) + msg:set_int("wanted", wanted) + msg:set_int("amount", amount) + msg:send_faction(mage.faction) + return level +end diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 9e0ff43db..b6ea04082 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -1,643 +1,643 @@ -require "lunit" - -function setup() - free_game() -end - -function one_unit(r, f) - local u = unit.create(f, r, 1) - u:add_item("money", u.number * 100) - u:clear_orders() - return u -end - -function two_units(r, f1, f2) - return one_unit(r, f1), one_unit(r, f2) -end - -function two_factions() - local f1 = faction.create("noreply@eressea.de", "human", "de") - f1.id = 1 - local f2 = faction.create("noreply@eressea.de", "orc", "de") - f2.id = 2 - return f1, f2 -end - -module( "common", package.seeall, lunit.testcase ) - -function DISABLE_test_eventbus_fire() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - local u = unit.create(f, r) - - function compare_f(u, event, f) - assert_equal(u.faction, f) - end - eventbus.register(u, "weird", compare_f) - eventbus.fire(u, "weird", f) -end - -function test_fleeing_units_can_be_transported() - local r = region.create(0, 0, "plain") - local r1 = region.create(1, 0, "plain") - local f1, f2 = two_factions() - local u1, u2 = two_units(r, f1, f2) - local u3 = one_unit(r, f2) - u1.number = 100 - u1:add_order("ATTACKIEREN " .. itoa36(u2.id)) - u2.number = 100 - u2:add_order("FAHREN " .. itoa36(u3.id)) - u3.number = 100 - u3:add_order("KAEMPFE FLIEHE") - u3:add_order("TRANSPORT " .. itoa36(u2.id)) - u3:add_order("NACH O ") - u3:set_skill("riding", 2) - u3:add_item("horse", u2.number) - u3:add_order("KAEMPFE FLIEHE") - process_orders() - assert_equal(u3.region.id, r1.id, "transporter did not move") - assert_equal(u2.region.id, r1.id, "transported unit did not move") -end - -function test_plane() - local pl = plane.create(0, -3, -3, 7, 7) - local nx, ny = plane.normalize(pl, 4, 4) - assert_equal(nx, -3, "normalization failed") - assert_equal(ny, -3, "normalization failed") - local f = faction.create("noreply@eressea.de", "human", "de") - f.id = atoi36("tpla") - local r, x, y - for x = -3, 3 do for y = -3, 3 do - r = region.create(x, y, "plain") - if (x==y) then - local u = unit.create(f, r, 1) - end - end end -end - -function test_pure() - free_game() - local r = region.create(0, 0, "plain") - assert_not_equal(nil, r) - assert_equal(r, get_region(0, 0)) -end - -function test_read_write() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - local u = unit.create(f, r) - u.number = 2 - local fno = f.id - local uno = u.id - local result = 0 - assert_equal(r.terrain, "plain") - result = write_game("test_read_write.dat", "binary") - assert_equal(result, 0) - assert_not_equal(get_region(0, 0), nil) - assert_not_equal(get_faction(fno), nil) - assert_not_equal(get_unit(uno), nil) - r = nil - f = nil - u = nil - free_game() - assert_equal(get_region(0, 0), nil) - assert_equal(nil, get_faction(fno)) - assert_equal(nil, get_unit(uno)) - result = read_game("test_read_write.dat", "binary") - assert_equal(0, result) - assert_not_equal(nil, get_region(0, 0)) - assert_not_equal(nil, get_faction(fno)) - assert_not_equal(nil, get_unit(uno)) - free_game() -end - -function test_gmtool() - free_game() - local r1 = region.create(1, 0, "plain") - local r2 = region.create(1, 1, "plain") - local r3 = region.create(1, 2, "plain") - gmtool.open() - gmtool.select(r1, true) - gmtool.select_at(0, 1, true) - gmtool.select(r2, true) - gmtool.select_at(0, 2, true) - gmtool.select(r3, false) - gmtool.select(r3, true) - gmtool.select_at(0, 3, false) - gmtool.select(r3, false) - - local selections = 0 - for r in gmtool.get_selection() do - selections=selections+1 - end - assert_equal(2, selections) - assert_equal(nil, gmtool.get_cursor()) - - gmtool.close() -end - -function test_faction() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - assert(f) - f.info = "Spazz" - assert(f.info=="Spazz") - f:add_item("donotwant", 42) - f:add_item("stone", 42) - f:add_item("sword", 42) - local items = 0 - for u in f.items do - items = items + 1 - end - assert(items==2) - unit.create(f, r) - unit.create(f, r) - local units = 0 - for u in f.units do - units = units + 1 - end - assert(units==2) -end - -function test_unit() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - local u = unit.create(f, r) - u.number = 20 - u.name = "Enno" - assert(u.name=="Enno") - u.info = "Spazz" - assert(u.info=="Spazz") - u:add_item("sword", 4) - assert(u:get_item("sword")==4) - assert(u:get_pooled("sword")==4) - u:use_pooled("sword", 2) - assert(u:get_item("sword")==2) -end - -function test_region() - free_game() - local r = region.create(0, 0, "plain") - r:set_resource("horse", 42) - r:set_resource("money", 45) - r:set_resource("peasant", 200) - assert(r:get_resource("horse") == 42) - assert(r:get_resource("money") == 45) - assert(r:get_resource("peasant") == 200) - r.name = nil - r.info = nil - assert(r.name=="") - assert(r.info=="") - r.name = "Alabasterheim" - r.info = "Hier wohnen die siebzehn Zwerge" - assert(tostring(r) == "Alabasterheim (0,0)") -end - -function test_building() - free_game() - local u - local f = faction.create("noreply@eressea.de", "human", "de") - local r = region.create(0, 0, "plain") - local b = building.create(r, "castle") - u = unit.create(f, r) - u.number = 1 - u.building = b - u = unit.create(f, r) - u.number = 2 - -- u.building = b - u = unit.create(f, r) - u.number = 3 - u.building = b - local units = 0 - for u in b.units do - units = units + 1 - end - assert(units==2) - local r2 = region.create(0, 1, "plain") - assert(b.region==r) - b.region = r2 - assert(b.region==r2) - assert(r2.buildings()==b) -end - -function test_message() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - local u = unit.create(f, r) - local msg = message.create("item_create_spell") - msg:set_unit("mage", u) - msg:set_int("number", 1) - msg:set_resource("item", "sword") - msg:send_region(r) - msg:send_faction(f) - - return msg -end - -function test_hashtable() - free_game() - local f = faction.create("noreply@eressea.de", "human", "de") - f.objects:set("enno", "smart guy") - f.objects:set("age", 10) - assert(f.objects:get("jesus") == nil) - assert(f.objects:get("enno") == "smart guy") - assert(f.objects:get("age") == 10) - f.objects:set("age", nil) - assert(f.objects:get("age") == nil) -end - -function test_events() - local fail = 1 - local function msg_handler(u, evt) - str = evt:get(0) - u2 = evt:get(1) - assert(u2~=nil) - assert(str=="Du Elf stinken") - message_unit(u, u2, "thanks unit, i got your message: " .. str) - message_faction(u, u2.faction, "thanks faction, i got your message: " .. str) - message_region(u, "thanks region, i got your message: " .. str) - fail = 0 - end - - plain = region.create(0, 0, "plain") - skill = 8 - - f = faction.create("noreply@eressea.de", "orc", "de") - f.age = 20 - - u = unit.create(f, plain) - u.number = 1 - u:add_item("money", u.number*100) - u:clear_orders() - u:add_order("NUMMER PARTEI test") - u:add_handler("message", msg_handler) - msg = "BOTSCHAFT EINHEIT " .. itoa36(u.id) .. " Du~Elf~stinken" - f = faction.create("noreply@eressea.de", "elf", "de") - f.age = 20 - - u = unit.create(f, plain) - u.number = 1 - u:add_item("money", u.number*100) - u:clear_orders() - u:add_order("NUMMER PARTEI eviL") - u:add_order(msg) - process_orders() - assert(fail==0) -end - -function test_recruit2() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - local u = unit.create(f, r) - u.number = 1 - u:add_item("money", 2000) - u:clear_orders() - u:add_order("MACHE TEMP 1") - u:add_order("REKRUTIERE 1 Elf") - u:add_order("REKRUTIERE 1 mensch") - u:add_order("REKRUTIERE 1") - process_orders() -end - -function test_guard() - free_game() - region.create(1, 0, "plain") - local r = region.create(0, 0, "plain") - local f1 = faction.create("noreply@eressea.de", "human", "de") - f1.age = 20 - local u1 = unit.create(f1, r, 1) - u1:add_item("sword", 10) - u1:add_item("money", 10) - u1:set_skill("melee", 10) - u1:clear_orders() - u1:add_order("NACH O") - - local f2 = faction.create("noreply@eressea.de", "human", "de") - f2.age = 20 - local u2 = unit.create(f2, r, 1) - local u3 = unit.create(f2, r, 1) - local b = building.create(r, "castle") - b.size = 10 - u2.building = b - u3.building = b - u2:clear_orders() - u2:add_order("ATTACKIEREN " .. itoa36(u1.id)) -- you will die... - u2:add_item("money", 100) - u3:add_item("money", 100) - process_orders() - assert_equal(r.id, u1.region.id, "unit may not move after combat") -end - -function test_recruit() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - local u = unit.create(f, r) - u.number = 1 - local n = 3 - r:set_resource("peasant", 200) - u:clear_orders() - u:add_item("money", 110*n+20) - u:add_order("REKRUTIERE " .. n) - process_orders() - assert(u.number == n+1) - local p = r:get_resource("peasant") - assert(p<200 and p>=200-n) - -- assert(u:get_item("money")==10) -end - -function test_produce() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - local u = unit.create(f, r, 1) - u:clear_orders() - u:set_skill("weaponsmithing", 3) - u:add_item("iron", 2) - u:add_item("money", u.number * 10) - u:add_order("MACHE Schwert") - process_orders() - assert(u:get_item("iron")==1) - assert(u:get_item("sword")==1) -end - -function test_work() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - f.id = 42 - local u = unit.create(f, r, 1) - u:add_item("money", u.number * 10) -- humans cost 10 - u:set_skill("herbalism", 5) - u:clear_orders() - u:add_order("ARBEITEN") - process_orders() - assert(u:get_item("money")>=10) -end - -function test_upkeep() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - f.id = 42 - local u = unit.create(f, r, 5) - u:add_item("money", u.number * 11) - u:clear_orders() - u:add_order("LERNE Waffenbau") - process_orders() - assert(u:get_item("money")==u.number) -end - -function test_id() - free_game() - local r = region.create(0, 0, "plain") - - local f = faction.create("noreply@eressea.de", "human", "de") - f.id = atoi36("42") - assert(get_faction(42)~=f) - assert(get_faction("42")==f) - assert(get_faction(atoi36("42"))==f) - - local u = unit.create(f, r, 1) - u.id = atoi36("42") - assert(get_unit(42)~=u) - assert(get_unit("42")==u) - assert(get_unit(atoi36("42"))==u) - - local b = building.create(r, "castle") - -- b.id = atoi36("42") - local fortytwo = itoa36(b.id) - assert(get_building(fortytwo)==b) - assert(get_building(atoi36(fortytwo))==b) - - local s = ship.create(r, "canoe") - if (s==nil) then - s = ship.create(r, "boat") - end - -- s.id = atoi36("42") - local fortytwo = itoa36(s.id) - assert(get_ship(fortytwo)==s) - assert(get_ship(atoi36(fortytwo))==s) -end - -function test_herbalism() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - f.id = 42 - local u = unit.create(f, r, 1) - u:add_item("money", u.number * 100) - u:set_skill("herbalism", 5) - u:clear_orders() - u:add_order("MACHE Samen") - process_orders() -end - -function test_mallorn() - free_game() - local r = region.create(0, 0, "plain") - r:set_flag(1, false) -- not mallorn - r:set_resource("tree", 100) - assert(r:get_resource("tree")==100) - local m = region.create(0, 0, "plain") - m:set_flag(1, true) -- not mallorn - m:set_resource("tree", 100) - assert(m:get_resource("tree")==100) - - local f = faction.create("noreply@eressea.de", "human", "de") - - local u1 = unit.create(f, r, 1) - u1:add_item("money", u1.number * 100) - u1:set_skill("forestry", 2) - u1:clear_orders() - u1:add_order("MACHE HOLZ") - - local u2 = unit.create(f, m, 1) - u2:add_item("money", u2.number * 100) - u2:set_skill("forestry", 2) - u2:clear_orders() - u2:add_order("MACHE HOLZ") - - local u3 = unit.create(f, m, 1) - u3:add_item("money", u3.number * 100) - u3:set_skill("forestry", 2) - u3:clear_orders() - u3:add_order("MACHE Mallorn") - process_orders() - assert(u1:get_item("log")==2) - assert(u2:get_item("log")==2) - assert(u3:get_item("mallorn")==1) -end - -function test_coordinate_translation() - local pl = plane.create(1, 500, 500, 1001, 1001) -- astralraum - local pe = plane.create(1, -8761, 3620, 23, 23) -- eternath - local r = region.create(1000, 1000, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - assert_not_equal(nil, r) - assert_equal(r.x, 1000) - assert_equal(r.y, 1000) - local nx, ny = plane.normalize(pl, r.x, r.y) - assert_equal(nx, 1000) - assert_equal(ny, 1000) - local r1 = region.create(500, 500, "plain") - f:set_origin(r1) - nx, ny = f:normalize(r1) - assert_equal(0, nx) - assert_equal(0, ny) - local r0 = region.create(0, 0, "plain") - nx, ny = f:normalize(r0) - assert_equal(0, nx) - assert_equal(0, ny) - nx, ny = f:normalize(r) - assert_equal(500, nx) - assert_equal(500, ny) - local rn = region.create(1010, 1010, "plain") - nx, ny = f:normalize(rn) - assert_equal(-491, nx) - assert_equal(-491, ny) - - local re = region.create(-8760, 3541, "plain") -- eternath - nx, ny = f:normalize(rn) - assert_equal(-491, nx) - assert_equal(-491, ny) -end - -function test_control() - free_game() - local u1, u2 = two_units(region.create(0, 0, "plain"), two_factions()) - local r = u1.region - local b = building.create(r, "castle") - u1.building = b - u2.building = b - assert_equal(u1, b.owner) - u1:clear_orders() - u1:add_order("GIB " .. itoa36(u2.id) .. " KOMMANDO") - u1:add_order("VERLASSE") - process_orders() - assert_equal(u2, b.owner) -end - -function test_storage() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - f.id = 42 - local u = unit.create(f, r, 1) - u:add_item("money", u.number * 100) - store = storage.create("test.unit.dat", "wb") - assert_not_equal(store, nil) - store:write_unit(u) - store:close() - free_game() - -- recreate world: - r = region.create(0, 0, "plain") - f = faction.create("noreply@eressea.de", "human", "de") - f.id = 42 - store = storage.create("test.unit.dat", "rb") - assert(store) - u = store:read_unit() - store:close() - assert(u) - assert(u:get_item("money") == u.number * 100) -end - -function test_building_other() - local r = region.create(0,0, "plain") - local f1 = faction.create("noreply@eressea.de", "human", "de") - local f2 = faction.create("noreply@eressea.de", "human", "de") - local b = building.create(r, "castle") - b.size = 10 - local u1 = unit.create(f1, r, 3) - u1.building = b - u1:add_item("money", 100) - - local u2 = unit.create(f2, r, 3) - u2:set_skill("building", 10) - u2:add_item("money", 100) - u2:add_item("stone", 100) - u2:clear_orders() - u2:add_order("MACHEN BURG " .. itoa36(b.id)) - process_orders() - assert_not_equal(10, b.size) -end - -function test_config() - assert_not_equal(nil, config.basepath) - assert_not_equal(nil, config.locales) -end - -function test_guard_resources() - -- this is not quite http://bugs.eressea.de/view.php?id=1756 - local r = region.create(0,0, "mountain") - local f1 = faction.create("noreply@eressea.de", "human", "de") - f1.age=20 - local f2 = faction.create("noreply@eressea.de", "human", "de") - f2.age=20 - local u1 = unit.create(f1, r, 1) - u1:add_item("money", 100) - u1:set_skill("melee", 3) - u1:add_item("sword", 1) - u1:clear_orders() - u1:add_order("BEWACHEN") - - local u2 = unit.create(f2, r, 1) - u2:add_item("money", 100) - u2:set_skill("mining", 3) - u2:clear_orders() - u2:add_order("MACHEN EISEN") - - process_orders() - local iron = u2:get_item("iron") - process_orders() - assert_equal(iron, u2:get_item("iron")) -end - -local function is_flag_set(flags, flag) - return math.mod(flags, flag*2) - math.mod(flags, flag) == flag; -end - -function test_hero_hero_transfer() - local r = region.create(0,0, "mountain") - local f = faction.create("noreply@eressea.de", "human", "de") - f.age=20 - local UFL_HERO = 128 - - local u1 = unit.create(f, r, 1) - local u2 = unit.create(f, r, 1) - u1:add_item("money", 10000) - u1.flags = u1.flags + UFL_HERO - u2.flags = u2.flags + UFL_HERO - u1:clear_orders() - u1:add_order("GIB " .. itoa36(u2.id) .. " 1 PERSONEN") - u1:add_order("REKRUTIEREN 1") - process_orders() - assert_equal(1, u1.number) - assert_equal(2, u2.number) - assert_false(is_flag_set(u1.flags, 128), 128, "recruiting into an empty hero unit should not create a hero") - assert_true(is_flag_set(u2.flags, 128), 128, "unit is not a hero?") -end - -function test_hero_normal_transfer() - local r = region.create(0,0, "mountain") - local f = faction.create("noreply@eressea.de", "human", "de") - f.age=20 - local UFL_HERO = 128 - - local u1 = unit.create(f, r, 1) - local u2 = unit.create(f, r, 1) - u1:add_item("money", 10000) - u1.flags = u1.flags + UFL_HERO - u1:clear_orders() - u1:add_order("GIB " .. itoa36(u2.id) .. " 1 PERSONEN") - process_orders() - assert_equal(1, u1.number) - assert_equal(1, u2.number) - assert_true(is_flag_set(u1.flags, 128), "unit is not a hero?") - assert_false(is_flag_set(u2.flags, 128), "unit turned into a hero") -end +require "lunit" + +function setup() + free_game() +end + +function one_unit(r, f) + local u = unit.create(f, r, 1) + u:add_item("money", u.number * 100) + u:clear_orders() + return u +end + +function two_units(r, f1, f2) + return one_unit(r, f1), one_unit(r, f2) +end + +function two_factions() + local f1 = faction.create("noreply@eressea.de", "human", "de") + f1.id = 1 + local f2 = faction.create("noreply@eressea.de", "orc", "de") + f2.id = 2 + return f1, f2 +end + +module( "common", package.seeall, lunit.testcase ) + +function DISABLE_test_eventbus_fire() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r) + + function compare_f(u, event, f) + assert_equal(u.faction, f) + end + eventbus.register(u, "weird", compare_f) + eventbus.fire(u, "weird", f) +end + +function test_fleeing_units_can_be_transported() + local r = region.create(0, 0, "plain") + local r1 = region.create(1, 0, "plain") + local f1, f2 = two_factions() + local u1, u2 = two_units(r, f1, f2) + local u3 = one_unit(r, f2) + u1.number = 100 + u1:add_order("ATTACKIEREN " .. itoa36(u2.id)) + u2.number = 100 + u2:add_order("FAHREN " .. itoa36(u3.id)) + u3.number = 100 + u3:add_order("KAEMPFE FLIEHE") + u3:add_order("TRANSPORT " .. itoa36(u2.id)) + u3:add_order("NACH O ") + u3:set_skill("riding", 2) + u3:add_item("horse", u2.number) + u3:add_order("KAEMPFE FLIEHE") + process_orders() + assert_equal(u3.region.id, r1.id, "transporter did not move") + assert_equal(u2.region.id, r1.id, "transported unit did not move") +end + +function test_plane() + local pl = plane.create(0, -3, -3, 7, 7) + local nx, ny = plane.normalize(pl, 4, 4) + assert_equal(nx, -3, "normalization failed") + assert_equal(ny, -3, "normalization failed") + local f = faction.create("noreply@eressea.de", "human", "de") + f.id = atoi36("tpla") + local r, x, y + for x = -3, 3 do for y = -3, 3 do + r = region.create(x, y, "plain") + if (x==y) then + local u = unit.create(f, r, 1) + end + end end +end + +function test_pure() + free_game() + local r = region.create(0, 0, "plain") + assert_not_equal(nil, r) + assert_equal(r, get_region(0, 0)) +end + +function test_read_write() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r) + u.number = 2 + local fno = f.id + local uno = u.id + local result = 0 + assert_equal(r.terrain, "plain") + result = write_game("test_read_write.dat", "binary") + assert_equal(result, 0) + assert_not_equal(get_region(0, 0), nil) + assert_not_equal(get_faction(fno), nil) + assert_not_equal(get_unit(uno), nil) + r = nil + f = nil + u = nil + free_game() + assert_equal(get_region(0, 0), nil) + assert_equal(nil, get_faction(fno)) + assert_equal(nil, get_unit(uno)) + result = read_game("test_read_write.dat", "binary") + assert_equal(0, result) + assert_not_equal(nil, get_region(0, 0)) + assert_not_equal(nil, get_faction(fno)) + assert_not_equal(nil, get_unit(uno)) + free_game() +end + +function test_gmtool() + free_game() + local r1 = region.create(1, 0, "plain") + local r2 = region.create(1, 1, "plain") + local r3 = region.create(1, 2, "plain") + gmtool.open() + gmtool.select(r1, true) + gmtool.select_at(0, 1, true) + gmtool.select(r2, true) + gmtool.select_at(0, 2, true) + gmtool.select(r3, false) + gmtool.select(r3, true) + gmtool.select_at(0, 3, false) + gmtool.select(r3, false) + + local selections = 0 + for r in gmtool.get_selection() do + selections=selections+1 + end + assert_equal(2, selections) + assert_equal(nil, gmtool.get_cursor()) + + gmtool.close() +end + +function test_faction() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + assert(f) + f.info = "Spazz" + assert(f.info=="Spazz") + f:add_item("donotwant", 42) + f:add_item("stone", 42) + f:add_item("sword", 42) + local items = 0 + for u in f.items do + items = items + 1 + end + assert(items==2) + unit.create(f, r) + unit.create(f, r) + local units = 0 + for u in f.units do + units = units + 1 + end + assert(units==2) +end + +function test_unit() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r) + u.number = 20 + u.name = "Enno" + assert(u.name=="Enno") + u.info = "Spazz" + assert(u.info=="Spazz") + u:add_item("sword", 4) + assert(u:get_item("sword")==4) + assert(u:get_pooled("sword")==4) + u:use_pooled("sword", 2) + assert(u:get_item("sword")==2) +end + +function test_region() + free_game() + local r = region.create(0, 0, "plain") + r:set_resource("horse", 42) + r:set_resource("money", 45) + r:set_resource("peasant", 200) + assert(r:get_resource("horse") == 42) + assert(r:get_resource("money") == 45) + assert(r:get_resource("peasant") == 200) + r.name = nil + r.info = nil + assert(r.name=="") + assert(r.info=="") + r.name = "Alabasterheim" + r.info = "Hier wohnen die siebzehn Zwerge" + assert(tostring(r) == "Alabasterheim (0,0)") +end + +function test_building() + free_game() + local u + local f = faction.create("noreply@eressea.de", "human", "de") + local r = region.create(0, 0, "plain") + local b = building.create(r, "castle") + u = unit.create(f, r) + u.number = 1 + u.building = b + u = unit.create(f, r) + u.number = 2 + -- u.building = b + u = unit.create(f, r) + u.number = 3 + u.building = b + local units = 0 + for u in b.units do + units = units + 1 + end + assert(units==2) + local r2 = region.create(0, 1, "plain") + assert(b.region==r) + b.region = r2 + assert(b.region==r2) + assert(r2.buildings()==b) +end + +function test_message() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r) + local msg = message.create("item_create_spell") + msg:set_unit("mage", u) + msg:set_int("number", 1) + msg:set_resource("item", "sword") + msg:send_region(r) + msg:send_faction(f) + + return msg +end + +function test_hashtable() + free_game() + local f = faction.create("noreply@eressea.de", "human", "de") + f.objects:set("enno", "smart guy") + f.objects:set("age", 10) + assert(f.objects:get("jesus") == nil) + assert(f.objects:get("enno") == "smart guy") + assert(f.objects:get("age") == 10) + f.objects:set("age", nil) + assert(f.objects:get("age") == nil) +end + +function test_events() + local fail = 1 + local function msg_handler(u, evt) + str = evt:get(0) + u2 = evt:get(1) + assert(u2~=nil) + assert(str=="Du Elf stinken") + message_unit(u, u2, "thanks unit, i got your message: " .. str) + message_faction(u, u2.faction, "thanks faction, i got your message: " .. str) + message_region(u, "thanks region, i got your message: " .. str) + fail = 0 + end + + plain = region.create(0, 0, "plain") + skill = 8 + + f = faction.create("noreply@eressea.de", "orc", "de") + f.age = 20 + + u = unit.create(f, plain) + u.number = 1 + u:add_item("money", u.number*100) + u:clear_orders() + u:add_order("NUMMER PARTEI test") + u:add_handler("message", msg_handler) + msg = "BOTSCHAFT EINHEIT " .. itoa36(u.id) .. " Du~Elf~stinken" + f = faction.create("noreply@eressea.de", "elf", "de") + f.age = 20 + + u = unit.create(f, plain) + u.number = 1 + u:add_item("money", u.number*100) + u:clear_orders() + u:add_order("NUMMER PARTEI eviL") + u:add_order(msg) + process_orders() + assert(fail==0) +end + +function test_recruit2() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r) + u.number = 1 + u:add_item("money", 2000) + u:clear_orders() + u:add_order("MACHE TEMP 1") + u:add_order("REKRUTIERE 1 Elf") + u:add_order("REKRUTIERE 1 mensch") + u:add_order("REKRUTIERE 1") + process_orders() +end + +function test_guard() + free_game() + region.create(1, 0, "plain") + local r = region.create(0, 0, "plain") + local f1 = faction.create("noreply@eressea.de", "human", "de") + f1.age = 20 + local u1 = unit.create(f1, r, 1) + u1:add_item("sword", 10) + u1:add_item("money", 10) + u1:set_skill("melee", 10) + u1:clear_orders() + u1:add_order("NACH O") + + local f2 = faction.create("noreply@eressea.de", "human", "de") + f2.age = 20 + local u2 = unit.create(f2, r, 1) + local u3 = unit.create(f2, r, 1) + local b = building.create(r, "castle") + b.size = 10 + u2.building = b + u3.building = b + u2:clear_orders() + u2:add_order("ATTACKIEREN " .. itoa36(u1.id)) -- you will die... + u2:add_item("money", 100) + u3:add_item("money", 100) + process_orders() + assert_equal(r.id, u1.region.id, "unit may not move after combat") +end + +function test_recruit() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r) + u.number = 1 + local n = 3 + r:set_resource("peasant", 200) + u:clear_orders() + u:add_item("money", 110*n+20) + u:add_order("REKRUTIERE " .. n) + process_orders() + assert(u.number == n+1) + local p = r:get_resource("peasant") + assert(p<200 and p>=200-n) + -- assert(u:get_item("money")==10) +end + +function test_produce() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u:clear_orders() + u:set_skill("weaponsmithing", 3) + u:add_item("iron", 2) + u:add_item("money", u.number * 10) + u:add_order("MACHE Schwert") + process_orders() + assert(u:get_item("iron")==1) + assert(u:get_item("sword")==1) +end + +function test_work() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + f.id = 42 + local u = unit.create(f, r, 1) + u:add_item("money", u.number * 10) -- humans cost 10 + u:set_skill("herbalism", 5) + u:clear_orders() + u:add_order("ARBEITEN") + process_orders() + assert(u:get_item("money")>=10) +end + +function test_upkeep() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + f.id = 42 + local u = unit.create(f, r, 5) + u:add_item("money", u.number * 11) + u:clear_orders() + u:add_order("LERNE Waffenbau") + process_orders() + assert(u:get_item("money")==u.number) +end + +function test_id() + free_game() + local r = region.create(0, 0, "plain") + + local f = faction.create("noreply@eressea.de", "human", "de") + f.id = atoi36("42") + assert(get_faction(42)~=f) + assert(get_faction("42")==f) + assert(get_faction(atoi36("42"))==f) + + local u = unit.create(f, r, 1) + u.id = atoi36("42") + assert(get_unit(42)~=u) + assert(get_unit("42")==u) + assert(get_unit(atoi36("42"))==u) + + local b = building.create(r, "castle") + -- b.id = atoi36("42") + local fortytwo = itoa36(b.id) + assert(get_building(fortytwo)==b) + assert(get_building(atoi36(fortytwo))==b) + + local s = ship.create(r, "canoe") + if (s==nil) then + s = ship.create(r, "boat") + end + -- s.id = atoi36("42") + local fortytwo = itoa36(s.id) + assert(get_ship(fortytwo)==s) + assert(get_ship(atoi36(fortytwo))==s) +end + +function test_herbalism() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + f.id = 42 + local u = unit.create(f, r, 1) + u:add_item("money", u.number * 100) + u:set_skill("herbalism", 5) + u:clear_orders() + u:add_order("MACHE Samen") + process_orders() +end + +function test_mallorn() + free_game() + local r = region.create(0, 0, "plain") + r:set_flag(1, false) -- not mallorn + r:set_resource("tree", 100) + assert(r:get_resource("tree")==100) + local m = region.create(0, 0, "plain") + m:set_flag(1, true) -- not mallorn + m:set_resource("tree", 100) + assert(m:get_resource("tree")==100) + + local f = faction.create("noreply@eressea.de", "human", "de") + + local u1 = unit.create(f, r, 1) + u1:add_item("money", u1.number * 100) + u1:set_skill("forestry", 2) + u1:clear_orders() + u1:add_order("MACHE HOLZ") + + local u2 = unit.create(f, m, 1) + u2:add_item("money", u2.number * 100) + u2:set_skill("forestry", 2) + u2:clear_orders() + u2:add_order("MACHE HOLZ") + + local u3 = unit.create(f, m, 1) + u3:add_item("money", u3.number * 100) + u3:set_skill("forestry", 2) + u3:clear_orders() + u3:add_order("MACHE Mallorn") + process_orders() + assert(u1:get_item("log")==2) + assert(u2:get_item("log")==2) + assert(u3:get_item("mallorn")==1) +end + +function test_coordinate_translation() + local pl = plane.create(1, 500, 500, 1001, 1001) -- astralraum + local pe = plane.create(1, -8761, 3620, 23, 23) -- eternath + local r = region.create(1000, 1000, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + assert_not_equal(nil, r) + assert_equal(r.x, 1000) + assert_equal(r.y, 1000) + local nx, ny = plane.normalize(pl, r.x, r.y) + assert_equal(nx, 1000) + assert_equal(ny, 1000) + local r1 = region.create(500, 500, "plain") + f:set_origin(r1) + nx, ny = f:normalize(r1) + assert_equal(0, nx) + assert_equal(0, ny) + local r0 = region.create(0, 0, "plain") + nx, ny = f:normalize(r0) + assert_equal(0, nx) + assert_equal(0, ny) + nx, ny = f:normalize(r) + assert_equal(500, nx) + assert_equal(500, ny) + local rn = region.create(1010, 1010, "plain") + nx, ny = f:normalize(rn) + assert_equal(-491, nx) + assert_equal(-491, ny) + + local re = region.create(-8760, 3541, "plain") -- eternath + nx, ny = f:normalize(rn) + assert_equal(-491, nx) + assert_equal(-491, ny) +end + +function test_control() + free_game() + local u1, u2 = two_units(region.create(0, 0, "plain"), two_factions()) + local r = u1.region + local b = building.create(r, "castle") + u1.building = b + u2.building = b + assert_equal(u1, b.owner) + u1:clear_orders() + u1:add_order("GIB " .. itoa36(u2.id) .. " KOMMANDO") + u1:add_order("VERLASSE") + process_orders() + assert_equal(u2, b.owner) +end + +function test_storage() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + f.id = 42 + local u = unit.create(f, r, 1) + u:add_item("money", u.number * 100) + store = storage.create("test.unit.dat", "wb") + assert_not_equal(store, nil) + store:write_unit(u) + store:close() + free_game() + -- recreate world: + r = region.create(0, 0, "plain") + f = faction.create("noreply@eressea.de", "human", "de") + f.id = 42 + store = storage.create("test.unit.dat", "rb") + assert(store) + u = store:read_unit() + store:close() + assert(u) + assert(u:get_item("money") == u.number * 100) +end + +function test_building_other() + local r = region.create(0,0, "plain") + local f1 = faction.create("noreply@eressea.de", "human", "de") + local f2 = faction.create("noreply@eressea.de", "human", "de") + local b = building.create(r, "castle") + b.size = 10 + local u1 = unit.create(f1, r, 3) + u1.building = b + u1:add_item("money", 100) + + local u2 = unit.create(f2, r, 3) + u2:set_skill("building", 10) + u2:add_item("money", 100) + u2:add_item("stone", 100) + u2:clear_orders() + u2:add_order("MACHEN BURG " .. itoa36(b.id)) + process_orders() + assert_not_equal(10, b.size) +end + +function test_config() + assert_not_equal(nil, config.basepath) + assert_not_equal(nil, config.locales) +end + +function test_guard_resources() + -- this is not quite http://bugs.eressea.de/view.php?id=1756 + local r = region.create(0,0, "mountain") + local f1 = faction.create("noreply@eressea.de", "human", "de") + f1.age=20 + local f2 = faction.create("noreply@eressea.de", "human", "de") + f2.age=20 + local u1 = unit.create(f1, r, 1) + u1:add_item("money", 100) + u1:set_skill("melee", 3) + u1:add_item("sword", 1) + u1:clear_orders() + u1:add_order("BEWACHEN") + + local u2 = unit.create(f2, r, 1) + u2:add_item("money", 100) + u2:set_skill("mining", 3) + u2:clear_orders() + u2:add_order("MACHEN EISEN") + + process_orders() + local iron = u2:get_item("iron") + process_orders() + assert_equal(iron, u2:get_item("iron")) +end + +local function is_flag_set(flags, flag) + return math.mod(flags, flag*2) - math.mod(flags, flag) == flag; +end + +function test_hero_hero_transfer() + local r = region.create(0,0, "mountain") + local f = faction.create("noreply@eressea.de", "human", "de") + f.age=20 + local UFL_HERO = 128 + + local u1 = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + u1:add_item("money", 10000) + u1.flags = u1.flags + UFL_HERO + u2.flags = u2.flags + UFL_HERO + u1:clear_orders() + u1:add_order("GIB " .. itoa36(u2.id) .. " 1 PERSONEN") + u1:add_order("REKRUTIEREN 1") + process_orders() + assert_equal(1, u1.number) + assert_equal(2, u2.number) + assert_false(is_flag_set(u1.flags, 128), 128, "recruiting into an empty hero unit should not create a hero") + assert_true(is_flag_set(u2.flags, 128), 128, "unit is not a hero?") +end + +function test_hero_normal_transfer() + local r = region.create(0,0, "mountain") + local f = faction.create("noreply@eressea.de", "human", "de") + f.age=20 + local UFL_HERO = 128 + + local u1 = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + u1:add_item("money", 10000) + u1.flags = u1.flags + UFL_HERO + u1:clear_orders() + u1:add_order("GIB " .. itoa36(u2.id) .. " 1 PERSONEN") + process_orders() + assert_equal(1, u1.number) + assert_equal(1, u2.number) + assert_true(is_flag_set(u1.flags, 128), "unit is not a hero?") + assert_false(is_flag_set(u2.flags, 128), "unit turned into a hero") +end diff --git a/scripts/tests/spells.lua b/scripts/tests/spells.lua index e71935aa8..c88b70abf 100644 --- a/scripts/tests/spells.lua +++ b/scripts/tests/spells.lua @@ -1,64 +1,64 @@ -require "lunit" - -module( "spells", package.seeall, lunit.testcase ) - -function setup() - free_game() -end - -function test_roi() - local r = region.create(0,0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - local u = unit.create(f, r, 1) - u.race = "elf" - u:set_skill("magic", 10) - u:add_item("money", 3010) - u.magic = "tybied" - u.aura = 200 - u.ship = s1 - u:add_spell("create_roi") - u:clear_orders() - u:add_order("ZAUBERE 'Erschaffe einen Ring der Unsichtbarkeit' ") - process_orders() - write_reports() - assert_equal(1, u:get_item("roi")) -end - -function test_blessedharvest_lasts_n_turn() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "halfling", "de") - local u = unit.create(f, r) - r:set_resource("peasant", 100) - r:set_resource("money", 0) - u:add_item("money", 1000) - u.magic = "gwyrrd" - u.race = "dwarf" - u:set_skill("magic", 20) - u.aura = 200 - u:add_spell("raindance") - u:add_spell("blessedharvest") - u:clear_orders() - local level = 5 - u:add_order("ZAUBERE STUFE " .. level .. " Regentanz") - assert_equal(0, r:get_resource("money"), 0) - - local m = 0 - local p = 100 - for i=1,level+2 do - process_orders() - local income = p * 12 - p = r:get_resource("peasant") - income = income - p * 10 - m = m + income - -- print(i, m, p, r:get_resource("money")) - if (i>level+1) then - assert_not_equal(m, r:get_resource("money")) - else - assert_equal(m, r:get_resource("money")) - end - u:clear_orders() - u:add_order("ARBEITEN") --- u:add_spell("raindance") - end -end +require "lunit" + +module( "spells", package.seeall, lunit.testcase ) + +function setup() + free_game() +end + +function test_roi() + local r = region.create(0,0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u.race = "elf" + u:set_skill("magic", 10) + u:add_item("money", 3010) + u.magic = "tybied" + u.aura = 200 + u.ship = s1 + u:add_spell("create_roi") + u:clear_orders() + u:add_order("ZAUBERE 'Erschaffe einen Ring der Unsichtbarkeit' ") + process_orders() + write_reports() + assert_equal(1, u:get_item("roi")) +end + +function test_blessedharvest_lasts_n_turn() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "halfling", "de") + local u = unit.create(f, r) + r:set_resource("peasant", 100) + r:set_resource("money", 0) + u:add_item("money", 1000) + u.magic = "gwyrrd" + u.race = "dwarf" + u:set_skill("magic", 20) + u.aura = 200 + u:add_spell("raindance") + u:add_spell("blessedharvest") + u:clear_orders() + local level = 5 + u:add_order("ZAUBERE STUFE " .. level .. " Regentanz") + assert_equal(0, r:get_resource("money"), 0) + + local m = 0 + local p = 100 + for i=1,level+2 do + process_orders() + local income = p * 12 + p = r:get_resource("peasant") + income = income - p * 10 + m = m + income + -- print(i, m, p, r:get_resource("money")) + if (i>level+1) then + assert_not_equal(m, r:get_resource("money")) + else + assert_equal(m, r:get_resource("money")) + end + u:clear_orders() + u:add_order("ARBEITEN") +-- u:add_spell("raindance") + end +end diff --git a/src/attributes/aggressive.h b/src/attributes/aggressive.h index dd6060637..bcd173cd7 100644 --- a/src/attributes/aggressive.h +++ b/src/attributes/aggressive.h @@ -1,33 +1,33 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_AGGRESSIVE -#define H_ATTRIBUTE_AGGRESSIVE -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_aggressive; -extern struct attrib * make_aggressive(double probability); -extern void init_aggressive(void); - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_AGGRESSIVE +#define H_ATTRIBUTE_AGGRESSIVE +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_aggressive; +extern struct attrib * make_aggressive(double probability); +extern void init_aggressive(void); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/alliance.c b/src/attributes/alliance.c index 526ec18db..c0fd3a9a7 100644 --- a/src/attributes/alliance.c +++ b/src/attributes/alliance.c @@ -1,34 +1,34 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "alliance.h" - -#include -#include - -attrib_type at_alliance = { - "alliance", - NULL, - NULL, - NULL, - a_writeint, - a_readint, - ATF_UNIQUE -}; +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "alliance.h" + +#include +#include + +attrib_type at_alliance = { + "alliance", + NULL, + NULL, + NULL, + a_writeint, + a_readint, + ATF_UNIQUE +}; diff --git a/src/attributes/alliance.h b/src/attributes/alliance.h index 42336c47b..d89f70989 100644 --- a/src/attributes/alliance.h +++ b/src/attributes/alliance.h @@ -1,31 +1,31 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_ALLIANCE -#define H_ATTRIBUTE_ALLIANCE -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_alliance; - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_ALLIANCE +#define H_ATTRIBUTE_ALLIANCE +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_alliance; + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/attributes.c b/src/attributes/attributes.c index 8e9d4a0cd..0efc00aba 100644 --- a/src/attributes/attributes.c +++ b/src/attributes/attributes.c @@ -1,81 +1,81 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "attributes.h" - -/* attributes includes */ -#include "follow.h" -#include "gm.h" -#include "hate.h" -#include "iceberg.h" -#include "key.h" -#include "moved.h" -#include "movement.h" -#include "object.h" -#include "orcification.h" -#include "otherfaction.h" -#include "overrideroads.h" -#include "racename.h" -#include "raceprefix.h" -#include "reduceproduction.h" -#include "targetregion.h" -#ifdef WDW_PYRAMID -# include "alliance.h" -#endif - -/* kernel includes */ -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include - -attrib_type at_unitdissolve = { - "unitdissolve", NULL, NULL, NULL, a_writechars, a_readchars -}; - -void -register_attributes(void) -{ - at_register(&at_object); - at_register(&at_unitdissolve); - at_register(&at_overrideroads); - at_register(&at_raceprefix); - at_register(&at_iceberg); - at_register(&at_key); - at_register(&at_gm); - at_register(&at_follow); - at_register(&at_targetregion); - at_register(&at_orcification); - at_register(&at_hate); - at_register(&at_reduceproduction); - at_register(&at_otherfaction); - at_register(&at_racename); - at_register(&at_movement); - at_register(&at_moved); - -#ifdef WDW_PYRAMID - at_register(&at_alliance); -#endif /* WDW_PYRAMID */ -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "attributes.h" + +/* attributes includes */ +#include "follow.h" +#include "gm.h" +#include "hate.h" +#include "iceberg.h" +#include "key.h" +#include "moved.h" +#include "movement.h" +#include "object.h" +#include "orcification.h" +#include "otherfaction.h" +#include "overrideroads.h" +#include "racename.h" +#include "raceprefix.h" +#include "reduceproduction.h" +#include "targetregion.h" +#ifdef WDW_PYRAMID +# include "alliance.h" +#endif + +/* kernel includes */ +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include + +attrib_type at_unitdissolve = { + "unitdissolve", NULL, NULL, NULL, a_writechars, a_readchars +}; + +void +register_attributes(void) +{ + at_register(&at_object); + at_register(&at_unitdissolve); + at_register(&at_overrideroads); + at_register(&at_raceprefix); + at_register(&at_iceberg); + at_register(&at_key); + at_register(&at_gm); + at_register(&at_follow); + at_register(&at_targetregion); + at_register(&at_orcification); + at_register(&at_hate); + at_register(&at_reduceproduction); + at_register(&at_otherfaction); + at_register(&at_racename); + at_register(&at_movement); + at_register(&at_moved); + +#ifdef WDW_PYRAMID + at_register(&at_alliance); +#endif /* WDW_PYRAMID */ +} diff --git a/src/attributes/attributes.h b/src/attributes/attributes.h index 594ecf3f3..76ba24069 100644 --- a/src/attributes/attributes.h +++ b/src/attributes/attributes.h @@ -1,31 +1,31 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_ATTRIBUTES -#define H_ATTRIBUTE_ATTRIBUTES -#ifdef __cplusplus -extern "C" { -#endif - -extern void register_attributes(void); - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_ATTRIBUTES +#define H_ATTRIBUTE_ATTRIBUTES +#ifdef __cplusplus +extern "C" { +#endif + +extern void register_attributes(void); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/fleechance.c b/src/attributes/fleechance.c index 24062bd55..cb092c7d1 100644 --- a/src/attributes/fleechance.c +++ b/src/attributes/fleechance.c @@ -1,45 +1,45 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "fleechance.h" - -#include - -attrib_type at_fleechance = { - "fleechance", - NULL, - NULL, - NULL, - NULL, - NULL, -}; - -attrib * -make_fleechance(float fleechance) -{ - attrib * a = a_new(&at_fleechance); - a->data.flt = fleechance; - return a; -} - -void -init_fleechance(void) -{ - at_register(&at_fleechance); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "fleechance.h" + +#include + +attrib_type at_fleechance = { + "fleechance", + NULL, + NULL, + NULL, + NULL, + NULL, +}; + +attrib * +make_fleechance(float fleechance) +{ + attrib * a = a_new(&at_fleechance); + a->data.flt = fleechance; + return a; +} + +void +init_fleechance(void) +{ + at_register(&at_fleechance); +} diff --git a/src/attributes/fleechance.h b/src/attributes/fleechance.h index 482b1ad64..d26b4095e 100644 --- a/src/attributes/fleechance.h +++ b/src/attributes/fleechance.h @@ -1,33 +1,33 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_FLEECHANCE -#define H_ATTRIBUTE_FLEECHANCE -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_fleechance; - -extern struct attrib * make_fleechance(float fleechance); -extern void init_fleechance(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_FLEECHANCE +#define H_ATTRIBUTE_FLEECHANCE +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_fleechance; + +extern struct attrib * make_fleechance(float fleechance); +extern void init_fleechance(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/attributes/follow.c b/src/attributes/follow.c index d080a0d49..519372830 100644 --- a/src/attributes/follow.c +++ b/src/attributes/follow.c @@ -1,46 +1,46 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "follow.h" - -#include -#include - -#include -#include -#include - -static int -read_follow(attrib * a, void * owner, struct storage * store) -{ - read_unit_reference(store); /* skip it */ - return AT_READ_FAIL; -} - -attrib_type at_follow = { - "follow", NULL, NULL, NULL, NULL, read_follow -}; - -attrib * -make_follow(struct unit * u) -{ - attrib * a = a_new(&at_follow); - a->data.v = u; - return a; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "follow.h" + +#include +#include + +#include +#include +#include + +static int +read_follow(attrib * a, void * owner, struct storage * store) +{ + read_unit_reference(store); /* skip it */ + return AT_READ_FAIL; +} + +attrib_type at_follow = { + "follow", NULL, NULL, NULL, NULL, read_follow +}; + +attrib * +make_follow(struct unit * u) +{ + attrib * a = a_new(&at_follow); + a->data.v = u; + return a; +} diff --git a/src/attributes/follow.h b/src/attributes/follow.h index 0328949cc..f619842d8 100644 --- a/src/attributes/follow.h +++ b/src/attributes/follow.h @@ -1,35 +1,35 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_FOLLOW -#define H_ATTRIBUTE_FOLLOW -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_follow; - -struct unit; - -extern struct attrib * make_follow(struct unit * u); - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_FOLLOW +#define H_ATTRIBUTE_FOLLOW +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_follow; + +struct unit; + +extern struct attrib * make_follow(struct unit * u); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/giveitem.c b/src/attributes/giveitem.c index db0b136eb..ed393e28e 100644 --- a/src/attributes/giveitem.c +++ b/src/attributes/giveitem.c @@ -1,135 +1,135 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "giveitem.h" -#include - -/* kernel includes */ -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include - -typedef struct give_data { - struct building * building; - struct item * items; -} give_data; - -static void -a_writegive(const attrib * a, const void * owner, struct storage * store) -{ - give_data * gdata = (give_data*)a->data.v; - item * itm; - write_building_reference(gdata->building, store); - for (itm=gdata->items;itm;itm=itm->next) { - store->w_tok(store, resourcename(itm->type->rtype, 0)); - store->w_int(store, itm->number); - } - store->w_tok(store, "end"); -} - -static int -a_readgive(attrib * a, void * owner, struct storage * store) -{ - give_data * gdata = (give_data*)a->data.v; - variant var; - char zText[32]; - - var.i = store->r_id(store); - if (var.i>0) { - gdata->building = findbuilding(var.i); - if (gdata->building==NULL) { - ur_add(var, &gdata->building, resolve_building); - } - } else { - gdata->building=NULL; - } - for (;;) { - int i; - store->r_tok_buf(store, zText, sizeof(zText)); - if (!strcmp("end", zText)) break; - i = store->r_int(store); - if (i==0) i_add(&gdata->items, i_new(it_find(zText), i)); - } - return AT_READ_OK; -} - -static void -a_initgive(struct attrib * a) -{ - a->data.v = calloc(sizeof(give_data), 1); -} - -static void -a_finalizegive(struct attrib * a) -{ - free(a->data.v); -} - -static int -a_giveitem(attrib * a) -{ - give_data * gdata = (give_data*)a->data.v; - region * r; - unit * u; - if (gdata->building==NULL || gdata->items==NULL) return 0; - r = gdata->building->region; - u = building_owner(gdata->building); - if (u==NULL) return 1; - while (gdata->items) { - item * itm = gdata->items; - i_change(&u->items, itm->type, itm->number); - i_free(i_remove(&gdata->items, itm)); - } - return 0; -} - -attrib_type at_giveitem = { - "giveitem", - a_initgive, a_finalizegive, - a_giveitem, - a_writegive, a_readgive -}; - -attrib * -make_giveitem(struct building * b, struct item * ip) -{ - attrib * a = a_new(&at_giveitem); - give_data * gd = (give_data*)a->data.v; - gd->building = b; - gd->items = ip; - return a; -} - -void -init_giveitem(void) -{ - at_register(&at_giveitem); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "giveitem.h" +#include + +/* kernel includes */ +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include + +typedef struct give_data { + struct building * building; + struct item * items; +} give_data; + +static void +a_writegive(const attrib * a, const void * owner, struct storage * store) +{ + give_data * gdata = (give_data*)a->data.v; + item * itm; + write_building_reference(gdata->building, store); + for (itm=gdata->items;itm;itm=itm->next) { + store->w_tok(store, resourcename(itm->type->rtype, 0)); + store->w_int(store, itm->number); + } + store->w_tok(store, "end"); +} + +static int +a_readgive(attrib * a, void * owner, struct storage * store) +{ + give_data * gdata = (give_data*)a->data.v; + variant var; + char zText[32]; + + var.i = store->r_id(store); + if (var.i>0) { + gdata->building = findbuilding(var.i); + if (gdata->building==NULL) { + ur_add(var, &gdata->building, resolve_building); + } + } else { + gdata->building=NULL; + } + for (;;) { + int i; + store->r_tok_buf(store, zText, sizeof(zText)); + if (!strcmp("end", zText)) break; + i = store->r_int(store); + if (i==0) i_add(&gdata->items, i_new(it_find(zText), i)); + } + return AT_READ_OK; +} + +static void +a_initgive(struct attrib * a) +{ + a->data.v = calloc(sizeof(give_data), 1); +} + +static void +a_finalizegive(struct attrib * a) +{ + free(a->data.v); +} + +static int +a_giveitem(attrib * a) +{ + give_data * gdata = (give_data*)a->data.v; + region * r; + unit * u; + if (gdata->building==NULL || gdata->items==NULL) return 0; + r = gdata->building->region; + u = building_owner(gdata->building); + if (u==NULL) return 1; + while (gdata->items) { + item * itm = gdata->items; + i_change(&u->items, itm->type, itm->number); + i_free(i_remove(&gdata->items, itm)); + } + return 0; +} + +attrib_type at_giveitem = { + "giveitem", + a_initgive, a_finalizegive, + a_giveitem, + a_writegive, a_readgive +}; + +attrib * +make_giveitem(struct building * b, struct item * ip) +{ + attrib * a = a_new(&at_giveitem); + give_data * gd = (give_data*)a->data.v; + gd->building = b; + gd->items = ip; + return a; +} + +void +init_giveitem(void) +{ + at_register(&at_giveitem); +} diff --git a/src/attributes/giveitem.h b/src/attributes/giveitem.h index e45d3df56..673738960 100644 --- a/src/attributes/giveitem.h +++ b/src/attributes/giveitem.h @@ -1,36 +1,36 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_GIVEITEM -#define H_ATTRIBUTE_GIVEITEM -#ifdef __cplusplus -extern "C" { -#endif - -struct building; -struct item; - -extern struct attrib_type at_giveitem; - -extern struct attrib * make_giveitem(struct building * b, struct item * items); -extern void init_giveitem(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_GIVEITEM +#define H_ATTRIBUTE_GIVEITEM +#ifdef __cplusplus +extern "C" { +#endif + +struct building; +struct item; + +extern struct attrib_type at_giveitem; + +extern struct attrib * make_giveitem(struct building * b, struct item * items); +extern void init_giveitem(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/attributes/gm.c b/src/attributes/gm.c index bf062722a..9f2514e17 100644 --- a/src/attributes/gm.c +++ b/src/attributes/gm.c @@ -1,61 +1,61 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "gm.h" - -/* kernel includes */ -#include - -/* util includes */ -#include -#include - -static void -write_gm(const attrib * a, const void * owner, struct storage * store) -{ - write_plane_reference((plane*)a->data.v, store); -} - -static int -read_gm(attrib * a, void * owner, struct storage * store) -{ - plane * pl; - int result = read_plane_reference(&pl, store); - a->data.v = pl; - return result; -} - - -attrib_type at_gm = { - "gm", - NULL, - NULL, - NULL, - write_gm, - read_gm, -}; - -attrib * -make_gm(const struct plane * pl) -{ - attrib * a = a_new(&at_gm); - a->data.v = (void*)pl; - return a; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "gm.h" + +/* kernel includes */ +#include + +/* util includes */ +#include +#include + +static void +write_gm(const attrib * a, const void * owner, struct storage * store) +{ + write_plane_reference((plane*)a->data.v, store); +} + +static int +read_gm(attrib * a, void * owner, struct storage * store) +{ + plane * pl; + int result = read_plane_reference(&pl, store); + a->data.v = pl; + return result; +} + + +attrib_type at_gm = { + "gm", + NULL, + NULL, + NULL, + write_gm, + read_gm, +}; + +attrib * +make_gm(const struct plane * pl) +{ + attrib * a = a_new(&at_gm); + a->data.v = (void*)pl; + return a; +} diff --git a/src/attributes/gm.h b/src/attributes/gm.h index 341b4d76a..757092d43 100644 --- a/src/attributes/gm.h +++ b/src/attributes/gm.h @@ -1,36 +1,36 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_GM -#define H_ATTRIBUTE_GM -#ifdef __cplusplus -extern "C" { -#endif - -/* this is an attribute used by the kernel (isallied) */ - -struct plane; -extern struct attrib_type at_gm; - -extern struct attrib * make_gm(const struct plane *pl); - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_GM +#define H_ATTRIBUTE_GM +#ifdef __cplusplus +extern "C" { +#endif + +/* this is an attribute used by the kernel (isallied) */ + +struct plane; +extern struct attrib_type at_gm; + +extern struct attrib * make_gm(const struct plane *pl); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/hate.c b/src/attributes/hate.c index 545eec8e1..5b0e55423 100644 --- a/src/attributes/hate.c +++ b/src/attributes/hate.c @@ -1,70 +1,70 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "hate.h" - -#include -#include - -#include -#include -#include - -static int -verify_hate(attrib * a) -{ - if (a->data.v==NULL) { - return 0; - } - return 1; -} - -static void -write_hate(const attrib * a, const void * owner, struct storage * store) -{ - write_unit_reference((unit*)a->data.v, store); -} - -static int -read_hate(attrib * a, void * owner, struct storage * store) -{ - int result = read_reference(&a->data.v, store, read_unit_reference, resolve_unit); - if (result==0 && !a->data.v) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -attrib_type at_hate = { - "hates", - NULL, - NULL, - verify_hate, - write_hate, - read_hate, -}; - -attrib * -make_hate(struct unit * u) -{ - attrib * a = a_new(&at_hate); - a->data.v = u; - return a; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "hate.h" + +#include +#include + +#include +#include +#include + +static int +verify_hate(attrib * a) +{ + if (a->data.v==NULL) { + return 0; + } + return 1; +} + +static void +write_hate(const attrib * a, const void * owner, struct storage * store) +{ + write_unit_reference((unit*)a->data.v, store); +} + +static int +read_hate(attrib * a, void * owner, struct storage * store) +{ + int result = read_reference(&a->data.v, store, read_unit_reference, resolve_unit); + if (result==0 && !a->data.v) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +attrib_type at_hate = { + "hates", + NULL, + NULL, + verify_hate, + write_hate, + read_hate, +}; + +attrib * +make_hate(struct unit * u) +{ + attrib * a = a_new(&at_hate); + a->data.v = u; + return a; +} diff --git a/src/attributes/hate.h b/src/attributes/hate.h index e58c6205b..cda5d000c 100644 --- a/src/attributes/hate.h +++ b/src/attributes/hate.h @@ -1,35 +1,35 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_HATE -#define H_ATTRIBUTE_HATE -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_hate; - -struct unit; - -extern struct attrib * make_hate(struct unit * u); - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_HATE +#define H_ATTRIBUTE_HATE +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_hate; + +struct unit; + +extern struct attrib * make_hate(struct unit * u); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/iceberg.c b/src/attributes/iceberg.c index cb0efc7f3..37a26e197 100644 --- a/src/attributes/iceberg.c +++ b/src/attributes/iceberg.c @@ -1,42 +1,42 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "iceberg.h" - -#include -#include - -attrib_type at_iceberg = { - "iceberg_drift", - NULL, - NULL, - NULL, - a_writeint, - a_readint, - ATF_UNIQUE -}; - -attrib * -make_iceberg(direction_t dir) -{ - attrib * a = a_new(&at_iceberg); - a->data.i = (int)dir; - return a; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "iceberg.h" + +#include +#include + +attrib_type at_iceberg = { + "iceberg_drift", + NULL, + NULL, + NULL, + a_writeint, + a_readint, + ATF_UNIQUE +}; + +attrib * +make_iceberg(direction_t dir) +{ + attrib * a = a_new(&at_iceberg); + a->data.i = (int)dir; + return a; +} diff --git a/src/attributes/iceberg.h b/src/attributes/iceberg.h index 2f99d60dd..8356d2365 100644 --- a/src/attributes/iceberg.h +++ b/src/attributes/iceberg.h @@ -1,33 +1,33 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_ICEBERG -#define H_ATTRIBUTE_ICEBERG -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_iceberg; - -extern struct attrib * make_iceberg(direction_t dir); - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_ICEBERG +#define H_ATTRIBUTE_ICEBERG +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_iceberg; + +extern struct attrib * make_iceberg(direction_t dir); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/key.c b/src/attributes/key.c index ea612b01a..3d5d77469 100644 --- a/src/attributes/key.c +++ b/src/attributes/key.c @@ -1,59 +1,59 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "key.h" - -#include -#include - -attrib_type at_key = { - "key", - NULL, - NULL, - NULL, - a_writeint, - a_readint, -}; - -attrib * -add_key(attrib ** alist, int key) -{ - attrib * a = find_key(*alist, key); - if (a==NULL) a = a_add(alist, make_key(key)); - return a; -} - -attrib * -make_key(int key) -{ - attrib * a = a_new(&at_key); - a->data.i = key; - return a; -} - -attrib * -find_key(attrib * alist, int key) -{ - attrib * a = a_find(alist, &at_key); - while (a && a->type==&at_key && a->data.i != key) { - a = a->next; - } - return (a && a->type==&at_key)?a:NULL; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "key.h" + +#include +#include + +attrib_type at_key = { + "key", + NULL, + NULL, + NULL, + a_writeint, + a_readint, +}; + +attrib * +add_key(attrib ** alist, int key) +{ + attrib * a = find_key(*alist, key); + if (a==NULL) a = a_add(alist, make_key(key)); + return a; +} + +attrib * +make_key(int key) +{ + attrib * a = a_new(&at_key); + a->data.i = key; + return a; +} + +attrib * +find_key(attrib * alist, int key) +{ + attrib * a = a_find(alist, &at_key); + while (a && a->type==&at_key && a->data.i != key) { + a = a->next; + } + return (a && a->type==&at_key)?a:NULL; +} diff --git a/src/attributes/key.h b/src/attributes/key.h index 112bbe581..00fc3bdf1 100644 --- a/src/attributes/key.h +++ b/src/attributes/key.h @@ -1,35 +1,35 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_KEY -#define H_ATTRIBUTE_KEY -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_key; - -extern struct attrib * make_key(int key); -extern struct attrib * find_key(struct attrib * alist, int key); -extern struct attrib * add_key(struct attrib ** alist, int key); - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_KEY +#define H_ATTRIBUTE_KEY +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_key; + +extern struct attrib * make_key(int key); +extern struct attrib * find_key(struct attrib * alist, int key); +extern struct attrib * add_key(struct attrib ** alist, int key); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/matmod.c b/src/attributes/matmod.c index 8f8f6bec8..8dd9af252 100644 --- a/src/attributes/matmod.c +++ b/src/attributes/matmod.c @@ -1,40 +1,40 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "matmod.h" - -#include - -attrib_type at_matmod = { - "matmod", - NULL, - NULL, - NULL, - NULL, - NULL, - ATF_PRESERVE -}; - -attrib * -make_matmod(mm_fun function) -{ - attrib * a = a_new(&at_matmod); - a->data.f = (void(*)(void))function; - return a; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "matmod.h" + +#include + +attrib_type at_matmod = { + "matmod", + NULL, + NULL, + NULL, + NULL, + NULL, + ATF_PRESERVE +}; + +attrib * +make_matmod(mm_fun function) +{ + attrib * a = a_new(&at_matmod); + a->data.f = (void(*)(void))function; + return a; +} diff --git a/src/attributes/matmod.h b/src/attributes/matmod.h index e32b6a94c..4c683842c 100644 --- a/src/attributes/matmod.h +++ b/src/attributes/matmod.h @@ -1,37 +1,37 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_MATMOD -#define H_ATTRIBUTE_MATMOD - -#ifdef __cplusplus -extern "C" { -#endif - -struct resource_type; -struct unit; -typedef int (*mm_fun)(const struct unit * u, const struct resource_type * rtype, int value); - -extern struct attrib_type at_matmod; -extern struct attrib * make_matmod(mm_fun function); - -#ifdef __cplusplus -} -#endif - -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_MATMOD +#define H_ATTRIBUTE_MATMOD + +#ifdef __cplusplus +extern "C" { +#endif + +struct resource_type; +struct unit; +typedef int (*mm_fun)(const struct unit * u, const struct resource_type * rtype, int value); + +extern struct attrib_type at_matmod; +extern struct attrib * make_matmod(mm_fun function); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/attributes/moved.c b/src/attributes/moved.c index 08c11ac1e..18b5ad2ec 100644 --- a/src/attributes/moved.c +++ b/src/attributes/moved.c @@ -1,63 +1,63 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "moved.h" - -#include -#include - -static int -age_moved(attrib * a) -{ - --a->data.i; - return a->data.i > 0; -} - -static void -write_moved(const attrib * a, const void * owner, struct storage * store) -{ - store->w_int(store, a->data.i); -} - -static int -read_moved(attrib * a, void * owner, struct storage * store) -{ - a->data.i = store->r_int(store); - if (a->data.i !=0 ) return AT_READ_OK; - else return AT_READ_FAIL; -} - -attrib_type at_moved = { - "moved", NULL, NULL, age_moved, write_moved, read_moved -}; - -boolean -get_moved(attrib ** alist) -{ - return a_find(*alist, &at_moved) ? true : false; -} - -void -set_moved(attrib ** alist) -{ - attrib * a = a_find(*alist, &at_moved); - if (a==NULL) a = a_add(alist, a_new(&at_moved)); - a->data.i = 2; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "moved.h" + +#include +#include + +static int +age_moved(attrib * a) +{ + --a->data.i; + return a->data.i > 0; +} + +static void +write_moved(const attrib * a, const void * owner, struct storage * store) +{ + store->w_int(store, a->data.i); +} + +static int +read_moved(attrib * a, void * owner, struct storage * store) +{ + a->data.i = store->r_int(store); + if (a->data.i !=0 ) return AT_READ_OK; + else return AT_READ_FAIL; +} + +attrib_type at_moved = { + "moved", NULL, NULL, age_moved, write_moved, read_moved +}; + +boolean +get_moved(attrib ** alist) +{ + return a_find(*alist, &at_moved) ? true : false; +} + +void +set_moved(attrib ** alist) +{ + attrib * a = a_find(*alist, &at_moved); + if (a==NULL) a = a_add(alist, a_new(&at_moved)); + a->data.i = 2; +} diff --git a/src/attributes/moved.h b/src/attributes/moved.h index af84797ea..1727829da 100644 --- a/src/attributes/moved.h +++ b/src/attributes/moved.h @@ -1,37 +1,37 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_MOVED -#define H_ATTRIBUTE_MOVED -#ifdef __cplusplus -extern "C" { -#endif - -struct attrib; -struct attrib_type; - -extern boolean get_moved(struct attrib ** alist); -extern void set_moved(struct attrib ** alist); - -extern struct attrib_type at_moved; - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_MOVED +#define H_ATTRIBUTE_MOVED +#ifdef __cplusplus +extern "C" { +#endif + +struct attrib; +struct attrib_type; + +extern boolean get_moved(struct attrib ** alist); +extern void set_moved(struct attrib ** alist); + +extern struct attrib_type at_moved; + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/movement.c b/src/attributes/movement.c index 125fbf779..9834928e5 100644 --- a/src/attributes/movement.c +++ b/src/attributes/movement.c @@ -1,59 +1,59 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "movement.h" - -#include -#include - -static void -write_movement(const attrib * a, const void * owner, struct storage * store) -{ - store->w_int(store, a->data.i); -} - -static int -read_movement(attrib * a, void * owner, struct storage * store) -{ - a->data.i = store->r_int(store); - if (a->data.i !=0 ) return AT_READ_OK; - else return AT_READ_FAIL; -} - -attrib_type at_movement = { - "movement", NULL, NULL, NULL, write_movement, read_movement -}; - -boolean -get_movement(attrib * const * alist, int type) -{ - const attrib * a = a_findc(*alist, &at_movement); - if (a==NULL) return false; - if (a->data.i & type) return true; - return false; -} - -void -set_movement(attrib ** alist, int type) -{ - attrib * a = a_find(*alist, &at_movement); - if (a==NULL) a = a_add(alist, a_new(&at_movement)); - a->data.i |= type; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "movement.h" + +#include +#include + +static void +write_movement(const attrib * a, const void * owner, struct storage * store) +{ + store->w_int(store, a->data.i); +} + +static int +read_movement(attrib * a, void * owner, struct storage * store) +{ + a->data.i = store->r_int(store); + if (a->data.i !=0 ) return AT_READ_OK; + else return AT_READ_FAIL; +} + +attrib_type at_movement = { + "movement", NULL, NULL, NULL, write_movement, read_movement +}; + +boolean +get_movement(attrib * const * alist, int type) +{ + const attrib * a = a_findc(*alist, &at_movement); + if (a==NULL) return false; + if (a->data.i & type) return true; + return false; +} + +void +set_movement(attrib ** alist, int type) +{ + attrib * a = a_find(*alist, &at_movement); + if (a==NULL) a = a_add(alist, a_new(&at_movement)); + a->data.i |= type; +} diff --git a/src/attributes/movement.h b/src/attributes/movement.h index 53ae8f923..dde7c98d4 100644 --- a/src/attributes/movement.h +++ b/src/attributes/movement.h @@ -1,33 +1,33 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_MOVEMENT -#define H_ATTRIBUTE_MOVEMENT -#ifdef __cplusplus -extern "C" { -#endif - -extern boolean get_movement(struct attrib * const * alist, int type); -extern void set_movement(struct attrib ** alist, int type); - -extern struct attrib_type at_movement; - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_MOVEMENT +#define H_ATTRIBUTE_MOVEMENT +#ifdef __cplusplus +extern "C" { +#endif + +extern boolean get_movement(struct attrib * const * alist, int type); +extern void set_movement(struct attrib ** alist, int type); + +extern struct attrib_type at_movement; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/attributes/object.c b/src/attributes/object.c index 033fd8b32..d03a5f32c 100644 --- a/src/attributes/object.c +++ b/src/attributes/object.c @@ -1,267 +1,267 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "object.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include - -/* stdc includes */ -#include -#include - -typedef struct object_data { - object_type type; - char * name; - union { - int i; - char * str; - double real; - struct unit * u; - struct region * r; - struct building * b; - struct ship * sh; - struct faction * f; - } data; -} object_data; - -static void -object_write(const attrib * a, const void * owner, struct storage * store) -{ - const object_data * data = (object_data *)a->data.v; - int type = (int)data->type; - store->w_tok(store, data->name); - store->w_int(store, type); - switch (data->type) { - case TINTEGER: - store->w_int(store, data->data.i); - break; - case TREAL: - store->w_flt(store, (float)data->data.real); - break; - case TSTRING: - store->w_str(store, data->data.str); - break; - case TUNIT: - write_unit_reference(data->data.u, store ); - break; - case TFACTION: - write_faction_reference(data->data.f, store); - break; - case TBUILDING: - write_building_reference(data->data.b, store); - break; - case TSHIP: - /* write_ship_reference(data->data.sh, store); */ - assert(!"not implemented"); - break; - case TREGION: - write_region_reference(data->data.r, store); - break; - case TNONE: - break; - default: - assert(!"illegal type in object-attribute"); - } -} - -static int -object_read(attrib *a, void * owner, struct storage * store) -{ - object_data * data = (object_data *)a->data.v; - int result; - - data->name = store->r_str(store); - data->type = (object_type)store->r_int(store); - switch (data->type) { - case TINTEGER: - data->data.i = store->r_int(store); - break; - case TREAL: - data->data.real = store->r_flt(store); - break; - case TSTRING: - data->data.str = store->r_str(store); - break; - case TBUILDING: - result = read_reference(&data->data.b, store, read_building_reference, resolve_building); - if (result==0 && !data->data.b) { - return AT_READ_FAIL; - } - break; - case TUNIT: - result = read_reference(&data->data.u, store, read_unit_reference, resolve_unit); - if (result==0 && !data->data.u) { - return AT_READ_FAIL; - } - break; - case TFACTION: - result = read_reference(&data->data.f, store, read_faction_reference, resolve_faction); - if (result==0 && !data->data.f) { - return AT_READ_FAIL; - } - break; - case TREGION: - result = read_reference(&data->data.r, store, read_region_reference, RESOLVE_REGION(store->version)); - if (result==0 && !data->data.r) { - return AT_READ_FAIL; - } - break; - case TSHIP: - /* return read_ship_reference(&data->data.sh, store); */ - assert(!"not implemented"); - break; - case TNONE: - break; - default: - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -static void -object_init(attrib * a) -{ - object_data * data; - a->data.v = malloc(sizeof(object_data)); - data = (object_data *)a->data.v; - data->type = TNONE; -} - -static void -object_done(attrib * a) -{ - object_data * data = (object_data *)a->data.v; - if (data->type == TSTRING) free(data->data.str); - free(data->name); - free(a->data.v); -} - -attrib_type at_object = { - "object", object_init, object_done, NULL, - object_write, object_read -}; - -const char * -object_name(const attrib * a) -{ - object_data * data = (object_data *)a->data.v; - return data->name; -} - -struct attrib * -object_create(const char * name, object_type type, variant value) -{ - attrib * a = a_new(&at_object); - object_data * data = (object_data *)a->data.v; - data->name = strdup(name); - - object_set(a, type, value); - return a; -} - -void -object_set(attrib * a, object_type type, variant value) -{ - object_data * data = (object_data *)a->data.v; - - if (data->type==TSTRING) free(data->data.str); - data->type = type; - switch (type) { - case TSTRING: - data->data.str = value.v?strdup(value.v):NULL; - break; - case TINTEGER: - data->data.i = value.i; - break; - case TREAL: - data->data.real = value.f; - break; - case TREGION: - data->data.r = (region*)value.v; - break; - case TBUILDING: - data->data.b = (building*)value.v; - break; - case TFACTION: - data->data.f = (faction*)value.v; - break; - case TUNIT: - data->data.u = (unit*)value.v; - break; - case TSHIP: - data->data.sh = (ship*)value.v; - break; - case TNONE: - break; - default: - assert(!"invalid object-type"); - break; - } -} - -void -object_get(const struct attrib * a, object_type * type, variant * value) -{ - object_data * data = (object_data *)a->data.v; - *type = data->type; - switch (data->type) { - case TSTRING: - value->v = data->data.str; - break; - case TINTEGER: - value->i = data->data.i; - break; - case TREAL: - value->f = (float)data->data.real; - break; - case TREGION: - value->v = data->data.r; - break; - case TBUILDING: - value->v = data->data.b; - break; - case TFACTION: - value->v = data->data.f; - break; - case TUNIT: - value->v = data->data.u; - break; - case TSHIP: - value->v = data->data.sh; - break; - case TNONE: - break; - default: - assert(!"invalid object-type"); - break; - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "object.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include + +/* stdc includes */ +#include +#include + +typedef struct object_data { + object_type type; + char * name; + union { + int i; + char * str; + double real; + struct unit * u; + struct region * r; + struct building * b; + struct ship * sh; + struct faction * f; + } data; +} object_data; + +static void +object_write(const attrib * a, const void * owner, struct storage * store) +{ + const object_data * data = (object_data *)a->data.v; + int type = (int)data->type; + store->w_tok(store, data->name); + store->w_int(store, type); + switch (data->type) { + case TINTEGER: + store->w_int(store, data->data.i); + break; + case TREAL: + store->w_flt(store, (float)data->data.real); + break; + case TSTRING: + store->w_str(store, data->data.str); + break; + case TUNIT: + write_unit_reference(data->data.u, store ); + break; + case TFACTION: + write_faction_reference(data->data.f, store); + break; + case TBUILDING: + write_building_reference(data->data.b, store); + break; + case TSHIP: + /* write_ship_reference(data->data.sh, store); */ + assert(!"not implemented"); + break; + case TREGION: + write_region_reference(data->data.r, store); + break; + case TNONE: + break; + default: + assert(!"illegal type in object-attribute"); + } +} + +static int +object_read(attrib *a, void * owner, struct storage * store) +{ + object_data * data = (object_data *)a->data.v; + int result; + + data->name = store->r_str(store); + data->type = (object_type)store->r_int(store); + switch (data->type) { + case TINTEGER: + data->data.i = store->r_int(store); + break; + case TREAL: + data->data.real = store->r_flt(store); + break; + case TSTRING: + data->data.str = store->r_str(store); + break; + case TBUILDING: + result = read_reference(&data->data.b, store, read_building_reference, resolve_building); + if (result==0 && !data->data.b) { + return AT_READ_FAIL; + } + break; + case TUNIT: + result = read_reference(&data->data.u, store, read_unit_reference, resolve_unit); + if (result==0 && !data->data.u) { + return AT_READ_FAIL; + } + break; + case TFACTION: + result = read_reference(&data->data.f, store, read_faction_reference, resolve_faction); + if (result==0 && !data->data.f) { + return AT_READ_FAIL; + } + break; + case TREGION: + result = read_reference(&data->data.r, store, read_region_reference, RESOLVE_REGION(store->version)); + if (result==0 && !data->data.r) { + return AT_READ_FAIL; + } + break; + case TSHIP: + /* return read_ship_reference(&data->data.sh, store); */ + assert(!"not implemented"); + break; + case TNONE: + break; + default: + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +static void +object_init(attrib * a) +{ + object_data * data; + a->data.v = malloc(sizeof(object_data)); + data = (object_data *)a->data.v; + data->type = TNONE; +} + +static void +object_done(attrib * a) +{ + object_data * data = (object_data *)a->data.v; + if (data->type == TSTRING) free(data->data.str); + free(data->name); + free(a->data.v); +} + +attrib_type at_object = { + "object", object_init, object_done, NULL, + object_write, object_read +}; + +const char * +object_name(const attrib * a) +{ + object_data * data = (object_data *)a->data.v; + return data->name; +} + +struct attrib * +object_create(const char * name, object_type type, variant value) +{ + attrib * a = a_new(&at_object); + object_data * data = (object_data *)a->data.v; + data->name = strdup(name); + + object_set(a, type, value); + return a; +} + +void +object_set(attrib * a, object_type type, variant value) +{ + object_data * data = (object_data *)a->data.v; + + if (data->type==TSTRING) free(data->data.str); + data->type = type; + switch (type) { + case TSTRING: + data->data.str = value.v?strdup(value.v):NULL; + break; + case TINTEGER: + data->data.i = value.i; + break; + case TREAL: + data->data.real = value.f; + break; + case TREGION: + data->data.r = (region*)value.v; + break; + case TBUILDING: + data->data.b = (building*)value.v; + break; + case TFACTION: + data->data.f = (faction*)value.v; + break; + case TUNIT: + data->data.u = (unit*)value.v; + break; + case TSHIP: + data->data.sh = (ship*)value.v; + break; + case TNONE: + break; + default: + assert(!"invalid object-type"); + break; + } +} + +void +object_get(const struct attrib * a, object_type * type, variant * value) +{ + object_data * data = (object_data *)a->data.v; + *type = data->type; + switch (data->type) { + case TSTRING: + value->v = data->data.str; + break; + case TINTEGER: + value->i = data->data.i; + break; + case TREAL: + value->f = (float)data->data.real; + break; + case TREGION: + value->v = data->data.r; + break; + case TBUILDING: + value->v = data->data.b; + break; + case TFACTION: + value->v = data->data.f; + break; + case TUNIT: + value->v = data->data.u; + break; + case TSHIP: + value->v = data->data.sh; + break; + case TNONE: + break; + default: + assert(!"invalid object-type"); + break; + } +} diff --git a/src/attributes/object.h b/src/attributes/object.h index c0ebcab7e..61c13cb5d 100644 --- a/src/attributes/object.h +++ b/src/attributes/object.h @@ -1,38 +1,38 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_ATTRIBUTE_OBJECT -#define H_ATTRIBUTE_OBJECT - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - TNONE = 0, TINTEGER = 1, TREAL = 2, TSTRING = 3, - TUNIT = 10, TFACTION = 11, TREGION = 12, TBUILDING = 13, TSHIP = 14, -} object_type; - -extern struct attrib_type at_object; - -extern struct attrib * object_create(const char * name, object_type type, variant value); -extern void object_get(const struct attrib * a, object_type * type, variant * value); -extern void object_set(struct attrib * a, object_type type, variant value); -extern const char * object_name(const struct attrib * a); - -#ifdef __cplusplus -} -#endif -#endif - +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_ATTRIBUTE_OBJECT +#define H_ATTRIBUTE_OBJECT + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + TNONE = 0, TINTEGER = 1, TREAL = 2, TSTRING = 3, + TUNIT = 10, TFACTION = 11, TREGION = 12, TBUILDING = 13, TSHIP = 14, +} object_type; + +extern struct attrib_type at_object; + +extern struct attrib * object_create(const char * name, object_type type, variant value); +extern void object_get(const struct attrib * a, object_type * type, variant * value); +extern void object_set(struct attrib * a, object_type type, variant value); +extern const char * object_name(const struct attrib * a); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/orcification.c b/src/attributes/orcification.c index 745d13e24..1e2b8822b 100644 --- a/src/attributes/orcification.c +++ b/src/attributes/orcification.c @@ -1,40 +1,40 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "orcification.h" - -#include -#include - -/* - * simple attributes that do not yet have their own file - */ - -attrib_type at_orcification = { - "orcification", NULL, NULL, NULL, a_writeint, a_readint, ATF_UNIQUE -}; - -attrib * -make_orcification(int orcification) -{ - attrib * a = a_new(&at_orcification); - a->data.i = orcification; - return a; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "orcification.h" + +#include +#include + +/* + * simple attributes that do not yet have their own file + */ + +attrib_type at_orcification = { + "orcification", NULL, NULL, NULL, a_writeint, a_readint, ATF_UNIQUE +}; + +attrib * +make_orcification(int orcification) +{ + attrib * a = a_new(&at_orcification); + a->data.i = orcification; + return a; +} diff --git a/src/attributes/orcification.h b/src/attributes/orcification.h index 285e9414e..51a167276 100644 --- a/src/attributes/orcification.h +++ b/src/attributes/orcification.h @@ -1,28 +1,28 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifdef __cplusplus -extern "C" { -#endif -extern struct attrib_type at_orcification; - -extern struct attrib * make_orcification(int orcification); - -#ifdef __cplusplus -} -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifdef __cplusplus +extern "C" { +#endif +extern struct attrib_type at_orcification; + +extern struct attrib * make_orcification(int orcification); + +#ifdef __cplusplus +} +#endif diff --git a/src/attributes/otherfaction.c b/src/attributes/otherfaction.c index 14c4a3d03..c970b4ed2 100644 --- a/src/attributes/otherfaction.c +++ b/src/attributes/otherfaction.c @@ -1,80 +1,80 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "otherfaction.h" - -#include -#include -#include -#include -#include - -/* - * simple attributes that do not yet have their own file - */ - - -void -write_of(const struct attrib * a, const void * owner, struct storage * store) -{ - const faction * f = (faction*)a->data.v; - store->w_int(store, f->no); -} - -int -read_of(struct attrib * a, void * owner, struct storage * store) /* return 1 on success, 0 if attrib needs removal */ -{ - int of = store->r_int(store); - a->data.v = findfaction(of); - if (a->data.v) return AT_READ_OK; - return AT_READ_FAIL; -} - -attrib_type at_otherfaction = { - "otherfaction", NULL, NULL, NULL, write_of, read_of, ATF_UNIQUE -}; - -struct faction * - get_otherfaction(const struct attrib * a) -{ - return (faction*)(a->data.v); -} - -struct attrib * - make_otherfaction(struct faction * f) -{ - attrib * a = a_new(&at_otherfaction); - a->data.v = (void*)f; - return a; -} - -faction * -visible_faction(const faction *f, const unit * u) -{ - if (f==NULL || !alliedunit(u, f, HELP_FSTEALTH)) { - attrib *a = a_find(u->attribs, &at_otherfaction); - if (a) { - faction *fv = get_otherfaction(a); - assert (fv != NULL); /* fv should never be NULL! */ - return fv; - } - } - return u->faction; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "otherfaction.h" + +#include +#include +#include +#include +#include + +/* + * simple attributes that do not yet have their own file + */ + + +void +write_of(const struct attrib * a, const void * owner, struct storage * store) +{ + const faction * f = (faction*)a->data.v; + store->w_int(store, f->no); +} + +int +read_of(struct attrib * a, void * owner, struct storage * store) /* return 1 on success, 0 if attrib needs removal */ +{ + int of = store->r_int(store); + a->data.v = findfaction(of); + if (a->data.v) return AT_READ_OK; + return AT_READ_FAIL; +} + +attrib_type at_otherfaction = { + "otherfaction", NULL, NULL, NULL, write_of, read_of, ATF_UNIQUE +}; + +struct faction * + get_otherfaction(const struct attrib * a) +{ + return (faction*)(a->data.v); +} + +struct attrib * + make_otherfaction(struct faction * f) +{ + attrib * a = a_new(&at_otherfaction); + a->data.v = (void*)f; + return a; +} + +faction * +visible_faction(const faction *f, const unit * u) +{ + if (f==NULL || !alliedunit(u, f, HELP_FSTEALTH)) { + attrib *a = a_find(u->attribs, &at_otherfaction); + if (a) { + faction *fv = get_otherfaction(a); + assert (fv != NULL); /* fv should never be NULL! */ + return fv; + } + } + return u->faction; +} diff --git a/src/attributes/otherfaction.h b/src/attributes/otherfaction.h index 4fe99f295..79c6b24ad 100644 --- a/src/attributes/otherfaction.h +++ b/src/attributes/otherfaction.h @@ -1,33 +1,33 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifdef __cplusplus -extern "C" { -#endif - -struct faction; -struct attrib; -extern struct attrib_type at_otherfaction; - -extern struct faction * get_otherfaction(const struct attrib * a); -extern struct attrib * make_otherfaction(struct faction * f); -extern struct faction * visible_faction(const struct faction *f, const struct unit * u); - -#ifdef __cplusplus -extern "C" { -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifdef __cplusplus +extern "C" { +#endif + +struct faction; +struct attrib; +extern struct attrib_type at_otherfaction; + +extern struct faction * get_otherfaction(const struct attrib * a); +extern struct attrib * make_otherfaction(struct faction * f); +extern struct faction * visible_faction(const struct faction *f, const struct unit * u); + +#ifdef __cplusplus +extern "C" { +#endif diff --git a/src/attributes/overrideroads.c b/src/attributes/overrideroads.c index 96803a2a9..e1dc75b3d 100644 --- a/src/attributes/overrideroads.c +++ b/src/attributes/overrideroads.c @@ -1,29 +1,29 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "overrideroads.h" - -#include -#include - -attrib_type at_overrideroads = { - "roads_override", NULL, NULL, NULL, &a_writestring, &a_readstring -}; - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "overrideroads.h" + +#include +#include + +attrib_type at_overrideroads = { + "roads_override", NULL, NULL, NULL, &a_writestring, &a_readstring +}; + diff --git a/src/attributes/overrideroads.h b/src/attributes/overrideroads.h index a9322c598..731c9eee9 100644 --- a/src/attributes/overrideroads.h +++ b/src/attributes/overrideroads.h @@ -1,31 +1,31 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_OVERRRIDEROADS -#define H_ATTRIBUTE_OVERRRIDEROADS -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_overrideroads; - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_OVERRRIDEROADS +#define H_ATTRIBUTE_OVERRRIDEROADS +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_overrideroads; + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/racename.c b/src/attributes/racename.c index 39ba6b4fa..09a7e9e22 100644 --- a/src/attributes/racename.c +++ b/src/attributes/racename.c @@ -1,57 +1,57 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "racename.h" - -#include -#include - -/* libc includes */ -#include -#include - -attrib_type at_racename = { - "racename", NULL, a_finalizestring, NULL, a_writestring, a_readstring -}; - -const char * -get_racename(attrib * alist) -{ - attrib * a = a_find(alist, &at_racename); - if (a) return (const char *)a->data.v; - return NULL; -} - -void -set_racename(attrib ** palist, const char * name) -{ - attrib * a = a_find(*palist, &at_racename); - if (!a && name) { - a = a_add(palist, a_new(&at_racename)); - a->data.v = strdup(name); - } else if (a && !name) { - a_remove(palist, a); - } else if (a) { - if (strcmp(a->data.v, name)!=0) { - free(a->data.v); - a->data.v = strdup(name); - } - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "racename.h" + +#include +#include + +/* libc includes */ +#include +#include + +attrib_type at_racename = { + "racename", NULL, a_finalizestring, NULL, a_writestring, a_readstring +}; + +const char * +get_racename(attrib * alist) +{ + attrib * a = a_find(alist, &at_racename); + if (a) return (const char *)a->data.v; + return NULL; +} + +void +set_racename(attrib ** palist, const char * name) +{ + attrib * a = a_find(*palist, &at_racename); + if (!a && name) { + a = a_add(palist, a_new(&at_racename)); + a->data.v = strdup(name); + } else if (a && !name) { + a_remove(palist, a); + } else if (a) { + if (strcmp(a->data.v, name)!=0) { + free(a->data.v); + a->data.v = strdup(name); + } + } +} diff --git a/src/attributes/racename.h b/src/attributes/racename.h index 04b271e35..224494706 100644 --- a/src/attributes/racename.h +++ b/src/attributes/racename.h @@ -1,37 +1,37 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_RACENAME_H -#define H_ATTRIBUTE_RACENAME_H -#ifdef __cplusplus -extern "C" { -#endif - -struct attrib_type; -struct attrib; - -extern void set_racename(struct attrib ** palist, const char * name); -extern const char * get_racename(struct attrib * alist); - -extern struct attrib_type at_racename; - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_RACENAME_H +#define H_ATTRIBUTE_RACENAME_H +#ifdef __cplusplus +extern "C" { +#endif + +struct attrib_type; +struct attrib; + +extern void set_racename(struct attrib ** palist, const char * name); +extern const char * get_racename(struct attrib * alist); + +extern struct attrib_type at_racename; + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/raceprefix.c b/src/attributes/raceprefix.c index 3c15a93a0..9eccf7a87 100644 --- a/src/attributes/raceprefix.c +++ b/src/attributes/raceprefix.c @@ -1,60 +1,60 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "raceprefix.h" -#include - -#include - -#include -#include - -attrib_type at_raceprefix = { - "raceprefix", NULL, a_finalizestring, NULL, a_writestring, a_readstring, ATF_UNIQUE -}; - -void -set_prefix(attrib ** ap, const char * str) -{ - attrib * a = a_find(*ap, &at_raceprefix); - if (a==NULL) { - a = a_add(ap, a_new(&at_raceprefix)); - } else { - free(a->data.v); - } - assert(a->type==&at_raceprefix); - a->data.v = strdup(str); -} - -const char * -get_prefix(const attrib * a) -{ - char * str; - a = a_findc(a, &at_raceprefix); - if (a==NULL) return NULL; - str = (char *)a->data.v; - /* conversion of old prefixes */ - if (strncmp(str, "prefix_", 7)==0) { - ((attrib*)a)->data.v = strdup(str+7); - free(str); - str = (char *)a->data.v; - } - return str; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "raceprefix.h" +#include + +#include + +#include +#include + +attrib_type at_raceprefix = { + "raceprefix", NULL, a_finalizestring, NULL, a_writestring, a_readstring, ATF_UNIQUE +}; + +void +set_prefix(attrib ** ap, const char * str) +{ + attrib * a = a_find(*ap, &at_raceprefix); + if (a==NULL) { + a = a_add(ap, a_new(&at_raceprefix)); + } else { + free(a->data.v); + } + assert(a->type==&at_raceprefix); + a->data.v = strdup(str); +} + +const char * +get_prefix(const attrib * a) +{ + char * str; + a = a_findc(a, &at_raceprefix); + if (a==NULL) return NULL; + str = (char *)a->data.v; + /* conversion of old prefixes */ + if (strncmp(str, "prefix_", 7)==0) { + ((attrib*)a)->data.v = strdup(str+7); + free(str); + str = (char *)a->data.v; + } + return str; +} diff --git a/src/attributes/raceprefix.h b/src/attributes/raceprefix.h index f3fb85e7d..ec5c44398 100644 --- a/src/attributes/raceprefix.h +++ b/src/attributes/raceprefix.h @@ -1,33 +1,33 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_RACEPREFIX -#define H_ATTRIBUTE_RACEPREFIX -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_raceprefix; -extern void set_prefix(struct attrib ** ap, const char * str); -extern const char * get_prefix(const struct attrib * a); - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_RACEPREFIX +#define H_ATTRIBUTE_RACEPREFIX +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_raceprefix; +extern void set_prefix(struct attrib ** ap, const char * str); +extern const char * get_prefix(const struct attrib * a); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/reduceproduction.c b/src/attributes/reduceproduction.c index 3f1ef5ac9..ef240b7a8 100644 --- a/src/attributes/reduceproduction.c +++ b/src/attributes/reduceproduction.c @@ -1,51 +1,51 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "reduceproduction.h" -#include -#include - -static int -age_reduceproduction(attrib *a) -{ - int reduce = 100 - (5 * --a->data.sa[1]); - if (reduce < 10) reduce = 10; - a->data.sa[0] = (short)reduce; - return (a->data.sa[1]>0)?AT_AGE_KEEP:AT_AGE_REMOVE; -} - -attrib_type at_reduceproduction = { - "reduceproduction", - NULL, - NULL, - age_reduceproduction, - a_writeshorts, - a_readshorts, - ATF_UNIQUE -}; - -attrib * -make_reduceproduction(int percent, int time) -{ - attrib * a = a_new(&at_reduceproduction); - a->data.sa[0] = (short)percent; - a->data.sa[1] = (short)time; - return a; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "reduceproduction.h" +#include +#include + +static int +age_reduceproduction(attrib *a) +{ + int reduce = 100 - (5 * --a->data.sa[1]); + if (reduce < 10) reduce = 10; + a->data.sa[0] = (short)reduce; + return (a->data.sa[1]>0)?AT_AGE_KEEP:AT_AGE_REMOVE; +} + +attrib_type at_reduceproduction = { + "reduceproduction", + NULL, + NULL, + age_reduceproduction, + a_writeshorts, + a_readshorts, + ATF_UNIQUE +}; + +attrib * +make_reduceproduction(int percent, int time) +{ + attrib * a = a_new(&at_reduceproduction); + a->data.sa[0] = (short)percent; + a->data.sa[1] = (short)time; + return a; +} diff --git a/src/attributes/reduceproduction.h b/src/attributes/reduceproduction.h index 4bee20399..913b3075d 100644 --- a/src/attributes/reduceproduction.h +++ b/src/attributes/reduceproduction.h @@ -1,32 +1,32 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_REDUCEPRODUCTION -#define H_ATTRIBUTE_REDUCEPRODUCTION -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib * make_reduceproduction(int percent, int time); -extern struct attrib_type at_reduceproduction; - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_REDUCEPRODUCTION +#define H_ATTRIBUTE_REDUCEPRODUCTION +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib * make_reduceproduction(int percent, int time); +extern struct attrib_type at_reduceproduction; + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/targetregion.c b/src/attributes/targetregion.c index d182e7fff..a9a31557c 100644 --- a/src/attributes/targetregion.c +++ b/src/attributes/targetregion.c @@ -1,61 +1,61 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "targetregion.h" - -#include -#include -#include -#include - -#include -#include -#include - -static void -write_targetregion(const attrib * a, const void * owner, struct storage * store) -{ - write_region_reference((region*)a->data.v, store); -} - -static int -read_targetregion(attrib * a, void * owner, struct storage * store) -{ - int result = read_reference(&a->data.v, store, read_region_reference, RESOLVE_REGION(store->version)); - if (result==0 && !a->data.v) return AT_READ_FAIL; - return AT_READ_OK; -} - -attrib_type at_targetregion = { - "targetregion", - NULL, - NULL, - NULL, - write_targetregion, - read_targetregion, - ATF_UNIQUE -}; - -attrib * -make_targetregion(struct region * r) -{ - attrib * a = a_new(&at_targetregion); - a->data.v = r; - return a; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "targetregion.h" + +#include +#include +#include +#include + +#include +#include +#include + +static void +write_targetregion(const attrib * a, const void * owner, struct storage * store) +{ + write_region_reference((region*)a->data.v, store); +} + +static int +read_targetregion(attrib * a, void * owner, struct storage * store) +{ + int result = read_reference(&a->data.v, store, read_region_reference, RESOLVE_REGION(store->version)); + if (result==0 && !a->data.v) return AT_READ_FAIL; + return AT_READ_OK; +} + +attrib_type at_targetregion = { + "targetregion", + NULL, + NULL, + NULL, + write_targetregion, + read_targetregion, + ATF_UNIQUE +}; + +attrib * +make_targetregion(struct region * r) +{ + attrib * a = a_new(&at_targetregion); + a->data.v = r; + return a; +} diff --git a/src/attributes/targetregion.h b/src/attributes/targetregion.h index d35aeba06..2eff0ec54 100644 --- a/src/attributes/targetregion.h +++ b/src/attributes/targetregion.h @@ -1,34 +1,34 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_TARGETREGION -#define H_ATTRIBUTE_TARGETREGION -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_targetregion; - -struct region; -extern struct attrib * make_targetregion(struct region *); - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_TARGETREGION +#define H_ATTRIBUTE_TARGETREGION +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_targetregion; + +struct region; +extern struct attrib * make_targetregion(struct region *); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/viewrange.c b/src/attributes/viewrange.c index e44f2ca00..059ae8d3c 100644 --- a/src/attributes/viewrange.c +++ b/src/attributes/viewrange.c @@ -1,77 +1,77 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "viewrange.h" - -/* util includes */ -#include -#include -#include - -/* libc includes */ -#include - -static void -a_writefunction(const struct attrib * a, const void * owner, struct storage * store) -{ - const char * str = get_functionname((pf_generic)a->data.f); - store->w_tok(store, str); -} - -static int -a_readfunction(struct attrib *a, void * owner, struct storage * store) -/* return 1 on success, 0 if attrib needs removal */ -{ - char buf[64]; - store->r_tok_buf(store, buf, sizeof(buf)); - a->data.f = get_function(buf); - return AT_READ_OK; -} - -attrib_type at_viewrange = { - "viewrange", - NULL, - NULL, - NULL, - a_writefunction, - a_readfunction, -}; - -attrib * -add_viewrange(attrib ** alist, const char *function) -{ - attrib * a = a_find(*alist, &at_viewrange); - if (a==NULL) a = a_add(alist, make_viewrange(function)); - return a; -} - -attrib * -make_viewrange(const char *function) -{ - attrib * a = a_new(&at_viewrange); - a->data.f = get_function(function); - assert(a->data.f); - return a; -} - -void -init_viewrange(void) -{ - at_register(&at_viewrange); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "viewrange.h" + +/* util includes */ +#include +#include +#include + +/* libc includes */ +#include + +static void +a_writefunction(const struct attrib * a, const void * owner, struct storage * store) +{ + const char * str = get_functionname((pf_generic)a->data.f); + store->w_tok(store, str); +} + +static int +a_readfunction(struct attrib *a, void * owner, struct storage * store) +/* return 1 on success, 0 if attrib needs removal */ +{ + char buf[64]; + store->r_tok_buf(store, buf, sizeof(buf)); + a->data.f = get_function(buf); + return AT_READ_OK; +} + +attrib_type at_viewrange = { + "viewrange", + NULL, + NULL, + NULL, + a_writefunction, + a_readfunction, +}; + +attrib * +add_viewrange(attrib ** alist, const char *function) +{ + attrib * a = a_find(*alist, &at_viewrange); + if (a==NULL) a = a_add(alist, make_viewrange(function)); + return a; +} + +attrib * +make_viewrange(const char *function) +{ + attrib * a = a_new(&at_viewrange); + a->data.f = get_function(function); + assert(a->data.f); + return a; +} + +void +init_viewrange(void) +{ + at_register(&at_viewrange); +} diff --git a/src/attributes/viewrange.h b/src/attributes/viewrange.h index 8f8ec1c55..c3cb3b6d0 100644 --- a/src/attributes/viewrange.h +++ b/src/attributes/viewrange.h @@ -1,35 +1,35 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_VIEWRANGE -#define H_ATTRIBUTE_VIEWRANGE -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_viewrange; - -extern struct attrib * make_viewrange(const char *function); -extern struct attrib * add_viewrange(struct attrib ** alist, const char *function); -extern void init_viewrange(void); - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_VIEWRANGE +#define H_ATTRIBUTE_VIEWRANGE +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_viewrange; + +extern struct attrib * make_viewrange(const char *function); +extern struct attrib * add_viewrange(struct attrib ** alist, const char *function); +extern void init_viewrange(void); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/bindings/bind_attrib.c b/src/bindings/bind_attrib.c index f92bcb99e..503d4ab97 100644 --- a/src/bindings/bind_attrib.c +++ b/src/bindings/bind_attrib.c @@ -1,372 +1,372 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2010 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include "bind_attrib.h" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -static void -init_ext(attrib * a) { - lua_State * L = (lua_State *)global.vm_state; - - lua_pushstring(L, "callbacks"); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_istable(L, -1)) { - lua_pushstring(L, "attrib_init"); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, -1)) { - lua_rawgeti(L, LUA_REGISTRYINDEX, a->data.i); - if (lua_pcall(L, 1, 0, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("attrib_init '%d': %s.\n", a->data.i, error)); - } - } - } -} - -static void -free_ext(attrib * a) { - lua_State * L = (lua_State *)global.vm_state; - if (a->data.i>0) { - luaL_unref(L, LUA_REGISTRYINDEX, a->data.i); - } -} - -static int -age_ext(attrib * a) { - return AT_AGE_KEEP; -} - -static void -write_ext_i(lua_State * L, const char * name, bson_buffer * bb) -{ - int type = lua_type(L, -1); - switch (type) { - case LUA_TNUMBER: - { - double value = tolua_tonumber(L, -1, 0); - bson_append_double(bb, name, value); - } - break; - case LUA_TSTRING: - { - const char * value = tolua_tostring(L, -1, 0); - bson_append_string(bb, name, value); - } - break; - case LUA_TTABLE: - { - int n = luaL_getn(L, -1); - if (n) { - bson_buffer * arr = bson_append_start_array(bb, name); - int i; - for (i=0;i!=n;++i) { - char num[12]; - bson_numstr(num, i); - lua_rawgeti(L, -1, i+1); - write_ext_i(L, num, arr); - lua_pop(L, 1); - } - bson_append_finish_object(arr); - } else { - bson_buffer * sub = bson_append_start_object(bb, name); - lua_pushnil(L); /* first key */ - while (lua_next(L, -2) != 0) { - const char * key; - /* uses 'key' (at index -2) and 'value' (at index -1) */ - lua_pushvalue(L, -2); - key = lua_tolstring(L, -1, 0); - lua_pushvalue(L, -2); - if (key) { - write_ext_i(L, key, sub); - } - /* removes 'value'; keeps 'key' for next iteration */ - lua_pop(L, 3); - } - bson_append_finish_object(sub); - } - } - break; - case LUA_TUSERDATA: - { - tolua_Error tolua_err; - if (tolua_isusertype(L, -1, "unit", 0, &tolua_err)) { - unit * u = (unit *)tolua_tousertype(L, -1, 0); - bson_oid_t oid; - oid.ints[0] = TYP_UNIT; - oid.ints[1] = u->no; - bson_append_oid(bb, name, &oid); - } else if (tolua_isusertype(L, -1, "region", 0, &tolua_err)) { - region * r = (region *)tolua_tousertype(L, -1, 0); - bson_oid_t oid; - oid.ints[0] = TYP_REGION; - oid.ints[1] = r->uid; - bson_append_oid(bb, name, &oid); - } else if (tolua_isusertype(L, -1, "ship", 0, &tolua_err)) { - ship * sh = (ship *)tolua_tousertype(L, -1, 0); - bson_oid_t oid; - oid.ints[0] = TYP_SHIP; - oid.ints[1] = sh->no; - bson_append_oid(bb, name, &oid); - } else if (tolua_isusertype(L, -1, "building", 0, &tolua_err)) { - building * b = (building *)tolua_tousertype(L, -1, 0); - bson_oid_t oid; - oid.ints[0] = TYP_BUILDING; - oid.ints[1] = b->no; - bson_append_oid(bb, name, &oid); - } else { - log_error(("unsuported type.\n")); - bson_append_null(bb, name); - } - } - break; - default: - bson_append_null(bb, name); - break; - } -} - -static void -write_ext(const attrib * a, const void * owner, struct storage * store) { - lua_State * L = (lua_State *)global.vm_state; - if (a->data.i>0) { - int handle = a->data.i; - bson_buffer bb; - bson b; - - bson_buffer_init( & bb ); - lua_rawgeti(L, LUA_REGISTRYINDEX, handle); - write_ext_i(L, "_data", &bb); - bson_from_buffer(&b, &bb); - store->w_int(store, bson_size(&b)); - store->w_bin(store, b.data, bson_size(&b)); - bson_destroy(&b); - } -} - -static int -read_ext_i(lua_State * L, bson_iterator * it, bson_type type) -{ - switch (type) { - case bson_double: - { - lua_pushnumber(L, bson_iterator_double(it)); - } - break; - case bson_string: - { - lua_pushstring(L, bson_iterator_string(it)); - } - break; - case bson_array: - { - bson_iterator sub; - int err; - bson_iterator_subiterator(it, &sub); - lua_newtable(L); - if (bson_iterator_more(&sub)) { - bson_type ctype; - for (ctype = bson_iterator_next(&sub); bson_iterator_more(&sub); ctype = bson_iterator_next(&sub)) { - int i = atoi(bson_iterator_key(&sub)); - err = read_ext_i(L, &sub, ctype); - if (err) { - lua_pop(L, 1); - return err; - } - lua_rawseti(L, -2, i+1); - } - } - } - break; - case bson_object: - { - bson_iterator sub; - int err; - bson_iterator_subiterator(it, &sub); - lua_newtable(L); - if (bson_iterator_more(&sub)) { - bson_type ctype; - for (ctype = bson_iterator_next(&sub); bson_iterator_more(&sub); ctype = bson_iterator_next(&sub)) { - lua_pushstring(L, bson_iterator_key(&sub)); - err = read_ext_i(L, &sub, ctype); - if (err) { - lua_pop(L, 1); - return err; - } - lua_rawset(L, -3); - } - } - } - break; - case bson_oid: - { - bson_oid_t * oid = bson_iterator_oid(it); - if (oid->ints[0]==TYP_UNIT) { - unit * u = findunit(oid->ints[1]); - if (u) tolua_pushusertype(L, u, "unit"); - else lua_pushnil(L); - } else if (oid->ints[0]==TYP_REGION) { - region * r = findregionbyid(oid->ints[1]); - if (r) tolua_pushusertype(L, r, "region"); - else lua_pushnil(L); - } else if (oid->ints[0]==TYP_SHIP) { - ship * sh = findship(oid->ints[1]); - if (sh) tolua_pushusertype(L, sh, "ship"); - else lua_pushnil(L); - } else if (oid->ints[0]==TYP_BUILDING) { - building * b = findbuilding(oid->ints[1]); - if (b) tolua_pushusertype(L, b, "building"); - else lua_pushnil(L); - } - else { - log_error(("unknown oid %d %d %d\n", oid->ints[0], oid->ints[3], oid->ints[2])); - lua_pushnil(L); - } - } - break; - case bson_null: - lua_pushnil(L); - break; - case bson_eoo: - return EFAULT; - default: - return EINVAL; - } - return 0; -} - -static int -resolve_bson(variant data, void * address) -{ - lua_State * L = (lua_State *)global.vm_state; - bson b; - int err; - bson_iterator it; - attrib * a = (attrib*)address; - char * buffer = data.v; - - bson_init(&b, buffer, 1); - bson_iterator_init(&it, b.data); - err = read_ext_i(L, &it, bson_iterator_next(&it)); - a->data.i = luaL_ref(L, LUA_REGISTRYINDEX); - bson_destroy(&b); - return err?AT_READ_FAIL:AT_READ_OK; -} - -static int -read_ext(attrib * a, void * owner, struct storage * store) { - variant data; - int len = store->r_int(store); - data.v = bson_malloc(len); - store->r_bin(store, data.v, (size_t)len); - a->data.v = 0; - ur_add(data, a, resolve_bson); - return AT_READ_OK; -}; - -attrib_type at_lua_ext = { - "lua", init_ext, free_ext, age_ext, write_ext, read_ext -}; - -static int -tolua_attrib_create(lua_State* L) -{ - attrib ** ap = NULL; - tolua_Error tolua_err; - - if (tolua_isusertype(L, 1, TOLUA_CAST "unit", 0, &tolua_err)) { - unit * u = (unit *)tolua_tousertype(L, 1, 0); - ap = &u->attribs; - } - if (ap) { - attrib * a = a_new(&at_lua_ext); - int handle; - - lua_pushvalue(L, 2); - handle = luaL_ref(L, LUA_REGISTRYINDEX); - a->data.i = handle; - - a_add(ap, a); - tolua_pushusertype(L, (void*)a, TOLUA_CAST "attrib"); - return 1; - } - return 0; -} - -int -tolua_attrib_data(lua_State * L) -{ - attrib * a = (attrib *)tolua_tousertype(L, 1, 0); - if (a && a->data.i) { - lua_rawgeti(L, LUA_REGISTRYINDEX, a->data.i); - return 1; - } - return 0; -} - -attrib * -tolua_get_lua_ext(struct attrib * alist) -{ - while (alist && alist->type!=&at_lua_ext) alist = alist->next; - return alist; -} - -int -tolua_attriblist_next(lua_State *L) -{ - attrib** attrib_ptr = (attrib **)lua_touserdata(L, lua_upvalueindex(1)); - attrib * a = *attrib_ptr; - if (a != NULL) { - tolua_pushusertype(L, (void*)a, TOLUA_CAST "attrib"); - *attrib_ptr = tolua_get_lua_ext(a->next); - return 1; - } - else return 0; /* no more values to return */ -} - - -void -tolua_attrib_open(lua_State* L) -{ - at_register(&at_lua_ext); - - tolua_usertype(L, TOLUA_CAST "attrib"); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_cclass(L, TOLUA_CAST "attrib", TOLUA_CAST "attrib", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "attrib"); - { - tolua_function(L, TOLUA_CAST "create", &tolua_attrib_create); - tolua_variable(L, TOLUA_CAST "data", &tolua_attrib_data, NULL); - } - tolua_endmodule(L); - } - tolua_endmodule(L); -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2010 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bind_attrib.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +static void +init_ext(attrib * a) { + lua_State * L = (lua_State *)global.vm_state; + + lua_pushstring(L, "callbacks"); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_istable(L, -1)) { + lua_pushstring(L, "attrib_init"); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, -1)) { + lua_rawgeti(L, LUA_REGISTRYINDEX, a->data.i); + if (lua_pcall(L, 1, 0, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("attrib_init '%d': %s.\n", a->data.i, error)); + } + } + } +} + +static void +free_ext(attrib * a) { + lua_State * L = (lua_State *)global.vm_state; + if (a->data.i>0) { + luaL_unref(L, LUA_REGISTRYINDEX, a->data.i); + } +} + +static int +age_ext(attrib * a) { + return AT_AGE_KEEP; +} + +static void +write_ext_i(lua_State * L, const char * name, bson_buffer * bb) +{ + int type = lua_type(L, -1); + switch (type) { + case LUA_TNUMBER: + { + double value = tolua_tonumber(L, -1, 0); + bson_append_double(bb, name, value); + } + break; + case LUA_TSTRING: + { + const char * value = tolua_tostring(L, -1, 0); + bson_append_string(bb, name, value); + } + break; + case LUA_TTABLE: + { + int n = luaL_getn(L, -1); + if (n) { + bson_buffer * arr = bson_append_start_array(bb, name); + int i; + for (i=0;i!=n;++i) { + char num[12]; + bson_numstr(num, i); + lua_rawgeti(L, -1, i+1); + write_ext_i(L, num, arr); + lua_pop(L, 1); + } + bson_append_finish_object(arr); + } else { + bson_buffer * sub = bson_append_start_object(bb, name); + lua_pushnil(L); /* first key */ + while (lua_next(L, -2) != 0) { + const char * key; + /* uses 'key' (at index -2) and 'value' (at index -1) */ + lua_pushvalue(L, -2); + key = lua_tolstring(L, -1, 0); + lua_pushvalue(L, -2); + if (key) { + write_ext_i(L, key, sub); + } + /* removes 'value'; keeps 'key' for next iteration */ + lua_pop(L, 3); + } + bson_append_finish_object(sub); + } + } + break; + case LUA_TUSERDATA: + { + tolua_Error tolua_err; + if (tolua_isusertype(L, -1, "unit", 0, &tolua_err)) { + unit * u = (unit *)tolua_tousertype(L, -1, 0); + bson_oid_t oid; + oid.ints[0] = TYP_UNIT; + oid.ints[1] = u->no; + bson_append_oid(bb, name, &oid); + } else if (tolua_isusertype(L, -1, "region", 0, &tolua_err)) { + region * r = (region *)tolua_tousertype(L, -1, 0); + bson_oid_t oid; + oid.ints[0] = TYP_REGION; + oid.ints[1] = r->uid; + bson_append_oid(bb, name, &oid); + } else if (tolua_isusertype(L, -1, "ship", 0, &tolua_err)) { + ship * sh = (ship *)tolua_tousertype(L, -1, 0); + bson_oid_t oid; + oid.ints[0] = TYP_SHIP; + oid.ints[1] = sh->no; + bson_append_oid(bb, name, &oid); + } else if (tolua_isusertype(L, -1, "building", 0, &tolua_err)) { + building * b = (building *)tolua_tousertype(L, -1, 0); + bson_oid_t oid; + oid.ints[0] = TYP_BUILDING; + oid.ints[1] = b->no; + bson_append_oid(bb, name, &oid); + } else { + log_error(("unsuported type.\n")); + bson_append_null(bb, name); + } + } + break; + default: + bson_append_null(bb, name); + break; + } +} + +static void +write_ext(const attrib * a, const void * owner, struct storage * store) { + lua_State * L = (lua_State *)global.vm_state; + if (a->data.i>0) { + int handle = a->data.i; + bson_buffer bb; + bson b; + + bson_buffer_init( & bb ); + lua_rawgeti(L, LUA_REGISTRYINDEX, handle); + write_ext_i(L, "_data", &bb); + bson_from_buffer(&b, &bb); + store->w_int(store, bson_size(&b)); + store->w_bin(store, b.data, bson_size(&b)); + bson_destroy(&b); + } +} + +static int +read_ext_i(lua_State * L, bson_iterator * it, bson_type type) +{ + switch (type) { + case bson_double: + { + lua_pushnumber(L, bson_iterator_double(it)); + } + break; + case bson_string: + { + lua_pushstring(L, bson_iterator_string(it)); + } + break; + case bson_array: + { + bson_iterator sub; + int err; + bson_iterator_subiterator(it, &sub); + lua_newtable(L); + if (bson_iterator_more(&sub)) { + bson_type ctype; + for (ctype = bson_iterator_next(&sub); bson_iterator_more(&sub); ctype = bson_iterator_next(&sub)) { + int i = atoi(bson_iterator_key(&sub)); + err = read_ext_i(L, &sub, ctype); + if (err) { + lua_pop(L, 1); + return err; + } + lua_rawseti(L, -2, i+1); + } + } + } + break; + case bson_object: + { + bson_iterator sub; + int err; + bson_iterator_subiterator(it, &sub); + lua_newtable(L); + if (bson_iterator_more(&sub)) { + bson_type ctype; + for (ctype = bson_iterator_next(&sub); bson_iterator_more(&sub); ctype = bson_iterator_next(&sub)) { + lua_pushstring(L, bson_iterator_key(&sub)); + err = read_ext_i(L, &sub, ctype); + if (err) { + lua_pop(L, 1); + return err; + } + lua_rawset(L, -3); + } + } + } + break; + case bson_oid: + { + bson_oid_t * oid = bson_iterator_oid(it); + if (oid->ints[0]==TYP_UNIT) { + unit * u = findunit(oid->ints[1]); + if (u) tolua_pushusertype(L, u, "unit"); + else lua_pushnil(L); + } else if (oid->ints[0]==TYP_REGION) { + region * r = findregionbyid(oid->ints[1]); + if (r) tolua_pushusertype(L, r, "region"); + else lua_pushnil(L); + } else if (oid->ints[0]==TYP_SHIP) { + ship * sh = findship(oid->ints[1]); + if (sh) tolua_pushusertype(L, sh, "ship"); + else lua_pushnil(L); + } else if (oid->ints[0]==TYP_BUILDING) { + building * b = findbuilding(oid->ints[1]); + if (b) tolua_pushusertype(L, b, "building"); + else lua_pushnil(L); + } + else { + log_error(("unknown oid %d %d %d\n", oid->ints[0], oid->ints[3], oid->ints[2])); + lua_pushnil(L); + } + } + break; + case bson_null: + lua_pushnil(L); + break; + case bson_eoo: + return EFAULT; + default: + return EINVAL; + } + return 0; +} + +static int +resolve_bson(variant data, void * address) +{ + lua_State * L = (lua_State *)global.vm_state; + bson b; + int err; + bson_iterator it; + attrib * a = (attrib*)address; + char * buffer = data.v; + + bson_init(&b, buffer, 1); + bson_iterator_init(&it, b.data); + err = read_ext_i(L, &it, bson_iterator_next(&it)); + a->data.i = luaL_ref(L, LUA_REGISTRYINDEX); + bson_destroy(&b); + return err?AT_READ_FAIL:AT_READ_OK; +} + +static int +read_ext(attrib * a, void * owner, struct storage * store) { + variant data; + int len = store->r_int(store); + data.v = bson_malloc(len); + store->r_bin(store, data.v, (size_t)len); + a->data.v = 0; + ur_add(data, a, resolve_bson); + return AT_READ_OK; +}; + +attrib_type at_lua_ext = { + "lua", init_ext, free_ext, age_ext, write_ext, read_ext +}; + +static int +tolua_attrib_create(lua_State* L) +{ + attrib ** ap = NULL; + tolua_Error tolua_err; + + if (tolua_isusertype(L, 1, TOLUA_CAST "unit", 0, &tolua_err)) { + unit * u = (unit *)tolua_tousertype(L, 1, 0); + ap = &u->attribs; + } + if (ap) { + attrib * a = a_new(&at_lua_ext); + int handle; + + lua_pushvalue(L, 2); + handle = luaL_ref(L, LUA_REGISTRYINDEX); + a->data.i = handle; + + a_add(ap, a); + tolua_pushusertype(L, (void*)a, TOLUA_CAST "attrib"); + return 1; + } + return 0; +} + +int +tolua_attrib_data(lua_State * L) +{ + attrib * a = (attrib *)tolua_tousertype(L, 1, 0); + if (a && a->data.i) { + lua_rawgeti(L, LUA_REGISTRYINDEX, a->data.i); + return 1; + } + return 0; +} + +attrib * +tolua_get_lua_ext(struct attrib * alist) +{ + while (alist && alist->type!=&at_lua_ext) alist = alist->next; + return alist; +} + +int +tolua_attriblist_next(lua_State *L) +{ + attrib** attrib_ptr = (attrib **)lua_touserdata(L, lua_upvalueindex(1)); + attrib * a = *attrib_ptr; + if (a != NULL) { + tolua_pushusertype(L, (void*)a, TOLUA_CAST "attrib"); + *attrib_ptr = tolua_get_lua_ext(a->next); + return 1; + } + else return 0; /* no more values to return */ +} + + +void +tolua_attrib_open(lua_State* L) +{ + at_register(&at_lua_ext); + + tolua_usertype(L, TOLUA_CAST "attrib"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, TOLUA_CAST "attrib", TOLUA_CAST "attrib", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "attrib"); + { + tolua_function(L, TOLUA_CAST "create", &tolua_attrib_create); + tolua_variable(L, TOLUA_CAST "data", &tolua_attrib_data, NULL); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_attrib.h b/src/bindings/bind_attrib.h index d4ce7bf95..758ab62d6 100644 --- a/src/bindings/bind_attrib.h +++ b/src/bindings/bind_attrib.h @@ -1,24 +1,24 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2010 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct attrib; - void tolua_attrib_open(struct lua_State *L); - struct attrib * tolua_get_lua_ext(struct attrib * alist); - int tolua_attriblist_next(struct lua_State *L); - -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2010 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct attrib; + void tolua_attrib_open(struct lua_State *L); + struct attrib * tolua_get_lua_ext(struct attrib * alist); + int tolua_attriblist_next(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_building.c b/src/bindings/bind_building.c index e5c9efde3..8fadae4c1 100644 --- a/src/bindings/bind_building.c +++ b/src/bindings/bind_building.c @@ -1,255 +1,258 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include "bind_building.h" -#include "bind_unit.h" - -#include -#include -#include - -#include -#include - -int tolua_buildinglist_next(lua_State *L) -{ - building** building_ptr = (building **)lua_touserdata(L, lua_upvalueindex(1)); - building * u = *building_ptr; - if (u != NULL) { - tolua_pushusertype(L, (void*)u, TOLUA_CAST "building"); - *building_ptr = u->next; - return 1; - } - else return 0; /* no more values to return */ -} - - -static int -tolua_building_addaction(lua_State* L) -{ - building* self = (building*)tolua_tousertype(L, 1, 0); - const char * fname = tolua_tostring(L, 2, 0); - const char * param = tolua_tostring(L, 3, 0); - - building_addaction(self, fname, param); - - return 0; -} - -static int -tolua_building_get_objects(lua_State* L) -{ - building * self = (building *)tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); - return 1; -} - -static int tolua_building_get_region(lua_State* L) -{ - building* self = (building*) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, building_getregion(self), TOLUA_CAST "region"); - return 1; -} - -static int tolua_building_set_region(lua_State* L) -{ - building* self = (building*)tolua_tousertype(L, 1, 0); - building_setregion(self, (region*)tolua_tousertype(L, 2, 0)); - return 0; -} - - -static int tolua_building_get_info(lua_State* L) -{ - building* self = (building*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->display); - return 1; -} - -static int tolua_building_set_info(lua_State* L) -{ - building* self = (building*)tolua_tousertype(L, 1, 0); - const char * info = tolua_tostring(L, 2, 0); - free(self->display); - if (info) self->display = strdup(info); - else self->display = NULL; - return 0; -} - -static int tolua_building_get_name(lua_State* L) -{ - building* self = (building*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, building_getname(self)); - return 1; -} - -static int tolua_building_set_name(lua_State* L) -{ - building* self = (building*)tolua_tousertype(L, 1, 0); - building_setname(self, tolua_tostring(L, 2, 0)); - return 0; -} - -static int tolua_building_get_size(lua_State* L) -{ - building* self = (building*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, self->size); - return 1; -} - -static int tolua_building_set_size(lua_State* L) -{ - building* self = (building*)tolua_tousertype(L, 1, 0); - self->size = (int)tolua_tonumber(L, 2, 0); - return 0; -} - -static int -tolua_building_get_units(lua_State* L) -{ - building * self = (building *)tolua_tousertype(L, 1, 0); - unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); - unit * u = self->region->units; - - while (u && u->building!=self) u = u->next; - luaL_getmetatable(L, "unit"); - lua_setmetatable(L, -2); - - *unit_ptr = u; - - lua_pushcclosure(L, tolua_unitlist_nextb, 1); - return 1; -} - -static int -tolua_building_get_id(lua_State* L) -{ - building * self = (building *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->no); - return 1; -} - -static int -tolua_building_get_type(lua_State* L) -{ - building * self = (building *)tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->type->_name); - return 1; -} - -static int -tolua_building_get_typename(lua_State* L) -{ - building * b = (building *)tolua_tousertype(L, 1, 0); - if (b) { - int size = (int)tolua_tonumber(L, 2, b->size); - tolua_pushstring(L, buildingtype(b->type, b, size)); - return 1; - } - return 0; -} - -static int -tolua_building_get_owner(lua_State* L) -{ - building* b = (building*) tolua_tousertype(L, 1, 0); - unit * u = b?building_owner(b):NULL; - tolua_pushusertype(L, u, TOLUA_CAST "unit"); - return 1; -} - -static int -tolua_building_set_owner(lua_State* L) -{ - building* b = (building*) tolua_tousertype(L, 1, 0); - unit * u = (unit *)tolua_tousertype(L, 2, 0); - unit * o = b?building_owner(b):NULL; - if (o && o!=u) { - freset(o, UFL_OWNER); - } - if (u) { - fset(u, UFL_OWNER); - } - return 0; -} - -static int -tolua_building_create(lua_State* L) -{ - region * r = (region *)tolua_tousertype(L, 1, 0); - const char * bname = tolua_tostring(L, 2, 0); - if (bname) { - const building_type * btype = bt_find(bname); - if (btype) { - building * b = new_building(btype, r, default_locale); - tolua_pushusertype(L, (void*)b, TOLUA_CAST "building"); - return 1; - } - } - return 0; -} - -static int -tolua_building_tostring(lua_State *L) -{ - building * self = (building *)tolua_tousertype(L, 1, 0); - lua_pushstring(L, buildingname(self)); - return 1; -} - -static int -tolua_building_destroy(lua_State *L) -{ - building * self = (building *)tolua_tousertype(L, 1, 0); - remove_building(&self->region->buildings, self); - return 0; -} - -void -tolua_building_open(lua_State* L) -{ - /* register user types */ - tolua_usertype(L, TOLUA_CAST "building"); - tolua_usertype(L, TOLUA_CAST "building_list"); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_cclass(L, TOLUA_CAST "building", TOLUA_CAST "building", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "building"); - { - tolua_function(L, TOLUA_CAST "create", tolua_building_create); - tolua_function(L, TOLUA_CAST "destroy", tolua_building_destroy); - tolua_function(L, TOLUA_CAST "__tostring", tolua_building_tostring); - - tolua_variable(L, TOLUA_CAST "id", tolua_building_get_id, NULL); - tolua_variable(L, TOLUA_CAST "owner", tolua_building_get_owner, tolua_building_set_owner); - tolua_variable(L, TOLUA_CAST "type", tolua_building_get_type, NULL); - tolua_variable(L, TOLUA_CAST "name", tolua_building_get_name, tolua_building_set_name); - tolua_variable(L, TOLUA_CAST "info", tolua_building_get_info, tolua_building_set_info); - tolua_variable(L, TOLUA_CAST "units", tolua_building_get_units, NULL); - tolua_variable(L, TOLUA_CAST "region", tolua_building_get_region, tolua_building_set_region); - tolua_variable(L, TOLUA_CAST "size", tolua_building_get_size, tolua_building_set_size); - tolua_function(L, TOLUA_CAST "add_action", tolua_building_addaction); - tolua_function(L, TOLUA_CAST "get_typename", tolua_building_get_typename); -#ifdef TODO - .property("type", &building_gettype) - .def_readwrite("size", &building::size) -#endif - tolua_variable(L, TOLUA_CAST "objects", tolua_building_get_objects, 0); - - } - tolua_endmodule(L); - } - tolua_endmodule(L); -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bind_building.h" +#include "bind_unit.h" + +#include +#include +#include +#include + +#include + +#include +#include + +int tolua_buildinglist_next(lua_State *L) +{ + building** building_ptr = (building **)lua_touserdata(L, lua_upvalueindex(1)); + building * u = *building_ptr; + if (u != NULL) { + tolua_pushusertype(L, (void*)u, TOLUA_CAST "building"); + *building_ptr = u->next; + return 1; + } + else return 0; /* no more values to return */ +} + + +static int +tolua_building_addaction(lua_State* L) +{ + building* self = (building*)tolua_tousertype(L, 1, 0); + const char * fname = tolua_tostring(L, 2, 0); + const char * param = tolua_tostring(L, 3, 0); + + building_addaction(self, fname, param); + + return 0; +} + +static int +tolua_building_get_objects(lua_State* L) +{ + building * self = (building *)tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); + return 1; +} + +static int tolua_building_get_region(lua_State* L) +{ + building* self = (building*) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, building_getregion(self), TOLUA_CAST "region"); + return 1; +} + +static int tolua_building_set_region(lua_State* L) +{ + building* self = (building*)tolua_tousertype(L, 1, 0); + building_setregion(self, (region*)tolua_tousertype(L, 2, 0)); + return 0; +} + + +static int tolua_building_get_info(lua_State* L) +{ + building* self = (building*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->display); + return 1; +} + +static int tolua_building_set_info(lua_State* L) +{ + building* self = (building*)tolua_tousertype(L, 1, 0); + const char * info = tolua_tostring(L, 2, 0); + free(self->display); + if (info) self->display = strdup(info); + else self->display = NULL; + return 0; +} + +static int tolua_building_get_name(lua_State* L) +{ + building* self = (building*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, building_getname(self)); + return 1; +} + +static int tolua_building_set_name(lua_State* L) +{ + building* self = (building*)tolua_tousertype(L, 1, 0); + building_setname(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int tolua_building_get_size(lua_State* L) +{ + building* self = (building*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, self->size); + return 1; +} + +static int tolua_building_set_size(lua_State* L) +{ + building* self = (building*)tolua_tousertype(L, 1, 0); + self->size = (int)tolua_tonumber(L, 2, 0); + return 0; +} + +static int +tolua_building_get_units(lua_State* L) +{ + building * self = (building *)tolua_tousertype(L, 1, 0); + unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); + unit * u = self->region->units; + + while (u && u->building!=self) u = u->next; + luaL_getmetatable(L, "unit"); + lua_setmetatable(L, -2); + + *unit_ptr = u; + + lua_pushcclosure(L, tolua_unitlist_nextb, 1); + return 1; +} + +static int +tolua_building_get_id(lua_State* L) +{ + building * self = (building *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->no); + return 1; +} + +static int +tolua_building_get_type(lua_State* L) +{ + building * self = (building *)tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->type->_name); + return 1; +} + +static int +tolua_building_get_typename(lua_State* L) +{ + building * b = (building *)tolua_tousertype(L, 1, 0); + if (b) { + int size = (int)tolua_tonumber(L, 2, b->size); + tolua_pushstring(L, buildingtype(b->type, b, size)); + return 1; + } + return 0; +} + +static int +tolua_building_get_owner(lua_State* L) +{ + building* b = (building*) tolua_tousertype(L, 1, 0); + unit * u = b?building_owner(b):NULL; + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + return 1; +} + +static int +tolua_building_set_owner(lua_State* L) +{ + building* b = (building*) tolua_tousertype(L, 1, 0); + unit * u = (unit *)tolua_tousertype(L, 2, 0); + unit * o = b?building_owner(b):NULL; + if (o && o!=u) { + freset(o, UFL_OWNER); + } + if (u) { + fset(u, UFL_OWNER); + } + return 0; +} + +static int +tolua_building_create(lua_State* L) +{ + region * r = (region *)tolua_tousertype(L, 1, 0); + const char * bname = tolua_tostring(L, 2, 0); + if (bname) { + const building_type * btype = bt_find(bname); + if (btype) { + building * b = new_building(btype, r, default_locale); + tolua_pushusertype(L, (void*)b, TOLUA_CAST "building"); + return 1; + } + } + return 0; +} + +static int +tolua_building_tostring(lua_State *L) +{ + building * self = (building *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, buildingname(self)); + return 1; +} + +static int +tolua_building_destroy(lua_State *L) +{ + building * self = (building *)tolua_tousertype(L, 1, 0); + remove_building(&self->region->buildings, self); + return 0; +} + +void +tolua_building_open(lua_State* L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "building"); + tolua_usertype(L, TOLUA_CAST "building_list"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, TOLUA_CAST "building", TOLUA_CAST "building", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "building"); + { + tolua_function(L, TOLUA_CAST "create", tolua_building_create); + tolua_function(L, TOLUA_CAST "destroy", tolua_building_destroy); + tolua_function(L, TOLUA_CAST "__tostring", tolua_building_tostring); + + tolua_variable(L, TOLUA_CAST "id", tolua_building_get_id, NULL); + tolua_variable(L, TOLUA_CAST "owner", tolua_building_get_owner, tolua_building_set_owner); + tolua_variable(L, TOLUA_CAST "type", tolua_building_get_type, NULL); + tolua_variable(L, TOLUA_CAST "name", tolua_building_get_name, tolua_building_set_name); + tolua_variable(L, TOLUA_CAST "info", tolua_building_get_info, tolua_building_set_info); + tolua_variable(L, TOLUA_CAST "units", tolua_building_get_units, NULL); + tolua_variable(L, TOLUA_CAST "region", tolua_building_get_region, tolua_building_set_region); + tolua_variable(L, TOLUA_CAST "size", tolua_building_get_size, tolua_building_set_size); + tolua_function(L, TOLUA_CAST "add_action", tolua_building_addaction); + tolua_function(L, TOLUA_CAST "get_typename", tolua_building_get_typename); +#ifdef TODO + .property("type", &building_gettype) + .def_readwrite("size", &building::size) +#endif + tolua_variable(L, TOLUA_CAST "objects", tolua_building_get_objects, 0); + + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_building.h b/src/bindings/bind_building.h index a6168b66c..3f87c4952 100644 --- a/src/bindings/bind_building.h +++ b/src/bindings/bind_building.h @@ -1,23 +1,23 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - int tolua_buildinglist_next(struct lua_State *L); - void tolua_building_open(struct lua_State *L); - -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + int tolua_buildinglist_next(struct lua_State *L); + void tolua_building_open(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_faction.c b/src/bindings/bind_faction.c index 44caf3618..0931298b1 100644 --- a/src/bindings/bind_faction.c +++ b/src/bindings/bind_faction.c @@ -1,561 +1,561 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include "bind_faction.h" -#include "bind_unit.h" -#include "bindings.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - - -int tolua_factionlist_next(lua_State *L) -{ - faction** faction_ptr = (faction **)lua_touserdata(L, lua_upvalueindex(1)); - faction * f = *faction_ptr; - if (f != NULL) { - tolua_pushusertype(L, (void*)f, TOLUA_CAST "faction"); - *faction_ptr = f->next; - return 1; - } - else return 0; /* no more values to return */ -} - -int tolua_factionlist_iter(lua_State *L) -{ - faction_list** faction_ptr = (faction_list **)lua_touserdata(L, lua_upvalueindex(1)); - faction_list* flist = *faction_ptr; - if (flist != NULL) { - tolua_pushusertype(L, (void*)flist->data, TOLUA_CAST "faction"); - *faction_ptr = flist->next; - return 1; - } - else return 0; /* no more values to return */ -} - -static int tolua_faction_get_units(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); - - luaL_getmetatable(L, TOLUA_CAST "unit"); - lua_setmetatable(L, -2); - - *unit_ptr = self->units; - - lua_pushcclosure(L, tolua_unitlist_nextf, 1); - return 1; -} - -int tolua_faction_add_item(lua_State *L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - const char * iname = tolua_tostring(L, 2, 0); - int number = (int)tolua_tonumber(L, 3, 0); - int result = -1; - - if (iname!=NULL) { - const item_type * itype = it_find(iname); - if (itype!=NULL) { - item * i = i_change(&self->items, itype, number); - result = i?i->number:0; - } // if (itype!=NULL) - } - lua_pushnumber(L, result); - return 1; -} - -static int -tolua_faction_get_maxheroes(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)maxheroes(self)); - return 1; -} - -static int -tolua_faction_get_heroes(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)countheroes(self)); - return 1; -} - -static int -tolua_faction_get_score(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->score); - return 1; -} - -static int -tolua_faction_get_id(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->no); - return 1; -} - -static int -tolua_faction_set_id(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - int id = (int)tolua_tonumber(L, 2, 0); - if (findfaction(id)==NULL) { - renumber_faction(self, id); - lua_pushboolean(L, 1); - } else { - lua_pushboolean(L, 0); - } - return 1; -} - -static int -tolua_faction_get_age(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->age); - return 1; -} - -static int -tolua_faction_set_age(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - int age = (int)tolua_tonumber(L, 2, 0); - self->age = age; - return 0; -} - -static int -tolua_faction_get_flags(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->flags); - return 1; -} - -static int -tolua_faction_get_options(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->options); - return 1; -} - -static int -tolua_faction_set_options(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - int options = (int)tolua_tonumber(L, 2, self->options); - self->options = options; - return 1; -} - -static int -tolua_faction_get_lastturn(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->lastorders); - return 1; -} - -static int -tolua_faction_set_lastturn(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - if (self) { - self->lastorders = (int)tolua_tonumber(L, 2, self->lastorders); - } - return 0; -} - -static int -tolua_faction_renumber(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - int no = (int)tolua_tonumber(L, 2, 0); - - renumber_faction(self, no); - return 0; -} - -static int -tolua_faction_get_objects(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); - return 1; -} - -static int -tolua_faction_get_policy(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - faction * other = (faction *)tolua_tousertype(L, 2, 0); - const char * policy = tolua_tostring(L, 3, 0); - - int result = 0, mode; - for (mode=0;helpmodes[mode].name!=NULL;++mode) { - if (strcmp(policy, helpmodes[mode].name)==0) { - result = get_alliance(self, other) & mode; - break; - } - } - - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - - -static int -tolua_faction_set_policy(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - faction * other = (faction *)tolua_tousertype(L, 2, 0); - const char * policy = tolua_tostring(L, 3, 0); - int value = tolua_toboolean(L, 4, 0); - - int mode; - for (mode=0;helpmodes[mode].name!=NULL;++mode) { - if (strcmp(policy, helpmodes[mode].name)==0) { - if (value) { - set_alliance(self, other, get_alliance(self, other) | helpmodes[mode].status); - } else { - set_alliance(self, other, get_alliance(self, other) & ~helpmodes[mode].status); - } - break; - } - } - - return 0; -} - -static int -tolua_faction_normalize(lua_State* L) -{ - faction * f = (faction *)tolua_tousertype(L, 1, 0); - region * r = (region * )tolua_tousertype(L, 2, 0); - if (r) { - plane * pl = rplane(r); - int nx = r->x, ny = r->y; - pnormalize(&nx, &ny, pl); - adjust_coordinates(f, &nx, &ny, pl, r); - tolua_pushnumber(L, (lua_Number)nx); - tolua_pushnumber(L, (lua_Number)ny); - return 2; - } - return 0; -} - -static int -tolua_faction_set_origin(lua_State* L) -{ - faction * f = (faction *)tolua_tousertype(L, 1, 0); - region * r = (region *)tolua_tousertype(L, 2, 0); - plane * pl = rplane(r); - int id = pl?pl->id:0; - - set_ursprung(f, id, r->x - plane_center_x(pl), r->y - plane_center_y(pl)); - return 0; -} - -static int -tolua_faction_get_origin(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - - ursprung * origin = self->ursprung; - int x, y; - while (origin!=NULL && origin->id!=0) { - origin = origin->next; - } - if (origin) { - x = origin->x; - y = origin->y; - } else { - x = 0; - y = 0; - } - - tolua_pushnumber(L, (lua_Number)x); - tolua_pushnumber(L, (lua_Number)y); - return 2; -} - -static int -tolua_faction_destroy(lua_State* L) -{ - faction* f = (faction*) tolua_tousertype(L, 1, 0); - destroyfaction(f); - return 0; -} - -static int -tolua_faction_create(lua_State* L) -{ - const char * email = tolua_tostring(L, 1, 0); - const char * racename = tolua_tostring(L, 2, 0); - const char * lang = tolua_tostring(L, 3, 0); - struct locale * loc = find_locale(lang); - faction * f = NULL; - const struct race * frace = rc_find(racename); - if (frace==NULL) frace = findrace(racename, find_locale("de")); - if (frace==NULL) frace = findrace(racename, find_locale("en")); - if (frace!=NULL) { - f = addfaction(email, NULL, frace, loc, 0); - } - if (!f) { - log_error(("faction.create(%s, %s, %s)\n", email, racename, lang)); - } - tolua_pushusertype(L, f, TOLUA_CAST "faction"); - return 1; -} - -static int tolua_faction_get_password(lua_State* L) -{ - faction* self = (faction*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, faction_getpassword(self)); - return 1; -} - -static int tolua_faction_set_password(lua_State* L) -{ - faction* self = (faction*)tolua_tousertype(L, 1, 0); - faction_setpassword(self, tolua_tostring(L, 2, 0)); - return 0; -} - -static int tolua_faction_get_email(lua_State* L) -{ - faction* self = (faction*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, faction_getemail(self)); - return 1; -} - -static int tolua_faction_set_email(lua_State* L) -{ - faction* self = (faction*)tolua_tousertype(L, 1, 0); - faction_setemail(self, tolua_tostring(L, 2, 0)); - return 0; -} - -static int tolua_faction_get_locale(lua_State* L) -{ - faction* self = (faction*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, locale_name(self->locale)); - return 1; -} - -static int tolua_faction_set_locale(lua_State* L) -{ - faction* self = (faction*)tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - self->locale = find_locale(name); - return 0; -} - -static int tolua_faction_get_race(lua_State* L) -{ - faction* self = (faction*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->race->_name[0]); - return 1; -} - -static int tolua_faction_set_race(lua_State* L) -{ - faction* self = (faction*)tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - race * rc = rc_find(name); - if (rc!=NULL) { - self->race = rc; - } - - return 0; -} - -static int tolua_faction_get_name(lua_State* L) -{ - faction* self = (faction*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, faction_getname(self)); - return 1; -} - -static int tolua_faction_set_name(lua_State* L) -{ - faction* self = (faction*)tolua_tousertype(L, 1, 0); - faction_setname(self, tolua_tostring(L, 2, 0)); - return 0; -} - -static int tolua_faction_get_uid(lua_State* L) -{ - faction* f = (faction*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, f->subscription); - return 1; -} - -static int tolua_faction_set_uid(lua_State* L) -{ - faction* f = (faction*)tolua_tousertype(L, 1, 0); - f->subscription = (int)tolua_tonumber(L, 2, 0); - return 0; -} - -static int tolua_faction_get_info(lua_State* L) -{ - faction* self = (faction*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, faction_getbanner(self)); - return 1; -} - -static int tolua_faction_set_info(lua_State* L) -{ - faction* self = (faction*)tolua_tousertype(L, 1, 0); - faction_setbanner(self, tolua_tostring(L, 2, 0)); - return 0; -} - -static int tolua_faction_get_alliance(lua_State* L) -{ - faction* self = (faction*) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, f_get_alliance(self), TOLUA_CAST "alliance"); - return 1; -} - -static int tolua_faction_set_alliance(lua_State* L) -{ - faction* self = (faction*)tolua_tousertype(L, 1, 0); - alliance* alli = (alliance*)tolua_tousertype(L, 2, 0); - - setalliance(self, alli); - - return 0; -} - -static int tolua_faction_get_items(lua_State* L) -{ - faction* self = (faction*)tolua_tousertype(L, 1, 0); - item ** item_ptr = (item **)lua_newuserdata(L, sizeof(item *)); - - luaL_getmetatable(L, TOLUA_CAST "item"); - lua_setmetatable(L, -2); - - *item_ptr = self->items; - - lua_pushcclosure(L, tolua_itemlist_next, 1); - - return 1; -} - -static int -tolua_faction_tostring(lua_State *L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - lua_pushstring(L, factionname(self)); - return 1; -} - -static int tolua_faction_get_spells(lua_State* L) -{ - faction* self = (faction*)tolua_tousertype(L, 1, 0); - spell_list * slist = self->spellbook; - if (slist) { - spell_list ** spell_ptr = (spell_list **)lua_newuserdata(L, sizeof(spell_list *)); - luaL_getmetatable(L, TOLUA_CAST "spell_list"); - lua_setmetatable(L, -2); - - *spell_ptr = slist; - lua_pushcclosure(L, tolua_spelllist_next, 1); - return 1; - } - - lua_pushnil(L); - return 1; -} - -void -tolua_faction_open(lua_State* L) -{ - /* register user types */ - tolua_usertype(L, TOLUA_CAST "faction"); - tolua_usertype(L, TOLUA_CAST "faction_list"); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_cclass(L, TOLUA_CAST "faction", TOLUA_CAST "faction", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "faction"); - { - tolua_function(L, TOLUA_CAST "__tostring", tolua_faction_tostring); - - tolua_variable(L, TOLUA_CAST "id", tolua_faction_get_id, tolua_faction_set_id); - tolua_variable(L, TOLUA_CAST "uid", &tolua_faction_get_uid, &tolua_faction_set_uid); - tolua_variable(L, TOLUA_CAST "name", &tolua_faction_get_name, &tolua_faction_set_name); - tolua_variable(L, TOLUA_CAST "info", &tolua_faction_get_info, &tolua_faction_set_info); - tolua_variable(L, TOLUA_CAST "units", tolua_faction_get_units, NULL); - tolua_variable(L, TOLUA_CAST "heroes", tolua_faction_get_heroes, NULL); - tolua_variable(L, TOLUA_CAST "spells", tolua_faction_get_spells, 0); - tolua_variable(L, TOLUA_CAST "maxheroes", tolua_faction_get_maxheroes, NULL); - tolua_variable(L, TOLUA_CAST "password", tolua_faction_get_password, tolua_faction_set_password); - tolua_variable(L, TOLUA_CAST "email", tolua_faction_get_email, tolua_faction_set_email); - tolua_variable(L, TOLUA_CAST "locale", tolua_faction_get_locale, tolua_faction_set_locale); - tolua_variable(L, TOLUA_CAST "race", tolua_faction_get_race, tolua_faction_set_race); - tolua_variable(L, TOLUA_CAST "alliance", tolua_faction_get_alliance, tolua_faction_set_alliance); - tolua_variable(L, TOLUA_CAST "score", tolua_faction_get_score, NULL); - tolua_variable(L, TOLUA_CAST "age", tolua_faction_get_age, tolua_faction_set_age); - tolua_variable(L, TOLUA_CAST "options", tolua_faction_get_options, tolua_faction_set_options); - tolua_variable(L, TOLUA_CAST "flags", tolua_faction_get_flags, NULL); - tolua_variable(L, TOLUA_CAST "lastturn", tolua_faction_get_lastturn, tolua_faction_set_lastturn); - - tolua_function(L, TOLUA_CAST "set_policy", &tolua_faction_set_policy); - tolua_function(L, TOLUA_CAST "get_policy", &tolua_faction_get_policy); - tolua_function(L, TOLUA_CAST "get_origin", &tolua_faction_get_origin); - tolua_function(L, TOLUA_CAST "set_origin", &tolua_faction_set_origin); - tolua_function(L, TOLUA_CAST "normalize", &tolua_faction_normalize); - - tolua_function(L, TOLUA_CAST "add_item", tolua_faction_add_item); - tolua_variable(L, TOLUA_CAST "items", tolua_faction_get_items, NULL); - - tolua_function(L, TOLUA_CAST "renumber", &tolua_faction_renumber); - tolua_function(L, TOLUA_CAST "create", &tolua_faction_create); - tolua_function(L, TOLUA_CAST "destroy", &tolua_faction_destroy); -#ifdef TODO - def("faction_origin", &faction_getorigin, pure_out_value(_2) + pure_out_value(_3)), - - .def_readwrite("subscription", &faction::subscription) - - .property("x", &faction_getorigin_x, &faction_setorigin_x) - .property("y", &faction_getorigin_y, &faction_setorigin_y) - - .def("add_notice", &faction_addnotice) -#endif - tolua_variable(L, TOLUA_CAST "objects", tolua_faction_get_objects, NULL); - } - tolua_endmodule(L); - } - tolua_endmodule(L); -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bind_faction.h" +#include "bind_unit.h" +#include "bindings.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +int tolua_factionlist_next(lua_State *L) +{ + faction** faction_ptr = (faction **)lua_touserdata(L, lua_upvalueindex(1)); + faction * f = *faction_ptr; + if (f != NULL) { + tolua_pushusertype(L, (void*)f, TOLUA_CAST "faction"); + *faction_ptr = f->next; + return 1; + } + else return 0; /* no more values to return */ +} + +int tolua_factionlist_iter(lua_State *L) +{ + faction_list** faction_ptr = (faction_list **)lua_touserdata(L, lua_upvalueindex(1)); + faction_list* flist = *faction_ptr; + if (flist != NULL) { + tolua_pushusertype(L, (void*)flist->data, TOLUA_CAST "faction"); + *faction_ptr = flist->next; + return 1; + } + else return 0; /* no more values to return */ +} + +static int tolua_faction_get_units(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); + + luaL_getmetatable(L, TOLUA_CAST "unit"); + lua_setmetatable(L, -2); + + *unit_ptr = self->units; + + lua_pushcclosure(L, tolua_unitlist_nextf, 1); + return 1; +} + +int tolua_faction_add_item(lua_State *L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + const char * iname = tolua_tostring(L, 2, 0); + int number = (int)tolua_tonumber(L, 3, 0); + int result = -1; + + if (iname!=NULL) { + const item_type * itype = it_find(iname); + if (itype!=NULL) { + item * i = i_change(&self->items, itype, number); + result = i?i->number:0; + } // if (itype!=NULL) + } + lua_pushnumber(L, result); + return 1; +} + +static int +tolua_faction_get_maxheroes(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)maxheroes(self)); + return 1; +} + +static int +tolua_faction_get_heroes(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)countheroes(self)); + return 1; +} + +static int +tolua_faction_get_score(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->score); + return 1; +} + +static int +tolua_faction_get_id(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->no); + return 1; +} + +static int +tolua_faction_set_id(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + int id = (int)tolua_tonumber(L, 2, 0); + if (findfaction(id)==NULL) { + renumber_faction(self, id); + lua_pushboolean(L, 1); + } else { + lua_pushboolean(L, 0); + } + return 1; +} + +static int +tolua_faction_get_age(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->age); + return 1; +} + +static int +tolua_faction_set_age(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + int age = (int)tolua_tonumber(L, 2, 0); + self->age = age; + return 0; +} + +static int +tolua_faction_get_flags(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->flags); + return 1; +} + +static int +tolua_faction_get_options(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->options); + return 1; +} + +static int +tolua_faction_set_options(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + int options = (int)tolua_tonumber(L, 2, self->options); + self->options = options; + return 1; +} + +static int +tolua_faction_get_lastturn(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->lastorders); + return 1; +} + +static int +tolua_faction_set_lastturn(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + if (self) { + self->lastorders = (int)tolua_tonumber(L, 2, self->lastorders); + } + return 0; +} + +static int +tolua_faction_renumber(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + int no = (int)tolua_tonumber(L, 2, 0); + + renumber_faction(self, no); + return 0; +} + +static int +tolua_faction_get_objects(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); + return 1; +} + +static int +tolua_faction_get_policy(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + faction * other = (faction *)tolua_tousertype(L, 2, 0); + const char * policy = tolua_tostring(L, 3, 0); + + int result = 0, mode; + for (mode=0;helpmodes[mode].name!=NULL;++mode) { + if (strcmp(policy, helpmodes[mode].name)==0) { + result = get_alliance(self, other) & mode; + break; + } + } + + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + + +static int +tolua_faction_set_policy(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + faction * other = (faction *)tolua_tousertype(L, 2, 0); + const char * policy = tolua_tostring(L, 3, 0); + int value = tolua_toboolean(L, 4, 0); + + int mode; + for (mode=0;helpmodes[mode].name!=NULL;++mode) { + if (strcmp(policy, helpmodes[mode].name)==0) { + if (value) { + set_alliance(self, other, get_alliance(self, other) | helpmodes[mode].status); + } else { + set_alliance(self, other, get_alliance(self, other) & ~helpmodes[mode].status); + } + break; + } + } + + return 0; +} + +static int +tolua_faction_normalize(lua_State* L) +{ + faction * f = (faction *)tolua_tousertype(L, 1, 0); + region * r = (region * )tolua_tousertype(L, 2, 0); + if (r) { + plane * pl = rplane(r); + int nx = r->x, ny = r->y; + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl, r); + tolua_pushnumber(L, (lua_Number)nx); + tolua_pushnumber(L, (lua_Number)ny); + return 2; + } + return 0; +} + +static int +tolua_faction_set_origin(lua_State* L) +{ + faction * f = (faction *)tolua_tousertype(L, 1, 0); + region * r = (region *)tolua_tousertype(L, 2, 0); + plane * pl = rplane(r); + int id = pl?pl->id:0; + + set_ursprung(f, id, r->x - plane_center_x(pl), r->y - plane_center_y(pl)); + return 0; +} + +static int +tolua_faction_get_origin(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + + ursprung * origin = self->ursprung; + int x, y; + while (origin!=NULL && origin->id!=0) { + origin = origin->next; + } + if (origin) { + x = origin->x; + y = origin->y; + } else { + x = 0; + y = 0; + } + + tolua_pushnumber(L, (lua_Number)x); + tolua_pushnumber(L, (lua_Number)y); + return 2; +} + +static int +tolua_faction_destroy(lua_State* L) +{ + faction* f = (faction*) tolua_tousertype(L, 1, 0); + destroyfaction(f); + return 0; +} + +static int +tolua_faction_create(lua_State* L) +{ + const char * email = tolua_tostring(L, 1, 0); + const char * racename = tolua_tostring(L, 2, 0); + const char * lang = tolua_tostring(L, 3, 0); + struct locale * loc = find_locale(lang); + faction * f = NULL; + const struct race * frace = rc_find(racename); + if (frace==NULL) frace = findrace(racename, find_locale("de")); + if (frace==NULL) frace = findrace(racename, find_locale("en")); + if (frace!=NULL) { + f = addfaction(email, NULL, frace, loc, 0); + } + if (!f) { + log_error(("faction.create(%s, %s, %s)\n", email, racename, lang)); + } + tolua_pushusertype(L, f, TOLUA_CAST "faction"); + return 1; +} + +static int tolua_faction_get_password(lua_State* L) +{ + faction* self = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, faction_getpassword(self)); + return 1; +} + +static int tolua_faction_set_password(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + faction_setpassword(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int tolua_faction_get_email(lua_State* L) +{ + faction* self = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, faction_getemail(self)); + return 1; +} + +static int tolua_faction_set_email(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + faction_setemail(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int tolua_faction_get_locale(lua_State* L) +{ + faction* self = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, locale_name(self->locale)); + return 1; +} + +static int tolua_faction_set_locale(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + self->locale = find_locale(name); + return 0; +} + +static int tolua_faction_get_race(lua_State* L) +{ + faction* self = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->race->_name[0]); + return 1; +} + +static int tolua_faction_set_race(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + race * rc = rc_find(name); + if (rc!=NULL) { + self->race = rc; + } + + return 0; +} + +static int tolua_faction_get_name(lua_State* L) +{ + faction* self = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, faction_getname(self)); + return 1; +} + +static int tolua_faction_set_name(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + faction_setname(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int tolua_faction_get_uid(lua_State* L) +{ + faction* f = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, f->subscription); + return 1; +} + +static int tolua_faction_set_uid(lua_State* L) +{ + faction* f = (faction*)tolua_tousertype(L, 1, 0); + f->subscription = (int)tolua_tonumber(L, 2, 0); + return 0; +} + +static int tolua_faction_get_info(lua_State* L) +{ + faction* self = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, faction_getbanner(self)); + return 1; +} + +static int tolua_faction_set_info(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + faction_setbanner(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int tolua_faction_get_alliance(lua_State* L) +{ + faction* self = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, f_get_alliance(self), TOLUA_CAST "alliance"); + return 1; +} + +static int tolua_faction_set_alliance(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + alliance* alli = (alliance*)tolua_tousertype(L, 2, 0); + + setalliance(self, alli); + + return 0; +} + +static int tolua_faction_get_items(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + item ** item_ptr = (item **)lua_newuserdata(L, sizeof(item *)); + + luaL_getmetatable(L, TOLUA_CAST "item"); + lua_setmetatable(L, -2); + + *item_ptr = self->items; + + lua_pushcclosure(L, tolua_itemlist_next, 1); + + return 1; +} + +static int +tolua_faction_tostring(lua_State *L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, factionname(self)); + return 1; +} + +static int tolua_faction_get_spells(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + spell_list * slist = self->spellbook; + if (slist) { + spell_list ** spell_ptr = (spell_list **)lua_newuserdata(L, sizeof(spell_list *)); + luaL_getmetatable(L, TOLUA_CAST "spell_list"); + lua_setmetatable(L, -2); + + *spell_ptr = slist; + lua_pushcclosure(L, tolua_spelllist_next, 1); + return 1; + } + + lua_pushnil(L); + return 1; +} + +void +tolua_faction_open(lua_State* L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "faction"); + tolua_usertype(L, TOLUA_CAST "faction_list"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, TOLUA_CAST "faction", TOLUA_CAST "faction", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "faction"); + { + tolua_function(L, TOLUA_CAST "__tostring", tolua_faction_tostring); + + tolua_variable(L, TOLUA_CAST "id", tolua_faction_get_id, tolua_faction_set_id); + tolua_variable(L, TOLUA_CAST "uid", &tolua_faction_get_uid, &tolua_faction_set_uid); + tolua_variable(L, TOLUA_CAST "name", &tolua_faction_get_name, &tolua_faction_set_name); + tolua_variable(L, TOLUA_CAST "info", &tolua_faction_get_info, &tolua_faction_set_info); + tolua_variable(L, TOLUA_CAST "units", tolua_faction_get_units, NULL); + tolua_variable(L, TOLUA_CAST "heroes", tolua_faction_get_heroes, NULL); + tolua_variable(L, TOLUA_CAST "spells", tolua_faction_get_spells, 0); + tolua_variable(L, TOLUA_CAST "maxheroes", tolua_faction_get_maxheroes, NULL); + tolua_variable(L, TOLUA_CAST "password", tolua_faction_get_password, tolua_faction_set_password); + tolua_variable(L, TOLUA_CAST "email", tolua_faction_get_email, tolua_faction_set_email); + tolua_variable(L, TOLUA_CAST "locale", tolua_faction_get_locale, tolua_faction_set_locale); + tolua_variable(L, TOLUA_CAST "race", tolua_faction_get_race, tolua_faction_set_race); + tolua_variable(L, TOLUA_CAST "alliance", tolua_faction_get_alliance, tolua_faction_set_alliance); + tolua_variable(L, TOLUA_CAST "score", tolua_faction_get_score, NULL); + tolua_variable(L, TOLUA_CAST "age", tolua_faction_get_age, tolua_faction_set_age); + tolua_variable(L, TOLUA_CAST "options", tolua_faction_get_options, tolua_faction_set_options); + tolua_variable(L, TOLUA_CAST "flags", tolua_faction_get_flags, NULL); + tolua_variable(L, TOLUA_CAST "lastturn", tolua_faction_get_lastturn, tolua_faction_set_lastturn); + + tolua_function(L, TOLUA_CAST "set_policy", &tolua_faction_set_policy); + tolua_function(L, TOLUA_CAST "get_policy", &tolua_faction_get_policy); + tolua_function(L, TOLUA_CAST "get_origin", &tolua_faction_get_origin); + tolua_function(L, TOLUA_CAST "set_origin", &tolua_faction_set_origin); + tolua_function(L, TOLUA_CAST "normalize", &tolua_faction_normalize); + + tolua_function(L, TOLUA_CAST "add_item", tolua_faction_add_item); + tolua_variable(L, TOLUA_CAST "items", tolua_faction_get_items, NULL); + + tolua_function(L, TOLUA_CAST "renumber", &tolua_faction_renumber); + tolua_function(L, TOLUA_CAST "create", &tolua_faction_create); + tolua_function(L, TOLUA_CAST "destroy", &tolua_faction_destroy); +#ifdef TODO + def("faction_origin", &faction_getorigin, pure_out_value(_2) + pure_out_value(_3)), + + .def_readwrite("subscription", &faction::subscription) + + .property("x", &faction_getorigin_x, &faction_setorigin_x) + .property("y", &faction_getorigin_y, &faction_setorigin_y) + + .def("add_notice", &faction_addnotice) +#endif + tolua_variable(L, TOLUA_CAST "objects", tolua_faction_get_objects, NULL); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_faction.h b/src/bindings/bind_faction.h index c89750062..e4148e016 100644 --- a/src/bindings/bind_faction.h +++ b/src/bindings/bind_faction.h @@ -1,24 +1,24 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - int tolua_factionlist_next(struct lua_State *L); - int tolua_factionlist_iter(struct lua_State *L); - void tolua_faction_open(struct lua_State *L); - -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + int tolua_factionlist_next(struct lua_State *L); + int tolua_factionlist_iter(struct lua_State *L); + void tolua_faction_open(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_gmtool.c b/src/bindings/bind_gmtool.c index 6b57d1740..2e6924a5e 100644 --- a/src/bindings/bind_gmtool.c +++ b/src/bindings/bind_gmtool.c @@ -1,266 +1,266 @@ -#include -#include - -#include "bind_gmtool.h" -#include "../gmtool.h" -#include "../gmtool_structs.h" - -#include -#include -#include -#include - -#include -#include - -static int -tolua_run_mapper(lua_State* L) -{ - run_mapper(); - return 0; -} - -static int -tolua_highlight_region(lua_State* L) -{ - region * r = tolua_tousertype(L, 1, 0); - int select = tolua_toboolean(L, 2, 0); - highlight_region(r, select); - return 0; -} - -static int -tolua_current_region(lua_State* L) -{ - map_region * mr = cursor_region(¤t_state->display, ¤t_state->cursor); - tolua_pushusertype(L, mr?mr->r:NULL, TOLUA_CAST "region"); - return 1; -} - - -static int -tolua_select_coordinate(lua_State* L) -{ - int nx = (int)tolua_tonumber(L, 1, 0); - int ny = (int)tolua_tonumber(L, 2, 0); - int select = tolua_toboolean(L, 3, 0); - if (current_state) { - select_coordinate(current_state->selected, nx, ny, select); - } - return 0; -} - -static int -tolua_select_region(lua_State* L) -{ - region * r = tolua_tousertype(L, 1, 0); - int select = tolua_toboolean(L, 2, 0); - if (current_state && r) { - select_coordinate(current_state->selected, r->x, r->y, select); - } - return 0; -} - -typedef struct tag_iterator { - selection * list; - tag * node; - region * r; - int hash; -} tag_iterator; - -void -tag_advance(tag_iterator * iter) -{ - while (iter->hash!=MAXTHASH) { - if (iter->node) { - iter->node = iter->node->nexthash; - } - while (!iter->node && iter->hash != MAXTHASH) { - if (++iter->hash != MAXTHASH) { - iter->node = iter->list->tags[iter->hash]; - } - } - if (iter->node) { - iter->r = findregion(iter->node->coord.x, iter->node->coord.y); - if (iter->r) { - break; - } - } - } -} - -void -tag_rewind(tag_iterator * iter) -{ - if (iter->list) { - iter->r = NULL; - iter->node = iter->list->tags[0]; - iter->hash = 0; - if (iter->node) { - iter->r = findregion(iter->node->coord.x, iter->node->coord.y); - } - if (!iter->r) { - tag_advance(iter); - } - } else { - iter->node = 0; - iter->hash = MAXTHASH; - } -} - -static int -tolua_tags_next(lua_State *L) -{ - tag_iterator * iter = (tag_iterator *)lua_touserdata(L, lua_upvalueindex(1)); - if (iter->node) { - tolua_pushusertype(L, (void*)iter->r, TOLUA_CAST "region"); - tag_advance(iter); - return 1; - } - else { - return 0; /* no more values to return */ - } -} - -static int -tolua_selected_regions(lua_State* L) -{ - tag_iterator * iter = (tag_iterator*)lua_newuserdata(L, sizeof(tag_iterator)); - - luaL_getmetatable(L, "tag_iterator"); - lua_setmetatable(L, -2); - - iter->list = current_state->selected; - tag_rewind(iter); - - lua_pushcclosure(L, tolua_tags_next, 1); - return 1; -} - -static int -tolua_state_open(lua_State* L) -{ - unused(L); - state_open(); - return 0; -} - -static int -tolua_state_close(lua_State* L) -{ - unused(L); - state_close(current_state); - return 0; -} - -static int -tolua_make_island(lua_State * L) -{ - int x = (int)tolua_tonumber(L, 1, 0); - int y = (int)tolua_tonumber(L, 2, 0); - int s = (int)tolua_tonumber(L, 3, 0); - int n = (int)tolua_tonumber(L, 4, s / 3); - - n = build_island_e3(x, y, n, s); - tolua_pushnumber(L, n); - return 1; -} - -static int paint_handle; -static struct lua_State * paint_state; - -static void -lua_paint_info(struct window * wnd, const struct state * st) -{ - struct lua_State * L = paint_state; - int nx = st->cursor.x, ny = st->cursor.y; - pnormalize(&nx, &ny, st->cursor.pl); - lua_rawgeti(L, LUA_REGISTRYINDEX, paint_handle); - tolua_pushnumber(L, nx); - tolua_pushnumber(L, ny); - if (lua_pcall(L, 2, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("paint function failed: %s\n", error)); - lua_pop(L, 1); - tolua_error(L, TOLUA_CAST "event handler call failed", NULL); - } else { - const char* result = lua_tostring(L, -1); - WINDOW * win = wnd->handle; - int size = getmaxx(win)-2; - int line = 0, maxline = getmaxy(win)-2; - const char * str = result; - wxborder(win); - - while (*str && line +#include + +#include "bind_gmtool.h" +#include "../gmtool.h" +#include "../gmtool_structs.h" + +#include +#include +#include +#include + +#include +#include + +static int +tolua_run_mapper(lua_State* L) +{ + run_mapper(); + return 0; +} + +static int +tolua_highlight_region(lua_State* L) +{ + region * r = tolua_tousertype(L, 1, 0); + int select = tolua_toboolean(L, 2, 0); + highlight_region(r, select); + return 0; +} + +static int +tolua_current_region(lua_State* L) +{ + map_region * mr = cursor_region(¤t_state->display, ¤t_state->cursor); + tolua_pushusertype(L, mr?mr->r:NULL, TOLUA_CAST "region"); + return 1; +} + + +static int +tolua_select_coordinate(lua_State* L) +{ + int nx = (int)tolua_tonumber(L, 1, 0); + int ny = (int)tolua_tonumber(L, 2, 0); + int select = tolua_toboolean(L, 3, 0); + if (current_state) { + select_coordinate(current_state->selected, nx, ny, select); + } + return 0; +} + +static int +tolua_select_region(lua_State* L) +{ + region * r = tolua_tousertype(L, 1, 0); + int select = tolua_toboolean(L, 2, 0); + if (current_state && r) { + select_coordinate(current_state->selected, r->x, r->y, select); + } + return 0; +} + +typedef struct tag_iterator { + selection * list; + tag * node; + region * r; + int hash; +} tag_iterator; + +void +tag_advance(tag_iterator * iter) +{ + while (iter->hash!=MAXTHASH) { + if (iter->node) { + iter->node = iter->node->nexthash; + } + while (!iter->node && iter->hash != MAXTHASH) { + if (++iter->hash != MAXTHASH) { + iter->node = iter->list->tags[iter->hash]; + } + } + if (iter->node) { + iter->r = findregion(iter->node->coord.x, iter->node->coord.y); + if (iter->r) { + break; + } + } + } +} + +void +tag_rewind(tag_iterator * iter) +{ + if (iter->list) { + iter->r = NULL; + iter->node = iter->list->tags[0]; + iter->hash = 0; + if (iter->node) { + iter->r = findregion(iter->node->coord.x, iter->node->coord.y); + } + if (!iter->r) { + tag_advance(iter); + } + } else { + iter->node = 0; + iter->hash = MAXTHASH; + } +} + +static int +tolua_tags_next(lua_State *L) +{ + tag_iterator * iter = (tag_iterator *)lua_touserdata(L, lua_upvalueindex(1)); + if (iter->node) { + tolua_pushusertype(L, (void*)iter->r, TOLUA_CAST "region"); + tag_advance(iter); + return 1; + } + else { + return 0; /* no more values to return */ + } +} + +static int +tolua_selected_regions(lua_State* L) +{ + tag_iterator * iter = (tag_iterator*)lua_newuserdata(L, sizeof(tag_iterator)); + + luaL_getmetatable(L, "tag_iterator"); + lua_setmetatable(L, -2); + + iter->list = current_state->selected; + tag_rewind(iter); + + lua_pushcclosure(L, tolua_tags_next, 1); + return 1; +} + +static int +tolua_state_open(lua_State* L) +{ + unused(L); + state_open(); + return 0; +} + +static int +tolua_state_close(lua_State* L) +{ + unused(L); + state_close(current_state); + return 0; +} + +static int +tolua_make_island(lua_State * L) +{ + int x = (int)tolua_tonumber(L, 1, 0); + int y = (int)tolua_tonumber(L, 2, 0); + int s = (int)tolua_tonumber(L, 3, 0); + int n = (int)tolua_tonumber(L, 4, s / 3); + + n = build_island_e3(x, y, n, s); + tolua_pushnumber(L, n); + return 1; +} + +static int paint_handle; +static struct lua_State * paint_state; + +static void +lua_paint_info(struct window * wnd, const struct state * st) +{ + struct lua_State * L = paint_state; + int nx = st->cursor.x, ny = st->cursor.y; + pnormalize(&nx, &ny, st->cursor.pl); + lua_rawgeti(L, LUA_REGISTRYINDEX, paint_handle); + tolua_pushnumber(L, nx); + tolua_pushnumber(L, ny); + if (lua_pcall(L, 2, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("paint function failed: %s\n", error)); + lua_pop(L, 1); + tolua_error(L, TOLUA_CAST "event handler call failed", NULL); + } else { + const char* result = lua_tostring(L, -1); + WINDOW * win = wnd->handle; + int size = getmaxx(win)-2; + int line = 0, maxline = getmaxy(win)-2; + const char * str = result; + wxborder(win); + + while (*str && line -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include "bind_hashtable.h" - -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include - -#include - -static int -tolua_hashtable_get(lua_State* L) -{ - hashtable self = (hashtable) tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - attrib * a = a_find(*self, &at_object); - - for (; a && a->type == &at_object; a = a->next) { - const char * obj_name = object_name(a); - if (obj_name && name && strcmp(obj_name, name) == 0) { - variant val; - object_type type; - - object_get(a, &type, &val); - switch (type) { - case TNONE: - lua_pushnil(L); - break; - case TINTEGER: - lua_pushnumber(L, (lua_Number)val.i); - break; - case TREAL: - lua_pushnumber(L, (lua_Number)val.f); - break; - case TREGION: - tolua_pushusertype(L, val.v, TOLUA_CAST "region"); - break; - case TBUILDING: - tolua_pushusertype(L, val.v, TOLUA_CAST "building"); - break; - case TUNIT: - tolua_pushusertype(L, val.v, TOLUA_CAST "unit"); - break; - case TSHIP: - tolua_pushusertype(L, val.v, TOLUA_CAST "ship"); - break; - case TSTRING: - tolua_pushstring(L, (const char*) val.v); - break; - default: - assert(!"not implemented"); - } - return 1; - } - } - lua_pushnil(L); - return 1; -} - -static int -tolua_hashtable_set_number(lua_State* L) -{ - hashtable self = (hashtable) tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - lua_Number value = tolua_tonumber(L, 3, 0); - attrib * a = a_find(*self, &at_object); - variant val; - - val.f = (float)value; - - for (; a && a->type == &at_object; a = a->next) { - if (strcmp(object_name(a), name) == 0) { - object_set(a, TREAL, val); - return 0; - } - } - - a = a_add(self, object_create(name, TREAL, val)); - return 0; -} - -static int -tolua_hashtable_set_string(lua_State* L) -{ - hashtable self = (hashtable) tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - const char * value = tolua_tostring(L, 3, 0); - attrib * a = a_find(*self, &at_object); - variant val; - - val.v = strdup(value); - - for (; a && a->type == &at_object; a = a->next) { - if (strcmp(object_name(a), name) == 0) { - object_set(a, TSTRING, val); - return 0; - } - } - - a = a_add(self, object_create(name, TSTRING, val)); - return 0; -} - -static int -tolua_hashtable_set_usertype(lua_State* L, int type) -{ - hashtable self = (hashtable) tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - unit * value = tolua_tousertype(L, 3, 0); - attrib * a = a_find(*self, &at_object); - variant val; - - val.v = value; - - for (; a && a->type == &at_object; a = a->next) { - if (strcmp(object_name(a), name) == 0) { - object_set(a, type, val); - return 0; - } - } - - a = a_add(self, object_create(name, type, val)); - return 0; -} - - -static int -tolua_hashtable_set(lua_State* L) -{ - tolua_Error tolua_err; - if (tolua_isnumber(L, 3, 0, &tolua_err)) { - return tolua_hashtable_set_number(L); - } else if (tolua_isusertype(L, 3, TOLUA_CAST "unit", 0, &tolua_err)) { - return tolua_hashtable_set_usertype(L, TUNIT); - } else if (tolua_isusertype(L, 3, TOLUA_CAST "faction", 0, &tolua_err)) { - return tolua_hashtable_set_usertype(L, TFACTION); - } else if (tolua_isusertype(L, 3, TOLUA_CAST "ship", 0, &tolua_err)) { - return tolua_hashtable_set_usertype(L, TSHIP); - } else if (tolua_isusertype(L, 3, TOLUA_CAST "building", 0, &tolua_err)) { - return tolua_hashtable_set_usertype(L, TBUILDING); - } else if (tolua_isusertype(L, 3, TOLUA_CAST "region", 0, &tolua_err)) { - return tolua_hashtable_set_usertype(L, TREGION); - } - return tolua_hashtable_set_string(L); -} - - - -void -tolua_hashtable_open(lua_State* L) -{ - /* register user types */ - tolua_usertype(L, TOLUA_CAST "hashtable"); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_cclass(L, TOLUA_CAST "hashtable", TOLUA_CAST "hashtable", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "hashtable"); - { - tolua_function(L, TOLUA_CAST "get", tolua_hashtable_get); - tolua_function(L, TOLUA_CAST "set", tolua_hashtable_set); - } - tolua_endmodule(L); - } - tolua_endmodule(L); -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bind_hashtable.h" + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include + +static int +tolua_hashtable_get(lua_State* L) +{ + hashtable self = (hashtable) tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + attrib * a = a_find(*self, &at_object); + + for (; a && a->type == &at_object; a = a->next) { + const char * obj_name = object_name(a); + if (obj_name && name && strcmp(obj_name, name) == 0) { + variant val; + object_type type; + + object_get(a, &type, &val); + switch (type) { + case TNONE: + lua_pushnil(L); + break; + case TINTEGER: + lua_pushnumber(L, (lua_Number)val.i); + break; + case TREAL: + lua_pushnumber(L, (lua_Number)val.f); + break; + case TREGION: + tolua_pushusertype(L, val.v, TOLUA_CAST "region"); + break; + case TBUILDING: + tolua_pushusertype(L, val.v, TOLUA_CAST "building"); + break; + case TUNIT: + tolua_pushusertype(L, val.v, TOLUA_CAST "unit"); + break; + case TSHIP: + tolua_pushusertype(L, val.v, TOLUA_CAST "ship"); + break; + case TSTRING: + tolua_pushstring(L, (const char*) val.v); + break; + default: + assert(!"not implemented"); + } + return 1; + } + } + lua_pushnil(L); + return 1; +} + +static int +tolua_hashtable_set_number(lua_State* L) +{ + hashtable self = (hashtable) tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + lua_Number value = tolua_tonumber(L, 3, 0); + attrib * a = a_find(*self, &at_object); + variant val; + + val.f = (float)value; + + for (; a && a->type == &at_object; a = a->next) { + if (strcmp(object_name(a), name) == 0) { + object_set(a, TREAL, val); + return 0; + } + } + + a = a_add(self, object_create(name, TREAL, val)); + return 0; +} + +static int +tolua_hashtable_set_string(lua_State* L) +{ + hashtable self = (hashtable) tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + const char * value = tolua_tostring(L, 3, 0); + attrib * a = a_find(*self, &at_object); + variant val; + + val.v = strdup(value); + + for (; a && a->type == &at_object; a = a->next) { + if (strcmp(object_name(a), name) == 0) { + object_set(a, TSTRING, val); + return 0; + } + } + + a = a_add(self, object_create(name, TSTRING, val)); + return 0; +} + +static int +tolua_hashtable_set_usertype(lua_State* L, int type) +{ + hashtable self = (hashtable) tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + unit * value = tolua_tousertype(L, 3, 0); + attrib * a = a_find(*self, &at_object); + variant val; + + val.v = value; + + for (; a && a->type == &at_object; a = a->next) { + if (strcmp(object_name(a), name) == 0) { + object_set(a, type, val); + return 0; + } + } + + a = a_add(self, object_create(name, type, val)); + return 0; +} + + +static int +tolua_hashtable_set(lua_State* L) +{ + tolua_Error tolua_err; + if (tolua_isnumber(L, 3, 0, &tolua_err)) { + return tolua_hashtable_set_number(L); + } else if (tolua_isusertype(L, 3, TOLUA_CAST "unit", 0, &tolua_err)) { + return tolua_hashtable_set_usertype(L, TUNIT); + } else if (tolua_isusertype(L, 3, TOLUA_CAST "faction", 0, &tolua_err)) { + return tolua_hashtable_set_usertype(L, TFACTION); + } else if (tolua_isusertype(L, 3, TOLUA_CAST "ship", 0, &tolua_err)) { + return tolua_hashtable_set_usertype(L, TSHIP); + } else if (tolua_isusertype(L, 3, TOLUA_CAST "building", 0, &tolua_err)) { + return tolua_hashtable_set_usertype(L, TBUILDING); + } else if (tolua_isusertype(L, 3, TOLUA_CAST "region", 0, &tolua_err)) { + return tolua_hashtable_set_usertype(L, TREGION); + } + return tolua_hashtable_set_string(L); +} + + + +void +tolua_hashtable_open(lua_State* L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "hashtable"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, TOLUA_CAST "hashtable", TOLUA_CAST "hashtable", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "hashtable"); + { + tolua_function(L, TOLUA_CAST "get", tolua_hashtable_get); + tolua_function(L, TOLUA_CAST "set", tolua_hashtable_set); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_hashtable.h b/src/bindings/bind_hashtable.h index d137638f2..266b9027e 100644 --- a/src/bindings/bind_hashtable.h +++ b/src/bindings/bind_hashtable.h @@ -1,24 +1,24 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - void tolua_hashtable_open(struct lua_State *L); - - typedef struct attrib ** hashtable; - -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + void tolua_hashtable_open(struct lua_State *L); + + typedef struct attrib ** hashtable; + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_message.c b/src/bindings/bind_message.c index 44c5eb0e7..f2de9538a 100644 --- a/src/bindings/bind_message.c +++ b/src/bindings/bind_message.c @@ -1,348 +1,348 @@ -#include -#include - -// kernel includes -#include -#include -#include -#include -#include -#include - -// util includes -#include - -// lua includes -#include -#include - -#include - -#define E_OK 0 -#define E_INVALID_MESSAGE 1 -#define E_INVALID_PARAMETER_NAME 2 -#define E_INVALID_PARAMETER_TYPE 3 -#define E_INVALID_PARAMETER_VALUE 4 - -typedef struct lua_message { - const message_type * mtype; - message * msg; - variant * args; -} lua_message; - -int -mtype_get_param(const message_type * mtype, const char * param) -{ - int i; - for (i=0;i!=mtype->nparameters;++i) { - if (strcmp(mtype->pnames[i], param)==0) { - return i; - } - } - return mtype->nparameters; -} - -static lua_message * -msg_create_message(const char *type) -{ - lua_message * lmsg = malloc(sizeof(lua_message)); - lmsg->msg = 0; - lmsg->args = 0; - lmsg->mtype = mt_find(type); - if (lmsg->mtype) { - lmsg->args = (variant*)calloc(lmsg->mtype->nparameters, sizeof(variant)); - } - return lmsg; -} - -/* - static void -msg_destroy_message(lua_message * msg) -{ - if (msg->msg) msg_release(msg->msg); - if (msg->mtype) { - int i; - for (i=0;i!=msg->mtype->nparameters;++i) { - if (msg->mtype->types[i]->release) { - msg->mtype->types[i]->release(msg->args[i]); - } - } - } -} -*/ -int -msg_set_resource(lua_message * msg, const char * param, const char * resname) -{ - if (msg->mtype) { - int i = mtype_get_param(msg->mtype, param); - if (i==msg->mtype->nparameters) { - return E_INVALID_PARAMETER_NAME; - } - if (strcmp(msg->mtype->types[i]->name, "resource")!=0) { - return E_INVALID_PARAMETER_TYPE; - } - - msg->args[i].v = (void*)rt_find(resname); - - return E_OK; - } - return E_INVALID_MESSAGE; -} - -int -msg_set_unit(lua_message * msg, const char * param, const unit * u) -{ - if (msg->mtype) { - int i = mtype_get_param(msg->mtype, param); - - if (i==msg->mtype->nparameters) { - return E_INVALID_PARAMETER_NAME; - } - if (strcmp(msg->mtype->types[i]->name, "unit")!=0) { - return E_INVALID_PARAMETER_TYPE; - } - - msg->args[i].v = (void*)u; - - return E_OK; - } - return E_INVALID_MESSAGE; -} - -int -msg_set_region(lua_message * msg, const char * param, const region * r) -{ - if (msg->mtype) { - int i = mtype_get_param(msg->mtype, param); - - if (i==msg->mtype->nparameters) { - return E_INVALID_PARAMETER_NAME; - } - if (strcmp(msg->mtype->types[i]->name, "region")!=0) { - return E_INVALID_PARAMETER_TYPE; - } - - msg->args[i].v = (void*)r; - - return E_OK; - } - return E_INVALID_MESSAGE; -} - -int -msg_set_string(lua_message * msg, const char * param, const char * value) -{ - if (msg->mtype) { - int i = mtype_get_param(msg->mtype, param); - variant var; - - if (i==msg->mtype->nparameters) { - return E_INVALID_PARAMETER_NAME; - } - if (strcmp(msg->mtype->types[i]->name, "string")!=0) { - return E_INVALID_PARAMETER_TYPE; - } - - var.v = (void*)value; - msg->args[i] = msg->mtype->types[i]->copy(var); - - return E_OK; - } - return E_INVALID_MESSAGE; -} - -int -msg_set_int(lua_message * msg, const char * param, int value) -{ - if (msg->mtype) { - int i = mtype_get_param(msg->mtype, param); - if (i==msg->mtype->nparameters) { - return E_INVALID_PARAMETER_NAME; - } - if (strcmp(msg->mtype->types[i]->name, "int")!=0) { - return E_INVALID_PARAMETER_TYPE; - } - - msg->args[i].i = value; - - return E_OK; - } - return E_INVALID_MESSAGE; -} - -int -msg_send_faction(lua_message * msg, faction * f) -{ - assert(f); - assert(msg); - - if (msg->mtype) { - if (msg->msg==NULL) { - msg->msg = msg_create(msg->mtype, msg->args); - } - add_message(&f->msgs, msg->msg); - return E_OK; - } - return E_INVALID_MESSAGE; -} - -int -msg_send_region(lua_message * lmsg, region * r) -{ - if (lmsg->mtype) { - if (lmsg->msg==NULL) { - lmsg->msg = msg_create(lmsg->mtype, lmsg->args); - } - add_message(&r->msgs, lmsg->msg); - return E_OK; - } - return E_INVALID_MESSAGE; -} - - -static int -tolua_msg_create(lua_State * L) -{ - const char * type = tolua_tostring(L, 1, 0); - lua_message * lmsg = msg_create_message(type); - tolua_pushusertype(L, (void*)lmsg, TOLUA_CAST "message"); - return 1; -} -static int -tolua_msg_set_string(lua_State * L) -{ - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - const char * param = tolua_tostring(L, 2, 0); - const char * value = tolua_tostring(L, 3, 0); - int result = msg_set_string(lmsg, param, value); - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_msg_set_int(lua_State * L) -{ - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - const char * param = tolua_tostring(L, 2, 0); - int value = (int)tolua_tonumber(L, 3, 0); - int result = msg_set_int(lmsg, param, value); - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_msg_set_resource(lua_State * L) -{ - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - const char * param = tolua_tostring(L, 2, 0); - const char * value = tolua_tostring(L, 3, 0); - int result = msg_set_resource(lmsg, param, value); - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_msg_set_unit(lua_State * L) -{ - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - const char * param = tolua_tostring(L, 2, 0); - unit * value = (unit *)tolua_tousertype(L, 3, 0); - int result = msg_set_unit(lmsg, param, value); - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_msg_set_region(lua_State * L) -{ - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - const char * param = tolua_tostring(L, 2, 0); - region * value = (region *)tolua_tousertype(L, 3, 0); - int result = msg_set_region(lmsg, param, value); - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_msg_set(lua_State * L) -{ - tolua_Error err; - if (tolua_isnumber(L, 3, 0, &err)) { - return tolua_msg_set_int(L); - } else if (tolua_isusertype(L, 3, TOLUA_CAST "region", 0, &err)) { - return tolua_msg_set_region(L); - } else if (tolua_isusertype(L, 3, TOLUA_CAST "unit", 0, &err)) { - return tolua_msg_set_unit(L); - } - tolua_pushnumber(L, (lua_Number)-1); - return 1; -} - -static int -tolua_msg_send_region(lua_State * L) -{ - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - region * r = (region *)tolua_tousertype(L, 2, 0); - int result = msg_send_region(lmsg, r); - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_msg_report_action(lua_State * L) -{ - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - region * r = (region *)tolua_tousertype(L, 2, 0); - unit * u = (unit *)tolua_tousertype(L, 3, 0); - int result, flags = (int)tolua_tonumber(L, 4, 0); - if (lmsg->msg==NULL) { - lmsg->msg = msg_create(lmsg->mtype, lmsg->args); - } - result = report_action(r, u, lmsg->msg, flags); - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_msg_send_faction(lua_State * L) -{ - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - faction * f = (faction *)tolua_tousertype(L, 2, 0); - if (f && lmsg) { - int result = msg_send_faction(lmsg, f); - tolua_pushnumber(L, (lua_Number)result); - return 1; - } - return 0; -} - -void -tolua_message_open(lua_State* L) -{ - /* register user types */ - tolua_usertype(L, TOLUA_CAST "message"); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_function(L, TOLUA_CAST "message", tolua_msg_create); - - tolua_cclass(L, TOLUA_CAST "message", TOLUA_CAST "message", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "message"); - { - tolua_function(L, TOLUA_CAST "set", tolua_msg_set); - tolua_function(L, TOLUA_CAST "set_unit", tolua_msg_set_unit); - tolua_function(L, TOLUA_CAST "set_region", tolua_msg_set_region); - tolua_function(L, TOLUA_CAST "set_resource", tolua_msg_set_resource); - tolua_function(L, TOLUA_CAST "set_int", tolua_msg_set_int); - tolua_function(L, TOLUA_CAST "set_string", tolua_msg_set_string); - tolua_function(L, TOLUA_CAST "send_faction", tolua_msg_send_faction); - tolua_function(L, TOLUA_CAST "send_region", tolua_msg_send_region); - tolua_function(L, TOLUA_CAST "report_action", tolua_msg_report_action); - - tolua_function(L, TOLUA_CAST "create", tolua_msg_create); - } - tolua_endmodule(L); - } - tolua_endmodule(L); -} +#include +#include + +// kernel includes +#include +#include +#include +#include +#include +#include + +// util includes +#include + +// lua includes +#include +#include + +#include + +#define E_OK 0 +#define E_INVALID_MESSAGE 1 +#define E_INVALID_PARAMETER_NAME 2 +#define E_INVALID_PARAMETER_TYPE 3 +#define E_INVALID_PARAMETER_VALUE 4 + +typedef struct lua_message { + const message_type * mtype; + message * msg; + variant * args; +} lua_message; + +int +mtype_get_param(const message_type * mtype, const char * param) +{ + int i; + for (i=0;i!=mtype->nparameters;++i) { + if (strcmp(mtype->pnames[i], param)==0) { + return i; + } + } + return mtype->nparameters; +} + +static lua_message * +msg_create_message(const char *type) +{ + lua_message * lmsg = malloc(sizeof(lua_message)); + lmsg->msg = 0; + lmsg->args = 0; + lmsg->mtype = mt_find(type); + if (lmsg->mtype) { + lmsg->args = (variant*)calloc(lmsg->mtype->nparameters, sizeof(variant)); + } + return lmsg; +} + +/* + static void +msg_destroy_message(lua_message * msg) +{ + if (msg->msg) msg_release(msg->msg); + if (msg->mtype) { + int i; + for (i=0;i!=msg->mtype->nparameters;++i) { + if (msg->mtype->types[i]->release) { + msg->mtype->types[i]->release(msg->args[i]); + } + } + } +} +*/ +int +msg_set_resource(lua_message * msg, const char * param, const char * resname) +{ + if (msg->mtype) { + int i = mtype_get_param(msg->mtype, param); + if (i==msg->mtype->nparameters) { + return E_INVALID_PARAMETER_NAME; + } + if (strcmp(msg->mtype->types[i]->name, "resource")!=0) { + return E_INVALID_PARAMETER_TYPE; + } + + msg->args[i].v = (void*)rt_find(resname); + + return E_OK; + } + return E_INVALID_MESSAGE; +} + +int +msg_set_unit(lua_message * msg, const char * param, const unit * u) +{ + if (msg->mtype) { + int i = mtype_get_param(msg->mtype, param); + + if (i==msg->mtype->nparameters) { + return E_INVALID_PARAMETER_NAME; + } + if (strcmp(msg->mtype->types[i]->name, "unit")!=0) { + return E_INVALID_PARAMETER_TYPE; + } + + msg->args[i].v = (void*)u; + + return E_OK; + } + return E_INVALID_MESSAGE; +} + +int +msg_set_region(lua_message * msg, const char * param, const region * r) +{ + if (msg->mtype) { + int i = mtype_get_param(msg->mtype, param); + + if (i==msg->mtype->nparameters) { + return E_INVALID_PARAMETER_NAME; + } + if (strcmp(msg->mtype->types[i]->name, "region")!=0) { + return E_INVALID_PARAMETER_TYPE; + } + + msg->args[i].v = (void*)r; + + return E_OK; + } + return E_INVALID_MESSAGE; +} + +int +msg_set_string(lua_message * msg, const char * param, const char * value) +{ + if (msg->mtype) { + int i = mtype_get_param(msg->mtype, param); + variant var; + + if (i==msg->mtype->nparameters) { + return E_INVALID_PARAMETER_NAME; + } + if (strcmp(msg->mtype->types[i]->name, "string")!=0) { + return E_INVALID_PARAMETER_TYPE; + } + + var.v = (void*)value; + msg->args[i] = msg->mtype->types[i]->copy(var); + + return E_OK; + } + return E_INVALID_MESSAGE; +} + +int +msg_set_int(lua_message * msg, const char * param, int value) +{ + if (msg->mtype) { + int i = mtype_get_param(msg->mtype, param); + if (i==msg->mtype->nparameters) { + return E_INVALID_PARAMETER_NAME; + } + if (strcmp(msg->mtype->types[i]->name, "int")!=0) { + return E_INVALID_PARAMETER_TYPE; + } + + msg->args[i].i = value; + + return E_OK; + } + return E_INVALID_MESSAGE; +} + +int +msg_send_faction(lua_message * msg, faction * f) +{ + assert(f); + assert(msg); + + if (msg->mtype) { + if (msg->msg==NULL) { + msg->msg = msg_create(msg->mtype, msg->args); + } + add_message(&f->msgs, msg->msg); + return E_OK; + } + return E_INVALID_MESSAGE; +} + +int +msg_send_region(lua_message * lmsg, region * r) +{ + if (lmsg->mtype) { + if (lmsg->msg==NULL) { + lmsg->msg = msg_create(lmsg->mtype, lmsg->args); + } + add_message(&r->msgs, lmsg->msg); + return E_OK; + } + return E_INVALID_MESSAGE; +} + + +static int +tolua_msg_create(lua_State * L) +{ + const char * type = tolua_tostring(L, 1, 0); + lua_message * lmsg = msg_create_message(type); + tolua_pushusertype(L, (void*)lmsg, TOLUA_CAST "message"); + return 1; +} +static int +tolua_msg_set_string(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + const char * param = tolua_tostring(L, 2, 0); + const char * value = tolua_tostring(L, 3, 0); + int result = msg_set_string(lmsg, param, value); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_msg_set_int(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + const char * param = tolua_tostring(L, 2, 0); + int value = (int)tolua_tonumber(L, 3, 0); + int result = msg_set_int(lmsg, param, value); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_msg_set_resource(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + const char * param = tolua_tostring(L, 2, 0); + const char * value = tolua_tostring(L, 3, 0); + int result = msg_set_resource(lmsg, param, value); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_msg_set_unit(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + const char * param = tolua_tostring(L, 2, 0); + unit * value = (unit *)tolua_tousertype(L, 3, 0); + int result = msg_set_unit(lmsg, param, value); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_msg_set_region(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + const char * param = tolua_tostring(L, 2, 0); + region * value = (region *)tolua_tousertype(L, 3, 0); + int result = msg_set_region(lmsg, param, value); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_msg_set(lua_State * L) +{ + tolua_Error err; + if (tolua_isnumber(L, 3, 0, &err)) { + return tolua_msg_set_int(L); + } else if (tolua_isusertype(L, 3, TOLUA_CAST "region", 0, &err)) { + return tolua_msg_set_region(L); + } else if (tolua_isusertype(L, 3, TOLUA_CAST "unit", 0, &err)) { + return tolua_msg_set_unit(L); + } + tolua_pushnumber(L, (lua_Number)-1); + return 1; +} + +static int +tolua_msg_send_region(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + region * r = (region *)tolua_tousertype(L, 2, 0); + int result = msg_send_region(lmsg, r); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_msg_report_action(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + region * r = (region *)tolua_tousertype(L, 2, 0); + unit * u = (unit *)tolua_tousertype(L, 3, 0); + int result, flags = (int)tolua_tonumber(L, 4, 0); + if (lmsg->msg==NULL) { + lmsg->msg = msg_create(lmsg->mtype, lmsg->args); + } + result = report_action(r, u, lmsg->msg, flags); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_msg_send_faction(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + faction * f = (faction *)tolua_tousertype(L, 2, 0); + if (f && lmsg) { + int result = msg_send_faction(lmsg, f); + tolua_pushnumber(L, (lua_Number)result); + return 1; + } + return 0; +} + +void +tolua_message_open(lua_State* L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "message"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_function(L, TOLUA_CAST "message", tolua_msg_create); + + tolua_cclass(L, TOLUA_CAST "message", TOLUA_CAST "message", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "message"); + { + tolua_function(L, TOLUA_CAST "set", tolua_msg_set); + tolua_function(L, TOLUA_CAST "set_unit", tolua_msg_set_unit); + tolua_function(L, TOLUA_CAST "set_region", tolua_msg_set_region); + tolua_function(L, TOLUA_CAST "set_resource", tolua_msg_set_resource); + tolua_function(L, TOLUA_CAST "set_int", tolua_msg_set_int); + tolua_function(L, TOLUA_CAST "set_string", tolua_msg_set_string); + tolua_function(L, TOLUA_CAST "send_faction", tolua_msg_send_faction); + tolua_function(L, TOLUA_CAST "send_region", tolua_msg_send_region); + tolua_function(L, TOLUA_CAST "report_action", tolua_msg_report_action); + + tolua_function(L, TOLUA_CAST "create", tolua_msg_create); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_message.h b/src/bindings/bind_message.h index ed9aab133..fa39bbe4f 100644 --- a/src/bindings/bind_message.h +++ b/src/bindings/bind_message.h @@ -1,22 +1,22 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - void tolua_message_open(struct lua_State *L); - -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + void tolua_message_open(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_region.c b/src/bindings/bind_region.c index 19ec1dedb..c80f8e0d7 100644 --- a/src/bindings/bind_region.c +++ b/src/bindings/bind_region.c @@ -1,696 +1,696 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include "bind_region.h" -#include "bind_unit.h" -#include "bind_ship.h" -#include "bind_building.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include - -int tolua_regionlist_next(lua_State *L) -{ - region** region_ptr = (region **)lua_touserdata(L, lua_upvalueindex(1)); - region * r = *region_ptr; - if (r != NULL) { - tolua_pushusertype(L, (void*)r, TOLUA_CAST "region"); - *region_ptr = r->next; - return 1; - } - else return 0; /* no more values to return */ -} - -static int -tolua_region_get_id(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->uid); - return 1; -} - -static int -tolua_region_get_x(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->x); - return 1; -} - -static int -tolua_region_get_y(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->y); - return 1; -} - -static int -tolua_region_get_plane(lua_State* L) -{ - region * r = (region *)tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, rplane(r), TOLUA_CAST "plane"); - return 1; -} - -static int -tolua_region_get_terrain(lua_State* L) -{ - region* self = (region*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->terrain->_name); - return 1; -} - -static int -tolua_region_set_terrain(lua_State* L) -{ - region* r = (region*) tolua_tousertype(L, 1, 0); - const char * tname = tolua_tostring(L, 2, 0); - if (tname) { - const terrain_type * terrain = get_terrain(tname); - if (terrain) { - terraform_region(r, terrain); - } - } - return 0; -} - -static int -tolua_region_get_terrainname(lua_State* L) -{ - region* self = (region*) tolua_tousertype(L, 1, 0); - attrib * a = a_find(self->attribs, &at_racename); - if (a) { - tolua_pushstring(L, get_racename(a)); - return 1; - } - return 0; -} - -static int -tolua_region_set_owner(lua_State* L) -{ - region* r = (region*) tolua_tousertype(L, 1, 0); - struct faction* f = (struct faction*) tolua_tousertype(L, 2, 0); - if (r) { - region_set_owner(r, f, turn); - } - return 0; -} - -static int -tolua_region_get_owner(lua_State* L) -{ - region* r = (region*) tolua_tousertype(L, 1, 0); - if (r) { - struct faction * f = region_get_owner(r); - tolua_pushusertype(L, f, TOLUA_CAST "faction"); - return 1; - } - return 0; -} - -static int -tolua_region_set_terrainname(lua_State* L) -{ - region* self = (region*) tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - if (name==NULL) { - a_removeall(&self->attribs, &at_racename); - } else { - set_racename(&self->attribs, name); - } - return 0; -} - -static int tolua_region_get_info(lua_State* L) -{ - region* self = (region*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, region_getinfo(self)); - return 1; -} - -static int tolua_region_set_info(lua_State* L) -{ - region* self = (region*)tolua_tousertype(L, 1, 0); - region_setinfo(self, tolua_tostring(L, 2, 0)); - return 0; -} - - -static int tolua_region_get_name(lua_State* L) -{ - region* self = (region*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, region_getname(self)); - return 1; -} - -static int tolua_region_set_name(lua_State* L) -{ - region* self = (region*)tolua_tousertype(L, 1, 0); - region_setname(self, tolua_tostring(L, 2, 0)); - return 0; -} - - -static int tolua_region_get_morale(lua_State* L) -{ - region* r = (region*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, region_get_morale(r)); - return 1; -} - -static int tolua_region_set_morale(lua_State* L) -{ - region* r = (region*)tolua_tousertype(L, 1, 0); - region_set_morale(r, (int)tolua_tonumber(L, 2, 0), turn); - return 0; -} - -static int tolua_region_get_flag(lua_State* L) -{ - region* self = (region*)tolua_tousertype(L, 1, 0); - int bit = (int)tolua_tonumber(L, 2, 0); - - lua_pushboolean(L, (self->flags & (1<land) { - const item_type * lux = r_luxury(r); - if (lux) { - const char * name = lux->rtype->_name[0]; - tolua_pushstring(L, name); - return 1; - } - } - return 0; -} - -static int tolua_region_set_luxury(lua_State* L) -{ - region* r = (region*)tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - if (r->land && name) { - const item_type * lux = r_luxury(r); - const item_type * itype = it_find(name); - if (lux && itype && lux!=itype) { - r_setdemand(r, lux->rtype->ltype, 1); - r_setdemand(r, itype->rtype->ltype, 0); - } - } - return 0; -} - -static int tolua_region_set_herb(lua_State* L) -{ - region* r = (region*)tolua_tousertype(L, 1, 0); - if (r->land) { - const char * name = tolua_tostring(L, 2, 0); - const item_type * itype = it_find(name); - if (itype && (itype->flags&ITF_HERB)) { - r->land->herbtype = itype; - } - } - return 0; -} - -static int tolua_region_get_herb(lua_State* L) -{ - region* r = (region*)tolua_tousertype(L, 1, 0); - if (r->land && r->land->herbtype) { - const char * name = r->land->herbtype->rtype->_name[0]; - tolua_pushstring(L, name); - return 1; - } - return 0; -} - -static int tolua_region_get_next(lua_State* L) -{ - region* self = (region*)tolua_tousertype(L, 1, 0); - direction_t dir = (direction_t)tolua_tonumber(L, 2, 0); - - if (dir>=0 && dirflags |= (1<flags &= ~(1<resources;rm;rm=rm->next) { - if (rm->type->rtype==rtype) { - tolua_pushnumber(L, (lua_Number)rm->level); - return 1; - } - } - } - return 0; -} - -#define LUA_ASSERT(c, s) if (!(c)) { log_error(("%s(%d): %s\n", __FILE__, __LINE__, (s))); return 0; } -static int -tolua_region_get_resource(lua_State* L) -{ - region * r; - const char * type; - const resource_type * rtype; - int result = 0; - - r = (region *)tolua_tousertype(L, 1, 0); - LUA_ASSERT(r!=NULL, "invalid parameter"); - type = tolua_tostring(L, 2, 0); - LUA_ASSERT(type!=NULL, "invalid parameter"); - rtype = rt_find(type); - - if (!rtype) { - if (strcmp(type, "seed")==0) result = rtrees(r, 0); - if (strcmp(type, "sapling")==0) result = rtrees(r, 1); - if (strcmp(type, "tree")==0) result = rtrees(r, 2); - if (strcmp(type, "grave")==0) result = deathcount(r); - if (strcmp(type, "chaos")==0) result = chaoscount(r); - } else { - result = region_getresource(r, rtype); - } - - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_region_set_resource(lua_State* L) -{ - region * r = (region *)tolua_tousertype(L, 1, 0); - const char * type = tolua_tostring(L, 2, 0); - int value = (int)tolua_tonumber(L, 3, 0); - const resource_type * rtype = rt_find(type); - - if (rtype!=NULL) { - region_setresource(r, rtype, value); - } else { - if (strcmp(type, "seed")==0) { - rsettrees(r, 0, value); - } else if (strcmp(type, "sapling")==0) { - rsettrees(r, 1, value); - } else if (strcmp(type, "tree")==0) { - rsettrees(r, 2, value); - } else if (strcmp(type, "grave")==0) { - int fallen = value-deathcount(r); - deathcounts(r, fallen); - } else if (strcmp(type, "chaos")==0) { - int fallen = value-chaoscount(r); - chaoscounts(r, fallen); - } - } - return 0; -} - -static int -tolua_region_get_objects(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); - return 1; -} - -static int -tolua_region_destroy(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - remove_region(®ions, self); - return 0; -} - -static int -tolua_region_create(lua_State* L) -{ - int x = (int)tolua_tonumber(L, 1, 0); - int y = (int)tolua_tonumber(L, 2, 0); - const char * tname = tolua_tostring(L, 3, 0); - if (tname) { - plane * pl = findplane(x, y); - const terrain_type * terrain = get_terrain(tname); - region * r, * result; - if (!terrain) { - return 0; - } - - assert(!pnormalize(&x, &y, pl)); - r = result = findregion(x, y); - - if (terrain==NULL && r!=NULL && r->units!=NULL) { - /* TODO: error message */ - result = NULL; - } else if (r==NULL) { - result = new_region(x, y, pl, 0); - } - if (result) { - terraform_region(result, terrain); - } - fix_demand(result); - - tolua_pushusertype(L, result, TOLUA_CAST "region"); - return 1; - } - return 0; -} - -static int tolua_region_get_units(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); - - luaL_getmetatable(L, "unit"); - lua_setmetatable(L, -2); - - *unit_ptr = self->units; - - lua_pushcclosure(L, tolua_unitlist_next, 1); - return 1; -} - -static int tolua_region_get_buildings(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - building ** building_ptr = (building**)lua_newuserdata(L, sizeof(building *)); - - luaL_getmetatable(L, "building"); - lua_setmetatable(L, -2); - - *building_ptr = self->buildings; - - lua_pushcclosure(L, tolua_buildinglist_next, 1); - return 1; -} - -static int tolua_region_get_ships(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - ship ** ship_ptr = (ship**)lua_newuserdata(L, sizeof(ship *)); - - luaL_getmetatable(L, "ship"); - lua_setmetatable(L, -2); - - *ship_ptr = self->ships; - - lua_pushcclosure(L, tolua_shiplist_next, 1); - return 1; -} - -static int tolua_region_get_age(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - - if (self) { - lua_pushnumber(L, self->age); - return 1; - } - return 0; -} - -static int -tolua_region_getkey(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - - int flag = atoi36(name); - attrib * a = find_key(self->attribs, flag); - lua_pushboolean(L, a!=NULL); - - return 1; -} - -static int -tolua_region_setkey(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - int value = tolua_toboolean(L, 3, 0); - - int flag = atoi36(name); - attrib * a = find_key(self->attribs, flag); - if (a==NULL && value) { - add_key(&self->attribs, flag); - } else if (a!=NULL && !value) { - a_remove(&self->attribs, a); - } - return 0; -} - -static int -tolua_region_tostring(lua_State *L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - lua_pushstring(L, regionname(self, NULL)); - return 1; -} - -static int -tolua_plane_get(lua_State* L) -{ - int id = (int)tolua_tonumber(L, 1, 0); - plane * pl = getplanebyid(id); - - tolua_pushusertype(L, pl, TOLUA_CAST "plane"); - return 1; -} - -static int -tolua_plane_create(lua_State* L) -{ - int id = (int)tolua_tonumber(L, 1, 0); - int x = (int)tolua_tonumber(L, 2, 0); - int y = (int)tolua_tonumber(L, 3, 0); - int width = (int)tolua_tonumber(L, 4, 0); - int height = (int)tolua_tonumber(L, 5, 0); - const char * name = tolua_tostring(L, 6, 0); - plane * pl; - - pl = create_new_plane(id, name, x, x+width-1, y, y+height-1, 0); - - tolua_pushusertype(L, pl, TOLUA_CAST "plane"); - return 1; -} - -static int tolua_plane_get_name(lua_State* L) -{ - plane* self = (plane*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->name); - return 1; -} - -static int tolua_plane_set_name(lua_State* L) -{ - plane* self = (plane*)tolua_tousertype(L, 1, 0); - const char * str = tolua_tostring(L, 2, 0); - free(self->name); - if (str) self->name = strdup(str); - else self->name = 0; - return 0; -} - -static int -tolua_plane_get_id(lua_State* L) -{ - plane * self = (plane *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->id); - return 1; -} - -static int -tolua_plane_normalize(lua_State* L) -{ - plane * self = (plane *)tolua_tousertype(L, 1, 0); - int x = (int)tolua_tonumber(L, 2, 0); - int y = (int)tolua_tonumber(L, 3, 0); - pnormalize(&x, &y, self); - tolua_pushnumber(L, (lua_Number)x); - tolua_pushnumber(L, (lua_Number)y); - return 2; -} - -static int -tolua_plane_tostring(lua_State *L) -{ - plane * self = (plane *)tolua_tousertype(L, 1, 0); - lua_pushstring(L, self->name); - return 1; -} - -static int -tolua_plane_get_size(lua_State *L) -{ - plane * pl = (plane *)tolua_tousertype(L, 1, 0); - lua_pushnumber(L, plane_width(pl)); - lua_pushnumber(L, plane_height(pl)); - return 2; -} - -static int -tolua_distance(lua_State *L) -{ - int x1 = (int)tolua_tonumber(L, 1, 0); - int y1 = (int)tolua_tonumber(L, 2, 0); - int x2 = (int)tolua_tonumber(L, 3, 0); - int y2 = (int)tolua_tonumber(L, 4, 0); - plane * pl = (plane *)tolua_tousertype(L, 5, 0); - int result; - - if (!pl) pl = get_homeplane(); - pnormalize(&x1, &y1, pl); - pnormalize(&x2, &y2, pl); - result = koor_distance(x1, y1, x2, y2); - lua_pushnumber(L, result); - return 1; -} - -void -tolua_region_open(lua_State* L) -{ - /* register user types */ - tolua_usertype(L, TOLUA_CAST "region"); - tolua_usertype(L, TOLUA_CAST "plane"); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_function(L, TOLUA_CAST "distance", tolua_distance); - - tolua_cclass(L, TOLUA_CAST "region", TOLUA_CAST "region", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "region"); - { - tolua_function(L, TOLUA_CAST "create", tolua_region_create); - tolua_function(L, TOLUA_CAST "destroy", tolua_region_destroy); - tolua_function(L, TOLUA_CAST "__tostring", tolua_region_tostring); - - tolua_variable(L, TOLUA_CAST "id", tolua_region_get_id, NULL); - tolua_variable(L, TOLUA_CAST "x", tolua_region_get_x, NULL); - tolua_variable(L, TOLUA_CAST "y", tolua_region_get_y, NULL); - tolua_variable(L, TOLUA_CAST "plane", tolua_region_get_plane, NULL); - tolua_variable(L, TOLUA_CAST "name", tolua_region_get_name, tolua_region_set_name); - tolua_variable(L, TOLUA_CAST "morale", tolua_region_get_morale, tolua_region_set_morale); - tolua_variable(L, TOLUA_CAST "info", tolua_region_get_info, tolua_region_set_info); - tolua_variable(L, TOLUA_CAST "units", tolua_region_get_units, NULL); - tolua_variable(L, TOLUA_CAST "ships", tolua_region_get_ships, NULL); - tolua_variable(L, TOLUA_CAST "age", tolua_region_get_age, NULL); - tolua_variable(L, TOLUA_CAST "buildings", tolua_region_get_buildings, NULL); - tolua_variable(L, TOLUA_CAST "terrain", tolua_region_get_terrain, tolua_region_set_terrain); - tolua_function(L, TOLUA_CAST "get_resourcelevel", tolua_region_get_resourcelevel); - tolua_function(L, TOLUA_CAST "get_resource", tolua_region_get_resource); - tolua_function(L, TOLUA_CAST "set_resource", tolua_region_set_resource); - tolua_function(L, TOLUA_CAST "get_flag", tolua_region_get_flag); - tolua_function(L, TOLUA_CAST "set_flag", tolua_region_set_flag); - tolua_function(L, TOLUA_CAST "next", tolua_region_get_next); - tolua_variable(L, TOLUA_CAST "adj", tolua_region_get_adj, NULL); - - tolua_variable(L, TOLUA_CAST "luxury", &tolua_region_get_luxury, &tolua_region_set_luxury); - tolua_variable(L, TOLUA_CAST "herb", &tolua_region_get_herb, &tolua_region_set_herb); - - tolua_variable(L, TOLUA_CAST "terrain_name", &tolua_region_get_terrainname, &tolua_region_set_terrainname); - tolua_variable(L, TOLUA_CAST "owner", &tolua_region_get_owner, &tolua_region_set_owner); - - tolua_function(L, TOLUA_CAST "get_key", tolua_region_getkey); - tolua_function(L, TOLUA_CAST "set_key", tolua_region_setkey); -#if 0 - .def("add_notice", ®ion_addnotice) - .def("add_direction", ®ion_adddirection) - .def("move", ®ion_move) - .def("get_road", ®ion_getroad) - .def("set_road", ®ion_setroad) - .def("next", ®ion_next) - .def("add_item", ®ion_additem) - .property("items", ®ion_items, return_stl_iterator) - .property("plane_id", ®ion_plane) -#endif - tolua_variable(L, TOLUA_CAST "objects", tolua_region_get_objects, 0); - } - tolua_endmodule(L); - - tolua_cclass(L, TOLUA_CAST "plane", TOLUA_CAST "plane", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "plane"); - { - tolua_function(L, TOLUA_CAST "create", tolua_plane_create); - tolua_function(L, TOLUA_CAST "get", tolua_plane_get); - tolua_function(L, TOLUA_CAST "__tostring", tolua_plane_tostring); - - tolua_function(L, TOLUA_CAST "size", tolua_plane_get_size); - tolua_variable(L, TOLUA_CAST "id", tolua_plane_get_id, NULL); - tolua_function(L, TOLUA_CAST "normalize", tolua_plane_normalize); - tolua_variable(L, TOLUA_CAST "name", tolua_plane_get_name, tolua_plane_set_name); - } - tolua_endmodule(L); - } - tolua_endmodule(L); -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bind_region.h" +#include "bind_unit.h" +#include "bind_ship.h" +#include "bind_building.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +int tolua_regionlist_next(lua_State *L) +{ + region** region_ptr = (region **)lua_touserdata(L, lua_upvalueindex(1)); + region * r = *region_ptr; + if (r != NULL) { + tolua_pushusertype(L, (void*)r, TOLUA_CAST "region"); + *region_ptr = r->next; + return 1; + } + else return 0; /* no more values to return */ +} + +static int +tolua_region_get_id(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->uid); + return 1; +} + +static int +tolua_region_get_x(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->x); + return 1; +} + +static int +tolua_region_get_y(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->y); + return 1; +} + +static int +tolua_region_get_plane(lua_State* L) +{ + region * r = (region *)tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, rplane(r), TOLUA_CAST "plane"); + return 1; +} + +static int +tolua_region_get_terrain(lua_State* L) +{ + region* self = (region*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->terrain->_name); + return 1; +} + +static int +tolua_region_set_terrain(lua_State* L) +{ + region* r = (region*) tolua_tousertype(L, 1, 0); + const char * tname = tolua_tostring(L, 2, 0); + if (tname) { + const terrain_type * terrain = get_terrain(tname); + if (terrain) { + terraform_region(r, terrain); + } + } + return 0; +} + +static int +tolua_region_get_terrainname(lua_State* L) +{ + region* self = (region*) tolua_tousertype(L, 1, 0); + attrib * a = a_find(self->attribs, &at_racename); + if (a) { + tolua_pushstring(L, get_racename(a)); + return 1; + } + return 0; +} + +static int +tolua_region_set_owner(lua_State* L) +{ + region* r = (region*) tolua_tousertype(L, 1, 0); + struct faction* f = (struct faction*) tolua_tousertype(L, 2, 0); + if (r) { + region_set_owner(r, f, turn); + } + return 0; +} + +static int +tolua_region_get_owner(lua_State* L) +{ + region* r = (region*) tolua_tousertype(L, 1, 0); + if (r) { + struct faction * f = region_get_owner(r); + tolua_pushusertype(L, f, TOLUA_CAST "faction"); + return 1; + } + return 0; +} + +static int +tolua_region_set_terrainname(lua_State* L) +{ + region* self = (region*) tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + if (name==NULL) { + a_removeall(&self->attribs, &at_racename); + } else { + set_racename(&self->attribs, name); + } + return 0; +} + +static int tolua_region_get_info(lua_State* L) +{ + region* self = (region*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, region_getinfo(self)); + return 1; +} + +static int tolua_region_set_info(lua_State* L) +{ + region* self = (region*)tolua_tousertype(L, 1, 0); + region_setinfo(self, tolua_tostring(L, 2, 0)); + return 0; +} + + +static int tolua_region_get_name(lua_State* L) +{ + region* self = (region*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, region_getname(self)); + return 1; +} + +static int tolua_region_set_name(lua_State* L) +{ + region* self = (region*)tolua_tousertype(L, 1, 0); + region_setname(self, tolua_tostring(L, 2, 0)); + return 0; +} + + +static int tolua_region_get_morale(lua_State* L) +{ + region* r = (region*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, region_get_morale(r)); + return 1; +} + +static int tolua_region_set_morale(lua_State* L) +{ + region* r = (region*)tolua_tousertype(L, 1, 0); + region_set_morale(r, (int)tolua_tonumber(L, 2, 0), turn); + return 0; +} + +static int tolua_region_get_flag(lua_State* L) +{ + region* self = (region*)tolua_tousertype(L, 1, 0); + int bit = (int)tolua_tonumber(L, 2, 0); + + lua_pushboolean(L, (self->flags & (1<land) { + const item_type * lux = r_luxury(r); + if (lux) { + const char * name = lux->rtype->_name[0]; + tolua_pushstring(L, name); + return 1; + } + } + return 0; +} + +static int tolua_region_set_luxury(lua_State* L) +{ + region* r = (region*)tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + if (r->land && name) { + const item_type * lux = r_luxury(r); + const item_type * itype = it_find(name); + if (lux && itype && lux!=itype) { + r_setdemand(r, lux->rtype->ltype, 1); + r_setdemand(r, itype->rtype->ltype, 0); + } + } + return 0; +} + +static int tolua_region_set_herb(lua_State* L) +{ + region* r = (region*)tolua_tousertype(L, 1, 0); + if (r->land) { + const char * name = tolua_tostring(L, 2, 0); + const item_type * itype = it_find(name); + if (itype && (itype->flags&ITF_HERB)) { + r->land->herbtype = itype; + } + } + return 0; +} + +static int tolua_region_get_herb(lua_State* L) +{ + region* r = (region*)tolua_tousertype(L, 1, 0); + if (r->land && r->land->herbtype) { + const char * name = r->land->herbtype->rtype->_name[0]; + tolua_pushstring(L, name); + return 1; + } + return 0; +} + +static int tolua_region_get_next(lua_State* L) +{ + region* self = (region*)tolua_tousertype(L, 1, 0); + direction_t dir = (direction_t)tolua_tonumber(L, 2, 0); + + if (dir>=0 && dirflags |= (1<flags &= ~(1<resources;rm;rm=rm->next) { + if (rm->type->rtype==rtype) { + tolua_pushnumber(L, (lua_Number)rm->level); + return 1; + } + } + } + return 0; +} + +#define LUA_ASSERT(c, s) if (!(c)) { log_error(("%s(%d): %s\n", __FILE__, __LINE__, (s))); return 0; } +static int +tolua_region_get_resource(lua_State* L) +{ + region * r; + const char * type; + const resource_type * rtype; + int result = 0; + + r = (region *)tolua_tousertype(L, 1, 0); + LUA_ASSERT(r!=NULL, "invalid parameter"); + type = tolua_tostring(L, 2, 0); + LUA_ASSERT(type!=NULL, "invalid parameter"); + rtype = rt_find(type); + + if (!rtype) { + if (strcmp(type, "seed")==0) result = rtrees(r, 0); + if (strcmp(type, "sapling")==0) result = rtrees(r, 1); + if (strcmp(type, "tree")==0) result = rtrees(r, 2); + if (strcmp(type, "grave")==0) result = deathcount(r); + if (strcmp(type, "chaos")==0) result = chaoscount(r); + } else { + result = region_getresource(r, rtype); + } + + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_region_set_resource(lua_State* L) +{ + region * r = (region *)tolua_tousertype(L, 1, 0); + const char * type = tolua_tostring(L, 2, 0); + int value = (int)tolua_tonumber(L, 3, 0); + const resource_type * rtype = rt_find(type); + + if (rtype!=NULL) { + region_setresource(r, rtype, value); + } else { + if (strcmp(type, "seed")==0) { + rsettrees(r, 0, value); + } else if (strcmp(type, "sapling")==0) { + rsettrees(r, 1, value); + } else if (strcmp(type, "tree")==0) { + rsettrees(r, 2, value); + } else if (strcmp(type, "grave")==0) { + int fallen = value-deathcount(r); + deathcounts(r, fallen); + } else if (strcmp(type, "chaos")==0) { + int fallen = value-chaoscount(r); + chaoscounts(r, fallen); + } + } + return 0; +} + +static int +tolua_region_get_objects(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); + return 1; +} + +static int +tolua_region_destroy(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + remove_region(®ions, self); + return 0; +} + +static int +tolua_region_create(lua_State* L) +{ + int x = (int)tolua_tonumber(L, 1, 0); + int y = (int)tolua_tonumber(L, 2, 0); + const char * tname = tolua_tostring(L, 3, 0); + if (tname) { + plane * pl = findplane(x, y); + const terrain_type * terrain = get_terrain(tname); + region * r, * result; + if (!terrain) { + return 0; + } + + assert(!pnormalize(&x, &y, pl)); + r = result = findregion(x, y); + + if (terrain==NULL && r!=NULL && r->units!=NULL) { + /* TODO: error message */ + result = NULL; + } else if (r==NULL) { + result = new_region(x, y, pl, 0); + } + if (result) { + terraform_region(result, terrain); + } + fix_demand(result); + + tolua_pushusertype(L, result, TOLUA_CAST "region"); + return 1; + } + return 0; +} + +static int tolua_region_get_units(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); + + luaL_getmetatable(L, "unit"); + lua_setmetatable(L, -2); + + *unit_ptr = self->units; + + lua_pushcclosure(L, tolua_unitlist_next, 1); + return 1; +} + +static int tolua_region_get_buildings(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + building ** building_ptr = (building**)lua_newuserdata(L, sizeof(building *)); + + luaL_getmetatable(L, "building"); + lua_setmetatable(L, -2); + + *building_ptr = self->buildings; + + lua_pushcclosure(L, tolua_buildinglist_next, 1); + return 1; +} + +static int tolua_region_get_ships(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + ship ** ship_ptr = (ship**)lua_newuserdata(L, sizeof(ship *)); + + luaL_getmetatable(L, "ship"); + lua_setmetatable(L, -2); + + *ship_ptr = self->ships; + + lua_pushcclosure(L, tolua_shiplist_next, 1); + return 1; +} + +static int tolua_region_get_age(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + + if (self) { + lua_pushnumber(L, self->age); + return 1; + } + return 0; +} + +static int +tolua_region_getkey(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + + int flag = atoi36(name); + attrib * a = find_key(self->attribs, flag); + lua_pushboolean(L, a!=NULL); + + return 1; +} + +static int +tolua_region_setkey(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + int value = tolua_toboolean(L, 3, 0); + + int flag = atoi36(name); + attrib * a = find_key(self->attribs, flag); + if (a==NULL && value) { + add_key(&self->attribs, flag); + } else if (a!=NULL && !value) { + a_remove(&self->attribs, a); + } + return 0; +} + +static int +tolua_region_tostring(lua_State *L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, regionname(self, NULL)); + return 1; +} + +static int +tolua_plane_get(lua_State* L) +{ + int id = (int)tolua_tonumber(L, 1, 0); + plane * pl = getplanebyid(id); + + tolua_pushusertype(L, pl, TOLUA_CAST "plane"); + return 1; +} + +static int +tolua_plane_create(lua_State* L) +{ + int id = (int)tolua_tonumber(L, 1, 0); + int x = (int)tolua_tonumber(L, 2, 0); + int y = (int)tolua_tonumber(L, 3, 0); + int width = (int)tolua_tonumber(L, 4, 0); + int height = (int)tolua_tonumber(L, 5, 0); + const char * name = tolua_tostring(L, 6, 0); + plane * pl; + + pl = create_new_plane(id, name, x, x+width-1, y, y+height-1, 0); + + tolua_pushusertype(L, pl, TOLUA_CAST "plane"); + return 1; +} + +static int tolua_plane_get_name(lua_State* L) +{ + plane* self = (plane*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->name); + return 1; +} + +static int tolua_plane_set_name(lua_State* L) +{ + plane* self = (plane*)tolua_tousertype(L, 1, 0); + const char * str = tolua_tostring(L, 2, 0); + free(self->name); + if (str) self->name = strdup(str); + else self->name = 0; + return 0; +} + +static int +tolua_plane_get_id(lua_State* L) +{ + plane * self = (plane *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->id); + return 1; +} + +static int +tolua_plane_normalize(lua_State* L) +{ + plane * self = (plane *)tolua_tousertype(L, 1, 0); + int x = (int)tolua_tonumber(L, 2, 0); + int y = (int)tolua_tonumber(L, 3, 0); + pnormalize(&x, &y, self); + tolua_pushnumber(L, (lua_Number)x); + tolua_pushnumber(L, (lua_Number)y); + return 2; +} + +static int +tolua_plane_tostring(lua_State *L) +{ + plane * self = (plane *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, self->name); + return 1; +} + +static int +tolua_plane_get_size(lua_State *L) +{ + plane * pl = (plane *)tolua_tousertype(L, 1, 0); + lua_pushnumber(L, plane_width(pl)); + lua_pushnumber(L, plane_height(pl)); + return 2; +} + +static int +tolua_distance(lua_State *L) +{ + int x1 = (int)tolua_tonumber(L, 1, 0); + int y1 = (int)tolua_tonumber(L, 2, 0); + int x2 = (int)tolua_tonumber(L, 3, 0); + int y2 = (int)tolua_tonumber(L, 4, 0); + plane * pl = (plane *)tolua_tousertype(L, 5, 0); + int result; + + if (!pl) pl = get_homeplane(); + pnormalize(&x1, &y1, pl); + pnormalize(&x2, &y2, pl); + result = koor_distance(x1, y1, x2, y2); + lua_pushnumber(L, result); + return 1; +} + +void +tolua_region_open(lua_State* L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "region"); + tolua_usertype(L, TOLUA_CAST "plane"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_function(L, TOLUA_CAST "distance", tolua_distance); + + tolua_cclass(L, TOLUA_CAST "region", TOLUA_CAST "region", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "region"); + { + tolua_function(L, TOLUA_CAST "create", tolua_region_create); + tolua_function(L, TOLUA_CAST "destroy", tolua_region_destroy); + tolua_function(L, TOLUA_CAST "__tostring", tolua_region_tostring); + + tolua_variable(L, TOLUA_CAST "id", tolua_region_get_id, NULL); + tolua_variable(L, TOLUA_CAST "x", tolua_region_get_x, NULL); + tolua_variable(L, TOLUA_CAST "y", tolua_region_get_y, NULL); + tolua_variable(L, TOLUA_CAST "plane", tolua_region_get_plane, NULL); + tolua_variable(L, TOLUA_CAST "name", tolua_region_get_name, tolua_region_set_name); + tolua_variable(L, TOLUA_CAST "morale", tolua_region_get_morale, tolua_region_set_morale); + tolua_variable(L, TOLUA_CAST "info", tolua_region_get_info, tolua_region_set_info); + tolua_variable(L, TOLUA_CAST "units", tolua_region_get_units, NULL); + tolua_variable(L, TOLUA_CAST "ships", tolua_region_get_ships, NULL); + tolua_variable(L, TOLUA_CAST "age", tolua_region_get_age, NULL); + tolua_variable(L, TOLUA_CAST "buildings", tolua_region_get_buildings, NULL); + tolua_variable(L, TOLUA_CAST "terrain", tolua_region_get_terrain, tolua_region_set_terrain); + tolua_function(L, TOLUA_CAST "get_resourcelevel", tolua_region_get_resourcelevel); + tolua_function(L, TOLUA_CAST "get_resource", tolua_region_get_resource); + tolua_function(L, TOLUA_CAST "set_resource", tolua_region_set_resource); + tolua_function(L, TOLUA_CAST "get_flag", tolua_region_get_flag); + tolua_function(L, TOLUA_CAST "set_flag", tolua_region_set_flag); + tolua_function(L, TOLUA_CAST "next", tolua_region_get_next); + tolua_variable(L, TOLUA_CAST "adj", tolua_region_get_adj, NULL); + + tolua_variable(L, TOLUA_CAST "luxury", &tolua_region_get_luxury, &tolua_region_set_luxury); + tolua_variable(L, TOLUA_CAST "herb", &tolua_region_get_herb, &tolua_region_set_herb); + + tolua_variable(L, TOLUA_CAST "terrain_name", &tolua_region_get_terrainname, &tolua_region_set_terrainname); + tolua_variable(L, TOLUA_CAST "owner", &tolua_region_get_owner, &tolua_region_set_owner); + + tolua_function(L, TOLUA_CAST "get_key", tolua_region_getkey); + tolua_function(L, TOLUA_CAST "set_key", tolua_region_setkey); +#if 0 + .def("add_notice", ®ion_addnotice) + .def("add_direction", ®ion_adddirection) + .def("move", ®ion_move) + .def("get_road", ®ion_getroad) + .def("set_road", ®ion_setroad) + .def("next", ®ion_next) + .def("add_item", ®ion_additem) + .property("items", ®ion_items, return_stl_iterator) + .property("plane_id", ®ion_plane) +#endif + tolua_variable(L, TOLUA_CAST "objects", tolua_region_get_objects, 0); + } + tolua_endmodule(L); + + tolua_cclass(L, TOLUA_CAST "plane", TOLUA_CAST "plane", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "plane"); + { + tolua_function(L, TOLUA_CAST "create", tolua_plane_create); + tolua_function(L, TOLUA_CAST "get", tolua_plane_get); + tolua_function(L, TOLUA_CAST "__tostring", tolua_plane_tostring); + + tolua_function(L, TOLUA_CAST "size", tolua_plane_get_size); + tolua_variable(L, TOLUA_CAST "id", tolua_plane_get_id, NULL); + tolua_function(L, TOLUA_CAST "normalize", tolua_plane_normalize); + tolua_variable(L, TOLUA_CAST "name", tolua_plane_get_name, tolua_plane_set_name); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_region.h b/src/bindings/bind_region.h index f8d0c8e2a..002411e51 100644 --- a/src/bindings/bind_region.h +++ b/src/bindings/bind_region.h @@ -1,23 +1,23 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - void tolua_region_open(struct lua_State *L); - int tolua_regionlist_next(struct lua_State *L); - -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + void tolua_region_open(struct lua_State *L); + int tolua_regionlist_next(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_ship.c b/src/bindings/bind_ship.c index b5a0e90a3..053718091 100644 --- a/src/bindings/bind_ship.c +++ b/src/bindings/bind_ship.c @@ -1,182 +1,182 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include "bind_ship.h" -#include "bind_unit.h" - -#include -#include -#include -#include -#include - -#include - -#include -#include - -int tolua_shiplist_next(lua_State *L) -{ - ship** ship_ptr = (ship **)lua_touserdata(L, lua_upvalueindex(1)); - ship * u = *ship_ptr; - if (u != NULL) { - tolua_pushusertype(L, (void*)u, TOLUA_CAST "ship"); - *ship_ptr = u->next; - return 1; - } - else return 0; /* no more values to return */ -} - -static int -tolua_ship_get_id(lua_State* L) -{ - ship * self = (ship *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->no); - return 1; -} - -static int tolua_ship_get_name(lua_State* L) -{ - ship* self = (ship*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, ship_getname(self)); - return 1; -} - -static int tolua_ship_get_region(lua_State* L) -{ - ship* self = (ship*) tolua_tousertype(L, 1, 0); - if (self) { - tolua_pushusertype(L, self->region, TOLUA_CAST "region"); - return 1; - } - return 0; -} - -static int tolua_ship_set_region(lua_State* L) -{ - ship* self = (ship*) tolua_tousertype(L, 1, 0); - region * r = (region*) tolua_tousertype(L, 1, 0); - if (self) { - move_ship(self, self->region, r, NULL); - } - return 0; -} - -static int tolua_ship_set_name(lua_State* L) -{ - ship* self = (ship*)tolua_tousertype(L, 1, 0); - ship_setname(self, tolua_tostring(L, 2, 0)); - return 0; -} - -static int -tolua_ship_get_units(lua_State* L) -{ - ship * self = (ship *)tolua_tousertype(L, 1, 0); - unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); - unit * u = self->region->units; - - while (u && u->ship!=self) u = u->next; - luaL_getmetatable(L, TOLUA_CAST "unit"); - lua_setmetatable(L, -2); - - *unit_ptr = u; - - lua_pushcclosure(L, tolua_unitlist_nexts, 1); - return 1; -} - -static int -tolua_ship_get_objects(lua_State* L) -{ - ship * self = (ship *)tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); - return 1; -} - -static int -tolua_ship_create(lua_State* L) -{ - region * r = (region *)tolua_tousertype(L, 1, 0); - const char * sname = tolua_tostring(L, 2, 0); - if (sname) { - const ship_type * stype = st_find(sname); - if (stype) { - ship * sh = new_ship(stype, default_locale, r); - sh->size = stype->construction->maxsize; - tolua_pushusertype(L, (void*)sh, TOLUA_CAST "ship"); - return 1; - } - } - return 0; -} - -static int - -tolua_ship_tostring(lua_State *L) -{ - ship * self = (ship *)tolua_tousertype(L, 1, 0); - lua_pushstring(L, shipname(self)); - return 1; -} - -static int tolua_ship_get_flags(lua_State* L) -{ - ship* self = (ship*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->flags); - return 1; -} - -static int tolua_ship_set_flags(lua_State* L) -{ - ship* self = (ship*)tolua_tousertype(L, 1, 0); - self->flags = (int)tolua_tonumber(L, 2, 0); - return 0; -} - - -void -tolua_ship_open(lua_State* L) -{ - /* register user types */ - tolua_usertype(L, TOLUA_CAST "ship"); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_cclass(L, TOLUA_CAST "ship", TOLUA_CAST "ship", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "ship"); - { - tolua_function(L, TOLUA_CAST "__tostring", tolua_ship_tostring); - tolua_variable(L, TOLUA_CAST "id", tolua_ship_get_id, NULL); - tolua_variable(L, TOLUA_CAST "name", tolua_ship_get_name, tolua_ship_set_name); - tolua_variable(L, TOLUA_CAST "units", tolua_ship_get_units, NULL); - tolua_variable(L, TOLUA_CAST "flags", &tolua_ship_get_flags, tolua_ship_set_flags); - tolua_variable(L, TOLUA_CAST "region", tolua_ship_get_region, tolua_ship_set_region); -#ifdef TODO - .property("type", &ship_gettype) - .property("weight", &ship_getweight) - .property("capacity", &ship_getcapacity) - .property("maxsize", &ship_maxsize) - .def_readwrite("damage", &ship::damage) - .def_readwrite("size", &ship::size) - .def_readwrite("coast", &ship::coast) -#endif - tolua_variable(L, TOLUA_CAST "objects", tolua_ship_get_objects, 0); - - tolua_function(L, TOLUA_CAST "create", tolua_ship_create); - } - tolua_endmodule(L); - } - tolua_endmodule(L); -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bind_ship.h" +#include "bind_unit.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include + +int tolua_shiplist_next(lua_State *L) +{ + ship** ship_ptr = (ship **)lua_touserdata(L, lua_upvalueindex(1)); + ship * u = *ship_ptr; + if (u != NULL) { + tolua_pushusertype(L, (void*)u, TOLUA_CAST "ship"); + *ship_ptr = u->next; + return 1; + } + else return 0; /* no more values to return */ +} + +static int +tolua_ship_get_id(lua_State* L) +{ + ship * self = (ship *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->no); + return 1; +} + +static int tolua_ship_get_name(lua_State* L) +{ + ship* self = (ship*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, ship_getname(self)); + return 1; +} + +static int tolua_ship_get_region(lua_State* L) +{ + ship* self = (ship*) tolua_tousertype(L, 1, 0); + if (self) { + tolua_pushusertype(L, self->region, TOLUA_CAST "region"); + return 1; + } + return 0; +} + +static int tolua_ship_set_region(lua_State* L) +{ + ship* self = (ship*) tolua_tousertype(L, 1, 0); + region * r = (region*) tolua_tousertype(L, 1, 0); + if (self) { + move_ship(self, self->region, r, NULL); + } + return 0; +} + +static int tolua_ship_set_name(lua_State* L) +{ + ship* self = (ship*)tolua_tousertype(L, 1, 0); + ship_setname(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int +tolua_ship_get_units(lua_State* L) +{ + ship * self = (ship *)tolua_tousertype(L, 1, 0); + unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); + unit * u = self->region->units; + + while (u && u->ship!=self) u = u->next; + luaL_getmetatable(L, TOLUA_CAST "unit"); + lua_setmetatable(L, -2); + + *unit_ptr = u; + + lua_pushcclosure(L, tolua_unitlist_nexts, 1); + return 1; +} + +static int +tolua_ship_get_objects(lua_State* L) +{ + ship * self = (ship *)tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); + return 1; +} + +static int +tolua_ship_create(lua_State* L) +{ + region * r = (region *)tolua_tousertype(L, 1, 0); + const char * sname = tolua_tostring(L, 2, 0); + if (sname) { + const ship_type * stype = st_find(sname); + if (stype) { + ship * sh = new_ship(stype, default_locale, r); + sh->size = stype->construction->maxsize; + tolua_pushusertype(L, (void*)sh, TOLUA_CAST "ship"); + return 1; + } + } + return 0; +} + +static int + +tolua_ship_tostring(lua_State *L) +{ + ship * self = (ship *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, shipname(self)); + return 1; +} + +static int tolua_ship_get_flags(lua_State* L) +{ + ship* self = (ship*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->flags); + return 1; +} + +static int tolua_ship_set_flags(lua_State* L) +{ + ship* self = (ship*)tolua_tousertype(L, 1, 0); + self->flags = (int)tolua_tonumber(L, 2, 0); + return 0; +} + + +void +tolua_ship_open(lua_State* L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "ship"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, TOLUA_CAST "ship", TOLUA_CAST "ship", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "ship"); + { + tolua_function(L, TOLUA_CAST "__tostring", tolua_ship_tostring); + tolua_variable(L, TOLUA_CAST "id", tolua_ship_get_id, NULL); + tolua_variable(L, TOLUA_CAST "name", tolua_ship_get_name, tolua_ship_set_name); + tolua_variable(L, TOLUA_CAST "units", tolua_ship_get_units, NULL); + tolua_variable(L, TOLUA_CAST "flags", &tolua_ship_get_flags, tolua_ship_set_flags); + tolua_variable(L, TOLUA_CAST "region", tolua_ship_get_region, tolua_ship_set_region); +#ifdef TODO + .property("type", &ship_gettype) + .property("weight", &ship_getweight) + .property("capacity", &ship_getcapacity) + .property("maxsize", &ship_maxsize) + .def_readwrite("damage", &ship::damage) + .def_readwrite("size", &ship::size) + .def_readwrite("coast", &ship::coast) +#endif + tolua_variable(L, TOLUA_CAST "objects", tolua_ship_get_objects, 0); + + tolua_function(L, TOLUA_CAST "create", tolua_ship_create); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_ship.h b/src/bindings/bind_ship.h index 7c9426fce..a3daf5436 100644 --- a/src/bindings/bind_ship.h +++ b/src/bindings/bind_ship.h @@ -1,23 +1,23 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - int tolua_shiplist_next(struct lua_State *L); - void tolua_ship_open(struct lua_State *L); - -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + int tolua_shiplist_next(struct lua_State *L); + void tolua_ship_open(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_sqlite.c b/src/bindings/bind_sqlite.c index ce7f1aed4..a35e5723a 100644 --- a/src/bindings/bind_sqlite.c +++ b/src/bindings/bind_sqlite.c @@ -1,100 +1,100 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include - -#include "bind_unit.h" -#include "bindings.h" - -#include -#include -#include - -#define LTYPE_DB TOLUA_CAST "db" - -extern int db_update_factions(sqlite3 * db, boolean force); -static int -tolua_db_update_factions(lua_State* L) -{ - sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); - db_update_factions(db, tolua_toboolean(L, 2, 0)); - return 0; -} - -extern int db_update_scores(sqlite3 * db, boolean force); -static int -tolua_db_update_scores(lua_State* L) -{ - sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); - db_update_scores(db, tolua_toboolean(L, 2, 0)); - return 0; -} - -static int -tolua_db_execute(lua_State* L) -{ - sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); - const char * sql = tolua_tostring(L, 2, 0); - - int res = sqlite3_exec(db, sql, 0, 0, 0); - - tolua_pushnumber(L, (LUA_NUMBER)res); - return 1; -} - -static int -tolua_db_close(lua_State* L) -{ - sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); - sqlite3_close(db); - return 0; -} - -static int -tolua_db_create(lua_State* L) -{ - sqlite3 * db; - const char * dbname = tolua_tostring(L, 1, 0); - int result = sqlite3_open_v2(dbname, &db, SQLITE_OPEN_READWRITE, 0); - if (result==SQLITE_OK) { - tolua_pushusertype(L, (void*)db, LTYPE_DB); - return 1; - } - return 0; -} - -int -tolua_sqlite_open(lua_State * L) -{ - /* register user types */ - - tolua_usertype(L, LTYPE_DB); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_cclass(L, LTYPE_DB, LTYPE_DB, TOLUA_CAST "", NULL); - tolua_beginmodule(L, LTYPE_DB); - { - tolua_function(L, TOLUA_CAST "open", &tolua_db_create); - tolua_function(L, TOLUA_CAST "close", &tolua_db_close); - - tolua_function(L, TOLUA_CAST "update_factions", &tolua_db_update_factions); - tolua_function(L, TOLUA_CAST "update_scores", &tolua_db_update_scores); - tolua_function(L, TOLUA_CAST "execute", &tolua_db_execute); - } - tolua_endmodule(L); - - } - tolua_endmodule(L); - return 0; -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include + +#include "bind_unit.h" +#include "bindings.h" + +#include +#include +#include + +#define LTYPE_DB TOLUA_CAST "db" + +extern int db_update_factions(sqlite3 * db, boolean force); +static int +tolua_db_update_factions(lua_State* L) +{ + sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); + db_update_factions(db, tolua_toboolean(L, 2, 0)); + return 0; +} + +extern int db_update_scores(sqlite3 * db, boolean force); +static int +tolua_db_update_scores(lua_State* L) +{ + sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); + db_update_scores(db, tolua_toboolean(L, 2, 0)); + return 0; +} + +static int +tolua_db_execute(lua_State* L) +{ + sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); + const char * sql = tolua_tostring(L, 2, 0); + + int res = sqlite3_exec(db, sql, 0, 0, 0); + + tolua_pushnumber(L, (LUA_NUMBER)res); + return 1; +} + +static int +tolua_db_close(lua_State* L) +{ + sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); + sqlite3_close(db); + return 0; +} + +static int +tolua_db_create(lua_State* L) +{ + sqlite3 * db; + const char * dbname = tolua_tostring(L, 1, 0); + int result = sqlite3_open_v2(dbname, &db, SQLITE_OPEN_READWRITE, 0); + if (result==SQLITE_OK) { + tolua_pushusertype(L, (void*)db, LTYPE_DB); + return 1; + } + return 0; +} + +int +tolua_sqlite_open(lua_State * L) +{ + /* register user types */ + + tolua_usertype(L, LTYPE_DB); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, LTYPE_DB, LTYPE_DB, TOLUA_CAST "", NULL); + tolua_beginmodule(L, LTYPE_DB); + { + tolua_function(L, TOLUA_CAST "open", &tolua_db_create); + tolua_function(L, TOLUA_CAST "close", &tolua_db_close); + + tolua_function(L, TOLUA_CAST "update_factions", &tolua_db_update_factions); + tolua_function(L, TOLUA_CAST "update_scores", &tolua_db_update_scores); + tolua_function(L, TOLUA_CAST "execute", &tolua_db_execute); + } + tolua_endmodule(L); + + } + tolua_endmodule(L); + return 0; +} diff --git a/src/bindings/bind_storage.c b/src/bindings/bind_storage.c index 23b9a0a5a..2f5675cb5 100644 --- a/src/bindings/bind_storage.c +++ b/src/bindings/bind_storage.c @@ -1,144 +1,144 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "bind_storage.h" - -#include -#include -#include -#include - -#include - -#include -#include - - -static int -tolua_storage_create(lua_State* L) -{ - const char * filename = tolua_tostring(L, 1, 0); - const char * type = tolua_tostring(L, 2, "rb"); - storage * store = 0; - int mode = IO_READ; - if (strchr(type, 't')) { - store = malloc(sizeof(text_store)); - memcpy(store, &text_store, sizeof(text_store)); - } else { - store = malloc(sizeof(binary_store)); - memcpy(store, &binary_store, sizeof(binary_store)); - } - if (strchr(type, 'r')) mode = IO_READ; - if (strchr(type, 'w')) mode = IO_WRITE; - store->open(store, filename, mode); - tolua_pushusertype(L, (void*)store, TOLUA_CAST "storage"); - return 1; -} - -static int -tolua_storage_read_unit(lua_State *L) -{ - storage * self = (storage *)tolua_tousertype(L, 1, 0); - struct unit * u = read_unit(self); - tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); - return 1; -} - -static int -tolua_storage_write_unit(lua_State *L) -{ - storage * self = (storage *)tolua_tousertype(L, 1, 0); - struct unit * u = (struct unit *)tolua_tousertype(L, 2, 0); - write_unit(self, u); - return 0; -} - - -static int -tolua_storage_read_float(lua_State *L) -{ - storage * self = (storage *)tolua_tousertype(L, 1, 0); - float num = self->r_flt(self); - tolua_pushnumber(L, (lua_Number)num); - return 1; -} - -static int -tolua_storage_read_int(lua_State *L) -{ - storage * self = (storage *)tolua_tousertype(L, 1, 0); - int num = self->r_int(self); - tolua_pushnumber(L, (lua_Number)num); - return 1; -} - -static int -tolua_storage_write(lua_State *L) -{ - storage * self = (storage *)tolua_tousertype(L, 1, 0); - if (tolua_isnumber(L, 2, 0, 0)) { - lua_Number num = tolua_tonumber(L, 2, 0); - double n; - if (modf(num, &n)==0.0) { - self->w_int(self, (int)num); - } else { - self->w_flt(self, (float)num); - } - } - return 0; -} - -static int -tolua_storage_tostring(lua_State *L) -{ - storage * self = (storage *)tolua_tousertype(L, 1, 0); - char name[64]; - snprintf(name, sizeof(name), "", self->encoding, self->version); - lua_pushstring(L, name); - return 1; -} - -static int -tolua_storage_close(lua_State *L) -{ - storage * self = (storage *)tolua_tousertype(L, 1, 0); - self->close(self); - return 0; -} - -void -tolua_storage_open(lua_State* L) -{ - /* register user types */ - tolua_usertype(L, TOLUA_CAST "storage"); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_cclass(L, TOLUA_CAST "storage", TOLUA_CAST "storage", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "storage"); - { - tolua_function(L, TOLUA_CAST "__tostring", tolua_storage_tostring); - tolua_function(L, TOLUA_CAST "write", tolua_storage_write); - tolua_function(L, TOLUA_CAST "read_int", tolua_storage_read_int); - tolua_function(L, TOLUA_CAST "read_float", tolua_storage_read_float); - tolua_function(L, TOLUA_CAST "write_unit", tolua_storage_write_unit); - tolua_function(L, TOLUA_CAST "read_unit", tolua_storage_read_unit); - tolua_function(L, TOLUA_CAST "close", tolua_storage_close); - tolua_function(L, TOLUA_CAST "create", tolua_storage_create); - } - tolua_endmodule(L); - } - tolua_endmodule(L); -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "bind_storage.h" + +#include +#include +#include +#include + +#include + +#include +#include + + +static int +tolua_storage_create(lua_State* L) +{ + const char * filename = tolua_tostring(L, 1, 0); + const char * type = tolua_tostring(L, 2, "rb"); + storage * store = 0; + int mode = IO_READ; + if (strchr(type, 't')) { + store = malloc(sizeof(text_store)); + memcpy(store, &text_store, sizeof(text_store)); + } else { + store = malloc(sizeof(binary_store)); + memcpy(store, &binary_store, sizeof(binary_store)); + } + if (strchr(type, 'r')) mode = IO_READ; + if (strchr(type, 'w')) mode = IO_WRITE; + store->open(store, filename, mode); + tolua_pushusertype(L, (void*)store, TOLUA_CAST "storage"); + return 1; +} + +static int +tolua_storage_read_unit(lua_State *L) +{ + storage * self = (storage *)tolua_tousertype(L, 1, 0); + struct unit * u = read_unit(self); + tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); + return 1; +} + +static int +tolua_storage_write_unit(lua_State *L) +{ + storage * self = (storage *)tolua_tousertype(L, 1, 0); + struct unit * u = (struct unit *)tolua_tousertype(L, 2, 0); + write_unit(self, u); + return 0; +} + + +static int +tolua_storage_read_float(lua_State *L) +{ + storage * self = (storage *)tolua_tousertype(L, 1, 0); + float num = self->r_flt(self); + tolua_pushnumber(L, (lua_Number)num); + return 1; +} + +static int +tolua_storage_read_int(lua_State *L) +{ + storage * self = (storage *)tolua_tousertype(L, 1, 0); + int num = self->r_int(self); + tolua_pushnumber(L, (lua_Number)num); + return 1; +} + +static int +tolua_storage_write(lua_State *L) +{ + storage * self = (storage *)tolua_tousertype(L, 1, 0); + if (tolua_isnumber(L, 2, 0, 0)) { + lua_Number num = tolua_tonumber(L, 2, 0); + double n; + if (modf(num, &n)==0.0) { + self->w_int(self, (int)num); + } else { + self->w_flt(self, (float)num); + } + } + return 0; +} + +static int +tolua_storage_tostring(lua_State *L) +{ + storage * self = (storage *)tolua_tousertype(L, 1, 0); + char name[64]; + snprintf(name, sizeof(name), "", self->encoding, self->version); + lua_pushstring(L, name); + return 1; +} + +static int +tolua_storage_close(lua_State *L) +{ + storage * self = (storage *)tolua_tousertype(L, 1, 0); + self->close(self); + return 0; +} + +void +tolua_storage_open(lua_State* L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "storage"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, TOLUA_CAST "storage", TOLUA_CAST "storage", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "storage"); + { + tolua_function(L, TOLUA_CAST "__tostring", tolua_storage_tostring); + tolua_function(L, TOLUA_CAST "write", tolua_storage_write); + tolua_function(L, TOLUA_CAST "read_int", tolua_storage_read_int); + tolua_function(L, TOLUA_CAST "read_float", tolua_storage_read_float); + tolua_function(L, TOLUA_CAST "write_unit", tolua_storage_write_unit); + tolua_function(L, TOLUA_CAST "read_unit", tolua_storage_read_unit); + tolua_function(L, TOLUA_CAST "close", tolua_storage_close); + tolua_function(L, TOLUA_CAST "create", tolua_storage_create); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_storage.h b/src/bindings/bind_storage.h index fd79c7ca8..e47aba558 100644 --- a/src/bindings/bind_storage.h +++ b/src/bindings/bind_storage.h @@ -1,22 +1,22 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - void tolua_storage_open(struct lua_State *L); - -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + void tolua_storage_open(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 9de137d90..56a81bf3e 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -1,1026 +1,1026 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include - -#include "bind_unit.h" -#include "bind_attrib.h" -#include "bindings.h" - -// attributes includes -#include -#include - -// kernel includes -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// util includes -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -static int -tolua_unit_get_objects(lua_State* L) -{ - unit * self = (unit *)tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); - return 1; -} - - -static int -tolua_unit_get_attribs(lua_State* L) -{ - unit * self = (unit *)tolua_tousertype(L, 1, 0); - attrib ** attrib_ptr = (attrib**)lua_newuserdata(L, sizeof(attrib *)); - attrib * a = tolua_get_lua_ext(self->attribs); - - luaL_getmetatable(L, "attrib"); - lua_setmetatable(L, -2); - - *attrib_ptr = a; - - lua_pushcclosure(L, tolua_attriblist_next, 1); - return 1; -} - -int tolua_unitlist_nextf(lua_State *L) -{ - unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); - unit * u = *unit_ptr; - if (u != NULL) { - tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); - *unit_ptr = u->nextF; - return 1; - } - else return 0; /* no more values to return */ -} - -int tolua_unitlist_nextb(lua_State *L) -{ - unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); - unit * u = *unit_ptr; - if (u != NULL) { - unit * unext = u->next; - tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); - - while (unext && unext->building!=u->building) { - unext = unext->next; - } - *unit_ptr = unext; - - return 1; - } - else return 0; /* no more values to return */ -} - -int tolua_unitlist_nexts(lua_State *L) -{ - unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); - unit * u = *unit_ptr; - if (u != NULL) { - unit * unext = u->next; - tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); - - while (unext && unext->ship!=u->ship) { - unext = unext->next; - } - *unit_ptr = unext; - - return 1; - } - else return 0; /* no more values to return */ -} - -int tolua_unitlist_next(lua_State *L) -{ - unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); - unit * u = *unit_ptr; - if (u != NULL) { - tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); - *unit_ptr = u->next; - return 1; - } - else return 0; /* no more values to return */ -} - - -static int tolua_unit_get_name(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->name); - return 1; -} - -static int tolua_unit_set_name(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - unit_setname(self, tolua_tostring(L, 2, 0)); - return 0; -} - -static int tolua_unit_get_info(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, unit_getinfo(self)); - return 1; -} - -static int tolua_unit_set_info(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - unit_setinfo(self, tolua_tostring(L, 2, 0)); - return 0; -} - -static int tolua_unit_get_id(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)unit_getid(self)); - return 1; -} - -static int tolua_unit_set_id(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - unit_setid(self, (int)tolua_tonumber(L, 2, 0)); - return 0; -} - -static int tolua_unit_get_hpmax(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)unit_max_hp(self)); - return 1; -} - -static int tolua_unit_get_hp(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)unit_gethp(self)); - return 1; -} - -static int tolua_unit_set_hp(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - unit_sethp(self, (int)tolua_tonumber(L, 2, 0)); - return 0; -} - -static int tolua_unit_get_number(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->number); - return 1; -} - -static int tolua_unit_set_number(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - int number = (int)tolua_tonumber(L, 2, 0); - if (self->number==0) { - set_number(self, number); - self->hp = unit_max_hp(self) * number; - } else { - scale_number(self, number); - } - return 0; -} - -static int tolua_unit_get_flags(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->flags); - return 1; -} - -static int tolua_unit_set_flags(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - self->flags = (int)tolua_tonumber(L, 2, 0); - return 0; -} - -static const char * -unit_getmagic(const unit * u) -{ - sc_mage * mage = get_mage(u); - return mage?magic_school[mage->magietyp]:NULL; -} - -static int tolua_unit_get_magic(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - lua_pushstring(L, unit_getmagic(self)); - return 1; -} - -static void -unit_setmagic(unit * u, const char * type) -{ - sc_mage * mage = get_mage(u); - magic_t mtype; - for (mtype=0;mtype!=MAXMAGIETYP;++mtype) { - if (strcmp(magic_school[mtype], type)==0) break; - } - if (mtype==MAXMAGIETYP) return; - if (mage==NULL) { - mage = create_mage(u, mtype); - } -} - -static int tolua_unit_set_magic(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * type = tolua_tostring(L, 2, 0); - unit_setmagic(self, type); - return 0; -} - -static int tolua_unit_get_aura(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)get_spellpoints(self)); - return 1; -} - -static int tolua_unit_set_aura(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - set_spellpoints(self, (int)tolua_tonumber(L, 2, 0)); - return 0; -} - -static int tolua_unit_get_age(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->age); - return 1; -} - -static int tolua_unit_set_age(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - self->age = (short)tolua_tonumber(L, 2, 0); - return 0; -} - -static int tolua_unit_get_status(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)unit_getstatus(self)); - return 1; -} - -static int tolua_unit_set_status(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - unit_setstatus(self, (status_t)tolua_tonumber(L, 2, 0)); - return 0; -} - -static int -tolua_unit_get_item(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * iname = tolua_tostring(L, 2, 0); - int result = -1; - - if (iname!=NULL) { - const item_type * itype = it_find(iname); - if (itype!=NULL) { - result = i_get(self->items, itype); - } - } - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_unit_add_item(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * iname = tolua_tostring(L, 2, 0); - int number = (int)tolua_tonumber(L, 3, 0); - int result = -1; - - if (iname!=NULL) { - const item_type * itype = it_find(iname); - if (itype!=NULL) { - item * i = i_change(&self->items, itype, number); - result = i?i->number:0; - } - } - lua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_unit_getskill(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * skname = tolua_tostring(L, 2, 0); - skill_t sk = sk_find(skname); - int value = -1; - if (sk!=NOSKILL) { - skill * sv = get_skill(self, sk); - if (sv) { - value = sv->level; - } - else value = 0; - } - lua_pushnumber(L, (lua_Number)value); - return 1; -} - -static int -tolua_unit_effskill(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * skname = tolua_tostring(L, 2, 0); - skill_t sk = sk_find(skname); - int value = (sk==NOSKILL)?-1:eff_skill(self, sk, self->region); - lua_pushnumber(L, (lua_Number)value); - return 1; -} - -typedef struct fctr_data { - unit * target; - int fhandle; -} fctr_data; - -typedef struct event { - struct event_arg * args; - char * msg; -} event; - -int -fctr_handle(struct trigger * tp, void * data) -{ - trigger * t = tp; - event evt = { 0 }; - fctr_data * fd = (fctr_data*)t->data.v; - lua_State * L = (lua_State *)global.vm_state; - unit * u = fd->target; - - evt.args = (event_arg*)data; - lua_rawgeti(L, LUA_REGISTRYINDEX, fd->fhandle); - tolua_pushusertype(L, u, TOLUA_CAST "unit"); - tolua_pushusertype(L, &evt, TOLUA_CAST "event"); - if (lua_pcall(L, 2, 0, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("event (%s): %s\n", unitname(u), error)); - lua_pop(L, 1); - tolua_error(L, TOLUA_CAST "event handler call failed", NULL); - } - - return 0; -} - -static void -fctr_init(trigger * t) -{ - t->data.v = calloc(sizeof(fctr_data), 1); -} - -static void -fctr_done(trigger * t) -{ - fctr_data * fd = (fctr_data*)t->data.v; - lua_State * L = (lua_State *)global.vm_state; - luaL_unref(L, LUA_REGISTRYINDEX, fd->fhandle); - free(fd); -} - -static struct trigger_type tt_lua = { - "lua_event", - fctr_init, - fctr_done, - fctr_handle -}; - -static trigger * -trigger_lua(struct unit * u, int handle) -{ - trigger * t = t_new(&tt_lua); - fctr_data * td = (fctr_data*)t->data.v; - td->target = u; - td->fhandle = handle; - return t; -} - -static int -tolua_unit_addhandler(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * ename = tolua_tostring(L, 2, 0); - int handle; - - lua_pushvalue(L, 3); - handle = luaL_ref(L, LUA_REGISTRYINDEX); - add_trigger(&self->attribs, ename, trigger_lua(self, handle)); - - return 0; -} - -static int -tolua_unit_addnotice(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * str = tolua_tostring(L, 2, 0); - - addmessage(self->region, self->faction, str, MSG_MESSAGE, ML_IMPORTANT); - return 0; -} - -static void -unit_castspell(unit * u, const char * name) -{ - spell_list * slist = spells; - while (slist!=NULL) { - spell * sp = slist->data; - if (strcmp(name, sp->sname)==0) { - castorder * co = (castorder*)malloc(sizeof(castorder)); - co->distance = 0; - co->familiar = NULL; - co->force = sp->level; - co->level = sp->level; - co->magician.u = u; - co->order = NULL; - co->par = NULL; - co->rt = u->region; - co->sp = sp; - if (sp->sp_function==NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); - co->level = 0; - } else { - sp->sp_function(co); - } - free(co); - } - slist=slist->next; - } -} - -static int -tolua_unit_castspell(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * str = tolua_tostring(L, 2, 0); - unit_castspell(self, str); - return 0; -} - -static void -unit_addspell(unit * u, const char * name) -{ - int add = 0; - sc_mage * m = get_mage(u); - spell_list * slist = spells; - spell_list ** starget = NULL; - spell * spadd = NULL; - while (slist!=NULL) { - spell * sp = slist->data; - if (strcmp(name, sp->sname)==0) { - starget = get_spelllist(m, u->faction); - if (m->magietyp==sp->magietyp) spadd = sp; - else if (!spadd) spadd = sp; - add = 1; - } - slist=slist->next; - } - if (!spadd) log_error(("spell %s could not be found\n", name)); - else add_spell(starget, spadd); -} - -static int -tolua_unit_addspell(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * str = tolua_tostring(L, 2, 0); - unit_addspell(self, str); - return 0; -} - -static void -unit_removespell(unit * u, const spell * sp) -{ - spell_list ** isptr; - isptr = get_spelllist(get_mage(u), u->faction); - - while (*isptr && (*isptr)->data != sp) { - isptr = &(*isptr)->next; - } - if (*isptr) { - spell_list * sptr = *isptr; - *isptr = sptr->next; - free(sptr); - } -} - -static int -tolua_unit_removespell(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - spell * sp = (spell*)tolua_tousertype(L, 2, 0); - unit_removespell(self, sp); - return 0; -} - -static int -tolua_unit_set_racename(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * str = tolua_tostring(L, 2, 0); - - set_racename(&self->attribs, str); - return 0; -} - -static int -tolua_unit_get_racename(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - attrib * a = a_find(self->attribs, &at_racename); - if (a) { - tolua_pushstring(L, get_racename(a)); - return 1; - } - return 0; -} - -static int -tolua_unit_setskill(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * skname = tolua_tostring(L, 2, 0); - int level = (int)tolua_tonumber(L, 3, 0); - skill_t sk = sk_find(skname); - if (sk!=NOSKILL) { - set_level(self, sk, level); - } else { - level = -1; - } - lua_pushnumber(L, (lua_Number)level); - return 1; -} - -static int -tolua_unit_use_pooled(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * iname = tolua_tostring(L, 2, 0); - int number = (int)tolua_tonumber(L, 3, 0); - const resource_type * rtype = rt_find(iname); - int result = -1; - if (rtype!=NULL) { - result = use_pooled(self, rtype, GET_DEFAULT, number); - } - lua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_unit_get_pooled(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * iname = tolua_tostring(L, 2, 0); - const resource_type * rtype = rt_find(iname); - int result = -1; - if (rtype!=NULL) { - result = get_pooled(self, rtype, GET_DEFAULT, INT_MAX); - } - lua_pushnumber(L, (lua_Number)result); - return 1; -} - -static unit * -unit_getfamiliar(const unit * u) -{ - attrib * a = a_find(u->attribs, &at_familiar); - if (a!=NULL) { - return (unit*)a->data.v; - } - return NULL; -} - -static int tolua_unit_get_familiar(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, unit_getfamiliar(self), TOLUA_CAST "unit"); - return 1; -} - -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)); - return 0; -} - -static int tolua_unit_get_building(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, self->building, TOLUA_CAST "building"); - return 1; -} - -static void -unit_setbuilding(unit * u, building * b) -{ - leave(u, true); - if (b && u->region!=b->region) { - move_unit(u, b->region, NULL); - } - u->building = b; -} - -static int tolua_unit_set_building(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - if (self->faction) { - unit_setbuilding(self, (building *)tolua_tousertype(L, 2, 0)); - } - return 0; -} - -static int tolua_unit_get_ship(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, self->ship, TOLUA_CAST "ship"); - return 1; -} - -static void -unit_setship(unit * u, ship * s) -{ - leave(u, true); - if (s && u->region!=s->region) { - move_unit(u, s->region, NULL); - } - u->ship = s; -} - -static int tolua_unit_set_ship(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - if (self->faction) { - unit_setship(self, (ship *)tolua_tousertype(L, 2, 0)); - } - return 0; -} - -static int tolua_unit_get_region(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, self->region, TOLUA_CAST "region"); - return 1; -} - -static void -unit_setregion(unit * u, region * r) -{ - move_unit(u, r, NULL); -} - -static int tolua_unit_set_region(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - unit_setregion(self, (region *)tolua_tousertype(L, 2, 0)); - return 0; -} - -static int tolua_unit_add_order(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * str = tolua_tostring(L, 2, 0); - order * ord = parse_order(str, self->faction->locale); - unit_addorder(self, ord); - return 0; -} - -static int tolua_unit_clear_orders(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - free_orders(&self->orders); - return 0; -} - -static int tolua_unit_get_items(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - - item ** item_ptr = (item **)lua_newuserdata(L, sizeof(item *)); - - luaL_getmetatable(L, TOLUA_CAST "item"); - lua_setmetatable(L, -2); - - *item_ptr = self->items; - - lua_pushcclosure(L, tolua_itemlist_next, 1); - - return 1; -} - -static int tolua_unit_get_spells(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - sc_mage * mage = get_mage(self); - - if (mage) { - spell_list ** slist = get_spelllist(mage, self->faction); - assert(slist); - if (slist) { - spell_list ** spell_ptr = (spell_list **)lua_newuserdata(L, sizeof(spell_list *)); - luaL_getmetatable(L, TOLUA_CAST "spell_list"); - lua_setmetatable(L, -2); - - *spell_ptr = *slist; - lua_pushcclosure(L, tolua_spelllist_next, 1); - return 1; - } - } - - lua_pushnil(L); - return 1; -} - -static int tolua_unit_get_orders(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - - order ** order_ptr = (order **)lua_newuserdata(L, sizeof(order *)); - - luaL_getmetatable(L, TOLUA_CAST "order"); - lua_setmetatable(L, -2); - - *order_ptr = self->orders; - - lua_pushcclosure(L, tolua_orderlist_next, 1); - - return 1; -} - -static int tolua_unit_get_flag(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - int flag = atoi36(name); - attrib * a = find_key(self->attribs, flag); - lua_pushboolean(L, (a!=NULL)); - return 1; -} - -static int tolua_unit_set_flag(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - int value = (int)tolua_tonumber(L, 3, 0); - int flag = atoi36(name); - attrib * a = find_key(self->attribs, flag); - if (a==NULL && value) { - add_key(&self->attribs, flag); - } else if (a!=NULL && !value) { - a_remove(&self->attribs, a); - } - return 0; -} - -static int tolua_unit_get_weight(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)unit_getweight(self)); - return 1; -} - -static int tolua_unit_get_capacity(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)unit_getcapacity(self)); - return 1; -} - -static int tolua_unit_get_faction(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void*)self->faction, TOLUA_CAST "faction"); - return 1; -} - -static int tolua_unit_set_faction(lua_State* L) -{ - unit * self = (unit*) tolua_tousertype(L, 1, 0); - faction * f = (faction *)tolua_tousertype(L, 2, 0); - u_setfaction(self, f); - return 0; -} - -static int tolua_unit_get_race(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->race->_name[0]); - return 1; -} - -static int tolua_unit_set_race(lua_State* L) -{ - unit * self = (unit*) tolua_tousertype(L, 1, 0); - const char * rcname = tolua_tostring(L, 2, 0); - race * rc = rc_find(rcname); - if (rc!=NULL) { - if (count_unit(self)) --self->faction->no_units; - if (self->irace==self->race) self->irace = NULL; - self->race = rc; - if (count_unit(self)) --self->faction->no_units; - } - return 0; -} - -static int -tolua_unit_destroy(lua_State* L) -{ - unit * self = (unit *)tolua_tousertype(L, 1, 0); - if (self) { - remove_unit(&self->region->units, self); - } - return 0; -} - -static int -tolua_unit_create(lua_State* L) -{ - faction * f = (faction *)tolua_tousertype(L, 1, 0); - region * r = (region *)tolua_tousertype(L, 2, 0); - int num = (int)tolua_tonumber(L, 3, 1); - if (f && r) { - const race * rc = f->race; - const char * rcname = tolua_tostring(L, 4, NULL); - if (rcname) rc = rc_find(rcname); - if (rc) { - unit * u = create_unit(r, f, num, rc, 0, NULL, NULL); - tolua_pushusertype(L, u, TOLUA_CAST "unit"); - return 1; - } - } - return 0; -} - -static int -tolua_unit_tostring(lua_State *L) -{ - unit * self = (unit *)tolua_tousertype(L, 1, 0); - lua_pushstring(L, unitname(self)); - return 1; -} - -static int -tolua_event_gettype(lua_State *L) -{ - event * self = (event *)tolua_tousertype(L, 1, 0); - int index = (int)tolua_tonumber(L, 2, 0); - lua_pushstring(L, self->args[index].type); - return 1; -} - -static int -tolua_event_get(lua_State *L) -{ - struct event * self = (struct event *)tolua_tousertype(L, 1, 0); - int index = (int)tolua_tonumber(L, 2, 0); - - event_arg * arg = self->args+index; - - if (arg->type) { - if (strcmp(arg->type, "string")==0) { - tolua_pushstring(L, (const char *)arg->data.v); - } else if (strcmp(arg->type, "int")==0) { - tolua_pushnumber(L, (lua_Number)arg->data.i); - } else if (strcmp(arg->type, "float")==0) { - tolua_pushnumber(L, (lua_Number)arg->data.f); - } else { - /* this is pretty lazy */ - tolua_pushusertype(L, (void*)arg->data.v, TOLUA_CAST arg->type); - } - return 1; - } - tolua_error(L, TOLUA_CAST "invalid type argument for event", NULL); - return 0; -} - -void -tolua_unit_open(lua_State * L) -{ - /* register user types */ - tolua_usertype(L, TOLUA_CAST "unit"); - tolua_usertype(L, TOLUA_CAST "unit_list"); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_cclass(L, TOLUA_CAST "event", TOLUA_CAST "event", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "event"); - { - tolua_function(L, TOLUA_CAST "get_type", &tolua_event_gettype); - tolua_function(L, TOLUA_CAST "get", &tolua_event_get); - } - tolua_endmodule(L); - - tolua_cclass(L, TOLUA_CAST "unit", TOLUA_CAST "unit", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "unit"); - { - tolua_function(L, TOLUA_CAST "__tostring", &tolua_unit_tostring); - tolua_function(L, TOLUA_CAST "create", &tolua_unit_create); - tolua_function(L, TOLUA_CAST "destroy", &tolua_unit_destroy); - - tolua_variable(L, TOLUA_CAST "name", &tolua_unit_get_name, tolua_unit_set_name); - tolua_variable(L, TOLUA_CAST "faction", &tolua_unit_get_faction, tolua_unit_set_faction); - tolua_variable(L, TOLUA_CAST "id", &tolua_unit_get_id, tolua_unit_set_id); - tolua_variable(L, TOLUA_CAST "info", &tolua_unit_get_info, tolua_unit_set_info); - tolua_variable(L, TOLUA_CAST "hp", &tolua_unit_get_hp, tolua_unit_set_hp); - tolua_variable(L, TOLUA_CAST "status", &tolua_unit_get_status, tolua_unit_set_status); - tolua_variable(L, TOLUA_CAST "familiar", &tolua_unit_get_familiar, tolua_unit_set_familiar); - - tolua_variable(L, TOLUA_CAST "weight", &tolua_unit_get_weight, 0); - tolua_variable(L, TOLUA_CAST "capacity", &tolua_unit_get_capacity, 0); - - tolua_function(L, TOLUA_CAST "add_order", &tolua_unit_add_order); - tolua_function(L, TOLUA_CAST "clear_orders", &tolua_unit_clear_orders); - tolua_variable(L, TOLUA_CAST "orders", &tolua_unit_get_orders, 0); - - // key-attributes for named flags: - tolua_function(L, TOLUA_CAST "set_flag", &tolua_unit_set_flag); - tolua_function(L, TOLUA_CAST "get_flag", &tolua_unit_get_flag); - tolua_variable(L, TOLUA_CAST "flags", &tolua_unit_get_flags, &tolua_unit_set_flags); - tolua_variable(L, TOLUA_CAST "age", &tolua_unit_get_age, tolua_unit_set_age); - - // items: - tolua_function(L, TOLUA_CAST "get_item", &tolua_unit_get_item); - tolua_function(L, TOLUA_CAST "add_item", &tolua_unit_add_item); - tolua_variable(L, TOLUA_CAST "items", &tolua_unit_get_items, 0); - tolua_function(L, TOLUA_CAST "get_pooled", &tolua_unit_get_pooled); - tolua_function(L, TOLUA_CAST "use_pooled", &tolua_unit_use_pooled); - - // skills: - tolua_function(L, TOLUA_CAST "get_skill", &tolua_unit_getskill); - tolua_function(L, TOLUA_CAST "eff_skill", &tolua_unit_effskill); - tolua_function(L, TOLUA_CAST "set_skill", &tolua_unit_setskill); - - tolua_function(L, TOLUA_CAST "add_notice", &tolua_unit_addnotice); - - // npc logic: - tolua_function(L, TOLUA_CAST "add_handler", &tolua_unit_addhandler); - - tolua_variable(L, TOLUA_CAST "race_name", &tolua_unit_get_racename, &tolua_unit_set_racename); - tolua_function(L, TOLUA_CAST "add_spell", &tolua_unit_addspell); - tolua_function(L, TOLUA_CAST "remove_spell", &tolua_unit_removespell); - tolua_function(L, TOLUA_CAST "cast_spell", &tolua_unit_castspell); - - tolua_variable(L, TOLUA_CAST "magic", &tolua_unit_get_magic, tolua_unit_set_magic); - tolua_variable(L, TOLUA_CAST "aura", &tolua_unit_get_aura, tolua_unit_set_aura); - tolua_variable(L, TOLUA_CAST "building", &tolua_unit_get_building, tolua_unit_set_building); - tolua_variable(L, TOLUA_CAST "ship", &tolua_unit_get_ship, tolua_unit_set_ship); - tolua_variable(L, TOLUA_CAST "region", &tolua_unit_get_region, tolua_unit_set_region); - tolua_variable(L, TOLUA_CAST "spells", &tolua_unit_get_spells, 0); - tolua_variable(L, TOLUA_CAST "number", &tolua_unit_get_number, tolua_unit_set_number); - tolua_variable(L, TOLUA_CAST "race", &tolua_unit_get_race, tolua_unit_set_race); - tolua_variable(L, TOLUA_CAST "hp_max", &tolua_unit_get_hpmax, 0); - - tolua_variable(L, TOLUA_CAST "objects", &tolua_unit_get_objects, 0); - tolua_variable(L, TOLUA_CAST "attribs", &tolua_unit_get_attribs, 0); - } - tolua_endmodule(L); - } - tolua_endmodule(L); -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include + +#include "bind_unit.h" +#include "bind_attrib.h" +#include "bindings.h" + +// attributes includes +#include +#include + +// kernel includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// util includes +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +static int +tolua_unit_get_objects(lua_State* L) +{ + unit * self = (unit *)tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); + return 1; +} + + +static int +tolua_unit_get_attribs(lua_State* L) +{ + unit * self = (unit *)tolua_tousertype(L, 1, 0); + attrib ** attrib_ptr = (attrib**)lua_newuserdata(L, sizeof(attrib *)); + attrib * a = tolua_get_lua_ext(self->attribs); + + luaL_getmetatable(L, "attrib"); + lua_setmetatable(L, -2); + + *attrib_ptr = a; + + lua_pushcclosure(L, tolua_attriblist_next, 1); + return 1; +} + +int tolua_unitlist_nextf(lua_State *L) +{ + unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); + unit * u = *unit_ptr; + if (u != NULL) { + tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); + *unit_ptr = u->nextF; + return 1; + } + else return 0; /* no more values to return */ +} + +int tolua_unitlist_nextb(lua_State *L) +{ + unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); + unit * u = *unit_ptr; + if (u != NULL) { + unit * unext = u->next; + tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); + + while (unext && unext->building!=u->building) { + unext = unext->next; + } + *unit_ptr = unext; + + return 1; + } + else return 0; /* no more values to return */ +} + +int tolua_unitlist_nexts(lua_State *L) +{ + unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); + unit * u = *unit_ptr; + if (u != NULL) { + unit * unext = u->next; + tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); + + while (unext && unext->ship!=u->ship) { + unext = unext->next; + } + *unit_ptr = unext; + + return 1; + } + else return 0; /* no more values to return */ +} + +int tolua_unitlist_next(lua_State *L) +{ + unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); + unit * u = *unit_ptr; + if (u != NULL) { + tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); + *unit_ptr = u->next; + return 1; + } + else return 0; /* no more values to return */ +} + + +static int tolua_unit_get_name(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->name); + return 1; +} + +static int tolua_unit_set_name(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit_setname(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int tolua_unit_get_info(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, unit_getinfo(self)); + return 1; +} + +static int tolua_unit_set_info(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit_setinfo(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int tolua_unit_get_id(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)unit_getid(self)); + return 1; +} + +static int tolua_unit_set_id(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit_setid(self, (int)tolua_tonumber(L, 2, 0)); + return 0; +} + +static int tolua_unit_get_hpmax(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)unit_max_hp(self)); + return 1; +} + +static int tolua_unit_get_hp(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)unit_gethp(self)); + return 1; +} + +static int tolua_unit_set_hp(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit_sethp(self, (int)tolua_tonumber(L, 2, 0)); + return 0; +} + +static int tolua_unit_get_number(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->number); + return 1; +} + +static int tolua_unit_set_number(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + int number = (int)tolua_tonumber(L, 2, 0); + if (self->number==0) { + set_number(self, number); + self->hp = unit_max_hp(self) * number; + } else { + scale_number(self, number); + } + return 0; +} + +static int tolua_unit_get_flags(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->flags); + return 1; +} + +static int tolua_unit_set_flags(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + self->flags = (int)tolua_tonumber(L, 2, 0); + return 0; +} + +static const char * +unit_getmagic(const unit * u) +{ + sc_mage * mage = get_mage(u); + return mage?magic_school[mage->magietyp]:NULL; +} + +static int tolua_unit_get_magic(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + lua_pushstring(L, unit_getmagic(self)); + return 1; +} + +static void +unit_setmagic(unit * u, const char * type) +{ + sc_mage * mage = get_mage(u); + magic_t mtype; + for (mtype=0;mtype!=MAXMAGIETYP;++mtype) { + if (strcmp(magic_school[mtype], type)==0) break; + } + if (mtype==MAXMAGIETYP) return; + if (mage==NULL) { + mage = create_mage(u, mtype); + } +} + +static int tolua_unit_set_magic(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * type = tolua_tostring(L, 2, 0); + unit_setmagic(self, type); + return 0; +} + +static int tolua_unit_get_aura(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)get_spellpoints(self)); + return 1; +} + +static int tolua_unit_set_aura(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + set_spellpoints(self, (int)tolua_tonumber(L, 2, 0)); + return 0; +} + +static int tolua_unit_get_age(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->age); + return 1; +} + +static int tolua_unit_set_age(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + self->age = (short)tolua_tonumber(L, 2, 0); + return 0; +} + +static int tolua_unit_get_status(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)unit_getstatus(self)); + return 1; +} + +static int tolua_unit_set_status(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit_setstatus(self, (status_t)tolua_tonumber(L, 2, 0)); + return 0; +} + +static int +tolua_unit_get_item(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * iname = tolua_tostring(L, 2, 0); + int result = -1; + + if (iname!=NULL) { + const item_type * itype = it_find(iname); + if (itype!=NULL) { + result = i_get(self->items, itype); + } + } + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_unit_add_item(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * iname = tolua_tostring(L, 2, 0); + int number = (int)tolua_tonumber(L, 3, 0); + int result = -1; + + if (iname!=NULL) { + const item_type * itype = it_find(iname); + if (itype!=NULL) { + item * i = i_change(&self->items, itype, number); + result = i?i->number:0; + } + } + lua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_unit_getskill(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * skname = tolua_tostring(L, 2, 0); + skill_t sk = sk_find(skname); + int value = -1; + if (sk!=NOSKILL) { + skill * sv = get_skill(self, sk); + if (sv) { + value = sv->level; + } + else value = 0; + } + lua_pushnumber(L, (lua_Number)value); + return 1; +} + +static int +tolua_unit_effskill(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * skname = tolua_tostring(L, 2, 0); + skill_t sk = sk_find(skname); + int value = (sk==NOSKILL)?-1:eff_skill(self, sk, self->region); + lua_pushnumber(L, (lua_Number)value); + return 1; +} + +typedef struct fctr_data { + unit * target; + int fhandle; +} fctr_data; + +typedef struct event { + struct event_arg * args; + char * msg; +} event; + +int +fctr_handle(struct trigger * tp, void * data) +{ + trigger * t = tp; + event evt = { 0 }; + fctr_data * fd = (fctr_data*)t->data.v; + lua_State * L = (lua_State *)global.vm_state; + unit * u = fd->target; + + evt.args = (event_arg*)data; + lua_rawgeti(L, LUA_REGISTRYINDEX, fd->fhandle); + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + tolua_pushusertype(L, &evt, TOLUA_CAST "event"); + if (lua_pcall(L, 2, 0, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("event (%s): %s\n", unitname(u), error)); + lua_pop(L, 1); + tolua_error(L, TOLUA_CAST "event handler call failed", NULL); + } + + return 0; +} + +static void +fctr_init(trigger * t) +{ + t->data.v = calloc(sizeof(fctr_data), 1); +} + +static void +fctr_done(trigger * t) +{ + fctr_data * fd = (fctr_data*)t->data.v; + lua_State * L = (lua_State *)global.vm_state; + luaL_unref(L, LUA_REGISTRYINDEX, fd->fhandle); + free(fd); +} + +static struct trigger_type tt_lua = { + "lua_event", + fctr_init, + fctr_done, + fctr_handle +}; + +static trigger * +trigger_lua(struct unit * u, int handle) +{ + trigger * t = t_new(&tt_lua); + fctr_data * td = (fctr_data*)t->data.v; + td->target = u; + td->fhandle = handle; + return t; +} + +static int +tolua_unit_addhandler(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * ename = tolua_tostring(L, 2, 0); + int handle; + + lua_pushvalue(L, 3); + handle = luaL_ref(L, LUA_REGISTRYINDEX); + add_trigger(&self->attribs, ename, trigger_lua(self, handle)); + + return 0; +} + +static int +tolua_unit_addnotice(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * str = tolua_tostring(L, 2, 0); + + addmessage(self->region, self->faction, str, MSG_MESSAGE, ML_IMPORTANT); + return 0; +} + +static void +unit_castspell(unit * u, const char * name) +{ + spell_list * slist = spells; + while (slist!=NULL) { + spell * sp = slist->data; + if (strcmp(name, sp->sname)==0) { + castorder * co = (castorder*)malloc(sizeof(castorder)); + co->distance = 0; + co->familiar = NULL; + co->force = sp->level; + co->level = sp->level; + co->magician.u = u; + co->order = NULL; + co->par = NULL; + co->rt = u->region; + co->sp = sp; + if (sp->sp_function==NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + co->level = 0; + } else { + sp->sp_function(co); + } + free(co); + } + slist=slist->next; + } +} + +static int +tolua_unit_castspell(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * str = tolua_tostring(L, 2, 0); + unit_castspell(self, str); + return 0; +} + +static void +unit_addspell(unit * u, const char * name) +{ + int add = 0; + sc_mage * m = get_mage(u); + spell_list * slist = spells; + spell_list ** starget = NULL; + spell * spadd = NULL; + while (slist!=NULL) { + spell * sp = slist->data; + if (strcmp(name, sp->sname)==0) { + starget = get_spelllist(m, u->faction); + if (m->magietyp==sp->magietyp) spadd = sp; + else if (!spadd) spadd = sp; + add = 1; + } + slist=slist->next; + } + if (!spadd) log_error(("spell %s could not be found\n", name)); + else add_spell(starget, spadd); +} + +static int +tolua_unit_addspell(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * str = tolua_tostring(L, 2, 0); + unit_addspell(self, str); + return 0; +} + +static void +unit_removespell(unit * u, const spell * sp) +{ + spell_list ** isptr; + isptr = get_spelllist(get_mage(u), u->faction); + + while (*isptr && (*isptr)->data != sp) { + isptr = &(*isptr)->next; + } + if (*isptr) { + spell_list * sptr = *isptr; + *isptr = sptr->next; + free(sptr); + } +} + +static int +tolua_unit_removespell(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + spell * sp = (spell*)tolua_tousertype(L, 2, 0); + unit_removespell(self, sp); + return 0; +} + +static int +tolua_unit_set_racename(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * str = tolua_tostring(L, 2, 0); + + set_racename(&self->attribs, str); + return 0; +} + +static int +tolua_unit_get_racename(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + attrib * a = a_find(self->attribs, &at_racename); + if (a) { + tolua_pushstring(L, get_racename(a)); + return 1; + } + return 0; +} + +static int +tolua_unit_setskill(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * skname = tolua_tostring(L, 2, 0); + int level = (int)tolua_tonumber(L, 3, 0); + skill_t sk = sk_find(skname); + if (sk!=NOSKILL) { + set_level(self, sk, level); + } else { + level = -1; + } + lua_pushnumber(L, (lua_Number)level); + return 1; +} + +static int +tolua_unit_use_pooled(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * iname = tolua_tostring(L, 2, 0); + int number = (int)tolua_tonumber(L, 3, 0); + const resource_type * rtype = rt_find(iname); + int result = -1; + if (rtype!=NULL) { + result = use_pooled(self, rtype, GET_DEFAULT, number); + } + lua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_unit_get_pooled(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * iname = tolua_tostring(L, 2, 0); + const resource_type * rtype = rt_find(iname); + int result = -1; + if (rtype!=NULL) { + result = get_pooled(self, rtype, GET_DEFAULT, INT_MAX); + } + lua_pushnumber(L, (lua_Number)result); + return 1; +} + +static unit * +unit_getfamiliar(const unit * u) +{ + attrib * a = a_find(u->attribs, &at_familiar); + if (a!=NULL) { + return (unit*)a->data.v; + } + return NULL; +} + +static int tolua_unit_get_familiar(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, unit_getfamiliar(self), TOLUA_CAST "unit"); + return 1; +} + +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)); + return 0; +} + +static int tolua_unit_get_building(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, self->building, TOLUA_CAST "building"); + return 1; +} + +static void +unit_setbuilding(unit * u, building * b) +{ + leave(u, true); + if (b && u->region!=b->region) { + move_unit(u, b->region, NULL); + } + u->building = b; +} + +static int tolua_unit_set_building(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + if (self->faction) { + unit_setbuilding(self, (building *)tolua_tousertype(L, 2, 0)); + } + return 0; +} + +static int tolua_unit_get_ship(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, self->ship, TOLUA_CAST "ship"); + return 1; +} + +static void +unit_setship(unit * u, ship * s) +{ + leave(u, true); + if (s && u->region!=s->region) { + move_unit(u, s->region, NULL); + } + u->ship = s; +} + +static int tolua_unit_set_ship(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + if (self->faction) { + unit_setship(self, (ship *)tolua_tousertype(L, 2, 0)); + } + return 0; +} + +static int tolua_unit_get_region(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, self->region, TOLUA_CAST "region"); + return 1; +} + +static void +unit_setregion(unit * u, region * r) +{ + move_unit(u, r, NULL); +} + +static int tolua_unit_set_region(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit_setregion(self, (region *)tolua_tousertype(L, 2, 0)); + return 0; +} + +static int tolua_unit_add_order(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * str = tolua_tostring(L, 2, 0); + order * ord = parse_order(str, self->faction->locale); + unit_addorder(self, ord); + return 0; +} + +static int tolua_unit_clear_orders(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + free_orders(&self->orders); + return 0; +} + +static int tolua_unit_get_items(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + + item ** item_ptr = (item **)lua_newuserdata(L, sizeof(item *)); + + luaL_getmetatable(L, TOLUA_CAST "item"); + lua_setmetatable(L, -2); + + *item_ptr = self->items; + + lua_pushcclosure(L, tolua_itemlist_next, 1); + + return 1; +} + +static int tolua_unit_get_spells(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + sc_mage * mage = get_mage(self); + + if (mage) { + spell_list ** slist = get_spelllist(mage, self->faction); + assert(slist); + if (slist) { + spell_list ** spell_ptr = (spell_list **)lua_newuserdata(L, sizeof(spell_list *)); + luaL_getmetatable(L, TOLUA_CAST "spell_list"); + lua_setmetatable(L, -2); + + *spell_ptr = *slist; + lua_pushcclosure(L, tolua_spelllist_next, 1); + return 1; + } + } + + lua_pushnil(L); + return 1; +} + +static int tolua_unit_get_orders(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + + order ** order_ptr = (order **)lua_newuserdata(L, sizeof(order *)); + + luaL_getmetatable(L, TOLUA_CAST "order"); + lua_setmetatable(L, -2); + + *order_ptr = self->orders; + + lua_pushcclosure(L, tolua_orderlist_next, 1); + + return 1; +} + +static int tolua_unit_get_flag(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + int flag = atoi36(name); + attrib * a = find_key(self->attribs, flag); + lua_pushboolean(L, (a!=NULL)); + return 1; +} + +static int tolua_unit_set_flag(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + int value = (int)tolua_tonumber(L, 3, 0); + int flag = atoi36(name); + attrib * a = find_key(self->attribs, flag); + if (a==NULL && value) { + add_key(&self->attribs, flag); + } else if (a!=NULL && !value) { + a_remove(&self->attribs, a); + } + return 0; +} + +static int tolua_unit_get_weight(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)unit_getweight(self)); + return 1; +} + +static int tolua_unit_get_capacity(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)unit_getcapacity(self)); + return 1; +} + +static int tolua_unit_get_faction(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, (void*)self->faction, TOLUA_CAST "faction"); + return 1; +} + +static int tolua_unit_set_faction(lua_State* L) +{ + unit * self = (unit*) tolua_tousertype(L, 1, 0); + faction * f = (faction *)tolua_tousertype(L, 2, 0); + u_setfaction(self, f); + return 0; +} + +static int tolua_unit_get_race(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->race->_name[0]); + return 1; +} + +static int tolua_unit_set_race(lua_State* L) +{ + unit * self = (unit*) tolua_tousertype(L, 1, 0); + const char * rcname = tolua_tostring(L, 2, 0); + race * rc = rc_find(rcname); + if (rc!=NULL) { + if (count_unit(self)) --self->faction->no_units; + if (self->irace==self->race) self->irace = NULL; + self->race = rc; + if (count_unit(self)) --self->faction->no_units; + } + return 0; +} + +static int +tolua_unit_destroy(lua_State* L) +{ + unit * self = (unit *)tolua_tousertype(L, 1, 0); + if (self) { + remove_unit(&self->region->units, self); + } + return 0; +} + +static int +tolua_unit_create(lua_State* L) +{ + faction * f = (faction *)tolua_tousertype(L, 1, 0); + region * r = (region *)tolua_tousertype(L, 2, 0); + int num = (int)tolua_tonumber(L, 3, 1); + if (f && r) { + const race * rc = f->race; + const char * rcname = tolua_tostring(L, 4, NULL); + if (rcname) rc = rc_find(rcname); + if (rc) { + unit * u = create_unit(r, f, num, rc, 0, NULL, NULL); + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + return 1; + } + } + return 0; +} + +static int +tolua_unit_tostring(lua_State *L) +{ + unit * self = (unit *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, unitname(self)); + return 1; +} + +static int +tolua_event_gettype(lua_State *L) +{ + event * self = (event *)tolua_tousertype(L, 1, 0); + int index = (int)tolua_tonumber(L, 2, 0); + lua_pushstring(L, self->args[index].type); + return 1; +} + +static int +tolua_event_get(lua_State *L) +{ + struct event * self = (struct event *)tolua_tousertype(L, 1, 0); + int index = (int)tolua_tonumber(L, 2, 0); + + event_arg * arg = self->args+index; + + if (arg->type) { + if (strcmp(arg->type, "string")==0) { + tolua_pushstring(L, (const char *)arg->data.v); + } else if (strcmp(arg->type, "int")==0) { + tolua_pushnumber(L, (lua_Number)arg->data.i); + } else if (strcmp(arg->type, "float")==0) { + tolua_pushnumber(L, (lua_Number)arg->data.f); + } else { + /* this is pretty lazy */ + tolua_pushusertype(L, (void*)arg->data.v, TOLUA_CAST arg->type); + } + return 1; + } + tolua_error(L, TOLUA_CAST "invalid type argument for event", NULL); + return 0; +} + +void +tolua_unit_open(lua_State * L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "unit"); + tolua_usertype(L, TOLUA_CAST "unit_list"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, TOLUA_CAST "event", TOLUA_CAST "event", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "event"); + { + tolua_function(L, TOLUA_CAST "get_type", &tolua_event_gettype); + tolua_function(L, TOLUA_CAST "get", &tolua_event_get); + } + tolua_endmodule(L); + + tolua_cclass(L, TOLUA_CAST "unit", TOLUA_CAST "unit", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "unit"); + { + tolua_function(L, TOLUA_CAST "__tostring", &tolua_unit_tostring); + tolua_function(L, TOLUA_CAST "create", &tolua_unit_create); + tolua_function(L, TOLUA_CAST "destroy", &tolua_unit_destroy); + + tolua_variable(L, TOLUA_CAST "name", &tolua_unit_get_name, tolua_unit_set_name); + tolua_variable(L, TOLUA_CAST "faction", &tolua_unit_get_faction, tolua_unit_set_faction); + tolua_variable(L, TOLUA_CAST "id", &tolua_unit_get_id, tolua_unit_set_id); + tolua_variable(L, TOLUA_CAST "info", &tolua_unit_get_info, tolua_unit_set_info); + tolua_variable(L, TOLUA_CAST "hp", &tolua_unit_get_hp, tolua_unit_set_hp); + tolua_variable(L, TOLUA_CAST "status", &tolua_unit_get_status, tolua_unit_set_status); + tolua_variable(L, TOLUA_CAST "familiar", &tolua_unit_get_familiar, tolua_unit_set_familiar); + + tolua_variable(L, TOLUA_CAST "weight", &tolua_unit_get_weight, 0); + tolua_variable(L, TOLUA_CAST "capacity", &tolua_unit_get_capacity, 0); + + tolua_function(L, TOLUA_CAST "add_order", &tolua_unit_add_order); + tolua_function(L, TOLUA_CAST "clear_orders", &tolua_unit_clear_orders); + tolua_variable(L, TOLUA_CAST "orders", &tolua_unit_get_orders, 0); + + // key-attributes for named flags: + tolua_function(L, TOLUA_CAST "set_flag", &tolua_unit_set_flag); + tolua_function(L, TOLUA_CAST "get_flag", &tolua_unit_get_flag); + tolua_variable(L, TOLUA_CAST "flags", &tolua_unit_get_flags, &tolua_unit_set_flags); + tolua_variable(L, TOLUA_CAST "age", &tolua_unit_get_age, tolua_unit_set_age); + + // items: + tolua_function(L, TOLUA_CAST "get_item", &tolua_unit_get_item); + tolua_function(L, TOLUA_CAST "add_item", &tolua_unit_add_item); + tolua_variable(L, TOLUA_CAST "items", &tolua_unit_get_items, 0); + tolua_function(L, TOLUA_CAST "get_pooled", &tolua_unit_get_pooled); + tolua_function(L, TOLUA_CAST "use_pooled", &tolua_unit_use_pooled); + + // skills: + tolua_function(L, TOLUA_CAST "get_skill", &tolua_unit_getskill); + tolua_function(L, TOLUA_CAST "eff_skill", &tolua_unit_effskill); + tolua_function(L, TOLUA_CAST "set_skill", &tolua_unit_setskill); + + tolua_function(L, TOLUA_CAST "add_notice", &tolua_unit_addnotice); + + // npc logic: + tolua_function(L, TOLUA_CAST "add_handler", &tolua_unit_addhandler); + + tolua_variable(L, TOLUA_CAST "race_name", &tolua_unit_get_racename, &tolua_unit_set_racename); + tolua_function(L, TOLUA_CAST "add_spell", &tolua_unit_addspell); + tolua_function(L, TOLUA_CAST "remove_spell", &tolua_unit_removespell); + tolua_function(L, TOLUA_CAST "cast_spell", &tolua_unit_castspell); + + tolua_variable(L, TOLUA_CAST "magic", &tolua_unit_get_magic, tolua_unit_set_magic); + tolua_variable(L, TOLUA_CAST "aura", &tolua_unit_get_aura, tolua_unit_set_aura); + tolua_variable(L, TOLUA_CAST "building", &tolua_unit_get_building, tolua_unit_set_building); + tolua_variable(L, TOLUA_CAST "ship", &tolua_unit_get_ship, tolua_unit_set_ship); + tolua_variable(L, TOLUA_CAST "region", &tolua_unit_get_region, tolua_unit_set_region); + tolua_variable(L, TOLUA_CAST "spells", &tolua_unit_get_spells, 0); + tolua_variable(L, TOLUA_CAST "number", &tolua_unit_get_number, tolua_unit_set_number); + tolua_variable(L, TOLUA_CAST "race", &tolua_unit_get_race, tolua_unit_set_race); + tolua_variable(L, TOLUA_CAST "hp_max", &tolua_unit_get_hpmax, 0); + + tolua_variable(L, TOLUA_CAST "objects", &tolua_unit_get_objects, 0); + tolua_variable(L, TOLUA_CAST "attribs", &tolua_unit_get_attribs, 0); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_unit.h b/src/bindings/bind_unit.h index 767f4bfd6..011e17af0 100644 --- a/src/bindings/bind_unit.h +++ b/src/bindings/bind_unit.h @@ -1,26 +1,26 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - int tolua_unitlist_nextb(struct lua_State *L); - int tolua_unitlist_nexts(struct lua_State *L); - int tolua_unitlist_nextf(struct lua_State *L); - int tolua_unitlist_next(struct lua_State *L); - void tolua_unit_open(struct lua_State *L); - -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + int tolua_unitlist_nextb(struct lua_State *L); + int tolua_unitlist_nexts(struct lua_State *L); + int tolua_unitlist_nextf(struct lua_State *L); + int tolua_unitlist_next(struct lua_State *L); + void tolua_unit_open(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index fa1947c54..831d68477 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -1,1159 +1,1163 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include "bindings.h" -#include "bind_unit.h" -#include "bind_faction.h" -#include "bind_region.h" -#include "helpers.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -int -log_lua_error(lua_State * L) -{ - const char* error = lua_tostring(L, -1); - - log_error(("LUA call failed.\n%s\n", error)); - lua_pop(L, 1); - - return 1; -} - -int tolua_orderlist_next(lua_State *L) -{ - order** order_ptr = (order **)lua_touserdata(L, lua_upvalueindex(1)); - order* ord = *order_ptr; - if (ord != NULL) { - char cmd[8192]; - write_order(ord, cmd, sizeof(cmd)); - tolua_pushstring(L, cmd); - *order_ptr = ord->next; - return 1; - } - else return 0; /* no more values to return */ -} - -int tolua_spelllist_next(lua_State *L) -{ - spell_list** spell_ptr = (spell_list **)lua_touserdata(L, lua_upvalueindex(1)); - spell_list* slist = *spell_ptr; - if (slist != NULL) { - tolua_pushusertype(L, slist->data, TOLUA_CAST "spell"); - *spell_ptr = slist->next; - return 1; - } - else return 0; /* no more values to return */ -} - -int tolua_itemlist_next(lua_State *L) -{ - item** item_ptr = (item **)lua_touserdata(L, lua_upvalueindex(1)); - item* itm = *item_ptr; - if (itm != NULL) { - tolua_pushstring(L, itm->type->rtype->_name[0]); - *item_ptr = itm->next; - return 1; - } - else return 0; /* no more values to return */ -} - -static int -tolua_autoseed(lua_State * L) -{ - const char * filename = tolua_tostring(L, 1, 0); - int new_island = tolua_toboolean(L, 2, 0); - newfaction * players = read_newfactions(filename); - - if (players!=NULL) { - while (players) { - int n = listlen(players); - int k = (n+ISLANDSIZE-1)/ISLANDSIZE; - k = n / k; - n = autoseed(&players, k, new_island?0:TURNS_PER_ISLAND); - if (n==0) { - break; - } - } - } - return 0; -} - - -static int -tolua_getkey(lua_State* L) -{ - const char * name = tolua_tostring(L, 1, 0); - - int flag = atoi36(name); - attrib * a = find_key(global.attribs, flag); - lua_pushboolean(L, a!=NULL); - - return 1; -} - -static int -tolua_translate(lua_State* L) -{ - const char * str = tolua_tostring(L, 1, 0); - const char * lang = tolua_tostring(L, 2, 0); - struct locale * loc = lang?find_locale(lang):default_locale; - if (loc) { - str = locale_string(loc, str); - tolua_pushstring(L, str); - return 1; - } - return 0; -} - -static int -tolua_setkey(lua_State* L) -{ - const char * name = tolua_tostring(L, 1, 0); - int value = tolua_toboolean(L, 2, 0); - - int flag = atoi36(name); - attrib * a = find_key(global.attribs, flag); - if (a==NULL && value) { - add_key(&global.attribs, flag); - } else if (a!=NULL && !value) { - a_remove(&global.attribs, a); - } - - return 0; -} - -static int -tolua_rng_int(lua_State* L) -{ - lua_pushnumber(L, (lua_Number)rng_int()); - return 1; -} - -static int -tolua_read_orders(lua_State* L) -{ - const char * filename = tolua_tostring(L, 1, 0); - int result = readorders(filename); - lua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_message_unit(lua_State* L) -{ - unit * sender = (unit *)tolua_tousertype(L, 1, 0); - unit * target = (unit *)tolua_tousertype(L, 2, 0); - const char * str = tolua_tostring(L, 3, 0); - if (!target) tolua_error(L, TOLUA_CAST "target is nil", NULL); - if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); - deliverMail(target->faction, sender->region, sender, str, target); - return 0; -} - -static int -tolua_message_faction(lua_State * L) -{ - unit * sender = (unit *)tolua_tousertype(L, 1, 0); - faction * target = (faction *)tolua_tousertype(L, 2, 0); - const char * str = tolua_tostring(L, 3, 0); - if (!target) tolua_error(L, TOLUA_CAST "target is nil", NULL); - if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); - - deliverMail(target, sender->region, sender, str, NULL); - return 0; -} - -static int -tolua_message_region(lua_State * L) -{ - unit * sender = (unit *)tolua_tousertype(L, 1, 0); - const char * str = tolua_tostring(L, 2, 0); - - if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); - ADDMSG(&sender->region->msgs, msg_message("mail_result", "unit message", sender, str)); - - return 0; -} - -static int -tolua_update_guards(lua_State * L) -{ - update_guards(); - return 0; -} - -static int -tolua_set_turn(lua_State * L) -{ - turn = (int)tolua_tonumber(L, 1, 0); - return 0; -} - -static int -tolua_get_turn(lua_State * L) -{ - tolua_pushnumber(L, (lua_Number)turn); - return 1; -} - -static int -tolua_atoi36(lua_State * L) -{ - const char * s = tolua_tostring(L, 1, 0); - tolua_pushnumber(L, (lua_Number)atoi36(s)); - return 1; -} - -static int -tolua_itoa36(lua_State * L) -{ - int i = (int)tolua_tonumber(L, 1, 0); - tolua_pushstring(L, itoa36(i)); - return 1; -} - -static int -tolua_dice_rand(lua_State * L) -{ - const char * s = tolua_tostring(L, 1, 0); - tolua_pushnumber(L, dice_rand(s)); - return 1; -} - -static int -tolua_addequipment(lua_State * L) -{ - const char * eqname = tolua_tostring(L, 1, 0); - const char * iname = tolua_tostring(L, 2, 0); - const char * value = tolua_tostring(L, 3, 0); - int result = -1; - if (iname!=NULL) { - const struct item_type * itype = it_find(iname); - if (itype!=NULL) { - equipment_setitem(create_equipment(eqname), itype, value); - result = 0; - } - } - lua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_get_season(lua_State * L) -{ - int turnno = (int)tolua_tonumber(L, 1, 0); - gamedate gd; - get_gamedate(turnno, &gd); - tolua_pushstring(L, seasonnames[gd.season]); - return 1; -} - -static int -tolua_create_curse(lua_State * L) -{ - unit * u = (unit *)tolua_tousertype(L, 1, 0); - tolua_Error tolua_err; - attrib ** ap = NULL; - - if (tolua_isusertype(L, 2, TOLUA_CAST "unit", 0, &tolua_err)) { - unit * target = (unit *)tolua_tousertype(L, 2, 0); - if (target) ap = &target->attribs; - } else if (tolua_isusertype(L, 2, TOLUA_CAST "region", 0, &tolua_err)) { - region * target = (region *)tolua_tousertype(L, 2, 0); - if (target) ap = &target->attribs; - } else if (tolua_isusertype(L, 2, TOLUA_CAST "ship", 0, &tolua_err)) { - ship * target = (ship *)tolua_tousertype(L, 2, 0); - if (target) ap = &target->attribs; - } else if (tolua_isusertype(L, 2, TOLUA_CAST "building", 0, &tolua_err)) { - building * target = (building *)tolua_tousertype(L, 2, 0); - if (target) ap = &target->attribs; - } - if (ap) { - const char * cname = tolua_tostring(L, 3, 0); - const curse_type * ctype = ct_find(cname); - if (ctype) { - double vigour = tolua_tonumber(L, 4, 0); - int duration = (int)tolua_tonumber(L, 5, 0); - double effect = tolua_tonumber(L, 6, 0); - int men = (int)tolua_tonumber(L, 7, 0); /* optional */ - curse * c = create_curse(u, ap, ctype, vigour, duration, effect, men); - - if (c) { - tolua_pushboolean(L, true); - return 1; - } - } - } - tolua_pushboolean(L, false); - return 1; -} - -static int -tolua_learn_skill(lua_State * L) -{ - unit * u = (unit *)tolua_tousertype(L, 1, 0); - const char * skname = tolua_tostring(L, 2, 0); - float chances = (float)tolua_tonumber(L, 3, 0); - skill_t sk = sk_find(skname); - if (sk!=NOSKILL) { - learn_skill(u, sk, chances); - } - return 0; -} - -static int -tolua_update_scores(lua_State * L) -{ - score(); - return 0; -} - -static int -tolua_update_owners(lua_State * L) -{ - region * r; - for (r=regions;r;r=r->next) { - update_owners(r); - } - return 0; -} - -static int -tolua_update_subscriptions(lua_State * L) -{ - update_subscriptions(); - return 0; -} - -static int -tolua_remove_empty_units(lua_State * L) -{ - remove_empty_units(); - return 0; -} - -static int -tolua_get_nmrs(lua_State * L) -{ - int result = -1; - int n = (int)tolua_tonumber(L, 1, 0); - if (n>=0 && n<=NMRTimeout()) { - if (nmrs==NULL) { - update_nmrs(); - } - result = nmrs[n]; - } - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_equipunit(lua_State * L) -{ - unit * u = (unit *)tolua_tousertype(L, 1, 0); - const char * eqname = tolua_tostring(L, 2, 0); - - equip_unit(u, get_equipment(eqname)); - - return 0; -} - -static int -tolua_equipment_setitem(lua_State * L) -{ - int result = -1; - const char * eqname = tolua_tostring(L, 1, 0); - const char * iname = tolua_tostring(L, 2, 0); - const char * value = tolua_tostring(L, 3, 0); - if (iname!=NULL) { - const struct item_type * itype = it_find(iname); - if (itype!=NULL) { - equipment_setitem(create_equipment(eqname), itype, value); - result = 0; - } - } - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -#ifdef TODO_FOSS -static int -tolua_levitate_ship(lua_State * L) -{ - ship * sh = (ship *)tolua_tousertype(L, 1, 0); - unit * mage = (unit *)tolua_tousertype(L, 2, 0); - double power = (double)tolua_tonumber(L, 3, 0); - int duration = (int)tolua_tonumber(L, 4, 0); - int cno = levitate_ship(sh, mage, power, duration); - tolua_pushnumber(L, (lua_Number)cno); - return 1; -} -#endif - -static int -tolua_spawn_braineaters(lua_State * L) -{ - float chance = (float)tolua_tonumber(L, 1, 0); - spawn_braineaters(chance); - return 0; -} - -static int -tolua_init_reports(lua_State* L) -{ - int result = init_reports(); - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_write_report(lua_State* L) -{ - faction * f = (faction * )tolua_tousertype(L, 1, 0); - time_t ltime = time(0); - int result = write_reports(f, ltime); - - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_write_reports(lua_State* L) -{ - int result; - - init_reports(); - result = reports(); - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static void -reset_game(void) -{ - region * r; - faction * f; - for (r=regions;r;r=r->next) { - unit * u; - building * b; - r->flags &= RF_SAVEMASK; - for (u=r->units;u;u=u->next) { - u->flags &= UFL_SAVEMASK; - } - for (b=r->buildings;b;b=b->next) { - b->flags &= BLD_SAVEMASK; - } - - if (r->land && r->land->ownership && r->land->ownership->owner) { - faction * owner = r->land->ownership->owner; - if (owner==get_monsters()) { - /* some compat-fix, i believe. */ - owner = update_owners(r); - } - if (owner) { - fset(r, RF_GUARDED); - } - } - } - for (f=factions;f;f=f->next) { - f->flags &= FFL_SAVEMASK; - } -} - -static int -tolua_process_orders(lua_State* L) -{ - ++turn; - reset_game(); - processorders(); - return 0; -} - -static int -tolua_write_passwords(lua_State* L) -{ - int result = writepasswd(); - lua_pushnumber(L, (lua_Number)result); - return 0; -} - -static struct summary * sum_begin = 0; - -static int -tolua_init_summary(lua_State* L) -{ - sum_begin = make_summary(); - return 0; -} - -static int -tolua_write_summary(lua_State* L) -{ - if (sum_begin) { - struct summary * sum_end = make_summary(); - report_summary(sum_end, sum_begin, false); - report_summary(sum_end, sum_begin, true); - return 0; - } - return 0; -} - -static int -tolua_free_game(lua_State* L) -{ - free_gamedata(); - return 0; -} - -static int -tolua_write_map(lua_State* L) -{ - const char * filename = tolua_tostring(L, 1, 0); - if (filename) { - crwritemap(filename); - } - return 0; -} - -static int -tolua_write_game(lua_State* L) -{ - const char * filename = tolua_tostring(L, 1, 0); - const char * mode = tolua_tostring(L, 2, 0); - - int result, m = IO_BINARY; - if (mode && strcmp(mode, "text")==0) m = IO_TEXT; - remove_empty_factions(); - result = writegame(filename, m); - - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_read_game(lua_State* L) -{ - const char * filename = tolua_tostring(L, 1, 0); - const char * mode = tolua_tostring(L, 2, 0); - - int rv, m = IO_BINARY; - if (mode && strcmp(mode, "text")==0) m = IO_TEXT; - rv = readgame(filename, m, false); - - tolua_pushnumber(L, (lua_Number)rv); - return 1; -} - -static int -tolua_read_turn(lua_State* L) -{ - int cturn = current_turn(); - tolua_pushnumber(L, (lua_Number)cturn); - return 1; -} - -static int -tolua_get_faction(lua_State* L) -{ - int no = tolua_toid(L, 1, 0); - faction * f = findfaction(no); - - tolua_pushusertype(L, f, TOLUA_CAST "faction"); - return 1; -} - -static int -tolua_get_region(lua_State* L) -{ - int x = (int)tolua_tonumber(L, 1, 0); - int y = (int)tolua_tonumber(L, 2, 0); - region * r; - - assert(!pnormalize(&x, &y, findplane(x, y))); - r = findregion(x, y); - - tolua_pushusertype(L, r, TOLUA_CAST "region"); - return 1; -} - -static int -tolua_get_region_byid(lua_State* L) -{ - int uid = (int)tolua_tonumber(L, 1, 0); - region * r = findregionbyid(uid); - - tolua_pushusertype(L, r, TOLUA_CAST "region"); - return 1; -} - -static int -tolua_get_building(lua_State* L) -{ - int no = tolua_toid(L, 1, 0); - building * b = findbuilding(no); - - tolua_pushusertype(L, b, TOLUA_CAST "building"); - return 1; -} - -static int -tolua_get_ship(lua_State* L) -{ - int no = tolua_toid(L, 1, 0); - ship * sh = findship(no); - - tolua_pushusertype(L, sh, TOLUA_CAST "ship"); - return 1; -} - -static int -tolua_get_alliance(lua_State* L) -{ - int no = tolua_toid(L, 1, 0); - alliance * f = findalliance(no); - - tolua_pushusertype(L, f, TOLUA_CAST "alliance"); - return 1; -} - -static int -tolua_get_unit(lua_State* L) -{ - int no = tolua_toid(L, 1, 0); - unit * u = findunit(no); - - tolua_pushusertype(L, u, TOLUA_CAST "unit"); - return 1; -} - -static int -tolua_alliance_create(lua_State* L) -{ - int id = (int)tolua_tonumber(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - - alliance * alli = makealliance(id, name); - - tolua_pushusertype(L, alli, TOLUA_CAST "alliance"); - return 1; -} - -static int -tolua_get_regions(lua_State* L) -{ - region ** region_ptr = (region**)lua_newuserdata(L, sizeof(region *)); - - luaL_getmetatable(L, "region"); - lua_setmetatable(L, -2); - - *region_ptr = regions; - - lua_pushcclosure(L, tolua_regionlist_next, 1); - return 1; -} - -static int -tolua_get_factions(lua_State* L) -{ - faction ** faction_ptr = (faction**)lua_newuserdata(L, sizeof(faction *)); - - luaL_getmetatable(L, "faction"); - lua_setmetatable(L, -2); - - *faction_ptr = factions; - - lua_pushcclosure(L, tolua_factionlist_next, 1); - return 1; -} - -static int -tolua_get_alliance_factions(lua_State* L) -{ - alliance * self = (alliance *)tolua_tousertype(L, 1, 0); - faction_list ** faction_ptr = (faction_list**)lua_newuserdata(L, sizeof(faction_list *)); - - luaL_getmetatable(L, "faction_list"); - lua_setmetatable(L, -2); - - *faction_ptr = self->members; - - lua_pushcclosure(L, tolua_factionlist_iter, 1); - return 1; -} - -static int tolua_get_alliance_id(lua_State* L) -{ - alliance* self = (alliance*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->id); - return 1; -} - -static int tolua_get_alliance_name(lua_State* L) -{ - alliance* self = (alliance*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->name); - return 1; -} - -static int tolua_set_alliance_name(lua_State* L) -{ - alliance* self = (alliance*)tolua_tousertype(L, 1, 0); - alliance_setname(self, tolua_tostring(L, 2, 0)); - return 0; -} - -#include -#include -#include -#include - -static int -tolua_write_spells(lua_State* L) -{ - spell_f fun = (spell_f)get_function("lua_castspell"); - const char * filename = "magic.xml"; - xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); - xmlNodePtr root = xmlNewNode(NULL, BAD_CAST "spells"); - spell_list * splist; - - for (splist=spells; splist; splist=splist->next) { - spell * sp = splist->data; - if (sp->sp_function!=fun) { - int combat = 0; - xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "spell"); - xmlNewProp(node, BAD_CAST "name", BAD_CAST sp->sname); - xmlNewProp(node, BAD_CAST "type", BAD_CAST magic_school[sp->magietyp]); - xmlNewProp(node, BAD_CAST "rank", xml_i(sp->rank)); - xmlNewProp(node, BAD_CAST "level", xml_i(sp->level)); - xmlNewProp(node, BAD_CAST "index", xml_i(sp->id)); - if (sp->syntax) xmlNewProp(node, BAD_CAST "syntax", BAD_CAST sp->syntax); - if (sp->parameter) xmlNewProp(node, BAD_CAST "parameters", BAD_CAST sp->parameter); - if (sp->components) { - spell_component * comp = sp->components; - for (;comp->type!=0;++comp) { - static const char * costs[] = { "fixed", "level", "linear" }; - xmlNodePtr cnode = xmlNewNode(NULL, BAD_CAST "resource"); - xmlNewProp(cnode, BAD_CAST "name", BAD_CAST comp->type->_name[0]); - xmlNewProp(cnode, BAD_CAST "amount", xml_i(comp->amount)); - xmlNewProp(cnode, BAD_CAST "cost", BAD_CAST costs[comp->cost]); - xmlAddChild(node, cnode); - } - } - - if (sp->sptyp & TESTCANSEE) { - xmlNewProp(node, BAD_CAST "los", BAD_CAST "true"); - } - if (sp->sptyp & ONSHIPCAST) { - xmlNewProp(node, BAD_CAST "ship", BAD_CAST "true"); - } - if (sp->sptyp & OCEANCASTABLE) { - xmlNewProp(node, BAD_CAST "ocean", BAD_CAST "true"); - } - if (sp->sptyp & FARCASTING) { - xmlNewProp(node, BAD_CAST "far", BAD_CAST "true"); - } - if (sp->sptyp & SPELLLEVEL) { - xmlNewProp(node, BAD_CAST "variable", BAD_CAST "true"); - } - - if (sp->sptyp & POSTCOMBATSPELL) combat = 3; - else if (sp->sptyp & COMBATSPELL) combat = 2; - else if (sp->sptyp & PRECOMBATSPELL) combat = 1; - if (combat) { - xmlNewProp(node, BAD_CAST "combat", xml_i(combat)); - } - xmlAddChild(root, node); - } - } - xmlDocSetRootElement(doc, root); - xmlKeepBlanksDefault(0); - xmlSaveFormatFileEnc(filename, doc, "utf-8", 1); - xmlFreeDoc(doc); - return 0; -} - -static int -tolua_get_locales(lua_State *L) -{ - const struct locale * lang; - int i = 0, n = 0; - - for (lang = locales;lang;lang = nextlocale(lang)) ++n; - lua_createtable(L, n, 0); - - for (lang = locales;lang;lang = nextlocale(lang)) { - tolua_pushstring(L, TOLUA_CAST locale_name(lang)); - lua_rawseti(L, -2, ++i); - } - return 1; -} - -static int -tolua_get_spell_text(lua_State *L) -{ - const struct locale * loc = default_locale; - spell * self = (spell *)tolua_tousertype(L, 1, 0); - lua_pushstring(L, spell_info(self, loc)); - return 1; -} - -static int -tolua_get_spell_school(lua_State *L) -{ - spell * self = (spell *)tolua_tousertype(L, 1, 0); - lua_pushstring(L, magic_school[self->magietyp]); - return 1; -} - -static int -tolua_get_spell_level(lua_State *L) -{ - spell * self = (spell *)tolua_tousertype(L, 1, 0); - lua_pushnumber(L, self->level); - return 1; -} - -static int -tolua_get_spell_name(lua_State *L) -{ - const struct locale * lang = default_locale; - spell * self = (spell *)tolua_tousertype(L, 1, 0); - lua_pushstring(L, spell_name(self, lang)); - return 1; -} - -static int tolua_get_spells(lua_State* L) -{ - spell_list * slist = spells; - if (slist) { - spell_list ** spell_ptr = (spell_list **)lua_newuserdata(L, sizeof(spell_list *)); - luaL_getmetatable(L, "spell_list"); - lua_setmetatable(L, -2); - - *spell_ptr = slist; - lua_pushcclosure(L, tolua_spelllist_next, 1); - return 1; - } - - lua_pushnil(L); - return 1; -} - -int -tolua_read_xml(lua_State* L) -{ - const char * filename = tolua_tostring(L, 1, 0); - const char * catalog = tolua_tostring(L, 2, 0); - init_data(filename, catalog); - return 0; -} - -int tolua_process_markets(lua_State* L) { - do_markets(); - return 0; -} - -int tolua_process_produce(lua_State* L) { - region * r; - for (r=regions;r;r=r->next) { - produce(r); - } - return 0; -} - -typedef struct event_args { - int hfunction; - int hargs; - const char * sendertype; -} event_args; - -static void args_free(void * udata) -{ - free(udata); -} - -static void event_cb(void * sender, const char * event, void * udata) { - lua_State * L = (lua_State *)global.vm_state; - event_args * args = (event_args *)udata; - int nargs = 2; - - lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); - if (sender && args->sendertype) { - tolua_pushusertype(L, sender, TOLUA_CAST args->sendertype); - } else { - lua_pushnil(L); - } - tolua_pushstring(L, event); - if (args->hargs) { - lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); - ++nargs; - } - lua_pcall(L, nargs, 0, 0); -} - -static int -tolua_eventbus_register(lua_State * L) -{ - /* parameters: - ** 1: sender (usertype) - ** 2: event (string) - ** 3: handler (function) - ** 4: arguments (any, *optional*) - */ - void * sender = tolua_tousertype(L, 1, 0); - const char * event = tolua_tostring(L, 2, 0); - event_args * args = malloc(sizeof(event_args)); - - args->sendertype = sender?tolua_typename(L, 1):NULL; - lua_pushvalue(L, 3); - args->hfunction = luaL_ref(L, LUA_REGISTRYINDEX); - if (lua_type(L, 4)!=LUA_TNONE) { - lua_pushvalue(L, 4); - args->hargs = luaL_ref(L, LUA_REGISTRYINDEX); - } else { - args->hargs = 0; - } - eventbus_register(sender, event, &event_cb, &args_free, args); - return 0; -} - -static int -tolua_eventbus_fire(lua_State * L) -{ - void * sender = tolua_tousertype(L, 1, 0); - const char * event = tolua_tostring(L, 2, 0); - void * args = NULL; - eventbus_fire(sender, event, args); - return 0; -} - -static void -parse_inifile(lua_State* L, dictionary * d, const char * section) -{ - int i; - size_t len = strlen(section); - for (i=0;d && i!=d->n;++i) { - const char * key = d->key[i]; - - if (strncmp(section, key, len)==0 && key[len]==':') { - const char * str_value = d->val[i]; - char * endp; - double num_value = strtod(str_value, &endp); - lua_pushstring(L, key + len + 1); - if (*endp) { - tolua_pushstring(L, str_value); - } else { - tolua_pushnumber(L, num_value); - } - lua_rawset(L,-3); - } - } - /* special case */ - lua_pushstring(L, "basepath"); - lua_pushstring(L, basepath()); - lua_rawset(L,-3); -} - -int -tolua_eressea_open(lua_State* L) -{ - tolua_open(L); - - /* register user types */ - tolua_usertype(L, TOLUA_CAST "spell"); - tolua_usertype(L, TOLUA_CAST "spell_list"); - tolua_usertype(L, TOLUA_CAST "order"); - tolua_usertype(L, TOLUA_CAST "item"); - tolua_usertype(L, TOLUA_CAST "alliance"); - tolua_usertype(L, TOLUA_CAST "event"); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_module(L, "process", 0); - tolua_beginmodule(L, "process"); - { - tolua_function(L, "markets", &tolua_process_markets); - tolua_function(L, "produce", &tolua_process_produce); - } - tolua_endmodule(L); - - tolua_cclass(L, TOLUA_CAST "alliance", TOLUA_CAST "alliance", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "alliance"); - { - tolua_variable(L, TOLUA_CAST "name", tolua_get_alliance_name, tolua_set_alliance_name); - tolua_variable(L, TOLUA_CAST "id", tolua_get_alliance_id, NULL); - tolua_variable(L, TOLUA_CAST "factions", &tolua_get_alliance_factions, NULL); - tolua_function(L, TOLUA_CAST "create", tolua_alliance_create); - } - tolua_endmodule(L); - - tolua_cclass(L, TOLUA_CAST "spell", TOLUA_CAST "spell", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "spell"); - { - tolua_function(L, TOLUA_CAST "__tostring", tolua_get_spell_name); - tolua_variable(L, TOLUA_CAST "name", tolua_get_spell_name, 0); - tolua_variable(L, TOLUA_CAST "school", tolua_get_spell_school, 0); - tolua_variable(L, TOLUA_CAST "level", tolua_get_spell_level, 0); - tolua_variable(L, TOLUA_CAST "text", tolua_get_spell_text, 0); - } - tolua_endmodule(L); - - tolua_module(L, TOLUA_CAST "eventbus", 1); - tolua_beginmodule(L, TOLUA_CAST "eventbus"); - { - tolua_function(L, TOLUA_CAST "register", &tolua_eventbus_register); - tolua_function(L, TOLUA_CAST "fire", &tolua_eventbus_fire); - } - tolua_endmodule(L); - - tolua_module(L, TOLUA_CAST "config", 1); - tolua_beginmodule(L, TOLUA_CAST "config"); - { - parse_inifile(L, global.inifile, "config"); - tolua_variable(L, TOLUA_CAST "locales", &tolua_get_locales, 0); - } - tolua_endmodule(L); - - tolua_function(L, TOLUA_CAST "get_region_by_id", tolua_get_region_byid); - tolua_function(L, TOLUA_CAST "get_faction", tolua_get_faction); - tolua_function(L, TOLUA_CAST "get_unit", tolua_get_unit); - tolua_function(L, TOLUA_CAST "get_alliance", tolua_get_alliance); - tolua_function(L, TOLUA_CAST "get_ship", tolua_get_ship), - tolua_function(L, TOLUA_CAST "get_building", tolua_get_building), - tolua_function(L, TOLUA_CAST "get_region", tolua_get_region), - - // deprecated_function(L, TOLUA_CAST "add_faction"); - // deprecated_function(L, TOLUA_CAST "faction_origin"); - tolua_function(L, TOLUA_CAST "factions", tolua_get_factions); - tolua_function(L, TOLUA_CAST "regions", tolua_get_regions); - - tolua_function(L, TOLUA_CAST "read_turn", tolua_read_turn); - tolua_function(L, TOLUA_CAST "read_game", tolua_read_game); - tolua_function(L, TOLUA_CAST "write_game", tolua_write_game); - tolua_function(L, TOLUA_CAST "free_game", tolua_free_game); - tolua_function(L, TOLUA_CAST "write_map", &tolua_write_map); - - tolua_function(L, TOLUA_CAST "read_orders", tolua_read_orders); - tolua_function(L, TOLUA_CAST "process_orders", tolua_process_orders); - - tolua_function(L, TOLUA_CAST "init_reports", tolua_init_reports); - tolua_function(L, TOLUA_CAST "write_reports", tolua_write_reports); - tolua_function(L, TOLUA_CAST "write_report", tolua_write_report); - - tolua_function(L, TOLUA_CAST "init_summary", tolua_init_summary); - tolua_function(L, TOLUA_CAST "write_summary", tolua_write_summary); - tolua_function(L, TOLUA_CAST "write_passwords", tolua_write_passwords), - - tolua_function(L, TOLUA_CAST "message_unit", tolua_message_unit); - tolua_function(L, TOLUA_CAST "message_faction", tolua_message_faction); - tolua_function(L, TOLUA_CAST "message_region", tolua_message_region); - - /* scripted monsters */ - tolua_function(L, TOLUA_CAST "spawn_braineaters", tolua_spawn_braineaters); - -#ifdef TODO_FOSS - /* spells and stuff */ - tolua_function(L, TOLUA_CAST "levitate_ship", tolua_levitate_ship); -#endif - - tolua_function(L, TOLUA_CAST "update_guards", tolua_update_guards); - - tolua_function(L, TOLUA_CAST "set_turn", &tolua_set_turn); - tolua_function(L, TOLUA_CAST "get_turn", &tolua_get_turn); - tolua_function(L, TOLUA_CAST "get_season", tolua_get_season); - - tolua_function(L, TOLUA_CAST "equipment_setitem", tolua_equipment_setitem); - tolua_function(L, TOLUA_CAST "equip_unit", tolua_equipunit); - tolua_function(L, TOLUA_CAST "add_equipment", tolua_addequipment); - - tolua_function(L, TOLUA_CAST "atoi36", tolua_atoi36); - tolua_function(L, TOLUA_CAST "itoa36", tolua_itoa36); - tolua_function(L, TOLUA_CAST "dice_roll", tolua_dice_rand); - - tolua_function(L, TOLUA_CAST "get_nmrs", tolua_get_nmrs); - tolua_function(L, TOLUA_CAST "remove_empty_units", tolua_remove_empty_units); - - tolua_function(L, TOLUA_CAST "update_subscriptions", tolua_update_subscriptions); - tolua_function(L, TOLUA_CAST "update_scores", tolua_update_scores); - tolua_function(L, TOLUA_CAST "update_owners", tolua_update_owners); - - tolua_function(L, TOLUA_CAST "learn_skill", tolua_learn_skill); - tolua_function(L, TOLUA_CAST "create_curse", tolua_create_curse); - - tolua_function(L, TOLUA_CAST "autoseed", tolua_autoseed); - - tolua_function(L, TOLUA_CAST "get_key", tolua_getkey); - tolua_function(L, TOLUA_CAST "set_key", tolua_setkey); - - tolua_function(L, TOLUA_CAST "translate", &tolua_translate); - - tolua_function(L, TOLUA_CAST "rng_int", tolua_rng_int); - - tolua_function(L, TOLUA_CAST "spells", tolua_get_spells); - tolua_function(L, TOLUA_CAST "write_spells", tolua_write_spells); - - tolua_function(L, TOLUA_CAST "read_xml", tolua_read_xml); - - } - tolua_endmodule(L); - return 1; -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bindings.h" +#include "bind_unit.h" +#include "bind_faction.h" +#include "bind_region.h" +#include "helpers.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +int +log_lua_error(lua_State * L) +{ + const char* error = lua_tostring(L, -1); + + log_error(("LUA call failed.\n%s\n", error)); + lua_pop(L, 1); + + return 1; +} + +int tolua_orderlist_next(lua_State *L) +{ + order** order_ptr = (order **)lua_touserdata(L, lua_upvalueindex(1)); + order* ord = *order_ptr; + if (ord != NULL) { + char cmd[8192]; + write_order(ord, cmd, sizeof(cmd)); + tolua_pushstring(L, cmd); + *order_ptr = ord->next; + return 1; + } + else return 0; /* no more values to return */ +} + +int tolua_spelllist_next(lua_State *L) +{ + spell_list** spell_ptr = (spell_list **)lua_touserdata(L, lua_upvalueindex(1)); + spell_list* slist = *spell_ptr; + if (slist != NULL) { + tolua_pushusertype(L, slist->data, TOLUA_CAST "spell"); + *spell_ptr = slist->next; + return 1; + } + else return 0; /* no more values to return */ +} + +int tolua_itemlist_next(lua_State *L) +{ + item** item_ptr = (item **)lua_touserdata(L, lua_upvalueindex(1)); + item* itm = *item_ptr; + if (itm != NULL) { + tolua_pushstring(L, itm->type->rtype->_name[0]); + *item_ptr = itm->next; + return 1; + } + else return 0; /* no more values to return */ +} + +static int +tolua_autoseed(lua_State * L) +{ + const char * filename = tolua_tostring(L, 1, 0); + int new_island = tolua_toboolean(L, 2, 0); + newfaction * players = read_newfactions(filename); + + if (players!=NULL) { + while (players) { + int n = listlen(players); + int k = (n+ISLANDSIZE-1)/ISLANDSIZE; + k = n / k; + n = autoseed(&players, k, new_island?0:TURNS_PER_ISLAND); + if (n==0) { + break; + } + } + } + return 0; +} + + +static int +tolua_getkey(lua_State* L) +{ + const char * name = tolua_tostring(L, 1, 0); + + int flag = atoi36(name); + attrib * a = find_key(global.attribs, flag); + lua_pushboolean(L, a!=NULL); + + return 1; +} + +static int +tolua_translate(lua_State* L) +{ + const char * str = tolua_tostring(L, 1, 0); + const char * lang = tolua_tostring(L, 2, 0); + struct locale * loc = lang?find_locale(lang):default_locale; + if (loc) { + str = locale_string(loc, str); + tolua_pushstring(L, str); + return 1; + } + return 0; +} + +static int +tolua_setkey(lua_State* L) +{ + const char * name = tolua_tostring(L, 1, 0); + int value = tolua_toboolean(L, 2, 0); + + int flag = atoi36(name); + attrib * a = find_key(global.attribs, flag); + if (a==NULL && value) { + add_key(&global.attribs, flag); + } else if (a!=NULL && !value) { + a_remove(&global.attribs, a); + } + + return 0; +} + +static int +tolua_rng_int(lua_State* L) +{ + lua_pushnumber(L, (lua_Number)rng_int()); + return 1; +} + +static int +tolua_read_orders(lua_State* L) +{ + const char * filename = tolua_tostring(L, 1, 0); + int result = readorders(filename); + lua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_message_unit(lua_State* L) +{ + unit * sender = (unit *)tolua_tousertype(L, 1, 0); + unit * target = (unit *)tolua_tousertype(L, 2, 0); + const char * str = tolua_tostring(L, 3, 0); + if (!target) tolua_error(L, TOLUA_CAST "target is nil", NULL); + if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); + deliverMail(target->faction, sender->region, sender, str, target); + return 0; +} + +static int +tolua_message_faction(lua_State * L) +{ + unit * sender = (unit *)tolua_tousertype(L, 1, 0); + faction * target = (faction *)tolua_tousertype(L, 2, 0); + const char * str = tolua_tostring(L, 3, 0); + if (!target) tolua_error(L, TOLUA_CAST "target is nil", NULL); + if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); + + deliverMail(target, sender->region, sender, str, NULL); + return 0; +} + +static int +tolua_message_region(lua_State * L) +{ + unit * sender = (unit *)tolua_tousertype(L, 1, 0); + const char * str = tolua_tostring(L, 2, 0); + + if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); + ADDMSG(&sender->region->msgs, msg_message("mail_result", "unit message", sender, str)); + + return 0; +} + +static int +tolua_update_guards(lua_State * L) +{ + update_guards(); + return 0; +} + +static int +tolua_set_turn(lua_State * L) +{ + turn = (int)tolua_tonumber(L, 1, 0); + return 0; +} + +static int +tolua_get_turn(lua_State * L) +{ + tolua_pushnumber(L, (lua_Number)turn); + return 1; +} + +static int +tolua_atoi36(lua_State * L) +{ + const char * s = tolua_tostring(L, 1, 0); + tolua_pushnumber(L, (lua_Number)atoi36(s)); + return 1; +} + +static int +tolua_itoa36(lua_State * L) +{ + int i = (int)tolua_tonumber(L, 1, 0); + tolua_pushstring(L, itoa36(i)); + return 1; +} + +static int +tolua_dice_rand(lua_State * L) +{ + const char * s = tolua_tostring(L, 1, 0); + tolua_pushnumber(L, dice_rand(s)); + return 1; +} + +static int +tolua_addequipment(lua_State * L) +{ + const char * eqname = tolua_tostring(L, 1, 0); + const char * iname = tolua_tostring(L, 2, 0); + const char * value = tolua_tostring(L, 3, 0); + int result = -1; + if (iname!=NULL) { + const struct item_type * itype = it_find(iname); + if (itype!=NULL) { + equipment_setitem(create_equipment(eqname), itype, value); + result = 0; + } + } + lua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_get_season(lua_State * L) +{ + int turnno = (int)tolua_tonumber(L, 1, 0); + gamedate gd; + get_gamedate(turnno, &gd); + tolua_pushstring(L, seasonnames[gd.season]); + return 1; +} + +static int +tolua_create_curse(lua_State * L) +{ + unit * u = (unit *)tolua_tousertype(L, 1, 0); + tolua_Error tolua_err; + attrib ** ap = NULL; + + if (tolua_isusertype(L, 2, TOLUA_CAST "unit", 0, &tolua_err)) { + unit * target = (unit *)tolua_tousertype(L, 2, 0); + if (target) ap = &target->attribs; + } else if (tolua_isusertype(L, 2, TOLUA_CAST "region", 0, &tolua_err)) { + region * target = (region *)tolua_tousertype(L, 2, 0); + if (target) ap = &target->attribs; + } else if (tolua_isusertype(L, 2, TOLUA_CAST "ship", 0, &tolua_err)) { + ship * target = (ship *)tolua_tousertype(L, 2, 0); + if (target) ap = &target->attribs; + } else if (tolua_isusertype(L, 2, TOLUA_CAST "building", 0, &tolua_err)) { + building * target = (building *)tolua_tousertype(L, 2, 0); + if (target) ap = &target->attribs; + } + if (ap) { + const char * cname = tolua_tostring(L, 3, 0); + const curse_type * ctype = ct_find(cname); + if (ctype) { + double vigour = tolua_tonumber(L, 4, 0); + int duration = (int)tolua_tonumber(L, 5, 0); + double effect = tolua_tonumber(L, 6, 0); + int men = (int)tolua_tonumber(L, 7, 0); /* optional */ + curse * c = create_curse(u, ap, ctype, vigour, duration, effect, men); + + if (c) { + tolua_pushboolean(L, true); + return 1; + } + } + } + tolua_pushboolean(L, false); + return 1; +} + +static int +tolua_learn_skill(lua_State * L) +{ + unit * u = (unit *)tolua_tousertype(L, 1, 0); + const char * skname = tolua_tostring(L, 2, 0); + float chances = (float)tolua_tonumber(L, 3, 0); + skill_t sk = sk_find(skname); + if (sk!=NOSKILL) { + learn_skill(u, sk, chances); + } + return 0; +} + +static int +tolua_update_scores(lua_State * L) +{ + score(); + return 0; +} + +static int +tolua_update_owners(lua_State * L) +{ + region * r; + for (r=regions;r;r=r->next) { + update_owners(r); + } + return 0; +} + +static int +tolua_update_subscriptions(lua_State * L) +{ + update_subscriptions(); + return 0; +} + +static int +tolua_remove_empty_units(lua_State * L) +{ + remove_empty_units(); + return 0; +} + +static int +tolua_get_nmrs(lua_State * L) +{ + int result = -1; + int n = (int)tolua_tonumber(L, 1, 0); + if (n>=0 && n<=NMRTimeout()) { + if (nmrs==NULL) { + update_nmrs(); + } + result = nmrs[n]; + } + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_equipunit(lua_State * L) +{ + unit * u = (unit *)tolua_tousertype(L, 1, 0); + const char * eqname = tolua_tostring(L, 2, 0); + + equip_unit(u, get_equipment(eqname)); + + return 0; +} + +static int +tolua_equipment_setitem(lua_State * L) +{ + int result = -1; + const char * eqname = tolua_tostring(L, 1, 0); + const char * iname = tolua_tostring(L, 2, 0); + const char * value = tolua_tostring(L, 3, 0); + if (iname!=NULL) { + const struct item_type * itype = it_find(iname); + if (itype!=NULL) { + equipment_setitem(create_equipment(eqname), itype, value); + result = 0; + } + } + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +#ifdef TODO_FOSS +static int +tolua_levitate_ship(lua_State * L) +{ + ship * sh = (ship *)tolua_tousertype(L, 1, 0); + unit * mage = (unit *)tolua_tousertype(L, 2, 0); + double power = (double)tolua_tonumber(L, 3, 0); + int duration = (int)tolua_tonumber(L, 4, 0); + int cno = levitate_ship(sh, mage, power, duration); + tolua_pushnumber(L, (lua_Number)cno); + return 1; +} +#endif + +static int +tolua_spawn_braineaters(lua_State * L) +{ + float chance = (float)tolua_tonumber(L, 1, 0); + spawn_braineaters(chance); + return 0; +} + +static int +tolua_init_reports(lua_State* L) +{ + int result = init_reports(); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_write_report(lua_State* L) +{ + faction * f = (faction * )tolua_tousertype(L, 1, 0); + time_t ltime = time(0); + int result = write_reports(f, ltime); + + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_write_reports(lua_State* L) +{ + int result; + + init_reports(); + result = reports(); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static void +reset_game(void) +{ + region * r; + faction * f; + for (r=regions;r;r=r->next) { + unit * u; + building * b; + r->flags &= RF_SAVEMASK; + for (u=r->units;u;u=u->next) { + u->flags &= UFL_SAVEMASK; + } + for (b=r->buildings;b;b=b->next) { + b->flags &= BLD_SAVEMASK; + } + + if (r->land && r->land->ownership && r->land->ownership->owner) { + faction * owner = r->land->ownership->owner; + if (owner==get_monsters()) { + /* some compat-fix, i believe. */ + owner = update_owners(r); + } + if (owner) { + fset(r, RF_GUARDED); + } + } + } + for (f=factions;f;f=f->next) { + f->flags &= FFL_SAVEMASK; + } +} + +static int +tolua_process_orders(lua_State* L) +{ + ++turn; + reset_game(); + processorders(); + return 0; +} + +static int +tolua_write_passwords(lua_State* L) +{ + int result = writepasswd(); + lua_pushnumber(L, (lua_Number)result); + return 0; +} + +static struct summary * sum_begin = 0; + +static int +tolua_init_summary(lua_State* L) +{ + sum_begin = make_summary(); + return 0; +} + +static int +tolua_write_summary(lua_State* L) +{ + if (sum_begin) { + struct summary * sum_end = make_summary(); + report_summary(sum_end, sum_begin, false); + report_summary(sum_end, sum_begin, true); + return 0; + } + return 0; +} + +static int +tolua_free_game(lua_State* L) +{ + free_gamedata(); + return 0; +} + +static int +tolua_write_map(lua_State* L) +{ + const char * filename = tolua_tostring(L, 1, 0); + if (filename) { + crwritemap(filename); + } + return 0; +} + +static int +tolua_write_game(lua_State* L) +{ + const char * filename = tolua_tostring(L, 1, 0); + const char * mode = tolua_tostring(L, 2, 0); + + int result, m = IO_BINARY; + if (mode && strcmp(mode, "text")==0) m = IO_TEXT; + remove_empty_factions(); + result = writegame(filename, m); + + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_read_game(lua_State* L) +{ + const char * filename = tolua_tostring(L, 1, 0); + const char * mode = tolua_tostring(L, 2, 0); + + int rv, m = IO_BINARY; + if (mode && strcmp(mode, "text")==0) m = IO_TEXT; + rv = readgame(filename, m, false); + + tolua_pushnumber(L, (lua_Number)rv); + return 1; +} + +static int +tolua_read_turn(lua_State* L) +{ + int cturn = current_turn(); + tolua_pushnumber(L, (lua_Number)cturn); + return 1; +} + +static int +tolua_get_faction(lua_State* L) +{ + int no = tolua_toid(L, 1, 0); + faction * f = findfaction(no); + + tolua_pushusertype(L, f, TOLUA_CAST "faction"); + return 1; +} + +static int +tolua_get_region(lua_State* L) +{ + int x = (int)tolua_tonumber(L, 1, 0); + int y = (int)tolua_tonumber(L, 2, 0); + region * r; + + assert(!pnormalize(&x, &y, findplane(x, y))); + r = findregion(x, y); + + tolua_pushusertype(L, r, TOLUA_CAST "region"); + return 1; +} + +static int +tolua_get_region_byid(lua_State* L) +{ + int uid = (int)tolua_tonumber(L, 1, 0); + region * r = findregionbyid(uid); + + tolua_pushusertype(L, r, TOLUA_CAST "region"); + return 1; +} + +static int +tolua_get_building(lua_State* L) +{ + int no = tolua_toid(L, 1, 0); + building * b = findbuilding(no); + + tolua_pushusertype(L, b, TOLUA_CAST "building"); + return 1; +} + +static int +tolua_get_ship(lua_State* L) +{ + int no = tolua_toid(L, 1, 0); + ship * sh = findship(no); + + tolua_pushusertype(L, sh, TOLUA_CAST "ship"); + return 1; +} + +static int +tolua_get_alliance(lua_State* L) +{ + int no = tolua_toid(L, 1, 0); + alliance * f = findalliance(no); + + tolua_pushusertype(L, f, TOLUA_CAST "alliance"); + return 1; +} + +static int +tolua_get_unit(lua_State* L) +{ + int no = tolua_toid(L, 1, 0); + unit * u = findunit(no); + + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + return 1; +} + +static int +tolua_alliance_create(lua_State* L) +{ + int id = (int)tolua_tonumber(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + + alliance * alli = makealliance(id, name); + + tolua_pushusertype(L, alli, TOLUA_CAST "alliance"); + return 1; +} + +static int +tolua_get_regions(lua_State* L) +{ + region ** region_ptr = (region**)lua_newuserdata(L, sizeof(region *)); + + luaL_getmetatable(L, "region"); + lua_setmetatable(L, -2); + + *region_ptr = regions; + + lua_pushcclosure(L, tolua_regionlist_next, 1); + return 1; +} + +static int +tolua_get_factions(lua_State* L) +{ + faction ** faction_ptr = (faction**)lua_newuserdata(L, sizeof(faction *)); + + luaL_getmetatable(L, "faction"); + lua_setmetatable(L, -2); + + *faction_ptr = factions; + + lua_pushcclosure(L, tolua_factionlist_next, 1); + return 1; +} + +static int +tolua_get_alliance_factions(lua_State* L) +{ + alliance * self = (alliance *)tolua_tousertype(L, 1, 0); + faction_list ** faction_ptr = (faction_list**)lua_newuserdata(L, sizeof(faction_list *)); + + luaL_getmetatable(L, "faction_list"); + lua_setmetatable(L, -2); + + *faction_ptr = self->members; + + lua_pushcclosure(L, tolua_factionlist_iter, 1); + return 1; +} + +static int tolua_get_alliance_id(lua_State* L) +{ + alliance* self = (alliance*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->id); + return 1; +} + +static int tolua_get_alliance_name(lua_State* L) +{ + alliance* self = (alliance*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->name); + return 1; +} + +static int tolua_set_alliance_name(lua_State* L) +{ + alliance* self = (alliance*)tolua_tousertype(L, 1, 0); + alliance_setname(self, tolua_tostring(L, 2, 0)); + return 0; +} + +#ifdef HAVE_LIBXML +#include +#endif +#include +#include +#include + +static int +tolua_write_spells(lua_State* L) +{ +#ifdef HAVE_LIBXML + spell_f fun = (spell_f)get_function("lua_castspell"); + const char * filename = "magic.xml"; + xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); + xmlNodePtr root = xmlNewNode(NULL, BAD_CAST "spells"); + spell_list * splist; + + for (splist=spells; splist; splist=splist->next) { + spell * sp = splist->data; + if (sp->sp_function!=fun) { + int combat = 0; + xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "spell"); + xmlNewProp(node, BAD_CAST "name", BAD_CAST sp->sname); + xmlNewProp(node, BAD_CAST "type", BAD_CAST magic_school[sp->magietyp]); + xmlNewProp(node, BAD_CAST "rank", xml_i(sp->rank)); + xmlNewProp(node, BAD_CAST "level", xml_i(sp->level)); + xmlNewProp(node, BAD_CAST "index", xml_i(sp->id)); + if (sp->syntax) xmlNewProp(node, BAD_CAST "syntax", BAD_CAST sp->syntax); + if (sp->parameter) xmlNewProp(node, BAD_CAST "parameters", BAD_CAST sp->parameter); + if (sp->components) { + spell_component * comp = sp->components; + for (;comp->type!=0;++comp) { + static const char * costs[] = { "fixed", "level", "linear" }; + xmlNodePtr cnode = xmlNewNode(NULL, BAD_CAST "resource"); + xmlNewProp(cnode, BAD_CAST "name", BAD_CAST comp->type->_name[0]); + xmlNewProp(cnode, BAD_CAST "amount", xml_i(comp->amount)); + xmlNewProp(cnode, BAD_CAST "cost", BAD_CAST costs[comp->cost]); + xmlAddChild(node, cnode); + } + } + + if (sp->sptyp & TESTCANSEE) { + xmlNewProp(node, BAD_CAST "los", BAD_CAST "true"); + } + if (sp->sptyp & ONSHIPCAST) { + xmlNewProp(node, BAD_CAST "ship", BAD_CAST "true"); + } + if (sp->sptyp & OCEANCASTABLE) { + xmlNewProp(node, BAD_CAST "ocean", BAD_CAST "true"); + } + if (sp->sptyp & FARCASTING) { + xmlNewProp(node, BAD_CAST "far", BAD_CAST "true"); + } + if (sp->sptyp & SPELLLEVEL) { + xmlNewProp(node, BAD_CAST "variable", BAD_CAST "true"); + } + + if (sp->sptyp & POSTCOMBATSPELL) combat = 3; + else if (sp->sptyp & COMBATSPELL) combat = 2; + else if (sp->sptyp & PRECOMBATSPELL) combat = 1; + if (combat) { + xmlNewProp(node, BAD_CAST "combat", xml_i(combat)); + } + xmlAddChild(root, node); + } + } + xmlDocSetRootElement(doc, root); + xmlKeepBlanksDefault(0); + xmlSaveFormatFileEnc(filename, doc, "utf-8", 1); + xmlFreeDoc(doc); +#endif + return 0; +} + +static int +tolua_get_locales(lua_State *L) +{ + const struct locale * lang; + int i = 0, n = 0; + + for (lang = locales;lang;lang = nextlocale(lang)) ++n; + lua_createtable(L, n, 0); + + for (lang = locales;lang;lang = nextlocale(lang)) { + tolua_pushstring(L, TOLUA_CAST locale_name(lang)); + lua_rawseti(L, -2, ++i); + } + return 1; +} + +static int +tolua_get_spell_text(lua_State *L) +{ + const struct locale * loc = default_locale; + spell * self = (spell *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, spell_info(self, loc)); + return 1; +} + +static int +tolua_get_spell_school(lua_State *L) +{ + spell * self = (spell *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, magic_school[self->magietyp]); + return 1; +} + +static int +tolua_get_spell_level(lua_State *L) +{ + spell * self = (spell *)tolua_tousertype(L, 1, 0); + lua_pushnumber(L, self->level); + return 1; +} + +static int +tolua_get_spell_name(lua_State *L) +{ + const struct locale * lang = default_locale; + spell * self = (spell *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, spell_name(self, lang)); + return 1; +} + +static int tolua_get_spells(lua_State* L) +{ + spell_list * slist = spells; + if (slist) { + spell_list ** spell_ptr = (spell_list **)lua_newuserdata(L, sizeof(spell_list *)); + luaL_getmetatable(L, "spell_list"); + lua_setmetatable(L, -2); + + *spell_ptr = slist; + lua_pushcclosure(L, tolua_spelllist_next, 1); + return 1; + } + + lua_pushnil(L); + return 1; +} + +int +tolua_read_xml(lua_State* L) +{ + const char * filename = tolua_tostring(L, 1, 0); + const char * catalog = tolua_tostring(L, 2, 0); + init_data(filename, catalog); + return 0; +} + +int tolua_process_markets(lua_State* L) { + do_markets(); + return 0; +} + +int tolua_process_produce(lua_State* L) { + region * r; + for (r=regions;r;r=r->next) { + produce(r); + } + return 0; +} + +typedef struct event_args { + int hfunction; + int hargs; + const char * sendertype; +} event_args; + +static void args_free(void * udata) +{ + free(udata); +} + +static void event_cb(void * sender, const char * event, void * udata) { + lua_State * L = (lua_State *)global.vm_state; + event_args * args = (event_args *)udata; + int nargs = 2; + + lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); + if (sender && args->sendertype) { + tolua_pushusertype(L, sender, TOLUA_CAST args->sendertype); + } else { + lua_pushnil(L); + } + tolua_pushstring(L, event); + if (args->hargs) { + lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); + ++nargs; + } + lua_pcall(L, nargs, 0, 0); +} + +static int +tolua_eventbus_register(lua_State * L) +{ + /* parameters: + ** 1: sender (usertype) + ** 2: event (string) + ** 3: handler (function) + ** 4: arguments (any, *optional*) + */ + void * sender = tolua_tousertype(L, 1, 0); + const char * event = tolua_tostring(L, 2, 0); + event_args * args = malloc(sizeof(event_args)); + + args->sendertype = sender?tolua_typename(L, 1):NULL; + lua_pushvalue(L, 3); + args->hfunction = luaL_ref(L, LUA_REGISTRYINDEX); + if (lua_type(L, 4)!=LUA_TNONE) { + lua_pushvalue(L, 4); + args->hargs = luaL_ref(L, LUA_REGISTRYINDEX); + } else { + args->hargs = 0; + } + eventbus_register(sender, event, &event_cb, &args_free, args); + return 0; +} + +static int +tolua_eventbus_fire(lua_State * L) +{ + void * sender = tolua_tousertype(L, 1, 0); + const char * event = tolua_tostring(L, 2, 0); + void * args = NULL; + eventbus_fire(sender, event, args); + return 0; +} + +static void +parse_inifile(lua_State* L, dictionary * d, const char * section) +{ + int i; + size_t len = strlen(section); + for (i=0;d && i!=d->n;++i) { + const char * key = d->key[i]; + + if (strncmp(section, key, len)==0 && key[len]==':') { + const char * str_value = d->val[i]; + char * endp; + double num_value = strtod(str_value, &endp); + lua_pushstring(L, key + len + 1); + if (*endp) { + tolua_pushstring(L, str_value); + } else { + tolua_pushnumber(L, num_value); + } + lua_rawset(L,-3); + } + } + /* special case */ + lua_pushstring(L, "basepath"); + lua_pushstring(L, basepath()); + lua_rawset(L,-3); +} + +int +tolua_eressea_open(lua_State* L) +{ + tolua_open(L); + + /* register user types */ + tolua_usertype(L, TOLUA_CAST "spell"); + tolua_usertype(L, TOLUA_CAST "spell_list"); + tolua_usertype(L, TOLUA_CAST "order"); + tolua_usertype(L, TOLUA_CAST "item"); + tolua_usertype(L, TOLUA_CAST "alliance"); + tolua_usertype(L, TOLUA_CAST "event"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_module(L, "process", 0); + tolua_beginmodule(L, "process"); + { + tolua_function(L, "markets", &tolua_process_markets); + tolua_function(L, "produce", &tolua_process_produce); + } + tolua_endmodule(L); + + tolua_cclass(L, TOLUA_CAST "alliance", TOLUA_CAST "alliance", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "alliance"); + { + tolua_variable(L, TOLUA_CAST "name", tolua_get_alliance_name, tolua_set_alliance_name); + tolua_variable(L, TOLUA_CAST "id", tolua_get_alliance_id, NULL); + tolua_variable(L, TOLUA_CAST "factions", &tolua_get_alliance_factions, NULL); + tolua_function(L, TOLUA_CAST "create", tolua_alliance_create); + } + tolua_endmodule(L); + + tolua_cclass(L, TOLUA_CAST "spell", TOLUA_CAST "spell", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "spell"); + { + tolua_function(L, TOLUA_CAST "__tostring", tolua_get_spell_name); + tolua_variable(L, TOLUA_CAST "name", tolua_get_spell_name, 0); + tolua_variable(L, TOLUA_CAST "school", tolua_get_spell_school, 0); + tolua_variable(L, TOLUA_CAST "level", tolua_get_spell_level, 0); + tolua_variable(L, TOLUA_CAST "text", tolua_get_spell_text, 0); + } + tolua_endmodule(L); + + tolua_module(L, TOLUA_CAST "eventbus", 1); + tolua_beginmodule(L, TOLUA_CAST "eventbus"); + { + tolua_function(L, TOLUA_CAST "register", &tolua_eventbus_register); + tolua_function(L, TOLUA_CAST "fire", &tolua_eventbus_fire); + } + tolua_endmodule(L); + + tolua_module(L, TOLUA_CAST "config", 1); + tolua_beginmodule(L, TOLUA_CAST "config"); + { + parse_inifile(L, global.inifile, "config"); + tolua_variable(L, TOLUA_CAST "locales", &tolua_get_locales, 0); + } + tolua_endmodule(L); + + tolua_function(L, TOLUA_CAST "get_region_by_id", tolua_get_region_byid); + tolua_function(L, TOLUA_CAST "get_faction", tolua_get_faction); + tolua_function(L, TOLUA_CAST "get_unit", tolua_get_unit); + tolua_function(L, TOLUA_CAST "get_alliance", tolua_get_alliance); + tolua_function(L, TOLUA_CAST "get_ship", tolua_get_ship), + tolua_function(L, TOLUA_CAST "get_building", tolua_get_building), + tolua_function(L, TOLUA_CAST "get_region", tolua_get_region), + + // deprecated_function(L, TOLUA_CAST "add_faction"); + // deprecated_function(L, TOLUA_CAST "faction_origin"); + tolua_function(L, TOLUA_CAST "factions", tolua_get_factions); + tolua_function(L, TOLUA_CAST "regions", tolua_get_regions); + + tolua_function(L, TOLUA_CAST "read_turn", tolua_read_turn); + tolua_function(L, TOLUA_CAST "read_game", tolua_read_game); + tolua_function(L, TOLUA_CAST "write_game", tolua_write_game); + tolua_function(L, TOLUA_CAST "free_game", tolua_free_game); + tolua_function(L, TOLUA_CAST "write_map", &tolua_write_map); + + tolua_function(L, TOLUA_CAST "read_orders", tolua_read_orders); + tolua_function(L, TOLUA_CAST "process_orders", tolua_process_orders); + + tolua_function(L, TOLUA_CAST "init_reports", tolua_init_reports); + tolua_function(L, TOLUA_CAST "write_reports", tolua_write_reports); + tolua_function(L, TOLUA_CAST "write_report", tolua_write_report); + + tolua_function(L, TOLUA_CAST "init_summary", tolua_init_summary); + tolua_function(L, TOLUA_CAST "write_summary", tolua_write_summary); + tolua_function(L, TOLUA_CAST "write_passwords", tolua_write_passwords), + + tolua_function(L, TOLUA_CAST "message_unit", tolua_message_unit); + tolua_function(L, TOLUA_CAST "message_faction", tolua_message_faction); + tolua_function(L, TOLUA_CAST "message_region", tolua_message_region); + + /* scripted monsters */ + tolua_function(L, TOLUA_CAST "spawn_braineaters", tolua_spawn_braineaters); + +#ifdef TODO_FOSS + /* spells and stuff */ + tolua_function(L, TOLUA_CAST "levitate_ship", tolua_levitate_ship); +#endif + + tolua_function(L, TOLUA_CAST "update_guards", tolua_update_guards); + + tolua_function(L, TOLUA_CAST "set_turn", &tolua_set_turn); + tolua_function(L, TOLUA_CAST "get_turn", &tolua_get_turn); + tolua_function(L, TOLUA_CAST "get_season", tolua_get_season); + + tolua_function(L, TOLUA_CAST "equipment_setitem", tolua_equipment_setitem); + tolua_function(L, TOLUA_CAST "equip_unit", tolua_equipunit); + tolua_function(L, TOLUA_CAST "add_equipment", tolua_addequipment); + + tolua_function(L, TOLUA_CAST "atoi36", tolua_atoi36); + tolua_function(L, TOLUA_CAST "itoa36", tolua_itoa36); + tolua_function(L, TOLUA_CAST "dice_roll", tolua_dice_rand); + + tolua_function(L, TOLUA_CAST "get_nmrs", tolua_get_nmrs); + tolua_function(L, TOLUA_CAST "remove_empty_units", tolua_remove_empty_units); + + tolua_function(L, TOLUA_CAST "update_subscriptions", tolua_update_subscriptions); + tolua_function(L, TOLUA_CAST "update_scores", tolua_update_scores); + tolua_function(L, TOLUA_CAST "update_owners", tolua_update_owners); + + tolua_function(L, TOLUA_CAST "learn_skill", tolua_learn_skill); + tolua_function(L, TOLUA_CAST "create_curse", tolua_create_curse); + + tolua_function(L, TOLUA_CAST "autoseed", tolua_autoseed); + + tolua_function(L, TOLUA_CAST "get_key", tolua_getkey); + tolua_function(L, TOLUA_CAST "set_key", tolua_setkey); + + tolua_function(L, TOLUA_CAST "translate", &tolua_translate); + + tolua_function(L, TOLUA_CAST "rng_int", tolua_rng_int); + + tolua_function(L, TOLUA_CAST "spells", tolua_get_spells); + tolua_function(L, TOLUA_CAST "write_spells", tolua_write_spells); + + tolua_function(L, TOLUA_CAST "read_xml", tolua_read_xml); + + } + tolua_endmodule(L); + return 1; +} diff --git a/src/bindings/bindings.h b/src/bindings/bindings.h index 5ed8d6232..0cc1a1d42 100644 --- a/src/bindings/bindings.h +++ b/src/bindings/bindings.h @@ -1,27 +1,27 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - int tolua_sqlite_open(struct lua_State * L); - int tolua_eressea_open(struct lua_State* L); - int tolua_spelllist_next(struct lua_State *L); - int tolua_itemlist_next(struct lua_State *L); - int tolua_orderlist_next(struct lua_State *L); - - int log_lua_error(struct lua_State * L); -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + int tolua_sqlite_open(struct lua_State * L); + int tolua_eressea_open(struct lua_State* L); + int tolua_spelllist_next(struct lua_State *L); + int tolua_itemlist_next(struct lua_State *L); + int tolua_orderlist_next(struct lua_State *L); + + int log_lua_error(struct lua_State * L); +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/helpers.c b/src/bindings/helpers.c index 6395bce35..db1aaa6e9 100644 --- a/src/bindings/helpers.c +++ b/src/bindings/helpers.c @@ -1,664 +1,664 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include "helpers.h" -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include - -static int -lua_giveitem(unit * s, unit * d, const item_type * itype, int n, struct order * ord) -{ - lua_State * L = (lua_State *)global.vm_state; - char fname[64]; - int result = -1; - const char * iname = itype->rtype->_name[0]; - - assert(s!=NULL); - strcat(strcpy(fname, iname), "_give"); - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, s, TOLUA_CAST "unit"); - tolua_pushusertype(L, d, TOLUA_CAST "unit"); - tolua_pushstring(L, iname); - tolua_pushnumber(L, (lua_Number)n); - - if (lua_pcall(L, 4, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("unit %s calling '%s': %s.\n", - unitname(s), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("unit %s trying to call '%s' : not a function.\n", - unitname(s), fname)); - lua_pop(L, 1); - } - - return result; -} - -static int -limit_resource(const region * r, const resource_type * rtype) -{ - char fname[64]; - int result = -1; - lua_State * L = (lua_State *)global.vm_state; - - snprintf(fname, sizeof(fname), "%s_limit", rtype->_name[0]); - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); - - if (lua_pcall(L, 1, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("limit(%s) calling '%s': %s.\n", - regionname(r, NULL), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("limit(%s) calling '%s': not a function.\n", - regionname(r, NULL), fname)); - lua_pop(L, 1); - } - - return result; -} - -static void -produce_resource(region * r, const resource_type * rtype, int norders) -{ - lua_State * L = (lua_State *)global.vm_state; - char fname[64]; - snprintf(fname, sizeof(fname), "%s_produce", rtype->_name[0]); - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); - tolua_pushnumber(L, (lua_Number)norders); - - if (lua_pcall(L, 2, 0, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("produce(%s) calling '%s': %s.\n", - regionname(r, NULL), fname, error)); - lua_pop(L, 1); - } - } else { - log_error(("produce(%s) calling '%s': not a function.\n", - regionname(r, NULL), fname)); - lua_pop(L, 1); - } -} - - -static int -lc_age(struct attrib * a) -{ - building_action * data = (building_action*)a->data.v; - const char * fname = data->fname; - const char * fparam = data->param; - building * b = data->b; - int result = -1; - - assert(b!=NULL); - if (fname!=NULL) { - lua_State * L = (lua_State *)global.vm_state; - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); - if (fparam) { - tolua_pushstring(L, fparam); - } - - if (lua_pcall(L, fparam?2:1, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("lc_age(%s) calling '%s': %s.\n", - buildingname(b), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("lc_age(%s) calling '%s': not a function.\n", - buildingname(b), fname)); - lua_pop(L, 1); - } - } - return (result!=0)?AT_AGE_KEEP:AT_AGE_REMOVE; -} - -static void push_param(lua_State * L, char c, spllprm * param) -{ - if (c=='u') tolua_pushusertype(L, param->data.u, "unit"); - else if (c=='b') tolua_pushusertype(L, param->data.b, "building"); - else if (c=='s') tolua_pushusertype(L, param->data.sh, "ship"); - else if (c=='r') tolua_pushusertype(L, param->data.sh, "region"); - else if (c=='c') tolua_pushstring(L, param->data.s); - else { - log_error(("unsupported syntax %c.\n", c)); - lua_pushnil(L); - } -} - -/** callback to use lua for spell functions */ -static int -lua_callspell(castorder *co) -{ - lua_State * L = (lua_State *)global.vm_state; - const char * fname = co->sp->sname; - unit * mage = co->familiar?co->familiar:co->magician.u; - int result = -1; - const char * hashpos = strchr(fname, '#'); - char fbuf[64]; - - if (hashpos!=NULL) { - ptrdiff_t len = hashpos - fname; - assert(len<(ptrdiff_t)sizeof(fbuf)); - strncpy(fbuf, fname, len); - fbuf[len] = '\0'; - fname = fbuf; - } - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - int nparam = 4; - tolua_pushusertype(L, co->rt, TOLUA_CAST "region"); - tolua_pushusertype(L, mage, TOLUA_CAST "unit"); - tolua_pushnumber(L, (lua_Number)co->level); - tolua_pushnumber(L, (lua_Number)co->force); - if (co->sp->parameter && co->par->length) { - const char * synp = co->sp->parameter; - int i = 0; - ++nparam; - lua_newtable(L); - while (*synp&&ipar->length) { - spllprm * param = co->par->param[i]; - char c = *synp; - if (c=='+') { - push_param(L, *(synp-1), param); - } else { - push_param(L, c, param); - ++synp; - } - lua_rawseti(L, -2, ++i); - } - } - - if (lua_pcall(L, nparam, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("spell(%s) calling '%s': %s.\n", - unitname(mage), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("spell(%s) calling '%s': not a function.\n", - unitname(mage), fname)); - lua_pop(L, 1); - } - - return result; -} - -/** callback to initialize a familiar from lua. */ -static void -lua_initfamiliar(unit * u) -{ - lua_State * L = (lua_State *)global.vm_state; - char fname[64]; - int result = -1; - snprintf(fname, sizeof(fname), "initfamiliar_%s", u->race->_name[0]); - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, u, TOLUA_CAST "unit"); - - if (lua_pcall(L, 1, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("familiar(%s) calling '%s': %s.\n", - unitname(u), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_warning(("familiar(%s) calling '%s': not a function.\n", - unitname(u), fname)); - lua_pop(L, 1); - } - - create_mage(u, M_GRAY); - - snprintf(fname, sizeof(fname), "%s_familiar", u->race->_name[0]); - equip_unit(u, get_equipment(fname)); -} - -static int -lua_changeresource(unit * u, const struct resource_type * rtype, int delta) -{ - lua_State * L = (lua_State *)global.vm_state; - int result = -1; - char fname[64]; - snprintf(fname, sizeof(fname), "%s_changeresource", rtype->_name[0]); - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, u, TOLUA_CAST "unit"); - tolua_pushnumber(L, (lua_Number)delta); - - if (lua_pcall(L, 2, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("change(%s) calling '%s': %s.\n", - unitname(u), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("change(%s) calling '%s': not a function.\n", - unitname(u), fname)); - lua_pop(L, 1); - } - - return result; -} - -static int -lua_getresource(unit * u, const struct resource_type * rtype) -{ - lua_State * L = (lua_State *)global.vm_state; - int result = -1; - char fname[64]; - snprintf(fname, sizeof(fname), "%s_getresource", rtype->_name[0]); - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, u, TOLUA_CAST "unit"); - - if (lua_pcall(L, 1, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("get(%s) calling '%s': %s.\n", - unitname(u), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("get(%s) calling '%s': not a function.\n", - unitname(u), fname)); - lua_pop(L, 1); - } - - return result; -} - -static boolean -lua_canuse_item(const unit * u, const struct item_type * itype) -{ - static int function_exists = 1; - boolean result = true; - - if (function_exists) { - lua_State * L = (lua_State *)global.vm_state; - const char * fname = "item_canuse"; - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); - tolua_pushstring(L, itype->rtype->_name[0]); - - if (lua_pcall(L, 2, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("get(%s) calling '%s': %s.\n", - unitname(u), fname, error)); - lua_pop(L, 1); - } else { - result = lua_toboolean(L, -1); - lua_pop(L, 1); - } - } else { - function_exists = 0; - log_error(("get(%s) calling '%s': not a function.\n", - unitname(u), fname)); - lua_pop(L, 1); - } - } - return result; -} - -static int -lua_wage(const region * r, const faction * f, const race * rc, int in_turn) -{ - lua_State * L = (lua_State *)global.vm_state; - const char * fname = "wage"; - int result = -1; - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); - tolua_pushusertype(L, (void *)f, TOLUA_CAST "faction"); - tolua_pushstring(L, rc?rc->_name[0]:0); - tolua_pushnumber(L, (lua_Number)in_turn); - - if (lua_pcall(L, 3, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("wage(%s) calling '%s': %s.\n", - regionname(r, NULL), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("wage(%s) calling '%s': not a function.\n", - regionname(r, NULL), fname)); - lua_pop(L, 1); - } - - return result; -} - -static void -lua_agebuilding(building * b) -{ - lua_State * L = (lua_State *)global.vm_state; - char fname[64]; - - snprintf(fname, sizeof(fname), "age_%s", b->type->_name); - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); - - if (lua_pcall(L, 1, 0, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("agebuilding(%s) calling '%s': %s.\n", - buildingname(b), fname, error)); - lua_pop(L, 1); - } - } else { - log_error(("agebuilding(%s) calling '%s': not a function.\n", - buildingname(b), fname)); - lua_pop(L, 1); - } -} - -static int -lua_building_protection(building * b, unit * u) -{ - lua_State * L = (lua_State *)global.vm_state; - const char * fname = "building_protection"; - int result = 0; - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); - tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); - - if (lua_pcall(L, 2, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("building_protection(%s, %s) calling '%s': %s.\n", - buildingname(b), unitname(u), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("building_protection(%s, %s) calling '%s': not a function.\n", - buildingname(b), unitname(u), fname)); - lua_pop(L, 1); - } - return result; -} - -static double -lua_building_taxes(building * b, int level) -{ - lua_State * L = (lua_State *)global.vm_state; - const char * fname = "building_taxes"; - double result = 0.0F; - int type; - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - type=lua_type(L, 1); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); - tolua_pushnumber(L, level); - - if (lua_pcall(L, 2, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("building_taxes(%s) calling '%s': %s.\n", - buildingname(b), fname, error)); - lua_pop(L, 1); - } else { - result = (double)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("building_taxes(%s) calling '%s': not a function.\n", - buildingname(b), fname)); - lua_pop(L, 1); - } - return result; -} - -static int -lua_maintenance(const unit * u) -{ - lua_State * L = (lua_State *)global.vm_state; - const char * fname = "maintenance"; - int result = -1; - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); - - if (lua_pcall(L, 1, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("maintenance(%s) calling '%s': %s.\n", - unitname(u), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("maintenance(%s) calling '%s': not a function.\n", - unitname(u), fname)); - lua_pop(L, 1); - } - - return result; -} - -static void -lua_equipmentcallback(const struct equipment * eq, unit * u) -{ - lua_State * L = (lua_State *)global.vm_state; - char fname[64]; - int result = -1; - snprintf(fname, sizeof(fname), "equip_%s", eq->name); - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); - - if (lua_pcall(L, 1, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("equip(%s) calling '%s': %s.\n", - unitname(u), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("equip(%s) calling '%s': not a function.\n", - unitname(u), fname)); - lua_pop(L, 1); - } -} - -/** callback for an item-use function written in lua. */ -int -lua_useitem(struct unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - lua_State * L = (lua_State *)global.vm_state; - int result = 0; - char fname[64]; - snprintf(fname, sizeof(fname), "use_%s", itype->rtype->_name[0]); - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); - tolua_pushnumber(L, (lua_Number)amount); - - if (lua_pcall(L, 2, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("use(%s) calling '%s': %s.\n", - unitname(u), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("use(%s) calling '%s': not a function.\n", - unitname(u), fname)); - lua_pop(L, 1); - } - - return result; -} - -static int -lua_recruit(struct unit * u, const struct archetype * arch, int amount) -{ - lua_State * L = (lua_State *)global.vm_state; - int result = 0; - char fname[64]; - snprintf(fname, sizeof(fname), "recruit_%s", arch->name[0]); - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); - tolua_pushnumber(L, (lua_Number)amount); - - if (lua_pcall(L, 2, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("use(%s) calling '%s': %s.\n", - unitname(u), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("use(%s) calling '%s': not a function.\n", - unitname(u), fname)); - lua_pop(L, 1); - } - return result; -} - -int -tolua_toid(lua_State* L, int idx, int def) -{ - int no = 0; - int type = lua_type(L, idx); - if (type==LUA_TNUMBER) { - no = (int)tolua_tonumber(L, idx, def); - } else { - const char * str = tolua_tostring(L, idx, NULL); - no = str?atoi36(str):def; - } - return no; -} - -void -register_tolua_helpers(void) -{ - at_building_action.age = lc_age; - - register_function((pf_generic)&lua_building_protection, TOLUA_CAST "lua_building_protection"); - register_function((pf_generic)&lua_building_taxes, TOLUA_CAST "lua_building_taxes"); - register_function((pf_generic)&lua_agebuilding, TOLUA_CAST "lua_agebuilding"); - register_function((pf_generic)&lua_recruit, TOLUA_CAST "lua_recruit"); - register_function((pf_generic)&lua_callspell, TOLUA_CAST "lua_castspell"); - register_function((pf_generic)&lua_initfamiliar, TOLUA_CAST "lua_initfamiliar"); - register_item_use(&lua_useitem, TOLUA_CAST "lua_useitem"); - register_function((pf_generic)&lua_getresource, TOLUA_CAST "lua_getresource"); - register_function((pf_generic)&lua_canuse_item, TOLUA_CAST "lua_canuse_item"); - register_function((pf_generic)&lua_changeresource, TOLUA_CAST "lua_changeresource"); - register_function((pf_generic)&lua_equipmentcallback, TOLUA_CAST "lua_equip"); - - register_function((pf_generic)&lua_wage, TOLUA_CAST "lua_wage"); - register_function((pf_generic)&lua_maintenance, TOLUA_CAST "lua_maintenance"); - - - register_function((pf_generic)produce_resource, TOLUA_CAST "lua_produceresource"); - register_function((pf_generic)limit_resource, TOLUA_CAST "lua_limitresource"); - register_item_give(lua_giveitem, TOLUA_CAST "lua_giveitem"); -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include "helpers.h" +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +static int +lua_giveitem(unit * s, unit * d, const item_type * itype, int n, struct order * ord) +{ + lua_State * L = (lua_State *)global.vm_state; + char fname[64]; + int result = -1; + const char * iname = itype->rtype->_name[0]; + + assert(s!=NULL); + strcat(strcpy(fname, iname), "_give"); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, s, TOLUA_CAST "unit"); + tolua_pushusertype(L, d, TOLUA_CAST "unit"); + tolua_pushstring(L, iname); + tolua_pushnumber(L, (lua_Number)n); + + if (lua_pcall(L, 4, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("unit %s calling '%s': %s.\n", + unitname(s), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("unit %s trying to call '%s' : not a function.\n", + unitname(s), fname)); + lua_pop(L, 1); + } + + return result; +} + +static int +limit_resource(const region * r, const resource_type * rtype) +{ + char fname[64]; + int result = -1; + lua_State * L = (lua_State *)global.vm_state; + + snprintf(fname, sizeof(fname), "%s_limit", rtype->_name[0]); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); + + if (lua_pcall(L, 1, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("limit(%s) calling '%s': %s.\n", + regionname(r, NULL), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("limit(%s) calling '%s': not a function.\n", + regionname(r, NULL), fname)); + lua_pop(L, 1); + } + + return result; +} + +static void +produce_resource(region * r, const resource_type * rtype, int norders) +{ + lua_State * L = (lua_State *)global.vm_state; + char fname[64]; + snprintf(fname, sizeof(fname), "%s_produce", rtype->_name[0]); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); + tolua_pushnumber(L, (lua_Number)norders); + + if (lua_pcall(L, 2, 0, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("produce(%s) calling '%s': %s.\n", + regionname(r, NULL), fname, error)); + lua_pop(L, 1); + } + } else { + log_error(("produce(%s) calling '%s': not a function.\n", + regionname(r, NULL), fname)); + lua_pop(L, 1); + } +} + + +static int +lc_age(struct attrib * a) +{ + building_action * data = (building_action*)a->data.v; + const char * fname = data->fname; + const char * fparam = data->param; + building * b = data->b; + int result = -1; + + assert(b!=NULL); + if (fname!=NULL) { + lua_State * L = (lua_State *)global.vm_state; + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); + if (fparam) { + tolua_pushstring(L, fparam); + } + + if (lua_pcall(L, fparam?2:1, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("lc_age(%s) calling '%s': %s.\n", + buildingname(b), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("lc_age(%s) calling '%s': not a function.\n", + buildingname(b), fname)); + lua_pop(L, 1); + } + } + return (result!=0)?AT_AGE_KEEP:AT_AGE_REMOVE; +} + +static void push_param(lua_State * L, char c, spllprm * param) +{ + if (c=='u') tolua_pushusertype(L, param->data.u, "unit"); + else if (c=='b') tolua_pushusertype(L, param->data.b, "building"); + else if (c=='s') tolua_pushusertype(L, param->data.sh, "ship"); + else if (c=='r') tolua_pushusertype(L, param->data.sh, "region"); + else if (c=='c') tolua_pushstring(L, param->data.s); + else { + log_error(("unsupported syntax %c.\n", c)); + lua_pushnil(L); + } +} + +/** callback to use lua for spell functions */ +static int +lua_callspell(castorder *co) +{ + lua_State * L = (lua_State *)global.vm_state; + const char * fname = co->sp->sname; + unit * mage = co->familiar?co->familiar:co->magician.u; + int result = -1; + const char * hashpos = strchr(fname, '#'); + char fbuf[64]; + + if (hashpos!=NULL) { + ptrdiff_t len = hashpos - fname; + assert(len<(ptrdiff_t)sizeof(fbuf)); + strncpy(fbuf, fname, len); + fbuf[len] = '\0'; + fname = fbuf; + } + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + int nparam = 4; + tolua_pushusertype(L, co->rt, TOLUA_CAST "region"); + tolua_pushusertype(L, mage, TOLUA_CAST "unit"); + tolua_pushnumber(L, (lua_Number)co->level); + tolua_pushnumber(L, (lua_Number)co->force); + if (co->sp->parameter && co->par->length) { + const char * synp = co->sp->parameter; + int i = 0; + ++nparam; + lua_newtable(L); + while (*synp&&ipar->length) { + spllprm * param = co->par->param[i]; + char c = *synp; + if (c=='+') { + push_param(L, *(synp-1), param); + } else { + push_param(L, c, param); + ++synp; + } + lua_rawseti(L, -2, ++i); + } + } + + if (lua_pcall(L, nparam, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("spell(%s) calling '%s': %s.\n", + unitname(mage), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("spell(%s) calling '%s': not a function.\n", + unitname(mage), fname)); + lua_pop(L, 1); + } + + return result; +} + +/** callback to initialize a familiar from lua. */ +static void +lua_initfamiliar(unit * u) +{ + lua_State * L = (lua_State *)global.vm_state; + char fname[64]; + int result = -1; + snprintf(fname, sizeof(fname), "initfamiliar_%s", u->race->_name[0]); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + + if (lua_pcall(L, 1, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("familiar(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_warning(("familiar(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } + + create_mage(u, M_GRAY); + + snprintf(fname, sizeof(fname), "%s_familiar", u->race->_name[0]); + equip_unit(u, get_equipment(fname)); +} + +static int +lua_changeresource(unit * u, const struct resource_type * rtype, int delta) +{ + lua_State * L = (lua_State *)global.vm_state; + int result = -1; + char fname[64]; + snprintf(fname, sizeof(fname), "%s_changeresource", rtype->_name[0]); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + tolua_pushnumber(L, (lua_Number)delta); + + if (lua_pcall(L, 2, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("change(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("change(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } + + return result; +} + +static int +lua_getresource(unit * u, const struct resource_type * rtype) +{ + lua_State * L = (lua_State *)global.vm_state; + int result = -1; + char fname[64]; + snprintf(fname, sizeof(fname), "%s_getresource", rtype->_name[0]); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + + if (lua_pcall(L, 1, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("get(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("get(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } + + return result; +} + +static boolean +lua_canuse_item(const unit * u, const struct item_type * itype) +{ + static int function_exists = 1; + boolean result = true; + + if (function_exists) { + lua_State * L = (lua_State *)global.vm_state; + const char * fname = "item_canuse"; + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); + tolua_pushstring(L, itype->rtype->_name[0]); + + if (lua_pcall(L, 2, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("get(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = lua_toboolean(L, -1); + lua_pop(L, 1); + } + } else { + function_exists = 0; + log_error(("get(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } + } + return result; +} + +static int +lua_wage(const region * r, const faction * f, const race * rc, int in_turn) +{ + lua_State * L = (lua_State *)global.vm_state; + const char * fname = "wage"; + int result = -1; + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); + tolua_pushusertype(L, (void *)f, TOLUA_CAST "faction"); + tolua_pushstring(L, rc?rc->_name[0]:0); + tolua_pushnumber(L, (lua_Number)in_turn); + + if (lua_pcall(L, 3, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("wage(%s) calling '%s': %s.\n", + regionname(r, NULL), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("wage(%s) calling '%s': not a function.\n", + regionname(r, NULL), fname)); + lua_pop(L, 1); + } + + return result; +} + +static void +lua_agebuilding(building * b) +{ + lua_State * L = (lua_State *)global.vm_state; + char fname[64]; + + snprintf(fname, sizeof(fname), "age_%s", b->type->_name); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); + + if (lua_pcall(L, 1, 0, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("agebuilding(%s) calling '%s': %s.\n", + buildingname(b), fname, error)); + lua_pop(L, 1); + } + } else { + log_error(("agebuilding(%s) calling '%s': not a function.\n", + buildingname(b), fname)); + lua_pop(L, 1); + } +} + +static int +lua_building_protection(building * b, unit * u) +{ + lua_State * L = (lua_State *)global.vm_state; + const char * fname = "building_protection"; + int result = 0; + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); + + if (lua_pcall(L, 2, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("building_protection(%s, %s) calling '%s': %s.\n", + buildingname(b), unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("building_protection(%s, %s) calling '%s': not a function.\n", + buildingname(b), unitname(u), fname)); + lua_pop(L, 1); + } + return result; +} + +static double +lua_building_taxes(building * b, int level) +{ + lua_State * L = (lua_State *)global.vm_state; + const char * fname = "building_taxes"; + double result = 0.0F; + int type; + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + type=lua_type(L, 1); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); + tolua_pushnumber(L, level); + + if (lua_pcall(L, 2, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("building_taxes(%s) calling '%s': %s.\n", + buildingname(b), fname, error)); + lua_pop(L, 1); + } else { + result = (double)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("building_taxes(%s) calling '%s': not a function.\n", + buildingname(b), fname)); + lua_pop(L, 1); + } + return result; +} + +static int +lua_maintenance(const unit * u) +{ + lua_State * L = (lua_State *)global.vm_state; + const char * fname = "maintenance"; + int result = -1; + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); + + if (lua_pcall(L, 1, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("maintenance(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("maintenance(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } + + return result; +} + +static void +lua_equipmentcallback(const struct equipment * eq, unit * u) +{ + lua_State * L = (lua_State *)global.vm_state; + char fname[64]; + int result = -1; + snprintf(fname, sizeof(fname), "equip_%s", eq->name); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); + + if (lua_pcall(L, 1, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("equip(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("equip(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } +} + +/** callback for an item-use function written in lua. */ +int +lua_useitem(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + lua_State * L = (lua_State *)global.vm_state; + int result = 0; + char fname[64]; + snprintf(fname, sizeof(fname), "use_%s", itype->rtype->_name[0]); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); + tolua_pushnumber(L, (lua_Number)amount); + + if (lua_pcall(L, 2, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("use(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("use(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } + + return result; +} + +static int +lua_recruit(struct unit * u, const struct archetype * arch, int amount) +{ + lua_State * L = (lua_State *)global.vm_state; + int result = 0; + char fname[64]; + snprintf(fname, sizeof(fname), "recruit_%s", arch->name[0]); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); + tolua_pushnumber(L, (lua_Number)amount); + + if (lua_pcall(L, 2, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("use(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("use(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } + return result; +} + +int +tolua_toid(lua_State* L, int idx, int def) +{ + int no = 0; + int type = lua_type(L, idx); + if (type==LUA_TNUMBER) { + no = (int)tolua_tonumber(L, idx, def); + } else { + const char * str = tolua_tostring(L, idx, NULL); + no = str?atoi36(str):def; + } + return no; +} + +void +register_tolua_helpers(void) +{ + at_building_action.age = lc_age; + + register_function((pf_generic)&lua_building_protection, TOLUA_CAST "lua_building_protection"); + register_function((pf_generic)&lua_building_taxes, TOLUA_CAST "lua_building_taxes"); + register_function((pf_generic)&lua_agebuilding, TOLUA_CAST "lua_agebuilding"); + register_function((pf_generic)&lua_recruit, TOLUA_CAST "lua_recruit"); + register_function((pf_generic)&lua_callspell, TOLUA_CAST "lua_castspell"); + register_function((pf_generic)&lua_initfamiliar, TOLUA_CAST "lua_initfamiliar"); + register_item_use(&lua_useitem, TOLUA_CAST "lua_useitem"); + register_function((pf_generic)&lua_getresource, TOLUA_CAST "lua_getresource"); + register_function((pf_generic)&lua_canuse_item, TOLUA_CAST "lua_canuse_item"); + register_function((pf_generic)&lua_changeresource, TOLUA_CAST "lua_changeresource"); + register_function((pf_generic)&lua_equipmentcallback, TOLUA_CAST "lua_equip"); + + register_function((pf_generic)&lua_wage, TOLUA_CAST "lua_wage"); + register_function((pf_generic)&lua_maintenance, TOLUA_CAST "lua_maintenance"); + + + register_function((pf_generic)produce_resource, TOLUA_CAST "lua_produceresource"); + register_function((pf_generic)limit_resource, TOLUA_CAST "lua_limitresource"); + register_item_give(lua_giveitem, TOLUA_CAST "lua_giveitem"); +} diff --git a/src/bindings/helpers.h b/src/bindings/helpers.h index 8d3370650..4e0da152f 100644 --- a/src/bindings/helpers.h +++ b/src/bindings/helpers.h @@ -1,23 +1,23 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - void register_tolua_helpers(void); - int tolua_toid(struct lua_State* L, int idx, int def); - -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + void register_tolua_helpers(void); + int tolua_toid(struct lua_State* L, int idx, int def); + +#ifdef __cplusplus +} +#endif diff --git a/src/build/atoi36.c b/src/build/atoi36.c index 4f896a1e7..7965d78f6 100644 --- a/src/build/atoi36.c +++ b/src/build/atoi36.c @@ -1,6 +1,6 @@ -#include "common/settings.h" -#include "common/config.h" -#include "stdafx.h" - -#include "common/util/base36.c" -#include "tools/atoi36.c" +#include "common/settings.h" +#include "common/config.h" +#include "stdafx.h" + +#include "common/util/base36.c" +#include "tools/atoi36.c" diff --git a/src/build/external.c b/src/build/external.c index a882ce3fe..010ac20db 100644 --- a/src/build/external.c +++ b/src/build/external.c @@ -1,18 +1,18 @@ -#include -#include -#include "stdafx.h" - -#pragma warning(push) -#pragma warning(disable: 4244) -#pragma warning(disable: 4127) -#include -#pragma warning(pop) - -#include - -#include -#include - -#ifndef DISABLE_TESTS -#include -#endif +#include +#include +#include "stdafx.h" + +#pragma warning(push) +#pragma warning(disable: 4244) +#pragma warning(disable: 4127) +#include +#pragma warning(pop) + +#include + +#include +#include + +#ifndef DISABLE_TESTS +#include +#endif diff --git a/src/build/gamecode.c b/src/build/gamecode.c index 63120bde0..2d3dfbdfd 100644 --- a/src/build/gamecode.c +++ b/src/build/gamecode.c @@ -1,80 +1,80 @@ -#include -#include -#include "stdafx.h" - -#ifdef BINDINGS_TOLUA -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include "stdafx.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_CURSES +#include +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/src/build/kernel.c b/src/build/kernel.c index 9ac333f94..4fa586933 100644 --- a/src/build/kernel.c +++ b/src/build/kernel.c @@ -1,53 +1,58 @@ -#include -#include -#include "stdafx.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include "stdafx.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_LIBXML +#include +#else +void register_xmlreader(void) {} +void enable_xml_gamecode(void) {} +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/src/build/lib.c b/src/build/lib.c index 18624376a..0d6fcdf13 100644 --- a/src/build/lib.c +++ b/src/build/lib.c @@ -1,7 +1,10 @@ -#include -#include -#include "stdafx.h" - -#include -#include -#include +#include +#include +#include "stdafx.h" + +#ifdef HAVE_CURSES +#include +#include +#endif + +#include diff --git a/src/build/stdafx.c b/src/build/stdafx.c index fd4f341c7..a27b824da 100644 --- a/src/build/stdafx.c +++ b/src/build/stdafx.c @@ -1 +1 @@ -#include "stdafx.h" +#include "stdafx.h" diff --git a/src/build/stdafx.h b/src/build/stdafx.h index b0d94063d..338582b17 100644 --- a/src/build/stdafx.h +++ b/src/build/stdafx.h @@ -1,2 +1,2 @@ -#include -#include +#include +#include diff --git a/src/build/util.c b/src/build/util.c index dfae8d012..eb602ec6e 100644 --- a/src/build/util.c +++ b/src/build/util.c @@ -1,40 +1,40 @@ -#include -#include -#include "stdafx.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef HAVE_INLINE -#include -#endif - -#ifdef __GNUC__ -#include -#endif +#include +#include +#include "stdafx.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef HAVE_INLINE +#include +#endif + +#ifdef __GNUC__ +#include +#endif diff --git a/src/eressea.c b/src/eressea.c index 3a8dd4740..a23bb99f4 100644 --- a/src/eressea.c +++ b/src/eressea.c @@ -1,212 +1,211 @@ -#include -#include "settings.h" -#include "eressea.h" - -#include -#include -#include - -/* lua includes */ -#ifdef BINDINGS_TOLUA -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif // BINDINGS_TOLUA - -#if MUSEUM_MODULE -#include -#endif -#if ARENA_MODULE -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -static const struct { - const char * name; - int (*func)(lua_State *); -} lualibs[] = { - {"", luaopen_base}, - {LUA_TABLIBNAME, luaopen_table}, - {LUA_IOLIBNAME, luaopen_io}, - {LUA_STRLIBNAME, luaopen_string}, - {LUA_MATHLIBNAME, luaopen_math}, - {LUA_LOADLIBNAME, luaopen_package}, - {LUA_DBLIBNAME, luaopen_debug}, -#if LUA_VERSION_NUM>=501 - {LUA_OSLIBNAME, luaopen_os}, -#endif - { NULL, NULL } -}; - -static void -openlibs(lua_State * L) -{ - int i; - for (i=0;lualibs[i].func;++i) { - lua_pushcfunction(L, lualibs[i].func); - lua_pushstring(L, lualibs[i].name); - lua_call(L, 1, 0); - } -} - -static void -lua_done(lua_State * L) -{ - lua_close(L); -} - -static lua_State * -lua_init(void) -{ - lua_State * L = lua_open(); - - openlibs(L); -#ifdef BINDINGS_TOLUA - register_tolua_helpers(); - tolua_eressea_open(L); - tolua_sqlite_open(L); - tolua_unit_open(L); - tolua_building_open(L); - tolua_ship_open(L); - tolua_region_open(L); - tolua_faction_open(L); - tolua_attrib_open(L); - tolua_unit_open(L); - tolua_message_open(L); - tolua_hashtable_open(L); - tolua_gmtool_open(L); - tolua_storage_open(L); -#endif - return L; -} - -static void -game_done(void) -{ -#ifdef CLEANUP_CODE - /* Diese Routine enfernt allen allokierten Speicher wieder. Das ist nur - * zum Debugging interessant, wenn man Leak Detection hat, und nach - * nicht freigegebenem Speicher sucht, der nicht bis zum Ende benötigt - * wird (temporäre Hilsstrukturen) */ - - free_game(); - - creport_cleanup(); -#ifdef REPORT_FORMAT_NR - report_cleanup(); -#endif - calendar_cleanup(); -#endif -} - -static void -game_init(void) -{ - register_triggers(); - register_xmas(); - - register_reports(); - register_nr(); - register_cr(); - register_xr(); - - debug_language("locales.log"); - register_names(); - register_resources(); - register_buildings(); - register_itemfunctions(); -#if DUNGEON_MODULE - register_dungeon(); -#endif -#if MUSEUM_MODULE - register_museum(); -#endif -#if ARENA_MODULE - register_arena(); -#endif - register_wormholes(); - - register_itemtypes(); - register_xmlreader(); - register_archetypes(); - enable_xml_gamecode(); - - register_attributes(); - register_gmcmd(); - -} - -int eressea_init(void) -{ - global.vm_state = lua_init(); - kernel_init(); - game_init(); - - return 0; -} - -void eressea_done(void) -{ - game_done(); - kernel_done(); - lua_done((lua_State *)global.vm_state); -} - -int eressea_run(const char * luafile, const char * entry_point) -{ - int err; - lua_State * L = (lua_State *)global.vm_state; - /* run the main script */ - if (luafile) { - lua_getglobal(L, "dofile"); - lua_pushstring(L, luafile); - err = lua_pcall(L, 1, 0, 0); - if (err != 0) { - log_lua_error(L); - abort(); - return err; - } - } - if (entry_point) { - lua_getglobal(L, entry_point); - err = lua_pcall(L, 0, 1, 0); - if (err != 0) { - log_lua_error(L); - abort(); - return err; - } - } else { - err = lua_console(L); - } - return err; -} +#include +#include "settings.h" +#include "eressea.h" + +#include +#include +#include + +/* lua includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_CURSES +#include +#endif + +#if MUSEUM_MODULE +#include +#endif +#if ARENA_MODULE +#include +#endif +#include +#include +#ifdef HAVE_LIBXML +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static const struct { + const char * name; + int (*func)(lua_State *); +} lualibs[] = { + {"", luaopen_base}, + {LUA_TABLIBNAME, luaopen_table}, + {LUA_IOLIBNAME, luaopen_io}, + {LUA_STRLIBNAME, luaopen_string}, + {LUA_MATHLIBNAME, luaopen_math}, + {LUA_LOADLIBNAME, luaopen_package}, + {LUA_DBLIBNAME, luaopen_debug}, +#if LUA_VERSION_NUM>=501 + {LUA_OSLIBNAME, luaopen_os}, +#endif + { NULL, NULL } +}; + +static void +openlibs(lua_State * L) +{ + int i; + for (i=0;lualibs[i].func;++i) { + lua_pushcfunction(L, lualibs[i].func); + lua_pushstring(L, lualibs[i].name); + lua_call(L, 1, 0); + } +} + +static void +lua_done(lua_State * L) +{ + lua_close(L); +} + +static lua_State * +lua_init(void) +{ + lua_State * L = lua_open(); + + openlibs(L); + register_tolua_helpers(); + tolua_eressea_open(L); + tolua_sqlite_open(L); + tolua_unit_open(L); + tolua_building_open(L); + tolua_ship_open(L); + tolua_region_open(L); + tolua_faction_open(L); + tolua_attrib_open(L); + tolua_unit_open(L); + tolua_message_open(L); + tolua_hashtable_open(L); +#ifdef HAVE_CURSES + tolua_gmtool_open(L); +#endif + tolua_storage_open(L); + return L; +} + +static void +game_done(void) +{ +#ifdef CLEANUP_CODE + /* Diese Routine enfernt allen allokierten Speicher wieder. Das ist nur + * zum Debugging interessant, wenn man Leak Detection hat, und nach + * nicht freigegebenem Speicher sucht, der nicht bis zum Ende benötigt + * wird (temporäre Hilsstrukturen) */ + + free_game(); + + creport_cleanup(); +#ifdef REPORT_FORMAT_NR + report_cleanup(); +#endif + calendar_cleanup(); +#endif +} + +static void +game_init(void) +{ + register_triggers(); + register_xmas(); + + register_reports(); + register_nr(); + register_cr(); + + debug_language("locales.log"); + register_names(); + register_resources(); + register_buildings(); + register_itemfunctions(); +#if DUNGEON_MODULE + register_dungeon(); +#endif +#if MUSEUM_MODULE + register_museum(); +#endif +#if ARENA_MODULE + register_arena(); +#endif + register_wormholes(); + + register_itemtypes(); + register_xmlreader(); + register_archetypes(); + enable_xml_gamecode(); + register_attributes(); + register_gmcmd(); + +} + +int eressea_init(void) +{ + global.vm_state = lua_init(); + kernel_init(); + game_init(); + + return 0; +} + +void eressea_done(void) +{ + game_done(); + kernel_done(); + lua_done((lua_State *)global.vm_state); +} + +int eressea_run(const char * luafile, const char * entry_point) +{ + int err; + lua_State * L = (lua_State *)global.vm_state; + /* run the main script */ + if (luafile) { + lua_getglobal(L, "dofile"); + lua_pushstring(L, luafile); + err = lua_pcall(L, 1, 0, 0); + if (err != 0) { + log_lua_error(L); + abort(); + return err; + } + } + if (entry_point) { + lua_getglobal(L, entry_point); + err = lua_pcall(L, 0, 1, 0); + if (err != 0) { + log_lua_error(L); + abort(); + return err; + } + } else { + err = lua_console(L); + } + return err; +} diff --git a/src/eressea.h b/src/eressea.h index c2d15d458..d41339422 100644 --- a/src/eressea.h +++ b/src/eressea.h @@ -1,15 +1,15 @@ -#ifndef H_ERESSEA_LIB -#define H_ERESSEA_LIB -#ifdef __cplusplus -extern "C" { -#endif - -int eressea_init(void); -void eressea_done(void); -int eressea_run(const char * luafile, const char * entry_point); - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef H_ERESSEA_LIB +#define H_ERESSEA_LIB +#ifdef __cplusplus +extern "C" { +#endif + +int eressea_init(void); +void eressea_done(void); +int eressea_run(const char * luafile, const char * entry_point); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/gamecode.vcproj b/src/gamecode.vcproj index 27c322ae1..6cdabb3e8 100644 --- a/src/gamecode.vcproj +++ b/src/gamecode.vcproj @@ -1,354 +1,354 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gamecode.vcxproj b/src/gamecode.vcxproj index c955d12d1..8cfd4712a 100644 --- a/src/gamecode.vcxproj +++ b/src/gamecode.vcxproj @@ -1,141 +1,138 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {1E8BFF9E-3044-0742-992F-C5765B80FE65} - gamecode - Win32Proj - - - - StaticLibrary - MultiByte - - - StaticLibrary - MultiByte - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - - - - /MP %(AdditionalOptions) - Disabled - .;../../external;%(AdditionalIncludeDirectories) - WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - true - - - Level4 - true - EditAndContinue - - - WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - ..;.;%(AdditionalIncludeDirectories) - - - $(OutDir)gamecode.lib - - - - - Full - .;../../external;%(AdditionalIncludeDirectories) - WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) - true - MultiThreadedDLL - true - - - Level4 - - - - - WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) - ..;.;%(AdditionalIncludeDirectories) - - - $(OutDir)gamecode.lib - - - - - - - - - - - - - - true - true - - - - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + + {1E8BFF9E-3044-0742-992F-C5765B80FE65} + gamecode + Win32Proj + + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + + + + /MP %(AdditionalOptions) + Disabled + .;../../external;../../external/lua/src;../../external/tolua/include;..\..\external\pdcurses;..\..\external\libxml2\include;%(AdditionalIncludeDirectories) + WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + true + + + Level4 + true + EditAndContinue + + + WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + ..;.;%(AdditionalIncludeDirectories) + + + $(OutDir)gamecode.lib + + + + + Full + .;../../external;../../external/lua/src;../../external/tolua/include;..\..\external\pdcurses;..\..\external\libxml2\include;%(AdditionalIncludeDirectories) + WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + + + Level4 + + + + + WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) + ..;.;%(AdditionalIncludeDirectories) + + + $(OutDir)gamecode.lib + + + + + + + + + + + + + + true + true + + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/gamecode.vcxproj.filters b/src/gamecode.vcxproj.filters index 8eb7a6651..8cd90a6f3 100644 --- a/src/gamecode.vcxproj.filters +++ b/src/gamecode.vcxproj.filters @@ -1,131 +1,125 @@ - - - - - {d83e7c3e-0495-4145-86ea-a86b7d4d405b} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {7553a025-8a64-4b5a-90cb-a2eeae9190d3} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - + + + + + {d83e7c3e-0495-4145-86ea-a86b7d4d405b} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {7553a025-8a64-4b5a-90cb-a2eeae9190d3} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + \ No newline at end of file diff --git a/src/gamecode/archetype.c b/src/gamecode/archetype.c index 8f82e7d31..6d634f56a 100644 --- a/src/gamecode/archetype.c +++ b/src/gamecode/archetype.c @@ -1,165 +1,171 @@ -#include -#include -#include "archetype.h" - -/* kernel includes */ -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include - -/* libxml includes */ -#include -#include -#include - -/* libc includes */ -#include -#include - -static struct archetype * archetypes; - -struct attrib_type at_recruit = { - "recruit", NULL, NULL, NULL, NULL, NULL, ATF_UNIQUE -}; - -const struct archetype * -find_archetype(const char * s, const struct locale * lang) -{ - struct tnode * tokens = get_translations(lang, UT_ARCHETYPES); - variant token; - - if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { - return (const struct archetype *)token.v; - } - return NULL; -} - -void -register_archetype(archetype * arch) -{ - arch->next = archetypes; - archetypes = arch; -} - -void -init_archetypes(void) -{ - const struct locale * lang = locales; - for (;lang;lang=nextlocale(lang)) { - variant var; - archetype * arch = archetypes; - struct tnode * tokens = get_translations(lang, UT_ARCHETYPES); - for (;arch;arch=arch->next) { - const char *s1, *s2; - var.v = arch; - - s1 = LOC(lang, arch->name[0]); - addtoken(tokens, s1, var); - s2 = LOC(lang, arch->name[1]); - if (strcmp(s2, s1)!=0) { - addtoken(tokens, s2, var); - } - } - } -} - -static int -parse_archetypes(xmlDocPtr doc) -{ - char zName[64]; - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr result = xmlXPathEvalExpression(BAD_CAST "/eressea/archetypes/archetype", xpath); - xmlNodeSetPtr nodes = result->nodesetval; - - xmlChar * propValue; - if (nodes) { - int i; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr node = nodes->nodeTab[i]; - xmlNodePtr child; - archetype * arch = calloc(1, sizeof(archetype)); - xmlXPathObjectPtr sub; - - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - arch->name[0] = strdup((const char *)propValue); - sprintf(zName, "%s_p", arch->name[0]); - arch->name[1] = strdup(zName); - xmlFree(propValue); - - propValue = xmlGetProp(node, BAD_CAST "equip"); - if (propValue!=NULL) { - arch->equip = get_equipment((const char*)propValue); - xmlFree(propValue); - } else { - arch->equip = get_equipment(arch->name[0]); - } - - propValue = xmlGetProp(node, BAD_CAST "building"); - if (propValue!=NULL) { - arch->btype = bt_find((const char*)propValue); - xmlFree(propValue); - } - - arch->size = xml_ivalue(node, "cost", 0); - - for (child=node->children;child;child=child->next) { - if (strcmp((const char *)child->name, "function")==0) { - xmlChar * propName = xmlGetProp(child, BAD_CAST "name"); - xmlChar * propValue = xmlGetProp(child, BAD_CAST "value"); - if (strcmp((const char *)propName, "create")) { - pf_generic foo = get_function((const char *)propValue); - arch->exec = (archetype_function)foo; - } - xmlFree(propValue); - xmlFree(propName); - } - } - xpath->node = node; - sub = xmlXPathEvalExpression(BAD_CAST "allow|deny", xpath); - if (sub->nodesetval && sub->nodesetval->nodeNr) { - int k; - arch->rules = calloc(sub->nodesetval->nodeNr+1, sizeof(rule)); - for (k=0;k!=sub->nodesetval->nodeNr;++k) { - xmlNodePtr rule = sub->nodesetval->nodeTab[k]; - arch->rules[k].allow = (rule->name[0]=='a'); - - propValue = xmlGetProp(rule, BAD_CAST "property"); - arch->rules[k].property = strdup((const char *)propValue); - xmlFree(propValue); - - propValue = xmlGetProp(rule, BAD_CAST "value"); - arch->rules[k].value = strdup((const char *)propValue); - xmlFree(propValue); - } - } - xmlXPathFreeObject(sub); - - xpath->node = node; - sub = xmlXPathEvalExpression(BAD_CAST "construction", xpath); - if (sub->nodesetval) { - xml_readconstruction(xpath, sub->nodesetval, &arch->ctype); - } - xmlXPathFreeObject(sub); - register_archetype(arch); - } - } - xmlXPathFreeObject(result); - - xmlXPathFreeContext(xpath); - return 0; -} - -void -register_archetypes(void) -{ - xml_register_callback(parse_archetypes); -} +#include +#include +#include "archetype.h" + +/* kernel includes */ +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include + +#ifdef HAVE_LIBXML +/* libxml includes */ +#include +#include +#include +#endif + +/* libc includes */ +#include +#include + +static struct archetype * archetypes; + +struct attrib_type at_recruit = { + "recruit", NULL, NULL, NULL, NULL, NULL, ATF_UNIQUE +}; + +const struct archetype * +find_archetype(const char * s, const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_ARCHETYPES); + variant token; + + if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { + return (const struct archetype *)token.v; + } + return NULL; +} + +void +register_archetype(archetype * arch) +{ + arch->next = archetypes; + archetypes = arch; +} + +void +init_archetypes(void) +{ + const struct locale * lang = locales; + for (;lang;lang=nextlocale(lang)) { + variant var; + archetype * arch = archetypes; + struct tnode * tokens = get_translations(lang, UT_ARCHETYPES); + for (;arch;arch=arch->next) { + const char *s1, *s2; + var.v = arch; + + s1 = LOC(lang, arch->name[0]); + addtoken(tokens, s1, var); + s2 = LOC(lang, arch->name[1]); + if (strcmp(s2, s1)!=0) { + addtoken(tokens, s2, var); + } + } + } +} + +#ifdef HAVE_LIBXML +static int +parse_archetypes(xmlDocPtr doc) +{ + char zName[64]; + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr result = xmlXPathEvalExpression(BAD_CAST "/eressea/archetypes/archetype", xpath); + xmlNodeSetPtr nodes = result->nodesetval; + + xmlChar * propValue; + if (nodes) { + int i; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + xmlNodePtr child; + archetype * arch = calloc(1, sizeof(archetype)); + xmlXPathObjectPtr sub; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + arch->name[0] = strdup((const char *)propValue); + sprintf(zName, "%s_p", arch->name[0]); + arch->name[1] = strdup(zName); + xmlFree(propValue); + + propValue = xmlGetProp(node, BAD_CAST "equip"); + if (propValue!=NULL) { + arch->equip = get_equipment((const char*)propValue); + xmlFree(propValue); + } else { + arch->equip = get_equipment(arch->name[0]); + } + + propValue = xmlGetProp(node, BAD_CAST "building"); + if (propValue!=NULL) { + arch->btype = bt_find((const char*)propValue); + xmlFree(propValue); + } + + arch->size = xml_ivalue(node, "cost", 0); + + for (child=node->children;child;child=child->next) { + if (strcmp((const char *)child->name, "function")==0) { + xmlChar * propName = xmlGetProp(child, BAD_CAST "name"); + xmlChar * propValue = xmlGetProp(child, BAD_CAST "value"); + if (strcmp((const char *)propName, "create")) { + pf_generic foo = get_function((const char *)propValue); + arch->exec = (archetype_function)foo; + } + xmlFree(propValue); + xmlFree(propName); + } + } + xpath->node = node; + sub = xmlXPathEvalExpression(BAD_CAST "allow|deny", xpath); + if (sub->nodesetval && sub->nodesetval->nodeNr) { + int k; + arch->rules = calloc(sub->nodesetval->nodeNr+1, sizeof(rule)); + for (k=0;k!=sub->nodesetval->nodeNr;++k) { + xmlNodePtr rule = sub->nodesetval->nodeTab[k]; + arch->rules[k].allow = (rule->name[0]=='a'); + + propValue = xmlGetProp(rule, BAD_CAST "property"); + arch->rules[k].property = strdup((const char *)propValue); + xmlFree(propValue); + + propValue = xmlGetProp(rule, BAD_CAST "value"); + arch->rules[k].value = strdup((const char *)propValue); + xmlFree(propValue); + } + } + xmlXPathFreeObject(sub); + + xpath->node = node; + sub = xmlXPathEvalExpression(BAD_CAST "construction", xpath); + if (sub->nodesetval) { + xml_readconstruction(xpath, sub->nodesetval, &arch->ctype); + } + xmlXPathFreeObject(sub); + register_archetype(arch); + } + } + xmlXPathFreeObject(result); + + xmlXPathFreeContext(xpath); + return 0; +} +#endif + +void +register_archetypes(void) +{ +#ifdef HAVE_LIBXML + xml_register_callback(parse_archetypes); +#endif +} diff --git a/src/gamecode/archetype.h b/src/gamecode/archetype.h index 358946ccd..40bd4fb90 100644 --- a/src/gamecode/archetype.h +++ b/src/gamecode/archetype.h @@ -1,51 +1,51 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2007 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifndef H_GC_ARCHETYPE -#define H_GC_ARCHETYPE - -#ifdef __cplusplus -extern "C" { -#endif - - typedef struct rule { - boolean allow; - char * property; - char * value; - } rule; - - struct archetype; - typedef int (*archetype_function)(struct unit * u, const struct archetype *, int); - - typedef struct archetype { - struct archetype * next; - char * name[2]; - int size; - struct building_type * btype; - struct equipment * equip; - struct construction * ctype; - struct rule * rules; - archetype_function exec; - } archetype; - - extern const struct archetype * find_archetype(const char * s, const struct locale * lang); - extern void init_archetypes(void); - extern void register_archetype(struct archetype * arch); - extern void register_archetypes(void); - - extern struct attrib_type at_recruit; - -#ifdef __cplusplus -} -#endif - -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2007 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifndef H_GC_ARCHETYPE +#define H_GC_ARCHETYPE + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct rule { + boolean allow; + char * property; + char * value; + } rule; + + struct archetype; + typedef int (*archetype_function)(struct unit * u, const struct archetype *, int); + + typedef struct archetype { + struct archetype * next; + char * name[2]; + int size; + struct building_type * btype; + struct equipment * equip; + struct construction * ctype; + struct rule * rules; + archetype_function exec; + } archetype; + + extern const struct archetype * find_archetype(const char * s, const struct locale * lang); + extern void init_archetypes(void); + extern void register_archetype(struct archetype * arch); + extern void register_archetypes(void); + + extern struct attrib_type at_recruit; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/gamecode/creation.c b/src/gamecode/creation.c index b22dedaa8..f9878b922 100644 --- a/src/gamecode/creation.c +++ b/src/gamecode/creation.c @@ -1,73 +1,73 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "creation.h" -#include "monster.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include -#include -#include - -faction * -createmonsters(int no) -{ - faction *f = findfaction(no); - - if (f) { - puts("* Fehler! Die Monster Partei gibt es schon."); - return f; - } - f = (faction *) calloc(1, sizeof(faction)); - f->no = no; - /* alles ist auf null gesetzt, ausser dem folgenden. achtung - partei - * no 0 muss keine orders einreichen! */ - - f->email = strdup("monsters@eressea.de"); - f->name = strdup("Monster"); - f->alive = 1; - f->options = (char)(1< + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "creation.h" +#include "monster.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +faction * +createmonsters(int no) +{ + faction *f = findfaction(no); + + if (f) { + puts("* Fehler! Die Monster Partei gibt es schon."); + return f; + } + f = (faction *) calloc(1, sizeof(faction)); + f->no = no; + /* alles ist auf null gesetzt, ausser dem folgenden. achtung - partei + * no 0 muss keine orders einreichen! */ + + f->email = strdup("monsters@eressea.de"); + f->name = strdup("Monster"); + f->alive = 1; + f->options = (char)(1< - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_GC_CREATION -#define H_GC_CREATION -#ifdef __cplusplus -extern "C" { -#endif - -struct faction * createmonsters(int no); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_GC_CREATION +#define H_GC_CREATION +#ifdef __cplusplus +extern "C" { +#endif + +struct faction * createmonsters(int no); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index edef15247..d8fc76390 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -1,1608 +1,1607 @@ -/* vi: set ts=2: -+-------------------+ Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -+-------------------+ -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "creport.h" - -/* tweakable features */ -#define RENDER_CRMESSAGES -#define BUFFERSIZE 32768 -#define RESOURCECOMPAT - -/* modules include */ -#include - -/* attributes include */ -#include -#include -#include -#include -#include - -/* gamecode includes */ -#include "laws.h" -#include "economy.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include -#include - -/* imports */ -extern int verbosity; -boolean opt_cr_absolute_coords = false; - -/* globals */ -#define C_REPORT_VERSION 66 - -#define TAG_LOCALE "de" -#ifdef TAG_LOCALE -static const char * -crtag(const char * key) -{ - static const struct locale * lang = NULL; - if (!lang) lang = find_locale(TAG_LOCALE); - return locale_string(lang, key); -} -#else -#define crtag(x) (x) -#endif -/* - * translation table - */ -typedef struct translation { - struct translation * next; - char * key; - const char * value; -} translation; - -#define TRANSMAXHASH 257 -static translation * translation_table[TRANSMAXHASH]; -static translation * junkyard; - -static const char * -add_translation(const char * key, const char * value) -{ - int kk = ((key[0] << 5) + key[0]) % TRANSMAXHASH; - translation * t = translation_table[kk]; - while (t && strcmp(t->key, key)!=0) t=t->next; - if (!t) { - if (junkyard) { - t = junkyard; - junkyard = junkyard->next; - } else t = malloc(sizeof(translation)); - t->key = strdup(key); - t->value = value; - t->next = translation_table[kk]; - translation_table[kk] = t; - } - return crtag(key); -} - -static void -write_translations(FILE * F) -{ - int i; - fputs("TRANSLATION\n", F); - for (i=0;i!=TRANSMAXHASH;++i) { - translation * t = translation_table[i]; - while (t) { - fprintf(F, "\"%s\";%s\n", t->value, crtag(t->key)); - t = t->next; - } - } -} - -static void -reset_translations(void) -{ - int i; - for (i=0;i!=TRANSMAXHASH;++i) { - translation * t = translation_table[i]; - while (t) { - translation * c = t->next; - free(t->key); - t->next = junkyard; - junkyard = t; - t = c; - } - translation_table[i] = 0; - } -} - -#include - -static void -print_items(FILE * F, item * items, const struct locale * lang) -{ - item * itm; - - for (itm=items; itm; itm=itm->next) { - int in = itm->number; - const char * ic = resourcename(itm->type->rtype, 0); - if (itm==items) fputs("GEGENSTAENDE\n", F); - fprintf(F, "%d;%s\n", in, add_translation(ic, LOC(lang, ic))); - } -} - -static void -cr_output_curses(FILE * F, const faction * viewer, const void * obj, typ_t typ) -{ - boolean header = false; - attrib *a = NULL; - int self = 0; - region *r; - - /* Die Sichtbarkeit eines Zaubers und die Zaubermeldung sind bei - * Gebäuden und Schiffen je nach, ob man Besitzer ist, verschieden. - * Bei Einheiten sieht man Wirkungen auf eigene Einheiten immer. - * Spezialfälle (besonderes Talent, verursachender Magier usw. werde - * bei jedem curse gesondert behandelt. */ - if (typ == TYP_SHIP){ - ship * sh = (ship*)obj; - unit * owner = shipowner(sh); - a = sh->attribs; - r = sh->region; - if (owner != NULL) { - if (owner->faction == viewer){ - self = 2; - } else { /* steht eine person der Partei auf dem Schiff? */ - unit *u = NULL; - for (u = r->units; u; u = u->next) { - if (u->ship == sh) { - self = 1; - break; - } - } - } - } - } else if (typ == TYP_BUILDING) { - building * b = (building*)obj; - unit * owner = building_owner(b); - a = b->attribs; - r = b->region; - if (owner != NULL){ - if (owner->faction == viewer){ - self = 2; - } else { /* steht eine Person der Partei in der Burg? */ - unit *u = NULL; - for (u = r->units; u; u = u->next) { - if (u->building == b) { - self = 1; - break; - } - } - } - } - } else if (typ == TYP_UNIT) { - unit *u = (unit *)obj; - a = u->attribs; - r = u->region; - if (u->faction == viewer) { - self = 2; - } - } else if (typ == TYP_REGION) { - r = (region *)obj; - a = r->attribs; - } else { - /* fehler */ - } - - while (a) { - if (fval(a->type, ATF_CURSE)) { - curse * c = (curse *)a->data.v; - message * msg; - - if (c->type->cansee) { - self = c->type->cansee(viewer, obj, typ, c, self); - } - msg = msg_curse(c, obj, typ, self); - - if (msg) { - char buf[BUFFERSIZE]; - if (!header) { - header = 1; - fputs("EFFECTS\n", F); - } - nr_render(msg, viewer->locale, buf, sizeof(buf), viewer); - fprintf(F, "\"%s\"\n", buf); - msg_release(msg); - } - } else if (a->type==&at_effect && self) { - effect_data * data = (effect_data *)a->data.v; - if (data->value>0) { - const char * key = resourcename(data->type->itype->rtype, 0); - if (!header) { - header = 1; - fputs("EFFECTS\n", F); - } - fprintf(F, "\"%d %s\"\n", data->value, add_translation(key, locale_string(default_locale, key))); - } - } - a = a->next; - } -} - -static int -cr_unit(variant var, char * buffer, const void * userdata) -{ - unit * u = (unit *)var.v; - sprintf(buffer, "%d", u?u->no:-1); - return 0; -} - -static int -cr_ship(variant var, char * buffer, const void * userdata) -{ - ship * u = (ship *)var.v; - sprintf(buffer, "%d", u?u->no:-1); - return 0; -} - -static int -cr_building(variant var, char * buffer, const void * userdata) -{ - building * u = (building *)var.v; - sprintf(buffer, "%d", u?u->no:-1); - return 0; -} - -static int -cr_faction(variant var, char * buffer, const void * userdata) -{ - faction * f = (faction *)var.v; - sprintf(buffer, "%d", f?f->no:-1); - return 0; -} - -static int -cr_region(variant var, char * buffer, const void * userdata) -{ - const faction * report = (const faction*)userdata; - region * r = (region *)var.v; - if (r) { - plane * pl = rplane(r); - int nx = r->x, ny = r->y; - pnormalize(&nx, &ny, pl); - adjust_coordinates(report, &nx, &ny, pl, r); - sprintf(buffer, "%d %d %d", nx, ny, plane_id(pl)); - return 0; - } - return -1; -} - -static int -cr_resource(variant var, char * buffer, const void * userdata) -{ - const faction * report = (const faction*)userdata; - const resource_type * r = (const resource_type *)var.v; - if (r) { - const char * key = resourcename(r, 0); - sprintf(buffer, "\"%s\"", - add_translation(key, locale_string(report->locale, key))); - return 0; - } - return -1; -} - -static int -cr_race(variant var, char * buffer, const void * userdata) -{ - const faction * report = (const faction*)userdata; - const struct race * rc = (const race *)var.v; - const char * key = rc_name(rc, 0); - sprintf(buffer, "\"%s\"", - add_translation(key, locale_string(report->locale, key))); - return 0; -} - -static int -cr_alliance(variant var, char * buffer, const void * userdata) -{ - const alliance * al = (const alliance *)var.v; - if (al!=NULL) { - sprintf(buffer, "%d", al->id); - } - unused(userdata); - return 0; -} - -static int -cr_skill(variant var, char * buffer, const void * userdata) -{ - const faction * report = (const faction*)userdata; - skill_t sk = (skill_t)var.i; - if (sk!=NOSKILL) sprintf(buffer, "\"%s\"", - add_translation(mkname("skill", skillnames[sk]), skillname(sk, report->locale))); - else strcpy(buffer, "\"\""); - return 0; -} - -static int -cr_order(variant var, char * buffer, const void * userdata) -{ - order * ord = (order*)var.v; - if (ord!=NULL) { - char * wp = buffer; - char * cmd = getcommand(ord); - const char * rp = cmd; - - *wp++ = '\"'; - while (*rp) { - switch (*rp) { - case '\"': - case '\\': - *wp++ = '\\'; - default: - *wp++ = *rp++; - } - } - *wp++ = '\"'; - *wp++ = 0; - - free(cmd); - } - else strcpy(buffer, "\"\""); - return 0; -} - -static int -cr_resources(variant var, char * buffer, const void * userdata) -{ - faction * f = (faction*)userdata; - resource * rlist = (resource*)var.v; - char * wp = buffer; - if (rlist!=NULL) { - const char * name = resourcename(rlist->type, rlist->number!=1); - wp += sprintf(wp, "\"%d %s", rlist->number, add_translation(name, LOC(f->locale, name))); - for (;;) { - rlist = rlist->next; - if (rlist==NULL) break; - name = resourcename(rlist->type, rlist->number!=1); - wp += sprintf(wp, ", %d %s", rlist->number, add_translation(name, LOC(f->locale, name))); - } - strcat(wp, "\""); - } - return 0; -} - -static int -cr_regions(variant var, char * buffer, const void * userdata) -{ - faction * f = (faction*)userdata; - const arg_regions * rdata = (const arg_regions *)var.v; - - if (rdata!=NULL && rdata->nregions>0) { - region * r = rdata->regions[0]; - plane * pl = rplane(r); - int i, z = plane_id(pl); - char * wp = buffer; - int nx = r->x, ny = r->y; - - pnormalize(&nx, &ny, pl); - adjust_coordinates(f, &nx, &ny, pl, r); - wp += sprintf(wp, "\"%d %d %d", nx, ny, z); - for (i=1;i!=rdata->nregions;++i) { - r = rdata->regions[i]; - pl = rplane(r); - z = plane_id(pl); - wp += sprintf(wp, ", %d %d %d", nx, ny, z); - } - strcat(wp, "\""); - } else { - strcpy(buffer, "\"\""); - } - return 0; -} - -static int -cr_spell(variant var, char * buffer, const void * userdata) -{ - const faction * report = (const faction*)userdata; - spell * sp = (spell*)var.v; - if (sp!=NULL) sprintf(buffer, "\"%s\"", spell_name(sp, report->locale)); - else strcpy(buffer, "\"\""); - return 0; -} - -static int -cr_curse(variant var, char * buffer, const void * userdata) -{ - const faction * report = (const faction*)userdata; - const curse_type * ctype = (const curse_type*)var.v; - if (ctype!=NULL) { - sprintf(buffer, "\"%s\"", curse_name(ctype, report->locale)); - } else strcpy(buffer, "\"\""); - return 0; -} - -/*static int msgno; */ - -#define MTMAXHASH 1021 - -static struct known_mtype { - const struct message_type * mtype; - struct known_mtype * nexthash; -} * mtypehash[MTMAXHASH]; - -static void -report_crtypes(FILE * F, const struct locale* lang) -{ - int i; - for (i=0;i!=MTMAXHASH;++i) { - struct known_mtype * kmt; - for (kmt=mtypehash[i];kmt;kmt=kmt->nexthash) { - const struct nrmessage_type * nrt = nrt_find(lang, kmt->mtype); - if (nrt) { - unsigned int hash = kmt->mtype->key; - fprintf(F, "MESSAGETYPE %d\n", hash); - fputc('\"', F); - fputs(escape_string(nrt_string(nrt), NULL, 0), F); - fputs("\";text\n", F); - fprintf(F, "\"%s\";section\n", nrt_section(nrt)); - } - } - while (mtypehash[i]) { - kmt = mtypehash[i]; - mtypehash[i] = mtypehash[i]->nexthash; - free(kmt); - } - } -} - -static unsigned int -messagehash(const struct message * msg) -{ - variant var; - var.v = (void *)msg; - return (unsigned int)var.i; -} - -static void -render_messages(FILE * F, faction * f, message_list *msgs) -{ - struct mlist* m = msgs->begin; - while (m) { - char crbuffer[BUFFERSIZE]; /* gross, wegen spionage-messages :-( */ - boolean printed = false; - const struct message_type * mtype = m->msg->type; - unsigned int hash = mtype->key; -#ifdef RENDER_CRMESSAGES - char nrbuffer[1024*32]; - nrbuffer[0] = '\0'; - if (nr_render(m->msg, f->locale, nrbuffer, sizeof(nrbuffer), f)>=0) { - fprintf(F, "MESSAGE %u\n", messagehash(m->msg)); - fprintf(F, "%d;type\n", hash); - fwritestr(F, nrbuffer); - fputs(";rendered\n", F); - printed = true; - } -#endif - crbuffer[0] = '\0'; - if (cr_render(m->msg, crbuffer, (const void*)f)==0) { - if (!printed) fprintf(F, "MESSAGE %u\n", messagehash(m->msg)); - if (crbuffer[0]) fputs(crbuffer, F); - } else { - log_error(("could not render cr-message %p: %s\n", m->msg, m->msg->type->name)); - } - if (printed) { - unsigned int ihash = hash % MTMAXHASH; - struct known_mtype * kmt = mtypehash[ihash]; - while (kmt && kmt->mtype != mtype) kmt = kmt->nexthash; - if (kmt==NULL) { - kmt = (struct known_mtype*)malloc(sizeof(struct known_mtype)); - kmt->nexthash = mtypehash[ihash]; - kmt->mtype = mtype; - mtypehash[ihash] = kmt; - } - } - m = m->next; - } -} - -static void -cr_output_messages(FILE * F, message_list *msgs, faction * f) -{ - if (msgs) render_messages(F, f, msgs); -} - -/* prints a building */ -static void -cr_output_building(FILE * F, building * b, const unit * owner, int fno, faction *f) -{ - const char * bname, * billusion; - - fprintf(F, "BURG %d\n", b->no); - - report_building(b, &bname, &billusion); - if (billusion) { - fprintf(F, "\"%s\";Typ\n", add_translation(billusion, LOC(f->locale, billusion))); - if (owner && owner->faction==f) { - fprintf(F, "\"%s\";wahrerTyp\n", add_translation(bname, LOC(f->locale, bname))); - } - } else { - fprintf(F, "\"%s\";Typ\n", add_translation(bname, LOC(f->locale, bname))); - } - 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 ? owner->no : -1); - if (fno >= 0) - fprintf(F, "%d;Partei\n", fno); - if (b->besieged) - fprintf(F, "%d;Belagerer\n", b->besieged); - cr_output_curses(F, f, b, TYP_BUILDING); -} -/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ - -/* prints a ship */ -static void -cr_output_ship(FILE * F, 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); - if (sh->display && sh->display[0]) - fprintf(F, "\"%s\";Beschr\n", sh->display); - fprintf(F, "\"%s\";Typ\n", add_translation(sh->type->name[0], locale_string(f->locale, sh->type->name[0]))); - fprintf(F, "%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); - } - if (u) - fprintf(F, "%d;Kapitaen\n", u ? u->no : -1); - 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)); - } - /* shore */ - w = NODIRECTION; - if (!fval(r->terrain, SEA_REGION)) w = sh->coast; - if (w != NODIRECTION) - fprintf(F, "%d;Kueste\n", w); - - cr_output_curses(F, f, sh, TYP_SHIP); -} - -static void -fwriteorder(FILE * F, const struct order * ord, const struct locale * lang, boolean escape) -{ - char ebuf[1024]; - char obuf[1024]; - const char * str = obuf; - fputc('"', F); - write_order(ord, obuf, sizeof(obuf)); - if (escape) { - str = escape_string(obuf, ebuf, sizeof(ebuf)); - } - if (str[0]) fputs(str, F); - fputc('"', F); -} - -static void cr_output_spells(FILE * F, spell_list * slist, const faction * f, int maxlevel) -{ - if (slist) { - fprintf(F, "SPRUECHE\n"); - for (;slist; slist = slist->next) { - spell * sp = slist->data; - if (sp->level <= maxlevel) { - const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, f->locale)); - fprintf(F, "\"%s\"\n", name); - } - } - } -} - -/* prints all that belongs to a unit */ -static void -cr_output_unit(FILE * F, const region * r, - const faction * f, /* observers faction */ - const unit * u, int mode) -{ - /* Race attributes are always plural and item attributes always - * singular */ - const char * str; - const item_type * lasttype; - int pr; - item *itm, *show; - building * b; - const char * pzTmp; - skill * sv; - const attrib *a_fshidden = NULL; - boolean itemcloak = false; - static const curse_type * itemcloak_ct = 0; - static boolean init = false; - item result[MAX_INVENTORY]; - - if (fval(u->race, RCF_INVISIBLE)) return; - - if (!init) { - init = true; - itemcloak_ct = ct_find("itemcloak"); - } - if (itemcloak_ct!=NULL) { - itemcloak = curse_active(get_curse(u->attribs, itemcloak_ct)); - } - - assert(u && u->number); - - fprintf(F, "EINHEIT %d\n", u->no); - fprintf(F, "\"%s\";Name\n", u->name); - str = u_description(u, f->locale); - if (str) { - fprintf(F, "\"%s\";Beschr\n", str); - } - { - /* print faction information */ - const faction * sf = visible_faction(f, u); - const char * prefix = raceprefix(u); - if (u->faction == f || omniscient(f)) { - const attrib * a_otherfaction = a_find(u->attribs, &at_otherfaction); - const faction * otherfaction = a_otherfaction?get_otherfaction(a_otherfaction):NULL; - /* my own faction, full info */ - const attrib *a = NULL; - unit * mage; - - if (fval(u, UFL_GROUP)) a = a_find(u->attribs, &at_group); - if (a!=NULL) { - const group * g = (const group*)a->data.v; - fprintf(F, "%d;gruppe\n", g->gid); - } - fprintf(F, "%d;Partei\n", u->faction->no); - if (sf!=u->faction) fprintf(F, "%d;Verkleidung\n", sf->no); - if (fval(u, UFL_ANON_FACTION)) - fprintf(F, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION))); - if (otherfaction) { - if (otherfaction!=u->faction) { - fprintf(F, "%d;Anderepartei\n", otherfaction->no); - } - } - mage = get_familiar_mage(u); - if (mage) { - fprintf(F, "%u;familiarmage\n", mage->no); - } - } else { - if (fval(u, UFL_ANON_FACTION)) { - /* faction info is hidden */ - fprintf(F, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION))); - } else { - const attrib * a_otherfaction = a_find(u->attribs, &at_otherfaction); - const faction * otherfaction = a_otherfaction?get_otherfaction(a_otherfaction):NULL; - /* other unit. show visible faction, not u->faction */ - fprintf(F, "%d;Partei\n", sf->no); - if (sf == f) { - fprintf(F, "1;Verraeter\n"); - } - if (a_otherfaction) { - if (otherfaction!=u->faction) { - if (alliedunit(u, f, HELP_FSTEALTH)) { - fprintf(F, "%d;Anderepartei\n", otherfaction->no); - } - } - } - } - } - if (prefix) { - prefix = mkname("prefix", prefix); - fprintf(F, "\"%s\";typprefix\n", add_translation(prefix, LOC(f->locale, prefix))); - } - } - if (u->faction != f && a_fshidden - && a_fshidden->data.ca[0] == 1 && effskill(u, SK_STEALTH) >= 6) { - fprintf(F, "-1;Anzahl\n"); - } else { - fprintf(F, "%d;Anzahl\n", u->number); - } - - pzTmp = get_racename(u->attribs); - if (pzTmp) { - fprintf(F, "\"%s\";Typ\n", pzTmp); - if (u->faction==f && fval(u->race, RCF_SHAPESHIFTANY)) { - const char * zRace = rc_name(u->race, 1); - fprintf(F, "\"%s\";wahrerTyp\n", - add_translation(zRace, locale_string(f->locale, zRace))); - } - } else { - const race * irace = u_irace(u); - const char * zRace = rc_name(irace, 1); - fprintf(F, "\"%s\";Typ\n", - add_translation(zRace, locale_string(f->locale, zRace))); - if (u->faction==f && irace!=u->race) { - assert(skill_enabled[SK_STEALTH] || !"we're resetting this on load, so.. ircase should never be used"); - zRace = rc_name(u->race, 1); - fprintf(F, "\"%s\";wahrerTyp\n", - add_translation(zRace, locale_string(f->locale, zRace))); - } - } - - if (u->building) { - assert(u->building->region); - fprintf(F, "%d;Burg\n", u->building->no); - } - if (u->ship) { - assert(u->ship->region); - fprintf(F, "%d;Schiff\n", u->ship->no); - } - if (is_guard(u, GUARD_ALL)!=0) { - fprintf(F, "%d;bewacht\n", 1); - } - if ((b=usiege(u))!=NULL) { - fprintf(F, "%d;belagert\n", b->no); - } - /* additional information for own units */ - if (u->faction == f || omniscient(f)) { - order * ord; - const char *xc; - const char * c; - int i; - - i = ualias(u); - if (i>0) - fprintf(F, "%d;temp\n", i); - else if (i<0) - fprintf(F, "%d;alias\n", -i); - i = get_money(u); - fprintf(F, "%d;Kampfstatus\n", u->status); - fprintf(F, "%d;weight\n", weight(u)); - if (fval(u, UFL_NOAID)) { - fputs("1;unaided\n", F); - } - if (fval(u, UFL_STEALTH)) { - i = u_geteffstealth(u); - if (i >= 0) { - fprintf(F, "%d;Tarnung\n", i); - } - } - xc = uprivate(u); - if (xc) { - fprintf(F, "\"%s\";privat\n", xc); - } - c = hp_status(u); - if (c && *c && (u->faction == f || omniscient(f))) { - fprintf(F, "\"%s\";hp\n", add_translation(c, locale_string(u->faction->locale, c))); - } - if (fval(u, UFL_HERO)) { - fputs("1;hero\n", F); - } - - if (fval(u, UFL_HUNGER) && (u->faction == f)) { - fputs("1;hunger\n", F); - } - if (is_mage(u)) { - fprintf(F, "%d;Aura\n", get_spellpoints(u)); - fprintf(F, "%d;Auramax\n", max_spellpoints(u->region,u)); - } - /* default commands */ - fprintf(F, "COMMANDS\n"); - for (ord = u->old_orders; ord; ord = ord->next) { - /* this new order will replace the old defaults */ - if (is_persistent(ord)) { - fwriteorder(F, ord, f->locale, true); - fputc('\n', F); - } - } - for (ord = u->orders; ord; ord = ord->next) { - if (u->old_orders && is_repeated(ord)) continue; /* unit has defaults */ - if (is_persistent(ord)) { - fwriteorder(F, ord, f->locale, true); - fputc('\n', F); - } - } - - /* talents */ - pr = 0; - for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - if (sv->level>0) { - skill_t sk = sv->id; - int esk = eff_skill(u, sk, r); - if (!pr) { - pr = 1; - fprintf(F, "TALENTE\n"); - } - fprintf(F, "%d %d;%s\n", u->number*level_days(sv->level), esk, - add_translation(mkname("skill", skillnames[sk]), skillname(sk, f->locale))); - } - } - /* spells */ - if (is_mage(u)) { - sc_mage * mage = get_mage(u); - spell_list ** slistp = get_spelllist(mage, u->faction); - int i, maxlevel = effskill(u, SK_MAGIC); - - cr_output_spells(F, *slistp, f, maxlevel); - - for (i=0;i!=MAXCOMBATSPELLS;++i) { - const spell * sp = mage->combatspells[i].sp; - if (sp) { - const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, f->locale)); - fprintf(F, "KAMPFZAUBER %d\n", i); - fprintf(F, "\"%s\";name\n", name); - fprintf(F, "%d;level\n", mage->combatspells[i].level); - } - } - } - } - /* items */ - pr = 0; - if (f == u->faction || omniscient(u->faction)) { - show = u->items; - } else if (itemcloak==false && mode>=see_unit && !(a_fshidden - && a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) - { - int n = report_items(u->items, result, MAX_INVENTORY, u, f); - assert(n>=0); - if (n>0) show = result; - else show = NULL; - } else { - show = NULL; - } - lasttype = NULL; - for (itm=show; itm; itm=itm->next) { - const char * ic; - int in; - assert(itm->type!=lasttype || !"error: list contains two objects of the same item"); - report_item(u, itm, f, NULL, &ic, &in, true); - if (in==0) continue; - if (!pr) { - pr = 1; - fputs("GEGENSTAENDE\n", F); - } - fprintf(F, "%d;%s\n", in, add_translation(ic, locale_string(f->locale, ic))); - } - - cr_output_curses(F, f, u, TYP_UNIT); -} -/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ - -/* prints allies */ -static void -show_allies_cr(FILE * F, const faction * f, const ally * sf) -{ - for (; sf; sf = sf->next) if (sf->faction) { - int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); - if (mode!=0 && sf->status>0) { - fprintf(F, "ALLIANZ %d\n", sf->faction->no); - fprintf(F, "\"%s\";Parteiname\n", sf->faction->name); - fprintf(F, "%d;Status\n", sf->status & HELP_ALL); - } - } -} - -/* prints allies */ -static void -show_alliances_cr(FILE * F, const faction * f) -{ - alliance * al = f_get_alliance(f); - if (al) { - faction * lead = alliance_get_leader(al); - assert(lead); - fprintf(F, "ALLIANCE %d\n", al->id); - fprintf(F, "\"%s\";name\n", al->name); - fprintf(F, "%d;leader\n", lead->no); - } -} - -/* prints all visible spells in a region */ -static void -show_active_spells(const region * r) -{ - char fogwall[MAXDIRECTIONS]; -#ifdef TODO /* alte Regionszauberanzeigen umstellen */ - unit *u; - int env = 0; -#endif - memset(fogwall, 0, sizeof(char) * MAXDIRECTIONS); - -} -/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ - -/* this is a copy of laws.c->find_address output changed. */ -static void -cr_find_address(FILE * F, const faction * uf, const faction_list * addresses) -{ - const faction_list * flist = addresses; - while (flist!=NULL) { - const faction * f = flist->data; - if (uf!=f) { - fprintf(F, "PARTEI %d\n", f->no); - fprintf(F, "\"%s\";Parteiname\n", f->name); - if (f->email) fprintf(F, "\"%s\";email\n", f->email); - if (f->banner) fprintf(F, "\"%s\";banner\n", f->banner); - fprintf(F, "\"%s\";locale\n", locale_name(f->locale)); - if (f->alliance && f->alliance==uf->alliance) { - fprintf(F, "%d;alliance\n", f->alliance->id); - } - } - flist = flist->next; - } -} -/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ - -static void -cr_reportspell(FILE * F, spell *sp, const struct locale * lang) -{ - int k; - const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, lang)); - - fprintf(F, "ZAUBER %d\n", hashstring(sp->sname)); - fprintf(F, "\"%s\";name\n", name); - fprintf(F, "%d;level\n", sp->level); - fprintf(F, "%d;rank\n", sp->rank); - fprintf(F, "\"%s\";info\n", spell_info(sp, lang)); - if (sp->parameter) fprintf(F, "\"%s\";syntax\n", sp->parameter); - else fputs("\"\";syntax\n", F); - - if (sp->sptyp & PRECOMBATSPELL) fputs("\"precombat\";class\n", F); - else if (sp->sptyp & COMBATSPELL) fputs("\"combat\";class\n", F); - else if (sp->sptyp & POSTCOMBATSPELL) fputs("\"postcombat\";class\n", F); - else fputs("\"normal\";class\n", F); - - if (sp->sptyp & FARCASTING) fputs("1;far\n", F); - if (sp->sptyp & OCEANCASTABLE) fputs("1;ocean\n", F); - if (sp->sptyp & ONSHIPCAST) fputs("1;ship\n", F); - if (!(sp->sptyp & NOTFAMILIARCAST)) fputs("1;familiar\n", F); - fputs("KOMPONENTEN\n", F); - - for (k = 0; sp->components[k].type; ++k) { - const resource_type * rtype = sp->components[k].type; - int itemanz = sp->components[k].amount; - int costtyp = sp->components[k].cost; - if (itemanz > 0) { - const char * name = resourcename(rtype, 0); - fprintf(F, "%d %d;%s\n", itemanz, costtyp == SPC_LEVEL || costtyp == SPC_LINEAR, - add_translation(name, LOC(lang, name))); - } - } -} - -static char * -cr_output_resource(char * buf, const char * name, const struct locale * loc, int amount, int level) -{ - buf += sprintf(buf, "RESOURCE %u\n", hashstring(name)); - buf += sprintf(buf, "\"%s\";type\n", add_translation(name, LOC(loc, name))); - if (amount>=0) { - if (level>=0) buf += sprintf(buf, "%d;skill\n", level); - buf += sprintf(buf, "%d;number\n", amount); - } - return buf; -} - -static void -cr_borders(seen_region ** seen, const region * r, const faction * f, int seemode, FILE * F) -{ - direction_t d; - int g = 0; - for (d = 0; d != MAXDIRECTIONS; d++) - { /* Nachbarregionen, die gesehen werden, ermitteln */ - const region * r2 = rconnect(r, d); - const connection * b; - if (!r2) continue; - if (seemode==see_neighbour) { - seen_region * sr = find_seen(seen, r2); - if (sr==NULL || sr->mode<=see_neighbour) continue; - } - b = get_borders(r, r2); - while (b) { - boolean cs = b->type->fvisible(b, f, r); - - if (!cs) { - cs = b->type->rvisible(b, r); - if (!cs) { - unit * us = r->units; - while (us && !cs) { - if (us->faction==f) { - cs = b->type->uvisible(b, us); - if (cs) break; - } - us=us->next; - } - } - } - if (cs) { - const char * bname = mkname("border", b->type->name(b, r, f, GF_PURE)); - fprintf(F, "GRENZE %d\n", ++g); - fprintf(F, "\"%s\";typ\n", LOC(default_locale, bname)); - fprintf(F, "%d;richtung\n", d); - if (!b->type->transparent(b, f)) fputs("1;opaque\n", F); - /* hack: */ - if (b->type==&bt_road) { - int p = rroad(r, d)*100/r->terrain->max_road; - fprintf(F, "%d;prozent\n", p); - } - } - b = b->next; - } - } -} - -static void -cr_output_resources(FILE * F, report_context * ctx, seen_region * sr) -{ - char cbuf[BUFFERSIZE], *pos = cbuf; - region * r = sr->r; - faction * f = ctx->f; - resource_report result[MAX_RAWMATERIALS]; - int n, size = report_resources(sr, result, MAX_RAWMATERIALS, f); - -#ifdef RESOURCECOMPAT - int trees = rtrees(r, 2); - int saplings = rtrees(r, 1); - - if (trees > 0) fprintf(F, "%d;Baeume\n", trees); - if (saplings > 0) fprintf(F, "%d;Schoesslinge\n", saplings); - if (fval(r, RF_MALLORN) && (trees > 0 || saplings > 0)) - fprintf(F, "1;Mallorn\n"); - for (n=0;n=0 && result[n].number>=0) { - fprintf(F, "%d;%s\n", result[n].number, crtag(result[n].name)); - } - } -#endif - - for (n=0;n=0) { - pos = cr_output_resource(pos, result[n].name, f->locale, result[n].number, result[n].level); - } - } - if (pos!=cbuf) fputs(cbuf, F); -} - -static void -cr_region_header(FILE * F, int plid, int nx, int ny, unsigned int uid) -{ - if (plid==0) { - fprintf(F, "REGION %d %d\n", nx, ny); - } else { - fprintf(F, "REGION %d %d %d\n", nx, ny, plid); - } - if (uid) fprintf(F, "%d;id\n", uid); -} - -static void -cr_output_region(FILE * F, report_context * ctx, seen_region * sr) -{ - faction * f = ctx->f; - region * r = sr->r; - plane * pl = rplane(r); - int plid = plane_id(pl), nx, ny; - const char * tname; - int oc[4][2], o = 0; - int uid = r->uid; - -#ifdef OCEAN_NEIGHBORS_GET_NO_ID - if (sr->mode<=see_neighbour && !r->land) { - uid = 0; - } -#endif - - if (opt_cr_absolute_coords) { - nx = r->x; - ny = r->y; - } else { - nx = r->x, ny = r->y; - pnormalize(&nx, &ny, pl); - adjust_coordinates(f, &nx, &ny, pl, r); - } - - if (pl) { - if (ny==pl->maxy) { - oc[o][0] = nx; - oc[o++][1] = pl->miny-1; - } - if (nx==pl->maxx) { - oc[o][0] = pl->minx-1; - oc[o++][1] = ny; - } - if (ny==pl->miny) { - oc[o][0] = nx; - oc[o++][1] = pl->maxy+1; - } - if (nx==pl->minx) { - oc[o][0] = pl->maxx+1; - oc[o++][1] = ny; - } - } - while (o--) { - cr_region_header(F, plid, oc[o][0], oc[o][1], uid); - fputs("\"wrap\";visibility\n", F); - } - - cr_region_header(F, plid, nx, ny, uid); - - if (r->land) { - const char * str = rname(r, f->locale); - if (str && str[0]) { - fprintf(F, "\"%s\";Name\n", str); - } - } - tname = terrain_name(r); - - fprintf(F, "\"%s\";Terrain\n", add_translation(tname, locale_string(f->locale, tname))); - if (sr->mode!=see_unit) fprintf(F, "\"%s\";visibility\n", visibility[sr->mode]); - if (sr->mode == see_neighbour) { - cr_borders(ctx->seen, r, f, sr->mode, F); - } else { - building * b; - ship * sh; - unit * u; - int stealthmod = stealth_modifier(sr->mode); - - if (r->display && r->display[0]) - fprintf(F, "\"%s\";Beschr\n", r->display); - if (fval(r->terrain, LAND_REGION)) { - fprintf(F, "%d;Bauern\n", rpeasants(r)); - if(fval(r, RF_ORCIFIED)) { - fprintf(F, "1;Verorkt\n"); - } - fprintf(F, "%d;Pferde\n", rhorses(r)); - - if (sr->mode>=see_unit) { - if (rule_region_owners()) { - faction * owner = region_get_owner(r); - if (owner) { - fprintf(F, "%d;owner\n", owner->no); - } - } - fprintf(F, "%d;Silber\n", rmoney(r)); - if (skill_enabled[SK_ENTERTAINMENT]) { - fprintf(F, "%d;Unterh\n", entertainmoney(r)); - } - if (is_cursed(r->attribs, C_RIOT, 0)){ - fputs("0;Rekruten\n", F); - } else { - fprintf(F, "%d;Rekruten\n", rpeasants(r) / RECRUITFRACTION); - } - if (production(r)) { - int p_wage = wage(r, NULL, NULL, turn+1); - fprintf(F, "%d;Lohn\n", p_wage); - if (is_mourning(r, turn+1)) { - fputs("1;mourning\n", F); - } - } - if (r->land->ownership) { - fprintf(F, "%d;morale\n", r->land->morale); - } - } - - /* this writes both some tags (RESOURCECOMPAT) and a block. - * must not write any blocks before it */ - cr_output_resources(F, ctx, sr); - - if (sr->mode>=see_unit) { - /* trade */ - if (markets_module() && r->land) { - const item_type * lux = r_luxury(r); - const item_type * herb = r->land->herbtype; - if (lux || herb) { - fputs("PREISE\n", F); - if (lux) { - const char * ch = resourcename(lux->rtype, 0); - fprintf(F, "%d;%s\n", 1, add_translation(ch, locale_string(f->locale, ch))); - } - if (herb) { - const char * ch = resourcename(herb->rtype, 0); - fprintf(F, "%d;%s\n", 1, add_translation(ch, locale_string(f->locale, ch))); - } - } - } else if (rpeasants(r)/TRADE_FRACTION > 0) { - struct demand * dmd = r->land->demands; - fputs("PREISE\n", F); - while (dmd) { - const char * ch = resourcename(dmd->type->itype->rtype, 0); - fprintf(F, "%d;%s\n", (dmd->value - ? dmd->value*dmd->type->price - : -dmd->type->price), - add_translation(ch, locale_string(f->locale, ch))); - dmd=dmd->next; - } - } - } - } - if (r->land) { - print_items(F, r->land->items, f->locale); - } - cr_output_curses(F, f, r, TYP_REGION); - cr_borders(ctx->seen, r, f, sr->mode, F); - if (sr->mode==see_unit && is_astral(r) && !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) - { - /* Sonderbehandlung Teleport-Ebene */ - region_list *rl = astralregions(r, inhabitable); - - if (rl) { - region_list *rl2 = rl; - while(rl2) { - region * r = rl2->data; - int nx = r->x, ny = r->y; - plane * plx = rplane(r); - - pnormalize(&nx, &ny, plx); - adjust_coordinates(f, &nx, &ny, plx, r); - fprintf(F, "SCHEMEN %d %d\n", nx, ny); - fprintf(F, "\"%s\";Name\n", rname(r, f->locale)); - rl2 = rl2->next; - } - free_regionlist(rl); - } - } - - /* describe both passed and inhabited regions */ - show_active_spells(r); - if (fval(r, RF_TRAVELUNIT)) { - boolean seeunits = false, seeships = false; - const attrib * ru; - /* show units pulled through region */ - for (ru = a_find(r->attribs, &at_travelunit); ru && ru->type==&at_travelunit; ru = ru->next) { - unit * u = (unit*)ru->data.v; - if (cansee_durchgezogen(f, r, u, 0) && r!=u->region) { - if (!u->ship || !fval(u, UFL_OWNER)) continue; - if (!seeships) fprintf(F, "DURCHSCHIFFUNG\n"); - seeships = true; - fprintf(F, "\"%s\"\n", shipname(u->ship)); - } - } - for (ru = a_find(r->attribs, &at_travelunit); ru && ru->type==&at_travelunit; ru = ru->next) { - unit * u = (unit*)ru->data.v; - if (cansee_durchgezogen(f, r, u, 0) && r!=u->region) { - if (u->ship) continue; - if (!seeunits) fprintf(F, "DURCHREISE\n"); - seeunits = true; - fprintf(F, "\"%s\"\n", unitname(u)); - } - } - } - cr_output_messages(F, r->msgs, f); - { - message_list * mlist = r_getmessages(r, f); - if (mlist) cr_output_messages(F, mlist, f); - } - /* buildings */ - for (b = rbuildings(r); b; b = b->next) { - int fno = -1; - u = building_owner(b); - if (u && !fval(u, UFL_ANON_FACTION)) { - const faction * sf = visible_faction(f,u); - fno = sf->no; - } - cr_output_building(F, b, u, fno, f); - } - - /* ships */ - for (sh = r->ships; sh; sh = sh->next) { - int fno = -1; - u = shipowner(sh); - if (u && !fval(u, UFL_ANON_FACTION)) { - const faction * sf = visible_faction(f,u); - fno = sf->no; - } - - cr_output_ship(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))) { - cr_output_unit(F, r, f, u, sr->mode); - } - } - } -} - -/* main function of the creport. creates the header and traverses all regions */ -static int -report_computer(const char * filename, report_context * ctx, const char * charset) -{ - static int era = -1; - int i; - faction * f = ctx->f; - const char * prefix; - region * r; - const char * mailto = locale_string(f->locale, "mailto"); - const attrib * a; - seen_region * sr = NULL; -#if SCORE_MODULE - int score = 0, avgscore = 0; -#endif - int enc = xmlParseCharEncoding(charset); - FILE * F = fopen(filename, "wt"); - - if (era<0) { - era = get_param_int(global.parameters, "world.era", 2); - } - if (F==NULL) { - perror(filename); - return -1; - } else if (enc==XML_CHAR_ENCODING_UTF8) { - const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; - fwrite(utf8_bom, 1, 3, F); - } - - /* must call this to get all the neighbour regions */ - /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ - /* initialisations, header and lists */ - - fprintf(F, "VERSION %d\n", C_REPORT_VERSION); - fprintf(F, "\"%s\";charset\n", charset); - fprintf(F, "\"%s\";locale\n", locale_name(f->locale)); - fprintf(F, "%d;noskillpoints\n", 1); - fprintf(F, "%ld;date\n", ctx->report_time); - fprintf(F, "\"%s\";Spiel\n", global.gamename); - fprintf(F, "\"%s\";Konfiguration\n", "Standard"); - fprintf(F, "\"%s\";Koordinaten\n", "Hex"); - fprintf(F, "%d;Basis\n", 36); - fprintf(F, "%d;Runde\n", turn); - fprintf(F, "%d;Zeitalter\n", era); - if (mailto!=NULL) { - fprintf(F, "\"%s\";mailto\n", mailto); - fprintf(F, "\"%s\";mailcmd\n", locale_string(f->locale, "mailcmd")); - } - - show_alliances_cr(F, f); - - fprintf(F, "PARTEI %d\n", f->no); - fprintf(F, "\"%s\";locale\n", locale_name(f->locale)); - if (f_get_alliance(f)) { - fprintf(F, "%d;alliance\n", f->alliance->id); - fprintf(F, "%d;joined\n", f->alliance_joindate); - } - fprintf(F, "%d;age\n", f->age); - fprintf(F, "%d;Optionen\n", f->options); -#if SCORE_MODULE - if (f->options & want(O_SCORE) && f->age>DISPLAYSCORE) { - score = f->score; - avgscore = average_score_of_age(f->age, f->age / 24 + 1); - } - fprintf(F, "%d;Punkte\n", score); - fprintf(F, "%d;Punktedurchschnitt\n", avgscore); -#endif - { - const char * zRace = rc_name(f->race, 1); - fprintf(F, "\"%s\";Typ\n", add_translation(zRace, LOC(f->locale, zRace))); - } - prefix = get_prefix(f->attribs); - if (prefix!=NULL) { - prefix = mkname("prefix", prefix); - fprintf(F, "\"%s\";typprefix\n", - add_translation(prefix, LOC(f->locale, prefix))); - } - fprintf(F, "%d;Rekrutierungskosten\n", f->race->recruitcost); - fprintf(F, "%d;Anzahl Personen\n", count_all(f)); - fprintf(F, "\"%s\";Magiegebiet\n", magic_school[f->magiegebiet]); - - if (f->race == new_race[RC_HUMAN]) { - fprintf(F, "%d;Anzahl Immigranten\n", count_migrants(f)); - fprintf(F, "%d;Max. Immigranten\n", count_maxmigrants(f)); - } - - i = countheroes(f); - if (i>0) fprintf(F, "%d;heroes\n", i); - i = maxheroes(f); - if (i>0) fprintf(F, "%d;max_heroes\n", i); - - if (f->age > 1 && f->lastorders != turn) { - fprintf(F, "%d;nmr\n", turn-f->lastorders); - } - - fprintf(F, "\"%s\";Parteiname\n", f->name); - fprintf(F, "\"%s\";email\n", f->email); - if (f->banner) fprintf(F, "\"%s\";banner\n", f->banner); - print_items(F, f->items, f->locale); - fputs("OPTIONEN\n", F); - for (i=0;i!=MAXOPTIONS;++i) { - int flag = want(i); - if (options[i]) { - fprintf(F, "%d;%s\n", (f->options&flag)?1:0, options[i]); - } else if (f->options&flag) { - f->options &= (~flag); - } - } - show_allies_cr(F, f, f->allies); - { - group * g; - for (g=f->groups;g;g=g->next) { - - fprintf(F, "GRUPPE %d\n", g->gid); - fprintf(F, "\"%s\";name\n", g->name); - prefix = get_prefix(g->attribs); - if (prefix!=NULL) { - prefix = mkname("prefix", prefix); - fprintf(F, "\"%s\";typprefix\n", - add_translation(prefix, LOC(f->locale, prefix))); - } - show_allies_cr(F, f, g->allies); - } - } - - cr_output_messages(F, f->msgs, f); - { - struct bmsg * bm; - for (bm=f->battles;bm;bm=bm->next) { - plane * pl = rplane(bm->r); - int plid = plane_id(pl); - region * r = bm->r; - int nx = r->x, ny = r->y; - - pnormalize(&nx, &ny, pl); - adjust_coordinates(f, &nx, &ny, pl, r); - if (!plid) fprintf(F, "BATTLE %d %d\n", nx, ny); - else { - fprintf(F, "BATTLE %d %d %d\n", nx, ny, plid); - } - cr_output_messages(F, bm->msgs, f); - } - } - - cr_find_address(F, f, ctx->addresses); - a = a_find(f->attribs, &at_reportspell); - while (a && a->type==&at_reportspell) { - spell *sp = (spell *)a->data.v; - cr_reportspell(F, sp, f->locale); - a = a->next; - } - for (a=a_find(f->attribs, &at_showitem);a && a->type==&at_showitem;a=a->next) { - const potion_type * ptype = resource2potion(((const item_type*)a->data.v)->rtype); - const char * ch; - const char * description = NULL; - - if (ptype==NULL) continue; - ch = resourcename(ptype->itype->rtype, 0); - fprintf(F, "TRANK %d\n", hashstring(ch)); - fprintf(F, "\"%s\";Name\n", add_translation(ch, locale_string(f->locale, ch))); - fprintf(F, "%d;Stufe\n", ptype->level); - - if (description==NULL) { - const char * pname = resourcename(ptype->itype->rtype, 0); - const char * potiontext = mkname("potion", pname); - description = LOC(f->locale, potiontext); - } - - fprintf(F, "\"%s\";Beschr\n", description); - if (ptype->itype->construction) { - requirement * m = ptype->itype->construction->materials; - - fprintf(F, "ZUTATEN\n"); - - while (m->number) { - ch = resourcename(m->rtype, 0); - fprintf(F, "\"%s\"\n", add_translation(ch, locale_string(f->locale, ch))); - m++; - } - } - } - - /* traverse all regions */ - for (r=ctx->first;sr==NULL && r!=ctx->last;r=r->next) { - sr = find_seen(ctx->seen, r); - } - for (;sr!=NULL;sr=sr->next) { - cr_output_region(F, ctx, sr); - } - report_crtypes(F, f->locale); - write_translations(F); - reset_translations(); - fclose(F); - return 0; -} - -int -crwritemap(const char * filename) -{ - FILE * F = fopen(filename, "w"); - region * r; - - fprintf(F, "VERSION %d\n", C_REPORT_VERSION); - fputs("\"UTF-8\";charset\n", F); - - for (r=regions;r;r=r->next) { - plane * pl = rplane(r); - int plid = plane_id(pl); - if (plid) { - fprintf(F, "REGION %d %d %d\n", r->x, r->y, plid); - } else { - fprintf(F, "REGION %d %d\n", r->x, r->y); - } - fprintf(F, "\"%s\";Name\n\"%s\";Terrain\n", rname(r, default_locale), LOC(default_locale, terrain_name(r))); - } - fclose(F); - return 0; -} - -void -register_cr(void) -{ - tsf_register("report", &cr_ignore); - tsf_register("string", &cr_string); - tsf_register("order", &cr_order); - tsf_register("spell", &cr_spell); - tsf_register("curse", &cr_curse); - tsf_register("int", &cr_int); - tsf_register("unit", &cr_unit); - tsf_register("region", &cr_region); - tsf_register("faction", &cr_faction); - tsf_register("ship", &cr_ship); - tsf_register("building", &cr_building); - tsf_register("skill", &cr_skill); - tsf_register("resource", &cr_resource); - tsf_register("race", &cr_race); - tsf_register("direction", &cr_int); - tsf_register("alliance", &cr_alliance); - tsf_register("resources", &cr_resources); - tsf_register("items", &cr_resources); - tsf_register("regions", &cr_regions); - - if (!nocr) register_reporttype("cr", &report_computer, 1<next; - free(t); - } - junkyard = 0; -} - - +/* vi: set ts=2: ++-------------------+ Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel ++-------------------+ +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "creport.h" + +/* tweakable features */ +#define RENDER_CRMESSAGES +#define BUFFERSIZE 32768 +#define RESOURCECOMPAT + +/* modules include */ +#include + +/* attributes include */ +#include +#include +#include +#include +#include + +/* gamecode includes */ +#include "laws.h" +#include "economy.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include +#include + +/* imports */ +extern int verbosity; +boolean opt_cr_absolute_coords = false; + +/* globals */ +#define C_REPORT_VERSION 66 + +#define TAG_LOCALE "de" +#ifdef TAG_LOCALE +static const char * +crtag(const char * key) +{ + static const struct locale * lang = NULL; + if (!lang) lang = find_locale(TAG_LOCALE); + return locale_string(lang, key); +} +#else +#define crtag(x) (x) +#endif +/* + * translation table + */ +typedef struct translation { + struct translation * next; + char * key; + const char * value; +} translation; + +#define TRANSMAXHASH 257 +static translation * translation_table[TRANSMAXHASH]; +static translation * junkyard; + +static const char * +add_translation(const char * key, const char * value) +{ + int kk = ((key[0] << 5) + key[0]) % TRANSMAXHASH; + translation * t = translation_table[kk]; + while (t && strcmp(t->key, key)!=0) t=t->next; + if (!t) { + if (junkyard) { + t = junkyard; + junkyard = junkyard->next; + } else t = malloc(sizeof(translation)); + t->key = strdup(key); + t->value = value; + t->next = translation_table[kk]; + translation_table[kk] = t; + } + return crtag(key); +} + +static void +write_translations(FILE * F) +{ + int i; + fputs("TRANSLATION\n", F); + for (i=0;i!=TRANSMAXHASH;++i) { + translation * t = translation_table[i]; + while (t) { + fprintf(F, "\"%s\";%s\n", t->value, crtag(t->key)); + t = t->next; + } + } +} + +static void +reset_translations(void) +{ + int i; + for (i=0;i!=TRANSMAXHASH;++i) { + translation * t = translation_table[i]; + while (t) { + translation * c = t->next; + free(t->key); + t->next = junkyard; + junkyard = t; + t = c; + } + translation_table[i] = 0; + } +} + +#include + +static void +print_items(FILE * F, item * items, const struct locale * lang) +{ + item * itm; + + for (itm=items; itm; itm=itm->next) { + int in = itm->number; + const char * ic = resourcename(itm->type->rtype, 0); + if (itm==items) fputs("GEGENSTAENDE\n", F); + fprintf(F, "%d;%s\n", in, add_translation(ic, LOC(lang, ic))); + } +} + +static void +cr_output_curses(FILE * F, const faction * viewer, const void * obj, typ_t typ) +{ + boolean header = false; + attrib *a = NULL; + int self = 0; + region *r; + + /* Die Sichtbarkeit eines Zaubers und die Zaubermeldung sind bei + * Gebäuden und Schiffen je nach, ob man Besitzer ist, verschieden. + * Bei Einheiten sieht man Wirkungen auf eigene Einheiten immer. + * Spezialfälle (besonderes Talent, verursachender Magier usw. werde + * bei jedem curse gesondert behandelt. */ + if (typ == TYP_SHIP){ + ship * sh = (ship*)obj; + unit * owner = shipowner(sh); + a = sh->attribs; + r = sh->region; + if (owner != NULL) { + if (owner->faction == viewer){ + self = 2; + } else { /* steht eine person der Partei auf dem Schiff? */ + unit *u = NULL; + for (u = r->units; u; u = u->next) { + if (u->ship == sh) { + self = 1; + break; + } + } + } + } + } else if (typ == TYP_BUILDING) { + building * b = (building*)obj; + unit * owner = building_owner(b); + a = b->attribs; + r = b->region; + if (owner != NULL){ + if (owner->faction == viewer){ + self = 2; + } else { /* steht eine Person der Partei in der Burg? */ + unit *u = NULL; + for (u = r->units; u; u = u->next) { + if (u->building == b) { + self = 1; + break; + } + } + } + } + } else if (typ == TYP_UNIT) { + unit *u = (unit *)obj; + a = u->attribs; + r = u->region; + if (u->faction == viewer) { + self = 2; + } + } else if (typ == TYP_REGION) { + r = (region *)obj; + a = r->attribs; + } else { + /* fehler */ + } + + while (a) { + if (fval(a->type, ATF_CURSE)) { + curse * c = (curse *)a->data.v; + message * msg; + + if (c->type->cansee) { + self = c->type->cansee(viewer, obj, typ, c, self); + } + msg = msg_curse(c, obj, typ, self); + + if (msg) { + char buf[BUFFERSIZE]; + if (!header) { + header = 1; + fputs("EFFECTS\n", F); + } + nr_render(msg, viewer->locale, buf, sizeof(buf), viewer); + fprintf(F, "\"%s\"\n", buf); + msg_release(msg); + } + } else if (a->type==&at_effect && self) { + effect_data * data = (effect_data *)a->data.v; + if (data->value>0) { + const char * key = resourcename(data->type->itype->rtype, 0); + if (!header) { + header = 1; + fputs("EFFECTS\n", F); + } + fprintf(F, "\"%d %s\"\n", data->value, add_translation(key, locale_string(default_locale, key))); + } + } + a = a->next; + } +} + +static int +cr_unit(variant var, char * buffer, const void * userdata) +{ + unit * u = (unit *)var.v; + sprintf(buffer, "%d", u?u->no:-1); + return 0; +} + +static int +cr_ship(variant var, char * buffer, const void * userdata) +{ + ship * u = (ship *)var.v; + sprintf(buffer, "%d", u?u->no:-1); + return 0; +} + +static int +cr_building(variant var, char * buffer, const void * userdata) +{ + building * u = (building *)var.v; + sprintf(buffer, "%d", u?u->no:-1); + return 0; +} + +static int +cr_faction(variant var, char * buffer, const void * userdata) +{ + faction * f = (faction *)var.v; + sprintf(buffer, "%d", f?f->no:-1); + return 0; +} + +static int +cr_region(variant var, char * buffer, const void * userdata) +{ + const faction * report = (const faction*)userdata; + region * r = (region *)var.v; + if (r) { + plane * pl = rplane(r); + int nx = r->x, ny = r->y; + pnormalize(&nx, &ny, pl); + adjust_coordinates(report, &nx, &ny, pl, r); + sprintf(buffer, "%d %d %d", nx, ny, plane_id(pl)); + return 0; + } + return -1; +} + +static int +cr_resource(variant var, char * buffer, const void * userdata) +{ + const faction * report = (const faction*)userdata; + const resource_type * r = (const resource_type *)var.v; + if (r) { + const char * key = resourcename(r, 0); + sprintf(buffer, "\"%s\"", + add_translation(key, locale_string(report->locale, key))); + return 0; + } + return -1; +} + +static int +cr_race(variant var, char * buffer, const void * userdata) +{ + const faction * report = (const faction*)userdata; + const struct race * rc = (const race *)var.v; + const char * key = rc_name(rc, 0); + sprintf(buffer, "\"%s\"", + add_translation(key, locale_string(report->locale, key))); + return 0; +} + +static int +cr_alliance(variant var, char * buffer, const void * userdata) +{ + const alliance * al = (const alliance *)var.v; + if (al!=NULL) { + sprintf(buffer, "%d", al->id); + } + unused(userdata); + return 0; +} + +static int +cr_skill(variant var, char * buffer, const void * userdata) +{ + const faction * report = (const faction*)userdata; + skill_t sk = (skill_t)var.i; + if (sk!=NOSKILL) sprintf(buffer, "\"%s\"", + add_translation(mkname("skill", skillnames[sk]), skillname(sk, report->locale))); + else strcpy(buffer, "\"\""); + return 0; +} + +static int +cr_order(variant var, char * buffer, const void * userdata) +{ + order * ord = (order*)var.v; + if (ord!=NULL) { + char * wp = buffer; + char * cmd = getcommand(ord); + const char * rp = cmd; + + *wp++ = '\"'; + while (*rp) { + switch (*rp) { + case '\"': + case '\\': + *wp++ = '\\'; + default: + *wp++ = *rp++; + } + } + *wp++ = '\"'; + *wp++ = 0; + + free(cmd); + } + else strcpy(buffer, "\"\""); + return 0; +} + +static int +cr_resources(variant var, char * buffer, const void * userdata) +{ + faction * f = (faction*)userdata; + resource * rlist = (resource*)var.v; + char * wp = buffer; + if (rlist!=NULL) { + const char * name = resourcename(rlist->type, rlist->number!=1); + wp += sprintf(wp, "\"%d %s", rlist->number, add_translation(name, LOC(f->locale, name))); + for (;;) { + rlist = rlist->next; + if (rlist==NULL) break; + name = resourcename(rlist->type, rlist->number!=1); + wp += sprintf(wp, ", %d %s", rlist->number, add_translation(name, LOC(f->locale, name))); + } + strcat(wp, "\""); + } + return 0; +} + +static int +cr_regions(variant var, char * buffer, const void * userdata) +{ + faction * f = (faction*)userdata; + const arg_regions * rdata = (const arg_regions *)var.v; + + if (rdata!=NULL && rdata->nregions>0) { + region * r = rdata->regions[0]; + plane * pl = rplane(r); + int i, z = plane_id(pl); + char * wp = buffer; + int nx = r->x, ny = r->y; + + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl, r); + wp += sprintf(wp, "\"%d %d %d", nx, ny, z); + for (i=1;i!=rdata->nregions;++i) { + r = rdata->regions[i]; + pl = rplane(r); + z = plane_id(pl); + wp += sprintf(wp, ", %d %d %d", nx, ny, z); + } + strcat(wp, "\""); + } else { + strcpy(buffer, "\"\""); + } + return 0; +} + +static int +cr_spell(variant var, char * buffer, const void * userdata) +{ + const faction * report = (const faction*)userdata; + spell * sp = (spell*)var.v; + if (sp!=NULL) sprintf(buffer, "\"%s\"", spell_name(sp, report->locale)); + else strcpy(buffer, "\"\""); + return 0; +} + +static int +cr_curse(variant var, char * buffer, const void * userdata) +{ + const faction * report = (const faction*)userdata; + const curse_type * ctype = (const curse_type*)var.v; + if (ctype!=NULL) { + sprintf(buffer, "\"%s\"", curse_name(ctype, report->locale)); + } else strcpy(buffer, "\"\""); + return 0; +} + +/*static int msgno; */ + +#define MTMAXHASH 1021 + +static struct known_mtype { + const struct message_type * mtype; + struct known_mtype * nexthash; +} * mtypehash[MTMAXHASH]; + +static void +report_crtypes(FILE * F, const struct locale* lang) +{ + int i; + for (i=0;i!=MTMAXHASH;++i) { + struct known_mtype * kmt; + for (kmt=mtypehash[i];kmt;kmt=kmt->nexthash) { + const struct nrmessage_type * nrt = nrt_find(lang, kmt->mtype); + if (nrt) { + unsigned int hash = kmt->mtype->key; + fprintf(F, "MESSAGETYPE %d\n", hash); + fputc('\"', F); + fputs(escape_string(nrt_string(nrt), NULL, 0), F); + fputs("\";text\n", F); + fprintf(F, "\"%s\";section\n", nrt_section(nrt)); + } + } + while (mtypehash[i]) { + kmt = mtypehash[i]; + mtypehash[i] = mtypehash[i]->nexthash; + free(kmt); + } + } +} + +static unsigned int +messagehash(const struct message * msg) +{ + variant var; + var.v = (void *)msg; + return (unsigned int)var.i; +} + +static void +render_messages(FILE * F, faction * f, message_list *msgs) +{ + struct mlist* m = msgs->begin; + while (m) { + char crbuffer[BUFFERSIZE]; /* gross, wegen spionage-messages :-( */ + boolean printed = false; + const struct message_type * mtype = m->msg->type; + unsigned int hash = mtype->key; +#ifdef RENDER_CRMESSAGES + char nrbuffer[1024*32]; + nrbuffer[0] = '\0'; + if (nr_render(m->msg, f->locale, nrbuffer, sizeof(nrbuffer), f)>=0) { + fprintf(F, "MESSAGE %u\n", messagehash(m->msg)); + fprintf(F, "%d;type\n", hash); + fwritestr(F, nrbuffer); + fputs(";rendered\n", F); + printed = true; + } +#endif + crbuffer[0] = '\0'; + if (cr_render(m->msg, crbuffer, (const void*)f)==0) { + if (!printed) fprintf(F, "MESSAGE %u\n", messagehash(m->msg)); + if (crbuffer[0]) fputs(crbuffer, F); + } else { + log_error(("could not render cr-message %p: %s\n", m->msg, m->msg->type->name)); + } + if (printed) { + unsigned int ihash = hash % MTMAXHASH; + struct known_mtype * kmt = mtypehash[ihash]; + while (kmt && kmt->mtype != mtype) kmt = kmt->nexthash; + if (kmt==NULL) { + kmt = (struct known_mtype*)malloc(sizeof(struct known_mtype)); + kmt->nexthash = mtypehash[ihash]; + kmt->mtype = mtype; + mtypehash[ihash] = kmt; + } + } + m = m->next; + } +} + +static void +cr_output_messages(FILE * F, message_list *msgs, faction * f) +{ + if (msgs) render_messages(F, f, msgs); +} + +/* prints a building */ +static void +cr_output_building(FILE * F, building * b, const unit * owner, int fno, faction *f) +{ + const char * bname, * billusion; + + fprintf(F, "BURG %d\n", b->no); + + report_building(b, &bname, &billusion); + if (billusion) { + fprintf(F, "\"%s\";Typ\n", add_translation(billusion, LOC(f->locale, billusion))); + if (owner && owner->faction==f) { + fprintf(F, "\"%s\";wahrerTyp\n", add_translation(bname, LOC(f->locale, bname))); + } + } else { + fprintf(F, "\"%s\";Typ\n", add_translation(bname, LOC(f->locale, bname))); + } + 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 ? owner->no : -1); + if (fno >= 0) + fprintf(F, "%d;Partei\n", fno); + if (b->besieged) + fprintf(F, "%d;Belagerer\n", b->besieged); + cr_output_curses(F, f, b, TYP_BUILDING); +} +/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ + +/* prints a ship */ +static void +cr_output_ship(FILE * F, 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); + if (sh->display && sh->display[0]) + fprintf(F, "\"%s\";Beschr\n", sh->display); + fprintf(F, "\"%s\";Typ\n", add_translation(sh->type->name[0], locale_string(f->locale, sh->type->name[0]))); + fprintf(F, "%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); + } + if (u) + fprintf(F, "%d;Kapitaen\n", u ? u->no : -1); + 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)); + } + /* shore */ + w = NODIRECTION; + if (!fval(r->terrain, SEA_REGION)) w = sh->coast; + if (w != NODIRECTION) + fprintf(F, "%d;Kueste\n", w); + + cr_output_curses(F, f, sh, TYP_SHIP); +} + +static void +fwriteorder(FILE * F, const struct order * ord, const struct locale * lang, boolean escape) +{ + char ebuf[1024]; + char obuf[1024]; + const char * str = obuf; + fputc('"', F); + write_order(ord, obuf, sizeof(obuf)); + if (escape) { + str = escape_string(obuf, ebuf, sizeof(ebuf)); + } + if (str[0]) fputs(str, F); + fputc('"', F); +} + +static void cr_output_spells(FILE * F, spell_list * slist, const faction * f, int maxlevel) +{ + if (slist) { + fprintf(F, "SPRUECHE\n"); + for (;slist; slist = slist->next) { + spell * sp = slist->data; + if (sp->level <= maxlevel) { + const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, f->locale)); + fprintf(F, "\"%s\"\n", name); + } + } + } +} + +/* prints all that belongs to a unit */ +static void +cr_output_unit(FILE * F, const region * r, + const faction * f, /* observers faction */ + const unit * u, int mode) +{ + /* Race attributes are always plural and item attributes always + * singular */ + const char * str; + const item_type * lasttype; + int pr; + item *itm, *show; + building * b; + const char * pzTmp; + skill * sv; + const attrib *a_fshidden = NULL; + boolean itemcloak = false; + static const curse_type * itemcloak_ct = 0; + static boolean init = false; + item result[MAX_INVENTORY]; + + if (fval(u->race, RCF_INVISIBLE)) return; + + if (!init) { + init = true; + itemcloak_ct = ct_find("itemcloak"); + } + if (itemcloak_ct!=NULL) { + itemcloak = curse_active(get_curse(u->attribs, itemcloak_ct)); + } + + assert(u && u->number); + + fprintf(F, "EINHEIT %d\n", u->no); + fprintf(F, "\"%s\";Name\n", u->name); + str = u_description(u, f->locale); + if (str) { + fprintf(F, "\"%s\";Beschr\n", str); + } + { + /* print faction information */ + const faction * sf = visible_faction(f, u); + const char * prefix = raceprefix(u); + if (u->faction == f || omniscient(f)) { + const attrib * a_otherfaction = a_find(u->attribs, &at_otherfaction); + const faction * otherfaction = a_otherfaction?get_otherfaction(a_otherfaction):NULL; + /* my own faction, full info */ + const attrib *a = NULL; + unit * mage; + + if (fval(u, UFL_GROUP)) a = a_find(u->attribs, &at_group); + if (a!=NULL) { + const group * g = (const group*)a->data.v; + fprintf(F, "%d;gruppe\n", g->gid); + } + fprintf(F, "%d;Partei\n", u->faction->no); + if (sf!=u->faction) fprintf(F, "%d;Verkleidung\n", sf->no); + if (fval(u, UFL_ANON_FACTION)) + fprintf(F, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION))); + if (otherfaction) { + if (otherfaction!=u->faction) { + fprintf(F, "%d;Anderepartei\n", otherfaction->no); + } + } + mage = get_familiar_mage(u); + if (mage) { + fprintf(F, "%u;familiarmage\n", mage->no); + } + } else { + if (fval(u, UFL_ANON_FACTION)) { + /* faction info is hidden */ + fprintf(F, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION))); + } else { + const attrib * a_otherfaction = a_find(u->attribs, &at_otherfaction); + const faction * otherfaction = a_otherfaction?get_otherfaction(a_otherfaction):NULL; + /* other unit. show visible faction, not u->faction */ + fprintf(F, "%d;Partei\n", sf->no); + if (sf == f) { + fprintf(F, "1;Verraeter\n"); + } + if (a_otherfaction) { + if (otherfaction!=u->faction) { + if (alliedunit(u, f, HELP_FSTEALTH)) { + fprintf(F, "%d;Anderepartei\n", otherfaction->no); + } + } + } + } + } + if (prefix) { + prefix = mkname("prefix", prefix); + fprintf(F, "\"%s\";typprefix\n", add_translation(prefix, LOC(f->locale, prefix))); + } + } + if (u->faction != f && a_fshidden + && a_fshidden->data.ca[0] == 1 && effskill(u, SK_STEALTH) >= 6) { + fprintf(F, "-1;Anzahl\n"); + } else { + fprintf(F, "%d;Anzahl\n", u->number); + } + + pzTmp = get_racename(u->attribs); + if (pzTmp) { + fprintf(F, "\"%s\";Typ\n", pzTmp); + if (u->faction==f && fval(u->race, RCF_SHAPESHIFTANY)) { + const char * zRace = rc_name(u->race, 1); + fprintf(F, "\"%s\";wahrerTyp\n", + add_translation(zRace, locale_string(f->locale, zRace))); + } + } else { + const race * irace = u_irace(u); + const char * zRace = rc_name(irace, 1); + fprintf(F, "\"%s\";Typ\n", + add_translation(zRace, locale_string(f->locale, zRace))); + if (u->faction==f && irace!=u->race) { + assert(skill_enabled[SK_STEALTH] || !"we're resetting this on load, so.. ircase should never be used"); + zRace = rc_name(u->race, 1); + fprintf(F, "\"%s\";wahrerTyp\n", + add_translation(zRace, locale_string(f->locale, zRace))); + } + } + + if (u->building) { + assert(u->building->region); + fprintf(F, "%d;Burg\n", u->building->no); + } + if (u->ship) { + assert(u->ship->region); + fprintf(F, "%d;Schiff\n", u->ship->no); + } + if (is_guard(u, GUARD_ALL)!=0) { + fprintf(F, "%d;bewacht\n", 1); + } + if ((b=usiege(u))!=NULL) { + fprintf(F, "%d;belagert\n", b->no); + } + /* additional information for own units */ + if (u->faction == f || omniscient(f)) { + order * ord; + const char *xc; + const char * c; + int i; + + i = ualias(u); + if (i>0) + fprintf(F, "%d;temp\n", i); + else if (i<0) + fprintf(F, "%d;alias\n", -i); + i = get_money(u); + fprintf(F, "%d;Kampfstatus\n", u->status); + fprintf(F, "%d;weight\n", weight(u)); + if (fval(u, UFL_NOAID)) { + fputs("1;unaided\n", F); + } + if (fval(u, UFL_STEALTH)) { + i = u_geteffstealth(u); + if (i >= 0) { + fprintf(F, "%d;Tarnung\n", i); + } + } + xc = uprivate(u); + if (xc) { + fprintf(F, "\"%s\";privat\n", xc); + } + c = hp_status(u); + if (c && *c && (u->faction == f || omniscient(f))) { + fprintf(F, "\"%s\";hp\n", add_translation(c, locale_string(u->faction->locale, c))); + } + if (fval(u, UFL_HERO)) { + fputs("1;hero\n", F); + } + + if (fval(u, UFL_HUNGER) && (u->faction == f)) { + fputs("1;hunger\n", F); + } + if (is_mage(u)) { + fprintf(F, "%d;Aura\n", get_spellpoints(u)); + fprintf(F, "%d;Auramax\n", max_spellpoints(u->region,u)); + } + /* default commands */ + fprintf(F, "COMMANDS\n"); + for (ord = u->old_orders; ord; ord = ord->next) { + /* this new order will replace the old defaults */ + if (is_persistent(ord)) { + fwriteorder(F, ord, f->locale, true); + fputc('\n', F); + } + } + for (ord = u->orders; ord; ord = ord->next) { + if (u->old_orders && is_repeated(ord)) continue; /* unit has defaults */ + if (is_persistent(ord)) { + fwriteorder(F, ord, f->locale, true); + fputc('\n', F); + } + } + + /* talents */ + pr = 0; + for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { + if (sv->level>0) { + skill_t sk = sv->id; + int esk = eff_skill(u, sk, r); + if (!pr) { + pr = 1; + fprintf(F, "TALENTE\n"); + } + fprintf(F, "%d %d;%s\n", u->number*level_days(sv->level), esk, + add_translation(mkname("skill", skillnames[sk]), skillname(sk, f->locale))); + } + } + /* spells */ + if (is_mage(u)) { + sc_mage * mage = get_mage(u); + spell_list ** slistp = get_spelllist(mage, u->faction); + int i, maxlevel = effskill(u, SK_MAGIC); + + cr_output_spells(F, *slistp, f, maxlevel); + + for (i=0;i!=MAXCOMBATSPELLS;++i) { + const spell * sp = mage->combatspells[i].sp; + if (sp) { + const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, f->locale)); + fprintf(F, "KAMPFZAUBER %d\n", i); + fprintf(F, "\"%s\";name\n", name); + fprintf(F, "%d;level\n", mage->combatspells[i].level); + } + } + } + } + /* items */ + pr = 0; + if (f == u->faction || omniscient(u->faction)) { + show = u->items; + } else if (itemcloak==false && mode>=see_unit && !(a_fshidden + && a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) + { + int n = report_items(u->items, result, MAX_INVENTORY, u, f); + assert(n>=0); + if (n>0) show = result; + else show = NULL; + } else { + show = NULL; + } + lasttype = NULL; + for (itm=show; itm; itm=itm->next) { + const char * ic; + int in; + assert(itm->type!=lasttype || !"error: list contains two objects of the same item"); + report_item(u, itm, f, NULL, &ic, &in, true); + if (in==0) continue; + if (!pr) { + pr = 1; + fputs("GEGENSTAENDE\n", F); + } + fprintf(F, "%d;%s\n", in, add_translation(ic, locale_string(f->locale, ic))); + } + + cr_output_curses(F, f, u, TYP_UNIT); +} +/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ + +/* prints allies */ +static void +show_allies_cr(FILE * F, const faction * f, const ally * sf) +{ + for (; sf; sf = sf->next) if (sf->faction) { + int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); + if (mode!=0 && sf->status>0) { + fprintf(F, "ALLIANZ %d\n", sf->faction->no); + fprintf(F, "\"%s\";Parteiname\n", sf->faction->name); + fprintf(F, "%d;Status\n", sf->status & HELP_ALL); + } + } +} + +/* prints allies */ +static void +show_alliances_cr(FILE * F, const faction * f) +{ + alliance * al = f_get_alliance(f); + if (al) { + faction * lead = alliance_get_leader(al); + assert(lead); + fprintf(F, "ALLIANCE %d\n", al->id); + fprintf(F, "\"%s\";name\n", al->name); + fprintf(F, "%d;leader\n", lead->no); + } +} + +/* prints all visible spells in a region */ +static void +show_active_spells(const region * r) +{ + char fogwall[MAXDIRECTIONS]; +#ifdef TODO /* alte Regionszauberanzeigen umstellen */ + unit *u; + int env = 0; +#endif + memset(fogwall, 0, sizeof(char) * MAXDIRECTIONS); + +} +/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ + +/* this is a copy of laws.c->find_address output changed. */ +static void +cr_find_address(FILE * F, const faction * uf, const faction_list * addresses) +{ + const faction_list * flist = addresses; + while (flist!=NULL) { + const faction * f = flist->data; + if (uf!=f) { + fprintf(F, "PARTEI %d\n", f->no); + fprintf(F, "\"%s\";Parteiname\n", f->name); + if (f->email) fprintf(F, "\"%s\";email\n", f->email); + if (f->banner) fprintf(F, "\"%s\";banner\n", f->banner); + fprintf(F, "\"%s\";locale\n", locale_name(f->locale)); + if (f->alliance && f->alliance==uf->alliance) { + fprintf(F, "%d;alliance\n", f->alliance->id); + } + } + flist = flist->next; + } +} +/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ + +static void +cr_reportspell(FILE * F, spell *sp, const struct locale * lang) +{ + int k; + const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, lang)); + + fprintf(F, "ZAUBER %d\n", hashstring(sp->sname)); + fprintf(F, "\"%s\";name\n", name); + fprintf(F, "%d;level\n", sp->level); + fprintf(F, "%d;rank\n", sp->rank); + fprintf(F, "\"%s\";info\n", spell_info(sp, lang)); + if (sp->parameter) fprintf(F, "\"%s\";syntax\n", sp->parameter); + else fputs("\"\";syntax\n", F); + + if (sp->sptyp & PRECOMBATSPELL) fputs("\"precombat\";class\n", F); + else if (sp->sptyp & COMBATSPELL) fputs("\"combat\";class\n", F); + else if (sp->sptyp & POSTCOMBATSPELL) fputs("\"postcombat\";class\n", F); + else fputs("\"normal\";class\n", F); + + if (sp->sptyp & FARCASTING) fputs("1;far\n", F); + if (sp->sptyp & OCEANCASTABLE) fputs("1;ocean\n", F); + if (sp->sptyp & ONSHIPCAST) fputs("1;ship\n", F); + if (!(sp->sptyp & NOTFAMILIARCAST)) fputs("1;familiar\n", F); + fputs("KOMPONENTEN\n", F); + + for (k = 0; sp->components[k].type; ++k) { + const resource_type * rtype = sp->components[k].type; + int itemanz = sp->components[k].amount; + int costtyp = sp->components[k].cost; + if (itemanz > 0) { + const char * name = resourcename(rtype, 0); + fprintf(F, "%d %d;%s\n", itemanz, costtyp == SPC_LEVEL || costtyp == SPC_LINEAR, + add_translation(name, LOC(lang, name))); + } + } +} + +static char * +cr_output_resource(char * buf, const char * name, const struct locale * loc, int amount, int level) +{ + buf += sprintf(buf, "RESOURCE %u\n", hashstring(name)); + buf += sprintf(buf, "\"%s\";type\n", add_translation(name, LOC(loc, name))); + if (amount>=0) { + if (level>=0) buf += sprintf(buf, "%d;skill\n", level); + buf += sprintf(buf, "%d;number\n", amount); + } + return buf; +} + +static void +cr_borders(seen_region ** seen, const region * r, const faction * f, int seemode, FILE * F) +{ + direction_t d; + int g = 0; + for (d = 0; d != MAXDIRECTIONS; d++) + { /* Nachbarregionen, die gesehen werden, ermitteln */ + const region * r2 = rconnect(r, d); + const connection * b; + if (!r2) continue; + if (seemode==see_neighbour) { + seen_region * sr = find_seen(seen, r2); + if (sr==NULL || sr->mode<=see_neighbour) continue; + } + b = get_borders(r, r2); + while (b) { + boolean cs = b->type->fvisible(b, f, r); + + if (!cs) { + cs = b->type->rvisible(b, r); + if (!cs) { + unit * us = r->units; + while (us && !cs) { + if (us->faction==f) { + cs = b->type->uvisible(b, us); + if (cs) break; + } + us=us->next; + } + } + } + if (cs) { + const char * bname = mkname("border", b->type->name(b, r, f, GF_PURE)); + fprintf(F, "GRENZE %d\n", ++g); + fprintf(F, "\"%s\";typ\n", LOC(default_locale, bname)); + fprintf(F, "%d;richtung\n", d); + if (!b->type->transparent(b, f)) fputs("1;opaque\n", F); + /* hack: */ + if (b->type==&bt_road) { + int p = rroad(r, d)*100/r->terrain->max_road; + fprintf(F, "%d;prozent\n", p); + } + } + b = b->next; + } + } +} + +static void +cr_output_resources(FILE * F, report_context * ctx, seen_region * sr) +{ + char cbuf[BUFFERSIZE], *pos = cbuf; + region * r = sr->r; + faction * f = ctx->f; + resource_report result[MAX_RAWMATERIALS]; + int n, size = report_resources(sr, result, MAX_RAWMATERIALS, f); + +#ifdef RESOURCECOMPAT + int trees = rtrees(r, 2); + int saplings = rtrees(r, 1); + + if (trees > 0) fprintf(F, "%d;Baeume\n", trees); + if (saplings > 0) fprintf(F, "%d;Schoesslinge\n", saplings); + if (fval(r, RF_MALLORN) && (trees > 0 || saplings > 0)) + fprintf(F, "1;Mallorn\n"); + for (n=0;n=0 && result[n].number>=0) { + fprintf(F, "%d;%s\n", result[n].number, crtag(result[n].name)); + } + } +#endif + + for (n=0;n=0) { + pos = cr_output_resource(pos, result[n].name, f->locale, result[n].number, result[n].level); + } + } + if (pos!=cbuf) fputs(cbuf, F); +} + +static void +cr_region_header(FILE * F, int plid, int nx, int ny, unsigned int uid) +{ + if (plid==0) { + fprintf(F, "REGION %d %d\n", nx, ny); + } else { + fprintf(F, "REGION %d %d %d\n", nx, ny, plid); + } + if (uid) fprintf(F, "%d;id\n", uid); +} + +static void +cr_output_region(FILE * F, report_context * ctx, seen_region * sr) +{ + faction * f = ctx->f; + region * r = sr->r; + plane * pl = rplane(r); + int plid = plane_id(pl), nx, ny; + const char * tname; + int oc[4][2], o = 0; + int uid = r->uid; + +#ifdef OCEAN_NEIGHBORS_GET_NO_ID + if (sr->mode<=see_neighbour && !r->land) { + uid = 0; + } +#endif + + if (opt_cr_absolute_coords) { + nx = r->x; + ny = r->y; + } else { + nx = r->x, ny = r->y; + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl, r); + } + + if (pl) { + if (ny==pl->maxy) { + oc[o][0] = nx; + oc[o++][1] = pl->miny-1; + } + if (nx==pl->maxx) { + oc[o][0] = pl->minx-1; + oc[o++][1] = ny; + } + if (ny==pl->miny) { + oc[o][0] = nx; + oc[o++][1] = pl->maxy+1; + } + if (nx==pl->minx) { + oc[o][0] = pl->maxx+1; + oc[o++][1] = ny; + } + } + while (o--) { + cr_region_header(F, plid, oc[o][0], oc[o][1], uid); + fputs("\"wrap\";visibility\n", F); + } + + cr_region_header(F, plid, nx, ny, uid); + + if (r->land) { + const char * str = rname(r, f->locale); + if (str && str[0]) { + fprintf(F, "\"%s\";Name\n", str); + } + } + tname = terrain_name(r); + + fprintf(F, "\"%s\";Terrain\n", add_translation(tname, locale_string(f->locale, tname))); + if (sr->mode!=see_unit) fprintf(F, "\"%s\";visibility\n", visibility[sr->mode]); + if (sr->mode == see_neighbour) { + cr_borders(ctx->seen, r, f, sr->mode, F); + } else { + building * b; + ship * sh; + unit * u; + int stealthmod = stealth_modifier(sr->mode); + + if (r->display && r->display[0]) + fprintf(F, "\"%s\";Beschr\n", r->display); + if (fval(r->terrain, LAND_REGION)) { + fprintf(F, "%d;Bauern\n", rpeasants(r)); + if(fval(r, RF_ORCIFIED)) { + fprintf(F, "1;Verorkt\n"); + } + fprintf(F, "%d;Pferde\n", rhorses(r)); + + if (sr->mode>=see_unit) { + if (rule_region_owners()) { + faction * owner = region_get_owner(r); + if (owner) { + fprintf(F, "%d;owner\n", owner->no); + } + } + fprintf(F, "%d;Silber\n", rmoney(r)); + if (skill_enabled[SK_ENTERTAINMENT]) { + fprintf(F, "%d;Unterh\n", entertainmoney(r)); + } + if (is_cursed(r->attribs, C_RIOT, 0)){ + fputs("0;Rekruten\n", F); + } else { + fprintf(F, "%d;Rekruten\n", rpeasants(r) / RECRUITFRACTION); + } + if (production(r)) { + int p_wage = wage(r, NULL, NULL, turn+1); + fprintf(F, "%d;Lohn\n", p_wage); + if (is_mourning(r, turn+1)) { + fputs("1;mourning\n", F); + } + } + if (r->land->ownership) { + fprintf(F, "%d;morale\n", r->land->morale); + } + } + + /* this writes both some tags (RESOURCECOMPAT) and a block. + * must not write any blocks before it */ + cr_output_resources(F, ctx, sr); + + if (sr->mode>=see_unit) { + /* trade */ + if (markets_module() && r->land) { + const item_type * lux = r_luxury(r); + const item_type * herb = r->land->herbtype; + if (lux || herb) { + fputs("PREISE\n", F); + if (lux) { + const char * ch = resourcename(lux->rtype, 0); + fprintf(F, "%d;%s\n", 1, add_translation(ch, locale_string(f->locale, ch))); + } + if (herb) { + const char * ch = resourcename(herb->rtype, 0); + fprintf(F, "%d;%s\n", 1, add_translation(ch, locale_string(f->locale, ch))); + } + } + } else if (rpeasants(r)/TRADE_FRACTION > 0) { + struct demand * dmd = r->land->demands; + fputs("PREISE\n", F); + while (dmd) { + const char * ch = resourcename(dmd->type->itype->rtype, 0); + fprintf(F, "%d;%s\n", (dmd->value + ? dmd->value*dmd->type->price + : -dmd->type->price), + add_translation(ch, locale_string(f->locale, ch))); + dmd=dmd->next; + } + } + } + } + if (r->land) { + print_items(F, r->land->items, f->locale); + } + cr_output_curses(F, f, r, TYP_REGION); + cr_borders(ctx->seen, r, f, sr->mode, F); + if (sr->mode==see_unit && is_astral(r) && !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) + { + /* Sonderbehandlung Teleport-Ebene */ + region_list *rl = astralregions(r, inhabitable); + + if (rl) { + region_list *rl2 = rl; + while(rl2) { + region * r = rl2->data; + int nx = r->x, ny = r->y; + plane * plx = rplane(r); + + pnormalize(&nx, &ny, plx); + adjust_coordinates(f, &nx, &ny, plx, r); + fprintf(F, "SCHEMEN %d %d\n", nx, ny); + fprintf(F, "\"%s\";Name\n", rname(r, f->locale)); + rl2 = rl2->next; + } + free_regionlist(rl); + } + } + + /* describe both passed and inhabited regions */ + show_active_spells(r); + if (fval(r, RF_TRAVELUNIT)) { + boolean seeunits = false, seeships = false; + const attrib * ru; + /* show units pulled through region */ + for (ru = a_find(r->attribs, &at_travelunit); ru && ru->type==&at_travelunit; ru = ru->next) { + unit * u = (unit*)ru->data.v; + if (cansee_durchgezogen(f, r, u, 0) && r!=u->region) { + if (!u->ship || !fval(u, UFL_OWNER)) continue; + if (!seeships) fprintf(F, "DURCHSCHIFFUNG\n"); + seeships = true; + fprintf(F, "\"%s\"\n", shipname(u->ship)); + } + } + for (ru = a_find(r->attribs, &at_travelunit); ru && ru->type==&at_travelunit; ru = ru->next) { + unit * u = (unit*)ru->data.v; + if (cansee_durchgezogen(f, r, u, 0) && r!=u->region) { + if (u->ship) continue; + if (!seeunits) fprintf(F, "DURCHREISE\n"); + seeunits = true; + fprintf(F, "\"%s\"\n", unitname(u)); + } + } + } + cr_output_messages(F, r->msgs, f); + { + message_list * mlist = r_getmessages(r, f); + if (mlist) cr_output_messages(F, mlist, f); + } + /* buildings */ + for (b = rbuildings(r); b; b = b->next) { + int fno = -1; + u = building_owner(b); + if (u && !fval(u, UFL_ANON_FACTION)) { + const faction * sf = visible_faction(f,u); + fno = sf->no; + } + cr_output_building(F, b, u, fno, f); + } + + /* ships */ + for (sh = r->ships; sh; sh = sh->next) { + int fno = -1; + u = shipowner(sh); + if (u && !fval(u, UFL_ANON_FACTION)) { + const faction * sf = visible_faction(f,u); + fno = sf->no; + } + + cr_output_ship(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))) { + cr_output_unit(F, r, f, u, sr->mode); + } + } + } +} + +/* main function of the creport. creates the header and traverses all regions */ +static int +report_computer(const char * filename, report_context * ctx, const char * charset) +{ + static int era = -1; + int i; + faction * f = ctx->f; + const char * prefix; + region * r; + const char * mailto = locale_string(f->locale, "mailto"); + const attrib * a; + seen_region * sr = NULL; +#if SCORE_MODULE + int score = 0, avgscore = 0; +#endif + int enc = get_encoding_by_name(charset); + FILE * F = fopen(filename, "wt"); + + if (era<0) { + era = get_param_int(global.parameters, "world.era", 2); + } + if (F==NULL) { + perror(filename); + return -1; + } else if (enc==ENCODING_UTF8) { + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + fwrite(utf8_bom, 1, 3, F); + } + + /* must call this to get all the neighbour regions */ + /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ + /* initialisations, header and lists */ + + fprintf(F, "VERSION %d\n", C_REPORT_VERSION); + fprintf(F, "\"%s\";charset\n", charset); + fprintf(F, "\"%s\";locale\n", locale_name(f->locale)); + fprintf(F, "%d;noskillpoints\n", 1); + fprintf(F, "%ld;date\n", ctx->report_time); + fprintf(F, "\"%s\";Spiel\n", global.gamename); + fprintf(F, "\"%s\";Konfiguration\n", "Standard"); + fprintf(F, "\"%s\";Koordinaten\n", "Hex"); + fprintf(F, "%d;Basis\n", 36); + fprintf(F, "%d;Runde\n", turn); + fprintf(F, "%d;Zeitalter\n", era); + if (mailto!=NULL) { + fprintf(F, "\"%s\";mailto\n", mailto); + fprintf(F, "\"%s\";mailcmd\n", locale_string(f->locale, "mailcmd")); + } + + show_alliances_cr(F, f); + + fprintf(F, "PARTEI %d\n", f->no); + fprintf(F, "\"%s\";locale\n", locale_name(f->locale)); + if (f_get_alliance(f)) { + fprintf(F, "%d;alliance\n", f->alliance->id); + fprintf(F, "%d;joined\n", f->alliance_joindate); + } + fprintf(F, "%d;age\n", f->age); + fprintf(F, "%d;Optionen\n", f->options); +#if SCORE_MODULE + if (f->options & want(O_SCORE) && f->age>DISPLAYSCORE) { + score = f->score; + avgscore = average_score_of_age(f->age, f->age / 24 + 1); + } + fprintf(F, "%d;Punkte\n", score); + fprintf(F, "%d;Punktedurchschnitt\n", avgscore); +#endif + { + const char * zRace = rc_name(f->race, 1); + fprintf(F, "\"%s\";Typ\n", add_translation(zRace, LOC(f->locale, zRace))); + } + prefix = get_prefix(f->attribs); + if (prefix!=NULL) { + prefix = mkname("prefix", prefix); + fprintf(F, "\"%s\";typprefix\n", + add_translation(prefix, LOC(f->locale, prefix))); + } + fprintf(F, "%d;Rekrutierungskosten\n", f->race->recruitcost); + fprintf(F, "%d;Anzahl Personen\n", count_all(f)); + fprintf(F, "\"%s\";Magiegebiet\n", magic_school[f->magiegebiet]); + + if (f->race == new_race[RC_HUMAN]) { + fprintf(F, "%d;Anzahl Immigranten\n", count_migrants(f)); + fprintf(F, "%d;Max. Immigranten\n", count_maxmigrants(f)); + } + + i = countheroes(f); + if (i>0) fprintf(F, "%d;heroes\n", i); + i = maxheroes(f); + if (i>0) fprintf(F, "%d;max_heroes\n", i); + + if (f->age > 1 && f->lastorders != turn) { + fprintf(F, "%d;nmr\n", turn-f->lastorders); + } + + fprintf(F, "\"%s\";Parteiname\n", f->name); + fprintf(F, "\"%s\";email\n", f->email); + if (f->banner) fprintf(F, "\"%s\";banner\n", f->banner); + print_items(F, f->items, f->locale); + fputs("OPTIONEN\n", F); + for (i=0;i!=MAXOPTIONS;++i) { + int flag = want(i); + if (options[i]) { + fprintf(F, "%d;%s\n", (f->options&flag)?1:0, options[i]); + } else if (f->options&flag) { + f->options &= (~flag); + } + } + show_allies_cr(F, f, f->allies); + { + group * g; + for (g=f->groups;g;g=g->next) { + + fprintf(F, "GRUPPE %d\n", g->gid); + fprintf(F, "\"%s\";name\n", g->name); + prefix = get_prefix(g->attribs); + if (prefix!=NULL) { + prefix = mkname("prefix", prefix); + fprintf(F, "\"%s\";typprefix\n", + add_translation(prefix, LOC(f->locale, prefix))); + } + show_allies_cr(F, f, g->allies); + } + } + + cr_output_messages(F, f->msgs, f); + { + struct bmsg * bm; + for (bm=f->battles;bm;bm=bm->next) { + plane * pl = rplane(bm->r); + int plid = plane_id(pl); + region * r = bm->r; + int nx = r->x, ny = r->y; + + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl, r); + if (!plid) fprintf(F, "BATTLE %d %d\n", nx, ny); + else { + fprintf(F, "BATTLE %d %d %d\n", nx, ny, plid); + } + cr_output_messages(F, bm->msgs, f); + } + } + + cr_find_address(F, f, ctx->addresses); + a = a_find(f->attribs, &at_reportspell); + while (a && a->type==&at_reportspell) { + spell *sp = (spell *)a->data.v; + cr_reportspell(F, sp, f->locale); + a = a->next; + } + for (a=a_find(f->attribs, &at_showitem);a && a->type==&at_showitem;a=a->next) { + const potion_type * ptype = resource2potion(((const item_type*)a->data.v)->rtype); + const char * ch; + const char * description = NULL; + + if (ptype==NULL) continue; + ch = resourcename(ptype->itype->rtype, 0); + fprintf(F, "TRANK %d\n", hashstring(ch)); + fprintf(F, "\"%s\";Name\n", add_translation(ch, locale_string(f->locale, ch))); + fprintf(F, "%d;Stufe\n", ptype->level); + + if (description==NULL) { + const char * pname = resourcename(ptype->itype->rtype, 0); + const char * potiontext = mkname("potion", pname); + description = LOC(f->locale, potiontext); + } + + fprintf(F, "\"%s\";Beschr\n", description); + if (ptype->itype->construction) { + requirement * m = ptype->itype->construction->materials; + + fprintf(F, "ZUTATEN\n"); + + while (m->number) { + ch = resourcename(m->rtype, 0); + fprintf(F, "\"%s\"\n", add_translation(ch, locale_string(f->locale, ch))); + m++; + } + } + } + + /* traverse all regions */ + for (r=ctx->first;sr==NULL && r!=ctx->last;r=r->next) { + sr = find_seen(ctx->seen, r); + } + for (;sr!=NULL;sr=sr->next) { + cr_output_region(F, ctx, sr); + } + report_crtypes(F, f->locale); + write_translations(F); + reset_translations(); + fclose(F); + return 0; +} + +int +crwritemap(const char * filename) +{ + FILE * F = fopen(filename, "w"); + region * r; + + fprintf(F, "VERSION %d\n", C_REPORT_VERSION); + fputs("\"UTF-8\";charset\n", F); + + for (r=regions;r;r=r->next) { + plane * pl = rplane(r); + int plid = plane_id(pl); + if (plid) { + fprintf(F, "REGION %d %d %d\n", r->x, r->y, plid); + } else { + fprintf(F, "REGION %d %d\n", r->x, r->y); + } + fprintf(F, "\"%s\";Name\n\"%s\";Terrain\n", rname(r, default_locale), LOC(default_locale, terrain_name(r))); + } + fclose(F); + return 0; +} + +void +register_cr(void) +{ + tsf_register("report", &cr_ignore); + tsf_register("string", &cr_string); + tsf_register("order", &cr_order); + tsf_register("spell", &cr_spell); + tsf_register("curse", &cr_curse); + tsf_register("int", &cr_int); + tsf_register("unit", &cr_unit); + tsf_register("region", &cr_region); + tsf_register("faction", &cr_faction); + tsf_register("ship", &cr_ship); + tsf_register("building", &cr_building); + tsf_register("skill", &cr_skill); + tsf_register("resource", &cr_resource); + tsf_register("race", &cr_race); + tsf_register("direction", &cr_int); + tsf_register("alliance", &cr_alliance); + tsf_register("resources", &cr_resources); + tsf_register("items", &cr_resources); + tsf_register("regions", &cr_regions); + + if (!nocr) register_reporttype("cr", &report_computer, 1<next; + free(t); + } + junkyard = 0; +} + + diff --git a/src/gamecode/creport.h b/src/gamecode/creport.h index 473f1f0bc..cfe84d8aa 100644 --- a/src/gamecode/creport.h +++ b/src/gamecode/creport.h @@ -1,29 +1,29 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ -#ifndef H_GC_CREPORT -#define H_GC_CREPORT -#ifdef __cplusplus -extern "C" { -#endif - -#include - -extern void creport_cleanup(void); -extern void register_cr(void); - -extern int crwritemap(const char * filename); - -#ifdef __cplusplus -} -#endif -#endif - +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#ifndef H_GC_CREPORT +#define H_GC_CREPORT +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern void creport_cleanup(void); +extern void register_cr(void); + +extern int crwritemap(const char * filename); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index 53000af93..5a06f2a0b 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -1,3463 +1,3463 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#pragma region includes - -#include -#include -#include "economy.h" - -/* gamecode includes */ -#include "archetype.h" -#include "give.h" -#include "laws.h" -#include "randenc.h" -#include "spy.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -/* libs includes */ -#include -#include -#include -#include -#include - -#pragma endregion - -typedef struct request { - struct request * next; - struct unit * unit; - struct order * ord; - int qty; - int no; - union { - boolean goblin; /* stealing */ - const struct luxury_type * ltype; /* trading */ - } type; -} request; - -static int working; - -static request entertainers[1024]; -static request *nextentertainer; -static int entertaining; - -static int norders; -static request *oa; - -#define RECRUIT_MERGE 1 -#define RECRUIT_CLASSIC 2 -#define RECRUIT_ARCHETYPES 4 -static int rules_recruit = -1; - -static void recruit_init(void) -{ - if (rules_recruit<0) { - rules_recruit = 0; - if (get_param_int(global.parameters, "recruit.allow_merge", 1)) { - rules_recruit |= RECRUIT_MERGE; - } - if (get_param_int(global.parameters, "recruit.classic", 1)) { - rules_recruit |= RECRUIT_CLASSIC; - } - if (get_param_int(global.parameters, "recruit.archetype", 0)) { - rules_recruit |= RECRUIT_ARCHETYPES; - } - } -} - -int -income(const unit * u) -{ - switch(old_race(u->race)) { - case RC_FIREDRAGON: - return 150 * u->number; - case RC_DRAGON: - return 1000 * u->number; - case RC_WYRM: - return 5000 * u->number; - } - return 20 * u->number; -} - -static void -scramble(void *data, int n, size_t width) -{ - int j; - char temp[64]; - assert(width<=sizeof(temp)); - for (j=0;j!=n;++j) { - int k = rng_int() % n; - if (k==j) continue; - memcpy(temp, (char*)data+j*width, width); - memcpy((char*)data+j*width, (char*)data+k*width, width); - memcpy((char*)data+k*width, temp, width); - } -} - -static void -expandorders(region * r, request * requests) -{ - unit *u; - request *o; - - /* Alle Units ohne request haben ein -1, alle units mit orders haben ein - * 0 hier stehen */ - - for (u = r->units; u; u = u->next) - u->n = -1; - - norders = 0; - - for (o = requests; o; o = o->next) { - if (o->qty > 0) { - norders += o->qty; - } - } - - if (norders > 0) { - int i = 0; - oa = (request *) calloc(norders, sizeof(request)); - for (o = requests; o; o = o->next) { - if (o->qty > 0) { - int j; - for (j = o->qty; j; j--) { - oa[i] = *o; - oa[i].unit->n = 0; - i++; - } - } - } - scramble(oa, norders, sizeof(request)); - } else { - oa = NULL; - } - while (requests) { - request * o = requests->next; - free_order(requests->ord); - free(requests); - requests = o; - } -} -/* ------------------------------------------------------------- */ - -static void -change_level(unit * u, skill_t sk, int bylevel) -{ - skill * sv = get_skill(u, sk); - assert(bylevel>0); - if (sv==0) sv = add_skill(u, sk); - sk_set(sv, sv->level+bylevel); -} - -typedef struct recruitment { - struct recruitment * next; - faction * f; - request * requests; - int total, assigned; -} recruitment; - -static recruitment * -select_recruitment(request ** rop, int (*quantify)(const struct race*, int), int * total) -{ - recruitment * recruits = NULL; - - while (*rop) { - recruitment * rec = recruits; - request * ro = *rop; - unit * u = ro->unit; - const race * rc = u->race; - int qty = quantify(rc, ro->qty); - - if (qty<0) { - rop = &ro->next; /* skip this one */ - } else { - *rop = ro->next; /* remove this one */ - while (rec && rec->f!=u->faction) rec = rec->next; - if (rec==NULL) { - rec = malloc(sizeof(recruitment)); - rec->f = u->faction; - rec->total = 0; - rec->assigned = 0; - rec->requests = NULL; - rec->next = recruits; - recruits = rec; - } - *total += qty; - rec->total += qty; - ro->next = rec->requests; - rec->requests = ro; - } - } - return recruits; -} - -static void -add_recruits(unit * u, int number, int wanted) -{ - region * r = u->region; - assert(number<=wanted); - if (number > 0) { - unit * unew; - char equipment[64]; - - if (u->number==0) { - set_number(u, number); - u->hp = number * unit_max_hp(u); - unew = u; - } else { - unew = create_unit(r, u->faction, number, u->race, 0, NULL, u); - } - - snprintf(equipment, sizeof(equipment), "new_%s_unit", u->race->_name[0]); - equip_unit(unew, get_equipment(equipment)); - - - if (unew->race->ec_flags & ECF_REC_HORSES) { - change_level(unew, SK_RIDING, 1); - } - - if (unew!=u) { - transfermen(unew, u, unew->number); - remove_unit(&r->units, unew); - } - } - if (number < wanted) { - ADDMSG(&u->faction->msgs, msg_message("recruit", - "unit region amount want", u, r, number, wanted)); - } -} - -static int -any_recruiters(const struct race * rc, int qty) -{ - return (int)(qty * 2 * rc->recruit_multi); -} - -static int -peasant_recruiters(const struct race * rc, int qty) -{ - if (rc->ec_flags & ECF_REC_ETHEREAL) return -1; - if (rc->ec_flags & ECF_REC_HORSES) return -1; - return (int)(qty * 2 * rc->recruit_multi); -} - -static int -horse_recruiters(const struct race * rc, int qty) -{ - if (rc->ec_flags & ECF_REC_ETHEREAL) return -1; - if (rc->ec_flags & ECF_REC_HORSES) return (int)(qty * 2 * rc->recruit_multi); - return -1; -} - -static int -do_recruiting(recruitment * recruits, int available) -{ - recruitment * rec; - int recruited = 0; - - while (available>0) { - int n = 0; - int rest, mintotal = INT_MAX; - - for (rec=recruits;rec!=NULL;rec=rec->next) { - int want = rec->total - rec->assigned; - if (want>0) { - if (mintotal>want) mintotal = want; - ++n; - } - } - if (n==0) break; - if (mintotal*n>available) { - mintotal = available/n; - } - rest = available - mintotal*n; - - for (rec=recruits;rec!=NULL;rec=rec->next) { - int want = rec->total - rec->assigned; - - if (want>0) { - int get = mintotal; - if (want>mintotal && restassigned += get; - } - } - } - - for (rec=recruits;rec!=NULL;rec=rec->next) { - request * req; - int get = rec->assigned; - - for (req=rec->requests;req;req=req->next) { - unit * u = req->unit; - const race * rc = u->race; /* race is set in recruit() */ - int number, dec; - float multi = 2.0F * rc->recruit_multi; - - number = MIN(req->qty, (int)(get / multi)); - if (rc->recruitcost) { - int afford = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, number*rc->recruitcost) / rc->recruitcost; - number = MIN(number, afford); - use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, rc->recruitcost*number); - } - if (u->number+number>UNIT_MAXSIZE) { - ADDMSG(&u->faction->msgs, msg_feedback(u, req->ord, "error_unit_size", "maxsize", UNIT_MAXSIZE)); - number = UNIT_MAXSIZE-u->number; - assert(number>=0); - } - add_recruits(u, number, req->qty); - dec = (int)(number * multi); - if ((rc->ec_flags & ECF_REC_ETHEREAL)==0) { - recruited += dec; - } - - get -= dec; - } - } - return recruited; -} - -static void -feedback_give_not_allowed(unit * u, order * ord) -{ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_give_forbidden", "")); -} - -static boolean check_give(unit * u, unit * u2, const item_type * itype, int mask) -{ - if (u2) { - if (u->faction!=u2->faction) { - int rule = rule_give(); - if (itype) { - assert(mask==0); - if (itype->rtype->ltype) mask |= GIVE_LUXURIES; - else if (fval(itype, ITF_HERB)) mask |= GIVE_HERBS; - else mask |= GIVE_GOODS; - } - return (rule&mask)!=0; - } - } else { - int rule = rule_give(); - return (rule & GIVE_PEASANTS)!=0; - } - return true; -} - -void -free_recruitments(recruitment * recruits) -{ - while (recruits) { - recruitment * rec = recruits; - recruits = rec->next; - while (rec->requests) { - request * req = rec->requests; - rec->requests = req->next; - free(req); - } - free(rec); - } -} - -/* Rekrutierung */ -static void -expandrecruit(region * r, request * recruitorders) -{ - recruitment * recruits = NULL; - - int orc_total = 0; - - /* centaurs: */ - recruits = select_recruitment(&recruitorders, horse_recruiters, &orc_total); - if (recruits) { - int recruited, horses = rhorses(r) * 2; - if (orc_total0) { - rsetpeasants(r, peasants - recruited/2); - } - free_recruitments(recruits); - } - - assert(recruitorders==NULL); -} - -static int -recruit_cost(const faction * f, const race * rc) -{ - if (is_monsters(f) || f->race==rc) { - return rc->recruitcost; - } else if (valid_race(f, rc)) { - return rc->recruitcost; -/* return get_param_int(f->race->parameters, "other_cost", -1); */ - } - return -1; -} - -static void -recruit(unit * u, struct order * ord, request ** recruitorders) -{ - int n; - region * r = u->region; - plane * pl; - request *o; - int recruitcost = -1; - const faction * f = u->faction; - const struct race * rc = u->race; - const char * str; - - init_tokens(ord); - skip_token(); - n = getuint(); - - if (u->number==0) { - str = getstrtoken(); - if (str && str[0]) { - /* Monster dürfen REKRUTIERE 15 dracoid machen - * also: secondary race */ - rc = findrace(str, f->locale); - if (rc!=NULL) { - recruitcost = recruit_cost(f, rc); - } - } - } - if (recruitcost<0) { - rc = u->race; - recruitcost = recruit_cost(f, rc); - } - u->race = rc; - assert(rc && recruitcost>=0); - -#if GUARD_DISABLES_RECRUIT - /* this is a very special case because the recruiting unit may be empty - * at this point and we have to look at the creating unit instead. This - * is done in cansee, which is called indirectly by is_guarded(). */ - if (is_guarded(r, u, GUARD_RECRUIT)) { - cmistake(u, ord, 70, MSG_EVENT); - return; - } -#endif - - if (rc == new_race[RC_INSECT]) { - gamedate date; - get_gamedate(turn, &date); - if (date.season == 0 && r->terrain != newterrain(T_DESERT)) { -#ifdef INSECT_POTION - boolean usepotion = false; - unit *u2; - - for (u2 = r->units; u2; u2 = u2->next) - if (fval(u2, UFL_WARMTH)) { - usepotion = true; - break; - } - if (!usepotion) -#endif - { - cmistake(u, ord, 98, MSG_EVENT); - return; - } - } - /* in Gletschern, Eisbergen gar nicht rekrutieren */ - if (r_insectstalled(r)) { - cmistake(u, ord, 97, MSG_EVENT); - return; - } - } - if (is_cursed(r->attribs, C_RIOT, 0)) { - /* Die Region befindet sich in Aufruhr */ - cmistake(u, ord, 237, MSG_EVENT); - return; - } - - if (!(rc->ec_flags & ECF_REC_HORSES) && fval(r, RF_ORCIFIED)) { - if (rc != new_race[RC_ORC]) - { - cmistake(u, ord, 238, MSG_EVENT); - return; - } - } - - if (recruitcost) { - pl = getplane(r); - if (pl && fval(pl, PFL_NORECRUITS)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "error_pflnorecruit", "")); - return; - } - - if (get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, recruitcost) < recruitcost) { - cmistake(u, ord, 142, MSG_EVENT); - return; - } - } - if (!playerrace(rc) || idle(u->faction)) { - cmistake(u, ord, 139, MSG_EVENT); - return; - } - - if (has_skill(u, SK_MAGIC)) { - /* error158;de;{unit} in {region}: '{command}' - Magier arbeiten - * grundsätzlich nur alleine! */ - cmistake(u, ord, 158, MSG_EVENT); - return; - } - if (has_skill(u, SK_ALCHEMY) - && count_skill(u->faction, SK_ALCHEMY) + n > - skill_limit(u->faction, SK_ALCHEMY)) - { - cmistake(u, ord, 156, MSG_EVENT); - return; - } - if (recruitcost>0) { - int pooled = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, recruitcost * n); - n = MIN(n, pooled / recruitcost); - } - - u->wants = n; - - if (!n) { - cmistake(u, ord, 142, MSG_EVENT); - return; - } - - o = (request *) calloc(1, sizeof(request)); - o->qty = n; - o->unit = u; - o->ord = copy_order(ord); - addlist(recruitorders, o); -} - -static void -friendly_takeover(region * r, faction * f) -{ - int morale = region_get_morale(r); - region_set_owner(r, f, turn); - if (morale>0) { - morale = MAX(0, morale-MORALE_TRANSFER); - region_set_morale(r, morale, turn); - } -} - -static void -give_control(unit * u, unit * u2) -{ - if (u->building && u->faction!=u2->faction && rule_region_owners()) { - region * r = u->region; - faction * f = region_get_owner(r); - if (f==u->faction) { - building * b = largestbuilding(r, &cmp_current_owner, false); - if (b==u->building) { - friendly_takeover(r, u2->faction); - } - } - } - freset(u, UFL_OWNER); - fset(u2, UFL_OWNER); -} - -int -give_control_cmd(unit * u, order * ord) -{ - region * r = u->region; - unit *u2; - const char * s; - param_t p; - - init_tokens(ord); - skip_token(); - u2 = getunit(r, u->faction); - s = getstrtoken(); - p = findparam(s, u->faction->locale); - - /* first, do all the ones that do not require HELP_GIVE or CONTACT */ - if (p == P_CONTROL) { - message * msg; - - if (!u2) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } - else if (!u->building && !u->ship) { - cmistake(u, ord, 140, MSG_EVENT); - } - else if (u->building && u2->building != u->building) { - cmistake(u, ord, 33, MSG_EVENT); - } - else if (u->ship && u2->ship != u->ship) { - cmistake(u, ord, 32, MSG_EVENT); - } - else if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 49, MSG_EVENT); - } - else { - give_control(u, u2); - - msg = msg_message("givecommand", "unit recipient", u, u2); - add_message(&u->faction->msgs, msg); - if (u->faction != u2->faction) { - add_message(&u2->faction->msgs, msg); - } - msg_release(msg); - } - } - return 0; -} - -static void -give_cmd(unit * u, order * ord) -{ - region * r = u->region; - unit *u2; - const char *s; - int i, n; - const item_type * itype; - param_t p; - plane * pl; - - init_tokens(ord); - skip_token(); - u2 = getunit(r, u->faction); - s = getstrtoken(); - p = findparam(s, u->faction->locale); - - /* first, do all the ones that do not require HELP_GIVE or CONTACT */ - if (p == P_CONTROL) { - /* handled in give_control_cmd */ - return; - } - - if (!u2 && !getunitpeasants) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return; - } - - if (!check_give(u, u2, NULL, GIVE_ALLITEMS)) { - feedback_give_not_allowed(u, ord); - return; - } - - /* Damit Tarner nicht durch die Fehlermeldung enttarnt werden können */ - if (u2 && !alliedunit(u2, u->faction, HELP_GIVE) && !cansee(u->faction,r,u2,0) && !ucontact(u2, u) && !fval(u2, UFL_TAKEALL)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return; - } - if (u == u2) { - cmistake(u, ord, 8, MSG_COMMERCE); - return; - } - - /* UFL_TAKEALL ist ein grober Hack. Generalisierung tut not, ist aber nicht - * wirklich einfach. */ - pl = rplane(r); - if (pl && fval(pl, PFL_NOGIVE) && (!u2 || !fval(u2, UFL_TAKEALL))) { - cmistake(u, ord, 268, MSG_COMMERCE); - return; - } - - if (u2 && u2->race == new_race[RC_SPELL]) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return; - } - - else if (u2 && !alliedunit(u2, u->faction, HELP_GIVE) && !ucontact(u2, u)) { - cmistake(u, ord, 40, MSG_COMMERCE); - return; - } - - else if (p == P_HERBS) { - boolean given = false; - if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_nogive", "race", u->race)); - return; - } - if (!check_give(u, u2, NULL, GIVE_HERBS)) { - feedback_give_not_allowed(u, ord); - return; - } - if (u2 && !(u2->race->ec_flags & GETITEM)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_notake", "race", u2->race)); - return; - } - if (!u2) { - if (!getunitpeasants) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return; - } - } - if (u->items) { - item **itmp=&u->items; - while (*itmp) { - item * itm = *itmp; - const item_type * itype = itm->type; - if (fval(itype, ITF_HERB) && itm->number>0) { - /* give_item ändert im fall,das man alles übergibt, die - * item-liste der unit, darum continue vor pointerumsetzten */ - if (give_item(itm->number, itm->type, u, u2, ord)==0) { - given = true; - if (*itmp!=itm) continue; - continue; - } - } - itmp = &itm->next; - } - } - if (!given) cmistake(u, ord, 38, MSG_COMMERCE); - return; - } - - else if (p == P_ZAUBER) { - cmistake(u, ord, 7, MSG_COMMERCE); - /* geht nimmer */ - return; - } - - else if (p == P_UNIT) { /* Einheiten uebergeben */ - if (!(u->race->ec_flags & GIVEUNIT)) { - cmistake(u, ord, 167, MSG_COMMERCE); - return; - } - - give_unit(u, u2, ord); - return; - } - - else if (p==P_ANY) { - const char * s = getstrtoken(); - - if (!check_give(u, u2, NULL, GIVE_ALLITEMS)) { - feedback_give_not_allowed(u, ord); - return; - } - if (*s == 0) { /* Alle Gegenstände übergeben */ - - /* do these checks once, not for each item we have: */ - if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_nogive", "race", u->race)); - return; - } - if (u2 && !(u2->race->ec_flags & GETITEM)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_notake", "race", u2->race)); - return; - } - - /* für alle items einmal prüfen, ob wir mehr als von diesem Typ - * reserviert ist besitzen und diesen Teil dann übergeben */ - if (u->items) { - item **itmp=&u->items; - while (*itmp) { - item * itm = *itmp; - const item_type * itype = itm->type; - if (itm->number > 0 && itm->number - get_reservation(u, itype->rtype) > 0) { - n = itm->number - get_reservation(u, itype->rtype); - if (give_item(n, itype, u, u2, ord)==0) { - if (*itmp!=itm) continue; - } - } - itmp = &itm->next; - } - } - return; - } - else { - param_t p2 = findparam(s, u->faction->locale); - - if (p2 == P_PERSON) { - if (!(u->race->ec_flags & GIVEPERSON)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_noregroup", "race", u->race)); - return; - } - n = u->number; - give_men(n, u, u2, ord); - return; - } - - if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_nogive", "race", u->race)); - return; - } - if (u2 && !(u2->race->ec_flags & GETITEM)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_notake", "race", u2->race)); - return; - } - - itype = finditemtype(s, u->faction->locale); - if (itype!=NULL) { - item * i = *i_find(&u->items, itype); - if (i!=NULL) { - if (check_give(u, u2, itype, 0)) { - n = i->number - get_reservation(u, itype->rtype); - give_item(n, itype, u, u2, ord); - } else { - feedback_give_not_allowed(u, ord); - } - return; - } - } - } - } else if (p==P_EACH) { - if (u2==NULL) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "peasants_give_invalid", "")); - return; - } - s = getstrtoken(); /* skip one ahead to get the amount. */ - } - - n = atoip((const char *)s); /* n: Anzahl */ - if (p==P_EACH) { - n *= u2->number; - } - s = getstrtoken(); - - if (s == NULL) { - cmistake(u, ord, 113, MSG_COMMERCE); - return; - } - - i = findparam(s, u->faction->locale); - if (i == P_PERSON) { - if (!(u->race->ec_flags & GIVEPERSON)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_noregroup", "race", u->race)); - return; - } - give_men(n, u, u2, ord); - return; - } - - if (u2!=NULL) { - if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_nogive", "race", u->race)); - return; - } - if (!(u2->race->ec_flags & GETITEM)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_notake", "race", u2->race)); - return; - } - } - - itype = finditemtype(s, u->faction->locale); - if (itype!=NULL) { - if (check_give(u, u2, itype, 0)) { - give_item(n, itype, u, u2, ord); - } else { - feedback_give_not_allowed(u, ord); - } - return; - } - cmistake(u, ord, 123, MSG_COMMERCE); -} - -static int -forget_cmd(unit * u, order * ord) -{ - skill_t sk; - const char *s; - - if (is_cursed(u->attribs, C_SLAVE, 0)) { - /* charmed units shouldn't be losing their skills */ - return 0; - } - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - if ((sk = findskill(s, u->faction->locale)) != NOSKILL) { - ADDMSG(&u->faction->msgs, - msg_message("forget", "unit skill", u, sk)); - set_level(u, sk, 0); - } - return 0; -} - -void -add_spende(faction * f1, faction * f2, int amount, region * r) -{ - donation *sp; - - sp = r->donations; - - while (sp) { - if (sp->f1 == f1 && sp->f2 == f2) { - sp->amount += amount; - return; - } - sp = sp->next; - } - - sp = calloc(1, sizeof(donation)); - sp->f1 = f1; - sp->f2 = f2; - sp->amount = amount; - sp->next = r->donations; - r->donations = sp; -} - -static boolean -maintain(building * b, boolean first) -/* first==false -> take money from wherever you can */ -{ - int c; - region * r = b->region; - boolean paid = true, work = first; - unit * u; - if (fval(b, BLD_MAINTAINED) || b->type==NULL || b->type->maintenance==NULL || is_cursed(b->attribs, C_NOCOST, 0)) { - fset(b, BLD_MAINTAINED); - fset(b, BLD_WORKING); - return true; - } - if (fval(b, BLD_DONTPAY)) { - return false; - } - u = building_owner(b); - if (u==NULL) return false; - for (c=0;b->type->maintenance[c].number;++c) { - const maintenance * m = b->type->maintenance+c; - int need = m->number; - - if (fval(m, MTF_VARIABLE)) need = need * b->size; - if (u) { - /* first ist im ersten versuch true, im zweiten aber false! Das - * bedeutet, das in der Runde in die Region geschafften Resourcen - * nicht genutzt werden können, weil die reserviert sind! */ - if (!first) need -= get_pooled(u, m->rtype, GET_ALL, need); - else need -= get_pooled(u, m->rtype, GET_DEFAULT, need); - if (!first && need > 0) { - unit * ua; - for (ua=r->units;ua;ua=ua->next) freset(ua->faction, FFL_SELECT); - fset(u->faction, FFL_SELECT); /* hat schon */ - for (ua=r->units;ua;ua=ua->next) { - if (!fval(ua->faction, FFL_SELECT) && (ua->faction == u->faction || alliedunit(ua, u->faction, HELP_MONEY))) { - need -= get_pooled(ua, m->rtype, GET_ALL, need); - fset(ua->faction, FFL_SELECT); - if (need<=0) break; - } - } - } - if (need > 0) { - if (!fval(m, MTF_VITAL)) work = false; - else { - paid = false; - break; - } - } - } - } - if (paid && c>0) { - /* TODO: wieviel von was wurde bezahlt */ - if (first) { - ADDMSG(&u->faction->msgs, msg_message("maintenance", "unit building", u, b)); - } else { - ADDMSG(&u->faction->msgs, msg_message("maintenance_late", "building", b)); - } - fset(b, BLD_MAINTAINED); - if (work) { - fset(b, BLD_WORKING); - } - for (c=0;b->type->maintenance[c].number;++c) { - const maintenance * m = b->type->maintenance+c; - int cost = m->number; - - if (!fval(m, MTF_VITAL) && !work) continue; - if (fval(m, MTF_VARIABLE)) cost = cost * b->size; - - if (!first) cost -= use_pooled(u, m->rtype, GET_ALL, cost); - else cost -= use_pooled(u, m->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, cost); - if (!first && cost > 0) { - unit * ua; - for (ua=r->units;ua;ua=ua->next) freset(ua->faction, FFL_SELECT); - fset(u->faction, FFL_SELECT); /* hat schon */ - for (ua=r->units;ua;ua=ua->next) { - if (!fval(ua->faction, FFL_SELECT) && alliedunit(ua, u->faction, HELP_MONEY)) { - int give = use_pooled(ua, m->rtype, GET_ALL, cost); - if (!give) continue; - cost -= give; - fset(ua->faction, FFL_SELECT); - if (m->rtype==r_silver) add_spende(ua->faction, u->faction, give, r); - if (cost<=0) break; - } - } - } - assert(cost==0); - } - } else { - ADDMSG(&u->faction->msgs, - msg_message("maintenancefail", "unit building", u, b)); - return false; - } - return true; -} - -#ifdef COLLAPSE_CHANCE -static void -gebaeude_stuerzt_ein(region * r, building * b) -{ - unit *u; - int n, i; - int opfer = 0; - int road = 0; - struct message * msg; - - for (u = r->units; u; u = u->next) { - if (u->building == b) { - int loss = 0; - - fset(u->faction, FFL_MARK); - freset(u, UFL_OWNER); - leave(r,u); - n = u->number; -#ifdef COLLAPSE_SURVIVAL - for (i = 0; i < n; i++) { - if (rng_double() >= COLLAPSE_SURVIVAL) { - ++loss; - } - } -#endif - scale_number(u, u->number - loss); - opfer += loss; - } - } - - msg = msg_message("buildingcrash", "region building opfer road", r, b, opfer, road); - add_message(&r->msgs, msg); - for (u=r->units; u; u=u->next) { - faction * f = u->faction; - if (fval(f, FFL_MARK)) { - freset(u->faction, FFL_MARK); - add_message(&f->msgs, msg); - } - } - msg_release(msg); - remove_building(&r->buildings, b); -} -#endif - -void -maintain_buildings(region * r, boolean crash) -{ - building **bp = &r->buildings; - while (*bp) { - building * b = *bp; - boolean maintained = maintain(b, !crash); - - /* the second time, send a message */ - if (crash) { -#ifdef COLLAPSE_CHANCE - if (!maintained && (rng_double() < COLLAPSE_CHANCE)) { - gebaeude_stuerzt_ein(r, b); - continue; - } -#endif - if (!fval(b, BLD_WORKING)) { - unit * u = building_owner(b); - const char * msgtype = maintained?"maintenance_nowork":"maintenance_none"; - struct message * msg = msg_message(msgtype, "building", b); - - if (u) { - add_message(&u->faction->msgs, msg); - r_addmessage(r, u->faction, msg); - } else { - add_message(&r->msgs, msg); - } - msg_release(msg); - } - } - bp=&b->next; - } -} - -static int -recruit_archetype(unit * u, order * ord) -{ - boolean merge = (u->number>0); - int want; - const char * s; - - if (rules_recruit<0) recruit_init(); - - init_tokens(ord); - skip_token(); - want = getuint(); - s = getstrtoken(); - if (want>0 && s && s[0]) { - int n = want; - const archetype * arch = find_archetype(s, u->faction->locale); - attrib * a = NULL; - - if ((rules_recruit&RECRUIT_MERGE)==0 && merge) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_must_be_new", "")); - /* TODO: error message */ - return 0; - } - - if (arch==NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unknown_archetype", "name", s)); - /* TODO: error message */ - return 0; - } - if (arch->rules) { - /* Simple allow/deny style restrictions for archetypes (let only humans - * recruit gamedesigners, etc). These need to be more powerful to be - * useful, and the current way they are implemented is not, but the - * general idea strikes me as good. Also, feedback should be configurable - * for each failed rule. - */ - int k; - for (k=0;arch->rules[k].property;++k) { - boolean match = false; - if (arch->rules[k].value[0]=='*') match = true; - else if (strcmp(arch->rules[k].property, "race")==0) { - const race * rc = rc_find(arch->rules[k].value); - assert(rc); - if (rc==u->race) match = true; - } else if (strcmp(arch->rules[k].property, "building")==0) { - const building_type * btype = bt_find(arch->rules[k].value); - assert(btype); - if (u->building && u->building->type==btype) match = true; - } - if (match) { - if (arch->rules[k].allow) break; - else { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "recruit_rule_fail", - "property value", arch->rules[k].property, arch->rules[k].value)); - /* TODO: error message */ - return 0; - } - } - } - } - if (arch->btype) { - if (u->building==NULL || u->building->type!=arch->btype) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_must_be_in_building", "type", arch->btype)); - /* TODO: error message */ - return 0; - } - if (arch->size) { - int maxsize = u->building->size; - attrib * a = a_find(u->building->attribs, &at_recruit); - if (a!=NULL) { - maxsize -= a->data.i; - } - n = MIN(maxsize/arch->size, n); - if (n<=0) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "recruit_capacity_exhausted", "building", u->building)); - /* TODO: error message */ - return 0; - } - } - } - - n = build(u, arch->ctype, 0, n); - if (n>0) { - unit * u2; - if (merge) { - u2 = create_unit(u->region, u->faction, 0, u->race, 0, 0, u); - } else { - u2 = u; - } - if (arch->exec) { - n = arch->exec(u2, arch, n); - } - else { - set_number(u2, n); - equip_unit(u2, arch->equip); - u2->hp = n * unit_max_hp(u2); - if (arch->size) { - if (a==NULL) a = a_add(&u->building->attribs, a_new(&at_recruit)); - a->data.i += n*arch->size; - } - } - ADDMSG(&u->faction->msgs, msg_message("recruit_archetype", - "unit amount archetype", u, n, arch->name[n==1])); - if (u!=u2 && u->race==u2->race) { - transfermen(u2, u, u2->number); - } - return n; - } else switch(n) { - case ENOMATERIALS: - ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, arch->ctype, want)); - break; - case ELOWSKILL: - case ENEEDSKILL: - /* no skill, or not enough skill points to build */ - cmistake(u, ord, 50, MSG_PRODUCE); - break; - case EBUILDINGREQ: - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "building_needed", "building", arch->ctype->btype->_name)); - break; - default: - assert(!"unhandled return value from build() in recruit_archetype"); - } - return 0; - } - return -1; -} - -int recruit_archetypes(void) -{ - if (rules_recruit<0) recruit_init(); - return (rules_recruit&RECRUIT_ARCHETYPES)!=0; -} - -void -economics(region *r) -{ - unit *u; - request *recruitorders = NULL; - - /* Geben vor Selbstmord (doquit)! Hier alle unmittelbaren Befehle. - * Rekrutieren vor allen Einnahmequellen. Bewachen JA vor Steuern - * eintreiben. */ - - for (u = r->units; u; u = u->next) { - order * ord; - boolean destroyed = false; - if (u->number>0) { - for (ord = u->orders; ord; ord = ord->next) { - switch (get_keyword(ord)) { - case K_DESTROY: - if (!destroyed) { - if (destroy_cmd(u, ord)!=0) ord = NULL; - destroyed = true; - } - break; - - case K_GIVE: - case K_LIEFERE: - give_cmd(u, ord); - break; - - case K_FORGET: - forget_cmd(u, ord); - break; - - } - if (u->orders==NULL) break; - } - } - } - /* RECRUIT orders */ - - if (rules_recruit<0) recruit_init(); - for (u = r->units; u; u = u->next) { - order * ord; - - if ((rules_recruit&RECRUIT_MERGE) || u->number==0) { - for (ord = u->orders; ord; ord = ord->next) { - if (get_keyword(ord) == K_RECRUIT) { - if (rules_recruit&RECRUIT_ARCHETYPES) { - if (recruit_archetype(u, ord)>=0) { - continue; - } - } - if (rules_recruit&RECRUIT_CLASSIC) { - recruit(u, ord, &recruitorders); - } - break; - } - } - } - } - - if (recruitorders) expandrecruit(r, recruitorders); - remove_empty_units_in_region(r); -} -/* ------------------------------------------------------------- */ - - -static void -manufacture(unit * u, const item_type * itype, int want) -{ - int n; - int skill; - int minskill = itype->construction->minskill; - skill_t sk = itype->construction->skill; - - skill = effskill(u, sk); - skill = skillmod(itype->rtype->attribs, u, u->region, sk, skill, SMF_PRODUCTION); - - if (skill < 0) { - /* an error occured */ - int err = -skill; - cmistake(u, u->thisorder, err, MSG_PRODUCE); - return; - } - - if (want==0) { - want = maxbuild(u, itype->construction); - } - n = build(u, itype->construction, 0, want); - switch (n) { - case ENEEDSKILL: - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "skill_needed", "skill", sk)); - return; - case EBUILDINGREQ: - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "building_needed", "building", itype->construction->btype->_name)); - return; - case ELOWSKILL: - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "manufacture_skills", "skill minskill product", - sk, minskill, itype->rtype, 1)); - return; - case ENOMATERIALS: - ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, itype->construction, want)); - return; - } - if (n>0) { - i_change(&u->items, itype, n); - if (want==INT_MAX) want = n; - ADDMSG(&u->faction->msgs, msg_message("manufacture", - "unit region amount wanted resource", u, u->region, n, want, itype->rtype)); - } else { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_cannotmake", "")); - } -} - -typedef struct allocation { - struct allocation * next; - int want, get; - double save; - unsigned int flags; - unit * unit; -} allocation; -#define new_allocation() calloc(sizeof(allocation), 1) -#define free_allocation(a) free(a) - -typedef struct allocation_list { - struct allocation_list * next; - allocation * data; - const resource_type * type; -} allocation_list; - -static allocation_list * allocations; - -static boolean -can_guard(const unit * guard, const unit * u) -{ - if (fval(guard, UFL_ISNEW)) return false; - if (guard->number<=0 || !cansee(guard->faction, guard->region, u, 0)) return false; - if (besieged(guard) || !(fval(guard->race, RCF_UNARMEDGUARD) || armedmen(guard, true))) return false; - - return !alliedunit(guard, u->faction, HELP_GUARD); -} - -enum { - AFL_DONE = 1<<0, - AFL_LOWSKILL = 1<<1 -}; - -static void -allocate_resource(unit * u, const resource_type * rtype, int want) -{ - const item_type * itype = resource2item(rtype); - region * r = u->region; - int busy = u->number; - int dm = 0; - allocation_list * alist; - allocation * al; - attrib * a = a_find(rtype->attribs, &at_resourcelimit); - resource_limit * rdata = (resource_limit*)a->data.v; - int amount, skill; - - /* momentan kann man keine ressourcen abbauen, wenn man dafür - * Materialverbrauch hat: */ - assert(itype!=NULL && (itype->construction==NULL || itype->construction->materials==NULL)); - assert(rdata!=NULL); - - if (rdata->limit!=NULL) { - int avail = rdata->limit(r, rtype); - if (avail<=0) { - cmistake(u, u->thisorder, 121, MSG_PRODUCE); - return; - } - } - - if (besieged(u)) { - cmistake(u, u->thisorder, 60, MSG_PRODUCE); - return; - } - - if (rdata->modifiers) { - resource_mod * mod = rdata->modifiers; - for (;mod->flags!=0;++mod) { - if (mod->flags & RMF_REQUIREDBUILDING) { - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - if (mod->btype && mod->btype!=btype) { - cmistake(u, u->thisorder, 104, MSG_PRODUCE); - return; - } - } - } - } - - if (rdata->guard!=0) { - unit * u2; - for (u2 = r->units; u2; u2 = u2->next) { - if (is_guard(u2, rdata->guard)!=0 && can_guard(u2, u)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "region_guarded", "guard", u2)); - return; - } - } - } - - /* Bergwächter können Abbau von Eisen/Laen durch Bewachen verhindern. - * Als magische Wesen 'sehen' Bergwächter alles und werden durch - * Belagerung nicht aufgehalten. (Ansonsten wie oben bei Elfen anpassen). - */ - if (itype == olditemtype[I_IRON] || itype == olditemtype[I_LAEN]) { - unit * u2; - for (u2 = r->units; u2; u2 = u2->next ) { - if (is_guard(u, GUARD_MINING) - && !fval(u2, UFL_ISNEW) - && u2->number - && !alliedunit(u2, u->faction, HELP_GUARD)) - { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "region_guarded", "guard", u2)); - return; - } - } - } - - assert(itype->construction->skill!=0 || "limited resource needs a required skill for making it"); - skill = eff_skill(u, itype->construction->skill, u->region); - if (skill == 0) { - skill_t sk = itype->construction->skill; - add_message(&u->faction->msgs, - msg_feedback(u, u->thisorder, "skill_needed", "skill", sk)); - return; - } - if (skill < itype->construction->minskill) { - skill_t sk = itype->construction->skill; - add_message(&u->faction->msgs, - msg_feedback(u, u->thisorder, "manufacture_skills", "skill minskill product", - sk, itype->construction->minskill, itype->rtype)); - return; - } else { - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - - if (rdata->modifiers) { - resource_mod * mod = rdata->modifiers; - for (;mod->flags!=0;++mod) { - if (mod->flags & RMF_SKILL) { - if (mod->btype==NULL || mod->btype==btype) { - if (mod->race==NULL || mod->race==u->race) { - skill += mod->value.i; - } - } - } - } - } - } - amount = skill * u->number; - /* nun ist amount die Gesamtproduktion der Einheit (in punkten) */ - - /* mit Flinkfingerring verzehnfacht sich die Produktion */ - amount += skill * MIN(u->number, get_item(u, I_RING_OF_NIMBLEFINGER)) * (roqf_factor()-1); - - /* Schaffenstrunk: */ - if ((dm = get_effect(u, oldpotiontype[P_DOMORE])) != 0) { - dm = MIN(dm, u->number); - change_effect(u, oldpotiontype[P_DOMORE], -dm); - amount += dm * skill; /* dm Personen produzieren doppelt */ - } - - amount /= itype->construction->minskill; - - /* Limitierung durch Parameter m. */ - if (want > 0 && want < amount) amount = want; - - busy = (amount + skill - 1) / skill; /* wieviel leute tun etwas? */ - - alist = allocations; - while (alist && alist->type!=rtype) alist = alist->next; - if (!alist) { - alist = calloc(sizeof(struct allocation_list), 1); - alist->next = allocations; - alist->type = rtype; - allocations = alist; - } - al = new_allocation(); - al->want = amount; - al->save = 1.0; - al->next = alist->data; - al->unit = u; - alist->data = al; - - if (rdata->modifiers) { - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - - resource_mod * mod = rdata->modifiers; - for (;mod->flags!=0;++mod) { - if (mod->flags & RMF_SAVEMATERIAL) { - if (mod->btype==NULL || mod->btype==btype) { - if (mod->race==NULL || mod->race==u->race) { - al->save *= mod->value.f; - } - } - } - } - } -} - -static int -required(int want, double save) -{ - int norders = (int)(want * save); - if (norders < want*save) ++norders; - return norders; -} - -static void -leveled_allocation(const resource_type * rtype, region * r, allocation * alist) -{ - const item_type * itype = resource2item(rtype); - rawmaterial * rm = rm_get(r, rtype); - int need; - boolean first = true; - - if (rm!=NULL) { - do { - int avail = rm->amount; - int norders = 0; - allocation * al; - - if(avail <= 0) { - for (al=alist;al;al=al->next) { - al->get = 0; - } - break; - } - - assert(avail>0); - - for (al=alist;al;al=al->next) if (!fval(al, AFL_DONE)) { - int req = required(al->want-al->get, al->save); - assert(al->get<=al->want && al->get >= 0); - if (eff_skill(al->unit, itype->construction->skill, r) - >= rm->level+itype->construction->minskill-1) { - if (req) { - norders += req; - } else { - fset(al, AFL_DONE); - } - } else { - fset(al, AFL_DONE); - if (first) fset(al, AFL_LOWSKILL); - } - } - need = norders; - - avail = MIN(avail, norders); - if (need>0) { - int use = 0; - for (al=alist;al;al=al->next) if (!fval(al, AFL_DONE)) { - if (avail > 0) { - int want = required(al->want-al->get, al->save); - int x = avail*want/norders; - /* Wenn Rest, dann würfeln, ob ich was bekomme: */ - if (rng_int() % norders < (avail*want) % norders) - ++x; - avail -= x; - use += x; - norders -= want; - need -= x; - al->get = MIN(al->want, al->get+(int)(x/al->save)); - } - } - if (use) { - assert(use<=rm->amount); - rm->type->use(rm, r, use); - } - assert(avail==0 || norders==0); - } - first = false; - } while (need>0); - } -} - -static void -attrib_allocation(const resource_type * rtype, region * r, allocation * alist) -{ - allocation * al; - int norders = 0; - attrib * a = a_find(rtype->attribs, &at_resourcelimit); - resource_limit * rdata = (resource_limit*)a->data.v; - int avail = rdata->value; - - for (al=alist;al;al=al->next) { - norders += required(al->want, al->save); - } - - if (rdata->limit) { - avail = rdata->limit(r, rtype); - if (avail < 0) avail = 0; - } - - avail = MIN(avail, norders); - for (al=alist;al;al=al->next) { - if (avail > 0) { - int want = required(al->want, al->save); - int x = avail*want/norders; - /* Wenn Rest, dann würfeln, ob ich was bekomme: */ - if (rng_int() % norders < (avail*want) % norders) - ++x; - avail -= x; - norders -= want; - al->get = MIN(al->want, (int)(x/al->save)); - if (rdata->produce) { - int use = required(al->get, al->save); - if (use) rdata->produce(r, rtype, use); - } - } - } - assert(avail==0 || norders==0); -} - -typedef void (*allocate_function)(const resource_type *, struct region *, struct allocation *); - -static allocate_function -get_allocator(const struct resource_type * rtype) -{ - attrib * a = a_find(rtype->attribs, &at_resourcelimit); - - if (a!=NULL) { - resource_limit * rdata = (resource_limit*)a->data.v; - if (rdata->value>0 || rdata->limit!=NULL) { - return attrib_allocation; - } - return leveled_allocation; - } - return NULL; -} - -void -split_allocations(region * r) -{ - allocation_list ** p_alist=&allocations; - freset(r, RF_SELECT); - while (*p_alist) { - allocation_list * alist = *p_alist; - const resource_type * rtype = alist->type; - allocate_function alloc = get_allocator(rtype); - const item_type * itype = resource2item(rtype); - allocation ** p_al = &alist->data; - - freset(r, RF_SELECT); - alloc(rtype, r, alist->data); - - while (*p_al) { - allocation * al = *p_al; - if (al->get) { - assert(itype || !"not implemented for non-items"); - i_change(&al->unit->items, itype, al->get); - produceexp(al->unit, itype->construction->skill, al->unit->number); - fset(r, RF_SELECT); - } - if (al->want==INT_MAX) al->want = al->get; - if (fval(al, AFL_LOWSKILL)) { - ADDMSG(&al->unit->faction->msgs, - msg_message("produce_lowskill", "unit region resource", - al->unit, al->unit->region, rtype)); - } else { - ADDMSG(&al->unit->faction->msgs, msg_message("produce", - "unit region amount wanted resource", - al->unit, al->unit->region, al->get, al->want, rtype)); - } - *p_al=al->next; - free_allocation(al); - } - *p_alist=alist->next; - free(alist); - } - allocations = NULL; -} - -static void -create_potion(unit * u, const potion_type * ptype, int want) -{ - int built; - - if (want==0) { - want = maxbuild(u, ptype->itype->construction); - } - built = build(u, ptype->itype->construction, 0, want); - switch (built) { - case ELOWSKILL: - case ENEEDSKILL: - /* no skill, or not enough skill points to build */ - cmistake(u, u->thisorder, 50, MSG_PRODUCE); - break; - case EBUILDINGREQ: - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "building_needed", "building", ptype->itype->construction->btype->_name)); - break; - case ECOMPLETE: - assert(0); - break; - case ENOMATERIALS: - /* something missing from the list of materials */ - ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, ptype->itype->construction, want)); - return; - break; - default: - i_change(&u->items, ptype->itype, built); - if (want==INT_MAX) want = built; - ADDMSG(&u->faction->msgs, msg_message("manufacture", - "unit region amount wanted resource", u, u->region, built, want, ptype->itype->rtype)); - break; - } -} - -static void -create_item(unit * u, const item_type * itype, int want) -{ - if (itype->construction && fval(itype->rtype, RTF_LIMITED)) { -#if GUARD_DISABLES_PRODUCTION == 1 - if (is_guarded(u->region, u, GUARD_PRODUCE)) { - cmistake(u, u->thisorder, 70, MSG_EVENT); - return; - } -#endif - allocate_resource(u, itype->rtype, want); - } else { - const potion_type * ptype = resource2potion(itype->rtype); - if (ptype!=NULL) create_potion(u, ptype, want); - else if (itype->construction && itype->construction->materials) manufacture(u, itype, want); - else { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_cannotmake", "")); - } - } -} - -int -make_cmd(unit * u, struct order * ord) -{ - region * r = u->region; - const building_type * btype; - const ship_type * stype; - param_t p; - int m; - const item_type * itype; - const char *s; - const struct locale * lang = u->faction->locale; - char ibuf[16]; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - m = atoi((const char *)s); - sprintf(ibuf, "%d", m); - if (!strcmp(ibuf, (const char *)s)) { - /* first came a want-paramter */ - s = getstrtoken(); - } else { - m = INT_MAX; - } - - p = findparam(s, u->faction->locale); - - /* MACHE TEMP kann hier schon gar nicht auftauchen, weil diese nicht in - * thisorder abgespeichert werden - und auf den ist getstrtoken() beim - * aufruf von make geeicht */ - - if (p == P_ROAD) { - plane * pl = rplane(r); - if (pl && fval(pl, PFL_NOBUILD)) { - cmistake(u, ord, 275, MSG_PRODUCE); - } else { - direction_t d = finddirection(getstrtoken(), u->faction->locale); - if (d!=NODIRECTION) { - build_road(r, u, m, d); - } else { - /* Die Richtung wurde nicht erkannt */ - cmistake(u, ord, 71, MSG_PRODUCE); - } - } - return 0; - } else if (p == P_SHIP) { - plane * pl = rplane(r); - if (pl && fval(pl, PFL_NOBUILD)) { - cmistake(u, ord, 276, MSG_PRODUCE); - } else { - continue_ship(r, u, m); - } - return 0; - } else if (p == P_HERBS) { - herbsearch(r, u, m); - return 0; - } - - /* since the string can match several objects, like in 'academy' and - * 'academy of arts', we need to figure out what the player meant. - * This is not 100% safe. - */ - stype = findshiptype(s, lang); - btype = findbuildingtype(s, lang); - itype = finditemtype(s, lang); - - if (itype!=NULL && (btype!=NULL || stype!=NULL)) { - if (itype->construction==NULL) { - /* if the item cannot be made, we probably didn't mean to make it */ - itype = NULL; - } else if (stype!=NULL) { - const char * sname = LOC(lang, stype->name[0]); - const char * iname = LOC(lang, resourcename(itype->rtype, 0)); - if (strlen(iname)_name); - const char * iname = LOC(lang, resourcename(itype->rtype, 0)); - if (strlen(iname)_name); - const char * sname = LOC(lang, stype->name[0]); - if (strlen(sname)faction->msgs, msg_feedback(u, ord, "error_cannotmake", "")); - } - - return 0; -} -/* ------------------------------------------------------------- */ - -static void -free_luxuries(struct attrib * a) -{ - item * itm = (item*)a->data.v; - a->data.v = NULL; - i_freeall(&itm); -} - -const attrib_type at_luxuries = { - "luxuries", NULL, free_luxuries, NULL, NULL, NULL -}; - -static void -expandbuying(region * r, request * buyorders) -{ - int max_products; - unit *u; - static struct trade { - const luxury_type * type; - int number; - int multi; - } *trades, *trade; - static int ntrades=0; - int i, j; - const luxury_type * ltype; - - if (ntrades==0) { - for (ltype=luxurytypes;ltype;ltype=ltype->next) - ++ntrades; - trades = gc_add(calloc(sizeof(struct trade), ntrades)); - for (i=0, ltype=luxurytypes;i!=ntrades;++i, ltype=ltype->next) - trades[i].type = ltype; - } - for (i=0;i!=ntrades;++i) { - trades[i].number = 0; - trades[i].multi = 1; - } - - if (!buyorders) return; - - /* Initialisation. multiplier ist der Multiplikator auf den - * Verkaufspreis. Für max_products Produkte kauft man das Produkt zum - * einfachen Verkaufspreis, danach erhöht sich der Multiplikator um 1. - * counter ist ein Zähler, der die gekauften Produkte zählt. money - * wird für die debug message gebraucht. */ - - max_products = rpeasants(r) / TRADE_FRACTION; - - /* Kauf - auch so programmiert, daß er leicht erweiterbar auf mehrere - * Güter pro Monat ist. j sind die Befehle, i der Index des - * gehandelten Produktes. */ - if (max_products>0) { - expandorders(r, buyorders); - if (!norders) return; - - for (j = 0; j != norders; j++) { - int price, multi; - ltype = oa[j].type.ltype; - trade = trades; - while (trade->type!=ltype) ++trade; - multi = trade->multi; - price = ltype->price * multi; - - if (get_pooled(oa[j].unit, oldresourcetype[R_SILVER], GET_DEFAULT, price) >= price) { - unit * u = oa[j].unit; - item * items; - - /* litems zählt die Güter, die verkauft wurden, u->n das Geld, das - * verdient wurde. Dies muß gemacht werden, weil der Preis ständig sinkt, - * man sich also das verdiente Geld und die verkauften Produkte separat - * merken muß. */ - attrib * a = a_find(u->attribs, &at_luxuries); - if (a==NULL) a = a_add(&u->attribs, a_new(&at_luxuries)); - - items = a->data.v; - i_change(&items, ltype->itype, 1); - a->data.v = items; - i_change(&oa[j].unit->items, ltype->itype, 1); - use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, price); - if (u->n < 0) - u->n = 0; - u->n += price; - - rsetmoney(r, rmoney(r) + price); - - /* Falls mehr als max_products Bauern ein Produkt verkauft haben, steigt - * der Preis Multiplikator für das Produkt um den Faktor 1. Der Zähler - * wird wieder auf 0 gesetzt. */ - if (++trade->number == max_products) { - trade->number = 0; - ++trade->multi; - } - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - } - } - free(oa); - - /* Ausgabe an Einheiten */ - - for (u = r->units; u; u = u->next) { - attrib * a = a_find(u->attribs, &at_luxuries); - item * itm; - if (a==NULL) continue; - ADDMSG(&u->faction->msgs, msg_message("buy", "unit money", u, u->n)); - for (itm=(item*)a->data.v; itm; itm=itm->next) { - if (itm->number) { - ADDMSG(&u->faction->msgs, msg_message("buyamount", - "unit amount resource", u, itm->number, itm->type->rtype)); - } - } - a_remove(&u->attribs, a); - } - } -} - -attrib_type at_trades = { - "trades", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - NO_WRITE, - NO_READ -}; - -static void -buy(unit * u, request ** buyorders, struct order * ord) -{ - region * r = u->region; - int n, k; - request *o; - attrib * a; - const item_type * itype = NULL; - const luxury_type * ltype = NULL; - if (u->ship && is_guarded(r, u, GUARD_CREWS)) { - cmistake(u, ord, 69, MSG_INCOME); - return; - } - if (u->ship && is_guarded(r, u, GUARD_CREWS)) { - cmistake(u, ord, 69, MSG_INCOME); - return; - } - /* Im Augenblick kann man nur 1 Produkt kaufen. expandbuying ist aber - * schon dafür ausgerüstet, mehrere Produkte zu kaufen. */ - - init_tokens(ord); - skip_token(); - n = getuint(); - if (!n) { - cmistake(u, ord, 26, MSG_COMMERCE); - return; - } - if (besieged(u)) { - /* Belagerte Einheiten können nichts kaufen. */ - cmistake(u, ord, 60, MSG_COMMERCE); - return; - } - - if (u->race == new_race[RC_INSECT]) { - /* entweder man ist insekt, oder... */ - if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT) && !rbuildings(r)) { - cmistake(u, ord, 119, MSG_COMMERCE); - return; - } - } else { - /* ...oder in der Region muß es eine Burg geben. */ - building * b; - static const struct building_type * bt_castle; - if (!bt_castle) bt_castle = bt_find("castle"); - for (b=r->buildings;b;b=b->next) { - if (b->type==bt_castle && b->size>=2) break; - } - if (b==NULL) { - cmistake(u, ord, 119, MSG_COMMERCE); - return; - } - } - - /* Ein Händler kann nur 10 Güter pro Talentpunkt handeln. */ - k = u->number * 10 * eff_skill(u, SK_TRADE, r); - - /* hat der Händler bereits gehandelt, muss die Menge der bereits - * verkauften/gekauften Güter abgezogen werden */ - a = a_find(u->attribs, &at_trades); - if (!a) { - a = a_add(&u->attribs, a_new(&at_trades)); - } else { - k -= a->data.i; - } - - n = MIN(n, k); - - if (!n) { - cmistake(u, ord, 102, MSG_COMMERCE); - return; - } - - assert(n>=0); - /* die Menge der verkauften Güter merken */ - a->data.i += n; - - itype = finditemtype(getstrtoken(), u->faction->locale); - if (itype!=NULL) { - ltype = resource2luxury(itype->rtype); - if (ltype==NULL) { - cmistake(u, ord, 124, MSG_COMMERCE); - return; - } - } - if (r_demand(r, ltype)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "luxury_notsold", "")); - return; - } - o = (request *) calloc(1, sizeof(request)); - o->type.ltype = ltype; /* sollte immer gleich sein */ - - o->unit = u; - o->qty = n; - addlist(buyorders, o); -} -/* ------------------------------------------------------------- */ - -/* Steuersätze in % bei Burggröße */ -static int tax_per_size[7] = -{0, 6, 12, 18, 24, 30, 36}; - -static void -expandselling(region * r, request * sellorders, int limit) -{ - int money, price, j, max_products; - /* int m, n = 0; */ - int maxsize = 0, maxeffsize = 0; - int taxcollected = 0; - int hafencollected = 0; - unit *maxowner = (unit *) NULL; - building *maxb = (building *) NULL; - building *b; - unit *u; - unit *hafenowner; - static int *counter; - static int ncounter = 0; - - if (ncounter==0) { - const luxury_type * ltype; - for (ltype=luxurytypes;ltype;ltype=ltype->next) ++ncounter; - counter=(int*)gc_add(calloc(sizeof(int), ncounter)); - } else { - memset(counter, 0, sizeof(int)*ncounter); - } - - if (!sellorders) { /* NEIN, denn Insekten können in || !r->buildings) */ - return; /* Sümpfen und Wüsten auch so handeln */ - } - /* Stelle Eigentümer der größten Burg fest. Bekommt Steuern aus jedem - * Verkauf. Wenn zwei Burgen gleicher Größe bekommt gar keiner etwas. */ - - for (b = rbuildings(r); b; b = b->next) { - if (b->size > maxsize && building_owner(b) != NULL - && b->type == bt_find("castle")) { - maxb = b; - maxsize = b->size; - maxowner = building_owner(b); - } else if (b->size == maxsize && b->type == bt_find("castle")) { - maxb = (building *) NULL; - maxowner = (unit *) NULL; - } - } - - hafenowner = owner_buildingtyp(r, bt_find("harbour")); - - if (maxb != (building *) NULL && maxowner != (unit *) NULL) { - maxeffsize = buildingeffsize(maxb, false); - if (maxeffsize == 0) { - maxb = (building *) NULL; - maxowner = (unit *) NULL; - } - } - /* Die Region muss genug Geld haben, um die Produkte kaufen zu können. */ - - money = rmoney(r); - - /* max_products sind 1/100 der Bevölkerung, falls soviele Produkte - * verkauft werden - counter[] - sinkt die Nachfrage um 1 Punkt. - * multiplier speichert r->demand für die debug message ab. */ - - max_products = rpeasants(r) / TRADE_FRACTION; - if (max_products <= 0) return; - - if (r->terrain == newterrain(T_DESERT) && buildingtype_exists(r, bt_find("caravan"), true)) { - max_products = rpeasants(r) * 2 / TRADE_FRACTION; - } - /* Verkauf: so programmiert, dass er leicht auf mehrere Gueter pro - * Runde erweitert werden kann. */ - - expandorders(r, sellorders); - if (!norders) return; - - for (j = 0; j != norders; j++) { - static const luxury_type * search=NULL; - const luxury_type * ltype = oa[j].type.ltype; - int multi = r_demand(r, ltype); - static int i=-1; - int use = 0; - if (search!=ltype) { - i=0; - for (search=luxurytypes;search!=ltype;search=search->next) ++i; - } - if (counter[i]>=limit) continue; - if (counter[i]+1 > max_products && multi > 1) --multi; - price = ltype->price * multi; - - if (money >= price) { - int abgezogenhafen = 0; - int abgezogensteuer = 0; - unit * u = oa[j].unit; - item * itm; - attrib * a = a_find(u->attribs, &at_luxuries); - if (a==NULL) a = a_add(&u->attribs, a_new(&at_luxuries)); - itm = (item *)a->data.v; - i_change(&itm, ltype->itype, 1); - a->data.v = itm; - ++use; - if (u->n < 0) - u->n = 0; - - if (hafenowner != NULL) { - if (hafenowner->faction != u->faction) { - abgezogenhafen = price / 10; - hafencollected += abgezogenhafen; - price -= abgezogenhafen; - money -= abgezogenhafen; - } - } - if (maxb != NULL) { - if (maxowner->faction != u->faction) { - abgezogensteuer = price * tax_per_size[maxeffsize] / 100; - taxcollected += abgezogensteuer; - price -= abgezogensteuer; - money -= abgezogensteuer; - } - } - u->n += price; - change_money(u, price); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - - /* r->money -= price; --- dies wird eben nicht ausgeführt, denn die - * Produkte können auch als Steuern eingetrieben werden. In der Region - * wurden Silberstücke gegen Luxusgüter des selben Wertes eingetauscht! - * Falls mehr als max_products Kunden ein Produkt gekauft haben, sinkt - * die Nachfrage für das Produkt um 1. Der Zähler wird wieder auf 0 - * gesetzt. */ - - if (++counter[i] > max_products) { - int d = r_demand(r, ltype); - if (d > 1) { - r_setdemand(r, ltype, d-1); - } - counter[i] = 0; - } - } - if (use>0) { -#ifdef NDEBUG - use_pooled(oa[j].unit, ltype->itype->rtype, GET_DEFAULT, use); -#else - /* int i = */ use_pooled(oa[j].unit, ltype->itype->rtype, GET_DEFAULT, use); - /* assert(i==use); */ -#endif - } - } - free(oa); - - /* Steuern. Hier werden die Steuern dem Besitzer der größten Burg gegeben. */ - - if (maxowner) { - if (taxcollected > 0) { - change_money(maxowner, (int) taxcollected); - add_income(maxowner, IC_TRADETAX, taxcollected, taxcollected); - /* TODO: Meldung - * "%s verdient %d Silber durch den Handel in %s.", - * unitname(maxowner), (int) taxcollected, regionname(r)); */ - } - } - if (hafenowner) { - if (hafencollected > 0) { - change_money(hafenowner, (int) hafencollected); - add_income(hafenowner, IC_TRADETAX, hafencollected, hafencollected); - } - } - /* Berichte an die Einheiten */ - - for (u = r->units; u; u = u->next) { - - attrib * a = a_find(u->attribs, &at_luxuries); - item * itm; - if (a==NULL) continue; - for (itm=(item*)a->data.v; itm; itm=itm->next) { - if (itm->number) { - ADDMSG(&u->faction->msgs, msg_message("sellamount", - "unit amount resource", u, itm->number, itm->type->rtype)); - } - } - a_remove(&u->attribs, a); - add_income(u, IC_TRADE, u->n, u->n); - } -} - -static boolean - sell(unit * u, request ** sellorders, struct order * ord) -{ - boolean unlimited = true; - const item_type * itype; - const luxury_type * ltype=NULL; - int n; - region * r = u->region; - const char *s; - - if (u->ship && is_guarded(r, u, GUARD_CREWS)) { - cmistake(u, ord, 69, MSG_INCOME); - return false; - } - /* sellorders sind KEIN array, weil für alle items DIE SELBE resource - * (das geld der region) aufgebraucht wird. */ - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - if (findparam(s, u->faction->locale) == P_ANY) { - unlimited = false; - n = rpeasants(r) / TRADE_FRACTION; - if (r->terrain == newterrain(T_DESERT) && buildingtype_exists(r, bt_find("caravan"), true)) - n *= 2; - if (n==0) { - cmistake(u, ord, 303, MSG_COMMERCE); - return false; - } - } else { - n = atoi((const char *)s); - if (n==0) { - cmistake(u, ord, 27, MSG_COMMERCE); - return false; - } - } - /* Belagerte Einheiten können nichts verkaufen. */ - - if (besieged(u)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "error60", "")); - return false; - } - /* In der Region muß es eine Burg geben. */ - - if (u->race == new_race[RC_INSECT]) { - if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT) && !rbuildings(r)) { - cmistake(u, ord, 119, MSG_COMMERCE); - return false; - } - } else { - /* ...oder in der Region muß es eine Burg geben. */ - building * b; - static const struct building_type * bt_castle; - if (!bt_castle) bt_castle = bt_find("castle"); - for (b=r->buildings;b;b=b->next) { - if (b->type==bt_castle && b->size>=2) break; - } - if (b==NULL) { - cmistake(u, ord, 119, MSG_COMMERCE); - return false; - } - } - - /* Ein Händler kann nur 10 Güter pro Talentpunkt verkaufen. */ - - n = MIN(n, u->number * 10 * eff_skill(u, SK_TRADE, r)); - - if (!n) { - cmistake(u, ord, 54, MSG_COMMERCE); - return false; - } - s=getstrtoken(); - itype = finditemtype(s, u->faction->locale); - if (itype!=NULL) ltype = resource2luxury(itype->rtype); - if (ltype==NULL) { - cmistake(u, ord, 126, MSG_COMMERCE); - return false; - } - else { - attrib * a; - request *o; - int k, available; - - if (!r_demand(r, ltype)) { - cmistake(u, ord, 263, MSG_COMMERCE); - return false; - } - available = get_pooled(u, itype->rtype, GET_DEFAULT, INT_MAX); - - /* Wenn andere Einheiten das selbe verkaufen, muß ihr Zeug abgezogen - * werden damit es nicht zweimal verkauft wird: */ - for (o=*sellorders;o;o=o->next) { - if (o->type.ltype==ltype && o->unit->faction == u->faction) { - int fpool = o->qty - get_pooled(o->unit, itype->rtype, GET_RESERVE, INT_MAX); - available -= MAX(0, fpool); - } - } - - n = MIN(n, available); - - if (n <= 0) { - cmistake(u, ord, 264, MSG_COMMERCE); - return false; - } - /* Hier wird request->type verwendet, weil die obere limit durch - * das silber gegeben wird (region->money), welches für alle - * (!) produkte als summe gilt, als nicht wie bei der - * produktion, wo für jedes produkt einzeln eine obere limite - * existiert, so dass man arrays von orders machen kann. */ - - /* Ein Händler kann nur 10 Güter pro Talentpunkt handeln. */ - k = u->number * 10 * eff_skill(u, SK_TRADE, r); - - /* hat der Händler bereits gehandelt, muss die Menge der bereits - * verkauften/gekauften Güter abgezogen werden */ - a = a_find(u->attribs, &at_trades); - if (!a) { - a = a_add(&u->attribs, a_new(&at_trades)); - } else { - k -= a->data.i; - } - - n = MIN(n, k); - assert(n>=0); - /* die Menge der verkauften Güter merken */ - a->data.i += n; - o = (request *) calloc(1, sizeof(request)); - o->unit = u; - o->qty = n; - o->type.ltype = ltype; - addlist(sellorders, o); - - return unlimited; - } -} -/* ------------------------------------------------------------- */ - -static void -expandstealing(region * r, request * stealorders) -{ - int i; - - expandorders(r, stealorders); - if (!norders) return; - - /* Für jede unit in der Region wird Geld geklaut, wenn sie Opfer eines - * Beklauen-Orders ist. Jedes Opfer muß einzeln behandelt werden. - * - * u ist die beklaute unit. oa.unit ist die klauende unit. - */ - - for (i = 0; i != norders && oa[i].unit->n <= oa[i].unit->wants; i++) { - unit *u = findunitg(oa[i].no, r); - int n = 0; - if (u && u->region==r) { - n = get_pooled(u, r_silver, GET_ALL, INT_MAX); - } -#ifndef GOBLINKILL - if (oa[i].type.goblin) { /* Goblin-Spezialklau */ - int uct = 0; - unit *u2; - assert(effskill(oa[i].unit, SK_STEALTH)>=4 || !"this goblin\'s skill is too low"); - for (u2 = r->units; u2; u2 = u2->next) { - if (u2->faction == u->faction) { - uct += maintenance_cost(u2); - } - } - n -= uct * 2; - } -#endif - if (n>10 && rplane(r) && (rplane(r)->flags & PFL_NOALLIANCES)) { - /* In Questen nur reduziertes Klauen */ - n = 10; - } - if (n > 0) { - n = MIN(n, oa[i].unit->wants); - use_pooled(u, r_silver, GET_ALL, n); - oa[i].unit->n = n; - change_money(oa[i].unit, n); - ADDMSG(&u->faction->msgs, msg_message("stealeffect", "unit region amount", u, u->region, n)); - } - add_income(oa[i].unit, IC_STEAL, oa[i].unit->wants, oa[i].unit->n); - fset(oa[i].unit, UFL_LONGACTION|UFL_NOTMOVING); - } - free(oa); -} - -/* ------------------------------------------------------------- */ -static void -plant(region *r, unit *u, int raw) -{ - int n, i, skill, planted = 0; - const item_type * itype; - static const resource_type * rt_water = NULL; - if (rt_water==NULL) rt_water = rt_find("p2"); - - assert(rt_water!=NULL); - if (!fval(r->terrain, LAND_REGION)) { - return; - } - if (rherbtype(r) == NULL) { - cmistake(u, u->thisorder, 108, MSG_PRODUCE); - return; - } - - /* Skill prüfen */ - skill = eff_skill(u, SK_HERBALISM, r); - itype = rherbtype(r); - if (skill < 6) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "plant_skills", - "skill minskill product", SK_HERBALISM, 6, itype->rtype, 1)); - return; - } - /* Wasser des Lebens prüfen */ - if (get_pooled(u, rt_water, GET_DEFAULT, 1) == 0) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "resource_missing", "missing", rt_water)); - return; - } - n = get_pooled(u, itype->rtype, GET_DEFAULT, skill*u->number); - /* Kräuter prüfen */ - if (n==0) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "resource_missing", "missing", - itype->rtype)); - return; - } - - n = MIN(skill*u->number, n); - n = MIN(raw, n); - /* Für jedes Kraut Talent*10% Erfolgschance. */ - for(i = n; i>0; i--) { - if (rng_int()%10 < skill) planted++; - } - produceexp(u, SK_HERBALISM, u->number); - - /* Alles ok. Abziehen. */ - use_pooled(u, rt_water, GET_DEFAULT, 1); - use_pooled(u, itype->rtype, GET_DEFAULT, n); - rsetherbs(r, rherbs(r)+planted); - ADDMSG(&u->faction->msgs, msg_message("plant", "unit region amount herb", - u, r, planted, itype->rtype)); -} - -static void -planttrees(region *r, unit *u, int raw) -{ - int n, i, skill, planted = 0; - const resource_type * rtype; - - if (!fval(r->terrain, LAND_REGION)) { - return; - } - - /* Mallornbäume kann man nur in Mallornregionen züchten */ - if (fval(r, RF_MALLORN)) { - rtype = rt_mallornseed; - } else { - rtype = rt_seed; - } - - /* Skill prüfen */ - skill = eff_skill(u, SK_HERBALISM, r); - if (skill < 6) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "plant_skills", - "skill minskill product", SK_HERBALISM, 6, rtype, 1)); - return; - } - if (fval(r, RF_MALLORN) && skill < 7 ) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "plant_skills", - "skill minskill product", SK_HERBALISM, 7, rtype, 1)); - return; - } - - /* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */ - raw = MIN(raw, skill*u->number); - n = get_pooled(u, rtype, GET_DEFAULT, raw); - if (n==0) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype)); - return; - } - n = MIN(raw, n); - - /* Für jeden Samen Talent*10% Erfolgschance. */ - for(i = n; i>0; i--) { - if (rng_int()%10 < skill) planted++; - } - rsettrees(r, 0, rtrees(r, 0)+planted); - - /* Alles ok. Abziehen. */ - produceexp(u, SK_HERBALISM, u->number); - use_pooled(u, rtype, GET_DEFAULT, n); - - ADDMSG(&u->faction->msgs, msg_message("plant", - "unit region amount herb", u, r, planted, rtype)); -} - -/* züchte bäume */ -static void -breedtrees(region *r, unit *u, int raw) -{ - int n, i, skill, planted = 0; - const resource_type * rtype; - static int gamecookie = -1; - static int current_season; - - if (gamecookie!=global.cookie) { - gamedate date; - get_gamedate(turn, &date); - current_season = date.season; - gamecookie = global.cookie; - } - - /* Bäume züchten geht nur im Frühling */ - if (current_season != SEASON_SPRING){ - planttrees(r, u, raw); - return; - } - - if (!fval(r->terrain, LAND_REGION)) { - return; - } - - /* Mallornbäume kann man nur in Mallornregionen züchten */ - if (fval(r, RF_MALLORN)) { - rtype = rt_mallornseed; - } else { - rtype = rt_seed; - } - - /* Skill prüfen */ - skill = eff_skill(u, SK_HERBALISM, r); - if (skill < 12) { - planttrees(r, u, raw); - return; - } - - /* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */ - raw = MIN(skill*u->number, raw); - n = get_pooled(u, rtype, GET_DEFAULT, raw); - /* Samen prüfen */ - if (n==0) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype)); - return; - } - n = MIN(raw, n); - - /* Für jeden Samen Talent*5% Erfolgschance. */ - for(i = n; i>0; i--) { - if (rng_int()%100 < skill*5) planted++; - } - rsettrees(r, 1, rtrees(r, 1)+planted); - - /* Alles ok. Abziehen. */ - produceexp(u, SK_HERBALISM, u->number); - use_pooled(u, rtype, GET_DEFAULT, n); - - ADDMSG(&u->faction->msgs, msg_message("plant", - "unit region amount herb", u, r, planted, rtype)); -} - -/* züchte pferde */ -static void -breedhorses(region *r, unit *u) -{ - int n, c; - int gezuechtet = 0; - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - - if (btype!=bt_find("stables")) { - cmistake(u, u->thisorder, 122, MSG_PRODUCE); - return; - } - if (get_item(u, I_HORSE) < 2) { - cmistake(u, u->thisorder, 107, MSG_PRODUCE); - return; - } - n = MIN(u->number * eff_skill(u, SK_HORSE_TRAINING, r), get_item(u, I_HORSE)); - - for (c = 0; c < n; c++) { - if (rng_int() % 100 < eff_skill(u, SK_HORSE_TRAINING, r)) { - i_change(&u->items, olditemtype[I_HORSE], 1); - gezuechtet++; - } - } - - produceexp(u, SK_HORSE_TRAINING, u->number); - - ADDMSG(&u->faction->msgs, msg_message("raised", - "unit amount", u, gezuechtet)); -} - -static void -breed_cmd(unit *u, struct order * ord) -{ - int m; - const char *s; - param_t p; - region *r = u->region; - const resource_type * rtype = NULL; - - if (r->land==NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); - return; - } - - /* züchte [] */ - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - m = atoi((const char *)s); - if (m!=0) { - /* first came a want-paramter */ - s = getstrtoken(); - } else { - m = INT_MAX; - } - - if (!s[0]) { - p = P_ANY; - } else { - p = findparam(s, u->faction->locale); - } - - switch (p) { - case P_HERBS: - plant(r, u, m); - break; - case P_TREES: - breedtrees(r, u, m); - break; - default: - if (p!=P_ANY) { - rtype = findresourcetype(s, u->faction->locale); - if (rtype==rt_mallornseed || rtype==rt_seed) { - breedtrees(r, u, m); - break; - } else if (rtype!=oldresourcetype[R_HORSE]) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_cannotmake", "")); - break; - } - } - breedhorses(r, u); - break; - } -} - -static const char * -rough_amount(int a, int m) - -{ - int p = (a * 100)/m; - - if (p < 10) { - return "sehr wenige"; - } else if (p < 30) { - return "wenige"; - } else if (p < 60) { - return "relativ viele"; - } else if (p < 90) { - return "viele"; - } - return "sehr viele"; -} - -static void -research_cmd(unit *u, struct order * ord) -{ - region *r = u->region; - - init_tokens(ord); - skip_token(); - /* - const char *s = getstrtoken(); - - if (findparam(s, u->faction->locale) == P_HERBS) { */ - - if (eff_skill(u, SK_HERBALISM, r) < 7) { - cmistake(u, ord, 227, MSG_EVENT); - return; - } - - produceexp(u, SK_HERBALISM, u->number); - - if (rherbs(r) > 0) { - const item_type *itype = rherbtype(r); - - if (itype != NULL) { - ADDMSG(&u->faction->msgs, msg_message("researchherb", - "unit region amount herb", - u, r, rough_amount(rherbs(r), 100), itype->rtype)); - } else { - ADDMSG(&u->faction->msgs, msg_message("researchherb_none", - "unit region", u, r)); - } - } else { - ADDMSG(&u->faction->msgs, msg_message("researchherb_none", - "unit region", u, r)); - } -} - -static int -max_skill(region * r, faction * f, skill_t sk) -{ - unit *u; - int w = 0; - - for (u = r->units; u; u = u->next) { - if (u->faction == f) { - if (eff_skill(u, sk, r) > w) { - w = eff_skill(u, sk, r); - } - } - } - - return w; -} - -static void -steal_cmd(unit * u, struct order * ord, request ** stealorders) -{ - int n, i, id; - boolean goblin = false; - request * o; - unit * u2 = NULL; - region * r = u->region; - faction * f = NULL; - plane * pl; - - assert(skill_enabled[SK_PERCEPTION] && skill_enabled[SK_STEALTH]); - - if (!fval(u->race, RCF_CANSTEAL)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_nosteal", "race", u->race)); - return; - } - - if (fval(r->terrain, SEA_REGION) && u->race != new_race[RC_AQUARIAN]) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); - return; - } - - pl = rplane(r); - if (pl && fval(pl, PFL_NOATTACK)) { - cmistake(u, ord, 270, MSG_INCOME); - return; - } - - init_tokens(ord); - skip_token(); - id = read_unitid(u->faction, r); - u2 = findunitr(r, id); - - if (u2 && u2->region==u->region) { - f = u2->faction; - } else { - f = dfindhash(id); - } - - for (u2=r->units;u2;u2=u2->next) { - if (u2->faction == f && cansee(u->faction, r, u2, 0)) break; - } - - if (!u2) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return; - } - - if (IsImmune(u2->faction)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "newbie_immunity_error", - "turns", NewbieImmunity())); - return; - } - - if (u->faction->alliance && u->faction->alliance == u2->faction->alliance) { - cmistake(u, ord, 47, MSG_INCOME); - return; - } - - assert(u->region==u2->region); - if (!can_contact(r, u, u2)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error60", "")); - return; - } - - n = eff_skill(u, SK_STEALTH, r) - max_skill(r, f, SK_PERCEPTION); - - if (n <= 0) { - /* Wahrnehmung == Tarnung */ - if (u->race != new_race[RC_GOBLIN] || eff_skill(u, SK_STEALTH, r) <= 3) { - ADDMSG(&u->faction->msgs, msg_message("stealfail", "unit target", u, u2)); - if (n==0) { - ADDMSG(&u2->faction->msgs, msg_message("stealdetect", "unit", u2)); - } else { - ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target", u, u2)); - } - return; - } else { - ADDMSG(&u->faction->msgs, msg_message("stealfatal", "unit target", u, u2)); - ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target", u, u2)); - n = 1; - goblin = true; - } - } - - i = MIN(u->number, get_item(u, I_RING_OF_NIMBLEFINGER)); - if (i > 0) { - n *= STEALINCOME * (u->number + i * (roqf_factor()-1)); - } else { - n *= u->number * STEALINCOME; - } - - u->wants = n; - - /* wer dank unsichtbarkeitsringen klauen kann, muss nicht unbedingt ein - * guter dieb sein, schliesslich macht man immer noch sehr viel laerm */ - - o = (request *) calloc(1, sizeof(request)); - o->unit = u; - o->qty = 1; /* Betrag steht in u->wants */ - o->no = u2->no; - o->type.goblin = goblin; /* Merken, wenn Goblin-Spezialklau */ - addlist(stealorders, o); - - /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ - - produceexp(u, SK_STEALTH, MIN(n, u->number)); -} -/* ------------------------------------------------------------- */ - - -static void -expandentertainment(region * r) -{ - unit *u; - int m = entertainmoney(r); - request *o; - - for (o = &entertainers[0]; o != nextentertainer; ++o) { - double part = m / (double) entertaining; - u = o->unit; - if (entertaining <= m) - u->n = o->qty; - else - u->n = (int) (o->qty * part); - change_money(u, u->n); - rsetmoney(r, rmoney(r) - u->n); - m -= u->n; - entertaining -= o->qty; - - /* Nur soviel PRODUCEEXP wie auch tatsächlich gemacht wurde */ - produceexp(u, SK_ENTERTAINMENT, MIN(u->n, u->number)); - add_income(u, IC_ENTERTAIN, o->qty, u->n); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - } -} - -void -entertain_cmd(unit * u, struct order * ord) -{ - region * r = u->region; - int max_e; - request *o; - static int entertainbase = 0; - static int entertainperlevel = 0; - - if (!entertainbase) { - const char * str = get_param(global.parameters, "entertain.base"); - entertainbase = str?atoi(str):0; - } - if (!entertainperlevel) { - const char * str = get_param(global.parameters, "entertain.perlevel"); - entertainperlevel = str?atoi(str):0; - } - if (fval(u, UFL_WERE)) { - cmistake(u, ord, 58, MSG_INCOME); - return; - } - if (!effskill(u, SK_ENTERTAINMENT)) { - cmistake(u, ord, 58, MSG_INCOME); - return; - } - if (besieged(u)) { - cmistake(u, ord, 60, MSG_INCOME); - return; - } - if (u->ship && is_guarded(r, u, GUARD_CREWS)) { - cmistake(u, ord, 69, MSG_INCOME); - return; - } - if (is_cursed(r->attribs, C_DEPRESSION, 0)) { - cmistake(u, ord, 28, MSG_INCOME); - return; - } - - u->wants = u->number * (entertainbase + effskill(u, SK_ENTERTAINMENT) - * entertainperlevel); - - init_tokens(ord); - skip_token(); - max_e = getuint(); - if (max_e != 0) { - u->wants = MIN(u->wants,max_e); - } - o = nextentertainer++; - o->unit = u; - o->qty = u->wants; - entertaining += o->qty; -} - -/** - * \return number of working spaces taken by players - */ -static void -expandwork(region * r, request * work_begin, request * work_end, int maxwork) -{ - int earnings; - /* n: verbleibende Einnahmen */ - /* fishes: maximale Arbeiter */ - int jobs = maxwork; - int p_wage = wage(r, NULL, NULL, turn); - int money = rmoney(r); - request *o; - - for (o = work_begin; o != work_end; ++o) { - unit * u = o->unit; - int workers; - - if (u->number == 0) continue; - - if (jobs>=working) workers = u->number; - else { - workers = u->number * jobs / working; - if (rng_int() % working < (u->number * jobs) % working) workers++; - } - - assert(workers>=0); - - u->n = workers * wage(u->region, u->faction, u->race, turn); - - jobs -= workers; - assert(jobs>=0); - - change_money(u, u->n); - working -= o->unit->number; - add_income(u, IC_WORK, o->qty, u->n); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - } - - if (jobs>rpeasants(r)) { - jobs = rpeasants(r); - } - earnings = jobs * p_wage; - if (rule_blessed_harvest()==HARVEST_TAXES) { - /* E3 rules */ - static const curse_type * blessedharvest_ct; - if (!blessedharvest_ct) { - blessedharvest_ct = ct_find("blessedharvest"); - } - if (blessedharvest_ct && r->attribs) { - int happy = (int)curse_geteffect(get_curse(r->attribs, blessedharvest_ct)); - happy = MIN(happy, jobs); - earnings += happy; - } - } - rsetmoney(r, money + earnings); -} - -static int -do_work(unit * u, order * ord, request * o) -{ - if (playerrace(u->race)) { - region * r = u->region; - int w; - - if (fval(u, UFL_WERE)) { - if (ord) cmistake(u, ord, 313, MSG_INCOME); - return -1; - } - if (besieged(u)) { - if (ord) cmistake(u, ord, 60, MSG_INCOME); - return -1; - } - if (u->ship && is_guarded(r, u, GUARD_CREWS)) { - if (ord) cmistake(u, ord, 69, MSG_INCOME); - return -1; - } - w = wage(r, u->faction, u->race, turn); - u->wants = u->number * w; - o->unit = u; - o->qty = u->number * w; - working += u->number; - return 0; - } - else if (ord && !is_monsters(u->faction)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_cantwork", "race", u->race)); - } - return -1; -} - -static void -expandtax(region * r, request * taxorders) -{ - unit *u; - int i; - - expandorders(r, taxorders); - if (!norders) return; - - for (i = 0; i != norders && rmoney(r) > TAXFRACTION; i++) { - change_money(oa[i].unit, TAXFRACTION); - oa[i].unit->n += TAXFRACTION; - rsetmoney(r, rmoney(r) -TAXFRACTION); - } - free(oa); - - for (u = r->units; u; u = u->next) { - if (u->n >= 0) { - add_income(u, IC_TAX, u->wants, u->n); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - } - } -} - -void -tax_cmd(unit * u, struct order * ord, request ** taxorders) -{ - /* Steuern werden noch vor der Forschung eingetrieben */ - region * r = u->region; - unit *u2; - int n; - request *o; - int max; - - if (!humanoidrace(u->race) && !is_monsters(u->faction)) { - cmistake(u, ord, 228, MSG_INCOME); - return; - } - - if (fval(u, UFL_WERE)) { - cmistake(u, ord, 228, MSG_INCOME); - return; - } - - if (besieged(u)) { - cmistake(u, ord, 60, MSG_INCOME); - return; - } - n = armedmen(u, false); - - if (!n) { - cmistake(u, ord, 48, MSG_INCOME); - return; - } - - init_tokens(ord); - skip_token(); - max = getuint(); - - if (max == 0) max = INT_MAX; - if (!playerrace(u->race)) { - u->wants = MIN(income(u), max); - } else { - u->wants = MIN(n * eff_skill(u, SK_TAXING, r) * 20, max); - } - - u2 = is_guarded(r, u, GUARD_TAX); - if (u2) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "region_guarded", "guard", u2)); - return; - } - - /* die einnahmen werden in fraktionen von 10 silber eingeteilt: diese - * fraktionen werden dann bei eintreiben unter allen eintreibenden - * einheiten aufgeteilt. */ - - o = (request *) calloc(1, sizeof(request)); - o->qty = u->wants / TAXFRACTION; - o->unit = u; - addlist(taxorders, o); - return; -} - -#define MAX_WORKERS 2048 -void -auto_work(region * r) -{ - request workers[MAX_WORKERS]; - request * nextworker = workers; - unit * u; - - for (u=r->units;u;u=u->next) { - if (!(u->flags & UFL_LONGACTION) && !is_monsters(u->faction)) { - if (do_work(u, NULL, nextworker)==0) { - assert(nextworker-workersfaction!=f) return; - - maxsize = buildingeffsize(b, false); - if (maxsize>0) { - double taxfactor = money * b->type->taxes(b, maxsize); - double morale = money * region_get_morale(r) * MORALE_TAX_FACTOR; - if (taxfactor>morale) taxfactor = morale; - if (taxfactor>0) { - int taxmoney = (int)taxfactor; - change_money(u, taxmoney); - rsetmoney(r, money - taxmoney); - ADDMSG(&u->faction->msgs, msg_message("income_tax", - "unit region amount", u, r, taxmoney)); - } - } -} - -void -produce(struct region *r) -{ - request workers[MAX_WORKERS]; - request *taxorders, *sellorders, *stealorders, *buyorders; - unit *u; - int todo; - static int rule_autowork = -1; - boolean limited = true; - request * nextworker = workers; - assert(r); - - /* das sind alles befehle, die 30 tage brauchen, und die in thisorder - * stehen! von allen 30-tage befehlen wird einfach der letzte verwendet - * (dosetdefaults). - * - * kaufen vor einnahmequellen. da man in einer region dasselbe produkt - * nicht kaufen und verkaufen kann, ist die reihenfolge wegen der - * produkte egal. nicht so wegen dem geld. - * - * lehren vor lernen. */ - - if (rule_autowork<0) { - rule_autowork = get_param_int(global.parameters, "work.auto", 0); - } - - assert(rmoney(r) >= 0); - assert(rpeasants(r) >= 0); - - if (r->land && rule_auto_taxation()) { - /* new taxation rules, region owners make money based on morale and building */ - peasant_taxes(r); - } - - buyorders = 0; - sellorders = 0; - working = 0; - nextentertainer = &entertainers[0]; - entertaining = 0; - taxorders = 0; - stealorders = 0; - - for (u = r->units; u; u = u->next) { - order * ord; - boolean trader = false; - - if (u->race == new_race[RC_SPELL] || fval(u, UFL_LONGACTION)) - continue; - - if (u->race == new_race[RC_INSECT] && r_insectstalled(r) && - !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) - continue; - - if (fval(u, UFL_LONGACTION) && u->thisorder==NULL) { - cmistake(u, u->thisorder, 52, MSG_PRODUCE); - continue; - } - - for (ord = u->orders;ord;ord=ord->next) { - switch (get_keyword(ord)) { - case K_BUY: - buy(u, &buyorders, ord); - trader = true; - break; - case K_SELL: - /* sell returns true if the sale is not limited - * by the region limit */ - limited &= !sell(u, &sellorders, ord); - trader = true; - break; - } - } - if (trader) { - attrib * a = a_find(u->attribs, &at_trades); - if (a && a->data.i) { - produceexp(u, SK_TRADE, u->number); - } - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - continue; - } - - todo = get_keyword(u->thisorder); - if (todo == NOKEYWORD) continue; - - if (fval(r->terrain, SEA_REGION) && u->race != new_race[RC_AQUARIAN] - && !(u->race->flags & RCF_SWIM) - && todo != K_STEAL && todo != K_SPY && todo != K_SABOTAGE) - continue; - - switch (todo) { - - case K_ENTERTAIN: - entertain_cmd(u, u->thisorder); - break; - - case K_WORK: - if (!rule_autowork && do_work(u, u->thisorder, nextworker)==0) { - assert(nextworker-workersthisorder, &taxorders); - break; - - case K_STEAL: - steal_cmd(u, u->thisorder, &stealorders); - break; - - case K_SPY: - spy_cmd(u, u->thisorder); - break; - - case K_SABOTAGE: - sabotage_cmd(u, u->thisorder); - break; - - case K_PLANT: - case K_BREED: - breed_cmd(u, u->thisorder); - break; - - case K_RESEARCH: - research_cmd(u, u->thisorder); - break; - } - } - - /* Entertainment (expandentertainment) und Besteuerung (expandtax) vor den - * Befehlen, die den Bauern mehr Geld geben, damit man aus den Zahlen der - * letzten Runde berechnen kann, wieviel die Bauern für Unterhaltung - * auszugeben bereit sind. */ - if (entertaining) expandentertainment(r); - if (!rule_autowork) { - expandwork(r, workers, nextworker, maxworkingpeasants(r)); - } - if (taxorders) expandtax(r, taxorders); - - /* An erster Stelle Kaufen (expandbuying), die Bauern so Geld bekommen, um - * nachher zu beim Verkaufen (expandselling) den Spielern abkaufen zu - * können. */ - - if (buyorders) expandbuying(r, buyorders); - - if (sellorders) { - int limit = rpeasants(r) / TRADE_FRACTION; - if (r->terrain == newterrain(T_DESERT) && buildingtype_exists(r, bt_find("caravan"), true)) - limit *= 2; - expandselling(r, sellorders, limited?limit:INT_MAX); - } - - /* Die Spieler sollen alles Geld verdienen, bevor sie beklaut werden - * (expandstealing). */ - - if (stealorders) expandstealing(r, stealorders); - - assert(rmoney(r) >= 0); - assert(rpeasants(r) >= 0); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#pragma region includes + +#include +#include +#include "economy.h" + +/* gamecode includes */ +#include "archetype.h" +#include "give.h" +#include "laws.h" +#include "randenc.h" +#include "spy.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +/* libs includes */ +#include +#include +#include +#include +#include + +#pragma endregion + +typedef struct request { + struct request * next; + struct unit * unit; + struct order * ord; + int qty; + int no; + union { + boolean goblin; /* stealing */ + const struct luxury_type * ltype; /* trading */ + } type; +} request; + +static int working; + +static request entertainers[1024]; +static request *nextentertainer; +static int entertaining; + +static int norders; +static request *oa; + +#define RECRUIT_MERGE 1 +#define RECRUIT_CLASSIC 2 +#define RECRUIT_ARCHETYPES 4 +static int rules_recruit = -1; + +static void recruit_init(void) +{ + if (rules_recruit<0) { + rules_recruit = 0; + if (get_param_int(global.parameters, "recruit.allow_merge", 1)) { + rules_recruit |= RECRUIT_MERGE; + } + if (get_param_int(global.parameters, "recruit.classic", 1)) { + rules_recruit |= RECRUIT_CLASSIC; + } + if (get_param_int(global.parameters, "recruit.archetype", 0)) { + rules_recruit |= RECRUIT_ARCHETYPES; + } + } +} + +int +income(const unit * u) +{ + switch(old_race(u->race)) { + case RC_FIREDRAGON: + return 150 * u->number; + case RC_DRAGON: + return 1000 * u->number; + case RC_WYRM: + return 5000 * u->number; + } + return 20 * u->number; +} + +static void +scramble(void *data, int n, size_t width) +{ + int j; + char temp[64]; + assert(width<=sizeof(temp)); + for (j=0;j!=n;++j) { + int k = rng_int() % n; + if (k==j) continue; + memcpy(temp, (char*)data+j*width, width); + memcpy((char*)data+j*width, (char*)data+k*width, width); + memcpy((char*)data+k*width, temp, width); + } +} + +static void +expandorders(region * r, request * requests) +{ + unit *u; + request *o; + + /* Alle Units ohne request haben ein -1, alle units mit orders haben ein + * 0 hier stehen */ + + for (u = r->units; u; u = u->next) + u->n = -1; + + norders = 0; + + for (o = requests; o; o = o->next) { + if (o->qty > 0) { + norders += o->qty; + } + } + + if (norders > 0) { + int i = 0; + oa = (request *) calloc(norders, sizeof(request)); + for (o = requests; o; o = o->next) { + if (o->qty > 0) { + int j; + for (j = o->qty; j; j--) { + oa[i] = *o; + oa[i].unit->n = 0; + i++; + } + } + } + scramble(oa, norders, sizeof(request)); + } else { + oa = NULL; + } + while (requests) { + request * o = requests->next; + free_order(requests->ord); + free(requests); + requests = o; + } +} +/* ------------------------------------------------------------- */ + +static void +change_level(unit * u, skill_t sk, int bylevel) +{ + skill * sv = get_skill(u, sk); + assert(bylevel>0); + if (sv==0) sv = add_skill(u, sk); + sk_set(sv, sv->level+bylevel); +} + +typedef struct recruitment { + struct recruitment * next; + faction * f; + request * requests; + int total, assigned; +} recruitment; + +static recruitment * +select_recruitment(request ** rop, int (*quantify)(const struct race*, int), int * total) +{ + recruitment * recruits = NULL; + + while (*rop) { + recruitment * rec = recruits; + request * ro = *rop; + unit * u = ro->unit; + const race * rc = u->race; + int qty = quantify(rc, ro->qty); + + if (qty<0) { + rop = &ro->next; /* skip this one */ + } else { + *rop = ro->next; /* remove this one */ + while (rec && rec->f!=u->faction) rec = rec->next; + if (rec==NULL) { + rec = malloc(sizeof(recruitment)); + rec->f = u->faction; + rec->total = 0; + rec->assigned = 0; + rec->requests = NULL; + rec->next = recruits; + recruits = rec; + } + *total += qty; + rec->total += qty; + ro->next = rec->requests; + rec->requests = ro; + } + } + return recruits; +} + +static void +add_recruits(unit * u, int number, int wanted) +{ + region * r = u->region; + assert(number<=wanted); + if (number > 0) { + unit * unew; + char equipment[64]; + + if (u->number==0) { + set_number(u, number); + u->hp = number * unit_max_hp(u); + unew = u; + } else { + unew = create_unit(r, u->faction, number, u->race, 0, NULL, u); + } + + snprintf(equipment, sizeof(equipment), "new_%s_unit", u->race->_name[0]); + equip_unit(unew, get_equipment(equipment)); + + + if (unew->race->ec_flags & ECF_REC_HORSES) { + change_level(unew, SK_RIDING, 1); + } + + if (unew!=u) { + transfermen(unew, u, unew->number); + remove_unit(&r->units, unew); + } + } + if (number < wanted) { + ADDMSG(&u->faction->msgs, msg_message("recruit", + "unit region amount want", u, r, number, wanted)); + } +} + +static int +any_recruiters(const struct race * rc, int qty) +{ + return (int)(qty * 2 * rc->recruit_multi); +} + +static int +peasant_recruiters(const struct race * rc, int qty) +{ + if (rc->ec_flags & ECF_REC_ETHEREAL) return -1; + if (rc->ec_flags & ECF_REC_HORSES) return -1; + return (int)(qty * 2 * rc->recruit_multi); +} + +static int +horse_recruiters(const struct race * rc, int qty) +{ + if (rc->ec_flags & ECF_REC_ETHEREAL) return -1; + if (rc->ec_flags & ECF_REC_HORSES) return (int)(qty * 2 * rc->recruit_multi); + return -1; +} + +static int +do_recruiting(recruitment * recruits, int available) +{ + recruitment * rec; + int recruited = 0; + + while (available>0) { + int n = 0; + int rest, mintotal = INT_MAX; + + for (rec=recruits;rec!=NULL;rec=rec->next) { + int want = rec->total - rec->assigned; + if (want>0) { + if (mintotal>want) mintotal = want; + ++n; + } + } + if (n==0) break; + if (mintotal*n>available) { + mintotal = available/n; + } + rest = available - mintotal*n; + + for (rec=recruits;rec!=NULL;rec=rec->next) { + int want = rec->total - rec->assigned; + + if (want>0) { + int get = mintotal; + if (want>mintotal && restassigned += get; + } + } + } + + for (rec=recruits;rec!=NULL;rec=rec->next) { + request * req; + int get = rec->assigned; + + for (req=rec->requests;req;req=req->next) { + unit * u = req->unit; + const race * rc = u->race; /* race is set in recruit() */ + int number, dec; + float multi = 2.0F * rc->recruit_multi; + + number = MIN(req->qty, (int)(get / multi)); + if (rc->recruitcost) { + int afford = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, number*rc->recruitcost) / rc->recruitcost; + number = MIN(number, afford); + use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, rc->recruitcost*number); + } + if (u->number+number>UNIT_MAXSIZE) { + ADDMSG(&u->faction->msgs, msg_feedback(u, req->ord, "error_unit_size", "maxsize", UNIT_MAXSIZE)); + number = UNIT_MAXSIZE-u->number; + assert(number>=0); + } + add_recruits(u, number, req->qty); + dec = (int)(number * multi); + if ((rc->ec_flags & ECF_REC_ETHEREAL)==0) { + recruited += dec; + } + + get -= dec; + } + } + return recruited; +} + +static void +feedback_give_not_allowed(unit * u, order * ord) +{ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_give_forbidden", "")); +} + +static boolean check_give(unit * u, unit * u2, const item_type * itype, int mask) +{ + if (u2) { + if (u->faction!=u2->faction) { + int rule = rule_give(); + if (itype) { + assert(mask==0); + if (itype->rtype->ltype) mask |= GIVE_LUXURIES; + else if (fval(itype, ITF_HERB)) mask |= GIVE_HERBS; + else mask |= GIVE_GOODS; + } + return (rule&mask)!=0; + } + } else { + int rule = rule_give(); + return (rule & GIVE_PEASANTS)!=0; + } + return true; +} + +void +free_recruitments(recruitment * recruits) +{ + while (recruits) { + recruitment * rec = recruits; + recruits = rec->next; + while (rec->requests) { + request * req = rec->requests; + rec->requests = req->next; + free(req); + } + free(rec); + } +} + +/* Rekrutierung */ +static void +expandrecruit(region * r, request * recruitorders) +{ + recruitment * recruits = NULL; + + int orc_total = 0; + + /* centaurs: */ + recruits = select_recruitment(&recruitorders, horse_recruiters, &orc_total); + if (recruits) { + int recruited, horses = rhorses(r) * 2; + if (orc_total0) { + rsetpeasants(r, peasants - recruited/2); + } + free_recruitments(recruits); + } + + assert(recruitorders==NULL); +} + +static int +recruit_cost(const faction * f, const race * rc) +{ + if (is_monsters(f) || f->race==rc) { + return rc->recruitcost; + } else if (valid_race(f, rc)) { + return rc->recruitcost; +/* return get_param_int(f->race->parameters, "other_cost", -1); */ + } + return -1; +} + +static void +recruit(unit * u, struct order * ord, request ** recruitorders) +{ + int n; + region * r = u->region; + plane * pl; + request *o; + int recruitcost = -1; + const faction * f = u->faction; + const struct race * rc = u->race; + const char * str; + + init_tokens(ord); + skip_token(); + n = getuint(); + + if (u->number==0) { + str = getstrtoken(); + if (str && str[0]) { + /* Monster dürfen REKRUTIERE 15 dracoid machen + * also: secondary race */ + rc = findrace(str, f->locale); + if (rc!=NULL) { + recruitcost = recruit_cost(f, rc); + } + } + } + if (recruitcost<0) { + rc = u->race; + recruitcost = recruit_cost(f, rc); + } + u->race = rc; + assert(rc && recruitcost>=0); + +#if GUARD_DISABLES_RECRUIT + /* this is a very special case because the recruiting unit may be empty + * at this point and we have to look at the creating unit instead. This + * is done in cansee, which is called indirectly by is_guarded(). */ + if (is_guarded(r, u, GUARD_RECRUIT)) { + cmistake(u, ord, 70, MSG_EVENT); + return; + } +#endif + + if (rc == new_race[RC_INSECT]) { + gamedate date; + get_gamedate(turn, &date); + if (date.season == 0 && r->terrain != newterrain(T_DESERT)) { +#ifdef INSECT_POTION + boolean usepotion = false; + unit *u2; + + for (u2 = r->units; u2; u2 = u2->next) + if (fval(u2, UFL_WARMTH)) { + usepotion = true; + break; + } + if (!usepotion) +#endif + { + cmistake(u, ord, 98, MSG_EVENT); + return; + } + } + /* in Gletschern, Eisbergen gar nicht rekrutieren */ + if (r_insectstalled(r)) { + cmistake(u, ord, 97, MSG_EVENT); + return; + } + } + if (is_cursed(r->attribs, C_RIOT, 0)) { + /* Die Region befindet sich in Aufruhr */ + cmistake(u, ord, 237, MSG_EVENT); + return; + } + + if (!(rc->ec_flags & ECF_REC_HORSES) && fval(r, RF_ORCIFIED)) { + if (rc != new_race[RC_ORC]) + { + cmistake(u, ord, 238, MSG_EVENT); + return; + } + } + + if (recruitcost) { + pl = getplane(r); + if (pl && fval(pl, PFL_NORECRUITS)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "error_pflnorecruit", "")); + return; + } + + if (get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, recruitcost) < recruitcost) { + cmistake(u, ord, 142, MSG_EVENT); + return; + } + } + if (!playerrace(rc) || idle(u->faction)) { + cmistake(u, ord, 139, MSG_EVENT); + return; + } + + if (has_skill(u, SK_MAGIC)) { + /* error158;de;{unit} in {region}: '{command}' - Magier arbeiten + * grundsätzlich nur alleine! */ + cmistake(u, ord, 158, MSG_EVENT); + return; + } + if (has_skill(u, SK_ALCHEMY) + && count_skill(u->faction, SK_ALCHEMY) + n > + skill_limit(u->faction, SK_ALCHEMY)) + { + cmistake(u, ord, 156, MSG_EVENT); + return; + } + if (recruitcost>0) { + int pooled = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, recruitcost * n); + n = MIN(n, pooled / recruitcost); + } + + u->wants = n; + + if (!n) { + cmistake(u, ord, 142, MSG_EVENT); + return; + } + + o = (request *) calloc(1, sizeof(request)); + o->qty = n; + o->unit = u; + o->ord = copy_order(ord); + addlist(recruitorders, o); +} + +static void +friendly_takeover(region * r, faction * f) +{ + int morale = region_get_morale(r); + region_set_owner(r, f, turn); + if (morale>0) { + morale = MAX(0, morale-MORALE_TRANSFER); + region_set_morale(r, morale, turn); + } +} + +static void +give_control(unit * u, unit * u2) +{ + if (u->building && u->faction!=u2->faction && rule_region_owners()) { + region * r = u->region; + faction * f = region_get_owner(r); + if (f==u->faction) { + building * b = largestbuilding(r, &cmp_current_owner, false); + if (b==u->building) { + friendly_takeover(r, u2->faction); + } + } + } + freset(u, UFL_OWNER); + fset(u2, UFL_OWNER); +} + +int +give_control_cmd(unit * u, order * ord) +{ + region * r = u->region; + unit *u2; + const char * s; + param_t p; + + init_tokens(ord); + skip_token(); + u2 = getunit(r, u->faction); + s = getstrtoken(); + p = findparam(s, u->faction->locale); + + /* first, do all the ones that do not require HELP_GIVE or CONTACT */ + if (p == P_CONTROL) { + message * msg; + + if (!u2) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } + else if (!u->building && !u->ship) { + cmistake(u, ord, 140, MSG_EVENT); + } + else if (u->building && u2->building != u->building) { + cmistake(u, ord, 33, MSG_EVENT); + } + else if (u->ship && u2->ship != u->ship) { + cmistake(u, ord, 32, MSG_EVENT); + } + else if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 49, MSG_EVENT); + } + else { + give_control(u, u2); + + msg = msg_message("givecommand", "unit recipient", u, u2); + add_message(&u->faction->msgs, msg); + if (u->faction != u2->faction) { + add_message(&u2->faction->msgs, msg); + } + msg_release(msg); + } + } + return 0; +} + +static void +give_cmd(unit * u, order * ord) +{ + region * r = u->region; + unit *u2; + const char *s; + int i, n; + const item_type * itype; + param_t p; + plane * pl; + + init_tokens(ord); + skip_token(); + u2 = getunit(r, u->faction); + s = getstrtoken(); + p = findparam(s, u->faction->locale); + + /* first, do all the ones that do not require HELP_GIVE or CONTACT */ + if (p == P_CONTROL) { + /* handled in give_control_cmd */ + return; + } + + if (!u2 && !getunitpeasants) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + + if (!check_give(u, u2, NULL, GIVE_ALLITEMS)) { + feedback_give_not_allowed(u, ord); + return; + } + + /* Damit Tarner nicht durch die Fehlermeldung enttarnt werden können */ + if (u2 && !alliedunit(u2, u->faction, HELP_GIVE) && !cansee(u->faction,r,u2,0) && !ucontact(u2, u) && !fval(u2, UFL_TAKEALL)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + if (u == u2) { + cmistake(u, ord, 8, MSG_COMMERCE); + return; + } + + /* UFL_TAKEALL ist ein grober Hack. Generalisierung tut not, ist aber nicht + * wirklich einfach. */ + pl = rplane(r); + if (pl && fval(pl, PFL_NOGIVE) && (!u2 || !fval(u2, UFL_TAKEALL))) { + cmistake(u, ord, 268, MSG_COMMERCE); + return; + } + + if (u2 && u2->race == new_race[RC_SPELL]) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + + else if (u2 && !alliedunit(u2, u->faction, HELP_GIVE) && !ucontact(u2, u)) { + cmistake(u, ord, 40, MSG_COMMERCE); + return; + } + + else if (p == P_HERBS) { + boolean given = false; + if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_nogive", "race", u->race)); + return; + } + if (!check_give(u, u2, NULL, GIVE_HERBS)) { + feedback_give_not_allowed(u, ord); + return; + } + if (u2 && !(u2->race->ec_flags & GETITEM)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_notake", "race", u2->race)); + return; + } + if (!u2) { + if (!getunitpeasants) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + } + if (u->items) { + item **itmp=&u->items; + while (*itmp) { + item * itm = *itmp; + const item_type * itype = itm->type; + if (fval(itype, ITF_HERB) && itm->number>0) { + /* give_item ändert im fall,das man alles übergibt, die + * item-liste der unit, darum continue vor pointerumsetzten */ + if (give_item(itm->number, itm->type, u, u2, ord)==0) { + given = true; + if (*itmp!=itm) continue; + continue; + } + } + itmp = &itm->next; + } + } + if (!given) cmistake(u, ord, 38, MSG_COMMERCE); + return; + } + + else if (p == P_ZAUBER) { + cmistake(u, ord, 7, MSG_COMMERCE); + /* geht nimmer */ + return; + } + + else if (p == P_UNIT) { /* Einheiten uebergeben */ + if (!(u->race->ec_flags & GIVEUNIT)) { + cmistake(u, ord, 167, MSG_COMMERCE); + return; + } + + give_unit(u, u2, ord); + return; + } + + else if (p==P_ANY) { + const char * s = getstrtoken(); + + if (!check_give(u, u2, NULL, GIVE_ALLITEMS)) { + feedback_give_not_allowed(u, ord); + return; + } + if (*s == 0) { /* Alle Gegenstände übergeben */ + + /* do these checks once, not for each item we have: */ + if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_nogive", "race", u->race)); + return; + } + if (u2 && !(u2->race->ec_flags & GETITEM)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_notake", "race", u2->race)); + return; + } + + /* für alle items einmal prüfen, ob wir mehr als von diesem Typ + * reserviert ist besitzen und diesen Teil dann übergeben */ + if (u->items) { + item **itmp=&u->items; + while (*itmp) { + item * itm = *itmp; + const item_type * itype = itm->type; + if (itm->number > 0 && itm->number - get_reservation(u, itype->rtype) > 0) { + n = itm->number - get_reservation(u, itype->rtype); + if (give_item(n, itype, u, u2, ord)==0) { + if (*itmp!=itm) continue; + } + } + itmp = &itm->next; + } + } + return; + } + else { + param_t p2 = findparam(s, u->faction->locale); + + if (p2 == P_PERSON) { + if (!(u->race->ec_flags & GIVEPERSON)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_noregroup", "race", u->race)); + return; + } + n = u->number; + give_men(n, u, u2, ord); + return; + } + + if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_nogive", "race", u->race)); + return; + } + if (u2 && !(u2->race->ec_flags & GETITEM)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_notake", "race", u2->race)); + return; + } + + itype = finditemtype(s, u->faction->locale); + if (itype!=NULL) { + item * i = *i_find(&u->items, itype); + if (i!=NULL) { + if (check_give(u, u2, itype, 0)) { + n = i->number - get_reservation(u, itype->rtype); + give_item(n, itype, u, u2, ord); + } else { + feedback_give_not_allowed(u, ord); + } + return; + } + } + } + } else if (p==P_EACH) { + if (u2==NULL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "peasants_give_invalid", "")); + return; + } + s = getstrtoken(); /* skip one ahead to get the amount. */ + } + + n = atoip((const char *)s); /* n: Anzahl */ + if (p==P_EACH) { + n *= u2->number; + } + s = getstrtoken(); + + if (s == NULL) { + cmistake(u, ord, 113, MSG_COMMERCE); + return; + } + + i = findparam(s, u->faction->locale); + if (i == P_PERSON) { + if (!(u->race->ec_flags & GIVEPERSON)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_noregroup", "race", u->race)); + return; + } + give_men(n, u, u2, ord); + return; + } + + if (u2!=NULL) { + if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_nogive", "race", u->race)); + return; + } + if (!(u2->race->ec_flags & GETITEM)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_notake", "race", u2->race)); + return; + } + } + + itype = finditemtype(s, u->faction->locale); + if (itype!=NULL) { + if (check_give(u, u2, itype, 0)) { + give_item(n, itype, u, u2, ord); + } else { + feedback_give_not_allowed(u, ord); + } + return; + } + cmistake(u, ord, 123, MSG_COMMERCE); +} + +static int +forget_cmd(unit * u, order * ord) +{ + skill_t sk; + const char *s; + + if (is_cursed(u->attribs, C_SLAVE, 0)) { + /* charmed units shouldn't be losing their skills */ + return 0; + } + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + if ((sk = findskill(s, u->faction->locale)) != NOSKILL) { + ADDMSG(&u->faction->msgs, + msg_message("forget", "unit skill", u, sk)); + set_level(u, sk, 0); + } + return 0; +} + +void +add_spende(faction * f1, faction * f2, int amount, region * r) +{ + donation *sp; + + sp = r->donations; + + while (sp) { + if (sp->f1 == f1 && sp->f2 == f2) { + sp->amount += amount; + return; + } + sp = sp->next; + } + + sp = calloc(1, sizeof(donation)); + sp->f1 = f1; + sp->f2 = f2; + sp->amount = amount; + sp->next = r->donations; + r->donations = sp; +} + +static boolean +maintain(building * b, boolean first) +/* first==false -> take money from wherever you can */ +{ + int c; + region * r = b->region; + boolean paid = true, work = first; + unit * u; + if (fval(b, BLD_MAINTAINED) || b->type==NULL || b->type->maintenance==NULL || is_cursed(b->attribs, C_NOCOST, 0)) { + fset(b, BLD_MAINTAINED); + fset(b, BLD_WORKING); + return true; + } + if (fval(b, BLD_DONTPAY)) { + return false; + } + u = building_owner(b); + if (u==NULL) return false; + for (c=0;b->type->maintenance[c].number;++c) { + const maintenance * m = b->type->maintenance+c; + int need = m->number; + + if (fval(m, MTF_VARIABLE)) need = need * b->size; + if (u) { + /* first ist im ersten versuch true, im zweiten aber false! Das + * bedeutet, das in der Runde in die Region geschafften Resourcen + * nicht genutzt werden können, weil die reserviert sind! */ + if (!first) need -= get_pooled(u, m->rtype, GET_ALL, need); + else need -= get_pooled(u, m->rtype, GET_DEFAULT, need); + if (!first && need > 0) { + unit * ua; + for (ua=r->units;ua;ua=ua->next) freset(ua->faction, FFL_SELECT); + fset(u->faction, FFL_SELECT); /* hat schon */ + for (ua=r->units;ua;ua=ua->next) { + if (!fval(ua->faction, FFL_SELECT) && (ua->faction == u->faction || alliedunit(ua, u->faction, HELP_MONEY))) { + need -= get_pooled(ua, m->rtype, GET_ALL, need); + fset(ua->faction, FFL_SELECT); + if (need<=0) break; + } + } + } + if (need > 0) { + if (!fval(m, MTF_VITAL)) work = false; + else { + paid = false; + break; + } + } + } + } + if (paid && c>0) { + /* TODO: wieviel von was wurde bezahlt */ + if (first) { + ADDMSG(&u->faction->msgs, msg_message("maintenance", "unit building", u, b)); + } else { + ADDMSG(&u->faction->msgs, msg_message("maintenance_late", "building", b)); + } + fset(b, BLD_MAINTAINED); + if (work) { + fset(b, BLD_WORKING); + } + for (c=0;b->type->maintenance[c].number;++c) { + const maintenance * m = b->type->maintenance+c; + int cost = m->number; + + if (!fval(m, MTF_VITAL) && !work) continue; + if (fval(m, MTF_VARIABLE)) cost = cost * b->size; + + if (!first) cost -= use_pooled(u, m->rtype, GET_ALL, cost); + else cost -= use_pooled(u, m->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, cost); + if (!first && cost > 0) { + unit * ua; + for (ua=r->units;ua;ua=ua->next) freset(ua->faction, FFL_SELECT); + fset(u->faction, FFL_SELECT); /* hat schon */ + for (ua=r->units;ua;ua=ua->next) { + if (!fval(ua->faction, FFL_SELECT) && alliedunit(ua, u->faction, HELP_MONEY)) { + int give = use_pooled(ua, m->rtype, GET_ALL, cost); + if (!give) continue; + cost -= give; + fset(ua->faction, FFL_SELECT); + if (m->rtype==r_silver) add_spende(ua->faction, u->faction, give, r); + if (cost<=0) break; + } + } + } + assert(cost==0); + } + } else { + ADDMSG(&u->faction->msgs, + msg_message("maintenancefail", "unit building", u, b)); + return false; + } + return true; +} + +#ifdef COLLAPSE_CHANCE +static void +gebaeude_stuerzt_ein(region * r, building * b) +{ + unit *u; + int n, i; + int opfer = 0; + int road = 0; + struct message * msg; + + for (u = r->units; u; u = u->next) { + if (u->building == b) { + int loss = 0; + + fset(u->faction, FFL_MARK); + freset(u, UFL_OWNER); + leave(r,u); + n = u->number; +#ifdef COLLAPSE_SURVIVAL + for (i = 0; i < n; i++) { + if (rng_double() >= COLLAPSE_SURVIVAL) { + ++loss; + } + } +#endif + scale_number(u, u->number - loss); + opfer += loss; + } + } + + msg = msg_message("buildingcrash", "region building opfer road", r, b, opfer, road); + add_message(&r->msgs, msg); + for (u=r->units; u; u=u->next) { + faction * f = u->faction; + if (fval(f, FFL_MARK)) { + freset(u->faction, FFL_MARK); + add_message(&f->msgs, msg); + } + } + msg_release(msg); + remove_building(&r->buildings, b); +} +#endif + +void +maintain_buildings(region * r, boolean crash) +{ + building **bp = &r->buildings; + while (*bp) { + building * b = *bp; + boolean maintained = maintain(b, !crash); + + /* the second time, send a message */ + if (crash) { +#ifdef COLLAPSE_CHANCE + if (!maintained && (rng_double() < COLLAPSE_CHANCE)) { + gebaeude_stuerzt_ein(r, b); + continue; + } +#endif + if (!fval(b, BLD_WORKING)) { + unit * u = building_owner(b); + const char * msgtype = maintained?"maintenance_nowork":"maintenance_none"; + struct message * msg = msg_message(msgtype, "building", b); + + if (u) { + add_message(&u->faction->msgs, msg); + r_addmessage(r, u->faction, msg); + } else { + add_message(&r->msgs, msg); + } + msg_release(msg); + } + } + bp=&b->next; + } +} + +static int +recruit_archetype(unit * u, order * ord) +{ + boolean merge = (u->number>0); + int want; + const char * s; + + if (rules_recruit<0) recruit_init(); + + init_tokens(ord); + skip_token(); + want = getuint(); + s = getstrtoken(); + if (want>0 && s && s[0]) { + int n = want; + const archetype * arch = find_archetype(s, u->faction->locale); + attrib * a = NULL; + + if ((rules_recruit&RECRUIT_MERGE)==0 && merge) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_must_be_new", "")); + /* TODO: error message */ + return 0; + } + + if (arch==NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unknown_archetype", "name", s)); + /* TODO: error message */ + return 0; + } + if (arch->rules) { + /* Simple allow/deny style restrictions for archetypes (let only humans + * recruit gamedesigners, etc). These need to be more powerful to be + * useful, and the current way they are implemented is not, but the + * general idea strikes me as good. Also, feedback should be configurable + * for each failed rule. + */ + int k; + for (k=0;arch->rules[k].property;++k) { + boolean match = false; + if (arch->rules[k].value[0]=='*') match = true; + else if (strcmp(arch->rules[k].property, "race")==0) { + const race * rc = rc_find(arch->rules[k].value); + assert(rc); + if (rc==u->race) match = true; + } else if (strcmp(arch->rules[k].property, "building")==0) { + const building_type * btype = bt_find(arch->rules[k].value); + assert(btype); + if (u->building && u->building->type==btype) match = true; + } + if (match) { + if (arch->rules[k].allow) break; + else { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "recruit_rule_fail", + "property value", arch->rules[k].property, arch->rules[k].value)); + /* TODO: error message */ + return 0; + } + } + } + } + if (arch->btype) { + if (u->building==NULL || u->building->type!=arch->btype) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_must_be_in_building", "type", arch->btype)); + /* TODO: error message */ + return 0; + } + if (arch->size) { + int maxsize = u->building->size; + attrib * a = a_find(u->building->attribs, &at_recruit); + if (a!=NULL) { + maxsize -= a->data.i; + } + n = MIN(maxsize/arch->size, n); + if (n<=0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "recruit_capacity_exhausted", "building", u->building)); + /* TODO: error message */ + return 0; + } + } + } + + n = build(u, arch->ctype, 0, n); + if (n>0) { + unit * u2; + if (merge) { + u2 = create_unit(u->region, u->faction, 0, u->race, 0, 0, u); + } else { + u2 = u; + } + if (arch->exec) { + n = arch->exec(u2, arch, n); + } + else { + set_number(u2, n); + equip_unit(u2, arch->equip); + u2->hp = n * unit_max_hp(u2); + if (arch->size) { + if (a==NULL) a = a_add(&u->building->attribs, a_new(&at_recruit)); + a->data.i += n*arch->size; + } + } + ADDMSG(&u->faction->msgs, msg_message("recruit_archetype", + "unit amount archetype", u, n, arch->name[n==1])); + if (u!=u2 && u->race==u2->race) { + transfermen(u2, u, u2->number); + } + return n; + } else switch(n) { + case ENOMATERIALS: + ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, arch->ctype, want)); + break; + case ELOWSKILL: + case ENEEDSKILL: + /* no skill, or not enough skill points to build */ + cmistake(u, ord, 50, MSG_PRODUCE); + break; + case EBUILDINGREQ: + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "building_needed", "building", arch->ctype->btype->_name)); + break; + default: + assert(!"unhandled return value from build() in recruit_archetype"); + } + return 0; + } + return -1; +} + +int recruit_archetypes(void) +{ + if (rules_recruit<0) recruit_init(); + return (rules_recruit&RECRUIT_ARCHETYPES)!=0; +} + +void +economics(region *r) +{ + unit *u; + request *recruitorders = NULL; + + /* Geben vor Selbstmord (doquit)! Hier alle unmittelbaren Befehle. + * Rekrutieren vor allen Einnahmequellen. Bewachen JA vor Steuern + * eintreiben. */ + + for (u = r->units; u; u = u->next) { + order * ord; + boolean destroyed = false; + if (u->number>0) { + for (ord = u->orders; ord; ord = ord->next) { + switch (get_keyword(ord)) { + case K_DESTROY: + if (!destroyed) { + if (destroy_cmd(u, ord)!=0) ord = NULL; + destroyed = true; + } + break; + + case K_GIVE: + case K_LIEFERE: + give_cmd(u, ord); + break; + + case K_FORGET: + forget_cmd(u, ord); + break; + + } + if (u->orders==NULL) break; + } + } + } + /* RECRUIT orders */ + + if (rules_recruit<0) recruit_init(); + for (u = r->units; u; u = u->next) { + order * ord; + + if ((rules_recruit&RECRUIT_MERGE) || u->number==0) { + for (ord = u->orders; ord; ord = ord->next) { + if (get_keyword(ord) == K_RECRUIT) { + if (rules_recruit&RECRUIT_ARCHETYPES) { + if (recruit_archetype(u, ord)>=0) { + continue; + } + } + if (rules_recruit&RECRUIT_CLASSIC) { + recruit(u, ord, &recruitorders); + } + break; + } + } + } + } + + if (recruitorders) expandrecruit(r, recruitorders); + remove_empty_units_in_region(r); +} +/* ------------------------------------------------------------- */ + + +static void +manufacture(unit * u, const item_type * itype, int want) +{ + int n; + int skill; + int minskill = itype->construction->minskill; + skill_t sk = itype->construction->skill; + + skill = effskill(u, sk); + skill = skillmod(itype->rtype->attribs, u, u->region, sk, skill, SMF_PRODUCTION); + + if (skill < 0) { + /* an error occured */ + int err = -skill; + cmistake(u, u->thisorder, err, MSG_PRODUCE); + return; + } + + if (want==0) { + want = maxbuild(u, itype->construction); + } + n = build(u, itype->construction, 0, want); + switch (n) { + case ENEEDSKILL: + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "skill_needed", "skill", sk)); + return; + case EBUILDINGREQ: + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "building_needed", "building", itype->construction->btype->_name)); + return; + case ELOWSKILL: + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "manufacture_skills", "skill minskill product", + sk, minskill, itype->rtype, 1)); + return; + case ENOMATERIALS: + ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, itype->construction, want)); + return; + } + if (n>0) { + i_change(&u->items, itype, n); + if (want==INT_MAX) want = n; + ADDMSG(&u->faction->msgs, msg_message("manufacture", + "unit region amount wanted resource", u, u->region, n, want, itype->rtype)); + } else { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_cannotmake", "")); + } +} + +typedef struct allocation { + struct allocation * next; + int want, get; + double save; + unsigned int flags; + unit * unit; +} allocation; +#define new_allocation() calloc(sizeof(allocation), 1) +#define free_allocation(a) free(a) + +typedef struct allocation_list { + struct allocation_list * next; + allocation * data; + const resource_type * type; +} allocation_list; + +static allocation_list * allocations; + +static boolean +can_guard(const unit * guard, const unit * u) +{ + if (fval(guard, UFL_ISNEW)) return false; + if (guard->number<=0 || !cansee(guard->faction, guard->region, u, 0)) return false; + if (besieged(guard) || !(fval(guard->race, RCF_UNARMEDGUARD) || armedmen(guard, true))) return false; + + return !alliedunit(guard, u->faction, HELP_GUARD); +} + +enum { + AFL_DONE = 1<<0, + AFL_LOWSKILL = 1<<1 +}; + +static void +allocate_resource(unit * u, const resource_type * rtype, int want) +{ + const item_type * itype = resource2item(rtype); + region * r = u->region; + int busy = u->number; + int dm = 0; + allocation_list * alist; + allocation * al; + attrib * a = a_find(rtype->attribs, &at_resourcelimit); + resource_limit * rdata = (resource_limit*)a->data.v; + int amount, skill; + + /* momentan kann man keine ressourcen abbauen, wenn man dafür + * Materialverbrauch hat: */ + assert(itype!=NULL && (itype->construction==NULL || itype->construction->materials==NULL)); + assert(rdata!=NULL); + + if (rdata->limit!=NULL) { + int avail = rdata->limit(r, rtype); + if (avail<=0) { + cmistake(u, u->thisorder, 121, MSG_PRODUCE); + return; + } + } + + if (besieged(u)) { + cmistake(u, u->thisorder, 60, MSG_PRODUCE); + return; + } + + if (rdata->modifiers) { + resource_mod * mod = rdata->modifiers; + for (;mod->flags!=0;++mod) { + if (mod->flags & RMF_REQUIREDBUILDING) { + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + if (mod->btype && mod->btype!=btype) { + cmistake(u, u->thisorder, 104, MSG_PRODUCE); + return; + } + } + } + } + + if (rdata->guard!=0) { + unit * u2; + for (u2 = r->units; u2; u2 = u2->next) { + if (is_guard(u2, rdata->guard)!=0 && can_guard(u2, u)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "region_guarded", "guard", u2)); + return; + } + } + } + + /* Bergwächter können Abbau von Eisen/Laen durch Bewachen verhindern. + * Als magische Wesen 'sehen' Bergwächter alles und werden durch + * Belagerung nicht aufgehalten. (Ansonsten wie oben bei Elfen anpassen). + */ + if (itype == olditemtype[I_IRON] || itype == olditemtype[I_LAEN]) { + unit * u2; + for (u2 = r->units; u2; u2 = u2->next ) { + if (is_guard(u, GUARD_MINING) + && !fval(u2, UFL_ISNEW) + && u2->number + && !alliedunit(u2, u->faction, HELP_GUARD)) + { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "region_guarded", "guard", u2)); + return; + } + } + } + + assert(itype->construction->skill!=0 || "limited resource needs a required skill for making it"); + skill = eff_skill(u, itype->construction->skill, u->region); + if (skill == 0) { + skill_t sk = itype->construction->skill; + add_message(&u->faction->msgs, + msg_feedback(u, u->thisorder, "skill_needed", "skill", sk)); + return; + } + if (skill < itype->construction->minskill) { + skill_t sk = itype->construction->skill; + add_message(&u->faction->msgs, + msg_feedback(u, u->thisorder, "manufacture_skills", "skill minskill product", + sk, itype->construction->minskill, itype->rtype)); + return; + } else { + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + + if (rdata->modifiers) { + resource_mod * mod = rdata->modifiers; + for (;mod->flags!=0;++mod) { + if (mod->flags & RMF_SKILL) { + if (mod->btype==NULL || mod->btype==btype) { + if (mod->race==NULL || mod->race==u->race) { + skill += mod->value.i; + } + } + } + } + } + } + amount = skill * u->number; + /* nun ist amount die Gesamtproduktion der Einheit (in punkten) */ + + /* mit Flinkfingerring verzehnfacht sich die Produktion */ + amount += skill * MIN(u->number, get_item(u, I_RING_OF_NIMBLEFINGER)) * (roqf_factor()-1); + + /* Schaffenstrunk: */ + if ((dm = get_effect(u, oldpotiontype[P_DOMORE])) != 0) { + dm = MIN(dm, u->number); + change_effect(u, oldpotiontype[P_DOMORE], -dm); + amount += dm * skill; /* dm Personen produzieren doppelt */ + } + + amount /= itype->construction->minskill; + + /* Limitierung durch Parameter m. */ + if (want > 0 && want < amount) amount = want; + + busy = (amount + skill - 1) / skill; /* wieviel leute tun etwas? */ + + alist = allocations; + while (alist && alist->type!=rtype) alist = alist->next; + if (!alist) { + alist = calloc(sizeof(struct allocation_list), 1); + alist->next = allocations; + alist->type = rtype; + allocations = alist; + } + al = new_allocation(); + al->want = amount; + al->save = 1.0; + al->next = alist->data; + al->unit = u; + alist->data = al; + + if (rdata->modifiers) { + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + + resource_mod * mod = rdata->modifiers; + for (;mod->flags!=0;++mod) { + if (mod->flags & RMF_SAVEMATERIAL) { + if (mod->btype==NULL || mod->btype==btype) { + if (mod->race==NULL || mod->race==u->race) { + al->save *= mod->value.f; + } + } + } + } + } +} + +static int +required(int want, double save) +{ + int norders = (int)(want * save); + if (norders < want*save) ++norders; + return norders; +} + +static void +leveled_allocation(const resource_type * rtype, region * r, allocation * alist) +{ + const item_type * itype = resource2item(rtype); + rawmaterial * rm = rm_get(r, rtype); + int need; + boolean first = true; + + if (rm!=NULL) { + do { + int avail = rm->amount; + int norders = 0; + allocation * al; + + if(avail <= 0) { + for (al=alist;al;al=al->next) { + al->get = 0; + } + break; + } + + assert(avail>0); + + for (al=alist;al;al=al->next) if (!fval(al, AFL_DONE)) { + int req = required(al->want-al->get, al->save); + assert(al->get<=al->want && al->get >= 0); + if (eff_skill(al->unit, itype->construction->skill, r) + >= rm->level+itype->construction->minskill-1) { + if (req) { + norders += req; + } else { + fset(al, AFL_DONE); + } + } else { + fset(al, AFL_DONE); + if (first) fset(al, AFL_LOWSKILL); + } + } + need = norders; + + avail = MIN(avail, norders); + if (need>0) { + int use = 0; + for (al=alist;al;al=al->next) if (!fval(al, AFL_DONE)) { + if (avail > 0) { + int want = required(al->want-al->get, al->save); + int x = avail*want/norders; + /* Wenn Rest, dann würfeln, ob ich was bekomme: */ + if (rng_int() % norders < (avail*want) % norders) + ++x; + avail -= x; + use += x; + norders -= want; + need -= x; + al->get = MIN(al->want, al->get+(int)(x/al->save)); + } + } + if (use) { + assert(use<=rm->amount); + rm->type->use(rm, r, use); + } + assert(avail==0 || norders==0); + } + first = false; + } while (need>0); + } +} + +static void +attrib_allocation(const resource_type * rtype, region * r, allocation * alist) +{ + allocation * al; + int norders = 0; + attrib * a = a_find(rtype->attribs, &at_resourcelimit); + resource_limit * rdata = (resource_limit*)a->data.v; + int avail = rdata->value; + + for (al=alist;al;al=al->next) { + norders += required(al->want, al->save); + } + + if (rdata->limit) { + avail = rdata->limit(r, rtype); + if (avail < 0) avail = 0; + } + + avail = MIN(avail, norders); + for (al=alist;al;al=al->next) { + if (avail > 0) { + int want = required(al->want, al->save); + int x = avail*want/norders; + /* Wenn Rest, dann würfeln, ob ich was bekomme: */ + if (rng_int() % norders < (avail*want) % norders) + ++x; + avail -= x; + norders -= want; + al->get = MIN(al->want, (int)(x/al->save)); + if (rdata->produce) { + int use = required(al->get, al->save); + if (use) rdata->produce(r, rtype, use); + } + } + } + assert(avail==0 || norders==0); +} + +typedef void (*allocate_function)(const resource_type *, struct region *, struct allocation *); + +static allocate_function +get_allocator(const struct resource_type * rtype) +{ + attrib * a = a_find(rtype->attribs, &at_resourcelimit); + + if (a!=NULL) { + resource_limit * rdata = (resource_limit*)a->data.v; + if (rdata->value>0 || rdata->limit!=NULL) { + return attrib_allocation; + } + return leveled_allocation; + } + return NULL; +} + +void +split_allocations(region * r) +{ + allocation_list ** p_alist=&allocations; + freset(r, RF_SELECT); + while (*p_alist) { + allocation_list * alist = *p_alist; + const resource_type * rtype = alist->type; + allocate_function alloc = get_allocator(rtype); + const item_type * itype = resource2item(rtype); + allocation ** p_al = &alist->data; + + freset(r, RF_SELECT); + alloc(rtype, r, alist->data); + + while (*p_al) { + allocation * al = *p_al; + if (al->get) { + assert(itype || !"not implemented for non-items"); + i_change(&al->unit->items, itype, al->get); + produceexp(al->unit, itype->construction->skill, al->unit->number); + fset(r, RF_SELECT); + } + if (al->want==INT_MAX) al->want = al->get; + if (fval(al, AFL_LOWSKILL)) { + ADDMSG(&al->unit->faction->msgs, + msg_message("produce_lowskill", "unit region resource", + al->unit, al->unit->region, rtype)); + } else { + ADDMSG(&al->unit->faction->msgs, msg_message("produce", + "unit region amount wanted resource", + al->unit, al->unit->region, al->get, al->want, rtype)); + } + *p_al=al->next; + free_allocation(al); + } + *p_alist=alist->next; + free(alist); + } + allocations = NULL; +} + +static void +create_potion(unit * u, const potion_type * ptype, int want) +{ + int built; + + if (want==0) { + want = maxbuild(u, ptype->itype->construction); + } + built = build(u, ptype->itype->construction, 0, want); + switch (built) { + case ELOWSKILL: + case ENEEDSKILL: + /* no skill, or not enough skill points to build */ + cmistake(u, u->thisorder, 50, MSG_PRODUCE); + break; + case EBUILDINGREQ: + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "building_needed", "building", ptype->itype->construction->btype->_name)); + break; + case ECOMPLETE: + assert(0); + break; + case ENOMATERIALS: + /* something missing from the list of materials */ + ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, ptype->itype->construction, want)); + return; + break; + default: + i_change(&u->items, ptype->itype, built); + if (want==INT_MAX) want = built; + ADDMSG(&u->faction->msgs, msg_message("manufacture", + "unit region amount wanted resource", u, u->region, built, want, ptype->itype->rtype)); + break; + } +} + +static void +create_item(unit * u, const item_type * itype, int want) +{ + if (itype->construction && fval(itype->rtype, RTF_LIMITED)) { +#if GUARD_DISABLES_PRODUCTION == 1 + if (is_guarded(u->region, u, GUARD_PRODUCE)) { + cmistake(u, u->thisorder, 70, MSG_EVENT); + return; + } +#endif + allocate_resource(u, itype->rtype, want); + } else { + const potion_type * ptype = resource2potion(itype->rtype); + if (ptype!=NULL) create_potion(u, ptype, want); + else if (itype->construction && itype->construction->materials) manufacture(u, itype, want); + else { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_cannotmake", "")); + } + } +} + +int +make_cmd(unit * u, struct order * ord) +{ + region * r = u->region; + const building_type * btype; + const ship_type * stype; + param_t p; + int m; + const item_type * itype; + const char *s; + const struct locale * lang = u->faction->locale; + char ibuf[16]; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + m = atoi((const char *)s); + sprintf(ibuf, "%d", m); + if (!strcmp(ibuf, (const char *)s)) { + /* first came a want-paramter */ + s = getstrtoken(); + } else { + m = INT_MAX; + } + + p = findparam(s, u->faction->locale); + + /* MACHE TEMP kann hier schon gar nicht auftauchen, weil diese nicht in + * thisorder abgespeichert werden - und auf den ist getstrtoken() beim + * aufruf von make geeicht */ + + if (p == P_ROAD) { + plane * pl = rplane(r); + if (pl && fval(pl, PFL_NOBUILD)) { + cmistake(u, ord, 275, MSG_PRODUCE); + } else { + direction_t d = finddirection(getstrtoken(), u->faction->locale); + if (d!=NODIRECTION) { + build_road(r, u, m, d); + } else { + /* Die Richtung wurde nicht erkannt */ + cmistake(u, ord, 71, MSG_PRODUCE); + } + } + return 0; + } else if (p == P_SHIP) { + plane * pl = rplane(r); + if (pl && fval(pl, PFL_NOBUILD)) { + cmistake(u, ord, 276, MSG_PRODUCE); + } else { + continue_ship(r, u, m); + } + return 0; + } else if (p == P_HERBS) { + herbsearch(r, u, m); + return 0; + } + + /* since the string can match several objects, like in 'academy' and + * 'academy of arts', we need to figure out what the player meant. + * This is not 100% safe. + */ + stype = findshiptype(s, lang); + btype = findbuildingtype(s, lang); + itype = finditemtype(s, lang); + + if (itype!=NULL && (btype!=NULL || stype!=NULL)) { + if (itype->construction==NULL) { + /* if the item cannot be made, we probably didn't mean to make it */ + itype = NULL; + } else if (stype!=NULL) { + const char * sname = LOC(lang, stype->name[0]); + const char * iname = LOC(lang, resourcename(itype->rtype, 0)); + if (strlen(iname)_name); + const char * iname = LOC(lang, resourcename(itype->rtype, 0)); + if (strlen(iname)_name); + const char * sname = LOC(lang, stype->name[0]); + if (strlen(sname)faction->msgs, msg_feedback(u, ord, "error_cannotmake", "")); + } + + return 0; +} +/* ------------------------------------------------------------- */ + +static void +free_luxuries(struct attrib * a) +{ + item * itm = (item*)a->data.v; + a->data.v = NULL; + i_freeall(&itm); +} + +const attrib_type at_luxuries = { + "luxuries", NULL, free_luxuries, NULL, NULL, NULL +}; + +static void +expandbuying(region * r, request * buyorders) +{ + int max_products; + unit *u; + static struct trade { + const luxury_type * type; + int number; + int multi; + } *trades, *trade; + static int ntrades=0; + int i, j; + const luxury_type * ltype; + + if (ntrades==0) { + for (ltype=luxurytypes;ltype;ltype=ltype->next) + ++ntrades; + trades = gc_add(calloc(sizeof(struct trade), ntrades)); + for (i=0, ltype=luxurytypes;i!=ntrades;++i, ltype=ltype->next) + trades[i].type = ltype; + } + for (i=0;i!=ntrades;++i) { + trades[i].number = 0; + trades[i].multi = 1; + } + + if (!buyorders) return; + + /* Initialisation. multiplier ist der Multiplikator auf den + * Verkaufspreis. Für max_products Produkte kauft man das Produkt zum + * einfachen Verkaufspreis, danach erhöht sich der Multiplikator um 1. + * counter ist ein Zähler, der die gekauften Produkte zählt. money + * wird für die debug message gebraucht. */ + + max_products = rpeasants(r) / TRADE_FRACTION; + + /* Kauf - auch so programmiert, daß er leicht erweiterbar auf mehrere + * Güter pro Monat ist. j sind die Befehle, i der Index des + * gehandelten Produktes. */ + if (max_products>0) { + expandorders(r, buyorders); + if (!norders) return; + + for (j = 0; j != norders; j++) { + int price, multi; + ltype = oa[j].type.ltype; + trade = trades; + while (trade->type!=ltype) ++trade; + multi = trade->multi; + price = ltype->price * multi; + + if (get_pooled(oa[j].unit, oldresourcetype[R_SILVER], GET_DEFAULT, price) >= price) { + unit * u = oa[j].unit; + item * items; + + /* litems zählt die Güter, die verkauft wurden, u->n das Geld, das + * verdient wurde. Dies muß gemacht werden, weil der Preis ständig sinkt, + * man sich also das verdiente Geld und die verkauften Produkte separat + * merken muß. */ + attrib * a = a_find(u->attribs, &at_luxuries); + if (a==NULL) a = a_add(&u->attribs, a_new(&at_luxuries)); + + items = a->data.v; + i_change(&items, ltype->itype, 1); + a->data.v = items; + i_change(&oa[j].unit->items, ltype->itype, 1); + use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, price); + if (u->n < 0) + u->n = 0; + u->n += price; + + rsetmoney(r, rmoney(r) + price); + + /* Falls mehr als max_products Bauern ein Produkt verkauft haben, steigt + * der Preis Multiplikator für das Produkt um den Faktor 1. Der Zähler + * wird wieder auf 0 gesetzt. */ + if (++trade->number == max_products) { + trade->number = 0; + ++trade->multi; + } + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + } + } + free(oa); + + /* Ausgabe an Einheiten */ + + for (u = r->units; u; u = u->next) { + attrib * a = a_find(u->attribs, &at_luxuries); + item * itm; + if (a==NULL) continue; + ADDMSG(&u->faction->msgs, msg_message("buy", "unit money", u, u->n)); + for (itm=(item*)a->data.v; itm; itm=itm->next) { + if (itm->number) { + ADDMSG(&u->faction->msgs, msg_message("buyamount", + "unit amount resource", u, itm->number, itm->type->rtype)); + } + } + a_remove(&u->attribs, a); + } + } +} + +attrib_type at_trades = { + "trades", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +static void +buy(unit * u, request ** buyorders, struct order * ord) +{ + region * r = u->region; + int n, k; + request *o; + attrib * a; + const item_type * itype = NULL; + const luxury_type * ltype = NULL; + if (u->ship && is_guarded(r, u, GUARD_CREWS)) { + cmistake(u, ord, 69, MSG_INCOME); + return; + } + if (u->ship && is_guarded(r, u, GUARD_CREWS)) { + cmistake(u, ord, 69, MSG_INCOME); + return; + } + /* Im Augenblick kann man nur 1 Produkt kaufen. expandbuying ist aber + * schon dafür ausgerüstet, mehrere Produkte zu kaufen. */ + + init_tokens(ord); + skip_token(); + n = getuint(); + if (!n) { + cmistake(u, ord, 26, MSG_COMMERCE); + return; + } + if (besieged(u)) { + /* Belagerte Einheiten können nichts kaufen. */ + cmistake(u, ord, 60, MSG_COMMERCE); + return; + } + + if (u->race == new_race[RC_INSECT]) { + /* entweder man ist insekt, oder... */ + if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT) && !rbuildings(r)) { + cmistake(u, ord, 119, MSG_COMMERCE); + return; + } + } else { + /* ...oder in der Region muß es eine Burg geben. */ + building * b; + static const struct building_type * bt_castle; + if (!bt_castle) bt_castle = bt_find("castle"); + for (b=r->buildings;b;b=b->next) { + if (b->type==bt_castle && b->size>=2) break; + } + if (b==NULL) { + cmistake(u, ord, 119, MSG_COMMERCE); + return; + } + } + + /* Ein Händler kann nur 10 Güter pro Talentpunkt handeln. */ + k = u->number * 10 * eff_skill(u, SK_TRADE, r); + + /* hat der Händler bereits gehandelt, muss die Menge der bereits + * verkauften/gekauften Güter abgezogen werden */ + a = a_find(u->attribs, &at_trades); + if (!a) { + a = a_add(&u->attribs, a_new(&at_trades)); + } else { + k -= a->data.i; + } + + n = MIN(n, k); + + if (!n) { + cmistake(u, ord, 102, MSG_COMMERCE); + return; + } + + assert(n>=0); + /* die Menge der verkauften Güter merken */ + a->data.i += n; + + itype = finditemtype(getstrtoken(), u->faction->locale); + if (itype!=NULL) { + ltype = resource2luxury(itype->rtype); + if (ltype==NULL) { + cmistake(u, ord, 124, MSG_COMMERCE); + return; + } + } + if (r_demand(r, ltype)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "luxury_notsold", "")); + return; + } + o = (request *) calloc(1, sizeof(request)); + o->type.ltype = ltype; /* sollte immer gleich sein */ + + o->unit = u; + o->qty = n; + addlist(buyorders, o); +} +/* ------------------------------------------------------------- */ + +/* Steuersätze in % bei Burggröße */ +static int tax_per_size[7] = +{0, 6, 12, 18, 24, 30, 36}; + +static void +expandselling(region * r, request * sellorders, int limit) +{ + int money, price, j, max_products; + /* int m, n = 0; */ + int maxsize = 0, maxeffsize = 0; + int taxcollected = 0; + int hafencollected = 0; + unit *maxowner = (unit *) NULL; + building *maxb = (building *) NULL; + building *b; + unit *u; + unit *hafenowner; + static int *counter; + static int ncounter = 0; + + if (ncounter==0) { + const luxury_type * ltype; + for (ltype=luxurytypes;ltype;ltype=ltype->next) ++ncounter; + counter=(int*)gc_add(calloc(sizeof(int), ncounter)); + } else { + memset(counter, 0, sizeof(int)*ncounter); + } + + if (!sellorders) { /* NEIN, denn Insekten können in || !r->buildings) */ + return; /* Sümpfen und Wüsten auch so handeln */ + } + /* Stelle Eigentümer der größten Burg fest. Bekommt Steuern aus jedem + * Verkauf. Wenn zwei Burgen gleicher Größe bekommt gar keiner etwas. */ + + for (b = rbuildings(r); b; b = b->next) { + if (b->size > maxsize && building_owner(b) != NULL + && b->type == bt_find("castle")) { + maxb = b; + maxsize = b->size; + maxowner = building_owner(b); + } else if (b->size == maxsize && b->type == bt_find("castle")) { + maxb = (building *) NULL; + maxowner = (unit *) NULL; + } + } + + hafenowner = owner_buildingtyp(r, bt_find("harbour")); + + if (maxb != (building *) NULL && maxowner != (unit *) NULL) { + maxeffsize = buildingeffsize(maxb, false); + if (maxeffsize == 0) { + maxb = (building *) NULL; + maxowner = (unit *) NULL; + } + } + /* Die Region muss genug Geld haben, um die Produkte kaufen zu können. */ + + money = rmoney(r); + + /* max_products sind 1/100 der Bevölkerung, falls soviele Produkte + * verkauft werden - counter[] - sinkt die Nachfrage um 1 Punkt. + * multiplier speichert r->demand für die debug message ab. */ + + max_products = rpeasants(r) / TRADE_FRACTION; + if (max_products <= 0) return; + + if (r->terrain == newterrain(T_DESERT) && buildingtype_exists(r, bt_find("caravan"), true)) { + max_products = rpeasants(r) * 2 / TRADE_FRACTION; + } + /* Verkauf: so programmiert, dass er leicht auf mehrere Gueter pro + * Runde erweitert werden kann. */ + + expandorders(r, sellorders); + if (!norders) return; + + for (j = 0; j != norders; j++) { + static const luxury_type * search=NULL; + const luxury_type * ltype = oa[j].type.ltype; + int multi = r_demand(r, ltype); + static int i=-1; + int use = 0; + if (search!=ltype) { + i=0; + for (search=luxurytypes;search!=ltype;search=search->next) ++i; + } + if (counter[i]>=limit) continue; + if (counter[i]+1 > max_products && multi > 1) --multi; + price = ltype->price * multi; + + if (money >= price) { + int abgezogenhafen = 0; + int abgezogensteuer = 0; + unit * u = oa[j].unit; + item * itm; + attrib * a = a_find(u->attribs, &at_luxuries); + if (a==NULL) a = a_add(&u->attribs, a_new(&at_luxuries)); + itm = (item *)a->data.v; + i_change(&itm, ltype->itype, 1); + a->data.v = itm; + ++use; + if (u->n < 0) + u->n = 0; + + if (hafenowner != NULL) { + if (hafenowner->faction != u->faction) { + abgezogenhafen = price / 10; + hafencollected += abgezogenhafen; + price -= abgezogenhafen; + money -= abgezogenhafen; + } + } + if (maxb != NULL) { + if (maxowner->faction != u->faction) { + abgezogensteuer = price * tax_per_size[maxeffsize] / 100; + taxcollected += abgezogensteuer; + price -= abgezogensteuer; + money -= abgezogensteuer; + } + } + u->n += price; + change_money(u, price); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + + /* r->money -= price; --- dies wird eben nicht ausgeführt, denn die + * Produkte können auch als Steuern eingetrieben werden. In der Region + * wurden Silberstücke gegen Luxusgüter des selben Wertes eingetauscht! + * Falls mehr als max_products Kunden ein Produkt gekauft haben, sinkt + * die Nachfrage für das Produkt um 1. Der Zähler wird wieder auf 0 + * gesetzt. */ + + if (++counter[i] > max_products) { + int d = r_demand(r, ltype); + if (d > 1) { + r_setdemand(r, ltype, d-1); + } + counter[i] = 0; + } + } + if (use>0) { +#ifdef NDEBUG + use_pooled(oa[j].unit, ltype->itype->rtype, GET_DEFAULT, use); +#else + /* int i = */ use_pooled(oa[j].unit, ltype->itype->rtype, GET_DEFAULT, use); + /* assert(i==use); */ +#endif + } + } + free(oa); + + /* Steuern. Hier werden die Steuern dem Besitzer der größten Burg gegeben. */ + + if (maxowner) { + if (taxcollected > 0) { + change_money(maxowner, (int) taxcollected); + add_income(maxowner, IC_TRADETAX, taxcollected, taxcollected); + /* TODO: Meldung + * "%s verdient %d Silber durch den Handel in %s.", + * unitname(maxowner), (int) taxcollected, regionname(r)); */ + } + } + if (hafenowner) { + if (hafencollected > 0) { + change_money(hafenowner, (int) hafencollected); + add_income(hafenowner, IC_TRADETAX, hafencollected, hafencollected); + } + } + /* Berichte an die Einheiten */ + + for (u = r->units; u; u = u->next) { + + attrib * a = a_find(u->attribs, &at_luxuries); + item * itm; + if (a==NULL) continue; + for (itm=(item*)a->data.v; itm; itm=itm->next) { + if (itm->number) { + ADDMSG(&u->faction->msgs, msg_message("sellamount", + "unit amount resource", u, itm->number, itm->type->rtype)); + } + } + a_remove(&u->attribs, a); + add_income(u, IC_TRADE, u->n, u->n); + } +} + +static boolean + sell(unit * u, request ** sellorders, struct order * ord) +{ + boolean unlimited = true; + const item_type * itype; + const luxury_type * ltype=NULL; + int n; + region * r = u->region; + const char *s; + + if (u->ship && is_guarded(r, u, GUARD_CREWS)) { + cmistake(u, ord, 69, MSG_INCOME); + return false; + } + /* sellorders sind KEIN array, weil für alle items DIE SELBE resource + * (das geld der region) aufgebraucht wird. */ + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + if (findparam(s, u->faction->locale) == P_ANY) { + unlimited = false; + n = rpeasants(r) / TRADE_FRACTION; + if (r->terrain == newterrain(T_DESERT) && buildingtype_exists(r, bt_find("caravan"), true)) + n *= 2; + if (n==0) { + cmistake(u, ord, 303, MSG_COMMERCE); + return false; + } + } else { + n = atoi((const char *)s); + if (n==0) { + cmistake(u, ord, 27, MSG_COMMERCE); + return false; + } + } + /* Belagerte Einheiten können nichts verkaufen. */ + + if (besieged(u)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "error60", "")); + return false; + } + /* In der Region muß es eine Burg geben. */ + + if (u->race == new_race[RC_INSECT]) { + if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT) && !rbuildings(r)) { + cmistake(u, ord, 119, MSG_COMMERCE); + return false; + } + } else { + /* ...oder in der Region muß es eine Burg geben. */ + building * b; + static const struct building_type * bt_castle; + if (!bt_castle) bt_castle = bt_find("castle"); + for (b=r->buildings;b;b=b->next) { + if (b->type==bt_castle && b->size>=2) break; + } + if (b==NULL) { + cmistake(u, ord, 119, MSG_COMMERCE); + return false; + } + } + + /* Ein Händler kann nur 10 Güter pro Talentpunkt verkaufen. */ + + n = MIN(n, u->number * 10 * eff_skill(u, SK_TRADE, r)); + + if (!n) { + cmistake(u, ord, 54, MSG_COMMERCE); + return false; + } + s=getstrtoken(); + itype = finditemtype(s, u->faction->locale); + if (itype!=NULL) ltype = resource2luxury(itype->rtype); + if (ltype==NULL) { + cmistake(u, ord, 126, MSG_COMMERCE); + return false; + } + else { + attrib * a; + request *o; + int k, available; + + if (!r_demand(r, ltype)) { + cmistake(u, ord, 263, MSG_COMMERCE); + return false; + } + available = get_pooled(u, itype->rtype, GET_DEFAULT, INT_MAX); + + /* Wenn andere Einheiten das selbe verkaufen, muß ihr Zeug abgezogen + * werden damit es nicht zweimal verkauft wird: */ + for (o=*sellorders;o;o=o->next) { + if (o->type.ltype==ltype && o->unit->faction == u->faction) { + int fpool = o->qty - get_pooled(o->unit, itype->rtype, GET_RESERVE, INT_MAX); + available -= MAX(0, fpool); + } + } + + n = MIN(n, available); + + if (n <= 0) { + cmistake(u, ord, 264, MSG_COMMERCE); + return false; + } + /* Hier wird request->type verwendet, weil die obere limit durch + * das silber gegeben wird (region->money), welches für alle + * (!) produkte als summe gilt, als nicht wie bei der + * produktion, wo für jedes produkt einzeln eine obere limite + * existiert, so dass man arrays von orders machen kann. */ + + /* Ein Händler kann nur 10 Güter pro Talentpunkt handeln. */ + k = u->number * 10 * eff_skill(u, SK_TRADE, r); + + /* hat der Händler bereits gehandelt, muss die Menge der bereits + * verkauften/gekauften Güter abgezogen werden */ + a = a_find(u->attribs, &at_trades); + if (!a) { + a = a_add(&u->attribs, a_new(&at_trades)); + } else { + k -= a->data.i; + } + + n = MIN(n, k); + assert(n>=0); + /* die Menge der verkauften Güter merken */ + a->data.i += n; + o = (request *) calloc(1, sizeof(request)); + o->unit = u; + o->qty = n; + o->type.ltype = ltype; + addlist(sellorders, o); + + return unlimited; + } +} +/* ------------------------------------------------------------- */ + +static void +expandstealing(region * r, request * stealorders) +{ + int i; + + expandorders(r, stealorders); + if (!norders) return; + + /* Für jede unit in der Region wird Geld geklaut, wenn sie Opfer eines + * Beklauen-Orders ist. Jedes Opfer muß einzeln behandelt werden. + * + * u ist die beklaute unit. oa.unit ist die klauende unit. + */ + + for (i = 0; i != norders && oa[i].unit->n <= oa[i].unit->wants; i++) { + unit *u = findunitg(oa[i].no, r); + int n = 0; + if (u && u->region==r) { + n = get_pooled(u, r_silver, GET_ALL, INT_MAX); + } +#ifndef GOBLINKILL + if (oa[i].type.goblin) { /* Goblin-Spezialklau */ + int uct = 0; + unit *u2; + assert(effskill(oa[i].unit, SK_STEALTH)>=4 || !"this goblin\'s skill is too low"); + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->faction == u->faction) { + uct += maintenance_cost(u2); + } + } + n -= uct * 2; + } +#endif + if (n>10 && rplane(r) && (rplane(r)->flags & PFL_NOALLIANCES)) { + /* In Questen nur reduziertes Klauen */ + n = 10; + } + if (n > 0) { + n = MIN(n, oa[i].unit->wants); + use_pooled(u, r_silver, GET_ALL, n); + oa[i].unit->n = n; + change_money(oa[i].unit, n); + ADDMSG(&u->faction->msgs, msg_message("stealeffect", "unit region amount", u, u->region, n)); + } + add_income(oa[i].unit, IC_STEAL, oa[i].unit->wants, oa[i].unit->n); + fset(oa[i].unit, UFL_LONGACTION|UFL_NOTMOVING); + } + free(oa); +} + +/* ------------------------------------------------------------- */ +static void +plant(region *r, unit *u, int raw) +{ + int n, i, skill, planted = 0; + const item_type * itype; + static const resource_type * rt_water = NULL; + if (rt_water==NULL) rt_water = rt_find("p2"); + + assert(rt_water!=NULL); + if (!fval(r->terrain, LAND_REGION)) { + return; + } + if (rherbtype(r) == NULL) { + cmistake(u, u->thisorder, 108, MSG_PRODUCE); + return; + } + + /* Skill prüfen */ + skill = eff_skill(u, SK_HERBALISM, r); + itype = rherbtype(r); + if (skill < 6) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "plant_skills", + "skill minskill product", SK_HERBALISM, 6, itype->rtype, 1)); + return; + } + /* Wasser des Lebens prüfen */ + if (get_pooled(u, rt_water, GET_DEFAULT, 1) == 0) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "resource_missing", "missing", rt_water)); + return; + } + n = get_pooled(u, itype->rtype, GET_DEFAULT, skill*u->number); + /* Kräuter prüfen */ + if (n==0) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "resource_missing", "missing", + itype->rtype)); + return; + } + + n = MIN(skill*u->number, n); + n = MIN(raw, n); + /* Für jedes Kraut Talent*10% Erfolgschance. */ + for(i = n; i>0; i--) { + if (rng_int()%10 < skill) planted++; + } + produceexp(u, SK_HERBALISM, u->number); + + /* Alles ok. Abziehen. */ + use_pooled(u, rt_water, GET_DEFAULT, 1); + use_pooled(u, itype->rtype, GET_DEFAULT, n); + rsetherbs(r, rherbs(r)+planted); + ADDMSG(&u->faction->msgs, msg_message("plant", "unit region amount herb", + u, r, planted, itype->rtype)); +} + +static void +planttrees(region *r, unit *u, int raw) +{ + int n, i, skill, planted = 0; + const resource_type * rtype; + + if (!fval(r->terrain, LAND_REGION)) { + return; + } + + /* Mallornbäume kann man nur in Mallornregionen züchten */ + if (fval(r, RF_MALLORN)) { + rtype = rt_mallornseed; + } else { + rtype = rt_seed; + } + + /* Skill prüfen */ + skill = eff_skill(u, SK_HERBALISM, r); + if (skill < 6) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "plant_skills", + "skill minskill product", SK_HERBALISM, 6, rtype, 1)); + return; + } + if (fval(r, RF_MALLORN) && skill < 7 ) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "plant_skills", + "skill minskill product", SK_HERBALISM, 7, rtype, 1)); + return; + } + + /* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */ + raw = MIN(raw, skill*u->number); + n = get_pooled(u, rtype, GET_DEFAULT, raw); + if (n==0) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype)); + return; + } + n = MIN(raw, n); + + /* Für jeden Samen Talent*10% Erfolgschance. */ + for(i = n; i>0; i--) { + if (rng_int()%10 < skill) planted++; + } + rsettrees(r, 0, rtrees(r, 0)+planted); + + /* Alles ok. Abziehen. */ + produceexp(u, SK_HERBALISM, u->number); + use_pooled(u, rtype, GET_DEFAULT, n); + + ADDMSG(&u->faction->msgs, msg_message("plant", + "unit region amount herb", u, r, planted, rtype)); +} + +/* züchte bäume */ +static void +breedtrees(region *r, unit *u, int raw) +{ + int n, i, skill, planted = 0; + const resource_type * rtype; + static int gamecookie = -1; + static int current_season; + + if (gamecookie!=global.cookie) { + gamedate date; + get_gamedate(turn, &date); + current_season = date.season; + gamecookie = global.cookie; + } + + /* Bäume züchten geht nur im Frühling */ + if (current_season != SEASON_SPRING){ + planttrees(r, u, raw); + return; + } + + if (!fval(r->terrain, LAND_REGION)) { + return; + } + + /* Mallornbäume kann man nur in Mallornregionen züchten */ + if (fval(r, RF_MALLORN)) { + rtype = rt_mallornseed; + } else { + rtype = rt_seed; + } + + /* Skill prüfen */ + skill = eff_skill(u, SK_HERBALISM, r); + if (skill < 12) { + planttrees(r, u, raw); + return; + } + + /* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */ + raw = MIN(skill*u->number, raw); + n = get_pooled(u, rtype, GET_DEFAULT, raw); + /* Samen prüfen */ + if (n==0) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype)); + return; + } + n = MIN(raw, n); + + /* Für jeden Samen Talent*5% Erfolgschance. */ + for(i = n; i>0; i--) { + if (rng_int()%100 < skill*5) planted++; + } + rsettrees(r, 1, rtrees(r, 1)+planted); + + /* Alles ok. Abziehen. */ + produceexp(u, SK_HERBALISM, u->number); + use_pooled(u, rtype, GET_DEFAULT, n); + + ADDMSG(&u->faction->msgs, msg_message("plant", + "unit region amount herb", u, r, planted, rtype)); +} + +/* züchte pferde */ +static void +breedhorses(region *r, unit *u) +{ + int n, c; + int gezuechtet = 0; + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + + if (btype!=bt_find("stables")) { + cmistake(u, u->thisorder, 122, MSG_PRODUCE); + return; + } + if (get_item(u, I_HORSE) < 2) { + cmistake(u, u->thisorder, 107, MSG_PRODUCE); + return; + } + n = MIN(u->number * eff_skill(u, SK_HORSE_TRAINING, r), get_item(u, I_HORSE)); + + for (c = 0; c < n; c++) { + if (rng_int() % 100 < eff_skill(u, SK_HORSE_TRAINING, r)) { + i_change(&u->items, olditemtype[I_HORSE], 1); + gezuechtet++; + } + } + + produceexp(u, SK_HORSE_TRAINING, u->number); + + ADDMSG(&u->faction->msgs, msg_message("raised", + "unit amount", u, gezuechtet)); +} + +static void +breed_cmd(unit *u, struct order * ord) +{ + int m; + const char *s; + param_t p; + region *r = u->region; + const resource_type * rtype = NULL; + + if (r->land==NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); + return; + } + + /* züchte [] */ + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + m = atoi((const char *)s); + if (m!=0) { + /* first came a want-paramter */ + s = getstrtoken(); + } else { + m = INT_MAX; + } + + if (!s[0]) { + p = P_ANY; + } else { + p = findparam(s, u->faction->locale); + } + + switch (p) { + case P_HERBS: + plant(r, u, m); + break; + case P_TREES: + breedtrees(r, u, m); + break; + default: + if (p!=P_ANY) { + rtype = findresourcetype(s, u->faction->locale); + if (rtype==rt_mallornseed || rtype==rt_seed) { + breedtrees(r, u, m); + break; + } else if (rtype!=oldresourcetype[R_HORSE]) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_cannotmake", "")); + break; + } + } + breedhorses(r, u); + break; + } +} + +static const char * +rough_amount(int a, int m) + +{ + int p = (a * 100)/m; + + if (p < 10) { + return "sehr wenige"; + } else if (p < 30) { + return "wenige"; + } else if (p < 60) { + return "relativ viele"; + } else if (p < 90) { + return "viele"; + } + return "sehr viele"; +} + +static void +research_cmd(unit *u, struct order * ord) +{ + region *r = u->region; + + init_tokens(ord); + skip_token(); + /* + const char *s = getstrtoken(); + + if (findparam(s, u->faction->locale) == P_HERBS) { */ + + if (eff_skill(u, SK_HERBALISM, r) < 7) { + cmistake(u, ord, 227, MSG_EVENT); + return; + } + + produceexp(u, SK_HERBALISM, u->number); + + if (rherbs(r) > 0) { + const item_type *itype = rherbtype(r); + + if (itype != NULL) { + ADDMSG(&u->faction->msgs, msg_message("researchherb", + "unit region amount herb", + u, r, rough_amount(rherbs(r), 100), itype->rtype)); + } else { + ADDMSG(&u->faction->msgs, msg_message("researchherb_none", + "unit region", u, r)); + } + } else { + ADDMSG(&u->faction->msgs, msg_message("researchherb_none", + "unit region", u, r)); + } +} + +static int +max_skill(region * r, faction * f, skill_t sk) +{ + unit *u; + int w = 0; + + for (u = r->units; u; u = u->next) { + if (u->faction == f) { + if (eff_skill(u, sk, r) > w) { + w = eff_skill(u, sk, r); + } + } + } + + return w; +} + +static void +steal_cmd(unit * u, struct order * ord, request ** stealorders) +{ + int n, i, id; + boolean goblin = false; + request * o; + unit * u2 = NULL; + region * r = u->region; + faction * f = NULL; + plane * pl; + + assert(skill_enabled[SK_PERCEPTION] && skill_enabled[SK_STEALTH]); + + if (!fval(u->race, RCF_CANSTEAL)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_nosteal", "race", u->race)); + return; + } + + if (fval(r->terrain, SEA_REGION) && u->race != new_race[RC_AQUARIAN]) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); + return; + } + + pl = rplane(r); + if (pl && fval(pl, PFL_NOATTACK)) { + cmistake(u, ord, 270, MSG_INCOME); + return; + } + + init_tokens(ord); + skip_token(); + id = read_unitid(u->faction, r); + u2 = findunitr(r, id); + + if (u2 && u2->region==u->region) { + f = u2->faction; + } else { + f = dfindhash(id); + } + + for (u2=r->units;u2;u2=u2->next) { + if (u2->faction == f && cansee(u->faction, r, u2, 0)) break; + } + + if (!u2) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + + if (IsImmune(u2->faction)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "newbie_immunity_error", + "turns", NewbieImmunity())); + return; + } + + if (u->faction->alliance && u->faction->alliance == u2->faction->alliance) { + cmistake(u, ord, 47, MSG_INCOME); + return; + } + + assert(u->region==u2->region); + if (!can_contact(r, u, u2)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error60", "")); + return; + } + + n = eff_skill(u, SK_STEALTH, r) - max_skill(r, f, SK_PERCEPTION); + + if (n <= 0) { + /* Wahrnehmung == Tarnung */ + if (u->race != new_race[RC_GOBLIN] || eff_skill(u, SK_STEALTH, r) <= 3) { + ADDMSG(&u->faction->msgs, msg_message("stealfail", "unit target", u, u2)); + if (n==0) { + ADDMSG(&u2->faction->msgs, msg_message("stealdetect", "unit", u2)); + } else { + ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target", u, u2)); + } + return; + } else { + ADDMSG(&u->faction->msgs, msg_message("stealfatal", "unit target", u, u2)); + ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target", u, u2)); + n = 1; + goblin = true; + } + } + + i = MIN(u->number, get_item(u, I_RING_OF_NIMBLEFINGER)); + if (i > 0) { + n *= STEALINCOME * (u->number + i * (roqf_factor()-1)); + } else { + n *= u->number * STEALINCOME; + } + + u->wants = n; + + /* wer dank unsichtbarkeitsringen klauen kann, muss nicht unbedingt ein + * guter dieb sein, schliesslich macht man immer noch sehr viel laerm */ + + o = (request *) calloc(1, sizeof(request)); + o->unit = u; + o->qty = 1; /* Betrag steht in u->wants */ + o->no = u2->no; + o->type.goblin = goblin; /* Merken, wenn Goblin-Spezialklau */ + addlist(stealorders, o); + + /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ + + produceexp(u, SK_STEALTH, MIN(n, u->number)); +} +/* ------------------------------------------------------------- */ + + +static void +expandentertainment(region * r) +{ + unit *u; + int m = entertainmoney(r); + request *o; + + for (o = &entertainers[0]; o != nextentertainer; ++o) { + double part = m / (double) entertaining; + u = o->unit; + if (entertaining <= m) + u->n = o->qty; + else + u->n = (int) (o->qty * part); + change_money(u, u->n); + rsetmoney(r, rmoney(r) - u->n); + m -= u->n; + entertaining -= o->qty; + + /* Nur soviel PRODUCEEXP wie auch tatsächlich gemacht wurde */ + produceexp(u, SK_ENTERTAINMENT, MIN(u->n, u->number)); + add_income(u, IC_ENTERTAIN, o->qty, u->n); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + } +} + +void +entertain_cmd(unit * u, struct order * ord) +{ + region * r = u->region; + int max_e; + request *o; + static int entertainbase = 0; + static int entertainperlevel = 0; + + if (!entertainbase) { + const char * str = get_param(global.parameters, "entertain.base"); + entertainbase = str?atoi(str):0; + } + if (!entertainperlevel) { + const char * str = get_param(global.parameters, "entertain.perlevel"); + entertainperlevel = str?atoi(str):0; + } + if (fval(u, UFL_WERE)) { + cmistake(u, ord, 58, MSG_INCOME); + return; + } + if (!effskill(u, SK_ENTERTAINMENT)) { + cmistake(u, ord, 58, MSG_INCOME); + return; + } + if (besieged(u)) { + cmistake(u, ord, 60, MSG_INCOME); + return; + } + if (u->ship && is_guarded(r, u, GUARD_CREWS)) { + cmistake(u, ord, 69, MSG_INCOME); + return; + } + if (is_cursed(r->attribs, C_DEPRESSION, 0)) { + cmistake(u, ord, 28, MSG_INCOME); + return; + } + + u->wants = u->number * (entertainbase + effskill(u, SK_ENTERTAINMENT) + * entertainperlevel); + + init_tokens(ord); + skip_token(); + max_e = getuint(); + if (max_e != 0) { + u->wants = MIN(u->wants,max_e); + } + o = nextentertainer++; + o->unit = u; + o->qty = u->wants; + entertaining += o->qty; +} + +/** + * \return number of working spaces taken by players + */ +static void +expandwork(region * r, request * work_begin, request * work_end, int maxwork) +{ + int earnings; + /* n: verbleibende Einnahmen */ + /* fishes: maximale Arbeiter */ + int jobs = maxwork; + int p_wage = wage(r, NULL, NULL, turn); + int money = rmoney(r); + request *o; + + for (o = work_begin; o != work_end; ++o) { + unit * u = o->unit; + int workers; + + if (u->number == 0) continue; + + if (jobs>=working) workers = u->number; + else { + workers = u->number * jobs / working; + if (rng_int() % working < (u->number * jobs) % working) workers++; + } + + assert(workers>=0); + + u->n = workers * wage(u->region, u->faction, u->race, turn); + + jobs -= workers; + assert(jobs>=0); + + change_money(u, u->n); + working -= o->unit->number; + add_income(u, IC_WORK, o->qty, u->n); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + } + + if (jobs>rpeasants(r)) { + jobs = rpeasants(r); + } + earnings = jobs * p_wage; + if (rule_blessed_harvest()==HARVEST_TAXES) { + /* E3 rules */ + static const curse_type * blessedharvest_ct; + if (!blessedharvest_ct) { + blessedharvest_ct = ct_find("blessedharvest"); + } + if (blessedharvest_ct && r->attribs) { + int happy = (int)curse_geteffect(get_curse(r->attribs, blessedharvest_ct)); + happy = MIN(happy, jobs); + earnings += happy; + } + } + rsetmoney(r, money + earnings); +} + +static int +do_work(unit * u, order * ord, request * o) +{ + if (playerrace(u->race)) { + region * r = u->region; + int w; + + if (fval(u, UFL_WERE)) { + if (ord) cmistake(u, ord, 313, MSG_INCOME); + return -1; + } + if (besieged(u)) { + if (ord) cmistake(u, ord, 60, MSG_INCOME); + return -1; + } + if (u->ship && is_guarded(r, u, GUARD_CREWS)) { + if (ord) cmistake(u, ord, 69, MSG_INCOME); + return -1; + } + w = wage(r, u->faction, u->race, turn); + u->wants = u->number * w; + o->unit = u; + o->qty = u->number * w; + working += u->number; + return 0; + } + else if (ord && !is_monsters(u->faction)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_cantwork", "race", u->race)); + } + return -1; +} + +static void +expandtax(region * r, request * taxorders) +{ + unit *u; + int i; + + expandorders(r, taxorders); + if (!norders) return; + + for (i = 0; i != norders && rmoney(r) > TAXFRACTION; i++) { + change_money(oa[i].unit, TAXFRACTION); + oa[i].unit->n += TAXFRACTION; + rsetmoney(r, rmoney(r) -TAXFRACTION); + } + free(oa); + + for (u = r->units; u; u = u->next) { + if (u->n >= 0) { + add_income(u, IC_TAX, u->wants, u->n); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + } + } +} + +void +tax_cmd(unit * u, struct order * ord, request ** taxorders) +{ + /* Steuern werden noch vor der Forschung eingetrieben */ + region * r = u->region; + unit *u2; + int n; + request *o; + int max; + + if (!humanoidrace(u->race) && !is_monsters(u->faction)) { + cmistake(u, ord, 228, MSG_INCOME); + return; + } + + if (fval(u, UFL_WERE)) { + cmistake(u, ord, 228, MSG_INCOME); + return; + } + + if (besieged(u)) { + cmistake(u, ord, 60, MSG_INCOME); + return; + } + n = armedmen(u, false); + + if (!n) { + cmistake(u, ord, 48, MSG_INCOME); + return; + } + + init_tokens(ord); + skip_token(); + max = getuint(); + + if (max == 0) max = INT_MAX; + if (!playerrace(u->race)) { + u->wants = MIN(income(u), max); + } else { + u->wants = MIN(n * eff_skill(u, SK_TAXING, r) * 20, max); + } + + u2 = is_guarded(r, u, GUARD_TAX); + if (u2) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "region_guarded", "guard", u2)); + return; + } + + /* die einnahmen werden in fraktionen von 10 silber eingeteilt: diese + * fraktionen werden dann bei eintreiben unter allen eintreibenden + * einheiten aufgeteilt. */ + + o = (request *) calloc(1, sizeof(request)); + o->qty = u->wants / TAXFRACTION; + o->unit = u; + addlist(taxorders, o); + return; +} + +#define MAX_WORKERS 2048 +void +auto_work(region * r) +{ + request workers[MAX_WORKERS]; + request * nextworker = workers; + unit * u; + + for (u=r->units;u;u=u->next) { + if (!(u->flags & UFL_LONGACTION) && !is_monsters(u->faction)) { + if (do_work(u, NULL, nextworker)==0) { + assert(nextworker-workersfaction!=f) return; + + maxsize = buildingeffsize(b, false); + if (maxsize>0) { + double taxfactor = money * b->type->taxes(b, maxsize); + double morale = money * region_get_morale(r) * MORALE_TAX_FACTOR; + if (taxfactor>morale) taxfactor = morale; + if (taxfactor>0) { + int taxmoney = (int)taxfactor; + change_money(u, taxmoney); + rsetmoney(r, money - taxmoney); + ADDMSG(&u->faction->msgs, msg_message("income_tax", + "unit region amount", u, r, taxmoney)); + } + } +} + +void +produce(struct region *r) +{ + request workers[MAX_WORKERS]; + request *taxorders, *sellorders, *stealorders, *buyorders; + unit *u; + int todo; + static int rule_autowork = -1; + boolean limited = true; + request * nextworker = workers; + assert(r); + + /* das sind alles befehle, die 30 tage brauchen, und die in thisorder + * stehen! von allen 30-tage befehlen wird einfach der letzte verwendet + * (dosetdefaults). + * + * kaufen vor einnahmequellen. da man in einer region dasselbe produkt + * nicht kaufen und verkaufen kann, ist die reihenfolge wegen der + * produkte egal. nicht so wegen dem geld. + * + * lehren vor lernen. */ + + if (rule_autowork<0) { + rule_autowork = get_param_int(global.parameters, "work.auto", 0); + } + + assert(rmoney(r) >= 0); + assert(rpeasants(r) >= 0); + + if (r->land && rule_auto_taxation()) { + /* new taxation rules, region owners make money based on morale and building */ + peasant_taxes(r); + } + + buyorders = 0; + sellorders = 0; + working = 0; + nextentertainer = &entertainers[0]; + entertaining = 0; + taxorders = 0; + stealorders = 0; + + for (u = r->units; u; u = u->next) { + order * ord; + boolean trader = false; + + if (u->race == new_race[RC_SPELL] || fval(u, UFL_LONGACTION)) + continue; + + if (u->race == new_race[RC_INSECT] && r_insectstalled(r) && + !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) + continue; + + if (fval(u, UFL_LONGACTION) && u->thisorder==NULL) { + cmistake(u, u->thisorder, 52, MSG_PRODUCE); + continue; + } + + for (ord = u->orders;ord;ord=ord->next) { + switch (get_keyword(ord)) { + case K_BUY: + buy(u, &buyorders, ord); + trader = true; + break; + case K_SELL: + /* sell returns true if the sale is not limited + * by the region limit */ + limited &= !sell(u, &sellorders, ord); + trader = true; + break; + } + } + if (trader) { + attrib * a = a_find(u->attribs, &at_trades); + if (a && a->data.i) { + produceexp(u, SK_TRADE, u->number); + } + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + continue; + } + + todo = get_keyword(u->thisorder); + if (todo == NOKEYWORD) continue; + + if (fval(r->terrain, SEA_REGION) && u->race != new_race[RC_AQUARIAN] + && !(u->race->flags & RCF_SWIM) + && todo != K_STEAL && todo != K_SPY && todo != K_SABOTAGE) + continue; + + switch (todo) { + + case K_ENTERTAIN: + entertain_cmd(u, u->thisorder); + break; + + case K_WORK: + if (!rule_autowork && do_work(u, u->thisorder, nextworker)==0) { + assert(nextworker-workersthisorder, &taxorders); + break; + + case K_STEAL: + steal_cmd(u, u->thisorder, &stealorders); + break; + + case K_SPY: + spy_cmd(u, u->thisorder); + break; + + case K_SABOTAGE: + sabotage_cmd(u, u->thisorder); + break; + + case K_PLANT: + case K_BREED: + breed_cmd(u, u->thisorder); + break; + + case K_RESEARCH: + research_cmd(u, u->thisorder); + break; + } + } + + /* Entertainment (expandentertainment) und Besteuerung (expandtax) vor den + * Befehlen, die den Bauern mehr Geld geben, damit man aus den Zahlen der + * letzten Runde berechnen kann, wieviel die Bauern für Unterhaltung + * auszugeben bereit sind. */ + if (entertaining) expandentertainment(r); + if (!rule_autowork) { + expandwork(r, workers, nextworker, maxworkingpeasants(r)); + } + if (taxorders) expandtax(r, taxorders); + + /* An erster Stelle Kaufen (expandbuying), die Bauern so Geld bekommen, um + * nachher zu beim Verkaufen (expandselling) den Spielern abkaufen zu + * können. */ + + if (buyorders) expandbuying(r, buyorders); + + if (sellorders) { + int limit = rpeasants(r) / TRADE_FRACTION; + if (r->terrain == newterrain(T_DESERT) && buildingtype_exists(r, bt_find("caravan"), true)) + limit *= 2; + expandselling(r, sellorders, limited?limit:INT_MAX); + } + + /* Die Spieler sollen alles Geld verdienen, bevor sie beklaut werden + * (expandstealing). */ + + if (stealorders) expandstealing(r, stealorders); + + assert(rmoney(r) >= 0); + assert(rpeasants(r) >= 0); +} diff --git a/src/gamecode/economy.h b/src/gamecode/economy.h index db8359a63..7bc7d78e7 100644 --- a/src/gamecode/economy.h +++ b/src/gamecode/economy.h @@ -1,60 +1,60 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_GC_ECONOMY -#define H_GC_ECONOMY -#ifdef __cplusplus -extern "C" { -#endif - -/* Welchen Teil des Silbers die Bauern fuer Unterhaltung ausgeben (1/20), und - * wiviel Silber ein Unterhalter pro Talentpunkt bekommt. */ - -/* Wieviele Silbermuenzen jeweils auf einmal "getaxed" werden. */ - -#define TAXFRACTION 10 - -/* Wieviel Silber pro Talentpunkt geklaut wird. */ - -#define STEALINCOME 50 - -/* Teil der Bauern, welche Luxusgueter kaufen und verkaufen (1/100). */ - -#define TRADE_FRACTION 100 - -extern int income(const struct unit * u); - -/* Wieviel Fremde eine Partei pro Woche aufnehmen kann */ -#define MAXNEWBIES 5 - -void economics(struct region *r); -void produce(struct region *r); -void auto_work(struct region * r); - -enum { IC_WORK, IC_ENTERTAIN, IC_TAX, IC_TRADE, IC_TRADETAX, IC_STEAL, IC_MAGIC }; -void maintain_buildings(struct region * r, boolean crash); -extern void add_spende(struct faction * f1, struct faction * f2, int betrag, struct region * r); -extern int make_cmd(struct unit * u, struct order * ord); -extern void split_allocations(struct region * r); -extern int recruit_archetypes(void); -extern int give_control_cmd(struct unit * u, struct order * ord); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_GC_ECONOMY +#define H_GC_ECONOMY +#ifdef __cplusplus +extern "C" { +#endif + +/* Welchen Teil des Silbers die Bauern fuer Unterhaltung ausgeben (1/20), und + * wiviel Silber ein Unterhalter pro Talentpunkt bekommt. */ + +/* Wieviele Silbermuenzen jeweils auf einmal "getaxed" werden. */ + +#define TAXFRACTION 10 + +/* Wieviel Silber pro Talentpunkt geklaut wird. */ + +#define STEALINCOME 50 + +/* Teil der Bauern, welche Luxusgueter kaufen und verkaufen (1/100). */ + +#define TRADE_FRACTION 100 + +extern int income(const struct unit * u); + +/* Wieviel Fremde eine Partei pro Woche aufnehmen kann */ +#define MAXNEWBIES 5 + +void economics(struct region *r); +void produce(struct region *r); +void auto_work(struct region * r); + +enum { IC_WORK, IC_ENTERTAIN, IC_TAX, IC_TRADE, IC_TRADETAX, IC_STEAL, IC_MAGIC }; +void maintain_buildings(struct region * r, boolean crash); +extern void add_spende(struct faction * f1, struct faction * f2, int betrag, struct region * r); +extern int make_cmd(struct unit * u, struct order * ord); +extern void split_allocations(struct region * r); +extern int recruit_archetypes(void); +extern int give_control_cmd(struct unit * u, struct order * ord); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/give.c b/src/gamecode/give.c index 0bc783645..9777a3bee 100644 --- a/src/gamecode/give.c +++ b/src/gamecode/give.c @@ -1,438 +1,438 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - - */ -#include -#include -#include "give.h" - -#include "economy.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* attributes includes */ -#include -#include - -/* util includes */ -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -/* Wieviel Fremde eine Partei pro Woche aufnehmen kangiven */ -#define MAXNEWBIES 5 -#define RESERVE_DONATIONS /* shall we reserve objects given to us by other factions? */ -#define RESERVE_GIVE /* reserve anything that's given from one unit to another? */ - - -static int -GiveRestriction(void) { - static int value = -1; - if (value<0) { - const char * str = get_param(global.parameters, "GiveRestriction"); - value = str?atoi(str):0; - } - return value; -} - -static void -add_give(unit * u, unit * u2, int given, int received, const resource_type * rtype, struct order * ord, int error) -{ - if (error) { - cmistake(u, ord, error, MSG_COMMERCE); - } - else if (u2==NULL) { - ADDMSG(&u->faction->msgs, - msg_message("give_peasants", "unit resource amount", - u, rtype, given)); - } else if (u2->faction!=u->faction) { - message * msg; - - msg = msg_message("give", "unit target resource amount", u, u2, rtype, given); - add_message(&u->faction->msgs, msg); - msg_release(msg); - - msg = msg_message("receive", "unit target resource amount", u, u2, rtype, received); - add_message(&u2->faction->msgs, msg); - msg_release(msg); - } -} - -static boolean -limited_give(const item_type * type) -{ - /* trade only money 2:1, if at all */ - return (type == i_silver); -} - -int give_quota(const unit * src, const unit * dst, const item_type * type, int n) -{ - static float divisor = -1; - - if (divisor==0 || !limited_give(type)) { - return n; - } - if (dst && src && src->faction!=dst->faction) { - if (divisor<0) { - divisor = get_param_flt(global.parameters, "rules.items.give_divisor", 1); - assert(divisor==0 || divisor>=1); - } - if (divisor>=1) { - /* predictable > correct: */ - int x = (int)(n/divisor); - return x; - } - } - return n; -} - -int -give_item(int want, const item_type * itype, unit * src, unit * dest, struct order * ord) -{ - short error = 0; - int n, r; - - assert(itype!=NULL); - n = get_pooled(src, item2resource(itype), GET_DEFAULT, want); - n = MIN(want, n); - r = n; - if (dest && src->faction != dest->faction && src->faction->age < GiveRestriction()) { - if (ord!=NULL) { - ADDMSG(&src->faction->msgs, msg_feedback(src, ord, "giverestriction", - "turns", GiveRestriction())); - } - return -1; - } else if (n == 0) { - int reserve = get_reservation(src, itype->rtype); - if (reserve) { - msg_feedback(src, ord, "nogive_reserved", "resource reservation", - itype->rtype, reserve); - return -1; - } - error = 36; - } else if (itype->flags & ITF_CURSED) { - error = 25; - } else if (itype->give==NULL || itype->give(src, dest, itype, n, ord)!=0) { - int use = use_pooled(src, item2resource(itype), GET_SLACK, n); - if (useitems, itype, r); -#ifdef RESERVE_GIVE -#ifdef RESERVE_DONATIONS - change_reservation(dest, item2resource(itype), r); -#else - if (src->faction==dest->faction) { - change_reservation(dest, item2resource(itype), r); - } -#endif -#endif -#if MUSEUM_MODULE && defined(TODO) - /* TODO: use a trigger for the museum warden! */ - if (a_find(dest->attribs, &at_warden)) { - warden_add_give(src, dest, itype, r); - } -#endif - handle_event(dest->attribs, "receive", src); - } - handle_event(src->attribs, "give", dest); - } - add_give(src, dest, n, r, item2resource(itype), ord, error); - if (error) return -1; - return 0; -} - -void -give_men(int n, unit * u, unit * u2, struct order * ord) -{ - ship *sh; - int k = 0; - int error = 0; - - if (u2 && u->faction != u2->faction && u->faction->age < GiveRestriction()) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "giverestriction", - "turns", GiveRestriction())); - return; - } else if (u == u2) { - error = 10; - } else if (!u2 && u->race == new_race[RC_SNOTLING]) { - /* snotlings may not be given to the peasants. */ - error = 307; - } else if (u2 && u2->number && (fval(u, UFL_HERO) != fval(u2, UFL_HERO))) { - /* heroes may not be given to non-heroes and vice versa*/ - error = 75; - } else if (unit_has_cursed_item(u) || (u2 && unit_has_cursed_item(u2))) { - error = 78; - } else if (fval(u, UFL_LOCKED) || is_cursed(u->attribs, C_SLAVE, 0)) { - error = 74; - } else if (u2 && fval(u, UFL_HUNGER)) { - /* hungry people cannot be given away */ - error = 73; - } else if (u2 && (fval(u2, UFL_LOCKED)|| is_cursed(u2->attribs, C_SLAVE, 0))) { - error = 75; - } else if (u2 && !ucontact(u2, u)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", "target", u2)); - error = -1; - } else if (u2 && (has_skill(u, SK_MAGIC) || has_skill(u2, SK_MAGIC))) { - /* cannot give units to and from magicians */ - error = 158; - } else if (u2 && (fval(u, UFL_WERE) != fval(u2, UFL_WERE))) { - /* werewolves can't be given to non-werewolves and vice-versa */ - error = 312; - } else if (u2 && u2->number!=0 && u2->race != u->race) { - log_warning(("faction %s attempts to give %s to %s.\n", - itoa36(u->faction->no), u->race->_name[0], - u2->race->_name[1])); - error = 139; - } else if (u2!=NULL && (get_racename(u2->attribs) || get_racename(u->attribs))) { - error = 139; - } else if (u2 && u2->faction!=u->faction && !rule_transfermen()) { - error = 74; - } else { - if (n > u->number) n = u->number; - if (u2 && n+u2->number > UNIT_MAXSIZE) { - n = UNIT_MAXSIZE-u2->number; - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_unit_size", "maxsize", UNIT_MAXSIZE)); - assert(n>=0); - } - if (n == 0) { - error = 96; - } else if (u2 && u->faction != u2->faction) { - if (u2->faction->newbies + n > MAXNEWBIES) { - error = 129; - } else if (u->race != u2->faction->race) { - if (u2->faction->race != new_race[RC_HUMAN]) { - error = 120; - } else if (count_migrants(u2->faction) + n > count_maxmigrants(u2->faction)) { - error = 128; - } - else if (has_limited_skills(u) || has_limited_skills(u2)) { - error = 154; - } else if (u2->number!=0) { - error = 139; - } - } - } - } - - if (u2 && (has_skill(u, SK_ALCHEMY) || has_skill(u2, SK_ALCHEMY))) { - k = count_skill(u2->faction, SK_ALCHEMY); - - /* Falls die Zieleinheit keine Alchemisten sind, werden sie nun - * welche. */ - if (!has_skill(u2, SK_ALCHEMY) && has_skill(u, SK_ALCHEMY)) - k += u2->number; - - /* Wenn in eine Alchemisteneinheit Personen verschoben werden */ - if (has_skill(u2, SK_ALCHEMY) && !has_skill(u, SK_ALCHEMY)) - k += n; - - /* Wenn Parteigrenzen überschritten werden */ - if (u2->faction != u->faction) - k += n; - - /* wird das Alchemistenmaximum ueberschritten ? */ - - if (k > skill_limit(u2->faction, SK_ALCHEMY)) { - error = 156; - } - } - - if (error==0) { - if (u2 && u2->number == 0) { - set_racename(&u2->attribs, get_racename(u->attribs)); - u2->race = u->race; - u2->irace = u->irace; - if (fval(u, UFL_HERO)) fset(u2, UFL_HERO); - else freset(u2, UFL_HERO); - } - - if (u2) { - if (u2->number!=0 && recruit_archetypes()) { - /* must have same set of skills */ - boolean okay = false; - if (u->skill_size==u2->skill_size) { - int i; - for (i=0;i!=u->skill_size;++i) { - int j; - for (j=0;j!=u2->skill_size;++j) { - if (u->skills[i].id==u2->skills[j].id) break; - } - if (j!=u2->skill_size) break; - } - if (i==u->skill_size) okay = true; - } - if (!okay) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "give_cannot_merge", "")); - } - } - - - /* Einheiten von Schiffen können nicht NACH in von - * Nicht-alliierten bewachten Regionen ausführen */ - sh = leftship(u); - if (sh) set_leftship(u2, sh); - - transfermen(u, u2, n); - if (u->faction != u2->faction) { - u2->faction->newbies += n; - } - } else { - if (getunitpeasants) { -#ifdef ORCIFICATION - if (u->race == new_race[RC_SNOTLING] && !fval(u->region, RF_ORCIFIED)) { - attrib *a = a_find(u->region->attribs, &at_orcification); - if (!a) a = a_add(&u->region->attribs, a_new(&at_orcification)); - a->data.i += n; - } -#endif - transfermen(u, NULL, n); - } else { - error = 159; - } - } - } - if (error>0) { - cmistake(u, ord, error, MSG_COMMERCE); - } else if (!u2) { - ADDMSG(&u->faction->msgs, - msg_message("give_person_peasants", "unit amount", u, n)); - } else if (u2->faction!=u->faction) { - message * msg = msg_message("give_person", "unit target amount", u, u2, n); - add_message(&u->faction->msgs, msg); - add_message(&u2->faction->msgs, msg); - msg_release(msg); - } -} - -void -give_unit(unit * u, unit * u2, order * ord) -{ - region * r = u->region; - int n = u->number; - - if (!rule_transfermen() && u->faction!=u2->faction) { - cmistake(u, ord, 74, MSG_COMMERCE); - return; - } - - if (u && unit_has_cursed_item(u)) { - cmistake(u, ord, 78, MSG_COMMERCE); - return; - } - - if (fval(u, UFL_HERO)) { - cmistake(u, ord, 75, MSG_COMMERCE); - return; - } - if (fval(u, UFL_LOCKED) || fval(u, UFL_HUNGER)) { - cmistake(u, ord, 74, MSG_COMMERCE); - return; - } - - if (u2 == NULL) { - if (fval(r->terrain, SEA_REGION)) { - cmistake(u, ord, 152, MSG_COMMERCE); - } else if (getunitpeasants) { - unit *u3; - - for(u3 = r->units; u3; u3 = u3->next) - if(u3->faction == u->faction && u != u3) break; - - if(u3) { - while (u->items) { - item * iold = i_remove(&u->items, u->items); - item * inew = *i_find(&u3->items, iold->type); - if (inew==NULL) i_add(&u3->items, iold); - else { - inew->number += iold->number; - i_free(iold); - } - } - } - give_men(u->number, u, NULL, ord); - cmistake(u, ord, 153, MSG_COMMERCE); - } else { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } - return; - } - - if (!alliedunit(u2, u->faction, HELP_GIVE) && ucontact(u2, u) == 0) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", "target", u2)); - return; - } - if (u->number == 0) { - cmistake(u, ord, 105, MSG_COMMERCE); - return; - } - if (u2->faction->newbies + n > MAXNEWBIES) { - cmistake(u, ord, 129, MSG_COMMERCE); - return; - } - if (u->race != u2->faction->race) { - if (u2->faction->race != new_race[RC_HUMAN]) { - cmistake(u, ord, 120, MSG_COMMERCE); - return; - } - if (count_migrants(u2->faction) + u->number > count_maxmigrants(u2->faction)) { - cmistake(u, ord, 128, MSG_COMMERCE); - return; - } - if (has_limited_skills(u)) { - cmistake(u, ord, 154, MSG_COMMERCE); - return; - } - } - if (has_skill(u, SK_MAGIC)) { - sc_mage * mage; - if (count_skill(u2->faction, SK_MAGIC) + u->number > - skill_limit(u2->faction, SK_MAGIC)) - { - cmistake(u, ord, 155, MSG_COMMERCE); - return; - } - mage = get_mage(u); - if (!mage || u2->faction->magiegebiet != mage->magietyp) { - cmistake(u, ord, 157, MSG_COMMERCE); - return; - } - } - if (has_skill(u, SK_ALCHEMY) - && count_skill(u2->faction, SK_ALCHEMY) + u->number > - skill_limit(u2->faction, SK_ALCHEMY)) - { - cmistake(u, ord, 156, MSG_COMMERCE); - return; - } - add_give(u, u2, 1, 1, r_unit, ord, 0); - u_setfaction(u, u2->faction); - u2->faction->newbies += n; -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ +#include +#include +#include "give.h" + +#include "economy.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* attributes includes */ +#include +#include + +/* util includes */ +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +/* Wieviel Fremde eine Partei pro Woche aufnehmen kangiven */ +#define MAXNEWBIES 5 +#define RESERVE_DONATIONS /* shall we reserve objects given to us by other factions? */ +#define RESERVE_GIVE /* reserve anything that's given from one unit to another? */ + + +static int +GiveRestriction(void) { + static int value = -1; + if (value<0) { + const char * str = get_param(global.parameters, "GiveRestriction"); + value = str?atoi(str):0; + } + return value; +} + +static void +add_give(unit * u, unit * u2, int given, int received, const resource_type * rtype, struct order * ord, int error) +{ + if (error) { + cmistake(u, ord, error, MSG_COMMERCE); + } + else if (u2==NULL) { + ADDMSG(&u->faction->msgs, + msg_message("give_peasants", "unit resource amount", + u, rtype, given)); + } else if (u2->faction!=u->faction) { + message * msg; + + msg = msg_message("give", "unit target resource amount", u, u2, rtype, given); + add_message(&u->faction->msgs, msg); + msg_release(msg); + + msg = msg_message("receive", "unit target resource amount", u, u2, rtype, received); + add_message(&u2->faction->msgs, msg); + msg_release(msg); + } +} + +static boolean +limited_give(const item_type * type) +{ + /* trade only money 2:1, if at all */ + return (type == i_silver); +} + +int give_quota(const unit * src, const unit * dst, const item_type * type, int n) +{ + static float divisor = -1; + + if (divisor==0 || !limited_give(type)) { + return n; + } + if (dst && src && src->faction!=dst->faction) { + if (divisor<0) { + divisor = get_param_flt(global.parameters, "rules.items.give_divisor", 1); + assert(divisor==0 || divisor>=1); + } + if (divisor>=1) { + /* predictable > correct: */ + int x = (int)(n/divisor); + return x; + } + } + return n; +} + +int +give_item(int want, const item_type * itype, unit * src, unit * dest, struct order * ord) +{ + short error = 0; + int n, r; + + assert(itype!=NULL); + n = get_pooled(src, item2resource(itype), GET_DEFAULT, want); + n = MIN(want, n); + r = n; + if (dest && src->faction != dest->faction && src->faction->age < GiveRestriction()) { + if (ord!=NULL) { + ADDMSG(&src->faction->msgs, msg_feedback(src, ord, "giverestriction", + "turns", GiveRestriction())); + } + return -1; + } else if (n == 0) { + int reserve = get_reservation(src, itype->rtype); + if (reserve) { + msg_feedback(src, ord, "nogive_reserved", "resource reservation", + itype->rtype, reserve); + return -1; + } + error = 36; + } else if (itype->flags & ITF_CURSED) { + error = 25; + } else if (itype->give==NULL || itype->give(src, dest, itype, n, ord)!=0) { + int use = use_pooled(src, item2resource(itype), GET_SLACK, n); + if (useitems, itype, r); +#ifdef RESERVE_GIVE +#ifdef RESERVE_DONATIONS + change_reservation(dest, item2resource(itype), r); +#else + if (src->faction==dest->faction) { + change_reservation(dest, item2resource(itype), r); + } +#endif +#endif +#if MUSEUM_MODULE && defined(TODO) + /* TODO: use a trigger for the museum warden! */ + if (a_find(dest->attribs, &at_warden)) { + warden_add_give(src, dest, itype, r); + } +#endif + handle_event(dest->attribs, "receive", src); + } + handle_event(src->attribs, "give", dest); + } + add_give(src, dest, n, r, item2resource(itype), ord, error); + if (error) return -1; + return 0; +} + +void +give_men(int n, unit * u, unit * u2, struct order * ord) +{ + ship *sh; + int k = 0; + int error = 0; + + if (u2 && u->faction != u2->faction && u->faction->age < GiveRestriction()) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "giverestriction", + "turns", GiveRestriction())); + return; + } else if (u == u2) { + error = 10; + } else if (!u2 && u->race == new_race[RC_SNOTLING]) { + /* snotlings may not be given to the peasants. */ + error = 307; + } else if (u2 && u2->number && (fval(u, UFL_HERO) != fval(u2, UFL_HERO))) { + /* heroes may not be given to non-heroes and vice versa*/ + error = 75; + } else if (unit_has_cursed_item(u) || (u2 && unit_has_cursed_item(u2))) { + error = 78; + } else if (fval(u, UFL_LOCKED) || is_cursed(u->attribs, C_SLAVE, 0)) { + error = 74; + } else if (u2 && fval(u, UFL_HUNGER)) { + /* hungry people cannot be given away */ + error = 73; + } else if (u2 && (fval(u2, UFL_LOCKED)|| is_cursed(u2->attribs, C_SLAVE, 0))) { + error = 75; + } else if (u2 && !ucontact(u2, u)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", "target", u2)); + error = -1; + } else if (u2 && (has_skill(u, SK_MAGIC) || has_skill(u2, SK_MAGIC))) { + /* cannot give units to and from magicians */ + error = 158; + } else if (u2 && (fval(u, UFL_WERE) != fval(u2, UFL_WERE))) { + /* werewolves can't be given to non-werewolves and vice-versa */ + error = 312; + } else if (u2 && u2->number!=0 && u2->race != u->race) { + log_warning(("faction %s attempts to give %s to %s.\n", + itoa36(u->faction->no), u->race->_name[0], + u2->race->_name[1])); + error = 139; + } else if (u2!=NULL && (get_racename(u2->attribs) || get_racename(u->attribs))) { + error = 139; + } else if (u2 && u2->faction!=u->faction && !rule_transfermen()) { + error = 74; + } else { + if (n > u->number) n = u->number; + if (u2 && n+u2->number > UNIT_MAXSIZE) { + n = UNIT_MAXSIZE-u2->number; + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_unit_size", "maxsize", UNIT_MAXSIZE)); + assert(n>=0); + } + if (n == 0) { + error = 96; + } else if (u2 && u->faction != u2->faction) { + if (u2->faction->newbies + n > MAXNEWBIES) { + error = 129; + } else if (u->race != u2->faction->race) { + if (u2->faction->race != new_race[RC_HUMAN]) { + error = 120; + } else if (count_migrants(u2->faction) + n > count_maxmigrants(u2->faction)) { + error = 128; + } + else if (has_limited_skills(u) || has_limited_skills(u2)) { + error = 154; + } else if (u2->number!=0) { + error = 139; + } + } + } + } + + if (u2 && (has_skill(u, SK_ALCHEMY) || has_skill(u2, SK_ALCHEMY))) { + k = count_skill(u2->faction, SK_ALCHEMY); + + /* Falls die Zieleinheit keine Alchemisten sind, werden sie nun + * welche. */ + if (!has_skill(u2, SK_ALCHEMY) && has_skill(u, SK_ALCHEMY)) + k += u2->number; + + /* Wenn in eine Alchemisteneinheit Personen verschoben werden */ + if (has_skill(u2, SK_ALCHEMY) && !has_skill(u, SK_ALCHEMY)) + k += n; + + /* Wenn Parteigrenzen überschritten werden */ + if (u2->faction != u->faction) + k += n; + + /* wird das Alchemistenmaximum ueberschritten ? */ + + if (k > skill_limit(u2->faction, SK_ALCHEMY)) { + error = 156; + } + } + + if (error==0) { + if (u2 && u2->number == 0) { + set_racename(&u2->attribs, get_racename(u->attribs)); + u2->race = u->race; + u2->irace = u->irace; + if (fval(u, UFL_HERO)) fset(u2, UFL_HERO); + else freset(u2, UFL_HERO); + } + + if (u2) { + if (u2->number!=0 && recruit_archetypes()) { + /* must have same set of skills */ + boolean okay = false; + if (u->skill_size==u2->skill_size) { + int i; + for (i=0;i!=u->skill_size;++i) { + int j; + for (j=0;j!=u2->skill_size;++j) { + if (u->skills[i].id==u2->skills[j].id) break; + } + if (j!=u2->skill_size) break; + } + if (i==u->skill_size) okay = true; + } + if (!okay) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "give_cannot_merge", "")); + } + } + + + /* Einheiten von Schiffen können nicht NACH in von + * Nicht-alliierten bewachten Regionen ausführen */ + sh = leftship(u); + if (sh) set_leftship(u2, sh); + + transfermen(u, u2, n); + if (u->faction != u2->faction) { + u2->faction->newbies += n; + } + } else { + if (getunitpeasants) { +#ifdef ORCIFICATION + if (u->race == new_race[RC_SNOTLING] && !fval(u->region, RF_ORCIFIED)) { + attrib *a = a_find(u->region->attribs, &at_orcification); + if (!a) a = a_add(&u->region->attribs, a_new(&at_orcification)); + a->data.i += n; + } +#endif + transfermen(u, NULL, n); + } else { + error = 159; + } + } + } + if (error>0) { + cmistake(u, ord, error, MSG_COMMERCE); + } else if (!u2) { + ADDMSG(&u->faction->msgs, + msg_message("give_person_peasants", "unit amount", u, n)); + } else if (u2->faction!=u->faction) { + message * msg = msg_message("give_person", "unit target amount", u, u2, n); + add_message(&u->faction->msgs, msg); + add_message(&u2->faction->msgs, msg); + msg_release(msg); + } +} + +void +give_unit(unit * u, unit * u2, order * ord) +{ + region * r = u->region; + int n = u->number; + + if (!rule_transfermen() && u->faction!=u2->faction) { + cmistake(u, ord, 74, MSG_COMMERCE); + return; + } + + if (u && unit_has_cursed_item(u)) { + cmistake(u, ord, 78, MSG_COMMERCE); + return; + } + + if (fval(u, UFL_HERO)) { + cmistake(u, ord, 75, MSG_COMMERCE); + return; + } + if (fval(u, UFL_LOCKED) || fval(u, UFL_HUNGER)) { + cmistake(u, ord, 74, MSG_COMMERCE); + return; + } + + if (u2 == NULL) { + if (fval(r->terrain, SEA_REGION)) { + cmistake(u, ord, 152, MSG_COMMERCE); + } else if (getunitpeasants) { + unit *u3; + + for(u3 = r->units; u3; u3 = u3->next) + if(u3->faction == u->faction && u != u3) break; + + if(u3) { + while (u->items) { + item * iold = i_remove(&u->items, u->items); + item * inew = *i_find(&u3->items, iold->type); + if (inew==NULL) i_add(&u3->items, iold); + else { + inew->number += iold->number; + i_free(iold); + } + } + } + give_men(u->number, u, NULL, ord); + cmistake(u, ord, 153, MSG_COMMERCE); + } else { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } + return; + } + + if (!alliedunit(u2, u->faction, HELP_GIVE) && ucontact(u2, u) == 0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", "target", u2)); + return; + } + if (u->number == 0) { + cmistake(u, ord, 105, MSG_COMMERCE); + return; + } + if (u2->faction->newbies + n > MAXNEWBIES) { + cmistake(u, ord, 129, MSG_COMMERCE); + return; + } + if (u->race != u2->faction->race) { + if (u2->faction->race != new_race[RC_HUMAN]) { + cmistake(u, ord, 120, MSG_COMMERCE); + return; + } + if (count_migrants(u2->faction) + u->number > count_maxmigrants(u2->faction)) { + cmistake(u, ord, 128, MSG_COMMERCE); + return; + } + if (has_limited_skills(u)) { + cmistake(u, ord, 154, MSG_COMMERCE); + return; + } + } + if (has_skill(u, SK_MAGIC)) { + sc_mage * mage; + if (count_skill(u2->faction, SK_MAGIC) + u->number > + skill_limit(u2->faction, SK_MAGIC)) + { + cmistake(u, ord, 155, MSG_COMMERCE); + return; + } + mage = get_mage(u); + if (!mage || u2->faction->magiegebiet != mage->magietyp) { + cmistake(u, ord, 157, MSG_COMMERCE); + return; + } + } + if (has_skill(u, SK_ALCHEMY) + && count_skill(u2->faction, SK_ALCHEMY) + u->number > + skill_limit(u2->faction, SK_ALCHEMY)) + { + cmistake(u, ord, 156, MSG_COMMERCE); + return; + } + add_give(u, u2, 1, 1, r_unit, ord, 0); + u_setfaction(u, u2->faction); + u2->faction->newbies += n; +} diff --git a/src/gamecode/give.h b/src/gamecode/give.h index 9f4e16a64..afd456340 100644 --- a/src/gamecode/give.h +++ b/src/gamecode/give.h @@ -1,26 +1,26 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - - */ -#ifndef H_GC_GIVE -#define H_GC_GIVE -#ifdef __cplusplus -extern "C" { -#endif - - extern int give_item(int want, const struct item_type * itype, struct unit * src, struct unit * dest, struct order * ord); - extern void give_men(int n, struct unit * u, struct unit * u2, struct order * ord); - extern void give_unit(struct unit * u, struct unit * u2, struct order * ord); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ +#ifndef H_GC_GIVE +#define H_GC_GIVE +#ifdef __cplusplus +extern "C" { +#endif + + extern int give_item(int want, const struct item_type * itype, struct unit * src, struct unit * dest, struct order * ord); + extern void give_men(int n, struct unit * u, struct unit * u2, struct order * ord); + extern void give_unit(struct unit * u, struct unit * u2, struct order * ord); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/items.c b/src/gamecode/items.c index 0a6d00a65..b23fc5cc3 100644 --- a/src/gamecode/items.c +++ b/src/gamecode/items.c @@ -1,263 +1,263 @@ -#include -#include -#include "items.h" - -#include "study.h" -#include "curses.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -/* BEGIN studypotion */ -#define MAXGAIN 15 -static int -use_studypotion(struct unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - if (get_keyword(u->thisorder) == K_STUDY) { - skill_t sk; - skill * sv; - - init_tokens(u->thisorder); - skip_token(); - sk = findskill(getstrtoken(), u->faction->locale); - sv = get_skill(u, sk); - - if (sv && sv->level > 2) { - /* TODO: message */ - } else if (study_cost(u, sk)>0) { - /* TODO: message */ - } else { - attrib * a = a_find(u->attribs, &at_learning); - teaching_info * teach; - if (a==NULL) { - a = a_add(&u->attribs, a_new(&at_learning)); - } - teach = (teaching_info*) a->data.v; - if (amount>MAXGAIN) amount = MAXGAIN; - teach->value += amount * 30; - if (teach->value > MAXGAIN * 30) { - teach->value = MAXGAIN * 30; - } - i_change(&u->items, itype, -amount); - return 0; - } - } - return EUNUSABLE; -} -/* END studypotion */ - -/* BEGIN speedsail */ -#define SPEEDSAIL_EFFECT 1 -static int -use_speedsail(struct unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - curse *c; - double effect; - ship * sh = u->ship; - if (!sh) { - cmistake(u, ord, 20, MSG_MOVE); - return -1; - } - - effect = SPEEDSAIL_EFFECT; - c = create_curse(u, &sh->attribs, ct_find("shipspeedup"), 20, INT_MAX, effect, 0); - c_setflag(c, CURSE_NOAGE); - - ADDMSG(&u->faction->msgs, msg_message("use_speedsail", "unit speed", u, SPEEDSAIL_EFFECT)); - use_pooled(u, itype->rtype, GET_DEFAULT, 1); - - return 0; -} -/* END speedsail */ - -/* ------------------------------------------------------------- */ -/* Kann auch von Nichtmagiern benutzt werden, erzeugt eine -* Antimagiezone, die zwei Runden bestehen bleibt */ -static int -use_antimagiccrystal(unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - region * r = u->region; - const resource_type * rt_crystal = NULL; - int i; - - if (rt_crystal == NULL) { - rt_crystal = rt_find("antimagic"); - assert(rt_crystal!=NULL); - } - for (i=0;i!=amount;++i) { - int effect, duration = 2; - double force; - spell *sp = find_spell(M_NONE, "antimagiczone"); - attrib ** ap = &r->attribs; - unused(ord); - assert(sp); - - /* Reduziert die Stärke jedes Spruchs um effect */ - effect = sp->level; - - /* Hält Sprüche bis zu einem summierten Gesamtlevel von power aus. - * Jeder Zauber reduziert die 'Lebenskraft' (vigour) der Antimagiezone - * um seine Stufe */ - force = sp->level * 20; /* Stufe 5 =~ 100 */ - - /* Regionszauber auflösen */ - while (*ap && force > 0) { - curse * c; - attrib * a = *ap; - if (!fval(a->type, ATF_CURSE)) { - do { ap = &(*ap)->next; } while (*ap && a->type==(*ap)->type); - continue; - } - c = (curse*)a->data.v; - - /* Immunität prüfen */ - if (c_flags(c) & CURSE_IMMUNE) { - do { ap = &(*ap)->next; } while (*ap && a->type==(*ap)->type); - continue; - } - - force = destr_curse(c, effect, force); - if(c->vigour <= 0) { - a_remove(&r->attribs, a); - } - if(*ap) ap = &(*ap)->next; - } - - if (force > 0) { - create_curse(u, &r->attribs, ct_find("antimagiczone"), force, duration, effect, 0); - } - } - use_pooled(u, rt_crystal, GET_DEFAULT, amount); - ADDMSG(&u->faction->msgs, msg_message("use_antimagiccrystal", - "unit region", u, r)); - return 0; -} - -static int -use_instantartsculpture(struct unit * u, const struct item_type * itype, - int amount, struct order * ord) -{ - building *b; - - if(u->region->land == NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); - return -1; - } - - b = new_building(bt_find("artsculpture"), u->region, u->faction->locale); - b->size = 100; - - ADDMSG(&u->region->msgs, msg_message("artsculpture_create", "unit region", - u, u->region)); - - use_pooled(u, itype->rtype, GET_DEFAULT, 1); - - return 0; -} - -static int -use_instantartacademy(struct unit * u, const struct item_type * itype, - int amount, struct order * ord) -{ - building *b; - - if(u->region->land == NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); - return -1; - } - - b = new_building(bt_find("artacademy"), u->region, u->faction->locale); - b->size = 100; - - ADDMSG(&u->region->msgs, msg_message( - "artacademy_create", "unit region", u, u->region)); - - use_pooled(u, itype->rtype, GET_DEFAULT, 1); - - return 0; -} - -#define BAGPIPEFRACTION dice_rand("2d4+2") -#define BAGPIPEDURATION dice_rand("2d10+4") - -static int -use_bagpipeoffear(struct unit * u, const struct item_type * itype, - int amount, struct order * ord) -{ - int money; - - if (get_curse(u->region->attribs, ct_find("depression"))) { - cmistake(u, ord, 58, MSG_MAGIC); - return -1; - } - - money = entertainmoney(u->region)/BAGPIPEFRACTION; - change_money(u, money); - rsetmoney(u->region, rmoney(u->region) - money); - - create_curse(u, &u->region->attribs, ct_find("depression"), - 20, BAGPIPEDURATION, 0.0, 0); - - ADDMSG(&u->faction->msgs, msg_message("bagpipeoffear_faction", - "unit region command money", u, u->region, ord, money)); - - ADDMSG(&u->region->msgs, msg_message("bagpipeoffear_region", - "unit money", u, money)); - - return 0; -} - -static int -use_aurapotion50(struct unit * u, const struct item_type * itype, - int amount, struct order * ord) -{ - if (!is_mage(u)) { - cmistake(u, ord, 214, MSG_MAGIC); - return -1; - } - - change_spellpoints(u, 50); - - ADDMSG(&u->faction->msgs, msg_message("aurapotion50", - "unit region command", u, u->region, ord)); - - use_pooled(u, itype->rtype, GET_DEFAULT, 1); - - return 0; -} - - -void -register_itemfunctions(void) -{ - register_demonseye(); - register_item_use(use_antimagiccrystal, "use_antimagiccrystal"); - register_item_use(use_instantartsculpture, "use_instantartsculpture"); - register_item_use(use_studypotion, "use_studypotion"); - register_item_use(use_speedsail, "use_speedsail"); - register_item_use(use_instantartacademy, "use_instantartacademy"); - register_item_use(use_bagpipeoffear, "use_bagpipeoffear"); - register_item_use(use_aurapotion50, "use_aurapotion50"); -} +#include +#include +#include "items.h" + +#include "study.h" +#include "curses.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +/* BEGIN studypotion */ +#define MAXGAIN 15 +static int +use_studypotion(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + if (get_keyword(u->thisorder) == K_STUDY) { + skill_t sk; + skill * sv; + + init_tokens(u->thisorder); + skip_token(); + sk = findskill(getstrtoken(), u->faction->locale); + sv = get_skill(u, sk); + + if (sv && sv->level > 2) { + /* TODO: message */ + } else if (study_cost(u, sk)>0) { + /* TODO: message */ + } else { + attrib * a = a_find(u->attribs, &at_learning); + teaching_info * teach; + if (a==NULL) { + a = a_add(&u->attribs, a_new(&at_learning)); + } + teach = (teaching_info*) a->data.v; + if (amount>MAXGAIN) amount = MAXGAIN; + teach->value += amount * 30; + if (teach->value > MAXGAIN * 30) { + teach->value = MAXGAIN * 30; + } + i_change(&u->items, itype, -amount); + return 0; + } + } + return EUNUSABLE; +} +/* END studypotion */ + +/* BEGIN speedsail */ +#define SPEEDSAIL_EFFECT 1 +static int +use_speedsail(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + curse *c; + double effect; + ship * sh = u->ship; + if (!sh) { + cmistake(u, ord, 20, MSG_MOVE); + return -1; + } + + effect = SPEEDSAIL_EFFECT; + c = create_curse(u, &sh->attribs, ct_find("shipspeedup"), 20, INT_MAX, effect, 0); + c_setflag(c, CURSE_NOAGE); + + ADDMSG(&u->faction->msgs, msg_message("use_speedsail", "unit speed", u, SPEEDSAIL_EFFECT)); + use_pooled(u, itype->rtype, GET_DEFAULT, 1); + + return 0; +} +/* END speedsail */ + +/* ------------------------------------------------------------- */ +/* Kann auch von Nichtmagiern benutzt werden, erzeugt eine +* Antimagiezone, die zwei Runden bestehen bleibt */ +static int +use_antimagiccrystal(unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + region * r = u->region; + const resource_type * rt_crystal = NULL; + int i; + + if (rt_crystal == NULL) { + rt_crystal = rt_find("antimagic"); + assert(rt_crystal!=NULL); + } + for (i=0;i!=amount;++i) { + int effect, duration = 2; + double force; + spell *sp = find_spell(M_NONE, "antimagiczone"); + attrib ** ap = &r->attribs; + unused(ord); + assert(sp); + + /* Reduziert die Stärke jedes Spruchs um effect */ + effect = sp->level; + + /* Hält Sprüche bis zu einem summierten Gesamtlevel von power aus. + * Jeder Zauber reduziert die 'Lebenskraft' (vigour) der Antimagiezone + * um seine Stufe */ + force = sp->level * 20; /* Stufe 5 =~ 100 */ + + /* Regionszauber auflösen */ + while (*ap && force > 0) { + curse * c; + attrib * a = *ap; + if (!fval(a->type, ATF_CURSE)) { + do { ap = &(*ap)->next; } while (*ap && a->type==(*ap)->type); + continue; + } + c = (curse*)a->data.v; + + /* Immunität prüfen */ + if (c_flags(c) & CURSE_IMMUNE) { + do { ap = &(*ap)->next; } while (*ap && a->type==(*ap)->type); + continue; + } + + force = destr_curse(c, effect, force); + if(c->vigour <= 0) { + a_remove(&r->attribs, a); + } + if(*ap) ap = &(*ap)->next; + } + + if (force > 0) { + create_curse(u, &r->attribs, ct_find("antimagiczone"), force, duration, effect, 0); + } + } + use_pooled(u, rt_crystal, GET_DEFAULT, amount); + ADDMSG(&u->faction->msgs, msg_message("use_antimagiccrystal", + "unit region", u, r)); + return 0; +} + +static int +use_instantartsculpture(struct unit * u, const struct item_type * itype, + int amount, struct order * ord) +{ + building *b; + + if(u->region->land == NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); + return -1; + } + + b = new_building(bt_find("artsculpture"), u->region, u->faction->locale); + b->size = 100; + + ADDMSG(&u->region->msgs, msg_message("artsculpture_create", "unit region", + u, u->region)); + + use_pooled(u, itype->rtype, GET_DEFAULT, 1); + + return 0; +} + +static int +use_instantartacademy(struct unit * u, const struct item_type * itype, + int amount, struct order * ord) +{ + building *b; + + if(u->region->land == NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); + return -1; + } + + b = new_building(bt_find("artacademy"), u->region, u->faction->locale); + b->size = 100; + + ADDMSG(&u->region->msgs, msg_message( + "artacademy_create", "unit region", u, u->region)); + + use_pooled(u, itype->rtype, GET_DEFAULT, 1); + + return 0; +} + +#define BAGPIPEFRACTION dice_rand("2d4+2") +#define BAGPIPEDURATION dice_rand("2d10+4") + +static int +use_bagpipeoffear(struct unit * u, const struct item_type * itype, + int amount, struct order * ord) +{ + int money; + + if (get_curse(u->region->attribs, ct_find("depression"))) { + cmistake(u, ord, 58, MSG_MAGIC); + return -1; + } + + money = entertainmoney(u->region)/BAGPIPEFRACTION; + change_money(u, money); + rsetmoney(u->region, rmoney(u->region) - money); + + create_curse(u, &u->region->attribs, ct_find("depression"), + 20, BAGPIPEDURATION, 0.0, 0); + + ADDMSG(&u->faction->msgs, msg_message("bagpipeoffear_faction", + "unit region command money", u, u->region, ord, money)); + + ADDMSG(&u->region->msgs, msg_message("bagpipeoffear_region", + "unit money", u, money)); + + return 0; +} + +static int +use_aurapotion50(struct unit * u, const struct item_type * itype, + int amount, struct order * ord) +{ + if (!is_mage(u)) { + cmistake(u, ord, 214, MSG_MAGIC); + return -1; + } + + change_spellpoints(u, 50); + + ADDMSG(&u->faction->msgs, msg_message("aurapotion50", + "unit region command", u, u->region, ord)); + + use_pooled(u, itype->rtype, GET_DEFAULT, 1); + + return 0; +} + + +void +register_itemfunctions(void) +{ + register_demonseye(); + register_item_use(use_antimagiccrystal, "use_antimagiccrystal"); + register_item_use(use_instantartsculpture, "use_instantartsculpture"); + register_item_use(use_studypotion, "use_studypotion"); + register_item_use(use_speedsail, "use_speedsail"); + register_item_use(use_instantartacademy, "use_instantartacademy"); + register_item_use(use_bagpipeoffear, "use_bagpipeoffear"); + register_item_use(use_aurapotion50, "use_aurapotion50"); +} diff --git a/src/gamecode/items.h b/src/gamecode/items.h index 5de50e512..8dd11a6e1 100644 --- a/src/gamecode/items.h +++ b/src/gamecode/items.h @@ -1,24 +1,24 @@ -/* vi: set ts=2: -+-------------------+ Christian Schlittchen -| | Enno Rehling -| Eressea PBEM host | Katja Zedel -| (c) 1998 - 2003 | Henning Peters -| | Ingo Wilken -+-------------------+ Stefan Reich - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifndef H_KRNL_ITEMS -#define H_KRNL_ITEMS -#ifdef __cplusplus -extern "C" { -#endif - - extern void register_itemfunctions(void); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: ++-------------------+ Christian Schlittchen +| | Enno Rehling +| Eressea PBEM host | Katja Zedel +| (c) 1998 - 2003 | Henning Peters +| | Ingo Wilken ++-------------------+ Stefan Reich + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifndef H_KRNL_ITEMS +#define H_KRNL_ITEMS +#ifdef __cplusplus +extern "C" { +#endif + + extern void register_itemfunctions(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index c5cb1173e..39a66964b 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -1,4223 +1,4223 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#pragma region includes - -#include -#include -#include "laws.h" - -#include -#include - -/* gamecode includes */ -#include "economy.h" -#include "archetype.h" -#include "monster.h" -#include "randenc.h" -#include "spy.h" -#include "study.h" -#include "market.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for volcanoes in emigration (needs a flag) */ -#include - -/* attributes includes */ -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include -#include - -#include - -#pragma endregion - -/* chance that a peasant dies of starvation: */ -#define PEASANT_STARVATION_CHANCE 0.9F -/* Pferdevermehrung */ -#define HORSEGROWTH 4 -/* Wanderungschance pro Pferd */ -#define HORSEMOVE 3 -/* Vermehrungschance pro Baum */ -#define FORESTGROWTH 10000 /* In Millionstel */ - -/** Ausbreitung und Vermehrung */ -#define MAXDEMAND 25 -#define DMRISE 0.1F /* weekly chance that demand goes up */ -#define DMRISEHAFEN 0.2F /* weekly chance that demand goes up with harbor */ - - -/* - exported global symbols ----------------------------------- */ -boolean nobattle = false; -boolean nomonsters = false; -/* ------------------------------------------------------------- */ - -static int -RemoveNMRNewbie(void) { - static int value = -1; - if (value<0) { - value = get_param_int(global.parameters, "nmr.removenewbie", 0); - } - return value; -} - -static void -restart_race(unit *u, const race * rc) -{ - faction * oldf = u->faction; - faction *f = addfaction(oldf->email, oldf->passw, rc, oldf->locale, oldf->subscription); - unit * nu = addplayer(u->region, f); - order ** ordp = &u->orders; - f->subscription = u->faction->subscription; - f->age = u->faction->age; - fset(f, FFL_RESTART); - if (f->subscription) { - sql_print(("UPDATE subscriptions set faction='%s', race='%s' where id=%u;\n", - itoa36(f->no), dbrace(rc), f->subscription)); - } - f->magiegebiet = u->faction->magiegebiet; - f->options = u->faction->options; - free_orders(&nu->orders); - nu->orders = u->orders; - u->orders = NULL; - while (*ordp) { - order * ord = *ordp; - if (get_keyword(ord) != K_RESTART) { - *ordp = ord->next; - ord->next = NULL; - if (u->thisorder == ord) set_order(&u->thisorder, NULL); - } else { - ordp = &ord->next; - } - } - destroyfaction(u->faction); -} - -static void -checkorders(void) -{ - faction *f; - - if (verbosity>=1) puts(" - Warne spaete Spieler..."); - for (f = factions; f; f = f->next) - if (!is_monsters(f) && turn - f->lastorders == NMRTimeout() - 1) - ADDMSG(&f->msgs, msg_message("turnreminder", "")); -} - -static boolean -help_money(const unit * u) -{ - if (u->race->ec_flags & GIVEITEM) return true; - return false; -} - -static void -help_feed(unit * donor, unit * u, int * need_p) -{ - int need = *need_p; - int give = get_money(donor) - lifestyle(donor); - give = MIN(need, give); - - if (give>0) { - change_money(donor, -give); - change_money(u, give); - need -= give; - add_spende(donor->faction, u->faction, give, donor->region); - } - *need_p = need; -} - -static void -get_food(region *r) -{ - plane * pl = rplane(r); - unit *u; - int peasantfood = rpeasants(r)*10; - static int food_rules = -1; - - if (food_rules<0) { - food_rules = get_param_int(global.parameters, "rules.economy.food", 0); - } - - /* 1. Versorgung von eigenen Einheiten. Das vorhandene Silber - * wird zunächst so auf die Einheiten aufgeteilt, dass idealerweise - * jede Einheit genug Silber für ihren Unterhalt hat. */ - - for (u = r->units; u; u = u->next) { - int need = lifestyle(u); - - /* Erstmal zurücksetzen */ - freset(u, UFL_HUNGER); - - if (u->ship && (u->ship->flags&SF_FISHING)) { - unit * v; - int c = 2; - for (v=u;c>0 && v;v=v->next) { - if (v->ship==u->ship) { - int get = 0; - if (v->number<=c) { - get = lifestyle(v); - } else { - get = lifestyle(v) * c / v->number; - } - if (get) { - change_money(v, get); - } - } - c -= v->number; - } - u->ship->flags -= SF_FISHING; - } - - if (food_rules&1) { - faction * owner = region_get_owner(r); - /* if the region is owned, and the owner is nice, then we'll get - * food from the peasants - should not be used with WORK */ - if (owner!=NULL && (get_alliance(owner, u->faction) & HELP_MONEY)) { - int rm = rmoney(r); - int use = MIN(rm, need); - rsetmoney(r, rm-use); - need -= use; - } - } - - need -= get_money(u); - if (need > 0) { - unit *v; - - for (v = r->units; need && v; v = v->next) { - if (v->faction == u->faction && help_money(v)) { - int give = get_money(v) - lifestyle(v); - give = MIN(need, give); - if (give>0) { - change_money(v, -give); - change_money(u, give); - need -= give; - } - } - } - } - } - - /* 2. Versorgung durch Fremde. Das Silber alliierter Einheiten wird - * entsprechend verteilt. */ - for (u = r->units; u; u = u->next) { - int need = lifestyle(u); - faction * f = u->faction; - - need -= MAX(0, get_money(u)); - - if (need > 0) { - unit *v; - - if (food_rules&2) { - /* the owner of the region is the first faction to help out when you're hungry */ - faction * owner = region_get_owner(r); - if (owner && owner!=u->faction) { - for (v=r->units;v;v=v->next) { - if (v->faction==owner && alliedunit(v, f, HELP_MONEY) && help_money(v)) { - help_feed(v, u, &need); - break; - } - } - } - } - for (v = r->units; need && v; v = v->next) { - if (v->faction != f && alliedunit(v, f, HELP_MONEY) && help_money(v)) { - help_feed(v, u, &need); - } - } - - /* Die Einheit hat nicht genug Geld zusammengekratzt und - * nimmt Schaden: */ - if (need > 0) { - int lspp = lifestyle(u)/u->number; - if (lspp > 0) { - int number = (need+lspp-1)/lspp; - if (hunger(number, u)) fset(u, UFL_HUNGER); - } - } - } - } - - /* 3. bestimmen, wie viele Bauern gefressen werden. - * bei fehlenden Bauern den Dämon hungern lassen - */ - for (u = r->units; u; u = u->next) { - if (u->race == new_race[RC_DAEMON]) { - unit * donor = r->units; - int hungry = u->number; - - while (donor!=NULL && hungry>0) { - /* always start with the first known unit that may have some blood */ - static const struct potion_type * pt_blood; - if (pt_blood==NULL) { - const item_type * it_blood = it_find("peasantblood"); - if (it_blood) pt_blood = it_blood->rtype->ptype; - } - if (pt_blood!=NULL) { - while (donor!=NULL) { - if (donor->race==new_race[RC_DAEMON]) { - if (get_effect(donor, pt_blood)) { - /* if he's in our faction, drain him: */ - if (donor->faction==u->faction) break; - } - } - donor = donor->next; - } - if (donor != NULL) { - int blut = get_effect(donor, pt_blood); - blut = MIN(blut, hungry); - change_effect(donor, pt_blood, -blut); - hungry -= blut; - } - } - } - if (pl == NULL || !fval(pl, PFL_NOFEED)) { - if (peasantfood>=hungry) { - peasantfood -= hungry; - hungry = 0; - } else { - hungry -= peasantfood; - peasantfood = 0; - } - if (hungry > 0) { - static int demon_hunger = -1; - if (demon_hunger<0) { - demon_hunger = get_param_int(global.parameters, "hunger.demons", 0); - } - if (demon_hunger==0) { - /* nicht gefütterte dämonen hungern */ -#ifdef PEASANT_HUNGRY_DAEMONS_HAVE_FULL_SKILLS - /* wdw special rule */ - hunger(hungry, u); -#else - if (hunger(hungry, u)) fset(u, UFL_HUNGER); -#endif - /* used to be: hunger(hungry, u); */ - } else { - /* no damage, but set the hungry-flag */ - fset(u, UFL_HUNGER); - } - } - } - } - } - rsetpeasants(r, peasantfood/10); - - /* 3. Von den überlebenden das Geld abziehen: */ - for (u = r->units; u; u = u->next) { - int need = MIN(get_money(u), lifestyle(u)); - change_money(u, -need); - } -} - -static void -age_unit(region * r, unit * u) -{ - if (u->race == new_race[RC_SPELL]) { - if (--u->age <= 0) { - remove_unit(&r->units, u); - } - } else { - ++u->age; - if (u->number>0 && u->race->age) { - u->race->age(u); - } - } -#ifdef ASTRAL_ITEM_RESTRICTIONS - if (u->region && is_astral(u->region)) { - item ** itemp = &u->items; - while (*itemp) { - item * itm = *itemp; - if ((itm->type->flags & ITF_NOTLOST) == 0) { - if (itm->type->flags & (ITF_BIG|ITF_ANIMAL|ITF_CURSED)) { - ADDMSG(&u->faction->msgs, msg_message("itemcrumble", "unit region item amount", - u, u->region, itm->type->rtype, itm->number)); - i_free(i_remove(itemp, itm)); - continue; - } - } - itemp=&itm->next; - } - } -#endif -} - - -static void -live(region * r) -{ - unit **up = &r->units; - - get_food(r); - - while (*up) { - unit * u = *up; - /* IUW: age_unit() kann u loeschen, u->next ist dann - * undefiniert, also muessen wir hier schon das nächste - * Element bestimmen */ - - int effect = get_effect(u, oldpotiontype[P_FOOL]); - if (effect > 0) { /* Trank "Dumpfbackenbrot" */ - skill * sv = u->skills, * sb = NULL; - while (sv!=u->skills+u->skill_size) { - if (sb==NULL || skill_compare(sv, sb)>0) { - sb = sv; - } - ++sv; - } - /* bestes Talent raussuchen */ - if (sb!=NULL) { - int weeks = MIN(effect, u->number); - reduce_skill(u, sb, weeks); - ADDMSG(&u->faction->msgs, msg_message("dumbeffect", - "unit weeks skill", u, weeks, (skill_t)sb->id)); - } /* sonst Glück gehabt: wer nix weiß, kann nix vergessen... */ - change_effect(u, oldpotiontype[P_FOOL], -effect); - } - age_unit(r, u); - if (*up==u) up=&u->next; - } -} - -/* - * This procedure calculates the number of emigrating peasants for the given - * region r. There are two incentives for peasants to emigrate: - * 1) They prefer the less crowded areas. - * Example: mountains, 700 peasants (max 1000), 70% inhabited - * plain, 5000 peasants (max 10000), 50% inhabited - * 700*(PEASANTSWANDER_WEIGHT/100)*((70-50)/100) peasants wander - * from mountains to plain. - * Effect : peasents will leave densely populated regions. - * 2) Peasants prefer richer neighbour regions. - * Example: region A, 700 peasants, wealth $10500, $15 per head - * region B, 2500 peasants, wealth $25000, $10 per head - * Some peasants will emigrate from B to A because $15 > $10 - * exactly: 2500*(PEASANTSGREED_WEIGHT1/100)*((15-10)/100) - * Not taken in consideration: - * - movement because of monsters. - * - movement because of wars - * - movement because of low loyalty relating to present parties. - */ - -#define MAX_EMIGRATION(p) ((p)/MAXDIRECTIONS) -#define MAX_IMMIGRATION(p) ((p)*2/3) - -static void -calculate_emigration(region *r) -{ - int i; - int maxp = maxworkingpeasants(r); - int rp = rpeasants(r); - int max_immigrants = MAX_IMMIGRATION(maxp-rp); - - if (r->terrain == newterrain(T_VOLCANO) || r->terrain == newterrain(T_VOLCANO_SMOKING)) { - max_immigrants = max_immigrants/10; - } - - for (i = 0; max_immigrants>0 && i != MAXDIRECTIONS; i++) { - int dir = (turn+i) % MAXDIRECTIONS; - region *rc = rconnect(r, (direction_t)dir); - - if (rc != NULL && fval(rc->terrain, LAND_REGION)) { - int rp2 = rpeasants(rc); - int maxp2 = maxworkingpeasants(rc); - int max_emigration = MAX_EMIGRATION(rp2-maxp2); - - if (max_emigration>0) { - max_emigration = MIN(max_emigration, max_immigrants); - r->land->newpeasants += max_emigration; - rc->land->newpeasants -= max_emigration; - max_immigrants -= max_emigration; - } - } - } -} - -/** Bauern vermehren sich */ - -static void -peasants(region * r) -{ - int peasants = rpeasants(r); - int money = rmoney(r); - int maxp = production(r) * MAXPEASANTS_PER_AREA; - int n, satiated; - int dead = 0; - - /* Bis zu 1000 Bauern können Zwillinge bekommen oder 1000 Bauern - * wollen nicht! */ - - if (peasants>0) { - int glueck = 0; - double fraction = peasants * 0.0001F * PEASANTGROWTH; - int births = (int)fraction; - attrib * a = a_find(r->attribs, &at_peasantluck); - - if (rng_double()<(fraction-births)) { - /* because we don't want regions that never grow pga. rounding. */ - ++births; - } - if (a!=NULL) { - glueck = a->data.i * 1000; - } - - for (n = peasants; n; --n) { - int chances = 0; - - if (glueck>0) { - --glueck; - chances += PEASANTLUCK; - } - - while (chances--) { - if (rng_int() % 10000 < PEASANTGROWTH) { - /* Only raise with 75% chance if peasants have - * reached 90% of maxpopulation */ - if (peasants/(float)maxp < 0.9 || chance(PEASANTFORCE)) { - ++births; - } - } - } - } - peasants += births; - } - - /* Alle werden satt, oder halt soviele für die es auch Geld gibt */ - - satiated = MIN(peasants, money / maintenance_cost(NULL)); - rsetmoney(r, money - satiated * maintenance_cost(NULL)); - - /* Von denjenigen, die nicht satt geworden sind, verhungert der - * Großteil. dead kann nie größer als rpeasants(r) - satiated werden, - * so dass rpeasants(r) >= 0 bleiben muß. */ - - /* Es verhungert maximal die unterernährten Bevölkerung. */ - - n = MIN(peasants - satiated, rpeasants(r)); - dead += (int)(0.5F + n * PEASANT_STARVATION_CHANCE); - - if (dead > 0) { - message * msg = add_message(&r->msgs, msg_message("phunger", "dead", dead)); - msg_release(msg); - peasants -= dead; - } - - rsetpeasants(r, peasants); -} - -/* ------------------------------------------------------------- */ - -typedef struct migration { - struct migration * next; - region * r; - int horses; - int trees; -} migration; - -#define MSIZE 1023 -migration * migrants[MSIZE]; -migration * free_migrants; - -static migration * -get_migrants(region * r) -{ - int key = reg_hashkey(r); - int index = key % MSIZE; - migration * m = migrants[index]; - while (m && m->r != r) - m = m->next; - if (m == NULL) { - /* Es gibt noch keine Migration. Also eine erzeugen - */ - m = free_migrants; - if (!m) m = calloc(1, sizeof(migration)); - else { - free_migrants = free_migrants->next; - m->horses = 0; - m->trees = 0; - } - m->r = r; - m->next = migrants[index]; - migrants[index] = m; - } - return m; -} - -static void -migrate(region * r) -{ - int key = reg_hashkey(r); - int index = key % MSIZE; - migration ** hp = &migrants[index]; - fset(r, RF_MIGRATION); - while (*hp && (*hp)->r != r) hp = &(*hp)->next; - if (*hp) { - migration * m = *hp; - rsethorses(r, rhorses(r) + m->horses); - /* Was macht das denn hier? - * Baumwanderung wird in trees() gemacht. - * wer fragt das? Die Baumwanderung war abhängig von der - * Auswertungsreihenfolge der regionen, - * das hatte ich geändert. jemand hat es wieder gelöscht, toll. - * ich habe es wieder aktiviert, muß getestet werden. - */ - *hp = m->next; - m->next = free_migrants; - free_migrants = m; - } -} - -static void -horses(region * r) -{ - int horses, maxhorses; - direction_t n; - - /* Logistisches Wachstum, Optimum bei halbem Maximalbesatz. */ - maxhorses = maxworkingpeasants(r)/10; - maxhorses = MAX(0, maxhorses); - horses = rhorses(r); - if (horses > 0) { - if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { - rsethorses(r, (int)(horses*0.9F)); - } else if (maxhorses) { - int i; - double growth = (RESOURCE_QUANTITY * HORSEGROWTH * 200 * (maxhorses-horses))/maxhorses; - - if (growth>0) { - if (a_find(r->attribs, &at_horseluck)) growth *= 2; - /* printf("Horses: <%d> %d -> ", growth, horses); */ - i = (int)(0.5F + (horses * 0.0001F) * growth); - /* printf("%d\n", horses); */ - rsethorses(r, horses + i); - } - } - } - - /* Pferde wandern in Nachbarregionen. - * Falls die Nachbarregion noch berechnet - * werden muß, wird eine migration-Struktur gebildet, - * die dann erst in die Berechnung der Nachbarstruktur einfließt. - */ - - for(n = 0; n != MAXDIRECTIONS; n++) { - region * r2 = rconnect(r, n); - if (r2 && fval(r2->terrain, WALK_INTO)) { - int pt = (rhorses(r) * HORSEMOVE)/100; - pt = (int)normalvariate(pt, pt/4.0); - pt = MAX(0, pt); - if (fval(r2, RF_MIGRATION)) - rsethorses(r2, rhorses(r2) + pt); - else { - migration * nb; - /* haben wir die Migration schonmal benutzt? - * wenn nicht, müssen wir sie suchen. - * Wandernde Pferde vermehren sich nicht. - */ - nb = get_migrants(r2); - nb->horses += pt; - } - /* Wandernde Pferde sollten auch abgezogen werden */ - rsethorses(r, rhorses(r) - pt); - } - } - assert(rhorses(r) >= 0); -} - -static int -count_race(const region *r, const race *rc) -{ - unit *u; - int c = 0; - - for(u = r->units; u; u=u->next) - if(u->race == rc) c += u->number; - - return c; -} - -extern struct attrib_type at_germs; - -static void -growing_trees_e3(region * r, const int current_season, const int last_weeks_season) -{ - const static int transform[4][3] = { - { -1, -1, 0 }, - { TREE_SEED, TREE_SAPLING, 2 }, - { TREE_SAPLING, TREE_TREE, 2 }, - { TREE_TREE, TREE_SEED, 2 } - }; - - if (r->land && current_season!=last_weeks_season && transform[current_season][2]) { - int src_type = transform[current_season][0]; - int dst_type = transform[current_season][1]; - int src = rtrees(r, src_type); - int dst = rtrees(r, dst_type); - int grow = src/transform[current_season][2]; - if (grow>0) { - if (src_type!=TREE_TREE) { - rsettrees(r, src_type, src-grow); - } - rsettrees(r, dst_type, dst+grow); - - if (dst_type==TREE_SEED && r->terrain->size) { - region * rn[MAXDIRECTIONS]; - int d; - double fgrow = grow/(double)MAXDIRECTIONS; - - get_neighbours(r, rn); - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rx = rn[d]; - if (rx && rx->land) { - double scale = 1.0; - int g; - double fg, ch; - int seeds = rtrees(rx, dst_type); - - if (r->terrain->size>rx->terrain->size) { - scale = (scale * rx->terrain->size)/r->terrain->size; - } - fg = scale * fgrow; - g = (int)fg; - ch = fg - g; - if (chance(ch)) ++g; - if (g>0) { - rsettrees(rx, dst_type, seeds + g); - } - } - } - } - } - } -} - -static void -growing_trees(region * r, const int current_season, const int last_weeks_season) -{ - int growth, grownup_trees, i, seeds, sprout; - direction_t d; - attrib *a; - - if(current_season == SEASON_SUMMER || current_season == SEASON_AUTUMN) { - double seedchance = 0.01F * RESOURCE_QUANTITY; - int elves = count_race(r, new_race[RC_ELF]); - - a = a_find(r->attribs, &at_germs); - if(a && last_weeks_season == SEASON_SPRING) { - /* ungekeimte Samen bleiben erhalten, Sprößlinge wachsen */ - sprout = MIN(a->data.sa[1], rtrees(r, 1)); - /* aus dem gesamt Sprößlingepool abziehen */ - rsettrees(r, 1, rtrees(r, 1) - sprout); - /* zu den Bäumen hinzufügen */ - rsettrees(r, 2, rtrees(r, 2) + sprout); - - a_removeall(&r->attribs, &at_germs); - } - - if(is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { - rsettrees(r, 1, (int)(rtrees(r, 1) * 0.9)); - rsettrees(r, 2, (int)(rtrees(r, 2) * 0.9)); - return; - } - - if (production(r) <= 0) return; - - /* Grundchance 1.0% */ - /* Jeder Elf in der Region erhöht die Chance marginal */ - elves = MIN(elves, (production(r)*MAXPEASANTS_PER_AREA)/8); - if (elves) { - seedchance += 1.0-pow(0.99999, elves * RESOURCE_QUANTITY); - } - grownup_trees = rtrees(r, 2); - seeds = 0; - - if (grownup_trees>0) { - double remainder = seedchance*grownup_trees; - seeds = (int)(remainder); - remainder -= seeds; - if (chance(remainder)) { - ++seeds; - } - if (seeds>0) { - seeds += rtrees(r, 0); - rsettrees(r, 0, seeds); - } - } - - /* Bäume breiten sich in Nachbarregionen aus. */ - - /* Gesamtzahl der Samen: - * bis zu 6% (FORESTGROWTH*3) der Bäume samen in die Nachbarregionen */ - seeds = (rtrees(r, 2) * FORESTGROWTH * 3)/1000000; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * r2 = rconnect(r, d); - if (r2 && fval(r2->terrain, LAND_REGION) && r2->terrain->size) { - /* Eine Landregion, wir versuchen Samen zu verteilen: - * Die Chance, das Samen ein Stück Boden finden, in dem sie - * keimen können, hängt von der Bewuchsdichte und der - * verfügbaren Fläche ab. In Gletschern gibt es weniger - * Möglichkeiten als in Ebenen. */ - sprout = 0; - seedchance = (1000 * maxworkingpeasants(r2)) / r2->terrain->size; - for(i=0; iattribs, C_CURSED_BY_THE_GODS, 0)) return; - - /* in at_germs merken uns die Zahl der Samen und Sprößlinge, die - * dieses Jahr älter werden dürfen, damit nicht ein Same im selben - * Zyklus zum Baum werden kann */ - a = a_find(r->attribs, &at_germs); - if(!a) { - a = a_add(&r->attribs, a_new(&at_germs)); - a->data.sa[0] = (short)rtrees(r, 0); - a->data.sa[1] = (short)rtrees(r, 1); - } - /* wir haben 6 Wochen zum wachsen, jeder Same/Sproß hat 18% Chance - * zu wachsen, damit sollten nach 5-6 Wochen alle gewachsen sein */ - growth = 1800; - - /* Samenwachstum */ - - /* Raubbau abfangen, es dürfen nie mehr Samen wachsen, als aktuell - * in der Region sind */ - seeds = MIN(a->data.sa[0], rtrees(r, 0)); - sprout = 0; - - for(i=0;idata.sa[0] = (short)(seeds - sprout); - /* aus dem gesamt Samenpool abziehen */ - rsettrees(r, 0, rtrees(r, 0) - sprout); - /* zu den Sprößlinge hinzufügen */ - rsettrees(r, 1, rtrees(r, 1) + sprout); - - /* Baumwachstum */ - - /* hier gehen wir davon aus, das Jungbäume nicht ohne weiteres aus - * der Region entfernt werden können, da Jungbäume in der gleichen - * Runde nachwachsen, wir also nicht mehr zwischen diesjährigen und - * 'alten' Jungbäumen unterscheiden könnten */ - sprout = MIN(a->data.sa[1], rtrees(r, 1)); - grownup_trees = 0; - - for(i=0;idata.sa[1] = (short)(sprout - grownup_trees); - /* aus dem gesamt Sprößlingepool abziehen */ - rsettrees(r, 1, rtrees(r, 1) - grownup_trees); - /* zu den Bäumen hinzufügen */ - rsettrees(r, 2, rtrees(r, 2) + grownup_trees); - } -} - -static void -growing_herbs(region * r, const int current_season, const int last_weeks_season) -{ - /* Jetzt die Kräutervermehrung. Vermehrt wird logistisch: - * - * Jedes Kraut hat eine Wahrscheinlichkeit von (100-(vorhandene - * Kräuter))% sich zu vermehren. */ - if (current_season != SEASON_WINTER) { - int i; - for (i = rherbs(r); i > 0; i--) { - if (rng_int()%100 < (100-rherbs(r))) rsetherbs(r, (short)(rherbs(r)+1)); - } - } -} - -void -demographics(void) -{ - region *r; - static int last_weeks_season = -1; - static int current_season = -1; - - if (current_season<0) { - gamedate date; - get_gamedate(turn, &date); - current_season = date.season; - get_gamedate(turn-1, &date); - last_weeks_season = date.season; - } - - for (r = regions; r; r = r->next) { - ++r->age; /* also oceans. no idea why we didn't always do that */ - live(r); - /* check_split_dragons(); */ - - if (!fval(r->terrain, SEA_REGION)) { - /* die Nachfrage nach Produkten steigt. */ - struct demand * dmd; - if (r->land) { - static int plant_rules = -1; - - if (plant_rules<0) { - plant_rules = get_param_int(global.parameters, "rules.economy.grow", 0); - } - for (dmd=r->land->demands;dmd;dmd=dmd->next) { - if (dmd->value>0 && dmd->value < MAXDEMAND) { - float rise = DMRISE; - if (buildingtype_exists(r, bt_find("harbour"), true)) rise = DMRISEHAFEN; - if (rng_double()value; - } - } - /* Seuchen erst nachdem die Bauern sich vermehrt haben - * und gewandert sind */ - - calculate_emigration(r); - peasants(r); - if (r->age>20) { - plagues(r, false); - } - horses(r); - if (plant_rules==0) { /* E1 */ - growing_trees(r, current_season, last_weeks_season); - growing_herbs(r, current_season, last_weeks_season); - } else { /* E3 */ - growing_trees_e3(r, current_season, last_weeks_season); - } - } - - update_resources(r); - if (r->land) migrate(r); - } - } - while (free_migrants) { - migration * m = free_migrants->next; - free(free_migrants); - free_migrants = m; - }; - if (verbosity>=1) putchar('\n'); - - remove_empty_units(); - - if (verbosity>=1) puts(" - Einwanderung..."); - for (r = regions; r; r = r->next) { - if (r->land && r->land->newpeasants) { - int rp = rpeasants(r) + r->land->newpeasants; - rsetpeasants(r, MAX(0, rp)); - } - } - - checkorders(); -} -/* ------------------------------------------------------------- */ - -static int -modify(int i) -{ - int c; - - c = i * 2 / 3; - - if (c >= 1) { - return (c + rng_int() % c); - } else { - return (i); - } -} - -static void -inactivefaction(faction * f) -{ - FILE *inactiveFILE; - char zText[128]; - - sprintf(zText, "%s/%s", datapath(), "inactive"); - inactiveFILE = fopen(zText, "a"); - - if (inactiveFILE) { - fprintf(inactiveFILE, "%s:%s:%d:%d\n", - factionid(f), - LOC(default_locale, rc_name(f->race, 1)), - modify(count_all(f)), - turn - f->lastorders); - - fclose(inactiveFILE); - } -} - -static void -transfer_faction(faction *f, faction *f2) -{ - unit *u, *un; - - for (u = f->units; u;) { - un = u->nextF; - if(!unit_has_cursed_item(u) - && !has_skill(u, SK_MAGIC) - && !has_skill(u, SK_ALCHEMY)) { - u_setfaction(u, f2); - } - u = un; - } -} - -static int -restart_cmd(unit * u, struct order * ord) -{ - init_tokens(ord); - skip_token(); /* skip keyword */ - - if (!fval(u->region->terrain, LAND_REGION)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); - } else { - const char * s_race = getstrtoken(), * s_pass; - const race * frace = findrace(s_race, u->faction->locale); - - if (!frace) { - frace = u->faction->race; - s_pass = s_race; - } else { - s_pass = getstrtoken(); - } - - if (u->faction->age > 3 && fval(u->faction, FFL_RESTART)) { - cmistake(u, ord, 314, MSG_EVENT); - return 0; - } - - if (/* frace != u->faction->race && */ u->faction->age < 81) { - cmistake(u, ord, 241, MSG_EVENT); - return 0; - } - - if (!playerrace(frace)) { - cmistake(u, ord, 243, MSG_EVENT); - return 0; - } - - if (!checkpasswd(u->faction, (const char *)s_pass, false)) { - cmistake(u, ord, 86, MSG_EVENT); - log_warning(("RESTART with wrong password, faction %s, pass %s\n", - factionid(u->faction), s_pass)); - return 0; - } - restart_race(u, frace); - return -1; - } - return 0; -} - -static boolean -EnhancedQuit(void) -{ - static int value = -1; - if (value<0) { - const char * str = get_param(global.parameters, "alliance.transferquit"); - value = (str!=0 && strcmp(str, "true")==0); - } - return value; -} - -static int -quit_cmd(unit * u, struct order * ord) -{ - faction * f = u->faction; - const char * passwd; - - init_tokens(ord); - skip_token(); /* skip keyword */ - - passwd = getstrtoken(); - if (checkpasswd(f, (const char *)passwd, false)) { - if (EnhancedQuit()) { - int f2_id = getid(); - if (f2_id>0) { - faction *f2 = findfaction(f2_id); - - if(f2 == NULL) { - cmistake(u, ord, 66, MSG_EVENT); - return 0; - } else if (!u->faction->alliance || u->faction->alliance != f2->alliance) { - cmistake(u, ord, 315, MSG_EVENT); - return 0; - } else if(!alliedfaction(NULL, f, f2, HELP_MONEY)) { - cmistake(u, ord, 316, MSG_EVENT); - return 0; - } else { - variant var; - var.i = f2_id; - a_add(&f->attribs, object_create("quit", TINTEGER, var)); - } - } - } - fset(f, FFL_QUIT); - } else { - char buffer[64]; - write_order(ord, buffer, sizeof(buffer)); - cmistake(u, ord, 86, MSG_EVENT); - log_warning(("QUIT with illegal password for faction %s: %s\n", - factionid(f), buffer)); - } - return 0; -} - -static void -quit(void) -{ - faction ** fptr = &factions; - while (*fptr) { - faction * f = *fptr; - if (f->flags & FFL_QUIT) { - if (EnhancedQuit()) { - /* this doesn't work well (use object_name()) */ - attrib * a = a_find(f->attribs, &at_object); - if (a) { - variant var; - object_type type; - var.i = 0; - object_get(a, &type, &var); - assert(var.i && type==TINTEGER); - if (var.i) { - int f2_id = var.i; - faction *f2 = findfaction(f2_id); - - assert(f2_id>0); - assert(f2!=NULL); - transfer_faction(f, f2); - } - } - } - destroyfaction(f); - } - if (*fptr==f) fptr=&f->next; - } -} - -int dropouts[2]; -int * age = NULL; - -static void -nmr_death(faction * f) -{ - static int rule = -1; - if (rule<0) rule = get_param_int(global.parameters, "rules.nmr.destroy", 0); - if (rule) { - unit * u; - for (u=f->units;u;u=u->nextF) { - if (u->building && fval(u, UFL_OWNER)) { - remove_building(&u->region->buildings, u->building); - } - } - } -} - -static void -parse_restart(void) -{ - region *r; - faction *f; - - /* Sterben erst nachdem man allen anderen gegeben hat - bzw. man kann - * alles machen, was nicht ein dreißigtägiger Befehl ist. */ - - for (r = regions; r; r = r->next) { - unit * u, * un; - for (u = r->units; u;) { - order * ord; - - un = u->next; - for (ord = u->orders; ord!=NULL; ord = ord->next) { - if (get_keyword(ord) == K_RESTART) { - if (u->number > 0) { - if (restart_cmd(u, ord)!=0) { - break; - } - } - } - } - u = un; - } - } - - if (verbosity>=1) puts(" - beseitige Spieler, die sich zu lange nicht mehr gemeldet haben..."); - - for (f = factions; f; f = f->next) { - if(fval(f, FFL_NOIDLEOUT)) f->lastorders = turn; - if (NMRTimeout()>0 && turn - f->lastorders >= NMRTimeout()) { - nmr_death(f); - destroyfaction(f); - continue; - } - if (fval(f, FFL_OVERRIDE)) { - free(f->override); - f->override = strdup(itoa36(rng_int())); - freset(f, FFL_OVERRIDE); - } - if (turn!=f->lastorders) { - char info[256]; - sprintf(info, "%d Einheiten, %d Personen, %d Silber", - f->no_units, f->num_total, f->money); - if (f->subscription) { - sql_print(("UPDATE subscriptions SET lastturn=%d, password='%s', info='%s' WHERE id=%u;\n", - f->lastorders, f->override, info, f->subscription)); - } - } else { - if (f->subscription) { - sql_print(("UPDATE subscriptions SET status='ACTIVE', lastturn=%d, firstturn=greatest(firstturn,%d), password='%s' WHERE id=%u;\n", - f->lastorders, f->lastorders-f->age, - f->override, f->subscription)); - } - } - - if (NMRTimeout()>0 && turn - f->lastorders >= (NMRTimeout() - 1)) { - inactivefaction(f); - continue; - } - } - if (verbosity>=1) { - puts(" - beseitige Spieler, die sich nach der Anmeldung nicht " - "gemeldet haben..."); - } - - age = calloc(MAX(4,turn+1), sizeof(int)); - for (f = factions; f; f = f->next) if (!is_monsters(f)) { - if (RemoveNMRNewbie() && !fval(f, FFL_NOIDLEOUT)) { - if (f->age>=0 && f->age <= turn) ++age[f->age]; - if (f->age == 2 || f->age == 3) { - if (f->lastorders == turn - 2) { - destroyfaction(f); - ++dropouts[f->age-2]; - continue; - } - } - } - } - - if (verbosity>=1) puts(" - beseitige leere Einheiten und leere Parteien..."); - remove_empty_units(); -} -/* ------------------------------------------------------------- */ - -/* HELFE partei [] [NICHT] */ - -static int -ally_cmd(unit * u, struct order * ord) -{ - ally * sf, ** sfp; - faction *f; - int keyword, not_kw; - const char *s; - - init_tokens(ord); - skip_token(); - f = getfaction(); - - if (f==NULL || is_monsters(f)) { - cmistake(u, ord, 66, MSG_EVENT); - return 0; - } - if (f == u->faction) return 0; - - s = getstrtoken(); - - if (!s[0]) - keyword = P_ANY; - else - keyword = findparam(s, u->faction->locale); - - sfp = &u->faction->allies; - if (fval(u, UFL_GROUP)) { - attrib * a = a_find(u->attribs, &at_group); - if (a) sfp = &((group*)a->data.v)->allies; - } - for (sf=*sfp; sf; sf = sf->next) - if (sf->faction == f) - break; /* Gleich die passende raussuchen, wenn vorhanden */ - - not_kw = getparam(u->faction->locale); /* HELFE partei [modus] NICHT */ - - if (!sf) { - if (keyword == P_NOT || not_kw == P_NOT) { - /* Wir helfen der Partei gar nicht... */ - return 0; - } else { - sf = calloc(1, sizeof(ally)); - sf->faction = f; - sf->status = 0; - addlist(sfp, sf); - } - } - switch (keyword) { - case P_NOT: - sf->status = 0; - break; - - case NOPARAM: - cmistake(u, ord, 137, MSG_EVENT); - return 0; - - case P_ANY: - if (not_kw == P_NOT) - sf->status = 0; - else - sf->status = HELP_ALL; - break; - - case P_TRAVEL: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_TRAVEL); - else - sf->status = sf->status | HELP_TRAVEL; - break; - - case P_GIVE: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_GIVE); - else - sf->status = sf->status | HELP_GIVE; - break; - - case P_MONEY: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_MONEY); - else - sf->status = sf->status | HELP_MONEY; - break; - - case P_FIGHT: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_FIGHT); - else - sf->status = sf->status | HELP_FIGHT; - break; - - case P_FACTIONSTEALTH: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_FSTEALTH); - else - sf->status = sf->status | HELP_FSTEALTH; - break; - - case P_GUARD: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_GUARD); - else - sf->status = sf->status | HELP_GUARD; - break; - } - - sf->status &= HelpMask(); - - if (sf->status == 0) { /* Alle HELPs geloescht */ - removelist(sfp, sf); - } - return 0; -} - -static struct local_names * pnames; - -static void -init_prefixnames(void) -{ - int i; - for (i=0;localenames[i];++i) { - const struct locale * lang = find_locale(localenames[i]); - boolean exist = false; - struct local_names * in = pnames; - - while (in!=NULL) { - if (in->lang==lang) { - exist = true; - break; - } - in = in->next; - } - if (in==NULL) in = calloc(sizeof(local_names), 1); - in->next = pnames; - in->lang = lang; - - if (!exist) { - int key; - for (key=0;race_prefixes[key];++key) { - variant var; - const char * pname = locale_string(lang, mkname("prefix", race_prefixes[key])); - if (findtoken(&in->names, pname, &var)==E_TOK_NOMATCH || var.i!=key) { - var.i = key; - addtoken(&in->names, pname, var); - addtoken(&in->names, locale_string(lang, mkname("prefix", race_prefixes[key])), var); - } - } - } - pnames = in; - } -} - -static int -prefix_cmd(unit * u, struct order * ord) -{ - attrib **ap; - const char *s; - local_names * in = pnames; - variant var; - const struct locale * lang = u->faction->locale; - - while (in!=NULL) { - if (in->lang==lang) break; - in = in->next; - } - if (in==NULL) { - init_prefixnames(); - for (in=pnames;in->lang!=lang;in=in->next) ; - } - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - if (!*s) { - attrib *a = NULL; - if (fval(u, UFL_GROUP)) { - a = a_find(u->attribs, &at_group); - } - if (a) { - group * g = (group*)a->data.v; - a_removeall(&g->attribs, &at_raceprefix); - } else { - a_removeall(&u->faction->attribs, &at_raceprefix); - } - return 0; - } - - if (findtoken(&in->names, s, &var)==E_TOK_NOMATCH) { - return 0; - } else if (race_prefixes[var.i] == NULL) { - cmistake(u, ord, 299, MSG_EVENT); - } else { - ap = &u->faction->attribs; - if (fval(u, UFL_GROUP)) { - attrib * a = a_find(u->attribs, &at_group); - group * g = (group*)a->data.v; - if (a) ap = &g->attribs; - } - set_prefix(ap, race_prefixes[var.i]); - } - return 0; -} - - -static cmp_building_cb -get_cmp_region_owner(void) -{ - if (rule_region_owners()) { - return &cmp_current_owner; - } else { - return &cmp_wage; - } -} - -static int -display_cmd(unit * u, struct order * ord) -{ - building * b = u->building; - char **s = NULL; - region * r = u->region; - - init_tokens(ord); - skip_token(); - - switch (getparam(u->faction->locale)) { - case P_BUILDING: - case P_GEBAEUDE: - if (!b) { - cmistake(u, ord, 145, MSG_PRODUCE); - break; - } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 5, MSG_PRODUCE); - break; - } - if (!fval(b->type, BTF_NAMECHANGE) && b->display && b->display[0] != 0) { - cmistake(u, ord, 278, MSG_EVENT); - break; - } - s = &b->display; - break; - - case P_SHIP: - if (!u->ship) { - cmistake(u, ord, 144, MSG_PRODUCE); - break; - } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 12, MSG_PRODUCE); - break; - } - s = &u->ship->display; - break; - - case P_UNIT: - s = &u->display; - break; - - case P_PRIVAT: - { - const char *d = getstrtoken(); - if(d == NULL || *d == 0) { - usetprivate(u, NULL); - } else { - usetprivate(u, d); - } - } - break; - - case P_REGION: - if (!b) { - cmistake(u, ord, 145, MSG_EVENT); - break; - } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 148, MSG_EVENT); - break; - } - if (b != largestbuilding(r, get_cmp_region_owner(), false)) { - cmistake(u, ord, 147, MSG_EVENT); - break; - } - s = &r->display; - break; - - default: - cmistake(u, ord, 110, MSG_EVENT); - break; - } - - if (s!=NULL) { - const char * s2 = getstrtoken(); - - free(*s); - *s = strdup(s2); - if (strlen(s2)>=DISPLAYSIZE) { - (*s)[DISPLAYSIZE] = 0; - } - } - - return 0; -} - -static boolean -renamed_building(const building * b) -{ - const struct locale * lang = locales; - for (;lang;lang=nextlocale(lang)) { - const char * bdname = LOC(lang, b->type->_name); - size_t bdlen = strlen(bdname); - if (strlen(b->name)>=bdlen && strncmp(b->name, bdname, bdlen)==0) { - return false; - } - } - return true; -} - -static int -rename_cmd(unit * u, order * ord, char **s, const char * s2) -{ - if (!s2[0]) { - cmistake(u, ord, 84, MSG_EVENT); - return 0; - } - - /* TODO: Validate to make sure people don't have illegal characters in - * names, phishing-style? () come to mind. */ - - free(*s); - *s = strdup(s2); - if (strlen(s2)>=NAMESIZE) { - (*s)[NAMESIZE] = 0; - } - return 0; -} - -static int -rename_building(unit * u, order * ord, building * b, const char * name) { - unit * owner = b?building_owner(b):0; - boolean foreign = owner && owner->faction==u->faction; - - if (!b) { - cmistake(u, ord, u->building?6:145, MSG_EVENT); - return -1; - } - - if (!fval(b->type, BTF_NAMECHANGE) && renamed_building(b)) { - cmistake(u, ord, 278, MSG_EVENT); - return -1; - } - - if (foreign) { - unit *uo; - - if (renamed_building(b)) { - cmistake(u, ord, 246, MSG_EVENT); - return -1; - } - - uo = building_owner(b); - if (uo) { - if (cansee(uo->faction, u->region, u, 0)) { - ADDMSG(&uo->faction->msgs, msg_message("renamed_building_seen", - "building renamer region", b, u, u->region)); - } else { - ADDMSG(&uo->faction->msgs, msg_message("renamed_building_notseen", - "building region", b, u->region)); - } - } - } else { - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 148, MSG_PRODUCE); - return -1; - } - } - - return rename_cmd(u, ord, &b->name, getstrtoken()); -} - -static int -name_cmd(unit * u, struct order * ord) -{ - building * b = u->building; - region * r = u->region; - char **s = NULL; - param_t p; - boolean foreign = false; - - init_tokens(ord); - skip_token(); - p = getparam(u->faction->locale); - - if (p == P_FOREIGN) { - foreign = true; - p = getparam(u->faction->locale); - } - - switch (p) { - case P_ALLIANCE: - if (foreign==false && f_get_alliance(u->faction)) { - alliance * al = u->faction->alliance; - faction * lead = alliance_get_leader(al); - if (lead==u->faction) { - s = &al->name; - } - } - break; - case P_BUILDING: - case P_GEBAEUDE: - if (foreign) { - b = getbuilding(u->region); - } - - return rename_building(u, ord, b, getstrtoken()); - - case P_FACTION: - if (foreign == true) { - faction *f; - - f = getfaction(); - if (!f) { - cmistake(u, ord, 66, MSG_EVENT); - break; - } - if (f->age < 10) { - cmistake(u, ord, 248, MSG_EVENT); - break; - } else { - const struct locale * lang = locales; - for (;lang;lang=nextlocale(lang)) { - const char * fdname = LOC(lang, "factiondefault"); - size_t fdlen = strlen(fdname); - if (strlen(f->name)>=fdlen && strncmp(f->name, fdname, fdlen)==0) { - break; - } - } - if (lang==NULL) { - cmistake(u, ord, 247, MSG_EVENT); - break; - } - } - if (cansee(f, r, u, 0)) { - ADDMSG(&f->msgs, msg_message("renamed_faction_seen", "unit region", u, r)); - } else { - ADDMSG(&f->msgs, msg_message("renamed_faction_notseen", "", r)); - } - s = &f->name; - } else { - s = &u->faction->name; - } - break; - - case P_SHIP: - if (foreign == true) { - ship *sh = getship(r); - unit *uo; - - if (!sh) { - cmistake(u, ord, 20, MSG_EVENT); - break; - } else { - const struct locale * lang = locales; - for (;lang;lang=nextlocale(lang)) { - const char * sdname = LOC(lang, sh->type->name[0]); - size_t sdlen = strlen(sdname); - if (strlen(sh->name)>=sdlen && strncmp(sh->name, sdname, sdlen)==0) { - break; - } - - sdname = LOC(lang, parameters[P_SHIP]); - sdlen = strlen(sdname); - if (strlen(sh->name)>=sdlen && strncmp(sh->name, sdname, sdlen)==0) { - break; - } - - } - if (lang==NULL) { - cmistake(u, ord, 245, MSG_EVENT); - break; - } - } - uo = shipowner(sh); - if (uo) { - if (cansee(uo->faction, r, u, 0)) { - ADDMSG(&uo->faction->msgs, msg_message("renamed_ship_seen", - "ship renamer region", sh, u, r)); - } else { - ADDMSG(&uo->faction->msgs, msg_message("renamed_ship_notseen", - "ship region", sh, r)); - } - } - s = &sh->name; - } else { - if (!u->ship) { - cmistake(u, ord, 144, MSG_PRODUCE); - break; - } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 12, MSG_PRODUCE); - break; - } - s = &u->ship->name; - } - break; - - case P_UNIT: - if (foreign == true) { - unit *u2 = getunit(r, u->faction); - - if (!u2 || !cansee(u->faction, r, u2, 0)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - break; - } else { - const char * udefault = LOC(u2->faction->locale, "unitdefault"); - size_t udlen = strlen(udefault); - size_t unlen = strlen(u2->name); - if (unlen>=udlen && strncmp(u2->name, udefault, udlen)!=0) { - cmistake(u2, ord, 244, MSG_EVENT); - break; - } - } - if (cansee(u2->faction, r, u, 0)) { - ADDMSG(&u2->faction->msgs, msg_message("renamed_seen", - "renamer renamed region", u, u2, r)); - } else { - ADDMSG(&u2->faction->msgs, msg_message("renamed_notseen", - "renamed region", u2, r)); - } - s = &u2->name; - } else { - s = &u->name; - } - break; - - case P_REGION: - if (!b) { - cmistake(u, ord, 145, MSG_EVENT); - break; - } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 148, MSG_EVENT); - break; - } - - if (b != largestbuilding(r, get_cmp_region_owner(), false)) { - cmistake(u, ord, 147, MSG_EVENT); - break; - } - s = &r->land->name; - break; - - case P_GROUP: - { - attrib * a = NULL; - if (fval(u, UFL_GROUP)) a = a_find(u->attribs, &at_group); - if (a) { - group * g = (group*)a->data.v; - s = &g->name; - break; - } else { - cmistake(u, ord, 109, MSG_EVENT); - break; - } - } - break; - default: - cmistake(u, ord, 109, MSG_EVENT); - break; - } - - if (s!=NULL) { - return rename_cmd(u, ord, s, getstrtoken()); - } - - return 0; -} -/* ------------------------------------------------------------- */ - -void -deliverMail(faction * f, region * r, unit * u, const char *s, unit * receiver) -{ - if (!cansee(f, r, u, 0)) { - u = NULL; - } - if (!receiver) { /* BOTSCHAFT an PARTEI */ - ADDMSG(&f->msgs, msg_message("regionmessage", "region sender string", r, u, s)); - } else { /* BOTSCHAFT an EINHEIT */ - ADDMSG(&f->msgs, msg_message("unitmessage", "region unit sender string", r, receiver, u, s)); - } -} - -static void -mailunit(region * r, unit * u, int n, struct order * ord, const char * s) -{ - unit * u2 = findunitr(r,n); - - if (u2 && cansee(u->faction, r, u2, 0)) { - deliverMail(u2->faction, r, u, s, u2); - /* now done in prepare_mail_cmd */ - } - else { - /* Immer eine Meldung - sonst könnte man so getarnte EHs enttarnen: - * keine Meldung -> EH hier. */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } -} - -static void -mailfaction(unit * u, int n, struct order * ord, const char * s) -{ - faction *f; - - f = findfaction(n); - if (f && n>0) - deliverMail(f, u->region, u, s, NULL); - else - cmistake(u, ord, 66, MSG_MESSAGE); -} - -static int -mail_cmd(unit * u, struct order * ord) -{ - region * r = u->region; - unit *u2; - const char *s; - int n, cont; - - init_tokens(ord); - skip_token(); /* skip the keyword */ - s = getstrtoken(); - - /* Falls kein Parameter, ist das eine Einheitsnummer; - * das Füllwort "AN" muß wegfallen, da gültige Nummer! */ - - do { - cont = 0; - switch (findparam(s, u->faction->locale)) { - case P_REGION: - /* können alle Einheiten in der Region sehen */ - s = getstrtoken(); - if (!s[0]) { - cmistake(u, ord, 30, MSG_MESSAGE); - break; - } else { - ADDMSG(&r->msgs, msg_message("mail_result", "unit message", u, s)); - return 0; - } - - case P_FACTION: - { - boolean see = false; - - n = getfactionid(); - - for(u2=r->units; u2; u2=u2->next) { - if(u2->faction->no == n && seefaction(u->faction, r, u2, 0)) { - see = true; - break; - } - } - - if(see == false) { - cmistake(u, ord, 66, MSG_MESSAGE); - break; - } - - s = getstrtoken(); - if (!s[0]) { - cmistake(u, ord, 30, MSG_MESSAGE); - break; - } - mailfaction(u, n, ord, s); - return 0; - } - - case P_UNIT: - { - boolean see = false; - n = getid(); - - for (u2=r->units; u2; u2=u2->next) { - if (u2->no == n && cansee(u->faction, r, u2, 0)) { - see = true; - break; - } - } - - if (see == false) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return 0; - } - - s = getstrtoken(); - if (!s[0]) { - cmistake(u, ord, 30, MSG_MESSAGE); - break; - } else { - attrib * a = a_find(u2->attribs, &at_eventhandler); - if (a!=NULL) { - event_arg args[3]; - args[0].data.v = (void*)s; - args[0].type = "string"; - args[1].data.v = (void*)u; - args[1].type = "unit"; - args[2].type = NULL; - handle_event(a, "message", args); - } - - mailunit(r, u, n, ord, s); - } - return 0; - } - - case P_BUILDING: - case P_GEBAEUDE: - { - building *b = getbuilding(r); - - if(!b) { - cmistake(u, ord, 6, MSG_MESSAGE); - break; - } - - s = getstrtoken(); - - if (!s[0]) { - cmistake(u, ord, 30, MSG_MESSAGE); - break; - } - - for (u2 = r->units; u2; u2 = u2->next) freset(u2->faction, FFL_SELECT); - - for (u2=r->units; u2; u2=u2->next) { - if(u2->building == b && !fval(u2->faction, FFL_SELECT) - && cansee(u->faction, r, u2, 0)) { - mailunit(r, u, u2->no, ord, s); - fset(u2->faction, FFL_SELECT); - } - } - return 0; - } - - case P_SHIP: - { - ship *sh = getship(r); - - if(!sh) { - cmistake(u, ord, 20, MSG_MESSAGE); - break; - } - - s = getstrtoken(); - - if (!s[0]) { - cmistake(u, ord, 30, MSG_MESSAGE); - break; - } - - for (u2 = r->units; u2; u2 = u2->next) freset(u2->faction, FFL_SELECT); - - for(u2=r->units; u2; u2=u2->next) { - if(u2->ship == sh && !fval(u2->faction, FFL_SELECT) && cansee(u->faction, r, u2, 0)) { - mailunit(r, u, u2->no, ord, s); - fset(u2->faction, FFL_SELECT); - } - } - return 0; - } - - default: - /* possibly filler token? */ - s = getstrtoken(); - if (s && *s) cont = 1; - break; - } - } while (cont); - cmistake(u, ord, 149, MSG_MESSAGE); - return 0; -} -/* ------------------------------------------------------------- */ - -static int -banner_cmd(unit * u, struct order * ord) -{ - init_tokens(ord); - skip_token(); - - free(u->faction->banner); - u->faction->banner = strdup(getstrtoken()); - add_message(&u->faction->msgs, msg_message("changebanner", "value", - u->faction->banner)); - - return 0; -} - -static int -email_cmd(unit * u, struct order * ord) -{ - const char * s; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - if (!s[0]) { - cmistake(u, ord, 85, MSG_EVENT); - } else { - faction * f = u->faction; - if (set_email(&f->email, (const char *)s)!=0) { - log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), s)); - ADDMSG(&f->msgs, msg_message("changemail_invalid", "value", s)); - } else { - ADDMSG(&f->msgs, msg_message("changemail", "value", f->email)); - } - } - return 0; -} - -static int -password_cmd(unit * u, struct order * ord) -{ - char pwbuf[32]; - int i; - const char * s; - boolean pwok = true; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - if (!s || !*s) { - for(i=0; i<6; i++) pwbuf[i] = (char)(97 + rng_int() % 26); - pwbuf[6] = 0; - } else { - char *c; - - strlcpy(pwbuf, (const char *)s, 31); - pwbuf[31] = 0; - c = pwbuf; - while (*c && pwok) { - if (!isalnum(*(unsigned char*)c)) pwok = false; - c++; - } - } - free(u->faction->passw); - if (pwok == false) { - cmistake(u, ord, 283, MSG_EVENT); - u->faction->passw = strdup(itoa36(rng_int())); - } else { - u->faction->passw = strdup(pwbuf); - } - fset(u->faction, FFL_OVERRIDE); - ADDMSG(&u->faction->msgs, msg_message("changepasswd", - "value", u->faction->passw)); - return 0; -} - -static int -send_cmd(unit * u, struct order * ord) -{ - const char * s; - int option; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - option = findoption(s, u->faction->locale); - - if (option == -1) { - cmistake(u, ord, 135, MSG_EVENT); - } else { - if (getparam(u->faction->locale) == P_NOT) { - if (option == O_COMPRESS || option == O_BZIP2) { - cmistake(u, ord, 305, MSG_EVENT); - } else { - u->faction->options = u->faction->options & ~(1<faction->options = u->faction->options | (1<faction->options &= ~(1<faction->options &= ~(1<items, itype); - if (i==0) { - if (u->region->land!=NULL) { - i = i_get(u->region->land->items, itype); - } - if (i==0) { - i = i_get(u->faction->items, itype); - if (i==0) return false; - } - } - } - - name = resourcename(itype->rtype, 0); - key = mkname("iteminfo", name); - info = locale_getstring(f->locale, key); - - if (info==NULL) { - info = locale_string(f->locale, mkname("iteminfo", "no_info")); - } - ADDMSG(&f->msgs, msg_message("displayitem", "weight item description", - itype->weight, itype->rtype, info)); - - return true; -} - -static boolean -display_potion(faction *f, unit *u, const potion_type * ptype) -{ - attrib *a; - - if (ptype==NULL) return false; - else { - int i = i_get(u->items, ptype->itype); - if (i==0 && 2*ptype->level > effskill(u,SK_ALCHEMY)) { - return false; - } - } - - a = a_find(f->attribs, &at_showitem); - while (a && a->data.v != ptype) a=a->next; - if (!a) { - a = a_add(&f->attribs, a_new(&at_showitem)); - a->data.v = (void*) ptype->itype; - } - - return true; -} - -static boolean -display_race(faction *f, unit *u, const race * rc) -{ - const char *name, *key; - const char *info; - int a, at_count; - char buf[2048], * bufp = buf; - size_t size = sizeof(buf) - 1; - int bytes; - - if (u && u->race != rc) return false; - name = rc_name(rc, 0); - - bytes = slprintf(bufp, size, "%s: ", LOC(f->locale, name)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - key = mkname("raceinfo", rc->_name[0]); - info = locale_getstring(f->locale, key); - if (info==NULL) { - info = locale_string(f->locale, mkname("raceinfo", "no_info")); - } - - bytes = (int)strlcpy(bufp, info, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - /* hp_p : Trefferpunkte */ - bytes = snprintf(bufp, size, " %d %s", rc->hitpoints, LOC(f->locale, "stat_hitpoints")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - /* b_attacke : Angriff */ - bytes = snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_attack"), (rc->at_default+rc->at_bonus)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - /* b_defense : Verteidigung */ - bytes = snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_defense"), (rc->df_default+rc->df_bonus)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - /* b_armor : Rüstung */ - if (rc->armor > 0) { - bytes = snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_armor"), rc->armor); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - - if (size>1) { - *bufp++ ='.'; - --size; - } else WARN_STATIC_BUFFER(); - - /* b_damage : Schaden */ - at_count=0; - for (a = 0; a < 6; a++) { - if (rc->attack[a].type != AT_NONE){ - at_count++; - } - } - if (rc->battle_flags & BF_EQUIPMENT) { - bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_equipment")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (rc->battle_flags & BF_RES_PIERCE) { - bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_pierce")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (rc->battle_flags & BF_RES_CUT) { - bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_cut")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (rc->battle_flags & BF_RES_BASH) { - bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_bash")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - - bytes = snprintf(bufp, size, " %d %s", at_count, LOC(f->locale, (at_count==1)?"stat_attack":"stat_attacks")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - for (a = 0; a < 6; a++) { - if (rc->attack[a].type != AT_NONE){ - if (a!=0) bytes = (int)strlcpy(bufp, ", ", size); - else bytes = (int)strlcpy(bufp, ": ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - switch(rc->attack[a].type) { - case AT_STANDARD: - bytes = snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_standard"), rc->def_damage); - break; - case AT_NATURAL: - bytes = snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_natural"), rc->attack[a].data.dice); - break; - case AT_SPELL: - case AT_COMBATSPELL: - case AT_DRAIN_ST: - case AT_DAZZLE: - bytes = snprintf(bufp, size, "%s", LOC(f->locale, "attack_magical")); - break; - case AT_STRUCTURAL: - bytes = snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_structural"), rc->attack[a].data.dice); - break; - default: - bytes = 0; - } - - if (bytes && wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - - if (size>1) { - *bufp++ = '.'; - --size; - } else WARN_STATIC_BUFFER(); - - *bufp = 0; - addmessage(0, f, buf, MSG_EVENT, ML_IMPORTANT); - - return true; -} - -static void -reshow(unit * u, struct order * ord, const char * s, param_t p) -{ - int skill, c; - const potion_type * ptype; - const item_type * itype; - const spell * sp; - const race * rc; - - switch (p) { - case P_ZAUBER: - a_removeall(&u->faction->attribs, &at_seenspell); - break; - case P_POTIONS: - skill = effskill(u, SK_ALCHEMY); - c = 0; - for (ptype = potiontypes; ptype!=NULL; ptype=ptype->next) { - if (ptype->level * 2 <= skill) { - c += display_potion(u->faction, u, ptype); - } - } - if (c == 0) cmistake(u, ord, 285, MSG_EVENT); - break; - case NOPARAM: - /* check if it's an item */ - itype = finditemtype(s, u->faction->locale); - if (itype!=NULL) { - ptype = resource2potion(item2resource(itype)); - if (ptype!=NULL) { - if (display_potion(u->faction, u, ptype)) break; - } else { - if (display_item(u->faction, u, itype)) break; - } - } - /* try for a spell */ - sp = get_spellfromtoken(u, s, u->faction->locale); - if (sp!=NULL && u_hasspell(u, sp)) { - attrib *a = a_find(u->faction->attribs, &at_seenspell); - while (a!=NULL && a->type==&at_seenspell && a->data.v!=sp) a = a->next; - if (a!=NULL) a_remove(&u->faction->attribs, a); - break; - } - /* last, check if it's a race. */ - rc = findrace(s, u->faction->locale); - if (rc != NULL) { - if (display_race(u->faction, u, rc)) break; - } - cmistake(u, ord, 21, MSG_EVENT); - break; - default: - cmistake(u, ord, 222, MSG_EVENT); - break; - } -} - -static int -promotion_cmd(unit * u, struct order * ord) -{ - int money, people; - - if (fval(u, UFL_HERO)) { - /* TODO: message "is already a hero" */ - return 0; - } - - if (maxheroes(u->faction) < countheroes(u->faction)+u->number) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_maxed", "max count", - maxheroes(u->faction), countheroes(u->faction))); - return 0; - } - if (!valid_race(u->faction, u->race)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_race", "race", - u->race)); - return 0; - } - people = count_all(u->faction) * u->number; - money = get_pooled(u, i_silver->rtype, GET_ALL, people); - - if (people>money) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_cost", "cost have", - people, money)); - return 0; - } - use_pooled(u, i_silver->rtype, GET_ALL, people); - fset(u, UFL_HERO); - ADDMSG(&u->faction->msgs, msg_message("hero_promotion", "unit cost", - u, people)); - return 0; -} - -static int -group_cmd(unit * u, struct order * ord) -{ - const char * s; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - join_group(u, s); - return 0; -} - -static int -origin_cmd(unit * u, struct order * ord) -{ - short px, py; - - init_tokens(ord); - skip_token(); - - px = (short)getint(); - py = (short)getint(); - - set_ursprung(u->faction, getplaneid(u->region), px, py); - return 0; -} - -static int -guard_off_cmd(unit * u, struct order * ord) -{ - assert(get_keyword(ord)==K_GUARD); - init_tokens(ord); - skip_token(); - - if (getparam(u->faction->locale) == P_NOT) { - setguard(u, GUARD_NONE); - } - return 0; -} - -static int -reshow_cmd(unit * u, struct order * ord) -{ - const char * s; - param_t p = NOPARAM; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - if (findparam(s, u->faction->locale) == P_ANY) { - p = getparam(u->faction->locale); - s = NULL; - } - - reshow(u, ord, s, p); - return 0; -} - -static int -status_cmd(unit * u, struct order * ord) -{ - const char * param; - - init_tokens(ord); - skip_token(); - - param = getstrtoken(); - switch (findparam(param, u->faction->locale)) { - case P_NOT: - setstatus(u, ST_AVOID); - break; - case P_BEHIND: - setstatus(u, ST_BEHIND); - break; - case P_FLEE: - setstatus(u, ST_FLEE); - break; - case P_CHICKEN: - setstatus(u, ST_CHICKEN); - break; - case P_AGGRO: - setstatus(u, ST_AGGRO); - break; - case P_VORNE: - setstatus(u, ST_FIGHT); - break; - case P_HELP: - if (getparam(u->faction->locale) == P_NOT) { - fset(u, UFL_NOAID); - } else { - freset(u, UFL_NOAID); - } - break; - default: - if (param[0]) { - add_message(&u->faction->msgs, - msg_feedback(u, ord, "unknown_status", "")); - } else { - setstatus(u, ST_FIGHT); - } - } - return 0; -} - -static int -combatspell_cmd(unit * u, struct order * ord) -{ - const char * s; - int level = 0; - spell * spell; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - /* KAMPFZAUBER [NICHT] löscht alle gesetzten Kampfzauber */ - if (!s || *s == 0 || findparam(s, u->faction->locale) == P_NOT) { - unset_combatspell(u, 0); - return 0; - } - - /* Optional: STUFE n */ - if (findparam(s, u->faction->locale) == P_LEVEL) { - /* Merken, setzen kommt erst später */ - level = getint(); - level = MAX(0, level); - s = getstrtoken(); - } - - spell = get_spellfromtoken(u, s, u->faction->locale); - - if(!spell){ - cmistake(u, ord, 173, MSG_MAGIC); - return 0; - } - - s = getstrtoken(); - - if (findparam(s, u->faction->locale) == P_NOT) { - /* KAMPFZAUBER "" NICHT löscht diesen speziellen - * Kampfzauber */ - unset_combatspell(u, spell); - return 0; - } else { - /* KAMPFZAUBER "" setzt diesen Kampfzauber */ - set_combatspell(u, spell, ord, level); - } - - return 0; -} - -/* ------------------------------------------------------------- */ -/* Beachten: einige Monster sollen auch unbewaffent die Region bewachen - * können */ - -enum { E_GUARD_OK, E_GUARD_UNARMED, E_GUARD_NEWBIE, E_GUARD_FLEEING }; - -static int -can_start_guarding(const unit * u) -{ - if (u->status>=ST_FLEE) return E_GUARD_FLEEING; - if (fval(u->race, RCF_UNARMEDGUARD)) return E_GUARD_OK; - if (!armedmen(u, true)) return E_GUARD_UNARMED; - if (IsImmune(u->faction)) return E_GUARD_NEWBIE; - return E_GUARD_OK; -} - -void -update_guards(void) -{ - const region *r; - - for (r = regions; r; r = r->next) { - unit *u; - for (u = r->units; u; u = u->next) { - if (fval(u, UFL_GUARD)) { - if (can_start_guarding(u)!=E_GUARD_OK) { - setguard(u, GUARD_NONE); - } else { - attrib * a = a_find(u->attribs, &at_guard); - if (a && a->data.i==(int)guard_flags(u)) { - /* this is really rather not necessary */ - a_remove(&u->attribs, a); - } - } - } - } - } -} - -static int -guard_on_cmd(unit * u, struct order * ord) -{ - assert(get_keyword(ord)==K_GUARD); - - init_tokens(ord); - skip_token(); - - /* GUARD NOT is handled in goard_off_cmd earlier in the turn */ - if (getparam(u->faction->locale) == P_NOT) return 0; - - if (fval(u->region->terrain, SEA_REGION)) { - cmistake(u, ord, 2, MSG_EVENT); - } else { - if (fval(u, UFL_MOVED)) { - cmistake(u, ord, 187, MSG_EVENT); - } else if (fval(u->race, RCF_ILLUSIONARY) || u->race == new_race[RC_SPELL]) { - cmistake(u, ord, 95, MSG_EVENT); - } else { - /* Monster der Monsterpartei dürfen immer bewachen */ - if (is_monsters(u->faction)) { - guard(u, GUARD_ALL); - } else { - int err = can_start_guarding(u); - if (err==E_GUARD_OK) { - guard(u, GUARD_ALL); - } else if (err==E_GUARD_UNARMED) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_unarmed", "")); - } else if (err==E_GUARD_FLEEING) { - cmistake(u, ord, 320, MSG_EVENT); - } else if (err==E_GUARD_NEWBIE) { - cmistake(u, ord, 304, MSG_EVENT); - } - } - } - } - return 0; -} - -static void -sinkships(region * r) -{ - ship **shp = &r->ships; - - while (*shp) { - ship * sh = *shp; - if (fval(r->terrain, SEA_REGION) && (!enoughsailors(sh, r) || get_captain(sh)==NULL)) { - /* Schiff nicht seetüchtig */ - damage_ship(sh, 0.30); - } - if (shipowner(sh)==NULL) { - damage_ship(sh, 0.05); - } - if (sh->damage >= sh->size * DAMAGE_SCALE) { - remove_ship(shp, sh); - } - if (*shp==sh) shp=&sh->next; - } -} - -/* The following functions do not really belong here: */ -#include -#include - -static attrib_type at_number = { - "faction_renum", - NULL, NULL, NULL, NULL, NULL, - ATF_UNIQUE -}; - -static void -renumber_factions(void) - /* gibt parteien neue nummern */ -{ - struct renum { - struct renum * next; - int want; - faction * faction; - attrib * attrib; - } * renum = NULL, * rp; - faction * f; - for (f=factions;f;f=f->next) { - attrib * a = a_find(f->attribs, &at_number); - int want; - struct renum ** rn; - faction * old; - - if (!a) continue; - want = a->data.i; - if (fval(f, FFL_NEWID)) { - ADDMSG(&f->msgs, msg_message("renumber_twice", "id", want)); - continue; - } - old = findfaction(want); - if (old) { - a_remove(&f->attribs, a); - ADDMSG(&f->msgs, msg_message("renumber_inuse", "id", want)); - continue; - } - if (!faction_id_is_unused(want)) { - a_remove(&f->attribs, a); - ADDMSG(&f->msgs, msg_message("renumber_inuse", "id", want)); - continue; - } - for (rn=&renum; *rn; rn=&(*rn)->next) { - if ((*rn)->want>=want) break; - } - if (*rn && (*rn)->want==want) { - ADDMSG(&f->msgs, msg_message("renumber_inuse", "id", want)); - } else { - struct renum * r = calloc(sizeof(struct renum), 1); - r->next = *rn; - r->attrib = a; - r->faction = f; - r->want = want; - *rn = r; - } - } - for (rp=renum;rp;rp=rp->next) { - f = rp->faction; - a_remove(&f->attribs, rp->attrib); - renumber_faction(f, rp->want); - } - while (renum) { - rp = renum->next; - free(renum); - renum = rp; - } -} - -static void -reorder(void) -{ - region * r; - for (r=regions;r;r=r->next) { - unit ** up=&r->units; - boolean sorted=false; - while (*up) { - unit * u = *up; - if (!fval(u, UFL_MARK)) { - struct order * ord; - for (ord = u->orders;ord;ord=ord->next) { - if (get_keyword(ord)==K_SORT) { - const char * s; - param_t p; - int id; - unit *v; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - p = findparam(s, u->faction->locale); - id = getid(); - v = findunit(id); - - if (v==NULL || v->faction!=u->faction || v->region!=r) { - cmistake(u, ord, 258, MSG_EVENT); - } else if (v->building != u->building || v->ship!=u->ship) { - cmistake(u, ord, 259, MSG_EVENT); - } else if (fval(u, UFL_OWNER)) { - cmistake(u, ord, 260, MSG_EVENT); - } else if (v == u) { - cmistake(u, ord, 10, MSG_EVENT); - } else { - switch(p) { - case P_AFTER: - *up = u->next; - u->next = v->next; - v->next = u; - break; - case P_BEFORE: - if (fval(v, UFL_OWNER)) { - cmistake(v, ord, 261, MSG_EVENT); - } else { - unit ** vp=&r->units; - while (*vp!=v) vp=&(*vp)->next; - *vp = u; - *up = u->next; - u->next = v; - } - break; - } - fset(u, UFL_MARK); - sorted = true; - } - break; - } - } - } - if (u==*up) up=&u->next; - } - if (sorted) { - unit * u; - for (u=r->units;u;u=u->next) freset(u, UFL_MARK); - } - } -} - -#if 0 -/* Aus Gebäude weisen, VERBANNE */ -static void -evict(void) -{ - region *r; - strlist *S; - unit * u; - - for (r=regions;r;r=r->next) { - for (u=r->units;u;u=u->next) { - for (S = u->orders; S; S = S->next) if (get_keyword(ord)==K_EVICT) { - int id; - unit *u2; - /* Nur der Kapitän bzw Burgherr kann jemanden rausschmeißen */ - if(!fval(u, UFL_OWNER)) { - /* Die Einheit ist nicht der Eigentümer */ - cmistake(u,ord,49,MSG_EVENT); - continue; - } - init_tokens(ord); - skip_token(); - id = getid(); - u2 = findunit(id); - - if (u2==NULL) { - /* Einheit nicht gefunden */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - continue; - } - - if (u->building){ - /* in der selben Burg? */ - if (u->building != u2->building){ - /* nicht in Burg */ - cmistake(u,ord,33,MSG_EVENT); - continue; - } - leave_building(u2); - /* meldung an beide */ - } - - if (u->ship){ - if (u->ship != u2->ship){ - /* nicht an Bord */ - cmistake(u, ord, 32, MSG_EVENT); - continue; - } - leave_ship(u2); - /* meldung an beide */ - } - } - } - } -} -#endif - - -static int -renumber_cmd(unit * u, order * ord) -{ - const char * s; - int i; - faction * f = u->faction; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - switch(findparam(s, u->faction->locale)) { - - case P_FACTION: - s = getstrtoken(); - if (s && *s) { - int id = atoi36((const char *)s); - attrib * a = a_find(f->attribs, &at_number); - if (!a) a = a_add(&f->attribs, a_new(&at_number)); - a->data.i = id; - } - break; - - case P_UNIT: - s = getstrtoken(); - if (s == NULL || *s == 0) { - i = newunitid(); - } else { - i = atoi36((const char *)s); - if (i<=0 || i>MAX_UNIT_NR) { - cmistake(u, ord, 114, MSG_EVENT); - break; - } - - if (forbiddenid(i)) { - cmistake(u, ord, 116, MSG_EVENT); - break; - } - - if (findunitg(i, u->region)) { - cmistake(u, ord, 115, MSG_EVENT); - break; - } - } - uunhash(u); - if (!ualias(u)) { - attrib *a = a_add(&u->attribs, a_new(&at_alias)); - a->data.i = -u->no; - } - u->no = i; - uhash(u); - break; - - case P_SHIP: - if (!u->ship) { - cmistake(u, ord, 144, MSG_EVENT); - break; - } - if (u->ship->coast != NODIRECTION) { - cmistake(u, ord, 116, MSG_EVENT); - break; - } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 146, MSG_EVENT); - break; - } - s = getstrtoken(); - if (s == NULL || *s == 0) { - i = newcontainerid(); - } else { - i = atoi36((const char *)s); - if (i<=0 || i>MAX_CONTAINER_NR) { - cmistake(u,ord,114,MSG_EVENT); - break; - } - if (findship(i) || findbuilding(i)) { - cmistake(u, ord, 115, MSG_EVENT); - break; - } - } - sunhash(u->ship); - u->ship->no = i; - shash(u->ship); - break; - case P_BUILDING: - case P_GEBAEUDE: - if (!u->building) { - cmistake(u,ord,145,MSG_EVENT); - break; - } - if(!fval(u, UFL_OWNER)) { - cmistake(u,ord,148,MSG_EVENT); - break; - } - s = getstrtoken(); - if(*s == 0) { - i = newcontainerid(); - } else { - i = atoi36((const char *)s); - if (i<=0 || i>MAX_CONTAINER_NR) { - cmistake(u,ord,114,MSG_EVENT); - break; - } - if(findship(i) || findbuilding(i)) { - cmistake(u,ord,115,MSG_EVENT); - break; - } - } - bunhash(u->building); - u->building->no = i; - bhash(u->building); - break; - - default: - cmistake(u, ord, 239, MSG_EVENT); - } - return 0; -} - -static building * -age_building(building * b) -{ - static boolean init = false; - static const building_type * bt_blessed; - static const curse_type * ct_astralblock; - if (!init) { - init = true; - bt_blessed = bt_find("blessedstonecircle"); - ct_astralblock = ct_find("astralblock"); - } - - /* blesses stone circles create an astral protection in the astral region - * above the shield, which prevents chaos suction and other spells. - * The shield is created when a magician enters the blessed stone circle, - * and lasts for as long as his skill level / 2 is, at no mana cost. - * - * TODO: this would be nicer in a btype->age function, but we don't have it. - */ - if (ct_astralblock && bt_blessed && b->type==bt_blessed) { - region * r = b->region; - region * rt = r_standard_to_astral(r); - unit * u, * mage = NULL; - - if (fval(rt->terrain, FORBIDDEN_REGION)) rt = NULL; - /* step 1: give unicorns to people in the building, - * find out if there's a magician in there. */ - for (u=r->units;u;u=u->next) { - if (b==u->building && inside_building(u)) { - if (!(u->race->ec_flags & GIVEITEM)==0) { - int n, unicorns = 0; - for (n=0; n!=u->number; ++n) { - if (chance(0.02)) { - i_change(&u->items, olditemtype[I_ELVENHORSE], 1); - ++unicorns; - } - if (unicorns) { - ADDMSG(&u->faction->msgs, msg_message("scunicorn", - "unit amount rtype", u, unicorns, - olditemtype[I_ELVENHORSE]->rtype)); - } - } - } - if (mage==NULL && is_mage(u)) { - mage = u; - } - } - } - - /* if there's a magician, and a connection to astral space, create the - * curse. */ - if (rt!=NULL && mage!=NULL) { - curse * c = get_curse(rt->attribs, ct_astralblock); - if (c==NULL) { - if (mage!=NULL) { - int sk = effskill(mage, SK_MAGIC); - double effect; - effect = 100; - /* the mage reactivates the circle */ - c = create_curse(mage, &rt->attribs, ct_astralblock, - (float)MAX(1, sk), MAX(1, sk/2), effect, 0); - ADDMSG(&r->msgs, msg_message("astralshield_activate", - "region unit", r, mage)); - } - } else if (mage!=NULL) { - int sk = effskill(mage, SK_MAGIC); - c->duration = MAX(c->duration, sk/2); - c->vigour = MAX(c->vigour, sk); - } - } - } - - a_age(&b->attribs); - handle_event(b->attribs, "timer", b); - - if (b->type->age) { - b->type->age(b); - } - - return b; -} - -static double rc_popularity(const struct race * rc) -{ - int pop = get_param_int(rc->parameters, "morale", MORALE_AVERAGE); - return 1.0/(pop-MORALE_COOLDOWN); /* 10 turns average */ -} - -static void age_region(region * r) -{ - a_age(&r->attribs); - handle_event(r->attribs, "timer", r); - - if (!r->land) return; - - if (r->land->ownership && r->land->ownership->owner) { - int stability = turn - r->land->ownership->morale_turn; - int maxmorale = MORALE_DEFAULT; - building * b = largestbuilding(r, &cmp_taxes, false); - if (b) { - int bsize = buildingeffsize(b, false); - maxmorale = (int)(0.5 + b->type->taxes(b, bsize+1) / MORALE_TAX_FACTOR); - } - if (r->land->moraleMORALE_COOLDOWN && r->land->ownership->owner && r->land->moraleland->ownership->owner->race); - if (is_cursed(r->attribs, C_GENEROUS, 0)) { - ch *= 1.2; /* 20% improvement */ - } - if (stability>=MORALE_AVERAGE*2 || chance(ch)) { - region_set_morale(r, r->land->morale+1, turn); - } - } - } else if (r->land->morale>maxmorale) { - region_set_morale(r, r->land->morale-1, turn); - } - } else if (r->land->morale>MORALE_DEFAULT) { - region_set_morale(r, r->land->morale-1, turn); - } -} - -static void -ageing(void) -{ - faction *f; - region *r; - - /* altern spezieller Attribute, die eine Sonderbehandlung brauchen? */ - for(r=regions;r;r=r->next) { - unit *u; - - for (u=r->units;u;u=u->next) { - /* Goliathwasser */ - int i = get_effect(u, oldpotiontype[P_STRONG]); - if (i > 0){ - change_effect(u, oldpotiontype[P_STRONG], -1 * MIN(u->number, i)); - } - /* Berserkerblut*/ - i = get_effect(u, oldpotiontype[P_BERSERK]); - if (i > 0){ - change_effect(u, oldpotiontype[P_BERSERK], -1 * MIN(u->number, i)); - } - - if (is_cursed(u->attribs, C_OLDRACE, 0)){ - curse *c = get_curse(u->attribs, ct_find("oldrace")); - if (c->duration == 1 && !(c_flags(c) & CURSE_NOAGE)) { - u->race = new_race[curse_geteffect_int(c)]; - u->irace = NULL; - } - } - } - } - - /* Borders */ - age_borders(); - - /* Factions */ - for (f=factions;f;f=f->next) { - a_age(&f->attribs); - handle_event(f->attribs, "timer", f); - } - - /* Regionen */ - for (r=regions;r;r=r->next) { - building ** bp; - unit ** up; - ship ** sp; - - age_region(r); - - /* Einheiten */ - for (up=&r->units;*up;) { - unit * u = *up; - a_age(&u->attribs); - if (u==*up) handle_event(u->attribs, "timer", u); - if (u==*up) up = &(*up)->next; - } - - /* Schiffe */ - for (sp=&r->ships;*sp;) { - ship * s = *sp; - a_age(&s->attribs); - if (s==*sp) handle_event(s->attribs, "timer", s); - if (s==*sp) sp = &(*sp)->next; - } - - /* Gebäude */ - for (bp=&r->buildings;*bp;) { - building * b = *bp; - age_building(b); - if (b==*bp) bp = &b->next; - } - - if (rule_region_owners()) { - update_owners(r); - } - } -} - -static int -maxunits(const faction *f) -{ - int flimit = rule_faction_limit(); - int alimit = rule_alliance_limit(); - if (alimit==0) { - return flimit; - } - if (flimit==0) { - return alimit; - } - return MIN(alimit, flimit); -} - -int -checkunitnumber(const faction *f, int add) -{ - int alimit, flimit; - - alimit = rule_alliance_limit(); - if (alimit) { - /* if unitsperalliance is true, maxunits returns the - number of units allowed in an alliance */ - faction *f2; - int unitsinalliance = add; - - for (f2 = factions; f2; f2 = f2->next) { - if (f->alliance == f2->alliance) { - unitsinalliance += f2->no_units; - } - if (unitsinalliance > alimit) { - return 1; - } - } - } - - flimit = rule_faction_limit(); - if (flimit) { - if (f->no_units + add > flimit) { - return 2; - } - } - - return 0; -} - -static void -new_units(void) -{ - region *r; - unit *u, *u2; - - /* neue einheiten werden gemacht und ihre befehle (bis zum "ende" zu - * ihnen rueberkopiert, damit diese einheiten genauso wie die alten - * einheiten verwendet werden koennen. */ - - for (r = regions; r; r = r->next) { - for (u = r->units; u; u = u->next) { - order ** ordp = &u->orders; - - /* this needs to happen very early in the game somewhere. since this is - ** pretty much the first function called per turn, and I am lazy, I - ** decree that it goes here */ - if (u->flags&UFL_GUARD) { - fset(r, RF_GUARDED); - } - - while (*ordp) { - order * makeord = *ordp; - if (get_keyword(makeord) == K_MAKE) { - init_tokens(makeord); - skip_token(); - if (getparam(u->faction->locale) == P_TEMP) { - const char * token; - char * name = NULL; - 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 (get_keyword(ord) == K_END) break; - *ordp = ord->next; - ord->next = NULL; - free_order(ord); - } - continue; - } - alias = getid(); - - token = getstrtoken(); - if (token && token[0]) { - name = strdup(token); - } - u2 = create_unit(r, u->faction, 0, u->faction->race, alias, name, u); - if (name!=NULL) free(name); - 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 (get_keyword(ord) == K_END) break; - *ordp = ord->next; - ord->next = NULL; - *newordersp = ord; - newordersp = &ord->next; - } - } - } - if (*ordp==makeord) ordp=&makeord->next; - } - } - } -} - -static void -setdefaults(unit *u) -{ - order *ord; - boolean trade = false; - boolean hunger = LongHunger(u); - - freset(u, UFL_LONGACTION); - if (hunger) { - /* Hungernde Einheiten führen NUR den default-Befehl aus */ - set_order(&u->thisorder, default_order(u->faction->locale)); - } - /* check all orders for a potential new long order this round: */ - for (ord = u->orders; ord; ord = ord->next) { - if (u->old_orders && is_repeated(ord)) { - /* this new order will replace the old defaults */ - free_orders(&u->old_orders); - if (hunger) break; - } - if (hunger) continue; - - if (is_exclusive(ord)) { - /* Über dieser Zeile nur Befehle, die auch eine idle Faction machen darf */ - if (idle(u->faction)) { - set_order(&u->thisorder, default_order(u->faction->locale)); - } else { - set_order(&u->thisorder, copy_order(ord)); - } - break; - } else { - keyword_t keyword = get_keyword(ord); - switch (keyword) { - /* Wenn gehandelt wird, darf kein langer Befehl ausgeführt - * werden. Da Handel erst nach anderen langen Befehlen kommt, - * muß das vorher abgefangen werden. Wir merken uns also - * hier, ob die Einheit handelt. */ - case NOKEYWORD: - cmistake(u, ord, 22, MSG_EVENT); - break; - case K_BUY: - case K_SELL: - /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht - * werden. */ - trade = true; - break; - - case K_CAST: - /* dient dazu, das neben Zaubern kein weiterer Befehl - * ausgeführt werden kann, Zaubern ist ein kurzer Befehl */ - set_order(&u->thisorder, NULL); - break; - - case K_WEREWOLF: - set_order(&u->thisorder, copy_order(ord)); - break; - - /* Wird je diese Ausschliesslichkeit aufgehoben, muss man aufpassen - * mit der Reihenfolge von Kaufen, Verkaufen etc., damit es Spielern - * nicht moeglich ist, Schulden zu machen. */ - } - } - } - - if (hunger) return; - - /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht - * werden. */ - - if (trade == true) { - /* fset(u, UFL_LONGACTION|UFL_NOTMOVING); */ - set_order(&u->thisorder, NULL); - } -} - -static int -use_item(unit * u, const item_type * itype, int amount, struct order * ord) -{ - int i; - int target = read_unitid(u->faction, u->region); - - i = get_pooled(u, itype->rtype, GET_DEFAULT, amount); - - if (amount>i) { - amount = i; - } - if (amount==0) { - cmistake(u, ord, 43, MSG_PRODUCE); - return ENOITEM; - } - - if (target==-1) { - if (itype->use==NULL) { - cmistake(u, ord, 76, MSG_PRODUCE); - return EUNUSABLE; - } - return itype->use(u, itype, amount, ord); - } else { - if (itype->useonother==NULL) { - cmistake(u, ord, 76, MSG_PRODUCE); - return EUNUSABLE; - } - return itype->useonother(u, target, itype, amount, ord); - } -} - - -static double -heal_factor(const unit * u) -{ - static float elf_regen = -1; - switch(old_race(u->race)) { - case RC_TROLL: - case RC_DAEMON: - return 1.5; - case RC_GOBLIN: - return 2.0; - case RC_ELF: - if (elf_regen<0) elf_regen = get_param_flt(u->race->parameters, "regen.forest", 1.0F); - if (elf_regen!=1.0 && r_isforest(u->region)) { - return elf_regen; - } - return 1.0; - } - return 1.0; -} - -static void -monthly_healing(void) -{ - region *r; - static const curse_type * heal_ct = NULL; - if (heal_ct==NULL) heal_ct = ct_find("healingzone"); - - for (r = regions; r; r = r->next) { - unit *u; - double healingcurse = 0; - - if (heal_ct!=NULL) { - /* bonus zurücksetzen */ - curse * c = get_curse(r->attribs, heal_ct); - if (c!=NULL) { - healingcurse = curse_geteffect(c); - } - } - for (u = r->units; u; u = u->next) { - int umhp = unit_max_hp(u) * u->number; - double p = 1.0; - - /* hp über Maximum bauen sich ab. Wird zb durch Elixier der Macht - * oder verändertes Ausdauertalent verursacht */ - if (u->hp > umhp) { - u->hp -= (int) ceil((u->hp - umhp) / 2.0); - if (u->hp < umhp) u->hp = umhp; - continue; - } - - if (u->race->flags & RCF_NOHEAL) continue; - if (fval(u, UFL_HUNGER)) continue; - - if (fval(r->terrain, SEA_REGION) && u->ship==NULL && !(canswim(u) || canfly(u))) { - continue; - } - - p *= heal_factor(u); - if (u->hp < umhp) { -#ifdef NEW_DAEMONHUNGER_RULE - double maxheal = MAX(u->number, umhp/20.0); -#else - double maxheal = MAX(u->number, umhp/10.0); -#endif - int addhp; - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - if (btype == bt_find("inn")) { - p *= 1.5; - } - /* pro punkt 5% höher */ - p *= (1.0 + healingcurse * 0.05); - - maxheal = p * maxheal; - addhp = (int)maxheal; - maxheal -= addhp; - if (maxheal>0.0 && chance(maxheal)) ++addhp; - - /* Aufaddieren der geheilten HP. */ - u->hp = MIN(u->hp + addhp, umhp); - - /* soll man an negativer regeneration sterben können? */ - assert(u->hp > 0); - } - } - } -} - -static void -remove_exclusive(order ** ordp) -{ - while (*ordp) { - order * ord = *ordp; - if (is_exclusive(ord)) { - *ordp = ord->next; - ord->next = NULL; - free_order(ord); - } else { - ordp = &ord->next; - } - } -} - -static void -defaultorders (void) -{ - region *r; - for (r=regions;r;r=r->next) { - unit *u; - for (u=r->units;u;u=u->next) { - boolean neworders = false; - order ** ordp = &u->orders; - while (*ordp!=NULL) { - order * ord = *ordp; - if (get_keyword(ord)==K_DEFAULT) { - char lbuf[8192]; - order * new_order; - init_tokens(ord); - skip_token(); /* skip the keyword */ - strcpy(lbuf, getstrtoken()); - new_order = parse_order(lbuf, u->faction->locale); - *ordp = ord->next; - ord->next = NULL; - free_order(ord); - if (!neworders) { - /* lange Befehle aus orders und old_orders löschen zu gunsten des neuen */ - remove_exclusive(&u->orders); - remove_exclusive(&u->old_orders); - neworders = true; - ordp = &u->orders; /* we could have broken ordp */ - } - if (new_order) addlist(&u->old_orders, new_order); - } - else ordp = &ord->next; - } - } - } -} - -/* ************************************************************ */ -/* GANZ WICHTIG! ALLE GEÄNDERTEN SPRÜCHE NEU ANZEIGEN */ -/* GANZ WICHTIG! FÜGT AUCH NEUE ZAUBER IN DIE LISTE DER BEKANNTEN EIN */ -/* ************************************************************ */ -#define MAXMAGES 128 /* should be enough */ -static void -update_spells(void) -{ - faction * f; - - for (f=factions;f;f=f->next) { - if (f->magiegebiet!=M_NONE && !is_monsters(f)) { - unit * mages[MAXMAGES]; - unit *u; - int maxlevel = 0, n = 0, i; - - for (u=f->units;u;u=u->nextF) { - if (u->number>0) { - sc_mage *mage = get_mage(u); - if (mage) { - int level = eff_skill(u, SK_MAGIC, u->region); - if (level>maxlevel) maxlevel = level; - assert(nf->max_spelllevel) { - update_spellbook(f, maxlevel); - for (i=0;i!=n;++i) { - sc_mage *mage = get_mage(mages[i]); - while (mage->spells) { - spell_list * slist = mage->spells; - mage->spells = slist->next; - free(slist); - } - } - } - for (i=0;i!=n;++i) { - updatespelllist(mages[i]); - } - } - } -} - -static void -age_factions(void) -{ - faction *f; - - for (f = factions; f; f = f->next) { - ++f->age; - if (f->age+1 < NewbieImmunity()) { - ADDMSG(&f->msgs, msg_message("newbieimmunity", "turns", - NewbieImmunity() - f->age - 1)); - } - } -} - -static int -use_cmd(unit * u, struct order * ord) -{ - const char * t; - int n; - const item_type * itype; - - init_tokens(ord); - skip_token(); - - t = getstrtoken(); - n = atoi((const char *)t); - if (n==0) { - if (findparam(t, u->faction->locale) == P_ANY) { - /* BENUTZE ALLES Yanxspirit */ - n = INT_MAX; - t = getstrtoken(); - } else { - /* BENUTZE Yanxspirit */ - n = 1; - } - } else { - /* BENUTZE 42 Yanxspirit */ - t = getstrtoken(); - } - itype = finditemtype(t, u->faction->locale); - - if (itype!=NULL) { - int i = use_item(u, itype, n, ord); - assert(i<=0 || !"use_item should not return positive values."); - if (i>0) { - log_error(("use_item returned a value>0 for %s\n", resourcename(itype->rtype, 0))); - } - } else { - cmistake(u, ord, 43, MSG_PRODUCE); - } - return 0; -} - -static int -pay_cmd(unit * u, struct order * ord) -{ - if (!u->building) { - cmistake(u, ord, 6, MSG_EVENT); - } else { - param_t p; - init_tokens(ord); - skip_token(); - p = getparam(u->faction->locale); - if (p==P_NOT) { - unit * owner = building_owner(u->building); - if (owner->faction!=u->faction) { - cmistake(u, ord, 1222, MSG_EVENT); - } else { - u->building->flags |= BLD_DONTPAY; - } - } - } - return 0; -} - -static int -claim_cmd(unit * u, struct order * ord) -{ - const char * t; - int n; - const item_type * itype; - - init_tokens(ord); - skip_token(); - - t = getstrtoken(); - n = atoi((const char *)t); - if (n==0) { - n = 1; - } else { - t = getstrtoken(); - } - itype = finditemtype(t, u->faction->locale); - - if (itype!=NULL) { - item ** iclaim = i_find(&u->faction->items, itype); - if (iclaim!=NULL && *iclaim!=NULL) { - n = MIN(n, (*iclaim)->number); - i_change(iclaim, itype, -n); - i_change(&u->items, itype, n); - } - } else { - cmistake(u, ord, 43, MSG_PRODUCE); - } - return 0; -} - -enum { - PROC_THISORDER = 1<<0, - PROC_LONGORDER = 1<<1 -}; -typedef struct processor { - struct processor * next; - int priority; - enum { PR_GLOBAL, PR_REGION_PRE, PR_UNIT, PR_ORDER, PR_REGION_POST } type; - unsigned int flags; - union { - struct { - keyword_t kword; - int (*process)(struct unit *, struct order *); - } per_order; - struct { - void (*process)(struct unit *); - } per_unit; - struct { - void (*process)(struct region *); - } per_region; - struct { - void (*process)(void); - } global; - } data; - const char * name; -} processor; - -static processor * processors; - -processor * -add_proc(int priority, const char * name, int type) -{ - processor **pproc = &processors; - processor *proc; - - while (*pproc) { - proc = *pproc; - if (proc->priority>priority) break; - else if (proc->priority==priority && proc->type>=type) break; - pproc = &proc->next; - } - - proc = malloc(sizeof(processor)); - proc->priority = priority; - proc->type = type; - proc->name = name; - proc->next = *pproc; - *pproc = proc; - return proc; -} - -void -add_proc_order(int priority, keyword_t kword, int (*parser)(struct unit *, struct order *), unsigned int flags, const char * name) -{ - if (!global.disabled[kword]) { - processor * proc = add_proc(priority, name, PR_ORDER); - if (proc) { - proc->data.per_order.process = parser; - proc->data.per_order.kword = kword; - proc->flags = flags; - } - } -} - -void -add_proc_global(int priority, void (*process)(void), const char * name) -{ - processor * proc = add_proc(priority, name, PR_GLOBAL); - if (proc) { - proc->data.global.process = process; - } -} - -void -add_proc_region(int priority, void (*process)(region *), const char * name) -{ - processor * proc = add_proc(priority, name, PR_REGION_PRE); - if (proc) { - proc->data.per_region.process = process; - } -} - -void -add_proc_postregion(int priority, void (*process)(region *), const char * name) -{ - processor * proc = add_proc(priority, name, PR_REGION_POST); - if (proc) { - proc->data.per_region.process = process; - } -} - -void -add_proc_unit(int priority, void (*process)(unit *), const char * name) -{ - processor * proc = add_proc(priority, name, PR_UNIT); - if (proc) { - proc->data.per_unit.process = process; - } -} - -/* per priority, execute processors in order from PR_GLOBAL down to PR_ORDER */ -void -process(void) -{ - processor *proc = processors; - faction * f; - - while (proc) { - int prio = proc->priority; - region *r; - processor *pglobal = proc; - - if (verbosity>=3) printf("- Step %u\n", prio); - while (proc && proc->priority==prio) { - if (proc->name && verbosity>=1) log_stdio(stdout, " - %s\n", proc->name); - proc = proc->next; - } - - while (pglobal && pglobal->priority==prio && pglobal->type==PR_GLOBAL) { - pglobal->data.global.process(); - pglobal = pglobal->next; - } - if (pglobal==NULL || pglobal->priority!=prio) continue; - - for (r = regions; r; r = r->next) { - unit *u; - processor *pregion = pglobal; - - while (pregion && pregion->priority==prio && pregion->type==PR_REGION_PRE) { - pregion->data.per_region.process(r); - pregion = pregion->next; - } - if (pregion==NULL || pregion->priority!=prio) continue; - - if (r->units) { - for (u=r->units;u;u=u->next) { - processor *porder, *punit = pregion; - - while (punit && punit->priority==prio && punit->type==PR_UNIT) { - punit->data.per_unit.process(u); - punit = punit->next; - } - if (punit==NULL || punit->priority!=prio) continue; - - porder = punit; - while (porder && porder->priority==prio && porder->type==PR_ORDER) { - order ** ordp = &u->orders; - if (porder->flags & PROC_THISORDER) ordp = &u->thisorder; - while (*ordp) { - order * ord = *ordp; - if (get_keyword(ord) == porder->data.per_order.kword) { - if (porder->flags & PROC_LONGORDER) { - if (u->number==0) { - ord = NULL; - } else if (u->race == new_race[RC_INSECT] && r_insectstalled(r) && !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) { - ord = NULL; - } else if (LongHunger(u)) { - cmistake(u, ord, 224, MSG_MAGIC); - ord = NULL; - } else if (fval(u, UFL_LONGACTION)) { - cmistake(u, ord, 52, MSG_PRODUCE); - ord = NULL; - } else if (fval(r->terrain, SEA_REGION) && u->race != new_race[RC_AQUARIAN] && !(u->race->flags & RCF_SWIM)) { - /* error message disabled by popular demand */ - ord = NULL; - } - } - if (ord) { - porder->data.per_order.process(u, ord); - } - } - if (!ord || *ordp==ord) ordp=&(*ordp)->next; - } - porder = porder->next; - } - } - } - - while (pregion && pregion->priority==prio && pregion->type!=PR_REGION_POST) { - pregion = pregion->next; - } - - while (pregion && pregion->priority==prio && pregion->type==PR_REGION_POST) { - pregion->data.per_region.process(r); - pregion = pregion->next; - } - if (pregion==NULL || pregion->priority!=prio) continue; - - } - } - - if (verbosity>=3) printf("\n - Leere Gruppen loeschen...\n"); - for (f=factions; f; f=f->next) { - group ** gp = &f->groups; - while (*gp) { - group * g = *gp; - if (g->members==0) { - *gp = g->next; - free_group(g); - } else - gp = &g->next; - } - } - -} - -static void enter_1(region * r) { do_misc(r, false); } -static void enter_2(region * r) { do_misc(r, true); } -static void maintain_buildings_1(region * r) { maintain_buildings(r, false); } -#ifdef COLLAPSE_CHANCE -static void maintain_buildings_2(region * r) { maintain_buildings(r,true); } -#endif -static void reset_moved(unit * u) { freset(u, UFL_MOVED); } - -/** warn about passwords that are not US ASCII. - * even though passwords are technically UTF8 strings, the server receives - * them as part of the Subject of an email when reports are requested. - * This means that we need to limit them to ASCII characters until that - * mechanism has been changed. - */ -static int -warn_password(void) -{ - faction * f = factions; - while (f) { - boolean pwok = true; - const char * c = f->passw; - while (*c && pwok) { - if (!isalnum((unsigned char)*c)) pwok = false; - c++; - } - if (!pwok) { - free(f->passw); - f->passw = strdup(itoa36(rng_int())); - ADDMSG(&f->msgs, msg_message("illegal_password", "newpass", f->passw)); - } - f = f->next; - } - return 0; -} - -void -init_processor(void) -{ - int p; - - p = 10; - add_proc_global(p, &new_units, "Neue Einheiten erschaffen"); - - p+=10; - add_proc_unit(p, &setdefaults, "Default-Befehle"); - add_proc_order(p, K_BANNER, &banner_cmd, 0, NULL); - add_proc_order(p, K_EMAIL, &email_cmd, 0, NULL); - add_proc_order(p, K_PASSWORD, &password_cmd, 0, NULL); - add_proc_order(p, K_SEND, &send_cmd, 0, NULL); - add_proc_order(p, K_GROUP, &group_cmd, 0, NULL); - - p+=10; - add_proc_unit(p, &reset_moved, "Instant-Befehle"); - add_proc_order(p, K_QUIT, &quit_cmd, 0, NULL); - add_proc_order(p, K_URSPRUNG, &origin_cmd, 0, NULL); - add_proc_order(p, K_ALLY, &ally_cmd, 0, NULL); - add_proc_order(p, K_PREFIX, &prefix_cmd, 0, NULL); - add_proc_order(p, K_SETSTEALTH, &setstealth_cmd, 0, NULL); - add_proc_order(p, K_STATUS, &status_cmd, 0, NULL); - add_proc_order(p, K_COMBATSPELL, &combatspell_cmd, 0, NULL); - add_proc_order(p, K_DISPLAY, &display_cmd, 0, NULL); - add_proc_order(p, K_NAME, &name_cmd, 0, NULL); - add_proc_order(p, K_GUARD, &guard_off_cmd, 0, NULL); - add_proc_order(p, K_RESHOW, &reshow_cmd, 0, NULL); - - if (get_param_int(global.parameters, "rules.alliances", 0)==1) { - p+=10; - add_proc_global(p, &alliance_cmd, NULL); - } - - p+=10; - add_proc_global(p, &age_factions, "Parteienalter++"); - add_proc_order(p, K_MAIL, &mail_cmd, 0, "Botschaften"); - - p+=10; /* all claims must be done before we can USE */ - add_proc_region(p, &enter_1, "Kontaktieren & Betreten (1. Versuch)"); - add_proc_order(p, K_USE, &use_cmd, 0, "Benutzen"); - - if (!global.disabled[K_GM]) { - add_proc_global(p, &gmcommands, "GM Kommandos"); - } - - p += 10; /* in case it has any effects on alliance victories */ - add_proc_order(p, K_GIVE, &give_control_cmd, 0, "GIB KOMMANDO"); - - p += 10; /* in case it has any effects on alliance victories */ - add_proc_order(p, K_LEAVE, &leave_cmd, 0, "Verlassen"); - - if (!nobattle) { - add_proc_region(p, &do_battle, "Attackieren"); - } - - if (!global.disabled[K_BESIEGE]) { - p+=10; - add_proc_region(p, &do_siege, "Belagern"); - } - - p+=10; /* can't allow reserve before siege (weapons) */ - add_proc_region(p, &enter_1, "Kontaktieren & Betreten (2. Versuch)"); - add_proc_order(p, K_RESERVE, &reserve_cmd, 0, "Reservieren"); - add_proc_order(p, K_CLAIM, &claim_cmd, 0, NULL); - add_proc_unit(p, &follow_unit, "Folge auf Einheiten setzen"); - - p+=10; /* rest rng again before economics */ - add_proc_region(p, &economics, "Zerstoeren, Geben, Rekrutieren, Vergessen"); - - p+=10; - if (!global.disabled[K_PAY]) { - add_proc_order(p, K_PAY, &pay_cmd, 0, "Gebaeudeunterhalt (disable)"); - } - add_proc_postregion(p, &maintain_buildings_1, "Gebaeudeunterhalt (1. Versuch)"); - - p+=10; /* QUIT fuer sich alleine */ - add_proc_global(p, &quit, "Sterben"); - if (!global.disabled[K_RESTART]) { - add_proc_global(p, &parse_restart, "Neustart"); - } - - if (!global.disabled[K_CAST]) { - p+=10; - add_proc_global(p, &magic, "Zaubern"); - } - - p+=10; - add_proc_order(p, K_TEACH, &teach_cmd, PROC_THISORDER|PROC_LONGORDER, "Lehren"); - p+=10; - add_proc_order(p, K_STUDY, &learn_cmd, PROC_THISORDER|PROC_LONGORDER, "Lernen"); - - p+=10; - add_proc_order(p, K_MAKE, &make_cmd, PROC_THISORDER|PROC_LONGORDER, "Produktion"); - add_proc_postregion(p, &produce, "Arbeiten, Handel, Rekruten"); - add_proc_postregion(p, &split_allocations, "Produktion II"); - - p+=10; - add_proc_region(p, &enter_2, "Kontaktieren & Betreten (3. Versuch)"); - - p+=10; - add_proc_region(p, &sinkships, "Schiffe sinken"); - - p+=10; - add_proc_global(p, &movement, "Bewegungen"); - - if (get_param_int(global.parameters, "work.auto", 0)) { - p+=10; - add_proc_region(p, &auto_work, "Arbeiten (auto)"); - } - - p+=10; - add_proc_order(p, K_GUARD, &guard_on_cmd, 0, "Bewache (an)"); -#if XECMD_MODULE - /* can do together with guard */ - add_proc_order(p, K_XE, &xecmd, 0, "Zeitung"); -#endif - - p+=10; - add_proc_global(p, &encounters, "Zufallsbegegnungen"); - p+=10; - add_proc_unit(p, &monster_kills_peasants, "Monster fressen und vertreiben Bauern"); - - p+=10; - add_proc_global(p, &randomevents, "Zufallsereignisse"); - - p+=10; - - add_proc_global(p, &monthly_healing, "Regeneration (HP)"); - add_proc_global(p, ®eneration_magiepunkte, "Regeneration (Aura)"); - if (!global.disabled[K_DEFAULT]) { - add_proc_global(p, &defaultorders, "Defaults setzen"); - } - add_proc_global(p, &demographics, "Nahrung, Seuchen, Wachstum, Wanderung"); - -#ifdef COLLAPSE_CHANCE - p+=10; - add_proc_region(p, &maintain_buildings_2, "Gebaeudeunterhalt (2. Versuch)"); -#endif - - if (!global.disabled[K_SORT]) { - p+=10; - add_proc_global(p, &reorder, "Einheiten sortieren"); - } - add_proc_order(p, K_PROMOTION, &promotion_cmd, 0, "Heldenbefoerderung"); - if (!global.disabled[K_NUMBER]) { - add_proc_order(p, K_NUMBER, &renumber_cmd, 0, "Neue Nummern (Einheiten)"); - p+=10; - add_proc_global(p, &renumber_factions, "Neue Nummern"); - } -} - -void -processorders (void) -{ - static int init = 0; - - if (!init) { - init_processor(); - init = 1; - } - update_spells(); - process(); - /*************************************************/ - - if (get_param_int(global.parameters, "modules.markets", 0)) { - do_markets(); - } - - if (verbosity>=1) puts(" - Attribute altern"); - ageing(); - remove_empty_units(); - - /* must happen AFTER age, because that would destroy them right away */ - if (get_param_int(global.parameters, "modules.wormholes", 0)) { - create_wormholes(); - } - - /* immer ausführen, wenn neue Sprüche dazugekommen sind, oder sich - * Beschreibungen geändert haben */ - update_spells(); - warn_password(); -} - -int -writepasswd(void) -{ - FILE * F; - char zText[128]; - - sprintf(zText, "%s/passwd", basepath()); - F = cfopen(zText, "w"); - if (F) { - faction *f; - puts("writing passwords..."); - - for (f = factions; f; f = f->next) { - fprintf(F, "%s:%s:%s:%s:%u\n", - factionid(f), f->email, f->passw, f->override, f->subscription); - } - fclose(F); - return 0; - } - return 1; -} - -void -update_subscriptions(void) -{ - FILE * F; - char zText[MAX_PATH]; - faction * f; - strcat(strcpy(zText, basepath()), "/subscriptions"); - F = fopen(zText, "r"); - if (F==NULL) { - log_warning((0, "could not open %s.\n", zText)); - return; - } - for (;;) { - char zFaction[5]; - int subscription, fno; - if (fscanf(F, "%d %s", &subscription, zFaction)<=0) break; - fno = atoi36(zFaction); - f = findfaction(fno); - if (f!=NULL) { - f->subscription=subscription; - } - } - fclose(F); - - sprintf(zText, "subscriptions.%u", turn); - F = fopen(zText, "w"); - for (f=factions;f!=NULL;f=f->next) { - fprintf(F, "%s:%u:%s:%s:%s:%u:\n", - itoa36(f->no), f->subscription, f->email, f->override, - dbrace(f->race), f->lastorders); - } - fclose(F); -} - -int -init_data(const char * filename, const char * catalog) -{ - int l; - - l = read_xml(filename, catalog); - if (l) return l; - - init_locales(); - init_archetypes(); - - if (turn<0) { - turn = first_turn; - } - return 0; -} - -#ifndef DISABLE_TESTS -#include "laws_test.c" -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#pragma region includes + +#include +#include +#include "laws.h" + +#include +#include + +/* gamecode includes */ +#include "economy.h" +#include "archetype.h" +#include "monster.h" +#include "randenc.h" +#include "spy.h" +#include "study.h" +#include "market.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for volcanoes in emigration (needs a flag) */ +#include + +/* attributes includes */ +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#pragma endregion + +/* chance that a peasant dies of starvation: */ +#define PEASANT_STARVATION_CHANCE 0.9F +/* Pferdevermehrung */ +#define HORSEGROWTH 4 +/* Wanderungschance pro Pferd */ +#define HORSEMOVE 3 +/* Vermehrungschance pro Baum */ +#define FORESTGROWTH 10000 /* In Millionstel */ + +/** Ausbreitung und Vermehrung */ +#define MAXDEMAND 25 +#define DMRISE 0.1F /* weekly chance that demand goes up */ +#define DMRISEHAFEN 0.2F /* weekly chance that demand goes up with harbor */ + + +/* - exported global symbols ----------------------------------- */ +boolean nobattle = false; +boolean nomonsters = false; +/* ------------------------------------------------------------- */ + +static int +RemoveNMRNewbie(void) { + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "nmr.removenewbie", 0); + } + return value; +} + +static void +restart_race(unit *u, const race * rc) +{ + faction * oldf = u->faction; + faction *f = addfaction(oldf->email, oldf->passw, rc, oldf->locale, oldf->subscription); + unit * nu = addplayer(u->region, f); + order ** ordp = &u->orders; + f->subscription = u->faction->subscription; + f->age = u->faction->age; + fset(f, FFL_RESTART); + if (f->subscription) { + sql_print(("UPDATE subscriptions set faction='%s', race='%s' where id=%u;\n", + itoa36(f->no), dbrace(rc), f->subscription)); + } + f->magiegebiet = u->faction->magiegebiet; + f->options = u->faction->options; + free_orders(&nu->orders); + nu->orders = u->orders; + u->orders = NULL; + while (*ordp) { + order * ord = *ordp; + if (get_keyword(ord) != K_RESTART) { + *ordp = ord->next; + ord->next = NULL; + if (u->thisorder == ord) set_order(&u->thisorder, NULL); + } else { + ordp = &ord->next; + } + } + destroyfaction(u->faction); +} + +static void +checkorders(void) +{ + faction *f; + + if (verbosity>=1) puts(" - Warne spaete Spieler..."); + for (f = factions; f; f = f->next) + if (!is_monsters(f) && turn - f->lastorders == NMRTimeout() - 1) + ADDMSG(&f->msgs, msg_message("turnreminder", "")); +} + +static boolean +help_money(const unit * u) +{ + if (u->race->ec_flags & GIVEITEM) return true; + return false; +} + +static void +help_feed(unit * donor, unit * u, int * need_p) +{ + int need = *need_p; + int give = get_money(donor) - lifestyle(donor); + give = MIN(need, give); + + if (give>0) { + change_money(donor, -give); + change_money(u, give); + need -= give; + add_spende(donor->faction, u->faction, give, donor->region); + } + *need_p = need; +} + +static void +get_food(region *r) +{ + plane * pl = rplane(r); + unit *u; + int peasantfood = rpeasants(r)*10; + static int food_rules = -1; + + if (food_rules<0) { + food_rules = get_param_int(global.parameters, "rules.economy.food", 0); + } + + /* 1. Versorgung von eigenen Einheiten. Das vorhandene Silber + * wird zunächst so auf die Einheiten aufgeteilt, dass idealerweise + * jede Einheit genug Silber für ihren Unterhalt hat. */ + + for (u = r->units; u; u = u->next) { + int need = lifestyle(u); + + /* Erstmal zurücksetzen */ + freset(u, UFL_HUNGER); + + if (u->ship && (u->ship->flags&SF_FISHING)) { + unit * v; + int c = 2; + for (v=u;c>0 && v;v=v->next) { + if (v->ship==u->ship) { + int get = 0; + if (v->number<=c) { + get = lifestyle(v); + } else { + get = lifestyle(v) * c / v->number; + } + if (get) { + change_money(v, get); + } + } + c -= v->number; + } + u->ship->flags -= SF_FISHING; + } + + if (food_rules&1) { + faction * owner = region_get_owner(r); + /* if the region is owned, and the owner is nice, then we'll get + * food from the peasants - should not be used with WORK */ + if (owner!=NULL && (get_alliance(owner, u->faction) & HELP_MONEY)) { + int rm = rmoney(r); + int use = MIN(rm, need); + rsetmoney(r, rm-use); + need -= use; + } + } + + need -= get_money(u); + if (need > 0) { + unit *v; + + for (v = r->units; need && v; v = v->next) { + if (v->faction == u->faction && help_money(v)) { + int give = get_money(v) - lifestyle(v); + give = MIN(need, give); + if (give>0) { + change_money(v, -give); + change_money(u, give); + need -= give; + } + } + } + } + } + + /* 2. Versorgung durch Fremde. Das Silber alliierter Einheiten wird + * entsprechend verteilt. */ + for (u = r->units; u; u = u->next) { + int need = lifestyle(u); + faction * f = u->faction; + + need -= MAX(0, get_money(u)); + + if (need > 0) { + unit *v; + + if (food_rules&2) { + /* the owner of the region is the first faction to help out when you're hungry */ + faction * owner = region_get_owner(r); + if (owner && owner!=u->faction) { + for (v=r->units;v;v=v->next) { + if (v->faction==owner && alliedunit(v, f, HELP_MONEY) && help_money(v)) { + help_feed(v, u, &need); + break; + } + } + } + } + for (v = r->units; need && v; v = v->next) { + if (v->faction != f && alliedunit(v, f, HELP_MONEY) && help_money(v)) { + help_feed(v, u, &need); + } + } + + /* Die Einheit hat nicht genug Geld zusammengekratzt und + * nimmt Schaden: */ + if (need > 0) { + int lspp = lifestyle(u)/u->number; + if (lspp > 0) { + int number = (need+lspp-1)/lspp; + if (hunger(number, u)) fset(u, UFL_HUNGER); + } + } + } + } + + /* 3. bestimmen, wie viele Bauern gefressen werden. + * bei fehlenden Bauern den Dämon hungern lassen + */ + for (u = r->units; u; u = u->next) { + if (u->race == new_race[RC_DAEMON]) { + unit * donor = r->units; + int hungry = u->number; + + while (donor!=NULL && hungry>0) { + /* always start with the first known unit that may have some blood */ + static const struct potion_type * pt_blood; + if (pt_blood==NULL) { + const item_type * it_blood = it_find("peasantblood"); + if (it_blood) pt_blood = it_blood->rtype->ptype; + } + if (pt_blood!=NULL) { + while (donor!=NULL) { + if (donor->race==new_race[RC_DAEMON]) { + if (get_effect(donor, pt_blood)) { + /* if he's in our faction, drain him: */ + if (donor->faction==u->faction) break; + } + } + donor = donor->next; + } + if (donor != NULL) { + int blut = get_effect(donor, pt_blood); + blut = MIN(blut, hungry); + change_effect(donor, pt_blood, -blut); + hungry -= blut; + } + } + } + if (pl == NULL || !fval(pl, PFL_NOFEED)) { + if (peasantfood>=hungry) { + peasantfood -= hungry; + hungry = 0; + } else { + hungry -= peasantfood; + peasantfood = 0; + } + if (hungry > 0) { + static int demon_hunger = -1; + if (demon_hunger<0) { + demon_hunger = get_param_int(global.parameters, "hunger.demons", 0); + } + if (demon_hunger==0) { + /* nicht gefütterte dämonen hungern */ +#ifdef PEASANT_HUNGRY_DAEMONS_HAVE_FULL_SKILLS + /* wdw special rule */ + hunger(hungry, u); +#else + if (hunger(hungry, u)) fset(u, UFL_HUNGER); +#endif + /* used to be: hunger(hungry, u); */ + } else { + /* no damage, but set the hungry-flag */ + fset(u, UFL_HUNGER); + } + } + } + } + } + rsetpeasants(r, peasantfood/10); + + /* 3. Von den überlebenden das Geld abziehen: */ + for (u = r->units; u; u = u->next) { + int need = MIN(get_money(u), lifestyle(u)); + change_money(u, -need); + } +} + +static void +age_unit(region * r, unit * u) +{ + if (u->race == new_race[RC_SPELL]) { + if (--u->age <= 0) { + remove_unit(&r->units, u); + } + } else { + ++u->age; + if (u->number>0 && u->race->age) { + u->race->age(u); + } + } +#ifdef ASTRAL_ITEM_RESTRICTIONS + if (u->region && is_astral(u->region)) { + item ** itemp = &u->items; + while (*itemp) { + item * itm = *itemp; + if ((itm->type->flags & ITF_NOTLOST) == 0) { + if (itm->type->flags & (ITF_BIG|ITF_ANIMAL|ITF_CURSED)) { + ADDMSG(&u->faction->msgs, msg_message("itemcrumble", "unit region item amount", + u, u->region, itm->type->rtype, itm->number)); + i_free(i_remove(itemp, itm)); + continue; + } + } + itemp=&itm->next; + } + } +#endif +} + + +static void +live(region * r) +{ + unit **up = &r->units; + + get_food(r); + + while (*up) { + unit * u = *up; + /* IUW: age_unit() kann u loeschen, u->next ist dann + * undefiniert, also muessen wir hier schon das nächste + * Element bestimmen */ + + int effect = get_effect(u, oldpotiontype[P_FOOL]); + if (effect > 0) { /* Trank "Dumpfbackenbrot" */ + skill * sv = u->skills, * sb = NULL; + while (sv!=u->skills+u->skill_size) { + if (sb==NULL || skill_compare(sv, sb)>0) { + sb = sv; + } + ++sv; + } + /* bestes Talent raussuchen */ + if (sb!=NULL) { + int weeks = MIN(effect, u->number); + reduce_skill(u, sb, weeks); + ADDMSG(&u->faction->msgs, msg_message("dumbeffect", + "unit weeks skill", u, weeks, (skill_t)sb->id)); + } /* sonst Glück gehabt: wer nix weiß, kann nix vergessen... */ + change_effect(u, oldpotiontype[P_FOOL], -effect); + } + age_unit(r, u); + if (*up==u) up=&u->next; + } +} + +/* + * This procedure calculates the number of emigrating peasants for the given + * region r. There are two incentives for peasants to emigrate: + * 1) They prefer the less crowded areas. + * Example: mountains, 700 peasants (max 1000), 70% inhabited + * plain, 5000 peasants (max 10000), 50% inhabited + * 700*(PEASANTSWANDER_WEIGHT/100)*((70-50)/100) peasants wander + * from mountains to plain. + * Effect : peasents will leave densely populated regions. + * 2) Peasants prefer richer neighbour regions. + * Example: region A, 700 peasants, wealth $10500, $15 per head + * region B, 2500 peasants, wealth $25000, $10 per head + * Some peasants will emigrate from B to A because $15 > $10 + * exactly: 2500*(PEASANTSGREED_WEIGHT1/100)*((15-10)/100) + * Not taken in consideration: + * - movement because of monsters. + * - movement because of wars + * - movement because of low loyalty relating to present parties. + */ + +#define MAX_EMIGRATION(p) ((p)/MAXDIRECTIONS) +#define MAX_IMMIGRATION(p) ((p)*2/3) + +static void +calculate_emigration(region *r) +{ + int i; + int maxp = maxworkingpeasants(r); + int rp = rpeasants(r); + int max_immigrants = MAX_IMMIGRATION(maxp-rp); + + if (r->terrain == newterrain(T_VOLCANO) || r->terrain == newterrain(T_VOLCANO_SMOKING)) { + max_immigrants = max_immigrants/10; + } + + for (i = 0; max_immigrants>0 && i != MAXDIRECTIONS; i++) { + int dir = (turn+i) % MAXDIRECTIONS; + region *rc = rconnect(r, (direction_t)dir); + + if (rc != NULL && fval(rc->terrain, LAND_REGION)) { + int rp2 = rpeasants(rc); + int maxp2 = maxworkingpeasants(rc); + int max_emigration = MAX_EMIGRATION(rp2-maxp2); + + if (max_emigration>0) { + max_emigration = MIN(max_emigration, max_immigrants); + r->land->newpeasants += max_emigration; + rc->land->newpeasants -= max_emigration; + max_immigrants -= max_emigration; + } + } + } +} + +/** Bauern vermehren sich */ + +static void +peasants(region * r) +{ + int peasants = rpeasants(r); + int money = rmoney(r); + int maxp = production(r) * MAXPEASANTS_PER_AREA; + int n, satiated; + int dead = 0; + + /* Bis zu 1000 Bauern können Zwillinge bekommen oder 1000 Bauern + * wollen nicht! */ + + if (peasants>0) { + int glueck = 0; + double fraction = peasants * 0.0001F * PEASANTGROWTH; + int births = (int)fraction; + attrib * a = a_find(r->attribs, &at_peasantluck); + + if (rng_double()<(fraction-births)) { + /* because we don't want regions that never grow pga. rounding. */ + ++births; + } + if (a!=NULL) { + glueck = a->data.i * 1000; + } + + for (n = peasants; n; --n) { + int chances = 0; + + if (glueck>0) { + --glueck; + chances += PEASANTLUCK; + } + + while (chances--) { + if (rng_int() % 10000 < PEASANTGROWTH) { + /* Only raise with 75% chance if peasants have + * reached 90% of maxpopulation */ + if (peasants/(float)maxp < 0.9 || chance(PEASANTFORCE)) { + ++births; + } + } + } + } + peasants += births; + } + + /* Alle werden satt, oder halt soviele für die es auch Geld gibt */ + + satiated = MIN(peasants, money / maintenance_cost(NULL)); + rsetmoney(r, money - satiated * maintenance_cost(NULL)); + + /* Von denjenigen, die nicht satt geworden sind, verhungert der + * Großteil. dead kann nie größer als rpeasants(r) - satiated werden, + * so dass rpeasants(r) >= 0 bleiben muß. */ + + /* Es verhungert maximal die unterernährten Bevölkerung. */ + + n = MIN(peasants - satiated, rpeasants(r)); + dead += (int)(0.5F + n * PEASANT_STARVATION_CHANCE); + + if (dead > 0) { + message * msg = add_message(&r->msgs, msg_message("phunger", "dead", dead)); + msg_release(msg); + peasants -= dead; + } + + rsetpeasants(r, peasants); +} + +/* ------------------------------------------------------------- */ + +typedef struct migration { + struct migration * next; + region * r; + int horses; + int trees; +} migration; + +#define MSIZE 1023 +migration * migrants[MSIZE]; +migration * free_migrants; + +static migration * +get_migrants(region * r) +{ + int key = reg_hashkey(r); + int index = key % MSIZE; + migration * m = migrants[index]; + while (m && m->r != r) + m = m->next; + if (m == NULL) { + /* Es gibt noch keine Migration. Also eine erzeugen + */ + m = free_migrants; + if (!m) m = calloc(1, sizeof(migration)); + else { + free_migrants = free_migrants->next; + m->horses = 0; + m->trees = 0; + } + m->r = r; + m->next = migrants[index]; + migrants[index] = m; + } + return m; +} + +static void +migrate(region * r) +{ + int key = reg_hashkey(r); + int index = key % MSIZE; + migration ** hp = &migrants[index]; + fset(r, RF_MIGRATION); + while (*hp && (*hp)->r != r) hp = &(*hp)->next; + if (*hp) { + migration * m = *hp; + rsethorses(r, rhorses(r) + m->horses); + /* Was macht das denn hier? + * Baumwanderung wird in trees() gemacht. + * wer fragt das? Die Baumwanderung war abhängig von der + * Auswertungsreihenfolge der regionen, + * das hatte ich geändert. jemand hat es wieder gelöscht, toll. + * ich habe es wieder aktiviert, muß getestet werden. + */ + *hp = m->next; + m->next = free_migrants; + free_migrants = m; + } +} + +static void +horses(region * r) +{ + int horses, maxhorses; + direction_t n; + + /* Logistisches Wachstum, Optimum bei halbem Maximalbesatz. */ + maxhorses = maxworkingpeasants(r)/10; + maxhorses = MAX(0, maxhorses); + horses = rhorses(r); + if (horses > 0) { + if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { + rsethorses(r, (int)(horses*0.9F)); + } else if (maxhorses) { + int i; + double growth = (RESOURCE_QUANTITY * HORSEGROWTH * 200 * (maxhorses-horses))/maxhorses; + + if (growth>0) { + if (a_find(r->attribs, &at_horseluck)) growth *= 2; + /* printf("Horses: <%d> %d -> ", growth, horses); */ + i = (int)(0.5F + (horses * 0.0001F) * growth); + /* printf("%d\n", horses); */ + rsethorses(r, horses + i); + } + } + } + + /* Pferde wandern in Nachbarregionen. + * Falls die Nachbarregion noch berechnet + * werden muß, wird eine migration-Struktur gebildet, + * die dann erst in die Berechnung der Nachbarstruktur einfließt. + */ + + for(n = 0; n != MAXDIRECTIONS; n++) { + region * r2 = rconnect(r, n); + if (r2 && fval(r2->terrain, WALK_INTO)) { + int pt = (rhorses(r) * HORSEMOVE)/100; + pt = (int)normalvariate(pt, pt/4.0); + pt = MAX(0, pt); + if (fval(r2, RF_MIGRATION)) + rsethorses(r2, rhorses(r2) + pt); + else { + migration * nb; + /* haben wir die Migration schonmal benutzt? + * wenn nicht, müssen wir sie suchen. + * Wandernde Pferde vermehren sich nicht. + */ + nb = get_migrants(r2); + nb->horses += pt; + } + /* Wandernde Pferde sollten auch abgezogen werden */ + rsethorses(r, rhorses(r) - pt); + } + } + assert(rhorses(r) >= 0); +} + +static int +count_race(const region *r, const race *rc) +{ + unit *u; + int c = 0; + + for(u = r->units; u; u=u->next) + if(u->race == rc) c += u->number; + + return c; +} + +extern struct attrib_type at_germs; + +static void +growing_trees_e3(region * r, const int current_season, const int last_weeks_season) +{ + const static int transform[4][3] = { + { -1, -1, 0 }, + { TREE_SEED, TREE_SAPLING, 2 }, + { TREE_SAPLING, TREE_TREE, 2 }, + { TREE_TREE, TREE_SEED, 2 } + }; + + if (r->land && current_season!=last_weeks_season && transform[current_season][2]) { + int src_type = transform[current_season][0]; + int dst_type = transform[current_season][1]; + int src = rtrees(r, src_type); + int dst = rtrees(r, dst_type); + int grow = src/transform[current_season][2]; + if (grow>0) { + if (src_type!=TREE_TREE) { + rsettrees(r, src_type, src-grow); + } + rsettrees(r, dst_type, dst+grow); + + if (dst_type==TREE_SEED && r->terrain->size) { + region * rn[MAXDIRECTIONS]; + int d; + double fgrow = grow/(double)MAXDIRECTIONS; + + get_neighbours(r, rn); + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rx = rn[d]; + if (rx && rx->land) { + double scale = 1.0; + int g; + double fg, ch; + int seeds = rtrees(rx, dst_type); + + if (r->terrain->size>rx->terrain->size) { + scale = (scale * rx->terrain->size)/r->terrain->size; + } + fg = scale * fgrow; + g = (int)fg; + ch = fg - g; + if (chance(ch)) ++g; + if (g>0) { + rsettrees(rx, dst_type, seeds + g); + } + } + } + } + } + } +} + +static void +growing_trees(region * r, const int current_season, const int last_weeks_season) +{ + int growth, grownup_trees, i, seeds, sprout; + direction_t d; + attrib *a; + + if(current_season == SEASON_SUMMER || current_season == SEASON_AUTUMN) { + double seedchance = 0.01F * RESOURCE_QUANTITY; + int elves = count_race(r, new_race[RC_ELF]); + + a = a_find(r->attribs, &at_germs); + if(a && last_weeks_season == SEASON_SPRING) { + /* ungekeimte Samen bleiben erhalten, Sprößlinge wachsen */ + sprout = MIN(a->data.sa[1], rtrees(r, 1)); + /* aus dem gesamt Sprößlingepool abziehen */ + rsettrees(r, 1, rtrees(r, 1) - sprout); + /* zu den Bäumen hinzufügen */ + rsettrees(r, 2, rtrees(r, 2) + sprout); + + a_removeall(&r->attribs, &at_germs); + } + + if(is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { + rsettrees(r, 1, (int)(rtrees(r, 1) * 0.9)); + rsettrees(r, 2, (int)(rtrees(r, 2) * 0.9)); + return; + } + + if (production(r) <= 0) return; + + /* Grundchance 1.0% */ + /* Jeder Elf in der Region erhöht die Chance marginal */ + elves = MIN(elves, (production(r)*MAXPEASANTS_PER_AREA)/8); + if (elves) { + seedchance += 1.0-pow(0.99999, elves * RESOURCE_QUANTITY); + } + grownup_trees = rtrees(r, 2); + seeds = 0; + + if (grownup_trees>0) { + double remainder = seedchance*grownup_trees; + seeds = (int)(remainder); + remainder -= seeds; + if (chance(remainder)) { + ++seeds; + } + if (seeds>0) { + seeds += rtrees(r, 0); + rsettrees(r, 0, seeds); + } + } + + /* Bäume breiten sich in Nachbarregionen aus. */ + + /* Gesamtzahl der Samen: + * bis zu 6% (FORESTGROWTH*3) der Bäume samen in die Nachbarregionen */ + seeds = (rtrees(r, 2) * FORESTGROWTH * 3)/1000000; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * r2 = rconnect(r, d); + if (r2 && fval(r2->terrain, LAND_REGION) && r2->terrain->size) { + /* Eine Landregion, wir versuchen Samen zu verteilen: + * Die Chance, das Samen ein Stück Boden finden, in dem sie + * keimen können, hängt von der Bewuchsdichte und der + * verfügbaren Fläche ab. In Gletschern gibt es weniger + * Möglichkeiten als in Ebenen. */ + sprout = 0; + seedchance = (1000 * maxworkingpeasants(r2)) / r2->terrain->size; + for(i=0; iattribs, C_CURSED_BY_THE_GODS, 0)) return; + + /* in at_germs merken uns die Zahl der Samen und Sprößlinge, die + * dieses Jahr älter werden dürfen, damit nicht ein Same im selben + * Zyklus zum Baum werden kann */ + a = a_find(r->attribs, &at_germs); + if(!a) { + a = a_add(&r->attribs, a_new(&at_germs)); + a->data.sa[0] = (short)rtrees(r, 0); + a->data.sa[1] = (short)rtrees(r, 1); + } + /* wir haben 6 Wochen zum wachsen, jeder Same/Sproß hat 18% Chance + * zu wachsen, damit sollten nach 5-6 Wochen alle gewachsen sein */ + growth = 1800; + + /* Samenwachstum */ + + /* Raubbau abfangen, es dürfen nie mehr Samen wachsen, als aktuell + * in der Region sind */ + seeds = MIN(a->data.sa[0], rtrees(r, 0)); + sprout = 0; + + for(i=0;idata.sa[0] = (short)(seeds - sprout); + /* aus dem gesamt Samenpool abziehen */ + rsettrees(r, 0, rtrees(r, 0) - sprout); + /* zu den Sprößlinge hinzufügen */ + rsettrees(r, 1, rtrees(r, 1) + sprout); + + /* Baumwachstum */ + + /* hier gehen wir davon aus, das Jungbäume nicht ohne weiteres aus + * der Region entfernt werden können, da Jungbäume in der gleichen + * Runde nachwachsen, wir also nicht mehr zwischen diesjährigen und + * 'alten' Jungbäumen unterscheiden könnten */ + sprout = MIN(a->data.sa[1], rtrees(r, 1)); + grownup_trees = 0; + + for(i=0;idata.sa[1] = (short)(sprout - grownup_trees); + /* aus dem gesamt Sprößlingepool abziehen */ + rsettrees(r, 1, rtrees(r, 1) - grownup_trees); + /* zu den Bäumen hinzufügen */ + rsettrees(r, 2, rtrees(r, 2) + grownup_trees); + } +} + +static void +growing_herbs(region * r, const int current_season, const int last_weeks_season) +{ + /* Jetzt die Kräutervermehrung. Vermehrt wird logistisch: + * + * Jedes Kraut hat eine Wahrscheinlichkeit von (100-(vorhandene + * Kräuter))% sich zu vermehren. */ + if (current_season != SEASON_WINTER) { + int i; + for (i = rherbs(r); i > 0; i--) { + if (rng_int()%100 < (100-rherbs(r))) rsetherbs(r, (short)(rherbs(r)+1)); + } + } +} + +void +demographics(void) +{ + region *r; + static int last_weeks_season = -1; + static int current_season = -1; + + if (current_season<0) { + gamedate date; + get_gamedate(turn, &date); + current_season = date.season; + get_gamedate(turn-1, &date); + last_weeks_season = date.season; + } + + for (r = regions; r; r = r->next) { + ++r->age; /* also oceans. no idea why we didn't always do that */ + live(r); + /* check_split_dragons(); */ + + if (!fval(r->terrain, SEA_REGION)) { + /* die Nachfrage nach Produkten steigt. */ + struct demand * dmd; + if (r->land) { + static int plant_rules = -1; + + if (plant_rules<0) { + plant_rules = get_param_int(global.parameters, "rules.economy.grow", 0); + } + for (dmd=r->land->demands;dmd;dmd=dmd->next) { + if (dmd->value>0 && dmd->value < MAXDEMAND) { + float rise = DMRISE; + if (buildingtype_exists(r, bt_find("harbour"), true)) rise = DMRISEHAFEN; + if (rng_double()value; + } + } + /* Seuchen erst nachdem die Bauern sich vermehrt haben + * und gewandert sind */ + + calculate_emigration(r); + peasants(r); + if (r->age>20) { + plagues(r, false); + } + horses(r); + if (plant_rules==0) { /* E1 */ + growing_trees(r, current_season, last_weeks_season); + growing_herbs(r, current_season, last_weeks_season); + } else { /* E3 */ + growing_trees_e3(r, current_season, last_weeks_season); + } + } + + update_resources(r); + if (r->land) migrate(r); + } + } + while (free_migrants) { + migration * m = free_migrants->next; + free(free_migrants); + free_migrants = m; + }; + if (verbosity>=1) putchar('\n'); + + remove_empty_units(); + + if (verbosity>=1) puts(" - Einwanderung..."); + for (r = regions; r; r = r->next) { + if (r->land && r->land->newpeasants) { + int rp = rpeasants(r) + r->land->newpeasants; + rsetpeasants(r, MAX(0, rp)); + } + } + + checkorders(); +} +/* ------------------------------------------------------------- */ + +static int +modify(int i) +{ + int c; + + c = i * 2 / 3; + + if (c >= 1) { + return (c + rng_int() % c); + } else { + return (i); + } +} + +static void +inactivefaction(faction * f) +{ + FILE *inactiveFILE; + char zText[128]; + + sprintf(zText, "%s/%s", datapath(), "inactive"); + inactiveFILE = fopen(zText, "a"); + + if (inactiveFILE) { + fprintf(inactiveFILE, "%s:%s:%d:%d\n", + factionid(f), + LOC(default_locale, rc_name(f->race, 1)), + modify(count_all(f)), + turn - f->lastorders); + + fclose(inactiveFILE); + } +} + +static void +transfer_faction(faction *f, faction *f2) +{ + unit *u, *un; + + for (u = f->units; u;) { + un = u->nextF; + if(!unit_has_cursed_item(u) + && !has_skill(u, SK_MAGIC) + && !has_skill(u, SK_ALCHEMY)) { + u_setfaction(u, f2); + } + u = un; + } +} + +static int +restart_cmd(unit * u, struct order * ord) +{ + init_tokens(ord); + skip_token(); /* skip keyword */ + + if (!fval(u->region->terrain, LAND_REGION)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); + } else { + const char * s_race = getstrtoken(), * s_pass; + const race * frace = findrace(s_race, u->faction->locale); + + if (!frace) { + frace = u->faction->race; + s_pass = s_race; + } else { + s_pass = getstrtoken(); + } + + if (u->faction->age > 3 && fval(u->faction, FFL_RESTART)) { + cmistake(u, ord, 314, MSG_EVENT); + return 0; + } + + if (/* frace != u->faction->race && */ u->faction->age < 81) { + cmistake(u, ord, 241, MSG_EVENT); + return 0; + } + + if (!playerrace(frace)) { + cmistake(u, ord, 243, MSG_EVENT); + return 0; + } + + if (!checkpasswd(u->faction, (const char *)s_pass, false)) { + cmistake(u, ord, 86, MSG_EVENT); + log_warning(("RESTART with wrong password, faction %s, pass %s\n", + factionid(u->faction), s_pass)); + return 0; + } + restart_race(u, frace); + return -1; + } + return 0; +} + +static boolean +EnhancedQuit(void) +{ + static int value = -1; + if (value<0) { + const char * str = get_param(global.parameters, "alliance.transferquit"); + value = (str!=0 && strcmp(str, "true")==0); + } + return value; +} + +static int +quit_cmd(unit * u, struct order * ord) +{ + faction * f = u->faction; + const char * passwd; + + init_tokens(ord); + skip_token(); /* skip keyword */ + + passwd = getstrtoken(); + if (checkpasswd(f, (const char *)passwd, false)) { + if (EnhancedQuit()) { + int f2_id = getid(); + if (f2_id>0) { + faction *f2 = findfaction(f2_id); + + if(f2 == NULL) { + cmistake(u, ord, 66, MSG_EVENT); + return 0; + } else if (!u->faction->alliance || u->faction->alliance != f2->alliance) { + cmistake(u, ord, 315, MSG_EVENT); + return 0; + } else if(!alliedfaction(NULL, f, f2, HELP_MONEY)) { + cmistake(u, ord, 316, MSG_EVENT); + return 0; + } else { + variant var; + var.i = f2_id; + a_add(&f->attribs, object_create("quit", TINTEGER, var)); + } + } + } + fset(f, FFL_QUIT); + } else { + char buffer[64]; + write_order(ord, buffer, sizeof(buffer)); + cmistake(u, ord, 86, MSG_EVENT); + log_warning(("QUIT with illegal password for faction %s: %s\n", + factionid(f), buffer)); + } + return 0; +} + +static void +quit(void) +{ + faction ** fptr = &factions; + while (*fptr) { + faction * f = *fptr; + if (f->flags & FFL_QUIT) { + if (EnhancedQuit()) { + /* this doesn't work well (use object_name()) */ + attrib * a = a_find(f->attribs, &at_object); + if (a) { + variant var; + object_type type; + var.i = 0; + object_get(a, &type, &var); + assert(var.i && type==TINTEGER); + if (var.i) { + int f2_id = var.i; + faction *f2 = findfaction(f2_id); + + assert(f2_id>0); + assert(f2!=NULL); + transfer_faction(f, f2); + } + } + } + destroyfaction(f); + } + if (*fptr==f) fptr=&f->next; + } +} + +int dropouts[2]; +int * age = NULL; + +static void +nmr_death(faction * f) +{ + static int rule = -1; + if (rule<0) rule = get_param_int(global.parameters, "rules.nmr.destroy", 0); + if (rule) { + unit * u; + for (u=f->units;u;u=u->nextF) { + if (u->building && fval(u, UFL_OWNER)) { + remove_building(&u->region->buildings, u->building); + } + } + } +} + +static void +parse_restart(void) +{ + region *r; + faction *f; + + /* Sterben erst nachdem man allen anderen gegeben hat - bzw. man kann + * alles machen, was nicht ein dreißigtägiger Befehl ist. */ + + for (r = regions; r; r = r->next) { + unit * u, * un; + for (u = r->units; u;) { + order * ord; + + un = u->next; + for (ord = u->orders; ord!=NULL; ord = ord->next) { + if (get_keyword(ord) == K_RESTART) { + if (u->number > 0) { + if (restart_cmd(u, ord)!=0) { + break; + } + } + } + } + u = un; + } + } + + if (verbosity>=1) puts(" - beseitige Spieler, die sich zu lange nicht mehr gemeldet haben..."); + + for (f = factions; f; f = f->next) { + if(fval(f, FFL_NOIDLEOUT)) f->lastorders = turn; + if (NMRTimeout()>0 && turn - f->lastorders >= NMRTimeout()) { + nmr_death(f); + destroyfaction(f); + continue; + } + if (fval(f, FFL_OVERRIDE)) { + free(f->override); + f->override = strdup(itoa36(rng_int())); + freset(f, FFL_OVERRIDE); + } + if (turn!=f->lastorders) { + char info[256]; + sprintf(info, "%d Einheiten, %d Personen, %d Silber", + f->no_units, f->num_total, f->money); + if (f->subscription) { + sql_print(("UPDATE subscriptions SET lastturn=%d, password='%s', info='%s' WHERE id=%u;\n", + f->lastorders, f->override, info, f->subscription)); + } + } else { + if (f->subscription) { + sql_print(("UPDATE subscriptions SET status='ACTIVE', lastturn=%d, firstturn=greatest(firstturn,%d), password='%s' WHERE id=%u;\n", + f->lastorders, f->lastorders-f->age, + f->override, f->subscription)); + } + } + + if (NMRTimeout()>0 && turn - f->lastorders >= (NMRTimeout() - 1)) { + inactivefaction(f); + continue; + } + } + if (verbosity>=1) { + puts(" - beseitige Spieler, die sich nach der Anmeldung nicht " + "gemeldet haben..."); + } + + age = calloc(MAX(4,turn+1), sizeof(int)); + for (f = factions; f; f = f->next) if (!is_monsters(f)) { + if (RemoveNMRNewbie() && !fval(f, FFL_NOIDLEOUT)) { + if (f->age>=0 && f->age <= turn) ++age[f->age]; + if (f->age == 2 || f->age == 3) { + if (f->lastorders == turn - 2) { + destroyfaction(f); + ++dropouts[f->age-2]; + continue; + } + } + } + } + + if (verbosity>=1) puts(" - beseitige leere Einheiten und leere Parteien..."); + remove_empty_units(); +} +/* ------------------------------------------------------------- */ + +/* HELFE partei [] [NICHT] */ + +static int +ally_cmd(unit * u, struct order * ord) +{ + ally * sf, ** sfp; + faction *f; + int keyword, not_kw; + const char *s; + + init_tokens(ord); + skip_token(); + f = getfaction(); + + if (f==NULL || is_monsters(f)) { + cmistake(u, ord, 66, MSG_EVENT); + return 0; + } + if (f == u->faction) return 0; + + s = getstrtoken(); + + if (!s[0]) + keyword = P_ANY; + else + keyword = findparam(s, u->faction->locale); + + sfp = &u->faction->allies; + if (fval(u, UFL_GROUP)) { + attrib * a = a_find(u->attribs, &at_group); + if (a) sfp = &((group*)a->data.v)->allies; + } + for (sf=*sfp; sf; sf = sf->next) + if (sf->faction == f) + break; /* Gleich die passende raussuchen, wenn vorhanden */ + + not_kw = getparam(u->faction->locale); /* HELFE partei [modus] NICHT */ + + if (!sf) { + if (keyword == P_NOT || not_kw == P_NOT) { + /* Wir helfen der Partei gar nicht... */ + return 0; + } else { + sf = calloc(1, sizeof(ally)); + sf->faction = f; + sf->status = 0; + addlist(sfp, sf); + } + } + switch (keyword) { + case P_NOT: + sf->status = 0; + break; + + case NOPARAM: + cmistake(u, ord, 137, MSG_EVENT); + return 0; + + case P_ANY: + if (not_kw == P_NOT) + sf->status = 0; + else + sf->status = HELP_ALL; + break; + + case P_TRAVEL: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_TRAVEL); + else + sf->status = sf->status | HELP_TRAVEL; + break; + + case P_GIVE: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_GIVE); + else + sf->status = sf->status | HELP_GIVE; + break; + + case P_MONEY: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_MONEY); + else + sf->status = sf->status | HELP_MONEY; + break; + + case P_FIGHT: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_FIGHT); + else + sf->status = sf->status | HELP_FIGHT; + break; + + case P_FACTIONSTEALTH: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_FSTEALTH); + else + sf->status = sf->status | HELP_FSTEALTH; + break; + + case P_GUARD: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_GUARD); + else + sf->status = sf->status | HELP_GUARD; + break; + } + + sf->status &= HelpMask(); + + if (sf->status == 0) { /* Alle HELPs geloescht */ + removelist(sfp, sf); + } + return 0; +} + +static struct local_names * pnames; + +static void +init_prefixnames(void) +{ + int i; + for (i=0;localenames[i];++i) { + const struct locale * lang = find_locale(localenames[i]); + boolean exist = false; + struct local_names * in = pnames; + + while (in!=NULL) { + if (in->lang==lang) { + exist = true; + break; + } + in = in->next; + } + if (in==NULL) in = calloc(sizeof(local_names), 1); + in->next = pnames; + in->lang = lang; + + if (!exist) { + int key; + for (key=0;race_prefixes[key];++key) { + variant var; + const char * pname = locale_string(lang, mkname("prefix", race_prefixes[key])); + if (findtoken(&in->names, pname, &var)==E_TOK_NOMATCH || var.i!=key) { + var.i = key; + addtoken(&in->names, pname, var); + addtoken(&in->names, locale_string(lang, mkname("prefix", race_prefixes[key])), var); + } + } + } + pnames = in; + } +} + +static int +prefix_cmd(unit * u, struct order * ord) +{ + attrib **ap; + const char *s; + local_names * in = pnames; + variant var; + const struct locale * lang = u->faction->locale; + + while (in!=NULL) { + if (in->lang==lang) break; + in = in->next; + } + if (in==NULL) { + init_prefixnames(); + for (in=pnames;in->lang!=lang;in=in->next) ; + } + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + if (!*s) { + attrib *a = NULL; + if (fval(u, UFL_GROUP)) { + a = a_find(u->attribs, &at_group); + } + if (a) { + group * g = (group*)a->data.v; + a_removeall(&g->attribs, &at_raceprefix); + } else { + a_removeall(&u->faction->attribs, &at_raceprefix); + } + return 0; + } + + if (findtoken(&in->names, s, &var)==E_TOK_NOMATCH) { + return 0; + } else if (race_prefixes[var.i] == NULL) { + cmistake(u, ord, 299, MSG_EVENT); + } else { + ap = &u->faction->attribs; + if (fval(u, UFL_GROUP)) { + attrib * a = a_find(u->attribs, &at_group); + group * g = (group*)a->data.v; + if (a) ap = &g->attribs; + } + set_prefix(ap, race_prefixes[var.i]); + } + return 0; +} + + +static cmp_building_cb +get_cmp_region_owner(void) +{ + if (rule_region_owners()) { + return &cmp_current_owner; + } else { + return &cmp_wage; + } +} + +static int +display_cmd(unit * u, struct order * ord) +{ + building * b = u->building; + char **s = NULL; + region * r = u->region; + + init_tokens(ord); + skip_token(); + + switch (getparam(u->faction->locale)) { + case P_BUILDING: + case P_GEBAEUDE: + if (!b) { + cmistake(u, ord, 145, MSG_PRODUCE); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 5, MSG_PRODUCE); + break; + } + if (!fval(b->type, BTF_NAMECHANGE) && b->display && b->display[0] != 0) { + cmistake(u, ord, 278, MSG_EVENT); + break; + } + s = &b->display; + break; + + case P_SHIP: + if (!u->ship) { + cmistake(u, ord, 144, MSG_PRODUCE); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 12, MSG_PRODUCE); + break; + } + s = &u->ship->display; + break; + + case P_UNIT: + s = &u->display; + break; + + case P_PRIVAT: + { + const char *d = getstrtoken(); + if(d == NULL || *d == 0) { + usetprivate(u, NULL); + } else { + usetprivate(u, d); + } + } + break; + + case P_REGION: + if (!b) { + cmistake(u, ord, 145, MSG_EVENT); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 148, MSG_EVENT); + break; + } + if (b != largestbuilding(r, get_cmp_region_owner(), false)) { + cmistake(u, ord, 147, MSG_EVENT); + break; + } + s = &r->display; + break; + + default: + cmistake(u, ord, 110, MSG_EVENT); + break; + } + + if (s!=NULL) { + const char * s2 = getstrtoken(); + + free(*s); + *s = strdup(s2); + if (strlen(s2)>=DISPLAYSIZE) { + (*s)[DISPLAYSIZE] = 0; + } + } + + return 0; +} + +static boolean +renamed_building(const building * b) +{ + const struct locale * lang = locales; + for (;lang;lang=nextlocale(lang)) { + const char * bdname = LOC(lang, b->type->_name); + size_t bdlen = strlen(bdname); + if (strlen(b->name)>=bdlen && strncmp(b->name, bdname, bdlen)==0) { + return false; + } + } + return true; +} + +static int +rename_cmd(unit * u, order * ord, char **s, const char * s2) +{ + if (!s2[0]) { + cmistake(u, ord, 84, MSG_EVENT); + return 0; + } + + /* TODO: Validate to make sure people don't have illegal characters in + * names, phishing-style? () come to mind. */ + + free(*s); + *s = strdup(s2); + if (strlen(s2)>=NAMESIZE) { + (*s)[NAMESIZE] = 0; + } + return 0; +} + +static int +rename_building(unit * u, order * ord, building * b, const char * name) { + unit * owner = b?building_owner(b):0; + boolean foreign = owner && owner->faction==u->faction; + + if (!b) { + cmistake(u, ord, u->building?6:145, MSG_EVENT); + return -1; + } + + if (!fval(b->type, BTF_NAMECHANGE) && renamed_building(b)) { + cmistake(u, ord, 278, MSG_EVENT); + return -1; + } + + if (foreign) { + unit *uo; + + if (renamed_building(b)) { + cmistake(u, ord, 246, MSG_EVENT); + return -1; + } + + uo = building_owner(b); + if (uo) { + if (cansee(uo->faction, u->region, u, 0)) { + ADDMSG(&uo->faction->msgs, msg_message("renamed_building_seen", + "building renamer region", b, u, u->region)); + } else { + ADDMSG(&uo->faction->msgs, msg_message("renamed_building_notseen", + "building region", b, u->region)); + } + } + } else { + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 148, MSG_PRODUCE); + return -1; + } + } + + return rename_cmd(u, ord, &b->name, getstrtoken()); +} + +static int +name_cmd(unit * u, struct order * ord) +{ + building * b = u->building; + region * r = u->region; + char **s = NULL; + param_t p; + boolean foreign = false; + + init_tokens(ord); + skip_token(); + p = getparam(u->faction->locale); + + if (p == P_FOREIGN) { + foreign = true; + p = getparam(u->faction->locale); + } + + switch (p) { + case P_ALLIANCE: + if (foreign==false && f_get_alliance(u->faction)) { + alliance * al = u->faction->alliance; + faction * lead = alliance_get_leader(al); + if (lead==u->faction) { + s = &al->name; + } + } + break; + case P_BUILDING: + case P_GEBAEUDE: + if (foreign) { + b = getbuilding(u->region); + } + + return rename_building(u, ord, b, getstrtoken()); + + case P_FACTION: + if (foreign == true) { + faction *f; + + f = getfaction(); + if (!f) { + cmistake(u, ord, 66, MSG_EVENT); + break; + } + if (f->age < 10) { + cmistake(u, ord, 248, MSG_EVENT); + break; + } else { + const struct locale * lang = locales; + for (;lang;lang=nextlocale(lang)) { + const char * fdname = LOC(lang, "factiondefault"); + size_t fdlen = strlen(fdname); + if (strlen(f->name)>=fdlen && strncmp(f->name, fdname, fdlen)==0) { + break; + } + } + if (lang==NULL) { + cmistake(u, ord, 247, MSG_EVENT); + break; + } + } + if (cansee(f, r, u, 0)) { + ADDMSG(&f->msgs, msg_message("renamed_faction_seen", "unit region", u, r)); + } else { + ADDMSG(&f->msgs, msg_message("renamed_faction_notseen", "", r)); + } + s = &f->name; + } else { + s = &u->faction->name; + } + break; + + case P_SHIP: + if (foreign == true) { + ship *sh = getship(r); + unit *uo; + + if (!sh) { + cmistake(u, ord, 20, MSG_EVENT); + break; + } else { + const struct locale * lang = locales; + for (;lang;lang=nextlocale(lang)) { + const char * sdname = LOC(lang, sh->type->name[0]); + size_t sdlen = strlen(sdname); + if (strlen(sh->name)>=sdlen && strncmp(sh->name, sdname, sdlen)==0) { + break; + } + + sdname = LOC(lang, parameters[P_SHIP]); + sdlen = strlen(sdname); + if (strlen(sh->name)>=sdlen && strncmp(sh->name, sdname, sdlen)==0) { + break; + } + + } + if (lang==NULL) { + cmistake(u, ord, 245, MSG_EVENT); + break; + } + } + uo = shipowner(sh); + if (uo) { + if (cansee(uo->faction, r, u, 0)) { + ADDMSG(&uo->faction->msgs, msg_message("renamed_ship_seen", + "ship renamer region", sh, u, r)); + } else { + ADDMSG(&uo->faction->msgs, msg_message("renamed_ship_notseen", + "ship region", sh, r)); + } + } + s = &sh->name; + } else { + if (!u->ship) { + cmistake(u, ord, 144, MSG_PRODUCE); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 12, MSG_PRODUCE); + break; + } + s = &u->ship->name; + } + break; + + case P_UNIT: + if (foreign == true) { + unit *u2 = getunit(r, u->faction); + + if (!u2 || !cansee(u->faction, r, u2, 0)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + break; + } else { + const char * udefault = LOC(u2->faction->locale, "unitdefault"); + size_t udlen = strlen(udefault); + size_t unlen = strlen(u2->name); + if (unlen>=udlen && strncmp(u2->name, udefault, udlen)!=0) { + cmistake(u2, ord, 244, MSG_EVENT); + break; + } + } + if (cansee(u2->faction, r, u, 0)) { + ADDMSG(&u2->faction->msgs, msg_message("renamed_seen", + "renamer renamed region", u, u2, r)); + } else { + ADDMSG(&u2->faction->msgs, msg_message("renamed_notseen", + "renamed region", u2, r)); + } + s = &u2->name; + } else { + s = &u->name; + } + break; + + case P_REGION: + if (!b) { + cmistake(u, ord, 145, MSG_EVENT); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 148, MSG_EVENT); + break; + } + + if (b != largestbuilding(r, get_cmp_region_owner(), false)) { + cmistake(u, ord, 147, MSG_EVENT); + break; + } + s = &r->land->name; + break; + + case P_GROUP: + { + attrib * a = NULL; + if (fval(u, UFL_GROUP)) a = a_find(u->attribs, &at_group); + if (a) { + group * g = (group*)a->data.v; + s = &g->name; + break; + } else { + cmistake(u, ord, 109, MSG_EVENT); + break; + } + } + break; + default: + cmistake(u, ord, 109, MSG_EVENT); + break; + } + + if (s!=NULL) { + return rename_cmd(u, ord, s, getstrtoken()); + } + + return 0; +} +/* ------------------------------------------------------------- */ + +void +deliverMail(faction * f, region * r, unit * u, const char *s, unit * receiver) +{ + if (!cansee(f, r, u, 0)) { + u = NULL; + } + if (!receiver) { /* BOTSCHAFT an PARTEI */ + ADDMSG(&f->msgs, msg_message("regionmessage", "region sender string", r, u, s)); + } else { /* BOTSCHAFT an EINHEIT */ + ADDMSG(&f->msgs, msg_message("unitmessage", "region unit sender string", r, receiver, u, s)); + } +} + +static void +mailunit(region * r, unit * u, int n, struct order * ord, const char * s) +{ + unit * u2 = findunitr(r,n); + + if (u2 && cansee(u->faction, r, u2, 0)) { + deliverMail(u2->faction, r, u, s, u2); + /* now done in prepare_mail_cmd */ + } + else { + /* Immer eine Meldung - sonst könnte man so getarnte EHs enttarnen: + * keine Meldung -> EH hier. */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } +} + +static void +mailfaction(unit * u, int n, struct order * ord, const char * s) +{ + faction *f; + + f = findfaction(n); + if (f && n>0) + deliverMail(f, u->region, u, s, NULL); + else + cmistake(u, ord, 66, MSG_MESSAGE); +} + +static int +mail_cmd(unit * u, struct order * ord) +{ + region * r = u->region; + unit *u2; + const char *s; + int n, cont; + + init_tokens(ord); + skip_token(); /* skip the keyword */ + s = getstrtoken(); + + /* Falls kein Parameter, ist das eine Einheitsnummer; + * das Füllwort "AN" muß wegfallen, da gültige Nummer! */ + + do { + cont = 0; + switch (findparam(s, u->faction->locale)) { + case P_REGION: + /* können alle Einheiten in der Region sehen */ + s = getstrtoken(); + if (!s[0]) { + cmistake(u, ord, 30, MSG_MESSAGE); + break; + } else { + ADDMSG(&r->msgs, msg_message("mail_result", "unit message", u, s)); + return 0; + } + + case P_FACTION: + { + boolean see = false; + + n = getfactionid(); + + for(u2=r->units; u2; u2=u2->next) { + if(u2->faction->no == n && seefaction(u->faction, r, u2, 0)) { + see = true; + break; + } + } + + if(see == false) { + cmistake(u, ord, 66, MSG_MESSAGE); + break; + } + + s = getstrtoken(); + if (!s[0]) { + cmistake(u, ord, 30, MSG_MESSAGE); + break; + } + mailfaction(u, n, ord, s); + return 0; + } + + case P_UNIT: + { + boolean see = false; + n = getid(); + + for (u2=r->units; u2; u2=u2->next) { + if (u2->no == n && cansee(u->faction, r, u2, 0)) { + see = true; + break; + } + } + + if (see == false) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return 0; + } + + s = getstrtoken(); + if (!s[0]) { + cmistake(u, ord, 30, MSG_MESSAGE); + break; + } else { + attrib * a = a_find(u2->attribs, &at_eventhandler); + if (a!=NULL) { + event_arg args[3]; + args[0].data.v = (void*)s; + args[0].type = "string"; + args[1].data.v = (void*)u; + args[1].type = "unit"; + args[2].type = NULL; + handle_event(a, "message", args); + } + + mailunit(r, u, n, ord, s); + } + return 0; + } + + case P_BUILDING: + case P_GEBAEUDE: + { + building *b = getbuilding(r); + + if(!b) { + cmistake(u, ord, 6, MSG_MESSAGE); + break; + } + + s = getstrtoken(); + + if (!s[0]) { + cmistake(u, ord, 30, MSG_MESSAGE); + break; + } + + for (u2 = r->units; u2; u2 = u2->next) freset(u2->faction, FFL_SELECT); + + for (u2=r->units; u2; u2=u2->next) { + if(u2->building == b && !fval(u2->faction, FFL_SELECT) + && cansee(u->faction, r, u2, 0)) { + mailunit(r, u, u2->no, ord, s); + fset(u2->faction, FFL_SELECT); + } + } + return 0; + } + + case P_SHIP: + { + ship *sh = getship(r); + + if(!sh) { + cmistake(u, ord, 20, MSG_MESSAGE); + break; + } + + s = getstrtoken(); + + if (!s[0]) { + cmistake(u, ord, 30, MSG_MESSAGE); + break; + } + + for (u2 = r->units; u2; u2 = u2->next) freset(u2->faction, FFL_SELECT); + + for(u2=r->units; u2; u2=u2->next) { + if(u2->ship == sh && !fval(u2->faction, FFL_SELECT) && cansee(u->faction, r, u2, 0)) { + mailunit(r, u, u2->no, ord, s); + fset(u2->faction, FFL_SELECT); + } + } + return 0; + } + + default: + /* possibly filler token? */ + s = getstrtoken(); + if (s && *s) cont = 1; + break; + } + } while (cont); + cmistake(u, ord, 149, MSG_MESSAGE); + return 0; +} +/* ------------------------------------------------------------- */ + +static int +banner_cmd(unit * u, struct order * ord) +{ + init_tokens(ord); + skip_token(); + + free(u->faction->banner); + u->faction->banner = strdup(getstrtoken()); + add_message(&u->faction->msgs, msg_message("changebanner", "value", + u->faction->banner)); + + return 0; +} + +static int +email_cmd(unit * u, struct order * ord) +{ + const char * s; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + if (!s[0]) { + cmistake(u, ord, 85, MSG_EVENT); + } else { + faction * f = u->faction; + if (set_email(&f->email, (const char *)s)!=0) { + log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), s)); + ADDMSG(&f->msgs, msg_message("changemail_invalid", "value", s)); + } else { + ADDMSG(&f->msgs, msg_message("changemail", "value", f->email)); + } + } + return 0; +} + +static int +password_cmd(unit * u, struct order * ord) +{ + char pwbuf[32]; + int i; + const char * s; + boolean pwok = true; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + if (!s || !*s) { + for(i=0; i<6; i++) pwbuf[i] = (char)(97 + rng_int() % 26); + pwbuf[6] = 0; + } else { + char *c; + + strlcpy(pwbuf, (const char *)s, 31); + pwbuf[31] = 0; + c = pwbuf; + while (*c && pwok) { + if (!isalnum(*(unsigned char*)c)) pwok = false; + c++; + } + } + free(u->faction->passw); + if (pwok == false) { + cmistake(u, ord, 283, MSG_EVENT); + u->faction->passw = strdup(itoa36(rng_int())); + } else { + u->faction->passw = strdup(pwbuf); + } + fset(u->faction, FFL_OVERRIDE); + ADDMSG(&u->faction->msgs, msg_message("changepasswd", + "value", u->faction->passw)); + return 0; +} + +static int +send_cmd(unit * u, struct order * ord) +{ + const char * s; + int option; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + option = findoption(s, u->faction->locale); + + if (option == -1) { + cmistake(u, ord, 135, MSG_EVENT); + } else { + if (getparam(u->faction->locale) == P_NOT) { + if (option == O_COMPRESS || option == O_BZIP2) { + cmistake(u, ord, 305, MSG_EVENT); + } else { + u->faction->options = u->faction->options & ~(1<faction->options = u->faction->options | (1<faction->options &= ~(1<faction->options &= ~(1<items, itype); + if (i==0) { + if (u->region->land!=NULL) { + i = i_get(u->region->land->items, itype); + } + if (i==0) { + i = i_get(u->faction->items, itype); + if (i==0) return false; + } + } + } + + name = resourcename(itype->rtype, 0); + key = mkname("iteminfo", name); + info = locale_getstring(f->locale, key); + + if (info==NULL) { + info = locale_string(f->locale, mkname("iteminfo", "no_info")); + } + ADDMSG(&f->msgs, msg_message("displayitem", "weight item description", + itype->weight, itype->rtype, info)); + + return true; +} + +static boolean +display_potion(faction *f, unit *u, const potion_type * ptype) +{ + attrib *a; + + if (ptype==NULL) return false; + else { + int i = i_get(u->items, ptype->itype); + if (i==0 && 2*ptype->level > effskill(u,SK_ALCHEMY)) { + return false; + } + } + + a = a_find(f->attribs, &at_showitem); + while (a && a->data.v != ptype) a=a->next; + if (!a) { + a = a_add(&f->attribs, a_new(&at_showitem)); + a->data.v = (void*) ptype->itype; + } + + return true; +} + +static boolean +display_race(faction *f, unit *u, const race * rc) +{ + const char *name, *key; + const char *info; + int a, at_count; + char buf[2048], * bufp = buf; + size_t size = sizeof(buf) - 1; + int bytes; + + if (u && u->race != rc) return false; + name = rc_name(rc, 0); + + bytes = slprintf(bufp, size, "%s: ", LOC(f->locale, name)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + key = mkname("raceinfo", rc->_name[0]); + info = locale_getstring(f->locale, key); + if (info==NULL) { + info = locale_string(f->locale, mkname("raceinfo", "no_info")); + } + + bytes = (int)strlcpy(bufp, info, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + /* hp_p : Trefferpunkte */ + bytes = snprintf(bufp, size, " %d %s", rc->hitpoints, LOC(f->locale, "stat_hitpoints")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + /* b_attacke : Angriff */ + bytes = snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_attack"), (rc->at_default+rc->at_bonus)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + /* b_defense : Verteidigung */ + bytes = snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_defense"), (rc->df_default+rc->df_bonus)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + /* b_armor : Rüstung */ + if (rc->armor > 0) { + bytes = snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_armor"), rc->armor); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + if (size>1) { + *bufp++ ='.'; + --size; + } else WARN_STATIC_BUFFER(); + + /* b_damage : Schaden */ + at_count=0; + for (a = 0; a < 6; a++) { + if (rc->attack[a].type != AT_NONE){ + at_count++; + } + } + if (rc->battle_flags & BF_EQUIPMENT) { + bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_equipment")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (rc->battle_flags & BF_RES_PIERCE) { + bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_pierce")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (rc->battle_flags & BF_RES_CUT) { + bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_cut")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (rc->battle_flags & BF_RES_BASH) { + bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_bash")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + bytes = snprintf(bufp, size, " %d %s", at_count, LOC(f->locale, (at_count==1)?"stat_attack":"stat_attacks")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + for (a = 0; a < 6; a++) { + if (rc->attack[a].type != AT_NONE){ + if (a!=0) bytes = (int)strlcpy(bufp, ", ", size); + else bytes = (int)strlcpy(bufp, ": ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + switch(rc->attack[a].type) { + case AT_STANDARD: + bytes = snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_standard"), rc->def_damage); + break; + case AT_NATURAL: + bytes = snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_natural"), rc->attack[a].data.dice); + break; + case AT_SPELL: + case AT_COMBATSPELL: + case AT_DRAIN_ST: + case AT_DAZZLE: + bytes = snprintf(bufp, size, "%s", LOC(f->locale, "attack_magical")); + break; + case AT_STRUCTURAL: + bytes = snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_structural"), rc->attack[a].data.dice); + break; + default: + bytes = 0; + } + + if (bytes && wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + + if (size>1) { + *bufp++ = '.'; + --size; + } else WARN_STATIC_BUFFER(); + + *bufp = 0; + addmessage(0, f, buf, MSG_EVENT, ML_IMPORTANT); + + return true; +} + +static void +reshow(unit * u, struct order * ord, const char * s, param_t p) +{ + int skill, c; + const potion_type * ptype; + const item_type * itype; + const spell * sp; + const race * rc; + + switch (p) { + case P_ZAUBER: + a_removeall(&u->faction->attribs, &at_seenspell); + break; + case P_POTIONS: + skill = effskill(u, SK_ALCHEMY); + c = 0; + for (ptype = potiontypes; ptype!=NULL; ptype=ptype->next) { + if (ptype->level * 2 <= skill) { + c += display_potion(u->faction, u, ptype); + } + } + if (c == 0) cmistake(u, ord, 285, MSG_EVENT); + break; + case NOPARAM: + /* check if it's an item */ + itype = finditemtype(s, u->faction->locale); + if (itype!=NULL) { + ptype = resource2potion(item2resource(itype)); + if (ptype!=NULL) { + if (display_potion(u->faction, u, ptype)) break; + } else { + if (display_item(u->faction, u, itype)) break; + } + } + /* try for a spell */ + sp = get_spellfromtoken(u, s, u->faction->locale); + if (sp!=NULL && u_hasspell(u, sp)) { + attrib *a = a_find(u->faction->attribs, &at_seenspell); + while (a!=NULL && a->type==&at_seenspell && a->data.v!=sp) a = a->next; + if (a!=NULL) a_remove(&u->faction->attribs, a); + break; + } + /* last, check if it's a race. */ + rc = findrace(s, u->faction->locale); + if (rc != NULL) { + if (display_race(u->faction, u, rc)) break; + } + cmistake(u, ord, 21, MSG_EVENT); + break; + default: + cmistake(u, ord, 222, MSG_EVENT); + break; + } +} + +static int +promotion_cmd(unit * u, struct order * ord) +{ + int money, people; + + if (fval(u, UFL_HERO)) { + /* TODO: message "is already a hero" */ + return 0; + } + + if (maxheroes(u->faction) < countheroes(u->faction)+u->number) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_maxed", "max count", + maxheroes(u->faction), countheroes(u->faction))); + return 0; + } + if (!valid_race(u->faction, u->race)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_race", "race", + u->race)); + return 0; + } + people = count_all(u->faction) * u->number; + money = get_pooled(u, i_silver->rtype, GET_ALL, people); + + if (people>money) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_cost", "cost have", + people, money)); + return 0; + } + use_pooled(u, i_silver->rtype, GET_ALL, people); + fset(u, UFL_HERO); + ADDMSG(&u->faction->msgs, msg_message("hero_promotion", "unit cost", + u, people)); + return 0; +} + +static int +group_cmd(unit * u, struct order * ord) +{ + const char * s; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + join_group(u, s); + return 0; +} + +static int +origin_cmd(unit * u, struct order * ord) +{ + short px, py; + + init_tokens(ord); + skip_token(); + + px = (short)getint(); + py = (short)getint(); + + set_ursprung(u->faction, getplaneid(u->region), px, py); + return 0; +} + +static int +guard_off_cmd(unit * u, struct order * ord) +{ + assert(get_keyword(ord)==K_GUARD); + init_tokens(ord); + skip_token(); + + if (getparam(u->faction->locale) == P_NOT) { + setguard(u, GUARD_NONE); + } + return 0; +} + +static int +reshow_cmd(unit * u, struct order * ord) +{ + const char * s; + param_t p = NOPARAM; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + if (findparam(s, u->faction->locale) == P_ANY) { + p = getparam(u->faction->locale); + s = NULL; + } + + reshow(u, ord, s, p); + return 0; +} + +static int +status_cmd(unit * u, struct order * ord) +{ + const char * param; + + init_tokens(ord); + skip_token(); + + param = getstrtoken(); + switch (findparam(param, u->faction->locale)) { + case P_NOT: + setstatus(u, ST_AVOID); + break; + case P_BEHIND: + setstatus(u, ST_BEHIND); + break; + case P_FLEE: + setstatus(u, ST_FLEE); + break; + case P_CHICKEN: + setstatus(u, ST_CHICKEN); + break; + case P_AGGRO: + setstatus(u, ST_AGGRO); + break; + case P_VORNE: + setstatus(u, ST_FIGHT); + break; + case P_HELP: + if (getparam(u->faction->locale) == P_NOT) { + fset(u, UFL_NOAID); + } else { + freset(u, UFL_NOAID); + } + break; + default: + if (param[0]) { + add_message(&u->faction->msgs, + msg_feedback(u, ord, "unknown_status", "")); + } else { + setstatus(u, ST_FIGHT); + } + } + return 0; +} + +static int +combatspell_cmd(unit * u, struct order * ord) +{ + const char * s; + int level = 0; + spell * spell; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + /* KAMPFZAUBER [NICHT] löscht alle gesetzten Kampfzauber */ + if (!s || *s == 0 || findparam(s, u->faction->locale) == P_NOT) { + unset_combatspell(u, 0); + return 0; + } + + /* Optional: STUFE n */ + if (findparam(s, u->faction->locale) == P_LEVEL) { + /* Merken, setzen kommt erst später */ + level = getint(); + level = MAX(0, level); + s = getstrtoken(); + } + + spell = get_spellfromtoken(u, s, u->faction->locale); + + if(!spell){ + cmistake(u, ord, 173, MSG_MAGIC); + return 0; + } + + s = getstrtoken(); + + if (findparam(s, u->faction->locale) == P_NOT) { + /* KAMPFZAUBER "" NICHT löscht diesen speziellen + * Kampfzauber */ + unset_combatspell(u, spell); + return 0; + } else { + /* KAMPFZAUBER "" setzt diesen Kampfzauber */ + set_combatspell(u, spell, ord, level); + } + + return 0; +} + +/* ------------------------------------------------------------- */ +/* Beachten: einige Monster sollen auch unbewaffent die Region bewachen + * können */ + +enum { E_GUARD_OK, E_GUARD_UNARMED, E_GUARD_NEWBIE, E_GUARD_FLEEING }; + +static int +can_start_guarding(const unit * u) +{ + if (u->status>=ST_FLEE) return E_GUARD_FLEEING; + if (fval(u->race, RCF_UNARMEDGUARD)) return E_GUARD_OK; + if (!armedmen(u, true)) return E_GUARD_UNARMED; + if (IsImmune(u->faction)) return E_GUARD_NEWBIE; + return E_GUARD_OK; +} + +void +update_guards(void) +{ + const region *r; + + for (r = regions; r; r = r->next) { + unit *u; + for (u = r->units; u; u = u->next) { + if (fval(u, UFL_GUARD)) { + if (can_start_guarding(u)!=E_GUARD_OK) { + setguard(u, GUARD_NONE); + } else { + attrib * a = a_find(u->attribs, &at_guard); + if (a && a->data.i==(int)guard_flags(u)) { + /* this is really rather not necessary */ + a_remove(&u->attribs, a); + } + } + } + } + } +} + +static int +guard_on_cmd(unit * u, struct order * ord) +{ + assert(get_keyword(ord)==K_GUARD); + + init_tokens(ord); + skip_token(); + + /* GUARD NOT is handled in goard_off_cmd earlier in the turn */ + if (getparam(u->faction->locale) == P_NOT) return 0; + + if (fval(u->region->terrain, SEA_REGION)) { + cmistake(u, ord, 2, MSG_EVENT); + } else { + if (fval(u, UFL_MOVED)) { + cmistake(u, ord, 187, MSG_EVENT); + } else if (fval(u->race, RCF_ILLUSIONARY) || u->race == new_race[RC_SPELL]) { + cmistake(u, ord, 95, MSG_EVENT); + } else { + /* Monster der Monsterpartei dürfen immer bewachen */ + if (is_monsters(u->faction)) { + guard(u, GUARD_ALL); + } else { + int err = can_start_guarding(u); + if (err==E_GUARD_OK) { + guard(u, GUARD_ALL); + } else if (err==E_GUARD_UNARMED) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_unarmed", "")); + } else if (err==E_GUARD_FLEEING) { + cmistake(u, ord, 320, MSG_EVENT); + } else if (err==E_GUARD_NEWBIE) { + cmistake(u, ord, 304, MSG_EVENT); + } + } + } + } + return 0; +} + +static void +sinkships(region * r) +{ + ship **shp = &r->ships; + + while (*shp) { + ship * sh = *shp; + if (fval(r->terrain, SEA_REGION) && (!enoughsailors(sh, r) || get_captain(sh)==NULL)) { + /* Schiff nicht seetüchtig */ + damage_ship(sh, 0.30); + } + if (shipowner(sh)==NULL) { + damage_ship(sh, 0.05); + } + if (sh->damage >= sh->size * DAMAGE_SCALE) { + remove_ship(shp, sh); + } + if (*shp==sh) shp=&sh->next; + } +} + +/* The following functions do not really belong here: */ +#include +#include + +static attrib_type at_number = { + "faction_renum", + NULL, NULL, NULL, NULL, NULL, + ATF_UNIQUE +}; + +static void +renumber_factions(void) + /* gibt parteien neue nummern */ +{ + struct renum { + struct renum * next; + int want; + faction * faction; + attrib * attrib; + } * renum = NULL, * rp; + faction * f; + for (f=factions;f;f=f->next) { + attrib * a = a_find(f->attribs, &at_number); + int want; + struct renum ** rn; + faction * old; + + if (!a) continue; + want = a->data.i; + if (fval(f, FFL_NEWID)) { + ADDMSG(&f->msgs, msg_message("renumber_twice", "id", want)); + continue; + } + old = findfaction(want); + if (old) { + a_remove(&f->attribs, a); + ADDMSG(&f->msgs, msg_message("renumber_inuse", "id", want)); + continue; + } + if (!faction_id_is_unused(want)) { + a_remove(&f->attribs, a); + ADDMSG(&f->msgs, msg_message("renumber_inuse", "id", want)); + continue; + } + for (rn=&renum; *rn; rn=&(*rn)->next) { + if ((*rn)->want>=want) break; + } + if (*rn && (*rn)->want==want) { + ADDMSG(&f->msgs, msg_message("renumber_inuse", "id", want)); + } else { + struct renum * r = calloc(sizeof(struct renum), 1); + r->next = *rn; + r->attrib = a; + r->faction = f; + r->want = want; + *rn = r; + } + } + for (rp=renum;rp;rp=rp->next) { + f = rp->faction; + a_remove(&f->attribs, rp->attrib); + renumber_faction(f, rp->want); + } + while (renum) { + rp = renum->next; + free(renum); + renum = rp; + } +} + +static void +reorder(void) +{ + region * r; + for (r=regions;r;r=r->next) { + unit ** up=&r->units; + boolean sorted=false; + while (*up) { + unit * u = *up; + if (!fval(u, UFL_MARK)) { + struct order * ord; + for (ord = u->orders;ord;ord=ord->next) { + if (get_keyword(ord)==K_SORT) { + const char * s; + param_t p; + int id; + unit *v; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + p = findparam(s, u->faction->locale); + id = getid(); + v = findunit(id); + + if (v==NULL || v->faction!=u->faction || v->region!=r) { + cmistake(u, ord, 258, MSG_EVENT); + } else if (v->building != u->building || v->ship!=u->ship) { + cmistake(u, ord, 259, MSG_EVENT); + } else if (fval(u, UFL_OWNER)) { + cmistake(u, ord, 260, MSG_EVENT); + } else if (v == u) { + cmistake(u, ord, 10, MSG_EVENT); + } else { + switch(p) { + case P_AFTER: + *up = u->next; + u->next = v->next; + v->next = u; + break; + case P_BEFORE: + if (fval(v, UFL_OWNER)) { + cmistake(v, ord, 261, MSG_EVENT); + } else { + unit ** vp=&r->units; + while (*vp!=v) vp=&(*vp)->next; + *vp = u; + *up = u->next; + u->next = v; + } + break; + } + fset(u, UFL_MARK); + sorted = true; + } + break; + } + } + } + if (u==*up) up=&u->next; + } + if (sorted) { + unit * u; + for (u=r->units;u;u=u->next) freset(u, UFL_MARK); + } + } +} + +#if 0 +/* Aus Gebäude weisen, VERBANNE */ +static void +evict(void) +{ + region *r; + strlist *S; + unit * u; + + for (r=regions;r;r=r->next) { + for (u=r->units;u;u=u->next) { + for (S = u->orders; S; S = S->next) if (get_keyword(ord)==K_EVICT) { + int id; + unit *u2; + /* Nur der Kapitän bzw Burgherr kann jemanden rausschmeißen */ + if(!fval(u, UFL_OWNER)) { + /* Die Einheit ist nicht der Eigentümer */ + cmistake(u,ord,49,MSG_EVENT); + continue; + } + init_tokens(ord); + skip_token(); + id = getid(); + u2 = findunit(id); + + if (u2==NULL) { + /* Einheit nicht gefunden */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + continue; + } + + if (u->building){ + /* in der selben Burg? */ + if (u->building != u2->building){ + /* nicht in Burg */ + cmistake(u,ord,33,MSG_EVENT); + continue; + } + leave_building(u2); + /* meldung an beide */ + } + + if (u->ship){ + if (u->ship != u2->ship){ + /* nicht an Bord */ + cmistake(u, ord, 32, MSG_EVENT); + continue; + } + leave_ship(u2); + /* meldung an beide */ + } + } + } + } +} +#endif + + +static int +renumber_cmd(unit * u, order * ord) +{ + const char * s; + int i; + faction * f = u->faction; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + switch(findparam(s, u->faction->locale)) { + + case P_FACTION: + s = getstrtoken(); + if (s && *s) { + int id = atoi36((const char *)s); + attrib * a = a_find(f->attribs, &at_number); + if (!a) a = a_add(&f->attribs, a_new(&at_number)); + a->data.i = id; + } + break; + + case P_UNIT: + s = getstrtoken(); + if (s == NULL || *s == 0) { + i = newunitid(); + } else { + i = atoi36((const char *)s); + if (i<=0 || i>MAX_UNIT_NR) { + cmistake(u, ord, 114, MSG_EVENT); + break; + } + + if (forbiddenid(i)) { + cmistake(u, ord, 116, MSG_EVENT); + break; + } + + if (findunitg(i, u->region)) { + cmistake(u, ord, 115, MSG_EVENT); + break; + } + } + uunhash(u); + if (!ualias(u)) { + attrib *a = a_add(&u->attribs, a_new(&at_alias)); + a->data.i = -u->no; + } + u->no = i; + uhash(u); + break; + + case P_SHIP: + if (!u->ship) { + cmistake(u, ord, 144, MSG_EVENT); + break; + } + if (u->ship->coast != NODIRECTION) { + cmistake(u, ord, 116, MSG_EVENT); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 146, MSG_EVENT); + break; + } + s = getstrtoken(); + if (s == NULL || *s == 0) { + i = newcontainerid(); + } else { + i = atoi36((const char *)s); + if (i<=0 || i>MAX_CONTAINER_NR) { + cmistake(u,ord,114,MSG_EVENT); + break; + } + if (findship(i) || findbuilding(i)) { + cmistake(u, ord, 115, MSG_EVENT); + break; + } + } + sunhash(u->ship); + u->ship->no = i; + shash(u->ship); + break; + case P_BUILDING: + case P_GEBAEUDE: + if (!u->building) { + cmistake(u,ord,145,MSG_EVENT); + break; + } + if(!fval(u, UFL_OWNER)) { + cmistake(u,ord,148,MSG_EVENT); + break; + } + s = getstrtoken(); + if(*s == 0) { + i = newcontainerid(); + } else { + i = atoi36((const char *)s); + if (i<=0 || i>MAX_CONTAINER_NR) { + cmistake(u,ord,114,MSG_EVENT); + break; + } + if(findship(i) || findbuilding(i)) { + cmistake(u,ord,115,MSG_EVENT); + break; + } + } + bunhash(u->building); + u->building->no = i; + bhash(u->building); + break; + + default: + cmistake(u, ord, 239, MSG_EVENT); + } + return 0; +} + +static building * +age_building(building * b) +{ + static boolean init = false; + static const building_type * bt_blessed; + static const curse_type * ct_astralblock; + if (!init) { + init = true; + bt_blessed = bt_find("blessedstonecircle"); + ct_astralblock = ct_find("astralblock"); + } + + /* blesses stone circles create an astral protection in the astral region + * above the shield, which prevents chaos suction and other spells. + * The shield is created when a magician enters the blessed stone circle, + * and lasts for as long as his skill level / 2 is, at no mana cost. + * + * TODO: this would be nicer in a btype->age function, but we don't have it. + */ + if (ct_astralblock && bt_blessed && b->type==bt_blessed) { + region * r = b->region; + region * rt = r_standard_to_astral(r); + unit * u, * mage = NULL; + + if (fval(rt->terrain, FORBIDDEN_REGION)) rt = NULL; + /* step 1: give unicorns to people in the building, + * find out if there's a magician in there. */ + for (u=r->units;u;u=u->next) { + if (b==u->building && inside_building(u)) { + if (!(u->race->ec_flags & GIVEITEM)==0) { + int n, unicorns = 0; + for (n=0; n!=u->number; ++n) { + if (chance(0.02)) { + i_change(&u->items, olditemtype[I_ELVENHORSE], 1); + ++unicorns; + } + if (unicorns) { + ADDMSG(&u->faction->msgs, msg_message("scunicorn", + "unit amount rtype", u, unicorns, + olditemtype[I_ELVENHORSE]->rtype)); + } + } + } + if (mage==NULL && is_mage(u)) { + mage = u; + } + } + } + + /* if there's a magician, and a connection to astral space, create the + * curse. */ + if (rt!=NULL && mage!=NULL) { + curse * c = get_curse(rt->attribs, ct_astralblock); + if (c==NULL) { + if (mage!=NULL) { + int sk = effskill(mage, SK_MAGIC); + double effect; + effect = 100; + /* the mage reactivates the circle */ + c = create_curse(mage, &rt->attribs, ct_astralblock, + (float)MAX(1, sk), MAX(1, sk/2), effect, 0); + ADDMSG(&r->msgs, msg_message("astralshield_activate", + "region unit", r, mage)); + } + } else if (mage!=NULL) { + int sk = effskill(mage, SK_MAGIC); + c->duration = MAX(c->duration, sk/2); + c->vigour = MAX(c->vigour, sk); + } + } + } + + a_age(&b->attribs); + handle_event(b->attribs, "timer", b); + + if (b->type->age) { + b->type->age(b); + } + + return b; +} + +static double rc_popularity(const struct race * rc) +{ + int pop = get_param_int(rc->parameters, "morale", MORALE_AVERAGE); + return 1.0/(pop-MORALE_COOLDOWN); /* 10 turns average */ +} + +static void age_region(region * r) +{ + a_age(&r->attribs); + handle_event(r->attribs, "timer", r); + + if (!r->land) return; + + if (r->land->ownership && r->land->ownership->owner) { + int stability = turn - r->land->ownership->morale_turn; + int maxmorale = MORALE_DEFAULT; + building * b = largestbuilding(r, &cmp_taxes, false); + if (b) { + int bsize = buildingeffsize(b, false); + maxmorale = (int)(0.5 + b->type->taxes(b, bsize+1) / MORALE_TAX_FACTOR); + } + if (r->land->moraleMORALE_COOLDOWN && r->land->ownership->owner && r->land->moraleland->ownership->owner->race); + if (is_cursed(r->attribs, C_GENEROUS, 0)) { + ch *= 1.2; /* 20% improvement */ + } + if (stability>=MORALE_AVERAGE*2 || chance(ch)) { + region_set_morale(r, r->land->morale+1, turn); + } + } + } else if (r->land->morale>maxmorale) { + region_set_morale(r, r->land->morale-1, turn); + } + } else if (r->land->morale>MORALE_DEFAULT) { + region_set_morale(r, r->land->morale-1, turn); + } +} + +static void +ageing(void) +{ + faction *f; + region *r; + + /* altern spezieller Attribute, die eine Sonderbehandlung brauchen? */ + for(r=regions;r;r=r->next) { + unit *u; + + for (u=r->units;u;u=u->next) { + /* Goliathwasser */ + int i = get_effect(u, oldpotiontype[P_STRONG]); + if (i > 0){ + change_effect(u, oldpotiontype[P_STRONG], -1 * MIN(u->number, i)); + } + /* Berserkerblut*/ + i = get_effect(u, oldpotiontype[P_BERSERK]); + if (i > 0){ + change_effect(u, oldpotiontype[P_BERSERK], -1 * MIN(u->number, i)); + } + + if (is_cursed(u->attribs, C_OLDRACE, 0)){ + curse *c = get_curse(u->attribs, ct_find("oldrace")); + if (c->duration == 1 && !(c_flags(c) & CURSE_NOAGE)) { + u->race = new_race[curse_geteffect_int(c)]; + u->irace = NULL; + } + } + } + } + + /* Borders */ + age_borders(); + + /* Factions */ + for (f=factions;f;f=f->next) { + a_age(&f->attribs); + handle_event(f->attribs, "timer", f); + } + + /* Regionen */ + for (r=regions;r;r=r->next) { + building ** bp; + unit ** up; + ship ** sp; + + age_region(r); + + /* Einheiten */ + for (up=&r->units;*up;) { + unit * u = *up; + a_age(&u->attribs); + if (u==*up) handle_event(u->attribs, "timer", u); + if (u==*up) up = &(*up)->next; + } + + /* Schiffe */ + for (sp=&r->ships;*sp;) { + ship * s = *sp; + a_age(&s->attribs); + if (s==*sp) handle_event(s->attribs, "timer", s); + if (s==*sp) sp = &(*sp)->next; + } + + /* Gebäude */ + for (bp=&r->buildings;*bp;) { + building * b = *bp; + age_building(b); + if (b==*bp) bp = &b->next; + } + + if (rule_region_owners()) { + update_owners(r); + } + } +} + +static int +maxunits(const faction *f) +{ + int flimit = rule_faction_limit(); + int alimit = rule_alliance_limit(); + if (alimit==0) { + return flimit; + } + if (flimit==0) { + return alimit; + } + return MIN(alimit, flimit); +} + +int +checkunitnumber(const faction *f, int add) +{ + int alimit, flimit; + + alimit = rule_alliance_limit(); + if (alimit) { + /* if unitsperalliance is true, maxunits returns the + number of units allowed in an alliance */ + faction *f2; + int unitsinalliance = add; + + for (f2 = factions; f2; f2 = f2->next) { + if (f->alliance == f2->alliance) { + unitsinalliance += f2->no_units; + } + if (unitsinalliance > alimit) { + return 1; + } + } + } + + flimit = rule_faction_limit(); + if (flimit) { + if (f->no_units + add > flimit) { + return 2; + } + } + + return 0; +} + +static void +new_units(void) +{ + region *r; + unit *u, *u2; + + /* neue einheiten werden gemacht und ihre befehle (bis zum "ende" zu + * ihnen rueberkopiert, damit diese einheiten genauso wie die alten + * einheiten verwendet werden koennen. */ + + for (r = regions; r; r = r->next) { + for (u = r->units; u; u = u->next) { + order ** ordp = &u->orders; + + /* this needs to happen very early in the game somewhere. since this is + ** pretty much the first function called per turn, and I am lazy, I + ** decree that it goes here */ + if (u->flags&UFL_GUARD) { + fset(r, RF_GUARDED); + } + + while (*ordp) { + order * makeord = *ordp; + if (get_keyword(makeord) == K_MAKE) { + init_tokens(makeord); + skip_token(); + if (getparam(u->faction->locale) == P_TEMP) { + const char * token; + char * name = NULL; + 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 (get_keyword(ord) == K_END) break; + *ordp = ord->next; + ord->next = NULL; + free_order(ord); + } + continue; + } + alias = getid(); + + token = getstrtoken(); + if (token && token[0]) { + name = strdup(token); + } + u2 = create_unit(r, u->faction, 0, u->faction->race, alias, name, u); + if (name!=NULL) free(name); + 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 (get_keyword(ord) == K_END) break; + *ordp = ord->next; + ord->next = NULL; + *newordersp = ord; + newordersp = &ord->next; + } + } + } + if (*ordp==makeord) ordp=&makeord->next; + } + } + } +} + +static void +setdefaults(unit *u) +{ + order *ord; + boolean trade = false; + boolean hunger = LongHunger(u); + + freset(u, UFL_LONGACTION); + if (hunger) { + /* Hungernde Einheiten führen NUR den default-Befehl aus */ + set_order(&u->thisorder, default_order(u->faction->locale)); + } + /* check all orders for a potential new long order this round: */ + for (ord = u->orders; ord; ord = ord->next) { + if (u->old_orders && is_repeated(ord)) { + /* this new order will replace the old defaults */ + free_orders(&u->old_orders); + if (hunger) break; + } + if (hunger) continue; + + if (is_exclusive(ord)) { + /* Über dieser Zeile nur Befehle, die auch eine idle Faction machen darf */ + if (idle(u->faction)) { + set_order(&u->thisorder, default_order(u->faction->locale)); + } else { + set_order(&u->thisorder, copy_order(ord)); + } + break; + } else { + keyword_t keyword = get_keyword(ord); + switch (keyword) { + /* Wenn gehandelt wird, darf kein langer Befehl ausgeführt + * werden. Da Handel erst nach anderen langen Befehlen kommt, + * muß das vorher abgefangen werden. Wir merken uns also + * hier, ob die Einheit handelt. */ + case NOKEYWORD: + cmistake(u, ord, 22, MSG_EVENT); + break; + case K_BUY: + case K_SELL: + /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht + * werden. */ + trade = true; + break; + + case K_CAST: + /* dient dazu, das neben Zaubern kein weiterer Befehl + * ausgeführt werden kann, Zaubern ist ein kurzer Befehl */ + set_order(&u->thisorder, NULL); + break; + + case K_WEREWOLF: + set_order(&u->thisorder, copy_order(ord)); + break; + + /* Wird je diese Ausschliesslichkeit aufgehoben, muss man aufpassen + * mit der Reihenfolge von Kaufen, Verkaufen etc., damit es Spielern + * nicht moeglich ist, Schulden zu machen. */ + } + } + } + + if (hunger) return; + + /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht + * werden. */ + + if (trade == true) { + /* fset(u, UFL_LONGACTION|UFL_NOTMOVING); */ + set_order(&u->thisorder, NULL); + } +} + +static int +use_item(unit * u, const item_type * itype, int amount, struct order * ord) +{ + int i; + int target = read_unitid(u->faction, u->region); + + i = get_pooled(u, itype->rtype, GET_DEFAULT, amount); + + if (amount>i) { + amount = i; + } + if (amount==0) { + cmistake(u, ord, 43, MSG_PRODUCE); + return ENOITEM; + } + + if (target==-1) { + if (itype->use==NULL) { + cmistake(u, ord, 76, MSG_PRODUCE); + return EUNUSABLE; + } + return itype->use(u, itype, amount, ord); + } else { + if (itype->useonother==NULL) { + cmistake(u, ord, 76, MSG_PRODUCE); + return EUNUSABLE; + } + return itype->useonother(u, target, itype, amount, ord); + } +} + + +static double +heal_factor(const unit * u) +{ + static float elf_regen = -1; + switch(old_race(u->race)) { + case RC_TROLL: + case RC_DAEMON: + return 1.5; + case RC_GOBLIN: + return 2.0; + case RC_ELF: + if (elf_regen<0) elf_regen = get_param_flt(u->race->parameters, "regen.forest", 1.0F); + if (elf_regen!=1.0 && r_isforest(u->region)) { + return elf_regen; + } + return 1.0; + } + return 1.0; +} + +static void +monthly_healing(void) +{ + region *r; + static const curse_type * heal_ct = NULL; + if (heal_ct==NULL) heal_ct = ct_find("healingzone"); + + for (r = regions; r; r = r->next) { + unit *u; + double healingcurse = 0; + + if (heal_ct!=NULL) { + /* bonus zurücksetzen */ + curse * c = get_curse(r->attribs, heal_ct); + if (c!=NULL) { + healingcurse = curse_geteffect(c); + } + } + for (u = r->units; u; u = u->next) { + int umhp = unit_max_hp(u) * u->number; + double p = 1.0; + + /* hp über Maximum bauen sich ab. Wird zb durch Elixier der Macht + * oder verändertes Ausdauertalent verursacht */ + if (u->hp > umhp) { + u->hp -= (int) ceil((u->hp - umhp) / 2.0); + if (u->hp < umhp) u->hp = umhp; + continue; + } + + if (u->race->flags & RCF_NOHEAL) continue; + if (fval(u, UFL_HUNGER)) continue; + + if (fval(r->terrain, SEA_REGION) && u->ship==NULL && !(canswim(u) || canfly(u))) { + continue; + } + + p *= heal_factor(u); + if (u->hp < umhp) { +#ifdef NEW_DAEMONHUNGER_RULE + double maxheal = MAX(u->number, umhp/20.0); +#else + double maxheal = MAX(u->number, umhp/10.0); +#endif + int addhp; + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + if (btype == bt_find("inn")) { + p *= 1.5; + } + /* pro punkt 5% höher */ + p *= (1.0 + healingcurse * 0.05); + + maxheal = p * maxheal; + addhp = (int)maxheal; + maxheal -= addhp; + if (maxheal>0.0 && chance(maxheal)) ++addhp; + + /* Aufaddieren der geheilten HP. */ + u->hp = MIN(u->hp + addhp, umhp); + + /* soll man an negativer regeneration sterben können? */ + assert(u->hp > 0); + } + } + } +} + +static void +remove_exclusive(order ** ordp) +{ + while (*ordp) { + order * ord = *ordp; + if (is_exclusive(ord)) { + *ordp = ord->next; + ord->next = NULL; + free_order(ord); + } else { + ordp = &ord->next; + } + } +} + +static void +defaultorders (void) +{ + region *r; + for (r=regions;r;r=r->next) { + unit *u; + for (u=r->units;u;u=u->next) { + boolean neworders = false; + order ** ordp = &u->orders; + while (*ordp!=NULL) { + order * ord = *ordp; + if (get_keyword(ord)==K_DEFAULT) { + char lbuf[8192]; + order * new_order; + init_tokens(ord); + skip_token(); /* skip the keyword */ + strcpy(lbuf, getstrtoken()); + new_order = parse_order(lbuf, u->faction->locale); + *ordp = ord->next; + ord->next = NULL; + free_order(ord); + if (!neworders) { + /* lange Befehle aus orders und old_orders löschen zu gunsten des neuen */ + remove_exclusive(&u->orders); + remove_exclusive(&u->old_orders); + neworders = true; + ordp = &u->orders; /* we could have broken ordp */ + } + if (new_order) addlist(&u->old_orders, new_order); + } + else ordp = &ord->next; + } + } + } +} + +/* ************************************************************ */ +/* GANZ WICHTIG! ALLE GEÄNDERTEN SPRÜCHE NEU ANZEIGEN */ +/* GANZ WICHTIG! FÜGT AUCH NEUE ZAUBER IN DIE LISTE DER BEKANNTEN EIN */ +/* ************************************************************ */ +#define MAXMAGES 128 /* should be enough */ +static void +update_spells(void) +{ + faction * f; + + for (f=factions;f;f=f->next) { + if (f->magiegebiet!=M_NONE && !is_monsters(f)) { + unit * mages[MAXMAGES]; + unit *u; + int maxlevel = 0, n = 0, i; + + for (u=f->units;u;u=u->nextF) { + if (u->number>0) { + sc_mage *mage = get_mage(u); + if (mage) { + int level = eff_skill(u, SK_MAGIC, u->region); + if (level>maxlevel) maxlevel = level; + assert(nf->max_spelllevel) { + update_spellbook(f, maxlevel); + for (i=0;i!=n;++i) { + sc_mage *mage = get_mage(mages[i]); + while (mage->spells) { + spell_list * slist = mage->spells; + mage->spells = slist->next; + free(slist); + } + } + } + for (i=0;i!=n;++i) { + updatespelllist(mages[i]); + } + } + } +} + +static void +age_factions(void) +{ + faction *f; + + for (f = factions; f; f = f->next) { + ++f->age; + if (f->age+1 < NewbieImmunity()) { + ADDMSG(&f->msgs, msg_message("newbieimmunity", "turns", + NewbieImmunity() - f->age - 1)); + } + } +} + +static int +use_cmd(unit * u, struct order * ord) +{ + const char * t; + int n; + const item_type * itype; + + init_tokens(ord); + skip_token(); + + t = getstrtoken(); + n = atoi((const char *)t); + if (n==0) { + if (findparam(t, u->faction->locale) == P_ANY) { + /* BENUTZE ALLES Yanxspirit */ + n = INT_MAX; + t = getstrtoken(); + } else { + /* BENUTZE Yanxspirit */ + n = 1; + } + } else { + /* BENUTZE 42 Yanxspirit */ + t = getstrtoken(); + } + itype = finditemtype(t, u->faction->locale); + + if (itype!=NULL) { + int i = use_item(u, itype, n, ord); + assert(i<=0 || !"use_item should not return positive values."); + if (i>0) { + log_error(("use_item returned a value>0 for %s\n", resourcename(itype->rtype, 0))); + } + } else { + cmistake(u, ord, 43, MSG_PRODUCE); + } + return 0; +} + +static int +pay_cmd(unit * u, struct order * ord) +{ + if (!u->building) { + cmistake(u, ord, 6, MSG_EVENT); + } else { + param_t p; + init_tokens(ord); + skip_token(); + p = getparam(u->faction->locale); + if (p==P_NOT) { + unit * owner = building_owner(u->building); + if (owner->faction!=u->faction) { + cmistake(u, ord, 1222, MSG_EVENT); + } else { + u->building->flags |= BLD_DONTPAY; + } + } + } + return 0; +} + +static int +claim_cmd(unit * u, struct order * ord) +{ + const char * t; + int n; + const item_type * itype; + + init_tokens(ord); + skip_token(); + + t = getstrtoken(); + n = atoi((const char *)t); + if (n==0) { + n = 1; + } else { + t = getstrtoken(); + } + itype = finditemtype(t, u->faction->locale); + + if (itype!=NULL) { + item ** iclaim = i_find(&u->faction->items, itype); + if (iclaim!=NULL && *iclaim!=NULL) { + n = MIN(n, (*iclaim)->number); + i_change(iclaim, itype, -n); + i_change(&u->items, itype, n); + } + } else { + cmistake(u, ord, 43, MSG_PRODUCE); + } + return 0; +} + +enum { + PROC_THISORDER = 1<<0, + PROC_LONGORDER = 1<<1 +}; +typedef struct processor { + struct processor * next; + int priority; + enum { PR_GLOBAL, PR_REGION_PRE, PR_UNIT, PR_ORDER, PR_REGION_POST } type; + unsigned int flags; + union { + struct { + keyword_t kword; + int (*process)(struct unit *, struct order *); + } per_order; + struct { + void (*process)(struct unit *); + } per_unit; + struct { + void (*process)(struct region *); + } per_region; + struct { + void (*process)(void); + } global; + } data; + const char * name; +} processor; + +static processor * processors; + +processor * +add_proc(int priority, const char * name, int type) +{ + processor **pproc = &processors; + processor *proc; + + while (*pproc) { + proc = *pproc; + if (proc->priority>priority) break; + else if (proc->priority==priority && proc->type>=type) break; + pproc = &proc->next; + } + + proc = malloc(sizeof(processor)); + proc->priority = priority; + proc->type = type; + proc->name = name; + proc->next = *pproc; + *pproc = proc; + return proc; +} + +void +add_proc_order(int priority, keyword_t kword, int (*parser)(struct unit *, struct order *), unsigned int flags, const char * name) +{ + if (!global.disabled[kword]) { + processor * proc = add_proc(priority, name, PR_ORDER); + if (proc) { + proc->data.per_order.process = parser; + proc->data.per_order.kword = kword; + proc->flags = flags; + } + } +} + +void +add_proc_global(int priority, void (*process)(void), const char * name) +{ + processor * proc = add_proc(priority, name, PR_GLOBAL); + if (proc) { + proc->data.global.process = process; + } +} + +void +add_proc_region(int priority, void (*process)(region *), const char * name) +{ + processor * proc = add_proc(priority, name, PR_REGION_PRE); + if (proc) { + proc->data.per_region.process = process; + } +} + +void +add_proc_postregion(int priority, void (*process)(region *), const char * name) +{ + processor * proc = add_proc(priority, name, PR_REGION_POST); + if (proc) { + proc->data.per_region.process = process; + } +} + +void +add_proc_unit(int priority, void (*process)(unit *), const char * name) +{ + processor * proc = add_proc(priority, name, PR_UNIT); + if (proc) { + proc->data.per_unit.process = process; + } +} + +/* per priority, execute processors in order from PR_GLOBAL down to PR_ORDER */ +void +process(void) +{ + processor *proc = processors; + faction * f; + + while (proc) { + int prio = proc->priority; + region *r; + processor *pglobal = proc; + + if (verbosity>=3) printf("- Step %u\n", prio); + while (proc && proc->priority==prio) { + if (proc->name && verbosity>=1) log_stdio(stdout, " - %s\n", proc->name); + proc = proc->next; + } + + while (pglobal && pglobal->priority==prio && pglobal->type==PR_GLOBAL) { + pglobal->data.global.process(); + pglobal = pglobal->next; + } + if (pglobal==NULL || pglobal->priority!=prio) continue; + + for (r = regions; r; r = r->next) { + unit *u; + processor *pregion = pglobal; + + while (pregion && pregion->priority==prio && pregion->type==PR_REGION_PRE) { + pregion->data.per_region.process(r); + pregion = pregion->next; + } + if (pregion==NULL || pregion->priority!=prio) continue; + + if (r->units) { + for (u=r->units;u;u=u->next) { + processor *porder, *punit = pregion; + + while (punit && punit->priority==prio && punit->type==PR_UNIT) { + punit->data.per_unit.process(u); + punit = punit->next; + } + if (punit==NULL || punit->priority!=prio) continue; + + porder = punit; + while (porder && porder->priority==prio && porder->type==PR_ORDER) { + order ** ordp = &u->orders; + if (porder->flags & PROC_THISORDER) ordp = &u->thisorder; + while (*ordp) { + order * ord = *ordp; + if (get_keyword(ord) == porder->data.per_order.kword) { + if (porder->flags & PROC_LONGORDER) { + if (u->number==0) { + ord = NULL; + } else if (u->race == new_race[RC_INSECT] && r_insectstalled(r) && !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) { + ord = NULL; + } else if (LongHunger(u)) { + cmistake(u, ord, 224, MSG_MAGIC); + ord = NULL; + } else if (fval(u, UFL_LONGACTION)) { + cmistake(u, ord, 52, MSG_PRODUCE); + ord = NULL; + } else if (fval(r->terrain, SEA_REGION) && u->race != new_race[RC_AQUARIAN] && !(u->race->flags & RCF_SWIM)) { + /* error message disabled by popular demand */ + ord = NULL; + } + } + if (ord) { + porder->data.per_order.process(u, ord); + } + } + if (!ord || *ordp==ord) ordp=&(*ordp)->next; + } + porder = porder->next; + } + } + } + + while (pregion && pregion->priority==prio && pregion->type!=PR_REGION_POST) { + pregion = pregion->next; + } + + while (pregion && pregion->priority==prio && pregion->type==PR_REGION_POST) { + pregion->data.per_region.process(r); + pregion = pregion->next; + } + if (pregion==NULL || pregion->priority!=prio) continue; + + } + } + + if (verbosity>=3) printf("\n - Leere Gruppen loeschen...\n"); + for (f=factions; f; f=f->next) { + group ** gp = &f->groups; + while (*gp) { + group * g = *gp; + if (g->members==0) { + *gp = g->next; + free_group(g); + } else + gp = &g->next; + } + } + +} + +static void enter_1(region * r) { do_misc(r, false); } +static void enter_2(region * r) { do_misc(r, true); } +static void maintain_buildings_1(region * r) { maintain_buildings(r, false); } +#ifdef COLLAPSE_CHANCE +static void maintain_buildings_2(region * r) { maintain_buildings(r,true); } +#endif +static void reset_moved(unit * u) { freset(u, UFL_MOVED); } + +/** warn about passwords that are not US ASCII. + * even though passwords are technically UTF8 strings, the server receives + * them as part of the Subject of an email when reports are requested. + * This means that we need to limit them to ASCII characters until that + * mechanism has been changed. + */ +static int +warn_password(void) +{ + faction * f = factions; + while (f) { + boolean pwok = true; + const char * c = f->passw; + while (*c && pwok) { + if (!isalnum((unsigned char)*c)) pwok = false; + c++; + } + if (!pwok) { + free(f->passw); + f->passw = strdup(itoa36(rng_int())); + ADDMSG(&f->msgs, msg_message("illegal_password", "newpass", f->passw)); + } + f = f->next; + } + return 0; +} + +void +init_processor(void) +{ + int p; + + p = 10; + add_proc_global(p, &new_units, "Neue Einheiten erschaffen"); + + p+=10; + add_proc_unit(p, &setdefaults, "Default-Befehle"); + add_proc_order(p, K_BANNER, &banner_cmd, 0, NULL); + add_proc_order(p, K_EMAIL, &email_cmd, 0, NULL); + add_proc_order(p, K_PASSWORD, &password_cmd, 0, NULL); + add_proc_order(p, K_SEND, &send_cmd, 0, NULL); + add_proc_order(p, K_GROUP, &group_cmd, 0, NULL); + + p+=10; + add_proc_unit(p, &reset_moved, "Instant-Befehle"); + add_proc_order(p, K_QUIT, &quit_cmd, 0, NULL); + add_proc_order(p, K_URSPRUNG, &origin_cmd, 0, NULL); + add_proc_order(p, K_ALLY, &ally_cmd, 0, NULL); + add_proc_order(p, K_PREFIX, &prefix_cmd, 0, NULL); + add_proc_order(p, K_SETSTEALTH, &setstealth_cmd, 0, NULL); + add_proc_order(p, K_STATUS, &status_cmd, 0, NULL); + add_proc_order(p, K_COMBATSPELL, &combatspell_cmd, 0, NULL); + add_proc_order(p, K_DISPLAY, &display_cmd, 0, NULL); + add_proc_order(p, K_NAME, &name_cmd, 0, NULL); + add_proc_order(p, K_GUARD, &guard_off_cmd, 0, NULL); + add_proc_order(p, K_RESHOW, &reshow_cmd, 0, NULL); + + if (get_param_int(global.parameters, "rules.alliances", 0)==1) { + p+=10; + add_proc_global(p, &alliance_cmd, NULL); + } + + p+=10; + add_proc_global(p, &age_factions, "Parteienalter++"); + add_proc_order(p, K_MAIL, &mail_cmd, 0, "Botschaften"); + + p+=10; /* all claims must be done before we can USE */ + add_proc_region(p, &enter_1, "Kontaktieren & Betreten (1. Versuch)"); + add_proc_order(p, K_USE, &use_cmd, 0, "Benutzen"); + + if (!global.disabled[K_GM]) { + add_proc_global(p, &gmcommands, "GM Kommandos"); + } + + p += 10; /* in case it has any effects on alliance victories */ + add_proc_order(p, K_GIVE, &give_control_cmd, 0, "GIB KOMMANDO"); + + p += 10; /* in case it has any effects on alliance victories */ + add_proc_order(p, K_LEAVE, &leave_cmd, 0, "Verlassen"); + + if (!nobattle) { + add_proc_region(p, &do_battle, "Attackieren"); + } + + if (!global.disabled[K_BESIEGE]) { + p+=10; + add_proc_region(p, &do_siege, "Belagern"); + } + + p+=10; /* can't allow reserve before siege (weapons) */ + add_proc_region(p, &enter_1, "Kontaktieren & Betreten (2. Versuch)"); + add_proc_order(p, K_RESERVE, &reserve_cmd, 0, "Reservieren"); + add_proc_order(p, K_CLAIM, &claim_cmd, 0, NULL); + add_proc_unit(p, &follow_unit, "Folge auf Einheiten setzen"); + + p+=10; /* rest rng again before economics */ + add_proc_region(p, &economics, "Zerstoeren, Geben, Rekrutieren, Vergessen"); + + p+=10; + if (!global.disabled[K_PAY]) { + add_proc_order(p, K_PAY, &pay_cmd, 0, "Gebaeudeunterhalt (disable)"); + } + add_proc_postregion(p, &maintain_buildings_1, "Gebaeudeunterhalt (1. Versuch)"); + + p+=10; /* QUIT fuer sich alleine */ + add_proc_global(p, &quit, "Sterben"); + if (!global.disabled[K_RESTART]) { + add_proc_global(p, &parse_restart, "Neustart"); + } + + if (!global.disabled[K_CAST]) { + p+=10; + add_proc_global(p, &magic, "Zaubern"); + } + + p+=10; + add_proc_order(p, K_TEACH, &teach_cmd, PROC_THISORDER|PROC_LONGORDER, "Lehren"); + p+=10; + add_proc_order(p, K_STUDY, &learn_cmd, PROC_THISORDER|PROC_LONGORDER, "Lernen"); + + p+=10; + add_proc_order(p, K_MAKE, &make_cmd, PROC_THISORDER|PROC_LONGORDER, "Produktion"); + add_proc_postregion(p, &produce, "Arbeiten, Handel, Rekruten"); + add_proc_postregion(p, &split_allocations, "Produktion II"); + + p+=10; + add_proc_region(p, &enter_2, "Kontaktieren & Betreten (3. Versuch)"); + + p+=10; + add_proc_region(p, &sinkships, "Schiffe sinken"); + + p+=10; + add_proc_global(p, &movement, "Bewegungen"); + + if (get_param_int(global.parameters, "work.auto", 0)) { + p+=10; + add_proc_region(p, &auto_work, "Arbeiten (auto)"); + } + + p+=10; + add_proc_order(p, K_GUARD, &guard_on_cmd, 0, "Bewache (an)"); +#if XECMD_MODULE + /* can do together with guard */ + add_proc_order(p, K_XE, &xecmd, 0, "Zeitung"); +#endif + + p+=10; + add_proc_global(p, &encounters, "Zufallsbegegnungen"); + p+=10; + add_proc_unit(p, &monster_kills_peasants, "Monster fressen und vertreiben Bauern"); + + p+=10; + add_proc_global(p, &randomevents, "Zufallsereignisse"); + + p+=10; + + add_proc_global(p, &monthly_healing, "Regeneration (HP)"); + add_proc_global(p, ®eneration_magiepunkte, "Regeneration (Aura)"); + if (!global.disabled[K_DEFAULT]) { + add_proc_global(p, &defaultorders, "Defaults setzen"); + } + add_proc_global(p, &demographics, "Nahrung, Seuchen, Wachstum, Wanderung"); + +#ifdef COLLAPSE_CHANCE + p+=10; + add_proc_region(p, &maintain_buildings_2, "Gebaeudeunterhalt (2. Versuch)"); +#endif + + if (!global.disabled[K_SORT]) { + p+=10; + add_proc_global(p, &reorder, "Einheiten sortieren"); + } + add_proc_order(p, K_PROMOTION, &promotion_cmd, 0, "Heldenbefoerderung"); + if (!global.disabled[K_NUMBER]) { + add_proc_order(p, K_NUMBER, &renumber_cmd, 0, "Neue Nummern (Einheiten)"); + p+=10; + add_proc_global(p, &renumber_factions, "Neue Nummern"); + } +} + +void +processorders (void) +{ + static int init = 0; + + if (!init) { + init_processor(); + init = 1; + } + update_spells(); + process(); + /*************************************************/ + + if (get_param_int(global.parameters, "modules.markets", 0)) { + do_markets(); + } + + if (verbosity>=1) puts(" - Attribute altern"); + ageing(); + remove_empty_units(); + + /* must happen AFTER age, because that would destroy them right away */ + if (get_param_int(global.parameters, "modules.wormholes", 0)) { + create_wormholes(); + } + + /* immer ausführen, wenn neue Sprüche dazugekommen sind, oder sich + * Beschreibungen geändert haben */ + update_spells(); + warn_password(); +} + +int +writepasswd(void) +{ + FILE * F; + char zText[128]; + + sprintf(zText, "%s/passwd", basepath()); + F = cfopen(zText, "w"); + if (F) { + faction *f; + puts("writing passwords..."); + + for (f = factions; f; f = f->next) { + fprintf(F, "%s:%s:%s:%s:%u\n", + factionid(f), f->email, f->passw, f->override, f->subscription); + } + fclose(F); + return 0; + } + return 1; +} + +void +update_subscriptions(void) +{ + FILE * F; + char zText[MAX_PATH]; + faction * f; + strcat(strcpy(zText, basepath()), "/subscriptions"); + F = fopen(zText, "r"); + if (F==NULL) { + log_warning((0, "could not open %s.\n", zText)); + return; + } + for (;;) { + char zFaction[5]; + int subscription, fno; + if (fscanf(F, "%d %s", &subscription, zFaction)<=0) break; + fno = atoi36(zFaction); + f = findfaction(fno); + if (f!=NULL) { + f->subscription=subscription; + } + } + fclose(F); + + sprintf(zText, "subscriptions.%u", turn); + F = fopen(zText, "w"); + for (f=factions;f!=NULL;f=f->next) { + fprintf(F, "%s:%u:%s:%s:%s:%u:\n", + itoa36(f->no), f->subscription, f->email, f->override, + dbrace(f->race), f->lastorders); + } + fclose(F); +} + +int +init_data(const char * filename, const char * catalog) +{ + int l; + + l = read_xml(filename, catalog); + if (l) return l; + + init_locales(); + init_archetypes(); + + if (turn<0) { + turn = first_turn; + } + return 0; +} + +#ifndef DISABLE_TESTS +#include "laws_test.c" +#endif diff --git a/src/gamecode/laws.h b/src/gamecode/laws.h index 5aa7d6f94..7b1e12cb0 100644 --- a/src/gamecode/laws.h +++ b/src/gamecode/laws.h @@ -1,47 +1,47 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_GC_LAWS -#define H_GC_LAWS -#ifdef __cplusplus -extern "C" { -#endif - -extern int writepasswd(void); -int getoption(void); -int wanderoff(struct region * r, int p); -void demographics(void); -void last_orders(void); -void find_address(void); -void update_guards(void); -void update_subscriptions(void); -void deliverMail(struct faction * f, struct region * r, struct unit * u, const char *s, struct unit * receiver); -int init_data(const char * filename, const char * catalog); - -/* eressea-specific. put somewhere else, please. */ -void processorders(void); -extern struct attrib_type at_germs; - -extern int dropouts[2]; -extern int * age; - -#ifdef __cplusplus -} -#endif - -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_GC_LAWS +#define H_GC_LAWS +#ifdef __cplusplus +extern "C" { +#endif + +extern int writepasswd(void); +int getoption(void); +int wanderoff(struct region * r, int p); +void demographics(void); +void last_orders(void); +void find_address(void); +void update_guards(void); +void update_subscriptions(void); +void deliverMail(struct faction * f, struct region * r, struct unit * u, const char *s, struct unit * receiver); +int init_data(const char * filename, const char * catalog); + +/* eressea-specific. put somewhere else, please. */ +void processorders(void); +extern struct attrib_type at_germs; + +extern int dropouts[2]; +extern int * age; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/gamecode/laws_test.c b/src/gamecode/laws_test.c index 2bc958813..f836ff784 100644 --- a/src/gamecode/laws_test.c +++ b/src/gamecode/laws_test.c @@ -1,148 +1,148 @@ -/* this file should only be included by laws.c, never compiled on its own - * (it does not even include all the headers needed to do so). -**/ -#include - -static void test_new_building_can_be_renamed(CuTest * tc) { - region * r; - building * b; - building_type * btype = bt_find("castle"); - - test_cleanup(); - test_create_world(); - r = findregion(-1, 0); - - b = new_building(btype, r, default_locale); - CuAssertTrue(tc, !renamed_building(b)); -} - -static void test_fishing_feeds_2_people(CuTest * tc) { - region * r; - faction * f; - unit * u; - ship * sh; - - test_cleanup(); - test_create_world(); - r = findregion(-1, 0); - CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ - f = test_create_faction(rc_find("human")); - u = test_create_unit(f, r); - sh = new_ship(st_find("boat"), NULL, r); - u->ship = sh; - i_change(&u->items, it_find("money"), 42); - - scale_number(u, 1); - sh->flags |= SF_FISHING; - get_food(r); - CuAssertIntEquals(tc, 42, i_get(u->items, it_find("money"))); - - scale_number(u, 2); - sh->flags |= SF_FISHING; - get_food(r); - CuAssertIntEquals(tc, 42, i_get(u->items, it_find("money"))); - - scale_number(u, 3); - sh->flags |= SF_FISHING; - get_food(r); - CuAssertIntEquals(tc, 32, i_get(u->items, it_find("money"))); - -} - -static int not_so_hungry(const unit * u) { - return 6 * u->number; -} - -static void test_fishing_does_not_give_goblins_money(CuTest * tc) { - region * r; - faction * f; - unit * u; - ship * sh; - - test_cleanup(); - test_create_world(); - - r = findregion(-1, 0); - CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ - f = test_create_faction(rc_find("human")); - u = test_create_unit(f, r); - sh = new_ship(st_find("boat"), NULL, r); - u->ship = sh; - i_change(&u->items, it_find("money"), 42); - - global.functions.maintenance = not_so_hungry; - scale_number(u, 2); - sh->flags |= SF_FISHING; - get_food(r); - CuAssertIntEquals(tc, 42, i_get(u->items, it_find("money"))); - -} - -static void test_fishing_gets_reset(CuTest * tc) { - region * r; - faction * f; - unit * u; - ship * sh; - - test_cleanup(); - test_create_world(); - r = findregion(-1, 0); - CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ - f = test_create_faction(rc_find("human")); - u = test_create_unit(f, r); - sh = new_ship(st_find("boat"), NULL, r); - u->ship = sh; - i_change(&u->items, it_find("money"), 42); - - scale_number(u, 1); - sh->flags |= SF_FISHING; - get_food(r); - CuAssertIntEquals(tc, 42, i_get(u->items, it_find("money"))); - - scale_number(u, 1); - get_food(r); - CuAssertIntEquals(tc, 32, i_get(u->items, it_find("money"))); - -} - -static void test_unit_limit(CuTest * tc) { - set_param(&global.parameters, "rules.limit.faction", "250"); - CuAssertIntEquals(tc, 250, rule_faction_limit()); - - set_param(&global.parameters, "rules.limit.faction", "200"); - CuAssertIntEquals(tc, 200, rule_faction_limit()); - - set_param(&global.parameters, "rules.limit.alliance", "250"); - CuAssertIntEquals(tc, 250, rule_alliance_limit()); - -} - -extern int checkunitnumber(const faction *f, int add); -static void test_cannot_create_unit_above_limit(CuTest * tc) { - faction * f; - - test_cleanup(); - test_create_world(); - f = test_create_faction(rc_find("human")); - set_param(&global.parameters, "rules.limit.faction", "4"); - - CuAssertIntEquals(tc, 0, checkunitnumber(f, 4)); - CuAssertIntEquals(tc, 2, checkunitnumber(f, 5)); - - set_param(&global.parameters, "rules.limit.alliance", "3"); - CuAssertIntEquals(tc, 0, checkunitnumber(f, 3)); - CuAssertIntEquals(tc, 1, checkunitnumber(f, 4)); -} - - -CuSuite* get_laws_suite(void) -{ - CuSuite* suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, &test_new_building_can_be_renamed); - SUITE_ADD_TEST(suite, &test_fishing_feeds_2_people); - SUITE_ADD_TEST(suite, &test_fishing_does_not_give_goblins_money); - SUITE_ADD_TEST(suite, &test_fishing_gets_reset); - SUITE_ADD_TEST(suite, &test_unit_limit); - SUITE_ADD_TEST(suite, &test_cannot_create_unit_above_limit); - return suite; -} +/* this file should only be included by laws.c, never compiled on its own + * (it does not even include all the headers needed to do so). +**/ +#include + +static void test_new_building_can_be_renamed(CuTest * tc) { + region * r; + building * b; + building_type * btype = bt_find("castle"); + + test_cleanup(); + test_create_world(); + r = findregion(-1, 0); + + b = new_building(btype, r, default_locale); + CuAssertTrue(tc, !renamed_building(b)); +} + +static void test_fishing_feeds_2_people(CuTest * tc) { + region * r; + faction * f; + unit * u; + ship * sh; + + test_cleanup(); + test_create_world(); + r = findregion(-1, 0); + CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ + f = test_create_faction(rc_find("human")); + u = test_create_unit(f, r); + sh = new_ship(st_find("boat"), NULL, r); + u->ship = sh; + i_change(&u->items, it_find("money"), 42); + + scale_number(u, 1); + sh->flags |= SF_FISHING; + get_food(r); + CuAssertIntEquals(tc, 42, i_get(u->items, it_find("money"))); + + scale_number(u, 2); + sh->flags |= SF_FISHING; + get_food(r); + CuAssertIntEquals(tc, 42, i_get(u->items, it_find("money"))); + + scale_number(u, 3); + sh->flags |= SF_FISHING; + get_food(r); + CuAssertIntEquals(tc, 32, i_get(u->items, it_find("money"))); + +} + +static int not_so_hungry(const unit * u) { + return 6 * u->number; +} + +static void test_fishing_does_not_give_goblins_money(CuTest * tc) { + region * r; + faction * f; + unit * u; + ship * sh; + + test_cleanup(); + test_create_world(); + + r = findregion(-1, 0); + CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ + f = test_create_faction(rc_find("human")); + u = test_create_unit(f, r); + sh = new_ship(st_find("boat"), NULL, r); + u->ship = sh; + i_change(&u->items, it_find("money"), 42); + + global.functions.maintenance = not_so_hungry; + scale_number(u, 2); + sh->flags |= SF_FISHING; + get_food(r); + CuAssertIntEquals(tc, 42, i_get(u->items, it_find("money"))); + +} + +static void test_fishing_gets_reset(CuTest * tc) { + region * r; + faction * f; + unit * u; + ship * sh; + + test_cleanup(); + test_create_world(); + r = findregion(-1, 0); + CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ + f = test_create_faction(rc_find("human")); + u = test_create_unit(f, r); + sh = new_ship(st_find("boat"), NULL, r); + u->ship = sh; + i_change(&u->items, it_find("money"), 42); + + scale_number(u, 1); + sh->flags |= SF_FISHING; + get_food(r); + CuAssertIntEquals(tc, 42, i_get(u->items, it_find("money"))); + + scale_number(u, 1); + get_food(r); + CuAssertIntEquals(tc, 32, i_get(u->items, it_find("money"))); + +} + +static void test_unit_limit(CuTest * tc) { + set_param(&global.parameters, "rules.limit.faction", "250"); + CuAssertIntEquals(tc, 250, rule_faction_limit()); + + set_param(&global.parameters, "rules.limit.faction", "200"); + CuAssertIntEquals(tc, 200, rule_faction_limit()); + + set_param(&global.parameters, "rules.limit.alliance", "250"); + CuAssertIntEquals(tc, 250, rule_alliance_limit()); + +} + +extern int checkunitnumber(const faction *f, int add); +static void test_cannot_create_unit_above_limit(CuTest * tc) { + faction * f; + + test_cleanup(); + test_create_world(); + f = test_create_faction(rc_find("human")); + set_param(&global.parameters, "rules.limit.faction", "4"); + + CuAssertIntEquals(tc, 0, checkunitnumber(f, 4)); + CuAssertIntEquals(tc, 2, checkunitnumber(f, 5)); + + set_param(&global.parameters, "rules.limit.alliance", "3"); + CuAssertIntEquals(tc, 0, checkunitnumber(f, 3)); + CuAssertIntEquals(tc, 1, checkunitnumber(f, 4)); +} + + +CuSuite* get_laws_suite(void) +{ + CuSuite* suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, &test_new_building_can_be_renamed); + SUITE_ADD_TEST(suite, &test_fishing_feeds_2_people); + SUITE_ADD_TEST(suite, &test_fishing_does_not_give_goblins_money); + SUITE_ADD_TEST(suite, &test_fishing_gets_reset); + SUITE_ADD_TEST(suite, &test_unit_limit); + SUITE_ADD_TEST(suite, &test_cannot_create_unit_above_limit); + return suite; +} diff --git a/src/gamecode/market.c b/src/gamecode/market.c index 34d13172e..037936a29 100644 --- a/src/gamecode/market.c +++ b/src/gamecode/market.c @@ -1,184 +1,184 @@ -/* vi: set ts=2: -+-------------------+ Christian Schlittchen -| | Enno Rehling -| Eressea PBEM host | Katja Zedel -| (c) 1998 - 2003 | Henning Peters -| | Ingo Wilken -+-------------------+ Stefan Reich - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. - -*/ -#include -#include -#include "market.h" - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -static unsigned int -get_markets(region * r, unit ** results, size_t size) -{ - unsigned int n = 0; - building * b; - static building_type * btype; - if (!btype) btype = bt_find("market"); - if (!btype) return 0; - for (b=r->buildings;nnext) { - if (b->type==btype && (b->flags&BLD_WORKING) && b->size>=b->type->maxsize) { - unit * u = building_owner(b); - unsigned int i; - for (i=0;u && i!=n;++i) { - /* only one market per faction */ - if (results[i]->faction==u->faction) u = NULL; - } - if (u) { - results[n++] = u; - } - } - } - return n; -} - - -static void -free_market(attrib * a) -{ - item * items = (item *)a->data.v; - i_freeall(&items); - a->data.v = 0; -} - -attrib_type at_market = { - "script", - NULL, free_market, NULL, - NULL, NULL, ATF_UNIQUE -}; - -static int rc_luxury_trade(const struct race * rc) -{ - if (rc) { - return get_param_int(rc->parameters, "luxury_trade", 1000); - } - return 1000; -} - -static int rc_herb_trade(const struct race * rc) -{ - if (rc) { - return get_param_int(rc->parameters, "herb_trade", 500); - } - return 500; -} - -#define MAX_MARKETS 128 -#define MIN_PEASANTS 50 /* if there are at least this many peasants, you will get 1 good */ - -void do_markets(void) -{ - unit_list * traders = 0; - unit * markets[MAX_MARKETS]; - region * r; - for (r=regions;r;r=r->next) { - if (r->land) { - faction * f = region_get_owner(r); - const struct race * rc = f?f->race:NULL; - int p = rpeasants(r); - int numlux = rc_luxury_trade(rc), numherbs = rc_herb_trade(rc); - numlux = (p+numlux-MIN_PEASANTS)/numlux; - numherbs = (p+numherbs-MIN_PEASANTS)/numherbs; - if (numlux>0 || numherbs>0) { - int d, nmarkets = 0; - const item_type * lux = r_luxury(r); - const item_type * herb = r->land->herbtype; - - nmarkets += get_markets(r, markets+nmarkets, MAX_MARKETS-nmarkets); - for (d=0;d!=MAXDIRECTIONS;++d) { - region * r2 = rconnect(r, d); - if (r2 && r2->buildings) { - nmarkets += get_markets(r2, markets+nmarkets, MAX_MARKETS-nmarkets); - } - } - if (nmarkets) { - while (lux && numlux--) { - int n = rng_int() % nmarkets; - unit * u = markets[n]; - item * items; - attrib * a = a_find(u->attribs, &at_market); - if (a==NULL) { - unit_list * ulist = malloc(sizeof(unit_list)); - a = a_add(&u->attribs, a_new(&at_market)); - ulist->next = traders; - ulist->data = u; - traders = ulist; - } - items = (item *)a->data.v; - i_change(&items, lux, 1); - a->data.v = items; - /* give 1 luxury */ - } - while (herb && numherbs--) { - int n = rng_int() % nmarkets; - unit * u = markets[n]; - item * items; - attrib * a = a_find(u->attribs, &at_market); - if (a==NULL) { - unit_list * ulist = malloc(sizeof(unit_list)); - a = a_add(&u->attribs, a_new(&at_market)); - ulist->next = traders; - ulist->data = u; - traders = ulist; - } - items = (item *)a->data.v; - i_change(&items, herb, 1); - a->data.v = items; - /* give 1 herb */ - } - } - } - } - } - - while (traders) { - unit_list * trade = traders; - unit * u = trade->data; - attrib * a = a_find(u->attribs, &at_market); - item * items = a->data.v; - - a->data.v = NULL; - while (items) { - item * itm = items; - items = itm->next; - - if (itm->number) { - ADDMSG(&u->faction->msgs, msg_message("buyamount", - "unit amount resource", u, itm->number, itm->type->rtype)); - itm->next = NULL; - i_add(&u->items, itm); - } else { - i_free(itm); - } - } - - traders = trade->next; - - a_remove(&u->attribs, a); - free(trade); - } -} -#ifndef DISABLE_TESTS -#include "market_test.c" -#endif +/* vi: set ts=2: ++-------------------+ Christian Schlittchen +| | Enno Rehling +| Eressea PBEM host | Katja Zedel +| (c) 1998 - 2003 | Henning Peters +| | Ingo Wilken ++-------------------+ Stefan Reich + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. + +*/ +#include +#include +#include "market.h" + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +static unsigned int +get_markets(region * r, unit ** results, size_t size) +{ + unsigned int n = 0; + building * b; + static building_type * btype; + if (!btype) btype = bt_find("market"); + if (!btype) return 0; + for (b=r->buildings;nnext) { + if (b->type==btype && (b->flags&BLD_WORKING) && b->size>=b->type->maxsize) { + unit * u = building_owner(b); + unsigned int i; + for (i=0;u && i!=n;++i) { + /* only one market per faction */ + if (results[i]->faction==u->faction) u = NULL; + } + if (u) { + results[n++] = u; + } + } + } + return n; +} + + +static void +free_market(attrib * a) +{ + item * items = (item *)a->data.v; + i_freeall(&items); + a->data.v = 0; +} + +attrib_type at_market = { + "script", + NULL, free_market, NULL, + NULL, NULL, ATF_UNIQUE +}; + +static int rc_luxury_trade(const struct race * rc) +{ + if (rc) { + return get_param_int(rc->parameters, "luxury_trade", 1000); + } + return 1000; +} + +static int rc_herb_trade(const struct race * rc) +{ + if (rc) { + return get_param_int(rc->parameters, "herb_trade", 500); + } + return 500; +} + +#define MAX_MARKETS 128 +#define MIN_PEASANTS 50 /* if there are at least this many peasants, you will get 1 good */ + +void do_markets(void) +{ + unit_list * traders = 0; + unit * markets[MAX_MARKETS]; + region * r; + for (r=regions;r;r=r->next) { + if (r->land) { + faction * f = region_get_owner(r); + const struct race * rc = f?f->race:NULL; + int p = rpeasants(r); + int numlux = rc_luxury_trade(rc), numherbs = rc_herb_trade(rc); + numlux = (p+numlux-MIN_PEASANTS)/numlux; + numherbs = (p+numherbs-MIN_PEASANTS)/numherbs; + if (numlux>0 || numherbs>0) { + int d, nmarkets = 0; + const item_type * lux = r_luxury(r); + const item_type * herb = r->land->herbtype; + + nmarkets += get_markets(r, markets+nmarkets, MAX_MARKETS-nmarkets); + for (d=0;d!=MAXDIRECTIONS;++d) { + region * r2 = rconnect(r, d); + if (r2 && r2->buildings) { + nmarkets += get_markets(r2, markets+nmarkets, MAX_MARKETS-nmarkets); + } + } + if (nmarkets) { + while (lux && numlux--) { + int n = rng_int() % nmarkets; + unit * u = markets[n]; + item * items; + attrib * a = a_find(u->attribs, &at_market); + if (a==NULL) { + unit_list * ulist = malloc(sizeof(unit_list)); + a = a_add(&u->attribs, a_new(&at_market)); + ulist->next = traders; + ulist->data = u; + traders = ulist; + } + items = (item *)a->data.v; + i_change(&items, lux, 1); + a->data.v = items; + /* give 1 luxury */ + } + while (herb && numherbs--) { + int n = rng_int() % nmarkets; + unit * u = markets[n]; + item * items; + attrib * a = a_find(u->attribs, &at_market); + if (a==NULL) { + unit_list * ulist = malloc(sizeof(unit_list)); + a = a_add(&u->attribs, a_new(&at_market)); + ulist->next = traders; + ulist->data = u; + traders = ulist; + } + items = (item *)a->data.v; + i_change(&items, herb, 1); + a->data.v = items; + /* give 1 herb */ + } + } + } + } + } + + while (traders) { + unit_list * trade = traders; + unit * u = trade->data; + attrib * a = a_find(u->attribs, &at_market); + item * items = a->data.v; + + a->data.v = NULL; + while (items) { + item * itm = items; + items = itm->next; + + if (itm->number) { + ADDMSG(&u->faction->msgs, msg_message("buyamount", + "unit amount resource", u, itm->number, itm->type->rtype)); + itm->next = NULL; + i_add(&u->items, itm); + } else { + i_free(itm); + } + } + + traders = trade->next; + + a_remove(&u->attribs, a); + free(trade); + } +} +#ifndef DISABLE_TESTS +#include "market_test.c" +#endif diff --git a/src/gamecode/market.h b/src/gamecode/market.h index e45fbb7a1..b66f27350 100644 --- a/src/gamecode/market.h +++ b/src/gamecode/market.h @@ -1,25 +1,25 @@ -/* vi: set ts=2: -+-------------------+ Christian Schlittchen -| | Enno Rehling -| Eressea PBEM host | Katja Zedel -| (c) 1998 - 2003 | Henning Peters -| | Ingo Wilken -+-------------------+ Stefan Reich - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. - -*/ -#ifndef H_GC_MARKET -#define H_GC_MARKET -#ifdef __cplusplus -extern "C" { -#endif - struct building; - - extern void do_markets(void); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: ++-------------------+ Christian Schlittchen +| | Enno Rehling +| Eressea PBEM host | Katja Zedel +| (c) 1998 - 2003 | Henning Peters +| | Ingo Wilken ++-------------------+ Stefan Reich + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. + +*/ +#ifndef H_GC_MARKET +#define H_GC_MARKET +#ifdef __cplusplus +extern "C" { +#endif + struct building; + + extern void do_markets(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/market_test.c b/src/gamecode/market_test.c index 6b993dc83..44dc677d3 100644 --- a/src/gamecode/market_test.c +++ b/src/gamecode/market_test.c @@ -1,66 +1,66 @@ -#include - -#include -#include - -static void market_curse(CuTest * tc) { - region * r; - building * b; - unit * u; - faction * f; - int x, y; - const char * names[4] = { "herb", "herbs", "balm", "balms" }; - terrain_type * terrain; - resource_type * hres = new_resourcetype(names, 0, RTF_ITEM|RTF_POOLED); - item_type * htype = new_itemtype(hres, ITF_HERB, 0, 0); - resource_type * lres = new_resourcetype(names+2, 0, RTF_ITEM|RTF_POOLED); - item_type * ltype = new_itemtype(lres, ITF_NONE, 0, 0); - luxury_type * lux = new_luxurytype(ltype, 0); - building_type * btype; - race * rc = rc_add(rc_new("human")); - struct locale * lang = make_locale("en"); - - free_gamedata(); - - set_param(&global.parameters, "rules.region_owners", "1"); - - btype = calloc(sizeof(building_type), 1); - btype->_name = "market"; - bt_register(btype); - - terrain = calloc(1, sizeof(terrain_type)); - terrain->_name = strdup("plain"); - register_terrain(terrain); - terrain->flags = LAND_REGION|WALK_INTO; - - for (x=0;x!=3;++x) { - for (y=0;y!=3;++y) { - r = new_region(x, y, NULL, 0); - terraform_region(r, terrain); - rsetpeasants(r, 5000); - r_setdemand(r, lux, 0); - rsetherbtype(r, htype); - } - } - r = findregion(1, 1); - b = new_building(btype, r, lang); - b->flags |= BLD_WORKING; - b->size = b->type->maxsize; - - f = addfaction("nobody@eressea.de", NULL, rc, default_locale, 0); - u = create_unit(r, f, 1, f->race, 0, 0, 0); - u->building = b; - u->flags |= UFL_OWNER; - - do_markets(); - - CuAssertIntEquals(tc, 70, i_get(u->items, htype)); - CuAssertIntEquals(tc, 35, i_get(u->items, ltype)); -} - -CuSuite* get_market_suite(void) -{ - CuSuite* suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, market_curse); - return suite; -} +#include + +#include +#include + +static void market_curse(CuTest * tc) { + region * r; + building * b; + unit * u; + faction * f; + int x, y; + const char * names[4] = { "herb", "herbs", "balm", "balms" }; + terrain_type * terrain; + resource_type * hres = new_resourcetype(names, 0, RTF_ITEM|RTF_POOLED); + item_type * htype = new_itemtype(hres, ITF_HERB, 0, 0); + resource_type * lres = new_resourcetype(names+2, 0, RTF_ITEM|RTF_POOLED); + item_type * ltype = new_itemtype(lres, ITF_NONE, 0, 0); + luxury_type * lux = new_luxurytype(ltype, 0); + building_type * btype; + race * rc = rc_add(rc_new("human")); + struct locale * lang = make_locale("en"); + + free_gamedata(); + + set_param(&global.parameters, "rules.region_owners", "1"); + + btype = calloc(sizeof(building_type), 1); + btype->_name = "market"; + bt_register(btype); + + terrain = calloc(1, sizeof(terrain_type)); + terrain->_name = strdup("plain"); + register_terrain(terrain); + terrain->flags = LAND_REGION|WALK_INTO; + + for (x=0;x!=3;++x) { + for (y=0;y!=3;++y) { + r = new_region(x, y, NULL, 0); + terraform_region(r, terrain); + rsetpeasants(r, 5000); + r_setdemand(r, lux, 0); + rsetherbtype(r, htype); + } + } + r = findregion(1, 1); + b = new_building(btype, r, lang); + b->flags |= BLD_WORKING; + b->size = b->type->maxsize; + + f = addfaction("nobody@eressea.de", NULL, rc, default_locale, 0); + u = create_unit(r, f, 1, f->race, 0, 0, 0); + u->building = b; + u->flags |= UFL_OWNER; + + do_markets(); + + CuAssertIntEquals(tc, 70, i_get(u->items, htype)); + CuAssertIntEquals(tc, 35, i_get(u->items, ltype)); +} + +CuSuite* get_market_suite(void) +{ + CuSuite* suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, market_curse); + return suite; +} diff --git a/src/gamecode/monster.c b/src/gamecode/monster.c index 50436a947..2a0e0d5da 100644 --- a/src/gamecode/monster.c +++ b/src/gamecode/monster.c @@ -1,227 +1,227 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "monster.h" - -/* gamecode includes */ -#include "economy.h" -#include "give.h" - -/* triggers includes */ -#include - -/* attributes includes */ -#include -#include - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -#define MOVECHANCE 25 /* chance fuer bewegung */ - -#define MAXILLUSION_TEXTS 3 - -boolean -monster_is_waiting(const unit * u) -{ - if (fval(u, UFL_ISNEW|UFL_MOVED)) return true; - return false; -} - -static void -eaten_by_monster(unit * u) -{ - /* adjustment for smaller worlds */ - static double multi = 0.0; - int n = 0; - int horse = 0; - - if (multi==0.0) { - multi = RESOURCE_QUANTITY * newterrain(T_PLAIN)->size / 10000.0; - } - - switch (old_race(u->race)) { - case RC_FIREDRAGON: - n = rng_int()%80 * u->number; - horse = get_item(u, I_HORSE); - break; - case RC_DRAGON: - n = rng_int()%200 * u->number; - horse = get_item(u, I_HORSE); - break; - case RC_WYRM: - n = rng_int()%500 * u->number; - horse = get_item(u, I_HORSE); - break; - default: - n = rng_int()%(u->number/20+1); - } - - n = (int)(n * multi); - if (n > 0) { - n = lovar(n); - n = MIN(rpeasants(u->region), n); - - if (n > 0) { - deathcounts(u->region, n); - rsetpeasants(u->region, rpeasants(u->region) - n); - ADDMSG(&u->region->msgs, msg_message("eatpeasants", "unit amount", u, n)); - } - } - if (horse > 0) { - set_item(u, I_HORSE, 0); - ADDMSG(&u->region->msgs, msg_message("eathorse", "unit amount", u, horse)); - } -} - -static void -absorbed_by_monster(unit * u) -{ - int n; - - switch (old_race(u->race)) { - default: - n = rng_int()%(u->number/20+1); - } - - if(n > 0) { - n = lovar(n); - n = MIN(rpeasants(u->region), n); - if (n > 0){ - rsetpeasants(u->region, rpeasants(u->region) - n); - scale_number(u, u->number + n); - ADDMSG(&u->region->msgs, msg_message("absorbpeasants", - "unit race amount", u, u->race, n)); - } - } -} - -static int -scareaway(region * r, int anzahl) -{ - int n, p, diff = 0, emigrants[MAXDIRECTIONS]; - direction_t d; - - anzahl = MIN(MAX(1, anzahl),rpeasants(r)); - - /* Wandern am Ende der Woche (normal) oder wegen Monster. Die - * Wanderung wird erst am Ende von demographics () ausgefuehrt. - * emigrants[] ist local, weil r->newpeasants durch die Monster - * vielleicht schon hochgezaehlt worden ist. */ - - for (d = 0; d != MAXDIRECTIONS; d++) - emigrants[d] = 0; - - p = rpeasants(r); - assert(p >= 0 && anzahl >= 0); - for (n = MIN(p, anzahl); n; n--) { - direction_t dir = (direction_t)(rng_int() % MAXDIRECTIONS); - region * rc = rconnect(r, dir); - - if (rc && fval(rc->terrain, LAND_REGION)) { - ++diff; - rc->land->newpeasants++; - emigrants[dir]++; - } - } - rsetpeasants(r, p-diff); - assert(p >= diff); - return diff; -} - -static void -scared_by_monster(unit * u) -{ - int n; - - switch (old_race(u->race)) { - case RC_FIREDRAGON: - n = rng_int()%160 * u->number; - break; - case RC_DRAGON: - n = rng_int()%400 * u->number; - break; - case RC_WYRM: - n = rng_int()%1000 * u->number; - break; - default: - n = rng_int()%(u->number/4+1); - } - - if(n > 0) { - n = lovar(n); - n = MIN(rpeasants(u->region), n); - if(n > 0) { - n = scareaway(u->region, n); - if(n > 0) { - ADDMSG(&u->region->msgs, msg_message("fleescared", - "amount unit", n, u)); - } - } - } -} - -void -monster_kills_peasants(unit * u) -{ - if (!monster_is_waiting(u)) { - if (u->race->flags & RCF_SCAREPEASANTS) { - scared_by_monster(u); - } - if (u->race->flags & RCF_KILLPEASANTS) { - eaten_by_monster(u); - } - if (u->race->flags & RCF_ABSORBPEASANTS) { - absorbed_by_monster(u); - } - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "monster.h" + +/* gamecode includes */ +#include "economy.h" +#include "give.h" + +/* triggers includes */ +#include + +/* attributes includes */ +#include +#include + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +#define MOVECHANCE 25 /* chance fuer bewegung */ + +#define MAXILLUSION_TEXTS 3 + +boolean +monster_is_waiting(const unit * u) +{ + if (fval(u, UFL_ISNEW|UFL_MOVED)) return true; + return false; +} + +static void +eaten_by_monster(unit * u) +{ + /* adjustment for smaller worlds */ + static double multi = 0.0; + int n = 0; + int horse = 0; + + if (multi==0.0) { + multi = RESOURCE_QUANTITY * newterrain(T_PLAIN)->size / 10000.0; + } + + switch (old_race(u->race)) { + case RC_FIREDRAGON: + n = rng_int()%80 * u->number; + horse = get_item(u, I_HORSE); + break; + case RC_DRAGON: + n = rng_int()%200 * u->number; + horse = get_item(u, I_HORSE); + break; + case RC_WYRM: + n = rng_int()%500 * u->number; + horse = get_item(u, I_HORSE); + break; + default: + n = rng_int()%(u->number/20+1); + } + + n = (int)(n * multi); + if (n > 0) { + n = lovar(n); + n = MIN(rpeasants(u->region), n); + + if (n > 0) { + deathcounts(u->region, n); + rsetpeasants(u->region, rpeasants(u->region) - n); + ADDMSG(&u->region->msgs, msg_message("eatpeasants", "unit amount", u, n)); + } + } + if (horse > 0) { + set_item(u, I_HORSE, 0); + ADDMSG(&u->region->msgs, msg_message("eathorse", "unit amount", u, horse)); + } +} + +static void +absorbed_by_monster(unit * u) +{ + int n; + + switch (old_race(u->race)) { + default: + n = rng_int()%(u->number/20+1); + } + + if(n > 0) { + n = lovar(n); + n = MIN(rpeasants(u->region), n); + if (n > 0){ + rsetpeasants(u->region, rpeasants(u->region) - n); + scale_number(u, u->number + n); + ADDMSG(&u->region->msgs, msg_message("absorbpeasants", + "unit race amount", u, u->race, n)); + } + } +} + +static int +scareaway(region * r, int anzahl) +{ + int n, p, diff = 0, emigrants[MAXDIRECTIONS]; + direction_t d; + + anzahl = MIN(MAX(1, anzahl),rpeasants(r)); + + /* Wandern am Ende der Woche (normal) oder wegen Monster. Die + * Wanderung wird erst am Ende von demographics () ausgefuehrt. + * emigrants[] ist local, weil r->newpeasants durch die Monster + * vielleicht schon hochgezaehlt worden ist. */ + + for (d = 0; d != MAXDIRECTIONS; d++) + emigrants[d] = 0; + + p = rpeasants(r); + assert(p >= 0 && anzahl >= 0); + for (n = MIN(p, anzahl); n; n--) { + direction_t dir = (direction_t)(rng_int() % MAXDIRECTIONS); + region * rc = rconnect(r, dir); + + if (rc && fval(rc->terrain, LAND_REGION)) { + ++diff; + rc->land->newpeasants++; + emigrants[dir]++; + } + } + rsetpeasants(r, p-diff); + assert(p >= diff); + return diff; +} + +static void +scared_by_monster(unit * u) +{ + int n; + + switch (old_race(u->race)) { + case RC_FIREDRAGON: + n = rng_int()%160 * u->number; + break; + case RC_DRAGON: + n = rng_int()%400 * u->number; + break; + case RC_WYRM: + n = rng_int()%1000 * u->number; + break; + default: + n = rng_int()%(u->number/4+1); + } + + if(n > 0) { + n = lovar(n); + n = MIN(rpeasants(u->region), n); + if(n > 0) { + n = scareaway(u->region, n); + if(n > 0) { + ADDMSG(&u->region->msgs, msg_message("fleescared", + "amount unit", n, u)); + } + } + } +} + +void +monster_kills_peasants(unit * u) +{ + if (!monster_is_waiting(u)) { + if (u->race->flags & RCF_SCAREPEASANTS) { + scared_by_monster(u); + } + if (u->race->flags & RCF_KILLPEASANTS) { + eaten_by_monster(u); + } + if (u->race->flags & RCF_ABSORBPEASANTS) { + absorbed_by_monster(u); + } + } +} diff --git a/src/gamecode/monster.h b/src/gamecode/monster.h index 54e5fec10..5431d580a 100644 --- a/src/gamecode/monster.h +++ b/src/gamecode/monster.h @@ -1,31 +1,31 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_GC_MONSTER -#define H_GC_MONSTER -#ifdef __cplusplus -extern "C" { -#endif - -void monster_kills_peasants(struct unit * u); -boolean monster_is_waiting(const struct unit * u); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_GC_MONSTER +#define H_GC_MONSTER +#ifdef __cplusplus +extern "C" { +#endif + +void monster_kills_peasants(struct unit * u); +boolean monster_is_waiting(const struct unit * u); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/randenc.c b/src/gamecode/randenc.c index a80eddea0..1cd766a66 100644 --- a/src/gamecode/randenc.c +++ b/src/gamecode/randenc.c @@ -1,1272 +1,1272 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "randenc.h" - -#include "economy.h" -#include "monster.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* attributes includes */ -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include - -#include -extern struct attrib_type at_unitdissolve; -extern struct attrib_type at_orcification; - -/* In a->data.ca[1] steht der Prozentsatz mit dem sich die Einheit - * auflöst, in a->data.ca[0] kann angegeben werden, wohin die Personen - * verschwinden. Passiert bereits in der ersten Runde! */ -static void -dissolve_units(void) -{ - region *r; - unit *u; - int n; - int i; - - for (r=regions;r;r=r->next) { - for (u=r->units;u;u=u->next) { - attrib * a = a_find(u->attribs, &at_unitdissolve); - if (a) { - message * msg; - - if (u->age == 0 && a->data.ca[1] < 100) continue; - - /* TODO: Durch einzelne Berechnung ersetzen */ - if (a->data.ca[1] == 100) { - n = u->number; - } else { - n = 0; - for (i=0;inumber;i++) { - if (rng_int()%100 < a->data.ca[1]) n++; - } - } - - /* wenn keiner verschwindet, auch keine Meldung */ - if (n == 0) { - continue; - } - - scale_number(u, u->number - n); - - switch(a->data.ca[0]) { - case 1: - rsetpeasants(r, rpeasants(r) + n); - msg = msg_message("dissolve_units_1", "unit region number race", u, r, n, u->race); - break; - case 2: - if (r->land && !fval(r, RF_MALLORN)) { - rsettrees(r, 2, rtrees(r,2) + n); - msg = msg_message("dissolve_units_2", "unit region number race", u, r, n, u->race); - } else { - msg = msg_message("dissolve_units_3", "unit region number race", u, r, n, u->race); - } - break; - default: - if (u->race == new_race[RC_STONEGOLEM] || u->race == new_race[RC_IRONGOLEM]) { - msg = msg_message("dissolve_units_4", "unit region number race", u, r, n, u->race); - } else { - msg = msg_message("dissolve_units_5", "unit region number race", u, r, n, u->race); - } - break; - } - - add_message(&u->faction->msgs, msg); - msg_release(msg); - } - } - } - - remove_empty_units(); -} - -static int -improve_all(faction * f, skill_t sk, int by_weeks) -{ - unit *u; - boolean ret = by_weeks; - - for (u = f->units; u; u = u->nextF) { - if (has_skill(u, sk)) { - int weeks = 0; - for (;weeks!=by_weeks;++weeks) { - learn_skill(u, sk, 1.0); - ret = 0; - } - } - } - - return ret; -} - -void -find_manual(region * r, unit * u) -{ - char zLocation[32]; - char zBook[32]; - skill_t skill = NOSKILL; - message * msg; - - switch (rng_int() % 36) { - case 0: - skill = SK_MAGIC; - break; - case 1: - case 2: - case 3: - case 4: - skill = SK_WEAPONSMITH; - break; - case 5: - case 6: - skill = SK_TACTICS; - break; - case 7: - case 8: - case 9: - case 10: - skill = SK_SHIPBUILDING; - break; - case 11: - case 12: - case 13: - case 14: - skill = SK_SAILING; - break; - case 15: - case 16: - case 17: - skill = SK_HERBALISM; - break; - case 18: - case 19: - skill = SK_ALCHEMY; - break; - case 20: - case 21: - case 22: - case 23: - skill = SK_BUILDING; - break; - case 24: - case 25: - case 26: - case 27: - skill = SK_ARMORER; - break; - case 28: - case 29: - case 30: - case 31: - skill = SK_MINING; - break; - case 32: - case 33: - case 34: - case 35: - skill = SK_ENTERTAINMENT; - break; - } - - snprintf(zLocation, sizeof(zLocation), "manual_location_%d", (int)(rng_int() % 4)); - snprintf(zBook, sizeof(zLocation), "manual_title_%s", skillnames[skill]); - - msg = msg_message("find_manual", "unit location book", u, zLocation, zBook); - r_addmessage(r, u->faction, msg); - msg_release(msg); - - if (improve_all(u->faction, skill, 3) == 3) { - int i; - for (i=0;i!=9;++i) learn_skill(u, skill, 1.0); - } -} - -static void -get_villagers(region * r, unit * u) -{ - unit *newunit; - message * msg = msg_message("encounter_villagers", "unit", u); - const char * name = LOC(u->faction->locale, "villagers"); - - r_addmessage(r, u->faction, msg); - msg_release(msg); - - newunit = create_unit(r, u->faction, rng_int() % 20 + 3, u->faction->race, 0, name, u); - leave(newunit, true); - fset(newunit, UFL_ISNEW|UFL_MOVED); - equip_unit(newunit, get_equipment("random_villagers")); -} - -static void -get_allies(region * r, unit * u) -{ - unit *newunit = NULL; - const char * name; - const char * equip; - int number; - message * msg; - - assert(u->number); - - switch (rterrain(r)) { - case T_PLAIN: - if (!r_isforest(r)) { - if (get_money(u) / u->number < 100 + rng_int() % 200) - return; - name = "random_plain_men"; - equip = "random_plain"; - number = rng_int() % 8 + 2; - break; - } else { - if (eff_skill(u, SK_LONGBOW, r) < 3 - && eff_skill(u, SK_HERBALISM, r) < 2 - && eff_skill(u, SK_MAGIC, r) < 2) { - return; - } - name = "random_forest_men"; - equip = "random_forest"; - number = rng_int() % 6 + 2; - } - break; - - case T_SWAMP: - if (eff_skill(u, SK_MELEE, r) <= 1) { - return; - } - name = "random_swamp_men"; - equip = "random_swamp"; - number = rng_int() % 6 + 2; - break; - - case T_DESERT: - if (eff_skill(u, SK_RIDING, r) <= 2) { - return; - } - name = "random_desert_men"; - equip = "random_desert"; - number = rng_int() % 12 + 2; - break; - - case T_HIGHLAND: - if (eff_skill(u, SK_MELEE, r) <= 1) { - return; - } - name = "random_highland_men"; - equip = "random_highland"; - number = rng_int() % 8 + 2; - break; - - case T_MOUNTAIN: - if (eff_skill(u, SK_MELEE, r) <= 1 || eff_skill(u, SK_TRADE, r) <= 2) { - return; - } - name = "random_mountain_men"; - equip = "random_mountain"; - number = rng_int() % 6 + 2; - break; - - case T_GLACIER: - if (eff_skill(u, SK_MELEE, r) <= 1 || eff_skill(u, SK_TRADE, r) <= 1) { - return; - } - name = "random_glacier_men"; - equip = "random_glacier"; - number = rng_int() % 4 + 2; - break; - - default: - return; - } - - newunit = create_unit(r, u->faction, number, u->faction->race, 0, LOC(u->faction->locale, name), u); - equip_unit(newunit, get_equipment(equip)); - - u_setfaction(newunit, u->faction); - set_racename(&newunit->attribs, get_racename(u->attribs)); - if (u->race->flags & RCF_SHAPESHIFT) { - newunit->irace = u->irace; - } - if (fval(u, UFL_ANON_FACTION)) fset(newunit, UFL_ANON_FACTION); - fset(newunit, UFL_ISNEW); - - msg = msg_message("encounter_allies", "unit name", u, name); - r_addmessage(r, u->faction, msg); - msg_release(msg); -} - -static void -encounter(region * r, unit * u) -{ - if (!fval(r, RF_ENCOUNTER)) return; - freset(r, RF_ENCOUNTER); - if (rng_int() % 100>=ENCCHANCE) return; - switch (rng_int() % 3) { - case 0: - find_manual(r, u); - break; - case 1: - get_villagers(r, u); - break; - case 2: - get_allies(r, u); - break; - } -} - -void -encounters(void) -{ - region *r; - - for (r = regions; r; r = r->next) { - if (!fval(r->terrain, SEA_REGION) && fval(r, RF_ENCOUNTER)) { - int c = 0; - unit * u; - for (u = r->units; u; u = u->next) { - c += u->number; - } - - if (c > 0) { - int i = 0; - int n = rng_int() % c; - - for (u = r->units; u; u = u->next) { - if (i+u->number>n) break; - i+=u->number; - } - assert(u && u->number); - encounter(r, u); - } - } - } -} - -static const terrain_type * -chaosterrain(void) -{ - static const terrain_type ** types; - static int numtypes; - - if (numtypes==0) { - const terrain_type * terrain; - for (terrain=terrains();terrain!=NULL;terrain=terrain->next) { - if (fval(terrain, LAND_REGION) && terrain->herbs) { - ++numtypes; - } - } - types = malloc(sizeof(terrain_type)*numtypes); - numtypes = 0; - for (terrain=terrains();terrain!=NULL;terrain=terrain->next) { - if (fval(terrain, LAND_REGION) && terrain->herbs) { - types[numtypes++] = terrain; - } - } - } - return types[rng_int() % numtypes]; -} - - -static unit * -random_unit(const region * r) -{ - int c = 0; - int n; - unit *u; - - for (u = r->units; u; u = u->next) { - if (u->race != new_race[RC_SPELL]) { - c += u->number; - } - } - - if (c == 0) { - return NULL; - } - n = rng_int() % c; - c = 0; - u = r->units; - - while (u && c < n) { - if (u->race != new_race[RC_SPELL]) { - c += u->number; - } - u = u->next; - } - - return u; -} - -void -chaos(region * r) -{ - if (rng_int() % 100 < 8) { - switch (rng_int() % 3) { - case 0: /* Untote */ - if (!fval(r->terrain, SEA_REGION)) { - unit * u = random_unit(r); - if (u && playerrace(u->race)) { - ADDMSG(&u->faction->msgs, msg_message("chaos_disease", "unit", u)); - u_setfaction(u, get_monsters()); - u->race = new_race[RC_GHOUL]; - } - } - break; - case 1: /* Drachen */ - if (random_unit(r)) { - int mfac = 0; - unit * u; - switch (rng_int() % 3) { - case 0: - mfac = 100; - u = createunit(r, get_monsters(), rng_int() % 8 + 1, new_race[RC_FIREDRAGON]); - break; - case 1: - mfac = 500; - u = createunit(r, get_monsters(), rng_int() % 4 + 1, new_race[RC_DRAGON]); - break; - default: - mfac = 1000; - u = createunit(r, get_monsters(), rng_int() % 2 + 1, new_race[RC_WYRM]); - break; - } - if (mfac) set_money(u, u->number * (rng_int() % mfac)); - fset(u, UFL_ISNEW|UFL_MOVED); - } - case 2: /* Terrainveränderung */ - if (!fval(r->terrain, FORBIDDEN_REGION)) { - if (!fval(r->terrain, SEA_REGION)) { - direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * rn = rconnect(r, dir); - if (rn && fval(rn->terrain, SEA_REGION)) break; - } - if (dir!=MAXDIRECTIONS) { - ship * sh = r->ships; - unit ** up; - - while (sh) { - ship * nsh = sh->next; - damage_ship(sh, 0.50); - if (sh->damage >= sh->size * DAMAGE_SCALE) { - remove_ship(&sh->region->ships, sh); - } - sh = nsh; - } - - for (up = &r->units; *up;) { - unit * u = *up; - if (u->race != new_race[RC_SPELL] && u->ship == 0 && !canfly(u)) { - ADDMSG(&u->faction->msgs, msg_message("tidalwave_kill", "region unit", r, u)); - remove_unit(up, u); - } - if (*up==u) up = &u->next; - } - ADDMSG(&r->msgs, msg_message("tidalwave", "region", r)); - - while (r->buildings) { - remove_building(&r->buildings, r->buildings); - } - terraform_region(r, newterrain(T_OCEAN)); - } - } else { - direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * rn = rconnect(r, dir); - if (rn && fval(rn->terrain, SEA_REGION)) break; - } - if (dir!=MAXDIRECTIONS) { - terraform_region(r, chaosterrain()); - } - } - } - } - } -} - - -static int -nb_armor(const unit *u, int index) -{ - const item * itm; - int av = 0; - int s = 0, a = 0; - - if (!(u->race->battle_flags & BF_EQUIPMENT)) return 0; - - /* Normale Rüstung */ - - for (itm=u->items;itm;itm=itm->next) { - const armor_type * atype = itm->type->rtype->atype; - if (atype!=NULL) { - int * schutz = &a; - if (atype->flags & ATF_SHIELD) schutz = &s; - if (*schutz <= index) { - *schutz += itm->number; - if (*schutz > index) { - av += atype->prot; - } - } - } - } - return av; -} - -static int -damage_unit(unit *u, const char *dam, boolean physical, boolean magic) -{ - int *hp = malloc(u->number * sizeof(int)); - int h; - int i, dead = 0, hp_rem = 0, heiltrank; - double magres = magic_resistance(u); - - assert(u->number); - if (fval(u->race, RCF_ILLUSIONARY) || u->race == new_race[RC_SPELL]) { - return 0; - } - - h = u->hp/u->number; - /* HP verteilen */ - for (i=0; inumber; i++) hp[i] = h; - h = u->hp - (u->number * h); - for (i=0; inumber; i++) { - int damage = dice_rand(dam); - if (magic) damage = (int)(damage * (1.0 - magres)); - if (physical) damage -= nb_armor(u, i); - hp[i] -= damage; - } - - /* Auswirkungen */ - for (i=0; inumber; i++) { - if (hp[i] <= 0){ - heiltrank = 0; - - /* Sieben Leben */ - if (old_race(u->race) == RC_CAT && (chance(1.0 / 7))) { - hp[i] = u->hp/u->number; - hp_rem += hp[i]; - continue; - } - - /* Heiltrank */ - if (oldpotiontype[P_HEAL]) { - if (get_effect(u, oldpotiontype[P_HEAL]) > 0) { - change_effect(u, oldpotiontype[P_HEAL], -1); - heiltrank = 1; - } else if (i_get(u->items, oldpotiontype[P_HEAL]->itype) > 0) { - i_change(&u->items, oldpotiontype[P_HEAL]->itype, -1); - change_effect(u, oldpotiontype[P_HEAL], 3); - heiltrank = 1; - } - if (heiltrank && (chance(0.50))) { - hp[i] = u->hp/u->number; - hp_rem += hp[i]; - continue; - } - } - dead++; - } else { - hp_rem += hp[i]; - } - } - - scale_number(u, u->number - dead); - u->hp = hp_rem; - - free(hp); - - return dead; -} - -void -drown(region *r) -{ - if (fval(r->terrain, SEA_REGION)) { - unit ** up = up=&r->units; - while (*up) { - unit *u = *up; - int amphibian_level = 0; - if (u->ship || u->race == new_race[RC_SPELL] || u->number==0) { - up=&u->next; - continue; - } - - if (amphibian_level) { - int dead = damage_unit(u, "5d1", false, false); - if (dead) { - ADDMSG(&u->faction->msgs, msg_message("drown_amphibian_dead", - "amount unit region", dead, u, r)); - } else { - ADDMSG(&u->faction->msgs, msg_message("drown_amphibian_nodead", - "unit region",u, r)); - } - } else if (!(canswim(u) || canfly(u))) { - scale_number(u, 0); - ADDMSG(&u->faction->msgs, msg_message("drown", "unit region", u, r)); - } - if (*up==u) up=&u->next; - } - remove_empty_units_in_region(r); - } -} - -region * -rrandneighbour(region *r) -{ - direction_t i; - region *rc = NULL; - int rr, c = 0; - - /* Nachsehen, wieviele Regionen in Frage kommen */ - - for (i = 0; i != MAXDIRECTIONS; i++) { - c++; - } - /* Zufällig eine auswählen */ - - rr = rng_int() % c; - - /* Durchzählen */ - - c = -1; - for (i = 0; i != MAXDIRECTIONS; i++) { - rc = rconnect(r, i); - c++; - if (c == rr) break; - } - assert(i!=MAXDIRECTIONS); - return rc; -} - -static void -volcano_destruction(region * volcano, region * r, region * rn, const char * damage) -{ - attrib * a; - unit ** up; - int percent = 25, time = 6 + rng_int()%12; - - rsettrees(r, 2, 0); - rsettrees(r, 1, 0); - rsettrees(r, 0, 0); - - a = a_find(r->attribs, &at_reduceproduction); - if (!a) { - a = make_reduceproduction(percent, time); - } else { - /* Produktion vierteln ... */ - a->data.sa[0] = (short)percent; - /* Für 6-17 Runden */ - a->data.sa[1] = (short)(a->data.sa[1] + time); - } - - /* Personen bekommen 4W10 Punkte Schaden. */ - - for (up=&r->units; *up;) { - unit * u = *up; - if (u->number) { - int dead = damage_unit(u, damage, true, false); - if (dead) { - ADDMSG(&u->faction->msgs, msg_message("volcano_dead", - "unit region dead", u, volcano, dead)); - } - if (r==volcano && !fval(u->faction, FFL_SELECT)) { - fset(u->faction, FFL_SELECT); - if (rn) { - ADDMSG(&u->faction->msgs, msg_message("volcanooutbreak", - "regionv regionn", r, rn)); - } else { - ADDMSG(&u->faction->msgs, msg_message("volcanooutbreaknn", - "region", r)); - } - } - } - if (u==*up) up=&u->next; - } - - remove_empty_units_in_region(r); -} - -void -volcano_outbreak(region *r) -{ - region *rn; - unit *u; - faction *f; - - for (f=NULL,u=r->units; u; u=u->next) { - if (f!=u->faction) { - f = u->faction; - freset(f, FFL_SELECT); - } - } - - /* Zufällige Nachbarregion verwüsten */ - rn = rrandneighbour(r); - - volcano_destruction(r, r, rn, "4d10"); - if (rn) { - volcano_destruction(r, rn, NULL, "3d10"); - } -} - -static void -melt_iceberg(region *r) -{ - attrib *a; - unit *u; - - for (u=r->units; u; u=u->next) freset(u->faction, FFL_SELECT); - for (u=r->units; u; u=u->next) if (!fval(u->faction, FFL_SELECT)) { - fset(u->faction, FFL_SELECT); - ADDMSG(&u->faction->msgs, msg_message("iceberg_melt", "region", r)); - } - - /* driftrichtung löschen */ - a = a_find(r->attribs, &at_iceberg); - if (a) a_remove(&r->attribs, a); - - /* Gebäude löschen */ - while (r->buildings) { - remove_building(&r->buildings, r->buildings); - } - - /* in Ozean wandeln */ - terraform_region(r, newterrain(T_OCEAN)); - - /* Einheiten, die nicht schwimmen können oder in Schiffen sind, - * ertrinken */ - drown(r); -} - -static void -move_iceberg(region *r) -{ - attrib *a; - direction_t dir; - region *rc; - - a = a_find(r->attribs, &at_iceberg); - if (!a) { - dir = (direction_t)(rng_int()%MAXDIRECTIONS); - a = a_add(&r->attribs, make_iceberg(dir)); - } else { - if (rng_int()%100 < 20) { - dir = (direction_t)(rng_int()%MAXDIRECTIONS); - a->data.i = dir; - } else { - dir = (direction_t)a->data.i; - } - } - - rc = rconnect(r, dir); - - if (rc && !fval(rc->terrain, ARCTIC_REGION)) { - if (fval(rc->terrain, SEA_REGION)) { /* Eisberg treibt */ - ship *sh, *shn; - unit *u; - int x, y; - - - for (u=r->units; u; u=u->next) freset(u->faction, FFL_SELECT); - for (u=r->units; u; u=u->next) if (!fval(u->faction, FFL_SELECT)) { - fset(u->faction, FFL_SELECT); - ADDMSG(&u->faction->msgs, msg_message("iceberg_drift", - "region dir", r, dir)); - } - - x = r->x; - y = r->y; - - runhash(r); - runhash(rc); - r->x = rc->x; - r->y = rc->y; - rc->x = x; - rc->y = y; - rhash(rc); - rhash(r); - - /* rc ist der Ozean (Ex-Eisberg), r der Eisberg (Ex-Ozean) */ - - /* Schiffe aus dem Zielozean werden in den Eisberg transferiert - * und nehmen Schaden. */ - - for (sh = r->ships; sh; sh=sh->next) freset(sh, SF_SELECT); - - for (sh = r->ships; sh; sh = sh->next) { - /* Meldung an Kapitän */ - damage_ship(sh, 0.10); - fset(sh, SF_SELECT); - } - - /* Personen, Schiffe und Gebäude verschieben */ - while (rc->buildings) { - rc->buildings->region = r; - translist(&rc->buildings, &r->buildings, rc->buildings); - } - while (rc->ships) { - fset(rc->ships, SF_SELECT); - damage_ship(rc->ships, 0.10); - move_ship(rc->ships, rc, r, NULL); - } - while (rc->units) { - building * b = rc->units->building; - u = rc->units; - move_unit(rc->units, r, NULL); - u->building = b; /* move_unit macht ein leave() */ - } - - /* Beschädigte Schiffe können sinken */ - - for (sh = r->ships; sh;) { - shn = sh->next; - if (fval(sh, SF_SELECT)) { - u = captain(sh); - if (sh->damage>=sh->size * DAMAGE_SCALE) { - if (u!=NULL) { - ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg_des", - "ship", sh)); - } - remove_ship(&sh->region->ships, sh); - } else if (u!=NULL) { - ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg", - "ship", sh)); - } - } - sh = shn; - } - - } else if (rng_int()%100 < 20) { /* Eisberg bleibt als Gletscher liegen */ - unit *u; - - rsetterrain(r, T_GLACIER); - a_remove(&r->attribs, a); - - for (u=r->units; u; u=u->next) freset(u->faction, FFL_SELECT); - for (u=r->units; u; u=u->next) if (!fval(u->faction, FFL_SELECT)) { - fset(u->faction, FFL_SELECT); - ADDMSG(&u->faction->msgs, msg_message("iceberg_land", "region", r)); - } - } - } -} - -static void -move_icebergs(void) -{ - region *r; - - for (r=regions; r; r=r->next) { - if (r->terrain == newterrain(T_ICEBERG) && !fval(r, RF_SELECT)) { - int select = rng_int() % 10; - if (select < 4) { - /* 4% chance */ - fset(r, RF_SELECT); - melt_iceberg(r); - } else if (select<64) { - /* 60% chance */ - fset(r, RF_SELECT); - move_iceberg(r); - } - } - } -} - -void -create_icebergs(void) -{ - region *r; - - for (r=regions; r; r=r->next) { - if (r->terrain == newterrain(T_ICEBERG_SLEEP) && chance(0.05)) { - boolean has_ocean_neighbour = false; - direction_t dir; - region *rc; - unit *u; - - freset(r, RF_SELECT); - for (dir=0; dir < MAXDIRECTIONS; dir++) { - rc = rconnect(r, dir); - if (rc && fval(rc->terrain, SEA_REGION)) { - has_ocean_neighbour = true; - break; - } - } - if (!has_ocean_neighbour) continue; - - rsetterrain(r, T_ICEBERG); - - fset(r, RF_SELECT); - move_iceberg(r); - - for (u=r->units; u; u=u->next) { - freset(u->faction, FFL_SELECT); - } - for (u=r->units; u; u=u->next) { - if (!fval(u->faction, FFL_SELECT)) { - fset(u->faction, FFL_SELECT); - ADDMSG(&u->faction->msgs, msg_message("iceberg_create", "region", r)); - } - } - } - } -} - -static void -godcurse(void) -{ - region *r; - - for (r=regions; r; r=r->next) { - if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { - unit * u; - for(u=r->units; u; u=u->next) { - skill * sv = u->skills; - while (sv!=u->skills+u->skill_size) { - int weeks = 1+rng_int()%3; - reduce_skill(u, sv, weeks); - ++sv; - } - } - if (fval(r->terrain, SEA_REGION)) { - ship *sh; - for (sh = r->ships; sh;) { - ship *shn = sh->next; - damage_ship(sh, 0.10); - if (sh->damage>=sh->size * DAMAGE_SCALE) { - unit * u = shipowner(sh); - if (u) ADDMSG(&u->faction->msgs, - msg_message("godcurse_destroy_ship", "ship", sh)); - remove_ship(&sh->region->ships, sh); - } - sh = shn; - } - } - } - } - -} - -/** handles the "orcish" curse that makes units grow like old orks - * This would probably be better handled in an age-function for the curse, - * but it's now being called by randomevents() - */ -static void -orc_growth(void) -{ - region * r; - for (r = regions; r; r = r->next) { - unit *u; - for (u = r->units; u; u = u->next) { - static boolean init = false; - static const curse_type *ct_orcish = 0; - curse *c = 0; - if (!init) { - init = true; - ct_orcish = ct_find("orcish"); - } - if (ct_orcish) c = get_curse(u->attribs, ct_orcish); - - if (c && !has_skill(u, SK_MAGIC) && !has_skill(u, SK_ALCHEMY) && !fval(u, UFL_HERO)) { - int n; - int increase = 0; - int num = get_cursedmen(u, c); - double prob = curse_geteffect(c); - - for (n = (num - get_item(u, I_CHASTITY_BELT)); n > 0; n--) { - if (chance(prob)) { - ++increase; - } - } - if (increase) { - unit * u2 = create_unit(r, u->faction, increase, u->race, 0, NULL, u); - transfermen(u2, u, u2->number); - - ADDMSG(&u->faction->msgs, msg_message("orcgrowth", - "unit amount race", u, increase, u->race)); - } - } - } - } -} - -/** Talente von Dämonen verschieben sich. - */ -static void -demon_skillchanges(void) -{ - region * r; - - for (r = regions; r; r = r->next) { - unit * u; - for (u = r->units; u; u = u->next) { - if (u->race == new_race[RC_DAEMON]) { - skill * sv = u->skills; - int upchance = 15; - int downchance = 10; - - if (fval(u, UFL_HUNGER)) { - /* hungry demons only go down, never up in skill */ - static int rule_hunger = -1; - if (rule_hunger<0) { - rule_hunger = get_param_int(global.parameters, "hunger.demon.skill", 0); - } - if (rule_hunger) { - upchance = 0; - downchance = 15; - } - } - - while (sv!=u->skills+u->skill_size) { - int roll = rng_int() % 100; - if (sv->level>0 && roll < upchance+downchance) { - int weeks = 1+rng_int()%3; - if (roll < downchance) { - reduce_skill(u, sv, weeks); - if (sv->level<1) { - /* demons should never forget below 1 */ - set_level(u, sv->id, 1); - } - } else { - while (weeks--) learn_skill(u, sv->id, 1.0); - } - if (sv->old>sv->level) { - if (verbosity>=3) { - log_printf("%s dropped from %u to %u:%u in %s\n", - unitname(u), sv->old, sv->level, sv->weeks, skillname(sv->id, NULL)); - } - } - } - ++sv; - } - } - } - } -} - -/** Eisberge entstehen und bewegen sich. - * Einheiten die im Wasser landen, ertrinken. - */ -static void -icebergs(void) -{ - region * r; - create_icebergs(); - move_icebergs(); - for (r=regions; r; r=r->next) { - drown(r); - } -} - -#ifdef HERBS_ROT -static void -rotting_herbs(void) -{ - static int rule_rot = -1; - region * r; - - if (rule_rot<0) { - rule_rot = get_param_int(global.parameters, "rules.economy.herbrot", HERBROTCHANCE); - } - if (rule_rot==0) return; - - for (r = regions; r; r = r->next) { - unit * u; - for (u = r->units; u; u=u->next) { - item **itmp = &u->items, *hbag = *i_find(itmp, olditemtype[I_SACK_OF_CONSERVATION]); - int rot_chance = rule_rot; - - if (hbag) rot_chance = (rot_chance*2)/5; - while (*itmp) { - item * itm = *itmp; - int n = itm->number; - double k = n*rot_chance/100.0; - if (fval(itm->type, ITF_HERB)) { - double nv = normalvariate(k, k/4); - int inv = (int)nv; - int delta = MIN(n, inv); - if (i_change(itmp, itm->type, -delta)==NULL) { - continue; - } - } - itmp = &itm->next; - } - } - } -} -#endif - -void -randomevents(void) -{ - region *r; - - icebergs(); - godcurse(); - orc_growth(); - demon_skillchanges(); - - /* Orkifizierte Regionen mutieren und mutieren zurück */ - - for (r = regions; r; r = r->next) { - if (fval(r, RF_ORCIFIED)) { - direction_t dir; - double probability = 0.0; - for (dir = 0; dir < MAXDIRECTIONS; dir++) { - region *rc = rconnect(r, dir); - if (rc && rpeasants(rc) > 0 && !fval(rc, RF_ORCIFIED)) probability += 0.02; - } - if (chance(probability)) { - ADDMSG(&r->msgs, msg_message("deorcified", "region", r)); - freset(r, RF_ORCIFIED); - } - } else { - attrib *a = a_find(r->attribs, &at_orcification); - if (a!=NULL) { - double probability = 0.0; - if (rpeasants(r) <= 0) continue; - probability = a->data.i/(double)rpeasants(r); - if (chance(probability)) { - fset(r, RF_ORCIFIED); - a_remove(&r->attribs, a); - ADDMSG(&r->msgs, msg_message("orcified", "region", r)); - } else { - a->data.i -= MAX(10,a->data.i/10); - if (a->data.i <= 0) a_remove(&r->attribs, a); - } - } - } - } - - /* Vulkane qualmen, brechen aus ... */ - for (r = regions; r; r = r->next) { - if (r->terrain == newterrain(T_VOLCANO_SMOKING)) { - if (a_find(r->attribs, &at_reduceproduction)) { - ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r)); - rsetterrain(r, T_VOLCANO); - } else { - if (rng_int()%100 < 12) { - ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r)); - rsetterrain(r, T_VOLCANO); - } else if (r->age>20 && rng_int()%100 < 8) { - volcano_outbreak(r); - } - } - } else if (r->terrain == newterrain(T_VOLCANO)) { - if (rng_int()%100 < 4) { - ADDMSG(&r->msgs, msg_message("volcanostartsmoke", "region", r)); - rsetterrain(r, T_VOLCANO_SMOKING); - } - } - } - - /* Monumente zerfallen, Schiffe verfaulen */ - - for (r = regions; r; r = r->next) { - building ** blist = &r->buildings; - while (*blist) { - building * b = *blist; - if (fval(b->type, BTF_DECAY) && !building_owner(b)) { - b->size -= MAX(1, (b->size * 20) / 100); - if (b->size == 0) { - remove_building(blist, r->buildings); - } - } - if (*blist==b) blist=&b->next; - } - } - - /* monster-einheiten desertieren */ - for (r = regions; r; r=r->next) { - unit *u; - - for (u=r->units; u; u=u->next) { - if (u->faction && !is_monsters(u->faction) - && (u->race->flags & RCF_DESERT)) { - if (fval(u, UFL_ISNEW)) continue; - if (rng_int()%100 < 5) { - ADDMSG(&u->faction->msgs, msg_message("desertion", - "unit region", u, r)); - u_setfaction(u, get_monsters()); - } - } - } - } - - /* Chaos */ - for (r = regions; r; r = r->next) { - int i; - - if (fval(r, RF_CHAOTIC)) { - chaos(r); - } - i = chaoscount(r); - if (i) { - chaoscounts(r, -(int) (i * ((double) (rng_int() % 10)) / 100.0)); - } - } -#ifdef HERBS_ROT - rotting_herbs(); -#endif - - dissolve_units(); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "randenc.h" + +#include "economy.h" +#include "monster.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* attributes includes */ +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +#include +extern struct attrib_type at_unitdissolve; +extern struct attrib_type at_orcification; + +/* In a->data.ca[1] steht der Prozentsatz mit dem sich die Einheit + * auflöst, in a->data.ca[0] kann angegeben werden, wohin die Personen + * verschwinden. Passiert bereits in der ersten Runde! */ +static void +dissolve_units(void) +{ + region *r; + unit *u; + int n; + int i; + + for (r=regions;r;r=r->next) { + for (u=r->units;u;u=u->next) { + attrib * a = a_find(u->attribs, &at_unitdissolve); + if (a) { + message * msg; + + if (u->age == 0 && a->data.ca[1] < 100) continue; + + /* TODO: Durch einzelne Berechnung ersetzen */ + if (a->data.ca[1] == 100) { + n = u->number; + } else { + n = 0; + for (i=0;inumber;i++) { + if (rng_int()%100 < a->data.ca[1]) n++; + } + } + + /* wenn keiner verschwindet, auch keine Meldung */ + if (n == 0) { + continue; + } + + scale_number(u, u->number - n); + + switch(a->data.ca[0]) { + case 1: + rsetpeasants(r, rpeasants(r) + n); + msg = msg_message("dissolve_units_1", "unit region number race", u, r, n, u->race); + break; + case 2: + if (r->land && !fval(r, RF_MALLORN)) { + rsettrees(r, 2, rtrees(r,2) + n); + msg = msg_message("dissolve_units_2", "unit region number race", u, r, n, u->race); + } else { + msg = msg_message("dissolve_units_3", "unit region number race", u, r, n, u->race); + } + break; + default: + if (u->race == new_race[RC_STONEGOLEM] || u->race == new_race[RC_IRONGOLEM]) { + msg = msg_message("dissolve_units_4", "unit region number race", u, r, n, u->race); + } else { + msg = msg_message("dissolve_units_5", "unit region number race", u, r, n, u->race); + } + break; + } + + add_message(&u->faction->msgs, msg); + msg_release(msg); + } + } + } + + remove_empty_units(); +} + +static int +improve_all(faction * f, skill_t sk, int by_weeks) +{ + unit *u; + boolean ret = by_weeks; + + for (u = f->units; u; u = u->nextF) { + if (has_skill(u, sk)) { + int weeks = 0; + for (;weeks!=by_weeks;++weeks) { + learn_skill(u, sk, 1.0); + ret = 0; + } + } + } + + return ret; +} + +void +find_manual(region * r, unit * u) +{ + char zLocation[32]; + char zBook[32]; + skill_t skill = NOSKILL; + message * msg; + + switch (rng_int() % 36) { + case 0: + skill = SK_MAGIC; + break; + case 1: + case 2: + case 3: + case 4: + skill = SK_WEAPONSMITH; + break; + case 5: + case 6: + skill = SK_TACTICS; + break; + case 7: + case 8: + case 9: + case 10: + skill = SK_SHIPBUILDING; + break; + case 11: + case 12: + case 13: + case 14: + skill = SK_SAILING; + break; + case 15: + case 16: + case 17: + skill = SK_HERBALISM; + break; + case 18: + case 19: + skill = SK_ALCHEMY; + break; + case 20: + case 21: + case 22: + case 23: + skill = SK_BUILDING; + break; + case 24: + case 25: + case 26: + case 27: + skill = SK_ARMORER; + break; + case 28: + case 29: + case 30: + case 31: + skill = SK_MINING; + break; + case 32: + case 33: + case 34: + case 35: + skill = SK_ENTERTAINMENT; + break; + } + + snprintf(zLocation, sizeof(zLocation), "manual_location_%d", (int)(rng_int() % 4)); + snprintf(zBook, sizeof(zLocation), "manual_title_%s", skillnames[skill]); + + msg = msg_message("find_manual", "unit location book", u, zLocation, zBook); + r_addmessage(r, u->faction, msg); + msg_release(msg); + + if (improve_all(u->faction, skill, 3) == 3) { + int i; + for (i=0;i!=9;++i) learn_skill(u, skill, 1.0); + } +} + +static void +get_villagers(region * r, unit * u) +{ + unit *newunit; + message * msg = msg_message("encounter_villagers", "unit", u); + const char * name = LOC(u->faction->locale, "villagers"); + + r_addmessage(r, u->faction, msg); + msg_release(msg); + + newunit = create_unit(r, u->faction, rng_int() % 20 + 3, u->faction->race, 0, name, u); + leave(newunit, true); + fset(newunit, UFL_ISNEW|UFL_MOVED); + equip_unit(newunit, get_equipment("random_villagers")); +} + +static void +get_allies(region * r, unit * u) +{ + unit *newunit = NULL; + const char * name; + const char * equip; + int number; + message * msg; + + assert(u->number); + + switch (rterrain(r)) { + case T_PLAIN: + if (!r_isforest(r)) { + if (get_money(u) / u->number < 100 + rng_int() % 200) + return; + name = "random_plain_men"; + equip = "random_plain"; + number = rng_int() % 8 + 2; + break; + } else { + if (eff_skill(u, SK_LONGBOW, r) < 3 + && eff_skill(u, SK_HERBALISM, r) < 2 + && eff_skill(u, SK_MAGIC, r) < 2) { + return; + } + name = "random_forest_men"; + equip = "random_forest"; + number = rng_int() % 6 + 2; + } + break; + + case T_SWAMP: + if (eff_skill(u, SK_MELEE, r) <= 1) { + return; + } + name = "random_swamp_men"; + equip = "random_swamp"; + number = rng_int() % 6 + 2; + break; + + case T_DESERT: + if (eff_skill(u, SK_RIDING, r) <= 2) { + return; + } + name = "random_desert_men"; + equip = "random_desert"; + number = rng_int() % 12 + 2; + break; + + case T_HIGHLAND: + if (eff_skill(u, SK_MELEE, r) <= 1) { + return; + } + name = "random_highland_men"; + equip = "random_highland"; + number = rng_int() % 8 + 2; + break; + + case T_MOUNTAIN: + if (eff_skill(u, SK_MELEE, r) <= 1 || eff_skill(u, SK_TRADE, r) <= 2) { + return; + } + name = "random_mountain_men"; + equip = "random_mountain"; + number = rng_int() % 6 + 2; + break; + + case T_GLACIER: + if (eff_skill(u, SK_MELEE, r) <= 1 || eff_skill(u, SK_TRADE, r) <= 1) { + return; + } + name = "random_glacier_men"; + equip = "random_glacier"; + number = rng_int() % 4 + 2; + break; + + default: + return; + } + + newunit = create_unit(r, u->faction, number, u->faction->race, 0, LOC(u->faction->locale, name), u); + equip_unit(newunit, get_equipment(equip)); + + u_setfaction(newunit, u->faction); + set_racename(&newunit->attribs, get_racename(u->attribs)); + if (u->race->flags & RCF_SHAPESHIFT) { + newunit->irace = u->irace; + } + if (fval(u, UFL_ANON_FACTION)) fset(newunit, UFL_ANON_FACTION); + fset(newunit, UFL_ISNEW); + + msg = msg_message("encounter_allies", "unit name", u, name); + r_addmessage(r, u->faction, msg); + msg_release(msg); +} + +static void +encounter(region * r, unit * u) +{ + if (!fval(r, RF_ENCOUNTER)) return; + freset(r, RF_ENCOUNTER); + if (rng_int() % 100>=ENCCHANCE) return; + switch (rng_int() % 3) { + case 0: + find_manual(r, u); + break; + case 1: + get_villagers(r, u); + break; + case 2: + get_allies(r, u); + break; + } +} + +void +encounters(void) +{ + region *r; + + for (r = regions; r; r = r->next) { + if (!fval(r->terrain, SEA_REGION) && fval(r, RF_ENCOUNTER)) { + int c = 0; + unit * u; + for (u = r->units; u; u = u->next) { + c += u->number; + } + + if (c > 0) { + int i = 0; + int n = rng_int() % c; + + for (u = r->units; u; u = u->next) { + if (i+u->number>n) break; + i+=u->number; + } + assert(u && u->number); + encounter(r, u); + } + } + } +} + +static const terrain_type * +chaosterrain(void) +{ + static const terrain_type ** types; + static int numtypes; + + if (numtypes==0) { + const terrain_type * terrain; + for (terrain=terrains();terrain!=NULL;terrain=terrain->next) { + if (fval(terrain, LAND_REGION) && terrain->herbs) { + ++numtypes; + } + } + types = malloc(sizeof(terrain_type)*numtypes); + numtypes = 0; + for (terrain=terrains();terrain!=NULL;terrain=terrain->next) { + if (fval(terrain, LAND_REGION) && terrain->herbs) { + types[numtypes++] = terrain; + } + } + } + return types[rng_int() % numtypes]; +} + + +static unit * +random_unit(const region * r) +{ + int c = 0; + int n; + unit *u; + + for (u = r->units; u; u = u->next) { + if (u->race != new_race[RC_SPELL]) { + c += u->number; + } + } + + if (c == 0) { + return NULL; + } + n = rng_int() % c; + c = 0; + u = r->units; + + while (u && c < n) { + if (u->race != new_race[RC_SPELL]) { + c += u->number; + } + u = u->next; + } + + return u; +} + +void +chaos(region * r) +{ + if (rng_int() % 100 < 8) { + switch (rng_int() % 3) { + case 0: /* Untote */ + if (!fval(r->terrain, SEA_REGION)) { + unit * u = random_unit(r); + if (u && playerrace(u->race)) { + ADDMSG(&u->faction->msgs, msg_message("chaos_disease", "unit", u)); + u_setfaction(u, get_monsters()); + u->race = new_race[RC_GHOUL]; + } + } + break; + case 1: /* Drachen */ + if (random_unit(r)) { + int mfac = 0; + unit * u; + switch (rng_int() % 3) { + case 0: + mfac = 100; + u = createunit(r, get_monsters(), rng_int() % 8 + 1, new_race[RC_FIREDRAGON]); + break; + case 1: + mfac = 500; + u = createunit(r, get_monsters(), rng_int() % 4 + 1, new_race[RC_DRAGON]); + break; + default: + mfac = 1000; + u = createunit(r, get_monsters(), rng_int() % 2 + 1, new_race[RC_WYRM]); + break; + } + if (mfac) set_money(u, u->number * (rng_int() % mfac)); + fset(u, UFL_ISNEW|UFL_MOVED); + } + case 2: /* Terrainveränderung */ + if (!fval(r->terrain, FORBIDDEN_REGION)) { + if (!fval(r->terrain, SEA_REGION)) { + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * rn = rconnect(r, dir); + if (rn && fval(rn->terrain, SEA_REGION)) break; + } + if (dir!=MAXDIRECTIONS) { + ship * sh = r->ships; + unit ** up; + + while (sh) { + ship * nsh = sh->next; + damage_ship(sh, 0.50); + if (sh->damage >= sh->size * DAMAGE_SCALE) { + remove_ship(&sh->region->ships, sh); + } + sh = nsh; + } + + for (up = &r->units; *up;) { + unit * u = *up; + if (u->race != new_race[RC_SPELL] && u->ship == 0 && !canfly(u)) { + ADDMSG(&u->faction->msgs, msg_message("tidalwave_kill", "region unit", r, u)); + remove_unit(up, u); + } + if (*up==u) up = &u->next; + } + ADDMSG(&r->msgs, msg_message("tidalwave", "region", r)); + + while (r->buildings) { + remove_building(&r->buildings, r->buildings); + } + terraform_region(r, newterrain(T_OCEAN)); + } + } else { + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * rn = rconnect(r, dir); + if (rn && fval(rn->terrain, SEA_REGION)) break; + } + if (dir!=MAXDIRECTIONS) { + terraform_region(r, chaosterrain()); + } + } + } + } + } +} + + +static int +nb_armor(const unit *u, int index) +{ + const item * itm; + int av = 0; + int s = 0, a = 0; + + if (!(u->race->battle_flags & BF_EQUIPMENT)) return 0; + + /* Normale Rüstung */ + + for (itm=u->items;itm;itm=itm->next) { + const armor_type * atype = itm->type->rtype->atype; + if (atype!=NULL) { + int * schutz = &a; + if (atype->flags & ATF_SHIELD) schutz = &s; + if (*schutz <= index) { + *schutz += itm->number; + if (*schutz > index) { + av += atype->prot; + } + } + } + } + return av; +} + +static int +damage_unit(unit *u, const char *dam, boolean physical, boolean magic) +{ + int *hp = malloc(u->number * sizeof(int)); + int h; + int i, dead = 0, hp_rem = 0, heiltrank; + double magres = magic_resistance(u); + + assert(u->number); + if (fval(u->race, RCF_ILLUSIONARY) || u->race == new_race[RC_SPELL]) { + return 0; + } + + h = u->hp/u->number; + /* HP verteilen */ + for (i=0; inumber; i++) hp[i] = h; + h = u->hp - (u->number * h); + for (i=0; inumber; i++) { + int damage = dice_rand(dam); + if (magic) damage = (int)(damage * (1.0 - magres)); + if (physical) damage -= nb_armor(u, i); + hp[i] -= damage; + } + + /* Auswirkungen */ + for (i=0; inumber; i++) { + if (hp[i] <= 0){ + heiltrank = 0; + + /* Sieben Leben */ + if (old_race(u->race) == RC_CAT && (chance(1.0 / 7))) { + hp[i] = u->hp/u->number; + hp_rem += hp[i]; + continue; + } + + /* Heiltrank */ + if (oldpotiontype[P_HEAL]) { + if (get_effect(u, oldpotiontype[P_HEAL]) > 0) { + change_effect(u, oldpotiontype[P_HEAL], -1); + heiltrank = 1; + } else if (i_get(u->items, oldpotiontype[P_HEAL]->itype) > 0) { + i_change(&u->items, oldpotiontype[P_HEAL]->itype, -1); + change_effect(u, oldpotiontype[P_HEAL], 3); + heiltrank = 1; + } + if (heiltrank && (chance(0.50))) { + hp[i] = u->hp/u->number; + hp_rem += hp[i]; + continue; + } + } + dead++; + } else { + hp_rem += hp[i]; + } + } + + scale_number(u, u->number - dead); + u->hp = hp_rem; + + free(hp); + + return dead; +} + +void +drown(region *r) +{ + if (fval(r->terrain, SEA_REGION)) { + unit ** up = up=&r->units; + while (*up) { + unit *u = *up; + int amphibian_level = 0; + if (u->ship || u->race == new_race[RC_SPELL] || u->number==0) { + up=&u->next; + continue; + } + + if (amphibian_level) { + int dead = damage_unit(u, "5d1", false, false); + if (dead) { + ADDMSG(&u->faction->msgs, msg_message("drown_amphibian_dead", + "amount unit region", dead, u, r)); + } else { + ADDMSG(&u->faction->msgs, msg_message("drown_amphibian_nodead", + "unit region",u, r)); + } + } else if (!(canswim(u) || canfly(u))) { + scale_number(u, 0); + ADDMSG(&u->faction->msgs, msg_message("drown", "unit region", u, r)); + } + if (*up==u) up=&u->next; + } + remove_empty_units_in_region(r); + } +} + +region * +rrandneighbour(region *r) +{ + direction_t i; + region *rc = NULL; + int rr, c = 0; + + /* Nachsehen, wieviele Regionen in Frage kommen */ + + for (i = 0; i != MAXDIRECTIONS; i++) { + c++; + } + /* Zufällig eine auswählen */ + + rr = rng_int() % c; + + /* Durchzählen */ + + c = -1; + for (i = 0; i != MAXDIRECTIONS; i++) { + rc = rconnect(r, i); + c++; + if (c == rr) break; + } + assert(i!=MAXDIRECTIONS); + return rc; +} + +static void +volcano_destruction(region * volcano, region * r, region * rn, const char * damage) +{ + attrib * a; + unit ** up; + int percent = 25, time = 6 + rng_int()%12; + + rsettrees(r, 2, 0); + rsettrees(r, 1, 0); + rsettrees(r, 0, 0); + + a = a_find(r->attribs, &at_reduceproduction); + if (!a) { + a = make_reduceproduction(percent, time); + } else { + /* Produktion vierteln ... */ + a->data.sa[0] = (short)percent; + /* Für 6-17 Runden */ + a->data.sa[1] = (short)(a->data.sa[1] + time); + } + + /* Personen bekommen 4W10 Punkte Schaden. */ + + for (up=&r->units; *up;) { + unit * u = *up; + if (u->number) { + int dead = damage_unit(u, damage, true, false); + if (dead) { + ADDMSG(&u->faction->msgs, msg_message("volcano_dead", + "unit region dead", u, volcano, dead)); + } + if (r==volcano && !fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + if (rn) { + ADDMSG(&u->faction->msgs, msg_message("volcanooutbreak", + "regionv regionn", r, rn)); + } else { + ADDMSG(&u->faction->msgs, msg_message("volcanooutbreaknn", + "region", r)); + } + } + } + if (u==*up) up=&u->next; + } + + remove_empty_units_in_region(r); +} + +void +volcano_outbreak(region *r) +{ + region *rn; + unit *u; + faction *f; + + for (f=NULL,u=r->units; u; u=u->next) { + if (f!=u->faction) { + f = u->faction; + freset(f, FFL_SELECT); + } + } + + /* Zufällige Nachbarregion verwüsten */ + rn = rrandneighbour(r); + + volcano_destruction(r, r, rn, "4d10"); + if (rn) { + volcano_destruction(r, rn, NULL, "3d10"); + } +} + +static void +melt_iceberg(region *r) +{ + attrib *a; + unit *u; + + for (u=r->units; u; u=u->next) freset(u->faction, FFL_SELECT); + for (u=r->units; u; u=u->next) if (!fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + ADDMSG(&u->faction->msgs, msg_message("iceberg_melt", "region", r)); + } + + /* driftrichtung löschen */ + a = a_find(r->attribs, &at_iceberg); + if (a) a_remove(&r->attribs, a); + + /* Gebäude löschen */ + while (r->buildings) { + remove_building(&r->buildings, r->buildings); + } + + /* in Ozean wandeln */ + terraform_region(r, newterrain(T_OCEAN)); + + /* Einheiten, die nicht schwimmen können oder in Schiffen sind, + * ertrinken */ + drown(r); +} + +static void +move_iceberg(region *r) +{ + attrib *a; + direction_t dir; + region *rc; + + a = a_find(r->attribs, &at_iceberg); + if (!a) { + dir = (direction_t)(rng_int()%MAXDIRECTIONS); + a = a_add(&r->attribs, make_iceberg(dir)); + } else { + if (rng_int()%100 < 20) { + dir = (direction_t)(rng_int()%MAXDIRECTIONS); + a->data.i = dir; + } else { + dir = (direction_t)a->data.i; + } + } + + rc = rconnect(r, dir); + + if (rc && !fval(rc->terrain, ARCTIC_REGION)) { + if (fval(rc->terrain, SEA_REGION)) { /* Eisberg treibt */ + ship *sh, *shn; + unit *u; + int x, y; + + + for (u=r->units; u; u=u->next) freset(u->faction, FFL_SELECT); + for (u=r->units; u; u=u->next) if (!fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + ADDMSG(&u->faction->msgs, msg_message("iceberg_drift", + "region dir", r, dir)); + } + + x = r->x; + y = r->y; + + runhash(r); + runhash(rc); + r->x = rc->x; + r->y = rc->y; + rc->x = x; + rc->y = y; + rhash(rc); + rhash(r); + + /* rc ist der Ozean (Ex-Eisberg), r der Eisberg (Ex-Ozean) */ + + /* Schiffe aus dem Zielozean werden in den Eisberg transferiert + * und nehmen Schaden. */ + + for (sh = r->ships; sh; sh=sh->next) freset(sh, SF_SELECT); + + for (sh = r->ships; sh; sh = sh->next) { + /* Meldung an Kapitän */ + damage_ship(sh, 0.10); + fset(sh, SF_SELECT); + } + + /* Personen, Schiffe und Gebäude verschieben */ + while (rc->buildings) { + rc->buildings->region = r; + translist(&rc->buildings, &r->buildings, rc->buildings); + } + while (rc->ships) { + fset(rc->ships, SF_SELECT); + damage_ship(rc->ships, 0.10); + move_ship(rc->ships, rc, r, NULL); + } + while (rc->units) { + building * b = rc->units->building; + u = rc->units; + move_unit(rc->units, r, NULL); + u->building = b; /* move_unit macht ein leave() */ + } + + /* Beschädigte Schiffe können sinken */ + + for (sh = r->ships; sh;) { + shn = sh->next; + if (fval(sh, SF_SELECT)) { + u = captain(sh); + if (sh->damage>=sh->size * DAMAGE_SCALE) { + if (u!=NULL) { + ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg_des", + "ship", sh)); + } + remove_ship(&sh->region->ships, sh); + } else if (u!=NULL) { + ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg", + "ship", sh)); + } + } + sh = shn; + } + + } else if (rng_int()%100 < 20) { /* Eisberg bleibt als Gletscher liegen */ + unit *u; + + rsetterrain(r, T_GLACIER); + a_remove(&r->attribs, a); + + for (u=r->units; u; u=u->next) freset(u->faction, FFL_SELECT); + for (u=r->units; u; u=u->next) if (!fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + ADDMSG(&u->faction->msgs, msg_message("iceberg_land", "region", r)); + } + } + } +} + +static void +move_icebergs(void) +{ + region *r; + + for (r=regions; r; r=r->next) { + if (r->terrain == newterrain(T_ICEBERG) && !fval(r, RF_SELECT)) { + int select = rng_int() % 10; + if (select < 4) { + /* 4% chance */ + fset(r, RF_SELECT); + melt_iceberg(r); + } else if (select<64) { + /* 60% chance */ + fset(r, RF_SELECT); + move_iceberg(r); + } + } + } +} + +void +create_icebergs(void) +{ + region *r; + + for (r=regions; r; r=r->next) { + if (r->terrain == newterrain(T_ICEBERG_SLEEP) && chance(0.05)) { + boolean has_ocean_neighbour = false; + direction_t dir; + region *rc; + unit *u; + + freset(r, RF_SELECT); + for (dir=0; dir < MAXDIRECTIONS; dir++) { + rc = rconnect(r, dir); + if (rc && fval(rc->terrain, SEA_REGION)) { + has_ocean_neighbour = true; + break; + } + } + if (!has_ocean_neighbour) continue; + + rsetterrain(r, T_ICEBERG); + + fset(r, RF_SELECT); + move_iceberg(r); + + for (u=r->units; u; u=u->next) { + freset(u->faction, FFL_SELECT); + } + for (u=r->units; u; u=u->next) { + if (!fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + ADDMSG(&u->faction->msgs, msg_message("iceberg_create", "region", r)); + } + } + } + } +} + +static void +godcurse(void) +{ + region *r; + + for (r=regions; r; r=r->next) { + if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { + unit * u; + for(u=r->units; u; u=u->next) { + skill * sv = u->skills; + while (sv!=u->skills+u->skill_size) { + int weeks = 1+rng_int()%3; + reduce_skill(u, sv, weeks); + ++sv; + } + } + if (fval(r->terrain, SEA_REGION)) { + ship *sh; + for (sh = r->ships; sh;) { + ship *shn = sh->next; + damage_ship(sh, 0.10); + if (sh->damage>=sh->size * DAMAGE_SCALE) { + unit * u = shipowner(sh); + if (u) ADDMSG(&u->faction->msgs, + msg_message("godcurse_destroy_ship", "ship", sh)); + remove_ship(&sh->region->ships, sh); + } + sh = shn; + } + } + } + } + +} + +/** handles the "orcish" curse that makes units grow like old orks + * This would probably be better handled in an age-function for the curse, + * but it's now being called by randomevents() + */ +static void +orc_growth(void) +{ + region * r; + for (r = regions; r; r = r->next) { + unit *u; + for (u = r->units; u; u = u->next) { + static boolean init = false; + static const curse_type *ct_orcish = 0; + curse *c = 0; + if (!init) { + init = true; + ct_orcish = ct_find("orcish"); + } + if (ct_orcish) c = get_curse(u->attribs, ct_orcish); + + if (c && !has_skill(u, SK_MAGIC) && !has_skill(u, SK_ALCHEMY) && !fval(u, UFL_HERO)) { + int n; + int increase = 0; + int num = get_cursedmen(u, c); + double prob = curse_geteffect(c); + + for (n = (num - get_item(u, I_CHASTITY_BELT)); n > 0; n--) { + if (chance(prob)) { + ++increase; + } + } + if (increase) { + unit * u2 = create_unit(r, u->faction, increase, u->race, 0, NULL, u); + transfermen(u2, u, u2->number); + + ADDMSG(&u->faction->msgs, msg_message("orcgrowth", + "unit amount race", u, increase, u->race)); + } + } + } + } +} + +/** Talente von Dämonen verschieben sich. + */ +static void +demon_skillchanges(void) +{ + region * r; + + for (r = regions; r; r = r->next) { + unit * u; + for (u = r->units; u; u = u->next) { + if (u->race == new_race[RC_DAEMON]) { + skill * sv = u->skills; + int upchance = 15; + int downchance = 10; + + if (fval(u, UFL_HUNGER)) { + /* hungry demons only go down, never up in skill */ + static int rule_hunger = -1; + if (rule_hunger<0) { + rule_hunger = get_param_int(global.parameters, "hunger.demon.skill", 0); + } + if (rule_hunger) { + upchance = 0; + downchance = 15; + } + } + + while (sv!=u->skills+u->skill_size) { + int roll = rng_int() % 100; + if (sv->level>0 && roll < upchance+downchance) { + int weeks = 1+rng_int()%3; + if (roll < downchance) { + reduce_skill(u, sv, weeks); + if (sv->level<1) { + /* demons should never forget below 1 */ + set_level(u, sv->id, 1); + } + } else { + while (weeks--) learn_skill(u, sv->id, 1.0); + } + if (sv->old>sv->level) { + if (verbosity>=3) { + log_printf("%s dropped from %u to %u:%u in %s\n", + unitname(u), sv->old, sv->level, sv->weeks, skillname(sv->id, NULL)); + } + } + } + ++sv; + } + } + } + } +} + +/** Eisberge entstehen und bewegen sich. + * Einheiten die im Wasser landen, ertrinken. + */ +static void +icebergs(void) +{ + region * r; + create_icebergs(); + move_icebergs(); + for (r=regions; r; r=r->next) { + drown(r); + } +} + +#ifdef HERBS_ROT +static void +rotting_herbs(void) +{ + static int rule_rot = -1; + region * r; + + if (rule_rot<0) { + rule_rot = get_param_int(global.parameters, "rules.economy.herbrot", HERBROTCHANCE); + } + if (rule_rot==0) return; + + for (r = regions; r; r = r->next) { + unit * u; + for (u = r->units; u; u=u->next) { + item **itmp = &u->items, *hbag = *i_find(itmp, olditemtype[I_SACK_OF_CONSERVATION]); + int rot_chance = rule_rot; + + if (hbag) rot_chance = (rot_chance*2)/5; + while (*itmp) { + item * itm = *itmp; + int n = itm->number; + double k = n*rot_chance/100.0; + if (fval(itm->type, ITF_HERB)) { + double nv = normalvariate(k, k/4); + int inv = (int)nv; + int delta = MIN(n, inv); + if (i_change(itmp, itm->type, -delta)==NULL) { + continue; + } + } + itmp = &itm->next; + } + } + } +} +#endif + +void +randomevents(void) +{ + region *r; + + icebergs(); + godcurse(); + orc_growth(); + demon_skillchanges(); + + /* Orkifizierte Regionen mutieren und mutieren zurück */ + + for (r = regions; r; r = r->next) { + if (fval(r, RF_ORCIFIED)) { + direction_t dir; + double probability = 0.0; + for (dir = 0; dir < MAXDIRECTIONS; dir++) { + region *rc = rconnect(r, dir); + if (rc && rpeasants(rc) > 0 && !fval(rc, RF_ORCIFIED)) probability += 0.02; + } + if (chance(probability)) { + ADDMSG(&r->msgs, msg_message("deorcified", "region", r)); + freset(r, RF_ORCIFIED); + } + } else { + attrib *a = a_find(r->attribs, &at_orcification); + if (a!=NULL) { + double probability = 0.0; + if (rpeasants(r) <= 0) continue; + probability = a->data.i/(double)rpeasants(r); + if (chance(probability)) { + fset(r, RF_ORCIFIED); + a_remove(&r->attribs, a); + ADDMSG(&r->msgs, msg_message("orcified", "region", r)); + } else { + a->data.i -= MAX(10,a->data.i/10); + if (a->data.i <= 0) a_remove(&r->attribs, a); + } + } + } + } + + /* Vulkane qualmen, brechen aus ... */ + for (r = regions; r; r = r->next) { + if (r->terrain == newterrain(T_VOLCANO_SMOKING)) { + if (a_find(r->attribs, &at_reduceproduction)) { + ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r)); + rsetterrain(r, T_VOLCANO); + } else { + if (rng_int()%100 < 12) { + ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r)); + rsetterrain(r, T_VOLCANO); + } else if (r->age>20 && rng_int()%100 < 8) { + volcano_outbreak(r); + } + } + } else if (r->terrain == newterrain(T_VOLCANO)) { + if (rng_int()%100 < 4) { + ADDMSG(&r->msgs, msg_message("volcanostartsmoke", "region", r)); + rsetterrain(r, T_VOLCANO_SMOKING); + } + } + } + + /* Monumente zerfallen, Schiffe verfaulen */ + + for (r = regions; r; r = r->next) { + building ** blist = &r->buildings; + while (*blist) { + building * b = *blist; + if (fval(b->type, BTF_DECAY) && !building_owner(b)) { + b->size -= MAX(1, (b->size * 20) / 100); + if (b->size == 0) { + remove_building(blist, r->buildings); + } + } + if (*blist==b) blist=&b->next; + } + } + + /* monster-einheiten desertieren */ + for (r = regions; r; r=r->next) { + unit *u; + + for (u=r->units; u; u=u->next) { + if (u->faction && !is_monsters(u->faction) + && (u->race->flags & RCF_DESERT)) { + if (fval(u, UFL_ISNEW)) continue; + if (rng_int()%100 < 5) { + ADDMSG(&u->faction->msgs, msg_message("desertion", + "unit region", u, r)); + u_setfaction(u, get_monsters()); + } + } + } + } + + /* Chaos */ + for (r = regions; r; r = r->next) { + int i; + + if (fval(r, RF_CHAOTIC)) { + chaos(r); + } + i = chaoscount(r); + if (i) { + chaoscounts(r, -(int) (i * ((double) (rng_int() % 10)) / 100.0)); + } + } +#ifdef HERBS_ROT + rotting_herbs(); +#endif + + dissolve_units(); +} diff --git a/src/gamecode/randenc.h b/src/gamecode/randenc.h index 31eb0f57f..e35dfa18f 100644 --- a/src/gamecode/randenc.h +++ b/src/gamecode/randenc.h @@ -1,31 +1,31 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_GC_RANDENC -#define H_GC_RANDENC -#ifdef __cplusplus -extern "C" { -#endif - -extern void encounters(void); -extern void randomevents(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_GC_RANDENC +#define H_GC_RANDENC +#ifdef __cplusplus +extern "C" { +#endif + +extern void encounters(void); +extern void randomevents(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/report.c b/src/gamecode/report.c index 4d9308a41..0a94e674d 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -1,2435 +1,2434 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#define ECHECK_VERSION "4.01" - -#include -#include - -/* modules includes */ -#include - -/* attributes includes */ -#include -#include -#include -#include -#include - -/* gamecode includes */ -#include "creport.h" -#include "economy.h" -#include "monster.h" -#include "laws.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_STAT -#include -#include -#endif - -extern int verbosity; -extern int *storms; -extern int weeks_per_month; -extern int months_per_year; - -static char * -gamedate_season(const struct locale * lang) -{ - static char buf[256]; - gamedate gd; - - get_gamedate(turn, &gd); - - sprintf(buf, (const char *)LOC(lang, "nr_calendar_season"), - LOC(lang, weeknames[gd.week]), - LOC(lang, monthnames[gd.month]), - gd.year, - agename?LOC(lang, agename):"", - LOC(lang, seasonnames[gd.season])); - - return buf; -} - -void -rpc(FILE * F, char c, size_t num) -{ - while(num > 0) { - putc(c, F); - num--; - } -} - -void -rnl(FILE * F) -{ - fputc('\n', F); -} - -static void -centre(FILE * F, const char *s, boolean breaking) -{ - /* Bei Namen die genau 80 Zeichen lang sind, kann es hier Probleme - * geben. Seltsamerweise wird i dann auf MAXINT oder aehnlich - * initialisiert. Deswegen keine Strings die laenger als REPORTWIDTH - * sind! */ - - if (breaking && REPORTWIDTH < strlen(s)) { - strlist *T, *SP = 0; - sparagraph(&SP, s, 0, 0); - T = SP; - while (SP) { - centre(F, SP->s, false); - SP = SP->next; - } - freestrlist(T); - } else { - rpc(F, ' ', (REPORTWIDTH - strlen(s)+1) / 2); - fputs(s, F); - putc('\n', F); - } -} - -static void -rparagraph(FILE *F, const char *str, ptrdiff_t indent, int hanging_indent, char mark) -{ - static const char * spaces = " "; - size_t length = REPORTWIDTH; - const char * end, * begin; - - /* find out if there's a mark + indent already encoded in the string. */ - if (!mark) { - const char * x = str; - while (*x == ' ') ++x; - indent += x - str; - if (x[0] && indent && x[1]==' ') { - indent += 2; - mark = x[0]; - str = x + 2; - hanging_indent -= 2; - } - } - begin = end = str; - - do { - const char * last_space = begin; - - if (mark && indent>=2) { - fwrite(spaces, sizeof(char), indent-2, F); - fputc(mark, F); - fputc(' ', F); - mark = 0; - } else if (begin==str) { - fwrite(spaces, sizeof(char), indent, F); - } else { - fwrite(spaces, sizeof(char), indent+ hanging_indent, F); - } - while (*end && end<=begin+length-indent) { - if (*end==' ') { - last_space = end; - } - ++end; - } - if (*end==0) last_space = end; - if (last_space==begin) { - /* there was no space in this line. clip it */ - last_space = end; - } - fwrite(begin, sizeof(char), last_space-begin, F); - begin = last_space; - while (*begin==' ') { - ++begin; - } - if (begin>end) begin = end; - fputc('\n', F); - } while (*begin); -} - -static void -nr_spell(FILE * F, spell *sp, const struct locale * lang) -{ - int bytes, k, itemanz, costtyp; - int dh = 0; - char buf[4096]; - char * bufp = buf; - size_t size = sizeof(buf) - 1; - const char * params = sp->parameter; - - rnl(F); - centre(F, spell_name(sp, lang), true); - rnl(F); - rparagraph(F, LOC(lang, "nr_spell_description"), 0, 0, 0); - rparagraph(F, spell_info(sp, lang), 2, 0, 0); - - bytes = (int)strlcpy(bufp, LOC(lang, "nr_spell_type"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (size) { *bufp++ = ' '; --size; } - if (sp->sptyp & PRECOMBATSPELL) { - bytes = (int)strlcpy(bufp, LOC(lang, "sptype_precombat"), size); - } else if (sp->sptyp & COMBATSPELL) { - bytes = (int)strlcpy(bufp, LOC(lang, "sptype_combat"), size); - } else if (sp->sptyp & POSTCOMBATSPELL) { - bytes = (int)strlcpy(bufp, LOC(lang, "sptype_postcombat"), size); - } else { - bytes = (int)strlcpy(bufp, LOC(lang, "sptype_normal"), size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - *bufp = 0; - rparagraph(F, buf, 0, 0, 0); - - sprintf(buf, "%s %d", LOC(lang, "nr_spell_level"), sp->level); - rparagraph(F, buf, 0, 0, 0); - - sprintf(buf, "%s %d", LOC(lang, "nr_spell_rank"), sp->rank); - rparagraph(F, buf, 0, 0, 0); - - rparagraph(F, LOC(lang, "nr_spell_components"), 0, 0, 0); - for (k = 0; sp->components[k].type; ++k) { - const resource_type * rtype = sp->components[k].type; - itemanz = sp->components[k].amount; - costtyp = sp->components[k].cost; - if (itemanz > 0) { - size = sizeof(buf) - 1; - bufp = buf; - if (sp->sptyp & SPELLLEVEL) { - bytes = snprintf(bufp, size, " %d %s", itemanz, LOC(lang, resourcename(rtype, itemanz!=1))); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR ) { - bytes = snprintf(bufp, size, " * %s", LOC(lang, "nr_level")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } else { - if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR ) { - itemanz *= sp->level; - } - bytes = snprintf(bufp, size, "%d %s", itemanz, LOC(lang, resourcename(rtype, itemanz!=1))); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - *bufp = 0; - rparagraph(F, buf, 2, 2, '-'); - } - } - - size = sizeof(buf) - 1; - bufp = buf; - bytes = (int)strlcpy(buf, LOC(lang, "nr_spell_modifiers"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (sp->sptyp & FARCASTING) { - bytes = (int)strlcpy(bufp, " Fernzauber", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - dh = 1; - } - if (sp->sptyp & OCEANCASTABLE) { - if (dh == 1) { - bytes = (int)strlcpy(bufp, ",", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - bytes = (int)strlcpy(bufp, " Seezauber", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - dh = 1; - } - if (sp->sptyp & ONSHIPCAST) { - if (dh == 1){ - bytes = (int)strlcpy(bufp, ",", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - bytes = (int)strlcpy(bufp, " Schiffszauber", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - dh = 1; - } - if (sp->sptyp & NOTFAMILIARCAST) { - if (dh == 1) { - bytes = (int)strlcpy(bufp, ", k", size); - } else { - bytes = (int)strlcpy(bufp, " K", size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, "ann nicht vom Vertrauten gezaubert werden", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - dh = 1; - } - if (dh == 0) { - bytes = (int)strlcpy(bufp, " Keine", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - *bufp = 0; - rparagraph(F, buf, 0, 0, 0); - - rparagraph(F, LOC(lang, "nr_spell_syntax"), 0, 0, 0); - - bufp = buf; - size = sizeof(buf) - 1; - - if (sp->sptyp & ISCOMBATSPELL) { - bytes = (int)strlcpy(bufp, LOC(lang, keywords[K_COMBATSPELL]), size); - } else { - bytes = (int)strlcpy(bufp, LOC(lang, keywords[K_CAST]), size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - /* Reihenfolge beachten: Erst REGION, dann STUFE! */ - if (sp->sptyp & FARCASTING) { - bytes = snprintf(bufp, size, " [%s x y]", LOC(lang, parameters[P_REGION])); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (sp->sptyp & SPELLLEVEL) { - bytes = snprintf(bufp, size, " [%s n]", LOC(lang, parameters[P_LEVEL])); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - - bytes = (int)snprintf(bufp, size, " \"%s\"", spell_name(sp, lang)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - while (params && *params) { - typedef struct starget { - param_t param; - int flag; - const char * vars; - } starget; - starget targets[] = { - { P_REGION, REGIONSPELL, NULL }, - { P_UNIT, UNITSPELL, "par_unit" }, - { P_SHIP, SHIPSPELL, "par_ship" }, - { P_BUILDING, BUILDINGSPELL, "par_building" }, - { 0, 0, NULL } - }; - starget * targetp; - char cp = *params++; - int i, maxparam = 0; - const char * locp; - const char * syntaxp = sp->syntax; - - if (cp=='u') { - targetp = targets+1; - locp = LOC(lang, targetp->vars); - bytes = (int)snprintf(bufp, size, " <%s>", locp); - if (*params=='+') { - ++params; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else if (cp=='s') { - targetp = targets+2; - locp = LOC(lang, targetp->vars); - bytes = (int)snprintf(bufp, size, " <%s>", locp); - if (*params=='+') { - ++params; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else if (cp=='r') { - bytes = (int)strlcpy(bufp, " ", size); - if (*params=='+') { - ++params; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " [ ...]", size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else if (cp=='b') { - targetp = targets+3; - locp = LOC(lang, targetp->vars); - bytes = (int)snprintf(bufp, size, " <%s>", locp); - if (*params=='+') { - ++params; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else if (cp=='k') { - if (*params=='c') { - /* skip over a potential id */ - ++params; - } - for (targetp=targets;targetp->flag;++targetp) { - if (sp->sptyp&targetp->flag) ++maxparam; - } - if (maxparam>1) { - bytes = (int)strlcpy(bufp, " (", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - i = 0; - for (targetp=targets;targetp->flag;++targetp) { - if (sp->sptyp&targetp->flag) { - if (i++!=0) { - bytes = (int)strlcpy(bufp, " |", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (targetp->param) { - locp = LOC(lang, targetp->vars); - bytes = (int)snprintf(bufp, size, " %s <%s>", parameters[targetp->param], locp); - if (*params=='+') { - ++params; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); - } - } else { - bytes = (int)snprintf(bufp, size, " %s", parameters[targetp->param]); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - if (maxparam>1) { - bytes = (int)strlcpy(bufp, " )", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } else if (cp=='i' || cp=='c') { - const char * cstr; - assert(syntaxp); - cstr = strchr(syntaxp, ':'); - if (!cstr) { - locp = LOC(lang, mkname("spellpar", syntaxp)); - } else { - char substr[32]; - strncpy(substr, syntaxp, cstr-syntaxp); - substr[cstr-syntaxp] = 0; - locp = LOC(lang, mkname("spellpar", substr)); - syntaxp = substr + 1; - } - bytes = (int)snprintf(bufp, size, " <%s>", locp); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - *bufp = 0; - rparagraph(F, buf, 2, 0, 0); - rnl(F); -} - -void -sparagraph(strlist ** SP, const char *s, int indent, char mark) -{ - - /* Die Liste SP wird mit dem String s aufgefuellt, mit indent und einer - * mark, falls angegeben. SP wurde also auf 0 gesetzt vor dem Aufruf. - * Vgl. spunit (). */ - - int i, j, width; - int firstline; - static char buf[REPORTWIDTH + 1]; - - width = REPORTWIDTH - indent; - firstline = 1; - - for (;;) { - i = 0; - - do { - j = i; - while (s[j] && s[j] != ' ') - j++; - if (j > width) { - - /* j zeigt auf das ende der aktuellen zeile, i zeigt auf den anfang der - * nächsten zeile. existiert ein wort am anfang der zeile, welches - * länger als eine zeile ist, muss dieses hier abgetrennt werden. */ - - if (i == 0) - i = width - 1; - break; - } - i = j + 1; - } - while (s[j]); - - for (j = 0; j != indent; j++) - buf[j] = ' '; - - if (firstline && mark) - buf[indent - 2] = mark; - - for (j = 0; j != i - 1; j++) - buf[indent + j] = s[j]; - buf[indent + j] = 0; - - addstrlist(SP, buf); - - if (s[i - 1] == 0) - break; - - s += i; - firstline = 0; - } -} - -int -hat_in_region(item_t it, region * r, faction * f) -{ - unit *u; - - for (u = r->units; u; u = u->next) { - if (u->faction == f && get_item(u, it) > 0) { - return 1; - } - } - return 0; -} - -static void -nr_curses(FILE *F, const faction *viewer, const void * obj, typ_t typ, int indent) -{ - attrib *a = NULL; - int self = 0; - region *r; - - /* Die Sichtbarkeit eines Zaubers und die Zaubermeldung sind bei - * Gebäuden und Schiffen je nach, ob man Besitzer ist, verschieden. - * Bei Einheiten sieht man Wirkungen auf eigene Einheiten immer. - * Spezialfälle (besonderes Talent, verursachender Magier usw. werde - * bei jedem curse gesondert behandelt. */ - if (typ == TYP_SHIP){ - ship * sh = (ship*)obj; - unit * owner = shipowner(sh); - a = sh->attribs; - r = sh->region; - if (owner) { - if (owner->faction == viewer){ - self = 2; - } else { /* steht eine person der Partei auf dem Schiff? */ - unit *u = NULL; - for (u = r->units; u; u = u->next) { - if (u->ship == sh) { - self = 1; - break; - } - } - } - } - } else if (typ == TYP_BUILDING) { - building * b = (building*)obj; - unit * owner; - a = b->attribs; - r = b->region; - if ((owner = building_owner(b)) != NULL){ - if (owner->faction == viewer){ - self = 2; - } else { /* steht eine Person der Partei in der Burg? */ - unit *u = NULL; - for (u = r->units; u; u = u->next) { - if (u->building == b) { - self = 1; - break; - } - } - } - } - } else if (typ == TYP_UNIT) { - unit *u = (unit *)obj; - a = u->attribs; - r = u->region; - if (u->faction == viewer){ - self = 2; - } - } else if (typ == TYP_REGION) { - r = (region *)obj; - a = r->attribs; - } else { - /* fehler */ - } - - for (;a;a=a->next) { - char buf[4096]; - - if (fval(a->type, ATF_CURSE)) { - curse *c = (curse *)a->data.v; - message * msg; - - if (c->type->cansee) { - self = c->type->cansee(viewer, obj, typ, c, self); - } - msg = msg_curse(c, obj, typ, self); - - if (msg) { - rnl(F); - nr_render(msg, viewer->locale, buf, sizeof(buf), viewer); - rparagraph(F, buf, indent, 2, 0); - msg_release(msg); - } - } else if (a->type==&at_effect && self) { - effect_data * data = (effect_data *)a->data.v; - if (data->value>0) { - sprintf(buf, "Auf der Einheit lieg%s %d Wirkung%s %s.", - (data->value==1 ? "t" : "en"), - data->value, - (data->value==1 ? "" : "en"), - LOC(default_locale, resourcename(data->type->itype->rtype, 0))); - rnl(F); - rparagraph(F, buf, indent, 2, 0); - } - } - } -} - -static void -rps_nowrap(FILE * F, const char *s) -{ - const char *x = s; - size_t indent = 0; - - while (*x++ == ' '); - indent = x - s - 1; - if (*(x - 1) && indent && *x == ' ') - indent += 2; - x = s; - while (*s) { - if (s == x) { - x = strchr(x + 1, ' '); - if (!x) - x = s + strlen(s); - } - rpc(F, *s++, 1); - } -} - -static void -nr_unit(FILE * F, const faction * f, const unit * u, int indent, int mode) -{ - attrib *a_otherfaction; - char marker; - int dh; - boolean isbattle = (boolean)(mode == see_battle); - char buf[8192]; - - if (fval(u->race, RCF_INVISIBLE)) return; - - { - rnl(F); - dh = bufunit(f, u, indent, mode, buf, sizeof(buf)); - } - - a_otherfaction = a_find(u->attribs, &at_otherfaction); - - if (u->faction == f) { - marker = '*'; - } else if ALLIED(u->faction, f) { - marker = 'o'; - } else if (a_otherfaction && f != u->faction && get_otherfaction(a_otherfaction) == f - && !fval(u, UFL_ANON_FACTION)) { - marker = '!'; - } else { - if (dh && !fval(u, UFL_ANON_FACTION)) { - marker = '+'; - } else { - marker = '-'; - } - } - rparagraph(F, buf, indent, 0, marker); - - if (!isbattle) { - nr_curses(F, f, u, TYP_UNIT, indent); - } -} - -static void -rp_messages(FILE * F, message_list * msgs, faction * viewer, int indent, boolean categorized) -{ - nrsection * section; - if (!msgs) return; - for (section = sections; section; section=section->next) { - int k = 0; - struct mlist * m = msgs->begin; - while (m) { - /* messagetype * mt = m->type; */ - if (!categorized || strcmp(nr_section(m->msg), section->name)==0) { - char lbuf[8192]; - - if (!k && categorized) { - const char * section_title; - char cat_identifier[24]; - - rnl(F); - sprintf(cat_identifier, "section_%s", section->name); - section_title = LOC(viewer->locale, cat_identifier); - centre(F, section_title, true); - rnl(F); - k = 1; - } - nr_render(m->msg, viewer->locale, lbuf, sizeof(lbuf), viewer); - rparagraph(F, lbuf, indent, 2, 0); - } - m = m->next; - } - if (!categorized) break; - } -} - -static void -rp_battles(FILE * F, faction * f) -{ - if (f->battles!=NULL) { - struct bmsg * bm = f->battles; - rnl(F); - centre(F, LOC(f->locale, "section_battle"), false); - rnl(F); - - while (bm) { - char buf[256]; - RENDER(f, buf, sizeof(buf), ("battle::header", "region", bm->r)); - rnl(F); - centre(F, buf, true); - rnl(F); - rp_messages(F, bm->msgs, f, 0, false); - bm = bm->next; - } - } -} - -static void -prices(FILE * F, const region * r, const faction * f) -{ - const luxury_type *sale=NULL; - struct demand * dmd; - message * m; - int bytes, n = 0; - char buf[4096], * bufp = buf; - size_t size = sizeof(buf) - 1; - - if (r->land==NULL || r->land->demands==NULL) return; - for (dmd=r->land->demands;dmd;dmd=dmd->next) { - if (dmd->value==0) sale = dmd->type; - else if (dmd->value > 0) n++; - } - assert(sale!=NULL); - - m = msg_message("nr_market_sale", "product price", - sale->itype->rtype, sale->price); - - bytes = (int)nr_render(m, f->locale, bufp, size, f); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - msg_release(m); - - if (n > 0) { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_intro"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - for (dmd=r->land->demands;dmd;dmd=dmd->next) if(dmd->value > 0) { - m = msg_message("nr_market_price", "product price", - dmd->type->itype->rtype, dmd->value * dmd->type->price); - bytes = (int)nr_render(m, f->locale, bufp, size, f); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - msg_release(m); - n--; - if (n == 0) { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_end"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - else if (n == 1) { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_final"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_next"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - } - /* Schreibe Paragraphen */ - *bufp = 0; - rparagraph(F, buf, 0, 0, 0); - -} - -boolean -see_border(const connection * b, const faction * f, const region * r) -{ - boolean cs = b->type->fvisible(b, f, r); - if (!cs) { - cs = b->type->rvisible(b, r); - if (!cs) { - const unit * us = r->units; - while (us && !cs) { - if (us->faction==f) { - cs = b->type->uvisible(b, us); - if (cs) break; - } - us=us->next; - } - } - } - return cs; -} - -static void -describe(FILE * F, const seen_region * sr, faction * f) -{ - const region * r = sr->r; - int n; - boolean dh; - direction_t d; - int trees; - int saplings; - attrib *a; - const char *tname; - struct edge { - struct edge * next; - char * name; - boolean transparent; - boolean block; - boolean exist[MAXDIRECTIONS]; - direction_t lastd; - } * edges = NULL, * e; - boolean see[MAXDIRECTIONS]; - char buf[8192]; - char * bufp = buf; - size_t size = sizeof(buf); - int bytes; - - for (d = 0; d != MAXDIRECTIONS; d++) { - /* Nachbarregionen, die gesehen werden, ermitteln */ - region *r2 = rconnect(r, d); - connection *b; - see[d] = true; - if (!r2) continue; - for (b=get_borders(r, r2);b;) { - struct edge * e = edges; - boolean transparent = b->type->transparent(b, f); - const char * name = b->type->name(b, r, f, GF_DETAILED|GF_ARTICLE); - - if (!transparent) see[d] = false; - if (!see_border(b, f, r)) { - b = b->next; - continue; - } - while (e && (e->transparent != transparent || strcmp(name,e->name))) e = e->next; - if (!e) { - e = calloc(sizeof(struct edge), 1); - e->name = strdup(name); - e->transparent = transparent; - e->next = edges; - edges = e; - } - e->lastd=d; - e->exist[d] = true; - b = b->next; - } - } - - bytes = (int)f_regionid(r, f, bufp, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (sr->mode==see_travel) { - bytes = (int)strlcpy(bufp, " (durchgereist)", size); - } - else if (sr->mode==see_neighbour) { - bytes = (int)strlcpy(bufp, " (benachbart)", size); - } - else if (sr->mode==see_lighthouse) { - bytes = (int)strlcpy(bufp, " (vom Turm erblickt)", size); - } else { - bytes = 0; - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - /* Terrain */ - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - tname = terrain_name(r); - bytes = (int)strlcpy(bufp, LOC(f->locale, tname), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - /* Trees */ - trees = rtrees(r,2); - saplings = rtrees(r,1); - if (production(r)) { - if (trees > 0 || saplings > 0) { - bytes = snprintf(bufp, size, ", %d/%d ", trees, saplings); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (fval(r, RF_MALLORN)) { - if (trees == 1) { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_mallorntree"), size); - } else { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_mallorntree_p"), size); - } - } - else if (trees == 1) { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_tree"), size); - } else { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_tree_p"), size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - - /* iron & stone */ - if (sr->mode==see_unit && f != (faction *) NULL) { - resource_report result[MAX_RAWMATERIALS]; - int n, numresults = report_resources(sr, result, MAX_RAWMATERIALS, f); - - for (n=0;n=0 && result[n].level>=0) { - bytes = snprintf(bufp, size, ", %d %s/%d", result[n].number, - LOC(f->locale, result[n].name), result[n].level); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - } - - /* peasants & silver */ - if (rpeasants(r)) { - int n = rpeasants(r); - bytes = snprintf(bufp, size, ", %d", n); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (r->land->ownership) { - const char * str = locale_string(f->locale, mkname("morale", itoa10(r->land->morale))); - bytes = snprintf(bufp, size, " %s", str); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (fval(r, RF_ORCIFIED)) { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - bytes = (int)strlcpy(bufp, LOC(f->locale, n==1?"rc_orc":"rc_orc_p"), size); - } else { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, n==1?"peasant":"peasant_p"), size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (is_mourning(r, turn+1)) { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_mourning"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - if (rmoney(r) && sr->mode>=see_travel) { - bytes = snprintf(bufp, size, ", %d ", rmoney(r)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, resourcename(oldresourcetype[R_SILVER], rmoney(r)!=1)), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - /* Pferde */ - - if (rhorses(r)) { - bytes = snprintf(bufp, size, ", %d ", rhorses(r)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, resourcename(oldresourcetype[R_HORSE], (rhorses(r)>1)?GR_PLURAL:0)), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - - if (r->display && r->display[0]) { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, r->display, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - n = r->display[strlen(r->display) - 1]; - if (n != '!' && n != '?' && n != '.') { - bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - - if (rule_region_owners()) { - const faction * owner = region_get_owner(r); - if (owner!=NULL) { - bytes = snprintf(bufp, size, " Die Region ist im Besitz von %s.", - factionname(owner)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - a = a_find(r->attribs, &at_overrideroads); - - if (a) { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, (char *)a->data.v, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else { - int nrd = 0; - - /* Nachbarregionen, die gesehen werden, ermitteln */ - for (d = 0; d != MAXDIRECTIONS; d++) { - if (see[d] && rconnect(r, d)) nrd++; - } - /* list directions */ - - dh = false; - for (d = 0; d != MAXDIRECTIONS; d++) if (see[d]) { - region * r2 = rconnect(r, d); - if(!r2) continue; - nrd--; - if (dh) { - char regname[4096]; - if (nrd == 0) { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nb_final"), size); - } else { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nb_next"), size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, directions[d]), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - f_regionid(r2, f, regname, sizeof(regname)); - bytes = snprintf(bufp, size, trailinto(r2, f->locale), regname); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - else { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - MSG(("nr_vicinitystart", "dir region", d, r2), bufp, size, f->locale, f); - bufp += strlen(bufp); - dh = true; - } - } - /* Spezielle Richtungen */ - for (a = a_find(r->attribs, &at_direction);a && a->type==&at_direction;a=a->next) { - spec_direction * d = (spec_direction *)(a->data.v); - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, d->desc), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " (\"", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, d->keyword), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, "\")", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - dh = 1; - } - } - rnl(F); - *bufp = 0; - rparagraph(F, buf, 0, 0, 0); - - if (sr->mode==see_unit && is_astral(r) && - !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) { - /* Sonderbehandlung Teleport-Ebene */ - region_list *rl = astralregions(r, inhabitable); - region_list *rl2; - - if (rl) { - bufp = buf; - size = sizeof(buf) - 1; - bytes = (int)strlcpy(bufp, "Schemen der Regionen ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - rl2 = rl; - while (rl2) { - bytes = (int)f_regionid(rl2->data, f, bufp, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - rl2 = rl2->next; - if (rl2) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - bytes = (int)strlcpy(bufp, " sind erkennbar.", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - free_regionlist(rl); - /* Schreibe Paragraphen */ - rnl(F); - *bufp = 0; - rparagraph(F, buf, 0, 0, 0); - } - } - - n = 0; - - /* Wirkungen permanenter Sprüche */ - nr_curses(F, f, r, TYP_REGION,0); - - /* Produktionsreduktion */ - a = a_find(r->attribs, &at_reduceproduction); - if (a) { - const char * str = LOC(f->locale, "nr_reduced_production"); - rparagraph(F, str, 0, 0, 0); - } - - if (edges) rnl(F); - for (e=edges;e;e=e->next) { - boolean first = true; - bufp = buf; - size = sizeof(buf) - 1; - for (d=0;d!=MAXDIRECTIONS;++d) { - if (!e->exist[d]) continue; - if (first) bytes = (int)strlcpy(bufp, "Im ", size); - else if (e->lastd==d) bytes = (int)strlcpy(bufp, " und im ", size); - else bytes = (int)strlcpy(bufp, ", im ", size ); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, directions[d]), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - first = false; - } - if (!e->transparent) bytes = (int)strlcpy(bufp, " versperrt ", size); - else bytes = (int)strlcpy(bufp, " befindet sich ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, e->name, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (!e->transparent) bytes = (int)strlcpy(bufp, " die Sicht.", size); - else bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - *bufp = 0; - rparagraph(F, buf, 0, 0, 0); - } - if (edges) { - while (edges) { - e = edges->next; - free(edges->name); - free(edges); - edges = e; - } - } -} - -static void -statistics(FILE * F, const region * r, const faction * f) -{ - const unit *u; - int number = 0, p = rpeasants(r); - message * m; - item *itm, *items = NULL; - char buf[4096]; - - /* count */ - for (u = r->units; u; u = u->next) { - if (u->faction == f && !fval(u->race, RCF_INVISIBLE)) { - for (itm=u->items;itm;itm=itm->next) { - i_change(&items, itm->type, itm->number); - } - number += u->number; - } - } - /* print */ - rnl(F); - m = msg_message("nr_stat_header", "region", r); - nr_render(m, f->locale, buf, sizeof(buf), f); - msg_release(m); - rparagraph(F, buf, 0, 0, 0); - rnl(F); - - /* Region */ - if (skill_enabled[SK_ENTERTAINMENT] && fval(r->terrain, LAND_REGION) && rmoney(r)) { - m = msg_message("nr_stat_maxentertainment", "max", entertainmoney(r)); - nr_render(m, f->locale, buf, sizeof(buf), f); - rparagraph(F, buf, 2, 2, 0); - msg_release(m); - } - if (production(r) && (!fval(r->terrain, SEA_REGION) || f->race == new_race[RC_AQUARIAN])) { - if (markets_module()) { /* hack */ - m = msg_message("nr_stat_salary_new", "max", wage(r, NULL, NULL, turn+1)); - } else { - m = msg_message("nr_stat_salary", "max", wage(r, f, f->race, turn+1)); - } - nr_render(m, f->locale, buf, sizeof(buf), f); - rparagraph(F, buf, 2, 2, 0); - msg_release(m); - } - - if (p) { - m = msg_message("nr_stat_recruits", "max", p / RECRUITFRACTION); - nr_render(m, f->locale, buf, sizeof(buf), f); - rparagraph(F, buf, 2, 2, 0); - msg_release(m); - - if (!markets_module()) { - if (buildingtype_exists(r, bt_find("caravan"), true)) { - m = msg_message("nr_stat_luxuries", "max", - (p * 2) / TRADE_FRACTION); - } else { - m = msg_message("nr_stat_luxuries", "max", - p / TRADE_FRACTION); - } - nr_render(m, f->locale, buf, sizeof(buf), f); - rparagraph(F, buf, 2, 2, 0); - msg_release(m); - } - - if (r->land->ownership) { - m = msg_message("nr_stat_morale", "morale", r->land->morale); - nr_render(m, f->locale, buf, sizeof(buf), f); - rparagraph(F, buf, 2, 2, 0); - msg_release(m); - } - - - } - /* info about units */ - - m = msg_message("nr_stat_people", "max", number); - nr_render(m, f->locale, buf, sizeof(buf), f); - rparagraph(F, buf, 2, 2, 0); - msg_release(m); - - for (itm = items; itm; itm=itm->next) { - sprintf(buf, "%s: %d", - LOC(f->locale, resourcename(itm->type->rtype, GR_PLURAL)), - itm->number); - rparagraph(F, buf, 2, 2, 0); - } - while (items) i_free(i_remove(&items, items)); -} - -static void -durchreisende(FILE * F, const region * r, const faction * f) -{ - if (fval(r, RF_TRAVELUNIT)) { - attrib *abegin = a_find(r->attribs, &at_travelunit), *a; - int counter = 0, maxtravel = 0; - char buf[8192]; - char * bufp = buf; - int bytes; - size_t size = sizeof(buf) - 1; - - /* How many are we listing? For grammar. */ - for (a = abegin; a && a->type==&at_travelunit; a = a->next) { - unit * u = (unit*)a->data.v; - - if (r!=u->region && (u->ship==NULL || fval(u, UFL_OWNER))) { - if (cansee_durchgezogen(f, r, u, 0)) { - ++maxtravel; - } - } - } - - if (maxtravel==0) { - return; - } - - /* Auflisten. */ - rnl(F); - - for (a = abegin; a && a->type==&at_travelunit; a = a->next) { - unit * u = (unit*)a->data.v; - - if (r!=u->region && (u->ship==NULL || fval(u, UFL_OWNER))) { - if (cansee_durchgezogen(f, r, u, 0)) { - ++counter; - if (u->ship != NULL) { - if (counter == 1) { - bytes = (int)strlcpy(bufp, "Die ", size); - } else { - bytes = (int)strlcpy(bufp, "die ", size); - } - if (wrptr(&bufp, &size, bytes)!=0) { - WARN_STATIC_BUFFER(); - break; - } - bytes = (int)strlcpy(bufp, shipname(u->ship), size); - } else { - bytes = (int)strlcpy(bufp, unitname(u), size); - } - if (wrptr(&bufp, &size, bytes)!=0) { - WARN_STATIC_BUFFER(); - break; - } - - if (counter + 1 < maxtravel) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) { - WARN_STATIC_BUFFER(); - break; - } - } else if (counter + 1 == maxtravel) { - bytes = (int)strlcpy(bufp, LOC(f->locale, "list_and"), size); - if (wrptr(&bufp, &size, bytes)!=0) { - WARN_STATIC_BUFFER(); - break; - } - } - } - } - } - /* TODO: finish localization */ - if (maxtravel == 1) { - bytes = (int)strlcpy(bufp, " hat die Region durchquert.", size); - } else { - bytes = (int)strlcpy(bufp, " haben die Region durchquert.", size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - *bufp = 0; - rparagraph(F, buf, 0, 0, 0); - } -} - -static int -buildingmaintenance(const building * b, const resource_type * rtype) -{ - const building_type * bt = b->type; - int c, cost=0; - static boolean init = false; - static const curse_type * nocost_ct; - if (!init) { init = true; nocost_ct = ct_find("nocostbuilding"); } - if (curse_active(get_curse(b->attribs, nocost_ct))) { - return 0; - } - for (c=0;bt->maintenance && bt->maintenance[c].number;++c) { - const maintenance * m = bt->maintenance + c; - if (m->rtype==rtype) { - if (fval(m, MTF_VARIABLE)) - cost += (b->size * m->number); - else - cost += m->number; - } - } - return cost; -} - -static int -report_template(const char * filename, report_context * ctx, const char * charset) -{ - faction * f = ctx->f; - region *r; - FILE * F = fopen(filename, "wt"); - seen_region * sr = NULL; - char buf[8192], * bufp; - size_t size; - int bytes; - - int enc = xmlParseCharEncoding(charset); - - if (F==NULL) { - perror(filename); - return -1; - } - - if (enc==XML_CHAR_ENCODING_UTF8) { - const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; - fwrite(utf8_bom, 1, 3, F); - } - - rps_nowrap(F, ""); - rnl(F); - rps_nowrap(F, LOC(f->locale, "nr_template")); - rnl(F); - rps_nowrap(F, ""); - rnl(F); - - sprintf(buf, "%s %s \"%s\"", LOC(f->locale, "ERESSEA"), factionid(f), LOC(f->locale, "enterpasswd")); - rps_nowrap(F, buf); - rnl(F); - - rps_nowrap(F, ""); - rnl(F); - sprintf(buf, "; ECHECK -l -w4 -r%d -v%s", f->race->recruitcost, ECHECK_VERSION); - /* -v3.4: ECheck Version 3.4.x */ - rps_nowrap(F, buf); - rnl(F); - - for (r=ctx->first; sr==NULL && r!=ctx->last; r=r->next) { - sr = find_seen(ctx->seen, r); - } - - for (;sr!=NULL;sr=sr->next) { - region * r = sr->r; - unit *u; - int dh = 0; - - if (sr->modeunits; u; u = u->next) { - if (u->faction == f && !fval(u->race, RCF_INVISIBLE)) { - order * ord; - if (!dh) { - plane * pl = getplane(r); - int nx = r->x, ny = r->y; - - pnormalize(&nx, &ny, pl); - adjust_coordinates(f, &nx, &ny, pl, r); - rps_nowrap(F, ""); - rnl(F); - if (pl && pl->id != 0) { - sprintf(buf, "%s %d,%d,%d ; %s", LOC(f->locale, parameters[P_REGION]), - nx, ny, pl->id, rname(r, f->locale)); - } else { - sprintf(buf, "%s %d,%d ; %s", LOC(f->locale, parameters[P_REGION]), - nx, ny, rname(r, f->locale)); - } - rps_nowrap(F, buf); - rnl(F); - sprintf(buf,"; ECheck Lohn %d", wage(r, f, f->race, turn+1)); - rps_nowrap(F, buf); - rnl(F); - rps_nowrap(F, ""); - rnl(F); - } - dh = 1; - - bufp = buf; - size = sizeof(buf) - 1; - bytes = snprintf(bufp, size, "%s %s; %s [%d,%d$", - LOC(u->faction->locale, parameters[P_UNIT]), - unitid(u), u->name, u->number, get_money(u)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (u->building != NULL && fval(u, UFL_OWNER)) { - building * b = u->building; - int cost = buildingmaintenance(b, r_silver); - - if (cost > 0) { - bytes = (int)strlcpy(bufp, ",U", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, itoa10(cost), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } else if (u->ship) { - if (fval(u, UFL_OWNER)) { - bytes = (int)strlcpy(bufp, ",S", size); - } else { - bytes = (int)strlcpy(bufp, ",s", size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, shipid(u->ship), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (lifestyle(u) == 0) { - bytes = (int)strlcpy(bufp, ",I", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - bytes = (int)strlcpy(bufp, "]", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - *bufp = 0; - rps_nowrap(F, buf); - rnl(F); - - for (ord = u->old_orders; ord; ord = ord->next) { - /* this new order will replace the old defaults */ - strcpy(buf, " "); - write_order(ord, buf+2, sizeof(buf)-2); - rps_nowrap(F, buf); - rnl(F); - } - for (ord = u->orders; ord; ord = ord->next) { - if (u->old_orders && is_repeated(ord)) continue; /* unit has defaults */ - if (is_persistent(ord)) { - strcpy(buf, " "); - write_order(ord, buf+2, sizeof(buf)-2); - rps_nowrap(F, buf); - rnl(F); - } - } - - /* If the lastorder begins with an @ it should have - * been printed in the loop before. */ - } - } - } - rps_nowrap(F, ""); - rnl(F); - strcpy(buf, LOC(f->locale, parameters[P_NEXT])); - rps_nowrap(F, buf); - rnl(F); - fclose(F); - return 0; -} - -static void -show_allies(const faction * f, const ally * allies, char * buf, size_t size) -{ - int allierte = 0; - int i=0, h, hh = 0; - int bytes, dh = 0; - const ally * sf; - char * bufp = buf; /* buf already contains data */ - - --size; /* leave room for a null-terminator */ - - for (sf = allies; sf; sf = sf->next) { - int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); - if (mode > 0) ++allierte; - } - - for (sf = allies; sf; sf = sf->next) { - int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); - if (mode <= 0) continue; - i++; - if (dh) { - if (i == allierte) { - bytes = (int)strlcpy(bufp, LOC(f->locale, "list_and"), size); - } else { - bytes = (int)strlcpy(bufp, ", ", size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - dh = 1; - hh = 0; - bytes = (int)strlcpy(bufp, factionname(sf->faction), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " (", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if ((mode & HELP_ALL) == HELP_ALL) { - bytes = (int)strlcpy(bufp, "Alles", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else { - for (h = 1; h < HELP_ALL; h *= 2) { - int p = MAXPARAMS; - if ((mode & h) == h) { - switch (h) { - case HELP_TRAVEL: - p = P_TRAVEL; - break; - case HELP_MONEY: - p = P_MONEY; - break; - case HELP_FIGHT: - p = P_FIGHT; - break; - case HELP_GIVE: - p = P_GIVE; - break; - case HELP_GUARD: - p = P_GUARD; - break; - case HELP_FSTEALTH: - p = P_FACTIONSTEALTH; - break; - } - } - if (p!=MAXPARAMS) { - if (hh) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - bytes = (int)strlcpy(bufp, parameters[p], size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - hh = 1; - } - } - } - bytes = (int)strlcpy(bufp, ")", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - *bufp = 0; -} - -static void -allies(FILE * F, const faction * f) -{ - const group * g = f->groups; - char buf[16384]; - - if (f->allies) { - int bytes; - size_t size = sizeof(buf); - if (!f->allies->next) { - bytes = (int)strlcpy(buf, "Wir helfen der Partei ", size); - } else { - bytes = (int)strlcpy(buf, "Wir helfen den Parteien ", size); - } - size -= bytes; - show_allies(f, f->allies, buf + bytes, size); - rparagraph(F, buf, 0, 0, 0); - rnl(F); - } - - while (g) { - if (g->allies) { - int bytes; - size_t size = sizeof(buf); - if (!g->allies->next) { - bytes = snprintf(buf, size, "%s hilft der Partei ", g->name); - } else { - bytes = snprintf(buf, size, "%s hilft den Parteien ", g->name); - } - size -= bytes; - show_allies(f, g->allies, buf + bytes, size); - rparagraph(F, buf, 0, 0, 0); - rnl(F); - } - g = g->next; - } -} - -static void -guards(FILE * F, const region * r, const faction * see) -{ - /* die Partei see sieht dies; wegen - * "unbekannte Partei", wenn man es selbst ist... */ - - faction* guardians[512]; - - int nextguard = 0; - - unit *u; - int i; - - boolean tarned = false; - /* Bewachung */ - - for (u = r->units; u; u = u->next) { - if (is_guard(u, GUARD_ALL)!=0) { - faction *f = u->faction; - faction *fv = visible_faction(see, u); - - if(fv != f && see != fv) { - f = fv; - } - - if (f != see && fval(u, UFL_ANON_FACTION)) { - tarned=true; - } else { - for (i=0;i!=nextguard;++i) if (guardians[i]==f) break; - if (i==nextguard) { - guardians[nextguard++] = f; - } - } - } - } - - if (nextguard || tarned) { - char buf[8192]; - char * bufp = buf; - size_t size = sizeof(buf) - 1; - int bytes; - - bytes = (int)strlcpy(bufp, "Die Region wird von ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - for (i = 0; i!=nextguard+(tarned?1:0); ++i) { - if (i!=0) { - if (i == nextguard-(tarned?0:1)) { - bytes = (int)strlcpy(bufp, LOC(see->locale, "list_and"), size); - } else { - bytes = (int)strlcpy(bufp, ", ", size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (ilocale, "nr_addresses"), false); - rnl(F); - - while (flist!=NULL) { - const faction * f = flist->data; - if (!is_monsters(f)) { - char buf[8192]; - char label = '-'; - - sprintf(buf, "%s: %s; %s", factionname(f), f->email, f->banner?f->banner:""); - if (uf==f) label = '*'; - else if (ALLIED(uf, f)) label = 'o'; - else if (alliedfaction(NULL, uf, f, HELP_ALL)) label = '+'; - rparagraph(F, buf, 4, 0, label); - - } - flist = flist->next; - } - rnl(F); - rpline(F); -} - -static void -nr_ship(FILE * F, const seen_region * sr, const ship * sh, const faction * f, const unit * captain) -{ - const region * r = sr->r; - char buffer[8192], * bufp = buffer; - size_t size = sizeof(buffer) - 1; - int bytes; - char ch; - - rnl(F); - - if (captain && captain->faction == f) { - int n = 0, p = 0; - getshipweight(sh, &n, &p); - n = (n+99) / 100; /* 1 Silber = 1 GE */ - - bytes = snprintf(bufp, size, "%s, %s, (%d/%d)", shipname(sh), - LOC(f->locale, sh->type->name[0]), n, shipcapacity(sh) / 100); - } else { - bytes = snprintf(bufp, size, "%s, %s", shipname(sh), LOC(f->locale, sh->type->name[0])); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - assert(sh->type->construction->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */ - if (sh->size!=sh->type->construction->maxsize) { - bytes = snprintf(bufp, size, ", %s (%d/%d)", - LOC(f->locale, "nr_undercons"), sh->size, - sh->type->construction->maxsize); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (sh->damage) { - int percent = (sh->damage*100+DAMAGE_SCALE-1)/(sh->size*DAMAGE_SCALE); - bytes = snprintf(bufp, size, ", %d%% %s", percent, LOC(f->locale, "nr_damaged")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (!fval(r->terrain, SEA_REGION)) { - if (sh->coast != NODIRECTION) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, coasts[sh->coast]), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - ch = 0; - if (sh->display && sh->display[0]) { - bytes = (int)strlcpy(bufp, "; ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, sh->display, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - ch = sh->display[strlen(sh->display) - 1]; - } - if (ch != '!' && ch != '?' && ch != '.') { - bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - *bufp = 0; - rparagraph(F, buffer, 2, 0, 0); - - nr_curses(F, f, sh, TYP_SHIP, 4); -} - -static void -nr_building(FILE *F, const seen_region * sr, const building * b, const faction * f) -{ - int i, bytes; - const char * name, * bname, * billusion = NULL; - const struct locale * lang = NULL; - char buffer[8192], * bufp = buffer; - size_t size = sizeof(buffer) - 1; - - rnl(F); - - if (f) lang = f->locale; - - bytes = snprintf(bufp, size, "%s, %s %d, ", buildingname(b), LOC(f->locale, "nr_size"), b->size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - report_building(b, &bname, &billusion); - name = LOC(lang, billusion?billusion:bname); - bytes = (int)strlcpy(bufp, name, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (billusion) { - unit * owner = building_owner(b); - if (owner && owner->faction==f) { - /* illusion. report real type */ - name = LOC(lang, bname); - bytes = snprintf(bufp, size, " (%s)", name); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - - if (b->size < b->type->maxsize) { - bytes = (int)strlcpy(bufp, " (im Bau)", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - - if (b->besieged > 0 && sr->mode>=see_lighthouse) { - bytes = (int)strlcpy(bufp, ", belagert von ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, itoa10(b->besieged), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " Personen ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (b->besieged >= b->size * SIEGEFACTOR) { - bytes = (int)strlcpy(bufp, "(abgeschnitten)", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - i = 0; - if (b->display && b->display[0]) { - bytes = (int)strlcpy(bufp, "; ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, b->display, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - i = b->display[strlen(b->display) - 1]; - } - -#ifdef WDW_PYRAMID - - if (i != '!' && i != '?' && i != '.') { - scat(", "); - } - - if (b->type == bt_find("pyramid")) { - unit * owner = building_owner(b); - scat("Größenstufe "); - icat(wdw_pyramid_level(b)); - scat("."); - - if (owner && owner->faction==f) { - const construction *ctype = b->type->construction; - int completed = b->size; - int c; - - scat(" Baukosten pro Größenpunkt: "); - - while(ctype->improvement != NULL && - ctype->improvement != ctype && - ctype->maxsize > 0 && - ctype->maxsize <= completed) - { - completed -= ctype->maxsize; - ctype = ctype->improvement; - } - - assert(ctype->materials != NULL); - - for (c=0;ctype->materials[c].number;c++) { - const resource_type * rtype = ctype->materials[c].rtype; - int number = ctype->materials[c].number; - - if(c > 0) { - scat(", "); - } - icat(number); - scat(" "); - scat(locale_string(lang, resourcename(rtype, number!=1?GR_PLURAL:0))); - } - - scat("."); - - scat(" Erforderlicher Talentwert: "); - icat(b->type->construction->minskill); - scat("."); - } - } - -#else - - if (i != '!' && i != '?' && i != '.') { - bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - -#endif - *bufp = 0; - rparagraph(F, buffer, 2, 0, 0); - - if (sr->modelocale, bufp, size, f); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - msg_release(m); - - rparagraph(F, buf, 0, 0, 0); -} - -int -report_plaintext(const char * filename, report_context * ctx, const char * charset) -{ - int flag = 0; - char ch; - int anyunits, no_units, no_people; - const struct region *r; - faction * f = ctx->f; - unit *u; - char pzTime[64]; - attrib *a; - message * m; - unsigned char op; - int bytes, ix = want(O_STATISTICS); - int wants_stats = (f->options & ix); - FILE * F = fopen(filename, "wt"); - seen_region * sr = NULL; - char buf[8192]; - char * bufp; - int enc = xmlParseCharEncoding(charset); - size_t size; - - /* static variables can cope with writing for different turns */ - static int thisseason = -1; - static int nextseason = -1; - static int gamecookie = -1; - if (gamecookie!=global.cookie) { - gamedate date; - get_gamedate(turn+1, &date); - thisseason = date.season; - get_gamedate(turn+2, &date); - nextseason = date.season; - gamecookie = global.cookie; - } - - if (F==NULL) { - perror(filename); - return -1; - } - if (enc==XML_CHAR_ENCODING_UTF8) { - const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; - fwrite(utf8_bom, 1, 3, F); - } - - strftime(pzTime, 64, "%A, %d. %B %Y, %H:%M", localtime(&ctx->report_time)); - m = msg_message("nr_header_date", "game date", global.gamename, pzTime); - nr_render(m, f->locale, buf, sizeof(buf), f); - msg_release(m); - centre(F, buf, true); - - centre(F, gamedate_season(f->locale), true); - rnl(F); - sprintf(buf, "%s, %s/%s (%s)", factionname(f), - LOC(f->locale, rc_name(f->race, 1)), - LOC(f->locale, mkname("school", magic_school[f->magiegebiet])), - f->email); - centre(F, buf, true); - if (f_get_alliance(f)) { - centre(F, alliancename(f->alliance), true); - } - - if (f->age <= 2) { - const char * s; - if (f->age <= 1) { - ADDMSG(&f->msgs, msg_message("changepasswd", - "value", f->passw)); - } - RENDER(f, buf, sizeof(buf), ("newbie_password", "password", f->passw)); - rnl(F); - centre(F, buf, true); - s = locale_getstring(f->locale, "newbie_info_1"); - if (s) { - rnl(F); - centre(F, s, true); - } - s = locale_getstring(f->locale, "newbie_info_2"); - if (s) { - rnl(F); - centre(F, s, true); - } - if ((f->options & want(O_COMPUTER)) == 0) { - f->options |= want(O_COMPUTER); - s = locale_getstring(f->locale, "newbie_info_3"); - if (s) { - rnl(F); - centre(F, s, true); - } - } - } - rnl(F); -#if SCORE_MODULE - if (f->options & want(O_SCORE) && f->age > DISPLAYSCORE) { - RENDER(f, buf, sizeof(buf), ("nr_score", "score average", f->score, average_score_of_age(f->age, f->age / 24 + 1))); - centre(F, buf, true); - } -#endif -#ifdef COUNT_AGAIN - no_units = 0; - no_people = 0; - for (u=f->units;u;u=u->nextF) { - if (playerrace(u->race)) { - ++no_people; - no_units += u->number; - assert(f==u->faction); - } - } - if (no_units!=f->no_units) { - f->no_units = no_units; - } - if (no_people!=f->num_people) { - f->num_people = no_people; - } -#else - no_units = f->no_units; - no_people = f->num_people; -#endif - m = msg_message("nr_population", "population units", no_people, no_units); - nr_render(m, f->locale, buf, sizeof(buf), f); - msg_release(m); - centre(F, buf, true); - if (f->race == new_race[RC_HUMAN]) { - int maxmig = count_maxmigrants(f); - if (maxmig>0) { - m = msg_message("nr_migrants", "units maxunits", count_migrants(f), maxmig); - nr_render(m, f->locale, buf, sizeof(buf), f); - msg_release(m); - centre(F, buf, true); - } - } - if (f_get_alliance(f)) { - m = msg_message("nr_alliance", "leader name id age", alliance_get_leader(f->alliance), f->alliance->name, f->alliance->id, turn-f->alliance_joindate); - nr_render(m, f->locale, buf, sizeof(buf), f); - msg_release(m); - centre(F, buf, true); - } - { - int maxh = maxheroes(f); - if (maxh) { - message * msg = msg_message("nr_heroes", "units maxunits", countheroes(f), maxh); - nr_render(msg, f->locale, buf, sizeof(buf), f); - msg_release(msg); - centre(F, buf, true); - } - } - - if (f->items!=NULL) { - message * msg = msg_message("nr_claims", "items", f->items); - nr_render(msg, f->locale, buf, sizeof(buf), f); - msg_release(msg); - rnl(F); - centre(F, buf, true); - } - - /* Insekten-Winter-Warnung */ - if (f->race == new_race[RC_INSECT]) { - if (thisseason == 0) { - centre(F, LOC(f->locale, "nr_insectwinter"), true); - rnl(F); - } else { - if (nextseason == 0) { - centre(F, LOC(f->locale, "nr_insectfall"), true); - rnl(F); - } - } - } - - bufp = buf; - size = sizeof(buf) - 1; - bytes = snprintf(buf, size,"%s:", LOC(f->locale, "nr_options")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - for (op = 0; op != MAXOPTIONS; op++) { - if (f->options & want(op) && options[op]) { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, options[op]), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - flag++; - } - } - if (flag > 0) { - rnl(F); - *bufp = 0; - centre(F, buf, true); - } - - rp_messages(F, f->msgs, f, 0, true); - rp_battles(F, f); - a = a_find(f->attribs, &at_reportspell); - if (a) { - rnl(F); - centre(F, LOC(f->locale, "section_newspells"), true); - while (a && a->type==&at_reportspell) { - spell *sp = (spell *)a->data.v; - nr_spell(F, sp, f->locale); - a = a->next; - } - } - - ch = 0; - for (a=a_find(f->attribs, &at_showitem);a && a->type==&at_showitem;a=a->next) { - const potion_type * ptype = resource2potion(((const item_type*)a->data.v)->rtype); - const char * description = NULL; - if (ptype!=NULL) { - const char * pname = resourcename(ptype->itype->rtype, 0); - - if (ch==0) { - rnl(F); - centre(F, LOC(f->locale, "section_newpotions"), true); - ch = 1; - } - - rnl(F); - centre(F, LOC(f->locale, pname), true); - snprintf(buf, sizeof(buf), "%s %d", LOC(f->locale, "nr_level"), ptype->level); - centre(F, buf, true); - rnl(F); - - bufp = buf; - size = sizeof(buf) - 1; - bytes = snprintf(bufp, size, "%s: ", LOC(f->locale, "nr_herbsrequired")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (ptype->itype->construction) { - requirement * m = ptype->itype->construction->materials; - while (m->number) { - bytes = (int)strlcpy(bufp, LOC(f->locale, resourcename(m->rtype, 0)), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - ++m; - if (m->number) - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - *bufp = 0; - centre(F, buf, true); - rnl(F); - if (description==NULL) { - const char * potiontext = mkname("potion", pname); - description = LOC(f->locale, potiontext); - } - centre(F, description, true); - } - } - rnl(F); - centre(F, LOC(f->locale, "nr_alliances"), false); - rnl(F); - - allies(F, f); - - rpline(F); - - anyunits = 0; - - for (r=ctx->first;sr==NULL && r!=ctx->last;r=r->next) { - sr = find_seen(ctx->seen, r); - } - for (;sr!=NULL;sr=sr->next) { - region * r = sr->r; - int stealthmod = stealth_modifier(sr->mode); - building * b = r->buildings; - ship * sh = r->ships; - - if (sr->modemode==see_unit) { - anyunits = 1; - describe(F, sr, f); - if (markets_module() && r->land) { - const item_type * lux = r_luxury(r); - const item_type * herb = r->land->herbtype; - message * m = 0; - if (herb && lux) { - m = msg_message("nr_market_info_p", "p1 p2", - lux?lux->rtype:0, herb?herb->rtype:0); - } else if (lux || herb) { - m = msg_message("nr_market_info_s", "p1", - lux?lux->rtype:herb->rtype); - } - if (m) { - rnl(F); - nr_paragraph(F, m, f); - } - // - } else { - if (!fval(r->terrain, SEA_REGION) && rpeasants(r)/TRADE_FRACTION > 0) { - rnl(F); - prices(F, r, f); - } - } - guards(F, r, f); - durchreisende(F, r, f); - } - else { - if (sr->mode==see_far) { - describe(F, sr, f); - guards(F, r, f); - durchreisende(F, r, f); - } - else if (sr->mode==see_lighthouse) { - describe(F, sr, f); - durchreisende(F, r, f); - } else { - describe(F, sr, f); - durchreisende(F, r, f); - } - } - /* Statistik */ - - if (wants_stats && sr->mode==see_unit) - statistics(F, r, f); - - /* Nachrichten an REGION in der Region */ - - if (sr->mode==see_unit || sr->mode==see_travel) { - message_list * mlist = r_getmessages(r, f); - rp_messages(F, r->msgs, f, 0, true); - if (mlist) rp_messages(F, mlist, f, 0, true); - } - - /* report all units. they are pre-sorted in an efficient manner */ - u = r->units; - while (b) { - while (b && (!u || u->building!=b)) { - nr_building(F, sr, b, f); - b = b->next; - } - if (b) { - nr_building(F, sr, b, f); - while (u && u->building==b) { - nr_unit(F, f, u, 6, sr->mode); - u = u->next; - } - b = b->next; - } - } - while (u && !u->ship) { - if (stealthmod>INT_MIN) { - if (u->faction == f || cansee(f, r, u, stealthmod)) { - nr_unit(F, f, u, 4, sr->mode); - } - } - assert(!u->building); - u = u->next; - } - while (sh) { - while (sh && (!u || u->ship!=sh)) { - nr_ship(F, sr, sh, f, NULL); - sh = sh->next; - } - if (sh) { - nr_ship(F, sr, sh, f, u); - while (u && u->ship==sh) { - nr_unit(F, f, u, 6, sr->mode); - u = u->next; - } - sh = sh->next; - } - } - - assert(!u); - - rnl(F); - rpline(F); - } - if (!is_monsters(f)) { - if (!anyunits) { - rnl(F); - rparagraph(F, LOC(f->locale, "nr_youaredead"), 0, 2, 0); - } else { - list_address(F, f, ctx->addresses); - } - } - fclose(F); - return 0; -} - -void -base36conversion(void) -{ - region * r; - for (r=regions;r;r=r->next) { - unit * u; - for (u=r->units;u;u=u->next) { - if (forbiddenid(u->no)) { - uunhash(u); - u->no = newunitid(); - uhash(u); - } - } - } -} - -#define FMAXHASH 1021 - -struct fsee { - struct fsee * nexthash; - faction * f; - struct see { - struct see * next; - faction * seen; - unit * proof; - } * see; -} * fsee[FMAXHASH]; - -#define REPORT_NR (1 << O_REPORT) -#define REPORT_CR (1 << O_COMPUTER) -#define REPORT_ZV (1 << O_ZUGVORLAGE) -#define REPORT_ZIP (1 << O_COMPRESS) -#define REPORT_BZIP2 (1 << O_BZIP2) - - -unit * -can_find(faction * f, faction * f2) -{ - int key = f->no % FMAXHASH; - struct fsee * fs = fsee[key]; - struct see * ss; - if (f==f2) return f->units; - while (fs && fs->f!=f) fs=fs->nexthash; - if (!fs) return NULL; - ss=fs->see; - while (ss && ss->seen!=f2) ss=ss->next; - if (ss) { - /* bei TARNE PARTEI yxz muss die Partei von unit proof nicht - * wirklich Partei f2 sein! */ - /* assert(ss->proof->faction==f2); */ - return ss->proof; - } - return NULL; -} - -static void -add_find(faction * f, unit * u, faction *f2) -{ - /* faction f sees f2 through u */ - int key = f->no % FMAXHASH; - struct fsee ** fp = &fsee[key]; - struct fsee * fs; - struct see ** sp; - struct see * ss; - while (*fp && (*fp)->f!=f) fp=&(*fp)->nexthash; - if (!*fp) { - fs = *fp = calloc(sizeof(struct fsee), 1); - fs->f = f; - } else fs = *fp; - sp = &fs->see; - while (*sp && (*sp)->seen!=f2) sp=&(*sp)->next; - if (!*sp) { - ss = *sp = calloc(sizeof(struct see), 1); - ss->proof = u; - ss->seen = f2; - } else ss = *sp; - ss->proof = u; -} - -static void -update_find(void) -{ - region * r; - static boolean initial = true; - - if (initial) for (r=regions;r;r=r->next) { - unit * u; - for (u=r->units;u;u=u->next) { - faction * lastf = u->faction; - unit * u2; - for (u2=r->units;u2;u2=u2->next) { - if (u2->faction==lastf || u2->faction==u->faction) - continue; - if (seefaction(u->faction, r, u2, 0)) { - faction *fv = visible_faction(u->faction, u2); - lastf = fv; - add_find(u->faction, u2, fv); - } - } - } - } - initial = false; -} - -boolean -kann_finden(faction * f1, faction * f2) -{ - update_find(); - return (boolean)(can_find(f1, f2)!=NULL); -} - -/******* end summary ******/ - -void -register_nr(void) -{ - if (!nocr) register_reporttype("nr", &report_plaintext, 1<nexthash; - free(fsee[i]); - fsee[i] = fs; - } - } -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#define ECHECK_VERSION "4.01" + +#include +#include + +/* modules includes */ +#include + +/* attributes includes */ +#include +#include +#include +#include +#include + +/* gamecode includes */ +#include "creport.h" +#include "economy.h" +#include "monster.h" +#include "laws.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_STAT +#include +#include +#endif + +extern int verbosity; +extern int *storms; +extern int weeks_per_month; +extern int months_per_year; + +static char * +gamedate_season(const struct locale * lang) +{ + static char buf[256]; + gamedate gd; + + get_gamedate(turn, &gd); + + sprintf(buf, (const char *)LOC(lang, "nr_calendar_season"), + LOC(lang, weeknames[gd.week]), + LOC(lang, monthnames[gd.month]), + gd.year, + agename?LOC(lang, agename):"", + LOC(lang, seasonnames[gd.season])); + + return buf; +} + +void +rpc(FILE * F, char c, size_t num) +{ + while(num > 0) { + putc(c, F); + num--; + } +} + +void +rnl(FILE * F) +{ + fputc('\n', F); +} + +static void +centre(FILE * F, const char *s, boolean breaking) +{ + /* Bei Namen die genau 80 Zeichen lang sind, kann es hier Probleme + * geben. Seltsamerweise wird i dann auf MAXINT oder aehnlich + * initialisiert. Deswegen keine Strings die laenger als REPORTWIDTH + * sind! */ + + if (breaking && REPORTWIDTH < strlen(s)) { + strlist *T, *SP = 0; + sparagraph(&SP, s, 0, 0); + T = SP; + while (SP) { + centre(F, SP->s, false); + SP = SP->next; + } + freestrlist(T); + } else { + rpc(F, ' ', (REPORTWIDTH - strlen(s)+1) / 2); + fputs(s, F); + putc('\n', F); + } +} + +static void +rparagraph(FILE *F, const char *str, ptrdiff_t indent, int hanging_indent, char mark) +{ + static const char * spaces = " "; + size_t length = REPORTWIDTH; + const char * end, * begin; + + /* find out if there's a mark + indent already encoded in the string. */ + if (!mark) { + const char * x = str; + while (*x == ' ') ++x; + indent += x - str; + if (x[0] && indent && x[1]==' ') { + indent += 2; + mark = x[0]; + str = x + 2; + hanging_indent -= 2; + } + } + begin = end = str; + + do { + const char * last_space = begin; + + if (mark && indent>=2) { + fwrite(spaces, sizeof(char), indent-2, F); + fputc(mark, F); + fputc(' ', F); + mark = 0; + } else if (begin==str) { + fwrite(spaces, sizeof(char), indent, F); + } else { + fwrite(spaces, sizeof(char), indent+ hanging_indent, F); + } + while (*end && end<=begin+length-indent) { + if (*end==' ') { + last_space = end; + } + ++end; + } + if (*end==0) last_space = end; + if (last_space==begin) { + /* there was no space in this line. clip it */ + last_space = end; + } + fwrite(begin, sizeof(char), last_space-begin, F); + begin = last_space; + while (*begin==' ') { + ++begin; + } + if (begin>end) begin = end; + fputc('\n', F); + } while (*begin); +} + +static void +nr_spell(FILE * F, spell *sp, const struct locale * lang) +{ + int bytes, k, itemanz, costtyp; + int dh = 0; + char buf[4096]; + char * bufp = buf; + size_t size = sizeof(buf) - 1; + const char * params = sp->parameter; + + rnl(F); + centre(F, spell_name(sp, lang), true); + rnl(F); + rparagraph(F, LOC(lang, "nr_spell_description"), 0, 0, 0); + rparagraph(F, spell_info(sp, lang), 2, 0, 0); + + bytes = (int)strlcpy(bufp, LOC(lang, "nr_spell_type"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (size) { *bufp++ = ' '; --size; } + if (sp->sptyp & PRECOMBATSPELL) { + bytes = (int)strlcpy(bufp, LOC(lang, "sptype_precombat"), size); + } else if (sp->sptyp & COMBATSPELL) { + bytes = (int)strlcpy(bufp, LOC(lang, "sptype_combat"), size); + } else if (sp->sptyp & POSTCOMBATSPELL) { + bytes = (int)strlcpy(bufp, LOC(lang, "sptype_postcombat"), size); + } else { + bytes = (int)strlcpy(bufp, LOC(lang, "sptype_normal"), size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + *bufp = 0; + rparagraph(F, buf, 0, 0, 0); + + sprintf(buf, "%s %d", LOC(lang, "nr_spell_level"), sp->level); + rparagraph(F, buf, 0, 0, 0); + + sprintf(buf, "%s %d", LOC(lang, "nr_spell_rank"), sp->rank); + rparagraph(F, buf, 0, 0, 0); + + rparagraph(F, LOC(lang, "nr_spell_components"), 0, 0, 0); + for (k = 0; sp->components[k].type; ++k) { + const resource_type * rtype = sp->components[k].type; + itemanz = sp->components[k].amount; + costtyp = sp->components[k].cost; + if (itemanz > 0) { + size = sizeof(buf) - 1; + bufp = buf; + if (sp->sptyp & SPELLLEVEL) { + bytes = snprintf(bufp, size, " %d %s", itemanz, LOC(lang, resourcename(rtype, itemanz!=1))); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR ) { + bytes = snprintf(bufp, size, " * %s", LOC(lang, "nr_level")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } else { + if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR ) { + itemanz *= sp->level; + } + bytes = snprintf(bufp, size, "%d %s", itemanz, LOC(lang, resourcename(rtype, itemanz!=1))); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + *bufp = 0; + rparagraph(F, buf, 2, 2, '-'); + } + } + + size = sizeof(buf) - 1; + bufp = buf; + bytes = (int)strlcpy(buf, LOC(lang, "nr_spell_modifiers"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (sp->sptyp & FARCASTING) { + bytes = (int)strlcpy(bufp, " Fernzauber", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + dh = 1; + } + if (sp->sptyp & OCEANCASTABLE) { + if (dh == 1) { + bytes = (int)strlcpy(bufp, ",", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + bytes = (int)strlcpy(bufp, " Seezauber", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + dh = 1; + } + if (sp->sptyp & ONSHIPCAST) { + if (dh == 1){ + bytes = (int)strlcpy(bufp, ",", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + bytes = (int)strlcpy(bufp, " Schiffszauber", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + dh = 1; + } + if (sp->sptyp & NOTFAMILIARCAST) { + if (dh == 1) { + bytes = (int)strlcpy(bufp, ", k", size); + } else { + bytes = (int)strlcpy(bufp, " K", size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, "ann nicht vom Vertrauten gezaubert werden", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + dh = 1; + } + if (dh == 0) { + bytes = (int)strlcpy(bufp, " Keine", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + *bufp = 0; + rparagraph(F, buf, 0, 0, 0); + + rparagraph(F, LOC(lang, "nr_spell_syntax"), 0, 0, 0); + + bufp = buf; + size = sizeof(buf) - 1; + + if (sp->sptyp & ISCOMBATSPELL) { + bytes = (int)strlcpy(bufp, LOC(lang, keywords[K_COMBATSPELL]), size); + } else { + bytes = (int)strlcpy(bufp, LOC(lang, keywords[K_CAST]), size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + /* Reihenfolge beachten: Erst REGION, dann STUFE! */ + if (sp->sptyp & FARCASTING) { + bytes = snprintf(bufp, size, " [%s x y]", LOC(lang, parameters[P_REGION])); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (sp->sptyp & SPELLLEVEL) { + bytes = snprintf(bufp, size, " [%s n]", LOC(lang, parameters[P_LEVEL])); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + bytes = (int)snprintf(bufp, size, " \"%s\"", spell_name(sp, lang)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + while (params && *params) { + typedef struct starget { + param_t param; + int flag; + const char * vars; + } starget; + starget targets[] = { + { P_REGION, REGIONSPELL, NULL }, + { P_UNIT, UNITSPELL, "par_unit" }, + { P_SHIP, SHIPSPELL, "par_ship" }, + { P_BUILDING, BUILDINGSPELL, "par_building" }, + { 0, 0, NULL } + }; + starget * targetp; + char cp = *params++; + int i, maxparam = 0; + const char * locp; + const char * syntaxp = sp->syntax; + + if (cp=='u') { + targetp = targets+1; + locp = LOC(lang, targetp->vars); + bytes = (int)snprintf(bufp, size, " <%s>", locp); + if (*params=='+') { + ++params; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else if (cp=='s') { + targetp = targets+2; + locp = LOC(lang, targetp->vars); + bytes = (int)snprintf(bufp, size, " <%s>", locp); + if (*params=='+') { + ++params; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else if (cp=='r') { + bytes = (int)strlcpy(bufp, " ", size); + if (*params=='+') { + ++params; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " [ ...]", size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else if (cp=='b') { + targetp = targets+3; + locp = LOC(lang, targetp->vars); + bytes = (int)snprintf(bufp, size, " <%s>", locp); + if (*params=='+') { + ++params; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else if (cp=='k') { + if (*params=='c') { + /* skip over a potential id */ + ++params; + } + for (targetp=targets;targetp->flag;++targetp) { + if (sp->sptyp&targetp->flag) ++maxparam; + } + if (maxparam>1) { + bytes = (int)strlcpy(bufp, " (", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + i = 0; + for (targetp=targets;targetp->flag;++targetp) { + if (sp->sptyp&targetp->flag) { + if (i++!=0) { + bytes = (int)strlcpy(bufp, " |", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (targetp->param) { + locp = LOC(lang, targetp->vars); + bytes = (int)snprintf(bufp, size, " %s <%s>", parameters[targetp->param], locp); + if (*params=='+') { + ++params; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); + } + } else { + bytes = (int)snprintf(bufp, size, " %s", parameters[targetp->param]); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + if (maxparam>1) { + bytes = (int)strlcpy(bufp, " )", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } else if (cp=='i' || cp=='c') { + const char * cstr; + assert(syntaxp); + cstr = strchr(syntaxp, ':'); + if (!cstr) { + locp = LOC(lang, mkname("spellpar", syntaxp)); + } else { + char substr[32]; + strncpy(substr, syntaxp, cstr-syntaxp); + substr[cstr-syntaxp] = 0; + locp = LOC(lang, mkname("spellpar", substr)); + syntaxp = substr + 1; + } + bytes = (int)snprintf(bufp, size, " <%s>", locp); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + *bufp = 0; + rparagraph(F, buf, 2, 0, 0); + rnl(F); +} + +void +sparagraph(strlist ** SP, const char *s, int indent, char mark) +{ + + /* Die Liste SP wird mit dem String s aufgefuellt, mit indent und einer + * mark, falls angegeben. SP wurde also auf 0 gesetzt vor dem Aufruf. + * Vgl. spunit (). */ + + int i, j, width; + int firstline; + static char buf[REPORTWIDTH + 1]; + + width = REPORTWIDTH - indent; + firstline = 1; + + for (;;) { + i = 0; + + do { + j = i; + while (s[j] && s[j] != ' ') + j++; + if (j > width) { + + /* j zeigt auf das ende der aktuellen zeile, i zeigt auf den anfang der + * nächsten zeile. existiert ein wort am anfang der zeile, welches + * länger als eine zeile ist, muss dieses hier abgetrennt werden. */ + + if (i == 0) + i = width - 1; + break; + } + i = j + 1; + } + while (s[j]); + + for (j = 0; j != indent; j++) + buf[j] = ' '; + + if (firstline && mark) + buf[indent - 2] = mark; + + for (j = 0; j != i - 1; j++) + buf[indent + j] = s[j]; + buf[indent + j] = 0; + + addstrlist(SP, buf); + + if (s[i - 1] == 0) + break; + + s += i; + firstline = 0; + } +} + +int +hat_in_region(item_t it, region * r, faction * f) +{ + unit *u; + + for (u = r->units; u; u = u->next) { + if (u->faction == f && get_item(u, it) > 0) { + return 1; + } + } + return 0; +} + +static void +nr_curses(FILE *F, const faction *viewer, const void * obj, typ_t typ, int indent) +{ + attrib *a = NULL; + int self = 0; + region *r; + + /* Die Sichtbarkeit eines Zaubers und die Zaubermeldung sind bei + * Gebäuden und Schiffen je nach, ob man Besitzer ist, verschieden. + * Bei Einheiten sieht man Wirkungen auf eigene Einheiten immer. + * Spezialfälle (besonderes Talent, verursachender Magier usw. werde + * bei jedem curse gesondert behandelt. */ + if (typ == TYP_SHIP){ + ship * sh = (ship*)obj; + unit * owner = shipowner(sh); + a = sh->attribs; + r = sh->region; + if (owner) { + if (owner->faction == viewer){ + self = 2; + } else { /* steht eine person der Partei auf dem Schiff? */ + unit *u = NULL; + for (u = r->units; u; u = u->next) { + if (u->ship == sh) { + self = 1; + break; + } + } + } + } + } else if (typ == TYP_BUILDING) { + building * b = (building*)obj; + unit * owner; + a = b->attribs; + r = b->region; + if ((owner = building_owner(b)) != NULL){ + if (owner->faction == viewer){ + self = 2; + } else { /* steht eine Person der Partei in der Burg? */ + unit *u = NULL; + for (u = r->units; u; u = u->next) { + if (u->building == b) { + self = 1; + break; + } + } + } + } + } else if (typ == TYP_UNIT) { + unit *u = (unit *)obj; + a = u->attribs; + r = u->region; + if (u->faction == viewer){ + self = 2; + } + } else if (typ == TYP_REGION) { + r = (region *)obj; + a = r->attribs; + } else { + /* fehler */ + } + + for (;a;a=a->next) { + char buf[4096]; + + if (fval(a->type, ATF_CURSE)) { + curse *c = (curse *)a->data.v; + message * msg; + + if (c->type->cansee) { + self = c->type->cansee(viewer, obj, typ, c, self); + } + msg = msg_curse(c, obj, typ, self); + + if (msg) { + rnl(F); + nr_render(msg, viewer->locale, buf, sizeof(buf), viewer); + rparagraph(F, buf, indent, 2, 0); + msg_release(msg); + } + } else if (a->type==&at_effect && self) { + effect_data * data = (effect_data *)a->data.v; + if (data->value>0) { + sprintf(buf, "Auf der Einheit lieg%s %d Wirkung%s %s.", + (data->value==1 ? "t" : "en"), + data->value, + (data->value==1 ? "" : "en"), + LOC(default_locale, resourcename(data->type->itype->rtype, 0))); + rnl(F); + rparagraph(F, buf, indent, 2, 0); + } + } + } +} + +static void +rps_nowrap(FILE * F, const char *s) +{ + const char *x = s; + size_t indent = 0; + + while (*x++ == ' '); + indent = x - s - 1; + if (*(x - 1) && indent && *x == ' ') + indent += 2; + x = s; + while (*s) { + if (s == x) { + x = strchr(x + 1, ' '); + if (!x) + x = s + strlen(s); + } + rpc(F, *s++, 1); + } +} + +static void +nr_unit(FILE * F, const faction * f, const unit * u, int indent, int mode) +{ + attrib *a_otherfaction; + char marker; + int dh; + boolean isbattle = (boolean)(mode == see_battle); + char buf[8192]; + + if (fval(u->race, RCF_INVISIBLE)) return; + + { + rnl(F); + dh = bufunit(f, u, indent, mode, buf, sizeof(buf)); + } + + a_otherfaction = a_find(u->attribs, &at_otherfaction); + + if (u->faction == f) { + marker = '*'; + } else if ALLIED(u->faction, f) { + marker = 'o'; + } else if (a_otherfaction && f != u->faction && get_otherfaction(a_otherfaction) == f + && !fval(u, UFL_ANON_FACTION)) { + marker = '!'; + } else { + if (dh && !fval(u, UFL_ANON_FACTION)) { + marker = '+'; + } else { + marker = '-'; + } + } + rparagraph(F, buf, indent, 0, marker); + + if (!isbattle) { + nr_curses(F, f, u, TYP_UNIT, indent); + } +} + +static void +rp_messages(FILE * F, message_list * msgs, faction * viewer, int indent, boolean categorized) +{ + nrsection * section; + if (!msgs) return; + for (section = sections; section; section=section->next) { + int k = 0; + struct mlist * m = msgs->begin; + while (m) { + /* messagetype * mt = m->type; */ + if (!categorized || strcmp(nr_section(m->msg), section->name)==0) { + char lbuf[8192]; + + if (!k && categorized) { + const char * section_title; + char cat_identifier[24]; + + rnl(F); + sprintf(cat_identifier, "section_%s", section->name); + section_title = LOC(viewer->locale, cat_identifier); + centre(F, section_title, true); + rnl(F); + k = 1; + } + nr_render(m->msg, viewer->locale, lbuf, sizeof(lbuf), viewer); + rparagraph(F, lbuf, indent, 2, 0); + } + m = m->next; + } + if (!categorized) break; + } +} + +static void +rp_battles(FILE * F, faction * f) +{ + if (f->battles!=NULL) { + struct bmsg * bm = f->battles; + rnl(F); + centre(F, LOC(f->locale, "section_battle"), false); + rnl(F); + + while (bm) { + char buf[256]; + RENDER(f, buf, sizeof(buf), ("battle::header", "region", bm->r)); + rnl(F); + centre(F, buf, true); + rnl(F); + rp_messages(F, bm->msgs, f, 0, false); + bm = bm->next; + } + } +} + +static void +prices(FILE * F, const region * r, const faction * f) +{ + const luxury_type *sale=NULL; + struct demand * dmd; + message * m; + int bytes, n = 0; + char buf[4096], * bufp = buf; + size_t size = sizeof(buf) - 1; + + if (r->land==NULL || r->land->demands==NULL) return; + for (dmd=r->land->demands;dmd;dmd=dmd->next) { + if (dmd->value==0) sale = dmd->type; + else if (dmd->value > 0) n++; + } + assert(sale!=NULL); + + m = msg_message("nr_market_sale", "product price", + sale->itype->rtype, sale->price); + + bytes = (int)nr_render(m, f->locale, bufp, size, f); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + msg_release(m); + + if (n > 0) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_intro"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + for (dmd=r->land->demands;dmd;dmd=dmd->next) if(dmd->value > 0) { + m = msg_message("nr_market_price", "product price", + dmd->type->itype->rtype, dmd->value * dmd->type->price); + bytes = (int)nr_render(m, f->locale, bufp, size, f); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + msg_release(m); + n--; + if (n == 0) { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_end"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + else if (n == 1) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_final"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_next"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + } + /* Schreibe Paragraphen */ + *bufp = 0; + rparagraph(F, buf, 0, 0, 0); + +} + +boolean +see_border(const connection * b, const faction * f, const region * r) +{ + boolean cs = b->type->fvisible(b, f, r); + if (!cs) { + cs = b->type->rvisible(b, r); + if (!cs) { + const unit * us = r->units; + while (us && !cs) { + if (us->faction==f) { + cs = b->type->uvisible(b, us); + if (cs) break; + } + us=us->next; + } + } + } + return cs; +} + +static void +describe(FILE * F, const seen_region * sr, faction * f) +{ + const region * r = sr->r; + int n; + boolean dh; + direction_t d; + int trees; + int saplings; + attrib *a; + const char *tname; + struct edge { + struct edge * next; + char * name; + boolean transparent; + boolean block; + boolean exist[MAXDIRECTIONS]; + direction_t lastd; + } * edges = NULL, * e; + boolean see[MAXDIRECTIONS]; + char buf[8192]; + char * bufp = buf; + size_t size = sizeof(buf); + int bytes; + + for (d = 0; d != MAXDIRECTIONS; d++) { + /* Nachbarregionen, die gesehen werden, ermitteln */ + region *r2 = rconnect(r, d); + connection *b; + see[d] = true; + if (!r2) continue; + for (b=get_borders(r, r2);b;) { + struct edge * e = edges; + boolean transparent = b->type->transparent(b, f); + const char * name = b->type->name(b, r, f, GF_DETAILED|GF_ARTICLE); + + if (!transparent) see[d] = false; + if (!see_border(b, f, r)) { + b = b->next; + continue; + } + while (e && (e->transparent != transparent || strcmp(name,e->name))) e = e->next; + if (!e) { + e = calloc(sizeof(struct edge), 1); + e->name = strdup(name); + e->transparent = transparent; + e->next = edges; + edges = e; + } + e->lastd=d; + e->exist[d] = true; + b = b->next; + } + } + + bytes = (int)f_regionid(r, f, bufp, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (sr->mode==see_travel) { + bytes = (int)strlcpy(bufp, " (durchgereist)", size); + } + else if (sr->mode==see_neighbour) { + bytes = (int)strlcpy(bufp, " (benachbart)", size); + } + else if (sr->mode==see_lighthouse) { + bytes = (int)strlcpy(bufp, " (vom Turm erblickt)", size); + } else { + bytes = 0; + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + /* Terrain */ + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + tname = terrain_name(r); + bytes = (int)strlcpy(bufp, LOC(f->locale, tname), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + /* Trees */ + trees = rtrees(r,2); + saplings = rtrees(r,1); + if (production(r)) { + if (trees > 0 || saplings > 0) { + bytes = snprintf(bufp, size, ", %d/%d ", trees, saplings); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (fval(r, RF_MALLORN)) { + if (trees == 1) { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_mallorntree"), size); + } else { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_mallorntree_p"), size); + } + } + else if (trees == 1) { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_tree"), size); + } else { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_tree_p"), size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + + /* iron & stone */ + if (sr->mode==see_unit && f != (faction *) NULL) { + resource_report result[MAX_RAWMATERIALS]; + int n, numresults = report_resources(sr, result, MAX_RAWMATERIALS, f); + + for (n=0;n=0 && result[n].level>=0) { + bytes = snprintf(bufp, size, ", %d %s/%d", result[n].number, + LOC(f->locale, result[n].name), result[n].level); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + } + + /* peasants & silver */ + if (rpeasants(r)) { + int n = rpeasants(r); + bytes = snprintf(bufp, size, ", %d", n); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (r->land->ownership) { + const char * str = locale_string(f->locale, mkname("morale", itoa10(r->land->morale))); + bytes = snprintf(bufp, size, " %s", str); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (fval(r, RF_ORCIFIED)) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + bytes = (int)strlcpy(bufp, LOC(f->locale, n==1?"rc_orc":"rc_orc_p"), size); + } else { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, n==1?"peasant":"peasant_p"), size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (is_mourning(r, turn+1)) { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_mourning"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + if (rmoney(r) && sr->mode>=see_travel) { + bytes = snprintf(bufp, size, ", %d ", rmoney(r)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, resourcename(oldresourcetype[R_SILVER], rmoney(r)!=1)), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + /* Pferde */ + + if (rhorses(r)) { + bytes = snprintf(bufp, size, ", %d ", rhorses(r)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, resourcename(oldresourcetype[R_HORSE], (rhorses(r)>1)?GR_PLURAL:0)), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + + if (r->display && r->display[0]) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, r->display, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + n = r->display[strlen(r->display) - 1]; + if (n != '!' && n != '?' && n != '.') { + bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + + if (rule_region_owners()) { + const faction * owner = region_get_owner(r); + if (owner!=NULL) { + bytes = snprintf(bufp, size, " Die Region ist im Besitz von %s.", + factionname(owner)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + a = a_find(r->attribs, &at_overrideroads); + + if (a) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, (char *)a->data.v, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else { + int nrd = 0; + + /* Nachbarregionen, die gesehen werden, ermitteln */ + for (d = 0; d != MAXDIRECTIONS; d++) { + if (see[d] && rconnect(r, d)) nrd++; + } + /* list directions */ + + dh = false; + for (d = 0; d != MAXDIRECTIONS; d++) if (see[d]) { + region * r2 = rconnect(r, d); + if(!r2) continue; + nrd--; + if (dh) { + char regname[4096]; + if (nrd == 0) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nb_final"), size); + } else { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nb_next"), size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, directions[d]), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + f_regionid(r2, f, regname, sizeof(regname)); + bytes = snprintf(bufp, size, trailinto(r2, f->locale), regname); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + else { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + MSG(("nr_vicinitystart", "dir region", d, r2), bufp, size, f->locale, f); + bufp += strlen(bufp); + dh = true; + } + } + /* Spezielle Richtungen */ + for (a = a_find(r->attribs, &at_direction);a && a->type==&at_direction;a=a->next) { + spec_direction * d = (spec_direction *)(a->data.v); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, d->desc), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " (\"", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, d->keyword), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, "\")", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + dh = 1; + } + } + rnl(F); + *bufp = 0; + rparagraph(F, buf, 0, 0, 0); + + if (sr->mode==see_unit && is_astral(r) && + !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) { + /* Sonderbehandlung Teleport-Ebene */ + region_list *rl = astralregions(r, inhabitable); + region_list *rl2; + + if (rl) { + bufp = buf; + size = sizeof(buf) - 1; + bytes = (int)strlcpy(bufp, "Schemen der Regionen ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + rl2 = rl; + while (rl2) { + bytes = (int)f_regionid(rl2->data, f, bufp, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + rl2 = rl2->next; + if (rl2) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + bytes = (int)strlcpy(bufp, " sind erkennbar.", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + free_regionlist(rl); + /* Schreibe Paragraphen */ + rnl(F); + *bufp = 0; + rparagraph(F, buf, 0, 0, 0); + } + } + + n = 0; + + /* Wirkungen permanenter Sprüche */ + nr_curses(F, f, r, TYP_REGION,0); + + /* Produktionsreduktion */ + a = a_find(r->attribs, &at_reduceproduction); + if (a) { + const char * str = LOC(f->locale, "nr_reduced_production"); + rparagraph(F, str, 0, 0, 0); + } + + if (edges) rnl(F); + for (e=edges;e;e=e->next) { + boolean first = true; + bufp = buf; + size = sizeof(buf) - 1; + for (d=0;d!=MAXDIRECTIONS;++d) { + if (!e->exist[d]) continue; + if (first) bytes = (int)strlcpy(bufp, "Im ", size); + else if (e->lastd==d) bytes = (int)strlcpy(bufp, " und im ", size); + else bytes = (int)strlcpy(bufp, ", im ", size ); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, directions[d]), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + first = false; + } + if (!e->transparent) bytes = (int)strlcpy(bufp, " versperrt ", size); + else bytes = (int)strlcpy(bufp, " befindet sich ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, e->name, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (!e->transparent) bytes = (int)strlcpy(bufp, " die Sicht.", size); + else bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + *bufp = 0; + rparagraph(F, buf, 0, 0, 0); + } + if (edges) { + while (edges) { + e = edges->next; + free(edges->name); + free(edges); + edges = e; + } + } +} + +static void +statistics(FILE * F, const region * r, const faction * f) +{ + const unit *u; + int number = 0, p = rpeasants(r); + message * m; + item *itm, *items = NULL; + char buf[4096]; + + /* count */ + for (u = r->units; u; u = u->next) { + if (u->faction == f && !fval(u->race, RCF_INVISIBLE)) { + for (itm=u->items;itm;itm=itm->next) { + i_change(&items, itm->type, itm->number); + } + number += u->number; + } + } + /* print */ + rnl(F); + m = msg_message("nr_stat_header", "region", r); + nr_render(m, f->locale, buf, sizeof(buf), f); + msg_release(m); + rparagraph(F, buf, 0, 0, 0); + rnl(F); + + /* Region */ + if (skill_enabled[SK_ENTERTAINMENT] && fval(r->terrain, LAND_REGION) && rmoney(r)) { + m = msg_message("nr_stat_maxentertainment", "max", entertainmoney(r)); + nr_render(m, f->locale, buf, sizeof(buf), f); + rparagraph(F, buf, 2, 2, 0); + msg_release(m); + } + if (production(r) && (!fval(r->terrain, SEA_REGION) || f->race == new_race[RC_AQUARIAN])) { + if (markets_module()) { /* hack */ + m = msg_message("nr_stat_salary_new", "max", wage(r, NULL, NULL, turn+1)); + } else { + m = msg_message("nr_stat_salary", "max", wage(r, f, f->race, turn+1)); + } + nr_render(m, f->locale, buf, sizeof(buf), f); + rparagraph(F, buf, 2, 2, 0); + msg_release(m); + } + + if (p) { + m = msg_message("nr_stat_recruits", "max", p / RECRUITFRACTION); + nr_render(m, f->locale, buf, sizeof(buf), f); + rparagraph(F, buf, 2, 2, 0); + msg_release(m); + + if (!markets_module()) { + if (buildingtype_exists(r, bt_find("caravan"), true)) { + m = msg_message("nr_stat_luxuries", "max", + (p * 2) / TRADE_FRACTION); + } else { + m = msg_message("nr_stat_luxuries", "max", + p / TRADE_FRACTION); + } + nr_render(m, f->locale, buf, sizeof(buf), f); + rparagraph(F, buf, 2, 2, 0); + msg_release(m); + } + + if (r->land->ownership) { + m = msg_message("nr_stat_morale", "morale", r->land->morale); + nr_render(m, f->locale, buf, sizeof(buf), f); + rparagraph(F, buf, 2, 2, 0); + msg_release(m); + } + + + } + /* info about units */ + + m = msg_message("nr_stat_people", "max", number); + nr_render(m, f->locale, buf, sizeof(buf), f); + rparagraph(F, buf, 2, 2, 0); + msg_release(m); + + for (itm = items; itm; itm=itm->next) { + sprintf(buf, "%s: %d", + LOC(f->locale, resourcename(itm->type->rtype, GR_PLURAL)), + itm->number); + rparagraph(F, buf, 2, 2, 0); + } + while (items) i_free(i_remove(&items, items)); +} + +static void +durchreisende(FILE * F, const region * r, const faction * f) +{ + if (fval(r, RF_TRAVELUNIT)) { + attrib *abegin = a_find(r->attribs, &at_travelunit), *a; + int counter = 0, maxtravel = 0; + char buf[8192]; + char * bufp = buf; + int bytes; + size_t size = sizeof(buf) - 1; + + /* How many are we listing? For grammar. */ + for (a = abegin; a && a->type==&at_travelunit; a = a->next) { + unit * u = (unit*)a->data.v; + + if (r!=u->region && (u->ship==NULL || fval(u, UFL_OWNER))) { + if (cansee_durchgezogen(f, r, u, 0)) { + ++maxtravel; + } + } + } + + if (maxtravel==0) { + return; + } + + /* Auflisten. */ + rnl(F); + + for (a = abegin; a && a->type==&at_travelunit; a = a->next) { + unit * u = (unit*)a->data.v; + + if (r!=u->region && (u->ship==NULL || fval(u, UFL_OWNER))) { + if (cansee_durchgezogen(f, r, u, 0)) { + ++counter; + if (u->ship != NULL) { + if (counter == 1) { + bytes = (int)strlcpy(bufp, "Die ", size); + } else { + bytes = (int)strlcpy(bufp, "die ", size); + } + if (wrptr(&bufp, &size, bytes)!=0) { + WARN_STATIC_BUFFER(); + break; + } + bytes = (int)strlcpy(bufp, shipname(u->ship), size); + } else { + bytes = (int)strlcpy(bufp, unitname(u), size); + } + if (wrptr(&bufp, &size, bytes)!=0) { + WARN_STATIC_BUFFER(); + break; + } + + if (counter + 1 < maxtravel) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) { + WARN_STATIC_BUFFER(); + break; + } + } else if (counter + 1 == maxtravel) { + bytes = (int)strlcpy(bufp, LOC(f->locale, "list_and"), size); + if (wrptr(&bufp, &size, bytes)!=0) { + WARN_STATIC_BUFFER(); + break; + } + } + } + } + } + /* TODO: finish localization */ + if (maxtravel == 1) { + bytes = (int)strlcpy(bufp, " hat die Region durchquert.", size); + } else { + bytes = (int)strlcpy(bufp, " haben die Region durchquert.", size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + *bufp = 0; + rparagraph(F, buf, 0, 0, 0); + } +} + +static int +buildingmaintenance(const building * b, const resource_type * rtype) +{ + const building_type * bt = b->type; + int c, cost=0; + static boolean init = false; + static const curse_type * nocost_ct; + if (!init) { init = true; nocost_ct = ct_find("nocostbuilding"); } + if (curse_active(get_curse(b->attribs, nocost_ct))) { + return 0; + } + for (c=0;bt->maintenance && bt->maintenance[c].number;++c) { + const maintenance * m = bt->maintenance + c; + if (m->rtype==rtype) { + if (fval(m, MTF_VARIABLE)) + cost += (b->size * m->number); + else + cost += m->number; + } + } + return cost; +} + +static int +report_template(const char * filename, report_context * ctx, const char * charset) +{ + faction * f = ctx->f; + region *r; + FILE * F = fopen(filename, "wt"); + seen_region * sr = NULL; + char buf[8192], * bufp; + size_t size; + int bytes; + + int enc = get_encoding_by_name(charset); + + if (F==NULL) { + perror(filename); + return -1; + } + + if (enc==ENCODING_UTF8) { + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + fwrite(utf8_bom, 1, 3, F); + } + + rps_nowrap(F, ""); + rnl(F); + rps_nowrap(F, LOC(f->locale, "nr_template")); + rnl(F); + rps_nowrap(F, ""); + rnl(F); + + sprintf(buf, "%s %s \"%s\"", LOC(f->locale, "ERESSEA"), factionid(f), LOC(f->locale, "enterpasswd")); + rps_nowrap(F, buf); + rnl(F); + + rps_nowrap(F, ""); + rnl(F); + sprintf(buf, "; ECHECK -l -w4 -r%d -v%s", f->race->recruitcost, ECHECK_VERSION); + /* -v3.4: ECheck Version 3.4.x */ + rps_nowrap(F, buf); + rnl(F); + + for (r=ctx->first; sr==NULL && r!=ctx->last; r=r->next) { + sr = find_seen(ctx->seen, r); + } + + for (;sr!=NULL;sr=sr->next) { + region * r = sr->r; + unit *u; + int dh = 0; + + if (sr->modeunits; u; u = u->next) { + if (u->faction == f && !fval(u->race, RCF_INVISIBLE)) { + order * ord; + if (!dh) { + plane * pl = getplane(r); + int nx = r->x, ny = r->y; + + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl, r); + rps_nowrap(F, ""); + rnl(F); + if (pl && pl->id != 0) { + sprintf(buf, "%s %d,%d,%d ; %s", LOC(f->locale, parameters[P_REGION]), + nx, ny, pl->id, rname(r, f->locale)); + } else { + sprintf(buf, "%s %d,%d ; %s", LOC(f->locale, parameters[P_REGION]), + nx, ny, rname(r, f->locale)); + } + rps_nowrap(F, buf); + rnl(F); + sprintf(buf,"; ECheck Lohn %d", wage(r, f, f->race, turn+1)); + rps_nowrap(F, buf); + rnl(F); + rps_nowrap(F, ""); + rnl(F); + } + dh = 1; + + bufp = buf; + size = sizeof(buf) - 1; + bytes = snprintf(bufp, size, "%s %s; %s [%d,%d$", + LOC(u->faction->locale, parameters[P_UNIT]), + unitid(u), u->name, u->number, get_money(u)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (u->building != NULL && fval(u, UFL_OWNER)) { + building * b = u->building; + int cost = buildingmaintenance(b, r_silver); + + if (cost > 0) { + bytes = (int)strlcpy(bufp, ",U", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, itoa10(cost), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } else if (u->ship) { + if (fval(u, UFL_OWNER)) { + bytes = (int)strlcpy(bufp, ",S", size); + } else { + bytes = (int)strlcpy(bufp, ",s", size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, shipid(u->ship), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (lifestyle(u) == 0) { + bytes = (int)strlcpy(bufp, ",I", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + bytes = (int)strlcpy(bufp, "]", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + *bufp = 0; + rps_nowrap(F, buf); + rnl(F); + + for (ord = u->old_orders; ord; ord = ord->next) { + /* this new order will replace the old defaults */ + strcpy(buf, " "); + write_order(ord, buf+2, sizeof(buf)-2); + rps_nowrap(F, buf); + rnl(F); + } + for (ord = u->orders; ord; ord = ord->next) { + if (u->old_orders && is_repeated(ord)) continue; /* unit has defaults */ + if (is_persistent(ord)) { + strcpy(buf, " "); + write_order(ord, buf+2, sizeof(buf)-2); + rps_nowrap(F, buf); + rnl(F); + } + } + + /* If the lastorder begins with an @ it should have + * been printed in the loop before. */ + } + } + } + rps_nowrap(F, ""); + rnl(F); + strcpy(buf, LOC(f->locale, parameters[P_NEXT])); + rps_nowrap(F, buf); + rnl(F); + fclose(F); + return 0; +} + +static void +show_allies(const faction * f, const ally * allies, char * buf, size_t size) +{ + int allierte = 0; + int i=0, h, hh = 0; + int bytes, dh = 0; + const ally * sf; + char * bufp = buf; /* buf already contains data */ + + --size; /* leave room for a null-terminator */ + + for (sf = allies; sf; sf = sf->next) { + int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); + if (mode > 0) ++allierte; + } + + for (sf = allies; sf; sf = sf->next) { + int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); + if (mode <= 0) continue; + i++; + if (dh) { + if (i == allierte) { + bytes = (int)strlcpy(bufp, LOC(f->locale, "list_and"), size); + } else { + bytes = (int)strlcpy(bufp, ", ", size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + dh = 1; + hh = 0; + bytes = (int)strlcpy(bufp, factionname(sf->faction), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " (", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if ((mode & HELP_ALL) == HELP_ALL) { + bytes = (int)strlcpy(bufp, "Alles", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else { + for (h = 1; h < HELP_ALL; h *= 2) { + int p = MAXPARAMS; + if ((mode & h) == h) { + switch (h) { + case HELP_TRAVEL: + p = P_TRAVEL; + break; + case HELP_MONEY: + p = P_MONEY; + break; + case HELP_FIGHT: + p = P_FIGHT; + break; + case HELP_GIVE: + p = P_GIVE; + break; + case HELP_GUARD: + p = P_GUARD; + break; + case HELP_FSTEALTH: + p = P_FACTIONSTEALTH; + break; + } + } + if (p!=MAXPARAMS) { + if (hh) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + bytes = (int)strlcpy(bufp, parameters[p], size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + hh = 1; + } + } + } + bytes = (int)strlcpy(bufp, ")", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + *bufp = 0; +} + +static void +allies(FILE * F, const faction * f) +{ + const group * g = f->groups; + char buf[16384]; + + if (f->allies) { + int bytes; + size_t size = sizeof(buf); + if (!f->allies->next) { + bytes = (int)strlcpy(buf, "Wir helfen der Partei ", size); + } else { + bytes = (int)strlcpy(buf, "Wir helfen den Parteien ", size); + } + size -= bytes; + show_allies(f, f->allies, buf + bytes, size); + rparagraph(F, buf, 0, 0, 0); + rnl(F); + } + + while (g) { + if (g->allies) { + int bytes; + size_t size = sizeof(buf); + if (!g->allies->next) { + bytes = snprintf(buf, size, "%s hilft der Partei ", g->name); + } else { + bytes = snprintf(buf, size, "%s hilft den Parteien ", g->name); + } + size -= bytes; + show_allies(f, g->allies, buf + bytes, size); + rparagraph(F, buf, 0, 0, 0); + rnl(F); + } + g = g->next; + } +} + +static void +guards(FILE * F, const region * r, const faction * see) +{ + /* die Partei see sieht dies; wegen + * "unbekannte Partei", wenn man es selbst ist... */ + + faction* guardians[512]; + + int nextguard = 0; + + unit *u; + int i; + + boolean tarned = false; + /* Bewachung */ + + for (u = r->units; u; u = u->next) { + if (is_guard(u, GUARD_ALL)!=0) { + faction *f = u->faction; + faction *fv = visible_faction(see, u); + + if(fv != f && see != fv) { + f = fv; + } + + if (f != see && fval(u, UFL_ANON_FACTION)) { + tarned=true; + } else { + for (i=0;i!=nextguard;++i) if (guardians[i]==f) break; + if (i==nextguard) { + guardians[nextguard++] = f; + } + } + } + } + + if (nextguard || tarned) { + char buf[8192]; + char * bufp = buf; + size_t size = sizeof(buf) - 1; + int bytes; + + bytes = (int)strlcpy(bufp, "Die Region wird von ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + for (i = 0; i!=nextguard+(tarned?1:0); ++i) { + if (i!=0) { + if (i == nextguard-(tarned?0:1)) { + bytes = (int)strlcpy(bufp, LOC(see->locale, "list_and"), size); + } else { + bytes = (int)strlcpy(bufp, ", ", size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (ilocale, "nr_addresses"), false); + rnl(F); + + while (flist!=NULL) { + const faction * f = flist->data; + if (!is_monsters(f)) { + char buf[8192]; + char label = '-'; + + sprintf(buf, "%s: %s; %s", factionname(f), f->email, f->banner?f->banner:""); + if (uf==f) label = '*'; + else if (ALLIED(uf, f)) label = 'o'; + else if (alliedfaction(NULL, uf, f, HELP_ALL)) label = '+'; + rparagraph(F, buf, 4, 0, label); + + } + flist = flist->next; + } + rnl(F); + rpline(F); +} + +static void +nr_ship(FILE * F, const seen_region * sr, const ship * sh, const faction * f, const unit * captain) +{ + const region * r = sr->r; + char buffer[8192], * bufp = buffer; + size_t size = sizeof(buffer) - 1; + int bytes; + char ch; + + rnl(F); + + if (captain && captain->faction == f) { + int n = 0, p = 0; + getshipweight(sh, &n, &p); + n = (n+99) / 100; /* 1 Silber = 1 GE */ + + bytes = snprintf(bufp, size, "%s, %s, (%d/%d)", shipname(sh), + LOC(f->locale, sh->type->name[0]), n, shipcapacity(sh) / 100); + } else { + bytes = snprintf(bufp, size, "%s, %s", shipname(sh), LOC(f->locale, sh->type->name[0])); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + assert(sh->type->construction->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (sh->size!=sh->type->construction->maxsize) { + bytes = snprintf(bufp, size, ", %s (%d/%d)", + LOC(f->locale, "nr_undercons"), sh->size, + sh->type->construction->maxsize); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (sh->damage) { + int percent = (sh->damage*100+DAMAGE_SCALE-1)/(sh->size*DAMAGE_SCALE); + bytes = snprintf(bufp, size, ", %d%% %s", percent, LOC(f->locale, "nr_damaged")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (!fval(r->terrain, SEA_REGION)) { + if (sh->coast != NODIRECTION) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, coasts[sh->coast]), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + ch = 0; + if (sh->display && sh->display[0]) { + bytes = (int)strlcpy(bufp, "; ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, sh->display, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + ch = sh->display[strlen(sh->display) - 1]; + } + if (ch != '!' && ch != '?' && ch != '.') { + bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + *bufp = 0; + rparagraph(F, buffer, 2, 0, 0); + + nr_curses(F, f, sh, TYP_SHIP, 4); +} + +static void +nr_building(FILE *F, const seen_region * sr, const building * b, const faction * f) +{ + int i, bytes; + const char * name, * bname, * billusion = NULL; + const struct locale * lang = NULL; + char buffer[8192], * bufp = buffer; + size_t size = sizeof(buffer) - 1; + + rnl(F); + + if (f) lang = f->locale; + + bytes = snprintf(bufp, size, "%s, %s %d, ", buildingname(b), LOC(f->locale, "nr_size"), b->size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + report_building(b, &bname, &billusion); + name = LOC(lang, billusion?billusion:bname); + bytes = (int)strlcpy(bufp, name, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (billusion) { + unit * owner = building_owner(b); + if (owner && owner->faction==f) { + /* illusion. report real type */ + name = LOC(lang, bname); + bytes = snprintf(bufp, size, " (%s)", name); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + + if (b->size < b->type->maxsize) { + bytes = (int)strlcpy(bufp, " (im Bau)", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + if (b->besieged > 0 && sr->mode>=see_lighthouse) { + bytes = (int)strlcpy(bufp, ", belagert von ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, itoa10(b->besieged), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " Personen ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (b->besieged >= b->size * SIEGEFACTOR) { + bytes = (int)strlcpy(bufp, "(abgeschnitten)", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + i = 0; + if (b->display && b->display[0]) { + bytes = (int)strlcpy(bufp, "; ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, b->display, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + i = b->display[strlen(b->display) - 1]; + } + +#ifdef WDW_PYRAMID + + if (i != '!' && i != '?' && i != '.') { + scat(", "); + } + + if (b->type == bt_find("pyramid")) { + unit * owner = building_owner(b); + scat("Größenstufe "); + icat(wdw_pyramid_level(b)); + scat("."); + + if (owner && owner->faction==f) { + const construction *ctype = b->type->construction; + int completed = b->size; + int c; + + scat(" Baukosten pro Größenpunkt: "); + + while(ctype->improvement != NULL && + ctype->improvement != ctype && + ctype->maxsize > 0 && + ctype->maxsize <= completed) + { + completed -= ctype->maxsize; + ctype = ctype->improvement; + } + + assert(ctype->materials != NULL); + + for (c=0;ctype->materials[c].number;c++) { + const resource_type * rtype = ctype->materials[c].rtype; + int number = ctype->materials[c].number; + + if(c > 0) { + scat(", "); + } + icat(number); + scat(" "); + scat(locale_string(lang, resourcename(rtype, number!=1?GR_PLURAL:0))); + } + + scat("."); + + scat(" Erforderlicher Talentwert: "); + icat(b->type->construction->minskill); + scat("."); + } + } + +#else + + if (i != '!' && i != '?' && i != '.') { + bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + +#endif + *bufp = 0; + rparagraph(F, buffer, 2, 0, 0); + + if (sr->modelocale, bufp, size, f); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + msg_release(m); + + rparagraph(F, buf, 0, 0, 0); +} + +int +report_plaintext(const char * filename, report_context * ctx, const char * charset) +{ + int flag = 0; + char ch; + int anyunits, no_units, no_people; + const struct region *r; + faction * f = ctx->f; + unit *u; + char pzTime[64]; + attrib *a; + message * m; + unsigned char op; + int bytes, ix = want(O_STATISTICS); + int wants_stats = (f->options & ix); + FILE * F = fopen(filename, "wt"); + seen_region * sr = NULL; + char buf[8192]; + char * bufp; + int enc = get_encoding_by_name(charset); + size_t size; + + /* static variables can cope with writing for different turns */ + static int thisseason = -1; + static int nextseason = -1; + static int gamecookie = -1; + if (gamecookie!=global.cookie) { + gamedate date; + get_gamedate(turn+1, &date); + thisseason = date.season; + get_gamedate(turn+2, &date); + nextseason = date.season; + gamecookie = global.cookie; + } + + if (F==NULL) { + perror(filename); + return -1; + } + if (enc==ENCODING_UTF8) { + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + fwrite(utf8_bom, 1, 3, F); + } + + strftime(pzTime, 64, "%A, %d. %B %Y, %H:%M", localtime(&ctx->report_time)); + m = msg_message("nr_header_date", "game date", global.gamename, pzTime); + nr_render(m, f->locale, buf, sizeof(buf), f); + msg_release(m); + centre(F, buf, true); + + centre(F, gamedate_season(f->locale), true); + rnl(F); + sprintf(buf, "%s, %s/%s (%s)", factionname(f), + LOC(f->locale, rc_name(f->race, 1)), + LOC(f->locale, mkname("school", magic_school[f->magiegebiet])), + f->email); + centre(F, buf, true); + if (f_get_alliance(f)) { + centre(F, alliancename(f->alliance), true); + } + + if (f->age <= 2) { + const char * s; + if (f->age <= 1) { + ADDMSG(&f->msgs, msg_message("changepasswd", + "value", f->passw)); + } + RENDER(f, buf, sizeof(buf), ("newbie_password", "password", f->passw)); + rnl(F); + centre(F, buf, true); + s = locale_getstring(f->locale, "newbie_info_1"); + if (s) { + rnl(F); + centre(F, s, true); + } + s = locale_getstring(f->locale, "newbie_info_2"); + if (s) { + rnl(F); + centre(F, s, true); + } + if ((f->options & want(O_COMPUTER)) == 0) { + f->options |= want(O_COMPUTER); + s = locale_getstring(f->locale, "newbie_info_3"); + if (s) { + rnl(F); + centre(F, s, true); + } + } + } + rnl(F); +#if SCORE_MODULE + if (f->options & want(O_SCORE) && f->age > DISPLAYSCORE) { + RENDER(f, buf, sizeof(buf), ("nr_score", "score average", f->score, average_score_of_age(f->age, f->age / 24 + 1))); + centre(F, buf, true); + } +#endif +#ifdef COUNT_AGAIN + no_units = 0; + no_people = 0; + for (u=f->units;u;u=u->nextF) { + if (playerrace(u->race)) { + ++no_people; + no_units += u->number; + assert(f==u->faction); + } + } + if (no_units!=f->no_units) { + f->no_units = no_units; + } + if (no_people!=f->num_people) { + f->num_people = no_people; + } +#else + no_units = f->no_units; + no_people = f->num_people; +#endif + m = msg_message("nr_population", "population units", no_people, no_units); + nr_render(m, f->locale, buf, sizeof(buf), f); + msg_release(m); + centre(F, buf, true); + if (f->race == new_race[RC_HUMAN]) { + int maxmig = count_maxmigrants(f); + if (maxmig>0) { + m = msg_message("nr_migrants", "units maxunits", count_migrants(f), maxmig); + nr_render(m, f->locale, buf, sizeof(buf), f); + msg_release(m); + centre(F, buf, true); + } + } + if (f_get_alliance(f)) { + m = msg_message("nr_alliance", "leader name id age", alliance_get_leader(f->alliance), f->alliance->name, f->alliance->id, turn-f->alliance_joindate); + nr_render(m, f->locale, buf, sizeof(buf), f); + msg_release(m); + centre(F, buf, true); + } + { + int maxh = maxheroes(f); + if (maxh) { + message * msg = msg_message("nr_heroes", "units maxunits", countheroes(f), maxh); + nr_render(msg, f->locale, buf, sizeof(buf), f); + msg_release(msg); + centre(F, buf, true); + } + } + + if (f->items!=NULL) { + message * msg = msg_message("nr_claims", "items", f->items); + nr_render(msg, f->locale, buf, sizeof(buf), f); + msg_release(msg); + rnl(F); + centre(F, buf, true); + } + + /* Insekten-Winter-Warnung */ + if (f->race == new_race[RC_INSECT]) { + if (thisseason == 0) { + centre(F, LOC(f->locale, "nr_insectwinter"), true); + rnl(F); + } else { + if (nextseason == 0) { + centre(F, LOC(f->locale, "nr_insectfall"), true); + rnl(F); + } + } + } + + bufp = buf; + size = sizeof(buf) - 1; + bytes = snprintf(buf, size,"%s:", LOC(f->locale, "nr_options")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + for (op = 0; op != MAXOPTIONS; op++) { + if (f->options & want(op) && options[op]) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, options[op]), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + flag++; + } + } + if (flag > 0) { + rnl(F); + *bufp = 0; + centre(F, buf, true); + } + + rp_messages(F, f->msgs, f, 0, true); + rp_battles(F, f); + a = a_find(f->attribs, &at_reportspell); + if (a) { + rnl(F); + centre(F, LOC(f->locale, "section_newspells"), true); + while (a && a->type==&at_reportspell) { + spell *sp = (spell *)a->data.v; + nr_spell(F, sp, f->locale); + a = a->next; + } + } + + ch = 0; + for (a=a_find(f->attribs, &at_showitem);a && a->type==&at_showitem;a=a->next) { + const potion_type * ptype = resource2potion(((const item_type*)a->data.v)->rtype); + const char * description = NULL; + if (ptype!=NULL) { + const char * pname = resourcename(ptype->itype->rtype, 0); + + if (ch==0) { + rnl(F); + centre(F, LOC(f->locale, "section_newpotions"), true); + ch = 1; + } + + rnl(F); + centre(F, LOC(f->locale, pname), true); + snprintf(buf, sizeof(buf), "%s %d", LOC(f->locale, "nr_level"), ptype->level); + centre(F, buf, true); + rnl(F); + + bufp = buf; + size = sizeof(buf) - 1; + bytes = snprintf(bufp, size, "%s: ", LOC(f->locale, "nr_herbsrequired")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (ptype->itype->construction) { + requirement * m = ptype->itype->construction->materials; + while (m->number) { + bytes = (int)strlcpy(bufp, LOC(f->locale, resourcename(m->rtype, 0)), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + ++m; + if (m->number) + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + *bufp = 0; + centre(F, buf, true); + rnl(F); + if (description==NULL) { + const char * potiontext = mkname("potion", pname); + description = LOC(f->locale, potiontext); + } + centre(F, description, true); + } + } + rnl(F); + centre(F, LOC(f->locale, "nr_alliances"), false); + rnl(F); + + allies(F, f); + + rpline(F); + + anyunits = 0; + + for (r=ctx->first;sr==NULL && r!=ctx->last;r=r->next) { + sr = find_seen(ctx->seen, r); + } + for (;sr!=NULL;sr=sr->next) { + region * r = sr->r; + int stealthmod = stealth_modifier(sr->mode); + building * b = r->buildings; + ship * sh = r->ships; + + if (sr->modemode==see_unit) { + anyunits = 1; + describe(F, sr, f); + if (markets_module() && r->land) { + const item_type * lux = r_luxury(r); + const item_type * herb = r->land->herbtype; + message * m = 0; + if (herb && lux) { + m = msg_message("nr_market_info_p", "p1 p2", + lux?lux->rtype:0, herb?herb->rtype:0); + } else if (lux || herb) { + m = msg_message("nr_market_info_s", "p1", + lux?lux->rtype:herb->rtype); + } + if (m) { + rnl(F); + nr_paragraph(F, m, f); + } + // + } else { + if (!fval(r->terrain, SEA_REGION) && rpeasants(r)/TRADE_FRACTION > 0) { + rnl(F); + prices(F, r, f); + } + } + guards(F, r, f); + durchreisende(F, r, f); + } + else { + if (sr->mode==see_far) { + describe(F, sr, f); + guards(F, r, f); + durchreisende(F, r, f); + } + else if (sr->mode==see_lighthouse) { + describe(F, sr, f); + durchreisende(F, r, f); + } else { + describe(F, sr, f); + durchreisende(F, r, f); + } + } + /* Statistik */ + + if (wants_stats && sr->mode==see_unit) + statistics(F, r, f); + + /* Nachrichten an REGION in der Region */ + + if (sr->mode==see_unit || sr->mode==see_travel) { + message_list * mlist = r_getmessages(r, f); + rp_messages(F, r->msgs, f, 0, true); + if (mlist) rp_messages(F, mlist, f, 0, true); + } + + /* report all units. they are pre-sorted in an efficient manner */ + u = r->units; + while (b) { + while (b && (!u || u->building!=b)) { + nr_building(F, sr, b, f); + b = b->next; + } + if (b) { + nr_building(F, sr, b, f); + while (u && u->building==b) { + nr_unit(F, f, u, 6, sr->mode); + u = u->next; + } + b = b->next; + } + } + while (u && !u->ship) { + if (stealthmod>INT_MIN) { + if (u->faction == f || cansee(f, r, u, stealthmod)) { + nr_unit(F, f, u, 4, sr->mode); + } + } + assert(!u->building); + u = u->next; + } + while (sh) { + while (sh && (!u || u->ship!=sh)) { + nr_ship(F, sr, sh, f, NULL); + sh = sh->next; + } + if (sh) { + nr_ship(F, sr, sh, f, u); + while (u && u->ship==sh) { + nr_unit(F, f, u, 6, sr->mode); + u = u->next; + } + sh = sh->next; + } + } + + assert(!u); + + rnl(F); + rpline(F); + } + if (!is_monsters(f)) { + if (!anyunits) { + rnl(F); + rparagraph(F, LOC(f->locale, "nr_youaredead"), 0, 2, 0); + } else { + list_address(F, f, ctx->addresses); + } + } + fclose(F); + return 0; +} + +void +base36conversion(void) +{ + region * r; + for (r=regions;r;r=r->next) { + unit * u; + for (u=r->units;u;u=u->next) { + if (forbiddenid(u->no)) { + uunhash(u); + u->no = newunitid(); + uhash(u); + } + } + } +} + +#define FMAXHASH 1021 + +struct fsee { + struct fsee * nexthash; + faction * f; + struct see { + struct see * next; + faction * seen; + unit * proof; + } * see; +} * fsee[FMAXHASH]; + +#define REPORT_NR (1 << O_REPORT) +#define REPORT_CR (1 << O_COMPUTER) +#define REPORT_ZV (1 << O_ZUGVORLAGE) +#define REPORT_ZIP (1 << O_COMPRESS) +#define REPORT_BZIP2 (1 << O_BZIP2) + + +unit * +can_find(faction * f, faction * f2) +{ + int key = f->no % FMAXHASH; + struct fsee * fs = fsee[key]; + struct see * ss; + if (f==f2) return f->units; + while (fs && fs->f!=f) fs=fs->nexthash; + if (!fs) return NULL; + ss=fs->see; + while (ss && ss->seen!=f2) ss=ss->next; + if (ss) { + /* bei TARNE PARTEI yxz muss die Partei von unit proof nicht + * wirklich Partei f2 sein! */ + /* assert(ss->proof->faction==f2); */ + return ss->proof; + } + return NULL; +} + +static void +add_find(faction * f, unit * u, faction *f2) +{ + /* faction f sees f2 through u */ + int key = f->no % FMAXHASH; + struct fsee ** fp = &fsee[key]; + struct fsee * fs; + struct see ** sp; + struct see * ss; + while (*fp && (*fp)->f!=f) fp=&(*fp)->nexthash; + if (!*fp) { + fs = *fp = calloc(sizeof(struct fsee), 1); + fs->f = f; + } else fs = *fp; + sp = &fs->see; + while (*sp && (*sp)->seen!=f2) sp=&(*sp)->next; + if (!*sp) { + ss = *sp = calloc(sizeof(struct see), 1); + ss->proof = u; + ss->seen = f2; + } else ss = *sp; + ss->proof = u; +} + +static void +update_find(void) +{ + region * r; + static boolean initial = true; + + if (initial) for (r=regions;r;r=r->next) { + unit * u; + for (u=r->units;u;u=u->next) { + faction * lastf = u->faction; + unit * u2; + for (u2=r->units;u2;u2=u2->next) { + if (u2->faction==lastf || u2->faction==u->faction) + continue; + if (seefaction(u->faction, r, u2, 0)) { + faction *fv = visible_faction(u->faction, u2); + lastf = fv; + add_find(u->faction, u2, fv); + } + } + } + } + initial = false; +} + +boolean +kann_finden(faction * f1, faction * f2) +{ + update_find(); + return (boolean)(can_find(f1, f2)!=NULL); +} + +/******* end summary ******/ + +void +register_nr(void) +{ + if (!nocr) register_reporttype("nr", &report_plaintext, 1<nexthash; + free(fsee[i]); + fsee[i] = fs; + } + } +} + diff --git a/src/gamecode/report.h b/src/gamecode/report.h index e294adf6d..7ff7564dc 100644 --- a/src/gamecode/report.h +++ b/src/gamecode/report.h @@ -1,25 +1,25 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ -#ifndef H_GC_REPORT -#define H_GC_REPORT -#ifdef __cplusplus -extern "C" { -#endif - - extern void register_nr(void); - extern void report_cleanup(void); - -#ifdef __cplusplus -} -#endif -#endif - +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#ifndef H_GC_REPORT +#define H_GC_REPORT +#ifdef __cplusplus +extern "C" { +#endif + + extern void register_nr(void); + extern void report_cleanup(void); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/gamecode/spy.c b/src/gamecode/spy.c index fe665bda8..14aea1786 100644 --- a/src/gamecode/spy.c +++ b/src/gamecode/spy.c @@ -1,482 +1,482 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "spy.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* attributes includes */ -#include - -/* util includes */ -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include - -#include - -/* in spy steht der Unterschied zwischen Wahrnehmung des Opfers und -* Spionage des Spions */ -void -spy_message(int spy, const unit *u, const unit *target) -{ - const char * str = report_kampfstatus(target, u->faction->locale); - - ADDMSG(&u->faction->msgs, msg_message("spyreport", "spy target status", u, target, str)); - if (spy > 20) { - sc_mage * mage = get_mage(target); - /* bei Magiern Zaubersprüche und Magiegebiet */ - if (mage) { - ADDMSG(&u->faction->msgs, msg_message("spyreport_mage", "target type", target, magic_school[mage->magietyp])); - } - } - if (spy > 6) { - faction * fv = visible_faction(u->faction,target); - if (fv && fv!=target->faction) { - /* wahre Partei */ - ADDMSG(&u->faction->msgs, msg_message("spyreport_faction", "target faction", target, target->faction)); - } - } - if (spy > 0) { - int first = 1; - int found = 0; - skill * sv; - char buf[4096]; - - buf[0] = 0; - for (sv = target->skills;sv!=target->skills+target->skill_size;++sv) { - if (sv->level>0) { - found++; - if (first == 1) { - first = 0; - } else { - strncat(buf, ", ", sizeof(buf)); - } - strncat(buf, (const char *)skillname(sv->id, u->faction->locale), sizeof(buf)); - strncat(buf, " ", sizeof(buf)); - strncat(buf, itoa10(eff_skill(target, sv->id, target->region)), sizeof(buf)); - } - } - if (found) { - ADDMSG(&u->faction->msgs, msg_message("spyreport_skills", "target skills", target, buf)); - } - - if (target->items) { - ADDMSG(&u->faction->msgs, msg_message("spyreport_items", "target items", target, target->items)); - } - } -} - - -int -spy_cmd(unit * u, struct order * ord) -{ - unit *target; - int spy, observe; - double spychance, observechance; - region * r = u->region; - - init_tokens(ord); - skip_token(); - target = getunit(r, u->faction); - - if (!target) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); - return 0; - } - if (!can_contact(r, u, target)) { - cmistake(u, u->thisorder, 24, MSG_EVENT); - return 0; - } - if (eff_skill(u, SK_SPY, r) < 1) { - cmistake(u, u->thisorder, 39, MSG_EVENT); - return 0; - } - /* Die Grundchance für einen erfolgreichen Spionage-Versuch ist 10%. - * Für jeden Talentpunkt, den das Spionagetalent das Tarnungstalent - * des Opfers übersteigt, erhöht sich dieses um 5%*/ - spy = eff_skill(u, SK_SPY, r) - eff_skill(target, SK_STEALTH, r); - spychance = 0.1 + MAX(spy*0.05, 0.0); - - if (chance(spychance)) { - produceexp(u, SK_SPY, u->number); - spy_message(spy, u, target); - } else { - ADDMSG(&u->faction->msgs, msg_message("spyfail", "spy target", u, target)); - } - - /* der Spion kann identifiziert werden, wenn das Opfer bessere - * Wahrnehmung als das Ziel Tarnung + Spionage/2 hat */ - observe = eff_skill(target, SK_PERCEPTION, r) - - (effskill(u, SK_STEALTH) + eff_skill(u, SK_SPY, r)/2); - - if (invisible(u, target) >= u->number) { - observe = MIN(observe, 0); - } - - /* Anschließend wird - unabhängig vom Erfolg - gewürfelt, ob der - * Spionageversuch bemerkt wurde. Die Wahrscheinlich dafür ist (100 - - * SpionageSpion*5 + WahrnehmungOpfer*2)%. */ - observechance = 1.0 - (eff_skill(u, SK_SPY, r) * 0.05) - + (eff_skill(target, SK_PERCEPTION, r) * 0.02); - - if (chance(observechance)) { - ADDMSG(&target->faction->msgs, msg_message("spydetect", - "spy target", observe>0?u:NULL, target)); - } - return 0; -} - -void -set_factionstealth(unit * u, faction * f) -{ - region * lastr = NULL; - /* for all units mu of our faction, check all the units in the region - * they are in, if their visible faction is f, it's ok. use lastr to - * avoid testing the same region twice in a row. */ - unit * mu = u->faction->units; - while (mu!=NULL) { - if (mu->number && mu->region!=lastr) { - unit * ru = mu->region->units; - lastr = mu->region; - while (ru!=NULL) { - if (ru->number) { - faction * fv = visible_faction(f, ru); - if (fv==f) { - if (cansee(f, lastr, ru, 0)) break; - } - } - ru = ru->next; - } - if (ru!=NULL) break; - } - mu = mu->nextF; - } - if (mu!=NULL) { - attrib * a = a_find(u->attribs, &at_otherfaction); - if (!a) a = a_add(&u->attribs, make_otherfaction(f)); - else a->data.v = f; - } -} - -int -setstealth_cmd(unit * u, struct order * ord) -{ - const char *s; - int level; - const race * trace; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - /* Tarne ohne Parameter: Setzt maximale Tarnung */ - - if (s == NULL || *s == 0) { - u_seteffstealth(u, -1); - return 0; - } - - trace = findrace(s, u->faction->locale); - if (trace) { - /* Dämonen können sich nur als andere Spielerrassen tarnen */ - if (u->race == new_race[RC_DAEMON]) { - race_t allowed[] = { RC_DWARF, RC_ELF, RC_ORC, RC_GOBLIN, RC_HUMAN, - RC_TROLL, RC_DAEMON, RC_INSECT, RC_HALFLING, RC_CAT, RC_AQUARIAN, - NORACE }; - int i; - for (i=0;allowed[i]!=NORACE;++i) if (new_race[allowed[i]]==trace) break; - if (new_race[allowed[i]]==trace) { - u->irace = trace; - if (u->race->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs)) - set_racename(&u->attribs, NULL); - } - return 0; - } - - /* Singdrachen können sich nur als Drachen tarnen */ - if (u->race == new_race[RC_SONGDRAGON] || u->race == new_race[RC_BIRTHDAYDRAGON]) { - if (trace==new_race[RC_SONGDRAGON]||trace==new_race[RC_FIREDRAGON]||trace==new_race[RC_DRAGON]||trace==new_race[RC_WYRM]) { - u->irace = trace; - if (u->race->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs)) - set_racename(&u->attribs, NULL); - } - return 0; - } - - /* Dämomen und Illusionsparteien können sich als andere race tarnen */ - if (u->race->flags & RCF_SHAPESHIFT) { - if (playerrace(trace)) { - u->irace = trace; - if ((u->race->flags & RCF_SHAPESHIFTANY) && get_racename(u->attribs)) - set_racename(&u->attribs, NULL); - } - } - return 0; - } - - switch(findparam(s, u->faction->locale)) { - case P_FACTION: - /* TARNE PARTEI [NICHT|NUMMER abcd] */ - if (!rule_stealth_faction()) break; - s = getstrtoken(); - if(!s || *s == 0) { - fset(u, UFL_ANON_FACTION); - } else if (findparam(s, u->faction->locale) == P_NOT) { - freset(u, UFL_ANON_FACTION); - } else if (findkeyword(s, u->faction->locale) == K_NUMBER) { - const char *s2 = (const char *)getstrtoken(); - int nr = -1; - - if (s2) nr = atoi36(s2); - if (!s2 || *s2 == 0 || nr == u->faction->no) { - a_removeall(&u->attribs, &at_otherfaction); - } else { - struct faction * f = findfaction(nr); - if (f==NULL) { - cmistake(u, ord, 66, MSG_EVENT); - } else { - set_factionstealth(u, f); - } - } - } else { - cmistake(u, ord, 289, MSG_EVENT); - } - break; - case P_ANY: - /* TARNE ALLES (was nicht so alles geht?) */ - u_seteffstealth(u, -1); - break; - case P_NOT: - u_seteffstealth(u, -1); - break; - default: - if (isdigit(s[0])) { - /* Tarnungslevel setzen */ - level = atoi((const char *)s); - if (level > effskill(u, SK_STEALTH)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_lowstealth", "")); - return 0; - } - u_seteffstealth(u, level); - } else if (u->race->flags & RCF_SHAPESHIFTANY) { - set_racename(&u->attribs, s); - } - } - return 0; -} - -static int -crew_skill(region * r, faction * f, ship * sh, skill_t sk) -{ - int value = 0; - unit *u; - - for (u=r->units;u;u=u->next) { - if (u->ship == sh && u->faction == f) { - int s = eff_skill(u, sk, r); - value = MAX(s, value); - } - } - return value; -} - -static int -try_destruction(unit * u, unit * u2, const ship *sh, int skilldiff) -{ - const char *destruction_success_msg = "destroy_ship_0"; - const char *destruction_failed_msg = "destroy_ship_1"; - const char *destruction_detected_msg = "destroy_ship_2"; - const char *detect_failure_msg = "destroy_ship_3"; - const char *object_destroyed_msg = "destroy_ship_4"; - - if (skilldiff == 0) { - /* tell the unit that the attempt failed: */ - ADDMSG(&u->faction->msgs, msg_message(destruction_failed_msg, "ship unit", sh, u)); - /* tell the enemy about the attempt: */ - if (u2) { - ADDMSG(&u2->faction->msgs, msg_message(detect_failure_msg, "ship", sh)); - } - return 0; - } else if (skilldiff < 0) { - /* tell the unit that the attempt was detected: */ - ADDMSG(&u2->faction->msgs, msg_message(destruction_detected_msg, "ship unit", sh, u)); - /* tell the enemy whodunit: */ - if (u2) { - ADDMSG(&u2->faction->msgs, msg_message(detect_failure_msg, "ship", sh)); - } - return 0; - } else { - /* tell the unit that the attempt succeeded */ - ADDMSG(&u->faction->msgs, msg_message(destruction_success_msg, "ship unit", sh, u)); - if (u2) { - ADDMSG(&u2->faction->msgs, msg_message(object_destroyed_msg, "ship", sh)); - } - } - return 1; /* success */ -} - -static void -sink_ship(region * r, ship * sh, const char *name, unit * saboteur) -{ - unit **ui, *u; - region *safety = r; - int i; - direction_t d; - double probability = 0.0; - message * sink_msg = NULL; - faction * f; - - for (f=NULL,u=r->units;u;u=u->next) { - /* slight optimization to avoid dereferencing u->faction each time */ - if (f!=u->faction) { - f = u->faction; - freset(f, FFL_SELECT); - } - } - - /* figure out what a unit's chances of survival are: */ - if (!fval(r->terrain, SEA_REGION)) { - probability = CANAL_SWIMMER_CHANCE; - } else { - for (d = 0; d != MAXDIRECTIONS; ++d) { - region * rn = rconnect(r, d); - if (!fval(rn->terrain, SEA_REGION) && !move_blocked(NULL, r, rn)) { - safety = rn; - probability = OCEAN_SWIMMER_CHANCE; - break; - } - } - } - for (ui = &r->units; *ui; ui = &(*ui)->next) { - unit *u = *ui; - - /* inform this faction about the sinking ship: */ - if (!fval(u->faction, FFL_SELECT)) { - fset(u->faction, FFL_SELECT); - if (sink_msg==NULL) { - sink_msg = msg_message("sink_msg", "ship region", sh, r); - } - add_message(&f->msgs, sink_msg); - } - - if (u->ship == sh) { - int dead = 0; - message * msg; - - /* if this fails, I misunderstood something: */ - for (i = 0; i != u->number; ++i) - if (chance(probability)) - ++dead; - - if (dead != u->number) { - /* she will live. but her items get stripped */ - if (dead > 0) { - msg = msg_message("sink_lost_msg", "dead region unit", dead, safety, u); - } else { - msg = msg_message("sink_saved_msg", "region unit", safety, u); - } - set_leftship(u, u->ship); - u->ship = 0; - if (r != safety) { - setguard(u, GUARD_NONE); - } - while (u->items) { - i_remove(&u->items, u->items); - } - move_unit(u, safety, NULL); - } else { - msg = msg_message("sink_lost_msg", "dead region unit", dead, NULL, u); - } - add_message(&u->faction->msgs, msg); - msg_release(msg); - if (dead == u->number) { - /* the poor creature, she dies */ - if (remove_unit(ui, u)!=0) { - ui = &u->next; - } - } - } - } - if (sink_msg) msg_release(sink_msg); - /* finally, get rid of the ship */ - remove_ship(&sh->region->ships, sh); -} - -int -sabotage_cmd(unit * u, struct order * ord) -{ - const char *s; - int i; - ship *sh; - unit *u2; - char buffer[DISPLAYSIZE]; - region * r = u->region; - int skdiff; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - i = findparam(s, u->faction->locale); - - switch (i) { - case P_SHIP: - sh = u->ship; - if (!sh) { - cmistake(u, u->thisorder, 144, MSG_EVENT); - return 0; - } - u2 = shipowner(sh); - skdiff = eff_skill(u, SK_SPY, r)-crew_skill(r, u2->faction, sh, SK_PERCEPTION); - if (try_destruction(u, u2, sh, skdiff)) { - sink_ship(r, sh, buffer, u); - } - break; - default: - cmistake(u, u->thisorder, 9, MSG_EVENT); - return 0; - } - - return 0; -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "spy.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* attributes includes */ +#include + +/* util includes */ +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +#include + +/* in spy steht der Unterschied zwischen Wahrnehmung des Opfers und +* Spionage des Spions */ +void +spy_message(int spy, const unit *u, const unit *target) +{ + const char * str = report_kampfstatus(target, u->faction->locale); + + ADDMSG(&u->faction->msgs, msg_message("spyreport", "spy target status", u, target, str)); + if (spy > 20) { + sc_mage * mage = get_mage(target); + /* bei Magiern Zaubersprüche und Magiegebiet */ + if (mage) { + ADDMSG(&u->faction->msgs, msg_message("spyreport_mage", "target type", target, magic_school[mage->magietyp])); + } + } + if (spy > 6) { + faction * fv = visible_faction(u->faction,target); + if (fv && fv!=target->faction) { + /* wahre Partei */ + ADDMSG(&u->faction->msgs, msg_message("spyreport_faction", "target faction", target, target->faction)); + } + } + if (spy > 0) { + int first = 1; + int found = 0; + skill * sv; + char buf[4096]; + + buf[0] = 0; + for (sv = target->skills;sv!=target->skills+target->skill_size;++sv) { + if (sv->level>0) { + found++; + if (first == 1) { + first = 0; + } else { + strncat(buf, ", ", sizeof(buf)); + } + strncat(buf, (const char *)skillname(sv->id, u->faction->locale), sizeof(buf)); + strncat(buf, " ", sizeof(buf)); + strncat(buf, itoa10(eff_skill(target, sv->id, target->region)), sizeof(buf)); + } + } + if (found) { + ADDMSG(&u->faction->msgs, msg_message("spyreport_skills", "target skills", target, buf)); + } + + if (target->items) { + ADDMSG(&u->faction->msgs, msg_message("spyreport_items", "target items", target, target->items)); + } + } +} + + +int +spy_cmd(unit * u, struct order * ord) +{ + unit *target; + int spy, observe; + double spychance, observechance; + region * r = u->region; + + init_tokens(ord); + skip_token(); + target = getunit(r, u->faction); + + if (!target) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); + return 0; + } + if (!can_contact(r, u, target)) { + cmistake(u, u->thisorder, 24, MSG_EVENT); + return 0; + } + if (eff_skill(u, SK_SPY, r) < 1) { + cmistake(u, u->thisorder, 39, MSG_EVENT); + return 0; + } + /* Die Grundchance für einen erfolgreichen Spionage-Versuch ist 10%. + * Für jeden Talentpunkt, den das Spionagetalent das Tarnungstalent + * des Opfers übersteigt, erhöht sich dieses um 5%*/ + spy = eff_skill(u, SK_SPY, r) - eff_skill(target, SK_STEALTH, r); + spychance = 0.1 + MAX(spy*0.05, 0.0); + + if (chance(spychance)) { + produceexp(u, SK_SPY, u->number); + spy_message(spy, u, target); + } else { + ADDMSG(&u->faction->msgs, msg_message("spyfail", "spy target", u, target)); + } + + /* der Spion kann identifiziert werden, wenn das Opfer bessere + * Wahrnehmung als das Ziel Tarnung + Spionage/2 hat */ + observe = eff_skill(target, SK_PERCEPTION, r) + - (effskill(u, SK_STEALTH) + eff_skill(u, SK_SPY, r)/2); + + if (invisible(u, target) >= u->number) { + observe = MIN(observe, 0); + } + + /* Anschließend wird - unabhängig vom Erfolg - gewürfelt, ob der + * Spionageversuch bemerkt wurde. Die Wahrscheinlich dafür ist (100 - + * SpionageSpion*5 + WahrnehmungOpfer*2)%. */ + observechance = 1.0 - (eff_skill(u, SK_SPY, r) * 0.05) + + (eff_skill(target, SK_PERCEPTION, r) * 0.02); + + if (chance(observechance)) { + ADDMSG(&target->faction->msgs, msg_message("spydetect", + "spy target", observe>0?u:NULL, target)); + } + return 0; +} + +void +set_factionstealth(unit * u, faction * f) +{ + region * lastr = NULL; + /* for all units mu of our faction, check all the units in the region + * they are in, if their visible faction is f, it's ok. use lastr to + * avoid testing the same region twice in a row. */ + unit * mu = u->faction->units; + while (mu!=NULL) { + if (mu->number && mu->region!=lastr) { + unit * ru = mu->region->units; + lastr = mu->region; + while (ru!=NULL) { + if (ru->number) { + faction * fv = visible_faction(f, ru); + if (fv==f) { + if (cansee(f, lastr, ru, 0)) break; + } + } + ru = ru->next; + } + if (ru!=NULL) break; + } + mu = mu->nextF; + } + if (mu!=NULL) { + attrib * a = a_find(u->attribs, &at_otherfaction); + if (!a) a = a_add(&u->attribs, make_otherfaction(f)); + else a->data.v = f; + } +} + +int +setstealth_cmd(unit * u, struct order * ord) +{ + const char *s; + int level; + const race * trace; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + /* Tarne ohne Parameter: Setzt maximale Tarnung */ + + if (s == NULL || *s == 0) { + u_seteffstealth(u, -1); + return 0; + } + + trace = findrace(s, u->faction->locale); + if (trace) { + /* Dämonen können sich nur als andere Spielerrassen tarnen */ + if (u->race == new_race[RC_DAEMON]) { + race_t allowed[] = { RC_DWARF, RC_ELF, RC_ORC, RC_GOBLIN, RC_HUMAN, + RC_TROLL, RC_DAEMON, RC_INSECT, RC_HALFLING, RC_CAT, RC_AQUARIAN, + NORACE }; + int i; + for (i=0;allowed[i]!=NORACE;++i) if (new_race[allowed[i]]==trace) break; + if (new_race[allowed[i]]==trace) { + u->irace = trace; + if (u->race->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs)) + set_racename(&u->attribs, NULL); + } + return 0; + } + + /* Singdrachen können sich nur als Drachen tarnen */ + if (u->race == new_race[RC_SONGDRAGON] || u->race == new_race[RC_BIRTHDAYDRAGON]) { + if (trace==new_race[RC_SONGDRAGON]||trace==new_race[RC_FIREDRAGON]||trace==new_race[RC_DRAGON]||trace==new_race[RC_WYRM]) { + u->irace = trace; + if (u->race->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs)) + set_racename(&u->attribs, NULL); + } + return 0; + } + + /* Dämomen und Illusionsparteien können sich als andere race tarnen */ + if (u->race->flags & RCF_SHAPESHIFT) { + if (playerrace(trace)) { + u->irace = trace; + if ((u->race->flags & RCF_SHAPESHIFTANY) && get_racename(u->attribs)) + set_racename(&u->attribs, NULL); + } + } + return 0; + } + + switch(findparam(s, u->faction->locale)) { + case P_FACTION: + /* TARNE PARTEI [NICHT|NUMMER abcd] */ + if (!rule_stealth_faction()) break; + s = getstrtoken(); + if(!s || *s == 0) { + fset(u, UFL_ANON_FACTION); + } else if (findparam(s, u->faction->locale) == P_NOT) { + freset(u, UFL_ANON_FACTION); + } else if (findkeyword(s, u->faction->locale) == K_NUMBER) { + const char *s2 = (const char *)getstrtoken(); + int nr = -1; + + if (s2) nr = atoi36(s2); + if (!s2 || *s2 == 0 || nr == u->faction->no) { + a_removeall(&u->attribs, &at_otherfaction); + } else { + struct faction * f = findfaction(nr); + if (f==NULL) { + cmistake(u, ord, 66, MSG_EVENT); + } else { + set_factionstealth(u, f); + } + } + } else { + cmistake(u, ord, 289, MSG_EVENT); + } + break; + case P_ANY: + /* TARNE ALLES (was nicht so alles geht?) */ + u_seteffstealth(u, -1); + break; + case P_NOT: + u_seteffstealth(u, -1); + break; + default: + if (isdigit(s[0])) { + /* Tarnungslevel setzen */ + level = atoi((const char *)s); + if (level > effskill(u, SK_STEALTH)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_lowstealth", "")); + return 0; + } + u_seteffstealth(u, level); + } else if (u->race->flags & RCF_SHAPESHIFTANY) { + set_racename(&u->attribs, s); + } + } + return 0; +} + +static int +crew_skill(region * r, faction * f, ship * sh, skill_t sk) +{ + int value = 0; + unit *u; + + for (u=r->units;u;u=u->next) { + if (u->ship == sh && u->faction == f) { + int s = eff_skill(u, sk, r); + value = MAX(s, value); + } + } + return value; +} + +static int +try_destruction(unit * u, unit * u2, const ship *sh, int skilldiff) +{ + const char *destruction_success_msg = "destroy_ship_0"; + const char *destruction_failed_msg = "destroy_ship_1"; + const char *destruction_detected_msg = "destroy_ship_2"; + const char *detect_failure_msg = "destroy_ship_3"; + const char *object_destroyed_msg = "destroy_ship_4"; + + if (skilldiff == 0) { + /* tell the unit that the attempt failed: */ + ADDMSG(&u->faction->msgs, msg_message(destruction_failed_msg, "ship unit", sh, u)); + /* tell the enemy about the attempt: */ + if (u2) { + ADDMSG(&u2->faction->msgs, msg_message(detect_failure_msg, "ship", sh)); + } + return 0; + } else if (skilldiff < 0) { + /* tell the unit that the attempt was detected: */ + ADDMSG(&u2->faction->msgs, msg_message(destruction_detected_msg, "ship unit", sh, u)); + /* tell the enemy whodunit: */ + if (u2) { + ADDMSG(&u2->faction->msgs, msg_message(detect_failure_msg, "ship", sh)); + } + return 0; + } else { + /* tell the unit that the attempt succeeded */ + ADDMSG(&u->faction->msgs, msg_message(destruction_success_msg, "ship unit", sh, u)); + if (u2) { + ADDMSG(&u2->faction->msgs, msg_message(object_destroyed_msg, "ship", sh)); + } + } + return 1; /* success */ +} + +static void +sink_ship(region * r, ship * sh, const char *name, unit * saboteur) +{ + unit **ui, *u; + region *safety = r; + int i; + direction_t d; + double probability = 0.0; + message * sink_msg = NULL; + faction * f; + + for (f=NULL,u=r->units;u;u=u->next) { + /* slight optimization to avoid dereferencing u->faction each time */ + if (f!=u->faction) { + f = u->faction; + freset(f, FFL_SELECT); + } + } + + /* figure out what a unit's chances of survival are: */ + if (!fval(r->terrain, SEA_REGION)) { + probability = CANAL_SWIMMER_CHANCE; + } else { + for (d = 0; d != MAXDIRECTIONS; ++d) { + region * rn = rconnect(r, d); + if (!fval(rn->terrain, SEA_REGION) && !move_blocked(NULL, r, rn)) { + safety = rn; + probability = OCEAN_SWIMMER_CHANCE; + break; + } + } + } + for (ui = &r->units; *ui; ui = &(*ui)->next) { + unit *u = *ui; + + /* inform this faction about the sinking ship: */ + if (!fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + if (sink_msg==NULL) { + sink_msg = msg_message("sink_msg", "ship region", sh, r); + } + add_message(&f->msgs, sink_msg); + } + + if (u->ship == sh) { + int dead = 0; + message * msg; + + /* if this fails, I misunderstood something: */ + for (i = 0; i != u->number; ++i) + if (chance(probability)) + ++dead; + + if (dead != u->number) { + /* she will live. but her items get stripped */ + if (dead > 0) { + msg = msg_message("sink_lost_msg", "dead region unit", dead, safety, u); + } else { + msg = msg_message("sink_saved_msg", "region unit", safety, u); + } + set_leftship(u, u->ship); + u->ship = 0; + if (r != safety) { + setguard(u, GUARD_NONE); + } + while (u->items) { + i_remove(&u->items, u->items); + } + move_unit(u, safety, NULL); + } else { + msg = msg_message("sink_lost_msg", "dead region unit", dead, NULL, u); + } + add_message(&u->faction->msgs, msg); + msg_release(msg); + if (dead == u->number) { + /* the poor creature, she dies */ + if (remove_unit(ui, u)!=0) { + ui = &u->next; + } + } + } + } + if (sink_msg) msg_release(sink_msg); + /* finally, get rid of the ship */ + remove_ship(&sh->region->ships, sh); +} + +int +sabotage_cmd(unit * u, struct order * ord) +{ + const char *s; + int i; + ship *sh; + unit *u2; + char buffer[DISPLAYSIZE]; + region * r = u->region; + int skdiff; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + i = findparam(s, u->faction->locale); + + switch (i) { + case P_SHIP: + sh = u->ship; + if (!sh) { + cmistake(u, u->thisorder, 144, MSG_EVENT); + return 0; + } + u2 = shipowner(sh); + skdiff = eff_skill(u, SK_SPY, r)-crew_skill(r, u2->faction, sh, SK_PERCEPTION); + if (try_destruction(u, u2, sh, skdiff)) { + sink_ship(r, sh, buffer, u); + } + break; + default: + cmistake(u, u->thisorder, 9, MSG_EVENT); + return 0; + } + + return 0; +} + diff --git a/src/gamecode/spy.h b/src/gamecode/spy.h index 6c56eaa53..6d039ebd7 100644 --- a/src/gamecode/spy.h +++ b/src/gamecode/spy.h @@ -1,40 +1,40 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_SPY -#define H_KRNL_SPY -#ifdef __cplusplus -extern "C" { -#endif - -struct unit; -struct region; -struct strlist; - -extern int setstealth_cmd(struct unit * u, struct order * ord); -extern int spy_cmd(struct unit * u, struct order * ord); -extern int sabotage_cmd(struct unit * u, struct order * ord); -extern void spy_message(int spy, const struct unit *u, const struct unit *target); - -#define OCEAN_SWIMMER_CHANCE 0.1 -#define CANAL_SWIMMER_CHANCE 0.9 - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_SPY +#define H_KRNL_SPY +#ifdef __cplusplus +extern "C" { +#endif + +struct unit; +struct region; +struct strlist; + +extern int setstealth_cmd(struct unit * u, struct order * ord); +extern int spy_cmd(struct unit * u, struct order * ord); +extern int sabotage_cmd(struct unit * u, struct order * ord); +extern void spy_message(int spy, const struct unit *u, const struct unit *target); + +#define OCEAN_SWIMMER_CHANCE 0.1 +#define CANAL_SWIMMER_CHANCE 0.9 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/study.c b/src/gamecode/study.c index 32911c286..38444e69a 100644 --- a/src/gamecode/study.c +++ b/src/gamecode/study.c @@ -1,793 +1,793 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#define TEACH_ALL 1 -#define TEACH_FRIENDS - -#include -#include -#include "study.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include - -#define TEACHNUMBER 10 - -static skill_t -getskill(const struct locale * lang) -{ - return findskill(getstrtoken(), lang); -} - -magic_t -getmagicskill(const struct locale * lang) -{ - struct tnode * tokens = get_translations(lang, UT_MAGIC); - variant token; - const char * s = getstrtoken(); - - if (s && s[0]) { - if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { - return (magic_t)token.i; - } else { - char buffer[3]; - buffer[0] = s[0]; - buffer[1] = s[1]; - buffer[2] = '\0'; - if (findtoken(tokens, buffer, &token)==E_TOK_SUCCESS) { - return (magic_t)token.i; - } - } - } - return M_NONE; -} - -/* ------------------------------------------------------------- */ -/* Vertraute und Kröten sind keine Migranten */ -boolean -is_migrant(unit *u) -{ - if (u->race == u->faction->race) return false; - - if (fval(u->race, RCF_UNDEAD|RCF_ILLUSIONARY)) return false; - if (is_familiar(u)) return false; - if (u->race == new_race[RC_TOAD]) return false; - - return true; -} - -/* ------------------------------------------------------------- */ -boolean -magic_lowskill(unit *u) -{ - if (u->race == new_race[RC_TOAD]) return true; - return false; -} - -/* ------------------------------------------------------------- */ - -int -study_cost(unit *u, skill_t sk) -{ - static int cost[MAXSKILLS]; - int stufe, k = 50; - - if (cost[sk]==0) { - char buffer[256]; - sprintf(buffer, "skills.cost.%s", skillnames[sk]); - cost[sk] = get_param_int(global.parameters, buffer, -1); - } - if (cost[sk]>=0) return cost[sk]; - - switch (sk) { - case SK_SPY: - return 100; - break; - case SK_TACTICS: - case SK_HERBALISM: - case SK_ALCHEMY: - return 200; - break; - case SK_MAGIC: /* Die Magiekosten betragen 50+Summe(50*Stufe) */ - /* 'Stufe' ist dabei die nächste zu erreichende Stufe */ - stufe = 1 + get_level(u, SK_MAGIC); - return k*(1+((stufe+1)*stufe/2)); - break; - } - return 0; -} - -/* ------------------------------------------------------------- */ - -static void -init_learning(struct attrib * a) -{ - a->data.v = calloc(sizeof(teaching_info), 1); -} - -static void -done_learning(struct attrib * a) -{ - free(a->data.v); -} - -const attrib_type at_learning = { - "learning", - init_learning, done_learning, NULL, NULL, NULL, - ATF_UNIQUE -}; - -static int -study_days(unit * student, skill_t sk) -{ - int speed = 30; - if (student->race->study_speed) { - speed += student->race->study_speed[sk]; - if (speed<30) { - skill * sv = get_skill(student, sk); - if (sv==0) { - speed = 30; - } - } - } - return student->number * speed; -} - -static int -teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, - boolean report, int * academy) -{ - teaching_info * teach = NULL; - attrib * a; - int n; - - /* learning sind die Tage, die sie schon durch andere Lehrer zugute - * geschrieben bekommen haben. Total darf dies nicht über 30 Tage pro Mann - * steigen. - * - * n ist die Anzahl zusätzlich gelernter Tage. n darf max. die Differenz - * von schon gelernten Tagen zum MAX(30 Tage pro Mann) betragen. */ - - if (magic_lowskill(student)){ - cmistake(teacher, teacher->thisorder, 292, MSG_EVENT); - return 0; - } - - n = 30; - a = a_find(student->attribs, &at_learning); - if (a!=NULL) { - teach = (teaching_info*)a->data.v; - n -= teach->value; - } - - n = MIN(n, nteaching); - - if (n != 0) { - struct building * b = inside_building(teacher); - const struct building_type * btype = b?b->type:NULL; - int index = 0; - - if (teach==NULL) { - a = a_add(&student->attribs, a_new(&at_learning)); - teach = (teaching_info*)a->data.v; - } else { - while (teach->teachers[index] && index!=MAXTEACHERS) ++index; - } - if (indexteachers[index++] = teacher; - if (indexteachers[index] = NULL; - teach->value += n; - - /* Solange Akademien größenbeschränkt sind, sollte Lehrer und - * Student auch in unterschiedlichen Gebäuden stehen dürfen */ - if (btype == bt_find("academy") - && student->building && student->building->type == bt_find("academy")) - { - int j = study_cost(student, sk); - j = MAX(50, j * 2); - /* kann Einheit das zahlen? */ - if (get_pooled(student, oldresourcetype[R_SILVER], GET_DEFAULT, j) >= j) { - /* Jeder Schüler zusätzlich +10 Tage wenn in Uni. */ - teach->value += (n / 30) * 10; /* learning erhöhen */ - /* Lehrer zusätzlich +1 Tag pro Schüler. */ - if (academy) *academy += n; - } /* sonst nehmen sie nicht am Unterricht teil */ - } - - /* Teaching ist die Anzahl Leute, denen man noch was beibringen kann. Da - * hier nicht n verwendet wird, werden die Leute gezählt und nicht die - * effektiv gelernten Tage. -> FALSCH ? (ENNO) - * - * Eine Einheit A von 11 Mann mit Talent 0 profitiert vom ersten Lehrer B - * also 10x30=300 tage, und der zweite Lehrer C lehrt für nur noch 1x30=30 - * Tage (damit das Maximum von 11x30=330 nicht überschritten wird). - * - * Damit es aber in der Ausführung nicht auf die Reihenfolge drauf ankommt, - * darf der zweite Lehrer C keine weiteren Einheiten D mehr lehren. Also - * wird student 30 Tage gutgeschrieben, aber teaching sinkt auf 0 (300-11x30 <= - * 0). - * - * Sonst träte dies auf: - * - * A: lernt B: lehrt A C: lehrt A D D: lernt - * - * Wenn B vor C dran ist, lehrt C nur 30 Tage an A (wie oben) und - * 270 Tage an D. - * - * Ist C aber vor B dran, lehrt C 300 tage an A, und 0 tage an D, - * und B lehrt auch 0 tage an A. - * - * Deswegen darf C D nie lehren dürfen. - * - * -> Das ist wirr. wer hat das entworfen? - * Besser wäre, man macht erst vorab alle zuordnungen, und dann - * die Talentänderung (enno). - */ - - nteaching = MAX(0, nteaching - student->number * 30); - - } - return n; -} - -int -teach_cmd(unit * u, struct order * ord) -{ - static const curse_type * gbdream_ct = NULL; - plane * pl; - region * r = u->region; - int teaching, i, j, count, academy=0; - unit *u2; - skill_t sk = NOSKILL; - - if (gbdream_ct==0) gbdream_ct = ct_find("gbdream"); - if (gbdream_ct) { - if (get_curse(u->region->attribs, gbdream_ct)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "gbdream_noteach", "")); - return 0; - } - } - - if ((u->race->flags & RCF_NOTEACH) || fval(u, UFL_WERE)) { - cmistake(u, ord, 274, MSG_EVENT); - return 0; - } - - pl = rplane(r); - if (pl && fval(pl, PFL_NOTEACH)) { - cmistake(u, ord, 273, MSG_EVENT); - return 0; - } - - teaching = u->number * 30 * TEACHNUMBER; - - if ((i = get_effect(u, oldpotiontype[P_FOOL])) > 0) { /* Trank "Dumpfbackenbrot" */ - i = MIN(i, u->number * TEACHNUMBER); - /* Trank wirkt pro Schüler, nicht pro Lehrer */ - teaching -= i * 30; - change_effect(u, oldpotiontype[P_FOOL], -i); - j = teaching / 30; - ADDMSG(&u->faction->msgs, msg_message("teachdumb", - "teacher amount", u, j)); - } - if (teaching == 0) return 0; - - - u2 = 0; - count = 0; - - init_tokens(ord); - skip_token(); - -#if TEACH_ALL - if (getparam(u->faction->locale)==P_ANY) { - unit * student = r->units; - skill_t teachskill[MAXSKILLS]; - int i = 0; - do { - sk = getskill(u->faction->locale); - teachskill[i++]=sk; - } while (sk!=NOSKILL); - while (teaching && student) { - if (student->faction == u->faction) { -#ifdef NEW_DAEMONHUNGER_RULE - if (LongHunger(student)) continue; -#else - if (fval(student, UFL_HUNGER)) continue; -#endif - if (get_keyword(student->thisorder) == K_STUDY) { - /* Input ist nun von student->thisorder !! */ - init_tokens(student->thisorder); - skip_token(); - sk = getskill(student->faction->locale); - if (sk!=NOSKILL && teachskill[0]!=NOSKILL) { - for (i=0;teachskill[i]!=NOSKILL;++i) if (sk==teachskill[i]) break; - sk = teachskill[i]; - } - if (sk != NOSKILL && eff_skill_study(u, sk, r)-TEACHDIFFERENCE > eff_skill_study(student, sk, r)) { - teaching -= teach_unit(u, student, teaching, sk, true, &academy); - } - } - } - student = student->next; - } -#ifdef TEACH_FRIENDS - while (teaching && student) { - if (student->faction != u->faction && alliedunit(u, student->faction, HELP_GUARD)) { -#ifdef NEW_DAEMONHUNGER_RULE - if (LongHunger(student)) continue; -#else - if (fval(student, UFL_HUNGER)) continue; -#endif - if (get_keyword(student->thisorder) == K_STUDY) { - /* Input ist nun von student->thisorder !! */ - init_tokens(student->thisorder); - skip_token(); - sk = getskill(student->faction->locale); - if (sk != NOSKILL && eff_skill_study(u, sk, r)-TEACHDIFFERENCE >= eff_skill(student, sk, r)) { - teaching -= teach_unit(u, student, teaching, sk, true, &academy); - } - } - } - student = student->next; - } -#endif - } - else -#endif - { - char zOrder[4096]; - order * new_order; - - zOrder[0] = '\0'; - init_tokens(ord); - skip_token(); - - while (!parser_end()) { - unit * u2 = getunit(r, u->faction); - boolean feedback; - ++count; - - /* Falls die Unit nicht gefunden wird, Fehler melden */ - - if (!u2) { - char tbuf[20]; - const char * uid; - const char * token; - /* Finde den string, der den Fehler verursacht hat */ - parser_pushstate(); - init_tokens(ord); - skip_token(); - - for (j=0; j!=count-1; ++j) { - /* skip over the first 'count' units */ - getunit(r, u->faction); - } - - token = getstrtoken(); - - /* Beginne die Fehlermeldung */ - if (findparam(token, u->faction->locale) != P_TEMP) { - uid = token; - } else { - token = getstrtoken(); - sprintf(tbuf, "%s %s", LOC(u->faction->locale, - parameters[P_TEMP]), token); - uid = tbuf; - } - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unitnotfound_id", - "id", uid)); - - parser_popstate(); - continue; - } - - feedback = u->faction==u2->faction || alliedunit(u2, u->faction, HELP_GUARD); - - /* Neuen Befehl zusammenbauen. TEMP-Einheiten werden automatisch in - * ihre neuen Nummern übersetzt. */ - if (zOrder[0]) strcat(zOrder, " "); - strcat(zOrder, unitid(u2)); - - if (get_keyword(u2->thisorder) != K_STUDY) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "teach_nolearn", "student", u2)); - continue; - } - - /* Input ist nun von u2->thisorder !! */ - parser_pushstate(); - init_tokens(u2->thisorder); - skip_token(); - sk = getskill(u2->faction->locale); - parser_popstate(); - - if (sk == NOSKILL) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "teach_nolearn", "student", u2)); - continue; - } - - /* u is teacher, u2 is student */ - if (eff_skill_study(u2, sk, r) > eff_skill_study(u, sk, r)-TEACHDIFFERENCE) { - if (feedback) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "teach_asgood", "student", u2)); - } - continue; - } - if (sk == SK_MAGIC) { - /* ist der Magier schon spezialisiert, so versteht er nur noch - * Lehrer seines Gebietes */ - sc_mage * mage1 = get_mage(u); - sc_mage * mage2 = get_mage(u2); - if (!mage2 || !mage1 || (mage2->magietyp!=M_GRAY && mage1->magietyp!=mage2->magietyp)) { - if (feedback) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_different_magic", "target", u2)); - } - continue; - } - } - - teaching -= teach_unit(u, u2, teaching, sk, false, &academy); - } - new_order = create_order(K_TEACH, u->faction->locale, "%s", zOrder); - replace_order(&u->orders, ord, new_order); - free_order(new_order); /* parse_order & set_order have each increased the refcount */ - } - if (academy && sk!=NOSKILL) { - academy = academy/30; /* anzahl gelehrter wochen, max. 10 */ - learn_skill(u, sk, academy/30.0/TEACHNUMBER); - } - return 0; -} - -static double -study_speedup(unit * u) -{ -#define MINTURN 5 /* 5 */ -#define OFSTURN 2 /* 2 */ - if (turn>MINTURN) { - static int speed_rule = -1; - if (speed_rule<0) { - speed_rule = get_param_int(global.parameters, "study.speedup", 0); - } - if (speed_rule==1) { - double learn_age = OFSTURN; - int i; - for (i=0;i!=u->skill_size;++i) { - skill * sv = u->skills+i; - double learn_time = sv->level*(sv->level+1)/2.0; - learn_age += learn_time; - } - if (learn_age < turn) { - return 2.0-learn_age/turn; - } - } - } - return 1.0; -} - -int -learn_cmd(unit * u, order * ord) -{ - region *r = u->region; - int p; - magic_t mtyp; - int l; - int studycost, days; - double multi = 1.0; - attrib * a = NULL; - teaching_info * teach = NULL; - int money = 0; - skill_t sk; - int maxalchemy = 0; - static int learn_newskills = -1; - if (learn_newskills<0) { - const char * str = get_param(global.parameters, "study.newskills"); - if (str && strcmp(str, "false")==0) learn_newskills = 0; - else learn_newskills = 1; - } - - if ((u->race->flags & RCF_NOLEARN) || fval(u, UFL_WERE)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_race_nolearn", "race", u->race)); - return 0; - } - - init_tokens(ord); - skip_token(); - sk = getskill(u->faction->locale); - - if (sk < 0) { - cmistake(u, ord, 77, MSG_EVENT); - return 0; - } - if (SkillCap(sk) && SkillCap(sk) <= effskill(u, sk)) { - cmistake(u, ord, 771, MSG_EVENT); - return 0; - } - /* Hack: Talente mit Malus -99 können nicht gelernt werden */ - if (u->race->bonus[sk] == -99) { - cmistake(u, ord, 771, MSG_EVENT); - return 0; - } - if (learn_newskills==0) { - skill * sv = get_skill(u, sk); - if (sv==NULL) { - /* we can only learn skills we already have */ - cmistake(u, ord, 771, MSG_EVENT); - return 0; - } - } - - /* snotlings können Talente nur bis T8 lernen */ - if (u->race == new_race[RC_SNOTLING]){ - if (get_level(u, sk) >= 8){ - cmistake(u, ord, 308, MSG_EVENT); - return 0; - } - } - - p = studycost = study_cost(u, sk); - a = a_find(u->attribs, &at_learning); - if (a!=NULL) { - teach = (teaching_info*)a->data.v; - } - - /* keine kostenpflichtigen Talente für Migranten. Vertraute sind - * keine Migranten, wird in is_migrant abgefangen. Vorsicht, - * studycost darf hier noch nicht durch Akademie erhöht sein */ - if (studycost > 0 && !ExpensiveMigrants() && is_migrant(u)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_migrants_nolearn", "")); - return 0; - } - /* Akademie: */ - { - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - - if (btype == bt_find("academy")) { - studycost = MAX(50, studycost * 2); - } - } - - if (sk == SK_MAGIC) { - if (u->number > 1){ - cmistake(u, ord, 106, MSG_MAGIC); - return 0; - } - if (is_familiar(u)){ - /* Vertraute zählen nicht zu den Magiern einer Partei, - * können aber nur Graue Magie lernen */ - mtyp = M_GRAY; - if (!is_mage(u)) create_mage(u, mtyp); - } else if (!has_skill(u, SK_MAGIC)) { - int mmax = skill_limit(u->faction, SK_MAGIC); - /* Die Einheit ist noch kein Magier */ - if (count_skill(u->faction, SK_MAGIC) + u->number > mmax) - { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_magicians", "amount", mmax)); - return 0; - } - mtyp = getmagicskill(u->faction->locale); - if (mtyp == M_NONE || mtyp == M_GRAY) { - /* wurde kein Magiegebiet angegeben, wird davon - * ausgegangen, daß das normal gelernt werden soll */ - if(u->faction->magiegebiet != 0) { - mtyp = u->faction->magiegebiet; - } else { - /* Es wurde kein Magiegebiet angegeben und die Partei - * hat noch keins gewählt. */ - mtyp = getmagicskill(u->faction->locale); - if (mtyp==M_NONE) { - cmistake(u, ord, 178, MSG_MAGIC); - return 0; - } - } - } - if (mtyp != u->faction->magiegebiet){ - /* Es wurde versucht, ein anderes Magiegebiet zu lernen - * als das der Partei */ - if (u->faction->magiegebiet != 0){ - cmistake(u, ord, 179, MSG_MAGIC); - return 0; - } else { - /* Lernt zum ersten mal Magie und legt damit das - * Magiegebiet der Partei fest */ - u->faction->magiegebiet = mtyp; - } - } - if (!is_mage(u)) create_mage(u, mtyp); - } else { - /* ist schon ein Magier und kein Vertrauter */ - if (u->faction->magiegebiet == 0) { - /* die Partei hat noch kein Magiegebiet gewählt. */ - mtyp = getmagicskill(u->faction->locale); - if (mtyp == M_NONE){ - mtyp = getmagicskill(u->faction->locale); - if (mtyp==M_NONE) { - cmistake(u, ord, 178, MSG_MAGIC); - return 0; - } - } - /* Legt damit das Magiegebiet der Partei fest */ - u->faction->magiegebiet = mtyp; - } - } - } - if (sk == SK_ALCHEMY) { - maxalchemy = eff_skill(u, SK_ALCHEMY, r); - if (!has_skill(u, SK_ALCHEMY)) { - int amax = skill_limit(u->faction, SK_ALCHEMY); - if (count_skill(u->faction, SK_ALCHEMY) + u->number > amax) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_alchemists", "amount", amax)); - return 0; - } - } - } - if (studycost) { - int cost = studycost * u->number; - money = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, cost); - money = MIN(money, cost); - } - if (money < studycost * u->number) { - studycost = p; /* Ohne Univertreurung */ - money = MIN(money, studycost); - if (p>0 && money < studycost * u->number) { - cmistake(u, ord, 65, MSG_EVENT); - multi = money / (double)(studycost * u->number); - } - } - - if (teach==NULL) { - a = a_add(&u->attribs, a_new(&at_learning)); - teach = (teaching_info*)a->data.v; - teach->teachers[0] = 0; - } - if (money>0) { - use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, money); - ADDMSG(&u->faction->msgs, msg_message("studycost", - "unit region cost skill", u, u->region, money, sk)); - } - - if (get_effect(u, oldpotiontype[P_WISE])) { - l = MIN(u->number, get_effect(u, oldpotiontype[P_WISE])); - teach->value += l * 10; - change_effect(u, oldpotiontype[P_WISE], -l); - } - if (get_effect(u, oldpotiontype[P_FOOL])) { - l = MIN(u->number, get_effect(u, oldpotiontype[P_FOOL])); - teach->value -= l * 30; - change_effect(u, oldpotiontype[P_FOOL], -l); - } - - if (p != studycost) { - /* ist_in_gebaeude(r, u, BT_UNIVERSITAET) == 1) { */ - /* p ist Kosten ohne Uni, studycost mit; wenn - * p!=studycost, ist die Einheit zwangsweise - * in einer Uni */ - teach->value += u->number * 10; - } - - if (is_cursed(r->attribs, C_BADLEARN,0)) { - teach->value -= u->number * 10; - } - - multi *= study_speedup(u); - days = study_days(u, sk); - days = (int)((days + teach->value) * multi); - - /* the artacademy currently improves the learning of entertainment - of all units in the region, to be able to make it cumulative with - with an academy */ - - if (sk == SK_ENTERTAINMENT && buildingtype_exists(r, bt_find("artacademy"), false)) { - days *= 2; - } - - if (fval(u, UFL_HUNGER)) days /= 2; - - while (days) { - if (days>=u->number*30) { - learn_skill(u, sk, 1.0); - days -= u->number*30; - } else { - double chance = (double)days/u->number/30; - learn_skill(u, sk, chance); - days = 0; - } - } - if (a!=NULL) { - if (teach!=NULL) { - int index = 0; - while (teach->teachers[index] && index!=MAXTEACHERS) { - unit * teacher = teach->teachers[index++]; - if (teacher->faction != u->faction) { - boolean feedback = alliedunit(u, teacher->faction, HELP_GUARD); - if (feedback) { - ADDMSG(&teacher->faction->msgs, msg_message("teach_teacher", - "teacher student skill level", teacher, u, sk, - effskill(u, sk))); - } - ADDMSG(&u->faction->msgs, msg_message("teach_student", - "teacher student skill", teacher, u, sk)); - } - } - } - a_remove(&u->attribs, a); - a = NULL; - } - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - - /* Anzeigen neuer Tränke */ - /* Spruchlistenaktualiesierung ist in Regeneration */ - - if (sk == SK_ALCHEMY) { - const potion_type * ptype; - faction * f = u->faction; - int skill = eff_skill(u, SK_ALCHEMY, r); - if (skill>maxalchemy) { - for (ptype=potiontypes; ptype; ptype=ptype->next) { - if (skill == ptype->level * 2) { - attrib * a = a_find(f->attribs, &at_showitem); - while (a && a->type==&at_showitem && a->data.v != ptype) a=a->next; - if (a==NULL || a->type!=&at_showitem) { - a = a_add(&f->attribs, a_new(&at_showitem)); - a->data.v = (void*) ptype->itype; - } - } - } - } - } - else if (sk==SK_MAGIC) { - sc_mage * mage = get_mage(u); - if (!mage) { - mage = create_mage(u, u->faction->magiegebiet); - } - } - - return 0; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#define TEACH_ALL 1 +#define TEACH_FRIENDS + +#include +#include +#include "study.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include + +#define TEACHNUMBER 10 + +static skill_t +getskill(const struct locale * lang) +{ + return findskill(getstrtoken(), lang); +} + +magic_t +getmagicskill(const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_MAGIC); + variant token; + const char * s = getstrtoken(); + + if (s && s[0]) { + if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { + return (magic_t)token.i; + } else { + char buffer[3]; + buffer[0] = s[0]; + buffer[1] = s[1]; + buffer[2] = '\0'; + if (findtoken(tokens, buffer, &token)==E_TOK_SUCCESS) { + return (magic_t)token.i; + } + } + } + return M_NONE; +} + +/* ------------------------------------------------------------- */ +/* Vertraute und Kröten sind keine Migranten */ +boolean +is_migrant(unit *u) +{ + if (u->race == u->faction->race) return false; + + if (fval(u->race, RCF_UNDEAD|RCF_ILLUSIONARY)) return false; + if (is_familiar(u)) return false; + if (u->race == new_race[RC_TOAD]) return false; + + return true; +} + +/* ------------------------------------------------------------- */ +boolean +magic_lowskill(unit *u) +{ + if (u->race == new_race[RC_TOAD]) return true; + return false; +} + +/* ------------------------------------------------------------- */ + +int +study_cost(unit *u, skill_t sk) +{ + static int cost[MAXSKILLS]; + int stufe, k = 50; + + if (cost[sk]==0) { + char buffer[256]; + sprintf(buffer, "skills.cost.%s", skillnames[sk]); + cost[sk] = get_param_int(global.parameters, buffer, -1); + } + if (cost[sk]>=0) return cost[sk]; + + switch (sk) { + case SK_SPY: + return 100; + break; + case SK_TACTICS: + case SK_HERBALISM: + case SK_ALCHEMY: + return 200; + break; + case SK_MAGIC: /* Die Magiekosten betragen 50+Summe(50*Stufe) */ + /* 'Stufe' ist dabei die nächste zu erreichende Stufe */ + stufe = 1 + get_level(u, SK_MAGIC); + return k*(1+((stufe+1)*stufe/2)); + break; + } + return 0; +} + +/* ------------------------------------------------------------- */ + +static void +init_learning(struct attrib * a) +{ + a->data.v = calloc(sizeof(teaching_info), 1); +} + +static void +done_learning(struct attrib * a) +{ + free(a->data.v); +} + +const attrib_type at_learning = { + "learning", + init_learning, done_learning, NULL, NULL, NULL, + ATF_UNIQUE +}; + +static int +study_days(unit * student, skill_t sk) +{ + int speed = 30; + if (student->race->study_speed) { + speed += student->race->study_speed[sk]; + if (speed<30) { + skill * sv = get_skill(student, sk); + if (sv==0) { + speed = 30; + } + } + } + return student->number * speed; +} + +static int +teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, + boolean report, int * academy) +{ + teaching_info * teach = NULL; + attrib * a; + int n; + + /* learning sind die Tage, die sie schon durch andere Lehrer zugute + * geschrieben bekommen haben. Total darf dies nicht über 30 Tage pro Mann + * steigen. + * + * n ist die Anzahl zusätzlich gelernter Tage. n darf max. die Differenz + * von schon gelernten Tagen zum MAX(30 Tage pro Mann) betragen. */ + + if (magic_lowskill(student)){ + cmistake(teacher, teacher->thisorder, 292, MSG_EVENT); + return 0; + } + + n = 30; + a = a_find(student->attribs, &at_learning); + if (a!=NULL) { + teach = (teaching_info*)a->data.v; + n -= teach->value; + } + + n = MIN(n, nteaching); + + if (n != 0) { + struct building * b = inside_building(teacher); + const struct building_type * btype = b?b->type:NULL; + int index = 0; + + if (teach==NULL) { + a = a_add(&student->attribs, a_new(&at_learning)); + teach = (teaching_info*)a->data.v; + } else { + while (teach->teachers[index] && index!=MAXTEACHERS) ++index; + } + if (indexteachers[index++] = teacher; + if (indexteachers[index] = NULL; + teach->value += n; + + /* Solange Akademien größenbeschränkt sind, sollte Lehrer und + * Student auch in unterschiedlichen Gebäuden stehen dürfen */ + if (btype == bt_find("academy") + && student->building && student->building->type == bt_find("academy")) + { + int j = study_cost(student, sk); + j = MAX(50, j * 2); + /* kann Einheit das zahlen? */ + if (get_pooled(student, oldresourcetype[R_SILVER], GET_DEFAULT, j) >= j) { + /* Jeder Schüler zusätzlich +10 Tage wenn in Uni. */ + teach->value += (n / 30) * 10; /* learning erhöhen */ + /* Lehrer zusätzlich +1 Tag pro Schüler. */ + if (academy) *academy += n; + } /* sonst nehmen sie nicht am Unterricht teil */ + } + + /* Teaching ist die Anzahl Leute, denen man noch was beibringen kann. Da + * hier nicht n verwendet wird, werden die Leute gezählt und nicht die + * effektiv gelernten Tage. -> FALSCH ? (ENNO) + * + * Eine Einheit A von 11 Mann mit Talent 0 profitiert vom ersten Lehrer B + * also 10x30=300 tage, und der zweite Lehrer C lehrt für nur noch 1x30=30 + * Tage (damit das Maximum von 11x30=330 nicht überschritten wird). + * + * Damit es aber in der Ausführung nicht auf die Reihenfolge drauf ankommt, + * darf der zweite Lehrer C keine weiteren Einheiten D mehr lehren. Also + * wird student 30 Tage gutgeschrieben, aber teaching sinkt auf 0 (300-11x30 <= + * 0). + * + * Sonst träte dies auf: + * + * A: lernt B: lehrt A C: lehrt A D D: lernt + * + * Wenn B vor C dran ist, lehrt C nur 30 Tage an A (wie oben) und + * 270 Tage an D. + * + * Ist C aber vor B dran, lehrt C 300 tage an A, und 0 tage an D, + * und B lehrt auch 0 tage an A. + * + * Deswegen darf C D nie lehren dürfen. + * + * -> Das ist wirr. wer hat das entworfen? + * Besser wäre, man macht erst vorab alle zuordnungen, und dann + * die Talentänderung (enno). + */ + + nteaching = MAX(0, nteaching - student->number * 30); + + } + return n; +} + +int +teach_cmd(unit * u, struct order * ord) +{ + static const curse_type * gbdream_ct = NULL; + plane * pl; + region * r = u->region; + int teaching, i, j, count, academy=0; + unit *u2; + skill_t sk = NOSKILL; + + if (gbdream_ct==0) gbdream_ct = ct_find("gbdream"); + if (gbdream_ct) { + if (get_curse(u->region->attribs, gbdream_ct)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "gbdream_noteach", "")); + return 0; + } + } + + if ((u->race->flags & RCF_NOTEACH) || fval(u, UFL_WERE)) { + cmistake(u, ord, 274, MSG_EVENT); + return 0; + } + + pl = rplane(r); + if (pl && fval(pl, PFL_NOTEACH)) { + cmistake(u, ord, 273, MSG_EVENT); + return 0; + } + + teaching = u->number * 30 * TEACHNUMBER; + + if ((i = get_effect(u, oldpotiontype[P_FOOL])) > 0) { /* Trank "Dumpfbackenbrot" */ + i = MIN(i, u->number * TEACHNUMBER); + /* Trank wirkt pro Schüler, nicht pro Lehrer */ + teaching -= i * 30; + change_effect(u, oldpotiontype[P_FOOL], -i); + j = teaching / 30; + ADDMSG(&u->faction->msgs, msg_message("teachdumb", + "teacher amount", u, j)); + } + if (teaching == 0) return 0; + + + u2 = 0; + count = 0; + + init_tokens(ord); + skip_token(); + +#if TEACH_ALL + if (getparam(u->faction->locale)==P_ANY) { + unit * student = r->units; + skill_t teachskill[MAXSKILLS]; + int i = 0; + do { + sk = getskill(u->faction->locale); + teachskill[i++]=sk; + } while (sk!=NOSKILL); + while (teaching && student) { + if (student->faction == u->faction) { +#ifdef NEW_DAEMONHUNGER_RULE + if (LongHunger(student)) continue; +#else + if (fval(student, UFL_HUNGER)) continue; +#endif + if (get_keyword(student->thisorder) == K_STUDY) { + /* Input ist nun von student->thisorder !! */ + init_tokens(student->thisorder); + skip_token(); + sk = getskill(student->faction->locale); + if (sk!=NOSKILL && teachskill[0]!=NOSKILL) { + for (i=0;teachskill[i]!=NOSKILL;++i) if (sk==teachskill[i]) break; + sk = teachskill[i]; + } + if (sk != NOSKILL && eff_skill_study(u, sk, r)-TEACHDIFFERENCE > eff_skill_study(student, sk, r)) { + teaching -= teach_unit(u, student, teaching, sk, true, &academy); + } + } + } + student = student->next; + } +#ifdef TEACH_FRIENDS + while (teaching && student) { + if (student->faction != u->faction && alliedunit(u, student->faction, HELP_GUARD)) { +#ifdef NEW_DAEMONHUNGER_RULE + if (LongHunger(student)) continue; +#else + if (fval(student, UFL_HUNGER)) continue; +#endif + if (get_keyword(student->thisorder) == K_STUDY) { + /* Input ist nun von student->thisorder !! */ + init_tokens(student->thisorder); + skip_token(); + sk = getskill(student->faction->locale); + if (sk != NOSKILL && eff_skill_study(u, sk, r)-TEACHDIFFERENCE >= eff_skill(student, sk, r)) { + teaching -= teach_unit(u, student, teaching, sk, true, &academy); + } + } + } + student = student->next; + } +#endif + } + else +#endif + { + char zOrder[4096]; + order * new_order; + + zOrder[0] = '\0'; + init_tokens(ord); + skip_token(); + + while (!parser_end()) { + unit * u2 = getunit(r, u->faction); + boolean feedback; + ++count; + + /* Falls die Unit nicht gefunden wird, Fehler melden */ + + if (!u2) { + char tbuf[20]; + const char * uid; + const char * token; + /* Finde den string, der den Fehler verursacht hat */ + parser_pushstate(); + init_tokens(ord); + skip_token(); + + for (j=0; j!=count-1; ++j) { + /* skip over the first 'count' units */ + getunit(r, u->faction); + } + + token = getstrtoken(); + + /* Beginne die Fehlermeldung */ + if (findparam(token, u->faction->locale) != P_TEMP) { + uid = token; + } else { + token = getstrtoken(); + sprintf(tbuf, "%s %s", LOC(u->faction->locale, + parameters[P_TEMP]), token); + uid = tbuf; + } + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unitnotfound_id", + "id", uid)); + + parser_popstate(); + continue; + } + + feedback = u->faction==u2->faction || alliedunit(u2, u->faction, HELP_GUARD); + + /* Neuen Befehl zusammenbauen. TEMP-Einheiten werden automatisch in + * ihre neuen Nummern übersetzt. */ + if (zOrder[0]) strcat(zOrder, " "); + strcat(zOrder, unitid(u2)); + + if (get_keyword(u2->thisorder) != K_STUDY) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "teach_nolearn", "student", u2)); + continue; + } + + /* Input ist nun von u2->thisorder !! */ + parser_pushstate(); + init_tokens(u2->thisorder); + skip_token(); + sk = getskill(u2->faction->locale); + parser_popstate(); + + if (sk == NOSKILL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "teach_nolearn", "student", u2)); + continue; + } + + /* u is teacher, u2 is student */ + if (eff_skill_study(u2, sk, r) > eff_skill_study(u, sk, r)-TEACHDIFFERENCE) { + if (feedback) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "teach_asgood", "student", u2)); + } + continue; + } + if (sk == SK_MAGIC) { + /* ist der Magier schon spezialisiert, so versteht er nur noch + * Lehrer seines Gebietes */ + sc_mage * mage1 = get_mage(u); + sc_mage * mage2 = get_mage(u2); + if (!mage2 || !mage1 || (mage2->magietyp!=M_GRAY && mage1->magietyp!=mage2->magietyp)) { + if (feedback) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_different_magic", "target", u2)); + } + continue; + } + } + + teaching -= teach_unit(u, u2, teaching, sk, false, &academy); + } + new_order = create_order(K_TEACH, u->faction->locale, "%s", zOrder); + replace_order(&u->orders, ord, new_order); + free_order(new_order); /* parse_order & set_order have each increased the refcount */ + } + if (academy && sk!=NOSKILL) { + academy = academy/30; /* anzahl gelehrter wochen, max. 10 */ + learn_skill(u, sk, academy/30.0/TEACHNUMBER); + } + return 0; +} + +static double +study_speedup(unit * u) +{ +#define MINTURN 5 /* 5 */ +#define OFSTURN 2 /* 2 */ + if (turn>MINTURN) { + static int speed_rule = -1; + if (speed_rule<0) { + speed_rule = get_param_int(global.parameters, "study.speedup", 0); + } + if (speed_rule==1) { + double learn_age = OFSTURN; + int i; + for (i=0;i!=u->skill_size;++i) { + skill * sv = u->skills+i; + double learn_time = sv->level*(sv->level+1)/2.0; + learn_age += learn_time; + } + if (learn_age < turn) { + return 2.0-learn_age/turn; + } + } + } + return 1.0; +} + +int +learn_cmd(unit * u, order * ord) +{ + region *r = u->region; + int p; + magic_t mtyp; + int l; + int studycost, days; + double multi = 1.0; + attrib * a = NULL; + teaching_info * teach = NULL; + int money = 0; + skill_t sk; + int maxalchemy = 0; + static int learn_newskills = -1; + if (learn_newskills<0) { + const char * str = get_param(global.parameters, "study.newskills"); + if (str && strcmp(str, "false")==0) learn_newskills = 0; + else learn_newskills = 1; + } + + if ((u->race->flags & RCF_NOLEARN) || fval(u, UFL_WERE)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_race_nolearn", "race", u->race)); + return 0; + } + + init_tokens(ord); + skip_token(); + sk = getskill(u->faction->locale); + + if (sk < 0) { + cmistake(u, ord, 77, MSG_EVENT); + return 0; + } + if (SkillCap(sk) && SkillCap(sk) <= effskill(u, sk)) { + cmistake(u, ord, 771, MSG_EVENT); + return 0; + } + /* Hack: Talente mit Malus -99 können nicht gelernt werden */ + if (u->race->bonus[sk] == -99) { + cmistake(u, ord, 771, MSG_EVENT); + return 0; + } + if (learn_newskills==0) { + skill * sv = get_skill(u, sk); + if (sv==NULL) { + /* we can only learn skills we already have */ + cmistake(u, ord, 771, MSG_EVENT); + return 0; + } + } + + /* snotlings können Talente nur bis T8 lernen */ + if (u->race == new_race[RC_SNOTLING]){ + if (get_level(u, sk) >= 8){ + cmistake(u, ord, 308, MSG_EVENT); + return 0; + } + } + + p = studycost = study_cost(u, sk); + a = a_find(u->attribs, &at_learning); + if (a!=NULL) { + teach = (teaching_info*)a->data.v; + } + + /* keine kostenpflichtigen Talente für Migranten. Vertraute sind + * keine Migranten, wird in is_migrant abgefangen. Vorsicht, + * studycost darf hier noch nicht durch Akademie erhöht sein */ + if (studycost > 0 && !ExpensiveMigrants() && is_migrant(u)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_migrants_nolearn", "")); + return 0; + } + /* Akademie: */ + { + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + + if (btype == bt_find("academy")) { + studycost = MAX(50, studycost * 2); + } + } + + if (sk == SK_MAGIC) { + if (u->number > 1){ + cmistake(u, ord, 106, MSG_MAGIC); + return 0; + } + if (is_familiar(u)){ + /* Vertraute zählen nicht zu den Magiern einer Partei, + * können aber nur Graue Magie lernen */ + mtyp = M_GRAY; + if (!is_mage(u)) create_mage(u, mtyp); + } else if (!has_skill(u, SK_MAGIC)) { + int mmax = skill_limit(u->faction, SK_MAGIC); + /* Die Einheit ist noch kein Magier */ + if (count_skill(u->faction, SK_MAGIC) + u->number > mmax) + { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_magicians", "amount", mmax)); + return 0; + } + mtyp = getmagicskill(u->faction->locale); + if (mtyp == M_NONE || mtyp == M_GRAY) { + /* wurde kein Magiegebiet angegeben, wird davon + * ausgegangen, daß das normal gelernt werden soll */ + if(u->faction->magiegebiet != 0) { + mtyp = u->faction->magiegebiet; + } else { + /* Es wurde kein Magiegebiet angegeben und die Partei + * hat noch keins gewählt. */ + mtyp = getmagicskill(u->faction->locale); + if (mtyp==M_NONE) { + cmistake(u, ord, 178, MSG_MAGIC); + return 0; + } + } + } + if (mtyp != u->faction->magiegebiet){ + /* Es wurde versucht, ein anderes Magiegebiet zu lernen + * als das der Partei */ + if (u->faction->magiegebiet != 0){ + cmistake(u, ord, 179, MSG_MAGIC); + return 0; + } else { + /* Lernt zum ersten mal Magie und legt damit das + * Magiegebiet der Partei fest */ + u->faction->magiegebiet = mtyp; + } + } + if (!is_mage(u)) create_mage(u, mtyp); + } else { + /* ist schon ein Magier und kein Vertrauter */ + if (u->faction->magiegebiet == 0) { + /* die Partei hat noch kein Magiegebiet gewählt. */ + mtyp = getmagicskill(u->faction->locale); + if (mtyp == M_NONE){ + mtyp = getmagicskill(u->faction->locale); + if (mtyp==M_NONE) { + cmistake(u, ord, 178, MSG_MAGIC); + return 0; + } + } + /* Legt damit das Magiegebiet der Partei fest */ + u->faction->magiegebiet = mtyp; + } + } + } + if (sk == SK_ALCHEMY) { + maxalchemy = eff_skill(u, SK_ALCHEMY, r); + if (!has_skill(u, SK_ALCHEMY)) { + int amax = skill_limit(u->faction, SK_ALCHEMY); + if (count_skill(u->faction, SK_ALCHEMY) + u->number > amax) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_alchemists", "amount", amax)); + return 0; + } + } + } + if (studycost) { + int cost = studycost * u->number; + money = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, cost); + money = MIN(money, cost); + } + if (money < studycost * u->number) { + studycost = p; /* Ohne Univertreurung */ + money = MIN(money, studycost); + if (p>0 && money < studycost * u->number) { + cmistake(u, ord, 65, MSG_EVENT); + multi = money / (double)(studycost * u->number); + } + } + + if (teach==NULL) { + a = a_add(&u->attribs, a_new(&at_learning)); + teach = (teaching_info*)a->data.v; + teach->teachers[0] = 0; + } + if (money>0) { + use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, money); + ADDMSG(&u->faction->msgs, msg_message("studycost", + "unit region cost skill", u, u->region, money, sk)); + } + + if (get_effect(u, oldpotiontype[P_WISE])) { + l = MIN(u->number, get_effect(u, oldpotiontype[P_WISE])); + teach->value += l * 10; + change_effect(u, oldpotiontype[P_WISE], -l); + } + if (get_effect(u, oldpotiontype[P_FOOL])) { + l = MIN(u->number, get_effect(u, oldpotiontype[P_FOOL])); + teach->value -= l * 30; + change_effect(u, oldpotiontype[P_FOOL], -l); + } + + if (p != studycost) { + /* ist_in_gebaeude(r, u, BT_UNIVERSITAET) == 1) { */ + /* p ist Kosten ohne Uni, studycost mit; wenn + * p!=studycost, ist die Einheit zwangsweise + * in einer Uni */ + teach->value += u->number * 10; + } + + if (is_cursed(r->attribs, C_BADLEARN,0)) { + teach->value -= u->number * 10; + } + + multi *= study_speedup(u); + days = study_days(u, sk); + days = (int)((days + teach->value) * multi); + + /* the artacademy currently improves the learning of entertainment + of all units in the region, to be able to make it cumulative with + with an academy */ + + if (sk == SK_ENTERTAINMENT && buildingtype_exists(r, bt_find("artacademy"), false)) { + days *= 2; + } + + if (fval(u, UFL_HUNGER)) days /= 2; + + while (days) { + if (days>=u->number*30) { + learn_skill(u, sk, 1.0); + days -= u->number*30; + } else { + double chance = (double)days/u->number/30; + learn_skill(u, sk, chance); + days = 0; + } + } + if (a!=NULL) { + if (teach!=NULL) { + int index = 0; + while (teach->teachers[index] && index!=MAXTEACHERS) { + unit * teacher = teach->teachers[index++]; + if (teacher->faction != u->faction) { + boolean feedback = alliedunit(u, teacher->faction, HELP_GUARD); + if (feedback) { + ADDMSG(&teacher->faction->msgs, msg_message("teach_teacher", + "teacher student skill level", teacher, u, sk, + effskill(u, sk))); + } + ADDMSG(&u->faction->msgs, msg_message("teach_student", + "teacher student skill", teacher, u, sk)); + } + } + } + a_remove(&u->attribs, a); + a = NULL; + } + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + + /* Anzeigen neuer Tränke */ + /* Spruchlistenaktualiesierung ist in Regeneration */ + + if (sk == SK_ALCHEMY) { + const potion_type * ptype; + faction * f = u->faction; + int skill = eff_skill(u, SK_ALCHEMY, r); + if (skill>maxalchemy) { + for (ptype=potiontypes; ptype; ptype=ptype->next) { + if (skill == ptype->level * 2) { + attrib * a = a_find(f->attribs, &at_showitem); + while (a && a->type==&at_showitem && a->data.v != ptype) a=a->next; + if (a==NULL || a->type!=&at_showitem) { + a = a_add(&f->attribs, a_new(&at_showitem)); + a->data.v = (void*) ptype->itype; + } + } + } + } + } + else if (sk==SK_MAGIC) { + sc_mage * mage = get_mage(u); + if (!mage) { + mage = create_mage(u, u->faction->magiegebiet); + } + } + + return 0; +} diff --git a/src/gamecode/study.h b/src/gamecode/study.h index 6ea695a26..83c39605a 100644 --- a/src/gamecode/study.h +++ b/src/gamecode/study.h @@ -1,45 +1,45 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_STUDY -#define H_KRNL_STUDY - -#ifdef __cplusplus -extern "C" { -#endif - -extern int teach_cmd(struct unit * u, struct order * ord); -extern int learn_cmd(struct unit * u, struct order * ord); - -extern magic_t getmagicskill(const struct locale * lang); -extern boolean is_migrant(struct unit *u); -extern int study_cost(struct unit *u, skill_t talent); - -#define MAXTEACHERS 4 -typedef struct teaching_info { - struct unit * teachers[MAXTEACHERS]; - int value; -} teaching_info; - -extern const struct attrib_type at_learning; - -#ifdef __cplusplus -} -#endif - -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_STUDY +#define H_KRNL_STUDY + +#ifdef __cplusplus +extern "C" { +#endif + +extern int teach_cmd(struct unit * u, struct order * ord); +extern int learn_cmd(struct unit * u, struct order * ord); + +extern magic_t getmagicskill(const struct locale * lang); +extern boolean is_migrant(struct unit *u); +extern int study_cost(struct unit *u, skill_t talent); + +#define MAXTEACHERS 4 +typedef struct teaching_info { + struct unit * teachers[MAXTEACHERS]; + int value; +} teaching_info; + +extern const struct attrib_type at_learning; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/gamecode/summary.c b/src/gamecode/summary.c index 5e16a53c4..015ce278c 100644 --- a/src/gamecode/summary.c +++ b/src/gamecode/summary.c @@ -1,413 +1,413 @@ -/* vi: set ts=2: - * +-------------------+ Christian Schlittchen - * | | Enno Rehling - * | Eressea PBEM host | Katja Zedel - * | (c) 1998 - 2007 | - * | | This program may not be used, modified or distributed - * +-------------------+ without prior permission by the authors of Eressea. - * - */ - -/* wenn platform.h nicht vor curses included wird, kompiliert es unter windows nicht */ -#include -#include - -#include "summary.h" - -#include "laws.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#undef SUMMARY_BOM /* write a BOM in the summary file */ - -typedef struct summary { - int waffen; - int factions; - int ruestungen; - int schiffe; - int gebaeude; - int maxskill; - int heroes; - int inhabitedregions; - int peasants; - int nunits; - int playerpop; - double playermoney; - double peasantmoney; - int armed_men; - int poprace[MAXRACES]; - int factionrace[MAXRACES]; - int landregionen; - int regionen_mit_spielern; - int landregionen_mit_spielern; - int orkifizierte_regionen; - int inactive_volcanos; - int active_volcanos; - int spielerpferde; - int pferde; - struct language { - struct language * next; - int number; - const struct locale * locale; - } * languages; -} summary; - -static char * -pcomp(double i, double j) -{ - static char buf[32]; - sprintf(buf, "%.0f (%s%.0f)", i, (i>=j)?"+":"", i-j); - return buf; -} - -static char * -rcomp(int i, int j) -{ - static char buf[32]; - sprintf(buf, "%d (%s%d,%s%d%%)", - i, (i>=j)?"+":"", i-j, (i>=j)?"+":"",j?((i-j)*100)/j:0); - return buf; -} - - -static void -out_faction(FILE *file, const struct faction *f) -{ - if (alliances!=NULL) { - fprintf(file, "%s (%s/%d) (%.3s/%.3s), %d Einh., %d Pers., $%d, %d NMR\n", - f->name, itoa36(f->no), f_get_alliance(f)?f->alliance->id:0, - LOC(default_locale, rc_name(f->race, 0)), magic_school[f->magiegebiet], - f->no_units, f->num_total, f->money, turn - f->lastorders); - } else { - fprintf(file, "%s (%.3s/%.3s), %d Einh., %d Pers., $%d, %d NMR\n", - factionname(f), LOC(default_locale, rc_name(f->race, 0)), - magic_school[f->magiegebiet], f->no_units, f->num_total, f->money, - turn - f->lastorders); - } -} - -static char * -gamedate2(const struct locale * lang) -{ - static char buf[256]; - gamedate gd; - - get_gamedate(turn, &gd); - sprintf(buf, "in %s des Monats %s im Jahre %d %s.", - LOC(lang, weeknames2[gd.week]), - LOC(lang, monthnames[gd.month]), - gd.year, - agename?LOC(lang, agename):""); - return buf; -} - -static void -writeturn(void) -{ - char zText[MAX_PATH]; - FILE *f; - - sprintf(zText, "%s/datum", basepath()); - f = cfopen(zText, "w"); - if (!f) return; - fputs(gamedate2(default_locale), f); - fclose(f); - sprintf(zText, "%s/turn", basepath()); - f = cfopen(zText, "w"); - if (!f) return; - fprintf(f, "%d\n", turn); - fclose(f); -} - -void -report_summary(summary * s, summary * o, boolean full) -{ - FILE * F = NULL; - int i, newplayers = 0; - faction * f; - char zText[MAX_PATH]; - - if (full) { - sprintf(zText, "%s/parteien.full", basepath()); - } else { - sprintf(zText, "%s/parteien", basepath()); - } - F = cfopen(zText, "w"); - if (!F) return; -#ifdef SUMMARY_BOM - else { - const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; - fwrite(utf8_bom, 1, 3, F); - } -#endif - printf("Schreibe Zusammenfassung (parteien)...\n"); - fprintf(F, "%s\n%s\n\n", global.gamename, gamedate2(default_locale)); - fprintf(F, "Auswertung Nr: %d\n\n", turn); - fprintf(F, "Parteien: %s\n", pcomp(s->factions, o->factions)); - fprintf(F, "Einheiten: %s\n", pcomp(s->nunits, o->nunits)); - fprintf(F, "Spielerpopulation: %s\n", - pcomp(s->playerpop, o->playerpop)); - fprintf(F, " davon bewaffnet: %s\n", - pcomp(s->armed_men, o->armed_men)); - fprintf(F, " Helden: %s\n", pcomp(s->heroes, o->heroes)); - - if (full) { - fprintf(F, "Regionen: %d\n", listlen(regions)); - fprintf(F, "Bewohnte Regionen: %d\n", s->inhabitedregions); - fprintf(F, "Landregionen: %d\n", s->landregionen); - fprintf(F, "Spielerregionen: %d\n", s->regionen_mit_spielern); - fprintf(F, "Landspielerregionen: %d\n", s->landregionen_mit_spielern); - fprintf(F, "Orkifizierte Regionen: %d\n", s->orkifizierte_regionen); - fprintf(F, "Inaktive Vulkane: %d\n", s->inactive_volcanos); - fprintf(F, "Aktive Vulkane: %d\n\n", s->active_volcanos); - } - - for (i = 0; i < MAXRACES; i++) { - const race * rc = new_race[i]; - if (s->factionrace[i] && rc && playerrace(rc) - && i != RC_TEMPLATE && i != RC_CLONE) { - fprintf(F, "%13s%s: %s\n", LOC(default_locale, rc_name(rc, 3)), LOC(default_locale, "stat_tribe_p"), - pcomp(s->factionrace[i], o->factionrace[i])); - } - } - - if(full) { - fprintf(F, "\n"); - { - struct language * plang = s->languages; - while (plang!=NULL) { - struct language * olang = o->languages; - int nold = 0; - while (olang && olang->locale!=plang->locale) olang=olang->next; - if (olang) nold = olang->number; - fprintf(F, "Sprache %12s: %s\n", locale_name(plang->locale), - rcomp(plang->number, nold)); - plang=plang->next; - } - } - } - - fprintf(F, "\n"); - if (full) { - for (i = 0; i < MAXRACES; i++) { - const race * rc = new_race[i]; - if (s->poprace[i]) { - fprintf(F, "%20s: %s\n", LOC(default_locale, rc_name(rc, 1)), - rcomp(s->poprace[i], o->poprace[i])); - } - } - } else { - for (i = 0; i < MAXRACES; i++) { - const race * rc = new_race[i]; - if (s->poprace[i] && playerrace(rc) - && i != RC_TEMPLATE && i != RC_CLONE) { - fprintf(F, "%20s: %s\n", LOC(default_locale, rc_name(rc, 1)), - rcomp(s->poprace[i], o->poprace[i])); - } - } - } - - if (full) { - fprintf(F, "\nWaffen: %s\n", pcomp(s->waffen,o->waffen)); - fprintf(F, "Ruestungen: %s\n", - pcomp(s->ruestungen,o->ruestungen)); - fprintf(F, "ungezaehmte Pferde: %s\n", pcomp(s->pferde, o->pferde)); - fprintf(F, "gezaehmte Pferde: %s\n", - pcomp(s->spielerpferde,o->spielerpferde)); - fprintf(F, "Schiffe: %s\n", pcomp(s->schiffe, o->schiffe)); - fprintf(F, "Gebaeude: %s\n", pcomp(s->gebaeude, o->gebaeude)); - - fprintf(F, "\nBauernpopulation: %s\n", pcomp(s->peasants,o->peasants)); - - fprintf(F, "Population gesamt: %d\n\n", s->playerpop+s->peasants); - - fprintf(F, "Reichtum Spieler: %s Silber\n", - pcomp(s->playermoney,o->playermoney)); - fprintf(F, "Reichtum Bauern: %s Silber\n", - pcomp(s->peasantmoney, o->peasantmoney)); - fprintf(F, "Reichtum gesamt: %s Silber\n\n", - pcomp(s->playermoney+s->peasantmoney, o->playermoney+o->peasantmoney)); - } - - fprintf(F, "\n\n"); - - newplayers = update_nmrs(); - - for (i = 0; i <= NMRTimeout(); ++i) { - if (i == NMRTimeout()) { - fprintf(F, "+ NMR:\t\t %d\n", nmrs[i]); - } else { - fprintf(F, "%d NMR:\t\t %d\n", i, nmrs[i]); - } - } - if (age) { - if (age[2] != 0) { - fprintf(F, "Erstabgaben:\t %d%%\n", 100 - (dropouts[0] * 100 / age[2])); - } - if (age[3] != 0) { - fprintf(F, "Zweitabgaben:\t %d%%\n", 100 - (dropouts[1] * 100 / age[3])); - } - } - fprintf(F, "Neue Spieler:\t %d\n", newplayers); - - if (full) { - if (factions) - fprintf(F, "\nParteien:\n\n"); - - for (f = factions; f; f = f->next) { - out_faction(F, f); - } - - if (NMRTimeout() && full) { - fprintf(F, "\n\nFactions with NMRs:\n"); - for (i = NMRTimeout(); i > 0; --i) { - for(f=factions; f; f=f->next) { - if(i == NMRTimeout()) { - if(turn - f->lastorders >= i) { - out_faction(F, f); - } - } else { - if(turn - f->lastorders == i) { - out_faction(F, f); - } - } - } - } - } - } - - fclose(F); - - if (full) { - printf("writing date & turn\n"); - writeturn(); - } - free(nmrs); - nmrs = NULL; -} - -summary * -make_summary(void) -{ - faction *f; - region *r; - unit *u; - summary * s = calloc(1, sizeof(summary)); - - for (f = factions; f; f = f->next) { - const struct locale * lang = f->locale; - struct language * plang = s->languages; - while (plang && plang->locale != lang) plang=plang->next; - if (!plang) { - plang = calloc(sizeof(struct language), 1); - plang->next = s->languages; - s->languages = plang; - plang->locale = lang; - } - ++plang->number; - f->nregions = 0; - f->num_total = 0; - f->money = 0; - if (f->alive && f->units) { - s->factions++; - /* Problem mit Monsterpartei ... */ - if (!is_monsters(f)) { - s->factionrace[old_race(f->race)]++; - } - } - } - - /* Alles zählen */ - - for (r = regions; r; r = r->next) { - s->pferde += rhorses(r); - s->schiffe += listlen(r->ships); - s->gebaeude += listlen(r->buildings); - if (!fval(r->terrain, SEA_REGION)) { - s->landregionen++; - if (r->units) { - s->landregionen_mit_spielern++; - } - if (fval(r, RF_ORCIFIED)) { - s->orkifizierte_regionen++; - } - if (r->terrain == newterrain(T_VOLCANO)) { - s->inactive_volcanos++; - } else if (r->terrain == newterrain(T_VOLCANO_SMOKING)) { - s->active_volcanos++; - } - } - if (r->units) { - s->regionen_mit_spielern++; - } - if (rpeasants(r) || r->units) { - s->inhabitedregions++; - s->peasants += rpeasants(r); - s->peasantmoney += rmoney(r); - - /* Einheiten Info. nregions darf nur einmal pro Partei - * incrementiert werden. */ - - for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT); - for (u = r->units; u; u = u->next) { - f = u->faction; - if (!is_monsters(u->faction)) { - skill * sv; - item * itm; - - s->nunits++; - s->playerpop += u->number; - if (u->flags & UFL_HERO) { - s->heroes += u->number; - } - s->spielerpferde += get_item(u, I_HORSE); - s->playermoney += get_money(u); - s->armed_men += armedmen(u, true); - for (itm=u->items;itm;itm=itm->next) { - if (itm->type->rtype->wtype) { - s->waffen += itm->number; - } - if (itm->type->rtype->atype) { - s->ruestungen += itm->number; - } - } - - s->spielerpferde += get_item(u, I_HORSE); - - for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - skill_t sk = sv->id; - int aktskill = eff_skill(u, sk, r); - if (aktskill > s->maxskill) s->maxskill = aktskill; - } - if (!fval(f, FFL_SELECT)) { - f->nregions++; - fset(f, FFL_SELECT); - } - } - - f->num_total += u->number; - f->money += get_money(u); - s->poprace[old_race(u->race)] += u->number; - } - } - } - - return s; -} +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2007 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +/* wenn platform.h nicht vor curses included wird, kompiliert es unter windows nicht */ +#include +#include + +#include "summary.h" + +#include "laws.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#undef SUMMARY_BOM /* write a BOM in the summary file */ + +typedef struct summary { + int waffen; + int factions; + int ruestungen; + int schiffe; + int gebaeude; + int maxskill; + int heroes; + int inhabitedregions; + int peasants; + int nunits; + int playerpop; + double playermoney; + double peasantmoney; + int armed_men; + int poprace[MAXRACES]; + int factionrace[MAXRACES]; + int landregionen; + int regionen_mit_spielern; + int landregionen_mit_spielern; + int orkifizierte_regionen; + int inactive_volcanos; + int active_volcanos; + int spielerpferde; + int pferde; + struct language { + struct language * next; + int number; + const struct locale * locale; + } * languages; +} summary; + +static char * +pcomp(double i, double j) +{ + static char buf[32]; + sprintf(buf, "%.0f (%s%.0f)", i, (i>=j)?"+":"", i-j); + return buf; +} + +static char * +rcomp(int i, int j) +{ + static char buf[32]; + sprintf(buf, "%d (%s%d,%s%d%%)", + i, (i>=j)?"+":"", i-j, (i>=j)?"+":"",j?((i-j)*100)/j:0); + return buf; +} + + +static void +out_faction(FILE *file, const struct faction *f) +{ + if (alliances!=NULL) { + fprintf(file, "%s (%s/%d) (%.3s/%.3s), %d Einh., %d Pers., $%d, %d NMR\n", + f->name, itoa36(f->no), f_get_alliance(f)?f->alliance->id:0, + LOC(default_locale, rc_name(f->race, 0)), magic_school[f->magiegebiet], + f->no_units, f->num_total, f->money, turn - f->lastorders); + } else { + fprintf(file, "%s (%.3s/%.3s), %d Einh., %d Pers., $%d, %d NMR\n", + factionname(f), LOC(default_locale, rc_name(f->race, 0)), + magic_school[f->magiegebiet], f->no_units, f->num_total, f->money, + turn - f->lastorders); + } +} + +static char * +gamedate2(const struct locale * lang) +{ + static char buf[256]; + gamedate gd; + + get_gamedate(turn, &gd); + sprintf(buf, "in %s des Monats %s im Jahre %d %s.", + LOC(lang, weeknames2[gd.week]), + LOC(lang, monthnames[gd.month]), + gd.year, + agename?LOC(lang, agename):""); + return buf; +} + +static void +writeturn(void) +{ + char zText[MAX_PATH]; + FILE *f; + + sprintf(zText, "%s/datum", basepath()); + f = cfopen(zText, "w"); + if (!f) return; + fputs(gamedate2(default_locale), f); + fclose(f); + sprintf(zText, "%s/turn", basepath()); + f = cfopen(zText, "w"); + if (!f) return; + fprintf(f, "%d\n", turn); + fclose(f); +} + +void +report_summary(summary * s, summary * o, boolean full) +{ + FILE * F = NULL; + int i, newplayers = 0; + faction * f; + char zText[MAX_PATH]; + + if (full) { + sprintf(zText, "%s/parteien.full", basepath()); + } else { + sprintf(zText, "%s/parteien", basepath()); + } + F = cfopen(zText, "w"); + if (!F) return; +#ifdef SUMMARY_BOM + else { + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + fwrite(utf8_bom, 1, 3, F); + } +#endif + printf("Schreibe Zusammenfassung (parteien)...\n"); + fprintf(F, "%s\n%s\n\n", global.gamename, gamedate2(default_locale)); + fprintf(F, "Auswertung Nr: %d\n\n", turn); + fprintf(F, "Parteien: %s\n", pcomp(s->factions, o->factions)); + fprintf(F, "Einheiten: %s\n", pcomp(s->nunits, o->nunits)); + fprintf(F, "Spielerpopulation: %s\n", + pcomp(s->playerpop, o->playerpop)); + fprintf(F, " davon bewaffnet: %s\n", + pcomp(s->armed_men, o->armed_men)); + fprintf(F, " Helden: %s\n", pcomp(s->heroes, o->heroes)); + + if (full) { + fprintf(F, "Regionen: %d\n", listlen(regions)); + fprintf(F, "Bewohnte Regionen: %d\n", s->inhabitedregions); + fprintf(F, "Landregionen: %d\n", s->landregionen); + fprintf(F, "Spielerregionen: %d\n", s->regionen_mit_spielern); + fprintf(F, "Landspielerregionen: %d\n", s->landregionen_mit_spielern); + fprintf(F, "Orkifizierte Regionen: %d\n", s->orkifizierte_regionen); + fprintf(F, "Inaktive Vulkane: %d\n", s->inactive_volcanos); + fprintf(F, "Aktive Vulkane: %d\n\n", s->active_volcanos); + } + + for (i = 0; i < MAXRACES; i++) { + const race * rc = new_race[i]; + if (s->factionrace[i] && rc && playerrace(rc) + && i != RC_TEMPLATE && i != RC_CLONE) { + fprintf(F, "%13s%s: %s\n", LOC(default_locale, rc_name(rc, 3)), LOC(default_locale, "stat_tribe_p"), + pcomp(s->factionrace[i], o->factionrace[i])); + } + } + + if(full) { + fprintf(F, "\n"); + { + struct language * plang = s->languages; + while (plang!=NULL) { + struct language * olang = o->languages; + int nold = 0; + while (olang && olang->locale!=plang->locale) olang=olang->next; + if (olang) nold = olang->number; + fprintf(F, "Sprache %12s: %s\n", locale_name(plang->locale), + rcomp(plang->number, nold)); + plang=plang->next; + } + } + } + + fprintf(F, "\n"); + if (full) { + for (i = 0; i < MAXRACES; i++) { + const race * rc = new_race[i]; + if (s->poprace[i]) { + fprintf(F, "%20s: %s\n", LOC(default_locale, rc_name(rc, 1)), + rcomp(s->poprace[i], o->poprace[i])); + } + } + } else { + for (i = 0; i < MAXRACES; i++) { + const race * rc = new_race[i]; + if (s->poprace[i] && playerrace(rc) + && i != RC_TEMPLATE && i != RC_CLONE) { + fprintf(F, "%20s: %s\n", LOC(default_locale, rc_name(rc, 1)), + rcomp(s->poprace[i], o->poprace[i])); + } + } + } + + if (full) { + fprintf(F, "\nWaffen: %s\n", pcomp(s->waffen,o->waffen)); + fprintf(F, "Ruestungen: %s\n", + pcomp(s->ruestungen,o->ruestungen)); + fprintf(F, "ungezaehmte Pferde: %s\n", pcomp(s->pferde, o->pferde)); + fprintf(F, "gezaehmte Pferde: %s\n", + pcomp(s->spielerpferde,o->spielerpferde)); + fprintf(F, "Schiffe: %s\n", pcomp(s->schiffe, o->schiffe)); + fprintf(F, "Gebaeude: %s\n", pcomp(s->gebaeude, o->gebaeude)); + + fprintf(F, "\nBauernpopulation: %s\n", pcomp(s->peasants,o->peasants)); + + fprintf(F, "Population gesamt: %d\n\n", s->playerpop+s->peasants); + + fprintf(F, "Reichtum Spieler: %s Silber\n", + pcomp(s->playermoney,o->playermoney)); + fprintf(F, "Reichtum Bauern: %s Silber\n", + pcomp(s->peasantmoney, o->peasantmoney)); + fprintf(F, "Reichtum gesamt: %s Silber\n\n", + pcomp(s->playermoney+s->peasantmoney, o->playermoney+o->peasantmoney)); + } + + fprintf(F, "\n\n"); + + newplayers = update_nmrs(); + + for (i = 0; i <= NMRTimeout(); ++i) { + if (i == NMRTimeout()) { + fprintf(F, "+ NMR:\t\t %d\n", nmrs[i]); + } else { + fprintf(F, "%d NMR:\t\t %d\n", i, nmrs[i]); + } + } + if (age) { + if (age[2] != 0) { + fprintf(F, "Erstabgaben:\t %d%%\n", 100 - (dropouts[0] * 100 / age[2])); + } + if (age[3] != 0) { + fprintf(F, "Zweitabgaben:\t %d%%\n", 100 - (dropouts[1] * 100 / age[3])); + } + } + fprintf(F, "Neue Spieler:\t %d\n", newplayers); + + if (full) { + if (factions) + fprintf(F, "\nParteien:\n\n"); + + for (f = factions; f; f = f->next) { + out_faction(F, f); + } + + if (NMRTimeout() && full) { + fprintf(F, "\n\nFactions with NMRs:\n"); + for (i = NMRTimeout(); i > 0; --i) { + for(f=factions; f; f=f->next) { + if(i == NMRTimeout()) { + if(turn - f->lastorders >= i) { + out_faction(F, f); + } + } else { + if(turn - f->lastorders == i) { + out_faction(F, f); + } + } + } + } + } + } + + fclose(F); + + if (full) { + printf("writing date & turn\n"); + writeturn(); + } + free(nmrs); + nmrs = NULL; +} + +summary * +make_summary(void) +{ + faction *f; + region *r; + unit *u; + summary * s = calloc(1, sizeof(summary)); + + for (f = factions; f; f = f->next) { + const struct locale * lang = f->locale; + struct language * plang = s->languages; + while (plang && plang->locale != lang) plang=plang->next; + if (!plang) { + plang = calloc(sizeof(struct language), 1); + plang->next = s->languages; + s->languages = plang; + plang->locale = lang; + } + ++plang->number; + f->nregions = 0; + f->num_total = 0; + f->money = 0; + if (f->alive && f->units) { + s->factions++; + /* Problem mit Monsterpartei ... */ + if (!is_monsters(f)) { + s->factionrace[old_race(f->race)]++; + } + } + } + + /* Alles zählen */ + + for (r = regions; r; r = r->next) { + s->pferde += rhorses(r); + s->schiffe += listlen(r->ships); + s->gebaeude += listlen(r->buildings); + if (!fval(r->terrain, SEA_REGION)) { + s->landregionen++; + if (r->units) { + s->landregionen_mit_spielern++; + } + if (fval(r, RF_ORCIFIED)) { + s->orkifizierte_regionen++; + } + if (r->terrain == newterrain(T_VOLCANO)) { + s->inactive_volcanos++; + } else if (r->terrain == newterrain(T_VOLCANO_SMOKING)) { + s->active_volcanos++; + } + } + if (r->units) { + s->regionen_mit_spielern++; + } + if (rpeasants(r) || r->units) { + s->inhabitedregions++; + s->peasants += rpeasants(r); + s->peasantmoney += rmoney(r); + + /* Einheiten Info. nregions darf nur einmal pro Partei + * incrementiert werden. */ + + for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT); + for (u = r->units; u; u = u->next) { + f = u->faction; + if (!is_monsters(u->faction)) { + skill * sv; + item * itm; + + s->nunits++; + s->playerpop += u->number; + if (u->flags & UFL_HERO) { + s->heroes += u->number; + } + s->spielerpferde += get_item(u, I_HORSE); + s->playermoney += get_money(u); + s->armed_men += armedmen(u, true); + for (itm=u->items;itm;itm=itm->next) { + if (itm->type->rtype->wtype) { + s->waffen += itm->number; + } + if (itm->type->rtype->atype) { + s->ruestungen += itm->number; + } + } + + s->spielerpferde += get_item(u, I_HORSE); + + for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { + skill_t sk = sv->id; + int aktskill = eff_skill(u, sk, r); + if (aktskill > s->maxskill) s->maxskill = aktskill; + } + if (!fval(f, FFL_SELECT)) { + f->nregions++; + fset(f, FFL_SELECT); + } + } + + f->num_total += u->number; + f->money += get_money(u); + s->poprace[old_race(u->race)] += u->number; + } + } + } + + return s; +} diff --git a/src/gamecode/summary.h b/src/gamecode/summary.h index f7419a30b..e1a665d53 100644 --- a/src/gamecode/summary.h +++ b/src/gamecode/summary.h @@ -1,25 +1,25 @@ -/* vi: set ts=2: - * +-------------------+ Christian Schlittchen - * | | Enno Rehling - * | Eressea PBEM host | Katja Zedel - * | (c) 1998 - 2007 | - * | | This program may not be used, modified or distributed - * +-------------------+ without prior permission by the authors of Eressea. - * - */ - -#ifndef H_GC_SUMMARY -#define H_GC_SUMMARY - -#ifdef __cplusplus -extern "C" { -#endif - - struct summary; - extern void report_summary(struct summary * n, struct summary * o, boolean full); - extern struct summary * make_summary(void); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2007 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +#ifndef H_GC_SUMMARY +#define H_GC_SUMMARY + +#ifdef __cplusplus +extern "C" { +#endif + + struct summary; + extern void report_summary(struct summary * n, struct summary * o, boolean full); + extern struct summary * make_summary(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gmtool.c b/src/gmtool.c index 5d1ce1227..2fab96186 100644 --- a/src/gmtool.c +++ b/src/gmtool.c @@ -1,1298 +1,1296 @@ -/* vi: set ts=2: - * +-------------------+ Christian Schlittchen - * | | Enno Rehling - * | Eressea PBEM host | Katja Zedel - * | (c) 1998 - 2006 | - * | | This program may not be used, modified or distributed - * +-------------------+ without prior permission by the authors of Eressea. - * - */ - -/* wenn platform.h nicht vor curses included wird, kompiliert es unter windows nicht */ -#include -#include -#include - -#include "gmtool.h" -#include "gmtool_structs.h" - -#include -#include -#if MUSEUM_MODULE -#include -#endif -#if ARENA_MODULE -#include -#endif -#include -#include -#if DUNGEON_MODULE -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include - -static int g_quit; -int force_color = 0; - -state * current_state = NULL; - -#define IFL_SHIPS (1<<0) -#define IFL_UNITS (1<<1) -#define IFL_FACTIONS (1<<2) -#define IFL_BUILDINGS (1<<3) - -static WINDOW * hstatus; - -static void -init_curses(void) -{ - short fg, bg; - initscr(); - - if (has_colors() || force_color) { - short bcol = COLOR_BLACK; - short hcol = COLOR_MAGENTA; - start_color(); -#ifdef WIN32 - /* looks crap on putty with TERM=linux */ - if (can_change_color()) { - init_color(COLOR_YELLOW, 1000, 1000, 0); - } -#endif - - for (fg=0;fg!=8;++fg) { - for (bg=0;bg!=2;++bg) { - init_pair(fg+8*bg, fg, bg?hcol:bcol); - } - } - - attrset(COLOR_PAIR(COLOR_BLACK)); - bkgd(' ' | COLOR_PAIR(COLOR_BLACK)); - bkgdset(' ' | COLOR_PAIR(COLOR_BLACK)); - } - - keypad(stdscr, TRUE); /* enable keyboard mapping */ - meta(stdscr, TRUE); - nonl(); /* tell curses not to do NL->CR/NL on output */ - cbreak(); /* take input chars one at a time, no wait for \n */ - noecho(); /* don't echo input */ - scrollok(stdscr, FALSE); - refresh(); -} - -void cnormalize(const coordinate * c, int * x, int * y) -{ - *x = c->x; - *y = c->y; - pnormalize(x, y, c->pl); -} - -map_region * -mr_get(const view * vi, int xofs, int yofs) -{ - return vi->regions + xofs + yofs * vi->size.width; -} - -static point * -coor2point(const coordinate * c, point * p) -{ - assert(c && p); - p->x = c->x * TWIDTH + c->y * TWIDTH / 2; - p->y = c->y * THEIGHT; - return p; -} - -static window * wnd_first, * wnd_last; - -static window * -win_create(WINDOW * hwin) -{ - window * wnd = calloc(1, sizeof(window)); - wnd->handle = hwin; - if (wnd_first!=NULL) { - wnd->next = wnd_first; - wnd_first->prev = wnd; - wnd_first = wnd; - } else { - wnd_first = wnd; - wnd_last = wnd; - } - return wnd; -} - -static void -untag_region(selection * s, int nx, int ny) -{ - unsigned int key = ((nx << 12) ^ ny); - tag ** tp = &s->tags[key & (MAXTHASH-1)]; - tag * t = NULL; - while (*tp) { - t = *tp; - if (t->coord.x==nx && t->coord.y==ny) break; - tp=&t->nexthash; - } - if (!*tp) return; - *tp = t->nexthash; - free(t); - return; -} - -static void -tag_region(selection * s, int nx, int ny) -{ - unsigned int key = ((nx << 12) ^ ny); - tag ** tp = &s->tags[key & (MAXTHASH-1)]; - while (*tp) { - tag * t = *tp; - if (t->coord.x==nx && t->coord.y==ny) return; - tp=&t->nexthash; - } - *tp = calloc(1, sizeof(tag)); - (*tp)->coord.x = nx; - (*tp)->coord.y = ny; - (*tp)->coord.pl = findplane(nx, ny); - return; -} - -static int -tagged_region(selection * s, int nx, int ny) -{ - unsigned int key = ((nx << 12) ^ ny); - tag ** tp = &s->tags[key & (MAXTHASH-1)]; - while (*tp) { - tag * t = *tp; - if (t->coord.x==nx && t->coord.y==ny) return 1; - tp=&t->nexthash; - } - return 0; -} - -static int -mr_tile(const map_region * mr, int highlight) -{ - int hl = 8 * highlight; - if (mr!=NULL && mr->r!=NULL) { - const region * r = mr->r; - switch (r->terrain->_name[0]) { - case 'o' : - return '.' | COLOR_PAIR(hl + COLOR_CYAN); - case 'd' : - return 'D' | COLOR_PAIR(hl + COLOR_YELLOW) | A_BOLD; - case 't' : - return '%' | COLOR_PAIR(hl + COLOR_YELLOW) | A_BOLD; - case 'f' : - if (r->terrain->_name[1]=='o') { /* fog */ - return '.' | COLOR_PAIR(hl + COLOR_YELLOW) | A_NORMAL; - } else if (r->terrain->_name[1]=='i') { /* firewall */ - return '%' | COLOR_PAIR(hl + COLOR_RED) | A_BOLD; - } - case 'h' : - return 'H' | COLOR_PAIR(hl + COLOR_YELLOW) | A_NORMAL; - case 'm' : - return '^' | COLOR_PAIR(hl + COLOR_WHITE) | A_NORMAL; - case 'p' : - if (r_isforest(r)) return '#' | COLOR_PAIR(hl + COLOR_GREEN) | A_NORMAL; - return '+' | COLOR_PAIR(hl + COLOR_GREEN) | A_BOLD; - case 'g' : - return '*' | COLOR_PAIR(hl + COLOR_WHITE) | A_BOLD; - case 's' : - return 'S' | COLOR_PAIR(hl + COLOR_MAGENTA) | A_NORMAL; - } - return r->terrain->_name[0] | COLOR_PAIR(hl + COLOR_RED); - } - return ' ' | COLOR_PAIR(hl + COLOR_WHITE); -} - -static void -paint_map(window * wnd, const state * st) -{ - WINDOW * win = wnd->handle; - int lines = getmaxy(win); - int cols = getmaxx(win); - int vx, vy; - - lines = lines/THEIGHT; - cols = cols/TWIDTH; - for (vy = 0; vy!=lines; ++vy) { - int yp = (lines - vy - 1) * THEIGHT; - for (vx = 0; vx!=cols; ++vx) { - map_region * mr = mr_get(&st->display, vx, vy); - int attr = 0; - int hl = 0; - int xp = vx * TWIDTH + (vy & 1) * TWIDTH/2; - int nx, ny; - if (mr) { - if (st) { - cnormalize(&mr->coord, &nx, &ny); - if (tagged_region(st->selected, nx, ny)) { - attr |= A_REVERSE; - } - } - if (mr->r && mr->r->flags & RF_MAPPER_HIGHLIGHT) hl = 1; - mvwaddch(win, yp, xp, mr_tile(mr, hl) | attr); - } - } - } -} - -map_region * -cursor_region(const view * v, const coordinate * c) -{ - coordinate relpos; - int cx, cy; - - if (c) { - relpos.x = c->x - v->topleft.x; - relpos.y = c->y - v->topleft.y; - cy = relpos.y; - cx = relpos.x + cy/2; - return mr_get(v, cx, cy); - } - return NULL; -} - -static void -draw_cursor(WINDOW * win, selection * s, const view * v, const coordinate * c, int show) -{ - int lines = getmaxy(win)/THEIGHT; - int xp, yp, nx, ny; - int attr = 0; - map_region * mr = cursor_region(v, c); - coordinate relpos; - int cx, cy; - - if (!mr) return; - - relpos.x = c->x - v->topleft.x; - relpos.y = c->y - v->topleft.y; - cy = relpos.y; - cx = relpos.x + cy/2; - - yp = (lines - cy - 1) * THEIGHT; - xp = cx * TWIDTH + (cy & 1) * TWIDTH/2; - cnormalize(&mr->coord, &nx, &ny); - if (s && tagged_region(s, nx, ny)) attr = A_REVERSE; - if (mr->r) { - int hl = 0; - if (mr->r->flags & RF_MAPPER_HIGHLIGHT) hl = 1; - mvwaddch(win, yp, xp, mr_tile(mr, hl) | attr); - } - else mvwaddch(win, yp, xp, ' ' | attr | COLOR_PAIR(COLOR_YELLOW)); - if (show) { - attr = A_BOLD; - mvwaddch(win, yp, xp-1, '<' | attr | COLOR_PAIR(COLOR_YELLOW)); - mvwaddch(win, yp, xp+1, '>' | attr | COLOR_PAIR(COLOR_YELLOW)); - } else { - attr = A_NORMAL; - mvwaddch(win, yp, xp-1, ' ' | attr | COLOR_PAIR(COLOR_WHITE)); - mvwaddch(win, yp, xp+1, ' ' | attr | COLOR_PAIR(COLOR_WHITE)); - } - wmove(win, yp, xp); - wnoutrefresh(win); -} - - - -static void -paint_status(window * wnd, const state * st) -{ - WINDOW * win = wnd->handle; - const char * name = ""; - int nx, ny, uid = 0; - const char * terrain = "----"; - map_region * mr = cursor_region(&st->display, &st->cursor); - if (mr && mr->r) { - uid = mr->r->uid; - if (mr->r->land) { - name = (const char *)mr->r->land->name; - } else { - name = mr->r->terrain->_name; - } - terrain = mr->r->terrain->_name; - } - cnormalize(&st->cursor, &nx, &ny); - mvwprintw(win, 0, 0, "%4d %4d | %.4s | %.20s (%d)", nx, ny, terrain, name, uid); - wclrtoeol(win); -} - -static boolean -handle_info_region(window * wnd, state * st, int c) -{ - return false; -} - -static void -paint_info_region(window * wnd, const state * st) -{ - WINDOW * win = wnd->handle; - int size = getmaxx(win)-2; - int line = 0, maxline = getmaxy(win)-2; - map_region * mr = cursor_region(&st->display, &st->cursor); - - unused(st); - werase(win); - wxborder(win); - if (mr && mr->r) { - const region * r = mr->r; - if (r->land) { - mvwaddnstr(win, line++, 1, (char *)r->land->name, size); - } else { - mvwaddnstr(win, line++, 1, r->terrain->_name, size); - } - line++; - mvwprintw(win, line++, 1, "%s, age %d", r->terrain->_name, r->age); - if (r->land) { - mvwprintw(win, line++, 1, "$:%6d P:%5d", r->land->money, r->land->peasants); - mvwprintw(win, line++, 1, "H:%6d %s:%5d", r->land->horses, (r->flags&RF_MALLORN)?"M":"T", r->land->trees[1]+r->land->trees[2]); - } - line++; - if (r->ships && (st->info_flags & IFL_SHIPS)) { - ship * sh; - wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - mvwaddnstr(win, line++, 1, "* ships:", size-5); - wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - for (sh=r->ships;sh && linenext) { - mvwprintw(win, line, 1, "%.4s ", itoa36(sh->no)); - mvwaddnstr(win, line++, 6, (char*)sh->type->name[0], size-5); - } - } - if (r->units && (st->info_flags & IFL_FACTIONS)) { - unit * u; - wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - mvwaddnstr(win, line++, 1, "* factions:", size-5); - wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - for (u=r->units;u && linenext) { - if (!fval(u->faction, FFL_MARK)) { - mvwprintw(win, line, 1, "%.4s ", itoa36(u->faction->no)); - mvwaddnstr(win, line++, 6, (char *)u->faction->name, size-5); - fset(u->faction, FFL_MARK); - } - } - for (u=r->units;u && linenext) { - freset(u->faction, FFL_MARK); - } - } - if (r->units && (st->info_flags & IFL_UNITS)) { - unit * u; - wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - mvwaddnstr(win, line++, 1, "* units:", size-5); - wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - for (u=r->units;u && linenext) { - mvwprintw(win, line, 1, "%.4s ", itoa36(u->no)); - mvwaddnstr(win, line++, 6, (char *)u->name, size-5); - } - } - } -} - -static void (*paint_info)(struct window * wnd, const struct state * st); - -static void -paint_info_default(window * wnd, const state * st) -{ - if (paint_info) paint_info(wnd, st); - else paint_info_region(wnd, st); -} - -void set_info_function(void (*callback)(struct window *, const struct state *)) -{ - paint_info = callback; -} - -static char * -askstring(WINDOW * win, const char * q, char * buffer, size_t size) -{ - werase(win); - mvwaddstr(win, 0, 0, (char*)q); - wmove(win, 0, (int)(strlen(q)+1)); - echo(); - wgetnstr(win, buffer, (int)size); - noecho(); - return buffer; -} - -static void -statusline(WINDOW * win, const char * str) -{ - mvwaddstr(win, 0, 0, (char*)str); - wclrtoeol(win); - wnoutrefresh(win); -} - -static void -terraform_at(coordinate * c, const terrain_type *terrain) -{ - if (terrain!=NULL) { - region * r; - int nx = c->x, ny = c->y; - pnormalize(&nx, &ny, c->pl); - r = findregion(nx, ny); - if (r==NULL) { - r = new_region(nx, ny, c->pl, 0); - } - terraform_region(r, terrain); - } -} - -static void -terraform_selection(selection * selected, const terrain_type *terrain) -{ - int i; - - if (terrain==NULL) return; - for (i=0;i!=MAXTHASH;++i) { - tag ** tp = &selected->tags[i]; - while (*tp) { - region * r; - tag * t = *tp; - int nx = t->coord.x, ny = t->coord.y; - plane * pl = t->coord.pl; - - pnormalize(&nx, &ny, pl); - r = findregion(nx, ny); - if (r==NULL) { - r = new_region(nx, ny, pl, 0); - } - terraform_region(r, terrain); - tp = &t->nexthash; - } - } -} - -static faction * -select_faction(state * st) -{ - list_selection *prev, *ilist = NULL, **iinsert; - list_selection *selected = NULL; - faction * f = factions; - - if (!f) return NULL; - iinsert = &ilist; - prev = ilist; - - while (f) { - char buffer[32]; - sprintf(buffer, "%.4s %.26s", itoa36(f->no), f->name); - insert_selection(iinsert, NULL, buffer, (void*)f); - f = f->next; - } - selected = do_selection(ilist, "Select Faction", NULL, NULL); - st->wnd_info->update |= 1; - st->wnd_map->update |= 1; - st->wnd_status->update |= 1; - - if (selected==NULL) return NULL; - return (faction*)selected->data; -} - -static const terrain_type * -select_terrain(state * st, const terrain_type * default_terrain) -{ - list_selection *prev, *ilist = NULL, **iinsert; - list_selection *selected = NULL; - const terrain_type * terrain = terrains(); - - if (!terrain) return NULL; - iinsert = &ilist; - prev = ilist; - - while (terrain) { - insert_selection(iinsert, NULL, terrain->_name, (void*)terrain); - terrain = terrain->next; - } - selected = do_selection(ilist, "Terrain", NULL, NULL); - st->wnd_info->update |= 1; - st->wnd_map->update |= 1; - st->wnd_status->update |= 1; - - if (selected==NULL) return NULL; - return (const terrain_type*)selected->data; -} - -static coordinate * -region2coord(const region * r, coordinate * c) -{ - c->x = r->x; - c->y = r->y; - c->pl = rplane(r); - return c; -} - -#ifdef __PDCURSES__ -#define FAST_UP CTL_UP -#define FAST_DOWN CTL_DOWN -#define FAST_LEFT CTL_LEFT -#define FAST_RIGHT CTL_RIGHT -#else -#define FAST_UP KEY_PPAGE -#define FAST_DOWN KEY_NPAGE -#define FAST_LEFT KEY_SLEFT -#define FAST_RIGHT KEY_SRIGHT -#endif - -void -highlight_region(region *r, int toggle) -{ - if (r!=NULL) { - if (toggle) r->flags |= RF_MAPPER_HIGHLIGHT; - else r->flags &= ~RF_MAPPER_HIGHLIGHT; - } -} - -void -select_coordinate(struct selection * selected, int nx, int ny, int toggle) -{ - if (toggle) tag_region(selected, nx, ny); - else untag_region(selected, nx, ny); -} - -enum { MODE_MARK, MODE_SELECT, MODE_UNMARK, MODE_UNSELECT }; - -static void -select_regions(state * st, int selectmode) -{ - char sbuffer[80]; - int findmode; - const char * statustext[] = { - "mark-", "select-", "unmark-", "deselect-" - }; - const char * status = statustext[selectmode]; - statusline(st->wnd_status->handle, status); - doupdate(); - findmode = getch(); - if (findmode=='n') { /* none */ - int i; - sprintf(sbuffer, "%snone", status); - statusline(st->wnd_status->handle, sbuffer); - if (selectmode&MODE_SELECT) { - for (i=0;i!=MAXTHASH;++i) { - tag ** tp = &st->selected->tags[i]; - while (*tp) { - tag * t = *tp; - *tp = t->nexthash; - free(t); - } - } - } else { - region * r; - for (r=regions;r;r=r->next) { - r->flags &= ~RF_MAPPER_HIGHLIGHT; - } - } - } - else if (findmode=='m') { - region * r; - sprintf(sbuffer, "%smonsters", status); - statusline(st->wnd_status->handle, sbuffer); - for (r=regions;r;r=r->next) { - unit * u = r->units; - for (;u;u=u->next) { - if (fval(u->faction, FFL_NPC)!=0) break; - } - if (u) { - 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=='p') { - region * r; - sprintf(sbuffer, "%splayers", status); - statusline(st->wnd_status->handle, sbuffer); - for (r=regions;r;r=r->next) { - unit * u = r->units; - for (;u;u=u->next) { - if (fval(u->faction, FFL_NPC)==0) break; - } - if (u) { - 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=='u') { - region * r; - sprintf(sbuffer, "%sunits", status); - statusline(st->wnd_status->handle, sbuffer); - for (r=regions;r;r=r->next) { - if (r->units) { - 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=='s') { - region * r; - sprintf(sbuffer, "%sships", status); - statusline(st->wnd_status->handle, sbuffer); - for (r=regions;r;r=r->next) { - if (r->ships) { - 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=='f') { - char fbuffer[12]; - sprintf(sbuffer, "%sfaction:", status); - askstring(st->wnd_status->handle, sbuffer, fbuffer, 12); - if (fbuffer[0]) { - faction * f = findfaction(atoi36(fbuffer)); - - if (f!=NULL) { - unit * u; - - sprintf(sbuffer, "%sfaction: %s", status, itoa36(f->no)); - statusline(st->wnd_status->handle, sbuffer); - for (u=f->units;u;u=u->nextF) { - region * r = u->region; - if (selectmode&MODE_SELECT) { - select_coordinate(st->selected, r->x, r->y, selectmode==MODE_SELECT); - } else { - highlight_region(r, selectmode==MODE_MARK); - } - } - } else { - statusline(st->wnd_status->handle, "faction not found."); - beep(); - return; - } - } - } - else if (findmode=='t') { - const struct terrain_type * terrain; - sprintf(sbuffer, "%sterrain: ", status); - statusline(st->wnd_status->handle, sbuffer); - terrain = select_terrain(st, NULL); - if (terrain!=NULL) { - region * r; - sprintf(sbuffer, "%sterrain: %s", status, terrain->_name); - statusline(st->wnd_status->handle, sbuffer); - for (r=regions;r;r=r->next) { - if (r->terrain==terrain) { - if (selectmode&MODE_SELECT) { - select_coordinate(st->selected, r->x, r->y, selectmode==MODE_SELECT); - } else { - highlight_region(r, selectmode==MODE_MARK); - } - } - } - } - } else { - statusline(st->wnd_status->handle, "unknown command."); - beep(); - return; - } - st->wnd_info->update |= 3; - st->wnd_status->update |= 3; - st->wnd_map->update |= 3; -} - -static void -handlekey(state * st, int c) -{ - window * wnd; - coordinate * cursor = &st->cursor; - static char locate[80]; - static int findmode = 0; - region *r; - char sbuffer[80]; - static char kbuffer[80]; - int n, nx, ny; - - switch(c) { - case FAST_RIGHT: - cursor->x+=10; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case FAST_LEFT: - cursor->x-=10; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case FAST_UP: - cursor->y+=10; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case FAST_DOWN: - cursor->y-=10; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case KEY_UP: - cursor->y++; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case KEY_DOWN: - cursor->y--; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case KEY_RIGHT: - cursor->x++; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case KEY_LEFT: - cursor->x--; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case 'S': - case KEY_SAVE: - case KEY_F(2): - /* if (st->modified) */ { - char datafile[MAX_PATH]; - - askstring(st->wnd_status->handle, "save as:", datafile, sizeof(datafile)); - if (strlen(datafile)>0) { - create_backup(datafile); - remove_empty_units(); - writegame(datafile, IO_DEFAULT); - st->modified = 0; - } - } - break; - case 'B': - /* - make_block(st->cursor.x, st->cursor.y, 6, select_terrain(st, NULL)); - */ - cnormalize(&st->cursor, &nx, &ny); - n = rng_int() % 8 + 8; - build_island_e3(nx, ny, n, n*3); - st->modified = 1; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - st->wnd_map->update |= 1; - break; - case 0x02: /* CTRL+b */ - cnormalize(&st->cursor, &nx, &ny); - make_block(nx, ny, 6, newterrain(T_OCEAN)); - st->modified = 1; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - st->wnd_map->update |= 1; - break; - case 0x09: /* tab = next selected*/ - if (regions!=NULL) { - map_region * mr = cursor_region(&st->display, cursor); - if (mr) { - region * first = mr->r; - region * cur = (first&&first->next)?first->next:regions; - - while (cur!=first) { - coordinate coord; - region2coord(cur, &coord); - cnormalize(&coord, &nx, &ny); - if (tagged_region(st->selected, nx, ny)) { - st->cursor = coord; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - } - cur = cur->next; - if (!cur && first) cur = regions; - } - } - } - break; - - case 'p': - if (planes) { - plane * pl = planes; - if (cursor->pl) { - while (pl && pl!=cursor->pl) { - pl = pl->next; - } - if (pl && pl->next) { - cursor->pl = pl->next; - } else { - cursor->pl = get_homeplane(); - } - } else { - cursor->pl = planes; - } - } - break; - - case 'a': - if (regions!=NULL) { - map_region * mr = cursor_region(&st->display, cursor); - if (mr && mr->r) { - region * cur = mr->r; - plane * pl = rplane(cur); - if (pl==NULL) { - cur = r_standard_to_astral(cur); - } else if (is_astral(cur)) { - cur = r_astral_to_standard(cur); - } else { - cur = NULL; - } - if (cur!=NULL) { - region2coord(cur, &st->cursor); - } else { - beep(); - } - } - } - break; - case 'g': - askstring(st->wnd_status->handle, "goto-x:", sbuffer, 12); - if (sbuffer[0]) { - askstring(st->wnd_status->handle, "goto-y:", sbuffer+16, 12); - if (sbuffer[16]) { - st->cursor.x = atoi(sbuffer); - st->cursor.y = atoi(sbuffer+16); - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - } - } - break; - case 0x14: /* C-t */ - terraform_at(&st->cursor, select_terrain(st, NULL)); - st->modified = 1; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - st->wnd_map->update |= 1; - break; - case 'I': - statusline(st->wnd_status->handle, "info-"); - doupdate(); - do { - c = getch(); - switch (c) { - case 's': - st->info_flags ^= IFL_SHIPS; - if (st->info_flags & IFL_SHIPS) statusline(st->wnd_status->handle, "info-ships true"); - else statusline(st->wnd_status->handle, "info-ships false"); - break; - case 'b': - st->info_flags ^= IFL_BUILDINGS; - if (st->info_flags & IFL_BUILDINGS) statusline(st->wnd_status->handle, "info-buildings true"); - else statusline(st->wnd_status->handle, "info-buildings false"); - case 'f': - st->info_flags ^= IFL_FACTIONS; - if (st->info_flags & IFL_FACTIONS) statusline(st->wnd_status->handle, "info-factions true"); - else statusline(st->wnd_status->handle, "info-factions false"); - break; - case 'u': - st->info_flags ^= IFL_UNITS; - if (st->info_flags & IFL_UNITS) statusline(st->wnd_status->handle, "info-units true"); - else statusline(st->wnd_status->handle, "info-units false"); - break; - case 27: /* esc */ - break; - default: - beep(); - c = 0; - } - } while (c==0); - break; - case 'L': - if (global.vm_state) { - move(0, 0); - refresh(); - lua_do((struct lua_State*)global.vm_state); - /* todo: do this from inside the script */ - clear(); - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - st->wnd_map->update |= 1; - } - break; - case 12: /* Ctrl-L */ - clear(); - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - st->wnd_map->update |= 1; - break; - case 'h': - select_regions(st, MODE_MARK); - break; - case 'H': - select_regions(st, MODE_UNMARK); - break; - case 't': - select_regions(st, MODE_SELECT); - break; - case 'T': - select_regions(st, MODE_UNSELECT); - break; - case ';': - statusline(st->wnd_status->handle, "tag-"); - doupdate(); - switch (getch()) { - case 't': - terraform_selection(st->selected, select_terrain(st, NULL)); - st->modified = 1; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - st->wnd_map->update |= 1; - break; - case 'm': - break; - default: - statusline(st->wnd_status->handle, "unknown command."); - beep(); - } - break; - case ' ': - cnormalize(cursor, &nx, &ny); - if (tagged_region(st->selected, nx, ny)) untag_region(st->selected, nx, ny); - else tag_region(st->selected, nx, ny); - break; - case 'A': - sprintf(sbuffer, "%s/newfactions", basepath()); - seed_players(sbuffer, false); - st->wnd_map->update |= 1; - break; - case '/': - statusline(st->wnd_status->handle, "find-"); - doupdate(); - findmode = getch(); - if (findmode=='r') { - askstring(st->wnd_status->handle, "find-region:", locate, sizeof(locate)); - } else if (findmode=='u') { - askstring(st->wnd_status->handle, "find-unit:", locate, sizeof(locate)); - } else if (findmode=='f') { - askstring(st->wnd_status->handle, "find-faction:", locate, sizeof(locate)); - } else if (findmode=='F') { - faction * f = select_faction(st); - if (f!=NULL) { - strcpy(locate, itoa36(f->no)); - findmode='f'; - } else { - break; - } - } else { - statusline(st->wnd_status->handle, "unknown command."); - beep(); - break; - } - /* achtung: fall-through ist absicht: */ - if (!strlen(locate)) break; - case 'n': - if (findmode=='u') { - unit * u = findunit(atoi36(locate)); - r = u?u->region:NULL; - } else if (findmode && regions!=NULL) { - struct faction * f = NULL; - map_region * mr = cursor_region(&st->display, cursor); - region * first = (mr && mr->r && mr->r->next)?mr->r->next:regions; - - if (findmode=='f') { - sprintf(sbuffer, "find-faction: %s", locate); - statusline(st->wnd_status->handle, sbuffer); - f = findfaction(atoi36(locate)); - if (f==NULL) { - statusline(st->wnd_status->handle, "faction not found."); - beep(); - break; - } - } - for (r=first;;) { - if (findmode=='r' && r->land && r->land->name && strstr((const char*)r->land->name, locate)) { - break; - } else if (findmode=='f') { - unit * u; - for (u=r->units;u;u=u->next) { - if (u->faction==f) { - break; - } - } - if (u) break; - } - r = r->next; - if (r==NULL) r = regions; - if (r==first) { - r = NULL; - statusline(st->wnd_status->handle, "not found."); - beep(); - break; - } - } - } else { - r = NULL; - } - if (r!=NULL) { - region2coord(r, &st->cursor); - } - break; - case 'Q': - g_quit = 1; - break; - default: - for (wnd=wnd_first;wnd!=NULL;wnd=wnd->next) { - if (wnd->handlekey) { - if (wnd->handlekey(wnd, st, c)) break; - } - } - if (wnd==NULL) { - if (kbuffer[0]==0) { - strcpy(kbuffer, "getch:"); - } - sprintf(sbuffer, " 0x%x", c); - strncat(kbuffer, sbuffer, sizeof(kbuffer)); - statusline(st->wnd_status->handle, kbuffer); - if (strlen(kbuffer)>70) kbuffer[0]=0; - } - break; - } -} - -static void -init_view(view * display, WINDOW * win) -{ - display->topleft.x = 1; - display->topleft.y = 1; - display->topleft.pl = get_homeplane(); - display->pl = get_homeplane(); - display->size.width = getmaxx(win)/TWIDTH; - display->size.height = getmaxy(win)/THEIGHT; - display->regions = calloc(display->size.height * display->size.width, sizeof(map_region)); -} - -static void -update_view(view * vi) -{ - int i, j; - for (i=0;i!=vi->size.width;++i) { - for (j=0;j!=vi->size.height;++j) { - map_region * mr = mr_get(vi, i, j); - mr->coord.x = vi->topleft.x + i - j/2; - mr->coord.y = vi->topleft.y + j; - mr->coord.pl = vi->pl; - pnormalize(&mr->coord.x, &mr->coord.y, mr->coord.pl); - mr->r = findregion(mr->coord.x, mr->coord.y); - } - } -} - -state * -state_open(void) -{ - state * st = calloc(sizeof(state), 1); - st->display.pl = get_homeplane(); - st->cursor.pl = get_homeplane(); - st->cursor.x = 0; - st->cursor.y = 0; - st->selected = calloc(1, sizeof(struct selection)); - st->modified = 0; - st->info_flags = 0xFFFFFFFF; - st->prev = current_state; - current_state = st; - return st; -} - -void -state_close(state * st) -{ - assert(st==current_state); - current_state = st->prev; - free(st); -} - -void -run_mapper(void) -{ - WINDOW * hwinstatus; - WINDOW * hwininfo; - WINDOW * hwinmap; - int width, height, x, y; - int split = 20, old_flags = log_flags; - state * st; - point tl; - - log_flags &= ~(LOG_CPERROR|LOG_CPWARNING); - init_curses(); - curs_set(1); - - set_readline(curses_readline); - - getbegyx(stdscr, x, y); - width = getmaxx(stdscr); - height = getmaxy(stdscr); - - hwinmap = subwin(stdscr, getmaxy(stdscr)-1, getmaxx(stdscr)-split, y, x); - hwininfo = subwin(stdscr, getmaxy(stdscr)-1, split, y, x+getmaxx(stdscr)-split); - hwinstatus = subwin(stdscr, 1, width, height-1, x); - - st = state_open(); - st->wnd_map = win_create(hwinmap); - st->wnd_map->paint = &paint_map; - st->wnd_map->update = 1; - st->wnd_info = win_create(hwininfo); - st->wnd_info->paint = &paint_info_default; - st->wnd_info->handlekey = &handle_info_region; - st->wnd_info->update = 1; - st->wnd_status = win_create(hwinstatus); - st->wnd_status->paint = &paint_status; - st->wnd_status->update = 1; - - init_view(&st->display, hwinmap); - coor2point(&st->display.topleft, &tl); - - hstatus = st->wnd_status->handle; /* the lua console needs this */ - - while (!g_quit) { - int c; - point p; - window * wnd; - view * vi = &st->display; - - getbegyx(hwinmap, x, y); - width = getmaxx(hwinmap)-x; - height = getmaxy(hwinmap)-y; - coor2point(&st->cursor, &p); - - if (st->cursor.pl != vi->pl) { - vi->pl = st->cursor.pl; - st->wnd_map->update |= 1; - } - if (p.y < tl.y) { - vi->topleft.y = st->cursor.y-vi->size.height/2; - st->wnd_map->update |= 1; - } - else if (p.y >= tl.y + vi->size.height * THEIGHT) { - vi->topleft.y = st->cursor.y-vi->size.height/2; - st->wnd_map->update |= 1; - } - if (p.x <= tl.x) { - vi->topleft.x = st->cursor.x+(st->cursor.y-vi->topleft.y)/2-vi->size.width / 2; - st->wnd_map->update |= 1; - } - else if (p.x >= tl.x + vi->size.width * TWIDTH-1) { - vi->topleft.x = st->cursor.x+(st->cursor.y-vi->topleft.y)/2-vi->size.width / 2; - st->wnd_map->update |= 1; - } - - if (st->wnd_map->update) { - update_view(vi); - coor2point(&vi->topleft, &tl); - } - for (wnd=wnd_last;wnd!=NULL;wnd=wnd->prev) { - if (wnd->update && wnd->paint) { - if (wnd->update & 1) { - wnd->paint(wnd, st); - wnoutrefresh(wnd->handle); - } - if (wnd->update & 2) { - touchwin(wnd->handle); - } - wnd->update = 0; - } - } - draw_cursor(st->wnd_map->handle, st->selected, vi, &st->cursor, 1); - doupdate(); - c = getch(); - draw_cursor(st->wnd_map->handle, st->selected, vi, &st->cursor, 0); - handlekey(st, c); - } - g_quit = 0; - set_readline(NULL); - curs_set(1); - endwin(); - log_flags = old_flags; - state_close(st); -} - -int -curses_readline(struct lua_State * L, char * buffer, size_t size, const char * prompt) -{ - unused(L); - askstring(hstatus, prompt, buffer, size); - return buffer[0]!=0; -} - - -void -seed_players(const char * filename, boolean new_island) -{ - newfaction * players = read_newfactions(filename); - if (players!=NULL) { - while (players) { - int n = listlen(players); - int k = (n+ISLANDSIZE-1)/ISLANDSIZE; - k = n / k; - n = autoseed(&players, k, new_island?0:TURNS_PER_ISLAND); - if (n==0) { - break; - } - } - } -} - -void -make_block(int x, int y, int radius, const struct terrain_type * terrain) -{ - int cx, cy; - region *r; - plane * pl = findplane(x, y); - - if (terrain==NULL) return; - - for (cx = x - radius; cx != x+radius; ++cx) { - for (cy = y - radius; cy != y+radius; ++cy) { - int nx = cx, ny = cy; - pnormalize(&nx, &ny, pl); - if (koor_distance(nx, ny, x, y) < radius) { - if (!findregion(nx, ny)) { - r = new_region(nx, ny, pl, 0); - terraform_region(r, terrain); - } - } - } - } -} +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2006 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +/* wenn platform.h nicht vor curses included wird, kompiliert es unter windows nicht */ +#include +#include +#include + +#include "gmtool.h" +#include "gmtool_structs.h" + +#include +#include +#if MUSEUM_MODULE +#include +#endif +#if ARENA_MODULE +#include +#endif +#include +#include +#if DUNGEON_MODULE +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +static int g_quit; +int force_color = 0; + +state * current_state = NULL; + +#define IFL_SHIPS (1<<0) +#define IFL_UNITS (1<<1) +#define IFL_FACTIONS (1<<2) +#define IFL_BUILDINGS (1<<3) + +static WINDOW * hstatus; + +static void +init_curses(void) +{ + short fg, bg; + initscr(); + + if (has_colors() || force_color) { + short bcol = COLOR_BLACK; + short hcol = COLOR_MAGENTA; + start_color(); +#ifdef WIN32 + /* looks crap on putty with TERM=linux */ + if (can_change_color()) { + init_color(COLOR_YELLOW, 1000, 1000, 0); + } +#endif + + for (fg=0;fg!=8;++fg) { + for (bg=0;bg!=2;++bg) { + init_pair(fg+8*bg, fg, bg?hcol:bcol); + } + } + + attrset(COLOR_PAIR(COLOR_BLACK)); + bkgd(' ' | COLOR_PAIR(COLOR_BLACK)); + bkgdset(' ' | COLOR_PAIR(COLOR_BLACK)); + } + + keypad(stdscr, TRUE); /* enable keyboard mapping */ + meta(stdscr, TRUE); + nonl(); /* tell curses not to do NL->CR/NL on output */ + cbreak(); /* take input chars one at a time, no wait for \n */ + noecho(); /* don't echo input */ + scrollok(stdscr, FALSE); + refresh(); +} + +void cnormalize(const coordinate * c, int * x, int * y) +{ + *x = c->x; + *y = c->y; + pnormalize(x, y, c->pl); +} + +map_region * +mr_get(const view * vi, int xofs, int yofs) +{ + return vi->regions + xofs + yofs * vi->size.width; +} + +static point * +coor2point(const coordinate * c, point * p) +{ + assert(c && p); + p->x = c->x * TWIDTH + c->y * TWIDTH / 2; + p->y = c->y * THEIGHT; + return p; +} + +static window * wnd_first, * wnd_last; + +static window * +win_create(WINDOW * hwin) +{ + window * wnd = calloc(1, sizeof(window)); + wnd->handle = hwin; + if (wnd_first!=NULL) { + wnd->next = wnd_first; + wnd_first->prev = wnd; + wnd_first = wnd; + } else { + wnd_first = wnd; + wnd_last = wnd; + } + return wnd; +} + +static void +untag_region(selection * s, int nx, int ny) +{ + unsigned int key = ((nx << 12) ^ ny); + tag ** tp = &s->tags[key & (MAXTHASH-1)]; + tag * t = NULL; + while (*tp) { + t = *tp; + if (t->coord.x==nx && t->coord.y==ny) break; + tp=&t->nexthash; + } + if (!*tp) return; + *tp = t->nexthash; + free(t); + return; +} + +static void +tag_region(selection * s, int nx, int ny) +{ + unsigned int key = ((nx << 12) ^ ny); + tag ** tp = &s->tags[key & (MAXTHASH-1)]; + while (*tp) { + tag * t = *tp; + if (t->coord.x==nx && t->coord.y==ny) return; + tp=&t->nexthash; + } + *tp = calloc(1, sizeof(tag)); + (*tp)->coord.x = nx; + (*tp)->coord.y = ny; + (*tp)->coord.pl = findplane(nx, ny); + return; +} + +static int +tagged_region(selection * s, int nx, int ny) +{ + unsigned int key = ((nx << 12) ^ ny); + tag ** tp = &s->tags[key & (MAXTHASH-1)]; + while (*tp) { + tag * t = *tp; + if (t->coord.x==nx && t->coord.y==ny) return 1; + tp=&t->nexthash; + } + return 0; +} + +static int +mr_tile(const map_region * mr, int highlight) +{ + int hl = 8 * highlight; + if (mr!=NULL && mr->r!=NULL) { + const region * r = mr->r; + switch (r->terrain->_name[0]) { + case 'o' : + return '.' | COLOR_PAIR(hl + COLOR_CYAN); + case 'd' : + return 'D' | COLOR_PAIR(hl + COLOR_YELLOW) | A_BOLD; + case 't' : + return '%' | COLOR_PAIR(hl + COLOR_YELLOW) | A_BOLD; + case 'f' : + if (r->terrain->_name[1]=='o') { /* fog */ + return '.' | COLOR_PAIR(hl + COLOR_YELLOW) | A_NORMAL; + } else if (r->terrain->_name[1]=='i') { /* firewall */ + return '%' | COLOR_PAIR(hl + COLOR_RED) | A_BOLD; + } + case 'h' : + return 'H' | COLOR_PAIR(hl + COLOR_YELLOW) | A_NORMAL; + case 'm' : + return '^' | COLOR_PAIR(hl + COLOR_WHITE) | A_NORMAL; + case 'p' : + if (r_isforest(r)) return '#' | COLOR_PAIR(hl + COLOR_GREEN) | A_NORMAL; + return '+' | COLOR_PAIR(hl + COLOR_GREEN) | A_BOLD; + case 'g' : + return '*' | COLOR_PAIR(hl + COLOR_WHITE) | A_BOLD; + case 's' : + return 'S' | COLOR_PAIR(hl + COLOR_MAGENTA) | A_NORMAL; + } + return r->terrain->_name[0] | COLOR_PAIR(hl + COLOR_RED); + } + return ' ' | COLOR_PAIR(hl + COLOR_WHITE); +} + +static void +paint_map(window * wnd, const state * st) +{ + WINDOW * win = wnd->handle; + int lines = getmaxy(win); + int cols = getmaxx(win); + int vx, vy; + + lines = lines/THEIGHT; + cols = cols/TWIDTH; + for (vy = 0; vy!=lines; ++vy) { + int yp = (lines - vy - 1) * THEIGHT; + for (vx = 0; vx!=cols; ++vx) { + map_region * mr = mr_get(&st->display, vx, vy); + int attr = 0; + int hl = 0; + int xp = vx * TWIDTH + (vy & 1) * TWIDTH/2; + int nx, ny; + if (mr) { + if (st) { + cnormalize(&mr->coord, &nx, &ny); + if (tagged_region(st->selected, nx, ny)) { + attr |= A_REVERSE; + } + } + if (mr->r && mr->r->flags & RF_MAPPER_HIGHLIGHT) hl = 1; + mvwaddch(win, yp, xp, mr_tile(mr, hl) | attr); + } + } + } +} + +map_region * +cursor_region(const view * v, const coordinate * c) +{ + coordinate relpos; + int cx, cy; + + if (c) { + relpos.x = c->x - v->topleft.x; + relpos.y = c->y - v->topleft.y; + cy = relpos.y; + cx = relpos.x + cy/2; + return mr_get(v, cx, cy); + } + return NULL; +} + +static void +draw_cursor(WINDOW * win, selection * s, const view * v, const coordinate * c, int show) +{ + int lines = getmaxy(win)/THEIGHT; + int xp, yp, nx, ny; + int attr = 0; + map_region * mr = cursor_region(v, c); + coordinate relpos; + int cx, cy; + + if (!mr) return; + + relpos.x = c->x - v->topleft.x; + relpos.y = c->y - v->topleft.y; + cy = relpos.y; + cx = relpos.x + cy/2; + + yp = (lines - cy - 1) * THEIGHT; + xp = cx * TWIDTH + (cy & 1) * TWIDTH/2; + cnormalize(&mr->coord, &nx, &ny); + if (s && tagged_region(s, nx, ny)) attr = A_REVERSE; + if (mr->r) { + int hl = 0; + if (mr->r->flags & RF_MAPPER_HIGHLIGHT) hl = 1; + mvwaddch(win, yp, xp, mr_tile(mr, hl) | attr); + } + else mvwaddch(win, yp, xp, ' ' | attr | COLOR_PAIR(COLOR_YELLOW)); + if (show) { + attr = A_BOLD; + mvwaddch(win, yp, xp-1, '<' | attr | COLOR_PAIR(COLOR_YELLOW)); + mvwaddch(win, yp, xp+1, '>' | attr | COLOR_PAIR(COLOR_YELLOW)); + } else { + attr = A_NORMAL; + mvwaddch(win, yp, xp-1, ' ' | attr | COLOR_PAIR(COLOR_WHITE)); + mvwaddch(win, yp, xp+1, ' ' | attr | COLOR_PAIR(COLOR_WHITE)); + } + wmove(win, yp, xp); + wnoutrefresh(win); +} + + + +static void +paint_status(window * wnd, const state * st) +{ + WINDOW * win = wnd->handle; + const char * name = ""; + int nx, ny, uid = 0; + const char * terrain = "----"; + map_region * mr = cursor_region(&st->display, &st->cursor); + if (mr && mr->r) { + uid = mr->r->uid; + if (mr->r->land) { + name = (const char *)mr->r->land->name; + } else { + name = mr->r->terrain->_name; + } + terrain = mr->r->terrain->_name; + } + cnormalize(&st->cursor, &nx, &ny); + mvwprintw(win, 0, 0, "%4d %4d | %.4s | %.20s (%d)", nx, ny, terrain, name, uid); + wclrtoeol(win); +} + +static boolean +handle_info_region(window * wnd, state * st, int c) +{ + return false; +} + +static void +paint_info_region(window * wnd, const state * st) +{ + WINDOW * win = wnd->handle; + int size = getmaxx(win)-2; + int line = 0, maxline = getmaxy(win)-2; + map_region * mr = cursor_region(&st->display, &st->cursor); + + unused(st); + werase(win); + wxborder(win); + if (mr && mr->r) { + const region * r = mr->r; + if (r->land) { + mvwaddnstr(win, line++, 1, (char *)r->land->name, size); + } else { + mvwaddnstr(win, line++, 1, r->terrain->_name, size); + } + line++; + mvwprintw(win, line++, 1, "%s, age %d", r->terrain->_name, r->age); + if (r->land) { + mvwprintw(win, line++, 1, "$:%6d P:%5d", r->land->money, r->land->peasants); + mvwprintw(win, line++, 1, "H:%6d %s:%5d", r->land->horses, (r->flags&RF_MALLORN)?"M":"T", r->land->trees[1]+r->land->trees[2]); + } + line++; + if (r->ships && (st->info_flags & IFL_SHIPS)) { + ship * sh; + wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + mvwaddnstr(win, line++, 1, "* ships:", size-5); + wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + for (sh=r->ships;sh && linenext) { + mvwprintw(win, line, 1, "%.4s ", itoa36(sh->no)); + mvwaddnstr(win, line++, 6, (char*)sh->type->name[0], size-5); + } + } + if (r->units && (st->info_flags & IFL_FACTIONS)) { + unit * u; + wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + mvwaddnstr(win, line++, 1, "* factions:", size-5); + wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + for (u=r->units;u && linenext) { + if (!fval(u->faction, FFL_MARK)) { + mvwprintw(win, line, 1, "%.4s ", itoa36(u->faction->no)); + mvwaddnstr(win, line++, 6, (char *)u->faction->name, size-5); + fset(u->faction, FFL_MARK); + } + } + for (u=r->units;u && linenext) { + freset(u->faction, FFL_MARK); + } + } + if (r->units && (st->info_flags & IFL_UNITS)) { + unit * u; + wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + mvwaddnstr(win, line++, 1, "* units:", size-5); + wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + for (u=r->units;u && linenext) { + mvwprintw(win, line, 1, "%.4s ", itoa36(u->no)); + mvwaddnstr(win, line++, 6, (char *)u->name, size-5); + } + } + } +} + +static void (*paint_info)(struct window * wnd, const struct state * st); + +static void +paint_info_default(window * wnd, const state * st) +{ + if (paint_info) paint_info(wnd, st); + else paint_info_region(wnd, st); +} + +void set_info_function(void (*callback)(struct window *, const struct state *)) +{ + paint_info = callback; +} + +static char * +askstring(WINDOW * win, const char * q, char * buffer, size_t size) +{ + werase(win); + mvwaddstr(win, 0, 0, (char*)q); + wmove(win, 0, (int)(strlen(q)+1)); + echo(); + wgetnstr(win, buffer, (int)size); + noecho(); + return buffer; +} + +static void +statusline(WINDOW * win, const char * str) +{ + mvwaddstr(win, 0, 0, (char*)str); + wclrtoeol(win); + wnoutrefresh(win); +} + +static void +terraform_at(coordinate * c, const terrain_type *terrain) +{ + if (terrain!=NULL) { + region * r; + int nx = c->x, ny = c->y; + pnormalize(&nx, &ny, c->pl); + r = findregion(nx, ny); + if (r==NULL) { + r = new_region(nx, ny, c->pl, 0); + } + terraform_region(r, terrain); + } +} + +static void +terraform_selection(selection * selected, const terrain_type *terrain) +{ + int i; + + if (terrain==NULL) return; + for (i=0;i!=MAXTHASH;++i) { + tag ** tp = &selected->tags[i]; + while (*tp) { + region * r; + tag * t = *tp; + int nx = t->coord.x, ny = t->coord.y; + plane * pl = t->coord.pl; + + pnormalize(&nx, &ny, pl); + r = findregion(nx, ny); + if (r==NULL) { + r = new_region(nx, ny, pl, 0); + } + terraform_region(r, terrain); + tp = &t->nexthash; + } + } +} + +static faction * +select_faction(state * st) +{ + list_selection *prev, *ilist = NULL, **iinsert; + list_selection *selected = NULL; + faction * f = factions; + + if (!f) return NULL; + iinsert = &ilist; + prev = ilist; + + while (f) { + char buffer[32]; + sprintf(buffer, "%.4s %.26s", itoa36(f->no), f->name); + insert_selection(iinsert, NULL, buffer, (void*)f); + f = f->next; + } + selected = do_selection(ilist, "Select Faction", NULL, NULL); + st->wnd_info->update |= 1; + st->wnd_map->update |= 1; + st->wnd_status->update |= 1; + + if (selected==NULL) return NULL; + return (faction*)selected->data; +} + +static const terrain_type * +select_terrain(state * st, const terrain_type * default_terrain) +{ + list_selection *prev, *ilist = NULL, **iinsert; + list_selection *selected = NULL; + const terrain_type * terrain = terrains(); + + if (!terrain) return NULL; + iinsert = &ilist; + prev = ilist; + + while (terrain) { + insert_selection(iinsert, NULL, terrain->_name, (void*)terrain); + terrain = terrain->next; + } + selected = do_selection(ilist, "Terrain", NULL, NULL); + st->wnd_info->update |= 1; + st->wnd_map->update |= 1; + st->wnd_status->update |= 1; + + if (selected==NULL) return NULL; + return (const terrain_type*)selected->data; +} + +static coordinate * +region2coord(const region * r, coordinate * c) +{ + c->x = r->x; + c->y = r->y; + c->pl = rplane(r); + return c; +} + +#ifdef __PDCURSES__ +#define FAST_UP CTL_UP +#define FAST_DOWN CTL_DOWN +#define FAST_LEFT CTL_LEFT +#define FAST_RIGHT CTL_RIGHT +#else +#define FAST_UP KEY_PPAGE +#define FAST_DOWN KEY_NPAGE +#define FAST_LEFT KEY_SLEFT +#define FAST_RIGHT KEY_SRIGHT +#endif + +void +highlight_region(region *r, int toggle) +{ + if (r!=NULL) { + if (toggle) r->flags |= RF_MAPPER_HIGHLIGHT; + else r->flags &= ~RF_MAPPER_HIGHLIGHT; + } +} + +void +select_coordinate(struct selection * selected, int nx, int ny, int toggle) +{ + if (toggle) tag_region(selected, nx, ny); + else untag_region(selected, nx, ny); +} + +enum { MODE_MARK, MODE_SELECT, MODE_UNMARK, MODE_UNSELECT }; + +static void +select_regions(state * st, int selectmode) +{ + char sbuffer[80]; + int findmode; + const char * statustext[] = { + "mark-", "select-", "unmark-", "deselect-" + }; + const char * status = statustext[selectmode]; + statusline(st->wnd_status->handle, status); + doupdate(); + findmode = getch(); + if (findmode=='n') { /* none */ + int i; + sprintf(sbuffer, "%snone", status); + statusline(st->wnd_status->handle, sbuffer); + if (selectmode&MODE_SELECT) { + for (i=0;i!=MAXTHASH;++i) { + tag ** tp = &st->selected->tags[i]; + while (*tp) { + tag * t = *tp; + *tp = t->nexthash; + free(t); + } + } + } else { + region * r; + for (r=regions;r;r=r->next) { + r->flags &= ~RF_MAPPER_HIGHLIGHT; + } + } + } + else if (findmode=='m') { + region * r; + sprintf(sbuffer, "%smonsters", status); + statusline(st->wnd_status->handle, sbuffer); + for (r=regions;r;r=r->next) { + unit * u = r->units; + for (;u;u=u->next) { + if (fval(u->faction, FFL_NPC)!=0) break; + } + if (u) { + 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=='p') { + region * r; + sprintf(sbuffer, "%splayers", status); + statusline(st->wnd_status->handle, sbuffer); + for (r=regions;r;r=r->next) { + unit * u = r->units; + for (;u;u=u->next) { + if (fval(u->faction, FFL_NPC)==0) break; + } + if (u) { + 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=='u') { + region * r; + sprintf(sbuffer, "%sunits", status); + statusline(st->wnd_status->handle, sbuffer); + for (r=regions;r;r=r->next) { + if (r->units) { + 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=='s') { + region * r; + sprintf(sbuffer, "%sships", status); + statusline(st->wnd_status->handle, sbuffer); + for (r=regions;r;r=r->next) { + if (r->ships) { + 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=='f') { + char fbuffer[12]; + sprintf(sbuffer, "%sfaction:", status); + askstring(st->wnd_status->handle, sbuffer, fbuffer, 12); + if (fbuffer[0]) { + faction * f = findfaction(atoi36(fbuffer)); + + if (f!=NULL) { + unit * u; + + sprintf(sbuffer, "%sfaction: %s", status, itoa36(f->no)); + statusline(st->wnd_status->handle, sbuffer); + for (u=f->units;u;u=u->nextF) { + region * r = u->region; + if (selectmode&MODE_SELECT) { + select_coordinate(st->selected, r->x, r->y, selectmode==MODE_SELECT); + } else { + highlight_region(r, selectmode==MODE_MARK); + } + } + } else { + statusline(st->wnd_status->handle, "faction not found."); + beep(); + return; + } + } + } + else if (findmode=='t') { + const struct terrain_type * terrain; + sprintf(sbuffer, "%sterrain: ", status); + statusline(st->wnd_status->handle, sbuffer); + terrain = select_terrain(st, NULL); + if (terrain!=NULL) { + region * r; + sprintf(sbuffer, "%sterrain: %s", status, terrain->_name); + statusline(st->wnd_status->handle, sbuffer); + for (r=regions;r;r=r->next) { + if (r->terrain==terrain) { + if (selectmode&MODE_SELECT) { + select_coordinate(st->selected, r->x, r->y, selectmode==MODE_SELECT); + } else { + highlight_region(r, selectmode==MODE_MARK); + } + } + } + } + } else { + statusline(st->wnd_status->handle, "unknown command."); + beep(); + return; + } + st->wnd_info->update |= 3; + st->wnd_status->update |= 3; + st->wnd_map->update |= 3; +} + +static void +handlekey(state * st, int c) +{ + window * wnd; + coordinate * cursor = &st->cursor; + static char locate[80]; + static int findmode = 0; + region *r; + char sbuffer[80]; + static char kbuffer[80]; + int n, nx, ny; + + switch(c) { + case FAST_RIGHT: + cursor->x+=10; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case FAST_LEFT: + cursor->x-=10; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case FAST_UP: + cursor->y+=10; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case FAST_DOWN: + cursor->y-=10; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case KEY_UP: + cursor->y++; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case KEY_DOWN: + cursor->y--; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case KEY_RIGHT: + cursor->x++; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case KEY_LEFT: + cursor->x--; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case 'S': + case KEY_SAVE: + case KEY_F(2): + /* if (st->modified) */ { + char datafile[MAX_PATH]; + + askstring(st->wnd_status->handle, "save as:", datafile, sizeof(datafile)); + if (strlen(datafile)>0) { + create_backup(datafile); + remove_empty_units(); + writegame(datafile, IO_DEFAULT); + st->modified = 0; + } + } + break; + case 'B': + /* + make_block(st->cursor.x, st->cursor.y, 6, select_terrain(st, NULL)); + */ + cnormalize(&st->cursor, &nx, &ny); + n = rng_int() % 8 + 8; + build_island_e3(nx, ny, n, n*3); + st->modified = 1; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + break; + case 0x02: /* CTRL+b */ + cnormalize(&st->cursor, &nx, &ny); + make_block(nx, ny, 6, newterrain(T_OCEAN)); + st->modified = 1; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + break; + case 0x09: /* tab = next selected*/ + if (regions!=NULL) { + map_region * mr = cursor_region(&st->display, cursor); + if (mr) { + region * first = mr->r; + region * cur = (first&&first->next)?first->next:regions; + + while (cur!=first) { + coordinate coord; + region2coord(cur, &coord); + cnormalize(&coord, &nx, &ny); + if (tagged_region(st->selected, nx, ny)) { + st->cursor = coord; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + } + cur = cur->next; + if (!cur && first) cur = regions; + } + } + } + break; + + case 'p': + if (planes) { + plane * pl = planes; + if (cursor->pl) { + while (pl && pl!=cursor->pl) { + pl = pl->next; + } + if (pl && pl->next) { + cursor->pl = pl->next; + } else { + cursor->pl = get_homeplane(); + } + } else { + cursor->pl = planes; + } + } + break; + + case 'a': + if (regions!=NULL) { + map_region * mr = cursor_region(&st->display, cursor); + if (mr && mr->r) { + region * cur = mr->r; + plane * pl = rplane(cur); + if (pl==NULL) { + cur = r_standard_to_astral(cur); + } else if (is_astral(cur)) { + cur = r_astral_to_standard(cur); + } else { + cur = NULL; + } + if (cur!=NULL) { + region2coord(cur, &st->cursor); + } else { + beep(); + } + } + } + break; + case 'g': + askstring(st->wnd_status->handle, "goto-x:", sbuffer, 12); + if (sbuffer[0]) { + askstring(st->wnd_status->handle, "goto-y:", sbuffer+16, 12); + if (sbuffer[16]) { + st->cursor.x = atoi(sbuffer); + st->cursor.y = atoi(sbuffer+16); + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + } + } + break; + case 0x14: /* C-t */ + terraform_at(&st->cursor, select_terrain(st, NULL)); + st->modified = 1; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + break; + case 'I': + statusline(st->wnd_status->handle, "info-"); + doupdate(); + do { + c = getch(); + switch (c) { + case 's': + st->info_flags ^= IFL_SHIPS; + if (st->info_flags & IFL_SHIPS) statusline(st->wnd_status->handle, "info-ships true"); + else statusline(st->wnd_status->handle, "info-ships false"); + break; + case 'b': + st->info_flags ^= IFL_BUILDINGS; + if (st->info_flags & IFL_BUILDINGS) statusline(st->wnd_status->handle, "info-buildings true"); + else statusline(st->wnd_status->handle, "info-buildings false"); + case 'f': + st->info_flags ^= IFL_FACTIONS; + if (st->info_flags & IFL_FACTIONS) statusline(st->wnd_status->handle, "info-factions true"); + else statusline(st->wnd_status->handle, "info-factions false"); + break; + case 'u': + st->info_flags ^= IFL_UNITS; + if (st->info_flags & IFL_UNITS) statusline(st->wnd_status->handle, "info-units true"); + else statusline(st->wnd_status->handle, "info-units false"); + break; + case 27: /* esc */ + break; + default: + beep(); + c = 0; + } + } while (c==0); + break; + case 'L': + if (global.vm_state) { + move(0, 0); + refresh(); + lua_do((struct lua_State*)global.vm_state); + /* todo: do this from inside the script */ + clear(); + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + } + break; + case 12: /* Ctrl-L */ + clear(); + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + break; + case 'h': + select_regions(st, MODE_MARK); + break; + case 'H': + select_regions(st, MODE_UNMARK); + break; + case 't': + select_regions(st, MODE_SELECT); + break; + case 'T': + select_regions(st, MODE_UNSELECT); + break; + case ';': + statusline(st->wnd_status->handle, "tag-"); + doupdate(); + switch (getch()) { + case 't': + terraform_selection(st->selected, select_terrain(st, NULL)); + st->modified = 1; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + break; + case 'm': + break; + default: + statusline(st->wnd_status->handle, "unknown command."); + beep(); + } + break; + case ' ': + cnormalize(cursor, &nx, &ny); + if (tagged_region(st->selected, nx, ny)) untag_region(st->selected, nx, ny); + else tag_region(st->selected, nx, ny); + break; + case 'A': + sprintf(sbuffer, "%s/newfactions", basepath()); + seed_players(sbuffer, false); + st->wnd_map->update |= 1; + break; + case '/': + statusline(st->wnd_status->handle, "find-"); + doupdate(); + findmode = getch(); + if (findmode=='r') { + askstring(st->wnd_status->handle, "find-region:", locate, sizeof(locate)); + } else if (findmode=='u') { + askstring(st->wnd_status->handle, "find-unit:", locate, sizeof(locate)); + } else if (findmode=='f') { + askstring(st->wnd_status->handle, "find-faction:", locate, sizeof(locate)); + } else if (findmode=='F') { + faction * f = select_faction(st); + if (f!=NULL) { + strcpy(locate, itoa36(f->no)); + findmode='f'; + } else { + break; + } + } else { + statusline(st->wnd_status->handle, "unknown command."); + beep(); + break; + } + /* achtung: fall-through ist absicht: */ + if (!strlen(locate)) break; + case 'n': + if (findmode=='u') { + unit * u = findunit(atoi36(locate)); + r = u?u->region:NULL; + } else if (findmode && regions!=NULL) { + struct faction * f = NULL; + map_region * mr = cursor_region(&st->display, cursor); + region * first = (mr && mr->r && mr->r->next)?mr->r->next:regions; + + if (findmode=='f') { + sprintf(sbuffer, "find-faction: %s", locate); + statusline(st->wnd_status->handle, sbuffer); + f = findfaction(atoi36(locate)); + if (f==NULL) { + statusline(st->wnd_status->handle, "faction not found."); + beep(); + break; + } + } + for (r=first;;) { + if (findmode=='r' && r->land && r->land->name && strstr((const char*)r->land->name, locate)) { + break; + } else if (findmode=='f') { + unit * u; + for (u=r->units;u;u=u->next) { + if (u->faction==f) { + break; + } + } + if (u) break; + } + r = r->next; + if (r==NULL) r = regions; + if (r==first) { + r = NULL; + statusline(st->wnd_status->handle, "not found."); + beep(); + break; + } + } + } else { + r = NULL; + } + if (r!=NULL) { + region2coord(r, &st->cursor); + } + break; + case 'Q': + g_quit = 1; + break; + default: + for (wnd=wnd_first;wnd!=NULL;wnd=wnd->next) { + if (wnd->handlekey) { + if (wnd->handlekey(wnd, st, c)) break; + } + } + if (wnd==NULL) { + if (kbuffer[0]==0) { + strcpy(kbuffer, "getch:"); + } + sprintf(sbuffer, " 0x%x", c); + strncat(kbuffer, sbuffer, sizeof(kbuffer)); + statusline(st->wnd_status->handle, kbuffer); + if (strlen(kbuffer)>70) kbuffer[0]=0; + } + break; + } +} + +static void +init_view(view * display, WINDOW * win) +{ + display->topleft.x = 1; + display->topleft.y = 1; + display->topleft.pl = get_homeplane(); + display->pl = get_homeplane(); + display->size.width = getmaxx(win)/TWIDTH; + display->size.height = getmaxy(win)/THEIGHT; + display->regions = calloc(display->size.height * display->size.width, sizeof(map_region)); +} + +static void +update_view(view * vi) +{ + int i, j; + for (i=0;i!=vi->size.width;++i) { + for (j=0;j!=vi->size.height;++j) { + map_region * mr = mr_get(vi, i, j); + mr->coord.x = vi->topleft.x + i - j/2; + mr->coord.y = vi->topleft.y + j; + mr->coord.pl = vi->pl; + pnormalize(&mr->coord.x, &mr->coord.y, mr->coord.pl); + mr->r = findregion(mr->coord.x, mr->coord.y); + } + } +} + +state * +state_open(void) +{ + state * st = calloc(sizeof(state), 1); + st->display.pl = get_homeplane(); + st->cursor.pl = get_homeplane(); + st->cursor.x = 0; + st->cursor.y = 0; + st->selected = calloc(1, sizeof(struct selection)); + st->modified = 0; + st->info_flags = 0xFFFFFFFF; + st->prev = current_state; + current_state = st; + return st; +} + +void +state_close(state * st) +{ + assert(st==current_state); + current_state = st->prev; + free(st); +} + +void +run_mapper(void) +{ + WINDOW * hwinstatus; + WINDOW * hwininfo; + WINDOW * hwinmap; + int width, height, x, y; + int split = 20, old_flags = log_flags; + state * st; + point tl; + + log_flags &= ~(LOG_CPERROR|LOG_CPWARNING); + init_curses(); + curs_set(1); + + set_readline(curses_readline); + + getbegyx(stdscr, x, y); + width = getmaxx(stdscr); + height = getmaxy(stdscr); + + hwinmap = subwin(stdscr, getmaxy(stdscr)-1, getmaxx(stdscr)-split, y, x); + hwininfo = subwin(stdscr, getmaxy(stdscr)-1, split, y, x+getmaxx(stdscr)-split); + hwinstatus = subwin(stdscr, 1, width, height-1, x); + + st = state_open(); + st->wnd_map = win_create(hwinmap); + st->wnd_map->paint = &paint_map; + st->wnd_map->update = 1; + st->wnd_info = win_create(hwininfo); + st->wnd_info->paint = &paint_info_default; + st->wnd_info->handlekey = &handle_info_region; + st->wnd_info->update = 1; + st->wnd_status = win_create(hwinstatus); + st->wnd_status->paint = &paint_status; + st->wnd_status->update = 1; + + init_view(&st->display, hwinmap); + coor2point(&st->display.topleft, &tl); + + hstatus = st->wnd_status->handle; /* the lua console needs this */ + + while (!g_quit) { + int c; + point p; + window * wnd; + view * vi = &st->display; + + getbegyx(hwinmap, x, y); + width = getmaxx(hwinmap)-x; + height = getmaxy(hwinmap)-y; + coor2point(&st->cursor, &p); + + if (st->cursor.pl != vi->pl) { + vi->pl = st->cursor.pl; + st->wnd_map->update |= 1; + } + if (p.y < tl.y) { + vi->topleft.y = st->cursor.y-vi->size.height/2; + st->wnd_map->update |= 1; + } + else if (p.y >= tl.y + vi->size.height * THEIGHT) { + vi->topleft.y = st->cursor.y-vi->size.height/2; + st->wnd_map->update |= 1; + } + if (p.x <= tl.x) { + vi->topleft.x = st->cursor.x+(st->cursor.y-vi->topleft.y)/2-vi->size.width / 2; + st->wnd_map->update |= 1; + } + else if (p.x >= tl.x + vi->size.width * TWIDTH-1) { + vi->topleft.x = st->cursor.x+(st->cursor.y-vi->topleft.y)/2-vi->size.width / 2; + st->wnd_map->update |= 1; + } + + if (st->wnd_map->update) { + update_view(vi); + coor2point(&vi->topleft, &tl); + } + for (wnd=wnd_last;wnd!=NULL;wnd=wnd->prev) { + if (wnd->update && wnd->paint) { + if (wnd->update & 1) { + wnd->paint(wnd, st); + wnoutrefresh(wnd->handle); + } + if (wnd->update & 2) { + touchwin(wnd->handle); + } + wnd->update = 0; + } + } + draw_cursor(st->wnd_map->handle, st->selected, vi, &st->cursor, 1); + doupdate(); + c = getch(); + draw_cursor(st->wnd_map->handle, st->selected, vi, &st->cursor, 0); + handlekey(st, c); + } + g_quit = 0; + set_readline(NULL); + curs_set(1); + endwin(); + log_flags = old_flags; + state_close(st); +} + +int +curses_readline(struct lua_State * L, char * buffer, size_t size, const char * prompt) +{ + unused(L); + askstring(hstatus, prompt, buffer, size); + return buffer[0]!=0; +} + + +void +seed_players(const char * filename, boolean new_island) +{ + newfaction * players = read_newfactions(filename); + if (players!=NULL) { + while (players) { + int n = listlen(players); + int k = (n+ISLANDSIZE-1)/ISLANDSIZE; + k = n / k; + n = autoseed(&players, k, new_island?0:TURNS_PER_ISLAND); + if (n==0) { + break; + } + } + } +} + +void +make_block(int x, int y, int radius, const struct terrain_type * terrain) +{ + int cx, cy; + region *r; + plane * pl = findplane(x, y); + + if (terrain==NULL) return; + + for (cx = x - radius; cx != x+radius; ++cx) { + for (cy = y - radius; cy != y+radius; ++cy) { + int nx = cx, ny = cy; + pnormalize(&nx, &ny, pl); + if (koor_distance(nx, ny, x, y) < radius) { + if (!findregion(nx, ny)) { + r = new_region(nx, ny, pl, 0); + terraform_region(r, terrain); + } + } + } + } +} diff --git a/src/gmtool.h b/src/gmtool.h index 1912e03ee..717d3ab07 100644 --- a/src/gmtool.h +++ b/src/gmtool.h @@ -1,41 +1,41 @@ -/* vi: set ts=2: - * +-------------------+ Christian Schlittchen - * | | Enno Rehling - * | Eressea PBEM host | Katja Zedel - * | (c) 1998 - 2006 | - * | | This program may not be used, modified or distributed - * +-------------------+ without prior permission by the authors of Eressea. - * - */ - -#ifndef H_GMTOOL -#define H_GMTOOL - -#ifdef __cplusplus -extern "C" { -#endif - struct lua_State; - struct selection; - struct state; - struct region; - - int gmmain(int argc, char *argv[]); - int curses_readline(struct lua_State * L, char * buffer, size_t size, const char * prompt); - - void highlight_region(struct region *r, int on); - void select_coordinate(struct selection * selected, int x, int y, int on); - void run_mapper(void); - - int force_color; - - struct state * state_open(void); - void state_close(struct state * ); - - void make_block(int x, int y, int radius, const struct terrain_type * terrain); - void seed_players(const char * filename, boolean new_island); - -#ifdef __cplusplus -} -#endif - -#endif +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2006 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +#ifndef H_GMTOOL +#define H_GMTOOL + +#ifdef __cplusplus +extern "C" { +#endif + struct lua_State; + struct selection; + struct state; + struct region; + + int gmmain(int argc, char *argv[]); + int curses_readline(struct lua_State * L, char * buffer, size_t size, const char * prompt); + + void highlight_region(struct region *r, int on); + void select_coordinate(struct selection * selected, int x, int y, int on); + void run_mapper(void); + + int force_color; + + struct state * state_open(void); + void state_close(struct state * ); + + void make_block(int x, int y, int radius, const struct terrain_type * terrain); + void seed_players(const char * filename, boolean new_island); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/gmtool.vcproj b/src/gmtool.vcproj index b2d178c58..467785f12 100644 --- a/src/gmtool.vcproj +++ b/src/gmtool.vcproj @@ -1,314 +1,314 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gmtool_structs.h b/src/gmtool_structs.h index 129be7775..dbb715e4e 100644 --- a/src/gmtool_structs.h +++ b/src/gmtool_structs.h @@ -1,102 +1,102 @@ -/* vi: set ts=2: - * +-------------------+ Christian Schlittchen - * | | Enno Rehling - * | Eressea PBEM host | Katja Zedel - * | (c) 1998 - 2006 | - * | | This program may not be used, modified or distributed - * +-------------------+ without prior permission by the authors of Eressea. - * - */ - -#ifndef H_GMTOOL_STRUCTS -#define H_GMTOOL_STRUCTS - -#ifdef __cplusplus -extern "C" { -#endif - -/* types imported from eressea: */ -struct region; - -typedef struct extent { - /* Ein Vektor */ - int width, height; -} extent; - -typedef struct point { - /* Eine Koordinate in einer Ascii-Karte */ - int x, y; -} point; - -typedef struct coordinate { - /* Eine Koordinate im Editor, nicht normalisiert */ - int x, y; - struct plane * pl; -} coordinate; - -typedef struct map_region { - struct region * r; - coordinate coord; -} map_region; - -typedef struct view { - struct map_region * regions; - struct plane * pl; - coordinate topleft; /* upper left corner in map. */ - extent size; /* dimensions. */ -} view; - -typedef struct tag { - coordinate coord; - struct tag * nexthash; -} tag; - -#define MAXTHASH 512 - -typedef struct selection { - tag * tags[MAXTHASH]; -} selection; - -typedef struct state { - coordinate cursor; - selection * selected; - struct state * prev; - view display; - int modified; - unsigned int info_flags; - struct window * wnd_info; - struct window * wnd_map; - struct window * wnd_status; -} state; - -typedef struct window { - boolean (*handlekey)(struct window * win, struct state * st, int key); - void (*paint)(struct window * win, const struct state * st); - - WINDOW * handle; - struct window * next; - struct window * prev; - boolean initialized; - int update; -} window; - -extern map_region * cursor_region(const view * v, const coordinate * c); -extern void cnormalize(const coordinate * c, int * x, int * y); -extern state * current_state; - -extern void set_info_function(void (*callback)(struct window *, const struct state *)); - -#define TWIDTH 2 /* width of tile */ -#define THEIGHT 1 /* height of tile */ - -#ifdef WIN32 -#define wxborder(win) wborder(win, 0, 0, 0, 0, 0, 0, 0, 0) -#else -#define wxborder(win) wborder(win, '|', '|', '-', '-', '+', '+', '+', '+') -#endif - -#ifdef __cplusplus -} -#endif - -#endif +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2006 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +#ifndef H_GMTOOL_STRUCTS +#define H_GMTOOL_STRUCTS + +#ifdef __cplusplus +extern "C" { +#endif + +/* types imported from eressea: */ +struct region; + +typedef struct extent { + /* Ein Vektor */ + int width, height; +} extent; + +typedef struct point { + /* Eine Koordinate in einer Ascii-Karte */ + int x, y; +} point; + +typedef struct coordinate { + /* Eine Koordinate im Editor, nicht normalisiert */ + int x, y; + struct plane * pl; +} coordinate; + +typedef struct map_region { + struct region * r; + coordinate coord; +} map_region; + +typedef struct view { + struct map_region * regions; + struct plane * pl; + coordinate topleft; /* upper left corner in map. */ + extent size; /* dimensions. */ +} view; + +typedef struct tag { + coordinate coord; + struct tag * nexthash; +} tag; + +#define MAXTHASH 512 + +typedef struct selection { + tag * tags[MAXTHASH]; +} selection; + +typedef struct state { + coordinate cursor; + selection * selected; + struct state * prev; + view display; + int modified; + unsigned int info_flags; + struct window * wnd_info; + struct window * wnd_map; + struct window * wnd_status; +} state; + +typedef struct window { + boolean (*handlekey)(struct window * win, struct state * st, int key); + void (*paint)(struct window * win, const struct state * st); + + WINDOW * handle; + struct window * next; + struct window * prev; + boolean initialized; + int update; +} window; + +extern map_region * cursor_region(const view * v, const coordinate * c); +extern void cnormalize(const coordinate * c, int * x, int * y); +extern state * current_state; + +extern void set_info_function(void (*callback)(struct window *, const struct state *)); + +#define TWIDTH 2 /* width of tile */ +#define THEIGHT 1 /* height of tile */ + +#ifdef WIN32 +#define wxborder(win) wborder(win, 0, 0, 0, 0, 0, 0, 0, 0) +#else +#define wxborder(win) wborder(win, '|', '|', '-', '-', '+', '+', '+', '+') +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/items/artrewards.c b/src/items/artrewards.c index 06b152f6b..d37077559 100644 --- a/src/items/artrewards.c +++ b/src/items/artrewards.c @@ -1,157 +1,157 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "artrewards.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -#define HORNRANGE 10 -#define HORNDURATION 3 -#define HORNIMMUNITY 30 - -static int -age_peaceimmune(attrib * a) -{ - return (--a->data.i>0)?AT_AGE_KEEP:AT_AGE_REMOVE; -} - -static attrib_type at_peaceimmune = { - "peaceimmune", - NULL, NULL, - age_peaceimmune, - a_writeint, - a_readint -}; - -static int -use_hornofdancing(struct unit * u, const struct item_type * itype, - int amount, struct order * ord) -{ - region *r; - int regionsPacified = 0; - - for(r=regions; r; r=r->next) { - if(distance(u->region, r) < HORNRANGE) { - if(a_find(r->attribs, &at_peaceimmune) == NULL) { - attrib *a; - - create_curse(u, &r->attribs, ct_find("peacezone"), - 20, HORNDURATION, 1.0, 0); - - a = a_add(&r->attribs, a_new(&at_peaceimmune)); - a->data.i = HORNIMMUNITY; - - ADDMSG(&r->msgs, msg_message("hornofpeace_r_success", - "unit region", u, u->region)); - - regionsPacified++; - } else { - ADDMSG(&r->msgs, msg_message("hornofpeace_r_nosuccess", - "unit region", u, u->region)); - } - } - } - - if(regionsPacified > 0) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "hornofpeace_u_success", - "pacified", regionsPacified)); - } else { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "hornofpeace_u_nosuccess", "")); - } - - return 0; -} - -#define SPEEDUP 2 - - -static int -useonother_trappedairelemental(struct unit * u, int shipId, - const struct item_type * itype, - int amount, struct order * ord) -{ - curse *c; - ship *sh; - - if (shipId <= 0) { - cmistake(u, ord, 20, MSG_MOVE); - return -1; - } - - sh = findshipr(u->region, shipId); - if(!sh) { - cmistake(u, ord, 20, MSG_MOVE); - return -1; - } - - c = create_curse(u, &sh->attribs, ct_find("shipspeedup"), 20, INT_MAX, SPEEDUP, 0); - c_setflag(c, CURSE_NOAGE); - - ADDMSG(&u->faction->msgs, msg_message("trappedairelemental_success", - "unit region command ship", u, u->region, ord, sh)); - - use_pooled(u, itype->rtype, GET_DEFAULT, 1); - - return 0; -} - -static int -use_trappedairelemental(struct unit * u, - const struct item_type * itype, - int amount, struct order * ord) -{ - ship *sh = u->ship; - - if(sh == NULL) { - cmistake(u, ord, 20, MSG_MOVE); - return -1; - } - return useonother_trappedairelemental(u, sh->no, itype, amount,ord); -} - -void -register_artrewards(void) -{ - at_register(&at_peaceimmune); - register_item_use(use_hornofdancing, "use_hornofdancing"); - register_item_use(use_trappedairelemental, "use_trappedairelemental"); - register_item_useonother(useonother_trappedairelemental, "useonother_trappedairelemental"); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "artrewards.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +#define HORNRANGE 10 +#define HORNDURATION 3 +#define HORNIMMUNITY 30 + +static int +age_peaceimmune(attrib * a) +{ + return (--a->data.i>0)?AT_AGE_KEEP:AT_AGE_REMOVE; +} + +static attrib_type at_peaceimmune = { + "peaceimmune", + NULL, NULL, + age_peaceimmune, + a_writeint, + a_readint +}; + +static int +use_hornofdancing(struct unit * u, const struct item_type * itype, + int amount, struct order * ord) +{ + region *r; + int regionsPacified = 0; + + for(r=regions; r; r=r->next) { + if(distance(u->region, r) < HORNRANGE) { + if(a_find(r->attribs, &at_peaceimmune) == NULL) { + attrib *a; + + create_curse(u, &r->attribs, ct_find("peacezone"), + 20, HORNDURATION, 1.0, 0); + + a = a_add(&r->attribs, a_new(&at_peaceimmune)); + a->data.i = HORNIMMUNITY; + + ADDMSG(&r->msgs, msg_message("hornofpeace_r_success", + "unit region", u, u->region)); + + regionsPacified++; + } else { + ADDMSG(&r->msgs, msg_message("hornofpeace_r_nosuccess", + "unit region", u, u->region)); + } + } + } + + if(regionsPacified > 0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "hornofpeace_u_success", + "pacified", regionsPacified)); + } else { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "hornofpeace_u_nosuccess", "")); + } + + return 0; +} + +#define SPEEDUP 2 + + +static int +useonother_trappedairelemental(struct unit * u, int shipId, + const struct item_type * itype, + int amount, struct order * ord) +{ + curse *c; + ship *sh; + + if (shipId <= 0) { + cmistake(u, ord, 20, MSG_MOVE); + return -1; + } + + sh = findshipr(u->region, shipId); + if(!sh) { + cmistake(u, ord, 20, MSG_MOVE); + return -1; + } + + c = create_curse(u, &sh->attribs, ct_find("shipspeedup"), 20, INT_MAX, SPEEDUP, 0); + c_setflag(c, CURSE_NOAGE); + + ADDMSG(&u->faction->msgs, msg_message("trappedairelemental_success", + "unit region command ship", u, u->region, ord, sh)); + + use_pooled(u, itype->rtype, GET_DEFAULT, 1); + + return 0; +} + +static int +use_trappedairelemental(struct unit * u, + const struct item_type * itype, + int amount, struct order * ord) +{ + ship *sh = u->ship; + + if(sh == NULL) { + cmistake(u, ord, 20, MSG_MOVE); + return -1; + } + return useonother_trappedairelemental(u, sh->no, itype, amount,ord); +} + +void +register_artrewards(void) +{ + at_register(&at_peaceimmune); + register_item_use(use_hornofdancing, "use_hornofdancing"); + register_item_use(use_trappedairelemental, "use_trappedairelemental"); + register_item_useonother(useonother_trappedairelemental, "useonother_trappedairelemental"); +} diff --git a/src/items/artrewards.h b/src/items/artrewards.h index 552a3b27a..e8ef8c28e 100644 --- a/src/items/artrewards.h +++ b/src/items/artrewards.h @@ -1,30 +1,30 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ITM_ARTREWARDS -#define H_ITM_ARTREWARDS -#ifdef __cplusplus -extern "C" { -#endif - -extern void register_artrewards(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ITM_ARTREWARDS +#define H_ITM_ARTREWARDS +#ifdef __cplusplus +extern "C" { +#endif + +extern void register_artrewards(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/demonseye.c b/src/items/demonseye.c index 6c6ddee15..1e3b6ec5f 100644 --- a/src/items/demonseye.c +++ b/src/items/demonseye.c @@ -1,64 +1,64 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "demonseye.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include - -/* libc includes */ -#include - -static int -summon_igjarjuk(struct unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - struct plane * p = rplane(u->region); - unused(amount); - unused(itype); - if (p!=NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "use_realworld_only", "")); - return EUNUSABLE; - } else { - assert(!"not implemented"); - return EUNUSABLE; - } -} - -static int -give_igjarjuk(struct unit * src, struct unit * d, const struct item_type * itype, int n, struct order * ord) -{ - ADDMSG(&src->faction->msgs, msg_feedback(src, ord, "error_giveeye", "")); - return 0; -} - -void -register_demonseye(void) -{ - register_item_use(summon_igjarjuk, "useigjarjuk"); - register_item_give(give_igjarjuk, "giveigjarjuk"); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "demonseye.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include + +/* libc includes */ +#include + +static int +summon_igjarjuk(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + struct plane * p = rplane(u->region); + unused(amount); + unused(itype); + if (p!=NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "use_realworld_only", "")); + return EUNUSABLE; + } else { + assert(!"not implemented"); + return EUNUSABLE; + } +} + +static int +give_igjarjuk(struct unit * src, struct unit * d, const struct item_type * itype, int n, struct order * ord) +{ + ADDMSG(&src->faction->msgs, msg_feedback(src, ord, "error_giveeye", "")); + return 0; +} + +void +register_demonseye(void) +{ + register_item_use(summon_igjarjuk, "useigjarjuk"); + register_item_give(give_igjarjuk, "giveigjarjuk"); +} diff --git a/src/items/demonseye.h b/src/items/demonseye.h index be802d6dc..636e6a6e8 100644 --- a/src/items/demonseye.h +++ b/src/items/demonseye.h @@ -1,30 +1,30 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ITM_DEMONSEYE -#define H_ITM_DEMONSEYE -#ifdef __cplusplus -extern "C" { -#endif - -extern void register_demonseye(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ITM_DEMONSEYE +#define H_ITM_DEMONSEYE +#ifdef __cplusplus +extern "C" { +#endif + +extern void register_demonseye(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/itemtypes.c b/src/items/itemtypes.c index af0efe305..765e5994c 100644 --- a/src/items/itemtypes.c +++ b/src/items/itemtypes.c @@ -1,38 +1,38 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "itemtypes.h" - -#include "xerewards.h" -#include "artrewards.h" -#include "phoenixcompass.h" -#include "weapons.h" -#include "seed.h" - -void -register_itemtypes(void) -{ - /* registering misc. functions */ - register_weapons(); - register_xerewards(); - register_artrewards(); - register_phoenixcompass(); -} - -void -init_itemtypes(void) -{ - init_seed(); - init_mallornseed(); -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "itemtypes.h" + +#include "xerewards.h" +#include "artrewards.h" +#include "phoenixcompass.h" +#include "weapons.h" +#include "seed.h" + +void +register_itemtypes(void) +{ + /* registering misc. functions */ + register_weapons(); + register_xerewards(); + register_artrewards(); + register_phoenixcompass(); +} + +void +init_itemtypes(void) +{ + init_seed(); + init_mallornseed(); +} diff --git a/src/items/itemtypes.h b/src/items/itemtypes.h index 1cc8fecec..55f006bc2 100644 --- a/src/items/itemtypes.h +++ b/src/items/itemtypes.h @@ -1,25 +1,25 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_ITM_ITEMS -#define H_ITM_ITEMS -#ifdef __cplusplus -extern "C" { -#endif - -extern void init_itemtypes(void); -extern void register_itemtypes(void); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_ITM_ITEMS +#define H_ITM_ITEMS +#ifdef __cplusplus +extern "C" { +#endif + +extern void init_itemtypes(void); +extern void register_itemtypes(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/phoenixcompass.c b/src/items/phoenixcompass.c index ffe208797..0680aa539 100644 --- a/src/items/phoenixcompass.c +++ b/src/items/phoenixcompass.c @@ -1,129 +1,129 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "phoenixcompass.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -static int -use_phoenixcompass(struct unit * u, const struct item_type * itype, - int amount, struct order * ord) -{ - region *r; - unit *closest_phoenix = NULL; - int closest_phoenix_distance = INT_MAX; - boolean confusion = false; - direction_t direction; - unit *u2; - direction_t closest_neighbour_direction = 0; - static race * rc_phoenix = NULL; - - if (rc_phoenix==NULL) { - rc_phoenix = rc_find("phoenix"); - if (rc_phoenix==NULL) return 0; - } - - /* find the closest phoenix. */ - - for(r=regions; r; r=r->next) { - for(u2=r->units; u2; u2=u2->next) { - if (u2->race == rc_phoenix) { - if(closest_phoenix == NULL) { - closest_phoenix = u2; - closest_phoenix_distance = distance(u->region, closest_phoenix->region); - } else { - int dist = distance(u->region, r); - if(dist < closest_phoenix_distance) { - closest_phoenix = u2; - closest_phoenix_distance = dist; - confusion = false; - } else if(dist == closest_phoenix_distance) { - confusion = true; - } - } - } - } - } - - /* no phoenix found at all.* if confusion == true more than one phoenix - * at the same distance was found and the device is confused */ - - if(closest_phoenix == NULL - || closest_phoenix->region == u->region - || confusion == true) { - add_message(&u->faction->msgs, msg_message("phoenixcompass_confusion", - "unit region command", u, u->region, ord)); - return 0; - } - - /* else calculate the direction. this is tricky. we calculate the - * neighbouring region which is closest to the phoenix found. hardcoded - * for readability. */ - - for(direction = 0; direction < MAXDIRECTIONS; ++direction) { - region *neighbour; - int closest_neighbour_distance = INT_MAX; - - neighbour = r_connect(u->region, direction); - if(neighbour != NULL) { - int dist = distance(neighbour, closest_phoenix->region); - if(dist < closest_neighbour_distance) { - closest_neighbour_direction = direction; - closest_neighbour_distance = dist; - } else if(dist == closest_neighbour_distance && rng_int()%100 < 50) { - /* there can never be more than two neighbours with the same - * distance (except when you are standing in the same region - * as the phoenix, but that case has already been handled). - * therefore this simple solution is correct */ - closest_neighbour_direction = direction; - closest_neighbour_distance = dist; - } - } - } - - add_message(&u->faction->msgs, msg_message("phoenixcompass_success", - "unit region command dir", - u, u->region, ord, closest_neighbour_direction)); - - return 0; -} - -void -register_phoenixcompass(void) -{ - register_item_use(use_phoenixcompass, "use_phoenixcompass"); -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "phoenixcompass.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +static int +use_phoenixcompass(struct unit * u, const struct item_type * itype, + int amount, struct order * ord) +{ + region *r; + unit *closest_phoenix = NULL; + int closest_phoenix_distance = INT_MAX; + boolean confusion = false; + direction_t direction; + unit *u2; + direction_t closest_neighbour_direction = 0; + static race * rc_phoenix = NULL; + + if (rc_phoenix==NULL) { + rc_phoenix = rc_find("phoenix"); + if (rc_phoenix==NULL) return 0; + } + + /* find the closest phoenix. */ + + for(r=regions; r; r=r->next) { + for(u2=r->units; u2; u2=u2->next) { + if (u2->race == rc_phoenix) { + if(closest_phoenix == NULL) { + closest_phoenix = u2; + closest_phoenix_distance = distance(u->region, closest_phoenix->region); + } else { + int dist = distance(u->region, r); + if(dist < closest_phoenix_distance) { + closest_phoenix = u2; + closest_phoenix_distance = dist; + confusion = false; + } else if(dist == closest_phoenix_distance) { + confusion = true; + } + } + } + } + } + + /* no phoenix found at all.* if confusion == true more than one phoenix + * at the same distance was found and the device is confused */ + + if(closest_phoenix == NULL + || closest_phoenix->region == u->region + || confusion == true) { + add_message(&u->faction->msgs, msg_message("phoenixcompass_confusion", + "unit region command", u, u->region, ord)); + return 0; + } + + /* else calculate the direction. this is tricky. we calculate the + * neighbouring region which is closest to the phoenix found. hardcoded + * for readability. */ + + for(direction = 0; direction < MAXDIRECTIONS; ++direction) { + region *neighbour; + int closest_neighbour_distance = INT_MAX; + + neighbour = r_connect(u->region, direction); + if(neighbour != NULL) { + int dist = distance(neighbour, closest_phoenix->region); + if(dist < closest_neighbour_distance) { + closest_neighbour_direction = direction; + closest_neighbour_distance = dist; + } else if(dist == closest_neighbour_distance && rng_int()%100 < 50) { + /* there can never be more than two neighbours with the same + * distance (except when you are standing in the same region + * as the phoenix, but that case has already been handled). + * therefore this simple solution is correct */ + closest_neighbour_direction = direction; + closest_neighbour_distance = dist; + } + } + } + + add_message(&u->faction->msgs, msg_message("phoenixcompass_success", + "unit region command dir", + u, u->region, ord, closest_neighbour_direction)); + + return 0; +} + +void +register_phoenixcompass(void) +{ + register_item_use(use_phoenixcompass, "use_phoenixcompass"); +} + diff --git a/src/items/phoenixcompass.h b/src/items/phoenixcompass.h index b99876056..8bd634484 100644 --- a/src/items/phoenixcompass.h +++ b/src/items/phoenixcompass.h @@ -1,30 +1,30 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ITM_PHOENIXCOMPASS -#define H_ITM_PHOENIXCOMPASS -#ifdef __cplusplus -extern "C" { -#endif - -extern void register_phoenixcompass(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ITM_PHOENIXCOMPASS +#define H_ITM_PHOENIXCOMPASS +#ifdef __cplusplus +extern "C" { +#endif + +extern void register_phoenixcompass(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/seed.c b/src/items/seed.c index 3ad84e0c7..4bef3c496 100644 --- a/src/items/seed.c +++ b/src/items/seed.c @@ -1,100 +1,100 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include - -#include "seed.h" - -/* kernel includes */ -#include -#include -#include -#include - -/* util includes */ -#include -#include - -/* libc includes */ -#include - -resource_type * rt_seed = 0; -resource_type * rt_mallornseed = 0; - -static void -produce_seeds(region * r, const resource_type * rtype, int norders) -{ - assert(rtype==rt_seed && r->land && r->land->trees[0] >= norders); - r->land->trees[0] -= norders; -} - -static int -limit_seeds(const region * r, const resource_type * rtype) -{ - assert(rtype==rt_seed); - if(fval(r, RF_MALLORN)) return 0; - return r->land?r->land->trees[0]:0; -} - -void -init_seed(void) -{ - attrib * a; - resource_limit * rdata; - - rt_seed = rt_find("seed"); - if (rt_seed!=NULL) { - a = a_add(&rt_seed->attribs, a_new(&at_resourcelimit)); - rdata = (resource_limit*)a->data.v; - rdata->limit = limit_seeds; - rdata->produce = produce_seeds; - } -} - -/* mallorn */ - -static void -produce_mallornseeds(region * r, const resource_type * rtype, int norders) -{ - assert(rtype==rt_mallornseed && r->land && r->land->trees[0] >= norders); - assert(fval(r, RF_MALLORN)); - r->land->trees[0] -= norders; -} - -static int -limit_mallornseeds(const region * r, const resource_type * rtype) -{ - assert(rtype==rt_mallornseed); - if (!fval(r, RF_MALLORN)) { - return 0; - } - return r->land?r->land->trees[0]:0; -} - -void -init_mallornseed(void) -{ - attrib * a; - resource_limit * rdata; - - rt_mallornseed = rt_find("mallornseed"); - if (rt_mallornseed!=NULL) { - rt_mallornseed->flags |= RTF_LIMITED; - rt_mallornseed->flags |= RTF_POOLED; - - a = a_add(&rt_mallornseed->attribs, a_new(&at_resourcelimit)); - rdata = (resource_limit*)a->data.v; - rdata->limit = limit_mallornseeds; - rdata->produce = produce_mallornseeds; - } -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include + +#include "seed.h" + +/* kernel includes */ +#include +#include +#include +#include + +/* util includes */ +#include +#include + +/* libc includes */ +#include + +resource_type * rt_seed = 0; +resource_type * rt_mallornseed = 0; + +static void +produce_seeds(region * r, const resource_type * rtype, int norders) +{ + assert(rtype==rt_seed && r->land && r->land->trees[0] >= norders); + r->land->trees[0] -= norders; +} + +static int +limit_seeds(const region * r, const resource_type * rtype) +{ + assert(rtype==rt_seed); + if(fval(r, RF_MALLORN)) return 0; + return r->land?r->land->trees[0]:0; +} + +void +init_seed(void) +{ + attrib * a; + resource_limit * rdata; + + rt_seed = rt_find("seed"); + if (rt_seed!=NULL) { + a = a_add(&rt_seed->attribs, a_new(&at_resourcelimit)); + rdata = (resource_limit*)a->data.v; + rdata->limit = limit_seeds; + rdata->produce = produce_seeds; + } +} + +/* mallorn */ + +static void +produce_mallornseeds(region * r, const resource_type * rtype, int norders) +{ + assert(rtype==rt_mallornseed && r->land && r->land->trees[0] >= norders); + assert(fval(r, RF_MALLORN)); + r->land->trees[0] -= norders; +} + +static int +limit_mallornseeds(const region * r, const resource_type * rtype) +{ + assert(rtype==rt_mallornseed); + if (!fval(r, RF_MALLORN)) { + return 0; + } + return r->land?r->land->trees[0]:0; +} + +void +init_mallornseed(void) +{ + attrib * a; + resource_limit * rdata; + + rt_mallornseed = rt_find("mallornseed"); + if (rt_mallornseed!=NULL) { + rt_mallornseed->flags |= RTF_LIMITED; + rt_mallornseed->flags |= RTF_POOLED; + + a = a_add(&rt_mallornseed->attribs, a_new(&at_resourcelimit)); + rdata = (resource_limit*)a->data.v; + rdata->limit = limit_mallornseeds; + rdata->produce = produce_mallornseeds; + } +} diff --git a/src/items/seed.h b/src/items/seed.h index 7905d8887..d373bfe17 100644 --- a/src/items/seed.h +++ b/src/items/seed.h @@ -1,35 +1,35 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ITM_SEED -#define H_ITM_SEED -#ifdef __cplusplus -extern "C" { -#endif - - -extern struct resource_type * rt_seed; -extern void init_seed(void); - -extern struct resource_type * rt_mallornseed; -extern void init_mallornseed(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ITM_SEED +#define H_ITM_SEED +#ifdef __cplusplus +extern "C" { +#endif + + +extern struct resource_type * rt_seed; +extern void init_seed(void); + +extern struct resource_type * rt_mallornseed; +extern void init_mallornseed(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/speedsail.c b/src/items/speedsail.c index 0d80e9158..e8bbcf793 100644 --- a/src/items/speedsail.c +++ b/src/items/speedsail.c @@ -1,73 +1,73 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "speedsail.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include - -/* libc includes */ -#include - -static int -use_speedsail(struct unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - struct plane * p = rplane(u->region); - unused(amount); - unused(itype); - if (p!=NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "use_realworld_only", "")); - } else { - if (u->ship) { - attrib * a = a_find(u->ship->attribs, &at_speedup); - if (a==NULL) { - a = a_add(&u->ship->attribs, a_new(&at_speedup)); - a->data.sa[0] = 50; /* speed */ - a->data.sa[1] = 50; /* decay */ - ADDMSG(&u->faction->msgs, msg_message("use_speedsail", "unit", u)); - /* Ticket abziehen */ - i_change(&u->items, itype, -1); - return 0; - } else { - cmistake(u, ord, 211, MSG_EVENT); - } - } else { - cmistake(u, ord, 144, MSG_EVENT); - } - } - return EUNUSABLE; -} - -void -register_speedsail(void) -{ - register_item_use(use_speedsail, "use_speedsail"); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "speedsail.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include + +/* libc includes */ +#include + +static int +use_speedsail(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + struct plane * p = rplane(u->region); + unused(amount); + unused(itype); + if (p!=NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "use_realworld_only", "")); + } else { + if (u->ship) { + attrib * a = a_find(u->ship->attribs, &at_speedup); + if (a==NULL) { + a = a_add(&u->ship->attribs, a_new(&at_speedup)); + a->data.sa[0] = 50; /* speed */ + a->data.sa[1] = 50; /* decay */ + ADDMSG(&u->faction->msgs, msg_message("use_speedsail", "unit", u)); + /* Ticket abziehen */ + i_change(&u->items, itype, -1); + return 0; + } else { + cmistake(u, ord, 211, MSG_EVENT); + } + } else { + cmistake(u, ord, 144, MSG_EVENT); + } + } + return EUNUSABLE; +} + +void +register_speedsail(void) +{ + register_item_use(use_speedsail, "use_speedsail"); +} diff --git a/src/items/speedsail.h b/src/items/speedsail.h index 2539571a4..08591893f 100644 --- a/src/items/speedsail.h +++ b/src/items/speedsail.h @@ -1,30 +1,30 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ITM_SPEEDVIAL -#define H_ITM_SPEEDVIAL -#ifdef __cplusplus -extern "C" { -#endif - -extern void register_speedsail(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ITM_SPEEDVIAL +#define H_ITM_SPEEDVIAL +#ifdef __cplusplus +extern "C" { +#endif + +extern void register_speedsail(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/studypotion.c b/src/items/studypotion.c index 91f7b84f3..113048ba7 100644 --- a/src/items/studypotion.c +++ b/src/items/studypotion.c @@ -1,58 +1,58 @@ -#include -#include -#include "studypotion.h" - -#include -#include -#include -#include -#include -#include - -#include -#include - -/* BEGIN it_studypotion */ -#define MAXGAIN 15 -static int -use_studypotion(struct unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - if (get_keyword(u->thisorder) == K_STUDY) { - skill_t sk; - skill * sv; - - init_tokens(u->thisorder); - skip_token(); - sk = findskill(getstrtoken(), u->faction->locale); - sv = get_skill(u, sk); - - if (sv && sv->level > 2) { - /* TODO: message */ - } else if (study_cost(u, sk)>0) { - /* TODO: message */ - } else { - attrib * a = a_find(u->attribs, &at_learning); - teaching_info * teach; - if (a==NULL) { - a = a_add(&u->attribs, a_new(&at_learning)); - } - teach = (teaching_info*) a->data.v; - if (amount>MAXGAIN) amount = MAXGAIN; - teach->value += amount * 30; - if (teach->value > MAXGAIN * 30) { - teach->value = MAXGAIN * 30; - } - i_change(&u->items, itype, -amount); - return 0; - } - } - return EUNUSABLE; -} - -void -register_studypotion(void) -{ - register_function((pf_generic)use_studypotion, "use_studypotion"); -} - -/* END it_studypotion */ +#include +#include +#include "studypotion.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* BEGIN it_studypotion */ +#define MAXGAIN 15 +static int +use_studypotion(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + if (get_keyword(u->thisorder) == K_STUDY) { + skill_t sk; + skill * sv; + + init_tokens(u->thisorder); + skip_token(); + sk = findskill(getstrtoken(), u->faction->locale); + sv = get_skill(u, sk); + + if (sv && sv->level > 2) { + /* TODO: message */ + } else if (study_cost(u, sk)>0) { + /* TODO: message */ + } else { + attrib * a = a_find(u->attribs, &at_learning); + teaching_info * teach; + if (a==NULL) { + a = a_add(&u->attribs, a_new(&at_learning)); + } + teach = (teaching_info*) a->data.v; + if (amount>MAXGAIN) amount = MAXGAIN; + teach->value += amount * 30; + if (teach->value > MAXGAIN * 30) { + teach->value = MAXGAIN * 30; + } + i_change(&u->items, itype, -amount); + return 0; + } + } + return EUNUSABLE; +} + +void +register_studypotion(void) +{ + register_function((pf_generic)use_studypotion, "use_studypotion"); +} + +/* END it_studypotion */ diff --git a/src/items/studypotion.h b/src/items/studypotion.h index 454f137c2..8131bb7fb 100644 --- a/src/items/studypotion.h +++ b/src/items/studypotion.h @@ -1,30 +1,30 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ITM_STUDYPOTION -#define H_ITM_STUDYPOTION -#ifdef __cplusplus -extern "C" { -#endif - - extern void register_studypotion(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ITM_STUDYPOTION +#define H_ITM_STUDYPOTION +#ifdef __cplusplus +extern "C" { +#endif + + extern void register_studypotion(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/weapons.c b/src/items/weapons.c index 11c0379c8..c3ac842cf 100644 --- a/src/items/weapons.c +++ b/src/items/weapons.c @@ -1,155 +1,155 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "weapons.h" - -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include - -/* libc includes */ -#include -#include - -/* damage types */ - -static boolean -attack_firesword(const troop * at, const struct weapon_type * wtype, int *casualties) -{ - fighter *fi = at->fighter; - troop dt; - int killed = 0; - const char *damage = "2d8"; - int force = 1+rng_int()%10; - int enemies = count_enemies(fi->side->battle, fi, 0, 1, SELECT_ADVANCE|SELECT_DISTANCE); - - if (!enemies) { - if (casualties) *casualties = 0; - return true; /* if no enemy found, no use doing standarad attack */ - } - - if (fi->catmsg == -1) { - int i, k=0; - message * msg; - for (i=0;i<=at->index;++i) { - struct weapon * wp = fi->person[i].melee; - if (wp!=NULL && wp->type == wtype) ++k; - } - msg = msg_message("battle::useflamingsword", "amount unit", k, fi->unit); - message_all(fi->side->battle, msg); - msg_release(msg); - fi->catmsg = 0; - } - - do { - dt = select_enemy(fi, 0, 1, SELECT_ADVANCE|SELECT_DISTANCE); - assert(dt.fighter); - --force; - killed += terminate(dt, *at, AT_SPELL, damage, 1); - } while (force && killed < enemies); - if (casualties) *casualties = killed; - return true; -} - -#define CATAPULT_ATTACKS 6 - -static boolean -attack_catapult(const troop * at, const struct weapon_type * wtype, int * casualties) -{ - fighter *af = at->fighter; - unit *au = af->unit; - battle * b = af->side->battle; - troop dt; - int d = 0, enemies; - weapon * wp = af->person[at->index].missile; - static item_type * it_catapultammo = NULL; - if (it_catapultammo==NULL) { - it_catapultammo = it_find("catapultammo"); - } - - assert(wp->type==wtype); - assert(af->person[at->index].reload==0); - - if (it_catapultammo!=NULL) { - if (get_pooled(au, it_catapultammo->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, 1) <= 0) { - /* No ammo. Use other weapon if available. */ - return true; - } - } - - enemies = count_enemies(b, af, FIGHT_ROW, FIGHT_ROW, SELECT_ADVANCE); - enemies = MIN(enemies, CATAPULT_ATTACKS); - if (enemies==0) { - return true; /* allow further attacks */ - } - - if (af->catmsg == -1) { - int i, k=0; - message * msg; - - for (i=0;i<=at->index;++i) { - if (af->person[i].reload==0 && af->person[i].missile == wp) ++k; - } - msg = msg_message("battle::usecatapult", "amount unit", k, au); - message_all(b, msg); - msg_release(msg); - af->catmsg = 0; - } - - if (it_catapultammo!=NULL) { - use_pooled(au, it_catapultammo->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, 1); - } - - while (--enemies >= 0) { - /* Select defender */ - dt = select_enemy(af, FIGHT_ROW, FIGHT_ROW, SELECT_ADVANCE); - if (!dt.fighter) - break; - - /* If battle succeeds */ - if (hits(*at, dt, wp)) { - d += terminate(dt, *at, AT_STANDARD, wp->type->damage[0], true); -#ifdef CATAPULT_STRUCTURAL_DAMAGE - if (dt.fighter->unit->building && rng_int()%100 < 5) { - damage_building(b, dt.fighter->unit->building, 1); - } else if (dt.fighter->unit->ship && rng_int()%100 < 5) { - dt.fighter->unit->ship->damage+=DAMAGE_SCALE; - } -#endif - } - } - - if (casualties) *casualties = d; - return false; /* keine weitren attacken */ -} -void -register_weapons(void) -{ - register_function((pf_generic)attack_catapult, "attack_catapult"); - register_function((pf_generic)attack_firesword, "attack_firesword"); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "weapons.h" + +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include + +/* libc includes */ +#include +#include + +/* damage types */ + +static boolean +attack_firesword(const troop * at, const struct weapon_type * wtype, int *casualties) +{ + fighter *fi = at->fighter; + troop dt; + int killed = 0; + const char *damage = "2d8"; + int force = 1+rng_int()%10; + int enemies = count_enemies(fi->side->battle, fi, 0, 1, SELECT_ADVANCE|SELECT_DISTANCE); + + if (!enemies) { + if (casualties) *casualties = 0; + return true; /* if no enemy found, no use doing standarad attack */ + } + + if (fi->catmsg == -1) { + int i, k=0; + message * msg; + for (i=0;i<=at->index;++i) { + struct weapon * wp = fi->person[i].melee; + if (wp!=NULL && wp->type == wtype) ++k; + } + msg = msg_message("battle::useflamingsword", "amount unit", k, fi->unit); + message_all(fi->side->battle, msg); + msg_release(msg); + fi->catmsg = 0; + } + + do { + dt = select_enemy(fi, 0, 1, SELECT_ADVANCE|SELECT_DISTANCE); + assert(dt.fighter); + --force; + killed += terminate(dt, *at, AT_SPELL, damage, 1); + } while (force && killed < enemies); + if (casualties) *casualties = killed; + return true; +} + +#define CATAPULT_ATTACKS 6 + +static boolean +attack_catapult(const troop * at, const struct weapon_type * wtype, int * casualties) +{ + fighter *af = at->fighter; + unit *au = af->unit; + battle * b = af->side->battle; + troop dt; + int d = 0, enemies; + weapon * wp = af->person[at->index].missile; + static item_type * it_catapultammo = NULL; + if (it_catapultammo==NULL) { + it_catapultammo = it_find("catapultammo"); + } + + assert(wp->type==wtype); + assert(af->person[at->index].reload==0); + + if (it_catapultammo!=NULL) { + if (get_pooled(au, it_catapultammo->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, 1) <= 0) { + /* No ammo. Use other weapon if available. */ + return true; + } + } + + enemies = count_enemies(b, af, FIGHT_ROW, FIGHT_ROW, SELECT_ADVANCE); + enemies = MIN(enemies, CATAPULT_ATTACKS); + if (enemies==0) { + return true; /* allow further attacks */ + } + + if (af->catmsg == -1) { + int i, k=0; + message * msg; + + for (i=0;i<=at->index;++i) { + if (af->person[i].reload==0 && af->person[i].missile == wp) ++k; + } + msg = msg_message("battle::usecatapult", "amount unit", k, au); + message_all(b, msg); + msg_release(msg); + af->catmsg = 0; + } + + if (it_catapultammo!=NULL) { + use_pooled(au, it_catapultammo->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, 1); + } + + while (--enemies >= 0) { + /* Select defender */ + dt = select_enemy(af, FIGHT_ROW, FIGHT_ROW, SELECT_ADVANCE); + if (!dt.fighter) + break; + + /* If battle succeeds */ + if (hits(*at, dt, wp)) { + d += terminate(dt, *at, AT_STANDARD, wp->type->damage[0], true); +#ifdef CATAPULT_STRUCTURAL_DAMAGE + if (dt.fighter->unit->building && rng_int()%100 < 5) { + damage_building(b, dt.fighter->unit->building, 1); + } else if (dt.fighter->unit->ship && rng_int()%100 < 5) { + dt.fighter->unit->ship->damage+=DAMAGE_SCALE; + } +#endif + } + } + + if (casualties) *casualties = d; + return false; /* keine weitren attacken */ +} +void +register_weapons(void) +{ + register_function((pf_generic)attack_catapult, "attack_catapult"); + register_function((pf_generic)attack_firesword, "attack_firesword"); +} diff --git a/src/items/weapons.h b/src/items/weapons.h index cc44aa390..7ff4f0683 100644 --- a/src/items/weapons.h +++ b/src/items/weapons.h @@ -1,24 +1,24 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_ITM_WEAPONS -#define H_ITM_WEAPONS -#ifdef __cplusplus -extern "C" { -#endif - -extern void register_weapons(void); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_ITM_WEAPONS +#define H_ITM_WEAPONS +#ifdef __cplusplus +extern "C" { +#endif + +extern void register_weapons(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/xerewards.c b/src/items/xerewards.c index c7cda363a..1e0140ac5 100644 --- a/src/items/xerewards.c +++ b/src/items/xerewards.c @@ -1,91 +1,91 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "xerewards.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include - -/* libc includes */ -#include -#include -#include - -static int -use_skillpotion(struct unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - /* the problem with making this a lua function is that there's no way - * to get the list of skills for a unit. and with the way skills are - * currently saved, it doesn't look likely (can't make eressea::list - * from them) - */ - int n; - for (n=0;n!=amount;++n) { - skill * sv = u->skills; - while (sv!=u->skills+u->skill_size) { - int i; - for (i=0;i!=3;++i) learn_skill(u, sv->id, 1.0); - ++sv; - } - } - ADDMSG(&u->faction->msgs, msg_message("skillpotion_use", "unit", u)); - - res_changeitem(u, itype->rtype, -amount); - return 0; -} - -static int -use_manacrystal(struct unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - int i, sp = 0; - - if(!is_mage(u)) { - cmistake(u, u->thisorder, 295, MSG_EVENT); - return -1; - } - - for (i=0;i!=amount;++i) { - sp += MAX(25, max_spellpoints(u->region, u)/2); - change_spellpoints(u, sp); - } - - ADDMSG(&u->faction->msgs, msg_message("manacrystal_use", "unit aura", u, sp)); - - res_changeitem(u, itype->rtype, -amount); - return 0; -} - -void -register_xerewards(void) -{ - register_item_use(use_skillpotion, "use_skillpotion"); - register_item_use(use_manacrystal, "use_manacrystal"); -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "xerewards.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include + +/* libc includes */ +#include +#include +#include + +static int +use_skillpotion(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + /* the problem with making this a lua function is that there's no way + * to get the list of skills for a unit. and with the way skills are + * currently saved, it doesn't look likely (can't make eressea::list + * from them) + */ + int n; + for (n=0;n!=amount;++n) { + skill * sv = u->skills; + while (sv!=u->skills+u->skill_size) { + int i; + for (i=0;i!=3;++i) learn_skill(u, sv->id, 1.0); + ++sv; + } + } + ADDMSG(&u->faction->msgs, msg_message("skillpotion_use", "unit", u)); + + res_changeitem(u, itype->rtype, -amount); + return 0; +} + +static int +use_manacrystal(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + int i, sp = 0; + + if(!is_mage(u)) { + cmistake(u, u->thisorder, 295, MSG_EVENT); + return -1; + } + + for (i=0;i!=amount;++i) { + sp += MAX(25, max_spellpoints(u->region, u)/2); + change_spellpoints(u, sp); + } + + ADDMSG(&u->faction->msgs, msg_message("manacrystal_use", "unit aura", u, sp)); + + res_changeitem(u, itype->rtype, -amount); + return 0; +} + +void +register_xerewards(void) +{ + register_item_use(use_skillpotion, "use_skillpotion"); + register_item_use(use_manacrystal, "use_manacrystal"); +} + diff --git a/src/items/xerewards.h b/src/items/xerewards.h index c914c5ed4..c23d6014b 100644 --- a/src/items/xerewards.h +++ b/src/items/xerewards.h @@ -1,30 +1,30 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ITM_XEREWARDS -#define H_ITM_XEREWARDS -#ifdef __cplusplus -extern "C" { -#endif - -extern void register_xerewards(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ITM_XEREWARDS +#define H_ITM_XEREWARDS +#ifdef __cplusplus +extern "C" { +#endif + +extern void register_xerewards(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel.vcproj b/src/kernel.vcproj index 43f2c50a0..17a487ae5 100644 --- a/src/kernel.vcproj +++ b/src/kernel.vcproj @@ -1,948 +1,948 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/kernel.vcxproj b/src/kernel.vcxproj index 31a4ee968..cc64219c6 100644 --- a/src/kernel.vcxproj +++ b/src/kernel.vcxproj @@ -1,289 +1,291 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {6F104C0A-DDF5-A34B-A89C-0DC278DCEF6D} - kernel - Win32Proj - - - - StaticLibrary - MultiByte - - - StaticLibrary - MultiByte - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - - - - /MP %(AdditionalOptions) - Disabled - .;../../external;%(AdditionalIncludeDirectories) - WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - true - - - Level4 - true - EditAndContinue - - - WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - ..;.;%(AdditionalIncludeDirectories) - - - $(OutDir)kernel.lib - - - - - Full - .;../../external;%(AdditionalIncludeDirectories) - WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) - true - MultiThreadedDLL - true - - - Level4 - - - - - WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) - ..;.;%(AdditionalIncludeDirectories) - - - $(OutDir)kernel.lib - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + + {6F104C0A-DDF5-A34B-A89C-0DC278DCEF6D} + kernel + Win32Proj + + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + + + + /MP %(AdditionalOptions) + Disabled + .;..\..\external;..\..\external\libxml2\include;%(AdditionalIncludeDirectories) + WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + true + + + Level4 + true + EditAndContinue + + + WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + ..;.;%(AdditionalIncludeDirectories) + + + $(OutDir)kernel.lib + + + + + Full + .;..\..\external;..\..\external\libxml2\include;%(AdditionalIncludeDirectories) + WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + + + Level4 + + + + + WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) + ..;.;%(AdditionalIncludeDirectories) + + + $(OutDir)kernel.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/kernel.vcxproj.filters b/src/kernel.vcxproj.filters index 65b46ba39..38fd989f5 100644 --- a/src/kernel.vcxproj.filters +++ b/src/kernel.vcxproj.filters @@ -1,598 +1,598 @@ - - - - - {0d7b749c-a7f2-4791-b356-6ae450020131} - - - {0ebbe376-a35f-44f6-97c6-9b449a839ddb} - - - {0f293992-e32e-49fb-a5f2-74686b0d042e} - - - {e12969f3-9de3-4f65-812d-1e120875a15c} - - - {c10dd4f8-3a6a-470b-8a04-bb652854e228} - - - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - items - - - items - - - items - - - items - - - items - - - items - - - items - - - items - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - items - - - items - - - items - - - items - - - items - - - items - - - items - - - items - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - + + + + + {0d7b749c-a7f2-4791-b356-6ae450020131} + + + {0ebbe376-a35f-44f6-97c6-9b449a839ddb} + + + {0f293992-e32e-49fb-a5f2-74686b0d042e} + + + {e12969f3-9de3-4f65-812d-1e120875a15c} + + + {c10dd4f8-3a6a-470b-8a04-bb652854e228} + + + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + items + + + items + + + items + + + items + + + items + + + items + + + items + + + items + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + kernel + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + triggers + + + items + + + items + + + items + + + items + + + items + + + items + + + items + + + items + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + modules + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + + attributes + + \ No newline at end of file diff --git a/src/kernel/alchemy.c b/src/kernel/alchemy.c index 05f06471a..f79d59abf 100644 --- a/src/kernel/alchemy.c +++ b/src/kernel/alchemy.c @@ -1,338 +1,338 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "alchemy.h" - -#include "item.h" -#include "faction.h" -#include "message.h" -#include "build.h" -#include "magic.h" -#include "region.h" -#include "pool.h" -#include "race.h" -#include "unit.h" -#include "skill.h" -#include "move.h" - -/* util includes */ -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -/* ------------------------------------------------------------- */ - -void -herbsearch(region * r, unit * u, int max) -{ - int herbsfound; - const item_type * whichherb; - - if (eff_skill(u, SK_HERBALISM, r) == 0) { - cmistake(u, u->thisorder, 59, MSG_PRODUCE); - return; - } - - if(is_guarded(r, u, GUARD_PRODUCE)) { - cmistake(u, u->thisorder, 70, MSG_EVENT); - return; - } - - whichherb = rherbtype(r); - if (whichherb == NULL) { - cmistake(u, u->thisorder, 108, MSG_PRODUCE); - return; - } - - if (max) max = MIN(max, rherbs(r)); - else max = rherbs(r); - herbsfound = ntimespprob(eff_skill(u, SK_HERBALISM, r) * u->number, - (double)rherbs(r)/100.0F, -0.01F); - herbsfound = MIN(herbsfound, max); - rsetherbs(r, rherbs(r)-herbsfound); - - if (herbsfound) { - produceexp(u, SK_HERBALISM, u->number); - i_change(&u->items, whichherb, herbsfound); - ADDMSG(&u->faction->msgs, msg_message("herbfound", - "unit region amount herb", u, r, herbsfound, whichherb->rtype)); - } else { - ADDMSG(&u->faction->msgs, msg_message("researchherb_none", - "unit region", u, u->region)); - } -} - -static int -begin_potion(unit * u, const potion_type * ptype, struct order *ord) -{ - static int rule_multipotion = -1; - assert(ptype!=NULL); - - if (rule_multipotion<0) { - /* should we allow multiple different potions to be used the same turn? */ - rule_multipotion = get_param_int(global.parameters, "rules.magic.multipotion", 0); - } - if (!rule_multipotion) { - const potion_type * use = ugetpotionuse(u); - if (use != NULL && use!=ptype) { - ADDMSG(&u->faction->msgs, - msg_message("errusingpotion", "unit using command", - u, use->itype->rtype, ord)); - return ECUSTOM; - } - } - return 0; -} - -static void -end_potion(unit * u, const potion_type * ptype, int amount) -{ - use_pooled(u, ptype->itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); - usetpotionuse(u, ptype); - - ADDMSG(&u->faction->msgs, msg_message("usepotion", - "unit potion", u, ptype->itype->rtype)); -} - -void -do_potion(unit * u, const potion_type * ptype, int amount) -{ - if (ptype==oldpotiontype[P_LIFE]) { - region * r = u->region; - int holz = 0; - static int tree_type = -1; - static int tree_count = -1; - if (tree_type<0) { - tree_type = get_param_int(global.parameters, "rules.magic.wol_type", 1); - tree_count = get_param_int(global.parameters, "rules.magic.wol_effect", 10); - } - /* mallorn is required to make mallorn forests, wood for regular ones */ - if (fval(r, RF_MALLORN)) { - holz = use_pooled(u, rt_find("mallorn"), - GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, tree_count*amount); - } else { - holz = use_pooled(u, rt_find("log"), - GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, tree_count*amount); - } - if (r->land==0) holz = 0; - if (holzfaction->msgs, msg_message("growtree_effect", - "mage amount", u, holz)); - } else if (ptype==oldpotiontype[P_HEILWASSER]) { - u->hp = MIN(unit_max_hp(u) * u->number, u->hp + 400 * amount); - } else if (ptype==oldpotiontype[P_PEOPLE]) { - region * r = u->region; - attrib * a = (attrib*)a_find(r->attribs, &at_peasantluck); - if (!a) a = a_add(&r->attribs, a_new(&at_peasantluck)); - a->data.i+=amount; - } else if (ptype==oldpotiontype[P_HORSE]) { - region * r = u->region; - attrib * a = (attrib*)a_find(r->attribs, &at_horseluck); - if (!a) a = a_add(&r->attribs, a_new(&at_horseluck)); - a->data.i+=amount; - } else if (ptype==oldpotiontype[P_WAHRHEIT]) { - fset(u, UFL_DISBELIEVES); - amount=1; - } else if (ptype==oldpotiontype[P_MACHT]) { - /* Verfünffacht die HP von max. 10 Personen in der Einheit */ - u->hp += MIN(u->number, 10*amount) * unit_max_hp(u) * 4; - } else { - change_effect(u, ptype, 10*amount); - } -} - -int -use_potion(unit * u, const item_type * itype, int amount, struct order *ord) -{ - const potion_type * ptype = resource2potion(itype->rtype); - - if (oldpotiontype[P_HEAL] && ptype==oldpotiontype[P_HEAL]) { - return EUNUSABLE; - } else { - int result = begin_potion(u, ptype, ord); - if (result) return result; - do_potion(u, ptype, amount); - end_potion(u, ptype, amount); - } - return 0; -} - -typedef struct potiondelay { - unit * u; - const potion_type * ptype; - int amount; -} potiondelay; - -static void init_potiondelay(attrib * a) { - a->data.v = malloc(sizeof(potiondelay)); -} - -static void free_potiondelay(attrib * a) { - free(a->data.v); -} - -static int age_potiondelay(attrib * a) { - potiondelay * pd = (potiondelay *)a->data.v; - do_potion(pd->u, pd->ptype, pd->amount); - return AT_AGE_REMOVE; -} - -/* TODO: - * - this should be a more general item_delay - * - it should not just happen in age(), but be done with eventhandling - */ -attrib_type at_potiondelay = { - "potiondelay", - init_potiondelay, - free_potiondelay, - age_potiondelay, 0, 0 -}; - -static attrib * -make_potiondelay(unit * u, const potion_type* ptype, int amount) -{ - attrib * a = a_new(&at_potiondelay); - potiondelay * pd = (potiondelay *)a->data.v; - pd->u = u; - pd->ptype = ptype; - pd->amount = amount; - return a; -} - -int -use_potion_delayed(unit * u, const item_type * itype, int amount, struct order *ord) -{ - const potion_type * ptype = resource2potion(itype->rtype); - int result = begin_potion(u, ptype, ord); - if (result) return result; - - a_add(&u->attribs, make_potiondelay(u, ptype, amount)); - - end_potion(u, ptype, amount); - return 0; -} - -/*****************/ -/* at_effect */ -/*****************/ - -static void -a_initeffect(attrib *a) -{ - a->data.v = calloc(sizeof(effect_data), 1); -} - -static void -a_finalizeeffect(attrib * a) -{ - free(a->data.v); -} - -static void -a_writeeffect(const attrib * a, const void * owner, struct storage * store) -{ - effect_data * edata = (effect_data*)a->data.v; - store->w_tok(store, resourcename(edata->type->itype->rtype, 0)); - store->w_int(store, edata->value); -} - -static int -a_readeffect(attrib *a, void * owner, struct storage * store) -{ - int power; - const item_type * itype; - effect_data * edata = (effect_data*)a->data.v; - char zText[32]; - - store->r_tok_buf(store, zText, sizeof(zText)); - itype = it_find(zText); - - power = store->r_int(store); - if (itype==NULL || itype->rtype==NULL || itype->rtype->ptype==NULL || power<=0) { - return AT_READ_FAIL; - } - edata->type = itype->rtype->ptype; - edata->value = power; - return AT_READ_OK; -} - -attrib_type at_effect = { - "effect", - a_initeffect, - a_finalizeeffect, - DEFAULT_AGE, - a_writeeffect, - a_readeffect, -}; - -int -get_effect(const unit * u, const potion_type * effect) -{ - const attrib * a; - for (a=a_find(u->attribs, &at_effect); a!=NULL && a->type==&at_effect; a=a->next) { - const effect_data * data = (const effect_data *)a->data.v; - if (data->type==effect) return data->value; - } - return 0; -} - -int -change_effect (unit * u, const potion_type * effect, int delta) -{ - if (delta!=0) { - attrib * a = a_find(u->attribs, &at_effect); - effect_data * data = NULL; - - while (a && a->type==&at_effect) { - data = (effect_data *)a->data.v; - if (data->type==effect) { - if (data->value+delta==0) { - a_remove(&u->attribs, a); - return 0; - } else { - data->value += delta; - return data->value; - } - } - a = a->next; - } - - a = a_add(&u->attribs, a_new(&at_effect)); - data = (effect_data*)a->data.v; - data->type = effect; - data->value = delta; - return data->value; - } - log_error(("change effect with delta==0 for unit %s\n", itoa36(u->no))); - return 0; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "alchemy.h" + +#include "item.h" +#include "faction.h" +#include "message.h" +#include "build.h" +#include "magic.h" +#include "region.h" +#include "pool.h" +#include "race.h" +#include "unit.h" +#include "skill.h" +#include "move.h" + +/* util includes */ +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +/* ------------------------------------------------------------- */ + +void +herbsearch(region * r, unit * u, int max) +{ + int herbsfound; + const item_type * whichherb; + + if (eff_skill(u, SK_HERBALISM, r) == 0) { + cmistake(u, u->thisorder, 59, MSG_PRODUCE); + return; + } + + if(is_guarded(r, u, GUARD_PRODUCE)) { + cmistake(u, u->thisorder, 70, MSG_EVENT); + return; + } + + whichherb = rherbtype(r); + if (whichherb == NULL) { + cmistake(u, u->thisorder, 108, MSG_PRODUCE); + return; + } + + if (max) max = MIN(max, rherbs(r)); + else max = rherbs(r); + herbsfound = ntimespprob(eff_skill(u, SK_HERBALISM, r) * u->number, + (double)rherbs(r)/100.0F, -0.01F); + herbsfound = MIN(herbsfound, max); + rsetherbs(r, rherbs(r)-herbsfound); + + if (herbsfound) { + produceexp(u, SK_HERBALISM, u->number); + i_change(&u->items, whichherb, herbsfound); + ADDMSG(&u->faction->msgs, msg_message("herbfound", + "unit region amount herb", u, r, herbsfound, whichherb->rtype)); + } else { + ADDMSG(&u->faction->msgs, msg_message("researchherb_none", + "unit region", u, u->region)); + } +} + +static int +begin_potion(unit * u, const potion_type * ptype, struct order *ord) +{ + static int rule_multipotion = -1; + assert(ptype!=NULL); + + if (rule_multipotion<0) { + /* should we allow multiple different potions to be used the same turn? */ + rule_multipotion = get_param_int(global.parameters, "rules.magic.multipotion", 0); + } + if (!rule_multipotion) { + const potion_type * use = ugetpotionuse(u); + if (use != NULL && use!=ptype) { + ADDMSG(&u->faction->msgs, + msg_message("errusingpotion", "unit using command", + u, use->itype->rtype, ord)); + return ECUSTOM; + } + } + return 0; +} + +static void +end_potion(unit * u, const potion_type * ptype, int amount) +{ + use_pooled(u, ptype->itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); + usetpotionuse(u, ptype); + + ADDMSG(&u->faction->msgs, msg_message("usepotion", + "unit potion", u, ptype->itype->rtype)); +} + +void +do_potion(unit * u, const potion_type * ptype, int amount) +{ + if (ptype==oldpotiontype[P_LIFE]) { + region * r = u->region; + int holz = 0; + static int tree_type = -1; + static int tree_count = -1; + if (tree_type<0) { + tree_type = get_param_int(global.parameters, "rules.magic.wol_type", 1); + tree_count = get_param_int(global.parameters, "rules.magic.wol_effect", 10); + } + /* mallorn is required to make mallorn forests, wood for regular ones */ + if (fval(r, RF_MALLORN)) { + holz = use_pooled(u, rt_find("mallorn"), + GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, tree_count*amount); + } else { + holz = use_pooled(u, rt_find("log"), + GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, tree_count*amount); + } + if (r->land==0) holz = 0; + if (holzfaction->msgs, msg_message("growtree_effect", + "mage amount", u, holz)); + } else if (ptype==oldpotiontype[P_HEILWASSER]) { + u->hp = MIN(unit_max_hp(u) * u->number, u->hp + 400 * amount); + } else if (ptype==oldpotiontype[P_PEOPLE]) { + region * r = u->region; + attrib * a = (attrib*)a_find(r->attribs, &at_peasantluck); + if (!a) a = a_add(&r->attribs, a_new(&at_peasantluck)); + a->data.i+=amount; + } else if (ptype==oldpotiontype[P_HORSE]) { + region * r = u->region; + attrib * a = (attrib*)a_find(r->attribs, &at_horseluck); + if (!a) a = a_add(&r->attribs, a_new(&at_horseluck)); + a->data.i+=amount; + } else if (ptype==oldpotiontype[P_WAHRHEIT]) { + fset(u, UFL_DISBELIEVES); + amount=1; + } else if (ptype==oldpotiontype[P_MACHT]) { + /* Verfünffacht die HP von max. 10 Personen in der Einheit */ + u->hp += MIN(u->number, 10*amount) * unit_max_hp(u) * 4; + } else { + change_effect(u, ptype, 10*amount); + } +} + +int +use_potion(unit * u, const item_type * itype, int amount, struct order *ord) +{ + const potion_type * ptype = resource2potion(itype->rtype); + + if (oldpotiontype[P_HEAL] && ptype==oldpotiontype[P_HEAL]) { + return EUNUSABLE; + } else { + int result = begin_potion(u, ptype, ord); + if (result) return result; + do_potion(u, ptype, amount); + end_potion(u, ptype, amount); + } + return 0; +} + +typedef struct potiondelay { + unit * u; + const potion_type * ptype; + int amount; +} potiondelay; + +static void init_potiondelay(attrib * a) { + a->data.v = malloc(sizeof(potiondelay)); +} + +static void free_potiondelay(attrib * a) { + free(a->data.v); +} + +static int age_potiondelay(attrib * a) { + potiondelay * pd = (potiondelay *)a->data.v; + do_potion(pd->u, pd->ptype, pd->amount); + return AT_AGE_REMOVE; +} + +/* TODO: + * - this should be a more general item_delay + * - it should not just happen in age(), but be done with eventhandling + */ +attrib_type at_potiondelay = { + "potiondelay", + init_potiondelay, + free_potiondelay, + age_potiondelay, 0, 0 +}; + +static attrib * +make_potiondelay(unit * u, const potion_type* ptype, int amount) +{ + attrib * a = a_new(&at_potiondelay); + potiondelay * pd = (potiondelay *)a->data.v; + pd->u = u; + pd->ptype = ptype; + pd->amount = amount; + return a; +} + +int +use_potion_delayed(unit * u, const item_type * itype, int amount, struct order *ord) +{ + const potion_type * ptype = resource2potion(itype->rtype); + int result = begin_potion(u, ptype, ord); + if (result) return result; + + a_add(&u->attribs, make_potiondelay(u, ptype, amount)); + + end_potion(u, ptype, amount); + return 0; +} + +/*****************/ +/* at_effect */ +/*****************/ + +static void +a_initeffect(attrib *a) +{ + a->data.v = calloc(sizeof(effect_data), 1); +} + +static void +a_finalizeeffect(attrib * a) +{ + free(a->data.v); +} + +static void +a_writeeffect(const attrib * a, const void * owner, struct storage * store) +{ + effect_data * edata = (effect_data*)a->data.v; + store->w_tok(store, resourcename(edata->type->itype->rtype, 0)); + store->w_int(store, edata->value); +} + +static int +a_readeffect(attrib *a, void * owner, struct storage * store) +{ + int power; + const item_type * itype; + effect_data * edata = (effect_data*)a->data.v; + char zText[32]; + + store->r_tok_buf(store, zText, sizeof(zText)); + itype = it_find(zText); + + power = store->r_int(store); + if (itype==NULL || itype->rtype==NULL || itype->rtype->ptype==NULL || power<=0) { + return AT_READ_FAIL; + } + edata->type = itype->rtype->ptype; + edata->value = power; + return AT_READ_OK; +} + +attrib_type at_effect = { + "effect", + a_initeffect, + a_finalizeeffect, + DEFAULT_AGE, + a_writeeffect, + a_readeffect, +}; + +int +get_effect(const unit * u, const potion_type * effect) +{ + const attrib * a; + for (a=a_find(u->attribs, &at_effect); a!=NULL && a->type==&at_effect; a=a->next) { + const effect_data * data = (const effect_data *)a->data.v; + if (data->type==effect) return data->value; + } + return 0; +} + +int +change_effect (unit * u, const potion_type * effect, int delta) +{ + if (delta!=0) { + attrib * a = a_find(u->attribs, &at_effect); + effect_data * data = NULL; + + while (a && a->type==&at_effect) { + data = (effect_data *)a->data.v; + if (data->type==effect) { + if (data->value+delta==0) { + a_remove(&u->attribs, a); + return 0; + } else { + data->value += delta; + return data->value; + } + } + a = a->next; + } + + a = a_add(&u->attribs, a_new(&at_effect)); + data = (effect_data*)a->data.v; + data->type = effect; + data->value = delta; + return data->value; + } + log_error(("change effect with delta==0 for unit %s\n", itoa36(u->no))); + return 0; +} diff --git a/src/kernel/alchemy.h b/src/kernel/alchemy.h index 128286cd1..ba89d242b 100644 --- a/src/kernel/alchemy.h +++ b/src/kernel/alchemy.h @@ -1,70 +1,70 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_ALCHEMY_H -#define H_KRNL_ALCHEMY_H -#ifdef __cplusplus -extern "C" { -#endif - -enum { - /* Stufe 1 */ - P_FAST, - P_STRONG, - P_LIFE, - /* Stufe 2 */ - P_DOMORE, - P_HEILWASSER, - P_BAUERNBLUT, - /* Stufe 3 */ - P_WISE, /* 6 */ - P_FOOL, -#ifdef INSECT_POTION - P_WARMTH, -#else - P_STEEL, -#endif - P_HORSE, - P_BERSERK, /* 10 */ - /* Stufe 4 */ - P_PEOPLE, - P_WAHRHEIT, - P_MACHT, - P_HEAL, - MAX_POTIONS -}; - -extern void herbsearch(struct region * r, struct unit * u, int max); -extern int use_potion(struct unit * u, const struct item_type * itype, int amount, struct order *); -extern int use_potion_delayed(struct unit * u, const struct item_type * itype, int amount, struct order *); -extern void init_potions(void); - -extern int get_effect(const struct unit * u, const struct potion_type * effect); -extern int change_effect(struct unit * u, const struct potion_type * effect, int value); -extern struct attrib_type at_effect; - -/* rausnehmen, sobald man attribute splitten kann: */ -typedef struct effect_data { - const struct potion_type * type; - int value; -} effect_data; - -#ifdef __cplusplus -} -#endif -#endif /* ALCHEMY_H */ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_ALCHEMY_H +#define H_KRNL_ALCHEMY_H +#ifdef __cplusplus +extern "C" { +#endif + +enum { + /* Stufe 1 */ + P_FAST, + P_STRONG, + P_LIFE, + /* Stufe 2 */ + P_DOMORE, + P_HEILWASSER, + P_BAUERNBLUT, + /* Stufe 3 */ + P_WISE, /* 6 */ + P_FOOL, +#ifdef INSECT_POTION + P_WARMTH, +#else + P_STEEL, +#endif + P_HORSE, + P_BERSERK, /* 10 */ + /* Stufe 4 */ + P_PEOPLE, + P_WAHRHEIT, + P_MACHT, + P_HEAL, + MAX_POTIONS +}; + +extern void herbsearch(struct region * r, struct unit * u, int max); +extern int use_potion(struct unit * u, const struct item_type * itype, int amount, struct order *); +extern int use_potion_delayed(struct unit * u, const struct item_type * itype, int amount, struct order *); +extern void init_potions(void); + +extern int get_effect(const struct unit * u, const struct potion_type * effect); +extern int change_effect(struct unit * u, const struct potion_type * effect, int value); +extern struct attrib_type at_effect; + +/* rausnehmen, sobald man attribute splitten kann: */ +typedef struct effect_data { + const struct potion_type * type; + int value; +} effect_data; + +#ifdef __cplusplus +} +#endif +#endif /* ALCHEMY_H */ diff --git a/src/kernel/alliance.c b/src/kernel/alliance.c index cec763793..f1d77b7b6 100644 --- a/src/kernel/alliance.c +++ b/src/kernel/alliance.c @@ -1,548 +1,548 @@ -/* vi: set ts=2: -+-------------------+ Christian Schlittchen -| | Enno Rehling -| Eressea PBEM host | Katja Zedel -| (c) 1998 - 2003 | Henning Peters -| | Ingo Wilken -+-------------------+ Stefan Reich - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#pragma region includes - -#include -#include -#include "alliance.h" - -#include - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -#pragma endregion - -alliance * alliances = NULL; - -void -free_alliance(alliance * al) -{ - free(al->name); - while (al->members) { - faction_list * m = al->members; - al->members = m->next; - free(m); - } - free(al); -} - -alliance * -makealliance(int id, const char * name) -{ - alliance * al;; - - for (;;) { - if (id>0) { - for (al=alliances;al;al=al->next) { - if (al->id==id) { - id = 0; - break; - } - } - if (id>0) break; - } - id = id?id:(1 + (rng_int() % MAX_UNIT_NR)); - } - al = calloc(1, sizeof(alliance)); - al->id = id; - if (name) { - al->name = strdup(name); - } else { - al->flags |= ALF_NON_ALLIED; - } - al->next = alliances; - return alliances=al; -} - -alliance * -findalliance(int id) -{ - alliance * al; - for (al=alliances;al;al=al->next) { - if (al->id==id) return al; - } - return NULL; -} - -typedef struct alliance_transaction { - struct alliance_transaction * next; - unit * u; - order * ord; -// alliance * al; -// variant userdata; -} alliance_transaction; - -static struct alliance_transaction * transactions[ALLIANCE_MAX]; - - -faction * -alliance_get_leader(alliance * al) -{ - if (!al->_leader) { - if (al->members) { - al->_leader = al->members->data; - } - } - return al->_leader; -} - -static void -create_transaction(int type, unit * u, order * ord) -{ - alliance_transaction * tr = calloc(1, sizeof(alliance_transaction)); - tr->ord = ord; - tr->u = u; - tr->next = transactions[type]; - transactions[type] = tr; -} - -static void -cmd_kick(const tnode * tnext, void * data, struct order * ord) -{ - create_transaction(ALLIANCE_KICK, (unit*)data, ord); -} - -static void -cmd_leave(const tnode * tnext, void * data, struct order * ord) -{ - create_transaction(ALLIANCE_LEAVE, (unit*)data, ord); -} - -static void -cmd_transfer(const tnode * tnext, void * data, struct order * ord) -{ - create_transaction(ALLIANCE_TRANSFER, (unit*)data, ord); -} - -static void -cmd_new(const tnode * tnext, void * data, struct order * ord) -{ - create_transaction(ALLIANCE_NEW, (unit*)data, ord); -} - -static void -cmd_invite(const tnode * tnext, void * data, struct order * ord) -{ - create_transaction(ALLIANCE_INVITE, (unit*)data, ord); -} - -static void -cmd_join(const tnode * tnext, void * data, struct order * ord) -{ - create_transaction(ALLIANCE_JOIN, (unit*)data, ord); -} - -static void -perform_kick(void) -{ - alliance_transaction ** tap = transactions+ALLIANCE_KICK; - while (*tap) { - alliance_transaction * ta = *tap; - alliance * al = f_get_alliance(ta->u->faction); - - if (al && alliance_get_leader(al)==ta->u->faction) { - faction * f; - init_tokens(ta->ord); - skip_token(); - skip_token(); - f = getfaction(); - if (f && f_get_alliance(f)==al) { - setalliance(f, NULL); - } - } - *tap = ta->next; - free(ta); - } -} - -static void -perform_new(void) -{ - alliance_transaction ** tap = transactions+ALLIANCE_NEW; - while (*tap) { - alliance_transaction * ta = *tap; - alliance * al; - int id; - faction * f = ta->u->faction; - - init_tokens(ta->ord); - skip_token(); - skip_token(); - id = getid(); - - al = makealliance(id, itoa36(id)); - setalliance(f, al); - - *tap = ta->next; - free(ta); - } -} - -static void -perform_leave(void) -{ - alliance_transaction ** tap = transactions+ALLIANCE_LEAVE; - while (*tap) { - alliance_transaction * ta = *tap; - faction * f = ta->u->faction; - - setalliance(f, NULL); - - *tap = ta->next; - free(ta); - } -} - -static void -perform_transfer(void) -{ - alliance_transaction ** tap = transactions+ALLIANCE_TRANSFER; - while (*tap) { - alliance_transaction * ta = *tap; - alliance * al = f_get_alliance(ta->u->faction); - - if (al && alliance_get_leader(al)==ta->u->faction) { - faction * f; - init_tokens(ta->ord); - skip_token(); - skip_token(); - f = getfaction(); - if (f && f_get_alliance(f)==al) { - al->_leader = f; - } - } - *tap = ta->next; - free(ta); - } -} - -static void -perform_join(void) -{ - alliance_transaction ** tap = transactions+ALLIANCE_JOIN; - while (*tap) { - alliance_transaction * ta = *tap; - faction * fj = ta->u->faction; - int aid; - - init_tokens(ta->ord); - skip_token(); - skip_token(); - aid = getid(); - if (aid) { - alliance * al = findalliance(aid); - if (al && f_get_alliance(fj)!=al) { - alliance_transaction ** tip = transactions+ALLIANCE_INVITE; - alliance_transaction * ti = *tip; - while (ti) { - faction * fi = ti->u->faction; - if (fi && f_get_alliance(fi)==al) { - int fid; - init_tokens(ti->ord); - skip_token(); - skip_token(); - fid = getid(); - if (fid==fj->no) { - break; - } - } - tip = &ti->next; - ti = *tip; - } - if (ti) { - setalliance(fj, al); - *tip = ti->next; - free(ti); - } else { - /* TODO: error message */ - } - } - } - *tap = ta->next; - free(ta); - } -} - -static void -execute(const struct syntaxtree * syntax, keyword_t kwd) -{ - int run = 0; - - region ** rp = ®ions; - while (*rp) { - region * r = *rp; - unit **up = &r->units; - while (*up) { - unit * u = *up; - if (u->number) { - const struct locale * lang = u->faction->locale; - tnode * root = stree_find(syntax, lang); - order * ord; - for (ord = u->orders; ord; ord = ord->next) { - if (get_keyword(ord) == kwd) { - do_command(root, u, ord); - run = 1; - } - } - } - if (u==*up) up = &u->next; - } - if (*rp==r) rp = &r->next; - } - - if (run) { - perform_kick(); - perform_leave(); - perform_transfer(); - perform_new(); - perform_join(); - } -} - -void -alliance_cmd(void) -{ - static syntaxtree * stree = NULL; - if (stree==NULL) { - syntaxtree * slang = stree = stree_create(); - while (slang) { - // struct tnode * root = calloc(sizeof(tnode), 1); - struct tnode * leaf = calloc(sizeof(tnode), 1); - // add_command(root, leaf, LOC(slang->lang, "alliance"), NULL); - add_command(leaf, NULL, LOC(slang->lang, "new"), &cmd_new); - add_command(leaf, NULL, LOC(slang->lang, "invite"), &cmd_invite); - add_command(leaf, NULL, LOC(slang->lang, "join"), &cmd_join); - add_command(leaf, NULL, LOC(slang->lang, "kick"), &cmd_kick); - add_command(leaf, NULL, LOC(slang->lang, "leave"), &cmd_leave); - add_command(leaf, NULL, LOC(slang->lang, "command"), &cmd_transfer); - slang->root = leaf; - slang = slang->next; - } - } - execute(stree, K_ALLIANCE); - /* some may have been kicked, must remove f->alliance==NULL */ -} - -void -alliancejoin(void) -{ - static syntaxtree * stree = NULL; - if (stree==NULL) { - syntaxtree * slang = stree = stree_create(); - while (slang) { - struct tnode * root = calloc(sizeof(tnode), 1); - struct tnode * leaf = calloc(sizeof(tnode), 1); - add_command(root, leaf, LOC(slang->lang, "alliance"), NULL); - add_command(leaf, NULL, LOC(slang->lang, "join"), &cmd_join); - slang = slang->next; - } - } - execute(stree, K_ALLIANCE); -} - -void -setalliance(struct faction * f, alliance * al) -{ - faction_list * flist = NULL; - if (f->alliance==al) return; - if (f->alliance!=NULL) { - faction_list ** flistp = &f->alliance->members; - while (*flistp) { - faction_list * flist = *flistp; - if ((*flistp)->data==f) { - *flistp = flist->next; - break; - } - flistp = &flist->next; - } - - if (f->alliance->_leader==f) { - if (f->alliance->members) { - f->alliance->_leader = f->alliance->members->data; - } else { - f->alliance->_leader = NULL; - } - } - } - f->alliance = al; - f->alliance_joindate = turn; - if (al!=NULL) { - faction_list ** flistp = &al->members; - while (*flistp) { - flistp = &(*flistp)->next; - } - if (flist==NULL) { - flist = malloc(sizeof(faction_list)); - flist->data = f; - } - *flistp = flist; - flist->next = NULL; - if (al->_leader==NULL) { - al->_leader = f; - } - flist = NULL; - } - free(flist); -} - -const char * -alliancename(const alliance * al) -{ - typedef char name[OBJECTIDSIZE + 1]; - static name idbuf[8]; - static int nextbuf = 0; - - char *ibuf = idbuf[(++nextbuf) % 8]; - - if (al && al->name) { - snprintf(ibuf, sizeof(name), "%s (%s)", al->name, itoa36(al->id)); - ibuf[sizeof(name)-1] = 0; - } else { - return NULL; - } - return ibuf; -} - -void -alliancevictory(void) -{ - const struct building_type * btype = bt_find("stronghold"); - region * r = regions; - alliance * al = alliances; - if (btype==NULL) return; - while (r!=NULL) { - building * b = r->buildings; - while (b!=NULL) { - if (b->type==btype) { - unit * u = building_owner(b); - if (u) { - fset(u->faction->alliance, FFL_MARK); - } - } - b = b->next; - } - r=r->next; - } - while (al!=NULL) { - if (!fval(al, FFL_MARK)) { - faction_list * flist = al->members; - while (flist!=0) { - faction * f = flist->data; - if (f->alliance==al) { - ADDMSG(&f->msgs, msg_message("alliance::lost", - "alliance", al)); - destroyfaction(f); - } - flist = flist->next; - } - } else { - freset(al, FFL_MARK); - } - al = al->next; - } -} - -int -victorycondition(const alliance * al, const char * name) -{ - const char * gems[] = { "opal", "diamond", "zaphire", "topaz", "beryl", "agate", "garnet", "emerald", NULL }; - if (strcmp(name, "gems")==0) { - const char ** igem = gems; - - for (;*igem;++igem) { - const struct item_type * itype = it_find(*igem); - faction_list * flist = al->members; - boolean found = false; - - assert(itype!=NULL); - for (;flist && !found;flist=flist->next) { - unit * u = flist->data->units; - - for (;u;u=u->nextF) { - if (i_get(u->items, itype)>0) { - found = true; - break; - } - } - } - if (!found) return 0; - } - return 1; - - } else if (strcmp(name, "phoenix")==0) { - faction_list * flist = al->members; - for (;flist;flist=flist->next) { - faction * f = flist->data; - if (find_key(f->attribs, atoi36("phnx"))) { - return 1; - } - } - return 0; - - } else if (strcmp(name, "pyramid")==0) { - - /* Logik: - * - if (pyr > last_passed_size && pyr > all_others) { - * pyr->passed->counter++; - * for(all_other_pyrs) { - * pyr->passed->counter=0; - * } - * - * if(pyr->passed->counter >= 3) { - * set(pyr, passed); - * pyr->owner->set_attrib(pyra); - * } - * last_passed_size = pyr->size; - * } - */ - - faction_list * flist = al->members; - for (;flist;flist=flist->next) { - faction * f = flist->data; - if (find_key(f->attribs, atoi36("pyra"))) { - return 1; - } - } - return 0; - } - return -1; -} - -void alliance_setname(alliance * self, const char * name) -{ - free(self->name); - if (name) self->name = strdup(name); - else self->name = NULL; -} +/* vi: set ts=2: ++-------------------+ Christian Schlittchen +| | Enno Rehling +| Eressea PBEM host | Katja Zedel +| (c) 1998 - 2003 | Henning Peters +| | Ingo Wilken ++-------------------+ Stefan Reich + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#pragma region includes + +#include +#include +#include "alliance.h" + +#include + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +#pragma endregion + +alliance * alliances = NULL; + +void +free_alliance(alliance * al) +{ + free(al->name); + while (al->members) { + faction_list * m = al->members; + al->members = m->next; + free(m); + } + free(al); +} + +alliance * +makealliance(int id, const char * name) +{ + alliance * al;; + + for (;;) { + if (id>0) { + for (al=alliances;al;al=al->next) { + if (al->id==id) { + id = 0; + break; + } + } + if (id>0) break; + } + id = id?id:(1 + (rng_int() % MAX_UNIT_NR)); + } + al = calloc(1, sizeof(alliance)); + al->id = id; + if (name) { + al->name = strdup(name); + } else { + al->flags |= ALF_NON_ALLIED; + } + al->next = alliances; + return alliances=al; +} + +alliance * +findalliance(int id) +{ + alliance * al; + for (al=alliances;al;al=al->next) { + if (al->id==id) return al; + } + return NULL; +} + +typedef struct alliance_transaction { + struct alliance_transaction * next; + unit * u; + order * ord; +// alliance * al; +// variant userdata; +} alliance_transaction; + +static struct alliance_transaction * transactions[ALLIANCE_MAX]; + + +faction * +alliance_get_leader(alliance * al) +{ + if (!al->_leader) { + if (al->members) { + al->_leader = al->members->data; + } + } + return al->_leader; +} + +static void +create_transaction(int type, unit * u, order * ord) +{ + alliance_transaction * tr = calloc(1, sizeof(alliance_transaction)); + tr->ord = ord; + tr->u = u; + tr->next = transactions[type]; + transactions[type] = tr; +} + +static void +cmd_kick(const tnode * tnext, void * data, struct order * ord) +{ + create_transaction(ALLIANCE_KICK, (unit*)data, ord); +} + +static void +cmd_leave(const tnode * tnext, void * data, struct order * ord) +{ + create_transaction(ALLIANCE_LEAVE, (unit*)data, ord); +} + +static void +cmd_transfer(const tnode * tnext, void * data, struct order * ord) +{ + create_transaction(ALLIANCE_TRANSFER, (unit*)data, ord); +} + +static void +cmd_new(const tnode * tnext, void * data, struct order * ord) +{ + create_transaction(ALLIANCE_NEW, (unit*)data, ord); +} + +static void +cmd_invite(const tnode * tnext, void * data, struct order * ord) +{ + create_transaction(ALLIANCE_INVITE, (unit*)data, ord); +} + +static void +cmd_join(const tnode * tnext, void * data, struct order * ord) +{ + create_transaction(ALLIANCE_JOIN, (unit*)data, ord); +} + +static void +perform_kick(void) +{ + alliance_transaction ** tap = transactions+ALLIANCE_KICK; + while (*tap) { + alliance_transaction * ta = *tap; + alliance * al = f_get_alliance(ta->u->faction); + + if (al && alliance_get_leader(al)==ta->u->faction) { + faction * f; + init_tokens(ta->ord); + skip_token(); + skip_token(); + f = getfaction(); + if (f && f_get_alliance(f)==al) { + setalliance(f, NULL); + } + } + *tap = ta->next; + free(ta); + } +} + +static void +perform_new(void) +{ + alliance_transaction ** tap = transactions+ALLIANCE_NEW; + while (*tap) { + alliance_transaction * ta = *tap; + alliance * al; + int id; + faction * f = ta->u->faction; + + init_tokens(ta->ord); + skip_token(); + skip_token(); + id = getid(); + + al = makealliance(id, itoa36(id)); + setalliance(f, al); + + *tap = ta->next; + free(ta); + } +} + +static void +perform_leave(void) +{ + alliance_transaction ** tap = transactions+ALLIANCE_LEAVE; + while (*tap) { + alliance_transaction * ta = *tap; + faction * f = ta->u->faction; + + setalliance(f, NULL); + + *tap = ta->next; + free(ta); + } +} + +static void +perform_transfer(void) +{ + alliance_transaction ** tap = transactions+ALLIANCE_TRANSFER; + while (*tap) { + alliance_transaction * ta = *tap; + alliance * al = f_get_alliance(ta->u->faction); + + if (al && alliance_get_leader(al)==ta->u->faction) { + faction * f; + init_tokens(ta->ord); + skip_token(); + skip_token(); + f = getfaction(); + if (f && f_get_alliance(f)==al) { + al->_leader = f; + } + } + *tap = ta->next; + free(ta); + } +} + +static void +perform_join(void) +{ + alliance_transaction ** tap = transactions+ALLIANCE_JOIN; + while (*tap) { + alliance_transaction * ta = *tap; + faction * fj = ta->u->faction; + int aid; + + init_tokens(ta->ord); + skip_token(); + skip_token(); + aid = getid(); + if (aid) { + alliance * al = findalliance(aid); + if (al && f_get_alliance(fj)!=al) { + alliance_transaction ** tip = transactions+ALLIANCE_INVITE; + alliance_transaction * ti = *tip; + while (ti) { + faction * fi = ti->u->faction; + if (fi && f_get_alliance(fi)==al) { + int fid; + init_tokens(ti->ord); + skip_token(); + skip_token(); + fid = getid(); + if (fid==fj->no) { + break; + } + } + tip = &ti->next; + ti = *tip; + } + if (ti) { + setalliance(fj, al); + *tip = ti->next; + free(ti); + } else { + /* TODO: error message */ + } + } + } + *tap = ta->next; + free(ta); + } +} + +static void +execute(const struct syntaxtree * syntax, keyword_t kwd) +{ + int run = 0; + + region ** rp = ®ions; + while (*rp) { + region * r = *rp; + unit **up = &r->units; + while (*up) { + unit * u = *up; + if (u->number) { + const struct locale * lang = u->faction->locale; + tnode * root = stree_find(syntax, lang); + order * ord; + for (ord = u->orders; ord; ord = ord->next) { + if (get_keyword(ord) == kwd) { + do_command(root, u, ord); + run = 1; + } + } + } + if (u==*up) up = &u->next; + } + if (*rp==r) rp = &r->next; + } + + if (run) { + perform_kick(); + perform_leave(); + perform_transfer(); + perform_new(); + perform_join(); + } +} + +void +alliance_cmd(void) +{ + static syntaxtree * stree = NULL; + if (stree==NULL) { + syntaxtree * slang = stree = stree_create(); + while (slang) { + // struct tnode * root = calloc(sizeof(tnode), 1); + struct tnode * leaf = calloc(sizeof(tnode), 1); + // add_command(root, leaf, LOC(slang->lang, "alliance"), NULL); + add_command(leaf, NULL, LOC(slang->lang, "new"), &cmd_new); + add_command(leaf, NULL, LOC(slang->lang, "invite"), &cmd_invite); + add_command(leaf, NULL, LOC(slang->lang, "join"), &cmd_join); + add_command(leaf, NULL, LOC(slang->lang, "kick"), &cmd_kick); + add_command(leaf, NULL, LOC(slang->lang, "leave"), &cmd_leave); + add_command(leaf, NULL, LOC(slang->lang, "command"), &cmd_transfer); + slang->root = leaf; + slang = slang->next; + } + } + execute(stree, K_ALLIANCE); + /* some may have been kicked, must remove f->alliance==NULL */ +} + +void +alliancejoin(void) +{ + static syntaxtree * stree = NULL; + if (stree==NULL) { + syntaxtree * slang = stree = stree_create(); + while (slang) { + struct tnode * root = calloc(sizeof(tnode), 1); + struct tnode * leaf = calloc(sizeof(tnode), 1); + add_command(root, leaf, LOC(slang->lang, "alliance"), NULL); + add_command(leaf, NULL, LOC(slang->lang, "join"), &cmd_join); + slang = slang->next; + } + } + execute(stree, K_ALLIANCE); +} + +void +setalliance(struct faction * f, alliance * al) +{ + faction_list * flist = NULL; + if (f->alliance==al) return; + if (f->alliance!=NULL) { + faction_list ** flistp = &f->alliance->members; + while (*flistp) { + faction_list * flist = *flistp; + if ((*flistp)->data==f) { + *flistp = flist->next; + break; + } + flistp = &flist->next; + } + + if (f->alliance->_leader==f) { + if (f->alliance->members) { + f->alliance->_leader = f->alliance->members->data; + } else { + f->alliance->_leader = NULL; + } + } + } + f->alliance = al; + f->alliance_joindate = turn; + if (al!=NULL) { + faction_list ** flistp = &al->members; + while (*flistp) { + flistp = &(*flistp)->next; + } + if (flist==NULL) { + flist = malloc(sizeof(faction_list)); + flist->data = f; + } + *flistp = flist; + flist->next = NULL; + if (al->_leader==NULL) { + al->_leader = f; + } + flist = NULL; + } + free(flist); +} + +const char * +alliancename(const alliance * al) +{ + typedef char name[OBJECTIDSIZE + 1]; + static name idbuf[8]; + static int nextbuf = 0; + + char *ibuf = idbuf[(++nextbuf) % 8]; + + if (al && al->name) { + snprintf(ibuf, sizeof(name), "%s (%s)", al->name, itoa36(al->id)); + ibuf[sizeof(name)-1] = 0; + } else { + return NULL; + } + return ibuf; +} + +void +alliancevictory(void) +{ + const struct building_type * btype = bt_find("stronghold"); + region * r = regions; + alliance * al = alliances; + if (btype==NULL) return; + while (r!=NULL) { + building * b = r->buildings; + while (b!=NULL) { + if (b->type==btype) { + unit * u = building_owner(b); + if (u) { + fset(u->faction->alliance, FFL_MARK); + } + } + b = b->next; + } + r=r->next; + } + while (al!=NULL) { + if (!fval(al, FFL_MARK)) { + faction_list * flist = al->members; + while (flist!=0) { + faction * f = flist->data; + if (f->alliance==al) { + ADDMSG(&f->msgs, msg_message("alliance::lost", + "alliance", al)); + destroyfaction(f); + } + flist = flist->next; + } + } else { + freset(al, FFL_MARK); + } + al = al->next; + } +} + +int +victorycondition(const alliance * al, const char * name) +{ + const char * gems[] = { "opal", "diamond", "zaphire", "topaz", "beryl", "agate", "garnet", "emerald", NULL }; + if (strcmp(name, "gems")==0) { + const char ** igem = gems; + + for (;*igem;++igem) { + const struct item_type * itype = it_find(*igem); + faction_list * flist = al->members; + boolean found = false; + + assert(itype!=NULL); + for (;flist && !found;flist=flist->next) { + unit * u = flist->data->units; + + for (;u;u=u->nextF) { + if (i_get(u->items, itype)>0) { + found = true; + break; + } + } + } + if (!found) return 0; + } + return 1; + + } else if (strcmp(name, "phoenix")==0) { + faction_list * flist = al->members; + for (;flist;flist=flist->next) { + faction * f = flist->data; + if (find_key(f->attribs, atoi36("phnx"))) { + return 1; + } + } + return 0; + + } else if (strcmp(name, "pyramid")==0) { + + /* Logik: + * - if (pyr > last_passed_size && pyr > all_others) { + * pyr->passed->counter++; + * for(all_other_pyrs) { + * pyr->passed->counter=0; + * } + * + * if(pyr->passed->counter >= 3) { + * set(pyr, passed); + * pyr->owner->set_attrib(pyra); + * } + * last_passed_size = pyr->size; + * } + */ + + faction_list * flist = al->members; + for (;flist;flist=flist->next) { + faction * f = flist->data; + if (find_key(f->attribs, atoi36("pyra"))) { + return 1; + } + } + return 0; + } + return -1; +} + +void alliance_setname(alliance * self, const char * name) +{ + free(self->name); + if (name) self->name = strdup(name); + else self->name = NULL; +} diff --git a/src/kernel/alliance.h b/src/kernel/alliance.h index e9cab8b66..7b77b6ea1 100644 --- a/src/kernel/alliance.h +++ b/src/kernel/alliance.h @@ -1,68 +1,68 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_ALLIANCE -#define H_KRNL_ALLIANCE -#ifdef __cplusplus -extern "C" { -#endif - -struct plane; -struct attrib; -struct unit; -struct faction; -struct region; -struct faction_list; - -enum { - ALLIANCE_KICK, - ALLIANCE_LEAVE, - ALLIANCE_TRANSFER, - ALLIANCE_NEW, - ALLIANCE_INVITE, - ALLIANCE_JOIN, - ALLIANCE_MAX -}; - -#define ALF_NON_ALLIED (1<<0) /* this alliance is just a default for a non-allied faction */ - -typedef struct alliance { - struct alliance * next; - struct faction * _leader; - struct faction_list * members; - unsigned int flags; - int id; - char * name; -} alliance; - -extern alliance * alliances; -extern alliance * findalliance(int id); -extern alliance * makealliance(int id, const char * name); -extern const char * alliancename(const struct alliance * al); -extern void setalliance(struct faction * f, alliance * al); -void free_alliance(struct alliance * al); -extern struct faction * alliance_get_leader(struct alliance * al); -extern void alliance_cmd(void); - -void alliance_setname(alliance * self, const char * name); -/* execute commands */ - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_ALLIANCE +#define H_KRNL_ALLIANCE +#ifdef __cplusplus +extern "C" { +#endif + +struct plane; +struct attrib; +struct unit; +struct faction; +struct region; +struct faction_list; + +enum { + ALLIANCE_KICK, + ALLIANCE_LEAVE, + ALLIANCE_TRANSFER, + ALLIANCE_NEW, + ALLIANCE_INVITE, + ALLIANCE_JOIN, + ALLIANCE_MAX +}; + +#define ALF_NON_ALLIED (1<<0) /* this alliance is just a default for a non-allied faction */ + +typedef struct alliance { + struct alliance * next; + struct faction * _leader; + struct faction_list * members; + unsigned int flags; + int id; + char * name; +} alliance; + +extern alliance * alliances; +extern alliance * findalliance(int id); +extern alliance * makealliance(int id, const char * name); +extern const char * alliancename(const struct alliance * al); +extern void setalliance(struct faction * f, alliance * al); +void free_alliance(struct alliance * al); +extern struct faction * alliance_get_leader(struct alliance * al); +extern void alliance_cmd(void); + +void alliance_setname(alliance * self, const char * name); +/* execute commands */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/battle.c b/src/kernel/battle.c index a4eadfcda..85fc85db8 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -1,4371 +1,4371 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#pragma region includes - -#include -#include -#include "battle.h" - -#include "alchemy.h" -#include "alliance.h" -#include "build.h" -#include "building.h" -#include "curse.h" -#include "equipment.h" -#include "faction.h" -#include "group.h" -#include "item.h" -#include "magic.h" -#include "message.h" -#include "move.h" -#include "names.h" -#include "order.h" -#include "plane.h" -#include "race.h" -#include "region.h" -#include "reports.h" -#include "ship.h" -#include "skill.h" -#include "terrain.h" -#include "unit.h" - -/* attributes includes */ -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include - -#pragma endregion - -static FILE *bdebug; - -#define TACTICS_BONUS 1 /* when undefined, we have a tactics round. else this is the bonus tactics give */ -#define TACTICS_MODIFIER 1 /* modifier for generals in the fromt/rear */ - -#define CATAPULT_INITIAL_RELOAD 4 /* erster schuss in runde 1 + rng_int() % INITIAL */ -#define CATAPULT_STRUCTURAL_DAMAGE - -#define BASE_CHANCE 70 /* 70% Basis-Überlebenschance */ -#ifdef NEW_COMBATSKILLS_RULE -#define TDIFF_CHANGE 5 /* 5% höher pro Stufe */ -#define DAMAGE_QUOTIENT 2 /* damage += skilldiff/DAMAGE_QUOTIENT */ -#else -#define TDIFF_CHANGE 10 -# define DAMAGE_QUOTIENT 1 /* damage += skilldiff/DAMAGE_QUOTIENT */ -#endif - -#undef DEBUG_FAST /* should be disabled when b->fast and b->rowcache works */ -#define DEBUG_SELECT /* should be disabled if select_enemy works */ - -typedef enum combatmagic { - DO_PRECOMBATSPELL, - DO_POSTCOMBATSPELL -} combatmagic_t; - -/* globals */ -static int obs_count = 0; - -#define MINSPELLRANGE 1 -#define MAXSPELLRANGE 7 - -#ifndef ROW_FACTOR -# define ROW_FACTOR 10 -#endif -static const double EFFECT_PANIC_SPELL = 0.25; -static const double TROLL_REGENERATION = 0.10; - -/* Nach dem alten System: */ -static int missile_range[2] = {FIGHT_ROW, BEHIND_ROW}; -static int melee_range[2] = {FIGHT_ROW, FIGHT_ROW}; -static message * msg_separator; - -const troop no_troop = {0, 0}; - -static int max_turns = 0; -static int damage_rules = 0; -static int loot_rules = 0; -static int skill_formula = 0; - -#define FORMULA_ORIG 0 -#define FORMULA_NEW 1 - -#define LOOT_MONSTERS (1<<0) -#define LOOT_SELF (1<<1) /* code is mutually exclusive with LOOT_OTHERS */ -#define LOOT_OTHERS (1<<2) -#define LOOT_KEEPLOOT (1<<4) - -#define DAMAGE_CRITICAL (1<<0) -#define DAMAGE_MELEE_BONUS (1<<1) -#define DAMAGE_MISSILE_BONUS (1<<2) -#define DAMAGE_UNARMED_BONUS (1<<3) -#define DAMAGE_SKILL_BONUS (1<<4) -/** initialize rules from configuration. - */ -static void -static_rules(void) -{ - loot_rules = get_param_int(global.parameters, "rules.combat.loot", LOOT_MONSTERS|LOOT_OTHERS|LOOT_KEEPLOOT); - /* new formula to calculate to-hit-chance */ - skill_formula = get_param_int(global.parameters, "rules.combat.skill_formula", FORMULA_ORIG); - /* maximum number of combat turns */ - max_turns = get_param_int(global.parameters, "rules.combat.turns", COMBAT_TURNS); - /* damage calculation */ - if (get_param_int(global.parameters, "rules.combat.critical", 1)) { - damage_rules |= DAMAGE_CRITICAL; - } - if (get_param_int(global.parameters, "rules.combat.melee_bonus", 1)) { - damage_rules |= DAMAGE_MELEE_BONUS; - } - if (get_param_int(global.parameters, "rules.combat.missile_bonus", 1)) { - damage_rules |= DAMAGE_MISSILE_BONUS; - } - if (get_param_int(global.parameters, "rules.combat.unarmed_bonus", 1)) { - damage_rules |= DAMAGE_UNARMED_BONUS; - } - if (get_param_int(global.parameters, "rules.combat.skill_bonus", 1)) { - damage_rules |= DAMAGE_SKILL_BONUS; - } -} - -static int -army_index(side * s) -{ - return s->index; -} - -#ifndef SIMPLE_ESCAPE -region * -fleeregion(const unit * u) -{ - region *r = u->region; - region *neighbours[MAXDIRECTIONS]; - int c = 0; - direction_t i; - - if (u->ship && !fval(r->terrain, SEA_REGION)) - return NULL; - - if (u->ship && - !(u->race->flags & RCF_SWIM) && - !(u->race->flags & RCF_FLY)) { - return NULL; - } - - for (i = 0; i != MAXDIRECTIONS; ++i) { - region * r2 = rconnect(r, i); - if (r2) { - if (can_survive(u,r2) && !move_blocked(u, r, r2)) - neighbours[c++] = r2; - } - } - - if (!c) - return NULL; - return neighbours[rng_int() % c]; -} -#endif /* SIMPLE_ESCAPE */ - -static char * -sidename(side * s) -{ -#define SIDENAMEBUFLEN 256 - static int bufno; /* STATIC_XCALL: used across calls */ - static char sidename_buf[4][SIDENAMEBUFLEN]; /* STATIC_RESULT: used for return, not across calls */ - - bufno = bufno % 4; - if (s->stealthfaction) { - snprintf(sidename_buf[bufno], SIDENAMEBUFLEN, - "%s", factionname(s->stealthfaction)); - } else { - snprintf(sidename_buf[bufno], SIDENAMEBUFLEN, - "%s", factionname(s->faction)); - } - return sidename_buf[bufno++]; -} - -static const char * -sideabkz(side *s, boolean truename) -{ - static char sideabkz_buf[8]; /* STATIC_RESULT: used for return, not across calls */ - const faction * f = (s->stealthfaction && !truename)?s->stealthfaction:s->faction; - -#undef SIDE_ABKZ -#ifdef SIDE_ABKZ - abkz(f->name, sideabkz_buf, sizeof(sideabkz_buf), 3); -#else - strcpy(sideabkz_buf, itoa36(f->no)); -#endif - return sideabkz_buf; -} - -static void -message_faction(battle * b, faction * f, struct message * m) -{ - region * r = b->region; - - if (f->battles==NULL || f->battles->r!=r) { - struct bmsg * bm = calloc(1, sizeof(struct bmsg)); - bm->next = f->battles; - f->battles = bm; - bm->r = r; - } - add_message(&f->battles->msgs, m); -} - -int -armedmen(const unit * u, boolean siege_weapons) -{ - item * itm; - int n = 0; - if (!(urace(u)->flags & RCF_NOWEAPONS)) { - if (effskill(u, SK_WEAPONLESS)>=1) { - /* kann ohne waffen bewachen: fuer drachen */ - n = u->number; - } else { - /* alle Waffen werden gezaehlt, und dann wird auf die Anzahl - * Personen minimiert */ - for (itm=u->items;itm;itm=itm->next) { - const weapon_type * wtype = resource2weapon(itm->type->rtype); - if (wtype==NULL || (!siege_weapons && (wtype->flags & WTF_SIEGE))) continue; - if (effskill(u, wtype->skill) >= 1) n += itm->number; - /* if (effskill(u, wtype->skill) >= wtype->minskill) n += itm->number; */ - if (n>u->number) break; - } - n = MIN(n, u->number); - } - } - return n; -} - -void -message_all(battle * b, message * m) -{ - bfaction * bf; - plane * p = rplane(b->region); - watcher * w; - - for (bf = b->factions;bf;bf=bf->next) { - message_faction(b, bf->faction, m); - } - if (p) for (w=p->watchers;w;w=w->next) { - for (bf = b->factions;bf;bf=bf->next) if (bf->faction==w->faction) break; - if (bf==NULL) message_faction(b, w->faction, m); - } -} - -static void -fbattlerecord(battle * b, faction * f, const char *s) -{ - message * m = msg_message("battle_msg", "string", s); - message_faction(b, f, m); - msg_release(m); -} - -/* being an enemy or a friend is (and must always be!) symmetrical */ -#define enemy_i(as, di) (as->relations[di]&E_ENEMY) -#define friendly_i(as, di) (as->relations[di]&E_FRIEND) -#define enemy(as, ds) (as->relations[ds->index]&E_ENEMY) -#define friendly(as, ds) (as->relations[ds->index]&E_FRIEND) - -static boolean -set_enemy(side * as, side * ds, boolean attacking) -{ - int i; - for (i=0;i!=MAXSIDES;++i) { - if (ds->enemies[i]==NULL) ds->enemies[i]=as; - if (ds->enemies[i]==as) break; - } - for (i=0;i!=MAXSIDES;++i) { - if (as->enemies[i]==NULL) as->enemies[i]=ds; - if (as->enemies[i]==ds) break; - } - assert(i!=MAXSIDES); - if (attacking) as->relations[ds->index] |= E_ATTACKING; - if ((ds->relations[as->index] & E_ENEMY)==0) { - /* enemy-relation are always symmetrical */ - assert((as->relations[ds->index] & (E_ENEMY|E_FRIEND))==0); - ds->relations[as->index] |= E_ENEMY; - as->relations[ds->index] |= E_ENEMY; - return true; - } - return false; -} - -static void -set_friendly(side * as, side * ds) -{ - assert((as->relations[ds->index] & E_ENEMY)==0); - ds->relations[as->index] |= E_FRIEND; - as->relations[ds->index] |= E_FRIEND; -} - -static int -allysfm(const side * s, const faction * f, int mode) -{ - if (s->faction==f) return mode; - if (s->group) { - return alliedgroup(s->battle->plane, s->faction, f, s->group->allies, mode); - } - return alliedfaction(s->battle->plane, s->faction, f, mode); -} - -static int -allysf(const side * s, const faction * f) -{ - return allysfm(s, f, HELP_FIGHT); -} - -static int -dead_fighters(const fighter * df) -{ - return df->unit->number - df->alive - df->run.number; -} - -fighter * -select_corpse(battle * b, fighter * af) -/* Wählt eine Leiche aus, der af hilft. casualties ist die Anzahl der - * Toten auf allen Seiten (im Array). Wenn af == NULL, wird die - * Parteizugehörigkeit ignoriert, und irgendeine Leiche genommen. - * - * Untote werden nicht ausgewählt (casualties, not dead) */ -{ - int si, di, maxcasualties = 0; - fighter *df; - side *s; - - for (si=0;si!=b->nsides;++si) { - side * s = b->sides+si; - if (af==NULL || (!enemy_i(af->side, si) && allysf(af->side, s->faction))) { - maxcasualties += s->casualties; - } - } - di = rng_int() % maxcasualties; - for (s=b->sides;s!=b->sides+b->nsides;++s) { - for (df=s->fighters;df;df=df->next) { - /* Geflohene haben auch 0 hp, dürfen hier aber nicht ausgewählt - * werden! */ - int dead = dead_fighters(df); - if (!playerrace(df->unit->race)) continue; - - if (af && !helping(af->side, df->side)) - continue; - if (di < dead) { - return df; - } - di -= dead; - } - } - - return NULL; -} - -boolean -helping(const side * as, const side * ds) -{ - if (as->faction==ds->faction) return true; - return (boolean)(!enemy(as, ds) && allysf(as, ds->faction)); -} - -int -statusrow(int status) -{ - switch (status) { - case ST_AGGRO: - case ST_FIGHT: - return FIGHT_ROW; - case ST_BEHIND: - case ST_CHICKEN: - return BEHIND_ROW; - case ST_AVOID: - return AVOID_ROW; - case ST_FLEE: - return FLEE_ROW; - default: - assert(!"unknown combatrow"); - } - return FIGHT_ROW; -} - -static double -hpflee(int status) - /* if hp drop below this percentage, run away */ -{ - switch (status) { - case ST_AGGRO: - return 0.0; - case ST_FIGHT: - case ST_BEHIND: - return 0.2; - case ST_CHICKEN: - case ST_AVOID: - return 0.9; - case ST_FLEE: - return 1.0; - default: - assert(!"unknown combatrow"); - } - return 0.0; -} - -static int -get_row(const side * s, int row, const side * vs) -{ - boolean counted[MAXSIDES]; - int enemyfront = 0; - int line, result; - int retreat = 0; - int size[NUMROWS]; - int front = 0; - battle * b = s->battle; - - memset(counted, 0, sizeof(counted)); - memset(size, 0, sizeof(size)); - for (line=FIRST_ROW;line!=NUMROWS;++line) { - int si, sa_i; - /* how many enemies are there in the first row? */ - for (si=0;s->enemies[si];++si) { - side *se = s->enemies[si]; - if (se->size[line]>0) { - enemyfront += se->size[line]; - /* - s->nonblockers[line] (nicht, weil angreifer) */ - } - } - for (sa_i=0; sa_i!=b->nsides; ++sa_i) { - side * sa = b->sides+sa_i; - /* count people that like me, but don't like my enemy */ - if (friendly_i(s, sa_i) && enemy_i(vs, sa_i)) { - if (!counted[sa_i]) { - int i; - - for (i=0;i!=NUMROWS;++i) { - size[i] += sa->size[i] - sa->nonblockers[i]; - } - counted[sa_i] = true; - } - } - } - if (enemyfront) break; - } - if (enemyfront) { - for (line=FIRST_ROW;line!=NUMROWS;++line) { - front += size[line]; - if (!front || frontstatus); - if (vs==NULL) { - int i; - for (i=FIGHT_ROW;i!=row;++i) if (af->side->size[i]) break; - return FIGHT_ROW+(row-i); - } else { -#ifdef FASTROW - battle * b = vs->battle; - if (row!=b->rowcache.row || b->alive!=b->rowcache.alive || af->side!=b->rowcache.as || vs!=b->rowcache.vs) { - b->rowcache.alive = b->alive; - b->rowcache.as = af->side; - b->rowcache.vs = vs; - b->rowcache.row = row; - b->rowcache.result = get_row(af->side, row, vs); - return b->rowcache.result; - } -#ifdef DEBUG_FAST /* validation code */ - { - int i = get_row(af->side, row, vs); - assert(i==b->rowcache.result); - } -#endif - return b->rowcache.result; -#else - return get_row(af->side, row, vs); -#endif - } -} - -static void -reportcasualties(battle * b, fighter * fig, int dead) -{ - struct message * m; - region * r = NULL; - if (fig->alive == fig->unit->number) return; -#ifndef SIMPLE_ESCAPE - if (fig->run.region == NULL) { - fig->run.region = fleeregion(fig->unit); - if (fig->run.region == NULL) fig->run.region = b->region; - } - r = fig->run.region; -#endif /* SIMPLE_ESCAPE */ - m = msg_message("casualties", "unit runto run alive fallen", - fig->unit, r, fig->run.number, fig->alive, dead); - message_all(b, m); - msg_release(m); -} - -static int -contest_classic(int skilldiff, const armor_type * ar, const armor_type * sh) -{ - int p, vw = BASE_CHANCE - TDIFF_CHANGE * skilldiff; - double mod = 1.0; - - if (ar != NULL) - mod *= (1 + ar->penalty); - if (sh != NULL) - mod *= (1 + sh->penalty); - vw = (int)(100 - ((100 - vw) * mod)); - - do { - p = rng_int() % 100; - vw -= p; - } - while (vw >= 0 && p >= 90); - return (vw <= 0); -} - -/** new rule for Eressea 1.5 - * \param skilldiff - the attack skill with every modifier applied - */ -static int -contest_new(int skilldiff, const troop dt, const armor_type * ar, const armor_type * sh) -{ - double tohit = 0.5 + skilldiff * 0.1; - if (tohit<0.5) tohit = 0.5; - if (chance(tohit)) { - int defense = effskill(dt.fighter->unit, SK_STAMINA); - double tosave = defense * 0.05; - return !chance(tosave); - } - return 0; -} - -static int -contest(int skdiff, const troop dt, const armor_type * ar, const armor_type * sh) -{ - if (skill_formula==FORMULA_ORIG) { - return contest_classic(skdiff, ar, sh); - } else { - return contest_new(skdiff, dt, ar, sh); - } -} - -static boolean -is_riding(const troop t) { - if (t.fighter->building!=NULL) return false; - if (t.fighter->horses + t.fighter->elvenhorses > t.index) return true; - return false; -} - -static weapon * -preferred_weapon(const troop t, boolean attacking) -{ - weapon * missile = t.fighter->person[t.index].missile; - weapon * melee = t.fighter->person[t.index].melee; - if (attacking) { - if (melee==NULL || (missile && missile->attackskill>melee->attackskill)) { - return missile; - } - } else { - if (melee==NULL || (missile && missile->defenseskill>melee->defenseskill)) { - return missile; - } - } - return melee; -} - -static weapon * -select_weapon(const troop t, boolean attacking, boolean ismissile) - /* select the primary weapon for this trooper */ -{ - if (attacking) { - if (ismissile) { - /* from the back rows, have to use your missile weapon */ - return t.fighter->person[t.index].missile; - } - } else { - if (!ismissile) { - /* have to use your melee weapon if it's melee */ - return t.fighter->person[t.index].melee; - } - } - return preferred_weapon(t, attacking); -} - -static boolean -i_canuse(const unit * u, const item_type * itype) -{ - if (itype->canuse) { - return itype->canuse(u, itype); - } - return true; -} - -static int -weapon_skill(const weapon_type * wtype, const unit * u, boolean attacking) - /* the 'pure' skill when using this weapon to attack or defend. - * only undiscriminate modifiers (not affected by troops or enemies) - * are taken into account, e.g. no horses, magic, etc. */ -{ - int skill; - - if (wtype==NULL) { - skill = effskill(u, SK_WEAPONLESS); - if (skill<=0) { - /* wenn kein waffenloser kampf, dann den rassen-defaultwert */ - if (u->race == new_race[RC_ORC]) { - int sword = effskill(u, SK_MELEE); - int spear = effskill(u, SK_SPEAR); - skill = MAX(sword, spear) - 3; - if (attacking) { - skill = MAX(skill, u->race->at_default); - } else { - skill = MAX(skill, u->race->df_default); - } - } else { - if (attacking) { - skill = u->race->at_default; - } else { - skill = u->race->df_default; - } - } - } else { - /* der rassen-defaultwert kann höher sein als der Talentwert von - * waffenloser kampf */ - if (attacking) { - if (skill < u->race->at_default) skill = u->race->at_default; - } else { - if (skill < u->race->df_default) skill = u->race->df_default; - } - } - if (attacking) { - skill += u->race->at_bonus; - if (fval(u->region->terrain, SEA_REGION) && u->ship) skill += u->ship->type->at_bonus; - } else { - skill += u->race->df_bonus; - if (fval(u->region->terrain, SEA_REGION) && u->ship) skill += u->ship->type->df_bonus; - } - } else { - /* changed: if we own a weapon, we have at least a skill of 0 */ - if (!i_canuse(u, wtype->itype)) return -1; - skill = effskill(u, wtype->skill); - if (skill < wtype->minskill) skill = 0; - if (skill > 0) { - if (attacking) { - skill += u->race->at_bonus; - } else { - skill += u->race->df_bonus; - } - } - if (attacking) { - skill += wtype->offmod; - } else { - skill += wtype->defmod; - } - } - - return skill; -} - -static int CavalrySkill(void) -{ - static int skill = -1; - - if (skill<0) { - skill = get_param_int(global.parameters, "rules.cavalry.skill", 2); - } - return skill; -} - -#define BONUS_SKILL 1 -#define BONUS_DAMAGE 2 -static int -CavalryBonus(const unit * u, troop enemy, int type) -{ - static int mode = -1; - - if (mode<0) { - mode = get_param_int(global.parameters, "rules.cavalry.mode", 1); - } - if (mode==0) { - /* old rule, Eressea 1.0 compat */ - return (type==BONUS_SKILL)?2:0; - } else { - /* new rule, chargers in Eressea 1.1 */ - int skl = effskill(u, SK_RIDING); - /* only half against trolls */ - if (skl>0) { - if (type==BONUS_DAMAGE) { - int dmg = MIN(skl, 8); - if (enemy.fighter->unit->race==new_race[RC_TROLL]) { - dmg = dmg/4; - } else { - dmg = dmg/2; - } - return dmg; - } else { - skl = skl/2; - return MIN(skl, 4); - } - } - } - return 0; -} - -static int -weapon_effskill(troop t, troop enemy, const weapon * w, boolean attacking, boolean missile) - /* effektiver Waffenskill während des Kampfes */ -{ - /* In dieser Runde alle die Modifier berechnen, die fig durch die - * Waffen bekommt. */ - fighter * tf = t.fighter; - unit * tu = t.fighter->unit; - int skill; - const weapon_type * wtype = w?w->type:NULL; - - if (wtype==NULL) { - /* Ohne Waffe: Waffenlose Angriffe */ - skill = weapon_skill(NULL, tu, attacking); - } else { - if (attacking) { - skill = w->attackskill; - } else { - skill = w->defenseskill; - } - if (wtype->modifiers!=NULL) { - /* Pferdebonus, Lanzenbonus, usw. */ - int m; - unsigned int flags = WMF_SKILL|(attacking?WMF_OFFENSIVE:WMF_DEFENSIVE); - - if (is_riding(t)) flags |= WMF_RIDING; - else flags |= WMF_WALKING; - if (is_riding(enemy)) flags |= WMF_AGAINST_RIDING; - else flags |= WMF_AGAINST_WALKING; - - for (m=0;wtype->modifiers[m].value;++m) { - if ((wtype->modifiers[m].flags & flags) == flags) { - race_list * rlist = wtype->modifiers[m].races; - if (rlist!=NULL) { - while (rlist) { - if (rlist->data == tu->race) break; - rlist = rlist->next; - } - if (rlist==NULL) continue; - } - skill += wtype->modifiers[m].value; - } - } - } - } - - /* Burgenbonus, Pferdebonus */ - if (is_riding(t) && (wtype==NULL || (fval(wtype, WTF_HORSEBONUS) && !fval(wtype, WTF_MISSILE)))) { - skill += CavalryBonus(tu, enemy, BONUS_SKILL); - if (wtype) skill = skillmod(urace(tu)->attribs, tu, tu->region, wtype->skill, skill, SMF_RIDING); - } - - if (t.indexelvenhorses) { - /* Elfenpferde: Helfen dem Reiter, egal ob und welche Waffe. Das ist - * eleganter, und vor allem einfacher, sonst muß man noch ein - * WMF_ELVENHORSE einbauen. */ - skill += 2; - } - - if (skill>0 && !attacking && missile) { - /* - * Wenn ich verteidige, und nicht direkt meinem Feind gegenüberstehe, - * halbiert sich mein Skill: (z.B. gegen Fernkämpfer. Nahkämpfer - * können mich eh nicht treffen) - */ - skill /= 2; - } - return skill; -} - -static const armor_type * -select_armor(troop t, boolean shield) -{ - unsigned int type = shield?ATF_SHIELD:0; - unit * u = t.fighter->unit; - const armor * a = t.fighter->armors; - int geschuetzt = 0; - - /* some monsters should not use armor (dragons in chainmail? ha!) */ - if (!(u->race->battle_flags & BF_EQUIPMENT)) - return NULL; - - /* ... neither do werewolves */ - if (fval(u, UFL_WERE)) { - return NULL; - } - - for (;a;a=a->next) { - if ((a->atype->flags & ATF_SHIELD)==type) { - geschuetzt += a->count; - if (geschuetzt > t.index) { - /* unser Kandidat wird geschuetzt */ - return a->atype; - } - } - } - return NULL; -} - - -/* Hier ist zu beachten, ob und wie sich Zauber und Artefakte, die - * Rüstungschutz geben, addieren. - * - Artefakt I_TROLLBELT gibt Rüstung +1 - * - Zauber Rindenhaut gibt Rüstung +3 - */ -int -select_magicarmor(troop t) -{ - unit *u = t.fighter->unit; - int geschuetzt = 0; - int ma = 0; - - geschuetzt = MIN(get_item(u, I_TROLLBELT), u->number); - - if (geschuetzt > t.index) /* unser Kandidat wird geschuetzt */ - ma += 1; - - return ma; -} - -/* Sind side ds und Magier des meffect verbündet, dann return 1*/ -boolean -meffect_protection(battle * b, meffect * s, side * ds) -{ - if (!s->magician->alive) return false; - if (s->duration <= 0) return false; - if (enemy(s->magician->side, ds)) return false; - if (allysf(s->magician->side, ds->faction)) return true; - return false; -} - -/* Sind side as und Magier des meffect verfeindet, dann return 1*/ -boolean -meffect_blocked(battle *b, meffect *s, side *as) -{ - if (!s->magician->alive) return false; - if (s->duration <= 0) return false; - if (enemy(s->magician->side, as)) return true; - return false; -} - -/* rmfighter wird schon im PRAECOMBAT gebraucht, da gibt es noch keine - * troops */ -void -rmfighter(fighter *df, int i) -{ - side *ds = df->side; - - /* nicht mehr personen abziehen, als in der Einheit am Leben sind */ - assert(df->alive >= i); - assert(df->alive <= df->unit->number); - - /* erst ziehen wir die Anzahl der Personen von den Kämpfern in der - * Schlacht, dann von denen auf dieser Seite ab*/ - df->side->alive -= i; - df->side->battle->alive -= i; - - /* Dann die Kampfreihen aktualisieren */ - ds->size[SUM_ROW] -= i; - ds->size[statusrow(df->status)] -= i; - - /* Spezialwirkungen, z.B. Schattenritter */ - if (df->unit->race->battle_flags & BF_NOBLOCK) { - ds->nonblockers[SUM_ROW] -= i; - ds->nonblockers[statusrow(df->status)] -= i; - } - - /* und die Einheit selbst aktualisieren */ - df->alive -= i; -} - - -static void -rmtroop(troop dt) -{ - fighter *df = dt.fighter; - - /* troop ist immer eine einzele Person */ - rmfighter(df, 1); - - assert(dt.index >= 0 && dt.index < df->unit->number); - df->person[dt.index] = df->person[df->alive - df->removed]; - if (df->removed) { - df->person[df->alive - df->removed] = df->person[df->alive]; - } - df->person[df->alive].hp = 0; -} - -void -remove_troop(troop dt) -{ - fighter * df = dt.fighter; - struct person p = df->person[dt.index]; - battle * b = df->side->battle; -#ifdef FASTCOUNT - b->fast.alive = -1; /* invalidate cached value */ -#endif -#ifdef FASTROW - b->rowcache.alive = -1; /* invalidate cached value */ -#endif - ++df->removed; - ++df->side->removed; - df->person[dt.index] = df->person[df->alive-df->removed]; - df->person[df->alive - df->removed] = p; -} - -void -kill_troop(troop dt) -{ - fighter * df = dt.fighter; - unit * du = df->unit; - - rmtroop(dt); - if (!df->alive) { - char eqname[64]; - const struct equipment * eq; - if (du->race->itemdrop) { - item * drops = du->race->itemdrop(du->race, du->number-df->run.number); - - if (drops != NULL){ - i_merge(&du->items, &drops); - } - } - sprintf(eqname, "%s_spoils", du->race->_name[0]); - eq = get_equipment(eqname); - if (eq!=NULL) { - equip_items(&du->items, eq); - } - } -} - -/** reduces the target's exp by an equivalent of n points learning - * 30 points = 1 week - */ -void -drain_exp(struct unit *u, int n) -{ - skill_t sk = (skill_t)(rng_int() % MAXSKILLS); - skill_t ssk; - - ssk = sk; - - while (get_level(u, sk)==0) { - sk++; - if (sk == MAXSKILLS) - sk = 0; - if (sk == ssk) { - sk = NOSKILL; - break; - } - } - if (sk != NOSKILL) { - skill * sv = get_skill(u, sk); - while (n>0) { - if (n>=30*u->number) { - reduce_skill(u, sv, 1); - n-=30; - } else { - if (rng_int()%(30*u->number) 0.75) { - return "eine klaffende Wunde"; - } else if (q > 0.5) { - return "eine schwere Wunde"; - } else if (q > 0.25) { - return "eine Wunde"; - } - return "eine kleine Wunde"; -} - -static void vampirism(troop at, int damage) -{ - static int vampire = -1; - if (vampire<0) vampire = get_param_int(global.parameters, "rules.combat.demon_vampire", 0); - if (vampire>0) { - int gain = damage/vampire; - int chance = damage - vampire * gain; - if (chance>0 && (rng_int() % vampire < chance)) ++gain; - if (gain>0) { - int maxhp = unit_max_hp(at.fighter->unit); - at.fighter->person[at.index].hp = MIN(gain+at.fighter->person[at.index].hp, maxhp); - } - } -} - -static int -natural_armor(unit * du) -{ - static int * bonus = 0; - int an = du->race->armor; - if (bonus==0) { - bonus = calloc(sizeof(int), num_races); - } - if (bonus[du->race->index]==0) { - bonus[du->race->index] = get_param_int(du->race->parameters, "armor.stamina", -1); - if (bonus[du->race->index]==0) bonus[du->race->index] = -1; - } - if (bonus[du->race->index]>0) { - int sk = effskill(du, SK_STAMINA); - sk /= bonus[du->race->index]; - an += sk; - } - return an; -} - -boolean -terminate(troop dt, troop at, int type, const char *damage, boolean missile) -{ - item ** pitm; - fighter *df = dt.fighter; - fighter *af = at.fighter; - unit *au = af->unit; - unit *du = df->unit; - battle *b = df->side->battle; - int heiltrank = 0; - static int rule_armor = -1; - - /* Schild */ - void **si; - side *ds = df->side; - int hp; - - int ar = 0, an, am; - const armor_type * armor = select_armor(dt, true); - const armor_type * shield = select_armor(dt, false); - - const weapon_type *dwtype = NULL; - const weapon_type *awtype = NULL; - const weapon * weapon; - - int rda, sk = 0, sd; - boolean magic = false; - int da = dice_rand(damage); - - assert(du->number>0); -#ifdef SHOW_KILLS - ++at.fighter->hits; -#endif - - switch (type) { - case AT_STANDARD: - weapon = select_weapon(at, true, missile); - sk = weapon_effskill(at, dt, weapon, true, missile); - if (weapon) awtype = weapon->type; - if (awtype && fval(awtype, WTF_MAGICAL)) magic = true; - break; - case AT_NATURAL: - sk = weapon_effskill(at, dt, NULL, true, missile); - break; - case AT_SPELL: - case AT_COMBATSPELL: - magic = true; - break; - default: - break; - } - weapon = select_weapon(dt, false, true); /* missile=true to get the unmodified best weapon she has */ - sd = weapon_effskill(dt, at, weapon, false, false); - if (weapon!=NULL) dwtype=weapon->type; - - if (is_riding(at) && (awtype==NULL || (fval(awtype, WTF_HORSEBONUS) && !fval(awtype, WTF_MISSILE)))) { - da += CavalryBonus(au, dt, BONUS_DAMAGE); - } - - if (armor) { - ar += armor->prot; - if (armor->projectile>0 && chance(armor->projectile)) { - return false; - } - } - if (shield) { - ar += shield->prot; - if (shield->projectile>0 && chance(shield->projectile)) { - return false; - } - } - - /* natürliche Rüstung */ - an = natural_armor(du); - - /* magische Rüstung durch Artefakte oder Sprüche */ - /* Momentan nur Trollgürtel und Werwolf-Eigenschaft */ - am = select_magicarmor(dt); - -#if CHANGED_CROSSBOWS - if (awtype && fval(awtype, WTF_ARMORPIERCING)) { - /* crossbows */ - ar /= 2; - an /= 2; - } -#endif - - if (rule_armor<0) { - rule_armor = get_param_int(global.parameters, "rules.combat.nat_armor", 0); - } - if (rule_armor==0) { - /* natürliche Rüstung ist halbkumulativ */ - if (ar>0) { - ar += an/2; - } else { - ar = an; - } - } else { - /* use the higher value, add half the other value */ - ar = (ar>an)?(ar+an/2):(an+ar/2); - } - ar += am; - - if (type!=AT_COMBATSPELL && type!=AT_SPELL) { - if (damage_rules&DAMAGE_CRITICAL) { - double kritchance = (sk * 3 - sd) / 200.0; - - kritchance = MAX(kritchance, 0.005); - kritchance = MIN(0.9, kritchance); - - while (chance(kritchance)) { - if (bdebug) { - fprintf(bdebug, "%s/%d lands a critical hit\n", unitid(au), at.index); - } - da += dice_rand(damage); - } - } - - da += rc_specialdamage(au->race, du->race, awtype); - - if (awtype!=NULL && fval(awtype, WTF_MISSILE)) { - /* missile weapon bonus */ - if (damage_rules&DAMAGE_MISSILE_BONUS) { - da += af->person[at.index].damage_rear; - } - } else if (awtype==NULL) { - /* skill bonus for unarmed combat */ - if (damage_rules&DAMAGE_UNARMED_BONUS) { - da += effskill(au, SK_WEAPONLESS); - } - } else { - /* melee bonus */ - if (damage_rules&DAMAGE_MELEE_BONUS) { - da += af->person[at.index].damage; - } - } - - /* Skilldifferenzbonus */ - if (damage_rules&DAMAGE_SKILL_BONUS) { - da += MAX(0, (sk-sd)/DAMAGE_QUOTIENT); - } - } - - - if (magic) { - /* Magischer Schaden durch Spruch oder magische Waffe */ - double res = 1.0; - - /* magic_resistance gib x% Resistenzbonus zurück */ - res -= magic_resistance(du)*3.0; - - if (du->race->battle_flags & BF_EQUIPMENT) { -#ifdef TODO_RUNESWORD - /* Runenschwert gibt im Kampf 80% Resistenzbonus */ - if (dwp == WP_RUNESWORD) res -= 0.80; -#endif - /* der Effekt von Laen steigt nicht linear */ - if (armor && fval(armor, ATF_LAEN)) res *= (1-armor->magres); - if (shield && fval(shield, ATF_LAEN)) res *= (1-shield->magres); - if (dwtype) res *= (1-dwtype->magres); - } - - if (res > 0) { - da = (int) (MAX(da * res, 0)); - } - /* gegen Magie wirkt nur natürliche und magische Rüstung */ - ar = an+am; - } - - rda = MAX(da - ar,0); - - if ((du->race->battle_flags & BF_INV_NONMAGIC) && !magic) rda = 0; - else { - unsigned int i = 0; - if (du->race->battle_flags & BF_RES_PIERCE) i |= WTF_PIERCE; - if (du->race->battle_flags & BF_RES_CUT) i |= WTF_CUT; - if (du->race->battle_flags & BF_RES_BASH) i |= WTF_BLUNT; - - if (i && awtype && fval(awtype, i)) rda /= 2; - - /* Schilde */ - for (si = b->meffects.begin; si != b->meffects.end; ++si) { - meffect *meffect = *si; - if (meffect_protection(b, meffect, ds) != 0) { - assert(0 <= rda); /* rda sollte hier immer mindestens 0 sein */ - /* jeder Schaden wird um effect% reduziert bis der Schild duration - * Trefferpunkte aufgefangen hat */ - if (meffect->typ == SHIELD_REDUCE) { - hp = rda * (meffect->effect/100); - rda -= hp; - meffect->duration -= hp; - } - /* gibt Rüstung +effect für duration Treffer */ - if (meffect->typ == SHIELD_ARMOR) { - rda = MAX(rda - meffect->effect, 0); - meffect->duration--; - } - } - } - } - - assert(dt.indexnumber); - df->person[dt.index].hp -= rda; - if (au->race==new_race[RC_DAEMON]) { - vampirism(at, rda); - } - - if (df->person[dt.index].hp > 0) { /* Hat überlebt */ - if (bdebug) { - fprintf(bdebug, "Damage %d, armor %d: %d -> %d HP\n", - da, ar, df->person[dt.index].hp + rda, df->person[dt.index].hp); - } - if (au->race == new_race[RC_DAEMON]) { -#ifdef TODO_RUNESWORD - if (select_weapon(dt, 0, -1) == WP_RUNESWORD) continue; -#endif - if (!(df->person[dt.index].flags & (FL_COURAGE|FL_DAZZLED))) { - df->person[dt.index].flags |= FL_DAZZLED; - df->person[dt.index].defence--; - } - } - df->person[dt.index].flags = (df->person[dt.index].flags & ~FL_SLEEPING); - return false; - } - - /* Sieben Leben */ - if (du->race == new_race[RC_CAT] && (chance(1.0 / 7))) { - assert(dt.index>=0 && dt.indexnumber); - df->person[dt.index].hp = unit_max_hp(du); - return false; - } - - /* Heiltrank schluerfen und hoffen */ - if (oldpotiontype[P_HEAL]) { - if (get_effect(du, oldpotiontype[P_HEAL]) > 0) { - change_effect(du, oldpotiontype[P_HEAL], -1); - heiltrank = 1; - } else if (i_get(du->items, oldpotiontype[P_HEAL]->itype) > 0) { - i_change(&du->items, oldpotiontype[P_HEAL]->itype, -1); - change_effect(du, oldpotiontype[P_HEAL], 3); - heiltrank = 1; - } - if (heiltrank && (chance(0.50))) { - { - message * m = msg_message("battle::potionsave", "unit", du); - message_faction(b, du->faction, m); - msg_release(m); - } - assert(dt.index>=0 && dt.indexnumber); - df->person[dt.index].hp = du->race->hitpoints; - return false; - } - } -#ifdef SHOW_KILLS - ++at.fighter->kills; -#endif - - if (bdebug) { - fprintf(bdebug, "Damage %d, armor %d, type %d: %d -> %d HP, tot.\n", - da, ar, type, df->person[dt.index].hp + rda, df->person[dt.index].hp); - } - for (pitm=&du->items; *pitm; ) { - item * itm = *pitm; - const item_type * itype = itm->type; - if (!(itype->flags & ITF_CURSED) && dt.index < itm->number) { - /* 25% Grundchance, das ein Item kaputtgeht. */ - if (rng_int() % 4 < 1) { - i_change(pitm, itype, -1); - } - } - if (*pitm==itm) { - pitm = &itm->next; - } - } - kill_troop(dt); - - return true; -} - -static int -count_side(const side * s, const side * vs, int minrow, int maxrow, int select) -{ - fighter * fig; - int people = 0; - int unitrow[NUMROWS]; - - if (maxrowfighters; fig; fig = fig->next) { - if (fig->alive - fig->removed > 0) { - int row = statusrow(fig->status); - if (select&SELECT_ADVANCE) { - if (unitrow[row] == -1) { - unitrow[row] = get_unitrow(fig, vs); - } - row = unitrow[row]; - } - if (row >= minrow && row <= maxrow) { - people += fig->alive - fig->removed; - if (people>0 && (select&SELECT_FIND)) break; - } - } - } - return people; -} - -/* return the number of live allies warning: this function only considers -* troops that are still alive, not those that are still fighting although -* dead. */ -int -count_allies(const side * as, int minrow, int maxrow, int select, int allytype) -{ - battle *b = as->battle; - side *ds; - int count = 0; - - for (ds=b->sides;ds!=b->sides+b->nsides;++ds) { - if ((allytype==ALLY_ANY && helping(as, ds)) || (allytype==ALLY_SELF && as->faction==ds->faction)) { - count += count_side(ds, NULL, minrow, maxrow, select); - if (count>0 && (select&SELECT_FIND)) break; - } - } - return count; -} - -static int -count_enemies_i(battle * b, const fighter * af, int minrow, int maxrow, int select) -{ - side *es, *as = af->side; - int i = 0; - - for (es=b->sides;es!=b->sides+b->nsides;++es) { - if (as==NULL || enemy(es, as)) { - int offset = 0; - if (select&SELECT_DISTANCE) { - offset = get_unitrow(af, es) - FIGHT_ROW; - } - i += count_side(es, as, minrow-offset, maxrow-offset, select); - if (i>0 && (select&SELECT_FIND)) break; - } - } - return i; -} - -int -count_enemies(battle * b, const fighter * af, int minrow, int maxrow, int select) -{ -#ifdef FASTCOUNT - int sr = statusrow(af->status); - side *as = af->side; - - if (b->alive==b->fast.alive && as==b->fast.side && sr==b->fast.status && minrow==b->fast.minrow && maxrow==b->fast.maxrow) { - if (b->fast.enemies[select]>=0) { -#ifdef DEBUG_FAST - int i = count_enemies_i(b, af, minrow, maxrow, select); - assert(i==b->fast.enemies[select]); -#endif - return b->fast.enemies[select]; - } else if (select&SELECT_FIND) { - if (b->fast.enemies[select-SELECT_FIND]>=0) { -#ifdef DEBUG_FAST - int i = count_enemies_i(b, af, minrow, maxrow, select); - assert((i>0)==(b->fast.enemies[select-SELECT_FIND]>0)); -#endif - return b->fast.enemies[select-SELECT_FIND]; - } - } - } else if (select!=SELECT_FIND || b->alive!=b->fast.alive) { - b->fast.side = as; - b->fast.status = sr; - b->fast.minrow = minrow; - b->fast.alive=b->alive; - b->fast.maxrow = maxrow; - memset(b->fast.enemies, -1, sizeof(b->fast.enemies)); - } -#endif - if (maxrow>=FIRST_ROW) { - int i = count_enemies_i(b, af, minrow, maxrow, select); -#ifdef FASTCOUNT - b->fast.enemies[select] = i; -#endif - return i; - } - return 0; -} - -troop -select_enemy(fighter * af, int minrow, int maxrow, int select) -{ - side *as = af->side; - battle * b = as->battle; - int si, selected; - int enemies; -#ifdef DEBUG_SELECT - troop result = no_troop; -#endif - if (af->unit->race->flags & RCF_FLY) { - /* flying races ignore min- and maxrow and can attack anyone fighting - * them */ - minrow = FIGHT_ROW; - maxrow = BEHIND_ROW; - } - minrow = MAX(minrow, FIGHT_ROW); - - enemies = count_enemies(b, af, minrow, maxrow, select); - - /* Niemand ist in der angegebenen Entfernung? */ - if (enemies<=0) return no_troop; - - selected = rng_int() % enemies; - for (si=0;as->enemies[si];++si) { - side *ds = as->enemies[si]; - fighter * df; - int unitrow[NUMROWS]; - int offset = 0; - - if (select&SELECT_DISTANCE) offset = get_unitrow(af, ds) - FIGHT_ROW; - - if (select&SELECT_ADVANCE) { - int ui; - for (ui=0;ui!=NUMROWS;++ui) unitrow[ui] = -1; - } - - for (df=ds->fighters; df ; df = df->next) { - int dr; - - dr = statusrow(df->status); - if (select&SELECT_ADVANCE) { - if (unitrow[dr]<0) { - unitrow[dr] = get_unitrow(df, as); - } - dr = unitrow[dr]; - } - - if (select&SELECT_DISTANCE) dr += offset; - if (dr < minrow || dr > maxrow) continue; - if (df->alive - df->removed > selected) { -#ifdef DEBUG_SELECT - if (result.fighter==NULL) { - result.index = selected; - result.fighter = df; - } -#else - troop dt; - dt.index = selected; - dt.fighter = df; - return dt; -#endif - } - selected -= (df->alive - df->removed); - enemies -= (df->alive - df->removed); - } - } - if (enemies!=0) { - log_error(("select_enemies has a bug.\n")); - } -#ifdef DEBUG_SELECT - return result; -#else - assert(!selected); - return no_troop; -#endif -} - -static int -get_tactics(const side * as, const side * ds) -{ - battle * b = as->battle; - side *stac; - int result = 0; - int defense = 0; - - if (b->max_tactics > 0) { - for (stac=b->sides;stac!=b->sides+b->nsides;++stac) { - if (stac->leader.value > result && helping(stac, as)) { - assert(ds==NULL || !helping(stac, ds)); - result = stac->leader.value; - } - if (ds && stac->leader.value > defense && helping(stac, ds)) { - assert(!helping(stac, as)); - defense = stac->leader.value; - } - } - } - return result - defense; -} - -static troop -select_opponent(battle * b, troop at, int mindist, int maxdist) -{ - fighter * af = at.fighter; - troop dt; - - if (af->unit->race->flags & RCF_FLY) { - /* flying races ignore min- and maxrow and can attack anyone fighting - * them */ - dt = select_enemy(at.fighter, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); - } else { - mindist = MAX(mindist, FIGHT_ROW); - dt = select_enemy(at.fighter, mindist, maxdist, SELECT_ADVANCE); - } - - if (b->turn==0 && dt.fighter) { - int tactics_formula = -1; - - if (tactics_formula<0) { - tactics_formula = get_param_int(global.parameters, "rules.tactics.formula", 0); - } - if (tactics_formula==1) { - int tactics = get_tactics(at.fighter->side, dt.fighter->side); - - /* percentage chance to get this attack */ - if (tactics>0) { - double tacch = 0.1 * tactics; - if (fval(b->region->terrain, SEA_REGION)) { - ship * sh = at.fighter->unit->ship; - if (sh) tacch *= sh->type->tac_bonus; - } - if (!chance(tacch)) { - dt.fighter = NULL; - } - } else { - dt.fighter = NULL; - } - } - } - - return dt; -} - -/* - * Abfrage mit - * - * cvector *fgs=fighters(b,af,FIGHT_ROW,BEHIND_ROW, FS_HELP|FS_ENEMY); - * fighter *fig; - * - * Optional: Verwirbeln. Vorsicht: Aufwändig! - * v_scramble(fgs->begin, fgs->end); - * - * for (fig = fgs->begin; fig != fgs->end; ++fig) { - * fighter *df = *fig; - * - * } - * - * cv_kill(fgs); free(fgs); Nicht vergessen - */ - -cvector * -fighters(battle *b, const side * vs, int minrow, int maxrow, int mask) -{ - side * s; - cvector *fightervp = malloc(sizeof(cvector)); - - assert(vs!=NULL); - cv_init(fightervp); - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter *fig; - - if (mask==FS_ENEMY) { - if (!enemy(s, vs)) continue; - } else if (mask==FS_HELP) { - if (enemy(s, vs) || !allysf(s, vs->faction)) { - continue; - } - } else { - assert(mask==(FS_HELP|FS_ENEMY) || !"invalid alliance state"); - } - for (fig = s->fighters; fig; fig = fig->next) { - int row = get_unitrow(fig, vs); - if (row >= minrow && row <= maxrow) { - cv_pushback(fightervp, fig); - } - } - } - - return fightervp; -} - -static void -report_failed_spell(battle * b, unit * mage, const spell * sp) -{ - message * m = msg_message("battle::spell_failed", "unit spell", mage, sp); - message_all(b, m); - msg_release(m); -} - -void -do_combatmagic(battle *b, combatmagic_t was) -{ - side * s; - region *r = b->region; - castorder *co; - int level, rank, sl; - spellrank spellranks[MAX_SPELLRANK]; - - memset(spellranks, 0, sizeof(spellranks)); - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter * fig; - for (fig = s->fighters; fig; fig = fig->next) { - unit * mage = fig->unit; - - if (fig->alive <= 0) continue; /* fighter kann im Kampf getötet worden sein */ - - level = eff_skill(mage, SK_MAGIC, r); - if (level > 0) { - double power; - const spell *sp; - const struct locale * lang = mage->faction->locale; - order * ord; - - switch(was) { - case DO_PRECOMBATSPELL: - sp = get_combatspell(mage, 0); - sl = get_combatspelllevel(mage, 0); - break; - case DO_POSTCOMBATSPELL: - sp = get_combatspell(mage, 2); - sl = get_combatspelllevel(mage, 2); - break; - default: - /* Fehler! */ - return; - } - if (sp == NULL) - continue; - - ord = create_order(K_CAST, lang, "'%s'", spell_name(sp, lang)); - if (cancast(mage, sp, 1, 1, ord) == false) { - free_order(ord); - continue; - } - - level = eff_spelllevel(mage, sp, level, 1); - if (sl > 0) level = MIN(sl, level); - if (level < 0) { - report_failed_spell(b, mage, sp); - free_order(ord); - continue; - } - - power = spellpower(r, mage, sp, level, ord); - free_order(ord); - if (power <= 0) { /* Effekt von Antimagie */ - report_failed_spell(b, mage, sp); - pay_spell(mage, sp, level, 1); - } else if (fumble(r, mage, sp, sp->level) == true) { - report_failed_spell(b, mage, sp); - pay_spell(mage, sp, level, 1); - } else { - co = new_castorder(fig, 0, sp, r, level, power, 0, 0, 0); - add_castorder(&spellranks[sp->rank], co); - } - } - } - } - for (rank = 0; rank < MAX_SPELLRANK; rank++) { - for (co = spellranks[rank].begin; co; co = co->next) { - fighter * fig = co->magician.fig; - const spell * sp = co->sp; - int level = co->level; - double power = co->force; - - if (sp->sp_function==NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); - } else { - level = ((cspell_f)sp->sp_function)(fig, level, power, sp); - if (level > 0) { - pay_spell(fig->unit, sp, level, 1); - } - } - } - } - for (rank = 0; rank < MAX_SPELLRANK; rank++) { - free_castorders(spellranks[rank].begin); - } -} - -static void -combat_action(fighter * af, int turn) -{ -#ifndef SIMPLE_COMBAT - af->action_counter++; - af->side->bf->lastturn = turn; -#endif -} - - -static void -do_combatspell(troop at) -{ - const spell *sp; - fighter *fi = at.fighter; - unit *mage = fi->unit; - battle *b = fi->side->battle; - region *r = b->region; - int level; - double power; - int fumblechance = 0; - void **mg; - order * ord; - int sl; - const struct locale * lang = mage->faction->locale; - - sp = get_combatspell(mage, 1); - if (sp == NULL) { - fi->magic = 0; /* Hat keinen Kampfzauber, kämpft nichtmagisch weiter */ - return; - } - ord = create_order(K_CAST, lang, "'%s'", spell_name(sp, lang)); - if (cancast(mage, sp, 1, 1, ord) == false) { - fi->magic = 0; /* Kann nicht mehr Zaubern, kämpft nichtmagisch weiter */ - return; - } - - level = eff_spelllevel(mage, sp, fi->magic, 1); - if ((sl = get_combatspelllevel(mage, 1)) > 0) level = MIN(level, sl); - - if (fumble(r, mage, sp, sp->level) == true) { - report_failed_spell(b, mage, sp); - pay_spell(mage, sp, level, 1); - return; - } - - for (mg = b->meffects.begin; mg != b->meffects.end; ++mg) { - meffect *mblock = *mg; - if (mblock->typ == SHIELD_BLOCK) { - if (meffect_blocked(b, mblock, fi->side) != 0) { - fumblechance += mblock->duration; - mblock->duration -= mblock->effect; - } - } - } - - /* Antimagie die Fehlschlag erhöht */ - if (rng_int()%100 < fumblechance) { - report_failed_spell(b, mage, sp); - pay_spell(mage, sp, level, 1); - free_order(ord); - return; - } - power = spellpower(r, mage, sp, level, ord); - free_order(ord); - if (power <= 0) { /* Effekt von Antimagie */ - report_failed_spell(b, mage, sp); - pay_spell(mage, sp, level, 1); - return; - } - - if (sp->sp_function==NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); - } else { - level = ((cspell_f)sp->sp_function)(fi, level, power, sp); - if (level > 0) { - pay_spell(mage, sp, level, 1); - combat_action(at.fighter, b->turn); - } - } -} - - -/* Sonderattacken: Monster patzern nicht und zahlen auch keine - * Spruchkosten. Da die Spruchstärke direkt durch den Level bestimmt - * wird, wirkt auch keine Antimagie (wird sonst in spellpower - * gemacht) */ - -static void -do_extra_spell(troop at, const att *a) -{ - const spell *sp = a->data.sp; - fighter *fi = at.fighter; - double power; - - power = sp->level * MagicPower(); - if (sp->sp_function==NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); - } else { - ((cspell_f)sp->sp_function)(fi, sp->level, power, sp); - } -} - -static int -skilldiff(troop at, troop dt, int dist) -{ - fighter *af = at.fighter, *df = dt.fighter; - unit *au = af->unit, *du = df->unit; - int is_protected = 0, skdiff = 0; - weapon * awp = select_weapon(at, true, dist>1); - - skdiff += af->person[at.index].attack; - skdiff -= df->person[dt.index].defence; - - if (df->person[dt.index].flags & FL_SLEEPING) - skdiff += 2; - - /* Effekte durch Rassen */ - if (awp!=NULL && au->race == new_race[RC_HALFLING] && dragonrace(du->race)) { - skdiff += 5; - } - - if (au->race == new_race[RC_GOBLIN]) { - static int goblin_bonus = -1; - if (goblin_bonus<0) goblin_bonus = get_param_int(global.parameters, "rules.combat.goblinbonus", 10); - if (af->side->size[SUM_ROW] >= df->side->size[SUM_ROW] * goblin_bonus) { - skdiff += 1; - } - } - - if (df->building) { - boolean init = false; - static const curse_type * strongwall_ct, * magicwalls_ct; - if (!init) { - strongwall_ct = ct_find("strongwall"); - magicwalls_ct = ct_find("magicwalls"); - init=true; - } - if (df->building->type->protection) { - int beff = df->building->type->protection(df->building, du); - if (beff) { - skdiff -= beff; - is_protected = 2; - } - } - if (strongwall_ct) { - curse * c = get_curse(df->building->attribs, strongwall_ct); - if (curse_active(c)) { - /* wirkt auf alle Gebäude */ - skdiff -= curse_geteffect_int(c); - is_protected = 2; - } - } - if (magicwalls_ct && curse_active(get_curse(df->building->attribs, magicwalls_ct))) { - /* Verdoppelt Burgenbonus */ - skdiff -= buildingeffsize(df->building, false); - } - } - /* Goblin-Verteidigung - * ist direkt in der Rassentabelle als df_default - */ - - /* Effekte der Waffen */ - skdiff += weapon_effskill(at, dt, awp, true, dist>1); - if (awp && fval(awp->type, WTF_MISSILE)) { - skdiff -= is_protected; - if (awp->type->modifiers) { - int w; - for (w=0;awp->type->modifiers[w].value!=0;++w) { - if (awp->type->modifiers[w].flags & WMF_MISSILE_TARGET) { - /* skill decreases by targeting difficulty (bow -2, catapult -4) */ - skdiff -= awp->type->modifiers[w].value; - break; - } - } - } - } - if (skill_formula==FORMULA_ORIG) { - weapon * dwp = select_weapon(dt, false, dist>1); - skdiff -= weapon_effskill(dt, at, dwp, false, dist>1); - } - return skdiff; -} - -static int -setreload(troop at) -{ - fighter * af = at.fighter; - const weapon_type * wtype = af->person[at.index].missile->type; - if (wtype->reload == 0) return 0; - return af->person[at.index].reload = wtype->reload; -} - -int -getreload(troop at) -{ - return at.fighter->person[at.index].reload; -} - -static void -debug_hit(troop at, const weapon * awp, troop dt, const weapon * dwp, int skdiff, int dist, boolean success) -{ - fprintf(bdebug, "%.4s/%d [%6s/%d] %s %.4s/%d [%6s/%d] with %d, distance %d\n", - unitid(at.fighter->unit), at.index, - LOC(default_locale, awp ? resourcename(awp->type->itype->rtype, 0) : "unarmed"), - weapon_effskill(at, dt, awp, true, dist>1), - success?"hits":"misses", - unitid(dt.fighter->unit), dt.index, - LOC(default_locale, dwp ? resourcename(dwp->type->itype->rtype, 0) : "unarmed"), - weapon_effskill(dt, at, dwp, false, dist>1), - skdiff, dist); -} - -int -hits(troop at, troop dt, weapon * awp) -{ - fighter *af = at.fighter, *df = dt.fighter; - const armor_type * armor, * shield = 0; - int skdiff = 0; - int dist = get_unitrow(af, df->side) + get_unitrow(df, af->side) - 1; - weapon * dwp = select_weapon(dt, false, dist>1); - - if (!df->alive) return 0; - if (getreload(at)) return 0; - if (dist>1 && (awp == NULL || !fval(awp->type, WTF_MISSILE))) return 0; - - /* mark this person as hit. */ - df->person[dt.index].flags |= FL_HIT; - - if (af->person[at.index].flags & FL_STUNNED) { - af->person[at.index].flags &= ~FL_STUNNED; - return 0; - } - if ((af->person[at.index].flags & FL_TIRED && rng_int()%100 < 50) - || (af->person[at.index].flags & FL_SLEEPING)) - return 0; - - /* effect of sp_reeling_arrows combatspell */ - if (af->side->battle->reelarrow && awp && fval(awp->type, WTF_MISSILE) && rng_double() < 0.5) { - return 0; - } - - skdiff = skilldiff(at, dt, dist); - /* Verteidiger bekommt eine Rüstung */ - armor = select_armor(dt, true); - if (dwp==NULL || (dwp->type->flags & WTF_USESHIELD)) { - shield = select_armor(dt, false); - } - if (contest(skdiff, dt, armor, shield)) { - if (bdebug) { - debug_hit(at, awp, dt, dwp, skdiff, dist, true); - } - return 1; - } - if (bdebug) { - debug_hit(at, awp, dt, dwp, skdiff, dist, false); - } - return 0; -} - -void -dazzle(battle *b, troop *td) -{ - /* Nicht kumulativ ! */ - if(td->fighter->person[td->index].flags & FL_DAZZLED) return; - -#ifdef TODO_RUNESWORD - if (td->fighter->weapon[WP_RUNESWORD].count > td->index) { - return; - } -#endif - if (td->fighter->person[td->index].flags & FL_COURAGE) { - return; - } - - if (td->fighter->person[td->index].flags & FL_DAZZLED) { - return; - } - - td->fighter->person[td->index].flags |= FL_DAZZLED; - td->fighter->person[td->index].defence--; -} - -/* TODO: Gebäude/Schiffe sollten auch zerstörbar sein. Schwierig im Kampf, - * besonders bei Schiffen. */ - -void -damage_building(battle *b, building *bldg, int damage_abs) -{ - bldg->size = MAX(1, bldg->size-damage_abs); - - /* Wenn Burg, dann gucken, ob die Leute alle noch in das Gebäude passen. */ - - if (bldg->type->protection) { - side * s; - - bldg->sizeleft = bldg->size; - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter * fig; - for (fig=s->fighters;fig;fig=fig->next) { - if (fig->building == bldg) { - if (bldg->sizeleft >= fig->unit->number) { - fig->building = bldg; - bldg->sizeleft -= fig->unit->number; - } else { - fig->building = NULL; - } - } - } - } - } -} - -static int -attacks_per_round(troop t) -{ - return t.fighter->person[t.index].speed; -} - -static void -make_heroes(battle * b) -{ - side * s; - static int hero_speed = 0; - if (hero_speed==0) { - hero_speed = get_param_int(global.parameters, "rules.combat.herospeed", 10); - } - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter * fig; - for (fig=s->fighters;fig;fig=fig->next) { - unit * u = fig->unit; - if (fval(u, UFL_HERO)) { - int i; - assert(playerrace(u->race)); - for (i=0;i!=u->number;++i) { - fig->person[i].speed += (hero_speed-1); - } - } - } - } -} - -static void -attack(battle *b, troop ta, const att *a, int numattack) -{ - fighter *af = ta.fighter; - troop td; - unit *au = af->unit; - - switch(a->type) { - case AT_COMBATSPELL: - /* Magier versuchen immer erstmal zu zaubern, erst wenn das - * fehlschlägt, wird af->magic == 0 und der Magier kämpft - * konventionell weiter */ - if (numattack==0 && af->magic > 0) { - /* wenn der magier in die potenzielle Reichweite von Attacken des - * Feindes kommt, beginnt er auch bei einem Status von KAEMPFE NICHT, - * Kampfzauber zu schleudern: */ - if (count_enemies(b, af, melee_range[0], missile_range[1], SELECT_ADVANCE|SELECT_DISTANCE|SELECT_FIND)) { - do_combatspell(ta); - } - } - break; - case AT_STANDARD: /* Waffen, mag. Gegenstände, Kampfzauber */ - if (numattack > 0 || af->magic <= 0) { - weapon * wp = ta.fighter->person[ta.index].missile; - int melee = count_enemies(b, af, melee_range[0], melee_range[1], SELECT_ADVANCE|SELECT_DISTANCE|SELECT_FIND); - if (melee) wp = preferred_weapon(ta, true); - /* Sonderbehandlungen */ - - if (getreload(ta)) { - ta.fighter->person[ta.index].reload--; - } else { - boolean standard_attack = true; - boolean reload = false; - /* spezialattacken der waffe nur, wenn erste attacke in der runde. - * sonst helden mit feuerschwertern zu mächtig */ - if (numattack==0 && wp && wp->type->attack) { - int dead = 0; - standard_attack = wp->type->attack(&ta, wp->type, &dead); - if (!standard_attack) reload = true; - af->catmsg += dead; - if (!standard_attack && af->person[ta.index].last_action < b->turn) { - af->person[ta.index].last_action = b->turn; - combat_action(af, b->turn); - } - } - if (standard_attack) { - boolean missile = false; - if (wp && fval(wp->type, WTF_MISSILE)) missile = true; - if (missile) { - td = select_opponent(b, ta, missile_range[0], missile_range[1]); - } - else { - td = select_opponent(b, ta, melee_range[0], melee_range[1]); - } - if (!td.fighter) return; - if (ta.fighter->person[ta.index].last_action < b->turn) { - ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); - } - reload = true; - if (hits(ta, td, wp)) { - const char * d; - if (wp == NULL) d = au->race->def_damage; - else if (is_riding(ta)) d = wp->type->damage[1]; - else d = wp->type->damage[0]; - terminate(td, ta, a->type, d, missile); - } - } - if (reload && wp && wp->type->reload && !getreload(ta)) { - int i = setreload(ta); - if (bdebug) { - fprintf(bdebug, "%s/%d reloading %d turns\n", unitid(au), ta.index, i); - } - } - } - } - break; - case AT_SPELL: /* Extra-Sprüche. Kampfzauber in AT_COMBATSPELL! */ - do_extra_spell(ta, a); - break; - case AT_NATURAL: - td = select_opponent(b, ta, melee_range[0], melee_range[1]); - if (!td.fighter) return; - if(ta.fighter->person[ta.index].last_action < b->turn) { - ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); - } - if (hits(ta, td, NULL)) { - terminate(td, ta, a->type, a->data.dice, false); - } - break; - case AT_DRAIN_ST: - td = select_opponent(b, ta, melee_range[0], melee_range[1]); - if (!td.fighter) return; - if(ta.fighter->person[ta.index].last_action < b->turn) { - ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); - } - if (hits(ta, td, NULL)) { - int c = dice_rand(a->data.dice); - while(c > 0) { - if (rng_int()%2) { - td.fighter->person[td.index].attack -= 1; - } else { - td.fighter->person[td.index].defence -= 1; - } - c--; - } - } - break; - case AT_DRAIN_EXP: - td = select_opponent(b, ta, melee_range[0], melee_range[1]); - if (!td.fighter) return; - if(ta.fighter->person[ta.index].last_action < b->turn) { - ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); - } - if (hits(ta, td, NULL)) { - drain_exp(td.fighter->unit, dice_rand(a->data.dice)); - } - break; - case AT_DAZZLE: - td = select_opponent(b, ta, melee_range[0], melee_range[1]); - if (!td.fighter) return; - if(ta.fighter->person[ta.index].last_action < b->turn) { - ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); - } - if (hits(ta, td, NULL)) { - dazzle(b, &td); - } - break; - case AT_STRUCTURAL: - td = select_opponent(b, ta, melee_range[0], melee_range[1]); - if (!td.fighter) return; - if(ta.fighter->person[ta.index].last_action < b->turn) { - ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); - } - if (td.fighter->unit->ship) { - td.fighter->unit->ship->damage += DAMAGE_SCALE * dice_rand(a->data.dice); - } else if (td.fighter->unit->building) { - damage_building(b, td.fighter->unit->building, dice_rand(a->data.dice)); - } - } -} - -void -do_attack(fighter * af) -{ - troop ta; - unit *au = af->unit; - side *side = af->side; - battle *b = side->battle; - - ta.fighter = af; - - assert(au && au->number); - /* Da das Zuschlagen auf Einheiten und nicht auf den einzelnen - * Kämpfern beruht, darf die Reihenfolge und Größe der Einheit keine - * Rolle spielen, Das tut sie nur dann, wenn jeder, der am Anfang der - * Runde lebte, auch zuschlagen darf. Ansonsten ist der, der zufällig - * mit einer großen Einheit zuerst drankommt, extrem bevorteilt. */ - ta.index = af->fighting; - - while (ta.index--) { - /* Wir suchen eine beliebige Feind-Einheit aus. An der können - * wir feststellen, ob noch jemand da ist. */ - int apr, attacks = attacks_per_round(ta); - if (!count_enemies(b, af, FIGHT_ROW, LAST_ROW, SELECT_FIND)) break; - - for (apr=0;apr!=attacks;++apr) { - int a; - for (a=0; a!=10 && au->race->attack[a].type!=AT_NONE; ++a) { - if (apr>0) { - /* Wenn die Waffe nachladen muss, oder es sich nicht um einen - * Waffen-Angriff handelt, dann gilt der Speed nicht. */ - if (au->race->attack[a].type!=AT_STANDARD) continue; - else { - weapon * wp = preferred_weapon(ta, true); - if (wp!=NULL && wp->type->reload) continue; - } - } - attack(b, ta, &(au->race->attack[a]), apr); - } - } - } - /* Der letzte Katapultschütze setzt die - * Ladezeit neu und generiert die Meldung. */ - if (af->catmsg>=0) { - struct message * m = msg_message("battle::killed", "unit dead", au, af->catmsg); - message_all(b, m); - msg_release(m); - af->catmsg = -1; - } -} - -void -do_regenerate(fighter *af) -{ - troop ta; - unit *au = af->unit; - - ta.fighter = af; - ta.index = af->fighting; - - while(ta.index--) { - af->person[ta.index].hp += effskill(au, SK_STAMINA); - af->person[ta.index].hp = MIN(unit_max_hp(au), af->person[ta.index].hp); - } -} - -static void -add_tactics(tactics * ta, fighter * fig, int value) -{ - if (value == 0 || value < ta->value) - return; - if (value > ta->value) - cv_kill(&ta->fighters); - cv_pushback(&ta->fighters, fig); - cv_pushback(&fig->side->battle->leaders, fig); - ta->value = value; -} - -static double horsebonus(const unit * u) -{ - static const item_type * it_horse = 0; - static const item_type * it_elvenhorse = 0; - static const item_type * it_charger = 0; - region * r = u->region; - int n1 = 0, n2 = 0, n3 = 0; - item * itm = u->items; - int skl = eff_skill(u, SK_RIDING, r); - - if (skl<1) return 0.0; - - if (it_horse==0) { - it_horse = it_find("horse"); - it_elvenhorse = it_find("elvenhorse"); - it_charger = it_find("charger"); - } - - for (;itm;itm=itm->next) { - if (itm->type->flags&ITF_ANIMAL) { - if (itm->type==it_elvenhorse) n3 +=itm->number; - else if (itm->type==it_charger) n2 +=itm->number; - else if (itm->type==it_horse) n1 +=itm->number; - } - } - if (skl >= 5 && n3>=u->number) return 0.30; - if (skl >= 3 && n2+n3>=u->number) return 0.20; - if (skl >= 1 && n1+n2+n3>=u->number) return 0.10; - return 0.0F; -} - -double -fleechance(unit * u) -{ - double c = 0.20; /* Fluchtwahrscheinlichkeit in % */ - region * r = u->region; - attrib * a = a_find(u->attribs, &at_fleechance); - /* Einheit u versucht, dem Getümmel zu entkommen */ - - c += (eff_skill(u, SK_STEALTH, r) * 0.05); - c += horsebonus(u); - - if (u->race == new_race[RC_HALFLING]) { - c += 0.20; - c = MIN(c, 0.90); - } else { - c = MIN(c, 0.75); - } - - if (a!=NULL) c += a->data.flt; - - return c; -} - -/** add a new army to the conflict - * beware: armies need to be added _at the beginning_ of the list because - * otherwise join_allies() will get into trouble */ -static side * -make_side(battle * b, const faction * f, const group * g, unsigned int flags, const faction *stealthfaction) -{ - side *s1 = b->sides+b->nsides; - bfaction * bf; - -#ifdef SIMPLE_COMBAT - if (fval(b->region->terrain, SEA_REGION)) { - /* every fight in an ocean is short */ - flags |= SIDE_HASGUARDS; - } else { - unit * u; - for (u = b->region->units; u; u = u->next) { - if (is_guard(u, HELP_ALL)) { - if (alliedunit(u, f, HELP_GUARD)) { - flags |= SIDE_HASGUARDS; - break; - } - } - } - } -#endif - - s1->battle = b; - s1->group = g; - s1->flags = flags; - s1->stealthfaction = stealthfaction; - for (bf = b->factions;bf;bf=bf->next) { - faction * f2 = bf->faction; - - if (f2 == f) { - s1->bf = bf; - s1->faction = f2; - s1->index = b->nsides++; - s1->nextF = bf->sides; - bf->sides = s1; - assert(b->nsides<=MAXSIDES); - break; - } - } - assert(bf); - return s1; -} - -troop -select_ally(fighter * af, int minrow, int maxrow, int allytype) -{ - side *as = af->side; - battle *b = as->battle; - side * ds; - int allies = count_allies(as, minrow, maxrow, SELECT_ADVANCE, allytype); - - if (!allies) { - return no_troop; - } - allies = rng_int() % allies; - - for (ds=b->sides;ds!=b->sides+b->nsides;++ds) { - if ((allytype==ALLY_ANY && helping(as, ds)) || (allytype==ALLY_SELF && as->faction==ds->faction)) { - fighter * df; - for (df=ds->fighters; df; df=df->next) { - int dr = get_unitrow(df, NULL); - if (dr >= minrow && dr <= maxrow) { - if (df->alive - df->removed > allies) { - troop dt; - assert(allies>=0); - dt.index = allies; - dt.fighter = df; - return dt; - } - allies -= df->alive; - } - } - } - } - assert(!"we should never have gotten here"); - return no_troop; -} - - -static int loot_quota(const unit * src, const unit * dst, const item_type * type, int n) -{ - static float divisor = -1; - if (dst && src && src->faction!=dst->faction) { - if (divisor<0) { - divisor = get_param_flt(global.parameters, "rules.items.loot_divisor", 1); - assert(divisor==0 || divisor>=1); - } - if (divisor>=1) { - double r = n / divisor; - int x = (int)r; - - r = r - x; - if (chance(r)) ++x; - - return x; - } - } - return n; -} - -static void -loot_items(fighter * corpse) -{ - unit * u = corpse->unit; - item * itm = u->items; - battle * b = corpse->side->battle; - int dead = dead_fighters(corpse); - - if (dead<=0) return; - - while (itm) { - float lootfactor = dead/(float)u->number; /* only loot the dead! */ - int maxloot = (int)(itm->number*lootfactor); - if (maxloot>0) { - int i = MIN(10, maxloot); - for (; i != 0; --i) { - int loot = maxloot/i; - - if (loot>0) { - fighter *fig = NULL; - int looting = 0; - int maxrow = 0; - /* mustloot: we absolutely, positively must have somebody loot this thing */ - int mustloot = itm->type->flags & (ITF_CURSED|ITF_NOTLOST); - - itm->number -= loot; - maxloot -= loot; - - if (is_monsters(u->faction) && (loot_rules & LOOT_MONSTERS)) { - looting = 1; - } else if (loot_rules&LOOT_OTHERS) { - looting = 1; - } else if (loot_rules&LOOT_SELF) { - looting = 2; - } - if (looting) { - if (mustloot) { - maxrow = LAST_ROW; - } else if (loot_rules&LOOT_KEEPLOOT) { - int lootchance = 50 + b->keeploot; - if (rng_int() % 100 < lootchance) { - maxrow = BEHIND_ROW; - } - } else { - maxrow = LAST_ROW; - } - } - if (maxrow>0) { - if (looting==1) { - /* enemies get dibs */ - fig = select_enemy(corpse, FIGHT_ROW, maxrow, 0).fighter; - } - if (!fig) { - /* self and allies get second pick */ - fig = select_ally(corpse, FIGHT_ROW, LAST_ROW, ALLY_SELF).fighter; - } - } - - if (fig) { - int trueloot = mustloot?loot:loot_quota(corpse->unit, fig->unit, itm->type, loot); - if (trueloot>0) { - item * l = fig->loot; - while (l && l->type!=itm->type) l=l->next; - if (!l) { - l = calloc(sizeof(item), 1); - l->next = fig->loot; - fig->loot = l; - l->type = itm->type; - } - l->number += trueloot; - } - } - } - } - } - itm = itm->next; - } -} - -#ifndef SIMPLE_ESCAPE -static void -loot_fleeing(fighter* fig, unit* runner) -{ - /* TODO: Vernünftig fixen */ - runner->items = NULL; - assert(runner->items == NULL); - runner->items = fig->run.items; - fig->run.items = NULL; -} - -static void -merge_fleeloot(fighter* fig, unit* u) -{ - i_merge(&u->items, &fig->run.items); -} -#endif /* SIMPLE_ESCAPE */ - -static boolean -seematrix(const faction * f, const side * s) -{ - if (f==s->faction) return true; - if (s->flags & SIDE_STEALTH) return false; - return true; -} - -static double -PopulationDamage(void) -{ - static double value = -1.0; - if (value<0) { - int damage = get_param_int(global.parameters, "rules.combat.populationdamage", BATTLE_KILLS_PEASANTS); - value = damage/100.0; - } - return value; -} - - -static void -battle_effects(battle * b, int dead_players) -{ - region * r = b->region; - int dead_peasants = MIN(rpeasants(r), (int)(dead_players*PopulationDamage())); - if (dead_peasants) { - deathcounts(r, dead_peasants + dead_players); - chaoscounts(r, dead_peasants / 2); - rsetpeasants(r, rpeasants(r) - dead_peasants); - } -} - -static void -reorder_fleeing(region * r) -{ - unit **usrc = &r->units; - unit **udst = &r->units; - unit *ufirst = NULL; - unit *u; - - for (;*udst;udst=&u->next) { - u = *udst; - } - - for (u=*usrc;u!=ufirst;u=*usrc) { - if (u->next && fval(u, UFL_FLEEING)) { - *usrc = u->next; - *udst = u; - udst = &u->next; - if (!ufirst) ufirst = u; - } else { - usrc = &u->next; - } - } - *udst = NULL; -} - -static void -aftermath(battle * b) -{ - int i; - region *r = b->region; - ship *sh; - side *s; - int dead_players = 0; - bfaction * bf; - boolean ships_damaged = (boolean)(b->turn+(b->has_tactics_turn?1:0)>2); /* only used for ship damage! */ - -#ifdef TROLLSAVE - int *trollsave = calloc(2 * cv_size(&b->factions), sizeof(int)); -#endif - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter * df; - for (df = s->fighters; df; df=df->next) { - unit *du = df->unit; - int dead = dead_fighters(df); - int pr_mercy = 0; - -#ifdef TROLLSAVE - /* Trolle können regenerieren */ - if (df->alive > 0 && dead>0 && du->race == new_race[RC_TROLL]) { - for (i = 0; i != dead; ++i) { - if (chance(TROLL_REGENERATION)) { - ++df->alive; - ++s->alive; - ++s->battle->alive; - ++trollsave[s->index]; - /* do not change dead here, or loop will not terminate! recalculate later */ - } - } - dead = dead_fighters(df); - } -#endif - /* Regeneration durch PR_MERCY */ - if (dead>0 && pr_mercy) { - for (i = 0; i != dead; ++i) { - if (rng_int()%100 < pr_mercy) { - ++df->alive; - ++s->alive; - ++s->battle->alive; - /* do not change dead here, or loop will not terminate! recalculate later */ - } - } - dead = dead_fighters(df); - } - - /* tote insgesamt: */ - s->dead += dead; - /* Tote, die wiederbelebt werde können: */ - if (playerrace(df->unit->race)) { - s->casualties += dead; - } -#ifdef SHOW_KILLS - if (df->hits + df->kills) { - struct message * m = msg_message("killsandhits", "unit hits kills", du, df->hits, df->kills); - message_faction(b, du->faction, m); - msg_release(m); - } -#endif - } - } - - /* POSTCOMBAT */ - do_combatmagic(b, DO_POSTCOMBATSPELL); - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - int snumber = 0; - fighter *df; - boolean relevant = false; /* Kampf relevant für diese Partei? */ -#ifdef SIMPLE_COMBAT - if (fval(s, SIDE_HASGUARDS) == 0) relevant = true; -#else - if (s->bf->lastturn>1) { - relevant = true; - } else if (s->bf->lastturn==1 && b->has_tactics_turn) { - side * stac; - for (stac=b->sides; stac; stac=stac->next) { - if (stac->leader.value == b->max_tactics && helping(stac, s)) { - relevant = true; - break; - } - } - } -#endif - s->flee = 0; - - for (df=s->fighters;df;df=df->next) { - unit *du = df->unit; - int dead = dead_fighters(df); - int sum_hp = 0; - int n; - - for (n = 0; n != df->alive; ++n) { - if (df->person[n].hp > 0) { - sum_hp += df->person[n].hp; - } - } - snumber += du->number; -#ifdef SIMPLE_COMBAT - if (relevant) { - int flags = UFL_LONGACTION|UFL_NOTMOVING; -#ifdef SIMPLE_ESCAPE - if (du->status==ST_FLEE) flags -= UFL_NOTMOVING; -#endif /* SIMPLE_ESCAPE */ - fset(du, flags); - } - if (sum_hp+df->run.hphp) { - /* someone on the ship got damaged, damage the ship */ - ship * sh = du->ship?du->ship:leftship(du); - if (sh) fset(sh, SF_DAMAGED); - } -#else - if (relevant) { - fset(du, UFL_NOTMOVING); /* unit cannot move this round */ - if (df->action_counter >= du->number) { - ship * sh = du->ship?du->ship:leftship(du); - if (sh) fset(sh, SF_DAMAGED); - fset(du, UFL_LONGACTION); - } - } -#endif - - if (df->alive == du->number) { - du->hp = sum_hp; - continue; /* nichts passiert */ - } else if (df->run.hp) { - if (df->alive == 0) { - /* Report the casualties */ - reportcasualties(b, df, dead); - - /* Zuerst dürfen die Feinde plündern, die mitgenommenen Items - * stehen in fig->run.items. Dann werden die Fliehenden auf - * die leere (tote) alte Einheit gemapt */ -#ifdef SIMPLE_ESCAPE - if (!fval(df, FIG_NOLOOT)) { - loot_items(df); - } -#else - if (fval(df, FIG_NOLOOT)){ - merge_fleeloot(df, du); - } else { - loot_items(df); - loot_fleeing(df, du); - } -#endif /* SIMPLE_ESCAPE */ - scale_number(du, df->run.number); - du->hp = df->run.hp; - setguard(du, GUARD_NONE); - /* must leave ships or buildings, or a stealthy hobbit - * can hold castles indefinitely */ - if (!fval(r->terrain, SEA_REGION)) { - leave(du, true); /* even region owners have to flee */ - } -#ifndef SIMPLE_ESCAPE - if (df->run.region) { - run_to(du, df->run.region); - df->run.region = du->region; - } - fset(du, UFL_LONGACTION|UFL_NOTMOVING); -#endif /* SIMPLE_ESCAPE */ - fset(du, UFL_FLEEING); - } else { - /* nur teilweise geflohene Einheiten mergen sich wieder */ - df->alive += df->run.number; - s->size[0] += df->run.number; - s->size[statusrow(df->status)] += df->run.number; - s->alive += df->run.number; - sum_hp += df->run.hp; -#ifndef SIMPLE_ESCAPE - merge_fleeloot(df, du); -#endif /* SIMPLE_ESCAPE */ - df->run.number = 0; - df->run.hp = 0; - /* df->run.region = NULL;*/ - - reportcasualties(b, df, dead); - - scale_number(du, df->alive); - du->hp = sum_hp; - } - } else { - if (df->alive==0) { - /* alle sind tot, niemand geflohen. Einheit auflösen */ - df->run.number = 0; - df->run.hp = 0; -#ifndef SIMPLE_ESCAPE - df->run.region = NULL; -#endif /* SIMPLE_ESCAPE */ - - /* Report the casualties */ - reportcasualties(b, df, dead); - - /* Distribute Loot */ - loot_items(df); - - setguard(du, GUARD_NONE); - scale_number(du, 0); - } else { - df->run.number = 0; - df->run.hp = 0; - - reportcasualties(b, df, dead); - - scale_number(du, df->alive); - du->hp = sum_hp; - } - } - s->flee += df->run.number; - - if (playerrace(du->race)) { - /* tote im kampf werden zu regionsuntoten: - * for each of them, a peasant will die as well */ - dead_players += dead; - } - if (du->hp < du->number) { - log_error(("%s has less hitpoints (%u) than people (%u)\n", - itoa36(du->no), du->hp, du->number)); - du->hp = du->number; - } - } - s->alive+=s->healed; - assert(snumber==s->flee+s->alive+s->dead); - } - - battle_effects(b, dead_players); - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - message * seen = msg_message("battle::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", - "index abbrev dead fled survived", - army_index(s), "-?-", s->dead, s->flee, s->alive); - - for (bf=b->factions;bf;bf=bf->next) { - faction * f = bf->faction; - message * m = seematrix(f, s)?seen:unseen; - - message_faction(b, f, m); - } - - msg_release(seen); - msg_release(unseen); - } - - /* Wir benutzen drifted, um uns zu merken, ob ein Schiff - * schonmal Schaden genommen hat. (moved und drifted - * sollten in flags überführt werden */ - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter *df; - - for (df=s->fighters; df; df=df->next) { - unit *du = df->unit; - item * l; - - /* Beute verteilen */ - for (l=df->loot; l; l=l->next) { - const item_type * itype = l->type; - message * m = msg_message("battle_loot", "unit amount item", du, l->number, itype->rtype); - message_faction(b, du->faction, m); - msg_release(m); - i_change(&du->items, itype, l->number); - } - - /* Wenn sich die Einheit auf einem Schiff befindet, wird - * dieses Schiff beschädigt. Andernfalls ein Schiff, welches - * evt. zuvor verlassen wurde. */ - if (ships_damaged) { - if (du->ship) sh = du->ship; - else sh = leftship(du); - - if (sh && fval(sh, SF_DAMAGED)) { - int n = b->turn - 2; - if (n>0) { - damage_ship(sh, 0.05 * n); - freset(sh, SF_DAMAGED); - } - } - } - } - } - - if (ships_damaged) { - ship **sp = &r->ships; - - while (*sp) { - ship * sh = *sp; - freset(sh, SF_DAMAGED); - if (sh->damage >= sh->size * DAMAGE_SCALE) { - remove_ship(sp, sh); - } - if (*sp==sh) sp=&sh->next; - } - } -#ifdef TROLLSAVE - free(trollsave); -#endif - - reorder_fleeing(r); - - if (bdebug) { - fprintf(bdebug, "The battle lasted %d turns, %s and %s.\n", - b->turn, - b->has_tactics_turn?"had a tactic turn":"had no tactic turn", - ships_damaged?"was relevant":"was not relevant."); - } -} - -static void -battle_punit(unit * u, battle * b) -{ - bfaction * bf; - strlist *S, *x; - - for (bf = b->factions;bf;bf=bf->next) { - faction *f = bf->faction; - - S = 0; - spunit(&S, f, u, 4, see_battle); - for (x = S; x; x = x->next) { - fbattlerecord(b, f, x->s); - if (bdebug && u->faction == f) { - fputs(x->s, bdebug); - fputc('\n', bdebug); - } - } - if (S) - freestrlist(S); - } -} - -static void -print_fighters(battle * b, const side * s) -{ - fighter *df; - int row; - - for (row=1;row!=NUMROWS;++row) { - message * m = NULL; - - for (df=s->fighters; df; df=df->next) { - unit *du = df->unit; - int thisrow = statusrow(df->unit->status); - - if (row == thisrow) { - if (m==NULL) { - m = msg_message("battle::row_header", "row", row); - message_all(b, m); - } - battle_punit(du, b); - } - } - if (m!=NULL) msg_release(m); - } -} - -boolean -is_attacker(const fighter * fig) -{ - return fval(fig, FIG_ATTACKER)!=0; -} - -static void -set_attacker(fighter * fig) -{ - fset(fig, FIG_ATTACKER); -} - -static void -print_header(battle * b) -{ - bfaction * bf; - char zText[32*MAXSIDES]; - - for (bf=b->factions;bf;bf=bf->next) { - message * m; - faction * f = bf->faction; - const char * lastf = NULL; - boolean first = false; - side * s; - char * bufp = zText; - size_t size = sizeof(zText) - 1; - int bytes; - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter *df; - for (df=s->fighters;df;df=df->next) { - if (is_attacker(df)) { - if (first) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (lastf) { - bytes = (int)strlcpy(bufp, (const char *)lastf, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - first = true; - } - if (seematrix(f, s) == true) - lastf = sidename(s); - else - lastf = LOC(f->locale, "unknown_faction_dative"); - break; - } - } - } - if (first) { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, (const char *)LOC(f->locale, "and"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (lastf) { - bytes = (int)strlcpy(bufp, (const char *)lastf, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - - m = msg_message("battle::starters", "factions", zText); - message_faction(b, f, m); - msg_release(m); - } -} - -static void -print_stats(battle * b) -{ - side *s2; - side *s; - int i = 0; - for (s=b->sides;s!=b->sides+b->nsides;++s) { - bfaction *bf; - - ++i; - - for (bf=b->factions;bf;bf=bf->next) { - faction * f = bf->faction; - const char * loc_army = LOC(f->locale, "battle_army"); - char * bufp; - const char * header; - size_t rsize, size; - int komma; - const char * sname = seematrix(f, s) ? sidename(s) : LOC(f->locale, "unknown_faction"); - message * msg; - char buf[1024]; - - message_faction(b, f, msg_separator); - - msg = msg_message("battle_army", "index name", army_index(s), sname); - message_faction(b, f, msg); - msg_release(msg); - - bufp = buf; - size = sizeof(buf); - komma = 0; - header = LOC(f->locale, "battle_opponents"); - - for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { - if (enemy(s2, s)) { - const char * abbrev = seematrix(f, s2)?sideabkz(s2, false):"-?-"; - rsize = slprintf(bufp, size, "%s %s %d(%s)", - komma++ ? "," : (const char*)header, loc_army, army_index(s2), abbrev); - if (rsize>size) rsize = size-1; - size -= rsize; - bufp += rsize; - } - } - if (komma) fbattlerecord(b, f, buf); - - bufp = buf; - size = sizeof(buf); - komma = 0; - header = LOC(f->locale, "battle_helpers"); - - for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { - if (friendly(s2, s)) { - const char * abbrev = seematrix(f, s2)?sideabkz(s2, false):"-?-"; - rsize = slprintf(bufp, size, "%s %s %d(%s)", - komma++ ? "," : (const char*)header, loc_army, army_index(s2), abbrev); - if (rsize>size) rsize = size-1; - size -= rsize; - bufp += rsize; - } - } - if (komma) fbattlerecord(b, f, buf); - - bufp = buf; - size = sizeof(buf); - komma = 0; - header = LOC(f->locale, "battle_attack"); - - for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { - if (s->relations[s2->index] & E_ATTACKING) { - const char * abbrev = seematrix(f, s2)?sideabkz(s2, false):"-?-"; - rsize = slprintf(bufp, size, "%s %s %d(%s)", komma++ ? "," : (const char*)header, loc_army, - army_index(s2), abbrev); - if (rsize>size) rsize = size-1; - size -= rsize; - bufp += rsize; - } - } - if (komma) fbattlerecord(b, f, buf); - } - - if (bdebug && s->faction) { - if (f_get_alliance(s->faction)) { - fprintf(bdebug, "##### %s (%s/%d)\n", s->faction->name, itoa36(s->faction->no), - s->faction->alliance?s->faction->alliance->id:0); - } else { - fprintf(bdebug, "##### %s (%s)\n", s->faction->name, itoa36(s->faction->no)); - } - } - print_fighters(b, s); - } - - message_all(b, msg_separator); - - /* Besten Taktiker ermitteln */ - - b->max_tactics = 0; - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - if (cv_size(&s->leader.fighters)) { - b->max_tactics = MAX(b->max_tactics, s->leader.value); - } - } - - if (b->max_tactics > 0) { - for (s=b->sides;s!=b->sides+b->nsides;++s) { - if (s->leader.value == b->max_tactics) { - fighter *tf; - cv_foreach(tf, s->leader.fighters) { - unit *u = tf->unit; - message * m = NULL; - if (!is_attacker(tf)) { - m = msg_message("battle::tactics_lost", "unit", u); - } else { - m = msg_message("battle::tactics_won", "unit", u); - } - message_all(b, m); - msg_release(m); - } cv_next(tf); - } - } - } -} - -static int -weapon_weight(const weapon * w, boolean missile) -{ - if (missile == i2b(fval(w->type, WTF_MISSILE))) { - return w->attackskill + w->defenseskill; - } - return 0; -} - -fighter * -make_fighter(battle * b, unit * u, side * s1, boolean attack) -{ -#define WMAX 20 - weapon weapons[WMAX]; - int owp[WMAX]; - int dwp[WMAX]; - int w = 0; - region *r = b->region; - item * itm; - fighter *fig = NULL; - int i, tactics = eff_skill(u, SK_TACTICS, r); - side *s2; - int h; - int berserk; - int strongmen; - int speeded = 0, speed = 1; - boolean pr_aid = false; - int rest; - const group * g = NULL; - const attrib *a = a_find(u->attribs, &at_otherfaction); - const faction *stealthfaction = a?get_otherfaction(a):NULL; - unsigned int flags = 0; - - assert(u->number); - if (fval(u, UFL_ANON_FACTION)!=0) flags |= SIDE_STEALTH; - - if (!(AllianceAuto() & HELP_FIGHT) && fval(u, UFL_GROUP)) { - const attrib * agroup = a_find(u->attribs, &at_group); - if (agroup!=NULL) g = (const group*)agroup->data.v; - } - - /* Illusionen und Zauber kaempfen nicht */ - if (fval(u->race, RCF_ILLUSIONARY) || idle(u->faction) || u->number==0) - return NULL; - - if (s1==NULL) { - for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { - if (s2->faction == u->faction && s2->group==g) { -#ifdef SIMPLE_COMBAT - int s1flags = flags|SIDE_HASGUARDS; - int s2flags = s2->flags|SIDE_HASGUARDS; -#else - int s1flags = flags; - int s2flags = s2->flags; -#endif - if (s1flags==s2flags && s2->stealthfaction==stealthfaction) { - s1 = s2; - break; - } - } - } - - /* aliances are moved out of make_fighter and will be handled later */ - if (!s1) { - s1 = make_side(b, u->faction, g, flags, stealthfaction); - } - /* Zu diesem Zeitpunkt ist attacked noch 0, da die Einheit für noch - * keinen Kampf ausgewählt wurde (sonst würde ein fighter existieren) */ - } - fig = calloc(1, sizeof(struct fighter)); - - fig->next = s1->fighters; - s1->fighters = fig; - - fig->unit = u; - /* In einer Burg muß man a) nicht Angreifer sein, und b) drin sein, und - * c) noch Platz finden. d) menschanähnlich sein */ - if (attack) { - set_attacker(fig); - } else { - building * b = u->building; - if (b && b->sizeleft>=u->number && playerrace(u->race)) { - fig->building = b; - fig->building->sizeleft -= u->number; - } - } - fig->status = u->status; - fig->side = s1; - fig->alive = u->number; - fig->side->alive += u->number; - fig->side->battle->alive += u->number; - fig->catmsg = -1; - - /* Freigeben nicht vergessen! */ - fig->person = calloc(fig->alive, sizeof(struct person)); - - h = u->hp / u->number; - assert(h); - rest = u->hp % u->number; - - /* Effekte von Sprüchen */ - - { - static const curse_type * speed_ct; - speed_ct = ct_find("speed"); - if (speed_ct) { - curse *c = get_curse(u->attribs, speed_ct); - if (c) { - speeded = get_cursedmen(u, c); - speed = curse_geteffect_int(c); - } - } - } - - /* Effekte von Alchemie */ - berserk = get_effect(u, oldpotiontype[P_BERSERK]); - /* change_effect wird in ageing gemacht */ - - /* Effekte von Artefakten */ - strongmen = MIN(fig->unit->number, get_item(u, I_TROLLBELT)); - - /* Hitpoints, Attack- und Defence-Boni für alle Personen */ - for (i = 0; i < fig->alive; i++) { - assert(i < fig->unit->number); - fig->person[i].hp = h; - if (i < rest) - fig->person[i].hp++; - - if (i < speeded) - fig->person[i].speed = speed; - else - fig->person[i].speed = 1; - - if (i < berserk) { - fig->person[i].attack++; - } - /* Leute mit einem Aid-Prayer bekommen +1 auf fast alles. */ - if (pr_aid) { - fig->person[i].attack++; - fig->person[i].defence++; - fig->person[i].damage++; - fig->person[i].damage_rear++; - fig->person[i].flags |= FL_COURAGE; - } - /* Leute mit Kraftzauber machen +2 Schaden im Nahkampf. */ - if (i < strongmen) { - fig->person[i].damage += 2; - } - } - - /* Für alle Waffengattungne wird bestimmt, wie viele der Personen mit - * ihr kämpfen könnten, und was ihr Wert darin ist. */ - if (u->race->battle_flags & BF_EQUIPMENT) { - int oi=0, di=0; - for (itm=u->items;itm && w!=WMAX;itm=itm->next) { - const weapon_type * wtype = resource2weapon(itm->type->rtype); - if (wtype==NULL || itm->number==0) continue; - weapons[w].attackskill = weapon_skill(wtype, u, true); - weapons[w].defenseskill = weapon_skill(wtype, u, false); - if (weapons[w].attackskill>=0 || weapons[w].defenseskill>=0) { - weapons[w].type = wtype; - weapons[w].used = 0; - weapons[w].count = itm->number; - ++w; - } - assert(w!=WMAX); - } - fig->weapons = calloc(sizeof(weapon), w+1); - memcpy(fig->weapons, weapons, w*sizeof(weapon)); - - for (i=0; i!=w; ++i) { - int j, o=0, d=0; - for (j=0; j!=i; ++j) { - if (weapon_weight(fig->weapons+j, true)>=weapon_weight(fig->weapons+i, true)) ++d; - if (weapon_weight(fig->weapons+j, false)>=weapon_weight(fig->weapons+i, false)) ++o; - } - for (j=i+1; j!=w; ++j) { - if (weapon_weight(fig->weapons+j, true)>weapon_weight(fig->weapons+i, true)) ++d; - if (weapon_weight(fig->weapons+j, false)>weapon_weight(fig->weapons+i, false)) ++o; - } - owp[o] = i; - dwp[d] = i; - } - /* jetzt enthalten owp und dwp eine absteigend schlechter werdende Liste der Waffen - * oi and di are the current index to the sorted owp/dwp arrays - * owp, dwp contain indices to the figther::weapons array */ - - /* hand out melee weapons: */ - for (i=0; i!=fig->alive; ++i) { - int wpless = weapon_skill(NULL, u, true); - while (oi!=w && (fig->weapons[owp[oi]].used==fig->weapons[owp[oi]].count || fval(fig->weapons[owp[oi]].type, WTF_MISSILE))) { - ++oi; - } - if (oi==w) break; /* no more weapons available */ - if (weapon_weight(fig->weapons+owp[oi], false)<=wpless) { - continue; /* we fight better with bare hands */ - } - fig->person[i].melee = &fig->weapons[owp[oi]]; - ++fig->weapons[owp[oi]].used; - } - /* hand out missile weapons (from back to front, in case of mixed troops). */ - for (di=0, i=fig->alive; i--!=0;) { - while (di!=w && (fig->weapons[dwp[di]].used==fig->weapons[dwp[di]].count || !fval(fig->weapons[dwp[di]].type, WTF_MISSILE))) { - ++di; - } - if (di==w) break; /* no more weapons available */ - if (weapon_weight(fig->weapons+dwp[di], true)>0) { - fig->person[i].missile = &fig->weapons[dwp[di]]; - ++fig->weapons[dwp[di]].used; - } - } - } - - s1->size[statusrow(fig->status)] += u->number; - s1->size[SUM_ROW] += u->number; - if (u->race->battle_flags & BF_NOBLOCK) { - s1->nonblockers[statusrow(fig->status)] += u->number; - } - - if (fig->unit->race->flags & RCF_HORSE) { - fig->horses = fig->unit->number; - fig->elvenhorses = 0; - } else { - static const item_type * it_charger = 0; - if (it_charger==0) { - it_charger = it_find("charger"); - if (!it_charger) { - it_charger = it_find("horse"); - } - } - fig->horses = i_get(u->items, it_charger); - fig->elvenhorses = get_item(u, I_ELVENHORSE); - } - - if (u->race->battle_flags & BF_EQUIPMENT) { - for (itm=u->items; itm; itm=itm->next) { - if (itm->type->rtype->atype) { - if (i_canuse(u, itm->type)) { - struct armor * adata = malloc(sizeof(armor)), **aptr; - adata->atype = itm->type->rtype->atype; - adata->count = itm->number; - for (aptr=&fig->armors;*aptr;aptr=&(*aptr)->next) { - if (adata->atype->prot > (*aptr)->atype->prot) break; - } - adata->next = *aptr; - *aptr = adata; - } - } - } - } - - - /* Jetzt muß noch geschaut werden, wo die Einheit die jeweils besten - * Werte hat, das kommt aber erst irgendwo später. Ich entscheide - * wärend des Kampfes, welche ich nehme, je nach Gegner. Deswegen auch - * keine addierten boni. */ - - /* Zuerst mal die Spezialbehandlung gewisser Sonderfälle. */ - fig->magic = eff_skill(u, SK_MAGIC, r); - - if (fig->horses) { - if (!fval(r->terrain, CAVALRY_REGION) || r_isforest(r) - || eff_skill(u, SK_RIDING, r) < CavalrySkill() || u->race == new_race[RC_TROLL] || fval(u, UFL_WERE)) - fig->horses = 0; - } - - if (fig->elvenhorses) { - if (eff_skill(u, SK_RIDING, r) < 5 || u->race == new_race[RC_TROLL] || fval(u, UFL_WERE)) - fig->elvenhorses = 0; - } - - /* Schauen, wie gut wir in Taktik sind. */ - if (tactics > 0 && u->race == new_race[RC_INSECT]) - tactics -= 1 - (int) log10(fig->side->size[SUM_ROW]); -#ifdef TACTICS_MODIFIER - if (tactics > 0 && statusrow(fig->status) == FIGHT_ROW) - tactics += TACTICS_MODIFIER; - if (tactics > 0 && statusrow(fig->status) > BEHIND_ROW) { - tactics -= TACTICS_MODIFIER; - } -#endif - - if (tactics > 0) { - int bonus = 0; - - for (i = 0; i < fig->alive; i++) { - int p_bonus = 0; - int rnd; - - do { - rnd = rng_int()%100; - if (rnd >= 40 && rnd <= 69) - p_bonus += 1; - else if (rnd <= 89) - p_bonus += 2; - else - p_bonus += 3; - } while(rnd >= 97); - bonus = MAX(p_bonus, bonus); - } - tactics += bonus; - } - - add_tactics(&fig->side->leader, fig, tactics); - ++b->nfighters; - return fig; -} - - -static int -join_battle(battle * b, unit * u, boolean attack, fighter ** cp) -{ - side * s; - fighter *c = NULL; - - if (!attack) { - attrib * a = a_find(u->attribs, &at_fleechance); - if (a!=NULL) { - if (rng_double()<=a->data.flt) { - *cp = NULL; - return false; - } - } - } - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter *fig; - if (s->faction==u->faction) { - for (fig=s->fighters;fig;fig=fig->next) { - if (fig->unit == u) { - c = fig; - if (attack) { - set_attacker(fig); - } - break; - } - } - } - } - if (!c) { - *cp = make_fighter(b, u, NULL, attack); - return *cp!=NULL; - } - *cp = c; - return false; -} - -static const char * -simplename(region * r) -{ - int i; - static char name[17]; - const char * cp = rname(r, default_locale); - for (i=0;*cp && i!=16;++i, ++cp) { - int c = *(unsigned char *)cp; - while (c && !isalpha(c) && !isxspace(c)) { - ++cp; - c = *(unsigned char*)cp; - } - if (isxspace(c)) name[i] = '_'; - else name[i] = *cp; - if (c==0) break; - } - name[i]=0; - return name; -} - -static battle * -make_battle(region * r) -{ - battle *b = calloc(1, sizeof(struct battle)); - unit *u; - bfaction * bf; - static int max_fac_no = 0; /* need this only once */ - - if (battledebug) { - char zText[MAX_PATH]; - char zFilename[MAX_PATH]; - sprintf(zText, "%s/battles", basepath()); - makedir(zText, 0700); - sprintf(zFilename, "%s/battle-%d-%s.log", zText, obs_count, simplename(r)); - bdebug = fopen(zFilename, "w"); - if (!bdebug) log_error(("battles cannot be debugged\n")); - else { - const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; - fwrite(utf8_bom, 1, 3, bdebug); - fprintf(bdebug, "In %s findet ein Kampf stattactics:\n", rname(r, default_locale)); - } - obs_count++; - } - - b->region = r; - b->plane = getplane(r); - /* Finde alle Parteien, die den Kampf beobachten können: */ - for (u = r->units; u; u=u->next) { - if (u->number > 0) { - if (!fval(u->faction, FFL_MARK)) { - fset(u->faction, FFL_MARK); - for (bf=b->factions;bf;bf=bf->next) { - if (bf->faction==u->faction) break; - } - if (!bf) { - bf = calloc(sizeof(bfaction), 1); - ++b->nfactions; - bf->faction = u->faction; - bf->next = b->factions; - b->factions = bf; - } - } - } - } - - for (bf=b->factions;bf;bf=bf->next) { - faction * f = bf->faction; - max_fac_no = MAX(max_fac_no, f->no); - freset(f, FFL_MARK); - } - return b; -} - -static void -free_side(side * si) -{ - cv_kill(&si->leader.fighters); -} - -static void -free_fighter(fighter * fig) -{ - while (fig->loot) { - i_free(i_remove(&fig->loot, fig->loot)); - } - while (fig->armors) { - armor * a = fig->armors; - fig->armors = a->next; - free(a); - } - free(fig->person); - free(fig->weapons); - -} - -static void -free_battle(battle * b) -{ - side *s; - meffect *meffect; - int max_fac_no = 0; - - if (bdebug) { - fclose(bdebug); - } - - while (b->factions) { - bfaction * bf = b->factions; - faction * f = bf->faction; - b->factions = bf->next; - max_fac_no = MAX(max_fac_no, f->no); - free(bf); - } - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter *fnext = s->fighters; - while (fnext) { - fighter *fig = fnext; - fnext = fig->next; - free_fighter(fig); - free(fig); - } - free_side(s); - } - cv_kill(&b->leaders); - cv_foreach(meffect, b->meffects) { - free(meffect); - } - cv_next(meffect); - cv_kill(&b->meffects); -} - -static int * -get_alive(side * s) -{ -#if 0 - static int alive[NUMROWS]; - fighter *fig; - memset(alive, 0, NUMROWS * sizeof(int)); - for (fig=s->fighters;fig;fig=fig->next) { - if (fig->alive>0) { - int row = statusrow(fig); - alive[row] += fig->alive; - } - } - return alive; -#endif - return s->size; -} - -static int -battle_report(battle * b) -{ - side *s, *s2; - boolean cont = false; - boolean komma; - bfaction *bf; - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - if (s->alive-s->removed > 0) { - for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { - if (s2->alive-s2->removed > 0 && enemy(s, s2)) { - cont = true; - break; - } - } - if (cont) break; - } - } - - if (verbosity>0) log_stdio(stdout, " %d", b->turn); - fflush(stdout); - - for (bf=b->factions;bf;bf=bf->next) { - faction * fac = bf->faction; - char buf[32*MAXSIDES]; - char * bufp = buf; - int bytes; - size_t size = sizeof(buf) - 1; - message * m; - - message_faction(b, fac, msg_separator); - - if (cont) m = msg_message("battle::lineup", "turn", b->turn); - else m = msg_message("battle::after", ""); - message_faction(b, fac, m); - msg_release(m); - - komma = false; - for (s=b->sides;s!=b->sides+b->nsides;++s) { - if (s->alive) { - int r, k = 0, * alive = get_alive(s); - int l = FIGHT_ROW; - const char * abbrev = seematrix(fac, s)?sideabkz(s, false):"-?-"; - const char * loc_army = LOC(fac->locale, "battle_army"); - char buffer[32]; - - if (komma) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - snprintf(buffer, sizeof(buffer), "%s %2d(%s): ", - loc_army, army_index(s), abbrev); - buffer[sizeof(buffer)-1] = 0; - - bytes = (int)strlcpy(bufp, buffer, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - for (r=FIGHT_ROW;r!=NUMROWS;++r) { - if (alive[r]) { - if (l!=FIGHT_ROW) { - bytes = (int)strlcpy(bufp, "+", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - while (k--) { - bytes = (int)strlcpy(bufp, "0+", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - sprintf(buffer, "%d", alive[r]); - - bytes = (int)strlcpy(bufp, buffer, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - k = 0; - l = r+1; - } else ++k; - } - - komma = true; - } - } - *bufp = 0; - fbattlerecord(b, fac, buf); - } - return cont; -} - -static void -join_allies(battle * b) -{ - region *r = b->region; - unit *u; - side *s, *s_end = b->sides+b->nsides; - /* make_side might be adding a new faction, but it adds them to the end - * of the list, so we're safe in our iteration here if we remember the end - * up front. */ - for (u=r->units;u;u=u->next) { - /* Was ist mit Schiffen? */ - if (u->status != ST_FLEE && u->status != ST_AVOID && !fval(u, UFL_LONGACTION|UFL_ISNEW) && u->number > 0) { - faction * f = u->faction; - fighter * c = NULL; - - for (s=b->sides;s!=s_end;++s) { - side * se; - /* Wenn alle attackierten noch FFL_NOAID haben, dann kämpfe nicht mit. */ - if (fval(s->faction, FFL_NOAID)) continue; - if (s->faction!=f) { - /* Wenn wir attackiert haben, kommt niemand mehr hinzu: */ - if (s->bf->attacker) continue; - /* alliiert müssen wir schon sein, sonst ist's eh egal : */ - if (!alliedunit(u, s->faction, HELP_FIGHT)) continue; - /* wenn die partei verborgen ist, oder gar eine andere - * vorgespiegelt wird, und er sich uns gegenüber nicht zu - * erkennen gibt, helfen wir ihm nicht */ - if (s->stealthfaction){ - if(!allysfm(s, u->faction, HELP_FSTEALTH)) { - continue; - } - } - } - /* einen alliierten angreifen dürfen sie nicht, es sei denn, der - * ist mit einem alliierten verfeindet, der nicht attackiert - * hat: */ - for (se=b->sides;se!=s_end;++se) { - if (u->faction==se->faction) continue; - if (alliedunit(u, se->faction, HELP_FIGHT) && !se->bf->attacker) { - continue; - } - if (enemy(s, se)) break; - } - if (se==s_end) continue; - /* Wenn die Einheit belagert ist, muß auch einer der Alliierten belagert sein: */ - if (besieged(u)) { - fighter *ally; - for (ally = s->fighters; ally; ally=ally->next) { - if (besieged(ally->unit)) { - break; - } - } - if (ally==NULL) continue; - } - /* keine Einwände, also soll er mitmachen: */ - if (c==NULL) { - if (join_battle(b, u, false, &c)) { - if (battledebug) { - fprintf(bdebug, "%s joins to help %s against %s.\n", - unitname(u), factionname(s->faction), - factionname(se->faction)); - } - } else if (c==NULL) { - continue; - } - } - - /* the enemy of my friend is my enemy: */ - for (se=b->sides;se!=s_end;++se) { - if (se->faction!=u->faction && enemy(s, se)) { - if (set_enemy(se, c->side, false) && battledebug) { - fprintf(bdebug, "%u/%s hates %u/%s because they are enemies with %u/%s.\n", - c->side->index, sidename(c->side), - se->index, sidename(se), - s->index, sidename(s)); - } - } - } - } - } - } - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - int si; - side * sa; - faction * f = s->faction; - - /* Den Feinden meiner Feinde gebe ich Deckung (gegen gemeinsame Feinde): */ - for (si=0; s->enemies[si]; ++si) { - side * se = s->enemies[si]; - int ai; - for (ai=0; se->enemies[ai]; ++ai) { - side * as = se->enemies[ai]; - if (as==s || !enemy(as, s)) { - set_friendly(as, s); - } - } - } - - for (sa=s+1;sa!=b->sides+b->nsides;++sa) { - plane * pl = rplane(r); - if (enemy(s, sa)) continue; - if (friendly(s, sa)) continue; - if (!alliedgroup(pl, f, sa->faction, f->allies, HELP_FIGHT)) continue; - if (!alliedgroup(pl, sa->faction, f, sa->faction->allies, HELP_FIGHT)) continue; - - set_friendly(s, sa); - } - } -} - -static void -flee(const troop dt) -{ - fighter * fig = dt.fighter; - unit * u = fig->unit; - -#ifndef SIMPLE_ESCAPE - int carry = personcapacity(u) - u->race->weight; - int money; - - item ** ip = &u->items; - - while (*ip) { - item * itm = *ip; - const item_type * itype = itm->type; - int keep = 0; - - if (fval(itype, ITF_ANIMAL)) { - /* Regeländerung: Man muß das Tier nicht reiten können, - * um es vom Schlachtfeld mitzunehmen, ist ja nur - * eine Region weit. * */ - keep = MIN(1, itm->number); - /* da ist das weight des tiers mit drin */ - carry += itype->capacity - itype->weight; - } else if (itm->type->weight <= 0) { - /* if it doesn'tactics weigh anything, it won'tactics slow us down */ - keep = itm->number; - } - /* jeder troop nimmt seinen eigenen Teil der Sachen mit */ - if (keep>0){ - if (itm->number==keep) { - i_add(&fig->run.items, i_remove(ip, itm)); - } else { - item *run_itm = i_new(itype, keep); - i_add(&fig->run.items, run_itm); - i_change(ip, itype, -keep); - } - } - if (*ip==itm) ip = &itm->next; - } - - /* we will take money with us */ - money = get_money(u); - /* nur ganzgeflohene/resttote Einheiten verlassen die Region */ - if (money > carry) money = carry; - if (money > 0) { - i_change(&u->items, i_silver, -money); - i_change(&fig->run.items, i_silver, +money); - } -#endif /* SIMPLE_ESCAPE */ - - fig->run.hp += fig->person[dt.index].hp; - ++fig->run.number; - - setguard(u, GUARD_NONE); - - kill_troop(dt); -} - -static boolean -init_battle(region * r, battle **bp) -{ - battle * b = NULL; - unit * u; - boolean fighting = false; - - /* list_foreach geht nicht, wegen flucht */ - for (u = r->units; u != NULL; u = u->next) { - if (fval(u, UFL_LONGACTION)) continue; - if (u->number > 0) { - order * ord; - - for (ord=u->orders;ord;ord=ord->next) { - static boolean init = false; - static const curse_type * peace_ct, * slave_ct, * calm_ct; - - if (!init) { - init = true; - peace_ct = ct_find("peacezone"); - slave_ct = ct_find("slavery"); - calm_ct = ct_find("calmmonster"); - } - if (get_keyword(ord) == K_ATTACK) { - unit *u2; - fighter *c1, *c2; - ship * lsh = NULL; - plane * pl = rplane(r); - - if (pl && fval(pl, PFL_NOATTACK)) { - cmistake(u, ord, 271, MSG_BATTLE); - continue; - } - - if ((u->race->battle_flags&BF_CANATTACK) == 0) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_no_attack", "race", u->race)); - continue; - } - /** - ** Fehlerbehandlung Angreifer - **/ - if (LongHunger(u)) { - cmistake(u, ord, 225, MSG_BATTLE); - continue; - } - - if (u->status == ST_AVOID || u->status == ST_FLEE) { - cmistake(u, ord, 226, MSG_BATTLE); - continue; - } - - /* ist ein Flüchtling aus einem andern Kampf */ - if (fval(u, UFL_LONGACTION)) continue; - - if (peace_ct && curse_active(get_curse(r->attribs, peace_ct))) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "peace_active", "")); - continue; - } - - if (slave_ct && curse_active(get_curse(u->attribs, slave_ct))) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "slave_active", "")); - continue; - } - - if ((u->ship != NULL && !fval(r->terrain, SEA_REGION)) || (lsh = leftship(u))!=NULL) { - if (is_guarded(r, u, GUARD_TRAVELTHRU)) { - if (lsh) { - cmistake(u, ord, 234, MSG_BATTLE); - } else { - /* Fehler: "Das Schiff muß erst verlassen werden" */ - cmistake(u, ord, 19, MSG_BATTLE); - } - continue; - } - } - - /* Ende Fehlerbehandlung Angreifer */ - - init_tokens(ord); - skip_token(); - /* attackierte Einheit ermitteln */ - u2 = getunit(r, u->faction); - - /* Beginn Fehlerbehandlung */ - /* Fehler: "Die Einheit wurde nicht gefunden" */ - if (!u2 || u2->number == 0 || !cansee(u->faction, u->region, u2, 0)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - continue; - } - /* Fehler: "Die Einheit ist eine der unsrigen" */ - if (u2->faction == u->faction) { - cmistake(u, ord, 45, MSG_BATTLE); - continue; - } - /* Fehler: "Die Einheit ist mit uns alliert" */ - if (alliedunit(u, u2->faction, HELP_FIGHT)) { - cmistake(u, ord, 47, MSG_BATTLE); - continue; - } - if (IsImmune(u2->faction)) { - add_message(&u->faction->msgs, - msg_feedback(u, u->thisorder, "newbie_immunity_error", "turns", NewbieImmunity())); - continue; - } - /* Fehler: "Die Einheit ist mit uns alliert" */ - - if (calm_ct) { - attrib * a = a_find(u->attribs, &at_curse); - boolean calm = false; - while (a && a->type==&at_curse) { - curse * c = (curse *)a->data.v; - if (c->type==calm_ct && curse_geteffect(c)==u2->faction->subscription) { - if (curse_active(c)) { - calm = true; - break; - } - } - a = a->next; - } - if (calm) { - cmistake(u, ord, 47, MSG_BATTLE); - continue; - } - } - /* Ende Fehlerbehandlung */ - if (b==NULL) { - unit * utmp; - for (utmp=r->units; utmp!=NULL; utmp=utmp->next) { - fset(utmp->faction, FFL_NOAID); - } - b = make_battle(r); - } - if (join_battle(b, u, true, &c1)) { - if (battledebug) { - fprintf(bdebug, "%s joins by attacking %s.\n", - unitname(u), unitname(u2)); - } - } - if (join_battle(b, u2, false, &c2)) { - if (battledebug) { - fprintf(bdebug, "%s joins because of an attack from %s.\n", - unitname(u2), unitname(u)); - } - } - - /* Hat die attackierte Einheit keinen Noaid-Status, - * wird das Flag von der Faction genommen, andere - * Einheiten greifen ein. */ - if (!fval(u2, UFL_NOAID)) freset(u2->faction, FFL_NOAID); - - if (c1!=NULL && c2!=NULL) { - /* Merken, wer Angreifer ist, für die Rückzahlung der - * Präcombataura bei kurzem Kampf. */ - c1->side->bf->attacker = true; - - if (set_enemy(c1->side, c2->side, true) && battledebug) { - fprintf(bdebug, "%u/%s hates %u/%s because they attacked them.\n", - c2->side->index, sidename(c2->side), - c1->side->index, sidename(c1->side)); - } - fighting = true; - } - } - } - } - } - *bp = b; - return fighting; -} - -static void -battle_stats(FILE * F, battle * b) -{ - typedef struct stat_info { - struct stat_info * next; - const weapon_type * wtype; - int level; - int number; - } stat_info; - side * s; - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter * df; - stat_info * stats = NULL, * stat; - - for (df = s->fighters; df; df = df->next) { - unit *du = df->unit; - troop dt; - stat_info * slast = NULL; - - dt.fighter = df; - for (dt.index=0;dt.index!=du->number;++dt.index) { - weapon * wp = preferred_weapon(dt, true); - int level = wp?wp->attackskill:0; - const weapon_type * wtype = wp?wp->type:NULL; - stat_info ** slist = &stats; - - if (slast && slast->wtype==wtype && slast->level==level) { - ++slast->number; - continue; - } - while (*slist && (*slist)->wtype!=wtype) { - slist = &(*slist)->next; - } - while (*slist && (*slist)->wtype==wtype && (*slist)->level>level) { - slist = &(*slist)->next; - } - stat = *slist; - if (stat==NULL || stat->wtype!=wtype || stat->level!=level) { - stat = calloc(1, sizeof(stat_info)); - stat->wtype = wtype; - stat->level = level; - stat->next = *slist; - *slist = stat; - } - slast = stat; - ++slast->number; - } - } - - fprintf(F, "##STATS## Heer %u - %s:\n", army_index(s), factionname(s->faction)); - for (stat=stats;stat!=NULL;stat=stat->next) { - fprintf(F, "%s %u : %u\n", stat->wtype?stat->wtype->itype->rtype->_name[0]:"none", stat->level, stat->number); - } - freelist(stats); - } -} - -/** execute one round of attacks - * fig->fighting is used to determine who attacks, not fig->alive, since - * the latter may be influenced by attacks that already took place. - */ -static void -battle_attacks(battle * b) -{ - side * s; - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter *fig; - - if (b->turn!=0 || (b->max_tactics > 0 && get_tactics(s, NULL) == b->max_tactics)) { - for (fig=s->fighters;fig;fig=fig->next) { - - /* ist in dieser Einheit noch jemand handlungsfähig? */ - if (fig->fighting <= 0) continue; - - /* Handle the unit's attack on someone */ - do_attack(fig); - } - } - } -} - -/** updates the number of attacking troops in each fighter struct. - * this has to be calculated _before_ the actual attacks take - * place because otherwise dead troops would not strike in the - * round they die. */ -static void -battle_update(battle * b) -{ - side * s; - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter *fig; - for (fig=s->fighters;fig;fig=fig->next) { - fig->fighting = fig->alive - fig->removed; - } - } -} - -/** attempt to flee from battle before the next round begins - * there's a double attempt before the first round, but only - * one attempt before round zero, the potential tactics round. */ -static void -battle_flee(battle * b) -{ - int attempt, flee_ops = 1; - - if (b->turn==1) - flee_ops = 2; - - for (attempt=1;attempt<=flee_ops;++attempt) { - side * s; - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter *fig; - for (fig=s->fighters;fig;fig=fig->next) { - unit *u = fig->unit; - troop dt; - int runners = 0; - /* Flucht nicht bei mehr als 600 HP. Damit Wyrme tötbar bleiben. */ - int runhp = MIN(600,(int)(0.9+unit_max_hp(u)*hpflee(u->status))); - - if (u->ship && fval(u->region->terrain, SEA_REGION)) { - /* keine Flucht von Schiffen auf hoher See */ - continue; - } - if (fval(u->race, RCF_UNDEAD) || u->race == new_race[RC_SHADOWKNIGHT]) { - /* Untote fliehen nicht. Warum eigentlich? */ - continue; - } - - dt.fighter = fig; -#ifndef SIMPLE_ESCAPE - if (!fig->run.region) fig->run.region = fleeregion(u); - if (!fig->run.region) continue; -#endif /* SIMPLE_ESCAPE */ - dt.index = fig->alive - fig->removed; - while (s->size[SUM_ROW] && dt.index != 0) { - double ispaniced = 0.0; - --dt.index; - assert(dt.index>=0 && dt.indexunit->number); - assert(fig->person[dt.index].hp > 0); - - /* Versuche zu fliehen, wenn - * - Kampfstatus fliehe - * - schwer verwundet und nicht erste kampfrunde - * - in panik (Zauber) - * aber nicht, wenn der Zaubereffekt Held auf dir liegt! - */ - switch (u->status) { - case ST_FLEE: - break; - default: - if ((fig->person[dt.index].flags & FL_HIT) == 0) continue; - if (b->turn<=1) continue; - if (fig->person[dt.index].hp <= runhp) break; - if (fig->person[dt.index].flags & FL_PANICED) { - if ((fig->person[dt.index].flags & FL_COURAGE)==0) break; - } - continue; - } - - if (fig->person[dt.index].flags & FL_PANICED) { - ispaniced = EFFECT_PANIC_SPELL; - } - if (chance(MIN(fleechance(u)+ispaniced, 0.90))) { - ++runners; - flee(dt); - } - } - if (bdebug && runners > 0) { - fprintf(bdebug, "Fleeing: %d from %s\n", runners, itoa36(fig->unit->no)); - } - } - } - } -} - -void -do_battle(region * r) -{ - battle *b = NULL; - boolean fighting = false; - ship * sh; - building *bu; - static int init_rules = 0; - - if (!init_rules) { - static_rules(); - init_rules = 1; - } - if (msg_separator==NULL) { - msg_separator = msg_message("battle::section", ""); - } - - fighting = init_battle(r, &b); - - if (b==NULL) return; - - /* Bevor wir die alliierten hineinziehen, sollten wir schauen, * - * Ob jemand fliehen kann. Dann erübrigt sich das ganze ja - * vielleicht schon. */ - print_header(b); - if (!fighting) { - /* Niemand mehr da, Kampf kann nicht stattfinden. */ - message * m = msg_message("battle::aborted", ""); - message_all(b, m); - msg_release(m); - free_battle(b); - free(b); - return; - } - join_allies(b); - make_heroes(b); - - /* Alle Mann raus aus der Burg! */ - for (bu=r->buildings; bu!=NULL; bu=bu->next) bu->sizeleft = bu->size; - - /* make sure no ships are damaged initially */ - for (sh=r->ships; sh; sh=sh->next) freset(sh, SF_DAMAGED); - - /* Gibt es eine Taktikrunde ? */ - if (cv_size(&b->leaders)) { - b->turn = 0; - b->has_tactics_turn = true; - } else { - b->turn = 1; - b->has_tactics_turn = false; - } - - if (b->region->flags & RF_COMBATDEBUG) battle_stats(bdebug, b); - - /* PRECOMBATSPELLS */ - do_combatmagic(b, DO_PRECOMBATSPELL); - - print_stats(b); /* gibt die Kampfaufstellung aus */ - if (verbosity>0) log_stdio(stdout, "%s (%d, %d) : ", rname(r, default_locale), r->x, r->y); - - for (;battle_report(b) && b->turn<=max_turns;++b->turn) { - if (bdebug) { - fprintf(bdebug, "*** Turn: %d\n", b->turn); - } - battle_flee(b); - battle_update(b); - battle_attacks(b); - - } - - if (verbosity>0) log_stdio(stdout, "\n"); - - /* Auswirkungen berechnen: */ - aftermath(b); - /* Hier ist das Gefecht beendet, und wir können die - * Hilfsstrukturen * wieder löschen: */ - - if (b) { - free_battle(b); - free(b); - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#pragma region includes + +#include +#include +#include "battle.h" + +#include "alchemy.h" +#include "alliance.h" +#include "build.h" +#include "building.h" +#include "curse.h" +#include "equipment.h" +#include "faction.h" +#include "group.h" +#include "item.h" +#include "magic.h" +#include "message.h" +#include "move.h" +#include "names.h" +#include "order.h" +#include "plane.h" +#include "race.h" +#include "region.h" +#include "reports.h" +#include "ship.h" +#include "skill.h" +#include "terrain.h" +#include "unit.h" + +/* attributes includes */ +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include + +#pragma endregion + +static FILE *bdebug; + +#define TACTICS_BONUS 1 /* when undefined, we have a tactics round. else this is the bonus tactics give */ +#define TACTICS_MODIFIER 1 /* modifier for generals in the fromt/rear */ + +#define CATAPULT_INITIAL_RELOAD 4 /* erster schuss in runde 1 + rng_int() % INITIAL */ +#define CATAPULT_STRUCTURAL_DAMAGE + +#define BASE_CHANCE 70 /* 70% Basis-Überlebenschance */ +#ifdef NEW_COMBATSKILLS_RULE +#define TDIFF_CHANGE 5 /* 5% höher pro Stufe */ +#define DAMAGE_QUOTIENT 2 /* damage += skilldiff/DAMAGE_QUOTIENT */ +#else +#define TDIFF_CHANGE 10 +# define DAMAGE_QUOTIENT 1 /* damage += skilldiff/DAMAGE_QUOTIENT */ +#endif + +#undef DEBUG_FAST /* should be disabled when b->fast and b->rowcache works */ +#define DEBUG_SELECT /* should be disabled if select_enemy works */ + +typedef enum combatmagic { + DO_PRECOMBATSPELL, + DO_POSTCOMBATSPELL +} combatmagic_t; + +/* globals */ +static int obs_count = 0; + +#define MINSPELLRANGE 1 +#define MAXSPELLRANGE 7 + +#ifndef ROW_FACTOR +# define ROW_FACTOR 10 +#endif +static const double EFFECT_PANIC_SPELL = 0.25; +static const double TROLL_REGENERATION = 0.10; + +/* Nach dem alten System: */ +static int missile_range[2] = {FIGHT_ROW, BEHIND_ROW}; +static int melee_range[2] = {FIGHT_ROW, FIGHT_ROW}; +static message * msg_separator; + +const troop no_troop = {0, 0}; + +static int max_turns = 0; +static int damage_rules = 0; +static int loot_rules = 0; +static int skill_formula = 0; + +#define FORMULA_ORIG 0 +#define FORMULA_NEW 1 + +#define LOOT_MONSTERS (1<<0) +#define LOOT_SELF (1<<1) /* code is mutually exclusive with LOOT_OTHERS */ +#define LOOT_OTHERS (1<<2) +#define LOOT_KEEPLOOT (1<<4) + +#define DAMAGE_CRITICAL (1<<0) +#define DAMAGE_MELEE_BONUS (1<<1) +#define DAMAGE_MISSILE_BONUS (1<<2) +#define DAMAGE_UNARMED_BONUS (1<<3) +#define DAMAGE_SKILL_BONUS (1<<4) +/** initialize rules from configuration. + */ +static void +static_rules(void) +{ + loot_rules = get_param_int(global.parameters, "rules.combat.loot", LOOT_MONSTERS|LOOT_OTHERS|LOOT_KEEPLOOT); + /* new formula to calculate to-hit-chance */ + skill_formula = get_param_int(global.parameters, "rules.combat.skill_formula", FORMULA_ORIG); + /* maximum number of combat turns */ + max_turns = get_param_int(global.parameters, "rules.combat.turns", COMBAT_TURNS); + /* damage calculation */ + if (get_param_int(global.parameters, "rules.combat.critical", 1)) { + damage_rules |= DAMAGE_CRITICAL; + } + if (get_param_int(global.parameters, "rules.combat.melee_bonus", 1)) { + damage_rules |= DAMAGE_MELEE_BONUS; + } + if (get_param_int(global.parameters, "rules.combat.missile_bonus", 1)) { + damage_rules |= DAMAGE_MISSILE_BONUS; + } + if (get_param_int(global.parameters, "rules.combat.unarmed_bonus", 1)) { + damage_rules |= DAMAGE_UNARMED_BONUS; + } + if (get_param_int(global.parameters, "rules.combat.skill_bonus", 1)) { + damage_rules |= DAMAGE_SKILL_BONUS; + } +} + +static int +army_index(side * s) +{ + return s->index; +} + +#ifndef SIMPLE_ESCAPE +region * +fleeregion(const unit * u) +{ + region *r = u->region; + region *neighbours[MAXDIRECTIONS]; + int c = 0; + direction_t i; + + if (u->ship && !fval(r->terrain, SEA_REGION)) + return NULL; + + if (u->ship && + !(u->race->flags & RCF_SWIM) && + !(u->race->flags & RCF_FLY)) { + return NULL; + } + + for (i = 0; i != MAXDIRECTIONS; ++i) { + region * r2 = rconnect(r, i); + if (r2) { + if (can_survive(u,r2) && !move_blocked(u, r, r2)) + neighbours[c++] = r2; + } + } + + if (!c) + return NULL; + return neighbours[rng_int() % c]; +} +#endif /* SIMPLE_ESCAPE */ + +static char * +sidename(side * s) +{ +#define SIDENAMEBUFLEN 256 + static int bufno; /* STATIC_XCALL: used across calls */ + static char sidename_buf[4][SIDENAMEBUFLEN]; /* STATIC_RESULT: used for return, not across calls */ + + bufno = bufno % 4; + if (s->stealthfaction) { + snprintf(sidename_buf[bufno], SIDENAMEBUFLEN, + "%s", factionname(s->stealthfaction)); + } else { + snprintf(sidename_buf[bufno], SIDENAMEBUFLEN, + "%s", factionname(s->faction)); + } + return sidename_buf[bufno++]; +} + +static const char * +sideabkz(side *s, boolean truename) +{ + static char sideabkz_buf[8]; /* STATIC_RESULT: used for return, not across calls */ + const faction * f = (s->stealthfaction && !truename)?s->stealthfaction:s->faction; + +#undef SIDE_ABKZ +#ifdef SIDE_ABKZ + abkz(f->name, sideabkz_buf, sizeof(sideabkz_buf), 3); +#else + strcpy(sideabkz_buf, itoa36(f->no)); +#endif + return sideabkz_buf; +} + +static void +message_faction(battle * b, faction * f, struct message * m) +{ + region * r = b->region; + + if (f->battles==NULL || f->battles->r!=r) { + struct bmsg * bm = calloc(1, sizeof(struct bmsg)); + bm->next = f->battles; + f->battles = bm; + bm->r = r; + } + add_message(&f->battles->msgs, m); +} + +int +armedmen(const unit * u, boolean siege_weapons) +{ + item * itm; + int n = 0; + if (!(urace(u)->flags & RCF_NOWEAPONS)) { + if (effskill(u, SK_WEAPONLESS)>=1) { + /* kann ohne waffen bewachen: fuer drachen */ + n = u->number; + } else { + /* alle Waffen werden gezaehlt, und dann wird auf die Anzahl + * Personen minimiert */ + for (itm=u->items;itm;itm=itm->next) { + const weapon_type * wtype = resource2weapon(itm->type->rtype); + if (wtype==NULL || (!siege_weapons && (wtype->flags & WTF_SIEGE))) continue; + if (effskill(u, wtype->skill) >= 1) n += itm->number; + /* if (effskill(u, wtype->skill) >= wtype->minskill) n += itm->number; */ + if (n>u->number) break; + } + n = MIN(n, u->number); + } + } + return n; +} + +void +message_all(battle * b, message * m) +{ + bfaction * bf; + plane * p = rplane(b->region); + watcher * w; + + for (bf = b->factions;bf;bf=bf->next) { + message_faction(b, bf->faction, m); + } + if (p) for (w=p->watchers;w;w=w->next) { + for (bf = b->factions;bf;bf=bf->next) if (bf->faction==w->faction) break; + if (bf==NULL) message_faction(b, w->faction, m); + } +} + +static void +fbattlerecord(battle * b, faction * f, const char *s) +{ + message * m = msg_message("battle_msg", "string", s); + message_faction(b, f, m); + msg_release(m); +} + +/* being an enemy or a friend is (and must always be!) symmetrical */ +#define enemy_i(as, di) (as->relations[di]&E_ENEMY) +#define friendly_i(as, di) (as->relations[di]&E_FRIEND) +#define enemy(as, ds) (as->relations[ds->index]&E_ENEMY) +#define friendly(as, ds) (as->relations[ds->index]&E_FRIEND) + +static boolean +set_enemy(side * as, side * ds, boolean attacking) +{ + int i; + for (i=0;i!=MAXSIDES;++i) { + if (ds->enemies[i]==NULL) ds->enemies[i]=as; + if (ds->enemies[i]==as) break; + } + for (i=0;i!=MAXSIDES;++i) { + if (as->enemies[i]==NULL) as->enemies[i]=ds; + if (as->enemies[i]==ds) break; + } + assert(i!=MAXSIDES); + if (attacking) as->relations[ds->index] |= E_ATTACKING; + if ((ds->relations[as->index] & E_ENEMY)==0) { + /* enemy-relation are always symmetrical */ + assert((as->relations[ds->index] & (E_ENEMY|E_FRIEND))==0); + ds->relations[as->index] |= E_ENEMY; + as->relations[ds->index] |= E_ENEMY; + return true; + } + return false; +} + +static void +set_friendly(side * as, side * ds) +{ + assert((as->relations[ds->index] & E_ENEMY)==0); + ds->relations[as->index] |= E_FRIEND; + as->relations[ds->index] |= E_FRIEND; +} + +static int +allysfm(const side * s, const faction * f, int mode) +{ + if (s->faction==f) return mode; + if (s->group) { + return alliedgroup(s->battle->plane, s->faction, f, s->group->allies, mode); + } + return alliedfaction(s->battle->plane, s->faction, f, mode); +} + +static int +allysf(const side * s, const faction * f) +{ + return allysfm(s, f, HELP_FIGHT); +} + +static int +dead_fighters(const fighter * df) +{ + return df->unit->number - df->alive - df->run.number; +} + +fighter * +select_corpse(battle * b, fighter * af) +/* Wählt eine Leiche aus, der af hilft. casualties ist die Anzahl der + * Toten auf allen Seiten (im Array). Wenn af == NULL, wird die + * Parteizugehörigkeit ignoriert, und irgendeine Leiche genommen. + * + * Untote werden nicht ausgewählt (casualties, not dead) */ +{ + int si, di, maxcasualties = 0; + fighter *df; + side *s; + + for (si=0;si!=b->nsides;++si) { + side * s = b->sides+si; + if (af==NULL || (!enemy_i(af->side, si) && allysf(af->side, s->faction))) { + maxcasualties += s->casualties; + } + } + di = rng_int() % maxcasualties; + for (s=b->sides;s!=b->sides+b->nsides;++s) { + for (df=s->fighters;df;df=df->next) { + /* Geflohene haben auch 0 hp, dürfen hier aber nicht ausgewählt + * werden! */ + int dead = dead_fighters(df); + if (!playerrace(df->unit->race)) continue; + + if (af && !helping(af->side, df->side)) + continue; + if (di < dead) { + return df; + } + di -= dead; + } + } + + return NULL; +} + +boolean +helping(const side * as, const side * ds) +{ + if (as->faction==ds->faction) return true; + return (boolean)(!enemy(as, ds) && allysf(as, ds->faction)); +} + +int +statusrow(int status) +{ + switch (status) { + case ST_AGGRO: + case ST_FIGHT: + return FIGHT_ROW; + case ST_BEHIND: + case ST_CHICKEN: + return BEHIND_ROW; + case ST_AVOID: + return AVOID_ROW; + case ST_FLEE: + return FLEE_ROW; + default: + assert(!"unknown combatrow"); + } + return FIGHT_ROW; +} + +static double +hpflee(int status) + /* if hp drop below this percentage, run away */ +{ + switch (status) { + case ST_AGGRO: + return 0.0; + case ST_FIGHT: + case ST_BEHIND: + return 0.2; + case ST_CHICKEN: + case ST_AVOID: + return 0.9; + case ST_FLEE: + return 1.0; + default: + assert(!"unknown combatrow"); + } + return 0.0; +} + +static int +get_row(const side * s, int row, const side * vs) +{ + boolean counted[MAXSIDES]; + int enemyfront = 0; + int line, result; + int retreat = 0; + int size[NUMROWS]; + int front = 0; + battle * b = s->battle; + + memset(counted, 0, sizeof(counted)); + memset(size, 0, sizeof(size)); + for (line=FIRST_ROW;line!=NUMROWS;++line) { + int si, sa_i; + /* how many enemies are there in the first row? */ + for (si=0;s->enemies[si];++si) { + side *se = s->enemies[si]; + if (se->size[line]>0) { + enemyfront += se->size[line]; + /* - s->nonblockers[line] (nicht, weil angreifer) */ + } + } + for (sa_i=0; sa_i!=b->nsides; ++sa_i) { + side * sa = b->sides+sa_i; + /* count people that like me, but don't like my enemy */ + if (friendly_i(s, sa_i) && enemy_i(vs, sa_i)) { + if (!counted[sa_i]) { + int i; + + for (i=0;i!=NUMROWS;++i) { + size[i] += sa->size[i] - sa->nonblockers[i]; + } + counted[sa_i] = true; + } + } + } + if (enemyfront) break; + } + if (enemyfront) { + for (line=FIRST_ROW;line!=NUMROWS;++line) { + front += size[line]; + if (!front || frontstatus); + if (vs==NULL) { + int i; + for (i=FIGHT_ROW;i!=row;++i) if (af->side->size[i]) break; + return FIGHT_ROW+(row-i); + } else { +#ifdef FASTROW + battle * b = vs->battle; + if (row!=b->rowcache.row || b->alive!=b->rowcache.alive || af->side!=b->rowcache.as || vs!=b->rowcache.vs) { + b->rowcache.alive = b->alive; + b->rowcache.as = af->side; + b->rowcache.vs = vs; + b->rowcache.row = row; + b->rowcache.result = get_row(af->side, row, vs); + return b->rowcache.result; + } +#ifdef DEBUG_FAST /* validation code */ + { + int i = get_row(af->side, row, vs); + assert(i==b->rowcache.result); + } +#endif + return b->rowcache.result; +#else + return get_row(af->side, row, vs); +#endif + } +} + +static void +reportcasualties(battle * b, fighter * fig, int dead) +{ + struct message * m; + region * r = NULL; + if (fig->alive == fig->unit->number) return; +#ifndef SIMPLE_ESCAPE + if (fig->run.region == NULL) { + fig->run.region = fleeregion(fig->unit); + if (fig->run.region == NULL) fig->run.region = b->region; + } + r = fig->run.region; +#endif /* SIMPLE_ESCAPE */ + m = msg_message("casualties", "unit runto run alive fallen", + fig->unit, r, fig->run.number, fig->alive, dead); + message_all(b, m); + msg_release(m); +} + +static int +contest_classic(int skilldiff, const armor_type * ar, const armor_type * sh) +{ + int p, vw = BASE_CHANCE - TDIFF_CHANGE * skilldiff; + double mod = 1.0; + + if (ar != NULL) + mod *= (1 + ar->penalty); + if (sh != NULL) + mod *= (1 + sh->penalty); + vw = (int)(100 - ((100 - vw) * mod)); + + do { + p = rng_int() % 100; + vw -= p; + } + while (vw >= 0 && p >= 90); + return (vw <= 0); +} + +/** new rule for Eressea 1.5 + * \param skilldiff - the attack skill with every modifier applied + */ +static int +contest_new(int skilldiff, const troop dt, const armor_type * ar, const armor_type * sh) +{ + double tohit = 0.5 + skilldiff * 0.1; + if (tohit<0.5) tohit = 0.5; + if (chance(tohit)) { + int defense = effskill(dt.fighter->unit, SK_STAMINA); + double tosave = defense * 0.05; + return !chance(tosave); + } + return 0; +} + +static int +contest(int skdiff, const troop dt, const armor_type * ar, const armor_type * sh) +{ + if (skill_formula==FORMULA_ORIG) { + return contest_classic(skdiff, ar, sh); + } else { + return contest_new(skdiff, dt, ar, sh); + } +} + +static boolean +is_riding(const troop t) { + if (t.fighter->building!=NULL) return false; + if (t.fighter->horses + t.fighter->elvenhorses > t.index) return true; + return false; +} + +static weapon * +preferred_weapon(const troop t, boolean attacking) +{ + weapon * missile = t.fighter->person[t.index].missile; + weapon * melee = t.fighter->person[t.index].melee; + if (attacking) { + if (melee==NULL || (missile && missile->attackskill>melee->attackskill)) { + return missile; + } + } else { + if (melee==NULL || (missile && missile->defenseskill>melee->defenseskill)) { + return missile; + } + } + return melee; +} + +static weapon * +select_weapon(const troop t, boolean attacking, boolean ismissile) + /* select the primary weapon for this trooper */ +{ + if (attacking) { + if (ismissile) { + /* from the back rows, have to use your missile weapon */ + return t.fighter->person[t.index].missile; + } + } else { + if (!ismissile) { + /* have to use your melee weapon if it's melee */ + return t.fighter->person[t.index].melee; + } + } + return preferred_weapon(t, attacking); +} + +static boolean +i_canuse(const unit * u, const item_type * itype) +{ + if (itype->canuse) { + return itype->canuse(u, itype); + } + return true; +} + +static int +weapon_skill(const weapon_type * wtype, const unit * u, boolean attacking) + /* the 'pure' skill when using this weapon to attack or defend. + * only undiscriminate modifiers (not affected by troops or enemies) + * are taken into account, e.g. no horses, magic, etc. */ +{ + int skill; + + if (wtype==NULL) { + skill = effskill(u, SK_WEAPONLESS); + if (skill<=0) { + /* wenn kein waffenloser kampf, dann den rassen-defaultwert */ + if (u->race == new_race[RC_ORC]) { + int sword = effskill(u, SK_MELEE); + int spear = effskill(u, SK_SPEAR); + skill = MAX(sword, spear) - 3; + if (attacking) { + skill = MAX(skill, u->race->at_default); + } else { + skill = MAX(skill, u->race->df_default); + } + } else { + if (attacking) { + skill = u->race->at_default; + } else { + skill = u->race->df_default; + } + } + } else { + /* der rassen-defaultwert kann höher sein als der Talentwert von + * waffenloser kampf */ + if (attacking) { + if (skill < u->race->at_default) skill = u->race->at_default; + } else { + if (skill < u->race->df_default) skill = u->race->df_default; + } + } + if (attacking) { + skill += u->race->at_bonus; + if (fval(u->region->terrain, SEA_REGION) && u->ship) skill += u->ship->type->at_bonus; + } else { + skill += u->race->df_bonus; + if (fval(u->region->terrain, SEA_REGION) && u->ship) skill += u->ship->type->df_bonus; + } + } else { + /* changed: if we own a weapon, we have at least a skill of 0 */ + if (!i_canuse(u, wtype->itype)) return -1; + skill = effskill(u, wtype->skill); + if (skill < wtype->minskill) skill = 0; + if (skill > 0) { + if (attacking) { + skill += u->race->at_bonus; + } else { + skill += u->race->df_bonus; + } + } + if (attacking) { + skill += wtype->offmod; + } else { + skill += wtype->defmod; + } + } + + return skill; +} + +static int CavalrySkill(void) +{ + static int skill = -1; + + if (skill<0) { + skill = get_param_int(global.parameters, "rules.cavalry.skill", 2); + } + return skill; +} + +#define BONUS_SKILL 1 +#define BONUS_DAMAGE 2 +static int +CavalryBonus(const unit * u, troop enemy, int type) +{ + static int mode = -1; + + if (mode<0) { + mode = get_param_int(global.parameters, "rules.cavalry.mode", 1); + } + if (mode==0) { + /* old rule, Eressea 1.0 compat */ + return (type==BONUS_SKILL)?2:0; + } else { + /* new rule, chargers in Eressea 1.1 */ + int skl = effskill(u, SK_RIDING); + /* only half against trolls */ + if (skl>0) { + if (type==BONUS_DAMAGE) { + int dmg = MIN(skl, 8); + if (enemy.fighter->unit->race==new_race[RC_TROLL]) { + dmg = dmg/4; + } else { + dmg = dmg/2; + } + return dmg; + } else { + skl = skl/2; + return MIN(skl, 4); + } + } + } + return 0; +} + +static int +weapon_effskill(troop t, troop enemy, const weapon * w, boolean attacking, boolean missile) + /* effektiver Waffenskill während des Kampfes */ +{ + /* In dieser Runde alle die Modifier berechnen, die fig durch die + * Waffen bekommt. */ + fighter * tf = t.fighter; + unit * tu = t.fighter->unit; + int skill; + const weapon_type * wtype = w?w->type:NULL; + + if (wtype==NULL) { + /* Ohne Waffe: Waffenlose Angriffe */ + skill = weapon_skill(NULL, tu, attacking); + } else { + if (attacking) { + skill = w->attackskill; + } else { + skill = w->defenseskill; + } + if (wtype->modifiers!=NULL) { + /* Pferdebonus, Lanzenbonus, usw. */ + int m; + unsigned int flags = WMF_SKILL|(attacking?WMF_OFFENSIVE:WMF_DEFENSIVE); + + if (is_riding(t)) flags |= WMF_RIDING; + else flags |= WMF_WALKING; + if (is_riding(enemy)) flags |= WMF_AGAINST_RIDING; + else flags |= WMF_AGAINST_WALKING; + + for (m=0;wtype->modifiers[m].value;++m) { + if ((wtype->modifiers[m].flags & flags) == flags) { + race_list * rlist = wtype->modifiers[m].races; + if (rlist!=NULL) { + while (rlist) { + if (rlist->data == tu->race) break; + rlist = rlist->next; + } + if (rlist==NULL) continue; + } + skill += wtype->modifiers[m].value; + } + } + } + } + + /* Burgenbonus, Pferdebonus */ + if (is_riding(t) && (wtype==NULL || (fval(wtype, WTF_HORSEBONUS) && !fval(wtype, WTF_MISSILE)))) { + skill += CavalryBonus(tu, enemy, BONUS_SKILL); + if (wtype) skill = skillmod(urace(tu)->attribs, tu, tu->region, wtype->skill, skill, SMF_RIDING); + } + + if (t.indexelvenhorses) { + /* Elfenpferde: Helfen dem Reiter, egal ob und welche Waffe. Das ist + * eleganter, und vor allem einfacher, sonst muß man noch ein + * WMF_ELVENHORSE einbauen. */ + skill += 2; + } + + if (skill>0 && !attacking && missile) { + /* + * Wenn ich verteidige, und nicht direkt meinem Feind gegenüberstehe, + * halbiert sich mein Skill: (z.B. gegen Fernkämpfer. Nahkämpfer + * können mich eh nicht treffen) + */ + skill /= 2; + } + return skill; +} + +static const armor_type * +select_armor(troop t, boolean shield) +{ + unsigned int type = shield?ATF_SHIELD:0; + unit * u = t.fighter->unit; + const armor * a = t.fighter->armors; + int geschuetzt = 0; + + /* some monsters should not use armor (dragons in chainmail? ha!) */ + if (!(u->race->battle_flags & BF_EQUIPMENT)) + return NULL; + + /* ... neither do werewolves */ + if (fval(u, UFL_WERE)) { + return NULL; + } + + for (;a;a=a->next) { + if ((a->atype->flags & ATF_SHIELD)==type) { + geschuetzt += a->count; + if (geschuetzt > t.index) { + /* unser Kandidat wird geschuetzt */ + return a->atype; + } + } + } + return NULL; +} + + +/* Hier ist zu beachten, ob und wie sich Zauber und Artefakte, die + * Rüstungschutz geben, addieren. + * - Artefakt I_TROLLBELT gibt Rüstung +1 + * - Zauber Rindenhaut gibt Rüstung +3 + */ +int +select_magicarmor(troop t) +{ + unit *u = t.fighter->unit; + int geschuetzt = 0; + int ma = 0; + + geschuetzt = MIN(get_item(u, I_TROLLBELT), u->number); + + if (geschuetzt > t.index) /* unser Kandidat wird geschuetzt */ + ma += 1; + + return ma; +} + +/* Sind side ds und Magier des meffect verbündet, dann return 1*/ +boolean +meffect_protection(battle * b, meffect * s, side * ds) +{ + if (!s->magician->alive) return false; + if (s->duration <= 0) return false; + if (enemy(s->magician->side, ds)) return false; + if (allysf(s->magician->side, ds->faction)) return true; + return false; +} + +/* Sind side as und Magier des meffect verfeindet, dann return 1*/ +boolean +meffect_blocked(battle *b, meffect *s, side *as) +{ + if (!s->magician->alive) return false; + if (s->duration <= 0) return false; + if (enemy(s->magician->side, as)) return true; + return false; +} + +/* rmfighter wird schon im PRAECOMBAT gebraucht, da gibt es noch keine + * troops */ +void +rmfighter(fighter *df, int i) +{ + side *ds = df->side; + + /* nicht mehr personen abziehen, als in der Einheit am Leben sind */ + assert(df->alive >= i); + assert(df->alive <= df->unit->number); + + /* erst ziehen wir die Anzahl der Personen von den Kämpfern in der + * Schlacht, dann von denen auf dieser Seite ab*/ + df->side->alive -= i; + df->side->battle->alive -= i; + + /* Dann die Kampfreihen aktualisieren */ + ds->size[SUM_ROW] -= i; + ds->size[statusrow(df->status)] -= i; + + /* Spezialwirkungen, z.B. Schattenritter */ + if (df->unit->race->battle_flags & BF_NOBLOCK) { + ds->nonblockers[SUM_ROW] -= i; + ds->nonblockers[statusrow(df->status)] -= i; + } + + /* und die Einheit selbst aktualisieren */ + df->alive -= i; +} + + +static void +rmtroop(troop dt) +{ + fighter *df = dt.fighter; + + /* troop ist immer eine einzele Person */ + rmfighter(df, 1); + + assert(dt.index >= 0 && dt.index < df->unit->number); + df->person[dt.index] = df->person[df->alive - df->removed]; + if (df->removed) { + df->person[df->alive - df->removed] = df->person[df->alive]; + } + df->person[df->alive].hp = 0; +} + +void +remove_troop(troop dt) +{ + fighter * df = dt.fighter; + struct person p = df->person[dt.index]; + battle * b = df->side->battle; +#ifdef FASTCOUNT + b->fast.alive = -1; /* invalidate cached value */ +#endif +#ifdef FASTROW + b->rowcache.alive = -1; /* invalidate cached value */ +#endif + ++df->removed; + ++df->side->removed; + df->person[dt.index] = df->person[df->alive-df->removed]; + df->person[df->alive - df->removed] = p; +} + +void +kill_troop(troop dt) +{ + fighter * df = dt.fighter; + unit * du = df->unit; + + rmtroop(dt); + if (!df->alive) { + char eqname[64]; + const struct equipment * eq; + if (du->race->itemdrop) { + item * drops = du->race->itemdrop(du->race, du->number-df->run.number); + + if (drops != NULL){ + i_merge(&du->items, &drops); + } + } + sprintf(eqname, "%s_spoils", du->race->_name[0]); + eq = get_equipment(eqname); + if (eq!=NULL) { + equip_items(&du->items, eq); + } + } +} + +/** reduces the target's exp by an equivalent of n points learning + * 30 points = 1 week + */ +void +drain_exp(struct unit *u, int n) +{ + skill_t sk = (skill_t)(rng_int() % MAXSKILLS); + skill_t ssk; + + ssk = sk; + + while (get_level(u, sk)==0) { + sk++; + if (sk == MAXSKILLS) + sk = 0; + if (sk == ssk) { + sk = NOSKILL; + break; + } + } + if (sk != NOSKILL) { + skill * sv = get_skill(u, sk); + while (n>0) { + if (n>=30*u->number) { + reduce_skill(u, sv, 1); + n-=30; + } else { + if (rng_int()%(30*u->number) 0.75) { + return "eine klaffende Wunde"; + } else if (q > 0.5) { + return "eine schwere Wunde"; + } else if (q > 0.25) { + return "eine Wunde"; + } + return "eine kleine Wunde"; +} + +static void vampirism(troop at, int damage) +{ + static int vampire = -1; + if (vampire<0) vampire = get_param_int(global.parameters, "rules.combat.demon_vampire", 0); + if (vampire>0) { + int gain = damage/vampire; + int chance = damage - vampire * gain; + if (chance>0 && (rng_int() % vampire < chance)) ++gain; + if (gain>0) { + int maxhp = unit_max_hp(at.fighter->unit); + at.fighter->person[at.index].hp = MIN(gain+at.fighter->person[at.index].hp, maxhp); + } + } +} + +static int +natural_armor(unit * du) +{ + static int * bonus = 0; + int an = du->race->armor; + if (bonus==0) { + bonus = calloc(sizeof(int), num_races); + } + if (bonus[du->race->index]==0) { + bonus[du->race->index] = get_param_int(du->race->parameters, "armor.stamina", -1); + if (bonus[du->race->index]==0) bonus[du->race->index] = -1; + } + if (bonus[du->race->index]>0) { + int sk = effskill(du, SK_STAMINA); + sk /= bonus[du->race->index]; + an += sk; + } + return an; +} + +boolean +terminate(troop dt, troop at, int type, const char *damage, boolean missile) +{ + item ** pitm; + fighter *df = dt.fighter; + fighter *af = at.fighter; + unit *au = af->unit; + unit *du = df->unit; + battle *b = df->side->battle; + int heiltrank = 0; + static int rule_armor = -1; + + /* Schild */ + void **si; + side *ds = df->side; + int hp; + + int ar = 0, an, am; + const armor_type * armor = select_armor(dt, true); + const armor_type * shield = select_armor(dt, false); + + const weapon_type *dwtype = NULL; + const weapon_type *awtype = NULL; + const weapon * weapon; + + int rda, sk = 0, sd; + boolean magic = false; + int da = dice_rand(damage); + + assert(du->number>0); +#ifdef SHOW_KILLS + ++at.fighter->hits; +#endif + + switch (type) { + case AT_STANDARD: + weapon = select_weapon(at, true, missile); + sk = weapon_effskill(at, dt, weapon, true, missile); + if (weapon) awtype = weapon->type; + if (awtype && fval(awtype, WTF_MAGICAL)) magic = true; + break; + case AT_NATURAL: + sk = weapon_effskill(at, dt, NULL, true, missile); + break; + case AT_SPELL: + case AT_COMBATSPELL: + magic = true; + break; + default: + break; + } + weapon = select_weapon(dt, false, true); /* missile=true to get the unmodified best weapon she has */ + sd = weapon_effskill(dt, at, weapon, false, false); + if (weapon!=NULL) dwtype=weapon->type; + + if (is_riding(at) && (awtype==NULL || (fval(awtype, WTF_HORSEBONUS) && !fval(awtype, WTF_MISSILE)))) { + da += CavalryBonus(au, dt, BONUS_DAMAGE); + } + + if (armor) { + ar += armor->prot; + if (armor->projectile>0 && chance(armor->projectile)) { + return false; + } + } + if (shield) { + ar += shield->prot; + if (shield->projectile>0 && chance(shield->projectile)) { + return false; + } + } + + /* natürliche Rüstung */ + an = natural_armor(du); + + /* magische Rüstung durch Artefakte oder Sprüche */ + /* Momentan nur Trollgürtel und Werwolf-Eigenschaft */ + am = select_magicarmor(dt); + +#if CHANGED_CROSSBOWS + if (awtype && fval(awtype, WTF_ARMORPIERCING)) { + /* crossbows */ + ar /= 2; + an /= 2; + } +#endif + + if (rule_armor<0) { + rule_armor = get_param_int(global.parameters, "rules.combat.nat_armor", 0); + } + if (rule_armor==0) { + /* natürliche Rüstung ist halbkumulativ */ + if (ar>0) { + ar += an/2; + } else { + ar = an; + } + } else { + /* use the higher value, add half the other value */ + ar = (ar>an)?(ar+an/2):(an+ar/2); + } + ar += am; + + if (type!=AT_COMBATSPELL && type!=AT_SPELL) { + if (damage_rules&DAMAGE_CRITICAL) { + double kritchance = (sk * 3 - sd) / 200.0; + + kritchance = MAX(kritchance, 0.005); + kritchance = MIN(0.9, kritchance); + + while (chance(kritchance)) { + if (bdebug) { + fprintf(bdebug, "%s/%d lands a critical hit\n", unitid(au), at.index); + } + da += dice_rand(damage); + } + } + + da += rc_specialdamage(au->race, du->race, awtype); + + if (awtype!=NULL && fval(awtype, WTF_MISSILE)) { + /* missile weapon bonus */ + if (damage_rules&DAMAGE_MISSILE_BONUS) { + da += af->person[at.index].damage_rear; + } + } else if (awtype==NULL) { + /* skill bonus for unarmed combat */ + if (damage_rules&DAMAGE_UNARMED_BONUS) { + da += effskill(au, SK_WEAPONLESS); + } + } else { + /* melee bonus */ + if (damage_rules&DAMAGE_MELEE_BONUS) { + da += af->person[at.index].damage; + } + } + + /* Skilldifferenzbonus */ + if (damage_rules&DAMAGE_SKILL_BONUS) { + da += MAX(0, (sk-sd)/DAMAGE_QUOTIENT); + } + } + + + if (magic) { + /* Magischer Schaden durch Spruch oder magische Waffe */ + double res = 1.0; + + /* magic_resistance gib x% Resistenzbonus zurück */ + res -= magic_resistance(du)*3.0; + + if (du->race->battle_flags & BF_EQUIPMENT) { +#ifdef TODO_RUNESWORD + /* Runenschwert gibt im Kampf 80% Resistenzbonus */ + if (dwp == WP_RUNESWORD) res -= 0.80; +#endif + /* der Effekt von Laen steigt nicht linear */ + if (armor && fval(armor, ATF_LAEN)) res *= (1-armor->magres); + if (shield && fval(shield, ATF_LAEN)) res *= (1-shield->magres); + if (dwtype) res *= (1-dwtype->magres); + } + + if (res > 0) { + da = (int) (MAX(da * res, 0)); + } + /* gegen Magie wirkt nur natürliche und magische Rüstung */ + ar = an+am; + } + + rda = MAX(da - ar,0); + + if ((du->race->battle_flags & BF_INV_NONMAGIC) && !magic) rda = 0; + else { + unsigned int i = 0; + if (du->race->battle_flags & BF_RES_PIERCE) i |= WTF_PIERCE; + if (du->race->battle_flags & BF_RES_CUT) i |= WTF_CUT; + if (du->race->battle_flags & BF_RES_BASH) i |= WTF_BLUNT; + + if (i && awtype && fval(awtype, i)) rda /= 2; + + /* Schilde */ + for (si = b->meffects.begin; si != b->meffects.end; ++si) { + meffect *meffect = *si; + if (meffect_protection(b, meffect, ds) != 0) { + assert(0 <= rda); /* rda sollte hier immer mindestens 0 sein */ + /* jeder Schaden wird um effect% reduziert bis der Schild duration + * Trefferpunkte aufgefangen hat */ + if (meffect->typ == SHIELD_REDUCE) { + hp = rda * (meffect->effect/100); + rda -= hp; + meffect->duration -= hp; + } + /* gibt Rüstung +effect für duration Treffer */ + if (meffect->typ == SHIELD_ARMOR) { + rda = MAX(rda - meffect->effect, 0); + meffect->duration--; + } + } + } + } + + assert(dt.indexnumber); + df->person[dt.index].hp -= rda; + if (au->race==new_race[RC_DAEMON]) { + vampirism(at, rda); + } + + if (df->person[dt.index].hp > 0) { /* Hat überlebt */ + if (bdebug) { + fprintf(bdebug, "Damage %d, armor %d: %d -> %d HP\n", + da, ar, df->person[dt.index].hp + rda, df->person[dt.index].hp); + } + if (au->race == new_race[RC_DAEMON]) { +#ifdef TODO_RUNESWORD + if (select_weapon(dt, 0, -1) == WP_RUNESWORD) continue; +#endif + if (!(df->person[dt.index].flags & (FL_COURAGE|FL_DAZZLED))) { + df->person[dt.index].flags |= FL_DAZZLED; + df->person[dt.index].defence--; + } + } + df->person[dt.index].flags = (df->person[dt.index].flags & ~FL_SLEEPING); + return false; + } + + /* Sieben Leben */ + if (du->race == new_race[RC_CAT] && (chance(1.0 / 7))) { + assert(dt.index>=0 && dt.indexnumber); + df->person[dt.index].hp = unit_max_hp(du); + return false; + } + + /* Heiltrank schluerfen und hoffen */ + if (oldpotiontype[P_HEAL]) { + if (get_effect(du, oldpotiontype[P_HEAL]) > 0) { + change_effect(du, oldpotiontype[P_HEAL], -1); + heiltrank = 1; + } else if (i_get(du->items, oldpotiontype[P_HEAL]->itype) > 0) { + i_change(&du->items, oldpotiontype[P_HEAL]->itype, -1); + change_effect(du, oldpotiontype[P_HEAL], 3); + heiltrank = 1; + } + if (heiltrank && (chance(0.50))) { + { + message * m = msg_message("battle::potionsave", "unit", du); + message_faction(b, du->faction, m); + msg_release(m); + } + assert(dt.index>=0 && dt.indexnumber); + df->person[dt.index].hp = du->race->hitpoints; + return false; + } + } +#ifdef SHOW_KILLS + ++at.fighter->kills; +#endif + + if (bdebug) { + fprintf(bdebug, "Damage %d, armor %d, type %d: %d -> %d HP, tot.\n", + da, ar, type, df->person[dt.index].hp + rda, df->person[dt.index].hp); + } + for (pitm=&du->items; *pitm; ) { + item * itm = *pitm; + const item_type * itype = itm->type; + if (!(itype->flags & ITF_CURSED) && dt.index < itm->number) { + /* 25% Grundchance, das ein Item kaputtgeht. */ + if (rng_int() % 4 < 1) { + i_change(pitm, itype, -1); + } + } + if (*pitm==itm) { + pitm = &itm->next; + } + } + kill_troop(dt); + + return true; +} + +static int +count_side(const side * s, const side * vs, int minrow, int maxrow, int select) +{ + fighter * fig; + int people = 0; + int unitrow[NUMROWS]; + + if (maxrowfighters; fig; fig = fig->next) { + if (fig->alive - fig->removed > 0) { + int row = statusrow(fig->status); + if (select&SELECT_ADVANCE) { + if (unitrow[row] == -1) { + unitrow[row] = get_unitrow(fig, vs); + } + row = unitrow[row]; + } + if (row >= minrow && row <= maxrow) { + people += fig->alive - fig->removed; + if (people>0 && (select&SELECT_FIND)) break; + } + } + } + return people; +} + +/* return the number of live allies warning: this function only considers +* troops that are still alive, not those that are still fighting although +* dead. */ +int +count_allies(const side * as, int minrow, int maxrow, int select, int allytype) +{ + battle *b = as->battle; + side *ds; + int count = 0; + + for (ds=b->sides;ds!=b->sides+b->nsides;++ds) { + if ((allytype==ALLY_ANY && helping(as, ds)) || (allytype==ALLY_SELF && as->faction==ds->faction)) { + count += count_side(ds, NULL, minrow, maxrow, select); + if (count>0 && (select&SELECT_FIND)) break; + } + } + return count; +} + +static int +count_enemies_i(battle * b, const fighter * af, int minrow, int maxrow, int select) +{ + side *es, *as = af->side; + int i = 0; + + for (es=b->sides;es!=b->sides+b->nsides;++es) { + if (as==NULL || enemy(es, as)) { + int offset = 0; + if (select&SELECT_DISTANCE) { + offset = get_unitrow(af, es) - FIGHT_ROW; + } + i += count_side(es, as, minrow-offset, maxrow-offset, select); + if (i>0 && (select&SELECT_FIND)) break; + } + } + return i; +} + +int +count_enemies(battle * b, const fighter * af, int minrow, int maxrow, int select) +{ +#ifdef FASTCOUNT + int sr = statusrow(af->status); + side *as = af->side; + + if (b->alive==b->fast.alive && as==b->fast.side && sr==b->fast.status && minrow==b->fast.minrow && maxrow==b->fast.maxrow) { + if (b->fast.enemies[select]>=0) { +#ifdef DEBUG_FAST + int i = count_enemies_i(b, af, minrow, maxrow, select); + assert(i==b->fast.enemies[select]); +#endif + return b->fast.enemies[select]; + } else if (select&SELECT_FIND) { + if (b->fast.enemies[select-SELECT_FIND]>=0) { +#ifdef DEBUG_FAST + int i = count_enemies_i(b, af, minrow, maxrow, select); + assert((i>0)==(b->fast.enemies[select-SELECT_FIND]>0)); +#endif + return b->fast.enemies[select-SELECT_FIND]; + } + } + } else if (select!=SELECT_FIND || b->alive!=b->fast.alive) { + b->fast.side = as; + b->fast.status = sr; + b->fast.minrow = minrow; + b->fast.alive=b->alive; + b->fast.maxrow = maxrow; + memset(b->fast.enemies, -1, sizeof(b->fast.enemies)); + } +#endif + if (maxrow>=FIRST_ROW) { + int i = count_enemies_i(b, af, minrow, maxrow, select); +#ifdef FASTCOUNT + b->fast.enemies[select] = i; +#endif + return i; + } + return 0; +} + +troop +select_enemy(fighter * af, int minrow, int maxrow, int select) +{ + side *as = af->side; + battle * b = as->battle; + int si, selected; + int enemies; +#ifdef DEBUG_SELECT + troop result = no_troop; +#endif + if (af->unit->race->flags & RCF_FLY) { + /* flying races ignore min- and maxrow and can attack anyone fighting + * them */ + minrow = FIGHT_ROW; + maxrow = BEHIND_ROW; + } + minrow = MAX(minrow, FIGHT_ROW); + + enemies = count_enemies(b, af, minrow, maxrow, select); + + /* Niemand ist in der angegebenen Entfernung? */ + if (enemies<=0) return no_troop; + + selected = rng_int() % enemies; + for (si=0;as->enemies[si];++si) { + side *ds = as->enemies[si]; + fighter * df; + int unitrow[NUMROWS]; + int offset = 0; + + if (select&SELECT_DISTANCE) offset = get_unitrow(af, ds) - FIGHT_ROW; + + if (select&SELECT_ADVANCE) { + int ui; + for (ui=0;ui!=NUMROWS;++ui) unitrow[ui] = -1; + } + + for (df=ds->fighters; df ; df = df->next) { + int dr; + + dr = statusrow(df->status); + if (select&SELECT_ADVANCE) { + if (unitrow[dr]<0) { + unitrow[dr] = get_unitrow(df, as); + } + dr = unitrow[dr]; + } + + if (select&SELECT_DISTANCE) dr += offset; + if (dr < minrow || dr > maxrow) continue; + if (df->alive - df->removed > selected) { +#ifdef DEBUG_SELECT + if (result.fighter==NULL) { + result.index = selected; + result.fighter = df; + } +#else + troop dt; + dt.index = selected; + dt.fighter = df; + return dt; +#endif + } + selected -= (df->alive - df->removed); + enemies -= (df->alive - df->removed); + } + } + if (enemies!=0) { + log_error(("select_enemies has a bug.\n")); + } +#ifdef DEBUG_SELECT + return result; +#else + assert(!selected); + return no_troop; +#endif +} + +static int +get_tactics(const side * as, const side * ds) +{ + battle * b = as->battle; + side *stac; + int result = 0; + int defense = 0; + + if (b->max_tactics > 0) { + for (stac=b->sides;stac!=b->sides+b->nsides;++stac) { + if (stac->leader.value > result && helping(stac, as)) { + assert(ds==NULL || !helping(stac, ds)); + result = stac->leader.value; + } + if (ds && stac->leader.value > defense && helping(stac, ds)) { + assert(!helping(stac, as)); + defense = stac->leader.value; + } + } + } + return result - defense; +} + +static troop +select_opponent(battle * b, troop at, int mindist, int maxdist) +{ + fighter * af = at.fighter; + troop dt; + + if (af->unit->race->flags & RCF_FLY) { + /* flying races ignore min- and maxrow and can attack anyone fighting + * them */ + dt = select_enemy(at.fighter, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); + } else { + mindist = MAX(mindist, FIGHT_ROW); + dt = select_enemy(at.fighter, mindist, maxdist, SELECT_ADVANCE); + } + + if (b->turn==0 && dt.fighter) { + int tactics_formula = -1; + + if (tactics_formula<0) { + tactics_formula = get_param_int(global.parameters, "rules.tactics.formula", 0); + } + if (tactics_formula==1) { + int tactics = get_tactics(at.fighter->side, dt.fighter->side); + + /* percentage chance to get this attack */ + if (tactics>0) { + double tacch = 0.1 * tactics; + if (fval(b->region->terrain, SEA_REGION)) { + ship * sh = at.fighter->unit->ship; + if (sh) tacch *= sh->type->tac_bonus; + } + if (!chance(tacch)) { + dt.fighter = NULL; + } + } else { + dt.fighter = NULL; + } + } + } + + return dt; +} + +/* + * Abfrage mit + * + * cvector *fgs=fighters(b,af,FIGHT_ROW,BEHIND_ROW, FS_HELP|FS_ENEMY); + * fighter *fig; + * + * Optional: Verwirbeln. Vorsicht: Aufwändig! + * v_scramble(fgs->begin, fgs->end); + * + * for (fig = fgs->begin; fig != fgs->end; ++fig) { + * fighter *df = *fig; + * + * } + * + * cv_kill(fgs); free(fgs); Nicht vergessen + */ + +cvector * +fighters(battle *b, const side * vs, int minrow, int maxrow, int mask) +{ + side * s; + cvector *fightervp = malloc(sizeof(cvector)); + + assert(vs!=NULL); + cv_init(fightervp); + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *fig; + + if (mask==FS_ENEMY) { + if (!enemy(s, vs)) continue; + } else if (mask==FS_HELP) { + if (enemy(s, vs) || !allysf(s, vs->faction)) { + continue; + } + } else { + assert(mask==(FS_HELP|FS_ENEMY) || !"invalid alliance state"); + } + for (fig = s->fighters; fig; fig = fig->next) { + int row = get_unitrow(fig, vs); + if (row >= minrow && row <= maxrow) { + cv_pushback(fightervp, fig); + } + } + } + + return fightervp; +} + +static void +report_failed_spell(battle * b, unit * mage, const spell * sp) +{ + message * m = msg_message("battle::spell_failed", "unit spell", mage, sp); + message_all(b, m); + msg_release(m); +} + +void +do_combatmagic(battle *b, combatmagic_t was) +{ + side * s; + region *r = b->region; + castorder *co; + int level, rank, sl; + spellrank spellranks[MAX_SPELLRANK]; + + memset(spellranks, 0, sizeof(spellranks)); + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter * fig; + for (fig = s->fighters; fig; fig = fig->next) { + unit * mage = fig->unit; + + if (fig->alive <= 0) continue; /* fighter kann im Kampf getötet worden sein */ + + level = eff_skill(mage, SK_MAGIC, r); + if (level > 0) { + double power; + const spell *sp; + const struct locale * lang = mage->faction->locale; + order * ord; + + switch(was) { + case DO_PRECOMBATSPELL: + sp = get_combatspell(mage, 0); + sl = get_combatspelllevel(mage, 0); + break; + case DO_POSTCOMBATSPELL: + sp = get_combatspell(mage, 2); + sl = get_combatspelllevel(mage, 2); + break; + default: + /* Fehler! */ + return; + } + if (sp == NULL) + continue; + + ord = create_order(K_CAST, lang, "'%s'", spell_name(sp, lang)); + if (cancast(mage, sp, 1, 1, ord) == false) { + free_order(ord); + continue; + } + + level = eff_spelllevel(mage, sp, level, 1); + if (sl > 0) level = MIN(sl, level); + if (level < 0) { + report_failed_spell(b, mage, sp); + free_order(ord); + continue; + } + + power = spellpower(r, mage, sp, level, ord); + free_order(ord); + if (power <= 0) { /* Effekt von Antimagie */ + report_failed_spell(b, mage, sp); + pay_spell(mage, sp, level, 1); + } else if (fumble(r, mage, sp, sp->level) == true) { + report_failed_spell(b, mage, sp); + pay_spell(mage, sp, level, 1); + } else { + co = new_castorder(fig, 0, sp, r, level, power, 0, 0, 0); + add_castorder(&spellranks[sp->rank], co); + } + } + } + } + for (rank = 0; rank < MAX_SPELLRANK; rank++) { + for (co = spellranks[rank].begin; co; co = co->next) { + fighter * fig = co->magician.fig; + const spell * sp = co->sp; + int level = co->level; + double power = co->force; + + if (sp->sp_function==NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + } else { + level = ((cspell_f)sp->sp_function)(fig, level, power, sp); + if (level > 0) { + pay_spell(fig->unit, sp, level, 1); + } + } + } + } + for (rank = 0; rank < MAX_SPELLRANK; rank++) { + free_castorders(spellranks[rank].begin); + } +} + +static void +combat_action(fighter * af, int turn) +{ +#ifndef SIMPLE_COMBAT + af->action_counter++; + af->side->bf->lastturn = turn; +#endif +} + + +static void +do_combatspell(troop at) +{ + const spell *sp; + fighter *fi = at.fighter; + unit *mage = fi->unit; + battle *b = fi->side->battle; + region *r = b->region; + int level; + double power; + int fumblechance = 0; + void **mg; + order * ord; + int sl; + const struct locale * lang = mage->faction->locale; + + sp = get_combatspell(mage, 1); + if (sp == NULL) { + fi->magic = 0; /* Hat keinen Kampfzauber, kämpft nichtmagisch weiter */ + return; + } + ord = create_order(K_CAST, lang, "'%s'", spell_name(sp, lang)); + if (cancast(mage, sp, 1, 1, ord) == false) { + fi->magic = 0; /* Kann nicht mehr Zaubern, kämpft nichtmagisch weiter */ + return; + } + + level = eff_spelllevel(mage, sp, fi->magic, 1); + if ((sl = get_combatspelllevel(mage, 1)) > 0) level = MIN(level, sl); + + if (fumble(r, mage, sp, sp->level) == true) { + report_failed_spell(b, mage, sp); + pay_spell(mage, sp, level, 1); + return; + } + + for (mg = b->meffects.begin; mg != b->meffects.end; ++mg) { + meffect *mblock = *mg; + if (mblock->typ == SHIELD_BLOCK) { + if (meffect_blocked(b, mblock, fi->side) != 0) { + fumblechance += mblock->duration; + mblock->duration -= mblock->effect; + } + } + } + + /* Antimagie die Fehlschlag erhöht */ + if (rng_int()%100 < fumblechance) { + report_failed_spell(b, mage, sp); + pay_spell(mage, sp, level, 1); + free_order(ord); + return; + } + power = spellpower(r, mage, sp, level, ord); + free_order(ord); + if (power <= 0) { /* Effekt von Antimagie */ + report_failed_spell(b, mage, sp); + pay_spell(mage, sp, level, 1); + return; + } + + if (sp->sp_function==NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + } else { + level = ((cspell_f)sp->sp_function)(fi, level, power, sp); + if (level > 0) { + pay_spell(mage, sp, level, 1); + combat_action(at.fighter, b->turn); + } + } +} + + +/* Sonderattacken: Monster patzern nicht und zahlen auch keine + * Spruchkosten. Da die Spruchstärke direkt durch den Level bestimmt + * wird, wirkt auch keine Antimagie (wird sonst in spellpower + * gemacht) */ + +static void +do_extra_spell(troop at, const att *a) +{ + const spell *sp = a->data.sp; + fighter *fi = at.fighter; + double power; + + power = sp->level * MagicPower(); + if (sp->sp_function==NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + } else { + ((cspell_f)sp->sp_function)(fi, sp->level, power, sp); + } +} + +static int +skilldiff(troop at, troop dt, int dist) +{ + fighter *af = at.fighter, *df = dt.fighter; + unit *au = af->unit, *du = df->unit; + int is_protected = 0, skdiff = 0; + weapon * awp = select_weapon(at, true, dist>1); + + skdiff += af->person[at.index].attack; + skdiff -= df->person[dt.index].defence; + + if (df->person[dt.index].flags & FL_SLEEPING) + skdiff += 2; + + /* Effekte durch Rassen */ + if (awp!=NULL && au->race == new_race[RC_HALFLING] && dragonrace(du->race)) { + skdiff += 5; + } + + if (au->race == new_race[RC_GOBLIN]) { + static int goblin_bonus = -1; + if (goblin_bonus<0) goblin_bonus = get_param_int(global.parameters, "rules.combat.goblinbonus", 10); + if (af->side->size[SUM_ROW] >= df->side->size[SUM_ROW] * goblin_bonus) { + skdiff += 1; + } + } + + if (df->building) { + boolean init = false; + static const curse_type * strongwall_ct, * magicwalls_ct; + if (!init) { + strongwall_ct = ct_find("strongwall"); + magicwalls_ct = ct_find("magicwalls"); + init=true; + } + if (df->building->type->protection) { + int beff = df->building->type->protection(df->building, du); + if (beff) { + skdiff -= beff; + is_protected = 2; + } + } + if (strongwall_ct) { + curse * c = get_curse(df->building->attribs, strongwall_ct); + if (curse_active(c)) { + /* wirkt auf alle Gebäude */ + skdiff -= curse_geteffect_int(c); + is_protected = 2; + } + } + if (magicwalls_ct && curse_active(get_curse(df->building->attribs, magicwalls_ct))) { + /* Verdoppelt Burgenbonus */ + skdiff -= buildingeffsize(df->building, false); + } + } + /* Goblin-Verteidigung + * ist direkt in der Rassentabelle als df_default + */ + + /* Effekte der Waffen */ + skdiff += weapon_effskill(at, dt, awp, true, dist>1); + if (awp && fval(awp->type, WTF_MISSILE)) { + skdiff -= is_protected; + if (awp->type->modifiers) { + int w; + for (w=0;awp->type->modifiers[w].value!=0;++w) { + if (awp->type->modifiers[w].flags & WMF_MISSILE_TARGET) { + /* skill decreases by targeting difficulty (bow -2, catapult -4) */ + skdiff -= awp->type->modifiers[w].value; + break; + } + } + } + } + if (skill_formula==FORMULA_ORIG) { + weapon * dwp = select_weapon(dt, false, dist>1); + skdiff -= weapon_effskill(dt, at, dwp, false, dist>1); + } + return skdiff; +} + +static int +setreload(troop at) +{ + fighter * af = at.fighter; + const weapon_type * wtype = af->person[at.index].missile->type; + if (wtype->reload == 0) return 0; + return af->person[at.index].reload = wtype->reload; +} + +int +getreload(troop at) +{ + return at.fighter->person[at.index].reload; +} + +static void +debug_hit(troop at, const weapon * awp, troop dt, const weapon * dwp, int skdiff, int dist, boolean success) +{ + fprintf(bdebug, "%.4s/%d [%6s/%d] %s %.4s/%d [%6s/%d] with %d, distance %d\n", + unitid(at.fighter->unit), at.index, + LOC(default_locale, awp ? resourcename(awp->type->itype->rtype, 0) : "unarmed"), + weapon_effskill(at, dt, awp, true, dist>1), + success?"hits":"misses", + unitid(dt.fighter->unit), dt.index, + LOC(default_locale, dwp ? resourcename(dwp->type->itype->rtype, 0) : "unarmed"), + weapon_effskill(dt, at, dwp, false, dist>1), + skdiff, dist); +} + +int +hits(troop at, troop dt, weapon * awp) +{ + fighter *af = at.fighter, *df = dt.fighter; + const armor_type * armor, * shield = 0; + int skdiff = 0; + int dist = get_unitrow(af, df->side) + get_unitrow(df, af->side) - 1; + weapon * dwp = select_weapon(dt, false, dist>1); + + if (!df->alive) return 0; + if (getreload(at)) return 0; + if (dist>1 && (awp == NULL || !fval(awp->type, WTF_MISSILE))) return 0; + + /* mark this person as hit. */ + df->person[dt.index].flags |= FL_HIT; + + if (af->person[at.index].flags & FL_STUNNED) { + af->person[at.index].flags &= ~FL_STUNNED; + return 0; + } + if ((af->person[at.index].flags & FL_TIRED && rng_int()%100 < 50) + || (af->person[at.index].flags & FL_SLEEPING)) + return 0; + + /* effect of sp_reeling_arrows combatspell */ + if (af->side->battle->reelarrow && awp && fval(awp->type, WTF_MISSILE) && rng_double() < 0.5) { + return 0; + } + + skdiff = skilldiff(at, dt, dist); + /* Verteidiger bekommt eine Rüstung */ + armor = select_armor(dt, true); + if (dwp==NULL || (dwp->type->flags & WTF_USESHIELD)) { + shield = select_armor(dt, false); + } + if (contest(skdiff, dt, armor, shield)) { + if (bdebug) { + debug_hit(at, awp, dt, dwp, skdiff, dist, true); + } + return 1; + } + if (bdebug) { + debug_hit(at, awp, dt, dwp, skdiff, dist, false); + } + return 0; +} + +void +dazzle(battle *b, troop *td) +{ + /* Nicht kumulativ ! */ + if(td->fighter->person[td->index].flags & FL_DAZZLED) return; + +#ifdef TODO_RUNESWORD + if (td->fighter->weapon[WP_RUNESWORD].count > td->index) { + return; + } +#endif + if (td->fighter->person[td->index].flags & FL_COURAGE) { + return; + } + + if (td->fighter->person[td->index].flags & FL_DAZZLED) { + return; + } + + td->fighter->person[td->index].flags |= FL_DAZZLED; + td->fighter->person[td->index].defence--; +} + +/* TODO: Gebäude/Schiffe sollten auch zerstörbar sein. Schwierig im Kampf, + * besonders bei Schiffen. */ + +void +damage_building(battle *b, building *bldg, int damage_abs) +{ + bldg->size = MAX(1, bldg->size-damage_abs); + + /* Wenn Burg, dann gucken, ob die Leute alle noch in das Gebäude passen. */ + + if (bldg->type->protection) { + side * s; + + bldg->sizeleft = bldg->size; + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter * fig; + for (fig=s->fighters;fig;fig=fig->next) { + if (fig->building == bldg) { + if (bldg->sizeleft >= fig->unit->number) { + fig->building = bldg; + bldg->sizeleft -= fig->unit->number; + } else { + fig->building = NULL; + } + } + } + } + } +} + +static int +attacks_per_round(troop t) +{ + return t.fighter->person[t.index].speed; +} + +static void +make_heroes(battle * b) +{ + side * s; + static int hero_speed = 0; + if (hero_speed==0) { + hero_speed = get_param_int(global.parameters, "rules.combat.herospeed", 10); + } + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter * fig; + for (fig=s->fighters;fig;fig=fig->next) { + unit * u = fig->unit; + if (fval(u, UFL_HERO)) { + int i; + assert(playerrace(u->race)); + for (i=0;i!=u->number;++i) { + fig->person[i].speed += (hero_speed-1); + } + } + } + } +} + +static void +attack(battle *b, troop ta, const att *a, int numattack) +{ + fighter *af = ta.fighter; + troop td; + unit *au = af->unit; + + switch(a->type) { + case AT_COMBATSPELL: + /* Magier versuchen immer erstmal zu zaubern, erst wenn das + * fehlschlägt, wird af->magic == 0 und der Magier kämpft + * konventionell weiter */ + if (numattack==0 && af->magic > 0) { + /* wenn der magier in die potenzielle Reichweite von Attacken des + * Feindes kommt, beginnt er auch bei einem Status von KAEMPFE NICHT, + * Kampfzauber zu schleudern: */ + if (count_enemies(b, af, melee_range[0], missile_range[1], SELECT_ADVANCE|SELECT_DISTANCE|SELECT_FIND)) { + do_combatspell(ta); + } + } + break; + case AT_STANDARD: /* Waffen, mag. Gegenstände, Kampfzauber */ + if (numattack > 0 || af->magic <= 0) { + weapon * wp = ta.fighter->person[ta.index].missile; + int melee = count_enemies(b, af, melee_range[0], melee_range[1], SELECT_ADVANCE|SELECT_DISTANCE|SELECT_FIND); + if (melee) wp = preferred_weapon(ta, true); + /* Sonderbehandlungen */ + + if (getreload(ta)) { + ta.fighter->person[ta.index].reload--; + } else { + boolean standard_attack = true; + boolean reload = false; + /* spezialattacken der waffe nur, wenn erste attacke in der runde. + * sonst helden mit feuerschwertern zu mächtig */ + if (numattack==0 && wp && wp->type->attack) { + int dead = 0; + standard_attack = wp->type->attack(&ta, wp->type, &dead); + if (!standard_attack) reload = true; + af->catmsg += dead; + if (!standard_attack && af->person[ta.index].last_action < b->turn) { + af->person[ta.index].last_action = b->turn; + combat_action(af, b->turn); + } + } + if (standard_attack) { + boolean missile = false; + if (wp && fval(wp->type, WTF_MISSILE)) missile = true; + if (missile) { + td = select_opponent(b, ta, missile_range[0], missile_range[1]); + } + else { + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + } + if (!td.fighter) return; + if (ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + reload = true; + if (hits(ta, td, wp)) { + const char * d; + if (wp == NULL) d = au->race->def_damage; + else if (is_riding(ta)) d = wp->type->damage[1]; + else d = wp->type->damage[0]; + terminate(td, ta, a->type, d, missile); + } + } + if (reload && wp && wp->type->reload && !getreload(ta)) { + int i = setreload(ta); + if (bdebug) { + fprintf(bdebug, "%s/%d reloading %d turns\n", unitid(au), ta.index, i); + } + } + } + } + break; + case AT_SPELL: /* Extra-Sprüche. Kampfzauber in AT_COMBATSPELL! */ + do_extra_spell(ta, a); + break; + case AT_NATURAL: + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + if (!td.fighter) return; + if(ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + if (hits(ta, td, NULL)) { + terminate(td, ta, a->type, a->data.dice, false); + } + break; + case AT_DRAIN_ST: + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + if (!td.fighter) return; + if(ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + if (hits(ta, td, NULL)) { + int c = dice_rand(a->data.dice); + while(c > 0) { + if (rng_int()%2) { + td.fighter->person[td.index].attack -= 1; + } else { + td.fighter->person[td.index].defence -= 1; + } + c--; + } + } + break; + case AT_DRAIN_EXP: + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + if (!td.fighter) return; + if(ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + if (hits(ta, td, NULL)) { + drain_exp(td.fighter->unit, dice_rand(a->data.dice)); + } + break; + case AT_DAZZLE: + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + if (!td.fighter) return; + if(ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + if (hits(ta, td, NULL)) { + dazzle(b, &td); + } + break; + case AT_STRUCTURAL: + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + if (!td.fighter) return; + if(ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + if (td.fighter->unit->ship) { + td.fighter->unit->ship->damage += DAMAGE_SCALE * dice_rand(a->data.dice); + } else if (td.fighter->unit->building) { + damage_building(b, td.fighter->unit->building, dice_rand(a->data.dice)); + } + } +} + +void +do_attack(fighter * af) +{ + troop ta; + unit *au = af->unit; + side *side = af->side; + battle *b = side->battle; + + ta.fighter = af; + + assert(au && au->number); + /* Da das Zuschlagen auf Einheiten und nicht auf den einzelnen + * Kämpfern beruht, darf die Reihenfolge und Größe der Einheit keine + * Rolle spielen, Das tut sie nur dann, wenn jeder, der am Anfang der + * Runde lebte, auch zuschlagen darf. Ansonsten ist der, der zufällig + * mit einer großen Einheit zuerst drankommt, extrem bevorteilt. */ + ta.index = af->fighting; + + while (ta.index--) { + /* Wir suchen eine beliebige Feind-Einheit aus. An der können + * wir feststellen, ob noch jemand da ist. */ + int apr, attacks = attacks_per_round(ta); + if (!count_enemies(b, af, FIGHT_ROW, LAST_ROW, SELECT_FIND)) break; + + for (apr=0;apr!=attacks;++apr) { + int a; + for (a=0; a!=10 && au->race->attack[a].type!=AT_NONE; ++a) { + if (apr>0) { + /* Wenn die Waffe nachladen muss, oder es sich nicht um einen + * Waffen-Angriff handelt, dann gilt der Speed nicht. */ + if (au->race->attack[a].type!=AT_STANDARD) continue; + else { + weapon * wp = preferred_weapon(ta, true); + if (wp!=NULL && wp->type->reload) continue; + } + } + attack(b, ta, &(au->race->attack[a]), apr); + } + } + } + /* Der letzte Katapultschütze setzt die + * Ladezeit neu und generiert die Meldung. */ + if (af->catmsg>=0) { + struct message * m = msg_message("battle::killed", "unit dead", au, af->catmsg); + message_all(b, m); + msg_release(m); + af->catmsg = -1; + } +} + +void +do_regenerate(fighter *af) +{ + troop ta; + unit *au = af->unit; + + ta.fighter = af; + ta.index = af->fighting; + + while(ta.index--) { + af->person[ta.index].hp += effskill(au, SK_STAMINA); + af->person[ta.index].hp = MIN(unit_max_hp(au), af->person[ta.index].hp); + } +} + +static void +add_tactics(tactics * ta, fighter * fig, int value) +{ + if (value == 0 || value < ta->value) + return; + if (value > ta->value) + cv_kill(&ta->fighters); + cv_pushback(&ta->fighters, fig); + cv_pushback(&fig->side->battle->leaders, fig); + ta->value = value; +} + +static double horsebonus(const unit * u) +{ + static const item_type * it_horse = 0; + static const item_type * it_elvenhorse = 0; + static const item_type * it_charger = 0; + region * r = u->region; + int n1 = 0, n2 = 0, n3 = 0; + item * itm = u->items; + int skl = eff_skill(u, SK_RIDING, r); + + if (skl<1) return 0.0; + + if (it_horse==0) { + it_horse = it_find("horse"); + it_elvenhorse = it_find("elvenhorse"); + it_charger = it_find("charger"); + } + + for (;itm;itm=itm->next) { + if (itm->type->flags&ITF_ANIMAL) { + if (itm->type==it_elvenhorse) n3 +=itm->number; + else if (itm->type==it_charger) n2 +=itm->number; + else if (itm->type==it_horse) n1 +=itm->number; + } + } + if (skl >= 5 && n3>=u->number) return 0.30; + if (skl >= 3 && n2+n3>=u->number) return 0.20; + if (skl >= 1 && n1+n2+n3>=u->number) return 0.10; + return 0.0F; +} + +double +fleechance(unit * u) +{ + double c = 0.20; /* Fluchtwahrscheinlichkeit in % */ + region * r = u->region; + attrib * a = a_find(u->attribs, &at_fleechance); + /* Einheit u versucht, dem Getümmel zu entkommen */ + + c += (eff_skill(u, SK_STEALTH, r) * 0.05); + c += horsebonus(u); + + if (u->race == new_race[RC_HALFLING]) { + c += 0.20; + c = MIN(c, 0.90); + } else { + c = MIN(c, 0.75); + } + + if (a!=NULL) c += a->data.flt; + + return c; +} + +/** add a new army to the conflict + * beware: armies need to be added _at the beginning_ of the list because + * otherwise join_allies() will get into trouble */ +static side * +make_side(battle * b, const faction * f, const group * g, unsigned int flags, const faction *stealthfaction) +{ + side *s1 = b->sides+b->nsides; + bfaction * bf; + +#ifdef SIMPLE_COMBAT + if (fval(b->region->terrain, SEA_REGION)) { + /* every fight in an ocean is short */ + flags |= SIDE_HASGUARDS; + } else { + unit * u; + for (u = b->region->units; u; u = u->next) { + if (is_guard(u, HELP_ALL)) { + if (alliedunit(u, f, HELP_GUARD)) { + flags |= SIDE_HASGUARDS; + break; + } + } + } + } +#endif + + s1->battle = b; + s1->group = g; + s1->flags = flags; + s1->stealthfaction = stealthfaction; + for (bf = b->factions;bf;bf=bf->next) { + faction * f2 = bf->faction; + + if (f2 == f) { + s1->bf = bf; + s1->faction = f2; + s1->index = b->nsides++; + s1->nextF = bf->sides; + bf->sides = s1; + assert(b->nsides<=MAXSIDES); + break; + } + } + assert(bf); + return s1; +} + +troop +select_ally(fighter * af, int minrow, int maxrow, int allytype) +{ + side *as = af->side; + battle *b = as->battle; + side * ds; + int allies = count_allies(as, minrow, maxrow, SELECT_ADVANCE, allytype); + + if (!allies) { + return no_troop; + } + allies = rng_int() % allies; + + for (ds=b->sides;ds!=b->sides+b->nsides;++ds) { + if ((allytype==ALLY_ANY && helping(as, ds)) || (allytype==ALLY_SELF && as->faction==ds->faction)) { + fighter * df; + for (df=ds->fighters; df; df=df->next) { + int dr = get_unitrow(df, NULL); + if (dr >= minrow && dr <= maxrow) { + if (df->alive - df->removed > allies) { + troop dt; + assert(allies>=0); + dt.index = allies; + dt.fighter = df; + return dt; + } + allies -= df->alive; + } + } + } + } + assert(!"we should never have gotten here"); + return no_troop; +} + + +static int loot_quota(const unit * src, const unit * dst, const item_type * type, int n) +{ + static float divisor = -1; + if (dst && src && src->faction!=dst->faction) { + if (divisor<0) { + divisor = get_param_flt(global.parameters, "rules.items.loot_divisor", 1); + assert(divisor==0 || divisor>=1); + } + if (divisor>=1) { + double r = n / divisor; + int x = (int)r; + + r = r - x; + if (chance(r)) ++x; + + return x; + } + } + return n; +} + +static void +loot_items(fighter * corpse) +{ + unit * u = corpse->unit; + item * itm = u->items; + battle * b = corpse->side->battle; + int dead = dead_fighters(corpse); + + if (dead<=0) return; + + while (itm) { + float lootfactor = dead/(float)u->number; /* only loot the dead! */ + int maxloot = (int)(itm->number*lootfactor); + if (maxloot>0) { + int i = MIN(10, maxloot); + for (; i != 0; --i) { + int loot = maxloot/i; + + if (loot>0) { + fighter *fig = NULL; + int looting = 0; + int maxrow = 0; + /* mustloot: we absolutely, positively must have somebody loot this thing */ + int mustloot = itm->type->flags & (ITF_CURSED|ITF_NOTLOST); + + itm->number -= loot; + maxloot -= loot; + + if (is_monsters(u->faction) && (loot_rules & LOOT_MONSTERS)) { + looting = 1; + } else if (loot_rules&LOOT_OTHERS) { + looting = 1; + } else if (loot_rules&LOOT_SELF) { + looting = 2; + } + if (looting) { + if (mustloot) { + maxrow = LAST_ROW; + } else if (loot_rules&LOOT_KEEPLOOT) { + int lootchance = 50 + b->keeploot; + if (rng_int() % 100 < lootchance) { + maxrow = BEHIND_ROW; + } + } else { + maxrow = LAST_ROW; + } + } + if (maxrow>0) { + if (looting==1) { + /* enemies get dibs */ + fig = select_enemy(corpse, FIGHT_ROW, maxrow, 0).fighter; + } + if (!fig) { + /* self and allies get second pick */ + fig = select_ally(corpse, FIGHT_ROW, LAST_ROW, ALLY_SELF).fighter; + } + } + + if (fig) { + int trueloot = mustloot?loot:loot_quota(corpse->unit, fig->unit, itm->type, loot); + if (trueloot>0) { + item * l = fig->loot; + while (l && l->type!=itm->type) l=l->next; + if (!l) { + l = calloc(sizeof(item), 1); + l->next = fig->loot; + fig->loot = l; + l->type = itm->type; + } + l->number += trueloot; + } + } + } + } + } + itm = itm->next; + } +} + +#ifndef SIMPLE_ESCAPE +static void +loot_fleeing(fighter* fig, unit* runner) +{ + /* TODO: Vernünftig fixen */ + runner->items = NULL; + assert(runner->items == NULL); + runner->items = fig->run.items; + fig->run.items = NULL; +} + +static void +merge_fleeloot(fighter* fig, unit* u) +{ + i_merge(&u->items, &fig->run.items); +} +#endif /* SIMPLE_ESCAPE */ + +static boolean +seematrix(const faction * f, const side * s) +{ + if (f==s->faction) return true; + if (s->flags & SIDE_STEALTH) return false; + return true; +} + +static double +PopulationDamage(void) +{ + static double value = -1.0; + if (value<0) { + int damage = get_param_int(global.parameters, "rules.combat.populationdamage", BATTLE_KILLS_PEASANTS); + value = damage/100.0; + } + return value; +} + + +static void +battle_effects(battle * b, int dead_players) +{ + region * r = b->region; + int dead_peasants = MIN(rpeasants(r), (int)(dead_players*PopulationDamage())); + if (dead_peasants) { + deathcounts(r, dead_peasants + dead_players); + chaoscounts(r, dead_peasants / 2); + rsetpeasants(r, rpeasants(r) - dead_peasants); + } +} + +static void +reorder_fleeing(region * r) +{ + unit **usrc = &r->units; + unit **udst = &r->units; + unit *ufirst = NULL; + unit *u; + + for (;*udst;udst=&u->next) { + u = *udst; + } + + for (u=*usrc;u!=ufirst;u=*usrc) { + if (u->next && fval(u, UFL_FLEEING)) { + *usrc = u->next; + *udst = u; + udst = &u->next; + if (!ufirst) ufirst = u; + } else { + usrc = &u->next; + } + } + *udst = NULL; +} + +static void +aftermath(battle * b) +{ + int i; + region *r = b->region; + ship *sh; + side *s; + int dead_players = 0; + bfaction * bf; + boolean ships_damaged = (boolean)(b->turn+(b->has_tactics_turn?1:0)>2); /* only used for ship damage! */ + +#ifdef TROLLSAVE + int *trollsave = calloc(2 * cv_size(&b->factions), sizeof(int)); +#endif + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter * df; + for (df = s->fighters; df; df=df->next) { + unit *du = df->unit; + int dead = dead_fighters(df); + int pr_mercy = 0; + +#ifdef TROLLSAVE + /* Trolle können regenerieren */ + if (df->alive > 0 && dead>0 && du->race == new_race[RC_TROLL]) { + for (i = 0; i != dead; ++i) { + if (chance(TROLL_REGENERATION)) { + ++df->alive; + ++s->alive; + ++s->battle->alive; + ++trollsave[s->index]; + /* do not change dead here, or loop will not terminate! recalculate later */ + } + } + dead = dead_fighters(df); + } +#endif + /* Regeneration durch PR_MERCY */ + if (dead>0 && pr_mercy) { + for (i = 0; i != dead; ++i) { + if (rng_int()%100 < pr_mercy) { + ++df->alive; + ++s->alive; + ++s->battle->alive; + /* do not change dead here, or loop will not terminate! recalculate later */ + } + } + dead = dead_fighters(df); + } + + /* tote insgesamt: */ + s->dead += dead; + /* Tote, die wiederbelebt werde können: */ + if (playerrace(df->unit->race)) { + s->casualties += dead; + } +#ifdef SHOW_KILLS + if (df->hits + df->kills) { + struct message * m = msg_message("killsandhits", "unit hits kills", du, df->hits, df->kills); + message_faction(b, du->faction, m); + msg_release(m); + } +#endif + } + } + + /* POSTCOMBAT */ + do_combatmagic(b, DO_POSTCOMBATSPELL); + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + int snumber = 0; + fighter *df; + boolean relevant = false; /* Kampf relevant für diese Partei? */ +#ifdef SIMPLE_COMBAT + if (fval(s, SIDE_HASGUARDS) == 0) relevant = true; +#else + if (s->bf->lastturn>1) { + relevant = true; + } else if (s->bf->lastturn==1 && b->has_tactics_turn) { + side * stac; + for (stac=b->sides; stac; stac=stac->next) { + if (stac->leader.value == b->max_tactics && helping(stac, s)) { + relevant = true; + break; + } + } + } +#endif + s->flee = 0; + + for (df=s->fighters;df;df=df->next) { + unit *du = df->unit; + int dead = dead_fighters(df); + int sum_hp = 0; + int n; + + for (n = 0; n != df->alive; ++n) { + if (df->person[n].hp > 0) { + sum_hp += df->person[n].hp; + } + } + snumber += du->number; +#ifdef SIMPLE_COMBAT + if (relevant) { + int flags = UFL_LONGACTION|UFL_NOTMOVING; +#ifdef SIMPLE_ESCAPE + if (du->status==ST_FLEE) flags -= UFL_NOTMOVING; +#endif /* SIMPLE_ESCAPE */ + fset(du, flags); + } + if (sum_hp+df->run.hphp) { + /* someone on the ship got damaged, damage the ship */ + ship * sh = du->ship?du->ship:leftship(du); + if (sh) fset(sh, SF_DAMAGED); + } +#else + if (relevant) { + fset(du, UFL_NOTMOVING); /* unit cannot move this round */ + if (df->action_counter >= du->number) { + ship * sh = du->ship?du->ship:leftship(du); + if (sh) fset(sh, SF_DAMAGED); + fset(du, UFL_LONGACTION); + } + } +#endif + + if (df->alive == du->number) { + du->hp = sum_hp; + continue; /* nichts passiert */ + } else if (df->run.hp) { + if (df->alive == 0) { + /* Report the casualties */ + reportcasualties(b, df, dead); + + /* Zuerst dürfen die Feinde plündern, die mitgenommenen Items + * stehen in fig->run.items. Dann werden die Fliehenden auf + * die leere (tote) alte Einheit gemapt */ +#ifdef SIMPLE_ESCAPE + if (!fval(df, FIG_NOLOOT)) { + loot_items(df); + } +#else + if (fval(df, FIG_NOLOOT)){ + merge_fleeloot(df, du); + } else { + loot_items(df); + loot_fleeing(df, du); + } +#endif /* SIMPLE_ESCAPE */ + scale_number(du, df->run.number); + du->hp = df->run.hp; + setguard(du, GUARD_NONE); + /* must leave ships or buildings, or a stealthy hobbit + * can hold castles indefinitely */ + if (!fval(r->terrain, SEA_REGION)) { + leave(du, true); /* even region owners have to flee */ + } +#ifndef SIMPLE_ESCAPE + if (df->run.region) { + run_to(du, df->run.region); + df->run.region = du->region; + } + fset(du, UFL_LONGACTION|UFL_NOTMOVING); +#endif /* SIMPLE_ESCAPE */ + fset(du, UFL_FLEEING); + } else { + /* nur teilweise geflohene Einheiten mergen sich wieder */ + df->alive += df->run.number; + s->size[0] += df->run.number; + s->size[statusrow(df->status)] += df->run.number; + s->alive += df->run.number; + sum_hp += df->run.hp; +#ifndef SIMPLE_ESCAPE + merge_fleeloot(df, du); +#endif /* SIMPLE_ESCAPE */ + df->run.number = 0; + df->run.hp = 0; + /* df->run.region = NULL;*/ + + reportcasualties(b, df, dead); + + scale_number(du, df->alive); + du->hp = sum_hp; + } + } else { + if (df->alive==0) { + /* alle sind tot, niemand geflohen. Einheit auflösen */ + df->run.number = 0; + df->run.hp = 0; +#ifndef SIMPLE_ESCAPE + df->run.region = NULL; +#endif /* SIMPLE_ESCAPE */ + + /* Report the casualties */ + reportcasualties(b, df, dead); + + /* Distribute Loot */ + loot_items(df); + + setguard(du, GUARD_NONE); + scale_number(du, 0); + } else { + df->run.number = 0; + df->run.hp = 0; + + reportcasualties(b, df, dead); + + scale_number(du, df->alive); + du->hp = sum_hp; + } + } + s->flee += df->run.number; + + if (playerrace(du->race)) { + /* tote im kampf werden zu regionsuntoten: + * for each of them, a peasant will die as well */ + dead_players += dead; + } + if (du->hp < du->number) { + log_error(("%s has less hitpoints (%u) than people (%u)\n", + itoa36(du->no), du->hp, du->number)); + du->hp = du->number; + } + } + s->alive+=s->healed; + assert(snumber==s->flee+s->alive+s->dead); + } + + battle_effects(b, dead_players); + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + message * seen = msg_message("battle::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", + "index abbrev dead fled survived", + army_index(s), "-?-", s->dead, s->flee, s->alive); + + for (bf=b->factions;bf;bf=bf->next) { + faction * f = bf->faction; + message * m = seematrix(f, s)?seen:unseen; + + message_faction(b, f, m); + } + + msg_release(seen); + msg_release(unseen); + } + + /* Wir benutzen drifted, um uns zu merken, ob ein Schiff + * schonmal Schaden genommen hat. (moved und drifted + * sollten in flags überführt werden */ + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *df; + + for (df=s->fighters; df; df=df->next) { + unit *du = df->unit; + item * l; + + /* Beute verteilen */ + for (l=df->loot; l; l=l->next) { + const item_type * itype = l->type; + message * m = msg_message("battle_loot", "unit amount item", du, l->number, itype->rtype); + message_faction(b, du->faction, m); + msg_release(m); + i_change(&du->items, itype, l->number); + } + + /* Wenn sich die Einheit auf einem Schiff befindet, wird + * dieses Schiff beschädigt. Andernfalls ein Schiff, welches + * evt. zuvor verlassen wurde. */ + if (ships_damaged) { + if (du->ship) sh = du->ship; + else sh = leftship(du); + + if (sh && fval(sh, SF_DAMAGED)) { + int n = b->turn - 2; + if (n>0) { + damage_ship(sh, 0.05 * n); + freset(sh, SF_DAMAGED); + } + } + } + } + } + + if (ships_damaged) { + ship **sp = &r->ships; + + while (*sp) { + ship * sh = *sp; + freset(sh, SF_DAMAGED); + if (sh->damage >= sh->size * DAMAGE_SCALE) { + remove_ship(sp, sh); + } + if (*sp==sh) sp=&sh->next; + } + } +#ifdef TROLLSAVE + free(trollsave); +#endif + + reorder_fleeing(r); + + if (bdebug) { + fprintf(bdebug, "The battle lasted %d turns, %s and %s.\n", + b->turn, + b->has_tactics_turn?"had a tactic turn":"had no tactic turn", + ships_damaged?"was relevant":"was not relevant."); + } +} + +static void +battle_punit(unit * u, battle * b) +{ + bfaction * bf; + strlist *S, *x; + + for (bf = b->factions;bf;bf=bf->next) { + faction *f = bf->faction; + + S = 0; + spunit(&S, f, u, 4, see_battle); + for (x = S; x; x = x->next) { + fbattlerecord(b, f, x->s); + if (bdebug && u->faction == f) { + fputs(x->s, bdebug); + fputc('\n', bdebug); + } + } + if (S) + freestrlist(S); + } +} + +static void +print_fighters(battle * b, const side * s) +{ + fighter *df; + int row; + + for (row=1;row!=NUMROWS;++row) { + message * m = NULL; + + for (df=s->fighters; df; df=df->next) { + unit *du = df->unit; + int thisrow = statusrow(df->unit->status); + + if (row == thisrow) { + if (m==NULL) { + m = msg_message("battle::row_header", "row", row); + message_all(b, m); + } + battle_punit(du, b); + } + } + if (m!=NULL) msg_release(m); + } +} + +boolean +is_attacker(const fighter * fig) +{ + return fval(fig, FIG_ATTACKER)!=0; +} + +static void +set_attacker(fighter * fig) +{ + fset(fig, FIG_ATTACKER); +} + +static void +print_header(battle * b) +{ + bfaction * bf; + char zText[32*MAXSIDES]; + + for (bf=b->factions;bf;bf=bf->next) { + message * m; + faction * f = bf->faction; + const char * lastf = NULL; + boolean first = false; + side * s; + char * bufp = zText; + size_t size = sizeof(zText) - 1; + int bytes; + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *df; + for (df=s->fighters;df;df=df->next) { + if (is_attacker(df)) { + if (first) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (lastf) { + bytes = (int)strlcpy(bufp, (const char *)lastf, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + first = true; + } + if (seematrix(f, s) == true) + lastf = sidename(s); + else + lastf = LOC(f->locale, "unknown_faction_dative"); + break; + } + } + } + if (first) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, (const char *)LOC(f->locale, "and"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (lastf) { + bytes = (int)strlcpy(bufp, (const char *)lastf, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + m = msg_message("battle::starters", "factions", zText); + message_faction(b, f, m); + msg_release(m); + } +} + +static void +print_stats(battle * b) +{ + side *s2; + side *s; + int i = 0; + for (s=b->sides;s!=b->sides+b->nsides;++s) { + bfaction *bf; + + ++i; + + for (bf=b->factions;bf;bf=bf->next) { + faction * f = bf->faction; + const char * loc_army = LOC(f->locale, "battle_army"); + char * bufp; + const char * header; + size_t rsize, size; + int komma; + const char * sname = seematrix(f, s) ? sidename(s) : LOC(f->locale, "unknown_faction"); + message * msg; + char buf[1024]; + + message_faction(b, f, msg_separator); + + msg = msg_message("battle_army", "index name", army_index(s), sname); + message_faction(b, f, msg); + msg_release(msg); + + bufp = buf; + size = sizeof(buf); + komma = 0; + header = LOC(f->locale, "battle_opponents"); + + for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { + if (enemy(s2, s)) { + const char * abbrev = seematrix(f, s2)?sideabkz(s2, false):"-?-"; + rsize = slprintf(bufp, size, "%s %s %d(%s)", + komma++ ? "," : (const char*)header, loc_army, army_index(s2), abbrev); + if (rsize>size) rsize = size-1; + size -= rsize; + bufp += rsize; + } + } + if (komma) fbattlerecord(b, f, buf); + + bufp = buf; + size = sizeof(buf); + komma = 0; + header = LOC(f->locale, "battle_helpers"); + + for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { + if (friendly(s2, s)) { + const char * abbrev = seematrix(f, s2)?sideabkz(s2, false):"-?-"; + rsize = slprintf(bufp, size, "%s %s %d(%s)", + komma++ ? "," : (const char*)header, loc_army, army_index(s2), abbrev); + if (rsize>size) rsize = size-1; + size -= rsize; + bufp += rsize; + } + } + if (komma) fbattlerecord(b, f, buf); + + bufp = buf; + size = sizeof(buf); + komma = 0; + header = LOC(f->locale, "battle_attack"); + + for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { + if (s->relations[s2->index] & E_ATTACKING) { + const char * abbrev = seematrix(f, s2)?sideabkz(s2, false):"-?-"; + rsize = slprintf(bufp, size, "%s %s %d(%s)", komma++ ? "," : (const char*)header, loc_army, + army_index(s2), abbrev); + if (rsize>size) rsize = size-1; + size -= rsize; + bufp += rsize; + } + } + if (komma) fbattlerecord(b, f, buf); + } + + if (bdebug && s->faction) { + if (f_get_alliance(s->faction)) { + fprintf(bdebug, "##### %s (%s/%d)\n", s->faction->name, itoa36(s->faction->no), + s->faction->alliance?s->faction->alliance->id:0); + } else { + fprintf(bdebug, "##### %s (%s)\n", s->faction->name, itoa36(s->faction->no)); + } + } + print_fighters(b, s); + } + + message_all(b, msg_separator); + + /* Besten Taktiker ermitteln */ + + b->max_tactics = 0; + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + if (cv_size(&s->leader.fighters)) { + b->max_tactics = MAX(b->max_tactics, s->leader.value); + } + } + + if (b->max_tactics > 0) { + for (s=b->sides;s!=b->sides+b->nsides;++s) { + if (s->leader.value == b->max_tactics) { + fighter *tf; + cv_foreach(tf, s->leader.fighters) { + unit *u = tf->unit; + message * m = NULL; + if (!is_attacker(tf)) { + m = msg_message("battle::tactics_lost", "unit", u); + } else { + m = msg_message("battle::tactics_won", "unit", u); + } + message_all(b, m); + msg_release(m); + } cv_next(tf); + } + } + } +} + +static int +weapon_weight(const weapon * w, boolean missile) +{ + if (missile == i2b(fval(w->type, WTF_MISSILE))) { + return w->attackskill + w->defenseskill; + } + return 0; +} + +fighter * +make_fighter(battle * b, unit * u, side * s1, boolean attack) +{ +#define WMAX 20 + weapon weapons[WMAX]; + int owp[WMAX]; + int dwp[WMAX]; + int w = 0; + region *r = b->region; + item * itm; + fighter *fig = NULL; + int i, tactics = eff_skill(u, SK_TACTICS, r); + side *s2; + int h; + int berserk; + int strongmen; + int speeded = 0, speed = 1; + boolean pr_aid = false; + int rest; + const group * g = NULL; + const attrib *a = a_find(u->attribs, &at_otherfaction); + const faction *stealthfaction = a?get_otherfaction(a):NULL; + unsigned int flags = 0; + + assert(u->number); + if (fval(u, UFL_ANON_FACTION)!=0) flags |= SIDE_STEALTH; + + if (!(AllianceAuto() & HELP_FIGHT) && fval(u, UFL_GROUP)) { + const attrib * agroup = a_find(u->attribs, &at_group); + if (agroup!=NULL) g = (const group*)agroup->data.v; + } + + /* Illusionen und Zauber kaempfen nicht */ + if (fval(u->race, RCF_ILLUSIONARY) || idle(u->faction) || u->number==0) + return NULL; + + if (s1==NULL) { + for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { + if (s2->faction == u->faction && s2->group==g) { +#ifdef SIMPLE_COMBAT + int s1flags = flags|SIDE_HASGUARDS; + int s2flags = s2->flags|SIDE_HASGUARDS; +#else + int s1flags = flags; + int s2flags = s2->flags; +#endif + if (s1flags==s2flags && s2->stealthfaction==stealthfaction) { + s1 = s2; + break; + } + } + } + + /* aliances are moved out of make_fighter and will be handled later */ + if (!s1) { + s1 = make_side(b, u->faction, g, flags, stealthfaction); + } + /* Zu diesem Zeitpunkt ist attacked noch 0, da die Einheit für noch + * keinen Kampf ausgewählt wurde (sonst würde ein fighter existieren) */ + } + fig = calloc(1, sizeof(struct fighter)); + + fig->next = s1->fighters; + s1->fighters = fig; + + fig->unit = u; + /* In einer Burg muß man a) nicht Angreifer sein, und b) drin sein, und + * c) noch Platz finden. d) menschanähnlich sein */ + if (attack) { + set_attacker(fig); + } else { + building * b = u->building; + if (b && b->sizeleft>=u->number && playerrace(u->race)) { + fig->building = b; + fig->building->sizeleft -= u->number; + } + } + fig->status = u->status; + fig->side = s1; + fig->alive = u->number; + fig->side->alive += u->number; + fig->side->battle->alive += u->number; + fig->catmsg = -1; + + /* Freigeben nicht vergessen! */ + fig->person = calloc(fig->alive, sizeof(struct person)); + + h = u->hp / u->number; + assert(h); + rest = u->hp % u->number; + + /* Effekte von Sprüchen */ + + { + static const curse_type * speed_ct; + speed_ct = ct_find("speed"); + if (speed_ct) { + curse *c = get_curse(u->attribs, speed_ct); + if (c) { + speeded = get_cursedmen(u, c); + speed = curse_geteffect_int(c); + } + } + } + + /* Effekte von Alchemie */ + berserk = get_effect(u, oldpotiontype[P_BERSERK]); + /* change_effect wird in ageing gemacht */ + + /* Effekte von Artefakten */ + strongmen = MIN(fig->unit->number, get_item(u, I_TROLLBELT)); + + /* Hitpoints, Attack- und Defence-Boni für alle Personen */ + for (i = 0; i < fig->alive; i++) { + assert(i < fig->unit->number); + fig->person[i].hp = h; + if (i < rest) + fig->person[i].hp++; + + if (i < speeded) + fig->person[i].speed = speed; + else + fig->person[i].speed = 1; + + if (i < berserk) { + fig->person[i].attack++; + } + /* Leute mit einem Aid-Prayer bekommen +1 auf fast alles. */ + if (pr_aid) { + fig->person[i].attack++; + fig->person[i].defence++; + fig->person[i].damage++; + fig->person[i].damage_rear++; + fig->person[i].flags |= FL_COURAGE; + } + /* Leute mit Kraftzauber machen +2 Schaden im Nahkampf. */ + if (i < strongmen) { + fig->person[i].damage += 2; + } + } + + /* Für alle Waffengattungne wird bestimmt, wie viele der Personen mit + * ihr kämpfen könnten, und was ihr Wert darin ist. */ + if (u->race->battle_flags & BF_EQUIPMENT) { + int oi=0, di=0; + for (itm=u->items;itm && w!=WMAX;itm=itm->next) { + const weapon_type * wtype = resource2weapon(itm->type->rtype); + if (wtype==NULL || itm->number==0) continue; + weapons[w].attackskill = weapon_skill(wtype, u, true); + weapons[w].defenseskill = weapon_skill(wtype, u, false); + if (weapons[w].attackskill>=0 || weapons[w].defenseskill>=0) { + weapons[w].type = wtype; + weapons[w].used = 0; + weapons[w].count = itm->number; + ++w; + } + assert(w!=WMAX); + } + fig->weapons = calloc(sizeof(weapon), w+1); + memcpy(fig->weapons, weapons, w*sizeof(weapon)); + + for (i=0; i!=w; ++i) { + int j, o=0, d=0; + for (j=0; j!=i; ++j) { + if (weapon_weight(fig->weapons+j, true)>=weapon_weight(fig->weapons+i, true)) ++d; + if (weapon_weight(fig->weapons+j, false)>=weapon_weight(fig->weapons+i, false)) ++o; + } + for (j=i+1; j!=w; ++j) { + if (weapon_weight(fig->weapons+j, true)>weapon_weight(fig->weapons+i, true)) ++d; + if (weapon_weight(fig->weapons+j, false)>weapon_weight(fig->weapons+i, false)) ++o; + } + owp[o] = i; + dwp[d] = i; + } + /* jetzt enthalten owp und dwp eine absteigend schlechter werdende Liste der Waffen + * oi and di are the current index to the sorted owp/dwp arrays + * owp, dwp contain indices to the figther::weapons array */ + + /* hand out melee weapons: */ + for (i=0; i!=fig->alive; ++i) { + int wpless = weapon_skill(NULL, u, true); + while (oi!=w && (fig->weapons[owp[oi]].used==fig->weapons[owp[oi]].count || fval(fig->weapons[owp[oi]].type, WTF_MISSILE))) { + ++oi; + } + if (oi==w) break; /* no more weapons available */ + if (weapon_weight(fig->weapons+owp[oi], false)<=wpless) { + continue; /* we fight better with bare hands */ + } + fig->person[i].melee = &fig->weapons[owp[oi]]; + ++fig->weapons[owp[oi]].used; + } + /* hand out missile weapons (from back to front, in case of mixed troops). */ + for (di=0, i=fig->alive; i--!=0;) { + while (di!=w && (fig->weapons[dwp[di]].used==fig->weapons[dwp[di]].count || !fval(fig->weapons[dwp[di]].type, WTF_MISSILE))) { + ++di; + } + if (di==w) break; /* no more weapons available */ + if (weapon_weight(fig->weapons+dwp[di], true)>0) { + fig->person[i].missile = &fig->weapons[dwp[di]]; + ++fig->weapons[dwp[di]].used; + } + } + } + + s1->size[statusrow(fig->status)] += u->number; + s1->size[SUM_ROW] += u->number; + if (u->race->battle_flags & BF_NOBLOCK) { + s1->nonblockers[statusrow(fig->status)] += u->number; + } + + if (fig->unit->race->flags & RCF_HORSE) { + fig->horses = fig->unit->number; + fig->elvenhorses = 0; + } else { + static const item_type * it_charger = 0; + if (it_charger==0) { + it_charger = it_find("charger"); + if (!it_charger) { + it_charger = it_find("horse"); + } + } + fig->horses = i_get(u->items, it_charger); + fig->elvenhorses = get_item(u, I_ELVENHORSE); + } + + if (u->race->battle_flags & BF_EQUIPMENT) { + for (itm=u->items; itm; itm=itm->next) { + if (itm->type->rtype->atype) { + if (i_canuse(u, itm->type)) { + struct armor * adata = malloc(sizeof(armor)), **aptr; + adata->atype = itm->type->rtype->atype; + adata->count = itm->number; + for (aptr=&fig->armors;*aptr;aptr=&(*aptr)->next) { + if (adata->atype->prot > (*aptr)->atype->prot) break; + } + adata->next = *aptr; + *aptr = adata; + } + } + } + } + + + /* Jetzt muß noch geschaut werden, wo die Einheit die jeweils besten + * Werte hat, das kommt aber erst irgendwo später. Ich entscheide + * wärend des Kampfes, welche ich nehme, je nach Gegner. Deswegen auch + * keine addierten boni. */ + + /* Zuerst mal die Spezialbehandlung gewisser Sonderfälle. */ + fig->magic = eff_skill(u, SK_MAGIC, r); + + if (fig->horses) { + if (!fval(r->terrain, CAVALRY_REGION) || r_isforest(r) + || eff_skill(u, SK_RIDING, r) < CavalrySkill() || u->race == new_race[RC_TROLL] || fval(u, UFL_WERE)) + fig->horses = 0; + } + + if (fig->elvenhorses) { + if (eff_skill(u, SK_RIDING, r) < 5 || u->race == new_race[RC_TROLL] || fval(u, UFL_WERE)) + fig->elvenhorses = 0; + } + + /* Schauen, wie gut wir in Taktik sind. */ + if (tactics > 0 && u->race == new_race[RC_INSECT]) + tactics -= 1 - (int) log10(fig->side->size[SUM_ROW]); +#ifdef TACTICS_MODIFIER + if (tactics > 0 && statusrow(fig->status) == FIGHT_ROW) + tactics += TACTICS_MODIFIER; + if (tactics > 0 && statusrow(fig->status) > BEHIND_ROW) { + tactics -= TACTICS_MODIFIER; + } +#endif + + if (tactics > 0) { + int bonus = 0; + + for (i = 0; i < fig->alive; i++) { + int p_bonus = 0; + int rnd; + + do { + rnd = rng_int()%100; + if (rnd >= 40 && rnd <= 69) + p_bonus += 1; + else if (rnd <= 89) + p_bonus += 2; + else + p_bonus += 3; + } while(rnd >= 97); + bonus = MAX(p_bonus, bonus); + } + tactics += bonus; + } + + add_tactics(&fig->side->leader, fig, tactics); + ++b->nfighters; + return fig; +} + + +static int +join_battle(battle * b, unit * u, boolean attack, fighter ** cp) +{ + side * s; + fighter *c = NULL; + + if (!attack) { + attrib * a = a_find(u->attribs, &at_fleechance); + if (a!=NULL) { + if (rng_double()<=a->data.flt) { + *cp = NULL; + return false; + } + } + } + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *fig; + if (s->faction==u->faction) { + for (fig=s->fighters;fig;fig=fig->next) { + if (fig->unit == u) { + c = fig; + if (attack) { + set_attacker(fig); + } + break; + } + } + } + } + if (!c) { + *cp = make_fighter(b, u, NULL, attack); + return *cp!=NULL; + } + *cp = c; + return false; +} + +static const char * +simplename(region * r) +{ + int i; + static char name[17]; + const char * cp = rname(r, default_locale); + for (i=0;*cp && i!=16;++i, ++cp) { + int c = *(unsigned char *)cp; + while (c && !isalpha(c) && !isxspace(c)) { + ++cp; + c = *(unsigned char*)cp; + } + if (isxspace(c)) name[i] = '_'; + else name[i] = *cp; + if (c==0) break; + } + name[i]=0; + return name; +} + +static battle * +make_battle(region * r) +{ + battle *b = calloc(1, sizeof(struct battle)); + unit *u; + bfaction * bf; + static int max_fac_no = 0; /* need this only once */ + + if (battledebug) { + char zText[MAX_PATH]; + char zFilename[MAX_PATH]; + sprintf(zText, "%s/battles", basepath()); + makedir(zText, 0700); + sprintf(zFilename, "%s/battle-%d-%s.log", zText, obs_count, simplename(r)); + bdebug = fopen(zFilename, "w"); + if (!bdebug) log_error(("battles cannot be debugged\n")); + else { + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + fwrite(utf8_bom, 1, 3, bdebug); + fprintf(bdebug, "In %s findet ein Kampf stattactics:\n", rname(r, default_locale)); + } + obs_count++; + } + + b->region = r; + b->plane = getplane(r); + /* Finde alle Parteien, die den Kampf beobachten können: */ + for (u = r->units; u; u=u->next) { + if (u->number > 0) { + if (!fval(u->faction, FFL_MARK)) { + fset(u->faction, FFL_MARK); + for (bf=b->factions;bf;bf=bf->next) { + if (bf->faction==u->faction) break; + } + if (!bf) { + bf = calloc(sizeof(bfaction), 1); + ++b->nfactions; + bf->faction = u->faction; + bf->next = b->factions; + b->factions = bf; + } + } + } + } + + for (bf=b->factions;bf;bf=bf->next) { + faction * f = bf->faction; + max_fac_no = MAX(max_fac_no, f->no); + freset(f, FFL_MARK); + } + return b; +} + +static void +free_side(side * si) +{ + cv_kill(&si->leader.fighters); +} + +static void +free_fighter(fighter * fig) +{ + while (fig->loot) { + i_free(i_remove(&fig->loot, fig->loot)); + } + while (fig->armors) { + armor * a = fig->armors; + fig->armors = a->next; + free(a); + } + free(fig->person); + free(fig->weapons); + +} + +static void +free_battle(battle * b) +{ + side *s; + meffect *meffect; + int max_fac_no = 0; + + if (bdebug) { + fclose(bdebug); + } + + while (b->factions) { + bfaction * bf = b->factions; + faction * f = bf->faction; + b->factions = bf->next; + max_fac_no = MAX(max_fac_no, f->no); + free(bf); + } + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *fnext = s->fighters; + while (fnext) { + fighter *fig = fnext; + fnext = fig->next; + free_fighter(fig); + free(fig); + } + free_side(s); + } + cv_kill(&b->leaders); + cv_foreach(meffect, b->meffects) { + free(meffect); + } + cv_next(meffect); + cv_kill(&b->meffects); +} + +static int * +get_alive(side * s) +{ +#if 0 + static int alive[NUMROWS]; + fighter *fig; + memset(alive, 0, NUMROWS * sizeof(int)); + for (fig=s->fighters;fig;fig=fig->next) { + if (fig->alive>0) { + int row = statusrow(fig); + alive[row] += fig->alive; + } + } + return alive; +#endif + return s->size; +} + +static int +battle_report(battle * b) +{ + side *s, *s2; + boolean cont = false; + boolean komma; + bfaction *bf; + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + if (s->alive-s->removed > 0) { + for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { + if (s2->alive-s2->removed > 0 && enemy(s, s2)) { + cont = true; + break; + } + } + if (cont) break; + } + } + + if (verbosity>0) log_stdio(stdout, " %d", b->turn); + fflush(stdout); + + for (bf=b->factions;bf;bf=bf->next) { + faction * fac = bf->faction; + char buf[32*MAXSIDES]; + char * bufp = buf; + int bytes; + size_t size = sizeof(buf) - 1; + message * m; + + message_faction(b, fac, msg_separator); + + if (cont) m = msg_message("battle::lineup", "turn", b->turn); + else m = msg_message("battle::after", ""); + message_faction(b, fac, m); + msg_release(m); + + komma = false; + for (s=b->sides;s!=b->sides+b->nsides;++s) { + if (s->alive) { + int r, k = 0, * alive = get_alive(s); + int l = FIGHT_ROW; + const char * abbrev = seematrix(fac, s)?sideabkz(s, false):"-?-"; + const char * loc_army = LOC(fac->locale, "battle_army"); + char buffer[32]; + + if (komma) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + snprintf(buffer, sizeof(buffer), "%s %2d(%s): ", + loc_army, army_index(s), abbrev); + buffer[sizeof(buffer)-1] = 0; + + bytes = (int)strlcpy(bufp, buffer, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + for (r=FIGHT_ROW;r!=NUMROWS;++r) { + if (alive[r]) { + if (l!=FIGHT_ROW) { + bytes = (int)strlcpy(bufp, "+", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + while (k--) { + bytes = (int)strlcpy(bufp, "0+", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + sprintf(buffer, "%d", alive[r]); + + bytes = (int)strlcpy(bufp, buffer, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + k = 0; + l = r+1; + } else ++k; + } + + komma = true; + } + } + *bufp = 0; + fbattlerecord(b, fac, buf); + } + return cont; +} + +static void +join_allies(battle * b) +{ + region *r = b->region; + unit *u; + side *s, *s_end = b->sides+b->nsides; + /* make_side might be adding a new faction, but it adds them to the end + * of the list, so we're safe in our iteration here if we remember the end + * up front. */ + for (u=r->units;u;u=u->next) { + /* Was ist mit Schiffen? */ + if (u->status != ST_FLEE && u->status != ST_AVOID && !fval(u, UFL_LONGACTION|UFL_ISNEW) && u->number > 0) { + faction * f = u->faction; + fighter * c = NULL; + + for (s=b->sides;s!=s_end;++s) { + side * se; + /* Wenn alle attackierten noch FFL_NOAID haben, dann kämpfe nicht mit. */ + if (fval(s->faction, FFL_NOAID)) continue; + if (s->faction!=f) { + /* Wenn wir attackiert haben, kommt niemand mehr hinzu: */ + if (s->bf->attacker) continue; + /* alliiert müssen wir schon sein, sonst ist's eh egal : */ + if (!alliedunit(u, s->faction, HELP_FIGHT)) continue; + /* wenn die partei verborgen ist, oder gar eine andere + * vorgespiegelt wird, und er sich uns gegenüber nicht zu + * erkennen gibt, helfen wir ihm nicht */ + if (s->stealthfaction){ + if(!allysfm(s, u->faction, HELP_FSTEALTH)) { + continue; + } + } + } + /* einen alliierten angreifen dürfen sie nicht, es sei denn, der + * ist mit einem alliierten verfeindet, der nicht attackiert + * hat: */ + for (se=b->sides;se!=s_end;++se) { + if (u->faction==se->faction) continue; + if (alliedunit(u, se->faction, HELP_FIGHT) && !se->bf->attacker) { + continue; + } + if (enemy(s, se)) break; + } + if (se==s_end) continue; + /* Wenn die Einheit belagert ist, muß auch einer der Alliierten belagert sein: */ + if (besieged(u)) { + fighter *ally; + for (ally = s->fighters; ally; ally=ally->next) { + if (besieged(ally->unit)) { + break; + } + } + if (ally==NULL) continue; + } + /* keine Einwände, also soll er mitmachen: */ + if (c==NULL) { + if (join_battle(b, u, false, &c)) { + if (battledebug) { + fprintf(bdebug, "%s joins to help %s against %s.\n", + unitname(u), factionname(s->faction), + factionname(se->faction)); + } + } else if (c==NULL) { + continue; + } + } + + /* the enemy of my friend is my enemy: */ + for (se=b->sides;se!=s_end;++se) { + if (se->faction!=u->faction && enemy(s, se)) { + if (set_enemy(se, c->side, false) && battledebug) { + fprintf(bdebug, "%u/%s hates %u/%s because they are enemies with %u/%s.\n", + c->side->index, sidename(c->side), + se->index, sidename(se), + s->index, sidename(s)); + } + } + } + } + } + } + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + int si; + side * sa; + faction * f = s->faction; + + /* Den Feinden meiner Feinde gebe ich Deckung (gegen gemeinsame Feinde): */ + for (si=0; s->enemies[si]; ++si) { + side * se = s->enemies[si]; + int ai; + for (ai=0; se->enemies[ai]; ++ai) { + side * as = se->enemies[ai]; + if (as==s || !enemy(as, s)) { + set_friendly(as, s); + } + } + } + + for (sa=s+1;sa!=b->sides+b->nsides;++sa) { + plane * pl = rplane(r); + if (enemy(s, sa)) continue; + if (friendly(s, sa)) continue; + if (!alliedgroup(pl, f, sa->faction, f->allies, HELP_FIGHT)) continue; + if (!alliedgroup(pl, sa->faction, f, sa->faction->allies, HELP_FIGHT)) continue; + + set_friendly(s, sa); + } + } +} + +static void +flee(const troop dt) +{ + fighter * fig = dt.fighter; + unit * u = fig->unit; + +#ifndef SIMPLE_ESCAPE + int carry = personcapacity(u) - u->race->weight; + int money; + + item ** ip = &u->items; + + while (*ip) { + item * itm = *ip; + const item_type * itype = itm->type; + int keep = 0; + + if (fval(itype, ITF_ANIMAL)) { + /* Regeländerung: Man muß das Tier nicht reiten können, + * um es vom Schlachtfeld mitzunehmen, ist ja nur + * eine Region weit. * */ + keep = MIN(1, itm->number); + /* da ist das weight des tiers mit drin */ + carry += itype->capacity - itype->weight; + } else if (itm->type->weight <= 0) { + /* if it doesn'tactics weigh anything, it won'tactics slow us down */ + keep = itm->number; + } + /* jeder troop nimmt seinen eigenen Teil der Sachen mit */ + if (keep>0){ + if (itm->number==keep) { + i_add(&fig->run.items, i_remove(ip, itm)); + } else { + item *run_itm = i_new(itype, keep); + i_add(&fig->run.items, run_itm); + i_change(ip, itype, -keep); + } + } + if (*ip==itm) ip = &itm->next; + } + + /* we will take money with us */ + money = get_money(u); + /* nur ganzgeflohene/resttote Einheiten verlassen die Region */ + if (money > carry) money = carry; + if (money > 0) { + i_change(&u->items, i_silver, -money); + i_change(&fig->run.items, i_silver, +money); + } +#endif /* SIMPLE_ESCAPE */ + + fig->run.hp += fig->person[dt.index].hp; + ++fig->run.number; + + setguard(u, GUARD_NONE); + + kill_troop(dt); +} + +static boolean +init_battle(region * r, battle **bp) +{ + battle * b = NULL; + unit * u; + boolean fighting = false; + + /* list_foreach geht nicht, wegen flucht */ + for (u = r->units; u != NULL; u = u->next) { + if (fval(u, UFL_LONGACTION)) continue; + if (u->number > 0) { + order * ord; + + for (ord=u->orders;ord;ord=ord->next) { + static boolean init = false; + static const curse_type * peace_ct, * slave_ct, * calm_ct; + + if (!init) { + init = true; + peace_ct = ct_find("peacezone"); + slave_ct = ct_find("slavery"); + calm_ct = ct_find("calmmonster"); + } + if (get_keyword(ord) == K_ATTACK) { + unit *u2; + fighter *c1, *c2; + ship * lsh = NULL; + plane * pl = rplane(r); + + if (pl && fval(pl, PFL_NOATTACK)) { + cmistake(u, ord, 271, MSG_BATTLE); + continue; + } + + if ((u->race->battle_flags&BF_CANATTACK) == 0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_no_attack", "race", u->race)); + continue; + } + /** + ** Fehlerbehandlung Angreifer + **/ + if (LongHunger(u)) { + cmistake(u, ord, 225, MSG_BATTLE); + continue; + } + + if (u->status == ST_AVOID || u->status == ST_FLEE) { + cmistake(u, ord, 226, MSG_BATTLE); + continue; + } + + /* ist ein Flüchtling aus einem andern Kampf */ + if (fval(u, UFL_LONGACTION)) continue; + + if (peace_ct && curse_active(get_curse(r->attribs, peace_ct))) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "peace_active", "")); + continue; + } + + if (slave_ct && curse_active(get_curse(u->attribs, slave_ct))) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "slave_active", "")); + continue; + } + + if ((u->ship != NULL && !fval(r->terrain, SEA_REGION)) || (lsh = leftship(u))!=NULL) { + if (is_guarded(r, u, GUARD_TRAVELTHRU)) { + if (lsh) { + cmistake(u, ord, 234, MSG_BATTLE); + } else { + /* Fehler: "Das Schiff muß erst verlassen werden" */ + cmistake(u, ord, 19, MSG_BATTLE); + } + continue; + } + } + + /* Ende Fehlerbehandlung Angreifer */ + + init_tokens(ord); + skip_token(); + /* attackierte Einheit ermitteln */ + u2 = getunit(r, u->faction); + + /* Beginn Fehlerbehandlung */ + /* Fehler: "Die Einheit wurde nicht gefunden" */ + if (!u2 || u2->number == 0 || !cansee(u->faction, u->region, u2, 0)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + continue; + } + /* Fehler: "Die Einheit ist eine der unsrigen" */ + if (u2->faction == u->faction) { + cmistake(u, ord, 45, MSG_BATTLE); + continue; + } + /* Fehler: "Die Einheit ist mit uns alliert" */ + if (alliedunit(u, u2->faction, HELP_FIGHT)) { + cmistake(u, ord, 47, MSG_BATTLE); + continue; + } + if (IsImmune(u2->faction)) { + add_message(&u->faction->msgs, + msg_feedback(u, u->thisorder, "newbie_immunity_error", "turns", NewbieImmunity())); + continue; + } + /* Fehler: "Die Einheit ist mit uns alliert" */ + + if (calm_ct) { + attrib * a = a_find(u->attribs, &at_curse); + boolean calm = false; + while (a && a->type==&at_curse) { + curse * c = (curse *)a->data.v; + if (c->type==calm_ct && curse_geteffect(c)==u2->faction->subscription) { + if (curse_active(c)) { + calm = true; + break; + } + } + a = a->next; + } + if (calm) { + cmistake(u, ord, 47, MSG_BATTLE); + continue; + } + } + /* Ende Fehlerbehandlung */ + if (b==NULL) { + unit * utmp; + for (utmp=r->units; utmp!=NULL; utmp=utmp->next) { + fset(utmp->faction, FFL_NOAID); + } + b = make_battle(r); + } + if (join_battle(b, u, true, &c1)) { + if (battledebug) { + fprintf(bdebug, "%s joins by attacking %s.\n", + unitname(u), unitname(u2)); + } + } + if (join_battle(b, u2, false, &c2)) { + if (battledebug) { + fprintf(bdebug, "%s joins because of an attack from %s.\n", + unitname(u2), unitname(u)); + } + } + + /* Hat die attackierte Einheit keinen Noaid-Status, + * wird das Flag von der Faction genommen, andere + * Einheiten greifen ein. */ + if (!fval(u2, UFL_NOAID)) freset(u2->faction, FFL_NOAID); + + if (c1!=NULL && c2!=NULL) { + /* Merken, wer Angreifer ist, für die Rückzahlung der + * Präcombataura bei kurzem Kampf. */ + c1->side->bf->attacker = true; + + if (set_enemy(c1->side, c2->side, true) && battledebug) { + fprintf(bdebug, "%u/%s hates %u/%s because they attacked them.\n", + c2->side->index, sidename(c2->side), + c1->side->index, sidename(c1->side)); + } + fighting = true; + } + } + } + } + } + *bp = b; + return fighting; +} + +static void +battle_stats(FILE * F, battle * b) +{ + typedef struct stat_info { + struct stat_info * next; + const weapon_type * wtype; + int level; + int number; + } stat_info; + side * s; + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter * df; + stat_info * stats = NULL, * stat; + + for (df = s->fighters; df; df = df->next) { + unit *du = df->unit; + troop dt; + stat_info * slast = NULL; + + dt.fighter = df; + for (dt.index=0;dt.index!=du->number;++dt.index) { + weapon * wp = preferred_weapon(dt, true); + int level = wp?wp->attackskill:0; + const weapon_type * wtype = wp?wp->type:NULL; + stat_info ** slist = &stats; + + if (slast && slast->wtype==wtype && slast->level==level) { + ++slast->number; + continue; + } + while (*slist && (*slist)->wtype!=wtype) { + slist = &(*slist)->next; + } + while (*slist && (*slist)->wtype==wtype && (*slist)->level>level) { + slist = &(*slist)->next; + } + stat = *slist; + if (stat==NULL || stat->wtype!=wtype || stat->level!=level) { + stat = calloc(1, sizeof(stat_info)); + stat->wtype = wtype; + stat->level = level; + stat->next = *slist; + *slist = stat; + } + slast = stat; + ++slast->number; + } + } + + fprintf(F, "##STATS## Heer %u - %s:\n", army_index(s), factionname(s->faction)); + for (stat=stats;stat!=NULL;stat=stat->next) { + fprintf(F, "%s %u : %u\n", stat->wtype?stat->wtype->itype->rtype->_name[0]:"none", stat->level, stat->number); + } + freelist(stats); + } +} + +/** execute one round of attacks + * fig->fighting is used to determine who attacks, not fig->alive, since + * the latter may be influenced by attacks that already took place. + */ +static void +battle_attacks(battle * b) +{ + side * s; + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *fig; + + if (b->turn!=0 || (b->max_tactics > 0 && get_tactics(s, NULL) == b->max_tactics)) { + for (fig=s->fighters;fig;fig=fig->next) { + + /* ist in dieser Einheit noch jemand handlungsfähig? */ + if (fig->fighting <= 0) continue; + + /* Handle the unit's attack on someone */ + do_attack(fig); + } + } + } +} + +/** updates the number of attacking troops in each fighter struct. + * this has to be calculated _before_ the actual attacks take + * place because otherwise dead troops would not strike in the + * round they die. */ +static void +battle_update(battle * b) +{ + side * s; + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *fig; + for (fig=s->fighters;fig;fig=fig->next) { + fig->fighting = fig->alive - fig->removed; + } + } +} + +/** attempt to flee from battle before the next round begins + * there's a double attempt before the first round, but only + * one attempt before round zero, the potential tactics round. */ +static void +battle_flee(battle * b) +{ + int attempt, flee_ops = 1; + + if (b->turn==1) + flee_ops = 2; + + for (attempt=1;attempt<=flee_ops;++attempt) { + side * s; + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *fig; + for (fig=s->fighters;fig;fig=fig->next) { + unit *u = fig->unit; + troop dt; + int runners = 0; + /* Flucht nicht bei mehr als 600 HP. Damit Wyrme tötbar bleiben. */ + int runhp = MIN(600,(int)(0.9+unit_max_hp(u)*hpflee(u->status))); + + if (u->ship && fval(u->region->terrain, SEA_REGION)) { + /* keine Flucht von Schiffen auf hoher See */ + continue; + } + if (fval(u->race, RCF_UNDEAD) || u->race == new_race[RC_SHADOWKNIGHT]) { + /* Untote fliehen nicht. Warum eigentlich? */ + continue; + } + + dt.fighter = fig; +#ifndef SIMPLE_ESCAPE + if (!fig->run.region) fig->run.region = fleeregion(u); + if (!fig->run.region) continue; +#endif /* SIMPLE_ESCAPE */ + dt.index = fig->alive - fig->removed; + while (s->size[SUM_ROW] && dt.index != 0) { + double ispaniced = 0.0; + --dt.index; + assert(dt.index>=0 && dt.indexunit->number); + assert(fig->person[dt.index].hp > 0); + + /* Versuche zu fliehen, wenn + * - Kampfstatus fliehe + * - schwer verwundet und nicht erste kampfrunde + * - in panik (Zauber) + * aber nicht, wenn der Zaubereffekt Held auf dir liegt! + */ + switch (u->status) { + case ST_FLEE: + break; + default: + if ((fig->person[dt.index].flags & FL_HIT) == 0) continue; + if (b->turn<=1) continue; + if (fig->person[dt.index].hp <= runhp) break; + if (fig->person[dt.index].flags & FL_PANICED) { + if ((fig->person[dt.index].flags & FL_COURAGE)==0) break; + } + continue; + } + + if (fig->person[dt.index].flags & FL_PANICED) { + ispaniced = EFFECT_PANIC_SPELL; + } + if (chance(MIN(fleechance(u)+ispaniced, 0.90))) { + ++runners; + flee(dt); + } + } + if (bdebug && runners > 0) { + fprintf(bdebug, "Fleeing: %d from %s\n", runners, itoa36(fig->unit->no)); + } + } + } + } +} + +void +do_battle(region * r) +{ + battle *b = NULL; + boolean fighting = false; + ship * sh; + building *bu; + static int init_rules = 0; + + if (!init_rules) { + static_rules(); + init_rules = 1; + } + if (msg_separator==NULL) { + msg_separator = msg_message("battle::section", ""); + } + + fighting = init_battle(r, &b); + + if (b==NULL) return; + + /* Bevor wir die alliierten hineinziehen, sollten wir schauen, * + * Ob jemand fliehen kann. Dann erübrigt sich das ganze ja + * vielleicht schon. */ + print_header(b); + if (!fighting) { + /* Niemand mehr da, Kampf kann nicht stattfinden. */ + message * m = msg_message("battle::aborted", ""); + message_all(b, m); + msg_release(m); + free_battle(b); + free(b); + return; + } + join_allies(b); + make_heroes(b); + + /* Alle Mann raus aus der Burg! */ + for (bu=r->buildings; bu!=NULL; bu=bu->next) bu->sizeleft = bu->size; + + /* make sure no ships are damaged initially */ + for (sh=r->ships; sh; sh=sh->next) freset(sh, SF_DAMAGED); + + /* Gibt es eine Taktikrunde ? */ + if (cv_size(&b->leaders)) { + b->turn = 0; + b->has_tactics_turn = true; + } else { + b->turn = 1; + b->has_tactics_turn = false; + } + + if (b->region->flags & RF_COMBATDEBUG) battle_stats(bdebug, b); + + /* PRECOMBATSPELLS */ + do_combatmagic(b, DO_PRECOMBATSPELL); + + print_stats(b); /* gibt die Kampfaufstellung aus */ + if (verbosity>0) log_stdio(stdout, "%s (%d, %d) : ", rname(r, default_locale), r->x, r->y); + + for (;battle_report(b) && b->turn<=max_turns;++b->turn) { + if (bdebug) { + fprintf(bdebug, "*** Turn: %d\n", b->turn); + } + battle_flee(b); + battle_update(b); + battle_attacks(b); + + } + + if (verbosity>0) log_stdio(stdout, "\n"); + + /* Auswirkungen berechnen: */ + aftermath(b); + /* Hier ist das Gefecht beendet, und wir können die + * Hilfsstrukturen * wieder löschen: */ + + if (b) { + free_battle(b); + free(b); + } +} diff --git a/src/kernel/battle.h b/src/kernel/battle.h index 4bc054818..da1930595 100644 --- a/src/kernel/battle.h +++ b/src/kernel/battle.h @@ -1,271 +1,271 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_BATTLE -#define H_KRNL_BATTLE -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#define SHOW_KILLS -#undef SMALL_BATTLE_MESSAGES - - /** more defines **/ -#define FS_ENEMY 1 -#define FS_HELP 2 - - /***** Verteidigungslinien. - * Eressea hat 4 Verteidigungslinien. 1 ist vorn, 5. enthält Summen - */ - -#define NUMROWS 5 -#define SUM_ROW 0 -#define FIGHT_ROW 1 -#define BEHIND_ROW 2 -#define AVOID_ROW 3 -#define FLEE_ROW 4 -#define LAST_ROW (NUMROWS-1) -#define FIRST_ROW FIGHT_ROW -#define MAXSIDES 192 /* if there are ever more than this, we're fucked. */ - - struct message; - - typedef struct bfaction { - struct bfaction * next; - struct side * sides; - struct faction *faction; -#ifndef SIMPLE_COMBAT - int lastturn; /* last time this struct faction was involved in combat */ -#endif - boolean attacker; - } bfaction; - - typedef struct tactics { - cvector fighters; - int value; - } tactics; - -#define SIDE_STEALTH 1<<0 -#ifdef SIMPLE_COMBAT -#define SIDE_HASGUARDS 1<<1 -#endif - typedef struct side { - struct side * nextF; /* next army of same faction */ - struct battle * battle; - struct bfaction * bf; /* battle info that goes with the faction */ - struct faction * faction; /* cache optimization for bf->faction */ - const struct group * group; - struct tactics leader; /* this army's best tactician */ -# define E_ENEMY 1 -# define E_FRIEND 2 -# define E_ATTACKING 4 - unsigned char relations[MAXSIDES]; - struct side * enemies[MAXSIDES]; - struct fighter * fighters; - int index; /* Eintrag der Fraktion in b->matrix/b->enemies */ - int size[NUMROWS]; /* Anzahl Personen in Reihe X. 0 = Summe */ - int nonblockers[NUMROWS]; /* Anzahl nichtblockierender Kämpfer, z.B. Schattenritter. */ - int alive; /* Die Partei hat den Kampf verlassen */ - int removed; /* stoned */ - int flee; - int dead; - int casualties; /* those dead that were real people, not undead! */ - int healed; - unsigned int flags; - const struct faction *stealthfaction; - } side; - - typedef struct battle { - cvector leaders; - struct region *region; - struct plane *plane; - bfaction * factions; - int nfactions; - int nfighters; - side sides[MAXSIDES]; - int nsides; - cvector meffects; - int max_tactics; - int turn; - boolean has_tactics_turn; - int keeploot; - boolean reelarrow; - int alive; -#ifdef SMALL_BATTLE_MESSAGES - boolean small; -#endif -#define FASTROW -#ifdef FASTROW - struct { - const struct side * as; - const struct side * vs; - int alive; - int row; - int result; - } rowcache; -#endif -#define FASTCOUNT -#ifdef FASTCOUNT - struct { - struct side * side; - int status; - int alive; - int minrow, maxrow; - int enemies[8]; - } fast; -#endif - } battle; - - typedef struct weapon { - int count, used; - const struct weapon_type * type; - int attackskill : 8; - int defenseskill : 8; - } weapon; - - /*** fighter::person::flags ***/ -#define FL_TIRED 1 -#define FL_DAZZLED 2 /* durch Untote oder Dämonen eingeschüchtert */ -#define FL_PANICED 4 -#define FL_COURAGE 8 /* Helden fliehen nie */ -#define FL_SLEEPING 16 -#define FL_STUNNED 32 /* eine Runde keinen Angriff */ -#define FL_HIT 64 /* the person at attacked */ - - typedef struct troop { - struct fighter *fighter; - int index; - } troop; - - typedef struct armor { - struct armor * next; - const struct armor_type * atype; - int count; - } armor; - - /*** fighter::flags ***/ -#define FIG_ATTACKER 1<<0 -#define FIG_NOLOOT 1<<1 - typedef struct fighter { - struct fighter * next; - struct side *side; - struct unit *unit; /* Die Einheit, die hier kämpft */ - struct building *building; /* Gebäude, in dem die Einheit evtl. steht */ - status_t status; /* Kampfstatus */ - struct weapon * weapons; - struct armor *armors; /* Anzahl Rüstungen jeden Typs */ - int alive; /* Anzahl der noch nicht Toten in der Einheit */ - int fighting; /* Anzahl der Kämpfer in der aktuellen Runde */ - int removed; /* Anzahl Kaempfer, die nicht tot sind, aber - aus dem Kampf raus sind (zB weil sie - versteinert wurden). Diese werden auch - in alive noch mitgezählt! */ - int magic; /* Magietalent der Einheit */ - int horses; /* Anzahl brauchbarer Pferde der Einheit */ - int elvenhorses; /* Anzahl brauchbarer Elfenpferde der Einheit */ - struct item * loot; - int catmsg; /* Merkt sich, ob Katapultmessage schon generiert. */ - struct person { - int hp; /* Trefferpunkte der Personen */ - int attack : 8; /* (Magie) Attackenbonus der Personen */ - int defence : 8; /* (Magie) Paradenbonus der Personen */ - int damage : 8; /* (Magie) Schadensbonus der Personen im Nahkampf */ - int damage_rear : 8; /* (Magie) Schadensbonus der Personen im Fernkampf */ - int flags : 8; /* (Magie) Diverse Flags auf Kämpfern */ - int speed : 8; /* (Magie) Geschwindigkeitsmultiplkator. */ - int reload : 4; /* Anzahl Runden, die die Waffe x noch laden muss. - * dahinter steckt ein array[RL_MAX] wenn er min. eine hat. */ - int last_action : 4; /* In welcher Runde haben wir zuletzt etwas getan */ - struct weapon * missile; /* missile weapon */ - struct weapon * melee; /* melee weapon */ - } * person; - unsigned int flags; - struct { - int number; /* number of people who fled */ - int hp; /* accumulated hp of fleeing people */ -#ifndef SIMPLE_ESCAPE - struct region *region; /* destination of fleeing people */ - struct item * items; /* items they take */ -#endif /* SIMPLE_ESCAPE */ - } run; -#ifndef SIMPLE_COMBAT - int action_counter; /* number of active actions the struct unit did in the fight */ -#endif /* SIMPLE_COMBAT */ -#ifdef SHOW_KILLS - int kills; - int hits; -#endif - } fighter; - - - /* schilde */ - - enum { - SHIELD_REDUCE, - SHIELD_ARMOR, - SHIELD_WIND, - SHIELD_BLOCK, - SHIELD_MAX - }; - - typedef struct meffect { - fighter *magician; /* Der Zauberer, der den Schild gezaubert hat */ - int typ; /* Wirkungsweise des Schilds */ - int effect; - int duration; - } meffect; - - extern const troop no_troop; - - extern void do_battle(struct region * r); - - /* for combat spells and special attacks */ - enum { SELECT_ADVANCE = 0x1, SELECT_DISTANCE = 0x2, SELECT_FIND = 0x4 }; - enum { ALLY_SELF, ALLY_ANY }; - - extern troop select_enemy(struct fighter * af, int minrow, int maxrow, int select); - extern troop select_ally(struct fighter * af, int minrow, int maxrow, int allytype); - - extern int count_enemies(struct battle * b, const struct fighter * af, int minrow, int maxrow, int select); - extern boolean terminate(troop dt, troop at, int type, const char *damage, boolean missile); - extern void message_all(battle * b, struct message * m); - extern int hits(troop at, troop dt, weapon * awp); - extern void damage_building(struct battle *b, struct building *bldg, int damage_abs); - extern struct cvector * fighters(struct battle *b, const struct side * vs, int minrow, int maxrow, int mask); - extern int count_allies(const struct side * as, int minrow, int maxrow, int select, int allytype); - extern int get_unitrow(const struct fighter * af, const struct side * vs); - extern boolean helping(const struct side * as, const struct side * ds); - extern void rmfighter(fighter *df, int i); -#ifndef SIMPLE_ESCAPE - extern struct region * fleeregion(const struct unit * u); -#endif - extern struct fighter * select_corpse(struct battle * b, struct fighter * af); - extern fighter * make_fighter(struct battle * b, struct unit * u, side * s, boolean attack); - extern int statusrow(int status); - extern void drain_exp(struct unit *u, int d); - extern void kill_troop(troop dt); - extern void remove_troop(troop dt); /* not the same as the badly named rmtroop */ - extern boolean is_attacker(const fighter * fig); - -#ifdef __cplusplus -} -#endif - -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_BATTLE +#define H_KRNL_BATTLE +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define SHOW_KILLS +#undef SMALL_BATTLE_MESSAGES + + /** more defines **/ +#define FS_ENEMY 1 +#define FS_HELP 2 + + /***** Verteidigungslinien. + * Eressea hat 4 Verteidigungslinien. 1 ist vorn, 5. enthält Summen + */ + +#define NUMROWS 5 +#define SUM_ROW 0 +#define FIGHT_ROW 1 +#define BEHIND_ROW 2 +#define AVOID_ROW 3 +#define FLEE_ROW 4 +#define LAST_ROW (NUMROWS-1) +#define FIRST_ROW FIGHT_ROW +#define MAXSIDES 192 /* if there are ever more than this, we're fucked. */ + + struct message; + + typedef struct bfaction { + struct bfaction * next; + struct side * sides; + struct faction *faction; +#ifndef SIMPLE_COMBAT + int lastturn; /* last time this struct faction was involved in combat */ +#endif + boolean attacker; + } bfaction; + + typedef struct tactics { + cvector fighters; + int value; + } tactics; + +#define SIDE_STEALTH 1<<0 +#ifdef SIMPLE_COMBAT +#define SIDE_HASGUARDS 1<<1 +#endif + typedef struct side { + struct side * nextF; /* next army of same faction */ + struct battle * battle; + struct bfaction * bf; /* battle info that goes with the faction */ + struct faction * faction; /* cache optimization for bf->faction */ + const struct group * group; + struct tactics leader; /* this army's best tactician */ +# define E_ENEMY 1 +# define E_FRIEND 2 +# define E_ATTACKING 4 + unsigned char relations[MAXSIDES]; + struct side * enemies[MAXSIDES]; + struct fighter * fighters; + int index; /* Eintrag der Fraktion in b->matrix/b->enemies */ + int size[NUMROWS]; /* Anzahl Personen in Reihe X. 0 = Summe */ + int nonblockers[NUMROWS]; /* Anzahl nichtblockierender Kämpfer, z.B. Schattenritter. */ + int alive; /* Die Partei hat den Kampf verlassen */ + int removed; /* stoned */ + int flee; + int dead; + int casualties; /* those dead that were real people, not undead! */ + int healed; + unsigned int flags; + const struct faction *stealthfaction; + } side; + + typedef struct battle { + cvector leaders; + struct region *region; + struct plane *plane; + bfaction * factions; + int nfactions; + int nfighters; + side sides[MAXSIDES]; + int nsides; + cvector meffects; + int max_tactics; + int turn; + boolean has_tactics_turn; + int keeploot; + boolean reelarrow; + int alive; +#ifdef SMALL_BATTLE_MESSAGES + boolean small; +#endif +#define FASTROW +#ifdef FASTROW + struct { + const struct side * as; + const struct side * vs; + int alive; + int row; + int result; + } rowcache; +#endif +#define FASTCOUNT +#ifdef FASTCOUNT + struct { + struct side * side; + int status; + int alive; + int minrow, maxrow; + int enemies[8]; + } fast; +#endif + } battle; + + typedef struct weapon { + int count, used; + const struct weapon_type * type; + int attackskill : 8; + int defenseskill : 8; + } weapon; + + /*** fighter::person::flags ***/ +#define FL_TIRED 1 +#define FL_DAZZLED 2 /* durch Untote oder Dämonen eingeschüchtert */ +#define FL_PANICED 4 +#define FL_COURAGE 8 /* Helden fliehen nie */ +#define FL_SLEEPING 16 +#define FL_STUNNED 32 /* eine Runde keinen Angriff */ +#define FL_HIT 64 /* the person at attacked */ + + typedef struct troop { + struct fighter *fighter; + int index; + } troop; + + typedef struct armor { + struct armor * next; + const struct armor_type * atype; + int count; + } armor; + + /*** fighter::flags ***/ +#define FIG_ATTACKER 1<<0 +#define FIG_NOLOOT 1<<1 + typedef struct fighter { + struct fighter * next; + struct side *side; + struct unit *unit; /* Die Einheit, die hier kämpft */ + struct building *building; /* Gebäude, in dem die Einheit evtl. steht */ + status_t status; /* Kampfstatus */ + struct weapon * weapons; + struct armor *armors; /* Anzahl Rüstungen jeden Typs */ + int alive; /* Anzahl der noch nicht Toten in der Einheit */ + int fighting; /* Anzahl der Kämpfer in der aktuellen Runde */ + int removed; /* Anzahl Kaempfer, die nicht tot sind, aber + aus dem Kampf raus sind (zB weil sie + versteinert wurden). Diese werden auch + in alive noch mitgezählt! */ + int magic; /* Magietalent der Einheit */ + int horses; /* Anzahl brauchbarer Pferde der Einheit */ + int elvenhorses; /* Anzahl brauchbarer Elfenpferde der Einheit */ + struct item * loot; + int catmsg; /* Merkt sich, ob Katapultmessage schon generiert. */ + struct person { + int hp; /* Trefferpunkte der Personen */ + int attack : 8; /* (Magie) Attackenbonus der Personen */ + int defence : 8; /* (Magie) Paradenbonus der Personen */ + int damage : 8; /* (Magie) Schadensbonus der Personen im Nahkampf */ + int damage_rear : 8; /* (Magie) Schadensbonus der Personen im Fernkampf */ + int flags : 8; /* (Magie) Diverse Flags auf Kämpfern */ + int speed : 8; /* (Magie) Geschwindigkeitsmultiplkator. */ + int reload : 4; /* Anzahl Runden, die die Waffe x noch laden muss. + * dahinter steckt ein array[RL_MAX] wenn er min. eine hat. */ + int last_action : 4; /* In welcher Runde haben wir zuletzt etwas getan */ + struct weapon * missile; /* missile weapon */ + struct weapon * melee; /* melee weapon */ + } * person; + unsigned int flags; + struct { + int number; /* number of people who fled */ + int hp; /* accumulated hp of fleeing people */ +#ifndef SIMPLE_ESCAPE + struct region *region; /* destination of fleeing people */ + struct item * items; /* items they take */ +#endif /* SIMPLE_ESCAPE */ + } run; +#ifndef SIMPLE_COMBAT + int action_counter; /* number of active actions the struct unit did in the fight */ +#endif /* SIMPLE_COMBAT */ +#ifdef SHOW_KILLS + int kills; + int hits; +#endif + } fighter; + + + /* schilde */ + + enum { + SHIELD_REDUCE, + SHIELD_ARMOR, + SHIELD_WIND, + SHIELD_BLOCK, + SHIELD_MAX + }; + + typedef struct meffect { + fighter *magician; /* Der Zauberer, der den Schild gezaubert hat */ + int typ; /* Wirkungsweise des Schilds */ + int effect; + int duration; + } meffect; + + extern const troop no_troop; + + extern void do_battle(struct region * r); + + /* for combat spells and special attacks */ + enum { SELECT_ADVANCE = 0x1, SELECT_DISTANCE = 0x2, SELECT_FIND = 0x4 }; + enum { ALLY_SELF, ALLY_ANY }; + + extern troop select_enemy(struct fighter * af, int minrow, int maxrow, int select); + extern troop select_ally(struct fighter * af, int minrow, int maxrow, int allytype); + + extern int count_enemies(struct battle * b, const struct fighter * af, int minrow, int maxrow, int select); + extern boolean terminate(troop dt, troop at, int type, const char *damage, boolean missile); + extern void message_all(battle * b, struct message * m); + extern int hits(troop at, troop dt, weapon * awp); + extern void damage_building(struct battle *b, struct building *bldg, int damage_abs); + extern struct cvector * fighters(struct battle *b, const struct side * vs, int minrow, int maxrow, int mask); + extern int count_allies(const struct side * as, int minrow, int maxrow, int select, int allytype); + extern int get_unitrow(const struct fighter * af, const struct side * vs); + extern boolean helping(const struct side * as, const struct side * ds); + extern void rmfighter(fighter *df, int i); +#ifndef SIMPLE_ESCAPE + extern struct region * fleeregion(const struct unit * u); +#endif + extern struct fighter * select_corpse(struct battle * b, struct fighter * af); + extern fighter * make_fighter(struct battle * b, struct unit * u, side * s, boolean attack); + extern int statusrow(int status); + extern void drain_exp(struct unit *u, int d); + extern void kill_troop(troop dt); + extern void remove_troop(troop dt); /* not the same as the badly named rmtroop */ + extern boolean is_attacker(const fighter * fig); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/kernel/binarystore.c b/src/kernel/binarystore.c index 13780c981..fdc02a09b 100644 --- a/src/kernel/binarystore.c +++ b/src/kernel/binarystore.c @@ -1,291 +1,294 @@ -/* vi: set ts=2: -+-------------------+ Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -+-------------------+ -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ -#include -#include "config.h" -#include "textstore.h" - -#include "save.h" -#include "version.h" -#include -#include - -#include -#include -#include -#include - -#define file(store) (FILE *)((store)->userdata) - -#define STREAM_VERSION 2 - -INLINE_FUNCTION size_t -pack_int(int v, char * buffer) -{ - int sign = (v<0); - - if (sign) { - v = ~v + 1; - sign = 0x40; - } - if (v<0x40) { - buffer[0] = (char)(v | sign); - return 1; - } else if (v<0x2000) { - buffer[0] = (char)((v>> 6) | 0x80); - buffer[1] = (char)((v & 0x3F) | sign); - return 2; - } else if (v<0x100000) { - buffer[0] = (char)(((v>>13) & 0x7f) | 0x80); - buffer[1] = (char)(((v>> 6) & 0x7f) | 0x80); - buffer[2] = (char)((v & 0x3F) | sign); - return 3; - } else if (v<0x8000000) { - buffer[0] = (char)(((v>>20) & 0x7f) | 0x80); - buffer[1] = (char)(((v>>13) & 0x7f) | 0x80); - buffer[2] = (char)(((v>> 6) & 0x7f) | 0x80); - buffer[3] = (char)((v & 0x3F) | sign); - return 4; - } - buffer[0] = (char)(((v>>27) & 0x7f) | 0x80); - buffer[1] = (char)(((v>>20) & 0x7f) | 0x80); - buffer[2] = (char)(((v>>13) & 0x7f) | 0x80); - buffer[3] = (char)(((v>> 6) & 0x7f) | 0x80); - buffer[4] = (char)((v & 0x3F) | sign); - return 5; -} - -INLINE_FUNCTION int -unpack_int(const char * buffer) -{ - int i = 0, v = 0; - - while (buffer[i] & 0x80) { - v = (v << 7) | (buffer[i++] & 0x7f); - } - v = (v << 6) | (buffer[i] & 0x3f); - - if (buffer[i] & 0x40) { - v = ~v + 1; - } - return v; -} - -static int -bin_w_brk(struct storage * store) -{ - return 0; -} - -static int -bin_w_int_pak(struct storage * store, int arg) -{ - char buffer[5]; - size_t size = pack_int(arg, buffer); - return (int)fwrite(buffer, sizeof(char), size, file(store)); -} - -static int -bin_r_int_pak(struct storage * store) -{ - int v = 0; - char ch; - - fread(&ch, sizeof(char), 1, file(store)); - while (ch & 0x80) { - v = (v << 7) | (ch & 0x7f); - fread(&ch, sizeof(char), 1, file(store)); - } - v = (v << 6) | (ch & 0x3f); - - if (ch & 0x40) { - v = ~v + 1; - } - return v; -} - -static int -bin_w_int(struct storage * store, int arg) -{ - return (int)fwrite(&arg, sizeof(arg), 1, file(store)); -} - -static int -bin_r_int(struct storage * store) -{ - int result; - fread(&result, sizeof(result), 1, file(store)); - return result; -} - -static int -bin_w_flt(struct storage * store, float arg) -{ - return (int)fwrite(&arg, sizeof(arg), 1, file(store)); -} - -static float -bin_r_flt(struct storage * store) -{ - float result; - fread(&result, sizeof(result), 1, file(store)); - return result; -} - -static int -bin_w_str(struct storage * store, const char * tok) -{ - int result; - if (tok==NULL || tok[0]==0) { - result = store->w_int(store, 0); - } else { - int size = (int)strlen(tok); - result = store->w_int(store, size); - result += (int)fwrite(tok, size, 1, file(store)); - } - return result; -} - -#define FIX_INVALID_CHARS /* required for data pre-574 */ -static char * -bin_r_str(struct storage * store) -{ - int len; - - len = store->r_int(store); - if (len>=0) { - char * result = malloc(len+1); - - fread(result, sizeof(char), len, file(store)); - result[len] = 0; -#ifdef FIX_INVALID_CHARS - { - char * p = strpbrk(result, "\n\r"); - while (p) { - log_error(("Invalid character %d in input string \"%s\".\n", *p, result)); - strcpy(p, p+1); - p = strpbrk(p, "\n\r"); - } - } -#endif - return result; - } else if (len<0) { - log_error(("invalid string-length %d in input.\n", len)); - } - return NULL; -} - -static void -bin_r_str_buf(struct storage * store, char * result, size_t size) -{ - int i; - size_t rd, len; - - i = store->r_int(store); - assert(i>=0); - if (i==0) { - result[0] = 0; - } else { - len = (size_t)i; - rd = MIN(len, size-1); - fread(result, sizeof(char), rd, file(store)); - if (rdw_int(store, len); - if (len>0) { - result += (int)fwrite(arg, len, 1, file(store)); - } - return result; -} - -static void -bin_r_bin(struct storage * store, void * result, size_t size) -{ - int len = store->r_int(store); - if (len>0) { - if ((size_t)len>size) { - log_error(("destination buffer too small %d %u.\n", len, size)); - fseek(file(store), len, SEEK_CUR); - } else { - fread(result, len, 1, file(store)); - } - } -} - - -static int -bin_open(struct storage * store, const char * filename, int mode) -{ - const char * modes[] = { 0, "rb", "wb", "ab" }; - FILE * F = fopen(filename, modes[mode]); - store->userdata = F; - store->encoding=XML_CHAR_ENCODING_UTF8; /* always utf8 it is */ - if (F) { - if (mode==IO_READ) { - int stream_version = 0; - store->version = bin_r_int(store); - if (store->version>=INTPAK_VERSION) { - stream_version = bin_r_int(store); - } - if (stream_version<=1) { - store->r_id = bin_r_int; - store->w_id = bin_w_int; - } - if (stream_version==0) { - store->r_int = bin_r_int; - store->w_int = bin_w_int; - } - } else if (store->encoding==XML_CHAR_ENCODING_UTF8) { - bin_w_int(store, RELEASE_VERSION); - bin_w_int(store, STREAM_VERSION); - } - } - return (F==NULL); -} - -static int -bin_close(struct storage * store) -{ - return fclose(file(store)); -} - -const storage binary_store = { - bin_w_brk, /* newline (ignore) */ - bin_w_int_pak, bin_r_int_pak, /* int storage */ - bin_w_flt, bin_r_flt, /* float storage */ - bin_w_int_pak, bin_r_int_pak, /* id storage */ - bin_w_str, bin_r_str, bin_r_str_buf, /* token storage */ - bin_w_str, bin_r_str, bin_r_str_buf, /* string storage */ - bin_w_bin, bin_r_bin, /* binary storage */ - bin_open, bin_close, - 0, 0, NULL -}; - +/* vi: set ts=2: ++-------------------+ Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel ++-------------------+ +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ +#include +#include "config.h" +#include "textstore.h" + +#include "save.h" +#include "version.h" +#include +#include +#include + +#include +#include +#include +#ifdef HAVE_LIBXML +#include +#endif + +#define file(store) (FILE *)((store)->userdata) + +#define STREAM_VERSION 2 + +INLINE_FUNCTION size_t +pack_int(int v, char * buffer) +{ + int sign = (v<0); + + if (sign) { + v = ~v + 1; + sign = 0x40; + } + if (v<0x40) { + buffer[0] = (char)(v | sign); + return 1; + } else if (v<0x2000) { + buffer[0] = (char)((v>> 6) | 0x80); + buffer[1] = (char)((v & 0x3F) | sign); + return 2; + } else if (v<0x100000) { + buffer[0] = (char)(((v>>13) & 0x7f) | 0x80); + buffer[1] = (char)(((v>> 6) & 0x7f) | 0x80); + buffer[2] = (char)((v & 0x3F) | sign); + return 3; + } else if (v<0x8000000) { + buffer[0] = (char)(((v>>20) & 0x7f) | 0x80); + buffer[1] = (char)(((v>>13) & 0x7f) | 0x80); + buffer[2] = (char)(((v>> 6) & 0x7f) | 0x80); + buffer[3] = (char)((v & 0x3F) | sign); + return 4; + } + buffer[0] = (char)(((v>>27) & 0x7f) | 0x80); + buffer[1] = (char)(((v>>20) & 0x7f) | 0x80); + buffer[2] = (char)(((v>>13) & 0x7f) | 0x80); + buffer[3] = (char)(((v>> 6) & 0x7f) | 0x80); + buffer[4] = (char)((v & 0x3F) | sign); + return 5; +} + +INLINE_FUNCTION int +unpack_int(const char * buffer) +{ + int i = 0, v = 0; + + while (buffer[i] & 0x80) { + v = (v << 7) | (buffer[i++] & 0x7f); + } + v = (v << 6) | (buffer[i] & 0x3f); + + if (buffer[i] & 0x40) { + v = ~v + 1; + } + return v; +} + +static int +bin_w_brk(struct storage * store) +{ + return 0; +} + +static int +bin_w_int_pak(struct storage * store, int arg) +{ + char buffer[5]; + size_t size = pack_int(arg, buffer); + return (int)fwrite(buffer, sizeof(char), size, file(store)); +} + +static int +bin_r_int_pak(struct storage * store) +{ + int v = 0; + char ch; + + fread(&ch, sizeof(char), 1, file(store)); + while (ch & 0x80) { + v = (v << 7) | (ch & 0x7f); + fread(&ch, sizeof(char), 1, file(store)); + } + v = (v << 6) | (ch & 0x3f); + + if (ch & 0x40) { + v = ~v + 1; + } + return v; +} + +static int +bin_w_int(struct storage * store, int arg) +{ + return (int)fwrite(&arg, sizeof(arg), 1, file(store)); +} + +static int +bin_r_int(struct storage * store) +{ + int result; + fread(&result, sizeof(result), 1, file(store)); + return result; +} + +static int +bin_w_flt(struct storage * store, float arg) +{ + return (int)fwrite(&arg, sizeof(arg), 1, file(store)); +} + +static float +bin_r_flt(struct storage * store) +{ + float result; + fread(&result, sizeof(result), 1, file(store)); + return result; +} + +static int +bin_w_str(struct storage * store, const char * tok) +{ + int result; + if (tok==NULL || tok[0]==0) { + result = store->w_int(store, 0); + } else { + int size = (int)strlen(tok); + result = store->w_int(store, size); + result += (int)fwrite(tok, size, 1, file(store)); + } + return result; +} + +#define FIX_INVALID_CHARS /* required for data pre-574 */ +static char * +bin_r_str(struct storage * store) +{ + int len; + + len = store->r_int(store); + if (len>=0) { + char * result = malloc(len+1); + + fread(result, sizeof(char), len, file(store)); + result[len] = 0; +#ifdef FIX_INVALID_CHARS + { + char * p = strpbrk(result, "\n\r"); + while (p) { + log_error(("Invalid character %d in input string \"%s\".\n", *p, result)); + strcpy(p, p+1); + p = strpbrk(p, "\n\r"); + } + } +#endif + return result; + } else if (len<0) { + log_error(("invalid string-length %d in input.\n", len)); + } + return NULL; +} + +static void +bin_r_str_buf(struct storage * store, char * result, size_t size) +{ + int i; + size_t rd, len; + + i = store->r_int(store); + assert(i>=0); + if (i==0) { + result[0] = 0; + } else { + len = (size_t)i; + rd = MIN(len, size-1); + fread(result, sizeof(char), rd, file(store)); + if (rdw_int(store, len); + if (len>0) { + result += (int)fwrite(arg, len, 1, file(store)); + } + return result; +} + +static void +bin_r_bin(struct storage * store, void * result, size_t size) +{ + int len = store->r_int(store); + if (len>0) { + if ((size_t)len>size) { + log_error(("destination buffer too small %d %u.\n", len, size)); + fseek(file(store), len, SEEK_CUR); + } else { + fread(result, len, 1, file(store)); + } + } +} + + +static int +bin_open(struct storage * store, const char * filename, int mode) +{ + const char * modes[] = { 0, "rb", "wb", "ab" }; + FILE * F = fopen(filename, modes[mode]); + store->userdata = F; + store->encoding = ENCODING_UTF8; /* always utf8 it is */ + if (F) { + if (mode==IO_READ) { + int stream_version = 0; + store->version = bin_r_int(store); + if (store->version>=INTPAK_VERSION) { + stream_version = bin_r_int(store); + } + if (stream_version<=1) { + store->r_id = bin_r_int; + store->w_id = bin_w_int; + } + if (stream_version==0) { + store->r_int = bin_r_int; + store->w_int = bin_w_int; + } + } else if (store->encoding==ENCODING_UTF8) { + bin_w_int(store, RELEASE_VERSION); + bin_w_int(store, STREAM_VERSION); + } + } + return (F==NULL); +} + +static int +bin_close(struct storage * store) +{ + return fclose(file(store)); +} + +const storage binary_store = { + bin_w_brk, /* newline (ignore) */ + bin_w_int_pak, bin_r_int_pak, /* int storage */ + bin_w_flt, bin_r_flt, /* float storage */ + bin_w_int_pak, bin_r_int_pak, /* id storage */ + bin_w_str, bin_r_str, bin_r_str_buf, /* token storage */ + bin_w_str, bin_r_str, bin_r_str_buf, /* string storage */ + bin_w_bin, bin_r_bin, /* binary storage */ + bin_open, bin_close, + 0, 0, NULL +}; + diff --git a/src/kernel/binarystore.h b/src/kernel/binarystore.h index 8ba979667..6ab4c16fb 100644 --- a/src/kernel/binarystore.h +++ b/src/kernel/binarystore.h @@ -1,23 +1,23 @@ -/* vi: set ts=2: -+-------------------+ Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -+-------------------+ -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifndef H_KERNEL_BINSTORE -#define H_KERNEL_BINSTORE -#ifdef __cplusplus -extern "C" { -#endif - -#include - -extern const storage binary_store; - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: ++-------------------+ Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel ++-------------------+ +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifndef H_KERNEL_BINSTORE +#define H_KERNEL_BINSTORE +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern const storage binary_store; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/build.c b/src/kernel/build.c index 50ab584c4..77adbcfca 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -1,1350 +1,1349 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "build.h" - -/* kernel includes */ -#include "alchemy.h" -#include "alliance.h" -#include "connection.h" -#include "building.h" -#include "curse.h" -#include "faction.h" -#include "group.h" -#include "item.h" -#include "magic.h" -#include "message.h" -#include "move.h" -#include "order.h" -#include "pool.h" -#include "race.h" -#include "region.h" -#include "ship.h" -#include "skill.h" -#include "terrain.h" -#include "terrainid.h" -#include "unit.h" - -/* from libutil */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* from libc */ -#include -#include -#include -#include -#include -#include - -/* attributes inclues */ -#include -#include - -#define STONERECYCLE 50 -/* Name, MaxGroesse, MinBauTalent, Kapazitaet, {Eisen, Holz, Stein, BauSilber, - * Laen, Mallorn}, UnterSilber, UnterSpezialTyp, UnterSpezial */ - - -static boolean -CheckOverload(void) -{ - static int value = -1; - if (value<0) { - value = get_param_int(global.parameters, "rules.check_overload", 0); - } - return value; -} - -/* test if the unit can slip through a siege undetected. - * returns 0 if siege is successful, or 1 if the building is either - * not besieged or the unit can slip through the siege due to better stealth. - */ -static int -slipthru(const region * r, const unit * u, const building * b) -{ - unit *u2; - int n, o; - - /* b ist die burg, in die man hinein oder aus der man heraus will. */ - if (b==NULL || b->besieged < b->size * SIEGEFACTOR) { - return 1; - } - - /* u wird am hinein- oder herausschluepfen gehindert, wenn STEALTH <= - * OBSERVATION +2 der belagerer u2 ist */ - n = eff_skill(u, SK_STEALTH, r); - - for (u2 = r->units; u2; u2 = u2->next) { - if (usiege(u2) == b) { - - if (invisible(u, u2) >= u->number) continue; - - o = eff_skill(u2, SK_PERCEPTION, r); - - if (o + 2 >= n) { - return 0; /* entdeckt! */ - } - } - } - return 1; -} - -boolean -can_contact(const region * r, const unit * u, const unit * u2) -{ - - /* hier geht es nur um die belagerung von burgen */ - - if (u->building == u2->building) - return true; - - /* unit u is trying to contact u2 - unasked for contact. wenn u oder u2 - * nicht in einer burg ist, oder die burg nicht belagert ist, ist - * slipthru () == 1. ansonsten ist es nur 1, wenn man die belagerer */ - - if (slipthru(u->region, u, u->building) - && slipthru(u->region, u2, u2->building)) - return true; - - if (alliedunit(u, u2->faction, HELP_GIVE)) - return true; - - return false; -} - - -static void -contact_cmd(unit * u, order * ord, boolean tries) -{ - /* unit u kontaktiert unit u2. Dies setzt den contact einfach auf 1 - - * ein richtiger toggle ist (noch?) nicht noetig. die region als - * parameter ist nur deswegen wichtig, weil er an getunit () - * weitergegeben wird. dies wird fuer das auffinden von tempunits in - * getnewunit () verwendet! */ - unit *u2; - region * r = u->region; - - init_tokens(ord); - skip_token(); - u2 = getunitg(r, u->faction); - - if (u2!=NULL) { - if (!can_contact(r, u, u2)) { - if (tries) cmistake(u, u->thisorder, 23, MSG_EVENT); - return; - } - usetcontact(u, u2); - } -} -/* ------------------------------------------------------------- */ - -/* ------------------------------------------------------------- */ - - -/* ------------------------------------------------------------- */ - -struct building * -getbuilding(const struct region * r) -{ - building * b = findbuilding(getid()); - if (b==NULL || r!=b->region) return NULL; - return b; -} - -ship * -getship(const struct region * r) -{ - ship *sh, *sx = findship(getshipid()); - for (sh = r->ships; sh; sh = sh->next) { - if (sh == sx) return sh; - } - return NULL; -} - -/* ------------------------------------------------------------- */ - -static void -siege_cmd(unit * u, order * ord) -{ - region * r = u->region; - building *b; - int d, pooled; - int bewaffnete, katapultiere = 0; - static boolean init = false; - static const curse_type * magicwalls_ct; - static item_type * it_catapultammo = NULL; - static item_type * it_catapult = NULL; - if (!init) { - init = true; - magicwalls_ct = ct_find("magicwalls"); - it_catapultammo = it_find("catapultammo"); - it_catapult = it_find("catapult"); - } - /* gibt es ueberhaupt Burgen? */ - - init_tokens(ord); - skip_token(); - b = getbuilding(r); - - if (!b) { - cmistake(u, ord, 31, MSG_BATTLE); - return; - } - - if (!playerrace(u->race)) { - /* keine Drachen, Illusionen, Untote etc */ - cmistake(u, ord, 166, MSG_BATTLE); - return; - } - /* schaden durch katapulte */ - - d = i_get(u->items, it_catapult); - d = MIN(u->number, d); - pooled = get_pooled(u, it_catapultammo->rtype, GET_DEFAULT, d); - d = MIN(pooled, d); - if (eff_skill(u, SK_CATAPULT, r) >= 1) { - katapultiere = d; - d *= eff_skill(u, SK_CATAPULT, r); - } else { - d = 0; - } - - bewaffnete = armedmen(u, true); - if (d == 0 && bewaffnete == 0) { - /* abbruch, falls unbewaffnet oder unfaehig, katapulte zu benutzen */ - cmistake(u, ord, 80, MSG_EVENT); - return; - } - - if (!is_guard(u, GUARD_TRAVELTHRU)) { - /* abbruch, wenn die einheit nicht vorher die region bewacht - als - * warnung fuer alle anderen! */ - cmistake(u, ord, 81, MSG_EVENT); - return; - } - /* einheit und burg markieren - spart zeit beim behandeln der einheiten - * in der burg, falls die burg auch markiert ist und nicht alle - * einheiten wieder abgesucht werden muessen! */ - - usetsiege(u, b); - b->besieged += MAX(bewaffnete, katapultiere); - - /* definitiver schaden eingeschraenkt */ - - d = MIN(d, b->size - 1); - - /* meldung, schaden anrichten */ - if (d && !curse_active(get_curse(b->attribs, magicwalls_ct))) { - b->size -= d; - use_pooled(u, it_catapultammo->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, d); - /* send message to the entire region */ - ADDMSG(&r->msgs, msg_message("siege_catapults", - "unit building destruction", u, b, d)); - } else { - /* send message to the entire region */ - ADDMSG(&r->msgs, msg_message("siege", - "unit building", u, b)); - } -} - -void -do_siege(region *r) -{ - if (fval(r->terrain, LAND_REGION)) { - unit *u; - - for (u = r->units; u; u = u->next) { - if (get_keyword(u->thisorder) == K_BESIEGE) { - siege_cmd(u, u->thisorder); - } - } - } -} -/* ------------------------------------------------------------- */ - -static void -destroy_road(unit *u, int nmax, struct order * ord) -{ - direction_t d = getdirection(u->faction->locale); - unit *u2; - region *r = u->region; - short n = (short)nmax; - - if (nmax>SHRT_MAX) n = SHRT_MAX; - else if (nmax<0) n = 0; - - for (u2=r->units;u2;u2=u2->next) { - if (u2->faction!=u->faction && is_guard(u2, GUARD_TAX) - && cansee(u2->faction, u->region, u, 0) - && !alliedunit(u, u2->faction, HELP_GUARD)) { - cmistake(u, ord, 70, MSG_EVENT); - return; - } - } - - if (d==NODIRECTION) { - /* Die Richtung wurde nicht erkannt */ - cmistake(u, ord, 71, MSG_PRODUCE); - } else { - short road = rroad(r, d); - n = MIN(n, road); - if (n!=0) { - region * r2 = rconnect(r,d); - int willdo = eff_skill(u, SK_ROAD_BUILDING, r)*u->number; - willdo = MIN(willdo, n); - if (willdo==0) { - /* TODO: error message */ - } - if (willdo>SHRT_MAX) road = 0; - else road = road - (short)willdo; - rsetroad(r, d, road); - ADDMSG(&u->faction->msgs, msg_message("destroy_road", - "unit from to", u, r, r2)); - } - } -} - -int -destroy_cmd(unit * u, struct order * ord) -{ - ship *sh; - unit *u2; - region * r = u->region; - const construction * con = NULL; - int size = 0; - const char *s; - int n = INT_MAX; - - if (u->number < 1) - return 0; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - if (findparam(s, u->faction->locale)==P_ROAD) { - destroy_road(u, INT_MAX, ord); - return 0; - } - - if (s && *s) { - n = atoi((const char *)s); - if (n <= 0) { - cmistake(u, ord, 288, MSG_PRODUCE); - return 0; - } - } - - if (getparam(u->faction->locale) == P_ROAD) { - destroy_road(u, n, ord); - return 0; - } - - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 138, MSG_PRODUCE); - return 0; - } - - if (u->building) { - building *b = u->building; - - if (n >= b->size) { - /* destroy completly */ - /* all units leave the building */ - for (u2 = r->units; u2; u2 = u2->next) { - if (u2->building == b) { - u2->building = 0; - freset(u2, UFL_OWNER); - } - } - ADDMSG(&u->faction->msgs, msg_message("destroy", - "building unit", b, u)); - con = b->type->construction; - remove_building(&r->buildings, b); - } else { - /* partial destroy */ - b->size -= n; - ADDMSG(&u->faction->msgs, msg_message("destroy_partial", - "building unit", b, u)); - } - } else if (u->ship) { - sh = u->ship; - - if (fval(r->terrain, SEA_REGION)) { - cmistake(u, ord, 14, MSG_EVENT); - return 0; - } - - if (n >= (sh->size*100)/sh->type->construction->maxsize) { - /* destroy completly */ - /* all units leave the ship */ - for (u2 = r->units; u2; u2 = u2->next) { - if (u2->ship == sh) { - u2->ship = 0; - freset(u2, UFL_OWNER); - } - } - ADDMSG(&u->faction->msgs, msg_message("shipdestroy", - "unit region ship", u, r, sh)); - con = sh->type->construction; - remove_ship(&sh->region->ships, sh); - } else { - /* partial destroy */ - sh->size -= (sh->type->construction->maxsize * n)/100; - ADDMSG(&u->faction->msgs, msg_message("shipdestroy_partial", - "unit region ship", u, r, sh)); - } - } else { - log_error(("Die Einheit %s von %s war owner eines objects, war aber weder in einer Burg noch in einem Schiff.\n", - unitname(u), u->faction->name, u->faction->email)); - } - - if (con) { - /* TODO: Nicht an ZERSTÖRE mit Punktangabe angepaßt! */ - int c; - for (c=0;con->materials[c].number;++c) { - const requirement * rq = con->materials+c; - int recycle = (int)(rq->recycle * rq->number * size/con->reqsize); - if (recycle) { - change_resource(u, rq->rtype, recycle); - } - } - } - return 0; -} -/* ------------------------------------------------------------- */ - -void -build_road(region * r, unit * u, int size, direction_t d) -{ - int n, left; - region * rn = rconnect(r,d); - - assert(u->number); - if (!eff_skill(u, SK_ROAD_BUILDING, r)) { - cmistake(u, u->thisorder, 103, MSG_PRODUCE); - return; - } - if (besieged(u)) { - cmistake(u, u->thisorder, 60, MSG_PRODUCE); - return; - } - - if (rn==NULL || rn->terrain->max_road < 0) { - cmistake(u, u->thisorder, 94, MSG_PRODUCE); - return; - } - - if (r->terrain->max_road < 0) { - cmistake(u, u->thisorder, 94, MSG_PRODUCE); - return; - } - - if (r->terrain == newterrain(T_SWAMP)) { - /* wenn kein Damm existiert */ - static const struct building_type * bt_dam; - if (!bt_dam) bt_dam = bt_find("dam"); - assert(bt_dam); - if (!buildingtype_exists(r, bt_dam, true)) { - cmistake(u, u->thisorder, 132, MSG_PRODUCE); - return; - } - } else if (r->terrain == newterrain(T_DESERT)) { - static const struct building_type * bt_caravan; - if (!bt_caravan) bt_caravan = bt_find("caravan"); - assert(bt_caravan); - /* wenn keine Karawanserei existiert */ - if (!buildingtype_exists(r, bt_caravan, true)) { - cmistake(u, u->thisorder, 133, MSG_PRODUCE); - return; - } - } else if (r->terrain == newterrain(T_GLACIER)) { - static const struct building_type * bt_tunnel; - if (!bt_tunnel) bt_tunnel = bt_find("tunnel"); - assert(bt_tunnel); - /* wenn kein Tunnel existiert */ - if (!buildingtype_exists(r, bt_tunnel, true)) { - cmistake(u, u->thisorder, 131, MSG_PRODUCE); - return; - } - } - - /* left kann man noch bauen */ - left = r->terrain->max_road - rroad(r, d); - - /* hoffentlich ist r->road <= r->terrain->max_road, n also >= 0 */ - if (left <= 0) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_roads_finished", "")); - return; - } - - if (size>0) left = MIN(size, left); - /* baumaximum anhand der rohstoffe */ - if (u->race == new_race[RC_STONEGOLEM]){ - n = u->number * GOLEM_STONE; - } else { - n = get_pooled(u, oldresourcetype[R_STONE], GET_DEFAULT, left); - if (n==0) { - cmistake(u, u->thisorder, 151, MSG_PRODUCE); - return; - } - } - left = MIN(n, left); - - /* n = maximum by skill. try to maximize it */ - n = u->number * eff_skill(u, SK_ROAD_BUILDING, r); - if (n < left) { - item * itm = *i_find(&u->items, olditemtype[I_RING_OF_NIMBLEFINGER]); - if (itm!=NULL && itm->number>0) { - int rings = MIN(u->number, itm->number); - n = n * ((roqf_factor()-1)*rings+u->number) / u->number; - } - } - if (n < left) { - int dm = get_effect(u, oldpotiontype[P_DOMORE]); - if (dm != 0) { - int sk = eff_skill(u, SK_ROAD_BUILDING, r); - int todo = (left - n + sk - 1) / sk; - todo = MIN(todo, u->number); - dm = MIN(dm, todo); - change_effect(u, oldpotiontype[P_DOMORE], -dm); - n += dm * sk; - } /* Auswirkung Schaffenstrunk */ - } - - /* make minimum of possible and available: */ - n = MIN(left, n); - - /* n is now modified by several special effects, so we have to - * minimize it again to make sure the road will not grow beyond - * maximum. */ - rsetroad(r, d, rroad(r, d) + (short)n); - - if (u->race == new_race[RC_STONEGOLEM]) { - int golemsused = n / GOLEM_STONE; - if (n%GOLEM_STONE != 0){ - ++golemsused; - } - scale_number(u, u->number - golemsused); - } else { - use_pooled(u, oldresourcetype[R_STONE], GET_DEFAULT, n); - /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ - produceexp(u, SK_ROAD_BUILDING, MIN(n, u->number)); - } - ADDMSG(&u->faction->msgs, msg_message("buildroad", - "region unit size", r, u, n)); -} -/* ------------------------------------------------------------- */ - -/* ** ** ** ** ** ** * - * new build rules * - * ** ** ** ** ** ** */ - -static int -required(int size, int msize, int maxneed) - /* um size von msize Punkten zu bauen, - * braucht man required von maxneed resourcen */ -{ - int used; - - used = size * maxneed / msize; - if (size * maxneed % msize) - ++used; - return used; -} - -static int -matmod(const attrib * a, const unit * u, const resource_type * material, int value) -{ - for (a=a_find((attrib*)a, &at_matmod);a && a->type==&at_matmod;a=a->next) { - mm_fun fun = (mm_fun)a->data.f; - value = fun(u, material, value); - if (value<0) return value; /* pass errors to caller */ - } - return value; -} - -int roqf_factor(void) -{ - int value = -1; - if (value<0) { - value = get_param_int(global.parameters, "rules.economy.roqf", 10); - } - return value; -} - -/** Use up resources for building an object. -* Build up to 'size' points of 'type', where 'completed' -* of the first object have already been finished. return the -* actual size that could be built. -*/ -int -build(unit * u, const construction * ctype, int completed, int want) -{ - const construction * type = ctype; - int skills = INT_MAX; /* number of skill points remainig */ - int basesk = 0; - int made = 0; - - if (want<=0) return 0; - if (type==NULL) return 0; - if (type->improvement==NULL && completed==type->maxsize) - return ECOMPLETE; - if (type->btype!=NULL) { - building * b; - if (!u->building || u->building->type!=type->btype) { - return EBUILDINGREQ; - } - b = inside_building(u); - if (b==NULL) return EBUILDINGREQ; - } - - if (type->skill!=NOSKILL) { - int effsk; - int dm = get_effect(u, oldpotiontype[P_DOMORE]); - - assert(u->number); - basesk = effskill(u, type->skill); - if (basesk==0) return ENEEDSKILL; - - effsk = basesk; - if (inside_building(u)) { - effsk = skillmod(u->building->type->attribs, u, u->region, type->skill, - effsk, SMF_PRODUCTION); - } - effsk = skillmod(type->attribs, u, u->region, type->skill, - effsk, SMF_PRODUCTION); - if (effsk<0) return effsk; /* pass errors to caller */ - if (effsk==0) return ENEEDSKILL; - - skills = effsk * u->number; - - /* technically, nimblefinge and domore should be in a global set of - * "game"-attributes, (as at_skillmod) but for a while, we're leaving - * them in here. */ - - if (dm != 0) { - /* Auswirkung Schaffenstrunk */ - dm = MIN(dm, u->number); - change_effect(u, oldpotiontype[P_DOMORE], -dm); - skills += dm * effsk; - } - } - for (;want>0 && skills>0;) { - int c, n; - - /* skip over everything that's already been done: - * type->improvement==NULL means no more improvements, but no size limits - * type->improvement==type means build another object of the same time - * while material lasts type->improvement==x means build x when type - * is finished */ - while (type->improvement!=NULL && - type->improvement!=type && - type->maxsize>0 && - type->maxsize<=completed) - { - completed -= type->maxsize; - type = type->improvement; - } - if (type==NULL) { - if (made==0) return ECOMPLETE; - break; /* completed */ - } - - /* Hier ist entweder maxsize == -1, oder completed < maxsize. - * Andernfalls ist das Datenfile oder sonstwas kaputt... - * (enno): Nein, das ist für Dinge, bei denen die nächste Ausbaustufe - * die gleiche wie die vorherige ist. z.b. gegenstände. - */ - if (type->maxsize>1) { - completed = completed % type->maxsize; - } - else { - completed = 0; assert(type->reqsize>=1); - } - - if (basesk < type->minskill) { - if (made==0) return ELOWSKILL; /* not good enough to go on */ - } - - /* n = maximum buildable size */ - if (type->minskill > 1) { - n = skills / type->minskill; - } else { - n = skills; - } - /* Flinkfingerring wirkt nicht auf Mengenbegrenzte (magische) - * Talente */ - if (skill_limit(u->faction, type->skill)==INT_MAX) { - int i = 0; - item * itm = *i_find(&u->items, olditemtype[I_RING_OF_NIMBLEFINGER]); - if (itm!=NULL) i = itm->number; - if (i>0) { - int rings = MIN(u->number, i); - n = n * ((roqf_factor()-1)*rings+u->number) / u->number; - } - } - - if (want>0) { - n = MIN(want, n); - } - - if (type->maxsize>0) { - n = MIN(type->maxsize-completed, n); - if (type->improvement==NULL) { - want = n; - } - } - - if (type->materials) for (c=0;n>0 && type->materials[c].number;c++) { - const struct resource_type * rtype = type->materials[c].rtype; - int need, prebuilt; - int canuse = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); - - if (inside_building(u)) { - canuse = matmod(u->building->type->attribs, u, rtype, canuse); - } - - if (canuse<0) return canuse; /* pass errors to caller */ - canuse = matmod(type->attribs, u, rtype, canuse); - if (type->reqsize>1) { - prebuilt = required(completed, type->reqsize, type->materials[c].number); - for (;n;) { - need = required(completed + n, type->reqsize, type->materials[c].number); - if (need-prebuilt<=canuse) break; - --n; /* TODO: optimieren? */ - } - } else { - int maxn = canuse / type->materials[c].number; - if (maxn < n) n = maxn; - } - } - if (n<=0) { - if (made==0) return ENOMATERIALS; - else break; - } - if (type->materials) for (c=0;type->materials[c].number;c++) { - const struct resource_type * rtype = type->materials[c].rtype; - int prebuilt = required(completed, type->reqsize, type->materials[c].number); - int need = required(completed + n, type->reqsize, type->materials[c].number); - int multi = 1; - int canuse = 100; /* normalization */ - if (inside_building(u)) canuse = matmod(u->building->type->attribs, u, rtype, canuse); - if (canuse<0) return canuse; /* pass errors to caller */ - canuse = matmod(type->attribs, u, rtype, canuse); - - assert(canuse % 100 == 0 || !"only constant multipliers are implemented in build()"); - multi = canuse/100; - if (canuse<0) return canuse; /* pass errors to caller */ - - use_pooled(u, rtype, GET_DEFAULT, (need-prebuilt+multi-1)/multi); - } - made += n; - skills -= n * type->minskill; - want -= n; - completed = completed + n; - } - /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ - produceexp(u, ctype->skill, MIN(made, u->number)); - - return made; -} - -message * -msg_materials_required(unit * u, order * ord, const construction * ctype, int multi) -{ - int c; - /* something missing from the list of materials */ - resource * reslist = NULL; - - if (multi<=0 || multi==INT_MAX) multi = 1; - for (c=0;ctype->materials[c].number; ++c) { - resource * res = malloc(sizeof(resource)); - res->number = multi * ctype->materials[c].number / ctype->reqsize; - res->type = ctype->materials[c].rtype; - res->next = reslist; - reslist = res; - } - return msg_feedback(u, ord, "build_required", "required", reslist); -} - -int -maxbuild(const unit * u, const construction * cons) - /* calculate maximum size that can be built from available material */ - /* !! ignores maximum objectsize and improvements...*/ -{ - int c; - int maximum = INT_MAX; - for (c=0;cons->materials[c].number;c++) { - const resource_type * rtype = cons->materials[c].rtype; - int have = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); - int need = required(1, cons->reqsize, cons->materials[c].number); - if (haveregion; - boolean newbuilding = false; - int n = want, built = 0, id; - building * b = NULL; - /* einmalige Korrektur */ - const char * btname; - order * new_order = NULL; - const struct locale * lang = u->faction->locale; - static int rule_other = -1; - - assert(u->number); - if (eff_skill(u, SK_BUILDING, r) == 0) { - cmistake(u, ord, 101, MSG_PRODUCE); - return; - } - - /* Falls eine Nummer angegeben worden ist, und ein Gebaeude mit der - * betreffenden Nummer existiert, ist b nun gueltig. Wenn keine Burg - * gefunden wurde, dann wird nicht einfach eine neue erbaut. Ansonsten - * baut man an der eigenen burg weiter. */ - - /* Wenn die angegebene Nummer falsch ist, KEINE Burg bauen! */ - id = getid(); - if (id>0) { /* eine Nummer angegeben, keine neue Burg bauen */ - b = findbuilding(id); - if (!b || b->region != u->region) { /* eine Burg mit dieser Nummer gibt es hier nicht */ - /* vieleicht Tippfehler und die eigene Burg ist gemeint? */ - if (u->building && u->building->type==btype) { - b = u->building; - } else { - /* keine neue Burg anfangen wenn eine Nummer angegeben war */ - cmistake(u, ord, 6, MSG_PRODUCE); - return; - } - } - } else if (u->building && u->building->type==btype) { - b = u->building; - } - - if (b) btype = b->type; - - if (b && fval(btype, BTF_UNIQUE) && buildingtype_exists(r, btype, false)) { - /* only one of these per region */ - cmistake(u, ord, 93, MSG_PRODUCE); - return; - } - if (besieged(u)) { - /* units under siege can not build */ - cmistake(u, ord, 60, MSG_PRODUCE); - return; - } - if (btype->flags & BTF_NOBUILD) { - /* special building, cannot be built */ - cmistake(u, ord, 221, MSG_PRODUCE); - return; - } - if (btype->flags & BTF_ONEPERTURN) { - if(b && fval(b, BLD_EXPANDED)) { - cmistake(u, ord, 318, MSG_PRODUCE); - return; - } - n = 1; - } - if (b) { - if (rule_other<0) { - rule_other = get_param_int(global.parameters, "rules.build.other_buildings", 1); - } - if (!rule_other) { - unit * owner = building_owner(b); - if (!owner || owner->faction!=u->faction) { - cmistake(u, ord, 1222, MSG_PRODUCE); - return; - } - } - } - - if (b) built = b->size; - if (n<=0 || n == INT_MAX) { - if(b == NULL) { - if(btype->maxsize > 0) { - n = btype->maxsize - built; - } else { - n = INT_MAX; - } - } else { - if (b->type->maxsize > 0) { - n = b->type->maxsize - built; - } else { - n = INT_MAX; - } - } - } - built = build(u, btype->construction, built, n); - - switch (built) { - case ECOMPLETE: - /* the building is already complete */ - cmistake(u, ord, 4, MSG_PRODUCE); - return; - case ENOMATERIALS: - ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, btype->construction, want)); - return; - case ELOWSKILL: - case ENEEDSKILL: - /* no skill, or not enough skill points to build */ - cmistake(u, ord, 50, MSG_PRODUCE); - return; - } - - - /* at this point, the building size is increased. */ - if (b==NULL) { - /* build a new building */ - b = new_building(btype, r, lang); - b->type = btype; - fset(b, BLD_MAINTAINED); - - /* Die Einheit befindet sich automatisch im Inneren der neuen Burg. */ - if (leave(u, false)) { - u->building = b; - fset(u, UFL_OWNER); - } - -#ifdef WDW_PYRAMID - if(b->type == bt_find("pyramid") && f_get_alliance(u->faction) != NULL) { - attrib * a = a_add(&b->attribs, a_new(&at_alliance)); - a->data.i = u->faction->alliance->id; - } -#endif - - newbuilding = true; - } - - btname = LOC(lang, btype->_name); - - if (want-built <= 0) { - /* gebäude fertig */ - new_order = default_order(lang); - } else if (want!=INT_MAX) { - /* reduzierte restgröße */ - const char * hasspace = strchr(btname, ' '); - if (hasspace) { - new_order = create_order(K_MAKE, lang, "%d \"%s\" %i", n-built, btname, b->no); - } else { - new_order = create_order(K_MAKE, lang, "%d %s %i", n-built, btname, b->no); - } - } else if (btname) { - /* Neues Haus, Befehl mit Gebäudename */ - const char * hasspace = strchr(btname, ' '); - if (hasspace) { - new_order = create_order(K_MAKE, lang, "\"%s\" %i", btname, b->no); - } else { - new_order = create_order(K_MAKE, lang, "%s %i", btname, b->no); - } - } - - if (new_order) { - replace_order(&u->orders, ord, new_order); - free_order(new_order); - } - - b->size += built; - fset(b, BLD_EXPANDED); - - update_lighthouse(b); - - - ADDMSG(&u->faction->msgs, msg_message("buildbuilding", - "building unit size", b, u, built)); -} - -static void -build_ship(unit * u, ship * sh, int want) -{ - const construction * construction = sh->type->construction; - int size = (sh->size * DAMAGE_SCALE - sh->damage) / DAMAGE_SCALE; - int n; - int can = build(u, construction, size, want); - - if ((n=construction->maxsize - sh->size)>0 && can>0) { - if (can>=n) { - sh->size += n; - can -= n; - } - else { - sh->size += can; - n=can; - can = 0; - } - } - - if (sh->damage && can) { - int repair = MIN(sh->damage, can * DAMAGE_SCALE); - n += repair / DAMAGE_SCALE; - if (repair % DAMAGE_SCALE) ++n; - sh->damage = sh->damage - repair; - } - - if (n) ADDMSG(&u->faction->msgs, - msg_message("buildship", "ship unit size", sh, u, n)); -} - -void -create_ship(region * r, unit * u, const struct ship_type * newtype, int want, order * ord) -{ - ship *sh; - int msize; - const construction * cons = newtype->construction; - order * new_order; - - if (!eff_skill(u, SK_SHIPBUILDING, r)) { - cmistake(u, ord, 100, MSG_PRODUCE); - return; - } - if (besieged(u)) { - cmistake(u, ord, 60, MSG_PRODUCE); - return; - } - - /* check if skill and material for 1 size is available */ - if (eff_skill(u, cons->skill, r) < cons->minskill) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_build_skill_low", "value name", - cons->minskill, newtype->name[1])); - return; - } - - msize = maxbuild(u, cons); - if (msize==0) { - cmistake(u, ord, 88, MSG_PRODUCE); - return; - } - if (want>0) want = MIN(want, msize); - else want = msize; - - sh = new_ship(newtype, u->faction->locale, r); - - if (leave(u, false)) { - if (fval(u->race, RCF_CANSAIL)) { - u->ship = sh; - fset(u, UFL_OWNER); - } - } - new_order = create_order(K_MAKE, u->faction->locale, "%s %i", LOC(u->faction->locale, parameters[P_SHIP]), sh->no); - replace_order(&u->orders, ord, new_order); - free_order(new_order); - - build_ship(u, sh, want); -} - -void -continue_ship(region * r, unit * u, int want) -{ - const construction * cons; - ship *sh; - int msize; - - if (!eff_skill(u, SK_SHIPBUILDING, r)) { - cmistake(u, u->thisorder, 100, MSG_PRODUCE); - return; - } - - /* Die Schiffsnummer bzw der Schiffstyp wird eingelesen */ - sh = getship(r); - - if (!sh) sh = u->ship; - - if (!sh) { - cmistake(u, u->thisorder, 20, MSG_PRODUCE); - return; - } - cons = sh->type->construction; - assert(cons->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */ - if (sh->size==cons->maxsize && !sh->damage) { - cmistake(u, u->thisorder, 16, MSG_PRODUCE); - return; - } - if (eff_skill(u, cons->skill, r) < cons->minskill) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_build_skill_low", "value name", - cons->minskill, sh->type->name[1])); - return; - } - msize = maxbuild(u, cons); - if (msize==0) { - cmistake(u, u->thisorder, 88, MSG_PRODUCE); - return; - } - if (want > 0) want = MIN(want, msize); - else want = msize; - - build_ship(u, sh, want); -} -/* ------------------------------------------------------------- */ - -static boolean -mayenter(region * r, unit * u, building * b) -{ - unit *u2; - if (fval(b, BLD_UNGUARDED)) return true; - u2 = building_owner(b); - - if (u2==NULL || ucontact(u2, u) - || alliedunit(u2, u->faction, HELP_GUARD)) return true; - - return false; -} - -static int -mayboard(const unit * u, const ship * sh) -{ - unit *u2 = shipowner(sh); - - return (!u2 || ucontact(u2, u) || alliedunit(u2, u->faction, HELP_GUARD)); -} - -int -leave_cmd(unit * u, struct order * ord) -{ - region * r = u->region; - - if (fval(u, UFL_ENTER)) { - /* if we just entered this round, then we don't leave again */ - return 0; - } - - if (fval(r->terrain, SEA_REGION) && u->ship) { - if(!fval(u->race, RCF_SWIM)) { - cmistake(u, ord, 11, MSG_MOVE); - return 0; - } - if (has_horses(u)) { - cmistake(u, ord, 231, MSG_MOVE); - return 0; - } - } - if (!slipthru(r, u, u->building)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "entrance_besieged", "building", u->building)); - } else { - leave(u, true); - } - return 0; -} - -static boolean -enter_ship(unit * u, struct order * ord, int id, boolean report) -{ - region * r = u->region; - ship * sh; - - /* Muß abgefangen werden, sonst könnten Schwimmer an - * Bord von Schiffen an Land gelangen. */ - if (!fval(u->race, RCF_CANSAIL) || (!fval(u->race, RCF_WALK) && !fval(u->race, RCF_FLY))) { - cmistake(u, ord, 233, MSG_MOVE); - return false; - } - - sh = findship(id); - if (sh == NULL || sh->region!=r) { - if (report) cmistake(u, ord, 20, MSG_MOVE); - return false; - } - if (sh==u->ship) return true; - if (!mayboard(u, sh)) { - if (report) cmistake(u, ord, 34, MSG_MOVE); - return false; - } - if (CheckOverload()) { - int sweight, scabins; - int mweight = shipcapacity(sh); - int mcabins = sh->type->cabins; - - if (mweight>0) { - getshipweight(sh, &sweight, &scabins); - sweight += weight(u); - if (mcabins) { - int pweight = u->number * u->race->weight; - /* weight goes into number of cabins, not cargo */ - scabins += pweight; - sweight -= pweight; - } - - if (sweight > mweight || (mcabins && (scabins > mcabins))) { - if (report) cmistake(u, ord, 34, MSG_MOVE); - return false; - } - } - } - - if (leave(u, false)) { - u->ship = sh; - - if (shipowner(sh) == NULL) { - fset(u, UFL_OWNER); - } - fset(u, UFL_ENTER); - } - return true; -} - -static boolean -enter_building(unit * u, order * ord, int id, boolean report) -{ - region * r = u->region; - building * b; - - /* Schwimmer können keine Gebäude betreten, außer diese sind - * auf dem Ozean */ - if (!fval(u->race, RCF_WALK) && !fval(u->race, RCF_FLY)) { - if (!fval(r->terrain, SEA_REGION)) { - if (report) { - cmistake(u, ord, 232, MSG_MOVE); - } - return false; - } - } - - b = findbuilding(id); - if (b==NULL || b->region!=r) { - if (report) { - cmistake(u, ord, 6, MSG_MOVE); - } - return false; - } - if (!mayenter(r, u, b)) { - if (report) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "entrance_denied", "building", b)); - } - return false; - } - if (!slipthru(r, u, b)) { - if (report) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "entrance_besieged", "building", b)); - } - return false; - } - - if (leave(u, false)) { - if (building_owner(b) == 0) { - fset(u, UFL_OWNER); - } - fset(u, UFL_ENTER); - u->building = b; - return true; - } - return false; -} - -void -do_misc(region * r, boolean lasttry) -{ - unit **uptr, *uc; - - for (uc = r->units; uc; uc = uc->next) { - order * ord; - for (ord = uc->orders; ord; ord = ord->next) { - switch (get_keyword(ord)) { - case K_CONTACT: - contact_cmd(uc, ord, lasttry); - break; - } - } - } - - for (uptr = &r->units; *uptr;) { - unit * u = *uptr; - order ** ordp = &u->orders; - - while (*ordp) { - order * ord = *ordp; - if (get_keyword(ord) == K_ENTER) { - param_t p; - int id; - unit * ulast = NULL; - - init_tokens(ord); - skip_token(); - p = getparam(u->faction->locale); - id = getid(); - - switch (p) { - case P_BUILDING: - case P_GEBAEUDE: - if (u->building && u->building->no==id) break; - if (enter_building(u, ord, id, lasttry)) { - unit *ub; - for (ub=u;ub;ub=ub->next) { - if (ub->building==u->building) { - ulast = ub; - } - } - } - break; - - case P_SHIP: - if (u->ship && u->ship->no==id) break; - if (enter_ship(u, ord, id, lasttry)) { - unit *ub; - ulast = u; - for (ub=u;ub;ub=ub->next) { - if (ub->ship==u->ship) { - ulast = ub; - } - } - } - break; - - default: - if (lasttry) cmistake(u, ord, 79, MSG_MOVE); - - } - if (ulast!=NULL) { - /* Wenn wir hier angekommen sind, war der Befehl - * erfolgreich und wir löschen ihn, damit er im - * zweiten Versuch nicht nochmal ausgeführt wird. */ - *ordp = ord->next; - ord->next = NULL; - free_order(ord); - - if (ulast!=u) { - /* put u behind ulast so it's the last unit in the building */ - *uptr = u->next; - u->next = ulast->next; - ulast->next = u; - } - break; - } - } - if (*ordp==ord) ordp = &ord->next; - } - if (*uptr==u) uptr = &u->next; - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "build.h" + +/* kernel includes */ +#include "alchemy.h" +#include "alliance.h" +#include "connection.h" +#include "building.h" +#include "curse.h" +#include "faction.h" +#include "group.h" +#include "item.h" +#include "magic.h" +#include "message.h" +#include "move.h" +#include "order.h" +#include "pool.h" +#include "race.h" +#include "region.h" +#include "ship.h" +#include "skill.h" +#include "terrain.h" +#include "terrainid.h" +#include "unit.h" + +/* from libutil */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* from libc */ +#include +#include +#include +#include +#include +#include + +/* attributes inclues */ +#include +#include + +#define STONERECYCLE 50 +/* Name, MaxGroesse, MinBauTalent, Kapazitaet, {Eisen, Holz, Stein, BauSilber, + * Laen, Mallorn}, UnterSilber, UnterSpezialTyp, UnterSpezial */ + + +static boolean +CheckOverload(void) +{ + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "rules.check_overload", 0); + } + return value; +} + +/* test if the unit can slip through a siege undetected. + * returns 0 if siege is successful, or 1 if the building is either + * not besieged or the unit can slip through the siege due to better stealth. + */ +static int +slipthru(const region * r, const unit * u, const building * b) +{ + unit *u2; + int n, o; + + /* b ist die burg, in die man hinein oder aus der man heraus will. */ + if (b==NULL || b->besieged < b->size * SIEGEFACTOR) { + return 1; + } + + /* u wird am hinein- oder herausschluepfen gehindert, wenn STEALTH <= + * OBSERVATION +2 der belagerer u2 ist */ + n = eff_skill(u, SK_STEALTH, r); + + for (u2 = r->units; u2; u2 = u2->next) { + if (usiege(u2) == b) { + + if (invisible(u, u2) >= u->number) continue; + + o = eff_skill(u2, SK_PERCEPTION, r); + + if (o + 2 >= n) { + return 0; /* entdeckt! */ + } + } + } + return 1; +} + +boolean +can_contact(const region * r, const unit * u, const unit * u2) +{ + + /* hier geht es nur um die belagerung von burgen */ + + if (u->building == u2->building) + return true; + + /* unit u is trying to contact u2 - unasked for contact. wenn u oder u2 + * nicht in einer burg ist, oder die burg nicht belagert ist, ist + * slipthru () == 1. ansonsten ist es nur 1, wenn man die belagerer */ + + if (slipthru(u->region, u, u->building) + && slipthru(u->region, u2, u2->building)) + return true; + + if (alliedunit(u, u2->faction, HELP_GIVE)) + return true; + + return false; +} + + +static void +contact_cmd(unit * u, order * ord, boolean tries) +{ + /* unit u kontaktiert unit u2. Dies setzt den contact einfach auf 1 - + * ein richtiger toggle ist (noch?) nicht noetig. die region als + * parameter ist nur deswegen wichtig, weil er an getunit () + * weitergegeben wird. dies wird fuer das auffinden von tempunits in + * getnewunit () verwendet! */ + unit *u2; + region * r = u->region; + + init_tokens(ord); + skip_token(); + u2 = getunitg(r, u->faction); + + if (u2!=NULL) { + if (!can_contact(r, u, u2)) { + if (tries) cmistake(u, u->thisorder, 23, MSG_EVENT); + return; + } + usetcontact(u, u2); + } +} +/* ------------------------------------------------------------- */ + +/* ------------------------------------------------------------- */ + + +/* ------------------------------------------------------------- */ + +struct building * +getbuilding(const struct region * r) +{ + building * b = findbuilding(getid()); + if (b==NULL || r!=b->region) return NULL; + return b; +} + +ship * +getship(const struct region * r) +{ + ship *sh, *sx = findship(getshipid()); + for (sh = r->ships; sh; sh = sh->next) { + if (sh == sx) return sh; + } + return NULL; +} + +/* ------------------------------------------------------------- */ + +static void +siege_cmd(unit * u, order * ord) +{ + region * r = u->region; + building *b; + int d, pooled; + int bewaffnete, katapultiere = 0; + static boolean init = false; + static const curse_type * magicwalls_ct; + static item_type * it_catapultammo = NULL; + static item_type * it_catapult = NULL; + if (!init) { + init = true; + magicwalls_ct = ct_find("magicwalls"); + it_catapultammo = it_find("catapultammo"); + it_catapult = it_find("catapult"); + } + /* gibt es ueberhaupt Burgen? */ + + init_tokens(ord); + skip_token(); + b = getbuilding(r); + + if (!b) { + cmistake(u, ord, 31, MSG_BATTLE); + return; + } + + if (!playerrace(u->race)) { + /* keine Drachen, Illusionen, Untote etc */ + cmistake(u, ord, 166, MSG_BATTLE); + return; + } + /* schaden durch katapulte */ + + d = i_get(u->items, it_catapult); + d = MIN(u->number, d); + pooled = get_pooled(u, it_catapultammo->rtype, GET_DEFAULT, d); + d = MIN(pooled, d); + if (eff_skill(u, SK_CATAPULT, r) >= 1) { + katapultiere = d; + d *= eff_skill(u, SK_CATAPULT, r); + } else { + d = 0; + } + + bewaffnete = armedmen(u, true); + if (d == 0 && bewaffnete == 0) { + /* abbruch, falls unbewaffnet oder unfaehig, katapulte zu benutzen */ + cmistake(u, ord, 80, MSG_EVENT); + return; + } + + if (!is_guard(u, GUARD_TRAVELTHRU)) { + /* abbruch, wenn die einheit nicht vorher die region bewacht - als + * warnung fuer alle anderen! */ + cmistake(u, ord, 81, MSG_EVENT); + return; + } + /* einheit und burg markieren - spart zeit beim behandeln der einheiten + * in der burg, falls die burg auch markiert ist und nicht alle + * einheiten wieder abgesucht werden muessen! */ + + usetsiege(u, b); + b->besieged += MAX(bewaffnete, katapultiere); + + /* definitiver schaden eingeschraenkt */ + + d = MIN(d, b->size - 1); + + /* meldung, schaden anrichten */ + if (d && !curse_active(get_curse(b->attribs, magicwalls_ct))) { + b->size -= d; + use_pooled(u, it_catapultammo->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, d); + /* send message to the entire region */ + ADDMSG(&r->msgs, msg_message("siege_catapults", + "unit building destruction", u, b, d)); + } else { + /* send message to the entire region */ + ADDMSG(&r->msgs, msg_message("siege", + "unit building", u, b)); + } +} + +void +do_siege(region *r) +{ + if (fval(r->terrain, LAND_REGION)) { + unit *u; + + for (u = r->units; u; u = u->next) { + if (get_keyword(u->thisorder) == K_BESIEGE) { + siege_cmd(u, u->thisorder); + } + } + } +} +/* ------------------------------------------------------------- */ + +static void +destroy_road(unit *u, int nmax, struct order * ord) +{ + direction_t d = getdirection(u->faction->locale); + unit *u2; + region *r = u->region; + short n = (short)nmax; + + if (nmax>SHRT_MAX) n = SHRT_MAX; + else if (nmax<0) n = 0; + + for (u2=r->units;u2;u2=u2->next) { + if (u2->faction!=u->faction && is_guard(u2, GUARD_TAX) + && cansee(u2->faction, u->region, u, 0) + && !alliedunit(u, u2->faction, HELP_GUARD)) { + cmistake(u, ord, 70, MSG_EVENT); + return; + } + } + + if (d==NODIRECTION) { + /* Die Richtung wurde nicht erkannt */ + cmistake(u, ord, 71, MSG_PRODUCE); + } else { + short road = rroad(r, d); + n = MIN(n, road); + if (n!=0) { + region * r2 = rconnect(r,d); + int willdo = eff_skill(u, SK_ROAD_BUILDING, r)*u->number; + willdo = MIN(willdo, n); + if (willdo==0) { + /* TODO: error message */ + } + if (willdo>SHRT_MAX) road = 0; + else road = road - (short)willdo; + rsetroad(r, d, road); + ADDMSG(&u->faction->msgs, msg_message("destroy_road", + "unit from to", u, r, r2)); + } + } +} + +int +destroy_cmd(unit * u, struct order * ord) +{ + ship *sh; + unit *u2; + region * r = u->region; + const construction * con = NULL; + int size = 0; + const char *s; + int n = INT_MAX; + + if (u->number < 1) + return 0; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + if (findparam(s, u->faction->locale)==P_ROAD) { + destroy_road(u, INT_MAX, ord); + return 0; + } + + if (s && *s) { + n = atoi((const char *)s); + if (n <= 0) { + cmistake(u, ord, 288, MSG_PRODUCE); + return 0; + } + } + + if (getparam(u->faction->locale) == P_ROAD) { + destroy_road(u, n, ord); + return 0; + } + + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 138, MSG_PRODUCE); + return 0; + } + + if (u->building) { + building *b = u->building; + + if (n >= b->size) { + /* destroy completly */ + /* all units leave the building */ + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->building == b) { + u2->building = 0; + freset(u2, UFL_OWNER); + } + } + ADDMSG(&u->faction->msgs, msg_message("destroy", + "building unit", b, u)); + con = b->type->construction; + remove_building(&r->buildings, b); + } else { + /* partial destroy */ + b->size -= n; + ADDMSG(&u->faction->msgs, msg_message("destroy_partial", + "building unit", b, u)); + } + } else if (u->ship) { + sh = u->ship; + + if (fval(r->terrain, SEA_REGION)) { + cmistake(u, ord, 14, MSG_EVENT); + return 0; + } + + if (n >= (sh->size*100)/sh->type->construction->maxsize) { + /* destroy completly */ + /* all units leave the ship */ + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->ship == sh) { + u2->ship = 0; + freset(u2, UFL_OWNER); + } + } + ADDMSG(&u->faction->msgs, msg_message("shipdestroy", + "unit region ship", u, r, sh)); + con = sh->type->construction; + remove_ship(&sh->region->ships, sh); + } else { + /* partial destroy */ + sh->size -= (sh->type->construction->maxsize * n)/100; + ADDMSG(&u->faction->msgs, msg_message("shipdestroy_partial", + "unit region ship", u, r, sh)); + } + } else { + log_error(("Die Einheit %s von %s war owner eines objects, war aber weder in einer Burg noch in einem Schiff.\n", + unitname(u), u->faction->name, u->faction->email)); + } + + if (con) { + /* TODO: Nicht an ZERSTÖRE mit Punktangabe angepaßt! */ + int c; + for (c=0;con->materials[c].number;++c) { + const requirement * rq = con->materials+c; + int recycle = (int)(rq->recycle * rq->number * size/con->reqsize); + if (recycle) { + change_resource(u, rq->rtype, recycle); + } + } + } + return 0; +} +/* ------------------------------------------------------------- */ + +void +build_road(region * r, unit * u, int size, direction_t d) +{ + int n, left; + region * rn = rconnect(r,d); + + assert(u->number); + if (!eff_skill(u, SK_ROAD_BUILDING, r)) { + cmistake(u, u->thisorder, 103, MSG_PRODUCE); + return; + } + if (besieged(u)) { + cmistake(u, u->thisorder, 60, MSG_PRODUCE); + return; + } + + if (rn==NULL || rn->terrain->max_road < 0) { + cmistake(u, u->thisorder, 94, MSG_PRODUCE); + return; + } + + if (r->terrain->max_road < 0) { + cmistake(u, u->thisorder, 94, MSG_PRODUCE); + return; + } + + if (r->terrain == newterrain(T_SWAMP)) { + /* wenn kein Damm existiert */ + static const struct building_type * bt_dam; + if (!bt_dam) bt_dam = bt_find("dam"); + assert(bt_dam); + if (!buildingtype_exists(r, bt_dam, true)) { + cmistake(u, u->thisorder, 132, MSG_PRODUCE); + return; + } + } else if (r->terrain == newterrain(T_DESERT)) { + static const struct building_type * bt_caravan; + if (!bt_caravan) bt_caravan = bt_find("caravan"); + assert(bt_caravan); + /* wenn keine Karawanserei existiert */ + if (!buildingtype_exists(r, bt_caravan, true)) { + cmistake(u, u->thisorder, 133, MSG_PRODUCE); + return; + } + } else if (r->terrain == newterrain(T_GLACIER)) { + static const struct building_type * bt_tunnel; + if (!bt_tunnel) bt_tunnel = bt_find("tunnel"); + assert(bt_tunnel); + /* wenn kein Tunnel existiert */ + if (!buildingtype_exists(r, bt_tunnel, true)) { + cmistake(u, u->thisorder, 131, MSG_PRODUCE); + return; + } + } + + /* left kann man noch bauen */ + left = r->terrain->max_road - rroad(r, d); + + /* hoffentlich ist r->road <= r->terrain->max_road, n also >= 0 */ + if (left <= 0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_roads_finished", "")); + return; + } + + if (size>0) left = MIN(size, left); + /* baumaximum anhand der rohstoffe */ + if (u->race == new_race[RC_STONEGOLEM]){ + n = u->number * GOLEM_STONE; + } else { + n = get_pooled(u, oldresourcetype[R_STONE], GET_DEFAULT, left); + if (n==0) { + cmistake(u, u->thisorder, 151, MSG_PRODUCE); + return; + } + } + left = MIN(n, left); + + /* n = maximum by skill. try to maximize it */ + n = u->number * eff_skill(u, SK_ROAD_BUILDING, r); + if (n < left) { + item * itm = *i_find(&u->items, olditemtype[I_RING_OF_NIMBLEFINGER]); + if (itm!=NULL && itm->number>0) { + int rings = MIN(u->number, itm->number); + n = n * ((roqf_factor()-1)*rings+u->number) / u->number; + } + } + if (n < left) { + int dm = get_effect(u, oldpotiontype[P_DOMORE]); + if (dm != 0) { + int sk = eff_skill(u, SK_ROAD_BUILDING, r); + int todo = (left - n + sk - 1) / sk; + todo = MIN(todo, u->number); + dm = MIN(dm, todo); + change_effect(u, oldpotiontype[P_DOMORE], -dm); + n += dm * sk; + } /* Auswirkung Schaffenstrunk */ + } + + /* make minimum of possible and available: */ + n = MIN(left, n); + + /* n is now modified by several special effects, so we have to + * minimize it again to make sure the road will not grow beyond + * maximum. */ + rsetroad(r, d, rroad(r, d) + (short)n); + + if (u->race == new_race[RC_STONEGOLEM]) { + int golemsused = n / GOLEM_STONE; + if (n%GOLEM_STONE != 0){ + ++golemsused; + } + scale_number(u, u->number - golemsused); + } else { + use_pooled(u, oldresourcetype[R_STONE], GET_DEFAULT, n); + /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ + produceexp(u, SK_ROAD_BUILDING, MIN(n, u->number)); + } + ADDMSG(&u->faction->msgs, msg_message("buildroad", + "region unit size", r, u, n)); +} +/* ------------------------------------------------------------- */ + +/* ** ** ** ** ** ** * + * new build rules * + * ** ** ** ** ** ** */ + +static int +required(int size, int msize, int maxneed) + /* um size von msize Punkten zu bauen, + * braucht man required von maxneed resourcen */ +{ + int used; + + used = size * maxneed / msize; + if (size * maxneed % msize) + ++used; + return used; +} + +static int +matmod(const attrib * a, const unit * u, const resource_type * material, int value) +{ + for (a=a_find((attrib*)a, &at_matmod);a && a->type==&at_matmod;a=a->next) { + mm_fun fun = (mm_fun)a->data.f; + value = fun(u, material, value); + if (value<0) return value; /* pass errors to caller */ + } + return value; +} + +int roqf_factor(void) +{ + int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "rules.economy.roqf", 10); + } + return value; +} + +/** Use up resources for building an object. +* Build up to 'size' points of 'type', where 'completed' +* of the first object have already been finished. return the +* actual size that could be built. +*/ +int +build(unit * u, const construction * ctype, int completed, int want) +{ + const construction * type = ctype; + int skills = INT_MAX; /* number of skill points remainig */ + int basesk = 0; + int made = 0; + + if (want<=0) return 0; + if (type==NULL) return 0; + if (type->improvement==NULL && completed==type->maxsize) + return ECOMPLETE; + if (type->btype!=NULL) { + building * b; + if (!u->building || u->building->type!=type->btype) { + return EBUILDINGREQ; + } + b = inside_building(u); + if (b==NULL) return EBUILDINGREQ; + } + + if (type->skill!=NOSKILL) { + int effsk; + int dm = get_effect(u, oldpotiontype[P_DOMORE]); + + assert(u->number); + basesk = effskill(u, type->skill); + if (basesk==0) return ENEEDSKILL; + + effsk = basesk; + if (inside_building(u)) { + effsk = skillmod(u->building->type->attribs, u, u->region, type->skill, + effsk, SMF_PRODUCTION); + } + effsk = skillmod(type->attribs, u, u->region, type->skill, + effsk, SMF_PRODUCTION); + if (effsk<0) return effsk; /* pass errors to caller */ + if (effsk==0) return ENEEDSKILL; + + skills = effsk * u->number; + + /* technically, nimblefinge and domore should be in a global set of + * "game"-attributes, (as at_skillmod) but for a while, we're leaving + * them in here. */ + + if (dm != 0) { + /* Auswirkung Schaffenstrunk */ + dm = MIN(dm, u->number); + change_effect(u, oldpotiontype[P_DOMORE], -dm); + skills += dm * effsk; + } + } + for (;want>0 && skills>0;) { + int c, n; + + /* skip over everything that's already been done: + * type->improvement==NULL means no more improvements, but no size limits + * type->improvement==type means build another object of the same time + * while material lasts type->improvement==x means build x when type + * is finished */ + while (type->improvement!=NULL && + type->improvement!=type && + type->maxsize>0 && + type->maxsize<=completed) + { + completed -= type->maxsize; + type = type->improvement; + } + if (type==NULL) { + if (made==0) return ECOMPLETE; + break; /* completed */ + } + + /* Hier ist entweder maxsize == -1, oder completed < maxsize. + * Andernfalls ist das Datenfile oder sonstwas kaputt... + * (enno): Nein, das ist für Dinge, bei denen die nächste Ausbaustufe + * die gleiche wie die vorherige ist. z.b. gegenstände. + */ + if (type->maxsize>1) { + completed = completed % type->maxsize; + } + else { + completed = 0; assert(type->reqsize>=1); + } + + if (basesk < type->minskill) { + if (made==0) return ELOWSKILL; /* not good enough to go on */ + } + + /* n = maximum buildable size */ + if (type->minskill > 1) { + n = skills / type->minskill; + } else { + n = skills; + } + /* Flinkfingerring wirkt nicht auf Mengenbegrenzte (magische) + * Talente */ + if (skill_limit(u->faction, type->skill)==INT_MAX) { + int i = 0; + item * itm = *i_find(&u->items, olditemtype[I_RING_OF_NIMBLEFINGER]); + if (itm!=NULL) i = itm->number; + if (i>0) { + int rings = MIN(u->number, i); + n = n * ((roqf_factor()-1)*rings+u->number) / u->number; + } + } + + if (want>0) { + n = MIN(want, n); + } + + if (type->maxsize>0) { + n = MIN(type->maxsize-completed, n); + if (type->improvement==NULL) { + want = n; + } + } + + if (type->materials) for (c=0;n>0 && type->materials[c].number;c++) { + const struct resource_type * rtype = type->materials[c].rtype; + int need, prebuilt; + int canuse = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); + + if (inside_building(u)) { + canuse = matmod(u->building->type->attribs, u, rtype, canuse); + } + + if (canuse<0) return canuse; /* pass errors to caller */ + canuse = matmod(type->attribs, u, rtype, canuse); + if (type->reqsize>1) { + prebuilt = required(completed, type->reqsize, type->materials[c].number); + for (;n;) { + need = required(completed + n, type->reqsize, type->materials[c].number); + if (need-prebuilt<=canuse) break; + --n; /* TODO: optimieren? */ + } + } else { + int maxn = canuse / type->materials[c].number; + if (maxn < n) n = maxn; + } + } + if (n<=0) { + if (made==0) return ENOMATERIALS; + else break; + } + if (type->materials) for (c=0;type->materials[c].number;c++) { + const struct resource_type * rtype = type->materials[c].rtype; + int prebuilt = required(completed, type->reqsize, type->materials[c].number); + int need = required(completed + n, type->reqsize, type->materials[c].number); + int multi = 1; + int canuse = 100; /* normalization */ + if (inside_building(u)) canuse = matmod(u->building->type->attribs, u, rtype, canuse); + if (canuse<0) return canuse; /* pass errors to caller */ + canuse = matmod(type->attribs, u, rtype, canuse); + + assert(canuse % 100 == 0 || !"only constant multipliers are implemented in build()"); + multi = canuse/100; + if (canuse<0) return canuse; /* pass errors to caller */ + + use_pooled(u, rtype, GET_DEFAULT, (need-prebuilt+multi-1)/multi); + } + made += n; + skills -= n * type->minskill; + want -= n; + completed = completed + n; + } + /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ + produceexp(u, ctype->skill, MIN(made, u->number)); + + return made; +} + +message * +msg_materials_required(unit * u, order * ord, const construction * ctype, int multi) +{ + int c; + /* something missing from the list of materials */ + resource * reslist = NULL; + + if (multi<=0 || multi==INT_MAX) multi = 1; + for (c=0;ctype->materials[c].number; ++c) { + resource * res = malloc(sizeof(resource)); + res->number = multi * ctype->materials[c].number / ctype->reqsize; + res->type = ctype->materials[c].rtype; + res->next = reslist; + reslist = res; + } + return msg_feedback(u, ord, "build_required", "required", reslist); +} + +int +maxbuild(const unit * u, const construction * cons) + /* calculate maximum size that can be built from available material */ + /* !! ignores maximum objectsize and improvements...*/ +{ + int c; + int maximum = INT_MAX; + for (c=0;cons->materials[c].number;c++) { + const resource_type * rtype = cons->materials[c].rtype; + int have = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); + int need = required(1, cons->reqsize, cons->materials[c].number); + if (haveregion; + boolean newbuilding = false; + int n = want, built = 0, id; + building * b = NULL; + /* einmalige Korrektur */ + const char * btname; + order * new_order = NULL; + const struct locale * lang = u->faction->locale; + static int rule_other = -1; + + assert(u->number); + if (eff_skill(u, SK_BUILDING, r) == 0) { + cmistake(u, ord, 101, MSG_PRODUCE); + return; + } + + /* Falls eine Nummer angegeben worden ist, und ein Gebaeude mit der + * betreffenden Nummer existiert, ist b nun gueltig. Wenn keine Burg + * gefunden wurde, dann wird nicht einfach eine neue erbaut. Ansonsten + * baut man an der eigenen burg weiter. */ + + /* Wenn die angegebene Nummer falsch ist, KEINE Burg bauen! */ + id = getid(); + if (id>0) { /* eine Nummer angegeben, keine neue Burg bauen */ + b = findbuilding(id); + if (!b || b->region != u->region) { /* eine Burg mit dieser Nummer gibt es hier nicht */ + /* vieleicht Tippfehler und die eigene Burg ist gemeint? */ + if (u->building && u->building->type==btype) { + b = u->building; + } else { + /* keine neue Burg anfangen wenn eine Nummer angegeben war */ + cmistake(u, ord, 6, MSG_PRODUCE); + return; + } + } + } else if (u->building && u->building->type==btype) { + b = u->building; + } + + if (b) btype = b->type; + + if (b && fval(btype, BTF_UNIQUE) && buildingtype_exists(r, btype, false)) { + /* only one of these per region */ + cmistake(u, ord, 93, MSG_PRODUCE); + return; + } + if (besieged(u)) { + /* units under siege can not build */ + cmistake(u, ord, 60, MSG_PRODUCE); + return; + } + if (btype->flags & BTF_NOBUILD) { + /* special building, cannot be built */ + cmistake(u, ord, 221, MSG_PRODUCE); + return; + } + if (btype->flags & BTF_ONEPERTURN) { + if(b && fval(b, BLD_EXPANDED)) { + cmistake(u, ord, 318, MSG_PRODUCE); + return; + } + n = 1; + } + if (b) { + if (rule_other<0) { + rule_other = get_param_int(global.parameters, "rules.build.other_buildings", 1); + } + if (!rule_other) { + unit * owner = building_owner(b); + if (!owner || owner->faction!=u->faction) { + cmistake(u, ord, 1222, MSG_PRODUCE); + return; + } + } + } + + if (b) built = b->size; + if (n<=0 || n == INT_MAX) { + if(b == NULL) { + if(btype->maxsize > 0) { + n = btype->maxsize - built; + } else { + n = INT_MAX; + } + } else { + if (b->type->maxsize > 0) { + n = b->type->maxsize - built; + } else { + n = INT_MAX; + } + } + } + built = build(u, btype->construction, built, n); + + switch (built) { + case ECOMPLETE: + /* the building is already complete */ + cmistake(u, ord, 4, MSG_PRODUCE); + return; + case ENOMATERIALS: + ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, btype->construction, want)); + return; + case ELOWSKILL: + case ENEEDSKILL: + /* no skill, or not enough skill points to build */ + cmistake(u, ord, 50, MSG_PRODUCE); + return; + } + + + /* at this point, the building size is increased. */ + if (b==NULL) { + /* build a new building */ + b = new_building(btype, r, lang); + b->type = btype; + fset(b, BLD_MAINTAINED); + + /* Die Einheit befindet sich automatisch im Inneren der neuen Burg. */ + if (leave(u, false)) { + u->building = b; + fset(u, UFL_OWNER); + } + +#ifdef WDW_PYRAMID + if(b->type == bt_find("pyramid") && f_get_alliance(u->faction) != NULL) { + attrib * a = a_add(&b->attribs, a_new(&at_alliance)); + a->data.i = u->faction->alliance->id; + } +#endif + + newbuilding = true; + } + + btname = LOC(lang, btype->_name); + + if (want-built <= 0) { + /* gebäude fertig */ + new_order = default_order(lang); + } else if (want!=INT_MAX) { + /* reduzierte restgröße */ + const char * hasspace = strchr(btname, ' '); + if (hasspace) { + new_order = create_order(K_MAKE, lang, "%d \"%s\" %i", n-built, btname, b->no); + } else { + new_order = create_order(K_MAKE, lang, "%d %s %i", n-built, btname, b->no); + } + } else if (btname) { + /* Neues Haus, Befehl mit Gebäudename */ + const char * hasspace = strchr(btname, ' '); + if (hasspace) { + new_order = create_order(K_MAKE, lang, "\"%s\" %i", btname, b->no); + } else { + new_order = create_order(K_MAKE, lang, "%s %i", btname, b->no); + } + } + + if (new_order) { + replace_order(&u->orders, ord, new_order); + free_order(new_order); + } + + b->size += built; + fset(b, BLD_EXPANDED); + + update_lighthouse(b); + + + ADDMSG(&u->faction->msgs, msg_message("buildbuilding", + "building unit size", b, u, built)); +} + +static void +build_ship(unit * u, ship * sh, int want) +{ + const construction * construction = sh->type->construction; + int size = (sh->size * DAMAGE_SCALE - sh->damage) / DAMAGE_SCALE; + int n; + int can = build(u, construction, size, want); + + if ((n=construction->maxsize - sh->size)>0 && can>0) { + if (can>=n) { + sh->size += n; + can -= n; + } + else { + sh->size += can; + n=can; + can = 0; + } + } + + if (sh->damage && can) { + int repair = MIN(sh->damage, can * DAMAGE_SCALE); + n += repair / DAMAGE_SCALE; + if (repair % DAMAGE_SCALE) ++n; + sh->damage = sh->damage - repair; + } + + if (n) ADDMSG(&u->faction->msgs, + msg_message("buildship", "ship unit size", sh, u, n)); +} + +void +create_ship(region * r, unit * u, const struct ship_type * newtype, int want, order * ord) +{ + ship *sh; + int msize; + const construction * cons = newtype->construction; + order * new_order; + + if (!eff_skill(u, SK_SHIPBUILDING, r)) { + cmistake(u, ord, 100, MSG_PRODUCE); + return; + } + if (besieged(u)) { + cmistake(u, ord, 60, MSG_PRODUCE); + return; + } + + /* check if skill and material for 1 size is available */ + if (eff_skill(u, cons->skill, r) < cons->minskill) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_build_skill_low", "value name", + cons->minskill, newtype->name[1])); + return; + } + + msize = maxbuild(u, cons); + if (msize==0) { + cmistake(u, ord, 88, MSG_PRODUCE); + return; + } + if (want>0) want = MIN(want, msize); + else want = msize; + + sh = new_ship(newtype, u->faction->locale, r); + + if (leave(u, false)) { + if (fval(u->race, RCF_CANSAIL)) { + u->ship = sh; + fset(u, UFL_OWNER); + } + } + new_order = create_order(K_MAKE, u->faction->locale, "%s %i", LOC(u->faction->locale, parameters[P_SHIP]), sh->no); + replace_order(&u->orders, ord, new_order); + free_order(new_order); + + build_ship(u, sh, want); +} + +void +continue_ship(region * r, unit * u, int want) +{ + const construction * cons; + ship *sh; + int msize; + + if (!eff_skill(u, SK_SHIPBUILDING, r)) { + cmistake(u, u->thisorder, 100, MSG_PRODUCE); + return; + } + + /* Die Schiffsnummer bzw der Schiffstyp wird eingelesen */ + sh = getship(r); + + if (!sh) sh = u->ship; + + if (!sh) { + cmistake(u, u->thisorder, 20, MSG_PRODUCE); + return; + } + cons = sh->type->construction; + assert(cons->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (sh->size==cons->maxsize && !sh->damage) { + cmistake(u, u->thisorder, 16, MSG_PRODUCE); + return; + } + if (eff_skill(u, cons->skill, r) < cons->minskill) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_build_skill_low", "value name", + cons->minskill, sh->type->name[1])); + return; + } + msize = maxbuild(u, cons); + if (msize==0) { + cmistake(u, u->thisorder, 88, MSG_PRODUCE); + return; + } + if (want > 0) want = MIN(want, msize); + else want = msize; + + build_ship(u, sh, want); +} +/* ------------------------------------------------------------- */ + +static boolean +mayenter(region * r, unit * u, building * b) +{ + unit *u2; + if (fval(b, BLD_UNGUARDED)) return true; + u2 = building_owner(b); + + if (u2==NULL || ucontact(u2, u) + || alliedunit(u2, u->faction, HELP_GUARD)) return true; + + return false; +} + +static int +mayboard(const unit * u, const ship * sh) +{ + unit *u2 = shipowner(sh); + + return (!u2 || ucontact(u2, u) || alliedunit(u2, u->faction, HELP_GUARD)); +} + +int +leave_cmd(unit * u, struct order * ord) +{ + region * r = u->region; + + if (fval(u, UFL_ENTER)) { + /* if we just entered this round, then we don't leave again */ + return 0; + } + + if (fval(r->terrain, SEA_REGION) && u->ship) { + if(!fval(u->race, RCF_SWIM)) { + cmistake(u, ord, 11, MSG_MOVE); + return 0; + } + if (has_horses(u)) { + cmistake(u, ord, 231, MSG_MOVE); + return 0; + } + } + if (!slipthru(r, u, u->building)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "entrance_besieged", "building", u->building)); + } else { + leave(u, true); + } + return 0; +} + +static boolean +enter_ship(unit * u, struct order * ord, int id, boolean report) +{ + region * r = u->region; + ship * sh; + + /* Muß abgefangen werden, sonst könnten Schwimmer an + * Bord von Schiffen an Land gelangen. */ + if (!fval(u->race, RCF_CANSAIL) || (!fval(u->race, RCF_WALK) && !fval(u->race, RCF_FLY))) { + cmistake(u, ord, 233, MSG_MOVE); + return false; + } + + sh = findship(id); + if (sh == NULL || sh->region!=r) { + if (report) cmistake(u, ord, 20, MSG_MOVE); + return false; + } + if (sh==u->ship) return true; + if (!mayboard(u, sh)) { + if (report) cmistake(u, ord, 34, MSG_MOVE); + return false; + } + if (CheckOverload()) { + int sweight, scabins; + int mweight = shipcapacity(sh); + int mcabins = sh->type->cabins; + + if (mweight>0) { + getshipweight(sh, &sweight, &scabins); + sweight += weight(u); + if (mcabins) { + int pweight = u->number * u->race->weight; + /* weight goes into number of cabins, not cargo */ + scabins += pweight; + sweight -= pweight; + } + + if (sweight > mweight || (mcabins && (scabins > mcabins))) { + if (report) cmistake(u, ord, 34, MSG_MOVE); + return false; + } + } + } + + if (leave(u, false)) { + u->ship = sh; + + if (shipowner(sh) == NULL) { + fset(u, UFL_OWNER); + } + fset(u, UFL_ENTER); + } + return true; +} + +static boolean +enter_building(unit * u, order * ord, int id, boolean report) +{ + region * r = u->region; + building * b; + + /* Schwimmer können keine Gebäude betreten, außer diese sind + * auf dem Ozean */ + if (!fval(u->race, RCF_WALK) && !fval(u->race, RCF_FLY)) { + if (!fval(r->terrain, SEA_REGION)) { + if (report) { + cmistake(u, ord, 232, MSG_MOVE); + } + return false; + } + } + + b = findbuilding(id); + if (b==NULL || b->region!=r) { + if (report) { + cmistake(u, ord, 6, MSG_MOVE); + } + return false; + } + if (!mayenter(r, u, b)) { + if (report) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "entrance_denied", "building", b)); + } + return false; + } + if (!slipthru(r, u, b)) { + if (report) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "entrance_besieged", "building", b)); + } + return false; + } + + if (leave(u, false)) { + if (building_owner(b) == 0) { + fset(u, UFL_OWNER); + } + fset(u, UFL_ENTER); + u->building = b; + return true; + } + return false; +} + +void +do_misc(region * r, boolean lasttry) +{ + unit **uptr, *uc; + + for (uc = r->units; uc; uc = uc->next) { + order * ord; + for (ord = uc->orders; ord; ord = ord->next) { + switch (get_keyword(ord)) { + case K_CONTACT: + contact_cmd(uc, ord, lasttry); + break; + } + } + } + + for (uptr = &r->units; *uptr;) { + unit * u = *uptr; + order ** ordp = &u->orders; + + while (*ordp) { + order * ord = *ordp; + if (get_keyword(ord) == K_ENTER) { + param_t p; + int id; + unit * ulast = NULL; + + init_tokens(ord); + skip_token(); + p = getparam(u->faction->locale); + id = getid(); + + switch (p) { + case P_BUILDING: + case P_GEBAEUDE: + if (u->building && u->building->no==id) break; + if (enter_building(u, ord, id, lasttry)) { + unit *ub; + for (ub=u;ub;ub=ub->next) { + if (ub->building==u->building) { + ulast = ub; + } + } + } + break; + + case P_SHIP: + if (u->ship && u->ship->no==id) break; + if (enter_ship(u, ord, id, lasttry)) { + unit *ub; + ulast = u; + for (ub=u;ub;ub=ub->next) { + if (ub->ship==u->ship) { + ulast = ub; + } + } + } + break; + + default: + if (lasttry) cmistake(u, ord, 79, MSG_MOVE); + + } + if (ulast!=NULL) { + /* Wenn wir hier angekommen sind, war der Befehl + * erfolgreich und wir löschen ihn, damit er im + * zweiten Versuch nicht nochmal ausgeführt wird. */ + *ordp = ord->next; + ord->next = NULL; + free_order(ord); + + if (ulast!=u) { + /* put u behind ulast so it's the last unit in the building */ + *uptr = u->next; + u->next = ulast->next; + ulast->next = u; + } + break; + } + } + if (*ordp==ord) ordp = &ord->next; + } + if (*uptr==u) uptr = &u->next; + } +} diff --git a/src/kernel/build.h b/src/kernel/build.h index 012f06000..35d8f44a3 100644 --- a/src/kernel/build.h +++ b/src/kernel/build.h @@ -1,99 +1,99 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_BUILD -#define H_KRNL_BUILD - -#include "types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Die enums fuer Gebauede werden nie gebraucht, nur bei der Bestimmung - * des Schutzes durch eine Burg wird die Reihenfolge und MAXBUILDINGS - * wichtig - */ - -struct xml_tag; - -typedef struct requirement { - const struct resource_type * rtype; - int number; - double recycle; /* recycling quota */ -} requirement; - -typedef struct construction { - skill_t skill; /* skill req'd per point of size */ - int minskill; /* skill req'd per point of size */ - - int maxsize; /* maximum size of this type */ - int reqsize; /* size of object using up 1 set of requirement. */ - requirement * materials; /* material req'd to build one object */ - const struct building_type * btype; - /* building type required to make this thing */ - - struct construction * improvement; - /* next level, if upgradable. if more than one of these items - * can be built (weapons, armour) per turn, must not be NULL, - * but point to the same type again: - * const_sword.improvement = &const_sword - * last level of a building points to NULL, as do objects of - * an unlimited size. - */ - struct attrib * attribs; - /* stores skill modifiers and other attributes */ - -} construction; - -extern int destroy_cmd(struct unit * u, struct order * ord); -extern int leave_cmd(struct unit * u, struct order * ord); - -extern boolean can_contact(const struct region *r, const struct unit *u, const struct unit *u2); - -void do_siege(struct region *r); -void build_road(struct region * r, struct unit * u, int size, direction_t d); -void create_ship(struct region * r, struct unit * u, const struct ship_type * newtype, int size, struct order * ord); -void continue_ship(struct region * r, struct unit * u, int size); - -struct building * getbuilding(const struct region * r); -struct ship *getship(const struct region * r); - -void do_misc(struct region *r, boolean tries); - -void reportevent(struct region * r, char *s); - -void shash(struct ship * sh); -void sunhash(struct ship * sh); -extern int roqf_factor(void); - -extern int build(struct unit * u, const construction * ctype, int completed, int want); -extern int maxbuild(const struct unit *u, const construction *cons); -extern struct message * msg_materials_required(struct unit * u, struct order * ord, const struct construction * ctype, int multi); -/** error messages that build may return: */ -#define ELOWSKILL -1 -#define ENEEDSKILL -2 -#define ECOMPLETE -3 -#define ENOMATERIALS -4 -#define EBUILDINGREQ -5 - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_BUILD +#define H_KRNL_BUILD + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Die enums fuer Gebauede werden nie gebraucht, nur bei der Bestimmung + * des Schutzes durch eine Burg wird die Reihenfolge und MAXBUILDINGS + * wichtig + */ + +struct xml_tag; + +typedef struct requirement { + const struct resource_type * rtype; + int number; + double recycle; /* recycling quota */ +} requirement; + +typedef struct construction { + skill_t skill; /* skill req'd per point of size */ + int minskill; /* skill req'd per point of size */ + + int maxsize; /* maximum size of this type */ + int reqsize; /* size of object using up 1 set of requirement. */ + requirement * materials; /* material req'd to build one object */ + const struct building_type * btype; + /* building type required to make this thing */ + + struct construction * improvement; + /* next level, if upgradable. if more than one of these items + * can be built (weapons, armour) per turn, must not be NULL, + * but point to the same type again: + * const_sword.improvement = &const_sword + * last level of a building points to NULL, as do objects of + * an unlimited size. + */ + struct attrib * attribs; + /* stores skill modifiers and other attributes */ + +} construction; + +extern int destroy_cmd(struct unit * u, struct order * ord); +extern int leave_cmd(struct unit * u, struct order * ord); + +extern boolean can_contact(const struct region *r, const struct unit *u, const struct unit *u2); + +void do_siege(struct region *r); +void build_road(struct region * r, struct unit * u, int size, direction_t d); +void create_ship(struct region * r, struct unit * u, const struct ship_type * newtype, int size, struct order * ord); +void continue_ship(struct region * r, struct unit * u, int size); + +struct building * getbuilding(const struct region * r); +struct ship *getship(const struct region * r); + +void do_misc(struct region *r, boolean tries); + +void reportevent(struct region * r, char *s); + +void shash(struct ship * sh); +void sunhash(struct ship * sh); +extern int roqf_factor(void); + +extern int build(struct unit * u, const construction * ctype, int completed, int want); +extern int maxbuild(const struct unit *u, const construction *cons); +extern struct message * msg_materials_required(struct unit * u, struct order * ord, const struct construction * ctype, int multi); +/** error messages that build may return: */ +#define ELOWSKILL -1 +#define ENEEDSKILL -2 +#define ECOMPLETE -3 +#define ENOMATERIALS -4 +#define EBUILDINGREQ -5 + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/kernel/building.c b/src/kernel/building.c index 3b2553812..c16efe8b9 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -1,695 +1,695 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include - -#include -#include "building.h" - -/* kernel includes */ -#include "item.h" -#include "curse.h" /* für C_NOCOST */ -#include "unit.h" -#include "faction.h" -#include "region.h" -#include "skill.h" -#include "magic.h" -#include "save.h" -#include "version.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -/* attributes includes */ -#include - -static const char * NULLSTRING = "(null)"; - -static void -lc_init(struct attrib *a) -{ - a->data.v = calloc(1, sizeof(building_action)); -} - -static void -lc_done(struct attrib *a) -{ - building_action * data = (building_action*)a->data.v; - if (data->fname) free(data->fname); - if (data->param) free(data->param); - free(data); -} - -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; - const char * fparam = data->param; - building * b = data->b; - - write_building_reference(b, store); - store->w_tok(store, fname); - store->w_tok(store, fparam?fparam:NULLSTRING); -} - -static int -lc_read(struct attrib * a, void * owner, struct storage * store) -{ - building_action * data = (building_action*)a->data.v; - int result = read_reference(&data->b, store, read_building_reference, resolve_building); - if (store->versionfname = store->r_str(store); - } else { - data->fname = store->r_tok(store); - } - if (store->version>=BACTION_VERSION) { - char lbuf[256]; - if (store->versionr_str_buf(store, lbuf, sizeof(lbuf)); - } else { - store->r_tok_buf(store, lbuf, sizeof(lbuf)); - } - if (strcmp(lbuf, NULLSTRING)==0) data->param = NULL; - else data->param = strdup(lbuf); - } else { - data->param = strdup(NULLSTRING); - } - if (result==0 && !data->b) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -attrib_type at_building_action = { - "lcbuilding", - lc_init, lc_done, - NULL, - lc_write, lc_read -}; - -typedef struct building_typelist { - struct building_typelist * next; - building_type * type; -} building_typelist; - -static building_typelist *buildingtypes; - -building_type * -bt_find(const char* name) -{ - const struct building_typelist * btl = buildingtypes; - assert(name); - while (btl && strcmp(btl->type->_name, name)) btl = btl->next; - if (btl==NULL) { - return NULL; - } - return btl->type; -} - -void -bt_register(building_type * type) -{ - struct building_typelist * btl = malloc(sizeof(building_type)); - if (type->init) type->init(type); - btl->type = type; - btl->next = buildingtypes; - buildingtypes = btl; -} - -int -buildingcapacity(const building * b) -{ - if (b->type->capacity>=0) { - if (b->type->maxcapacity>=0) { - return MIN(b->type->maxcapacity, b->size * b->type->capacity); - } - return b->size * b->type->capacity; - } - if (b->size>=b->type->maxsize) { - if (b->type->maxcapacity>=0) { - return b->type->maxcapacity; - } - } - return 0; -} - -attrib_type at_building_generic_type = { - "building_generic_type", NULL, NULL, NULL, a_writestring, a_readstring, ATF_UNIQUE -}; - -const char * -buildingtype(const building_type * btype, const building * b, int bsize) -{ - const char * s = NULL; - static boolean init_generic = false; - static const struct building_type * bt_generic; - - if (!init_generic) { - init_generic = true; - bt_generic = bt_find("generic"); - } - - if (btype == bt_generic) { - const attrib *a = a_find(b->attribs, &at_building_generic_type); - if (a) s = (const char*)a->data.v; - } - - if (btype->name) s = btype->name(btype, b, bsize); - if (s==NULL) s = btype->_name; - return s; -} - -#define BMAXHASH 7919 -static building *buildhash[BMAXHASH]; -void -bhash(building * b) -{ - building *old = buildhash[b->no % BMAXHASH]; - - buildhash[b->no % BMAXHASH] = b; - b->nexthash = old; -} - -void -bunhash(building * b) -{ - building **show; - - for (show = &buildhash[b->no % BMAXHASH]; *show; show = &(*show)->nexthash) { - if ((*show)->no == b->no) - break; - } - if (*show) { - assert(*show == b); - *show = (*show)->nexthash; - b->nexthash = 0; - } -} - -static building * -bfindhash(int i) -{ - building *old; - - for (old = buildhash[i % BMAXHASH]; old; old = old->nexthash) - if (old->no == i) - return old; - return 0; -} - -building * -findbuilding(int i) -{ - return bfindhash(i); -} -/* ** old building types ** */ - - -static int -sm_smithy(const unit * u, const region * r, skill_t sk, int value) /* skillmod */ -{ - if (sk==SK_WEAPONSMITH || sk==SK_ARMORER) { - if (u->region == r) return value + 1; - } - return value; -} -static int -mm_smithy(const unit * u, const resource_type * rtype, int value) /* material-mod */ -{ - if (rtype == oldresourcetype[R_IRON]) return value * 2; - return value; -} -static void -init_smithy(struct building_type * bt) -{ - a_add(&bt->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION, sm_smithy, 1.0, 0)); - a_add(&bt->attribs, make_matmod(mm_smithy)); -} - -static const char * -castle_name_i(const struct building_type* btype, const struct building * b, int bsize, const char * fname[]) -{ - int i = bt_effsize(btype, b, bsize); - - return fname[i]; -} - -static const char * -castle_name_2(const struct building_type* btype, const struct building * b, int bsize) -{ - const char * fname[] = { - "site", - "fortification", - "tower", - "castle", - "fortress", - "citadel" - }; - return castle_name_i(btype, b, bsize, fname); -} - -static const char * -castle_name(const struct building_type* btype, const struct building * b, int bsize) -{ - const char * fname[] = { - "site", - "tradepost", - "fortification", - "tower", - "castle", - "fortress", - "citadel" - }; - return castle_name_i(btype, b, bsize, fname); -} - -static const char * -fort_name(const struct building_type* btype, const struct building * b, int bsize) -{ - const char * fname[] = { - "scaffolding", - "guardhouse", - "guardtower", - }; - return castle_name_i(btype, b, bsize, fname); -} - -#ifdef WDW_PYRAMID - -static const char * -pyramid_name(const struct building_type* btype, int bsize) -{ - static char p_name_buf[32]; - int level=0; - const construction * ctype; - - ctype = btype->construction; - - while (ctype && ctype->maxsize != -1 && ctype->maxsize<=bsize) { - bsize-=ctype->maxsize; - ctype=ctype->improvement; - ++level; - } - - sprintf(p_name_buf, "pyramid%d", level); - - return p_name_buf; -} - -int -wdw_pyramid_level(const struct building *b) -{ - const construction *ctype = b->type->construction; - int completed = b->size; - int level = 0; - - while(ctype->improvement != NULL && - ctype->improvement != ctype && - ctype->maxsize > 0 && - ctype->maxsize <= completed) - { - ++level; - completed-=ctype->maxsize; - ctype = ctype->improvement; - } - - return level; -} -#endif - -/* for finding out what was meant by a particular building string */ - -static local_names * bnames; - -const building_type * -findbuildingtype(const char * name, const struct locale * lang) -{ - variant type; - local_names * bn = bnames; - - while (bn) { - if (bn->lang==lang) break; - bn=bn->next; - } - if (!bn) { - struct building_typelist * btl = buildingtypes; - bn = calloc(sizeof(local_names), 1); - bn->next = bnames; - bn->lang = lang; - while (btl) { - const char * n = locale_string(lang, btl->type->_name); - type.v = (void*)btl->type; - addtoken(&bn->names, n, type); - btl=btl->next; - } - bnames = bn; - } - if (findtoken(&bn->names, name, &type)==E_TOK_NOMATCH) return NULL; - return (const building_type*)type.v; -} - -static int eressea_building_protection(building * b, unit * u) -{ - int beff = buildingeffsize(b, false)-1; - /* -1 because the tradepost has no protection value */ - - return beff; -} - -void -register_buildings(void) -{ - register_function((pf_generic)&eressea_building_protection, "eressea_building_protection"); - register_function((pf_generic)&init_smithy, "init_smithy"); - register_function((pf_generic)&castle_name, "castle_name"); - register_function((pf_generic)&castle_name_2, "castle_name_2"); - register_function((pf_generic)&fort_name, "fort_name"); -#ifdef WDW_PYRAMID - register_function((pf_generic)&pyramid_name, "pyramid_name"); -#endif -} - -void -write_building_reference(const struct building * b, struct storage * store) -{ - store->w_id(store, (b && b->region)?b->no:0); -} - - -int -resolve_building(variant id, void * address) -{ - int result = 0; - building * b = NULL; - if (id.i!=0) { - b = findbuilding(id.i); - if (b==NULL) { - result = -1; - } - } - *(building**)address = b; - return result; -} - -variant -read_building_reference(struct storage * store) -{ - variant result; - result.i = store->r_id(store); - return result; -} - -void -free_buildinglist(building_list *blist) -{ - while (blist) { - building_list * rl2 = blist->next; - free(blist); - blist = rl2; - } -} - -void -add_buildinglist(building_list **blist, building *b) -{ - building_list *rl2 = (building_list*)malloc(sizeof(building_list)); - - rl2->data = b; - rl2->next = *blist; - - *blist = rl2; -} - -building * -new_building(const struct building_type * btype, region * r, const struct locale * lang) -{ - building *b = (building *) calloc(1, sizeof(building)); - static boolean init_lighthouse = false; - static const struct building_type * bt_lighthouse = 0; - - if (!init_lighthouse) { - bt_lighthouse = bt_find("lighthouse"); - init_lighthouse = true; - } - - b->flags = BLD_WORKING|BLD_MAINTAINED; - b->no = newcontainerid(); - bhash(b); - - b->type = btype; - b->region = r; - addlist(&r->buildings, b); - - if (b->type==bt_lighthouse) { - r->flags |= RF_LIGHTHOUSE; - } - { - const char * bname; - if (b->type->name==NULL) { - bname = LOC(lang, btype->_name); - } else { - bname = LOC(lang, buildingtype(btype, b, 0)); - } - b->name = strdup(bname); - } - return b; -} - -static building * deleted_buildings; - -/** remove a building from the region. - * remove_building lets units leave the building - */ -void -remove_building(building ** blist, building * b) -{ - unit *u; - direction_t d; - static const struct building_type * bt_caravan, * bt_dam, * bt_tunnel; - static boolean init = false; - - if (!init) { - init = true; - bt_caravan = bt_find("caravan"); - bt_dam = bt_find("dam"); - bt_tunnel = bt_find("tunnel"); - } - - assert(bfindhash(b->no)); - - handle_event(b->attribs, "destroy", b); - for (u=b->region->units; u; u=u->next) { - if (u->building == b) leave(u, true); - } - - b->size = 0; - update_lighthouse(b); - bunhash(b); - - /* Falls Karawanserei, Damm oder Tunnel einstürzen, wird die schon - * gebaute Straße zur Hälfte vernichtet */ - if (b->type == bt_caravan || b->type == bt_dam || b->type == bt_tunnel) { - region * r = b->region; - for (d=0;d!=MAXDIRECTIONS;++d) if (rroad(r, d) > 0) { - rsetroad(r, d, rroad(r, d) / 2); - } - } - - /* Stattdessen nur aus Liste entfernen, aber im Speicher halten. */ - while (*blist && *blist!=b) blist = &(*blist)->next; - *blist = b->next; - b->region = NULL; - b->next = deleted_buildings; - deleted_buildings = b; -} - -void -free_building(building * b) -{ - while (b->attribs) a_remove (&b->attribs, b->attribs); - free(b->name); - free(b->display); - free(b); -} - -void -free_buildings(void) -{ - while (deleted_buildings) { - building * b = deleted_buildings; - deleted_buildings = b->next; - } -} - -extern struct attrib_type at_icastle; - -/** returns the building's build stage (NOT size in people). - * only makes sense for castles or similar buildings with multiple - * stages */ -int -buildingeffsize(const building * b, boolean img) -{ - const struct building_type * btype = NULL; - - if (b==NULL) return 0; - - btype = b->type; - if (img) { - const attrib * a = a_find(b->attribs, &at_icastle); - if (a) { - btype = (const struct building_type *)a->data.v; - } - } - return bt_effsize(btype, b, b->size); -} - -int bt_effsize(const building_type * btype, const building * b, int bsize) -{ - int i = bsize, n = 0; - const construction * cons = btype->construction; - - /* TECH DEBT: simplest thing that works for E3 dwarf/halfling faction rules */ - if (b && get_param_int(global.parameters, "rules.dwarf_castles", 1) && strcmp(btype->_name, "castle")==0) { - unit * u = building_owner(b); - if (u && u->faction->race == new_race[RC_HALFLING]) { - i = bsize * 10 / 8; - } - } - - if (!cons || !cons->improvement) { - return 0; - } - - while (cons && cons->maxsize != -1 && i>=cons->maxsize) { - i -= cons->maxsize; - cons = cons->improvement; - ++n; - } - - return n; -} - -const char * -write_buildingname(const building * b, char * ibuf, size_t size) -{ - snprintf((char*)ibuf, size, "%s (%s)", b->name, itoa36(b->no)); - ibuf[size-1] = 0; - return ibuf; -} - -const char * -buildingname(const building * b) -{ - typedef char name[OBJECTIDSIZE + 1]; - static name idbuf[8]; - static int nextbuf = 0; - char *ibuf = idbuf[(++nextbuf) % 8]; - return write_buildingname(b, ibuf, sizeof(name)); -} - -unit * -building_owner(const building * b) -{ - unit *u = NULL; - unit *first = NULL; - region * r = b->region; - /* Prüfen ob Eigentümer am leben. */ - - for (u = r->units; u; u = u->next) { - if (u->building == b) { - if (!first && u->number > 0) - first = u; - if (fval(u, UFL_OWNER) && u->number > 0) - return u; - if (u->number == 0) - freset(u, UFL_OWNER); - } - } - - /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit - * nehmen. */ - - if (first) { - fset(first, UFL_OWNER); - } - return first; -} - -const char * building_getname(const building * self) -{ - return self->name; -} - -void building_setname(building * self, const char * name) -{ - free(self->name); - if (name) self->name = strdup(name); - else self->name = NULL; -} - -void -building_addaction(building * b, const char * fname, const char * param) -{ - attrib * a = a_add(&b->attribs, a_new(&at_building_action)); - building_action * data = (building_action*)a->data.v; - data->b = b; - data->fname = strdup(fname); - if (param) { - data->param = strdup(param); - } -} - -region * -building_getregion(const building * b) -{ - return b->region; -} - -void -building_setregion(building * b, region * r) -{ - building ** blist = &b->region->buildings; - while (*blist && *blist!=b) { - blist = &(*blist)->next; - } - *blist = b->next; - b->next = NULL; - - blist = &r->buildings; - while (*blist && *blist!=b) blist = &(*blist)->next; - *blist = b; - - b->region = r; -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include + +#include +#include "building.h" + +/* kernel includes */ +#include "item.h" +#include "curse.h" /* für C_NOCOST */ +#include "unit.h" +#include "faction.h" +#include "region.h" +#include "skill.h" +#include "magic.h" +#include "save.h" +#include "version.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +/* attributes includes */ +#include + +static const char * NULLSTRING = "(null)"; + +static void +lc_init(struct attrib *a) +{ + a->data.v = calloc(1, sizeof(building_action)); +} + +static void +lc_done(struct attrib *a) +{ + building_action * data = (building_action*)a->data.v; + if (data->fname) free(data->fname); + if (data->param) free(data->param); + free(data); +} + +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; + const char * fparam = data->param; + building * b = data->b; + + write_building_reference(b, store); + store->w_tok(store, fname); + store->w_tok(store, fparam?fparam:NULLSTRING); +} + +static int +lc_read(struct attrib * a, void * owner, struct storage * store) +{ + building_action * data = (building_action*)a->data.v; + int result = read_reference(&data->b, store, read_building_reference, resolve_building); + if (store->versionfname = store->r_str(store); + } else { + data->fname = store->r_tok(store); + } + if (store->version>=BACTION_VERSION) { + char lbuf[256]; + if (store->versionr_str_buf(store, lbuf, sizeof(lbuf)); + } else { + store->r_tok_buf(store, lbuf, sizeof(lbuf)); + } + if (strcmp(lbuf, NULLSTRING)==0) data->param = NULL; + else data->param = strdup(lbuf); + } else { + data->param = strdup(NULLSTRING); + } + if (result==0 && !data->b) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +attrib_type at_building_action = { + "lcbuilding", + lc_init, lc_done, + NULL, + lc_write, lc_read +}; + +typedef struct building_typelist { + struct building_typelist * next; + building_type * type; +} building_typelist; + +static building_typelist *buildingtypes; + +building_type * +bt_find(const char* name) +{ + const struct building_typelist * btl = buildingtypes; + assert(name); + while (btl && strcmp(btl->type->_name, name)) btl = btl->next; + if (btl==NULL) { + return NULL; + } + return btl->type; +} + +void +bt_register(building_type * type) +{ + struct building_typelist * btl = malloc(sizeof(building_type)); + if (type->init) type->init(type); + btl->type = type; + btl->next = buildingtypes; + buildingtypes = btl; +} + +int +buildingcapacity(const building * b) +{ + if (b->type->capacity>=0) { + if (b->type->maxcapacity>=0) { + return MIN(b->type->maxcapacity, b->size * b->type->capacity); + } + return b->size * b->type->capacity; + } + if (b->size>=b->type->maxsize) { + if (b->type->maxcapacity>=0) { + return b->type->maxcapacity; + } + } + return 0; +} + +attrib_type at_building_generic_type = { + "building_generic_type", NULL, NULL, NULL, a_writestring, a_readstring, ATF_UNIQUE +}; + +const char * +buildingtype(const building_type * btype, const building * b, int bsize) +{ + const char * s = NULL; + static boolean init_generic = false; + static const struct building_type * bt_generic; + + if (!init_generic) { + init_generic = true; + bt_generic = bt_find("generic"); + } + + if (btype == bt_generic) { + const attrib *a = a_find(b->attribs, &at_building_generic_type); + if (a) s = (const char*)a->data.v; + } + + if (btype->name) s = btype->name(btype, b, bsize); + if (s==NULL) s = btype->_name; + return s; +} + +#define BMAXHASH 7919 +static building *buildhash[BMAXHASH]; +void +bhash(building * b) +{ + building *old = buildhash[b->no % BMAXHASH]; + + buildhash[b->no % BMAXHASH] = b; + b->nexthash = old; +} + +void +bunhash(building * b) +{ + building **show; + + for (show = &buildhash[b->no % BMAXHASH]; *show; show = &(*show)->nexthash) { + if ((*show)->no == b->no) + break; + } + if (*show) { + assert(*show == b); + *show = (*show)->nexthash; + b->nexthash = 0; + } +} + +static building * +bfindhash(int i) +{ + building *old; + + for (old = buildhash[i % BMAXHASH]; old; old = old->nexthash) + if (old->no == i) + return old; + return 0; +} + +building * +findbuilding(int i) +{ + return bfindhash(i); +} +/* ** old building types ** */ + + +static int +sm_smithy(const unit * u, const region * r, skill_t sk, int value) /* skillmod */ +{ + if (sk==SK_WEAPONSMITH || sk==SK_ARMORER) { + if (u->region == r) return value + 1; + } + return value; +} +static int +mm_smithy(const unit * u, const resource_type * rtype, int value) /* material-mod */ +{ + if (rtype == oldresourcetype[R_IRON]) return value * 2; + return value; +} +static void +init_smithy(struct building_type * bt) +{ + a_add(&bt->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION, sm_smithy, 1.0, 0)); + a_add(&bt->attribs, make_matmod(mm_smithy)); +} + +static const char * +castle_name_i(const struct building_type* btype, const struct building * b, int bsize, const char * fname[]) +{ + int i = bt_effsize(btype, b, bsize); + + return fname[i]; +} + +static const char * +castle_name_2(const struct building_type* btype, const struct building * b, int bsize) +{ + const char * fname[] = { + "site", + "fortification", + "tower", + "castle", + "fortress", + "citadel" + }; + return castle_name_i(btype, b, bsize, fname); +} + +static const char * +castle_name(const struct building_type* btype, const struct building * b, int bsize) +{ + const char * fname[] = { + "site", + "tradepost", + "fortification", + "tower", + "castle", + "fortress", + "citadel" + }; + return castle_name_i(btype, b, bsize, fname); +} + +static const char * +fort_name(const struct building_type* btype, const struct building * b, int bsize) +{ + const char * fname[] = { + "scaffolding", + "guardhouse", + "guardtower", + }; + return castle_name_i(btype, b, bsize, fname); +} + +#ifdef WDW_PYRAMID + +static const char * +pyramid_name(const struct building_type* btype, int bsize) +{ + static char p_name_buf[32]; + int level=0; + const construction * ctype; + + ctype = btype->construction; + + while (ctype && ctype->maxsize != -1 && ctype->maxsize<=bsize) { + bsize-=ctype->maxsize; + ctype=ctype->improvement; + ++level; + } + + sprintf(p_name_buf, "pyramid%d", level); + + return p_name_buf; +} + +int +wdw_pyramid_level(const struct building *b) +{ + const construction *ctype = b->type->construction; + int completed = b->size; + int level = 0; + + while(ctype->improvement != NULL && + ctype->improvement != ctype && + ctype->maxsize > 0 && + ctype->maxsize <= completed) + { + ++level; + completed-=ctype->maxsize; + ctype = ctype->improvement; + } + + return level; +} +#endif + +/* for finding out what was meant by a particular building string */ + +static local_names * bnames; + +const building_type * +findbuildingtype(const char * name, const struct locale * lang) +{ + variant type; + local_names * bn = bnames; + + while (bn) { + if (bn->lang==lang) break; + bn=bn->next; + } + if (!bn) { + struct building_typelist * btl = buildingtypes; + bn = calloc(sizeof(local_names), 1); + bn->next = bnames; + bn->lang = lang; + while (btl) { + const char * n = locale_string(lang, btl->type->_name); + type.v = (void*)btl->type; + addtoken(&bn->names, n, type); + btl=btl->next; + } + bnames = bn; + } + if (findtoken(&bn->names, name, &type)==E_TOK_NOMATCH) return NULL; + return (const building_type*)type.v; +} + +static int eressea_building_protection(building * b, unit * u) +{ + int beff = buildingeffsize(b, false)-1; + /* -1 because the tradepost has no protection value */ + + return beff; +} + +void +register_buildings(void) +{ + register_function((pf_generic)&eressea_building_protection, "eressea_building_protection"); + register_function((pf_generic)&init_smithy, "init_smithy"); + register_function((pf_generic)&castle_name, "castle_name"); + register_function((pf_generic)&castle_name_2, "castle_name_2"); + register_function((pf_generic)&fort_name, "fort_name"); +#ifdef WDW_PYRAMID + register_function((pf_generic)&pyramid_name, "pyramid_name"); +#endif +} + +void +write_building_reference(const struct building * b, struct storage * store) +{ + store->w_id(store, (b && b->region)?b->no:0); +} + + +int +resolve_building(variant id, void * address) +{ + int result = 0; + building * b = NULL; + if (id.i!=0) { + b = findbuilding(id.i); + if (b==NULL) { + result = -1; + } + } + *(building**)address = b; + return result; +} + +variant +read_building_reference(struct storage * store) +{ + variant result; + result.i = store->r_id(store); + return result; +} + +void +free_buildinglist(building_list *blist) +{ + while (blist) { + building_list * rl2 = blist->next; + free(blist); + blist = rl2; + } +} + +void +add_buildinglist(building_list **blist, building *b) +{ + building_list *rl2 = (building_list*)malloc(sizeof(building_list)); + + rl2->data = b; + rl2->next = *blist; + + *blist = rl2; +} + +building * +new_building(const struct building_type * btype, region * r, const struct locale * lang) +{ + building *b = (building *) calloc(1, sizeof(building)); + static boolean init_lighthouse = false; + static const struct building_type * bt_lighthouse = 0; + + if (!init_lighthouse) { + bt_lighthouse = bt_find("lighthouse"); + init_lighthouse = true; + } + + b->flags = BLD_WORKING|BLD_MAINTAINED; + b->no = newcontainerid(); + bhash(b); + + b->type = btype; + b->region = r; + addlist(&r->buildings, b); + + if (b->type==bt_lighthouse) { + r->flags |= RF_LIGHTHOUSE; + } + { + const char * bname; + if (b->type->name==NULL) { + bname = LOC(lang, btype->_name); + } else { + bname = LOC(lang, buildingtype(btype, b, 0)); + } + b->name = strdup(bname); + } + return b; +} + +static building * deleted_buildings; + +/** remove a building from the region. + * remove_building lets units leave the building + */ +void +remove_building(building ** blist, building * b) +{ + unit *u; + direction_t d; + static const struct building_type * bt_caravan, * bt_dam, * bt_tunnel; + static boolean init = false; + + if (!init) { + init = true; + bt_caravan = bt_find("caravan"); + bt_dam = bt_find("dam"); + bt_tunnel = bt_find("tunnel"); + } + + assert(bfindhash(b->no)); + + handle_event(b->attribs, "destroy", b); + for (u=b->region->units; u; u=u->next) { + if (u->building == b) leave(u, true); + } + + b->size = 0; + update_lighthouse(b); + bunhash(b); + + /* Falls Karawanserei, Damm oder Tunnel einstürzen, wird die schon + * gebaute Straße zur Hälfte vernichtet */ + if (b->type == bt_caravan || b->type == bt_dam || b->type == bt_tunnel) { + region * r = b->region; + for (d=0;d!=MAXDIRECTIONS;++d) if (rroad(r, d) > 0) { + rsetroad(r, d, rroad(r, d) / 2); + } + } + + /* Stattdessen nur aus Liste entfernen, aber im Speicher halten. */ + while (*blist && *blist!=b) blist = &(*blist)->next; + *blist = b->next; + b->region = NULL; + b->next = deleted_buildings; + deleted_buildings = b; +} + +void +free_building(building * b) +{ + while (b->attribs) a_remove (&b->attribs, b->attribs); + free(b->name); + free(b->display); + free(b); +} + +void +free_buildings(void) +{ + while (deleted_buildings) { + building * b = deleted_buildings; + deleted_buildings = b->next; + } +} + +extern struct attrib_type at_icastle; + +/** returns the building's build stage (NOT size in people). + * only makes sense for castles or similar buildings with multiple + * stages */ +int +buildingeffsize(const building * b, boolean img) +{ + const struct building_type * btype = NULL; + + if (b==NULL) return 0; + + btype = b->type; + if (img) { + const attrib * a = a_find(b->attribs, &at_icastle); + if (a) { + btype = (const struct building_type *)a->data.v; + } + } + return bt_effsize(btype, b, b->size); +} + +int bt_effsize(const building_type * btype, const building * b, int bsize) +{ + int i = bsize, n = 0; + const construction * cons = btype->construction; + + /* TECH DEBT: simplest thing that works for E3 dwarf/halfling faction rules */ + if (b && get_param_int(global.parameters, "rules.dwarf_castles", 1) && strcmp(btype->_name, "castle")==0) { + unit * u = building_owner(b); + if (u && u->faction->race == new_race[RC_HALFLING]) { + i = bsize * 10 / 8; + } + } + + if (!cons || !cons->improvement) { + return 0; + } + + while (cons && cons->maxsize != -1 && i>=cons->maxsize) { + i -= cons->maxsize; + cons = cons->improvement; + ++n; + } + + return n; +} + +const char * +write_buildingname(const building * b, char * ibuf, size_t size) +{ + snprintf((char*)ibuf, size, "%s (%s)", b->name, itoa36(b->no)); + ibuf[size-1] = 0; + return ibuf; +} + +const char * +buildingname(const building * b) +{ + typedef char name[OBJECTIDSIZE + 1]; + static name idbuf[8]; + static int nextbuf = 0; + char *ibuf = idbuf[(++nextbuf) % 8]; + return write_buildingname(b, ibuf, sizeof(name)); +} + +unit * +building_owner(const building * b) +{ + unit *u = NULL; + unit *first = NULL; + region * r = b->region; + /* Prüfen ob Eigentümer am leben. */ + + for (u = r->units; u; u = u->next) { + if (u->building == b) { + if (!first && u->number > 0) + first = u; + if (fval(u, UFL_OWNER) && u->number > 0) + return u; + if (u->number == 0) + freset(u, UFL_OWNER); + } + } + + /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit + * nehmen. */ + + if (first) { + fset(first, UFL_OWNER); + } + return first; +} + +const char * building_getname(const building * self) +{ + return self->name; +} + +void building_setname(building * self, const char * name) +{ + free(self->name); + if (name) self->name = strdup(name); + else self->name = NULL; +} + +void +building_addaction(building * b, const char * fname, const char * param) +{ + attrib * a = a_add(&b->attribs, a_new(&at_building_action)); + building_action * data = (building_action*)a->data.v; + data->b = b; + data->fname = strdup(fname); + if (param) { + data->param = strdup(param); + } +} + +region * +building_getregion(const building * b) +{ + return b->region; +} + +void +building_setregion(building * b, region * r) +{ + building ** blist = &b->region->buildings; + while (*blist && *blist!=b) { + blist = &(*blist)->next; + } + *blist = b->next; + b->next = NULL; + + blist = &r->buildings; + while (*blist && *blist!=b) blist = &(*blist)->next; + *blist = b; + + b->region = r; +} + diff --git a/src/kernel/building.h b/src/kernel/building.h index 7aea49bd1..64b8941eb 100644 --- a/src/kernel/building.h +++ b/src/kernel/building.h @@ -1,177 +1,177 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_BUILDING -#define H_KRNL_BUILDING - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* maintenance::flags */ -#define MTF_NONE 0x00 -#define MTF_VARIABLE 0x01 /* resource usage scales with size */ -#define MTF_VITAL 0x02 /* if resource missing, building may crash */ - -typedef struct maintenance { - const struct resource_type * rtype; /* type of resource required */ - int number; /* amount of resources */ - unsigned int flags; /* misc. flags */ -} maintenance; - -/* building_type::flags */ -#define BTF_NONE 0x00 -#define BTF_INDESTRUCTIBLE 0x01 /* cannot be torm down */ -#define BTF_NOBUILD 0x02 /* special, can't be built */ -#define BTF_UNIQUE 0x04 /* only one per struct region (harbour) */ -#define BTF_DECAY 0x08 /* decays when not occupied */ -#define BTF_DYNAMIC 0x10 /* dynamic type, needs bt_write */ -#define BTF_MAGIC 0x40 /* magical effect */ -#define BTF_ONEPERTURN 0x80 /* one one sizepoint can be added per turn */ -#define BTF_NAMECHANGE 0x100 /* name and description can be changed more than once */ - -typedef struct building_type { - const char * _name; - - int flags; /* flags */ - int capacity; /* Kapazität pro Größenpunkt */ - int maxcapacity; /* Max. Kapazität */ - int maxsize; /* how big can it get, with all the extensions? */ - int magres; /* how well it resists against spells */ - int magresbonus; /* bonus it gives the target against spells */ - int fumblebonus; /* bonus that reduces fumbling */ - double auraregen; /* modifier for aura regeneration inside building */ - struct maintenance * maintenance; /* array of requirements */ - struct construction * construction; /* construction of 1 building-level */ - - const char * (*name)(const struct building_type*, const struct building * b, int size); - void (*init)(struct building_type*); - void (*age)(struct building *); - int (*protection)(struct building *, struct unit *); - double (*taxes)(const struct building *, int size); - struct attrib * attribs; -} building_type; - -extern building_type * bt_find(const char* name); -extern void register_buildings(void); -extern void bt_register(struct building_type * type); -extern int bt_effsize(const struct building_type * btype, const struct building * b, int bsize); - -/* buildingt => building_type - * Name => locale_string(name) - * MaxGroesse => levels - * MinBauTalent => construction->minskill - * Kapazitaet => capacity, maxcapacity - * Materialien => construction->materials - * UnterSilber, UnterSpezialTyp, UnterSpezial => maintenance - * per_size => !maintenance->fixed - */ -#define BFL_NONE 0x00 -#define BLD_MAINTAINED 0x01 /* vital maintenance paid for */ -#define BLD_WORKING 0x02 /* full maintenance paid, it works */ -#define BLD_UNGUARDED 0x04 /* you can enter this building anytime */ -#define BLD_EXPANDED 0x08 /* has been expanded this turn */ -#define BLD_SELECT 0x10 /* formerly FL_DH */ -#define BLD_DONTPAY 0x20 /* PAY NOT */ - -#define BLD_SAVEMASK 0x00 /* mask for persistent flags */ - -typedef struct building { - struct building *next; - struct building *nexthash; - - const struct building_type * type; - struct region *region; - char *name; - char *display; - struct attrib * attribs; - int no; - int size; - int sizeleft; /* is only used during battle. should be a temporary attribute */ - int besieged; /* should be an attribute */ - unsigned int flags; -} building; - -typedef struct building_list { - struct building_list * next; - building * data; -} building_list; - -extern void free_buildinglist(building_list *bl); -extern void add_buildinglist(building_list **bl, struct building *b); - -extern struct attrib_type at_building_generic_type; -extern const char * buildingtype(const building_type * btype, const struct building * b, int bsize); -extern const char * write_buildingname(const building * b, char * ibuf, size_t size); -extern int buildingcapacity(const struct building * b); -extern struct building *new_building(const struct building_type * typ, struct region * r, const struct locale * lang); -void build_building(struct unit * u, const struct building_type * typ, int size, struct order * ord); - -/* Alte Gebäudetypen: */ - -/* old functions, still in build.c: */ -int buildingeffsize(const building * b, boolean img); -void bhash(struct building * b); -void bunhash(struct building * b); -int buildingcapacity(const struct building * b); - -extern void remove_building(struct building * *blist, struct building * b); -extern void free_building(struct building * b); -extern void free_buildings(void); - -const struct building_type * findbuildingtype(const char * name, const struct locale * lang); - -#include "build.h" -#define NOBUILDING NULL - -extern int resolve_building(variant data, void * address); -extern void write_building_reference(const struct building * b, struct storage * store); -extern variant read_building_reference(struct storage * store); - -extern struct building *findbuilding(int n); - -extern struct unit * building_owner(const struct building * b); - -extern struct attrib_type at_building_action; -void building_addaction(struct building * b, const char * fname, const char * param); - -#ifdef WDW_PYRAMID -extern int wdw_pyramid_level(const struct building *b); -#endif - -typedef struct building_action { - building * b; - char * fname; - char * param; -} building_action; - -extern const char * buildingname(const struct building * b); - -extern const char * building_getname(const struct building * b); -extern void building_setname(struct building * self, const char * name); - -struct region * building_getregion(const struct building * b); -void building_setregion(struct building * bld, struct region * r); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_BUILDING +#define H_KRNL_BUILDING + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* maintenance::flags */ +#define MTF_NONE 0x00 +#define MTF_VARIABLE 0x01 /* resource usage scales with size */ +#define MTF_VITAL 0x02 /* if resource missing, building may crash */ + +typedef struct maintenance { + const struct resource_type * rtype; /* type of resource required */ + int number; /* amount of resources */ + unsigned int flags; /* misc. flags */ +} maintenance; + +/* building_type::flags */ +#define BTF_NONE 0x00 +#define BTF_INDESTRUCTIBLE 0x01 /* cannot be torm down */ +#define BTF_NOBUILD 0x02 /* special, can't be built */ +#define BTF_UNIQUE 0x04 /* only one per struct region (harbour) */ +#define BTF_DECAY 0x08 /* decays when not occupied */ +#define BTF_DYNAMIC 0x10 /* dynamic type, needs bt_write */ +#define BTF_MAGIC 0x40 /* magical effect */ +#define BTF_ONEPERTURN 0x80 /* one one sizepoint can be added per turn */ +#define BTF_NAMECHANGE 0x100 /* name and description can be changed more than once */ + +typedef struct building_type { + const char * _name; + + int flags; /* flags */ + int capacity; /* Kapazität pro Größenpunkt */ + int maxcapacity; /* Max. Kapazität */ + int maxsize; /* how big can it get, with all the extensions? */ + int magres; /* how well it resists against spells */ + int magresbonus; /* bonus it gives the target against spells */ + int fumblebonus; /* bonus that reduces fumbling */ + double auraregen; /* modifier for aura regeneration inside building */ + struct maintenance * maintenance; /* array of requirements */ + struct construction * construction; /* construction of 1 building-level */ + + const char * (*name)(const struct building_type*, const struct building * b, int size); + void (*init)(struct building_type*); + void (*age)(struct building *); + int (*protection)(struct building *, struct unit *); + double (*taxes)(const struct building *, int size); + struct attrib * attribs; +} building_type; + +extern building_type * bt_find(const char* name); +extern void register_buildings(void); +extern void bt_register(struct building_type * type); +extern int bt_effsize(const struct building_type * btype, const struct building * b, int bsize); + +/* buildingt => building_type + * Name => locale_string(name) + * MaxGroesse => levels + * MinBauTalent => construction->minskill + * Kapazitaet => capacity, maxcapacity + * Materialien => construction->materials + * UnterSilber, UnterSpezialTyp, UnterSpezial => maintenance + * per_size => !maintenance->fixed + */ +#define BFL_NONE 0x00 +#define BLD_MAINTAINED 0x01 /* vital maintenance paid for */ +#define BLD_WORKING 0x02 /* full maintenance paid, it works */ +#define BLD_UNGUARDED 0x04 /* you can enter this building anytime */ +#define BLD_EXPANDED 0x08 /* has been expanded this turn */ +#define BLD_SELECT 0x10 /* formerly FL_DH */ +#define BLD_DONTPAY 0x20 /* PAY NOT */ + +#define BLD_SAVEMASK 0x00 /* mask for persistent flags */ + +typedef struct building { + struct building *next; + struct building *nexthash; + + const struct building_type * type; + struct region *region; + char *name; + char *display; + struct attrib * attribs; + int no; + int size; + int sizeleft; /* is only used during battle. should be a temporary attribute */ + int besieged; /* should be an attribute */ + unsigned int flags; +} building; + +typedef struct building_list { + struct building_list * next; + building * data; +} building_list; + +extern void free_buildinglist(building_list *bl); +extern void add_buildinglist(building_list **bl, struct building *b); + +extern struct attrib_type at_building_generic_type; +extern const char * buildingtype(const building_type * btype, const struct building * b, int bsize); +extern const char * write_buildingname(const building * b, char * ibuf, size_t size); +extern int buildingcapacity(const struct building * b); +extern struct building *new_building(const struct building_type * typ, struct region * r, const struct locale * lang); +void build_building(struct unit * u, const struct building_type * typ, int size, struct order * ord); + +/* Alte Gebäudetypen: */ + +/* old functions, still in build.c: */ +int buildingeffsize(const building * b, boolean img); +void bhash(struct building * b); +void bunhash(struct building * b); +int buildingcapacity(const struct building * b); + +extern void remove_building(struct building * *blist, struct building * b); +extern void free_building(struct building * b); +extern void free_buildings(void); + +const struct building_type * findbuildingtype(const char * name, const struct locale * lang); + +#include "build.h" +#define NOBUILDING NULL + +extern int resolve_building(variant data, void * address); +extern void write_building_reference(const struct building * b, struct storage * store); +extern variant read_building_reference(struct storage * store); + +extern struct building *findbuilding(int n); + +extern struct unit * building_owner(const struct building * b); + +extern struct attrib_type at_building_action; +void building_addaction(struct building * b, const char * fname, const char * param); + +#ifdef WDW_PYRAMID +extern int wdw_pyramid_level(const struct building *b); +#endif + +typedef struct building_action { + building * b; + char * fname; + char * param; +} building_action; + +extern const char * buildingname(const struct building * b); + +extern const char * building_getname(const struct building * b); +extern void building_setname(struct building * self, const char * name); + +struct region * building_getregion(const struct building * b); +void building_setregion(struct building * bld, struct region * r); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/calendar.c b/src/kernel/calendar.c index 8a4efccca..6a9e6b58f 100644 --- a/src/kernel/calendar.c +++ b/src/kernel/calendar.c @@ -1,59 +1,59 @@ -#include -#include "calendar.h" - -#include - -int first_turn = 0; -int first_month = 0; -int weeks_per_month = 0; -int months_per_year = 0; -char **seasonnames = NULL; -char **weeknames = NULL; -char **weeknames2 = NULL; -char **monthnames = NULL; -int *month_season = NULL; -char *agename = NULL; -int seasons = 0; - -const gamedate * -get_gamedate(int turn, gamedate * gd) -{ - int weeks_per_year = months_per_year * weeks_per_month; - int t = turn - first_turn; - - assert(gd); - if (t<0) t = turn; - - gd->week = t%weeks_per_month; /* 0 - weeks_per_month-1 */ - gd->month = (t/weeks_per_month + first_month)%months_per_year; /* 0 - months_per_year-1 */ - gd->year = t/(weeks_per_year) + 1; - gd->season = month_season[gd->month]; - return gd; -} - -void -calendar_cleanup(void) -{ - int i; - - free(agename); - - for (i=0;i!=seasons;++i) { - free(seasonnames[i]); - } - free(seasonnames); - - for (i=0;i!=months_per_year;++i) { - free(monthnames[i]); - } - free(storms); - free(month_season); - free(monthnames); - - for (i=0;i!=weeks_per_month;++i) { - free(weeknames[i]); - free(weeknames2[i]); - } - free(weeknames); - free(weeknames2); -} +#include +#include "calendar.h" + +#include + +int first_turn = 0; +int first_month = 0; +int weeks_per_month = 0; +int months_per_year = 0; +char **seasonnames = NULL; +char **weeknames = NULL; +char **weeknames2 = NULL; +char **monthnames = NULL; +int *month_season = NULL; +char *agename = NULL; +int seasons = 0; + +const gamedate * +get_gamedate(int turn, gamedate * gd) +{ + int weeks_per_year = months_per_year * weeks_per_month; + int t = turn - first_turn; + + assert(gd); + if (t<0) t = turn; + + gd->week = t%weeks_per_month; /* 0 - weeks_per_month-1 */ + gd->month = (t/weeks_per_month + first_month)%months_per_year; /* 0 - months_per_year-1 */ + gd->year = t/(weeks_per_year) + 1; + gd->season = month_season[gd->month]; + return gd; +} + +void +calendar_cleanup(void) +{ + int i; + + free(agename); + + for (i=0;i!=seasons;++i) { + free(seasonnames[i]); + } + free(seasonnames); + + for (i=0;i!=months_per_year;++i) { + free(monthnames[i]); + } + free(storms); + free(month_season); + free(monthnames); + + for (i=0;i!=weeks_per_month;++i) { + free(weeknames[i]); + free(weeknames2[i]); + } + free(weeknames); + free(weeknames2); +} diff --git a/src/kernel/calendar.h b/src/kernel/calendar.h index ae4306d28..fe7d0f930 100644 --- a/src/kernel/calendar.h +++ b/src/kernel/calendar.h @@ -1,45 +1,45 @@ -#ifndef KRNL_CALENDAR_H -#define KRNL_CALENDAR_H - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - SEASON_WINTER, - SEASON_SPRING, - SEASON_SUMMER, - SEASON_AUTUMN -}; - - -extern char *agename; -extern int first_turn; -extern int first_month; - -extern int seasons; -extern char **seasonnames; - -extern int months_per_year; -extern char **monthnames; -extern int *month_season; -extern int *storms; /* in movement.c */ - -extern char **weeknames; -extern char **weeknames2; -extern int weeks_per_month; - -typedef struct gamedate { - int year; - int season; - int month; - int week; -} gamedate; - -extern const gamedate * get_gamedate(int turn, gamedate * gd); -extern void calendar_cleanup(void); - -#ifdef __cplusplus -} -#endif -#endif +#ifndef KRNL_CALENDAR_H +#define KRNL_CALENDAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + SEASON_WINTER, + SEASON_SPRING, + SEASON_SUMMER, + SEASON_AUTUMN +}; + + +extern char *agename; +extern int first_turn; +extern int first_month; + +extern int seasons; +extern char **seasonnames; + +extern int months_per_year; +extern char **monthnames; +extern int *month_season; +extern int *storms; /* in movement.c */ + +extern char **weeknames; +extern char **weeknames2; +extern int weeks_per_month; + +typedef struct gamedate { + int year; + int season; + int month; + int week; +} gamedate; + +extern const gamedate * get_gamedate(int turn, gamedate * gd); +extern void calendar_cleanup(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/command.c b/src/kernel/command.c index 93741e4c2..f2c6a1bea 100644 --- a/src/kernel/command.c +++ b/src/kernel/command.c @@ -1,103 +1,103 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - - */ -#include -#include -#include "command.h" - -#include - -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -typedef struct command { - parser fun; - struct tnode * nodes; -} command; - -tnode * -stree_find(const syntaxtree * stree, const struct locale * lang) -{ - while (stree) { - if (stree->lang==lang) return stree->root; - stree = stree->next; - } - return NULL; -} - -syntaxtree * -stree_create(void) -{ - syntaxtree * sroot = NULL; - const struct locale * lang = locales; - while (lang) { - syntaxtree * stree = (syntaxtree *)malloc(sizeof(syntaxtree)); - stree->lang = lang; - stree->next = sroot; - sroot=stree; - lang=nextlocale(lang); - } - return sroot; -} - -void -add_command(struct tnode * keys, struct tnode * tnext, - const char * str, parser fun) -{ - command * cmd = (command *)malloc(sizeof(command)); - variant var; - - cmd->fun = fun; - cmd->nodes = tnext; - var.v = cmd; - addtoken(keys, str, var); -} - -static int -do_command_i(const struct tnode * keys, void * u, struct order * ord) -{ - const char * c; - variant var; - - c = getstrtoken(); - if (findtoken(keys, c, &var)==E_TOK_SUCCESS) { - command * cmd = (command *)var.v; - if (cmd->nodes && *c) { - assert(!cmd->fun); - return do_command_i(cmd->nodes, u, ord); - } else if (cmd->fun) { - cmd->fun(cmd->nodes, u, ord); - return E_TOK_SUCCESS; - } - } - return E_TOK_NOMATCH; -} - -void -do_command(const struct tnode * keys, void * u, struct order * ord) -{ - init_tokens(ord); - skip_token(); - if (do_command_i(keys, u, ord)!=E_TOK_SUCCESS) { - char * cmd = getcommand(ord); - log_warning(("%s failed command '%s'\n", unitname(u), cmd)); - free(cmd); - } -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ +#include +#include +#include "command.h" + +#include + +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +typedef struct command { + parser fun; + struct tnode * nodes; +} command; + +tnode * +stree_find(const syntaxtree * stree, const struct locale * lang) +{ + while (stree) { + if (stree->lang==lang) return stree->root; + stree = stree->next; + } + return NULL; +} + +syntaxtree * +stree_create(void) +{ + syntaxtree * sroot = NULL; + const struct locale * lang = locales; + while (lang) { + syntaxtree * stree = (syntaxtree *)malloc(sizeof(syntaxtree)); + stree->lang = lang; + stree->next = sroot; + sroot=stree; + lang=nextlocale(lang); + } + return sroot; +} + +void +add_command(struct tnode * keys, struct tnode * tnext, + const char * str, parser fun) +{ + command * cmd = (command *)malloc(sizeof(command)); + variant var; + + cmd->fun = fun; + cmd->nodes = tnext; + var.v = cmd; + addtoken(keys, str, var); +} + +static int +do_command_i(const struct tnode * keys, void * u, struct order * ord) +{ + const char * c; + variant var; + + c = getstrtoken(); + if (findtoken(keys, c, &var)==E_TOK_SUCCESS) { + command * cmd = (command *)var.v; + if (cmd->nodes && *c) { + assert(!cmd->fun); + return do_command_i(cmd->nodes, u, ord); + } else if (cmd->fun) { + cmd->fun(cmd->nodes, u, ord); + return E_TOK_SUCCESS; + } + } + return E_TOK_NOMATCH; +} + +void +do_command(const struct tnode * keys, void * u, struct order * ord) +{ + init_tokens(ord); + skip_token(); + if (do_command_i(keys, u, ord)!=E_TOK_SUCCESS) { + char * cmd = getcommand(ord); + log_warning(("%s failed command '%s'\n", unitname(u), cmd)); + free(cmd); + } +} diff --git a/src/kernel/command.h b/src/kernel/command.h index 401b9e8bc..56403db53 100644 --- a/src/kernel/command.h +++ b/src/kernel/command.h @@ -1,39 +1,39 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - - */ -#ifndef H_UTIL_COMMAND_H -#define H_UTIL_COMMAND_H -#ifdef __cplusplus -extern "C" { -#endif - -struct tnode; -struct locale; -struct order; - -typedef struct syntaxtree { - const struct locale * lang; - struct tnode * root; - struct syntaxtree * next; -} syntaxtree; - -typedef void (*parser)(const struct tnode *, void *, struct order*); -extern void add_command(struct tnode * troot, struct tnode * tnext, const char * str, parser fun); -extern void do_command(const struct tnode * troot, void * u, struct order *); - -extern struct syntaxtree * stree_create(void); -extern struct tnode * stree_find(const struct syntaxtree * stree, const struct locale * lang); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ +#ifndef H_UTIL_COMMAND_H +#define H_UTIL_COMMAND_H +#ifdef __cplusplus +extern "C" { +#endif + +struct tnode; +struct locale; +struct order; + +typedef struct syntaxtree { + const struct locale * lang; + struct tnode * root; + struct syntaxtree * next; +} syntaxtree; + +typedef void (*parser)(const struct tnode *, void *, struct order*); +extern void add_command(struct tnode * troot, struct tnode * tnext, const char * str, parser fun); +extern void do_command(const struct tnode * troot, void * u, struct order *); + +extern struct syntaxtree * stree_create(void); +extern struct tnode * stree_find(const struct syntaxtree * stree, const struct locale * lang); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/config.c b/src/kernel/config.c index 814bc45d5..b0c5ac4d4 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -1,3275 +1,3271 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include - -/* attributes includes */ -#include -#include - -/* kernel includes */ -#include "alliance.h" -#include "alchemy.h" -#include "battle.h" -#include "connection.h" -#include "building.h" -#include "calendar.h" -#include "curse.h" -#include "faction.h" -#include "group.h" -#include "item.h" -#include "magic.h" -#include "message.h" -#include "move.h" -#include "names.h" -#include "objtypes.h" -#include "order.h" -#include "plane.h" -#include "pool.h" -#include "race.h" -#include "region.h" -#include "save.h" -#include "ship.h" -#include "skill.h" -#include "terrain.h" -#include "unit.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libxml includes */ -#include -#include - -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include -#include -#include - -#define PTRIES 0 /* it turns out they are slow :-( */ -#if PTRIES -#include -#endif - -struct settings global = { - "Eressea", /* gamename */ -}; -FILE *logfile; -FILE *updatelog; -const struct race * new_race[MAXRACES]; -boolean sqlpatch = false; -boolean battledebug = false; -int turn = 0; - -#if XECMD_MODULE -attrib_type at_xontormiaexpress = { - "xontormiaexpress", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - a_writeint, - a_readint, - ATF_UNIQUE -}; -#endif - -int -NewbieImmunity(void) { - static int value = -1; - if (value<0) { - value = get_param_int(global.parameters, "NewbieImmunity", 0); - } - return value; -} - -boolean -IsImmune(const faction * f) -{ - return !fval(f, FFL_NPC) && f->age < NewbieImmunity(); -} - -static int -MaxAge(void) { - static int value = -1; - if (value<0) { - value = get_param_int(global.parameters, "MaxAge", 0); - } - return value; -} - -static int -ally_flag(const char * s, int help_mask) -{ - if ((help_mask&HELP_MONEY) && strcmp(s, "money")==0) return HELP_MONEY; - if ((help_mask&HELP_FIGHT) && strcmp(s, "fight")==0) return HELP_FIGHT; - if ((help_mask&HELP_GIVE) && strcmp(s, "give")==0) return HELP_GIVE; - if ((help_mask&HELP_GUARD) && strcmp(s, "guard")==0) return HELP_GUARD; - if ((help_mask&HELP_FSTEALTH) && strcmp(s, "stealth")==0) return HELP_FSTEALTH; - if ((help_mask&HELP_TRAVEL) && strcmp(s, "travel")==0) return HELP_TRAVEL; - return 0; -} - -boolean -ExpensiveMigrants(void) -{ - int value = -1; - if (value<0) { - value = get_param_int(global.parameters, "study.expensivemigrants", 0); - } - return value; -} -/** Specifies automatic alliance modes. - * If this returns a value then the bits set are immutable between alliance - * partners (faction::alliance) and cannot be changed with the HELP command. - */ -int -AllianceAuto(void) -{ - static int value = -1; - if (value<0) { - const char * str = get_param(global.parameters, "alliance.auto"); - value = 0; - if (str!=NULL) { - char * sstr = strdup(str); - char * tok = strtok(sstr, " "); - while (tok) { - value |= ally_flag(tok, -1); - tok = strtok(NULL, " "); - } - free(sstr); - } - } - return value & HelpMask(); -} - -/** Limits the available help modes - * The bitfield returned by this function specifies the available help modes - * in this game (so you can, for example, disable HELP GIVE globally). - * Disabling a status will disable the command sequence entirely (order parsing - * uses this function). - */ -int -HelpMask(void) -{ - static int value = -1; - if (value<0) { - const char * str = get_param(global.parameters, "rules.help.mask"); - value = 0; - if (str!=NULL) { - char * sstr = strdup(str); - char * tok = strtok(sstr, " "); - while (tok) { - value |= ally_flag(tok, -1); - tok = strtok(NULL, " "); - } - free(sstr); - } else { - value = HELP_ALL; - } - } - return value; -} - -int -AllianceRestricted(void) -{ - static int value = -1; - if (value<0) { - const char * str = get_param(global.parameters, "alliance.restricted"); - value = 0; - if (str!=NULL) { - char * sstr = strdup(str); - char * tok = strtok(sstr, " "); - while (tok) { - value |= ally_flag(tok, -1); - tok = strtok(NULL, " "); - } - free(sstr); - } - value &= HelpMask(); - } - return value; -} - -int -LongHunger(const struct unit * u) { - static int value = -1; - if (u!=NULL) { - if (!fval(u, UFL_HUNGER)) return false; -#ifdef NEW_DAEMONHUNGER_RULE - if (u->race==new_race[RC_DAEMON]) return false; -#endif - } - if (value<0) { - value = get_param_int(global.parameters, "hunger.long", 0); - } - return value; -} - -int -SkillCap(skill_t sk) { - static int value = -1; - if (sk==SK_MAGIC) return 0; /* no caps on magic */ - if (value<0) { - value = get_param_int(global.parameters, "skill.maxlevel", 0); - } - return value; -} - -int -NMRTimeout(void) { - static int value = -1; - if (value<0) { - value = get_param_int(global.parameters, "nmr.timeout", 0); - } - return value; -} - -race_t -old_race(const struct race * rc) -{ - race_t i; - for (i=0;i!=MAXRACES;++i) { - if (new_race[i]==rc) return i; - } - return NORACE; -} - -helpmode helpmodes[] = { - { "all", HELP_ALL }, - { "money", HELP_MONEY }, - { "fight", HELP_FIGHT }, - { "observe", HELP_OBSERVE }, - { "give", HELP_GIVE }, - { "guard", HELP_GUARD }, - { "stealth", HELP_FSTEALTH }, - { "travel", HELP_TRAVEL }, - { NULL, 0 } -}; - -const char *directions[MAXDIRECTIONS+2] = -{ - "northwest", - "northeast", - "east", - "southeast", - "southwest", - "west", - "", - "pause" -}; - -/** Returns the English name of the race, which is what the database uses. - */ -const char * -dbrace(const struct race * rc) -{ - static char zText[32]; - char * zPtr = zText; - - /* the english names are all in ASCII, so we don't need to worry about UTF8 */ - strcpy(zText, (const char*)LOC(find_locale("en"), rc_name(rc, 0))); - while (*zPtr) { - *zPtr = (char)(toupper(*zPtr)); - ++zPtr; - } - return zText; -} - -const char *parameters[MAXPARAMS] = -{ - "LOCALE", - "ALLES", - "JEDEM", - "BAUERN", - "BURG", - "EINHEIT", - "PRIVAT", - "HINTEN", - "KOMMANDO", - "KRAEUTER", - "NICHT", - "NAECHSTER", - "PARTEI", - "ERESSEA", - "PERSONEN", - "REGION", - "SCHIFF", - "SILBER", - "STRASSEN", - "TEMPORAERE", - "FLIEHE", - "GEBAEUDE", - "GIB", /* Für HELFE */ - "KAEMPFE", - "DURCHREISE", - "BEWACHE", - "ZAUBER", - "PAUSE", - "VORNE", - "AGGRESSIV", - "DEFENSIV", - "STUFE", - "HELFE", - "FREMDES", - "AURA", - "UM", - "BEISTAND", - "GNADE", - "HINTER", - "VOR", - "ANZAHL", - "GEGENSTAENDE", - "TRAENKE", - "GRUPPE", - "PARTEITARNUNG", - "BAEUME", - "XEPOTION", - "XEBALLOON", - "XELAEN", - "ALLIANZ" -}; - - -const char *keywords[MAXKEYWORDS] = -{ - "//", - "BANNER", - "ARBEITEN", - "ATTACKIEREN", - "BEKLAUEN", - "BELAGERE", - "BENENNEN", - "BENUTZEN", - "BESCHREIBEN", - "BETRETEN", - "BEWACHEN", - "BOTSCHAFT", - "ENDE", - "FAHREN", - "NUMMER", - "KRIEG", - "FRIEDEN", - "FOLGEN", - "FORSCHEN", - "GIB", - "HELFEN", - "KAEMPFEN", - "KAMPFZAUBER", - "KAUFEN", - "KONTAKTIEREN", - "LEHREN", - "LERNEN", - "LIEFERE", - "MACHEN", - "NACH", - "PASSWORT", - "REKRUTIEREN", - "RESERVIEREN", - "ROUTE", - "SABOTIEREN", - "OPTION", - "SPIONIEREN", - "STIRB", - "TARNEN", - "TRANSPORTIEREN", - "TREIBEN", - "UNTERHALTEN", - "VERKAUFEN", - "VERLASSEN", - "VERGESSEN", - "ZAUBERE", - "ZEIGEN", - "ZERSTOEREN", - "ZUECHTEN", - "DEFAULT", - "URSPRUNG", - "EMAIL", - "PIRATERIE", - "NEUSTART", - "GRUPPE", - "OPFERE", - "BETEN", - "SORTIEREN", - "JIHAD", - "GM", - "INFO", - "PRAEFIX", - "PFLANZEN", - "WERWESEN", - "XONTORMIA", - "ALLIANZ", - "BEANSPRUCHEN", - "PROMOTION", - "BEZAHLEN", -}; - -const char *report_options[MAX_MSG] = -{ - "Kampf", - "Ereignisse", - "Bewegung", - "Einkommen", - "Handel", - "Produktion", - "Orkvermehrung", - "Zauber", - "", - "" -}; - -const char *message_levels[ML_MAX] = -{ - "Wichtig", - "Debug", - "Fehler", - "Warnungen", - "Infos" -}; - -const char *options[MAXOPTIONS] = -{ - "AUSWERTUNG", - "COMPUTER", - "ZUGVORLAGE", - NULL, - "STATISTIK", - "DEBUG", - "ZIPPED", - "ZEITUNG", /* Option hat Sonderbehandlung! */ - NULL, - "ADRESSEN", - "BZIP2", - "PUNKTE", - "SHOWSKCHANGE", - "XML" -}; - -static int -allied_skillcount(const faction * f, skill_t sk) -{ - int num = 0; - alliance * a = f_get_alliance(f); - faction_list * members = a->members; - while (members!=NULL) { - num += count_skill(members->data, sk); - members=members->next; - } - return num; -} - -static int -allied_skilllimit(const faction * f, skill_t sk) -{ - static int value = -1; - if (value<0) { - value = get_param_int(global.parameters, "alliance.skilllimit", 0); - } - return value; -} - -static void -init_maxmagicians(struct attrib *a) -{ - a->data.i = MAXMAGICIANS; -} - -static attrib_type at_maxmagicians = { - "maxmagicians", - init_maxmagicians, - NULL, - NULL, - a_writeint, - a_readint, - ATF_UNIQUE -}; - -static void -init_npcfaction(struct attrib *a) -{ - a->data.i = 1; -} - - -static attrib_type at_npcfaction = { - "npcfaction", - init_npcfaction, - NULL, - NULL, - a_writeint, - a_readint, - ATF_UNIQUE -}; - -int -max_magicians(const faction * f) -{ - int m = MAXMAGICIANS; - attrib * a; - - if ((a = a_find(f->attribs, &at_maxmagicians)) != NULL) { - m = a->data.i; - } - if (f->race == new_race[RC_ELF]) ++m; - return m; -} - -int -skill_limit(faction * f, skill_t sk) -{ - int m = INT_MAX; - int al = allied_skilllimit(f, sk); - if (al>0) { - if (sk!=SK_ALCHEMY && sk!=SK_MAGIC) return INT_MAX; - if (f_get_alliance(f)) { - int ac = listlen(f->alliance->members); /* number of factions */ - int fl = (al+ac-1)/ac; /* faction limit, rounded up */ - /* the faction limit may not be achievable because it would break the alliance-limit */ - int sc = al - allied_skillcount(f, sk); - if (sc<=0) return 0; - return fl; - } - } - switch (sk) { - case SK_MAGIC: - m = max_magicians(f); - break; - case SK_ALCHEMY: - m = MAXALCHEMISTS; - break; - } - return m; -} - -int -count_skill(faction * f, skill_t sk) -{ - int n = 0; - unit *u; - - for (u = f->units; u; u = u->nextF) { - if (has_skill(u, sk)) { - if (!is_familiar(u)) n += u->number; - } - } - return n; -} - -int verbosity = 0; - -FILE *debug; - -static int -ShipSpeedBonus(const unit * u) -{ - static int level = -1; - if (level==-1) { - level = get_param_int(global.parameters, "movement.shipspeed.skillbonus", 0); - } - if (level>0) { - ship * sh = u->ship; - int skl = effskill(u, SK_SAILING); - int minsk = (sh->type->cptskill+1)/2; - return (skl-minsk)/level; - } - return 0; -} - -int -shipspeed(const ship * sh, const unit * u) -{ - double k = sh->type->range; - static const curse_type * stormwind_ct, * nodrift_ct; - static boolean init; - attrib *a; - curse *c; - - if (!init) { - init = true; - stormwind_ct = ct_find("stormwind"); - nodrift_ct = ct_find("nodrift"); - } - - assert(u->ship==sh); - assert(sh->type->construction->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */ - if (sh->size!=sh->type->construction->maxsize) return 0; - - if( curse_active(get_curse(sh->attribs, stormwind_ct))) - k *= 2; - if( curse_active(get_curse(sh->attribs, nodrift_ct))) - k += 1; - - if (u->faction->race == u->race) { - /* race bonus for this faction? */ - if (fval(u->race, RCF_SHIPSPEED)) { - k += 1; - } - } - - k += ShipSpeedBonus(u); - - a = a_find(sh->attribs, &at_speedup); - while (a != NULL && a->type==&at_speedup) { - k += a->data.sa[0]; - a = a->next; - } - - c = get_curse(sh->attribs, ct_find("shipspeedup")); - while(c) { - k += curse_geteffect(c); - c = c->nexthash; - } - -#ifdef SHIPSPEED - k *= SHIPSPEED; -#endif - -#ifdef SHIPDAMAGE - if (sh->damage) k = (k * (sh->size * DAMAGE_SCALE - sh->damage) + sh->size * DAMAGE_SCALE- 1) / (sh->size*DAMAGE_SCALE); -#endif - - return (int)k; -} - -#define FMAXHASH 2039 -faction * factionhash[FMAXHASH]; - -void -fhash(faction * f) -{ - int index = f->no % FMAXHASH; - f->nexthash = factionhash[index]; - factionhash[index] = f; -} - -void -funhash(faction * f) -{ - int index = f->no % FMAXHASH; - faction ** fp = factionhash+index; - while (*fp && (*fp)!=f) fp = &(*fp)->nexthash; - *fp = f->nexthash; -} - -static faction * -ffindhash(int no) -{ - int index = no % FMAXHASH; - faction * f = factionhash[index]; - while (f && f->no!=no) f = f->nexthash; - return f; -} -/* ----------------------------------------------------------------------- */ - -void -verify_data(void) -{ -#ifndef NDEBUG - int lf = -1; - faction *f; - unit *u; - int mage, alchemist; - - if (verbosity>=1) puts(" - Überprüfe Daten auf Korrektheit..."); - - list_foreach(faction, factions, f) { - mage = 0; - alchemist = 0; - for (u=f->units;u;u=u->nextF) { - if (eff_skill(u, SK_MAGIC, u->region)) { - mage += u->number; - } - if (eff_skill(u, SK_ALCHEMY, u->region)) - alchemist += u->number; - if (u->number > UNIT_MAXSIZE) { - if (lf != f->no) { - lf = f->no; - log_stdio(stdout, "Partei %s:\n", factionid(f)); - } - log_warning(("Einheit %s hat %d Personen\n", unitid(u), u->number)); - } - } - if (f->no != 0 && ((mage > 3 && f->race != new_race[RC_ELF]) || mage > 4)) - log_error(("Partei %s hat %d Magier.\n", factionid(f), mage)); - if (alchemist > 3) - log_error(("Partei %s hat %d Alchemisten.\n", factionid(f), alchemist)); - } - list_next(f); -#endif -} - -int -distribute(int old, int new_value, int n) -{ - int i; - int t; - assert(new_value <= old); - - if (old == 0) - return 0; - - t = (n / old) * new_value; - for (i = (n % old); i; i--) - if (rng_int() % old < new_value) - t++; - - return t; -} - -int -change_hitpoints (unit * u, int value) -{ - int hp = u->hp; - - hp += value; - - /* Jede Person benötigt mindestens 1 HP */ - if (hp < u->number){ - if (hp < 0){ /* Einheit tot */ - hp = 0; - } - scale_number(u, hp); - } - u->hp = hp; - return hp; -} - -unsigned int -atoip(const char *s) -{ - int n; - - n = atoi (s); - - if (n < 0) - n = 0; - - return n; -} - -region * -findunitregion (const unit * su) -{ -#ifndef SLOW_REGION - return su->region; -#else - region *r; - const unit *u; - - for (r = regions; r; r = r->next) { - for (u = r->units; u; u = u->next) { - if (su == u) { - return r; - } - } - } - - /* This should never happen */ - assert (!"Die unit wurde nicht gefunden"); - - return (region *) NULL; -#endif -} - -int -effskill(const unit * u, skill_t sk) -{ - return eff_skill(u, sk, u->region); -} - -int -eff_stealth(const unit * u, const region * r) -{ - int e = 0; - - /* Auf Schiffen keine Tarnung! */ - if (!u->ship && skill_enabled[SK_STEALTH]) { - e = eff_skill (u, SK_STEALTH, r); - - if (fval(u, UFL_STEALTH)) { - int es = u_geteffstealth(u); - if (es >=0 && es < e) return es; - } - } - return e; -} - -boolean -unit_has_cursed_item(unit *u) -{ - item * itm = u->items; - while (itm) { - if (fval(itm->type, ITF_CURSED) && itm->number>0) return true; - itm=itm->next; - } - return false; -} - -static void -init_gms(void) -{ - faction * f; - - for (f=factions;f;f=f->next) { - const attrib * a = a_findc(f->attribs, &at_gm); - - if (a!=NULL) fset(f, FFL_GM); - } -} - -static int -autoalliance(const plane * pl, const faction * sf, const faction * f2) -{ - static boolean init = false; - if (!init) { - init_gms(); - init = true; - } - if (pl && (pl->flags & PFL_FRIENDLY)) return HELP_ALL; - /* if f2 is a gm in this plane, everyone has an auto-help to it */ - if (fval(f2, FFL_GM)) { - attrib * a = a_find(f2->attribs, &at_gm); - - while (a) { - const plane * p = (const plane*)a->data.v; - if (p==pl) return HELP_ALL; - a=a->next; - } - } - - if (f_get_alliance(sf)!=NULL && AllianceAuto()) { - if (sf->alliance==f2->alliance) return AllianceAuto(); - } - - return 0; -} - -static int -ally_mode(const ally * sf, int mode) -{ - if (sf==NULL) return 0; - return sf->status & mode; -} - -int -alliedgroup(const struct plane * pl, const struct faction * f, - const struct faction * f2, const struct ally * sf, int mode) -{ - while (sf && sf->faction!=f2) sf=sf->next; - if (sf==NULL) { - mode = mode & autoalliance(pl, f, f2); - } - mode = ally_mode(sf, mode) | (mode & autoalliance(pl, f, f2)); - if (AllianceRestricted()) { - if (a_findc(f->attribs, &at_npcfaction)) { - return mode; - } - if (a_findc(f2->attribs, &at_npcfaction)) { - return mode; - } - if (f->alliance!=f2->alliance) { - mode &= ~AllianceRestricted(); - } - } - return mode; -} - -int -alliedfaction(const struct plane * pl, const struct faction * f, - const struct faction * f2, int mode) -{ - return alliedgroup(pl, f, f2, f->allies, mode); -} - -/* Die Gruppe von Einheit u hat helfe zu f2 gesetzt. */ -int -alliedunit(const unit * u, const faction * f2, int mode) -{ - ally * sf; - int automode; - - assert(u->region); /* the unit should be in a region, but it's possible that u->number==0 (TEMP units) */ - if (u->faction == f2) return mode; - if (u->faction != NULL && f2!=NULL) { - plane * pl; - - if (mode&HELP_FIGHT) { - if ((u->flags&UFL_DEFENDER) || (u->faction->flags&FFL_DEFENDER)) { - faction * owner = region_get_owner(u->region); - /* helps the owner of the region */ - if (owner==f2) { - return HELP_FIGHT; - } - } - } - - pl = rplane(u->region); - automode = mode & autoalliance(pl, u->faction, f2); - - if (pl!=NULL && (pl->flags & PFL_NOALLIANCES)) - mode = (mode & automode) | (mode & HELP_GIVE); - - sf = u->faction->allies; - if (fval(u, UFL_GROUP)) { - const attrib * a = a_findc(u->attribs, &at_group); - if (a!=NULL) sf = ((group*)a->data.v)->allies; - } - return alliedgroup(pl, u->faction, f2, sf, mode); - } - return 0; -} - -boolean -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)) - return true; - return false; -} - -boolean -cansee(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 */ -{ - int stealth, rings; - unit *u2 = r->units; - static const item_type * itype_grail; - static boolean init; - - if (!init) { - init = true; - itype_grail = it_find("grail"); - } - - if (u->faction == f || omniscient(f)) { - return true; - } else if (fval(u->race, RCF_INVISIBLE)) { - return false; - } else if (u->number == 0) { - 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. */ - u = (unit *)a->data.v; - } else { - return false; - } - } - - if (leftship(u)) return true; - if (itype_grail!=NULL && i_get(u->items, itype_grail)) 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, GUARD_ALL)!=0 || usiege(u) || u->building || u->ship) { - return true; - } - - rings = invisible(u, NULL); - stealth = eff_stealth(u, r) - modifier; - - while (u2) { - if (ringsnumber || invisible(u, u2) < u->number) { - if (skill_enabled[SK_PERCEPTION]) { - int observation = eff_skill(u2, SK_PERCEPTION, r); - - if (observation >= stealth) { - return true; - } - } else { - return true; - } - } - - /* find next unit in our faction */ - do { - u2=u2->next; - } while (u2 && u2->faction != f); - } - return false; -} - -boolean -cansee_unit(const unit * u, const unit * target, int modifier) -/* target->region kann != u->region sein, wenn es um durchreisen geht */ -{ - if (fval(target->race, RCF_INVISIBLE) || target->number == 0) return false; - else if (target->faction == u->faction) return true; - else { - int n, rings, o; - - if (is_guard(target, GUARD_ALL)!=0 || usiege(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]) { - o = eff_skill(u, SK_PERCEPTION, target->region); - if (o >= n) { - return true; - } - } else { - return true; - } - } - return false; -} - -boolean -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 */ -{ - int n; - unit *u2; - - if (fval(u->race, RCF_INVISIBLE) || u->number == 0) return false; - else if (u->faction == f) return true; - else { - int rings; - - if (is_guard(u, GUARD_ALL)!=0 || usiege(u) || u->building || u->ship) { - return true; - } - - n = eff_stealth(u, r) - modifier; - rings = invisible(u, NULL); - if (rings==0 && n<=0) { - return true; - } - - for (u2 = r->units; u2; u2 = u2->next){ - if (u2->faction == f) { - int o; - - if (rings && invisible(u, u2) >= u->number) continue; - - o = eff_skill(u2, SK_PERCEPTION, r); - - if (o >= n) { - return true; - } - } - } - } - return false; -} - -#ifndef NDEBUG -const char * -strcheck (const char *s, size_t maxlen) -{ - static char buffer[16 * 1024]; - if (strlen(s) > maxlen) { - assert(maxlen < 16 * 1024); - log_warning(("[strcheck] String wurde auf %d Zeichen verkürzt:\n%s\n", - (int)maxlen, s)); - strlcpy(buffer, s, maxlen); - return buffer; - } - return s; -} -#endif - -static attrib_type at_lighthouse = { - "lighthouse" - /* Rest ist NULL; temporäres, nicht alterndes Attribut */ -}; - -/* update_lighthouse: call this function whenever the size of a lighthouse changes - * it adds temporary markers to the surrounding regions. - * The existence of markers says nothing about the quality of the observer in - * the lighthouse, for this may change more frequently. - */ -void -update_lighthouse(building * lh) -{ - static boolean init_lighthouse = false; - static const struct building_type * bt_lighthouse = 0; - - if (!init_lighthouse) { - bt_lighthouse = bt_find("lighthouse"); - if (bt_lighthouse==NULL) return; - init_lighthouse = true; - } - - if (lh->type==bt_lighthouse) { - region * r = lh->region; - int d = (int)log10(lh->size) + 1; - int x; - - if (lh->size>0) { - r->flags |= RF_LIGHTHOUSE; - } - - for (x=-d;x<=d;++x) { - int y; - for (y=-d;y<=d;++y) { - attrib * a; - region * r2; - int px = r->x+x, py = r->y+y; - pnormalize(&px, &py, rplane(r)); - r2 = findregion(px, py); - if (r2==NULL) continue; - if (!fval(r2->terrain, SEA_REGION)) continue; - if (distance(r, r2) > d) continue; - a = a_find(r2->attribs, &at_lighthouse); - while (a && a->type==&at_lighthouse) { - building * b = (building*)a->data.v; - if (b==lh) break; - a = a->next; - } - if (!a) { - a = a_add(&r2->attribs, a_new(&at_lighthouse)); - a->data.v = (void*)lh; - } - } - } - } -} - -int -count_all(const faction * f) -{ -#ifndef NDEBUG - int n = 0; - unit *u; - for (u=f->units;u;u=u->nextF) { - if (playerrace(u->race)) { - n += u->number; - assert(f==u->faction); - } - } - if (f->num_people != n) { - log_error(("# of people in %s is != num_people: %d should be %d.\n", - factionid(f), f->num_people, n)); - } -#endif - return f->num_people; -} - -int -count_migrants (const faction * f) -{ - unit *u = f->units; - int n = 0; - while (u) { - assert(u->faction == f); - if (u->race != f->race && u->race != new_race[RC_ILLUSION] && u->race != new_race[RC_SPELL] - && !!playerrace(u->race) && !(is_cursed(u->attribs, C_SLAVE, 0))) - { - n += u->number; - } - u = u->nextF; - } - return n; -} - -int -count_maxmigrants(const faction * f) -{ - static int migrants = -1; - - if (migrants<0) { - migrants = get_param_int(global.parameters, "rules.migrants", INT_MAX); - } - if (migrants==INT_MAX) { - int x = 0; - if (f->race == new_race[RC_HUMAN]) { - int nsize = count_all(f); - if (nsize>0) { - x = (int)(log10(nsize / 50.0) * 20); - if (x < 0) x = 0; - } - } - return x; - } - return migrants; -} - -void -init_tokens(const struct order * ord) -{ - char * cmd = getcommand(ord); - init_tokens_str(cmd, cmd); -} - -void -parse(keyword_t kword, int (*dofun)(unit *, struct order *), boolean thisorder) -{ - region *r; - - for (r = regions; r; r = r->next) { - unit **up = &r->units; - while (*up) { - unit * u = *up; - order ** ordp = &u->orders; - if (thisorder) ordp = &u->thisorder; - while (*ordp) { - order * ord = *ordp; - if (get_keyword(ord) == kword) { - if (dofun(u, ord)!=0) break; - if (u->orders==NULL) break; - } - if (thisorder) break; - if (*ordp==ord) ordp=&ord->next; - } - if (*up==u) up=&u->next; - } - } -} - -const char * -igetstrtoken(const char * initstr) -{ - if (initstr!=NULL) { - init_tokens_str(initstr, NULL); - } - - return getstrtoken(); -} - -unsigned int -getuint (void) -{ - return atoip((const char *)getstrtoken()); -} - -int -getint (void) -{ - return atoi((const char *)getstrtoken()); -} - -const struct race * -findrace(const char * s, const struct locale * lang) -{ - struct tnode * tokens = get_translations(lang, UT_RACES); - variant token; - - assert(lang); - if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { - return (const struct race *)token.v; - } - return NULL; -} - -int -findoption(const char *s, const struct locale * lang) -{ - struct tnode * tokens = get_translations(lang, UT_OPTIONS); - variant token; - - if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { - return (direction_t)token.i; - } - return NODIRECTION; -} - -#if PTRIES -static struct trie_node * ptries[UT_MAX][4]; - -static struct trie_node ** -get_ptrie(const struct locale * lang, int type) -{ - int index = (strcmp(locale_name(lang), "de")==0); - return &(ptries[type][index]); -} - -static int -umlaut_substitution(const char * ip, char * op, size_t outlen) -{ -#define UMAX 7 - static struct replace { - ucs4_t ucs; - const char str[3]; - } replace[UMAX] = { - /* match lower-case (!) umlauts and others to transcriptions */ - { 223, "ss"}, /* szlig */ - { 228, "ae"}, /* auml */ - { 229, "aa"}, /* norsk */ - { 230, "ae"}, /* norsk */ - { 246, "oe"}, /* ouml */ - { 248, "oe"}, /* norsk */ - { 252, "ue"}, /* uuml */ - }; - int subs = 0; - while (*ip) { - ucs4_t ucs = *ip; - size_t size = 1; - size_t cpsize = 1; - - if (ucs & 0x80) { - int ret = unicode_utf8_to_ucs4(&ucs, ip, &size); - if (ret!=0) { - return ret; - } - cpsize = size; - if (ucs >= replace[0].ucs && ucs <= replace[UMAX-1].ucs) { - int i; - for (i=0;i!=UMAX;++i) { - if (replace[i].ucs==ucs) { - cpsize = 0; - memcpy(op, replace[i].str, 2); - op+=2; - ++subs; - break; - } - } - } - } - if (cpsize) { - if (cpsize>outlen) { - return -1; - } - memcpy(op, ip, cpsize); - } - - ip += size; - op += cpsize; - outlen -= cpsize; - } - - if (outlen<=0) { - return -1; - } - *op = 0; - return subs; -} - -static int -ptrie_find(struct trie_node *ptrie, const char * key, void * data, size_t size) -{ - trie_node * node = trie_find_prefix(ptrie, key); - if (node) { - void * result = trie_getdata(node); - memcpy(data, result, size); - return 0; - } - return -1; -} - -static int -ptrie_insert(struct trie_node **ptrie, const char * name, void * data, size_t size) -{ - char converted[256]; - char simple[256]; - int ret = unicode_utf8_tolower(converted, 256, name); - if (ret==0) { - int subs = umlaut_substitution(converted, simple, sizeof(simple)); - if (subs>0) { - trie_insert(ptrie, simple, data, size); - } - trie_insert(ptrie, converted, data, size); - } - return ret; -} -#endif - -skill_t -findskill(const char *s, const struct locale * lang) -{ -#if PTRIES - char lowercase[256]; - int res = unicode_utf8_tolower(lowercase, sizeof(lowercase), s); - if (res==0) { - trie_node ** ptrie = get_ptrie(lang, UT_SKILLS); - skill_t sk; - int result = ptrie_find(*ptrie, lowercase, &sk, sizeof(sk)); - if (result==0) return sk; - } - return NOSKILL; -#else - struct tnode * tokens = get_translations(lang, UT_SKILLS); - variant token; - - if (findtoken(tokens, s, &token)==E_TOK_NOMATCH) return NOSKILL; - return (skill_t)token.i; -#endif -} - -keyword_t -findkeyword(const char *s, const struct locale * lang) -{ - struct tnode * tokens = get_translations(lang, UT_KEYWORDS); - variant token; - - if (*s == '@') s++; - if (findtoken(tokens, s, &token)==E_TOK_NOMATCH) return NOKEYWORD; - if (global.disabled[token.i]) return NOKEYWORD; - return (keyword_t) token.i; -} - -param_t -findparam(const char *s, const struct locale * lang) -{ - struct tnode * tokens = get_translations(lang, UT_PARAMS); - variant token; - - if (findtoken(tokens, s, &token)==E_TOK_NOMATCH) { - const building_type * btype = findbuildingtype(s, lang); - if (btype!=NULL) return (param_t) P_GEBAEUDE; - return NOPARAM; - } - if (token.i==P_BUILDING) return P_GEBAEUDE; - return (param_t)token.i; -} - -param_t -getparam (const struct locale * lang) -{ - return findparam (getstrtoken (), lang); -} - -faction * -findfaction (int n) -{ - faction * f = ffindhash(n); - return f; -} - -faction * -getfaction (void) -{ - return findfaction (getid()); -} - -unit * -findunitr (const region * r, int n) -{ - unit *u; - - /* findunit regional! */ - - for (u = r->units; u; u = u->next) - if (u->no == n) - return u; - - return 0; -} - -unit *findunit(int n) -{ - if (n <= 0) { - return NULL; - } - return ufindhash(n); -} - -unit * -findunitg (int n, const region * hint) -{ - - /* Abfangen von Syntaxfehlern. */ - if (n <= 0) - return NULL; - - /* findunit global! */ - hint = 0; - return ufindhash(n); -} - -unit * -getnewunit (const region * r, const faction * f) -{ - int n; - n = getid(); - - return findnewunit (r, f, n); -} - -static int -read_newunitid (const faction * f, const region * r) -{ - int n; - unit *u2; - n = getid(); - if (n == 0) - return -1; - - u2 = findnewunit(r, f, n); - if (u2) return u2->no; - - return -1; -} - -int -read_unitid (const faction * f, const region * r) -{ - const char * s = getstrtoken(); - - /* Da s nun nur einen string enthaelt, suchen wir ihn direkt in der - * paramliste. machen wir das nicht, dann wird getnewunit in s nach der - * nummer suchen, doch dort steht bei temp-units nur "temp" drinnen! */ - - switch (findparam(s, f->locale)) { - case P_TEMP: - return read_newunitid(f, r); - } - if (!s || *s == 0) - return -1; - return atoi36((const char *)s); -} - -/* exported symbol */ -boolean getunitpeasants; -unit * -getunitg(const region * r, const faction * f) -{ - int n = read_unitid(f, r); - - if (n == 0) { - getunitpeasants = 1; - return NULL; - } - getunitpeasants = 0; - if (n < 0) return 0; - - return findunit(n); -} - -unit * -getunit(const region * r, const faction * f) -{ - int n = read_unitid(f, r); - unit *u2; - - if (n == 0) { - getunitpeasants = 1; - return NULL; - } - getunitpeasants = 0; - if (n < 0) return 0; - - u2 = findunit(n); - if (u2!=NULL && u2->region==r) { - /* there used to be a 'u2->flags & UFL_ISNEW || u2->number>0' condition - * here, but it got removed because of a bug that made units disappear: - * http://eressea.upb.de/mantis/bug_view_page.php?bug_id=0000172 - */ - return u2; - } - - return NULL; -} - -/* - String Listen --------------------------------------------- */ -void -addstrlist (strlist ** SP, const char *s) -{ - strlist * slist = malloc(sizeof(strlist)); - slist->next = NULL; - slist->s = strdup(s); - addlist(SP, slist); -} - -void -freestrlist (strlist * s) -{ - strlist *q, *p = s; - while (p) { - q = p->next; - free(p->s); - free(p); - p = q; - } -} - -/* - Meldungen und Fehler ------------------------------------------------- */ - -boolean lomem = false; - -/* - Namen der Strukturen -------------------------------------- */ -typedef char name[OBJECTIDSIZE+1]; -static name idbuf[8]; -static int nextbuf = 0; - -char * -estring_i(char *ibuf) -{ - char *p = ibuf; - - while (*p) { - if (isxspace(*(unsigned*)p) == ' ') { - *p = '~'; - } - ++p; - } - return ibuf; -} - -char * -estring(const char *s) -{ - char *ibuf = idbuf[(++nextbuf) % 8]; - - strlcpy(ibuf, s, sizeof(name)); - return estring_i(ibuf); -} - -char * -cstring_i(char *ibuf) -{ - char *p = ibuf; - - while (*p) { - if (*p == '~') { - *p = ' '; - } - ++p; - } - return ibuf; -} - -char * -cstring(const char *s) -{ - char *ibuf = idbuf[(++nextbuf) % 8]; - - strlcpy(ibuf, s, sizeof(name)); - return cstring_i(ibuf); -} - -building * -largestbuilding(const region * r, cmp_building_cb cmp_gt, boolean imaginary) -{ - building *b, *best = NULL; - - for (b = rbuildings(r); b; b = b->next) { - if (cmp_gt(b, best)<=0) continue; - if (!imaginary) { - const attrib * a = a_find(b->attribs, &at_icastle); - if (a) continue; - } - best = b; - } - return best; -} - -char * -write_unitname(const unit * u, char * buffer, size_t size) -{ - snprintf((char*)buffer, size, "%s (%s)", (const char*)u->name, itoa36(u->no)); - buffer[size-1] = 0; - return buffer; -} - -const char * -unitname(const unit * u) -{ - char *ubuf = idbuf[(++nextbuf) % 8]; - return write_unitname(u, ubuf, sizeof(name)); -} - -/* -- Erschaffung neuer Einheiten ------------------------------ */ - -extern faction * dfindhash(int i); - -static const char* forbidden[] = { "t", "te", "tem", "temp", NULL }; - -int -forbiddenid(int id) -{ - static int * forbid = NULL; - static size_t len; - size_t i; - if (id<=0) return 1; - if (!forbid) { - while (forbidden[len]) ++len; - forbid = calloc(len, sizeof(int)); - for (i=0;i!=len;++i) { - forbid[i] = strtol(forbidden[i], NULL, 36); - } - } - for (i=0;i!=len;++i) if (id==forbid[i]) return 1; - return 0; -} - -/* ID's für Einheiten und Zauber */ -int -newunitid(void) -{ - int random_unit_no; - int start_random_no; - random_unit_no = 1 + (rng_int() % MAX_UNIT_NR); - start_random_no = random_unit_no; - - while (ufindhash(random_unit_no) || dfindhash(random_unit_no) - || cfindhash(random_unit_no) - || forbiddenid(random_unit_no)) - { - random_unit_no++; - if (random_unit_no == MAX_UNIT_NR + 1) { - random_unit_no = 1; - } - if (random_unit_no == start_random_no) { - random_unit_no = (int) MAX_UNIT_NR + 1; - } - } - return random_unit_no; -} - -int -newcontainerid(void) -{ - int random_no; - int start_random_no; - - random_no = 1 + (rng_int() % MAX_CONTAINER_NR); - start_random_no = random_no; - - while (findship(random_no) || findbuilding(random_no)) { - random_no++; - if (random_no == MAX_CONTAINER_NR + 1) { - random_no = 1; - } - if (random_no == start_random_no) { - random_no = (int) MAX_CONTAINER_NR + 1; - } - } - return random_no; -} - -unit * -createunit(region * r, faction * f, int number, const struct race * rc) -{ - assert(rc); - return create_unit(r, f, number, rc, 0, NULL, NULL); -} - -boolean -idle (faction * f) -{ - return (boolean) (f ? false : true); -} - - -int -maxworkingpeasants(const struct region * r) -{ - int i = production(r) * MAXPEASANTS_PER_AREA - - ((rtrees(r,2)+rtrees(r,1)/2) * TREESIZE); - return MAX(i, 0); -} - -int -lighthouse_range(const building * b, const faction * f) -{ - int d = 0; - if (fval(b, BLD_WORKING) && b->size >= 10) { - int maxd = (int)log10(b->size) + 1; - - if (skill_enabled[SK_PERCEPTION]) { - region * r = b->region; - int c = 0; - unit *u; - for (u = r->units; u; u = u->next) { - if (u->building == b) { - c += u->number; - if (c > buildingcapacity(b)) break; - if (f==NULL || u->faction == f) { - int sk = eff_skill(u, SK_PERCEPTION, r) / 3; - d = MAX(d, sk); - d = MIN(maxd, d); - if (d==maxd) break; - } - } else if (c) break; /* first unit that's no longer in the house ends the search */ - } - } else { - /* E3A rule: no perception req'd */ - return maxd; - } - } - return d; -} - -boolean -check_leuchtturm(region * r, faction * f) -{ - attrib * a; - - if (!fval(r->terrain, SEA_REGION)) return false; - - for (a = a_find(r->attribs, &at_lighthouse);a && a->type==&at_lighthouse;a=a->next) { - building *b = (building *)a->data.v; - - assert(b->type == bt_find("lighthouse")); - if (fval(b, BLD_WORKING) && b->size >= 10) { - int maxd = (int)log10(b->size) + 1; - - if (skill_enabled[SK_PERCEPTION]) { - region *r2 = b->region; - unit *u; - int c = 0; - int d = 0; - - for (u = r2->units; u; u = u->next) { - if (u->building == b) { - c += u->number; - if (c > buildingcapacity(b)) break; - if (f==NULL || u->faction == f) { - if (!d) d = distance(r, r2); - if (maxd < d) break; - if (eff_skill(u, SK_PERCEPTION, r) >= d * 3) return true; - } - } else if (c) break; /* first unit that's no longer in the house ends the search */ - } - } else { - /* E3A rule: no perception req'd */ - return maxd; - } - } - } - - return false; -} - -region * -lastregion (faction * f) -{ -#ifdef SMART_INTERVALS - unit * u = f->units; - region *r = f->last; - - if (u==NULL) return NULL; - if (r!=NULL) return r->next; - - /* it is safe to start in the region of the first unit. */ - f->last = u->region; - /* if regions have indices, we can skip ahead: */ - for (u=u->nextF; u!=NULL; u=u->nextF) { - r = u->region; - if (r->index > f->last->index) f->last = r; - } - - /* we continue from the best region and look for travelthru etc. */ - for (r = f->last->next; r; r = r->next) { - plane * p = rplane(r); - - /* search the region for travelthru-attributes: */ - if (fval(r, RF_TRAVELUNIT)) { - attrib * ru = a_find(r->attribs, &at_travelunit); - while (ru && ru->type==&at_travelunit) { - u = (unit*)ru->data.v; - if (u->faction == f) { - f->last = r; - break; - } - ru = ru->next; - } - } - if (f->last == r) continue; - if (check_leuchtturm(r, f)) - f->last = r; - if (p && is_watcher(p, f)) { - f->last = r; - } - } - return f->last->next; -#else - return NULL; -#endif -} - -region * -firstregion (faction * f) -{ -#ifdef SMART_INTERVALS - region *r = f->first; - - if (f->units==NULL) return NULL; - if (r!=NULL) return r; - - return f->first = regions; -#else - return regions; -#endif -} - -void ** blk_list[1024]; -int list_index; -int blk_index; - -static void -gc_done(void) -{ - int i, k; - for (i=0;i!=list_index;++i) - { - for (k=0;k!=1024;++k) free(blk_list[i][k]); - free(blk_list[i]); - } - for (k=0;k!=blk_index;++k) free(blk_list[list_index][k]); - free(blk_list[list_index]); - -} - -void * -gc_add(void * p) -{ - if (blk_index==0) { - blk_list[list_index] = (void**)malloc(1024 * sizeof(void*)); - } - blk_list[list_index][blk_index] = p; - blk_index = (blk_index+1) % 1024; - if (!blk_index) ++ list_index; - return p; -} - -static void -init_directions(tnode * root, const struct locale * lang) -{ - /* mit dieser routine kann man mehrere namen für eine direction geben, - * das ist für die hexes ideal. */ - const struct { - const char* name; - int direction; - } dirs [] = { - { "dir_ne", D_NORTHEAST}, - { "dir_nw", D_NORTHWEST}, - { "dir_se", D_SOUTHEAST}, - { "dir_sw", D_SOUTHWEST}, - { "dir_east", D_EAST}, - { "dir_west", D_WEST}, - { "northeast", D_NORTHEAST}, - { "northwest", D_NORTHWEST}, - { "southeast", D_SOUTHEAST}, - { "southwest", D_SOUTHWEST}, - { "east", D_EAST }, - { "west",D_WEST }, - { "PAUSE", D_PAUSE }, - { NULL, NODIRECTION} - }; - int i; - struct tnode * tokens = get_translations(lang, UT_DIRECTIONS); - - for (i=0; dirs[i].direction!=NODIRECTION;++i) { - variant token; - token.i = dirs[i].direction; - addtoken(tokens, LOC(lang, dirs[i].name), token); - } -} - -direction_t -finddirection(const char *s, const struct locale * lang) -{ - struct tnode * tokens = get_translations(lang, UT_DIRECTIONS); - variant token; - - if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { - return (direction_t)token.i; - } - return NODIRECTION; -} - -static void -init_locale(const struct locale * lang) -{ - variant var; - int i; - const struct race * rc; - struct tnode * tokens; - const terrain_type * terrain; -#if PTRIES - trie_node ** ptrie; -#endif - - tokens = get_translations(lang, UT_MAGIC); - if (tokens) { - const char * str = get_param(global.parameters, "rules.magic.playerschools"); - char * sstr, * tok; - if (str==NULL) { - str = "gwyrrd illaun draig cerddor tybied"; - } - - sstr = strdup(str); - tok = strtok(sstr, " "); - while (tok) { - for (i=0;i!=MAXMAGIETYP;++i) { - if (strcmp(tok, magic_school[i])==0) break; - } - assert(i!=MAXMAGIETYP); - var.i = i; - addtoken(tokens, LOC(lang, mkname("school", tok)), var); - tok = strtok(NULL, " "); - } - free(sstr); - } - - tokens = get_translations(lang, UT_DIRECTIONS); - init_directions(tokens, lang); - - tokens = get_translations(lang, UT_RACES); - for (rc=races;rc;rc=rc->next) { - var.v = (void*)rc; - addtoken(tokens, LOC(lang, rc_name(rc, 1)), var); - addtoken(tokens, LOC(lang, rc_name(rc, 0)), var); - } - - tokens = get_translations(lang, UT_PARAMS); - for (i=0;i!=MAXPARAMS;++i) { - var.i = i; - addtoken(tokens, LOC(lang, parameters[i]), var); - } -#if PTRIES - ptrie = get_ptrie(lang, UT_SKILLS); - for (i=0;i!=MAXSKILLS;++i) { - skill_t sk = (skill_t)i; - const char * skname = skillname(sk, lang); - if (skname!=NULL) { - ptrie_insert(ptrie, skname, &sk, sizeof(sk)); - } - } -#else - tokens = get_translations(lang, UT_SKILLS); - for (i=0;i!=MAXSKILLS;++i) { - const char * skname = skillname((skill_t)i, lang); - if (skname!=NULL) { - var.i = i; - addtoken(tokens, skname, var); - } - } -#endif - - tokens = get_translations(lang, UT_KEYWORDS); - for (i=0;i!=MAXKEYWORDS;++i) { - var.i = i; - if (keywords[i]) addtoken(tokens, LOC(lang, keywords[i]), var); - } - - tokens = get_translations(lang, UT_OPTIONS); - for (i=0;i!=MAXOPTIONS;++i) { - var.i = i; - if (options[i]) addtoken(tokens, LOC(lang, options[i]), var); - } - - tokens = get_translations(lang, UT_TERRAINS); - for (terrain=terrains();terrain!=NULL;terrain=terrain->next) { - var.v = (void*)terrain; - addtoken(tokens, LOC(lang, terrain->_name), var); - } -} - -typedef struct param { - struct param * next; - char * name; - char * data; -} param; - -int -getid(void) -{ - const char * str = (const char *)getstrtoken(); - int i = atoi36(str); - if (i<0) { - return -1; - } - return i; -} - -const char * -get_param(const struct param * p, const char * key) -{ - while (p!=NULL) { - if (strcmp(p->name, key)==0) return p->data; - p = p->next; - } - return NULL; -} - -int -get_param_int(const struct param * p, const char * key, int def) -{ - while (p!=NULL) { - if (strcmp(p->name, key)==0) return atoi(p->data); - p = p->next; - } - return def; -} - -static const char * g_datadir; -const char * -datapath(void) -{ - static char zText[MAX_PATH]; - if (g_datadir) return g_datadir; - return strcat(strcpy(zText, basepath()), "/data"); -} - -void -set_datapath(const char * path) -{ - g_datadir = path; -} - - -static const char * g_reportdir; -const char * -reportpath(void) -{ - static char zText[MAX_PATH]; - if (g_reportdir) return g_reportdir; - return strcat(strcpy(zText, basepath()), "/reports"); -} - -void -set_reportpath(const char * path) -{ - g_reportdir = path; -} - -static const char * g_basedir; -const char * -basepath(void) -{ - if (g_basedir) return g_basedir; - return "."; -} - - -void -set_basepath(const char * path) -{ - g_basedir = path; -} - -float -get_param_flt(const struct param * p, const char * key, float def) -{ - while (p!=NULL) { - if (strcmp(p->name, key)==0) return (float)atof(p->data); - p = p->next; - } - return def; -} - -void -set_param(struct param ** p, const char * key, const char * data) -{ - ++global.cookie; - while (*p!=NULL) { - if (strcmp((*p)->name, key)==0) { - free((*p)->data); - (*p)->data = strdup(data); - return; - } - p=&(*p)->next; - } - *p = malloc(sizeof(param)); - (*p)->name = strdup(key); - (*p)->data = strdup(data); - (*p)->next = NULL; -} - -void -kernel_done(void) -{ - /* calling this function releases memory assigned to static variables, etc. - * calling it is optional, e.g. a release server will most likely not do it. - */ - translation_done(); - gc_done(); - sql_done(); -} - -const char * localenames[] = { - "de", "en", - NULL -}; - -void -init_locales(void) -{ - int l; - for (l=0;localenames[l];++l) { - const struct locale * lang = find_locale(localenames[l]); - if (lang) init_locale(lang); - } -} - -/* TODO: soll hier weg */ -extern struct attrib_type at_shiptrail; - -attrib_type at_germs = { - "germs", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - a_writeshorts, - a_readshorts, - ATF_UNIQUE -}; - -/*********************/ -/* at_guard */ -/*********************/ -attrib_type at_guard = { - "guard", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - a_writeint, - a_readint, - ATF_UNIQUE -}; - -void -setstatus(struct unit * u, int status) -{ - assert(status>=ST_AGGRO && status<=ST_FLEE); - if (u->status!=status) { - u->status = (status_t)status; - } -} - -void -setguard(unit * u, unsigned int flags) -{ - /* setzt die guard-flags der Einheit */ - attrib * a = NULL; - assert(flags==0 || !fval(u, UFL_MOVED)); - assert(flags==0 || u->statusattribs, &at_guard); - } - if (flags == GUARD_NONE) { - freset(u, UFL_GUARD); - if (a) a_remove(&u->attribs, a); - return; - } - fset(u, UFL_GUARD); - fset(u->region, RF_GUARDED); - if ((int)flags==guard_flags(u)) { - if (a) a_remove(&u->attribs, a); - } else { - if (!a) a = a_add(&u->attribs, a_new(&at_guard)); - a->data.i = (int)flags; - } -} - -unsigned int -getguard(const unit * u) -{ - attrib * a; - - assert((u->building && fval(u, UFL_OWNER)) || fval(u, UFL_GUARD) || !"you're doing it wrong! check is_guard first"); - a = a_find(u->attribs, &at_guard); - if (a) { - return (unsigned int)a->data.i; - } - return guard_flags(u); -} - -#ifndef HAVE_STRDUP -char * -strdup(const char *s) -{ - return strcpy((char*)malloc(sizeof(char)*(strlen(s)+1)), s); -} -#endif - -void -remove_empty_factions(void) -{ - faction **fp, *f3; - - for (fp = &factions; *fp;) { - faction * f = *fp; - /* monster (0) werden nicht entfernt. alive kann beim readgame - * () auf 0 gesetzt werden, wenn monsters keine einheiten mehr - * haben. */ - if ((f->units==NULL || f->alive == 0) && !is_monsters(f)) { - ursprung * ur = f->ursprung; - while (ur && ur->id!=0) ur=ur->next; - if (verbosity>=2) log_stdio(stdout, "\t%s\n", factionname(f)); - - /* Einfach in eine Datei schreiben und später vermailen */ - - if (updatelog) fprintf(updatelog, "dropout %s\n", itoa36(f->no)); - - for (f3 = factions; f3; f3 = f3->next) { - ally * sf; - group * g; - ally ** sfp = &f3->allies; - while (*sfp) { - sf = *sfp; - if (sf->faction == f || sf->faction == NULL) { - *sfp = sf->next; - free(sf); - } - else sfp = &(*sfp)->next; - } - for (g = f3->groups; g; g=g->next) { - sfp = &g->allies; - while (*sfp) { - sf = *sfp; - if (sf->faction == f || sf->faction == NULL) { - *sfp = sf->next; - free(sf); - } - else sfp = &(*sfp)->next; - } - } - } - if (f->subscription) { - sql_print(("UPDATE subscriptions set status='DEAD' where id=%u;\n", - f->subscription)); - } - - *fp = f->next; - funhash(f); - free_faction(f); - free(f); - } - else fp = &(*fp)->next; - } -} - -void -remove_empty_units_in_region(region *r) -{ - unit **up = &r->units; - - while (*up) { - unit * u = *up; - - if (u->number) { - faction * f = u->faction; - if (f==NULL || !f->alive) { - set_number(u, 0); - } - if (MaxAge()>0) { - if ((!fval(f, FFL_NOTIMEOUT) && f->age > MaxAge())) { - set_number(u, 0); - } - } - } - if ((u->number == 0 && u->race != new_race[RC_SPELL]) || (u->age <= 0 && u->race == new_race[RC_SPELL])) { - remove_unit(up, u); - } - if (*up==u) up=&u->next; - } -} - -void -remove_empty_units(void) -{ - region *r; - - for (r = regions; r; r = r->next) { - remove_empty_units_in_region(r); - } -} - -boolean -faction_id_is_unused(int id) -{ - return findfaction(id)==NULL; -} - -int -weight(const unit * u) -{ - int w, n = 0, in_bag = 0; - - item * itm; - for (itm=u->items;itm;itm=itm->next) { - w = itm->type->weight * itm->number; - n += w; - if( !fval(itm->type, ITF_BIG)) - in_bag += w; - } - - n += u->number * u->race->weight; - - w = get_item(u, I_BAG_OF_HOLDING) * BAGCAPACITY; - if( w > in_bag ) - w = in_bag; - n -= w; - - return n; -} - -void -make_undead_unit(unit * u) -{ - free_orders(&u->orders); - name_unit(u); - fset(u, UFL_ISNEW); -} - -unsigned int guard_flags(const unit * u) -{ - unsigned int flags = GUARD_CREWS | GUARD_LANDING | GUARD_TRAVELTHRU | GUARD_TAX; -#if GUARD_DISABLES_PRODUCTION == 1 - flags |= GUARD_PRODUCE; -#endif -#if GUARD_DISABLES_RECRUIT == 1 - flags |= GUARD_RECRUIT; -#endif - switch (old_race(u->race)) { - case RC_ELF: - if (u->faction->race != u->race) break; - /* else fallthrough */ - case RC_TREEMAN: - flags |= GUARD_TREES; - break; - case RC_IRONKEEPER: - flags = GUARD_MINING; - break; - } - return flags; -} - -void -guard(unit * u, unsigned int mask) -{ - unsigned int flags = guard_flags(u); - setguard(u, flags & mask); -} - -int -besieged(const unit * u) -{ - /* belagert kann man in schiffen und burgen werden */ - return (u && !global.disabled[K_BESIEGE] - && u->building && u->building->besieged - && u->building->besieged >= u->building->size * SIEGEFACTOR); -} - -int -lifestyle(const unit * u) -{ - int need; - plane * pl; - static int gamecookie = -1; - if (gamecookie!=global.cookie) { - gamecookie = global.cookie; - } - - if (is_monsters(u->faction)) return 0; - - need = maintenance_cost(u); - - pl = rplane(u->region); - if (pl && fval(pl, PFL_NOFEED)) - return 0; - - return need; -} - -boolean has_horses(const struct unit * u) -{ - item * itm = u->items; - for (;itm;itm=itm->next) { - if (itm->type->flags&ITF_ANIMAL) return true; - } - return false; -} - -boolean -hunger(int number, unit * u) -{ - region * r = u->region; - int dead = 0, hpsub = 0; - int hp = u->hp / u->number; - static const char * damage = 0; - static const char * rcdamage = 0; - static const race * rc = 0; - - if (!damage) { - damage = get_param(global.parameters, "hunger.damage"); - if (damage==NULL) damage = "1d12+12"; - } - if (rc!=u->race) { - rcdamage = get_param(u->race->parameters, "hunger.damage"); - rc = u->race; - } - - while (number--) { - int dam = dice_rand(rcdamage?rcdamage:damage); - if (dam >= hp) { - ++dead; - } else { - hpsub += dam; - } - } - - if (dead) { - /* Gestorbene aus der Einheit nehmen, - * Sie bekommen keine Beerdingung. */ - ADDMSG(&u->faction->msgs, msg_message("starvation", - "unit region dead live", u, r, dead, u->number-dead)); - - scale_number(u, u->number - dead); - deathcounts(r, dead); - } - if (hpsub > 0) { - /* Jetzt die Schäden der nicht gestorbenen abziehen. */ - u->hp -= hpsub; - /* Meldung nur, wenn noch keine für Tote generiert. */ - if (dead == 0) { - /* Durch unzureichende Ernährung wird %s geschwächt */ - ADDMSG(&u->faction->msgs, msg_message("malnourish", - "unit region", u, r)); - } - } - return (dead || hpsub); -} - -void -plagues(region * r, boolean ismagic) -{ - int peasants; - int i; - int dead = 0; - - /* Seuchenwahrscheinlichkeit in % */ - - if (!ismagic) { - double mwp = MAX(maxworkingpeasants(r), 1); - double prob = pow(rpeasants(r) / (mwp * wage(r, NULL, NULL, turn) * 0.13), 4.0) - * PLAGUE_CHANCE; - - if (rng_double() >= prob) return; - } - - peasants = rpeasants(r); - dead = (int)(0.5F + PLAGUE_VICTIMS * peasants); - for (i = dead; i != 0; i--) { - if (rng_double() < PLAGUE_HEALCHANCE && rmoney(r) >= PLAGUE_HEALCOST) { - rsetmoney(r, rmoney(r) - PLAGUE_HEALCOST); - } else { - --dead; - } - } - - if (dead > 0) { - message * msg = add_message(&r->msgs, msg_message("pest", "dead", dead)); - msg_release(msg); - deathcounts(r, dead); - rsetpeasants(r, peasants - dead); - } -} - -/* Lohn bei den einzelnen Burgstufen für Normale Typen, Orks, Bauern, - * Modifikation für Städter. */ - -static const int wagetable[7][4] = { - {10, 10, 11, -7}, /* Baustelle */ - {10, 10, 11, -5}, /* Handelsposten */ - {11, 11, 12, -3}, /* Befestigung */ - {12, 11, 13, -1}, /* Turm */ - {13, 12, 14, 0}, /* Burg */ - {14, 12, 15, 1}, /* Festung */ - {15, 13, 16, 2} /* Zitadelle */ -}; - -int -cmp_wage(const struct building * b, const building * a) -{ - static const struct building_type * bt_castle; - if (!bt_castle) bt_castle = bt_find("castle"); - if (b->type==bt_castle) { - if (!a) return 1; - if (b->size>a->size) return 1; - if (b->size==a->size) return 0; - } - return -1; -} - -boolean is_owner_building(const struct building * b) -{ - region * r = b->region; - if (b->type->taxes && r->land && r->land->ownership) { - unit * u = building_owner(b); - return u && u->faction == r->land->ownership->owner; - } - return false; -} - -int -cmp_taxes(const building * b, const building * a) -{ - faction * f = region_get_owner(b->region); - if (b->type->taxes) { - unit * u = building_owner(b); - if (!u) { - return -1; - } else if (a) { - int newsize = buildingeffsize(b, false); - double newtaxes = b->type->taxes(b, newsize); - int oldsize = buildingeffsize(a, false); - double oldtaxes = a->type->taxes(a, oldsize); - - if (newtaxesoldtaxes) return 1; - else if (b->sizesize) return -1; - else if (b->size>a->size) return 1; - else { - if (u && u->faction==f) { - u = building_owner(a); - if (u && u->faction==f) return -1; - return 1; - } - } - } else { - return 1; - } - } - return -1; -} - -int -cmp_current_owner(const building * b, const building * a) -{ - faction * f = region_get_owner(b->region); - - assert(rule_region_owners()); - if (f && b->type->taxes) { - unit * u = building_owner(b); - if (!u || u->faction!=f) return -1; - if (a) { - int newsize = buildingeffsize(b, false); - double newtaxes = b->type->taxes(b, newsize); - int oldsize = buildingeffsize(a, false); - double oldtaxes = a->type->taxes(a, oldsize); - - if (newtaxes!=oldtaxes) return (newtaxes>oldtaxes)?1:-1; - if (newsize!=oldsize) return newsize-oldsize; - return (b->size-a->size); - } else { - return 1; - } - } - return -1; -} - -int rule_stealth_faction(void) -{ - static int gamecookie = -1; - static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { - rule = get_param_int(global.parameters, "rules.stealth.faction", 1); - gamecookie = global.cookie; - assert(rule>=0); - } - return rule; -} - -int rule_region_owners(void) -{ - static int gamecookie = -1; - static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { - rule = get_param_int(global.parameters, "rules.region_owners", 0); - gamecookie = global.cookie; - assert(rule>=0); - } - return rule; -} - -int rule_auto_taxation(void) -{ - static int gamecookie = -1; - static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { - rule = get_param_int(global.parameters, "rules.economy.taxation", TAX_ORDER); - gamecookie = global.cookie; - assert(rule>=0); - } - return rule; -} - -int rule_blessed_harvest(void) -{ - static int gamecookie = -1; - static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { - rule = get_param_int(global.parameters, "rules.magic.blessed_harvest", HARVEST_WORK); - gamecookie = global.cookie; - assert(rule>=0); - } - return rule; -} - -int rule_alliance_limit(void) -{ - static int gamecookie = -1; - static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { - rule = get_param_int(global.parameters, "rules.limit.alliance", 0); - gamecookie = global.cookie; - assert(rule>=0); - } - return rule; -} - -int rule_faction_limit(void) -{ - static int gamecookie = -1; - static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { - rule = get_param_int(global.parameters, "rules.limit.faction", 0); - gamecookie = global.cookie; - assert(rule>=0); - } - return rule; -} - -int rule_transfermen(void) -{ - static int gamecookie = -1; - static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { - rule = get_param_int(global.parameters, "rules.transfermen", 1); - gamecookie = global.cookie; - assert(rule>=0); - } - return rule; -} - -static int -default_wage(const region *r, const faction * f, const race * rc, int in_turn) -{ - building *b = largestbuilding(r, &cmp_wage, false); - int esize = 0; - curse * c; - double wage; - attrib *a; - const building_type *artsculpture_type = bt_find("artsculpture"); - static const curse_type * drought_ct, * blessedharvest_ct; - static boolean init; - - if (!init) { - init = true; - drought_ct = ct_find("drought"); - blessedharvest_ct = ct_find("blessedharvest"); - } - - if (b!=NULL) { - /* TODO: this reveals imaginary castles */ - esize = buildingeffsize(b, false); - } - - if (f!=NULL) { - int index = 0; - if (rc==new_race[RC_ORC] || rc==new_race[RC_SNOTLING]) { - index = 1; - } - wage = wagetable[esize][index]; - } else { - if (is_mourning(r, in_turn)) { - wage = 10; - } else if (fval(r->terrain, SEA_REGION)) { - wage = 11; - } else if (fval(r, RF_ORCIFIED)) { - wage = wagetable[esize][1]; - } else { - wage = wagetable[esize][2]; - } - if (rule_blessed_harvest()==HARVEST_WORK) { - /* E1 rules */ - wage += curse_geteffect(get_curse(r->attribs, blessedharvest_ct)); - } - } - - /* Artsculpture: Income +5 */ - for(b=r->buildings; b; b=b->next) { - if(b->type == artsculpture_type) { - wage += 5; - } - } - - /* Godcurse: Income -10 */ - if (curse_active(get_curse(r->attribs, ct_find("godcursezone")))) { - wage = MAX(0,wage-10); - } - - /* Bei einer Dürre verdient man nur noch ein Viertel */ - if (drought_ct) { - c = get_curse(r->attribs, drought_ct); - if (curse_active(c)) wage /= curse_geteffect(c); - } - - a = a_find(r->attribs, &at_reduceproduction); - if (a) wage = (wage * a->data.sa[0])/100; - - return (int)wage; -} - -static int -minimum_wage(const region *r, const faction * f, const race * rc, int in_turn) -{ - if (f && rc) { - return rc->maintenance; - } - return default_wage(r, f, rc, in_turn); -} - -/* Gibt Arbeitslohn für entsprechende Rasse zurück, oder für -* die Bauern wenn f == NULL. */ -int -wage(const region *r, const faction * f, const race * rc, int in_turn) -{ - if (global.functions.wage) { - return global.functions.wage(r, f, rc, in_turn); - } - return default_wage(r, f, rc, in_turn); -} - - -#define MAINTENANCE 10 -int -maintenance_cost(const struct unit * u) -{ - if (u==NULL) return MAINTENANCE; - if (global.functions.maintenance) { - int retval = global.functions.maintenance(u); - if (retval>=0) return retval; - } - return u->race->maintenance * u->number; -} - -message * -movement_error(unit * u, const char * token, order * ord, int error_code) -{ - direction_t d; - switch (error_code) { - case E_MOVE_BLOCKED: - d = finddirection(token, u->faction->locale); - return msg_message("moveblocked", "unit direction", u, d); - case E_MOVE_NOREGION: - return msg_feedback(u, ord, "unknowndirection", "dirname", token); - } - return NULL; -} - -int -movewhere(const unit *u, const char * token, region * r, region** resultp) -{ - region * r2; - direction_t d; - - if (*token == '\0') { - *resultp = NULL; - return E_MOVE_OK; - } - - d = finddirection(token, u->faction->locale); - switch (d) { - case D_PAUSE: - *resultp = r; - break; - - case NODIRECTION: - r2 = find_special_direction(r, token, u->faction->locale); - if (r2==NULL) { - return E_MOVE_NOREGION; - } - *resultp = r2; - break; - - default: - r2 = rconnect(r, d); - if (r2==NULL || move_blocked(u, r, r2)) { - return E_MOVE_BLOCKED; - } - *resultp = r2; - } - return E_MOVE_OK; -} - -boolean -move_blocked(const unit * u, const region *r, const region *r2) -{ - connection * b; - curse * c; - static const curse_type * fogtrap_ct = NULL; - - if (r2==NULL) return true; - b = get_borders(r, r2); - while (b) { - if (b->type->block && b->type->block(b, u, r)) return true; - b = b->next; - } - - if (fogtrap_ct==NULL) fogtrap_ct = ct_find("fogtrap"); - c = get_curse(r->attribs, fogtrap_ct); - if (curse_active(c)) return true; - return false; -} - -void -add_income(unit * u, int type, int want, int qty) -{ - if (want==INT_MAX) want = qty; - ADDMSG(&u->faction->msgs, msg_message("income", "unit region mode wanted amount", - u, u->region, type, want, qty)); -} - -void -reorder_units(region * r) -{ - unit ** unext = &r->units; - - if (r->buildings) { - building * b = r->buildings; - while (*unext && b) { - unit ** ufirst = unext; /* where the first unit in the building should go */ - unit ** umove = unext; /* a unit we consider moving */ - unit * owner = NULL; - while (*umove) { - unit * u = *umove; - if (u->number && u->building==b) { - unit ** uinsert = unext; - if (fval(u, UFL_OWNER)) { - uinsert = ufirst; - owner = u; - } - if (umove!=uinsert) { - *umove = u->next; - u->next = *uinsert; - *uinsert = u; - } else { - /* no need to move, skip ahead */ - umove = &u->next; - } - if (unext==uinsert) { - /* we have a new well-placed unit. jump over it */ - unext = &u->next; - } - } else { - umove = &u->next; - } - } - if (!owner && ufirst!=unext) { - owner = *ufirst; - fset(owner, UFL_OWNER); - } - b = b->next; - } - } - - if (r->ships) { - ship * sh = r->ships; - /* first, move all units up that are not on ships */ - unit ** umove = unext; /* a unit we consider moving */ - while (*umove) { - unit * u = *umove; - if (u->number && !u->ship) { - if (umove!=unext) { - *umove = u->next; - u->next = *unext; - *unext = u; - } else { - /* no need to move, skip ahead */ - umove = &u->next; - } - /* we have a new well-placed unit. jump over it */ - unext = &u->next; - } else { - umove = &u->next; - } - } - - while (*unext && sh) { - unit ** ufirst = unext; /* where the first unit in the building should go */ - unit ** umove = unext; /* a unit we consider moving */ - unit * owner = NULL; - while (*umove) { - unit * u = *umove; - if (u->number && u->ship==sh) { - unit ** uinsert = unext; - if (fval(u, UFL_OWNER)) { - uinsert = ufirst; - owner = u; - } - if (umove!=uinsert) { - *umove = u->next; - u->next = *uinsert; - *uinsert = u; - } else { - /* no need to move, skip ahead */ - umove = &u->next; - } - if (unext==uinsert) { - /* we have a new well-placed unit. jump over it */ - unext = &u->next; - } - } else { - umove = &u->next; - } - } - if (!owner && ufirst!=unext) { - owner = *ufirst; - fset(owner, UFL_OWNER); - } - sh = sh->next; - } - } -} - -int -produceexp(struct unit * u, skill_t sk, int n) -{ - if (global.producexpchance>0.0F) { - if (n==0 || !playerrace(u->race)) return 0; - learn_skill(u, sk, global.producexpchance); - } - return 0; -} - -int -lovar(double xpct_x2) -{ - int n = (int)(xpct_x2 * 500)+1; - if (n==0) return 0; - return (rng_int() % n + rng_int() % n)/1000; -} - -boolean -has_limited_skills (const struct unit * u) -{ - if (has_skill(u, SK_MAGIC) || has_skill(u, SK_ALCHEMY) || - has_skill(u, SK_TACTICS) || has_skill(u, SK_HERBALISM) || - has_skill(u, SK_SPY)) { - return true; - } else { - return false; - } -} - -void -attrib_init(void) -{ - /* Alle speicherbaren Attribute müssen hier registriert werden */ - at_register(&at_shiptrail); - at_register(&at_familiar); - at_register(&at_familiarmage); - at_register(&at_clone); - at_register(&at_clonemage); - at_register(&at_eventhandler); - at_register(&at_stealth); - at_register(&at_mage); - at_register(&at_countdown); - at_register(&at_curse); - - at_register(&at_seenspell); - - /* neue REGION-Attribute */ - at_register(&at_direction); - at_register(&at_moveblock); - at_register(&at_deathcount); - at_register(&at_chaoscount); - at_register(&at_woodcount); - - /* neue UNIT-Attribute */ - at_register(&at_siege); - at_register(&at_effect); - at_register(&at_private); - - at_register(&at_icastle); - at_register(&at_guard); - at_register(&at_group); - - at_register(&at_building_generic_type); - at_register(&at_maxmagicians); - at_register(&at_npcfaction); - - /* connection-typen */ - register_bordertype(&bt_noway); - register_bordertype(&bt_fogwall); - register_bordertype(&bt_wall); - register_bordertype(&bt_illusionwall); - register_bordertype(&bt_road); - register_bordertype(&bt_questportal); - - register_function((pf_generic)&minimum_wage, "minimum_wage"); - - at_register(&at_germs); -#if XECMD_MODULE - at_register(&at_xontormiaexpress); /* required for old datafiles */ -#endif - at_register(&at_speedup); - at_register(&at_building_action); -} - -void -kernel_init(void) -{ - char zBuffer[MAX_PATH]; - attrib_init(); - translation_init(); - - if (sqlpatch) { - sprintf(zBuffer, "%s/patch-%d.sql", datapath(), turn); - sql_init(zBuffer); - } -} - -order * -default_order(const struct locale * lang) -{ - return parse_order(locale_string(lang, "defaultorder"), lang); -} - -int -entertainmoney(const region *r) -{ - double n; - - if (is_cursed(r->attribs, C_DEPRESSION, 0)) { - return 0; - } - - n = rmoney(r) / ENTERTAINFRACTION; - - if (is_cursed(r->attribs, C_GENEROUS, 0)) { - n *= get_curseeffect(r->attribs, C_GENEROUS, 0); - } - - return (int)n; -} - -int rule_give(void) -{ - static int value = -1; - if (value<0) { - value = get_param_int(global.parameters, "rules.give", GIVE_DEFAULT); - } - return value; -} - -int markets_module(void) -{ - static int value = -1; - if (value<0) { - value = get_param_int(global.parameters, "modules.markets", 0); - } - return value; -} - -/** releases all memory associated with the game state. - * call this function before calling read_game() to load a new game - * if you have a previously loaded state in memory. - */ -void -free_gamedata(void) -{ - free_units(); - free_regions(); - free_borders(); - - while (alliances) { - alliance * al = alliances; - alliances = al->next; - free_alliance(al); - } - while (factions) { - faction * f = factions; - factions = f->next; - funhash(f); - free_faction(f); - free(f); - } - - while (planes) { - plane * pl = planes; - planes = planes->next; - free(pl->name); - free(pl); - } - - while (global.attribs) { - a_remove(&global.attribs, global.attribs); - } - ++global.cookie; /* readgame() already does this, but sjust in case */ -} - - -void -load_inifile(dictionary * d) -{ - const char * reportdir = reportpath(); - const char * datadir = datapath(); - const char * basedir = basepath(); - const char * str; - - assert(d); - - str = iniparser_getstring(d, "eressea:base", basedir); - if (str!=basedir) set_basepath(str); - str = iniparser_getstring(d, "eressea:report", reportdir); - if (str!=reportdir) set_reportpath(str); - str = iniparser_getstring(d, "eressea:data", datadir); - if (str!=datadir) set_datapath(str); - - lomem = iniparser_getint(d, "eressea:lomem", lomem)?1:0; - - str = iniparser_getstring(d, "eressea:encoding", NULL); - if (str) enc_gamedata = xmlParseCharEncoding(str); - - verbosity = iniparser_getint(d, "eressea:verbose", 2); - sqlpatch = iniparser_getint(d, "eressea:sqlpatch", false); - battledebug = iniparser_getint(d, "eressea:debug", battledebug)?1:0; - - str = iniparser_getstring(d, "eressea:locales", "de,en"); - make_locales(str); - - /* excerpt from [config] (the rest is used in bindings.c) */ - game_name = iniparser_getstring(d, "config:game", game_name); - - global.inifile = d; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include + +/* attributes includes */ +#include +#include + +/* kernel includes */ +#include "alliance.h" +#include "alchemy.h" +#include "battle.h" +#include "connection.h" +#include "building.h" +#include "calendar.h" +#include "curse.h" +#include "faction.h" +#include "group.h" +#include "item.h" +#include "magic.h" +#include "message.h" +#include "move.h" +#include "names.h" +#include "objtypes.h" +#include "order.h" +#include "plane.h" +#include "pool.h" +#include "race.h" +#include "region.h" +#include "save.h" +#include "ship.h" +#include "skill.h" +#include "terrain.h" +#include "unit.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define PTRIES 0 /* it turns out they are slow :-( */ +#if PTRIES +#include +#endif + +struct settings global = { + "Eressea", /* gamename */ +}; +FILE *logfile; +FILE *updatelog; +const struct race * new_race[MAXRACES]; +boolean sqlpatch = false; +boolean battledebug = false; +int turn = 0; + +#if XECMD_MODULE +attrib_type at_xontormiaexpress = { + "xontormiaexpress", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + a_writeint, + a_readint, + ATF_UNIQUE +}; +#endif + +int +NewbieImmunity(void) { + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "NewbieImmunity", 0); + } + return value; +} + +boolean +IsImmune(const faction * f) +{ + return !fval(f, FFL_NPC) && f->age < NewbieImmunity(); +} + +static int +MaxAge(void) { + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "MaxAge", 0); + } + return value; +} + +static int +ally_flag(const char * s, int help_mask) +{ + if ((help_mask&HELP_MONEY) && strcmp(s, "money")==0) return HELP_MONEY; + if ((help_mask&HELP_FIGHT) && strcmp(s, "fight")==0) return HELP_FIGHT; + if ((help_mask&HELP_GIVE) && strcmp(s, "give")==0) return HELP_GIVE; + if ((help_mask&HELP_GUARD) && strcmp(s, "guard")==0) return HELP_GUARD; + if ((help_mask&HELP_FSTEALTH) && strcmp(s, "stealth")==0) return HELP_FSTEALTH; + if ((help_mask&HELP_TRAVEL) && strcmp(s, "travel")==0) return HELP_TRAVEL; + return 0; +} + +boolean +ExpensiveMigrants(void) +{ + int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "study.expensivemigrants", 0); + } + return value; +} +/** Specifies automatic alliance modes. + * If this returns a value then the bits set are immutable between alliance + * partners (faction::alliance) and cannot be changed with the HELP command. + */ +int +AllianceAuto(void) +{ + static int value = -1; + if (value<0) { + const char * str = get_param(global.parameters, "alliance.auto"); + value = 0; + if (str!=NULL) { + char * sstr = strdup(str); + char * tok = strtok(sstr, " "); + while (tok) { + value |= ally_flag(tok, -1); + tok = strtok(NULL, " "); + } + free(sstr); + } + } + return value & HelpMask(); +} + +/** Limits the available help modes + * The bitfield returned by this function specifies the available help modes + * in this game (so you can, for example, disable HELP GIVE globally). + * Disabling a status will disable the command sequence entirely (order parsing + * uses this function). + */ +int +HelpMask(void) +{ + static int value = -1; + if (value<0) { + const char * str = get_param(global.parameters, "rules.help.mask"); + value = 0; + if (str!=NULL) { + char * sstr = strdup(str); + char * tok = strtok(sstr, " "); + while (tok) { + value |= ally_flag(tok, -1); + tok = strtok(NULL, " "); + } + free(sstr); + } else { + value = HELP_ALL; + } + } + return value; +} + +int +AllianceRestricted(void) +{ + static int value = -1; + if (value<0) { + const char * str = get_param(global.parameters, "alliance.restricted"); + value = 0; + if (str!=NULL) { + char * sstr = strdup(str); + char * tok = strtok(sstr, " "); + while (tok) { + value |= ally_flag(tok, -1); + tok = strtok(NULL, " "); + } + free(sstr); + } + value &= HelpMask(); + } + return value; +} + +int +LongHunger(const struct unit * u) { + static int value = -1; + if (u!=NULL) { + if (!fval(u, UFL_HUNGER)) return false; +#ifdef NEW_DAEMONHUNGER_RULE + if (u->race==new_race[RC_DAEMON]) return false; +#endif + } + if (value<0) { + value = get_param_int(global.parameters, "hunger.long", 0); + } + return value; +} + +int +SkillCap(skill_t sk) { + static int value = -1; + if (sk==SK_MAGIC) return 0; /* no caps on magic */ + if (value<0) { + value = get_param_int(global.parameters, "skill.maxlevel", 0); + } + return value; +} + +int +NMRTimeout(void) { + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "nmr.timeout", 0); + } + return value; +} + +race_t +old_race(const struct race * rc) +{ + race_t i; + for (i=0;i!=MAXRACES;++i) { + if (new_race[i]==rc) return i; + } + return NORACE; +} + +helpmode helpmodes[] = { + { "all", HELP_ALL }, + { "money", HELP_MONEY }, + { "fight", HELP_FIGHT }, + { "observe", HELP_OBSERVE }, + { "give", HELP_GIVE }, + { "guard", HELP_GUARD }, + { "stealth", HELP_FSTEALTH }, + { "travel", HELP_TRAVEL }, + { NULL, 0 } +}; + +const char *directions[MAXDIRECTIONS+2] = +{ + "northwest", + "northeast", + "east", + "southeast", + "southwest", + "west", + "", + "pause" +}; + +/** Returns the English name of the race, which is what the database uses. + */ +const char * +dbrace(const struct race * rc) +{ + static char zText[32]; + char * zPtr = zText; + + /* the english names are all in ASCII, so we don't need to worry about UTF8 */ + strcpy(zText, (const char*)LOC(find_locale("en"), rc_name(rc, 0))); + while (*zPtr) { + *zPtr = (char)(toupper(*zPtr)); + ++zPtr; + } + return zText; +} + +const char *parameters[MAXPARAMS] = +{ + "LOCALE", + "ALLES", + "JEDEM", + "BAUERN", + "BURG", + "EINHEIT", + "PRIVAT", + "HINTEN", + "KOMMANDO", + "KRAEUTER", + "NICHT", + "NAECHSTER", + "PARTEI", + "ERESSEA", + "PERSONEN", + "REGION", + "SCHIFF", + "SILBER", + "STRASSEN", + "TEMPORAERE", + "FLIEHE", + "GEBAEUDE", + "GIB", /* Für HELFE */ + "KAEMPFE", + "DURCHREISE", + "BEWACHE", + "ZAUBER", + "PAUSE", + "VORNE", + "AGGRESSIV", + "DEFENSIV", + "STUFE", + "HELFE", + "FREMDES", + "AURA", + "UM", + "BEISTAND", + "GNADE", + "HINTER", + "VOR", + "ANZAHL", + "GEGENSTAENDE", + "TRAENKE", + "GRUPPE", + "PARTEITARNUNG", + "BAEUME", + "XEPOTION", + "XEBALLOON", + "XELAEN", + "ALLIANZ" +}; + + +const char *keywords[MAXKEYWORDS] = +{ + "//", + "BANNER", + "ARBEITEN", + "ATTACKIEREN", + "BEKLAUEN", + "BELAGERE", + "BENENNEN", + "BENUTZEN", + "BESCHREIBEN", + "BETRETEN", + "BEWACHEN", + "BOTSCHAFT", + "ENDE", + "FAHREN", + "NUMMER", + "KRIEG", + "FRIEDEN", + "FOLGEN", + "FORSCHEN", + "GIB", + "HELFEN", + "KAEMPFEN", + "KAMPFZAUBER", + "KAUFEN", + "KONTAKTIEREN", + "LEHREN", + "LERNEN", + "LIEFERE", + "MACHEN", + "NACH", + "PASSWORT", + "REKRUTIEREN", + "RESERVIEREN", + "ROUTE", + "SABOTIEREN", + "OPTION", + "SPIONIEREN", + "STIRB", + "TARNEN", + "TRANSPORTIEREN", + "TREIBEN", + "UNTERHALTEN", + "VERKAUFEN", + "VERLASSEN", + "VERGESSEN", + "ZAUBERE", + "ZEIGEN", + "ZERSTOEREN", + "ZUECHTEN", + "DEFAULT", + "URSPRUNG", + "EMAIL", + "PIRATERIE", + "NEUSTART", + "GRUPPE", + "OPFERE", + "BETEN", + "SORTIEREN", + "JIHAD", + "GM", + "INFO", + "PRAEFIX", + "PFLANZEN", + "WERWESEN", + "XONTORMIA", + "ALLIANZ", + "BEANSPRUCHEN", + "PROMOTION", + "BEZAHLEN", +}; + +const char *report_options[MAX_MSG] = +{ + "Kampf", + "Ereignisse", + "Bewegung", + "Einkommen", + "Handel", + "Produktion", + "Orkvermehrung", + "Zauber", + "", + "" +}; + +const char *message_levels[ML_MAX] = +{ + "Wichtig", + "Debug", + "Fehler", + "Warnungen", + "Infos" +}; + +const char *options[MAXOPTIONS] = +{ + "AUSWERTUNG", + "COMPUTER", + "ZUGVORLAGE", + NULL, + "STATISTIK", + "DEBUG", + "ZIPPED", + "ZEITUNG", /* Option hat Sonderbehandlung! */ + NULL, + "ADRESSEN", + "BZIP2", + "PUNKTE", + "SHOWSKCHANGE", + "XML" +}; + +static int +allied_skillcount(const faction * f, skill_t sk) +{ + int num = 0; + alliance * a = f_get_alliance(f); + faction_list * members = a->members; + while (members!=NULL) { + num += count_skill(members->data, sk); + members=members->next; + } + return num; +} + +static int +allied_skilllimit(const faction * f, skill_t sk) +{ + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "alliance.skilllimit", 0); + } + return value; +} + +static void +init_maxmagicians(struct attrib *a) +{ + a->data.i = MAXMAGICIANS; +} + +static attrib_type at_maxmagicians = { + "maxmagicians", + init_maxmagicians, + NULL, + NULL, + a_writeint, + a_readint, + ATF_UNIQUE +}; + +static void +init_npcfaction(struct attrib *a) +{ + a->data.i = 1; +} + + +static attrib_type at_npcfaction = { + "npcfaction", + init_npcfaction, + NULL, + NULL, + a_writeint, + a_readint, + ATF_UNIQUE +}; + +int +max_magicians(const faction * f) +{ + int m = MAXMAGICIANS; + attrib * a; + + if ((a = a_find(f->attribs, &at_maxmagicians)) != NULL) { + m = a->data.i; + } + if (f->race == new_race[RC_ELF]) ++m; + return m; +} + +int +skill_limit(faction * f, skill_t sk) +{ + int m = INT_MAX; + int al = allied_skilllimit(f, sk); + if (al>0) { + if (sk!=SK_ALCHEMY && sk!=SK_MAGIC) return INT_MAX; + if (f_get_alliance(f)) { + int ac = listlen(f->alliance->members); /* number of factions */ + int fl = (al+ac-1)/ac; /* faction limit, rounded up */ + /* the faction limit may not be achievable because it would break the alliance-limit */ + int sc = al - allied_skillcount(f, sk); + if (sc<=0) return 0; + return fl; + } + } + switch (sk) { + case SK_MAGIC: + m = max_magicians(f); + break; + case SK_ALCHEMY: + m = MAXALCHEMISTS; + break; + } + return m; +} + +int +count_skill(faction * f, skill_t sk) +{ + int n = 0; + unit *u; + + for (u = f->units; u; u = u->nextF) { + if (has_skill(u, sk)) { + if (!is_familiar(u)) n += u->number; + } + } + return n; +} + +int verbosity = 0; + +FILE *debug; + +static int +ShipSpeedBonus(const unit * u) +{ + static int level = -1; + if (level==-1) { + level = get_param_int(global.parameters, "movement.shipspeed.skillbonus", 0); + } + if (level>0) { + ship * sh = u->ship; + int skl = effskill(u, SK_SAILING); + int minsk = (sh->type->cptskill+1)/2; + return (skl-minsk)/level; + } + return 0; +} + +int +shipspeed(const ship * sh, const unit * u) +{ + double k = sh->type->range; + static const curse_type * stormwind_ct, * nodrift_ct; + static boolean init; + attrib *a; + curse *c; + + if (!init) { + init = true; + stormwind_ct = ct_find("stormwind"); + nodrift_ct = ct_find("nodrift"); + } + + assert(u->ship==sh); + assert(sh->type->construction->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (sh->size!=sh->type->construction->maxsize) return 0; + + if( curse_active(get_curse(sh->attribs, stormwind_ct))) + k *= 2; + if( curse_active(get_curse(sh->attribs, nodrift_ct))) + k += 1; + + if (u->faction->race == u->race) { + /* race bonus for this faction? */ + if (fval(u->race, RCF_SHIPSPEED)) { + k += 1; + } + } + + k += ShipSpeedBonus(u); + + a = a_find(sh->attribs, &at_speedup); + while (a != NULL && a->type==&at_speedup) { + k += a->data.sa[0]; + a = a->next; + } + + c = get_curse(sh->attribs, ct_find("shipspeedup")); + while(c) { + k += curse_geteffect(c); + c = c->nexthash; + } + +#ifdef SHIPSPEED + k *= SHIPSPEED; +#endif + +#ifdef SHIPDAMAGE + if (sh->damage) k = (k * (sh->size * DAMAGE_SCALE - sh->damage) + sh->size * DAMAGE_SCALE- 1) / (sh->size*DAMAGE_SCALE); +#endif + + return (int)k; +} + +#define FMAXHASH 2039 +faction * factionhash[FMAXHASH]; + +void +fhash(faction * f) +{ + int index = f->no % FMAXHASH; + f->nexthash = factionhash[index]; + factionhash[index] = f; +} + +void +funhash(faction * f) +{ + int index = f->no % FMAXHASH; + faction ** fp = factionhash+index; + while (*fp && (*fp)!=f) fp = &(*fp)->nexthash; + *fp = f->nexthash; +} + +static faction * +ffindhash(int no) +{ + int index = no % FMAXHASH; + faction * f = factionhash[index]; + while (f && f->no!=no) f = f->nexthash; + return f; +} +/* ----------------------------------------------------------------------- */ + +void +verify_data(void) +{ +#ifndef NDEBUG + int lf = -1; + faction *f; + unit *u; + int mage, alchemist; + + if (verbosity>=1) puts(" - Überprüfe Daten auf Korrektheit..."); + + list_foreach(faction, factions, f) { + mage = 0; + alchemist = 0; + for (u=f->units;u;u=u->nextF) { + if (eff_skill(u, SK_MAGIC, u->region)) { + mage += u->number; + } + if (eff_skill(u, SK_ALCHEMY, u->region)) + alchemist += u->number; + if (u->number > UNIT_MAXSIZE) { + if (lf != f->no) { + lf = f->no; + log_stdio(stdout, "Partei %s:\n", factionid(f)); + } + log_warning(("Einheit %s hat %d Personen\n", unitid(u), u->number)); + } + } + if (f->no != 0 && ((mage > 3 && f->race != new_race[RC_ELF]) || mage > 4)) + log_error(("Partei %s hat %d Magier.\n", factionid(f), mage)); + if (alchemist > 3) + log_error(("Partei %s hat %d Alchemisten.\n", factionid(f), alchemist)); + } + list_next(f); +#endif +} + +int +distribute(int old, int new_value, int n) +{ + int i; + int t; + assert(new_value <= old); + + if (old == 0) + return 0; + + t = (n / old) * new_value; + for (i = (n % old); i; i--) + if (rng_int() % old < new_value) + t++; + + return t; +} + +int +change_hitpoints (unit * u, int value) +{ + int hp = u->hp; + + hp += value; + + /* Jede Person benötigt mindestens 1 HP */ + if (hp < u->number){ + if (hp < 0){ /* Einheit tot */ + hp = 0; + } + scale_number(u, hp); + } + u->hp = hp; + return hp; +} + +unsigned int +atoip(const char *s) +{ + int n; + + n = atoi (s); + + if (n < 0) + n = 0; + + return n; +} + +region * +findunitregion (const unit * su) +{ +#ifndef SLOW_REGION + return su->region; +#else + region *r; + const unit *u; + + for (r = regions; r; r = r->next) { + for (u = r->units; u; u = u->next) { + if (su == u) { + return r; + } + } + } + + /* This should never happen */ + assert (!"Die unit wurde nicht gefunden"); + + return (region *) NULL; +#endif +} + +int +effskill(const unit * u, skill_t sk) +{ + return eff_skill(u, sk, u->region); +} + +int +eff_stealth(const unit * u, const region * r) +{ + int e = 0; + + /* Auf Schiffen keine Tarnung! */ + if (!u->ship && skill_enabled[SK_STEALTH]) { + e = eff_skill (u, SK_STEALTH, r); + + if (fval(u, UFL_STEALTH)) { + int es = u_geteffstealth(u); + if (es >=0 && es < e) return es; + } + } + return e; +} + +boolean +unit_has_cursed_item(unit *u) +{ + item * itm = u->items; + while (itm) { + if (fval(itm->type, ITF_CURSED) && itm->number>0) return true; + itm=itm->next; + } + return false; +} + +static void +init_gms(void) +{ + faction * f; + + for (f=factions;f;f=f->next) { + const attrib * a = a_findc(f->attribs, &at_gm); + + if (a!=NULL) fset(f, FFL_GM); + } +} + +static int +autoalliance(const plane * pl, const faction * sf, const faction * f2) +{ + static boolean init = false; + if (!init) { + init_gms(); + init = true; + } + if (pl && (pl->flags & PFL_FRIENDLY)) return HELP_ALL; + /* if f2 is a gm in this plane, everyone has an auto-help to it */ + if (fval(f2, FFL_GM)) { + attrib * a = a_find(f2->attribs, &at_gm); + + while (a) { + const plane * p = (const plane*)a->data.v; + if (p==pl) return HELP_ALL; + a=a->next; + } + } + + if (f_get_alliance(sf)!=NULL && AllianceAuto()) { + if (sf->alliance==f2->alliance) return AllianceAuto(); + } + + return 0; +} + +static int +ally_mode(const ally * sf, int mode) +{ + if (sf==NULL) return 0; + return sf->status & mode; +} + +int +alliedgroup(const struct plane * pl, const struct faction * f, + const struct faction * f2, const struct ally * sf, int mode) +{ + while (sf && sf->faction!=f2) sf=sf->next; + if (sf==NULL) { + mode = mode & autoalliance(pl, f, f2); + } + mode = ally_mode(sf, mode) | (mode & autoalliance(pl, f, f2)); + if (AllianceRestricted()) { + if (a_findc(f->attribs, &at_npcfaction)) { + return mode; + } + if (a_findc(f2->attribs, &at_npcfaction)) { + return mode; + } + if (f->alliance!=f2->alliance) { + mode &= ~AllianceRestricted(); + } + } + return mode; +} + +int +alliedfaction(const struct plane * pl, const struct faction * f, + const struct faction * f2, int mode) +{ + return alliedgroup(pl, f, f2, f->allies, mode); +} + +/* Die Gruppe von Einheit u hat helfe zu f2 gesetzt. */ +int +alliedunit(const unit * u, const faction * f2, int mode) +{ + ally * sf; + int automode; + + assert(u->region); /* the unit should be in a region, but it's possible that u->number==0 (TEMP units) */ + if (u->faction == f2) return mode; + if (u->faction != NULL && f2!=NULL) { + plane * pl; + + if (mode&HELP_FIGHT) { + if ((u->flags&UFL_DEFENDER) || (u->faction->flags&FFL_DEFENDER)) { + faction * owner = region_get_owner(u->region); + /* helps the owner of the region */ + if (owner==f2) { + return HELP_FIGHT; + } + } + } + + pl = rplane(u->region); + automode = mode & autoalliance(pl, u->faction, f2); + + if (pl!=NULL && (pl->flags & PFL_NOALLIANCES)) + mode = (mode & automode) | (mode & HELP_GIVE); + + sf = u->faction->allies; + if (fval(u, UFL_GROUP)) { + const attrib * a = a_findc(u->attribs, &at_group); + if (a!=NULL) sf = ((group*)a->data.v)->allies; + } + return alliedgroup(pl, u->faction, f2, sf, mode); + } + return 0; +} + +boolean +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)) + return true; + return false; +} + +boolean +cansee(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 */ +{ + int stealth, rings; + unit *u2 = r->units; + static const item_type * itype_grail; + static boolean init; + + if (!init) { + init = true; + itype_grail = it_find("grail"); + } + + if (u->faction == f || omniscient(f)) { + return true; + } else if (fval(u->race, RCF_INVISIBLE)) { + return false; + } else if (u->number == 0) { + 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. */ + u = (unit *)a->data.v; + } else { + return false; + } + } + + if (leftship(u)) return true; + if (itype_grail!=NULL && i_get(u->items, itype_grail)) 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, GUARD_ALL)!=0 || usiege(u) || u->building || u->ship) { + return true; + } + + rings = invisible(u, NULL); + stealth = eff_stealth(u, r) - modifier; + + while (u2) { + if (ringsnumber || invisible(u, u2) < u->number) { + if (skill_enabled[SK_PERCEPTION]) { + int observation = eff_skill(u2, SK_PERCEPTION, r); + + if (observation >= stealth) { + return true; + } + } else { + return true; + } + } + + /* find next unit in our faction */ + do { + u2=u2->next; + } while (u2 && u2->faction != f); + } + return false; +} + +boolean +cansee_unit(const unit * u, const unit * target, int modifier) +/* target->region kann != u->region sein, wenn es um durchreisen geht */ +{ + if (fval(target->race, RCF_INVISIBLE) || target->number == 0) return false; + else if (target->faction == u->faction) return true; + else { + int n, rings, o; + + if (is_guard(target, GUARD_ALL)!=0 || usiege(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]) { + o = eff_skill(u, SK_PERCEPTION, target->region); + if (o >= n) { + return true; + } + } else { + return true; + } + } + return false; +} + +boolean +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 */ +{ + int n; + unit *u2; + + if (fval(u->race, RCF_INVISIBLE) || u->number == 0) return false; + else if (u->faction == f) return true; + else { + int rings; + + if (is_guard(u, GUARD_ALL)!=0 || usiege(u) || u->building || u->ship) { + return true; + } + + n = eff_stealth(u, r) - modifier; + rings = invisible(u, NULL); + if (rings==0 && n<=0) { + return true; + } + + for (u2 = r->units; u2; u2 = u2->next){ + if (u2->faction == f) { + int o; + + if (rings && invisible(u, u2) >= u->number) continue; + + o = eff_skill(u2, SK_PERCEPTION, r); + + if (o >= n) { + return true; + } + } + } + } + return false; +} + +#ifndef NDEBUG +const char * +strcheck (const char *s, size_t maxlen) +{ + static char buffer[16 * 1024]; + if (strlen(s) > maxlen) { + assert(maxlen < 16 * 1024); + log_warning(("[strcheck] String wurde auf %d Zeichen verkürzt:\n%s\n", + (int)maxlen, s)); + strlcpy(buffer, s, maxlen); + return buffer; + } + return s; +} +#endif + +static attrib_type at_lighthouse = { + "lighthouse" + /* Rest ist NULL; temporäres, nicht alterndes Attribut */ +}; + +/* update_lighthouse: call this function whenever the size of a lighthouse changes + * it adds temporary markers to the surrounding regions. + * The existence of markers says nothing about the quality of the observer in + * the lighthouse, for this may change more frequently. + */ +void +update_lighthouse(building * lh) +{ + static boolean init_lighthouse = false; + static const struct building_type * bt_lighthouse = 0; + + if (!init_lighthouse) { + bt_lighthouse = bt_find("lighthouse"); + if (bt_lighthouse==NULL) return; + init_lighthouse = true; + } + + if (lh->type==bt_lighthouse) { + region * r = lh->region; + int d = (int)log10(lh->size) + 1; + int x; + + if (lh->size>0) { + r->flags |= RF_LIGHTHOUSE; + } + + for (x=-d;x<=d;++x) { + int y; + for (y=-d;y<=d;++y) { + attrib * a; + region * r2; + int px = r->x+x, py = r->y+y; + pnormalize(&px, &py, rplane(r)); + r2 = findregion(px, py); + if (r2==NULL) continue; + if (!fval(r2->terrain, SEA_REGION)) continue; + if (distance(r, r2) > d) continue; + a = a_find(r2->attribs, &at_lighthouse); + while (a && a->type==&at_lighthouse) { + building * b = (building*)a->data.v; + if (b==lh) break; + a = a->next; + } + if (!a) { + a = a_add(&r2->attribs, a_new(&at_lighthouse)); + a->data.v = (void*)lh; + } + } + } + } +} + +int +count_all(const faction * f) +{ +#ifndef NDEBUG + int n = 0; + unit *u; + for (u=f->units;u;u=u->nextF) { + if (playerrace(u->race)) { + n += u->number; + assert(f==u->faction); + } + } + if (f->num_people != n) { + log_error(("# of people in %s is != num_people: %d should be %d.\n", + factionid(f), f->num_people, n)); + } +#endif + return f->num_people; +} + +int +count_migrants (const faction * f) +{ + unit *u = f->units; + int n = 0; + while (u) { + assert(u->faction == f); + if (u->race != f->race && u->race != new_race[RC_ILLUSION] && u->race != new_race[RC_SPELL] + && !!playerrace(u->race) && !(is_cursed(u->attribs, C_SLAVE, 0))) + { + n += u->number; + } + u = u->nextF; + } + return n; +} + +int +count_maxmigrants(const faction * f) +{ + static int migrants = -1; + + if (migrants<0) { + migrants = get_param_int(global.parameters, "rules.migrants", INT_MAX); + } + if (migrants==INT_MAX) { + int x = 0; + if (f->race == new_race[RC_HUMAN]) { + int nsize = count_all(f); + if (nsize>0) { + x = (int)(log10(nsize / 50.0) * 20); + if (x < 0) x = 0; + } + } + return x; + } + return migrants; +} + +void +init_tokens(const struct order * ord) +{ + char * cmd = getcommand(ord); + init_tokens_str(cmd, cmd); +} + +void +parse(keyword_t kword, int (*dofun)(unit *, struct order *), boolean thisorder) +{ + region *r; + + for (r = regions; r; r = r->next) { + unit **up = &r->units; + while (*up) { + unit * u = *up; + order ** ordp = &u->orders; + if (thisorder) ordp = &u->thisorder; + while (*ordp) { + order * ord = *ordp; + if (get_keyword(ord) == kword) { + if (dofun(u, ord)!=0) break; + if (u->orders==NULL) break; + } + if (thisorder) break; + if (*ordp==ord) ordp=&ord->next; + } + if (*up==u) up=&u->next; + } + } +} + +const char * +igetstrtoken(const char * initstr) +{ + if (initstr!=NULL) { + init_tokens_str(initstr, NULL); + } + + return getstrtoken(); +} + +unsigned int +getuint (void) +{ + return atoip((const char *)getstrtoken()); +} + +int +getint (void) +{ + return atoi((const char *)getstrtoken()); +} + +const struct race * +findrace(const char * s, const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_RACES); + variant token; + + assert(lang); + if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { + return (const struct race *)token.v; + } + return NULL; +} + +int +findoption(const char *s, const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_OPTIONS); + variant token; + + if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { + return (direction_t)token.i; + } + return NODIRECTION; +} + +#if PTRIES +static struct trie_node * ptries[UT_MAX][4]; + +static struct trie_node ** +get_ptrie(const struct locale * lang, int type) +{ + int index = (strcmp(locale_name(lang), "de")==0); + return &(ptries[type][index]); +} + +static int +umlaut_substitution(const char * ip, char * op, size_t outlen) +{ +#define UMAX 7 + static struct replace { + ucs4_t ucs; + const char str[3]; + } replace[UMAX] = { + /* match lower-case (!) umlauts and others to transcriptions */ + { 223, "ss"}, /* szlig */ + { 228, "ae"}, /* auml */ + { 229, "aa"}, /* norsk */ + { 230, "ae"}, /* norsk */ + { 246, "oe"}, /* ouml */ + { 248, "oe"}, /* norsk */ + { 252, "ue"}, /* uuml */ + }; + int subs = 0; + while (*ip) { + ucs4_t ucs = *ip; + size_t size = 1; + size_t cpsize = 1; + + if (ucs & 0x80) { + int ret = unicode_utf8_to_ucs4(&ucs, ip, &size); + if (ret!=0) { + return ret; + } + cpsize = size; + if (ucs >= replace[0].ucs && ucs <= replace[UMAX-1].ucs) { + int i; + for (i=0;i!=UMAX;++i) { + if (replace[i].ucs==ucs) { + cpsize = 0; + memcpy(op, replace[i].str, 2); + op+=2; + ++subs; + break; + } + } + } + } + if (cpsize) { + if (cpsize>outlen) { + return -1; + } + memcpy(op, ip, cpsize); + } + + ip += size; + op += cpsize; + outlen -= cpsize; + } + + if (outlen<=0) { + return -1; + } + *op = 0; + return subs; +} + +static int +ptrie_find(struct trie_node *ptrie, const char * key, void * data, size_t size) +{ + trie_node * node = trie_find_prefix(ptrie, key); + if (node) { + void * result = trie_getdata(node); + memcpy(data, result, size); + return 0; + } + return -1; +} + +static int +ptrie_insert(struct trie_node **ptrie, const char * name, void * data, size_t size) +{ + char converted[256]; + char simple[256]; + int ret = unicode_utf8_tolower(converted, 256, name); + if (ret==0) { + int subs = umlaut_substitution(converted, simple, sizeof(simple)); + if (subs>0) { + trie_insert(ptrie, simple, data, size); + } + trie_insert(ptrie, converted, data, size); + } + return ret; +} +#endif + +skill_t +findskill(const char *s, const struct locale * lang) +{ +#if PTRIES + char lowercase[256]; + int res = unicode_utf8_tolower(lowercase, sizeof(lowercase), s); + if (res==0) { + trie_node ** ptrie = get_ptrie(lang, UT_SKILLS); + skill_t sk; + int result = ptrie_find(*ptrie, lowercase, &sk, sizeof(sk)); + if (result==0) return sk; + } + return NOSKILL; +#else + struct tnode * tokens = get_translations(lang, UT_SKILLS); + variant token; + + if (findtoken(tokens, s, &token)==E_TOK_NOMATCH) return NOSKILL; + return (skill_t)token.i; +#endif +} + +keyword_t +findkeyword(const char *s, const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_KEYWORDS); + variant token; + + if (*s == '@') s++; + if (findtoken(tokens, s, &token)==E_TOK_NOMATCH) return NOKEYWORD; + if (global.disabled[token.i]) return NOKEYWORD; + return (keyword_t) token.i; +} + +param_t +findparam(const char *s, const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_PARAMS); + variant token; + + if (findtoken(tokens, s, &token)==E_TOK_NOMATCH) { + const building_type * btype = findbuildingtype(s, lang); + if (btype!=NULL) return (param_t) P_GEBAEUDE; + return NOPARAM; + } + if (token.i==P_BUILDING) return P_GEBAEUDE; + return (param_t)token.i; +} + +param_t +getparam (const struct locale * lang) +{ + return findparam (getstrtoken (), lang); +} + +faction * +findfaction (int n) +{ + faction * f = ffindhash(n); + return f; +} + +faction * +getfaction (void) +{ + return findfaction (getid()); +} + +unit * +findunitr (const region * r, int n) +{ + unit *u; + + /* findunit regional! */ + + for (u = r->units; u; u = u->next) + if (u->no == n) + return u; + + return 0; +} + +unit *findunit(int n) +{ + if (n <= 0) { + return NULL; + } + return ufindhash(n); +} + +unit * +findunitg (int n, const region * hint) +{ + + /* Abfangen von Syntaxfehlern. */ + if (n <= 0) + return NULL; + + /* findunit global! */ + hint = 0; + return ufindhash(n); +} + +unit * +getnewunit (const region * r, const faction * f) +{ + int n; + n = getid(); + + return findnewunit (r, f, n); +} + +static int +read_newunitid (const faction * f, const region * r) +{ + int n; + unit *u2; + n = getid(); + if (n == 0) + return -1; + + u2 = findnewunit(r, f, n); + if (u2) return u2->no; + + return -1; +} + +int +read_unitid (const faction * f, const region * r) +{ + const char * s = getstrtoken(); + + /* Da s nun nur einen string enthaelt, suchen wir ihn direkt in der + * paramliste. machen wir das nicht, dann wird getnewunit in s nach der + * nummer suchen, doch dort steht bei temp-units nur "temp" drinnen! */ + + switch (findparam(s, f->locale)) { + case P_TEMP: + return read_newunitid(f, r); + } + if (!s || *s == 0) + return -1; + return atoi36((const char *)s); +} + +/* exported symbol */ +boolean getunitpeasants; +unit * +getunitg(const region * r, const faction * f) +{ + int n = read_unitid(f, r); + + if (n == 0) { + getunitpeasants = 1; + return NULL; + } + getunitpeasants = 0; + if (n < 0) return 0; + + return findunit(n); +} + +unit * +getunit(const region * r, const faction * f) +{ + int n = read_unitid(f, r); + unit *u2; + + if (n == 0) { + getunitpeasants = 1; + return NULL; + } + getunitpeasants = 0; + if (n < 0) return 0; + + u2 = findunit(n); + if (u2!=NULL && u2->region==r) { + /* there used to be a 'u2->flags & UFL_ISNEW || u2->number>0' condition + * here, but it got removed because of a bug that made units disappear: + * http://eressea.upb.de/mantis/bug_view_page.php?bug_id=0000172 + */ + return u2; + } + + return NULL; +} + +/* - String Listen --------------------------------------------- */ +void +addstrlist (strlist ** SP, const char *s) +{ + strlist * slist = malloc(sizeof(strlist)); + slist->next = NULL; + slist->s = strdup(s); + addlist(SP, slist); +} + +void +freestrlist (strlist * s) +{ + strlist *q, *p = s; + while (p) { + q = p->next; + free(p->s); + free(p); + p = q; + } +} + +/* - Meldungen und Fehler ------------------------------------------------- */ + +boolean lomem = false; + +/* - Namen der Strukturen -------------------------------------- */ +typedef char name[OBJECTIDSIZE+1]; +static name idbuf[8]; +static int nextbuf = 0; + +char * +estring_i(char *ibuf) +{ + char *p = ibuf; + + while (*p) { + if (isxspace(*(unsigned*)p) == ' ') { + *p = '~'; + } + ++p; + } + return ibuf; +} + +char * +estring(const char *s) +{ + char *ibuf = idbuf[(++nextbuf) % 8]; + + strlcpy(ibuf, s, sizeof(name)); + return estring_i(ibuf); +} + +char * +cstring_i(char *ibuf) +{ + char *p = ibuf; + + while (*p) { + if (*p == '~') { + *p = ' '; + } + ++p; + } + return ibuf; +} + +char * +cstring(const char *s) +{ + char *ibuf = idbuf[(++nextbuf) % 8]; + + strlcpy(ibuf, s, sizeof(name)); + return cstring_i(ibuf); +} + +building * +largestbuilding(const region * r, cmp_building_cb cmp_gt, boolean imaginary) +{ + building *b, *best = NULL; + + for (b = rbuildings(r); b; b = b->next) { + if (cmp_gt(b, best)<=0) continue; + if (!imaginary) { + const attrib * a = a_find(b->attribs, &at_icastle); + if (a) continue; + } + best = b; + } + return best; +} + +char * +write_unitname(const unit * u, char * buffer, size_t size) +{ + snprintf((char*)buffer, size, "%s (%s)", (const char*)u->name, itoa36(u->no)); + buffer[size-1] = 0; + return buffer; +} + +const char * +unitname(const unit * u) +{ + char *ubuf = idbuf[(++nextbuf) % 8]; + return write_unitname(u, ubuf, sizeof(name)); +} + +/* -- Erschaffung neuer Einheiten ------------------------------ */ + +extern faction * dfindhash(int i); + +static const char* forbidden[] = { "t", "te", "tem", "temp", NULL }; + +int +forbiddenid(int id) +{ + static int * forbid = NULL; + static size_t len; + size_t i; + if (id<=0) return 1; + if (!forbid) { + while (forbidden[len]) ++len; + forbid = calloc(len, sizeof(int)); + for (i=0;i!=len;++i) { + forbid[i] = strtol(forbidden[i], NULL, 36); + } + } + for (i=0;i!=len;++i) if (id==forbid[i]) return 1; + return 0; +} + +/* ID's für Einheiten und Zauber */ +int +newunitid(void) +{ + int random_unit_no; + int start_random_no; + random_unit_no = 1 + (rng_int() % MAX_UNIT_NR); + start_random_no = random_unit_no; + + while (ufindhash(random_unit_no) || dfindhash(random_unit_no) + || cfindhash(random_unit_no) + || forbiddenid(random_unit_no)) + { + random_unit_no++; + if (random_unit_no == MAX_UNIT_NR + 1) { + random_unit_no = 1; + } + if (random_unit_no == start_random_no) { + random_unit_no = (int) MAX_UNIT_NR + 1; + } + } + return random_unit_no; +} + +int +newcontainerid(void) +{ + int random_no; + int start_random_no; + + random_no = 1 + (rng_int() % MAX_CONTAINER_NR); + start_random_no = random_no; + + while (findship(random_no) || findbuilding(random_no)) { + random_no++; + if (random_no == MAX_CONTAINER_NR + 1) { + random_no = 1; + } + if (random_no == start_random_no) { + random_no = (int) MAX_CONTAINER_NR + 1; + } + } + return random_no; +} + +unit * +createunit(region * r, faction * f, int number, const struct race * rc) +{ + assert(rc); + return create_unit(r, f, number, rc, 0, NULL, NULL); +} + +boolean +idle (faction * f) +{ + return (boolean) (f ? false : true); +} + + +int +maxworkingpeasants(const struct region * r) +{ + int i = production(r) * MAXPEASANTS_PER_AREA + - ((rtrees(r,2)+rtrees(r,1)/2) * TREESIZE); + return MAX(i, 0); +} + +int +lighthouse_range(const building * b, const faction * f) +{ + int d = 0; + if (fval(b, BLD_WORKING) && b->size >= 10) { + int maxd = (int)log10(b->size) + 1; + + if (skill_enabled[SK_PERCEPTION]) { + region * r = b->region; + int c = 0; + unit *u; + for (u = r->units; u; u = u->next) { + if (u->building == b) { + c += u->number; + if (c > buildingcapacity(b)) break; + if (f==NULL || u->faction == f) { + int sk = eff_skill(u, SK_PERCEPTION, r) / 3; + d = MAX(d, sk); + d = MIN(maxd, d); + if (d==maxd) break; + } + } else if (c) break; /* first unit that's no longer in the house ends the search */ + } + } else { + /* E3A rule: no perception req'd */ + return maxd; + } + } + return d; +} + +boolean +check_leuchtturm(region * r, faction * f) +{ + attrib * a; + + if (!fval(r->terrain, SEA_REGION)) return false; + + for (a = a_find(r->attribs, &at_lighthouse);a && a->type==&at_lighthouse;a=a->next) { + building *b = (building *)a->data.v; + + assert(b->type == bt_find("lighthouse")); + if (fval(b, BLD_WORKING) && b->size >= 10) { + int maxd = (int)log10(b->size) + 1; + + if (skill_enabled[SK_PERCEPTION]) { + region *r2 = b->region; + unit *u; + int c = 0; + int d = 0; + + for (u = r2->units; u; u = u->next) { + if (u->building == b) { + c += u->number; + if (c > buildingcapacity(b)) break; + if (f==NULL || u->faction == f) { + if (!d) d = distance(r, r2); + if (maxd < d) break; + if (eff_skill(u, SK_PERCEPTION, r) >= d * 3) return true; + } + } else if (c) break; /* first unit that's no longer in the house ends the search */ + } + } else { + /* E3A rule: no perception req'd */ + return maxd; + } + } + } + + return false; +} + +region * +lastregion (faction * f) +{ +#ifdef SMART_INTERVALS + unit * u = f->units; + region *r = f->last; + + if (u==NULL) return NULL; + if (r!=NULL) return r->next; + + /* it is safe to start in the region of the first unit. */ + f->last = u->region; + /* if regions have indices, we can skip ahead: */ + for (u=u->nextF; u!=NULL; u=u->nextF) { + r = u->region; + if (r->index > f->last->index) f->last = r; + } + + /* we continue from the best region and look for travelthru etc. */ + for (r = f->last->next; r; r = r->next) { + plane * p = rplane(r); + + /* search the region for travelthru-attributes: */ + if (fval(r, RF_TRAVELUNIT)) { + attrib * ru = a_find(r->attribs, &at_travelunit); + while (ru && ru->type==&at_travelunit) { + u = (unit*)ru->data.v; + if (u->faction == f) { + f->last = r; + break; + } + ru = ru->next; + } + } + if (f->last == r) continue; + if (check_leuchtturm(r, f)) + f->last = r; + if (p && is_watcher(p, f)) { + f->last = r; + } + } + return f->last->next; +#else + return NULL; +#endif +} + +region * +firstregion (faction * f) +{ +#ifdef SMART_INTERVALS + region *r = f->first; + + if (f->units==NULL) return NULL; + if (r!=NULL) return r; + + return f->first = regions; +#else + return regions; +#endif +} + +void ** blk_list[1024]; +int list_index; +int blk_index; + +static void +gc_done(void) +{ + int i, k; + for (i=0;i!=list_index;++i) + { + for (k=0;k!=1024;++k) free(blk_list[i][k]); + free(blk_list[i]); + } + for (k=0;k!=blk_index;++k) free(blk_list[list_index][k]); + free(blk_list[list_index]); + +} + +void * +gc_add(void * p) +{ + if (blk_index==0) { + blk_list[list_index] = (void**)malloc(1024 * sizeof(void*)); + } + blk_list[list_index][blk_index] = p; + blk_index = (blk_index+1) % 1024; + if (!blk_index) ++ list_index; + return p; +} + +static void +init_directions(tnode * root, const struct locale * lang) +{ + /* mit dieser routine kann man mehrere namen für eine direction geben, + * das ist für die hexes ideal. */ + const struct { + const char* name; + int direction; + } dirs [] = { + { "dir_ne", D_NORTHEAST}, + { "dir_nw", D_NORTHWEST}, + { "dir_se", D_SOUTHEAST}, + { "dir_sw", D_SOUTHWEST}, + { "dir_east", D_EAST}, + { "dir_west", D_WEST}, + { "northeast", D_NORTHEAST}, + { "northwest", D_NORTHWEST}, + { "southeast", D_SOUTHEAST}, + { "southwest", D_SOUTHWEST}, + { "east", D_EAST }, + { "west",D_WEST }, + { "PAUSE", D_PAUSE }, + { NULL, NODIRECTION} + }; + int i; + struct tnode * tokens = get_translations(lang, UT_DIRECTIONS); + + for (i=0; dirs[i].direction!=NODIRECTION;++i) { + variant token; + token.i = dirs[i].direction; + addtoken(tokens, LOC(lang, dirs[i].name), token); + } +} + +direction_t +finddirection(const char *s, const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_DIRECTIONS); + variant token; + + if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { + return (direction_t)token.i; + } + return NODIRECTION; +} + +static void +init_locale(const struct locale * lang) +{ + variant var; + int i; + const struct race * rc; + struct tnode * tokens; + const terrain_type * terrain; +#if PTRIES + trie_node ** ptrie; +#endif + + tokens = get_translations(lang, UT_MAGIC); + if (tokens) { + const char * str = get_param(global.parameters, "rules.magic.playerschools"); + char * sstr, * tok; + if (str==NULL) { + str = "gwyrrd illaun draig cerddor tybied"; + } + + sstr = strdup(str); + tok = strtok(sstr, " "); + while (tok) { + for (i=0;i!=MAXMAGIETYP;++i) { + if (strcmp(tok, magic_school[i])==0) break; + } + assert(i!=MAXMAGIETYP); + var.i = i; + addtoken(tokens, LOC(lang, mkname("school", tok)), var); + tok = strtok(NULL, " "); + } + free(sstr); + } + + tokens = get_translations(lang, UT_DIRECTIONS); + init_directions(tokens, lang); + + tokens = get_translations(lang, UT_RACES); + for (rc=races;rc;rc=rc->next) { + var.v = (void*)rc; + addtoken(tokens, LOC(lang, rc_name(rc, 1)), var); + addtoken(tokens, LOC(lang, rc_name(rc, 0)), var); + } + + tokens = get_translations(lang, UT_PARAMS); + for (i=0;i!=MAXPARAMS;++i) { + var.i = i; + addtoken(tokens, LOC(lang, parameters[i]), var); + } +#if PTRIES + ptrie = get_ptrie(lang, UT_SKILLS); + for (i=0;i!=MAXSKILLS;++i) { + skill_t sk = (skill_t)i; + const char * skname = skillname(sk, lang); + if (skname!=NULL) { + ptrie_insert(ptrie, skname, &sk, sizeof(sk)); + } + } +#else + tokens = get_translations(lang, UT_SKILLS); + for (i=0;i!=MAXSKILLS;++i) { + const char * skname = skillname((skill_t)i, lang); + if (skname!=NULL) { + var.i = i; + addtoken(tokens, skname, var); + } + } +#endif + + tokens = get_translations(lang, UT_KEYWORDS); + for (i=0;i!=MAXKEYWORDS;++i) { + var.i = i; + if (keywords[i]) addtoken(tokens, LOC(lang, keywords[i]), var); + } + + tokens = get_translations(lang, UT_OPTIONS); + for (i=0;i!=MAXOPTIONS;++i) { + var.i = i; + if (options[i]) addtoken(tokens, LOC(lang, options[i]), var); + } + + tokens = get_translations(lang, UT_TERRAINS); + for (terrain=terrains();terrain!=NULL;terrain=terrain->next) { + var.v = (void*)terrain; + addtoken(tokens, LOC(lang, terrain->_name), var); + } +} + +typedef struct param { + struct param * next; + char * name; + char * data; +} param; + +int +getid(void) +{ + const char * str = (const char *)getstrtoken(); + int i = atoi36(str); + if (i<0) { + return -1; + } + return i; +} + +const char * +get_param(const struct param * p, const char * key) +{ + while (p!=NULL) { + if (strcmp(p->name, key)==0) return p->data; + p = p->next; + } + return NULL; +} + +int +get_param_int(const struct param * p, const char * key, int def) +{ + while (p!=NULL) { + if (strcmp(p->name, key)==0) return atoi(p->data); + p = p->next; + } + return def; +} + +static const char * g_datadir; +const char * +datapath(void) +{ + static char zText[MAX_PATH]; + if (g_datadir) return g_datadir; + return strcat(strcpy(zText, basepath()), "/data"); +} + +void +set_datapath(const char * path) +{ + g_datadir = path; +} + + +static const char * g_reportdir; +const char * +reportpath(void) +{ + static char zText[MAX_PATH]; + if (g_reportdir) return g_reportdir; + return strcat(strcpy(zText, basepath()), "/reports"); +} + +void +set_reportpath(const char * path) +{ + g_reportdir = path; +} + +static const char * g_basedir; +const char * +basepath(void) +{ + if (g_basedir) return g_basedir; + return "."; +} + + +void +set_basepath(const char * path) +{ + g_basedir = path; +} + +float +get_param_flt(const struct param * p, const char * key, float def) +{ + while (p!=NULL) { + if (strcmp(p->name, key)==0) return (float)atof(p->data); + p = p->next; + } + return def; +} + +void +set_param(struct param ** p, const char * key, const char * data) +{ + ++global.cookie; + while (*p!=NULL) { + if (strcmp((*p)->name, key)==0) { + free((*p)->data); + (*p)->data = strdup(data); + return; + } + p=&(*p)->next; + } + *p = malloc(sizeof(param)); + (*p)->name = strdup(key); + (*p)->data = strdup(data); + (*p)->next = NULL; +} + +void +kernel_done(void) +{ + /* calling this function releases memory assigned to static variables, etc. + * calling it is optional, e.g. a release server will most likely not do it. + */ + translation_done(); + gc_done(); + sql_done(); +} + +const char * localenames[] = { + "de", "en", + NULL +}; + +void +init_locales(void) +{ + int l; + for (l=0;localenames[l];++l) { + const struct locale * lang = find_locale(localenames[l]); + if (lang) init_locale(lang); + } +} + +/* TODO: soll hier weg */ +extern struct attrib_type at_shiptrail; + +attrib_type at_germs = { + "germs", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + a_writeshorts, + a_readshorts, + ATF_UNIQUE +}; + +/*********************/ +/* at_guard */ +/*********************/ +attrib_type at_guard = { + "guard", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + a_writeint, + a_readint, + ATF_UNIQUE +}; + +void +setstatus(struct unit * u, int status) +{ + assert(status>=ST_AGGRO && status<=ST_FLEE); + if (u->status!=status) { + u->status = (status_t)status; + } +} + +void +setguard(unit * u, unsigned int flags) +{ + /* setzt die guard-flags der Einheit */ + attrib * a = NULL; + assert(flags==0 || !fval(u, UFL_MOVED)); + assert(flags==0 || u->statusattribs, &at_guard); + } + if (flags == GUARD_NONE) { + freset(u, UFL_GUARD); + if (a) a_remove(&u->attribs, a); + return; + } + fset(u, UFL_GUARD); + fset(u->region, RF_GUARDED); + if ((int)flags==guard_flags(u)) { + if (a) a_remove(&u->attribs, a); + } else { + if (!a) a = a_add(&u->attribs, a_new(&at_guard)); + a->data.i = (int)flags; + } +} + +unsigned int +getguard(const unit * u) +{ + attrib * a; + + assert((u->building && fval(u, UFL_OWNER)) || fval(u, UFL_GUARD) || !"you're doing it wrong! check is_guard first"); + a = a_find(u->attribs, &at_guard); + if (a) { + return (unsigned int)a->data.i; + } + return guard_flags(u); +} + +#ifndef HAVE_STRDUP +char * +strdup(const char *s) +{ + return strcpy((char*)malloc(sizeof(char)*(strlen(s)+1)), s); +} +#endif + +void +remove_empty_factions(void) +{ + faction **fp, *f3; + + for (fp = &factions; *fp;) { + faction * f = *fp; + /* monster (0) werden nicht entfernt. alive kann beim readgame + * () auf 0 gesetzt werden, wenn monsters keine einheiten mehr + * haben. */ + if ((f->units==NULL || f->alive == 0) && !is_monsters(f)) { + ursprung * ur = f->ursprung; + while (ur && ur->id!=0) ur=ur->next; + if (verbosity>=2) log_stdio(stdout, "\t%s\n", factionname(f)); + + /* Einfach in eine Datei schreiben und später vermailen */ + + if (updatelog) fprintf(updatelog, "dropout %s\n", itoa36(f->no)); + + for (f3 = factions; f3; f3 = f3->next) { + ally * sf; + group * g; + ally ** sfp = &f3->allies; + while (*sfp) { + sf = *sfp; + if (sf->faction == f || sf->faction == NULL) { + *sfp = sf->next; + free(sf); + } + else sfp = &(*sfp)->next; + } + for (g = f3->groups; g; g=g->next) { + sfp = &g->allies; + while (*sfp) { + sf = *sfp; + if (sf->faction == f || sf->faction == NULL) { + *sfp = sf->next; + free(sf); + } + else sfp = &(*sfp)->next; + } + } + } + if (f->subscription) { + sql_print(("UPDATE subscriptions set status='DEAD' where id=%u;\n", + f->subscription)); + } + + *fp = f->next; + funhash(f); + free_faction(f); + free(f); + } + else fp = &(*fp)->next; + } +} + +void +remove_empty_units_in_region(region *r) +{ + unit **up = &r->units; + + while (*up) { + unit * u = *up; + + if (u->number) { + faction * f = u->faction; + if (f==NULL || !f->alive) { + set_number(u, 0); + } + if (MaxAge()>0) { + if ((!fval(f, FFL_NOTIMEOUT) && f->age > MaxAge())) { + set_number(u, 0); + } + } + } + if ((u->number == 0 && u->race != new_race[RC_SPELL]) || (u->age <= 0 && u->race == new_race[RC_SPELL])) { + remove_unit(up, u); + } + if (*up==u) up=&u->next; + } +} + +void +remove_empty_units(void) +{ + region *r; + + for (r = regions; r; r = r->next) { + remove_empty_units_in_region(r); + } +} + +boolean +faction_id_is_unused(int id) +{ + return findfaction(id)==NULL; +} + +int +weight(const unit * u) +{ + int w, n = 0, in_bag = 0; + + item * itm; + for (itm=u->items;itm;itm=itm->next) { + w = itm->type->weight * itm->number; + n += w; + if( !fval(itm->type, ITF_BIG)) + in_bag += w; + } + + n += u->number * u->race->weight; + + w = get_item(u, I_BAG_OF_HOLDING) * BAGCAPACITY; + if( w > in_bag ) + w = in_bag; + n -= w; + + return n; +} + +void +make_undead_unit(unit * u) +{ + free_orders(&u->orders); + name_unit(u); + fset(u, UFL_ISNEW); +} + +unsigned int guard_flags(const unit * u) +{ + unsigned int flags = GUARD_CREWS | GUARD_LANDING | GUARD_TRAVELTHRU | GUARD_TAX; +#if GUARD_DISABLES_PRODUCTION == 1 + flags |= GUARD_PRODUCE; +#endif +#if GUARD_DISABLES_RECRUIT == 1 + flags |= GUARD_RECRUIT; +#endif + switch (old_race(u->race)) { + case RC_ELF: + if (u->faction->race != u->race) break; + /* else fallthrough */ + case RC_TREEMAN: + flags |= GUARD_TREES; + break; + case RC_IRONKEEPER: + flags = GUARD_MINING; + break; + } + return flags; +} + +void +guard(unit * u, unsigned int mask) +{ + unsigned int flags = guard_flags(u); + setguard(u, flags & mask); +} + +int +besieged(const unit * u) +{ + /* belagert kann man in schiffen und burgen werden */ + return (u && !global.disabled[K_BESIEGE] + && u->building && u->building->besieged + && u->building->besieged >= u->building->size * SIEGEFACTOR); +} + +int +lifestyle(const unit * u) +{ + int need; + plane * pl; + static int gamecookie = -1; + if (gamecookie!=global.cookie) { + gamecookie = global.cookie; + } + + if (is_monsters(u->faction)) return 0; + + need = maintenance_cost(u); + + pl = rplane(u->region); + if (pl && fval(pl, PFL_NOFEED)) + return 0; + + return need; +} + +boolean has_horses(const struct unit * u) +{ + item * itm = u->items; + for (;itm;itm=itm->next) { + if (itm->type->flags&ITF_ANIMAL) return true; + } + return false; +} + +boolean +hunger(int number, unit * u) +{ + region * r = u->region; + int dead = 0, hpsub = 0; + int hp = u->hp / u->number; + static const char * damage = 0; + static const char * rcdamage = 0; + static const race * rc = 0; + + if (!damage) { + damage = get_param(global.parameters, "hunger.damage"); + if (damage==NULL) damage = "1d12+12"; + } + if (rc!=u->race) { + rcdamage = get_param(u->race->parameters, "hunger.damage"); + rc = u->race; + } + + while (number--) { + int dam = dice_rand(rcdamage?rcdamage:damage); + if (dam >= hp) { + ++dead; + } else { + hpsub += dam; + } + } + + if (dead) { + /* Gestorbene aus der Einheit nehmen, + * Sie bekommen keine Beerdingung. */ + ADDMSG(&u->faction->msgs, msg_message("starvation", + "unit region dead live", u, r, dead, u->number-dead)); + + scale_number(u, u->number - dead); + deathcounts(r, dead); + } + if (hpsub > 0) { + /* Jetzt die Schäden der nicht gestorbenen abziehen. */ + u->hp -= hpsub; + /* Meldung nur, wenn noch keine für Tote generiert. */ + if (dead == 0) { + /* Durch unzureichende Ernährung wird %s geschwächt */ + ADDMSG(&u->faction->msgs, msg_message("malnourish", + "unit region", u, r)); + } + } + return (dead || hpsub); +} + +void +plagues(region * r, boolean ismagic) +{ + int peasants; + int i; + int dead = 0; + + /* Seuchenwahrscheinlichkeit in % */ + + if (!ismagic) { + double mwp = MAX(maxworkingpeasants(r), 1); + double prob = pow(rpeasants(r) / (mwp * wage(r, NULL, NULL, turn) * 0.13), 4.0) + * PLAGUE_CHANCE; + + if (rng_double() >= prob) return; + } + + peasants = rpeasants(r); + dead = (int)(0.5F + PLAGUE_VICTIMS * peasants); + for (i = dead; i != 0; i--) { + if (rng_double() < PLAGUE_HEALCHANCE && rmoney(r) >= PLAGUE_HEALCOST) { + rsetmoney(r, rmoney(r) - PLAGUE_HEALCOST); + } else { + --dead; + } + } + + if (dead > 0) { + message * msg = add_message(&r->msgs, msg_message("pest", "dead", dead)); + msg_release(msg); + deathcounts(r, dead); + rsetpeasants(r, peasants - dead); + } +} + +/* Lohn bei den einzelnen Burgstufen für Normale Typen, Orks, Bauern, + * Modifikation für Städter. */ + +static const int wagetable[7][4] = { + {10, 10, 11, -7}, /* Baustelle */ + {10, 10, 11, -5}, /* Handelsposten */ + {11, 11, 12, -3}, /* Befestigung */ + {12, 11, 13, -1}, /* Turm */ + {13, 12, 14, 0}, /* Burg */ + {14, 12, 15, 1}, /* Festung */ + {15, 13, 16, 2} /* Zitadelle */ +}; + +int +cmp_wage(const struct building * b, const building * a) +{ + static const struct building_type * bt_castle; + if (!bt_castle) bt_castle = bt_find("castle"); + if (b->type==bt_castle) { + if (!a) return 1; + if (b->size>a->size) return 1; + if (b->size==a->size) return 0; + } + return -1; +} + +boolean is_owner_building(const struct building * b) +{ + region * r = b->region; + if (b->type->taxes && r->land && r->land->ownership) { + unit * u = building_owner(b); + return u && u->faction == r->land->ownership->owner; + } + return false; +} + +int +cmp_taxes(const building * b, const building * a) +{ + faction * f = region_get_owner(b->region); + if (b->type->taxes) { + unit * u = building_owner(b); + if (!u) { + return -1; + } else if (a) { + int newsize = buildingeffsize(b, false); + double newtaxes = b->type->taxes(b, newsize); + int oldsize = buildingeffsize(a, false); + double oldtaxes = a->type->taxes(a, oldsize); + + if (newtaxesoldtaxes) return 1; + else if (b->sizesize) return -1; + else if (b->size>a->size) return 1; + else { + if (u && u->faction==f) { + u = building_owner(a); + if (u && u->faction==f) return -1; + return 1; + } + } + } else { + return 1; + } + } + return -1; +} + +int +cmp_current_owner(const building * b, const building * a) +{ + faction * f = region_get_owner(b->region); + + assert(rule_region_owners()); + if (f && b->type->taxes) { + unit * u = building_owner(b); + if (!u || u->faction!=f) return -1; + if (a) { + int newsize = buildingeffsize(b, false); + double newtaxes = b->type->taxes(b, newsize); + int oldsize = buildingeffsize(a, false); + double oldtaxes = a->type->taxes(a, oldsize); + + if (newtaxes!=oldtaxes) return (newtaxes>oldtaxes)?1:-1; + if (newsize!=oldsize) return newsize-oldsize; + return (b->size-a->size); + } else { + return 1; + } + } + return -1; +} + +int rule_stealth_faction(void) +{ + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + rule = get_param_int(global.parameters, "rules.stealth.faction", 1); + gamecookie = global.cookie; + assert(rule>=0); + } + return rule; +} + +int rule_region_owners(void) +{ + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + rule = get_param_int(global.parameters, "rules.region_owners", 0); + gamecookie = global.cookie; + assert(rule>=0); + } + return rule; +} + +int rule_auto_taxation(void) +{ + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + rule = get_param_int(global.parameters, "rules.economy.taxation", TAX_ORDER); + gamecookie = global.cookie; + assert(rule>=0); + } + return rule; +} + +int rule_blessed_harvest(void) +{ + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + rule = get_param_int(global.parameters, "rules.magic.blessed_harvest", HARVEST_WORK); + gamecookie = global.cookie; + assert(rule>=0); + } + return rule; +} + +int rule_alliance_limit(void) +{ + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + rule = get_param_int(global.parameters, "rules.limit.alliance", 0); + gamecookie = global.cookie; + assert(rule>=0); + } + return rule; +} + +int rule_faction_limit(void) +{ + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + rule = get_param_int(global.parameters, "rules.limit.faction", 0); + gamecookie = global.cookie; + assert(rule>=0); + } + return rule; +} + +int rule_transfermen(void) +{ + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + rule = get_param_int(global.parameters, "rules.transfermen", 1); + gamecookie = global.cookie; + assert(rule>=0); + } + return rule; +} + +static int +default_wage(const region *r, const faction * f, const race * rc, int in_turn) +{ + building *b = largestbuilding(r, &cmp_wage, false); + int esize = 0; + curse * c; + double wage; + attrib *a; + const building_type *artsculpture_type = bt_find("artsculpture"); + static const curse_type * drought_ct, * blessedharvest_ct; + static boolean init; + + if (!init) { + init = true; + drought_ct = ct_find("drought"); + blessedharvest_ct = ct_find("blessedharvest"); + } + + if (b!=NULL) { + /* TODO: this reveals imaginary castles */ + esize = buildingeffsize(b, false); + } + + if (f!=NULL) { + int index = 0; + if (rc==new_race[RC_ORC] || rc==new_race[RC_SNOTLING]) { + index = 1; + } + wage = wagetable[esize][index]; + } else { + if (is_mourning(r, in_turn)) { + wage = 10; + } else if (fval(r->terrain, SEA_REGION)) { + wage = 11; + } else if (fval(r, RF_ORCIFIED)) { + wage = wagetable[esize][1]; + } else { + wage = wagetable[esize][2]; + } + if (rule_blessed_harvest()==HARVEST_WORK) { + /* E1 rules */ + wage += curse_geteffect(get_curse(r->attribs, blessedharvest_ct)); + } + } + + /* Artsculpture: Income +5 */ + for(b=r->buildings; b; b=b->next) { + if(b->type == artsculpture_type) { + wage += 5; + } + } + + /* Godcurse: Income -10 */ + if (curse_active(get_curse(r->attribs, ct_find("godcursezone")))) { + wage = MAX(0,wage-10); + } + + /* Bei einer Dürre verdient man nur noch ein Viertel */ + if (drought_ct) { + c = get_curse(r->attribs, drought_ct); + if (curse_active(c)) wage /= curse_geteffect(c); + } + + a = a_find(r->attribs, &at_reduceproduction); + if (a) wage = (wage * a->data.sa[0])/100; + + return (int)wage; +} + +static int +minimum_wage(const region *r, const faction * f, const race * rc, int in_turn) +{ + if (f && rc) { + return rc->maintenance; + } + return default_wage(r, f, rc, in_turn); +} + +/* Gibt Arbeitslohn für entsprechende Rasse zurück, oder für +* die Bauern wenn f == NULL. */ +int +wage(const region *r, const faction * f, const race * rc, int in_turn) +{ + if (global.functions.wage) { + return global.functions.wage(r, f, rc, in_turn); + } + return default_wage(r, f, rc, in_turn); +} + + +#define MAINTENANCE 10 +int +maintenance_cost(const struct unit * u) +{ + if (u==NULL) return MAINTENANCE; + if (global.functions.maintenance) { + int retval = global.functions.maintenance(u); + if (retval>=0) return retval; + } + return u->race->maintenance * u->number; +} + +message * +movement_error(unit * u, const char * token, order * ord, int error_code) +{ + direction_t d; + switch (error_code) { + case E_MOVE_BLOCKED: + d = finddirection(token, u->faction->locale); + return msg_message("moveblocked", "unit direction", u, d); + case E_MOVE_NOREGION: + return msg_feedback(u, ord, "unknowndirection", "dirname", token); + } + return NULL; +} + +int +movewhere(const unit *u, const char * token, region * r, region** resultp) +{ + region * r2; + direction_t d; + + if (*token == '\0') { + *resultp = NULL; + return E_MOVE_OK; + } + + d = finddirection(token, u->faction->locale); + switch (d) { + case D_PAUSE: + *resultp = r; + break; + + case NODIRECTION: + r2 = find_special_direction(r, token, u->faction->locale); + if (r2==NULL) { + return E_MOVE_NOREGION; + } + *resultp = r2; + break; + + default: + r2 = rconnect(r, d); + if (r2==NULL || move_blocked(u, r, r2)) { + return E_MOVE_BLOCKED; + } + *resultp = r2; + } + return E_MOVE_OK; +} + +boolean +move_blocked(const unit * u, const region *r, const region *r2) +{ + connection * b; + curse * c; + static const curse_type * fogtrap_ct = NULL; + + if (r2==NULL) return true; + b = get_borders(r, r2); + while (b) { + if (b->type->block && b->type->block(b, u, r)) return true; + b = b->next; + } + + if (fogtrap_ct==NULL) fogtrap_ct = ct_find("fogtrap"); + c = get_curse(r->attribs, fogtrap_ct); + if (curse_active(c)) return true; + return false; +} + +void +add_income(unit * u, int type, int want, int qty) +{ + if (want==INT_MAX) want = qty; + ADDMSG(&u->faction->msgs, msg_message("income", "unit region mode wanted amount", + u, u->region, type, want, qty)); +} + +void +reorder_units(region * r) +{ + unit ** unext = &r->units; + + if (r->buildings) { + building * b = r->buildings; + while (*unext && b) { + unit ** ufirst = unext; /* where the first unit in the building should go */ + unit ** umove = unext; /* a unit we consider moving */ + unit * owner = NULL; + while (*umove) { + unit * u = *umove; + if (u->number && u->building==b) { + unit ** uinsert = unext; + if (fval(u, UFL_OWNER)) { + uinsert = ufirst; + owner = u; + } + if (umove!=uinsert) { + *umove = u->next; + u->next = *uinsert; + *uinsert = u; + } else { + /* no need to move, skip ahead */ + umove = &u->next; + } + if (unext==uinsert) { + /* we have a new well-placed unit. jump over it */ + unext = &u->next; + } + } else { + umove = &u->next; + } + } + if (!owner && ufirst!=unext) { + owner = *ufirst; + fset(owner, UFL_OWNER); + } + b = b->next; + } + } + + if (r->ships) { + ship * sh = r->ships; + /* first, move all units up that are not on ships */ + unit ** umove = unext; /* a unit we consider moving */ + while (*umove) { + unit * u = *umove; + if (u->number && !u->ship) { + if (umove!=unext) { + *umove = u->next; + u->next = *unext; + *unext = u; + } else { + /* no need to move, skip ahead */ + umove = &u->next; + } + /* we have a new well-placed unit. jump over it */ + unext = &u->next; + } else { + umove = &u->next; + } + } + + while (*unext && sh) { + unit ** ufirst = unext; /* where the first unit in the building should go */ + unit ** umove = unext; /* a unit we consider moving */ + unit * owner = NULL; + while (*umove) { + unit * u = *umove; + if (u->number && u->ship==sh) { + unit ** uinsert = unext; + if (fval(u, UFL_OWNER)) { + uinsert = ufirst; + owner = u; + } + if (umove!=uinsert) { + *umove = u->next; + u->next = *uinsert; + *uinsert = u; + } else { + /* no need to move, skip ahead */ + umove = &u->next; + } + if (unext==uinsert) { + /* we have a new well-placed unit. jump over it */ + unext = &u->next; + } + } else { + umove = &u->next; + } + } + if (!owner && ufirst!=unext) { + owner = *ufirst; + fset(owner, UFL_OWNER); + } + sh = sh->next; + } + } +} + +int +produceexp(struct unit * u, skill_t sk, int n) +{ + if (global.producexpchance>0.0F) { + if (n==0 || !playerrace(u->race)) return 0; + learn_skill(u, sk, global.producexpchance); + } + return 0; +} + +int +lovar(double xpct_x2) +{ + int n = (int)(xpct_x2 * 500)+1; + if (n==0) return 0; + return (rng_int() % n + rng_int() % n)/1000; +} + +boolean +has_limited_skills (const struct unit * u) +{ + if (has_skill(u, SK_MAGIC) || has_skill(u, SK_ALCHEMY) || + has_skill(u, SK_TACTICS) || has_skill(u, SK_HERBALISM) || + has_skill(u, SK_SPY)) { + return true; + } else { + return false; + } +} + +void +attrib_init(void) +{ + /* Alle speicherbaren Attribute müssen hier registriert werden */ + at_register(&at_shiptrail); + at_register(&at_familiar); + at_register(&at_familiarmage); + at_register(&at_clone); + at_register(&at_clonemage); + at_register(&at_eventhandler); + at_register(&at_stealth); + at_register(&at_mage); + at_register(&at_countdown); + at_register(&at_curse); + + at_register(&at_seenspell); + + /* neue REGION-Attribute */ + at_register(&at_direction); + at_register(&at_moveblock); + at_register(&at_deathcount); + at_register(&at_chaoscount); + at_register(&at_woodcount); + + /* neue UNIT-Attribute */ + at_register(&at_siege); + at_register(&at_effect); + at_register(&at_private); + + at_register(&at_icastle); + at_register(&at_guard); + at_register(&at_group); + + at_register(&at_building_generic_type); + at_register(&at_maxmagicians); + at_register(&at_npcfaction); + + /* connection-typen */ + register_bordertype(&bt_noway); + register_bordertype(&bt_fogwall); + register_bordertype(&bt_wall); + register_bordertype(&bt_illusionwall); + register_bordertype(&bt_road); + register_bordertype(&bt_questportal); + + register_function((pf_generic)&minimum_wage, "minimum_wage"); + + at_register(&at_germs); +#if XECMD_MODULE + at_register(&at_xontormiaexpress); /* required for old datafiles */ +#endif + at_register(&at_speedup); + at_register(&at_building_action); +} + +void +kernel_init(void) +{ + char zBuffer[MAX_PATH]; + attrib_init(); + translation_init(); + + if (sqlpatch) { + sprintf(zBuffer, "%s/patch-%d.sql", datapath(), turn); + sql_init(zBuffer); + } +} + +order * +default_order(const struct locale * lang) +{ + return parse_order(locale_string(lang, "defaultorder"), lang); +} + +int +entertainmoney(const region *r) +{ + double n; + + if (is_cursed(r->attribs, C_DEPRESSION, 0)) { + return 0; + } + + n = rmoney(r) / ENTERTAINFRACTION; + + if (is_cursed(r->attribs, C_GENEROUS, 0)) { + n *= get_curseeffect(r->attribs, C_GENEROUS, 0); + } + + return (int)n; +} + +int rule_give(void) +{ + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "rules.give", GIVE_DEFAULT); + } + return value; +} + +int markets_module(void) +{ + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "modules.markets", 0); + } + return value; +} + +/** releases all memory associated with the game state. + * call this function before calling read_game() to load a new game + * if you have a previously loaded state in memory. + */ +void +free_gamedata(void) +{ + free_units(); + free_regions(); + free_borders(); + + while (alliances) { + alliance * al = alliances; + alliances = al->next; + free_alliance(al); + } + while (factions) { + faction * f = factions; + factions = f->next; + funhash(f); + free_faction(f); + free(f); + } + + while (planes) { + plane * pl = planes; + planes = planes->next; + free(pl->name); + free(pl); + } + + while (global.attribs) { + a_remove(&global.attribs, global.attribs); + } + ++global.cookie; /* readgame() already does this, but sjust in case */ +} + + +void +load_inifile(dictionary * d) +{ + const char * reportdir = reportpath(); + const char * datadir = datapath(); + const char * basedir = basepath(); + const char * str; + + assert(d); + + str = iniparser_getstring(d, "eressea:base", basedir); + if (str!=basedir) set_basepath(str); + str = iniparser_getstring(d, "eressea:report", reportdir); + if (str!=reportdir) set_reportpath(str); + str = iniparser_getstring(d, "eressea:data", datadir); + if (str!=datadir) set_datapath(str); + + lomem = iniparser_getint(d, "eressea:lomem", lomem)?1:0; + + str = iniparser_getstring(d, "eressea:encoding", NULL); + if (str) enc_gamedata = get_encoding_by_name(str); + + verbosity = iniparser_getint(d, "eressea:verbose", 2); + sqlpatch = iniparser_getint(d, "eressea:sqlpatch", false); + battledebug = iniparser_getint(d, "eressea:debug", battledebug)?1:0; + + str = iniparser_getstring(d, "eressea:locales", "de,en"); + make_locales(str); + + /* excerpt from [config] (the rest is used in bindings.c) */ + game_name = iniparser_getstring(d, "config:game", game_name); + + global.inifile = d; +} diff --git a/src/kernel/config.h b/src/kernel/config.h index 22544a78b..89fb25f9a 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -1,460 +1,460 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef ERESSEA_H -#define ERESSEA_H - -#ifdef __cplusplus -extern "C" { -#endif - - /* this should always be the first thing included after platform.h */ -#include "types.h" - -struct _dictionary_; - - /* experimental gameplay features (that don't affect the savefile) */ - /* TODO: move these settings to settings.h or into configuration files */ -#define GOBLINKILL /* Goblin-Spezialklau kann tödlich enden */ -#define HERBS_ROT /* herbs owned by units have a chance to rot. */ -#define SHIPDAMAGE /* Schiffsbeschädigungen */ -#define INSECT_POTION /* Spezialtrank für Insekten */ -#define ORCIFICATION /* giving snotlings to the peasants gets counted */ -#undef TROLLSAVE /* saving throw for dead trolls */ - -#define ALLIED(f1, f2) (f1==f2 || (f1->alliance && f1->alliance==f2->alliance)) - -/* for some good prime numbers, check http://www.math.niu.edu/~rusin/known-math/98/pi_x */ -#ifndef MAXREGIONS -# define MAXREGIONS 524287 /* must be prime for hashing. 262139 was a little small */ -#endif -#ifndef MAXUNITS -# define MAXUNITS 1048573 /* must be prime for hashing. 524287 was >90% full */ -#endif - -#define MAXPEASANTS_PER_AREA 10 /* number of peasants per region-size */ -#define TREESIZE (MAXPEASANTS_PER_AREA-2) /* space used by trees (in #peasants) */ - -#define PEASANTFORCE 0.75 /* Chance einer Vermehrung trotz 90% Auslastung */ -#define HERBROTCHANCE 5 /* Verrottchance für Kräuter (ifdef HERBS_ROT) */ - -/* Gebäudegröße = Minimalbelagerer */ -#define SIEGEFACTOR 2 - -/** Magic */ -#define MAXMAGICIANS 3 -#define MAXALCHEMISTS 3 - -/** Plagues **/ -#define PLAGUE_CHANCE 0.1F /* Seuchenwahrscheinlichkeit (siehe plagues()) */ -#define PLAGUE_VICTIMS 0.2F /* % Betroffene */ -#define PLAGUE_HEALCHANCE 0.25F /* Wahrscheinlichkeit Heilung */ -#define PLAGUE_HEALCOST 30 /* Heilkosten */ - -/* Chance of a monster attack */ -#define MONSTERATTACK 0.4F - -/** Chance of an unmaintained building crashing */ -/* #define COLLAPSE_CHANCE 0.4F */ -#undef COLLAPSE_CHANCE -/** chance to survive the crash of a building */ -/* #define COLLAPSE_SURVIVAL 0.5F */ -#undef COLLAPSE_SURVIVAL - -/* 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 - -#define PERSON_WEIGHT 1000 /* weight of a "normal" human unit */ -#define STAMINA_AFFECTS_HP 1<<0 - -/** - * Hier endet der Teil von config.h, der die defines für die - * Spielwelt Eressea enthält, und beginnen die allgemeinen Routinen - */ - -#define ENCCHANCE 10 /* %-Chance für einmalige Zufallsbegegnung */ - -#define DISPLAYSIZE 8191 /* max. Länge einer Beschreibung, ohne trailing 0 */ -#define NAMESIZE 127 /* max. Länge eines Namens, ohne trailing 0 */ -#define IDSIZE 15 /* max. Länge einer no (als String), ohne trailing 0 */ -#define KEYWORDSIZE 15 /* max. Länge eines Keyword, ohne trailing 0 */ -#define OBJECTIDSIZE (NAMESIZE+5+IDSIZE) /* max. Länge der Strings, die - * von struct unitname, etc. zurückgegeben werden. ohne die 0 */ - -#define BAGCAPACITY 20000 /* soviel paßt in einen Bag of Holding */ -#define STRENGTHCAPACITY 50000 /* zusätzliche Tragkraft beim Kraftzauber (deprecated) */ -#define STRENGTHMULTIPLIER 50 /* multiplier for trollbelt */ - -/* ----------------- Befehle ----------------------------------- */ - -extern const char *keywords[MAXKEYWORDS]; -extern const char *parameters[MAXPARAMS]; - -/** report options **/ -#define want(option) (1<flags & (i)) -#define fset(u, i) ((u)->flags |= (i)) -#define freset(u, i) ((u)->flags &= ~(i)) - -extern int turn; -extern int verbosity; - -/* parteinummern */ -extern boolean faction_id_is_unused(int); - -/* leuchtturm */ -extern boolean check_leuchtturm(struct region * r, struct faction * f); -extern void update_lighthouse(struct building * lh); -extern int lighthouse_range(const struct building * b, const struct faction * f); - -/* skills */ -extern int skill_limit(struct faction * f, skill_t sk); -extern int count_skill(struct faction * f, skill_t sk); - -/* direction, geography */ -extern const char *directions[]; -extern direction_t finddirection(const char *s, const struct locale *); - -extern int findoption(const char *s, const struct locale * lang); - -/* special units */ -void make_undead_unit(struct unit *); - -void addstrlist(strlist ** SP, const char *s); - -int armedmen(const struct unit * u, boolean siege_weapons); - -unsigned int atoip(const char *s); -unsigned int getuint(void); -int getint(void); - -extern const char *igetstrtoken(const char *s); - -extern void init_tokens(const struct order * ord); /* initialize token parsing */ -extern skill_t findskill(const char *s, const struct locale * lang); - -extern keyword_t findkeyword(const char *s, const struct locale * lang); - -extern param_t findparam(const char *s, const struct locale * lang); -extern param_t getparam(const struct locale * lang); - -extern int getid(void); -#define unitid(x) itoa36((x)->no) - -#define getshipid() getid() -#define getfactionid() getid() - -#define buildingid(x) itoa36((x)->no) -#define shipid(x) itoa36((x)->no) -#define factionid(x) itoa36((x)->no) -#define curseid(x) itoa36((x)->no) - -extern boolean cansee(const struct faction * f, const struct region * r, const struct unit * u, int modifier); -boolean cansee_durchgezogen(const struct faction * f, const struct region * r, const struct unit * u, int modifier); -extern boolean cansee_unit(const struct unit * u, const struct unit * target, int modifier); -boolean seefaction(const struct faction * f, const struct region * r, const struct unit * u, int modifier); -extern int effskill(const struct unit * u, skill_t sk); - -extern int lovar(double xpct_x2); - /* returns a value between [0..xpct_2], generated with two dice */ - -int distribute(int old, int new_value, int n); - -int newunitid(void); -int forbiddenid(int id); -int newcontainerid(void); - -extern struct unit *createunit(struct region * r, struct faction * f, int number, const struct race * rc); -extern void create_unitid(struct unit *u, int id); -extern boolean getunitpeasants; -extern struct unit *getunitg(const struct region * r, const struct faction * f); -extern struct unit *getunit(const struct region * r, const struct faction * f); - -extern int read_unitid(const struct faction * f, const struct region * r); - -extern int alliedunit(const struct unit * u, const struct faction * f2, int mode); -extern int alliedfaction(const struct plane * pl, const struct faction * f, - const struct faction * f2, int mode); -extern int alliedgroup(const struct plane * pl, const struct faction * f, - const struct faction * f2, const struct ally * sf, - int mode); - -struct faction *findfaction(int n); -struct faction *getfaction(void); - -struct unit *findunitg(int n, const struct region * hint); -struct unit *findunit(int n); - -struct unit *findunitr(const struct region * r, int n); -struct region *findunitregion(const struct unit * su); - -extern char *estring(const char *s); -extern char *estring_i(char *s); -extern char *cstring(const char *s); -extern char *cstring_i(char *s); -extern const char *unitname(const struct unit * u); -extern char * write_unitname(const struct unit * u, char * buffer, size_t size); - -typedef int (*cmp_building_cb)(const struct building * b, const struct building * a); -struct building *largestbuilding(const struct region * r, cmp_building_cb, boolean imaginary); -int cmp_wage(const struct building * b, const struct building * bother); -int cmp_taxes(const struct building * b, const struct building * bother); -int cmp_current_owner(const struct building * b, const struct building * bother); - -#define TAX_ORDER 0x00 -#define TAX_OWNER 0x01 -int rule_auto_taxation(void); -int rule_transfermen(void); -int rule_region_owners(void); -int rule_stealth_faction(void); -#define HARVEST_WORK 0x00 -#define HARVEST_TAXES 0x01 -int rule_blessed_harvest(void); -extern int rule_give(void); -extern int rule_alliance_limit(void); -extern int rule_faction_limit(void); - -extern int count_all(const struct faction * f); -extern int count_migrants (const struct faction * f); -extern int count_maxmigrants(const struct faction * f); - -extern boolean has_limited_skills(const struct unit * u); -extern const struct race * findrace(const char *, const struct locale *); - -int eff_stealth(const struct unit * u, const struct region * r); -int ispresent(const struct faction * f, const struct region * r); - -int check_option(struct faction * f, int option); -extern void parse(keyword_t kword, int (*dofun)(struct unit *, struct order *), boolean thisorder); - -/* Anzahl Personen in einer Einheit festlegen. NUR (!) mit dieser Routine, - * sonst großes Unglück. Durch asserts an ein paar Stellen abgesichert. */ -void verify_data(void); - -void freestrlist(strlist * s); - -int change_hitpoints(struct unit *u, int value); - -int weight(const struct unit * u); -void changeblockchaos(void); - -/* intervall, in dem die regionen der partei zu finden sind */ -extern struct region *firstregion(struct faction * f); -extern struct region *lastregion(struct faction * f); - -void fhash(struct faction * f); -void funhash(struct faction * f); - -boolean idle(struct faction * f); -boolean unit_has_cursed_item(struct unit *u); - -/* simple garbage collection: */ -void * gc_add(void * p); - -/* grammatik-flags: */ -#define GF_NONE 0 - /* singular, ohne was dran */ -#define GF_PLURAL 1 - /* Angaben in Mehrzahl */ -#define GF_ARTICLE 8 - /* der, die, eine */ -#define GF_SPECIFIC 16 - /* der, die, das vs. ein, eine */ -#define GF_DETAILED 32 - /* mehr Informationen. z.b. straße zu 50% */ -#define GF_PURE 64 - /* untranslated */ - -#define GUARD_NONE 0 -#define GUARD_TAX 1 - /* Verhindert Steuereintreiben */ -#define GUARD_MINING 2 - /* Verhindert Bergbau */ -#define GUARD_TREES 4 - /* Verhindert Waldarbeiten */ -#define GUARD_TRAVELTHRU 8 - /* Blockiert Durchreisende */ -#define GUARD_LANDING 16 - /* Verhindert Ausstieg + Weiterreise */ -#define GUARD_CREWS 32 - /* Verhindert Unterhaltung auf Schiffen */ -#define GUARD_RECRUIT 64 - /* Verhindert Rekrutieren */ -#define GUARD_PRODUCE 128 - /* Verhindert Abbau von Resourcen mit RTF_LIMITED */ -#define GUARD_ALL 0xFFFF - -extern void setstatus(struct unit * u, int status); -/* !< sets combatstatus of a unit */ -extern void setguard(struct unit * u, unsigned int flags); -/* !< setzt die guard-flags der Einheit */ -extern unsigned int getguard(const struct unit * u); - /* liest die guard-flags der Einheit */ -extern void guard(struct unit * u, unsigned int mask); - /* Einheit setzt "BEWACHE", rassenspezifzisch. - * 'mask' kann einzelne flags zusätzlich und-maskieren. - */ -unsigned int guard_flags(const struct unit * u); - -extern boolean hunger(int number, struct unit * u); -extern int lifestyle(const struct unit*); -extern int besieged(const struct unit * u); -extern int maxworkingpeasants(const struct region * r); -extern boolean has_horses(const struct unit * u); -extern int markets_module(void); -extern int wage(const struct region *r, const struct faction *f, const struct race * rc, int in_turn); -extern int maintenance_cost(const struct unit * u); -extern struct message * movement_error(struct unit * u, const char * token, struct order * ord, int error_code); -extern boolean move_blocked(const struct unit * u, const struct region *src, const struct region *dest); -extern void add_income(struct unit * u, int type, int want, int qty); - -/* movewhere error codes */ -enum { - E_MOVE_OK = 0, /* possible to move */ - E_MOVE_NOREGION, /* no region exists in this direction */ - E_MOVE_BLOCKED /* cannot see this region, there is a blocking connection. */ -}; -extern int movewhere(const struct unit *u, const char * token, struct region * r, struct region** resultp); - -extern const char * datapath(void); -extern void set_datapath(const char * path); - -extern const char * basepath(void); -extern void set_basepath(const char *); -void load_inifile(struct _dictionary_ * d); - -extern const char * reportpath(void); -extern void set_reportpath(const char *); - -extern void kernel_init(void); -extern void kernel_done(void); - -extern void reorder_units(struct region * r); - -extern const char *localenames[]; - -/** compatibility: **/ -extern race_t old_race(const struct race *); -extern const struct race * new_race[]; - -/* globale settings des Spieles */ -typedef struct settings { - const char *gamename; - struct attrib *attribs; - unsigned int data_turn; - boolean disabled[MAXKEYWORDS]; - struct param * parameters; - void * vm_state; - float producexpchance; - int cookie; - struct _dictionary_ * inifile; - - struct global_functions { - int (*wage)(const struct region *r, const struct faction * f, const struct race * rc, int in_turn); - int (*maintenance)(const struct unit * u); - } functions; -} settings; -extern settings global; - -extern int produceexp(struct unit * u, skill_t sk, int n); - -extern boolean battledebug; -extern boolean sqlpatch; -extern boolean lomem; /* save memory */ - -extern const char * dbrace(const struct race * rc); - -extern void set_param(struct param ** p, const char * name, const char * data); -extern const char* get_param(const struct param * p, const char * name); -extern int get_param_int(const struct param * p, const char * name, int def); -extern float get_param_flt(const struct param * p, const char * name, float def); - -extern boolean ExpensiveMigrants(void); -extern int NMRTimeout(void); -extern int LongHunger(const struct unit * u); -extern int SkillCap(skill_t sk); -extern int NewbieImmunity(void); -extern boolean IsImmune(const struct faction * f); -extern int AllianceAuto(void); /* flags that allied factions get automatically */ -extern int AllianceRestricted(void); /* flags restricted to allied factions */ -extern int HelpMask(void); /* flags restricted to allied factions */ -extern struct order * default_order(const struct locale * lang); -extern int entertainmoney(const struct region * r); - -extern void plagues(struct region * r, boolean ismagic); -typedef struct helpmode { - const char * name; - int status; -} helpmode; - -extern struct helpmode helpmodes[]; - -#define GIVE_SELF 1 -#define GIVE_PEASANTS 2 -#define GIVE_LUXURIES 4 -#define GIVE_HERBS 8 -#define GIVE_GOODS 16 -#define GIVE_ONDEATH 32 -#define GIVE_ALLITEMS (GIVE_GOODS|GIVE_HERBS|GIVE_LUXURIES) -#define GIVE_DEFAULT (GIVE_SELF|GIVE_PEASANTS|GIVE_LUXURIES|GIVE_HERBS|GIVE_GOODS) - -extern struct attrib_type at_guard; -extern void free_gamedata(void); -#if 1 /* disable to count all units */ -# define count_unit(u) playerrace(u->race) -#else -# define count_unit(u) 1 -#endif - -#if XECMD_MODULE -extern struct attrib_type at_xontormiaexpress; -#endif - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef ERESSEA_H +#define ERESSEA_H + +#ifdef __cplusplus +extern "C" { +#endif + + /* this should always be the first thing included after platform.h */ +#include "types.h" + +struct _dictionary_; + + /* experimental gameplay features (that don't affect the savefile) */ + /* TODO: move these settings to settings.h or into configuration files */ +#define GOBLINKILL /* Goblin-Spezialklau kann tödlich enden */ +#define HERBS_ROT /* herbs owned by units have a chance to rot. */ +#define SHIPDAMAGE /* Schiffsbeschädigungen */ +#define INSECT_POTION /* Spezialtrank für Insekten */ +#define ORCIFICATION /* giving snotlings to the peasants gets counted */ +#undef TROLLSAVE /* saving throw for dead trolls */ + +#define ALLIED(f1, f2) (f1==f2 || (f1->alliance && f1->alliance==f2->alliance)) + +/* for some good prime numbers, check http://www.math.niu.edu/~rusin/known-math/98/pi_x */ +#ifndef MAXREGIONS +# define MAXREGIONS 524287 /* must be prime for hashing. 262139 was a little small */ +#endif +#ifndef MAXUNITS +# define MAXUNITS 1048573 /* must be prime for hashing. 524287 was >90% full */ +#endif + +#define MAXPEASANTS_PER_AREA 10 /* number of peasants per region-size */ +#define TREESIZE (MAXPEASANTS_PER_AREA-2) /* space used by trees (in #peasants) */ + +#define PEASANTFORCE 0.75 /* Chance einer Vermehrung trotz 90% Auslastung */ +#define HERBROTCHANCE 5 /* Verrottchance für Kräuter (ifdef HERBS_ROT) */ + +/* Gebäudegröße = Minimalbelagerer */ +#define SIEGEFACTOR 2 + +/** Magic */ +#define MAXMAGICIANS 3 +#define MAXALCHEMISTS 3 + +/** Plagues **/ +#define PLAGUE_CHANCE 0.1F /* Seuchenwahrscheinlichkeit (siehe plagues()) */ +#define PLAGUE_VICTIMS 0.2F /* % Betroffene */ +#define PLAGUE_HEALCHANCE 0.25F /* Wahrscheinlichkeit Heilung */ +#define PLAGUE_HEALCOST 30 /* Heilkosten */ + +/* Chance of a monster attack */ +#define MONSTERATTACK 0.4F + +/** Chance of an unmaintained building crashing */ +/* #define COLLAPSE_CHANCE 0.4F */ +#undef COLLAPSE_CHANCE +/** chance to survive the crash of a building */ +/* #define COLLAPSE_SURVIVAL 0.5F */ +#undef COLLAPSE_SURVIVAL + +/* 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 + +#define PERSON_WEIGHT 1000 /* weight of a "normal" human unit */ +#define STAMINA_AFFECTS_HP 1<<0 + +/** + * Hier endet der Teil von config.h, der die defines für die + * Spielwelt Eressea enthält, und beginnen die allgemeinen Routinen + */ + +#define ENCCHANCE 10 /* %-Chance für einmalige Zufallsbegegnung */ + +#define DISPLAYSIZE 8191 /* max. Länge einer Beschreibung, ohne trailing 0 */ +#define NAMESIZE 127 /* max. Länge eines Namens, ohne trailing 0 */ +#define IDSIZE 15 /* max. Länge einer no (als String), ohne trailing 0 */ +#define KEYWORDSIZE 15 /* max. Länge eines Keyword, ohne trailing 0 */ +#define OBJECTIDSIZE (NAMESIZE+5+IDSIZE) /* max. Länge der Strings, die + * von struct unitname, etc. zurückgegeben werden. ohne die 0 */ + +#define BAGCAPACITY 20000 /* soviel paßt in einen Bag of Holding */ +#define STRENGTHCAPACITY 50000 /* zusätzliche Tragkraft beim Kraftzauber (deprecated) */ +#define STRENGTHMULTIPLIER 50 /* multiplier for trollbelt */ + +/* ----------------- Befehle ----------------------------------- */ + +extern const char *keywords[MAXKEYWORDS]; +extern const char *parameters[MAXPARAMS]; + +/** report options **/ +#define want(option) (1<flags & (i)) +#define fset(u, i) ((u)->flags |= (i)) +#define freset(u, i) ((u)->flags &= ~(i)) + +extern int turn; +extern int verbosity; + +/* parteinummern */ +extern boolean faction_id_is_unused(int); + +/* leuchtturm */ +extern boolean check_leuchtturm(struct region * r, struct faction * f); +extern void update_lighthouse(struct building * lh); +extern int lighthouse_range(const struct building * b, const struct faction * f); + +/* skills */ +extern int skill_limit(struct faction * f, skill_t sk); +extern int count_skill(struct faction * f, skill_t sk); + +/* direction, geography */ +extern const char *directions[]; +extern direction_t finddirection(const char *s, const struct locale *); + +extern int findoption(const char *s, const struct locale * lang); + +/* special units */ +void make_undead_unit(struct unit *); + +void addstrlist(strlist ** SP, const char *s); + +int armedmen(const struct unit * u, boolean siege_weapons); + +unsigned int atoip(const char *s); +unsigned int getuint(void); +int getint(void); + +extern const char *igetstrtoken(const char *s); + +extern void init_tokens(const struct order * ord); /* initialize token parsing */ +extern skill_t findskill(const char *s, const struct locale * lang); + +extern keyword_t findkeyword(const char *s, const struct locale * lang); + +extern param_t findparam(const char *s, const struct locale * lang); +extern param_t getparam(const struct locale * lang); + +extern int getid(void); +#define unitid(x) itoa36((x)->no) + +#define getshipid() getid() +#define getfactionid() getid() + +#define buildingid(x) itoa36((x)->no) +#define shipid(x) itoa36((x)->no) +#define factionid(x) itoa36((x)->no) +#define curseid(x) itoa36((x)->no) + +extern boolean cansee(const struct faction * f, const struct region * r, const struct unit * u, int modifier); +boolean cansee_durchgezogen(const struct faction * f, const struct region * r, const struct unit * u, int modifier); +extern boolean cansee_unit(const struct unit * u, const struct unit * target, int modifier); +boolean seefaction(const struct faction * f, const struct region * r, const struct unit * u, int modifier); +extern int effskill(const struct unit * u, skill_t sk); + +extern int lovar(double xpct_x2); + /* returns a value between [0..xpct_2], generated with two dice */ + +int distribute(int old, int new_value, int n); + +int newunitid(void); +int forbiddenid(int id); +int newcontainerid(void); + +extern struct unit *createunit(struct region * r, struct faction * f, int number, const struct race * rc); +extern void create_unitid(struct unit *u, int id); +extern boolean getunitpeasants; +extern struct unit *getunitg(const struct region * r, const struct faction * f); +extern struct unit *getunit(const struct region * r, const struct faction * f); + +extern int read_unitid(const struct faction * f, const struct region * r); + +extern int alliedunit(const struct unit * u, const struct faction * f2, int mode); +extern int alliedfaction(const struct plane * pl, const struct faction * f, + const struct faction * f2, int mode); +extern int alliedgroup(const struct plane * pl, const struct faction * f, + const struct faction * f2, const struct ally * sf, + int mode); + +struct faction *findfaction(int n); +struct faction *getfaction(void); + +struct unit *findunitg(int n, const struct region * hint); +struct unit *findunit(int n); + +struct unit *findunitr(const struct region * r, int n); +struct region *findunitregion(const struct unit * su); + +extern char *estring(const char *s); +extern char *estring_i(char *s); +extern char *cstring(const char *s); +extern char *cstring_i(char *s); +extern const char *unitname(const struct unit * u); +extern char * write_unitname(const struct unit * u, char * buffer, size_t size); + +typedef int (*cmp_building_cb)(const struct building * b, const struct building * a); +struct building *largestbuilding(const struct region * r, cmp_building_cb, boolean imaginary); +int cmp_wage(const struct building * b, const struct building * bother); +int cmp_taxes(const struct building * b, const struct building * bother); +int cmp_current_owner(const struct building * b, const struct building * bother); + +#define TAX_ORDER 0x00 +#define TAX_OWNER 0x01 +int rule_auto_taxation(void); +int rule_transfermen(void); +int rule_region_owners(void); +int rule_stealth_faction(void); +#define HARVEST_WORK 0x00 +#define HARVEST_TAXES 0x01 +int rule_blessed_harvest(void); +extern int rule_give(void); +extern int rule_alliance_limit(void); +extern int rule_faction_limit(void); + +extern int count_all(const struct faction * f); +extern int count_migrants (const struct faction * f); +extern int count_maxmigrants(const struct faction * f); + +extern boolean has_limited_skills(const struct unit * u); +extern const struct race * findrace(const char *, const struct locale *); + +int eff_stealth(const struct unit * u, const struct region * r); +int ispresent(const struct faction * f, const struct region * r); + +int check_option(struct faction * f, int option); +extern void parse(keyword_t kword, int (*dofun)(struct unit *, struct order *), boolean thisorder); + +/* Anzahl Personen in einer Einheit festlegen. NUR (!) mit dieser Routine, + * sonst großes Unglück. Durch asserts an ein paar Stellen abgesichert. */ +void verify_data(void); + +void freestrlist(strlist * s); + +int change_hitpoints(struct unit *u, int value); + +int weight(const struct unit * u); +void changeblockchaos(void); + +/* intervall, in dem die regionen der partei zu finden sind */ +extern struct region *firstregion(struct faction * f); +extern struct region *lastregion(struct faction * f); + +void fhash(struct faction * f); +void funhash(struct faction * f); + +boolean idle(struct faction * f); +boolean unit_has_cursed_item(struct unit *u); + +/* simple garbage collection: */ +void * gc_add(void * p); + +/* grammatik-flags: */ +#define GF_NONE 0 + /* singular, ohne was dran */ +#define GF_PLURAL 1 + /* Angaben in Mehrzahl */ +#define GF_ARTICLE 8 + /* der, die, eine */ +#define GF_SPECIFIC 16 + /* der, die, das vs. ein, eine */ +#define GF_DETAILED 32 + /* mehr Informationen. z.b. straße zu 50% */ +#define GF_PURE 64 + /* untranslated */ + +#define GUARD_NONE 0 +#define GUARD_TAX 1 + /* Verhindert Steuereintreiben */ +#define GUARD_MINING 2 + /* Verhindert Bergbau */ +#define GUARD_TREES 4 + /* Verhindert Waldarbeiten */ +#define GUARD_TRAVELTHRU 8 + /* Blockiert Durchreisende */ +#define GUARD_LANDING 16 + /* Verhindert Ausstieg + Weiterreise */ +#define GUARD_CREWS 32 + /* Verhindert Unterhaltung auf Schiffen */ +#define GUARD_RECRUIT 64 + /* Verhindert Rekrutieren */ +#define GUARD_PRODUCE 128 + /* Verhindert Abbau von Resourcen mit RTF_LIMITED */ +#define GUARD_ALL 0xFFFF + +extern void setstatus(struct unit * u, int status); +/* !< sets combatstatus of a unit */ +extern void setguard(struct unit * u, unsigned int flags); +/* !< setzt die guard-flags der Einheit */ +extern unsigned int getguard(const struct unit * u); + /* liest die guard-flags der Einheit */ +extern void guard(struct unit * u, unsigned int mask); + /* Einheit setzt "BEWACHE", rassenspezifzisch. + * 'mask' kann einzelne flags zusätzlich und-maskieren. + */ +unsigned int guard_flags(const struct unit * u); + +extern boolean hunger(int number, struct unit * u); +extern int lifestyle(const struct unit*); +extern int besieged(const struct unit * u); +extern int maxworkingpeasants(const struct region * r); +extern boolean has_horses(const struct unit * u); +extern int markets_module(void); +extern int wage(const struct region *r, const struct faction *f, const struct race * rc, int in_turn); +extern int maintenance_cost(const struct unit * u); +extern struct message * movement_error(struct unit * u, const char * token, struct order * ord, int error_code); +extern boolean move_blocked(const struct unit * u, const struct region *src, const struct region *dest); +extern void add_income(struct unit * u, int type, int want, int qty); + +/* movewhere error codes */ +enum { + E_MOVE_OK = 0, /* possible to move */ + E_MOVE_NOREGION, /* no region exists in this direction */ + E_MOVE_BLOCKED /* cannot see this region, there is a blocking connection. */ +}; +extern int movewhere(const struct unit *u, const char * token, struct region * r, struct region** resultp); + +extern const char * datapath(void); +extern void set_datapath(const char * path); + +extern const char * basepath(void); +extern void set_basepath(const char *); +void load_inifile(struct _dictionary_ * d); + +extern const char * reportpath(void); +extern void set_reportpath(const char *); + +extern void kernel_init(void); +extern void kernel_done(void); + +extern void reorder_units(struct region * r); + +extern const char *localenames[]; + +/** compatibility: **/ +extern race_t old_race(const struct race *); +extern const struct race * new_race[]; + +/* globale settings des Spieles */ +typedef struct settings { + const char *gamename; + struct attrib *attribs; + unsigned int data_turn; + boolean disabled[MAXKEYWORDS]; + struct param * parameters; + void * vm_state; + float producexpchance; + int cookie; + struct _dictionary_ * inifile; + + struct global_functions { + int (*wage)(const struct region *r, const struct faction * f, const struct race * rc, int in_turn); + int (*maintenance)(const struct unit * u); + } functions; +} settings; +extern settings global; + +extern int produceexp(struct unit * u, skill_t sk, int n); + +extern boolean battledebug; +extern boolean sqlpatch; +extern boolean lomem; /* save memory */ + +extern const char * dbrace(const struct race * rc); + +extern void set_param(struct param ** p, const char * name, const char * data); +extern const char* get_param(const struct param * p, const char * name); +extern int get_param_int(const struct param * p, const char * name, int def); +extern float get_param_flt(const struct param * p, const char * name, float def); + +extern boolean ExpensiveMigrants(void); +extern int NMRTimeout(void); +extern int LongHunger(const struct unit * u); +extern int SkillCap(skill_t sk); +extern int NewbieImmunity(void); +extern boolean IsImmune(const struct faction * f); +extern int AllianceAuto(void); /* flags that allied factions get automatically */ +extern int AllianceRestricted(void); /* flags restricted to allied factions */ +extern int HelpMask(void); /* flags restricted to allied factions */ +extern struct order * default_order(const struct locale * lang); +extern int entertainmoney(const struct region * r); + +extern void plagues(struct region * r, boolean ismagic); +typedef struct helpmode { + const char * name; + int status; +} helpmode; + +extern struct helpmode helpmodes[]; + +#define GIVE_SELF 1 +#define GIVE_PEASANTS 2 +#define GIVE_LUXURIES 4 +#define GIVE_HERBS 8 +#define GIVE_GOODS 16 +#define GIVE_ONDEATH 32 +#define GIVE_ALLITEMS (GIVE_GOODS|GIVE_HERBS|GIVE_LUXURIES) +#define GIVE_DEFAULT (GIVE_SELF|GIVE_PEASANTS|GIVE_LUXURIES|GIVE_HERBS|GIVE_GOODS) + +extern struct attrib_type at_guard; +extern void free_gamedata(void); +#if 1 /* disable to count all units */ +# define count_unit(u) playerrace(u->race) +#else +# define count_unit(u) 1 +#endif + +#if XECMD_MODULE +extern struct attrib_type at_xontormiaexpress; +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/connection.c b/src/kernel/connection.c index 0dc4a3753..6ea99361d 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -1,613 +1,613 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "connection.h" - -#include "region.h" -#include "save.h" -#include "terrain.h" -#include "unit.h" -#include "version.h" - -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -unsigned int nextborder = 0; - -#define BORDER_MAXHASH 8191 -connection * borders[BORDER_MAXHASH]; -border_type * bordertypes; - -void (*border_convert_cb)(struct connection * con, struct attrib * attr) = 0; - -void -free_borders(void) -{ - int i; - for (i=0;i!=BORDER_MAXHASH;++i) { - while (borders[i]) { - connection * b = borders[i]; - borders[i] = b->nexthash; - while (b) { - connection * bf = b; - b = b->next; - assert(b==NULL || b->nexthash==NULL); - if (bf->type->destroy) { - bf->type->destroy(bf); - } - free(bf); - } - } - } -} - -connection * -find_border(unsigned int id) -{ - int key; - for (key=0;key!=BORDER_MAXHASH;key++) { - connection * bhash; - for (bhash=borders[key];bhash!=NULL;bhash=bhash->nexthash) { - connection * b; - for (b=bhash;b;b=b->next) { - if (b->id==id) return b; - } - } - } - return NULL; -} - -int -resolve_borderid(variant id, void * addr) -{ - int result = 0; - connection * b = NULL; - if (id.i!=0) { - b = find_border(id.i); - if (b==NULL) { - result = -1; - } - } - *(connection**)addr = b; - return result; -} - -static connection ** -get_borders_i(const region * r1, const region * r2) -{ - connection ** bp; - int key = reg_hashkey(r1); - int k2 = reg_hashkey(r2); - - key = MIN(k2, key) % BORDER_MAXHASH; - bp = &borders[key]; - while (*bp) { - connection * b = *bp; - if ((b->from==r1 && b->to==r2) || (b->from==r2 && b->to==r1)) break; - bp = &b->nexthash; - } - return bp; -} - -connection * -get_borders(const region * r1, const region * r2) -{ - connection ** bp = get_borders_i(r1, r2); - return *bp; -} - -connection * -new_border(border_type * type, region * from, region * to) -{ - connection * b = calloc(1, sizeof(struct connection)); - - if (from && to) { - connection ** bp = get_borders_i(from, to); - while (*bp) bp = &(*bp)->next; - *bp = b; - } - b->type = type; - b->from = from; - b->to = to; - b->id = ++nextborder; - - if (type->init) type->init(b); - return b; -} - -void -erase_border(connection * b) -{ - if (b->from && b->to) { - connection ** bp = get_borders_i(b->from, b->to); - assert(*bp!=NULL || !"error: connection is not registered"); - if (*bp==b) { - /* it is the first in the list, so it is in the nexthash list */ - if (b->next) { - *bp = b->next; - (*bp)->nexthash = b->nexthash; - } else { - *bp = b->nexthash; - } - } else { - while (*bp && *bp != b) { - bp = &(*bp)->next; - } - assert(*bp==b || !"error: connection is not registered"); - *bp = b->next; - } - } - if (b->type->destroy) { - b->type->destroy(b); - } - free(b); -} - -void -register_bordertype(border_type * type) -{ - border_type ** btp = &bordertypes; - - while (*btp && *btp!=type) btp = &(*btp)->next; - if (*btp) return; - *btp = type; -} - - -border_type * -find_bordertype(const char * name) -{ - border_type * bt = bordertypes; - - while (bt && strcmp(bt->__name, name)) bt = bt->next; - return bt; -} - -void -b_read(connection * b, storage * store) -{ - int result = 0; - switch (b->type->datatype) { - case VAR_NONE: - case VAR_INT: - b->data.i = store->r_int(store); - break; - case VAR_SHORTA: - b->data.sa[0] = (short)store->r_int(store); - b->data.sa[1] = (short)store->r_int(store); - break; - case VAR_VOIDPTR: - default: - assert(!"invalid variant type in connection"); - result = 0; - } - assert(result>=0 || "EOF encountered?"); -} - -void -b_write(const connection * b, storage * store) -{ - switch (b->type->datatype) { - case VAR_NONE: - case VAR_INT: - store->w_int(store, b->data.i); - break; - case VAR_SHORTA: - store->w_int(store, b->data.sa[0]); - store->w_int(store, b->data.sa[1]); - break; - case VAR_VOIDPTR: - default: - assert(!"invalid variant type in connection"); - } -} - -boolean b_transparent(const connection * b, const struct faction * f) { unused(b); unused(f); return true; } -boolean b_opaque(const connection * b, const struct faction * f) { unused(b); unused(f); return false; } -boolean b_blockall(const connection * b, const unit * u, const region * r) { unused(u); unused(r); unused(b); return true; } -boolean b_blocknone(const connection * b, const unit * u, const region * r) { unused(u); unused(r); unused(b); return false; } -boolean b_rvisible(const connection * b, const region * r) { return (boolean)(b->to==r || b->from==r); } -boolean b_fvisible(const connection * b, const struct faction * f, const region * r) { unused(r); unused(f); unused(b); return true; } -boolean b_uvisible(const connection * b, const unit * u) { unused(u); unused(b); return true; } -boolean b_rinvisible(const connection * b, const region * r) { unused(r); unused(b); return false; } -boolean b_finvisible(const connection * b, const struct faction * f, const region * r) { unused(r); unused(f); unused(b); return false; } -boolean b_uinvisible(const connection * b, const unit * u) { unused(u); unused(b); return false; } - -/**************************************/ -/* at_countdown - legacy, do not use */ -/**************************************/ - -attrib_type at_countdown = { - "countdown", - DEFAULT_INIT, - DEFAULT_FINALIZE, - NULL, - NULL, - a_readint -}; - -void -age_borders(void) -{ - border_list * deleted = NULL; - int i; - - for (i=0;i!=BORDER_MAXHASH;++i) { - connection * bhash = borders[i]; - for (;bhash;bhash=bhash->nexthash) { - connection * b = bhash; - for (;b;b=b->next) { - if (b->type->age) { - if (b->type->age(b)==AT_AGE_REMOVE) { - border_list * kill = malloc(sizeof(border_list)); - kill->data = b; - kill->next = deleted; - deleted = kill; - } - } - } - } - } - while (deleted) { - border_list * blist = deleted->next; - connection * b = deleted->data; - erase_border(b); - free(deleted); - deleted = blist; - } -} - -/******** - * implementation of a couple of borders. this shouldn't really be in here, so - * let's keep it separate from the more general stuff above - ********/ - -#include "faction.h" - -static const char * -b_namewall(const connection * b, const region * r, const struct faction * f, int gflags) -{ - const char * bname = "wall"; - - unused(f); - unused(r); - unused(b); - if (gflags & GF_ARTICLE) bname = "a_wall"; - if (gflags & GF_PURE) return bname; - return LOC(f->locale, mkname("border", bname)); -} - -border_type bt_wall = { - "wall", VAR_INT, - b_opaque, - NULL, /* init */ - NULL, /* destroy */ - b_read, /* read */ - b_write, /* write */ - b_blockall, /* block */ - b_namewall, /* name */ - b_rvisible, /* rvisible */ - b_fvisible, /* fvisible */ - b_uvisible, /* uvisible */ -}; - -border_type bt_noway = { - "noway", VAR_INT, - b_transparent, - NULL, /* init */ - NULL, /* destroy */ - b_read, /* read */ - b_write, /* write */ - b_blockall, /* block */ - NULL, /* name */ - b_rinvisible, /* rvisible */ - b_finvisible, /* fvisible */ - b_uinvisible, /* uvisible */ -}; - -static const char * -b_namefogwall(const connection * b, const region * r, const struct faction * f, int gflags) -{ - unused(f); - unused(b); - unused(r); - if (gflags & GF_PURE) return "fogwall"; - if (gflags & GF_ARTICLE) return LOC(f->locale, mkname("border", "a_fogwall")); - return LOC(f->locale, mkname("border", "fogwall")); -} - -static boolean -b_blockfogwall(const connection * b, const unit * u, const region * r) -{ - unused(b); - unused(r); - if (!u) return true; - return (boolean)(effskill(u, SK_PERCEPTION) > 4); /* Das ist die alte Nebelwand */ -} - -/** Legacy type used in old Eressea games, no longer in use. */ -border_type bt_fogwall = { - "fogwall", VAR_INT, - b_transparent, /* transparent */ - NULL, /* init */ - NULL, /* destroy */ - b_read, /* read */ - b_write, /* write */ - b_blockfogwall, /* block */ - b_namefogwall, /* name */ - b_rvisible, /* rvisible */ - b_fvisible, /* fvisible */ - b_uvisible, /* uvisible */ -}; - -static const char * -b_nameillusionwall(const connection * b, const region * r, const struct faction * f, int gflags) -{ - int fno = b->data.i; - unused(b); - unused(r); - if (gflags & GF_PURE) return (f && fno==f->no)?"illusionwall":"wall"; - if (gflags & GF_ARTICLE) { - return LOC(f->locale, mkname("border", (f && fno==f->subscription)?"an_illusionwall":"a_wall")); - } - return LOC(f->locale, mkname("border", (f && fno==f->no)?"illusionwall":"wall")); -} - -border_type bt_illusionwall = { - "illusionwall", VAR_INT, - b_opaque, - NULL, /* init */ - NULL, /* destroy */ - b_read, /* read */ - b_write, /* write */ - b_blocknone, /* block */ - b_nameillusionwall, /* name */ - b_rvisible, /* rvisible */ - b_fvisible, /* fvisible */ - b_uvisible, /* uvisible */ -}; - -/*** - * special quest door - ***/ - -boolean b_blockquestportal(const connection * b, const unit * u, const region * r) { - if(b->data.i > 0) return true; - return false; -} - -static const char * -b_namequestportal(const connection * b, const region * r, const struct faction * f, int gflags) -{ - const char * bname; - int lock = b->data.i; - unused(b); - unused(r); - - if (gflags & GF_ARTICLE) { - if (lock > 0) { - bname = "a_gate_locked"; - } else { - bname = "a_gate_open"; - } - } else { - if (lock > 0) { - bname = "gate_locked"; - } else { - bname = "gate_open"; - } - } - if (gflags & GF_PURE) return bname; - return LOC(f->locale, mkname("border", bname)); -} - -border_type bt_questportal = { - "questportal", VAR_INT, - b_opaque, - NULL, /* init */ - NULL, /* destroy */ - b_read, /* read */ - b_write, /* write */ - b_blockquestportal, /* block */ - b_namequestportal, /* name */ - b_rvisible, /* rvisible */ - b_fvisible, /* fvisible */ - b_uvisible, /* uvisible */ -}; - -/*** - * roads. meant to replace the old at_road or r->road attribute - ***/ - -static const char * -b_nameroad(const connection * b, const region * r, const struct faction * f, int gflags) -{ - region * r2 = (r==b->to)?b->from:b->to; - int local = (r==b->from)?b->data.sa[0]:b->data.sa[1]; - static char buffer[64]; - - unused(f); - if (gflags & GF_PURE) return "road"; - if (gflags & GF_ARTICLE) { - if (!(gflags & GF_DETAILED)) return LOC(f->locale, mkname("border", "a_road")); - else if (r->terrain->max_road<=local) { - int remote = (r2==b->from)?b->data.sa[0]:b->data.sa[1]; - if (r2->terrain->max_road<=remote) { - return LOC(f->locale, mkname("border", "a_road")); - } else { - return LOC(f->locale, mkname("border", "an_incomplete_road")); - } - } else { - int percent = MAX(1, 100*local/r->terrain->max_road); - if (local) { - snprintf(buffer, sizeof(buffer), LOC(f->locale, mkname("border", "a_road_percent")), percent); - } else { - return LOC(f->locale, mkname("border", "a_road_connection")); - } - } - } - else if (gflags & GF_PLURAL) return LOC(f->locale, mkname("border", "roads")); - else return LOC(f->locale, mkname("border", "road")); - return buffer; -} - -static void -b_readroad(connection * b, storage * store) -{ - b->data.sa[0] = (short)store->r_int(store); - b->data.sa[1] = (short)store->r_int(store); -} - -static void -b_writeroad(const connection * b, storage * store) -{ - store->w_int(store, b->data.sa[0]); - store->w_int(store, b->data.sa[1]); -} - -static boolean -b_validroad(const connection * b) -{ - if (b->data.sa[0]==SHRT_MAX) return false; - return true; -} - -static boolean -b_rvisibleroad(const connection * b, const region * r) -{ - int x = b->data.i; - x = (r==b->from)?b->data.sa[0]:b->data.sa[1]; - if (x==0) { - return false; - } - if (b->to!=r && b->from!=r) { - return false; - } - return true; -} - -border_type bt_road = { - "road", VAR_INT, - b_transparent, - NULL, /* init */ - NULL, /* destroy */ - b_readroad, /* read */ - b_writeroad, /* write */ - b_blocknone, /* block */ - b_nameroad, /* name */ - b_rvisibleroad, /* rvisible */ - b_finvisible, /* fvisible */ - b_uinvisible, /* uvisible */ - b_validroad /* valid */ -}; - -void -write_borders(struct storage * store) -{ - int i; - for (i=0;i!=BORDER_MAXHASH;++i) { - connection * bhash; - for (bhash=borders[i];bhash;bhash=bhash->nexthash) { - connection * b; - for (b=bhash;b!=NULL;b=b->next) { - if (b->type->valid && !b->type->valid(b)) continue; - store->w_tok(store, b->type->__name); - store->w_int(store, b->id); - store->w_int(store, b->from->uid); - store->w_int(store, b->to->uid); - - if (b->type->write) b->type->write(b, store); - store->w_brk(store); - } - } - } - store->w_tok(store, "end"); -} - -int -read_borders(struct storage * store) -{ - for (;;) { - unsigned int bid = 0; - char zText[32]; - connection * b; - region * from, * to; - border_type * type; - - store->r_tok_buf(store, zText, sizeof(zText)); - if (!strcmp(zText, "end")) break; - bid = store->r_int(store); - if (store->versionr_int(store); - fy = (short)store->r_int(store); - tx = (short)store->r_int(store); - ty = (short)store->r_int(store); - from = findregion(fx, fy); - to = findregion(tx, ty); - } else { - unsigned int fid = (unsigned int)store->r_int(store); - unsigned int tid = (unsigned int)store->r_int(store); - from = findregionbyid(fid); - to = findregionbyid(tid); - } - - type = find_bordertype(zText); - if (type==NULL) { - log_error(("[read_borders] unknown connection type %s in %s\n", zText, - regionname(from, NULL))); - assert(type || !"connection type not registered"); - } - - if (to==from && type && from) { - direction_t dir = (direction_t) (rng_int() % MAXDIRECTIONS); - region * r = rconnect(from, dir); - log_error(("[read_borders] invalid %s in %s\n", type->__name, - regionname(from, NULL))); - if (r!=NULL) to = r; - } - b = new_border(type, from, to); - nextborder--; /* new_border erhöht den Wert */ - b->id = bid; - assert(bid<=nextborder); - if (type->read) type->read(b, store); - if (store->version + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "connection.h" + +#include "region.h" +#include "save.h" +#include "terrain.h" +#include "unit.h" +#include "version.h" + +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +unsigned int nextborder = 0; + +#define BORDER_MAXHASH 8191 +connection * borders[BORDER_MAXHASH]; +border_type * bordertypes; + +void (*border_convert_cb)(struct connection * con, struct attrib * attr) = 0; + +void +free_borders(void) +{ + int i; + for (i=0;i!=BORDER_MAXHASH;++i) { + while (borders[i]) { + connection * b = borders[i]; + borders[i] = b->nexthash; + while (b) { + connection * bf = b; + b = b->next; + assert(b==NULL || b->nexthash==NULL); + if (bf->type->destroy) { + bf->type->destroy(bf); + } + free(bf); + } + } + } +} + +connection * +find_border(unsigned int id) +{ + int key; + for (key=0;key!=BORDER_MAXHASH;key++) { + connection * bhash; + for (bhash=borders[key];bhash!=NULL;bhash=bhash->nexthash) { + connection * b; + for (b=bhash;b;b=b->next) { + if (b->id==id) return b; + } + } + } + return NULL; +} + +int +resolve_borderid(variant id, void * addr) +{ + int result = 0; + connection * b = NULL; + if (id.i!=0) { + b = find_border(id.i); + if (b==NULL) { + result = -1; + } + } + *(connection**)addr = b; + return result; +} + +static connection ** +get_borders_i(const region * r1, const region * r2) +{ + connection ** bp; + int key = reg_hashkey(r1); + int k2 = reg_hashkey(r2); + + key = MIN(k2, key) % BORDER_MAXHASH; + bp = &borders[key]; + while (*bp) { + connection * b = *bp; + if ((b->from==r1 && b->to==r2) || (b->from==r2 && b->to==r1)) break; + bp = &b->nexthash; + } + return bp; +} + +connection * +get_borders(const region * r1, const region * r2) +{ + connection ** bp = get_borders_i(r1, r2); + return *bp; +} + +connection * +new_border(border_type * type, region * from, region * to) +{ + connection * b = calloc(1, sizeof(struct connection)); + + if (from && to) { + connection ** bp = get_borders_i(from, to); + while (*bp) bp = &(*bp)->next; + *bp = b; + } + b->type = type; + b->from = from; + b->to = to; + b->id = ++nextborder; + + if (type->init) type->init(b); + return b; +} + +void +erase_border(connection * b) +{ + if (b->from && b->to) { + connection ** bp = get_borders_i(b->from, b->to); + assert(*bp!=NULL || !"error: connection is not registered"); + if (*bp==b) { + /* it is the first in the list, so it is in the nexthash list */ + if (b->next) { + *bp = b->next; + (*bp)->nexthash = b->nexthash; + } else { + *bp = b->nexthash; + } + } else { + while (*bp && *bp != b) { + bp = &(*bp)->next; + } + assert(*bp==b || !"error: connection is not registered"); + *bp = b->next; + } + } + if (b->type->destroy) { + b->type->destroy(b); + } + free(b); +} + +void +register_bordertype(border_type * type) +{ + border_type ** btp = &bordertypes; + + while (*btp && *btp!=type) btp = &(*btp)->next; + if (*btp) return; + *btp = type; +} + + +border_type * +find_bordertype(const char * name) +{ + border_type * bt = bordertypes; + + while (bt && strcmp(bt->__name, name)) bt = bt->next; + return bt; +} + +void +b_read(connection * b, storage * store) +{ + int result = 0; + switch (b->type->datatype) { + case VAR_NONE: + case VAR_INT: + b->data.i = store->r_int(store); + break; + case VAR_SHORTA: + b->data.sa[0] = (short)store->r_int(store); + b->data.sa[1] = (short)store->r_int(store); + break; + case VAR_VOIDPTR: + default: + assert(!"invalid variant type in connection"); + result = 0; + } + assert(result>=0 || "EOF encountered?"); +} + +void +b_write(const connection * b, storage * store) +{ + switch (b->type->datatype) { + case VAR_NONE: + case VAR_INT: + store->w_int(store, b->data.i); + break; + case VAR_SHORTA: + store->w_int(store, b->data.sa[0]); + store->w_int(store, b->data.sa[1]); + break; + case VAR_VOIDPTR: + default: + assert(!"invalid variant type in connection"); + } +} + +boolean b_transparent(const connection * b, const struct faction * f) { unused(b); unused(f); return true; } +boolean b_opaque(const connection * b, const struct faction * f) { unused(b); unused(f); return false; } +boolean b_blockall(const connection * b, const unit * u, const region * r) { unused(u); unused(r); unused(b); return true; } +boolean b_blocknone(const connection * b, const unit * u, const region * r) { unused(u); unused(r); unused(b); return false; } +boolean b_rvisible(const connection * b, const region * r) { return (boolean)(b->to==r || b->from==r); } +boolean b_fvisible(const connection * b, const struct faction * f, const region * r) { unused(r); unused(f); unused(b); return true; } +boolean b_uvisible(const connection * b, const unit * u) { unused(u); unused(b); return true; } +boolean b_rinvisible(const connection * b, const region * r) { unused(r); unused(b); return false; } +boolean b_finvisible(const connection * b, const struct faction * f, const region * r) { unused(r); unused(f); unused(b); return false; } +boolean b_uinvisible(const connection * b, const unit * u) { unused(u); unused(b); return false; } + +/**************************************/ +/* at_countdown - legacy, do not use */ +/**************************************/ + +attrib_type at_countdown = { + "countdown", + DEFAULT_INIT, + DEFAULT_FINALIZE, + NULL, + NULL, + a_readint +}; + +void +age_borders(void) +{ + border_list * deleted = NULL; + int i; + + for (i=0;i!=BORDER_MAXHASH;++i) { + connection * bhash = borders[i]; + for (;bhash;bhash=bhash->nexthash) { + connection * b = bhash; + for (;b;b=b->next) { + if (b->type->age) { + if (b->type->age(b)==AT_AGE_REMOVE) { + border_list * kill = malloc(sizeof(border_list)); + kill->data = b; + kill->next = deleted; + deleted = kill; + } + } + } + } + } + while (deleted) { + border_list * blist = deleted->next; + connection * b = deleted->data; + erase_border(b); + free(deleted); + deleted = blist; + } +} + +/******** + * implementation of a couple of borders. this shouldn't really be in here, so + * let's keep it separate from the more general stuff above + ********/ + +#include "faction.h" + +static const char * +b_namewall(const connection * b, const region * r, const struct faction * f, int gflags) +{ + const char * bname = "wall"; + + unused(f); + unused(r); + unused(b); + if (gflags & GF_ARTICLE) bname = "a_wall"; + if (gflags & GF_PURE) return bname; + return LOC(f->locale, mkname("border", bname)); +} + +border_type bt_wall = { + "wall", VAR_INT, + b_opaque, + NULL, /* init */ + NULL, /* destroy */ + b_read, /* read */ + b_write, /* write */ + b_blockall, /* block */ + b_namewall, /* name */ + b_rvisible, /* rvisible */ + b_fvisible, /* fvisible */ + b_uvisible, /* uvisible */ +}; + +border_type bt_noway = { + "noway", VAR_INT, + b_transparent, + NULL, /* init */ + NULL, /* destroy */ + b_read, /* read */ + b_write, /* write */ + b_blockall, /* block */ + NULL, /* name */ + b_rinvisible, /* rvisible */ + b_finvisible, /* fvisible */ + b_uinvisible, /* uvisible */ +}; + +static const char * +b_namefogwall(const connection * b, const region * r, const struct faction * f, int gflags) +{ + unused(f); + unused(b); + unused(r); + if (gflags & GF_PURE) return "fogwall"; + if (gflags & GF_ARTICLE) return LOC(f->locale, mkname("border", "a_fogwall")); + return LOC(f->locale, mkname("border", "fogwall")); +} + +static boolean +b_blockfogwall(const connection * b, const unit * u, const region * r) +{ + unused(b); + unused(r); + if (!u) return true; + return (boolean)(effskill(u, SK_PERCEPTION) > 4); /* Das ist die alte Nebelwand */ +} + +/** Legacy type used in old Eressea games, no longer in use. */ +border_type bt_fogwall = { + "fogwall", VAR_INT, + b_transparent, /* transparent */ + NULL, /* init */ + NULL, /* destroy */ + b_read, /* read */ + b_write, /* write */ + b_blockfogwall, /* block */ + b_namefogwall, /* name */ + b_rvisible, /* rvisible */ + b_fvisible, /* fvisible */ + b_uvisible, /* uvisible */ +}; + +static const char * +b_nameillusionwall(const connection * b, const region * r, const struct faction * f, int gflags) +{ + int fno = b->data.i; + unused(b); + unused(r); + if (gflags & GF_PURE) return (f && fno==f->no)?"illusionwall":"wall"; + if (gflags & GF_ARTICLE) { + return LOC(f->locale, mkname("border", (f && fno==f->subscription)?"an_illusionwall":"a_wall")); + } + return LOC(f->locale, mkname("border", (f && fno==f->no)?"illusionwall":"wall")); +} + +border_type bt_illusionwall = { + "illusionwall", VAR_INT, + b_opaque, + NULL, /* init */ + NULL, /* destroy */ + b_read, /* read */ + b_write, /* write */ + b_blocknone, /* block */ + b_nameillusionwall, /* name */ + b_rvisible, /* rvisible */ + b_fvisible, /* fvisible */ + b_uvisible, /* uvisible */ +}; + +/*** + * special quest door + ***/ + +boolean b_blockquestportal(const connection * b, const unit * u, const region * r) { + if(b->data.i > 0) return true; + return false; +} + +static const char * +b_namequestportal(const connection * b, const region * r, const struct faction * f, int gflags) +{ + const char * bname; + int lock = b->data.i; + unused(b); + unused(r); + + if (gflags & GF_ARTICLE) { + if (lock > 0) { + bname = "a_gate_locked"; + } else { + bname = "a_gate_open"; + } + } else { + if (lock > 0) { + bname = "gate_locked"; + } else { + bname = "gate_open"; + } + } + if (gflags & GF_PURE) return bname; + return LOC(f->locale, mkname("border", bname)); +} + +border_type bt_questportal = { + "questportal", VAR_INT, + b_opaque, + NULL, /* init */ + NULL, /* destroy */ + b_read, /* read */ + b_write, /* write */ + b_blockquestportal, /* block */ + b_namequestportal, /* name */ + b_rvisible, /* rvisible */ + b_fvisible, /* fvisible */ + b_uvisible, /* uvisible */ +}; + +/*** + * roads. meant to replace the old at_road or r->road attribute + ***/ + +static const char * +b_nameroad(const connection * b, const region * r, const struct faction * f, int gflags) +{ + region * r2 = (r==b->to)?b->from:b->to; + int local = (r==b->from)?b->data.sa[0]:b->data.sa[1]; + static char buffer[64]; + + unused(f); + if (gflags & GF_PURE) return "road"; + if (gflags & GF_ARTICLE) { + if (!(gflags & GF_DETAILED)) return LOC(f->locale, mkname("border", "a_road")); + else if (r->terrain->max_road<=local) { + int remote = (r2==b->from)?b->data.sa[0]:b->data.sa[1]; + if (r2->terrain->max_road<=remote) { + return LOC(f->locale, mkname("border", "a_road")); + } else { + return LOC(f->locale, mkname("border", "an_incomplete_road")); + } + } else { + int percent = MAX(1, 100*local/r->terrain->max_road); + if (local) { + snprintf(buffer, sizeof(buffer), LOC(f->locale, mkname("border", "a_road_percent")), percent); + } else { + return LOC(f->locale, mkname("border", "a_road_connection")); + } + } + } + else if (gflags & GF_PLURAL) return LOC(f->locale, mkname("border", "roads")); + else return LOC(f->locale, mkname("border", "road")); + return buffer; +} + +static void +b_readroad(connection * b, storage * store) +{ + b->data.sa[0] = (short)store->r_int(store); + b->data.sa[1] = (short)store->r_int(store); +} + +static void +b_writeroad(const connection * b, storage * store) +{ + store->w_int(store, b->data.sa[0]); + store->w_int(store, b->data.sa[1]); +} + +static boolean +b_validroad(const connection * b) +{ + if (b->data.sa[0]==SHRT_MAX) return false; + return true; +} + +static boolean +b_rvisibleroad(const connection * b, const region * r) +{ + int x = b->data.i; + x = (r==b->from)?b->data.sa[0]:b->data.sa[1]; + if (x==0) { + return false; + } + if (b->to!=r && b->from!=r) { + return false; + } + return true; +} + +border_type bt_road = { + "road", VAR_INT, + b_transparent, + NULL, /* init */ + NULL, /* destroy */ + b_readroad, /* read */ + b_writeroad, /* write */ + b_blocknone, /* block */ + b_nameroad, /* name */ + b_rvisibleroad, /* rvisible */ + b_finvisible, /* fvisible */ + b_uinvisible, /* uvisible */ + b_validroad /* valid */ +}; + +void +write_borders(struct storage * store) +{ + int i; + for (i=0;i!=BORDER_MAXHASH;++i) { + connection * bhash; + for (bhash=borders[i];bhash;bhash=bhash->nexthash) { + connection * b; + for (b=bhash;b!=NULL;b=b->next) { + if (b->type->valid && !b->type->valid(b)) continue; + store->w_tok(store, b->type->__name); + store->w_int(store, b->id); + store->w_int(store, b->from->uid); + store->w_int(store, b->to->uid); + + if (b->type->write) b->type->write(b, store); + store->w_brk(store); + } + } + } + store->w_tok(store, "end"); +} + +int +read_borders(struct storage * store) +{ + for (;;) { + unsigned int bid = 0; + char zText[32]; + connection * b; + region * from, * to; + border_type * type; + + store->r_tok_buf(store, zText, sizeof(zText)); + if (!strcmp(zText, "end")) break; + bid = store->r_int(store); + if (store->versionr_int(store); + fy = (short)store->r_int(store); + tx = (short)store->r_int(store); + ty = (short)store->r_int(store); + from = findregion(fx, fy); + to = findregion(tx, ty); + } else { + unsigned int fid = (unsigned int)store->r_int(store); + unsigned int tid = (unsigned int)store->r_int(store); + from = findregionbyid(fid); + to = findregionbyid(tid); + } + + type = find_bordertype(zText); + if (type==NULL) { + log_error(("[read_borders] unknown connection type %s in %s\n", zText, + regionname(from, NULL))); + assert(type || !"connection type not registered"); + } + + if (to==from && type && from) { + direction_t dir = (direction_t) (rng_int() % MAXDIRECTIONS); + region * r = rconnect(from, dir); + log_error(("[read_borders] invalid %s in %s\n", type->__name, + regionname(from, NULL))); + if (r!=NULL) to = r; + } + b = new_border(type, from, to); + nextborder--; /* new_border erhöht den Wert */ + b->id = bid; + assert(bid<=nextborder); + if (type->read) type->read(b, store); + if (store->version - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_BORDER -#define H_KRNL_BORDER - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - extern unsigned int nextborder; - - typedef struct connection { - struct border_type * type; /* the type of this connection */ - struct connection * next; /* next connection between these regions */ - struct connection * nexthash; /* next connection between these regions */ - struct region * from, * to; /* borders can be directed edges */ - variant data; - unsigned int id; /* unique id */ - } connection; - - typedef struct border_list { - struct border_list * next; - struct connection * data; - } border_list; - - typedef struct border_type { - const char* __name; /* internal use only */ - variant_type datatype; - boolean (*transparent)(const connection *, const struct faction *); - /* is it possible to see through this? */ - void (*init)(connection *); - /* constructor: initialize the connection. allocate extra memory if needed */ - void (*destroy)(connection *); - /* destructor: remove all extra memory for destruction */ - void (*read)(connection *, struct storage *); - void (*write)(const connection *, struct storage *); - boolean (*block)(const connection *, const struct unit *, const struct region * r); - /* return true if it blocks movement of u from - * r to the opposite struct region. - * warning: struct unit may be NULL. - */ - const char *(*name)(const connection * b, const struct region * r, const struct faction * f, int gflags); - /* for example "a wall of fog" or "a doorway from r1 to r2" - * may depend on the struct faction, for example "a wall" may - * turn out to be "an illusionary wall" - */ - boolean (*rvisible)(const connection *, const struct region *); - /* is it visible to everyone in r ? - * if not, it may still be fvisible() for some f. - */ - boolean (*fvisible)(const connection *, const struct faction *, const struct region *); - /* is it visible to units of f in r? - * the function shall not check for - * existence of a struct unit in r. Example: a spell - * may be visible only to the struct faction that created it and thus - * appear in it's report (if there is a struct unit of f in r, which - * the reporting function will have to assure). - * if not true, it may still be uvisible() for some u. - */ - boolean (*uvisible)(const connection *, const struct unit *); - /* is it visible to u ? - * a doorway may only be visible to a struct unit with perception > 5 - */ - boolean (*valid)(const connection *); - /* is the connection in a valid state, - * or should it be erased at the end of this turn to save space? - */ - struct region * (*move)(const connection *, struct unit * u, struct region * from, struct region * to, boolean routing); - /* executed when the units traverses this connection */ - int (*age)(struct connection *); - /* return 0 if connection needs to be removed. >0 if still aging, <0 if not aging */ - struct border_type * next; /* for internal use only */ - } border_type; - - - extern connection * find_border(unsigned int id); - int resolve_borderid(variant data, void * addr); - extern void free_borders(void); - - extern connection * get_borders(const struct region * r1, const struct region * r2); - /* returns the list of borders between r1 and r2 or r2 and r1 */ - extern connection * new_border(border_type * type, struct region * from, struct region * to); - /* creates a connection of the specified type */ - extern void erase_border(connection * b); - /* remove the connection from memory */ - extern border_type * find_bordertype(const char * name); - extern void register_bordertype(border_type * type); - /* register a new bordertype */ - - extern int read_borders(struct storage * store); - extern void write_borders(struct storage * store); - extern void age_borders(void); - - /* provide default implementations for some member functions: */ - extern void b_read(connection * b, struct storage * store); - extern void b_write(const connection * b, struct storage * store); - extern boolean b_blockall(const connection *, const struct unit *, const struct region *); - extern boolean b_blocknone(const connection *, const struct unit *, const struct region *); - extern boolean b_rvisible(const connection *, const struct region * r); - extern boolean b_fvisible(const connection *, const struct faction * f, const struct region *); - extern boolean b_uvisible(const connection *, const struct unit * u); - extern boolean b_rinvisible(const connection *, const struct region * r); - extern boolean b_finvisible(const connection *, const struct faction * f, const struct region *); - extern boolean b_uinvisible(const connection *, const struct unit * u); - extern boolean b_transparent(const connection *, const struct faction *); - extern boolean b_opaque(const connection *, const struct faction *); /* !transparent */ - - extern border_type bt_fogwall; - extern border_type bt_noway; - extern border_type bt_wall; - extern border_type bt_illusionwall; - extern border_type bt_road; - extern border_type bt_questportal; - - extern struct attrib_type at_countdown; - - /* game-specific callbacks */ - extern void (*border_convert_cb)(struct connection * con, struct attrib * attr); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_BORDER +#define H_KRNL_BORDER + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + extern unsigned int nextborder; + + typedef struct connection { + struct border_type * type; /* the type of this connection */ + struct connection * next; /* next connection between these regions */ + struct connection * nexthash; /* next connection between these regions */ + struct region * from, * to; /* borders can be directed edges */ + variant data; + unsigned int id; /* unique id */ + } connection; + + typedef struct border_list { + struct border_list * next; + struct connection * data; + } border_list; + + typedef struct border_type { + const char* __name; /* internal use only */ + variant_type datatype; + boolean (*transparent)(const connection *, const struct faction *); + /* is it possible to see through this? */ + void (*init)(connection *); + /* constructor: initialize the connection. allocate extra memory if needed */ + void (*destroy)(connection *); + /* destructor: remove all extra memory for destruction */ + void (*read)(connection *, struct storage *); + void (*write)(const connection *, struct storage *); + boolean (*block)(const connection *, const struct unit *, const struct region * r); + /* return true if it blocks movement of u from + * r to the opposite struct region. + * warning: struct unit may be NULL. + */ + const char *(*name)(const connection * b, const struct region * r, const struct faction * f, int gflags); + /* for example "a wall of fog" or "a doorway from r1 to r2" + * may depend on the struct faction, for example "a wall" may + * turn out to be "an illusionary wall" + */ + boolean (*rvisible)(const connection *, const struct region *); + /* is it visible to everyone in r ? + * if not, it may still be fvisible() for some f. + */ + boolean (*fvisible)(const connection *, const struct faction *, const struct region *); + /* is it visible to units of f in r? + * the function shall not check for + * existence of a struct unit in r. Example: a spell + * may be visible only to the struct faction that created it and thus + * appear in it's report (if there is a struct unit of f in r, which + * the reporting function will have to assure). + * if not true, it may still be uvisible() for some u. + */ + boolean (*uvisible)(const connection *, const struct unit *); + /* is it visible to u ? + * a doorway may only be visible to a struct unit with perception > 5 + */ + boolean (*valid)(const connection *); + /* is the connection in a valid state, + * or should it be erased at the end of this turn to save space? + */ + struct region * (*move)(const connection *, struct unit * u, struct region * from, struct region * to, boolean routing); + /* executed when the units traverses this connection */ + int (*age)(struct connection *); + /* return 0 if connection needs to be removed. >0 if still aging, <0 if not aging */ + struct border_type * next; /* for internal use only */ + } border_type; + + + extern connection * find_border(unsigned int id); + int resolve_borderid(variant data, void * addr); + extern void free_borders(void); + + extern connection * get_borders(const struct region * r1, const struct region * r2); + /* returns the list of borders between r1 and r2 or r2 and r1 */ + extern connection * new_border(border_type * type, struct region * from, struct region * to); + /* creates a connection of the specified type */ + extern void erase_border(connection * b); + /* remove the connection from memory */ + extern border_type * find_bordertype(const char * name); + extern void register_bordertype(border_type * type); + /* register a new bordertype */ + + extern int read_borders(struct storage * store); + extern void write_borders(struct storage * store); + extern void age_borders(void); + + /* provide default implementations for some member functions: */ + extern void b_read(connection * b, struct storage * store); + extern void b_write(const connection * b, struct storage * store); + extern boolean b_blockall(const connection *, const struct unit *, const struct region *); + extern boolean b_blocknone(const connection *, const struct unit *, const struct region *); + extern boolean b_rvisible(const connection *, const struct region * r); + extern boolean b_fvisible(const connection *, const struct faction * f, const struct region *); + extern boolean b_uvisible(const connection *, const struct unit * u); + extern boolean b_rinvisible(const connection *, const struct region * r); + extern boolean b_finvisible(const connection *, const struct faction * f, const struct region *); + extern boolean b_uinvisible(const connection *, const struct unit * u); + extern boolean b_transparent(const connection *, const struct faction *); + extern boolean b_opaque(const connection *, const struct faction *); /* !transparent */ + + extern border_type bt_fogwall; + extern border_type bt_noway; + extern border_type bt_wall; + extern border_type bt_illusionwall; + extern border_type bt_road; + extern border_type bt_questportal; + + extern struct attrib_type at_countdown; + + /* game-specific callbacks */ + extern void (*border_convert_cb)(struct connection * con, struct attrib * attr); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 415308d2c..f660b2597 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -1,821 +1,821 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "curse.h" - -/* kernel includes */ -#include "building.h" -#include "faction.h" -#include "magic.h" -#include "message.h" -#include "objtypes.h" -#include "race.h" -#include "region.h" -#include "ship.h" -#include "skill.h" -#include "unit.h" -#include "version.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include - -#include - -#define MAXENTITYHASH 7919 -curse *cursehash[MAXENTITYHASH]; - -void -c_setflag(curse *c, unsigned int flags) -{ - assert(c); - c->flags = (c->flags & ~flags) | (flags & (c->type->flags ^ flags)); -} -/* -------------------------------------------------------------------------- */ -void -c_clearflag(curse *c, unsigned int flags) -{ - assert(c); - c->flags = (c->flags & ~flags) | (c->type->flags & flags); -} - -void -chash(curse *c) -{ - curse *old = cursehash[c->no %MAXENTITYHASH]; - - cursehash[c->no %MAXENTITYHASH] = c; - c->nexthash = old; -} - -static void -cunhash(curse *c) -{ - curse **show; - - for (show = &cursehash[c->no % MAXENTITYHASH]; *show; show = &(*show)->nexthash) { - if ((*show)->no == c->no) - break; - } - if (*show) { - assert(*show == c); - *show = (*show)->nexthash; - c->nexthash = 0; - } -} - -curse * -cfindhash(int i) -{ - curse *old; - - for (old = cursehash[i % MAXENTITYHASH]; old; old = old->nexthash) - if (old->no == i) - return old; - return NULL; -} - -/* ------------------------------------------------------------- */ -/* at_curse */ -void -curse_init(attrib * a) { - a->data.v = calloc(1, sizeof(curse)); -} - -int -curse_age(attrib * a) -{ - curse * c = (curse*)a->data.v; - int result = 0; - - if (c_flags(c) & CURSE_NOAGE) { - c->duration = INT_MAX; - } - if (c->type->age) { - result = c->type->age(c); - } - if (result!=0) { - c->duration = 0; - } else if (c->duration!=INT_MAX) { - c->duration = MAX(0, c->duration-1); - } - return c->duration; -} - -void -destroy_curse(curse * c) -{ - cunhash(c); - free(c); -} - -void -curse_done(attrib * a) { - destroy_curse((curse *)a->data.v); -} - -/** reads curses that have been removed from the code */ -static int -read_ccompat(const char * cursename, struct storage * store) -{ - struct compat { - const char * name; - const char * tokens; - } * seek, old_curses[] = { {"disorientationzone", ""}, {"shipdisorientation", ""}, { NULL, NULL } } ; - for (seek=old_curses;seek->name;++seek) { - if (strcmp(seek->tokens, cursename)==0) { - const char * p; - for (p=seek->name;p;++p) { - switch (*p) { - case 'd': store->r_int(store); break; - case 's': store->r_str(store); break; - case 't': store->r_tok(store); break; - case 'i': store->r_id(store); break; - case 'f': store->r_flt(store); break; - } - } - return 0; - } - } - return -1; -} - -int -curse_read(attrib * a, void * owner, struct storage * store) -{ - curse * c = (curse*)a->data.v; - int ur; - char cursename[64]; - unsigned int flags; - - c->no = store->r_int(store); - chash(c); - store->r_tok_buf(store, cursename, sizeof(cursename)); - flags = store->r_int(store); - c->duration = store->r_int(store); - if (store->version >= CURSEVIGOURISFLOAT_VERSION) { - c->vigour = store->r_flt(store); - } else { - int vigour = store->r_int(store); - c->vigour = vigour; - } - if (store->versionmagician, store, read_int, resolve_unit); - } else { - ur = read_reference(&c->magician, store, read_unit_reference, resolve_unit); - } - if (store->versioneffect = (double)store->r_int(store); - } else { - c->effect = store->r_flt(store); - } - c->type = ct_find(cursename); - if (c->type==NULL) { - int result = read_ccompat(cursename, store); - if (result!=0) { - log_error(("missing curse %s, no compatibility code either.\n", cursename)); - } - assert(result==0); - return AT_READ_FAIL; - } - if (store->version < CURSEFLAGS_VERSION) { - c_setflag(c, flags); - } else { - c->flags = flags; - } - c_clearflag(c, CURSE_ISNEW); - - if (c->type->read) c->type->read(store, c, owner); - else if (c->type->typ==CURSETYP_UNIT) { - c->data.i = store->r_int(store); - } - if (c->type->typ == CURSETYP_REGION) { - int rr = read_reference(&c->data.v, store, read_region_reference, RESOLVE_REGION(store->version)); - if (ur==0 && rr==0 && !c->data.v) { - return AT_READ_FAIL; - } - } - - return AT_READ_OK; -} - -void -curse_write(const attrib * a, const void * owner, struct storage * store) -{ - unsigned int flags; - curse * c = (curse*)a->data.v; - const curse_type * ct = c->type; - unit * mage = (c->magician && c->magician->number)?c->magician:NULL; - - /* copied from c_clearflag */ - flags = (c->flags & ~CURSE_ISNEW) | (c->type->flags & CURSE_ISNEW); - - store->w_int(store, c->no); - store->w_tok(store, ct->cname); - store->w_int(store, flags); - store->w_int(store, c->duration); - store->w_flt(store, (float)c->vigour); - write_unit_reference(mage, store); - store->w_flt(store, (float)c->effect); - - if (c->type->write) c->type->write(store, c, owner); - else if (c->type->typ == CURSETYP_UNIT) { - store->w_int(store, c->data.i); - } - if (c->type->typ == CURSETYP_REGION) { - write_region_reference((region*)c->data.v, store); - } -} - -attrib_type at_curse = -{ - "curse", - curse_init, - curse_done, - curse_age, - curse_write, - curse_read, - ATF_CURSE -}; -/* ------------------------------------------------------------- */ -/* Spruch identifizieren */ - -#include - -typedef struct cursetype_list { - struct cursetype_list * next; - const curse_type * type; -} cursetype_list; - -cursetype_list * cursetypes[256]; - -void -ct_register(const curse_type * ct) -{ - unsigned int hash = tolower(ct->cname[0]); - cursetype_list ** ctlp = &cursetypes[hash]; - - while (*ctlp) { - cursetype_list * ctl = *ctlp; - if (ctl->type==ct) return; - ctlp=&ctl->next; - } - *ctlp = calloc(1, sizeof(cursetype_list)); - (*ctlp)->type = ct; -} - -const curse_type * -ct_find(const char *c) -{ - unsigned int hash = tolower(c[0]); - cursetype_list * ctl = cursetypes[hash]; - while (ctl) { - if (strcmp(c, ctl->type->cname)==0) { - return ctl->type; - } else { - size_t k = MIN(strlen(c), strlen(ctl->type->cname)); - if (!strncasecmp(c, ctl->type->cname, k)) { - return ctl->type; - } - } - ctl = ctl->next; - } - return NULL; -} - -/* ------------------------------------------------------------- */ -/* get_curse identifiziert eine Verzauberung über die ID und gibt - * einen pointer auf die struct zurück. - */ - -boolean -cmp_curse(const attrib * a, const void * data) { - const curse * c = (const curse*)data; - if (a->type->flags & ATF_CURSE) { - if (!data || c == (curse*)a->data.v) return true; - } - return false; -} - -boolean -cmp_cursetype(const attrib * a, const void * data) -{ - const curse_type * ct = (const curse_type *)data; - if (a->type->flags & ATF_CURSE) { - if (!data || ct == ((curse*)a->data.v)->type) return true; - } - return false; -} - -curse * -get_cursex(attrib *ap, const curse_type * ctype, variant data, boolean(*compare)(const curse *, variant)) -{ - attrib * a = a_select(ap, ctype, cmp_cursetype); - while (a) { - curse * c = (curse*)a->data.v; - if (compare(c, data)) return c; - a = a_select(a->next, ctype, cmp_cursetype); - } - return NULL; -} - -curse * -get_curse(attrib *ap, const curse_type * ctype) -{ - attrib * a = ap; - while (a) { - if (a->type->flags & ATF_CURSE) { - const attrib_type * at = a->type; - while (a && a->type==at) { - curse* c = (curse *)a->data.v; - if (c->type==ctype) return c; - a = a->next; - } - } else { - a = a->nexttype; - } - } - return NULL; -} - -/* ------------------------------------------------------------- */ -/* findet einen curse global anhand seiner 'curse-Einheitnummer' */ - -curse * -findcurse(int cid) -{ - return cfindhash(cid); -} - -/* ------------------------------------------------------------- */ -void -remove_curse(attrib **ap, const curse *c) -{ - attrib *a = a_select(*ap, c, cmp_curse); - if (a) a_remove(ap, a); -} - -/* gibt die allgemeine Stärke der Verzauberung zurück. id2 wird wie - * oben benutzt. Dies ist nicht die Wirkung, sondern die Kraft und - * damit der gegen Antimagie wirkende Widerstand einer Verzauberung */ -static double -get_cursevigour(const curse *c) -{ - if (c) return c->vigour; - return 0; -} - -/* setzt die Stärke der Verzauberung auf i */ -static void -set_cursevigour(curse *c, double vigour) -{ - assert(c && vigour > 0); - c->vigour = vigour; -} - -/* verändert die Stärke der Verzauberung um +i und gibt die neue - * Stärke zurück. Sollte die Zauberstärke unter Null sinken, löst er - * sich auf. - */ -double -curse_changevigour(attrib **ap, curse *c, double vigour) -{ - vigour += get_cursevigour(c); - - if (vigour <= 0) { - remove_curse(ap, c); - vigour = 0; - } else { - set_cursevigour(c, vigour); - } - return vigour; -} - -/* ------------------------------------------------------------- */ - -double -curse_geteffect(const curse *c) -{ - if (c==NULL) return 0; - if (c_flags(c) & CURSE_ISNEW) return 0; - return c->effect; -} - -int -curse_geteffect_int(const curse *c) -{ - double effect = curse_geteffect(c); - assert(effect-(int)effect == 0); - return (int)effect; -} - -/* ------------------------------------------------------------- */ -static void -set_curseingmagician(struct unit *magician, struct attrib *ap_target, const curse_type *ct) -{ - curse * c = get_curse(ap_target, ct); - if (c) { - c->magician = magician; - } -} - -/* ------------------------------------------------------------- */ -/* gibt bei Personenbeschränkten Verzauberungen die Anzahl der - * betroffenen Personen zurück. Ansonsten wird 0 zurückgegeben. */ -int -get_cursedmen(unit *u, const curse *c) -{ - int cursedmen = u->number; - - if (!c) return 0; - - /* je nach curse_type andere data struct */ - if (c->type->typ == CURSETYP_UNIT) { - cursedmen = c->data.i; - } - - return MIN(u->number, cursedmen); -} - -/* setzt die Anzahl der betroffenen Personen auf cursedmen */ -static void -set_cursedmen(curse *c, int cursedmen) -{ - if (!c) return; - - /* je nach curse_type andere data struct */ - if (c->type->typ == CURSETYP_UNIT) { - c->data.i = cursedmen; - } -} - -/* ------------------------------------------------------------- */ -/* Legt eine neue Verzauberung an. Sollte es schon einen Zauber - * dieses Typs geben, gibt es den bestehenden zurück. - */ -static curse * -make_curse(unit *mage, attrib **ap, const curse_type *ct, double vigour, - int duration, double effect, int men) -{ - curse *c; - attrib * a; - - a = a_new(&at_curse); - a_add(ap, a); - c = (curse*)a->data.v; - - c->type = ct; - c->flags = 0; - c->vigour = vigour; - c->duration = duration; - c->effect = effect; - c->magician = mage; - - c->no = newunitid(); - chash(c); - - switch (c->type->typ) { - case CURSETYP_NORM: - break; - - case CURSETYP_UNIT: - { - c->data.i = men; - break; - } - - } - return c; -} - - -/* Mapperfunktion für das Anlegen neuer curse. Automatisch wird zum - * passenden Typ verzweigt und die relevanten Variablen weitergegeben. - */ -curse * -create_curse(unit *magician, attrib **ap, const curse_type *ct, double vigour, - int duration, double effect, int men) -{ - curse *c; - - /* die Kraft eines Spruchs darf nicht 0 sein*/ - assert(vigour > 0); - - c = get_curse(*ap, ct); - - if (c && (c_flags(c) & CURSE_ONLYONE)){ - return NULL; - } - assert(c==NULL || ct==c->type); - - /* es gibt schon eins diese Typs */ - if (c && ct->mergeflags != NO_MERGE) { - if(ct->mergeflags & M_DURATION){ - c->duration = MAX(c->duration, duration); - } - if(ct->mergeflags & M_SUMDURATION){ - c->duration += duration; - } - if(ct->mergeflags & M_SUMEFFECT){ - c->effect += effect; - } - if(ct->mergeflags & M_MAXEFFECT){ - c->effect = MAX(c->effect, effect); - } - if(ct->mergeflags & M_VIGOUR){ - c->vigour = MAX(vigour, c->vigour); - } - if(ct->mergeflags & M_VIGOUR_ADD){ - c->vigour = vigour + c->vigour; - } - if(ct->mergeflags & M_MEN){ - switch (ct->typ) { - case CURSETYP_UNIT: - { - c->data.i += men; - } - } - } - set_curseingmagician(magician, *ap, ct); - } else { - c = make_curse(magician, ap, ct, vigour, duration, effect, men); - } - return c; -} - -/* ------------------------------------------------------------- */ -/* hier müssen alle c-typen, die auf Einheiten gezaubert werden können, - * berücksichtigt werden */ - -static void -do_transfer_curse(curse *c, unit * u, unit * u2, int n) -{ - int cursedmen = 0; - int men = get_cursedmen(u, c); - boolean dogive = false; - const curse_type *ct = c->type; - - switch ((ct->flags | c->flags) & CURSE_SPREADMASK) { - case CURSE_SPREADALWAYS: - dogive = true; - men = u2->number + n; - break; - - case CURSE_SPREADMODULO: - { - int i; - int u_number = u->number; - for (i=0;i0;i++){ - if (rng_int()%u_number < cursedmen){ - ++men; - --cursedmen; - dogive = true; - } - --u_number; - } - break; - } - case CURSE_SPREADCHANCE: - if (chance(u2->number/(double)(u2->number + n))) { - men = u2->number + n; - dogive = true; - } - break; - case CURSE_SPREADNEVER: - break; - } - - if (dogive == true) { - curse * cnew = make_curse(c->magician, &u2->attribs, c->type, c->vigour, - c->duration, c->effect, men); - cnew->flags = c->flags; - - if (ct->typ == CURSETYP_UNIT) set_cursedmen(cnew, men); - } -} - -void -transfer_curse(unit * u, unit * u2, int n) -{ - attrib * a; - - a = a_find(u->attribs, &at_curse); - while (a && a->type==&at_curse) { - curse *c = (curse*)a->data.v; - do_transfer_curse(c, u, u2, n); - a = a->next; - } -} - -/* ------------------------------------------------------------- */ - -boolean -curse_active(const curse *c) -{ - if (!c) return false; - if (c_flags(c) & CURSE_ISNEW) return false; - if (c->vigour <= 0) return false; - - return true; -} - -boolean -is_cursed_internal(attrib *ap, const curse_type *ct) -{ - curse *c = get_curse(ap, ct); - - if (!c) - return false; - - return true; -} - - -boolean -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)) { - return true; - } - a = a->next; - } - - return false; -} -/* ------------------------------------------------------------- */ -/* cursedata */ -/* ------------------------------------------------------------- */ -/* - * typedef struct curse_type { - * const char *cname; (Name der Zauberwirkung, Identifizierung des curse) - * int typ; - * spread_t spread; - * unsigned int mergeflags; - * int (*curseinfo)(const struct locale*, const void*, int, curse*, int); - * void (*change_vigour)(curse*, double); - * int (*read)(struct storage * store, curse * c); - * int (*write)(struct storage * store, const curse * c); - * } curse_type; - */ - -int -resolve_curse(variant id, void * address) -{ - int result = 0; - curse * c = NULL; - if (id.i!=0) { - c = cfindhash(id.i); - if (c==NULL) { - result = -1; - } - } - *(curse**)address = c; - return result; -} - -static const char * oldnames[MAXCURSE] = { - /* OBS: when removing curses, remember to update read_ccompat() */ - "fogtrap", - "antimagiczone", - "farvision", - "gbdream", - "auraboost", - "maelstrom", - "blessedharvest", - "drought", - "badlearn", - "stormwind", - "flyingship", - "nodrift", - "depression", - "magicwalls", - "strongwall", - "astralblock", - "generous", - "peacezone", - "magicstreet", - "magicrunes", - "badmagicresistancezone", - "goodmagicresistancezone", - "slavery", - "calmmonster", - "oldrace", - "fumble", - "riotzone", - "nocostbuilding", - "godcursezone", - "speed", - "orcish", - "magicboost", - "insectfur", - "strength", - "worse", - "magicresistance", - "itemcloak", - "sparkle", - "skillmod" -}; - -const char * -oldcursename(int id) -{ - return oldnames[id]; -} - -/* ------------------------------------------------------------- */ -message * -cinfo_simple(const void * obj, typ_t typ, const struct curse *c, int self) -{ - struct message * msg; - - unused(typ); - unused(self); - unused(obj); - - msg = msg_message(mkname("curseinfo", c->type->cname), "id", c->no); - if (msg==NULL) { - log_error(("There is no curseinfo for %s.\n", c->type->cname)); - } - return msg; -} - - -/* ------------------------------------------------------------- */ -/* Antimagie - curse auflösen */ -/* ------------------------------------------------------------- */ - -/* Wenn der Curse schwächer ist als der cast_level, dann wird er -* aufgelöst, bzw seine Kraft (vigour) auf 0 gesetzt. -* Ist der cast_level zu gering, hat die Antimagie nur mit einer Chance -* von 100-20*Stufenunterschied % eine Wirkung auf den Curse. Dann wird -* die Kraft des Curse um die halbe Stärke der Antimagie reduziert. -* Zurückgegeben wird der noch unverbrauchte Rest von force. -*/ -double -destr_curse(curse* c, int cast_level, double force) -{ - if (cast_level < c->vigour) { /* Zauber ist nicht stark genug */ - double probability = 0.1 + (cast_level - c->vigour)*0.2; - /* pro Stufe Unterschied -20% */ - if (chance(probability)) { - force -= c->vigour; - if (c->type->change_vigour) { - c->type->change_vigour(c, -(cast_level+1/2)); - } else { - c->vigour -= cast_level+1/2; - } - } - } else { /* Zauber ist stärker als curse */ - if (force >= c->vigour) { /* reicht die Kraft noch aus? */ - force -= c->vigour; - if (c->type->change_vigour) { - c->type->change_vigour(c, -c->vigour); - } else { - c->vigour = 0; - } - - } - } - return force; -} - -#ifndef DISABLE_TESTS -#include "curse_test.c" -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "curse.h" + +/* kernel includes */ +#include "building.h" +#include "faction.h" +#include "magic.h" +#include "message.h" +#include "objtypes.h" +#include "race.h" +#include "region.h" +#include "ship.h" +#include "skill.h" +#include "unit.h" +#include "version.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include + +#include + +#define MAXENTITYHASH 7919 +curse *cursehash[MAXENTITYHASH]; + +void +c_setflag(curse *c, unsigned int flags) +{ + assert(c); + c->flags = (c->flags & ~flags) | (flags & (c->type->flags ^ flags)); +} +/* -------------------------------------------------------------------------- */ +void +c_clearflag(curse *c, unsigned int flags) +{ + assert(c); + c->flags = (c->flags & ~flags) | (c->type->flags & flags); +} + +void +chash(curse *c) +{ + curse *old = cursehash[c->no %MAXENTITYHASH]; + + cursehash[c->no %MAXENTITYHASH] = c; + c->nexthash = old; +} + +static void +cunhash(curse *c) +{ + curse **show; + + for (show = &cursehash[c->no % MAXENTITYHASH]; *show; show = &(*show)->nexthash) { + if ((*show)->no == c->no) + break; + } + if (*show) { + assert(*show == c); + *show = (*show)->nexthash; + c->nexthash = 0; + } +} + +curse * +cfindhash(int i) +{ + curse *old; + + for (old = cursehash[i % MAXENTITYHASH]; old; old = old->nexthash) + if (old->no == i) + return old; + return NULL; +} + +/* ------------------------------------------------------------- */ +/* at_curse */ +void +curse_init(attrib * a) { + a->data.v = calloc(1, sizeof(curse)); +} + +int +curse_age(attrib * a) +{ + curse * c = (curse*)a->data.v; + int result = 0; + + if (c_flags(c) & CURSE_NOAGE) { + c->duration = INT_MAX; + } + if (c->type->age) { + result = c->type->age(c); + } + if (result!=0) { + c->duration = 0; + } else if (c->duration!=INT_MAX) { + c->duration = MAX(0, c->duration-1); + } + return c->duration; +} + +void +destroy_curse(curse * c) +{ + cunhash(c); + free(c); +} + +void +curse_done(attrib * a) { + destroy_curse((curse *)a->data.v); +} + +/** reads curses that have been removed from the code */ +static int +read_ccompat(const char * cursename, struct storage * store) +{ + struct compat { + const char * name; + const char * tokens; + } * seek, old_curses[] = { {"disorientationzone", ""}, {"shipdisorientation", ""}, { NULL, NULL } } ; + for (seek=old_curses;seek->name;++seek) { + if (strcmp(seek->tokens, cursename)==0) { + const char * p; + for (p=seek->name;p;++p) { + switch (*p) { + case 'd': store->r_int(store); break; + case 's': store->r_str(store); break; + case 't': store->r_tok(store); break; + case 'i': store->r_id(store); break; + case 'f': store->r_flt(store); break; + } + } + return 0; + } + } + return -1; +} + +int +curse_read(attrib * a, void * owner, struct storage * store) +{ + curse * c = (curse*)a->data.v; + int ur; + char cursename[64]; + unsigned int flags; + + c->no = store->r_int(store); + chash(c); + store->r_tok_buf(store, cursename, sizeof(cursename)); + flags = store->r_int(store); + c->duration = store->r_int(store); + if (store->version >= CURSEVIGOURISFLOAT_VERSION) { + c->vigour = store->r_flt(store); + } else { + int vigour = store->r_int(store); + c->vigour = vigour; + } + if (store->versionmagician, store, read_int, resolve_unit); + } else { + ur = read_reference(&c->magician, store, read_unit_reference, resolve_unit); + } + if (store->versioneffect = (double)store->r_int(store); + } else { + c->effect = store->r_flt(store); + } + c->type = ct_find(cursename); + if (c->type==NULL) { + int result = read_ccompat(cursename, store); + if (result!=0) { + log_error(("missing curse %s, no compatibility code either.\n", cursename)); + } + assert(result==0); + return AT_READ_FAIL; + } + if (store->version < CURSEFLAGS_VERSION) { + c_setflag(c, flags); + } else { + c->flags = flags; + } + c_clearflag(c, CURSE_ISNEW); + + if (c->type->read) c->type->read(store, c, owner); + else if (c->type->typ==CURSETYP_UNIT) { + c->data.i = store->r_int(store); + } + if (c->type->typ == CURSETYP_REGION) { + int rr = read_reference(&c->data.v, store, read_region_reference, RESOLVE_REGION(store->version)); + if (ur==0 && rr==0 && !c->data.v) { + return AT_READ_FAIL; + } + } + + return AT_READ_OK; +} + +void +curse_write(const attrib * a, const void * owner, struct storage * store) +{ + unsigned int flags; + curse * c = (curse*)a->data.v; + const curse_type * ct = c->type; + unit * mage = (c->magician && c->magician->number)?c->magician:NULL; + + /* copied from c_clearflag */ + flags = (c->flags & ~CURSE_ISNEW) | (c->type->flags & CURSE_ISNEW); + + store->w_int(store, c->no); + store->w_tok(store, ct->cname); + store->w_int(store, flags); + store->w_int(store, c->duration); + store->w_flt(store, (float)c->vigour); + write_unit_reference(mage, store); + store->w_flt(store, (float)c->effect); + + if (c->type->write) c->type->write(store, c, owner); + else if (c->type->typ == CURSETYP_UNIT) { + store->w_int(store, c->data.i); + } + if (c->type->typ == CURSETYP_REGION) { + write_region_reference((region*)c->data.v, store); + } +} + +attrib_type at_curse = +{ + "curse", + curse_init, + curse_done, + curse_age, + curse_write, + curse_read, + ATF_CURSE +}; +/* ------------------------------------------------------------- */ +/* Spruch identifizieren */ + +#include + +typedef struct cursetype_list { + struct cursetype_list * next; + const curse_type * type; +} cursetype_list; + +cursetype_list * cursetypes[256]; + +void +ct_register(const curse_type * ct) +{ + unsigned int hash = tolower(ct->cname[0]); + cursetype_list ** ctlp = &cursetypes[hash]; + + while (*ctlp) { + cursetype_list * ctl = *ctlp; + if (ctl->type==ct) return; + ctlp=&ctl->next; + } + *ctlp = calloc(1, sizeof(cursetype_list)); + (*ctlp)->type = ct; +} + +const curse_type * +ct_find(const char *c) +{ + unsigned int hash = tolower(c[0]); + cursetype_list * ctl = cursetypes[hash]; + while (ctl) { + if (strcmp(c, ctl->type->cname)==0) { + return ctl->type; + } else { + size_t k = MIN(strlen(c), strlen(ctl->type->cname)); + if (!strncasecmp(c, ctl->type->cname, k)) { + return ctl->type; + } + } + ctl = ctl->next; + } + return NULL; +} + +/* ------------------------------------------------------------- */ +/* get_curse identifiziert eine Verzauberung über die ID und gibt + * einen pointer auf die struct zurück. + */ + +boolean +cmp_curse(const attrib * a, const void * data) { + const curse * c = (const curse*)data; + if (a->type->flags & ATF_CURSE) { + if (!data || c == (curse*)a->data.v) return true; + } + return false; +} + +boolean +cmp_cursetype(const attrib * a, const void * data) +{ + const curse_type * ct = (const curse_type *)data; + if (a->type->flags & ATF_CURSE) { + if (!data || ct == ((curse*)a->data.v)->type) return true; + } + return false; +} + +curse * +get_cursex(attrib *ap, const curse_type * ctype, variant data, boolean(*compare)(const curse *, variant)) +{ + attrib * a = a_select(ap, ctype, cmp_cursetype); + while (a) { + curse * c = (curse*)a->data.v; + if (compare(c, data)) return c; + a = a_select(a->next, ctype, cmp_cursetype); + } + return NULL; +} + +curse * +get_curse(attrib *ap, const curse_type * ctype) +{ + attrib * a = ap; + while (a) { + if (a->type->flags & ATF_CURSE) { + const attrib_type * at = a->type; + while (a && a->type==at) { + curse* c = (curse *)a->data.v; + if (c->type==ctype) return c; + a = a->next; + } + } else { + a = a->nexttype; + } + } + return NULL; +} + +/* ------------------------------------------------------------- */ +/* findet einen curse global anhand seiner 'curse-Einheitnummer' */ + +curse * +findcurse(int cid) +{ + return cfindhash(cid); +} + +/* ------------------------------------------------------------- */ +void +remove_curse(attrib **ap, const curse *c) +{ + attrib *a = a_select(*ap, c, cmp_curse); + if (a) a_remove(ap, a); +} + +/* gibt die allgemeine Stärke der Verzauberung zurück. id2 wird wie + * oben benutzt. Dies ist nicht die Wirkung, sondern die Kraft und + * damit der gegen Antimagie wirkende Widerstand einer Verzauberung */ +static double +get_cursevigour(const curse *c) +{ + if (c) return c->vigour; + return 0; +} + +/* setzt die Stärke der Verzauberung auf i */ +static void +set_cursevigour(curse *c, double vigour) +{ + assert(c && vigour > 0); + c->vigour = vigour; +} + +/* verändert die Stärke der Verzauberung um +i und gibt die neue + * Stärke zurück. Sollte die Zauberstärke unter Null sinken, löst er + * sich auf. + */ +double +curse_changevigour(attrib **ap, curse *c, double vigour) +{ + vigour += get_cursevigour(c); + + if (vigour <= 0) { + remove_curse(ap, c); + vigour = 0; + } else { + set_cursevigour(c, vigour); + } + return vigour; +} + +/* ------------------------------------------------------------- */ + +double +curse_geteffect(const curse *c) +{ + if (c==NULL) return 0; + if (c_flags(c) & CURSE_ISNEW) return 0; + return c->effect; +} + +int +curse_geteffect_int(const curse *c) +{ + double effect = curse_geteffect(c); + assert(effect-(int)effect == 0); + return (int)effect; +} + +/* ------------------------------------------------------------- */ +static void +set_curseingmagician(struct unit *magician, struct attrib *ap_target, const curse_type *ct) +{ + curse * c = get_curse(ap_target, ct); + if (c) { + c->magician = magician; + } +} + +/* ------------------------------------------------------------- */ +/* gibt bei Personenbeschränkten Verzauberungen die Anzahl der + * betroffenen Personen zurück. Ansonsten wird 0 zurückgegeben. */ +int +get_cursedmen(unit *u, const curse *c) +{ + int cursedmen = u->number; + + if (!c) return 0; + + /* je nach curse_type andere data struct */ + if (c->type->typ == CURSETYP_UNIT) { + cursedmen = c->data.i; + } + + return MIN(u->number, cursedmen); +} + +/* setzt die Anzahl der betroffenen Personen auf cursedmen */ +static void +set_cursedmen(curse *c, int cursedmen) +{ + if (!c) return; + + /* je nach curse_type andere data struct */ + if (c->type->typ == CURSETYP_UNIT) { + c->data.i = cursedmen; + } +} + +/* ------------------------------------------------------------- */ +/* Legt eine neue Verzauberung an. Sollte es schon einen Zauber + * dieses Typs geben, gibt es den bestehenden zurück. + */ +static curse * +make_curse(unit *mage, attrib **ap, const curse_type *ct, double vigour, + int duration, double effect, int men) +{ + curse *c; + attrib * a; + + a = a_new(&at_curse); + a_add(ap, a); + c = (curse*)a->data.v; + + c->type = ct; + c->flags = 0; + c->vigour = vigour; + c->duration = duration; + c->effect = effect; + c->magician = mage; + + c->no = newunitid(); + chash(c); + + switch (c->type->typ) { + case CURSETYP_NORM: + break; + + case CURSETYP_UNIT: + { + c->data.i = men; + break; + } + + } + return c; +} + + +/* Mapperfunktion für das Anlegen neuer curse. Automatisch wird zum + * passenden Typ verzweigt und die relevanten Variablen weitergegeben. + */ +curse * +create_curse(unit *magician, attrib **ap, const curse_type *ct, double vigour, + int duration, double effect, int men) +{ + curse *c; + + /* die Kraft eines Spruchs darf nicht 0 sein*/ + assert(vigour > 0); + + c = get_curse(*ap, ct); + + if (c && (c_flags(c) & CURSE_ONLYONE)){ + return NULL; + } + assert(c==NULL || ct==c->type); + + /* es gibt schon eins diese Typs */ + if (c && ct->mergeflags != NO_MERGE) { + if(ct->mergeflags & M_DURATION){ + c->duration = MAX(c->duration, duration); + } + if(ct->mergeflags & M_SUMDURATION){ + c->duration += duration; + } + if(ct->mergeflags & M_SUMEFFECT){ + c->effect += effect; + } + if(ct->mergeflags & M_MAXEFFECT){ + c->effect = MAX(c->effect, effect); + } + if(ct->mergeflags & M_VIGOUR){ + c->vigour = MAX(vigour, c->vigour); + } + if(ct->mergeflags & M_VIGOUR_ADD){ + c->vigour = vigour + c->vigour; + } + if(ct->mergeflags & M_MEN){ + switch (ct->typ) { + case CURSETYP_UNIT: + { + c->data.i += men; + } + } + } + set_curseingmagician(magician, *ap, ct); + } else { + c = make_curse(magician, ap, ct, vigour, duration, effect, men); + } + return c; +} + +/* ------------------------------------------------------------- */ +/* hier müssen alle c-typen, die auf Einheiten gezaubert werden können, + * berücksichtigt werden */ + +static void +do_transfer_curse(curse *c, unit * u, unit * u2, int n) +{ + int cursedmen = 0; + int men = get_cursedmen(u, c); + boolean dogive = false; + const curse_type *ct = c->type; + + switch ((ct->flags | c->flags) & CURSE_SPREADMASK) { + case CURSE_SPREADALWAYS: + dogive = true; + men = u2->number + n; + break; + + case CURSE_SPREADMODULO: + { + int i; + int u_number = u->number; + for (i=0;i0;i++){ + if (rng_int()%u_number < cursedmen){ + ++men; + --cursedmen; + dogive = true; + } + --u_number; + } + break; + } + case CURSE_SPREADCHANCE: + if (chance(u2->number/(double)(u2->number + n))) { + men = u2->number + n; + dogive = true; + } + break; + case CURSE_SPREADNEVER: + break; + } + + if (dogive == true) { + curse * cnew = make_curse(c->magician, &u2->attribs, c->type, c->vigour, + c->duration, c->effect, men); + cnew->flags = c->flags; + + if (ct->typ == CURSETYP_UNIT) set_cursedmen(cnew, men); + } +} + +void +transfer_curse(unit * u, unit * u2, int n) +{ + attrib * a; + + a = a_find(u->attribs, &at_curse); + while (a && a->type==&at_curse) { + curse *c = (curse*)a->data.v; + do_transfer_curse(c, u, u2, n); + a = a->next; + } +} + +/* ------------------------------------------------------------- */ + +boolean +curse_active(const curse *c) +{ + if (!c) return false; + if (c_flags(c) & CURSE_ISNEW) return false; + if (c->vigour <= 0) return false; + + return true; +} + +boolean +is_cursed_internal(attrib *ap, const curse_type *ct) +{ + curse *c = get_curse(ap, ct); + + if (!c) + return false; + + return true; +} + + +boolean +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)) { + return true; + } + a = a->next; + } + + return false; +} +/* ------------------------------------------------------------- */ +/* cursedata */ +/* ------------------------------------------------------------- */ +/* + * typedef struct curse_type { + * const char *cname; (Name der Zauberwirkung, Identifizierung des curse) + * int typ; + * spread_t spread; + * unsigned int mergeflags; + * int (*curseinfo)(const struct locale*, const void*, int, curse*, int); + * void (*change_vigour)(curse*, double); + * int (*read)(struct storage * store, curse * c); + * int (*write)(struct storage * store, const curse * c); + * } curse_type; + */ + +int +resolve_curse(variant id, void * address) +{ + int result = 0; + curse * c = NULL; + if (id.i!=0) { + c = cfindhash(id.i); + if (c==NULL) { + result = -1; + } + } + *(curse**)address = c; + return result; +} + +static const char * oldnames[MAXCURSE] = { + /* OBS: when removing curses, remember to update read_ccompat() */ + "fogtrap", + "antimagiczone", + "farvision", + "gbdream", + "auraboost", + "maelstrom", + "blessedharvest", + "drought", + "badlearn", + "stormwind", + "flyingship", + "nodrift", + "depression", + "magicwalls", + "strongwall", + "astralblock", + "generous", + "peacezone", + "magicstreet", + "magicrunes", + "badmagicresistancezone", + "goodmagicresistancezone", + "slavery", + "calmmonster", + "oldrace", + "fumble", + "riotzone", + "nocostbuilding", + "godcursezone", + "speed", + "orcish", + "magicboost", + "insectfur", + "strength", + "worse", + "magicresistance", + "itemcloak", + "sparkle", + "skillmod" +}; + +const char * +oldcursename(int id) +{ + return oldnames[id]; +} + +/* ------------------------------------------------------------- */ +message * +cinfo_simple(const void * obj, typ_t typ, const struct curse *c, int self) +{ + struct message * msg; + + unused(typ); + unused(self); + unused(obj); + + msg = msg_message(mkname("curseinfo", c->type->cname), "id", c->no); + if (msg==NULL) { + log_error(("There is no curseinfo for %s.\n", c->type->cname)); + } + return msg; +} + + +/* ------------------------------------------------------------- */ +/* Antimagie - curse auflösen */ +/* ------------------------------------------------------------- */ + +/* Wenn der Curse schwächer ist als der cast_level, dann wird er +* aufgelöst, bzw seine Kraft (vigour) auf 0 gesetzt. +* Ist der cast_level zu gering, hat die Antimagie nur mit einer Chance +* von 100-20*Stufenunterschied % eine Wirkung auf den Curse. Dann wird +* die Kraft des Curse um die halbe Stärke der Antimagie reduziert. +* Zurückgegeben wird der noch unverbrauchte Rest von force. +*/ +double +destr_curse(curse* c, int cast_level, double force) +{ + if (cast_level < c->vigour) { /* Zauber ist nicht stark genug */ + double probability = 0.1 + (cast_level - c->vigour)*0.2; + /* pro Stufe Unterschied -20% */ + if (chance(probability)) { + force -= c->vigour; + if (c->type->change_vigour) { + c->type->change_vigour(c, -(cast_level+1/2)); + } else { + c->vigour -= cast_level+1/2; + } + } + } else { /* Zauber ist stärker als curse */ + if (force >= c->vigour) { /* reicht die Kraft noch aus? */ + force -= c->vigour; + if (c->type->change_vigour) { + c->type->change_vigour(c, -c->vigour); + } else { + c->vigour = 0; + } + + } + } + return force; +} + +#ifndef DISABLE_TESTS +#include "curse_test.c" +#endif diff --git a/src/kernel/curse.h b/src/kernel/curse.h index 7adb53477..6c6621b5c 100644 --- a/src/kernel/curse.h +++ b/src/kernel/curse.h @@ -1,330 +1,330 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef CURSE_H -#define CURSE_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* Sprueche in der struct region und auf Einheiten, Schiffen oder Burgen - * (struct attribute) - */ - -/* Brainstorming Überarbeitung curse - * - * Ziel: Keine Enum-Liste, flexible, leicht erweiterbare Curse-Objekte - * - * Was wird gebraucht? - * - Eindeutige Kennung für globale Suche - * - eine Wirkung, die sich einfach 'anwenden' läßt, dabei flexibel ist, - * Raum läßt für variable Boni, Anzahl betroffener Personen, - * spezielle Effekte oder anderes - * - einfacher Zugriff auf allgemeine Funktionen wie zb Alterung, aber - * auch Antimagieverhalten - * - Ausgabe von Beschreibungen in verschiedenen Sprachen - * - definiertes gekapseltes Verhalten zb bei Zusammenlegung von - * Einheiten, Übergabe von Personen, Mehrfachverzauberung - * - (Rück-)Referenzen auf Objekt, Verursacher (Magier), ? - * - * Vieleicht wäre ein Wirkungsklassensystem sinnvoll, so das im übrigen - * source einfach alle curse-attribs abgefragt werden können und bei - * gewünschter Wirkungsklasse angewendet, also nicht für jeden curse - * spezielle Änderungen im übrigen source notwendig sind. - * - * Die (Wirkungs-)Typen sollten die wichtigen Funktionen speziell - * belegen können, zb Alterung, Ausgabetexte, Merge-Verhalten - * - * Was sind wichtige individuelle Eigenschaften? - * - Referenzen auf Objekt und Verursacher - * - Referenzen für globale Liste - * > die Wirkung: - * - Dauer - * - Widerstandskraft, zb gegen Antimagie - * - Seiteneffekte zb Flag ONLYONE, Unverträglichkeiten - * - Alterungsverhalten zb Flag NOAGE - * - Effektverhalten, zb Bonus (variabel) - * - bei Einheitenzaubern die Zahl der betroffenen Personen - * - * Dabei sind nur die beiden letzten Punkte wirklich reine individuelle - * Wirkung, die anderen sind eher allgemeine Kennzeichen eines jeden - * Curse, die individuell belegt sind. - * ONLYONE und NOAGE könnten auch Eigenschaften des Typs sein, nicht des - * individuellen curse. Allgemein ist Alterung wohl eher eine - * Typeigenschaft als die eines individuellen curse. - * Dagegen ist der Widerstand gegen Antimagie sowohl abhängig von der - * Güte des Verursachers, also des Magiers zum Zeitpunkt des Zaubers, - * als auch vom Typ, der gegen bestimmte Arten des 'Fluchbrechens' immun - * sein könnte. - * - * Was sind wichtige Typeigenschaften? - * - Verhalten bei Personenübergaben - * - allgemeine Wirkung - * - Beschreibungstexte - * - Verhalten bei Antimagie - * - Alterung - * - Speicherung des C-Objekts - * - Laden des C-Objekts - * - Erzeugen des C-Objekts - * - Löschen und Aufräumen des C-Objekts - * - Funktionen zur Änderung der Werte - * - * */ - -#include - -/* ------------------------------------------------------------- */ -/* Zauberwirkungen */ -/* nicht vergessen curse_type zu aktualisieren und Reihenfolge beachten! - */ - -enum { -/* struct's vom typ curse: */ - C_FOGTRAP, - C_ANTIMAGICZONE, - C_FARVISION, - C_GBDREAM, - C_AURA, - C_MAELSTROM, - C_BLESSEDHARVEST, - C_DROUGHT, - C_BADLEARN, - C_SHIP_SPEEDUP, /* 9 - Sturmwind-Zauber */ - C_SHIP_FLYING, /* 10 - Luftschiff-Zauber */ - C_SHIP_NODRIFT, /* 11 - GünstigeWinde-Zauber */ - C_DEPRESSION, - C_MAGICWALLS, /* 13 - Heimstein */ - C_STRONGWALL, /* 14 - Feste Mauer - Precombat*/ - C_ASTRALBLOCK, /* 15 - Astralblock */ - C_GENEROUS, /* 16 - Unterhaltung vermehren */ - C_PEACE, /* 17 - Regionsweit Attacken verhindern */ - C_MAGICSTREET, /* 19 - magisches Straßennetz */ - C_RESIST_MAGIC, /* 20 - verändert Magieresistenz von Objekten */ - C_SONG_BADMR, /* 21 - verändert Magieresistenz */ - C_SONG_GOODMR, /* 22 - verändert Magieresistenz */ - C_SLAVE, /* 23 - dient fremder Partei */ - C_CALM, /* 25 - Beinflussung */ - C_OLDRACE, - C_FUMBLE, - C_RIOT, /*region in Aufruhr */ - C_NOCOST, - C_CURSED_BY_THE_GODS, -/* struct's vom untertyp curse_unit: */ - C_SPEED, /* Beschleunigt */ - C_ORC, - C_MBOOST, - C_KAELTESCHUTZ, - C_STRENGTH, - C_ALLSKILLS, - C_MAGICRESISTANCE, /* 44 - verändert Magieresistenz */ - C_ITEMCLOAK, - C_SPARKLE, -/* struct's vom untertyp curse_skill: */ - C_SKILL, - MAXCURSE /* OBS: when removing curses, remember to update read_ccompat() */ -}; - -/* ------------------------------------------------------------- */ -/* Flags */ - - -/* Verhalten von Zaubern auf Units beim Übergeben von Personen */ -typedef enum { - CURSE_ISNEW = 0x01, /* wirkt in der zauberrunde nicht (default)*/ - CURSE_NOAGE = 0x02, /* wirkt ewig */ - CURSE_IMMUNE = 0x04, /* ignoriert Antimagie */ - CURSE_ONLYONE = 0x08, /* Verhindert, das ein weiterer Zauber dieser Art auf das Objekt gezaubert wird */ - - /* the following are mutually exclusive */ - CURSE_SPREADNEVER = 0x00, /* wird nie mit übertragen */ - CURSE_SPREADALWAYS = 0x10, /* wird immer mit übertragen */ - CURSE_SPREADMODULO = 0x20, /* personenweise weitergabe */ - CURSE_SPREADCHANCE = 0x30 /* Ansteckungschance je nach Mengenverhältnis*/ -} curseflags; - -#define CURSE_FLAGSMASK 0x0F -#define CURSE_SPREADMASK 0x30 - -/* typ von struct */ -enum { - CURSETYP_NORM, - CURSETYP_UNIT, - CURSETYP_REGION, /* stores the region in c->data.v */ - MAXCURSETYP -}; - -/* Verhalten beim Zusammenfassen mit einem schon bestehenden Zauber - * gleichen Typs */ - -#define NO_MERGE 0 /* erzeugt jedesmal einen neuen Zauber */ -#define M_DURATION 1 /* Die Zauberdauer ist die maximale Dauer beider */ -#define M_SUMDURATION 2 /* die Dauer des Zaubers wird summiert */ -#define M_MAXEFFECT 4 /* der Effekt ist der maximale Effekt beider */ -#define M_SUMEFFECT 8 /* der Effekt summiert sich */ -#define M_MEN 16 /* die Anzahl der betroffenen Personen summiert - sich */ -#define M_VIGOUR 32 /* das Maximum der beiden Stärken wird die - Stärke des neuen Zaubers */ -#define M_VIGOUR_ADD 64 /* Vigour wird addiert */ - -/* ------------------------------------------------------------- */ -/* Allgemeine Zauberwirkungen */ - -typedef struct curse { - struct curse *nexthash; - int no; /* 'Einheitennummer' dieses Curse */ - const struct curse_type * type; /* Zeiger auf ein curse_type-struct */ - unsigned int flags; /* WARNING: these are XORed with type->flags! */ - int duration; /* Dauer der Verzauberung. Wird jede Runde vermindert */ - double vigour; /* Stärke der Verzauberung, Widerstand gegen Antimagie */ - struct unit *magician; /* Pointer auf den Magier, der den Spruch gewirkt hat */ - double effect; - variant data; /* pointer auf spezielle curse-unterstructs*/ -} curse; - -#define c_flags(c) ((c)->type->flags ^ (c)->flags) - -/* ------------------------------------------------------------- */ - -typedef struct curse_type { - const char *cname; /* Name der Zauberwirkung, Identifizierung des curse */ - int typ; - unsigned int flags; - unsigned int mergeflags; - struct message * (*curseinfo)(const void*, typ_t, const struct curse*, int); - void (*change_vigour)(curse*, double); - int (*read)(struct storage * store, curse * c, void * target); - int (*write)(struct storage * store, const struct curse * c, const void * target); - int (*cansee)(const struct faction*, const void*, typ_t, const struct curse *, int); - int (*age)(curse *); -} curse_type; - -extern struct attrib_type at_curse; -void curse_write(const struct attrib * a, const void * owner, struct storage * store); -int curse_read(struct attrib * a, void * owner, struct storage * store); - - -/* ------------------------------------------------------------- */ -/* Kommentare: - * Bei einigen Typen von Verzauberungen (z.B.Skillmodif.) muss neben - * der curse-id noch ein weiterer Identifizierer angegeben werden (id2). - * - * Wenn der Typ korrekt definiert wurde, erfolgt die Verzweigung zum - * korrekten Typus automatisch, und die unterschiedlichen struct-typen - * sind nach aussen unsichtbar. - * -* allgemeine Funktionen * -*/ - -curse * create_curse(struct unit *magician, struct attrib**ap, const curse_type * ctype, - double vigour, int duration, double ceffect, int men); - /* Verzweigt automatisch zum passenden struct-typ. Sollte es schon - * einen Zauber dieses Typs geben, so wird der neue dazuaddiert. Die - * Zahl der verzauberten Personen sollte beim Aufruf der Funktion - * nochmal gesondert auf min(get_cursedmen, u->number) gesetzt werden. - */ - -extern void destroy_curse(curse * c); - - -boolean is_cursed_internal(struct attrib *ap, const curse_type * ctype); - /* ignoriert CURSE_ISNEW */ - -extern void remove_curse(struct attrib **ap, const struct curse * c); - /* löscht einen konkreten Spruch auf einem Objekt. - */ - -extern int curse_geteffect_int(const struct curse * c); -extern double curse_geteffect(const struct curse * c); - /* gibt die Auswirkungen der Verzauberungen zurück. zB bei - * Skillmodifiziernden Verzauberungen ist hier der Modifizierer - * gespeichert. Wird automatisch beim Anlegen eines neuen curse - * gesetzt. Gibt immer den ersten Treffer von ap aus zurück. - */ - - -extern double curse_changevigour(struct attrib **ap, curse * c, double i); - /* verändert die Stärke der Verzauberung um i */ - -extern int get_cursedmen(struct unit *u, const struct curse *c); - /* gibt bei Personenbeschränkten Verzauberungen die Anzahl der - * betroffenen Personen zurück. Ansonsten wird 0 zurückgegeben. */ - -extern void c_setflag(curse * c, unsigned int flag); -extern void c_clearflag(curse *c, unsigned int flags); - /* setzt/loescht Spezialflag einer Verzauberung (zB 'dauert ewig') */ - -void transfer_curse(struct unit * u, struct unit * u2, int n); - /* sorgt dafür, das bei der Übergabe von Personen die curse-attribute - * korrekt gehandhabt werden. Je nach internen Flag kann dies - * unterschiedlich gewünscht sein - * */ - -extern struct curse * get_cursex(struct attrib *ap, const curse_type * ctype, variant data, - boolean(*compare)(const struct curse *, variant)); - /* gibt pointer auf die erste curse-struct zurück, deren Typ ctype ist, - * und für die compare() true liefert, oder einen NULL-pointer. - * */ -extern struct curse * get_curse(struct attrib *ap, const curse_type * ctype); - /* gibt pointer auf die erste curse-struct zurück, deren Typ ctype ist, - * oder einen NULL-pointer - * */ - -int find_cursebyname(const char *c); -const curse_type * ct_find(const char *c); -void ct_register(const curse_type *); -/* Regionszauber */ - -curse * cfindhash(int i); - -curse * findcurse(int curseid); - -extern void curse_init(struct attrib * a); -extern void curse_done(struct attrib * a); -extern int curse_age(struct attrib * a); - -extern boolean cmp_curse(const struct attrib * a, const void * data); -extern boolean cmp_cursetype(const struct attrib * a, const void * data); - -extern double destr_curse(struct curse* c, int cast_level, double force); - -extern int resolve_curse(variant data, void * address); -extern boolean is_cursed_with(const struct attrib *ap, const struct curse *c); - -extern boolean curse_active(const struct curse * c); - /* gibt true, wenn der Curse nicht NULL oder inaktiv ist */ - -/*** COMPATIBILITY MACROS. DO NOT USE FOR NEW CODE, REPLACE IN OLD CODE: */ -extern const char * oldcursename(int id); -extern struct message * cinfo_simple(const void * obj, typ_t typ, const struct curse *c, int self); - -#define is_cursed(a, id, id2) \ - curse_active(get_curse(a, ct_find(oldcursename(id)))) -#define get_curseeffect(a, id, id2) \ - curse_geteffect(get_curse(a, ct_find(oldcursename(id)))) - -/* eressea-defined attribute-type flags */ -#define ATF_CURSE ATF_USER_DEFINED - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CURSE_H +#define CURSE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Sprueche in der struct region und auf Einheiten, Schiffen oder Burgen + * (struct attribute) + */ + +/* Brainstorming Überarbeitung curse + * + * Ziel: Keine Enum-Liste, flexible, leicht erweiterbare Curse-Objekte + * + * Was wird gebraucht? + * - Eindeutige Kennung für globale Suche + * - eine Wirkung, die sich einfach 'anwenden' läßt, dabei flexibel ist, + * Raum läßt für variable Boni, Anzahl betroffener Personen, + * spezielle Effekte oder anderes + * - einfacher Zugriff auf allgemeine Funktionen wie zb Alterung, aber + * auch Antimagieverhalten + * - Ausgabe von Beschreibungen in verschiedenen Sprachen + * - definiertes gekapseltes Verhalten zb bei Zusammenlegung von + * Einheiten, Übergabe von Personen, Mehrfachverzauberung + * - (Rück-)Referenzen auf Objekt, Verursacher (Magier), ? + * + * Vieleicht wäre ein Wirkungsklassensystem sinnvoll, so das im übrigen + * source einfach alle curse-attribs abgefragt werden können und bei + * gewünschter Wirkungsklasse angewendet, also nicht für jeden curse + * spezielle Änderungen im übrigen source notwendig sind. + * + * Die (Wirkungs-)Typen sollten die wichtigen Funktionen speziell + * belegen können, zb Alterung, Ausgabetexte, Merge-Verhalten + * + * Was sind wichtige individuelle Eigenschaften? + * - Referenzen auf Objekt und Verursacher + * - Referenzen für globale Liste + * > die Wirkung: + * - Dauer + * - Widerstandskraft, zb gegen Antimagie + * - Seiteneffekte zb Flag ONLYONE, Unverträglichkeiten + * - Alterungsverhalten zb Flag NOAGE + * - Effektverhalten, zb Bonus (variabel) + * - bei Einheitenzaubern die Zahl der betroffenen Personen + * + * Dabei sind nur die beiden letzten Punkte wirklich reine individuelle + * Wirkung, die anderen sind eher allgemeine Kennzeichen eines jeden + * Curse, die individuell belegt sind. + * ONLYONE und NOAGE könnten auch Eigenschaften des Typs sein, nicht des + * individuellen curse. Allgemein ist Alterung wohl eher eine + * Typeigenschaft als die eines individuellen curse. + * Dagegen ist der Widerstand gegen Antimagie sowohl abhängig von der + * Güte des Verursachers, also des Magiers zum Zeitpunkt des Zaubers, + * als auch vom Typ, der gegen bestimmte Arten des 'Fluchbrechens' immun + * sein könnte. + * + * Was sind wichtige Typeigenschaften? + * - Verhalten bei Personenübergaben + * - allgemeine Wirkung + * - Beschreibungstexte + * - Verhalten bei Antimagie + * - Alterung + * - Speicherung des C-Objekts + * - Laden des C-Objekts + * - Erzeugen des C-Objekts + * - Löschen und Aufräumen des C-Objekts + * - Funktionen zur Änderung der Werte + * + * */ + +#include + +/* ------------------------------------------------------------- */ +/* Zauberwirkungen */ +/* nicht vergessen curse_type zu aktualisieren und Reihenfolge beachten! + */ + +enum { +/* struct's vom typ curse: */ + C_FOGTRAP, + C_ANTIMAGICZONE, + C_FARVISION, + C_GBDREAM, + C_AURA, + C_MAELSTROM, + C_BLESSEDHARVEST, + C_DROUGHT, + C_BADLEARN, + C_SHIP_SPEEDUP, /* 9 - Sturmwind-Zauber */ + C_SHIP_FLYING, /* 10 - Luftschiff-Zauber */ + C_SHIP_NODRIFT, /* 11 - GünstigeWinde-Zauber */ + C_DEPRESSION, + C_MAGICWALLS, /* 13 - Heimstein */ + C_STRONGWALL, /* 14 - Feste Mauer - Precombat*/ + C_ASTRALBLOCK, /* 15 - Astralblock */ + C_GENEROUS, /* 16 - Unterhaltung vermehren */ + C_PEACE, /* 17 - Regionsweit Attacken verhindern */ + C_MAGICSTREET, /* 19 - magisches Straßennetz */ + C_RESIST_MAGIC, /* 20 - verändert Magieresistenz von Objekten */ + C_SONG_BADMR, /* 21 - verändert Magieresistenz */ + C_SONG_GOODMR, /* 22 - verändert Magieresistenz */ + C_SLAVE, /* 23 - dient fremder Partei */ + C_CALM, /* 25 - Beinflussung */ + C_OLDRACE, + C_FUMBLE, + C_RIOT, /*region in Aufruhr */ + C_NOCOST, + C_CURSED_BY_THE_GODS, +/* struct's vom untertyp curse_unit: */ + C_SPEED, /* Beschleunigt */ + C_ORC, + C_MBOOST, + C_KAELTESCHUTZ, + C_STRENGTH, + C_ALLSKILLS, + C_MAGICRESISTANCE, /* 44 - verändert Magieresistenz */ + C_ITEMCLOAK, + C_SPARKLE, +/* struct's vom untertyp curse_skill: */ + C_SKILL, + MAXCURSE /* OBS: when removing curses, remember to update read_ccompat() */ +}; + +/* ------------------------------------------------------------- */ +/* Flags */ + + +/* Verhalten von Zaubern auf Units beim Übergeben von Personen */ +typedef enum { + CURSE_ISNEW = 0x01, /* wirkt in der zauberrunde nicht (default)*/ + CURSE_NOAGE = 0x02, /* wirkt ewig */ + CURSE_IMMUNE = 0x04, /* ignoriert Antimagie */ + CURSE_ONLYONE = 0x08, /* Verhindert, das ein weiterer Zauber dieser Art auf das Objekt gezaubert wird */ + + /* the following are mutually exclusive */ + CURSE_SPREADNEVER = 0x00, /* wird nie mit übertragen */ + CURSE_SPREADALWAYS = 0x10, /* wird immer mit übertragen */ + CURSE_SPREADMODULO = 0x20, /* personenweise weitergabe */ + CURSE_SPREADCHANCE = 0x30 /* Ansteckungschance je nach Mengenverhältnis*/ +} curseflags; + +#define CURSE_FLAGSMASK 0x0F +#define CURSE_SPREADMASK 0x30 + +/* typ von struct */ +enum { + CURSETYP_NORM, + CURSETYP_UNIT, + CURSETYP_REGION, /* stores the region in c->data.v */ + MAXCURSETYP +}; + +/* Verhalten beim Zusammenfassen mit einem schon bestehenden Zauber + * gleichen Typs */ + +#define NO_MERGE 0 /* erzeugt jedesmal einen neuen Zauber */ +#define M_DURATION 1 /* Die Zauberdauer ist die maximale Dauer beider */ +#define M_SUMDURATION 2 /* die Dauer des Zaubers wird summiert */ +#define M_MAXEFFECT 4 /* der Effekt ist der maximale Effekt beider */ +#define M_SUMEFFECT 8 /* der Effekt summiert sich */ +#define M_MEN 16 /* die Anzahl der betroffenen Personen summiert + sich */ +#define M_VIGOUR 32 /* das Maximum der beiden Stärken wird die + Stärke des neuen Zaubers */ +#define M_VIGOUR_ADD 64 /* Vigour wird addiert */ + +/* ------------------------------------------------------------- */ +/* Allgemeine Zauberwirkungen */ + +typedef struct curse { + struct curse *nexthash; + int no; /* 'Einheitennummer' dieses Curse */ + const struct curse_type * type; /* Zeiger auf ein curse_type-struct */ + unsigned int flags; /* WARNING: these are XORed with type->flags! */ + int duration; /* Dauer der Verzauberung. Wird jede Runde vermindert */ + double vigour; /* Stärke der Verzauberung, Widerstand gegen Antimagie */ + struct unit *magician; /* Pointer auf den Magier, der den Spruch gewirkt hat */ + double effect; + variant data; /* pointer auf spezielle curse-unterstructs*/ +} curse; + +#define c_flags(c) ((c)->type->flags ^ (c)->flags) + +/* ------------------------------------------------------------- */ + +typedef struct curse_type { + const char *cname; /* Name der Zauberwirkung, Identifizierung des curse */ + int typ; + unsigned int flags; + unsigned int mergeflags; + struct message * (*curseinfo)(const void*, typ_t, const struct curse*, int); + void (*change_vigour)(curse*, double); + int (*read)(struct storage * store, curse * c, void * target); + int (*write)(struct storage * store, const struct curse * c, const void * target); + int (*cansee)(const struct faction*, const void*, typ_t, const struct curse *, int); + int (*age)(curse *); +} curse_type; + +extern struct attrib_type at_curse; +void curse_write(const struct attrib * a, const void * owner, struct storage * store); +int curse_read(struct attrib * a, void * owner, struct storage * store); + + +/* ------------------------------------------------------------- */ +/* Kommentare: + * Bei einigen Typen von Verzauberungen (z.B.Skillmodif.) muss neben + * der curse-id noch ein weiterer Identifizierer angegeben werden (id2). + * + * Wenn der Typ korrekt definiert wurde, erfolgt die Verzweigung zum + * korrekten Typus automatisch, und die unterschiedlichen struct-typen + * sind nach aussen unsichtbar. + * +* allgemeine Funktionen * +*/ + +curse * create_curse(struct unit *magician, struct attrib**ap, const curse_type * ctype, + double vigour, int duration, double ceffect, int men); + /* Verzweigt automatisch zum passenden struct-typ. Sollte es schon + * einen Zauber dieses Typs geben, so wird der neue dazuaddiert. Die + * Zahl der verzauberten Personen sollte beim Aufruf der Funktion + * nochmal gesondert auf min(get_cursedmen, u->number) gesetzt werden. + */ + +extern void destroy_curse(curse * c); + + +boolean is_cursed_internal(struct attrib *ap, const curse_type * ctype); + /* ignoriert CURSE_ISNEW */ + +extern void remove_curse(struct attrib **ap, const struct curse * c); + /* löscht einen konkreten Spruch auf einem Objekt. + */ + +extern int curse_geteffect_int(const struct curse * c); +extern double curse_geteffect(const struct curse * c); + /* gibt die Auswirkungen der Verzauberungen zurück. zB bei + * Skillmodifiziernden Verzauberungen ist hier der Modifizierer + * gespeichert. Wird automatisch beim Anlegen eines neuen curse + * gesetzt. Gibt immer den ersten Treffer von ap aus zurück. + */ + + +extern double curse_changevigour(struct attrib **ap, curse * c, double i); + /* verändert die Stärke der Verzauberung um i */ + +extern int get_cursedmen(struct unit *u, const struct curse *c); + /* gibt bei Personenbeschränkten Verzauberungen die Anzahl der + * betroffenen Personen zurück. Ansonsten wird 0 zurückgegeben. */ + +extern void c_setflag(curse * c, unsigned int flag); +extern void c_clearflag(curse *c, unsigned int flags); + /* setzt/loescht Spezialflag einer Verzauberung (zB 'dauert ewig') */ + +void transfer_curse(struct unit * u, struct unit * u2, int n); + /* sorgt dafür, das bei der Übergabe von Personen die curse-attribute + * korrekt gehandhabt werden. Je nach internen Flag kann dies + * unterschiedlich gewünscht sein + * */ + +extern struct curse * get_cursex(struct attrib *ap, const curse_type * ctype, variant data, + boolean(*compare)(const struct curse *, variant)); + /* gibt pointer auf die erste curse-struct zurück, deren Typ ctype ist, + * und für die compare() true liefert, oder einen NULL-pointer. + * */ +extern struct curse * get_curse(struct attrib *ap, const curse_type * ctype); + /* gibt pointer auf die erste curse-struct zurück, deren Typ ctype ist, + * oder einen NULL-pointer + * */ + +int find_cursebyname(const char *c); +const curse_type * ct_find(const char *c); +void ct_register(const curse_type *); +/* Regionszauber */ + +curse * cfindhash(int i); + +curse * findcurse(int curseid); + +extern void curse_init(struct attrib * a); +extern void curse_done(struct attrib * a); +extern int curse_age(struct attrib * a); + +extern boolean cmp_curse(const struct attrib * a, const void * data); +extern boolean cmp_cursetype(const struct attrib * a, const void * data); + +extern double destr_curse(struct curse* c, int cast_level, double force); + +extern int resolve_curse(variant data, void * address); +extern boolean is_cursed_with(const struct attrib *ap, const struct curse *c); + +extern boolean curse_active(const struct curse * c); + /* gibt true, wenn der Curse nicht NULL oder inaktiv ist */ + +/*** COMPATIBILITY MACROS. DO NOT USE FOR NEW CODE, REPLACE IN OLD CODE: */ +extern const char * oldcursename(int id); +extern struct message * cinfo_simple(const void * obj, typ_t typ, const struct curse *c, int self); + +#define is_cursed(a, id, id2) \ + curse_active(get_curse(a, ct_find(oldcursename(id)))) +#define get_curseeffect(a, id, id2) \ + curse_geteffect(get_curse(a, ct_find(oldcursename(id)))) + +/* eressea-defined attribute-type flags */ +#define ATF_CURSE ATF_USER_DEFINED + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/curse_test.c b/src/kernel/curse_test.c index 0445995bc..d0d11d2d8 100644 --- a/src/kernel/curse_test.c +++ b/src/kernel/curse_test.c @@ -1,23 +1,23 @@ -#include - -static void test_curse(CuTest * tc) { - attrib * attrs = NULL; - curse * c, * result; - int cid; - - curse_type ct_dummy = { "dummy", CURSETYP_NORM, 0, M_SUMEFFECT, NULL }; - c = create_curse(NULL, &attrs, &ct_dummy, 1.0, 1, 1, 1); - cid = c->no; - result = findcurse(cid); - CuAssertPtrEquals(tc, c, result); - destroy_curse(c); - result = findcurse(cid); - CuAssertPtrEquals(tc, NULL, result); -} - -CuSuite* get_curse_suite(void) -{ - CuSuite* suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, test_curse); - return suite; -} +#include + +static void test_curse(CuTest * tc) { + attrib * attrs = NULL; + curse * c, * result; + int cid; + + curse_type ct_dummy = { "dummy", CURSETYP_NORM, 0, M_SUMEFFECT, NULL }; + c = create_curse(NULL, &attrs, &ct_dummy, 1.0, 1, 1, 1); + cid = c->no; + result = findcurse(cid); + CuAssertPtrEquals(tc, c, result); + destroy_curse(c); + result = findcurse(cid); + CuAssertPtrEquals(tc, NULL, result); +} + +CuSuite* get_curse_suite(void) +{ + CuSuite* suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_curse); + return suite; +} diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index 9b7e0393b..17a44fc09 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -1,220 +1,220 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "equipment.h" - -/* kernel includes */ -#include "item.h" -#include "unit.h" -#include "race.h" - -/* util includes */ -#include -#include - -/* libc includes */ -#include -#include - -static equipment * equipment_sets; - -equipment * -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 = malloc(sizeof(equipment)); - eq->name = strdup(eqname); - eq->next = *eqp; - eq->items = NULL; - eq->spells = NULL; - eq->subsets = NULL; - eq->callback = NULL; - 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) { - if (value!=NULL) { - eq->skills[sk] = strdup(value); - } else if (eq->skills[sk]) { - free(eq->skills[sk]); - } - } -} - -void -equipment_addspell(equipment * eq, spell * sp) -{ - if (eq!=NULL) { - spelllist_add(&eq->spells, sp); - } -} - -void -equipment_setitem(equipment * eq, const item_type * itype, const char * value) -{ - if (eq!=NULL) { - if (itype!=NULL) { - itemdata * idata = eq->items; - while (idata &&idata->itype!=itype) { - idata = idata->next; - } - if (idata==NULL) { - idata = malloc(sizeof(itemdata)); - idata->itype = itype; - idata->value = strdup(value); - idata->next = eq->items; - eq->items = idata; - } - } - } -} - -void -equipment_setcallback(struct equipment * eq, void (*callback)(const struct equipment *, struct unit *)) -{ - eq->callback = callback; -} - -void -equip_unit(struct unit * u, const struct equipment * eq) -{ - equip_unit_mask(u, eq, EQUIP_ALL); -} - -void -equip_unit_mask(struct unit * u, const struct equipment * eq, int mask) -{ - if (eq) { - - if (mask&EQUIP_SKILLS) { - skill_t sk; - for (sk=0;sk!=MAXSKILLS;++sk) { - if (eq->skills[sk]!=NULL) { - int i = dice_rand(eq->skills[sk]); - if (i>0) set_level(u, sk, i); - } - } - } - - if (mask&EQUIP_SPELLS) { - spell_list * sp = eq->spells; - if (sp!=NULL) { - sc_mage * m = get_mage(u); - if (m==NULL) { - assert(!"trying to equip spells on a non-mage!"); - } else { - while (sp) { - add_spell(get_spelllist(m, u->faction), sp->data); - sp = sp->next; - } - } - } - } - - if (mask&EQUIP_ITEMS) { - itemdata * idata; - for (idata=eq->items;idata!=NULL;idata=idata->next) { - int i = u->number * dice_rand(idata->value); - if (i>0) { - i_add(&u->items, i_new(idata->itype, i)); - } - } - } - - if (eq->subsets) { - int i; - for (i=0;eq->subsets[i].sets;++i) { - if (chance(eq->subsets[i].chance)) { - float rnd = (1+rng_int() % 1000) / 1000.0f; - int k; - for (k=0;eq->subsets[i].sets[k].set;++k) { - if (rnd<=eq->subsets[i].sets[k].chance) { - equip_unit_mask(u, eq->subsets[i].sets[k].set, mask); - break; - } - rnd -= eq->subsets[i].sets[k].chance; - } - } - } - } - - if (mask&EQUIP_SPECIAL) { - if (eq->callback) eq->callback(eq, u); - } - } -} - -void -equip_items(struct item ** items, const struct equipment * eq) -{ - if (eq) { - itemdata * idata; - - for (idata=eq->items;idata!=NULL;idata=idata->next) { - int i = dice_rand(idata->value); - if (i>0) { - i_add(items, i_new(idata->itype, i)); - } - } - if (eq->subsets) { - int i; - for (i=0;eq->subsets[i].sets;++i) { - if (chance(eq->subsets[i].chance)) { - float rnd = (1+rng_int() % 1000) / 1000.0f; - int k; - for (k=0;eq->subsets[i].sets[k].set;++k) { - if (rnd<=eq->subsets[i].sets[k].chance) { - equip_items(items, eq->subsets[i].sets[k].set); - break; - } - rnd -= eq->subsets[i].sets[k].chance; - } - } - } - } - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "equipment.h" + +/* kernel includes */ +#include "item.h" +#include "unit.h" +#include "race.h" + +/* util includes */ +#include +#include + +/* libc includes */ +#include +#include + +static equipment * equipment_sets; + +equipment * +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 = malloc(sizeof(equipment)); + eq->name = strdup(eqname); + eq->next = *eqp; + eq->items = NULL; + eq->spells = NULL; + eq->subsets = NULL; + eq->callback = NULL; + 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) { + if (value!=NULL) { + eq->skills[sk] = strdup(value); + } else if (eq->skills[sk]) { + free(eq->skills[sk]); + } + } +} + +void +equipment_addspell(equipment * eq, spell * sp) +{ + if (eq!=NULL) { + spelllist_add(&eq->spells, sp); + } +} + +void +equipment_setitem(equipment * eq, const item_type * itype, const char * value) +{ + if (eq!=NULL) { + if (itype!=NULL) { + itemdata * idata = eq->items; + while (idata &&idata->itype!=itype) { + idata = idata->next; + } + if (idata==NULL) { + idata = malloc(sizeof(itemdata)); + idata->itype = itype; + idata->value = strdup(value); + idata->next = eq->items; + eq->items = idata; + } + } + } +} + +void +equipment_setcallback(struct equipment * eq, void (*callback)(const struct equipment *, struct unit *)) +{ + eq->callback = callback; +} + +void +equip_unit(struct unit * u, const struct equipment * eq) +{ + equip_unit_mask(u, eq, EQUIP_ALL); +} + +void +equip_unit_mask(struct unit * u, const struct equipment * eq, int mask) +{ + if (eq) { + + if (mask&EQUIP_SKILLS) { + skill_t sk; + for (sk=0;sk!=MAXSKILLS;++sk) { + if (eq->skills[sk]!=NULL) { + int i = dice_rand(eq->skills[sk]); + if (i>0) set_level(u, sk, i); + } + } + } + + if (mask&EQUIP_SPELLS) { + spell_list * sp = eq->spells; + if (sp!=NULL) { + sc_mage * m = get_mage(u); + if (m==NULL) { + assert(!"trying to equip spells on a non-mage!"); + } else { + while (sp) { + add_spell(get_spelllist(m, u->faction), sp->data); + sp = sp->next; + } + } + } + } + + if (mask&EQUIP_ITEMS) { + itemdata * idata; + for (idata=eq->items;idata!=NULL;idata=idata->next) { + int i = u->number * dice_rand(idata->value); + if (i>0) { + i_add(&u->items, i_new(idata->itype, i)); + } + } + } + + if (eq->subsets) { + int i; + for (i=0;eq->subsets[i].sets;++i) { + if (chance(eq->subsets[i].chance)) { + float rnd = (1+rng_int() % 1000) / 1000.0f; + int k; + for (k=0;eq->subsets[i].sets[k].set;++k) { + if (rnd<=eq->subsets[i].sets[k].chance) { + equip_unit_mask(u, eq->subsets[i].sets[k].set, mask); + break; + } + rnd -= eq->subsets[i].sets[k].chance; + } + } + } + } + + if (mask&EQUIP_SPECIAL) { + if (eq->callback) eq->callback(eq, u); + } + } +} + +void +equip_items(struct item ** items, const struct equipment * eq) +{ + if (eq) { + itemdata * idata; + + for (idata=eq->items;idata!=NULL;idata=idata->next) { + int i = dice_rand(idata->value); + if (i>0) { + i_add(items, i_new(idata->itype, i)); + } + } + if (eq->subsets) { + int i; + for (i=0;eq->subsets[i].sets;++i) { + if (chance(eq->subsets[i].chance)) { + float rnd = (1+rng_int() % 1000) / 1000.0f; + int k; + for (k=0;eq->subsets[i].sets[k].set;++k) { + if (rnd<=eq->subsets[i].sets[k].chance) { + equip_items(items, eq->subsets[i].sets[k].set); + break; + } + rnd -= eq->subsets[i].sets[k].chance; + } + } + } + } + } +} diff --git a/src/kernel/equipment.h b/src/kernel/equipment.h index 174aad7f4..315854b42 100644 --- a/src/kernel/equipment.h +++ b/src/kernel/equipment.h @@ -1,73 +1,73 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_EQUIPMENT_H -#define H_KRNL_EQUIPMENT_H -#ifdef __cplusplus -extern "C" { -#endif - struct spell; - - typedef struct itemdata { - const struct item_type * itype; - char * value; - struct itemdata * next; - } itemdata; - - typedef struct subsetitem { - struct equipment * set; - float chance; - } subsetitem; - - typedef struct subset { - float chance; - subsetitem * sets; - } subset; - - typedef struct equipment { - char * name; - struct itemdata * items; - char * skills[MAXSKILLS]; - struct spell_list * spells; - struct subset * subsets; - struct equipment * next; - void (*callback)(const struct equipment *, struct unit *); - } equipment; - - - extern struct equipment * create_equipment(const char * eqname); - extern struct equipment * get_equipment(const char * eqname); - - extern void equipment_setitem(struct equipment * eq, const struct item_type * itype, const char * value); - extern void equipment_setskill(struct equipment * eq, skill_t sk, const char * value); - extern void equipment_addspell(struct equipment * eq, struct spell * sp); - extern void equipment_setcallback(struct equipment * eq, void (*callback)(const struct equipment *, struct unit *)); - - extern void equip_unit(struct unit * u, const struct equipment * eq); -#define EQUIP_SKILLS (1<<1) -#define EQUIP_SPELLS (1<<2) -#define EQUIP_ITEMS (1<<3) -#define EQUIP_SPECIAL (1<<4) -#define EQUIP_ALL (0xFF) - extern void equip_unit_mask(struct unit * u, const struct equipment * eq, int mask); - extern void equip_items(struct item ** items, const struct equipment * eq); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_EQUIPMENT_H +#define H_KRNL_EQUIPMENT_H +#ifdef __cplusplus +extern "C" { +#endif + struct spell; + + typedef struct itemdata { + const struct item_type * itype; + char * value; + struct itemdata * next; + } itemdata; + + typedef struct subsetitem { + struct equipment * set; + float chance; + } subsetitem; + + typedef struct subset { + float chance; + subsetitem * sets; + } subset; + + typedef struct equipment { + char * name; + struct itemdata * items; + char * skills[MAXSKILLS]; + struct spell_list * spells; + struct subset * subsets; + struct equipment * next; + void (*callback)(const struct equipment *, struct unit *); + } equipment; + + + extern struct equipment * create_equipment(const char * eqname); + extern struct equipment * get_equipment(const char * eqname); + + extern void equipment_setitem(struct equipment * eq, const struct item_type * itype, const char * value); + extern void equipment_setskill(struct equipment * eq, skill_t sk, const char * value); + extern void equipment_addspell(struct equipment * eq, struct spell * sp); + extern void equipment_setcallback(struct equipment * eq, void (*callback)(const struct equipment *, struct unit *)); + + extern void equip_unit(struct unit * u, const struct equipment * eq); +#define EQUIP_SKILLS (1<<1) +#define EQUIP_SPELLS (1<<2) +#define EQUIP_ITEMS (1<<3) +#define EQUIP_SPECIAL (1<<4) +#define EQUIP_ALL (0xFF) + extern void equip_unit_mask(struct unit * u, const struct equipment * eq, int mask); + extern void equip_items(struct item ** items, const struct equipment * eq); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/faction.c b/src/kernel/faction.c index f5ac32f3c..c7df564e8 100644 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -1,507 +1,507 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "faction.h" - -#include "alliance.h" -#include "equipment.h" -#include "group.h" -#include "item.h" -#include "message.h" -#include "plane.h" -#include "race.h" -#include "region.h" -#include "terrain.h" -#include "unit.h" -#include "version.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -faction *factions; - -/** remove the faction from memory. - * this frees all memory that's only accessible through the faction, - * but you should still call funhash and remove the faction from the - * global list. - */ -void -free_faction (faction * f) -{ - if (f->msgs) free_messagelist(f->msgs); - while (f->battles) { - struct bmsg * bm = f->battles; - f->battles = bm->next; - if (bm->msgs) free_messagelist(bm->msgs); - free(bm); - } - - while (f->groups) { - group * g = f->groups; - f->groups = g->next; - free_group(g); - } - freelist(f->allies); - - free(f->email); - free(f->banner); - free(f->passw); - free(f->override); - free(f->name); - - while (f->attribs) { - a_remove (&f->attribs, f->attribs); - } - - i_freeall(&f->items); - - freelist(f->ursprung); -} - -faction * -get_monsters(void) -{ - static faction * monsters; - static int gamecookie = -1; - - if (gamecookie!=global.cookie) { - monsters = NULL; - gamecookie = global.cookie; - } - - if (!monsters) { - faction * f; - for (f=factions;f;f=f->next) { - if (f->flags&FFL_NPC) { - return monsters=f; - } - } - if (!monsters) { - /* shit! */ - monsters = findfaction(666); - } - if (monsters) { - fset(monsters, FFL_NPC|FFL_NOIDLEOUT); - } - } - return monsters; -} - -const unit * -random_unit_in_faction(const faction *f) -{ - unit *u; - int c = 0, u_nr; - - for(u = f->units; u; u=u->next) c++; - - u_nr = rng_int()%c; - c = 0; - - for(u = f->units; u; u=u->next) - if(u_nr == c) return u; - - /* Hier sollte er nie ankommen */ - return NULL; -} - -const char * -factionname(const faction * f) -{ - typedef char name[OBJECTIDSIZE+1]; - static name idbuf[8]; - static int nextbuf = 0; - - char *ibuf = idbuf[(++nextbuf) % 8]; - - if (f && f->name) { - snprintf(ibuf, sizeof(name), "%s (%s)", f->name, itoa36(f->no)); - ibuf[sizeof(name)-1] = 0; - } else { - strcpy(ibuf, "Unbekannte Partei (?)"); - } - 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; - } - } - *(faction**)address = f; - return result; -} - -#define MAX_FACTION_ID (36*36*36*36) - -static int -unused_faction_id(void) -{ - int id = rng_int()%MAX_FACTION_ID; - - while (!faction_id_is_unused(id)) { - id++; if(id == MAX_FACTION_ID) id = 0; - } - - return id; -} - -faction * -addfaction(const char *email, const char * password, - const struct race * frace, const struct locale *loc, - int subscription) -{ - faction * f = calloc(sizeof(faction), 1); - char buf[128]; - - assert(frace); - - if (set_email(&f->email, email)!=0) { - log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), email)); - } - - f->override = strdup(itoa36(rng_int())); - faction_setpassword(f, password); - - f->alliance_joindate = turn; - f->lastorders = turn; - f->alive = 1; - f->age = 0; - f->race = frace; - f->magiegebiet = 0; - f->locale = loc; - f->subscription = subscription; - - f->options = want(O_REPORT) | want(O_ZUGVORLAGE) | want(O_COMPUTER) | want(O_COMPRESS) | want(O_ADRESSEN) | want(O_STATISTICS); - - f->no = unused_faction_id(); - if (rule_region_owners()) { - alliance * al = makealliance(f->no, NULL); - setalliance(f, al); - } - addlist(&factions, f); - fhash(f); - - snprintf(buf, sizeof(buf), "%s %s", LOC(loc, "factiondefault"), factionid(f)); - f->name = strdup(buf); - - return f; -} - -unit * -addplayer(region *r, faction * f) -{ - unit *u; - char buffer[32]; - - assert(f->units==NULL); - set_ursprung(f, 0, r->x, r->y); - u = createunit(r, f, 1, f->race); - equip_items(&u->faction->items, get_equipment("new_faction")); - equip_unit(u, get_equipment("first_unit")); - sprintf(buffer, "first_%s", u->race->_name[0]); - equip_unit(u, get_equipment(buffer)); - u->hp = unit_max_hp(u) * u->number; - fset(u, UFL_ISNEW); - if (f->race == new_race[RC_DAEMON]) { - race_t urc; - do { - urc = (race_t)(rng_int() % MAXRACES); - } while (new_race[urc]==NULL || urc == RC_DAEMON || !playerrace(new_race[urc])); - u->irace = new_race[urc]; - } - - return u; -} - -boolean -checkpasswd(const faction * f, const char * passwd, boolean shortp) -{ - if (unicode_utf8_strcasecmp(f->passw, passwd)==0) return true; - if (unicode_utf8_strcasecmp(f->override, passwd)==0) return true; - return false; -} - - -variant -read_faction_reference(struct storage * store) -{ - variant id; - id.i = store->r_id(store); - return id; -} - -void -write_faction_reference(const faction * f, struct storage * store) -{ - store->w_id(store, f?f->no:0); -} - -void -destroyfaction(faction * f) -{ - unit *u = f->units; - faction *ff; - - if (!f->alive) return; - fset(f, FFL_QUIT); - - freelist(f->spellbook); - f->spellbook = NULL; - - while (f->battles) { - struct bmsg * bm = f->battles; - f->battles = bm->next; - if (bm->msgs) free_messagelist(bm->msgs); - free(bm); - } - - while (u) { - /* give away your stuff, make zombies if you cannot (quest items) */ - int result = gift_items(u, GIFT_FRIENDS|GIFT_PEASANTS); - if (result!=0) { - unit * zombie = u; - u = u->nextF; - make_zombie(zombie); - } else { - region * r = u->region; - - if (!fval(r->terrain, SEA_REGION) && !!playerrace(u->race)) { - const race * rc = u->race; - int m = rmoney(r); - - if ((rc->ec_flags & ECF_REC_ETHEREAL)==0) { - int p = rpeasants(u->region); - int h = rhorses(u->region); - item * itm; - - /* Personen gehen nur an die Bauern, wenn sie auch von dort - * stammen */ - if (rc->ec_flags & ECF_REC_HORSES) { /* Zentauren an die Pferde */ - h += u->number; - } else { /* Orks zählen nur zur Hälfte */ - p += (int)(u->number * rc->recruit_multi); - } - for (itm=u->items;itm;itm=itm->next) { - if (itm->type->flags&ITF_ANIMAL) { - h += itm->number; - } - } - rsetpeasants(r, p); - rsethorses(r, h); - } - m += get_money(u); - rsetmoney(r, m); - } - set_number(u, 0); - u=u->nextF; - } - } - f->alive = 0; -/* no way! f->units = NULL; */ - handle_event(f->attribs, "destroy", f); - for (ff = factions; ff; ff = ff->next) { - group *g; - ally *sf, *sfn; - - /* Alle HELFE für die Partei löschen */ - for (sf = ff->allies; sf; sf = sf->next) { - if (sf->faction == f) { - removelist(&ff->allies, sf); - break; - } - } - for(g=ff->groups; g; g=g->next) { - for (sf = g->allies; sf;) { - sfn = sf->next; - if (sf->faction == f) { - removelist(&g->allies, sf); - break; - } - sf = sfn; - } - } - } - - /* units of other factions that were disguised as this faction - * have their disguise replaced by ordinary faction hiding. */ - if (rule_stealth_faction()) { - region * rc; - for (rc=regions; rc; rc=rc->next) { - for(u=rc->units; u; u=u->next) { - attrib *a = a_find(u->attribs, &at_otherfaction); - if(!a) continue; - if (get_otherfaction(a) == f) { - a_removeall(&u->attribs, &at_otherfaction); - fset(u, UFL_ANON_FACTION); - } - } - } - } -} - -int -get_alliance(const faction * a, const faction * b) -{ - const ally * sf = a->allies; - for (;sf!=NULL;sf=sf->next) { - if (sf->faction==b) { - return sf->status; - } - } - return 0; -} - -void -set_alliance(faction * a, faction * b, int status) -{ - ally ** sfp; - sfp = &a->allies; - while (*sfp) { - ally * sf = *sfp; - if (sf->faction==b) break; - sfp = &sf->next; - } - if (*sfp==NULL) { - ally * sf = *sfp = malloc(sizeof(ally)); - sf->next = NULL; - sf->status = status; - sf->faction = b; - return; - } - (*sfp)->status |= status; -} - -void -renumber_faction(faction * f, int no) -{ - if (f->subscription) { - sql_print(("UPDATE subscriptions set faction='%s' where id=%u;\n", - itoa36(no), f->subscription)); - } - funhash(f); - f->no = no; - fhash(f); - fset(f, FFL_NEWID); -} - -#ifdef SMART_INTERVALS -void -update_interval(struct faction * f, struct region * r) -{ - if (r==NULL || f==NULL) return; - if (f->first==NULL || f->first->index>r->index) { - f->first = r; - } - if (f->last==NULL || f->last->index<=r->index) { - f->last = r; - } -} -#endif - -const char * faction_getname(const faction * self) -{ - return self->name?self->name:""; -} - -void faction_setname(faction * self, const char * name) -{ - free(self->name); - if (name) self->name = strdup(name); -} - -const char * faction_getemail(const faction * self) -{ - return self->email?self->email:""; -} - -void faction_setemail(faction * self, const char * email) -{ - free(self->email); - if (email) self->email = strdup(email); -} - -const char * faction_getbanner(const faction * self) -{ - return self->banner?self->banner:""; -} - -void faction_setbanner(faction * self, const char * banner) -{ - free(self->banner); - if (banner) self->banner = strdup(banner); -} - -void -faction_setpassword(faction * f, const char * passw) -{ - free(f->passw); - if (passw) f->passw = strdup(passw); - else f->passw = strdup(itoa36(rng_int())); -} - -boolean valid_race(const struct faction * f, const struct race * rc) -{ - if (f->race==rc) return true; - else { - const char * str = get_param(f->race->parameters, "other_race"); - if (str) return (boolean)(rc_find(str)==rc); - return false; - } -} - -const char * -faction_getpassword(const faction * f) -{ - return f->passw; -} - -struct alliance * -f_get_alliance(const struct faction * f) -{ - if (f->alliance && !(f->alliance->flags&ALF_NON_ALLIED)) { - return f->alliance; - } - return NULL; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "faction.h" + +#include "alliance.h" +#include "equipment.h" +#include "group.h" +#include "item.h" +#include "message.h" +#include "plane.h" +#include "race.h" +#include "region.h" +#include "terrain.h" +#include "unit.h" +#include "version.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +faction *factions; + +/** remove the faction from memory. + * this frees all memory that's only accessible through the faction, + * but you should still call funhash and remove the faction from the + * global list. + */ +void +free_faction (faction * f) +{ + if (f->msgs) free_messagelist(f->msgs); + while (f->battles) { + struct bmsg * bm = f->battles; + f->battles = bm->next; + if (bm->msgs) free_messagelist(bm->msgs); + free(bm); + } + + while (f->groups) { + group * g = f->groups; + f->groups = g->next; + free_group(g); + } + freelist(f->allies); + + free(f->email); + free(f->banner); + free(f->passw); + free(f->override); + free(f->name); + + while (f->attribs) { + a_remove (&f->attribs, f->attribs); + } + + i_freeall(&f->items); + + freelist(f->ursprung); +} + +faction * +get_monsters(void) +{ + static faction * monsters; + static int gamecookie = -1; + + if (gamecookie!=global.cookie) { + monsters = NULL; + gamecookie = global.cookie; + } + + if (!monsters) { + faction * f; + for (f=factions;f;f=f->next) { + if (f->flags&FFL_NPC) { + return monsters=f; + } + } + if (!monsters) { + /* shit! */ + monsters = findfaction(666); + } + if (monsters) { + fset(monsters, FFL_NPC|FFL_NOIDLEOUT); + } + } + return monsters; +} + +const unit * +random_unit_in_faction(const faction *f) +{ + unit *u; + int c = 0, u_nr; + + for(u = f->units; u; u=u->next) c++; + + u_nr = rng_int()%c; + c = 0; + + for(u = f->units; u; u=u->next) + if(u_nr == c) return u; + + /* Hier sollte er nie ankommen */ + return NULL; +} + +const char * +factionname(const faction * f) +{ + typedef char name[OBJECTIDSIZE+1]; + static name idbuf[8]; + static int nextbuf = 0; + + char *ibuf = idbuf[(++nextbuf) % 8]; + + if (f && f->name) { + snprintf(ibuf, sizeof(name), "%s (%s)", f->name, itoa36(f->no)); + ibuf[sizeof(name)-1] = 0; + } else { + strcpy(ibuf, "Unbekannte Partei (?)"); + } + 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; + } + } + *(faction**)address = f; + return result; +} + +#define MAX_FACTION_ID (36*36*36*36) + +static int +unused_faction_id(void) +{ + int id = rng_int()%MAX_FACTION_ID; + + while (!faction_id_is_unused(id)) { + id++; if(id == MAX_FACTION_ID) id = 0; + } + + return id; +} + +faction * +addfaction(const char *email, const char * password, + const struct race * frace, const struct locale *loc, + int subscription) +{ + faction * f = calloc(sizeof(faction), 1); + char buf[128]; + + assert(frace); + + if (set_email(&f->email, email)!=0) { + log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), email)); + } + + f->override = strdup(itoa36(rng_int())); + faction_setpassword(f, password); + + f->alliance_joindate = turn; + f->lastorders = turn; + f->alive = 1; + f->age = 0; + f->race = frace; + f->magiegebiet = 0; + f->locale = loc; + f->subscription = subscription; + + f->options = want(O_REPORT) | want(O_ZUGVORLAGE) | want(O_COMPUTER) | want(O_COMPRESS) | want(O_ADRESSEN) | want(O_STATISTICS); + + f->no = unused_faction_id(); + if (rule_region_owners()) { + alliance * al = makealliance(f->no, NULL); + setalliance(f, al); + } + addlist(&factions, f); + fhash(f); + + snprintf(buf, sizeof(buf), "%s %s", LOC(loc, "factiondefault"), factionid(f)); + f->name = strdup(buf); + + return f; +} + +unit * +addplayer(region *r, faction * f) +{ + unit *u; + char buffer[32]; + + assert(f->units==NULL); + set_ursprung(f, 0, r->x, r->y); + u = createunit(r, f, 1, f->race); + equip_items(&u->faction->items, get_equipment("new_faction")); + equip_unit(u, get_equipment("first_unit")); + sprintf(buffer, "first_%s", u->race->_name[0]); + equip_unit(u, get_equipment(buffer)); + u->hp = unit_max_hp(u) * u->number; + fset(u, UFL_ISNEW); + if (f->race == new_race[RC_DAEMON]) { + race_t urc; + do { + urc = (race_t)(rng_int() % MAXRACES); + } while (new_race[urc]==NULL || urc == RC_DAEMON || !playerrace(new_race[urc])); + u->irace = new_race[urc]; + } + + return u; +} + +boolean +checkpasswd(const faction * f, const char * passwd, boolean shortp) +{ + if (unicode_utf8_strcasecmp(f->passw, passwd)==0) return true; + if (unicode_utf8_strcasecmp(f->override, passwd)==0) return true; + return false; +} + + +variant +read_faction_reference(struct storage * store) +{ + variant id; + id.i = store->r_id(store); + return id; +} + +void +write_faction_reference(const faction * f, struct storage * store) +{ + store->w_id(store, f?f->no:0); +} + +void +destroyfaction(faction * f) +{ + unit *u = f->units; + faction *ff; + + if (!f->alive) return; + fset(f, FFL_QUIT); + + freelist(f->spellbook); + f->spellbook = NULL; + + while (f->battles) { + struct bmsg * bm = f->battles; + f->battles = bm->next; + if (bm->msgs) free_messagelist(bm->msgs); + free(bm); + } + + while (u) { + /* give away your stuff, make zombies if you cannot (quest items) */ + int result = gift_items(u, GIFT_FRIENDS|GIFT_PEASANTS); + if (result!=0) { + unit * zombie = u; + u = u->nextF; + make_zombie(zombie); + } else { + region * r = u->region; + + if (!fval(r->terrain, SEA_REGION) && !!playerrace(u->race)) { + const race * rc = u->race; + int m = rmoney(r); + + if ((rc->ec_flags & ECF_REC_ETHEREAL)==0) { + int p = rpeasants(u->region); + int h = rhorses(u->region); + item * itm; + + /* Personen gehen nur an die Bauern, wenn sie auch von dort + * stammen */ + if (rc->ec_flags & ECF_REC_HORSES) { /* Zentauren an die Pferde */ + h += u->number; + } else { /* Orks zählen nur zur Hälfte */ + p += (int)(u->number * rc->recruit_multi); + } + for (itm=u->items;itm;itm=itm->next) { + if (itm->type->flags&ITF_ANIMAL) { + h += itm->number; + } + } + rsetpeasants(r, p); + rsethorses(r, h); + } + m += get_money(u); + rsetmoney(r, m); + } + set_number(u, 0); + u=u->nextF; + } + } + f->alive = 0; +/* no way! f->units = NULL; */ + handle_event(f->attribs, "destroy", f); + for (ff = factions; ff; ff = ff->next) { + group *g; + ally *sf, *sfn; + + /* Alle HELFE für die Partei löschen */ + for (sf = ff->allies; sf; sf = sf->next) { + if (sf->faction == f) { + removelist(&ff->allies, sf); + break; + } + } + for(g=ff->groups; g; g=g->next) { + for (sf = g->allies; sf;) { + sfn = sf->next; + if (sf->faction == f) { + removelist(&g->allies, sf); + break; + } + sf = sfn; + } + } + } + + /* units of other factions that were disguised as this faction + * have their disguise replaced by ordinary faction hiding. */ + if (rule_stealth_faction()) { + region * rc; + for (rc=regions; rc; rc=rc->next) { + for(u=rc->units; u; u=u->next) { + attrib *a = a_find(u->attribs, &at_otherfaction); + if(!a) continue; + if (get_otherfaction(a) == f) { + a_removeall(&u->attribs, &at_otherfaction); + fset(u, UFL_ANON_FACTION); + } + } + } + } +} + +int +get_alliance(const faction * a, const faction * b) +{ + const ally * sf = a->allies; + for (;sf!=NULL;sf=sf->next) { + if (sf->faction==b) { + return sf->status; + } + } + return 0; +} + +void +set_alliance(faction * a, faction * b, int status) +{ + ally ** sfp; + sfp = &a->allies; + while (*sfp) { + ally * sf = *sfp; + if (sf->faction==b) break; + sfp = &sf->next; + } + if (*sfp==NULL) { + ally * sf = *sfp = malloc(sizeof(ally)); + sf->next = NULL; + sf->status = status; + sf->faction = b; + return; + } + (*sfp)->status |= status; +} + +void +renumber_faction(faction * f, int no) +{ + if (f->subscription) { + sql_print(("UPDATE subscriptions set faction='%s' where id=%u;\n", + itoa36(no), f->subscription)); + } + funhash(f); + f->no = no; + fhash(f); + fset(f, FFL_NEWID); +} + +#ifdef SMART_INTERVALS +void +update_interval(struct faction * f, struct region * r) +{ + if (r==NULL || f==NULL) return; + if (f->first==NULL || f->first->index>r->index) { + f->first = r; + } + if (f->last==NULL || f->last->index<=r->index) { + f->last = r; + } +} +#endif + +const char * faction_getname(const faction * self) +{ + return self->name?self->name:""; +} + +void faction_setname(faction * self, const char * name) +{ + free(self->name); + if (name) self->name = strdup(name); +} + +const char * faction_getemail(const faction * self) +{ + return self->email?self->email:""; +} + +void faction_setemail(faction * self, const char * email) +{ + free(self->email); + if (email) self->email = strdup(email); +} + +const char * faction_getbanner(const faction * self) +{ + return self->banner?self->banner:""; +} + +void faction_setbanner(faction * self, const char * banner) +{ + free(self->banner); + if (banner) self->banner = strdup(banner); +} + +void +faction_setpassword(faction * f, const char * passw) +{ + free(f->passw); + if (passw) f->passw = strdup(passw); + else f->passw = strdup(itoa36(rng_int())); +} + +boolean valid_race(const struct faction * f, const struct race * rc) +{ + if (f->race==rc) return true; + else { + const char * str = get_param(f->race->parameters, "other_race"); + if (str) return (boolean)(rc_find(str)==rc); + return false; + } +} + +const char * +faction_getpassword(const faction * f) +{ + return f->passw; +} + +struct alliance * +f_get_alliance(const struct faction * f) +{ + if (f->alliance && !(f->alliance->flags&ALF_NON_ALLIED)) { + return f->alliance; + } + return NULL; +} diff --git a/src/kernel/faction.h b/src/kernel/faction.h index faa552581..c9049c52f 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -1,161 +1,161 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_FACTION -#define H_KRNL_FACTION -#ifdef __cplusplus -extern "C" { -#endif - -struct player; -struct alliance; -struct item; -struct seen_region; - -/* SMART_INTERVALS: define to speed up finding the interval of regions that a - faction is in. defining this speeds up the turn by 30-40% */ -#define SMART_INTERVALS - -/* faction flags */ -#define FFL_NEWID (1<<0) /* Die Partei hat bereits einmal ihre no gewechselt */ -#define FFL_ISNEW (1<<1) -#define FFL_RESTART (1<<2) -#define FFL_QUIT (1<<3) -#define FFL_DEFENDER (1<<10) -#define FFL_SELECT (1<<18) /* ehemals f->dh, u->dh, r->dh, etc... */ -#define FFL_NOAID (1<<21) /* Hilfsflag Kampf */ -#define FFL_MARK (1<<23) /* für markierende algorithmen, die das - * hinterher auch wieder löschen müssen! - * (FFL_SELECT muss man vorher initialisieren, - * FL_MARK hinterher löschen) */ -#define FFL_NOIDLEOUT (1<<24) /* Partei stirbt nicht an NMRs */ -#define FFL_OVERRIDE (1<<27) /* Override-Passwort wurde benutzt */ -#define FFL_DBENTRY (1<<28) /* Partei ist in Datenbank eingetragen */ -#define FFL_NOTIMEOUT (1<<29) /* ignore MaxAge() */ -#define FFL_GM (1<<30) /* eine Partei mit Sonderrechten */ -#define FFL_NPC (1<<31) /* eine Partei mit Monstern */ - -#define FFL_SAVEMASK (FFL_DEFENDER|FFL_NEWID|FFL_GM|FFL_NPC|FFL_NOTIMEOUT|FFL_DBENTRY|FFL_NOTIMEOUT) - -struct faction * get_monsters(void); -#define is_monsters(f) ((f)->flags&FFL_NPC) - -typedef struct faction { - struct faction *next; - struct faction *nexthash; - - struct player *owner; -#ifdef SMART_INTERVALS - struct region *first; - struct region *last; -#endif - int no; - int subscription; - unsigned int flags; - char *name; - char *banner; - char *email; - char *passw; - char *override; - int max_spelllevel; - struct spell_list * spellbook; - const struct locale * locale; - int lastorders; /* enno: short? */ - int age; /* enno: short? */ - struct ursprung *ursprung; - const struct race * race; - magic_t magiegebiet; - int newbies; - int num_people; /* Anzahl Personen ohne Monster */ - int num_total; /* Anzahl Personen mit Monstern */ - int options; - int no_units; - struct ally *allies; - struct group *groups; - boolean alive; /* enno: sollte ein flag werden */ - int nregions; - int money; -#if SCORE_MODULE - int score; -#endif - struct alliance * alliance; - int alliance_joindate; /* the turn on which the faction joined its current alliance (or left the last one) */ -#ifdef VICTORY_DELAY - unsigned char victory_delay; -#endif - struct unit * units; - struct attrib *attribs; - struct message_list * msgs; - struct bmsg { - struct bmsg * next; - struct region * r; - struct message_list * msgs; - } * battles; - struct item * items; /* items this faction can claim */ - struct seen_region ** seen; -} faction; - -extern struct faction *factions; - -typedef struct faction_list { - struct faction_list * next; - struct faction * data; -} faction_list; - -extern const struct unit * random_unit_in_faction(const struct faction *f); -extern const char * factionname(const struct faction * f); -extern struct unit * addplayer(struct region *r, faction * f); -extern struct faction * addfaction(const char *email, const char* password, - const struct race * frace, - const struct locale *loc, int subscription); -extern boolean checkpasswd(const faction * f, const char * passwd, boolean shortp); -extern void destroyfaction(faction * f); - -extern void set_alliance(struct faction * a, struct faction * b, int status); -extern int get_alliance(const struct faction * a, const struct faction * b); - -extern struct alliance * f_get_alliance(const struct faction * a); - -extern void write_faction_reference(const struct faction * f, struct storage * store); -extern variant read_faction_reference(struct storage * store); -extern int resolve_faction(variant data, void * addr); - -extern void renumber_faction(faction * f, int no); -void free_faction(struct faction * f); - -#ifdef SMART_INTERVALS -extern void update_interval(struct faction * f, struct region * r); -#endif - -const char * faction_getbanner(const struct faction * self); -void faction_setbanner(struct faction * self, const char * name); - -const char * faction_getname(const struct faction * self); -void faction_setname(struct faction * self, const char * name); - -const char * faction_getemail(const struct faction * self); -void faction_setemail(struct faction * self, const char * email); - -const char * faction_getpassword(const struct faction * self); -void faction_setpassword(struct faction * self, const char * password); -boolean valid_race(const struct faction * f, const struct race * rc); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_FACTION +#define H_KRNL_FACTION +#ifdef __cplusplus +extern "C" { +#endif + +struct player; +struct alliance; +struct item; +struct seen_region; + +/* SMART_INTERVALS: define to speed up finding the interval of regions that a + faction is in. defining this speeds up the turn by 30-40% */ +#define SMART_INTERVALS + +/* faction flags */ +#define FFL_NEWID (1<<0) /* Die Partei hat bereits einmal ihre no gewechselt */ +#define FFL_ISNEW (1<<1) +#define FFL_RESTART (1<<2) +#define FFL_QUIT (1<<3) +#define FFL_DEFENDER (1<<10) +#define FFL_SELECT (1<<18) /* ehemals f->dh, u->dh, r->dh, etc... */ +#define FFL_NOAID (1<<21) /* Hilfsflag Kampf */ +#define FFL_MARK (1<<23) /* für markierende algorithmen, die das + * hinterher auch wieder löschen müssen! + * (FFL_SELECT muss man vorher initialisieren, + * FL_MARK hinterher löschen) */ +#define FFL_NOIDLEOUT (1<<24) /* Partei stirbt nicht an NMRs */ +#define FFL_OVERRIDE (1<<27) /* Override-Passwort wurde benutzt */ +#define FFL_DBENTRY (1<<28) /* Partei ist in Datenbank eingetragen */ +#define FFL_NOTIMEOUT (1<<29) /* ignore MaxAge() */ +#define FFL_GM (1<<30) /* eine Partei mit Sonderrechten */ +#define FFL_NPC (1<<31) /* eine Partei mit Monstern */ + +#define FFL_SAVEMASK (FFL_DEFENDER|FFL_NEWID|FFL_GM|FFL_NPC|FFL_NOTIMEOUT|FFL_DBENTRY|FFL_NOTIMEOUT) + +struct faction * get_monsters(void); +#define is_monsters(f) ((f)->flags&FFL_NPC) + +typedef struct faction { + struct faction *next; + struct faction *nexthash; + + struct player *owner; +#ifdef SMART_INTERVALS + struct region *first; + struct region *last; +#endif + int no; + int subscription; + unsigned int flags; + char *name; + char *banner; + char *email; + char *passw; + char *override; + int max_spelllevel; + struct spell_list * spellbook; + const struct locale * locale; + int lastorders; /* enno: short? */ + int age; /* enno: short? */ + struct ursprung *ursprung; + const struct race * race; + magic_t magiegebiet; + int newbies; + int num_people; /* Anzahl Personen ohne Monster */ + int num_total; /* Anzahl Personen mit Monstern */ + int options; + int no_units; + struct ally *allies; + struct group *groups; + boolean alive; /* enno: sollte ein flag werden */ + int nregions; + int money; +#if SCORE_MODULE + int score; +#endif + struct alliance * alliance; + int alliance_joindate; /* the turn on which the faction joined its current alliance (or left the last one) */ +#ifdef VICTORY_DELAY + unsigned char victory_delay; +#endif + struct unit * units; + struct attrib *attribs; + struct message_list * msgs; + struct bmsg { + struct bmsg * next; + struct region * r; + struct message_list * msgs; + } * battles; + struct item * items; /* items this faction can claim */ + struct seen_region ** seen; +} faction; + +extern struct faction *factions; + +typedef struct faction_list { + struct faction_list * next; + struct faction * data; +} faction_list; + +extern const struct unit * random_unit_in_faction(const struct faction *f); +extern const char * factionname(const struct faction * f); +extern struct unit * addplayer(struct region *r, faction * f); +extern struct faction * addfaction(const char *email, const char* password, + const struct race * frace, + const struct locale *loc, int subscription); +extern boolean checkpasswd(const faction * f, const char * passwd, boolean shortp); +extern void destroyfaction(faction * f); + +extern void set_alliance(struct faction * a, struct faction * b, int status); +extern int get_alliance(const struct faction * a, const struct faction * b); + +extern struct alliance * f_get_alliance(const struct faction * a); + +extern void write_faction_reference(const struct faction * f, struct storage * store); +extern variant read_faction_reference(struct storage * store); +extern int resolve_faction(variant data, void * addr); + +extern void renumber_faction(faction * f, int no); +void free_faction(struct faction * f); + +#ifdef SMART_INTERVALS +extern void update_interval(struct faction * f, struct region * r); +#endif + +const char * faction_getbanner(const struct faction * self); +void faction_setbanner(struct faction * self, const char * name); + +const char * faction_getname(const struct faction * self); +void faction_setname(struct faction * self, const char * name); + +const char * faction_getemail(const struct faction * self); +void faction_setemail(struct faction * self, const char * email); + +const char * faction_getpassword(const struct faction * self); +void faction_setpassword(struct faction * self, const char * password); +boolean valid_race(const struct faction * f, const struct race * rc); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/group.c b/src/kernel/group.c index 4838e26fc..1c2c23bff 100644 --- a/src/kernel/group.c +++ b/src/kernel/group.c @@ -1,243 +1,243 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "group.h" - -/* kernel includes */ -#include "unit.h" -#include "faction.h" -#include "save.h" -#include "version.h" - -/* attrib includes */ -#include - -/* util includes */ -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -#define GMAXHASH 2039 -static group * ghash[GMAXHASH]; -static int maxgid; - -static group * -new_group(faction * f, const char * name, int gid) -{ - group ** gp = &f->groups; - int index = gid % GMAXHASH; - group * g = calloc(sizeof(group), 1); - - while (*gp) gp = &(*gp)->next; - *gp = g; - - maxgid = MAX(gid, maxgid); - g->name = strdup(name); - g->gid = gid; - - g->nexthash = ghash[index]; - return ghash[index] = g; -} - -static void -init_group(faction * f, group * g) -{ - ally * a, ** an; - - an = &g->allies; - for (a=f->allies;a;a=a->next) if (a->faction) { - ally * ga = calloc(sizeof(ally), 1); - *ga = *a; - *an = ga; - an = &ga->next; - } -} - -static group * -find_groupbyname(group * g, const char * name) -{ - while (g && unicode_utf8_strcasecmp(name, g->name)!=0) g = g->next; - return g; -} - -static group * -find_group(int gid) -{ - int index = gid % GMAXHASH; - group * g = ghash[index]; - while (g && g->gid!=gid) g = g->nexthash; - return g; -} - -static int -read_group(attrib * a, void * owner, struct storage * store) -{ - group * g; - int gid = store->r_int(store); - a->data.v = g = find_group(gid); - if (g!=0) { - g->members++; - return AT_READ_OK; - } - return AT_READ_FAIL; -} - -static void -write_group(const attrib * a, const void * owner, struct storage * store) -{ - group * g = (group*)a->data.v; - store->w_int(store, g->gid); -} - -attrib_type -at_group = { /* attribute for units assigned to a group */ - "grp", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - write_group, - read_group, - ATF_UNIQUE -}; - -void -free_group(group * g) -{ - int index = g->gid % GMAXHASH; - group ** g_ptr = ghash+index; - while (*g_ptr && (*g_ptr)->gid!=g->gid) g_ptr = &(*g_ptr)->nexthash; - assert(*g_ptr==g); - *g_ptr = g->nexthash; - - while (g->allies) { - ally * a = g->allies; - g->allies = a->next; - free(a); - } - free(g->name); - free(g); -} - -void -set_group(struct unit * u, struct group * g) -{ - attrib * a = NULL; - - if (fval(u, UFL_GROUP)) { - a = a_find(u->attribs, &at_group); - } - - if (a) { - group * og = (group *)a->data.v; - if (og==g) return; - --og->members; - } - - if (g) { - if (!a) { - a = a_add(&u->attribs, a_new(&at_group)); - fset(u, UFL_GROUP); - } - a->data.v = g; - g->members++; - } else if (a) { - a_remove(&u->attribs, a); - freset(u, UFL_GROUP); - } -} - -boolean -join_group(unit * u, const char * name) -{ - group * g = NULL; - - if (name && name[0]) { - g = find_groupbyname(u->faction->groups, name); - if (g==NULL) { - g = new_group(u->faction, name, ++maxgid); - init_group(u->faction, g); - } - } - - set_group(u, g); - return true; -} - -void -write_groups(struct storage * store, group * g) -{ - while (g) { - ally * a; - store->w_int(store, g->gid); - store->w_str(store, g->name); - for (a=g->allies;a;a=a->next) { - if (a->faction) { - write_faction_reference(a->faction, store); - store->w_int(store, a->status); - } - } - store->w_id(store, 0); - a_write(store, g->attribs, g); - store->w_brk(store); - g=g->next; - } - store->w_int(store, 0); -} - -void -read_groups(struct storage * store, faction * f) -{ - for(;;) { - ally ** pa; - group * g; - int gid; - char buf[1024]; - - gid = store->r_int(store); - if (gid==0) break; - store->r_str_buf(store, buf, sizeof(buf)); - g = new_group(f, buf, gid); - pa = &g->allies; - for (;;) { - ally * a; - variant fid; - fid.i = store->r_id(store); - if (fid.i<=0) break; - if (store->versionnext; - a->status = store->r_int(store); - - a->faction = findfaction(fid.i); - if (!a->faction) ur_add(fid, &a->faction, resolve_faction); - } - *pa = 0; - a_read(store, &g->attribs, g); - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "group.h" + +/* kernel includes */ +#include "unit.h" +#include "faction.h" +#include "save.h" +#include "version.h" + +/* attrib includes */ +#include + +/* util includes */ +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +#define GMAXHASH 2039 +static group * ghash[GMAXHASH]; +static int maxgid; + +static group * +new_group(faction * f, const char * name, int gid) +{ + group ** gp = &f->groups; + int index = gid % GMAXHASH; + group * g = calloc(sizeof(group), 1); + + while (*gp) gp = &(*gp)->next; + *gp = g; + + maxgid = MAX(gid, maxgid); + g->name = strdup(name); + g->gid = gid; + + g->nexthash = ghash[index]; + return ghash[index] = g; +} + +static void +init_group(faction * f, group * g) +{ + ally * a, ** an; + + an = &g->allies; + for (a=f->allies;a;a=a->next) if (a->faction) { + ally * ga = calloc(sizeof(ally), 1); + *ga = *a; + *an = ga; + an = &ga->next; + } +} + +static group * +find_groupbyname(group * g, const char * name) +{ + while (g && unicode_utf8_strcasecmp(name, g->name)!=0) g = g->next; + return g; +} + +static group * +find_group(int gid) +{ + int index = gid % GMAXHASH; + group * g = ghash[index]; + while (g && g->gid!=gid) g = g->nexthash; + return g; +} + +static int +read_group(attrib * a, void * owner, struct storage * store) +{ + group * g; + int gid = store->r_int(store); + a->data.v = g = find_group(gid); + if (g!=0) { + g->members++; + return AT_READ_OK; + } + return AT_READ_FAIL; +} + +static void +write_group(const attrib * a, const void * owner, struct storage * store) +{ + group * g = (group*)a->data.v; + store->w_int(store, g->gid); +} + +attrib_type +at_group = { /* attribute for units assigned to a group */ + "grp", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + write_group, + read_group, + ATF_UNIQUE +}; + +void +free_group(group * g) +{ + int index = g->gid % GMAXHASH; + group ** g_ptr = ghash+index; + while (*g_ptr && (*g_ptr)->gid!=g->gid) g_ptr = &(*g_ptr)->nexthash; + assert(*g_ptr==g); + *g_ptr = g->nexthash; + + while (g->allies) { + ally * a = g->allies; + g->allies = a->next; + free(a); + } + free(g->name); + free(g); +} + +void +set_group(struct unit * u, struct group * g) +{ + attrib * a = NULL; + + if (fval(u, UFL_GROUP)) { + a = a_find(u->attribs, &at_group); + } + + if (a) { + group * og = (group *)a->data.v; + if (og==g) return; + --og->members; + } + + if (g) { + if (!a) { + a = a_add(&u->attribs, a_new(&at_group)); + fset(u, UFL_GROUP); + } + a->data.v = g; + g->members++; + } else if (a) { + a_remove(&u->attribs, a); + freset(u, UFL_GROUP); + } +} + +boolean +join_group(unit * u, const char * name) +{ + group * g = NULL; + + if (name && name[0]) { + g = find_groupbyname(u->faction->groups, name); + if (g==NULL) { + g = new_group(u->faction, name, ++maxgid); + init_group(u->faction, g); + } + } + + set_group(u, g); + return true; +} + +void +write_groups(struct storage * store, group * g) +{ + while (g) { + ally * a; + store->w_int(store, g->gid); + store->w_str(store, g->name); + for (a=g->allies;a;a=a->next) { + if (a->faction) { + write_faction_reference(a->faction, store); + store->w_int(store, a->status); + } + } + store->w_id(store, 0); + a_write(store, g->attribs, g); + store->w_brk(store); + g=g->next; + } + store->w_int(store, 0); +} + +void +read_groups(struct storage * store, faction * f) +{ + for(;;) { + ally ** pa; + group * g; + int gid; + char buf[1024]; + + gid = store->r_int(store); + if (gid==0) break; + store->r_str_buf(store, buf, sizeof(buf)); + g = new_group(f, buf, gid); + pa = &g->allies; + for (;;) { + ally * a; + variant fid; + fid.i = store->r_id(store); + if (fid.i<=0) break; + if (store->versionnext; + a->status = store->r_int(store); + + a->faction = findfaction(fid.i); + if (!a->faction) ur_add(fid, &a->faction, resolve_faction); + } + *pa = 0; + a_read(store, &g->attribs, g); + } +} diff --git a/src/kernel/group.h b/src/kernel/group.h index 63f8c0ba8..0db22cd6d 100644 --- a/src/kernel/group.h +++ b/src/kernel/group.h @@ -1,51 +1,51 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KERNEL_GROUP -#define H_KERNEL_GROUP -#ifdef __cplusplus -extern "C" { -#endif - -/* bitfield value for group::flags */ -#define GFL_ALIVE 0x01 /* There is at least one struct unit in the group */ - -typedef struct group { - struct group * next; - struct group * nexthash; - struct faction * f; - struct attrib *attribs; - char * name; - struct ally * allies; - int flags; - int gid; - int members; -} group; - -extern struct attrib_type at_group; /* attribute for units assigned to a group */ -extern boolean join_group(struct unit * u, const char * name); -extern void set_group(struct unit * u, struct group * g); -extern void free_group(struct group * g); - -extern void write_groups(struct storage * F, struct group * g); -extern void read_groups(struct storage * F, struct faction * f); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KERNEL_GROUP +#define H_KERNEL_GROUP +#ifdef __cplusplus +extern "C" { +#endif + +/* bitfield value for group::flags */ +#define GFL_ALIVE 0x01 /* There is at least one struct unit in the group */ + +typedef struct group { + struct group * next; + struct group * nexthash; + struct faction * f; + struct attrib *attribs; + char * name; + struct ally * allies; + int flags; + int gid; + int members; +} group; + +extern struct attrib_type at_group; /* attribute for units assigned to a group */ +extern boolean join_group(struct unit * u, const char * name); +extern void set_group(struct unit * u, struct group * g); +extern void free_group(struct group * g); + +extern void write_groups(struct storage * F, struct group * g); +extern void read_groups(struct storage * F, struct faction * f); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/item.c b/src/kernel/item.c index 02e110f93..ce329460b 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -1,1185 +1,1186 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "item.h" - -#include - -#include "alchemy.h" -#include "build.h" -#include "faction.h" -#include "message.h" -#include "pool.h" -#include "race.h" -#include "region.h" -#include "save.h" -#include "skill.h" -#include "terrain.h" -#include "unit.h" - -/* triggers includes */ -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -resource_type * resourcetypes; -luxury_type * luxurytypes; -potion_type * potiontypes; - -#define IMAXHASH 127 -static item_type * itemtypes[IMAXHASH]; - -static int -res_changeaura(unit * u, const resource_type * rtype, int delta) -{ - assert(rtype!=NULL); - change_spellpoints(u, delta); - return 0; -} - -static int -res_changeperson(unit * u, const resource_type * rtype, int delta) -{ - assert(rtype!=NULL || !"not implemented"); - scale_number(u, u->number+delta); - return 0; -} - -static int -res_changepermaura(unit * u, const resource_type * rtype, int delta) -{ - assert(rtype!=NULL); - change_maxspellpoints(u, delta); - return 0; -} - -static int -res_changehp(unit * u, const resource_type * rtype, int delta) -{ - assert(rtype!=NULL); - u->hp+=delta; - return 0; -} - -static int -res_changepeasants(unit * u, const resource_type * rtype, int delta) -{ - assert(rtype!=NULL && u->region->land); - u->region->land->peasants+=delta; - return 0; -} - -int -res_changeitem(unit * u, const resource_type * rtype, int delta) -{ - int num; - if (rtype == oldresourcetype[R_STONE] && u->race==new_race[RC_STONEGOLEM] && delta<=0) { - int reduce = delta / GOLEM_STONE; - if (delta % GOLEM_STONE != 0) --reduce; - scale_number(u, u->number+reduce); - num = u->number; - } else if (rtype == oldresourcetype[R_IRON] && u->race==new_race[RC_IRONGOLEM] && delta<=0) { - int reduce = delta / GOLEM_IRON; - if (delta % GOLEM_IRON != 0) --reduce; - scale_number(u, u->number+reduce); - num = u->number; - } else { - const item_type * itype = resource2item(rtype); - item * i; - assert(itype!=NULL); - i = i_change(&u->items, itype, delta); - if (i==NULL) return 0; - num = i->number; - } - return num; -} - -const char * -resourcename(const resource_type * rtype, int flags) -{ - int i = 0; - - if (rtype) { - if (rtype->name) return rtype->name(rtype, flags); - - if (flags & NMF_PLURAL) i = 1; - if (flags & NMF_APPEARANCE && rtype->_appearance[i]) { - return rtype->_appearance[i]; - } - return rtype->_name[i]; - } - return "none"; -} - -resource_type * -new_resourcetype(const char ** names, const char ** appearances, int flags) -{ - resource_type * rtype = rt_find(names[0]); - - if (rtype==NULL) { - int i; - rtype = calloc(sizeof(resource_type), 1); - - for (i=0; i!=2; ++i) { - rtype->_name[i] = strdup(names[i]); - if (appearances) rtype->_appearance[i] = strdup(appearances[i]); - else rtype->_appearance[i] = NULL; - } - rt_register(rtype); - } -#ifndef NDEBUG - else { - /* TODO: check that this is the same type */ - } -#endif - rtype->flags |= flags; - return rtype; -} - -void -it_register(item_type * itype) -{ - int hash = hashstring(itype->rtype->_name[0]); - int key = hash % IMAXHASH; - item_type ** p_itype = &itemtypes[key]; - while (*p_itype && *p_itype != itype) p_itype = &(*p_itype)->next; - if (*p_itype==NULL) { - itype->rtype->itype = itype; - *p_itype = itype; - rt_register(itype->rtype); - } -} - -item_type * -new_itemtype(resource_type * rtype, - int iflags, int weight, int capacity) -{ - item_type * itype; - assert(resource2item(rtype) == NULL); - assert(rtype->flags & RTF_ITEM); - - itype = calloc(sizeof(item_type), 1); - - itype->rtype = rtype; - itype->weight = weight; - itype->capacity = capacity; - itype->flags |= iflags; - it_register(itype); - - rtype->uchange = res_changeitem; - - return itype; -} - -static void -lt_register(luxury_type * ltype) -{ - ltype->itype->rtype->ltype = ltype; - ltype->next = luxurytypes; - luxurytypes = ltype; -} - -luxury_type * -new_luxurytype(item_type * itype, int price) -{ - luxury_type * ltype; - - assert(resource2luxury(itype->rtype) == NULL); - - ltype = calloc(sizeof(luxury_type), 1); - ltype->itype = itype; - ltype->price = price; - lt_register(ltype); - - return ltype; -} - -weapon_type * -new_weapontype(item_type * itype, - int wflags, double magres, const char* damage[], int offmod, int defmod, int reload, skill_t sk, int minskill) -{ - weapon_type * wtype; - - assert(resource2weapon(itype->rtype)==NULL); - - wtype = calloc(sizeof(weapon_type), 1); - if (damage) { - wtype->damage[0] = strdup(damage[0]); - wtype->damage[1] = strdup(damage[1]); - } - wtype->defmod = defmod; - wtype->flags |= wflags; - wtype->itype = itype; - wtype->magres = magres; - wtype->minskill = minskill; - wtype->offmod = offmod; - wtype->reload = reload; - wtype->skill = sk; - itype->rtype->wtype = wtype; - - return wtype; -} - - -armor_type * -new_armortype(item_type * itype, double penalty, double magres, int prot, unsigned int flags) -{ - armor_type * atype; - - assert(itype->rtype->atype==NULL); - - atype = calloc(sizeof(armor_type), 1); - - atype->itype = itype; - atype->penalty = penalty; - atype->magres = magres; - atype->prot = prot; - atype->flags = flags; - itype->rtype->atype = atype; - - return atype; -} - -static void -pt_register(potion_type * ptype) -{ - ptype->itype->rtype->ptype = ptype; - ptype->next = potiontypes; - potiontypes = ptype; -} - -potion_type * -new_potiontype(item_type * itype, - int level) -{ - potion_type * ptype; - - assert(resource2potion(itype->rtype)==NULL); - - ptype = calloc(sizeof(potion_type), 1); - ptype->itype = itype; - ptype->level = level; - pt_register(ptype); - - return ptype; -} - - -void -rt_register(resource_type * rtype) -{ - resource_type ** prtype = &resourcetypes; - - if (!rtype->hashkey) { - rtype->hashkey = hashstring(rtype->_name[0]); - } - while (*prtype && *prtype!=rtype) prtype=&(*prtype)->next; - if (*prtype == NULL) { - *prtype = rtype; - } -} - -const resource_type * -item2resource(const item_type * itype) -{ - return itype?itype->rtype:NULL; -} - -const item_type * -resource2item(const resource_type * rtype) -{ - return rtype?rtype->itype:NULL; -} - -const weapon_type * -resource2weapon(const resource_type * rtype) { - return rtype->wtype; -} - -const luxury_type * -resource2luxury(const resource_type * rtype) -{ -#ifdef AT_LTYPE - attrib * a = a_find(rtype->attribs, &at_ltype); - if (a) return (const luxury_type *)a->data.v; - return NULL; -#else - return rtype->ltype; -#endif -} - -const potion_type * -resource2potion(const resource_type * rtype) -{ -#ifdef AT_PTYPE - attrib * a = a_find(rtype->attribs, &at_ptype); - if (a) return (const potion_type *)a->data.v; - return NULL; -#else - return rtype->ptype; -#endif -} - -resource_type * -rt_find(const char * name) -{ - unsigned int hash = hashstring(name); - resource_type * rtype; - - for (rtype=resourcetypes; rtype; rtype=rtype->next) { - if (rtype->hashkey==hash && !strcmp(rtype->_name[0], name)) break; - } - - return rtype; -} - -static const char * it_aliases[][2] = { - { "Runenschwert", "runesword" }, - { "p12", "truthpotion" }, - { "p1", "goliathwater" }, - { "p4", "ointment" }, - { "p5", "peasantblood" }, - { "p8", "nestwarmth" }, - { "diamond", "adamantium" }, - { "diamondaxe", "adamantiumaxe" }, - { "diamondplate", "adamantiumplate" }, - { "aoh", "ao_healing" }, - { NULL, NULL }, -}; - -static const char * -it_alias(const char * zname) -{ - int i; - for (i=0;it_aliases[i][0];++i) { - if (strcmp(it_aliases[i][0], zname)==0) return it_aliases[i][1]; - } - return zname; -} - -item_type * -it_find(const char * zname) -{ - const char * name = it_alias(zname); - unsigned int hash = hashstring(name); - item_type * itype; - unsigned int key = hash % IMAXHASH; - - for (itype=itemtypes[key]; itype; itype=itype->next) { - if (itype->rtype->hashkey==hash && strcmp(itype->rtype->_name[0], name) == 0) { - break; - } - } - if (itype==NULL) { - for (itype=itemtypes[key]; itype; itype=itype->next) { - if (strcmp(itype->rtype->_name[1], name) == 0) break; - } - } - return itype; -} - -item ** -i_find(item ** i, const item_type * it) -{ - while (*i && (*i)->type!=it) i = &(*i)->next; - return i; -} - -item * const * -i_findc(item * const * i, const item_type * it) -{ - while (*i && (*i)->type!=it) { - i = &(*i)->next; - } - return i; -} - -int -i_get(const item * i, const item_type * it) -{ - i = *i_find((item**)&i, it); - if (i) return i->number; - return 0; -} - -item * -i_add(item ** pi, item * i) -{ - assert(i && i->type && !i->next); - while (*pi) { - int d = strcmp((*pi)->type->rtype->_name[0], i->type->rtype->_name[0]); - if (d>=0) break; - pi = &(*pi)->next; - } - if (*pi && (*pi)->type==i->type) { - (*pi)->number += i->number; - assert((*pi)->number>=0); - i_free(i); - } else { - i->next = *pi; - *pi = i; - } - return *pi; -} - -void -i_merge(item ** pi, item ** si) -{ - item * i = *si; - while (i) { - item * itmp; - while (*pi) { - int d = strcmp((*pi)->type->rtype->_name[0], i->type->rtype->_name[0]); - if (d>=0) break; - pi=&(*pi)->next; - } - if (*pi && (*pi)->type==i->type) { - (*pi)->number += i->number; - assert((*pi)->number>=0); - i_free(i_remove(&i, i)); - } else { - itmp = i->next; - i->next=*pi; - *pi = i; - i = itmp; - } - } - *si=NULL; -} - -item * -i_change(item ** pi, const item_type * itype, int delta) -{ - assert(itype); - while (*pi) { - int d = strcmp((*pi)->type->rtype->_name[0], itype->rtype->_name[0]); - if (d>=0) break; - pi=&(*pi)->next; - } - if (!*pi || (*pi)->type!=itype) { - item * i; - if (delta==0) return NULL; - i = i_new(itype, delta); - i->next = *pi; - *pi = i; - } else { - item * i = *pi; - i->number+=delta; - if (i->number<0) { - log_error(("serious accounting error. number of items is %d.\n", i->number)); - assert(i>=0); - i->number = 0; - } - if (i->number==0) { - *pi = i->next; - i_free(i); - return NULL; - } - } - return *pi; -} - -item * -i_remove(item ** pi, item * i) -{ - assert(i); - while ((*pi)->type!=i->type) pi = &(*pi)->next; - assert(*pi); - *pi = i->next; - i->next = NULL; - return i; -} - -static item * icache; -static int icache_size; -#define ICACHE_MAX 100 - -void -i_free(item * i) -{ - if (icache_size>=ICACHE_MAX) { - free(i); - } else { - i->next = icache; - icache = i; - ++icache_size; - } -} - -void -i_freeall(item **i) { - item *in; - - while(*i) { - in = (*i)->next; - i_free(*i); - *i = in; - } -} - - -item * -i_new(const item_type * itype, int size) -{ - item * i; - if (icache_size>0) { - i = icache; - icache = i->next; - --icache_size; - } else { - i = malloc(sizeof(item)); - } - assert(itype); - i->next = NULL; - i->type = itype; - i->number = size; - assert(i->number>=0); - return i; -} - -#include "region.h" - -static int -give_horses(unit * s, unit * d, const item_type * itype, int n, struct order * ord) -{ - if (d==NULL) { - int use = use_pooled(s, item2resource(itype), GET_SLACK, n); - if (useregion, rhorses(s->region) + use); - return 0; - } - return -1; /* use the mechanism */ -} - -static int -give_money(unit * s, unit * d, const item_type * itype, int n, struct order * ord) -{ - if (d==NULL) { - int use = use_pooled(s, item2resource(itype), GET_SLACK, n); - if (useregion, rmoney(s->region) + use); - return 0; - } - return -1; /* use the mechanism */ -} - -#define R_MINOTHER R_SILVER -#define R_MINHERB R_PLAIN_1 -#define R_MINPOTION R_FAST -#define R_MINITEM R_IRON -#define MAXITEMS MAX_ITEMS -#define MAXRESOURCES MAX_RESOURCES -#define MAXHERBS MAX_HERBS -#define MAXPOTIONS MAX_POTIONS -#define MAXHERBSPERPOTION 6 -#define FIRSTLUXURY (I_BALM) -#define LASTLUXURY (I_INCENSE +1) -#define MAXLUXURIES (LASTLUXURY - FIRSTLUXURY) - -const item_type * olditemtype[MAXITEMS+1]; -const resource_type * oldresourcetype[MAXRESOURCES+1]; -const potion_type * oldpotiontype[MAXPOTIONS+1]; - -/*** alte items ***/ - -int -get_item(const unit * u, item_t it) -{ - const item_type * type = olditemtype[it]; - const item * i = *i_findc(&u->items, type); - if (i) assert(i->number>=0); - return i?i->number:0; -} - -int -set_item(unit * u, item_t it, int value) -{ - const item_type * type = olditemtype[it]; - item * i = *i_find(&u->items, type); - if (!i) { - i = i_add(&u->items, i_new(type, value)); - } else { - i->number = value; - assert(i->number>=0); - } - return value; -} - -static int -use_birthdayamulet(unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - direction_t d; - message * msg = msg_message("meow", ""); - - unused(ord); - unused(amount); - unused(itype); - - add_message(&u->region->msgs, msg); - for(d=0;dregion, d); - if (tr) add_message(&tr->msgs, msg); - } - msg_release(msg); - return 0; -} - - -/* t_item::flags */ -#define FL_ITEM_CURSED (1<<0) -#define FL_ITEM_NOTLOST (1<<1) -#define FL_ITEM_NOTINBAG (1<<2) /* nicht im Bag Of Holding */ -#define FL_ITEM_ANIMAL (1<<3) /* ist ein Tier */ -#define FL_ITEM_MOUNT ((1<<4) | FL_ITEM_ANIMAL) /* ist ein Reittier */ - -/* ------------------------------------------------------------- */ -/* Kann auch von Nichtmagier benutzt werden, modifiziert Taktik für diese - * Runde um -1 - 4 Punkte. */ -static int -use_tacticcrystal(unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - int i; - for (i=0;i!=amount;++i) { - int duration = 1; /* wirkt nur eine Runde */ - float power = 5; /* Widerstand gegen Antimagiesprüche, ist in diesem - Fall egal, da der curse für den Kampf gelten soll, - der vor den Antimagiezaubern passiert */ - curse * c; - double effect; - - effect = rng_int()%6 - 1; - c = create_curse(u, &u->attribs, ct_find("skillmod"), power, - duration, effect, u->number); - c->data.i = SK_TACTICS; - unused(ord); - } - use_pooled(u, itype->rtype, GET_DEFAULT, amount); - ADDMSG(&u->faction->msgs, msg_message("use_tacticcrystal", - "unit region", u, u->region)); - return 0; -} - -typedef struct t_item { - const char *name; - /* [0]: Einzahl für eigene; [1]: Mehrzahl für eigene; - * [2]: Einzahl für Fremde; [3]: Mehrzahl für Fremde */ - boolean is_resource; - skill_t skill; - int minskill; - int gewicht; - int preis; - unsigned int flags; - void (*benutze_funktion) (struct region *, struct unit *, int amount, struct order *); -} t_item; - -const char * itemnames[MAXITEMS] = { - "iron", "stone", "horse", "ao_healing", - "aots", "roi", "rop", "ao_chastity", - "laen", "fairyboot", "aoc", "pegasus", - "elvenhorse", "dolphin", "roqf", "trollbelt", - "presspass", "aurafocus", "sphereofinv", "magicbag", - "magicherbbag", "dreameye" -}; - -#include "move.h" - -static int -mod_elves_only(const unit * u, const region * r, skill_t sk, int value) -{ - if (u->race == new_race[RC_ELF]) return value; - unused(r); - return -118; -} - -static int -mod_dwarves_only(const unit * u, const region * r, skill_t sk, int value) -{ - if (u->race == new_race[RC_DWARF]) return value; - unused(r); - return -118; -} - -static void -init_olditems(void) -{ - item_t i; -#if 0 - resource_type * rtype; - const struct locale * lang = find_locale("de"); - assert(lang); -#endif - - for (i=0; i!=MAXITEMS; ++i) { - /* item is defined in XML file, but IT_XYZ enum still in use */ - const item_type * itype = it_find(itemnames[i]); - - if (itype) { - olditemtype[i] = itype; - oldresourcetype[i] = itype->rtype; - } - } -} - -static int -heal(unit * user, int effect) -{ - int req = unit_max_hp(user) * user->number - user->hp; - if (req>0) { - req = MIN(req, effect); - effect -= req; - user->hp += req; - } - return effect; -} - -void -register_item_give(int (*foo) (struct unit *, struct unit *, const struct item_type *, int, struct order *), const char * name) -{ - register_function((pf_generic)foo, name); -} - -void -register_item_use(int (*foo) (struct unit *, const struct item_type *, int, struct order *), const char * name) -{ - register_function((pf_generic)foo, name); -} - -void -register_item_useonother(int (*foo) (struct unit *, int, const struct item_type *, int, struct order *), const char * name) -{ - register_function((pf_generic)foo, name); -} - -static int -use_healingpotion(struct unit *user, const struct item_type *itype, int amount, struct order * ord) -{ - int effect = amount * 400; - unit * u = user->region->units; - effect = heal(user, effect); - while (effect>0 && u!=NULL) { - if (u->faction==user->faction) { - effect = heal(u, effect); - } - u = u->next; - } - use_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); - usetpotionuse(user, itype->rtype->ptype); - - ADDMSG(&user->faction->msgs, msg_message("usepotion", - "unit potion", user, itype->rtype)); - return 0; -} - -static int -use_warmthpotion(struct unit *u, const struct item_type *itype, int amount, struct order * ord) -{ - if (u->faction->race == new_race[RC_INSECT]) { - fset(u, UFL_WARMTH); - } else { - /* nur für insekten: */ - cmistake(u, ord, 163, MSG_EVENT); - return ECUSTOM; - } - use_pooled(u, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); - usetpotionuse(u, itype->rtype->ptype); - - ADDMSG(&u->faction->msgs, msg_message("usepotion", - "unit potion", u, itype->rtype)); - return 0; -} - -static int -use_foolpotion(struct unit *u, int targetno, const struct item_type *itype, int amount, struct order * ord) -{ - unit * target = findunit(targetno); - if (target==NULL || u->region!=target->region) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return ECUSTOM; - } - if (effskill(u, SK_STEALTH)<=effskill(target, SK_PERCEPTION)) { - cmistake(u, ord, 64, MSG_EVENT); - return ECUSTOM; - } - ADDMSG(&u->faction->msgs, msg_message("givedumb", - "unit recipient amount", u, target, amount)); - - change_effect(target, itype->rtype->ptype, amount); - use_pooled(u, itype->rtype, GET_DEFAULT, amount); - return 0; -} - -static int -use_bloodpotion(struct unit *u, const struct item_type *itype, int amount, struct order * ord) -{ - if (u->race == new_race[RC_DAEMON]) { - change_effect(u, itype->rtype->ptype, 100*amount); - } else { - const race * irace = u_irace(u); - if (irace == u->race) { - static race * rcfailure; - if (!rcfailure) { - rcfailure = rc_find("smurf"); - if (!rcfailure) rcfailure = rc_find("toad"); - } - if (rcfailure) { - trigger * trestore = trigger_changerace(u, u->race, irace); - if (trestore) { - int duration = 2 + rng_int() % 8; - - add_trigger(&u->attribs, "timer", trigger_timeout(duration, trestore)); - u->irace = NULL; - u->race = rcfailure; - } - } - } - } - use_pooled(u, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); - usetpotionuse(u, itype->rtype->ptype); - - ADDMSG(&u->faction->msgs, msg_message("usepotion", - "unit potion", u, itype->rtype)); - return 0; -} - -#include -static int -use_mistletoe(struct unit * user, const struct item_type * itype, int amount, struct order * ord) -{ - int mtoes = get_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); - - if (user->number>mtoes) { - ADDMSG(&user->faction->msgs, msg_message("use_singleperson", - "unit item region command", user, itype->rtype, user->region, ord)); - return -1; - } - use_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); - a_add(&user->attribs, make_fleechance((float)1.0)); - ADDMSG(&user->faction->msgs, - msg_message("use_item", "unit item", user, itype->rtype)); - - return 0; -} - -static int -use_magicboost(struct unit * user, const struct item_type * itype, int amount, struct order * ord) -{ - int mtoes = get_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); - faction * f = user->faction; - if (user->number>mtoes) { - ADDMSG(&user->faction->msgs, msg_message("use_singleperson", - "unit item region command", user, itype->rtype, user->region, ord)); - return -1; - } - if (!is_mage(user) || find_key(f->attribs, atoi36("mbst"))!=NULL) { - cmistake(user, user->thisorder, 214, MSG_EVENT); - return -1; - } - use_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); - - a_add(&f->attribs, make_key(atoi36("mbst"))); - set_level(user, sk_find("magic"), 3); - - ADDMSG(&user->faction->msgs, msg_message("use_item", - "unit item", user, itype->rtype)); - - return 0; -} - -static int -use_snowball(struct unit * user, const struct item_type * itype, int amount, struct order * ord) -{ - return 0; -} - -static void -init_oldpotions(void) -{ - const char * potionnames[MAX_POTIONS] = { - "p0", "goliathwater", "p2", "p3", "ointment", "peasantblood", "p6", - "p7", "nestwarmth", "p9", "p10", "p11", "truthpotion", "p13", "p14" - }; - int p; - - for (p=0;p!=MAXPOTIONS;++p) { - item_type * itype = it_find(potionnames[p]); - if (itype!=NULL) { - oldpotiontype[p] = itype->rtype->ptype; - } - } -} - -resource_type * r_silver; -resource_type * r_aura; -resource_type * r_permaura; -resource_type * r_unit; -resource_type * r_hp; - -resource_type * r_silver; -item_type * i_silver; - -static const char * names[] = { - "money", "money_p", - "person", "person_p", - "permaura", "permaura_p", - "hp", "hp_p", - "peasant", "peasant_p", - "aura", "aura_p", - "unit", "unit_p" -}; - -void -init_resources(void) -{ - static boolean initialized = false; - if (initialized) return; - initialized = true; - - /* silver was never an item: */ - r_silver = new_resourcetype(&names[0], NULL, RTF_ITEM|RTF_POOLED); - i_silver = new_itemtype(r_silver, ITF_NONE, 1/*weight*/, 0); - r_silver->uchange = res_changeitem; - i_silver->give = give_money; - - r_permaura = new_resourcetype(&names[4], NULL, RTF_NONE); - r_permaura->uchange = res_changepermaura; - - r_hp = new_resourcetype(&names[6], NULL, RTF_NONE); - r_hp->uchange = res_changehp; - - r_aura = new_resourcetype(&names[10], NULL, RTF_NONE); - r_aura->uchange = res_changeaura; - - r_unit = new_resourcetype(&names[12], NULL, RTF_NONE); - r_unit->uchange = res_changeperson; - - oldresourcetype[R_SILVER] = r_silver; - oldresourcetype[R_AURA] = r_aura; - oldresourcetype[R_PERMAURA] = r_permaura; - - /* alte typen registrieren: */ - init_olditems(); - init_oldpotions(); -} - -int -get_money(const unit * u) -{ - const item * i = u->items; - while (i && i->type!=i_silver) i=i->next; - if (i==NULL) return 0; - return i->number; -} - -int -set_money(unit * u, int v) -{ - item ** ip = &u->items; - while (*ip && (*ip)->type!=i_silver) ip = &(*ip)->next; - if ((*ip)==NULL && v) { - i_add(&u->items, i_new(i_silver, v)); - return v; - } - if ((*ip)!=NULL) { - if (v) { - (*ip)->number = v; - assert((*ip)->number>=0); - } - else i_remove(ip, *ip); - } - return v; -} - -int -change_money(unit * u, int v) -{ - item ** ip = &u->items; - while (*ip && (*ip)->type!=i_silver) ip = &(*ip)->next; - if ((*ip)==NULL && v) { - i_add(&u->items, i_new(i_silver, v)); - return v; - } - if ((*ip)!=NULL) { - item * i = *ip; - if (i->number + v != 0) { - i->number += v; - assert(i->number>=0); - return i->number; - } - else i_free(i_remove(ip, *ip)); - } - return 0; -} - - -static local_names * rnames; - -const resource_type * -findresourcetype(const char * name, const struct locale * lang) -{ - local_names * rn = rnames; - variant token; - - while (rn) { - if (rn->lang==lang) break; - rn = rn->next; - } - if (!rn) { - const resource_type * rtl = resourcetypes; - rn = calloc(sizeof(local_names), 1); - rn->next = rnames; - rn->lang = lang; - while (rtl) { - token.v = (void*)rtl; - addtoken(&rn->names, locale_string(lang, rtl->_name[0]), token); - addtoken(&rn->names, locale_string(lang, rtl->_name[1]), token); - rtl=rtl->next; - } - rnames = rn; - } - - if (findtoken(&rn->names, name, &token)==E_TOK_NOMATCH) return NULL; - return (const resource_type*)token.v; -} - -attrib_type at_showitem = { - "showitem" -}; - -static local_names * inames; - -void -init_itemnames(void) -{ - int i; - for (i=0;localenames[i];++i) { - const struct locale * lang = find_locale(localenames[i]); - boolean exist = false; - local_names * in = inames; - - while (in!=NULL) { - if (in->lang==lang) { - exist = true; - break; - } - in = in->next; - } - if (in==NULL) in = calloc(sizeof(local_names), 1); - in->next = inames; - in->lang = lang; - - if (!exist) { - int key; - for (key=0;key!=IMAXHASH;++key) { - const item_type * itl; - for (itl=itemtypes[key];itl;itl=itl->next) { - variant var; - const char * iname = locale_string(lang, itl->rtype->_name[0]); - if (findtoken(&in->names, iname, &var)==E_TOK_NOMATCH || var.v!=itl) { - var.v = (void*)itl; - addtoken(&in->names, iname, var); - addtoken(&in->names, locale_string(lang, itl->rtype->_name[1]), var); - } - } - } - } - inames = in; - } -} - -const item_type * -finditemtype(const char * name, const struct locale * lang) -{ - local_names * in = inames; - variant var; - - while (in!=NULL) { - if (in->lang==lang) break; - in=in->next; - } - if (in==NULL) { - init_itemnames(); - for (in=inames;in->lang!=lang;in=in->next) ; - } - if (findtoken(&in->names, name, &var)==E_TOK_NOMATCH) return NULL; - return (const item_type*)var.v; -} - -static void -init_resourcelimit(attrib * a) -{ - a->data.v = calloc(sizeof(resource_limit), 1); -} - -static void -finalize_resourcelimit(attrib * a) -{ - free(a->data.v); -} - -attrib_type at_resourcelimit = { - "resourcelimit", - init_resourcelimit, - finalize_resourcelimit, -}; - -void -register_resources(void) -{ - register_function((pf_generic)mod_elves_only, "mod_elves_only"); - register_function((pf_generic)mod_dwarves_only, "mod_dwarves_only"); - register_function((pf_generic)res_changeitem, "changeitem"); - register_function((pf_generic)res_changeperson, "changeperson"); - register_function((pf_generic)res_changepeasants, "changepeasants"); - register_function((pf_generic)res_changepermaura, "changepermaura"); - register_function((pf_generic)res_changehp, "changehp"); - register_function((pf_generic)res_changeaura, "changeaura"); - - register_item_use(use_potion, "usepotion"); - register_item_use(use_potion_delayed, "usepotion_delayed"); - register_item_use(use_tacticcrystal, "use_tacticcrystal"); - register_item_use(use_birthdayamulet, "use_birthdayamulet"); - register_item_use(use_warmthpotion, "usewarmthpotion"); - register_item_use(use_bloodpotion, "usebloodpotion"); - register_item_use(use_healingpotion, "usehealingpotion"); - register_item_useonother(use_foolpotion, "usefoolpotion"); - register_item_use(use_mistletoe, "usemistletoe"); - register_item_use(use_magicboost, "usemagicboost"); - register_item_use(use_snowball, "usesnowball"); - - register_item_give(give_horses, "givehorses"); - - /* make sure noone has deleted an I_ tpe without deleting the R_ type that goes with it! */ - assert((int)I_TACTICCRYSTAL == (int)R_TACTICCRYSTAL); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "item.h" + +#include + +#include "alchemy.h" +#include "build.h" +#include "faction.h" +#include "message.h" +#include "pool.h" +#include "race.h" +#include "region.h" +#include "save.h" +#include "skill.h" +#include "terrain.h" +#include "unit.h" + +/* triggers includes */ +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +resource_type * resourcetypes; +luxury_type * luxurytypes; +potion_type * potiontypes; + +#define IMAXHASH 127 +static item_type * itemtypes[IMAXHASH]; + +static int +res_changeaura(unit * u, const resource_type * rtype, int delta) +{ + assert(rtype!=NULL); + change_spellpoints(u, delta); + return 0; +} + +static int +res_changeperson(unit * u, const resource_type * rtype, int delta) +{ + assert(rtype!=NULL || !"not implemented"); + scale_number(u, u->number+delta); + return 0; +} + +static int +res_changepermaura(unit * u, const resource_type * rtype, int delta) +{ + assert(rtype!=NULL); + change_maxspellpoints(u, delta); + return 0; +} + +static int +res_changehp(unit * u, const resource_type * rtype, int delta) +{ + assert(rtype!=NULL); + u->hp+=delta; + return 0; +} + +static int +res_changepeasants(unit * u, const resource_type * rtype, int delta) +{ + assert(rtype!=NULL && u->region->land); + u->region->land->peasants+=delta; + return 0; +} + +int +res_changeitem(unit * u, const resource_type * rtype, int delta) +{ + int num; + if (rtype == oldresourcetype[R_STONE] && u->race==new_race[RC_STONEGOLEM] && delta<=0) { + int reduce = delta / GOLEM_STONE; + if (delta % GOLEM_STONE != 0) --reduce; + scale_number(u, u->number+reduce); + num = u->number; + } else if (rtype == oldresourcetype[R_IRON] && u->race==new_race[RC_IRONGOLEM] && delta<=0) { + int reduce = delta / GOLEM_IRON; + if (delta % GOLEM_IRON != 0) --reduce; + scale_number(u, u->number+reduce); + num = u->number; + } else { + const item_type * itype = resource2item(rtype); + item * i; + assert(itype!=NULL); + i = i_change(&u->items, itype, delta); + if (i==NULL) return 0; + num = i->number; + } + return num; +} + +const char * +resourcename(const resource_type * rtype, int flags) +{ + int i = 0; + + if (rtype) { + if (rtype->name) return rtype->name(rtype, flags); + + if (flags & NMF_PLURAL) i = 1; + if (flags & NMF_APPEARANCE && rtype->_appearance[i]) { + return rtype->_appearance[i]; + } + return rtype->_name[i]; + } + return "none"; +} + +resource_type * +new_resourcetype(const char ** names, const char ** appearances, int flags) +{ + resource_type * rtype = rt_find(names[0]); + + if (rtype==NULL) { + int i; + rtype = calloc(sizeof(resource_type), 1); + + for (i=0; i!=2; ++i) { + rtype->_name[i] = strdup(names[i]); + if (appearances) rtype->_appearance[i] = strdup(appearances[i]); + else rtype->_appearance[i] = NULL; + } + rt_register(rtype); + } +#ifndef NDEBUG + else { + /* TODO: check that this is the same type */ + } +#endif + rtype->flags |= flags; + return rtype; +} + +void +it_register(item_type * itype) +{ + int hash = hashstring(itype->rtype->_name[0]); + int key = hash % IMAXHASH; + item_type ** p_itype = &itemtypes[key]; + while (*p_itype && *p_itype != itype) p_itype = &(*p_itype)->next; + if (*p_itype==NULL) { + itype->rtype->itype = itype; + *p_itype = itype; + rt_register(itype->rtype); + } +} + +item_type * +new_itemtype(resource_type * rtype, + int iflags, int weight, int capacity) +{ + item_type * itype; + assert(resource2item(rtype) == NULL); + assert(rtype->flags & RTF_ITEM); + + itype = calloc(sizeof(item_type), 1); + + itype->rtype = rtype; + itype->weight = weight; + itype->capacity = capacity; + itype->flags |= iflags; + it_register(itype); + + rtype->uchange = res_changeitem; + + return itype; +} + +static void +lt_register(luxury_type * ltype) +{ + ltype->itype->rtype->ltype = ltype; + ltype->next = luxurytypes; + luxurytypes = ltype; +} + +luxury_type * +new_luxurytype(item_type * itype, int price) +{ + luxury_type * ltype; + + assert(resource2luxury(itype->rtype) == NULL); + + ltype = calloc(sizeof(luxury_type), 1); + ltype->itype = itype; + ltype->price = price; + lt_register(ltype); + + return ltype; +} + +weapon_type * +new_weapontype(item_type * itype, + int wflags, double magres, const char* damage[], int offmod, int defmod, int reload, skill_t sk, int minskill) +{ + weapon_type * wtype; + + assert(resource2weapon(itype->rtype)==NULL); + + wtype = calloc(sizeof(weapon_type), 1); + if (damage) { + wtype->damage[0] = strdup(damage[0]); + wtype->damage[1] = strdup(damage[1]); + } + wtype->defmod = defmod; + wtype->flags |= wflags; + wtype->itype = itype; + wtype->magres = magres; + wtype->minskill = minskill; + wtype->offmod = offmod; + wtype->reload = reload; + wtype->skill = sk; + itype->rtype->wtype = wtype; + + return wtype; +} + + +armor_type * +new_armortype(item_type * itype, double penalty, double magres, int prot, unsigned int flags) +{ + armor_type * atype; + + assert(itype->rtype->atype==NULL); + + atype = calloc(sizeof(armor_type), 1); + + atype->itype = itype; + atype->penalty = penalty; + atype->magres = magres; + atype->prot = prot; + atype->flags = flags; + itype->rtype->atype = atype; + + return atype; +} + +static void +pt_register(potion_type * ptype) +{ + ptype->itype->rtype->ptype = ptype; + ptype->next = potiontypes; + potiontypes = ptype; +} + +potion_type * +new_potiontype(item_type * itype, + int level) +{ + potion_type * ptype; + + assert(resource2potion(itype->rtype)==NULL); + + ptype = calloc(sizeof(potion_type), 1); + ptype->itype = itype; + ptype->level = level; + pt_register(ptype); + + return ptype; +} + + +void +rt_register(resource_type * rtype) +{ + resource_type ** prtype = &resourcetypes; + + if (!rtype->hashkey) { + rtype->hashkey = hashstring(rtype->_name[0]); + } + while (*prtype && *prtype!=rtype) prtype=&(*prtype)->next; + if (*prtype == NULL) { + *prtype = rtype; + } +} + +const resource_type * +item2resource(const item_type * itype) +{ + return itype?itype->rtype:NULL; +} + +const item_type * +resource2item(const resource_type * rtype) +{ + return rtype?rtype->itype:NULL; +} + +const weapon_type * +resource2weapon(const resource_type * rtype) { + return rtype->wtype; +} + +const luxury_type * +resource2luxury(const resource_type * rtype) +{ +#ifdef AT_LTYPE + attrib * a = a_find(rtype->attribs, &at_ltype); + if (a) return (const luxury_type *)a->data.v; + return NULL; +#else + return rtype->ltype; +#endif +} + +const potion_type * +resource2potion(const resource_type * rtype) +{ +#ifdef AT_PTYPE + attrib * a = a_find(rtype->attribs, &at_ptype); + if (a) return (const potion_type *)a->data.v; + return NULL; +#else + return rtype->ptype; +#endif +} + +resource_type * +rt_find(const char * name) +{ + unsigned int hash = hashstring(name); + resource_type * rtype; + + for (rtype=resourcetypes; rtype; rtype=rtype->next) { + if (rtype->hashkey==hash && !strcmp(rtype->_name[0], name)) break; + } + + return rtype; +} + +static const char * it_aliases[][2] = { + { "Runenschwert", "runesword" }, + { "p12", "truthpotion" }, + { "p1", "goliathwater" }, + { "p4", "ointment" }, + { "p5", "peasantblood" }, + { "p8", "nestwarmth" }, + { "diamond", "adamantium" }, + { "diamondaxe", "adamantiumaxe" }, + { "diamondplate", "adamantiumplate" }, + { "aoh", "ao_healing" }, + { NULL, NULL }, +}; + +static const char * +it_alias(const char * zname) +{ + int i; + for (i=0;it_aliases[i][0];++i) { + if (strcmp(it_aliases[i][0], zname)==0) return it_aliases[i][1]; + } + return zname; +} + +item_type * +it_find(const char * zname) +{ + const char * name = it_alias(zname); + unsigned int hash = hashstring(name); + item_type * itype; + unsigned int key = hash % IMAXHASH; + + for (itype=itemtypes[key]; itype; itype=itype->next) { + if (itype->rtype->hashkey==hash && strcmp(itype->rtype->_name[0], name) == 0) { + break; + } + } + if (itype==NULL) { + for (itype=itemtypes[key]; itype; itype=itype->next) { + if (strcmp(itype->rtype->_name[1], name) == 0) break; + } + } + return itype; +} + +item ** +i_find(item ** i, const item_type * it) +{ + while (*i && (*i)->type!=it) i = &(*i)->next; + return i; +} + +item * const * +i_findc(item * const * i, const item_type * it) +{ + while (*i && (*i)->type!=it) { + i = &(*i)->next; + } + return i; +} + +int +i_get(const item * i, const item_type * it) +{ + i = *i_find((item**)&i, it); + if (i) return i->number; + return 0; +} + +item * +i_add(item ** pi, item * i) +{ + assert(i && i->type && !i->next); + while (*pi) { + int d = strcmp((*pi)->type->rtype->_name[0], i->type->rtype->_name[0]); + if (d>=0) break; + pi = &(*pi)->next; + } + if (*pi && (*pi)->type==i->type) { + (*pi)->number += i->number; + assert((*pi)->number>=0); + i_free(i); + } else { + i->next = *pi; + *pi = i; + } + return *pi; +} + +void +i_merge(item ** pi, item ** si) +{ + item * i = *si; + while (i) { + item * itmp; + while (*pi) { + int d = strcmp((*pi)->type->rtype->_name[0], i->type->rtype->_name[0]); + if (d>=0) break; + pi=&(*pi)->next; + } + if (*pi && (*pi)->type==i->type) { + (*pi)->number += i->number; + assert((*pi)->number>=0); + i_free(i_remove(&i, i)); + } else { + itmp = i->next; + i->next=*pi; + *pi = i; + i = itmp; + } + } + *si=NULL; +} + +item * +i_change(item ** pi, const item_type * itype, int delta) +{ + assert(itype); + while (*pi) { + int d = strcmp((*pi)->type->rtype->_name[0], itype->rtype->_name[0]); + if (d>=0) break; + pi=&(*pi)->next; + } + if (!*pi || (*pi)->type!=itype) { + item * i; + if (delta==0) return NULL; + i = i_new(itype, delta); + i->next = *pi; + *pi = i; + } else { + item * i = *pi; + i->number+=delta; + if (i->number<0) { + log_error(("serious accounting error. number of items is %d.\n", i->number)); + assert(i>=0); + i->number = 0; + } + if (i->number==0) { + *pi = i->next; + i_free(i); + return NULL; + } + } + return *pi; +} + +item * +i_remove(item ** pi, item * i) +{ + assert(i); + while ((*pi)->type!=i->type) pi = &(*pi)->next; + assert(*pi); + *pi = i->next; + i->next = NULL; + return i; +} + +static item * icache; +static int icache_size; +#define ICACHE_MAX 100 + +void +i_free(item * i) +{ + if (icache_size>=ICACHE_MAX) { + free(i); + } else { + i->next = icache; + icache = i; + ++icache_size; + } +} + +void +i_freeall(item **i) { + item *in; + + while(*i) { + in = (*i)->next; + i_free(*i); + *i = in; + } +} + + +item * +i_new(const item_type * itype, int size) +{ + item * i; + if (icache_size>0) { + i = icache; + icache = i->next; + --icache_size; + } else { + i = malloc(sizeof(item)); + } + assert(itype); + i->next = NULL; + i->type = itype; + i->number = size; + assert(i->number>=0); + return i; +} + +#include "region.h" + +static int +give_horses(unit * s, unit * d, const item_type * itype, int n, struct order * ord) +{ + if (d==NULL) { + int use = use_pooled(s, item2resource(itype), GET_SLACK, n); + if (useregion, rhorses(s->region) + use); + return 0; + } + return -1; /* use the mechanism */ +} + +static int +give_money(unit * s, unit * d, const item_type * itype, int n, struct order * ord) +{ + if (d==NULL) { + int use = use_pooled(s, item2resource(itype), GET_SLACK, n); + if (useregion, rmoney(s->region) + use); + return 0; + } + return -1; /* use the mechanism */ +} + +#define R_MINOTHER R_SILVER +#define R_MINHERB R_PLAIN_1 +#define R_MINPOTION R_FAST +#define R_MINITEM R_IRON +#define MAXITEMS MAX_ITEMS +#define MAXRESOURCES MAX_RESOURCES +#define MAXHERBS MAX_HERBS +#define MAXPOTIONS MAX_POTIONS +#define MAXHERBSPERPOTION 6 +#define FIRSTLUXURY (I_BALM) +#define LASTLUXURY (I_INCENSE +1) +#define MAXLUXURIES (LASTLUXURY - FIRSTLUXURY) + +const item_type * olditemtype[MAXITEMS+1]; +const resource_type * oldresourcetype[MAXRESOURCES+1]; +const potion_type * oldpotiontype[MAXPOTIONS+1]; + +/*** alte items ***/ + +int +get_item(const unit * u, item_t it) +{ + const item_type * type = olditemtype[it]; + const item * i = *i_findc(&u->items, type); + if (i) assert(i->number>=0); + return i?i->number:0; +} + +int +set_item(unit * u, item_t it, int value) +{ + const item_type * type = olditemtype[it]; + item * i = *i_find(&u->items, type); + if (!i) { + i = i_add(&u->items, i_new(type, value)); + } else { + i->number = value; + assert(i->number>=0); + } + return value; +} + +static int +use_birthdayamulet(unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + direction_t d; + message * msg = msg_message("meow", ""); + + unused(ord); + unused(amount); + unused(itype); + + add_message(&u->region->msgs, msg); + for(d=0;dregion, d); + if (tr) add_message(&tr->msgs, msg); + } + msg_release(msg); + return 0; +} + + +/* t_item::flags */ +#define FL_ITEM_CURSED (1<<0) +#define FL_ITEM_NOTLOST (1<<1) +#define FL_ITEM_NOTINBAG (1<<2) /* nicht im Bag Of Holding */ +#define FL_ITEM_ANIMAL (1<<3) /* ist ein Tier */ +#define FL_ITEM_MOUNT ((1<<4) | FL_ITEM_ANIMAL) /* ist ein Reittier */ + +/* ------------------------------------------------------------- */ +/* Kann auch von Nichtmagier benutzt werden, modifiziert Taktik für diese + * Runde um -1 - 4 Punkte. */ +static int +use_tacticcrystal(unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + int i; + for (i=0;i!=amount;++i) { + int duration = 1; /* wirkt nur eine Runde */ + float power = 5; /* Widerstand gegen Antimagiesprüche, ist in diesem + Fall egal, da der curse für den Kampf gelten soll, + der vor den Antimagiezaubern passiert */ + curse * c; + double effect; + + effect = rng_int()%6 - 1; + c = create_curse(u, &u->attribs, ct_find("skillmod"), power, + duration, effect, u->number); + c->data.i = SK_TACTICS; + unused(ord); + } + use_pooled(u, itype->rtype, GET_DEFAULT, amount); + ADDMSG(&u->faction->msgs, msg_message("use_tacticcrystal", + "unit region", u, u->region)); + return 0; +} + +typedef struct t_item { + const char *name; + /* [0]: Einzahl für eigene; [1]: Mehrzahl für eigene; + * [2]: Einzahl für Fremde; [3]: Mehrzahl für Fremde */ + boolean is_resource; + skill_t skill; + int minskill; + int gewicht; + int preis; + unsigned int flags; + void (*benutze_funktion) (struct region *, struct unit *, int amount, struct order *); +} t_item; + +const char * itemnames[MAXITEMS] = { + "iron", "stone", "horse", "ao_healing", + "aots", "roi", "rop", "ao_chastity", + "laen", "fairyboot", "aoc", "pegasus", + "elvenhorse", "dolphin", "roqf", "trollbelt", + "presspass", "aurafocus", "sphereofinv", "magicbag", + "magicherbbag", "dreameye" +}; + +#include "move.h" + +static int +mod_elves_only(const unit * u, const region * r, skill_t sk, int value) +{ + if (u->race == new_race[RC_ELF]) return value; + unused(r); + return -118; +} + +static int +mod_dwarves_only(const unit * u, const region * r, skill_t sk, int value) +{ + if (u->race == new_race[RC_DWARF]) return value; + unused(r); + return -118; +} + +static void +init_olditems(void) +{ + item_t i; +#if 0 + resource_type * rtype; + const struct locale * lang = find_locale("de"); + assert(lang); +#endif + + for (i=0; i!=MAXITEMS; ++i) { + /* item is defined in XML file, but IT_XYZ enum still in use */ + const item_type * itype = it_find(itemnames[i]); + + if (itype) { + olditemtype[i] = itype; + oldresourcetype[i] = itype->rtype; + } + } +} + +static int +heal(unit * user, int effect) +{ + int req = unit_max_hp(user) * user->number - user->hp; + if (req>0) { + req = MIN(req, effect); + effect -= req; + user->hp += req; + } + return effect; +} + +void +register_item_give(int (*foo) (struct unit *, struct unit *, const struct item_type *, int, struct order *), const char * name) +{ + register_function((pf_generic)foo, name); +} + +void +register_item_use(int (*foo) (struct unit *, const struct item_type *, int, struct order *), const char * name) +{ + register_function((pf_generic)foo, name); +} + +void +register_item_useonother(int (*foo) (struct unit *, int, const struct item_type *, int, struct order *), const char * name) +{ + register_function((pf_generic)foo, name); +} + +static int +use_healingpotion(struct unit *user, const struct item_type *itype, int amount, struct order * ord) +{ + int effect = amount * 400; + unit * u = user->region->units; + effect = heal(user, effect); + while (effect>0 && u!=NULL) { + if (u->faction==user->faction) { + effect = heal(u, effect); + } + u = u->next; + } + use_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); + usetpotionuse(user, itype->rtype->ptype); + + ADDMSG(&user->faction->msgs, msg_message("usepotion", + "unit potion", user, itype->rtype)); + return 0; +} + +static int +use_warmthpotion(struct unit *u, const struct item_type *itype, int amount, struct order * ord) +{ + if (u->faction->race == new_race[RC_INSECT]) { + fset(u, UFL_WARMTH); + } else { + /* nur für insekten: */ + cmistake(u, ord, 163, MSG_EVENT); + return ECUSTOM; + } + use_pooled(u, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); + usetpotionuse(u, itype->rtype->ptype); + + ADDMSG(&u->faction->msgs, msg_message("usepotion", + "unit potion", u, itype->rtype)); + return 0; +} + +static int +use_foolpotion(struct unit *u, int targetno, const struct item_type *itype, int amount, struct order * ord) +{ + unit * target = findunit(targetno); + if (target==NULL || u->region!=target->region) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return ECUSTOM; + } + if (effskill(u, SK_STEALTH)<=effskill(target, SK_PERCEPTION)) { + cmistake(u, ord, 64, MSG_EVENT); + return ECUSTOM; + } + ADDMSG(&u->faction->msgs, msg_message("givedumb", + "unit recipient amount", u, target, amount)); + + change_effect(target, itype->rtype->ptype, amount); + use_pooled(u, itype->rtype, GET_DEFAULT, amount); + return 0; +} + +static int +use_bloodpotion(struct unit *u, const struct item_type *itype, int amount, struct order * ord) +{ + if (u->race == new_race[RC_DAEMON]) { + change_effect(u, itype->rtype->ptype, 100*amount); + } else { + const race * irace = u_irace(u); + if (irace == u->race) { + static race * rcfailure; + if (!rcfailure) { + rcfailure = rc_find("smurf"); + if (!rcfailure) rcfailure = rc_find("toad"); + } + if (rcfailure) { + trigger * trestore = trigger_changerace(u, u->race, irace); + if (trestore) { + int duration = 2 + rng_int() % 8; + + add_trigger(&u->attribs, "timer", trigger_timeout(duration, trestore)); + u->irace = NULL; + u->race = rcfailure; + } + } + } + } + use_pooled(u, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); + usetpotionuse(u, itype->rtype->ptype); + + ADDMSG(&u->faction->msgs, msg_message("usepotion", + "unit potion", u, itype->rtype)); + return 0; +} + +#include +static int +use_mistletoe(struct unit * user, const struct item_type * itype, int amount, struct order * ord) +{ + int mtoes = get_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); + + if (user->number>mtoes) { + ADDMSG(&user->faction->msgs, msg_message("use_singleperson", + "unit item region command", user, itype->rtype, user->region, ord)); + return -1; + } + use_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); + a_add(&user->attribs, make_fleechance((float)1.0)); + ADDMSG(&user->faction->msgs, + msg_message("use_item", "unit item", user, itype->rtype)); + + return 0; +} + +static int +use_magicboost(struct unit * user, const struct item_type * itype, int amount, struct order * ord) +{ + int mtoes = get_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); + faction * f = user->faction; + if (user->number>mtoes) { + ADDMSG(&user->faction->msgs, msg_message("use_singleperson", + "unit item region command", user, itype->rtype, user->region, ord)); + return -1; + } + if (!is_mage(user) || find_key(f->attribs, atoi36("mbst"))!=NULL) { + cmistake(user, user->thisorder, 214, MSG_EVENT); + return -1; + } + use_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); + + a_add(&f->attribs, make_key(atoi36("mbst"))); + set_level(user, sk_find("magic"), 3); + + ADDMSG(&user->faction->msgs, msg_message("use_item", + "unit item", user, itype->rtype)); + + return 0; +} + +static int +use_snowball(struct unit * user, const struct item_type * itype, int amount, struct order * ord) +{ + return 0; +} + +static void +init_oldpotions(void) +{ + const char * potionnames[MAX_POTIONS] = { + "p0", "goliathwater", "p2", "p3", "ointment", "peasantblood", "p6", + "p7", "nestwarmth", "p9", "p10", "p11", "truthpotion", "p13", "p14" + }; + int p; + + for (p=0;p!=MAXPOTIONS;++p) { + item_type * itype = it_find(potionnames[p]); + if (itype!=NULL) { + oldpotiontype[p] = itype->rtype->ptype; + } + } +} + +resource_type * r_silver; +resource_type * r_aura; +resource_type * r_permaura; +resource_type * r_unit; +resource_type * r_hp; + +resource_type * r_silver; +item_type * i_silver; + +static const char * names[] = { + "money", "money_p", + "person", "person_p", + "permaura", "permaura_p", + "hp", "hp_p", + "peasant", "peasant_p", + "aura", "aura_p", + "unit", "unit_p" +}; + +void +init_resources(void) +{ + static boolean initialized = false; + if (initialized) return; + initialized = true; + + /* silver was never an item: */ + r_silver = new_resourcetype(&names[0], NULL, RTF_ITEM|RTF_POOLED); + i_silver = new_itemtype(r_silver, ITF_NONE, 1/*weight*/, 0); + r_silver->uchange = res_changeitem; + i_silver->give = give_money; + + r_permaura = new_resourcetype(&names[4], NULL, RTF_NONE); + r_permaura->uchange = res_changepermaura; + + r_hp = new_resourcetype(&names[6], NULL, RTF_NONE); + r_hp->uchange = res_changehp; + + r_aura = new_resourcetype(&names[10], NULL, RTF_NONE); + r_aura->uchange = res_changeaura; + + r_unit = new_resourcetype(&names[12], NULL, RTF_NONE); + r_unit->uchange = res_changeperson; + + oldresourcetype[R_SILVER] = r_silver; + oldresourcetype[R_AURA] = r_aura; + oldresourcetype[R_PERMAURA] = r_permaura; + + /* alte typen registrieren: */ + init_olditems(); + init_oldpotions(); +} + +int +get_money(const unit * u) +{ + const item * i = u->items; + while (i && i->type!=i_silver) i=i->next; + if (i==NULL) return 0; + return i->number; +} + +int +set_money(unit * u, int v) +{ + item ** ip = &u->items; + while (*ip && (*ip)->type!=i_silver) ip = &(*ip)->next; + if ((*ip)==NULL && v) { + i_add(&u->items, i_new(i_silver, v)); + return v; + } + if ((*ip)!=NULL) { + if (v) { + (*ip)->number = v; + assert((*ip)->number>=0); + } + else i_remove(ip, *ip); + } + return v; +} + +int +change_money(unit * u, int v) +{ + item ** ip = &u->items; + while (*ip && (*ip)->type!=i_silver) ip = &(*ip)->next; + if ((*ip)==NULL && v) { + i_add(&u->items, i_new(i_silver, v)); + return v; + } + if ((*ip)!=NULL) { + item * i = *ip; + if (i->number + v != 0) { + i->number += v; + assert(i->number>=0); + return i->number; + } + else i_free(i_remove(ip, *ip)); + } + return 0; +} + + +static local_names * rnames; + +const resource_type * +findresourcetype(const char * name, const struct locale * lang) +{ + local_names * rn = rnames; + variant token; + + while (rn) { + if (rn->lang==lang) break; + rn = rn->next; + } + if (!rn) { + const resource_type * rtl = resourcetypes; + rn = calloc(sizeof(local_names), 1); + rn->next = rnames; + rn->lang = lang; + while (rtl) { + token.v = (void*)rtl; + addtoken(&rn->names, locale_string(lang, rtl->_name[0]), token); + addtoken(&rn->names, locale_string(lang, rtl->_name[1]), token); + rtl=rtl->next; + } + rnames = rn; + } + + if (findtoken(&rn->names, name, &token)==E_TOK_NOMATCH) return NULL; + return (const resource_type*)token.v; +} + +attrib_type at_showitem = { + "showitem" +}; + +static local_names * inames; + +void +init_itemnames(void) +{ + int i; + for (i=0;localenames[i];++i) { + const struct locale * lang = find_locale(localenames[i]); + boolean exist = false; + local_names * in = inames; + + while (in!=NULL) { + if (in->lang==lang) { + exist = true; + break; + } + in = in->next; + } + if (in==NULL) in = calloc(sizeof(local_names), 1); + in->next = inames; + in->lang = lang; + + if (!exist) { + int key; + for (key=0;key!=IMAXHASH;++key) { + const item_type * itl; + for (itl=itemtypes[key];itl;itl=itl->next) { + variant var; + const char * iname = locale_string(lang, itl->rtype->_name[0]); + if (findtoken(&in->names, iname, &var)==E_TOK_NOMATCH || var.v!=itl) { + var.v = (void*)itl; + addtoken(&in->names, iname, var); + addtoken(&in->names, locale_string(lang, itl->rtype->_name[1]), var); + } + } + } + } + inames = in; + } +} + +const item_type * +finditemtype(const char * name, const struct locale * lang) +{ + local_names * in = inames; + variant var; + + while (in!=NULL) { + if (in->lang==lang) break; + in=in->next; + } + if (in==NULL) { + init_itemnames(); + for (in=inames;in->lang!=lang;in=in->next) ; + } + if (findtoken(&in->names, name, &var)==E_TOK_NOMATCH) return NULL; + return (const item_type*)var.v; +} + +static void +init_resourcelimit(attrib * a) +{ + a->data.v = calloc(sizeof(resource_limit), 1); +} + +static void +finalize_resourcelimit(attrib * a) +{ + free(a->data.v); +} + +attrib_type at_resourcelimit = { + "resourcelimit", + init_resourcelimit, + finalize_resourcelimit, +}; + +void +register_resources(void) +{ + register_function((pf_generic)mod_elves_only, "mod_elves_only"); + register_function((pf_generic)mod_dwarves_only, "mod_dwarves_only"); + register_function((pf_generic)res_changeitem, "changeitem"); + register_function((pf_generic)res_changeperson, "changeperson"); + register_function((pf_generic)res_changepeasants, "changepeasants"); + register_function((pf_generic)res_changepermaura, "changepermaura"); + register_function((pf_generic)res_changehp, "changehp"); + register_function((pf_generic)res_changeaura, "changeaura"); + + register_item_use(use_potion, "usepotion"); + register_item_use(use_potion_delayed, "usepotion_delayed"); + register_item_use(use_tacticcrystal, "use_tacticcrystal"); + register_item_use(use_birthdayamulet, "use_birthdayamulet"); + register_item_use(use_warmthpotion, "usewarmthpotion"); + register_item_use(use_bloodpotion, "usebloodpotion"); + register_item_use(use_healingpotion, "usehealingpotion"); + register_item_useonother(use_foolpotion, "usefoolpotion"); + register_item_use(use_mistletoe, "usemistletoe"); + register_item_use(use_magicboost, "usemagicboost"); + register_item_use(use_snowball, "usesnowball"); + + register_item_give(give_horses, "givehorses"); + + /* make sure noone has deleted an I_ tpe without deleting the R_ type that goes with it! */ + assert((int)I_TACTICCRYSTAL == (int)R_TACTICCRYSTAL); +} diff --git a/src/kernel/item.h b/src/kernel/item.h index 516d0856d..7633790ed 100644 --- a/src/kernel/item.h +++ b/src/kernel/item.h @@ -1,357 +1,357 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_ITEM -#define H_KRNL_ITEM -#ifdef __cplusplus -extern "C" { -#endif - -struct unit; -struct attrib; -struct attrib_type; -struct region; -struct resource_type; -struct locale; -struct troop; - -typedef struct item { - struct item * next; - const struct item_type * type; - int number; -} item; - -typedef struct resource { - const struct resource_type * type; - int number; - struct resource * next; -} resource; - -/* bitfield values for resource_type::flags */ -#define RTF_NONE 0 -#define RTF_ITEM (1<<0) /* this resource is an item */ -#define RTF_LIMITED (1<<1) /* a resource that's freely available, but in - * limited supply */ -#define RTF_POOLED (1<<2) /* resource is available in pool */ - -/* flags for resource_type::name() */ -#define NMF_PLURAL 0x01 -#define NMF_APPEARANCE 0x02 - -typedef int (*rtype_uchange)(struct unit * user, const struct resource_type * rtype, int delta); -typedef int (*rtype_uget)(const struct unit * user, const struct resource_type * rtype); -typedef char * (*rtype_name)(const struct resource_type * rtype, int flags); -typedef struct resource_type { - /* --- constants --- */ - char * _name[2]; /* wie es heißt */ - char * _appearance[2]; /* wie es für andere aussieht */ - unsigned int flags; - /* --- functions --- */ - rtype_uchange uchange; - rtype_uget uget; - rtype_name name; - /* --- pointers --- */ - struct attrib * attribs; - struct resource_type * next; - unsigned int hashkey; - struct item_type * itype; - struct potion_type * ptype; - struct luxury_type * ltype; - struct weapon_type * wtype; - struct armor_type * atype; -} resource_type; -extern resource_type * resourcetypes; -extern const char* resourcename(const resource_type * rtype, int flags); -extern const resource_type * findresourcetype(const char * name, const struct locale * lang); - -/* resource-limits for regions */ -#define RMF_SKILL 0x01 /* int, bonus on resource production skill */ -#define RMF_SAVEMATERIAL 0x02 /* float, multiplier on resource usage */ -#define RMF_SAVERESOURCE 0x03 /* int, bonus on resource production skill */ -#define RMF_REQUIREDBUILDING 0x04 /* building, required to build */ - -typedef struct resource_mod { - variant value; - const struct building_type * btype; - const struct race * race; - unsigned int flags; -} resource_mod; - -extern struct attrib_type at_resourcelimit; -typedef int (*rlimit_limit)(const struct region * r, const struct resource_type * rtype); -typedef void (*rlimit_produce)(struct region * r, const struct resource_type * rtype, int n); -typedef struct resource_limit { - rlimit_limit limit; - rlimit_produce produce; - unsigned int guard; /* how to guard against theft */ - int value; - resource_mod * modifiers; -} resource_limit; - - -/* bitfield values for item_type::flags */ -#define ITF_NONE 0x0000 -#define ITF_HERB 0x0001 /* this item is a herb */ -#define ITF_CURSED 0x0010 /* cursed object, cannot be given away */ -#define ITF_NOTLOST 0x0020 /* special object (quests), cannot be lost through death etc. */ -#define ITF_BIG 0x0040 /* big item, e.g. does not fit in a bag of holding */ -#define ITF_ANIMAL 0x0080 /* an animal */ -#define ITF_VEHICLE 0x0100 /* a vehicle, drawn by two animals */ - -/* error codes for item_type::use */ -#define ECUSTOM -1; -#define ENOITEM -2; -#define ENOSKILL -3; -#define EUNUSABLE -4; - -typedef struct itemtype_list { - struct itemtype_list * next; - const struct item_type * type; -} itemtype_list; - -typedef struct item_type { - resource_type * rtype; - /* --- constants --- */ - unsigned int flags; - int weight; - int capacity; - struct construction * construction; - /* --- functions --- */ - boolean (*canuse)(const struct unit * user, const struct item_type * itype); - int (*use)(struct unit * user, const struct item_type * itype, int amount, struct order * ord); - int (*useonother)(struct unit * user, int targetno, const struct item_type * itype, int amount, struct order * ord); - int (*give)(struct unit * src, struct unit * dest, const struct item_type * itm, int number, struct order * ord); -#if SCORE_MODULE - int score; -#endif - struct item_type * next; -} item_type; - -extern const item_type * finditemtype(const char * name, const struct locale * lang); -extern void init_itemnames(void); - -typedef struct luxury_type { - struct luxury_type * next; - const item_type * itype; - int price; -} luxury_type; -extern luxury_type * luxurytypes; - -typedef struct potion_type { - struct potion_type * next; - const item_type * itype; - int level; -} potion_type; -extern potion_type * potiontypes; - -#define WMF_WALKING 0x0001 -#define WMF_RIDING 0x0002 -#define WMF_ANYONE 0x000F /* convenience */ - -#define WMF_AGAINST_RIDING 0x0010 -#define WMF_AGAINST_WALKING 0x0020 -#define WMF_AGAINST_ANYONE 0x00F0 /* convenience */ - -#define WMF_OFFENSIVE 0x0100 -#define WMF_DEFENSIVE 0x0200 -#define WMF_ANYTIME 0x0F00 /* convenience */ - -#define WMF_DAMAGE 0x1000 -#define WMF_SKILL 0x2000 -#define WMF_MISSILE_TARGET 0x4000 - -struct race_list; -typedef struct weapon_mod { - int value; - unsigned int flags; - struct race_list * races; -} weapon_mod; - -#define ATF_NONE 0x00 -#define ATF_SHIELD 0x01 -#define ATF_LAEN 0x02 - -typedef struct armor_type { - const item_type * itype; - double penalty; - double magres; - int prot; - float projectile; /* chance, dass ein projektil abprallt */ - unsigned int flags; -} armor_type; - -#define WTF_NONE 0x00 -#define WTF_MISSILE 0x01 -#define WTF_MAGICAL 0x02 -#define WTF_PIERCE 0x04 -#define WTF_CUT 0x08 -#define WTF_BLUNT 0x10 -#define WTF_SIEGE 0x20 -#define WTF_ARMORPIERCING 0x40 /* armor has only half value */ -#define WTF_HORSEBONUS 0x80 -#define WTF_USESHIELD 0x100 - -typedef struct weapon_type { - const item_type * itype; - const char * damage[2]; - unsigned int flags; - skill_t skill; - int minskill; - int offmod; - int defmod; - double magres; - int reload; /* time to reload this weapon */ - weapon_mod * modifiers; - /* --- functions --- */ - boolean (*attack)(const struct troop *, const struct weapon_type *, int *deaths); -} weapon_type; - -extern void rt_register(resource_type * it); -extern resource_type * rt_find(const char * name); -extern item_type * it_find(const char * name); - -extern void it_register(item_type * it); -extern void wt_register(weapon_type * wt); - -extern const item_type * resource2item(const resource_type * rtype); -extern const resource_type * item2resource(const item_type * i); - -extern const weapon_type * resource2weapon(const resource_type * i); -extern const potion_type * resource2potion(const resource_type * i); -extern const luxury_type * resource2luxury(const resource_type * i); - -extern item ** i_find(item ** pi, const item_type * it); -extern item * const * i_findc(item * const * pi, const item_type * it); -extern item * i_add(item ** pi, item * it); -extern void i_merge(item ** pi, item ** si); -extern item * i_remove(item ** pi, item * it); -extern void i_free(item * i); -extern void i_freeall(item ** i); -extern item * i_new(const item_type * it, int number); - -/* convenience: */ -extern item * i_change(item ** items, const item_type * it, int delta); -extern int i_get(const item * i, const item_type * it); - -/* creation */ -extern resource_type * new_resourcetype(const char ** names, const char ** appearances, int flags); -extern item_type * new_itemtype(resource_type * rtype, int iflags, int weight, int capacity); -extern luxury_type * new_luxurytype(item_type * itype, int price); -extern weapon_type * new_weapontype(item_type * itype, int wflags, double magres, const char* damage[], int offmod, int defmod, int reload, skill_t sk, int minskill); -extern armor_type * new_armortype(item_type * itype, double penalty, double magres, int prot, unsigned int flags); -extern potion_type * new_potiontype(item_type * itype, int level); - -/* for lack of another file: */ - -/* sonstige resourcen */ -extern resource_type * r_silver; -extern resource_type * r_aura; -extern resource_type * r_permaura; -extern resource_type * r_unit; -extern resource_type * r_hp; - -enum { - I_IRON, /* 0 */ - I_STONE, - I_HORSE, - /* alte Artefakte */ - I_AMULET_OF_HEALING, - I_AMULET_OF_TRUE_SEEING, - I_RING_OF_INVISIBILITY, - I_RING_OF_POWER, - I_CHASTITY_BELT, /* bleibt */ - I_LAEN, - I_FEENSTIEFEL, - I_BIRTHDAYAMULET, - I_PEGASUS, - I_ELVENHORSE, - I_DOLPHIN, - I_RING_OF_NIMBLEFINGER, - I_TROLLBELT, - I_PRESSCARD, - I_AURAKULUM, - I_SPHERE_OF_INVISIBILITY, - I_BAG_OF_HOLDING, - I_SACK_OF_CONSERVATION, - I_TACTICCRYSTAL, - MAX_ITEMS /* do not use outside item.c ! */ -}; - -enum { - /* ITEMS: */ - R_IRON, - R_STONE, - R_HORSE, - /**/ - R_AMULET_OF_HEALING, - R_AMULET_OF_TRUE_SEEING, - R_RING_OF_INVISIBILITY, - R_RING_OF_POWER, - R_CHASTITY_BELT, - R_EOG, - R_FEENSTIEFEL, - R_BIRTHDAYAMULET, - R_PEGASUS, - R_UNICORN, - R_DOLPHIN, - R_RING_OF_NIMBLEFINGER, - R_TROLLBELT, - R_PRESSCARD, - R_AURAKULUM, - R_SPHERE_OF_INVISIBILITY, - R_BAG_OF_HOLDING, - R_SACK_OF_CONSERVATION, - R_TACTICCRYSTAL, - - /* SONSTIGE */ - R_SILVER, - R_AURA, /* Aura */ - R_PERMAURA, /* Permanente Aura */ - - MAX_RESOURCES, /* do not use outside item.c ! */ - NORESOURCE = -1 -}; - -extern const struct potion_type * oldpotiontype[]; -extern const struct item_type * olditemtype[]; -extern const struct resource_type * oldresourcetype[]; - -int get_item(const struct unit *, item_t); -int set_item(struct unit *, item_t, int); - -int get_money(const struct unit *); -int set_money(struct unit *, int); -int change_money(struct unit *, int); -int res_changeitem(struct unit * u, const resource_type * rtype, int delta); - -extern struct attrib_type at_showitem; /* show this potion's description */ - -extern void register_resources(void); -extern void init_resources(void); -extern void init_itemtypes(void); - -extern void register_item_give(int (*foo) (struct unit *, struct unit *, const struct item_type *, int, struct order *), const char * name); -extern void register_item_use(int (*foo) (struct unit *, const struct item_type *, int, struct order *), const char * name); -extern void register_item_useonother(int (*foo) (struct unit *, int, const struct item_type *, int, struct order *), const char * name); - -extern struct item_type *i_silver; - -#ifdef __cplusplus -} -#endif -#endif /* _ITEM_H */ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_ITEM +#define H_KRNL_ITEM +#ifdef __cplusplus +extern "C" { +#endif + +struct unit; +struct attrib; +struct attrib_type; +struct region; +struct resource_type; +struct locale; +struct troop; + +typedef struct item { + struct item * next; + const struct item_type * type; + int number; +} item; + +typedef struct resource { + const struct resource_type * type; + int number; + struct resource * next; +} resource; + +/* bitfield values for resource_type::flags */ +#define RTF_NONE 0 +#define RTF_ITEM (1<<0) /* this resource is an item */ +#define RTF_LIMITED (1<<1) /* a resource that's freely available, but in + * limited supply */ +#define RTF_POOLED (1<<2) /* resource is available in pool */ + +/* flags for resource_type::name() */ +#define NMF_PLURAL 0x01 +#define NMF_APPEARANCE 0x02 + +typedef int (*rtype_uchange)(struct unit * user, const struct resource_type * rtype, int delta); +typedef int (*rtype_uget)(const struct unit * user, const struct resource_type * rtype); +typedef char * (*rtype_name)(const struct resource_type * rtype, int flags); +typedef struct resource_type { + /* --- constants --- */ + char * _name[2]; /* wie es heißt */ + char * _appearance[2]; /* wie es für andere aussieht */ + unsigned int flags; + /* --- functions --- */ + rtype_uchange uchange; + rtype_uget uget; + rtype_name name; + /* --- pointers --- */ + struct attrib * attribs; + struct resource_type * next; + unsigned int hashkey; + struct item_type * itype; + struct potion_type * ptype; + struct luxury_type * ltype; + struct weapon_type * wtype; + struct armor_type * atype; +} resource_type; +extern resource_type * resourcetypes; +extern const char* resourcename(const resource_type * rtype, int flags); +extern const resource_type * findresourcetype(const char * name, const struct locale * lang); + +/* resource-limits for regions */ +#define RMF_SKILL 0x01 /* int, bonus on resource production skill */ +#define RMF_SAVEMATERIAL 0x02 /* float, multiplier on resource usage */ +#define RMF_SAVERESOURCE 0x03 /* int, bonus on resource production skill */ +#define RMF_REQUIREDBUILDING 0x04 /* building, required to build */ + +typedef struct resource_mod { + variant value; + const struct building_type * btype; + const struct race * race; + unsigned int flags; +} resource_mod; + +extern struct attrib_type at_resourcelimit; +typedef int (*rlimit_limit)(const struct region * r, const struct resource_type * rtype); +typedef void (*rlimit_produce)(struct region * r, const struct resource_type * rtype, int n); +typedef struct resource_limit { + rlimit_limit limit; + rlimit_produce produce; + unsigned int guard; /* how to guard against theft */ + int value; + resource_mod * modifiers; +} resource_limit; + + +/* bitfield values for item_type::flags */ +#define ITF_NONE 0x0000 +#define ITF_HERB 0x0001 /* this item is a herb */ +#define ITF_CURSED 0x0010 /* cursed object, cannot be given away */ +#define ITF_NOTLOST 0x0020 /* special object (quests), cannot be lost through death etc. */ +#define ITF_BIG 0x0040 /* big item, e.g. does not fit in a bag of holding */ +#define ITF_ANIMAL 0x0080 /* an animal */ +#define ITF_VEHICLE 0x0100 /* a vehicle, drawn by two animals */ + +/* error codes for item_type::use */ +#define ECUSTOM -1; +#define ENOITEM -2; +#define ENOSKILL -3; +#define EUNUSABLE -4; + +typedef struct itemtype_list { + struct itemtype_list * next; + const struct item_type * type; +} itemtype_list; + +typedef struct item_type { + resource_type * rtype; + /* --- constants --- */ + unsigned int flags; + int weight; + int capacity; + struct construction * construction; + /* --- functions --- */ + boolean (*canuse)(const struct unit * user, const struct item_type * itype); + int (*use)(struct unit * user, const struct item_type * itype, int amount, struct order * ord); + int (*useonother)(struct unit * user, int targetno, const struct item_type * itype, int amount, struct order * ord); + int (*give)(struct unit * src, struct unit * dest, const struct item_type * itm, int number, struct order * ord); +#if SCORE_MODULE + int score; +#endif + struct item_type * next; +} item_type; + +extern const item_type * finditemtype(const char * name, const struct locale * lang); +extern void init_itemnames(void); + +typedef struct luxury_type { + struct luxury_type * next; + const item_type * itype; + int price; +} luxury_type; +extern luxury_type * luxurytypes; + +typedef struct potion_type { + struct potion_type * next; + const item_type * itype; + int level; +} potion_type; +extern potion_type * potiontypes; + +#define WMF_WALKING 0x0001 +#define WMF_RIDING 0x0002 +#define WMF_ANYONE 0x000F /* convenience */ + +#define WMF_AGAINST_RIDING 0x0010 +#define WMF_AGAINST_WALKING 0x0020 +#define WMF_AGAINST_ANYONE 0x00F0 /* convenience */ + +#define WMF_OFFENSIVE 0x0100 +#define WMF_DEFENSIVE 0x0200 +#define WMF_ANYTIME 0x0F00 /* convenience */ + +#define WMF_DAMAGE 0x1000 +#define WMF_SKILL 0x2000 +#define WMF_MISSILE_TARGET 0x4000 + +struct race_list; +typedef struct weapon_mod { + int value; + unsigned int flags; + struct race_list * races; +} weapon_mod; + +#define ATF_NONE 0x00 +#define ATF_SHIELD 0x01 +#define ATF_LAEN 0x02 + +typedef struct armor_type { + const item_type * itype; + double penalty; + double magres; + int prot; + float projectile; /* chance, dass ein projektil abprallt */ + unsigned int flags; +} armor_type; + +#define WTF_NONE 0x00 +#define WTF_MISSILE 0x01 +#define WTF_MAGICAL 0x02 +#define WTF_PIERCE 0x04 +#define WTF_CUT 0x08 +#define WTF_BLUNT 0x10 +#define WTF_SIEGE 0x20 +#define WTF_ARMORPIERCING 0x40 /* armor has only half value */ +#define WTF_HORSEBONUS 0x80 +#define WTF_USESHIELD 0x100 + +typedef struct weapon_type { + const item_type * itype; + const char * damage[2]; + unsigned int flags; + skill_t skill; + int minskill; + int offmod; + int defmod; + double magres; + int reload; /* time to reload this weapon */ + weapon_mod * modifiers; + /* --- functions --- */ + boolean (*attack)(const struct troop *, const struct weapon_type *, int *deaths); +} weapon_type; + +extern void rt_register(resource_type * it); +extern resource_type * rt_find(const char * name); +extern item_type * it_find(const char * name); + +extern void it_register(item_type * it); +extern void wt_register(weapon_type * wt); + +extern const item_type * resource2item(const resource_type * rtype); +extern const resource_type * item2resource(const item_type * i); + +extern const weapon_type * resource2weapon(const resource_type * i); +extern const potion_type * resource2potion(const resource_type * i); +extern const luxury_type * resource2luxury(const resource_type * i); + +extern item ** i_find(item ** pi, const item_type * it); +extern item * const * i_findc(item * const * pi, const item_type * it); +extern item * i_add(item ** pi, item * it); +extern void i_merge(item ** pi, item ** si); +extern item * i_remove(item ** pi, item * it); +extern void i_free(item * i); +extern void i_freeall(item ** i); +extern item * i_new(const item_type * it, int number); + +/* convenience: */ +extern item * i_change(item ** items, const item_type * it, int delta); +extern int i_get(const item * i, const item_type * it); + +/* creation */ +extern resource_type * new_resourcetype(const char ** names, const char ** appearances, int flags); +extern item_type * new_itemtype(resource_type * rtype, int iflags, int weight, int capacity); +extern luxury_type * new_luxurytype(item_type * itype, int price); +extern weapon_type * new_weapontype(item_type * itype, int wflags, double magres, const char* damage[], int offmod, int defmod, int reload, skill_t sk, int minskill); +extern armor_type * new_armortype(item_type * itype, double penalty, double magres, int prot, unsigned int flags); +extern potion_type * new_potiontype(item_type * itype, int level); + +/* for lack of another file: */ + +/* sonstige resourcen */ +extern resource_type * r_silver; +extern resource_type * r_aura; +extern resource_type * r_permaura; +extern resource_type * r_unit; +extern resource_type * r_hp; + +enum { + I_IRON, /* 0 */ + I_STONE, + I_HORSE, + /* alte Artefakte */ + I_AMULET_OF_HEALING, + I_AMULET_OF_TRUE_SEEING, + I_RING_OF_INVISIBILITY, + I_RING_OF_POWER, + I_CHASTITY_BELT, /* bleibt */ + I_LAEN, + I_FEENSTIEFEL, + I_BIRTHDAYAMULET, + I_PEGASUS, + I_ELVENHORSE, + I_DOLPHIN, + I_RING_OF_NIMBLEFINGER, + I_TROLLBELT, + I_PRESSCARD, + I_AURAKULUM, + I_SPHERE_OF_INVISIBILITY, + I_BAG_OF_HOLDING, + I_SACK_OF_CONSERVATION, + I_TACTICCRYSTAL, + MAX_ITEMS /* do not use outside item.c ! */ +}; + +enum { + /* ITEMS: */ + R_IRON, + R_STONE, + R_HORSE, + /**/ + R_AMULET_OF_HEALING, + R_AMULET_OF_TRUE_SEEING, + R_RING_OF_INVISIBILITY, + R_RING_OF_POWER, + R_CHASTITY_BELT, + R_EOG, + R_FEENSTIEFEL, + R_BIRTHDAYAMULET, + R_PEGASUS, + R_UNICORN, + R_DOLPHIN, + R_RING_OF_NIMBLEFINGER, + R_TROLLBELT, + R_PRESSCARD, + R_AURAKULUM, + R_SPHERE_OF_INVISIBILITY, + R_BAG_OF_HOLDING, + R_SACK_OF_CONSERVATION, + R_TACTICCRYSTAL, + + /* SONSTIGE */ + R_SILVER, + R_AURA, /* Aura */ + R_PERMAURA, /* Permanente Aura */ + + MAX_RESOURCES, /* do not use outside item.c ! */ + NORESOURCE = -1 +}; + +extern const struct potion_type * oldpotiontype[]; +extern const struct item_type * olditemtype[]; +extern const struct resource_type * oldresourcetype[]; + +int get_item(const struct unit *, item_t); +int set_item(struct unit *, item_t, int); + +int get_money(const struct unit *); +int set_money(struct unit *, int); +int change_money(struct unit *, int); +int res_changeitem(struct unit * u, const resource_type * rtype, int delta); + +extern struct attrib_type at_showitem; /* show this potion's description */ + +extern void register_resources(void); +extern void init_resources(void); +extern void init_itemtypes(void); + +extern void register_item_give(int (*foo) (struct unit *, struct unit *, const struct item_type *, int, struct order *), const char * name); +extern void register_item_use(int (*foo) (struct unit *, const struct item_type *, int, struct order *), const char * name); +extern void register_item_useonother(int (*foo) (struct unit *, int, const struct item_type *, int, struct order *), const char * name); + +extern struct item_type *i_silver; + +#ifdef __cplusplus +} +#endif +#endif /* _ITEM_H */ diff --git a/src/kernel/magic.c b/src/kernel/magic.c index a1e1251b6..d181b6328 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -1,2923 +1,2923 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "magic.h" - -#include "building.h" -#include "curse.h" -#include "faction.h" -#include "item.h" -#include "message.h" -#include "objtypes.h" -#include "order.h" -#include "pathfinder.h" -#include "plane.h" -#include "pool.h" -#include "race.h" -#include "region.h" -#include "ship.h" -#include "skill.h" -#include "spell.h" -#include "teleport.h" -#include "terrain.h" -#include "unit.h" -#include "version.h" - -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include -#include - -/* ------------------------------------------------------------- */ - -const char *magic_school[MAXMAGIETYP] = -{ - "gray", - "illaun", - "tybied", - "cerddor", - "gwyrrd", - "draig", - "common" -}; - -attrib_type at_reportspell = { - "reportspell", NULL, NULL, NULL, NO_WRITE, NO_READ -}; - -/** - ** at_icastle - ** TODO: separate castle-appearance from illusion-effects - **/ - -static double -MagicRegeneration(void) -{ - static double value = -1.0; - if (value<0) { - const char * str = get_param(global.parameters, "magic.regeneration"); - value = str?atof(str):1.0; - } - return value; -} - -double -MagicPower(void) -{ - static double value = -1.0; - if (value<0) { - const char * str = get_param(global.parameters, "magic.power"); - value = str?atof(str):1.0; - } - return value; -} - -static int -a_readicastle(attrib * a, void * owner, struct storage * store) -{ - icastle_data * data = (icastle_data*)a->data.v; - variant bno; - char token[32]; - store->r_tok_buf(store, token, sizeof(token)); - bno.i = store->r_int(store); - data->time = store->r_int(store); - data->building = findbuilding(bno.i); - if (!data->building) { - /* this shouldn't happen, but just in case it does: */ - ur_add(bno, &data->building, resolve_building); - } - data->type = bt_find(token); - return AT_READ_OK; -} - -static void -a_writeicastle(const attrib * a, const void * owner, struct storage * store) -{ - icastle_data * data = (icastle_data*)a->data.v; - store->w_tok(store, data->type->_name); - store->w_int(store, data->building->no); - store->w_int(store, data->time); -} - -static int -a_ageicastle(struct attrib * a) -{ - icastle_data * data = (icastle_data*)a->data.v; - if (data->time<=0) { - building * b = data->building; - region * r = b->region; - ADDMSG(&r->msgs, msg_message("icastle_dissolve", "building", b)); - /* remove_building lets units leave the building */ - remove_building(&r->buildings, b); - return AT_AGE_REMOVE; - } - else data->time--; - return AT_AGE_KEEP; -} - -static void -a_initicastle(struct attrib * a) -{ - a->data.v = calloc(sizeof(icastle_data), 1); -} - -static void -a_finalizeicastle(struct attrib * a) -{ - free(a->data.v); -} - -attrib_type at_icastle = { - "zauber_icastle", - a_initicastle, - a_finalizeicastle, - a_ageicastle, - a_writeicastle, - a_readicastle -}; - -/* ------------------------------------------------------------- */ - -extern int dice(int count, int value); - -/* ------------------------------------------------------------- */ -/* aus dem alten System übriggebliegene Funktionen, die bei der - * Umwandlung von alt nach neu gebraucht werden */ -/* ------------------------------------------------------------- */ - -static void -init_mage(attrib * a) { - a->data.v = calloc(sizeof(sc_mage), 1); -} - -static void -free_mage(attrib * a) -{ - sc_mage * mage = (sc_mage*)a->data.v; - freelist(mage->spells); - free(mage); -} - -int FactionSpells(void) -{ - static int rules_factionspells = -1; - if (rules_factionspells<0) { - rules_factionspells = get_param_int(global.parameters, "rules.magic.factionlist", 0); - } - return rules_factionspells; -} - -void read_spellist(struct spell_list ** slistp, magic_t mtype, struct storage * store) -{ - for (;;) { - spell * sp; - char spname[64]; - - if (store->versionr_int(store); - if (i < 0) break; - sp = find_spellbyid(M_NONE, (spellid_t)i); - } else { - store->r_tok_buf(store, spname, sizeof(spname)); - if (strcmp(spname, "end")==0) break; - sp = find_spell(mtype, spname); - } - if (sp!=NULL) { - add_spell(slistp, sp); - } - } -} - -static int -read_mage(attrib * a, void * owner, struct storage * store) -{ - int i, mtype; - sc_mage * mage = (sc_mage*)a->data.v; - char spname[64]; - - mtype = store->r_int(store); - mage->spellpoints = store->r_int(store); - mage->spchange = store->r_int(store); - mage->magietyp = (magic_t)mtype; - for (i=0;i!=MAXCOMBATSPELLS;++i) { - spell * sp = NULL; - int level = 0; - if (store->versionr_int(store); - level = store->r_int(store); - if (spid>=0) { - sp = find_spellbyid(mage->magietyp, (spellid_t)spid); - } - } else { - store->r_tok_buf(store, spname, sizeof(spname)); - level = store->r_int(store); - - if (strcmp("none", spname)!=0) { - sp = find_spell(mage->magietyp, spname); - } - } - if (sp && level>=0) { - int slot = -1; - if (sp->sptyp & PRECOMBATSPELL) slot = 0; - else if (sp->sptyp & COMBATSPELL) slot = 1; - else if (sp->sptyp & POSTCOMBATSPELL) slot = 2; - if (slot>=0) { - mage->combatspells[slot].level = level; - mage->combatspells[slot].sp = sp; - } - } - } - read_spellist(&mage->spells, mage->magietyp, store); - return AT_READ_OK; -} - -void write_spelllist(const spell_list * slist, struct storage * store) -{ - while (slist!=NULL) { - spell * sp = slist->data; - store->w_tok(store, sp->sname); - slist = slist->next; - } - store->w_tok(store, "end"); -} - -static void -write_mage(const attrib * a, const void * owner, struct storage * store) -{ - int i; - sc_mage *mage = (sc_mage*)a->data.v; - - store->w_int(store, mage->magietyp); - store->w_int(store, mage->spellpoints); - store->w_int(store, mage->spchange); - for (i=0;i!=MAXCOMBATSPELLS;++i) { - store->w_tok(store, mage->combatspells[i].sp?mage->combatspells[i].sp->sname:"none"); - store->w_int(store, mage->combatspells[i].level); - } - write_spelllist(mage->spells, store); -} - -attrib_type at_mage = { - "mage", - init_mage, - free_mage, - NULL, - write_mage, - read_mage, - ATF_UNIQUE -}; - -boolean -is_mage(const unit * u) -{ - return i2b(get_mage(u) != NULL); -} - -sc_mage * -get_mage(const unit * u) -{ - if (has_skill(u, SK_MAGIC)) { - attrib * a = a_find(u->attribs, &at_mage); - if (a) return a->data.v; - } - return (sc_mage *) NULL; -} - -/* ------------------------------------------------------------- */ -/* Ausgabe der Spruchbeschreibungen -* Anzeige des Spruchs nur, wenn die Stufe des besten Magiers vorher -* kleiner war (u->faction->seenspells). Ansonsten muss nur geprüft -* werden, ob dieser Magier den Spruch schon kennt, und andernfalls der -* Spruch zu seiner List-of-known-spells hinzugefügt werden. -*/ - - -static int -read_seenspell(attrib * a, void * owner, struct storage * store) -{ - int i; - spell * sp = NULL; - char token[32]; - - store->r_tok_buf(store, token, sizeof(token)); - i = atoi(token); - if (i!=0) { - sp = find_spellbyid(M_NONE, (spellid_t)i); - } else { - int mtype; - mtype = store->r_int(store); - sp = find_spell((magic_t)mtype, token); - } - if (sp==NULL) { - /* log_error(("could not find seenspell '%s'\n", buf)); */ - return AT_READ_FAIL; - } - a->data.v = sp; - return AT_READ_OK; -} - -static void -write_seenspell(const attrib * a, const void * owner, struct storage * store) -{ - const spell * sp = (const spell*)a->data.v; - store->w_tok(store, sp->sname); - store->w_int(store, sp->magietyp); -} - -attrib_type at_seenspell = { - "seenspell", NULL, NULL, NULL, write_seenspell, read_seenspell -}; - -static boolean -already_seen(const faction * f, const spell * sp) -{ - attrib *a; - - for (a = a_find(f->attribs, &at_seenspell); a && a->type==&at_seenspell; a=a->next) { - if (a->data.v==sp) return true; - } - return false; -} - -static boolean know_school(const faction * f, magic_t school) -{ - static int common = MAXMAGIETYP; - if (f->magiegebiet==school) return true; - if (common==MAXMAGIETYP) { - const char * common_school = get_param(global.parameters, "rules.magic.common"); - if (common_school) { - for (common=0;common!=MAXMAGIETYP;++common) { - if (strcmp(common_school, magic_school[common])==0) break; - } - if (common==MAXMAGIETYP) { - common = M_NONE; - } - } else { - return false; - } - } - return school==common; -} - -#define COMMONSPELLS 1 /* number of new common spells per level */ -#define MAXSPELLS 256 - -/** update the spellbook with a new level -* Written for Eressea 1.1 -*/ -void -update_spellbook(faction * f, int level) -{ - spell * commonspells[MAXSPELLS]; - int numspells = 0; - spell_list * slist; - - for (slist=spells;slist!=NULL;slist=slist->next) { - spell * sp = slist->data; - if (sp->magietyp == M_COMMON && level>f->max_spelllevel && sp->level<=level) { - commonspells[numspells++] = sp; - } else { - if (know_school(f, sp->magietyp) && sp->level <= level) { - if (!has_spell(f->spellbook, sp)) { - add_spell(&f->spellbook, sp); - } - } - } - } - while (numspells>0 && level>f->max_spelllevel) { - int i; - for (i=0;i!=COMMONSPELLS;++i) { - int maxspell = numspells; - int spellno = -1; - spell * sp; - do { - if (spellno==maxspell) { - --maxspell; - } - spellno = rng_int() % maxspell; - sp = commonspells[spellno]; - } - while (maxspell>0 && sp && sp->level<=f->max_spelllevel && !has_spell(f->spellbook, sp)); - - if (sp) { - add_spell(&f->spellbook, sp); - commonspells[spellno] = 0; - } - } - ++f->max_spelllevel; - } -} - -void -updatespelllist(unit * u) -{ - int sk = eff_skill(u, SK_MAGIC, u->region); - spell_list * slist = spells; - struct sc_mage * mage = get_mage(u); - boolean ismonster = is_monsters(u->faction); - - if (mage->magietyp==M_GRAY) { - /* Magier mit M_GRAY bekommen weder Sprüche angezeigt noch - * neue Sprüche in ihre List-of-known-spells. Das sind zb alle alten - * Drachen, die noch den Skill Magie haben, und alle familiars */ - return; - } - - if (FactionSpells()) { - slist = u->faction->spellbook; - } - - for (;slist!=NULL;slist=slist->next) { - spell * sp = slist->data; - if (sp->level<=sk) { - boolean know = u_hasspell(u, sp); - - if (know || sp->magietyp==M_COMMON || know_school(u->faction, sp->magietyp)) { - faction * f = u->faction; - - if (!know) add_spell(get_spelllist(mage, u->faction), sp); - if (!ismonster && !already_seen(u->faction, sp)) { - a_add(&f->attribs, a_new(&at_reportspell))->data.v = sp; - a_add(&f->attribs, a_new(&at_seenspell))->data.v = sp; - } - } - } - } - -} - -/* ------------------------------------------------------------- */ -/* Erzeugen eines neuen Magiers */ -sc_mage * -create_mage(unit * u, magic_t mtyp) -{ - sc_mage *mage; - attrib *a; - - a = a_find(u->attribs, &at_mage); - if (a!=NULL) { - a_remove(&u->attribs, a); - } - a = a_add(&u->attribs, a_new(&at_mage)); - mage = a->data.v; - - mage->magietyp = mtyp; - return mage; -} - -/* ------------------------------------------------------------- */ -/* Funktionen für die Bearbeitung der List-of-known-spells */ - -void -add_spell(spell_list ** slistp, spell * sp) -{ - if (slistp==NULL) { - log_error(("add_spell: unit is not a mage.\n")); - } else { - spell_list ** slist = spelllist_find(slistp, sp); - if (*slist) { - spell * psp = (*slist)->data; - if (psp==sp) { - log_error(("add_spell: unit already has spell '%s'.\n", sp->sname)); - return; - } - } - spelllist_add(slist, sp); - } -} - -boolean -has_spell(spell_list * slist, const spell * sp) -{ - if (slist!=NULL) { - spell_list * sfind = *spelllist_find(&slist, sp); - return sfind!=NULL && sfind->data==sp; - } - return false; -} - -boolean -u_hasspell(const struct unit *u, const struct spell * sp) -{ - sc_mage * mage = get_mage(u); - if (mage) return has_spell(mage->spells, sp); - return false; -} - -/* ------------------------------------------------------------- */ -/* Eingestellte Kampfzauberstufe ermitteln */ - -int -get_combatspelllevel(const unit *u, int nr) -{ - sc_mage *m = get_mage(u); - - assert(nr < MAXCOMBATSPELLS); - if (m) { - int level = eff_skill(u, SK_MAGIC, u->region); - return MIN(m->combatspells[nr].level, level); - } - return -1; -} - -/* ------------------------------------------------------------- */ -/* Kampfzauber ermitteln, setzen oder löschen */ - -const spell* -get_combatspell(const unit *u, int nr) -{ - sc_mage *m; - - assert(nr < MAXCOMBATSPELLS); - m = get_mage(u); - if (m) { - return m->combatspells[nr].sp; - } else if (u->race->precombatspell != NULL) { - return u->race->precombatspell; - } - - return NULL; -} - -void -set_combatspell(unit *u, spell *sp, struct order * ord, int level) -{ - sc_mage *m = get_mage(u); - int i = -1; - if (!m) return; - - /* knowsspell prüft auf ist_magier, ist_spruch, kennt_spruch */ - if (knowsspell(u->region, u, sp) == false){ - /* Fehler 'Spell not found' */ - cmistake(u, ord, 173, MSG_MAGIC); - return; - } - if (!u_hasspell(u, sp)) { - /* Diesen Zauber kennt die Einheit nicht */ - cmistake(u, ord, 169, MSG_MAGIC); - return; - } - if (!(sp->sptyp & ISCOMBATSPELL)) { - /* Diesen Kampfzauber gibt es nicht */ - cmistake(u, ord, 171, MSG_MAGIC); - return; - } - - if (sp->sptyp & PRECOMBATSPELL) i = 0; - else if (sp->sptyp & COMBATSPELL) i = 1; - else if (sp->sptyp & POSTCOMBATSPELL) i = 2; - assert(i>=0); - m->combatspells[i].sp = sp; - m->combatspells[i].level = level; - return; -} - -void -unset_combatspell(unit *u, spell *sp) -{ - sc_mage *m; - int nr = 0; - int i; - - m = get_mage(u); - if (!m) return; - - if (!sp) { - for (i=0;icombatspells[i].sp = NULL; - } - } - else if (sp->sptyp & PRECOMBATSPELL) { - if (sp != get_combatspell(u,0)) - return; - } else if (sp->sptyp & COMBATSPELL) { - if (sp != get_combatspell(u,1)) { - return; - } - nr = 1; - } else if (sp->sptyp & POSTCOMBATSPELL) { - if (sp != get_combatspell(u,2)) { - return; - } - nr = 2; - } - m->combatspells[nr].sp = NULL; - m->combatspells[nr].level = 0; - return; -} - -/* ------------------------------------------------------------- */ -/* Gibt die aktuelle Anzahl der Magiepunkte der Einheit zurück */ -int -get_spellpoints(const unit * u) -{ - sc_mage *m; - - m = get_mage(u); - if (!m) return 0; - - return m->spellpoints; -} - -void -set_spellpoints(unit * u, int sp) -{ - sc_mage *m; - - m = get_mage(u); - if (!m) return; - - m->spellpoints = sp; - - return; -} - -/* - * verändert die Anzahl der Magiepunkte der Einheit um +mp - */ -int -change_spellpoints(unit * u, int mp) -{ - sc_mage *m; - int sp; - - m = get_mage(u); - if (!m) return 0; - - /* verhindere negative Magiepunkte */ - sp = MAX(m->spellpoints + mp, 0); - m->spellpoints = sp; - - return sp; -} - -/* bietet die Möglichkeit, die maximale Anzahl der Magiepunkte mit - * Regionszaubern oder Attributen zu beinflussen - */ -static int -get_spchange(const unit * u) -{ - sc_mage *m; - - m = get_mage(u); - if (!m) return 0; - - return m->spchange; -} - -/* ein Magier kann normalerweise maximal Stufe^2.1/1.2+1 Magiepunkte - * haben. - * Manche Rassen haben einen zusätzlichen Multiplikator - * Durch Talentverlust (zB Insekten im Berg) können negative Werte - * entstehen - */ - -/* Artefakt der Stärke - * Ermöglicht dem Magier mehr Magiepunkte zu 'speichern' - */ -/** TODO: at_skillmod daraus machen */ -static int -use_item_aura(const region * r, const unit * u) -{ - int sk, n; - - sk = eff_skill(u, SK_MAGIC, r); - n = (int)(sk * sk * u->race->maxaura / 4); - - return n; -} - -int -max_spellpoints(const region * r, const unit * u) -{ - int sk; - double n, msp; - double potenz = 2.1; - double divisor = 1.2; - - sk = eff_skill(u, SK_MAGIC, r); - msp = u->race->maxaura*(pow(sk, potenz)/divisor+1) + get_spchange(u); - - if (get_item(u, I_AURAKULUM) > 0) { - msp += use_item_aura(r, u); - } - n = get_curseeffect(u->attribs, C_AURA, 0); - if (n>0) msp = (msp*n)/100; - - return MAX((int)msp, 0); -} - -int -change_maxspellpoints(unit * u, int csp) -{ - sc_mage *m; - - m = get_mage(u); - if (!m) return 0; - - m->spchange += csp; - return max_spellpoints(u->region, u); -} - -/* ------------------------------------------------------------- */ -/* Counter für die bereits gezauberte Anzahl Sprüche pro Runde. - * Um nur die Zahl der bereits gezauberten Sprüche zu ermitteln mit - * step = 0 aufrufen. - */ -int -countspells(unit *u, int step) -{ - sc_mage *m; - int count; - - m = get_mage(u); - if (!m) - return 0; - - if (step == 0) - return m->spellcount; - - count = m->spellcount + step; - - /* negative Werte abfangen. */ - m->spellcount = MAX(0,count); - - return m->spellcount; -} - -/* ------------------------------------------------------------- */ -/* Die für den Spruch benötigte Aura pro Stufe. - * Die Grundkosten pro Stufe werden hier um 2^count erhöht. Der - * Parameter count ist dabei die Anzahl der bereits gezauberten Sprüche - */ -int -spellcost(unit *u, const spell * sp) -{ - int k, aura = 0; - int count = countspells(u, 0); - - for (k = 0; sp->components[k].type; k++) { - if (sp->components[k].type == r_aura) { - aura = sp->components[k].amount; - } - } - aura *= (1<components[k].type; k++) { - if (costtyp == SPC_LINEAR) return SPC_LINEAR; - - if (sp->components[k].cost == SPC_LINEAR) { - return SPC_LINEAR; - } - - /* wenn keine Fixkosten, Typ übernehmen */ - if (sp->components[k].cost != SPC_FIX) { - costtyp = sp->components[k].cost; - } - } - return costtyp; -} - -/* ------------------------------------------------------------- */ -/* durch Komponenten und cast_level begrenzter maximal möglicher - * Level - * Da die Funktion nicht alle Komponenten durchprobiert sondern beim - * ersten Fehler abbricht, muss die Fehlermeldung später mit cancast() - * generiert werden. - * */ -int -eff_spelllevel(unit *u, const spell * sp, int cast_level, int range) -{ - int k, maxlevel, needplevel; - int costtyp = SPC_FIX; - - for (k = 0; sp->components[k].type; k++) { - if (cast_level == 0) - return 0; - - if (sp->components[k].amount > 0) { - /* Die Kosten für Aura sind auch von der Zahl der bereits - * gezauberten Sprüche abhängig */ - if (sp->components[k].type == r_aura) { - needplevel = spellcost(u, sp) * range; - } else { - needplevel = sp->components[k].amount * range; - } - maxlevel = get_pooled(u, sp->components[k].type, GET_DEFAULT, needplevel*cast_level)/needplevel; - - /* sind die Kosten fix, so muss die Komponente nur einmal vorhanden - * sein und der cast_level ändert sich nicht */ - if (sp->components[k].cost == SPC_FIX) { - if (maxlevel < 1) cast_level = 0; - /* ansonsten wird das Minimum aus maximal möglicher Stufe und der - * gewünschten gebildet */ - } else if (sp->components[k].cost == SPC_LEVEL) { - costtyp = SPC_LEVEL; - cast_level = MIN(cast_level, maxlevel); - /* bei Typ Linear müssen die Kosten in Höhe der Stufe vorhanden - * sein, ansonsten schlägt der Spruch fehl */ - } else if (sp->components[k].cost == SPC_LINEAR) { - costtyp = SPC_LINEAR; - if (maxlevel < cast_level) cast_level = 0; - } - } - } - /* Ein Spruch mit Fixkosten wird immer mit der Stufe des Spruchs und - * nicht auf der Stufe des Magiers gezaubert */ - if (costtyp == SPC_FIX) { - cast_level = MIN(cast_level, sp->level); - } - - return cast_level; -} - -/* ------------------------------------------------------------- */ -/* Die Spruchgrundkosten werden mit der Entfernung (Farcasting) - * multipliziert, wobei die Aurakosten ein Sonderfall sind, da sie sich - * auch durch die Menge der bereits gezauberten Sprüche erhöht. - * Je nach Kostenart werden dann die Komponenten noch mit cast_level - * multipliziert. - */ -void -pay_spell(unit * u, const spell * sp, int cast_level, int range) -{ - int k; - int resuse; - - for (k = 0; sp->components[k].type; k++) { - if (sp->components[k].type == r_aura) { - resuse = spellcost(u, sp) * range; - } else { - resuse = sp->components[k].amount * range; - } - - if (sp->components[k].cost == SPC_LINEAR - || sp->components[k].cost == SPC_LEVEL) - { - resuse *= cast_level; - } - - use_pooled(u, sp->components[k].type, GET_DEFAULT, resuse); - } -} - - -/* ------------------------------------------------------------- */ -/* Ein Magier kennt den Spruch und kann sich die Beschreibung anzeigen - * lassen, wenn diese in seiner Spruchliste steht. Zaubern muss er ihn - * aber dann immer noch nicht können, vieleicht ist seine Stufe derzeit - * nicht ausreichend oder die Komponenten fehlen. - */ -boolean -knowsspell(const region * r, const unit * u, const spell * sp) -{ - sc_mage * mage; - /* Ist überhaupt ein gültiger Spruch angegeben? */ - if (!sp || sp->id == 0) { - return false; - } - /* Magier? */ - mage = get_mage(u); - if (mage == NULL) { - log_warning(("%s ist kein Magier, versucht aber zu zaubern.\n", - unitname(u))); - return false; - } - /* steht der Spruch in der Spruchliste? */ - if (!u_hasspell(u, sp)) { - /* ist der Spruch aus einem anderen Magiegebiet? */ - if (know_school(u->faction, sp->magietyp)) { - return false; - } - if (eff_skill(u, SK_MAGIC, u->region) >= sp->level) { - log_warning(("%s ist hat die erforderliche Stufe, kennt aber %s nicht.\n", - unitname(u), spell_name(sp, default_locale))); - } - return false; - } - - /* hier sollten alle potentiellen Fehler abgefangen sein */ - return true; -} - -/* Um einen Spruch zu beherrschen, muss der Magier die Stufe des - * Spruchs besitzen, nicht nur wissen, das es ihn gibt (also den Spruch - * in seiner Spruchliste haben). - * Kosten für einen Spruch können Magiepunkte, Silber, Kraeuter - * und sonstige Gegenstaende sein. - */ - -boolean -cancast(unit * u, const spell * sp, int level, int range, struct order * ord) -{ - int k; - int itemanz; - resource * reslist = NULL; - - if (knowsspell(u->region, u, sp) == false) { - /* Diesen Zauber kennt die Einheit nicht */ - cmistake(u, ord, 173, MSG_MAGIC); - return false; - } - /* reicht die Stufe aus? */ - if (eff_skill(u, SK_MAGIC, u->region) < sp->level) { - /* die Einheit ist nicht erfahren genug für diesen Zauber */ - cmistake(u, ord, 169, MSG_MAGIC); - return false; - } - - for (k = 0; sp->components[k].type; ++k) { - if (sp->components[k].amount > 0) { - const resource_type * rtype = sp->components[k].type; - int itemhave; - - /* Die Kosten für Aura sind auch von der Zahl der bereits - * gezauberten Sprüche abhängig */ - if (rtype == r_aura) { - itemanz = spellcost(u, sp) * range; - } else { - itemanz = sp->components[k].amount * range; - } - - /* sind die Kosten stufenabhängig, so muss itemanz noch mit dem - * level multipliziert werden */ - switch(sp->components[k].cost) { - case SPC_LEVEL: - case SPC_LINEAR: - itemanz *= level; - break; - case SPC_FIX: - default: - break; - } - - itemhave = get_pooled(u, rtype, GET_DEFAULT, itemanz); - if (itemhave < itemanz) { - resource * res = malloc(sizeof(resource)); - res->number = itemanz-itemhave; - res->type = rtype; - res->next = reslist; - reslist = res; - } - } - } - if (reslist!=NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "missing_components_list", "list", reslist)); - return false; - } - return true; -} - -/* ------------------------------------------------------------- */ -/* generische Spruchstaerke, - * - * setzt sich derzeit aus der Stufe des Magiers, Magieturmeffekt, - * Spruchitems und Antimagiefeldern zusammen. Es koennen noch die - * Stufe des Spruchs und Magiekosten mit einfliessen. - * - * Die effektive Spruchstärke und ihre Auswirkungen werden in der - * Spruchfunktionsroutine ermittelt. - */ - -double -spellpower(region * r, unit * u, const spell * sp, int cast_level, struct order * ord) -{ - curse * c; - double force = cast_level; - int elf_power = -1; - - if (sp==NULL) { - return 0; - } else { - /* Bonus durch Magieturm und gesegneten Steinkreis */ - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - if (btype && btype->flags & BTF_MAGIC) ++force; - } - - if (get_item(u, I_RING_OF_POWER) > 0) ++force; - if (elf_power<0) { - elf_power = get_param_int(global.parameters, "rules.magic.elfpower", 0); - } - if (elf_power && u->race==new_race[RC_ELF] && r_isforest(r)) { - ++force; - } - - /* Antimagie in der Zielregion */ - c = get_curse(r->attribs, ct_find("antimagiczone")); - if (curse_active(c)) { - unit * mage = c->magician; - force -= curse_geteffect(c); - curse_changevigour(&r->attribs, c, (float)-cast_level); - cmistake(u, ord, 185, MSG_MAGIC); - if (mage!=NULL && mage->faction!=NULL) { - if (force>0) { - ADDMSG(&mage->faction->msgs, msg_message("reduce_spell", "self mage region", mage, u, r)); - } else { - ADDMSG(&mage->faction->msgs, msg_message("block_spell", "self mage region", mage, u, r)); - } - } - } - - /* Patzerfluch-Effekt: */ - c = get_curse(r->attribs, ct_find("fumble")); - if (curse_active(c)) { - unit * mage = c->magician; - force -= curse_geteffect(c); - curse_changevigour(&u->attribs, c, -1); - cmistake(u, ord, 185, MSG_MAGIC); - if (mage!=NULL && mage->faction!=NULL) { - if (force>0) { - ADDMSG(&mage->faction->msgs, msg_message("reduce_spell", "self mage region", mage, u, r)); - } else { - ADDMSG(&mage->faction->msgs, msg_message("block_spell", "self mage region", mage, u, r)); - } - } - } - - force = force * MagicPower(); - - return MAX(force, 0); -} - -/* ------------------------------------------------------------- */ -/* farcasting() == 1 -> gleiche Region, da man mit Null nicht vernünfigt - * rechnen kann */ -static int -farcasting(unit *magician, region *r) -{ - int dist; - int mult; - - if (!r) { - return INT_MAX; - } - - dist = koor_distance(r->x, r->y, magician->region->x, magician->region->y); - - if (dist > 24) return INT_MAX; - - mult = 1 << dist; - if (dist > 1) { - if (!path_exists(magician->region, r, dist*2, allowed_fly)) mult = INT_MAX; - } - - return mult; -} - - -/* ------------------------------------------------------------- */ -/* Antimagie - Magieresistenz */ -/* ------------------------------------------------------------- */ - -/* allgemeine Magieresistenz einer Einheit, - * reduziert magischen Schaden */ -double -magic_resistance(unit *target) -{ - attrib * a; - curse *c; - int n; - - /* Bonus durch Rassenmagieresistenz */ - double probability = target->race->magres; - assert(target->number>0); - - /* Magier haben einen Resistenzbonus vom Magietalent * 5%*/ - probability += effskill(target, SK_MAGIC)*0.05; - - /* Auswirkungen von Zaubern auf der Einheit */ - c = get_curse(target->attribs, ct_find("magicresistance")); - if (c) { - probability += 0.01 * curse_geteffect(c) * get_cursedmen(target, c); - } - - /* Unicorn +10 */ - n = get_item(target, I_ELVENHORSE); - if (n) probability += n*0.1/target->number; - - /* Auswirkungen von Zaubern auf der Region */ - a = a_find(target->region->attribs, &at_curse); - while (a && a->type==&at_curse) { - curse *c = (curse*)a->data.v; - unit *mage = c->magician; - - if (mage!=NULL) { - if (c->type == ct_find("goodmagicresistancezone")) { - if (alliedunit(mage, target->faction, HELP_GUARD)) { - probability += curse_geteffect(c)*0.01; - break; - } - } - else if (c->type == ct_find("badmagicresistancezone")) { - if (alliedunit(mage, target->faction, HELP_GUARD)) { - /* TODO: hier sollte doch sicher was passieren? */ - a = a->next; - continue; - } - } - } - a = a->next; - } - /* Bonus durch Artefakte */ - /* TODO (noch gibs keine)*/ - - /* Bonus durch Gebäude */ - { - struct building * b = inside_building(target); - const struct building_type * btype = b?b->type:NULL; - - /* gesegneter Steinkreis gibt 30% dazu */ - if (btype) probability += btype->magresbonus * 0.01; - } - return probability; -} - -/* ------------------------------------------------------------- */ -/* Prüft, ob das Objekt dem Zauber widerstehen kann. - * Objekte können Regionen, Units, Gebäude oder Schiffe sein. - * TYP_UNIT: - * Das höchste Talent des Ziels ist sein 'Magieresistenz-Talent', Magier - * bekommen einen Bonus. Grundchance ist 50%, für jede Stufe - * Unterschied gibt es 5%, minimalchance ist 5% für jeden (5-95%) - * Scheitert der Spruch an der Magieresistenz, so gibt die Funktion - * true zurück - */ - -boolean -target_resists_magic(unit *magician, void *obj, int objtyp, int t_bonus) -{ - double probability = 0.0; - - if (magician == NULL) return true; - if (obj == NULL) return true; - - switch(objtyp) { - case TYP_UNIT: - { - int at, pa = 0; - skill * sv; - unit * u = (unit*)obj; - - at = effskill(magician, SK_MAGIC); - - for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - int sk = effskill(u, sv->id); - if (pa < sk) pa = sk; - } - - /* Contest */ - probability = 0.05 * (10 + pa - at); - - probability += magic_resistance((unit *)obj); - break; - } - - case TYP_REGION: - /* Bonus durch Zauber */ - probability += 0.01 * get_curseeffect(((region *)obj)->attribs, C_RESIST_MAGIC, 0); - break; - - case TYP_BUILDING: - /* Bonus durch Zauber */ - probability += 0.01 * get_curseeffect(((building *)obj)->attribs, C_RESIST_MAGIC, 0); - - /* Bonus durch Typ */ - probability += 0.01 * ((building *)obj)->type->magres; - - break; - - case TYP_SHIP: - /* Bonus durch Zauber */ - probability += 0.01 * get_curseeffect(((ship *)obj)->attribs, C_RESIST_MAGIC, 0); - break; - } - - probability = MAX(0.02, probability + t_bonus*0.01); - probability = MIN(0.98, probability); - - /* gibt true, wenn die Zufallszahl kleiner als die chance ist und - * false, wenn sie gleich oder größer ist, dh je größer die - * Magieresistenz (chance) desto eher gibt die Funktion true zurück */ - return chance(probability); -} - -/* ------------------------------------------------------------- */ - -boolean -is_magic_resistant(unit *magician, unit *target, int resist_bonus) -{ - return (boolean)target_resists_magic(magician, target, TYP_UNIT, resist_bonus); -} - -/* ------------------------------------------------------------- */ -/* Patzer */ -/* ------------------------------------------------------------- */ -/* allgemeine Zauberpatzer: - * Treten auf, wenn die Stufe des Magieres zu niedrig ist. - * Abhaengig von Staerke des Spruchs. - * - * Die Warscheinlichkeit reicht von 20% (beherrscht den Spruch gerade - * eben) bis zu etwa 1% bei doppelt so gut wie notwendig - */ - -boolean -fumble(region * r, unit * u, const spell * sp, int cast_grade) -{ -/* X ergibt Zahl zwischen 1 und 0, je kleiner, desto besser der Magier. - * 0,5*40-20=0, dh wenn der Magier doppelt so gut ist, wie der Spruch - * benötigt, gelingt er immer, ist er gleich gut, gelingt der Spruch mit - * 20% Warscheinlichkeit nicht - * */ - - int rnd = 0; - double x = (double) cast_grade / (double) eff_skill(u, SK_MAGIC, r); - int patzer = (int) (((double) x * 40.0) - 20.0); - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - - if (btype) patzer -= btype->fumblebonus; - /* CHAOSPATZERCHANCE 10 : +10% Chance zu Patzern */ - if (sp->magietyp == M_DRAIG) { - patzer += CHAOSPATZERCHANCE; - } - if (is_cursed(u->attribs, C_MBOOST, 0) == true) { - patzer += CHAOSPATZERCHANCE; - } - if (is_cursed(u->attribs, C_FUMBLE, 0) == true) { - patzer += CHAOSPATZERCHANCE; - } - - /* wenn die Chance kleiner als 0 ist, können wir gleich false - * zurückgeben */ - if (patzer <= 0) { - return false; - } - rnd = rng_int()%100; - - if (rnd > patzer) { - /* Glück gehabt, kein Patzer */ - return false; - } - return true; -} - -/* ------------------------------------------------------------- */ -/* Dummy-Zauberpatzer, Platzhalter für speziel auf die Sprüche -* zugeschnittene Patzer */ -static void -patzer(castorder *co) -{ - unit *mage = co->magician.u; - - cmistake(mage, co->order, 180, MSG_MAGIC); - - return; -} -/* Die normalen Spruchkosten müssen immer bezahlt werden, hier noch - * alle weiteren Folgen eines Patzers - */ - -static void -do_fumble(castorder *co) -{ - curse * c; - region * r = co->rt; - unit * u = co->magician.u; - const spell *sp = co->sp; - int level = co->level; - int duration; - double effect; - - ADDMSG(&u->faction->msgs, msg_message("patzer", "unit region spell", - u, r, sp)); - switch (rng_int() % 10) { - case 0: - /* wenn vorhanden spezieller Patzer, ansonsten nix */ - if (sp->patzer) sp->patzer(co); - else patzer(co); - break; - - case 1: - /* Kröte */ - { - /* 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 triggerlit of the mage gone toad. - */ - trigger * trestore = trigger_changerace(u, u->race, u->irace); - - if (chance(0.7)) { - const item_type * it_toadslime = it_find("toadslime"); - if (it_toadslime!=NULL) { - t_add(&trestore, trigger_giveitem(u, it_toadslime, 1)); - } - } - - duration = rng_int()%level/2; - if (duration<2) duration = 2; - add_trigger(&u->attribs, "timer", trigger_timeout(duration, trestore)); - u->race = new_race[RC_TOAD]; - u->irace = NULL; - ADDMSG(&r->msgs, msg_message("patzer6", "unit region spell", - u, r, sp)); - break; - } - /* fall-through is intentional! */ - - case 2: - /* temporärer Stufenverlust */ - duration = MAX(rng_int()%level/2, 2); - effect = -0.5*level; - c = create_curse(u, &u->attribs, ct_find("skillmod"), (float)level, duration, - effect, 1); - c->data.i = SK_MAGIC; - ADDMSG(&u->faction->msgs, msg_message("patzer2", "unit region", u, r)); - break; - case 3: - case 4: - /* Spruch schlägt fehl, alle Magiepunkte weg */ - set_spellpoints(u, 0); - ADDMSG(&u->faction->msgs, msg_message("patzer3", "unit region spell", - u, r, sp)); - break; - - case 5: - case 6: - /* Spruch gelingt, aber alle Magiepunkte weg */ - if (sp->sp_function==NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); - } else { - ((nspell_f)sp->sp_function)(co); - } - set_spellpoints(u, 0); - ADDMSG(&u->faction->msgs, msg_message("patzer4", "unit region spell", - u, r, sp)); - break; - - case 7: - case 8: - case 9: - default: - /* Spruch gelingt, alle nachfolgenden Sprüche werden 2^4 so teuer */ - if (sp->sp_function==NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); - } else { - ((nspell_f)sp->sp_function)(co); - } - ADDMSG(&u->faction->msgs, msg_message("patzer5", "unit region spell", - u, r, sp)); - countspells(u, 3); - } - - return; -} - -/* ------------------------------------------------------------- */ -/* Regeneration von Aura */ -/* ------------------------------------------------------------- */ - -/* Ein Magier regeneriert pro Woche W(Stufe^1.5/2+1), mindestens 1 - * Zwerge nur die Hälfte - */ -static double -regeneration(unit * u) -{ - int sk; - double aura, d; - double potenz = 1.5; - double divisor = 2.0; - - sk = effskill(u, SK_MAGIC); - /* Rassenbonus/-malus */ - d = pow(sk, potenz) * u->race->regaura / divisor; - d++; - - /* Einfluss von Artefakten */ - /* TODO (noch gibs keine)*/ - - /* Würfeln */ - aura = (rng_double() * d + rng_double() * d)/2 + 1; - - aura *= MagicRegeneration(); - - return aura; -} - -void -regeneration_magiepunkte(void) -{ - region *r; - unit *u; - int aura, auramax; - double reg_aura; - int regen; - double mod; - - for (r = regions; r; r = r->next) { - for (u = r->units; u; u = u->next) { - if (u->number && is_mage(u)) { - aura = get_spellpoints(u); - auramax = max_spellpoints(r, u); - if (aura < auramax) { - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - reg_aura = regeneration(u); - - /* Magierturm erhöht die Regeneration um 75% */ - /* Steinkreis erhöht die Regeneration um 50% */ - if (btype) reg_aura *= btype->auraregen; - - /* Bonus/Malus durch Zauber */ - mod = get_curseeffect(u->attribs, C_AURA, 0); - if (mod>0) { - reg_aura = (reg_aura*mod)/100.0; - } - - /* Einfluss von Artefakten */ - /* TODO (noch gibs keine)*/ - - /* maximal Differenz bis Maximale-Aura regenerieren - * mindestens 1 Aura pro Monat */ - regen = (int)reg_aura; - reg_aura -= regen; - if (chance(reg_aura)) ++regen; - regen = MAX(1, regen); - regen = MIN((auramax - aura), regen); - - aura += regen; - ADDMSG(&u->faction->msgs, msg_message( - "regenaura", "unit region amount", - u, r, regen)); - } - set_spellpoints(u, MIN(aura, auramax)); - - /* Zum letzten Mal Spruchliste aktualisieren */ - /*updatespelllist(u);*/ - } - } - } -} - -static boolean -verify_ship(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) -{ - ship *sh = findship(spobj->data.i); - - if (sh!=NULL && sh->region!=r && (sp->sptyp & SEARCHLOCAL)) { - /* Burg muss in gleicher Region sein */ - sh = NULL; - } - - if (sh==NULL) { - /* Burg nicht gefunden */ - spobj->flag = TARGET_NOTFOUND; - ADDMSG(&mage->faction->msgs, msg_message("spellshipnotfound", - "unit region command id", mage, mage->region, ord, spobj->data.i)); - return false; - } - spobj->flag = 0; - spobj->data.sh = sh; - return true; -} - -static boolean -verify_building(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) -{ - building *b = findbuilding(spobj->data.i); - - if (b!=NULL && b->region!=r && (sp->sptyp & SEARCHLOCAL)) { - /* Burg muss in gleicher Region sein */ - b = NULL; - } - - if (b==NULL) { - /* Burg nicht gefunden */ - spobj->flag = TARGET_NOTFOUND; - ADDMSG(&mage->faction->msgs, msg_message("spellbuildingnotfound", - "unit region command id", mage, mage->region, ord, spobj->data.i)); - return false; - } - spobj->flag = 0; - spobj->data.b = b; - return true; -} - -message * -msg_unitnotfound(const struct unit * mage, struct order * ord, const struct spllprm * spobj) -{ - /* Einheit nicht gefunden */ - char tbuf[20]; - const char * uid; - - if (spobj->typ==SPP_UNIT) { - uid = itoa36(spobj->data.i); - } else { - sprintf(tbuf, "%s %s", LOC(mage->faction->locale, - parameters[P_TEMP]), itoa36(spobj->data.i)); - uid = tbuf; - } - return msg_message("unitnotfound_id", - "unit region command id", mage, mage->region, ord, uid); -} - -static boolean -verify_unit(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) -{ - unit *u = NULL; - switch (spobj->typ) { - case SPP_UNIT: - u = findunit(spobj->data.i); - break; - case SPP_TEMP: - u = findnewunit(r, mage->faction, spobj->data.i); - if (u==NULL) u = findnewunit(mage->region, mage->faction, spobj->data.i); - break; - default: - assert(!"shouldn't happen, this"); - } - if (u!=NULL && (sp->sptyp & SEARCHLOCAL)) { - if (u->region!=r) u = NULL; - else if (sp->sptyp & TESTCANSEE) { - if (!cansee(mage->faction, r, u, 0) && !ucontact(u, mage)) { - u = NULL; - } - } - } - - if (u==NULL) { - /* Einheit nicht gefunden */ - spobj->flag = TARGET_NOTFOUND; - ADDMSG(&mage->faction->msgs, msg_unitnotfound(mage, ord, spobj)); - return false; - } - /* Einheit wurde gefunden, pointer setzen */ - spobj->flag = 0; - spobj->data.u = u; - return true; -} - -/* ------------------------------------------------------------- */ -/* Zuerst wird versucht alle noch nicht gefundenen Objekte zu finden - * oder zu prüfen, ob das gefundene Objekt wirklich hätte gefunden - * werden dürfen (nicht alle Zauber wirken global). Dabei zählen wir die - * Misserfolge (failed). - * Dann folgen die Tests der gefundenen Objekte auf Magieresistenz und - * Sichtbarkeit. Dabei zählen wir die magieresistenten (resists) - * Objekte. Alle anderen werten wir als Erfolge (success) */ - -/* gibt bei Misserfolg 0 zurück, bei Magieresistenz zumindeste eines - * Objektes 1 und bei Erfolg auf ganzer Linie 2 */ -static void -verify_targets(castorder *co, int * invalid, int * resist, int * success) -{ - unit *mage = co->magician.u; - const spell *sp = co->sp; - region *target_r = co->rt; - spellparameter *sa = co->par; - int i; - - *invalid = 0; - *resist = 0; - *success = 0; - - if (sa && sa->length) { - /* zuerst versuchen wir vorher nicht gefundene Objekte zu finden. - * Wurde ein Objekt durch globalsuche gefunden, obwohl der Zauber - * gar nicht global hätte suchen dürften, setzen wir das Objekt - * zurück. */ - for (i=0;ilength;i++) { - spllprm * spobj = sa->param[i]; - - switch(spobj->typ) { - case SPP_TEMP: - case SPP_UNIT: - if (!verify_unit(target_r, mage, sp, spobj, co->order)) ++*invalid; - break; - case SPP_BUILDING: - if (!verify_building(target_r, mage, sp, spobj, co->order)) ++*invalid; - break; - case SPP_SHIP: - if (!verify_ship(target_r, mage, sp, spobj, co->order)) ++*invalid; - break; - default: - break; - } - } - - /* Nun folgen die Tests auf cansee und Magieresistenz */ - for (i=0;ilength;i++) { - spllprm * spobj = sa->param[i]; - unit * u; - building * b; - ship * sh; - region * tr; - - if (spobj->flag == TARGET_NOTFOUND) continue; - switch(spobj->typ) { - case SPP_TEMP: - case SPP_UNIT: - u = spobj->data.u; - - if ((sp->sptyp & TESTRESISTANCE) - && target_resists_magic(mage, u, TYP_UNIT, 0)) - { - /* Fehlermeldung */ - spobj->data.i = u->no; - spobj->flag = TARGET_RESISTS; - ++*resist; - ADDMSG(&mage->faction->msgs, msg_message("spellunitresists", - "unit region command target", - mage, mage->region, co->order, u)); - break; - } - - /* TODO: Test auf Parteieigenschaft Magieresistsenz */ - ++*success; - break; - case SPP_BUILDING: - b = spobj->data.b; - - if ((sp->sptyp & TESTRESISTANCE) - && target_resists_magic(mage, b, TYP_BUILDING, 0)) - { /* Fehlermeldung */ - spobj->data.i = b->no; - spobj->flag = TARGET_RESISTS; - ++*resist; - ADDMSG(&mage->faction->msgs, msg_message("spellbuildingresists", - "unit region command id", - mage, mage->region, co->order, spobj->data.i)); - break; - } - ++*success; - break; - case SPP_SHIP: - sh = spobj->data.sh; - - if ((sp->sptyp & TESTRESISTANCE) - && target_resists_magic(mage, sh, TYP_SHIP, 0)) - { /* Fehlermeldung */ - spobj->data.i = sh->no; - spobj->flag = TARGET_RESISTS; - ++*resist; - ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, - "spellshipresists", "ship", sh)); - break; - } - ++*success; - break; - - case SPP_REGION: - /* haben wir ein Regionsobjekt, dann wird auch dieses und - nicht target_r überprüft. */ - tr = spobj->data.r; - - if ((sp->sptyp & TESTRESISTANCE) - && target_resists_magic(mage, tr, TYP_REGION, 0)) - { /* Fehlermeldung */ - spobj->flag = TARGET_RESISTS; - ++*resist; - ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", - "unit region command", mage, mage->region, co->order)); - break; - } - ++*success; - break; - case SPP_INT: - case SPP_STRING: - ++*success; - break; - - default: - break; - } - } - } else { - /* der Zauber hat keine expliziten Parameter/Ziele, es kann sich - * aber um einen Regionszauber handeln. Wenn notwendig hier die - * Magieresistenz der Region prüfen. */ - if ((sp->sptyp & REGIONSPELL)) { - /* Zielobjekt Region anlegen */ - spllprm * spobj = malloc(sizeof(spllprm)); - spobj->flag = 0; - spobj->typ = SPP_REGION; - spobj->data.r = target_r; - - sa = calloc(1, sizeof(spellparameter)); - sa->length = 1; - sa->param = calloc(sa->length, sizeof(spllprm *)); - sa->param[0] = spobj; - co->par = sa; - - if ((sp->sptyp & TESTRESISTANCE)) { - if (target_resists_magic(mage, target_r, TYP_REGION, 0)) { - /* Fehlermeldung */ - ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", - "unit region command", mage, mage->region, co->order)); - spobj->flag = TARGET_RESISTS; - ++*resist; - } else { - ++*success; - } - } else { - ++*success; - } - } else { - ++*success; - } - } -} - -/* ------------------------------------------------------------- */ -/* Hilfsstrukturen für ZAUBERE */ -/* ------------------------------------------------------------- */ - -static void -free_spellparameter(spellparameter *pa) -{ - int i; - - /* Elemente free'en */ - for (i=0; i < pa->length; i++) { - - switch(pa->param[i]->typ) { - case SPP_STRING: - free(pa->param[i]->data.s); - break; - default: - break; - } - free(pa->param[i]); - } - - if (pa->param) free(pa->param); - /* struct free'en */ - free(pa); -} - -static int -addparam_string(const char * const param[], spllprm ** spobjp) -{ - spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); - assert(param[0]); - - spobj->flag = 0; - spobj->typ = SPP_STRING; - spobj->data.xs = strdup(param[0]); - return 1; -} - -static int -addparam_int(const char * const param[], spllprm ** spobjp) -{ - spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); - assert(param[0]); - - spobj->flag = 0; - spobj->typ = SPP_INT; - spobj->data.i = atoi((char*)param[0]); - return 1; -} - -static int -addparam_ship(const char * const param[], spllprm ** spobjp) -{ - spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); - int id = atoi36((const char *)param[0]); - - spobj->flag = 0; - spobj->typ = SPP_SHIP; - spobj->data.i = id; - return 1; -} - -static int -addparam_building(const char * const param[], spllprm ** spobjp) -{ - spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); - int id = atoi36((const char *)param[0]); - - spobj->flag = 0; - spobj->typ = SPP_BUILDING; - spobj->data.i = id; - return 1; -} - -static int -addparam_region(const char * const param[], spllprm ** spobjp, const unit * u, order * ord, plane * pl) -{ - assert(param[0]); - if (param[1]==0) { - /* Fehler: Zielregion vergessen */ - cmistake(u, ord, 194, MSG_MAGIC); - return -1; - } else { - int tx = atoi((const char*)param[0]), ty = atoi((const char*)param[1]); - int x = rel_to_abs(pl, u->faction, tx, 0); - int y = rel_to_abs(pl, u->faction, ty, 1); - region *rt; - - pnormalize(&x, &y, pl); - rt = findregion(x,y); - - if (rt!=NULL) { - spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); - - spobj->flag = 0; - spobj->typ = SPP_REGION; - spobj->data.r = rt; - } else { - /* Fehler: Zielregion vergessen */ - cmistake(u, ord, 194, MSG_MAGIC); - return -1; - } - return 2; - } -} - - -static int -addparam_unit(const char * const param[], spllprm ** spobjp, const unit * u, order * ord) -{ - spllprm *spobj; - int i = 0; - sppobj_t otype = SPP_UNIT; - - *spobjp = NULL; - if (findparam(param[0], u->faction->locale)==P_TEMP) { - if (param[1]==NULL) { - /* Fehler: Ziel vergessen */ - cmistake(u, ord, 203, MSG_MAGIC); - return -1; - } - ++i; - otype = SPP_TEMP; - } - - spobj = *spobjp = malloc(sizeof(spllprm)); - spobj->flag = 0; - spobj->typ = otype; - spobj->data.i = atoi36((const char*)param[i]); - - return i+1; -} - -static spellparameter * -add_spellparameter(region *target_r, unit *u, const char *syntax, const char * const param[], int size, struct order * ord) -{ - boolean fail = false; - int i = 0; - int p = 0; - const char * c; - spellparameter *par; - int minlen = 0; - - for (c=syntax;*c!=0;++c) { - /* this makes sure that: - * minlen("kc?") = 0 - * minlen("kc+") = 1 - * minlen("cccc+c?") = 4 - */ - if (*c=='?') --minlen; - else if (*c!='+' && *c!='k') ++minlen; - } - c = syntax; - - /* mindestens ein Ziel (Ziellose Zauber werden nicht - * geparst) */ - if (minlen && size==0) { - /* Fehler: Ziel vergessen */ - cmistake(u, ord, 203, MSG_MAGIC); - return 0; - } - - par = malloc(sizeof(spellparameter)); - par->length = size; - if (!size) { - par->param = NULL; - return par; - } - par->param = malloc(size * sizeof(spllprm *)); - - while (!fail && *c && ifaction->locale); - switch (pword) { - case P_REGION: - spobj = malloc(sizeof(spllprm)); - spobj->flag = 0; - spobj->typ = SPP_REGION; - spobj->data.r = u->region; - j = 0; - ++c; - break; - case P_UNIT: - if (iparam[p++] = spobj; - i += j; - } - } - - /* im Endeffekt waren es evtl. nur p parameter (wegen TEMP) */ - par->length = p; - if (fail || par->lengthmagician.u = u; - corder->familiar = u2; - corder->sp = sp; - corder->level = lev; - corder->force = force; - corder->rt = r; - corder->distance = range; - corder->order = copy_order(ord); - corder->par = p; - - return corder; -} - -/* Hänge c-order co an die letze c-order von cll an */ -void -add_castorder(spellrank *cll, castorder *co) -{ - if (cll->begin==NULL) { - cll->end = &cll->begin; - } - - *cll->end = co; - cll->end = &co->next; - - return; -} - -void -free_castorders(castorder *co) -{ - castorder *co2; - - while (co) { - co2 = co; - co = co->next; - if (co2->par) { - free_spellparameter(co2->par); - } - if (co2->order) free_order(co2->order); - free(co2); - } - return; -} - -/* ------------------------------------------------------------- */ -/*** - ** at_familiarmage - **/ - -typedef struct familiar_data { - unit * mage; - unit * familiar; -} famililar_data; - -boolean -is_familiar(const unit *u) -{ - attrib * a = a_find(u->attribs, &at_familiarmage); - return i2b(a!=NULL); -} - -static void -a_write_unit(const attrib * a, const void * owner, struct storage * store) -{ - unit * u = (unit*)a->data.v; - write_unit_reference(u, store); -} - -static int -sm_familiar(const unit * u, const region * r, skill_t sk, int value) /* skillmod */ -{ - if (sk==SK_MAGIC) return value; - else { - int mod; - unit * familiar = get_familiar(u); - if (familiar==NULL) { - /* the familiar is dead */ - return value; - } - mod = eff_skill(familiar, sk, r)/2; - if (r != familiar->region) { - mod /= distance(r, familiar->region); - } - return value + mod; - } -} - -static 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); - 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; - } - - a = a_find(mage->attribs, &at_familiar); - if (a==NULL) { - a = a_add(&mage->attribs, a_new(&at_familiar)); - a->data.v = familiar; - } else assert(!a->data.v || a->data.v == familiar); - /* 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 assert(!a->data.v || a->data.v == mage); -} - -void -remove_familiar(unit *mage) -{ - attrib *a = a_find(mage->attribs, &at_familiar); - attrib *an; - skillmod_data *smd; - - if (a!=NULL) { - a_remove(&mage->attribs, a); - } - a = a_find(mage->attribs, &at_skillmod); - while (a && a->type==&at_skillmod) { - an = a->next; - smd = (skillmod_data *)a->data.v; - if (smd->special==sm_familiar) a_remove(&mage->attribs, a); - a = an; - } -} - -boolean -create_newfamiliar(unit * mage, unit * familiar) -{ - /* 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); - - 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; - - /* TODO: Diese Attribute beim Tod des Familiars entfernen: */ - /* Wenn der Magier stirbt, dann auch der Vertraute */ - add_trigger(&mage->attribs, "destroy", trigger_killunit(familiar)); - /* 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; -} - -static int -resolve_familiar(variant data, void * addr) -{ - unit * familiar; - int result = resolve_unit(data, &familiar); - if (result==0 && familiar) { - 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; -} - -static int -read_familiar(attrib * a, void * owner, struct storage * store) -{ - int result = read_reference(&a->data.v, store, read_unit_reference, resolve_familiar); - if (result==0 && a->data.v==NULL) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -/* clones */ - -void -create_newclone(unit * mage, unit * clone) -{ - attrib *a; - - a = a_find(mage->attribs, &at_clone); - if (a == NULL) { - a = a_add(&mage->attribs, a_new(&at_clone)); - a->data.v = clone; - } else assert(!a->data.v || a->data.v == clone); - /* TODO: Diese Attribute beim Tod des Klons entfernen: */ - - a = a_find(clone->attribs, &at_clonemage); - if (a == NULL) { - a = a_add(&clone->attribs, a_new(&at_clonemage)); - a->data.v = mage; - } else assert(!a->data.v || a->data.v == mage); - - /* Wenn der Magier stirbt, wird das in destroy_unit abgefangen. - * Kein Trigger, zu kompliziert. */ - - /* Wenn der Klon stirbt, dann bekommt der Magier einen Schock */ - add_trigger(&clone->attribs, "destroy", trigger_clonedied(mage)); -} - -static void -set_clone(unit * mage, unit * clone) -{ - attrib *a; - - a = a_find(mage->attribs, &at_clone); - if (a==NULL) { - a = a_add(&mage->attribs, a_new(&at_clone)); - a->data.v = clone; - } else assert(!a->data.v || a->data.v == clone); - - a = a_find(clone->attribs, &at_clonemage); - if (a==NULL) { - a = a_add(&clone->attribs, a_new(&at_clonemage)); - a->data.v = mage; - } else assert(!a->data.v || a->data.v == mage); -} - -unit * -has_clone(unit *mage) -{ - attrib *a = a_find(mage->attribs, &at_clone); - if(a) return (unit *)a->data.v; - return NULL; -} - -static int -resolve_clone(variant data, void * addr) -{ - unit * clone; - int result = resolve_unit(data, &clone); - if (result==0 && clone) { - 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; -} - -static int -read_clone(attrib * a, void * owner, struct storage * store) -{ - int result = read_reference(&a->data.v, store, read_unit_reference, resolve_clone); - if (result==0 && a->data.v==NULL) { - 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) { - 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; -} - -static int -read_magician(attrib * a, void * owner, struct storage * store) -{ - int result = read_reference(&a->data.v, store, read_unit_reference, resolve_mage); - if (result==0 && a->data.v==NULL) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -static int -age_unit(attrib * a) -/* if unit is gone or dead, remove the attribute */ -{ - unit * u = (unit*)a->data.v; - return (u!=NULL && u->number>0)?AT_AGE_KEEP:AT_AGE_REMOVE; -} - -attrib_type at_familiarmage = { - "familiarmage", - NULL, - NULL, - age_unit, - a_write_unit, - read_magician, - ATF_UNIQUE -}; - -attrib_type at_familiar = { - "familiar", - NULL, - NULL, - age_unit, - a_write_unit, - read_familiar, - ATF_UNIQUE -}; - -attrib_type at_clonemage = { - "clonemage", - NULL, - NULL, - age_unit, - a_write_unit, - read_magician, - ATF_UNIQUE -}; - -attrib_type at_clone = { - "clone", - NULL, - NULL, - age_unit, - a_write_unit, - read_clone, - ATF_UNIQUE -}; - -unit * -get_familiar(const unit *u) -{ - attrib * a = a_find(u->attribs, &at_familiar); - if (a!=NULL) { - unit * u = (unit*)a->data.v; - if (u->number>0) return u; - } - return NULL; -} - -unit * -get_familiar_mage(const unit *u) -{ - attrib * a = a_find(u->attribs, &at_familiarmage); - if (a!=NULL) { - unit * u = (unit*)a->data.v; - if (u->number>0) return u; - } - return NULL; -} - -unit * -get_clone(const unit *u) -{ - attrib * a = a_find(u->attribs, &at_clone); - if (a!=NULL) { - unit * u = (unit*)a->data.v; - if (u->number>0) return u; - } - return NULL; -} - -unit * -get_clone_mage(const unit *u) -{ - attrib * a = a_find(u->attribs, &at_clonemage); - if (a!=NULL) { - unit * u = (unit*)a->data.v; - if (u->number>0) return u; - } - return NULL; -} - -static boolean -is_moving_ship(const region * r, const ship *sh) -{ - const unit *u = shipowner(sh); - - if (u) switch (get_keyword(u->thisorder)) { - case K_ROUTE: - case K_MOVE: - case K_FOLLOW: - return true; - } - return false; -} - -static castorder * -cast_cmd(unit * u, order * ord) -{ - region * r = u->region; - region * target_r = r; - int level, range; - unit *familiar = NULL, *mage = u; - const char * s; - spell * sp; - plane * pl; - spellparameter *args = NULL; - - if (LongHunger(u)) { - cmistake(u, ord, 224, MSG_MAGIC); - return 0; - } - pl = rplane(r); - if (pl && fval(pl, PFL_NOMAGIC)) { - cmistake(u, ord, 269, MSG_MAGIC); - return 0; - } - level = eff_skill(u, SK_MAGIC, r); - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - /* für Syntax ' STUFE x REGION y z ' */ - if (findparam(s, u->faction->locale) == P_LEVEL) { - int p = getint(); - level = MIN(p, level); - if (level < 1) { - /* Fehler "Das macht wenig Sinn" */ - cmistake(u, ord, 10, MSG_MAGIC); - return 0; - } - s = getstrtoken(); - } - if (findparam(s, u->faction->locale) == P_REGION) { - int t_x = getint(); - int t_y = getint(); - plane * pl = getplane(u->region); - t_x = rel_to_abs(pl, u->faction, t_x,0); - t_y = rel_to_abs(pl, u->faction, t_y,1); - pnormalize(&t_x, &t_y, pl); - target_r = findregion(t_x, t_y); - if (!target_r) { - /* Fehler "Die Region konnte nicht verzaubert werden" */ - ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", - "unit region command", mage, mage->region, ord)); - return 0; - } - s = getstrtoken(); - } - /* für Syntax ' REGION x y STUFE z ' - * hier nach REGION nochmal auf STUFE prüfen */ - if (findparam(s, u->faction->locale) == P_LEVEL) { - int p = getint(); - level = MIN(p, level); - if (level < 1) { - /* Fehler "Das macht wenig Sinn" */ - cmistake(u, ord, 10, MSG_MAGIC); - return 0; - } - s = getstrtoken(); - } - if (!s[0] || strlen(s) == 0) { - /* Fehler "Es wurde kein Zauber angegeben" */ - cmistake(u, ord, 172, MSG_MAGIC); - return 0; - } - sp = get_spellfromtoken(u, s, u->faction->locale); - - /* Vertraute können auch Zauber sprechen, die sie selbst nicht - * können. get_spellfromtoken findet aber nur jene Sprüche, die - * die Einheit beherrscht. */ - if (sp == NULL && is_familiar(u)) { - familiar = u; - mage = get_familiar_mage(u); - if (mage!=NULL) sp = get_spellfromtoken(mage, s, mage->faction->locale); - } - - if (sp == NULL) { - /* Fehler 'Spell not found' */ - cmistake(u, ord, 173, MSG_MAGIC); - return 0; - } - /* um testen auf spruchnamen zu unterbinden sollte vor allen - * fehlermeldungen die anzeigen das der magier diesen Spruch - * nur in diese Situation nicht anwenden kann, noch eine - * einfache Sicherheitsprüfung kommen */ - if (!knowsspell(r, u, sp)) { - /* vorsicht! u kann der familiar sein */ - if (!familiar) { - cmistake(u, ord, 173, MSG_MAGIC); - return 0; - } - } - if (sp->sptyp & ISCOMBATSPELL) { - /* Fehler: "Dieser Zauber ist nur im Kampf sinnvoll" */ - cmistake(u, ord, 174, MSG_MAGIC); - return 0; - } - /* Auf dem Ozean Zaubern als quasi-langer Befehl können - * normalerweise nur Meermenschen, ausgenommen explizit als - * OCEANCASTABLE deklarierte Sprüche */ - if (fval(r->terrain, SEA_REGION)) { - if (u->race != new_race[RC_AQUARIAN] - && !fval(u->race, RCF_SWIM) - && !(sp->sptyp & OCEANCASTABLE)) { - /* Fehlermeldung */ - ADDMSG(&u->faction->msgs, msg_message("spellfail_onocean", - "unit region command", u, u->region, ord)); - return 0; - } - /* Auf bewegenden Schiffen kann man nur explizit als - * ONSHIPCAST deklarierte Zauber sprechen */ - } else if (u->ship) { - if (is_moving_ship(r, u->ship)) { - if (!(sp->sptyp & ONSHIPCAST)) { - /* Fehler: "Diesen Spruch kann man nicht auf einem sich - * bewegenden Schiff stehend zaubern" */ - cmistake(u, ord, 175, MSG_MAGIC); - return 0; - } - } - } - /* Farcasting bei nicht farcastbaren Sprüchen abfangen */ - range = farcasting(u, target_r); - if (range > 1) { - if (!(sp->sptyp & FARCASTING)) { - /* Fehler "Diesen Spruch kann man nicht in die Ferne - * richten" */ - cmistake(u, ord, 176, MSG_MAGIC); - return 0; - } - if (range > 1024) { /* (2^10) weiter als 10 Regionen entfernt */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "spellfail::nocontact", - "target", target_r)); - return 0; - } - } - /* Stufenangabe bei nicht Stufenvariierbaren Sprüchen abfangen */ - if (!(sp->sptyp & SPELLLEVEL)) { - int ilevel = eff_skill(u, SK_MAGIC, u->region); - if (ilevel!=level) { - level = ilevel; - ADDMSG(&u->faction->msgs, msg_message("spellfail::nolevel", - "mage region command", u, u->region, ord)); - } - } - /* Vertrautenmagie */ - /* Kennt der Vertraute den Spruch, so zaubert er ganz normal. - * Ansonsten zaubert der Magier durch seinen Vertrauten, dh - * zahlt Komponenten und Aura. Dabei ist die maximale Stufe - * die des Vertrauten! - * Der Spruch wirkt dann auf die Region des Vertrauten und - * gilt nicht als Farcasting. */ - if (familiar || is_familiar(u)) { - if ((sp->sptyp & NOTFAMILIARCAST)) { - /* Fehler: "Diesen Spruch kann der Vertraute nicht zaubern" */ - cmistake(u, ord, 177, MSG_MAGIC); - return 0; - } - if (!knowsspell(r, u, sp)) { /* Magier zaubert durch Vertrauten */ - mage = get_familiar_mage(u); - if (range > 1) { /* Fehler! Versucht zu Farcasten */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_farcast", - "mage", mage)); - return 0; - } - if (distance(mage->region, r) > eff_skill(mage, SK_MAGIC, mage->region)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_toofar", - "mage", mage)); - return 0; - } - /* mage auf magier setzen, level anpassen, range für Erhöhung - * der Spruchkosten nutzen, langen Befehl des Magiers - * löschen, zaubern kann er noch */ - range *= 2; - set_order(&mage->thisorder, NULL); - level = MIN(level, eff_skill(mage, SK_MAGIC, mage->region)/2); - familiar = u; - } - } - /* Weitere Argumente zusammenbasteln */ - if (sp->parameter) { - char ** params = malloc(2*sizeof(char*)); - int p = 0, size = 2; - for (;;) { - s = getstrtoken(); - if (*s==0) break; - if (p+1>=size) { - size*=2; - params = realloc(params, sizeof(char*)*size); - } - params[p++] = strdup(s); - } - params[p] = 0; - args = add_spellparameter(target_r, mage, sp->parameter, (const char * const *)params, p, ord); - for (p=0;params[p];++p) free(params[p]); - free(params); - if (args==NULL) { - /* Syntax war falsch */ - return 0; - } - } - return new_castorder(mage, familiar, sp, target_r, level, 0, range, ord, args); -} - -/* ------------------------------------------------------------- */ -/* Damit man keine Rituale in fremden Gebiet machen kann, diese vor - * Bewegung zaubern. Magier sind also in einem fremden Gebiet eine Runde - * lang verletzlich, da sie es betreten, und angegriffen werden können, - * bevor sie ein Ritual machen können. - * - * Syntax: ZAUBER [REGION X Y] [STUFE ] "Spruchname" [Einheit-1 - * Einheit-2 ..] - * - * Nach Priorität geordnet die Zauber global auswerten. - * - * Die Kosten für Farcasting multiplizieren sich mit der Entfernung, - * cast_level gibt die virtuelle Stufe an, die den durch das Farcasten - * entstandenen Spruchkosten entspricht. Sind die Spruchkosten nicht - * levelabhängig, so sind die Kosten nur von der Entfernung bestimmt, - * die Stärke/Level durch den realen Skill des Magiers - */ - -void -magic(void) -{ - region *r; - int rank; - castorder *co; - spellrank spellranks[MAX_SPELLRANK]; - - memset(spellranks, 0, sizeof(spellranks)); - - for (r = regions; r; r = r->next) { - unit *u; - for (u = r->units; u; u = u->next) { - order * ord; - - if (u->number<=0 || u->race == new_race[RC_SPELL]) - continue; - - if (u->race == new_race[RC_INSECT] && r_insectstalled(r) && - !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) - continue; - - if (fval(u, UFL_WERE|UFL_LONGACTION)) { - continue; - } - - for (ord = u->orders; ord; ord = ord->next) { - if (get_keyword(ord) == K_CAST) { - castorder * co = cast_cmd(u, ord); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - if (co) { - const spell * sp = co->sp; - add_castorder(&spellranks[sp->rank], co); - } - } - } - } - } - - /* Da sich die Aura und Komponenten in der Zwischenzeit verändert - * haben können und sich durch vorherige Sprüche das Zaubern - * erschwert haben kann, muss beim zaubern erneut geprüft werden, ob der - * Spruch überhaupt gezaubert werden kann. - * (level) die effektive Stärke des Spruchs (= Stufe, auf der der - * Spruch gezaubert wird) */ - - for (rank = 0; rank < MAX_SPELLRANK; rank++) { - for (co = spellranks[rank].begin; co; co = co->next) { - order * ord = co->order; - int invalid, resist, success, cast_level = co->level; - boolean fumbled = false; - unit * u = co->magician.u; - const spell *sp = co->sp; - region * target_r = co->rt; - - /* reichen die Komponenten nicht, wird der Level reduziert. */ - co->level = eff_spelllevel(u, sp, cast_level, co->distance); - - if (co->level < 1) { - /* Fehlermeldung mit Komponenten generieren */ - cancast(u, sp, cast_level, co->distance, ord); - continue; - } - - if (cast_level > co->level) { - /* Sprüche mit Fixkosten werden immer auf Stufe des Spruchs - * gezaubert, co->level ist aber defaultmäßig Stufe des Magiers */ - if (spl_costtyp(sp) != SPC_FIX) { - ADDMSG(&u->faction->msgs, msg_message("missing_components", - "unit spell level", u, sp, cast_level)); - } - } - - /* Prüfen, ob die realen Kosten für die gewünschten Stufe bezahlt - * werden können */ - if (cancast(u, sp, co->level, co->distance, ord) == false) { - /* die Fehlermeldung wird in cancast generiert */ - continue; - } - - co->force = spellpower(target_r, u, sp, co->level, ord); - /* die Stärke kann durch Antimagie auf 0 sinken */ - if (co->force <= 0) { - co->force = 0; - ADDMSG(&u->faction->msgs, msg_message("missing_force", - "unit spell level", u, sp, co->level)); - } - - /* Ziele auf Existenz prüfen und Magieresistenz feststellen. Wurde - * kein Ziel gefunden, so ist verify_targets=0. Scheitert der - * Spruch an der Magieresistenz, so ist verify_targets = 1, bei - * Erfolg auf ganzer Linie ist verify_targets= 2 - */ - verify_targets(co, &invalid, &resist, &success); - if (success+resist==0) { - /* kein Ziel gefunden, Fehlermeldungen sind in verify_targets */ - /* keine kosten für den zauber */ - continue; /* äußere Schleife, nächster Zauberer */ - } else if (co->force>0 && resist>0) { - /* einige oder alle Ziele waren magieresistent */ - if (success==0) { - co->force = 0; - /* zwar wurde mindestens ein Ziel gefunden, das widerstand - * jedoch dem Zauber. Kosten abziehen und abbrechen. */ - ADDMSG(&u->faction->msgs, msg_message("spell_resist", "unit region spell", - u, r, sp)); - } - } - - /* Auch für Patzer gibt es Erfahrung, müssen die Spruchkosten - * bezahlt werden und die nachfolgenden Sprüche werden teurer */ - if (co->force>0) { - if (fumble(target_r, u, sp, co->level)) { - /* zuerst bezahlen, dann evt in do_fumble alle Aura verlieren */ - fumbled = true; - } else { - if (sp->sp_function==NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); - co->level = 0; - } else { - co->level = ((nspell_f)sp->sp_function)(co); - } - if (co->level <= 0) { - /* Kosten nur für real benötige Stufe berechnen */ - continue; - } - } - } - pay_spell(u, sp, co->level, co->distance); - /* erst bezahlen, dann Kostenzähler erhöhen */ - if (fumbled) do_fumble(co); - countspells(u, 1); - } - } - - /* Sind alle Zauber gesprochen gibts Erfahrung */ - for (r = regions; r; r = r->next) { - unit *u; - for (u = r->units; u; u = u->next) { - if (is_mage(u) && countspells(u, 0) > 0) { - produceexp(u, SK_MAGIC, u->number); - /* Spruchlistenaktualiesierung ist in Regeneration */ - } - } - } - for (rank = 0; rank < MAX_SPELLRANK; rank++) { - free_castorders(spellranks[rank].begin); - } - remove_empty_units(); -} - -const char * -spell_info(const spell * sp, const struct locale * lang) -{ - return LOC(lang, mkname("spellinfo", sp->sname)); -} - -const char * -spell_name(const spell * sp, const struct locale * lang) -{ - return LOC(lang, mkname("spell", sp->sname)); -} - -const char * -curse_name(const curse_type * ctype, const struct locale * lang) -{ - return LOC(lang, mkname("spell", ctype->cname)); -} - -void -spelllist_add(spell_list ** lspells, spell * sp) -{ - spell_list * entry; - - while (*lspells) { - spell_list * slist = *lspells; - if (slist->data->id==sp->id) { - if (slist->data==sp) { - log_error(("trying to add spell '%s' to a list twice.\n", sp->sname)); - return; - } - } - if (slist->data->id>sp->id) break; - lspells = &slist->next; - } - entry = malloc(sizeof(spell_list)); - entry->data = sp; - entry->next = *lspells; - *lspells = entry; -} - -spell_list ** -spelllist_find(spell_list ** lspells, const spell * sp) -{ - while (*lspells) { - spell_list * slist = *lspells; - if (slist->data->id>=sp->id) break; - lspells = &slist->next; - } - return lspells; -} - -extern struct spell_list ** get_spelllist(struct sc_mage * mage, struct faction * f) -{ - if (mage) { - return &mage->spells; - } - return NULL; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "magic.h" + +#include "building.h" +#include "curse.h" +#include "faction.h" +#include "item.h" +#include "message.h" +#include "objtypes.h" +#include "order.h" +#include "pathfinder.h" +#include "plane.h" +#include "pool.h" +#include "race.h" +#include "region.h" +#include "ship.h" +#include "skill.h" +#include "spell.h" +#include "teleport.h" +#include "terrain.h" +#include "unit.h" +#include "version.h" + +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include +#include + +/* ------------------------------------------------------------- */ + +const char *magic_school[MAXMAGIETYP] = +{ + "gray", + "illaun", + "tybied", + "cerddor", + "gwyrrd", + "draig", + "common" +}; + +attrib_type at_reportspell = { + "reportspell", NULL, NULL, NULL, NO_WRITE, NO_READ +}; + +/** + ** at_icastle + ** TODO: separate castle-appearance from illusion-effects + **/ + +static double +MagicRegeneration(void) +{ + static double value = -1.0; + if (value<0) { + const char * str = get_param(global.parameters, "magic.regeneration"); + value = str?atof(str):1.0; + } + return value; +} + +double +MagicPower(void) +{ + static double value = -1.0; + if (value<0) { + const char * str = get_param(global.parameters, "magic.power"); + value = str?atof(str):1.0; + } + return value; +} + +static int +a_readicastle(attrib * a, void * owner, struct storage * store) +{ + icastle_data * data = (icastle_data*)a->data.v; + variant bno; + char token[32]; + store->r_tok_buf(store, token, sizeof(token)); + bno.i = store->r_int(store); + data->time = store->r_int(store); + data->building = findbuilding(bno.i); + if (!data->building) { + /* this shouldn't happen, but just in case it does: */ + ur_add(bno, &data->building, resolve_building); + } + data->type = bt_find(token); + return AT_READ_OK; +} + +static void +a_writeicastle(const attrib * a, const void * owner, struct storage * store) +{ + icastle_data * data = (icastle_data*)a->data.v; + store->w_tok(store, data->type->_name); + store->w_int(store, data->building->no); + store->w_int(store, data->time); +} + +static int +a_ageicastle(struct attrib * a) +{ + icastle_data * data = (icastle_data*)a->data.v; + if (data->time<=0) { + building * b = data->building; + region * r = b->region; + ADDMSG(&r->msgs, msg_message("icastle_dissolve", "building", b)); + /* remove_building lets units leave the building */ + remove_building(&r->buildings, b); + return AT_AGE_REMOVE; + } + else data->time--; + return AT_AGE_KEEP; +} + +static void +a_initicastle(struct attrib * a) +{ + a->data.v = calloc(sizeof(icastle_data), 1); +} + +static void +a_finalizeicastle(struct attrib * a) +{ + free(a->data.v); +} + +attrib_type at_icastle = { + "zauber_icastle", + a_initicastle, + a_finalizeicastle, + a_ageicastle, + a_writeicastle, + a_readicastle +}; + +/* ------------------------------------------------------------- */ + +extern int dice(int count, int value); + +/* ------------------------------------------------------------- */ +/* aus dem alten System übriggebliegene Funktionen, die bei der + * Umwandlung von alt nach neu gebraucht werden */ +/* ------------------------------------------------------------- */ + +static void +init_mage(attrib * a) { + a->data.v = calloc(sizeof(sc_mage), 1); +} + +static void +free_mage(attrib * a) +{ + sc_mage * mage = (sc_mage*)a->data.v; + freelist(mage->spells); + free(mage); +} + +int FactionSpells(void) +{ + static int rules_factionspells = -1; + if (rules_factionspells<0) { + rules_factionspells = get_param_int(global.parameters, "rules.magic.factionlist", 0); + } + return rules_factionspells; +} + +void read_spellist(struct spell_list ** slistp, magic_t mtype, struct storage * store) +{ + for (;;) { + spell * sp; + char spname[64]; + + if (store->versionr_int(store); + if (i < 0) break; + sp = find_spellbyid(M_NONE, (spellid_t)i); + } else { + store->r_tok_buf(store, spname, sizeof(spname)); + if (strcmp(spname, "end")==0) break; + sp = find_spell(mtype, spname); + } + if (sp!=NULL) { + add_spell(slistp, sp); + } + } +} + +static int +read_mage(attrib * a, void * owner, struct storage * store) +{ + int i, mtype; + sc_mage * mage = (sc_mage*)a->data.v; + char spname[64]; + + mtype = store->r_int(store); + mage->spellpoints = store->r_int(store); + mage->spchange = store->r_int(store); + mage->magietyp = (magic_t)mtype; + for (i=0;i!=MAXCOMBATSPELLS;++i) { + spell * sp = NULL; + int level = 0; + if (store->versionr_int(store); + level = store->r_int(store); + if (spid>=0) { + sp = find_spellbyid(mage->magietyp, (spellid_t)spid); + } + } else { + store->r_tok_buf(store, spname, sizeof(spname)); + level = store->r_int(store); + + if (strcmp("none", spname)!=0) { + sp = find_spell(mage->magietyp, spname); + } + } + if (sp && level>=0) { + int slot = -1; + if (sp->sptyp & PRECOMBATSPELL) slot = 0; + else if (sp->sptyp & COMBATSPELL) slot = 1; + else if (sp->sptyp & POSTCOMBATSPELL) slot = 2; + if (slot>=0) { + mage->combatspells[slot].level = level; + mage->combatspells[slot].sp = sp; + } + } + } + read_spellist(&mage->spells, mage->magietyp, store); + return AT_READ_OK; +} + +void write_spelllist(const spell_list * slist, struct storage * store) +{ + while (slist!=NULL) { + spell * sp = slist->data; + store->w_tok(store, sp->sname); + slist = slist->next; + } + store->w_tok(store, "end"); +} + +static void +write_mage(const attrib * a, const void * owner, struct storage * store) +{ + int i; + sc_mage *mage = (sc_mage*)a->data.v; + + store->w_int(store, mage->magietyp); + store->w_int(store, mage->spellpoints); + store->w_int(store, mage->spchange); + for (i=0;i!=MAXCOMBATSPELLS;++i) { + store->w_tok(store, mage->combatspells[i].sp?mage->combatspells[i].sp->sname:"none"); + store->w_int(store, mage->combatspells[i].level); + } + write_spelllist(mage->spells, store); +} + +attrib_type at_mage = { + "mage", + init_mage, + free_mage, + NULL, + write_mage, + read_mage, + ATF_UNIQUE +}; + +boolean +is_mage(const unit * u) +{ + return i2b(get_mage(u) != NULL); +} + +sc_mage * +get_mage(const unit * u) +{ + if (has_skill(u, SK_MAGIC)) { + attrib * a = a_find(u->attribs, &at_mage); + if (a) return a->data.v; + } + return (sc_mage *) NULL; +} + +/* ------------------------------------------------------------- */ +/* Ausgabe der Spruchbeschreibungen +* Anzeige des Spruchs nur, wenn die Stufe des besten Magiers vorher +* kleiner war (u->faction->seenspells). Ansonsten muss nur geprüft +* werden, ob dieser Magier den Spruch schon kennt, und andernfalls der +* Spruch zu seiner List-of-known-spells hinzugefügt werden. +*/ + + +static int +read_seenspell(attrib * a, void * owner, struct storage * store) +{ + int i; + spell * sp = NULL; + char token[32]; + + store->r_tok_buf(store, token, sizeof(token)); + i = atoi(token); + if (i!=0) { + sp = find_spellbyid(M_NONE, (spellid_t)i); + } else { + int mtype; + mtype = store->r_int(store); + sp = find_spell((magic_t)mtype, token); + } + if (sp==NULL) { + /* log_error(("could not find seenspell '%s'\n", buf)); */ + return AT_READ_FAIL; + } + a->data.v = sp; + return AT_READ_OK; +} + +static void +write_seenspell(const attrib * a, const void * owner, struct storage * store) +{ + const spell * sp = (const spell*)a->data.v; + store->w_tok(store, sp->sname); + store->w_int(store, sp->magietyp); +} + +attrib_type at_seenspell = { + "seenspell", NULL, NULL, NULL, write_seenspell, read_seenspell +}; + +static boolean +already_seen(const faction * f, const spell * sp) +{ + attrib *a; + + for (a = a_find(f->attribs, &at_seenspell); a && a->type==&at_seenspell; a=a->next) { + if (a->data.v==sp) return true; + } + return false; +} + +static boolean know_school(const faction * f, magic_t school) +{ + static int common = MAXMAGIETYP; + if (f->magiegebiet==school) return true; + if (common==MAXMAGIETYP) { + const char * common_school = get_param(global.parameters, "rules.magic.common"); + if (common_school) { + for (common=0;common!=MAXMAGIETYP;++common) { + if (strcmp(common_school, magic_school[common])==0) break; + } + if (common==MAXMAGIETYP) { + common = M_NONE; + } + } else { + return false; + } + } + return school==common; +} + +#define COMMONSPELLS 1 /* number of new common spells per level */ +#define MAXSPELLS 256 + +/** update the spellbook with a new level +* Written for Eressea 1.1 +*/ +void +update_spellbook(faction * f, int level) +{ + spell * commonspells[MAXSPELLS]; + int numspells = 0; + spell_list * slist; + + for (slist=spells;slist!=NULL;slist=slist->next) { + spell * sp = slist->data; + if (sp->magietyp == M_COMMON && level>f->max_spelllevel && sp->level<=level) { + commonspells[numspells++] = sp; + } else { + if (know_school(f, sp->magietyp) && sp->level <= level) { + if (!has_spell(f->spellbook, sp)) { + add_spell(&f->spellbook, sp); + } + } + } + } + while (numspells>0 && level>f->max_spelllevel) { + int i; + for (i=0;i!=COMMONSPELLS;++i) { + int maxspell = numspells; + int spellno = -1; + spell * sp; + do { + if (spellno==maxspell) { + --maxspell; + } + spellno = rng_int() % maxspell; + sp = commonspells[spellno]; + } + while (maxspell>0 && sp && sp->level<=f->max_spelllevel && !has_spell(f->spellbook, sp)); + + if (sp) { + add_spell(&f->spellbook, sp); + commonspells[spellno] = 0; + } + } + ++f->max_spelllevel; + } +} + +void +updatespelllist(unit * u) +{ + int sk = eff_skill(u, SK_MAGIC, u->region); + spell_list * slist = spells; + struct sc_mage * mage = get_mage(u); + boolean ismonster = is_monsters(u->faction); + + if (mage->magietyp==M_GRAY) { + /* Magier mit M_GRAY bekommen weder Sprüche angezeigt noch + * neue Sprüche in ihre List-of-known-spells. Das sind zb alle alten + * Drachen, die noch den Skill Magie haben, und alle familiars */ + return; + } + + if (FactionSpells()) { + slist = u->faction->spellbook; + } + + for (;slist!=NULL;slist=slist->next) { + spell * sp = slist->data; + if (sp->level<=sk) { + boolean know = u_hasspell(u, sp); + + if (know || sp->magietyp==M_COMMON || know_school(u->faction, sp->magietyp)) { + faction * f = u->faction; + + if (!know) add_spell(get_spelllist(mage, u->faction), sp); + if (!ismonster && !already_seen(u->faction, sp)) { + a_add(&f->attribs, a_new(&at_reportspell))->data.v = sp; + a_add(&f->attribs, a_new(&at_seenspell))->data.v = sp; + } + } + } + } + +} + +/* ------------------------------------------------------------- */ +/* Erzeugen eines neuen Magiers */ +sc_mage * +create_mage(unit * u, magic_t mtyp) +{ + sc_mage *mage; + attrib *a; + + a = a_find(u->attribs, &at_mage); + if (a!=NULL) { + a_remove(&u->attribs, a); + } + a = a_add(&u->attribs, a_new(&at_mage)); + mage = a->data.v; + + mage->magietyp = mtyp; + return mage; +} + +/* ------------------------------------------------------------- */ +/* Funktionen für die Bearbeitung der List-of-known-spells */ + +void +add_spell(spell_list ** slistp, spell * sp) +{ + if (slistp==NULL) { + log_error(("add_spell: unit is not a mage.\n")); + } else { + spell_list ** slist = spelllist_find(slistp, sp); + if (*slist) { + spell * psp = (*slist)->data; + if (psp==sp) { + log_error(("add_spell: unit already has spell '%s'.\n", sp->sname)); + return; + } + } + spelllist_add(slist, sp); + } +} + +boolean +has_spell(spell_list * slist, const spell * sp) +{ + if (slist!=NULL) { + spell_list * sfind = *spelllist_find(&slist, sp); + return sfind!=NULL && sfind->data==sp; + } + return false; +} + +boolean +u_hasspell(const struct unit *u, const struct spell * sp) +{ + sc_mage * mage = get_mage(u); + if (mage) return has_spell(mage->spells, sp); + return false; +} + +/* ------------------------------------------------------------- */ +/* Eingestellte Kampfzauberstufe ermitteln */ + +int +get_combatspelllevel(const unit *u, int nr) +{ + sc_mage *m = get_mage(u); + + assert(nr < MAXCOMBATSPELLS); + if (m) { + int level = eff_skill(u, SK_MAGIC, u->region); + return MIN(m->combatspells[nr].level, level); + } + return -1; +} + +/* ------------------------------------------------------------- */ +/* Kampfzauber ermitteln, setzen oder löschen */ + +const spell* +get_combatspell(const unit *u, int nr) +{ + sc_mage *m; + + assert(nr < MAXCOMBATSPELLS); + m = get_mage(u); + if (m) { + return m->combatspells[nr].sp; + } else if (u->race->precombatspell != NULL) { + return u->race->precombatspell; + } + + return NULL; +} + +void +set_combatspell(unit *u, spell *sp, struct order * ord, int level) +{ + sc_mage *m = get_mage(u); + int i = -1; + if (!m) return; + + /* knowsspell prüft auf ist_magier, ist_spruch, kennt_spruch */ + if (knowsspell(u->region, u, sp) == false){ + /* Fehler 'Spell not found' */ + cmistake(u, ord, 173, MSG_MAGIC); + return; + } + if (!u_hasspell(u, sp)) { + /* Diesen Zauber kennt die Einheit nicht */ + cmistake(u, ord, 169, MSG_MAGIC); + return; + } + if (!(sp->sptyp & ISCOMBATSPELL)) { + /* Diesen Kampfzauber gibt es nicht */ + cmistake(u, ord, 171, MSG_MAGIC); + return; + } + + if (sp->sptyp & PRECOMBATSPELL) i = 0; + else if (sp->sptyp & COMBATSPELL) i = 1; + else if (sp->sptyp & POSTCOMBATSPELL) i = 2; + assert(i>=0); + m->combatspells[i].sp = sp; + m->combatspells[i].level = level; + return; +} + +void +unset_combatspell(unit *u, spell *sp) +{ + sc_mage *m; + int nr = 0; + int i; + + m = get_mage(u); + if (!m) return; + + if (!sp) { + for (i=0;icombatspells[i].sp = NULL; + } + } + else if (sp->sptyp & PRECOMBATSPELL) { + if (sp != get_combatspell(u,0)) + return; + } else if (sp->sptyp & COMBATSPELL) { + if (sp != get_combatspell(u,1)) { + return; + } + nr = 1; + } else if (sp->sptyp & POSTCOMBATSPELL) { + if (sp != get_combatspell(u,2)) { + return; + } + nr = 2; + } + m->combatspells[nr].sp = NULL; + m->combatspells[nr].level = 0; + return; +} + +/* ------------------------------------------------------------- */ +/* Gibt die aktuelle Anzahl der Magiepunkte der Einheit zurück */ +int +get_spellpoints(const unit * u) +{ + sc_mage *m; + + m = get_mage(u); + if (!m) return 0; + + return m->spellpoints; +} + +void +set_spellpoints(unit * u, int sp) +{ + sc_mage *m; + + m = get_mage(u); + if (!m) return; + + m->spellpoints = sp; + + return; +} + +/* + * verändert die Anzahl der Magiepunkte der Einheit um +mp + */ +int +change_spellpoints(unit * u, int mp) +{ + sc_mage *m; + int sp; + + m = get_mage(u); + if (!m) return 0; + + /* verhindere negative Magiepunkte */ + sp = MAX(m->spellpoints + mp, 0); + m->spellpoints = sp; + + return sp; +} + +/* bietet die Möglichkeit, die maximale Anzahl der Magiepunkte mit + * Regionszaubern oder Attributen zu beinflussen + */ +static int +get_spchange(const unit * u) +{ + sc_mage *m; + + m = get_mage(u); + if (!m) return 0; + + return m->spchange; +} + +/* ein Magier kann normalerweise maximal Stufe^2.1/1.2+1 Magiepunkte + * haben. + * Manche Rassen haben einen zusätzlichen Multiplikator + * Durch Talentverlust (zB Insekten im Berg) können negative Werte + * entstehen + */ + +/* Artefakt der Stärke + * Ermöglicht dem Magier mehr Magiepunkte zu 'speichern' + */ +/** TODO: at_skillmod daraus machen */ +static int +use_item_aura(const region * r, const unit * u) +{ + int sk, n; + + sk = eff_skill(u, SK_MAGIC, r); + n = (int)(sk * sk * u->race->maxaura / 4); + + return n; +} + +int +max_spellpoints(const region * r, const unit * u) +{ + int sk; + double n, msp; + double potenz = 2.1; + double divisor = 1.2; + + sk = eff_skill(u, SK_MAGIC, r); + msp = u->race->maxaura*(pow(sk, potenz)/divisor+1) + get_spchange(u); + + if (get_item(u, I_AURAKULUM) > 0) { + msp += use_item_aura(r, u); + } + n = get_curseeffect(u->attribs, C_AURA, 0); + if (n>0) msp = (msp*n)/100; + + return MAX((int)msp, 0); +} + +int +change_maxspellpoints(unit * u, int csp) +{ + sc_mage *m; + + m = get_mage(u); + if (!m) return 0; + + m->spchange += csp; + return max_spellpoints(u->region, u); +} + +/* ------------------------------------------------------------- */ +/* Counter für die bereits gezauberte Anzahl Sprüche pro Runde. + * Um nur die Zahl der bereits gezauberten Sprüche zu ermitteln mit + * step = 0 aufrufen. + */ +int +countspells(unit *u, int step) +{ + sc_mage *m; + int count; + + m = get_mage(u); + if (!m) + return 0; + + if (step == 0) + return m->spellcount; + + count = m->spellcount + step; + + /* negative Werte abfangen. */ + m->spellcount = MAX(0,count); + + return m->spellcount; +} + +/* ------------------------------------------------------------- */ +/* Die für den Spruch benötigte Aura pro Stufe. + * Die Grundkosten pro Stufe werden hier um 2^count erhöht. Der + * Parameter count ist dabei die Anzahl der bereits gezauberten Sprüche + */ +int +spellcost(unit *u, const spell * sp) +{ + int k, aura = 0; + int count = countspells(u, 0); + + for (k = 0; sp->components[k].type; k++) { + if (sp->components[k].type == r_aura) { + aura = sp->components[k].amount; + } + } + aura *= (1<components[k].type; k++) { + if (costtyp == SPC_LINEAR) return SPC_LINEAR; + + if (sp->components[k].cost == SPC_LINEAR) { + return SPC_LINEAR; + } + + /* wenn keine Fixkosten, Typ übernehmen */ + if (sp->components[k].cost != SPC_FIX) { + costtyp = sp->components[k].cost; + } + } + return costtyp; +} + +/* ------------------------------------------------------------- */ +/* durch Komponenten und cast_level begrenzter maximal möglicher + * Level + * Da die Funktion nicht alle Komponenten durchprobiert sondern beim + * ersten Fehler abbricht, muss die Fehlermeldung später mit cancast() + * generiert werden. + * */ +int +eff_spelllevel(unit *u, const spell * sp, int cast_level, int range) +{ + int k, maxlevel, needplevel; + int costtyp = SPC_FIX; + + for (k = 0; sp->components[k].type; k++) { + if (cast_level == 0) + return 0; + + if (sp->components[k].amount > 0) { + /* Die Kosten für Aura sind auch von der Zahl der bereits + * gezauberten Sprüche abhängig */ + if (sp->components[k].type == r_aura) { + needplevel = spellcost(u, sp) * range; + } else { + needplevel = sp->components[k].amount * range; + } + maxlevel = get_pooled(u, sp->components[k].type, GET_DEFAULT, needplevel*cast_level)/needplevel; + + /* sind die Kosten fix, so muss die Komponente nur einmal vorhanden + * sein und der cast_level ändert sich nicht */ + if (sp->components[k].cost == SPC_FIX) { + if (maxlevel < 1) cast_level = 0; + /* ansonsten wird das Minimum aus maximal möglicher Stufe und der + * gewünschten gebildet */ + } else if (sp->components[k].cost == SPC_LEVEL) { + costtyp = SPC_LEVEL; + cast_level = MIN(cast_level, maxlevel); + /* bei Typ Linear müssen die Kosten in Höhe der Stufe vorhanden + * sein, ansonsten schlägt der Spruch fehl */ + } else if (sp->components[k].cost == SPC_LINEAR) { + costtyp = SPC_LINEAR; + if (maxlevel < cast_level) cast_level = 0; + } + } + } + /* Ein Spruch mit Fixkosten wird immer mit der Stufe des Spruchs und + * nicht auf der Stufe des Magiers gezaubert */ + if (costtyp == SPC_FIX) { + cast_level = MIN(cast_level, sp->level); + } + + return cast_level; +} + +/* ------------------------------------------------------------- */ +/* Die Spruchgrundkosten werden mit der Entfernung (Farcasting) + * multipliziert, wobei die Aurakosten ein Sonderfall sind, da sie sich + * auch durch die Menge der bereits gezauberten Sprüche erhöht. + * Je nach Kostenart werden dann die Komponenten noch mit cast_level + * multipliziert. + */ +void +pay_spell(unit * u, const spell * sp, int cast_level, int range) +{ + int k; + int resuse; + + for (k = 0; sp->components[k].type; k++) { + if (sp->components[k].type == r_aura) { + resuse = spellcost(u, sp) * range; + } else { + resuse = sp->components[k].amount * range; + } + + if (sp->components[k].cost == SPC_LINEAR + || sp->components[k].cost == SPC_LEVEL) + { + resuse *= cast_level; + } + + use_pooled(u, sp->components[k].type, GET_DEFAULT, resuse); + } +} + + +/* ------------------------------------------------------------- */ +/* Ein Magier kennt den Spruch und kann sich die Beschreibung anzeigen + * lassen, wenn diese in seiner Spruchliste steht. Zaubern muss er ihn + * aber dann immer noch nicht können, vieleicht ist seine Stufe derzeit + * nicht ausreichend oder die Komponenten fehlen. + */ +boolean +knowsspell(const region * r, const unit * u, const spell * sp) +{ + sc_mage * mage; + /* Ist überhaupt ein gültiger Spruch angegeben? */ + if (!sp || sp->id == 0) { + return false; + } + /* Magier? */ + mage = get_mage(u); + if (mage == NULL) { + log_warning(("%s ist kein Magier, versucht aber zu zaubern.\n", + unitname(u))); + return false; + } + /* steht der Spruch in der Spruchliste? */ + if (!u_hasspell(u, sp)) { + /* ist der Spruch aus einem anderen Magiegebiet? */ + if (know_school(u->faction, sp->magietyp)) { + return false; + } + if (eff_skill(u, SK_MAGIC, u->region) >= sp->level) { + log_warning(("%s ist hat die erforderliche Stufe, kennt aber %s nicht.\n", + unitname(u), spell_name(sp, default_locale))); + } + return false; + } + + /* hier sollten alle potentiellen Fehler abgefangen sein */ + return true; +} + +/* Um einen Spruch zu beherrschen, muss der Magier die Stufe des + * Spruchs besitzen, nicht nur wissen, das es ihn gibt (also den Spruch + * in seiner Spruchliste haben). + * Kosten für einen Spruch können Magiepunkte, Silber, Kraeuter + * und sonstige Gegenstaende sein. + */ + +boolean +cancast(unit * u, const spell * sp, int level, int range, struct order * ord) +{ + int k; + int itemanz; + resource * reslist = NULL; + + if (knowsspell(u->region, u, sp) == false) { + /* Diesen Zauber kennt die Einheit nicht */ + cmistake(u, ord, 173, MSG_MAGIC); + return false; + } + /* reicht die Stufe aus? */ + if (eff_skill(u, SK_MAGIC, u->region) < sp->level) { + /* die Einheit ist nicht erfahren genug für diesen Zauber */ + cmistake(u, ord, 169, MSG_MAGIC); + return false; + } + + for (k = 0; sp->components[k].type; ++k) { + if (sp->components[k].amount > 0) { + const resource_type * rtype = sp->components[k].type; + int itemhave; + + /* Die Kosten für Aura sind auch von der Zahl der bereits + * gezauberten Sprüche abhängig */ + if (rtype == r_aura) { + itemanz = spellcost(u, sp) * range; + } else { + itemanz = sp->components[k].amount * range; + } + + /* sind die Kosten stufenabhängig, so muss itemanz noch mit dem + * level multipliziert werden */ + switch(sp->components[k].cost) { + case SPC_LEVEL: + case SPC_LINEAR: + itemanz *= level; + break; + case SPC_FIX: + default: + break; + } + + itemhave = get_pooled(u, rtype, GET_DEFAULT, itemanz); + if (itemhave < itemanz) { + resource * res = malloc(sizeof(resource)); + res->number = itemanz-itemhave; + res->type = rtype; + res->next = reslist; + reslist = res; + } + } + } + if (reslist!=NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "missing_components_list", "list", reslist)); + return false; + } + return true; +} + +/* ------------------------------------------------------------- */ +/* generische Spruchstaerke, + * + * setzt sich derzeit aus der Stufe des Magiers, Magieturmeffekt, + * Spruchitems und Antimagiefeldern zusammen. Es koennen noch die + * Stufe des Spruchs und Magiekosten mit einfliessen. + * + * Die effektive Spruchstärke und ihre Auswirkungen werden in der + * Spruchfunktionsroutine ermittelt. + */ + +double +spellpower(region * r, unit * u, const spell * sp, int cast_level, struct order * ord) +{ + curse * c; + double force = cast_level; + int elf_power = -1; + + if (sp==NULL) { + return 0; + } else { + /* Bonus durch Magieturm und gesegneten Steinkreis */ + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + if (btype && btype->flags & BTF_MAGIC) ++force; + } + + if (get_item(u, I_RING_OF_POWER) > 0) ++force; + if (elf_power<0) { + elf_power = get_param_int(global.parameters, "rules.magic.elfpower", 0); + } + if (elf_power && u->race==new_race[RC_ELF] && r_isforest(r)) { + ++force; + } + + /* Antimagie in der Zielregion */ + c = get_curse(r->attribs, ct_find("antimagiczone")); + if (curse_active(c)) { + unit * mage = c->magician; + force -= curse_geteffect(c); + curse_changevigour(&r->attribs, c, (float)-cast_level); + cmistake(u, ord, 185, MSG_MAGIC); + if (mage!=NULL && mage->faction!=NULL) { + if (force>0) { + ADDMSG(&mage->faction->msgs, msg_message("reduce_spell", "self mage region", mage, u, r)); + } else { + ADDMSG(&mage->faction->msgs, msg_message("block_spell", "self mage region", mage, u, r)); + } + } + } + + /* Patzerfluch-Effekt: */ + c = get_curse(r->attribs, ct_find("fumble")); + if (curse_active(c)) { + unit * mage = c->magician; + force -= curse_geteffect(c); + curse_changevigour(&u->attribs, c, -1); + cmistake(u, ord, 185, MSG_MAGIC); + if (mage!=NULL && mage->faction!=NULL) { + if (force>0) { + ADDMSG(&mage->faction->msgs, msg_message("reduce_spell", "self mage region", mage, u, r)); + } else { + ADDMSG(&mage->faction->msgs, msg_message("block_spell", "self mage region", mage, u, r)); + } + } + } + + force = force * MagicPower(); + + return MAX(force, 0); +} + +/* ------------------------------------------------------------- */ +/* farcasting() == 1 -> gleiche Region, da man mit Null nicht vernünfigt + * rechnen kann */ +static int +farcasting(unit *magician, region *r) +{ + int dist; + int mult; + + if (!r) { + return INT_MAX; + } + + dist = koor_distance(r->x, r->y, magician->region->x, magician->region->y); + + if (dist > 24) return INT_MAX; + + mult = 1 << dist; + if (dist > 1) { + if (!path_exists(magician->region, r, dist*2, allowed_fly)) mult = INT_MAX; + } + + return mult; +} + + +/* ------------------------------------------------------------- */ +/* Antimagie - Magieresistenz */ +/* ------------------------------------------------------------- */ + +/* allgemeine Magieresistenz einer Einheit, + * reduziert magischen Schaden */ +double +magic_resistance(unit *target) +{ + attrib * a; + curse *c; + int n; + + /* Bonus durch Rassenmagieresistenz */ + double probability = target->race->magres; + assert(target->number>0); + + /* Magier haben einen Resistenzbonus vom Magietalent * 5%*/ + probability += effskill(target, SK_MAGIC)*0.05; + + /* Auswirkungen von Zaubern auf der Einheit */ + c = get_curse(target->attribs, ct_find("magicresistance")); + if (c) { + probability += 0.01 * curse_geteffect(c) * get_cursedmen(target, c); + } + + /* Unicorn +10 */ + n = get_item(target, I_ELVENHORSE); + if (n) probability += n*0.1/target->number; + + /* Auswirkungen von Zaubern auf der Region */ + a = a_find(target->region->attribs, &at_curse); + while (a && a->type==&at_curse) { + curse *c = (curse*)a->data.v; + unit *mage = c->magician; + + if (mage!=NULL) { + if (c->type == ct_find("goodmagicresistancezone")) { + if (alliedunit(mage, target->faction, HELP_GUARD)) { + probability += curse_geteffect(c)*0.01; + break; + } + } + else if (c->type == ct_find("badmagicresistancezone")) { + if (alliedunit(mage, target->faction, HELP_GUARD)) { + /* TODO: hier sollte doch sicher was passieren? */ + a = a->next; + continue; + } + } + } + a = a->next; + } + /* Bonus durch Artefakte */ + /* TODO (noch gibs keine)*/ + + /* Bonus durch Gebäude */ + { + struct building * b = inside_building(target); + const struct building_type * btype = b?b->type:NULL; + + /* gesegneter Steinkreis gibt 30% dazu */ + if (btype) probability += btype->magresbonus * 0.01; + } + return probability; +} + +/* ------------------------------------------------------------- */ +/* Prüft, ob das Objekt dem Zauber widerstehen kann. + * Objekte können Regionen, Units, Gebäude oder Schiffe sein. + * TYP_UNIT: + * Das höchste Talent des Ziels ist sein 'Magieresistenz-Talent', Magier + * bekommen einen Bonus. Grundchance ist 50%, für jede Stufe + * Unterschied gibt es 5%, minimalchance ist 5% für jeden (5-95%) + * Scheitert der Spruch an der Magieresistenz, so gibt die Funktion + * true zurück + */ + +boolean +target_resists_magic(unit *magician, void *obj, int objtyp, int t_bonus) +{ + double probability = 0.0; + + if (magician == NULL) return true; + if (obj == NULL) return true; + + switch(objtyp) { + case TYP_UNIT: + { + int at, pa = 0; + skill * sv; + unit * u = (unit*)obj; + + at = effskill(magician, SK_MAGIC); + + for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { + int sk = effskill(u, sv->id); + if (pa < sk) pa = sk; + } + + /* Contest */ + probability = 0.05 * (10 + pa - at); + + probability += magic_resistance((unit *)obj); + break; + } + + case TYP_REGION: + /* Bonus durch Zauber */ + probability += 0.01 * get_curseeffect(((region *)obj)->attribs, C_RESIST_MAGIC, 0); + break; + + case TYP_BUILDING: + /* Bonus durch Zauber */ + probability += 0.01 * get_curseeffect(((building *)obj)->attribs, C_RESIST_MAGIC, 0); + + /* Bonus durch Typ */ + probability += 0.01 * ((building *)obj)->type->magres; + + break; + + case TYP_SHIP: + /* Bonus durch Zauber */ + probability += 0.01 * get_curseeffect(((ship *)obj)->attribs, C_RESIST_MAGIC, 0); + break; + } + + probability = MAX(0.02, probability + t_bonus*0.01); + probability = MIN(0.98, probability); + + /* gibt true, wenn die Zufallszahl kleiner als die chance ist und + * false, wenn sie gleich oder größer ist, dh je größer die + * Magieresistenz (chance) desto eher gibt die Funktion true zurück */ + return chance(probability); +} + +/* ------------------------------------------------------------- */ + +boolean +is_magic_resistant(unit *magician, unit *target, int resist_bonus) +{ + return (boolean)target_resists_magic(magician, target, TYP_UNIT, resist_bonus); +} + +/* ------------------------------------------------------------- */ +/* Patzer */ +/* ------------------------------------------------------------- */ +/* allgemeine Zauberpatzer: + * Treten auf, wenn die Stufe des Magieres zu niedrig ist. + * Abhaengig von Staerke des Spruchs. + * + * Die Warscheinlichkeit reicht von 20% (beherrscht den Spruch gerade + * eben) bis zu etwa 1% bei doppelt so gut wie notwendig + */ + +boolean +fumble(region * r, unit * u, const spell * sp, int cast_grade) +{ +/* X ergibt Zahl zwischen 1 und 0, je kleiner, desto besser der Magier. + * 0,5*40-20=0, dh wenn der Magier doppelt so gut ist, wie der Spruch + * benötigt, gelingt er immer, ist er gleich gut, gelingt der Spruch mit + * 20% Warscheinlichkeit nicht + * */ + + int rnd = 0; + double x = (double) cast_grade / (double) eff_skill(u, SK_MAGIC, r); + int patzer = (int) (((double) x * 40.0) - 20.0); + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + + if (btype) patzer -= btype->fumblebonus; + /* CHAOSPATZERCHANCE 10 : +10% Chance zu Patzern */ + if (sp->magietyp == M_DRAIG) { + patzer += CHAOSPATZERCHANCE; + } + if (is_cursed(u->attribs, C_MBOOST, 0) == true) { + patzer += CHAOSPATZERCHANCE; + } + if (is_cursed(u->attribs, C_FUMBLE, 0) == true) { + patzer += CHAOSPATZERCHANCE; + } + + /* wenn die Chance kleiner als 0 ist, können wir gleich false + * zurückgeben */ + if (patzer <= 0) { + return false; + } + rnd = rng_int()%100; + + if (rnd > patzer) { + /* Glück gehabt, kein Patzer */ + return false; + } + return true; +} + +/* ------------------------------------------------------------- */ +/* Dummy-Zauberpatzer, Platzhalter für speziel auf die Sprüche +* zugeschnittene Patzer */ +static void +patzer(castorder *co) +{ + unit *mage = co->magician.u; + + cmistake(mage, co->order, 180, MSG_MAGIC); + + return; +} +/* Die normalen Spruchkosten müssen immer bezahlt werden, hier noch + * alle weiteren Folgen eines Patzers + */ + +static void +do_fumble(castorder *co) +{ + curse * c; + region * r = co->rt; + unit * u = co->magician.u; + const spell *sp = co->sp; + int level = co->level; + int duration; + double effect; + + ADDMSG(&u->faction->msgs, msg_message("patzer", "unit region spell", + u, r, sp)); + switch (rng_int() % 10) { + case 0: + /* wenn vorhanden spezieller Patzer, ansonsten nix */ + if (sp->patzer) sp->patzer(co); + else patzer(co); + break; + + case 1: + /* Kröte */ + { + /* 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 triggerlit of the mage gone toad. + */ + trigger * trestore = trigger_changerace(u, u->race, u->irace); + + if (chance(0.7)) { + const item_type * it_toadslime = it_find("toadslime"); + if (it_toadslime!=NULL) { + t_add(&trestore, trigger_giveitem(u, it_toadslime, 1)); + } + } + + duration = rng_int()%level/2; + if (duration<2) duration = 2; + add_trigger(&u->attribs, "timer", trigger_timeout(duration, trestore)); + u->race = new_race[RC_TOAD]; + u->irace = NULL; + ADDMSG(&r->msgs, msg_message("patzer6", "unit region spell", + u, r, sp)); + break; + } + /* fall-through is intentional! */ + + case 2: + /* temporärer Stufenverlust */ + duration = MAX(rng_int()%level/2, 2); + effect = -0.5*level; + c = create_curse(u, &u->attribs, ct_find("skillmod"), (float)level, duration, + effect, 1); + c->data.i = SK_MAGIC; + ADDMSG(&u->faction->msgs, msg_message("patzer2", "unit region", u, r)); + break; + case 3: + case 4: + /* Spruch schlägt fehl, alle Magiepunkte weg */ + set_spellpoints(u, 0); + ADDMSG(&u->faction->msgs, msg_message("patzer3", "unit region spell", + u, r, sp)); + break; + + case 5: + case 6: + /* Spruch gelingt, aber alle Magiepunkte weg */ + if (sp->sp_function==NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + } else { + ((nspell_f)sp->sp_function)(co); + } + set_spellpoints(u, 0); + ADDMSG(&u->faction->msgs, msg_message("patzer4", "unit region spell", + u, r, sp)); + break; + + case 7: + case 8: + case 9: + default: + /* Spruch gelingt, alle nachfolgenden Sprüche werden 2^4 so teuer */ + if (sp->sp_function==NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + } else { + ((nspell_f)sp->sp_function)(co); + } + ADDMSG(&u->faction->msgs, msg_message("patzer5", "unit region spell", + u, r, sp)); + countspells(u, 3); + } + + return; +} + +/* ------------------------------------------------------------- */ +/* Regeneration von Aura */ +/* ------------------------------------------------------------- */ + +/* Ein Magier regeneriert pro Woche W(Stufe^1.5/2+1), mindestens 1 + * Zwerge nur die Hälfte + */ +static double +regeneration(unit * u) +{ + int sk; + double aura, d; + double potenz = 1.5; + double divisor = 2.0; + + sk = effskill(u, SK_MAGIC); + /* Rassenbonus/-malus */ + d = pow(sk, potenz) * u->race->regaura / divisor; + d++; + + /* Einfluss von Artefakten */ + /* TODO (noch gibs keine)*/ + + /* Würfeln */ + aura = (rng_double() * d + rng_double() * d)/2 + 1; + + aura *= MagicRegeneration(); + + return aura; +} + +void +regeneration_magiepunkte(void) +{ + region *r; + unit *u; + int aura, auramax; + double reg_aura; + int regen; + double mod; + + for (r = regions; r; r = r->next) { + for (u = r->units; u; u = u->next) { + if (u->number && is_mage(u)) { + aura = get_spellpoints(u); + auramax = max_spellpoints(r, u); + if (aura < auramax) { + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + reg_aura = regeneration(u); + + /* Magierturm erhöht die Regeneration um 75% */ + /* Steinkreis erhöht die Regeneration um 50% */ + if (btype) reg_aura *= btype->auraregen; + + /* Bonus/Malus durch Zauber */ + mod = get_curseeffect(u->attribs, C_AURA, 0); + if (mod>0) { + reg_aura = (reg_aura*mod)/100.0; + } + + /* Einfluss von Artefakten */ + /* TODO (noch gibs keine)*/ + + /* maximal Differenz bis Maximale-Aura regenerieren + * mindestens 1 Aura pro Monat */ + regen = (int)reg_aura; + reg_aura -= regen; + if (chance(reg_aura)) ++regen; + regen = MAX(1, regen); + regen = MIN((auramax - aura), regen); + + aura += regen; + ADDMSG(&u->faction->msgs, msg_message( + "regenaura", "unit region amount", + u, r, regen)); + } + set_spellpoints(u, MIN(aura, auramax)); + + /* Zum letzten Mal Spruchliste aktualisieren */ + /*updatespelllist(u);*/ + } + } + } +} + +static boolean +verify_ship(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) +{ + ship *sh = findship(spobj->data.i); + + if (sh!=NULL && sh->region!=r && (sp->sptyp & SEARCHLOCAL)) { + /* Burg muss in gleicher Region sein */ + sh = NULL; + } + + if (sh==NULL) { + /* Burg nicht gefunden */ + spobj->flag = TARGET_NOTFOUND; + ADDMSG(&mage->faction->msgs, msg_message("spellshipnotfound", + "unit region command id", mage, mage->region, ord, spobj->data.i)); + return false; + } + spobj->flag = 0; + spobj->data.sh = sh; + return true; +} + +static boolean +verify_building(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) +{ + building *b = findbuilding(spobj->data.i); + + if (b!=NULL && b->region!=r && (sp->sptyp & SEARCHLOCAL)) { + /* Burg muss in gleicher Region sein */ + b = NULL; + } + + if (b==NULL) { + /* Burg nicht gefunden */ + spobj->flag = TARGET_NOTFOUND; + ADDMSG(&mage->faction->msgs, msg_message("spellbuildingnotfound", + "unit region command id", mage, mage->region, ord, spobj->data.i)); + return false; + } + spobj->flag = 0; + spobj->data.b = b; + return true; +} + +message * +msg_unitnotfound(const struct unit * mage, struct order * ord, const struct spllprm * spobj) +{ + /* Einheit nicht gefunden */ + char tbuf[20]; + const char * uid; + + if (spobj->typ==SPP_UNIT) { + uid = itoa36(spobj->data.i); + } else { + sprintf(tbuf, "%s %s", LOC(mage->faction->locale, + parameters[P_TEMP]), itoa36(spobj->data.i)); + uid = tbuf; + } + return msg_message("unitnotfound_id", + "unit region command id", mage, mage->region, ord, uid); +} + +static boolean +verify_unit(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) +{ + unit *u = NULL; + switch (spobj->typ) { + case SPP_UNIT: + u = findunit(spobj->data.i); + break; + case SPP_TEMP: + u = findnewunit(r, mage->faction, spobj->data.i); + if (u==NULL) u = findnewunit(mage->region, mage->faction, spobj->data.i); + break; + default: + assert(!"shouldn't happen, this"); + } + if (u!=NULL && (sp->sptyp & SEARCHLOCAL)) { + if (u->region!=r) u = NULL; + else if (sp->sptyp & TESTCANSEE) { + if (!cansee(mage->faction, r, u, 0) && !ucontact(u, mage)) { + u = NULL; + } + } + } + + if (u==NULL) { + /* Einheit nicht gefunden */ + spobj->flag = TARGET_NOTFOUND; + ADDMSG(&mage->faction->msgs, msg_unitnotfound(mage, ord, spobj)); + return false; + } + /* Einheit wurde gefunden, pointer setzen */ + spobj->flag = 0; + spobj->data.u = u; + return true; +} + +/* ------------------------------------------------------------- */ +/* Zuerst wird versucht alle noch nicht gefundenen Objekte zu finden + * oder zu prüfen, ob das gefundene Objekt wirklich hätte gefunden + * werden dürfen (nicht alle Zauber wirken global). Dabei zählen wir die + * Misserfolge (failed). + * Dann folgen die Tests der gefundenen Objekte auf Magieresistenz und + * Sichtbarkeit. Dabei zählen wir die magieresistenten (resists) + * Objekte. Alle anderen werten wir als Erfolge (success) */ + +/* gibt bei Misserfolg 0 zurück, bei Magieresistenz zumindeste eines + * Objektes 1 und bei Erfolg auf ganzer Linie 2 */ +static void +verify_targets(castorder *co, int * invalid, int * resist, int * success) +{ + unit *mage = co->magician.u; + const spell *sp = co->sp; + region *target_r = co->rt; + spellparameter *sa = co->par; + int i; + + *invalid = 0; + *resist = 0; + *success = 0; + + if (sa && sa->length) { + /* zuerst versuchen wir vorher nicht gefundene Objekte zu finden. + * Wurde ein Objekt durch globalsuche gefunden, obwohl der Zauber + * gar nicht global hätte suchen dürften, setzen wir das Objekt + * zurück. */ + for (i=0;ilength;i++) { + spllprm * spobj = sa->param[i]; + + switch(spobj->typ) { + case SPP_TEMP: + case SPP_UNIT: + if (!verify_unit(target_r, mage, sp, spobj, co->order)) ++*invalid; + break; + case SPP_BUILDING: + if (!verify_building(target_r, mage, sp, spobj, co->order)) ++*invalid; + break; + case SPP_SHIP: + if (!verify_ship(target_r, mage, sp, spobj, co->order)) ++*invalid; + break; + default: + break; + } + } + + /* Nun folgen die Tests auf cansee und Magieresistenz */ + for (i=0;ilength;i++) { + spllprm * spobj = sa->param[i]; + unit * u; + building * b; + ship * sh; + region * tr; + + if (spobj->flag == TARGET_NOTFOUND) continue; + switch(spobj->typ) { + case SPP_TEMP: + case SPP_UNIT: + u = spobj->data.u; + + if ((sp->sptyp & TESTRESISTANCE) + && target_resists_magic(mage, u, TYP_UNIT, 0)) + { + /* Fehlermeldung */ + spobj->data.i = u->no; + spobj->flag = TARGET_RESISTS; + ++*resist; + ADDMSG(&mage->faction->msgs, msg_message("spellunitresists", + "unit region command target", + mage, mage->region, co->order, u)); + break; + } + + /* TODO: Test auf Parteieigenschaft Magieresistsenz */ + ++*success; + break; + case SPP_BUILDING: + b = spobj->data.b; + + if ((sp->sptyp & TESTRESISTANCE) + && target_resists_magic(mage, b, TYP_BUILDING, 0)) + { /* Fehlermeldung */ + spobj->data.i = b->no; + spobj->flag = TARGET_RESISTS; + ++*resist; + ADDMSG(&mage->faction->msgs, msg_message("spellbuildingresists", + "unit region command id", + mage, mage->region, co->order, spobj->data.i)); + break; + } + ++*success; + break; + case SPP_SHIP: + sh = spobj->data.sh; + + if ((sp->sptyp & TESTRESISTANCE) + && target_resists_magic(mage, sh, TYP_SHIP, 0)) + { /* Fehlermeldung */ + spobj->data.i = sh->no; + spobj->flag = TARGET_RESISTS; + ++*resist; + ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + "spellshipresists", "ship", sh)); + break; + } + ++*success; + break; + + case SPP_REGION: + /* haben wir ein Regionsobjekt, dann wird auch dieses und + nicht target_r überprüft. */ + tr = spobj->data.r; + + if ((sp->sptyp & TESTRESISTANCE) + && target_resists_magic(mage, tr, TYP_REGION, 0)) + { /* Fehlermeldung */ + spobj->flag = TARGET_RESISTS; + ++*resist; + ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", + "unit region command", mage, mage->region, co->order)); + break; + } + ++*success; + break; + case SPP_INT: + case SPP_STRING: + ++*success; + break; + + default: + break; + } + } + } else { + /* der Zauber hat keine expliziten Parameter/Ziele, es kann sich + * aber um einen Regionszauber handeln. Wenn notwendig hier die + * Magieresistenz der Region prüfen. */ + if ((sp->sptyp & REGIONSPELL)) { + /* Zielobjekt Region anlegen */ + spllprm * spobj = malloc(sizeof(spllprm)); + spobj->flag = 0; + spobj->typ = SPP_REGION; + spobj->data.r = target_r; + + sa = calloc(1, sizeof(spellparameter)); + sa->length = 1; + sa->param = calloc(sa->length, sizeof(spllprm *)); + sa->param[0] = spobj; + co->par = sa; + + if ((sp->sptyp & TESTRESISTANCE)) { + if (target_resists_magic(mage, target_r, TYP_REGION, 0)) { + /* Fehlermeldung */ + ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", + "unit region command", mage, mage->region, co->order)); + spobj->flag = TARGET_RESISTS; + ++*resist; + } else { + ++*success; + } + } else { + ++*success; + } + } else { + ++*success; + } + } +} + +/* ------------------------------------------------------------- */ +/* Hilfsstrukturen für ZAUBERE */ +/* ------------------------------------------------------------- */ + +static void +free_spellparameter(spellparameter *pa) +{ + int i; + + /* Elemente free'en */ + for (i=0; i < pa->length; i++) { + + switch(pa->param[i]->typ) { + case SPP_STRING: + free(pa->param[i]->data.s); + break; + default: + break; + } + free(pa->param[i]); + } + + if (pa->param) free(pa->param); + /* struct free'en */ + free(pa); +} + +static int +addparam_string(const char * const param[], spllprm ** spobjp) +{ + spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); + assert(param[0]); + + spobj->flag = 0; + spobj->typ = SPP_STRING; + spobj->data.xs = strdup(param[0]); + return 1; +} + +static int +addparam_int(const char * const param[], spllprm ** spobjp) +{ + spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); + assert(param[0]); + + spobj->flag = 0; + spobj->typ = SPP_INT; + spobj->data.i = atoi((char*)param[0]); + return 1; +} + +static int +addparam_ship(const char * const param[], spllprm ** spobjp) +{ + spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); + int id = atoi36((const char *)param[0]); + + spobj->flag = 0; + spobj->typ = SPP_SHIP; + spobj->data.i = id; + return 1; +} + +static int +addparam_building(const char * const param[], spllprm ** spobjp) +{ + spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); + int id = atoi36((const char *)param[0]); + + spobj->flag = 0; + spobj->typ = SPP_BUILDING; + spobj->data.i = id; + return 1; +} + +static int +addparam_region(const char * const param[], spllprm ** spobjp, const unit * u, order * ord, plane * pl) +{ + assert(param[0]); + if (param[1]==0) { + /* Fehler: Zielregion vergessen */ + cmistake(u, ord, 194, MSG_MAGIC); + return -1; + } else { + int tx = atoi((const char*)param[0]), ty = atoi((const char*)param[1]); + int x = rel_to_abs(pl, u->faction, tx, 0); + int y = rel_to_abs(pl, u->faction, ty, 1); + region *rt; + + pnormalize(&x, &y, pl); + rt = findregion(x,y); + + if (rt!=NULL) { + spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); + + spobj->flag = 0; + spobj->typ = SPP_REGION; + spobj->data.r = rt; + } else { + /* Fehler: Zielregion vergessen */ + cmistake(u, ord, 194, MSG_MAGIC); + return -1; + } + return 2; + } +} + + +static int +addparam_unit(const char * const param[], spllprm ** spobjp, const unit * u, order * ord) +{ + spllprm *spobj; + int i = 0; + sppobj_t otype = SPP_UNIT; + + *spobjp = NULL; + if (findparam(param[0], u->faction->locale)==P_TEMP) { + if (param[1]==NULL) { + /* Fehler: Ziel vergessen */ + cmistake(u, ord, 203, MSG_MAGIC); + return -1; + } + ++i; + otype = SPP_TEMP; + } + + spobj = *spobjp = malloc(sizeof(spllprm)); + spobj->flag = 0; + spobj->typ = otype; + spobj->data.i = atoi36((const char*)param[i]); + + return i+1; +} + +static spellparameter * +add_spellparameter(region *target_r, unit *u, const char *syntax, const char * const param[], int size, struct order * ord) +{ + boolean fail = false; + int i = 0; + int p = 0; + const char * c; + spellparameter *par; + int minlen = 0; + + for (c=syntax;*c!=0;++c) { + /* this makes sure that: + * minlen("kc?") = 0 + * minlen("kc+") = 1 + * minlen("cccc+c?") = 4 + */ + if (*c=='?') --minlen; + else if (*c!='+' && *c!='k') ++minlen; + } + c = syntax; + + /* mindestens ein Ziel (Ziellose Zauber werden nicht + * geparst) */ + if (minlen && size==0) { + /* Fehler: Ziel vergessen */ + cmistake(u, ord, 203, MSG_MAGIC); + return 0; + } + + par = malloc(sizeof(spellparameter)); + par->length = size; + if (!size) { + par->param = NULL; + return par; + } + par->param = malloc(size * sizeof(spllprm *)); + + while (!fail && *c && ifaction->locale); + switch (pword) { + case P_REGION: + spobj = malloc(sizeof(spllprm)); + spobj->flag = 0; + spobj->typ = SPP_REGION; + spobj->data.r = u->region; + j = 0; + ++c; + break; + case P_UNIT: + if (iparam[p++] = spobj; + i += j; + } + } + + /* im Endeffekt waren es evtl. nur p parameter (wegen TEMP) */ + par->length = p; + if (fail || par->lengthmagician.u = u; + corder->familiar = u2; + corder->sp = sp; + corder->level = lev; + corder->force = force; + corder->rt = r; + corder->distance = range; + corder->order = copy_order(ord); + corder->par = p; + + return corder; +} + +/* Hänge c-order co an die letze c-order von cll an */ +void +add_castorder(spellrank *cll, castorder *co) +{ + if (cll->begin==NULL) { + cll->end = &cll->begin; + } + + *cll->end = co; + cll->end = &co->next; + + return; +} + +void +free_castorders(castorder *co) +{ + castorder *co2; + + while (co) { + co2 = co; + co = co->next; + if (co2->par) { + free_spellparameter(co2->par); + } + if (co2->order) free_order(co2->order); + free(co2); + } + return; +} + +/* ------------------------------------------------------------- */ +/*** + ** at_familiarmage + **/ + +typedef struct familiar_data { + unit * mage; + unit * familiar; +} famililar_data; + +boolean +is_familiar(const unit *u) +{ + attrib * a = a_find(u->attribs, &at_familiarmage); + return i2b(a!=NULL); +} + +static void +a_write_unit(const attrib * a, const void * owner, struct storage * store) +{ + unit * u = (unit*)a->data.v; + write_unit_reference(u, store); +} + +static int +sm_familiar(const unit * u, const region * r, skill_t sk, int value) /* skillmod */ +{ + if (sk==SK_MAGIC) return value; + else { + int mod; + unit * familiar = get_familiar(u); + if (familiar==NULL) { + /* the familiar is dead */ + return value; + } + mod = eff_skill(familiar, sk, r)/2; + if (r != familiar->region) { + mod /= distance(r, familiar->region); + } + return value + mod; + } +} + +static 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); + 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; + } + + a = a_find(mage->attribs, &at_familiar); + if (a==NULL) { + a = a_add(&mage->attribs, a_new(&at_familiar)); + a->data.v = familiar; + } else assert(!a->data.v || a->data.v == familiar); + /* 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 assert(!a->data.v || a->data.v == mage); +} + +void +remove_familiar(unit *mage) +{ + attrib *a = a_find(mage->attribs, &at_familiar); + attrib *an; + skillmod_data *smd; + + if (a!=NULL) { + a_remove(&mage->attribs, a); + } + a = a_find(mage->attribs, &at_skillmod); + while (a && a->type==&at_skillmod) { + an = a->next; + smd = (skillmod_data *)a->data.v; + if (smd->special==sm_familiar) a_remove(&mage->attribs, a); + a = an; + } +} + +boolean +create_newfamiliar(unit * mage, unit * familiar) +{ + /* 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); + + 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; + + /* TODO: Diese Attribute beim Tod des Familiars entfernen: */ + /* Wenn der Magier stirbt, dann auch der Vertraute */ + add_trigger(&mage->attribs, "destroy", trigger_killunit(familiar)); + /* 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; +} + +static int +resolve_familiar(variant data, void * addr) +{ + unit * familiar; + int result = resolve_unit(data, &familiar); + if (result==0 && familiar) { + 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; +} + +static int +read_familiar(attrib * a, void * owner, struct storage * store) +{ + int result = read_reference(&a->data.v, store, read_unit_reference, resolve_familiar); + if (result==0 && a->data.v==NULL) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +/* clones */ + +void +create_newclone(unit * mage, unit * clone) +{ + attrib *a; + + a = a_find(mage->attribs, &at_clone); + if (a == NULL) { + a = a_add(&mage->attribs, a_new(&at_clone)); + a->data.v = clone; + } else assert(!a->data.v || a->data.v == clone); + /* TODO: Diese Attribute beim Tod des Klons entfernen: */ + + a = a_find(clone->attribs, &at_clonemage); + if (a == NULL) { + a = a_add(&clone->attribs, a_new(&at_clonemage)); + a->data.v = mage; + } else assert(!a->data.v || a->data.v == mage); + + /* Wenn der Magier stirbt, wird das in destroy_unit abgefangen. + * Kein Trigger, zu kompliziert. */ + + /* Wenn der Klon stirbt, dann bekommt der Magier einen Schock */ + add_trigger(&clone->attribs, "destroy", trigger_clonedied(mage)); +} + +static void +set_clone(unit * mage, unit * clone) +{ + attrib *a; + + a = a_find(mage->attribs, &at_clone); + if (a==NULL) { + a = a_add(&mage->attribs, a_new(&at_clone)); + a->data.v = clone; + } else assert(!a->data.v || a->data.v == clone); + + a = a_find(clone->attribs, &at_clonemage); + if (a==NULL) { + a = a_add(&clone->attribs, a_new(&at_clonemage)); + a->data.v = mage; + } else assert(!a->data.v || a->data.v == mage); +} + +unit * +has_clone(unit *mage) +{ + attrib *a = a_find(mage->attribs, &at_clone); + if(a) return (unit *)a->data.v; + return NULL; +} + +static int +resolve_clone(variant data, void * addr) +{ + unit * clone; + int result = resolve_unit(data, &clone); + if (result==0 && clone) { + 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; +} + +static int +read_clone(attrib * a, void * owner, struct storage * store) +{ + int result = read_reference(&a->data.v, store, read_unit_reference, resolve_clone); + if (result==0 && a->data.v==NULL) { + 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) { + 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; +} + +static int +read_magician(attrib * a, void * owner, struct storage * store) +{ + int result = read_reference(&a->data.v, store, read_unit_reference, resolve_mage); + if (result==0 && a->data.v==NULL) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +static int +age_unit(attrib * a) +/* if unit is gone or dead, remove the attribute */ +{ + unit * u = (unit*)a->data.v; + return (u!=NULL && u->number>0)?AT_AGE_KEEP:AT_AGE_REMOVE; +} + +attrib_type at_familiarmage = { + "familiarmage", + NULL, + NULL, + age_unit, + a_write_unit, + read_magician, + ATF_UNIQUE +}; + +attrib_type at_familiar = { + "familiar", + NULL, + NULL, + age_unit, + a_write_unit, + read_familiar, + ATF_UNIQUE +}; + +attrib_type at_clonemage = { + "clonemage", + NULL, + NULL, + age_unit, + a_write_unit, + read_magician, + ATF_UNIQUE +}; + +attrib_type at_clone = { + "clone", + NULL, + NULL, + age_unit, + a_write_unit, + read_clone, + ATF_UNIQUE +}; + +unit * +get_familiar(const unit *u) +{ + attrib * a = a_find(u->attribs, &at_familiar); + if (a!=NULL) { + unit * u = (unit*)a->data.v; + if (u->number>0) return u; + } + return NULL; +} + +unit * +get_familiar_mage(const unit *u) +{ + attrib * a = a_find(u->attribs, &at_familiarmage); + if (a!=NULL) { + unit * u = (unit*)a->data.v; + if (u->number>0) return u; + } + return NULL; +} + +unit * +get_clone(const unit *u) +{ + attrib * a = a_find(u->attribs, &at_clone); + if (a!=NULL) { + unit * u = (unit*)a->data.v; + if (u->number>0) return u; + } + return NULL; +} + +unit * +get_clone_mage(const unit *u) +{ + attrib * a = a_find(u->attribs, &at_clonemage); + if (a!=NULL) { + unit * u = (unit*)a->data.v; + if (u->number>0) return u; + } + return NULL; +} + +static boolean +is_moving_ship(const region * r, const ship *sh) +{ + const unit *u = shipowner(sh); + + if (u) switch (get_keyword(u->thisorder)) { + case K_ROUTE: + case K_MOVE: + case K_FOLLOW: + return true; + } + return false; +} + +static castorder * +cast_cmd(unit * u, order * ord) +{ + region * r = u->region; + region * target_r = r; + int level, range; + unit *familiar = NULL, *mage = u; + const char * s; + spell * sp; + plane * pl; + spellparameter *args = NULL; + + if (LongHunger(u)) { + cmistake(u, ord, 224, MSG_MAGIC); + return 0; + } + pl = rplane(r); + if (pl && fval(pl, PFL_NOMAGIC)) { + cmistake(u, ord, 269, MSG_MAGIC); + return 0; + } + level = eff_skill(u, SK_MAGIC, r); + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + /* für Syntax ' STUFE x REGION y z ' */ + if (findparam(s, u->faction->locale) == P_LEVEL) { + int p = getint(); + level = MIN(p, level); + if (level < 1) { + /* Fehler "Das macht wenig Sinn" */ + cmistake(u, ord, 10, MSG_MAGIC); + return 0; + } + s = getstrtoken(); + } + if (findparam(s, u->faction->locale) == P_REGION) { + int t_x = getint(); + int t_y = getint(); + plane * pl = getplane(u->region); + t_x = rel_to_abs(pl, u->faction, t_x,0); + t_y = rel_to_abs(pl, u->faction, t_y,1); + pnormalize(&t_x, &t_y, pl); + target_r = findregion(t_x, t_y); + if (!target_r) { + /* Fehler "Die Region konnte nicht verzaubert werden" */ + ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", + "unit region command", mage, mage->region, ord)); + return 0; + } + s = getstrtoken(); + } + /* für Syntax ' REGION x y STUFE z ' + * hier nach REGION nochmal auf STUFE prüfen */ + if (findparam(s, u->faction->locale) == P_LEVEL) { + int p = getint(); + level = MIN(p, level); + if (level < 1) { + /* Fehler "Das macht wenig Sinn" */ + cmistake(u, ord, 10, MSG_MAGIC); + return 0; + } + s = getstrtoken(); + } + if (!s[0] || strlen(s) == 0) { + /* Fehler "Es wurde kein Zauber angegeben" */ + cmistake(u, ord, 172, MSG_MAGIC); + return 0; + } + sp = get_spellfromtoken(u, s, u->faction->locale); + + /* Vertraute können auch Zauber sprechen, die sie selbst nicht + * können. get_spellfromtoken findet aber nur jene Sprüche, die + * die Einheit beherrscht. */ + if (sp == NULL && is_familiar(u)) { + familiar = u; + mage = get_familiar_mage(u); + if (mage!=NULL) sp = get_spellfromtoken(mage, s, mage->faction->locale); + } + + if (sp == NULL) { + /* Fehler 'Spell not found' */ + cmistake(u, ord, 173, MSG_MAGIC); + return 0; + } + /* um testen auf spruchnamen zu unterbinden sollte vor allen + * fehlermeldungen die anzeigen das der magier diesen Spruch + * nur in diese Situation nicht anwenden kann, noch eine + * einfache Sicherheitsprüfung kommen */ + if (!knowsspell(r, u, sp)) { + /* vorsicht! u kann der familiar sein */ + if (!familiar) { + cmistake(u, ord, 173, MSG_MAGIC); + return 0; + } + } + if (sp->sptyp & ISCOMBATSPELL) { + /* Fehler: "Dieser Zauber ist nur im Kampf sinnvoll" */ + cmistake(u, ord, 174, MSG_MAGIC); + return 0; + } + /* Auf dem Ozean Zaubern als quasi-langer Befehl können + * normalerweise nur Meermenschen, ausgenommen explizit als + * OCEANCASTABLE deklarierte Sprüche */ + if (fval(r->terrain, SEA_REGION)) { + if (u->race != new_race[RC_AQUARIAN] + && !fval(u->race, RCF_SWIM) + && !(sp->sptyp & OCEANCASTABLE)) { + /* Fehlermeldung */ + ADDMSG(&u->faction->msgs, msg_message("spellfail_onocean", + "unit region command", u, u->region, ord)); + return 0; + } + /* Auf bewegenden Schiffen kann man nur explizit als + * ONSHIPCAST deklarierte Zauber sprechen */ + } else if (u->ship) { + if (is_moving_ship(r, u->ship)) { + if (!(sp->sptyp & ONSHIPCAST)) { + /* Fehler: "Diesen Spruch kann man nicht auf einem sich + * bewegenden Schiff stehend zaubern" */ + cmistake(u, ord, 175, MSG_MAGIC); + return 0; + } + } + } + /* Farcasting bei nicht farcastbaren Sprüchen abfangen */ + range = farcasting(u, target_r); + if (range > 1) { + if (!(sp->sptyp & FARCASTING)) { + /* Fehler "Diesen Spruch kann man nicht in die Ferne + * richten" */ + cmistake(u, ord, 176, MSG_MAGIC); + return 0; + } + if (range > 1024) { /* (2^10) weiter als 10 Regionen entfernt */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "spellfail::nocontact", + "target", target_r)); + return 0; + } + } + /* Stufenangabe bei nicht Stufenvariierbaren Sprüchen abfangen */ + if (!(sp->sptyp & SPELLLEVEL)) { + int ilevel = eff_skill(u, SK_MAGIC, u->region); + if (ilevel!=level) { + level = ilevel; + ADDMSG(&u->faction->msgs, msg_message("spellfail::nolevel", + "mage region command", u, u->region, ord)); + } + } + /* Vertrautenmagie */ + /* Kennt der Vertraute den Spruch, so zaubert er ganz normal. + * Ansonsten zaubert der Magier durch seinen Vertrauten, dh + * zahlt Komponenten und Aura. Dabei ist die maximale Stufe + * die des Vertrauten! + * Der Spruch wirkt dann auf die Region des Vertrauten und + * gilt nicht als Farcasting. */ + if (familiar || is_familiar(u)) { + if ((sp->sptyp & NOTFAMILIARCAST)) { + /* Fehler: "Diesen Spruch kann der Vertraute nicht zaubern" */ + cmistake(u, ord, 177, MSG_MAGIC); + return 0; + } + if (!knowsspell(r, u, sp)) { /* Magier zaubert durch Vertrauten */ + mage = get_familiar_mage(u); + if (range > 1) { /* Fehler! Versucht zu Farcasten */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_farcast", + "mage", mage)); + return 0; + } + if (distance(mage->region, r) > eff_skill(mage, SK_MAGIC, mage->region)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_toofar", + "mage", mage)); + return 0; + } + /* mage auf magier setzen, level anpassen, range für Erhöhung + * der Spruchkosten nutzen, langen Befehl des Magiers + * löschen, zaubern kann er noch */ + range *= 2; + set_order(&mage->thisorder, NULL); + level = MIN(level, eff_skill(mage, SK_MAGIC, mage->region)/2); + familiar = u; + } + } + /* Weitere Argumente zusammenbasteln */ + if (sp->parameter) { + char ** params = malloc(2*sizeof(char*)); + int p = 0, size = 2; + for (;;) { + s = getstrtoken(); + if (*s==0) break; + if (p+1>=size) { + size*=2; + params = realloc(params, sizeof(char*)*size); + } + params[p++] = strdup(s); + } + params[p] = 0; + args = add_spellparameter(target_r, mage, sp->parameter, (const char * const *)params, p, ord); + for (p=0;params[p];++p) free(params[p]); + free(params); + if (args==NULL) { + /* Syntax war falsch */ + return 0; + } + } + return new_castorder(mage, familiar, sp, target_r, level, 0, range, ord, args); +} + +/* ------------------------------------------------------------- */ +/* Damit man keine Rituale in fremden Gebiet machen kann, diese vor + * Bewegung zaubern. Magier sind also in einem fremden Gebiet eine Runde + * lang verletzlich, da sie es betreten, und angegriffen werden können, + * bevor sie ein Ritual machen können. + * + * Syntax: ZAUBER [REGION X Y] [STUFE ] "Spruchname" [Einheit-1 + * Einheit-2 ..] + * + * Nach Priorität geordnet die Zauber global auswerten. + * + * Die Kosten für Farcasting multiplizieren sich mit der Entfernung, + * cast_level gibt die virtuelle Stufe an, die den durch das Farcasten + * entstandenen Spruchkosten entspricht. Sind die Spruchkosten nicht + * levelabhängig, so sind die Kosten nur von der Entfernung bestimmt, + * die Stärke/Level durch den realen Skill des Magiers + */ + +void +magic(void) +{ + region *r; + int rank; + castorder *co; + spellrank spellranks[MAX_SPELLRANK]; + + memset(spellranks, 0, sizeof(spellranks)); + + for (r = regions; r; r = r->next) { + unit *u; + for (u = r->units; u; u = u->next) { + order * ord; + + if (u->number<=0 || u->race == new_race[RC_SPELL]) + continue; + + if (u->race == new_race[RC_INSECT] && r_insectstalled(r) && + !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) + continue; + + if (fval(u, UFL_WERE|UFL_LONGACTION)) { + continue; + } + + for (ord = u->orders; ord; ord = ord->next) { + if (get_keyword(ord) == K_CAST) { + castorder * co = cast_cmd(u, ord); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + if (co) { + const spell * sp = co->sp; + add_castorder(&spellranks[sp->rank], co); + } + } + } + } + } + + /* Da sich die Aura und Komponenten in der Zwischenzeit verändert + * haben können und sich durch vorherige Sprüche das Zaubern + * erschwert haben kann, muss beim zaubern erneut geprüft werden, ob der + * Spruch überhaupt gezaubert werden kann. + * (level) die effektive Stärke des Spruchs (= Stufe, auf der der + * Spruch gezaubert wird) */ + + for (rank = 0; rank < MAX_SPELLRANK; rank++) { + for (co = spellranks[rank].begin; co; co = co->next) { + order * ord = co->order; + int invalid, resist, success, cast_level = co->level; + boolean fumbled = false; + unit * u = co->magician.u; + const spell *sp = co->sp; + region * target_r = co->rt; + + /* reichen die Komponenten nicht, wird der Level reduziert. */ + co->level = eff_spelllevel(u, sp, cast_level, co->distance); + + if (co->level < 1) { + /* Fehlermeldung mit Komponenten generieren */ + cancast(u, sp, cast_level, co->distance, ord); + continue; + } + + if (cast_level > co->level) { + /* Sprüche mit Fixkosten werden immer auf Stufe des Spruchs + * gezaubert, co->level ist aber defaultmäßig Stufe des Magiers */ + if (spl_costtyp(sp) != SPC_FIX) { + ADDMSG(&u->faction->msgs, msg_message("missing_components", + "unit spell level", u, sp, cast_level)); + } + } + + /* Prüfen, ob die realen Kosten für die gewünschten Stufe bezahlt + * werden können */ + if (cancast(u, sp, co->level, co->distance, ord) == false) { + /* die Fehlermeldung wird in cancast generiert */ + continue; + } + + co->force = spellpower(target_r, u, sp, co->level, ord); + /* die Stärke kann durch Antimagie auf 0 sinken */ + if (co->force <= 0) { + co->force = 0; + ADDMSG(&u->faction->msgs, msg_message("missing_force", + "unit spell level", u, sp, co->level)); + } + + /* Ziele auf Existenz prüfen und Magieresistenz feststellen. Wurde + * kein Ziel gefunden, so ist verify_targets=0. Scheitert der + * Spruch an der Magieresistenz, so ist verify_targets = 1, bei + * Erfolg auf ganzer Linie ist verify_targets= 2 + */ + verify_targets(co, &invalid, &resist, &success); + if (success+resist==0) { + /* kein Ziel gefunden, Fehlermeldungen sind in verify_targets */ + /* keine kosten für den zauber */ + continue; /* äußere Schleife, nächster Zauberer */ + } else if (co->force>0 && resist>0) { + /* einige oder alle Ziele waren magieresistent */ + if (success==0) { + co->force = 0; + /* zwar wurde mindestens ein Ziel gefunden, das widerstand + * jedoch dem Zauber. Kosten abziehen und abbrechen. */ + ADDMSG(&u->faction->msgs, msg_message("spell_resist", "unit region spell", + u, r, sp)); + } + } + + /* Auch für Patzer gibt es Erfahrung, müssen die Spruchkosten + * bezahlt werden und die nachfolgenden Sprüche werden teurer */ + if (co->force>0) { + if (fumble(target_r, u, sp, co->level)) { + /* zuerst bezahlen, dann evt in do_fumble alle Aura verlieren */ + fumbled = true; + } else { + if (sp->sp_function==NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + co->level = 0; + } else { + co->level = ((nspell_f)sp->sp_function)(co); + } + if (co->level <= 0) { + /* Kosten nur für real benötige Stufe berechnen */ + continue; + } + } + } + pay_spell(u, sp, co->level, co->distance); + /* erst bezahlen, dann Kostenzähler erhöhen */ + if (fumbled) do_fumble(co); + countspells(u, 1); + } + } + + /* Sind alle Zauber gesprochen gibts Erfahrung */ + for (r = regions; r; r = r->next) { + unit *u; + for (u = r->units; u; u = u->next) { + if (is_mage(u) && countspells(u, 0) > 0) { + produceexp(u, SK_MAGIC, u->number); + /* Spruchlistenaktualiesierung ist in Regeneration */ + } + } + } + for (rank = 0; rank < MAX_SPELLRANK; rank++) { + free_castorders(spellranks[rank].begin); + } + remove_empty_units(); +} + +const char * +spell_info(const spell * sp, const struct locale * lang) +{ + return LOC(lang, mkname("spellinfo", sp->sname)); +} + +const char * +spell_name(const spell * sp, const struct locale * lang) +{ + return LOC(lang, mkname("spell", sp->sname)); +} + +const char * +curse_name(const curse_type * ctype, const struct locale * lang) +{ + return LOC(lang, mkname("spell", ctype->cname)); +} + +void +spelllist_add(spell_list ** lspells, spell * sp) +{ + spell_list * entry; + + while (*lspells) { + spell_list * slist = *lspells; + if (slist->data->id==sp->id) { + if (slist->data==sp) { + log_error(("trying to add spell '%s' to a list twice.\n", sp->sname)); + return; + } + } + if (slist->data->id>sp->id) break; + lspells = &slist->next; + } + entry = malloc(sizeof(spell_list)); + entry->data = sp; + entry->next = *lspells; + *lspells = entry; +} + +spell_list ** +spelllist_find(spell_list ** lspells, const spell * sp) +{ + while (*lspells) { + spell_list * slist = *lspells; + if (slist->data->id>=sp->id) break; + lspells = &slist->next; + } + return lspells; +} + +extern struct spell_list ** get_spelllist(struct sc_mage * mage, struct faction * f) +{ + if (mage) { + return &mage->spells; + } + return NULL; +} diff --git a/src/kernel/magic.h b/src/kernel/magic.h index 623c5f516..ff91341af 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -1,395 +1,395 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_MAGIC -#define H_KRNL_MAGIC -#ifdef __cplusplus -extern "C" { -#endif - -#include "curse.h" -struct fighter; -struct building; - -/* ------------------------------------------------------------- */ - -#define MAXCOMBATSPELLS 3 /* PRECOMBAT COMBAT POSTCOMBAT */ -#define MAX_SPELLRANK 9 /* Standard-Rank 5 */ -#define MAXINGREDIENT 5 /* bis zu 5 Komponenten pro Zauber */ -#define CHAOSPATZERCHANCE 10 /* +10% Chance zu Patzern */ - -/* ------------------------------------------------------------- */ - -#define IRONGOLEM_CRUMBLE 15 /* monatlich Chance zu zerfallen */ -#define STONEGOLEM_CRUMBLE 10 /* monatlich Chance zu zerfallen */ - -/* ------------------------------------------------------------- */ -/* Spruchparameter - * Wir suchen beim Parsen des Befehls erstmal nach lokalen Objekten, - * erst in verify_targets wird dann global gesucht, da in den meisten - * Fällen das Zielobjekt lokal sein dürfte */ - -/* siehe auch typ_t in objtypes.h */ -typedef enum { - SPP_REGION, /* "r" : findregion(x,y) -> *region */ - SPP_UNIT, /* - : atoi36() -> int */ - SPP_TEMP, /* - : temp einheit */ - SPP_BUILDING, /* - : atoi() -> int */ - SPP_SHIP, /* - : atoi() -> int */ - SPP_STRING, /* "c" */ - SPP_INT, /* "i" : atoi() -> int */ -} sppobj_t; - -typedef struct spllprm{ - sppobj_t typ; - int flag; - union { - struct region *r; - struct unit *u; - struct building *b; - struct ship *sh; - char *s; - char * xs; - int i; - } data; -} spllprm; - -typedef struct spellparameter{ - int length; /* Anzahl der Elemente */ - struct spllprm **param; -} spellparameter; - -typedef struct strarray { - int length; /* Anzahl der Elemente */ - char **strings; -} strarray; - -#define TARGET_RESISTS (1<<0) -#define TARGET_NOTFOUND (1<<1) - -/* ------------------------------------------------------------- */ -/* Magierichtungen */ - -/* typedef unsigned char magic_t; */ -enum { - M_GRAY = 0, /* Gray */ - M_ILLAUN = 1, /* Illaun */ - M_TYBIED = 2, /* Tybied */ - M_CERDDOR = 3, /* Cerddor */ - M_GWYRRD = 4, /* Gwyrrd */ - M_DRAIG = 5, /* Draig */ - M_COMMON = 6, /* common spells */ - MAXMAGIETYP, - /* this enum is stored in the datafile, so do not change the numbers around */ - M_NONE = (magic_t) -1 -}; -extern const char *magic_school[MAXMAGIETYP]; - -/* ------------------------------------------------------------- */ -/* Magier: - * - Magierichtung - * - Magiepunkte derzeit - * - Malus (neg. Wert)/ Bonus (pos. Wert) auf maximale Magiepunkte - * (können sich durch Questen absolut verändern und durch Gegenstände - * temporär). Auch für Artefakt benötigt man permanente MP - * - Anzahl bereits gezauberte Sprüche diese Runde - * - Kampfzauber (3) (vor/während/nach) - * - Spruchliste - */ - -typedef struct combatspell { - int level; - const struct spell * sp; -} combatspell; - -typedef struct sc_mage { - magic_t magietyp; - int spellpoints; - int spchange; - int spellcount; - combatspell combatspells[MAXCOMBATSPELLS]; - struct spell_list * spells; -} sc_mage; - -/* ------------------------------------------------------------- */ -/* Zauberliste */ - -typedef struct castorder { - struct castorder *next; - union { - struct unit * u; - struct fighter * fig; - } magician; /* Magier (kann vom Typ struct unit oder fighter sein) */ - struct unit *familiar; /* Vertrauter, gesetzt, wenn der Spruch durch - den Vertrauten gezaubert wird */ - const struct spell *sp; /* Spruch */ - int level; /* gewünschte Stufe oder Stufe des Magiers */ - double force; /* Stärke des Zaubers */ - struct region *rt; /* Zielregion des Spruchs */ - int distance; /* Entfernung zur Zielregion */ - struct order * order; /* Befehl */ - struct spellparameter *par; /* für weitere Parameter */ -} castorder; - -/* irgendwelche zauber: */ -typedef void (*spell_f) (void*); -/* normale zauber: */ -typedef int (*nspell_f)(castorder*); -/* kampfzauber: */ -typedef int (*cspell_f) (struct fighter*, int, double, const struct spell * sp); -/* zauber-patzer: */ -typedef void (*pspell_f) (castorder *); - -typedef struct spell_component { - const struct resource_type * type; - int amount; - int cost; -} spell_component; - -typedef struct spell { - spellid_t id; - char *sname; - char *syntax; - char *parameter; - magic_t magietyp; - int sptyp; - int rank; /* Reihenfolge der Zauber */ - int level; /* Stufe des Zaubers */ - struct spell_component * components; - spell_f sp_function; - void (*patzer) (castorder*); -} spell; - -typedef struct spell_list { - struct spell_list * next; - spell * data; /* TODO: should be const */ -} spell_list; - -extern void spelllist_add(spell_list ** lspells, struct spell * sp); -extern spell_list ** spelllist_find(spell_list ** lspells, const struct spell * sp); -/* ------------------------------------------------------------- */ - -/* besondere Spruchtypen */ -#define FARCASTING (1<<0) /* ZAUBER [struct region x y] */ -#define SPELLLEVEL (1<<1) /* ZAUBER [STUFE x] */ - -/* ID's können zu drei unterschiedlichen Entitäten gehören: Einheiten, - * Gebäuden und Schiffen. */ -#define UNITSPELL (1<<2) /* ZAUBER .. [ ..] */ -#define SHIPSPELL (1<<3) /* ZAUBER .. [ ..] */ -#define BUILDINGSPELL (1<<4) /* ZAUBER .. [ ..] */ -#define REGIONSPELL (1<<5) /* wirkt auf struct region */ - -#define PRECOMBATSPELL (1<<7) /* PRÄKAMPFZAUBER .. */ -#define COMBATSPELL (1<<8) /* KAMPFZAUBER .. */ -#define POSTCOMBATSPELL (1<<9) /* POSTKAMPFZAUBER .. */ -#define ISCOMBATSPELL (PRECOMBATSPELL|COMBATSPELL|POSTCOMBATSPELL) - -#define OCEANCASTABLE (1<<10) /* Können auch nicht-Meermenschen auf - hoher See zaubern */ -#define ONSHIPCAST (1<<11) /* kann auch auf von Land ablegenden - Schiffen stehend gezaubert werden */ -/* */ -#define NOTFAMILIARCAST (1<<12) -#define TESTRESISTANCE (1<<13) /* alle Zielobjekte (u, s, b, r) auf - Magieresistenz prüfen */ -#define SEARCHLOCAL (1<<14) /* Ziel muss in der target_region sein */ -#define TESTCANSEE (1<<15) /* alle Zielunits auf cansee prüfen */ -#define ANYTARGET (UNITSPELL|REGIONSPELL|BUILDINGSPELL|SHIPSPELL) /* wirkt auf alle objekttypen (unit, ship, building, region) */ - -/* Flag Spruchkostenberechnung: */ -enum{ - SPC_FIX, /* Fixkosten */ - SPC_LEVEL, /* Komponenten pro Level */ - SPC_LINEAR /* Komponenten pro Level und müssen vorhanden sein */ -}; - -enum { - RS_DUMMY, - RS_FARVISION, - MAX_REGIONSPELLS -}; - -/* ------------------------------------------------------------- */ -/* Prototypen */ - -void magic(void); - -void regeneration_magiepunkte(void); - -extern struct attrib_type at_seenspell; -extern struct attrib_type at_mage; -extern struct attrib_type at_familiarmage; -extern struct attrib_type at_familiar; -extern struct attrib_type at_clonemage; -extern struct attrib_type at_clone; -extern struct attrib_type at_reportspell; -extern struct attrib_type at_icastle; - -typedef struct icastle_data { - const struct building_type * type; - struct building * building; /* reverse pointer to dissolve the object */ - int time; -} icastle_data; - - -/* ------------------------------------------------------------- */ -/* Kommentare: - * - * Spruchzauberrei und Gegenstandszauberrei werden getrennt behandelt. - * Das macht u.a. bestimmte Fehlermeldungen einfacher, das - * identifizieren der Komponennten über den Missversuch ist nicht - * möglich - * Spruchzauberrei: 'ZAUBER [struct region x y] [STUFE a] "Spruchname" [Ziel]' - * Gegenstandszauberrei: 'BENUTZE "Gegenstand" [Ziel]' - * - * Die Funktionen: - */ - -/* Magier */ -sc_mage * create_mage(struct unit *u, magic_t mtyp); - /* macht die struct unit zu einem neuen Magier: legt die struct u->mage an - * und initialisiert den Magiertypus mit mtyp. */ -sc_mage * get_mage(const struct unit *u); - /* gibt u->mage zurück, bei nicht-Magiern *NULL */ -boolean is_mage(const struct unit *u); - /* gibt true, wenn u->mage gesetzt. */ -boolean is_familiar(const struct unit *u); - /* gibt true, wenn eine Familiar-Relation besteht. */ - -/* Sprüche */ -int get_combatspelllevel(const struct unit *u, int nr); - /* versucht, eine eingestellte maximale Kampfzauberstufe - * zurückzugeben. 0 = Maximum, -1 u ist kein Magier. */ -const spell *get_combatspell(const struct unit *u, int nr); - /* gibt den Kampfzauber nr [pre/kampf/post] oder NULL zurück */ -void set_combatspell(struct unit *u, spell *sp, struct order * ord, int level); - /* setzt Kampfzauber */ -void unset_combatspell(struct unit *u, spell *sp); - /* löscht Kampfzauber */ -void add_spell(spell_list ** slistp, spell *sp); - /* fügt den Spruch mit der Id spellid der Spruchliste der Einheit hinzu. */ -boolean has_spell(struct spell_list *slist, const struct spell * sp); - /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ -boolean u_hasspell(const struct unit * u, const struct spell * sp); - /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ -void update_spellbook(struct faction * f, int level); -void updatespelllist(struct unit *u); - /* fügt alle Zauber des Magiegebietes der Einheit, deren Stufe kleiner - * als das aktuelle Magietalent ist, in die Spruchliste der Einheit - * ein */ -boolean knowsspell(const struct region * r, const struct unit * u, const spell * sp); - /* prüft, ob die Einheit diesen Spruch gerade beherrscht, dh - * mindestens die erforderliche Stufe hat. Hier können auch Abfragen - * auf spezielle Antimagiezauber auf Regionen oder Einheiten eingefügt - * werden - */ - - -/* Magiepunkte */ -int get_spellpoints(const struct unit *u); - /* Gibt die aktuelle Anzahl der Magiepunkte der Einheit zurück */ -void set_spellpoints(struct unit * u, int sp); - /* setzt die Magiepunkte auf sp */ -int change_spellpoints(struct unit *u, int mp); - /* verändert die Anzahl der Magiepunkte der Einheit um +mp */ -int max_spellpoints(const struct region *r, const struct unit *u); - /* gibt die aktuell maximal möglichen Magiepunkte der Einheit zurück */ -int change_maxspellpoints(struct unit * u, int csp); - /* verändert die maximalen Magiepunkte einer Einheit */ - -/* Zaubern */ -extern double spellpower(struct region *r, struct unit *u, const spell *sp, int cast_level, struct order * ord); - /* ermittelt die Stärke eines Spruchs */ -boolean fumble (struct region *r, struct unit *u, const spell *sp, int cast_level); - /* true, wenn der Zauber misslingt, bei false gelingt der Zauber */ - - -typedef struct spellrank { - struct castorder * begin; - struct castorder ** end; -} spellrank; - -castorder *new_castorder(void *u, struct unit *familiar, const spell *sp, struct region *r, - int lev, double force, int distance, struct order * ord, spellparameter *p); - /* Zwischenspreicher für Zauberbefehle, notwendig für Prioritäten */ -void add_castorder(struct spellrank *cll, struct castorder *co); - /* Hänge c-order co an die letze c-order von cll an */ -void free_castorders(struct castorder *co); - /* Speicher wieder freigeben */ - -/* Prüfroutinen für Zaubern */ -int countspells(struct unit *u, int step); - /* erhöht den Counter für Zaubersprüche um 'step' und gibt die neue - * Anzahl der gezauberten Sprüche zurück. */ -int spellcost(struct unit *u, const spell *sp); - /* gibt die für diesen Spruch derzeit notwendigen Magiepunkte auf der - * geringstmöglichen Stufe zurück, schon um den Faktor der bereits - * zuvor gezauberten Sprüche erhöht */ -boolean cancast (struct unit *u, const spell *spruch, int eff_stufe, int distance, struct order * ord); - /* true, wenn Einheit alle Komponenten des Zaubers (incl. MP) für die - * geringstmögliche Stufe hat und den Spruch beherrscht */ -void pay_spell(struct unit *u, const spell *sp, int eff_stufe, int distance); - /* zieht die Komponenten des Zaubers aus dem Inventory der Einheit - * ab. Die effektive Stufe des gezauberten Spruchs ist wichtig für - * die korrekte Bestimmung der Magiepunktkosten */ -int eff_spelllevel(struct unit *u, const spell * sp, int cast_level, int distance); - /* ermittelt die effektive Stufe des Zaubers. Dabei ist cast_level - * die gewünschte maximale Stufe (im Normalfall Stufe des Magiers, - * bei Farcasting Stufe*2^Entfernung) */ -boolean is_magic_resistant(struct unit *magician, struct unit *target, int - resist_bonus); - /* Mapperfunktion für target_resists_magic() vom Typ struct unit. */ -extern double magic_resistance(struct unit *target); - /* gibt die Chance an, mit der einem Zauber widerstanden wird. Je - * größer, desto resistenter ist da Opfer */ -boolean target_resists_magic(struct unit *magician, void *obj, int objtyp, - int resist_bonus); - /* gibt false zurück, wenn der Zauber gelingt, true, wenn das Ziel - * widersteht */ - - -/* 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 boolean 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); - -extern const char * spell_info(const struct spell * sp, const struct locale * lang); -extern const char * spell_name(const struct spell * sp, const struct locale * lang); -extern const char * curse_name(const struct curse_type * ctype, const struct locale * lang); - -extern struct message * msg_unitnotfound(const struct unit * mage, struct order * ord, const struct spllprm * spobj); -extern int FactionSpells(void); -extern struct spell_list ** get_spelllist(struct sc_mage * mage, struct faction * f); - -extern void write_spelllist(const struct spell_list * slist, struct storage * store); -extern void read_spellist(struct spell_list ** slistp, magic_t mtype, struct storage * store); -extern double MagicPower(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_MAGIC +#define H_KRNL_MAGIC +#ifdef __cplusplus +extern "C" { +#endif + +#include "curse.h" +struct fighter; +struct building; + +/* ------------------------------------------------------------- */ + +#define MAXCOMBATSPELLS 3 /* PRECOMBAT COMBAT POSTCOMBAT */ +#define MAX_SPELLRANK 9 /* Standard-Rank 5 */ +#define MAXINGREDIENT 5 /* bis zu 5 Komponenten pro Zauber */ +#define CHAOSPATZERCHANCE 10 /* +10% Chance zu Patzern */ + +/* ------------------------------------------------------------- */ + +#define IRONGOLEM_CRUMBLE 15 /* monatlich Chance zu zerfallen */ +#define STONEGOLEM_CRUMBLE 10 /* monatlich Chance zu zerfallen */ + +/* ------------------------------------------------------------- */ +/* Spruchparameter + * Wir suchen beim Parsen des Befehls erstmal nach lokalen Objekten, + * erst in verify_targets wird dann global gesucht, da in den meisten + * Fällen das Zielobjekt lokal sein dürfte */ + +/* siehe auch typ_t in objtypes.h */ +typedef enum { + SPP_REGION, /* "r" : findregion(x,y) -> *region */ + SPP_UNIT, /* - : atoi36() -> int */ + SPP_TEMP, /* - : temp einheit */ + SPP_BUILDING, /* - : atoi() -> int */ + SPP_SHIP, /* - : atoi() -> int */ + SPP_STRING, /* "c" */ + SPP_INT, /* "i" : atoi() -> int */ +} sppobj_t; + +typedef struct spllprm{ + sppobj_t typ; + int flag; + union { + struct region *r; + struct unit *u; + struct building *b; + struct ship *sh; + char *s; + char * xs; + int i; + } data; +} spllprm; + +typedef struct spellparameter{ + int length; /* Anzahl der Elemente */ + struct spllprm **param; +} spellparameter; + +typedef struct strarray { + int length; /* Anzahl der Elemente */ + char **strings; +} strarray; + +#define TARGET_RESISTS (1<<0) +#define TARGET_NOTFOUND (1<<1) + +/* ------------------------------------------------------------- */ +/* Magierichtungen */ + +/* typedef unsigned char magic_t; */ +enum { + M_GRAY = 0, /* Gray */ + M_ILLAUN = 1, /* Illaun */ + M_TYBIED = 2, /* Tybied */ + M_CERDDOR = 3, /* Cerddor */ + M_GWYRRD = 4, /* Gwyrrd */ + M_DRAIG = 5, /* Draig */ + M_COMMON = 6, /* common spells */ + MAXMAGIETYP, + /* this enum is stored in the datafile, so do not change the numbers around */ + M_NONE = (magic_t) -1 +}; +extern const char *magic_school[MAXMAGIETYP]; + +/* ------------------------------------------------------------- */ +/* Magier: + * - Magierichtung + * - Magiepunkte derzeit + * - Malus (neg. Wert)/ Bonus (pos. Wert) auf maximale Magiepunkte + * (können sich durch Questen absolut verändern und durch Gegenstände + * temporär). Auch für Artefakt benötigt man permanente MP + * - Anzahl bereits gezauberte Sprüche diese Runde + * - Kampfzauber (3) (vor/während/nach) + * - Spruchliste + */ + +typedef struct combatspell { + int level; + const struct spell * sp; +} combatspell; + +typedef struct sc_mage { + magic_t magietyp; + int spellpoints; + int spchange; + int spellcount; + combatspell combatspells[MAXCOMBATSPELLS]; + struct spell_list * spells; +} sc_mage; + +/* ------------------------------------------------------------- */ +/* Zauberliste */ + +typedef struct castorder { + struct castorder *next; + union { + struct unit * u; + struct fighter * fig; + } magician; /* Magier (kann vom Typ struct unit oder fighter sein) */ + struct unit *familiar; /* Vertrauter, gesetzt, wenn der Spruch durch + den Vertrauten gezaubert wird */ + const struct spell *sp; /* Spruch */ + int level; /* gewünschte Stufe oder Stufe des Magiers */ + double force; /* Stärke des Zaubers */ + struct region *rt; /* Zielregion des Spruchs */ + int distance; /* Entfernung zur Zielregion */ + struct order * order; /* Befehl */ + struct spellparameter *par; /* für weitere Parameter */ +} castorder; + +/* irgendwelche zauber: */ +typedef void (*spell_f) (void*); +/* normale zauber: */ +typedef int (*nspell_f)(castorder*); +/* kampfzauber: */ +typedef int (*cspell_f) (struct fighter*, int, double, const struct spell * sp); +/* zauber-patzer: */ +typedef void (*pspell_f) (castorder *); + +typedef struct spell_component { + const struct resource_type * type; + int amount; + int cost; +} spell_component; + +typedef struct spell { + spellid_t id; + char *sname; + char *syntax; + char *parameter; + magic_t magietyp; + int sptyp; + int rank; /* Reihenfolge der Zauber */ + int level; /* Stufe des Zaubers */ + struct spell_component * components; + spell_f sp_function; + void (*patzer) (castorder*); +} spell; + +typedef struct spell_list { + struct spell_list * next; + spell * data; /* TODO: should be const */ +} spell_list; + +extern void spelllist_add(spell_list ** lspells, struct spell * sp); +extern spell_list ** spelllist_find(spell_list ** lspells, const struct spell * sp); +/* ------------------------------------------------------------- */ + +/* besondere Spruchtypen */ +#define FARCASTING (1<<0) /* ZAUBER [struct region x y] */ +#define SPELLLEVEL (1<<1) /* ZAUBER [STUFE x] */ + +/* ID's können zu drei unterschiedlichen Entitäten gehören: Einheiten, + * Gebäuden und Schiffen. */ +#define UNITSPELL (1<<2) /* ZAUBER .. [ ..] */ +#define SHIPSPELL (1<<3) /* ZAUBER .. [ ..] */ +#define BUILDINGSPELL (1<<4) /* ZAUBER .. [ ..] */ +#define REGIONSPELL (1<<5) /* wirkt auf struct region */ + +#define PRECOMBATSPELL (1<<7) /* PRÄKAMPFZAUBER .. */ +#define COMBATSPELL (1<<8) /* KAMPFZAUBER .. */ +#define POSTCOMBATSPELL (1<<9) /* POSTKAMPFZAUBER .. */ +#define ISCOMBATSPELL (PRECOMBATSPELL|COMBATSPELL|POSTCOMBATSPELL) + +#define OCEANCASTABLE (1<<10) /* Können auch nicht-Meermenschen auf + hoher See zaubern */ +#define ONSHIPCAST (1<<11) /* kann auch auf von Land ablegenden + Schiffen stehend gezaubert werden */ +/* */ +#define NOTFAMILIARCAST (1<<12) +#define TESTRESISTANCE (1<<13) /* alle Zielobjekte (u, s, b, r) auf + Magieresistenz prüfen */ +#define SEARCHLOCAL (1<<14) /* Ziel muss in der target_region sein */ +#define TESTCANSEE (1<<15) /* alle Zielunits auf cansee prüfen */ +#define ANYTARGET (UNITSPELL|REGIONSPELL|BUILDINGSPELL|SHIPSPELL) /* wirkt auf alle objekttypen (unit, ship, building, region) */ + +/* Flag Spruchkostenberechnung: */ +enum{ + SPC_FIX, /* Fixkosten */ + SPC_LEVEL, /* Komponenten pro Level */ + SPC_LINEAR /* Komponenten pro Level und müssen vorhanden sein */ +}; + +enum { + RS_DUMMY, + RS_FARVISION, + MAX_REGIONSPELLS +}; + +/* ------------------------------------------------------------- */ +/* Prototypen */ + +void magic(void); + +void regeneration_magiepunkte(void); + +extern struct attrib_type at_seenspell; +extern struct attrib_type at_mage; +extern struct attrib_type at_familiarmage; +extern struct attrib_type at_familiar; +extern struct attrib_type at_clonemage; +extern struct attrib_type at_clone; +extern struct attrib_type at_reportspell; +extern struct attrib_type at_icastle; + +typedef struct icastle_data { + const struct building_type * type; + struct building * building; /* reverse pointer to dissolve the object */ + int time; +} icastle_data; + + +/* ------------------------------------------------------------- */ +/* Kommentare: + * + * Spruchzauberrei und Gegenstandszauberrei werden getrennt behandelt. + * Das macht u.a. bestimmte Fehlermeldungen einfacher, das + * identifizieren der Komponennten über den Missversuch ist nicht + * möglich + * Spruchzauberrei: 'ZAUBER [struct region x y] [STUFE a] "Spruchname" [Ziel]' + * Gegenstandszauberrei: 'BENUTZE "Gegenstand" [Ziel]' + * + * Die Funktionen: + */ + +/* Magier */ +sc_mage * create_mage(struct unit *u, magic_t mtyp); + /* macht die struct unit zu einem neuen Magier: legt die struct u->mage an + * und initialisiert den Magiertypus mit mtyp. */ +sc_mage * get_mage(const struct unit *u); + /* gibt u->mage zurück, bei nicht-Magiern *NULL */ +boolean is_mage(const struct unit *u); + /* gibt true, wenn u->mage gesetzt. */ +boolean is_familiar(const struct unit *u); + /* gibt true, wenn eine Familiar-Relation besteht. */ + +/* Sprüche */ +int get_combatspelllevel(const struct unit *u, int nr); + /* versucht, eine eingestellte maximale Kampfzauberstufe + * zurückzugeben. 0 = Maximum, -1 u ist kein Magier. */ +const spell *get_combatspell(const struct unit *u, int nr); + /* gibt den Kampfzauber nr [pre/kampf/post] oder NULL zurück */ +void set_combatspell(struct unit *u, spell *sp, struct order * ord, int level); + /* setzt Kampfzauber */ +void unset_combatspell(struct unit *u, spell *sp); + /* löscht Kampfzauber */ +void add_spell(spell_list ** slistp, spell *sp); + /* fügt den Spruch mit der Id spellid der Spruchliste der Einheit hinzu. */ +boolean has_spell(struct spell_list *slist, const struct spell * sp); + /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ +boolean u_hasspell(const struct unit * u, const struct spell * sp); + /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ +void update_spellbook(struct faction * f, int level); +void updatespelllist(struct unit *u); + /* fügt alle Zauber des Magiegebietes der Einheit, deren Stufe kleiner + * als das aktuelle Magietalent ist, in die Spruchliste der Einheit + * ein */ +boolean knowsspell(const struct region * r, const struct unit * u, const spell * sp); + /* prüft, ob die Einheit diesen Spruch gerade beherrscht, dh + * mindestens die erforderliche Stufe hat. Hier können auch Abfragen + * auf spezielle Antimagiezauber auf Regionen oder Einheiten eingefügt + * werden + */ + + +/* Magiepunkte */ +int get_spellpoints(const struct unit *u); + /* Gibt die aktuelle Anzahl der Magiepunkte der Einheit zurück */ +void set_spellpoints(struct unit * u, int sp); + /* setzt die Magiepunkte auf sp */ +int change_spellpoints(struct unit *u, int mp); + /* verändert die Anzahl der Magiepunkte der Einheit um +mp */ +int max_spellpoints(const struct region *r, const struct unit *u); + /* gibt die aktuell maximal möglichen Magiepunkte der Einheit zurück */ +int change_maxspellpoints(struct unit * u, int csp); + /* verändert die maximalen Magiepunkte einer Einheit */ + +/* Zaubern */ +extern double spellpower(struct region *r, struct unit *u, const spell *sp, int cast_level, struct order * ord); + /* ermittelt die Stärke eines Spruchs */ +boolean fumble (struct region *r, struct unit *u, const spell *sp, int cast_level); + /* true, wenn der Zauber misslingt, bei false gelingt der Zauber */ + + +typedef struct spellrank { + struct castorder * begin; + struct castorder ** end; +} spellrank; + +castorder *new_castorder(void *u, struct unit *familiar, const spell *sp, struct region *r, + int lev, double force, int distance, struct order * ord, spellparameter *p); + /* Zwischenspreicher für Zauberbefehle, notwendig für Prioritäten */ +void add_castorder(struct spellrank *cll, struct castorder *co); + /* Hänge c-order co an die letze c-order von cll an */ +void free_castorders(struct castorder *co); + /* Speicher wieder freigeben */ + +/* Prüfroutinen für Zaubern */ +int countspells(struct unit *u, int step); + /* erhöht den Counter für Zaubersprüche um 'step' und gibt die neue + * Anzahl der gezauberten Sprüche zurück. */ +int spellcost(struct unit *u, const spell *sp); + /* gibt die für diesen Spruch derzeit notwendigen Magiepunkte auf der + * geringstmöglichen Stufe zurück, schon um den Faktor der bereits + * zuvor gezauberten Sprüche erhöht */ +boolean cancast (struct unit *u, const spell *spruch, int eff_stufe, int distance, struct order * ord); + /* true, wenn Einheit alle Komponenten des Zaubers (incl. MP) für die + * geringstmögliche Stufe hat und den Spruch beherrscht */ +void pay_spell(struct unit *u, const spell *sp, int eff_stufe, int distance); + /* zieht die Komponenten des Zaubers aus dem Inventory der Einheit + * ab. Die effektive Stufe des gezauberten Spruchs ist wichtig für + * die korrekte Bestimmung der Magiepunktkosten */ +int eff_spelllevel(struct unit *u, const spell * sp, int cast_level, int distance); + /* ermittelt die effektive Stufe des Zaubers. Dabei ist cast_level + * die gewünschte maximale Stufe (im Normalfall Stufe des Magiers, + * bei Farcasting Stufe*2^Entfernung) */ +boolean is_magic_resistant(struct unit *magician, struct unit *target, int + resist_bonus); + /* Mapperfunktion für target_resists_magic() vom Typ struct unit. */ +extern double magic_resistance(struct unit *target); + /* gibt die Chance an, mit der einem Zauber widerstanden wird. Je + * größer, desto resistenter ist da Opfer */ +boolean target_resists_magic(struct unit *magician, void *obj, int objtyp, + int resist_bonus); + /* gibt false zurück, wenn der Zauber gelingt, true, wenn das Ziel + * widersteht */ + + +/* 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 boolean 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); + +extern const char * spell_info(const struct spell * sp, const struct locale * lang); +extern const char * spell_name(const struct spell * sp, const struct locale * lang); +extern const char * curse_name(const struct curse_type * ctype, const struct locale * lang); + +extern struct message * msg_unitnotfound(const struct unit * mage, struct order * ord, const struct spllprm * spobj); +extern int FactionSpells(void); +extern struct spell_list ** get_spelllist(struct sc_mage * mage, struct faction * f); + +extern void write_spelllist(const struct spell_list * slist, struct storage * store); +extern void read_spellist(struct spell_list ** slistp, magic_t mtype, struct storage * store); +extern double MagicPower(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/message.c b/src/kernel/message.c index 67ccadfa3..77a892b72 100644 --- a/src/kernel/message.c +++ b/src/kernel/message.c @@ -1,283 +1,283 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "message.h" - -/* kernel includes */ -#include "building.h" -#include "faction.h" -#include "item.h" -#include "order.h" -#include "plane.h" -#include "region.h" -#include "unit.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include - -typedef struct msg_setting { - struct msg_setting *next; - const struct message_type *type; - int level; -} msg_setting; - -/************ Compatibility function *************/ -#define MAXSTRLEN (4*DISPLAYSIZE+3) -#include "region.h" -#include - -static void -arg_set(variant args[], const message_type * mtype, const char * buffer, variant v) -{ - int i; - for (i=0;i!=mtype->nparameters;++i) { - if (!strcmp(buffer, mtype->pnames[i])) break; - } - if (i!=mtype->nparameters) { - args[i] = v; - } else { - fprintf(stderr, "invalid parameter %s for message type %s\n", buffer, mtype->name); - assert(!"program aborted."); - } -} - -struct message * -msg_feedback(const struct unit * u, struct order * ord, const char * name, const char* sig, ...) -{ - va_list marker; - const message_type * mtype = mt_find(name); - char paramname[64]; - const char *ic = sig; - variant args[16]; - variant var; - memset(args, 0, sizeof(args)); - - if (ord==NULL) ord = u->thisorder; - - if (!mtype) { - log_error(("trying to create message of unknown type \"%s\"\n", name)); - return msg_message("missing_feedback", "unit region command name", u, u->region, ord, name); - } - - var.v = (void*)u; - arg_set(args, mtype, "unit", var); - var.v = (void*)u->region; - arg_set(args, mtype, "region", var); - var.v = (void*)ord; - arg_set(args, mtype, "command", var); - - va_start(marker, sig); - while (*ic && !isalnum(*ic)) ic++; - while (*ic) { - char * oc = paramname; - int i; - - while (isalnum(*ic)) *oc++ = *ic++; - *oc = '\0'; - - for (i=0;i!=mtype->nparameters;++i) { - if (!strcmp(paramname, mtype->pnames[i])) break; - } - if (i!=mtype->nparameters) { - if (mtype->types[i]->vtype==VAR_VOIDPTR) { - args[i].v = va_arg(marker, void*); - } else if (mtype->types[i]->vtype==VAR_INT) { - args[i].i = va_arg(marker, int); - } else { - assert(!"unknown variant type"); - } - } else { - log_error(("invalid parameter %s for message type %s\n", paramname, mtype->name)); - assert(!"program aborted."); - } - while (*ic && !isalnum(*ic)) ic++; - } - va_end(marker); - - return msg_create(mtype, args); -} - -message * -msg_message(const char * name, const char* sig, ...) - /* msg_message("oops_error", "unit region command", u, r, cmd) */ -{ - va_list marker; - const message_type * mtype = mt_find(name); - char paramname[64]; - const char *ic = sig; - variant args[16]; - memset(args, 0, sizeof(args)); - - if (!mtype) { - log_error(("trying to create message of unknown type \"%s\"\n", name)); - if (strcmp(name, "missing_message")!=0) { - return msg_message("missing_message", "name", name); - } - return NULL; - } - - va_start(marker, sig); - while (*ic && !isalnum(*ic)) ic++; - while (*ic) { - char * oc = paramname; - int i; - - while (isalnum(*ic)) *oc++ = *ic++; - *oc = '\0'; - - for (i=0;i!=mtype->nparameters;++i) { - if (!strcmp(paramname, mtype->pnames[i])) break; - } - if (i!=mtype->nparameters) { - if (mtype->types[i]->vtype==VAR_VOIDPTR) { - args[i].v = va_arg(marker, void*); - } else if (mtype->types[i]->vtype==VAR_INT) { - args[i].i = va_arg(marker, int); - } else { - assert(!"unknown variant type"); - } - } else { - log_error(("invalid parameter %s for message type %s\n", paramname, mtype->name)); - assert(!"program aborted."); - } - while (*ic && !isalnum(*ic)) ic++; - } - va_end(marker); - - return msg_create(mtype, args); -} - -static void -caddmessage(region * r, faction * f, const char *s, msg_t mtype, int level) -{ - message * m = NULL; - -#define LOG_ENGLISH -#ifdef LOG_ENGLISH - if (f && f->locale!=default_locale) { - log_warning(("message for locale \"%s\": %s\n", locale_name(f->locale), s)); - } -#endif - unused(level); - switch (mtype) { - case MSG_INCOME: - assert(f); - m = add_message(&f->msgs, msg_message("msg_economy", "string", s)); - break; - case MSG_BATTLE: - assert(0 || !"battle-meldungen nicht über addmessage machen"); - break; - case MSG_MOVE: - assert(f); - m = add_message(&f->msgs, msg_message("msg_movement", "string", s)); - break; - case MSG_COMMERCE: - assert(f); - m = add_message(&f->msgs, msg_message("msg_economy", "string", s)); - break; - case MSG_PRODUCE: - assert(f); - m = add_message(&f->msgs, msg_message("msg_production", "string", s)); - break; - case MSG_MAGIC: - case MSG_COMMENT: - case MSG_MESSAGE: - case MSG_ORCVERMEHRUNG: - case MSG_EVENT: - /* Botschaften an REGION oder einzelne PARTEI */ - m = msg_message("msg_event", "string", s); - if (!r) { - assert(f); - m = add_message(&f->msgs, m); - } else { - if (f==NULL) add_message(&r->msgs, m); - else r_addmessage(r, f, m); - } - break; - default: - assert(!"Ungültige Msg-Klasse!"); - } - if (m) msg_release(m); -} - -void -addmessage(region * r, faction * f, const char *s, msg_t mtype, int level) -{ - caddmessage(r, f, s, mtype, level); -} - -void -cmistake(const unit * u, struct order *ord, int mno, int mtype) -{ - static char msgname[20]; - unused(mtype); - - if (is_monsters(u->faction)) return; - sprintf(msgname, "error%d", mno); - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, msgname, "")); -} - -extern unsigned int new_hashstring(const char* s); - -void -free_messagelist(message_list * msgs) -{ - struct mlist ** mlistptr = &msgs->begin; - while (*mlistptr) { - struct mlist * ml = *mlistptr; - *mlistptr = ml->next; - msg_release(ml->msg); - free(ml); - } - free(msgs); -} - -message * -add_message(message_list** pm, message * m) -{ - if (!lomem && m!=NULL) { - struct mlist * mnew = malloc(sizeof(struct mlist)); - if (*pm==NULL) { - *pm = malloc(sizeof(message_list)); - (*pm)->end=&(*pm)->begin; - } - mnew->msg = msg_addref(m); - mnew->next = NULL; - *((*pm)->end) = mnew; - (*pm)->end=&mnew->next; - } - return m; -} - - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "message.h" + +/* kernel includes */ +#include "building.h" +#include "faction.h" +#include "item.h" +#include "order.h" +#include "plane.h" +#include "region.h" +#include "unit.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include + +typedef struct msg_setting { + struct msg_setting *next; + const struct message_type *type; + int level; +} msg_setting; + +/************ Compatibility function *************/ +#define MAXSTRLEN (4*DISPLAYSIZE+3) +#include "region.h" +#include + +static void +arg_set(variant args[], const message_type * mtype, const char * buffer, variant v) +{ + int i; + for (i=0;i!=mtype->nparameters;++i) { + if (!strcmp(buffer, mtype->pnames[i])) break; + } + if (i!=mtype->nparameters) { + args[i] = v; + } else { + fprintf(stderr, "invalid parameter %s for message type %s\n", buffer, mtype->name); + assert(!"program aborted."); + } +} + +struct message * +msg_feedback(const struct unit * u, struct order * ord, const char * name, const char* sig, ...) +{ + va_list marker; + const message_type * mtype = mt_find(name); + char paramname[64]; + const char *ic = sig; + variant args[16]; + variant var; + memset(args, 0, sizeof(args)); + + if (ord==NULL) ord = u->thisorder; + + if (!mtype) { + log_error(("trying to create message of unknown type \"%s\"\n", name)); + return msg_message("missing_feedback", "unit region command name", u, u->region, ord, name); + } + + var.v = (void*)u; + arg_set(args, mtype, "unit", var); + var.v = (void*)u->region; + arg_set(args, mtype, "region", var); + var.v = (void*)ord; + arg_set(args, mtype, "command", var); + + va_start(marker, sig); + while (*ic && !isalnum(*ic)) ic++; + while (*ic) { + char * oc = paramname; + int i; + + while (isalnum(*ic)) *oc++ = *ic++; + *oc = '\0'; + + for (i=0;i!=mtype->nparameters;++i) { + if (!strcmp(paramname, mtype->pnames[i])) break; + } + if (i!=mtype->nparameters) { + if (mtype->types[i]->vtype==VAR_VOIDPTR) { + args[i].v = va_arg(marker, void*); + } else if (mtype->types[i]->vtype==VAR_INT) { + args[i].i = va_arg(marker, int); + } else { + assert(!"unknown variant type"); + } + } else { + log_error(("invalid parameter %s for message type %s\n", paramname, mtype->name)); + assert(!"program aborted."); + } + while (*ic && !isalnum(*ic)) ic++; + } + va_end(marker); + + return msg_create(mtype, args); +} + +message * +msg_message(const char * name, const char* sig, ...) + /* msg_message("oops_error", "unit region command", u, r, cmd) */ +{ + va_list marker; + const message_type * mtype = mt_find(name); + char paramname[64]; + const char *ic = sig; + variant args[16]; + memset(args, 0, sizeof(args)); + + if (!mtype) { + log_error(("trying to create message of unknown type \"%s\"\n", name)); + if (strcmp(name, "missing_message")!=0) { + return msg_message("missing_message", "name", name); + } + return NULL; + } + + va_start(marker, sig); + while (*ic && !isalnum(*ic)) ic++; + while (*ic) { + char * oc = paramname; + int i; + + while (isalnum(*ic)) *oc++ = *ic++; + *oc = '\0'; + + for (i=0;i!=mtype->nparameters;++i) { + if (!strcmp(paramname, mtype->pnames[i])) break; + } + if (i!=mtype->nparameters) { + if (mtype->types[i]->vtype==VAR_VOIDPTR) { + args[i].v = va_arg(marker, void*); + } else if (mtype->types[i]->vtype==VAR_INT) { + args[i].i = va_arg(marker, int); + } else { + assert(!"unknown variant type"); + } + } else { + log_error(("invalid parameter %s for message type %s\n", paramname, mtype->name)); + assert(!"program aborted."); + } + while (*ic && !isalnum(*ic)) ic++; + } + va_end(marker); + + return msg_create(mtype, args); +} + +static void +caddmessage(region * r, faction * f, const char *s, msg_t mtype, int level) +{ + message * m = NULL; + +#define LOG_ENGLISH +#ifdef LOG_ENGLISH + if (f && f->locale!=default_locale) { + log_warning(("message for locale \"%s\": %s\n", locale_name(f->locale), s)); + } +#endif + unused(level); + switch (mtype) { + case MSG_INCOME: + assert(f); + m = add_message(&f->msgs, msg_message("msg_economy", "string", s)); + break; + case MSG_BATTLE: + assert(0 || !"battle-meldungen nicht über addmessage machen"); + break; + case MSG_MOVE: + assert(f); + m = add_message(&f->msgs, msg_message("msg_movement", "string", s)); + break; + case MSG_COMMERCE: + assert(f); + m = add_message(&f->msgs, msg_message("msg_economy", "string", s)); + break; + case MSG_PRODUCE: + assert(f); + m = add_message(&f->msgs, msg_message("msg_production", "string", s)); + break; + case MSG_MAGIC: + case MSG_COMMENT: + case MSG_MESSAGE: + case MSG_ORCVERMEHRUNG: + case MSG_EVENT: + /* Botschaften an REGION oder einzelne PARTEI */ + m = msg_message("msg_event", "string", s); + if (!r) { + assert(f); + m = add_message(&f->msgs, m); + } else { + if (f==NULL) add_message(&r->msgs, m); + else r_addmessage(r, f, m); + } + break; + default: + assert(!"Ungültige Msg-Klasse!"); + } + if (m) msg_release(m); +} + +void +addmessage(region * r, faction * f, const char *s, msg_t mtype, int level) +{ + caddmessage(r, f, s, mtype, level); +} + +void +cmistake(const unit * u, struct order *ord, int mno, int mtype) +{ + static char msgname[20]; + unused(mtype); + + if (is_monsters(u->faction)) return; + sprintf(msgname, "error%d", mno); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, msgname, "")); +} + +extern unsigned int new_hashstring(const char* s); + +void +free_messagelist(message_list * msgs) +{ + struct mlist ** mlistptr = &msgs->begin; + while (*mlistptr) { + struct mlist * ml = *mlistptr; + *mlistptr = ml->next; + msg_release(ml->msg); + free(ml); + } + free(msgs); +} + +message * +add_message(message_list** pm, message * m) +{ + if (!lomem && m!=NULL) { + struct mlist * mnew = malloc(sizeof(struct mlist)); + if (*pm==NULL) { + *pm = malloc(sizeof(message_list)); + (*pm)->end=&(*pm)->begin; + } + mnew->msg = msg_addref(m); + mnew->next = NULL; + *((*pm)->end) = mnew; + (*pm)->end=&mnew->next; + } + return m; +} + + diff --git a/src/kernel/message.h b/src/kernel/message.h index c3e6e3fbe..709def1b0 100644 --- a/src/kernel/message.h +++ b/src/kernel/message.h @@ -1,61 +1,61 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_MESSAGE -#define H_KRNL_MESSAGE -#ifdef __cplusplus -extern "C" { -#endif - -#include - -struct message; -struct faction; -struct msglevel; - -struct message_type; - -typedef struct message_list { - struct mlist { - struct mlist * next; - struct message *msg; - } * begin, **end; -} message_list; - -extern void free_messagelist(message_list * msgs); - -typedef struct msglevel { - /* used to set specialized msg-levels */ - struct msglevel *next; - const struct message_type *type; - 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, - const char * name, const char* sig, ...); -extern 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); - -#define ADDMSG(msgs, mcreate) { message * m = mcreate; if (m) { assert(m->refcount>=1); add_message(msgs, m); msg_release(m); } } - -extern void cmistake(const struct unit * u, struct order *ord, int mno, int mtype); -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_MESSAGE +#define H_KRNL_MESSAGE +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct message; +struct faction; +struct msglevel; + +struct message_type; + +typedef struct message_list { + struct mlist { + struct mlist * next; + struct message *msg; + } * begin, **end; +} message_list; + +extern void free_messagelist(message_list * msgs); + +typedef struct msglevel { + /* used to set specialized msg-levels */ + struct msglevel *next; + const struct message_type *type; + 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, + const char * name, const char* sig, ...); +extern 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); + +#define ADDMSG(msgs, mcreate) { message * m = mcreate; if (m) { assert(m->refcount>=1); add_message(msgs, m); msg_release(m); } } + +extern void cmistake(const struct unit * u, struct order *ord, int mno, int mtype); +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/move.c b/src/kernel/move.c index 137d3c35d..0924775ad 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -1,2648 +1,2648 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "move.h" - -#include "alchemy.h" -#include "connection.h" -#include "build.h" -#include "building.h" -#include "calendar.h" -#include "curse.h" -#include "faction.h" -#include "item.h" -#include "magic.h" -#include "message.h" -#include "order.h" -#include "plane.h" -#include "race.h" -#include "region.h" -#include "render.h" -#include "reports.h" -#include "save.h" -#include "ship.h" -#include "skill.h" -#include "terrain.h" -#include "teleport.h" -#include "unit.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* attributes includes */ -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -int * storms; - -typedef struct traveldir { - int no; - direction_t dir; - int age; -} traveldir; - -static attrib_type at_traveldir = { - "traveldir", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, /* Weil normales Aging an ungünstiger Stelle */ - a_writechars, - a_readchars -}; - -typedef struct follower { - struct follower * next; - unit * uf; - unit * ut; - const region_list * route_end; -} follower; - -static void -get_followers(unit * target, region * r, const region_list * route_end, follower ** followers) -{ - unit * uf; - for (uf=r->units;uf;uf=uf->next) { - if (fval(uf, UFL_FOLLOWING) && !fval(uf, UFL_NOTMOVING)) { - const attrib * a = a_findc(uf->attribs, &at_follow); - if (a && a->data.v == target) { - follower * fnew = malloc(sizeof(follower)); - fnew->uf = uf; - fnew->ut = target; - fnew->route_end = route_end; - fnew->next = *followers; - *followers = fnew; - } - } - } -} - -static void -shiptrail_init(attrib *a) -{ - a->data.v = calloc(1, sizeof(traveldir)); -} - -static void -shiptrail_finalize(attrib *a) -{ - free(a->data.v); -} - -static int -shiptrail_age(attrib *a) -{ - traveldir *t = (traveldir *)(a->data.v); - - t->age--; - return (t->age>0)?AT_AGE_KEEP:AT_AGE_REMOVE; -} - -static int -shiptrail_read(attrib *a, void * owner, struct storage * store) -{ - traveldir *t = (traveldir *)(a->data.v); - - t->no = store->r_int(store); - t->dir = (direction_t)store->r_int(store); - t->age = store->r_int(store); - return AT_READ_OK; -} - -static void -shiptrail_write(const attrib * a, const void * owner, struct storage * store) -{ - traveldir *t = (traveldir *)(a->data.v); - store->w_int(store, t->no); - store->w_int(store, t->dir); - store->w_int(store, t->age); -} - -attrib_type at_shiptrail = { - "traveldir_new", - shiptrail_init, - shiptrail_finalize, - shiptrail_age, - shiptrail_write, - shiptrail_read -}; - -static int -age_speedup(attrib *a) -{ - if (a->data.sa[0] > 0) { - a->data.sa[0] = a->data.sa[0] - a->data.sa[1]; - } - return (a->data.sa[0]>0)?AT_AGE_KEEP:AT_AGE_REMOVE; -} - -attrib_type at_speedup = { - "speedup", - NULL, NULL, - age_speedup, - a_writeint, - a_readint -}; - -/* ------------------------------------------------------------- */ - -direction_t -getdirection(const struct locale * lang) -{ - return finddirection(getstrtoken(), lang); -} -/* ------------------------------------------------------------- */ - -static attrib_type at_driveweight = { - "driveweight", NULL, NULL, NULL, NULL, NULL -}; - -static boolean -entrance_allowed(const struct unit * u, const struct region * r) -{ -#ifdef REGIONOWNERS - faction * owner = region_get_owner(r); - if (owner == NULL || u->faction == owner) return true; - if (alliedfaction(rplane(r), owner, u->faction, HELP_TRAVEL)) return true; - return false; -#else - return true; -#endif -} - -int -personcapacity(const unit *u) -{ - int cap = u->race->weight+u->race->capacity; - return cap; -} - -static int -eff_weight(const unit *u) -{ - attrib *a = a_find(u->attribs, &at_driveweight); - - if (a) return weight(u) + a->data.i; - - return weight(u); -} - -static void -get_transporters(const item * itm, int * p_animals, int *p_acap, int * p_vehicles, int * p_vcap) -{ - int vehicles = 0, vcap = 0; - int animals = 0, acap = 0; - - for (;itm!=NULL;itm=itm->next) { - const item_type * itype = itm->type; - if (itype->capacity>0) { - if (itype->flags & ITF_ANIMAL) { - animals += itm->number; - if (acap==0) acap = itype->capacity; - assert(acap==itype->capacity || !"animals with different capacity not supported"); - } - if (itype->flags & ITF_VEHICLE) { - vehicles += itm->number; - if (vcap==0) vcap = itype->capacity; - assert(vcap==itype->capacity || !"vehicles with different capacity not supported"); - } - } - } - *p_vehicles = vehicles; - *p_animals = animals; - *p_vcap = vcap; - *p_acap = acap; -} - -static int -ridingcapacity(unit * u) -{ - int vehicles = 0, vcap = 0; - int animals = 0, acap = 0; - - get_transporters(u->items, &animals, &acap, &vehicles, &vcap); - - /* Man trägt sein eigenes Gewicht plus seine Kapazität! Die Menschen - ** tragen nichts (siehe walkingcapacity). Ein Wagen zählt nur, wenn er - ** von zwei Pferden gezogen wird */ - - animals = MIN(animals, effskill(u, SK_RIDING) * u->number * 2); - if (fval(u->race, RCF_HORSE)) animals += u->number; - - /* maximal diese Pferde können zum Ziehen benutzt werden */ - vehicles = MIN(animals / HORSESNEEDED, vehicles); - - return vehicles * vcap + animals * acap; -} - -int -walkingcapacity(const struct unit * u) -{ - int n, tmp, people, pferde_fuer_wagen; - int wagen_ohne_pferde, wagen_mit_pferden, wagen_mit_trollen; - int vehicles = 0, vcap = 0; - int animals = 0, acap = 0; - - get_transporters(u->items, &animals, &acap, &vehicles, &vcap); - - /* Das Gewicht, welches die Pferde tragen, plus das Gewicht, welches - * die Leute tragen */ - - pferde_fuer_wagen = MIN(animals, effskill(u, SK_RIDING) * u->number * 4); - if (fval(u->race, RCF_HORSE)) { - animals += u->number; - people = 0; - } else { - people = u->number; - } - - /* maximal diese Pferde können zum Ziehen benutzt werden */ - wagen_mit_pferden = MIN(vehicles, pferde_fuer_wagen / HORSESNEEDED); - - n = wagen_mit_pferden * vcap; - - if (u->race == new_race[RC_TROLL]) { - /* 4 Trolle ziehen einen Wagen. */ - /* Unbesetzte Wagen feststellen */ - wagen_ohne_pferde = vehicles - wagen_mit_pferden; - - /* Genug Trolle, um die Restwagen zu ziehen? */ - wagen_mit_trollen = MIN(u->number / 4, wagen_ohne_pferde); - - /* Wagenkapazität hinzuzählen */ - n += wagen_mit_trollen * vcap; - wagen_ohne_pferde -= wagen_mit_trollen; - } - - n += animals * acap; - n += people * personcapacity(u); - /* Goliathwasser */ - tmp = get_effect(u, oldpotiontype[P_STRONG]); - if (tmp>0) { - int horsecap = olditemtype[I_HORSE]->capacity; - if (tmp>people) tmp = people; - n += tmp * (horsecap - personcapacity(u)); - } - /* change_effect wird in ageing gemacht */ - tmp = get_item(u, I_TROLLBELT); - n += MIN(people, tmp) * (STRENGTHMULTIPLIER-1) * personcapacity(u); - - return n; -} - -enum { - E_CANWALK_OK = 0, - E_CANWALK_TOOMANYHORSES, - E_CANWALK_TOOMANYCARTS, - E_CANWALK_TOOHEAVY -}; - -static int -canwalk(unit * u) -{ - int maxwagen, maxpferde; - int vehicles = 0, vcap = 0; - int animals = 0, acap = 0; - - /* workaround: monsters are too stupid to drop items, therefore they have - * infinite carrying capacity */ - - if (is_monsters(u->faction)) return E_CANWALK_OK; - - get_transporters(u->items, &animals, &acap, &vehicles, &vcap); - - maxwagen = effskill(u, SK_RIDING) * u->number * 2; - if (u->race == new_race[RC_TROLL]) { - maxwagen = MAX(maxwagen, u->number / 4); - } - maxpferde = effskill(u, SK_RIDING) * u->number * 4 + u->number; - - if (animals > maxpferde) - return E_CANWALK_TOOMANYHORSES; - - if (walkingcapacity(u) - eff_weight(u) >= 0) - return E_CANWALK_OK; - - /* Stimmt das Gewicht, impliziert dies hier, daß alle Wagen ohne - * Zugpferde/-trolle als Fracht aufgeladen wurden: zu viele Pferde hat - * die Einheit nicht zum Ziehen benutzt, also nicht mehr Wagen gezogen - * als erlaubt. */ - - if (vehicles > maxwagen) - return E_CANWALK_TOOMANYCARTS; - /* Es muß nicht zwingend an den Wagen liegen, aber egal... (man - * könnte z.B. auch 8 Eisen abladen, damit ein weiterer Wagen als - * Fracht draufpaßt) */ - - return E_CANWALK_TOOHEAVY; -} - -boolean -canfly(unit *u) -{ - if (get_item(u, I_PEGASUS) >= u->number && effskill(u, SK_RIDING) >= 4) - return true; - - if (fval(u->race, RCF_FLY)) return true; - - if (get_movement(&u->attribs, MV_FLY)) return true; - - return false; -} - -boolean -canswim(unit *u) -{ - if (get_item(u, I_DOLPHIN) >= u->number && effskill(u, SK_RIDING) >= 4) - return true; - - if (u->race->flags & RCF_FLY) return true; - - if (u->race->flags & RCF_SWIM) return true; - - if (get_movement(&u->attribs, MV_FLY)) return true; - - if (get_movement(&u->attribs, MV_SWIM)) return true; - - return false; -} - -static int -canride(unit * u) -{ - int horses = 0, maxhorses, unicorns = 0, maxunicorns; - int skill = effskill(u, SK_RIDING); - item * itm; - static const item_type * it_horse = 0; - static const item_type * it_elvenhorse = 0; - static const item_type * it_charger = 0; - - if (it_horse==0) { - it_horse = it_find("horse"); - it_elvenhorse = it_find("elvenhorse"); - it_charger = it_find("charger"); - } - - for (itm=u->items;itm;itm=itm->next) { - if (itm->type==it_horse || itm->type==it_charger) { - horses += itm->number; - } else if (itm->type==it_elvenhorse) { - unicorns += itm->number; - } - } - - maxunicorns = (skill/5) * u->number; - maxhorses = skill * u->number * 2; - - if(!(u->race->flags & RCF_HORSE) - && ((horses == 0 && unicorns == 0) - || horses > maxhorses || unicorns > maxunicorns)) { - return 0; - } - - if (ridingcapacity(u) - eff_weight(u) >= 0) { - if (horses == 0 && unicorns >= u->number && !(u->race->flags & RCF_HORSE)) { - return 2; - } - return 1; - } - - return 0; -} - -static boolean -cansail(const region * r, ship * sh) -{ - /* sonst ist construction:: size nicht ship_type::maxsize */ - assert(!sh->type->construction || sh->type->construction->improvement == NULL); - - if (sh->type->construction && sh->size!=sh->type->construction->maxsize) { - return false; - } else { - int n = 0, p = 0; - int mweight = shipcapacity(sh); - int mcabins = sh->type->cabins; - - getshipweight(sh, &n, &p); - - if (n > mweight) return false; - if (mcabins && p > mcabins) return false; - } - return true; -} - -int -enoughsailors(const ship * sh, const region * r) -{ - int n; - unit *u; - - n = 0; - - for (u = r->units; u; u = u->next) { - if (u->ship == sh) - n += eff_skill(u, SK_SAILING, r) * u->number; - } - return n >= sh->type->sumskill; -} -/* ------------------------------------------------------------- */ - -static ship * -do_maelstrom(region *r, unit *u) -{ - int damage; - ship * sh = u->ship; - - damage = rng_int()%75 + rng_int()%75 - eff_skill(u, SK_SAILING, r)*4; - - if (damage <= 0) { - return sh; - } - - damage_ship(u->ship, 0.01*damage); - - if (sh->damage >= sh->size * DAMAGE_SCALE) { - ADDMSG(&u->faction->msgs, msg_message("entermaelstrom", - "region ship damage sink", r, sh, damage, 1)); - remove_ship(&sh->region->ships, sh); - return NULL; - } - ADDMSG(&u->faction->msgs, msg_message("entermaelstrom", - "region ship damage sink", r, sh, damage, 0)); - return u->ship; -} - -/** sets a marker in the region telling that the unit has travelled through it - * this is used for two distinctly different purposes: - * - to report that a unit has travelled through. the report function - * makes sure to only report the ships of travellers, not the travellers - * themselves - * - to report the region to the traveller - */ -void -travelthru(const unit * u, region * r) -{ - attrib *ru = a_add(&r->attribs, a_new(&at_travelunit)); - - fset(r, RF_TRAVELUNIT); - - ru->data.v = (void*)u; - - /* the first and last region of the faction gets reset, because travelthrough - * could be in regions that are located before the [first, last] interval, - * and recalculation is needed */ -#ifdef SMART_INTERVALS - update_interval(u->faction, r); -#endif -} - -static void -leave_trail(ship * sh, region * from, region_list *route) -{ - region * r = from; - - while (route!=NULL) { - region * rn = route->data; - direction_t dir = reldirection(r, rn); - - /* TODO: we cannot leave a trail into special directions - * if we use this kind of direction-attribute */ - if (dir=0) { - traveldir * td = NULL; - attrib * a = a_find(r->attribs, &at_shiptrail); - - while (a!=NULL && a->type==&at_shiptrail) { - td = (traveldir *)a->data.v; - if (td->no == sh->no) break; - a = a->next; - } - - if (a == NULL || a->type!=&at_shiptrail) { - a = a_add(&(r->attribs), a_new(&at_shiptrail)); - td = (traveldir *)a->data.v; - td->no = sh->no; - } - td->dir = dir; - td->age = 2; - } - route = route->next; - r = rn; - } -} - -static void -mark_travelthru(const unit * u, region * r, const region_list * route, const region_list * route_end) -{ - /* kein travelthru in der letzten region! */ - while (route!=route_end) { - travelthru(u, r); - r = route->data; - route = route->next; - } -} - -ship * -move_ship(ship * sh, region * from, region * to, region_list * route) -{ - unit **iunit = &from->units; - unit **ulist = &to->units; - boolean trail = (route == NULL); - - if (from!=to) { - translist(&from->ships, &to->ships, sh); - sh->region = to; - } - if (!trail) { - leave_trail(sh, from, route); - trail = true; - } - - while (*iunit!=NULL) { - unit *u = *iunit; - assert(u->region == from); - - if (u->ship == sh) { - if (route!=NULL) mark_travelthru(u, from, route, NULL); - if (from!=to) { - u->ship = NULL; /* damit move_unit() kein leave() macht */ - move_unit(u, to, ulist); - ulist = &u->next; - u->ship = sh; - } - if (route && eff_skill(u, SK_SAILING, from) >= 1) { - produceexp(u, SK_SAILING, u->number); - } - } - if (*iunit == u) iunit=&u->next; - } - - return sh; -} - -static boolean -is_freezing(const unit * u) -{ - if (u->race!=new_race[RC_INSECT]) return false; - if (is_cursed(u->attribs, C_KAELTESCHUTZ, 0)) return false; - return true; -} - -static boolean -ship_allowed(const struct ship * sh, const region * r) -{ - int c = 0; - static const building_type * bt_harbour=NULL; - - if (bt_harbour == NULL) bt_harbour=bt_find("harbour"); - - if (r_insectstalled(r)) { - /* insekten dürfen nicht hier rein. haben wir welche? */ - unit * u; - - for (u=sh->region->units;u!=NULL;u=u->next) { - if (u->ship!=sh) continue; - - if (is_freezing(u)) { - unit * captain = shipowner(sh); - if (captain) { - ADDMSG(&captain->faction->msgs, msg_message("detectforbidden", - "unit region", u, r)); - } - - return false; - } - } - } - - if (buildingtype_exists(r, bt_harbour, true)) return true; - for (c=0;sh->type->coasts[c]!=NULL;++c) { - if (sh->type->coasts[c] == r->terrain) return true; - } - - return false; -} - -static boolean -flying_ship(const ship * sh) -{ - if (sh->type->flags & SFL_FLY) return true; - if (sh->flags & SF_FLYING) return true; - return false; -} - -static void -set_coast(ship * sh, region * r, region * rnext) -{ - if (sh->type->flags & SFL_NOCOAST) { - sh->coast = NODIRECTION; - } else if (!fval(rnext->terrain, SEA_REGION) && !flying_ship(sh)) { - sh->coast = reldirection(rnext, r); - assert(fval(r->terrain, SEA_REGION)); - } else { - sh->coast = NODIRECTION; - } -} - -static float -damage_drift(void) -{ - static float value = -1.0F; - if (value<0) { - value = get_param_flt(global.parameters, "rules.ship.damage_drift", 0.02F); - } - return value; -} - -static void -drifting_ships(region * r) -{ - direction_t d; - - if (fval(r->terrain, SEA_REGION)) { - ship** shp = &r->ships; - while (*shp) { - ship * sh = *shp; - region * rnext = NULL; - region_list * route = NULL; - unit *firstu = NULL, *captain; - int d_offset; - direction_t dir = 0; - - if (sh->type->fishing>0) { - sh->flags |= SF_FISHING; - } - - /* Schiff schon abgetrieben oder durch Zauber geschützt? */ - if (fval(sh, SF_DRIFTED) || is_cursed(sh->attribs, C_SHIP_NODRIFT, 0)) { - shp = &sh->next; - continue; - } - - /* Kapitän bestimmen */ - for (captain = r->units; captain; captain = captain->next) { - if (captain->ship != sh) continue; - if (firstu==NULL) firstu = captain; - if (eff_skill(captain, SK_SAILING, r) >= sh->type->cptskill) { - break; - } - } - /* Kapitän da? Beschädigt? Genügend Matrosen? - * Genügend leicht? Dann ist alles OK. */ - - assert(sh->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ - if (captain && sh->size == sh->type->construction->maxsize && enoughsailors(sh, r) && cansail(r, sh)) { - shp = &sh->next; - continue; - } - - /* Auswahl einer Richtung: Zuerst auf Land, dann - * zufällig. Falls unmögliches Resultat: vergiß es. */ - d_offset = rng_int() % MAXDIRECTIONS; - for (d = 0; d != MAXDIRECTIONS; ++d) { - region * rn; - dir = (direction_t)((d + d_offset) % MAXDIRECTIONS); - rn = rconnect(r, dir); - if (rn!=NULL && fval(rn->terrain, SAIL_INTO) && ship_allowed(sh, rn)) { - rnext = rn; - if (!fval(rnext->terrain, SEA_REGION)) break; - } - } - - if (rnext == NULL) { - shp = &sh->next; - continue; - } - - /* Das Schiff und alle Einheiten darin werden nun von r - * nach rnext verschoben. Danach eine Meldung. */ - add_regionlist(&route, rnext); - - set_coast(sh, r, rnext); - sh = move_ship(sh, r, rnext, route); - free_regionlist(route); - - if (firstu!=NULL) { - unit *u, *lastu = NULL; - message * msg = msg_message("ship_drift", "ship dir", sh, dir); - for (u=firstu;u;u=u->next) { - if (u->ship==sh && !fval(u->faction, FFL_MARK)) { - fset(u->faction, FFL_MARK); - add_message(&u->faction->msgs, msg); - lastu = u->next; - } - } - for (u=firstu;u!=lastu;u=u->next) { - freset(u->faction, FFL_MARK); - } - msg_release(msg); - } - - if (sh!=NULL) { - fset(sh, SF_DRIFTED); - - damage_ship(sh, damage_drift()); - if (sh->damage>=sh->size * DAMAGE_SCALE) { - remove_ship(&sh->region->ships, sh); - } - } - - if (*shp == sh) shp = &sh->next; - } - } -} - -static boolean -present(region * r, unit * u) -{ - return (boolean) (u && u->region == r); -} - -static void -caught_target(region * r, unit * u) -{ - attrib * a = a_find(u->attribs, &at_follow); - - /* Verfolgungen melden */ - /* Misserfolgsmeldung, oder bei erfolgreichem Verfolgen unter - * Umstaenden eine Warnung. */ - - if (a) { - unit * target = (unit*)a->data.v; - - if (!present(r, target)) { - ADDMSG(&u->faction->msgs, msg_message("followfail", "unit follower", - target, u)); - } else if (!alliedunit(target, u->faction, HELP_ALL) - && cansee(target->faction, r, u, 0)) - { - ADDMSG(&target->faction->msgs, msg_message("followdetect", - "unit follower", target, u)); - } - } -} - -/* TODO: Unsichtbarkeit bedenken ! */ - -static unit * -bewegung_blockiert_von(unit * reisender, region * r) -{ - unit *u; - int perception = 0; - boolean contact = false; - unit * guard = NULL; - - if (fval(reisender->race, RCF_ILLUSIONARY)) return NULL; - for (u=r->units;u && !contact;u=u->next) { - if (is_guard(u, GUARD_TRAVELTHRU)) { - int sk = eff_skill(u, SK_PERCEPTION, r); - if (invisible(reisender, u) >= reisender->number) continue; - if (u->faction == reisender->faction) contact = true; - else if (ucontact(u, reisender)) contact = true; - else if (alliedunit(u, reisender->faction, HELP_GUARD)) contact = true; - else if (sk>=perception) { - perception = sk; - guard = u; - } - } - } - if (!contact && guard) { - double prob = 0.3; /* 30% base chance */ - prob += 0.1 * (perception - eff_stealth(reisender, r)); - prob += 0.1 * MIN(guard->number, get_item(guard, I_AMULET_OF_TRUE_SEEING)); - - if (chance(prob)) { - return guard; - } - } - return NULL; -} - -static boolean -is_guardian_u(const unit * guard, unit *u, unsigned int mask) -{ - if (guard->faction == u->faction) return false; - if (is_guard(guard, mask) == 0) return false; - if (alliedunit(guard, u->faction, HELP_GUARD)) return false; - if (ucontact(guard, u)) return false; - if (!cansee(guard->faction, u->region, u, 0)) return false; - - return true; -} - -static boolean -is_guardian_r(const unit * guard) -{ - if (guard->number == 0) return false; - if (besieged(guard)) return false; - - /* if region_owners exist then they may be guardians: */ - if (guard->building && rule_region_owners() && fval(guard, UFL_OWNER)) { - faction * owner = region_get_owner(guard->region); - if (owner==guard->faction) { - building * bowner = largestbuilding(guard->region, &cmp_taxes, false); - if (bowner==guard->building) { - return true; - } - } - } - - if ((guard->flags&UFL_GUARD)==0) return false; - if (!armedmen(guard, true) && !fval(guard->race, RCF_UNARMEDGUARD)) return false; - return true; -} - -boolean is_guard(const struct unit * u, int mask) -{ - return is_guardian_r(u) && (getguard(u) & mask)!=0; -} - -#define MAXGUARDCACHE 16 -/** returns the guard which prevents 'u' from doing 'mask' actions in 'r'. -*/ -unit * -is_guarded(region * r, unit * u, unsigned int mask) -{ - unit *u2 = NULL; - int i, noguards = 1; - static unit * guardcache[MAXGUARDCACHE], * lastguard; /* STATIC_XCALL: used across calls */ - static int gamecookie = -1; - - if (!fval(r, RF_GUARDED)) { - return NULL; - } - - if (gamecookie!=global.cookie) { - if (gamecookie>=0) { - /* clear the previous turn's cache */ - memset(guardcache, 0, sizeof(guardcache)); - lastguard = NULL; - } - gamecookie = global.cookie; - } - - if (lastguard && lastguard->region==r) { - if (is_guardian_u(lastguard, u, mask)) { - return lastguard; - } - } - - for (i=0;i!=MAXGUARDCACHE;++i) { - unit * guard = guardcache[i]; - if (guard && guard!=lastguard && guard->region==r) { - noguards = 0; - if (is_guardian_u(guard, u, mask)) { - lastguard = guard; - return guard; - } - if (u2==guard) { - /* same guard twice signals we've tested everyone */ - return NULL; - } - u2 = guard; - } else { - /* exhausted all the guards in the cache, but maybe we'll find one later? */ - break; - } - } - - /* at this point, u2 is the last unit we tested to - * be a guard (and failed), or NULL - * i is the position of the first free slot in the cache */ - - for (u2 = (u2?u2->next:r->units); u2; u2=u2->next) { - if (is_guardian_r(u2)) { - noguards = 0; - /* u2 is a guard, so worth remembering */ - if (i0 && ifaction->locale; - pause = false; - token = getstrtoken(); - d = finddirection(token, lang); - if(d == D_PAUSE) { - pause = true; - } else if (d == NODIRECTION) { - break; - } - if (cmsizeof(neworder)/2) break; - else if (cm == gereist && !paused && pause) { - const char * loc = LOC(lang, parameters[P_PAUSE]); - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, loc, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - paused = true; - } - else if (pause) { - /* da PAUSE nicht in ein shortdirections[d] umgesetzt wird (ist - * hier keine normale direction), muss jede PAUSE einzeln - * herausgefiltert und explizit gesetzt werden */ - if (neworder[0]) strcat(neworder, " "); - strcat(neworder, LOC(lang, parameters[P_PAUSE])); - } else { - if (neworder[0]) strcat(neworder, " "); - strcat(neworder, LOC(lang, shortdirections[d])); - } - } - - if (neworder[0]) { - norder = create_order(K_ROUTE, u->faction->locale, "%s %s", neworder, tail); - } else { - norder = create_order(K_ROUTE, u->faction->locale, "%s", tail); - } - replace_order(&u->orders, ord, norder); - free_order(norder); -} - -static boolean -transport(unit * ut, unit * u) -{ - order * ord; - - if (LongHunger(u) || fval(ut->region->terrain, SEA_REGION)) { - return false; - } - - for (ord = ut->orders; ord; ord = ord->next) { - if (get_keyword(ord) == K_TRANSPORT) { - init_tokens(ord); - skip_token(); - if (getunit(ut->region, ut->faction) == u) { - return true; - } - } - } - return false; -} - -static boolean -can_move(const unit * u) -{ - if (u->race->flags & RCF_CANNOTMOVE) return false; - if (get_movement(&u->attribs, MV_CANNOTMOVE)) return false; - return true; -} - -static void -init_transportation(void) -{ - region *r; - - for (r=regions; r; r=r->next) { - unit *u; - - /* This is just a simple check for non-corresponding K_TRANSPORT/ - * K_DRIVE. This is time consuming for an error check, but there - * doesn't seem to be an easy way to speed this up. */ - for (u=r->units; u; u=u->next) { - if (get_keyword(u->thisorder) == K_DRIVE && can_move(u) && !fval(u, UFL_NOTMOVING) && !LongHunger(u)) { - unit * ut; - - init_tokens(u->thisorder); - skip_token(); - ut = getunit(r, u->faction); - if (ut == NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); - continue; - } - if (!transport(ut, u)) { - if (cansee(u->faction, r, ut, 0)) { - cmistake(u, u->thisorder, 286, MSG_MOVE); - } else { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); - } - } - } - } - - /* This calculates the weights of all transported units and - * adds them to an internal counter which is used by travel () to - * calculate effective weight and movement. */ - - if (!fval(r->terrain, SEA_REGION)) { - for (u=r->units; u; u=u->next) { - order * ord; - int w = 0; - - for (ord = u->orders; ord; ord = ord->next) { - if (get_keyword(ord) == K_TRANSPORT) { - init_tokens(ord); - skip_token(); - for (;;) { - unit * ut = getunit(r, u->faction); - - if (ut == NULL) break; - if (get_keyword(ut->thisorder) == K_DRIVE && can_move(ut) && !fval(ut, UFL_NOTMOVING) && !LongHunger(ut)) { - init_tokens(ut->thisorder); - skip_token(); - if (getunit(r, ut->faction) == u) { - w += weight(ut); - } - } - } - } - } - if (w > 0) a_add(&u->attribs, a_new(&at_driveweight))->data.i = w; - } - } - } -} - -static boolean -roadto(const region * r, direction_t dir) -{ - /* wenn es hier genug strassen gibt, und verbunden ist, und es dort - * genug strassen gibt, dann existiert eine strasse in diese richtung */ - region * r2; - static const curse_type * roads_ct = NULL; - - if (dir>=MAXDIRECTIONS || dir<0) return false; - r2 = rconnect(r, dir); - if (r == NULL || r2 == NULL) return false; - - if (roads_ct == NULL) roads_ct = ct_find("magicstreet"); - if (roads_ct!=NULL) { - if (get_curse(r->attribs, roads_ct)!=NULL) return true; - if (get_curse(r2->attribs, roads_ct)!=NULL) return true; - } - - if (r->terrain->max_road <= 0) return false; - if (r2->terrain->max_road <= 0) return false; - if (rroad(r, dir) < r->terrain->max_road) return false; - if (rroad(r2, dir_invert(dir)) < r2->terrain->max_road) return false; - return true; -} - -static const region_list * -cap_route(region * r, const region_list * route, const region_list * route_end, int speed) -{ - region * current = r; - int moves = speed; - const region_list * iroute = route; - while (iroute!=route_end) { - region * next = iroute->data; - direction_t reldir = reldirection(current, next); - - /* adjust the range of the unit */ - if (roadto(current, reldir)) moves -= BP_ROAD; - else moves -= BP_NORMAL; - if (moves<0) break; - iroute = iroute->next; - current = next; - } - return iroute; -} - -static region * -next_region(unit * u, region * current, region * next) -{ - connection * b; - - b = get_borders(current, next); - while (b!=NULL) { - if (b->type->move) { - region * rto = b->type->move(b, u, current, next, true); - if (rto!=next) { - /* the target region was changed (wisps, for example). check the - * new target region for borders */ - next = rto; - b = get_borders(current, next); - continue; - } - } - b = b->next; - } - return next; -} - -static const region_list * -reroute(unit * u, const region_list * route, const region_list * route_end) -{ - region * current = u->region; - while (route!=route_end) { - region * next = next_region(u, current, route->data); - if (next!=route->data) break; - route = route->next; - } - return route; -} - -static void -make_route(unit * u, order * ord, region_list ** routep) -{ - region_list **iroute = routep; - region * current = u->region; - region * next = NULL; - const char * token = getstrtoken(); - int error = movewhere(u, token, current, &next); - - if (error!=E_MOVE_OK) { - message * msg = movement_error(u, token, ord, error); - if (msg!=NULL) { - add_message(&u->faction->msgs, msg); - msg_release(msg); - } - next = NULL; - } - - while (next!=NULL) { - direction_t reldir; - - if (current == next) { - /* PAUSE */ - break; - } - next = next_region(u, current, next); - reldir = reldirection(current, next); - - add_regionlist(iroute, next); - iroute = &(*iroute)->next; - - current = next; - token = getstrtoken(); - error = movewhere(u, token, current, &next); - if (error) { - message * msg = movement_error(u, token, ord, error); - if (msg!=NULL) { - add_message(&u->faction->msgs, msg); - msg_release(msg); - } - next = NULL; - } - } -} - -/** calculate the speed of a unit - * - * zu Fuß reist man 1 Region, zu Pferd 2 Regionen. Mit Straßen reist - * man zu Fuß 2, mit Pferden 3 weit. - * - * Berechnet wird das mit BPs. Zu Fuß hat man 4 BPs, zu Pferd 6. - * 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 mp; - static const curse_type * speed_ct; - static boolean init = false; - double dk = u->race->speed; - - assert(u->number); - /* dragons have a fixed speed, and no other effects work on them: */ - switch (old_race(u->race)) { - case RC_DRAGON: - case RC_WYRM: - case RC_FIREDRAGON: - case RC_BIRTHDAYDRAGON: - case RC_SONGDRAGON: - return BP_DRAGON; - } - - if (!init) { - init = true; - speed_ct = ct_find("speed"); - } - if (speed_ct) { - curse *c = get_curse(u->attribs, speed_ct); - if (c!=NULL) { - int men = get_cursedmen(u, c); - dk *= 1.0 + (double)men/(double)u->number; - } - } - - switch (canride(u)) { - - case 1: /* Pferd */ - mp = BP_RIDING; - break; - - case 2: /* Einhorn */ - mp = BP_UNICORN; - break; - - default: - mp = BP_WALKING; - - /* 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 <= get_item(u, I_FEENSTIEFEL)) { - mp *= 2; - } - - /* Im Astralraum sind Tyb und Ill-Magier doppelt so schnell. - * Nicht kumulativ mit anderen Beschleunigungen! */ - if (mp*dk <= BP_WALKING*u->race->speed && is_astral(u->region) && is_mage(u)) { - sc_mage * mage = get_mage(u); - if (mage->magietyp == M_TYBIED || mage->magietyp == M_ILLAUN) { - mp *= 2; - } - } - break; - } - return (int)(dk*mp); -} - -enum { - TRAVEL_NORMAL, - TRAVEL_FOLLOWING, - TRAVEL_TRANSPORTED, - TRAVEL_RUNNING -}; - -static arg_regions * -var_copy_regions(const region_list * begin, int size) -{ - const region_list * rsrc; - - if (size>0) { - int i = 0; - arg_regions * dst = (arg_regions *)malloc(sizeof(arg_regions) + sizeof(region*) * size); - dst->nregions = size; - dst->regions = (region**)(dst+1); - for (rsrc = begin; i!=size; rsrc=rsrc->next) { - dst->regions[i++] = rsrc->data; - } - return dst; - } - return NULL; -} - - -static const region_list * -travel_route(unit * u, const region_list * route_begin, const region_list * route_end, order * ord, int mode) -{ - region * r = u->region; - region * current = u->region; - const region_list * iroute = route_begin; - int steps = 0; - boolean landing = false; /* aquarians have landed */ - - while (iroute && iroute!=route_end) { - region * next = iroute->data; - direction_t reldir = reldirection(current, next); - connection * b = get_borders(current, next); - - /* check if we are caught by guarding units */ - if (iroute!=route_begin && mode!=TRAVEL_RUNNING && mode!=TRAVEL_TRANSPORTED) { - unit * wache = bewegung_blockiert_von(u, current); - if (wache!=NULL) { - ADDMSG(&u->faction->msgs, msg_message("moveblockedbyguard", - "unit region guard", u, current, wache)); - break; - } - } - - /* check movement from/to oceans. - * aquarian special, flying units, horses, the works */ - if ((u->race->flags & RCF_FLY) == 0) { - if (!fval(next->terrain, SEA_REGION)) { - /* next region is land */ - if (fval(current->terrain, SEA_REGION)) { - int moving = u->race->flags & (RCF_SWIM|RCF_WALK|RCF_COASTAL); - /* Die Einheit kann nicht fliegen, ist im Ozean, und will an Land */ - if (moving != (RCF_SWIM|RCF_WALK) && (moving&RCF_COASTAL) == 0) { - /* can't swim+walk and isn't allowed to enter coast from sea */ - if (ord!=NULL) cmistake(u, ord, 44, MSG_MOVE); - break; - } - landing = true; - } else if ((u->race->flags & RCF_WALK) == 0) { - /* Spezialeinheiten, die nicht laufen können. */ - ADDMSG(&u->faction->msgs, msg_message("detectocean", - "unit region", u, next)); - break; - } else if (landing) { - /* wir sind diese woche angelandet */ - ADDMSG(&u->faction->msgs, msg_message("detectocean", - "unit region", u, next)); - break; - } - } else { - /* Ozeanfelder können nur von Einheiten mit Schwimmen und ohne - * Pferde betreten werden. */ - if (!(canswim(u) || canfly(u))) { - ADDMSG(&u->faction->msgs, msg_message("detectocean", - "unit region", u, next)); - break; - } - } - - if (fval(current->terrain, SEA_REGION) || fval(next->terrain, SEA_REGION)) { - /* trying to enter or exit ocean with horses, are we? */ - if (has_horses(u)) { - /* tries to do it with horses */ - if (ord!=NULL) cmistake(u, ord, 67, MSG_MOVE); - break; - } - } - - } - - /* movement blocked by a wall */ - if (reldir>=0 && move_blocked(u, current, next)) { - ADDMSG(&u->faction->msgs, msg_message("leavefail", - "unit region", u, next)); - break; - } - - /* region ownership only: region owned by enemies */ - if (!entrance_allowed(u, next)) { - ADDMSG(&u->faction->msgs, msg_message("regionowned", - "unit region target", u, current, next)); - break; - } - - /* illusionary units disappear in antimagic zones */ - if (fval(u->race, RCF_ILLUSIONARY)) { - curse * c = get_curse(next->attribs, ct_find("antimagiczone")); - if (curse_active(c)) { - curse_changevigour(&next->attribs, c, (float)-u->number); - ADDMSG(&u->faction->msgs, msg_message("illusionantimagic", "unit", u)); - set_number(u, 0); - break; - } - } - - /* terrain is marked as forbidden (curse, etc) */ - if (fval(next, RF_BLOCKED) || fval(next->terrain, FORBIDDEN_REGION)) { - ADDMSG(&u->faction->msgs, msg_message("detectforbidden", - "unit region", u, next)); - break; - } - - /* unit is an insect and cannot move into a glacier */ - if (u->race == new_race[RC_INSECT]) { - if (r_insectstalled(next) && is_freezing(u)) { - ADDMSG(&u->faction->msgs, msg_message("detectforbidden", - "unit region", u, next)); - break; - } - } - - /* effect of borders */ - while (b!=NULL) { - if (b->type->move) { - b->type->move(b, u, current, next, false); - } - b = b->next; - } - - current = next; - iroute = iroute->next; - ++steps; - if (u->number == 0) break; - } - - if (iroute!=route_begin) { - /* the unit has moved at least one region */ - int walkmode; - - setguard(u, GUARD_NONE); - cycle_route(ord, u, steps); - - if (mode == TRAVEL_RUNNING) { - walkmode = 0; - } if (canride(u)) { - walkmode = 1; - produceexp(u, SK_RIDING, u->number); - } else { - walkmode = 2; - } - - /* Berichte über Durchreiseregionen */ - - if (mode!=TRAVEL_TRANSPORTED) { - arg_regions * ar = var_copy_regions(route_begin, steps-1); - ADDMSG(&u->faction->msgs, msg_message("travel", - "unit mode start end regions", u, walkmode, r, current, ar)); - } - - mark_travelthru(u, r, route_begin, iroute); - move_unit(u, current, NULL); - - /* make orders for the followers */ - } - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - setguard(u, GUARD_NONE); - assert(u->region == current); - return iroute; -} - -static boolean -ship_ready(const region * r, unit * u) -{ - if (!fval(u, UFL_OWNER)) { - cmistake(u, u->thisorder, 146, MSG_MOVE); - return false; - } - if (eff_skill(u, SK_SAILING, r) < u->ship->type->cptskill) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_captain_skill_low", - "value ship", u->ship->type->cptskill, u->ship)); - return false; - } - assert(u->ship->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ - if (u->ship->size!=u->ship->type->construction->maxsize) { - cmistake(u, u->thisorder, 15, MSG_MOVE); - return false; - } - if (!enoughsailors(u->ship, r)) { - cmistake(u, u->thisorder, 1, MSG_MOVE); -/* mistake(u, u->thisorder, - "Auf dem Schiff befinden sich zuwenig erfahrene Seeleute.", MSG_MOVE); */ - return false; - } - if (!cansail(r, u->ship)) { - cmistake(u, u->thisorder, 18, MSG_MOVE); - return false; - } - return true; -} - -unit * -owner_buildingtyp(const region * r, const building_type * bt) -{ - building *b; - unit *owner; - - for (b = rbuildings(r); b; b = b->next) { - owner = building_owner(b); - if (b->type == bt && owner != NULL) { - if (b->size >= bt->maxsize) { - return owner; - } - } - } - - return NULL; -} - -boolean -buildingtype_exists(const region * r, const building_type * bt, boolean working) -{ - building *b; - - for (b = rbuildings(r); b; b = b->next) { - if (b->type == bt) { - if (b->size >= bt->maxsize) { - return true; - } - } - } - - return false; -} - -/* Prüft, ob Ablegen von einer Küste in eine der erlaubten Richtungen erfolgt. */ - -static boolean -check_takeoff(ship *sh, region *from, region *to) -{ - if (!fval(from->terrain, SEA_REGION) && sh->coast != NODIRECTION) { - direction_t coast = sh->coast; - direction_t dir = reldirection(from, to); - direction_t coastr = (direction_t)((coast+1) % MAXDIRECTIONS); - direction_t coastl = (direction_t)((coast+MAXDIRECTIONS-1) % MAXDIRECTIONS); - - if (dir!=coast && dir!=coastl && dir!=coastr - && !buildingtype_exists(from, bt_find("harbour"), true)) - { - return false; - } - } - - return true; -} - -static void -sail(unit * u, order * ord, boolean move_on_land, region_list **routep) -{ - region *starting_point = u->region; - region *current_point, *last_point; - int k, step = 0; - region_list **iroute = routep; - ship * sh = u->ship; - faction * f = u->faction; - region * next_point = NULL; - int error; - const char * token = getstrtoken(); - - if (routep) *routep = NULL; - - error = movewhere(u, token, starting_point, &next_point); - if (error) { - message * msg = movement_error(u, token, ord, error); - if (msg!=NULL) { - add_message(&u->faction->msgs, msg); - msg_release(msg); - } - return; - } - - if (!ship_ready(starting_point, u)) return; - - /* Wir suchen so lange nach neuen Richtungen, wie es geht. Diese werden - * dann nacheinander ausgeführt. */ - - k = shipspeed(sh, u); - - last_point = starting_point; - current_point = starting_point; - - /* die nächste Region, in die man segelt, wird durch movewhere () aus der - * letzten Region bestimmt. - * - * Anfangen tun wir bei starting_point. next_point ist beim ersten - * Durchlauf schon gesetzt (Parameter!). current_point ist die letzte gültige, - * befahrene Region. */ - - while (next_point && current_point!=next_point && step < k) { - const char * token; - int error; - const terrain_type * tthis = current_point->terrain; - /* these values need to be updated if next_point changes (due to storms): */ - const terrain_type * tnext = next_point->terrain; - direction_t dir = reldirection(current_point, next_point); - - assert(sh == u->ship || !"ship has sunk, but we didn't notice it"); - - if (fval(next_point->terrain, FORBIDDEN_REGION)) { - ADDMSG(&f->msgs, msg_message("sailforbidden", - "ship region", sh, next_point)); - break; - } - - if (!flying_ship(sh)) { - int stormchance; - static int stormyness; - static int gamecookie = -1; - - if (gamecookie != global.cookie) { - gamedate date; - get_gamedate(turn, &date); - stormyness = storms[date.month] * 5; - gamecookie = global.cookie; - } - - /* storms should be the first thing we do. */ - stormchance = stormyness / shipspeed(sh, u); - if (check_leuchtturm(next_point, NULL)) stormchance /= 3; - - if (rng_int()%10000 < stormchance*sh->type->storm && fval(current_point->terrain, SEA_REGION)) { - if (!is_cursed(sh->attribs, C_SHIP_NODRIFT, 0)) { - region * rnext = NULL; - boolean storm = true; - int d_offset = rng_int() % MAXDIRECTIONS; - direction_t d; - /* Sturm nur, wenn nächste Region Hochsee ist. */ - for (d=0;d!=MAXDIRECTIONS;++d) { - direction_t dnext = (direction_t)((d + d_offset) % MAXDIRECTIONS); - region * rn = rconnect(current_point, dnext); - - if (rn!=NULL) { - if (fval(rn->terrain, FORBIDDEN_REGION)) continue; - if (!fval(rn->terrain, SEA_REGION)) { - storm = false; - break; - } - if (rn!=next_point) rnext = rn; - } - } - if (storm && rnext!=NULL) { - ADDMSG(&f->msgs, msg_message("storm", "ship region sink", - sh, current_point, sh->damage>=sh->size * DAMAGE_SCALE)); - - /* damage the ship. we handle destruction in the end */ - damage_ship(sh, damage_drift()); - if (sh->damage>=sh->size * DAMAGE_SCALE) break; - - next_point = rnext; - /* these values need to be updated if next_point changes (due to storms): */ - tnext = next_point->terrain; - dir = reldirection(current_point, next_point); - } - } - } - - if (!fval(tthis, SEA_REGION)) { - if (!fval(tnext, SEA_REGION)) { - if (!move_on_land) { - /* check that you're not traveling from one land region to another. */ - ADDMSG(&u->faction->msgs, msg_message("shipnoshore", - "ship region", sh, next_point)); - break; - } - } else { - if (check_takeoff(sh, current_point, next_point) == false) { - /* Schiff kann nicht ablegen */ - cmistake(u, ord, 182, MSG_MOVE); - break; - } - } - } else if (fval(tnext, SEA_REGION)) { - /* target region is an ocean, and we're not leaving a shore */ - if (!(sh->type->flags & SFL_OPENSEA)) { - /* ship can only stay close to shore */ - direction_t d; - - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rc = rconnect(next_point, d); - if (rc==NULL || !fval(rc->terrain, SEA_REGION)) break; - } - if (d == MAXDIRECTIONS) { - /* Schiff kann nicht aufs offene Meer */ - cmistake(u, ord, 249, MSG_MOVE); - break; - } - } - } - - if (!ship_allowed(sh, next_point)) { - /* for some reason or another, we aren't allowed in there.. */ - if (check_leuchtturm(current_point, NULL)) { - ADDMSG(&f->msgs, msg_message("sailnolandingstorm", "ship", sh)); - } else { - ADDMSG(&f->msgs, msg_message("sailnolanding", "ship region", sh, next_point)); - damage_ship(sh, 0.10); - /* we handle destruction at the end */ - } - break; - } - - - if (curse_active(get_curse(next_point->attribs, ct_find("maelstrom")))) { - if (do_maelstrom(next_point, u) == NULL) break; - } - - } /* !flying_ship */ - - /* Falls Blockade, endet die Seglerei hier */ - if (move_blocked(u, current_point, next_point)) { - ADDMSG(&u->faction->msgs, msg_message("sailfail", "ship region", sh, current_point)); - break; - } - - /* Falls kein Problem, eines weiter ziehen */ - fset(sh, SF_MOVED); - if (iroute) { - add_regionlist(iroute, next_point); - iroute = &(*iroute)->next; - } - step++; - - last_point = current_point; - current_point = next_point; - - if (!fval(current_point->terrain, SEA_REGION) && !is_cursed(sh->attribs, C_SHIP_FLYING, 0)) break; - token = getstrtoken(); - error = movewhere(u, token, current_point, &next_point); - if (error || next_point == NULL) { - message * msg = movement_error(u, token, ord, error); - if (msg!=NULL) { - add_message(&u->faction->msgs, msg); - msg_release(msg); - } - next_point = current_point; - break; - } - } - - if (sh->damage>=sh->size * DAMAGE_SCALE) { - if (sh->region) { - ADDMSG(&f->msgs, msg_message("shipsink", "ship", sh)); - remove_ship(&sh->region->ships, sh); - } - sh = NULL; - } - - /* Nun enthält current_point die Region, in der das Schiff seine Runde - * beendet hat. Wir generieren hier ein Ereignis für den Spieler, das - * ihm sagt, bis wohin er gesegelt ist, falls er überhaupt vom Fleck - * gekommen ist. Das ist nicht der Fall, wenn er von der Küste ins - * Inland zu segeln versuchte */ - - if (sh!=NULL && fval(sh, SF_MOVED)) { - unit * hafenmeister; - /* nachdem alle Richtungen abgearbeitet wurden, und alle Einheiten - * transferiert wurden, kann der aktuelle Befehl gelöscht werden. */ - cycle_route(ord, u, step); - set_order(&u->thisorder, NULL); - set_coast(sh, last_point, current_point); - - if( is_cursed(sh->attribs, C_SHIP_FLYING, 0) ) { - ADDMSG(&f->msgs, msg_message("shipfly", "ship from to", sh, starting_point, current_point)); - } else { - ADDMSG(&f->msgs, msg_message("shipsail", "ship from to", sh, starting_point, current_point)); - } - - /* Das Schiff und alle Einheiten darin werden nun von - * starting_point nach current_point verschoben */ - - /* Verfolgungen melden */ - if (fval(u, UFL_FOLLOWING)) caught_target(current_point, u); - - sh = move_ship(sh, starting_point, current_point, *routep); - - /* Hafengebühren ? */ - - hafenmeister = owner_buildingtyp(current_point, bt_find("harbour")); - if (sh && hafenmeister != NULL) { - item * itm; - unit * u2; - item * trans = NULL; - - for (u2 = current_point->units; u2; u2 = u2->next) { - if (u2->ship == sh && - !alliedunit(hafenmeister, u->faction, HELP_GUARD)) { - - - if (effskill(hafenmeister, SK_PERCEPTION) > effskill(u2, SK_STEALTH)) { - for (itm=u2->items; itm; itm=itm->next) { - const luxury_type * ltype = resource2luxury(itm->type->rtype); - if (ltype!=NULL && itm->number>0) { - int st = itm->number * effskill(hafenmeister, SK_TRADE) / 50; - st = MIN(itm->number, st); - - if (st > 0) { - i_change(&u2->items, itm->type, -st); - i_change(&hafenmeister->items, itm->type, st); - i_add(&trans, i_new(itm->type, st)); - } - } - } - } - } - } - if (trans) { - message * msg = msg_message("harbor_trade", "unit items ship", hafenmeister, trans, u->ship); - add_message(&u->faction->msgs, msg); - add_message(&hafenmeister->faction->msgs, msg); - msg_release(msg); - while (trans) i_remove(&trans, trans); - } - } - } -} - -unit * -get_captain(const ship * sh) -{ - const region * r = sh->region; - unit *u; - - for (u = r->units; u; u = u->next) { - if (u->ship == sh && eff_skill(u, SK_SAILING, r) >= sh->type->cptskill) - return u; - } - - return NULL; -} - -/* Segeln, Wandern, Reiten -* when this routine returns a non-zero value, movement for the region needs -* to be done again because of followers that got new MOVE orders. -* Setting FL_LONGACTION will prevent a unit from being handled more than once -* by this routine -* -* the token parser needs to be initialized before calling this function! -*/ - -/** fleeing units use this function -*/ -void -run_to(unit * u, region * to) -{ - region_list * route = NULL; - add_regionlist(&route, to); - travel_route(u, route, NULL, NULL, TRAVEL_RUNNING); - free_regionlist(route); - /* weder transport noch follow */ -} - -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; - - if (u->building && !can_leave(u)) { - cmistake(u, u->thisorder, 150, MSG_MOVE); - return route_begin; - } - switch (canwalk(u)) { - case E_CANWALK_TOOHEAVY: - cmistake(u, ord, 57, MSG_MOVE); - return route_begin; - case E_CANWALK_TOOMANYHORSES: - cmistake(u, ord, 56, MSG_MOVE); - return route_begin; - case E_CANWALK_TOOMANYCARTS: - cmistake(u, ord, 42, MSG_MOVE); - return route_begin; - } - route_end = cap_route(r, route_begin, route_end, movement_speed(u)); - - route_end = travel_route(u, route_begin, route_end, ord, mode); - get_followers(u, r, route_end, followers); - - /* transportation */ - for (ord = u->orders; ord; ord = ord->next) { - unit * ut; - - if (get_keyword(ord) != K_TRANSPORT) continue; - - init_tokens(ord); - skip_token(); - ut = getunit(r, u->faction); - if (ut!=NULL) { - if (get_keyword(ut->thisorder) == K_DRIVE) { - if (ut->building && !can_leave(ut)) { - cmistake(ut, ut->thisorder, 150, MSG_MOVE); - cmistake(u, ord, 99, MSG_MOVE); - } else if (!can_move(ut)) { - cmistake(u, ord, 99, MSG_MOVE); - } else { - boolean found = false; - - if (!fval(ut, UFL_NOTMOVING) && !LongHunger(ut)) { - init_tokens(ut->thisorder); - skip_token(); - if (getunit(u->region, ut->faction) == u) { - const region_list * route_to = travel_route(ut, route_begin, route_end, ord, TRAVEL_TRANSPORTED); - - if (route_to!=route_begin) { - get_followers(ut, r, route_to, followers); - } - ADDMSG(&ut->faction->msgs, msg_message("transport", - "unit target start end", u, ut, r, ut->region)); - found = true; - } - } - if (!found) { - if (cansee(u->faction, u->region, ut, 0)) { - cmistake(u, ord, 90, MSG_MOVE); - } else { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } - } - } - } - } else { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } - } - return route_end; -} - -/** traveling without ships - * walking, flying or riding units use this function - */ -static void -travel(unit * u, region_list ** routep) -{ - region * r = u->region; - region_list * route_begin = NULL; - follower * followers = NULL; - - if (routep) *routep = NULL; - - /* a few pre-checks that need not be done for each step: */ - if (!fval(r->terrain, SEA_REGION)) { - ship * sh = u->ship; - - if (!can_leave(u)) { - cmistake(u, u->thisorder, 150, MSG_MOVE); - return; - } - - /* An Land kein NACH wenn in dieser Runde Schiff VERLASSEN! */ - if (sh == NULL) { - sh = leftship(u); - if (sh && sh->region!=u->region) sh = NULL; - } - if (sh) { - unit * guard = is_guarded(r, u, GUARD_LANDING); - if (guard) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "region_guarded", "guard", guard)); - return; - } - } - if (u->ship && u->race->flags & RCF_SWIM) { - cmistake(u, u->thisorder, 143, MSG_MOVE); - return; - } - } - else if (u->ship && fval(u->ship, SF_MOVED)) { - /* die Einheit ist auf einem Schiff, das sich bereits bewegt hat */ - cmistake(u, u->thisorder, 13, MSG_MOVE); - return; - } - - make_route(u, u->thisorder, routep); - route_begin = *routep; - - /* und ab die post: */ - travel_i(u, route_begin, NULL, u->thisorder, TRAVEL_NORMAL, &followers); - - /* followers */ - while (followers!=NULL) { - follower * fnext = followers->next; - unit * uf = followers->uf; - unit * ut = followers->ut; - const region_list * route_end = followers->route_end; - - free(followers); - followers = fnext; - - if (uf->region == r) { - order * follow_order; - const struct locale * lang = u->faction->locale; - - /* construct an order */ - follow_order = create_order(K_FOLLOW, lang, "%s %i", - LOC(uf->faction->locale, parameters[P_UNIT]), ut->no); - - route_end = reroute(uf, route_begin, route_end); - travel_i(uf, route_begin, route_end, follow_order, TRAVEL_FOLLOWING, &followers); - caught_target(uf->region, uf); - free_order(follow_order); - } - } - -} - -static void -move(unit * u, boolean move_on_land) -{ - region_list * route = NULL; - - assert(u->number); - if (u->ship && fval(u, UFL_OWNER)) { - sail(u, u->thisorder, move_on_land, &route); - } else { - travel(u, &route); - } - - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - set_order(&u->thisorder, NULL); - - if (route!=NULL) free_regionlist(route); -} - -typedef struct piracy_data { - const struct faction * pirate; - const struct faction * target; - direction_t dir; -} piracy_data; - -static void -piracy_init(struct attrib * a) -{ - a->data.v = calloc(1, sizeof(piracy_data)); -} - -static void -piracy_done(struct attrib * a) -{ - free(a->data.v); -} - -static attrib_type at_piracy_direction = { - "piracy_direction", - piracy_init, - piracy_done, - DEFAULT_AGE, - NO_WRITE, - NO_READ -}; - -static attrib * -mk_piracy(const faction * pirate, const faction * target, direction_t target_dir) -{ - attrib * a = a_new(&at_piracy_direction); - piracy_data * data = a->data.v; - data->pirate = pirate; - data->target = target; - data->dir = target_dir; - return a; -} - -static void -piracy_cmd(unit *u, struct order * ord) -{ - region *r = u->region; - ship *sh = u->ship, *sh2; - direction_t dir, target_dir = NODIRECTION; - struct { - const faction * target; - int value; - } aff[MAXDIRECTIONS]; - int saff = 0; - int *il = NULL; - const char *s; - attrib *a; - - if (!sh) { - cmistake(u, ord, 144, MSG_MOVE); - return; - } - - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 146, MSG_MOVE); - return; - } - - /* Feststellen, ob schon ein anderer alliierter Pirat ein - * Ziel gefunden hat. */ - - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - if (s!=NULL && *s) { - il = intlist_init(); - while (s && *s) { - il = intlist_add(il, atoi36(s)); - s = getstrtoken(); - } - } - - for (a = a_find(r->attribs, &at_piracy_direction); a && a->type==&at_piracy_direction; a=a->next) { - piracy_data * data = a->data.v; - const faction * p = data->pirate; - const faction * t = data->target; - - if (alliedunit(u, p, HELP_FIGHT)) { - if (il == 0 || (t && intlist_find(il, t->no))) { - target_dir = data->dir; - break; - } - } - } - - /* Wenn nicht, sehen wir, ob wir ein Ziel finden. */ - - if (target_dir == NODIRECTION) { - /* Einheit ist also Kapitän. Jetzt gucken, in wievielen - * Nachbarregionen potentielle Opfer sind. */ - - for(dir = 0; dir < MAXDIRECTIONS; dir++) { - region *rc = rconnect(r, dir); - aff[dir].value = 0; - aff[dir].target = 0; - if (rc && fval(rc->terrain, SWIM_INTO) - && check_takeoff(sh, r, rc) == true) { - - for (sh2 = rc->ships; sh2; sh2 = sh2->next) { - unit * cap = shipowner(sh2); - if (cap) { - faction * f = visible_faction(cap->faction, cap); - if (alliedunit(u, f, HELP_FIGHT)) continue; - if (il == 0 || intlist_find(il, cap->faction->no)) { - ++aff[dir].value; - if (rng_int() % aff[dir].value == 0) { - aff[dir].target = f; - } - } - } - } - - /* Und aufaddieren. */ - saff += aff[dir].value; - } - } - - if (saff != 0) { - saff = rng_int() % saff; - for (dir=0; dir!=MAXDIRECTIONS; ++dir) { - if (saff!=aff[dir].value) break; - saff -= aff[dir].value; - } - target_dir = dir; - a = a_add(&r->attribs, mk_piracy(u->faction, aff[dir].target, target_dir)); - } - } - - free(il); - - /* Wenn kein Ziel gefunden, entsprechende Meldung generieren */ - if (target_dir == NODIRECTION) { - ADDMSG(&u->faction->msgs, msg_message("piratenovictim", - "ship region", sh, r)); - return; - } - - /* Meldung generieren */ - ADDMSG(&u->faction->msgs, msg_message("piratesawvictim", - "ship region dir", sh, r, target_dir)); - - /* Befehl konstruieren */ - set_order(&u->thisorder, create_order(K_MOVE, u->faction->locale, "%s", - LOC(u->faction->locale, directions[target_dir]))); - - /* Bewegung ausführen */ - init_tokens(u->thisorder); - skip_token(); - move(u, true); -} - -static void -age_traveldir(region *r) -{ - attrib *a = a_find(r->attribs, &at_traveldir); - - while(a && a->type==&at_traveldir) { - attrib *an = a->next; - a->data.ca[3]--; - if(a->data.ca[3] <= 0) { - a_remove(&r->attribs, a); - } - a = an; - } -} - -static direction_t -hunted_dir(attrib *at, int id) -{ - attrib *a = a_find(at, &at_shiptrail); - direction_t d = NODIRECTION; - - while (a!=NULL && a->type==&at_shiptrail) { - traveldir *t = (traveldir *)(a->data.v); - if (t->no == id) { - d = t->dir; - /* do not break, because we want the last one for this ship */ - } - a = a->next; - } - - return d; -} - -static int -hunt(unit *u, order * ord) -{ - region *rc = u->region; - int bytes, moves, id, speed; - char command[256], * bufp = command; - size_t size = sizeof(command); - direction_t dir; - - if (fval(u, UFL_NOTMOVING)) { - return 0; - } else if (u->ship == NULL) { - cmistake(u, ord, 144, MSG_MOVE); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ - return 0; - } else if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 146, MSG_MOVE); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ - return 0; - } else if (!can_move(u)) { - cmistake(u, ord, 55, MSG_MOVE); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ - return 0; - } - - id = getshipid(); - - if (id <= 0) { - cmistake(u, ord, 20, MSG_MOVE); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ - return 0; - } - - dir = hunted_dir(rc->attribs, id); - - if (dir == NODIRECTION) { - ship * sh = findship(id); - if (sh == NULL || sh->region!=rc) { - cmistake(u, ord, 20, MSG_MOVE); - } - fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ - return 0; - } - - bufp = command; - bytes = snprintf(bufp, size, "%s %s", LOC(u->faction->locale, keywords[K_MOVE]), - LOC(u->faction->locale, directions[dir])); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - moves = 1; - - speed = getuint(); - if (speed==0) { - speed = shipspeed(u->ship, u); - } else { - int maxspeed = shipspeed(u->ship, u); - if (maxspeedattribs, id)) != NODIRECTION) - { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(u->faction->locale, directions[dir]), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - moves++; - rc = rconnect(rc, dir); - } - - /* In command steht jetzt das NACH-Kommando. */ - - /* NACH ignorieren und Parsing initialisieren. */ - igetstrtoken(command); - /* NACH ausführen */ - move(u, false); - return 1; /* true -> Einheitenliste von vorne durchgehen */ -} - -void -destroy_damaged_ships(void) -{ - region *r; - ship *sh,*shn; - - for(r=regions;r;r=r->next) { - for(sh=r->ships;sh;) { - shn = sh->next; - if (sh->damage>=sh->size * DAMAGE_SCALE) { - remove_ship(&sh->region->ships, sh); - } - sh = shn; - } - } -} - -/* Bewegung, Verfolgung, Piraterie */ - -/** ships that folow other ships - * Dann generieren die jagenden Einheiten ihre Befehle und - * bewegen sich. - * Following the trails of other ships. - */ -static void -move_hunters(void) -{ - region *r; - - for (r = regions; r; r = r->next) { - unit ** up = &r->units; - - while (*up!=NULL) { - unit * u = *up; - - if (!fval(u, UFL_MOVED|UFL_NOTMOVING)) { - order * ord; - - for (ord=u->orders;ord;ord=ord->next) { - if (get_keyword(ord) == K_FOLLOW) { - param_t p; - - init_tokens(ord); - skip_token(); - p = getparam(u->faction->locale); - if (p != P_SHIP) { - if (p != P_UNIT) { - cmistake(u, ord, 240, MSG_MOVE); - } - break; - } - - /* wir folgen definitiv einem Schiff. */ - - if (fval(u, UFL_NOTMOVING)) { - cmistake(u, ord, 52, MSG_MOVE); - break; - } else if (!can_move(u)) { - cmistake(u, ord, 55, MSG_MOVE); - break; - } - - if (!fval(u, UFL_NOTMOVING) && !LongHunger(u) && hunt(u, ord)) { - up = &r->units; - break; - } - } - } - } - if (*up == u) up=&u->next; - } - } -} - -/** Piraten and Drift - * - */ -static void -move_pirates(void) -{ - region * r; - - for (r = regions; r; r = r->next) { - unit ** up = &r->units; - - while (*up) { - unit *u = *up; - - if (!fval(u, UFL_NOTMOVING) && get_keyword(u->thisorder) == K_PIRACY) { - piracy_cmd(u, u->thisorder); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - } - - if (*up == u) { - /* not moved, use next unit */ - up = &u->next; - } else if (*up && (*up)->region!=r) { - /* moved the previous unit along with u (units on same ship) - * must start from the beginning again */ - up = &r->units; - } - /* else *up is already the next unit */ - } - - a_removeall(&r->attribs, &at_piracy_direction); - age_traveldir(r); - } -} - -void -movement(void) -{ - int ships; - - /* Initialize the additional encumbrance by transported units */ - init_transportation(); - - /* Move ships in last phase, others first - * This is to make sure you can't land someplace and then get off the ship - * in the same turn. - */ - for (ships=0;ships<=1;++ships) { - region * r = regions; - while (r!=NULL) { - unit ** up = &r->units; - boolean repeat = false; - - while (*up) { - unit *u = *up; - keyword_t kword; - - if (u->ship && fval(u->ship, SF_DRIFTED)) { - up = &u->next; - continue; - } - kword = get_keyword(u->thisorder); - - switch (kword) { - case K_ROUTE: - case K_MOVE: - /* after moving, the unit has no thisorder. this prevents - * it from moving twice (or getting error messages twice). - * UFL_NOTMOVING is set in combat if the unit is not allowed - * to move because it was involved in a battle. - */ - if (fval(u, UFL_NOTMOVING)) { - if (fval(u, UFL_LONGACTION)) { - cmistake(u, u->thisorder, 52, MSG_MOVE); - set_order(&u->thisorder, NULL); - } else { - cmistake(u, u->thisorder, 319, MSG_MOVE); - set_order(&u->thisorder, NULL); - } - } else if (fval(u, UFL_MOVED)) { - cmistake(u, u->thisorder, 187, MSG_MOVE); - set_order(&u->thisorder, NULL); - } else if (!can_move(u)) { - cmistake(u, u->thisorder, 55, MSG_MOVE); - set_order(&u->thisorder, NULL); - } else { - if (ships) { - if (u->ship && fval(u, UFL_OWNER)) { - init_tokens(u->thisorder); - skip_token(); - move(u, false); - } - } else { - if (u->ship == NULL || !fval(u, UFL_OWNER)) { - init_tokens(u->thisorder); - skip_token(); - move(u, false); - } - } - } - break; - } - if (u->region == r) { - /* not moved, use next unit */ - up = &u->next; - } else { - if (*up && (*up)->region!=r) { - /* moved the upcoming unit along with u (units on ships or followers, - * for example). must start from the beginning again immediately */ - up = &r->units; - repeat = false; - } else { - repeat = true; - } - } - /* else *up is already the next unit */ - } - if (repeat) continue; - if (ships == 0) { - /* Abtreiben von beschädigten, unterbemannten, überladenen Schiffen */ - drifting_ships(r); - } - r = r->next; - } - } - - move_hunters(); - move_pirates(); -} - -/** Overrides long orders with a FOLLOW order if the target is moving. - * FOLLOW SHIP is a long order, and doesn't need to be treated in here. - * BUGS: http://bugs.eressea.de/view.php?id=1444 (A folgt B folgt C) - */ -void -follow_unit(unit * u) -{ - region * r = u->region; - attrib * a = NULL; - order * ord; - - if (fval(u, UFL_NOTMOVING) || LongHunger(u)) return; - - for (ord=u->orders;ord;ord=ord->next) { - const struct locale * lang = u->faction->locale; - - if (get_keyword(ord) == K_FOLLOW) { - init_tokens(ord); - skip_token(); - if (getparam(lang) == P_UNIT) { - int id = read_unitid(u->faction, r); - - if (a!=NULL) { - a = a_find(u->attribs, &at_follow); - } - - if (id>0) { - unit * uf = findunit(id); - if (!a) { - a = a_add(&u->attribs, make_follow(uf)); - } else { - a->data.v = uf; - } - } else if (a) { - a_remove(&u->attribs, a); - a = NULL; - } - } - } - } - - if (a && !fval(u, UFL_MOVED|UFL_NOTMOVING)) { - unit * u2 = a->data.v; - boolean follow = false; - - if (!u2 || u2->region!=r || !cansee(u->faction, r, u2, 0)) { - return; - } - - switch (get_keyword(u2->thisorder)) { - case K_MOVE: - case K_ROUTE: - case K_DRIVE: - follow = true; - break; - default: - for (ord=u2->orders;ord;ord=ord->next) { - switch (get_keyword(ord)) { - case K_FOLLOW: - case K_PIRACY: - follow = true; - break; - default: - continue; - } - break; - } - break; - } - if (!follow) { - attrib * a2 = a_find(u2->attribs, &at_follow); - if (a2!=NULL) { - unit * u3 = a2->data.v; - follow = (u3 && u2->region == u2->region); - } - } - if (follow) { - fset(u, UFL_FOLLOWING); - fset(u2, UFL_FOLLOWED); - set_order(&u->thisorder, NULL); - } - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "move.h" + +#include "alchemy.h" +#include "connection.h" +#include "build.h" +#include "building.h" +#include "calendar.h" +#include "curse.h" +#include "faction.h" +#include "item.h" +#include "magic.h" +#include "message.h" +#include "order.h" +#include "plane.h" +#include "race.h" +#include "region.h" +#include "render.h" +#include "reports.h" +#include "save.h" +#include "ship.h" +#include "skill.h" +#include "terrain.h" +#include "teleport.h" +#include "unit.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* attributes includes */ +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +int * storms; + +typedef struct traveldir { + int no; + direction_t dir; + int age; +} traveldir; + +static attrib_type at_traveldir = { + "traveldir", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, /* Weil normales Aging an ungünstiger Stelle */ + a_writechars, + a_readchars +}; + +typedef struct follower { + struct follower * next; + unit * uf; + unit * ut; + const region_list * route_end; +} follower; + +static void +get_followers(unit * target, region * r, const region_list * route_end, follower ** followers) +{ + unit * uf; + for (uf=r->units;uf;uf=uf->next) { + if (fval(uf, UFL_FOLLOWING) && !fval(uf, UFL_NOTMOVING)) { + const attrib * a = a_findc(uf->attribs, &at_follow); + if (a && a->data.v == target) { + follower * fnew = malloc(sizeof(follower)); + fnew->uf = uf; + fnew->ut = target; + fnew->route_end = route_end; + fnew->next = *followers; + *followers = fnew; + } + } + } +} + +static void +shiptrail_init(attrib *a) +{ + a->data.v = calloc(1, sizeof(traveldir)); +} + +static void +shiptrail_finalize(attrib *a) +{ + free(a->data.v); +} + +static int +shiptrail_age(attrib *a) +{ + traveldir *t = (traveldir *)(a->data.v); + + t->age--; + return (t->age>0)?AT_AGE_KEEP:AT_AGE_REMOVE; +} + +static int +shiptrail_read(attrib *a, void * owner, struct storage * store) +{ + traveldir *t = (traveldir *)(a->data.v); + + t->no = store->r_int(store); + t->dir = (direction_t)store->r_int(store); + t->age = store->r_int(store); + return AT_READ_OK; +} + +static void +shiptrail_write(const attrib * a, const void * owner, struct storage * store) +{ + traveldir *t = (traveldir *)(a->data.v); + store->w_int(store, t->no); + store->w_int(store, t->dir); + store->w_int(store, t->age); +} + +attrib_type at_shiptrail = { + "traveldir_new", + shiptrail_init, + shiptrail_finalize, + shiptrail_age, + shiptrail_write, + shiptrail_read +}; + +static int +age_speedup(attrib *a) +{ + if (a->data.sa[0] > 0) { + a->data.sa[0] = a->data.sa[0] - a->data.sa[1]; + } + return (a->data.sa[0]>0)?AT_AGE_KEEP:AT_AGE_REMOVE; +} + +attrib_type at_speedup = { + "speedup", + NULL, NULL, + age_speedup, + a_writeint, + a_readint +}; + +/* ------------------------------------------------------------- */ + +direction_t +getdirection(const struct locale * lang) +{ + return finddirection(getstrtoken(), lang); +} +/* ------------------------------------------------------------- */ + +static attrib_type at_driveweight = { + "driveweight", NULL, NULL, NULL, NULL, NULL +}; + +static boolean +entrance_allowed(const struct unit * u, const struct region * r) +{ +#ifdef REGIONOWNERS + faction * owner = region_get_owner(r); + if (owner == NULL || u->faction == owner) return true; + if (alliedfaction(rplane(r), owner, u->faction, HELP_TRAVEL)) return true; + return false; +#else + return true; +#endif +} + +int +personcapacity(const unit *u) +{ + int cap = u->race->weight+u->race->capacity; + return cap; +} + +static int +eff_weight(const unit *u) +{ + attrib *a = a_find(u->attribs, &at_driveweight); + + if (a) return weight(u) + a->data.i; + + return weight(u); +} + +static void +get_transporters(const item * itm, int * p_animals, int *p_acap, int * p_vehicles, int * p_vcap) +{ + int vehicles = 0, vcap = 0; + int animals = 0, acap = 0; + + for (;itm!=NULL;itm=itm->next) { + const item_type * itype = itm->type; + if (itype->capacity>0) { + if (itype->flags & ITF_ANIMAL) { + animals += itm->number; + if (acap==0) acap = itype->capacity; + assert(acap==itype->capacity || !"animals with different capacity not supported"); + } + if (itype->flags & ITF_VEHICLE) { + vehicles += itm->number; + if (vcap==0) vcap = itype->capacity; + assert(vcap==itype->capacity || !"vehicles with different capacity not supported"); + } + } + } + *p_vehicles = vehicles; + *p_animals = animals; + *p_vcap = vcap; + *p_acap = acap; +} + +static int +ridingcapacity(unit * u) +{ + int vehicles = 0, vcap = 0; + int animals = 0, acap = 0; + + get_transporters(u->items, &animals, &acap, &vehicles, &vcap); + + /* Man trägt sein eigenes Gewicht plus seine Kapazität! Die Menschen + ** tragen nichts (siehe walkingcapacity). Ein Wagen zählt nur, wenn er + ** von zwei Pferden gezogen wird */ + + animals = MIN(animals, effskill(u, SK_RIDING) * u->number * 2); + if (fval(u->race, RCF_HORSE)) animals += u->number; + + /* maximal diese Pferde können zum Ziehen benutzt werden */ + vehicles = MIN(animals / HORSESNEEDED, vehicles); + + return vehicles * vcap + animals * acap; +} + +int +walkingcapacity(const struct unit * u) +{ + int n, tmp, people, pferde_fuer_wagen; + int wagen_ohne_pferde, wagen_mit_pferden, wagen_mit_trollen; + int vehicles = 0, vcap = 0; + int animals = 0, acap = 0; + + get_transporters(u->items, &animals, &acap, &vehicles, &vcap); + + /* Das Gewicht, welches die Pferde tragen, plus das Gewicht, welches + * die Leute tragen */ + + pferde_fuer_wagen = MIN(animals, effskill(u, SK_RIDING) * u->number * 4); + if (fval(u->race, RCF_HORSE)) { + animals += u->number; + people = 0; + } else { + people = u->number; + } + + /* maximal diese Pferde können zum Ziehen benutzt werden */ + wagen_mit_pferden = MIN(vehicles, pferde_fuer_wagen / HORSESNEEDED); + + n = wagen_mit_pferden * vcap; + + if (u->race == new_race[RC_TROLL]) { + /* 4 Trolle ziehen einen Wagen. */ + /* Unbesetzte Wagen feststellen */ + wagen_ohne_pferde = vehicles - wagen_mit_pferden; + + /* Genug Trolle, um die Restwagen zu ziehen? */ + wagen_mit_trollen = MIN(u->number / 4, wagen_ohne_pferde); + + /* Wagenkapazität hinzuzählen */ + n += wagen_mit_trollen * vcap; + wagen_ohne_pferde -= wagen_mit_trollen; + } + + n += animals * acap; + n += people * personcapacity(u); + /* Goliathwasser */ + tmp = get_effect(u, oldpotiontype[P_STRONG]); + if (tmp>0) { + int horsecap = olditemtype[I_HORSE]->capacity; + if (tmp>people) tmp = people; + n += tmp * (horsecap - personcapacity(u)); + } + /* change_effect wird in ageing gemacht */ + tmp = get_item(u, I_TROLLBELT); + n += MIN(people, tmp) * (STRENGTHMULTIPLIER-1) * personcapacity(u); + + return n; +} + +enum { + E_CANWALK_OK = 0, + E_CANWALK_TOOMANYHORSES, + E_CANWALK_TOOMANYCARTS, + E_CANWALK_TOOHEAVY +}; + +static int +canwalk(unit * u) +{ + int maxwagen, maxpferde; + int vehicles = 0, vcap = 0; + int animals = 0, acap = 0; + + /* workaround: monsters are too stupid to drop items, therefore they have + * infinite carrying capacity */ + + if (is_monsters(u->faction)) return E_CANWALK_OK; + + get_transporters(u->items, &animals, &acap, &vehicles, &vcap); + + maxwagen = effskill(u, SK_RIDING) * u->number * 2; + if (u->race == new_race[RC_TROLL]) { + maxwagen = MAX(maxwagen, u->number / 4); + } + maxpferde = effskill(u, SK_RIDING) * u->number * 4 + u->number; + + if (animals > maxpferde) + return E_CANWALK_TOOMANYHORSES; + + if (walkingcapacity(u) - eff_weight(u) >= 0) + return E_CANWALK_OK; + + /* Stimmt das Gewicht, impliziert dies hier, daß alle Wagen ohne + * Zugpferde/-trolle als Fracht aufgeladen wurden: zu viele Pferde hat + * die Einheit nicht zum Ziehen benutzt, also nicht mehr Wagen gezogen + * als erlaubt. */ + + if (vehicles > maxwagen) + return E_CANWALK_TOOMANYCARTS; + /* Es muß nicht zwingend an den Wagen liegen, aber egal... (man + * könnte z.B. auch 8 Eisen abladen, damit ein weiterer Wagen als + * Fracht draufpaßt) */ + + return E_CANWALK_TOOHEAVY; +} + +boolean +canfly(unit *u) +{ + if (get_item(u, I_PEGASUS) >= u->number && effskill(u, SK_RIDING) >= 4) + return true; + + if (fval(u->race, RCF_FLY)) return true; + + if (get_movement(&u->attribs, MV_FLY)) return true; + + return false; +} + +boolean +canswim(unit *u) +{ + if (get_item(u, I_DOLPHIN) >= u->number && effskill(u, SK_RIDING) >= 4) + return true; + + if (u->race->flags & RCF_FLY) return true; + + if (u->race->flags & RCF_SWIM) return true; + + if (get_movement(&u->attribs, MV_FLY)) return true; + + if (get_movement(&u->attribs, MV_SWIM)) return true; + + return false; +} + +static int +canride(unit * u) +{ + int horses = 0, maxhorses, unicorns = 0, maxunicorns; + int skill = effskill(u, SK_RIDING); + item * itm; + static const item_type * it_horse = 0; + static const item_type * it_elvenhorse = 0; + static const item_type * it_charger = 0; + + if (it_horse==0) { + it_horse = it_find("horse"); + it_elvenhorse = it_find("elvenhorse"); + it_charger = it_find("charger"); + } + + for (itm=u->items;itm;itm=itm->next) { + if (itm->type==it_horse || itm->type==it_charger) { + horses += itm->number; + } else if (itm->type==it_elvenhorse) { + unicorns += itm->number; + } + } + + maxunicorns = (skill/5) * u->number; + maxhorses = skill * u->number * 2; + + if(!(u->race->flags & RCF_HORSE) + && ((horses == 0 && unicorns == 0) + || horses > maxhorses || unicorns > maxunicorns)) { + return 0; + } + + if (ridingcapacity(u) - eff_weight(u) >= 0) { + if (horses == 0 && unicorns >= u->number && !(u->race->flags & RCF_HORSE)) { + return 2; + } + return 1; + } + + return 0; +} + +static boolean +cansail(const region * r, ship * sh) +{ + /* sonst ist construction:: size nicht ship_type::maxsize */ + assert(!sh->type->construction || sh->type->construction->improvement == NULL); + + if (sh->type->construction && sh->size!=sh->type->construction->maxsize) { + return false; + } else { + int n = 0, p = 0; + int mweight = shipcapacity(sh); + int mcabins = sh->type->cabins; + + getshipweight(sh, &n, &p); + + if (n > mweight) return false; + if (mcabins && p > mcabins) return false; + } + return true; +} + +int +enoughsailors(const ship * sh, const region * r) +{ + int n; + unit *u; + + n = 0; + + for (u = r->units; u; u = u->next) { + if (u->ship == sh) + n += eff_skill(u, SK_SAILING, r) * u->number; + } + return n >= sh->type->sumskill; +} +/* ------------------------------------------------------------- */ + +static ship * +do_maelstrom(region *r, unit *u) +{ + int damage; + ship * sh = u->ship; + + damage = rng_int()%75 + rng_int()%75 - eff_skill(u, SK_SAILING, r)*4; + + if (damage <= 0) { + return sh; + } + + damage_ship(u->ship, 0.01*damage); + + if (sh->damage >= sh->size * DAMAGE_SCALE) { + ADDMSG(&u->faction->msgs, msg_message("entermaelstrom", + "region ship damage sink", r, sh, damage, 1)); + remove_ship(&sh->region->ships, sh); + return NULL; + } + ADDMSG(&u->faction->msgs, msg_message("entermaelstrom", + "region ship damage sink", r, sh, damage, 0)); + return u->ship; +} + +/** sets a marker in the region telling that the unit has travelled through it + * this is used for two distinctly different purposes: + * - to report that a unit has travelled through. the report function + * makes sure to only report the ships of travellers, not the travellers + * themselves + * - to report the region to the traveller + */ +void +travelthru(const unit * u, region * r) +{ + attrib *ru = a_add(&r->attribs, a_new(&at_travelunit)); + + fset(r, RF_TRAVELUNIT); + + ru->data.v = (void*)u; + + /* the first and last region of the faction gets reset, because travelthrough + * could be in regions that are located before the [first, last] interval, + * and recalculation is needed */ +#ifdef SMART_INTERVALS + update_interval(u->faction, r); +#endif +} + +static void +leave_trail(ship * sh, region * from, region_list *route) +{ + region * r = from; + + while (route!=NULL) { + region * rn = route->data; + direction_t dir = reldirection(r, rn); + + /* TODO: we cannot leave a trail into special directions + * if we use this kind of direction-attribute */ + if (dir=0) { + traveldir * td = NULL; + attrib * a = a_find(r->attribs, &at_shiptrail); + + while (a!=NULL && a->type==&at_shiptrail) { + td = (traveldir *)a->data.v; + if (td->no == sh->no) break; + a = a->next; + } + + if (a == NULL || a->type!=&at_shiptrail) { + a = a_add(&(r->attribs), a_new(&at_shiptrail)); + td = (traveldir *)a->data.v; + td->no = sh->no; + } + td->dir = dir; + td->age = 2; + } + route = route->next; + r = rn; + } +} + +static void +mark_travelthru(const unit * u, region * r, const region_list * route, const region_list * route_end) +{ + /* kein travelthru in der letzten region! */ + while (route!=route_end) { + travelthru(u, r); + r = route->data; + route = route->next; + } +} + +ship * +move_ship(ship * sh, region * from, region * to, region_list * route) +{ + unit **iunit = &from->units; + unit **ulist = &to->units; + boolean trail = (route == NULL); + + if (from!=to) { + translist(&from->ships, &to->ships, sh); + sh->region = to; + } + if (!trail) { + leave_trail(sh, from, route); + trail = true; + } + + while (*iunit!=NULL) { + unit *u = *iunit; + assert(u->region == from); + + if (u->ship == sh) { + if (route!=NULL) mark_travelthru(u, from, route, NULL); + if (from!=to) { + u->ship = NULL; /* damit move_unit() kein leave() macht */ + move_unit(u, to, ulist); + ulist = &u->next; + u->ship = sh; + } + if (route && eff_skill(u, SK_SAILING, from) >= 1) { + produceexp(u, SK_SAILING, u->number); + } + } + if (*iunit == u) iunit=&u->next; + } + + return sh; +} + +static boolean +is_freezing(const unit * u) +{ + if (u->race!=new_race[RC_INSECT]) return false; + if (is_cursed(u->attribs, C_KAELTESCHUTZ, 0)) return false; + return true; +} + +static boolean +ship_allowed(const struct ship * sh, const region * r) +{ + int c = 0; + static const building_type * bt_harbour=NULL; + + if (bt_harbour == NULL) bt_harbour=bt_find("harbour"); + + if (r_insectstalled(r)) { + /* insekten dürfen nicht hier rein. haben wir welche? */ + unit * u; + + for (u=sh->region->units;u!=NULL;u=u->next) { + if (u->ship!=sh) continue; + + if (is_freezing(u)) { + unit * captain = shipowner(sh); + if (captain) { + ADDMSG(&captain->faction->msgs, msg_message("detectforbidden", + "unit region", u, r)); + } + + return false; + } + } + } + + if (buildingtype_exists(r, bt_harbour, true)) return true; + for (c=0;sh->type->coasts[c]!=NULL;++c) { + if (sh->type->coasts[c] == r->terrain) return true; + } + + return false; +} + +static boolean +flying_ship(const ship * sh) +{ + if (sh->type->flags & SFL_FLY) return true; + if (sh->flags & SF_FLYING) return true; + return false; +} + +static void +set_coast(ship * sh, region * r, region * rnext) +{ + if (sh->type->flags & SFL_NOCOAST) { + sh->coast = NODIRECTION; + } else if (!fval(rnext->terrain, SEA_REGION) && !flying_ship(sh)) { + sh->coast = reldirection(rnext, r); + assert(fval(r->terrain, SEA_REGION)); + } else { + sh->coast = NODIRECTION; + } +} + +static float +damage_drift(void) +{ + static float value = -1.0F; + if (value<0) { + value = get_param_flt(global.parameters, "rules.ship.damage_drift", 0.02F); + } + return value; +} + +static void +drifting_ships(region * r) +{ + direction_t d; + + if (fval(r->terrain, SEA_REGION)) { + ship** shp = &r->ships; + while (*shp) { + ship * sh = *shp; + region * rnext = NULL; + region_list * route = NULL; + unit *firstu = NULL, *captain; + int d_offset; + direction_t dir = 0; + + if (sh->type->fishing>0) { + sh->flags |= SF_FISHING; + } + + /* Schiff schon abgetrieben oder durch Zauber geschützt? */ + if (fval(sh, SF_DRIFTED) || is_cursed(sh->attribs, C_SHIP_NODRIFT, 0)) { + shp = &sh->next; + continue; + } + + /* Kapitän bestimmen */ + for (captain = r->units; captain; captain = captain->next) { + if (captain->ship != sh) continue; + if (firstu==NULL) firstu = captain; + if (eff_skill(captain, SK_SAILING, r) >= sh->type->cptskill) { + break; + } + } + /* Kapitän da? Beschädigt? Genügend Matrosen? + * Genügend leicht? Dann ist alles OK. */ + + assert(sh->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (captain && sh->size == sh->type->construction->maxsize && enoughsailors(sh, r) && cansail(r, sh)) { + shp = &sh->next; + continue; + } + + /* Auswahl einer Richtung: Zuerst auf Land, dann + * zufällig. Falls unmögliches Resultat: vergiß es. */ + d_offset = rng_int() % MAXDIRECTIONS; + for (d = 0; d != MAXDIRECTIONS; ++d) { + region * rn; + dir = (direction_t)((d + d_offset) % MAXDIRECTIONS); + rn = rconnect(r, dir); + if (rn!=NULL && fval(rn->terrain, SAIL_INTO) && ship_allowed(sh, rn)) { + rnext = rn; + if (!fval(rnext->terrain, SEA_REGION)) break; + } + } + + if (rnext == NULL) { + shp = &sh->next; + continue; + } + + /* Das Schiff und alle Einheiten darin werden nun von r + * nach rnext verschoben. Danach eine Meldung. */ + add_regionlist(&route, rnext); + + set_coast(sh, r, rnext); + sh = move_ship(sh, r, rnext, route); + free_regionlist(route); + + if (firstu!=NULL) { + unit *u, *lastu = NULL; + message * msg = msg_message("ship_drift", "ship dir", sh, dir); + for (u=firstu;u;u=u->next) { + if (u->ship==sh && !fval(u->faction, FFL_MARK)) { + fset(u->faction, FFL_MARK); + add_message(&u->faction->msgs, msg); + lastu = u->next; + } + } + for (u=firstu;u!=lastu;u=u->next) { + freset(u->faction, FFL_MARK); + } + msg_release(msg); + } + + if (sh!=NULL) { + fset(sh, SF_DRIFTED); + + damage_ship(sh, damage_drift()); + if (sh->damage>=sh->size * DAMAGE_SCALE) { + remove_ship(&sh->region->ships, sh); + } + } + + if (*shp == sh) shp = &sh->next; + } + } +} + +static boolean +present(region * r, unit * u) +{ + return (boolean) (u && u->region == r); +} + +static void +caught_target(region * r, unit * u) +{ + attrib * a = a_find(u->attribs, &at_follow); + + /* Verfolgungen melden */ + /* Misserfolgsmeldung, oder bei erfolgreichem Verfolgen unter + * Umstaenden eine Warnung. */ + + if (a) { + unit * target = (unit*)a->data.v; + + if (!present(r, target)) { + ADDMSG(&u->faction->msgs, msg_message("followfail", "unit follower", + target, u)); + } else if (!alliedunit(target, u->faction, HELP_ALL) + && cansee(target->faction, r, u, 0)) + { + ADDMSG(&target->faction->msgs, msg_message("followdetect", + "unit follower", target, u)); + } + } +} + +/* TODO: Unsichtbarkeit bedenken ! */ + +static unit * +bewegung_blockiert_von(unit * reisender, region * r) +{ + unit *u; + int perception = 0; + boolean contact = false; + unit * guard = NULL; + + if (fval(reisender->race, RCF_ILLUSIONARY)) return NULL; + for (u=r->units;u && !contact;u=u->next) { + if (is_guard(u, GUARD_TRAVELTHRU)) { + int sk = eff_skill(u, SK_PERCEPTION, r); + if (invisible(reisender, u) >= reisender->number) continue; + if (u->faction == reisender->faction) contact = true; + else if (ucontact(u, reisender)) contact = true; + else if (alliedunit(u, reisender->faction, HELP_GUARD)) contact = true; + else if (sk>=perception) { + perception = sk; + guard = u; + } + } + } + if (!contact && guard) { + double prob = 0.3; /* 30% base chance */ + prob += 0.1 * (perception - eff_stealth(reisender, r)); + prob += 0.1 * MIN(guard->number, get_item(guard, I_AMULET_OF_TRUE_SEEING)); + + if (chance(prob)) { + return guard; + } + } + return NULL; +} + +static boolean +is_guardian_u(const unit * guard, unit *u, unsigned int mask) +{ + if (guard->faction == u->faction) return false; + if (is_guard(guard, mask) == 0) return false; + if (alliedunit(guard, u->faction, HELP_GUARD)) return false; + if (ucontact(guard, u)) return false; + if (!cansee(guard->faction, u->region, u, 0)) return false; + + return true; +} + +static boolean +is_guardian_r(const unit * guard) +{ + if (guard->number == 0) return false; + if (besieged(guard)) return false; + + /* if region_owners exist then they may be guardians: */ + if (guard->building && rule_region_owners() && fval(guard, UFL_OWNER)) { + faction * owner = region_get_owner(guard->region); + if (owner==guard->faction) { + building * bowner = largestbuilding(guard->region, &cmp_taxes, false); + if (bowner==guard->building) { + return true; + } + } + } + + if ((guard->flags&UFL_GUARD)==0) return false; + if (!armedmen(guard, true) && !fval(guard->race, RCF_UNARMEDGUARD)) return false; + return true; +} + +boolean is_guard(const struct unit * u, int mask) +{ + return is_guardian_r(u) && (getguard(u) & mask)!=0; +} + +#define MAXGUARDCACHE 16 +/** returns the guard which prevents 'u' from doing 'mask' actions in 'r'. +*/ +unit * +is_guarded(region * r, unit * u, unsigned int mask) +{ + unit *u2 = NULL; + int i, noguards = 1; + static unit * guardcache[MAXGUARDCACHE], * lastguard; /* STATIC_XCALL: used across calls */ + static int gamecookie = -1; + + if (!fval(r, RF_GUARDED)) { + return NULL; + } + + if (gamecookie!=global.cookie) { + if (gamecookie>=0) { + /* clear the previous turn's cache */ + memset(guardcache, 0, sizeof(guardcache)); + lastguard = NULL; + } + gamecookie = global.cookie; + } + + if (lastguard && lastguard->region==r) { + if (is_guardian_u(lastguard, u, mask)) { + return lastguard; + } + } + + for (i=0;i!=MAXGUARDCACHE;++i) { + unit * guard = guardcache[i]; + if (guard && guard!=lastguard && guard->region==r) { + noguards = 0; + if (is_guardian_u(guard, u, mask)) { + lastguard = guard; + return guard; + } + if (u2==guard) { + /* same guard twice signals we've tested everyone */ + return NULL; + } + u2 = guard; + } else { + /* exhausted all the guards in the cache, but maybe we'll find one later? */ + break; + } + } + + /* at this point, u2 is the last unit we tested to + * be a guard (and failed), or NULL + * i is the position of the first free slot in the cache */ + + for (u2 = (u2?u2->next:r->units); u2; u2=u2->next) { + if (is_guardian_r(u2)) { + noguards = 0; + /* u2 is a guard, so worth remembering */ + if (i0 && ifaction->locale; + pause = false; + token = getstrtoken(); + d = finddirection(token, lang); + if(d == D_PAUSE) { + pause = true; + } else if (d == NODIRECTION) { + break; + } + if (cmsizeof(neworder)/2) break; + else if (cm == gereist && !paused && pause) { + const char * loc = LOC(lang, parameters[P_PAUSE]); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, loc, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + paused = true; + } + else if (pause) { + /* da PAUSE nicht in ein shortdirections[d] umgesetzt wird (ist + * hier keine normale direction), muss jede PAUSE einzeln + * herausgefiltert und explizit gesetzt werden */ + if (neworder[0]) strcat(neworder, " "); + strcat(neworder, LOC(lang, parameters[P_PAUSE])); + } else { + if (neworder[0]) strcat(neworder, " "); + strcat(neworder, LOC(lang, shortdirections[d])); + } + } + + if (neworder[0]) { + norder = create_order(K_ROUTE, u->faction->locale, "%s %s", neworder, tail); + } else { + norder = create_order(K_ROUTE, u->faction->locale, "%s", tail); + } + replace_order(&u->orders, ord, norder); + free_order(norder); +} + +static boolean +transport(unit * ut, unit * u) +{ + order * ord; + + if (LongHunger(u) || fval(ut->region->terrain, SEA_REGION)) { + return false; + } + + for (ord = ut->orders; ord; ord = ord->next) { + if (get_keyword(ord) == K_TRANSPORT) { + init_tokens(ord); + skip_token(); + if (getunit(ut->region, ut->faction) == u) { + return true; + } + } + } + return false; +} + +static boolean +can_move(const unit * u) +{ + if (u->race->flags & RCF_CANNOTMOVE) return false; + if (get_movement(&u->attribs, MV_CANNOTMOVE)) return false; + return true; +} + +static void +init_transportation(void) +{ + region *r; + + for (r=regions; r; r=r->next) { + unit *u; + + /* This is just a simple check for non-corresponding K_TRANSPORT/ + * K_DRIVE. This is time consuming for an error check, but there + * doesn't seem to be an easy way to speed this up. */ + for (u=r->units; u; u=u->next) { + if (get_keyword(u->thisorder) == K_DRIVE && can_move(u) && !fval(u, UFL_NOTMOVING) && !LongHunger(u)) { + unit * ut; + + init_tokens(u->thisorder); + skip_token(); + ut = getunit(r, u->faction); + if (ut == NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); + continue; + } + if (!transport(ut, u)) { + if (cansee(u->faction, r, ut, 0)) { + cmistake(u, u->thisorder, 286, MSG_MOVE); + } else { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); + } + } + } + } + + /* This calculates the weights of all transported units and + * adds them to an internal counter which is used by travel () to + * calculate effective weight and movement. */ + + if (!fval(r->terrain, SEA_REGION)) { + for (u=r->units; u; u=u->next) { + order * ord; + int w = 0; + + for (ord = u->orders; ord; ord = ord->next) { + if (get_keyword(ord) == K_TRANSPORT) { + init_tokens(ord); + skip_token(); + for (;;) { + unit * ut = getunit(r, u->faction); + + if (ut == NULL) break; + if (get_keyword(ut->thisorder) == K_DRIVE && can_move(ut) && !fval(ut, UFL_NOTMOVING) && !LongHunger(ut)) { + init_tokens(ut->thisorder); + skip_token(); + if (getunit(r, ut->faction) == u) { + w += weight(ut); + } + } + } + } + } + if (w > 0) a_add(&u->attribs, a_new(&at_driveweight))->data.i = w; + } + } + } +} + +static boolean +roadto(const region * r, direction_t dir) +{ + /* wenn es hier genug strassen gibt, und verbunden ist, und es dort + * genug strassen gibt, dann existiert eine strasse in diese richtung */ + region * r2; + static const curse_type * roads_ct = NULL; + + if (dir>=MAXDIRECTIONS || dir<0) return false; + r2 = rconnect(r, dir); + if (r == NULL || r2 == NULL) return false; + + if (roads_ct == NULL) roads_ct = ct_find("magicstreet"); + if (roads_ct!=NULL) { + if (get_curse(r->attribs, roads_ct)!=NULL) return true; + if (get_curse(r2->attribs, roads_ct)!=NULL) return true; + } + + if (r->terrain->max_road <= 0) return false; + if (r2->terrain->max_road <= 0) return false; + if (rroad(r, dir) < r->terrain->max_road) return false; + if (rroad(r2, dir_invert(dir)) < r2->terrain->max_road) return false; + return true; +} + +static const region_list * +cap_route(region * r, const region_list * route, const region_list * route_end, int speed) +{ + region * current = r; + int moves = speed; + const region_list * iroute = route; + while (iroute!=route_end) { + region * next = iroute->data; + direction_t reldir = reldirection(current, next); + + /* adjust the range of the unit */ + if (roadto(current, reldir)) moves -= BP_ROAD; + else moves -= BP_NORMAL; + if (moves<0) break; + iroute = iroute->next; + current = next; + } + return iroute; +} + +static region * +next_region(unit * u, region * current, region * next) +{ + connection * b; + + b = get_borders(current, next); + while (b!=NULL) { + if (b->type->move) { + region * rto = b->type->move(b, u, current, next, true); + if (rto!=next) { + /* the target region was changed (wisps, for example). check the + * new target region for borders */ + next = rto; + b = get_borders(current, next); + continue; + } + } + b = b->next; + } + return next; +} + +static const region_list * +reroute(unit * u, const region_list * route, const region_list * route_end) +{ + region * current = u->region; + while (route!=route_end) { + region * next = next_region(u, current, route->data); + if (next!=route->data) break; + route = route->next; + } + return route; +} + +static void +make_route(unit * u, order * ord, region_list ** routep) +{ + region_list **iroute = routep; + region * current = u->region; + region * next = NULL; + const char * token = getstrtoken(); + int error = movewhere(u, token, current, &next); + + if (error!=E_MOVE_OK) { + message * msg = movement_error(u, token, ord, error); + if (msg!=NULL) { + add_message(&u->faction->msgs, msg); + msg_release(msg); + } + next = NULL; + } + + while (next!=NULL) { + direction_t reldir; + + if (current == next) { + /* PAUSE */ + break; + } + next = next_region(u, current, next); + reldir = reldirection(current, next); + + add_regionlist(iroute, next); + iroute = &(*iroute)->next; + + current = next; + token = getstrtoken(); + error = movewhere(u, token, current, &next); + if (error) { + message * msg = movement_error(u, token, ord, error); + if (msg!=NULL) { + add_message(&u->faction->msgs, msg); + msg_release(msg); + } + next = NULL; + } + } +} + +/** calculate the speed of a unit + * + * zu Fuß reist man 1 Region, zu Pferd 2 Regionen. Mit Straßen reist + * man zu Fuß 2, mit Pferden 3 weit. + * + * Berechnet wird das mit BPs. Zu Fuß hat man 4 BPs, zu Pferd 6. + * 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 mp; + static const curse_type * speed_ct; + static boolean init = false; + double dk = u->race->speed; + + assert(u->number); + /* dragons have a fixed speed, and no other effects work on them: */ + switch (old_race(u->race)) { + case RC_DRAGON: + case RC_WYRM: + case RC_FIREDRAGON: + case RC_BIRTHDAYDRAGON: + case RC_SONGDRAGON: + return BP_DRAGON; + } + + if (!init) { + init = true; + speed_ct = ct_find("speed"); + } + if (speed_ct) { + curse *c = get_curse(u->attribs, speed_ct); + if (c!=NULL) { + int men = get_cursedmen(u, c); + dk *= 1.0 + (double)men/(double)u->number; + } + } + + switch (canride(u)) { + + case 1: /* Pferd */ + mp = BP_RIDING; + break; + + case 2: /* Einhorn */ + mp = BP_UNICORN; + break; + + default: + mp = BP_WALKING; + + /* 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 <= get_item(u, I_FEENSTIEFEL)) { + mp *= 2; + } + + /* Im Astralraum sind Tyb und Ill-Magier doppelt so schnell. + * Nicht kumulativ mit anderen Beschleunigungen! */ + if (mp*dk <= BP_WALKING*u->race->speed && is_astral(u->region) && is_mage(u)) { + sc_mage * mage = get_mage(u); + if (mage->magietyp == M_TYBIED || mage->magietyp == M_ILLAUN) { + mp *= 2; + } + } + break; + } + return (int)(dk*mp); +} + +enum { + TRAVEL_NORMAL, + TRAVEL_FOLLOWING, + TRAVEL_TRANSPORTED, + TRAVEL_RUNNING +}; + +static arg_regions * +var_copy_regions(const region_list * begin, int size) +{ + const region_list * rsrc; + + if (size>0) { + int i = 0; + arg_regions * dst = (arg_regions *)malloc(sizeof(arg_regions) + sizeof(region*) * size); + dst->nregions = size; + dst->regions = (region**)(dst+1); + for (rsrc = begin; i!=size; rsrc=rsrc->next) { + dst->regions[i++] = rsrc->data; + } + return dst; + } + return NULL; +} + + +static const region_list * +travel_route(unit * u, const region_list * route_begin, const region_list * route_end, order * ord, int mode) +{ + region * r = u->region; + region * current = u->region; + const region_list * iroute = route_begin; + int steps = 0; + boolean landing = false; /* aquarians have landed */ + + while (iroute && iroute!=route_end) { + region * next = iroute->data; + direction_t reldir = reldirection(current, next); + connection * b = get_borders(current, next); + + /* check if we are caught by guarding units */ + if (iroute!=route_begin && mode!=TRAVEL_RUNNING && mode!=TRAVEL_TRANSPORTED) { + unit * wache = bewegung_blockiert_von(u, current); + if (wache!=NULL) { + ADDMSG(&u->faction->msgs, msg_message("moveblockedbyguard", + "unit region guard", u, current, wache)); + break; + } + } + + /* check movement from/to oceans. + * aquarian special, flying units, horses, the works */ + if ((u->race->flags & RCF_FLY) == 0) { + if (!fval(next->terrain, SEA_REGION)) { + /* next region is land */ + if (fval(current->terrain, SEA_REGION)) { + int moving = u->race->flags & (RCF_SWIM|RCF_WALK|RCF_COASTAL); + /* Die Einheit kann nicht fliegen, ist im Ozean, und will an Land */ + if (moving != (RCF_SWIM|RCF_WALK) && (moving&RCF_COASTAL) == 0) { + /* can't swim+walk and isn't allowed to enter coast from sea */ + if (ord!=NULL) cmistake(u, ord, 44, MSG_MOVE); + break; + } + landing = true; + } else if ((u->race->flags & RCF_WALK) == 0) { + /* Spezialeinheiten, die nicht laufen können. */ + ADDMSG(&u->faction->msgs, msg_message("detectocean", + "unit region", u, next)); + break; + } else if (landing) { + /* wir sind diese woche angelandet */ + ADDMSG(&u->faction->msgs, msg_message("detectocean", + "unit region", u, next)); + break; + } + } else { + /* Ozeanfelder können nur von Einheiten mit Schwimmen und ohne + * Pferde betreten werden. */ + if (!(canswim(u) || canfly(u))) { + ADDMSG(&u->faction->msgs, msg_message("detectocean", + "unit region", u, next)); + break; + } + } + + if (fval(current->terrain, SEA_REGION) || fval(next->terrain, SEA_REGION)) { + /* trying to enter or exit ocean with horses, are we? */ + if (has_horses(u)) { + /* tries to do it with horses */ + if (ord!=NULL) cmistake(u, ord, 67, MSG_MOVE); + break; + } + } + + } + + /* movement blocked by a wall */ + if (reldir>=0 && move_blocked(u, current, next)) { + ADDMSG(&u->faction->msgs, msg_message("leavefail", + "unit region", u, next)); + break; + } + + /* region ownership only: region owned by enemies */ + if (!entrance_allowed(u, next)) { + ADDMSG(&u->faction->msgs, msg_message("regionowned", + "unit region target", u, current, next)); + break; + } + + /* illusionary units disappear in antimagic zones */ + if (fval(u->race, RCF_ILLUSIONARY)) { + curse * c = get_curse(next->attribs, ct_find("antimagiczone")); + if (curse_active(c)) { + curse_changevigour(&next->attribs, c, (float)-u->number); + ADDMSG(&u->faction->msgs, msg_message("illusionantimagic", "unit", u)); + set_number(u, 0); + break; + } + } + + /* terrain is marked as forbidden (curse, etc) */ + if (fval(next, RF_BLOCKED) || fval(next->terrain, FORBIDDEN_REGION)) { + ADDMSG(&u->faction->msgs, msg_message("detectforbidden", + "unit region", u, next)); + break; + } + + /* unit is an insect and cannot move into a glacier */ + if (u->race == new_race[RC_INSECT]) { + if (r_insectstalled(next) && is_freezing(u)) { + ADDMSG(&u->faction->msgs, msg_message("detectforbidden", + "unit region", u, next)); + break; + } + } + + /* effect of borders */ + while (b!=NULL) { + if (b->type->move) { + b->type->move(b, u, current, next, false); + } + b = b->next; + } + + current = next; + iroute = iroute->next; + ++steps; + if (u->number == 0) break; + } + + if (iroute!=route_begin) { + /* the unit has moved at least one region */ + int walkmode; + + setguard(u, GUARD_NONE); + cycle_route(ord, u, steps); + + if (mode == TRAVEL_RUNNING) { + walkmode = 0; + } if (canride(u)) { + walkmode = 1; + produceexp(u, SK_RIDING, u->number); + } else { + walkmode = 2; + } + + /* Berichte über Durchreiseregionen */ + + if (mode!=TRAVEL_TRANSPORTED) { + arg_regions * ar = var_copy_regions(route_begin, steps-1); + ADDMSG(&u->faction->msgs, msg_message("travel", + "unit mode start end regions", u, walkmode, r, current, ar)); + } + + mark_travelthru(u, r, route_begin, iroute); + move_unit(u, current, NULL); + + /* make orders for the followers */ + } + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + setguard(u, GUARD_NONE); + assert(u->region == current); + return iroute; +} + +static boolean +ship_ready(const region * r, unit * u) +{ + if (!fval(u, UFL_OWNER)) { + cmistake(u, u->thisorder, 146, MSG_MOVE); + return false; + } + if (eff_skill(u, SK_SAILING, r) < u->ship->type->cptskill) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_captain_skill_low", + "value ship", u->ship->type->cptskill, u->ship)); + return false; + } + assert(u->ship->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (u->ship->size!=u->ship->type->construction->maxsize) { + cmistake(u, u->thisorder, 15, MSG_MOVE); + return false; + } + if (!enoughsailors(u->ship, r)) { + cmistake(u, u->thisorder, 1, MSG_MOVE); +/* mistake(u, u->thisorder, + "Auf dem Schiff befinden sich zuwenig erfahrene Seeleute.", MSG_MOVE); */ + return false; + } + if (!cansail(r, u->ship)) { + cmistake(u, u->thisorder, 18, MSG_MOVE); + return false; + } + return true; +} + +unit * +owner_buildingtyp(const region * r, const building_type * bt) +{ + building *b; + unit *owner; + + for (b = rbuildings(r); b; b = b->next) { + owner = building_owner(b); + if (b->type == bt && owner != NULL) { + if (b->size >= bt->maxsize) { + return owner; + } + } + } + + return NULL; +} + +boolean +buildingtype_exists(const region * r, const building_type * bt, boolean working) +{ + building *b; + + for (b = rbuildings(r); b; b = b->next) { + if (b->type == bt) { + if (b->size >= bt->maxsize) { + return true; + } + } + } + + return false; +} + +/* Prüft, ob Ablegen von einer Küste in eine der erlaubten Richtungen erfolgt. */ + +static boolean +check_takeoff(ship *sh, region *from, region *to) +{ + if (!fval(from->terrain, SEA_REGION) && sh->coast != NODIRECTION) { + direction_t coast = sh->coast; + direction_t dir = reldirection(from, to); + direction_t coastr = (direction_t)((coast+1) % MAXDIRECTIONS); + direction_t coastl = (direction_t)((coast+MAXDIRECTIONS-1) % MAXDIRECTIONS); + + if (dir!=coast && dir!=coastl && dir!=coastr + && !buildingtype_exists(from, bt_find("harbour"), true)) + { + return false; + } + } + + return true; +} + +static void +sail(unit * u, order * ord, boolean move_on_land, region_list **routep) +{ + region *starting_point = u->region; + region *current_point, *last_point; + int k, step = 0; + region_list **iroute = routep; + ship * sh = u->ship; + faction * f = u->faction; + region * next_point = NULL; + int error; + const char * token = getstrtoken(); + + if (routep) *routep = NULL; + + error = movewhere(u, token, starting_point, &next_point); + if (error) { + message * msg = movement_error(u, token, ord, error); + if (msg!=NULL) { + add_message(&u->faction->msgs, msg); + msg_release(msg); + } + return; + } + + if (!ship_ready(starting_point, u)) return; + + /* Wir suchen so lange nach neuen Richtungen, wie es geht. Diese werden + * dann nacheinander ausgeführt. */ + + k = shipspeed(sh, u); + + last_point = starting_point; + current_point = starting_point; + + /* die nächste Region, in die man segelt, wird durch movewhere () aus der + * letzten Region bestimmt. + * + * Anfangen tun wir bei starting_point. next_point ist beim ersten + * Durchlauf schon gesetzt (Parameter!). current_point ist die letzte gültige, + * befahrene Region. */ + + while (next_point && current_point!=next_point && step < k) { + const char * token; + int error; + const terrain_type * tthis = current_point->terrain; + /* these values need to be updated if next_point changes (due to storms): */ + const terrain_type * tnext = next_point->terrain; + direction_t dir = reldirection(current_point, next_point); + + assert(sh == u->ship || !"ship has sunk, but we didn't notice it"); + + if (fval(next_point->terrain, FORBIDDEN_REGION)) { + ADDMSG(&f->msgs, msg_message("sailforbidden", + "ship region", sh, next_point)); + break; + } + + if (!flying_ship(sh)) { + int stormchance; + static int stormyness; + static int gamecookie = -1; + + if (gamecookie != global.cookie) { + gamedate date; + get_gamedate(turn, &date); + stormyness = storms[date.month] * 5; + gamecookie = global.cookie; + } + + /* storms should be the first thing we do. */ + stormchance = stormyness / shipspeed(sh, u); + if (check_leuchtturm(next_point, NULL)) stormchance /= 3; + + if (rng_int()%10000 < stormchance*sh->type->storm && fval(current_point->terrain, SEA_REGION)) { + if (!is_cursed(sh->attribs, C_SHIP_NODRIFT, 0)) { + region * rnext = NULL; + boolean storm = true; + int d_offset = rng_int() % MAXDIRECTIONS; + direction_t d; + /* Sturm nur, wenn nächste Region Hochsee ist. */ + for (d=0;d!=MAXDIRECTIONS;++d) { + direction_t dnext = (direction_t)((d + d_offset) % MAXDIRECTIONS); + region * rn = rconnect(current_point, dnext); + + if (rn!=NULL) { + if (fval(rn->terrain, FORBIDDEN_REGION)) continue; + if (!fval(rn->terrain, SEA_REGION)) { + storm = false; + break; + } + if (rn!=next_point) rnext = rn; + } + } + if (storm && rnext!=NULL) { + ADDMSG(&f->msgs, msg_message("storm", "ship region sink", + sh, current_point, sh->damage>=sh->size * DAMAGE_SCALE)); + + /* damage the ship. we handle destruction in the end */ + damage_ship(sh, damage_drift()); + if (sh->damage>=sh->size * DAMAGE_SCALE) break; + + next_point = rnext; + /* these values need to be updated if next_point changes (due to storms): */ + tnext = next_point->terrain; + dir = reldirection(current_point, next_point); + } + } + } + + if (!fval(tthis, SEA_REGION)) { + if (!fval(tnext, SEA_REGION)) { + if (!move_on_land) { + /* check that you're not traveling from one land region to another. */ + ADDMSG(&u->faction->msgs, msg_message("shipnoshore", + "ship region", sh, next_point)); + break; + } + } else { + if (check_takeoff(sh, current_point, next_point) == false) { + /* Schiff kann nicht ablegen */ + cmistake(u, ord, 182, MSG_MOVE); + break; + } + } + } else if (fval(tnext, SEA_REGION)) { + /* target region is an ocean, and we're not leaving a shore */ + if (!(sh->type->flags & SFL_OPENSEA)) { + /* ship can only stay close to shore */ + direction_t d; + + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rc = rconnect(next_point, d); + if (rc==NULL || !fval(rc->terrain, SEA_REGION)) break; + } + if (d == MAXDIRECTIONS) { + /* Schiff kann nicht aufs offene Meer */ + cmistake(u, ord, 249, MSG_MOVE); + break; + } + } + } + + if (!ship_allowed(sh, next_point)) { + /* for some reason or another, we aren't allowed in there.. */ + if (check_leuchtturm(current_point, NULL)) { + ADDMSG(&f->msgs, msg_message("sailnolandingstorm", "ship", sh)); + } else { + ADDMSG(&f->msgs, msg_message("sailnolanding", "ship region", sh, next_point)); + damage_ship(sh, 0.10); + /* we handle destruction at the end */ + } + break; + } + + + if (curse_active(get_curse(next_point->attribs, ct_find("maelstrom")))) { + if (do_maelstrom(next_point, u) == NULL) break; + } + + } /* !flying_ship */ + + /* Falls Blockade, endet die Seglerei hier */ + if (move_blocked(u, current_point, next_point)) { + ADDMSG(&u->faction->msgs, msg_message("sailfail", "ship region", sh, current_point)); + break; + } + + /* Falls kein Problem, eines weiter ziehen */ + fset(sh, SF_MOVED); + if (iroute) { + add_regionlist(iroute, next_point); + iroute = &(*iroute)->next; + } + step++; + + last_point = current_point; + current_point = next_point; + + if (!fval(current_point->terrain, SEA_REGION) && !is_cursed(sh->attribs, C_SHIP_FLYING, 0)) break; + token = getstrtoken(); + error = movewhere(u, token, current_point, &next_point); + if (error || next_point == NULL) { + message * msg = movement_error(u, token, ord, error); + if (msg!=NULL) { + add_message(&u->faction->msgs, msg); + msg_release(msg); + } + next_point = current_point; + break; + } + } + + if (sh->damage>=sh->size * DAMAGE_SCALE) { + if (sh->region) { + ADDMSG(&f->msgs, msg_message("shipsink", "ship", sh)); + remove_ship(&sh->region->ships, sh); + } + sh = NULL; + } + + /* Nun enthält current_point die Region, in der das Schiff seine Runde + * beendet hat. Wir generieren hier ein Ereignis für den Spieler, das + * ihm sagt, bis wohin er gesegelt ist, falls er überhaupt vom Fleck + * gekommen ist. Das ist nicht der Fall, wenn er von der Küste ins + * Inland zu segeln versuchte */ + + if (sh!=NULL && fval(sh, SF_MOVED)) { + unit * hafenmeister; + /* nachdem alle Richtungen abgearbeitet wurden, und alle Einheiten + * transferiert wurden, kann der aktuelle Befehl gelöscht werden. */ + cycle_route(ord, u, step); + set_order(&u->thisorder, NULL); + set_coast(sh, last_point, current_point); + + if( is_cursed(sh->attribs, C_SHIP_FLYING, 0) ) { + ADDMSG(&f->msgs, msg_message("shipfly", "ship from to", sh, starting_point, current_point)); + } else { + ADDMSG(&f->msgs, msg_message("shipsail", "ship from to", sh, starting_point, current_point)); + } + + /* Das Schiff und alle Einheiten darin werden nun von + * starting_point nach current_point verschoben */ + + /* Verfolgungen melden */ + if (fval(u, UFL_FOLLOWING)) caught_target(current_point, u); + + sh = move_ship(sh, starting_point, current_point, *routep); + + /* Hafengebühren ? */ + + hafenmeister = owner_buildingtyp(current_point, bt_find("harbour")); + if (sh && hafenmeister != NULL) { + item * itm; + unit * u2; + item * trans = NULL; + + for (u2 = current_point->units; u2; u2 = u2->next) { + if (u2->ship == sh && + !alliedunit(hafenmeister, u->faction, HELP_GUARD)) { + + + if (effskill(hafenmeister, SK_PERCEPTION) > effskill(u2, SK_STEALTH)) { + for (itm=u2->items; itm; itm=itm->next) { + const luxury_type * ltype = resource2luxury(itm->type->rtype); + if (ltype!=NULL && itm->number>0) { + int st = itm->number * effskill(hafenmeister, SK_TRADE) / 50; + st = MIN(itm->number, st); + + if (st > 0) { + i_change(&u2->items, itm->type, -st); + i_change(&hafenmeister->items, itm->type, st); + i_add(&trans, i_new(itm->type, st)); + } + } + } + } + } + } + if (trans) { + message * msg = msg_message("harbor_trade", "unit items ship", hafenmeister, trans, u->ship); + add_message(&u->faction->msgs, msg); + add_message(&hafenmeister->faction->msgs, msg); + msg_release(msg); + while (trans) i_remove(&trans, trans); + } + } + } +} + +unit * +get_captain(const ship * sh) +{ + const region * r = sh->region; + unit *u; + + for (u = r->units; u; u = u->next) { + if (u->ship == sh && eff_skill(u, SK_SAILING, r) >= sh->type->cptskill) + return u; + } + + return NULL; +} + +/* Segeln, Wandern, Reiten +* when this routine returns a non-zero value, movement for the region needs +* to be done again because of followers that got new MOVE orders. +* Setting FL_LONGACTION will prevent a unit from being handled more than once +* by this routine +* +* the token parser needs to be initialized before calling this function! +*/ + +/** fleeing units use this function +*/ +void +run_to(unit * u, region * to) +{ + region_list * route = NULL; + add_regionlist(&route, to); + travel_route(u, route, NULL, NULL, TRAVEL_RUNNING); + free_regionlist(route); + /* weder transport noch follow */ +} + +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; + + if (u->building && !can_leave(u)) { + cmistake(u, u->thisorder, 150, MSG_MOVE); + return route_begin; + } + switch (canwalk(u)) { + case E_CANWALK_TOOHEAVY: + cmistake(u, ord, 57, MSG_MOVE); + return route_begin; + case E_CANWALK_TOOMANYHORSES: + cmistake(u, ord, 56, MSG_MOVE); + return route_begin; + case E_CANWALK_TOOMANYCARTS: + cmistake(u, ord, 42, MSG_MOVE); + return route_begin; + } + route_end = cap_route(r, route_begin, route_end, movement_speed(u)); + + route_end = travel_route(u, route_begin, route_end, ord, mode); + get_followers(u, r, route_end, followers); + + /* transportation */ + for (ord = u->orders; ord; ord = ord->next) { + unit * ut; + + if (get_keyword(ord) != K_TRANSPORT) continue; + + init_tokens(ord); + skip_token(); + ut = getunit(r, u->faction); + if (ut!=NULL) { + if (get_keyword(ut->thisorder) == K_DRIVE) { + if (ut->building && !can_leave(ut)) { + cmistake(ut, ut->thisorder, 150, MSG_MOVE); + cmistake(u, ord, 99, MSG_MOVE); + } else if (!can_move(ut)) { + cmistake(u, ord, 99, MSG_MOVE); + } else { + boolean found = false; + + if (!fval(ut, UFL_NOTMOVING) && !LongHunger(ut)) { + init_tokens(ut->thisorder); + skip_token(); + if (getunit(u->region, ut->faction) == u) { + const region_list * route_to = travel_route(ut, route_begin, route_end, ord, TRAVEL_TRANSPORTED); + + if (route_to!=route_begin) { + get_followers(ut, r, route_to, followers); + } + ADDMSG(&ut->faction->msgs, msg_message("transport", + "unit target start end", u, ut, r, ut->region)); + found = true; + } + } + if (!found) { + if (cansee(u->faction, u->region, ut, 0)) { + cmistake(u, ord, 90, MSG_MOVE); + } else { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } + } + } + } + } else { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } + } + return route_end; +} + +/** traveling without ships + * walking, flying or riding units use this function + */ +static void +travel(unit * u, region_list ** routep) +{ + region * r = u->region; + region_list * route_begin = NULL; + follower * followers = NULL; + + if (routep) *routep = NULL; + + /* a few pre-checks that need not be done for each step: */ + if (!fval(r->terrain, SEA_REGION)) { + ship * sh = u->ship; + + if (!can_leave(u)) { + cmistake(u, u->thisorder, 150, MSG_MOVE); + return; + } + + /* An Land kein NACH wenn in dieser Runde Schiff VERLASSEN! */ + if (sh == NULL) { + sh = leftship(u); + if (sh && sh->region!=u->region) sh = NULL; + } + if (sh) { + unit * guard = is_guarded(r, u, GUARD_LANDING); + if (guard) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "region_guarded", "guard", guard)); + return; + } + } + if (u->ship && u->race->flags & RCF_SWIM) { + cmistake(u, u->thisorder, 143, MSG_MOVE); + return; + } + } + else if (u->ship && fval(u->ship, SF_MOVED)) { + /* die Einheit ist auf einem Schiff, das sich bereits bewegt hat */ + cmistake(u, u->thisorder, 13, MSG_MOVE); + return; + } + + make_route(u, u->thisorder, routep); + route_begin = *routep; + + /* und ab die post: */ + travel_i(u, route_begin, NULL, u->thisorder, TRAVEL_NORMAL, &followers); + + /* followers */ + while (followers!=NULL) { + follower * fnext = followers->next; + unit * uf = followers->uf; + unit * ut = followers->ut; + const region_list * route_end = followers->route_end; + + free(followers); + followers = fnext; + + if (uf->region == r) { + order * follow_order; + const struct locale * lang = u->faction->locale; + + /* construct an order */ + follow_order = create_order(K_FOLLOW, lang, "%s %i", + LOC(uf->faction->locale, parameters[P_UNIT]), ut->no); + + route_end = reroute(uf, route_begin, route_end); + travel_i(uf, route_begin, route_end, follow_order, TRAVEL_FOLLOWING, &followers); + caught_target(uf->region, uf); + free_order(follow_order); + } + } + +} + +static void +move(unit * u, boolean move_on_land) +{ + region_list * route = NULL; + + assert(u->number); + if (u->ship && fval(u, UFL_OWNER)) { + sail(u, u->thisorder, move_on_land, &route); + } else { + travel(u, &route); + } + + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + set_order(&u->thisorder, NULL); + + if (route!=NULL) free_regionlist(route); +} + +typedef struct piracy_data { + const struct faction * pirate; + const struct faction * target; + direction_t dir; +} piracy_data; + +static void +piracy_init(struct attrib * a) +{ + a->data.v = calloc(1, sizeof(piracy_data)); +} + +static void +piracy_done(struct attrib * a) +{ + free(a->data.v); +} + +static attrib_type at_piracy_direction = { + "piracy_direction", + piracy_init, + piracy_done, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +static attrib * +mk_piracy(const faction * pirate, const faction * target, direction_t target_dir) +{ + attrib * a = a_new(&at_piracy_direction); + piracy_data * data = a->data.v; + data->pirate = pirate; + data->target = target; + data->dir = target_dir; + return a; +} + +static void +piracy_cmd(unit *u, struct order * ord) +{ + region *r = u->region; + ship *sh = u->ship, *sh2; + direction_t dir, target_dir = NODIRECTION; + struct { + const faction * target; + int value; + } aff[MAXDIRECTIONS]; + int saff = 0; + int *il = NULL; + const char *s; + attrib *a; + + if (!sh) { + cmistake(u, ord, 144, MSG_MOVE); + return; + } + + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 146, MSG_MOVE); + return; + } + + /* Feststellen, ob schon ein anderer alliierter Pirat ein + * Ziel gefunden hat. */ + + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + if (s!=NULL && *s) { + il = intlist_init(); + while (s && *s) { + il = intlist_add(il, atoi36(s)); + s = getstrtoken(); + } + } + + for (a = a_find(r->attribs, &at_piracy_direction); a && a->type==&at_piracy_direction; a=a->next) { + piracy_data * data = a->data.v; + const faction * p = data->pirate; + const faction * t = data->target; + + if (alliedunit(u, p, HELP_FIGHT)) { + if (il == 0 || (t && intlist_find(il, t->no))) { + target_dir = data->dir; + break; + } + } + } + + /* Wenn nicht, sehen wir, ob wir ein Ziel finden. */ + + if (target_dir == NODIRECTION) { + /* Einheit ist also Kapitän. Jetzt gucken, in wievielen + * Nachbarregionen potentielle Opfer sind. */ + + for(dir = 0; dir < MAXDIRECTIONS; dir++) { + region *rc = rconnect(r, dir); + aff[dir].value = 0; + aff[dir].target = 0; + if (rc && fval(rc->terrain, SWIM_INTO) + && check_takeoff(sh, r, rc) == true) { + + for (sh2 = rc->ships; sh2; sh2 = sh2->next) { + unit * cap = shipowner(sh2); + if (cap) { + faction * f = visible_faction(cap->faction, cap); + if (alliedunit(u, f, HELP_FIGHT)) continue; + if (il == 0 || intlist_find(il, cap->faction->no)) { + ++aff[dir].value; + if (rng_int() % aff[dir].value == 0) { + aff[dir].target = f; + } + } + } + } + + /* Und aufaddieren. */ + saff += aff[dir].value; + } + } + + if (saff != 0) { + saff = rng_int() % saff; + for (dir=0; dir!=MAXDIRECTIONS; ++dir) { + if (saff!=aff[dir].value) break; + saff -= aff[dir].value; + } + target_dir = dir; + a = a_add(&r->attribs, mk_piracy(u->faction, aff[dir].target, target_dir)); + } + } + + free(il); + + /* Wenn kein Ziel gefunden, entsprechende Meldung generieren */ + if (target_dir == NODIRECTION) { + ADDMSG(&u->faction->msgs, msg_message("piratenovictim", + "ship region", sh, r)); + return; + } + + /* Meldung generieren */ + ADDMSG(&u->faction->msgs, msg_message("piratesawvictim", + "ship region dir", sh, r, target_dir)); + + /* Befehl konstruieren */ + set_order(&u->thisorder, create_order(K_MOVE, u->faction->locale, "%s", + LOC(u->faction->locale, directions[target_dir]))); + + /* Bewegung ausführen */ + init_tokens(u->thisorder); + skip_token(); + move(u, true); +} + +static void +age_traveldir(region *r) +{ + attrib *a = a_find(r->attribs, &at_traveldir); + + while(a && a->type==&at_traveldir) { + attrib *an = a->next; + a->data.ca[3]--; + if(a->data.ca[3] <= 0) { + a_remove(&r->attribs, a); + } + a = an; + } +} + +static direction_t +hunted_dir(attrib *at, int id) +{ + attrib *a = a_find(at, &at_shiptrail); + direction_t d = NODIRECTION; + + while (a!=NULL && a->type==&at_shiptrail) { + traveldir *t = (traveldir *)(a->data.v); + if (t->no == id) { + d = t->dir; + /* do not break, because we want the last one for this ship */ + } + a = a->next; + } + + return d; +} + +static int +hunt(unit *u, order * ord) +{ + region *rc = u->region; + int bytes, moves, id, speed; + char command[256], * bufp = command; + size_t size = sizeof(command); + direction_t dir; + + if (fval(u, UFL_NOTMOVING)) { + return 0; + } else if (u->ship == NULL) { + cmistake(u, ord, 144, MSG_MOVE); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ + return 0; + } else if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 146, MSG_MOVE); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ + return 0; + } else if (!can_move(u)) { + cmistake(u, ord, 55, MSG_MOVE); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ + return 0; + } + + id = getshipid(); + + if (id <= 0) { + cmistake(u, ord, 20, MSG_MOVE); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ + return 0; + } + + dir = hunted_dir(rc->attribs, id); + + if (dir == NODIRECTION) { + ship * sh = findship(id); + if (sh == NULL || sh->region!=rc) { + cmistake(u, ord, 20, MSG_MOVE); + } + fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ + return 0; + } + + bufp = command; + bytes = snprintf(bufp, size, "%s %s", LOC(u->faction->locale, keywords[K_MOVE]), + LOC(u->faction->locale, directions[dir])); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + moves = 1; + + speed = getuint(); + if (speed==0) { + speed = shipspeed(u->ship, u); + } else { + int maxspeed = shipspeed(u->ship, u); + if (maxspeedattribs, id)) != NODIRECTION) + { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(u->faction->locale, directions[dir]), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + moves++; + rc = rconnect(rc, dir); + } + + /* In command steht jetzt das NACH-Kommando. */ + + /* NACH ignorieren und Parsing initialisieren. */ + igetstrtoken(command); + /* NACH ausführen */ + move(u, false); + return 1; /* true -> Einheitenliste von vorne durchgehen */ +} + +void +destroy_damaged_ships(void) +{ + region *r; + ship *sh,*shn; + + for(r=regions;r;r=r->next) { + for(sh=r->ships;sh;) { + shn = sh->next; + if (sh->damage>=sh->size * DAMAGE_SCALE) { + remove_ship(&sh->region->ships, sh); + } + sh = shn; + } + } +} + +/* Bewegung, Verfolgung, Piraterie */ + +/** ships that folow other ships + * Dann generieren die jagenden Einheiten ihre Befehle und + * bewegen sich. + * Following the trails of other ships. + */ +static void +move_hunters(void) +{ + region *r; + + for (r = regions; r; r = r->next) { + unit ** up = &r->units; + + while (*up!=NULL) { + unit * u = *up; + + if (!fval(u, UFL_MOVED|UFL_NOTMOVING)) { + order * ord; + + for (ord=u->orders;ord;ord=ord->next) { + if (get_keyword(ord) == K_FOLLOW) { + param_t p; + + init_tokens(ord); + skip_token(); + p = getparam(u->faction->locale); + if (p != P_SHIP) { + if (p != P_UNIT) { + cmistake(u, ord, 240, MSG_MOVE); + } + break; + } + + /* wir folgen definitiv einem Schiff. */ + + if (fval(u, UFL_NOTMOVING)) { + cmistake(u, ord, 52, MSG_MOVE); + break; + } else if (!can_move(u)) { + cmistake(u, ord, 55, MSG_MOVE); + break; + } + + if (!fval(u, UFL_NOTMOVING) && !LongHunger(u) && hunt(u, ord)) { + up = &r->units; + break; + } + } + } + } + if (*up == u) up=&u->next; + } + } +} + +/** Piraten and Drift + * + */ +static void +move_pirates(void) +{ + region * r; + + for (r = regions; r; r = r->next) { + unit ** up = &r->units; + + while (*up) { + unit *u = *up; + + if (!fval(u, UFL_NOTMOVING) && get_keyword(u->thisorder) == K_PIRACY) { + piracy_cmd(u, u->thisorder); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + } + + if (*up == u) { + /* not moved, use next unit */ + up = &u->next; + } else if (*up && (*up)->region!=r) { + /* moved the previous unit along with u (units on same ship) + * must start from the beginning again */ + up = &r->units; + } + /* else *up is already the next unit */ + } + + a_removeall(&r->attribs, &at_piracy_direction); + age_traveldir(r); + } +} + +void +movement(void) +{ + int ships; + + /* Initialize the additional encumbrance by transported units */ + init_transportation(); + + /* Move ships in last phase, others first + * This is to make sure you can't land someplace and then get off the ship + * in the same turn. + */ + for (ships=0;ships<=1;++ships) { + region * r = regions; + while (r!=NULL) { + unit ** up = &r->units; + boolean repeat = false; + + while (*up) { + unit *u = *up; + keyword_t kword; + + if (u->ship && fval(u->ship, SF_DRIFTED)) { + up = &u->next; + continue; + } + kword = get_keyword(u->thisorder); + + switch (kword) { + case K_ROUTE: + case K_MOVE: + /* after moving, the unit has no thisorder. this prevents + * it from moving twice (or getting error messages twice). + * UFL_NOTMOVING is set in combat if the unit is not allowed + * to move because it was involved in a battle. + */ + if (fval(u, UFL_NOTMOVING)) { + if (fval(u, UFL_LONGACTION)) { + cmistake(u, u->thisorder, 52, MSG_MOVE); + set_order(&u->thisorder, NULL); + } else { + cmistake(u, u->thisorder, 319, MSG_MOVE); + set_order(&u->thisorder, NULL); + } + } else if (fval(u, UFL_MOVED)) { + cmistake(u, u->thisorder, 187, MSG_MOVE); + set_order(&u->thisorder, NULL); + } else if (!can_move(u)) { + cmistake(u, u->thisorder, 55, MSG_MOVE); + set_order(&u->thisorder, NULL); + } else { + if (ships) { + if (u->ship && fval(u, UFL_OWNER)) { + init_tokens(u->thisorder); + skip_token(); + move(u, false); + } + } else { + if (u->ship == NULL || !fval(u, UFL_OWNER)) { + init_tokens(u->thisorder); + skip_token(); + move(u, false); + } + } + } + break; + } + if (u->region == r) { + /* not moved, use next unit */ + up = &u->next; + } else { + if (*up && (*up)->region!=r) { + /* moved the upcoming unit along with u (units on ships or followers, + * for example). must start from the beginning again immediately */ + up = &r->units; + repeat = false; + } else { + repeat = true; + } + } + /* else *up is already the next unit */ + } + if (repeat) continue; + if (ships == 0) { + /* Abtreiben von beschädigten, unterbemannten, überladenen Schiffen */ + drifting_ships(r); + } + r = r->next; + } + } + + move_hunters(); + move_pirates(); +} + +/** Overrides long orders with a FOLLOW order if the target is moving. + * FOLLOW SHIP is a long order, and doesn't need to be treated in here. + * BUGS: http://bugs.eressea.de/view.php?id=1444 (A folgt B folgt C) + */ +void +follow_unit(unit * u) +{ + region * r = u->region; + attrib * a = NULL; + order * ord; + + if (fval(u, UFL_NOTMOVING) || LongHunger(u)) return; + + for (ord=u->orders;ord;ord=ord->next) { + const struct locale * lang = u->faction->locale; + + if (get_keyword(ord) == K_FOLLOW) { + init_tokens(ord); + skip_token(); + if (getparam(lang) == P_UNIT) { + int id = read_unitid(u->faction, r); + + if (a!=NULL) { + a = a_find(u->attribs, &at_follow); + } + + if (id>0) { + unit * uf = findunit(id); + if (!a) { + a = a_add(&u->attribs, make_follow(uf)); + } else { + a->data.v = uf; + } + } else if (a) { + a_remove(&u->attribs, a); + a = NULL; + } + } + } + } + + if (a && !fval(u, UFL_MOVED|UFL_NOTMOVING)) { + unit * u2 = a->data.v; + boolean follow = false; + + if (!u2 || u2->region!=r || !cansee(u->faction, r, u2, 0)) { + return; + } + + switch (get_keyword(u2->thisorder)) { + case K_MOVE: + case K_ROUTE: + case K_DRIVE: + follow = true; + break; + default: + for (ord=u2->orders;ord;ord=ord->next) { + switch (get_keyword(ord)) { + case K_FOLLOW: + case K_PIRACY: + follow = true; + break; + default: + continue; + } + break; + } + break; + } + if (!follow) { + attrib * a2 = a_find(u2->attribs, &at_follow); + if (a2!=NULL) { + unit * u3 = a2->data.v; + follow = (u3 && u2->region == u2->region); + } + } + if (follow) { + fset(u, UFL_FOLLOWING); + fset(u2, UFL_FOLLOWED); + set_order(&u->thisorder, NULL); + } + } +} diff --git a/src/kernel/move.h b/src/kernel/move.h index 2b5b7bdd1..96c04a117 100644 --- a/src/kernel/move.h +++ b/src/kernel/move.h @@ -1,71 +1,71 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_MOVEMENT -#define H_KRNL_MOVEMENT -#ifdef __cplusplus -extern "C" { -#endif - -struct unit; -struct ship; -struct building_type; - -/* die Zahlen sind genau äquivalent zu den race Flags */ -#define MV_CANNOTMOVE (1<<5) -#define MV_FLY (1<<7) /* kann fliegen */ -#define MV_SWIM (1<<8) /* kann schwimmen */ -#define MV_WALK (1<<9) /* kann über Land gehen */ - -/* Die tragekapaz. ist hardcodiert mit defines, da es bis jetzt sowieso nur 2 -** objekte gibt, die etwas tragen. */ -#define SILVERWEIGHT 1 -#define SCALEWEIGHT 100 /* Faktor, um den die Anzeige von gewichten - * * skaliert wird */ -#define HORSECAPACITY 7000 -#define WAGONCAPACITY 14000 - -#define HORSESNEEDED 2 - -/* ein mensch wiegt 10, traegt also 5, ein pferd wiegt 50, traegt also 20. ein -** wagen wird von zwei pferden gezogen und traegt total 140, davon 40 die -** pferde, macht nur noch 100, aber samt eigenem gewicht (40) macht also 140. */ - -int personcapacity(const struct unit *u); -direction_t getdirection(const struct locale *); -void movement(void); -void run_to(struct unit * u, struct region * to); -struct unit *is_guarded(struct region * r, struct unit * u, unsigned int mask); -boolean is_guard(const struct unit * u, int mask); -int enoughsailors(const struct ship * sh, const struct region * r); -boolean canswim(struct unit *u); -boolean canfly(struct unit *u); -struct unit *get_captain(const struct ship * sh); -void travelthru(const struct unit * u, struct region * r); -struct ship * move_ship(struct ship * sh, struct region * from, struct region * to, struct region_list * route); -int walkingcapacity(const struct unit * u); -void follow_unit(struct unit * u); -boolean buildingtype_exists(const struct region * r, const struct building_type * bt, boolean working); -struct unit* owner_buildingtyp(const struct region * r, const struct building_type * bt); - -extern struct attrib_type at_speedup; - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_MOVEMENT +#define H_KRNL_MOVEMENT +#ifdef __cplusplus +extern "C" { +#endif + +struct unit; +struct ship; +struct building_type; + +/* die Zahlen sind genau äquivalent zu den race Flags */ +#define MV_CANNOTMOVE (1<<5) +#define MV_FLY (1<<7) /* kann fliegen */ +#define MV_SWIM (1<<8) /* kann schwimmen */ +#define MV_WALK (1<<9) /* kann über Land gehen */ + +/* Die tragekapaz. ist hardcodiert mit defines, da es bis jetzt sowieso nur 2 +** objekte gibt, die etwas tragen. */ +#define SILVERWEIGHT 1 +#define SCALEWEIGHT 100 /* Faktor, um den die Anzeige von gewichten + * * skaliert wird */ +#define HORSECAPACITY 7000 +#define WAGONCAPACITY 14000 + +#define HORSESNEEDED 2 + +/* ein mensch wiegt 10, traegt also 5, ein pferd wiegt 50, traegt also 20. ein +** wagen wird von zwei pferden gezogen und traegt total 140, davon 40 die +** pferde, macht nur noch 100, aber samt eigenem gewicht (40) macht also 140. */ + +int personcapacity(const struct unit *u); +direction_t getdirection(const struct locale *); +void movement(void); +void run_to(struct unit * u, struct region * to); +struct unit *is_guarded(struct region * r, struct unit * u, unsigned int mask); +boolean is_guard(const struct unit * u, int mask); +int enoughsailors(const struct ship * sh, const struct region * r); +boolean canswim(struct unit *u); +boolean canfly(struct unit *u); +struct unit *get_captain(const struct ship * sh); +void travelthru(const struct unit * u, struct region * r); +struct ship * move_ship(struct ship * sh, struct region * from, struct region * to, struct region_list * route); +int walkingcapacity(const struct unit * u); +void follow_unit(struct unit * u); +boolean buildingtype_exists(const struct region * r, const struct building_type * bt, boolean working); +struct unit* owner_buildingtyp(const struct region * r, const struct building_type * bt); + +extern struct attrib_type at_speedup; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/names.c b/src/kernel/names.c index 9d617cc0b..7875983c6 100644 --- a/src/kernel/names.c +++ b/src/kernel/names.c @@ -1,483 +1,483 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "names.h" - -/* kernel includes */ -#include "unit.h" -#include "region.h" -#include "faction.h" -#include "magic.h" -#include "race.h" -#include "terrain.h" -#include "terrainid.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -const char * -describe_braineater(unit * u, const struct locale * lang) -{ - return LOC(lang, "describe_braineater"); -} - -static const char * -make_names(const char * monster, int * num_postfix, int pprefix, int * num_name, int * num_prefix, int ppostfix) -{ - int uv, uu, un; - static char name[NAMESIZE + 1]; - char zText[32]; - const char * str; - - if (*num_prefix==0) { - - for (*num_prefix=0;;++*num_prefix) { - sprintf(zText, "%s_prefix_%d", monster, *num_prefix); - str = locale_getstring(default_locale, zText); - if (str==NULL) break; - } - - for (*num_name=0;;++*num_name) { - sprintf(zText, "%s_name_%d", monster, *num_name); - str = locale_getstring(default_locale, zText); - if (str==NULL) break; - } - - for (*num_postfix=0;;++*num_postfix) { - sprintf(zText, "%s_postfix_%d", monster, *num_postfix); - str = locale_getstring(default_locale, zText); - if (str==NULL) break; - } - } - - if (*num_name==0) { - return NULL; - } - - /* nur 50% aller Namen haben "Vor-Teil" */ - uv = rng_int() % (*num_prefix * pprefix); - - uu = rng_int() % *num_name; - - /* nur 50% aller Namen haben "Nach-Teil", wenn kein Vor-Teil */ - if (uv>=*num_prefix) { - un = rng_int() % *num_postfix; - } else { - un = rng_int() % (*num_postfix * ppostfix); - } - - name[0] = 0; - if (uv < *num_prefix) { - sprintf(zText, "%s_prefix_%d", monster, uv); - str = locale_getstring(default_locale, zText); - if (str) { - strcat(name, (const char *)str); - strcat(name, " "); - } - } - - sprintf(zText, "%s_name_%d", monster, uu); - str = locale_getstring(default_locale, zText); - if (str) strcat(name, (const char *)str); - - if (un < *num_postfix) { - sprintf(zText, "%s_postfix_%d", monster, un); - str = locale_getstring(default_locale, zText); - if (str) { - strcat(name, " "); - strcat(name, (const char *)str); - } - } - return name; -} - -const char * -undead_name(const unit * u) -{ - static int num_postfix, num_name, num_prefix; - return make_names("undead", &num_postfix, 2, &num_name, &num_prefix, 2); -} - -const char * -skeleton_name(const unit * u) -{ - static int num_postfix, num_name, num_prefix; - return make_names("skeleton", &num_postfix, 5, &num_name, &num_prefix, 2); -} - -const char * -zombie_name(const unit * u) -{ - static int num_postfix, num_name, num_prefix; - return make_names("zombie", &num_postfix, 5, &num_name, &num_prefix, 2); -} - -const char * -ghoul_name(const unit * u) -{ - static int num_postfix, num_name, num_prefix; - return make_names("ghoul", &num_postfix, 5, &num_name, &num_prefix, 4); -} - - -/* Drachen */ - -#define SIL1 15 - -const char *silbe1[SIL1] = { - "Tar", - "Ter", - "Tor", - "Pan", - "Par", - "Per", - "Nim", - "Nan", - "Nun", - "Gor", - "For", - "Fer", - "Kar", - "Kur", - "Pen", -}; - -#define SIL2 19 - -const char *silbe2[SIL2] = { - "da", - "do", - "dil", - "di", - "dor", - "dar", - "ra", - "ran", - "ras", - "ro", - "rum", - "rin", - "ten", - "tan", - "ta", - "tor", - "gur", - "ga", - "gas", -}; - -#define SIL3 14 - -const char *silbe3[SIL3] = { - "gul", - "gol", - "dol", - "tan", - "tar", - "tur", - "sur", - "sin", - "kur", - "kor", - "kar", - "dul", - "dol", - "bus", -}; - -const char * -generic_name(const unit *u) -{ - if (u->no == 1) { - return LOC(u->faction->locale, mkname("race", u->race->_name[0])); - } - return LOC(u->faction->locale, mkname("race", u->race->_name[1])); -} - -const char * -dragon_name(const unit *u) -{ - static char name[NAMESIZE + 1]; - int rnd, ter = 0; - int anzahl = 1; - static int num_postfix; - char zText[32]; - const char * str; - - if (num_postfix==0) { - for (num_postfix=0;;++num_postfix) { - sprintf(zText, "dragon_postfix_%d", num_postfix); - str = locale_getstring(default_locale, zText); - if (str==NULL) break; - } - if (num_postfix==0) num_postfix = -1; - } - if (num_postfix<=0) { - return NULL; - } - - if (u) { - region *r = u->region; - anzahl = u->number; - switch (rterrain(r)) { - case T_PLAIN: - ter = 1; - break; - case T_MOUNTAIN: - ter = 2; - break; - case T_DESERT: - ter = 3; - break; - case T_SWAMP: - ter = 4; - break; - case T_GLACIER: - ter = 5; - break; - } - } - - rnd = num_postfix / 6; - rnd = (rng_int() % rnd) + ter * rnd; - - sprintf(zText, "dragon_postfix_%d", rnd); - - str = locale_getstring(default_locale, zText); - assert(str!=NULL); - - if (anzahl > 1) { - const char * no_article = strchr((const char *)str, ' '); - assert(no_article); - /* TODO: GERMAN */ - sprintf(name, "Die %sn von %s", no_article, rname(u->region, default_locale)); - } else { - char n[32]; - - strcpy(n, silbe1[rng_int() % SIL1]); - strcat(n, silbe2[rng_int() % SIL2]); - strcat(n, silbe3[rng_int() % SIL3]); - if (rng_int() % 5 > 2) { - sprintf(name, "%s, %s", n, str); /* "Name, der Titel" */ - } else { - strcpy(name, (const char *)str); /* "Der Titel Name" */ - name[0] = (char)toupper(name[0]); /* TODO: UNICODE - should use towupper() */ - strcat(name, " "); - strcat(name, n); - } - if (u && (rng_int() % 3 == 0)) { - strcat(name, " von "); - strcat(name, (const char *)rname(u->region, default_locale)); - } - } - - return name; -} - -/* Dracoide */ - -#define DRAC_PRE 13 -static const char *drac_pre[DRAC_PRE] = { - "Siss", - "Xxaa", - "Shht", - "X'xixi", - "Xar", - "X'zish", - "X", - "Sh", - "R", - "Z", - "Y", - "L", - "Ck", -}; - -#define DRAC_MID 12 -static const char *drac_mid[DRAC_MID] = { - "siss", - "xxaa", - "shht", - "xxi", - "xar", - "x'zish", - "x", - "sh", - "r", - "z'ck", - "y", - "rl" -}; - -#define DRAC_SUF 10 -static const char *drac_suf[DRAC_SUF] = { - "xil", - "shh", - "s", - "x", - "arr", - "lll", - "lll", - "shack", - "ck", - "k" -}; - -const char * -dracoid_name(const unit *u) -{ - static char name[NAMESIZE + 1]; - int mid_syllabels; - - u=u; - /* Wieviele Mittelteile? */ - - mid_syllabels = rng_int()%4; - - strcpy(name, drac_pre[rng_int()%DRAC_PRE]); - while(mid_syllabels > 0) { - mid_syllabels--; - if(rng_int()%10 < 4) strcat(name,"'"); - strcat(name, drac_mid[rng_int()%DRAC_MID]); - } - strcat(name, drac_suf[rng_int()%DRAC_SUF]); - return name; -} - -/** returns an abbreviation of a string. - * TODO: buflen is being ignored */ - -const char * -abkz(const char *s, char * buf, size_t buflen, size_t maxchars) -{ - const char *p = s; - char * bufp; - unsigned int c = 0; - size_t bpt, i; - ucs4_t ucs; - size_t size; - int result; - - /* Prüfen, ob Kurz genug */ - - if (strlen(s) <= maxchars) { - return s; - } - /* Anzahl der Wörter feststellen */ - - while (*p != 0) { - - result = unicode_utf8_to_ucs4(&ucs, p, &size); - assert(result==0 || "damnit, we're not handling invalid input here!"); - - /* Leerzeichen überspringen */ - while (*p != 0 && !iswalnum((wint_t)ucs)) { - p += size; - result = unicode_utf8_to_ucs4(&ucs, p, &size); - assert(result==0 || "damnit, we're not handling invalid input here!"); - } - - /* Counter erhöhen */ - if (*p != 0) ++c; - - /* alnums überspringen */ - while (*p != 0 && iswalnum((wint_t)ucs)) { - p+=size; - result = unicode_utf8_to_ucs4(&ucs, p, &size); - assert(result==0 || "damnit, we're not handling invalid input here!"); - } - } - - /* Buchstaben pro Teilkürzel = MAX(1,max/AnzWort) */ - - bpt = MAX(1, maxchars / c); - - /* Einzelne Wörter anspringen und jeweils die ersten BpT kopieren */ - - p = s; - c = 0; - bufp = buf; - - result = unicode_utf8_to_ucs4(&ucs, p, &size); - assert(result==0 || "damnit, we're not handling invalid input here!"); - - while (*p != 0 && c < maxchars) { - /* Leerzeichen überspringen */ - - while (*p != 0 && !iswalnum((wint_t)ucs)) { - p+=size; - result = unicode_utf8_to_ucs4(&ucs, p, &size); - assert(result==0 || "damnit, we're not handling invalid input here!"); - } - - /* alnums übertragen */ - - for (i = 0; i < bpt && *p != 0 && iswalnum((wint_t)ucs); ++i) { - memcpy(bufp, p, size); - p += size; - bufp += size; - ++c; - - result = unicode_utf8_to_ucs4(&ucs, p, &size); - assert(result==0 || "damnit, we're not handling invalid input here!"); - } - - /* Bis zum nächsten Leerzeichen */ - - while (c < maxchars && *p != 0 && iswalnum((wint_t)ucs)) { - p+=size; - result = unicode_utf8_to_ucs4(&ucs, p, &size); - assert(result==0 || "damnit, we're not handling invalid input here!"); - } - } - - *bufp = 0; - - return buf; -} - -void -register_names(void) -{ - register_function((pf_generic)describe_braineater, "describe_braineater"); - /* function name - * generate a name for a nonplayerunit - * race->generate_name() */ - register_function((pf_generic)undead_name, "nameundead"); - register_function((pf_generic)skeleton_name, "nameskeleton"); - register_function((pf_generic)zombie_name, "namezombie"); - register_function((pf_generic)ghoul_name, "nameghoul"); - register_function((pf_generic)dragon_name, "namedragon"); - register_function((pf_generic)dracoid_name, "namedracoid"); - register_function((pf_generic)generic_name, "namegeneric"); -} - - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "names.h" + +/* kernel includes */ +#include "unit.h" +#include "region.h" +#include "faction.h" +#include "magic.h" +#include "race.h" +#include "terrain.h" +#include "terrainid.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +const char * +describe_braineater(unit * u, const struct locale * lang) +{ + return LOC(lang, "describe_braineater"); +} + +static const char * +make_names(const char * monster, int * num_postfix, int pprefix, int * num_name, int * num_prefix, int ppostfix) +{ + int uv, uu, un; + static char name[NAMESIZE + 1]; + char zText[32]; + const char * str; + + if (*num_prefix==0) { + + for (*num_prefix=0;;++*num_prefix) { + sprintf(zText, "%s_prefix_%d", monster, *num_prefix); + str = locale_getstring(default_locale, zText); + if (str==NULL) break; + } + + for (*num_name=0;;++*num_name) { + sprintf(zText, "%s_name_%d", monster, *num_name); + str = locale_getstring(default_locale, zText); + if (str==NULL) break; + } + + for (*num_postfix=0;;++*num_postfix) { + sprintf(zText, "%s_postfix_%d", monster, *num_postfix); + str = locale_getstring(default_locale, zText); + if (str==NULL) break; + } + } + + if (*num_name==0) { + return NULL; + } + + /* nur 50% aller Namen haben "Vor-Teil" */ + uv = rng_int() % (*num_prefix * pprefix); + + uu = rng_int() % *num_name; + + /* nur 50% aller Namen haben "Nach-Teil", wenn kein Vor-Teil */ + if (uv>=*num_prefix) { + un = rng_int() % *num_postfix; + } else { + un = rng_int() % (*num_postfix * ppostfix); + } + + name[0] = 0; + if (uv < *num_prefix) { + sprintf(zText, "%s_prefix_%d", monster, uv); + str = locale_getstring(default_locale, zText); + if (str) { + strcat(name, (const char *)str); + strcat(name, " "); + } + } + + sprintf(zText, "%s_name_%d", monster, uu); + str = locale_getstring(default_locale, zText); + if (str) strcat(name, (const char *)str); + + if (un < *num_postfix) { + sprintf(zText, "%s_postfix_%d", monster, un); + str = locale_getstring(default_locale, zText); + if (str) { + strcat(name, " "); + strcat(name, (const char *)str); + } + } + return name; +} + +const char * +undead_name(const unit * u) +{ + static int num_postfix, num_name, num_prefix; + return make_names("undead", &num_postfix, 2, &num_name, &num_prefix, 2); +} + +const char * +skeleton_name(const unit * u) +{ + static int num_postfix, num_name, num_prefix; + return make_names("skeleton", &num_postfix, 5, &num_name, &num_prefix, 2); +} + +const char * +zombie_name(const unit * u) +{ + static int num_postfix, num_name, num_prefix; + return make_names("zombie", &num_postfix, 5, &num_name, &num_prefix, 2); +} + +const char * +ghoul_name(const unit * u) +{ + static int num_postfix, num_name, num_prefix; + return make_names("ghoul", &num_postfix, 5, &num_name, &num_prefix, 4); +} + + +/* Drachen */ + +#define SIL1 15 + +const char *silbe1[SIL1] = { + "Tar", + "Ter", + "Tor", + "Pan", + "Par", + "Per", + "Nim", + "Nan", + "Nun", + "Gor", + "For", + "Fer", + "Kar", + "Kur", + "Pen", +}; + +#define SIL2 19 + +const char *silbe2[SIL2] = { + "da", + "do", + "dil", + "di", + "dor", + "dar", + "ra", + "ran", + "ras", + "ro", + "rum", + "rin", + "ten", + "tan", + "ta", + "tor", + "gur", + "ga", + "gas", +}; + +#define SIL3 14 + +const char *silbe3[SIL3] = { + "gul", + "gol", + "dol", + "tan", + "tar", + "tur", + "sur", + "sin", + "kur", + "kor", + "kar", + "dul", + "dol", + "bus", +}; + +const char * +generic_name(const unit *u) +{ + if (u->no == 1) { + return LOC(u->faction->locale, mkname("race", u->race->_name[0])); + } + return LOC(u->faction->locale, mkname("race", u->race->_name[1])); +} + +const char * +dragon_name(const unit *u) +{ + static char name[NAMESIZE + 1]; + int rnd, ter = 0; + int anzahl = 1; + static int num_postfix; + char zText[32]; + const char * str; + + if (num_postfix==0) { + for (num_postfix=0;;++num_postfix) { + sprintf(zText, "dragon_postfix_%d", num_postfix); + str = locale_getstring(default_locale, zText); + if (str==NULL) break; + } + if (num_postfix==0) num_postfix = -1; + } + if (num_postfix<=0) { + return NULL; + } + + if (u) { + region *r = u->region; + anzahl = u->number; + switch (rterrain(r)) { + case T_PLAIN: + ter = 1; + break; + case T_MOUNTAIN: + ter = 2; + break; + case T_DESERT: + ter = 3; + break; + case T_SWAMP: + ter = 4; + break; + case T_GLACIER: + ter = 5; + break; + } + } + + rnd = num_postfix / 6; + rnd = (rng_int() % rnd) + ter * rnd; + + sprintf(zText, "dragon_postfix_%d", rnd); + + str = locale_getstring(default_locale, zText); + assert(str!=NULL); + + if (anzahl > 1) { + const char * no_article = strchr((const char *)str, ' '); + assert(no_article); + /* TODO: GERMAN */ + sprintf(name, "Die %sn von %s", no_article, rname(u->region, default_locale)); + } else { + char n[32]; + + strcpy(n, silbe1[rng_int() % SIL1]); + strcat(n, silbe2[rng_int() % SIL2]); + strcat(n, silbe3[rng_int() % SIL3]); + if (rng_int() % 5 > 2) { + sprintf(name, "%s, %s", n, str); /* "Name, der Titel" */ + } else { + strcpy(name, (const char *)str); /* "Der Titel Name" */ + name[0] = (char)toupper(name[0]); /* TODO: UNICODE - should use towupper() */ + strcat(name, " "); + strcat(name, n); + } + if (u && (rng_int() % 3 == 0)) { + strcat(name, " von "); + strcat(name, (const char *)rname(u->region, default_locale)); + } + } + + return name; +} + +/* Dracoide */ + +#define DRAC_PRE 13 +static const char *drac_pre[DRAC_PRE] = { + "Siss", + "Xxaa", + "Shht", + "X'xixi", + "Xar", + "X'zish", + "X", + "Sh", + "R", + "Z", + "Y", + "L", + "Ck", +}; + +#define DRAC_MID 12 +static const char *drac_mid[DRAC_MID] = { + "siss", + "xxaa", + "shht", + "xxi", + "xar", + "x'zish", + "x", + "sh", + "r", + "z'ck", + "y", + "rl" +}; + +#define DRAC_SUF 10 +static const char *drac_suf[DRAC_SUF] = { + "xil", + "shh", + "s", + "x", + "arr", + "lll", + "lll", + "shack", + "ck", + "k" +}; + +const char * +dracoid_name(const unit *u) +{ + static char name[NAMESIZE + 1]; + int mid_syllabels; + + u=u; + /* Wieviele Mittelteile? */ + + mid_syllabels = rng_int()%4; + + strcpy(name, drac_pre[rng_int()%DRAC_PRE]); + while(mid_syllabels > 0) { + mid_syllabels--; + if(rng_int()%10 < 4) strcat(name,"'"); + strcat(name, drac_mid[rng_int()%DRAC_MID]); + } + strcat(name, drac_suf[rng_int()%DRAC_SUF]); + return name; +} + +/** returns an abbreviation of a string. + * TODO: buflen is being ignored */ + +const char * +abkz(const char *s, char * buf, size_t buflen, size_t maxchars) +{ + const char *p = s; + char * bufp; + unsigned int c = 0; + size_t bpt, i; + ucs4_t ucs; + size_t size; + int result; + + /* Prüfen, ob Kurz genug */ + + if (strlen(s) <= maxchars) { + return s; + } + /* Anzahl der Wörter feststellen */ + + while (*p != 0) { + + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result==0 || "damnit, we're not handling invalid input here!"); + + /* Leerzeichen überspringen */ + while (*p != 0 && !iswalnum((wint_t)ucs)) { + p += size; + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result==0 || "damnit, we're not handling invalid input here!"); + } + + /* Counter erhöhen */ + if (*p != 0) ++c; + + /* alnums überspringen */ + while (*p != 0 && iswalnum((wint_t)ucs)) { + p+=size; + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result==0 || "damnit, we're not handling invalid input here!"); + } + } + + /* Buchstaben pro Teilkürzel = MAX(1,max/AnzWort) */ + + bpt = MAX(1, maxchars / c); + + /* Einzelne Wörter anspringen und jeweils die ersten BpT kopieren */ + + p = s; + c = 0; + bufp = buf; + + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result==0 || "damnit, we're not handling invalid input here!"); + + while (*p != 0 && c < maxchars) { + /* Leerzeichen überspringen */ + + while (*p != 0 && !iswalnum((wint_t)ucs)) { + p+=size; + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result==0 || "damnit, we're not handling invalid input here!"); + } + + /* alnums übertragen */ + + for (i = 0; i < bpt && *p != 0 && iswalnum((wint_t)ucs); ++i) { + memcpy(bufp, p, size); + p += size; + bufp += size; + ++c; + + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result==0 || "damnit, we're not handling invalid input here!"); + } + + /* Bis zum nächsten Leerzeichen */ + + while (c < maxchars && *p != 0 && iswalnum((wint_t)ucs)) { + p+=size; + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result==0 || "damnit, we're not handling invalid input here!"); + } + } + + *bufp = 0; + + return buf; +} + +void +register_names(void) +{ + register_function((pf_generic)describe_braineater, "describe_braineater"); + /* function name + * generate a name for a nonplayerunit + * race->generate_name() */ + register_function((pf_generic)undead_name, "nameundead"); + register_function((pf_generic)skeleton_name, "nameskeleton"); + register_function((pf_generic)zombie_name, "namezombie"); + register_function((pf_generic)ghoul_name, "nameghoul"); + register_function((pf_generic)dragon_name, "namedragon"); + register_function((pf_generic)dracoid_name, "namedracoid"); + register_function((pf_generic)generic_name, "namegeneric"); +} + + diff --git a/src/kernel/names.h b/src/kernel/names.h index d689197d2..0cde3a55d 100644 --- a/src/kernel/names.h +++ b/src/kernel/names.h @@ -1,37 +1,37 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_NAMES -#define H_KRNL_NAMES -#ifdef __cplusplus -extern "C" { -#endif -extern void register_names(void); -const char *undead_name(const struct unit * u); -const char *skeleton_name(const struct unit * u); -const char *zombie_name(const struct unit * u); -const char *ghoul_name(const struct unit * u); -const char *dragon_name(const struct unit *u); -const char *dracoid_name(const struct unit *u); -const char *generic_name(const struct unit *u); -const char *abkz(const char *s, char * buf, size_t size, size_t maxchars); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_NAMES +#define H_KRNL_NAMES +#ifdef __cplusplus +extern "C" { +#endif +extern void register_names(void); +const char *undead_name(const struct unit * u); +const char *skeleton_name(const struct unit * u); +const char *zombie_name(const struct unit * u); +const char *ghoul_name(const struct unit * u); +const char *dragon_name(const struct unit *u); +const char *dracoid_name(const struct unit *u); +const char *generic_name(const struct unit *u); +const char *abkz(const char *s, char * buf, size_t size, size_t maxchars); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/objtypes.h b/src/kernel/objtypes.h index 789ef0c5d..6ba12e034 100644 --- a/src/kernel/objtypes.h +++ b/src/kernel/objtypes.h @@ -1,40 +1,40 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_OBJTYPES -#define H_KRNL_OBJTYPES -#ifdef __cplusplus -extern "C" { -#endif - -enum { - TYP_UNIT, - TYP_REGION, - TYP_BUILDING, - TYP_SHIP, - TYP_FACTION, - TYP_ACTION, - TYP_TRIGGER, - TYP_TIMEOUT -}; - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_OBJTYPES +#define H_KRNL_OBJTYPES +#ifdef __cplusplus +extern "C" { +#endif + +enum { + TYP_UNIT, + TYP_REGION, + TYP_BUILDING, + TYP_SHIP, + TYP_FACTION, + TYP_ACTION, + TYP_TRIGGER, + TYP_TIMEOUT +}; + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/kernel/order.c b/src/kernel/order.c index 690cd0181..2ecf5162e 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -1,517 +1,517 @@ -/* vi: set ts=2: - +-------------------+ - | | Christian Schlittchen - | Eressea PBEM host | Enno Rehling - | (c) 1998 - 2004 | Katja Zedel - | | - +-------------------+ - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "order.h" - -#include "skill.h" - -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include - -# define ORD_KEYWORD(ord) (ord)->data->_keyword -# 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 * study_orders[MAXSKILLS]; - const struct locale * lang; -} locale_data; - -static struct locale_data * locale_array[16]; -static int nlocales = 0; - -typedef struct order_data { - char * _str; - int _refcount : 20; - int _lindex : 4; - keyword_t _keyword; -} order_data; - -static void -release_data(order_data * data) -{ - if (data) { - if (--data->_refcount == 0) { - if (data->_str) free(data->_str); - free(data); - } - } -} - -void -replace_order(order ** dlist, order * orig, const order * src) -{ - while (*dlist!=NULL) { - order * dst = *dlist; - if (dst->data==orig->data) { - order * cpy = copy_order(src); - *dlist = cpy; - cpy->next = dst->next; - dst->next = 0; - free_order(dst); - } - dlist = &(*dlist)->next; - } -} - -keyword_t -get_keyword(const order * ord) -{ - if (ord==NULL) { - return NOKEYWORD; - } - return ORD_KEYWORD(ord); -} - -/** returns a plain-text representation of the order. - * This is the inverse function to the parse_order command. Note that - * keywords are expanded to their full length. - */ -static char * -get_command(const order * ord, char * sbuffer, size_t size) -{ - char * bufp = sbuffer; - const char * text = ORD_STRING(ord); - keyword_t kwd = ORD_KEYWORD(ord); - int bytes; - - if (ord->_persistent) { - if (size>0) { - *bufp++ = '@'; - --size; - } else { - WARN_STATIC_BUFFER(); - } - } - if (kwd!=NOKEYWORD) { - const struct locale * lang = ORD_LOCALE(ord); - if (size>0) { - if (text) --size; - bytes = (int)strlcpy(bufp, (const char*)LOC(lang, keywords[kwd]), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (text) *bufp++ = ' '; - } else WARN_STATIC_BUFFER(); - } - if (text) { - bytes = (int)strlcpy(bufp, (const char *)text, size); - if (wrptr(&bufp, &size, bytes)!=0) { - WARN_STATIC_BUFFER(); - if (bufp-sbuffer>=6) { - bufp -= 6; - while (bufp>sbuffer&& (*bufp&0x80)!=0) { - ++size; - --bufp; - } - memcpy(bufp+1, "[...]", 6); /* TODO: make sure this only happens in eval_command */ - bufp += 6; - } - } - } - if (size>0) *bufp = 0; - return sbuffer; -} - -char * -getcommand(const order * ord) -{ - char sbuffer[DISPLAYSIZE*2]; - return strdup(get_command(ord, sbuffer, sizeof(sbuffer))); -} - -void -free_order(order * ord) -{ - if (ord!=NULL) { - assert(ord->next==0); - - release_data(ord->data); - free(ord); - } -} - -order * -copy_order(const order * src) -{ - if (src!=NULL) { - order * ord = (order*)malloc(sizeof(order)); - ord->next = NULL; - ord->_persistent = src->_persistent; - ord->data = src->data; - ++ord->data->_refcount; - return ord; - } - return NULL; -} - -void -set_order(struct order ** destp, struct order * src) -{ - if (*destp==src) return; - free_order(*destp); - *destp = src; -} - -void -free_orders(order ** olist) -{ - while (*olist) { - order * ord = *olist; - *olist = ord->next; - ord->next = NULL; - free_order(ord); - } -} - -static order_data * -create_data(keyword_t kwd, const char * sptr, int lindex) -{ - const char * s = sptr; - order_data * data; - const struct locale * lang = locale_array[lindex]->lang; - - if (kwd!=NOKEYWORD) s = (*sptr)?sptr:NULL; - - /* learning, only one order_data per skill required */ - if (kwd==K_STUDY) { - skill_t sk = findskill(parse_token(&sptr), lang); - switch (sk) { - case NOSKILL: /* fehler */ - break; - case SK_MAGIC: /* kann parameter haben */ - if (*sptr != 0) break; - default: /* nur skill als Parameter, keine extras */ - data = locale_array[lindex]->study_orders[sk]; - if (data==NULL) { - const char * skname = skillname(sk, lang); - data = (order_data*)malloc(sizeof(order_data)); - locale_array[lindex]->study_orders[sk] = data; - data->_keyword = kwd; - data->_lindex = lindex; - if (strchr(skname, ' ')!=NULL) { - size_t len = strlen(skname); - data->_str = malloc(len+3); - data->_str[0]='\"'; - memcpy(data->_str+1, skname, len); - data->_str[len+1]='\"'; - data->_str[len+2]='\0'; - } else { - data->_str = strdup(skname); - } - data->_refcount = 1; - } - ++data->_refcount; - return data; - } - } - - /* orders with no parameter, only one order_data per order required */ - else if (kwd!=NOKEYWORD && *sptr == 0) { - data = locale_array[lindex]->short_orders[kwd]; - if (data == NULL) { - data = (order_data*)malloc(sizeof(order_data)); - locale_array[lindex]->short_orders[kwd] = data; - data->_keyword = kwd; - data->_lindex = lindex; - data->_str = NULL; - data->_refcount = 1; - } - ++data->_refcount; - return data; - } - data = (order_data*)malloc(sizeof(order_data)); - data->_keyword = kwd; - data->_lindex = lindex; - data->_str = s?strdup(s):NULL; - data->_refcount = 1; - return data; -} - -static order * -create_order_i(keyword_t kwd, const char * sptr, int persistent, const struct locale * lang) -{ - order * ord = NULL; - int lindex; - - /* if this is just nonsense, then we skip it. */ - if (lomem) { - switch (kwd) { - case K_KOMMENTAR: - case NOKEYWORD: - return NULL; - case K_LIEFERE: - kwd = K_GIVE; - persistent = 1; - break; - default: - break; - } - } - - for (lindex=0;lindex!=nlocales;++lindex) { - if (locale_array[lindex]->lang==lang) break; - } - if (lindex==nlocales) { - locale_array[nlocales] = (locale_data*)calloc(1, sizeof(locale_data)); - locale_array[nlocales]->lang = lang; - ++nlocales; - } - - ord = (order*)malloc(sizeof(order)); - ord->_persistent = persistent; - ord->next = NULL; - - ord->data = create_data(kwd, sptr, lindex); - - return ord; -} - -order * -create_order(keyword_t kwd, const struct locale * lang, const char * params, ...) -{ - char zBuffer[DISPLAYSIZE]; - if (params) { - char * bufp = zBuffer; - int bytes; - size_t size = sizeof(zBuffer) - 1; - va_list marker; - - va_start(marker, params); - while (*params) { - if (*params=='%') { - int i; - const char * s; - ++params; - switch (*params) { - case 's': - s = va_arg(marker, const char *); - bytes = (int)strlcpy(bufp, s, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - break; - case 'd': - i = va_arg(marker, int); - bytes = (int)strlcpy(bufp, itoa10(i), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - break; - case 'i': - i = va_arg(marker, int); - bytes = (int)strlcpy(bufp, itoa36(i), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - break; - default: - assert(!"unknown format-character in create_order"); - } - } else if (size>0) { - *bufp++ = *params; - --size; - } - ++params; - } - va_end(marker); - *bufp = 0; - } else { - zBuffer[0] = 0; - } - return create_order_i(kwd, zBuffer, 0, lang); -} - -order * -parse_order(const char * s, const struct locale * lang) -{ - while (*s && !isalnum(*(unsigned char*)s) && !ispunct(*(unsigned char*)s)) ++s; - if (*s!=0) { - keyword_t kwd; - const char * sptr; - int persistent = 0; - - while (*s=='@') { - persistent = 1; - ++s; - } - sptr = s; - kwd = findkeyword(parse_token(&sptr), lang); - if (kwd!=NOKEYWORD) { - while (isxspace(*(unsigned char*)sptr)) ++sptr; - s = sptr; - } - return create_order_i(kwd, s, persistent, lang); - } - return NULL; -} - -boolean -is_repeated(const order * ord) -{ - keyword_t kwd = ORD_KEYWORD(ord); - const struct locale * lang = ORD_LOCALE(ord); - param_t param; - - switch (kwd) { - case K_CAST: - case K_BUY: - case K_SELL: - case K_ROUTE: - case K_DRIVE: - case K_WORK: - case K_BESIEGE: - case K_ENTERTAIN: - case K_TAX: - case K_RESEARCH: - case K_SPY: - case K_STEAL: - case K_SABOTAGE: - case K_STUDY: - case K_TEACH: - case K_BREED: - case K_PIRACY: - return true; - - case K_PLANT: - return true; - - case K_FOLLOW: - /* FOLLOW is only a long order if we are following a ship. */ - parser_pushstate(); - init_tokens(ord); - skip_token(); - param = getparam(lang); - parser_popstate(); - - if (param == P_SHIP) return true; - break; - - case K_MAKE: - /* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen - * Arten von MACHE zaehlen aber als neue defaults und werden - * behandelt wie die anderen (deswegen kein break nach case - * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) - * abgespeichert). */ - parser_pushstate(); - init_tokens(ord); /* initialize token-parser */ - skip_token(); - param = getparam(lang); - parser_popstate(); - - if (param != P_TEMP) return true; - break; - } - return false; -} - -boolean -is_exclusive(const order * ord) -{ - keyword_t kwd = ORD_KEYWORD(ord); - const struct locale * lang = ORD_LOCALE(ord); - param_t param; - - switch (kwd) { - case K_MOVE: - case K_WEREWOLF: - /* these should not become persistent */ - case K_ROUTE: - case K_DRIVE: - case K_WORK: - case K_BESIEGE: - case K_ENTERTAIN: - case K_TAX: - case K_RESEARCH: - case K_SPY: - case K_STEAL: - case K_SABOTAGE: - case K_STUDY: - case K_TEACH: - case K_BREED: - case K_PIRACY: - return true; - - case K_PLANT: - return true; - - case K_FOLLOW: - /* FOLLOW is only a long order if we are following a ship. */ - parser_pushstate(); - init_tokens(ord); - skip_token(); - param = getparam(lang); - parser_popstate(); - - if (param == P_SHIP) return true; - break; - - case K_MAKE: - /* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen - * Arten von MACHE zaehlen aber als neue defaults und werden - * behandelt wie die anderen (deswegen kein break nach case - * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) - * abgespeichert). */ - parser_pushstate(); - init_tokens(ord); /* initialize token-parser */ - skip_token(); - param = getparam(lang); - parser_popstate(); - - if (param != P_TEMP) return true; - break; - } - return false; -} - -boolean -is_persistent(const order * ord) -{ - keyword_t kwd = ORD_KEYWORD(ord); - boolean persist = ord->_persistent!=0; - switch (kwd) { - case K_MOVE: - case K_WEREWOLF: - case NOKEYWORD: - /* lang, aber niemals persistent! */ - return false; - - case K_KOMMENTAR: - case K_LIEFERE: - return true; - } - - return persist || is_repeated(ord); -} - -char * -write_order(const order * ord, char * buffer, size_t size) -{ - if (ord==0) { - buffer[0]=0; - } else { - keyword_t kwd = ORD_KEYWORD(ord); - if (kwd==NOKEYWORD) { - const char * text = ORD_STRING(ord); - strlcpy(buffer, (const char *)text, size); - } else { - get_command(ord, buffer, size); - } - } - return buffer; -} +/* vi: set ts=2: + +-------------------+ + | | Christian Schlittchen + | Eressea PBEM host | Enno Rehling + | (c) 1998 - 2004 | Katja Zedel + | | + +-------------------+ + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "order.h" + +#include "skill.h" + +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +# define ORD_KEYWORD(ord) (ord)->data->_keyword +# 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 * study_orders[MAXSKILLS]; + const struct locale * lang; +} locale_data; + +static struct locale_data * locale_array[16]; +static int nlocales = 0; + +typedef struct order_data { + char * _str; + int _refcount : 20; + int _lindex : 4; + keyword_t _keyword; +} order_data; + +static void +release_data(order_data * data) +{ + if (data) { + if (--data->_refcount == 0) { + if (data->_str) free(data->_str); + free(data); + } + } +} + +void +replace_order(order ** dlist, order * orig, const order * src) +{ + while (*dlist!=NULL) { + order * dst = *dlist; + if (dst->data==orig->data) { + order * cpy = copy_order(src); + *dlist = cpy; + cpy->next = dst->next; + dst->next = 0; + free_order(dst); + } + dlist = &(*dlist)->next; + } +} + +keyword_t +get_keyword(const order * ord) +{ + if (ord==NULL) { + return NOKEYWORD; + } + return ORD_KEYWORD(ord); +} + +/** returns a plain-text representation of the order. + * This is the inverse function to the parse_order command. Note that + * keywords are expanded to their full length. + */ +static char * +get_command(const order * ord, char * sbuffer, size_t size) +{ + char * bufp = sbuffer; + const char * text = ORD_STRING(ord); + keyword_t kwd = ORD_KEYWORD(ord); + int bytes; + + if (ord->_persistent) { + if (size>0) { + *bufp++ = '@'; + --size; + } else { + WARN_STATIC_BUFFER(); + } + } + if (kwd!=NOKEYWORD) { + const struct locale * lang = ORD_LOCALE(ord); + if (size>0) { + if (text) --size; + bytes = (int)strlcpy(bufp, (const char*)LOC(lang, keywords[kwd]), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (text) *bufp++ = ' '; + } else WARN_STATIC_BUFFER(); + } + if (text) { + bytes = (int)strlcpy(bufp, (const char *)text, size); + if (wrptr(&bufp, &size, bytes)!=0) { + WARN_STATIC_BUFFER(); + if (bufp-sbuffer>=6) { + bufp -= 6; + while (bufp>sbuffer&& (*bufp&0x80)!=0) { + ++size; + --bufp; + } + memcpy(bufp+1, "[...]", 6); /* TODO: make sure this only happens in eval_command */ + bufp += 6; + } + } + } + if (size>0) *bufp = 0; + return sbuffer; +} + +char * +getcommand(const order * ord) +{ + char sbuffer[DISPLAYSIZE*2]; + return strdup(get_command(ord, sbuffer, sizeof(sbuffer))); +} + +void +free_order(order * ord) +{ + if (ord!=NULL) { + assert(ord->next==0); + + release_data(ord->data); + free(ord); + } +} + +order * +copy_order(const order * src) +{ + if (src!=NULL) { + order * ord = (order*)malloc(sizeof(order)); + ord->next = NULL; + ord->_persistent = src->_persistent; + ord->data = src->data; + ++ord->data->_refcount; + return ord; + } + return NULL; +} + +void +set_order(struct order ** destp, struct order * src) +{ + if (*destp==src) return; + free_order(*destp); + *destp = src; +} + +void +free_orders(order ** olist) +{ + while (*olist) { + order * ord = *olist; + *olist = ord->next; + ord->next = NULL; + free_order(ord); + } +} + +static order_data * +create_data(keyword_t kwd, const char * sptr, int lindex) +{ + const char * s = sptr; + order_data * data; + const struct locale * lang = locale_array[lindex]->lang; + + if (kwd!=NOKEYWORD) s = (*sptr)?sptr:NULL; + + /* learning, only one order_data per skill required */ + if (kwd==K_STUDY) { + skill_t sk = findskill(parse_token(&sptr), lang); + switch (sk) { + case NOSKILL: /* fehler */ + break; + case SK_MAGIC: /* kann parameter haben */ + if (*sptr != 0) break; + default: /* nur skill als Parameter, keine extras */ + data = locale_array[lindex]->study_orders[sk]; + if (data==NULL) { + const char * skname = skillname(sk, lang); + data = (order_data*)malloc(sizeof(order_data)); + locale_array[lindex]->study_orders[sk] = data; + data->_keyword = kwd; + data->_lindex = lindex; + if (strchr(skname, ' ')!=NULL) { + size_t len = strlen(skname); + data->_str = malloc(len+3); + data->_str[0]='\"'; + memcpy(data->_str+1, skname, len); + data->_str[len+1]='\"'; + data->_str[len+2]='\0'; + } else { + data->_str = strdup(skname); + } + data->_refcount = 1; + } + ++data->_refcount; + return data; + } + } + + /* orders with no parameter, only one order_data per order required */ + else if (kwd!=NOKEYWORD && *sptr == 0) { + data = locale_array[lindex]->short_orders[kwd]; + if (data == NULL) { + data = (order_data*)malloc(sizeof(order_data)); + locale_array[lindex]->short_orders[kwd] = data; + data->_keyword = kwd; + data->_lindex = lindex; + data->_str = NULL; + data->_refcount = 1; + } + ++data->_refcount; + return data; + } + data = (order_data*)malloc(sizeof(order_data)); + data->_keyword = kwd; + data->_lindex = lindex; + data->_str = s?strdup(s):NULL; + data->_refcount = 1; + return data; +} + +static order * +create_order_i(keyword_t kwd, const char * sptr, int persistent, const struct locale * lang) +{ + order * ord = NULL; + int lindex; + + /* if this is just nonsense, then we skip it. */ + if (lomem) { + switch (kwd) { + case K_KOMMENTAR: + case NOKEYWORD: + return NULL; + case K_LIEFERE: + kwd = K_GIVE; + persistent = 1; + break; + default: + break; + } + } + + for (lindex=0;lindex!=nlocales;++lindex) { + if (locale_array[lindex]->lang==lang) break; + } + if (lindex==nlocales) { + locale_array[nlocales] = (locale_data*)calloc(1, sizeof(locale_data)); + locale_array[nlocales]->lang = lang; + ++nlocales; + } + + ord = (order*)malloc(sizeof(order)); + ord->_persistent = persistent; + ord->next = NULL; + + ord->data = create_data(kwd, sptr, lindex); + + return ord; +} + +order * +create_order(keyword_t kwd, const struct locale * lang, const char * params, ...) +{ + char zBuffer[DISPLAYSIZE]; + if (params) { + char * bufp = zBuffer; + int bytes; + size_t size = sizeof(zBuffer) - 1; + va_list marker; + + va_start(marker, params); + while (*params) { + if (*params=='%') { + int i; + const char * s; + ++params; + switch (*params) { + case 's': + s = va_arg(marker, const char *); + bytes = (int)strlcpy(bufp, s, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + break; + case 'd': + i = va_arg(marker, int); + bytes = (int)strlcpy(bufp, itoa10(i), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + break; + case 'i': + i = va_arg(marker, int); + bytes = (int)strlcpy(bufp, itoa36(i), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + break; + default: + assert(!"unknown format-character in create_order"); + } + } else if (size>0) { + *bufp++ = *params; + --size; + } + ++params; + } + va_end(marker); + *bufp = 0; + } else { + zBuffer[0] = 0; + } + return create_order_i(kwd, zBuffer, 0, lang); +} + +order * +parse_order(const char * s, const struct locale * lang) +{ + while (*s && !isalnum(*(unsigned char*)s) && !ispunct(*(unsigned char*)s)) ++s; + if (*s!=0) { + keyword_t kwd; + const char * sptr; + int persistent = 0; + + while (*s=='@') { + persistent = 1; + ++s; + } + sptr = s; + kwd = findkeyword(parse_token(&sptr), lang); + if (kwd!=NOKEYWORD) { + while (isxspace(*(unsigned char*)sptr)) ++sptr; + s = sptr; + } + return create_order_i(kwd, s, persistent, lang); + } + return NULL; +} + +boolean +is_repeated(const order * ord) +{ + keyword_t kwd = ORD_KEYWORD(ord); + const struct locale * lang = ORD_LOCALE(ord); + param_t param; + + switch (kwd) { + case K_CAST: + case K_BUY: + case K_SELL: + case K_ROUTE: + case K_DRIVE: + case K_WORK: + case K_BESIEGE: + case K_ENTERTAIN: + case K_TAX: + case K_RESEARCH: + case K_SPY: + case K_STEAL: + case K_SABOTAGE: + case K_STUDY: + case K_TEACH: + case K_BREED: + case K_PIRACY: + return true; + + case K_PLANT: + return true; + + case K_FOLLOW: + /* FOLLOW is only a long order if we are following a ship. */ + parser_pushstate(); + init_tokens(ord); + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param == P_SHIP) return true; + break; + + case K_MAKE: + /* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen + * Arten von MACHE zaehlen aber als neue defaults und werden + * behandelt wie die anderen (deswegen kein break nach case + * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) + * abgespeichert). */ + parser_pushstate(); + init_tokens(ord); /* initialize token-parser */ + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param != P_TEMP) return true; + break; + } + return false; +} + +boolean +is_exclusive(const order * ord) +{ + keyword_t kwd = ORD_KEYWORD(ord); + const struct locale * lang = ORD_LOCALE(ord); + param_t param; + + switch (kwd) { + case K_MOVE: + case K_WEREWOLF: + /* these should not become persistent */ + case K_ROUTE: + case K_DRIVE: + case K_WORK: + case K_BESIEGE: + case K_ENTERTAIN: + case K_TAX: + case K_RESEARCH: + case K_SPY: + case K_STEAL: + case K_SABOTAGE: + case K_STUDY: + case K_TEACH: + case K_BREED: + case K_PIRACY: + return true; + + case K_PLANT: + return true; + + case K_FOLLOW: + /* FOLLOW is only a long order if we are following a ship. */ + parser_pushstate(); + init_tokens(ord); + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param == P_SHIP) return true; + break; + + case K_MAKE: + /* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen + * Arten von MACHE zaehlen aber als neue defaults und werden + * behandelt wie die anderen (deswegen kein break nach case + * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) + * abgespeichert). */ + parser_pushstate(); + init_tokens(ord); /* initialize token-parser */ + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param != P_TEMP) return true; + break; + } + return false; +} + +boolean +is_persistent(const order * ord) +{ + keyword_t kwd = ORD_KEYWORD(ord); + boolean persist = ord->_persistent!=0; + switch (kwd) { + case K_MOVE: + case K_WEREWOLF: + case NOKEYWORD: + /* lang, aber niemals persistent! */ + return false; + + case K_KOMMENTAR: + case K_LIEFERE: + return true; + } + + return persist || is_repeated(ord); +} + +char * +write_order(const order * ord, char * buffer, size_t size) +{ + if (ord==0) { + buffer[0]=0; + } else { + keyword_t kwd = ORD_KEYWORD(ord); + if (kwd==NOKEYWORD) { + const char * text = ORD_STRING(ord); + strlcpy(buffer, (const char *)text, size); + } else { + get_command(ord, buffer, size); + } + } + return buffer; +} diff --git a/src/kernel/order.h b/src/kernel/order.h index 29f273863..5d87fe045 100644 --- a/src/kernel/order.h +++ b/src/kernel/order.h @@ -1,61 +1,61 @@ -/* vi: set ts=2: - +-------------------+ - | | Christian Schlittchen - | Eressea PBEM host | Enno Rehling - | (c) 1998 - 2004 | Katja Zedel - | | - +-------------------+ - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef KRNL_ORDER_H -#define KRNL_ORDER_H -#ifdef __cplusplus -extern "C" { -#endif - -/* Encapsulation of an order - * - * This structure contains one order given by a unit. These used to be - * stored in string lists, but by storing them in order-structures, - * it is possible to use reference-counting on them, reduce string copies, - * and reduce overall memory usage by sharing strings between orders (not - * implemented yet) saving approx. 50% of all string-related memory. - */ - -struct order_data; - -typedef struct order { - struct order * next; - /* do not access this data: */ - struct order_data * data; - int _persistent : 1; -} order; - -/* constructor */ -extern 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); - -/* reference counted copies of orders: */ -extern order * copy_order(const order * ord); -extern void free_order(order * ord); -extern void free_orders(order ** olist); - -/* access functions for orders */ -extern keyword_t get_keyword(const order * ord); -extern void set_order(order ** destp, order * src); -extern char * getcommand(const order * ord); -extern boolean is_persistent(const order *ord); -extern boolean is_exclusive(const order *ord); -extern boolean is_repeated(const order * ord); - -extern char * write_order(const order * ord, char * buffer, size_t size); - - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ + | | Christian Schlittchen + | Eressea PBEM host | Enno Rehling + | (c) 1998 - 2004 | Katja Zedel + | | + +-------------------+ + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef KRNL_ORDER_H +#define KRNL_ORDER_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Encapsulation of an order + * + * This structure contains one order given by a unit. These used to be + * stored in string lists, but by storing them in order-structures, + * it is possible to use reference-counting on them, reduce string copies, + * and reduce overall memory usage by sharing strings between orders (not + * implemented yet) saving approx. 50% of all string-related memory. + */ + +struct order_data; + +typedef struct order { + struct order * next; + /* do not access this data: */ + struct order_data * data; + int _persistent : 1; +} order; + +/* constructor */ +extern 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); + +/* reference counted copies of orders: */ +extern order * copy_order(const order * ord); +extern void free_order(order * ord); +extern void free_orders(order ** olist); + +/* access functions for orders */ +extern keyword_t get_keyword(const order * ord); +extern void set_order(order ** destp, order * src); +extern char * getcommand(const order * ord); +extern boolean is_persistent(const order *ord); +extern boolean is_exclusive(const order *ord); +extern boolean is_repeated(const order * ord); + +extern char * write_order(const order * ord, char * buffer, size_t size); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/pathfinder.c b/src/kernel/pathfinder.c index 29c52ed8b..5c2ebb9a7 100644 --- a/src/kernel/pathfinder.c +++ b/src/kernel/pathfinder.c @@ -1,200 +1,200 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "pathfinder.h" - -#include "region.h" -#include "terrain.h" - -#include -#include -#include - -boolean -allowed_swim(const region * src, const region * r) -{ - if (fval(r->terrain, SWIM_INTO)) return true; - return false; -} - -boolean -allowed_walk(const region * src, const region * r) -{ - if (fval(r->terrain, WALK_INTO)) return true; - return false; -} - -boolean -allowed_fly(const region * src, const region * r) -{ - if (fval(r->terrain, FLY_INTO)) return true; - return false; -} - -typedef struct node { - struct node * next; - region * r; - struct node * prev; - int distance; -} node; - -static node * node_garbage; - -void -pathfinder_cleanup(void) -{ - while (node_garbage) { - node * n = node_garbage; - node_garbage = n->next; - free(n); - } -} - -static node * -new_node(region * r, int distance, node * prev) -{ - node * n; - if (node_garbage!=NULL) { - n = node_garbage; - node_garbage = n->next; - } - else n = malloc(sizeof(node)); - n->next = NULL; - n->prev = prev; - n->r= r; - n->distance= distance; - return n; -} - -static node * -free_node(node * n) -{ - node * s = n->next; - n->next = node_garbage; - node_garbage = n; - return s; -} - -static void -free_nodes(node * root) -{ - while (root!=NULL) { - region * r = root->r; - freset(r, RF_MARK); - root = free_node(root); - } -} - -struct region_list * -regions_in_range(struct region * start, int maxdist, boolean (*allowed)(const struct region*, const struct region*)) -{ - region_list * rlist = NULL; - node * root = new_node(start, 0, NULL); - node ** end = &root->next; - node * n = root; - - while (n!=NULL) { - region * r = n->r; - int depth = n->distance+1; - direction_t d; - - if (n->distance >= maxdist) break; - for (d=0;d!=MAXDIRECTIONS; ++d) { - region * rn = rconnect(r, d); - if (rn==NULL) continue; - if (fval(rn, RF_MARK)) continue; /* already been there */ - if (allowed && !allowed(r, rn)) continue; /* can't go there */ - - /* add the region to the list of available ones. */ - add_regionlist(&rlist, rn); - - /* make sure we don't go here again, and put the region into the set for - further BFS'ing */ - fset(rn, RF_MARK); - *end = new_node(rn, depth, n); - end = &(*end)->next; - } - n = n->next; - } - free_nodes(root); - - return rlist; -} - -static region ** -internal_path_find(region *start, const region *target, int maxlen, boolean (*allowed)(const region*, const region*)) -{ - static region * path[MAXDEPTH+2]; /* STATIC_RETURN: used for return, not across calls */ - direction_t d; - node * root = new_node(start, 0, NULL); - node ** end = &root->next; - node * n = root; - boolean found = false; - assert(maxlen<=MAXDEPTH); - fset(start, RF_MARK); - - while (n!=NULL) { - region * r = n->r; - int depth = n->distance+1; - if (n->distance >= maxlen) break; - for (d=0;d!=MAXDIRECTIONS; ++d) { - region * rn = rconnect(r, d); - if (rn==NULL) continue; - if (fval(rn, RF_MARK)) continue; /* already been there */ - if (!allowed(r, rn)) continue; /* can't go there */ - if (rn==target) { - int i = depth; - path[i+1] = NULL; - path[i] = rn; - while (n) { - path[--i] = n->r; - n = n->prev; - } - found = true; - break; - } else { - fset(rn, RF_MARK); - *end = new_node(rn, depth, n); - end = &(*end)->next; - } - } - if (found) break; - n = n->next; - } - free_nodes(root); - if (found) return path; - return NULL; -} - -boolean -path_exists(region *start, const region *target, int maxlen, boolean (*allowed)(const region*, const region*)) -{ - assert((!fval(start, RF_MARK) && !fval(target, RF_MARK)) || !"Some Algorithm did not clear its RF_MARKs!"); - if (start==target) return true; - if (internal_path_find(start, target, maxlen, allowed)!=NULL) return true; - return false; -} - -region ** -path_find(region *start, const region *target, int maxlen, boolean (*allowed)(const region*, const region*)) -{ - assert((!fval(start, RF_MARK) && !fval(target, RF_MARK)) || !"Did you call path_init()?"); - return internal_path_find(start, target, maxlen, allowed); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "pathfinder.h" + +#include "region.h" +#include "terrain.h" + +#include +#include +#include + +boolean +allowed_swim(const region * src, const region * r) +{ + if (fval(r->terrain, SWIM_INTO)) return true; + return false; +} + +boolean +allowed_walk(const region * src, const region * r) +{ + if (fval(r->terrain, WALK_INTO)) return true; + return false; +} + +boolean +allowed_fly(const region * src, const region * r) +{ + if (fval(r->terrain, FLY_INTO)) return true; + return false; +} + +typedef struct node { + struct node * next; + region * r; + struct node * prev; + int distance; +} node; + +static node * node_garbage; + +void +pathfinder_cleanup(void) +{ + while (node_garbage) { + node * n = node_garbage; + node_garbage = n->next; + free(n); + } +} + +static node * +new_node(region * r, int distance, node * prev) +{ + node * n; + if (node_garbage!=NULL) { + n = node_garbage; + node_garbage = n->next; + } + else n = malloc(sizeof(node)); + n->next = NULL; + n->prev = prev; + n->r= r; + n->distance= distance; + return n; +} + +static node * +free_node(node * n) +{ + node * s = n->next; + n->next = node_garbage; + node_garbage = n; + return s; +} + +static void +free_nodes(node * root) +{ + while (root!=NULL) { + region * r = root->r; + freset(r, RF_MARK); + root = free_node(root); + } +} + +struct region_list * +regions_in_range(struct region * start, int maxdist, boolean (*allowed)(const struct region*, const struct region*)) +{ + region_list * rlist = NULL; + node * root = new_node(start, 0, NULL); + node ** end = &root->next; + node * n = root; + + while (n!=NULL) { + region * r = n->r; + int depth = n->distance+1; + direction_t d; + + if (n->distance >= maxdist) break; + for (d=0;d!=MAXDIRECTIONS; ++d) { + region * rn = rconnect(r, d); + if (rn==NULL) continue; + if (fval(rn, RF_MARK)) continue; /* already been there */ + if (allowed && !allowed(r, rn)) continue; /* can't go there */ + + /* add the region to the list of available ones. */ + add_regionlist(&rlist, rn); + + /* make sure we don't go here again, and put the region into the set for + further BFS'ing */ + fset(rn, RF_MARK); + *end = new_node(rn, depth, n); + end = &(*end)->next; + } + n = n->next; + } + free_nodes(root); + + return rlist; +} + +static region ** +internal_path_find(region *start, const region *target, int maxlen, boolean (*allowed)(const region*, const region*)) +{ + static region * path[MAXDEPTH+2]; /* STATIC_RETURN: used for return, not across calls */ + direction_t d; + node * root = new_node(start, 0, NULL); + node ** end = &root->next; + node * n = root; + boolean found = false; + assert(maxlen<=MAXDEPTH); + fset(start, RF_MARK); + + while (n!=NULL) { + region * r = n->r; + int depth = n->distance+1; + if (n->distance >= maxlen) break; + for (d=0;d!=MAXDIRECTIONS; ++d) { + region * rn = rconnect(r, d); + if (rn==NULL) continue; + if (fval(rn, RF_MARK)) continue; /* already been there */ + if (!allowed(r, rn)) continue; /* can't go there */ + if (rn==target) { + int i = depth; + path[i+1] = NULL; + path[i] = rn; + while (n) { + path[--i] = n->r; + n = n->prev; + } + found = true; + break; + } else { + fset(rn, RF_MARK); + *end = new_node(rn, depth, n); + end = &(*end)->next; + } + } + if (found) break; + n = n->next; + } + free_nodes(root); + if (found) return path; + return NULL; +} + +boolean +path_exists(region *start, const region *target, int maxlen, boolean (*allowed)(const region*, const region*)) +{ + assert((!fval(start, RF_MARK) && !fval(target, RF_MARK)) || !"Some Algorithm did not clear its RF_MARKs!"); + if (start==target) return true; + if (internal_path_find(start, target, maxlen, allowed)!=NULL) return true; + return false; +} + +region ** +path_find(region *start, const region *target, int maxlen, boolean (*allowed)(const region*, const region*)) +{ + assert((!fval(start, RF_MARK) && !fval(target, RF_MARK)) || !"Did you call path_init()?"); + return internal_path_find(start, target, maxlen, allowed); +} diff --git a/src/kernel/pathfinder.h b/src/kernel/pathfinder.h index 5ae704509..42785f25e 100644 --- a/src/kernel/pathfinder.h +++ b/src/kernel/pathfinder.h @@ -1,42 +1,42 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_PATHFINDER -#define H_KRNL_PATHFINDER -#ifdef __cplusplus -extern "C" { -#endif - -#define MAXDEPTH 1024 - -extern int search[MAXDEPTH][2]; -extern int search_len; - -extern struct region ** path_find(struct region *start, const struct region *target, int maxlen, boolean (*allowed)(const struct region*, const struct region*)); -extern boolean path_exists(struct region *start, const struct region *target, int maxlen, boolean (*allowed)(const struct region*, const struct region*)); -extern boolean allowed_swim(const struct region * src, const struct region * target); -extern boolean allowed_fly(const struct region * src, const struct region * target); -extern boolean allowed_walk(const struct region * src, const struct region * target); -extern struct region_list * regions_in_range(struct region * src, int maxdist, boolean (*allowed)(const struct region*, const struct region*)); - -extern void pathfinder_cleanup(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_PATHFINDER +#define H_KRNL_PATHFINDER +#ifdef __cplusplus +extern "C" { +#endif + +#define MAXDEPTH 1024 + +extern int search[MAXDEPTH][2]; +extern int search_len; + +extern struct region ** path_find(struct region *start, const struct region *target, int maxlen, boolean (*allowed)(const struct region*, const struct region*)); +extern boolean path_exists(struct region *start, const struct region *target, int maxlen, boolean (*allowed)(const struct region*, const struct region*)); +extern boolean allowed_swim(const struct region * src, const struct region * target); +extern boolean allowed_fly(const struct region * src, const struct region * target); +extern boolean allowed_walk(const struct region * src, const struct region * target); +extern struct region_list * regions_in_range(struct region * src, int maxdist, boolean (*allowed)(const struct region*, const struct region*)); + +extern void pathfinder_cleanup(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/plane.c b/src/kernel/plane.c index 8ab941838..929230285 100644 --- a/src/kernel/plane.c +++ b/src/kernel/plane.c @@ -1,326 +1,326 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "plane.h" - -/* kernel includes */ -#include "region.h" -#include "faction.h" - -/* util includes */ -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -struct plane *planes; - -int plane_width(const plane * pl) -{ - if (pl) { - return pl->maxx-pl->minx+1; - } - return 0; -} - -int plane_height(const plane * pl) -{ - if (pl) { - return pl->maxy-pl->miny+1; - } - return 0; -} - -static plane * home_plane = NULL; - -plane * -get_homeplane(void) -{ - return getplanebyid(0); -} - - -plane * -getplane(const region *r) -{ - if (r) { - return r->_plane; - } - return get_homeplane(); -} - -plane * -getplanebyid(int id) -{ - plane *p; - - for (p=planes; p; p=p->next) { - if (p->id == id) { - return p; - } - } - return NULL; -} - -plane * -getplanebyname(const char * name) -{ - plane *p; - - for (p=planes; p; p=p->next) - if (p->name && !strcmp(p->name, name)) - return p; - return NULL; -} - -plane * -findplane(int x, int y) -{ - plane *pl; - - for(pl=planes;pl;pl=pl->next) { - if(x >= pl->minx && x <= pl->maxx - && y >= pl->miny && y <= pl->maxy) { - return pl; - } - } - return NULL; -} - -int -getplaneid(const region *r) - -{ - if(r) { - plane * pl = getplane(r); - if (pl) return pl->id; - - for(pl=planes;pl;pl=pl->next) { - if(r->x >= pl->minx && r->x <= pl->maxx - && r->y >= pl->miny && r->y <= pl->maxy) { - return pl->id; - } - } - } - return 0; -} - -static int -ursprung_x(const faction *f, const plane *pl, const region * rdefault) -{ - ursprung *ur; - int id = 0; - - if(!f) - return 0; - - if(pl) - id = pl->id; - - for(ur = f->ursprung; ur; ur = ur->next) { - if(ur->id == id) - return ur->x; - } - if (!rdefault) return 0; - set_ursprung((faction*)f, id, rdefault->x - plane_center_x(pl), rdefault->y - plane_center_y(pl)); - return rdefault->x - plane_center_x(pl); -} - -static int -ursprung_y(const faction *f, const plane *pl, const region * rdefault) -{ - ursprung *ur; - int id = 0; - - if(!f) - return 0; - - if(pl) - id = pl->id; - - for(ur = f->ursprung; ur; ur = ur->next) { - if(ur->id == id) - return ur->y; - } - if (!rdefault) return 0; - set_ursprung((faction*)f, id, rdefault->x - plane_center_x(pl), rdefault->y - plane_center_y(pl)); - return rdefault->y - plane_center_y(pl); -} - -int -plane_center_x(const plane *pl) -{ - if(pl == NULL) - return 0; - - return(pl->minx + pl->maxx)/2; -} - -int -plane_center_y(const plane *pl) -{ - if(pl == NULL) - return 0; - - return(pl->miny + pl->maxy)/2; -} - -void -adjust_coordinates(const faction *f, int *x, int *y, const plane * pl, const region * r) -{ - int nx = *x; - int ny = *y; - if (f) { - nx -= ursprung_x(f, pl, r); - ny -= ursprung_y(f, pl, r); - } - if (pl) { - nx -= plane_center_x(pl); - ny -= plane_center_y(pl); - } - - if (pl) { - int width = plane_width(pl); - int height = plane_height(pl); - int width_2 = width/2; - int height_2 = height/2; - - if (nx<0) nx = (width-(-nx)%width); - if (nx>width_2) nx -= width; - if (ny<0) ny = (height-(-ny)%height); - if (ny>height_2) ny -= height; - } - - assert(!pl || nx<=pl->maxx - plane_center_x(pl)); - assert(!pl || nx>=pl->minx - plane_center_x(pl)); - assert(!pl || ny<=pl->maxy - plane_center_y(pl)); - assert(!pl || ny>=pl->miny - plane_center_y(pl)); - - *x = nx; - *y = ny; -} - -void -set_ursprung(faction *f, int id, int x, int y) -{ - ursprung *ur; - assert(f!=NULL); - for(ur=f->ursprung;ur;ur=ur->next) { - if (ur->id == id) { - ur->x = ur->x + x; - ur->y = ur->y + y; - return; - } - } - - ur = calloc(1, sizeof(ursprung)); - ur->id = id; - ur->x = x; - ur->y = y; - - addlist(&f->ursprung, ur); -} - -plane * -create_new_plane(int id, const char *name, int minx, int maxx, int miny, int maxy, int flags) -{ - plane *pl = getplanebyid(id); - - if (pl) return pl; - pl = calloc(1, sizeof(plane)); - - pl->next = NULL; - pl->id = id; - if (name) pl->name = strdup(name); - pl->minx = minx; - pl->maxx = maxx; - pl->miny = miny; - pl->maxy = maxy; - pl->flags = flags; - - addlist(&planes, pl); - if (id==0) { - home_plane = pl; - } - return pl; -} - -/* Umrechnung Relative-Absolute-Koordinaten */ -int -rel_to_abs(const struct plane *pl, const struct faction * f, int rel, unsigned char index) -{ - assert(index == 0 || index == 1); - - if(index == 0) - return (rel + ursprung_x(f, pl, NULL) + plane_center_x(pl)); - - return (rel + ursprung_y(f, pl, NULL) + plane_center_y(pl)); -} - - -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) -{ - store->w_int(store, u?(u->id):0); -} - -int -read_plane_reference(plane ** pp, struct storage * store) -{ - variant id; - id.i = store->r_int(store); - 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; -} - -boolean -is_watcher(const struct plane * p, const struct faction * f) -{ - struct watcher * w; - if (!p) return false; - w = p->watchers; - while (w && w->faction!=f) w=w->next; - return (w!=NULL); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "plane.h" + +/* kernel includes */ +#include "region.h" +#include "faction.h" + +/* util includes */ +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +struct plane *planes; + +int plane_width(const plane * pl) +{ + if (pl) { + return pl->maxx-pl->minx+1; + } + return 0; +} + +int plane_height(const plane * pl) +{ + if (pl) { + return pl->maxy-pl->miny+1; + } + return 0; +} + +static plane * home_plane = NULL; + +plane * +get_homeplane(void) +{ + return getplanebyid(0); +} + + +plane * +getplane(const region *r) +{ + if (r) { + return r->_plane; + } + return get_homeplane(); +} + +plane * +getplanebyid(int id) +{ + plane *p; + + for (p=planes; p; p=p->next) { + if (p->id == id) { + return p; + } + } + return NULL; +} + +plane * +getplanebyname(const char * name) +{ + plane *p; + + for (p=planes; p; p=p->next) + if (p->name && !strcmp(p->name, name)) + return p; + return NULL; +} + +plane * +findplane(int x, int y) +{ + plane *pl; + + for(pl=planes;pl;pl=pl->next) { + if(x >= pl->minx && x <= pl->maxx + && y >= pl->miny && y <= pl->maxy) { + return pl; + } + } + return NULL; +} + +int +getplaneid(const region *r) + +{ + if(r) { + plane * pl = getplane(r); + if (pl) return pl->id; + + for(pl=planes;pl;pl=pl->next) { + if(r->x >= pl->minx && r->x <= pl->maxx + && r->y >= pl->miny && r->y <= pl->maxy) { + return pl->id; + } + } + } + return 0; +} + +static int +ursprung_x(const faction *f, const plane *pl, const region * rdefault) +{ + ursprung *ur; + int id = 0; + + if(!f) + return 0; + + if(pl) + id = pl->id; + + for(ur = f->ursprung; ur; ur = ur->next) { + if(ur->id == id) + return ur->x; + } + if (!rdefault) return 0; + set_ursprung((faction*)f, id, rdefault->x - plane_center_x(pl), rdefault->y - plane_center_y(pl)); + return rdefault->x - plane_center_x(pl); +} + +static int +ursprung_y(const faction *f, const plane *pl, const region * rdefault) +{ + ursprung *ur; + int id = 0; + + if(!f) + return 0; + + if(pl) + id = pl->id; + + for(ur = f->ursprung; ur; ur = ur->next) { + if(ur->id == id) + return ur->y; + } + if (!rdefault) return 0; + set_ursprung((faction*)f, id, rdefault->x - plane_center_x(pl), rdefault->y - plane_center_y(pl)); + return rdefault->y - plane_center_y(pl); +} + +int +plane_center_x(const plane *pl) +{ + if(pl == NULL) + return 0; + + return(pl->minx + pl->maxx)/2; +} + +int +plane_center_y(const plane *pl) +{ + if(pl == NULL) + return 0; + + return(pl->miny + pl->maxy)/2; +} + +void +adjust_coordinates(const faction *f, int *x, int *y, const plane * pl, const region * r) +{ + int nx = *x; + int ny = *y; + if (f) { + nx -= ursprung_x(f, pl, r); + ny -= ursprung_y(f, pl, r); + } + if (pl) { + nx -= plane_center_x(pl); + ny -= plane_center_y(pl); + } + + if (pl) { + int width = plane_width(pl); + int height = plane_height(pl); + int width_2 = width/2; + int height_2 = height/2; + + if (nx<0) nx = (width-(-nx)%width); + if (nx>width_2) nx -= width; + if (ny<0) ny = (height-(-ny)%height); + if (ny>height_2) ny -= height; + } + + assert(!pl || nx<=pl->maxx - plane_center_x(pl)); + assert(!pl || nx>=pl->minx - plane_center_x(pl)); + assert(!pl || ny<=pl->maxy - plane_center_y(pl)); + assert(!pl || ny>=pl->miny - plane_center_y(pl)); + + *x = nx; + *y = ny; +} + +void +set_ursprung(faction *f, int id, int x, int y) +{ + ursprung *ur; + assert(f!=NULL); + for(ur=f->ursprung;ur;ur=ur->next) { + if (ur->id == id) { + ur->x = ur->x + x; + ur->y = ur->y + y; + return; + } + } + + ur = calloc(1, sizeof(ursprung)); + ur->id = id; + ur->x = x; + ur->y = y; + + addlist(&f->ursprung, ur); +} + +plane * +create_new_plane(int id, const char *name, int minx, int maxx, int miny, int maxy, int flags) +{ + plane *pl = getplanebyid(id); + + if (pl) return pl; + pl = calloc(1, sizeof(plane)); + + pl->next = NULL; + pl->id = id; + if (name) pl->name = strdup(name); + pl->minx = minx; + pl->maxx = maxx; + pl->miny = miny; + pl->maxy = maxy; + pl->flags = flags; + + addlist(&planes, pl); + if (id==0) { + home_plane = pl; + } + return pl; +} + +/* Umrechnung Relative-Absolute-Koordinaten */ +int +rel_to_abs(const struct plane *pl, const struct faction * f, int rel, unsigned char index) +{ + assert(index == 0 || index == 1); + + if(index == 0) + return (rel + ursprung_x(f, pl, NULL) + plane_center_x(pl)); + + return (rel + ursprung_y(f, pl, NULL) + plane_center_y(pl)); +} + + +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) +{ + store->w_int(store, u?(u->id):0); +} + +int +read_plane_reference(plane ** pp, struct storage * store) +{ + variant id; + id.i = store->r_int(store); + 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; +} + +boolean +is_watcher(const struct plane * p, const struct faction * f) +{ + struct watcher * w; + if (!p) return false; + w = p->watchers; + while (w && w->faction!=f) w=w->next; + return (w!=NULL); +} diff --git a/src/kernel/plane.h b/src/kernel/plane.h index f7827679f..d5536b86e 100644 --- a/src/kernel/plane.h +++ b/src/kernel/plane.h @@ -1,84 +1,84 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_PLANES -#define H_KRNL_PLANES -#ifdef __cplusplus -extern "C" { -#endif - -#define PFL_NOCOORDS 1 /* not in use */ -#define PFL_NORECRUITS 2 -#define PFL_NOALLIANCES 4 -#define PFL_LOWSTEALING 8 -#define PFL_NOGIVE 16 /* Übergaben sind unmöglich */ -#define PFL_NOATTACK 32 /* Angriffe und Diebstähle sind unmöglich */ -#define PFL_NOTERRAIN 64 /* Terraintyp wird nicht angezeigt TODO? */ -#define PFL_NOMAGIC 128 /* Zaubern ist unmöglich */ -#define PFL_NOSTEALTH 256 /* Tarnung außer Betrieb */ -#define PFL_NOTEACH 512 /* Lehre außer Betrieb */ -#define PFL_NOBUILD 1024 /* Bauen außer Betrieb */ -#define PFL_NOFEED 2048 /* Kein Unterhalt nötig */ -#define PFL_FRIENDLY 4096 /* everyone is your ally */ -#define PFL_NOORCGROWTH 8192 /* orcs don't grow */ -#define PFL_NOMONSTERS 16384 /* no monster randenc */ -#define PFL_SEESPECIAL 32768 /* far seeing */ - -typedef struct watcher { - struct watcher * next; - struct faction * faction; - unsigned char mode; -} watcher; - -typedef struct plane { - struct plane *next; - struct watcher * watchers; - int id; - char *name; - int minx, maxx, miny, maxy; - unsigned int flags; - struct attrib *attribs; -} plane; - -#define plane_id(pl) ( (pl) ? (pl)->id : 0 ) - -extern struct plane *planes; - -struct plane *getplane(const struct region *r); -struct plane *findplane(int x, int y); -void init_planes(void); -int getplaneid(const struct region *r); -struct plane * getplanebyid(int id); -int plane_center_x(const struct plane *pl); -int plane_center_y(const struct plane *pl); -void set_ursprung(struct faction *f, int id, int x, int y); -struct plane * create_new_plane(int id, const char *name, int minx, int maxx, int miny, int maxy, int flags); -struct plane * getplanebyname(const char *); -struct plane * get_homeplane(void); -extern int rel_to_abs(const struct plane *pl, const struct faction * f, int rel, unsigned char index); -extern boolean is_watcher(const struct plane * p, const struct faction * f); -extern int resolve_plane(variant data, void * addr); -extern void write_plane_reference(const plane * p, struct storage * store); -extern int read_plane_reference(plane ** pp, struct storage * store); -extern int plane_width(const plane * pl); -extern int plane_height(const plane * pl); -void adjust_coordinates(const struct faction *f, int *x, int *y, const struct plane * pl, const struct region * r); -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_PLANES +#define H_KRNL_PLANES +#ifdef __cplusplus +extern "C" { +#endif + +#define PFL_NOCOORDS 1 /* not in use */ +#define PFL_NORECRUITS 2 +#define PFL_NOALLIANCES 4 +#define PFL_LOWSTEALING 8 +#define PFL_NOGIVE 16 /* Übergaben sind unmöglich */ +#define PFL_NOATTACK 32 /* Angriffe und Diebstähle sind unmöglich */ +#define PFL_NOTERRAIN 64 /* Terraintyp wird nicht angezeigt TODO? */ +#define PFL_NOMAGIC 128 /* Zaubern ist unmöglich */ +#define PFL_NOSTEALTH 256 /* Tarnung außer Betrieb */ +#define PFL_NOTEACH 512 /* Lehre außer Betrieb */ +#define PFL_NOBUILD 1024 /* Bauen außer Betrieb */ +#define PFL_NOFEED 2048 /* Kein Unterhalt nötig */ +#define PFL_FRIENDLY 4096 /* everyone is your ally */ +#define PFL_NOORCGROWTH 8192 /* orcs don't grow */ +#define PFL_NOMONSTERS 16384 /* no monster randenc */ +#define PFL_SEESPECIAL 32768 /* far seeing */ + +typedef struct watcher { + struct watcher * next; + struct faction * faction; + unsigned char mode; +} watcher; + +typedef struct plane { + struct plane *next; + struct watcher * watchers; + int id; + char *name; + int minx, maxx, miny, maxy; + unsigned int flags; + struct attrib *attribs; +} plane; + +#define plane_id(pl) ( (pl) ? (pl)->id : 0 ) + +extern struct plane *planes; + +struct plane *getplane(const struct region *r); +struct plane *findplane(int x, int y); +void init_planes(void); +int getplaneid(const struct region *r); +struct plane * getplanebyid(int id); +int plane_center_x(const struct plane *pl); +int plane_center_y(const struct plane *pl); +void set_ursprung(struct faction *f, int id, int x, int y); +struct plane * create_new_plane(int id, const char *name, int minx, int maxx, int miny, int maxy, int flags); +struct plane * getplanebyname(const char *); +struct plane * get_homeplane(void); +extern int rel_to_abs(const struct plane *pl, const struct faction * f, int rel, unsigned char index); +extern boolean is_watcher(const struct plane * p, const struct faction * f); +extern int resolve_plane(variant data, void * addr); +extern void write_plane_reference(const plane * p, struct storage * store); +extern int read_plane_reference(plane ** pp, struct storage * store); +extern int plane_width(const plane * pl); +extern int plane_height(const plane * pl); +void adjust_coordinates(const struct faction *f, int *x, int *y, const struct plane * pl, const struct region * r); +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/player.c b/src/kernel/player.c index c8076f640..5ac1dd457 100644 --- a/src/kernel/player.c +++ b/src/kernel/player.c @@ -1,101 +1,101 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - - */ -#include -#include "player.h" - -#include -#include - -#include -#include - -#define PMAXHASH 1021 - -typedef struct player_hash { - struct player * entries; -} player_hash; - -static player_hash * players[PMAXHASH]; - -player * -make_player(const struct faction * f) -{ - player * p = calloc(sizeof(player), 1); - unsigned int hash; - - for (p->id = rng_int();;p->id++) { - /* if there is a hashing conflict, resolve it */ - player * pi = get_player(p->id); - if (pi) p->id++; - else break; - } - hash = p->id % PMAXHASH; - p->faction = f; - p->nexthash = players[hash]->entries; - players[hash]->entries = p; - - return p; -} - -player * -next_player(player * p) -{ - if (p->nexthash) return p->nexthash; - else { - unsigned int hash = p->id % PMAXHASH; - p = NULL; - while (++hash!=PMAXHASH) { - if (players[hash]->entries!=NULL) { - p = players[hash]->entries; - break; - } - } - return p; - } -} - -player * -get_player(unsigned int id) -{ - unsigned int hash = id % PMAXHASH; - struct player * p = players[hash]->entries; - - while (p && p->id!=id) p = p->nexthash; - return p; -} - -player * -get_players(void) -{ - struct player * p = NULL; - unsigned int hash = 0; - - while (p!=NULL && hash!=PMAXHASH) { - p = players[hash++]->entries; - } - return p; -} - -void -players_done(void) -{ - int i; - for (i=0;i!=PMAXHASH;++i) { - player * p = players[i]->entries; - players[i]->entries = p->nexthash; - free(p->name); - if (p->email) free(p->email); - if (p->name) free(p->name); - free(p); - } -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ +#include +#include "player.h" + +#include +#include + +#include +#include + +#define PMAXHASH 1021 + +typedef struct player_hash { + struct player * entries; +} player_hash; + +static player_hash * players[PMAXHASH]; + +player * +make_player(const struct faction * f) +{ + player * p = calloc(sizeof(player), 1); + unsigned int hash; + + for (p->id = rng_int();;p->id++) { + /* if there is a hashing conflict, resolve it */ + player * pi = get_player(p->id); + if (pi) p->id++; + else break; + } + hash = p->id % PMAXHASH; + p->faction = f; + p->nexthash = players[hash]->entries; + players[hash]->entries = p; + + return p; +} + +player * +next_player(player * p) +{ + if (p->nexthash) return p->nexthash; + else { + unsigned int hash = p->id % PMAXHASH; + p = NULL; + while (++hash!=PMAXHASH) { + if (players[hash]->entries!=NULL) { + p = players[hash]->entries; + break; + } + } + return p; + } +} + +player * +get_player(unsigned int id) +{ + unsigned int hash = id % PMAXHASH; + struct player * p = players[hash]->entries; + + while (p && p->id!=id) p = p->nexthash; + return p; +} + +player * +get_players(void) +{ + struct player * p = NULL; + unsigned int hash = 0; + + while (p!=NULL && hash!=PMAXHASH) { + p = players[hash++]->entries; + } + return p; +} + +void +players_done(void) +{ + int i; + for (i=0;i!=PMAXHASH;++i) { + player * p = players[i]->entries; + players[i]->entries = p->nexthash; + free(p->name); + if (p->email) free(p->email); + if (p->name) free(p->name); + free(p); + } +} diff --git a/src/kernel/player.h b/src/kernel/player.h index 74fb8c4a5..d70fa4ad2 100644 --- a/src/kernel/player.h +++ b/src/kernel/player.h @@ -1,43 +1,43 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - - */ -#ifndef H_KRNL_PLAYER -#define H_KRNL_PLAYER -#ifdef __cplusplus -extern "C" { -#endif - -struct faction; - -typedef struct player { - unsigned int id; - char * name; - char * email; - char * address; - struct vacation { - int weeks; - char * email; - } * vacation; - const struct faction * faction; - - struct player * nexthash; /* don't use! */ -} player; - -extern struct player * get_players(void); -extern struct player * get_player(unsigned int id); -extern struct player * make_player(const struct faction * f); -extern struct player * next_player(struct player * p); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ +#ifndef H_KRNL_PLAYER +#define H_KRNL_PLAYER +#ifdef __cplusplus +extern "C" { +#endif + +struct faction; + +typedef struct player { + unsigned int id; + char * name; + char * email; + char * address; + struct vacation { + int weeks; + char * email; + } * vacation; + const struct faction * faction; + + struct player * nexthash; /* don't use! */ +} player; + +extern struct player * get_players(void); +extern struct player * get_player(unsigned int id); +extern struct player * make_player(const struct faction * f); +extern struct player * next_player(struct player * p); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/pool.c b/src/kernel/pool.c index a7a1e6b02..042cc7db3 100644 --- a/src/kernel/pool.c +++ b/src/kernel/pool.c @@ -1,262 +1,262 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "pool.h" - -#include "faction.h" -#include "item.h" -#include "magic.h" -#include "order.h" -#include "region.h" -#include "race.h" -#include "unit.h" - -#include -#include - -#include -#include - -#define TODO_POOL -#undef TODO_RESOURCES - -int -get_resource(const unit * u, const resource_type * rtype) -{ - const item_type * itype = resource2item(rtype); - - if (rtype->uget) { - /* this resource is probably special */ - int i = rtype->uget(u, rtype); - if (i>=0) return i; - } - if (itype!=NULL) { - if (itype == olditemtype[R_STONE] && (u->race->flags&RCF_STONEGOLEM)) { - return u->number*GOLEM_STONE; - } else if (itype==olditemtype[R_IRON] && (u->race->flags&RCF_IRONGOLEM)) { - return u->number*GOLEM_IRON; - } else { - const item * i = *i_findc(&u->items, itype); - if (i) return i->number; - return 0; - } - } - if (rtype == oldresourcetype[R_AURA]) - return get_spellpoints(u); - if (rtype == oldresourcetype[R_PERMAURA]) - return max_spellpoints(u->region, u); - log_error(("trying to get unknown resource '%s'.\n", rtype->_name[0])); - return 0; -} - -int -change_resource(unit * u, const resource_type * rtype, int change) -{ - int i = 0; - - if (rtype->uchange) - i = rtype->uchange(u, rtype, change); - else if (rtype == oldresourcetype[R_AURA]) - i = change_spellpoints(u, change); - else if (rtype == oldresourcetype[R_PERMAURA]) - i = change_maxspellpoints(u, change); - else - assert(!"undefined resource detected. rtype->uchange not initialized."); - assert(i >= 0 && (i < 100000000)); /* soft test to catch mischief */ - return i; -} - -int -get_reservation(const unit * u, const resource_type * rtype) -{ - struct reservation * res = u->reservations; - - if (rtype==oldresourcetype[R_STONE] && (u->race->flags&RCF_STONEGOLEM)) - return (u->number * GOLEM_STONE); - if (rtype==oldresourcetype[R_IRON] && (u->race->flags&RCF_IRONGOLEM)) - return (u->number * GOLEM_IRON); - while (res && res->type!=rtype) res=res->next; - if (res) return res->value; - return 0; -} - -int -change_reservation(unit * u, const resource_type * rtype, int value) -{ - struct reservation *res, ** rp = &u->reservations; - - if (!value) return 0; - - while (*rp && (*rp)->type!=rtype) rp=&(*rp)->next; - res = *rp; - if (!res) { - *rp = res = calloc(sizeof(struct reservation), 1); - res->type = rtype; - res->value = value; - } else if (res && res->value+value<=0) { - *rp = res->next; - free(res); - return 0; - } else { - res->value += value; - } - return res->value; -} - -static int -new_set_resvalue(unit * u, const resource_type * rtype, int value) -{ - struct reservation *res, ** rp = &u->reservations; - - while (*rp && (*rp)->type!=rtype) rp=&(*rp)->next; - res = *rp; - if (!res) { - if (!value) return 0; - *rp = res = calloc(sizeof(struct reservation), 1); - res->type = rtype; - res->value = value; - } else if (res && value<=0) { - *rp = res->next; - free(res); - return 0; - } else { - res->value = value; - } - return res->value; -} - -int -get_pooled(const unit * u, const resource_type * rtype, unsigned int mode, int count) -{ - const faction * f = u->faction; - unit *v; - int use = 0; - region * r = u->region; - int have = get_resource(u, rtype); - - if ((u->race->ec_flags & GETITEM) == 0) { - mode &= (GET_SLACK|GET_RESERVE); - } - - if ((mode & GET_SLACK) && (mode & GET_RESERVE)) use = have; - else { - int reserve = get_reservation(u, rtype); - int slack = MAX(0, have-reserve); - if (mode & GET_RESERVE) use = have-slack; - else if (mode & GET_SLACK) use = slack; - } - if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK|GET_RESERVE)) { - for (v = r->units; v && usenext) if (u!=v) { - int mask; - - if (v->items==NULL && rtype->uget==NULL) continue; - if ((urace(v)->ec_flags & GIVEITEM) == 0) continue; - - if (v->faction == f) { - mask = (mode >> 3) & (GET_SLACK|GET_RESERVE); - } - else if (alliedunit(v, f, HELP_MONEY)) mask = (mode >> 6) & (GET_SLACK|GET_RESERVE); - else continue; - use += get_pooled(v, rtype, mask, count-use); - } - } - return use; -} - -int -use_pooled(unit * u, const resource_type * rtype, unsigned int mode, int count) -{ - const faction *f = u->faction; - unit *v; - int use = count; - region * r = u->region; - int n = 0, have = get_resource(u, rtype); - - if ((u->race->ec_flags & GETITEM) == 0) { - mode &= (GET_SLACK|GET_RESERVE); - } - - if ((mode & GET_SLACK) && (mode & GET_RESERVE)) { - n = MIN(use, have); - } else { - int reserve = get_reservation(u, rtype); - int slack = MAX(0, have-reserve); - if (mode & GET_RESERVE) { - n = have-slack; - n = MIN(use, n); - change_reservation(u, rtype, -n); - } - else if (mode & GET_SLACK) { - n = MIN(use, slack); - } - } - if (n>0) { - change_resource(u, rtype, -n); - use -= n; - } - - if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK|GET_RESERVE)) { - for (v = r->units; use>0 && v!=NULL; v = v->next) if (u!=v) { - int mask; - if ((urace(v)->ec_flags & GIVEITEM) == 0) continue; - if (v->items==NULL && rtype->uget==NULL) continue; - - if (v->faction == f) { - mask = (mode >> 3) & (GET_SLACK|GET_RESERVE); - } - else if (alliedunit(v, f, HELP_MONEY)) mask = (mode >> 6) & (GET_SLACK|GET_RESERVE); - else continue; - use -= use_pooled(v, rtype, mask, use); - } - } - return count-use; -} - - -int -reserve_cmd(unit * u, struct order *ord) -{ - if (u->number > 0 && (urace(u)->ec_flags & GETITEM)) { - int use, count; - const resource_type * rtype; - const char * s; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - count = atoip((const char *)s); - - if (count == 0 && findparam(s, u->faction->locale)==P_EACH) { - count = getint() * u->number; - } - - rtype = findresourcetype(getstrtoken(), u->faction->locale); - if (rtype == NULL) return 0; - - new_set_resvalue(u, rtype, 0); /* make sure the pool is empty */ - use = use_pooled(u, rtype, GET_DEFAULT, count); - if (use) { - new_set_resvalue(u, rtype, use); - change_resource(u, rtype, use); - } - } - return 0; -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "pool.h" + +#include "faction.h" +#include "item.h" +#include "magic.h" +#include "order.h" +#include "region.h" +#include "race.h" +#include "unit.h" + +#include +#include + +#include +#include + +#define TODO_POOL +#undef TODO_RESOURCES + +int +get_resource(const unit * u, const resource_type * rtype) +{ + const item_type * itype = resource2item(rtype); + + if (rtype->uget) { + /* this resource is probably special */ + int i = rtype->uget(u, rtype); + if (i>=0) return i; + } + if (itype!=NULL) { + if (itype == olditemtype[R_STONE] && (u->race->flags&RCF_STONEGOLEM)) { + return u->number*GOLEM_STONE; + } else if (itype==olditemtype[R_IRON] && (u->race->flags&RCF_IRONGOLEM)) { + return u->number*GOLEM_IRON; + } else { + const item * i = *i_findc(&u->items, itype); + if (i) return i->number; + return 0; + } + } + if (rtype == oldresourcetype[R_AURA]) + return get_spellpoints(u); + if (rtype == oldresourcetype[R_PERMAURA]) + return max_spellpoints(u->region, u); + log_error(("trying to get unknown resource '%s'.\n", rtype->_name[0])); + return 0; +} + +int +change_resource(unit * u, const resource_type * rtype, int change) +{ + int i = 0; + + if (rtype->uchange) + i = rtype->uchange(u, rtype, change); + else if (rtype == oldresourcetype[R_AURA]) + i = change_spellpoints(u, change); + else if (rtype == oldresourcetype[R_PERMAURA]) + i = change_maxspellpoints(u, change); + else + assert(!"undefined resource detected. rtype->uchange not initialized."); + assert(i >= 0 && (i < 100000000)); /* soft test to catch mischief */ + return i; +} + +int +get_reservation(const unit * u, const resource_type * rtype) +{ + struct reservation * res = u->reservations; + + if (rtype==oldresourcetype[R_STONE] && (u->race->flags&RCF_STONEGOLEM)) + return (u->number * GOLEM_STONE); + if (rtype==oldresourcetype[R_IRON] && (u->race->flags&RCF_IRONGOLEM)) + return (u->number * GOLEM_IRON); + while (res && res->type!=rtype) res=res->next; + if (res) return res->value; + return 0; +} + +int +change_reservation(unit * u, const resource_type * rtype, int value) +{ + struct reservation *res, ** rp = &u->reservations; + + if (!value) return 0; + + while (*rp && (*rp)->type!=rtype) rp=&(*rp)->next; + res = *rp; + if (!res) { + *rp = res = calloc(sizeof(struct reservation), 1); + res->type = rtype; + res->value = value; + } else if (res && res->value+value<=0) { + *rp = res->next; + free(res); + return 0; + } else { + res->value += value; + } + return res->value; +} + +static int +new_set_resvalue(unit * u, const resource_type * rtype, int value) +{ + struct reservation *res, ** rp = &u->reservations; + + while (*rp && (*rp)->type!=rtype) rp=&(*rp)->next; + res = *rp; + if (!res) { + if (!value) return 0; + *rp = res = calloc(sizeof(struct reservation), 1); + res->type = rtype; + res->value = value; + } else if (res && value<=0) { + *rp = res->next; + free(res); + return 0; + } else { + res->value = value; + } + return res->value; +} + +int +get_pooled(const unit * u, const resource_type * rtype, unsigned int mode, int count) +{ + const faction * f = u->faction; + unit *v; + int use = 0; + region * r = u->region; + int have = get_resource(u, rtype); + + if ((u->race->ec_flags & GETITEM) == 0) { + mode &= (GET_SLACK|GET_RESERVE); + } + + if ((mode & GET_SLACK) && (mode & GET_RESERVE)) use = have; + else { + int reserve = get_reservation(u, rtype); + int slack = MAX(0, have-reserve); + if (mode & GET_RESERVE) use = have-slack; + else if (mode & GET_SLACK) use = slack; + } + if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK|GET_RESERVE)) { + for (v = r->units; v && usenext) if (u!=v) { + int mask; + + if (v->items==NULL && rtype->uget==NULL) continue; + if ((urace(v)->ec_flags & GIVEITEM) == 0) continue; + + if (v->faction == f) { + mask = (mode >> 3) & (GET_SLACK|GET_RESERVE); + } + else if (alliedunit(v, f, HELP_MONEY)) mask = (mode >> 6) & (GET_SLACK|GET_RESERVE); + else continue; + use += get_pooled(v, rtype, mask, count-use); + } + } + return use; +} + +int +use_pooled(unit * u, const resource_type * rtype, unsigned int mode, int count) +{ + const faction *f = u->faction; + unit *v; + int use = count; + region * r = u->region; + int n = 0, have = get_resource(u, rtype); + + if ((u->race->ec_flags & GETITEM) == 0) { + mode &= (GET_SLACK|GET_RESERVE); + } + + if ((mode & GET_SLACK) && (mode & GET_RESERVE)) { + n = MIN(use, have); + } else { + int reserve = get_reservation(u, rtype); + int slack = MAX(0, have-reserve); + if (mode & GET_RESERVE) { + n = have-slack; + n = MIN(use, n); + change_reservation(u, rtype, -n); + } + else if (mode & GET_SLACK) { + n = MIN(use, slack); + } + } + if (n>0) { + change_resource(u, rtype, -n); + use -= n; + } + + if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK|GET_RESERVE)) { + for (v = r->units; use>0 && v!=NULL; v = v->next) if (u!=v) { + int mask; + if ((urace(v)->ec_flags & GIVEITEM) == 0) continue; + if (v->items==NULL && rtype->uget==NULL) continue; + + if (v->faction == f) { + mask = (mode >> 3) & (GET_SLACK|GET_RESERVE); + } + else if (alliedunit(v, f, HELP_MONEY)) mask = (mode >> 6) & (GET_SLACK|GET_RESERVE); + else continue; + use -= use_pooled(v, rtype, mask, use); + } + } + return count-use; +} + + +int +reserve_cmd(unit * u, struct order *ord) +{ + if (u->number > 0 && (urace(u)->ec_flags & GETITEM)) { + int use, count; + const resource_type * rtype; + const char * s; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + count = atoip((const char *)s); + + if (count == 0 && findparam(s, u->faction->locale)==P_EACH) { + count = getint() * u->number; + } + + rtype = findresourcetype(getstrtoken(), u->faction->locale); + if (rtype == NULL) return 0; + + new_set_resvalue(u, rtype, 0); /* make sure the pool is empty */ + use = use_pooled(u, rtype, GET_DEFAULT, count); + if (use) { + new_set_resvalue(u, rtype, use); + change_resource(u, rtype, use); + } + } + return 0; +} + diff --git a/src/kernel/pool.h b/src/kernel/pool.h index 124bcb432..80239c8d7 100644 --- a/src/kernel/pool.h +++ b/src/kernel/pool.h @@ -1,62 +1,62 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_POOL_H -#define H_KRNL_POOL_H -#ifdef __cplusplus -extern "C" { -#endif - -/* bitfield values for get/use/change operations */ -#define GET_SLACK 0x01 -#define GET_RESERVE 0x02 - -#define GET_POOLED_SLACK 0x08 -#define GET_POOLED_RESERVE 0x10 -#define GET_POOLED_FORCE 0x20 /* ignore f->options pools */ -#define GET_ALLIED_SLACK 0x30 -#define GET_ALLIED_RESERVE 0x40 - -/* for convenience: */ -#define GET_DEFAULT (GET_RESERVE|GET_SLACK|GET_POOLED_SLACK) -#define GET_ALL (GET_SLACK|GET_RESERVE|GET_POOLED_SLACK|GET_POOLED_RESERVE|GET_POOLED_FORCE) - -int get_pooled(const struct unit * u, const struct resource_type * res, unsigned int mode, int count); -int use_pooled(struct unit * u, const struct resource_type * res, unsigned int mode, int count); - /** use_pooled - * verbraucht 'count' Objekte der resource 'itm' - * unter zuhilfenahme des Pools der struct region und Aufbrauch des - * von der Einheit reservierten Resourcen - */ - -int get_resource(const struct unit * u, const struct resource_type * res); -int change_resource(struct unit * u, const struct resource_type * res, int change); - -int get_reservation(const struct unit * u, const struct resource_type * res); -int change_reservation(struct unit * u, const struct resource_type * res, int value); - -int reserve_cmd(struct unit *u, struct order *ord); - -/** init_pool - * initialisiert den regionalen Pool. - */ - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_POOL_H +#define H_KRNL_POOL_H +#ifdef __cplusplus +extern "C" { +#endif + +/* bitfield values for get/use/change operations */ +#define GET_SLACK 0x01 +#define GET_RESERVE 0x02 + +#define GET_POOLED_SLACK 0x08 +#define GET_POOLED_RESERVE 0x10 +#define GET_POOLED_FORCE 0x20 /* ignore f->options pools */ +#define GET_ALLIED_SLACK 0x30 +#define GET_ALLIED_RESERVE 0x40 + +/* for convenience: */ +#define GET_DEFAULT (GET_RESERVE|GET_SLACK|GET_POOLED_SLACK) +#define GET_ALL (GET_SLACK|GET_RESERVE|GET_POOLED_SLACK|GET_POOLED_RESERVE|GET_POOLED_FORCE) + +int get_pooled(const struct unit * u, const struct resource_type * res, unsigned int mode, int count); +int use_pooled(struct unit * u, const struct resource_type * res, unsigned int mode, int count); + /** use_pooled + * verbraucht 'count' Objekte der resource 'itm' + * unter zuhilfenahme des Pools der struct region und Aufbrauch des + * von der Einheit reservierten Resourcen + */ + +int get_resource(const struct unit * u, const struct resource_type * res); +int change_resource(struct unit * u, const struct resource_type * res, int change); + +int get_reservation(const struct unit * u, const struct resource_type * res); +int change_reservation(struct unit * u, const struct resource_type * res, int value); + +int reserve_cmd(struct unit *u, struct order *ord); + +/** init_pool + * initialisiert den regionalen Pool. + */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/race.c b/src/kernel/race.c index bc2977b0a..ffb9bf8a5 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -1,296 +1,296 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "race.h" - -#include "alchemy.h" -#include "build.h" -#include "building.h" -#include "equipment.h" -#include "faction.h" -#include "group.h" -#include "item.h" -#include "magic.h" -#include "names.h" -#include "pathfinder.h" -#include "region.h" -#include "ship.h" -#include "skill.h" -#include "terrain.h" -#include "unit.h" -#include "version.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include - -/* attrib includes */ -#include - -/* libc includes */ -#include -#include -#include -#include -#include - -/** external variables **/ -race * races; -int num_races = 0; - -race_list * -get_familiarraces(void) -{ - static int init = 0; - static race_list * familiarraces; - - if (!init) { - race * rc = races; - for (;rc!=NULL;rc=rc->next) { - if (rc->init_familiar!=NULL) { - racelist_insert(&familiarraces, rc); - } - } - init = false; - } - return familiarraces; -} - -void -racelist_clear(struct race_list **rl) -{ - while (*rl) { - race_list * rl2 = (*rl)->next; - free(*rl); - *rl = rl2; - } -} - -void -racelist_insert(struct race_list **rl, const struct race *r) -{ - race_list *rl2 = (race_list*)malloc(sizeof(race_list)); - - rl2->data = r; - rl2->next = *rl; - - *rl = rl2; -} - -race * -rc_new(const char * zName) -{ - char zBuffer[80]; - race * rc = calloc(sizeof(race), 1); - if (strchr(zName, ' ')!=NULL) { - log_error(("race '%s' has an invalid name. remove spaces\n", zName)); - assert(strchr(zName, ' ')==NULL); - } - strcpy(zBuffer, zName); - rc->_name[0] = strdup(zBuffer); - sprintf(zBuffer, "%s_p", zName); - rc->_name[1] = strdup(zBuffer); - sprintf(zBuffer, "%s_d", zName); - rc->_name[2] = strdup(zBuffer); - sprintf(zBuffer, "%s_x", zName); - rc->_name[3] = strdup(zBuffer); - rc->precombatspell = NULL; - - rc->attack[0].type = AT_COMBATSPELL; - rc->attack[1].type = AT_NONE; - return rc; -} - -race * -rc_add(race * rc) -{ - rc->index = num_races++; - rc->next = races; - return races = rc; -} - -static const char * racealias[][2] = { - { "uruk", "orc" }, /* there was a time when the orc race was called uruk (and there were other orcs). That was really confusing */ - { "skeletton lord", "skeleton lord" }, /* we once had a typo here. it is fixed */ - { NULL, NULL } -}; - -race * -rc_find(const char * name) -{ - const char * rname = name; - race * rc = races; - int i; - - for (i=0;racealias[i][0];++i) { - if (strcmp(racealias[i][0], name)==0) { - rname = racealias[i][1]; - break; - } - } - while (rc && !strcmp(rname, rc->_name[0])==0) rc = rc->next; - return rc; -} - -/** dragon movement **/ -boolean -allowed_dragon(const region * src, const region * target) -{ - if (fval(src->terrain, ARCTIC_REGION) && fval(target->terrain, SEA_REGION)) return false; - return allowed_fly(src, target); -} - -char ** race_prefixes = NULL; - -extern void -add_raceprefix(const char * prefix) -{ - static size_t size = 4; - static unsigned int next = 0; - if (race_prefixes==NULL) race_prefixes = malloc(size * sizeof(char*)); - if (next+1==size) { - size *= 2; - race_prefixes = realloc(race_prefixes, size * sizeof(char*)); - } - race_prefixes[next++] = strdup(prefix); - race_prefixes[next] = NULL; -} - -/* Die Bezeichnungen dürfen wegen der Art des Speicherns keine - * Leerzeichen enthalten! */ - -/* "den Zwergen", "Halblingsparteien" */ - -void -set_show_item(faction *f, item_t i) -{ - attrib *a = a_add(&f->attribs, a_new(&at_showitem)); - a->data.v = (void*)olditemtype[i]; -} - -boolean -r_insectstalled(const region * r) -{ - return fval(r->terrain, ARCTIC_REGION); -} - -const char * -rc_name(const race * rc, int n) -{ - return rc?mkname("race", rc->_name[n]):NULL; -} - -const char * -raceprefix(const unit *u) -{ - const attrib * asource = u->faction->attribs; - - if (fval(u, UFL_GROUP)) { - const attrib * agroup = agroup = a_findc(u->attribs, &at_group); - if (agroup!=NULL) asource = ((const group *)(agroup->data.v))->attribs; - } - return get_prefix(asource); -} - -const char * -racename(const struct locale *loc, const unit *u, const race * rc) -{ - const char * prefix = raceprefix(u); - - if (prefix!=NULL) { - static char lbuf[80]; - char * bufp = lbuf; - size_t size = sizeof(lbuf) - 1; - int ch, bytes; - - bytes = (int)strlcpy(bufp, LOC(loc, mkname("prefix", prefix)), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - bytes = (int)strlcpy(bufp, LOC(loc, rc_name(rc, u->number != 1)), size); - assert(~bufp[0] & 0x80|| !"unicode/not implemented"); - ch = tolower(*(unsigned char *)bufp); - bufp[0] = (char)ch; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - *bufp = 0; - - return lbuf; - } - return LOC(loc, rc_name(rc, u->number != 1)); -} - -int -rc_specialdamage(const race * ar, const race * dr, const struct weapon_type * wtype) -{ - race_t art = old_race(ar); - int m, modifier = 0; - - if (wtype!=NULL && wtype->modifiers!=NULL) for (m=0;wtype->modifiers[m].value;++m) { - /* weapon damage for this weapon, possibly by race */ - if (wtype->modifiers[m].flags & WMF_DAMAGE) { - race_list * rlist = wtype->modifiers[m].races; - if (rlist!=NULL) { - while (rlist) { - if (rlist->data == ar) break; - rlist = rlist->next; - } - if (rlist==NULL) continue; - } - modifier += wtype->modifiers[m].value; - } - } - switch (art) { - case RC_HALFLING: - if (wtype!=NULL && dragonrace(dr)) { - modifier += 5; - } - break; - default: - break; - } - return modifier; -} - -void -write_race_reference(const race * rc, struct storage * store) -{ - store->w_tok(store, rc?rc->_name[0]:"none"); -} - -variant -read_race_reference(struct storage * store) -{ - variant result; - char zName[20]; - store->r_tok_buf(store, zName, sizeof(zName)); - - if (strcmp(zName, "none")==0) { - result.v = NULL; - return result; - } else { - result.v = rc_find(zName); - } - assert(result.v!=NULL); - return result; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "race.h" + +#include "alchemy.h" +#include "build.h" +#include "building.h" +#include "equipment.h" +#include "faction.h" +#include "group.h" +#include "item.h" +#include "magic.h" +#include "names.h" +#include "pathfinder.h" +#include "region.h" +#include "ship.h" +#include "skill.h" +#include "terrain.h" +#include "unit.h" +#include "version.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include + +/* attrib includes */ +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +/** external variables **/ +race * races; +int num_races = 0; + +race_list * +get_familiarraces(void) +{ + static int init = 0; + static race_list * familiarraces; + + if (!init) { + race * rc = races; + for (;rc!=NULL;rc=rc->next) { + if (rc->init_familiar!=NULL) { + racelist_insert(&familiarraces, rc); + } + } + init = false; + } + return familiarraces; +} + +void +racelist_clear(struct race_list **rl) +{ + while (*rl) { + race_list * rl2 = (*rl)->next; + free(*rl); + *rl = rl2; + } +} + +void +racelist_insert(struct race_list **rl, const struct race *r) +{ + race_list *rl2 = (race_list*)malloc(sizeof(race_list)); + + rl2->data = r; + rl2->next = *rl; + + *rl = rl2; +} + +race * +rc_new(const char * zName) +{ + char zBuffer[80]; + race * rc = calloc(sizeof(race), 1); + if (strchr(zName, ' ')!=NULL) { + log_error(("race '%s' has an invalid name. remove spaces\n", zName)); + assert(strchr(zName, ' ')==NULL); + } + strcpy(zBuffer, zName); + rc->_name[0] = strdup(zBuffer); + sprintf(zBuffer, "%s_p", zName); + rc->_name[1] = strdup(zBuffer); + sprintf(zBuffer, "%s_d", zName); + rc->_name[2] = strdup(zBuffer); + sprintf(zBuffer, "%s_x", zName); + rc->_name[3] = strdup(zBuffer); + rc->precombatspell = NULL; + + rc->attack[0].type = AT_COMBATSPELL; + rc->attack[1].type = AT_NONE; + return rc; +} + +race * +rc_add(race * rc) +{ + rc->index = num_races++; + rc->next = races; + return races = rc; +} + +static const char * racealias[][2] = { + { "uruk", "orc" }, /* there was a time when the orc race was called uruk (and there were other orcs). That was really confusing */ + { "skeletton lord", "skeleton lord" }, /* we once had a typo here. it is fixed */ + { NULL, NULL } +}; + +race * +rc_find(const char * name) +{ + const char * rname = name; + race * rc = races; + int i; + + for (i=0;racealias[i][0];++i) { + if (strcmp(racealias[i][0], name)==0) { + rname = racealias[i][1]; + break; + } + } + while (rc && !strcmp(rname, rc->_name[0])==0) rc = rc->next; + return rc; +} + +/** dragon movement **/ +boolean +allowed_dragon(const region * src, const region * target) +{ + if (fval(src->terrain, ARCTIC_REGION) && fval(target->terrain, SEA_REGION)) return false; + return allowed_fly(src, target); +} + +char ** race_prefixes = NULL; + +extern void +add_raceprefix(const char * prefix) +{ + static size_t size = 4; + static unsigned int next = 0; + if (race_prefixes==NULL) race_prefixes = malloc(size * sizeof(char*)); + if (next+1==size) { + size *= 2; + race_prefixes = realloc(race_prefixes, size * sizeof(char*)); + } + race_prefixes[next++] = strdup(prefix); + race_prefixes[next] = NULL; +} + +/* Die Bezeichnungen dürfen wegen der Art des Speicherns keine + * Leerzeichen enthalten! */ + +/* "den Zwergen", "Halblingsparteien" */ + +void +set_show_item(faction *f, item_t i) +{ + attrib *a = a_add(&f->attribs, a_new(&at_showitem)); + a->data.v = (void*)olditemtype[i]; +} + +boolean +r_insectstalled(const region * r) +{ + return fval(r->terrain, ARCTIC_REGION); +} + +const char * +rc_name(const race * rc, int n) +{ + return rc?mkname("race", rc->_name[n]):NULL; +} + +const char * +raceprefix(const unit *u) +{ + const attrib * asource = u->faction->attribs; + + if (fval(u, UFL_GROUP)) { + const attrib * agroup = agroup = a_findc(u->attribs, &at_group); + if (agroup!=NULL) asource = ((const group *)(agroup->data.v))->attribs; + } + return get_prefix(asource); +} + +const char * +racename(const struct locale *loc, const unit *u, const race * rc) +{ + const char * prefix = raceprefix(u); + + if (prefix!=NULL) { + static char lbuf[80]; + char * bufp = lbuf; + size_t size = sizeof(lbuf) - 1; + int ch, bytes; + + bytes = (int)strlcpy(bufp, LOC(loc, mkname("prefix", prefix)), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + bytes = (int)strlcpy(bufp, LOC(loc, rc_name(rc, u->number != 1)), size); + assert(~bufp[0] & 0x80|| !"unicode/not implemented"); + ch = tolower(*(unsigned char *)bufp); + bufp[0] = (char)ch; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + *bufp = 0; + + return lbuf; + } + return LOC(loc, rc_name(rc, u->number != 1)); +} + +int +rc_specialdamage(const race * ar, const race * dr, const struct weapon_type * wtype) +{ + race_t art = old_race(ar); + int m, modifier = 0; + + if (wtype!=NULL && wtype->modifiers!=NULL) for (m=0;wtype->modifiers[m].value;++m) { + /* weapon damage for this weapon, possibly by race */ + if (wtype->modifiers[m].flags & WMF_DAMAGE) { + race_list * rlist = wtype->modifiers[m].races; + if (rlist!=NULL) { + while (rlist) { + if (rlist->data == ar) break; + rlist = rlist->next; + } + if (rlist==NULL) continue; + } + modifier += wtype->modifiers[m].value; + } + } + switch (art) { + case RC_HALFLING: + if (wtype!=NULL && dragonrace(dr)) { + modifier += 5; + } + break; + default: + break; + } + return modifier; +} + +void +write_race_reference(const race * rc, struct storage * store) +{ + store->w_tok(store, rc?rc->_name[0]:"none"); +} + +variant +read_race_reference(struct storage * store) +{ + variant result; + char zName[20]; + store->r_tok_buf(store, zName, sizeof(zName)); + + if (strcmp(zName, "none")==0) { + result.v = NULL; + return result; + } else { + result.v = rc_find(zName); + } + assert(result.v!=NULL); + return result; +} diff --git a/src/kernel/race.h b/src/kernel/race.h index 321eb4826..e1f7e5439 100644 --- a/src/kernel/race.h +++ b/src/kernel/race.h @@ -1,192 +1,192 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_RACE_H -#define H_KRNL_RACE_H -#ifdef __cplusplus -extern "C" { -#endif - -#include "magic.h" /* wegen MAXMAGIETYP */ - -#define AT_NONE 0 -#define AT_STANDARD 1 -#define AT_DRAIN_EXP 2 -#define AT_DRAIN_ST 3 -#define AT_NATURAL 4 -#define AT_DAZZLE 5 -#define AT_SPELL 6 -#define AT_COMBATSPELL 7 -#define AT_STRUCTURAL 8 - -#define GOLEM_IRON 4 /* Anzahl Eisen in einem Eisengolem */ -#define GOLEM_STONE 4 /* Anzahl Steine in einem Steingolem */ - -#define RACESPOILCHANCE 5 /* Chance auf rassentypische Beute */ - -typedef struct att { - int type; - union { - const char * dice; - const struct spell * sp; - } data; - int flags; -} att; - -struct param; - -extern int num_races; - -typedef struct race { - struct param * parameters; - const char *_name[4]; /* neu: name[4]völker */ - float magres; - float maxaura; /* Faktor auf Maximale Aura */ - float regaura; /* Faktor auf Regeneration */ - float recruit_multi; /* Faktor für Bauernverbrauch */ - int index; - int recruitcost; - int maintenance; - int splitsize; - int weight; - int capacity; - float speed; - float aggression; /* chance that a monster will attack */ - int hitpoints; - const char *def_damage; - char armor; - int at_default; /* Angriffsskill Unbewaffnet (default: -2)*/ - int df_default; /* Verteidigungsskill Unbewaffnet (default: -2)*/ - int at_bonus; /* Verändert den Angriffsskill (default: 0)*/ - int df_bonus; /* Verändert den Verteidigungskill (default: 0)*/ - const spell * precombatspell; - struct att attack[10]; - char bonus[MAXSKILLS]; - signed char * study_speed; /* study-speed-bonus in points/turn (0=30 Tage) */ - boolean __remove_me_nonplayer; - int flags; - int battle_flags; - int ec_flags; - race_t oldfamiliars[MAXMAGIETYP]; - - const char *(*generate_name) (const struct unit *); - const char *(*describe) (const struct unit *, const struct locale *); - void (*age)(struct unit *u); - boolean (*move_allowed)(const struct region *, const struct region *); - struct item * (*itemdrop)(const struct race *, int size); - void (*init_familiar)(struct unit *); - - const struct race * familiars[MAXMAGIETYP]; - struct attrib * attribs; - struct race * next; -} race; - -typedef struct race_list { - struct race_list * next; - const struct race * data; -} race_list; - -extern void racelist_clear(struct race_list **rl); -extern void racelist_insert(struct race_list **rl, const struct race *r); - -extern struct race_list * get_familiarraces(void); -extern struct race * races; - -extern struct race * rc_find(const char *); -extern const char * rc_name(const struct race *, int); -extern struct race * rc_add(struct race *); -extern struct race * rc_new(const char * zName); -extern int rc_specialdamage(const race *, const race *, const struct weapon_type *); - -/* Flags */ -#define RCF_PLAYERRACE (1<<0) /* can be played by a player. */ -#define RCF_KILLPEASANTS (1<<1) /* Töten Bauern. Dämonen werden nicht über dieses Flag, sondern in randenc() behandelt. */ -#define RCF_SCAREPEASANTS (1<<2) -#define RCF_CANSTEAL (1<<3) -#define RCF_MOVERANDOM (1<<4) -#define RCF_CANNOTMOVE (1<<5) -#define RCF_LEARN (1<<6) /* Lernt automatisch wenn struct faction == 0 */ -#define RCF_FLY (1<<7) /* kann fliegen */ -#define RCF_SWIM (1<<8) /* kann schwimmen */ -#define RCF_WALK (1<<9) /* kann über Land gehen */ -#define RCF_NOLEARN (1<<10) /* kann nicht normal lernen */ -#define RCF_NOTEACH (1<<11) /* kann nicht lehren */ -#define RCF_HORSE (1<<12) /* Einheit ist Pferd, sozusagen */ -#define RCF_DESERT (1<<13) /* 5% Chance, das Einheit desertiert */ -#define RCF_ILLUSIONARY (1<<14) /* (Illusion & Spell) Does not drop items. */ -#define RCF_ABSORBPEASANTS (1<<15) /* Tötet und absorbiert Bauern */ -#define RCF_NOHEAL (1<<16) /* Einheit kann nicht geheilt werden */ -#define RCF_NOWEAPONS (1<<17) /* Einheit kann keine Waffen benutzen */ -#define RCF_SHAPESHIFT (1<<18) /* Kann TARNE RASSE benutzen. */ -#define RCF_SHAPESHIFTANY (1<<19) /* Kann TARNE RASSE "string" benutzen. */ -#define RCF_UNDEAD (1<<20) /* Undead. */ -#define RCF_DRAGON (1<<21) /* Drachenart (für Zauber)*/ -#define RCF_COASTAL (1<<22) /* kann in Landregionen an der Küste sein */ -#define RCF_UNARMEDGUARD (1<<23) /* kann ohne Waffen bewachen */ -#define RCF_CANSAIL (1<<24) /* Einheit darf Schiffe betreten */ -#define RCF_INVISIBLE (1<<25) /* not visible in any report */ -#define RCF_SHIPSPEED (1<<26) /* race gets +1 on shipspeed */ -#define RCF_STONEGOLEM (1<<27) /* race gets stonegolem properties */ -#define RCF_IRONGOLEM (1<<28) /* race gets irongolem properties */ - -/* Economic flags */ -#define GIVEITEM (1<<1) /* gibt Gegenstände weg */ -#define GIVEPERSON (1<<2) /* übergibt Personen */ -#define GIVEUNIT (1<<3) /* Einheiten an andere Partei übergeben */ -#define GETITEM (1<<4) /* nimmt Gegenstände an */ -#define ECF_REC_HORSES (1<<6) /* Rekrutiert aus Pferden */ -#define ECF_REC_ETHEREAL (1<<7) /* Rekrutiert aus dem Nichts */ -#define ECF_REC_UNLIMITED (1<<8) /* Rekrutiert ohne Limit */ - -/* Battle-Flags */ -#define BF_EQUIPMENT (1<<0) /* Kann Ausrüstung benutzen */ -#define BF_NOBLOCK (1<<1) /* Wird in die Rückzugsberechnung nicht einbezogen */ -#define BF_RES_PIERCE (1<<2) /* Halber Schaden durch PIERCE */ -#define BF_RES_CUT (1<<3) /* Halber Schaden durch CUT */ -#define BF_RES_BASH (1<<4) /* Halber Schaden durch BASH */ -#define BF_INV_NONMAGIC (1<<5) /* Immun gegen nichtmagischen Schaden */ -#define BF_CANATTACK (1<<6) /* Kann keine ATTACKIERE Befehle ausfuehren */ - -extern int unit_old_max_hp(struct unit * u); -extern const char * racename(const struct locale *lang, const struct unit *u, const race * rc); - -#define omniscient(f) (((f)->race)==new_race[RC_ILLUSION] || ((f)->race)==new_race[RC_TEMPLATE]) - -#define playerrace(rc) (fval((rc), RCF_PLAYERRACE)) -#define dragonrace(rc) ((rc) == new_race[RC_FIREDRAGON] || (rc) == new_race[RC_DRAGON] || (rc) == new_race[RC_WYRM] || (rc) == new_race[RC_BIRTHDAYDRAGON]) -#define humanoidrace(rc) (fval((rc), RCF_UNDEAD) || (rc)==new_race[RC_DRACOID] || playerrace(rc)) -#define illusionaryrace(rc) (fval(rc, RCF_ILLUSIONARY)) - -extern boolean allowed_dragon(const struct region * src, const struct region * target); - -extern boolean r_insectstalled(const struct region *r); - -extern void add_raceprefix(const char *); -extern char ** race_prefixes; - -extern void write_race_reference(const struct race * rc, struct storage * store); -extern variant read_race_reference(struct storage * store); - -extern const char * raceprefix(const struct unit *u); - -extern void give_starting_equipment(const struct equipment * eq, struct unit *u); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_RACE_H +#define H_KRNL_RACE_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "magic.h" /* wegen MAXMAGIETYP */ + +#define AT_NONE 0 +#define AT_STANDARD 1 +#define AT_DRAIN_EXP 2 +#define AT_DRAIN_ST 3 +#define AT_NATURAL 4 +#define AT_DAZZLE 5 +#define AT_SPELL 6 +#define AT_COMBATSPELL 7 +#define AT_STRUCTURAL 8 + +#define GOLEM_IRON 4 /* Anzahl Eisen in einem Eisengolem */ +#define GOLEM_STONE 4 /* Anzahl Steine in einem Steingolem */ + +#define RACESPOILCHANCE 5 /* Chance auf rassentypische Beute */ + +typedef struct att { + int type; + union { + const char * dice; + const struct spell * sp; + } data; + int flags; +} att; + +struct param; + +extern int num_races; + +typedef struct race { + struct param * parameters; + const char *_name[4]; /* neu: name[4]völker */ + float magres; + float maxaura; /* Faktor auf Maximale Aura */ + float regaura; /* Faktor auf Regeneration */ + float recruit_multi; /* Faktor für Bauernverbrauch */ + int index; + int recruitcost; + int maintenance; + int splitsize; + int weight; + int capacity; + float speed; + float aggression; /* chance that a monster will attack */ + int hitpoints; + const char *def_damage; + char armor; + int at_default; /* Angriffsskill Unbewaffnet (default: -2)*/ + int df_default; /* Verteidigungsskill Unbewaffnet (default: -2)*/ + int at_bonus; /* Verändert den Angriffsskill (default: 0)*/ + int df_bonus; /* Verändert den Verteidigungskill (default: 0)*/ + const spell * precombatspell; + struct att attack[10]; + char bonus[MAXSKILLS]; + signed char * study_speed; /* study-speed-bonus in points/turn (0=30 Tage) */ + boolean __remove_me_nonplayer; + int flags; + int battle_flags; + int ec_flags; + race_t oldfamiliars[MAXMAGIETYP]; + + const char *(*generate_name) (const struct unit *); + const char *(*describe) (const struct unit *, const struct locale *); + void (*age)(struct unit *u); + boolean (*move_allowed)(const struct region *, const struct region *); + struct item * (*itemdrop)(const struct race *, int size); + void (*init_familiar)(struct unit *); + + const struct race * familiars[MAXMAGIETYP]; + struct attrib * attribs; + struct race * next; +} race; + +typedef struct race_list { + struct race_list * next; + const struct race * data; +} race_list; + +extern void racelist_clear(struct race_list **rl); +extern void racelist_insert(struct race_list **rl, const struct race *r); + +extern struct race_list * get_familiarraces(void); +extern struct race * races; + +extern struct race * rc_find(const char *); +extern const char * rc_name(const struct race *, int); +extern struct race * rc_add(struct race *); +extern struct race * rc_new(const char * zName); +extern int rc_specialdamage(const race *, const race *, const struct weapon_type *); + +/* Flags */ +#define RCF_PLAYERRACE (1<<0) /* can be played by a player. */ +#define RCF_KILLPEASANTS (1<<1) /* Töten Bauern. Dämonen werden nicht über dieses Flag, sondern in randenc() behandelt. */ +#define RCF_SCAREPEASANTS (1<<2) +#define RCF_CANSTEAL (1<<3) +#define RCF_MOVERANDOM (1<<4) +#define RCF_CANNOTMOVE (1<<5) +#define RCF_LEARN (1<<6) /* Lernt automatisch wenn struct faction == 0 */ +#define RCF_FLY (1<<7) /* kann fliegen */ +#define RCF_SWIM (1<<8) /* kann schwimmen */ +#define RCF_WALK (1<<9) /* kann über Land gehen */ +#define RCF_NOLEARN (1<<10) /* kann nicht normal lernen */ +#define RCF_NOTEACH (1<<11) /* kann nicht lehren */ +#define RCF_HORSE (1<<12) /* Einheit ist Pferd, sozusagen */ +#define RCF_DESERT (1<<13) /* 5% Chance, das Einheit desertiert */ +#define RCF_ILLUSIONARY (1<<14) /* (Illusion & Spell) Does not drop items. */ +#define RCF_ABSORBPEASANTS (1<<15) /* Tötet und absorbiert Bauern */ +#define RCF_NOHEAL (1<<16) /* Einheit kann nicht geheilt werden */ +#define RCF_NOWEAPONS (1<<17) /* Einheit kann keine Waffen benutzen */ +#define RCF_SHAPESHIFT (1<<18) /* Kann TARNE RASSE benutzen. */ +#define RCF_SHAPESHIFTANY (1<<19) /* Kann TARNE RASSE "string" benutzen. */ +#define RCF_UNDEAD (1<<20) /* Undead. */ +#define RCF_DRAGON (1<<21) /* Drachenart (für Zauber)*/ +#define RCF_COASTAL (1<<22) /* kann in Landregionen an der Küste sein */ +#define RCF_UNARMEDGUARD (1<<23) /* kann ohne Waffen bewachen */ +#define RCF_CANSAIL (1<<24) /* Einheit darf Schiffe betreten */ +#define RCF_INVISIBLE (1<<25) /* not visible in any report */ +#define RCF_SHIPSPEED (1<<26) /* race gets +1 on shipspeed */ +#define RCF_STONEGOLEM (1<<27) /* race gets stonegolem properties */ +#define RCF_IRONGOLEM (1<<28) /* race gets irongolem properties */ + +/* Economic flags */ +#define GIVEITEM (1<<1) /* gibt Gegenstände weg */ +#define GIVEPERSON (1<<2) /* übergibt Personen */ +#define GIVEUNIT (1<<3) /* Einheiten an andere Partei übergeben */ +#define GETITEM (1<<4) /* nimmt Gegenstände an */ +#define ECF_REC_HORSES (1<<6) /* Rekrutiert aus Pferden */ +#define ECF_REC_ETHEREAL (1<<7) /* Rekrutiert aus dem Nichts */ +#define ECF_REC_UNLIMITED (1<<8) /* Rekrutiert ohne Limit */ + +/* Battle-Flags */ +#define BF_EQUIPMENT (1<<0) /* Kann Ausrüstung benutzen */ +#define BF_NOBLOCK (1<<1) /* Wird in die Rückzugsberechnung nicht einbezogen */ +#define BF_RES_PIERCE (1<<2) /* Halber Schaden durch PIERCE */ +#define BF_RES_CUT (1<<3) /* Halber Schaden durch CUT */ +#define BF_RES_BASH (1<<4) /* Halber Schaden durch BASH */ +#define BF_INV_NONMAGIC (1<<5) /* Immun gegen nichtmagischen Schaden */ +#define BF_CANATTACK (1<<6) /* Kann keine ATTACKIERE Befehle ausfuehren */ + +extern int unit_old_max_hp(struct unit * u); +extern const char * racename(const struct locale *lang, const struct unit *u, const race * rc); + +#define omniscient(f) (((f)->race)==new_race[RC_ILLUSION] || ((f)->race)==new_race[RC_TEMPLATE]) + +#define playerrace(rc) (fval((rc), RCF_PLAYERRACE)) +#define dragonrace(rc) ((rc) == new_race[RC_FIREDRAGON] || (rc) == new_race[RC_DRAGON] || (rc) == new_race[RC_WYRM] || (rc) == new_race[RC_BIRTHDAYDRAGON]) +#define humanoidrace(rc) (fval((rc), RCF_UNDEAD) || (rc)==new_race[RC_DRACOID] || playerrace(rc)) +#define illusionaryrace(rc) (fval(rc, RCF_ILLUSIONARY)) + +extern boolean allowed_dragon(const struct region * src, const struct region * target); + +extern boolean r_insectstalled(const struct region *r); + +extern void add_raceprefix(const char *); +extern char ** race_prefixes; + +extern void write_race_reference(const struct race * rc, struct storage * store); +extern variant read_race_reference(struct storage * store); + +extern const char * raceprefix(const struct unit *u); + +extern void give_starting_equipment(const struct equipment * eq, struct unit *u); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/region.c b/src/kernel/region.c index 7935691f5..a74dc6898 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -1,1608 +1,1608 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "region.h" - -/* kernel includes */ -#include "alliance.h" -#include "building.h" -#include "connection.h" -#include "curse.h" -#include "equipment.h" -#include "faction.h" -#include "item.h" -#include "message.h" -#include "plane.h" -#include "region.h" -#include "resources.h" -#include "save.h" -#include "ship.h" -#include "terrain.h" -#include "terrainid.h" -#include "unit.h" -#include "version.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* libc includes */ -#include -#include -#include -#include -#include - -extern int dice_rand(const char *s); - -region *regions; - -int -get_maxluxuries() -{ - static int maxluxuries = -1; - if (maxluxuries==-1) { - const luxury_type * ltype; - maxluxuries = 0; - for (ltype = luxurytypes;ltype;ltype=ltype->next) ++maxluxuries; - } - return maxluxuries; -} -const int delta_x[MAXDIRECTIONS] = -{ - -1, 0, 1, 1, 0, -1 -}; - -const int delta_y[MAXDIRECTIONS] = -{ - 1, 1, 0, -1, -1, 0 -}; - -static const direction_t back[MAXDIRECTIONS] = -{ - D_SOUTHEAST, - D_SOUTHWEST, - D_WEST, - D_NORTHWEST, - D_NORTHEAST, - D_EAST, -}; - -direction_t -dir_invert(direction_t dir) -{ - switch (dir) { - case D_PAUSE: - case D_SPECIAL: - return dir; - break; - default: - if (dir>=0 && dirlocale : 0; - if (r==NULL) { - strcpy(buf, "(null)"); - } else { - plane * pl = rplane(r); - int nx = r->x, ny = r->y; - pnormalize(&nx, &ny, pl); - adjust_coordinates(f, &nx, &ny, pl, r); - snprintf(buf, size, "%s (%d,%d)", rname(r, lang), nx, ny); - } - buf[size-1] = 0; - return buffer; -} - -const char * -regionname(const region * r, const faction * f) -{ - static char buf[NAMESIZE]; - return write_regionname(r, f, buf, sizeof(buf)); -} - -int -deathcount(const region * r) -{ - attrib * a = a_find(r->attribs, &at_deathcount); - if (!a) return 0; - return a->data.i; -} - -int -chaoscount(const region * r) -{ - attrib * a = a_find(r->attribs, &at_chaoscount); - if (!a) return 0; - return a->data.i; -} - -void -deathcounts (region * r, int fallen) -{ - attrib * a; - static const curse_type * ctype = NULL; - - if (fallen==0) return; - if (!ctype) ctype = ct_find("holyground"); - if (ctype && curse_active(get_curse(r->attribs, ctype))) return; - - a = a_find(r->attribs, &at_deathcount); - if (!a) a = a_add(&r->attribs, a_new(&at_deathcount)); - a->data.i += fallen; - - if (a->data.i<=0) a_remove(&r->attribs, a); -} - -void -chaoscounts(region * r, int fallen) -{ - attrib * a; - - if (fallen==0) return; - - a = a_find(r->attribs, &at_chaoscount); - if (!a) a = a_add(&r->attribs, a_new(&at_chaoscount)); - a->data.i += fallen; - - if (a->data.i<=0) a_remove(&r->attribs, a); -} - - - -/********************/ -/* at_direction */ -/********************/ -static void -a_initdirection(attrib *a) -{ - a->data.v = calloc(1, sizeof(spec_direction)); -} - -static void -a_freedirection(attrib *a) -{ - free(a->data.v); -} - -static int -a_agedirection(attrib *a) -{ - spec_direction *d = (spec_direction *)(a->data.v); - --d->duration; - return (d->duration>0)?AT_AGE_KEEP:AT_AGE_REMOVE; -} - -typedef struct dir_lookup { - char * name; - const char * oldname; - struct dir_lookup * next; -} dir_lookup; - -static dir_lookup * dir_name_lookup; - -void -register_special_direction(const char * name) -{ - struct locale * lang; - char * str = strdup(name); - - for (lang=locales;lang;lang=nextlocale(lang)) { - tnode * tokens = get_translations(lang, UT_SPECDIR); - const char * token = LOC(lang, name); - - if (token) { - variant var; - - var.v = str; - addtoken(tokens, token, var); - - if (lang==default_locale) { - dir_lookup * dl = malloc(sizeof(dir_lookup)); - dl->name = str; - dl->oldname = token; - dl->next = dir_name_lookup; - dir_name_lookup = dl; - } - } else { - log_error(("no translation for spec_direction '%s' in locale '%s'\n", - name, locale_name(lang))); - } - } -} - -static int -a_readdirection(attrib *a, void * owner, struct storage * store) -{ - spec_direction *d = (spec_direction *)(a->data.v); - - d->x = (short)store->r_int(store); - d->y = (short)store->r_int(store); - d->duration = store->r_int(store); - if (store->versionr_tok_buf(store, NULL, 0); - store->r_tok_buf(store, lbuf, sizeof(lbuf)); - - cstring_i(lbuf); - for (;dl;dl=dl->next) { - if (strcmp(lbuf, dl->oldname)==0) { - d->keyword=strdup(dl->name); - sprintf(lbuf, "%s_desc", d->keyword); - d->desc=strdup(dl->name); - break; - } - } - if (dl==NULL) { - log_error(("unknown spec_direction '%s'\n", lbuf)); - assert(!"not implemented"); - } - } - else { - d->desc = store->r_tok(store); - d->keyword = store->r_tok(store); - } - d->active = true; - return AT_READ_OK; -} - -static void -a_writedirection(const attrib * a, const void * owner, struct storage * store) -{ - spec_direction *d = (spec_direction *)(a->data.v); - - store->w_int(store, d->x); - store->w_int(store, d->y); - store->w_int(store, d->duration); - store->w_tok(store, d->desc); - store->w_tok(store, d->keyword); -} - -attrib_type at_direction = { - "direction", - a_initdirection, - a_freedirection, - a_agedirection, - a_writedirection, - a_readdirection -}; - -region * -find_special_direction(const region *r, const char *token, const struct locale * lang) -{ - attrib *a; - spec_direction *d; - - if (strlen(token)==0) return NULL; - for (a = a_find(r->attribs, &at_direction);a && a->type==&at_direction;a=a->next) { - d = (spec_direction *)(a->data.v); - - if (d->active) { - tnode * tokens = get_translations(lang, UT_SPECDIR); - variant var; - if (findtoken(tokens, token, &var)==E_TOK_SUCCESS) { - if (strcmp((const char *)var.v, d->keyword)==0) { - return findregion(d->x, d->y); - } - } - } - } - - return NULL; -} - -attrib * -create_special_direction(region *r, region * rt, int duration, - const char *desc, const char *keyword) - -{ - attrib *a = a_add(&r->attribs, a_new(&at_direction)); - spec_direction *d = (spec_direction *)(a->data.v); - - d->active = false; - d->x = rt->x; - d->y = rt->y; - d->duration = duration; - d->desc = strdup(desc); - d->keyword = strdup(keyword); - - return a; -} - -/* Moveblock wird zur Zeit nicht über Attribute, sondern ein Bitfeld - r->moveblock gemacht. Sollte umgestellt werden, wenn kompliziertere - Dinge gefragt werden. */ - -/********************/ -/* at_moveblock */ -/********************/ -void -a_initmoveblock(attrib *a) -{ - a->data.v = calloc(1, sizeof(moveblock)); -} - -int -a_readmoveblock(attrib *a, void * owner, struct storage * store) -{ - moveblock *m = (moveblock *)(a->data.v); - int i; - - i = store->r_int(store); - m->dir = (direction_t)i; - return AT_READ_OK; -} - -void -a_writemoveblock(const attrib * a, const void * owner, struct storage * store) -{ - moveblock *m = (moveblock *)(a->data.v); - store->w_int(store, (int)m->dir); -} - -attrib_type at_moveblock = { - "moveblock", a_initmoveblock, NULL, NULL, a_writemoveblock, a_readmoveblock -}; - -#define coor_hashkey(x, y) (unsigned int)((x<<16) + y) -#define RMAXHASH MAXREGIONS -static region * regionhash[RMAXHASH]; -static int dummy_data; -static region * dummy_ptr = (region*)&dummy_data; /* a funny hack */ - -typedef struct uidhashentry { - unsigned int uid; - region * r; -} uidhashentry; -static uidhashentry uidhash[MAXREGIONS]; - -struct region * -findregionbyid(unsigned int uid) -{ - int key = uid % MAXREGIONS; - while (uidhash[key].uid!=0 && uidhash[key].uid!=uid) ++key; - return uidhash[key].r; -} - -#define DELMARKER dummy_ptr - -static void -unhash_uid(region * r) -{ - int key = r->uid % MAXREGIONS; - assert(r->uid); - while (uidhash[key].uid!=0 && uidhash[key].uid!=r->uid) ++key; - assert(uidhash[key].r==r); - uidhash[key].r = NULL; -} - -static void -hash_uid(region * r) -{ - unsigned int uid = r->uid; - for (;;) { - if (uid!=0) { - int key = uid % MAXREGIONS; - while (uidhash[key].uid!=0 && uidhash[key].uid!=uid) ++key; - if (uidhash[key].uid==0) { - uidhash[key].uid = uid; - uidhash[key].r = r; - break; - } - assert(uidhash[key].r!=r || !"duplicate registration"); - } - r->uid = uid = rng_int(); - } -} - -#define HASH_STATISTICS 1 -#if HASH_STATISTICS -static int hash_requests; -static int hash_misses; -#endif - -boolean pnormalize(int * x, int * y, const plane * pl) -{ - if (pl) { - if (x) { - int width = pl->maxx - pl->minx + 1; - int nx = *x - pl->minx; - nx = (nx>0)?nx:(width-(-nx)%width); - *x = nx % width+ pl->minx; - } - if (y) { - int height = pl->maxy - pl->miny + 1; - int ny = *y - pl->miny; - ny = (ny>0)?ny:(height-(-ny)%height); - *y = ny % height + pl->miny; - } - } - return false; /* TBD */ -} - -static region * -rfindhash(int x, int y) -{ - unsigned int rid; - - rid = coor_hashkey(x, y); -#if HASH_STATISTICS - ++hash_requests; -#endif - if (rid>=0) { - int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); - while (regionhash[key]!=NULL && (regionhash[key]==DELMARKER || regionhash[key]->x!=x || regionhash[key]->y!=y)) { - key = (key + gk) % RMAXHASH; -#if HASH_STATISTICS - ++hash_misses; -#endif - } - return regionhash[key]; - } - return NULL; -} - -void -rhash(region * r) -{ - unsigned int rid = coor_hashkey(r->x, r->y); - int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); - while (regionhash[key]!=NULL && regionhash[key]!=DELMARKER && regionhash[key]!=r) { - key = (key + gk) % RMAXHASH; - } - assert(regionhash[key]!=r || !"trying to add the same region twice"); - regionhash[key] = r; -} - -void -runhash(region * r) -{ - unsigned int rid = coor_hashkey(r->x, r->y); - int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); - -#ifdef FAST_CONNECT - int d, di; - for (d=0,di=MAXDIRECTIONS/2;d!=MAXDIRECTIONS;++d,++di) { - region * rc = r->connect[d]; - if (rc!=NULL) { - if (di>=MAXDIRECTIONS) di-=MAXDIRECTIONS; - rc->connect[di] = NULL; - r->connect[d] = NULL; - } - } -#endif - while (regionhash[key]!=NULL && regionhash[key]!=r) { - key = (key + gk) % RMAXHASH; - } - assert(regionhash[key]==r || !"trying to remove a unit that is not hashed"); - regionhash[key] = DELMARKER; -} - -region * -r_connect(const region * r, direction_t dir) -{ - region * result; - int x, y; -#ifdef FAST_CONNECT - region * rmodify = (region*)r; - assert (dir>=0 && dirconnect[dir]) return r->connect[dir]; -#endif - assert(dirx + delta_x[dir]; - y = r->y + delta_y[dir]; - pnormalize(&x, &y, rplane(r)); - result = rfindhash(x, y); -#ifdef FAST_CONNECT - if (result) { - rmodify->connect[dir] = result; - result->connect[back[dir]] = rmodify; - } -#endif - return result; -} - -region * -findregion(int x, int y) -{ - return rfindhash(x, y); -} - -/* Contributed by Hubert Mackenberg. Thanks. - * x und y Abstand zwischen x1 und x2 berechnen - */ -static int -koor_distance_orig(int x1, int y1, int x2, int y2) -{ - int dx = x1 - x2; - int dy = y1 - y2; - - /* Bei negativem dy am Ursprung spiegeln, das veraendert - * den Abstand nicht - */ - if ( dy < 0 ) { - dy = -dy; - dx = -dx; - } - - /* - * dy ist jetzt >=0, fuer dx sind 3 Faelle zu untescheiden - */ - if ( dx >= 0 ) { - int result = dx + dy; - return result; - } - else if (-dx >= dy) { - int result = -dx; - return result; - } - else { - return dy; - } -} - -static int -koor_distance_wrap_xy(int x1, int y1, int x2, int y2, int width, int height) -{ - int dx = x1 - x2; - int dy = y1 - y2; - int result, dist; - int mindist = MIN(width, height) >> 1; - - /* Bei negativem dy am Ursprung spiegeln, das veraendert - * den Abstand nicht - */ - if ( dy < 0 ) { - dy = -dy; - dx = -dx; - } - if (dx<0) { - dx = width + dx; - } - /* dx,dy is now pointing northeast */ - result = dx + dy; - if (result<=mindist) return result; - - dist = (width-dx) + (height-dy); /* southwest */ - if (dist>=0 && dist=0 && dist=0 && distx, r1->y, r2->x, r2->y); -} - -static direction_t -koor_reldirection(int ax, int ay, int bx, int by, const struct plane * pl) -{ - direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - int x = ax + delta_x[dir]; - int y = ay + delta_y[dir]; - pnormalize(&x, &y, pl); - if (bx == x && by == y) return dir; - } - return NODIRECTION; -} - -spec_direction * -special_direction(const region * from, const region * to) -{ - const attrib *a = a_findc(from->attribs, &at_direction); - - while (a!=NULL && a->type==&at_direction) { - spec_direction * sd = (spec_direction *)a->data.v; - if (sd->x==to->x && sd->y==to->y) return sd; - a = a->next; - } - return NULL; -} - -direction_t -reldirection(const region * from, const region * to) -{ - plane * pl = rplane(from); - if (pl == rplane(to)) { - direction_t dir = koor_reldirection(from->x, from->y, to->x, to->y, pl); - - if (dir==NODIRECTION) { - spec_direction *sd = special_direction(from, to); - if (sd!=NULL && sd->active) return D_SPECIAL; - } - return dir; - } - return NODIRECTION; -} - -void -free_regionlist(region_list *rl) -{ - while (rl) { - region_list * rl2 = rl->next; - free(rl); - rl = rl2; - } -} - -void -add_regionlist(region_list **rl, region *r) -{ - region_list *rl2 = (region_list*)malloc(sizeof(region_list)); - - rl2->data = r; - rl2->next = *rl; - - *rl = rl2; -} - -/********************/ -/* at_horseluck */ -/********************/ -attrib_type at_horseluck = { - "horseluck", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - NO_WRITE, - NO_READ, - ATF_UNIQUE -}; - - -/**********************/ -/* at_peasantluck */ -/**********************/ -attrib_type at_peasantluck = { - "peasantluck", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - NO_WRITE, - NO_READ, - ATF_UNIQUE -}; - -/*********************/ -/* at_chaoscount */ -/*********************/ -attrib_type at_chaoscount = { - "chaoscount", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - a_writeint, - a_readint, - ATF_UNIQUE -}; - -/*********************/ -/* at_deathcount */ -/*********************/ -attrib_type at_deathcount = { - "deathcount", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - a_writeint, - a_readint, - ATF_UNIQUE -}; - -/*********************/ -/* at_woodcount */ -/*********************/ -attrib_type at_woodcount = { - "woodcount", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - NO_WRITE, - a_readint, - ATF_UNIQUE -}; - -/*********************/ -/* at_travelunit */ -/*********************/ -attrib_type at_travelunit = { - "travelunit", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - NO_WRITE, - NO_READ -}; - -void -rsetroad(region * r, direction_t d, short val) -{ - connection * b; - region * r2 = rconnect(r, d); - - if (!r2) return; - b = get_borders(r, r2); - while (b && b->type!=&bt_road) b = b->next; - if (!b) b = new_border(&bt_road, r, r2); - if (r==b->from) b->data.sa[0] = val; - else b->data.sa[1] = val; -} - -short -rroad(const region * r, direction_t d) -{ - int rval; - connection * b; - region * r2 = rconnect(r, d); - - if (!r2) return 0; - b = get_borders(r, r2); - while (b && b->type!=&bt_road) b = b->next; - if (!b) return 0; - rval = b->data.i; - if (r==b->from) return b->data.sa[0]; - return b->data.sa[1]; -} - -boolean -r_isforest(const region * r) -{ - if (fval(r->terrain, FOREST_REGION)) { - /* needs to be covered with at leas 48% trees */ - int mincover = (int)(r->terrain->size * 0.48); - int trees = rtrees(r, 2) + rtrees(r, 1); - return (trees*TREESIZE >= mincover); - } - return false; -} - -int -is_coastregion(region *r) -{ - direction_t i; - int res = 0; - - for(i=0;iterrain, SEA_REGION)) res++; - } - return res; -} - -int -rpeasants(const region * r) -{ - return ((r)->land?(r)->land->peasants:0); -} - -void -rsetpeasants(region * r, int value) -{ - ((r)->land?((r)->land->peasants=(value)):(assert((value)>=0), (value)),0); -} - -int -rmoney(const region * r) -{ - return ((r)->land?(r)->land->money:0); -} - -void -rsethorses(const region *r, int value) -{ - assert(value >= 0); - if(r->land) - r->land->horses = value; -} - -int -rhorses(const region *r) -{ - return r->land?r->land->horses:0; -} - -void -rsetmoney(region * r, int value) -{ - ((r)->land?((r)->land->money=(value)):(assert((value)>=0), (value)),0); -} - -void -r_setdemand(region * r, const luxury_type * ltype, int value) -{ - struct demand * d, ** dp = &r->land->demands; - - if (ltype==NULL) return; - - while (*dp && (*dp)->type != ltype) dp = &(*dp)->next; - d = *dp; - if (!d) { - d = *dp = malloc(sizeof(struct demand)); - d->next = NULL; - d->type = ltype; - } - d->value = value; -} - -const item_type * -r_luxury(region * r) -{ - struct demand * dmd; - if (r->land) { - if (!r->land->demands) { - fix_demand(r); - } - for (dmd=r->land->demands;dmd;dmd=dmd->next) { - if (dmd->value==0) return dmd->type->itype; - } - } - return NULL; -} - -int -r_demand(const region * r, const luxury_type * ltype) -{ - struct demand * d = r->land->demands; - while (d && d->type != ltype) d = d->next; - if (!d) return -1; - return d->value; -} - -const char * -rname(const region * r, const struct locale * lang) -{ - if (r->land) { - return r->land->name; - } - return LOC(lang, terrain_name(r)); -} - -int -rtrees(const region *r, int ageclass) -{ - return ((r)->land?(r)->land->trees[ageclass]:0); -} - -int -rsettrees(const region *r, int ageclass, int value) -{ - if (!r->land) assert(value==0); - else { - assert(value>=0); - return r->land->trees[ageclass]=value; - } - return 0; -} - -static region *last; - -static unsigned int max_index = 0; - -region * -new_region(int x, int y, struct plane * pl, unsigned int uid) -{ - region *r; - - pnormalize(&x, &y, pl); - r = rfindhash(x, y); - - if (r) { - log_error(("duplicate region discovered: %s(%d,%d)\n", regionname(r, NULL), x, y)); - if (r->units) - log_error(("duplicate region contains units\n")); - return r; - } - r = calloc(1, sizeof(region)); - r->x = x; - r->y = y; - r->uid = uid; - r->age = 1; - r->_plane = pl; - rhash(r); - hash_uid(r); - if (last) - addlist(&last, r); - else - addlist(®ions, r); - last = r; - assert(r->next==NULL); - r->index = ++max_index; - return r; -} - -static region * deleted_regions; - -void -remove_region(region ** rlist, region * r) -{ - - while (r->units) { - unit * u = r->units; - i_freeall(&u->items); - remove_unit(&r->units, u); - } - - runhash(r); - unhash_uid(r); - while (*rlist && *rlist!=r) rlist=&(*rlist)->next; - assert(*rlist==r); - *rlist = r->next; - r->next = deleted_regions; - deleted_regions = r; -} - -static void -freeland(land_region * lr) -{ - while (lr->demands) { - struct demand * d = lr->demands; - lr->demands = d->next; - free(d); - } - if (lr->name) free(lr->name); - free(lr); -} - -void -region_setresource(region * r, const resource_type * rtype, int value) -{ - rawmaterial * rm = r->resources; - while (rm) { - if (rm->type->rtype==rtype) { - rm->amount = value; - break; - } - rm=rm->next; - } - if (!rm) { - if (rtype==rt_find("money")) rsetmoney(r, value); - else if (rtype==rt_find("peasant")) rsetpeasants(r, value); - else if (rtype==rt_find("horse")) rsethorses(r, value); - } -} - -int -region_getresource(const region * r, const resource_type * rtype) -{ - const rawmaterial * rm; - for (rm=r->resources;rm;rm=rm->next) { - if (rm->type->rtype==rtype) { - return rm->amount; - } - } - if (rtype==rt_find("money")) return rmoney(r); - if (rtype==rt_find("horse")) return rhorses(r); - if (rtype==rt_find("peasant")) return rpeasants(r); - return 0; -} - -void -free_region(region * r) -{ - if (last == r) last = NULL; - free(r->display); - if (r->land) freeland(r->land); - - if (r->msgs) { - free_messagelist(r->msgs); - r->msgs = 0; - } - - while (r->individual_messages) { - struct individual_message * msg = r->individual_messages; - r->individual_messages = msg->next; - if (msg->msgs) free_messagelist(msg->msgs); - free(msg); - } - - while (r->attribs) a_remove (&r->attribs, r->attribs); - while (r->resources) { - rawmaterial * res = r->resources; - r->resources = res->next; - free(res); - } - - while (r->donations) { - donation * don = r->donations; - r->donations = don->next; - free(don); - } - - while (r->units) { - unit * u = r->units; - r->units = u->next; - uunhash(u); - free_unit(u); - free(u); - } - - while (r->buildings) { - building * b = r->buildings; - assert(b->region==r); - r->buildings = b->next; - bunhash(b); /* must be done here, because remove_building does it, and wasn't called */ - free_building(b); - } - - while (r->ships) { - ship * s = r->ships; - assert(s->region==r); - r->ships = s->next; - sunhash(s); - free_ship(s); - } - - free(r); -} - -void -free_regions(void) -{ - memset(uidhash, 0, sizeof(uidhash)); - while (deleted_regions) { - region * r = deleted_regions; - deleted_regions = r->next; - free_region(r); - } - while (regions) { - region * r = regions; - regions = r->next; - runhash(r); - free_region(r); - } - max_index = 0; - last = NULL; -} - -/** creates a name for a region - * TODO: Make vowels XML-configurable and allow non-ascii characters again. - * - that will probably require a wchar_t * string to pick from. - */ -static char * -makename(void) -{ - int s, v, k, e, p = 0, x = 0; - size_t nk, ne, nv, ns; - static char name[16]; - const char *kons = "bcdfghklmnprstvwz", - *start = "bcdgtskpvfr", - *end = "nlrdst", - *vowels = "aaaaaaaaaaaeeeeeeeeeeeeiiiiiiiiiiioooooooooooouuuuuuuuuuyy"; - - /* const char * vowels_latin1 = "aaaaaaaaaàâeeeeeeeeeéèêiiiiiiiiiíîoooooooooóòôuuuuuuuuuúyy"; */ - - nk = strlen(kons); - ne = strlen(end); - nv = strlen(vowels); - ns = strlen(start); - - for (s = rng_int() % 3 + 2; s > 0; s--) { - if (x > 0) { - k = rng_int() % (int)nk; - name[p] = kons[k]; - p++; - } else { - k = rng_int() % (int)ns; - name[p] = start[k]; - p++; - } - v = rng_int() % (int)nv; - name[p] = vowels[v]; - p++; - if (rng_int() % 3 == 2 || s == 1) { - e = rng_int() % (int)ne; - name[p] = end[e]; - p++; - x = 1; - } else - x = 0; - } - name[p] = '\0'; - name[0] = (char) toupper(name[0]); - return name; -} - -void -setluxuries(region * r, const luxury_type * sale) -{ - const luxury_type * ltype; - - assert(r->land); - - if(r->land->demands) freelist(r->land->demands); - - for (ltype=luxurytypes; ltype; ltype=ltype->next) { - struct demand * dmd = malloc(sizeof(struct demand)); - dmd->type = ltype; - if (ltype!=sale) dmd->value = 1 + rng_int() % 5; - else dmd->value = 0; - dmd->next = r->land->demands; - r->land->demands = dmd; - } -} - -void -terraform_region(region * r, const terrain_type * terrain) -{ - /* Resourcen, die nicht mehr vorkommen können, löschen */ - const terrain_type * oldterrain = r->terrain; - rawmaterial **lrm = &r->resources; - - assert(terrain); - - while (*lrm) { - rawmaterial *rm = *lrm; - const resource_type * rtype = NULL; - - if (terrain->production!=NULL) { - int i; - for (i=0;terrain->production[i].type;++i) { - if (rm->type->rtype == terrain->production[i].type) { - rtype = rm->type->rtype; - break; - } - } - } - if (rtype==NULL) { - *lrm = rm->next; - free(rm); - } else { - lrm = &rm->next; - } - } - - r->terrain = terrain; - terraform_resources(r); - - if (!fval(terrain, LAND_REGION)) { - region_setinfo(r, NULL); - if (r->land!=NULL) { - i_freeall(&r->land->items); - freeland(r->land); - r->land = NULL; - } - rsettrees(r, 0, 0); - rsettrees(r, 1, 0); - rsettrees(r, 2, 0); - rsethorses(r, 0); - rsetpeasants(r, 0); - rsetmoney(r, 0); - freset(r, RF_ENCOUNTER); - freset(r, RF_MALLORN); - /* Beschreibung und Namen löschen */ - return; - } - - if (r->land) { - i_freeall(&r->land->items); - } else { - static struct surround { - struct surround * next; - const luxury_type * type; - int value; - } *trash =NULL, *nb = NULL; - const luxury_type * ltype = NULL; - direction_t d; - int mnr = 0; - - r->land = calloc(1, sizeof(land_region)); - r->land->ownership = NULL; - region_set_morale(r, MORALE_DEFAULT, -1); - region_setname(r, makename()); - for (d=0;d!=MAXDIRECTIONS;++d) { - region * nr = rconnect(r, d); - if (nr && nr->land) { - struct demand * sale = r->land->demands; - while (sale && sale->value!=0) sale=sale->next; - if (sale) { - struct surround * sr = nb; - while (sr && sr->type!=sale->type) sr=sr->next; - if (!sr) { - if (trash) { - sr = trash; - trash = trash->next; - } else { - sr = calloc(1, sizeof(struct surround)); - } - sr->next = nb; - sr->type = sale->type; - sr->value = 1; - nb = sr; - } else sr->value++; - ++mnr; - } - } - } - if (!nb) { - int i = get_maxluxuries(); - if (i>0) { - i = rng_int() % i; - ltype = luxurytypes; - while (i--) ltype=ltype->next; - } - } else { - int i = rng_int() % mnr; - struct surround * srd = nb; - while (i>srd->value) { - i-=srd->value; - srd=srd->next; - } - if (srd->type) setluxuries(r, srd->type); - while (srd->next!=NULL) srd=srd->next; - srd->next=trash; - trash = nb; - nb = NULL; - } - } - - if (fval(terrain, LAND_REGION)) { - const item_type * itype = NULL; - char equip_hash[64]; - - /* TODO: put the equipment in struct terrain, faster */ - sprintf(equip_hash, "terrain_%s", terrain->_name); - equip_items(&r->land->items, get_equipment(equip_hash)); - - if (r->terrain->herbs) { - int len=0; - while (r->terrain->herbs[len]) ++len; - if (len) itype = r->terrain->herbs[rng_int()%len]; - } - if (itype!=NULL) { - rsetherbtype(r, itype); - rsetherbs(r, (short)(50+rng_int()%31)); - } - else { - rsetherbtype(r, NULL); - } - if (oldterrain==NULL || !fval(oldterrain, LAND_REGION)) { - if (rng_int() % 100 < 3) fset(r, RF_MALLORN); - else freset(r, RF_MALLORN); - if (rng_int() % 100 < ENCCHANCE) { - fset(r, RF_ENCOUNTER); - } - } - } - - if (oldterrain==NULL || terrain->size!=oldterrain->size) { - if (terrain==newterrain(T_PLAIN)) { - rsethorses(r, rng_int() % (terrain->size / 50)); - if(rng_int()%100 < 40) { - rsettrees(r, 2, terrain->size * (30+rng_int()%40)/1000); - } - } else if (chance(0.2)) { - rsettrees(r, 2, terrain->size * (30 + rng_int() % 40) / 1000); - } else { - rsettrees(r, 2, 0); - } - rsettrees(r, 1, rtrees(r, 2)/4); - rsettrees(r, 0, rtrees(r, 2)/8); - - if (!fval(r, RF_CHAOTIC)) { - int peasants; - peasants = (maxworkingpeasants(r) * (20+dice_rand("6d10")))/100; - rsetpeasants(r, MAX(100, peasants)); - rsetmoney(r, rpeasants(r) * ((wage(r, NULL, NULL, INT_MAX)+1) + rng_int() % 5)); - } - } -} - -/** ENNO: - * ich denke, das das hier nicht sein sollte. - * statt dessen sollte ein attribut an der region sein, das das erledigt, - * egal ob durch den spell oder anderes angelegt. - **/ -#include "curse.h" -int -production(const region *r) -{ - /* muß rterrain(r) sein, nicht rterrain() wegen rekursion */ - int p = r->terrain->size / MAXPEASANTS_PER_AREA; - if (curse_active(get_curse(r->attribs, ct_find("drought")))) p /= 2; - - return p; -} - -int -resolve_region_coor(variant id, void * address) { - region * r = findregion(id.sa[0], id.sa[1]); - if (r) { - *(region**)address = r; - return 0; - } - *(region**)address = NULL; - return -1; -} - -int -resolve_region_id(variant id, void * address) -{ - region * r = NULL; - if (id.i!=0) { - r = findregionbyid((unsigned int)id.i); - if (r==NULL) { - *(region**)address = NULL; - return -1; - } - } - *(region**)address = r; - return 0; -} - -variant -read_region_reference(struct storage * store) -{ - variant result; - if (store->versionr_int(store); - result.sa[1] = (short)store->r_int(store); - } else { - result.i = store->r_int(store); - } - return result; -} - -void -write_region_reference(const region * r, struct storage * store) -{ - if (r) { - store->w_int(store, r->uid); - } else { - store->w_int(store, 0); - } -} - -struct message_list * -r_getmessages(const struct region * r, const struct faction * viewer) -{ - struct individual_message * imsg = r->individual_messages; - while (imsg && (imsg)->viewer!=viewer) imsg = imsg->next; - if (imsg) return imsg->msgs; - return NULL; -} - -struct message * -r_addmessage(struct region * r, const struct faction * viewer, struct message * msg) -{ - assert(r); - if (viewer) { - struct individual_message * imsg; - imsg = r->individual_messages; - while (imsg && imsg->viewer!=viewer) imsg = imsg->next; - if (imsg==NULL) { - imsg = malloc(sizeof(struct individual_message)); - imsg->next = r->individual_messages; - imsg->msgs = NULL; - r->individual_messages = imsg; - imsg->viewer = viewer; - } - return add_message(&imsg->msgs, msg); - } - return add_message(&r->msgs, msg); -} - -struct faction * -region_get_owner(const struct region * r) -{ - assert(rule_region_owners()); - if (r->land && r->land->ownership) { - return r->land->ownership->owner; - } - return NULL; -} - -struct alliance * -region_get_alliance(const struct region * r) -{ - assert(rule_region_owners()); - if (r->land && r->land->ownership) { - region_owner * own = r->land->ownership; - return own->owner?own->owner->alliance:own->alliance; - } - return NULL; -} - -void -region_set_owner(struct region * r, struct faction * owner, int turn) -{ - assert(rule_region_owners()); - if (r->land) { - if (!r->land->ownership) { - r->land->ownership = malloc(sizeof(region_owner)); - assert(region_get_morale(r)==MORALE_DEFAULT); - r->land->ownership->owner = NULL; - r->land->ownership->alliance = NULL; - r->land->ownership->flags = 0; - } - r->land->ownership->since_turn = turn; - r->land->ownership->morale_turn = turn; - assert(r->land->ownership->owner != owner); - r->land->ownership->owner = owner; - if (owner) { - r->land->ownership->alliance = owner->alliance; - } - } -} - - -faction * update_owners(region * r) -{ - faction * f = NULL; - assert(rule_region_owners()); - if (r->land) { - building * bowner = largestbuilding(r, &cmp_current_owner, false); - building * blargest = largestbuilding(r, &cmp_taxes, false); - if (blargest) { - if (!bowner || bowner->sizesize) { - /* region owners update? */ - unit * u = building_owner(blargest); - f = region_get_owner(r); - if (u==NULL) { - if (f) { - region_set_owner(r, NULL, turn); - r->land->ownership->flags |= OWNER_MOURNING; - f = NULL; - } - } else if (u->faction!=f) { - if (!r->land->ownership) { - /* there has never been a prior owner */ - region_set_morale(r, MORALE_DEFAULT, turn); - } else { - alliance * al = region_get_alliance(r); - if (al && u->faction->alliance==al) { - int morale = MAX(0, r->land->morale-MORALE_TRANSFER); - region_set_morale(r, morale, turn); - } else { - region_set_morale(r, MORALE_TAKEOVER, turn); - if (f) { - r->land->ownership->flags |= OWNER_MOURNING; - } - } - } - region_set_owner(r, u->faction, turn); - f = u->faction; - } - } - } else if (r->land->ownership && r->land->ownership->owner) { - r->land->ownership->flags |= OWNER_MOURNING; - region_set_owner(r, NULL, turn); - f = NULL; - } - } - return f; -} - -void -region_setinfo(struct region * r, const char * info) -{ - free(r->display); - r->display = info?strdup(info):0; -} - -const char * -region_getinfo(const region * r) { - return r->display?r->display:""; -} - -void -region_setname(struct region * r, const char * name) -{ - if (r->land) { - free(r->land->name); - r->land->name = name?strdup(name):0; - } -} - -const char * -region_getname(const region * r) { - if (r->land && r->land->name) { - return r->land->name; - } - return ""; -} - -int region_get_morale(const region * r) -{ - if (r->land) { - assert(r->land->morale>=0 && r->land->morale<=MORALE_MAX); - return r->land->morale; - } - return -1; -} - -void region_set_morale(region * r, int morale, int turn) -{ - if (r->land) { - r->land->morale = (short)morale; - if (turn>=0 && r->land->ownership) { - r->land->ownership->morale_turn = turn; - } - assert(r->land->morale>=0 && r->land->morale<=MORALE_MAX); - } -} - -void get_neighbours(const region * r, region ** list) -{ - direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - list[dir] = rconnect(r, dir); - } -} - -int owner_change(const region * r) -{ - if (r->land && r->land->ownership) { - return r->land->ownership->since_turn; - } - return -1; -} - -boolean is_mourning(const region * r, int in_turn) -{ - int change = owner_change(r); - return (change==in_turn-1 && (r->land->ownership->flags&OWNER_MOURNING)); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "region.h" + +/* kernel includes */ +#include "alliance.h" +#include "building.h" +#include "connection.h" +#include "curse.h" +#include "equipment.h" +#include "faction.h" +#include "item.h" +#include "message.h" +#include "plane.h" +#include "region.h" +#include "resources.h" +#include "save.h" +#include "ship.h" +#include "terrain.h" +#include "terrainid.h" +#include "unit.h" +#include "version.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +extern int dice_rand(const char *s); + +region *regions; + +int +get_maxluxuries() +{ + static int maxluxuries = -1; + if (maxluxuries==-1) { + const luxury_type * ltype; + maxluxuries = 0; + for (ltype = luxurytypes;ltype;ltype=ltype->next) ++maxluxuries; + } + return maxluxuries; +} +const int delta_x[MAXDIRECTIONS] = +{ + -1, 0, 1, 1, 0, -1 +}; + +const int delta_y[MAXDIRECTIONS] = +{ + 1, 1, 0, -1, -1, 0 +}; + +static const direction_t back[MAXDIRECTIONS] = +{ + D_SOUTHEAST, + D_SOUTHWEST, + D_WEST, + D_NORTHWEST, + D_NORTHEAST, + D_EAST, +}; + +direction_t +dir_invert(direction_t dir) +{ + switch (dir) { + case D_PAUSE: + case D_SPECIAL: + return dir; + break; + default: + if (dir>=0 && dirlocale : 0; + if (r==NULL) { + strcpy(buf, "(null)"); + } else { + plane * pl = rplane(r); + int nx = r->x, ny = r->y; + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl, r); + snprintf(buf, size, "%s (%d,%d)", rname(r, lang), nx, ny); + } + buf[size-1] = 0; + return buffer; +} + +const char * +regionname(const region * r, const faction * f) +{ + static char buf[NAMESIZE]; + return write_regionname(r, f, buf, sizeof(buf)); +} + +int +deathcount(const region * r) +{ + attrib * a = a_find(r->attribs, &at_deathcount); + if (!a) return 0; + return a->data.i; +} + +int +chaoscount(const region * r) +{ + attrib * a = a_find(r->attribs, &at_chaoscount); + if (!a) return 0; + return a->data.i; +} + +void +deathcounts (region * r, int fallen) +{ + attrib * a; + static const curse_type * ctype = NULL; + + if (fallen==0) return; + if (!ctype) ctype = ct_find("holyground"); + if (ctype && curse_active(get_curse(r->attribs, ctype))) return; + + a = a_find(r->attribs, &at_deathcount); + if (!a) a = a_add(&r->attribs, a_new(&at_deathcount)); + a->data.i += fallen; + + if (a->data.i<=0) a_remove(&r->attribs, a); +} + +void +chaoscounts(region * r, int fallen) +{ + attrib * a; + + if (fallen==0) return; + + a = a_find(r->attribs, &at_chaoscount); + if (!a) a = a_add(&r->attribs, a_new(&at_chaoscount)); + a->data.i += fallen; + + if (a->data.i<=0) a_remove(&r->attribs, a); +} + + + +/********************/ +/* at_direction */ +/********************/ +static void +a_initdirection(attrib *a) +{ + a->data.v = calloc(1, sizeof(spec_direction)); +} + +static void +a_freedirection(attrib *a) +{ + free(a->data.v); +} + +static int +a_agedirection(attrib *a) +{ + spec_direction *d = (spec_direction *)(a->data.v); + --d->duration; + return (d->duration>0)?AT_AGE_KEEP:AT_AGE_REMOVE; +} + +typedef struct dir_lookup { + char * name; + const char * oldname; + struct dir_lookup * next; +} dir_lookup; + +static dir_lookup * dir_name_lookup; + +void +register_special_direction(const char * name) +{ + struct locale * lang; + char * str = strdup(name); + + for (lang=locales;lang;lang=nextlocale(lang)) { + tnode * tokens = get_translations(lang, UT_SPECDIR); + const char * token = LOC(lang, name); + + if (token) { + variant var; + + var.v = str; + addtoken(tokens, token, var); + + if (lang==default_locale) { + dir_lookup * dl = malloc(sizeof(dir_lookup)); + dl->name = str; + dl->oldname = token; + dl->next = dir_name_lookup; + dir_name_lookup = dl; + } + } else { + log_error(("no translation for spec_direction '%s' in locale '%s'\n", + name, locale_name(lang))); + } + } +} + +static int +a_readdirection(attrib *a, void * owner, struct storage * store) +{ + spec_direction *d = (spec_direction *)(a->data.v); + + d->x = (short)store->r_int(store); + d->y = (short)store->r_int(store); + d->duration = store->r_int(store); + if (store->versionr_tok_buf(store, NULL, 0); + store->r_tok_buf(store, lbuf, sizeof(lbuf)); + + cstring_i(lbuf); + for (;dl;dl=dl->next) { + if (strcmp(lbuf, dl->oldname)==0) { + d->keyword=strdup(dl->name); + sprintf(lbuf, "%s_desc", d->keyword); + d->desc=strdup(dl->name); + break; + } + } + if (dl==NULL) { + log_error(("unknown spec_direction '%s'\n", lbuf)); + assert(!"not implemented"); + } + } + else { + d->desc = store->r_tok(store); + d->keyword = store->r_tok(store); + } + d->active = true; + return AT_READ_OK; +} + +static void +a_writedirection(const attrib * a, const void * owner, struct storage * store) +{ + spec_direction *d = (spec_direction *)(a->data.v); + + store->w_int(store, d->x); + store->w_int(store, d->y); + store->w_int(store, d->duration); + store->w_tok(store, d->desc); + store->w_tok(store, d->keyword); +} + +attrib_type at_direction = { + "direction", + a_initdirection, + a_freedirection, + a_agedirection, + a_writedirection, + a_readdirection +}; + +region * +find_special_direction(const region *r, const char *token, const struct locale * lang) +{ + attrib *a; + spec_direction *d; + + if (strlen(token)==0) return NULL; + for (a = a_find(r->attribs, &at_direction);a && a->type==&at_direction;a=a->next) { + d = (spec_direction *)(a->data.v); + + if (d->active) { + tnode * tokens = get_translations(lang, UT_SPECDIR); + variant var; + if (findtoken(tokens, token, &var)==E_TOK_SUCCESS) { + if (strcmp((const char *)var.v, d->keyword)==0) { + return findregion(d->x, d->y); + } + } + } + } + + return NULL; +} + +attrib * +create_special_direction(region *r, region * rt, int duration, + const char *desc, const char *keyword) + +{ + attrib *a = a_add(&r->attribs, a_new(&at_direction)); + spec_direction *d = (spec_direction *)(a->data.v); + + d->active = false; + d->x = rt->x; + d->y = rt->y; + d->duration = duration; + d->desc = strdup(desc); + d->keyword = strdup(keyword); + + return a; +} + +/* Moveblock wird zur Zeit nicht über Attribute, sondern ein Bitfeld + r->moveblock gemacht. Sollte umgestellt werden, wenn kompliziertere + Dinge gefragt werden. */ + +/********************/ +/* at_moveblock */ +/********************/ +void +a_initmoveblock(attrib *a) +{ + a->data.v = calloc(1, sizeof(moveblock)); +} + +int +a_readmoveblock(attrib *a, void * owner, struct storage * store) +{ + moveblock *m = (moveblock *)(a->data.v); + int i; + + i = store->r_int(store); + m->dir = (direction_t)i; + return AT_READ_OK; +} + +void +a_writemoveblock(const attrib * a, const void * owner, struct storage * store) +{ + moveblock *m = (moveblock *)(a->data.v); + store->w_int(store, (int)m->dir); +} + +attrib_type at_moveblock = { + "moveblock", a_initmoveblock, NULL, NULL, a_writemoveblock, a_readmoveblock +}; + +#define coor_hashkey(x, y) (unsigned int)((x<<16) + y) +#define RMAXHASH MAXREGIONS +static region * regionhash[RMAXHASH]; +static int dummy_data; +static region * dummy_ptr = (region*)&dummy_data; /* a funny hack */ + +typedef struct uidhashentry { + unsigned int uid; + region * r; +} uidhashentry; +static uidhashentry uidhash[MAXREGIONS]; + +struct region * +findregionbyid(unsigned int uid) +{ + int key = uid % MAXREGIONS; + while (uidhash[key].uid!=0 && uidhash[key].uid!=uid) ++key; + return uidhash[key].r; +} + +#define DELMARKER dummy_ptr + +static void +unhash_uid(region * r) +{ + int key = r->uid % MAXREGIONS; + assert(r->uid); + while (uidhash[key].uid!=0 && uidhash[key].uid!=r->uid) ++key; + assert(uidhash[key].r==r); + uidhash[key].r = NULL; +} + +static void +hash_uid(region * r) +{ + unsigned int uid = r->uid; + for (;;) { + if (uid!=0) { + int key = uid % MAXREGIONS; + while (uidhash[key].uid!=0 && uidhash[key].uid!=uid) ++key; + if (uidhash[key].uid==0) { + uidhash[key].uid = uid; + uidhash[key].r = r; + break; + } + assert(uidhash[key].r!=r || !"duplicate registration"); + } + r->uid = uid = rng_int(); + } +} + +#define HASH_STATISTICS 1 +#if HASH_STATISTICS +static int hash_requests; +static int hash_misses; +#endif + +boolean pnormalize(int * x, int * y, const plane * pl) +{ + if (pl) { + if (x) { + int width = pl->maxx - pl->minx + 1; + int nx = *x - pl->minx; + nx = (nx>0)?nx:(width-(-nx)%width); + *x = nx % width+ pl->minx; + } + if (y) { + int height = pl->maxy - pl->miny + 1; + int ny = *y - pl->miny; + ny = (ny>0)?ny:(height-(-ny)%height); + *y = ny % height + pl->miny; + } + } + return false; /* TBD */ +} + +static region * +rfindhash(int x, int y) +{ + unsigned int rid; + + rid = coor_hashkey(x, y); +#if HASH_STATISTICS + ++hash_requests; +#endif + if (rid>=0) { + int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); + while (regionhash[key]!=NULL && (regionhash[key]==DELMARKER || regionhash[key]->x!=x || regionhash[key]->y!=y)) { + key = (key + gk) % RMAXHASH; +#if HASH_STATISTICS + ++hash_misses; +#endif + } + return regionhash[key]; + } + return NULL; +} + +void +rhash(region * r) +{ + unsigned int rid = coor_hashkey(r->x, r->y); + int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); + while (regionhash[key]!=NULL && regionhash[key]!=DELMARKER && regionhash[key]!=r) { + key = (key + gk) % RMAXHASH; + } + assert(regionhash[key]!=r || !"trying to add the same region twice"); + regionhash[key] = r; +} + +void +runhash(region * r) +{ + unsigned int rid = coor_hashkey(r->x, r->y); + int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); + +#ifdef FAST_CONNECT + int d, di; + for (d=0,di=MAXDIRECTIONS/2;d!=MAXDIRECTIONS;++d,++di) { + region * rc = r->connect[d]; + if (rc!=NULL) { + if (di>=MAXDIRECTIONS) di-=MAXDIRECTIONS; + rc->connect[di] = NULL; + r->connect[d] = NULL; + } + } +#endif + while (regionhash[key]!=NULL && regionhash[key]!=r) { + key = (key + gk) % RMAXHASH; + } + assert(regionhash[key]==r || !"trying to remove a unit that is not hashed"); + regionhash[key] = DELMARKER; +} + +region * +r_connect(const region * r, direction_t dir) +{ + region * result; + int x, y; +#ifdef FAST_CONNECT + region * rmodify = (region*)r; + assert (dir>=0 && dirconnect[dir]) return r->connect[dir]; +#endif + assert(dirx + delta_x[dir]; + y = r->y + delta_y[dir]; + pnormalize(&x, &y, rplane(r)); + result = rfindhash(x, y); +#ifdef FAST_CONNECT + if (result) { + rmodify->connect[dir] = result; + result->connect[back[dir]] = rmodify; + } +#endif + return result; +} + +region * +findregion(int x, int y) +{ + return rfindhash(x, y); +} + +/* Contributed by Hubert Mackenberg. Thanks. + * x und y Abstand zwischen x1 und x2 berechnen + */ +static int +koor_distance_orig(int x1, int y1, int x2, int y2) +{ + int dx = x1 - x2; + int dy = y1 - y2; + + /* Bei negativem dy am Ursprung spiegeln, das veraendert + * den Abstand nicht + */ + if ( dy < 0 ) { + dy = -dy; + dx = -dx; + } + + /* + * dy ist jetzt >=0, fuer dx sind 3 Faelle zu untescheiden + */ + if ( dx >= 0 ) { + int result = dx + dy; + return result; + } + else if (-dx >= dy) { + int result = -dx; + return result; + } + else { + return dy; + } +} + +static int +koor_distance_wrap_xy(int x1, int y1, int x2, int y2, int width, int height) +{ + int dx = x1 - x2; + int dy = y1 - y2; + int result, dist; + int mindist = MIN(width, height) >> 1; + + /* Bei negativem dy am Ursprung spiegeln, das veraendert + * den Abstand nicht + */ + if ( dy < 0 ) { + dy = -dy; + dx = -dx; + } + if (dx<0) { + dx = width + dx; + } + /* dx,dy is now pointing northeast */ + result = dx + dy; + if (result<=mindist) return result; + + dist = (width-dx) + (height-dy); /* southwest */ + if (dist>=0 && dist=0 && dist=0 && distx, r1->y, r2->x, r2->y); +} + +static direction_t +koor_reldirection(int ax, int ay, int bx, int by, const struct plane * pl) +{ + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + int x = ax + delta_x[dir]; + int y = ay + delta_y[dir]; + pnormalize(&x, &y, pl); + if (bx == x && by == y) return dir; + } + return NODIRECTION; +} + +spec_direction * +special_direction(const region * from, const region * to) +{ + const attrib *a = a_findc(from->attribs, &at_direction); + + while (a!=NULL && a->type==&at_direction) { + spec_direction * sd = (spec_direction *)a->data.v; + if (sd->x==to->x && sd->y==to->y) return sd; + a = a->next; + } + return NULL; +} + +direction_t +reldirection(const region * from, const region * to) +{ + plane * pl = rplane(from); + if (pl == rplane(to)) { + direction_t dir = koor_reldirection(from->x, from->y, to->x, to->y, pl); + + if (dir==NODIRECTION) { + spec_direction *sd = special_direction(from, to); + if (sd!=NULL && sd->active) return D_SPECIAL; + } + return dir; + } + return NODIRECTION; +} + +void +free_regionlist(region_list *rl) +{ + while (rl) { + region_list * rl2 = rl->next; + free(rl); + rl = rl2; + } +} + +void +add_regionlist(region_list **rl, region *r) +{ + region_list *rl2 = (region_list*)malloc(sizeof(region_list)); + + rl2->data = r; + rl2->next = *rl; + + *rl = rl2; +} + +/********************/ +/* at_horseluck */ +/********************/ +attrib_type at_horseluck = { + "horseluck", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ, + ATF_UNIQUE +}; + + +/**********************/ +/* at_peasantluck */ +/**********************/ +attrib_type at_peasantluck = { + "peasantluck", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ, + ATF_UNIQUE +}; + +/*********************/ +/* at_chaoscount */ +/*********************/ +attrib_type at_chaoscount = { + "chaoscount", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + a_writeint, + a_readint, + ATF_UNIQUE +}; + +/*********************/ +/* at_deathcount */ +/*********************/ +attrib_type at_deathcount = { + "deathcount", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + a_writeint, + a_readint, + ATF_UNIQUE +}; + +/*********************/ +/* at_woodcount */ +/*********************/ +attrib_type at_woodcount = { + "woodcount", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + a_readint, + ATF_UNIQUE +}; + +/*********************/ +/* at_travelunit */ +/*********************/ +attrib_type at_travelunit = { + "travelunit", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +void +rsetroad(region * r, direction_t d, short val) +{ + connection * b; + region * r2 = rconnect(r, d); + + if (!r2) return; + b = get_borders(r, r2); + while (b && b->type!=&bt_road) b = b->next; + if (!b) b = new_border(&bt_road, r, r2); + if (r==b->from) b->data.sa[0] = val; + else b->data.sa[1] = val; +} + +short +rroad(const region * r, direction_t d) +{ + int rval; + connection * b; + region * r2 = rconnect(r, d); + + if (!r2) return 0; + b = get_borders(r, r2); + while (b && b->type!=&bt_road) b = b->next; + if (!b) return 0; + rval = b->data.i; + if (r==b->from) return b->data.sa[0]; + return b->data.sa[1]; +} + +boolean +r_isforest(const region * r) +{ + if (fval(r->terrain, FOREST_REGION)) { + /* needs to be covered with at leas 48% trees */ + int mincover = (int)(r->terrain->size * 0.48); + int trees = rtrees(r, 2) + rtrees(r, 1); + return (trees*TREESIZE >= mincover); + } + return false; +} + +int +is_coastregion(region *r) +{ + direction_t i; + int res = 0; + + for(i=0;iterrain, SEA_REGION)) res++; + } + return res; +} + +int +rpeasants(const region * r) +{ + return ((r)->land?(r)->land->peasants:0); +} + +void +rsetpeasants(region * r, int value) +{ + ((r)->land?((r)->land->peasants=(value)):(assert((value)>=0), (value)),0); +} + +int +rmoney(const region * r) +{ + return ((r)->land?(r)->land->money:0); +} + +void +rsethorses(const region *r, int value) +{ + assert(value >= 0); + if(r->land) + r->land->horses = value; +} + +int +rhorses(const region *r) +{ + return r->land?r->land->horses:0; +} + +void +rsetmoney(region * r, int value) +{ + ((r)->land?((r)->land->money=(value)):(assert((value)>=0), (value)),0); +} + +void +r_setdemand(region * r, const luxury_type * ltype, int value) +{ + struct demand * d, ** dp = &r->land->demands; + + if (ltype==NULL) return; + + while (*dp && (*dp)->type != ltype) dp = &(*dp)->next; + d = *dp; + if (!d) { + d = *dp = malloc(sizeof(struct demand)); + d->next = NULL; + d->type = ltype; + } + d->value = value; +} + +const item_type * +r_luxury(region * r) +{ + struct demand * dmd; + if (r->land) { + if (!r->land->demands) { + fix_demand(r); + } + for (dmd=r->land->demands;dmd;dmd=dmd->next) { + if (dmd->value==0) return dmd->type->itype; + } + } + return NULL; +} + +int +r_demand(const region * r, const luxury_type * ltype) +{ + struct demand * d = r->land->demands; + while (d && d->type != ltype) d = d->next; + if (!d) return -1; + return d->value; +} + +const char * +rname(const region * r, const struct locale * lang) +{ + if (r->land) { + return r->land->name; + } + return LOC(lang, terrain_name(r)); +} + +int +rtrees(const region *r, int ageclass) +{ + return ((r)->land?(r)->land->trees[ageclass]:0); +} + +int +rsettrees(const region *r, int ageclass, int value) +{ + if (!r->land) assert(value==0); + else { + assert(value>=0); + return r->land->trees[ageclass]=value; + } + return 0; +} + +static region *last; + +static unsigned int max_index = 0; + +region * +new_region(int x, int y, struct plane * pl, unsigned int uid) +{ + region *r; + + pnormalize(&x, &y, pl); + r = rfindhash(x, y); + + if (r) { + log_error(("duplicate region discovered: %s(%d,%d)\n", regionname(r, NULL), x, y)); + if (r->units) + log_error(("duplicate region contains units\n")); + return r; + } + r = calloc(1, sizeof(region)); + r->x = x; + r->y = y; + r->uid = uid; + r->age = 1; + r->_plane = pl; + rhash(r); + hash_uid(r); + if (last) + addlist(&last, r); + else + addlist(®ions, r); + last = r; + assert(r->next==NULL); + r->index = ++max_index; + return r; +} + +static region * deleted_regions; + +void +remove_region(region ** rlist, region * r) +{ + + while (r->units) { + unit * u = r->units; + i_freeall(&u->items); + remove_unit(&r->units, u); + } + + runhash(r); + unhash_uid(r); + while (*rlist && *rlist!=r) rlist=&(*rlist)->next; + assert(*rlist==r); + *rlist = r->next; + r->next = deleted_regions; + deleted_regions = r; +} + +static void +freeland(land_region * lr) +{ + while (lr->demands) { + struct demand * d = lr->demands; + lr->demands = d->next; + free(d); + } + if (lr->name) free(lr->name); + free(lr); +} + +void +region_setresource(region * r, const resource_type * rtype, int value) +{ + rawmaterial * rm = r->resources; + while (rm) { + if (rm->type->rtype==rtype) { + rm->amount = value; + break; + } + rm=rm->next; + } + if (!rm) { + if (rtype==rt_find("money")) rsetmoney(r, value); + else if (rtype==rt_find("peasant")) rsetpeasants(r, value); + else if (rtype==rt_find("horse")) rsethorses(r, value); + } +} + +int +region_getresource(const region * r, const resource_type * rtype) +{ + const rawmaterial * rm; + for (rm=r->resources;rm;rm=rm->next) { + if (rm->type->rtype==rtype) { + return rm->amount; + } + } + if (rtype==rt_find("money")) return rmoney(r); + if (rtype==rt_find("horse")) return rhorses(r); + if (rtype==rt_find("peasant")) return rpeasants(r); + return 0; +} + +void +free_region(region * r) +{ + if (last == r) last = NULL; + free(r->display); + if (r->land) freeland(r->land); + + if (r->msgs) { + free_messagelist(r->msgs); + r->msgs = 0; + } + + while (r->individual_messages) { + struct individual_message * msg = r->individual_messages; + r->individual_messages = msg->next; + if (msg->msgs) free_messagelist(msg->msgs); + free(msg); + } + + while (r->attribs) a_remove (&r->attribs, r->attribs); + while (r->resources) { + rawmaterial * res = r->resources; + r->resources = res->next; + free(res); + } + + while (r->donations) { + donation * don = r->donations; + r->donations = don->next; + free(don); + } + + while (r->units) { + unit * u = r->units; + r->units = u->next; + uunhash(u); + free_unit(u); + free(u); + } + + while (r->buildings) { + building * b = r->buildings; + assert(b->region==r); + r->buildings = b->next; + bunhash(b); /* must be done here, because remove_building does it, and wasn't called */ + free_building(b); + } + + while (r->ships) { + ship * s = r->ships; + assert(s->region==r); + r->ships = s->next; + sunhash(s); + free_ship(s); + } + + free(r); +} + +void +free_regions(void) +{ + memset(uidhash, 0, sizeof(uidhash)); + while (deleted_regions) { + region * r = deleted_regions; + deleted_regions = r->next; + free_region(r); + } + while (regions) { + region * r = regions; + regions = r->next; + runhash(r); + free_region(r); + } + max_index = 0; + last = NULL; +} + +/** creates a name for a region + * TODO: Make vowels XML-configurable and allow non-ascii characters again. + * - that will probably require a wchar_t * string to pick from. + */ +static char * +makename(void) +{ + int s, v, k, e, p = 0, x = 0; + size_t nk, ne, nv, ns; + static char name[16]; + const char *kons = "bcdfghklmnprstvwz", + *start = "bcdgtskpvfr", + *end = "nlrdst", + *vowels = "aaaaaaaaaaaeeeeeeeeeeeeiiiiiiiiiiioooooooooooouuuuuuuuuuyy"; + + /* const char * vowels_latin1 = "aaaaaaaaaàâeeeeeeeeeéèêiiiiiiiiiíîoooooooooóòôuuuuuuuuuúyy"; */ + + nk = strlen(kons); + ne = strlen(end); + nv = strlen(vowels); + ns = strlen(start); + + for (s = rng_int() % 3 + 2; s > 0; s--) { + if (x > 0) { + k = rng_int() % (int)nk; + name[p] = kons[k]; + p++; + } else { + k = rng_int() % (int)ns; + name[p] = start[k]; + p++; + } + v = rng_int() % (int)nv; + name[p] = vowels[v]; + p++; + if (rng_int() % 3 == 2 || s == 1) { + e = rng_int() % (int)ne; + name[p] = end[e]; + p++; + x = 1; + } else + x = 0; + } + name[p] = '\0'; + name[0] = (char) toupper(name[0]); + return name; +} + +void +setluxuries(region * r, const luxury_type * sale) +{ + const luxury_type * ltype; + + assert(r->land); + + if(r->land->demands) freelist(r->land->demands); + + for (ltype=luxurytypes; ltype; ltype=ltype->next) { + struct demand * dmd = malloc(sizeof(struct demand)); + dmd->type = ltype; + if (ltype!=sale) dmd->value = 1 + rng_int() % 5; + else dmd->value = 0; + dmd->next = r->land->demands; + r->land->demands = dmd; + } +} + +void +terraform_region(region * r, const terrain_type * terrain) +{ + /* Resourcen, die nicht mehr vorkommen können, löschen */ + const terrain_type * oldterrain = r->terrain; + rawmaterial **lrm = &r->resources; + + assert(terrain); + + while (*lrm) { + rawmaterial *rm = *lrm; + const resource_type * rtype = NULL; + + if (terrain->production!=NULL) { + int i; + for (i=0;terrain->production[i].type;++i) { + if (rm->type->rtype == terrain->production[i].type) { + rtype = rm->type->rtype; + break; + } + } + } + if (rtype==NULL) { + *lrm = rm->next; + free(rm); + } else { + lrm = &rm->next; + } + } + + r->terrain = terrain; + terraform_resources(r); + + if (!fval(terrain, LAND_REGION)) { + region_setinfo(r, NULL); + if (r->land!=NULL) { + i_freeall(&r->land->items); + freeland(r->land); + r->land = NULL; + } + rsettrees(r, 0, 0); + rsettrees(r, 1, 0); + rsettrees(r, 2, 0); + rsethorses(r, 0); + rsetpeasants(r, 0); + rsetmoney(r, 0); + freset(r, RF_ENCOUNTER); + freset(r, RF_MALLORN); + /* Beschreibung und Namen löschen */ + return; + } + + if (r->land) { + i_freeall(&r->land->items); + } else { + static struct surround { + struct surround * next; + const luxury_type * type; + int value; + } *trash =NULL, *nb = NULL; + const luxury_type * ltype = NULL; + direction_t d; + int mnr = 0; + + r->land = calloc(1, sizeof(land_region)); + r->land->ownership = NULL; + region_set_morale(r, MORALE_DEFAULT, -1); + region_setname(r, makename()); + for (d=0;d!=MAXDIRECTIONS;++d) { + region * nr = rconnect(r, d); + if (nr && nr->land) { + struct demand * sale = r->land->demands; + while (sale && sale->value!=0) sale=sale->next; + if (sale) { + struct surround * sr = nb; + while (sr && sr->type!=sale->type) sr=sr->next; + if (!sr) { + if (trash) { + sr = trash; + trash = trash->next; + } else { + sr = calloc(1, sizeof(struct surround)); + } + sr->next = nb; + sr->type = sale->type; + sr->value = 1; + nb = sr; + } else sr->value++; + ++mnr; + } + } + } + if (!nb) { + int i = get_maxluxuries(); + if (i>0) { + i = rng_int() % i; + ltype = luxurytypes; + while (i--) ltype=ltype->next; + } + } else { + int i = rng_int() % mnr; + struct surround * srd = nb; + while (i>srd->value) { + i-=srd->value; + srd=srd->next; + } + if (srd->type) setluxuries(r, srd->type); + while (srd->next!=NULL) srd=srd->next; + srd->next=trash; + trash = nb; + nb = NULL; + } + } + + if (fval(terrain, LAND_REGION)) { + const item_type * itype = NULL; + char equip_hash[64]; + + /* TODO: put the equipment in struct terrain, faster */ + sprintf(equip_hash, "terrain_%s", terrain->_name); + equip_items(&r->land->items, get_equipment(equip_hash)); + + if (r->terrain->herbs) { + int len=0; + while (r->terrain->herbs[len]) ++len; + if (len) itype = r->terrain->herbs[rng_int()%len]; + } + if (itype!=NULL) { + rsetherbtype(r, itype); + rsetherbs(r, (short)(50+rng_int()%31)); + } + else { + rsetherbtype(r, NULL); + } + if (oldterrain==NULL || !fval(oldterrain, LAND_REGION)) { + if (rng_int() % 100 < 3) fset(r, RF_MALLORN); + else freset(r, RF_MALLORN); + if (rng_int() % 100 < ENCCHANCE) { + fset(r, RF_ENCOUNTER); + } + } + } + + if (oldterrain==NULL || terrain->size!=oldterrain->size) { + if (terrain==newterrain(T_PLAIN)) { + rsethorses(r, rng_int() % (terrain->size / 50)); + if(rng_int()%100 < 40) { + rsettrees(r, 2, terrain->size * (30+rng_int()%40)/1000); + } + } else if (chance(0.2)) { + rsettrees(r, 2, terrain->size * (30 + rng_int() % 40) / 1000); + } else { + rsettrees(r, 2, 0); + } + rsettrees(r, 1, rtrees(r, 2)/4); + rsettrees(r, 0, rtrees(r, 2)/8); + + if (!fval(r, RF_CHAOTIC)) { + int peasants; + peasants = (maxworkingpeasants(r) * (20+dice_rand("6d10")))/100; + rsetpeasants(r, MAX(100, peasants)); + rsetmoney(r, rpeasants(r) * ((wage(r, NULL, NULL, INT_MAX)+1) + rng_int() % 5)); + } + } +} + +/** ENNO: + * ich denke, das das hier nicht sein sollte. + * statt dessen sollte ein attribut an der region sein, das das erledigt, + * egal ob durch den spell oder anderes angelegt. + **/ +#include "curse.h" +int +production(const region *r) +{ + /* muß rterrain(r) sein, nicht rterrain() wegen rekursion */ + int p = r->terrain->size / MAXPEASANTS_PER_AREA; + if (curse_active(get_curse(r->attribs, ct_find("drought")))) p /= 2; + + return p; +} + +int +resolve_region_coor(variant id, void * address) { + region * r = findregion(id.sa[0], id.sa[1]); + if (r) { + *(region**)address = r; + return 0; + } + *(region**)address = NULL; + return -1; +} + +int +resolve_region_id(variant id, void * address) +{ + region * r = NULL; + if (id.i!=0) { + r = findregionbyid((unsigned int)id.i); + if (r==NULL) { + *(region**)address = NULL; + return -1; + } + } + *(region**)address = r; + return 0; +} + +variant +read_region_reference(struct storage * store) +{ + variant result; + if (store->versionr_int(store); + result.sa[1] = (short)store->r_int(store); + } else { + result.i = store->r_int(store); + } + return result; +} + +void +write_region_reference(const region * r, struct storage * store) +{ + if (r) { + store->w_int(store, r->uid); + } else { + store->w_int(store, 0); + } +} + +struct message_list * +r_getmessages(const struct region * r, const struct faction * viewer) +{ + struct individual_message * imsg = r->individual_messages; + while (imsg && (imsg)->viewer!=viewer) imsg = imsg->next; + if (imsg) return imsg->msgs; + return NULL; +} + +struct message * +r_addmessage(struct region * r, const struct faction * viewer, struct message * msg) +{ + assert(r); + if (viewer) { + struct individual_message * imsg; + imsg = r->individual_messages; + while (imsg && imsg->viewer!=viewer) imsg = imsg->next; + if (imsg==NULL) { + imsg = malloc(sizeof(struct individual_message)); + imsg->next = r->individual_messages; + imsg->msgs = NULL; + r->individual_messages = imsg; + imsg->viewer = viewer; + } + return add_message(&imsg->msgs, msg); + } + return add_message(&r->msgs, msg); +} + +struct faction * +region_get_owner(const struct region * r) +{ + assert(rule_region_owners()); + if (r->land && r->land->ownership) { + return r->land->ownership->owner; + } + return NULL; +} + +struct alliance * +region_get_alliance(const struct region * r) +{ + assert(rule_region_owners()); + if (r->land && r->land->ownership) { + region_owner * own = r->land->ownership; + return own->owner?own->owner->alliance:own->alliance; + } + return NULL; +} + +void +region_set_owner(struct region * r, struct faction * owner, int turn) +{ + assert(rule_region_owners()); + if (r->land) { + if (!r->land->ownership) { + r->land->ownership = malloc(sizeof(region_owner)); + assert(region_get_morale(r)==MORALE_DEFAULT); + r->land->ownership->owner = NULL; + r->land->ownership->alliance = NULL; + r->land->ownership->flags = 0; + } + r->land->ownership->since_turn = turn; + r->land->ownership->morale_turn = turn; + assert(r->land->ownership->owner != owner); + r->land->ownership->owner = owner; + if (owner) { + r->land->ownership->alliance = owner->alliance; + } + } +} + + +faction * update_owners(region * r) +{ + faction * f = NULL; + assert(rule_region_owners()); + if (r->land) { + building * bowner = largestbuilding(r, &cmp_current_owner, false); + building * blargest = largestbuilding(r, &cmp_taxes, false); + if (blargest) { + if (!bowner || bowner->sizesize) { + /* region owners update? */ + unit * u = building_owner(blargest); + f = region_get_owner(r); + if (u==NULL) { + if (f) { + region_set_owner(r, NULL, turn); + r->land->ownership->flags |= OWNER_MOURNING; + f = NULL; + } + } else if (u->faction!=f) { + if (!r->land->ownership) { + /* there has never been a prior owner */ + region_set_morale(r, MORALE_DEFAULT, turn); + } else { + alliance * al = region_get_alliance(r); + if (al && u->faction->alliance==al) { + int morale = MAX(0, r->land->morale-MORALE_TRANSFER); + region_set_morale(r, morale, turn); + } else { + region_set_morale(r, MORALE_TAKEOVER, turn); + if (f) { + r->land->ownership->flags |= OWNER_MOURNING; + } + } + } + region_set_owner(r, u->faction, turn); + f = u->faction; + } + } + } else if (r->land->ownership && r->land->ownership->owner) { + r->land->ownership->flags |= OWNER_MOURNING; + region_set_owner(r, NULL, turn); + f = NULL; + } + } + return f; +} + +void +region_setinfo(struct region * r, const char * info) +{ + free(r->display); + r->display = info?strdup(info):0; +} + +const char * +region_getinfo(const region * r) { + return r->display?r->display:""; +} + +void +region_setname(struct region * r, const char * name) +{ + if (r->land) { + free(r->land->name); + r->land->name = name?strdup(name):0; + } +} + +const char * +region_getname(const region * r) { + if (r->land && r->land->name) { + return r->land->name; + } + return ""; +} + +int region_get_morale(const region * r) +{ + if (r->land) { + assert(r->land->morale>=0 && r->land->morale<=MORALE_MAX); + return r->land->morale; + } + return -1; +} + +void region_set_morale(region * r, int morale, int turn) +{ + if (r->land) { + r->land->morale = (short)morale; + if (turn>=0 && r->land->ownership) { + r->land->ownership->morale_turn = turn; + } + assert(r->land->morale>=0 && r->land->morale<=MORALE_MAX); + } +} + +void get_neighbours(const region * r, region ** list) +{ + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + list[dir] = rconnect(r, dir); + } +} + +int owner_change(const region * r) +{ + if (r->land && r->land->ownership) { + return r->land->ownership->since_turn; + } + return -1; +} + +boolean is_mourning(const region * r, int in_turn) +{ + int change = owner_change(r); + return (change==in_turn-1 && (r->land->ownership->flags&OWNER_MOURNING)); +} diff --git a/src/kernel/region.h b/src/kernel/region.h index 5c226fd2a..b5a955eac 100644 --- a/src/kernel/region.h +++ b/src/kernel/region.h @@ -1,300 +1,300 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_REGION -#define H_KRNL_REGION -#ifdef __cplusplus -extern "C" { -#endif - -#include "types.h" - -/* FAST_CONNECT: regions are directly connected to neighbours, saves doing - a hash-access each time a neighbour is needed */ -#define FAST_CONNECT - -#define RF_CHAOTIC (1<<0) -#define RF_MALLORN (1<<1) -#define RF_BLOCKED (1<<2) - -#define RF_BLOCK_NORTHWEST (1<<3) -#define RF_BLOCK_NORTHEAST (1<<4) -#define RF_BLOCK_EAST (1<<5) -#define RF_BLOCK_SOUTHEAST (1<<6) -#define RF_BLOCK_SOUTHWEST (1<<7) -#define RF_BLOCK_WEST (1<<8) - -#define RF_ENCOUNTER (1<<9) -#define RF_MIGRATION (1<<10) -#define RF_UNUSED_1 (1<<11) -#define RF_ORCIFIED (1<<12) -#define RF_CURSED (1<<13) - - /* debug flags */ -#define RF_COMBATDEBUG (1<<14) -#define RF_MAPPER_HIGHLIGHT (1<<14) /* only used by mapper, not stored */ -#define RF_LIGHTHOUSE (1<<15) /* this region may contain a lighthouse */ - -#define RF_SELECT (1<<17) -#define RF_MARK (1<<18) - -/* flags that speed up attribute access: */ -#define RF_TRAVELUNIT (1<<19) -#define RF_GUARDED (1<<20) - -#define RF_ALL 0xFFFFFF - -#define RF_SAVEMASK (RF_GUARDED|RF_CHAOTIC|RF_MALLORN|RF_BLOCKED|RF_BLOCK_NORTHWEST|RF_BLOCK_NORTHEAST|RF_BLOCK_EAST|RF_BLOCK_SOUTHEAST|RF_BLOCK_SOUTHWEST|RF_BLOCK_WEST|RF_ENCOUNTER|RF_ORCIFIED) -struct message; -struct message_list; -struct rawmaterial; -struct donation; -struct item; - -#define MORALE_TAX_FACTOR 0.005 /* 0.5% tax per point of morale */ -#define MORALE_MAX 10 /* Maximum morale allowed */ -#define MORALE_DEFAULT 1 /* Morale of peasants when they are conquered for the first time */ -#define MORALE_TAKEOVER 0 /* Morale of peasants after they lose their lord */ -#define MORALE_COOLDOWN 2 /* minimum cooldown before a morale change occurs */ -#define MORALE_AVERAGE 6 /* default average time for morale to change */ -#define MORALE_TRANSFER 2 /* points of morale lost when GIVE COMMAND */ - -#define OWNER_MOURNING 0x01 -typedef struct region_owner { - struct faction * owner; - struct alliance * alliance; - int since_turn; /* turn the region changed owners */ - int morale_turn; /* turn when morale has changed most recently */ - unsigned int flags; -} region_owner; - -typedef struct demand { - struct demand * next; - const struct luxury_type * type; - int value; -} demand; - -typedef struct land_region { - char *name; - /* TODO: demand kann nach Konvertierung entfernt werden. */ - demand * demands; - const struct item_type * herbtype; - short herbs; - short morale; - int trees[3]; /* 0 -> seeds, 1 -> shoots, 2 -> trees */ - int horses; - int peasants; - int newpeasants; - int money; - struct item * items; /* items that can be claimed */ - struct region_owner * ownership; -} land_region; - -typedef struct donation { - struct donation *next; - struct faction *f1, *f2; - int amount; -} donation; - -typedef struct region { - struct region *next; - struct land_region *land; - struct unit *units; - struct ship *ships; - struct building *buildings; - unsigned int index; - /* an ascending number, to improve the speed of determining the interval in - which a faction has its units. See the implementations of firstregion - and lastregion */ - unsigned int uid; /* a unique id */ - int x, y; - struct plane * _plane; /* to access, use rplane(r) */ - char *display; - unsigned int flags; - unsigned short age; - struct message_list *msgs; - struct individual_message { - struct individual_message * next; - const struct faction * viewer; - struct message_list *msgs; - } * individual_messages; - struct attrib *attribs; - struct donation * donations; - const struct terrain_type * terrain; - struct rawmaterial * resources; -#ifdef FAST_CONNECT - struct region * connect[MAXDIRECTIONS]; /* use rconnect(r, dir) to access */ -#endif -} region; - -extern struct region *regions; - -typedef struct region_list { - struct region_list * next; - struct region * data; -} region_list; - -struct message_list * r_getmessages(const struct region * r, const struct faction * viewer); -struct message * r_addmessage(struct region * r, const struct faction * viewer, struct message * msg); - -typedef struct spec_direction { - int x, y; - int duration; - boolean active; - char *desc; - char *keyword; -} spec_direction; - -typedef struct { - direction_t dir; -} moveblock; - -#define reg_hashkey(r) (r->index) - -int distance(const struct region*, const struct region*); -int koor_distance(int ax, int ay, int bx, int by) ; -direction_t reldirection(const struct region * from, const struct region * to); -struct region * findregion(int x, int y); -struct region * findregionbyid(unsigned int uid); - -extern struct attrib_type at_direction; -extern struct attrib_type at_moveblock; -extern struct attrib_type at_peasantluck; -extern struct attrib_type at_horseluck; -extern struct attrib_type at_chaoscount; -extern struct attrib_type at_woodcount; -extern struct attrib_type at_deathcount; -extern struct attrib_type at_travelunit; - -void initrhash(void); -void rhash(struct region * r); -void runhash(struct region * r); - -void free_regionlist(region_list *rl); -void add_regionlist(region_list **rl, struct region *r); - -struct region * find_special_direction(const struct region *r, const char *token, const struct locale * lang); -void register_special_direction(const char * name); -struct spec_direction * special_direction(const region * from, const region * to); -struct attrib *create_special_direction(struct region *r, struct region *rt, - int duration, const char *desc, - const char *keyword); - -int deathcount(const struct region * r); -int chaoscount(const struct region * r); - -void deathcounts(struct region * r, int delta); -void chaoscounts(struct region * r, int delta); - -void setluxuries(struct region * r, const struct luxury_type * sale); -int get_maxluxuries(void); - -short rroad(const struct region * r, direction_t d); -void rsetroad(struct region * r, direction_t d, short value); - -int is_coastregion(struct region *r); - -int rtrees(const struct region * r, int ageclass); -enum { - TREE_SEED = 0, - TREE_SAPLING = 1, - TREE_TREE = 2 -}; - -int rsettrees(const struct region *r, int ageclass, int value); - -int rpeasants(const struct region * r); -void rsetpeasants(struct region * r, int value); -int rmoney(const struct region * r); -void rsetmoney(struct region * r, int value); -int rhorses(const struct region * r); -void rsethorses(const struct region * r, int value); - -#define rbuildings(r) ((r)->buildings) - -#define rherbtype(r) ((r)->land?(r)->land->herbtype:0) -#define rsetherbtype(r, value) if ((r)->land) (r)->land->herbtype=(value) - -#define rherbs(r) ((r)->land?(r)->land->herbs:0) -#define rsetherbs(r, value) if ((r)->land) ((r)->land->herbs=(short)(value)) - -boolean r_isforest(const struct region * r); - -#define rterrain(r) (oldterrain((r)->terrain)) -#define rsetterrain(r, t) ((r)->terrain = newterrain(t)) - -const char * rname(const struct region * r, const struct locale * lang); - -#define rplane(r) getplane(r) - -void r_setdemand(struct region * r, const struct luxury_type * ltype, int value); -int r_demand(const struct region * r, const struct luxury_type * ltype); - -const char * write_regionname(const struct region * r, const struct faction * f, char * buffer, size_t size); - -struct region * new_region(int x, int y, struct plane * pl, unsigned int uid); -void remove_region(region ** rlist, region * r); -void terraform_region(struct region * r, const struct terrain_type * terrain); -boolean pnormalize(int * x, int * y, const struct plane * pl); - -extern const int delta_x[MAXDIRECTIONS]; -extern const int delta_y[MAXDIRECTIONS]; -direction_t dir_invert(direction_t dir); -int production(const struct region *r); - -void region_set_owner(struct region * r, struct faction * owner, int turn); -struct faction * region_get_owner(const struct region * r); -struct alliance * region_get_alliance(const struct region * r); - -struct region * r_connect(const struct region *, direction_t dir); -#ifdef FAST_CONNECT -# define rconnect(r, dir) ((r)->connect[dir]?(r)->connect[dir]:r_connect(r, (direction_t)dir)) -#else -# define rconnect(r, dir) r_connect(r, (direction_t)dir) -#endif - -void free_regions(void); - -int region_get_morale(const region * r); -void region_set_morale(region * r, int morale, int turn); - -void write_region_reference(const struct region * r, struct storage * store); -variant read_region_reference(struct storage * store); -int resolve_region_coor(variant id, void * address); -int resolve_region_id(variant id, void * address); -#define RESOLVE_REGION(version) ((version + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_REGION +#define H_KRNL_REGION +#ifdef __cplusplus +extern "C" { +#endif + +#include "types.h" + +/* FAST_CONNECT: regions are directly connected to neighbours, saves doing + a hash-access each time a neighbour is needed */ +#define FAST_CONNECT + +#define RF_CHAOTIC (1<<0) +#define RF_MALLORN (1<<1) +#define RF_BLOCKED (1<<2) + +#define RF_BLOCK_NORTHWEST (1<<3) +#define RF_BLOCK_NORTHEAST (1<<4) +#define RF_BLOCK_EAST (1<<5) +#define RF_BLOCK_SOUTHEAST (1<<6) +#define RF_BLOCK_SOUTHWEST (1<<7) +#define RF_BLOCK_WEST (1<<8) + +#define RF_ENCOUNTER (1<<9) +#define RF_MIGRATION (1<<10) +#define RF_UNUSED_1 (1<<11) +#define RF_ORCIFIED (1<<12) +#define RF_CURSED (1<<13) + + /* debug flags */ +#define RF_COMBATDEBUG (1<<14) +#define RF_MAPPER_HIGHLIGHT (1<<14) /* only used by mapper, not stored */ +#define RF_LIGHTHOUSE (1<<15) /* this region may contain a lighthouse */ + +#define RF_SELECT (1<<17) +#define RF_MARK (1<<18) + +/* flags that speed up attribute access: */ +#define RF_TRAVELUNIT (1<<19) +#define RF_GUARDED (1<<20) + +#define RF_ALL 0xFFFFFF + +#define RF_SAVEMASK (RF_GUARDED|RF_CHAOTIC|RF_MALLORN|RF_BLOCKED|RF_BLOCK_NORTHWEST|RF_BLOCK_NORTHEAST|RF_BLOCK_EAST|RF_BLOCK_SOUTHEAST|RF_BLOCK_SOUTHWEST|RF_BLOCK_WEST|RF_ENCOUNTER|RF_ORCIFIED) +struct message; +struct message_list; +struct rawmaterial; +struct donation; +struct item; + +#define MORALE_TAX_FACTOR 0.005 /* 0.5% tax per point of morale */ +#define MORALE_MAX 10 /* Maximum morale allowed */ +#define MORALE_DEFAULT 1 /* Morale of peasants when they are conquered for the first time */ +#define MORALE_TAKEOVER 0 /* Morale of peasants after they lose their lord */ +#define MORALE_COOLDOWN 2 /* minimum cooldown before a morale change occurs */ +#define MORALE_AVERAGE 6 /* default average time for morale to change */ +#define MORALE_TRANSFER 2 /* points of morale lost when GIVE COMMAND */ + +#define OWNER_MOURNING 0x01 +typedef struct region_owner { + struct faction * owner; + struct alliance * alliance; + int since_turn; /* turn the region changed owners */ + int morale_turn; /* turn when morale has changed most recently */ + unsigned int flags; +} region_owner; + +typedef struct demand { + struct demand * next; + const struct luxury_type * type; + int value; +} demand; + +typedef struct land_region { + char *name; + /* TODO: demand kann nach Konvertierung entfernt werden. */ + demand * demands; + const struct item_type * herbtype; + short herbs; + short morale; + int trees[3]; /* 0 -> seeds, 1 -> shoots, 2 -> trees */ + int horses; + int peasants; + int newpeasants; + int money; + struct item * items; /* items that can be claimed */ + struct region_owner * ownership; +} land_region; + +typedef struct donation { + struct donation *next; + struct faction *f1, *f2; + int amount; +} donation; + +typedef struct region { + struct region *next; + struct land_region *land; + struct unit *units; + struct ship *ships; + struct building *buildings; + unsigned int index; + /* an ascending number, to improve the speed of determining the interval in + which a faction has its units. See the implementations of firstregion + and lastregion */ + unsigned int uid; /* a unique id */ + int x, y; + struct plane * _plane; /* to access, use rplane(r) */ + char *display; + unsigned int flags; + unsigned short age; + struct message_list *msgs; + struct individual_message { + struct individual_message * next; + const struct faction * viewer; + struct message_list *msgs; + } * individual_messages; + struct attrib *attribs; + struct donation * donations; + const struct terrain_type * terrain; + struct rawmaterial * resources; +#ifdef FAST_CONNECT + struct region * connect[MAXDIRECTIONS]; /* use rconnect(r, dir) to access */ +#endif +} region; + +extern struct region *regions; + +typedef struct region_list { + struct region_list * next; + struct region * data; +} region_list; + +struct message_list * r_getmessages(const struct region * r, const struct faction * viewer); +struct message * r_addmessage(struct region * r, const struct faction * viewer, struct message * msg); + +typedef struct spec_direction { + int x, y; + int duration; + boolean active; + char *desc; + char *keyword; +} spec_direction; + +typedef struct { + direction_t dir; +} moveblock; + +#define reg_hashkey(r) (r->index) + +int distance(const struct region*, const struct region*); +int koor_distance(int ax, int ay, int bx, int by) ; +direction_t reldirection(const struct region * from, const struct region * to); +struct region * findregion(int x, int y); +struct region * findregionbyid(unsigned int uid); + +extern struct attrib_type at_direction; +extern struct attrib_type at_moveblock; +extern struct attrib_type at_peasantluck; +extern struct attrib_type at_horseluck; +extern struct attrib_type at_chaoscount; +extern struct attrib_type at_woodcount; +extern struct attrib_type at_deathcount; +extern struct attrib_type at_travelunit; + +void initrhash(void); +void rhash(struct region * r); +void runhash(struct region * r); + +void free_regionlist(region_list *rl); +void add_regionlist(region_list **rl, struct region *r); + +struct region * find_special_direction(const struct region *r, const char *token, const struct locale * lang); +void register_special_direction(const char * name); +struct spec_direction * special_direction(const region * from, const region * to); +struct attrib *create_special_direction(struct region *r, struct region *rt, + int duration, const char *desc, + const char *keyword); + +int deathcount(const struct region * r); +int chaoscount(const struct region * r); + +void deathcounts(struct region * r, int delta); +void chaoscounts(struct region * r, int delta); + +void setluxuries(struct region * r, const struct luxury_type * sale); +int get_maxluxuries(void); + +short rroad(const struct region * r, direction_t d); +void rsetroad(struct region * r, direction_t d, short value); + +int is_coastregion(struct region *r); + +int rtrees(const struct region * r, int ageclass); +enum { + TREE_SEED = 0, + TREE_SAPLING = 1, + TREE_TREE = 2 +}; + +int rsettrees(const struct region *r, int ageclass, int value); + +int rpeasants(const struct region * r); +void rsetpeasants(struct region * r, int value); +int rmoney(const struct region * r); +void rsetmoney(struct region * r, int value); +int rhorses(const struct region * r); +void rsethorses(const struct region * r, int value); + +#define rbuildings(r) ((r)->buildings) + +#define rherbtype(r) ((r)->land?(r)->land->herbtype:0) +#define rsetherbtype(r, value) if ((r)->land) (r)->land->herbtype=(value) + +#define rherbs(r) ((r)->land?(r)->land->herbs:0) +#define rsetherbs(r, value) if ((r)->land) ((r)->land->herbs=(short)(value)) + +boolean r_isforest(const struct region * r); + +#define rterrain(r) (oldterrain((r)->terrain)) +#define rsetterrain(r, t) ((r)->terrain = newterrain(t)) + +const char * rname(const struct region * r, const struct locale * lang); + +#define rplane(r) getplane(r) + +void r_setdemand(struct region * r, const struct luxury_type * ltype, int value); +int r_demand(const struct region * r, const struct luxury_type * ltype); + +const char * write_regionname(const struct region * r, const struct faction * f, char * buffer, size_t size); + +struct region * new_region(int x, int y, struct plane * pl, unsigned int uid); +void remove_region(region ** rlist, region * r); +void terraform_region(struct region * r, const struct terrain_type * terrain); +boolean pnormalize(int * x, int * y, const struct plane * pl); + +extern const int delta_x[MAXDIRECTIONS]; +extern const int delta_y[MAXDIRECTIONS]; +direction_t dir_invert(direction_t dir); +int production(const struct region *r); + +void region_set_owner(struct region * r, struct faction * owner, int turn); +struct faction * region_get_owner(const struct region * r); +struct alliance * region_get_alliance(const struct region * r); + +struct region * r_connect(const struct region *, direction_t dir); +#ifdef FAST_CONNECT +# define rconnect(r, dir) ((r)->connect[dir]?(r)->connect[dir]:r_connect(r, (direction_t)dir)) +#else +# define rconnect(r, dir) r_connect(r, (direction_t)dir) +#endif + +void free_regions(void); + +int region_get_morale(const region * r); +void region_set_morale(region * r, int morale, int turn); + +void write_region_reference(const struct region * r, struct storage * store); +variant read_region_reference(struct storage * store); +int resolve_region_coor(variant id, void * address); +int resolve_region_id(variant id, void * address); +#define RESOLVE_REGION(version) ((version - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include - -struct message; - -/* TODO: this could be nicer and faster - * call with MSG(("msg_name", "param", p), buf, faction). */ -#define MSG(makemsg, buf, size, loc, ud) { struct message * m = msg_message makemsg; nr_render(m, loc, buf, size, ud); msg_release(m); } -#define RENDER(f, buf, size, mcreate) { struct message * m = msg_message mcreate; nr_render(m, f->locale, buf, size, f); msg_release(m); } +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include + +struct message; + +/* TODO: this could be nicer and faster + * call with MSG(("msg_name", "param", p), buf, faction). */ +#define MSG(makemsg, buf, size, loc, ud) { struct message * m = msg_message makemsg; nr_render(m, loc, buf, size, ud); msg_release(m); } +#define RENDER(f, buf, size, mcreate) { struct message * m = msg_message mcreate; nr_render(m, f->locale, buf, size, f); msg_release(m); } diff --git a/src/kernel/reports.c b/src/kernel/reports.c index dadad6481..b373e73ba 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -1,2186 +1,2186 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "reports.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include -#include - -/* attributes includes */ -#include -#include -#include -#include - -boolean nocr = false; -boolean nonr = false; -boolean noreports = false; - -const char * visibility[] = { - "none", - "neighbour", - "lighthouse", - "travel", - "far", - "unit", - "battle" -}; - -const char *coasts[MAXDIRECTIONS] = -{ - "coast::nw", - "coast::ne", - "coast::e", - "coast::se", - "coast::sw", - "coast::w" -}; - -static char * -groupid(const struct group * g, const struct faction * f) -{ - typedef char name[OBJECTIDSIZE + 1]; - static name idbuf[8]; - static int nextbuf = 0; - char *buf = idbuf[(++nextbuf) % 8]; - sprintf(buf, "%s (%s)", g->name, factionid(f)); - return buf; -} - -const char * combatstatus[] = { - "status_aggressive", "status_front", - "status_rear", "status_defensive", - "status_avoid", "status_flee" -}; - -const char * -report_kampfstatus(const unit * u, const struct locale * lang) -{ - static char fsbuf[64]; - - strlcpy(fsbuf, LOC(lang, combatstatus[u->status]), sizeof(fsbuf)); - if (fval(u, UFL_NOAID)) { - strcat(fsbuf, ", "); - strcat(fsbuf, LOC(lang, "status_noaid")); - } - - return fsbuf; -} - -const char * -hp_status(const unit * u) -{ - double p = (double) ((double) u->hp / (double) (u->number * unit_max_hp(u))); - - if (p > 2.00) return mkname("damage", "critical"); - if (p > 1.50) return mkname("damage", "heavily"); - if (p < 0.50) return mkname("damage", "badly"); - if (p < 0.75) return mkname("damage", "wounded"); - if (p < 0.99) return mkname("damage", "exhausted"); - - return NULL; -} - -void -report_item(const unit * owner, const item * i, const faction * viewer, const char ** name, const char ** basename, int * number, boolean singular) -{ - assert(!owner || owner->number); - if (owner && owner->faction == viewer) { - if (name) *name = locale_string(viewer->locale, resourcename(i->type->rtype, ((i->number!=1 && !singular)?GR_PLURAL:0))); - if (basename) *basename = resourcename(i->type->rtype, 0); - if (number) *number = i->number; - } else if (owner && i->type->rtype==r_silver) { - int pp = i->number/owner->number; - if (number) *number = 1; - if (pp > 50000 && dragonrace(owner->race)) { - if (name) *name = locale_string(viewer->locale, "dragonhoard"); - if (basename) *basename = "dragonhoard"; - } else if (pp > 5000) { - if (name) *name = locale_string(viewer->locale, "moneychest"); - if (basename) *basename = "moneychest"; - } else if (pp > 500) { - if (name) *name = locale_string(viewer->locale, "moneybag"); - if (basename) *basename = "moneybag"; - } else { - if (number) *number = 0; - if (name) *name = NULL; - if (basename) *basename = NULL; - } - } else { - if (name) *name = locale_string(viewer->locale, resourcename(i->type->rtype, NMF_APPEARANCE|((i->number!=1 && !singular)?GR_PLURAL:0))); - if (basename) *basename = resourcename(i->type->rtype, NMF_APPEARANCE); - if (number) { - if (fval(i->type, ITF_HERB)) *number = 1; - else *number = i->number; - } - } -} - - -int * nmrs = NULL; - -int -update_nmrs(void) -{ - int i, newplayers =0; - faction *f; - int turn = global.data_turn; - - if (nmrs==NULL) nmrs = malloc(sizeof(int)*(NMRTimeout()+1)); - for (i = 0; i <= NMRTimeout(); ++i) { - nmrs[i] = 0; - } - - for (f = factions; f; f = f->next) { - if (fval(f, FFL_ISNEW)) { - ++newplayers; - } else if (!is_monsters(f) && f->alive) { - int nmr = turn-f->lastorders+1; - if (nmr<0 || nmr>NMRTimeout()) { - log_error(("faction %s has %d NMRS\n", factionid(f), nmr)); - nmr = MAX(0, nmr); - nmr = MIN(nmr, NMRTimeout()); - } - ++nmrs[nmr]; - } - } - return newplayers; -} - -#define ORDERS_IN_NR 1 -static size_t -buforder(char * bufp, size_t size, const order * ord, int mode) -{ - size_t tsize = 0; - int bytes; - - bytes = (int)strlcpy(bufp, ", \"", size); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (mode1) { - *bufp++ ='\"'; - --size; - } else { - WARN_STATIC_BUFFER(); - } - ++tsize; - - return tsize; -} - -/** create a report of a list of items to a non-owner. - * \param result: an array of size items. - * \param size: maximum number of items to return - * \param owner: the owner of the items, or NULL for faction::items etc. - * \param viewer: the faction looking at the items - */ -int -report_items(const item * items, item * result, int size, const unit * owner, const faction * viewer) -{ - const item * itm; - int n = 0; /* number of results */ - - assert(owner==NULL || viewer!=owner->faction || !"not required for owner=viewer!"); - assert(size); - - for (itm=items;itm;itm=itm->next) { - item * ishow; - const char * ic; - - report_item(owner, itm, viewer, NULL, &ic, NULL, false); - if (ic && *ic) { - for (ishow = result; ishow!=result+n; ++ishow) { - const char * sc; - - if (ishow->type==itm->type) sc = ic; - else report_item(owner, ishow, viewer, NULL, &sc, NULL, false); - if (sc==ic || strcmp(sc, ic)==0) { - ishow->number+=itm->number; - break; - } - } - if (ishow==result+n) { - if (n==size) { - log_error(("too many items to report, increase buffer size.\n")); - return -1; - } - result[n].number = itm->number; - result[n].type = itm->type; - result[n].next = (n+1==size)?NULL:result+n+1; - ++n; - } - } - } - if (n>0) result[n-1].next = NULL; - return n; -} - -static void -report_resource(resource_report * result, const char * name, int number, int level) -{ - result->name = name; - result->number = number; - result->level = level; -} - -void -report_race(const struct unit * u, const char ** name, const char ** illusion) -{ - if (illusion) { - const race * irace = u_irace(u); - if (irace && irace!=u->race) { - *illusion = irace->_name[0]; - } - else { - *illusion = NULL; - } - } - if (name) { - *name = u->race->_name[0]; - if (fval(u->race, RCF_SHAPESHIFTANY)) { - const char * str = get_racename(u->attribs); - if (str) *name = str; - } - } -} - -void -report_building(const struct building * b, const char ** name, const char ** illusion) -{ - static int init; - static const struct building_type * bt_illusion; - - if (name) { - *name = buildingtype(b->type, b, b->size); - } - if (illusion) { - *illusion = NULL; - - if (!init) { - bt_illusion = bt_find("illusioncastle"); - init = 1; - } - if (bt_illusion && b->type==bt_illusion) { - const attrib * a = a_findc(b->attribs, &at_icastle); - if (a!=NULL) { - icastle_data * icastle = (icastle_data*)a->data.v; - *illusion = buildingtype(icastle->type, b, b->size); - } - } - } -} - -int -report_resources(const seen_region * sr, resource_report * result, int size, const faction * viewer) -{ - const region * r = sr->r; - int n = 0; - - if (r->land) { - int peasants = rpeasants(r); - int money = rmoney(r); - int horses = rhorses(r); - int trees = rtrees(r, 2); - int saplings = rtrees(r, 1); - boolean mallorn = fval(r, RF_MALLORN)!=0; - - if (money) { - if (n>=size) return -1; - report_resource(result+n, "rm_money", money, -1); - ++n; - } - if (peasants) { - if (n>=size) return -1; - report_resource(result+n, "rm_peasant", peasants, -1); - ++n; - } - if (horses) { - if (n>=size) return -1; - report_resource(result+n, "rm_horse", horses, -1); - ++n; - } - if (saplings) { - if (n>=size) return -1; - report_resource(result+n, mallorn?"rm_mallornsapling":"rm_sapling", saplings, -1); - ++n; - } - if (trees) { - if (n>=size) return -1; - report_resource(result+n, mallorn?"rm_mallorn":"rm_tree", trees, -1); - ++n; - } - } - - if (sr->mode>=see_unit) { - rawmaterial * res = r->resources; - while (res) { - int maxskill = 0; - const item_type * itype = resource2item(res->type->rtype); - int level = res->level + itype->construction->minskill - 1; - int visible = -1; - if (res->type->visible==NULL) { - visible = res->amount; - level = res->level + itype->construction->minskill - 1; - } else { - const unit * u; - for (u=r->units; visible!=res->amount && u!=NULL; u=u->next) { - if (u->faction == viewer) { - int s = eff_skill(u, itype->construction->skill, r); - if (s>maxskill) { - maxskill = s; - visible = res->type->visible(res, maxskill); - } - } - } - } - if (level>=0 && visible>=0) { - if (n>=size) return -1; - report_resource(result+n, res->type->name, visible, level); - n++; - } - res = res->next; - } - } - return n; -} - -int -bufunit(const faction * f, const unit * u, int indent, int mode, char * buf, size_t size) -{ - int i, dh; - int getarnt = fval(u, UFL_ANON_FACTION); - const char *pzTmp, *str; - building * b; - boolean isbattle = (boolean)(mode == see_battle); - int telepath_see = 0; - attrib *a_fshidden = NULL; - item * itm; - item * show; - faction *fv = visible_faction(f, u); - char * bufp = buf; - boolean itemcloak = false; - static const curse_type * itemcloak_ct = 0; - static boolean init = false; - int bytes; - item result[MAX_INVENTORY]; - - if (!init) { - init = true; - itemcloak_ct = ct_find("itemcloak"); - } - if (itemcloak_ct!=NULL) { - itemcloak = curse_active(get_curse(u->attribs, itemcloak_ct)); - } - - bytes = (int)strlcpy(bufp, unitname(u), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (!isbattle) { - attrib *a_otherfaction = a_find(u->attribs, &at_otherfaction); - if (u->faction == f) { - if (fval(u, UFL_GROUP)) { - attrib *a = a_find(u->attribs, &at_group); - if (a) { - group * g = (group*)a->data.v; - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, groupid(g, f), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - if (getarnt) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, "anonymous"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else if (a_otherfaction) { - faction * otherfaction = get_otherfaction(a_otherfaction); - if (otherfaction) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, factionname(otherfaction), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - } else { - if (getarnt) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, "anonymous"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else { - if (a_otherfaction && alliedunit(u, f, HELP_FSTEALTH)) { - faction * f = get_otherfaction(a_otherfaction); - bytes = snprintf(bufp, size, ", %s (%s)", factionname(f), factionname(u->faction)); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, factionname(fv), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - } - } - - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (u->faction != f && a_fshidden && a_fshidden->data.ca[0] == 1 && effskill(u, SK_STEALTH) >= 6) { - bytes = (int)strlcpy(bufp, "? ", size); - } else { - bytes = snprintf(bufp, size, "%d ", u->number); - } - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - pzTmp = get_racename(u->attribs); - if (pzTmp) { - bytes = (int)strlcpy(bufp, pzTmp, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (u->faction==f && fval(u->race, RCF_SHAPESHIFTANY)) { - bytes = (int)strlcpy(bufp, " (", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, racename(f->locale, u, u->race), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (size>1) { - strcpy(bufp++, ")"); - --size; - } - } - } else { - const race * irace = u_irace(u); - bytes = (int)strlcpy(bufp, racename(f->locale, u, irace), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (u->faction==f && irace!=u->race) { - bytes = (int)strlcpy(bufp, " (", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, racename(f->locale, u, u->race), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (size>1) { - strcpy(bufp++, ")"); - --size; - } - } - } - - if (fval(u, UFL_HERO) && (u->faction == f || omniscient(f))) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, "hero"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - /* status */ - - if (u->number && (u->faction == f || telepath_see || isbattle)) { - const char * c = locale_string(f->locale, hp_status(u)); - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, report_kampfstatus(u, f->locale), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (c || fval(u, UFL_HUNGER)) { - bytes = (int)strlcpy(bufp, " (", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (c) { - bytes = (int)strlcpy(bufp, c, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (fval(u, UFL_HUNGER)) { - if (c) bytes = (int)strlcpy(bufp, ", hungert", size); - else bytes = (int)strlcpy(bufp, "hungert", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (size>1) { - strcpy(bufp++, ")"); - --size; - } - } - } - if (is_guard(u, GUARD_ALL)!=0) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, "unit_guards"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - - if ((b = usiege(u))!=NULL) { - bytes = (int)strlcpy(bufp, ", belagert ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, buildingname(b), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - - dh = 0; - if (u->faction == f || telepath_see) { - skill * sv; - for (sv = u->skills;sv!=u->skills+u->skill_size;++sv) { - bytes = (int)spskill(bufp, size, f->locale, u, sv, &dh, 1); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - - dh = 0; - if (f == u->faction || telepath_see || omniscient(f)) { - show = u->items; - } else if (!itemcloak && mode >= see_unit && !(a_fshidden - && a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) - { - int n = report_items(u->items, result, MAX_INVENTORY, u, f); - assert(n>=0); - if (n>0) show = result; - else show = NULL; - } else { - show = NULL; - } - for (itm=show; itm; itm=itm->next) { - const char * ic; - int in, bytes; - report_item(u, itm, f, &ic, NULL, &in, false); - if (in==0 || ic==NULL) continue; - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (!dh) { - bytes = snprintf(bufp, size, "%s: ", LOC(f->locale, "nr_inventory")); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - dh = 1; - } - if (in == 1) { - bytes = (int)strlcpy(bufp, ic, size); - } else { - bytes = snprintf(bufp, size, "%d %s", in, ic); - } - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - - if (u->faction == f || telepath_see) { - sc_mage * m = get_mage(u); - - if (m!=NULL) { - spell_list *slist = m->spells; - int t = effskill(u, SK_MAGIC); - int bytes = snprintf(bufp, size, ". Aura %d/%d", get_spellpoints(u), max_spellpoints(u->region,u)); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - for (dh=0; slist; slist=slist->next) { - spell * sp = slist->data; - if (sp->level > t) continue; - if (!dh) { - bytes = snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_spells")); - dh = 1; - } else { - bytes = (int)strlcpy(bufp, ", ", size); - } - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, spell_name(sp, f->locale), size); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - - for (i=0; i!=MAXCOMBATSPELLS; ++i) { - if (get_combatspell(u, i)) break; - } - if (i!=MAXCOMBATSPELLS) { - bytes = snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_combatspells")); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - dh = 0; - for (i = 0; i < MAXCOMBATSPELLS; i++){ - const spell *sp; - if (!dh){ - dh = 1; - } else { - bytes = (int)strlcpy(bufp, ", ", size); - if (bytes && wrptr(&bufp, &size, bytes)!=0) { - WARN_STATIC_BUFFER(); - } - } - sp = get_combatspell(u,i); - if (sp) { - int sl = get_combatspelllevel(u, i); - bytes = (int)strlcpy(bufp, spell_name(sp, u->faction->locale), size); - if (bytes && wrptr(&bufp, &size, bytes)!=0) { - WARN_STATIC_BUFFER(); - } - - if (sl > 0) { - bytes = snprintf(bufp, size, " (%d)", sl); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } else { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nospells"), size); - if (bytes && wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - } - } - if (!isbattle) { - boolean printed = 0; - order * ord;; - for (ord=u->old_orders;ord;ord=ord->next) { - if (is_repeated(ord)) { - if (printedorders;ord;ord=ord->next) { - if (is_repeated(ord)) { - if (printedlocale); - if (str) { - bytes = (int)strlcpy(bufp, "; ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - bytes = (int)strlcpy(bufp, str, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - i = str[strlen(str) - 1]; - } - if (i != '!' && i != '?' && i != '.') { - if (size>1) { - strcpy(bufp++, "."); - --size; - } - } - pzTmp = uprivate(u); - if (u->faction == f && pzTmp) { - bytes = (int)strlcpy(bufp, " (Bem: ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, pzTmp, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, ")", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - - dh=0; - if (!getarnt && f) { - if (alliedfaction(rplane(u->region), f, fv, HELP_ALL)) { - dh = 1; - } - } - if (size<=1) { - log_warning(("bufunit ran out of space after writing %u bytes.\n", (bufp-buf))); - } - return dh; -} - -/* TODO: telepath_see wird nicht berücksichtigt: Parteien mit - * telepath_see sollten immer einzelne Einheiten zu sehen - * bekommen, alles andere ist darstellungsteschnisch kompliziert. - */ - -size_t -spskill(char * buffer, size_t size, const struct locale * lang, const struct unit * u, struct skill * sv, int *dh, int days) -{ - char * bufp = buffer; - int i, effsk; - int bytes; - size_t tsize = 0; - - if (!u->number) return 0; - if (sv->level<=0) { - if (sv->old<=0 || (u->faction->options & want(O_SHOWSKCHANGE))==0) { - return 0; - } - } - - bytes = (int)strlcpy(bufp, ", ", size); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (!*dh) { - bytes = (int)strlcpy(bufp, LOC(lang, "nr_skills"), size); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - bytes = (int)strlcpy(bufp, ": ", size); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - *dh = 1; - } - bytes = (int)strlcpy(bufp, skillname(sv->id, lang), size); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - bytes = (int)strlcpy(bufp, " ", size); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (sv->id == SK_MAGIC){ - sc_mage * mage = get_mage(u); - if (mage && mage->magietyp != M_GRAY) { - bytes = (int)strlcpy(bufp, LOC(lang, mkname("school", magic_school[mage->magietyp])), size); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - bytes = (int)strlcpy(bufp, " ", size); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - - if (sv->id == SK_STEALTH && fval(u, UFL_STEALTH)) { - i = u_geteffstealth(u); - if (i>=0) { - bytes = slprintf(bufp, size, "%d/", i); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - - effsk = effskill(u, sv->id); - bytes = slprintf(bufp, size, "%d", effsk); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (u->faction->options & want(O_SHOWSKCHANGE)) { - int oldeff = 0; - int diff; - - if (sv->old > 0) { - oldeff = sv->old + get_modifier(u, sv->id, sv->old, u->region, false); - } - - oldeff = MAX(0, oldeff); - diff = effsk - oldeff; - - if (diff != 0) { - bytes = slprintf(bufp, size, " (%s%d)", (diff>0)?"+":"", diff); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - return tsize; -} - -void -lparagraph(struct strlist ** SP, char *s, int indent, char mark) -{ - - /* Die Liste SP wird mit dem String s aufgefuellt, mit indent und einer - * mark, falls angegeben. SP wurde also auf 0 gesetzt vor dem Aufruf. - * Vgl. spunit (). */ - - char *buflocal = calloc(strlen(s) + indent + 1, sizeof(char)); - - if (indent) { - memset(buflocal, ' ', indent); - if (mark) - buflocal[indent - 2] = mark; - } - strcpy(buflocal + indent, s); - addstrlist(SP, buflocal); - free(buflocal); -} - -void -spunit(struct strlist ** SP, const struct faction * f, const unit * u, int indent, - int mode) -{ - char buf[DISPLAYSIZE]; - int dh = bufunit(f, u, indent, mode, buf, sizeof(buf)); - lparagraph(SP, buf, indent, (char) ((u->faction == f) ? '*' : (dh ? '+' : '-'))); -} - -struct message * -msg_curse(const struct curse * c, const void * obj, typ_t typ, int self) -{ - if (c->type->curseinfo) { - /* if curseinfo returns NULL, then we don't want to tell the viewer anything. */ - return c->type->curseinfo(obj, typ, c, self); - } else { - message * msg = cinfo_simple(obj, typ, c, self); - if (msg==NULL) { - const char * unknown[] = { "unit_unknown", "region_unknown", "building_unknown", "ship_unknown" }; - msg = msg_message(mkname("curseinfo", unknown[typ]), "id", c->no); - log_error(("no curseinfo function for %s and no fallback either.\n", c->type->cname)); - } else { - log_error(("no curseinfo function for %s, using cinfo_simple fallback.\n", c->type->cname)); - } - return msg; - } -} - -const struct unit * -ucansee(const struct faction *f, const struct unit *u, const struct unit *x) -{ - if (cansee(f, u->region, u, 0)) return u; - return x; -} - -static void -add_faction(faction_list ** flist, faction * sf) -{ - faction_list ** fnew = flist; - while (*fnew && (*fnew)->data->no < sf->no) { - fnew =&(*fnew)->next; - } - if ((*fnew==NULL) || (*fnew)->data!=sf) { - faction_list * finsert = malloc(sizeof(faction_list)); - finsert->next = *fnew; - *fnew = finsert; - finsert->data = sf; - } -} - -int -stealth_modifier(int seen_mode) -{ - switch (seen_mode) { - case see_unit: - return 0; - case see_far: - case see_lighthouse: - return -2; - case see_travel: - return -1; - default: - return INT_MIN; - } -} - -static void -get_addresses(report_context * ctx) -{ -/* "TODO: travelthru" */ - seen_region * sr = NULL; - region *r; - const faction * lastf = NULL; - faction_list * flist = calloc(1, sizeof(faction_list)); - - flist->data = ctx->f; - - if (f_get_alliance(ctx->f)) { - faction_list * member = ctx->f->alliance->members; - for (;member;member=member->next) { - add_faction(&flist, member->data); - } - } - - for (r=ctx->first;sr==NULL && r!=ctx->last;r=r->next) { - sr = find_seen(ctx->seen, r); - } - - for (;sr!=NULL;sr=sr->next) { - int stealthmod = stealth_modifier(sr->mode); - r = sr->r; - if (sr->mode==see_lighthouse) { - unit * u = r->units; - for (;u;u=u->next) { - faction * sf = visible_faction(ctx->f, u); - if (lastf!=sf) { - if (u->building || u->ship || (stealthmod>INT_MIN && cansee(ctx->f, r, u, stealthmod))) { - add_faction(&flist, sf); - lastf = sf; - } - } - } - } else if (sr->mode==see_travel) { - unit * u = r->units; - while (u) { - faction * sf = visible_faction(ctx->f, u); - assert(u->faction!=ctx->f); /* if this is see_travel only, then I shouldn't be here. */ - if (lastf!=sf) { - attrib * a = a_find(r->attribs, &at_travelunit); - while (a && a->type==&at_travelunit) { - unit * u2 = (unit*)a->data.v; - if (u2->faction==ctx->f) { - if (cansee_unit(u2, u, stealthmod)) { - add_faction(&flist, sf); - lastf = sf; - break; - } - } - a = a->next; - } - } - u = u->next; - } - } else if (sr->mode>see_travel) { - const unit * u = r->units; - while (u!=NULL) { - if (u->faction!=ctx->f) { - faction * sf = visible_faction(ctx->f, u); - boolean ballied = sf && sf!=ctx->f && sf!=lastf - && !fval(u, UFL_ANON_FACTION) && cansee(ctx->f, r, u, stealthmod); - if (ballied || ALLIED(ctx->f, sf)) { - add_faction(&flist, sf); - lastf = sf; - } - } - u = u->next; - } - } - } - - if (f_get_alliance(ctx->f)) { - faction *f2; - for (f2 = factions; f2; f2 = f2->next) { - if (f2->alliance == ctx->f->alliance) { - add_faction(&flist, f2); - } - } - } - ctx->addresses = flist; -} - -#define MAXSEEHASH 0x1000 -seen_region * reuse; - -seen_region ** -seen_init(void) -{ - return (seen_region **)calloc(MAXSEEHASH, sizeof(seen_region*)); -} - -void -seen_done(seen_region * seehash[]) -{ - int i; - for (i=0;i!=MAXSEEHASH;++i) { - seen_region * sd = seehash[i]; - if (sd==NULL) continue; - while (sd->nextHash!=NULL) sd = sd->nextHash; - sd->nextHash = reuse; - reuse = seehash[i]; - seehash[i] = NULL; - } - // free(seehash); -} - -void -free_seen(void) -{ - while (reuse) { - seen_region * r = reuse; - reuse = reuse->nextHash; - free(r); - } -} - -void -link_seen(seen_region * seehash[], const region * first, const region * last) -{ - const region * r = first; - seen_region * sr = NULL; - - if (first==last) return; - - do { - sr = find_seen(seehash, r); - r = r->next; - } while (sr==NULL && r!=last); - - while (r!=last) { - seen_region * sn = find_seen(seehash, r); - if (sn!=NULL) { - sr->next = sn; - sr = sn; - } - r = r->next; - } - sr->next = 0; -} - -seen_region * -find_seen(struct seen_region * seehash[], const region * r) -{ - unsigned int index = reg_hashkey(r) & (MAXSEEHASH-1); - seen_region * find = seehash[index]; - while (find) { - if (find->r==r) return find; - find=find->nextHash; - } - return NULL; -} - -static void -get_seen_interval(report_context * ctx) -{ - /* this is required to find the neighbour regions of the ones we are in, - * which may well be outside of [firstregion, lastregion) */ - int i; - for (i=0;i!=MAXSEEHASH;++i) { - seen_region * sr = ctx->seen[i]; - while (sr!=NULL) { - if (ctx->first==NULL || sr->r->indexfirst->index) { - ctx->first = sr->r; - } - if (ctx->last!=NULL && sr->r->index>=ctx->last->index) { - ctx->last = sr->r->next; - } - sr = sr->nextHash; - } - } - link_seen(ctx->seen, ctx->first, ctx->last); -} - -boolean -add_seen(struct seen_region * seehash[], struct region * r, unsigned char mode, boolean dis) -{ - seen_region * find = find_seen(seehash, r); - if (find==NULL) { - unsigned int index = reg_hashkey(r) & (MAXSEEHASH-1); - if (!reuse) reuse = (seen_region*)calloc(1, sizeof(struct seen_region)); - find = reuse; - reuse = reuse->nextHash; - find->nextHash = seehash[index]; - seehash[index] = find; - find->r = r; - } else if (find->mode >= mode) { - return false; - } - find->mode = mode; - find->disbelieves |= dis; - return true; -} - -typedef struct report_type { - struct report_type * next; - report_fun write; - const char * extension; - int flag; -} report_type; - -static report_type * report_types; - -void -register_reporttype(const char * extension, report_fun write, int flag) -{ - report_type * type = malloc(sizeof(report_type)); - type->extension = extension; - type->write = write; - type->flag = flag; - type->next = report_types; - report_types = type; -} - -static region_list * -get_regions_distance(region * root, int radius) -{ - region_list * rptr, * rlist = NULL; - region_list ** rp = &rlist; - add_regionlist(rp, root); - fset(root, RF_MARK); - while (*rp) { - region_list * r = *rp; - direction_t d; - rp = &r->next; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(r->data, d); - if (rn!=NULL && !fval(rn, RF_MARK) && distance(rn, root)<=radius) { - add_regionlist(rp, rn); - fset(rn, RF_MARK); - } - } - } - for (rptr=rlist;rptr;rptr=rptr->next) { - freset(rptr->data, RF_MARK); - } - return rlist; -} - -static void -view_default(struct seen_region ** seen, region *r, faction *f) -{ - direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * r2 = rconnect(r, dir); - if (r2) { - connection * b = get_borders(r, r2); - while (b) { - if (!b->type->transparent(b, f)) break; - b = b->next; - } - if (!b) add_seen(seen, r2, see_neighbour, false); - } - } -} - -static void -view_neighbours(struct seen_region ** seen, region * r, faction * f) -{ - direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * r2 = rconnect(r, dir); - if (r2) { - connection * b = get_borders(r, r2); - while (b) { - if (!b->type->transparent(b, f)) break; - b = b->next; - } - if (!b) { - if (add_seen(seen, r2, see_far, false)) { - if (!(fval(r2->terrain, FORBIDDEN_REGION))) { - direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * r3 = rconnect(r2, dir); - if (r3) { - connection * b = get_borders(r2, r3); - while (b) { - if (!b->type->transparent(b, f)) break; - b = b->next; - } - if (!b) add_seen(seen, r3, see_neighbour, false); - } - } - } - } - } - } - } -} - -static void -recurse_regatta(struct seen_region ** seen, region *center, region *r, faction *f, int maxdist) -{ - direction_t dir; - int dist = distance(center, r); - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * r2 = rconnect(r, dir); - if (r2) { - int ndist = distance(center, r2); - if (ndist>dist && fval(r2->terrain, SEA_REGION)) { - connection * b = get_borders(r, r2); - while (b) { - if (!b->type->transparent(b, f)) break; - b = b->next; - } - if (!b) { - if (ndistunits; u; u=u->next) { - if (u->faction==f) { - int es = effskill(u, SK_PERCEPTION); - if (es>skill) skill=es; - } - } - recurse_regatta(seen, r, r, f, skill/2); -} - -static void -prepare_reports(void) -{ - region * r; - faction * f; - static const struct building_type * bt_lighthouse = NULL; - if (bt_lighthouse==NULL) bt_lighthouse = bt_find("lighthouse"); - - for (f = factions; f ; f = f->next) { - if (f->seen) seen_done(f->seen); - f->seen = seen_init(); - } - - for (r = regions; r ; r = r->next) { - attrib *ru; - unit * u; - plane * p = rplane(r); - - reorder_units(r); - - if (p) { - watcher * w = p->watchers; - for (;w;w=w->next) { - add_seen(w->faction->seen, r, w->mode, false); -#ifdef SMART_INTERVALS - update_interval(w->faction, r); -#endif - } - } - - for (u = r->units; u; u = u->next) { - if (u->building && u->building->type==bt_lighthouse) { - /* we are in a lighthouse. add the regions we can see from here! */ - int range = lighthouse_range(u->building, u->faction); - region_list * rlist = get_regions_distance(r, range); - region_list * rp = rlist; - - while (rp) { - region * rl = rp->data; - if (fval(rl->terrain, SEA_REGION)) { - direction_t d; - add_seen(u->faction->seen, rl, see_lighthouse, false); - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(rl, d); - if (rn!=NULL) { - add_seen(u->faction->seen, rn, see_neighbour, false); - } - } - } - rp = rp->next; - } - free_regionlist(rlist); - } - - if (u->race != new_race[RC_SPELL] || u->number == RS_FARVISION) { - if (fval(u, UFL_DISBELIEVES)) { - add_seen(u->faction->seen, r, see_unit, true); - } else { - add_seen(u->faction->seen, r, see_unit, false); - } - } - } - - if (fval(r, RF_TRAVELUNIT)) { - for (ru = a_find(r->attribs, &at_travelunit); ru && ru->type==&at_travelunit; ru = ru->next) { - unit * u = (unit*)ru->data.v; - - /* make sure the faction has not been removed this turn: */ - if (u->faction) { - add_seen(u->faction->seen, r, see_travel, false); - } - } - } - } -} - -static seen_region ** -prepare_report(faction * f) -{ - struct seen_region * sr; - region * r = firstregion(f); - region * last = lastregion(f); - - link_seen(f->seen, r, last); - - for (sr=NULL; sr==NULL && r!=last; r=r->next) { - sr = find_seen(f->seen, r); - } - - for (;sr!=NULL;sr=sr->next) { - if (sr->mode>see_neighbour) { - region * r = sr->r; - plane * p = rplane(r); - - void (*view)(struct seen_region **, region *, faction *) = view_default; - if (p && fval(p, PFL_SEESPECIAL)) { - attrib * a = a_find(p->attribs, &at_viewrange); - if (a) view = (void (*)(struct seen_region **, region *, faction *))a->data.f; - } - view(f->seen, r, f); - } - } - return f->seen; -} - -int -write_reports(faction * f, time_t ltime) -{ - int backup = 1, maxbackup = 128; - boolean gotit = false; - struct report_context ctx; - const char * encoding = "UTF-8"; - - if (noreports) { - return false; - } - ctx.f = f; - ctx.report_time = time(NULL); - ctx.seen = prepare_report(f); - ctx.first = firstregion(f); - ctx.last = lastregion(f); - ctx.addresses = NULL; - ctx.userdata = NULL; - get_seen_interval(&ctx); - get_addresses(&ctx); - - do { - report_type * rtype = report_types; - - errno = 0; - if (verbosity>=2) { - log_stdio(stdout, "Reports for %s:", factionname(f)); - } - for (;rtype!=NULL;rtype=rtype->next) { - if (f->options & rtype->flag) { - char filename[MAX_PATH]; - sprintf(filename, "%s/%d-%s.%s", reportpath(), turn, factionid(f), rtype->extension); - if (rtype->write(filename, &ctx, encoding)==0) { - gotit = true; - } - } - } - - if (errno) { - char zText[64]; - puts(" ERROR"); - sprintf(zText, "Waiting %u seconds before retry", backup); - perror(zText); - sleep(backup); - if (backup=2) { - puts(" DONE"); - } - } while (errno); - if (!gotit) { - log_warning(("No report for faction %s!\n", factionid(f))); - } - freelist(ctx.addresses); - seen_done(ctx.seen); - return 0; -} - -static void -nmr_warnings(void) -{ - faction *f,*fa; -#define FRIEND (HELP_GUARD|HELP_MONEY) - for (f=factions;f;f=f->next) { - if (!is_monsters(f) && (turn-f->lastorders) >= 2) { - message * msg = NULL; - for (fa=factions;fa;fa=fa->next) { - int warn = 0; - if (get_param_int(global.parameters, "rules.alliances", 0)!=0) { - if (f->alliance && f->alliance==fa->alliance) { - warn = 1; - } - } else if (alliedfaction(NULL, f, fa, FRIEND) && alliedfaction(NULL, fa, f, FRIEND)) { - warn = 1; - } - if (warn) { - if (msg==NULL) { - msg = msg_message("warn_dropout", "faction turns", f, turn - f->lastorders); - } - add_message(&fa->msgs, msg); - } - } - if (msg!=NULL) msg_release(msg); - } - } -} - -static void -report_donations(void) -{ - region * r; - for (r=regions;r;r=r->next) { - while (r->donations) { - donation * sp = r->donations; - if (sp->amount > 0) { - struct message * msg = msg_message("donation", - "from to amount", sp->f1, sp->f2, sp->amount); - r_addmessage(r, sp->f1, msg); - r_addmessage(r, sp->f2, msg); - msg_release(msg); - } - r->donations = sp->next; - free(sp); - } - } -} - -static void -write_script(FILE * F, const faction * f) -{ - report_type * rtype; - char buf[1024]; - - fprintf(F, "faction=%s:email=%s:lang=%s", factionid(f), f->email, locale_name(f->locale)); - if (f->options & (1<extension); - } - } - fputs(buf, F); - fputc('\n', F); -} - -int -init_reports(void) -{ - prepare_reports(); -#ifdef HAVE_STAT - { - stat_type st; - if (stat(reportpath(), &st)==0) return 0; - } -#endif - if (makedir(reportpath(), 0700)!=0) { - if (errno!=EEXIST) { - perror("could not create reportpath"); - return -1; - } - } - return 0; -} - -int -reports(void) -{ - faction *f; - FILE *mailit; - time_t ltime = time(NULL); - const char * str; - int retval = 0; - char path[MAX_PATH]; - - if (verbosity>=1) { - log_stdio(stdout, "Writing reports for turn %d:", turn); - } - nmr_warnings(); - report_donations(); - remove_empty_units(); - - sprintf(path, "%s/reports.txt", reportpath()); - mailit = fopen(path, "w"); - if (mailit == NULL) { - log_error(("%s could not be opened!\n", path)); - } - - for (f = factions; f; f = f->next) { - int error = write_reports(f, ltime); - if (error) retval = error; - if (mailit) write_script(mailit, f); - } - if (mailit) fclose(mailit); - free_seen(); - str = get_param(global.parameters, "globalreport"); -#ifdef GLOBAL_REPORT - if (str!=NULL) { - sprintf(path, "%s/%s.%u.cr", reportpath(), str, turn); - global_report(path); - } -#endif - return retval; -} - -static variant -var_copy_string(variant x) -{ - x.v = strdup((const char*)x.v); - return x; -} - -static void -var_free_string(variant x) -{ - free(x.v); -} - -static variant -var_copy_order(variant x) -{ - x.v = copy_order((order*)x.v); - return x; -} - -static void -var_free_order(variant x) -{ - free_order(x.v); -} - -static variant -var_copy_items(variant x) -{ - item * isrc; - resource * rdst = NULL, ** rptr = &rdst; - - for (isrc = (item*)x.v; isrc!=NULL; isrc=isrc->next) { - resource * res = malloc(sizeof(resource)); - res->number = isrc->number; - res->type = isrc->type->rtype; - *rptr = res; - rptr = &res->next; - } - *rptr = NULL; - x.v = rdst; - return x; -} - -static void -var_free_resources(variant x) -{ - resource * rsrc = (resource*)x.v; - while (rsrc) { - resource * res = rsrc->next; - free(rsrc); - rsrc = res; - } - x.v = 0; -} - -static void -var_free_regions(variant x) -{ - free(x.v); -} - -const char * -trailinto(const region * r, const struct locale * lang) -{ - char ref[32]; - const char * s; - if (r) { - const char * tname = terrain_name(r); - strcat(strcpy(ref, tname), "_trail"); - s = locale_string(lang, ref); - if (s && *s) { - if (strstr(s, "%s")) return s; - } - } - return "%s"; -} - -size_t -f_regionid(const region * r, const faction * f, char * buffer, size_t size) -{ - if (!r) { - strncpy(buffer, "(Chaos)", size); - } else { - plane * pl = rplane(r); - const char * name = pl?pl->name:0; - int nx = r->x, ny = r->y; - pnormalize(&nx, &ny, pl); - adjust_coordinates(f, &nx, &ny, pl, r); - strncpy(buffer, rname(r, f->locale), size); - buffer[size-1]=0; - sprintf(buffer+strlen(buffer), " (%d,%d%s%s)", nx, ny, name?",":"", (name)?name:""); - } - return strlen(buffer); -} - -static char * -f_regionid_s(const region * r, const faction * f) -{ - static int i = 0; - static char bufs[4][NAMESIZE + 20]; - char * buf = bufs[(++i)%4]; - - f_regionid(r, f, buf, NAMESIZE + 20); - return buf; -} - -/*** BEGIN MESSAGE RENDERING ***/ -static void -eval_localize(struct opstack ** stack, const void * userdata) /* (string, locale) -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct locale * lang = f?f->locale:default_locale; - const char *c = (const char *)opop_v(stack); - c = locale_string(lang, c); - opush_v(stack, strcpy(balloc(strlen(c)+1), c)); -} - -static void -eval_trailto(struct opstack ** stack, const void * userdata) /* (int, int) -> int */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct locale * lang = f?f->locale:default_locale; - const struct region * r = (const struct region*)opop(stack).v; - const char * trail = trailinto(r, lang); - const char * rn = f_regionid_s(r, f); - variant var; - char * x = var.v = balloc(strlen(trail)+strlen(rn)); - sprintf(x, trail, rn); - opush(stack, var); -} - -static void -eval_unit(struct opstack ** stack, const void * userdata) /* unit -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct unit * u = (const struct unit *)opop(stack).v; - const char * c = u?unitname(u):LOC(f->locale, "an_unknown_unit"); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_unit_dative(struct opstack ** stack, const void * userdata) /* unit -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct unit * u = (const struct unit *)opop(stack).v; - const char * c = u?unitname(u):LOC(f->locale, "unknown_unit_dative"); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_spell(struct opstack ** stack, const void * userdata) /* unit -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct spell * sp = (const struct spell *)opop(stack).v; - const char * c = sp?spell_name(sp, f->locale):LOC(f->locale, "an_unknown_spell"); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_curse(struct opstack ** stack, const void * userdata) /* unit -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct curse_type * sp = (const struct curse_type *)opop(stack).v; - const char * c = sp?curse_name(sp, f->locale):LOC(f->locale, "an_unknown_curse"); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_unitname(struct opstack ** stack, const void * userdata) /* unit -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct unit * u = (const struct unit *)opop(stack).v; - const char * c = u?u->name:LOC(f->locale, "an_unknown_unit"); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - - -static void -eval_unitid(struct opstack ** stack, const void * userdata) /* unit -> int */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct unit * u = (const struct unit *)opop(stack).v; - const char * c = u?u->name:LOC(f->locale, "an_unknown_unit"); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_unitsize(struct opstack ** stack, const void * userdata) /* unit -> int */ -{ - const struct unit * u = (const struct unit *)opop(stack).v; - variant var; - - var.i = u->number; - opush(stack, var); -} - -static void -eval_faction(struct opstack ** stack, const void * userdata) /* faction -> string */ -{ - const struct faction * f = (const struct faction *)opop(stack).v; - const char * c = factionname(f); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_alliance(struct opstack ** stack, const void * userdata) /* faction -> string */ -{ - const struct alliance * al = (const struct alliance *)opop(stack).v; - const char * c = alliancename(al); - variant var; - if (c!=NULL) { - size_t len = strlen(c); - var.v = strcpy(balloc(len+1), c); - } - else var.v = NULL; - opush(stack, var); -} - -static void -eval_region(struct opstack ** stack, const void * userdata) /* region -> string */ -{ - char name[NAMESIZE+32]; - const struct faction * f = (const struct faction *)userdata; - const struct region * r = (const struct region *)opop(stack).v; - const char * c = write_regionname(r, f, name, sizeof(name)); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_terrain(struct opstack ** stack, const void * userdata) /* region -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct region * r = (const struct region *)opop(stack).v; - const char * c = LOC(f->locale, terrain_name(r)); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_ship(struct opstack ** stack, const void * userdata) /* ship -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct ship * u = (const struct ship *)opop(stack).v; - const char * c = u?shipname(u):LOC(f->locale, "an_unknown_ship"); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_building(struct opstack ** stack, const void * userdata) /* building -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct building * u = (const struct building *)opop(stack).v; - const char * c = u?buildingname(u):LOC(f->locale, "an_unknown_building"); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_weight(struct opstack ** stack, const void * userdata) /* region -> string */ -{ - char buffer[32]; - const struct faction * f = (const struct faction *)userdata; - const struct locale * lang = f->locale; - int weight = opop_i(stack); - variant var; - - if (weight % SCALEWEIGHT == 0) { - if (weight==SCALEWEIGHT) { - sprintf(buffer, "1 %s", LOC(lang, "weight_unit")); - } else { - sprintf(buffer, "%u %s", weight/SCALEWEIGHT, LOC(lang, "weight_unit_p")); - } - } else { - if (weight==1) { - sprintf(buffer, "1 %s %u", LOC(lang, "weight_per"), SCALEWEIGHT); - } else { - sprintf(buffer, "%u %s %u", weight, LOC(lang, "weight_per_p"), SCALEWEIGHT); - } - } - - var.v = strcpy(balloc(strlen(buffer)+1), buffer); - opush(stack, var); -} - -static void -eval_resource(struct opstack ** stack, const void * userdata) -{ - const faction * report = (const faction*)userdata; - const struct locale * lang = report?report->locale:default_locale; - int j = opop(stack).i; - const struct resource_type * res = (const struct resource_type *)opop(stack).v; - const char * c = LOC(lang, resourcename(res, j!=1)); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_race(struct opstack ** stack, const void * userdata) -{ - const faction * report = (const faction*)userdata; - const struct locale * lang = report?report->locale:default_locale; - int j = opop(stack).i; - const race * r = (const race *)opop(stack).v; - const char * c = LOC(lang, rc_name(r, j!=1)); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_order(struct opstack ** stack, const void * userdata) /* order -> string */ -{ - const struct order * ord = (const struct order *)opop(stack).v; - static char buf[256]; - size_t len; - variant var; - - unused(userdata); - write_order(ord, buf, sizeof(buf)); - len = strlen(buf); - var.v = strcpy(balloc(len+1), buf); - opush(stack, var); -} - -static void -eval_resources(struct opstack ** stack, const void * userdata) /* order -> string */ -{ - const faction * report = (const faction*)userdata; - const struct locale * lang = report?report->locale:default_locale; - const struct resource * res = (const struct resource *)opop(stack).v; - static char buf[1024]; /* but we only use about half of this */ - size_t size = sizeof(buf) - 1; - variant var; - - char * bufp = buf; - while (res!=NULL && size > 4) { - const char * rname = resourcename(res->type, (res->number!=1)?NMF_PLURAL:0); - int bytes = snprintf(bufp, size, "%d %s", res->number, LOC(lang, rname)); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0 || sizenext; - if (res!=NULL && size>2) { - strcat(bufp, ", "); - bufp += 2; - size -= 2; - } - } - *bufp = 0; - var.v = strcpy(balloc(bufp-buf+1), buf); - opush(stack, var); -} - -static void -eval_regions(struct opstack ** stack, const void * userdata) /* order -> string */ -{ - const faction * report = (const faction*)userdata; - int i = opop(stack).i; - int end, begin = opop(stack).i; - const arg_regions * regions = (const arg_regions *)opop(stack).v; - static char buf[256]; - size_t size = sizeof(buf) - 1; - variant var; - char * bufp = buf; - - if (regions==NULL) { - end = begin; - } else { - if (i>=0) end = begin+i; - else end = regions->nregions+i; - } - for (i=begin;iregions[i], report); - int bytes = (int)strlcpy(bufp, rname, size); - if (bytes && wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (i+12) { - strcat(bufp, ", "); - bufp += 2; - size -= 2; - } - } - *bufp = 0; - var.v = strcpy(balloc(bufp-buf+1), buf); - opush(stack, var); -} - -static void -eval_trail(struct opstack ** stack, const void * userdata) /* order -> string */ -{ - const faction * report = (const faction*)userdata; - const struct locale * lang = report?report->locale:default_locale; - int i, end = 0, begin = 0; - const arg_regions * regions = (const arg_regions *)opop(stack).v; - static char buf[512]; - size_t size = sizeof(buf) - 1; - variant var; - char * bufp = buf; -#ifdef _SECURECRT_ERRCODE_VALUES_DEFINED - /* stupid MS broke snprintf */ - int eold = errno; -#endif - - if (regions!=NULL) { - end = regions->nregions; - for (i=begin;iregions[i]; - const char * trail = trailinto(r, lang); - const char * rn = f_regionid_s(r, report); - int bytes = snprintf(bufp, size, trail, rn); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (i+2locale:default_locale; - int i = opop(stack).i; - const char * c = LOC(lang, (i>=0)?directions[i]:"unknown_direction"); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_skill(struct opstack ** stack, const void * userdata) -{ - const faction * report = (const faction*)userdata; - const struct locale * lang = report?report->locale:default_locale; - skill_t sk = (skill_t)opop(stack).i; - const char * c = skillname(sk, lang); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_int36(struct opstack ** stack, const void * userdata) -{ - int i = opop(stack).i; - const char * c = itoa36(i); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); - unused(userdata); -} -/*** END MESSAGE RENDERING ***/ - -#include - -static void log_orders(const struct message * msg) -{ - faction * f = get_monsters(); - char buffer[4096]; - int i; - - for (i=0;i!=msg->type->nparameters;++i) { - if (msg->type->types[i]->copy==&var_copy_order) { - const char * section = nr_section(msg); - nr_render(msg, f?f->locale:default_locale, buffer, sizeof(buffer), f); - log_printf("MESSAGE [%s]: %s\n", section, buffer); - break; - } - } -} - -int -report_action(region * r, unit * actor, message * msg, int flags) -{ - int result = 0; - unit * u; - int view = flags&(ACTION_CANSEE|ACTION_CANNOTSEE); - - /* melden, 1x pro Partei */ - if (flags&ACTION_RESET) { - freset(actor->faction, FFL_SELECT); - for (u = r->units; u; u = u->next ) freset(u->faction, FFL_SELECT); - } - if (view) { - for (u = r->units; u; u = u->next ) { - if (!fval(u->faction, FFL_SELECT) ) { - boolean show = u->faction == actor->faction; - fset(u->faction, FFL_SELECT); - if (view==ACTION_CANSEE) { - /* Bei Fernzaubern sieht nur die eigene Partei den Magier */ - show = show || (r==actor->region && cansee(u->faction, r, actor, 0)); - } else if (view==ACTION_CANNOTSEE) { - show = !show && !(r==actor->region && cansee(u->faction, r, actor, 0)); - } else { - /* the unliely (or lazy) case */ - show = true; - } - - if (show) { - r_addmessage(r, u->faction, msg); - } else { /* Partei des Magiers, sieht diesen immer */ - result = 1; - } - } - } - /* Ist niemand von der Partei des Magiers in der Region, dem Magier - * nochmal gesondert melden */ - if ((flags&ACTION_CANSEE) && !fval(actor->faction, FFL_SELECT)) { - add_message(&actor->faction->msgs, msg); - } - } - return result; -} - - -void -register_reports(void) -{ - /* register datatypes for the different message objects */ - register_argtype("alliance", NULL, NULL, VAR_VOIDPTR); - register_argtype("building", NULL, NULL, VAR_VOIDPTR); - register_argtype("direction", NULL, NULL, VAR_INT); - register_argtype("faction", NULL, NULL, VAR_VOIDPTR); - register_argtype("race", NULL, NULL, VAR_VOIDPTR); - register_argtype("region", NULL, NULL, VAR_VOIDPTR); - register_argtype("resource", NULL, NULL, VAR_VOIDPTR); - register_argtype("ship", NULL, NULL, VAR_VOIDPTR); - register_argtype("skill", NULL, NULL, VAR_VOIDPTR); - register_argtype("spell", NULL, NULL, VAR_VOIDPTR); - register_argtype("curse", NULL, NULL, VAR_VOIDPTR); - register_argtype("unit", NULL, NULL, VAR_VOIDPTR); - register_argtype("int", NULL, NULL, VAR_INT); - register_argtype("string", var_free_string, var_copy_string, VAR_VOIDPTR); - register_argtype("order", var_free_order, var_copy_order, VAR_VOIDPTR); - register_argtype("resources", var_free_resources, NULL, VAR_VOIDPTR); - register_argtype("items", var_free_resources, var_copy_items, VAR_VOIDPTR); - register_argtype("regions", var_free_regions, NULL, VAR_VOIDPTR); - - - msg_log_create = &log_orders; - - /* register functions that turn message contents to readable strings */ - add_function("alliance", &eval_alliance); - add_function("region", &eval_region); - add_function("terrain", &eval_terrain); - add_function("weight", &eval_weight); - add_function("resource", &eval_resource); - add_function("race", &eval_race); - add_function("faction", &eval_faction); - add_function("ship", &eval_ship); - add_function("unit", &eval_unit); - add_function("unit.dative", &eval_unit_dative); - add_function("unit.name", &eval_unitname); - add_function("unit.id", &eval_unitid); - add_function("unit.size", &eval_unitsize); - add_function("building", &eval_building); - add_function("skill", &eval_skill); - add_function("order", &eval_order); - add_function("direction", &eval_direction); - add_function("int36", &eval_int36); - add_function("trailto", &eval_trailto); - add_function("localize", &eval_localize); - add_function("spell", &eval_spell); - add_function("curse", &eval_curse); - add_function("resources", &eval_resources); - add_function("regions", &eval_regions); - add_function("trail", &eval_trail); - - /* register alternative visibility functions */ - register_function((pf_generic)view_neighbours, "view_neighbours"); - register_function((pf_generic)view_regatta, "view_regatta"); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "reports.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include +#include + +/* attributes includes */ +#include +#include +#include +#include + +boolean nocr = false; +boolean nonr = false; +boolean noreports = false; + +const char * visibility[] = { + "none", + "neighbour", + "lighthouse", + "travel", + "far", + "unit", + "battle" +}; + +const char *coasts[MAXDIRECTIONS] = +{ + "coast::nw", + "coast::ne", + "coast::e", + "coast::se", + "coast::sw", + "coast::w" +}; + +static char * +groupid(const struct group * g, const struct faction * f) +{ + typedef char name[OBJECTIDSIZE + 1]; + static name idbuf[8]; + static int nextbuf = 0; + char *buf = idbuf[(++nextbuf) % 8]; + sprintf(buf, "%s (%s)", g->name, factionid(f)); + return buf; +} + +const char * combatstatus[] = { + "status_aggressive", "status_front", + "status_rear", "status_defensive", + "status_avoid", "status_flee" +}; + +const char * +report_kampfstatus(const unit * u, const struct locale * lang) +{ + static char fsbuf[64]; + + strlcpy(fsbuf, LOC(lang, combatstatus[u->status]), sizeof(fsbuf)); + if (fval(u, UFL_NOAID)) { + strcat(fsbuf, ", "); + strcat(fsbuf, LOC(lang, "status_noaid")); + } + + return fsbuf; +} + +const char * +hp_status(const unit * u) +{ + double p = (double) ((double) u->hp / (double) (u->number * unit_max_hp(u))); + + if (p > 2.00) return mkname("damage", "critical"); + if (p > 1.50) return mkname("damage", "heavily"); + if (p < 0.50) return mkname("damage", "badly"); + if (p < 0.75) return mkname("damage", "wounded"); + if (p < 0.99) return mkname("damage", "exhausted"); + + return NULL; +} + +void +report_item(const unit * owner, const item * i, const faction * viewer, const char ** name, const char ** basename, int * number, boolean singular) +{ + assert(!owner || owner->number); + if (owner && owner->faction == viewer) { + if (name) *name = locale_string(viewer->locale, resourcename(i->type->rtype, ((i->number!=1 && !singular)?GR_PLURAL:0))); + if (basename) *basename = resourcename(i->type->rtype, 0); + if (number) *number = i->number; + } else if (owner && i->type->rtype==r_silver) { + int pp = i->number/owner->number; + if (number) *number = 1; + if (pp > 50000 && dragonrace(owner->race)) { + if (name) *name = locale_string(viewer->locale, "dragonhoard"); + if (basename) *basename = "dragonhoard"; + } else if (pp > 5000) { + if (name) *name = locale_string(viewer->locale, "moneychest"); + if (basename) *basename = "moneychest"; + } else if (pp > 500) { + if (name) *name = locale_string(viewer->locale, "moneybag"); + if (basename) *basename = "moneybag"; + } else { + if (number) *number = 0; + if (name) *name = NULL; + if (basename) *basename = NULL; + } + } else { + if (name) *name = locale_string(viewer->locale, resourcename(i->type->rtype, NMF_APPEARANCE|((i->number!=1 && !singular)?GR_PLURAL:0))); + if (basename) *basename = resourcename(i->type->rtype, NMF_APPEARANCE); + if (number) { + if (fval(i->type, ITF_HERB)) *number = 1; + else *number = i->number; + } + } +} + + +int * nmrs = NULL; + +int +update_nmrs(void) +{ + int i, newplayers =0; + faction *f; + int turn = global.data_turn; + + if (nmrs==NULL) nmrs = malloc(sizeof(int)*(NMRTimeout()+1)); + for (i = 0; i <= NMRTimeout(); ++i) { + nmrs[i] = 0; + } + + for (f = factions; f; f = f->next) { + if (fval(f, FFL_ISNEW)) { + ++newplayers; + } else if (!is_monsters(f) && f->alive) { + int nmr = turn-f->lastorders+1; + if (nmr<0 || nmr>NMRTimeout()) { + log_error(("faction %s has %d NMRS\n", factionid(f), nmr)); + nmr = MAX(0, nmr); + nmr = MIN(nmr, NMRTimeout()); + } + ++nmrs[nmr]; + } + } + return newplayers; +} + +#define ORDERS_IN_NR 1 +static size_t +buforder(char * bufp, size_t size, const order * ord, int mode) +{ + size_t tsize = 0; + int bytes; + + bytes = (int)strlcpy(bufp, ", \"", size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (mode1) { + *bufp++ ='\"'; + --size; + } else { + WARN_STATIC_BUFFER(); + } + ++tsize; + + return tsize; +} + +/** create a report of a list of items to a non-owner. + * \param result: an array of size items. + * \param size: maximum number of items to return + * \param owner: the owner of the items, or NULL for faction::items etc. + * \param viewer: the faction looking at the items + */ +int +report_items(const item * items, item * result, int size, const unit * owner, const faction * viewer) +{ + const item * itm; + int n = 0; /* number of results */ + + assert(owner==NULL || viewer!=owner->faction || !"not required for owner=viewer!"); + assert(size); + + for (itm=items;itm;itm=itm->next) { + item * ishow; + const char * ic; + + report_item(owner, itm, viewer, NULL, &ic, NULL, false); + if (ic && *ic) { + for (ishow = result; ishow!=result+n; ++ishow) { + const char * sc; + + if (ishow->type==itm->type) sc = ic; + else report_item(owner, ishow, viewer, NULL, &sc, NULL, false); + if (sc==ic || strcmp(sc, ic)==0) { + ishow->number+=itm->number; + break; + } + } + if (ishow==result+n) { + if (n==size) { + log_error(("too many items to report, increase buffer size.\n")); + return -1; + } + result[n].number = itm->number; + result[n].type = itm->type; + result[n].next = (n+1==size)?NULL:result+n+1; + ++n; + } + } + } + if (n>0) result[n-1].next = NULL; + return n; +} + +static void +report_resource(resource_report * result, const char * name, int number, int level) +{ + result->name = name; + result->number = number; + result->level = level; +} + +void +report_race(const struct unit * u, const char ** name, const char ** illusion) +{ + if (illusion) { + const race * irace = u_irace(u); + if (irace && irace!=u->race) { + *illusion = irace->_name[0]; + } + else { + *illusion = NULL; + } + } + if (name) { + *name = u->race->_name[0]; + if (fval(u->race, RCF_SHAPESHIFTANY)) { + const char * str = get_racename(u->attribs); + if (str) *name = str; + } + } +} + +void +report_building(const struct building * b, const char ** name, const char ** illusion) +{ + static int init; + static const struct building_type * bt_illusion; + + if (name) { + *name = buildingtype(b->type, b, b->size); + } + if (illusion) { + *illusion = NULL; + + if (!init) { + bt_illusion = bt_find("illusioncastle"); + init = 1; + } + if (bt_illusion && b->type==bt_illusion) { + const attrib * a = a_findc(b->attribs, &at_icastle); + if (a!=NULL) { + icastle_data * icastle = (icastle_data*)a->data.v; + *illusion = buildingtype(icastle->type, b, b->size); + } + } + } +} + +int +report_resources(const seen_region * sr, resource_report * result, int size, const faction * viewer) +{ + const region * r = sr->r; + int n = 0; + + if (r->land) { + int peasants = rpeasants(r); + int money = rmoney(r); + int horses = rhorses(r); + int trees = rtrees(r, 2); + int saplings = rtrees(r, 1); + boolean mallorn = fval(r, RF_MALLORN)!=0; + + if (money) { + if (n>=size) return -1; + report_resource(result+n, "rm_money", money, -1); + ++n; + } + if (peasants) { + if (n>=size) return -1; + report_resource(result+n, "rm_peasant", peasants, -1); + ++n; + } + if (horses) { + if (n>=size) return -1; + report_resource(result+n, "rm_horse", horses, -1); + ++n; + } + if (saplings) { + if (n>=size) return -1; + report_resource(result+n, mallorn?"rm_mallornsapling":"rm_sapling", saplings, -1); + ++n; + } + if (trees) { + if (n>=size) return -1; + report_resource(result+n, mallorn?"rm_mallorn":"rm_tree", trees, -1); + ++n; + } + } + + if (sr->mode>=see_unit) { + rawmaterial * res = r->resources; + while (res) { + int maxskill = 0; + const item_type * itype = resource2item(res->type->rtype); + int level = res->level + itype->construction->minskill - 1; + int visible = -1; + if (res->type->visible==NULL) { + visible = res->amount; + level = res->level + itype->construction->minskill - 1; + } else { + const unit * u; + for (u=r->units; visible!=res->amount && u!=NULL; u=u->next) { + if (u->faction == viewer) { + int s = eff_skill(u, itype->construction->skill, r); + if (s>maxskill) { + maxskill = s; + visible = res->type->visible(res, maxskill); + } + } + } + } + if (level>=0 && visible>=0) { + if (n>=size) return -1; + report_resource(result+n, res->type->name, visible, level); + n++; + } + res = res->next; + } + } + return n; +} + +int +bufunit(const faction * f, const unit * u, int indent, int mode, char * buf, size_t size) +{ + int i, dh; + int getarnt = fval(u, UFL_ANON_FACTION); + const char *pzTmp, *str; + building * b; + boolean isbattle = (boolean)(mode == see_battle); + int telepath_see = 0; + attrib *a_fshidden = NULL; + item * itm; + item * show; + faction *fv = visible_faction(f, u); + char * bufp = buf; + boolean itemcloak = false; + static const curse_type * itemcloak_ct = 0; + static boolean init = false; + int bytes; + item result[MAX_INVENTORY]; + + if (!init) { + init = true; + itemcloak_ct = ct_find("itemcloak"); + } + if (itemcloak_ct!=NULL) { + itemcloak = curse_active(get_curse(u->attribs, itemcloak_ct)); + } + + bytes = (int)strlcpy(bufp, unitname(u), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (!isbattle) { + attrib *a_otherfaction = a_find(u->attribs, &at_otherfaction); + if (u->faction == f) { + if (fval(u, UFL_GROUP)) { + attrib *a = a_find(u->attribs, &at_group); + if (a) { + group * g = (group*)a->data.v; + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, groupid(g, f), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + if (getarnt) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "anonymous"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else if (a_otherfaction) { + faction * otherfaction = get_otherfaction(a_otherfaction); + if (otherfaction) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, factionname(otherfaction), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + } else { + if (getarnt) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "anonymous"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else { + if (a_otherfaction && alliedunit(u, f, HELP_FSTEALTH)) { + faction * f = get_otherfaction(a_otherfaction); + bytes = snprintf(bufp, size, ", %s (%s)", factionname(f), factionname(u->faction)); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, factionname(fv), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + } + } + + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (u->faction != f && a_fshidden && a_fshidden->data.ca[0] == 1 && effskill(u, SK_STEALTH) >= 6) { + bytes = (int)strlcpy(bufp, "? ", size); + } else { + bytes = snprintf(bufp, size, "%d ", u->number); + } + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + pzTmp = get_racename(u->attribs); + if (pzTmp) { + bytes = (int)strlcpy(bufp, pzTmp, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (u->faction==f && fval(u->race, RCF_SHAPESHIFTANY)) { + bytes = (int)strlcpy(bufp, " (", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, racename(f->locale, u, u->race), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (size>1) { + strcpy(bufp++, ")"); + --size; + } + } + } else { + const race * irace = u_irace(u); + bytes = (int)strlcpy(bufp, racename(f->locale, u, irace), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (u->faction==f && irace!=u->race) { + bytes = (int)strlcpy(bufp, " (", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, racename(f->locale, u, u->race), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (size>1) { + strcpy(bufp++, ")"); + --size; + } + } + } + + if (fval(u, UFL_HERO) && (u->faction == f || omniscient(f))) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "hero"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + /* status */ + + if (u->number && (u->faction == f || telepath_see || isbattle)) { + const char * c = locale_string(f->locale, hp_status(u)); + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, report_kampfstatus(u, f->locale), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (c || fval(u, UFL_HUNGER)) { + bytes = (int)strlcpy(bufp, " (", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (c) { + bytes = (int)strlcpy(bufp, c, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (fval(u, UFL_HUNGER)) { + if (c) bytes = (int)strlcpy(bufp, ", hungert", size); + else bytes = (int)strlcpy(bufp, "hungert", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (size>1) { + strcpy(bufp++, ")"); + --size; + } + } + } + if (is_guard(u, GUARD_ALL)!=0) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "unit_guards"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + if ((b = usiege(u))!=NULL) { + bytes = (int)strlcpy(bufp, ", belagert ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, buildingname(b), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + dh = 0; + if (u->faction == f || telepath_see) { + skill * sv; + for (sv = u->skills;sv!=u->skills+u->skill_size;++sv) { + bytes = (int)spskill(bufp, size, f->locale, u, sv, &dh, 1); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + + dh = 0; + if (f == u->faction || telepath_see || omniscient(f)) { + show = u->items; + } else if (!itemcloak && mode >= see_unit && !(a_fshidden + && a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) + { + int n = report_items(u->items, result, MAX_INVENTORY, u, f); + assert(n>=0); + if (n>0) show = result; + else show = NULL; + } else { + show = NULL; + } + for (itm=show; itm; itm=itm->next) { + const char * ic; + int in, bytes; + report_item(u, itm, f, &ic, NULL, &in, false); + if (in==0 || ic==NULL) continue; + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (!dh) { + bytes = snprintf(bufp, size, "%s: ", LOC(f->locale, "nr_inventory")); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + dh = 1; + } + if (in == 1) { + bytes = (int)strlcpy(bufp, ic, size); + } else { + bytes = snprintf(bufp, size, "%d %s", in, ic); + } + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + if (u->faction == f || telepath_see) { + sc_mage * m = get_mage(u); + + if (m!=NULL) { + spell_list *slist = m->spells; + int t = effskill(u, SK_MAGIC); + int bytes = snprintf(bufp, size, ". Aura %d/%d", get_spellpoints(u), max_spellpoints(u->region,u)); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + for (dh=0; slist; slist=slist->next) { + spell * sp = slist->data; + if (sp->level > t) continue; + if (!dh) { + bytes = snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_spells")); + dh = 1; + } else { + bytes = (int)strlcpy(bufp, ", ", size); + } + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, spell_name(sp, f->locale), size); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + for (i=0; i!=MAXCOMBATSPELLS; ++i) { + if (get_combatspell(u, i)) break; + } + if (i!=MAXCOMBATSPELLS) { + bytes = snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_combatspells")); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + dh = 0; + for (i = 0; i < MAXCOMBATSPELLS; i++){ + const spell *sp; + if (!dh){ + dh = 1; + } else { + bytes = (int)strlcpy(bufp, ", ", size); + if (bytes && wrptr(&bufp, &size, bytes)!=0) { + WARN_STATIC_BUFFER(); + } + } + sp = get_combatspell(u,i); + if (sp) { + int sl = get_combatspelllevel(u, i); + bytes = (int)strlcpy(bufp, spell_name(sp, u->faction->locale), size); + if (bytes && wrptr(&bufp, &size, bytes)!=0) { + WARN_STATIC_BUFFER(); + } + + if (sl > 0) { + bytes = snprintf(bufp, size, " (%d)", sl); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } else { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nospells"), size); + if (bytes && wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + } + } + if (!isbattle) { + boolean printed = 0; + order * ord;; + for (ord=u->old_orders;ord;ord=ord->next) { + if (is_repeated(ord)) { + if (printedorders;ord;ord=ord->next) { + if (is_repeated(ord)) { + if (printedlocale); + if (str) { + bytes = (int)strlcpy(bufp, "; ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + bytes = (int)strlcpy(bufp, str, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + i = str[strlen(str) - 1]; + } + if (i != '!' && i != '?' && i != '.') { + if (size>1) { + strcpy(bufp++, "."); + --size; + } + } + pzTmp = uprivate(u); + if (u->faction == f && pzTmp) { + bytes = (int)strlcpy(bufp, " (Bem: ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, pzTmp, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, ")", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + dh=0; + if (!getarnt && f) { + if (alliedfaction(rplane(u->region), f, fv, HELP_ALL)) { + dh = 1; + } + } + if (size<=1) { + log_warning(("bufunit ran out of space after writing %u bytes.\n", (bufp-buf))); + } + return dh; +} + +/* TODO: telepath_see wird nicht berücksichtigt: Parteien mit + * telepath_see sollten immer einzelne Einheiten zu sehen + * bekommen, alles andere ist darstellungsteschnisch kompliziert. + */ + +size_t +spskill(char * buffer, size_t size, const struct locale * lang, const struct unit * u, struct skill * sv, int *dh, int days) +{ + char * bufp = buffer; + int i, effsk; + int bytes; + size_t tsize = 0; + + if (!u->number) return 0; + if (sv->level<=0) { + if (sv->old<=0 || (u->faction->options & want(O_SHOWSKCHANGE))==0) { + return 0; + } + } + + bytes = (int)strlcpy(bufp, ", ", size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (!*dh) { + bytes = (int)strlcpy(bufp, LOC(lang, "nr_skills"), size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + bytes = (int)strlcpy(bufp, ": ", size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + *dh = 1; + } + bytes = (int)strlcpy(bufp, skillname(sv->id, lang), size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + bytes = (int)strlcpy(bufp, " ", size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (sv->id == SK_MAGIC){ + sc_mage * mage = get_mage(u); + if (mage && mage->magietyp != M_GRAY) { + bytes = (int)strlcpy(bufp, LOC(lang, mkname("school", magic_school[mage->magietyp])), size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + bytes = (int)strlcpy(bufp, " ", size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + + if (sv->id == SK_STEALTH && fval(u, UFL_STEALTH)) { + i = u_geteffstealth(u); + if (i>=0) { + bytes = slprintf(bufp, size, "%d/", i); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + + effsk = effskill(u, sv->id); + bytes = slprintf(bufp, size, "%d", effsk); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (u->faction->options & want(O_SHOWSKCHANGE)) { + int oldeff = 0; + int diff; + + if (sv->old > 0) { + oldeff = sv->old + get_modifier(u, sv->id, sv->old, u->region, false); + } + + oldeff = MAX(0, oldeff); + diff = effsk - oldeff; + + if (diff != 0) { + bytes = slprintf(bufp, size, " (%s%d)", (diff>0)?"+":"", diff); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + return tsize; +} + +void +lparagraph(struct strlist ** SP, char *s, int indent, char mark) +{ + + /* Die Liste SP wird mit dem String s aufgefuellt, mit indent und einer + * mark, falls angegeben. SP wurde also auf 0 gesetzt vor dem Aufruf. + * Vgl. spunit (). */ + + char *buflocal = calloc(strlen(s) + indent + 1, sizeof(char)); + + if (indent) { + memset(buflocal, ' ', indent); + if (mark) + buflocal[indent - 2] = mark; + } + strcpy(buflocal + indent, s); + addstrlist(SP, buflocal); + free(buflocal); +} + +void +spunit(struct strlist ** SP, const struct faction * f, const unit * u, int indent, + int mode) +{ + char buf[DISPLAYSIZE]; + int dh = bufunit(f, u, indent, mode, buf, sizeof(buf)); + lparagraph(SP, buf, indent, (char) ((u->faction == f) ? '*' : (dh ? '+' : '-'))); +} + +struct message * +msg_curse(const struct curse * c, const void * obj, typ_t typ, int self) +{ + if (c->type->curseinfo) { + /* if curseinfo returns NULL, then we don't want to tell the viewer anything. */ + return c->type->curseinfo(obj, typ, c, self); + } else { + message * msg = cinfo_simple(obj, typ, c, self); + if (msg==NULL) { + const char * unknown[] = { "unit_unknown", "region_unknown", "building_unknown", "ship_unknown" }; + msg = msg_message(mkname("curseinfo", unknown[typ]), "id", c->no); + log_error(("no curseinfo function for %s and no fallback either.\n", c->type->cname)); + } else { + log_error(("no curseinfo function for %s, using cinfo_simple fallback.\n", c->type->cname)); + } + return msg; + } +} + +const struct unit * +ucansee(const struct faction *f, const struct unit *u, const struct unit *x) +{ + if (cansee(f, u->region, u, 0)) return u; + return x; +} + +static void +add_faction(faction_list ** flist, faction * sf) +{ + faction_list ** fnew = flist; + while (*fnew && (*fnew)->data->no < sf->no) { + fnew =&(*fnew)->next; + } + if ((*fnew==NULL) || (*fnew)->data!=sf) { + faction_list * finsert = malloc(sizeof(faction_list)); + finsert->next = *fnew; + *fnew = finsert; + finsert->data = sf; + } +} + +int +stealth_modifier(int seen_mode) +{ + switch (seen_mode) { + case see_unit: + return 0; + case see_far: + case see_lighthouse: + return -2; + case see_travel: + return -1; + default: + return INT_MIN; + } +} + +static void +get_addresses(report_context * ctx) +{ +/* "TODO: travelthru" */ + seen_region * sr = NULL; + region *r; + const faction * lastf = NULL; + faction_list * flist = calloc(1, sizeof(faction_list)); + + flist->data = ctx->f; + + if (f_get_alliance(ctx->f)) { + faction_list * member = ctx->f->alliance->members; + for (;member;member=member->next) { + add_faction(&flist, member->data); + } + } + + for (r=ctx->first;sr==NULL && r!=ctx->last;r=r->next) { + sr = find_seen(ctx->seen, r); + } + + for (;sr!=NULL;sr=sr->next) { + int stealthmod = stealth_modifier(sr->mode); + r = sr->r; + if (sr->mode==see_lighthouse) { + unit * u = r->units; + for (;u;u=u->next) { + faction * sf = visible_faction(ctx->f, u); + if (lastf!=sf) { + if (u->building || u->ship || (stealthmod>INT_MIN && cansee(ctx->f, r, u, stealthmod))) { + add_faction(&flist, sf); + lastf = sf; + } + } + } + } else if (sr->mode==see_travel) { + unit * u = r->units; + while (u) { + faction * sf = visible_faction(ctx->f, u); + assert(u->faction!=ctx->f); /* if this is see_travel only, then I shouldn't be here. */ + if (lastf!=sf) { + attrib * a = a_find(r->attribs, &at_travelunit); + while (a && a->type==&at_travelunit) { + unit * u2 = (unit*)a->data.v; + if (u2->faction==ctx->f) { + if (cansee_unit(u2, u, stealthmod)) { + add_faction(&flist, sf); + lastf = sf; + break; + } + } + a = a->next; + } + } + u = u->next; + } + } else if (sr->mode>see_travel) { + const unit * u = r->units; + while (u!=NULL) { + if (u->faction!=ctx->f) { + faction * sf = visible_faction(ctx->f, u); + boolean ballied = sf && sf!=ctx->f && sf!=lastf + && !fval(u, UFL_ANON_FACTION) && cansee(ctx->f, r, u, stealthmod); + if (ballied || ALLIED(ctx->f, sf)) { + add_faction(&flist, sf); + lastf = sf; + } + } + u = u->next; + } + } + } + + if (f_get_alliance(ctx->f)) { + faction *f2; + for (f2 = factions; f2; f2 = f2->next) { + if (f2->alliance == ctx->f->alliance) { + add_faction(&flist, f2); + } + } + } + ctx->addresses = flist; +} + +#define MAXSEEHASH 0x1000 +seen_region * reuse; + +seen_region ** +seen_init(void) +{ + return (seen_region **)calloc(MAXSEEHASH, sizeof(seen_region*)); +} + +void +seen_done(seen_region * seehash[]) +{ + int i; + for (i=0;i!=MAXSEEHASH;++i) { + seen_region * sd = seehash[i]; + if (sd==NULL) continue; + while (sd->nextHash!=NULL) sd = sd->nextHash; + sd->nextHash = reuse; + reuse = seehash[i]; + seehash[i] = NULL; + } + // free(seehash); +} + +void +free_seen(void) +{ + while (reuse) { + seen_region * r = reuse; + reuse = reuse->nextHash; + free(r); + } +} + +void +link_seen(seen_region * seehash[], const region * first, const region * last) +{ + const region * r = first; + seen_region * sr = NULL; + + if (first==last) return; + + do { + sr = find_seen(seehash, r); + r = r->next; + } while (sr==NULL && r!=last); + + while (r!=last) { + seen_region * sn = find_seen(seehash, r); + if (sn!=NULL) { + sr->next = sn; + sr = sn; + } + r = r->next; + } + sr->next = 0; +} + +seen_region * +find_seen(struct seen_region * seehash[], const region * r) +{ + unsigned int index = reg_hashkey(r) & (MAXSEEHASH-1); + seen_region * find = seehash[index]; + while (find) { + if (find->r==r) return find; + find=find->nextHash; + } + return NULL; +} + +static void +get_seen_interval(report_context * ctx) +{ + /* this is required to find the neighbour regions of the ones we are in, + * which may well be outside of [firstregion, lastregion) */ + int i; + for (i=0;i!=MAXSEEHASH;++i) { + seen_region * sr = ctx->seen[i]; + while (sr!=NULL) { + if (ctx->first==NULL || sr->r->indexfirst->index) { + ctx->first = sr->r; + } + if (ctx->last!=NULL && sr->r->index>=ctx->last->index) { + ctx->last = sr->r->next; + } + sr = sr->nextHash; + } + } + link_seen(ctx->seen, ctx->first, ctx->last); +} + +boolean +add_seen(struct seen_region * seehash[], struct region * r, unsigned char mode, boolean dis) +{ + seen_region * find = find_seen(seehash, r); + if (find==NULL) { + unsigned int index = reg_hashkey(r) & (MAXSEEHASH-1); + if (!reuse) reuse = (seen_region*)calloc(1, sizeof(struct seen_region)); + find = reuse; + reuse = reuse->nextHash; + find->nextHash = seehash[index]; + seehash[index] = find; + find->r = r; + } else if (find->mode >= mode) { + return false; + } + find->mode = mode; + find->disbelieves |= dis; + return true; +} + +typedef struct report_type { + struct report_type * next; + report_fun write; + const char * extension; + int flag; +} report_type; + +static report_type * report_types; + +void +register_reporttype(const char * extension, report_fun write, int flag) +{ + report_type * type = malloc(sizeof(report_type)); + type->extension = extension; + type->write = write; + type->flag = flag; + type->next = report_types; + report_types = type; +} + +static region_list * +get_regions_distance(region * root, int radius) +{ + region_list * rptr, * rlist = NULL; + region_list ** rp = &rlist; + add_regionlist(rp, root); + fset(root, RF_MARK); + while (*rp) { + region_list * r = *rp; + direction_t d; + rp = &r->next; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(r->data, d); + if (rn!=NULL && !fval(rn, RF_MARK) && distance(rn, root)<=radius) { + add_regionlist(rp, rn); + fset(rn, RF_MARK); + } + } + } + for (rptr=rlist;rptr;rptr=rptr->next) { + freset(rptr->data, RF_MARK); + } + return rlist; +} + +static void +view_default(struct seen_region ** seen, region *r, faction *f) +{ + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * r2 = rconnect(r, dir); + if (r2) { + connection * b = get_borders(r, r2); + while (b) { + if (!b->type->transparent(b, f)) break; + b = b->next; + } + if (!b) add_seen(seen, r2, see_neighbour, false); + } + } +} + +static void +view_neighbours(struct seen_region ** seen, region * r, faction * f) +{ + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * r2 = rconnect(r, dir); + if (r2) { + connection * b = get_borders(r, r2); + while (b) { + if (!b->type->transparent(b, f)) break; + b = b->next; + } + if (!b) { + if (add_seen(seen, r2, see_far, false)) { + if (!(fval(r2->terrain, FORBIDDEN_REGION))) { + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * r3 = rconnect(r2, dir); + if (r3) { + connection * b = get_borders(r2, r3); + while (b) { + if (!b->type->transparent(b, f)) break; + b = b->next; + } + if (!b) add_seen(seen, r3, see_neighbour, false); + } + } + } + } + } + } + } +} + +static void +recurse_regatta(struct seen_region ** seen, region *center, region *r, faction *f, int maxdist) +{ + direction_t dir; + int dist = distance(center, r); + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * r2 = rconnect(r, dir); + if (r2) { + int ndist = distance(center, r2); + if (ndist>dist && fval(r2->terrain, SEA_REGION)) { + connection * b = get_borders(r, r2); + while (b) { + if (!b->type->transparent(b, f)) break; + b = b->next; + } + if (!b) { + if (ndistunits; u; u=u->next) { + if (u->faction==f) { + int es = effskill(u, SK_PERCEPTION); + if (es>skill) skill=es; + } + } + recurse_regatta(seen, r, r, f, skill/2); +} + +static void +prepare_reports(void) +{ + region * r; + faction * f; + static const struct building_type * bt_lighthouse = NULL; + if (bt_lighthouse==NULL) bt_lighthouse = bt_find("lighthouse"); + + for (f = factions; f ; f = f->next) { + if (f->seen) seen_done(f->seen); + f->seen = seen_init(); + } + + for (r = regions; r ; r = r->next) { + attrib *ru; + unit * u; + plane * p = rplane(r); + + reorder_units(r); + + if (p) { + watcher * w = p->watchers; + for (;w;w=w->next) { + add_seen(w->faction->seen, r, w->mode, false); +#ifdef SMART_INTERVALS + update_interval(w->faction, r); +#endif + } + } + + for (u = r->units; u; u = u->next) { + if (u->building && u->building->type==bt_lighthouse) { + /* we are in a lighthouse. add the regions we can see from here! */ + int range = lighthouse_range(u->building, u->faction); + region_list * rlist = get_regions_distance(r, range); + region_list * rp = rlist; + + while (rp) { + region * rl = rp->data; + if (fval(rl->terrain, SEA_REGION)) { + direction_t d; + add_seen(u->faction->seen, rl, see_lighthouse, false); + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(rl, d); + if (rn!=NULL) { + add_seen(u->faction->seen, rn, see_neighbour, false); + } + } + } + rp = rp->next; + } + free_regionlist(rlist); + } + + if (u->race != new_race[RC_SPELL] || u->number == RS_FARVISION) { + if (fval(u, UFL_DISBELIEVES)) { + add_seen(u->faction->seen, r, see_unit, true); + } else { + add_seen(u->faction->seen, r, see_unit, false); + } + } + } + + if (fval(r, RF_TRAVELUNIT)) { + for (ru = a_find(r->attribs, &at_travelunit); ru && ru->type==&at_travelunit; ru = ru->next) { + unit * u = (unit*)ru->data.v; + + /* make sure the faction has not been removed this turn: */ + if (u->faction) { + add_seen(u->faction->seen, r, see_travel, false); + } + } + } + } +} + +static seen_region ** +prepare_report(faction * f) +{ + struct seen_region * sr; + region * r = firstregion(f); + region * last = lastregion(f); + + link_seen(f->seen, r, last); + + for (sr=NULL; sr==NULL && r!=last; r=r->next) { + sr = find_seen(f->seen, r); + } + + for (;sr!=NULL;sr=sr->next) { + if (sr->mode>see_neighbour) { + region * r = sr->r; + plane * p = rplane(r); + + void (*view)(struct seen_region **, region *, faction *) = view_default; + if (p && fval(p, PFL_SEESPECIAL)) { + attrib * a = a_find(p->attribs, &at_viewrange); + if (a) view = (void (*)(struct seen_region **, region *, faction *))a->data.f; + } + view(f->seen, r, f); + } + } + return f->seen; +} + +int +write_reports(faction * f, time_t ltime) +{ + int backup = 1, maxbackup = 128; + boolean gotit = false; + struct report_context ctx; + const char * encoding = "UTF-8"; + + if (noreports) { + return false; + } + ctx.f = f; + ctx.report_time = time(NULL); + ctx.seen = prepare_report(f); + ctx.first = firstregion(f); + ctx.last = lastregion(f); + ctx.addresses = NULL; + ctx.userdata = NULL; + get_seen_interval(&ctx); + get_addresses(&ctx); + + do { + report_type * rtype = report_types; + + errno = 0; + if (verbosity>=2) { + log_stdio(stdout, "Reports for %s:", factionname(f)); + } + for (;rtype!=NULL;rtype=rtype->next) { + if (f->options & rtype->flag) { + char filename[MAX_PATH]; + sprintf(filename, "%s/%d-%s.%s", reportpath(), turn, factionid(f), rtype->extension); + if (rtype->write(filename, &ctx, encoding)==0) { + gotit = true; + } + } + } + + if (errno) { + char zText[64]; + puts(" ERROR"); + sprintf(zText, "Waiting %u seconds before retry", backup); + perror(zText); + sleep(backup); + if (backup=2) { + puts(" DONE"); + } + } while (errno); + if (!gotit) { + log_warning(("No report for faction %s!\n", factionid(f))); + } + freelist(ctx.addresses); + seen_done(ctx.seen); + return 0; +} + +static void +nmr_warnings(void) +{ + faction *f,*fa; +#define FRIEND (HELP_GUARD|HELP_MONEY) + for (f=factions;f;f=f->next) { + if (!is_monsters(f) && (turn-f->lastorders) >= 2) { + message * msg = NULL; + for (fa=factions;fa;fa=fa->next) { + int warn = 0; + if (get_param_int(global.parameters, "rules.alliances", 0)!=0) { + if (f->alliance && f->alliance==fa->alliance) { + warn = 1; + } + } else if (alliedfaction(NULL, f, fa, FRIEND) && alliedfaction(NULL, fa, f, FRIEND)) { + warn = 1; + } + if (warn) { + if (msg==NULL) { + msg = msg_message("warn_dropout", "faction turns", f, turn - f->lastorders); + } + add_message(&fa->msgs, msg); + } + } + if (msg!=NULL) msg_release(msg); + } + } +} + +static void +report_donations(void) +{ + region * r; + for (r=regions;r;r=r->next) { + while (r->donations) { + donation * sp = r->donations; + if (sp->amount > 0) { + struct message * msg = msg_message("donation", + "from to amount", sp->f1, sp->f2, sp->amount); + r_addmessage(r, sp->f1, msg); + r_addmessage(r, sp->f2, msg); + msg_release(msg); + } + r->donations = sp->next; + free(sp); + } + } +} + +static void +write_script(FILE * F, const faction * f) +{ + report_type * rtype; + char buf[1024]; + + fprintf(F, "faction=%s:email=%s:lang=%s", factionid(f), f->email, locale_name(f->locale)); + if (f->options & (1<extension); + } + } + fputs(buf, F); + fputc('\n', F); +} + +int +init_reports(void) +{ + prepare_reports(); +#ifdef HAVE_STAT + { + stat_type st; + if (stat(reportpath(), &st)==0) return 0; + } +#endif + if (makedir(reportpath(), 0700)!=0) { + if (errno!=EEXIST) { + perror("could not create reportpath"); + return -1; + } + } + return 0; +} + +int +reports(void) +{ + faction *f; + FILE *mailit; + time_t ltime = time(NULL); + const char * str; + int retval = 0; + char path[MAX_PATH]; + + if (verbosity>=1) { + log_stdio(stdout, "Writing reports for turn %d:", turn); + } + nmr_warnings(); + report_donations(); + remove_empty_units(); + + sprintf(path, "%s/reports.txt", reportpath()); + mailit = fopen(path, "w"); + if (mailit == NULL) { + log_error(("%s could not be opened!\n", path)); + } + + for (f = factions; f; f = f->next) { + int error = write_reports(f, ltime); + if (error) retval = error; + if (mailit) write_script(mailit, f); + } + if (mailit) fclose(mailit); + free_seen(); + str = get_param(global.parameters, "globalreport"); +#ifdef GLOBAL_REPORT + if (str!=NULL) { + sprintf(path, "%s/%s.%u.cr", reportpath(), str, turn); + global_report(path); + } +#endif + return retval; +} + +static variant +var_copy_string(variant x) +{ + x.v = strdup((const char*)x.v); + return x; +} + +static void +var_free_string(variant x) +{ + free(x.v); +} + +static variant +var_copy_order(variant x) +{ + x.v = copy_order((order*)x.v); + return x; +} + +static void +var_free_order(variant x) +{ + free_order(x.v); +} + +static variant +var_copy_items(variant x) +{ + item * isrc; + resource * rdst = NULL, ** rptr = &rdst; + + for (isrc = (item*)x.v; isrc!=NULL; isrc=isrc->next) { + resource * res = malloc(sizeof(resource)); + res->number = isrc->number; + res->type = isrc->type->rtype; + *rptr = res; + rptr = &res->next; + } + *rptr = NULL; + x.v = rdst; + return x; +} + +static void +var_free_resources(variant x) +{ + resource * rsrc = (resource*)x.v; + while (rsrc) { + resource * res = rsrc->next; + free(rsrc); + rsrc = res; + } + x.v = 0; +} + +static void +var_free_regions(variant x) +{ + free(x.v); +} + +const char * +trailinto(const region * r, const struct locale * lang) +{ + char ref[32]; + const char * s; + if (r) { + const char * tname = terrain_name(r); + strcat(strcpy(ref, tname), "_trail"); + s = locale_string(lang, ref); + if (s && *s) { + if (strstr(s, "%s")) return s; + } + } + return "%s"; +} + +size_t +f_regionid(const region * r, const faction * f, char * buffer, size_t size) +{ + if (!r) { + strncpy(buffer, "(Chaos)", size); + } else { + plane * pl = rplane(r); + const char * name = pl?pl->name:0; + int nx = r->x, ny = r->y; + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl, r); + strncpy(buffer, rname(r, f->locale), size); + buffer[size-1]=0; + sprintf(buffer+strlen(buffer), " (%d,%d%s%s)", nx, ny, name?",":"", (name)?name:""); + } + return strlen(buffer); +} + +static char * +f_regionid_s(const region * r, const faction * f) +{ + static int i = 0; + static char bufs[4][NAMESIZE + 20]; + char * buf = bufs[(++i)%4]; + + f_regionid(r, f, buf, NAMESIZE + 20); + return buf; +} + +/*** BEGIN MESSAGE RENDERING ***/ +static void +eval_localize(struct opstack ** stack, const void * userdata) /* (string, locale) -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct locale * lang = f?f->locale:default_locale; + const char *c = (const char *)opop_v(stack); + c = locale_string(lang, c); + opush_v(stack, strcpy(balloc(strlen(c)+1), c)); +} + +static void +eval_trailto(struct opstack ** stack, const void * userdata) /* (int, int) -> int */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct locale * lang = f?f->locale:default_locale; + const struct region * r = (const struct region*)opop(stack).v; + const char * trail = trailinto(r, lang); + const char * rn = f_regionid_s(r, f); + variant var; + char * x = var.v = balloc(strlen(trail)+strlen(rn)); + sprintf(x, trail, rn); + opush(stack, var); +} + +static void +eval_unit(struct opstack ** stack, const void * userdata) /* unit -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct unit * u = (const struct unit *)opop(stack).v; + const char * c = u?unitname(u):LOC(f->locale, "an_unknown_unit"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_unit_dative(struct opstack ** stack, const void * userdata) /* unit -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct unit * u = (const struct unit *)opop(stack).v; + const char * c = u?unitname(u):LOC(f->locale, "unknown_unit_dative"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_spell(struct opstack ** stack, const void * userdata) /* unit -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct spell * sp = (const struct spell *)opop(stack).v; + const char * c = sp?spell_name(sp, f->locale):LOC(f->locale, "an_unknown_spell"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_curse(struct opstack ** stack, const void * userdata) /* unit -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct curse_type * sp = (const struct curse_type *)opop(stack).v; + const char * c = sp?curse_name(sp, f->locale):LOC(f->locale, "an_unknown_curse"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_unitname(struct opstack ** stack, const void * userdata) /* unit -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct unit * u = (const struct unit *)opop(stack).v; + const char * c = u?u->name:LOC(f->locale, "an_unknown_unit"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + + +static void +eval_unitid(struct opstack ** stack, const void * userdata) /* unit -> int */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct unit * u = (const struct unit *)opop(stack).v; + const char * c = u?u->name:LOC(f->locale, "an_unknown_unit"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_unitsize(struct opstack ** stack, const void * userdata) /* unit -> int */ +{ + const struct unit * u = (const struct unit *)opop(stack).v; + variant var; + + var.i = u->number; + opush(stack, var); +} + +static void +eval_faction(struct opstack ** stack, const void * userdata) /* faction -> string */ +{ + const struct faction * f = (const struct faction *)opop(stack).v; + const char * c = factionname(f); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_alliance(struct opstack ** stack, const void * userdata) /* faction -> string */ +{ + const struct alliance * al = (const struct alliance *)opop(stack).v; + const char * c = alliancename(al); + variant var; + if (c!=NULL) { + size_t len = strlen(c); + var.v = strcpy(balloc(len+1), c); + } + else var.v = NULL; + opush(stack, var); +} + +static void +eval_region(struct opstack ** stack, const void * userdata) /* region -> string */ +{ + char name[NAMESIZE+32]; + const struct faction * f = (const struct faction *)userdata; + const struct region * r = (const struct region *)opop(stack).v; + const char * c = write_regionname(r, f, name, sizeof(name)); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_terrain(struct opstack ** stack, const void * userdata) /* region -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct region * r = (const struct region *)opop(stack).v; + const char * c = LOC(f->locale, terrain_name(r)); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_ship(struct opstack ** stack, const void * userdata) /* ship -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct ship * u = (const struct ship *)opop(stack).v; + const char * c = u?shipname(u):LOC(f->locale, "an_unknown_ship"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_building(struct opstack ** stack, const void * userdata) /* building -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct building * u = (const struct building *)opop(stack).v; + const char * c = u?buildingname(u):LOC(f->locale, "an_unknown_building"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_weight(struct opstack ** stack, const void * userdata) /* region -> string */ +{ + char buffer[32]; + const struct faction * f = (const struct faction *)userdata; + const struct locale * lang = f->locale; + int weight = opop_i(stack); + variant var; + + if (weight % SCALEWEIGHT == 0) { + if (weight==SCALEWEIGHT) { + sprintf(buffer, "1 %s", LOC(lang, "weight_unit")); + } else { + sprintf(buffer, "%u %s", weight/SCALEWEIGHT, LOC(lang, "weight_unit_p")); + } + } else { + if (weight==1) { + sprintf(buffer, "1 %s %u", LOC(lang, "weight_per"), SCALEWEIGHT); + } else { + sprintf(buffer, "%u %s %u", weight, LOC(lang, "weight_per_p"), SCALEWEIGHT); + } + } + + var.v = strcpy(balloc(strlen(buffer)+1), buffer); + opush(stack, var); +} + +static void +eval_resource(struct opstack ** stack, const void * userdata) +{ + const faction * report = (const faction*)userdata; + const struct locale * lang = report?report->locale:default_locale; + int j = opop(stack).i; + const struct resource_type * res = (const struct resource_type *)opop(stack).v; + const char * c = LOC(lang, resourcename(res, j!=1)); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_race(struct opstack ** stack, const void * userdata) +{ + const faction * report = (const faction*)userdata; + const struct locale * lang = report?report->locale:default_locale; + int j = opop(stack).i; + const race * r = (const race *)opop(stack).v; + const char * c = LOC(lang, rc_name(r, j!=1)); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_order(struct opstack ** stack, const void * userdata) /* order -> string */ +{ + const struct order * ord = (const struct order *)opop(stack).v; + static char buf[256]; + size_t len; + variant var; + + unused(userdata); + write_order(ord, buf, sizeof(buf)); + len = strlen(buf); + var.v = strcpy(balloc(len+1), buf); + opush(stack, var); +} + +static void +eval_resources(struct opstack ** stack, const void * userdata) /* order -> string */ +{ + const faction * report = (const faction*)userdata; + const struct locale * lang = report?report->locale:default_locale; + const struct resource * res = (const struct resource *)opop(stack).v; + static char buf[1024]; /* but we only use about half of this */ + size_t size = sizeof(buf) - 1; + variant var; + + char * bufp = buf; + while (res!=NULL && size > 4) { + const char * rname = resourcename(res->type, (res->number!=1)?NMF_PLURAL:0); + int bytes = snprintf(bufp, size, "%d %s", res->number, LOC(lang, rname)); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0 || sizenext; + if (res!=NULL && size>2) { + strcat(bufp, ", "); + bufp += 2; + size -= 2; + } + } + *bufp = 0; + var.v = strcpy(balloc(bufp-buf+1), buf); + opush(stack, var); +} + +static void +eval_regions(struct opstack ** stack, const void * userdata) /* order -> string */ +{ + const faction * report = (const faction*)userdata; + int i = opop(stack).i; + int end, begin = opop(stack).i; + const arg_regions * regions = (const arg_regions *)opop(stack).v; + static char buf[256]; + size_t size = sizeof(buf) - 1; + variant var; + char * bufp = buf; + + if (regions==NULL) { + end = begin; + } else { + if (i>=0) end = begin+i; + else end = regions->nregions+i; + } + for (i=begin;iregions[i], report); + int bytes = (int)strlcpy(bufp, rname, size); + if (bytes && wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (i+12) { + strcat(bufp, ", "); + bufp += 2; + size -= 2; + } + } + *bufp = 0; + var.v = strcpy(balloc(bufp-buf+1), buf); + opush(stack, var); +} + +static void +eval_trail(struct opstack ** stack, const void * userdata) /* order -> string */ +{ + const faction * report = (const faction*)userdata; + const struct locale * lang = report?report->locale:default_locale; + int i, end = 0, begin = 0; + const arg_regions * regions = (const arg_regions *)opop(stack).v; + static char buf[512]; + size_t size = sizeof(buf) - 1; + variant var; + char * bufp = buf; +#ifdef _SECURECRT_ERRCODE_VALUES_DEFINED + /* stupid MS broke snprintf */ + int eold = errno; +#endif + + if (regions!=NULL) { + end = regions->nregions; + for (i=begin;iregions[i]; + const char * trail = trailinto(r, lang); + const char * rn = f_regionid_s(r, report); + int bytes = snprintf(bufp, size, trail, rn); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (i+2locale:default_locale; + int i = opop(stack).i; + const char * c = LOC(lang, (i>=0)?directions[i]:"unknown_direction"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_skill(struct opstack ** stack, const void * userdata) +{ + const faction * report = (const faction*)userdata; + const struct locale * lang = report?report->locale:default_locale; + skill_t sk = (skill_t)opop(stack).i; + const char * c = skillname(sk, lang); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_int36(struct opstack ** stack, const void * userdata) +{ + int i = opop(stack).i; + const char * c = itoa36(i); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); + unused(userdata); +} +/*** END MESSAGE RENDERING ***/ + +#include + +static void log_orders(const struct message * msg) +{ + faction * f = get_monsters(); + char buffer[4096]; + int i; + + for (i=0;i!=msg->type->nparameters;++i) { + if (msg->type->types[i]->copy==&var_copy_order) { + const char * section = nr_section(msg); + nr_render(msg, f?f->locale:default_locale, buffer, sizeof(buffer), f); + log_printf("MESSAGE [%s]: %s\n", section, buffer); + break; + } + } +} + +int +report_action(region * r, unit * actor, message * msg, int flags) +{ + int result = 0; + unit * u; + int view = flags&(ACTION_CANSEE|ACTION_CANNOTSEE); + + /* melden, 1x pro Partei */ + if (flags&ACTION_RESET) { + freset(actor->faction, FFL_SELECT); + for (u = r->units; u; u = u->next ) freset(u->faction, FFL_SELECT); + } + if (view) { + for (u = r->units; u; u = u->next ) { + if (!fval(u->faction, FFL_SELECT) ) { + boolean show = u->faction == actor->faction; + fset(u->faction, FFL_SELECT); + if (view==ACTION_CANSEE) { + /* Bei Fernzaubern sieht nur die eigene Partei den Magier */ + show = show || (r==actor->region && cansee(u->faction, r, actor, 0)); + } else if (view==ACTION_CANNOTSEE) { + show = !show && !(r==actor->region && cansee(u->faction, r, actor, 0)); + } else { + /* the unliely (or lazy) case */ + show = true; + } + + if (show) { + r_addmessage(r, u->faction, msg); + } else { /* Partei des Magiers, sieht diesen immer */ + result = 1; + } + } + } + /* Ist niemand von der Partei des Magiers in der Region, dem Magier + * nochmal gesondert melden */ + if ((flags&ACTION_CANSEE) && !fval(actor->faction, FFL_SELECT)) { + add_message(&actor->faction->msgs, msg); + } + } + return result; +} + + +void +register_reports(void) +{ + /* register datatypes for the different message objects */ + register_argtype("alliance", NULL, NULL, VAR_VOIDPTR); + register_argtype("building", NULL, NULL, VAR_VOIDPTR); + register_argtype("direction", NULL, NULL, VAR_INT); + register_argtype("faction", NULL, NULL, VAR_VOIDPTR); + register_argtype("race", NULL, NULL, VAR_VOIDPTR); + register_argtype("region", NULL, NULL, VAR_VOIDPTR); + register_argtype("resource", NULL, NULL, VAR_VOIDPTR); + register_argtype("ship", NULL, NULL, VAR_VOIDPTR); + register_argtype("skill", NULL, NULL, VAR_VOIDPTR); + register_argtype("spell", NULL, NULL, VAR_VOIDPTR); + register_argtype("curse", NULL, NULL, VAR_VOIDPTR); + register_argtype("unit", NULL, NULL, VAR_VOIDPTR); + register_argtype("int", NULL, NULL, VAR_INT); + register_argtype("string", var_free_string, var_copy_string, VAR_VOIDPTR); + register_argtype("order", var_free_order, var_copy_order, VAR_VOIDPTR); + register_argtype("resources", var_free_resources, NULL, VAR_VOIDPTR); + register_argtype("items", var_free_resources, var_copy_items, VAR_VOIDPTR); + register_argtype("regions", var_free_regions, NULL, VAR_VOIDPTR); + + + msg_log_create = &log_orders; + + /* register functions that turn message contents to readable strings */ + add_function("alliance", &eval_alliance); + add_function("region", &eval_region); + add_function("terrain", &eval_terrain); + add_function("weight", &eval_weight); + add_function("resource", &eval_resource); + add_function("race", &eval_race); + add_function("faction", &eval_faction); + add_function("ship", &eval_ship); + add_function("unit", &eval_unit); + add_function("unit.dative", &eval_unit_dative); + add_function("unit.name", &eval_unitname); + add_function("unit.id", &eval_unitid); + add_function("unit.size", &eval_unitsize); + add_function("building", &eval_building); + add_function("skill", &eval_skill); + add_function("order", &eval_order); + add_function("direction", &eval_direction); + add_function("int36", &eval_int36); + add_function("trailto", &eval_trailto); + add_function("localize", &eval_localize); + add_function("spell", &eval_spell); + add_function("curse", &eval_curse); + add_function("resources", &eval_resources); + add_function("regions", &eval_regions); + add_function("trail", &eval_trail); + + /* register alternative visibility functions */ + register_function((pf_generic)view_neighbours, "view_neighbours"); + register_function((pf_generic)view_regatta, "view_regatta"); +} diff --git a/src/kernel/reports.h b/src/kernel/reports.h index f4082f91c..cd22bf13e 100644 --- a/src/kernel/reports.h +++ b/src/kernel/reports.h @@ -1,140 +1,140 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_REPORTS -#define H_KRNL_REPORTS -#ifdef __cplusplus -extern "C" { -#endif - -/* Alter, ab dem der Score angezeigt werden soll: */ -#define DISPLAYSCORE 12 -/* Breite einer Reportzeile: */ -#define REPORTWIDTH 78 - -extern const char *directions[]; -extern const char *coasts[]; -extern boolean nonr; -extern boolean nocr; -extern boolean noreports; - -/* kann_finden speedups */ -extern boolean kann_finden(struct faction * f1, struct faction * f2); -extern struct unit * can_find(struct faction *, struct faction *); - -/* funktionen zum schreiben eines reports */ -void sparagraph(struct strlist ** SP, const char *s, int indent, char mark); -void lparagraph(struct strlist ** SP, char *s, int indent, char mark); -const char *hp_status(const struct unit * u); -extern size_t spskill(char * pbuf, size_t siz, const struct locale * lang, const struct unit * u, struct skill * sv, int *dh, int days); /* mapper */ -extern void spunit(struct strlist ** SP, const struct faction * f, const struct unit * u, int indent, int mode); - -extern int reports(void); -extern int write_reports(struct faction * f, time_t ltime); -extern int init_reports(void); - -extern const struct unit *ucansee(const struct faction *f, const struct unit *u, const struct unit *x); - -int hat_in_region(item_t itm, struct region * r, struct faction * f); - -/* für fast_region und neuen CR: */ - -enum { - see_none, - see_neighbour, - see_lighthouse, - see_travel, - see_far, - see_unit, - see_battle -}; -extern int stealth_modifier(int seen_mode); - -typedef struct seen_region { - struct seen_region * nextHash; - struct seen_region * next; - struct region *r; - unsigned char mode; - boolean disbelieves; -} seen_region; - -extern struct seen_region * find_seen(struct seen_region * seehash[], const struct region * r); -extern boolean add_seen(struct seen_region * seehash[], struct region * r, unsigned char mode, boolean dis); -extern struct seen_region ** seen_init(void); -extern void seen_done(struct seen_region * seehash[]); -extern void free_seen(void); -extern void link_seen(seen_region * seehash[], const struct region * first, const struct region * last); -extern const char * visibility[]; - -typedef struct report_context { - struct faction * f; - struct faction_list * addresses; - struct seen_region ** seen; - struct region * first, * last; - void * userdata; - time_t report_time; -} report_context; - -typedef int (*report_fun)(const char * filename, report_context * ctx, const char * charset); -extern void register_reporttype(const char * extension, report_fun write, int flag); - - -extern int bufunit(const struct faction * f, const struct unit * u, int indent, int mode, char * buf, size_t size); - -extern const char * trailinto(const struct region * r, const struct locale * lang); -extern const char * report_kampfstatus(const struct unit * u, const struct locale * lang); - - extern void register_reports(void); - - extern int update_nmrs(void); - extern int * nmrs; - - extern struct message * msg_curse(const struct curse * c, const void * obj, typ_t typ, int slef); - - typedef struct arg_regions { - int nregions; - struct region ** regions; - } arg_regions; - - typedef struct resource_report { - const char * name; - int number; - int level; - } resource_report; - int report_resources(const struct seen_region * sr, struct resource_report * result, int size, const struct faction * viewer); - int report_items(const struct item * items, struct item * result, int size, const struct unit * owner, const struct faction * viewer); - void report_item(const struct unit * owner, const struct item * i, const struct faction * viewer, const char ** name, const char ** basename, int * number, boolean singular); - void report_building(const struct building * b, const char ** btype, const char ** billusion); - void report_race(const struct unit * u, const char ** rcname, const char ** rcillusion); - -#define ACTION_RESET 0x01 /* reset the one-time-flag FFL_SELECT (on first pass) */ -#define ACTION_CANSEE 0x02 /* to people who can see the actor */ -#define ACTION_CANNOTSEE 0x04 /* to people who can not see the actor */ -extern int report_action(struct region * r, struct unit * actor, struct message * msg, int flags); - - extern size_t f_regionid(const struct region * r, const struct faction * f, char * buffer, size_t size); - - extern const char * combatstatus[]; -#define GR_PLURAL 0x01 /* grammar: plural */ -#define MAX_INVENTORY 128 /* maimum number of different items in an inventory */ -#define MAX_RAWMATERIALS 8 /* maximum kinds of raw materials in a regions */ - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_REPORTS +#define H_KRNL_REPORTS +#ifdef __cplusplus +extern "C" { +#endif + +/* Alter, ab dem der Score angezeigt werden soll: */ +#define DISPLAYSCORE 12 +/* Breite einer Reportzeile: */ +#define REPORTWIDTH 78 + +extern const char *directions[]; +extern const char *coasts[]; +extern boolean nonr; +extern boolean nocr; +extern boolean noreports; + +/* kann_finden speedups */ +extern boolean kann_finden(struct faction * f1, struct faction * f2); +extern struct unit * can_find(struct faction *, struct faction *); + +/* funktionen zum schreiben eines reports */ +void sparagraph(struct strlist ** SP, const char *s, int indent, char mark); +void lparagraph(struct strlist ** SP, char *s, int indent, char mark); +const char *hp_status(const struct unit * u); +extern size_t spskill(char * pbuf, size_t siz, const struct locale * lang, const struct unit * u, struct skill * sv, int *dh, int days); /* mapper */ +extern void spunit(struct strlist ** SP, const struct faction * f, const struct unit * u, int indent, int mode); + +extern int reports(void); +extern int write_reports(struct faction * f, time_t ltime); +extern int init_reports(void); + +extern const struct unit *ucansee(const struct faction *f, const struct unit *u, const struct unit *x); + +int hat_in_region(item_t itm, struct region * r, struct faction * f); + +/* für fast_region und neuen CR: */ + +enum { + see_none, + see_neighbour, + see_lighthouse, + see_travel, + see_far, + see_unit, + see_battle +}; +extern int stealth_modifier(int seen_mode); + +typedef struct seen_region { + struct seen_region * nextHash; + struct seen_region * next; + struct region *r; + unsigned char mode; + boolean disbelieves; +} seen_region; + +extern struct seen_region * find_seen(struct seen_region * seehash[], const struct region * r); +extern boolean add_seen(struct seen_region * seehash[], struct region * r, unsigned char mode, boolean dis); +extern struct seen_region ** seen_init(void); +extern void seen_done(struct seen_region * seehash[]); +extern void free_seen(void); +extern void link_seen(seen_region * seehash[], const struct region * first, const struct region * last); +extern const char * visibility[]; + +typedef struct report_context { + struct faction * f; + struct faction_list * addresses; + struct seen_region ** seen; + struct region * first, * last; + void * userdata; + time_t report_time; +} report_context; + +typedef int (*report_fun)(const char * filename, report_context * ctx, const char * charset); +extern void register_reporttype(const char * extension, report_fun write, int flag); + + +extern int bufunit(const struct faction * f, const struct unit * u, int indent, int mode, char * buf, size_t size); + +extern const char * trailinto(const struct region * r, const struct locale * lang); +extern const char * report_kampfstatus(const struct unit * u, const struct locale * lang); + + extern void register_reports(void); + + extern int update_nmrs(void); + extern int * nmrs; + + extern struct message * msg_curse(const struct curse * c, const void * obj, typ_t typ, int slef); + + typedef struct arg_regions { + int nregions; + struct region ** regions; + } arg_regions; + + typedef struct resource_report { + const char * name; + int number; + int level; + } resource_report; + int report_resources(const struct seen_region * sr, struct resource_report * result, int size, const struct faction * viewer); + int report_items(const struct item * items, struct item * result, int size, const struct unit * owner, const struct faction * viewer); + void report_item(const struct unit * owner, const struct item * i, const struct faction * viewer, const char ** name, const char ** basename, int * number, boolean singular); + void report_building(const struct building * b, const char ** btype, const char ** billusion); + void report_race(const struct unit * u, const char ** rcname, const char ** rcillusion); + +#define ACTION_RESET 0x01 /* reset the one-time-flag FFL_SELECT (on first pass) */ +#define ACTION_CANSEE 0x02 /* to people who can see the actor */ +#define ACTION_CANNOTSEE 0x04 /* to people who can not see the actor */ +extern int report_action(struct region * r, struct unit * actor, struct message * msg, int flags); + + extern size_t f_regionid(const struct region * r, const struct faction * f, char * buffer, size_t size); + + extern const char * combatstatus[]; +#define GR_PLURAL 0x01 /* grammar: plural */ +#define MAX_INVENTORY 128 /* maimum number of different items in an inventory */ +#define MAX_RAWMATERIALS 8 /* maximum kinds of raw materials in a regions */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/resources.c b/src/kernel/resources.c index 999ff1671..81620ba46 100644 --- a/src/kernel/resources.c +++ b/src/kernel/resources.c @@ -1,208 +1,208 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "resources.h" - -/* kernel includes */ -#include "build.h" -#include "item.h" -#include "region.h" -#include "terrain.h" - -#include -#include - -#include -#include -#include - -static double -ResourceFactor(void) -{ - static double value = -1.0; - if (value<0) { - const char * str = get_param(global.parameters, "resource.factor"); - value = str?atof(str):1.0; - } - return value; -} - -void -update_resources(region * r) -{ - struct rawmaterial * res = r->resources; - while (res) { - if (res->type->update) res->type->update(res, r); - res = res->next; - } -} - -extern int dice_rand(const char *s); - -static void -update_resource(struct rawmaterial * res, double modifier) -{ - double amount = 1 + (res->level-res->startlevel) * res->divisor/100.0; - amount = ResourceFactor() * res->base * amount * modifier; - if (amount<1.0) res->amount = 1; - else res->amount = (int)amount; - assert(res->amount>0); -} - -void -add_resource(region * r, int level, int base, int divisor, const resource_type * rtype) -{ - struct rawmaterial * rm = calloc(sizeof(struct rawmaterial), 1); - - rm->next = r->resources; - r->resources = rm; - rm->level = level; - rm->startlevel = level; - rm->base = base; - rm->divisor = divisor; - rm->flags = 0; - rm->type = rmt_get(rtype); - update_resource(rm, 1.0); - rm->type->terraform(rm, r); -} - -void -terraform_resources(region * r) -{ - int i; - const terrain_type * terrain = r->terrain; - - if (terrain->production==NULL) return; - for (i=0;terrain->production[i].type; ++i) { - rawmaterial *rm; - const terrain_production * production = terrain->production+i; - const resource_type * rtype = production->type; - - for (rm=r->resources; rm; rm=rm->next) { - if (rm->type->rtype == rtype) break; - } - if (rm) continue; - - if (chance(production->chance)) { - add_resource(r, dice_rand(production->startlevel), dice_rand(production->base), dice_rand(production->divisor), production->type); - } - } -} - -static void -terraform_default(struct rawmaterial * res, const region * r) -{ -#define SHIFT 70 - double modifier = 1.0 + ((rng_int() % (SHIFT*2+1)) - SHIFT) * ((rng_int() % (SHIFT*2+1)) - SHIFT) / 10000.0; - res->amount = (int)(res->amount*modifier); /* random adjustment, +/- 91% */ - if (res->amount<1) res->amount=1; - unused(r); -} - -#ifdef RANDOM_CHANGE -static void -resource_random_change(int *pvalue, boolean used) -{ - int split = 5; - int rnd = rng_int()%100; - - if (pvalue==0 || rnd %10 >= 10) return; - if (used) split = 4; - /* if a resource was mined this round, there is a 6% probability - * of a decline and a 4% probability of a raise. */ - /* if it wasn't mined this round, there is an equal probability - * of 5% for a decline or a raise. */ - if(rnd < split) { - (*pvalue)++; - } else { - (*pvalue)--; - } - if ((*pvalue) < 0) (*pvalue) = 0; -} -#endif - -static int -visible_default(const rawmaterial *res, int skilllevel) -/* resources are visible, if skill equals minimum skill to mine them - * plus current level of difficulty */ -{ - const struct item_type * itype = res->type->rtype->itype; - if (res->level<=1 && res->level + itype->construction->minskill <= skilllevel+1) { - assert (res->amount>0); - return res->amount; - } else if (res->level + itype->construction->minskill <= skilllevel+2) { - assert (res->amount>0); - return res->amount; - } - return -1; -} - -static void -use_default(rawmaterial *res, const region * r, int amount) -{ - assert(res->amount>0 && amount>=0 && amount <= res->amount); - res->amount-=amount; - while (res->amount==0) { - double modifier = 1.0 + ((rng_int() % (SHIFT*2+1)) - SHIFT) * ((rng_int() % (SHIFT*2+1)) - SHIFT) / 10000.0; - int i; - - for (i=0;r->terrain->production[i].type;++i) { - if (res->type->rtype == r->terrain->production[i].type) break; - } - - ++res->level; - update_resource(res, modifier); - } -} - -struct rawmaterial * -rm_get(region * r, const struct resource_type * rtype) -{ - struct rawmaterial * rm = r->resources; - while (rm && rm->type->rtype!=rtype) rm = rm->next; - return rm; -} - -struct rawmaterial_type * rawmaterialtypes = 0; - -struct rawmaterial_type * -rmt_find(const char * str) -{ - rawmaterial_type * rmt = rawmaterialtypes; - while (rmt && strcmp(rmt->name, str)!=0) rmt = rmt->next; - return rmt; -} - -struct rawmaterial_type * -rmt_get(const struct resource_type * rtype) -{ - rawmaterial_type * rmt = rawmaterialtypes; - while (rmt && rmt->rtype!=rtype) rmt = rmt->next; - return rmt; -} - -struct rawmaterial_type * -rmt_create(const struct resource_type * rtype, const char * name) -{ - rawmaterial_type * rmtype = malloc(sizeof(rawmaterial_type)); - rmtype->name = strdup(name); - rmtype->rtype = rtype; - rmtype->terraform = terraform_default; - rmtype->update = NULL; - rmtype->use = use_default; - rmtype->visible = visible_default; - rmtype->next = rawmaterialtypes; - rawmaterialtypes = rmtype; - return rmtype; -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "resources.h" + +/* kernel includes */ +#include "build.h" +#include "item.h" +#include "region.h" +#include "terrain.h" + +#include +#include + +#include +#include +#include + +static double +ResourceFactor(void) +{ + static double value = -1.0; + if (value<0) { + const char * str = get_param(global.parameters, "resource.factor"); + value = str?atof(str):1.0; + } + return value; +} + +void +update_resources(region * r) +{ + struct rawmaterial * res = r->resources; + while (res) { + if (res->type->update) res->type->update(res, r); + res = res->next; + } +} + +extern int dice_rand(const char *s); + +static void +update_resource(struct rawmaterial * res, double modifier) +{ + double amount = 1 + (res->level-res->startlevel) * res->divisor/100.0; + amount = ResourceFactor() * res->base * amount * modifier; + if (amount<1.0) res->amount = 1; + else res->amount = (int)amount; + assert(res->amount>0); +} + +void +add_resource(region * r, int level, int base, int divisor, const resource_type * rtype) +{ + struct rawmaterial * rm = calloc(sizeof(struct rawmaterial), 1); + + rm->next = r->resources; + r->resources = rm; + rm->level = level; + rm->startlevel = level; + rm->base = base; + rm->divisor = divisor; + rm->flags = 0; + rm->type = rmt_get(rtype); + update_resource(rm, 1.0); + rm->type->terraform(rm, r); +} + +void +terraform_resources(region * r) +{ + int i; + const terrain_type * terrain = r->terrain; + + if (terrain->production==NULL) return; + for (i=0;terrain->production[i].type; ++i) { + rawmaterial *rm; + const terrain_production * production = terrain->production+i; + const resource_type * rtype = production->type; + + for (rm=r->resources; rm; rm=rm->next) { + if (rm->type->rtype == rtype) break; + } + if (rm) continue; + + if (chance(production->chance)) { + add_resource(r, dice_rand(production->startlevel), dice_rand(production->base), dice_rand(production->divisor), production->type); + } + } +} + +static void +terraform_default(struct rawmaterial * res, const region * r) +{ +#define SHIFT 70 + double modifier = 1.0 + ((rng_int() % (SHIFT*2+1)) - SHIFT) * ((rng_int() % (SHIFT*2+1)) - SHIFT) / 10000.0; + res->amount = (int)(res->amount*modifier); /* random adjustment, +/- 91% */ + if (res->amount<1) res->amount=1; + unused(r); +} + +#ifdef RANDOM_CHANGE +static void +resource_random_change(int *pvalue, boolean used) +{ + int split = 5; + int rnd = rng_int()%100; + + if (pvalue==0 || rnd %10 >= 10) return; + if (used) split = 4; + /* if a resource was mined this round, there is a 6% probability + * of a decline and a 4% probability of a raise. */ + /* if it wasn't mined this round, there is an equal probability + * of 5% for a decline or a raise. */ + if(rnd < split) { + (*pvalue)++; + } else { + (*pvalue)--; + } + if ((*pvalue) < 0) (*pvalue) = 0; +} +#endif + +static int +visible_default(const rawmaterial *res, int skilllevel) +/* resources are visible, if skill equals minimum skill to mine them + * plus current level of difficulty */ +{ + const struct item_type * itype = res->type->rtype->itype; + if (res->level<=1 && res->level + itype->construction->minskill <= skilllevel+1) { + assert (res->amount>0); + return res->amount; + } else if (res->level + itype->construction->minskill <= skilllevel+2) { + assert (res->amount>0); + return res->amount; + } + return -1; +} + +static void +use_default(rawmaterial *res, const region * r, int amount) +{ + assert(res->amount>0 && amount>=0 && amount <= res->amount); + res->amount-=amount; + while (res->amount==0) { + double modifier = 1.0 + ((rng_int() % (SHIFT*2+1)) - SHIFT) * ((rng_int() % (SHIFT*2+1)) - SHIFT) / 10000.0; + int i; + + for (i=0;r->terrain->production[i].type;++i) { + if (res->type->rtype == r->terrain->production[i].type) break; + } + + ++res->level; + update_resource(res, modifier); + } +} + +struct rawmaterial * +rm_get(region * r, const struct resource_type * rtype) +{ + struct rawmaterial * rm = r->resources; + while (rm && rm->type->rtype!=rtype) rm = rm->next; + return rm; +} + +struct rawmaterial_type * rawmaterialtypes = 0; + +struct rawmaterial_type * +rmt_find(const char * str) +{ + rawmaterial_type * rmt = rawmaterialtypes; + while (rmt && strcmp(rmt->name, str)!=0) rmt = rmt->next; + return rmt; +} + +struct rawmaterial_type * +rmt_get(const struct resource_type * rtype) +{ + rawmaterial_type * rmt = rawmaterialtypes; + while (rmt && rmt->rtype!=rtype) rmt = rmt->next; + return rmt; +} + +struct rawmaterial_type * +rmt_create(const struct resource_type * rtype, const char * name) +{ + rawmaterial_type * rmtype = malloc(sizeof(rawmaterial_type)); + rmtype->name = strdup(name); + rmtype->rtype = rtype; + rmtype->terraform = terraform_default; + rmtype->update = NULL; + rmtype->use = use_default; + rmtype->visible = visible_default; + rmtype->next = rawmaterialtypes; + rawmaterialtypes = rmtype; + return rmtype; +} diff --git a/src/kernel/resources.h b/src/kernel/resources.h index 9c99ad6f8..5e1333c78 100644 --- a/src/kernel/resources.h +++ b/src/kernel/resources.h @@ -1,63 +1,63 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ -#ifndef H_KRNL_RESOURCES -#define H_KRNL_RESOURCES -#ifdef __cplusplus -extern "C" { -#endif - -enum { - RM_USED = 1<<0, /* resource has been used */ - RM_MALLORN = 1<<1 /* this is not wood. it's mallorn */ -}; - -typedef struct rawmaterial { - const struct rawmaterial_type * type; - int amount : 16; - int level : 8; - int flags : 8; - int base : 8; - int divisor : 8; - int startlevel : 8; - struct rawmaterial * next; -} rawmaterial; - -typedef struct rawmaterial_type { - char * name; - const struct resource_type * rtype; - - void (*terraform) (struct rawmaterial *, const struct region *); - void (*update) (struct rawmaterial *, const struct region *); - void (*use) (struct rawmaterial *, const struct region *, int amount); - int (*visible) (const struct rawmaterial *, int skilllevel); - - /* no initialization required */ - struct rawmaterial_type * next; -} rawmaterial_type; - -extern struct rawmaterial_type * rawmaterialtypes; - -extern void update_resources(struct region * r); -extern void terraform_resources(struct region * r); -extern void read_resources(struct region * r); -extern void write_resources(struct region * r); -extern struct rawmaterial * rm_get(struct region *, const struct resource_type *); -extern struct rawmaterial_type * rmt_find(const char * str); -extern struct rawmaterial_type * rmt_get(const struct resource_type *); - -extern void add_resource(struct region * r, int level, int base, int divisor, const struct resource_type * rtype); -extern struct rawmaterial_type * rmt_create(const struct resource_type * rtype, const char * name); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#ifndef H_KRNL_RESOURCES +#define H_KRNL_RESOURCES +#ifdef __cplusplus +extern "C" { +#endif + +enum { + RM_USED = 1<<0, /* resource has been used */ + RM_MALLORN = 1<<1 /* this is not wood. it's mallorn */ +}; + +typedef struct rawmaterial { + const struct rawmaterial_type * type; + int amount : 16; + int level : 8; + int flags : 8; + int base : 8; + int divisor : 8; + int startlevel : 8; + struct rawmaterial * next; +} rawmaterial; + +typedef struct rawmaterial_type { + char * name; + const struct resource_type * rtype; + + void (*terraform) (struct rawmaterial *, const struct region *); + void (*update) (struct rawmaterial *, const struct region *); + void (*use) (struct rawmaterial *, const struct region *, int amount); + int (*visible) (const struct rawmaterial *, int skilllevel); + + /* no initialization required */ + struct rawmaterial_type * next; +} rawmaterial_type; + +extern struct rawmaterial_type * rawmaterialtypes; + +extern void update_resources(struct region * r); +extern void terraform_resources(struct region * r); +extern void read_resources(struct region * r); +extern void write_resources(struct region * r); +extern struct rawmaterial * rm_get(struct region *, const struct resource_type *); +extern struct rawmaterial_type * rmt_find(const char * str); +extern struct rawmaterial_type * rmt_get(const struct resource_type *); + +extern void add_resource(struct region * r, int level, int base, int divisor, const struct resource_type * rtype); +extern struct rawmaterial_type * rmt_create(const struct resource_type * rtype, const char * name); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/save.c b/src/kernel/save.c index 67c268d45..b303acb16 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1,1890 +1,1889 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "save.h" - -#include "alchemy.h" -#include "alliance.h" -#include "connection.h" -#include "building.h" -#include "faction.h" -#include "group.h" -#include "item.h" -#include "magic.h" -#include "message.h" -#include "move.h" -#include "objtypes.h" -#include "order.h" -#include "pathfinder.h" -#include "plane.h" -#include "race.h" -#include "region.h" -#include "resources.h" -#include "ship.h" -#include "skill.h" -#include "spell.h" -#include "terrain.h" -#include "terrainid.h" /* only for conversion code */ -#include "unit.h" -#include "version.h" - -#include "textstore.h" -#include "binarystore.h" - -/* attributes includes */ -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* libc includes */ -#include -#include -#include -#include -#include - -#define xisdigit(c) (((c) >= '0' && (c) <= '9') || (c) == '-') - -#define ESCAPE_FIX -#define MAXORDERS 256 -#define MAXPERSISTENT 128 - -/* exported symbols symbols */ -const char * game_name = "eressea"; -int firstx = 0, firsty = 0; -int enc_gamedata = 0; - -/* local symbols */ -static region * current_region; - -char * -rns(FILE * f, char *c, size_t size) -{ - char * s = c; - do { - *s = (char) getc(f); - } while (*s!='"'); - - for (;;) { - *s = (char) getc(f); - if (*s=='"') break; - if (s0) str+=ret; - else { - log_error(("input data was not iso-8859-1! assuming utf-8\n")); - encoding = XML_CHAR_ENCODING_ERROR; - *str++ = (char)c; - } - } else { - *str++ = (char)c; - } - } - } - break; - default: - if ((size_t)(str-start+1)0) str+=ret; - else { - log_error(("input data was not iso-8859-1! assuming utf-8\n")); - encoding = XML_CHAR_ENCODING_ERROR; - *str++ = (char)c; - } - } else { - *str++ = (char)c; - } - } - } - } -} - - -/** writes a quoted string to the file -* no trailing space, since this is used to make the creport. -*/ -int -fwritestr(FILE * F, const char * str) -{ - int nwrite = 0; - fputc('\"', F); - if (str) while (*str) { - int c = (int)(unsigned char)*str++; - switch (c) { - case '"': - case '\\': - fputc('\\', F); - fputc(c, F); - nwrite+=2; - break; - case '\n': - fputc('\\', F); - fputc('n', F); - nwrite+=2; - break; - default: - fputc(c, F); - ++nwrite; - } - } - fputc('\"', F); - return nwrite + 2; -} - -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->race == new_race[RC_SPELL]) return 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; - if (!is_repeated(ord)) { - *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]) { - const char * stok = s; - stok = parse_token(&stok); - - if (stok) { - boolean 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; - } - } - if (quit) break; - } - /* Nun wird der Befehl erzeut und eingehängt */ - *ordp = parse_order(s, u->faction->locale); - if (*ordp) ordp = &(*ordp)->next; - } - } - - } else { - /* cmistake(?, buf, 160, MSG_EVENT); */ - return NULL; - } - return u; -} - -static faction * -factionorders(void) -{ - faction * f = NULL; - int fid = getid(); - - f = findfaction(fid); - - if (f!=NULL && !is_monsters(f)) { - const char * pass = getstrtoken(); - - if (!checkpasswd(f, (const char *)pass, true)) { - log_warning(("Invalid password for faction %s\n", itoa36(fid))); - ADDMSG(&f->msgs, msg_message("wrongpasswd", "faction password", - f->no, pass)); - return 0; - } - /* Die Partei hat sich zumindest gemeldet, so daß sie noch - * nicht als untätig gilt */ - - /* TODO: +1 ist ein Workaround, weil cturn erst in process_orders - * incrementiert wird. */ - f->lastorders = global.data_turn+1; - - } else { - log_warning(("orders for invalid faction %s\n", itoa36(fid))); - } - return f; -} - -double -version(void) -{ - return RELEASE_VERSION * 0.1; -} -/* ------------------------------------------------------------- */ - -static param_t -igetparam (const char *s, const struct locale *lang) -{ - return findparam (igetstrtoken (s), lang); -} - -int -readorders(const char *filename) -{ - FILE * F = NULL; - const char *b; - int nfactions=0; - struct faction *f = NULL; - - if (filename) F = cfopen(filename, "rb"); - if (F==NULL) return 0; - - if (verbosity>=1) puts(" - lese Befehlsdatei...\n"); - - /* TODO: recognize UTF8 BOM */ - b = getbuf(F, enc_gamedata); - - /* Auffinden der ersten Partei, und danach abarbeiten bis zur letzten - * Partei */ - - while (b) { - const struct locale * lang = f?f->locale:default_locale; - int p; - const char * s; - - switch (igetparam(b, lang)) { - case P_LOCALE: - s = getstrtoken(); -#undef LOCALE_CHANGE -#ifdef LOCALE_CHANGE - if (f && find_locale(s)) { - f->locale = find_locale(s); - } -#endif - - b = getbuf(F, enc_gamedata); - break; - 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; - p = igetparam(b, lang); - } 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 - * muß buf erneut gefüllt werden, da die betreffende Information in nur - * einer Zeile steht, und nun die nächste gelesen werden muß. */ - - case P_NEXT: - f = NULL; - b = getbuf(F, enc_gamedata); - break; - - default: - b = getbuf(F, enc_gamedata); - break; - } - } - - fclose(F); - puts("\n"); - log_printf(" %d Befehlsdateien gelesen\n", nfactions); - return 0; -} -/* ------------------------------------------------------------- */ - -/* #define INNER_WORLD */ -/* fürs debuggen nur den inneren Teil der Welt laden */ -/* -9;-27;-1;-19;Sumpfloch */ -int -inner_world(region * r) -{ - static int xy[2] = - {18, -45}; - static int size[2] = - {27, 27}; - - if (r->x >= xy[0] && r->x < xy[0] + size[0] && r->y >= xy[1] && r->y < xy[1] + size[1]) - return 2; - if (r->x >= xy[0] - 9 && r->x < xy[0] + size[0] + 9 && r->y >= xy[1] - 9 && r->y < xy[1] + size[1] + 9) - return 1; - return 0; -} - -int maxregions = -1; -int loadplane = 0; - -enum { - U_MAN, - U_UNDEAD, - U_ILLUSION, - U_FIREDRAGON, - U_DRAGON, - U_WYRM, - U_SPELL, - U_TAVERNE, - U_MONSTER, - U_BIRTHDAYDRAGON, - U_TREEMAN, - MAXTYPES -}; - -race_t -typus2race(unsigned char typus) -{ - if (typus>0 && typus <=11) return (race_t)(typus-1); - return NORACE; -} - -void -create_backup(char *file) -{ -#ifdef HAVE_LINK - char bfile[MAX_PATH]; - int c = 1; - - if (access(file, R_OK) == 0) return; - do { - sprintf(bfile, "%s.backup%d", file, c); - c++; - } while(access(bfile, R_OK) == 0); - link(file, bfile); -#endif -} - -void -read_items(struct storage * store, item **ilist) -{ - for (;;) { - char ibuf[32]; - const item_type * itype; - int i; - store->r_str_buf(store, ibuf, sizeof(ibuf)); - if (!strcmp("end", ibuf)) break; - itype = it_find(ibuf); - i = store->r_int(store); - if (i<=0) { - log_error(("data contains an entry with %d %s\n", i, itype->rtype->_name[1])); - } else { - assert(itype!=NULL); - if (itype!=NULL) { - i_change(ilist, itype, i); - } - } - } -} - -static void -read_alliances(struct storage * store) -{ - char pbuf[8]; - int id, terminator = 0; - if (store->versionversionr_str_buf(store, pbuf, sizeof(pbuf)); - id = atoi36(pbuf); - } else { - id = store->r_id(store); - } - while (id!=terminator) { - char aname[128]; - alliance * al; - store->r_str_buf(store, aname, sizeof(aname)); - al = makealliance(id, aname); - if (store->version>=OWNER_2_VERSION) { - al->flags = store->r_int(store); - } - if (store->version>=ALLIANCELEADER_VERSION) { - read_reference(&al->_leader, store, read_faction_reference, resolve_faction); - id = store->r_id(store); - } else{ - store->r_str_buf(store, pbuf, sizeof(pbuf)); - id = atoi36(pbuf); - } - } -} - -void -write_alliances(struct storage * store) -{ - alliance * al = alliances; - while (al) { - if (al->_leader) { - store->w_id(store, al->id); - store->w_str(store, al->name); - store->w_int(store, (int)al->flags); - write_faction_reference(al->_leader, store); - store->w_brk(store); - } - al = al->next; - } - store->w_id(store, 0); - store->w_brk(store); -} - -void -write_items(struct storage * store, item *ilist) -{ - item * itm; - for (itm=ilist;itm;itm=itm->next) { - assert(itm->number>=0); - if (itm->number) { - store->w_tok(store, resourcename(itm->type->rtype, 0)); - store->w_int(store, itm->number); - } - } - store->w_tok(store, "end"); -} - -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)\n", itoa36(id.i))); - f = get_monsters(); - } - } - owner->owner = f; - if (f) { - owner->alliance = f->alliance; - } - return result; -} - -static void -read_owner(struct storage * store, region_owner **powner) -{ - int since_turn = store->r_int(store); - if (since_turn>=0) { - region_owner * owner = malloc(sizeof(region_owner)); - owner->since_turn = since_turn; - owner->morale_turn = store->r_int(store); - if (store->version>=MOURNING_VERSION) { - owner->flags = store->r_int(store); - } else { - owner->flags = 0; - } - if (store->version>=OWNER_2_VERSION) { - int id = store->r_int(store); - owner->alliance = id?findalliance(id):NULL; - } else { - owner->alliance = NULL; - } - read_reference(owner, store, &read_faction_reference, &resolve_owner); - *powner = owner; - } else { - *powner = 0; - } -} - -static void -write_owner(struct storage * store, region_owner *owner) -{ - if (owner) { - store->w_int(store, owner->since_turn); - store->w_int(store, owner->morale_turn); - store->w_int(store, owner->flags); - store->w_id(store, owner->alliance?owner->alliance->id:0); - write_faction_reference(owner->owner, store); - } else { - store->w_int(store, -1); - } -} - -int -current_turn(void) -{ - char zText[MAX_PATH]; - int cturn = 0; - FILE * f; - - sprintf(zText, "%s/turn", basepath()); - f = cfopen(zText, "r"); - if (f) { - fscanf(f, "%d\n", &cturn); - fclose(f); - } - return cturn; -} - -static void -writeorder(struct storage * store, const struct order * ord, const struct locale * lang) -{ - char obuf[1024]; - write_order(ord, obuf, sizeof(obuf)); - if (obuf[0]) store->w_str(store, obuf); -} - -unit * -read_unit(struct storage * store) -{ - skill_t sk; - unit * u; - int number, n, p; - order ** orderp; - char obuf[1024]; - faction * f; - char rname[32]; - - n = store->r_id(store); - if (n<=0) return NULL; - u = findunit(n); - if (u==NULL) { - u = calloc(sizeof(unit), 1); - u->no = n; - uhash(u); - } else { - while (u->attribs) a_remove(&u->attribs, u->attribs); - while (u->items) i_free(i_remove(&u->items, u->items)); - free(u->skills); - u->skills = 0; - u->skill_size = 0; - u_setfaction(u, NULL); - } - - n = store->r_id(store); - f = findfaction(n); - if (f!=u->faction) u_setfaction(u, f); - - u->name = store->r_str(store); - if (lomem) { - store->r_str_buf(store, NULL, 0); - } else { - u->display = store->r_str(store); - } - number = store->r_int(store); - u->age = (short)store->r_int(store); - - if (store->versionr_str_buf(store, rname, sizeof(rname)); - space = strchr(rname, ' '); - if (space!=NULL) { - char * inc = space+1; - char * outc = space; - do { - while (*inc==' ') ++inc; - while (*inc) { - *outc++ = *inc++; - if (*inc==' ') break; - } - } while (*inc); - *outc = 0; - } - } else { - store->r_tok_buf(store, rname, sizeof(rname)); - } - u->race = rc_find(rname); - assert(u->race); - if (store->versionr_str_buf(store, rname, sizeof(rname)); - } else { - store->r_tok_buf(store, rname, sizeof(rname)); - } - if (rname[0] && skill_enabled[SK_STEALTH]) u->irace = rc_find(rname); - else u->irace = NULL; - - if (u->race->describe) { - const char * rcdisp = u->race->describe(u, u->faction->locale); - if (u->display && rcdisp) { - /* see if the data file contains old descriptions */ - if (strcmp(rcdisp, u->display)==0) { - free(u->display); - u->display = NULL; - } - } - } - if (u->faction == NULL) { - log_error(("unit %s has faction == NULL\n", unitname(u))); - u_setfaction(u, get_monsters()); - set_number(u, 0); - } - - if (count_unit(u) && u->faction) u->faction->no_units++; - - set_number(u, number); - - n = store->r_id(store); - if (n>0) u->building = findbuilding(n); - - n = store->r_id(store); - if (n>0) u->ship = findship(n); - - setstatus(u, store->r_int(store)); - u->flags = store->r_int(store); - u->flags &= UFL_SAVEMASK; - if ((u->flags&UFL_ANON_FACTION) && !rule_stealth_faction()) { - /* if this rule is broken, then fix broken units */ - u->flags -= UFL_ANON_FACTION; - log_warning(("%s was anonymous.\n", unitname(u))); - } - /* Persistente Befehle einlesen */ - free_orders(&u->orders); - store->r_str_buf(store, obuf, sizeof(obuf)); - p = n = 0; - orderp = &u->orders; - while (obuf[0]) { - if (!lomem) { - order * ord = parse_order(obuf, u->faction->locale); - if (ord!=NULL) { - if (++nnext; - ord = NULL; - } else if (p==MAXPERSISTENT) { - log_warning(("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT)); - } - } else if (n==MAXORDERS) { - log_warning(("%s had %d or more orders\n", unitname(u), MAXORDERS)); - } - if (ord!=NULL) free_order(ord); - } - } - store->r_str_buf(store, obuf, sizeof(obuf)); - } - if (store->versionr_str_buf(store, obuf, sizeof(obuf)); - ord = parse_order(obuf, u->faction->locale); - if (ord!=NULL) { - addlist(&u->orders, ord); - } - } - set_order(&u->thisorder, NULL); - - assert(u->race); - while ((sk = (skill_t) store->r_int(store)) != NOSKILL) { - int level = store->r_int(store); - int weeks = store->r_int(store); - if (level) { - skill * sv = add_skill(u, sk); - sv->level = sv->old = (unsigned char)level; - sv->weeks = (unsigned char)weeks; - } - } - read_items(store, &u->items); - u->hp = store->r_int(store); - if (u->hp < u->number) { - log_error(("Einheit %s hat %u Personen, und %u Trefferpunkte\n", itoa36(u->no), - u->number, u->hp)); - u->hp=u->number; - } - - a_read(store, &u->attribs, u); - return u; -} - -void -write_unit(struct storage * store, const unit * u) -{ - order * ord; - int i, p = 0; - const race * irace = u_irace(u); - write_unit_reference(u, store); - write_faction_reference(u->faction, store); - store->w_str(store, (const char *)u->name); - store->w_str(store, u->display?(const char *)u->display:""); - store->w_int(store, u->number); - store->w_int(store, u->age); - store->w_tok(store, u->race->_name[0]); - store->w_tok(store, (irace && irace!=u->race)?irace->_name[0]:""); - write_building_reference(u->building, store); - write_ship_reference(u->ship, store); - store->w_int(store, u->status); - store->w_int(store, u->flags & UFL_SAVEMASK); - store->w_brk(store); - for (ord = u->old_orders; ord; ord=ord->next) { - if (++pfaction->locale); - } else { - log_error(("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT)); - break; - } - } - for (ord = u->orders; ord; ord=ord->next) { - if (u->old_orders && is_repeated(ord)) continue; /* has new defaults */ - if (is_persistent(ord)) { - if (++pfaction->locale); - } else { - log_error(("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT)); - break; - } - } - } - /* write an empty string to terminate the list */ - store->w_str(store, ""); - store->w_brk(store); - - assert(u->race); - - for (i=0;i!=u->skill_size;++i) { - skill * sv = u->skills+i; - assert(sv->weeks<=sv->level*2+1); - if (sv->level>0) { - store->w_int(store, sv->id); - store->w_int(store, sv->level); - store->w_int(store, sv->weeks); - } - } - store->w_int(store, -1); - store->w_brk(store); - write_items(store, u->items); - store->w_brk(store); - if (u->hp == 0) { - log_error(("unit %s has 0 hitpoints, adjusting.\n", itoa36(u->no))); - ((unit*)u)->hp = u->number; - } - store->w_int(store, u->hp); - store->w_brk(store); - a_write(store, u->attribs, u); - store->w_brk(store); -} - -static region * -readregion(struct storage * store, int x, int y) -{ - region * r = findregion(x, y); - const terrain_type * terrain; - char token[32]; - unsigned int uid = 0; - - if (store->version>=UID_VERSION) { - uid = store->r_int(store); - } - - if (r==NULL) { - plane * pl = findplane(x, y); - r = new_region(x, y, pl, uid); - } else { - assert(uid==0 || r->uid==uid); - current_region = r; - while (r->attribs) a_remove(&r->attribs, r->attribs); - if (r->land) { - free(r->land); /* mem leak */ - r->land->demands = 0; /* mem leak */ - } - while (r->resources) { - rawmaterial * rm = r->resources; - r->resources = rm->next; - free(rm); - } - r->land = 0; - } - if (lomem) { - store->r_str_buf(store, NULL, 0); - } else { - char info[DISPLAYSIZE]; - store->r_str_buf(store, info, sizeof(info)); - region_setinfo(r, info); - } - - if (store->version < TERRAIN_VERSION) { - int ter = store->r_int(store); - terrain = newterrain((terrain_t)ter); - if (terrain==NULL) { - log_error(("while reading datafile from pre-TERRAIN_VERSION, could not find terrain #%d.\n", ter)); - terrain = newterrain(T_PLAIN); - } - } else { - char name[64]; - store->r_str_buf(store, name, sizeof(name)); - terrain = get_terrain(name); - if (terrain==NULL) { - log_error(("Unknown terrain '%s'\n", name)); - assert(!"unknown terrain"); - } - } - r->terrain = terrain; - r->flags = (char) store->r_int(store); - - r->age = (unsigned short) store->r_int(store); - - if (fval(r->terrain, LAND_REGION)) { - r->land = calloc(1, sizeof(land_region)); - r->land->name = store->r_str(store); - } - if (r->land) { - int i; - rawmaterial ** pres = &r->resources; - - i = store->r_int(store); - if (i<0) { - log_error(("number of trees in %s is %d.\n", - regionname(r, NULL), i)); - i=0; - } - rsettrees(r, 0, i); - i = store->r_int(store); - if (i<0) { - log_error(("number of young trees in %s is %d.\n", - regionname(r, NULL), i)); - i=0; - } - rsettrees(r, 1, i); - i = store->r_int(store); - if (i<0) { - log_error(("number of seeds in %s is %d.\n", - regionname(r, NULL), i)); - i=0; - } - rsettrees(r, 2, i); - - i = store->r_int(store); rsethorses(r, i); - assert(*pres==NULL); - for (;;) { - rawmaterial * res; - store->r_str_buf(store, token, sizeof(token)); - if (strcmp(token, "end")==0) break; - res = malloc(sizeof(rawmaterial)); - res->type = rmt_find(token); - if (res->type==NULL) { - log_error(("invalid resourcetype %s in data.\n", token)); - } - assert(res->type!=NULL); - res->level = store->r_int(store); - res->amount = store->r_int(store); - res->flags = 0; - - res->startlevel = store->r_int(store); - res->base = store->r_int(store); - res->divisor = store->r_int(store); - - *pres = res; - pres=&res->next; - } - *pres = NULL; - - store->r_str_buf(store, token, sizeof(token)); - if (strcmp(token, "noherb") != 0) { - const resource_type * rtype = rt_find(token); - assert(rtype && rtype->itype && fval(rtype->itype, ITF_HERB)); - rsetherbtype(r, rtype->itype); - } else { - rsetherbtype(r, NULL); - } - rsetherbs(r, (short)store->r_int(store)); - rsetpeasants(r, store->r_int(store)); - rsetmoney(r, store->r_int(store)); - } - - assert(r->terrain!=NULL); - assert(rhorses(r) >= 0); - assert(rpeasants(r) >= 0); - assert(rmoney(r) >= 0); - - if (r->land) { - for (;;) { - const struct item_type * itype; - store->r_str_buf(store, token, sizeof(token)); - if (!strcmp(token, "end")) break; - itype = it_find(token); - assert(itype->rtype->ltype); - r_setdemand(r, itype->rtype->ltype, store->r_int(store)); - } - if (store->version>=REGIONITEMS_VERSION) { - read_items(store, &r->land->items); - } - if (store->version>=REGIONOWNER_VERSION) { - r->land->morale = (short)store->r_int(store); - if (r->land->morale<0) r->land->morale = 0; - read_owner(store, &r->land->ownership); - } - } - a_read(store, &r->attribs, r); - - return r; -} - -void -writeregion(struct storage * store, const region * r) -{ - store->w_int(store, r->uid); - store->w_str(store, region_getinfo(r)); - store->w_tok(store, r->terrain->_name); - store->w_int(store, r->flags & RF_SAVEMASK); - store->w_int(store, r->age); - store->w_brk(store); - if (fval(r->terrain, LAND_REGION)) { - const item_type *rht; - struct demand * demand; - rawmaterial * res = r->resources; - store->w_str(store, (const char *)r->land->name); - assert(rtrees(r,0)>=0); - assert(rtrees(r,1)>=0); - assert(rtrees(r,2)>=0); - store->w_int(store, rtrees(r,0)); - store->w_int(store, rtrees(r,1)); - store->w_int(store, rtrees(r,2)); - store->w_int(store, rhorses(r)); - - while (res) { - store->w_tok(store, res->type->name); - store->w_int(store, res->level); - store->w_int(store, res->amount); - store->w_int(store, res->startlevel); - store->w_int(store, res->base); - store->w_int(store, res->divisor); - res = res->next; - } - store->w_tok(store, "end"); - - rht = rherbtype(r); - if (rht) { - store->w_tok(store, resourcename(rht->rtype, 0)); - } else { - store->w_tok(store, "noherb"); - } - store->w_int(store, rherbs(r)); - store->w_int(store, rpeasants(r)); - store->w_int(store, rmoney(r)); - if (r->land) for (demand=r->land->demands; demand; demand=demand->next) { - store->w_tok(store, resourcename(demand->type->itype->rtype, 0)); - store->w_int(store, demand->value); - } - store->w_tok(store, "end"); -#if RELEASE_VERSION>=REGIONITEMS_VERSION - write_items(store, r->land->items); - store->w_brk(store); -#endif -#if RELEASE_VERSION>=REGIONOWNER_VERSION - store->w_int(store, r->land->morale); - write_owner(store, r->land->ownership); - store->w_brk(store); -#endif - } - a_write(store, r->attribs, r); - store->w_brk(store); -} - -static ally ** -addally(const faction * f, ally ** sfp, int aid, int state) -{ - struct faction * af = findfaction(aid); - ally * sf; - - state &= ~HELP_OBSERVE; -#ifndef REGIONOWNERS - state &= ~HELP_TRAVEL; -#endif - state &= HelpMask(); - - if (state==0) return sfp; - - sf = calloc(1, sizeof(ally)); - sf->faction = af; - if (!sf->faction) { - variant id; - id.i = aid; - ur_add(id, &sf->faction, resolve_faction); - } - sf->status = state & HELP_ALL; - - while (*sfp) sfp=&(*sfp)->next; - *sfp = sf; - return &sf->next; -} - -/** Reads a faction from a file. - * This function requires no context, can be called in any state. The - * faction may not already exist, however. - */ -faction * -readfaction(struct storage * store) -{ - ally **sfp; - int planes; - int i = store->r_id(store); - faction * f = findfaction(i); - char email[128]; - char token[32]; - - if (f==NULL) { - f = (faction *) calloc(1, sizeof(faction)); - f->no = i; - } else { - f->allies = NULL; /* mem leak */ - while (f->attribs) a_remove(&f->attribs, f->attribs); - } - f->subscription = store->r_int(store); - - if (alliances || store->version>=OWNER_2_VERSION) { - int allianceid = store->r_id(store); - if (allianceid>0) f->alliance = findalliance(allianceid); - if (f->alliance) { - alliance * al = f->alliance; - faction_list * flist = malloc(sizeof(faction_list)); - if (al->flags&ALF_NON_ALLIED) { - assert(!al->members || !"non-allied dummy-alliance has more than one member"); - } - flist->data = f; - flist->next = al->members; - al->members = flist; - } else if (rule_region_owners()){ - /* compat fix for non-allied factions */ - alliance * al = makealliance(0, NULL); - setalliance(f, al); - } - if (store->version>=OWNER_2_VERSION) { - f->alliance_joindate = store->r_int(store); - } else { - f->alliance_joindate = turn - 10; /* we're guessing something safe here */ - } - } - - f->name = store->r_str(store); - f->banner = store->r_str(store); - - log_info((3, " - Lese Partei %s (%s)\n", f->name, factionid(f))); - - store->r_str_buf(store, email, sizeof(email)); - if (set_email(&f->email, email)!=0) { - log_warning(("Invalid email address for faction %s: %s\n", itoa36(f->no), email)); - set_email(&f->email, ""); - } - - f->passw = store->r_str(store); - if (store->version >= OVERRIDE_VERSION) { - f->override = store->r_str(store); - } else { - f->override = strdup(itoa36(rng_int())); - } - - store->r_str_buf(store, token, sizeof(token)); - f->locale = find_locale(token); - f->lastorders = store->r_int(store); - f->age = store->r_int(store); - store->r_str_buf(store, token, sizeof(token)); - f->race = rc_find(token); - assert(f->race); - f->magiegebiet = (magic_t)store->r_int(store); - - if (store->versionr_int(store); - } - - f->flags = store->r_int(store); - if (f->no==0) { - f->flags |= FFL_NPC; - } - - a_read(store, &f->attribs, f); - if (store->version>=CLAIM_VERSION) { - read_items(store, &f->items); - } - for (;;) { - int level; - store->r_tok_buf(store, token, sizeof(token)); - if (strcmp("end", token)==0) break; - level = store->r_int(store); - } - planes = store->r_int(store); - while(--planes >= 0) { - int id = store->r_int(store); - int ux = store->r_int(store); - int uy = store->r_int(store); - set_ursprung(f, id, ux, uy); - } - f->newbies = 0; - - i = f->options = store->r_int(store); - - if ((i & (want(O_REPORT)|want(O_COMPUTER)))==0 && !is_monsters(f)) { - /* Kein Report eingestellt, Fehler */ - f->options = f->options | want(O_REPORT) | want(O_ZUGVORLAGE); - } - - sfp = &f->allies; - if (store->versionr_int(store); - while (--p >= 0) { - int aid = store->r_id(store); - int state = store->r_int(store); - sfp = addally(f, sfp, aid, state); - } - } else { - for (;;) { - int aid = 0; - if (store->versionr_tok_buf(store, token, sizeof(token)); - if (strcmp(token, "end")!=0) { - aid = atoi36(token); - } - } else { - aid = store->r_id(store); - } - if (aid>0) { - int state = store->r_int(store); - sfp = addally(f, sfp, aid, state); - } else { - break; - } - } - } - read_groups(store, f); - f->spellbook = NULL; - if (store->version>=REGIONOWNER_VERSION) { - read_spellist(&f->spellbook, f->magiegebiet, store); - } - return f; -} - -void -writefaction(struct storage * store, const faction * f) -{ - ally *sf; - ursprung *ur; - - write_faction_reference(f, store); - store->w_int(store, f->subscription); - if (f->alliance) { - store->w_id(store, f->alliance->id); - if (f->alliance->flags&ALF_NON_ALLIED) { - assert(f==f->alliance->_leader || !"non-allied faction is not leader of its own dummy-alliance."); - } - } - else { - store->w_id(store, 0); - } - store->w_int(store, f->alliance_joindate); - - store->w_str(store, (const char *)f->name); - store->w_str(store, (const char *)f->banner); - store->w_str(store, f->email); - store->w_tok(store, (const char *)f->passw); - store->w_tok(store, (const char *)f->override); - store->w_tok(store, locale_name(f->locale)); - store->w_int(store, f->lastorders); - store->w_int(store, f->age); - store->w_tok(store, f->race->_name[0]); - store->w_brk(store); - store->w_int(store, f->magiegebiet); - - store->w_int(store, f->flags&FFL_SAVEMASK); - a_write(store, f->attribs, f); - store->w_brk(store); - write_items(store, f->items); - store->w_brk(store); - store->w_tok(store, "end"); - store->w_brk(store); - store->w_int(store, listlen(f->ursprung)); - for (ur = f->ursprung;ur;ur=ur->next) { - store->w_int(store, ur->id); - store->w_int(store, ur->x); - store->w_int(store, ur->y); - } - store->w_brk(store); - store->w_int(store, f->options & ~want(O_DEBUG)); - store->w_brk(store); - - for (sf = f->allies; sf; sf = sf->next) { - int no = (sf->faction!=NULL)?sf->faction->no:0; - int status = alliedfaction(NULL, f, sf->faction, HELP_ALL); - if (status!=0) { - store->w_id(store, no); - store->w_int(store, sf->status); - } - } - store->w_id(store, 0); - store->w_brk(store); - write_groups(store, f->groups); - write_spelllist(f->spellbook, store); -} - -int -readgame(const char * filename, int mode, int backup) -{ - int i, n, p; - faction *f, **fp; - region *r; - building *b, **bp; - ship **shp; - unit *u; - int rmax = maxregions; - char path[MAX_PATH]; - char token[32]; - const struct building_type * bt_lighthouse = bt_find("lighthouse"); - storage my_store = (mode==IO_BINARY)?binary_store:text_store; - storage * store = &my_store; - - sprintf(path, "%s/%s", datapath(), filename); - log_printf("- reading game data from %s\n", filename); - if (backup) create_backup(path); - - store->encoding = enc_gamedata; - if (store->open(store, path, IO_READ)!=0) { - return -1; - } - enc_gamedata = store->encoding; - - assert(store->version>=MIN_VERSION || !"unsupported data format"); - assert(store->version<=RELEASE_VERSION || !"unsupported data format"); - - if (store->version >= SAVEXMLNAME_VERSION) { - char basefile[1024]; - - store->r_str_buf(store, basefile, sizeof(basefile)); - if (strcmp(game_name, basefile)!=0) { - char buffer[64]; - snprintf(buffer, sizeof(buffer), "%s.xml", game_name); - if (strcmp(basefile, buffer)!=0) { - log_warning(("game mismatch: datafile contains %s, game is %s\n", basefile, game_name)); - printf("WARNING: any key to continue, Ctrl-C to stop\n"); - getchar(); - } - } - } - a_read(store, &global.attribs, NULL); - global.data_turn = turn = store->r_int(store); - log_info((1, " - reading turn %d\n", turn)); - rng_init(turn); - ++global.cookie; - store->r_int(store); /* max_unique_id = */ - nextborder = store->r_int(store); - - /* Planes */ - planes = NULL; - n = store->r_int(store); - while(--n >= 0) { - int id = store->r_int(store); - plane *pl = getplanebyid(id); - if (pl==NULL) { - pl = calloc(1, sizeof(plane)); - } else { - log_warning(("the plane with id=%d already exists.\n", id)); - } - pl->id = id; - pl->name = store->r_str(store); - pl->minx = store->r_int(store); - pl->maxx = store->r_int(store); - pl->miny = store->r_int(store); - pl->maxy = store->r_int(store); - pl->flags = store->r_int(store); - - /* read watchers */ - store->r_str_buf(store, token, sizeof(token)); - while (strcmp(token, "end")!=0) { - watcher * w = calloc(sizeof(watcher),1); - variant fno; - fno.i = atoi36(token); - w->mode = (unsigned char)store->r_int(store); - w->next = pl->watchers; - pl->watchers = w; - ur_add(fno, &w->faction, resolve_faction); - store->r_str_buf(store, token, sizeof(token)); - } - - a_read(store, &pl->attribs, pl); - addlist(&planes, pl); - } - - /* Read factions */ - if (store->version>=ALLIANCES_VERSION) { - read_alliances(store); - } - n = store->r_int(store); - log_info((1, " - Einzulesende Parteien: %d\n", n)); - fp = &factions; - while (*fp) fp=&(*fp)->next; - - while (--n >= 0) { - faction * f = readfaction(store); - - *fp = f; - fp = &f->next; - fhash(f); - } - *fp = 0; - - /* Benutzte Faction-Ids */ - if (store->versionr_int(store); - while (i--) { - store->r_int(store); /* used faction ids. ignore. */ - } - } - - /* Regionen */ - - n = store->r_int(store); - assert(n= 0) { - unit **up; - int x = store->r_int(store); - int y = store->r_int(store); - - if ((n & 0x3FF) == 0) { /* das spart extrem Zeit */ - log_info((2, " - Einzulesende Regionen: %d/%d * %d,%d \r", rmax, n, x, y)); - } - --rmax; - - r = readregion(store, x, y); - - /* Burgen */ - p = store->r_int(store); - bp = &r->buildings; - - while (--p >= 0) { - - b = (building *) calloc(1, sizeof(building)); - b->no = store->r_id(store); - *bp = b; - bp = &b->next; - bhash(b); - b->name = store->r_str(store); - if (lomem) { - store->r_str_buf(store, NULL, 0); - } - else { - b->display = store->r_str(store); - } - b->size = store->r_int(store); - store->r_str_buf(store, token, sizeof(token)); - b->type = bt_find(token); - b->region = r; - a_read(store, &b->attribs, b); - if (b->type==bt_lighthouse) { - r->flags |= RF_LIGHTHOUSE; - } - } - /* Schiffe */ - - p = store->r_int(store); - shp = &r->ships; - - while (--p >= 0) { - ship * sh = (ship *) calloc(1, sizeof(ship)); - sh->region = r; - sh->no = store->r_id(store); - *shp = sh; - shp = &sh->next; - shash(sh); - sh->name = store->r_str(store); - if (lomem) { - store->r_str_buf(store, NULL, 0); - } - else { - sh->display = store->r_str(store); - } - store->r_str_buf(store, token, sizeof(token)); - sh->type = st_find(token); - if (sh->type==NULL) { - /* old datafiles */ - sh->type = st_find((const char *)locale_string(default_locale, token)); - } - assert(sh->type || !"ship_type not registered!"); - sh->size = store->r_int(store); - sh->damage = store->r_int(store); - if (store->version>=FOSS_VERSION) { - sh->flags = store->r_int(store); - } - - /* Attribute rekursiv einlesen */ - - sh->coast = (direction_t)store->r_int(store); - if (sh->type->flags & SFL_NOCOAST) { - sh->coast = NODIRECTION; - } - a_read(store, &sh->attribs, sh); - } - - *shp = 0; - - /* Einheiten */ - - p = store->r_int(store); - up = &r->units; - - while (--p >= 0) { - unit * u = read_unit(store); - sc_mage * mage; - - assert(u->region==NULL); - u->region = r; - *up = u; - up = &u->next; - - update_interval(u->faction, u->region); - mage = get_mage(u); - if (mage) { - faction * f = u->faction; - int skl = effskill(u, SK_MAGIC); - if (!is_monsters(f) && f->magiegebiet==M_GRAY) { - log_error(("faction %s had magic=gray, fixing (%s)\n", - factionname(f), magic_school[mage->magietyp])); - f->magiegebiet = mage->magietyp; - } - if (f->max_spelllevelmax_spelllevel = skl; - } - if (mage->spellcount<0) { - mage->spellcount = 0; - updatespelllist(u); - } - } - } - } - log_info((1, "\n")); - read_borders(store); - - store->close(store); - - /* Unaufgeloeste Zeiger initialisieren */ - log_info((1, "fixing unresolved references.\n")); - resolve(); - - log_info((1, "updating area information for lighthouses.\n")); - for (r=regions;r;r=r->next) { - if (r->flags & RF_LIGHTHOUSE) { - building * b; - for (b=r->buildings;b;b=b->next) update_lighthouse(b); - } - } - log_info((1, "marking factions as alive.\n")); - for (f = factions; f; f = f->next) { - if (f->flags & FFL_NPC) { - f->alive = 1; - if (f->no==0) { - int no=666; - while (findfaction(no)) ++no; - log_warning(("renum(monsters, %d)\n", no)); - renumber_faction(f, no); - } - } else { - for (u = f->units; u; u = u->nextF) { - if (u->number>0) { - f->alive = 1; - break; - } - } - } - } - if (loadplane || maxregions>=0) { - remove_empty_factions(); - } - log_info((1, "Done loading turn %d.\n", turn)); - return 0; -} - -static void -clear_monster_orders(void) -{ - faction * f = get_monsters(); - if (f) { - unit * u; - for (u=f->units;u;u=u->nextF) { - free_orders(&u->orders); - } - } -} - -int -writegame(const char *filename, int mode) -{ - char *base; - int n; - faction *f; - region *r; - building *b; - ship *sh; - unit *u; - plane *pl; - char path[MAX_PATH]; - storage my_store = (mode==IO_BINARY)?binary_store:text_store; - storage * store = &my_store; - store->version = RELEASE_VERSION; - - clear_monster_orders(); - sprintf(path, "%s/%s", datapath(), filename); -#ifdef HAVE_UNISTD_H - if (access(path, R_OK) == 0) { - /* make sure we don't overwrite some hardlinkedfile */ - unlink(path); - } -#endif - - store->encoding = enc_gamedata; - if (store->open(store, path, IO_WRITE)!=0) { - return -1; - } - - /* globale Variablen */ - - base = strrchr(game_name, '/'); - if (base) { - store->w_str(store, base+1); - } else { - store->w_str(store, game_name); - } - store->w_brk(store); - - a_write(store, global.attribs, NULL); - store->w_brk(store); - - store->w_int(store, turn); - store->w_int(store, 0/*max_unique_id*/); - store->w_int(store, nextborder); - - /* Write planes */ - store->w_brk(store); - store->w_int(store, listlen(planes)); - store->w_brk(store); - - for(pl = planes; pl; pl=pl->next) { - watcher * w; - store->w_int(store, pl->id); - store->w_str(store, pl->name); - store->w_int(store, pl->minx); - store->w_int(store, pl->maxx); - store->w_int(store, pl->miny); - store->w_int(store, pl->maxy); - store->w_int(store, pl->flags); - w = pl->watchers; - while (w) { - if (w->faction) { - write_faction_reference(w->faction, store); - store->w_int(store, w->mode); - } - w = w->next; - } - store->w_tok(store, "end"); - a_write(store, pl->attribs, pl); - store->w_brk(store); - } - - - /* Write factions */ -#if RELEASE_VERSION>=ALLIANCES_VERSION - write_alliances(store); -#endif - n = listlen(factions); - store->w_int(store, n); - store->w_brk(store); - - log_info((1, " - Schreibe %d Parteien...\n", n)); - for (f = factions; f; f = f->next) { - writefaction(store, f); - store->w_brk(store); - } - - /* Write regions */ - - n=listlen(regions); - store->w_int(store, n); - store->w_brk(store); - log_info((1, " - Schreibe Regionen: %d \r", n)); - - for (r = regions; r; r = r->next, --n) { - /* plus leerzeile */ - if ((n%1024)==0) { /* das spart extrem Zeit */ - log_info((2, " - Schreibe Regionen: %d \r", n)); - fflush(stdout); - } - store->w_brk(store); - store->w_int(store, r->x); - store->w_int(store, r->y); - writeregion(store, r); - - store->w_int(store, listlen(r->buildings)); - store->w_brk(store); - for (b = r->buildings; b; b = b->next) { - write_building_reference(b, store); - store->w_str(store, b->name); - store->w_str(store, b->display?b->display:""); - store->w_int(store, b->size); - store->w_tok(store, b->type->_name); - store->w_brk(store); - a_write(store, b->attribs, b); - store->w_brk(store); - } - - store->w_int(store, listlen(r->ships)); - store->w_brk(store); - for (sh = r->ships; sh; sh = sh->next) { - assert(sh->region == r); - write_ship_reference(sh, store); - store->w_str(store, (const char *)sh->name); - store->w_str(store, sh->display?(const char *)sh->display:""); - store->w_tok(store, sh->type->name[0]); - store->w_int(store, sh->size); - store->w_int(store, sh->damage); - store->w_int(store, sh->flags & SFL_SAVEMASK); - assert((sh->type->flags & SFL_NOCOAST)==0 || sh->coast == NODIRECTION); - store->w_int(store, sh->coast); - store->w_brk(store); - a_write(store, sh->attribs, sh); - store->w_brk(store); - } - - store->w_int(store, listlen(r->units)); - store->w_brk(store); - for (u = r->units; u; u = u->next) { - write_unit(store, u); - } - } - store->w_brk(store); - write_borders(store); - store->w_brk(store); - - store->close(store); - - log_info((1, "\nOk.\n")); - return 0; -} - -int -a_readint(attrib * a, void * owner, struct storage * store) -{ - /* assert(sizeof(int)==sizeof(a->data)); */ - a->data.i = store->r_int(store); - return AT_READ_OK; -} - -void -a_writeint(const attrib * a, const void * owner, struct storage * store) -{ - store->w_int(store, a->data.i); -} - -int -a_readshorts(attrib * a, void * owner, struct storage * store) -{ - if (store->versiondata.sa[0] = (short)store->r_int(store); - a->data.sa[1] = (short)store->r_int(store); - return AT_READ_OK; -} - -void -a_writeshorts(const attrib * a, const void * owner, struct storage * store) -{ - store->w_int(store, a->data.sa[0]); - store->w_int(store, a->data.sa[1]); -} - -int -a_readchars(attrib * a, void * owner, struct storage * store) -{ - int i; - if (store->versiondata.ca[i] = (char)store->r_int(store); - } - return AT_READ_OK; -} - -void -a_writechars(const attrib * a, const void * owner, struct storage * store) -{ - int i; - - for (i=0;i!=4;++i) { - store->w_int(store, a->data.ca[i]); - } -} - -int -a_readvoid(attrib * a, void * owner, struct storage * store) -{ - if (store->versiondata.v = store->r_str(store); - return AT_READ_OK; -} - -void -a_writestring(const attrib * a, const void * owner, struct storage * store) -{ - assert(a->data.v); - store->w_str(store, (const char *)a->data.v); -} - -void -a_finalizestring(attrib * a) -{ - free(a->data.v); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "save.h" + +#include "alchemy.h" +#include "alliance.h" +#include "connection.h" +#include "building.h" +#include "faction.h" +#include "group.h" +#include "item.h" +#include "magic.h" +#include "message.h" +#include "move.h" +#include "objtypes.h" +#include "order.h" +#include "pathfinder.h" +#include "plane.h" +#include "race.h" +#include "region.h" +#include "resources.h" +#include "ship.h" +#include "skill.h" +#include "spell.h" +#include "terrain.h" +#include "terrainid.h" /* only for conversion code */ +#include "unit.h" +#include "version.h" + +#include "textstore.h" +#include "binarystore.h" + +/* attributes includes */ +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +#define xisdigit(c) (((c) >= '0' && (c) <= '9') || (c) == '-') + +#define ESCAPE_FIX +#define MAXORDERS 256 +#define MAXPERSISTENT 128 + +/* exported symbols symbols */ +const char * game_name = "eressea"; +int firstx = 0, firsty = 0; +int enc_gamedata = 0; + +/* local symbols */ +static region * current_region; + +char * +rns(FILE * f, char *c, size_t size) +{ + char * s = c; + do { + *s = (char) getc(f); + } while (*s!='"'); + + for (;;) { + *s = (char) getc(f); + if (*s=='"') break; + if (s0) str+=ret; + else { + log_error(("input data was not iso-8859-1! assuming utf-8\n")); + encoding = ENCODING_ERROR; + *str++ = (char)c; + } + } else { + *str++ = (char)c; + } + } + } + break; + default: + if ((size_t)(str-start+1)0) str+=ret; + else { + log_error(("input data was not iso-8859-1! assuming utf-8\n")); + encoding = ENCODING_ERROR; + *str++ = (char)c; + } + } else { + *str++ = (char)c; + } + } + } + } +} + + +/** writes a quoted string to the file +* no trailing space, since this is used to make the creport. +*/ +int +fwritestr(FILE * F, const char * str) +{ + int nwrite = 0; + fputc('\"', F); + if (str) while (*str) { + int c = (int)(unsigned char)*str++; + switch (c) { + case '"': + case '\\': + fputc('\\', F); + fputc(c, F); + nwrite+=2; + break; + case '\n': + fputc('\\', F); + fputc('n', F); + nwrite+=2; + break; + default: + fputc(c, F); + ++nwrite; + } + } + fputc('\"', F); + return nwrite + 2; +} + +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->race == new_race[RC_SPELL]) return 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; + if (!is_repeated(ord)) { + *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]) { + const char * stok = s; + stok = parse_token(&stok); + + if (stok) { + boolean 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; + } + } + if (quit) break; + } + /* Nun wird der Befehl erzeut und eingehängt */ + *ordp = parse_order(s, u->faction->locale); + if (*ordp) ordp = &(*ordp)->next; + } + } + + } else { + /* cmistake(?, buf, 160, MSG_EVENT); */ + return NULL; + } + return u; +} + +static faction * +factionorders(void) +{ + faction * f = NULL; + int fid = getid(); + + f = findfaction(fid); + + if (f!=NULL && !is_monsters(f)) { + const char * pass = getstrtoken(); + + if (!checkpasswd(f, (const char *)pass, true)) { + log_warning(("Invalid password for faction %s\n", itoa36(fid))); + ADDMSG(&f->msgs, msg_message("wrongpasswd", "faction password", + f->no, pass)); + return 0; + } + /* Die Partei hat sich zumindest gemeldet, so daß sie noch + * nicht als untätig gilt */ + + /* TODO: +1 ist ein Workaround, weil cturn erst in process_orders + * incrementiert wird. */ + f->lastorders = global.data_turn+1; + + } else { + log_warning(("orders for invalid faction %s\n", itoa36(fid))); + } + return f; +} + +double +version(void) +{ + return RELEASE_VERSION * 0.1; +} +/* ------------------------------------------------------------- */ + +static param_t +igetparam (const char *s, const struct locale *lang) +{ + return findparam (igetstrtoken (s), lang); +} + +int +readorders(const char *filename) +{ + FILE * F = NULL; + const char *b; + int nfactions=0; + struct faction *f = NULL; + + if (filename) F = cfopen(filename, "rb"); + if (F==NULL) return 0; + + if (verbosity>=1) puts(" - lese Befehlsdatei...\n"); + + /* TODO: recognize UTF8 BOM */ + b = getbuf(F, enc_gamedata); + + /* Auffinden der ersten Partei, und danach abarbeiten bis zur letzten + * Partei */ + + while (b) { + const struct locale * lang = f?f->locale:default_locale; + int p; + const char * s; + + switch (igetparam(b, lang)) { + case P_LOCALE: + s = getstrtoken(); +#undef LOCALE_CHANGE +#ifdef LOCALE_CHANGE + if (f && find_locale(s)) { + f->locale = find_locale(s); + } +#endif + + b = getbuf(F, enc_gamedata); + break; + 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; + p = igetparam(b, lang); + } 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 + * muß buf erneut gefüllt werden, da die betreffende Information in nur + * einer Zeile steht, und nun die nächste gelesen werden muß. */ + + case P_NEXT: + f = NULL; + b = getbuf(F, enc_gamedata); + break; + + default: + b = getbuf(F, enc_gamedata); + break; + } + } + + fclose(F); + puts("\n"); + log_printf(" %d Befehlsdateien gelesen\n", nfactions); + return 0; +} +/* ------------------------------------------------------------- */ + +/* #define INNER_WORLD */ +/* fürs debuggen nur den inneren Teil der Welt laden */ +/* -9;-27;-1;-19;Sumpfloch */ +int +inner_world(region * r) +{ + static int xy[2] = + {18, -45}; + static int size[2] = + {27, 27}; + + if (r->x >= xy[0] && r->x < xy[0] + size[0] && r->y >= xy[1] && r->y < xy[1] + size[1]) + return 2; + if (r->x >= xy[0] - 9 && r->x < xy[0] + size[0] + 9 && r->y >= xy[1] - 9 && r->y < xy[1] + size[1] + 9) + return 1; + return 0; +} + +int maxregions = -1; +int loadplane = 0; + +enum { + U_MAN, + U_UNDEAD, + U_ILLUSION, + U_FIREDRAGON, + U_DRAGON, + U_WYRM, + U_SPELL, + U_TAVERNE, + U_MONSTER, + U_BIRTHDAYDRAGON, + U_TREEMAN, + MAXTYPES +}; + +race_t +typus2race(unsigned char typus) +{ + if (typus>0 && typus <=11) return (race_t)(typus-1); + return NORACE; +} + +void +create_backup(char *file) +{ +#ifdef HAVE_LINK + char bfile[MAX_PATH]; + int c = 1; + + if (access(file, R_OK) == 0) return; + do { + sprintf(bfile, "%s.backup%d", file, c); + c++; + } while(access(bfile, R_OK) == 0); + link(file, bfile); +#endif +} + +void +read_items(struct storage * store, item **ilist) +{ + for (;;) { + char ibuf[32]; + const item_type * itype; + int i; + store->r_str_buf(store, ibuf, sizeof(ibuf)); + if (!strcmp("end", ibuf)) break; + itype = it_find(ibuf); + i = store->r_int(store); + if (i<=0) { + log_error(("data contains an entry with %d %s\n", i, itype->rtype->_name[1])); + } else { + assert(itype!=NULL); + if (itype!=NULL) { + i_change(ilist, itype, i); + } + } + } +} + +static void +read_alliances(struct storage * store) +{ + char pbuf[8]; + int id, terminator = 0; + if (store->versionversionr_str_buf(store, pbuf, sizeof(pbuf)); + id = atoi36(pbuf); + } else { + id = store->r_id(store); + } + while (id!=terminator) { + char aname[128]; + alliance * al; + store->r_str_buf(store, aname, sizeof(aname)); + al = makealliance(id, aname); + if (store->version>=OWNER_2_VERSION) { + al->flags = store->r_int(store); + } + if (store->version>=ALLIANCELEADER_VERSION) { + read_reference(&al->_leader, store, read_faction_reference, resolve_faction); + id = store->r_id(store); + } else{ + store->r_str_buf(store, pbuf, sizeof(pbuf)); + id = atoi36(pbuf); + } + } +} + +void +write_alliances(struct storage * store) +{ + alliance * al = alliances; + while (al) { + if (al->_leader) { + store->w_id(store, al->id); + store->w_str(store, al->name); + store->w_int(store, (int)al->flags); + write_faction_reference(al->_leader, store); + store->w_brk(store); + } + al = al->next; + } + store->w_id(store, 0); + store->w_brk(store); +} + +void +write_items(struct storage * store, item *ilist) +{ + item * itm; + for (itm=ilist;itm;itm=itm->next) { + assert(itm->number>=0); + if (itm->number) { + store->w_tok(store, resourcename(itm->type->rtype, 0)); + store->w_int(store, itm->number); + } + } + store->w_tok(store, "end"); +} + +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)\n", itoa36(id.i))); + f = get_monsters(); + } + } + owner->owner = f; + if (f) { + owner->alliance = f->alliance; + } + return result; +} + +static void +read_owner(struct storage * store, region_owner **powner) +{ + int since_turn = store->r_int(store); + if (since_turn>=0) { + region_owner * owner = malloc(sizeof(region_owner)); + owner->since_turn = since_turn; + owner->morale_turn = store->r_int(store); + if (store->version>=MOURNING_VERSION) { + owner->flags = store->r_int(store); + } else { + owner->flags = 0; + } + if (store->version>=OWNER_2_VERSION) { + int id = store->r_int(store); + owner->alliance = id?findalliance(id):NULL; + } else { + owner->alliance = NULL; + } + read_reference(owner, store, &read_faction_reference, &resolve_owner); + *powner = owner; + } else { + *powner = 0; + } +} + +static void +write_owner(struct storage * store, region_owner *owner) +{ + if (owner) { + store->w_int(store, owner->since_turn); + store->w_int(store, owner->morale_turn); + store->w_int(store, owner->flags); + store->w_id(store, owner->alliance?owner->alliance->id:0); + write_faction_reference(owner->owner, store); + } else { + store->w_int(store, -1); + } +} + +int +current_turn(void) +{ + char zText[MAX_PATH]; + int cturn = 0; + FILE * f; + + sprintf(zText, "%s/turn", basepath()); + f = cfopen(zText, "r"); + if (f) { + fscanf(f, "%d\n", &cturn); + fclose(f); + } + return cturn; +} + +static void +writeorder(struct storage * store, const struct order * ord, const struct locale * lang) +{ + char obuf[1024]; + write_order(ord, obuf, sizeof(obuf)); + if (obuf[0]) store->w_str(store, obuf); +} + +unit * +read_unit(struct storage * store) +{ + skill_t sk; + unit * u; + int number, n, p; + order ** orderp; + char obuf[1024]; + faction * f; + char rname[32]; + + n = store->r_id(store); + if (n<=0) return NULL; + u = findunit(n); + if (u==NULL) { + u = calloc(sizeof(unit), 1); + u->no = n; + uhash(u); + } else { + while (u->attribs) a_remove(&u->attribs, u->attribs); + while (u->items) i_free(i_remove(&u->items, u->items)); + free(u->skills); + u->skills = 0; + u->skill_size = 0; + u_setfaction(u, NULL); + } + + n = store->r_id(store); + f = findfaction(n); + if (f!=u->faction) u_setfaction(u, f); + + u->name = store->r_str(store); + if (lomem) { + store->r_str_buf(store, NULL, 0); + } else { + u->display = store->r_str(store); + } + number = store->r_int(store); + u->age = (short)store->r_int(store); + + if (store->versionr_str_buf(store, rname, sizeof(rname)); + space = strchr(rname, ' '); + if (space!=NULL) { + char * inc = space+1; + char * outc = space; + do { + while (*inc==' ') ++inc; + while (*inc) { + *outc++ = *inc++; + if (*inc==' ') break; + } + } while (*inc); + *outc = 0; + } + } else { + store->r_tok_buf(store, rname, sizeof(rname)); + } + u->race = rc_find(rname); + assert(u->race); + if (store->versionr_str_buf(store, rname, sizeof(rname)); + } else { + store->r_tok_buf(store, rname, sizeof(rname)); + } + if (rname[0] && skill_enabled[SK_STEALTH]) u->irace = rc_find(rname); + else u->irace = NULL; + + if (u->race->describe) { + const char * rcdisp = u->race->describe(u, u->faction->locale); + if (u->display && rcdisp) { + /* see if the data file contains old descriptions */ + if (strcmp(rcdisp, u->display)==0) { + free(u->display); + u->display = NULL; + } + } + } + if (u->faction == NULL) { + log_error(("unit %s has faction == NULL\n", unitname(u))); + u_setfaction(u, get_monsters()); + set_number(u, 0); + } + + if (count_unit(u) && u->faction) u->faction->no_units++; + + set_number(u, number); + + n = store->r_id(store); + if (n>0) u->building = findbuilding(n); + + n = store->r_id(store); + if (n>0) u->ship = findship(n); + + setstatus(u, store->r_int(store)); + u->flags = store->r_int(store); + u->flags &= UFL_SAVEMASK; + if ((u->flags&UFL_ANON_FACTION) && !rule_stealth_faction()) { + /* if this rule is broken, then fix broken units */ + u->flags -= UFL_ANON_FACTION; + log_warning(("%s was anonymous.\n", unitname(u))); + } + /* Persistente Befehle einlesen */ + free_orders(&u->orders); + store->r_str_buf(store, obuf, sizeof(obuf)); + p = n = 0; + orderp = &u->orders; + while (obuf[0]) { + if (!lomem) { + order * ord = parse_order(obuf, u->faction->locale); + if (ord!=NULL) { + if (++nnext; + ord = NULL; + } else if (p==MAXPERSISTENT) { + log_warning(("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT)); + } + } else if (n==MAXORDERS) { + log_warning(("%s had %d or more orders\n", unitname(u), MAXORDERS)); + } + if (ord!=NULL) free_order(ord); + } + } + store->r_str_buf(store, obuf, sizeof(obuf)); + } + if (store->versionr_str_buf(store, obuf, sizeof(obuf)); + ord = parse_order(obuf, u->faction->locale); + if (ord!=NULL) { + addlist(&u->orders, ord); + } + } + set_order(&u->thisorder, NULL); + + assert(u->race); + while ((sk = (skill_t) store->r_int(store)) != NOSKILL) { + int level = store->r_int(store); + int weeks = store->r_int(store); + if (level) { + skill * sv = add_skill(u, sk); + sv->level = sv->old = (unsigned char)level; + sv->weeks = (unsigned char)weeks; + } + } + read_items(store, &u->items); + u->hp = store->r_int(store); + if (u->hp < u->number) { + log_error(("Einheit %s hat %u Personen, und %u Trefferpunkte\n", itoa36(u->no), + u->number, u->hp)); + u->hp=u->number; + } + + a_read(store, &u->attribs, u); + return u; +} + +void +write_unit(struct storage * store, const unit * u) +{ + order * ord; + int i, p = 0; + const race * irace = u_irace(u); + write_unit_reference(u, store); + write_faction_reference(u->faction, store); + store->w_str(store, (const char *)u->name); + store->w_str(store, u->display?(const char *)u->display:""); + store->w_int(store, u->number); + store->w_int(store, u->age); + store->w_tok(store, u->race->_name[0]); + store->w_tok(store, (irace && irace!=u->race)?irace->_name[0]:""); + write_building_reference(u->building, store); + write_ship_reference(u->ship, store); + store->w_int(store, u->status); + store->w_int(store, u->flags & UFL_SAVEMASK); + store->w_brk(store); + for (ord = u->old_orders; ord; ord=ord->next) { + if (++pfaction->locale); + } else { + log_error(("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT)); + break; + } + } + for (ord = u->orders; ord; ord=ord->next) { + if (u->old_orders && is_repeated(ord)) continue; /* has new defaults */ + if (is_persistent(ord)) { + if (++pfaction->locale); + } else { + log_error(("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT)); + break; + } + } + } + /* write an empty string to terminate the list */ + store->w_str(store, ""); + store->w_brk(store); + + assert(u->race); + + for (i=0;i!=u->skill_size;++i) { + skill * sv = u->skills+i; + assert(sv->weeks<=sv->level*2+1); + if (sv->level>0) { + store->w_int(store, sv->id); + store->w_int(store, sv->level); + store->w_int(store, sv->weeks); + } + } + store->w_int(store, -1); + store->w_brk(store); + write_items(store, u->items); + store->w_brk(store); + if (u->hp == 0) { + log_error(("unit %s has 0 hitpoints, adjusting.\n", itoa36(u->no))); + ((unit*)u)->hp = u->number; + } + store->w_int(store, u->hp); + store->w_brk(store); + a_write(store, u->attribs, u); + store->w_brk(store); +} + +static region * +readregion(struct storage * store, int x, int y) +{ + region * r = findregion(x, y); + const terrain_type * terrain; + char token[32]; + unsigned int uid = 0; + + if (store->version>=UID_VERSION) { + uid = store->r_int(store); + } + + if (r==NULL) { + plane * pl = findplane(x, y); + r = new_region(x, y, pl, uid); + } else { + assert(uid==0 || r->uid==uid); + current_region = r; + while (r->attribs) a_remove(&r->attribs, r->attribs); + if (r->land) { + free(r->land); /* mem leak */ + r->land->demands = 0; /* mem leak */ + } + while (r->resources) { + rawmaterial * rm = r->resources; + r->resources = rm->next; + free(rm); + } + r->land = 0; + } + if (lomem) { + store->r_str_buf(store, NULL, 0); + } else { + char info[DISPLAYSIZE]; + store->r_str_buf(store, info, sizeof(info)); + region_setinfo(r, info); + } + + if (store->version < TERRAIN_VERSION) { + int ter = store->r_int(store); + terrain = newterrain((terrain_t)ter); + if (terrain==NULL) { + log_error(("while reading datafile from pre-TERRAIN_VERSION, could not find terrain #%d.\n", ter)); + terrain = newterrain(T_PLAIN); + } + } else { + char name[64]; + store->r_str_buf(store, name, sizeof(name)); + terrain = get_terrain(name); + if (terrain==NULL) { + log_error(("Unknown terrain '%s'\n", name)); + assert(!"unknown terrain"); + } + } + r->terrain = terrain; + r->flags = (char) store->r_int(store); + + r->age = (unsigned short) store->r_int(store); + + if (fval(r->terrain, LAND_REGION)) { + r->land = calloc(1, sizeof(land_region)); + r->land->name = store->r_str(store); + } + if (r->land) { + int i; + rawmaterial ** pres = &r->resources; + + i = store->r_int(store); + if (i<0) { + log_error(("number of trees in %s is %d.\n", + regionname(r, NULL), i)); + i=0; + } + rsettrees(r, 0, i); + i = store->r_int(store); + if (i<0) { + log_error(("number of young trees in %s is %d.\n", + regionname(r, NULL), i)); + i=0; + } + rsettrees(r, 1, i); + i = store->r_int(store); + if (i<0) { + log_error(("number of seeds in %s is %d.\n", + regionname(r, NULL), i)); + i=0; + } + rsettrees(r, 2, i); + + i = store->r_int(store); rsethorses(r, i); + assert(*pres==NULL); + for (;;) { + rawmaterial * res; + store->r_str_buf(store, token, sizeof(token)); + if (strcmp(token, "end")==0) break; + res = malloc(sizeof(rawmaterial)); + res->type = rmt_find(token); + if (res->type==NULL) { + log_error(("invalid resourcetype %s in data.\n", token)); + } + assert(res->type!=NULL); + res->level = store->r_int(store); + res->amount = store->r_int(store); + res->flags = 0; + + res->startlevel = store->r_int(store); + res->base = store->r_int(store); + res->divisor = store->r_int(store); + + *pres = res; + pres=&res->next; + } + *pres = NULL; + + store->r_str_buf(store, token, sizeof(token)); + if (strcmp(token, "noherb") != 0) { + const resource_type * rtype = rt_find(token); + assert(rtype && rtype->itype && fval(rtype->itype, ITF_HERB)); + rsetherbtype(r, rtype->itype); + } else { + rsetherbtype(r, NULL); + } + rsetherbs(r, (short)store->r_int(store)); + rsetpeasants(r, store->r_int(store)); + rsetmoney(r, store->r_int(store)); + } + + assert(r->terrain!=NULL); + assert(rhorses(r) >= 0); + assert(rpeasants(r) >= 0); + assert(rmoney(r) >= 0); + + if (r->land) { + for (;;) { + const struct item_type * itype; + store->r_str_buf(store, token, sizeof(token)); + if (!strcmp(token, "end")) break; + itype = it_find(token); + assert(itype->rtype->ltype); + r_setdemand(r, itype->rtype->ltype, store->r_int(store)); + } + if (store->version>=REGIONITEMS_VERSION) { + read_items(store, &r->land->items); + } + if (store->version>=REGIONOWNER_VERSION) { + r->land->morale = (short)store->r_int(store); + if (r->land->morale<0) r->land->morale = 0; + read_owner(store, &r->land->ownership); + } + } + a_read(store, &r->attribs, r); + + return r; +} + +void +writeregion(struct storage * store, const region * r) +{ + store->w_int(store, r->uid); + store->w_str(store, region_getinfo(r)); + store->w_tok(store, r->terrain->_name); + store->w_int(store, r->flags & RF_SAVEMASK); + store->w_int(store, r->age); + store->w_brk(store); + if (fval(r->terrain, LAND_REGION)) { + const item_type *rht; + struct demand * demand; + rawmaterial * res = r->resources; + store->w_str(store, (const char *)r->land->name); + assert(rtrees(r,0)>=0); + assert(rtrees(r,1)>=0); + assert(rtrees(r,2)>=0); + store->w_int(store, rtrees(r,0)); + store->w_int(store, rtrees(r,1)); + store->w_int(store, rtrees(r,2)); + store->w_int(store, rhorses(r)); + + while (res) { + store->w_tok(store, res->type->name); + store->w_int(store, res->level); + store->w_int(store, res->amount); + store->w_int(store, res->startlevel); + store->w_int(store, res->base); + store->w_int(store, res->divisor); + res = res->next; + } + store->w_tok(store, "end"); + + rht = rherbtype(r); + if (rht) { + store->w_tok(store, resourcename(rht->rtype, 0)); + } else { + store->w_tok(store, "noherb"); + } + store->w_int(store, rherbs(r)); + store->w_int(store, rpeasants(r)); + store->w_int(store, rmoney(r)); + if (r->land) for (demand=r->land->demands; demand; demand=demand->next) { + store->w_tok(store, resourcename(demand->type->itype->rtype, 0)); + store->w_int(store, demand->value); + } + store->w_tok(store, "end"); +#if RELEASE_VERSION>=REGIONITEMS_VERSION + write_items(store, r->land->items); + store->w_brk(store); +#endif +#if RELEASE_VERSION>=REGIONOWNER_VERSION + store->w_int(store, r->land->morale); + write_owner(store, r->land->ownership); + store->w_brk(store); +#endif + } + a_write(store, r->attribs, r); + store->w_brk(store); +} + +static ally ** +addally(const faction * f, ally ** sfp, int aid, int state) +{ + struct faction * af = findfaction(aid); + ally * sf; + + state &= ~HELP_OBSERVE; +#ifndef REGIONOWNERS + state &= ~HELP_TRAVEL; +#endif + state &= HelpMask(); + + if (state==0) return sfp; + + sf = calloc(1, sizeof(ally)); + sf->faction = af; + if (!sf->faction) { + variant id; + id.i = aid; + ur_add(id, &sf->faction, resolve_faction); + } + sf->status = state & HELP_ALL; + + while (*sfp) sfp=&(*sfp)->next; + *sfp = sf; + return &sf->next; +} + +/** Reads a faction from a file. + * This function requires no context, can be called in any state. The + * faction may not already exist, however. + */ +faction * +readfaction(struct storage * store) +{ + ally **sfp; + int planes; + int i = store->r_id(store); + faction * f = findfaction(i); + char email[128]; + char token[32]; + + if (f==NULL) { + f = (faction *) calloc(1, sizeof(faction)); + f->no = i; + } else { + f->allies = NULL; /* mem leak */ + while (f->attribs) a_remove(&f->attribs, f->attribs); + } + f->subscription = store->r_int(store); + + if (alliances || store->version>=OWNER_2_VERSION) { + int allianceid = store->r_id(store); + if (allianceid>0) f->alliance = findalliance(allianceid); + if (f->alliance) { + alliance * al = f->alliance; + faction_list * flist = malloc(sizeof(faction_list)); + if (al->flags&ALF_NON_ALLIED) { + assert(!al->members || !"non-allied dummy-alliance has more than one member"); + } + flist->data = f; + flist->next = al->members; + al->members = flist; + } else if (rule_region_owners()){ + /* compat fix for non-allied factions */ + alliance * al = makealliance(0, NULL); + setalliance(f, al); + } + if (store->version>=OWNER_2_VERSION) { + f->alliance_joindate = store->r_int(store); + } else { + f->alliance_joindate = turn - 10; /* we're guessing something safe here */ + } + } + + f->name = store->r_str(store); + f->banner = store->r_str(store); + + log_info((3, " - Lese Partei %s (%s)\n", f->name, factionid(f))); + + store->r_str_buf(store, email, sizeof(email)); + if (set_email(&f->email, email)!=0) { + log_warning(("Invalid email address for faction %s: %s\n", itoa36(f->no), email)); + set_email(&f->email, ""); + } + + f->passw = store->r_str(store); + if (store->version >= OVERRIDE_VERSION) { + f->override = store->r_str(store); + } else { + f->override = strdup(itoa36(rng_int())); + } + + store->r_str_buf(store, token, sizeof(token)); + f->locale = find_locale(token); + f->lastorders = store->r_int(store); + f->age = store->r_int(store); + store->r_str_buf(store, token, sizeof(token)); + f->race = rc_find(token); + assert(f->race); + f->magiegebiet = (magic_t)store->r_int(store); + + if (store->versionr_int(store); + } + + f->flags = store->r_int(store); + if (f->no==0) { + f->flags |= FFL_NPC; + } + + a_read(store, &f->attribs, f); + if (store->version>=CLAIM_VERSION) { + read_items(store, &f->items); + } + for (;;) { + int level; + store->r_tok_buf(store, token, sizeof(token)); + if (strcmp("end", token)==0) break; + level = store->r_int(store); + } + planes = store->r_int(store); + while(--planes >= 0) { + int id = store->r_int(store); + int ux = store->r_int(store); + int uy = store->r_int(store); + set_ursprung(f, id, ux, uy); + } + f->newbies = 0; + + i = f->options = store->r_int(store); + + if ((i & (want(O_REPORT)|want(O_COMPUTER)))==0 && !is_monsters(f)) { + /* Kein Report eingestellt, Fehler */ + f->options = f->options | want(O_REPORT) | want(O_ZUGVORLAGE); + } + + sfp = &f->allies; + if (store->versionr_int(store); + while (--p >= 0) { + int aid = store->r_id(store); + int state = store->r_int(store); + sfp = addally(f, sfp, aid, state); + } + } else { + for (;;) { + int aid = 0; + if (store->versionr_tok_buf(store, token, sizeof(token)); + if (strcmp(token, "end")!=0) { + aid = atoi36(token); + } + } else { + aid = store->r_id(store); + } + if (aid>0) { + int state = store->r_int(store); + sfp = addally(f, sfp, aid, state); + } else { + break; + } + } + } + read_groups(store, f); + f->spellbook = NULL; + if (store->version>=REGIONOWNER_VERSION) { + read_spellist(&f->spellbook, f->magiegebiet, store); + } + return f; +} + +void +writefaction(struct storage * store, const faction * f) +{ + ally *sf; + ursprung *ur; + + write_faction_reference(f, store); + store->w_int(store, f->subscription); + if (f->alliance) { + store->w_id(store, f->alliance->id); + if (f->alliance->flags&ALF_NON_ALLIED) { + assert(f==f->alliance->_leader || !"non-allied faction is not leader of its own dummy-alliance."); + } + } + else { + store->w_id(store, 0); + } + store->w_int(store, f->alliance_joindate); + + store->w_str(store, (const char *)f->name); + store->w_str(store, (const char *)f->banner); + store->w_str(store, f->email); + store->w_tok(store, (const char *)f->passw); + store->w_tok(store, (const char *)f->override); + store->w_tok(store, locale_name(f->locale)); + store->w_int(store, f->lastorders); + store->w_int(store, f->age); + store->w_tok(store, f->race->_name[0]); + store->w_brk(store); + store->w_int(store, f->magiegebiet); + + store->w_int(store, f->flags&FFL_SAVEMASK); + a_write(store, f->attribs, f); + store->w_brk(store); + write_items(store, f->items); + store->w_brk(store); + store->w_tok(store, "end"); + store->w_brk(store); + store->w_int(store, listlen(f->ursprung)); + for (ur = f->ursprung;ur;ur=ur->next) { + store->w_int(store, ur->id); + store->w_int(store, ur->x); + store->w_int(store, ur->y); + } + store->w_brk(store); + store->w_int(store, f->options & ~want(O_DEBUG)); + store->w_brk(store); + + for (sf = f->allies; sf; sf = sf->next) { + int no = (sf->faction!=NULL)?sf->faction->no:0; + int status = alliedfaction(NULL, f, sf->faction, HELP_ALL); + if (status!=0) { + store->w_id(store, no); + store->w_int(store, sf->status); + } + } + store->w_id(store, 0); + store->w_brk(store); + write_groups(store, f->groups); + write_spelllist(f->spellbook, store); +} + +int +readgame(const char * filename, int mode, int backup) +{ + int i, n, p; + faction *f, **fp; + region *r; + building *b, **bp; + ship **shp; + unit *u; + int rmax = maxregions; + char path[MAX_PATH]; + char token[32]; + const struct building_type * bt_lighthouse = bt_find("lighthouse"); + storage my_store = (mode==IO_BINARY)?binary_store:text_store; + storage * store = &my_store; + + sprintf(path, "%s/%s", datapath(), filename); + log_printf("- reading game data from %s\n", filename); + if (backup) create_backup(path); + + store->encoding = enc_gamedata; + if (store->open(store, path, IO_READ)!=0) { + return -1; + } + enc_gamedata = store->encoding; + + assert(store->version>=MIN_VERSION || !"unsupported data format"); + assert(store->version<=RELEASE_VERSION || !"unsupported data format"); + + if (store->version >= SAVEXMLNAME_VERSION) { + char basefile[1024]; + + store->r_str_buf(store, basefile, sizeof(basefile)); + if (strcmp(game_name, basefile)!=0) { + char buffer[64]; + snprintf(buffer, sizeof(buffer), "%s.xml", game_name); + if (strcmp(basefile, buffer)!=0) { + log_warning(("game mismatch: datafile contains %s, game is %s\n", basefile, game_name)); + printf("WARNING: any key to continue, Ctrl-C to stop\n"); + getchar(); + } + } + } + a_read(store, &global.attribs, NULL); + global.data_turn = turn = store->r_int(store); + log_info((1, " - reading turn %d\n", turn)); + rng_init(turn); + ++global.cookie; + store->r_int(store); /* max_unique_id = */ + nextborder = store->r_int(store); + + /* Planes */ + planes = NULL; + n = store->r_int(store); + while(--n >= 0) { + int id = store->r_int(store); + plane *pl = getplanebyid(id); + if (pl==NULL) { + pl = calloc(1, sizeof(plane)); + } else { + log_warning(("the plane with id=%d already exists.\n", id)); + } + pl->id = id; + pl->name = store->r_str(store); + pl->minx = store->r_int(store); + pl->maxx = store->r_int(store); + pl->miny = store->r_int(store); + pl->maxy = store->r_int(store); + pl->flags = store->r_int(store); + + /* read watchers */ + store->r_str_buf(store, token, sizeof(token)); + while (strcmp(token, "end")!=0) { + watcher * w = calloc(sizeof(watcher),1); + variant fno; + fno.i = atoi36(token); + w->mode = (unsigned char)store->r_int(store); + w->next = pl->watchers; + pl->watchers = w; + ur_add(fno, &w->faction, resolve_faction); + store->r_str_buf(store, token, sizeof(token)); + } + + a_read(store, &pl->attribs, pl); + addlist(&planes, pl); + } + + /* Read factions */ + if (store->version>=ALLIANCES_VERSION) { + read_alliances(store); + } + n = store->r_int(store); + log_info((1, " - Einzulesende Parteien: %d\n", n)); + fp = &factions; + while (*fp) fp=&(*fp)->next; + + while (--n >= 0) { + faction * f = readfaction(store); + + *fp = f; + fp = &f->next; + fhash(f); + } + *fp = 0; + + /* Benutzte Faction-Ids */ + if (store->versionr_int(store); + while (i--) { + store->r_int(store); /* used faction ids. ignore. */ + } + } + + /* Regionen */ + + n = store->r_int(store); + assert(n= 0) { + unit **up; + int x = store->r_int(store); + int y = store->r_int(store); + + if ((n & 0x3FF) == 0) { /* das spart extrem Zeit */ + log_info((2, " - Einzulesende Regionen: %d/%d * %d,%d \r", rmax, n, x, y)); + } + --rmax; + + r = readregion(store, x, y); + + /* Burgen */ + p = store->r_int(store); + bp = &r->buildings; + + while (--p >= 0) { + + b = (building *) calloc(1, sizeof(building)); + b->no = store->r_id(store); + *bp = b; + bp = &b->next; + bhash(b); + b->name = store->r_str(store); + if (lomem) { + store->r_str_buf(store, NULL, 0); + } + else { + b->display = store->r_str(store); + } + b->size = store->r_int(store); + store->r_str_buf(store, token, sizeof(token)); + b->type = bt_find(token); + b->region = r; + a_read(store, &b->attribs, b); + if (b->type==bt_lighthouse) { + r->flags |= RF_LIGHTHOUSE; + } + } + /* Schiffe */ + + p = store->r_int(store); + shp = &r->ships; + + while (--p >= 0) { + ship * sh = (ship *) calloc(1, sizeof(ship)); + sh->region = r; + sh->no = store->r_id(store); + *shp = sh; + shp = &sh->next; + shash(sh); + sh->name = store->r_str(store); + if (lomem) { + store->r_str_buf(store, NULL, 0); + } + else { + sh->display = store->r_str(store); + } + store->r_str_buf(store, token, sizeof(token)); + sh->type = st_find(token); + if (sh->type==NULL) { + /* old datafiles */ + sh->type = st_find((const char *)locale_string(default_locale, token)); + } + assert(sh->type || !"ship_type not registered!"); + sh->size = store->r_int(store); + sh->damage = store->r_int(store); + if (store->version>=FOSS_VERSION) { + sh->flags = store->r_int(store); + } + + /* Attribute rekursiv einlesen */ + + sh->coast = (direction_t)store->r_int(store); + if (sh->type->flags & SFL_NOCOAST) { + sh->coast = NODIRECTION; + } + a_read(store, &sh->attribs, sh); + } + + *shp = 0; + + /* Einheiten */ + + p = store->r_int(store); + up = &r->units; + + while (--p >= 0) { + unit * u = read_unit(store); + sc_mage * mage; + + assert(u->region==NULL); + u->region = r; + *up = u; + up = &u->next; + + update_interval(u->faction, u->region); + mage = get_mage(u); + if (mage) { + faction * f = u->faction; + int skl = effskill(u, SK_MAGIC); + if (!is_monsters(f) && f->magiegebiet==M_GRAY) { + log_error(("faction %s had magic=gray, fixing (%s)\n", + factionname(f), magic_school[mage->magietyp])); + f->magiegebiet = mage->magietyp; + } + if (f->max_spelllevelmax_spelllevel = skl; + } + if (mage->spellcount<0) { + mage->spellcount = 0; + updatespelllist(u); + } + } + } + } + log_info((1, "\n")); + read_borders(store); + + store->close(store); + + /* Unaufgeloeste Zeiger initialisieren */ + log_info((1, "fixing unresolved references.\n")); + resolve(); + + log_info((1, "updating area information for lighthouses.\n")); + for (r=regions;r;r=r->next) { + if (r->flags & RF_LIGHTHOUSE) { + building * b; + for (b=r->buildings;b;b=b->next) update_lighthouse(b); + } + } + log_info((1, "marking factions as alive.\n")); + for (f = factions; f; f = f->next) { + if (f->flags & FFL_NPC) { + f->alive = 1; + if (f->no==0) { + int no=666; + while (findfaction(no)) ++no; + log_warning(("renum(monsters, %d)\n", no)); + renumber_faction(f, no); + } + } else { + for (u = f->units; u; u = u->nextF) { + if (u->number>0) { + f->alive = 1; + break; + } + } + } + } + if (loadplane || maxregions>=0) { + remove_empty_factions(); + } + log_info((1, "Done loading turn %d.\n", turn)); + return 0; +} + +static void +clear_monster_orders(void) +{ + faction * f = get_monsters(); + if (f) { + unit * u; + for (u=f->units;u;u=u->nextF) { + free_orders(&u->orders); + } + } +} + +int +writegame(const char *filename, int mode) +{ + char *base; + int n; + faction *f; + region *r; + building *b; + ship *sh; + unit *u; + plane *pl; + char path[MAX_PATH]; + storage my_store = (mode==IO_BINARY)?binary_store:text_store; + storage * store = &my_store; + store->version = RELEASE_VERSION; + + clear_monster_orders(); + sprintf(path, "%s/%s", datapath(), filename); +#ifdef HAVE_UNISTD_H + if (access(path, R_OK) == 0) { + /* make sure we don't overwrite some hardlinkedfile */ + unlink(path); + } +#endif + + store->encoding = enc_gamedata; + if (store->open(store, path, IO_WRITE)!=0) { + return -1; + } + + /* globale Variablen */ + + base = strrchr(game_name, '/'); + if (base) { + store->w_str(store, base+1); + } else { + store->w_str(store, game_name); + } + store->w_brk(store); + + a_write(store, global.attribs, NULL); + store->w_brk(store); + + store->w_int(store, turn); + store->w_int(store, 0/*max_unique_id*/); + store->w_int(store, nextborder); + + /* Write planes */ + store->w_brk(store); + store->w_int(store, listlen(planes)); + store->w_brk(store); + + for(pl = planes; pl; pl=pl->next) { + watcher * w; + store->w_int(store, pl->id); + store->w_str(store, pl->name); + store->w_int(store, pl->minx); + store->w_int(store, pl->maxx); + store->w_int(store, pl->miny); + store->w_int(store, pl->maxy); + store->w_int(store, pl->flags); + w = pl->watchers; + while (w) { + if (w->faction) { + write_faction_reference(w->faction, store); + store->w_int(store, w->mode); + } + w = w->next; + } + store->w_tok(store, "end"); + a_write(store, pl->attribs, pl); + store->w_brk(store); + } + + + /* Write factions */ +#if RELEASE_VERSION>=ALLIANCES_VERSION + write_alliances(store); +#endif + n = listlen(factions); + store->w_int(store, n); + store->w_brk(store); + + log_info((1, " - Schreibe %d Parteien...\n", n)); + for (f = factions; f; f = f->next) { + writefaction(store, f); + store->w_brk(store); + } + + /* Write regions */ + + n=listlen(regions); + store->w_int(store, n); + store->w_brk(store); + log_info((1, " - Schreibe Regionen: %d \r", n)); + + for (r = regions; r; r = r->next, --n) { + /* plus leerzeile */ + if ((n%1024)==0) { /* das spart extrem Zeit */ + log_info((2, " - Schreibe Regionen: %d \r", n)); + fflush(stdout); + } + store->w_brk(store); + store->w_int(store, r->x); + store->w_int(store, r->y); + writeregion(store, r); + + store->w_int(store, listlen(r->buildings)); + store->w_brk(store); + for (b = r->buildings; b; b = b->next) { + write_building_reference(b, store); + store->w_str(store, b->name); + store->w_str(store, b->display?b->display:""); + store->w_int(store, b->size); + store->w_tok(store, b->type->_name); + store->w_brk(store); + a_write(store, b->attribs, b); + store->w_brk(store); + } + + store->w_int(store, listlen(r->ships)); + store->w_brk(store); + for (sh = r->ships; sh; sh = sh->next) { + assert(sh->region == r); + write_ship_reference(sh, store); + store->w_str(store, (const char *)sh->name); + store->w_str(store, sh->display?(const char *)sh->display:""); + store->w_tok(store, sh->type->name[0]); + store->w_int(store, sh->size); + store->w_int(store, sh->damage); + store->w_int(store, sh->flags & SFL_SAVEMASK); + assert((sh->type->flags & SFL_NOCOAST)==0 || sh->coast == NODIRECTION); + store->w_int(store, sh->coast); + store->w_brk(store); + a_write(store, sh->attribs, sh); + store->w_brk(store); + } + + store->w_int(store, listlen(r->units)); + store->w_brk(store); + for (u = r->units; u; u = u->next) { + write_unit(store, u); + } + } + store->w_brk(store); + write_borders(store); + store->w_brk(store); + + store->close(store); + + log_info((1, "\nOk.\n")); + return 0; +} + +int +a_readint(attrib * a, void * owner, struct storage * store) +{ + /* assert(sizeof(int)==sizeof(a->data)); */ + a->data.i = store->r_int(store); + return AT_READ_OK; +} + +void +a_writeint(const attrib * a, const void * owner, struct storage * store) +{ + store->w_int(store, a->data.i); +} + +int +a_readshorts(attrib * a, void * owner, struct storage * store) +{ + if (store->versiondata.sa[0] = (short)store->r_int(store); + a->data.sa[1] = (short)store->r_int(store); + return AT_READ_OK; +} + +void +a_writeshorts(const attrib * a, const void * owner, struct storage * store) +{ + store->w_int(store, a->data.sa[0]); + store->w_int(store, a->data.sa[1]); +} + +int +a_readchars(attrib * a, void * owner, struct storage * store) +{ + int i; + if (store->versiondata.ca[i] = (char)store->r_int(store); + } + return AT_READ_OK; +} + +void +a_writechars(const attrib * a, const void * owner, struct storage * store) +{ + int i; + + for (i=0;i!=4;++i) { + store->w_int(store, a->data.ca[i]); + } +} + +int +a_readvoid(attrib * a, void * owner, struct storage * store) +{ + if (store->versiondata.v = store->r_str(store); + return AT_READ_OK; +} + +void +a_writestring(const attrib * a, const void * owner, struct storage * store) +{ + assert(a->data.v); + store->w_str(store, (const char *)a->data.v); +} + +void +a_finalizestring(attrib * a) +{ + free(a->data.v); +} diff --git a/src/kernel/save.h b/src/kernel/save.h index 4f10e7090..4d11347b7 100644 --- a/src/kernel/save.h +++ b/src/kernel/save.h @@ -1,73 +1,73 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_SAVE -#define H_KRNL_SAVE -#ifdef __cplusplus -extern "C" { -#endif - -double version(void); - -#define MAX_INPUT_SIZE DISPLAYSIZE*2 -/* Nach MAX_INPUT_SIZE brechen wir das Einlesen der Zeile ab und nehmen an, - * dass hier ein Fehler (fehlende ") vorliegt */ - -FILE * cfopen(const char *filename, const char *mode); -int readorders(const char *filename); -int creategame(void); -extern int readgame(const char * filename, int mode, int backup); -int writegame(const char *filename, int mode); - -extern void rsf(FILE * F, char *s, size_t len); - -/* Versionsänderungen: */ -extern int data_version; -extern const char *game_name; -extern int enc_gamedata; - -extern void init_locales(void); -extern int current_turn(void); - -extern void read_items(struct storage * store, struct item **it); -extern void write_items(struct storage * store, struct item *it); - -extern void write_unit(struct storage * store, const struct unit * u); -extern struct unit * read_unit(struct storage * store); - -extern int a_readint(struct attrib * a, void * owner, struct storage * store); -extern void a_writeint(const struct attrib * a, const void * owner, struct storage * store); -extern int a_readshorts(struct attrib * a, void * owner, struct storage * store); -extern void a_writeshorts(const struct attrib * a, const void * owner, struct storage * store); -extern int a_readchars(struct attrib * a, void * owner, struct storage * store); -extern void a_writechars(const struct attrib * a, const void * owner, struct storage * store); -extern int a_readvoid(struct attrib * a, void * owner, struct storage * store); -extern void a_writevoid(const struct attrib * a, const void * owner, struct storage * store); -extern int a_readstring(struct attrib * a, void * owner, struct storage * store); -extern void a_writestring(const struct attrib * a, const void * owner, struct storage * store); -extern void a_finalizestring(struct attrib * a); - -extern int freadstr(FILE * F, int encoding, char * str, size_t size); -extern int fwritestr(FILE * F, const char * str); - -extern void create_backup(char *file); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_SAVE +#define H_KRNL_SAVE +#ifdef __cplusplus +extern "C" { +#endif + +double version(void); + +#define MAX_INPUT_SIZE DISPLAYSIZE*2 +/* Nach MAX_INPUT_SIZE brechen wir das Einlesen der Zeile ab und nehmen an, + * dass hier ein Fehler (fehlende ") vorliegt */ + +FILE * cfopen(const char *filename, const char *mode); +int readorders(const char *filename); +int creategame(void); +extern int readgame(const char * filename, int mode, int backup); +int writegame(const char *filename, int mode); + +extern void rsf(FILE * F, char *s, size_t len); + +/* Versionsänderungen: */ +extern int data_version; +extern const char *game_name; +extern int enc_gamedata; + +extern void init_locales(void); +extern int current_turn(void); + +extern void read_items(struct storage * store, struct item **it); +extern void write_items(struct storage * store, struct item *it); + +extern void write_unit(struct storage * store, const struct unit * u); +extern struct unit * read_unit(struct storage * store); + +extern int a_readint(struct attrib * a, void * owner, struct storage * store); +extern void a_writeint(const struct attrib * a, const void * owner, struct storage * store); +extern int a_readshorts(struct attrib * a, void * owner, struct storage * store); +extern void a_writeshorts(const struct attrib * a, const void * owner, struct storage * store); +extern int a_readchars(struct attrib * a, void * owner, struct storage * store); +extern void a_writechars(const struct attrib * a, const void * owner, struct storage * store); +extern int a_readvoid(struct attrib * a, void * owner, struct storage * store); +extern void a_writevoid(const struct attrib * a, const void * owner, struct storage * store); +extern int a_readstring(struct attrib * a, void * owner, struct storage * store); +extern void a_writestring(const struct attrib * a, const void * owner, struct storage * store); +extern void a_finalizestring(struct attrib * a); + +extern int freadstr(FILE * F, int encoding, char * str, size_t size); +extern int fwritestr(FILE * F, const char * str); + +extern void create_backup(char *file); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 5cf96aa3c..4a7764f82 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -1,338 +1,337 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "ship.h" - -/* kernel includes */ -#include "build.h" -#include "unit.h" -#include "item.h" -#include "race.h" -#include "region.h" -#include "skill.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - - -ship_typelist *shiptypes = NULL; - -static local_names * snames; - -const ship_type * -findshiptype(const char * name, const struct locale * lang) -{ - local_names * sn = snames; - variant var; - - while (sn) { - if (sn->lang==lang) break; - sn=sn->next; - } - if (!sn) { - struct ship_typelist * stl = shiptypes; - sn = calloc(sizeof(local_names), 1); - sn->next = snames; - sn->lang = lang; - while (stl) { - variant var; - const char * n = locale_string(lang, stl->type->name[0]); - var.v = (void*)stl->type; - addtoken(&sn->names, n, var); - stl = stl->next; - } - snames = sn; - } - if (findtoken(&sn->names, name, &var)==E_TOK_NOMATCH) return NULL; - return (const ship_type*)var.v; -} - -const ship_type * -st_find(const char* name) -{ - const struct ship_typelist * stl = shiptypes; - while (stl && strcmp(stl->type->name[0], name)) stl = stl->next; - return stl?stl->type:NULL; -} - -void -st_register(const ship_type * type) { - struct ship_typelist * stl = malloc(sizeof(ship_type)); - stl->type = type; - stl->next = shiptypes; - shiptypes = stl; -} - -#define SMAXHASH 7919 -ship *shiphash[SMAXHASH]; -void -shash(ship * s) -{ - ship *old = shiphash[s->no % SMAXHASH]; - - shiphash[s->no % SMAXHASH] = s; - s->nexthash = old; -} - -void -sunhash(ship * s) -{ - ship **show; - - for (show = &shiphash[s->no % SMAXHASH]; *show; show = &(*show)->nexthash) { - if ((*show)->no == s->no) - break; - } - if (*show) { - assert(*show == s); - *show = (*show)->nexthash; - s->nexthash = 0; - } -} - -static ship * -sfindhash(int i) -{ - ship *old; - - for (old = shiphash[i % SMAXHASH]; old; old = old->nexthash) - if (old->no == i) - return old; - return 0; -} - -struct ship * -findship(int i) -{ - return sfindhash(i); -} - -struct ship * -findshipr(const region *r, int n) -{ - ship * sh; - - for (sh = r->ships; sh; sh = sh->next) { - if (sh->no == n) { - assert(sh->region == r); - return sh; - } - } - return 0; -} - -void -damage_ship(ship * sh, double percent) -{ - double damage = DAMAGE_SCALE * sh->type->damage * percent * sh->size + sh->damage; - sh->damage = (int)damage; -} - -unit * -captain(ship *sh) -{ - unit *u; - - for(u = sh->region->units; u; u = u->next) - if(u->ship == sh && fval(u, UFL_OWNER)) return u; - - return NULL; -} - -/* Alte Schiffstypen: */ -static ship * deleted_ships; - -ship * -new_ship(const ship_type * stype, const struct locale * lang, region * r) -{ - static char buffer[7 + IDSIZE + 1]; - ship *sh = (ship *) calloc(1, sizeof(ship)); - - assert(stype); - sh->no = newcontainerid(); - sh->coast = NODIRECTION; - sh->type = stype; - sh->region = r; - - sprintf(buffer, "%s %s", LOC(lang, stype->name[0]), shipid(sh)); - sh->name = strdup(buffer); - shash(sh); - addlist(&r->ships, sh); - return sh; -} - -void -remove_ship(ship ** slist, ship * sh) -{ - region * r = sh->region; - unit * u = r->units; - - handle_event(sh->attribs, "destroy", sh); - while (u) { - if (u->ship == sh) { - leave_ship(u); - } - u = u->next; - } - sunhash(sh); - while (*slist && *slist!=sh) slist = &(*slist)->next; - assert(*slist); - *slist = sh->next; - sh->next = deleted_ships; - deleted_ships = sh; - sh->region = NULL; -} - -void -free_ship(ship * s) -{ - while (s->attribs) a_remove(&s->attribs, s->attribs); - free(s->name); - free(s->display); - free(s); -} - -void -free_ships(void) -{ - while (deleted_ships) { - ship * s = deleted_ships; - deleted_ships = s->next; - } -} - -const char * -write_shipname(const ship * sh, char * ibuf, size_t size) -{ - snprintf(ibuf, size, "%s (%s)", sh->name, itoa36(sh->no)); - ibuf[size-1] = 0; - return ibuf; -} - -const char * -shipname(const ship * sh) -{ - typedef char name[OBJECTIDSIZE + 1]; - static name idbuf[8]; - static int nextbuf = 0; - char *ibuf = idbuf[(++nextbuf) % 8]; - return write_shipname(sh, ibuf, sizeof(name)); -} - -int -shipcapacity (const ship * sh) -{ - int i = sh->type->cargo; - - /* sonst ist construction:: size nicht ship_type::maxsize */ - assert(!sh->type->construction || sh->type->construction->improvement==NULL); - - if (sh->type->construction && sh->size!=sh->type->construction->maxsize) - return 0; - -#ifdef SHIPDAMAGE - if (sh->damage) { - i = (int)ceil(i * (1.0 - sh->damage / sh->size / (double)DAMAGE_SCALE)); - } -#endif - return i; -} - -void -getshipweight(const ship * sh, int *sweight, int *scabins) -{ - unit * u; - - *sweight = 0; - *scabins = 0; - - for (u = sh->region->units; u; u = u->next) { - if (u->ship == sh) { - *sweight += weight(u); - if (sh->type->cabins) { - int pweight = u->number * u->race->weight; - /* weight goes into number of cabins, not cargo */ - *scabins += pweight; - *sweight -= pweight; - } - } - } -} - -unit * -shipowner(const ship * sh) -{ - unit *u; - unit *first = NULL; - - const region * r = sh->region; - - /* Prüfen ob Eigentümer am leben. */ - for (u = r->units; u; u = u->next) { - if (u->ship == sh) { - if (!first && u->number > 0) - first = u; - if (fval(u, UFL_OWNER) && u->number > 0) - return u; - if (u->number == 0) - freset(u, UFL_OWNER); - } - } - - /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit - * nehmen. */ - - if (first) - fset(first, UFL_OWNER); - return first; -} - -void -write_ship_reference(const struct ship * sh, struct storage * store) -{ - store->w_id(store, (sh && sh->region)?sh->no:0); -} - -void -ship_setname(ship * self, const char * name) -{ - free(self->name); - if (name) self->name = strdup(name); - else self->name = NULL; -} - -const char * -ship_getname(const ship * self) -{ - return self->name; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "ship.h" + +/* kernel includes */ +#include "build.h" +#include "unit.h" +#include "item.h" +#include "race.h" +#include "region.h" +#include "skill.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + + +ship_typelist *shiptypes = NULL; + +static local_names * snames; + +const ship_type * +findshiptype(const char * name, const struct locale * lang) +{ + local_names * sn = snames; + variant var; + + while (sn) { + if (sn->lang==lang) break; + sn=sn->next; + } + if (!sn) { + struct ship_typelist * stl = shiptypes; + sn = calloc(sizeof(local_names), 1); + sn->next = snames; + sn->lang = lang; + while (stl) { + variant var; + const char * n = locale_string(lang, stl->type->name[0]); + var.v = (void*)stl->type; + addtoken(&sn->names, n, var); + stl = stl->next; + } + snames = sn; + } + if (findtoken(&sn->names, name, &var)==E_TOK_NOMATCH) return NULL; + return (const ship_type*)var.v; +} + +const ship_type * +st_find(const char* name) +{ + const struct ship_typelist * stl = shiptypes; + while (stl && strcmp(stl->type->name[0], name)) stl = stl->next; + return stl?stl->type:NULL; +} + +void +st_register(const ship_type * type) { + struct ship_typelist * stl = malloc(sizeof(ship_type)); + stl->type = type; + stl->next = shiptypes; + shiptypes = stl; +} + +#define SMAXHASH 7919 +ship *shiphash[SMAXHASH]; +void +shash(ship * s) +{ + ship *old = shiphash[s->no % SMAXHASH]; + + shiphash[s->no % SMAXHASH] = s; + s->nexthash = old; +} + +void +sunhash(ship * s) +{ + ship **show; + + for (show = &shiphash[s->no % SMAXHASH]; *show; show = &(*show)->nexthash) { + if ((*show)->no == s->no) + break; + } + if (*show) { + assert(*show == s); + *show = (*show)->nexthash; + s->nexthash = 0; + } +} + +static ship * +sfindhash(int i) +{ + ship *old; + + for (old = shiphash[i % SMAXHASH]; old; old = old->nexthash) + if (old->no == i) + return old; + return 0; +} + +struct ship * +findship(int i) +{ + return sfindhash(i); +} + +struct ship * +findshipr(const region *r, int n) +{ + ship * sh; + + for (sh = r->ships; sh; sh = sh->next) { + if (sh->no == n) { + assert(sh->region == r); + return sh; + } + } + return 0; +} + +void +damage_ship(ship * sh, double percent) +{ + double damage = DAMAGE_SCALE * sh->type->damage * percent * sh->size + sh->damage; + sh->damage = (int)damage; +} + +unit * +captain(ship *sh) +{ + unit *u; + + for(u = sh->region->units; u; u = u->next) + if(u->ship == sh && fval(u, UFL_OWNER)) return u; + + return NULL; +} + +/* Alte Schiffstypen: */ +static ship * deleted_ships; + +ship * +new_ship(const ship_type * stype, const struct locale * lang, region * r) +{ + static char buffer[7 + IDSIZE + 1]; + ship *sh = (ship *) calloc(1, sizeof(ship)); + + assert(stype); + sh->no = newcontainerid(); + sh->coast = NODIRECTION; + sh->type = stype; + sh->region = r; + + sprintf(buffer, "%s %s", LOC(lang, stype->name[0]), shipid(sh)); + sh->name = strdup(buffer); + shash(sh); + addlist(&r->ships, sh); + return sh; +} + +void +remove_ship(ship ** slist, ship * sh) +{ + region * r = sh->region; + unit * u = r->units; + + handle_event(sh->attribs, "destroy", sh); + while (u) { + if (u->ship == sh) { + leave_ship(u); + } + u = u->next; + } + sunhash(sh); + while (*slist && *slist!=sh) slist = &(*slist)->next; + assert(*slist); + *slist = sh->next; + sh->next = deleted_ships; + deleted_ships = sh; + sh->region = NULL; +} + +void +free_ship(ship * s) +{ + while (s->attribs) a_remove(&s->attribs, s->attribs); + free(s->name); + free(s->display); + free(s); +} + +void +free_ships(void) +{ + while (deleted_ships) { + ship * s = deleted_ships; + deleted_ships = s->next; + } +} + +const char * +write_shipname(const ship * sh, char * ibuf, size_t size) +{ + snprintf(ibuf, size, "%s (%s)", sh->name, itoa36(sh->no)); + ibuf[size-1] = 0; + return ibuf; +} + +const char * +shipname(const ship * sh) +{ + typedef char name[OBJECTIDSIZE + 1]; + static name idbuf[8]; + static int nextbuf = 0; + char *ibuf = idbuf[(++nextbuf) % 8]; + return write_shipname(sh, ibuf, sizeof(name)); +} + +int +shipcapacity (const ship * sh) +{ + int i = sh->type->cargo; + + /* sonst ist construction:: size nicht ship_type::maxsize */ + assert(!sh->type->construction || sh->type->construction->improvement==NULL); + + if (sh->type->construction && sh->size!=sh->type->construction->maxsize) + return 0; + +#ifdef SHIPDAMAGE + if (sh->damage) { + i = (int)ceil(i * (1.0 - sh->damage / sh->size / (double)DAMAGE_SCALE)); + } +#endif + return i; +} + +void +getshipweight(const ship * sh, int *sweight, int *scabins) +{ + unit * u; + + *sweight = 0; + *scabins = 0; + + for (u = sh->region->units; u; u = u->next) { + if (u->ship == sh) { + *sweight += weight(u); + if (sh->type->cabins) { + int pweight = u->number * u->race->weight; + /* weight goes into number of cabins, not cargo */ + *scabins += pweight; + *sweight -= pweight; + } + } + } +} + +unit * +shipowner(const ship * sh) +{ + unit *u; + unit *first = NULL; + + const region * r = sh->region; + + /* Prüfen ob Eigentümer am leben. */ + for (u = r->units; u; u = u->next) { + if (u->ship == sh) { + if (!first && u->number > 0) + first = u; + if (fval(u, UFL_OWNER) && u->number > 0) + return u; + if (u->number == 0) + freset(u, UFL_OWNER); + } + } + + /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit + * nehmen. */ + + if (first) + fset(first, UFL_OWNER); + return first; +} + +void +write_ship_reference(const struct ship * sh, struct storage * store) +{ + store->w_id(store, (sh && sh->region)?sh->no:0); +} + +void +ship_setname(ship * self, const char * name) +{ + free(self->name); + if (name) self->name = strdup(name); + else self->name = NULL; +} + +const char * +ship_getname(const ship * self) +{ + return self->name; +} diff --git a/src/kernel/ship.h b/src/kernel/ship.h index 0bc8ee9d4..c850b480e 100644 --- a/src/kernel/ship.h +++ b/src/kernel/ship.h @@ -1,127 +1,127 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_SHIP -#define H_KRNL_SHIP -#ifdef __cplusplus -extern "C" { -#endif - -#include "types.h" - -#define DAMAGE_SCALE 100 /* multiplier for sh->damage */ - -/* ship_type::flags */ -#define SFL_OPENSEA 0x01 -#define SFL_FLY 0x02 -#define SFL_NOCOAST 0x04 - -typedef struct ship_type { - const char * name[2]; - - int range; /* range in regions */ - int flags; /* flags */ - int combat; /* modifier for combat */ - - double storm; /* multiplier for chance to drift in storm */ - double damage; /* multiplier for damage taken by the ship */ - - int cabins; /* max. cabins (weight) */ - int cargo; /* max. cargo (weight) */ - - int cptskill; /* min. skill of captain */ - int minskill; /* min. skill to sail this (crew) */ - int sumskill; /* min. sum of crew+captain */ - - int fishing; /* weekly income from fishing */ - - int at_bonus; /* Verändert den Angriffsskill (default: 0)*/ - int df_bonus; /* Verändert den Verteidigungskill (default: 0)*/ - float tac_bonus; - - const struct terrain_type ** coasts; /* coast that this ship can land on */ - - struct construction * construction; /* how to build a ship */ -} ship_type; - -typedef struct ship_typelist { - struct ship_typelist * next; - const ship_type * type; -} ship_typelist; - -extern ship_typelist *shiptypes; - -/* Alte Schiffstypen: */ - -extern const ship_type * st_find(const char* name); -extern void st_register(const ship_type * type); - -#define NOSHIP NULL - -#define SF_DRIFTED 1<<0 -#define SF_MOVED 1<<1 -#define SF_DAMAGED 1<<2 /* for use in combat */ -#define SF_SELECT 1<<3 /* previously FL_DH */ -#define SF_FISHING 1<<4 /* was on an ocean, can fish */ -#define SF_FLYING 1<<5 /* the ship can fly */ - -#define SFL_SAVEMASK (SF_FLYING) -#define INCOME_FISHING 10 - -typedef struct ship { - struct ship *next; - struct ship *nexthash; - int no; - struct region *region; - char *name; - char *display; - struct attrib * attribs; - int size; - int damage; /* damage in 100th of a point of size */ - unsigned int flags; - const struct ship_type * type; - direction_t coast; -} ship; - -extern void damage_ship(ship *sh, double percent); -extern struct unit *captain(ship *sh); -extern struct unit *shipowner(const struct ship * sh); -extern const char * shipname(const struct ship * self); -extern int shipcapacity(const struct ship * sh); -extern void getshipweight(const struct ship * sh, int *weight, int *cabins); - -extern ship *new_ship(const struct ship_type * stype, const struct locale * lang, struct region * r); -extern const char *write_shipname(const struct ship * sh, char * buffer, size_t size); -extern struct ship *findship(int n); -extern struct ship *findshipr(const struct region *r, int n); - -extern const struct ship_type * findshiptype(const char *s, const struct locale * lang); - -extern void write_ship_reference(const struct ship * sh, struct storage * store); - -extern void remove_ship(struct ship ** slist, struct ship * s); -extern void free_ship(struct ship * s); -extern void free_ships(void); - -extern const char * ship_getname(const struct ship * self); -extern void ship_setname(struct ship * self, const char * name); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_SHIP +#define H_KRNL_SHIP +#ifdef __cplusplus +extern "C" { +#endif + +#include "types.h" + +#define DAMAGE_SCALE 100 /* multiplier for sh->damage */ + +/* ship_type::flags */ +#define SFL_OPENSEA 0x01 +#define SFL_FLY 0x02 +#define SFL_NOCOAST 0x04 + +typedef struct ship_type { + const char * name[2]; + + int range; /* range in regions */ + int flags; /* flags */ + int combat; /* modifier for combat */ + + double storm; /* multiplier for chance to drift in storm */ + double damage; /* multiplier for damage taken by the ship */ + + int cabins; /* max. cabins (weight) */ + int cargo; /* max. cargo (weight) */ + + int cptskill; /* min. skill of captain */ + int minskill; /* min. skill to sail this (crew) */ + int sumskill; /* min. sum of crew+captain */ + + int fishing; /* weekly income from fishing */ + + int at_bonus; /* Verändert den Angriffsskill (default: 0)*/ + int df_bonus; /* Verändert den Verteidigungskill (default: 0)*/ + float tac_bonus; + + const struct terrain_type ** coasts; /* coast that this ship can land on */ + + struct construction * construction; /* how to build a ship */ +} ship_type; + +typedef struct ship_typelist { + struct ship_typelist * next; + const ship_type * type; +} ship_typelist; + +extern ship_typelist *shiptypes; + +/* Alte Schiffstypen: */ + +extern const ship_type * st_find(const char* name); +extern void st_register(const ship_type * type); + +#define NOSHIP NULL + +#define SF_DRIFTED 1<<0 +#define SF_MOVED 1<<1 +#define SF_DAMAGED 1<<2 /* for use in combat */ +#define SF_SELECT 1<<3 /* previously FL_DH */ +#define SF_FISHING 1<<4 /* was on an ocean, can fish */ +#define SF_FLYING 1<<5 /* the ship can fly */ + +#define SFL_SAVEMASK (SF_FLYING) +#define INCOME_FISHING 10 + +typedef struct ship { + struct ship *next; + struct ship *nexthash; + int no; + struct region *region; + char *name; + char *display; + struct attrib * attribs; + int size; + int damage; /* damage in 100th of a point of size */ + unsigned int flags; + const struct ship_type * type; + direction_t coast; +} ship; + +extern void damage_ship(ship *sh, double percent); +extern struct unit *captain(ship *sh); +extern struct unit *shipowner(const struct ship * sh); +extern const char * shipname(const struct ship * self); +extern int shipcapacity(const struct ship * sh); +extern void getshipweight(const struct ship * sh, int *weight, int *cabins); + +extern ship *new_ship(const struct ship_type * stype, const struct locale * lang, struct region * r); +extern const char *write_shipname(const struct ship * sh, char * buffer, size_t size); +extern struct ship *findship(int n); +extern struct ship *findshipr(const struct region *r, int n); + +extern const struct ship_type * findshiptype(const char *s, const struct locale * lang); + +extern void write_ship_reference(const struct ship * sh, struct storage * store); + +extern void remove_ship(struct ship ** slist, struct ship * s); +extern void free_ship(struct ship * s); +extern void free_ships(void); + +extern const char * ship_getname(const struct ship * self); +extern void ship_setname(struct ship * self, const char * name); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/skill.c b/src/kernel/skill.c index 5f8d053d4..645b8cffa 100644 --- a/src/kernel/skill.c +++ b/src/kernel/skill.c @@ -1,315 +1,315 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "skill.h" - -#include "curse.h" -#include "item.h" -#include "magic.h" -#include "race.h" -#include "region.h" -#include "terrain.h" -#include "terrainid.h" -#include "unit.h" - -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -const char *skillnames[MAXSKILLS] = -{ - "alchemy", - "crossbow", - "mining", - "bow", - "building", - "trade", - "forestry", - "catapult", - "herbalism", - "magic", - "training", - "riding", - "armorer", - "shipcraft", - "melee", - "sailing", - "polearm", - "espionage", - "quarrying", - "roadwork", - "tactics", - "stealth", - "entertainment", - "weaponsmithing", - "cartmaking", - "perception", - "taxation", - "stamina", - "unarmed" -}; - -boolean skill_enabled[MAXSKILLS]; - -const char * -skillname(skill_t sk, const struct locale * lang) -{ - if (skill_enabled[sk]) { - return locale_string(lang, mkname("skill", skillnames[sk])); - } - return NULL; -} - -void -enable_skill(const char * skname, boolean value) -{ - skill_t sk; - for (sk=0;sk!=MAXSKILLS;++sk) { - if (strcmp(skillnames[sk], skname)==0) { - skill_enabled[sk] = value; - return; - } - } - log_error(("Trying to set unknown skill %s to %u", skname, value)); -} - -skill_t -sk_find(const char * name) -{ - skill_t i; - if (name==NULL) return NOSKILL; - if (strncmp(name, "sk_", 3)==0) name+=3; - for (i=0;i!=MAXSKILLS;++i) { - if (skill_enabled[i]) { - if (strcmp(name, skillnames[i])==0) return i; - } - } - return NOSKILL; -} - -/** skillmod attribut **/ -static void -init_skillmod(attrib * a) { - a->data.v = calloc(sizeof(skillmod_data), 1); -} - -static void -finalize_skillmod(attrib * a) -{ - free(a->data.v); -} - -/** temporary skill modification (NOT SAVED!). */ -attrib_type at_skillmod = { - "skillmod", - init_skillmod, - finalize_skillmod, - NULL, - NULL, /* can't write function pointers */ - NULL, /* can't read function pointers */ - ATF_PRESERVE -}; - -attrib * -make_skillmod(skill_t sk, unsigned int flags, skillmod_fun special, double multiplier, int bonus) -{ - attrib * a = a_new(&at_skillmod); - skillmod_data * smd = (skillmod_data*)a->data.v; - - smd->skill=sk; - smd->special=special; - smd->bonus=bonus; - smd->multiplier=multiplier; - smd->flags=flags; - - return a; -} - -int -skillmod(const attrib * a, const unit * u, const region * r, skill_t sk, int value, int flags) -{ - for (a = a_find((attrib*)a, &at_skillmod); a && a->type==&at_skillmod; a=a->next) { - skillmod_data * smd = (skillmod_data *)a->data.v; - if (smd->skill!=NOSKILL && smd->skill!=sk) continue; - if (flags!=SMF_ALWAYS && (smd->flags & flags) == 0) continue; - if (smd->special) { - value = smd->special(u, r, sk, value); - if (value<0) return value; /* pass errors back to caller */ - } - if (smd->multiplier) value = (int)(value*smd->multiplier); - value += smd->bonus; - } - return value; -} - -int -skill_mod(const race * rc, skill_t sk, const struct terrain_type * terrain) -{ - int result = 0; - - result = rc->bonus[sk]; - - if (rc == new_race[RC_DWARF]) { - if (sk==SK_TACTICS) { - if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION)) - ++result; - } - } - else if (rc == new_race[RC_INSECT]) { - if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION)) - --result; - else if (terrain == newterrain(T_DESERT) || terrain == newterrain(T_SWAMP)) - ++result; - } - - return result; -} - -#define RCMODMAXHASH 31 -#ifdef FASTER_SKILLMOD -static struct skillmods { - struct skillmods * next; - const struct race * race; - struct modifiers { - int value[MAXSKILLS]; - } mod[MAXTERRAINS]; -} * modhash[RCMODMAXHASH]; - -static struct skillmods * -init_skills(const race * rc) -{ - terrain_t t; - struct skillmods *mods = (struct skillmods*)calloc(1, sizeof(struct skillmods)); - mods->race = rc; - - for (t=0;t!=MAXTERRAINS;++t) { - skill_t sk; - for (sk=0;sk!=MAXSKILLS;++sk) { - mods->mod[t].value[sk] = skill_mod(rc, sk, newterrain(t)); - } - } - return mods; -} -#endif - -int -rc_skillmod(const struct race * rc, const region *r, skill_t sk) -{ - int mods; - - if (!skill_enabled[sk]) return 0; -#ifdef FASTER_SKILLMOD - unsigned int index = hashstring(rc->_name[0]) % RCMODMAXHASH; - struct skillmods **imods = &modhash[index]; - while (*imods && (*imods)->race!=rc) imods = &(*imods)->next; - if (*imods==NULL) { - *imods = init_skills(rc); - } - mods = (*imods)->mod[rterrain(r)].value[sk]; -#else - mods = skill_mod(rc, sk, r->terrain); -#endif - if (rc == new_race[RC_ELF] && r_isforest(r)) switch (sk) { - case SK_PERCEPTION: - ++mods; - break; - case SK_STEALTH: - if (r_isforest(r)) ++mods; - break; - case SK_TACTICS: - if (r_isforest(r)) mods += 2; - break; - } - - return mods; -} - -int -level_days(int level) -{ - return 30 * ((level+1) * level / 2); -} - -int -level(int days) -{ - int i; - static int ldays[64]; - static boolean init = false; - if (!init) { - init = true; - for (i=0;i!=64;++i) ldays[i] = level_days(i+1); - } - for (i=0;i!=64;++i) if (ldays[i]>days) return i; - return i; -} - -void -sk_set(skill * sv, int level) -{ - assert(level!=0); - sv->weeks = (unsigned char)skill_weeks(level); - sv->level = (unsigned char)level; -} - -int -skill_weeks(int level) -/* how many weeks must i study to get from level to level+1 */ -{ - int coins = 2*level; - int heads = 1; - while (coins--) { - heads += rng_int() % 2; - } - return heads; -} - -void -reduce_skill(unit * u, skill * sv, unsigned int weeks) -{ - sv->weeks+=weeks; - while (sv->level>0 && sv->level*2+1weeks) { - sv->weeks -= sv->level; - --sv->level; - } - if (sv->level==0) { - /* reroll */ - sv->weeks = (unsigned char)skill_weeks(sv->level); - } -} - - -int -skill_compare(const skill * sk, const skill * sc) -{ - if (sk->level > sc->level) return 1; - if (sk->level < sc->level) return -1; - if (sk->weeks < sc->weeks) return 1; - if (sk->weeks > sc->weeks) return -1; - return 0; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "skill.h" + +#include "curse.h" +#include "item.h" +#include "magic.h" +#include "race.h" +#include "region.h" +#include "terrain.h" +#include "terrainid.h" +#include "unit.h" + +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +const char *skillnames[MAXSKILLS] = +{ + "alchemy", + "crossbow", + "mining", + "bow", + "building", + "trade", + "forestry", + "catapult", + "herbalism", + "magic", + "training", + "riding", + "armorer", + "shipcraft", + "melee", + "sailing", + "polearm", + "espionage", + "quarrying", + "roadwork", + "tactics", + "stealth", + "entertainment", + "weaponsmithing", + "cartmaking", + "perception", + "taxation", + "stamina", + "unarmed" +}; + +boolean skill_enabled[MAXSKILLS]; + +const char * +skillname(skill_t sk, const struct locale * lang) +{ + if (skill_enabled[sk]) { + return locale_string(lang, mkname("skill", skillnames[sk])); + } + return NULL; +} + +void +enable_skill(const char * skname, boolean value) +{ + skill_t sk; + for (sk=0;sk!=MAXSKILLS;++sk) { + if (strcmp(skillnames[sk], skname)==0) { + skill_enabled[sk] = value; + return; + } + } + log_error(("Trying to set unknown skill %s to %u", skname, value)); +} + +skill_t +sk_find(const char * name) +{ + skill_t i; + if (name==NULL) return NOSKILL; + if (strncmp(name, "sk_", 3)==0) name+=3; + for (i=0;i!=MAXSKILLS;++i) { + if (skill_enabled[i]) { + if (strcmp(name, skillnames[i])==0) return i; + } + } + return NOSKILL; +} + +/** skillmod attribut **/ +static void +init_skillmod(attrib * a) { + a->data.v = calloc(sizeof(skillmod_data), 1); +} + +static void +finalize_skillmod(attrib * a) +{ + free(a->data.v); +} + +/** temporary skill modification (NOT SAVED!). */ +attrib_type at_skillmod = { + "skillmod", + init_skillmod, + finalize_skillmod, + NULL, + NULL, /* can't write function pointers */ + NULL, /* can't read function pointers */ + ATF_PRESERVE +}; + +attrib * +make_skillmod(skill_t sk, unsigned int flags, skillmod_fun special, double multiplier, int bonus) +{ + attrib * a = a_new(&at_skillmod); + skillmod_data * smd = (skillmod_data*)a->data.v; + + smd->skill=sk; + smd->special=special; + smd->bonus=bonus; + smd->multiplier=multiplier; + smd->flags=flags; + + return a; +} + +int +skillmod(const attrib * a, const unit * u, const region * r, skill_t sk, int value, int flags) +{ + for (a = a_find((attrib*)a, &at_skillmod); a && a->type==&at_skillmod; a=a->next) { + skillmod_data * smd = (skillmod_data *)a->data.v; + if (smd->skill!=NOSKILL && smd->skill!=sk) continue; + if (flags!=SMF_ALWAYS && (smd->flags & flags) == 0) continue; + if (smd->special) { + value = smd->special(u, r, sk, value); + if (value<0) return value; /* pass errors back to caller */ + } + if (smd->multiplier) value = (int)(value*smd->multiplier); + value += smd->bonus; + } + return value; +} + +int +skill_mod(const race * rc, skill_t sk, const struct terrain_type * terrain) +{ + int result = 0; + + result = rc->bonus[sk]; + + if (rc == new_race[RC_DWARF]) { + if (sk==SK_TACTICS) { + if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION)) + ++result; + } + } + else if (rc == new_race[RC_INSECT]) { + if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION)) + --result; + else if (terrain == newterrain(T_DESERT) || terrain == newterrain(T_SWAMP)) + ++result; + } + + return result; +} + +#define RCMODMAXHASH 31 +#ifdef FASTER_SKILLMOD +static struct skillmods { + struct skillmods * next; + const struct race * race; + struct modifiers { + int value[MAXSKILLS]; + } mod[MAXTERRAINS]; +} * modhash[RCMODMAXHASH]; + +static struct skillmods * +init_skills(const race * rc) +{ + terrain_t t; + struct skillmods *mods = (struct skillmods*)calloc(1, sizeof(struct skillmods)); + mods->race = rc; + + for (t=0;t!=MAXTERRAINS;++t) { + skill_t sk; + for (sk=0;sk!=MAXSKILLS;++sk) { + mods->mod[t].value[sk] = skill_mod(rc, sk, newterrain(t)); + } + } + return mods; +} +#endif + +int +rc_skillmod(const struct race * rc, const region *r, skill_t sk) +{ + int mods; + + if (!skill_enabled[sk]) return 0; +#ifdef FASTER_SKILLMOD + unsigned int index = hashstring(rc->_name[0]) % RCMODMAXHASH; + struct skillmods **imods = &modhash[index]; + while (*imods && (*imods)->race!=rc) imods = &(*imods)->next; + if (*imods==NULL) { + *imods = init_skills(rc); + } + mods = (*imods)->mod[rterrain(r)].value[sk]; +#else + mods = skill_mod(rc, sk, r->terrain); +#endif + if (rc == new_race[RC_ELF] && r_isforest(r)) switch (sk) { + case SK_PERCEPTION: + ++mods; + break; + case SK_STEALTH: + if (r_isforest(r)) ++mods; + break; + case SK_TACTICS: + if (r_isforest(r)) mods += 2; + break; + } + + return mods; +} + +int +level_days(int level) +{ + return 30 * ((level+1) * level / 2); +} + +int +level(int days) +{ + int i; + static int ldays[64]; + static boolean init = false; + if (!init) { + init = true; + for (i=0;i!=64;++i) ldays[i] = level_days(i+1); + } + for (i=0;i!=64;++i) if (ldays[i]>days) return i; + return i; +} + +void +sk_set(skill * sv, int level) +{ + assert(level!=0); + sv->weeks = (unsigned char)skill_weeks(level); + sv->level = (unsigned char)level; +} + +int +skill_weeks(int level) +/* how many weeks must i study to get from level to level+1 */ +{ + int coins = 2*level; + int heads = 1; + while (coins--) { + heads += rng_int() % 2; + } + return heads; +} + +void +reduce_skill(unit * u, skill * sv, unsigned int weeks) +{ + sv->weeks+=weeks; + while (sv->level>0 && sv->level*2+1weeks) { + sv->weeks -= sv->level; + --sv->level; + } + if (sv->level==0) { + /* reroll */ + sv->weeks = (unsigned char)skill_weeks(sv->level); + } +} + + +int +skill_compare(const skill * sk, const skill * sc) +{ + if (sk->level > sc->level) return 1; + if (sk->level < sc->level) return -1; + if (sk->weeks < sc->weeks) return 1; + if (sk->weeks > sc->weeks) return -1; + return 0; +} diff --git a/src/kernel/skill.h b/src/kernel/skill.h index 1ed5c6ad6..6e7173eca 100644 --- a/src/kernel/skill.h +++ b/src/kernel/skill.h @@ -1,66 +1,66 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - */ - -#ifndef H_KRNL_SKILL -#define H_KRNL_SKILL -#ifdef __cplusplus -extern "C" { -#endif - -extern signed char skill_bonus(struct unit * u, struct region * r); - -/* skillmod_data::flags -- wann gilt der modifier? */ -#define SMF_ALWAYS (1<<0) /* immer */ -#define SMF_PRODUCTION (1<<1) /* für Produktion - am gebäude, an der einheit */ -#define SMF_RIDING (1<<2) /* Bonus für berittene - an der rasse*/ - -typedef struct skill { - unsigned char id; - unsigned int level : 8; - unsigned int weeks : 8; - unsigned int old : 8; -} skill; - -typedef int (*skillmod_fun)(const struct unit*, const struct region*, skill_t, int); -typedef struct skillmod_data { - skill_t skill; - skillmod_fun special; - double multiplier; - int number; - int bonus; - int flags; -} skillmod_data; -extern struct attrib_type at_skillmod; -extern int rc_skillmod(const struct race * rc, const struct region *r, skill_t sk); -extern int skillmod(const struct attrib * a, const struct unit * u, const struct region * r, skill_t sk, int value, int flags); -extern struct attrib * make_skillmod(skill_t sk, unsigned int flags, skillmod_fun special, double multiplier, int bonus); - -extern const char * skillname(skill_t, const struct locale *); -extern skill_t sk_find(const char * name); -extern void enable_skill(const char * name, boolean value); -extern int level_days(int level); -extern int level(int days); - -#define skill_level(level) (level) -extern void reduce_skill(struct unit *u, skill * sv, unsigned int change); -extern int skill_weeks(int level); -extern int skill_compare(const skill * sk, const skill * sc); - -extern void sk_set(skill * sv, int level); - -extern const char *skillnames[]; -extern boolean skill_enabled[]; - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + */ + +#ifndef H_KRNL_SKILL +#define H_KRNL_SKILL +#ifdef __cplusplus +extern "C" { +#endif + +extern signed char skill_bonus(struct unit * u, struct region * r); + +/* skillmod_data::flags -- wann gilt der modifier? */ +#define SMF_ALWAYS (1<<0) /* immer */ +#define SMF_PRODUCTION (1<<1) /* für Produktion - am gebäude, an der einheit */ +#define SMF_RIDING (1<<2) /* Bonus für berittene - an der rasse*/ + +typedef struct skill { + unsigned char id; + unsigned int level : 8; + unsigned int weeks : 8; + unsigned int old : 8; +} skill; + +typedef int (*skillmod_fun)(const struct unit*, const struct region*, skill_t, int); +typedef struct skillmod_data { + skill_t skill; + skillmod_fun special; + double multiplier; + int number; + int bonus; + int flags; +} skillmod_data; +extern struct attrib_type at_skillmod; +extern int rc_skillmod(const struct race * rc, const struct region *r, skill_t sk); +extern int skillmod(const struct attrib * a, const struct unit * u, const struct region * r, skill_t sk, int value, int flags); +extern struct attrib * make_skillmod(skill_t sk, unsigned int flags, skillmod_fun special, double multiplier, int bonus); + +extern const char * skillname(skill_t, const struct locale *); +extern skill_t sk_find(const char * name); +extern void enable_skill(const char * name, boolean value); +extern int level_days(int level); +extern int level(int days); + +#define skill_level(level) (level) +extern void reduce_skill(struct unit *u, skill * sv, unsigned int change); +extern int skill_weeks(int level); +extern int skill_compare(const skill * sk, const skill * sc); + +extern void sk_set(skill * sv, int level); + +extern const char *skillnames[]; +extern boolean skill_enabled[]; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/spell.c b/src/kernel/spell.c index 7bd05cf15..c9c8edfc9 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -1,184 +1,184 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "spell.h" - -/* kernel includes */ -#include "magic.h" -#include "unit.h" - -/* libc includes */ -#include -#include - -/* util includes */ -#include -#include -#include -#include - - /* Bitte die Sprüche nach Gebieten und Stufe ordnen, denn in derselben - * Reihenfolge wie in Spelldaten tauchen sie auch im Report auf - */ - -spell_list * spells = NULL; - -void -register_spell(spell * sp) -{ - if (sp->id==0) { - sp->id = hashstring(sp->sname); - } - spelllist_add(&spells, sp); -} - -/** versucht einen Spruch über gebiet + name zu identifizieren. - * gibt ansonsten NULL zurück */ -spell * -find_spell(magic_t mtype, const char * name) -{ - spell_list * slist = spells; - spell * spx = NULL; - while (slist) { - spell * sp = slist->data; - if (strcmp(name, sp->sname)==0) { - if (mtype==M_NONE || sp->magietyp==mtype) return sp; - spx = sp; - } - slist = slist->next; - } - if (spx==NULL) { - log_error(("cannot find spell by name: %s\n", name)); - } - return spx; -} - - -/* ------------------------------------------------------------- */ -/* Spruch identifizieren */ - -typedef struct spell_names { - struct spell_names * next; - const struct locale * lang; - magic_t mtype; - struct tnode names; -} spell_names; - -static spell_names * spellnames; - -static spell_names * -init_spellnames(const struct locale * lang, magic_t mtype) -{ - spell_list * slist; - spell_names * sn = calloc(sizeof(spell_names), 1); - sn->next = spellnames; - sn->lang = lang; - sn->mtype = mtype; - for (slist=spells;slist!=NULL;slist=slist->next) { - spell * sp = slist->data; - if (sp->magietyp==mtype) { - const char * n = spell_name(sp, lang); - variant token; - token.v = sp; - addtoken(&sn->names, n, token); - } - } - return spellnames = sn; -} - -static spell_names * -get_spellnames(const struct locale * lang, magic_t mtype) -{ - spell_names * sn = spellnames; - while (sn) { - if (sn->mtype==mtype && sn->lang==lang) break; - sn=sn->next; - } - if (!sn) return init_spellnames(lang, mtype); - return sn; -} - -static spell * -get_spellfromtoken_i(const char *name, const struct locale * lang, magic_t mtype) -{ - variant token = { 0 }; - spell_names * sn; - - sn = get_spellnames(lang, mtype); - if (findtoken(&sn->names, name, &token)==E_TOK_NOMATCH) { - magic_t mt; - /* if we could not find it in the main magic type, we look through all the others */ - for (mt=0;mt!=MAXMAGIETYP;++mt) { - if (mt!=mtype) { - sn = get_spellnames(lang, mt); - if (findtoken(&sn->names, name, &token)!=E_TOK_NOMATCH) break; - } - } - } - - if (token.v!=NULL) return (spell*)token.v; - if (lang==default_locale) return NULL; - return get_spellfromtoken_i(name, default_locale, mtype); -} - -spell * -get_spellfromtoken(unit *u, const char *name, const struct locale * lang) -{ - sc_mage * m = get_mage(u); - spell * sp; - - if (m==NULL) return NULL; - sp = get_spellfromtoken_i(name, lang, m->magietyp); - if (sp!=NULL) { - spell_list * slist = m->spells; - - while (slist && slist->data->id<=sp->id) { - if (sp==slist->data) return sp; - slist = slist->next; - } - } - return NULL; -} - -spell * -find_spellbyid(magic_t mtype, spellid_t id) -{ - spell_list * slist; - - assert(id>=0); - if (id==0) return NULL; - for (slist=spells;slist!=NULL;slist=slist->next) { - spell* sp = slist->data; - if (sp->id == id) return sp; - } - for (slist=spells;slist!=NULL;slist=slist->next) { - spell* sp = slist->data; - unsigned int hashid = hashstring(sp->sname); - if (hashid==id) { - if (sp->magietyp==mtype || mtype==M_NONE) { - return sp; - } - } - } - - log_warning(("cannot find spell by id: %u\n", id)); - return NULL; -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "spell.h" + +/* kernel includes */ +#include "magic.h" +#include "unit.h" + +/* libc includes */ +#include +#include + +/* util includes */ +#include +#include +#include +#include + + /* Bitte die Sprüche nach Gebieten und Stufe ordnen, denn in derselben + * Reihenfolge wie in Spelldaten tauchen sie auch im Report auf + */ + +spell_list * spells = NULL; + +void +register_spell(spell * sp) +{ + if (sp->id==0) { + sp->id = hashstring(sp->sname); + } + spelllist_add(&spells, sp); +} + +/** versucht einen Spruch über gebiet + name zu identifizieren. + * gibt ansonsten NULL zurück */ +spell * +find_spell(magic_t mtype, const char * name) +{ + spell_list * slist = spells; + spell * spx = NULL; + while (slist) { + spell * sp = slist->data; + if (strcmp(name, sp->sname)==0) { + if (mtype==M_NONE || sp->magietyp==mtype) return sp; + spx = sp; + } + slist = slist->next; + } + if (spx==NULL) { + log_error(("cannot find spell by name: %s\n", name)); + } + return spx; +} + + +/* ------------------------------------------------------------- */ +/* Spruch identifizieren */ + +typedef struct spell_names { + struct spell_names * next; + const struct locale * lang; + magic_t mtype; + struct tnode names; +} spell_names; + +static spell_names * spellnames; + +static spell_names * +init_spellnames(const struct locale * lang, magic_t mtype) +{ + spell_list * slist; + spell_names * sn = calloc(sizeof(spell_names), 1); + sn->next = spellnames; + sn->lang = lang; + sn->mtype = mtype; + for (slist=spells;slist!=NULL;slist=slist->next) { + spell * sp = slist->data; + if (sp->magietyp==mtype) { + const char * n = spell_name(sp, lang); + variant token; + token.v = sp; + addtoken(&sn->names, n, token); + } + } + return spellnames = sn; +} + +static spell_names * +get_spellnames(const struct locale * lang, magic_t mtype) +{ + spell_names * sn = spellnames; + while (sn) { + if (sn->mtype==mtype && sn->lang==lang) break; + sn=sn->next; + } + if (!sn) return init_spellnames(lang, mtype); + return sn; +} + +static spell * +get_spellfromtoken_i(const char *name, const struct locale * lang, magic_t mtype) +{ + variant token = { 0 }; + spell_names * sn; + + sn = get_spellnames(lang, mtype); + if (findtoken(&sn->names, name, &token)==E_TOK_NOMATCH) { + magic_t mt; + /* if we could not find it in the main magic type, we look through all the others */ + for (mt=0;mt!=MAXMAGIETYP;++mt) { + if (mt!=mtype) { + sn = get_spellnames(lang, mt); + if (findtoken(&sn->names, name, &token)!=E_TOK_NOMATCH) break; + } + } + } + + if (token.v!=NULL) return (spell*)token.v; + if (lang==default_locale) return NULL; + return get_spellfromtoken_i(name, default_locale, mtype); +} + +spell * +get_spellfromtoken(unit *u, const char *name, const struct locale * lang) +{ + sc_mage * m = get_mage(u); + spell * sp; + + if (m==NULL) return NULL; + sp = get_spellfromtoken_i(name, lang, m->magietyp); + if (sp!=NULL) { + spell_list * slist = m->spells; + + while (slist && slist->data->id<=sp->id) { + if (sp==slist->data) return sp; + slist = slist->next; + } + } + return NULL; +} + +spell * +find_spellbyid(magic_t mtype, spellid_t id) +{ + spell_list * slist; + + assert(id>=0); + if (id==0) return NULL; + for (slist=spells;slist!=NULL;slist=slist->next) { + spell* sp = slist->data; + if (sp->id == id) return sp; + } + for (slist=spells;slist!=NULL;slist=slist->next) { + spell* sp = slist->data; + unsigned int hashid = hashstring(sp->sname); + if (hashid==id) { + if (sp->magietyp==mtype || mtype==M_NONE) { + return sp; + } + } + } + + log_warning(("cannot find spell by id: %u\n", id)); + return NULL; +} + diff --git a/src/kernel/spell.h b/src/kernel/spell.h index 9a250deb0..ddf903c24 100644 --- a/src/kernel/spell.h +++ b/src/kernel/spell.h @@ -1,159 +1,159 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_SPELL -#define H_KRNL_SPELL -#ifdef __cplusplus -extern "C" { -#endif - - struct fighter; - struct spell; - struct border_type; - struct attrib_type; - struct curse_type; - struct castorder; - struct curse; - - /* Prototypen */ - - int use_item_power(struct region * r, struct unit * u); - int use_item_regeneration(struct region * r, struct unit * u); - void showspells(struct region *r, struct unit *u); - int sp_antimagiczone(struct castorder *co); - - /* ------------------------------------------------------------- */ - - extern struct attrib_type at_unitdissolve; - extern struct attrib_type at_wdwpyramid; - - extern struct spell_list * spells; - extern void register_spell(struct spell * sp); - extern struct spell * find_spell(magic_t mtype, const char * name); - extern struct spell * find_spellbyid(magic_t mtype, spellid_t i); - extern struct spell *get_spellfromtoken(struct unit *u, const char *s, const struct locale * lang); - -#ifdef __cplusplus -} -#endif -#endif - -/* ------------------------------------------------------------- */ -/* Erläuterungen zu den Spruchdefinitionen - * - * Spruchstukturdefinition: - * spell{ - * id, name, - * beschreibung, - * syntax, - * parameter, - * magietyp, - * sptyp, - * rank,level, - * costtyp, aura, - * komponenten[5][2][faktorart], - * &funktion, patzer} - * - * id: - * SPL_NOSPELL muss der letzte Spruch in der Liste spelldaten sein, - * denn nicht auf die Reihenfolge in der Liste sondern auf die id wird - * geprüft - * - * sptyp: - * besondere Spruchtypen und Flags - * (Regionszauber, Kampfzauber, Farcastbar, Stufe variable, ..) - * - * rank: - * gibt die Priorität und damit die Reihenfolge an, in der der Spruch - * gezaubert wird. - * 1: Aura übertragen - * 2: Antimagie - * 3: Magierverändernde Sprüche (Magic Boost, ..) - * 4: Monster erschaffen - * 5: Standartlevel - * 7: Teleport - * - * Komponenten[Anzahl mögl. Items][Art:Anzahl:Kostentyp] - * - * R_AURA: - * Grundkosten für einen Zauber. Soviel Mp müssen mindestens investiert - * werden, um den Spruch zu wirken. Zusätzliche Mp können unterschiedliche - * Auswirkungen haben, die in der Spruchfunktionsroutine definiert werden. - * - * R_PERMAURA: - * Kosten an permantenter Aura - * - * Komponenten Kostentyp: - * SPC_LEVEL == Spruch mit Levelabhängigen Magiekosten. Die angegeben - * Kosten müssen für Stufe 1 berechnet sein. - * SPC_FIX == Feste Kosten - * - * Wenn keine spezielle Syntax angegeben ist, wird die - * Syntaxbeschreibung aus sptyp generiert: - * FARCASTING: ZAUBER [REGION x y] - * SPELLLEVEL: ZAUBER [STUFE n] - * UNITSPELL : ZAUBER [ ..] - * SHIPSPELL : ZAUBER [ ..] - * BUILDINGSPELL: ZAUBER [ ..] - * PRECOMBATSPELL : KAMPFZAUBER [STUFE n] - * COMBATSPELL : KAMPFZAUBER [STUFE n] - * POSTCOMBATSPELL: KAMPFZAUBER [STUFE n] - * - * Das Parsing - * - * Der String spell->parameter gibt die Syntax an, nach der die - * Parameter des Spruches in add_spellparameter() geparst werden sollen. - * - * u : eine Einheitennummer - * r : hier kommen zwei Regionskoordinaten x y - * b : Gebäude- oder Burgnummer - * s : Schiffsnummer - * c : String, wird ohne Weiterverarbeitung übergeben - * i : Zahl (int), wird ohne Weiterverarbeitung übergeben - * k : Keywort - dieser String gibt den Paramter an, der folgt. Der - * Parameter wird mit findparam() identifiziert. - * k muss immer von einem c als Platzhalter für das Objekt gefolgt - * werden. - * Ein gutes Beispiel sind hierfür die Sprüche zur Magieanalyse. - * + : gibt an, das der vorherige Parameter mehrfach vorkommen kann. Da - * ein Ende nicht definiert werden kann, muss dies immer am Schluss - * kommen. - * - * Flags für das Parsing: - * TESTRESISTANCE : alle Zielobjekte, also alle Parameter vom Typ Unit, - * Burg, Schiff oder Region, werden auf ihre - * Magieresistenz überprüft - * TESTCANSEE : jedes Objekt vom Typ Einheit wird auf seine - * Sichtbarkeit überprüft - * SEARCHLOCAL : die Zielobjekte werden nur regional gesucht - * REGIONSPELL : Ziel ist die Region, auch wenn kein Zielobjekt - * angegeben wird. Ist TESTRESISTANCE gesetzt, so wird - * die Magieresistenz der Region überprüft - * - * Bei fehlendem Ziel oder wenn dieses dem Zauber widersteht, wird die - * Spruchfunktion nicht aufgerufen. - * Sind zu wenig Parameter vorhanden, wird der Zauber ebenfalls nicht - * ausgeführt. - * Ist eins von mehreren Zielobjekten resistent, so wird das Flag - * pa->param[n]->flag == TARGET_RESISTS - * Ist eins von mehreren Zielobjekten nicht gefunden worden, so ist - * pa->param[n]->flag == TARGET_NOTFOUND - * - */ -/* ------------------------------------------------------------- */ - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_SPELL +#define H_KRNL_SPELL +#ifdef __cplusplus +extern "C" { +#endif + + struct fighter; + struct spell; + struct border_type; + struct attrib_type; + struct curse_type; + struct castorder; + struct curse; + + /* Prototypen */ + + int use_item_power(struct region * r, struct unit * u); + int use_item_regeneration(struct region * r, struct unit * u); + void showspells(struct region *r, struct unit *u); + int sp_antimagiczone(struct castorder *co); + + /* ------------------------------------------------------------- */ + + extern struct attrib_type at_unitdissolve; + extern struct attrib_type at_wdwpyramid; + + extern struct spell_list * spells; + extern void register_spell(struct spell * sp); + extern struct spell * find_spell(magic_t mtype, const char * name); + extern struct spell * find_spellbyid(magic_t mtype, spellid_t i); + extern struct spell *get_spellfromtoken(struct unit *u, const char *s, const struct locale * lang); + +#ifdef __cplusplus +} +#endif +#endif + +/* ------------------------------------------------------------- */ +/* Erläuterungen zu den Spruchdefinitionen + * + * Spruchstukturdefinition: + * spell{ + * id, name, + * beschreibung, + * syntax, + * parameter, + * magietyp, + * sptyp, + * rank,level, + * costtyp, aura, + * komponenten[5][2][faktorart], + * &funktion, patzer} + * + * id: + * SPL_NOSPELL muss der letzte Spruch in der Liste spelldaten sein, + * denn nicht auf die Reihenfolge in der Liste sondern auf die id wird + * geprüft + * + * sptyp: + * besondere Spruchtypen und Flags + * (Regionszauber, Kampfzauber, Farcastbar, Stufe variable, ..) + * + * rank: + * gibt die Priorität und damit die Reihenfolge an, in der der Spruch + * gezaubert wird. + * 1: Aura übertragen + * 2: Antimagie + * 3: Magierverändernde Sprüche (Magic Boost, ..) + * 4: Monster erschaffen + * 5: Standartlevel + * 7: Teleport + * + * Komponenten[Anzahl mögl. Items][Art:Anzahl:Kostentyp] + * + * R_AURA: + * Grundkosten für einen Zauber. Soviel Mp müssen mindestens investiert + * werden, um den Spruch zu wirken. Zusätzliche Mp können unterschiedliche + * Auswirkungen haben, die in der Spruchfunktionsroutine definiert werden. + * + * R_PERMAURA: + * Kosten an permantenter Aura + * + * Komponenten Kostentyp: + * SPC_LEVEL == Spruch mit Levelabhängigen Magiekosten. Die angegeben + * Kosten müssen für Stufe 1 berechnet sein. + * SPC_FIX == Feste Kosten + * + * Wenn keine spezielle Syntax angegeben ist, wird die + * Syntaxbeschreibung aus sptyp generiert: + * FARCASTING: ZAUBER [REGION x y] + * SPELLLEVEL: ZAUBER [STUFE n] + * UNITSPELL : ZAUBER [ ..] + * SHIPSPELL : ZAUBER [ ..] + * BUILDINGSPELL: ZAUBER [ ..] + * PRECOMBATSPELL : KAMPFZAUBER [STUFE n] + * COMBATSPELL : KAMPFZAUBER [STUFE n] + * POSTCOMBATSPELL: KAMPFZAUBER [STUFE n] + * + * Das Parsing + * + * Der String spell->parameter gibt die Syntax an, nach der die + * Parameter des Spruches in add_spellparameter() geparst werden sollen. + * + * u : eine Einheitennummer + * r : hier kommen zwei Regionskoordinaten x y + * b : Gebäude- oder Burgnummer + * s : Schiffsnummer + * c : String, wird ohne Weiterverarbeitung übergeben + * i : Zahl (int), wird ohne Weiterverarbeitung übergeben + * k : Keywort - dieser String gibt den Paramter an, der folgt. Der + * Parameter wird mit findparam() identifiziert. + * k muss immer von einem c als Platzhalter für das Objekt gefolgt + * werden. + * Ein gutes Beispiel sind hierfür die Sprüche zur Magieanalyse. + * + : gibt an, das der vorherige Parameter mehrfach vorkommen kann. Da + * ein Ende nicht definiert werden kann, muss dies immer am Schluss + * kommen. + * + * Flags für das Parsing: + * TESTRESISTANCE : alle Zielobjekte, also alle Parameter vom Typ Unit, + * Burg, Schiff oder Region, werden auf ihre + * Magieresistenz überprüft + * TESTCANSEE : jedes Objekt vom Typ Einheit wird auf seine + * Sichtbarkeit überprüft + * SEARCHLOCAL : die Zielobjekte werden nur regional gesucht + * REGIONSPELL : Ziel ist die Region, auch wenn kein Zielobjekt + * angegeben wird. Ist TESTRESISTANCE gesetzt, so wird + * die Magieresistenz der Region überprüft + * + * Bei fehlendem Ziel oder wenn dieses dem Zauber widersteht, wird die + * Spruchfunktion nicht aufgerufen. + * Sind zu wenig Parameter vorhanden, wird der Zauber ebenfalls nicht + * ausgeführt. + * Ist eins von mehreren Zielobjekten resistent, so wird das Flag + * pa->param[n]->flag == TARGET_RESISTS + * Ist eins von mehreren Zielobjekten nicht gefunden worden, so ist + * pa->param[n]->flag == TARGET_NOTFOUND + * + */ +/* ------------------------------------------------------------- */ + diff --git a/src/kernel/spellid.h b/src/kernel/spellid.h index ffdc411f0..351e0b24a 100644 --- a/src/kernel/spellid.h +++ b/src/kernel/spellid.h @@ -1,176 +1,176 @@ -/* vi: set ts=2: -* +-------------------+ Christian Schlittchen -* | | Enno Rehling -* | Eressea PBEM host | Katja Zedel -* | (c) 1998 - 2005 | -* | | This program may not be used, modified or distributed -* +-------------------+ without prior permission by the authors of Eressea. -* -*/ - -#ifndef H_KRNL_SPELLID -#define H_KRNL_SPELLID - -/* Sprüche. Neue NUR hinten anfügen, oder das Datenfile geht kaputt */ -enum { - SPL_NOSPELL = 0, - SPL_FIREBALL = 4, - SPL_HAGEL, - SPL_RUSTWEAPON, - SPL_COMBATRUST, - SPL_TREEGROW, - SPL_HEALING, - SPL_HEALINGSONG, - SPL_BADDREAMS, - SPL_GOODDREAMS, - SPL_DREAMREADING, - SPL_SWEETDREAMS, - SPL_TIREDSOLDIERS, - SPL_PLAGUE, - SPL_MAGICBOOST, - SPL_CHAOSROW, - SPL_SONG_OF_CONFUSION, - SPL_FLEE, - SPL_SONG_OF_FEAR, - SPL_BERSERK, - SPL_BLOODTHIRST, - SPL_MAELSTROM, - SPL_TRANSFERAURA_DRUIDE = 27, - SPL_TRANSFERAURA_BARDE, - SPL_TRANSFERAURA_CHAOS, - SPL_TRANSFERAURA_TRAUM, - SPL_TRANSFERAURA_ASTRAL, - SPL_STONEGOLEM, - SPL_IRONGOLEM, - SPL_SUMMONSHADOW, - SPL_SUMMONSHADOWLORDS, - SPL_REELING_ARROWS, - SPL_ANTIMAGICZONE = 37, - SPL_KAELTESCHUTZ = 39, - SPL_STEALAURA, - SPL_SUMMONUNDEAD, - SPL_AURALEAK, - SPL_GREAT_DROUGHT, - SPL_STRONG_WALL, - SPL_HOMESTONE, - SPL_DROUGHT, - SPL_FOREST_FIRE = 47, - SPL_SUMMONENT = 49, - SPL_DISTURBINGDREAMS, - SPL_DENYATTACK, - SPL_SLEEP, - SPL_EARTHQUAKE, - SPL_IRONKEEPER, - SPL_STORMWINDS, - SPL_GOODWINDS, - SPL_FLYING_SHIP, - SPL_SUMMON_ALP, - SPL_WINDSHIELD, - SPL_RAISEPEASANTS, - SPL_DEPRESSION, - SPL_HEADACHE = 62, - SPL_ENTERASTRAL = 64, - SPL_LEAVEASTRAL, - SPL_SHOWASTRAL, - SPL_VERSTEINERN, - SPL_TREEWALKENTER, - SPL_TREEWALKEXIT, - SPL_CHAOSSUCTION, - SPL_VIEWREALITY, - SPL_DISRUPTASTRAL, - SPL_SEDUCE, - SPL_PUMP, - SPL_CALM_MONSTER, - SPL_HERO, - SPL_FRIGHTEN, - SPL_MINDBLAST, - SPL_SPEED, - SPL_SPEED2, - SPL_FIREDRAGONODEM, - SPL_DRAGONODEM, - SPL_WYRMODEM, /* 83 */ - SPL_MAGICSTREET, - SPL_REANIMATE, - SPL_RECRUIT, - SPL_GENEROUS, - SPL_PERMTRANSFER, - SPL_SONG_OF_PEACE, - SPL_MIGRANT, - SPL_RALLYPEASANTMOB, - SPL_RAISEPEASANTMOB, - SPL_ILL_SHAPESHIFT, - SPL_WOLFHOWL, - SPL_FOG_OF_CONFUSION, - SPL_DREAM_OF_CONFUSION, - SPL_RESISTMAGICBONUS, - SPL_KEEPLOOT, - SPL_SCHILDRUNEN, - SPL_SONG_RESISTMAGIC, - SPL_SONG_SUSCEPTMAGIC, - SPL_ANALYSEMAGIC, - SPL_ANALYSEDREAM, - SPL_UNIT_ANALYSESONG, - SPL_OBJ_ANALYSESONG, - SPL_TYBIED_DESTROY_MAGIC, - SPL_DESTROY_MAGIC, - SPL_METEORRAIN, - SPL_REDUCESHIELD, - SPL_ARMORSHIELD, - SPL_DEATHCLOUD, - SPL_ORKDREAM, - SPL_SUMMONDRAGON = 113, - SPL_MOVECASTLE = 116, - SPL_BLESSSTONECIRCLE, - SPL_ILLAUN_FAMILIAR, - SPL_GWYRRD_FAMILIAR, - SPL_DRAIG_FAMILIAR, - SPL_CERDDOR_FAMILIAR, - SPL_TYBIED_FAMILIAR, - SPL_SONG_OF_ENSLAVE = 123, - SPL_FUMBLECURSE = 136, - SPL_ICASTLE, - SPL_GWYRRD_DESTROY_MAGIC, - SPL_DRAIG_DESTROY_MAGIC, - SPL_ILLAUN_DESTROY_MAGIC, - SPL_CERDDOR_DESTROY_MAGIC, - SPL_GWYRRD_ARMORSHIELD, - SPL_DRAIG_FUMBLESHIELD, - SPL_GWYRRD_FUMBLESHIELD, - SPL_CERRDOR_FUMBLESHIELD, - SPL_TYBIED_FUMBLESHIELD, - SPL_SHADOWKNIGHTS = 147, - SPL_ITEMCLOAK = 150, - SPL_FIREWALL, - SPL_WISPS, - SPL_SPARKLE_CHAOS, - SPL_SPARKLE_DREAM = 154, - SPL_PULLASTRAL = 156, - SPL_FETCHASTRAL = 157, - SPL_SHOCKWAVE = 163, - SPL_UNDEADHERO = 164, - SPL_BECOMEWYRM = 166, - SPL_ETERNIZEWALL, - SPL_PUTTOREST, - SPL_UNHOLYPOWER, - SPL_HOLYGROUND, - SPL_BLOODSACRIFICE, - SPL_MALLORN, - SPL_CLONECOPY, - SPL_DRAINODEM, - SPL_AURA_OF_FEAR, - SPL_SHADOWCALL, - SPL_MALLORNTREEGROW = 177, - SPL_BIGRECRUIT = 179, - SPL_IMMOLATION, - SPL_FIREODEM, /* 181 */ - SPL_ICEODEM, - SPL_ACIDODEM, - /* no longer used, but kept for reference: */ - XMLSPL_WDWPYRAMID_TRAUM = 184, - XMLSPL_WDWPYRAMID_ASTRAL = 185, - XMLSPL_WDWPYRAMID_DRUIDE = 186, - XMLSPL_WDWPYRAMID_BARDE = 187, - XMLSPL_WDWPYRAMID_CHAOS = 188, -}; - -#endif +/* vi: set ts=2: +* +-------------------+ Christian Schlittchen +* | | Enno Rehling +* | Eressea PBEM host | Katja Zedel +* | (c) 1998 - 2005 | +* | | This program may not be used, modified or distributed +* +-------------------+ without prior permission by the authors of Eressea. +* +*/ + +#ifndef H_KRNL_SPELLID +#define H_KRNL_SPELLID + +/* Sprüche. Neue NUR hinten anfügen, oder das Datenfile geht kaputt */ +enum { + SPL_NOSPELL = 0, + SPL_FIREBALL = 4, + SPL_HAGEL, + SPL_RUSTWEAPON, + SPL_COMBATRUST, + SPL_TREEGROW, + SPL_HEALING, + SPL_HEALINGSONG, + SPL_BADDREAMS, + SPL_GOODDREAMS, + SPL_DREAMREADING, + SPL_SWEETDREAMS, + SPL_TIREDSOLDIERS, + SPL_PLAGUE, + SPL_MAGICBOOST, + SPL_CHAOSROW, + SPL_SONG_OF_CONFUSION, + SPL_FLEE, + SPL_SONG_OF_FEAR, + SPL_BERSERK, + SPL_BLOODTHIRST, + SPL_MAELSTROM, + SPL_TRANSFERAURA_DRUIDE = 27, + SPL_TRANSFERAURA_BARDE, + SPL_TRANSFERAURA_CHAOS, + SPL_TRANSFERAURA_TRAUM, + SPL_TRANSFERAURA_ASTRAL, + SPL_STONEGOLEM, + SPL_IRONGOLEM, + SPL_SUMMONSHADOW, + SPL_SUMMONSHADOWLORDS, + SPL_REELING_ARROWS, + SPL_ANTIMAGICZONE = 37, + SPL_KAELTESCHUTZ = 39, + SPL_STEALAURA, + SPL_SUMMONUNDEAD, + SPL_AURALEAK, + SPL_GREAT_DROUGHT, + SPL_STRONG_WALL, + SPL_HOMESTONE, + SPL_DROUGHT, + SPL_FOREST_FIRE = 47, + SPL_SUMMONENT = 49, + SPL_DISTURBINGDREAMS, + SPL_DENYATTACK, + SPL_SLEEP, + SPL_EARTHQUAKE, + SPL_IRONKEEPER, + SPL_STORMWINDS, + SPL_GOODWINDS, + SPL_FLYING_SHIP, + SPL_SUMMON_ALP, + SPL_WINDSHIELD, + SPL_RAISEPEASANTS, + SPL_DEPRESSION, + SPL_HEADACHE = 62, + SPL_ENTERASTRAL = 64, + SPL_LEAVEASTRAL, + SPL_SHOWASTRAL, + SPL_VERSTEINERN, + SPL_TREEWALKENTER, + SPL_TREEWALKEXIT, + SPL_CHAOSSUCTION, + SPL_VIEWREALITY, + SPL_DISRUPTASTRAL, + SPL_SEDUCE, + SPL_PUMP, + SPL_CALM_MONSTER, + SPL_HERO, + SPL_FRIGHTEN, + SPL_MINDBLAST, + SPL_SPEED, + SPL_SPEED2, + SPL_FIREDRAGONODEM, + SPL_DRAGONODEM, + SPL_WYRMODEM, /* 83 */ + SPL_MAGICSTREET, + SPL_REANIMATE, + SPL_RECRUIT, + SPL_GENEROUS, + SPL_PERMTRANSFER, + SPL_SONG_OF_PEACE, + SPL_MIGRANT, + SPL_RALLYPEASANTMOB, + SPL_RAISEPEASANTMOB, + SPL_ILL_SHAPESHIFT, + SPL_WOLFHOWL, + SPL_FOG_OF_CONFUSION, + SPL_DREAM_OF_CONFUSION, + SPL_RESISTMAGICBONUS, + SPL_KEEPLOOT, + SPL_SCHILDRUNEN, + SPL_SONG_RESISTMAGIC, + SPL_SONG_SUSCEPTMAGIC, + SPL_ANALYSEMAGIC, + SPL_ANALYSEDREAM, + SPL_UNIT_ANALYSESONG, + SPL_OBJ_ANALYSESONG, + SPL_TYBIED_DESTROY_MAGIC, + SPL_DESTROY_MAGIC, + SPL_METEORRAIN, + SPL_REDUCESHIELD, + SPL_ARMORSHIELD, + SPL_DEATHCLOUD, + SPL_ORKDREAM, + SPL_SUMMONDRAGON = 113, + SPL_MOVECASTLE = 116, + SPL_BLESSSTONECIRCLE, + SPL_ILLAUN_FAMILIAR, + SPL_GWYRRD_FAMILIAR, + SPL_DRAIG_FAMILIAR, + SPL_CERDDOR_FAMILIAR, + SPL_TYBIED_FAMILIAR, + SPL_SONG_OF_ENSLAVE = 123, + SPL_FUMBLECURSE = 136, + SPL_ICASTLE, + SPL_GWYRRD_DESTROY_MAGIC, + SPL_DRAIG_DESTROY_MAGIC, + SPL_ILLAUN_DESTROY_MAGIC, + SPL_CERDDOR_DESTROY_MAGIC, + SPL_GWYRRD_ARMORSHIELD, + SPL_DRAIG_FUMBLESHIELD, + SPL_GWYRRD_FUMBLESHIELD, + SPL_CERRDOR_FUMBLESHIELD, + SPL_TYBIED_FUMBLESHIELD, + SPL_SHADOWKNIGHTS = 147, + SPL_ITEMCLOAK = 150, + SPL_FIREWALL, + SPL_WISPS, + SPL_SPARKLE_CHAOS, + SPL_SPARKLE_DREAM = 154, + SPL_PULLASTRAL = 156, + SPL_FETCHASTRAL = 157, + SPL_SHOCKWAVE = 163, + SPL_UNDEADHERO = 164, + SPL_BECOMEWYRM = 166, + SPL_ETERNIZEWALL, + SPL_PUTTOREST, + SPL_UNHOLYPOWER, + SPL_HOLYGROUND, + SPL_BLOODSACRIFICE, + SPL_MALLORN, + SPL_CLONECOPY, + SPL_DRAINODEM, + SPL_AURA_OF_FEAR, + SPL_SHADOWCALL, + SPL_MALLORNTREEGROW = 177, + SPL_BIGRECRUIT = 179, + SPL_IMMOLATION, + SPL_FIREODEM, /* 181 */ + SPL_ICEODEM, + SPL_ACIDODEM, + /* no longer used, but kept for reference: */ + XMLSPL_WDWPYRAMID_TRAUM = 184, + XMLSPL_WDWPYRAMID_ASTRAL = 185, + XMLSPL_WDWPYRAMID_DRUIDE = 186, + XMLSPL_WDWPYRAMID_BARDE = 187, + XMLSPL_WDWPYRAMID_CHAOS = 188, +}; + +#endif diff --git a/src/kernel/sqlite.c b/src/kernel/sqlite.c index eba6f3b3e..2a428a614 100644 --- a/src/kernel/sqlite.c +++ b/src/kernel/sqlite.c @@ -1,257 +1,257 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -faction * get_faction_by_id(int uid) -{ - faction * f; - for (f=factions;f;f=f->next) { - if (f->subscription==uid) { - return f; - } - } - return NULL; -} - -#define SQL_EXPECT(res, val) if (res!=val) { return val; } -#define MAX_EMAIL_LENGTH 64 -#define MD5_LENGTH 32 -#define MD5_LENGTH_0 (MD5_LENGTH+1) /* MD5 + zero-terminator */ -#define MAX_FACTION_NAME 64 -#define MAX_FACTION_NAME_0 (MAX_FACTION_NAME+1) -typedef struct stmt_cache { - sqlite3 * db; - sqlite3_stmt * stmt; - const char * sql; - int inuse; -} stmt_cache; - -#define MAX_STMT_CACHE 64 -static stmt_cache cache[MAX_STMT_CACHE]; -static int cache_insert; - -static sqlite3_stmt * -stmt_cache_get(sqlite3 * db, const char * sql) -{ - int i, res; - - for (i=0;i!=MAX_STMT_CACHE && cache[i].db;++i) { - if (cache[i].sql==sql && cache[i].db==db) { - cache[i].inuse = 1; - res = sqlite3_reset(cache[i].stmt); - return cache[i].stmt; - } - } - if (i==MAX_STMT_CACHE) { - while (cache[cache_insert].inuse) { - cache[cache_insert].inuse = 0; - cache_insert = (cache_insert+1)&(MAX_STMT_CACHE-1); - } - i = cache_insert; - res = sqlite3_finalize(cache[i].stmt); - } - cache[i].inuse = 1; - cache[i].db = db; - cache[i].sql = sql; - res = sqlite3_prepare_v2(db, sql, -1, &cache[i].stmt, NULL); - return cache[i].stmt; -} - - -typedef struct db_faction { - sqlite3_uint64 id_faction; - sqlite3_uint64 id_email; - int no; - const char * email; - const char * passwd_md5; - const char * name; -} db_faction; - -static int -db_update_email(sqlite3 * db, const faction * f, const db_faction * dbstate, boolean force, /* [OUT] */ sqlite3_uint64 * id_email) -{ - boolean update = force; - int res = SQLITE_OK; - char email_lc[MAX_EMAIL_LENGTH]; - - if (update) { - unicode_utf8_tolower(email_lc, sizeof(email_lc), f->email); - } else { - if (strcmp(dbstate->email, f->email)!=0) { - unicode_utf8_tolower(email_lc, sizeof(email_lc), f->email); - if (strcmp(dbstate->email, email_lc)!=0) { - update = true; - } - } - } - - if (update) { - char email_md5[MD5_LENGTH_0]; - int i; - md5_state_t ms; - md5_byte_t digest[16]; - const char sql_insert_email[] = - "INSERT OR FAIL INTO email (email,md5) VALUES (?,?)"; - const char sql_select_email[] = - "SELECT id FROM email WHERE md5=?"; - sqlite3_stmt *stmt_insert_email = stmt_cache_get(db, sql_insert_email); - sqlite3_stmt *stmt_select_email = stmt_cache_get(db, sql_select_email); - - md5_init(&ms); - md5_append(&ms, (md5_byte_t*)email_lc, (int)strlen(email_lc)); - md5_finish(&ms, digest); - for (i=0;i!=16;++i) sprintf(email_md5+2*i, "%.02x", digest[i]); - - res = sqlite3_bind_text(stmt_insert_email, 1, email_lc, -1, SQLITE_TRANSIENT); - res = sqlite3_bind_text(stmt_insert_email, 2, email_md5, MD5_LENGTH, SQLITE_TRANSIENT); - res = sqlite3_step(stmt_insert_email); - - if (res==SQLITE_DONE) { - *id_email = sqlite3_last_insert_rowid(db); - } else { - res = sqlite3_bind_text(stmt_select_email, 1, email_md5, MD5_LENGTH, SQLITE_TRANSIENT); - res = sqlite3_step(stmt_select_email); - SQL_EXPECT(res, SQLITE_ROW); - *id_email = sqlite3_column_int64(stmt_select_email, 0); - } - } - - return SQLITE_OK; -} - -int -db_update_factions(sqlite3 * db, boolean force) -{ - int game_id = 6; - const char sql_select[] = - "SELECT faction.id, faction.email_id, faction.code, email.email, faction.password_md5, faction.name, faction.lastturn FROM email, faction" - " WHERE email.id=faction.email_id AND faction.game_id=? AND (lastturn IS NULL OR lastturn>?)"; - sqlite3_stmt *stmt_select = stmt_cache_get(db, sql_select); - faction * f; - int res; - - res = sqlite3_bind_int(stmt_select, 1, game_id); - SQL_EXPECT(res, SQLITE_OK); - res = sqlite3_bind_int(stmt_select, 2, turn-2); - SQL_EXPECT(res, SQLITE_OK); - for (;;) { - sqlite3_uint64 id_faction; - int lastturn; - - res = sqlite3_step(stmt_select); - if (res!=SQLITE_ROW) break; - - id_faction = sqlite3_column_int64(stmt_select, 0); - lastturn = sqlite3_column_int(stmt_select, 6); - f = get_faction_by_id((int)id_faction); - - if (f==NULL || !f->alive) { - if (lastturn==0) { - const char sql_update[] = "UPDATE faction SET lastturn=? WHERE id=?"; - sqlite3_stmt *stmt = stmt_cache_get(db, sql_update); - - lastturn = f?f->lastorders:turn-1; - sqlite3_bind_int(stmt, 1, lastturn); - sqlite3_bind_int64(stmt, 2, id_faction); - res = sqlite3_step(stmt); - SQL_EXPECT(res, SQLITE_DONE); - } - } else { - md5_state_t ms; - md5_byte_t digest[16]; - int i; - char passwd_md5[MD5_LENGTH_0]; - sqlite3_uint64 id_email; - boolean update = force; - db_faction dbstate; - const char * no_b36; - - fset(f, FFL_MARK); - dbstate.id_faction = id_faction; - dbstate.id_email = sqlite3_column_int64(stmt_select, 1); - no_b36 = (const char *)sqlite3_column_text(stmt_select, 2); - dbstate.no = no_b36?atoi36(no_b36):-1; - dbstate.email = (const char *)sqlite3_column_text(stmt_select, 3); - dbstate.passwd_md5 = (const char *)sqlite3_column_text(stmt_select, 4); - dbstate.name = (const char *)sqlite3_column_text(stmt_select, 5); - - id_email = dbstate.id_email; - res = db_update_email(db, f, &dbstate, force, &id_email); - SQL_EXPECT(res, SQLITE_OK); - - md5_init(&ms); - md5_append(&ms, (md5_byte_t*)f->passw, (int)strlen(f->passw)); - md5_finish(&ms, digest); - for (i=0;i!=16;++i) sprintf(passwd_md5+2*i, "%.02x", digest[i]); - - if (!update) { - update = ((id_email!=0 && dbstate.id_email!=id_email) || dbstate.no!=f->no - || dbstate.passwd_md5==NULL || strcmp(passwd_md5, dbstate.passwd_md5)!=0 - || dbstate.name==NULL || strncmp(f->name, dbstate.name, MAX_FACTION_NAME)!=0); - } - if (update) { - const char sql_update_faction[] = - "UPDATE faction SET email_id=?, password_md5=?, code=?, name=?, firstturn=? WHERE id=?"; - sqlite3_stmt *stmt_update_faction = stmt_cache_get(db, sql_update_faction); - - res = sqlite3_bind_int64(stmt_update_faction, 1, id_email); - SQL_EXPECT(res, SQLITE_OK); - res = sqlite3_bind_text(stmt_update_faction, 2, passwd_md5, MD5_LENGTH, SQLITE_TRANSIENT); - SQL_EXPECT(res, SQLITE_OK); - res = sqlite3_bind_text(stmt_update_faction, 3, no_b36, -1, SQLITE_TRANSIENT); - SQL_EXPECT(res, SQLITE_OK); - res = sqlite3_bind_text(stmt_update_faction, 4, f->name, -1, SQLITE_TRANSIENT); - SQL_EXPECT(res, SQLITE_OK); - res = sqlite3_bind_int(stmt_update_faction, 5, turn-f->age); - SQL_EXPECT(res, SQLITE_OK); - res = sqlite3_bind_int64(stmt_update_faction, 6, f->subscription); - SQL_EXPECT(res, SQLITE_OK); - res = sqlite3_step(stmt_update_faction); - SQL_EXPECT(res, SQLITE_DONE); - } - } - } - - for (f=factions;f;f=f->next) { - if (!fval(f, FFL_MARK)) { - log_error(("%s (sub=%d, email=%s) has no entry in the database\n", factionname(f), f->subscription, f->email)); - } else { - freset(f, FFL_MARK); - } - } - return SQLITE_OK; -} - -int -db_update_scores(sqlite3 * db, boolean force) -{ - const char * sql_ins = "INSERT OR FAIL INTO score (value,faction_id,turn) VALUES (?,?,?)"; - sqlite3_stmt * stmt_ins = stmt_cache_get(db, sql_ins); - const char * sql_upd = "UPDATE score set value=? WHERE faction_id=? AND turn=?"; - sqlite3_stmt * stmt_upd = stmt_cache_get(db, sql_upd); - faction * f; - sqlite3_exec(db, "BEGIN", 0, 0, 0); - for (f=factions;f;f=f->next) { - int res; - sqlite3_bind_int(stmt_ins, 1, f->score); - sqlite3_bind_int64(stmt_ins, 2, f->subscription); - sqlite3_bind_int(stmt_ins, 3, turn); - res = sqlite3_step(stmt_ins); - if (res==SQLITE_CONSTRAINT) { - sqlite3_bind_int(stmt_upd, 1, f->score); - sqlite3_bind_int64(stmt_upd, 2, f->subscription); - sqlite3_bind_int(stmt_upd, 3, turn); - res = sqlite3_step(stmt_upd); - sqlite3_reset(stmt_upd); - } - sqlite3_reset(stmt_ins); - } - sqlite3_exec(db, "COMMIT", 0, 0, 0); - return SQLITE_OK; -} +#include +#include +#include +#include +#include +#include +#include +#include +#include + +faction * get_faction_by_id(int uid) +{ + faction * f; + for (f=factions;f;f=f->next) { + if (f->subscription==uid) { + return f; + } + } + return NULL; +} + +#define SQL_EXPECT(res, val) if (res!=val) { return val; } +#define MAX_EMAIL_LENGTH 64 +#define MD5_LENGTH 32 +#define MD5_LENGTH_0 (MD5_LENGTH+1) /* MD5 + zero-terminator */ +#define MAX_FACTION_NAME 64 +#define MAX_FACTION_NAME_0 (MAX_FACTION_NAME+1) +typedef struct stmt_cache { + sqlite3 * db; + sqlite3_stmt * stmt; + const char * sql; + int inuse; +} stmt_cache; + +#define MAX_STMT_CACHE 64 +static stmt_cache cache[MAX_STMT_CACHE]; +static int cache_insert; + +static sqlite3_stmt * +stmt_cache_get(sqlite3 * db, const char * sql) +{ + int i, res; + + for (i=0;i!=MAX_STMT_CACHE && cache[i].db;++i) { + if (cache[i].sql==sql && cache[i].db==db) { + cache[i].inuse = 1; + res = sqlite3_reset(cache[i].stmt); + return cache[i].stmt; + } + } + if (i==MAX_STMT_CACHE) { + while (cache[cache_insert].inuse) { + cache[cache_insert].inuse = 0; + cache_insert = (cache_insert+1)&(MAX_STMT_CACHE-1); + } + i = cache_insert; + res = sqlite3_finalize(cache[i].stmt); + } + cache[i].inuse = 1; + cache[i].db = db; + cache[i].sql = sql; + res = sqlite3_prepare_v2(db, sql, -1, &cache[i].stmt, NULL); + return cache[i].stmt; +} + + +typedef struct db_faction { + sqlite3_uint64 id_faction; + sqlite3_uint64 id_email; + int no; + const char * email; + const char * passwd_md5; + const char * name; +} db_faction; + +static int +db_update_email(sqlite3 * db, const faction * f, const db_faction * dbstate, boolean force, /* [OUT] */ sqlite3_uint64 * id_email) +{ + boolean update = force; + int res = SQLITE_OK; + char email_lc[MAX_EMAIL_LENGTH]; + + if (update) { + unicode_utf8_tolower(email_lc, sizeof(email_lc), f->email); + } else { + if (strcmp(dbstate->email, f->email)!=0) { + unicode_utf8_tolower(email_lc, sizeof(email_lc), f->email); + if (strcmp(dbstate->email, email_lc)!=0) { + update = true; + } + } + } + + if (update) { + char email_md5[MD5_LENGTH_0]; + int i; + md5_state_t ms; + md5_byte_t digest[16]; + const char sql_insert_email[] = + "INSERT OR FAIL INTO email (email,md5) VALUES (?,?)"; + const char sql_select_email[] = + "SELECT id FROM email WHERE md5=?"; + sqlite3_stmt *stmt_insert_email = stmt_cache_get(db, sql_insert_email); + sqlite3_stmt *stmt_select_email = stmt_cache_get(db, sql_select_email); + + md5_init(&ms); + md5_append(&ms, (md5_byte_t*)email_lc, (int)strlen(email_lc)); + md5_finish(&ms, digest); + for (i=0;i!=16;++i) sprintf(email_md5+2*i, "%.02x", digest[i]); + + res = sqlite3_bind_text(stmt_insert_email, 1, email_lc, -1, SQLITE_TRANSIENT); + res = sqlite3_bind_text(stmt_insert_email, 2, email_md5, MD5_LENGTH, SQLITE_TRANSIENT); + res = sqlite3_step(stmt_insert_email); + + if (res==SQLITE_DONE) { + *id_email = sqlite3_last_insert_rowid(db); + } else { + res = sqlite3_bind_text(stmt_select_email, 1, email_md5, MD5_LENGTH, SQLITE_TRANSIENT); + res = sqlite3_step(stmt_select_email); + SQL_EXPECT(res, SQLITE_ROW); + *id_email = sqlite3_column_int64(stmt_select_email, 0); + } + } + + return SQLITE_OK; +} + +int +db_update_factions(sqlite3 * db, boolean force) +{ + int game_id = 6; + const char sql_select[] = + "SELECT faction.id, faction.email_id, faction.code, email.email, faction.password_md5, faction.name, faction.lastturn FROM email, faction" + " WHERE email.id=faction.email_id AND faction.game_id=? AND (lastturn IS NULL OR lastturn>?)"; + sqlite3_stmt *stmt_select = stmt_cache_get(db, sql_select); + faction * f; + int res; + + res = sqlite3_bind_int(stmt_select, 1, game_id); + SQL_EXPECT(res, SQLITE_OK); + res = sqlite3_bind_int(stmt_select, 2, turn-2); + SQL_EXPECT(res, SQLITE_OK); + for (;;) { + sqlite3_uint64 id_faction; + int lastturn; + + res = sqlite3_step(stmt_select); + if (res!=SQLITE_ROW) break; + + id_faction = sqlite3_column_int64(stmt_select, 0); + lastturn = sqlite3_column_int(stmt_select, 6); + f = get_faction_by_id((int)id_faction); + + if (f==NULL || !f->alive) { + if (lastturn==0) { + const char sql_update[] = "UPDATE faction SET lastturn=? WHERE id=?"; + sqlite3_stmt *stmt = stmt_cache_get(db, sql_update); + + lastturn = f?f->lastorders:turn-1; + sqlite3_bind_int(stmt, 1, lastturn); + sqlite3_bind_int64(stmt, 2, id_faction); + res = sqlite3_step(stmt); + SQL_EXPECT(res, SQLITE_DONE); + } + } else { + md5_state_t ms; + md5_byte_t digest[16]; + int i; + char passwd_md5[MD5_LENGTH_0]; + sqlite3_uint64 id_email; + boolean update = force; + db_faction dbstate; + const char * no_b36; + + fset(f, FFL_MARK); + dbstate.id_faction = id_faction; + dbstate.id_email = sqlite3_column_int64(stmt_select, 1); + no_b36 = (const char *)sqlite3_column_text(stmt_select, 2); + dbstate.no = no_b36?atoi36(no_b36):-1; + dbstate.email = (const char *)sqlite3_column_text(stmt_select, 3); + dbstate.passwd_md5 = (const char *)sqlite3_column_text(stmt_select, 4); + dbstate.name = (const char *)sqlite3_column_text(stmt_select, 5); + + id_email = dbstate.id_email; + res = db_update_email(db, f, &dbstate, force, &id_email); + SQL_EXPECT(res, SQLITE_OK); + + md5_init(&ms); + md5_append(&ms, (md5_byte_t*)f->passw, (int)strlen(f->passw)); + md5_finish(&ms, digest); + for (i=0;i!=16;++i) sprintf(passwd_md5+2*i, "%.02x", digest[i]); + + if (!update) { + update = ((id_email!=0 && dbstate.id_email!=id_email) || dbstate.no!=f->no + || dbstate.passwd_md5==NULL || strcmp(passwd_md5, dbstate.passwd_md5)!=0 + || dbstate.name==NULL || strncmp(f->name, dbstate.name, MAX_FACTION_NAME)!=0); + } + if (update) { + const char sql_update_faction[] = + "UPDATE faction SET email_id=?, password_md5=?, code=?, name=?, firstturn=? WHERE id=?"; + sqlite3_stmt *stmt_update_faction = stmt_cache_get(db, sql_update_faction); + + res = sqlite3_bind_int64(stmt_update_faction, 1, id_email); + SQL_EXPECT(res, SQLITE_OK); + res = sqlite3_bind_text(stmt_update_faction, 2, passwd_md5, MD5_LENGTH, SQLITE_TRANSIENT); + SQL_EXPECT(res, SQLITE_OK); + res = sqlite3_bind_text(stmt_update_faction, 3, no_b36, -1, SQLITE_TRANSIENT); + SQL_EXPECT(res, SQLITE_OK); + res = sqlite3_bind_text(stmt_update_faction, 4, f->name, -1, SQLITE_TRANSIENT); + SQL_EXPECT(res, SQLITE_OK); + res = sqlite3_bind_int(stmt_update_faction, 5, turn-f->age); + SQL_EXPECT(res, SQLITE_OK); + res = sqlite3_bind_int64(stmt_update_faction, 6, f->subscription); + SQL_EXPECT(res, SQLITE_OK); + res = sqlite3_step(stmt_update_faction); + SQL_EXPECT(res, SQLITE_DONE); + } + } + } + + for (f=factions;f;f=f->next) { + if (!fval(f, FFL_MARK)) { + log_error(("%s (sub=%d, email=%s) has no entry in the database\n", factionname(f), f->subscription, f->email)); + } else { + freset(f, FFL_MARK); + } + } + return SQLITE_OK; +} + +int +db_update_scores(sqlite3 * db, boolean force) +{ + const char * sql_ins = "INSERT OR FAIL INTO score (value,faction_id,turn) VALUES (?,?,?)"; + sqlite3_stmt * stmt_ins = stmt_cache_get(db, sql_ins); + const char * sql_upd = "UPDATE score set value=? WHERE faction_id=? AND turn=?"; + sqlite3_stmt * stmt_upd = stmt_cache_get(db, sql_upd); + faction * f; + sqlite3_exec(db, "BEGIN", 0, 0, 0); + for (f=factions;f;f=f->next) { + int res; + sqlite3_bind_int(stmt_ins, 1, f->score); + sqlite3_bind_int64(stmt_ins, 2, f->subscription); + sqlite3_bind_int(stmt_ins, 3, turn); + res = sqlite3_step(stmt_ins); + if (res==SQLITE_CONSTRAINT) { + sqlite3_bind_int(stmt_upd, 1, f->score); + sqlite3_bind_int64(stmt_upd, 2, f->subscription); + sqlite3_bind_int(stmt_upd, 3, turn); + res = sqlite3_step(stmt_upd); + sqlite3_reset(stmt_upd); + } + sqlite3_reset(stmt_ins); + } + sqlite3_exec(db, "COMMIT", 0, 0, 0); + return SQLITE_OK; +} diff --git a/src/kernel/teleport.c b/src/kernel/teleport.c index 40fc7b8ae..7098f9353 100644 --- a/src/kernel/teleport.c +++ b/src/kernel/teleport.c @@ -1,228 +1,228 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "teleport.h" - -/* kernel includes */ -#include "equipment.h" -#include "unit.h" -#include "region.h" -#include "race.h" -#include "skill.h" -#include "terrain.h" -#include "faction.h" -#include "plane.h" - -/* util includes */ -#include -#include - -/* libc includes */ -#include - -#define TE_CENTER_X 1000 -#define TE_CENTER_Y 1000 -#define TP_RADIUS 2 -#define TP_DISTANCE 4 - -static int -real2tp(int rk) { - /* in C: - * -4 / 5 = 0; - * +4 / 5 = 0; - * !!!!!!!!!!; - */ - return (rk + (TP_DISTANCE*5000)) / TP_DISTANCE - 5000; -} - -static region * -tpregion(const region *r) { - region * rt = findregion(TE_CENTER_X+real2tp(r->x), TE_CENTER_Y+real2tp(r->y)); - if (!is_astral(rt)) return NULL; - return rt; -} - -region_list * -astralregions(const region * r, boolean (*valid)(const region *)) -{ - region_list * rlist = NULL; - int x, y; - - assert(is_astral(r)); - if (!is_astral(r)) { - log_error(("astralregions was called with a non-astral region.\n")); - return NULL; - } - r = r_astral_to_standard(r); - if (r==NULL) return NULL; - - for (x=-TP_RADIUS;x<=+TP_RADIUS;++x) { - for (y=-TP_RADIUS;y<=+TP_RADIUS;++y) { - region * rn; - int dist = koor_distance(0, 0, x, y); - int nx = r->x+x, ny = r->y+y; - - if (dist > TP_RADIUS) continue; - pnormalize(&nx, &ny, rplane(r)); - rn = findregion(nx, ny); - if (rn!=NULL && (valid==NULL || valid(rn))) add_regionlist(&rlist, rn); - } - } - return rlist; -} - -region * -r_standard_to_astral(const region *r) -{ - if (rplane(r) != get_normalplane()) return NULL; - return tpregion(r); -} - -region * -r_astral_to_standard(const region *r) -{ - int x, y; - region *r2; - - assert(is_astral(r)); - x = (r->x-TE_CENTER_X)*TP_DISTANCE; - y = (r->y-TE_CENTER_Y)*TP_DISTANCE; - pnormalize(&x, &y, get_normalplane()); - r2 = findregion(x, y); - if (r2==NULL || rplane(r2)!=get_normalplane()) return NULL; - - return r2; -} - -region_list * -all_in_range(const region *r, int n, boolean (*valid)(const region *)) -{ - int x, y; - region_list *rlist = NULL; - plane * pl = rplane(r); - - if (r == NULL) return NULL; - - for (x = r->x-n; x <= r->x+n; x++) { - for (y = r->y-n; y <= r->y+n; y++) { - if (koor_distance(r->x, r->y, x, y) <= n) { - region * r2; - int nx = x, ny = y; - pnormalize(&nx, &ny, pl); - r2 = findregion(nx, ny); - if (r2!=NULL && (valid==NULL || valid(r2))) add_regionlist(&rlist, r2); - } - } - } - - return rlist; -} - -void -spawn_braineaters(float chance) -{ - region *r; - faction *f0 = get_monsters(); - int next = rng_int() % (int)(chance*100); - - if (f0==NULL) return; - - for (r = regions; r; r = r->next) { - if (!is_astral(r) || fval(r->terrain, FORBIDDEN_REGION)) continue; - - /* Neues Monster ? */ - if (next-- == 0) { - unit *u = createunit(r, f0, 1+rng_int()%10+rng_int()%10, new_race[RC_HIRNTOETER]); - equip_unit(u, get_equipment("monster_braineater")); - - next = rng_int() % (int)(chance*100); - } - } -} - -plane * -get_normalplane(void) -{ - return NULL; -} - -boolean -is_astral(const region * r) -{ - plane * pl = get_astralplane(); - return (pl && rplane(r) == pl); -} - -plane * -get_astralplane(void) -{ - static plane * astralspace; - static int rule_astralplane = -1; - static int gamecookie = -1; - if (rule_astralplane<0) { - rule_astralplane = get_param_int(global.parameters, "modules.astralspace", 1); - } - if (!rule_astralplane) { - return NULL; - } - if (gamecookie!=global.cookie) { - astralspace = getplanebyname("Astralraum"); - gamecookie = global.cookie; - } - - if (astralspace==NULL) { - astralspace = create_new_plane(1, "Astralraum", - TE_CENTER_X-500, TE_CENTER_X+500, - TE_CENTER_Y-500, TE_CENTER_Y+500, 0); - } - return astralspace; -} - -void -create_teleport_plane(void) -{ - region *r; - plane * hplane = get_homeplane(); - plane * aplane = get_astralplane(); - - const terrain_type * fog = get_terrain("fog"); - - for (r=regions;r;r=r->next) { - plane * pl = rplane(r); - if (pl == hplane) { - region *ra = tpregion(r); - - if (ra==NULL) { - int x = TE_CENTER_X+real2tp(r->x); - int y = TE_CENTER_Y+real2tp(r->y); - pnormalize(&x, &y, aplane); - - ra = new_region(x, y, aplane, 0); - terraform_region(ra, fog); - } - } - } -} - -boolean -inhabitable(const region * r) -{ - return fval(r->terrain, LAND_REGION); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "teleport.h" + +/* kernel includes */ +#include "equipment.h" +#include "unit.h" +#include "region.h" +#include "race.h" +#include "skill.h" +#include "terrain.h" +#include "faction.h" +#include "plane.h" + +/* util includes */ +#include +#include + +/* libc includes */ +#include + +#define TE_CENTER_X 1000 +#define TE_CENTER_Y 1000 +#define TP_RADIUS 2 +#define TP_DISTANCE 4 + +static int +real2tp(int rk) { + /* in C: + * -4 / 5 = 0; + * +4 / 5 = 0; + * !!!!!!!!!!; + */ + return (rk + (TP_DISTANCE*5000)) / TP_DISTANCE - 5000; +} + +static region * +tpregion(const region *r) { + region * rt = findregion(TE_CENTER_X+real2tp(r->x), TE_CENTER_Y+real2tp(r->y)); + if (!is_astral(rt)) return NULL; + return rt; +} + +region_list * +astralregions(const region * r, boolean (*valid)(const region *)) +{ + region_list * rlist = NULL; + int x, y; + + assert(is_astral(r)); + if (!is_astral(r)) { + log_error(("astralregions was called with a non-astral region.\n")); + return NULL; + } + r = r_astral_to_standard(r); + if (r==NULL) return NULL; + + for (x=-TP_RADIUS;x<=+TP_RADIUS;++x) { + for (y=-TP_RADIUS;y<=+TP_RADIUS;++y) { + region * rn; + int dist = koor_distance(0, 0, x, y); + int nx = r->x+x, ny = r->y+y; + + if (dist > TP_RADIUS) continue; + pnormalize(&nx, &ny, rplane(r)); + rn = findregion(nx, ny); + if (rn!=NULL && (valid==NULL || valid(rn))) add_regionlist(&rlist, rn); + } + } + return rlist; +} + +region * +r_standard_to_astral(const region *r) +{ + if (rplane(r) != get_normalplane()) return NULL; + return tpregion(r); +} + +region * +r_astral_to_standard(const region *r) +{ + int x, y; + region *r2; + + assert(is_astral(r)); + x = (r->x-TE_CENTER_X)*TP_DISTANCE; + y = (r->y-TE_CENTER_Y)*TP_DISTANCE; + pnormalize(&x, &y, get_normalplane()); + r2 = findregion(x, y); + if (r2==NULL || rplane(r2)!=get_normalplane()) return NULL; + + return r2; +} + +region_list * +all_in_range(const region *r, int n, boolean (*valid)(const region *)) +{ + int x, y; + region_list *rlist = NULL; + plane * pl = rplane(r); + + if (r == NULL) return NULL; + + for (x = r->x-n; x <= r->x+n; x++) { + for (y = r->y-n; y <= r->y+n; y++) { + if (koor_distance(r->x, r->y, x, y) <= n) { + region * r2; + int nx = x, ny = y; + pnormalize(&nx, &ny, pl); + r2 = findregion(nx, ny); + if (r2!=NULL && (valid==NULL || valid(r2))) add_regionlist(&rlist, r2); + } + } + } + + return rlist; +} + +void +spawn_braineaters(float chance) +{ + region *r; + faction *f0 = get_monsters(); + int next = rng_int() % (int)(chance*100); + + if (f0==NULL) return; + + for (r = regions; r; r = r->next) { + if (!is_astral(r) || fval(r->terrain, FORBIDDEN_REGION)) continue; + + /* Neues Monster ? */ + if (next-- == 0) { + unit *u = createunit(r, f0, 1+rng_int()%10+rng_int()%10, new_race[RC_HIRNTOETER]); + equip_unit(u, get_equipment("monster_braineater")); + + next = rng_int() % (int)(chance*100); + } + } +} + +plane * +get_normalplane(void) +{ + return NULL; +} + +boolean +is_astral(const region * r) +{ + plane * pl = get_astralplane(); + return (pl && rplane(r) == pl); +} + +plane * +get_astralplane(void) +{ + static plane * astralspace; + static int rule_astralplane = -1; + static int gamecookie = -1; + if (rule_astralplane<0) { + rule_astralplane = get_param_int(global.parameters, "modules.astralspace", 1); + } + if (!rule_astralplane) { + return NULL; + } + if (gamecookie!=global.cookie) { + astralspace = getplanebyname("Astralraum"); + gamecookie = global.cookie; + } + + if (astralspace==NULL) { + astralspace = create_new_plane(1, "Astralraum", + TE_CENTER_X-500, TE_CENTER_X+500, + TE_CENTER_Y-500, TE_CENTER_Y+500, 0); + } + return astralspace; +} + +void +create_teleport_plane(void) +{ + region *r; + plane * hplane = get_homeplane(); + plane * aplane = get_astralplane(); + + const terrain_type * fog = get_terrain("fog"); + + for (r=regions;r;r=r->next) { + plane * pl = rplane(r); + if (pl == hplane) { + region *ra = tpregion(r); + + if (ra==NULL) { + int x = TE_CENTER_X+real2tp(r->x); + int y = TE_CENTER_Y+real2tp(r->y); + pnormalize(&x, &y, aplane); + + ra = new_region(x, y, aplane, 0); + terraform_region(ra, fog); + } + } + } +} + +boolean +inhabitable(const region * r) +{ + return fval(r->terrain, LAND_REGION); +} diff --git a/src/kernel/teleport.h b/src/kernel/teleport.h index 83f777899..552a69736 100644 --- a/src/kernel/teleport.h +++ b/src/kernel/teleport.h @@ -1,41 +1,41 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef TELEPORT_H -#define TELEPORT_H -#ifdef __cplusplus -extern "C" { -#endif - - struct region *r_standard_to_astral(const struct region *r); - struct region *r_astral_to_standard(const struct region *); - extern struct region_list *astralregions(const struct region * rastral, boolean (*valid)(const struct region *)); - extern struct region_list *all_in_range(const struct region *r, int n, boolean (*valid)(const struct region *)); - extern boolean inhabitable(const struct region * r); - extern boolean is_astral(const struct region * r); - extern struct plane * get_astralplane(void); - extern struct plane * get_normalplane(void); - - void create_teleport_plane(void); - void set_teleport_plane_regiontypes(void); - void spawn_braineaters(float chance); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef TELEPORT_H +#define TELEPORT_H +#ifdef __cplusplus +extern "C" { +#endif + + struct region *r_standard_to_astral(const struct region *r); + struct region *r_astral_to_standard(const struct region *); + extern struct region_list *astralregions(const struct region * rastral, boolean (*valid)(const struct region *)); + extern struct region_list *all_in_range(const struct region *r, int n, boolean (*valid)(const struct region *)); + extern boolean inhabitable(const struct region * r); + extern boolean is_astral(const struct region * r); + extern struct plane * get_astralplane(void); + extern struct plane * get_normalplane(void); + + void create_teleport_plane(void); + void set_teleport_plane_regiontypes(void); + void spawn_braineaters(float chance); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/terrain.c b/src/kernel/terrain.c index 15ef6b58f..8605246fe 100644 --- a/src/kernel/terrain.c +++ b/src/kernel/terrain.c @@ -1,158 +1,158 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include -#include "terrain.h" -#include "terrainid.h" - -/* kernel includes */ -#include "curse.h" -#include "region.h" -#include "resources.h" - -#include -#include - -/* libc includes */ -#include -#include -#include - -#define MAXTERRAINS 20 - -const char * terraindata[MAXTERRAINS] = { - "ocean", - "plain", - "swamp", - "desert", - "highland", - "mountain", - "glacier", - "firewall", - NULL, /* dungeon module */ - NULL, /* former grassland */ - "fog", - "thickfog", - "volcano", - "activevolcano", - "iceberg_sleep", - "iceberg", - - NULL, /* museum module */ - NULL, /* museum module */ - NULL, /* former magicstorm */ - NULL /* museum module */ -}; - -static terrain_type * registered_terrains; - -const terrain_type * -terrains(void) -{ - return registered_terrains; -} - -static const char * -plain_name(const struct region * r) -{ - /* TODO: xml defined */ - if (r_isforest(r)) return "forest"; - return r->terrain->_name; -} - -void -register_terrain(struct terrain_type * terrain) -{ - assert(terrain->next==NULL), - terrain->next = registered_terrains; - registered_terrains = terrain; - if (strcmp("plain", terrain->_name)==0) - terrain->name = &plain_name; -} - -const struct terrain_type * -get_terrain(const char * name) -{ - const struct terrain_type * terrain; - for (terrain=registered_terrains;terrain;terrain=terrain->next) { - if (strcmp(terrain->_name, name)==0) break; - } - return terrain; -} - -static const terrain_type * newterrains[MAXTERRAINS]; - -const struct terrain_type * -newterrain(terrain_t t) -{ - if (t==NOTERRAIN) return NULL; - assert(t>=0); - assert(t_name)); - return NOTERRAIN; -} - -const char * -terrain_name(const struct region * r) -{ - if (r->attribs) { - attrib * a = a_find(r->attribs, &at_racename); - if (a) { - const char * str = get_racename(a); - if (str) return str; - } - } - - if (r->terrain->name!=NULL) { - return r->terrain->name(r); - } else if (fval(r->terrain, SEA_REGION)) { - if (curse_active(get_curse(r->attribs, ct_find("maelstrom")))) { - return "maelstrom"; - } - } - return r->terrain->_name; -} - -void -init_terrains(void) -{ - terrain_t t; - for (t=0;t!=MAXTERRAINS;++t) { - const terrain_type * newterrain = newterrains[t]; - if (newterrain!=NULL) continue; - if (terraindata[t]!=NULL) { - newterrain = get_terrain(terraindata[t]); - if (newterrain!=NULL) { - newterrains[t] = newterrain; - } - } - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include +#include "terrain.h" +#include "terrainid.h" + +/* kernel includes */ +#include "curse.h" +#include "region.h" +#include "resources.h" + +#include +#include + +/* libc includes */ +#include +#include +#include + +#define MAXTERRAINS 20 + +const char * terraindata[MAXTERRAINS] = { + "ocean", + "plain", + "swamp", + "desert", + "highland", + "mountain", + "glacier", + "firewall", + NULL, /* dungeon module */ + NULL, /* former grassland */ + "fog", + "thickfog", + "volcano", + "activevolcano", + "iceberg_sleep", + "iceberg", + + NULL, /* museum module */ + NULL, /* museum module */ + NULL, /* former magicstorm */ + NULL /* museum module */ +}; + +static terrain_type * registered_terrains; + +const terrain_type * +terrains(void) +{ + return registered_terrains; +} + +static const char * +plain_name(const struct region * r) +{ + /* TODO: xml defined */ + if (r_isforest(r)) return "forest"; + return r->terrain->_name; +} + +void +register_terrain(struct terrain_type * terrain) +{ + assert(terrain->next==NULL), + terrain->next = registered_terrains; + registered_terrains = terrain; + if (strcmp("plain", terrain->_name)==0) + terrain->name = &plain_name; +} + +const struct terrain_type * +get_terrain(const char * name) +{ + const struct terrain_type * terrain; + for (terrain=registered_terrains;terrain;terrain=terrain->next) { + if (strcmp(terrain->_name, name)==0) break; + } + return terrain; +} + +static const terrain_type * newterrains[MAXTERRAINS]; + +const struct terrain_type * +newterrain(terrain_t t) +{ + if (t==NOTERRAIN) return NULL; + assert(t>=0); + assert(t_name)); + return NOTERRAIN; +} + +const char * +terrain_name(const struct region * r) +{ + if (r->attribs) { + attrib * a = a_find(r->attribs, &at_racename); + if (a) { + const char * str = get_racename(a); + if (str) return str; + } + } + + if (r->terrain->name!=NULL) { + return r->terrain->name(r); + } else if (fval(r->terrain, SEA_REGION)) { + if (curse_active(get_curse(r->attribs, ct_find("maelstrom")))) { + return "maelstrom"; + } + } + return r->terrain->_name; +} + +void +init_terrains(void) +{ + terrain_t t; + for (t=0;t!=MAXTERRAINS;++t) { + const terrain_type * newterrain = newterrains[t]; + if (newterrain!=NULL) continue; + if (terraindata[t]!=NULL) { + newterrain = get_terrain(terraindata[t]); + if (newterrain!=NULL) { + newterrains[t] = newterrain; + } + } + } +} diff --git a/src/kernel/terrain.h b/src/kernel/terrain.h index 644a0e329..499a2acc8 100644 --- a/src/kernel/terrain.h +++ b/src/kernel/terrain.h @@ -1,83 +1,83 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef TERRAIN_H -#define TERRAIN_H -#ifdef __cplusplus -extern "C" { -#endif - -/* diverse Flags */ -/* Strassen können gebaut werden, wenn max_road > 0 */ -#define LAND_REGION (1<<0) /* Standard-Land-struct region */ -#define SEA_REGION (1<<1) /* hier braucht man ein Boot */ -#define FOREST_REGION (1<<2) /* Elfen- und Kampfvorteil durch Bäume */ -#define ARCTIC_REGION (1<<3) /* Gletscher & co = Keine Insekten! */ -#define CAVALRY_REGION (1<<4) /* Gletscher & co = Keine Insekten! */ -/* Achtung: SEA_REGION ist nicht das Gegenteil von LAND_REGION. Die zwei schliessen sich nichtmal aus! */ -#define FORBIDDEN_REGION (1<<5) /* unpassierbare Blockade-struct region */ -#define SAIL_INTO (1<<6) /* man darf hierhin segeln */ -#define FLY_INTO (1<<7) /* man darf hierhin fliegen */ -#define SWIM_INTO (1<<8) /* man darf hierhin schwimmen */ -#define WALK_INTO (1<<9) /* man darf hierhin laufen */ -#define LARGE_SHIPS (1<<10) /* grosse Schiffe dürfen hinfahren */ - -typedef struct production_rule { - char * name; - const struct resource_type * rtype; - - void (*terraform) (struct production_rule *, const struct region *); - void (*update) (struct production_rule *, const struct region *); - void (*use) (struct production_rule *, const struct region *, int amount); - int (*visible) (const struct production_rule *, int skilllevel); - - /* no initialization required */ - struct production_rule * next; -} production_rule; - -typedef struct terrain_production { - const struct resource_type * type; - const char *startlevel; - const char *base; - const char *divisor; - float chance; -} terrain_production; - -typedef struct terrain_type { - char * _name; - int size; /* how many peasants can work? */ - unsigned int flags; - short max_road; /* this many stones make a full road */ - short distribution; /* multiplier used for seeding */ - struct terrain_production * production; - const struct item_type ** herbs; /* zero-terminated array of herbs */ - const char * (*name)(const struct region * r); - const struct terrain_type * next; -} terrain_type; - -extern const terrain_type * terrains(void); -extern void register_terrain(struct terrain_type * terrain); -extern const struct terrain_type * get_terrain(const char * name); -extern const char * terrain_name(const struct region * r); - -extern void init_terrains(void); - -#ifdef __cplusplus -} -#endif -#endif /* TERRAIN_H */ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef TERRAIN_H +#define TERRAIN_H +#ifdef __cplusplus +extern "C" { +#endif + +/* diverse Flags */ +/* Strassen können gebaut werden, wenn max_road > 0 */ +#define LAND_REGION (1<<0) /* Standard-Land-struct region */ +#define SEA_REGION (1<<1) /* hier braucht man ein Boot */ +#define FOREST_REGION (1<<2) /* Elfen- und Kampfvorteil durch Bäume */ +#define ARCTIC_REGION (1<<3) /* Gletscher & co = Keine Insekten! */ +#define CAVALRY_REGION (1<<4) /* Gletscher & co = Keine Insekten! */ +/* Achtung: SEA_REGION ist nicht das Gegenteil von LAND_REGION. Die zwei schliessen sich nichtmal aus! */ +#define FORBIDDEN_REGION (1<<5) /* unpassierbare Blockade-struct region */ +#define SAIL_INTO (1<<6) /* man darf hierhin segeln */ +#define FLY_INTO (1<<7) /* man darf hierhin fliegen */ +#define SWIM_INTO (1<<8) /* man darf hierhin schwimmen */ +#define WALK_INTO (1<<9) /* man darf hierhin laufen */ +#define LARGE_SHIPS (1<<10) /* grosse Schiffe dürfen hinfahren */ + +typedef struct production_rule { + char * name; + const struct resource_type * rtype; + + void (*terraform) (struct production_rule *, const struct region *); + void (*update) (struct production_rule *, const struct region *); + void (*use) (struct production_rule *, const struct region *, int amount); + int (*visible) (const struct production_rule *, int skilllevel); + + /* no initialization required */ + struct production_rule * next; +} production_rule; + +typedef struct terrain_production { + const struct resource_type * type; + const char *startlevel; + const char *base; + const char *divisor; + float chance; +} terrain_production; + +typedef struct terrain_type { + char * _name; + int size; /* how many peasants can work? */ + unsigned int flags; + short max_road; /* this many stones make a full road */ + short distribution; /* multiplier used for seeding */ + struct terrain_production * production; + const struct item_type ** herbs; /* zero-terminated array of herbs */ + const char * (*name)(const struct region * r); + const struct terrain_type * next; +} terrain_type; + +extern const terrain_type * terrains(void); +extern void register_terrain(struct terrain_type * terrain); +extern const struct terrain_type * get_terrain(const char * name); +extern const char * terrain_name(const struct region * r); + +extern void init_terrains(void); + +#ifdef __cplusplus +} +#endif +#endif /* TERRAIN_H */ diff --git a/src/kernel/terrainid.h b/src/kernel/terrainid.h index fb2e40dd0..ee0947ec5 100644 --- a/src/kernel/terrainid.h +++ b/src/kernel/terrainid.h @@ -1,48 +1,48 @@ -/* vi: set ts=2: - * +-------------------+ Christian Schlittchen - * | | Enno Rehling - * | Eressea PBEM host | Katja Zedel - * | (c) 1998 - 2005 | - * | | This program may not be used, modified or distributed - * +-------------------+ without prior permission by the authors of Eressea. - */ - -#ifndef H_KRNL_TERRAINID_H -#define H_KRNL_TERRAINID_H - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - T_OCEAN = 0, - T_PLAIN = 1, - T_SWAMP = 2, - T_DESERT = 3, /* kann aus T_PLAIN entstehen */ - T_HIGHLAND = 4, - T_MOUNTAIN = 5, - T_GLACIER = 6, /* kann aus T_MOUNTAIN entstehen */ - T_FIREWALL = 7, /* Unpassierbar */ - /* T_HELL = 8, Hölle */ - /* T_GRASSLAND = 9, */ - T_ASTRAL = 10, - T_ASTRALB = 11, - T_VOLCANO = 12, - T_VOLCANO_SMOKING = 13, - T_ICEBERG_SLEEP = 14, - T_ICEBERG = 15, - /* T_HALL1 = 16, */ - /* T_CORRIDOR1 = 17, */ - /* T_MAGICSTORM = 18, */ - /* T_WALL1 = 19, */ - NOTERRAIN = (terrain_t) - 1 -}; - -extern const struct terrain_type * newterrain(terrain_t t); -extern terrain_t oldterrain(const struct terrain_type * terrain); - -#ifdef __cplusplus -} -#endif - -#endif +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2005 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + */ + +#ifndef H_KRNL_TERRAINID_H +#define H_KRNL_TERRAINID_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + T_OCEAN = 0, + T_PLAIN = 1, + T_SWAMP = 2, + T_DESERT = 3, /* kann aus T_PLAIN entstehen */ + T_HIGHLAND = 4, + T_MOUNTAIN = 5, + T_GLACIER = 6, /* kann aus T_MOUNTAIN entstehen */ + T_FIREWALL = 7, /* Unpassierbar */ + /* T_HELL = 8, Hölle */ + /* T_GRASSLAND = 9, */ + T_ASTRAL = 10, + T_ASTRALB = 11, + T_VOLCANO = 12, + T_VOLCANO_SMOKING = 13, + T_ICEBERG_SLEEP = 14, + T_ICEBERG = 15, + /* T_HALL1 = 16, */ + /* T_CORRIDOR1 = 17, */ + /* T_MAGICSTORM = 18, */ + /* T_WALL1 = 19, */ + NOTERRAIN = (terrain_t) - 1 +}; + +extern const struct terrain_type * newterrain(terrain_t t); +extern terrain_t oldterrain(const struct terrain_type * terrain); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/kernel/textstore.c b/src/kernel/textstore.c index 391038f0f..d3ffca98e 100644 --- a/src/kernel/textstore.c +++ b/src/kernel/textstore.c @@ -1,205 +1,208 @@ -/* vi: set ts=2: -+-------------------+ Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -+-------------------+ -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ -#include -#include "config.h" -#include "textstore.h" - -#include "save.h" -#include "version.h" -#include -#include - -#include -#include -#include -#include - -#define NULL_TOKEN '@' - -static int -txt_w_brk(struct storage * store) -{ - putc('\n', (FILE *)store->userdata); - return 1; -} - -static int -txt_w_id(struct storage * store, int arg) -{ - return fprintf((FILE *)store->userdata, "%s ", itoa36(arg)); -} - -static int -txt_r_id(struct storage * store) -{ - char id[8]; - fscanf((FILE *)store->userdata, "%7s", id); - return atoi36(id); -} - -static int -txt_w_int(struct storage * store, int arg) -{ - return fprintf((FILE *)store->userdata, "%d ", arg); -} - -static int -txt_r_int(struct storage * store) -{ - int result; - fscanf((FILE *)store->userdata, "%d", &result); - return result; -} - -static int -txt_w_flt(struct storage * store, float arg) -{ - return fprintf((FILE *)store->userdata, "%f ", arg); -} - -static float -txt_r_flt(struct storage * store) -{ - double result; - fscanf((FILE *)store->userdata, "%lf", &result); - return (float)result; -} - -static int -txt_w_tok(struct storage * store, const char * tok) -{ - int result; - if (tok==NULL || tok[0]==0) { - result = fputc(NULL_TOKEN, (FILE *)store->userdata); - } else { -#ifndef NDEBUG - const char * find = strchr(tok, ' '); - if (!find) find = strchr(tok, NULL_TOKEN); - assert(!find || !"reserved character in token"); -#endif - assert(tok[0]!=' '); - result = fputs(tok, (FILE *)store->userdata); - } - fputc(' ', (FILE *)store->userdata); - return result; -} -static char * -txt_r_tok(struct storage * store) -{ - char result[256]; - fscanf((FILE *)store->userdata, "%256s", result); - if (result[0]==NULL_TOKEN || result[0]==0) { - return NULL; - } - return strdup(result); -} -static void -txt_r_tok_buf(struct storage * store, char * result, size_t size) -{ - char format[16]; - if (result && size>0) { - format[0]='%'; - sprintf(format+1, "%us", size); - fscanf((FILE *)store->userdata, format, result); - if (result[0]==NULL_TOKEN) { - result[0] = 0; - } - } else { - /* trick to skip when no result expected */ - fscanf((FILE *)store->userdata, "%*s"); - } -} - -static int -txt_w_str(struct storage * store, const char * str) -{ - int result = fwritestr((FILE *)store->userdata, str); - fputc(' ', (FILE *)store->userdata); - return result+1; -} - -static char * -txt_r_str(struct storage * store) -{ - char buffer[DISPLAYSIZE]; - /* you should not use this */ - freadstr((FILE *)store->userdata, store->encoding, buffer, sizeof(buffer)); - return strdup(buffer); -} - -static void -txt_r_str_buf(struct storage * store, char * result, size_t size) -{ - freadstr((FILE *)store->userdata, store->encoding, result, size); -} - -static int -txt_open(struct storage * store, const char * filename, int mode) -{ - const char * modes[] = { 0, "rt", "wt", "at" }; - FILE * F = fopen(filename, modes[mode]); - store->userdata = F; - if (F) { - const char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; - if (mode==IO_READ) { - char token[8]; - /* recognize UTF8 BOM */ - store->r_tok_buf(store, token, sizeof(token)); - if (memcmp(token, utf8_bom, 3)==0) { - if (enc_gamedata!=XML_CHAR_ENCODING_UTF8) { - log_warning(("Found UTF-8 BOM, assuming unicode game data.\n")); - store->encoding = XML_CHAR_ENCODING_UTF8; - } - store->version = atoi(token+3); - } else { - if (store->encoding==XML_CHAR_ENCODING_NONE) { - store->encoding = XML_CHAR_ENCODING_8859_1; - log_warning(("No BOM, assuming 8859-1 game data.\n")); - } - store->version = atoi(token); - } - } else if (store->encoding==XML_CHAR_ENCODING_UTF8) { - fputs(utf8_bom, F); - fprintf(F, "%d\n", RELEASE_VERSION); - } - } - return (F==NULL); -} - -static int -txt_w_bin(struct storage * store, void * arg, size_t size) -{ - assert(!"not implemented!"); - return 0; -} - -static void -txt_r_bin(struct storage * store, void * result, size_t size) -{ - assert(!"not implemented!"); -} - -static int -txt_close(struct storage * store) -{ - return fclose((FILE *)store->userdata); -} - -const storage text_store = { - txt_w_brk, - txt_w_int, txt_r_int, - txt_w_flt, txt_r_flt, - txt_w_id, txt_r_id, - txt_w_tok, txt_r_tok, txt_r_tok_buf, - txt_w_str, txt_r_str, txt_r_str_buf, - txt_w_bin, txt_r_bin, - txt_open, txt_close, - 0, 0, NULL -}; - +/* vi: set ts=2: ++-------------------+ Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel ++-------------------+ +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ +#include +#include "config.h" +#include "textstore.h" + +#include "save.h" +#include "version.h" +#include +#include +#include + +#include +#include +#include +#ifdef HAVE_LIBXML +#include +#endif + +#define NULL_TOKEN '@' + +static int +txt_w_brk(struct storage * store) +{ + putc('\n', (FILE *)store->userdata); + return 1; +} + +static int +txt_w_id(struct storage * store, int arg) +{ + return fprintf((FILE *)store->userdata, "%s ", itoa36(arg)); +} + +static int +txt_r_id(struct storage * store) +{ + char id[8]; + fscanf((FILE *)store->userdata, "%7s", id); + return atoi36(id); +} + +static int +txt_w_int(struct storage * store, int arg) +{ + return fprintf((FILE *)store->userdata, "%d ", arg); +} + +static int +txt_r_int(struct storage * store) +{ + int result; + fscanf((FILE *)store->userdata, "%d", &result); + return result; +} + +static int +txt_w_flt(struct storage * store, float arg) +{ + return fprintf((FILE *)store->userdata, "%f ", arg); +} + +static float +txt_r_flt(struct storage * store) +{ + double result; + fscanf((FILE *)store->userdata, "%lf", &result); + return (float)result; +} + +static int +txt_w_tok(struct storage * store, const char * tok) +{ + int result; + if (tok==NULL || tok[0]==0) { + result = fputc(NULL_TOKEN, (FILE *)store->userdata); + } else { +#ifndef NDEBUG + const char * find = strchr(tok, ' '); + if (!find) find = strchr(tok, NULL_TOKEN); + assert(!find || !"reserved character in token"); +#endif + assert(tok[0]!=' '); + result = fputs(tok, (FILE *)store->userdata); + } + fputc(' ', (FILE *)store->userdata); + return result; +} +static char * +txt_r_tok(struct storage * store) +{ + char result[256]; + fscanf((FILE *)store->userdata, "%256s", result); + if (result[0]==NULL_TOKEN || result[0]==0) { + return NULL; + } + return strdup(result); +} +static void +txt_r_tok_buf(struct storage * store, char * result, size_t size) +{ + char format[16]; + if (result && size>0) { + format[0]='%'; + sprintf(format+1, "%us", size); + fscanf((FILE *)store->userdata, format, result); + if (result[0]==NULL_TOKEN) { + result[0] = 0; + } + } else { + /* trick to skip when no result expected */ + fscanf((FILE *)store->userdata, "%*s"); + } +} + +static int +txt_w_str(struct storage * store, const char * str) +{ + int result = fwritestr((FILE *)store->userdata, str); + fputc(' ', (FILE *)store->userdata); + return result+1; +} + +static char * +txt_r_str(struct storage * store) +{ + char buffer[DISPLAYSIZE]; + /* you should not use this */ + freadstr((FILE *)store->userdata, store->encoding, buffer, sizeof(buffer)); + return strdup(buffer); +} + +static void +txt_r_str_buf(struct storage * store, char * result, size_t size) +{ + freadstr((FILE *)store->userdata, store->encoding, result, size); +} + +static int +txt_open(struct storage * store, const char * filename, int mode) +{ + const char * modes[] = { 0, "rt", "wt", "at" }; + FILE * F = fopen(filename, modes[mode]); + store->userdata = F; + if (F) { + const char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + if (mode==IO_READ) { + char token[8]; + /* recognize UTF8 BOM */ + store->r_tok_buf(store, token, sizeof(token)); + if (memcmp(token, utf8_bom, 3)==0) { + if (enc_gamedata!=ENCODING_UTF8) { + log_warning(("Found UTF-8 BOM, assuming unicode game data.\n")); + store->encoding = ENCODING_UTF8; + } + store->version = atoi(token+3); + } else { + if (store->encoding==ENCODING_NONE) { + store->encoding = ENCODING_8859_1; + log_warning(("No BOM, assuming 8859-1 game data.\n")); + } + store->version = atoi(token); + } + } else if (store->encoding==ENCODING_UTF8) { + fputs(utf8_bom, F); + fprintf(F, "%d\n", RELEASE_VERSION); + } + } + return (F==NULL); +} + +static int +txt_w_bin(struct storage * store, void * arg, size_t size) +{ + assert(!"not implemented!"); + return 0; +} + +static void +txt_r_bin(struct storage * store, void * result, size_t size) +{ + assert(!"not implemented!"); +} + +static int +txt_close(struct storage * store) +{ + return fclose((FILE *)store->userdata); +} + +const storage text_store = { + txt_w_brk, + txt_w_int, txt_r_int, + txt_w_flt, txt_r_flt, + txt_w_id, txt_r_id, + txt_w_tok, txt_r_tok, txt_r_tok_buf, + txt_w_str, txt_r_str, txt_r_str_buf, + txt_w_bin, txt_r_bin, + txt_open, txt_close, + 0, 0, NULL +}; + diff --git a/src/kernel/textstore.h b/src/kernel/textstore.h index 134a8da7e..d6f60f776 100644 --- a/src/kernel/textstore.h +++ b/src/kernel/textstore.h @@ -1,23 +1,23 @@ -/* vi: set ts=2: -+-------------------+ Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -+-------------------+ -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifndef H_KERNEL_TEXTSTORE -#define H_KERNEL_TEXTSTORE -#ifdef __cplusplus -extern "C" { -#endif - -#include - -extern const storage text_store; - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: ++-------------------+ Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel ++-------------------+ +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifndef H_KERNEL_TEXTSTORE +#define H_KERNEL_TEXTSTORE +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern const storage text_store; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/types.h b/src/kernel/types.h index 9c16e63ac..af54b1d92 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -1,407 +1,407 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef ERESSEA_TYPES_H -#define ERESSEA_TYPES_H - -/* - * Features enabled: - * If you are lacking the settings.h, create a new file common/settings.h, - * and write #include (or whatever settings you want - * your game to use) in there. - * !!! DO NOT COMMIT THE SETTINGS.H FILE TO CVS !!! - * settings.h should always be the first thing you include (after platform.h). - */ -#include -#include - -typedef short terrain_t; -typedef short direction_t; -typedef short race_t; -typedef short magic_t; -typedef short skill_t; -typedef short typ_t; -typedef short item_t; -typedef unsigned int spellid_t; - -struct attrib; -struct attrib_type; -struct building; -struct building_type; -struct curse; -struct equipment; -struct faction; -struct fighter; -struct item; -struct item_type; -struct locale; -struct luxury_type; -struct order; -struct plane; -struct potion_type; -struct race; -struct region; -struct region_list; -struct resource_type; -struct ship; -struct ship_type; -struct skill; -struct spell; -struct storage; -struct strlist; -struct terrain_type; -struct unit; -struct unit_list; -struct weapon_type; - -typedef struct ursprung { - struct ursprung *next; - int id; - int x, y; -} ursprung; - -/* ----------------- Befehle ----------------------------------- */ - -typedef unsigned char keyword_t; -enum { - K_KOMMENTAR, - K_BANNER, - K_WORK, - K_ATTACK, - K_STEAL, - K_BESIEGE, - K_NAME, - K_USE, - K_DISPLAY, - K_ENTER, - K_GUARD, - K_MAIL, - K_END, - K_DRIVE, - K_NUMBER, - K_WAR, - K_PEACE, - K_FOLLOW, - K_RESEARCH, - K_GIVE, - K_ALLY, - K_STATUS, - K_COMBATSPELL, - K_BUY, - K_CONTACT, - K_TEACH, - K_STUDY, - K_LIEFERE, - K_MAKE, - K_MOVE, - K_PASSWORD, - K_RECRUIT, - K_RESERVE, - K_ROUTE, - K_SABOTAGE, - K_SEND, - K_SPY, - K_QUIT, - K_SETSTEALTH, - K_TRANSPORT, - K_TAX, - K_ENTERTAIN, - K_SELL, - K_LEAVE, - K_FORGET, - K_CAST, - K_RESHOW, - K_DESTROY, - K_BREED, - K_DEFAULT, - K_URSPRUNG, - K_EMAIL, - K_PIRACY, - K_RESTART, - K_GROUP, - K_SACRIFICE, - K_PRAY, - K_SORT, - K_SETJIHAD, - K_GM, /* perform GM commands */ - K_INFO, /* set player-info */ - K_PREFIX, - K_PLANT, - K_WEREWOLF, - K_XE, - K_ALLIANCE, - K_CLAIM, - K_PROMOTION, - K_PAY, - MAXKEYWORDS, - NOKEYWORD = (keyword_t) - 1 -}; - -/* ------------------ Status von Einheiten --------------------- */ - -typedef unsigned char status_t; -enum { - ST_AGGRO, - ST_FIGHT, - ST_BEHIND, - ST_CHICKEN, - ST_AVOID, - ST_FLEE -}; - -/* ----------------- Parameter --------------------------------- */ - -typedef unsigned char param_t; -enum { - P_LOCALE, - P_ANY, - P_EACH, - P_PEASANT, - P_BUILDING, - P_UNIT, - P_PRIVAT, - P_BEHIND, - P_CONTROL, - P_HERBS, - P_NOT, - P_NEXT, - P_FACTION, - P_GAMENAME, - P_PERSON, - P_REGION, - P_SHIP, - P_MONEY, - P_ROAD, - P_TEMP, - P_FLEE, - P_GEBAEUDE, - P_GIVE, - P_FIGHT, - P_TRAVEL, - P_GUARD, - P_ZAUBER, - P_PAUSE, - P_VORNE, - P_AGGRO, - P_CHICKEN, - P_LEVEL, - P_HELP, - P_FOREIGN, - P_AURA, - P_FOR, - P_AID, - P_MERCY, - P_AFTER, - P_BEFORE, - P_NUMBER, - P_ITEMS, - P_POTIONS, - P_GROUP, - P_FACTIONSTEALTH, - P_TREES, - P_XEPOTION, - P_XEBALLOON, - P_XELAEN, - P_ALLIANCE, - MAXPARAMS, - NOPARAM = (param_t) - 1 -}; - -typedef enum { /* Fehler und Meldungen im Report */ - MSG_BATTLE, - MSG_EVENT, - MSG_MOVE, - MSG_INCOME, - MSG_COMMERCE, - MSG_PRODUCE, - MSG_ORCVERMEHRUNG, - MSG_MESSAGE, - MSG_COMMENT, - MSG_MAGIC, - MAX_MSG -} msg_t; - -enum { /* Message-Level */ - ML_IMPORTANT, /* Sachen, die IMO erscheinen _muessen_ */ - ML_DEBUG, - ML_MISTAKE, - ML_WARN, - ML_INFO, - ML_MAX -}; - -extern const char *parameters[MAXPARAMS]; - -/* --------------- Reports Typen ------------------------------- */ - -enum { - O_REPORT, /* 1 */ - O_COMPUTER, /* 2 */ - O_ZUGVORLAGE, /* 4 */ - O_UNUSED_3, - O_STATISTICS, /* 16 */ - O_DEBUG, /* 32 */ - O_COMPRESS, /* 64 */ - O_NEWS, /* 128 */ - O_UNUSED_8, - O_ADRESSEN, /* 512 */ - O_BZIP2, /* 1024 - compress as bzip2 */ - O_SCORE, /* 2048 - punkte anzeigen? */ - O_SHOWSKCHANGE, /* 4096 - Skillveränderungen anzeigen? */ - O_XML, /* 8192 - XML report versenden */ - MAXOPTIONS -}; - -/* ------------------ Talente ---------------------------------- */ - -enum { - SK_ALCHEMY, - SK_CROSSBOW, - SK_MINING, - SK_LONGBOW, - SK_BUILDING, - SK_TRADE, - SK_LUMBERJACK, - SK_CATAPULT, - SK_HERBALISM, - SK_MAGIC, - SK_HORSE_TRAINING, /* 10 */ - SK_RIDING, - SK_ARMORER, - SK_SHIPBUILDING, - SK_MELEE, - SK_SAILING, - SK_SPEAR, - SK_SPY, - SK_QUARRYING, - SK_ROAD_BUILDING, - SK_TACTICS, /* 20 */ - SK_STEALTH, - SK_ENTERTAINMENT, - SK_WEAPONSMITH, - SK_CARTMAKER, - SK_PERCEPTION, - SK_TAXING, - SK_STAMINA, - SK_WEAPONLESS, - MAXSKILLS, - NOSKILL = (skill_t) -1 -}; - -/* ------------- Typ von Einheiten ----------------------------- */ - -enum { - RC_DWARF, /* 0 - Zwerg */ - RC_ELF, - RC_GOBLIN = 3, - RC_HUMAN, - - RC_TROLL, - RC_DAEMON, - RC_INSECT, - RC_HALFLING, - RC_CAT, - - RC_AQUARIAN, - RC_ORC, - RC_SNOTLING, - RC_UNDEAD, - RC_ILLUSION, - - RC_FIREDRAGON, - RC_DRAGON, - RC_WYRM, - RC_TREEMAN, - RC_BIRTHDAYDRAGON, - - RC_DRACOID, - RC_SPECIAL, - RC_SPELL, - RC_IRONGOLEM, - RC_STONEGOLEM, - - RC_SHADOW, - RC_SHADOWLORD, - RC_IRONKEEPER, - RC_ALP, - RC_TOAD, - - RC_HIRNTOETER, - RC_PEASANT, - RC_WOLF = 32, - - RC_SONGDRAGON = 37, - - RC_SEASERPENT = 51, - RC_SHADOWKNIGHT, - RC_CENTAUR, - RC_SKELETON, - - RC_SKELETON_LORD, - RC_ZOMBIE, - RC_ZOMBIE_LORD, - RC_GHOUL, - RC_GHOUL_LORD, - - RC_MUS_SPIRIT, - RC_GNOME, - RC_TEMPLATE, - RC_CLONE, - - MAXRACES, - NORACE = (race_t) - 1 -}; - -/* Richtungen */ -enum { - D_NORTHWEST, - D_NORTHEAST, - D_EAST, - D_SOUTHEAST, - D_SOUTHWEST, - D_WEST, - MAXDIRECTIONS, - D_PAUSE, - D_SPECIAL, - NODIRECTION = (direction_t) - 1 -}; - -#define DONT_HELP 0 -#define HELP_MONEY 1 /* Mitversorgen von Einheiten */ -#define HELP_FIGHT 2 /* Bei Verteidigung mithelfen */ -#define HELP_OBSERVE 4 /* Bei Wahrnehmung mithelfen */ -#define HELP_GIVE 8 /* Dinge annehmen ohne KONTAKTIERE */ -#define HELP_GUARD 16 /* Laesst Steuern eintreiben etc. */ -#define HELP_FSTEALTH 32 /* Parteitarnung anzeigen. */ -#define HELP_TRAVEL 64 /* Laesst Regionen betreten. */ -#define HELP_ALL (127-HELP_TRAVEL-HELP_OBSERVE) /* Alle "positiven" HELPs zusammen */ -/* HELP_OBSERVE deaktiviert */ -/* ------------------------------------------------------------- */ -/* Prototypen */ - - -#define ALLIED_TAX 1 -#define ALLIED_NOBLOCK 2 -#define ALLIED_HELP 4 - -/* alle vierstelligen zahlen: */ -#define MAX_UNIT_NR (36*36*36*36-1) -#define MAX_CONTAINER_NR (36*36*36*36-1) - - -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef ERESSEA_TYPES_H +#define ERESSEA_TYPES_H + +/* + * Features enabled: + * If you are lacking the settings.h, create a new file common/settings.h, + * and write #include (or whatever settings you want + * your game to use) in there. + * !!! DO NOT COMMIT THE SETTINGS.H FILE TO CVS !!! + * settings.h should always be the first thing you include (after platform.h). + */ +#include +#include + +typedef short terrain_t; +typedef short direction_t; +typedef short race_t; +typedef short magic_t; +typedef short skill_t; +typedef short typ_t; +typedef short item_t; +typedef unsigned int spellid_t; + +struct attrib; +struct attrib_type; +struct building; +struct building_type; +struct curse; +struct equipment; +struct faction; +struct fighter; +struct item; +struct item_type; +struct locale; +struct luxury_type; +struct order; +struct plane; +struct potion_type; +struct race; +struct region; +struct region_list; +struct resource_type; +struct ship; +struct ship_type; +struct skill; +struct spell; +struct storage; +struct strlist; +struct terrain_type; +struct unit; +struct unit_list; +struct weapon_type; + +typedef struct ursprung { + struct ursprung *next; + int id; + int x, y; +} ursprung; + +/* ----------------- Befehle ----------------------------------- */ + +typedef unsigned char keyword_t; +enum { + K_KOMMENTAR, + K_BANNER, + K_WORK, + K_ATTACK, + K_STEAL, + K_BESIEGE, + K_NAME, + K_USE, + K_DISPLAY, + K_ENTER, + K_GUARD, + K_MAIL, + K_END, + K_DRIVE, + K_NUMBER, + K_WAR, + K_PEACE, + K_FOLLOW, + K_RESEARCH, + K_GIVE, + K_ALLY, + K_STATUS, + K_COMBATSPELL, + K_BUY, + K_CONTACT, + K_TEACH, + K_STUDY, + K_LIEFERE, + K_MAKE, + K_MOVE, + K_PASSWORD, + K_RECRUIT, + K_RESERVE, + K_ROUTE, + K_SABOTAGE, + K_SEND, + K_SPY, + K_QUIT, + K_SETSTEALTH, + K_TRANSPORT, + K_TAX, + K_ENTERTAIN, + K_SELL, + K_LEAVE, + K_FORGET, + K_CAST, + K_RESHOW, + K_DESTROY, + K_BREED, + K_DEFAULT, + K_URSPRUNG, + K_EMAIL, + K_PIRACY, + K_RESTART, + K_GROUP, + K_SACRIFICE, + K_PRAY, + K_SORT, + K_SETJIHAD, + K_GM, /* perform GM commands */ + K_INFO, /* set player-info */ + K_PREFIX, + K_PLANT, + K_WEREWOLF, + K_XE, + K_ALLIANCE, + K_CLAIM, + K_PROMOTION, + K_PAY, + MAXKEYWORDS, + NOKEYWORD = (keyword_t) - 1 +}; + +/* ------------------ Status von Einheiten --------------------- */ + +typedef unsigned char status_t; +enum { + ST_AGGRO, + ST_FIGHT, + ST_BEHIND, + ST_CHICKEN, + ST_AVOID, + ST_FLEE +}; + +/* ----------------- Parameter --------------------------------- */ + +typedef unsigned char param_t; +enum { + P_LOCALE, + P_ANY, + P_EACH, + P_PEASANT, + P_BUILDING, + P_UNIT, + P_PRIVAT, + P_BEHIND, + P_CONTROL, + P_HERBS, + P_NOT, + P_NEXT, + P_FACTION, + P_GAMENAME, + P_PERSON, + P_REGION, + P_SHIP, + P_MONEY, + P_ROAD, + P_TEMP, + P_FLEE, + P_GEBAEUDE, + P_GIVE, + P_FIGHT, + P_TRAVEL, + P_GUARD, + P_ZAUBER, + P_PAUSE, + P_VORNE, + P_AGGRO, + P_CHICKEN, + P_LEVEL, + P_HELP, + P_FOREIGN, + P_AURA, + P_FOR, + P_AID, + P_MERCY, + P_AFTER, + P_BEFORE, + P_NUMBER, + P_ITEMS, + P_POTIONS, + P_GROUP, + P_FACTIONSTEALTH, + P_TREES, + P_XEPOTION, + P_XEBALLOON, + P_XELAEN, + P_ALLIANCE, + MAXPARAMS, + NOPARAM = (param_t) - 1 +}; + +typedef enum { /* Fehler und Meldungen im Report */ + MSG_BATTLE, + MSG_EVENT, + MSG_MOVE, + MSG_INCOME, + MSG_COMMERCE, + MSG_PRODUCE, + MSG_ORCVERMEHRUNG, + MSG_MESSAGE, + MSG_COMMENT, + MSG_MAGIC, + MAX_MSG +} msg_t; + +enum { /* Message-Level */ + ML_IMPORTANT, /* Sachen, die IMO erscheinen _muessen_ */ + ML_DEBUG, + ML_MISTAKE, + ML_WARN, + ML_INFO, + ML_MAX +}; + +extern const char *parameters[MAXPARAMS]; + +/* --------------- Reports Typen ------------------------------- */ + +enum { + O_REPORT, /* 1 */ + O_COMPUTER, /* 2 */ + O_ZUGVORLAGE, /* 4 */ + O_UNUSED_3, + O_STATISTICS, /* 16 */ + O_DEBUG, /* 32 */ + O_COMPRESS, /* 64 */ + O_NEWS, /* 128 */ + O_UNUSED_8, + O_ADRESSEN, /* 512 */ + O_BZIP2, /* 1024 - compress as bzip2 */ + O_SCORE, /* 2048 - punkte anzeigen? */ + O_SHOWSKCHANGE, /* 4096 - Skillveränderungen anzeigen? */ + O_XML, /* 8192 - XML report versenden */ + MAXOPTIONS +}; + +/* ------------------ Talente ---------------------------------- */ + +enum { + SK_ALCHEMY, + SK_CROSSBOW, + SK_MINING, + SK_LONGBOW, + SK_BUILDING, + SK_TRADE, + SK_LUMBERJACK, + SK_CATAPULT, + SK_HERBALISM, + SK_MAGIC, + SK_HORSE_TRAINING, /* 10 */ + SK_RIDING, + SK_ARMORER, + SK_SHIPBUILDING, + SK_MELEE, + SK_SAILING, + SK_SPEAR, + SK_SPY, + SK_QUARRYING, + SK_ROAD_BUILDING, + SK_TACTICS, /* 20 */ + SK_STEALTH, + SK_ENTERTAINMENT, + SK_WEAPONSMITH, + SK_CARTMAKER, + SK_PERCEPTION, + SK_TAXING, + SK_STAMINA, + SK_WEAPONLESS, + MAXSKILLS, + NOSKILL = (skill_t) -1 +}; + +/* ------------- Typ von Einheiten ----------------------------- */ + +enum { + RC_DWARF, /* 0 - Zwerg */ + RC_ELF, + RC_GOBLIN = 3, + RC_HUMAN, + + RC_TROLL, + RC_DAEMON, + RC_INSECT, + RC_HALFLING, + RC_CAT, + + RC_AQUARIAN, + RC_ORC, + RC_SNOTLING, + RC_UNDEAD, + RC_ILLUSION, + + RC_FIREDRAGON, + RC_DRAGON, + RC_WYRM, + RC_TREEMAN, + RC_BIRTHDAYDRAGON, + + RC_DRACOID, + RC_SPECIAL, + RC_SPELL, + RC_IRONGOLEM, + RC_STONEGOLEM, + + RC_SHADOW, + RC_SHADOWLORD, + RC_IRONKEEPER, + RC_ALP, + RC_TOAD, + + RC_HIRNTOETER, + RC_PEASANT, + RC_WOLF = 32, + + RC_SONGDRAGON = 37, + + RC_SEASERPENT = 51, + RC_SHADOWKNIGHT, + RC_CENTAUR, + RC_SKELETON, + + RC_SKELETON_LORD, + RC_ZOMBIE, + RC_ZOMBIE_LORD, + RC_GHOUL, + RC_GHOUL_LORD, + + RC_MUS_SPIRIT, + RC_GNOME, + RC_TEMPLATE, + RC_CLONE, + + MAXRACES, + NORACE = (race_t) - 1 +}; + +/* Richtungen */ +enum { + D_NORTHWEST, + D_NORTHEAST, + D_EAST, + D_SOUTHEAST, + D_SOUTHWEST, + D_WEST, + MAXDIRECTIONS, + D_PAUSE, + D_SPECIAL, + NODIRECTION = (direction_t) - 1 +}; + +#define DONT_HELP 0 +#define HELP_MONEY 1 /* Mitversorgen von Einheiten */ +#define HELP_FIGHT 2 /* Bei Verteidigung mithelfen */ +#define HELP_OBSERVE 4 /* Bei Wahrnehmung mithelfen */ +#define HELP_GIVE 8 /* Dinge annehmen ohne KONTAKTIERE */ +#define HELP_GUARD 16 /* Laesst Steuern eintreiben etc. */ +#define HELP_FSTEALTH 32 /* Parteitarnung anzeigen. */ +#define HELP_TRAVEL 64 /* Laesst Regionen betreten. */ +#define HELP_ALL (127-HELP_TRAVEL-HELP_OBSERVE) /* Alle "positiven" HELPs zusammen */ +/* HELP_OBSERVE deaktiviert */ +/* ------------------------------------------------------------- */ +/* Prototypen */ + + +#define ALLIED_TAX 1 +#define ALLIED_NOBLOCK 2 +#define ALLIED_HELP 4 + +/* alle vierstelligen zahlen: */ +#define MAX_UNIT_NR (36*36*36*36-1) +#define MAX_CONTAINER_NR (36*36*36*36-1) + + +#endif diff --git a/src/kernel/unit.c b/src/kernel/unit.c index e8ab947f7..0dd720bd0 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1,1743 +1,1743 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "unit.h" - -#include "building.h" -#include "faction.h" -#include "group.h" -#include "connection.h" -#include "item.h" -#include "move.h" -#include "order.h" -#include "plane.h" -#include "race.h" -#include "region.h" -#include "save.h" -#include "ship.h" -#include "skill.h" -#include "terrain.h" - -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -#define FIND_FOREIGN_TEMP - -attrib_type at_creator = { - "creator" - /* Rest ist NULL; temporäres, nicht alterndes Attribut */ -}; - -#define UMAXHASH MAXUNITS -static unit * unithash[UMAXHASH]; -static unit * delmarker = (unit*)unithash; /* a funny hack */ - -#define HASH_STATISTICS 1 -#if HASH_STATISTICS -static int hash_requests; -static int hash_misses; -#endif - -void -uhash(unit * u) -{ - int key = HASH1(u->no, UMAXHASH), gk = HASH2(u->no, UMAXHASH); - while (unithash[key]!=NULL && unithash[key]!=delmarker && unithash[key]!=u) { - key = (key + gk) % UMAXHASH; - } - assert(unithash[key]!=u || !"trying to add the same unit twice"); - unithash[key] = u; -} - -void -uunhash(unit * u) -{ - int key = HASH1(u->no, UMAXHASH), gk = HASH2(u->no, UMAXHASH); - while (unithash[key]!=NULL && unithash[key]!=u) { - key = (key + gk) % UMAXHASH; - } - assert(unithash[key]==u || !"trying to remove a unit that is not hashed"); - unithash[key] = delmarker; -} - -unit * -ufindhash(int uid) -{ - assert(uid>=0); -#if HASH_STATISTICS - ++hash_requests; -#endif - if (uid>=0) { - int key = HASH1(uid, UMAXHASH), gk = HASH2(uid, UMAXHASH); - while (unithash[key]!=NULL && (unithash[key]==delmarker || unithash[key]->no!=uid)) { - key = (key + gk) % UMAXHASH; -#if HASH_STATISTICS - ++hash_misses; -#endif - } - return unithash[key]; - } - return NULL; -} - -#define DMAXHASH 7919 -typedef struct dead { - struct dead * nexthash; - faction * f; - int no; -} dead; - -static dead* deadhash[DMAXHASH]; - -static void -dhash(int no, faction * f) -{ - dead * hash = (dead*)calloc(1, sizeof(dead)); - dead * old = deadhash[no % DMAXHASH]; - hash->no = no; - hash->f = f; - deadhash[no % DMAXHASH] = hash; - hash->nexthash = old; -} - -faction * -dfindhash(int no) -{ - dead * old; - - if(no < 0) return 0; - - for (old = deadhash[no % DMAXHASH]; old; old = old->nexthash) { - if (old->no == no) { - return old->f; - } - } - return 0; -} - -typedef struct friend { - struct friend * next; - int number; - faction * faction; - unit * unit; -} friend; - -static friend * -get_friends(const unit * u, int * numfriends) -{ - friend * friends = 0; - faction * f = u->faction; - region * r = u->region; - int number = 0; - unit * u2; - - for (u2=r->units;u2;u2=u2->next) { - if (u2->faction!=f && u2->number>0) { - int allied = 0; - if (get_param_int(global.parameters, "rules.alliances", 0)!=0) { - allied = (f->alliance && f->alliance==u2->faction->alliance); - } - else if (alliedunit(u, u2->faction, HELP_MONEY) && alliedunit(u2, f, HELP_GIVE)) { - allied = 1; - } - if (allied) { - friend * nf, ** fr = &friends; - - /* some units won't take stuff: */ - if (u2->race->ec_flags & GETITEM) { - while (*fr && (*fr)->faction->nofaction->no) fr = &(*fr)->next; - nf = *fr; - if (nf==NULL || nf->faction!=u2->faction) { - nf = malloc(sizeof(friend)); - nf->next = *fr; - nf->faction = u2->faction; - nf->unit = u2; - nf->number = 0; - *fr = nf; - } else if (nf->faction==u2->faction && (u2->race->ec_flags & GIVEITEM)) { - /* we don't like to gift it to units that won't give it back */ - if ((nf->unit->race->ec_flags & GIVEITEM) == 0) { - nf->unit = u2; - } - } - nf->number += u2->number; - number += u2->number; - } - } - } - } - if (numfriends) *numfriends = number; - return friends; -} - -/** give all items to friends or peasants. - * this function returns 0 on success, or 1 if there are items that - * could not be destroyed. - */ -int -gift_items(unit * u, int flags) -{ - region * r = u->region; - item ** itm_p = &u->items; - int retval = 0; - int rule = rule_give(); - - if ((u->faction->flags&FFL_QUIT)==0 || (rule&GIVE_ONDEATH)==0) { - if ((rule&GIVE_ALLITEMS)==0 && (flags&GIFT_FRIENDS)) flags-=GIFT_FRIENDS; - if ((rule&GIVE_PEASANTS)==0 && (flags&GIFT_PEASANTS)) flags-=GIFT_PEASANTS; - if ((rule&GIVE_SELF)==0 && (flags&GIFT_SELF)) flags-=GIFT_SELF; - } - - if (u->items==NULL || fval(u->race, RCF_ILLUSIONARY)) return 0; - if ((u->race->ec_flags & GIVEITEM) == 0) return 0; - - /* at first, I should try giving my crap to my own units in this region */ - if (u->faction && (u->faction->flags&FFL_QUIT)==0 && (flags & GIFT_SELF)) { - unit * u2, * u3 = NULL; - for (u2 = r->units; u2; u2 = u2->next) { - if (u2 != u && u2->faction == u->faction && u2->number>0) { - /* some units won't take stuff: */ - if (u2->race->ec_flags & GETITEM) { - /* we don't like to gift it to units that won't give it back */ - if (u2->race->ec_flags & GIVEITEM) { - i_merge(&u2->items, &u->items); - u->items = NULL; - break; - } else { - u3 = u2; - } - } - } - } - if (u->items && u3) { - /* if nobody else takes it, we give it to a unit that has issues */ - i_merge(&u3->items, &u->items); - u->items = NULL; - } - if (u->items==NULL) return 0; - } - - /* if I have friends, I'll try to give my stuff to them */ - if (u->faction && (flags & GIFT_FRIENDS)) { - int number = 0; - friend * friends = get_friends(u, &number); - - while (friends) { - struct friend * nf = friends; - unit * u2 = nf->unit; - item * itm = u->items; - while (itm!=NULL) { - const item_type * itype = itm->type; - item * itn = itm->next; - int n = itm->number; - n = n * nf->number / number; - if (n>0) { - i_change(&u->items, itype, -n); - i_change(&u2->items, itype, n); - } - itm = itn; - } - number -= nf->number; - friends = nf->next; - free(nf); - } - if (u->items==NULL) return 0; - } - - /* last, but not least, give money and horses to peasants */ - while (*itm_p) { - item * itm = *itm_p; - - if (flags & GIFT_PEASANTS) { - if (!fval(u->region->terrain, SEA_REGION)) { - if (itm->type==olditemtype[I_HORSE]) { - rsethorses(r, rhorses(r) + itm->number); - itm->number = 0; - } else if (itm->type==i_silver) { - rsetmoney(r, rmoney(r) + itm->number); - itm->number = 0; - } - } - } - if (itm->number>0 && (itm->type->flags & ITF_NOTLOST)) { - itm_p = &itm->next; - retval = -1; - } else { - i_remove(itm_p, itm); - i_free(itm); - } - } - return retval; -} - -void -make_zombie(unit * u) -{ - u_setfaction(u, get_monsters()); - scale_number(u, 1); - u->race = new_race[RC_ZOMBIE]; - u->irace = NULL; -} - -/** remove the unit from the list of active units. - * the unit is not actually freed, because there may still be references - * dangling to it (from messages, for example). To free all removed units, - * call free_units(). - * returns 0 on success, or -1 if unit could not be removed. - */ - -static unit * deleted_units = NULL; - -int -remove_unit(unit ** ulist, unit * u) -{ - int result; - - assert(ufindhash(u->no)); - handle_event(u->attribs, "destroy", u); - - result = gift_items(u, GIFT_SELF|GIFT_FRIENDS|GIFT_PEASANTS); - if (result!=0) { - make_zombie(u); - return -1; - } - - if (u->number) set_number(u, 0); - leave(u, true); - u->region = NULL; - - uunhash(u); - if (ulist) { - while (*ulist!=u) { - ulist = &(*ulist)->next; - } - assert(*ulist==u); - *ulist = u->next; - } - - u->next = deleted_units; - deleted_units = u; - dhash(u->no, u->faction); - - u_setfaction(u, NULL); - u->region = NULL; - - return 0; -} - -unit * -findnewunit (const region * r, const faction *f, int n) -{ - unit *u2; - - if (n == 0) - return 0; - - for (u2 = r->units; u2; u2 = u2->next) - if (u2->faction == f && ualias(u2) == n) - return u2; -#ifdef FIND_FOREIGN_TEMP - for (u2 = r->units; u2; u2 = u2->next) - if (ualias(u2) == n) - return u2; -#endif - return 0; -} - -/* ------------------------------------------------------------- */ - - -/*********************/ -/* at_alias */ -/*********************/ -attrib_type at_alias = { - "alias", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - NO_WRITE, - NO_READ -}; - -int -ualias(const unit * u) -{ - attrib * a = a_find(u->attribs, &at_alias); - if (!a) return 0; - return a->data.i; -} - -int -a_readprivate(attrib * a, void * owner, struct storage * store) -{ - a->data.v = store->r_str(store); - if (a->data.v) return AT_READ_OK; - return AT_READ_FAIL; -} - -/*********************/ -/* at_private */ -/*********************/ -attrib_type at_private = { - "private", - DEFAULT_INIT, - a_finalizestring, - DEFAULT_AGE, - a_writestring, - a_readprivate -}; - -const char * -u_description(const unit * u, const struct locale * lang) -{ - if (u->display && u->display[0]) { - return u->display; - } else if (u->race->describe) { - return u->race->describe(u, lang); - } - return NULL; -} - -const char * -uprivate(const unit * u) -{ - attrib * a = a_find(u->attribs, &at_private); - if (!a) return NULL; - return a->data.v; -} - -void -usetprivate(unit * u, const char * str) -{ - attrib * a = a_find(u->attribs, &at_private); - - if (str == NULL) { - if (a) a_remove(&u->attribs, a); - return; - } - if (!a) a = a_add(&u->attribs, a_new(&at_private)); - if (a->data.v) free(a->data.v); - a->data.v = strdup((const char*)str); -} - -/*********************/ -/* at_potionuser */ -/*********************/ -/* Einheit BENUTZT einen Trank */ -attrib_type at_potionuser = { - "potionuser", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - NO_WRITE, - NO_READ -}; - -void -usetpotionuse(unit * u, const potion_type * ptype) -{ - attrib * a = a_find(u->attribs, &at_potionuser); - if (!a) a = a_add(&u->attribs, a_new(&at_potionuser)); - a->data.v = (void*)ptype; -} - -const potion_type * -ugetpotionuse(const unit * u) { - attrib * a = a_find(u->attribs, &at_potionuser); - if (!a) return NULL; - return (const potion_type *)a->data.v; -} - -/*********************/ -/* at_target */ -/*********************/ -attrib_type at_target = { - "target", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - NO_WRITE, - NO_READ -}; - -unit * -utarget(const unit * u) { - attrib * a; - if (!fval(u, UFL_TARGET)) return NULL; - a = a_find(u->attribs, &at_target); - assert (a || !"flag set, but no target found"); - return (unit*)a->data.v; -} - -void -usettarget(unit * u, const unit * t) -{ - attrib * a = a_find(u->attribs, &at_target); - if (!a && t) a = a_add(&u->attribs, a_new(&at_target)); - if (a) { - if (!t) { - a_remove(&u->attribs, a); - freset(u, UFL_TARGET); - } - else { - a->data.v = (void*)t; - fset(u, UFL_TARGET); - } - } -} - -/*********************/ -/* at_siege */ -/*********************/ - -void -a_writesiege(const attrib * a, const void * owner, struct storage * store) -{ - struct building * b = (struct building*)a->data.v; - write_building_reference(b, store); -} - -int -a_readsiege(attrib * a, void * owner, struct storage * store) -{ - int result = read_reference(&a->data.v, store, read_building_reference, resolve_building); - if (result==0 && !a->data.v) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -attrib_type at_siege = { - "siege", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - a_writesiege, - a_readsiege -}; - -struct building * - usiege(const unit * u) { - attrib * a; - if (!fval(u, UFL_SIEGE)) return NULL; - a = a_find(u->attribs, &at_siege); - assert (a || !"flag set, but no siege found"); - return (struct building *)a->data.v; -} - -void -usetsiege(unit * u, const struct building * t) -{ - attrib * a = a_find(u->attribs, &at_siege); - if (!a && t) a = a_add(&u->attribs, a_new(&at_siege)); - if (a) { - if (!t) { - a_remove(&u->attribs, a); - freset(u, UFL_SIEGE); - } - else { - a->data.v = (void*)t; - fset(u, UFL_SIEGE); - } - } -} - -/*********************/ -/* at_contact */ -/*********************/ -attrib_type at_contact = { - "contact", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - NO_WRITE, - NO_READ -}; - -void -usetcontact(unit * u, const unit * u2) -{ - attrib * a = a_find(u->attribs, &at_contact); - while (a && a->type==&at_contact && a->data.v!=u2) a = a->next; - if (a && a->type==&at_contact) return; - a_add(&u->attribs, a_new(&at_contact))->data.v = (void*)u2; -} - -boolean -ucontact(const unit * u, const unit * u2) -/* Prüft, ob u den Kontaktiere-Befehl zu u2 gesetzt hat. */ -{ - attrib *ru; - if (u->faction==u2->faction) return true; - - /* Explizites KONTAKTIERE */ - for (ru = a_find(u->attribs, &at_contact); ru && ru->type==&at_contact; ru = ru->next) { - if (((unit*)ru->data.v) == u2) { - return true; - } - } - - return false; -} - -/*** -** init & cleanup module -**/ - -void -free_units(void) -{ - while (deleted_units) { - unit * u = deleted_units; - deleted_units = deleted_units->next; - free_unit(u); - free(u); - } -} - - -void -write_unit_reference(const unit * u, struct storage * store) -{ - store->w_id(store, (u && u->region)?u->no:0); -} - -int -resolve_unit(variant id, void * address) -{ - unit * u = NULL; - if (id.i!=0) { - u = findunit(id.i); - if (u==NULL) { - *(unit**)address = NULL; - return -1; - } - } - *(unit**)address = u; - return 0; -} - -variant -read_unit_reference(struct storage * store) -{ - variant var; - var.i = store->r_id(store); - return var; -} - -attrib_type at_stealth = { - "stealth", NULL, NULL, NULL, a_writeint, a_readint -}; - -void -u_seteffstealth(unit * u, int value) -{ - if (skill_enabled[SK_STEALTH]) { - attrib * a = NULL; - if (fval(u, UFL_STEALTH)) { - a = a_find(u->attribs, &at_stealth); - } - if (value<0) { - if (a!=NULL) { - freset(u, UFL_STEALTH); - a_remove(&u->attribs, a); - } - return; - } - if (a==NULL) { - a = a_add(&u->attribs, a_new(&at_stealth)); - fset(u, UFL_STEALTH); - } - a->data.i = value; - } -} - -int -u_geteffstealth(const struct unit * u) -{ - if (skill_enabled[SK_STEALTH]) { - if (fval(u, UFL_STEALTH)) { - attrib * a = a_find(u->attribs, &at_stealth); - if (a!=NULL) return a->data.i; - } - } - return -1; -} - -int -get_level(const unit * u, skill_t id) -{ - if (skill_enabled[id]) { - skill * sv = u->skills; - while (sv != u->skills + u->skill_size) { - if (sv->id == id) { - return sv->level; - } - ++sv; - } - } - return 0; -} - -void -set_level(unit * u, skill_t sk, int value) -{ - skill * sv = u->skills; - - if (!skill_enabled[sk]) return; - - if (value==0) { - remove_skill(u, sk); - return; - } - while (sv != u->skills + u->skill_size) { - if (sv->id == sk) { - sk_set(sv, value); - return; - } - ++sv; - } - sk_set(add_skill(u, sk), value); -} - -static int -leftship_age(struct attrib * a) -{ - /* must be aged, so it doesn't affect report generation (cansee) */ - unused(a); - return AT_AGE_REMOVE; /* remove me */ -} - -static attrib_type at_leftship = { - "leftship", NULL, NULL, leftship_age -}; - -static attrib * -make_leftship(struct ship * leftship) -{ - attrib * a = a_new(&at_leftship); - a->data.v = leftship; - return a; -} - -void -set_leftship(unit *u, ship *sh) -{ - a_add(&u->attribs, make_leftship(sh)); -} - -ship * -leftship(const unit *u) -{ - attrib * a = a_find(u->attribs, &at_leftship); - - /* Achtung: Es ist nicht garantiert, daß der Rückgabewert zu jedem - * Zeitpunkt noch auf ein existierendes Schiff zeigt! */ - - if (a) return (ship *)(a->data.v); - - return NULL; -} - -void -leave_ship(unit * u) -{ - struct ship * sh = u->ship; - if (sh==NULL) return; - u->ship = NULL; - set_leftship(u, sh); - - if (fval(u, UFL_OWNER)) { - unit *u2, *owner = NULL; - freset(u, UFL_OWNER); - - for (u2 = u->region->units; u2; u2 = u2->next) { - if (u2->ship == sh) { - if (u2->faction == u->faction) { - owner = u2; - break; - } - else if (owner==NULL) owner = u2; - } - } - if (owner!=NULL) fset(owner, UFL_OWNER); - } -} - -void -leave_building(unit * u) -{ - struct building * b = u->building; - if (!b) return; - u->building = NULL; - - if (fval(u, UFL_OWNER)) { - unit *u2, *owner = NULL; - freset(u, UFL_OWNER); - - for (u2 = u->region->units; u2; u2 = u2->next) { - if (u2->building == b) { - if (u2->faction == u->faction) { - owner = u2; - break; - } - else if (owner==NULL) owner = u2; - } - } - if (owner!=NULL) { - fset(owner, UFL_OWNER); - } - } -} - -boolean -can_leave(unit * u) -{ - static int rule_leave = -1; - - if (!u->building) { - return true; - } - if (rule_leave<0) { - rule_leave = get_param_int(global.parameters, "rules.move.owner_leave", 0); - } - if (rule_leave && u->building && u==building_owner(u->building)) { - return false; - } - return true; -} - -boolean -leave(unit * u, boolean force) -{ - if (!force) { - if (!can_leave(u)) { - return false; - } - } - if (u->building) leave_building(u); - else if (u->ship) leave_ship(u); - return true; -} - -const struct race * -urace(const struct unit * u) -{ - return u->race; -} - -boolean -can_survive(const unit *u, const region *r) -{ - if ((fval(r->terrain, WALK_INTO) && (u->race->flags & RCF_WALK)) - || (fval(r->terrain, SWIM_INTO) && (u->race->flags & RCF_SWIM)) - || (fval(r->terrain, FLY_INTO) && (u->race->flags & RCF_FLY))) - { - static const curse_type * ctype = NULL; - - if (has_horses(u) && !fval(r->terrain, WALK_INTO)) - return false; - - if (!ctype) ctype = ct_find("holyground"); - if (fval(u->race, RCF_UNDEAD) && curse_active(get_curse(r->attribs, ctype))) - return false; - - return true; - } - return false; -} - -void -move_unit(unit * u, region * r, unit ** ulist) -{ - int maxhp = 0; - assert(u && r); - - assert(u->faction || !"this unit is dead"); - if (u->region == r) return; - if (u->region!=NULL) maxhp = unit_max_hp(u); - if (!ulist) ulist = (&r->units); - if (u->region) { - setguard(u, GUARD_NONE); - fset(u, UFL_MOVED); - if (u->ship || u->building) { - /* can_leave must be checked in travel_i */ -#ifndef NDEBUG - boolean result = leave(u, false); - assert(result); -#else - leave(u, false); -#endif - } - translist(&u->region->units, ulist, u); - } else { - addlist(ulist, u); - } - -#ifdef SMART_INTERVALS - update_interval(u->faction, r); -#endif - u->region = r; - /* keine automatische hp reduzierung bei bewegung */ - /* if (maxhp>0) u->hp = u->hp * unit_max_hp(u) / maxhp; */ -} - -/* ist mist, aber wegen nicht skalierender attribute notwendig: */ -#include "alchemy.h" - -void -transfermen(unit * u, unit * u2, int n) -{ - const attrib * a; - int hp = u->hp; - region * r = u->region; - - if (n==0) return; - assert(n > 0); - /* "hat attackiert"-status wird übergeben */ - - if (u2) { - skill *sv, *sn; - skill_t sk; - ship * sh; - - assert(u2->number+n>0); - - for (sk=0; sk!=MAXSKILLS; ++sk) { - int weeks, level = 0; - - sv = get_skill(u, sk); - sn = get_skill(u2, sk); - - if (sv==NULL && sn==NULL) continue; - if (sn==NULL && u2->number==0) { - /* new unit, easy to solve */ - level = sv->level; - weeks = sv->weeks; - } else { - double dlevel = 0.0; - - if (sv && sv->level) { - dlevel += (sv->level + 1 - sv->weeks/(sv->level+1.0)) * n; - level += sv->level * n; - } - if (sn && sn->level) { - dlevel += (sn->level + 1 - sn->weeks/(sn->level+1.0)) * u2->number; - level += sn->level * u2->number; - } - - dlevel = dlevel / (n + u2->number); - level = level / (n + u2->number); - if (level<=dlevel) { - /* apply the remaining fraction to the number of weeks to go. - * subtract the according number of weeks, getting closer to the - * next level */ - level = (int)dlevel; - weeks = (level+1) - (int)((dlevel - level) * (level+1)); - } else { - /* make it harder to reach the next level. - * weeks+level is the max difficulty, 1 - the fraction between - * level and dlevel applied to the number of weeks between this - * and the previous level is the added difficutly */ - level = (int)dlevel+1; - weeks = 1 + 2 * level - (int)((1 + dlevel - level) * level); - } - } - if (level) { - if (sn==NULL) sn = add_skill(u2, sk); - sn->level = (unsigned char)level; - sn->weeks = (unsigned char)weeks; - assert(sn->weeks>0 && sn->weeks<=sn->level*2+1); - assert(u2->number!=0 || (sn->level==sv->level && sn->weeks==sv->weeks)); - } else if (sn) { - remove_skill(u2, sk); - sn = NULL; - } - } - a = a_find(u->attribs, &at_effect); - while (a && a->type==&at_effect) { - effect_data * olde = (effect_data*)a->data.v; - if (olde->value) change_effect(u2, olde->type, olde->value); - a = a->next; - } - sh = leftship(u); - if (sh!=NULL) set_leftship(u2, sh); - u2->flags |= u->flags&(UFL_LONGACTION|UFL_NOTMOVING|UFL_HUNGER|UFL_MOVED|UFL_ENTER); - if (u->attribs) { - transfer_curse(u, u2, n); - } - } - scale_number(u, u->number - n); - if (u2) { - set_number(u2, u2->number + n); - hp -= u->hp; - u2->hp += hp; - /* TODO: Das ist schnarchlahm! und gehört nicht hierhin */ - a = a_find(u2->attribs, &at_effect); - while (a && a->type==&at_effect) { - attrib * an = a->next; - effect_data * olde = (effect_data*)a->data.v; - int e = get_effect(u, olde->type); - if (e!=0) change_effect(u2, olde->type, -e); - a = an; - } - } - else if (r->land) { - if ((u->race->ec_flags & ECF_REC_ETHEREAL)==0) { - const race * rc = u->race; - if (rc->ec_flags & ECF_REC_HORSES) { /* Zentauren an die Pferde */ - int h = rhorses(r) + n; - rsethorses(r, h); - } else { - int p = rpeasants(r); - p += (int)(n * rc->recruit_multi); - rsetpeasants(r, p); - } - } - } -} - -struct building * - inside_building(const struct unit * u) -{ - if (u->building==NULL) return NULL; - - if (!fval(u->building, BLD_WORKING)) { - /* Unterhalt nicht bezahlt */ - return NULL; - } else if (u->building->size < u->building->type->maxsize) { - /* Gebäude noch nicht fertig */ - return NULL; - } else { - int p = 0, cap = buildingcapacity(u->building); - const unit * u2; - for (u2 = u->region->units; u2; u2 = u2->next) { - if (u2->building == u->building) { - p += u2->number; - if (u2 == u) { - if (p <= cap) return u->building; - return NULL; - } - if (p > cap) return NULL; - } - } - } - return NULL; -} - -void -u_setfaction(unit * u, faction * f) -{ - int cnt = u->number; - - if (u->faction==f) return; - if (u->faction) { - set_number(u, 0); - if (count_unit(u)) --u->faction->no_units; - join_group(u, NULL); - free_orders(&u->orders); - set_order(&u->thisorder, NULL); - - if (u->nextF) u->nextF->prevF = u->prevF; - if (u->prevF) u->prevF->nextF = u->nextF; - else u->faction->units = u->nextF; - } - - if (f!=NULL) { - if (f->units) f->units->prevF=u; - u->prevF = NULL; - u->nextF = f->units; - f->units = u; - } - else u->nextF = NULL; - - u->faction = f; - if (u->region) update_interval(f, u->region); - if (cnt && f) { - set_number(u, cnt); - if (count_unit(u)) ++f->no_units; - } -} - -/* vorsicht Sprüche können u->number == RS_FARVISION haben! */ -void -set_number(unit * u, int count) -{ - assert (count >= 0); - assert (count <= UNIT_MAXSIZE); - -#ifndef NDEBUG - assert(u->faction || count==0); -#endif - - if (count == 0) { - u->flags &= ~(UFL_HERO); - } - if (u->faction) { - if (playerrace(u->race)) { - u->faction->num_people += count - u->number; - } - u->number = (unsigned short)count; - } else if (u->number>0) { - assert(!"why doesn't this unit have a faction? this will fuck up num_people"); - } -} - -boolean -learn_skill(unit * u, skill_t sk, double chance) -{ - skill * sv = u->skills; - if (chance < 1.0 && rng_int()%10000>=chance*10000) return false; - while (sv != u->skills + u->skill_size) { - assert (sv->weeks>0); - if (sv->id == sk) { - if (sv->weeks<=1) { - sk_set(sv, sv->level+1); - } else { - sv->weeks--; - } - return true; - } - ++sv; - } - sv = add_skill(u, sk); - sk_set(sv, 1); - return true; -} - -void -remove_skill(unit *u, skill_t sk) -{ - skill * sv = u->skills; - for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - if (sv->id==sk) { - skill * sl = u->skills + u->skill_size - 1; - if (sl!=sv) { - *sv = *sl; - } - --u->skill_size; - return; - } - } -} - -skill * -add_skill(unit * u, skill_t id) -{ - skill * sv = u->skills; -#ifndef NDEBUG - for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - assert(sv->id != id); - } -#endif - ++u->skill_size; - u->skills = realloc(u->skills, u->skill_size * sizeof(skill)); - sv = (u->skills + u->skill_size - 1); - sv->level = (unsigned char)0; - sv->weeks = (unsigned char)1; - sv->old = (unsigned char)0; - sv->id = (unsigned char)id; - return sv; -} - -skill * -get_skill(const unit * u, skill_t sk) -{ - skill * sv = u->skills; - while (sv!=u->skills+u->skill_size) { - if (sv->id==sk) return sv; - ++sv; - } - return NULL; -} - -boolean -has_skill(const unit * u, skill_t sk) -{ - skill * sv = u->skills; - while (sv!=u->skills+u->skill_size) { - if (sv->id==sk) { - return (sv->level>0); - } - ++sv; - } - return false; -} - -static int -item_modification(const unit *u, skill_t sk, int val) -{ - /* Presseausweis: *2 Spionage, 0 Tarnung */ - if(sk == SK_SPY && get_item(u, I_PRESSCARD) >= u->number) { - val = val * 2; - } else if(sk == SK_STEALTH) { -#if NEWATSROI == 1 - if (get_item(u, I_RING_OF_INVISIBILITY) - + 100 * get_item(u, I_SPHERE_OF_INVISIBILITY) >= u->number) { - val += ROIBONUS; - } -#endif - if(get_item(u, I_PRESSCARD) >= u->number) { - val = 0; - } - } -#if NEWATSROI == 1 - if(sk == SK_PERCEPTION) { - if(get_item(u, I_AMULET_OF_TRUE_SEEING) >= u->number) { - val += ATSBONUS; - } - } -#endif - return val; -} - -static int -att_modification(const unit *u, skill_t sk) -{ - double bonus = 0, malus = 0; - attrib * a; - double result = 0; - static boolean init = false; - static const curse_type * skillmod_ct, * gbdream_ct, * worse_ct; - curse * c; - - if (!init) { - init = true; - skillmod_ct = ct_find("skillmod"); - gbdream_ct = ct_find("gbdream"); - worse_ct = ct_find("worse"); - } - - c = get_curse(u->attribs, worse_ct); - if (c!=NULL) result += curse_geteffect(c); - if (skillmod_ct) { - attrib * a = a_find(u->attribs, &at_curse); - while (a && a->type==&at_curse) { - curse * c = (curse *)a->data.v; - if (c->type==skillmod_ct && c->data.i==sk) { - result += curse_geteffect(c); - break; - } - a = a->next; - } - } - - /* TODO hier kann nicht mit get/iscursed gearbeitet werden, da nur der - * jeweils erste vom Typ C_GBDREAM zurückgegen wird, wir aber alle - * durchsuchen und aufaddieren müssen */ - a = a_find(u->region->attribs, &at_curse); - while (a && a->type==&at_curse) { - curse * c = (curse*)a->data.v; - if (curse_active(c) && c->type==gbdream_ct) { - double mod = curse_geteffect(c); - unit * mage = c->magician; - /* wir suchen jeweils den größten Bonus und den größten Malus */ - if (mod>bonus) { - if (mage==NULL || mage->number==0 || alliedunit(mage, u->faction, HELP_GUARD)) { - bonus = mod; - } - } else if (mod < malus) { - if (mage == NULL || !alliedunit(mage, u->faction, HELP_GUARD)) { - malus = mod; - } - } - } - a = a->next; - } - result = result + bonus + malus; - - return (int)result; -} - -int -get_modifier(const unit *u, skill_t sk, int level, const region *r, boolean noitem) -{ - int bskill = level; - int skill = bskill; - - assert(r); - if (sk == SK_STEALTH) { - plane * pl = rplane(r); - if (pl &&fval(pl, PFL_NOSTEALTH)) return 0; - } - - skill += rc_skillmod(u->race, r, sk); - skill += att_modification(u, sk); - - if (noitem == false) { - skill = item_modification(u, sk, skill); - } - skill = skillmod(u->attribs, u, r, sk, skill, SMF_ALWAYS); - -#ifdef HUNGER_REDUCES_SKILL - if (fval(u, UFL_HUNGER)) { - skill = skill/2; - } -#endif - return skill - bskill; -} - -int -eff_skill(const unit * u, skill_t sk, const region * r) -{ - if (skill_enabled[sk]) { - int level = get_level(u, sk); - if (level>0) { - int mlevel = level + get_modifier(u, sk, level, r, false); - - if (mlevel>0) { - int skillcap = SkillCap(sk); - if (skillcap && mlevel>skillcap) { - return skillcap; - } - return mlevel; - } - } - } - return 0; -} - -int -eff_skill_study(const unit * u, skill_t sk, const region * r) -{ - int level = get_level(u, sk); - if (level>0) { - int mlevel = level + get_modifier(u, sk, level, r, true); - - if (mlevel>0) return mlevel; - } - return 0; -} - -int -invisible(const unit *target, const unit * viewer) -{ -#if NEWATSROI == 1 - return 0; -#else - if (viewer && viewer->faction==target->faction) return 0; - else { - int hidden = get_item(target, I_RING_OF_INVISIBILITY) + 100 * get_item(target, I_SPHERE_OF_INVISIBILITY); - if (hidden) { - hidden = MIN(hidden, target->number); - if (viewer) hidden -= get_item(viewer, I_AMULET_OF_TRUE_SEEING); - } - return hidden; - } -#endif -} - -/** remove the unit from memory. - * this frees all memory that's only accessible through the unit, - * and you should already have called uunhash and removed the unit from the - * region. - */ -void -free_unit(unit * u) -{ - free(u->name); - free(u->display); - free_order(u->thisorder); - free_orders(&u->orders); - if (u->skills) free(u->skills); - while (u->items) { - item * it = u->items->next; - u->items->next = NULL; - i_free(u->items); - u->items = it; - } - while (u->attribs) a_remove (&u->attribs, u->attribs); - while (u->reservations) { - struct reservation *res = u->reservations; - u->reservations = res->next; - free(res); - } -} - - -void -unitlist_clear(struct unit_list **ul) -{ - while (*ul) { - unit_list * rl2 = (*ul)->next; - free(*ul); - *ul = rl2; - } -} - -void -unitlist_insert(struct unit_list **ul, struct unit *u) -{ - unit_list *rl2 = (unit_list*)malloc(sizeof(unit_list)); - - rl2->data = u; - rl2->next = *ul; - - *ul = rl2; -} - - -static void -createunitid(unit *u, int id) -{ - if (id<=0 || id > MAX_UNIT_NR || ufindhash(id) || dfindhash(id) || forbiddenid(id)) - u->no = newunitid(); - else - u->no = id; - uhash(u); -} - -void -name_unit(unit *u) -{ - if (u->race->generate_name) { - const char * gen_name = u->race->generate_name(u); - if (gen_name) { - unit_setname(u, gen_name); - } else { - unit_setname(u, racename(u->faction->locale, u, u->race)); - } - } else { - char name[32]; - snprintf(name, sizeof(name), "%s %s", LOC(u->faction->locale, "unitdefault"), itoa36(u->no)); - unit_setname(u, name); - } -} - -/** creates a new unit. -* -* @param dname: name, set to NULL to get a default. -* @param creator: unit to inherit stealth, group, building, ship, etc. from -*/ -unit * -create_unit(region * r, faction * f, int number, const struct race *urace, int id, const char * dname, unit *creator) -{ - unit * u = calloc(1, sizeof(unit)); - - assert(urace); - assert(f->alive); - u_setfaction(u, f); - - if (f->locale) { - order * deford = default_order(f->locale); - if (deford) { - set_order(&u->thisorder, NULL); - addlist(&u->orders, deford); - } - } - u_seteffstealth(u, -1); - u->race = urace; - u->irace = NULL; - - set_number(u, number); - - /* die nummer der neuen einheit muss vor name_unit generiert werden, - * da der default name immer noch 'Nummer u->no' ist */ - createunitid(u, id); - - /* zuerst in die Region setzen, da zb Drachennamen den Regionsnamen - * enthalten */ - if (r) move_unit(u, r, NULL); - - /* u->race muss bereits gesetzt sein, wird für default-hp gebraucht */ - /* u->region auch */ - u->hp = unit_max_hp(u) * number; - - if (!dname) { - name_unit(u); - } else { - u->name = strdup(dname); - } - if (count_unit(u)) f->no_units++; - - if (creator) { - attrib * a; - - /* erbt Kampfstatus */ - setstatus(u, creator->status); - - /* erbt Gebäude/Schiff*/ - if (creator->region==r) { - u->building = creator->building; - if (creator->ship!=NULL && fval(u->race, RCF_CANSAIL)) { - u->ship = creator->ship; - } - } - - /* Tarnlimit wird vererbt */ - if (fval(creator, UFL_STEALTH)) { - attrib * a = a_find(creator->attribs, &at_stealth); - if (a) { - int stealth = a->data.i; - a = a_add(&u->attribs, a_new(&at_stealth)); - a->data.i = stealth; - } - } - - /* Temps von parteigetarnten Einheiten sind wieder parteigetarnt */ - if (fval(creator, UFL_ANON_FACTION)) { - fset(u, UFL_ANON_FACTION); - } - /* Daemonentarnung */ - set_racename(&u->attribs, get_racename(creator->attribs)); - if (fval(u->race, RCF_SHAPESHIFT) && fval(creator->race, RCF_SHAPESHIFT)) { - u->irace = creator->irace; - } - - /* Gruppen */ - if (creator->faction==f && fval(creator, UFL_GROUP)) { - a = a_find(creator->attribs, &at_group); - if (a) { - group * g = (group*)a->data.v; - set_group(u, g); - } - } - a = a_find(creator->attribs, &at_otherfaction); - if (a) { - a_add(&u->attribs, make_otherfaction(get_otherfaction(a))); - } - - a = a_add(&u->attribs, a_new(&at_creator)); - a->data.v = creator; - } - - return u; -} - -int -maxheroes(const struct faction * f) -{ - int nsize = count_all(f); - if (nsize==0) return 0; - else { - int nmax = (int)(log10(nsize / 50.0) * 20); - return (nmax<0)?0:nmax; - } -} - -int -countheroes(const struct faction * f) -{ - const unit * u = f->units; - int n = 0; - - while (u) { - if (fval(u, UFL_HERO)) n+= u->number; - u = u->nextF; - } -#ifdef DEBUG_MAXHEROES - int m = maxheroes(f); - if (n>m) { - log_warning(("%s has %d of %d heroes\n", factionname(f), n, m)); - } -#endif - return n; -} - -const char * -unit_getname(const unit * u) -{ - return (const char *)u->name; -} - -void -unit_setname(unit * u, const char * name) -{ - free(u->name); - if (name) u->name = strdup(name); - else u->name = NULL; -} - -const char * -unit_getinfo(const unit * u) -{ - return (const char *)u->display; -} - -void -unit_setinfo(unit * u, const char * info) -{ - free(u->display); - if (info) u->display = strdup(info); - else u->display = NULL; -} - -int -unit_getid(const unit * u) -{ - return u->no; -} - -void -unit_setid(unit * u, int id) -{ - unit * nu = findunit(id); - if (nu==NULL) { - uunhash(u); - u->no = id; - uhash(u); - } -} - -int -unit_gethp(const unit * u) -{ - return u->hp; -} - -void -unit_sethp(unit * u, int hp) -{ - u->hp = hp; -} - -status_t -unit_getstatus(const unit * u) -{ - return u->status; -} - -void -unit_setstatus(unit * u, status_t status) -{ - u->status = status; -} - -int -unit_getweight(const unit * u) -{ - return weight(u); -} - -int -unit_getcapacity(const unit * u) -{ - return walkingcapacity(u); -} - -void -unit_addorder(unit * u, order * ord) -{ - order ** ordp = &u->orders; - while (*ordp) ordp = &(*ordp)->next; - *ordp = ord; - u->faction->lastorders = turn; -} - -int -unit_max_hp(const unit * u) -{ - static int rules_stamina = -1; - int h; - double p; - static const curse_type * heal_ct = NULL; - - if (rules_stamina<0) { - rules_stamina = get_param_int(global.parameters, "rules.stamina", STAMINA_AFFECTS_HP); - } - h = u->race->hitpoints; - if (heal_ct==NULL) heal_ct = ct_find("healingzone"); - - if (rules_stamina & 1) { - p = pow(effskill(u, SK_STAMINA) / 2.0, 1.5) * 0.2; - h += (int) (h * p + 0.5); - } - /* der healing curse verändert die maximalen hp */ - if (heal_ct) { - curse *c = get_curse(u->region->attribs, heal_ct); - if (c) { - h = (int) (h * (1.0+(curse_geteffect(c)/100))); - } - } - - return h; -} - -void -scale_number (unit * u, int n) -{ - skill_t sk; - const attrib * a; - int remain; - - if (n == u->number) return; - if (n && u->number>0) { - int full; - remain = ((u->hp%u->number) * (n % u->number)) % u->number; - - full = u->hp/u->number; /* wieviel kriegt jede person mindestens */ - u->hp = full * n + (u->hp-full*u->number) * n / u->number; - assert(u->hp>=0); - if ((rng_int() % u->number) < remain) - ++u->hp; /* Nachkommastellen */ - } else { - remain = 0; - u->hp = 0; - } - if (u->number>0) { - for (a = a_find(u->attribs, &at_effect);a && a->type==&at_effect;a=a->next) { - effect_data * data = (effect_data *)a->data.v; - int snew = data->value / u->number * n; - if (n) { - remain = data->value - snew / n * u->number; - snew += remain * n / u->number; - remain = (remain * n) % u->number; - if ((rng_int() % u->number) < remain) - ++snew; /* Nachkommastellen */ - } - data->value = snew; - } - } - if (u->number==0 || n==0) { - for (sk = 0; sk < MAXSKILLS; sk++) { - remove_skill(u, sk); - } - } - - set_number(u, n); -} - -const struct race * u_irace(const struct unit * u) -{ - if (u->irace && skill_enabled[SK_STEALTH]) { - return u->irace; - } - return u->race; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "unit.h" + +#include "building.h" +#include "faction.h" +#include "group.h" +#include "connection.h" +#include "item.h" +#include "move.h" +#include "order.h" +#include "plane.h" +#include "race.h" +#include "region.h" +#include "save.h" +#include "ship.h" +#include "skill.h" +#include "terrain.h" + +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +#define FIND_FOREIGN_TEMP + +attrib_type at_creator = { + "creator" + /* Rest ist NULL; temporäres, nicht alterndes Attribut */ +}; + +#define UMAXHASH MAXUNITS +static unit * unithash[UMAXHASH]; +static unit * delmarker = (unit*)unithash; /* a funny hack */ + +#define HASH_STATISTICS 1 +#if HASH_STATISTICS +static int hash_requests; +static int hash_misses; +#endif + +void +uhash(unit * u) +{ + int key = HASH1(u->no, UMAXHASH), gk = HASH2(u->no, UMAXHASH); + while (unithash[key]!=NULL && unithash[key]!=delmarker && unithash[key]!=u) { + key = (key + gk) % UMAXHASH; + } + assert(unithash[key]!=u || !"trying to add the same unit twice"); + unithash[key] = u; +} + +void +uunhash(unit * u) +{ + int key = HASH1(u->no, UMAXHASH), gk = HASH2(u->no, UMAXHASH); + while (unithash[key]!=NULL && unithash[key]!=u) { + key = (key + gk) % UMAXHASH; + } + assert(unithash[key]==u || !"trying to remove a unit that is not hashed"); + unithash[key] = delmarker; +} + +unit * +ufindhash(int uid) +{ + assert(uid>=0); +#if HASH_STATISTICS + ++hash_requests; +#endif + if (uid>=0) { + int key = HASH1(uid, UMAXHASH), gk = HASH2(uid, UMAXHASH); + while (unithash[key]!=NULL && (unithash[key]==delmarker || unithash[key]->no!=uid)) { + key = (key + gk) % UMAXHASH; +#if HASH_STATISTICS + ++hash_misses; +#endif + } + return unithash[key]; + } + return NULL; +} + +#define DMAXHASH 7919 +typedef struct dead { + struct dead * nexthash; + faction * f; + int no; +} dead; + +static dead* deadhash[DMAXHASH]; + +static void +dhash(int no, faction * f) +{ + dead * hash = (dead*)calloc(1, sizeof(dead)); + dead * old = deadhash[no % DMAXHASH]; + hash->no = no; + hash->f = f; + deadhash[no % DMAXHASH] = hash; + hash->nexthash = old; +} + +faction * +dfindhash(int no) +{ + dead * old; + + if(no < 0) return 0; + + for (old = deadhash[no % DMAXHASH]; old; old = old->nexthash) { + if (old->no == no) { + return old->f; + } + } + return 0; +} + +typedef struct friend { + struct friend * next; + int number; + faction * faction; + unit * unit; +} friend; + +static friend * +get_friends(const unit * u, int * numfriends) +{ + friend * friends = 0; + faction * f = u->faction; + region * r = u->region; + int number = 0; + unit * u2; + + for (u2=r->units;u2;u2=u2->next) { + if (u2->faction!=f && u2->number>0) { + int allied = 0; + if (get_param_int(global.parameters, "rules.alliances", 0)!=0) { + allied = (f->alliance && f->alliance==u2->faction->alliance); + } + else if (alliedunit(u, u2->faction, HELP_MONEY) && alliedunit(u2, f, HELP_GIVE)) { + allied = 1; + } + if (allied) { + friend * nf, ** fr = &friends; + + /* some units won't take stuff: */ + if (u2->race->ec_flags & GETITEM) { + while (*fr && (*fr)->faction->nofaction->no) fr = &(*fr)->next; + nf = *fr; + if (nf==NULL || nf->faction!=u2->faction) { + nf = malloc(sizeof(friend)); + nf->next = *fr; + nf->faction = u2->faction; + nf->unit = u2; + nf->number = 0; + *fr = nf; + } else if (nf->faction==u2->faction && (u2->race->ec_flags & GIVEITEM)) { + /* we don't like to gift it to units that won't give it back */ + if ((nf->unit->race->ec_flags & GIVEITEM) == 0) { + nf->unit = u2; + } + } + nf->number += u2->number; + number += u2->number; + } + } + } + } + if (numfriends) *numfriends = number; + return friends; +} + +/** give all items to friends or peasants. + * this function returns 0 on success, or 1 if there are items that + * could not be destroyed. + */ +int +gift_items(unit * u, int flags) +{ + region * r = u->region; + item ** itm_p = &u->items; + int retval = 0; + int rule = rule_give(); + + if ((u->faction->flags&FFL_QUIT)==0 || (rule&GIVE_ONDEATH)==0) { + if ((rule&GIVE_ALLITEMS)==0 && (flags&GIFT_FRIENDS)) flags-=GIFT_FRIENDS; + if ((rule&GIVE_PEASANTS)==0 && (flags&GIFT_PEASANTS)) flags-=GIFT_PEASANTS; + if ((rule&GIVE_SELF)==0 && (flags&GIFT_SELF)) flags-=GIFT_SELF; + } + + if (u->items==NULL || fval(u->race, RCF_ILLUSIONARY)) return 0; + if ((u->race->ec_flags & GIVEITEM) == 0) return 0; + + /* at first, I should try giving my crap to my own units in this region */ + if (u->faction && (u->faction->flags&FFL_QUIT)==0 && (flags & GIFT_SELF)) { + unit * u2, * u3 = NULL; + for (u2 = r->units; u2; u2 = u2->next) { + if (u2 != u && u2->faction == u->faction && u2->number>0) { + /* some units won't take stuff: */ + if (u2->race->ec_flags & GETITEM) { + /* we don't like to gift it to units that won't give it back */ + if (u2->race->ec_flags & GIVEITEM) { + i_merge(&u2->items, &u->items); + u->items = NULL; + break; + } else { + u3 = u2; + } + } + } + } + if (u->items && u3) { + /* if nobody else takes it, we give it to a unit that has issues */ + i_merge(&u3->items, &u->items); + u->items = NULL; + } + if (u->items==NULL) return 0; + } + + /* if I have friends, I'll try to give my stuff to them */ + if (u->faction && (flags & GIFT_FRIENDS)) { + int number = 0; + friend * friends = get_friends(u, &number); + + while (friends) { + struct friend * nf = friends; + unit * u2 = nf->unit; + item * itm = u->items; + while (itm!=NULL) { + const item_type * itype = itm->type; + item * itn = itm->next; + int n = itm->number; + n = n * nf->number / number; + if (n>0) { + i_change(&u->items, itype, -n); + i_change(&u2->items, itype, n); + } + itm = itn; + } + number -= nf->number; + friends = nf->next; + free(nf); + } + if (u->items==NULL) return 0; + } + + /* last, but not least, give money and horses to peasants */ + while (*itm_p) { + item * itm = *itm_p; + + if (flags & GIFT_PEASANTS) { + if (!fval(u->region->terrain, SEA_REGION)) { + if (itm->type==olditemtype[I_HORSE]) { + rsethorses(r, rhorses(r) + itm->number); + itm->number = 0; + } else if (itm->type==i_silver) { + rsetmoney(r, rmoney(r) + itm->number); + itm->number = 0; + } + } + } + if (itm->number>0 && (itm->type->flags & ITF_NOTLOST)) { + itm_p = &itm->next; + retval = -1; + } else { + i_remove(itm_p, itm); + i_free(itm); + } + } + return retval; +} + +void +make_zombie(unit * u) +{ + u_setfaction(u, get_monsters()); + scale_number(u, 1); + u->race = new_race[RC_ZOMBIE]; + u->irace = NULL; +} + +/** remove the unit from the list of active units. + * the unit is not actually freed, because there may still be references + * dangling to it (from messages, for example). To free all removed units, + * call free_units(). + * returns 0 on success, or -1 if unit could not be removed. + */ + +static unit * deleted_units = NULL; + +int +remove_unit(unit ** ulist, unit * u) +{ + int result; + + assert(ufindhash(u->no)); + handle_event(u->attribs, "destroy", u); + + result = gift_items(u, GIFT_SELF|GIFT_FRIENDS|GIFT_PEASANTS); + if (result!=0) { + make_zombie(u); + return -1; + } + + if (u->number) set_number(u, 0); + leave(u, true); + u->region = NULL; + + uunhash(u); + if (ulist) { + while (*ulist!=u) { + ulist = &(*ulist)->next; + } + assert(*ulist==u); + *ulist = u->next; + } + + u->next = deleted_units; + deleted_units = u; + dhash(u->no, u->faction); + + u_setfaction(u, NULL); + u->region = NULL; + + return 0; +} + +unit * +findnewunit (const region * r, const faction *f, int n) +{ + unit *u2; + + if (n == 0) + return 0; + + for (u2 = r->units; u2; u2 = u2->next) + if (u2->faction == f && ualias(u2) == n) + return u2; +#ifdef FIND_FOREIGN_TEMP + for (u2 = r->units; u2; u2 = u2->next) + if (ualias(u2) == n) + return u2; +#endif + return 0; +} + +/* ------------------------------------------------------------- */ + + +/*********************/ +/* at_alias */ +/*********************/ +attrib_type at_alias = { + "alias", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +int +ualias(const unit * u) +{ + attrib * a = a_find(u->attribs, &at_alias); + if (!a) return 0; + return a->data.i; +} + +int +a_readprivate(attrib * a, void * owner, struct storage * store) +{ + a->data.v = store->r_str(store); + if (a->data.v) return AT_READ_OK; + return AT_READ_FAIL; +} + +/*********************/ +/* at_private */ +/*********************/ +attrib_type at_private = { + "private", + DEFAULT_INIT, + a_finalizestring, + DEFAULT_AGE, + a_writestring, + a_readprivate +}; + +const char * +u_description(const unit * u, const struct locale * lang) +{ + if (u->display && u->display[0]) { + return u->display; + } else if (u->race->describe) { + return u->race->describe(u, lang); + } + return NULL; +} + +const char * +uprivate(const unit * u) +{ + attrib * a = a_find(u->attribs, &at_private); + if (!a) return NULL; + return a->data.v; +} + +void +usetprivate(unit * u, const char * str) +{ + attrib * a = a_find(u->attribs, &at_private); + + if (str == NULL) { + if (a) a_remove(&u->attribs, a); + return; + } + if (!a) a = a_add(&u->attribs, a_new(&at_private)); + if (a->data.v) free(a->data.v); + a->data.v = strdup((const char*)str); +} + +/*********************/ +/* at_potionuser */ +/*********************/ +/* Einheit BENUTZT einen Trank */ +attrib_type at_potionuser = { + "potionuser", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +void +usetpotionuse(unit * u, const potion_type * ptype) +{ + attrib * a = a_find(u->attribs, &at_potionuser); + if (!a) a = a_add(&u->attribs, a_new(&at_potionuser)); + a->data.v = (void*)ptype; +} + +const potion_type * +ugetpotionuse(const unit * u) { + attrib * a = a_find(u->attribs, &at_potionuser); + if (!a) return NULL; + return (const potion_type *)a->data.v; +} + +/*********************/ +/* at_target */ +/*********************/ +attrib_type at_target = { + "target", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +unit * +utarget(const unit * u) { + attrib * a; + if (!fval(u, UFL_TARGET)) return NULL; + a = a_find(u->attribs, &at_target); + assert (a || !"flag set, but no target found"); + return (unit*)a->data.v; +} + +void +usettarget(unit * u, const unit * t) +{ + attrib * a = a_find(u->attribs, &at_target); + if (!a && t) a = a_add(&u->attribs, a_new(&at_target)); + if (a) { + if (!t) { + a_remove(&u->attribs, a); + freset(u, UFL_TARGET); + } + else { + a->data.v = (void*)t; + fset(u, UFL_TARGET); + } + } +} + +/*********************/ +/* at_siege */ +/*********************/ + +void +a_writesiege(const attrib * a, const void * owner, struct storage * store) +{ + struct building * b = (struct building*)a->data.v; + write_building_reference(b, store); +} + +int +a_readsiege(attrib * a, void * owner, struct storage * store) +{ + int result = read_reference(&a->data.v, store, read_building_reference, resolve_building); + if (result==0 && !a->data.v) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +attrib_type at_siege = { + "siege", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + a_writesiege, + a_readsiege +}; + +struct building * + usiege(const unit * u) { + attrib * a; + if (!fval(u, UFL_SIEGE)) return NULL; + a = a_find(u->attribs, &at_siege); + assert (a || !"flag set, but no siege found"); + return (struct building *)a->data.v; +} + +void +usetsiege(unit * u, const struct building * t) +{ + attrib * a = a_find(u->attribs, &at_siege); + if (!a && t) a = a_add(&u->attribs, a_new(&at_siege)); + if (a) { + if (!t) { + a_remove(&u->attribs, a); + freset(u, UFL_SIEGE); + } + else { + a->data.v = (void*)t; + fset(u, UFL_SIEGE); + } + } +} + +/*********************/ +/* at_contact */ +/*********************/ +attrib_type at_contact = { + "contact", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +void +usetcontact(unit * u, const unit * u2) +{ + attrib * a = a_find(u->attribs, &at_contact); + while (a && a->type==&at_contact && a->data.v!=u2) a = a->next; + if (a && a->type==&at_contact) return; + a_add(&u->attribs, a_new(&at_contact))->data.v = (void*)u2; +} + +boolean +ucontact(const unit * u, const unit * u2) +/* Prüft, ob u den Kontaktiere-Befehl zu u2 gesetzt hat. */ +{ + attrib *ru; + if (u->faction==u2->faction) return true; + + /* Explizites KONTAKTIERE */ + for (ru = a_find(u->attribs, &at_contact); ru && ru->type==&at_contact; ru = ru->next) { + if (((unit*)ru->data.v) == u2) { + return true; + } + } + + return false; +} + +/*** +** init & cleanup module +**/ + +void +free_units(void) +{ + while (deleted_units) { + unit * u = deleted_units; + deleted_units = deleted_units->next; + free_unit(u); + free(u); + } +} + + +void +write_unit_reference(const unit * u, struct storage * store) +{ + store->w_id(store, (u && u->region)?u->no:0); +} + +int +resolve_unit(variant id, void * address) +{ + unit * u = NULL; + if (id.i!=0) { + u = findunit(id.i); + if (u==NULL) { + *(unit**)address = NULL; + return -1; + } + } + *(unit**)address = u; + return 0; +} + +variant +read_unit_reference(struct storage * store) +{ + variant var; + var.i = store->r_id(store); + return var; +} + +attrib_type at_stealth = { + "stealth", NULL, NULL, NULL, a_writeint, a_readint +}; + +void +u_seteffstealth(unit * u, int value) +{ + if (skill_enabled[SK_STEALTH]) { + attrib * a = NULL; + if (fval(u, UFL_STEALTH)) { + a = a_find(u->attribs, &at_stealth); + } + if (value<0) { + if (a!=NULL) { + freset(u, UFL_STEALTH); + a_remove(&u->attribs, a); + } + return; + } + if (a==NULL) { + a = a_add(&u->attribs, a_new(&at_stealth)); + fset(u, UFL_STEALTH); + } + a->data.i = value; + } +} + +int +u_geteffstealth(const struct unit * u) +{ + if (skill_enabled[SK_STEALTH]) { + if (fval(u, UFL_STEALTH)) { + attrib * a = a_find(u->attribs, &at_stealth); + if (a!=NULL) return a->data.i; + } + } + return -1; +} + +int +get_level(const unit * u, skill_t id) +{ + if (skill_enabled[id]) { + skill * sv = u->skills; + while (sv != u->skills + u->skill_size) { + if (sv->id == id) { + return sv->level; + } + ++sv; + } + } + return 0; +} + +void +set_level(unit * u, skill_t sk, int value) +{ + skill * sv = u->skills; + + if (!skill_enabled[sk]) return; + + if (value==0) { + remove_skill(u, sk); + return; + } + while (sv != u->skills + u->skill_size) { + if (sv->id == sk) { + sk_set(sv, value); + return; + } + ++sv; + } + sk_set(add_skill(u, sk), value); +} + +static int +leftship_age(struct attrib * a) +{ + /* must be aged, so it doesn't affect report generation (cansee) */ + unused(a); + return AT_AGE_REMOVE; /* remove me */ +} + +static attrib_type at_leftship = { + "leftship", NULL, NULL, leftship_age +}; + +static attrib * +make_leftship(struct ship * leftship) +{ + attrib * a = a_new(&at_leftship); + a->data.v = leftship; + return a; +} + +void +set_leftship(unit *u, ship *sh) +{ + a_add(&u->attribs, make_leftship(sh)); +} + +ship * +leftship(const unit *u) +{ + attrib * a = a_find(u->attribs, &at_leftship); + + /* Achtung: Es ist nicht garantiert, daß der Rückgabewert zu jedem + * Zeitpunkt noch auf ein existierendes Schiff zeigt! */ + + if (a) return (ship *)(a->data.v); + + return NULL; +} + +void +leave_ship(unit * u) +{ + struct ship * sh = u->ship; + if (sh==NULL) return; + u->ship = NULL; + set_leftship(u, sh); + + if (fval(u, UFL_OWNER)) { + unit *u2, *owner = NULL; + freset(u, UFL_OWNER); + + for (u2 = u->region->units; u2; u2 = u2->next) { + if (u2->ship == sh) { + if (u2->faction == u->faction) { + owner = u2; + break; + } + else if (owner==NULL) owner = u2; + } + } + if (owner!=NULL) fset(owner, UFL_OWNER); + } +} + +void +leave_building(unit * u) +{ + struct building * b = u->building; + if (!b) return; + u->building = NULL; + + if (fval(u, UFL_OWNER)) { + unit *u2, *owner = NULL; + freset(u, UFL_OWNER); + + for (u2 = u->region->units; u2; u2 = u2->next) { + if (u2->building == b) { + if (u2->faction == u->faction) { + owner = u2; + break; + } + else if (owner==NULL) owner = u2; + } + } + if (owner!=NULL) { + fset(owner, UFL_OWNER); + } + } +} + +boolean +can_leave(unit * u) +{ + static int rule_leave = -1; + + if (!u->building) { + return true; + } + if (rule_leave<0) { + rule_leave = get_param_int(global.parameters, "rules.move.owner_leave", 0); + } + if (rule_leave && u->building && u==building_owner(u->building)) { + return false; + } + return true; +} + +boolean +leave(unit * u, boolean force) +{ + if (!force) { + if (!can_leave(u)) { + return false; + } + } + if (u->building) leave_building(u); + else if (u->ship) leave_ship(u); + return true; +} + +const struct race * +urace(const struct unit * u) +{ + return u->race; +} + +boolean +can_survive(const unit *u, const region *r) +{ + if ((fval(r->terrain, WALK_INTO) && (u->race->flags & RCF_WALK)) + || (fval(r->terrain, SWIM_INTO) && (u->race->flags & RCF_SWIM)) + || (fval(r->terrain, FLY_INTO) && (u->race->flags & RCF_FLY))) + { + static const curse_type * ctype = NULL; + + if (has_horses(u) && !fval(r->terrain, WALK_INTO)) + return false; + + if (!ctype) ctype = ct_find("holyground"); + if (fval(u->race, RCF_UNDEAD) && curse_active(get_curse(r->attribs, ctype))) + return false; + + return true; + } + return false; +} + +void +move_unit(unit * u, region * r, unit ** ulist) +{ + int maxhp = 0; + assert(u && r); + + assert(u->faction || !"this unit is dead"); + if (u->region == r) return; + if (u->region!=NULL) maxhp = unit_max_hp(u); + if (!ulist) ulist = (&r->units); + if (u->region) { + setguard(u, GUARD_NONE); + fset(u, UFL_MOVED); + if (u->ship || u->building) { + /* can_leave must be checked in travel_i */ +#ifndef NDEBUG + boolean result = leave(u, false); + assert(result); +#else + leave(u, false); +#endif + } + translist(&u->region->units, ulist, u); + } else { + addlist(ulist, u); + } + +#ifdef SMART_INTERVALS + update_interval(u->faction, r); +#endif + u->region = r; + /* keine automatische hp reduzierung bei bewegung */ + /* if (maxhp>0) u->hp = u->hp * unit_max_hp(u) / maxhp; */ +} + +/* ist mist, aber wegen nicht skalierender attribute notwendig: */ +#include "alchemy.h" + +void +transfermen(unit * u, unit * u2, int n) +{ + const attrib * a; + int hp = u->hp; + region * r = u->region; + + if (n==0) return; + assert(n > 0); + /* "hat attackiert"-status wird übergeben */ + + if (u2) { + skill *sv, *sn; + skill_t sk; + ship * sh; + + assert(u2->number+n>0); + + for (sk=0; sk!=MAXSKILLS; ++sk) { + int weeks, level = 0; + + sv = get_skill(u, sk); + sn = get_skill(u2, sk); + + if (sv==NULL && sn==NULL) continue; + if (sn==NULL && u2->number==0) { + /* new unit, easy to solve */ + level = sv->level; + weeks = sv->weeks; + } else { + double dlevel = 0.0; + + if (sv && sv->level) { + dlevel += (sv->level + 1 - sv->weeks/(sv->level+1.0)) * n; + level += sv->level * n; + } + if (sn && sn->level) { + dlevel += (sn->level + 1 - sn->weeks/(sn->level+1.0)) * u2->number; + level += sn->level * u2->number; + } + + dlevel = dlevel / (n + u2->number); + level = level / (n + u2->number); + if (level<=dlevel) { + /* apply the remaining fraction to the number of weeks to go. + * subtract the according number of weeks, getting closer to the + * next level */ + level = (int)dlevel; + weeks = (level+1) - (int)((dlevel - level) * (level+1)); + } else { + /* make it harder to reach the next level. + * weeks+level is the max difficulty, 1 - the fraction between + * level and dlevel applied to the number of weeks between this + * and the previous level is the added difficutly */ + level = (int)dlevel+1; + weeks = 1 + 2 * level - (int)((1 + dlevel - level) * level); + } + } + if (level) { + if (sn==NULL) sn = add_skill(u2, sk); + sn->level = (unsigned char)level; + sn->weeks = (unsigned char)weeks; + assert(sn->weeks>0 && sn->weeks<=sn->level*2+1); + assert(u2->number!=0 || (sn->level==sv->level && sn->weeks==sv->weeks)); + } else if (sn) { + remove_skill(u2, sk); + sn = NULL; + } + } + a = a_find(u->attribs, &at_effect); + while (a && a->type==&at_effect) { + effect_data * olde = (effect_data*)a->data.v; + if (olde->value) change_effect(u2, olde->type, olde->value); + a = a->next; + } + sh = leftship(u); + if (sh!=NULL) set_leftship(u2, sh); + u2->flags |= u->flags&(UFL_LONGACTION|UFL_NOTMOVING|UFL_HUNGER|UFL_MOVED|UFL_ENTER); + if (u->attribs) { + transfer_curse(u, u2, n); + } + } + scale_number(u, u->number - n); + if (u2) { + set_number(u2, u2->number + n); + hp -= u->hp; + u2->hp += hp; + /* TODO: Das ist schnarchlahm! und gehört nicht hierhin */ + a = a_find(u2->attribs, &at_effect); + while (a && a->type==&at_effect) { + attrib * an = a->next; + effect_data * olde = (effect_data*)a->data.v; + int e = get_effect(u, olde->type); + if (e!=0) change_effect(u2, olde->type, -e); + a = an; + } + } + else if (r->land) { + if ((u->race->ec_flags & ECF_REC_ETHEREAL)==0) { + const race * rc = u->race; + if (rc->ec_flags & ECF_REC_HORSES) { /* Zentauren an die Pferde */ + int h = rhorses(r) + n; + rsethorses(r, h); + } else { + int p = rpeasants(r); + p += (int)(n * rc->recruit_multi); + rsetpeasants(r, p); + } + } + } +} + +struct building * + inside_building(const struct unit * u) +{ + if (u->building==NULL) return NULL; + + if (!fval(u->building, BLD_WORKING)) { + /* Unterhalt nicht bezahlt */ + return NULL; + } else if (u->building->size < u->building->type->maxsize) { + /* Gebäude noch nicht fertig */ + return NULL; + } else { + int p = 0, cap = buildingcapacity(u->building); + const unit * u2; + for (u2 = u->region->units; u2; u2 = u2->next) { + if (u2->building == u->building) { + p += u2->number; + if (u2 == u) { + if (p <= cap) return u->building; + return NULL; + } + if (p > cap) return NULL; + } + } + } + return NULL; +} + +void +u_setfaction(unit * u, faction * f) +{ + int cnt = u->number; + + if (u->faction==f) return; + if (u->faction) { + set_number(u, 0); + if (count_unit(u)) --u->faction->no_units; + join_group(u, NULL); + free_orders(&u->orders); + set_order(&u->thisorder, NULL); + + if (u->nextF) u->nextF->prevF = u->prevF; + if (u->prevF) u->prevF->nextF = u->nextF; + else u->faction->units = u->nextF; + } + + if (f!=NULL) { + if (f->units) f->units->prevF=u; + u->prevF = NULL; + u->nextF = f->units; + f->units = u; + } + else u->nextF = NULL; + + u->faction = f; + if (u->region) update_interval(f, u->region); + if (cnt && f) { + set_number(u, cnt); + if (count_unit(u)) ++f->no_units; + } +} + +/* vorsicht Sprüche können u->number == RS_FARVISION haben! */ +void +set_number(unit * u, int count) +{ + assert (count >= 0); + assert (count <= UNIT_MAXSIZE); + +#ifndef NDEBUG + assert(u->faction || count==0); +#endif + + if (count == 0) { + u->flags &= ~(UFL_HERO); + } + if (u->faction) { + if (playerrace(u->race)) { + u->faction->num_people += count - u->number; + } + u->number = (unsigned short)count; + } else if (u->number>0) { + assert(!"why doesn't this unit have a faction? this will fuck up num_people"); + } +} + +boolean +learn_skill(unit * u, skill_t sk, double chance) +{ + skill * sv = u->skills; + if (chance < 1.0 && rng_int()%10000>=chance*10000) return false; + while (sv != u->skills + u->skill_size) { + assert (sv->weeks>0); + if (sv->id == sk) { + if (sv->weeks<=1) { + sk_set(sv, sv->level+1); + } else { + sv->weeks--; + } + return true; + } + ++sv; + } + sv = add_skill(u, sk); + sk_set(sv, 1); + return true; +} + +void +remove_skill(unit *u, skill_t sk) +{ + skill * sv = u->skills; + for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { + if (sv->id==sk) { + skill * sl = u->skills + u->skill_size - 1; + if (sl!=sv) { + *sv = *sl; + } + --u->skill_size; + return; + } + } +} + +skill * +add_skill(unit * u, skill_t id) +{ + skill * sv = u->skills; +#ifndef NDEBUG + for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { + assert(sv->id != id); + } +#endif + ++u->skill_size; + u->skills = realloc(u->skills, u->skill_size * sizeof(skill)); + sv = (u->skills + u->skill_size - 1); + sv->level = (unsigned char)0; + sv->weeks = (unsigned char)1; + sv->old = (unsigned char)0; + sv->id = (unsigned char)id; + return sv; +} + +skill * +get_skill(const unit * u, skill_t sk) +{ + skill * sv = u->skills; + while (sv!=u->skills+u->skill_size) { + if (sv->id==sk) return sv; + ++sv; + } + return NULL; +} + +boolean +has_skill(const unit * u, skill_t sk) +{ + skill * sv = u->skills; + while (sv!=u->skills+u->skill_size) { + if (sv->id==sk) { + return (sv->level>0); + } + ++sv; + } + return false; +} + +static int +item_modification(const unit *u, skill_t sk, int val) +{ + /* Presseausweis: *2 Spionage, 0 Tarnung */ + if(sk == SK_SPY && get_item(u, I_PRESSCARD) >= u->number) { + val = val * 2; + } else if(sk == SK_STEALTH) { +#if NEWATSROI == 1 + if (get_item(u, I_RING_OF_INVISIBILITY) + + 100 * get_item(u, I_SPHERE_OF_INVISIBILITY) >= u->number) { + val += ROIBONUS; + } +#endif + if(get_item(u, I_PRESSCARD) >= u->number) { + val = 0; + } + } +#if NEWATSROI == 1 + if(sk == SK_PERCEPTION) { + if(get_item(u, I_AMULET_OF_TRUE_SEEING) >= u->number) { + val += ATSBONUS; + } + } +#endif + return val; +} + +static int +att_modification(const unit *u, skill_t sk) +{ + double bonus = 0, malus = 0; + attrib * a; + double result = 0; + static boolean init = false; + static const curse_type * skillmod_ct, * gbdream_ct, * worse_ct; + curse * c; + + if (!init) { + init = true; + skillmod_ct = ct_find("skillmod"); + gbdream_ct = ct_find("gbdream"); + worse_ct = ct_find("worse"); + } + + c = get_curse(u->attribs, worse_ct); + if (c!=NULL) result += curse_geteffect(c); + if (skillmod_ct) { + attrib * a = a_find(u->attribs, &at_curse); + while (a && a->type==&at_curse) { + curse * c = (curse *)a->data.v; + if (c->type==skillmod_ct && c->data.i==sk) { + result += curse_geteffect(c); + break; + } + a = a->next; + } + } + + /* TODO hier kann nicht mit get/iscursed gearbeitet werden, da nur der + * jeweils erste vom Typ C_GBDREAM zurückgegen wird, wir aber alle + * durchsuchen und aufaddieren müssen */ + a = a_find(u->region->attribs, &at_curse); + while (a && a->type==&at_curse) { + curse * c = (curse*)a->data.v; + if (curse_active(c) && c->type==gbdream_ct) { + double mod = curse_geteffect(c); + unit * mage = c->magician; + /* wir suchen jeweils den größten Bonus und den größten Malus */ + if (mod>bonus) { + if (mage==NULL || mage->number==0 || alliedunit(mage, u->faction, HELP_GUARD)) { + bonus = mod; + } + } else if (mod < malus) { + if (mage == NULL || !alliedunit(mage, u->faction, HELP_GUARD)) { + malus = mod; + } + } + } + a = a->next; + } + result = result + bonus + malus; + + return (int)result; +} + +int +get_modifier(const unit *u, skill_t sk, int level, const region *r, boolean noitem) +{ + int bskill = level; + int skill = bskill; + + assert(r); + if (sk == SK_STEALTH) { + plane * pl = rplane(r); + if (pl &&fval(pl, PFL_NOSTEALTH)) return 0; + } + + skill += rc_skillmod(u->race, r, sk); + skill += att_modification(u, sk); + + if (noitem == false) { + skill = item_modification(u, sk, skill); + } + skill = skillmod(u->attribs, u, r, sk, skill, SMF_ALWAYS); + +#ifdef HUNGER_REDUCES_SKILL + if (fval(u, UFL_HUNGER)) { + skill = skill/2; + } +#endif + return skill - bskill; +} + +int +eff_skill(const unit * u, skill_t sk, const region * r) +{ + if (skill_enabled[sk]) { + int level = get_level(u, sk); + if (level>0) { + int mlevel = level + get_modifier(u, sk, level, r, false); + + if (mlevel>0) { + int skillcap = SkillCap(sk); + if (skillcap && mlevel>skillcap) { + return skillcap; + } + return mlevel; + } + } + } + return 0; +} + +int +eff_skill_study(const unit * u, skill_t sk, const region * r) +{ + int level = get_level(u, sk); + if (level>0) { + int mlevel = level + get_modifier(u, sk, level, r, true); + + if (mlevel>0) return mlevel; + } + return 0; +} + +int +invisible(const unit *target, const unit * viewer) +{ +#if NEWATSROI == 1 + return 0; +#else + if (viewer && viewer->faction==target->faction) return 0; + else { + int hidden = get_item(target, I_RING_OF_INVISIBILITY) + 100 * get_item(target, I_SPHERE_OF_INVISIBILITY); + if (hidden) { + hidden = MIN(hidden, target->number); + if (viewer) hidden -= get_item(viewer, I_AMULET_OF_TRUE_SEEING); + } + return hidden; + } +#endif +} + +/** remove the unit from memory. + * this frees all memory that's only accessible through the unit, + * and you should already have called uunhash and removed the unit from the + * region. + */ +void +free_unit(unit * u) +{ + free(u->name); + free(u->display); + free_order(u->thisorder); + free_orders(&u->orders); + if (u->skills) free(u->skills); + while (u->items) { + item * it = u->items->next; + u->items->next = NULL; + i_free(u->items); + u->items = it; + } + while (u->attribs) a_remove (&u->attribs, u->attribs); + while (u->reservations) { + struct reservation *res = u->reservations; + u->reservations = res->next; + free(res); + } +} + + +void +unitlist_clear(struct unit_list **ul) +{ + while (*ul) { + unit_list * rl2 = (*ul)->next; + free(*ul); + *ul = rl2; + } +} + +void +unitlist_insert(struct unit_list **ul, struct unit *u) +{ + unit_list *rl2 = (unit_list*)malloc(sizeof(unit_list)); + + rl2->data = u; + rl2->next = *ul; + + *ul = rl2; +} + + +static void +createunitid(unit *u, int id) +{ + if (id<=0 || id > MAX_UNIT_NR || ufindhash(id) || dfindhash(id) || forbiddenid(id)) + u->no = newunitid(); + else + u->no = id; + uhash(u); +} + +void +name_unit(unit *u) +{ + if (u->race->generate_name) { + const char * gen_name = u->race->generate_name(u); + if (gen_name) { + unit_setname(u, gen_name); + } else { + unit_setname(u, racename(u->faction->locale, u, u->race)); + } + } else { + char name[32]; + snprintf(name, sizeof(name), "%s %s", LOC(u->faction->locale, "unitdefault"), itoa36(u->no)); + unit_setname(u, name); + } +} + +/** creates a new unit. +* +* @param dname: name, set to NULL to get a default. +* @param creator: unit to inherit stealth, group, building, ship, etc. from +*/ +unit * +create_unit(region * r, faction * f, int number, const struct race *urace, int id, const char * dname, unit *creator) +{ + unit * u = calloc(1, sizeof(unit)); + + assert(urace); + assert(f->alive); + u_setfaction(u, f); + + if (f->locale) { + order * deford = default_order(f->locale); + if (deford) { + set_order(&u->thisorder, NULL); + addlist(&u->orders, deford); + } + } + u_seteffstealth(u, -1); + u->race = urace; + u->irace = NULL; + + set_number(u, number); + + /* die nummer der neuen einheit muss vor name_unit generiert werden, + * da der default name immer noch 'Nummer u->no' ist */ + createunitid(u, id); + + /* zuerst in die Region setzen, da zb Drachennamen den Regionsnamen + * enthalten */ + if (r) move_unit(u, r, NULL); + + /* u->race muss bereits gesetzt sein, wird für default-hp gebraucht */ + /* u->region auch */ + u->hp = unit_max_hp(u) * number; + + if (!dname) { + name_unit(u); + } else { + u->name = strdup(dname); + } + if (count_unit(u)) f->no_units++; + + if (creator) { + attrib * a; + + /* erbt Kampfstatus */ + setstatus(u, creator->status); + + /* erbt Gebäude/Schiff*/ + if (creator->region==r) { + u->building = creator->building; + if (creator->ship!=NULL && fval(u->race, RCF_CANSAIL)) { + u->ship = creator->ship; + } + } + + /* Tarnlimit wird vererbt */ + if (fval(creator, UFL_STEALTH)) { + attrib * a = a_find(creator->attribs, &at_stealth); + if (a) { + int stealth = a->data.i; + a = a_add(&u->attribs, a_new(&at_stealth)); + a->data.i = stealth; + } + } + + /* Temps von parteigetarnten Einheiten sind wieder parteigetarnt */ + if (fval(creator, UFL_ANON_FACTION)) { + fset(u, UFL_ANON_FACTION); + } + /* Daemonentarnung */ + set_racename(&u->attribs, get_racename(creator->attribs)); + if (fval(u->race, RCF_SHAPESHIFT) && fval(creator->race, RCF_SHAPESHIFT)) { + u->irace = creator->irace; + } + + /* Gruppen */ + if (creator->faction==f && fval(creator, UFL_GROUP)) { + a = a_find(creator->attribs, &at_group); + if (a) { + group * g = (group*)a->data.v; + set_group(u, g); + } + } + a = a_find(creator->attribs, &at_otherfaction); + if (a) { + a_add(&u->attribs, make_otherfaction(get_otherfaction(a))); + } + + a = a_add(&u->attribs, a_new(&at_creator)); + a->data.v = creator; + } + + return u; +} + +int +maxheroes(const struct faction * f) +{ + int nsize = count_all(f); + if (nsize==0) return 0; + else { + int nmax = (int)(log10(nsize / 50.0) * 20); + return (nmax<0)?0:nmax; + } +} + +int +countheroes(const struct faction * f) +{ + const unit * u = f->units; + int n = 0; + + while (u) { + if (fval(u, UFL_HERO)) n+= u->number; + u = u->nextF; + } +#ifdef DEBUG_MAXHEROES + int m = maxheroes(f); + if (n>m) { + log_warning(("%s has %d of %d heroes\n", factionname(f), n, m)); + } +#endif + return n; +} + +const char * +unit_getname(const unit * u) +{ + return (const char *)u->name; +} + +void +unit_setname(unit * u, const char * name) +{ + free(u->name); + if (name) u->name = strdup(name); + else u->name = NULL; +} + +const char * +unit_getinfo(const unit * u) +{ + return (const char *)u->display; +} + +void +unit_setinfo(unit * u, const char * info) +{ + free(u->display); + if (info) u->display = strdup(info); + else u->display = NULL; +} + +int +unit_getid(const unit * u) +{ + return u->no; +} + +void +unit_setid(unit * u, int id) +{ + unit * nu = findunit(id); + if (nu==NULL) { + uunhash(u); + u->no = id; + uhash(u); + } +} + +int +unit_gethp(const unit * u) +{ + return u->hp; +} + +void +unit_sethp(unit * u, int hp) +{ + u->hp = hp; +} + +status_t +unit_getstatus(const unit * u) +{ + return u->status; +} + +void +unit_setstatus(unit * u, status_t status) +{ + u->status = status; +} + +int +unit_getweight(const unit * u) +{ + return weight(u); +} + +int +unit_getcapacity(const unit * u) +{ + return walkingcapacity(u); +} + +void +unit_addorder(unit * u, order * ord) +{ + order ** ordp = &u->orders; + while (*ordp) ordp = &(*ordp)->next; + *ordp = ord; + u->faction->lastorders = turn; +} + +int +unit_max_hp(const unit * u) +{ + static int rules_stamina = -1; + int h; + double p; + static const curse_type * heal_ct = NULL; + + if (rules_stamina<0) { + rules_stamina = get_param_int(global.parameters, "rules.stamina", STAMINA_AFFECTS_HP); + } + h = u->race->hitpoints; + if (heal_ct==NULL) heal_ct = ct_find("healingzone"); + + if (rules_stamina & 1) { + p = pow(effskill(u, SK_STAMINA) / 2.0, 1.5) * 0.2; + h += (int) (h * p + 0.5); + } + /* der healing curse verändert die maximalen hp */ + if (heal_ct) { + curse *c = get_curse(u->region->attribs, heal_ct); + if (c) { + h = (int) (h * (1.0+(curse_geteffect(c)/100))); + } + } + + return h; +} + +void +scale_number (unit * u, int n) +{ + skill_t sk; + const attrib * a; + int remain; + + if (n == u->number) return; + if (n && u->number>0) { + int full; + remain = ((u->hp%u->number) * (n % u->number)) % u->number; + + full = u->hp/u->number; /* wieviel kriegt jede person mindestens */ + u->hp = full * n + (u->hp-full*u->number) * n / u->number; + assert(u->hp>=0); + if ((rng_int() % u->number) < remain) + ++u->hp; /* Nachkommastellen */ + } else { + remain = 0; + u->hp = 0; + } + if (u->number>0) { + for (a = a_find(u->attribs, &at_effect);a && a->type==&at_effect;a=a->next) { + effect_data * data = (effect_data *)a->data.v; + int snew = data->value / u->number * n; + if (n) { + remain = data->value - snew / n * u->number; + snew += remain * n / u->number; + remain = (remain * n) % u->number; + if ((rng_int() % u->number) < remain) + ++snew; /* Nachkommastellen */ + } + data->value = snew; + } + } + if (u->number==0 || n==0) { + for (sk = 0; sk < MAXSKILLS; sk++) { + remove_skill(u, sk); + } + } + + set_number(u, n); +} + +const struct race * u_irace(const struct unit * u) +{ + if (u->irace && skill_enabled[SK_STEALTH]) { + return u->irace; + } + return u->race; +} diff --git a/src/kernel/unit.h b/src/kernel/unit.h index 86af46741..c6068bb3b 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -1,237 +1,237 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_UNIT_H -#define H_KRNL_UNIT_H - -#include -#include "types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct skill; -struct item; -#define UFL_DEBUG (1<<0) -#define UFL_ISNEW (1<<1) /* 2 */ -#define UFL_LONGACTION (1<<2) /* 4 */ -#define UFL_OWNER (1<<3) /* 8 */ -#define UFL_ANON_FACTION (1<<4) /* 16 */ -#define UFL_DISBELIEVES (1<<5) /* 32 */ -#define UFL_WARMTH (1<<6) /* 64 */ -#define UFL_HERO (1<<7) -#define UFL_MOVED (1<<8) -#define UFL_NOTMOVING (1<<9) /* Die Einheit kann sich wg. langen Kampfes nicht bewegen */ -#define UFL_DEFENDER (1<<10) -#define UFL_HUNGER (1<<11) /* kann im Folgemonat keinen langen Befehl außer ARBEITE ausführen */ -#define UFL_SIEGE (1<<12) /* speedup: belagert eine burg, siehe attribut */ -#define UFL_TARGET (1<<13) /* speedup: hat ein target, siehe attribut */ -#define UFL_WERE (1<<14) -#define UFL_ENTER (1<<15) /* unit has entered a ship/building and will not leave it */ - -/* warning: von 512/1024 gewechslet, wegen konflikt mit NEW_FOLLOW */ -#define UFL_LOCKED (1<<16) /* Einheit kann keine Personen aufnehmen oder weggeben, nicht rekrutieren. */ -#define UFL_FLEEING (1<<17) /* unit was in a battle, fleeing. */ -#define UFL_STORM (1<<19) /* Kapitän war in einem Sturm */ -#define UFL_FOLLOWING (1<<20) -#define UFL_FOLLOWED (1<<21) - -#define UFL_NOAID (1<<22) /* Einheit hat Noaid-Status */ -#define UFL_MARK (1<<23) /* same as FL_MARK */ -#define UFL_ORDERS (1<<24) /* Einheit hat Befehle erhalten */ -#define UFL_TAKEALL (1<<25) /* Einheit nimmt alle Gegenstände an */ - -/* flags that speed up attribute access: */ -#define UFL_STEALTH (1<<26) -#define UFL_GUARD (1<<27) -#define UFL_GROUP (1<<28) - -/* Flags, die gespeichert werden sollen: */ -#define UFL_SAVEMASK (UFL_DEFENDER|UFL_MOVED|UFL_NOAID|UFL_OWNER|UFL_ANON_FACTION|UFL_LOCKED|UFL_HUNGER|UFL_TAKEALL|UFL_GUARD|UFL_STEALTH|UFL_GROUP|UFL_HERO) - -#define UNIT_MAXSIZE 50000 -extern int maxheroes(const struct faction * f); -extern int countheroes(const struct faction * f); - -typedef struct unit { - struct unit *next; /* needs to be first entry, for region's unitlist */ - struct unit *nextF; /* nächste Einheit der Partei */ - struct unit *prevF; /* vorherige Einheit der Partei */ - struct region *region; - int no; - int hp; - char *name; - char *display; - struct faction *faction; - struct building *building; - struct ship *ship; - unsigned short number; - short age; - - /* skill data */ - short skill_size; - struct skill *skills; - struct item * items; - struct reservation { - struct reservation * next; - const struct resource_type * type; - int value; - } * reservations; - - /* orders */ - struct order * orders; - struct order * thisorder; - struct order * old_orders; - - /* race and illusionary race */ - const struct race * race; - const struct race * irace; - - unsigned int flags; - struct attrib * attribs; - status_t status; - int n; /* enno: attribut? */ - int wants; /* enno: attribut? */ -} unit; - -typedef struct unit_list { - struct unit_list * next; - struct unit * data; -} unit_list; - -extern void unitlist_clear(struct unit_list **ul); -extern void unitlist_insert(struct unit_list **ul, struct unit *u); - -extern struct attrib_type at_alias; -extern struct attrib_type at_siege; -extern struct attrib_type at_target; -extern struct attrib_type at_potionuser; -extern struct attrib_type at_contact; -extern struct attrib_type at_effect; -extern struct attrib_type at_private; -extern struct attrib_type at_showskchange; - -int ualias(const struct unit * u); - -extern struct attrib_type at_stealth; - -void u_seteffstealth(struct unit * u, int value); -int u_geteffstealth(const struct unit * u); -const struct race * u_irace(const struct unit * u); -struct building * usiege(const struct unit * u); -void usetsiege(struct unit * u, const struct building * b); - -struct unit * utarget(const struct unit * u); -void usettarget(struct unit * u, const struct unit * b); - -struct unit * utarget(const struct unit * u); -void usettarget(struct unit * u, const struct unit * b); - -extern const struct race * urace(const struct unit * u); - -const char * uprivate(const struct unit * u); -void usetprivate(struct unit * u, const char * c); - -const struct potion_type * ugetpotionuse(const struct unit * u); /* benutzt u einein trank? */ -void usetpotionuse(struct unit * u, const struct potion_type * p); /* u benutzt trank p (es darf halt nur einer pro runde) */ - -boolean ucontact(const struct unit * u, const struct unit * u2); -void usetcontact(struct unit * u, const struct unit * c); - -struct unit * findnewunit (const struct region * r, const struct faction *f, int alias); - -extern const char * u_description(const unit * u, const struct locale * lang); -extern struct skill * add_skill(struct unit * u, skill_t id); -extern void remove_skill(struct unit *u, skill_t sk); -extern struct skill * get_skill(const struct unit * u, skill_t id); -extern boolean has_skill(const unit* u, skill_t sk); - -extern void set_level(struct unit * u, skill_t id, int level); -extern int get_level(const struct unit * u, skill_t id); -extern void transfermen(struct unit * u, struct unit * u2, int n); - -extern int eff_skill(const struct unit * u, skill_t sk, const struct region * r); -extern int eff_skill_study(const struct unit * u, skill_t sk, const struct region * r); - -extern int get_modifier(const struct unit * u, skill_t sk, int lvl, const struct region * r, boolean noitem); -extern int remove_unit(struct unit ** ulist, struct unit * u); - -#define GIFT_SELF 1<<0 -#define GIFT_FRIENDS 1<<1 -#define GIFT_PEASANTS 1<<2 -int gift_items(struct unit * u, int flags); -void make_zombie(unit * u); - -/* see resolve.h */ -extern int resolve_unit(variant data, void * address); -extern void write_unit_reference(const struct unit * u, struct storage * store); -extern variant read_unit_reference(struct storage * store); - -extern boolean leave(struct unit * u, boolean force); -extern boolean can_leave(struct unit * u); - -extern void leave_ship(unit * u); -extern void leave_building(unit * u); - -extern void set_leftship(struct unit *u, struct ship *sh); -extern struct ship * leftship(const struct unit *); -extern boolean can_survive(const struct unit *u, const struct region *r); -extern void move_unit(struct unit * u, struct region * target, struct unit ** ulist); - -extern struct building * inside_building(const struct unit * u); - -/* cleanup code for this module */ -extern void free_units(void); -extern struct faction * dfindhash(int no); -extern void u_setfaction(struct unit * u, struct faction * f); -extern void set_number(struct unit * u, int count); - -extern boolean learn_skill(struct unit * u, skill_t sk, double chance); - -extern int invisible(const struct unit *target, const struct unit * viewer); -extern void free_unit(struct unit * u); - -extern void name_unit(struct unit *u); -extern struct unit * create_unit(struct region * r1, struct faction * f, int number, const struct race * rc, int id, const char * dname, struct unit *creator); - -extern void uhash(struct unit * u); -extern void uunhash(struct unit * u); -extern struct unit *ufindhash(int i); - -const char * unit_getname(const struct unit * u); -void unit_setname(struct unit * u, const char * name); -const char * unit_getinfo(const struct unit * u); -void unit_setinfo(struct unit * u, const char * name); -int unit_getid(const unit * u); -void unit_setid(unit * u, int id); -int unit_gethp(const unit * u); -void unit_sethp(unit * u, int id); -status_t unit_getstatus(const unit * u); -void unit_setstatus(unit * u, status_t status); -int unit_getweight(const unit * u); -int unit_getcapacity(const unit * u); -void unit_addorder(unit * u, struct order * ord); -int unit_max_hp(const struct unit * u); -void scale_number(struct unit * u, int n); - -extern struct attrib_type at_creator; -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_UNIT_H +#define H_KRNL_UNIT_H + +#include +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct skill; +struct item; +#define UFL_DEBUG (1<<0) +#define UFL_ISNEW (1<<1) /* 2 */ +#define UFL_LONGACTION (1<<2) /* 4 */ +#define UFL_OWNER (1<<3) /* 8 */ +#define UFL_ANON_FACTION (1<<4) /* 16 */ +#define UFL_DISBELIEVES (1<<5) /* 32 */ +#define UFL_WARMTH (1<<6) /* 64 */ +#define UFL_HERO (1<<7) +#define UFL_MOVED (1<<8) +#define UFL_NOTMOVING (1<<9) /* Die Einheit kann sich wg. langen Kampfes nicht bewegen */ +#define UFL_DEFENDER (1<<10) +#define UFL_HUNGER (1<<11) /* kann im Folgemonat keinen langen Befehl außer ARBEITE ausführen */ +#define UFL_SIEGE (1<<12) /* speedup: belagert eine burg, siehe attribut */ +#define UFL_TARGET (1<<13) /* speedup: hat ein target, siehe attribut */ +#define UFL_WERE (1<<14) +#define UFL_ENTER (1<<15) /* unit has entered a ship/building and will not leave it */ + +/* warning: von 512/1024 gewechslet, wegen konflikt mit NEW_FOLLOW */ +#define UFL_LOCKED (1<<16) /* Einheit kann keine Personen aufnehmen oder weggeben, nicht rekrutieren. */ +#define UFL_FLEEING (1<<17) /* unit was in a battle, fleeing. */ +#define UFL_STORM (1<<19) /* Kapitän war in einem Sturm */ +#define UFL_FOLLOWING (1<<20) +#define UFL_FOLLOWED (1<<21) + +#define UFL_NOAID (1<<22) /* Einheit hat Noaid-Status */ +#define UFL_MARK (1<<23) /* same as FL_MARK */ +#define UFL_ORDERS (1<<24) /* Einheit hat Befehle erhalten */ +#define UFL_TAKEALL (1<<25) /* Einheit nimmt alle Gegenstände an */ + +/* flags that speed up attribute access: */ +#define UFL_STEALTH (1<<26) +#define UFL_GUARD (1<<27) +#define UFL_GROUP (1<<28) + +/* Flags, die gespeichert werden sollen: */ +#define UFL_SAVEMASK (UFL_DEFENDER|UFL_MOVED|UFL_NOAID|UFL_OWNER|UFL_ANON_FACTION|UFL_LOCKED|UFL_HUNGER|UFL_TAKEALL|UFL_GUARD|UFL_STEALTH|UFL_GROUP|UFL_HERO) + +#define UNIT_MAXSIZE 50000 +extern int maxheroes(const struct faction * f); +extern int countheroes(const struct faction * f); + +typedef struct unit { + struct unit *next; /* needs to be first entry, for region's unitlist */ + struct unit *nextF; /* nächste Einheit der Partei */ + struct unit *prevF; /* vorherige Einheit der Partei */ + struct region *region; + int no; + int hp; + char *name; + char *display; + struct faction *faction; + struct building *building; + struct ship *ship; + unsigned short number; + short age; + + /* skill data */ + short skill_size; + struct skill *skills; + struct item * items; + struct reservation { + struct reservation * next; + const struct resource_type * type; + int value; + } * reservations; + + /* orders */ + struct order * orders; + struct order * thisorder; + struct order * old_orders; + + /* race and illusionary race */ + const struct race * race; + const struct race * irace; + + unsigned int flags; + struct attrib * attribs; + status_t status; + int n; /* enno: attribut? */ + int wants; /* enno: attribut? */ +} unit; + +typedef struct unit_list { + struct unit_list * next; + struct unit * data; +} unit_list; + +extern void unitlist_clear(struct unit_list **ul); +extern void unitlist_insert(struct unit_list **ul, struct unit *u); + +extern struct attrib_type at_alias; +extern struct attrib_type at_siege; +extern struct attrib_type at_target; +extern struct attrib_type at_potionuser; +extern struct attrib_type at_contact; +extern struct attrib_type at_effect; +extern struct attrib_type at_private; +extern struct attrib_type at_showskchange; + +int ualias(const struct unit * u); + +extern struct attrib_type at_stealth; + +void u_seteffstealth(struct unit * u, int value); +int u_geteffstealth(const struct unit * u); +const struct race * u_irace(const struct unit * u); +struct building * usiege(const struct unit * u); +void usetsiege(struct unit * u, const struct building * b); + +struct unit * utarget(const struct unit * u); +void usettarget(struct unit * u, const struct unit * b); + +struct unit * utarget(const struct unit * u); +void usettarget(struct unit * u, const struct unit * b); + +extern const struct race * urace(const struct unit * u); + +const char * uprivate(const struct unit * u); +void usetprivate(struct unit * u, const char * c); + +const struct potion_type * ugetpotionuse(const struct unit * u); /* benutzt u einein trank? */ +void usetpotionuse(struct unit * u, const struct potion_type * p); /* u benutzt trank p (es darf halt nur einer pro runde) */ + +boolean ucontact(const struct unit * u, const struct unit * u2); +void usetcontact(struct unit * u, const struct unit * c); + +struct unit * findnewunit (const struct region * r, const struct faction *f, int alias); + +extern const char * u_description(const unit * u, const struct locale * lang); +extern struct skill * add_skill(struct unit * u, skill_t id); +extern void remove_skill(struct unit *u, skill_t sk); +extern struct skill * get_skill(const struct unit * u, skill_t id); +extern boolean has_skill(const unit* u, skill_t sk); + +extern void set_level(struct unit * u, skill_t id, int level); +extern int get_level(const struct unit * u, skill_t id); +extern void transfermen(struct unit * u, struct unit * u2, int n); + +extern int eff_skill(const struct unit * u, skill_t sk, const struct region * r); +extern int eff_skill_study(const struct unit * u, skill_t sk, const struct region * r); + +extern int get_modifier(const struct unit * u, skill_t sk, int lvl, const struct region * r, boolean noitem); +extern int remove_unit(struct unit ** ulist, struct unit * u); + +#define GIFT_SELF 1<<0 +#define GIFT_FRIENDS 1<<1 +#define GIFT_PEASANTS 1<<2 +int gift_items(struct unit * u, int flags); +void make_zombie(unit * u); + +/* see resolve.h */ +extern int resolve_unit(variant data, void * address); +extern void write_unit_reference(const struct unit * u, struct storage * store); +extern variant read_unit_reference(struct storage * store); + +extern boolean leave(struct unit * u, boolean force); +extern boolean can_leave(struct unit * u); + +extern void leave_ship(unit * u); +extern void leave_building(unit * u); + +extern void set_leftship(struct unit *u, struct ship *sh); +extern struct ship * leftship(const struct unit *); +extern boolean can_survive(const struct unit *u, const struct region *r); +extern void move_unit(struct unit * u, struct region * target, struct unit ** ulist); + +extern struct building * inside_building(const struct unit * u); + +/* cleanup code for this module */ +extern void free_units(void); +extern struct faction * dfindhash(int no); +extern void u_setfaction(struct unit * u, struct faction * f); +extern void set_number(struct unit * u, int count); + +extern boolean learn_skill(struct unit * u, skill_t sk, double chance); + +extern int invisible(const struct unit *target, const struct unit * viewer); +extern void free_unit(struct unit * u); + +extern void name_unit(struct unit *u); +extern struct unit * create_unit(struct region * r1, struct faction * f, int number, const struct race * rc, int id, const char * dname, struct unit *creator); + +extern void uhash(struct unit * u); +extern void uunhash(struct unit * u); +extern struct unit *ufindhash(int i); + +const char * unit_getname(const struct unit * u); +void unit_setname(struct unit * u, const char * name); +const char * unit_getinfo(const struct unit * u); +void unit_setinfo(struct unit * u, const char * name); +int unit_getid(const unit * u); +void unit_setid(unit * u, int id); +int unit_gethp(const unit * u); +void unit_sethp(unit * u, int id); +status_t unit_getstatus(const unit * u); +void unit_setstatus(unit * u, status_t status); +int unit_getweight(const unit * u); +int unit_getcapacity(const unit * u); +void unit_addorder(unit * u, struct order * ord); +int unit_max_hp(const struct unit * u); +void scale_number(struct unit * u, int n); + +extern struct attrib_type at_creator; +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/version.h b/src/kernel/version.h index a07ea3e52..745a30a5e 100644 --- a/src/kernel/version.h +++ b/src/kernel/version.h @@ -1,71 +1,71 @@ -/* vi: set ts=2: - +-------------------+ - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2007 | Christian Schlittchen - | | - +-------------------+ - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - - */ - -/* changes from->to: 72->73: struct unit::lock entfernt. - * 73->74: struct unit::flags eingeführt. - * 74->75: parteitarnung als flag. - * 75->76: #ifdef NEW_HP: hp - * 76->77: ship->damage - * 77->78: neue Message-Option "Orkvermehrung" (MAX_MSG +1) - * 78->79: showdata nicht mehr speichern - * 79->HEX_VERSION: hex - * 80->82: ATTRIB_VERSION - * 90: Ebenen - * 92: Magiegebiet-Auswahl f->magiegebiet - * 94: f->attribs wird gespeichert - * 100: NEWMAGIC, neue Message-Option "Zauber" (MAX_MSG +1) - * 108: Speichern von Timeouts - * 193: curse bekommen id aus struct unit-nummernraum - */ - -/* -#define HEX_VERSION 81 -#define GROWTREE_VERSION 305 -#define RANDOMIZED_RESOURCES_VERSION 306 -#define NEWRACE_VERSION 307 -#define INTERIM_VERSION 309 -#define NEWSKILL_VERSION 309 -#define WATCHERS_VERSION 310 -*/ -#define OVERRIDE_VERSION 311 -#define CURSETYPE_VERSION 312 /* turn 287 */ -#define ALLIANCES_VERSION 313 -#define DBLINK_VERSION 314 -#define CURSEVIGOURISFLOAT_VERSION 315 -#define SAVEXMLNAME_VERSION 316 -#define SAVEALLIANCE_VERSION 317 -#define CLAIM_VERSION 318 -/* 319 is the HSE4 data version */ -#define BACTION_VERSION 319 /* building action gets a param string */ -#define NOLASTORDER_VERSION 320 /* do not use lastorder */ -#define SPELLNAME_VERSION 321 /* reference spells by name */ -#define TERRAIN_VERSION 322 /* terrains are a full type and saved by name */ -#define REGIONITEMS_VERSION 323 /* regions have items */ -#define ATTRIBREAD_VERSION 324 /* remove a_readint */ -#define CURSEFLAGS_VERSION 325 /* remove a_readint */ -#define UNICODE_VERSION 326 /* 2007-06-27 everything is stored as UTF8 */ -#define UID_VERSION 327 /* regions have a unique id */ -#define STORAGE_VERSION 328 /* with storage.h, some things are stored smarter (ids as base36, fractions as float) */ -#define INTPAK_VERSION 329 /* in binary, ints can get packed */ -#define NOZEROIDS_VERSION 330 /* 2008-05-16 zero is not a valid ID for anything (including factions) */ -#define NOBORDERATTRIBS_VERSION 331 /* 2008-05-17 connection::attribs has been moved to userdata */ -#define UIDHASH_VERSION 332 /* 2008-05-22 borders use the region.uid to store */ -#define REGIONOWNER_VERSION 333 /* 2009-05-14 regions have owners and morale */ -#define ALLIANCELEADER_VERSION 333 /* alliances have a leader */ -#define CURSEFLOAT_VERSION 334 /* all curse-effects are float */ -#define MOURNING_VERSION 335 /* mourning peasants */ -#define FOSS_VERSION 336 /* the open source release */ -#define OWNER_2_VERSION 337 /* region owners contain an alliance */ - -#define MIN_VERSION CURSETYPE_VERSION /* minimal datafile we support */ -#define RELEASE_VERSION OWNER_2_VERSION /* current datafile */ +/* vi: set ts=2: + +-------------------+ + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2007 | Christian Schlittchen + | | + +-------------------+ + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ + +/* changes from->to: 72->73: struct unit::lock entfernt. + * 73->74: struct unit::flags eingeführt. + * 74->75: parteitarnung als flag. + * 75->76: #ifdef NEW_HP: hp + * 76->77: ship->damage + * 77->78: neue Message-Option "Orkvermehrung" (MAX_MSG +1) + * 78->79: showdata nicht mehr speichern + * 79->HEX_VERSION: hex + * 80->82: ATTRIB_VERSION + * 90: Ebenen + * 92: Magiegebiet-Auswahl f->magiegebiet + * 94: f->attribs wird gespeichert + * 100: NEWMAGIC, neue Message-Option "Zauber" (MAX_MSG +1) + * 108: Speichern von Timeouts + * 193: curse bekommen id aus struct unit-nummernraum + */ + +/* +#define HEX_VERSION 81 +#define GROWTREE_VERSION 305 +#define RANDOMIZED_RESOURCES_VERSION 306 +#define NEWRACE_VERSION 307 +#define INTERIM_VERSION 309 +#define NEWSKILL_VERSION 309 +#define WATCHERS_VERSION 310 +*/ +#define OVERRIDE_VERSION 311 +#define CURSETYPE_VERSION 312 /* turn 287 */ +#define ALLIANCES_VERSION 313 +#define DBLINK_VERSION 314 +#define CURSEVIGOURISFLOAT_VERSION 315 +#define SAVEXMLNAME_VERSION 316 +#define SAVEALLIANCE_VERSION 317 +#define CLAIM_VERSION 318 +/* 319 is the HSE4 data version */ +#define BACTION_VERSION 319 /* building action gets a param string */ +#define NOLASTORDER_VERSION 320 /* do not use lastorder */ +#define SPELLNAME_VERSION 321 /* reference spells by name */ +#define TERRAIN_VERSION 322 /* terrains are a full type and saved by name */ +#define REGIONITEMS_VERSION 323 /* regions have items */ +#define ATTRIBREAD_VERSION 324 /* remove a_readint */ +#define CURSEFLAGS_VERSION 325 /* remove a_readint */ +#define UNICODE_VERSION 326 /* 2007-06-27 everything is stored as UTF8 */ +#define UID_VERSION 327 /* regions have a unique id */ +#define STORAGE_VERSION 328 /* with storage.h, some things are stored smarter (ids as base36, fractions as float) */ +#define INTPAK_VERSION 329 /* in binary, ints can get packed */ +#define NOZEROIDS_VERSION 330 /* 2008-05-16 zero is not a valid ID for anything (including factions) */ +#define NOBORDERATTRIBS_VERSION 331 /* 2008-05-17 connection::attribs has been moved to userdata */ +#define UIDHASH_VERSION 332 /* 2008-05-22 borders use the region.uid to store */ +#define REGIONOWNER_VERSION 333 /* 2009-05-14 regions have owners and morale */ +#define ALLIANCELEADER_VERSION 333 /* alliances have a leader */ +#define CURSEFLOAT_VERSION 334 /* all curse-effects are float */ +#define MOURNING_VERSION 335 /* mourning peasants */ +#define FOSS_VERSION 336 /* the open source release */ +#define OWNER_2_VERSION 337 /* region owners contain an alliance */ + +#define MIN_VERSION CURSETYPE_VERSION /* minimal datafile we support */ +#define RELEASE_VERSION OWNER_2_VERSION /* current datafile */ diff --git a/src/kernel/xmlkernel.h b/src/kernel/xmlkernel.h index b2cb331c4..9b3832b77 100644 --- a/src/kernel/xmlkernel.h +++ b/src/kernel/xmlkernel.h @@ -1,28 +1,30 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2007 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifndef H_KRNL_XML -#define H_KRNL_XML - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -extern void xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, struct construction ** consPtr); - -#ifdef __cplusplus -} -#endif - -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2007 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifndef H_KRNL_XML +#define H_KRNL_XML + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef HAVE_LIBXML +#include + +extern void xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, struct construction ** consPtr); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 829f3736d..a66ad5d86 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1,2180 +1,2180 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2004 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "xmlreader.h" - -/* kernel includes */ -#include "building.h" -#include "equipment.h" -#include "item.h" -#include "message.h" -#include "race.h" -#include "region.h" -#include "resources.h" -#include "ship.h" -#include "terrain.h" -#include "skill.h" -#include "spell.h" -#include "calendar.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include - - -/* libxml includes */ -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -static boolean gamecode_enabled = false; - -void (*set_spelldata_cb)(struct spell * sp) = 0; -static building_type * bt_get_or_create(const char * name) -{ - if (name!=NULL) { - building_type * btype = bt_find(name); - if (btype==NULL) { - btype = calloc(sizeof(building_type), 1); - btype->_name = strdup(name); - bt_register(btype); - } - return btype; - } - return NULL; -} - -void -enable_xml_gamecode(void) -{ - gamecode_enabled = true; -} - -static void -xml_readtext(xmlNodePtr node, struct locale ** lang, xmlChar **text) -{ - xmlChar * propValue = xmlGetProp(node, BAD_CAST "locale"); - assert(propValue!=NULL); - *lang = find_locale((const char*)propValue); -#ifdef MAKE_LOCALES - if (*lang==NULL) *lang = make_locale((const char*)propValue); -#endif - xmlFree(propValue); - - *text = xmlNodeListGetString(node->doc, node->children, 1); -} - -static const spell * -xml_spell(xmlNode * node, const char * name) -{ - const spell * sp = NULL; - xmlChar * propValue = xmlGetProp(node, BAD_CAST name); - if (propValue!=NULL) { - sp = find_spell(M_NONE, (const char *)propValue); - assert(sp); - xmlFree(propValue); - } - return sp; -} - -static xmlChar * -xml_cleanup_string(xmlChar * str) -{ - xmlChar * read = str; - xmlChar * write = str; - - while (*read) { - /* eat leading whitespace */ - if (*read && isxspace(*read)) { - while (*read && isxspace(*read)) { - ++read; - } - *write++ = ' '; - } - while (*read) { - if (*read== '\n') break; - if (*read== '\r') break; - *write++ = *read++; - } - } - *write = 0; - return str; -} - -static const resource_type * -rt_findorcreate(const char * name) -{ - resource_type * rtype = rt_find(name); - if (rtype==NULL) { - const char * names[2]; - char * namep = strcat(strcpy((char*)malloc(strlen(name)+3), name), "_p"); - /* we'll make a placeholder */ - names[0] = name; - names[1] = namep; - rtype = new_resourcetype(names, NULL, RTF_NONE); - free(namep); - } - return rtype; -} - -static void -xml_readrequirements(xmlNodePtr * nodeTab, int nodeNr, requirement ** reqArray) -{ - int req; - requirement * radd = *reqArray; - - assert (radd==NULL); - if (nodeNr==0) return; - - radd = *reqArray = calloc(sizeof(requirement), nodeNr+1); - - for (req=0;req!=nodeNr;++req) { - xmlNodePtr node = nodeTab[req]; - xmlChar * propValue; - - radd->number = xml_ivalue(node, "quantity", 1); - radd->recycle = xml_fvalue(node, "recycle", 0.5); - - propValue = xmlGetProp(node, BAD_CAST "type"); - radd->rtype = rt_findorcreate((const char*)propValue); - xmlFree(propValue); - - ++radd; - } -} - -void -xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, construction ** consPtr) -{ - xmlNodePtr pushNode = xpath->node; - int k; - for (k=0;k!=nodeSet->nodeNr;++k) { - xmlNodePtr node = nodeSet->nodeTab[k]; - xmlChar * propValue; - construction * con; - xmlXPathObjectPtr req; - int m; - skill_t sk = NOSKILL; - - propValue = xmlGetProp(node, BAD_CAST "skill"); - if (propValue!=NULL) { - sk = sk_find((const char*)propValue); - if (sk==NOSKILL) { - log_error(("construction requires skill '%s' that does not exist.\n", (const char *)propValue)); - xmlFree(propValue); - continue; - } - xmlFree(propValue); - } - - assert(*consPtr==NULL); - - *consPtr = con = calloc(sizeof(construction), 1); - consPtr = &con->improvement; - - con->skill = sk; - con->maxsize = xml_ivalue(node, "maxsize", -1); - con->minskill = xml_ivalue(node, "minskill", -1); - con->reqsize = xml_ivalue(node, "reqsize", -1); - - propValue = xmlGetProp(node, BAD_CAST "building"); - if (propValue!=NULL) { - con->btype = bt_get_or_create((const char*)propValue); - xmlFree(propValue); - } - - /* read construction/requirement */ - xpath->node = node; - req = xmlXPathEvalExpression(BAD_CAST "requirement", xpath); - xml_readrequirements(req->nodesetval->nodeTab, - req->nodesetval->nodeNr, &con->materials); - xmlXPathFreeObject(req); - - /* read construction/modifier */ - xpath->node = node; - req = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); - for (m=0;m!=req->nodesetval->nodeNr;++m) { - xmlNodePtr node = req->nodesetval->nodeTab[m]; - - propValue = xmlGetProp(node, BAD_CAST "function"); - if (propValue!=NULL) { - pf_generic foo = get_function((const char*)propValue); - a_add(&con->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION, (skillmod_fun)foo, 1.0, 0)); - xmlFree(propValue); - } - - } - xmlXPathFreeObject(req); - } - xpath->node = pushNode; -} - -static int -parse_function(xmlNodePtr node, pf_generic * funPtr, xmlChar ** namePtr) -{ - pf_generic fun; - xmlChar * propValue = xmlGetProp(node, BAD_CAST "value"); - assert(propValue!=NULL); - fun = get_function((const char*)propValue); - if (fun!=NULL) { - xmlFree(propValue); - - propValue = xmlGetProp(node, BAD_CAST "name"); - } - *namePtr = propValue; - *funPtr = fun; - return 0; -} - -static int -parse_buildings(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr buildings; - int i; - - /* reading eressea/buildings/building */ - buildings = xmlXPathEvalExpression(BAD_CAST "/eressea/buildings/building", xpath); - if (buildings->nodesetval!=NULL) { - xmlNodeSetPtr nodes = buildings->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr node = nodes->nodeTab[i]; - xmlChar * propValue; - building_type * btype; - xmlXPathObjectPtr result; - int k; - - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - btype = bt_get_or_create((const char*)propValue); - xmlFree(propValue); - - btype->capacity = xml_ivalue(node, "capacity", -1); - btype->maxcapacity = xml_ivalue(node, "maxcapacity", -1); - btype->maxsize = xml_ivalue(node, "maxsize", -1); - - btype->magres = xml_ivalue(node, "magres", 0); - btype->magresbonus = xml_ivalue(node, "magresbonus", 0); - btype->fumblebonus = xml_ivalue(node, "fumblebonus", 0); - btype->auraregen = xml_fvalue(node, "auraregen", 1.0); - - if (xml_bvalue(node, "nodestroy", false)) btype->flags |= BTF_INDESTRUCTIBLE; - if (xml_bvalue(node, "oneperturn", false)) btype->flags |= BTF_ONEPERTURN; - if (xml_bvalue(node, "nobuild", false)) btype->flags |= BTF_NOBUILD; - if (xml_bvalue(node, "namechange", true)) btype->flags |= BTF_NAMECHANGE; - if (xml_bvalue(node, "unique", false)) btype->flags |= BTF_UNIQUE; - if (xml_bvalue(node, "decay", false)) btype->flags |= BTF_DECAY; - if (xml_bvalue(node, "magic", false)) btype->flags |= BTF_MAGIC; - - /* reading eressea/buildings/building/construction */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); - xml_readconstruction(xpath, result->nodesetval, &btype->construction); - xmlXPathFreeObject(result); - - if (gamecode_enabled) { - /* reading eressea/buildings/building/function */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - pf_generic fun; - parse_function(node, &fun, &propValue); - - if (fun==NULL) { - log_error(("unknown function name '%s' for building %s\n", - (const char*)propValue, btype->_name)); - xmlFree(propValue); - continue; - } - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "name")==0) { - btype->name = (const char * (*)(const struct building_type*, const struct building *, int))fun; - } else if (strcmp((const char*)propValue, "init")==0) { - btype->init = (void (*)(struct building_type*))fun; - } else if (strcmp((const char*)propValue, "age")==0) { - btype->age = (void (*)(struct building*))fun; - } else if (strcmp((const char*)propValue, "protection")==0) { - btype->protection = (int (*)(struct building*, struct unit *))fun; - } else if (strcmp((const char*)propValue, "taxes")==0) { - btype->taxes = (double (*)(const struct building*, int))fun; - } else if (strcmp((const char*)propValue, "age")==0) { - btype->age = (void (*)(struct building*))fun; - } else { - log_error(("unknown function type '%s' for building %s\n", - (const char*)propValue, btype->_name)); - } - xmlFree(propValue); - } - xmlXPathFreeObject(result); - } - - /* reading eressea/buildings/building/maintenance */ - result = xmlXPathEvalExpression(BAD_CAST "maintenance", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - maintenance * mt; - - if (btype->maintenance==NULL) { - btype->maintenance = calloc(sizeof(struct maintenance), result->nodesetval->nodeNr+1); - } - mt = btype->maintenance + k; - mt->number = xml_ivalue(node, "amount", 0); - - propValue = xmlGetProp(node, BAD_CAST "type"); - assert(propValue!=NULL); - mt->rtype = rt_find((const char*)propValue); - assert(mt->rtype!=NULL); - xmlFree(propValue); - - if (xml_bvalue(node, "variable", false)) mt->flags |= MTF_VARIABLE; - if (xml_bvalue(node, "vital", false)) mt->flags |= MTF_VITAL; - - } - xmlXPathFreeObject(result); - - /* finally, initialize the new building type */ - if (btype->init) btype->init(btype); - } - } - xmlXPathFreeObject(buildings); - - xmlXPathFreeContext(xpath); - return 0; -} - -static int -parse_calendar(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr xpathCalendars; - xmlNodeSetPtr nsetCalendars; - int c, rv = 0; - - /* reading eressea/buildings/building */ - xpathCalendars = xmlXPathEvalExpression(BAD_CAST "/eressea/calendar", xpath); - nsetCalendars = xpathCalendars->nodesetval; - months_per_year = 0; - if (nsetCalendars==NULL || nsetCalendars->nodeNr==0) { - rv = -1; - } else for (c=0;c!=nsetCalendars->nodeNr;++c) { - xmlNodePtr calendar = nsetCalendars->nodeTab[c]; - xmlXPathObjectPtr xpathWeeks, xpathMonths, xpathSeasons; - xmlNodeSetPtr nsetWeeks, nsetMonths, nsetSeasons; - xmlChar * propValue = xmlGetProp(calendar, BAD_CAST "name"); - xmlChar * newyear = xmlGetProp(calendar, BAD_CAST "newyear"); - - first_turn = xml_ivalue(calendar, "start", first_turn); - if (propValue) { - free(agename); - agename = strdup(mkname("calendar", (const char*)propValue)); - xmlFree(propValue); - } - - xpath->node = calendar; - xpathWeeks = xmlXPathEvalExpression(BAD_CAST "week", xpath); - nsetWeeks = xpathWeeks->nodesetval; - if (nsetWeeks!=NULL && nsetWeeks->nodeNr) { - int i; - - weeks_per_month = nsetWeeks->nodeNr; - assert(!weeknames); - weeknames = malloc(sizeof(char *) * weeks_per_month); - weeknames2 = malloc(sizeof(char *) * weeks_per_month); - for (i=0;i!=nsetWeeks->nodeNr;++i) { - xmlNodePtr week = nsetWeeks->nodeTab[i]; - xmlChar * propValue = xmlGetProp(week, BAD_CAST "name"); - if (propValue) { - weeknames[i] = strdup(mkname("calendar", (const char*)propValue)); - weeknames2[i] = malloc(strlen(weeknames[i])+3); - sprintf(weeknames2[i], "%s_d", weeknames[i]); - xmlFree(propValue); - } - } - } - xmlXPathFreeObject(xpathWeeks); - - xpathSeasons = xmlXPathEvalExpression(BAD_CAST "season", xpath); - nsetSeasons = xpathSeasons->nodesetval; - if (nsetSeasons!=NULL && nsetSeasons->nodeNr) { - int i; - - seasons = nsetSeasons->nodeNr; - assert(!seasonnames); - seasonnames = malloc(sizeof(char *) * seasons); - - for (i=0;i!=nsetSeasons->nodeNr;++i) { - xmlNodePtr season = nsetSeasons->nodeTab[i]; - xmlChar * propValue = xmlGetProp(season, BAD_CAST "name"); - if (propValue) { - seasonnames[i] = strdup(mkname("calendar", (const char*)propValue)); - xmlFree(propValue); - } - } - } - - xpathMonths = xmlXPathEvalExpression(BAD_CAST "season/month", xpath); - nsetMonths = xpathMonths->nodesetval; - if (nsetMonths!=NULL && nsetMonths->nodeNr) { - int i; - - months_per_year = nsetMonths->nodeNr; - assert(!monthnames); - monthnames = malloc(sizeof(char *) * months_per_year); - month_season = malloc(sizeof(int) * months_per_year); - storms = malloc(sizeof(int) * months_per_year); - - for (i=0;i!=nsetMonths->nodeNr;++i) { - xmlNodePtr month = nsetMonths->nodeTab[i]; - xmlChar * propValue = xmlGetProp(month, BAD_CAST "name"); - int j; - - if (propValue) { - if (newyear && strcmp((const char*)newyear, (const char*)propValue)==0) { - first_month = i; - xmlFree(newyear); - newyear = NULL; - } - monthnames[i] = strdup(mkname("calendar", (const char*)propValue)); - xmlFree(propValue); - } - for (j=0;j!=seasons;++j) { - xmlNodePtr season = month->parent; - if (season==nsetSeasons->nodeTab[j]) { - month_season[i] = j; - break; - } - } - assert(j!=seasons); - storms[i] = xml_ivalue(nsetMonths->nodeTab[i], "storm", 0); - } - } - xmlXPathFreeObject(xpathMonths); - xmlXPathFreeObject(xpathSeasons); - } - xmlXPathFreeObject(xpathCalendars); - xmlXPathFreeContext(xpath); - - return rv; -} - -static int -parse_directions(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr xpathDirections; - xmlNodeSetPtr nsetDirections; - int rv = 0; - - /* reading eressea/directions/dir */ - xpathDirections = xmlXPathEvalExpression(BAD_CAST "/eressea/directions/dir", xpath); - nsetDirections = xpathDirections->nodesetval; - if (nsetDirections!=NULL) { - int k; - for (k=0;k!=nsetDirections->nodeNr;++k) { - xmlNodePtr dir = nsetDirections->nodeTab[k]; - xmlChar * propValue = xmlGetProp(dir, BAD_CAST "name"); - - register_special_direction((const char *)propValue); - xmlFree(propValue); - } - } - xmlXPathFreeObject(xpathDirections); - xmlXPathFreeContext(xpath); - - return rv; -} - -static int -parse_ships(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr ships; - int i; - - /* reading eressea/ships/ship */ - ships = xmlXPathEvalExpression(BAD_CAST "/eressea/ships/ship", xpath); - if (ships->nodesetval!=NULL) { - xmlNodeSetPtr nodes = ships->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr child, node = nodes->nodeTab[i]; - xmlChar * propValue; - ship_type * st = calloc(sizeof(ship_type), 1); - xmlXPathObjectPtr result; - int k, c; - - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - st->name[0] = strdup((const char *)propValue); - st->name[1] = strcat(strcpy(malloc(strlen(st->name[0])+3), st->name[0]),"_a"); - xmlFree(propValue); - - st->cabins = xml_ivalue(node, "cabins", 0) * PERSON_WEIGHT; - st->cargo = xml_ivalue(node, "cargo", 0); - st->combat = xml_ivalue(node, "combat", 0); - st->cptskill = xml_ivalue(node, "cptskill", 0); - st->damage = xml_fvalue(node, "damage", 0.0); - if (xml_bvalue(node, "nocoast", false)) st->flags |= SFL_NOCOAST; - if (xml_bvalue(node, "fly", false)) st->flags |= SFL_FLY; - if (xml_bvalue(node, "opensea", false)) st->flags |= SFL_OPENSEA; - st->fishing = xml_ivalue(node, "fishing", 0); - st->minskill = xml_ivalue(node, "minskill", 0); - st->range = xml_ivalue(node, "range", 0); - st->storm = xml_fvalue(node, "storm", 1.0); - st->sumskill = xml_ivalue(node, "sumskill", 0); - - /* reading eressea/ships/ship/construction */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); - xml_readconstruction(xpath, result->nodesetval, &st->construction); - xmlXPathFreeObject(result); - - for (child=node->children;child;child=child->next) { - if (strcmp((const char *)child->name, "modifier")==0) { - double value = xml_fvalue(child, "value", 0.0); - propValue = xmlGetProp(child, BAD_CAST "type"); - if (strcmp((const char *)propValue, "tactics")==0) st->tac_bonus = (float)value; - else if (strcmp((const char *)propValue, "attack")==0) st->at_bonus = (int)value; - else if (strcmp((const char *)propValue, "defense")==0) st->df_bonus = (int)value; - xmlFree(propValue); - } - } - /* reading eressea/ships/ship/coast */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "coast", xpath); - for (c=0,k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - - if (k==0) { - assert(st->coasts==NULL); - st->coasts = (const terrain_type**)malloc(sizeof(const terrain_type*) * (result->nodesetval->nodeNr+1)); - st->coasts[result->nodesetval->nodeNr] = NULL; - } - - propValue = xmlGetProp(node, BAD_CAST "terrain"); - assert(propValue!=NULL); - st->coasts[c] = get_terrain((const char*)propValue); - if (st->coasts[c]!=NULL) ++c; - else { - log_warning(("ship %s mentions a non-existing terrain %s.\n", st->name[0], propValue)); - } - xmlFree(propValue); - } - xmlXPathFreeObject(result); - - /* finally, register the new building type */ - st_register(st); - } - } - xmlXPathFreeObject(ships); - - xmlXPathFreeContext(xpath); - return 0; -} - -static void -race_compat(void) -{ - /* required for old_race, do not change order! */ - const char * oldracenames[MAXRACES] = { - "dwarf", "elf", NULL, "goblin", "human", "troll", "demon", "insect", - "halfling", "cat", "aquarian", "orc", "snotling", "undead", "illusion", - "youngdragon", "dragon", "wyrm", "ent", "catdragon", "dracoid", - "special", "spell", "irongolem", "stonegolem", "shadowdemon", - "shadowmaster", "mountainguard", "alp", "toad", "braineater", "peasant", - "wolf", NULL, NULL, NULL, NULL, "songdragon", NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, "seaserpent", - "shadowknight", "centaur", "skeleton", "skeletonlord", "zombie", - "juju-zombie", "ghoul", "ghast", "museumghost", "gnome", "template", - "clone" - }; - int i; - - for (i=0;i!=MAXRACES;++i) { - const char * rcname = oldracenames[i]; - if (rcname==NULL) { - new_race[i] = NULL; - } else { - race * rc = rc_find(oldracenames[i]); - if (rc) { - new_race[i] = rc; - if (rc == new_race[RC_TROLL]) { - a_add(&rc->attribs, make_skillmod(NOSKILL, SMF_RIDING, NULL, 0.0, -1)); - } - } - } - } -} - -static potion_type * -xml_readpotion(xmlXPathContextPtr xpath, item_type * itype) -{ - int level = xml_ivalue(xpath->node, "level", 0); - - assert(level>0); - return new_potiontype(itype, level); -} - -static luxury_type * -xml_readluxury(xmlXPathContextPtr xpath, item_type * itype) -{ - int price = xml_ivalue(xpath->node, "price", 0); - return new_luxurytype(itype, price); -} - - -static armor_type * -xml_readarmor(xmlXPathContextPtr xpath, item_type * itype) -{ - xmlNodePtr node = xpath->node; - armor_type * atype = NULL; - unsigned int flags = ATF_NONE; - int ac = xml_ivalue(node, "ac", 0); - double penalty = xml_fvalue(node, "penalty", 0.0); - double magres = xml_fvalue(node, "magres", 0.0); - - if (xml_bvalue(node, "laen", false)) flags |= ATF_LAEN; - if (xml_bvalue(node, "shield", false)) flags |= ATF_SHIELD; - - atype = new_armortype(itype, penalty, magres, ac, flags); - atype->projectile = (float)xml_fvalue(node, "projectile", 0.0); - return atype; -} - -static weapon_type * -xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) -{ - xmlNodePtr node = xpath->node; - weapon_type * wtype = NULL; - unsigned int flags = WTF_NONE; - xmlXPathObjectPtr result; - xmlChar * propValue; - int k; - skill_t sk; - int minskill = xml_ivalue(node, "minskill", 0); - int offmod = xml_ivalue(node, "offmod", 0); - int defmod = xml_ivalue(node, "defmod", 0); - int reload = xml_ivalue(node, "reload", 0); - double magres = xml_fvalue(node, "magres", 0.0); - - if (xml_bvalue(node, "armorpiercing", false)) flags |= WTF_ARMORPIERCING; - if (xml_bvalue(node, "magical", false)) flags |= WTF_MAGICAL; - if (xml_bvalue(node, "missile", false)) flags |= WTF_MISSILE; - if (xml_bvalue(node, "pierce", false)) flags |= WTF_PIERCE; - if (xml_bvalue(node, "cut", false)) flags |= WTF_CUT; - if (xml_bvalue(node, "blunt", false)) flags |= WTF_BLUNT; - if (xml_bvalue(node, "siege", false)) flags |= WTF_SIEGE; - if (xml_bvalue(node, "horse", (flags&WTF_MISSILE)==0)) flags |= WTF_HORSEBONUS; - if (xml_bvalue(node, "useshield", true)) flags |= WTF_USESHIELD; - - propValue = xmlGetProp(node, BAD_CAST "skill"); - assert(propValue!=NULL); - sk = sk_find((const char*)propValue); - assert(sk!=NOSKILL); - xmlFree(propValue); - - wtype = new_weapontype(itype, flags, magres, NULL, offmod, defmod, reload, sk, minskill); - - /* reading weapon/damage */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "damage", xpath); - assert(result->nodesetval->nodeNr<=2); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - int pos = 0; - - propValue = xmlGetProp(node, BAD_CAST "type"); - if (strcmp((const char *)propValue, "footman")!=0) { - pos = 1; - } - xmlFree(propValue); - - propValue = xmlGetProp(node, BAD_CAST "value"); - wtype->damage[pos] = gc_add(strdup((const char*)propValue)); - if (k==0) wtype->damage[1-pos] = wtype->damage[pos]; - xmlFree(propValue); - } - xmlXPathFreeObject(result); - - /* reading weapon/modifier */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); - assert(wtype->modifiers==NULL); - wtype->modifiers = calloc(result->nodesetval->nodeNr+1, sizeof(weapon_mod)); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - xmlXPathObjectPtr races; - int r, flags = 0; - - if (xml_bvalue(node, "walking", false)) flags|=WMF_WALKING; - if (xml_bvalue(node, "riding", false)) flags|=WMF_RIDING; - if (xml_bvalue(node, "against_walking", false)) flags|=WMF_AGAINST_WALKING; - if (xml_bvalue(node, "against_riding", false)) flags|=WMF_AGAINST_RIDING; - if (xml_bvalue(node, "offensive", false)) flags|=WMF_OFFENSIVE; - if (xml_bvalue(node, "defensive", false)) flags|=WMF_DEFENSIVE; - - propValue = xmlGetProp(node, BAD_CAST "type"); - if (strcmp((const char*)propValue, "damage")==0) flags|=WMF_DAMAGE; - else if (strcmp((const char*)propValue, "skill")==0) flags|=WMF_SKILL; - else if (strcmp((const char*)propValue, "missile_target")==0) flags|=WMF_MISSILE_TARGET; - xmlFree(propValue); - - wtype->modifiers[k].flags = flags; - wtype->modifiers[k].value = xml_ivalue(node, "value", 0); - - xpath->node = node; - races = xmlXPathEvalExpression(BAD_CAST "race", xpath); - for (r=0;r!=races->nodesetval->nodeNr;++r) { - xmlNodePtr node = races->nodesetval->nodeTab[r]; - - propValue = xmlGetProp(node, BAD_CAST "name"); - if (propValue!=NULL) { - const race * rc = rc_find((const char*)propValue); - if (rc==NULL) rc = rc_add(rc_new((const char*)propValue)); - racelist_insert(&wtype->modifiers[k].races, rc); - xmlFree(propValue); - } - } - xmlXPathFreeObject(races); - } - xmlXPathFreeObject(result); - - if (gamecode_enabled) { - /* reading weapon/function */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - xmlChar * propValue; - pf_generic fun; - - parse_function(node, &fun, &propValue); - if (fun==NULL) { - log_error(("unknown function name '%s' for item '%s'\n", - (const char*)propValue, itype->rtype->_name[0])); - xmlFree(propValue); - continue; - } - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "attack")==0) { - wtype->attack = (boolean (*)(const struct troop*, const struct weapon_type *, int*))fun; - } else { - log_error(("unknown function type '%s' for item '%s'\n", - (const char*)propValue, itype->rtype->_name[0])); - } - xmlFree(propValue); - } - xmlXPathFreeObject(result); - } - - xpath->node = node; - return wtype; -} - -static item_type * -xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) -{ - xmlNodePtr node = xpath->node; - item_type * itype = NULL; - unsigned int flags = ITF_NONE; - xmlXPathObjectPtr result; - int k; - - int weight = xml_ivalue(node, "weight", 0); - int capacity = xml_ivalue(node, "capacity", 0); - - if (xml_bvalue(node, "cursed", false)) flags |= ITF_CURSED; - if (xml_bvalue(node, "notlost", false)) flags |= ITF_NOTLOST; - if (xml_bvalue(node, "herb", false)) flags |= ITF_HERB; - if (xml_bvalue(node, "big", false)) flags |= ITF_BIG; - if (xml_bvalue(node, "animal", false)) flags |= ITF_ANIMAL; - if (xml_bvalue(node, "vehicle", false)) flags |= ITF_VEHICLE; - itype = new_itemtype(rtype, flags, weight, capacity); -#if SCORE_MODULE - itype->score = xml_ivalue(node, "score", 0); -#endif - - /* reading item/construction */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); - xml_readconstruction(xpath, result->nodesetval, &itype->construction); - xmlXPathFreeObject(result); - - /* reading item/weapon */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "weapon", xpath); - assert(result->nodesetval->nodeNr<=1); - if (result->nodesetval->nodeNr!=0) { - xpath->node = result->nodesetval->nodeTab[0]; - rtype->wtype = xml_readweapon(xpath, itype); - } - xmlXPathFreeObject(result); - - /* reading item/potion */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "potion", xpath); - assert(result->nodesetval->nodeNr<=1); - if (result->nodesetval->nodeNr!=0) { - xpath->node = result->nodesetval->nodeTab[0]; - rtype->ptype = xml_readpotion(xpath, itype); - } - xmlXPathFreeObject(result); - - /* reading item/luxury */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "luxury", xpath); - assert(result->nodesetval->nodeNr<=1); - if (result->nodesetval->nodeNr!=0) { - xpath->node = result->nodesetval->nodeTab[0]; - rtype->ltype = xml_readluxury(xpath, itype); - } - xmlXPathFreeObject(result); - - /* reading item/armor */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "armor", xpath); - assert(result->nodesetval->nodeNr<=1); - if (result->nodesetval->nodeNr!=0) { - xpath->node = result->nodesetval->nodeTab[0]; - rtype->atype = xml_readarmor(xpath, itype); - } - xmlXPathFreeObject(result); - - if (gamecode_enabled) { - /* reading item/function */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - xmlChar * propValue; - pf_generic fun; - - parse_function(node, &fun, &propValue); - if (fun==NULL) { - log_error(("unknown function name '%s' for item '%s'\n", - (const char*)propValue, rtype->_name[0])); - xmlFree(propValue); - continue; - } - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "give")==0) { - itype->give = (int (*)(struct unit*, struct unit*, const struct item_type *, int, struct order *))fun; - } else if (strcmp((const char*)propValue, "use")==0) { - itype->use = (int (*)(struct unit *, const struct item_type *, int, struct order *))fun; - } else if (strcmp((const char*)propValue, "canuse")==0) { - itype->canuse = (boolean (*)(const struct unit *, const struct item_type *))fun; - } else if (strcmp((const char*)propValue, "useonother")==0) { - itype->useonother = (int (*)(struct unit *, int, const struct item_type *, int, struct order *))fun; - } else { - log_error(("unknown function type '%s' for item '%s'\n", - (const char*)propValue, rtype->_name[0])); - } - xmlFree(propValue); - } - xmlXPathFreeObject(result); - } - - return itype; -} - -static int -parse_rules(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr functions; - xmlNodeSetPtr nodes; - int i; - - /* reading eressea/resources/resource */ - functions = xmlXPathEvalExpression(BAD_CAST "/eressea/rules/function", xpath); - nodes = functions->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr node = nodes->nodeTab[i]; - xmlChar *propValue; - pf_generic fun; - - parse_function(node, &fun, &propValue); - - if (fun==NULL) { - log_error(("unknown function for rule '%s' %s\n", (const char*)propValue)); - xmlFree(propValue); - continue; - } - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "wage")==0) { - global.functions.wage = (int (*)(const struct region*, const struct faction*, const struct race*, int))fun; - } else if (strcmp((const char*)propValue, "maintenance")==0) { - global.functions.maintenance = (int (*)(const struct unit*))fun; - } else { - log_error(("unknown function for rule '%s'\n", - (const char*)propValue)); - } - xmlFree(propValue); - } - xmlXPathFreeObject(functions); - xmlXPathFreeContext(xpath); - return 0; -} - -static int -parse_resources(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr resources; - xmlNodeSetPtr nodes; - int i; - - /* reading eressea/resources/resource */ - resources = xmlXPathEvalExpression(BAD_CAST "/eressea/resources/resource", xpath); - nodes = resources->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr node = nodes->nodeTab[i]; - xmlChar *propValue, *name, *appearance; - const char *names[2], *appearances[2]; - char * namep = NULL, * appearancep = NULL; - resource_type * rtype; - unsigned int flags = RTF_NONE; - xmlXPathObjectPtr result; - int k; - - if (xml_bvalue(node, "pooled", true)) flags |= RTF_POOLED; - if (xml_bvalue(node, "limited", false)) flags |= RTF_LIMITED; - - name = xmlGetProp(node, BAD_CAST "name"); - appearance = xmlGetProp(node, BAD_CAST "appearance"); - assert(name!=NULL); - - if (appearance!=NULL) { - appearancep = strcat(strcpy((char*)malloc(strlen((char*)appearance)+3), (char*)appearance), "_p"); - } - - rtype = rt_find((const char *)name); - if (rtype!=NULL) { - /* dependency from another item, was created earlier */ - rtype->flags |= flags; - if (appearance) { - rtype->_appearance[0] = strdup((const char*)appearance); - rtype->_appearance[1] = appearancep; - free(appearancep); - } - } else { - namep = strcat(strcpy((char*)malloc(strlen((char*)name)+3), (char*)name), "_p"); - names[0] = (const char*)name; - names[1] = namep; - if (appearance) { - appearances[0] = (const char*)appearance; - appearances[1] = appearancep; - rtype = new_resourcetype((const char**)names, (const char**)appearances, flags); - free(appearancep); - } else { - rtype = new_resourcetype(names, NULL, flags); - } - free(namep); - } - - if (name) xmlFree(name); - if (appearance) xmlFree(appearance); - - name = xmlGetProp(node, BAD_CAST "material"); - if (name) { - rmt_create(rtype, (const char *)name); - xmlFree(name); - } - - - if (gamecode_enabled) { - /* reading eressea/resources/resource/function */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - if (result->nodesetval!=NULL) for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - pf_generic fun; - - parse_function(node, &fun, &propValue); - if (fun==NULL) { - log_error(("unknown function name '%s' for resource %s\n", - (const char*)propValue, rtype->_name[0])); - xmlFree(propValue); - continue; - } - - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "change")==0) { - rtype->uchange = (rtype_uchange)fun; - } else if (strcmp((const char*)propValue, "get")==0) { - rtype->uget = (rtype_uget)fun; - } else if (strcmp((const char*)propValue, "name")==0) { - rtype->name = (rtype_name)fun; - } else { - log_error(("unknown function type '%s' for resource %s\n", - (const char*)propValue, rtype->_name[0])); - } - xmlFree(propValue); - } - xmlXPathFreeObject(result); - } - - /* reading eressea/resources/resource/resourcelimit */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "resourcelimit", xpath); - assert(result->nodesetval->nodeNr<=1); - if (result->nodesetval->nodeNr!=0) { - resource_limit * rdata; - attrib * a = a_find(rtype->attribs, &at_resourcelimit); - xmlNodePtr limit = result->nodesetval->nodeTab[0]; - - if (a==NULL) a = a_add(&rtype->attribs, a_new(&at_resourcelimit)); - rdata = (resource_limit*)a->data.v; - rtype->flags |= RTF_LIMITED; - xpath->node = limit; - xmlXPathFreeObject(result); - - result = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); - if (result->nodesetval!=NULL) { - rdata->modifiers = calloc(result->nodesetval->nodeNr+1, sizeof(resource_mod)); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - building_type * btype = NULL; - const race * rc = NULL; - - propValue = xmlGetProp(node, BAD_CAST "race"); - if (propValue!=NULL) { - rc = rc_find((const char*)propValue); - if (rc==NULL) rc = rc_add(rc_new((const char*)propValue)); - xmlFree(propValue); - } - rdata->modifiers[k].race = rc; - - propValue = xmlGetProp(node, BAD_CAST "building"); - if (propValue!=NULL) { - btype = bt_get_or_create((const char*)propValue); - xmlFree(propValue); - } - rdata->modifiers[k].btype = btype; - - propValue = xmlGetProp(node, BAD_CAST "type"); - assert(propValue!=NULL); - if (strcmp((const char *)propValue, "skill")==0) { - rdata->modifiers[k].value.i = xml_ivalue(node, "value", 0); - rdata->modifiers[k].flags = RMF_SKILL; - } else if (strcmp((const char *)propValue, "material")==0) { - rdata->modifiers[k].value.f = (float)xml_fvalue(node, "value", 0); - rdata->modifiers[k].flags = RMF_SAVEMATERIAL; - } else if (strcmp((const char *)propValue, "resource")==0) { - rdata->modifiers[k].value.f = (float)xml_fvalue(node, "value", 0); - rdata->modifiers[k].flags = RMF_SAVERESOURCE; - } else if (strcmp((const char *)propValue, "require")==0) { - xmlChar * propBldg = xmlGetProp(node, BAD_CAST "building"); - if (propBldg!=NULL) { - btype = bt_get_or_create((const char*)propBldg); - rdata->modifiers[k].btype = btype; - rdata->modifiers[k].flags = RMF_REQUIREDBUILDING; - xmlFree(propBldg); - } - } else { - log_error(("unknown type '%s' for resourcelimit-modifier '%s'\n", - (const char*)propValue, rtype->_name[0])); - } - xmlFree(propValue); - } - } - xmlXPathFreeObject(result); - - result = xmlXPathEvalExpression(BAD_CAST "guard", xpath); - if (result->nodesetval!=NULL) for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - xmlChar * propFlag = xmlGetProp(node, BAD_CAST "flag"); - - if (propFlag!=NULL) { - if (strcmp((const char *)propFlag, "logging")==0) { - rdata->guard |= GUARD_TREES; - } else if (strcmp((const char *)propFlag, "mining")==0) { - rdata->guard |= GUARD_MINING; - } - xmlFree(propFlag); - } - } - xmlXPathFreeObject(result); - - /* reading eressea/resources/resource/resourcelimit/function */ - result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - if (result->nodesetval!=NULL) for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - pf_generic fun; - - propValue = xmlGetProp(node, BAD_CAST "value"); - assert(propValue!=NULL); - fun = get_function((const char*)propValue); - if (fun==NULL) { - log_error(("unknown limit '%s' for resource %s\n", - (const char*)propValue, rtype->_name[0])); - xmlFree(propValue); - continue; - } - xmlFree(propValue); - - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "produce")==0) { - rdata->produce = (rlimit_produce)fun; - } else if (strcmp((const char*)propValue, "limit")==0) { - rdata->limit = (rlimit_limit)fun; - } else { - log_error(("unknown limit '%s' for resource %s\n", - (const char*)propValue, rtype->_name[0])); - } - xmlFree(propValue); - } - } - xmlXPathFreeObject(result); - - /* reading eressea/resources/resource/resourcelimit/function */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "resourcelimit/function", xpath); - xmlXPathFreeObject(result); - - /* reading eressea/resources/resource/item */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "item", xpath); - assert(result->nodesetval->nodeNr<=1); - if (result->nodesetval->nodeNr!=0) { - rtype->flags |= RTF_ITEM; - xpath->node = result->nodesetval->nodeTab[0]; - rtype->itype = xml_readitem(xpath, rtype); - } - xmlXPathFreeObject(result); - } - xmlXPathFreeObject(resources); - - xmlXPathFreeContext(xpath); - - /* make sure old items (used in requirements) are available */ - init_resources(); - init_itemtypes(); - - return 0; -} - -static void -add_items(equipment * eq, xmlNodeSetPtr nsetItems) -{ - if (nsetItems!=NULL && nsetItems->nodeNr>0) { - int i; - for (i=0;i!=nsetItems->nodeNr;++i) { - xmlNodePtr node = nsetItems->nodeTab[i]; - xmlChar * propValue; - const struct item_type * itype; - - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - itype = it_find((const char*)propValue); - xmlFree(propValue); - if (itype!=NULL) { - propValue = xmlGetProp(node, BAD_CAST "amount"); - if (propValue!=NULL) { - equipment_setitem(eq, itype, (const char*)propValue); - xmlFree(propValue); - } - } - } - } -} - -static void -add_callbacks(equipment * eq, xmlNodeSetPtr nsetItems) -{ - if (nsetItems!=NULL && nsetItems->nodeNr>0) { - int i; - for (i=0;i!=nsetItems->nodeNr;++i) { - xmlNodePtr node = nsetItems->nodeTab[i]; - xmlChar * propValue; - pf_generic fun; - - propValue = xmlGetProp(node, BAD_CAST "name"); - if (propValue!=NULL) { - fun = get_function((const char*)propValue); - if (fun) { - equipment_setcallback(eq, (void (*)(const struct equipment *, struct unit *))fun); - } - xmlFree(propValue); - } - } - } -} - -static void -add_spells(equipment * eq, xmlNodeSetPtr nsetItems) -{ - if (nsetItems!=NULL && nsetItems->nodeNr>0) { - int i; - for (i=0;i!=nsetItems->nodeNr;++i) { - xmlNodePtr node = nsetItems->nodeTab[i]; - xmlChar * propValue; - magic_t mtype = M_NONE; - struct spell * sp; - - propValue = xmlGetProp(node, BAD_CAST "school"); - if (propValue!=NULL) { - for (mtype=0;mtype!=MAXMAGIETYP;++mtype) { - if (strcmp((const char*)propValue, magic_school[mtype])==0) break; - } - assert(mtype!=MAXMAGIETYP); - xmlFree(propValue); - } - - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - sp = find_spell(mtype, (const char*)propValue); - assert(sp); - xmlFree(propValue); - if (sp!=NULL) { - equipment_addspell(eq, sp); - } - } - } -} - -static void -add_skills(equipment * eq, xmlNodeSetPtr nsetSkills) -{ - if (nsetSkills!=NULL && nsetSkills->nodeNr>0) { - int i; - for (i=0;i!=nsetSkills->nodeNr;++i) { - xmlNodePtr node = nsetSkills->nodeTab[i]; - xmlChar * propValue; - skill_t sk; - - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - sk = sk_find((const char*)propValue); - xmlFree(propValue); - if (sk!=NOSKILL) { - propValue = xmlGetProp(node, BAD_CAST "level"); - if (propValue!=NULL) { - equipment_setskill(eq, sk, (const char*)propValue); - xmlFree(propValue); - } - } - } - } -} - -static void -add_subsets(xmlDocPtr doc, equipment * eq, xmlNodeSetPtr nsetSubsets) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - if (nsetSubsets!=NULL && nsetSubsets->nodeNr>0) { - int i; - - eq->subsets = calloc(nsetSubsets->nodeNr+1, sizeof(subset)); - for (i=0;i!=nsetSubsets->nodeNr;++i) { - xmlXPathObjectPtr xpathResult; - xmlNodePtr node = nsetSubsets->nodeTab[i]; - xmlChar * propValue; - - eq->subsets[i].chance = 1.0f; - propValue = xmlGetProp(node, BAD_CAST "chance"); - if (propValue!=NULL) { - eq->subsets[i].chance = (float)atof((const char *)propValue); - xmlFree(propValue); - } - xpath->node = node; - xpathResult = xmlXPathEvalExpression(BAD_CAST "set", xpath); - if (xpathResult->nodesetval) { - xmlNodeSetPtr nsetSets = xpathResult->nodesetval; - float totalChance = 0.0f; - - if (nsetSets->nodeNr>0) { - int set; - eq->subsets[i].sets = calloc(nsetSets->nodeNr+1, sizeof(subsetitem)); - for (set=0;set!=nsetSets->nodeNr;++set) { - xmlNodePtr nodeSet = nsetSets->nodeTab[set]; - float chance = 1.0f; - - propValue = xmlGetProp(nodeSet, BAD_CAST "chance"); - if (propValue!=NULL) { - chance = (float)atof((const char *)propValue); - xmlFree(propValue); - } - totalChance += chance; - - propValue = xmlGetProp(nodeSet, BAD_CAST "name"); - assert(propValue!=NULL); - eq->subsets[i].sets[set].chance = chance; - eq->subsets[i].sets[set].set = create_equipment((const char*)propValue); - xmlFree(propValue); - } - } - if (totalChance>1.0f) { - log_error(("total chance exceeds 1.0: %f in equipment set %s.\n", - totalChance, eq->name)); - } - } - xmlXPathFreeObject(xpathResult); - } - } - xmlXPathFreeContext(xpath); -} - -static int -parse_equipment(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr xpathRaces; - - /* reading eressea/equipment/set */ - xpathRaces = xmlXPathEvalExpression(BAD_CAST "/eressea/equipment/set", xpath); - if (xpathRaces->nodesetval) { - xmlNodeSetPtr nsetRaces = xpathRaces->nodesetval; - int i; - - for (i=0;i!=nsetRaces->nodeNr;++i) { - xmlNodePtr node = nsetRaces->nodeTab[i]; - xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); - - if (propName!=NULL) { - equipment * eq = create_equipment((const char*)propName); - xmlXPathObjectPtr xpathResult; - - xpath->node = node; - - xpathResult = xmlXPathEvalExpression(BAD_CAST "callback", xpath); - assert(!eq->callback); - add_callbacks(eq, xpathResult->nodesetval); - xmlXPathFreeObject(xpathResult); - - xpathResult = xmlXPathEvalExpression(BAD_CAST "item", xpath); - assert(!eq->items); - add_items(eq, xpathResult->nodesetval); - xmlXPathFreeObject(xpathResult); - - xpathResult = xmlXPathEvalExpression(BAD_CAST "spell", xpath); - assert(!eq->spells); - add_spells(eq, xpathResult->nodesetval); - xmlXPathFreeObject(xpathResult); - - xpathResult = xmlXPathEvalExpression(BAD_CAST "skill", xpath); - add_skills(eq, xpathResult->nodesetval); - xmlXPathFreeObject(xpathResult); - - xpathResult = xmlXPathEvalExpression(BAD_CAST "subset", xpath); - assert(!eq->subsets); - add_subsets(doc, eq, xpathResult->nodesetval); - xmlXPathFreeObject(xpathResult); - - xmlFree(propName); - } - } - } - - xmlXPathFreeObject(xpathRaces); - xmlXPathFreeContext(xpath); - - return 0; -} - -static int -parse_spells(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr spells; - - /* reading eressea/spells/spell */ - spells = xmlXPathEvalExpression(BAD_CAST "/eressea/spells/spell", xpath); - if (spells->nodesetval!=NULL) { - xmlNodeSetPtr nodes = spells->nodesetval; - int i; - - for (i=0;i!=nodes->nodeNr;++i) { - xmlXPathObjectPtr result; - xmlNodePtr node = nodes->nodeTab[i]; - xmlChar * propValue; - int k; - spell * sp = calloc(1, sizeof(spell)); - static int modes[] = { 0, PRECOMBATSPELL, COMBATSPELL, POSTCOMBATSPELL }; - - /* spellname */ - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - sp->sname = strdup((const char*)propValue); - xmlFree(propValue); - - propValue = xmlGetProp(node, BAD_CAST "parameters"); - if (propValue) { - sp->parameter=strdup((const char *)propValue); - xmlFree(propValue); - } - - propValue = xmlGetProp(node, BAD_CAST "syntax"); - if (propValue) { - sp->syntax=strdup((const char *)propValue); - xmlFree(propValue); - } - - /* magic type */ - propValue = xmlGetProp(node, BAD_CAST "type"); - assert(propValue!=NULL); - for (sp->magietyp=0;sp->magietyp!=MAXMAGIETYP;++sp->magietyp) { - if (strcmp(magic_school[sp->magietyp], (const char *)propValue)==0) break; - } - assert(sp->magietyp!=MAXMAGIETYP); - xmlFree(propValue); - - /* level, rank and flags */ - sp->id = xml_ivalue(node, "index", 0); - sp->level = xml_ivalue(node, "level", -1); - sp->rank = (char)xml_ivalue(node, "rank", -1); - if (xml_bvalue(node, "los", false)) sp->sptyp |= TESTCANSEE; /* must see or have contact */ - if (!xml_bvalue(node, "target_global", false)) sp->sptyp |= SEARCHLOCAL; /* must be in same region */ - if (xml_bvalue(node, "ship", false)) sp->sptyp |= ONSHIPCAST; - if (xml_bvalue(node, "ocean", false)) sp->sptyp |= OCEANCASTABLE; - if (xml_bvalue(node, "far", false)) sp->sptyp |= FARCASTING; - if (xml_bvalue(node, "variable", false)) sp->sptyp |= SPELLLEVEL; - k = xml_ivalue(node, "combat", 0); - if (k>=0 && k<=3) sp->sptyp |= modes[k]; - - if (gamecode_enabled) { - /* reading eressea/spells/spell/function */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - - if (result->nodesetval->nodeNr==0) { - /* deprecated style: this spell gets its' function from a callback */ - if (set_spelldata_cb) set_spelldata_cb(sp); - } else { - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - pf_generic fun; - - parse_function(node, &fun, &propValue); - if (fun==NULL) { - log_error(("unknown function name '%s' for spell '%s'\n", - (const char*)propValue, sp->sname)); - xmlFree(propValue); - continue; - } - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "cast")==0) { - sp->sp_function = (spell_f)fun; - } else if (strcmp((const char*)propValue, "fumble")==0) { - sp->patzer = (pspell_f)fun; - } else { - log_error(("unknown function type '%s' for spell %s\n", - (const char*)propValue, sp->sname)); - } - xmlFree(propValue); - } - } - xmlXPathFreeObject(result); - } - - /* reading eressea/spells/spell/resource */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "resource", xpath); - if (result->nodesetval->nodeNr) { - sp->components = malloc(sizeof(spell_component)*(result->nodesetval->nodeNr+1)); - sp->components[result->nodesetval->nodeNr].type = 0; - } - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue); - sp->components[k].type = rt_find((const char *)propValue); - assert(sp->components[k].type); - xmlFree(propValue); - sp->components[k].amount = xml_ivalue(node, "amount", 1); - sp->components[k].cost = SPC_FIX; - propValue = xmlGetProp(node, BAD_CAST "cost"); - if (propValue!=NULL) { - if (strcmp((const char *)propValue, "linear")==0) { - sp->components[k].cost = SPC_LINEAR; - } else if (strcmp((const char *)propValue, "level")==0) { - sp->components[k].cost = SPC_LEVEL; - } - xmlFree(propValue); - } - } - xmlXPathFreeObject(result); - register_spell(sp); - } - } - - xmlXPathFreeObject(spells); - - xmlXPathFreeContext(xpath); - - return 0; -} - -static void -parse_param(struct param ** params, xmlNodePtr node) -{ - xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); - xmlChar * propValue = xmlGetProp(node, BAD_CAST "value"); - - set_param(params, (const char*)propName, (const char*)propValue); - - xmlFree(propName); - xmlFree(propValue); -} - -static void -parse_ai(race * rc, xmlNodePtr node) -{ - rc->splitsize = xml_ivalue(node, "splitsize", 0); - rc->aggression = (float)xml_fvalue(node, "aggression", 0.04); - if (xml_bvalue(node, "killpeasants", false)) rc->flags |= RCF_KILLPEASANTS; - if (xml_bvalue(node, "moverandom", false)) rc->flags |= RCF_MOVERANDOM; - if (xml_bvalue(node, "learn", false)) rc->flags |= RCF_LEARN; -} - -static int -parse_races(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr races; - xmlNodeSetPtr nodes; - int i; - - /* reading eressea/races/race */ - races = xmlXPathEvalExpression(BAD_CAST "/eressea/races/race", xpath); - nodes = races->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr node = nodes->nodeTab[i]; - xmlNodePtr child; - xmlChar * propValue; - race * rc; - xmlXPathObjectPtr result; - int k, study_speed_base; - struct att * attack; - - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - rc = rc_find((const char*)propValue); - if (rc==NULL) rc = rc_add(rc_new((const char*)propValue)); - xmlFree(propValue); - - propValue = xmlGetProp(node, BAD_CAST "damage"); - assert(propValue!=NULL); - rc->def_damage = strdup((const char*)propValue); - xmlFree(propValue); - - rc->magres = (float)xml_fvalue(node, "magres", 0.0); - rc->maxaura = (float)xml_fvalue(node, "maxaura", 0.0); - rc->regaura = (float)xml_fvalue(node, "regaura", 1.0); - rc->recruitcost = xml_ivalue(node, "recruitcost", 0); - rc->maintenance = xml_ivalue(node, "maintenance", 0); - rc->weight = xml_ivalue(node, "weight", PERSON_WEIGHT); - rc->capacity = xml_ivalue(node, "capacity", 540); - rc->speed = (float)xml_fvalue(node, "speed", 1.0F); - rc->hitpoints = xml_ivalue(node, "hp", 0); - rc->armor = (char)xml_ivalue(node, "ac", 0); - study_speed_base = xml_ivalue(node, "studyspeed", 0); - - rc->at_default = (char)xml_ivalue(node, "unarmedattack", -2); - rc->df_default = (char)xml_ivalue(node, "unarmeddefense", -2); - rc->at_bonus = (char)xml_ivalue(node, "attackmodifier", 0); - rc->df_bonus = (char)xml_ivalue(node, "defensemodifier", 0); - - if (xml_bvalue(node, "playerrace", false)) rc->flags |= RCF_PLAYERRACE; - if (xml_bvalue(node, "scarepeasants", false)) rc->flags |= RCF_SCAREPEASANTS; - if (xml_bvalue(node, "cansteal", true)) rc->flags |= RCF_CANSTEAL; - if (xml_bvalue(node, "cansail", true)) rc->flags |= RCF_CANSAIL; - if (xml_bvalue(node, "cannotmove", false)) rc->flags |= RCF_CANNOTMOVE; - if (xml_bvalue(node, "fly", false)) rc->flags |= RCF_FLY; - if (xml_bvalue(node, "invisible", false)) rc->flags |= RCF_INVISIBLE; - if (xml_bvalue(node, "coastal", false)) rc->flags |= RCF_COASTAL; - if (xml_bvalue(node, "unarmedguard", false)) rc->flags |= RCF_UNARMEDGUARD; - if (xml_bvalue(node, "swim", false)) rc->flags |= RCF_SWIM; - if (xml_bvalue(node, "walk", false)) rc->flags |= RCF_WALK; - if (!xml_bvalue(node, "canlearn", true)) rc->flags |= RCF_NOLEARN; - if (!xml_bvalue(node, "canteach", true)) rc->flags |= RCF_NOTEACH; - if (xml_bvalue(node, "horse", false)) rc->flags |= RCF_HORSE; - if (xml_bvalue(node, "desert", false)) rc->flags |= RCF_DESERT; - if (xml_bvalue(node, "absorbpeasants", false)) rc->flags |= RCF_ABSORBPEASANTS; - if (xml_bvalue(node, "noheal", false)) rc->flags |= RCF_NOHEAL; - if (xml_bvalue(node, "noweapons", false)) rc->flags |= RCF_NOWEAPONS; - if (xml_bvalue(node, "shapeshift", false)) rc->flags |= RCF_SHAPESHIFT; - if (xml_bvalue(node, "shapeshiftany", false)) rc->flags |= RCF_SHAPESHIFTANY; - if (xml_bvalue(node, "illusionary", false)) rc->flags |= RCF_ILLUSIONARY; - if (xml_bvalue(node, "undead", false)) rc->flags |= RCF_UNDEAD; - if (xml_bvalue(node, "dragon", false)) rc->flags |= RCF_DRAGON; - if (xml_bvalue(node, "shipspeed", false)) rc->flags |= RCF_SHIPSPEED; - if (xml_bvalue(node, "stonegolem", false)) rc->flags |= RCF_STONEGOLEM; - if (xml_bvalue(node, "irongolem", false)) rc->flags |= RCF_IRONGOLEM; - - if (xml_bvalue(node, "giveitem", false)) rc->ec_flags |= GIVEITEM; - if (xml_bvalue(node, "giveperson", false)) rc->ec_flags |= GIVEPERSON; - if (xml_bvalue(node, "giveunit", false)) rc->ec_flags |= GIVEUNIT; - if (xml_bvalue(node, "getitem", false)) rc->ec_flags |= GETITEM; - if (xml_bvalue(node, "recruithorses", false)) rc->ec_flags |= ECF_REC_HORSES; - if (xml_bvalue(node, "recruitethereal", false)) rc->ec_flags |= ECF_REC_ETHEREAL; - if (xml_bvalue(node, "recruitunlimited", false)) rc->ec_flags |= ECF_REC_UNLIMITED; - - if (xml_bvalue(node, "equipment", false)) rc->battle_flags |= BF_EQUIPMENT; - if (xml_bvalue(node, "noblock", false)) rc->battle_flags |= BF_NOBLOCK; - if (xml_bvalue(node, "invinciblenonmagic", false)) rc->battle_flags |= BF_INV_NONMAGIC; - if (xml_bvalue(node, "resistbash", false)) rc->battle_flags |= BF_RES_BASH; - if (xml_bvalue(node, "resistcut", false)) rc->battle_flags |= BF_RES_CUT; - if (xml_bvalue(node, "resistpierce", false)) rc->battle_flags |= BF_RES_PIERCE; - if (xml_bvalue(node, "canattack", true)) rc->battle_flags |= BF_CANATTACK; - - for (child=node->children;child;child=child->next) { - if (strcmp((const char *)child->name, "ai")==0) { - parse_ai(rc, child); - } else if (strcmp((const char *)child->name, "param")==0) { - parse_param(&rc->parameters, child); - } - } - rc->recruit_multi = get_param_flt(rc->parameters, "recruit_multi", 1.0); - - /* reading eressea/races/race/skill */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "skill", xpath); - memset(rc->bonus, 0, sizeof(rc->bonus)); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - int mod = xml_ivalue(node, "modifier", 0); - int speed = xml_ivalue(node, "speed", study_speed_base); - skill_t sk; - - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - sk = sk_find((const char*)propValue); - if (sk!=NOSKILL) { - rc->bonus[sk] = (char)mod; - if (speed) { - if (!rc->study_speed) rc->study_speed = calloc(1, MAXSKILLS); - rc->study_speed[sk] = (char)speed; - } - } else { - log_error(("unknown skill '%s' in race '%s'\n", - (const char*)propValue, rc->_name[0])); - } - xmlFree(propValue); - } - xmlXPathFreeObject(result); - - if (gamecode_enabled) { - /* reading eressea/races/race/function */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - pf_generic fun; - - parse_function(node, &fun, &propValue); - if (fun==NULL) { - log_error(("unknown function name '%s' for race %s\n", - (const char*)propValue, rc->_name[0])); - xmlFree(propValue); - continue; - } - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "name")==0) { - rc->generate_name = (const char * (*)(const struct unit*))fun; - } else if (strcmp((const char*)propValue, "describe")==0) { - rc->describe = (const char * (*)(const struct unit*, const struct locale *))fun; - } else if (strcmp((const char*)propValue, "age")==0) { - rc->age = (void(*)(struct unit*))fun; - } else if (strcmp((const char*)propValue, "move")==0) { - rc->move_allowed = (boolean(*)(const struct region *, const struct region *))fun; - } else if (strcmp((const char*)propValue, "itemdrop")==0) { - rc->itemdrop = (struct item *(*)(const struct race *, int))fun; - } else if (strcmp((const char*)propValue, "initfamiliar")==0) { - rc->init_familiar = (void(*)(struct unit *))fun; - } else { - log_error(("unknown function type '%s' for race %s\n", - (const char*)propValue, rc->_name[0])); - } - xmlFree(propValue); - } - xmlXPathFreeObject(result); - } - - /* reading eressea/races/race/familiar */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "familiar", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - race * frc; - - propValue = xmlGetProp(node, BAD_CAST "race"); - assert(propValue!=NULL); - frc = rc_find((const char *)propValue); - if (frc == NULL) { -// log_error(("%s not registered, is familiar for %s\n", -// (const char*)propValue, rc->_name[0])); -// assert(frc!=NULL); - frc = rc_add(rc_new((const char*)propValue)); - } - if (xml_bvalue(node, "default", false)) { - rc->familiars[k] = rc->familiars[0]; - rc->familiars[0] = frc; - } else { - rc->familiars[k] = frc; - } - xmlFree(propValue); - } - xmlXPathFreeObject(result); - - /* reading eressea/races/race/precombatspell */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "precombatspell", xpath); - assert(rc->precombatspell==NULL || !"precombatspell is already initialized"); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - rc->precombatspell = xml_spell(node, "spell"); - } - xmlXPathFreeObject(result); - - /* reading eressea/races/race/attack */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "attack", xpath); - attack = rc->attack; - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - while (attack->type!=AT_NONE) ++attack; - - propValue = xmlGetProp(node, BAD_CAST "damage"); - if (propValue!=NULL) { - attack->data.dice = strdup((const char*)propValue); - xmlFree(propValue); - } else { - attack->data.sp = xml_spell(node, "spell"); - } - attack->type = xml_ivalue(node, "type", 0); - attack->flags = xml_ivalue(node, "flags", 0); - } - xmlXPathFreeObject(result); - } - xmlXPathFreeObject(races); - - xmlXPathFreeContext(xpath); - - race_compat(); - return 0; -} - -static int -parse_terrains(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath; - xmlXPathObjectPtr terrains; - xmlNodeSetPtr nodes; - int i; - - xpath = xmlXPathNewContext(doc); - - /* reading eressea/terrains/terrain */ - terrains = xmlXPathEvalExpression(BAD_CAST "/eressea/terrains/terrain", xpath); - nodes = terrains->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr node = nodes->nodeTab[i]; - terrain_type * terrain = calloc(1, sizeof(terrain_type)); - xmlChar * propValue; - xmlXPathObjectPtr xpathChildren; - xmlNodeSetPtr children; - - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - terrain->_name = strdup((const char *)propValue); - xmlFree(propValue); - - terrain->max_road = (short)xml_ivalue(node, "road", 0); - assert(terrain->max_road>=0); - terrain->size = xml_ivalue(node, "size", 0); - - if (xml_bvalue(node, "forbidden", false)) terrain->flags |= FORBIDDEN_REGION; - else { - if (xml_bvalue(node, "fly", true)) terrain->flags |= FLY_INTO; - if (xml_bvalue(node, "sail", true)) terrain->flags |= SAIL_INTO; - if (xml_bvalue(node, "walk", true)) terrain->flags |= WALK_INTO; - if (xml_bvalue(node, "swim", false)) terrain->flags |= SWIM_INTO; - if (xml_bvalue(node, "shallow", true)) terrain->flags |= LARGE_SHIPS; - if (xml_bvalue(node, "cavalry", false)) terrain->flags |= CAVALRY_REGION; - } - if (xml_bvalue(node, "sea", false)) terrain->flags |= SEA_REGION; - if (xml_bvalue(node, "arctic", false)) terrain->flags |= ARCTIC_REGION; - if (xml_bvalue(node, "land", true)) terrain->flags |= LAND_REGION; - if (xml_bvalue(node, "forest", false)) terrain->flags |= FOREST_REGION; - - terrain->distribution = (short)xml_ivalue(node, "seed", 0); - - xpath->node = node; - xpathChildren = xmlXPathEvalExpression(BAD_CAST "herb", xpath); - children = xpathChildren->nodesetval; - if (children->nodeNr>0) { - int k; - - terrain->herbs = malloc((children->nodeNr+1) * sizeof(item_type*)); - terrain->herbs[children->nodeNr] = NULL; - for (k=0;k!=children->nodeNr;++k) { - xmlNodePtr nodeHerb = children->nodeTab[k]; - const struct resource_type * rtype; - - propValue = xmlGetProp(nodeHerb, BAD_CAST "name"); - assert(propValue!=NULL); - rtype = rt_find((const char*)propValue); - assert(rtype!=NULL && rtype->itype!=NULL && fval(rtype->itype, ITF_HERB)); - terrain->herbs[k] = rtype->itype; - xmlFree(propValue); - } - } - xmlXPathFreeObject(xpathChildren); - - xpath->node = node; - xpathChildren = xmlXPathEvalExpression(BAD_CAST "resource", xpath); - children = xpathChildren->nodesetval; - if (children->nodeNr>0) { - int k; - - terrain->production = malloc((children->nodeNr+1) * sizeof(terrain_production)); - terrain->production[children->nodeNr].type = NULL; - for (k=0;k!=children->nodeNr;++k) { - xmlNodePtr nodeProd = children->nodeTab[k]; - - propValue = xmlGetProp(nodeProd, BAD_CAST "name"); - assert(propValue!=NULL); - terrain->production[k].type = rt_find((const char*)propValue); - assert(terrain->production[k].type); - xmlFree(propValue); - - propValue = xmlGetProp(nodeProd, BAD_CAST "level"); - assert(propValue); - terrain->production[k].startlevel = strdup((const char *)propValue); - xmlFree(propValue); - - propValue = xmlGetProp(nodeProd, BAD_CAST "base"); - assert(propValue); - terrain->production[k].base = strdup((const char *)propValue); - xmlFree(propValue); - - propValue = xmlGetProp(nodeProd, BAD_CAST "div"); - assert(propValue); - terrain->production[k].divisor = strdup((const char *)propValue); - xmlFree(propValue); - - terrain->production[k].chance = (float)xml_fvalue(nodeProd, "chance", 1.0); - } - } - xmlXPathFreeObject(xpathChildren); - - register_terrain(terrain); - } - xmlXPathFreeObject(terrains); - - xmlXPathFreeContext(xpath); - - init_terrains(); - return 0; -} - -static int -parse_messages(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath; - xmlXPathObjectPtr messages; - xmlNodeSetPtr nodes; - int i; - - if (!gamecode_enabled) return 0; - - xpath = xmlXPathNewContext(doc); - - /* reading eressea/messages/message */ - messages = xmlXPathEvalExpression(BAD_CAST "/eressea/messages/message", xpath); - nodes = messages->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr node = nodes->nodeTab[i]; - const char * default_section = "events"; - xmlChar * propSection; - xmlChar * propValue; - xmlXPathObjectPtr result; - int k; - char ** argv = NULL; - const message_type * mtype; - - /* arguments */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "type/arg", xpath); - if (result->nodesetval && result->nodesetval->nodeNr>0) { - argv = malloc(sizeof(char*)*(result->nodesetval->nodeNr+1)); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - char zBuffer[128]; - xmlChar * propName, * propType; - - propName = xmlGetProp(node, BAD_CAST "name"); - propType = xmlGetProp(node, BAD_CAST "type"); - sprintf(zBuffer, "%s:%s", (const char*)propName, (const char*)propType); - xmlFree(propName); - xmlFree(propType); - argv[k] = strdup(zBuffer); - } - argv[result->nodesetval->nodeNr] = NULL; - } - xmlXPathFreeObject(result); - - /* add the messagetype */ - propValue = xmlGetProp(node, BAD_CAST "name"); - mtype = mt_find((const char *)propValue); - if (mtype==NULL) { - mtype = mt_register(mt_new((const char *)propValue, (const char**)argv)); - } else { - assert(argv!=NULL || !"cannot redefine arguments of message now"); - } - xmlFree(propValue); - - /* register the type for the CR */ - crt_register(mtype); - - /* let's clean up the mess */ - if (argv!=NULL) { - for (k=0;argv[k]!=NULL;++k) free(argv[k]); - free(argv); - } - - propSection = xmlGetProp(node, BAD_CAST "section"); - if (propSection==NULL) propSection = BAD_CAST default_section; - - /* strings */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "text", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - struct locale * lang; - xmlChar * propText; - - xml_readtext(node, &lang, &propText); - if (lang) { - xml_cleanup_string(propText); - nrt_register(mtype, lang, (const char *)propText, 0, (const char*)propSection); - } - xmlFree(propText); - - } - xmlXPathFreeObject(result); - - if (propSection != BAD_CAST default_section) xmlFree(propSection); - } - - xmlXPathFreeObject(messages); - - xmlXPathFreeContext(xpath); - return 0; -} - -static void -xml_readstrings(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, boolean names) -{ - int i; - - for (i=0;i!=nodeNr;++i) { - xmlNodePtr stringNode = nodeTab[i]; - xmlChar * propName = xmlGetProp(stringNode, BAD_CAST "name"); - xmlChar * propNamespace = NULL; - xmlXPathObjectPtr result; - int k; - char zName[128]; - - assert(propName!=NULL); - if (names) propNamespace = xmlGetProp(stringNode->parent, BAD_CAST "name"); - mkname_buf((const char*)propNamespace, (const char*)propName, zName); - if (propNamespace!=NULL) xmlFree(propNamespace); - xmlFree(propName); - - /* strings */ - xpath->node = stringNode; - result = xmlXPathEvalExpression(BAD_CAST "text", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr textNode = result->nodesetval->nodeTab[k]; - struct locale * lang; - xmlChar * propText; - - xml_readtext(textNode, &lang, &propText); - if (propText!=NULL) { - assert(strcmp(zName, (const char*)xml_cleanup_string(BAD_CAST zName))==0); - if (lang) { - xml_cleanup_string(propText); - locale_setstring(lang, zName, (const char *)propText); - } - xmlFree(propText); - } else { - log_warning(("string %s has no text in locale %s\n", - zName, locale_name(lang))); - } - } - xmlXPathFreeObject(result); - } -} - -static int -parse_strings(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr strings; - - /* reading eressea/strings/string */ - strings = xmlXPathEvalExpression(BAD_CAST "/eressea/strings/string", xpath); - xml_readstrings(xpath, strings->nodesetval->nodeTab, strings->nodesetval->nodeNr, false); - xmlXPathFreeObject(strings); - - strings = xmlXPathEvalExpression(BAD_CAST "/eressea/strings/namespace/string", xpath); - xml_readstrings(xpath, strings->nodesetval->nodeTab, strings->nodesetval->nodeNr, true); - xmlXPathFreeObject(strings); - - xmlXPathFreeContext(xpath); - return 0; -} - -static void -xml_readprefixes(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, boolean names) -{ - int i; - - for (i=0;i!=nodeNr;++i) { - xmlNodePtr node = nodeTab[i]; - xmlChar * propText = xmlNodeListGetString(node->doc, node->children, 1); - - if (propText!=NULL) { - add_raceprefix((const char*)propText); - xmlFree(propText); - } - } -} - -static int -parse_prefixes(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr strings; - - /* reading eressea/strings/string */ - strings = xmlXPathEvalExpression(BAD_CAST "/eressea/prefixes/prefix", xpath); - xml_readprefixes(xpath, strings->nodesetval->nodeTab, strings->nodesetval->nodeNr, false); - xmlXPathFreeObject(strings); - - xmlXPathFreeContext(xpath); - return 0; -} - -static int -parse_main(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr result = xmlXPathEvalExpression(BAD_CAST "/eressea/game", xpath); - xmlNodeSetPtr nodes = result->nodesetval; - int i; - - xmlChar * propValue; - if (nodes->nodeNr>0) { - xmlNodePtr node = nodes->nodeTab[0]; - - global.producexpchance = (float)xml_fvalue(node, "learningbydoing", 1.0/3); - - propValue = xmlGetProp(node, BAD_CAST "name"); - if (propValue!=NULL) { - global.gamename = strdup((const char*)propValue); - xmlFree(propValue); - } - - xmlXPathFreeObject(result); - - /* reading eressea/game/param */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "param", xpath); - nodes = result->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr node = nodes->nodeTab[i]; - parse_param(&global.parameters, node); - } - - xmlXPathFreeObject(result); - - /* reading eressea/game/order */ - result = xmlXPathEvalExpression(BAD_CAST "order", xpath); - nodes = result->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr node = nodes->nodeTab[i]; - xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); - boolean disable = xml_bvalue(node, "disable", false); - - if (disable) { - int k; - for (k=0;k!=MAXKEYWORDS;++k) { - if (strcmp(keywords[k], (const char*)propName)==0) { - global.disabled[k]=1; - break; - } - } - if (k==MAXKEYWORDS) { - log_error(("trying to disable unknown comand %s\n", (const char*)propName)); - } - } - xmlFree(propName); - } - - xmlXPathFreeObject(result); - - /* reading eressea/game/skill */ - result = xmlXPathEvalExpression(BAD_CAST "skill", xpath); - nodes = result->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr node = nodes->nodeTab[i]; - xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); - boolean enable = xml_bvalue(node, "enable", true); - enable_skill((const char*)propName, enable); - xmlFree(propName); - } - } - xmlXPathFreeObject(result); - - xmlXPathFreeContext(xpath); - return 0; -} - -void -register_xmlreader(void) -{ - xml_register_callback(parse_main); - - xml_register_callback(parse_strings); - xml_register_callback(parse_prefixes); - xml_register_callback(parse_messages); - xml_register_callback(parse_resources); - xml_register_callback(parse_rules); - - xml_register_callback(parse_terrains); /* requires resources */ - xml_register_callback(parse_buildings); /* requires resources */ - xml_register_callback(parse_ships); /* requires terrains */ - xml_register_callback(parse_spells); /* requires resources */ - xml_register_callback(parse_equipment); /* requires spells */ - xml_register_callback(parse_races); /* requires spells */ - xml_register_callback(parse_calendar); - xml_register_callback(parse_directions); -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2004 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "xmlreader.h" + +/* kernel includes */ +#include "building.h" +#include "equipment.h" +#include "item.h" +#include "message.h" +#include "race.h" +#include "region.h" +#include "resources.h" +#include "ship.h" +#include "terrain.h" +#include "skill.h" +#include "spell.h" +#include "calendar.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include + + +/* libxml includes */ +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +static boolean gamecode_enabled = false; + +void (*set_spelldata_cb)(struct spell * sp) = 0; +static building_type * bt_get_or_create(const char * name) +{ + if (name!=NULL) { + building_type * btype = bt_find(name); + if (btype==NULL) { + btype = calloc(sizeof(building_type), 1); + btype->_name = strdup(name); + bt_register(btype); + } + return btype; + } + return NULL; +} + +void +enable_xml_gamecode(void) +{ + gamecode_enabled = true; +} + +static void +xml_readtext(xmlNodePtr node, struct locale ** lang, xmlChar **text) +{ + xmlChar * propValue = xmlGetProp(node, BAD_CAST "locale"); + assert(propValue!=NULL); + *lang = find_locale((const char*)propValue); +#ifdef MAKE_LOCALES + if (*lang==NULL) *lang = make_locale((const char*)propValue); +#endif + xmlFree(propValue); + + *text = xmlNodeListGetString(node->doc, node->children, 1); +} + +static const spell * +xml_spell(xmlNode * node, const char * name) +{ + const spell * sp = NULL; + xmlChar * propValue = xmlGetProp(node, BAD_CAST name); + if (propValue!=NULL) { + sp = find_spell(M_NONE, (const char *)propValue); + assert(sp); + xmlFree(propValue); + } + return sp; +} + +static xmlChar * +xml_cleanup_string(xmlChar * str) +{ + xmlChar * read = str; + xmlChar * write = str; + + while (*read) { + /* eat leading whitespace */ + if (*read && isxspace(*read)) { + while (*read && isxspace(*read)) { + ++read; + } + *write++ = ' '; + } + while (*read) { + if (*read== '\n') break; + if (*read== '\r') break; + *write++ = *read++; + } + } + *write = 0; + return str; +} + +static const resource_type * +rt_findorcreate(const char * name) +{ + resource_type * rtype = rt_find(name); + if (rtype==NULL) { + const char * names[2]; + char * namep = strcat(strcpy((char*)malloc(strlen(name)+3), name), "_p"); + /* we'll make a placeholder */ + names[0] = name; + names[1] = namep; + rtype = new_resourcetype(names, NULL, RTF_NONE); + free(namep); + } + return rtype; +} + +static void +xml_readrequirements(xmlNodePtr * nodeTab, int nodeNr, requirement ** reqArray) +{ + int req; + requirement * radd = *reqArray; + + assert (radd==NULL); + if (nodeNr==0) return; + + radd = *reqArray = calloc(sizeof(requirement), nodeNr+1); + + for (req=0;req!=nodeNr;++req) { + xmlNodePtr node = nodeTab[req]; + xmlChar * propValue; + + radd->number = xml_ivalue(node, "quantity", 1); + radd->recycle = xml_fvalue(node, "recycle", 0.5); + + propValue = xmlGetProp(node, BAD_CAST "type"); + radd->rtype = rt_findorcreate((const char*)propValue); + xmlFree(propValue); + + ++radd; + } +} + +void +xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, construction ** consPtr) +{ + xmlNodePtr pushNode = xpath->node; + int k; + for (k=0;k!=nodeSet->nodeNr;++k) { + xmlNodePtr node = nodeSet->nodeTab[k]; + xmlChar * propValue; + construction * con; + xmlXPathObjectPtr req; + int m; + skill_t sk = NOSKILL; + + propValue = xmlGetProp(node, BAD_CAST "skill"); + if (propValue!=NULL) { + sk = sk_find((const char*)propValue); + if (sk==NOSKILL) { + log_error(("construction requires skill '%s' that does not exist.\n", (const char *)propValue)); + xmlFree(propValue); + continue; + } + xmlFree(propValue); + } + + assert(*consPtr==NULL); + + *consPtr = con = calloc(sizeof(construction), 1); + consPtr = &con->improvement; + + con->skill = sk; + con->maxsize = xml_ivalue(node, "maxsize", -1); + con->minskill = xml_ivalue(node, "minskill", -1); + con->reqsize = xml_ivalue(node, "reqsize", -1); + + propValue = xmlGetProp(node, BAD_CAST "building"); + if (propValue!=NULL) { + con->btype = bt_get_or_create((const char*)propValue); + xmlFree(propValue); + } + + /* read construction/requirement */ + xpath->node = node; + req = xmlXPathEvalExpression(BAD_CAST "requirement", xpath); + xml_readrequirements(req->nodesetval->nodeTab, + req->nodesetval->nodeNr, &con->materials); + xmlXPathFreeObject(req); + + /* read construction/modifier */ + xpath->node = node; + req = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); + for (m=0;m!=req->nodesetval->nodeNr;++m) { + xmlNodePtr node = req->nodesetval->nodeTab[m]; + + propValue = xmlGetProp(node, BAD_CAST "function"); + if (propValue!=NULL) { + pf_generic foo = get_function((const char*)propValue); + a_add(&con->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION, (skillmod_fun)foo, 1.0, 0)); + xmlFree(propValue); + } + + } + xmlXPathFreeObject(req); + } + xpath->node = pushNode; +} + +static int +parse_function(xmlNodePtr node, pf_generic * funPtr, xmlChar ** namePtr) +{ + pf_generic fun; + xmlChar * propValue = xmlGetProp(node, BAD_CAST "value"); + assert(propValue!=NULL); + fun = get_function((const char*)propValue); + if (fun!=NULL) { + xmlFree(propValue); + + propValue = xmlGetProp(node, BAD_CAST "name"); + } + *namePtr = propValue; + *funPtr = fun; + return 0; +} + +static int +parse_buildings(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr buildings; + int i; + + /* reading eressea/buildings/building */ + buildings = xmlXPathEvalExpression(BAD_CAST "/eressea/buildings/building", xpath); + if (buildings->nodesetval!=NULL) { + xmlNodeSetPtr nodes = buildings->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + xmlChar * propValue; + building_type * btype; + xmlXPathObjectPtr result; + int k; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + btype = bt_get_or_create((const char*)propValue); + xmlFree(propValue); + + btype->capacity = xml_ivalue(node, "capacity", -1); + btype->maxcapacity = xml_ivalue(node, "maxcapacity", -1); + btype->maxsize = xml_ivalue(node, "maxsize", -1); + + btype->magres = xml_ivalue(node, "magres", 0); + btype->magresbonus = xml_ivalue(node, "magresbonus", 0); + btype->fumblebonus = xml_ivalue(node, "fumblebonus", 0); + btype->auraregen = xml_fvalue(node, "auraregen", 1.0); + + if (xml_bvalue(node, "nodestroy", false)) btype->flags |= BTF_INDESTRUCTIBLE; + if (xml_bvalue(node, "oneperturn", false)) btype->flags |= BTF_ONEPERTURN; + if (xml_bvalue(node, "nobuild", false)) btype->flags |= BTF_NOBUILD; + if (xml_bvalue(node, "namechange", true)) btype->flags |= BTF_NAMECHANGE; + if (xml_bvalue(node, "unique", false)) btype->flags |= BTF_UNIQUE; + if (xml_bvalue(node, "decay", false)) btype->flags |= BTF_DECAY; + if (xml_bvalue(node, "magic", false)) btype->flags |= BTF_MAGIC; + + /* reading eressea/buildings/building/construction */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); + xml_readconstruction(xpath, result->nodesetval, &btype->construction); + xmlXPathFreeObject(result); + + if (gamecode_enabled) { + /* reading eressea/buildings/building/function */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "function", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + pf_generic fun; + parse_function(node, &fun, &propValue); + + if (fun==NULL) { + log_error(("unknown function name '%s' for building %s\n", + (const char*)propValue, btype->_name)); + xmlFree(propValue); + continue; + } + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "name")==0) { + btype->name = (const char * (*)(const struct building_type*, const struct building *, int))fun; + } else if (strcmp((const char*)propValue, "init")==0) { + btype->init = (void (*)(struct building_type*))fun; + } else if (strcmp((const char*)propValue, "age")==0) { + btype->age = (void (*)(struct building*))fun; + } else if (strcmp((const char*)propValue, "protection")==0) { + btype->protection = (int (*)(struct building*, struct unit *))fun; + } else if (strcmp((const char*)propValue, "taxes")==0) { + btype->taxes = (double (*)(const struct building*, int))fun; + } else if (strcmp((const char*)propValue, "age")==0) { + btype->age = (void (*)(struct building*))fun; + } else { + log_error(("unknown function type '%s' for building %s\n", + (const char*)propValue, btype->_name)); + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + } + + /* reading eressea/buildings/building/maintenance */ + result = xmlXPathEvalExpression(BAD_CAST "maintenance", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + maintenance * mt; + + if (btype->maintenance==NULL) { + btype->maintenance = calloc(sizeof(struct maintenance), result->nodesetval->nodeNr+1); + } + mt = btype->maintenance + k; + mt->number = xml_ivalue(node, "amount", 0); + + propValue = xmlGetProp(node, BAD_CAST "type"); + assert(propValue!=NULL); + mt->rtype = rt_find((const char*)propValue); + assert(mt->rtype!=NULL); + xmlFree(propValue); + + if (xml_bvalue(node, "variable", false)) mt->flags |= MTF_VARIABLE; + if (xml_bvalue(node, "vital", false)) mt->flags |= MTF_VITAL; + + } + xmlXPathFreeObject(result); + + /* finally, initialize the new building type */ + if (btype->init) btype->init(btype); + } + } + xmlXPathFreeObject(buildings); + + xmlXPathFreeContext(xpath); + return 0; +} + +static int +parse_calendar(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr xpathCalendars; + xmlNodeSetPtr nsetCalendars; + int c, rv = 0; + + /* reading eressea/buildings/building */ + xpathCalendars = xmlXPathEvalExpression(BAD_CAST "/eressea/calendar", xpath); + nsetCalendars = xpathCalendars->nodesetval; + months_per_year = 0; + if (nsetCalendars==NULL || nsetCalendars->nodeNr==0) { + rv = -1; + } else for (c=0;c!=nsetCalendars->nodeNr;++c) { + xmlNodePtr calendar = nsetCalendars->nodeTab[c]; + xmlXPathObjectPtr xpathWeeks, xpathMonths, xpathSeasons; + xmlNodeSetPtr nsetWeeks, nsetMonths, nsetSeasons; + xmlChar * propValue = xmlGetProp(calendar, BAD_CAST "name"); + xmlChar * newyear = xmlGetProp(calendar, BAD_CAST "newyear"); + + first_turn = xml_ivalue(calendar, "start", first_turn); + if (propValue) { + free(agename); + agename = strdup(mkname("calendar", (const char*)propValue)); + xmlFree(propValue); + } + + xpath->node = calendar; + xpathWeeks = xmlXPathEvalExpression(BAD_CAST "week", xpath); + nsetWeeks = xpathWeeks->nodesetval; + if (nsetWeeks!=NULL && nsetWeeks->nodeNr) { + int i; + + weeks_per_month = nsetWeeks->nodeNr; + assert(!weeknames); + weeknames = malloc(sizeof(char *) * weeks_per_month); + weeknames2 = malloc(sizeof(char *) * weeks_per_month); + for (i=0;i!=nsetWeeks->nodeNr;++i) { + xmlNodePtr week = nsetWeeks->nodeTab[i]; + xmlChar * propValue = xmlGetProp(week, BAD_CAST "name"); + if (propValue) { + weeknames[i] = strdup(mkname("calendar", (const char*)propValue)); + weeknames2[i] = malloc(strlen(weeknames[i])+3); + sprintf(weeknames2[i], "%s_d", weeknames[i]); + xmlFree(propValue); + } + } + } + xmlXPathFreeObject(xpathWeeks); + + xpathSeasons = xmlXPathEvalExpression(BAD_CAST "season", xpath); + nsetSeasons = xpathSeasons->nodesetval; + if (nsetSeasons!=NULL && nsetSeasons->nodeNr) { + int i; + + seasons = nsetSeasons->nodeNr; + assert(!seasonnames); + seasonnames = malloc(sizeof(char *) * seasons); + + for (i=0;i!=nsetSeasons->nodeNr;++i) { + xmlNodePtr season = nsetSeasons->nodeTab[i]; + xmlChar * propValue = xmlGetProp(season, BAD_CAST "name"); + if (propValue) { + seasonnames[i] = strdup(mkname("calendar", (const char*)propValue)); + xmlFree(propValue); + } + } + } + + xpathMonths = xmlXPathEvalExpression(BAD_CAST "season/month", xpath); + nsetMonths = xpathMonths->nodesetval; + if (nsetMonths!=NULL && nsetMonths->nodeNr) { + int i; + + months_per_year = nsetMonths->nodeNr; + assert(!monthnames); + monthnames = malloc(sizeof(char *) * months_per_year); + month_season = malloc(sizeof(int) * months_per_year); + storms = malloc(sizeof(int) * months_per_year); + + for (i=0;i!=nsetMonths->nodeNr;++i) { + xmlNodePtr month = nsetMonths->nodeTab[i]; + xmlChar * propValue = xmlGetProp(month, BAD_CAST "name"); + int j; + + if (propValue) { + if (newyear && strcmp((const char*)newyear, (const char*)propValue)==0) { + first_month = i; + xmlFree(newyear); + newyear = NULL; + } + monthnames[i] = strdup(mkname("calendar", (const char*)propValue)); + xmlFree(propValue); + } + for (j=0;j!=seasons;++j) { + xmlNodePtr season = month->parent; + if (season==nsetSeasons->nodeTab[j]) { + month_season[i] = j; + break; + } + } + assert(j!=seasons); + storms[i] = xml_ivalue(nsetMonths->nodeTab[i], "storm", 0); + } + } + xmlXPathFreeObject(xpathMonths); + xmlXPathFreeObject(xpathSeasons); + } + xmlXPathFreeObject(xpathCalendars); + xmlXPathFreeContext(xpath); + + return rv; +} + +static int +parse_directions(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr xpathDirections; + xmlNodeSetPtr nsetDirections; + int rv = 0; + + /* reading eressea/directions/dir */ + xpathDirections = xmlXPathEvalExpression(BAD_CAST "/eressea/directions/dir", xpath); + nsetDirections = xpathDirections->nodesetval; + if (nsetDirections!=NULL) { + int k; + for (k=0;k!=nsetDirections->nodeNr;++k) { + xmlNodePtr dir = nsetDirections->nodeTab[k]; + xmlChar * propValue = xmlGetProp(dir, BAD_CAST "name"); + + register_special_direction((const char *)propValue); + xmlFree(propValue); + } + } + xmlXPathFreeObject(xpathDirections); + xmlXPathFreeContext(xpath); + + return rv; +} + +static int +parse_ships(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr ships; + int i; + + /* reading eressea/ships/ship */ + ships = xmlXPathEvalExpression(BAD_CAST "/eressea/ships/ship", xpath); + if (ships->nodesetval!=NULL) { + xmlNodeSetPtr nodes = ships->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr child, node = nodes->nodeTab[i]; + xmlChar * propValue; + ship_type * st = calloc(sizeof(ship_type), 1); + xmlXPathObjectPtr result; + int k, c; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + st->name[0] = strdup((const char *)propValue); + st->name[1] = strcat(strcpy(malloc(strlen(st->name[0])+3), st->name[0]),"_a"); + xmlFree(propValue); + + st->cabins = xml_ivalue(node, "cabins", 0) * PERSON_WEIGHT; + st->cargo = xml_ivalue(node, "cargo", 0); + st->combat = xml_ivalue(node, "combat", 0); + st->cptskill = xml_ivalue(node, "cptskill", 0); + st->damage = xml_fvalue(node, "damage", 0.0); + if (xml_bvalue(node, "nocoast", false)) st->flags |= SFL_NOCOAST; + if (xml_bvalue(node, "fly", false)) st->flags |= SFL_FLY; + if (xml_bvalue(node, "opensea", false)) st->flags |= SFL_OPENSEA; + st->fishing = xml_ivalue(node, "fishing", 0); + st->minskill = xml_ivalue(node, "minskill", 0); + st->range = xml_ivalue(node, "range", 0); + st->storm = xml_fvalue(node, "storm", 1.0); + st->sumskill = xml_ivalue(node, "sumskill", 0); + + /* reading eressea/ships/ship/construction */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); + xml_readconstruction(xpath, result->nodesetval, &st->construction); + xmlXPathFreeObject(result); + + for (child=node->children;child;child=child->next) { + if (strcmp((const char *)child->name, "modifier")==0) { + double value = xml_fvalue(child, "value", 0.0); + propValue = xmlGetProp(child, BAD_CAST "type"); + if (strcmp((const char *)propValue, "tactics")==0) st->tac_bonus = (float)value; + else if (strcmp((const char *)propValue, "attack")==0) st->at_bonus = (int)value; + else if (strcmp((const char *)propValue, "defense")==0) st->df_bonus = (int)value; + xmlFree(propValue); + } + } + /* reading eressea/ships/ship/coast */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "coast", xpath); + for (c=0,k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + + if (k==0) { + assert(st->coasts==NULL); + st->coasts = (const terrain_type**)malloc(sizeof(const terrain_type*) * (result->nodesetval->nodeNr+1)); + st->coasts[result->nodesetval->nodeNr] = NULL; + } + + propValue = xmlGetProp(node, BAD_CAST "terrain"); + assert(propValue!=NULL); + st->coasts[c] = get_terrain((const char*)propValue); + if (st->coasts[c]!=NULL) ++c; + else { + log_warning(("ship %s mentions a non-existing terrain %s.\n", st->name[0], propValue)); + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + + /* finally, register the new building type */ + st_register(st); + } + } + xmlXPathFreeObject(ships); + + xmlXPathFreeContext(xpath); + return 0; +} + +static void +race_compat(void) +{ + /* required for old_race, do not change order! */ + const char * oldracenames[MAXRACES] = { + "dwarf", "elf", NULL, "goblin", "human", "troll", "demon", "insect", + "halfling", "cat", "aquarian", "orc", "snotling", "undead", "illusion", + "youngdragon", "dragon", "wyrm", "ent", "catdragon", "dracoid", + "special", "spell", "irongolem", "stonegolem", "shadowdemon", + "shadowmaster", "mountainguard", "alp", "toad", "braineater", "peasant", + "wolf", NULL, NULL, NULL, NULL, "songdragon", NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, "seaserpent", + "shadowknight", "centaur", "skeleton", "skeletonlord", "zombie", + "juju-zombie", "ghoul", "ghast", "museumghost", "gnome", "template", + "clone" + }; + int i; + + for (i=0;i!=MAXRACES;++i) { + const char * rcname = oldracenames[i]; + if (rcname==NULL) { + new_race[i] = NULL; + } else { + race * rc = rc_find(oldracenames[i]); + if (rc) { + new_race[i] = rc; + if (rc == new_race[RC_TROLL]) { + a_add(&rc->attribs, make_skillmod(NOSKILL, SMF_RIDING, NULL, 0.0, -1)); + } + } + } + } +} + +static potion_type * +xml_readpotion(xmlXPathContextPtr xpath, item_type * itype) +{ + int level = xml_ivalue(xpath->node, "level", 0); + + assert(level>0); + return new_potiontype(itype, level); +} + +static luxury_type * +xml_readluxury(xmlXPathContextPtr xpath, item_type * itype) +{ + int price = xml_ivalue(xpath->node, "price", 0); + return new_luxurytype(itype, price); +} + + +static armor_type * +xml_readarmor(xmlXPathContextPtr xpath, item_type * itype) +{ + xmlNodePtr node = xpath->node; + armor_type * atype = NULL; + unsigned int flags = ATF_NONE; + int ac = xml_ivalue(node, "ac", 0); + double penalty = xml_fvalue(node, "penalty", 0.0); + double magres = xml_fvalue(node, "magres", 0.0); + + if (xml_bvalue(node, "laen", false)) flags |= ATF_LAEN; + if (xml_bvalue(node, "shield", false)) flags |= ATF_SHIELD; + + atype = new_armortype(itype, penalty, magres, ac, flags); + atype->projectile = (float)xml_fvalue(node, "projectile", 0.0); + return atype; +} + +static weapon_type * +xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) +{ + xmlNodePtr node = xpath->node; + weapon_type * wtype = NULL; + unsigned int flags = WTF_NONE; + xmlXPathObjectPtr result; + xmlChar * propValue; + int k; + skill_t sk; + int minskill = xml_ivalue(node, "minskill", 0); + int offmod = xml_ivalue(node, "offmod", 0); + int defmod = xml_ivalue(node, "defmod", 0); + int reload = xml_ivalue(node, "reload", 0); + double magres = xml_fvalue(node, "magres", 0.0); + + if (xml_bvalue(node, "armorpiercing", false)) flags |= WTF_ARMORPIERCING; + if (xml_bvalue(node, "magical", false)) flags |= WTF_MAGICAL; + if (xml_bvalue(node, "missile", false)) flags |= WTF_MISSILE; + if (xml_bvalue(node, "pierce", false)) flags |= WTF_PIERCE; + if (xml_bvalue(node, "cut", false)) flags |= WTF_CUT; + if (xml_bvalue(node, "blunt", false)) flags |= WTF_BLUNT; + if (xml_bvalue(node, "siege", false)) flags |= WTF_SIEGE; + if (xml_bvalue(node, "horse", (flags&WTF_MISSILE)==0)) flags |= WTF_HORSEBONUS; + if (xml_bvalue(node, "useshield", true)) flags |= WTF_USESHIELD; + + propValue = xmlGetProp(node, BAD_CAST "skill"); + assert(propValue!=NULL); + sk = sk_find((const char*)propValue); + assert(sk!=NOSKILL); + xmlFree(propValue); + + wtype = new_weapontype(itype, flags, magres, NULL, offmod, defmod, reload, sk, minskill); + + /* reading weapon/damage */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "damage", xpath); + assert(result->nodesetval->nodeNr<=2); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + int pos = 0; + + propValue = xmlGetProp(node, BAD_CAST "type"); + if (strcmp((const char *)propValue, "footman")!=0) { + pos = 1; + } + xmlFree(propValue); + + propValue = xmlGetProp(node, BAD_CAST "value"); + wtype->damage[pos] = gc_add(strdup((const char*)propValue)); + if (k==0) wtype->damage[1-pos] = wtype->damage[pos]; + xmlFree(propValue); + } + xmlXPathFreeObject(result); + + /* reading weapon/modifier */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); + assert(wtype->modifiers==NULL); + wtype->modifiers = calloc(result->nodesetval->nodeNr+1, sizeof(weapon_mod)); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + xmlXPathObjectPtr races; + int r, flags = 0; + + if (xml_bvalue(node, "walking", false)) flags|=WMF_WALKING; + if (xml_bvalue(node, "riding", false)) flags|=WMF_RIDING; + if (xml_bvalue(node, "against_walking", false)) flags|=WMF_AGAINST_WALKING; + if (xml_bvalue(node, "against_riding", false)) flags|=WMF_AGAINST_RIDING; + if (xml_bvalue(node, "offensive", false)) flags|=WMF_OFFENSIVE; + if (xml_bvalue(node, "defensive", false)) flags|=WMF_DEFENSIVE; + + propValue = xmlGetProp(node, BAD_CAST "type"); + if (strcmp((const char*)propValue, "damage")==0) flags|=WMF_DAMAGE; + else if (strcmp((const char*)propValue, "skill")==0) flags|=WMF_SKILL; + else if (strcmp((const char*)propValue, "missile_target")==0) flags|=WMF_MISSILE_TARGET; + xmlFree(propValue); + + wtype->modifiers[k].flags = flags; + wtype->modifiers[k].value = xml_ivalue(node, "value", 0); + + xpath->node = node; + races = xmlXPathEvalExpression(BAD_CAST "race", xpath); + for (r=0;r!=races->nodesetval->nodeNr;++r) { + xmlNodePtr node = races->nodesetval->nodeTab[r]; + + propValue = xmlGetProp(node, BAD_CAST "name"); + if (propValue!=NULL) { + const race * rc = rc_find((const char*)propValue); + if (rc==NULL) rc = rc_add(rc_new((const char*)propValue)); + racelist_insert(&wtype->modifiers[k].races, rc); + xmlFree(propValue); + } + } + xmlXPathFreeObject(races); + } + xmlXPathFreeObject(result); + + if (gamecode_enabled) { + /* reading weapon/function */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "function", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + xmlChar * propValue; + pf_generic fun; + + parse_function(node, &fun, &propValue); + if (fun==NULL) { + log_error(("unknown function name '%s' for item '%s'\n", + (const char*)propValue, itype->rtype->_name[0])); + xmlFree(propValue); + continue; + } + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "attack")==0) { + wtype->attack = (boolean (*)(const struct troop*, const struct weapon_type *, int*))fun; + } else { + log_error(("unknown function type '%s' for item '%s'\n", + (const char*)propValue, itype->rtype->_name[0])); + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + } + + xpath->node = node; + return wtype; +} + +static item_type * +xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) +{ + xmlNodePtr node = xpath->node; + item_type * itype = NULL; + unsigned int flags = ITF_NONE; + xmlXPathObjectPtr result; + int k; + + int weight = xml_ivalue(node, "weight", 0); + int capacity = xml_ivalue(node, "capacity", 0); + + if (xml_bvalue(node, "cursed", false)) flags |= ITF_CURSED; + if (xml_bvalue(node, "notlost", false)) flags |= ITF_NOTLOST; + if (xml_bvalue(node, "herb", false)) flags |= ITF_HERB; + if (xml_bvalue(node, "big", false)) flags |= ITF_BIG; + if (xml_bvalue(node, "animal", false)) flags |= ITF_ANIMAL; + if (xml_bvalue(node, "vehicle", false)) flags |= ITF_VEHICLE; + itype = new_itemtype(rtype, flags, weight, capacity); +#if SCORE_MODULE + itype->score = xml_ivalue(node, "score", 0); +#endif + + /* reading item/construction */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); + xml_readconstruction(xpath, result->nodesetval, &itype->construction); + xmlXPathFreeObject(result); + + /* reading item/weapon */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "weapon", xpath); + assert(result->nodesetval->nodeNr<=1); + if (result->nodesetval->nodeNr!=0) { + xpath->node = result->nodesetval->nodeTab[0]; + rtype->wtype = xml_readweapon(xpath, itype); + } + xmlXPathFreeObject(result); + + /* reading item/potion */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "potion", xpath); + assert(result->nodesetval->nodeNr<=1); + if (result->nodesetval->nodeNr!=0) { + xpath->node = result->nodesetval->nodeTab[0]; + rtype->ptype = xml_readpotion(xpath, itype); + } + xmlXPathFreeObject(result); + + /* reading item/luxury */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "luxury", xpath); + assert(result->nodesetval->nodeNr<=1); + if (result->nodesetval->nodeNr!=0) { + xpath->node = result->nodesetval->nodeTab[0]; + rtype->ltype = xml_readluxury(xpath, itype); + } + xmlXPathFreeObject(result); + + /* reading item/armor */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "armor", xpath); + assert(result->nodesetval->nodeNr<=1); + if (result->nodesetval->nodeNr!=0) { + xpath->node = result->nodesetval->nodeTab[0]; + rtype->atype = xml_readarmor(xpath, itype); + } + xmlXPathFreeObject(result); + + if (gamecode_enabled) { + /* reading item/function */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "function", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + xmlChar * propValue; + pf_generic fun; + + parse_function(node, &fun, &propValue); + if (fun==NULL) { + log_error(("unknown function name '%s' for item '%s'\n", + (const char*)propValue, rtype->_name[0])); + xmlFree(propValue); + continue; + } + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "give")==0) { + itype->give = (int (*)(struct unit*, struct unit*, const struct item_type *, int, struct order *))fun; + } else if (strcmp((const char*)propValue, "use")==0) { + itype->use = (int (*)(struct unit *, const struct item_type *, int, struct order *))fun; + } else if (strcmp((const char*)propValue, "canuse")==0) { + itype->canuse = (boolean (*)(const struct unit *, const struct item_type *))fun; + } else if (strcmp((const char*)propValue, "useonother")==0) { + itype->useonother = (int (*)(struct unit *, int, const struct item_type *, int, struct order *))fun; + } else { + log_error(("unknown function type '%s' for item '%s'\n", + (const char*)propValue, rtype->_name[0])); + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + } + + return itype; +} + +static int +parse_rules(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr functions; + xmlNodeSetPtr nodes; + int i; + + /* reading eressea/resources/resource */ + functions = xmlXPathEvalExpression(BAD_CAST "/eressea/rules/function", xpath); + nodes = functions->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + xmlChar *propValue; + pf_generic fun; + + parse_function(node, &fun, &propValue); + + if (fun==NULL) { + log_error(("unknown function for rule '%s' %s\n", (const char*)propValue)); + xmlFree(propValue); + continue; + } + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "wage")==0) { + global.functions.wage = (int (*)(const struct region*, const struct faction*, const struct race*, int))fun; + } else if (strcmp((const char*)propValue, "maintenance")==0) { + global.functions.maintenance = (int (*)(const struct unit*))fun; + } else { + log_error(("unknown function for rule '%s'\n", + (const char*)propValue)); + } + xmlFree(propValue); + } + xmlXPathFreeObject(functions); + xmlXPathFreeContext(xpath); + return 0; +} + +static int +parse_resources(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr resources; + xmlNodeSetPtr nodes; + int i; + + /* reading eressea/resources/resource */ + resources = xmlXPathEvalExpression(BAD_CAST "/eressea/resources/resource", xpath); + nodes = resources->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + xmlChar *propValue, *name, *appearance; + const char *names[2], *appearances[2]; + char * namep = NULL, * appearancep = NULL; + resource_type * rtype; + unsigned int flags = RTF_NONE; + xmlXPathObjectPtr result; + int k; + + if (xml_bvalue(node, "pooled", true)) flags |= RTF_POOLED; + if (xml_bvalue(node, "limited", false)) flags |= RTF_LIMITED; + + name = xmlGetProp(node, BAD_CAST "name"); + appearance = xmlGetProp(node, BAD_CAST "appearance"); + assert(name!=NULL); + + if (appearance!=NULL) { + appearancep = strcat(strcpy((char*)malloc(strlen((char*)appearance)+3), (char*)appearance), "_p"); + } + + rtype = rt_find((const char *)name); + if (rtype!=NULL) { + /* dependency from another item, was created earlier */ + rtype->flags |= flags; + if (appearance) { + rtype->_appearance[0] = strdup((const char*)appearance); + rtype->_appearance[1] = appearancep; + free(appearancep); + } + } else { + namep = strcat(strcpy((char*)malloc(strlen((char*)name)+3), (char*)name), "_p"); + names[0] = (const char*)name; + names[1] = namep; + if (appearance) { + appearances[0] = (const char*)appearance; + appearances[1] = appearancep; + rtype = new_resourcetype((const char**)names, (const char**)appearances, flags); + free(appearancep); + } else { + rtype = new_resourcetype(names, NULL, flags); + } + free(namep); + } + + if (name) xmlFree(name); + if (appearance) xmlFree(appearance); + + name = xmlGetProp(node, BAD_CAST "material"); + if (name) { + rmt_create(rtype, (const char *)name); + xmlFree(name); + } + + + if (gamecode_enabled) { + /* reading eressea/resources/resource/function */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "function", xpath); + if (result->nodesetval!=NULL) for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + pf_generic fun; + + parse_function(node, &fun, &propValue); + if (fun==NULL) { + log_error(("unknown function name '%s' for resource %s\n", + (const char*)propValue, rtype->_name[0])); + xmlFree(propValue); + continue; + } + + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "change")==0) { + rtype->uchange = (rtype_uchange)fun; + } else if (strcmp((const char*)propValue, "get")==0) { + rtype->uget = (rtype_uget)fun; + } else if (strcmp((const char*)propValue, "name")==0) { + rtype->name = (rtype_name)fun; + } else { + log_error(("unknown function type '%s' for resource %s\n", + (const char*)propValue, rtype->_name[0])); + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + } + + /* reading eressea/resources/resource/resourcelimit */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "resourcelimit", xpath); + assert(result->nodesetval->nodeNr<=1); + if (result->nodesetval->nodeNr!=0) { + resource_limit * rdata; + attrib * a = a_find(rtype->attribs, &at_resourcelimit); + xmlNodePtr limit = result->nodesetval->nodeTab[0]; + + if (a==NULL) a = a_add(&rtype->attribs, a_new(&at_resourcelimit)); + rdata = (resource_limit*)a->data.v; + rtype->flags |= RTF_LIMITED; + xpath->node = limit; + xmlXPathFreeObject(result); + + result = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); + if (result->nodesetval!=NULL) { + rdata->modifiers = calloc(result->nodesetval->nodeNr+1, sizeof(resource_mod)); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + building_type * btype = NULL; + const race * rc = NULL; + + propValue = xmlGetProp(node, BAD_CAST "race"); + if (propValue!=NULL) { + rc = rc_find((const char*)propValue); + if (rc==NULL) rc = rc_add(rc_new((const char*)propValue)); + xmlFree(propValue); + } + rdata->modifiers[k].race = rc; + + propValue = xmlGetProp(node, BAD_CAST "building"); + if (propValue!=NULL) { + btype = bt_get_or_create((const char*)propValue); + xmlFree(propValue); + } + rdata->modifiers[k].btype = btype; + + propValue = xmlGetProp(node, BAD_CAST "type"); + assert(propValue!=NULL); + if (strcmp((const char *)propValue, "skill")==0) { + rdata->modifiers[k].value.i = xml_ivalue(node, "value", 0); + rdata->modifiers[k].flags = RMF_SKILL; + } else if (strcmp((const char *)propValue, "material")==0) { + rdata->modifiers[k].value.f = (float)xml_fvalue(node, "value", 0); + rdata->modifiers[k].flags = RMF_SAVEMATERIAL; + } else if (strcmp((const char *)propValue, "resource")==0) { + rdata->modifiers[k].value.f = (float)xml_fvalue(node, "value", 0); + rdata->modifiers[k].flags = RMF_SAVERESOURCE; + } else if (strcmp((const char *)propValue, "require")==0) { + xmlChar * propBldg = xmlGetProp(node, BAD_CAST "building"); + if (propBldg!=NULL) { + btype = bt_get_or_create((const char*)propBldg); + rdata->modifiers[k].btype = btype; + rdata->modifiers[k].flags = RMF_REQUIREDBUILDING; + xmlFree(propBldg); + } + } else { + log_error(("unknown type '%s' for resourcelimit-modifier '%s'\n", + (const char*)propValue, rtype->_name[0])); + } + xmlFree(propValue); + } + } + xmlXPathFreeObject(result); + + result = xmlXPathEvalExpression(BAD_CAST "guard", xpath); + if (result->nodesetval!=NULL) for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + xmlChar * propFlag = xmlGetProp(node, BAD_CAST "flag"); + + if (propFlag!=NULL) { + if (strcmp((const char *)propFlag, "logging")==0) { + rdata->guard |= GUARD_TREES; + } else if (strcmp((const char *)propFlag, "mining")==0) { + rdata->guard |= GUARD_MINING; + } + xmlFree(propFlag); + } + } + xmlXPathFreeObject(result); + + /* reading eressea/resources/resource/resourcelimit/function */ + result = xmlXPathEvalExpression(BAD_CAST "function", xpath); + if (result->nodesetval!=NULL) for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + pf_generic fun; + + propValue = xmlGetProp(node, BAD_CAST "value"); + assert(propValue!=NULL); + fun = get_function((const char*)propValue); + if (fun==NULL) { + log_error(("unknown limit '%s' for resource %s\n", + (const char*)propValue, rtype->_name[0])); + xmlFree(propValue); + continue; + } + xmlFree(propValue); + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "produce")==0) { + rdata->produce = (rlimit_produce)fun; + } else if (strcmp((const char*)propValue, "limit")==0) { + rdata->limit = (rlimit_limit)fun; + } else { + log_error(("unknown limit '%s' for resource %s\n", + (const char*)propValue, rtype->_name[0])); + } + xmlFree(propValue); + } + } + xmlXPathFreeObject(result); + + /* reading eressea/resources/resource/resourcelimit/function */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "resourcelimit/function", xpath); + xmlXPathFreeObject(result); + + /* reading eressea/resources/resource/item */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "item", xpath); + assert(result->nodesetval->nodeNr<=1); + if (result->nodesetval->nodeNr!=0) { + rtype->flags |= RTF_ITEM; + xpath->node = result->nodesetval->nodeTab[0]; + rtype->itype = xml_readitem(xpath, rtype); + } + xmlXPathFreeObject(result); + } + xmlXPathFreeObject(resources); + + xmlXPathFreeContext(xpath); + + /* make sure old items (used in requirements) are available */ + init_resources(); + init_itemtypes(); + + return 0; +} + +static void +add_items(equipment * eq, xmlNodeSetPtr nsetItems) +{ + if (nsetItems!=NULL && nsetItems->nodeNr>0) { + int i; + for (i=0;i!=nsetItems->nodeNr;++i) { + xmlNodePtr node = nsetItems->nodeTab[i]; + xmlChar * propValue; + const struct item_type * itype; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + itype = it_find((const char*)propValue); + xmlFree(propValue); + if (itype!=NULL) { + propValue = xmlGetProp(node, BAD_CAST "amount"); + if (propValue!=NULL) { + equipment_setitem(eq, itype, (const char*)propValue); + xmlFree(propValue); + } + } + } + } +} + +static void +add_callbacks(equipment * eq, xmlNodeSetPtr nsetItems) +{ + if (nsetItems!=NULL && nsetItems->nodeNr>0) { + int i; + for (i=0;i!=nsetItems->nodeNr;++i) { + xmlNodePtr node = nsetItems->nodeTab[i]; + xmlChar * propValue; + pf_generic fun; + + propValue = xmlGetProp(node, BAD_CAST "name"); + if (propValue!=NULL) { + fun = get_function((const char*)propValue); + if (fun) { + equipment_setcallback(eq, (void (*)(const struct equipment *, struct unit *))fun); + } + xmlFree(propValue); + } + } + } +} + +static void +add_spells(equipment * eq, xmlNodeSetPtr nsetItems) +{ + if (nsetItems!=NULL && nsetItems->nodeNr>0) { + int i; + for (i=0;i!=nsetItems->nodeNr;++i) { + xmlNodePtr node = nsetItems->nodeTab[i]; + xmlChar * propValue; + magic_t mtype = M_NONE; + struct spell * sp; + + propValue = xmlGetProp(node, BAD_CAST "school"); + if (propValue!=NULL) { + for (mtype=0;mtype!=MAXMAGIETYP;++mtype) { + if (strcmp((const char*)propValue, magic_school[mtype])==0) break; + } + assert(mtype!=MAXMAGIETYP); + xmlFree(propValue); + } + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + sp = find_spell(mtype, (const char*)propValue); + assert(sp); + xmlFree(propValue); + if (sp!=NULL) { + equipment_addspell(eq, sp); + } + } + } +} + +static void +add_skills(equipment * eq, xmlNodeSetPtr nsetSkills) +{ + if (nsetSkills!=NULL && nsetSkills->nodeNr>0) { + int i; + for (i=0;i!=nsetSkills->nodeNr;++i) { + xmlNodePtr node = nsetSkills->nodeTab[i]; + xmlChar * propValue; + skill_t sk; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + sk = sk_find((const char*)propValue); + xmlFree(propValue); + if (sk!=NOSKILL) { + propValue = xmlGetProp(node, BAD_CAST "level"); + if (propValue!=NULL) { + equipment_setskill(eq, sk, (const char*)propValue); + xmlFree(propValue); + } + } + } + } +} + +static void +add_subsets(xmlDocPtr doc, equipment * eq, xmlNodeSetPtr nsetSubsets) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + if (nsetSubsets!=NULL && nsetSubsets->nodeNr>0) { + int i; + + eq->subsets = calloc(nsetSubsets->nodeNr+1, sizeof(subset)); + for (i=0;i!=nsetSubsets->nodeNr;++i) { + xmlXPathObjectPtr xpathResult; + xmlNodePtr node = nsetSubsets->nodeTab[i]; + xmlChar * propValue; + + eq->subsets[i].chance = 1.0f; + propValue = xmlGetProp(node, BAD_CAST "chance"); + if (propValue!=NULL) { + eq->subsets[i].chance = (float)atof((const char *)propValue); + xmlFree(propValue); + } + xpath->node = node; + xpathResult = xmlXPathEvalExpression(BAD_CAST "set", xpath); + if (xpathResult->nodesetval) { + xmlNodeSetPtr nsetSets = xpathResult->nodesetval; + float totalChance = 0.0f; + + if (nsetSets->nodeNr>0) { + int set; + eq->subsets[i].sets = calloc(nsetSets->nodeNr+1, sizeof(subsetitem)); + for (set=0;set!=nsetSets->nodeNr;++set) { + xmlNodePtr nodeSet = nsetSets->nodeTab[set]; + float chance = 1.0f; + + propValue = xmlGetProp(nodeSet, BAD_CAST "chance"); + if (propValue!=NULL) { + chance = (float)atof((const char *)propValue); + xmlFree(propValue); + } + totalChance += chance; + + propValue = xmlGetProp(nodeSet, BAD_CAST "name"); + assert(propValue!=NULL); + eq->subsets[i].sets[set].chance = chance; + eq->subsets[i].sets[set].set = create_equipment((const char*)propValue); + xmlFree(propValue); + } + } + if (totalChance>1.0f) { + log_error(("total chance exceeds 1.0: %f in equipment set %s.\n", + totalChance, eq->name)); + } + } + xmlXPathFreeObject(xpathResult); + } + } + xmlXPathFreeContext(xpath); +} + +static int +parse_equipment(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr xpathRaces; + + /* reading eressea/equipment/set */ + xpathRaces = xmlXPathEvalExpression(BAD_CAST "/eressea/equipment/set", xpath); + if (xpathRaces->nodesetval) { + xmlNodeSetPtr nsetRaces = xpathRaces->nodesetval; + int i; + + for (i=0;i!=nsetRaces->nodeNr;++i) { + xmlNodePtr node = nsetRaces->nodeTab[i]; + xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); + + if (propName!=NULL) { + equipment * eq = create_equipment((const char*)propName); + xmlXPathObjectPtr xpathResult; + + xpath->node = node; + + xpathResult = xmlXPathEvalExpression(BAD_CAST "callback", xpath); + assert(!eq->callback); + add_callbacks(eq, xpathResult->nodesetval); + xmlXPathFreeObject(xpathResult); + + xpathResult = xmlXPathEvalExpression(BAD_CAST "item", xpath); + assert(!eq->items); + add_items(eq, xpathResult->nodesetval); + xmlXPathFreeObject(xpathResult); + + xpathResult = xmlXPathEvalExpression(BAD_CAST "spell", xpath); + assert(!eq->spells); + add_spells(eq, xpathResult->nodesetval); + xmlXPathFreeObject(xpathResult); + + xpathResult = xmlXPathEvalExpression(BAD_CAST "skill", xpath); + add_skills(eq, xpathResult->nodesetval); + xmlXPathFreeObject(xpathResult); + + xpathResult = xmlXPathEvalExpression(BAD_CAST "subset", xpath); + assert(!eq->subsets); + add_subsets(doc, eq, xpathResult->nodesetval); + xmlXPathFreeObject(xpathResult); + + xmlFree(propName); + } + } + } + + xmlXPathFreeObject(xpathRaces); + xmlXPathFreeContext(xpath); + + return 0; +} + +static int +parse_spells(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr spells; + + /* reading eressea/spells/spell */ + spells = xmlXPathEvalExpression(BAD_CAST "/eressea/spells/spell", xpath); + if (spells->nodesetval!=NULL) { + xmlNodeSetPtr nodes = spells->nodesetval; + int i; + + for (i=0;i!=nodes->nodeNr;++i) { + xmlXPathObjectPtr result; + xmlNodePtr node = nodes->nodeTab[i]; + xmlChar * propValue; + int k; + spell * sp = calloc(1, sizeof(spell)); + static int modes[] = { 0, PRECOMBATSPELL, COMBATSPELL, POSTCOMBATSPELL }; + + /* spellname */ + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + sp->sname = strdup((const char*)propValue); + xmlFree(propValue); + + propValue = xmlGetProp(node, BAD_CAST "parameters"); + if (propValue) { + sp->parameter=strdup((const char *)propValue); + xmlFree(propValue); + } + + propValue = xmlGetProp(node, BAD_CAST "syntax"); + if (propValue) { + sp->syntax=strdup((const char *)propValue); + xmlFree(propValue); + } + + /* magic type */ + propValue = xmlGetProp(node, BAD_CAST "type"); + assert(propValue!=NULL); + for (sp->magietyp=0;sp->magietyp!=MAXMAGIETYP;++sp->magietyp) { + if (strcmp(magic_school[sp->magietyp], (const char *)propValue)==0) break; + } + assert(sp->magietyp!=MAXMAGIETYP); + xmlFree(propValue); + + /* level, rank and flags */ + sp->id = xml_ivalue(node, "index", 0); + sp->level = xml_ivalue(node, "level", -1); + sp->rank = (char)xml_ivalue(node, "rank", -1); + if (xml_bvalue(node, "los", false)) sp->sptyp |= TESTCANSEE; /* must see or have contact */ + if (!xml_bvalue(node, "target_global", false)) sp->sptyp |= SEARCHLOCAL; /* must be in same region */ + if (xml_bvalue(node, "ship", false)) sp->sptyp |= ONSHIPCAST; + if (xml_bvalue(node, "ocean", false)) sp->sptyp |= OCEANCASTABLE; + if (xml_bvalue(node, "far", false)) sp->sptyp |= FARCASTING; + if (xml_bvalue(node, "variable", false)) sp->sptyp |= SPELLLEVEL; + k = xml_ivalue(node, "combat", 0); + if (k>=0 && k<=3) sp->sptyp |= modes[k]; + + if (gamecode_enabled) { + /* reading eressea/spells/spell/function */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "function", xpath); + + if (result->nodesetval->nodeNr==0) { + /* deprecated style: this spell gets its' function from a callback */ + if (set_spelldata_cb) set_spelldata_cb(sp); + } else { + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + pf_generic fun; + + parse_function(node, &fun, &propValue); + if (fun==NULL) { + log_error(("unknown function name '%s' for spell '%s'\n", + (const char*)propValue, sp->sname)); + xmlFree(propValue); + continue; + } + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "cast")==0) { + sp->sp_function = (spell_f)fun; + } else if (strcmp((const char*)propValue, "fumble")==0) { + sp->patzer = (pspell_f)fun; + } else { + log_error(("unknown function type '%s' for spell %s\n", + (const char*)propValue, sp->sname)); + } + xmlFree(propValue); + } + } + xmlXPathFreeObject(result); + } + + /* reading eressea/spells/spell/resource */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "resource", xpath); + if (result->nodesetval->nodeNr) { + sp->components = malloc(sizeof(spell_component)*(result->nodesetval->nodeNr+1)); + sp->components[result->nodesetval->nodeNr].type = 0; + } + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue); + sp->components[k].type = rt_find((const char *)propValue); + assert(sp->components[k].type); + xmlFree(propValue); + sp->components[k].amount = xml_ivalue(node, "amount", 1); + sp->components[k].cost = SPC_FIX; + propValue = xmlGetProp(node, BAD_CAST "cost"); + if (propValue!=NULL) { + if (strcmp((const char *)propValue, "linear")==0) { + sp->components[k].cost = SPC_LINEAR; + } else if (strcmp((const char *)propValue, "level")==0) { + sp->components[k].cost = SPC_LEVEL; + } + xmlFree(propValue); + } + } + xmlXPathFreeObject(result); + register_spell(sp); + } + } + + xmlXPathFreeObject(spells); + + xmlXPathFreeContext(xpath); + + return 0; +} + +static void +parse_param(struct param ** params, xmlNodePtr node) +{ + xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); + xmlChar * propValue = xmlGetProp(node, BAD_CAST "value"); + + set_param(params, (const char*)propName, (const char*)propValue); + + xmlFree(propName); + xmlFree(propValue); +} + +static void +parse_ai(race * rc, xmlNodePtr node) +{ + rc->splitsize = xml_ivalue(node, "splitsize", 0); + rc->aggression = (float)xml_fvalue(node, "aggression", 0.04); + if (xml_bvalue(node, "killpeasants", false)) rc->flags |= RCF_KILLPEASANTS; + if (xml_bvalue(node, "moverandom", false)) rc->flags |= RCF_MOVERANDOM; + if (xml_bvalue(node, "learn", false)) rc->flags |= RCF_LEARN; +} + +static int +parse_races(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr races; + xmlNodeSetPtr nodes; + int i; + + /* reading eressea/races/race */ + races = xmlXPathEvalExpression(BAD_CAST "/eressea/races/race", xpath); + nodes = races->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + xmlNodePtr child; + xmlChar * propValue; + race * rc; + xmlXPathObjectPtr result; + int k, study_speed_base; + struct att * attack; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + rc = rc_find((const char*)propValue); + if (rc==NULL) rc = rc_add(rc_new((const char*)propValue)); + xmlFree(propValue); + + propValue = xmlGetProp(node, BAD_CAST "damage"); + assert(propValue!=NULL); + rc->def_damage = strdup((const char*)propValue); + xmlFree(propValue); + + rc->magres = (float)xml_fvalue(node, "magres", 0.0); + rc->maxaura = (float)xml_fvalue(node, "maxaura", 0.0); + rc->regaura = (float)xml_fvalue(node, "regaura", 1.0); + rc->recruitcost = xml_ivalue(node, "recruitcost", 0); + rc->maintenance = xml_ivalue(node, "maintenance", 0); + rc->weight = xml_ivalue(node, "weight", PERSON_WEIGHT); + rc->capacity = xml_ivalue(node, "capacity", 540); + rc->speed = (float)xml_fvalue(node, "speed", 1.0F); + rc->hitpoints = xml_ivalue(node, "hp", 0); + rc->armor = (char)xml_ivalue(node, "ac", 0); + study_speed_base = xml_ivalue(node, "studyspeed", 0); + + rc->at_default = (char)xml_ivalue(node, "unarmedattack", -2); + rc->df_default = (char)xml_ivalue(node, "unarmeddefense", -2); + rc->at_bonus = (char)xml_ivalue(node, "attackmodifier", 0); + rc->df_bonus = (char)xml_ivalue(node, "defensemodifier", 0); + + if (xml_bvalue(node, "playerrace", false)) rc->flags |= RCF_PLAYERRACE; + if (xml_bvalue(node, "scarepeasants", false)) rc->flags |= RCF_SCAREPEASANTS; + if (xml_bvalue(node, "cansteal", true)) rc->flags |= RCF_CANSTEAL; + if (xml_bvalue(node, "cansail", true)) rc->flags |= RCF_CANSAIL; + if (xml_bvalue(node, "cannotmove", false)) rc->flags |= RCF_CANNOTMOVE; + if (xml_bvalue(node, "fly", false)) rc->flags |= RCF_FLY; + if (xml_bvalue(node, "invisible", false)) rc->flags |= RCF_INVISIBLE; + if (xml_bvalue(node, "coastal", false)) rc->flags |= RCF_COASTAL; + if (xml_bvalue(node, "unarmedguard", false)) rc->flags |= RCF_UNARMEDGUARD; + if (xml_bvalue(node, "swim", false)) rc->flags |= RCF_SWIM; + if (xml_bvalue(node, "walk", false)) rc->flags |= RCF_WALK; + if (!xml_bvalue(node, "canlearn", true)) rc->flags |= RCF_NOLEARN; + if (!xml_bvalue(node, "canteach", true)) rc->flags |= RCF_NOTEACH; + if (xml_bvalue(node, "horse", false)) rc->flags |= RCF_HORSE; + if (xml_bvalue(node, "desert", false)) rc->flags |= RCF_DESERT; + if (xml_bvalue(node, "absorbpeasants", false)) rc->flags |= RCF_ABSORBPEASANTS; + if (xml_bvalue(node, "noheal", false)) rc->flags |= RCF_NOHEAL; + if (xml_bvalue(node, "noweapons", false)) rc->flags |= RCF_NOWEAPONS; + if (xml_bvalue(node, "shapeshift", false)) rc->flags |= RCF_SHAPESHIFT; + if (xml_bvalue(node, "shapeshiftany", false)) rc->flags |= RCF_SHAPESHIFTANY; + if (xml_bvalue(node, "illusionary", false)) rc->flags |= RCF_ILLUSIONARY; + if (xml_bvalue(node, "undead", false)) rc->flags |= RCF_UNDEAD; + if (xml_bvalue(node, "dragon", false)) rc->flags |= RCF_DRAGON; + if (xml_bvalue(node, "shipspeed", false)) rc->flags |= RCF_SHIPSPEED; + if (xml_bvalue(node, "stonegolem", false)) rc->flags |= RCF_STONEGOLEM; + if (xml_bvalue(node, "irongolem", false)) rc->flags |= RCF_IRONGOLEM; + + if (xml_bvalue(node, "giveitem", false)) rc->ec_flags |= GIVEITEM; + if (xml_bvalue(node, "giveperson", false)) rc->ec_flags |= GIVEPERSON; + if (xml_bvalue(node, "giveunit", false)) rc->ec_flags |= GIVEUNIT; + if (xml_bvalue(node, "getitem", false)) rc->ec_flags |= GETITEM; + if (xml_bvalue(node, "recruithorses", false)) rc->ec_flags |= ECF_REC_HORSES; + if (xml_bvalue(node, "recruitethereal", false)) rc->ec_flags |= ECF_REC_ETHEREAL; + if (xml_bvalue(node, "recruitunlimited", false)) rc->ec_flags |= ECF_REC_UNLIMITED; + + if (xml_bvalue(node, "equipment", false)) rc->battle_flags |= BF_EQUIPMENT; + if (xml_bvalue(node, "noblock", false)) rc->battle_flags |= BF_NOBLOCK; + if (xml_bvalue(node, "invinciblenonmagic", false)) rc->battle_flags |= BF_INV_NONMAGIC; + if (xml_bvalue(node, "resistbash", false)) rc->battle_flags |= BF_RES_BASH; + if (xml_bvalue(node, "resistcut", false)) rc->battle_flags |= BF_RES_CUT; + if (xml_bvalue(node, "resistpierce", false)) rc->battle_flags |= BF_RES_PIERCE; + if (xml_bvalue(node, "canattack", true)) rc->battle_flags |= BF_CANATTACK; + + for (child=node->children;child;child=child->next) { + if (strcmp((const char *)child->name, "ai")==0) { + parse_ai(rc, child); + } else if (strcmp((const char *)child->name, "param")==0) { + parse_param(&rc->parameters, child); + } + } + rc->recruit_multi = get_param_flt(rc->parameters, "recruit_multi", 1.0); + + /* reading eressea/races/race/skill */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "skill", xpath); + memset(rc->bonus, 0, sizeof(rc->bonus)); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + int mod = xml_ivalue(node, "modifier", 0); + int speed = xml_ivalue(node, "speed", study_speed_base); + skill_t sk; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + sk = sk_find((const char*)propValue); + if (sk!=NOSKILL) { + rc->bonus[sk] = (char)mod; + if (speed) { + if (!rc->study_speed) rc->study_speed = calloc(1, MAXSKILLS); + rc->study_speed[sk] = (char)speed; + } + } else { + log_error(("unknown skill '%s' in race '%s'\n", + (const char*)propValue, rc->_name[0])); + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + + if (gamecode_enabled) { + /* reading eressea/races/race/function */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "function", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + pf_generic fun; + + parse_function(node, &fun, &propValue); + if (fun==NULL) { + log_error(("unknown function name '%s' for race %s\n", + (const char*)propValue, rc->_name[0])); + xmlFree(propValue); + continue; + } + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "name")==0) { + rc->generate_name = (const char * (*)(const struct unit*))fun; + } else if (strcmp((const char*)propValue, "describe")==0) { + rc->describe = (const char * (*)(const struct unit*, const struct locale *))fun; + } else if (strcmp((const char*)propValue, "age")==0) { + rc->age = (void(*)(struct unit*))fun; + } else if (strcmp((const char*)propValue, "move")==0) { + rc->move_allowed = (boolean(*)(const struct region *, const struct region *))fun; + } else if (strcmp((const char*)propValue, "itemdrop")==0) { + rc->itemdrop = (struct item *(*)(const struct race *, int))fun; + } else if (strcmp((const char*)propValue, "initfamiliar")==0) { + rc->init_familiar = (void(*)(struct unit *))fun; + } else { + log_error(("unknown function type '%s' for race %s\n", + (const char*)propValue, rc->_name[0])); + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + } + + /* reading eressea/races/race/familiar */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "familiar", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + race * frc; + + propValue = xmlGetProp(node, BAD_CAST "race"); + assert(propValue!=NULL); + frc = rc_find((const char *)propValue); + if (frc == NULL) { +// log_error(("%s not registered, is familiar for %s\n", +// (const char*)propValue, rc->_name[0])); +// assert(frc!=NULL); + frc = rc_add(rc_new((const char*)propValue)); + } + if (xml_bvalue(node, "default", false)) { + rc->familiars[k] = rc->familiars[0]; + rc->familiars[0] = frc; + } else { + rc->familiars[k] = frc; + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + + /* reading eressea/races/race/precombatspell */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "precombatspell", xpath); + assert(rc->precombatspell==NULL || !"precombatspell is already initialized"); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + rc->precombatspell = xml_spell(node, "spell"); + } + xmlXPathFreeObject(result); + + /* reading eressea/races/race/attack */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "attack", xpath); + attack = rc->attack; + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + while (attack->type!=AT_NONE) ++attack; + + propValue = xmlGetProp(node, BAD_CAST "damage"); + if (propValue!=NULL) { + attack->data.dice = strdup((const char*)propValue); + xmlFree(propValue); + } else { + attack->data.sp = xml_spell(node, "spell"); + } + attack->type = xml_ivalue(node, "type", 0); + attack->flags = xml_ivalue(node, "flags", 0); + } + xmlXPathFreeObject(result); + } + xmlXPathFreeObject(races); + + xmlXPathFreeContext(xpath); + + race_compat(); + return 0; +} + +static int +parse_terrains(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath; + xmlXPathObjectPtr terrains; + xmlNodeSetPtr nodes; + int i; + + xpath = xmlXPathNewContext(doc); + + /* reading eressea/terrains/terrain */ + terrains = xmlXPathEvalExpression(BAD_CAST "/eressea/terrains/terrain", xpath); + nodes = terrains->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + terrain_type * terrain = calloc(1, sizeof(terrain_type)); + xmlChar * propValue; + xmlXPathObjectPtr xpathChildren; + xmlNodeSetPtr children; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + terrain->_name = strdup((const char *)propValue); + xmlFree(propValue); + + terrain->max_road = (short)xml_ivalue(node, "road", 0); + assert(terrain->max_road>=0); + terrain->size = xml_ivalue(node, "size", 0); + + if (xml_bvalue(node, "forbidden", false)) terrain->flags |= FORBIDDEN_REGION; + else { + if (xml_bvalue(node, "fly", true)) terrain->flags |= FLY_INTO; + if (xml_bvalue(node, "sail", true)) terrain->flags |= SAIL_INTO; + if (xml_bvalue(node, "walk", true)) terrain->flags |= WALK_INTO; + if (xml_bvalue(node, "swim", false)) terrain->flags |= SWIM_INTO; + if (xml_bvalue(node, "shallow", true)) terrain->flags |= LARGE_SHIPS; + if (xml_bvalue(node, "cavalry", false)) terrain->flags |= CAVALRY_REGION; + } + if (xml_bvalue(node, "sea", false)) terrain->flags |= SEA_REGION; + if (xml_bvalue(node, "arctic", false)) terrain->flags |= ARCTIC_REGION; + if (xml_bvalue(node, "land", true)) terrain->flags |= LAND_REGION; + if (xml_bvalue(node, "forest", false)) terrain->flags |= FOREST_REGION; + + terrain->distribution = (short)xml_ivalue(node, "seed", 0); + + xpath->node = node; + xpathChildren = xmlXPathEvalExpression(BAD_CAST "herb", xpath); + children = xpathChildren->nodesetval; + if (children->nodeNr>0) { + int k; + + terrain->herbs = malloc((children->nodeNr+1) * sizeof(item_type*)); + terrain->herbs[children->nodeNr] = NULL; + for (k=0;k!=children->nodeNr;++k) { + xmlNodePtr nodeHerb = children->nodeTab[k]; + const struct resource_type * rtype; + + propValue = xmlGetProp(nodeHerb, BAD_CAST "name"); + assert(propValue!=NULL); + rtype = rt_find((const char*)propValue); + assert(rtype!=NULL && rtype->itype!=NULL && fval(rtype->itype, ITF_HERB)); + terrain->herbs[k] = rtype->itype; + xmlFree(propValue); + } + } + xmlXPathFreeObject(xpathChildren); + + xpath->node = node; + xpathChildren = xmlXPathEvalExpression(BAD_CAST "resource", xpath); + children = xpathChildren->nodesetval; + if (children->nodeNr>0) { + int k; + + terrain->production = malloc((children->nodeNr+1) * sizeof(terrain_production)); + terrain->production[children->nodeNr].type = NULL; + for (k=0;k!=children->nodeNr;++k) { + xmlNodePtr nodeProd = children->nodeTab[k]; + + propValue = xmlGetProp(nodeProd, BAD_CAST "name"); + assert(propValue!=NULL); + terrain->production[k].type = rt_find((const char*)propValue); + assert(terrain->production[k].type); + xmlFree(propValue); + + propValue = xmlGetProp(nodeProd, BAD_CAST "level"); + assert(propValue); + terrain->production[k].startlevel = strdup((const char *)propValue); + xmlFree(propValue); + + propValue = xmlGetProp(nodeProd, BAD_CAST "base"); + assert(propValue); + terrain->production[k].base = strdup((const char *)propValue); + xmlFree(propValue); + + propValue = xmlGetProp(nodeProd, BAD_CAST "div"); + assert(propValue); + terrain->production[k].divisor = strdup((const char *)propValue); + xmlFree(propValue); + + terrain->production[k].chance = (float)xml_fvalue(nodeProd, "chance", 1.0); + } + } + xmlXPathFreeObject(xpathChildren); + + register_terrain(terrain); + } + xmlXPathFreeObject(terrains); + + xmlXPathFreeContext(xpath); + + init_terrains(); + return 0; +} + +static int +parse_messages(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath; + xmlXPathObjectPtr messages; + xmlNodeSetPtr nodes; + int i; + + if (!gamecode_enabled) return 0; + + xpath = xmlXPathNewContext(doc); + + /* reading eressea/messages/message */ + messages = xmlXPathEvalExpression(BAD_CAST "/eressea/messages/message", xpath); + nodes = messages->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + const char * default_section = "events"; + xmlChar * propSection; + xmlChar * propValue; + xmlXPathObjectPtr result; + int k; + char ** argv = NULL; + const message_type * mtype; + + /* arguments */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "type/arg", xpath); + if (result->nodesetval && result->nodesetval->nodeNr>0) { + argv = malloc(sizeof(char*)*(result->nodesetval->nodeNr+1)); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + char zBuffer[128]; + xmlChar * propName, * propType; + + propName = xmlGetProp(node, BAD_CAST "name"); + propType = xmlGetProp(node, BAD_CAST "type"); + sprintf(zBuffer, "%s:%s", (const char*)propName, (const char*)propType); + xmlFree(propName); + xmlFree(propType); + argv[k] = strdup(zBuffer); + } + argv[result->nodesetval->nodeNr] = NULL; + } + xmlXPathFreeObject(result); + + /* add the messagetype */ + propValue = xmlGetProp(node, BAD_CAST "name"); + mtype = mt_find((const char *)propValue); + if (mtype==NULL) { + mtype = mt_register(mt_new((const char *)propValue, (const char**)argv)); + } else { + assert(argv!=NULL || !"cannot redefine arguments of message now"); + } + xmlFree(propValue); + + /* register the type for the CR */ + crt_register(mtype); + + /* let's clean up the mess */ + if (argv!=NULL) { + for (k=0;argv[k]!=NULL;++k) free(argv[k]); + free(argv); + } + + propSection = xmlGetProp(node, BAD_CAST "section"); + if (propSection==NULL) propSection = BAD_CAST default_section; + + /* strings */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "text", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + struct locale * lang; + xmlChar * propText; + + xml_readtext(node, &lang, &propText); + if (lang) { + xml_cleanup_string(propText); + nrt_register(mtype, lang, (const char *)propText, 0, (const char*)propSection); + } + xmlFree(propText); + + } + xmlXPathFreeObject(result); + + if (propSection != BAD_CAST default_section) xmlFree(propSection); + } + + xmlXPathFreeObject(messages); + + xmlXPathFreeContext(xpath); + return 0; +} + +static void +xml_readstrings(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, boolean names) +{ + int i; + + for (i=0;i!=nodeNr;++i) { + xmlNodePtr stringNode = nodeTab[i]; + xmlChar * propName = xmlGetProp(stringNode, BAD_CAST "name"); + xmlChar * propNamespace = NULL; + xmlXPathObjectPtr result; + int k; + char zName[128]; + + assert(propName!=NULL); + if (names) propNamespace = xmlGetProp(stringNode->parent, BAD_CAST "name"); + mkname_buf((const char*)propNamespace, (const char*)propName, zName); + if (propNamespace!=NULL) xmlFree(propNamespace); + xmlFree(propName); + + /* strings */ + xpath->node = stringNode; + result = xmlXPathEvalExpression(BAD_CAST "text", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr textNode = result->nodesetval->nodeTab[k]; + struct locale * lang; + xmlChar * propText; + + xml_readtext(textNode, &lang, &propText); + if (propText!=NULL) { + assert(strcmp(zName, (const char*)xml_cleanup_string(BAD_CAST zName))==0); + if (lang) { + xml_cleanup_string(propText); + locale_setstring(lang, zName, (const char *)propText); + } + xmlFree(propText); + } else { + log_warning(("string %s has no text in locale %s\n", + zName, locale_name(lang))); + } + } + xmlXPathFreeObject(result); + } +} + +static int +parse_strings(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr strings; + + /* reading eressea/strings/string */ + strings = xmlXPathEvalExpression(BAD_CAST "/eressea/strings/string", xpath); + xml_readstrings(xpath, strings->nodesetval->nodeTab, strings->nodesetval->nodeNr, false); + xmlXPathFreeObject(strings); + + strings = xmlXPathEvalExpression(BAD_CAST "/eressea/strings/namespace/string", xpath); + xml_readstrings(xpath, strings->nodesetval->nodeTab, strings->nodesetval->nodeNr, true); + xmlXPathFreeObject(strings); + + xmlXPathFreeContext(xpath); + return 0; +} + +static void +xml_readprefixes(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, boolean names) +{ + int i; + + for (i=0;i!=nodeNr;++i) { + xmlNodePtr node = nodeTab[i]; + xmlChar * propText = xmlNodeListGetString(node->doc, node->children, 1); + + if (propText!=NULL) { + add_raceprefix((const char*)propText); + xmlFree(propText); + } + } +} + +static int +parse_prefixes(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr strings; + + /* reading eressea/strings/string */ + strings = xmlXPathEvalExpression(BAD_CAST "/eressea/prefixes/prefix", xpath); + xml_readprefixes(xpath, strings->nodesetval->nodeTab, strings->nodesetval->nodeNr, false); + xmlXPathFreeObject(strings); + + xmlXPathFreeContext(xpath); + return 0; +} + +static int +parse_main(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr result = xmlXPathEvalExpression(BAD_CAST "/eressea/game", xpath); + xmlNodeSetPtr nodes = result->nodesetval; + int i; + + xmlChar * propValue; + if (nodes->nodeNr>0) { + xmlNodePtr node = nodes->nodeTab[0]; + + global.producexpchance = (float)xml_fvalue(node, "learningbydoing", 1.0/3); + + propValue = xmlGetProp(node, BAD_CAST "name"); + if (propValue!=NULL) { + global.gamename = strdup((const char*)propValue); + xmlFree(propValue); + } + + xmlXPathFreeObject(result); + + /* reading eressea/game/param */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "param", xpath); + nodes = result->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + parse_param(&global.parameters, node); + } + + xmlXPathFreeObject(result); + + /* reading eressea/game/order */ + result = xmlXPathEvalExpression(BAD_CAST "order", xpath); + nodes = result->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); + boolean disable = xml_bvalue(node, "disable", false); + + if (disable) { + int k; + for (k=0;k!=MAXKEYWORDS;++k) { + if (strcmp(keywords[k], (const char*)propName)==0) { + global.disabled[k]=1; + break; + } + } + if (k==MAXKEYWORDS) { + log_error(("trying to disable unknown comand %s\n", (const char*)propName)); + } + } + xmlFree(propName); + } + + xmlXPathFreeObject(result); + + /* reading eressea/game/skill */ + result = xmlXPathEvalExpression(BAD_CAST "skill", xpath); + nodes = result->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); + boolean enable = xml_bvalue(node, "enable", true); + enable_skill((const char*)propName, enable); + xmlFree(propName); + } + } + xmlXPathFreeObject(result); + + xmlXPathFreeContext(xpath); + return 0; +} + +void +register_xmlreader(void) +{ + xml_register_callback(parse_main); + + xml_register_callback(parse_strings); + xml_register_callback(parse_prefixes); + xml_register_callback(parse_messages); + xml_register_callback(parse_resources); + xml_register_callback(parse_rules); + + xml_register_callback(parse_terrains); /* requires resources */ + xml_register_callback(parse_buildings); /* requires resources */ + xml_register_callback(parse_ships); /* requires terrains */ + xml_register_callback(parse_spells); /* requires resources */ + xml_register_callback(parse_equipment); /* requires spells */ + xml_register_callback(parse_races); /* requires spells */ + xml_register_callback(parse_calendar); + xml_register_callback(parse_directions); +} diff --git a/src/kernel/xmlreader.h b/src/kernel/xmlreader.h index 4c4457da1..8dfb85dfe 100644 --- a/src/kernel/xmlreader.h +++ b/src/kernel/xmlreader.h @@ -1,27 +1,28 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2007 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifndef H_KRNL_XMLREADER_H -#define H_KRNL_XMLREADER_H -#ifdef __cplusplus -extern "C" { -#endif - extern void register_xmlreader(void); - extern void enable_xml_gamecode(void); - - /* game-specific callbacks */ - extern void (*set_spelldata_cb)(struct spell * sp); -#ifdef __cplusplus -} -#endif - -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2007 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifndef H_KRNL_XMLREADER_H +#define H_KRNL_XMLREADER_H + +#ifdef __cplusplus +extern "C" { +#endif + extern void register_xmlreader(void); + extern void enable_xml_gamecode(void); + + /* game-specific callbacks */ + extern void (*set_spelldata_cb)(struct spell * sp); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lua-bindings.vcproj b/src/lua-bindings.vcproj index 73fec767d..d62f13a90 100644 --- a/src/lua-bindings.vcproj +++ b/src/lua-bindings.vcproj @@ -1,274 +1,274 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/lua-bindings.vcxproj b/src/lua-bindings.vcxproj index 54e5c4332..3929ae569 100644 --- a/src/lua-bindings.vcxproj +++ b/src/lua-bindings.vcxproj @@ -1,125 +1,124 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {75501170-51C2-E641-BA8B-EDC008184192} - lua-bindings - Win32Proj - - - - StaticLibrary - MultiByte - - - StaticLibrary - MultiByte - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - - - - /MP %(AdditionalOptions) - Disabled - .;../../external;%(AdditionalIncludeDirectories) - WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - true - - - Level4 - true - EditAndContinue - - - WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - .;%(AdditionalIncludeDirectories) - - - $(OutDir)lua-bindings.lib - - - - - Full - .;../../external;%(AdditionalIncludeDirectories) - WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) - true - MultiThreadedDLL - true - - - Level4 - - - - - WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) - .;%(AdditionalIncludeDirectories) - - - $(OutDir)lua-bindings.lib - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + + {75501170-51C2-E641-BA8B-EDC008184192} + lua-bindings + Win32Proj + + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + + + + /MP %(AdditionalOptions) + Disabled + .;../../external;../../external/lua/src;../../external/tolua/include;..\..\external\pdcurses;..\..\external\libxml2\include;%(AdditionalIncludeDirectories) + WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + true + + + Level4 + true + EditAndContinue + + + WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + .;%(AdditionalIncludeDirectories) + + + $(OutDir)lua-bindings.lib + + + + + Full + .;../../external;../../external/lua/src;../../external/tolua/include;..\..\external\pdcurses;..\..\external\libxml2\include;%(AdditionalIncludeDirectories) + WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + + + Level4 + + + + + WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) + .;%(AdditionalIncludeDirectories) + + + $(OutDir)lua-bindings.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/lua-bindings.vcxproj.filters b/src/lua-bindings.vcxproj.filters index e7b96c870..cb23911a8 100644 --- a/src/lua-bindings.vcxproj.filters +++ b/src/lua-bindings.vcxproj.filters @@ -1,95 +1,95 @@ - - - - - {1a17299b-610f-40df-864f-84b37b67ebe7} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {5135c52b-b087-4aab-8d89-2b06da54e8e7} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - + + + + + {1a17299b-610f-40df-864f-84b37b67ebe7} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {5135c52b-b087-4aab-8d89-2b06da54e8e7} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + \ No newline at end of file diff --git a/src/modules/arena.c b/src/modules/arena.c index 84081797e..d7f817fab 100644 --- a/src/modules/arena.c +++ b/src/modules/arena.c @@ -1,527 +1,527 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include - -#if ARENA_MODULE -#include "arena.h" - -/* modules include */ -#include "score.h" - -/* attributes include */ -#include - -/* items include */ -#include - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util include */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc include */ -#include -#include -#include - - -/* exports: */ -plane * arena = NULL; - - -/* local vars */ -#define CENTRAL_VOLCANO 1 - -#ifdef ARENA_CREATION -static unsigned int arena_id = 0; -static region * arena_center = NULL; -static int newarena = 0; -#endif -static region * tower_region[6]; -static region * start_region[6]; - -static region * -arena_region(int school) -{ - return tower_region[school]; -} - -static building * -arena_tower(int school) -{ - return arena_region(school)->buildings; -} - -static int -leave_fail(unit * u) -{ - ADDMSG(&u->faction->msgs, msg_message("arena_leave_fail", "unit", u)); - return 1; -} - -static int -leave_arena(struct unit * u, const struct item_type * itype, int amount, order * ord) -{ - if (!u->building && leave_fail(u)) return -1; - if (u->building!=arena_tower(u->faction->magiegebiet) && leave_fail(u)) return -1; - unused(amount); - unused(ord); - unused(itype); - assert(!"not implemented"); - return 0; -} - -static int -enter_fail(unit * u) -{ - ADDMSG(&u->faction->msgs, msg_message("arena_enter_fail", "region unit", u->region, u)); - return 1; -} - -static int -enter_arena(unit * u, const item_type * itype, int amount, order * ord) -{ - skill_t sk; - region * r = u->region; - unit * u2; - int fee = u->faction->score / 5; - unused(ord); - unused(amount); - unused(itype); - if (fee>2000) fee = 2000; - if (getplane(r)==arena) return -1; - if (u->number!=1 && enter_fail(u)) return -1; - if (get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, fee) < fee && enter_fail(u)) return -1; - for (sk=0;sk!=MAXSKILLS;++sk) { - if (get_level(u, sk)>1 && enter_fail(u)) return -1; - } - for (u2=r->units;u2;u2=u2->next) if (u2->faction==u->faction) break; - - assert(!"not implemented"); -/* - for (res=0;res!=MAXRESOURCES;++res) if (res!=R_SILVER && res!=R_ARENA_GATE && (is_item(res) || is_herb(res) || is_potion(res))) { - int x = get_resource(u, res); - if (x) { - if (u2) { - change_resource(u2, res, x); - change_resource(u, res, -x); - } - else if (enter_fail(u)) return -1; - } - } -*/ - if (get_money(u) > fee) { - if (u2) change_money(u2, get_money(u) - fee); - else if (enter_fail(u)) return -1; - } - ADDMSG(&u->faction->msgs, msg_message("arena_enter_fail", "region unit", u->region, u)); - use_pooled(u, itype->rtype, GET_SLACK|GET_RESERVE, 1); - use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, fee); - set_money(u, 109); - fset(u, UFL_ANON_FACTION); - move_unit(u, start_region[rng_int() % 6], NULL); - return 0; -} - -/*** - ** Szepter der Tränen, Demo-Item - ***/ - -static int -use_wand_of_tears(unit * user, const struct item_type * itype, int amount, order * ord) -{ - int n; - unused(ord); - for (n=0;n!=amount;++n) { - unit * u; - for (u=user->region->units;u;u=u->next) { - if (u->faction != user->faction) { - int i; - - for (i=0;i!=u->skill_size;++i) { - if (rng_int()%3) reduce_skill(u, u->skills+i, 1); - } - ADDMSG(&u->faction->msgs, msg_message("wand_of_tears_effect", - "unit", u)); - } - } - } - ADDMSG(&user->region->msgs, msg_message("wand_of_tears_usage", - "unit", user)); - return 0; -} - -/** - * Tempel der Schreie, Demo-Gebäude **/ - -static int -age_hurting(attrib * a) { - building * b = (building *)a->data.v; - unit * u; - int active = 0; - if (b==NULL) return AT_AGE_REMOVE; - for (u=b->region->units;u;u=u->next) { - if (u->building==b) { - if (u->faction->magiegebiet==M_DRAIG) { - active ++; - ADDMSG(&b->region->msgs, msg_message("praytoigjarjuk", "unit", u)); - } - } - } - if (active) for (u=b->region->units;u;u=u->next) if (playerrace(u->faction->race)) { - int i; - if (u->faction->magiegebiet!=M_DRAIG) { - for (i=0;i!=active;++i) u->hp = (u->hp+1) / 2; /* make them suffer, but not die */ - ADDMSG(&b->region->msgs, msg_message("cryinpain", "unit", u)); - } - } - return AT_AGE_KEEP; -} - -static void -write_hurting(const attrib * a, const void * owner, struct storage * store) { - building * b = a->data.v; - store->w_int(store, b->no); -} - -static int -read_hurting(attrib * a, void * owner, struct storage * store) { - int i; - i = store->r_int(store); - a->data.v = (void*)findbuilding(i); - if (a->data.v==NULL) { - log_error(("temple of pain is broken\n")); - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -static attrib_type at_hurting = { - "hurting", NULL, NULL, age_hurting, write_hurting, read_hurting -}; - -#ifdef ARENA_CREATION -static void -make_temple(region * r) -{ - const building_type * btype = bt_find("temple"); - building * b; - if (btype==NULL) { - log_error(("could not find buildingtype 'temple'\n")); - return; - } - - b = r->buildings; - while (b!=NULL && b->type!=btype) b = b->next; - if (b!=NULL) return; /* gibt schon einen */ - - b = new_building(btype, r, NULL); - b->size = btype->maxsize; - b->name = strdup("Igjarjuk's Tempel der Schreie"); - b->display = strdup("Ein Schrein aus spitzen Knochen und lodernden Flammen, gewidmet dem Wyrm der Wyrme"); - a_add(&b->attribs, a_new(&at_hurting))->data.v=b; -} -#endif - -/** - * Initialisierung Türme */ - -#ifdef ARENA_CREATION -static void -tower_init(void) -{ - int i, first = newarena; - item_type * it_demonseye = it_find("demonseye"); - item_type * it_griphonwing = it_find("griphonwing"); - assert(it_griphonwing && it_demonseye); - for (i=0;i!=6;++i) { - region * r = tower_region[i] = findregion(arena_center->x+delta_x[i]*3, arena_center->y+delta_y[i]*3); - if (r) { - start_region[i] = findregion(arena_center->x+delta_x[i]*2, arena_center->y+delta_y[i]*2); - if (rterrain(r)!=T_DESERT) terraform(r, T_DESERT); - if (!r->buildings) { - building * b = new_building(bt_find("castle"), r, NULL); - b->size = 10; - if (i!=0) { - sprintf(buf, "Turm des %s", - LOC(default_locale, mkname("school", magic_school[i]))); - } - else sprintf(buf, "Turm der Ahnungslosen"); - set_string(&b->name, buf); - } - } - } - if (first && !arena_center->buildings) { - building * b = new_building(bt_find("castle"), arena_center, NULL); - attrib * a; - item * items; - - i_add(&items, i_new(it_griphonwing, 1)); - i_add(&items, i_new(it_demonseye, 1)); - a = a_add(&b->attribs, make_giveitem(b, items)); - - b->size = 10; - set_string(&b->name, "Höhle des Greifen"); - } -} -#endif - -#ifdef ARENA_CREATION -static void -guardian_faction(plane * pl, int id) -{ - region * r; - faction * f = findfaction(id); - - if (!f) { - f = calloc(1, sizeof(faction)); - f->banner = strdup("Sie dienen dem großen Wyrm"); - f->passw = strdup(itoa36(rng_int())); - f->override = strdup(itoa36(rng_int())); - set_email(&f->email, "igjarjuk@eressea.de"); - f->name = strdup("Igjarjuks Kundschafter"); - f->race = new_race[RC_ILLUSION]; - f->age = turn; - f->locale = find_locale("de"); - f->options = want(O_COMPRESS) | want(O_REPORT) | want(O_COMPUTER) | want(O_ADRESSEN) | want(O_DEBUG); - - f->no = id; - addlist(&factions, f); - fhash(f); - } - if (f->race != new_race[RC_ILLUSION]) { - assert(!"guardian id vergeben"); - exit(0); - } - f->lastorders = turn; - f->alive = true; - for (r=regions;r;r=r->next) if (getplane(r)==pl && rterrain(r)!=T_FIREWALL) - { - unit * u; - freset(r, RF_ENCOUNTER); - for (u=r->units;u;u=u->next) { - if (u->faction==f) break; - } - if (u) continue; - u = createunit(r, f, 1, new_race[RC_GOBLIN]); - set_string(&u->name, "Igjarjuks Auge"); - set_item(u, I_RING_OF_INVISIBILITY, 1); - set_order(&u->thisorder, NULL); - fset(u, UFL_ANON_FACTION); - set_money(u, 1000); - } -} -#endif - -#define BLOCKSIZE 9 - -#ifdef ARENA_CREATION -static void -block_create(int x1, int y1, char terrain) -{ - int x, y; - for (x=0;x!=BLOCKSIZE;++x) { - for (y=0;y!=BLOCKSIZE;++y) { - region * r = new_region(x1 + x, y1 + y, 0); - terraform(r, terrain); - } - } -} -#endif - -#ifdef CENTRAL_VOLCANO - -static int -caldera_handle(trigger * t, void * data) -{ - /* call an event handler on caldera. - * data.v -> ( variant event, int timer ) - */ - building *b = (building *)t->data.v; - if (b!=NULL) { - unit ** up = &b->region->units; - while (*up) { - unit * u = *up; - if (u->building==b) { - message * msg; - if (u->items) { - item ** ip = &u->items; - msg = msg_message("caldera_handle_1", "unit items", u, u->items); - while (*ip) { - item * i = *ip; - i_remove(ip, i); - if (*ip==i) ip=&i->next; - } - } else { - msg = msg_message("caldera_handle_0", "unit", u); - } - add_message(&u->region->msgs, msg); - set_number(u, 0); - } - if (*up==u) up = &u->next; - } - } else { - log_error(("could not perform caldera::handle()\n")); - } - unused(data); - return 0; -} - -static void -caldera_write(const trigger * t, struct storage * store) -{ - building *b = (building *)t->data.v; - write_building_reference(b, store); -} - -static int -caldera_read(trigger * t, struct storage * store) -{ - int rb = read_reference(&t->data.v, store, read_building_reference, resolve_building); - if (rb==0 && !t->data.v) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -struct trigger_type tt_caldera = { - "caldera", - NULL, - NULL, - caldera_handle, - caldera_write, - caldera_read -}; - -#ifdef ARENA_CREATION -static trigger * -trigger_caldera(building * b) -{ - trigger * t = t_new(&tt_caldera); - t->data.v = b; - return t; -} -#endif - -#ifdef ARENA_CREATION -static void -init_volcano(void) -{ - building * b; - region * r = arena_center; - assert(arena_center); - if (rterrain(r)!=T_DESERT) return; /* been done before */ - terraform(arena_center, T_VOLCANO_SMOKING); - b = new_building(bt_find("caldera"), r, NULL); - b->size = 1; - b->name = strdup("Igjarjuk's Schlund"); - b->display = strdup("Feurige Lava fließt aus dem Krater des großen Vulkans. Alles wird von ihr verschlungen."); - add_trigger(&b->attribs, "timer", trigger_caldera(b)); - tt_register(&tt_caldera); -} -#endif -#endif - -#ifdef ARENA_CREATION -void -create_arena(void) -{ - int x; - arena_id = hashstring("arena"); - arena = getplanebyid(arena_id); - if (arena!=NULL) return; - score(); /* ist wichtig, damit alle Parteien einen score haben, wenn sie durchs Tor wollen. */ - guardian_faction(arena, 999); - if (arena) arena_center = findregion(plane_center_x(arena), plane_center_y(arena)); - if (!arena_center) { - newarena = 1; - arena = create_new_plane(arena_id, "Arena", -10000, -10000, 0, BLOCKSIZE-1, PFL_LOWSTEALING | PFL_NORECRUITS | PFL_NOALLIANCES); - block_create(arena->minx, arena->miny, T_OCEAN); - arena_center = findregion(plane_center_x(arena), plane_center_y(arena)); - for (x=0;x!=BLOCKSIZE;++x) { - int y; - for (y=0;y!=BLOCKSIZE;++y) { - region * r = findregion(arena->minx+x, arena->miny+y); - freset(r, RF_ENCOUNTER); - r->planep = arena; - switch (distance(r, arena_center)) { - case 4: - terraform(r, T_FIREWALL); - break; - case 0: - terraform(r, T_GLACIER); - break; - case 1: - terraform(r, T_SWAMP); - break; - case 2: - terraform(r, T_MOUNTAIN); - break; - } - } - } - } - make_temple(arena_center); -#ifdef CENTRAL_VOLCANO - init_volcano(); -#else - if (arena_center->terrain!=T_DESERT) terraform(arena_center, T_DESERT); -#endif - rsetmoney(arena_center, 0); - rsetpeasants(arena_center, 0); - tower_init(); -} -#endif -void -register_arena(void) -{ - at_register(&at_hurting); - register_item_use(use_wand_of_tears, "use_wand_of_tears"); - register_function((pf_generic)enter_arena, "enter_arena"); - register_function((pf_generic)leave_arena, "leave_arena"); - tt_register(&tt_caldera); -} - -#endif /* def ARENA_MODULE */ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include + +#if ARENA_MODULE +#include "arena.h" + +/* modules include */ +#include "score.h" + +/* attributes include */ +#include + +/* items include */ +#include + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util include */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc include */ +#include +#include +#include + + +/* exports: */ +plane * arena = NULL; + + +/* local vars */ +#define CENTRAL_VOLCANO 1 + +#ifdef ARENA_CREATION +static unsigned int arena_id = 0; +static region * arena_center = NULL; +static int newarena = 0; +#endif +static region * tower_region[6]; +static region * start_region[6]; + +static region * +arena_region(int school) +{ + return tower_region[school]; +} + +static building * +arena_tower(int school) +{ + return arena_region(school)->buildings; +} + +static int +leave_fail(unit * u) +{ + ADDMSG(&u->faction->msgs, msg_message("arena_leave_fail", "unit", u)); + return 1; +} + +static int +leave_arena(struct unit * u, const struct item_type * itype, int amount, order * ord) +{ + if (!u->building && leave_fail(u)) return -1; + if (u->building!=arena_tower(u->faction->magiegebiet) && leave_fail(u)) return -1; + unused(amount); + unused(ord); + unused(itype); + assert(!"not implemented"); + return 0; +} + +static int +enter_fail(unit * u) +{ + ADDMSG(&u->faction->msgs, msg_message("arena_enter_fail", "region unit", u->region, u)); + return 1; +} + +static int +enter_arena(unit * u, const item_type * itype, int amount, order * ord) +{ + skill_t sk; + region * r = u->region; + unit * u2; + int fee = u->faction->score / 5; + unused(ord); + unused(amount); + unused(itype); + if (fee>2000) fee = 2000; + if (getplane(r)==arena) return -1; + if (u->number!=1 && enter_fail(u)) return -1; + if (get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, fee) < fee && enter_fail(u)) return -1; + for (sk=0;sk!=MAXSKILLS;++sk) { + if (get_level(u, sk)>1 && enter_fail(u)) return -1; + } + for (u2=r->units;u2;u2=u2->next) if (u2->faction==u->faction) break; + + assert(!"not implemented"); +/* + for (res=0;res!=MAXRESOURCES;++res) if (res!=R_SILVER && res!=R_ARENA_GATE && (is_item(res) || is_herb(res) || is_potion(res))) { + int x = get_resource(u, res); + if (x) { + if (u2) { + change_resource(u2, res, x); + change_resource(u, res, -x); + } + else if (enter_fail(u)) return -1; + } + } +*/ + if (get_money(u) > fee) { + if (u2) change_money(u2, get_money(u) - fee); + else if (enter_fail(u)) return -1; + } + ADDMSG(&u->faction->msgs, msg_message("arena_enter_fail", "region unit", u->region, u)); + use_pooled(u, itype->rtype, GET_SLACK|GET_RESERVE, 1); + use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, fee); + set_money(u, 109); + fset(u, UFL_ANON_FACTION); + move_unit(u, start_region[rng_int() % 6], NULL); + return 0; +} + +/*** + ** Szepter der Tränen, Demo-Item + ***/ + +static int +use_wand_of_tears(unit * user, const struct item_type * itype, int amount, order * ord) +{ + int n; + unused(ord); + for (n=0;n!=amount;++n) { + unit * u; + for (u=user->region->units;u;u=u->next) { + if (u->faction != user->faction) { + int i; + + for (i=0;i!=u->skill_size;++i) { + if (rng_int()%3) reduce_skill(u, u->skills+i, 1); + } + ADDMSG(&u->faction->msgs, msg_message("wand_of_tears_effect", + "unit", u)); + } + } + } + ADDMSG(&user->region->msgs, msg_message("wand_of_tears_usage", + "unit", user)); + return 0; +} + +/** + * Tempel der Schreie, Demo-Gebäude **/ + +static int +age_hurting(attrib * a) { + building * b = (building *)a->data.v; + unit * u; + int active = 0; + if (b==NULL) return AT_AGE_REMOVE; + for (u=b->region->units;u;u=u->next) { + if (u->building==b) { + if (u->faction->magiegebiet==M_DRAIG) { + active ++; + ADDMSG(&b->region->msgs, msg_message("praytoigjarjuk", "unit", u)); + } + } + } + if (active) for (u=b->region->units;u;u=u->next) if (playerrace(u->faction->race)) { + int i; + if (u->faction->magiegebiet!=M_DRAIG) { + for (i=0;i!=active;++i) u->hp = (u->hp+1) / 2; /* make them suffer, but not die */ + ADDMSG(&b->region->msgs, msg_message("cryinpain", "unit", u)); + } + } + return AT_AGE_KEEP; +} + +static void +write_hurting(const attrib * a, const void * owner, struct storage * store) { + building * b = a->data.v; + store->w_int(store, b->no); +} + +static int +read_hurting(attrib * a, void * owner, struct storage * store) { + int i; + i = store->r_int(store); + a->data.v = (void*)findbuilding(i); + if (a->data.v==NULL) { + log_error(("temple of pain is broken\n")); + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +static attrib_type at_hurting = { + "hurting", NULL, NULL, age_hurting, write_hurting, read_hurting +}; + +#ifdef ARENA_CREATION +static void +make_temple(region * r) +{ + const building_type * btype = bt_find("temple"); + building * b; + if (btype==NULL) { + log_error(("could not find buildingtype 'temple'\n")); + return; + } + + b = r->buildings; + while (b!=NULL && b->type!=btype) b = b->next; + if (b!=NULL) return; /* gibt schon einen */ + + b = new_building(btype, r, NULL); + b->size = btype->maxsize; + b->name = strdup("Igjarjuk's Tempel der Schreie"); + b->display = strdup("Ein Schrein aus spitzen Knochen und lodernden Flammen, gewidmet dem Wyrm der Wyrme"); + a_add(&b->attribs, a_new(&at_hurting))->data.v=b; +} +#endif + +/** + * Initialisierung Türme */ + +#ifdef ARENA_CREATION +static void +tower_init(void) +{ + int i, first = newarena; + item_type * it_demonseye = it_find("demonseye"); + item_type * it_griphonwing = it_find("griphonwing"); + assert(it_griphonwing && it_demonseye); + for (i=0;i!=6;++i) { + region * r = tower_region[i] = findregion(arena_center->x+delta_x[i]*3, arena_center->y+delta_y[i]*3); + if (r) { + start_region[i] = findregion(arena_center->x+delta_x[i]*2, arena_center->y+delta_y[i]*2); + if (rterrain(r)!=T_DESERT) terraform(r, T_DESERT); + if (!r->buildings) { + building * b = new_building(bt_find("castle"), r, NULL); + b->size = 10; + if (i!=0) { + sprintf(buf, "Turm des %s", + LOC(default_locale, mkname("school", magic_school[i]))); + } + else sprintf(buf, "Turm der Ahnungslosen"); + set_string(&b->name, buf); + } + } + } + if (first && !arena_center->buildings) { + building * b = new_building(bt_find("castle"), arena_center, NULL); + attrib * a; + item * items; + + i_add(&items, i_new(it_griphonwing, 1)); + i_add(&items, i_new(it_demonseye, 1)); + a = a_add(&b->attribs, make_giveitem(b, items)); + + b->size = 10; + set_string(&b->name, "Höhle des Greifen"); + } +} +#endif + +#ifdef ARENA_CREATION +static void +guardian_faction(plane * pl, int id) +{ + region * r; + faction * f = findfaction(id); + + if (!f) { + f = calloc(1, sizeof(faction)); + f->banner = strdup("Sie dienen dem großen Wyrm"); + f->passw = strdup(itoa36(rng_int())); + f->override = strdup(itoa36(rng_int())); + set_email(&f->email, "igjarjuk@eressea.de"); + f->name = strdup("Igjarjuks Kundschafter"); + f->race = new_race[RC_ILLUSION]; + f->age = turn; + f->locale = find_locale("de"); + f->options = want(O_COMPRESS) | want(O_REPORT) | want(O_COMPUTER) | want(O_ADRESSEN) | want(O_DEBUG); + + f->no = id; + addlist(&factions, f); + fhash(f); + } + if (f->race != new_race[RC_ILLUSION]) { + assert(!"guardian id vergeben"); + exit(0); + } + f->lastorders = turn; + f->alive = true; + for (r=regions;r;r=r->next) if (getplane(r)==pl && rterrain(r)!=T_FIREWALL) + { + unit * u; + freset(r, RF_ENCOUNTER); + for (u=r->units;u;u=u->next) { + if (u->faction==f) break; + } + if (u) continue; + u = createunit(r, f, 1, new_race[RC_GOBLIN]); + set_string(&u->name, "Igjarjuks Auge"); + set_item(u, I_RING_OF_INVISIBILITY, 1); + set_order(&u->thisorder, NULL); + fset(u, UFL_ANON_FACTION); + set_money(u, 1000); + } +} +#endif + +#define BLOCKSIZE 9 + +#ifdef ARENA_CREATION +static void +block_create(int x1, int y1, char terrain) +{ + int x, y; + for (x=0;x!=BLOCKSIZE;++x) { + for (y=0;y!=BLOCKSIZE;++y) { + region * r = new_region(x1 + x, y1 + y, 0); + terraform(r, terrain); + } + } +} +#endif + +#ifdef CENTRAL_VOLCANO + +static int +caldera_handle(trigger * t, void * data) +{ + /* call an event handler on caldera. + * data.v -> ( variant event, int timer ) + */ + building *b = (building *)t->data.v; + if (b!=NULL) { + unit ** up = &b->region->units; + while (*up) { + unit * u = *up; + if (u->building==b) { + message * msg; + if (u->items) { + item ** ip = &u->items; + msg = msg_message("caldera_handle_1", "unit items", u, u->items); + while (*ip) { + item * i = *ip; + i_remove(ip, i); + if (*ip==i) ip=&i->next; + } + } else { + msg = msg_message("caldera_handle_0", "unit", u); + } + add_message(&u->region->msgs, msg); + set_number(u, 0); + } + if (*up==u) up = &u->next; + } + } else { + log_error(("could not perform caldera::handle()\n")); + } + unused(data); + return 0; +} + +static void +caldera_write(const trigger * t, struct storage * store) +{ + building *b = (building *)t->data.v; + write_building_reference(b, store); +} + +static int +caldera_read(trigger * t, struct storage * store) +{ + int rb = read_reference(&t->data.v, store, read_building_reference, resolve_building); + if (rb==0 && !t->data.v) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +struct trigger_type tt_caldera = { + "caldera", + NULL, + NULL, + caldera_handle, + caldera_write, + caldera_read +}; + +#ifdef ARENA_CREATION +static trigger * +trigger_caldera(building * b) +{ + trigger * t = t_new(&tt_caldera); + t->data.v = b; + return t; +} +#endif + +#ifdef ARENA_CREATION +static void +init_volcano(void) +{ + building * b; + region * r = arena_center; + assert(arena_center); + if (rterrain(r)!=T_DESERT) return; /* been done before */ + terraform(arena_center, T_VOLCANO_SMOKING); + b = new_building(bt_find("caldera"), r, NULL); + b->size = 1; + b->name = strdup("Igjarjuk's Schlund"); + b->display = strdup("Feurige Lava fließt aus dem Krater des großen Vulkans. Alles wird von ihr verschlungen."); + add_trigger(&b->attribs, "timer", trigger_caldera(b)); + tt_register(&tt_caldera); +} +#endif +#endif + +#ifdef ARENA_CREATION +void +create_arena(void) +{ + int x; + arena_id = hashstring("arena"); + arena = getplanebyid(arena_id); + if (arena!=NULL) return; + score(); /* ist wichtig, damit alle Parteien einen score haben, wenn sie durchs Tor wollen. */ + guardian_faction(arena, 999); + if (arena) arena_center = findregion(plane_center_x(arena), plane_center_y(arena)); + if (!arena_center) { + newarena = 1; + arena = create_new_plane(arena_id, "Arena", -10000, -10000, 0, BLOCKSIZE-1, PFL_LOWSTEALING | PFL_NORECRUITS | PFL_NOALLIANCES); + block_create(arena->minx, arena->miny, T_OCEAN); + arena_center = findregion(plane_center_x(arena), plane_center_y(arena)); + for (x=0;x!=BLOCKSIZE;++x) { + int y; + for (y=0;y!=BLOCKSIZE;++y) { + region * r = findregion(arena->minx+x, arena->miny+y); + freset(r, RF_ENCOUNTER); + r->planep = arena; + switch (distance(r, arena_center)) { + case 4: + terraform(r, T_FIREWALL); + break; + case 0: + terraform(r, T_GLACIER); + break; + case 1: + terraform(r, T_SWAMP); + break; + case 2: + terraform(r, T_MOUNTAIN); + break; + } + } + } + } + make_temple(arena_center); +#ifdef CENTRAL_VOLCANO + init_volcano(); +#else + if (arena_center->terrain!=T_DESERT) terraform(arena_center, T_DESERT); +#endif + rsetmoney(arena_center, 0); + rsetpeasants(arena_center, 0); + tower_init(); +} +#endif +void +register_arena(void) +{ + at_register(&at_hurting); + register_item_use(use_wand_of_tears, "use_wand_of_tears"); + register_function((pf_generic)enter_arena, "enter_arena"); + register_function((pf_generic)leave_arena, "leave_arena"); + tt_register(&tt_caldera); +} + +#endif /* def ARENA_MODULE */ diff --git a/src/modules/arena.h b/src/modules/arena.h index 6dbec6e93..78872e9fc 100644 --- a/src/modules/arena.h +++ b/src/modules/arena.h @@ -1,39 +1,39 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef ARENA_H -#define ARENA_H -#ifdef __cplusplus -extern "C" { -#endif - -#if ARENA_MODULE == 0 -#error "must define ARENA_MODULE to use this module" -#endif -/* exports: */ -extern struct plane * arena; - -extern void register_arena(void); -#ifdef ARENA_CREATION -extern void create_arena(void); -#endif - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef ARENA_H +#define ARENA_H +#ifdef __cplusplus +extern "C" { +#endif + +#if ARENA_MODULE == 0 +#error "must define ARENA_MODULE to use this module" +#endif +/* exports: */ +extern struct plane * arena; + +extern void register_arena(void); +#ifdef ARENA_CREATION +extern void create_arena(void); +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c index c28a3f1bd..a7ad73e3f 100644 --- a/src/modules/autoseed.c +++ b/src/modules/autoseed.c @@ -1,1024 +1,1022 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "autoseed.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* libc includes */ -#include -#include -#include -#include -#include - -const terrain_type * -random_terrain(const terrain_type * terrains[], int distribution[], int size) -{ - int ndistribution = size; - const terrain_type * terrain; - int n; - - if (distribution) { - ndistribution = 0; - for (n=0;n!=size;++n) { - ndistribution += distribution[n]; - } - } - - n = rng_int() % ndistribution; - if (distribution) { - int i; - for (i=0;i!=size;++i) { - n -= distribution[i]; - if (n<0) break; - } - assert(iresources;rm;rm=rm->next) { - if (rm->type->rtype==rtype) break; - } - if (!rm) { - add_resource(r, 1, base, 150, rtype); - } - return 0; -} - - -static int -count_demand(const region *r) -{ - struct demand *dmd; - int c = 0; - if (r->land) { - for (dmd=r->land->demands;dmd;dmd=dmd->next) c++; - } - return c; -} - -static int -recurse_regions(region *r, region_list **rlist, boolean(*fun)(const region *r)) -{ - if (!fun(r)) return 0; - else { - int len = 0; - direction_t d; - region_list * rl = calloc(sizeof(region_list), 1); - rl->next = *rlist; - rl->data = r; - (*rlist) = rl; - fset(r, RF_MARK); - for (d=0;d!=MAXDIRECTIONS;++d) { - region * nr = rconnect(r, d); - if (nr && !fval(nr, RF_MARK)) len += recurse_regions(nr, rlist, fun); - } - return len+1; - } -} - -static boolean -f_nolux(const region * r) -{ - if (r->land && count_demand(r) != get_maxluxuries()) return true; - return false; -} - -int -fix_demand(region *rd) -{ - region_list *rl, *rlist = NULL; - static const struct luxury_type **mlux = 0, ** ltypes; - const luxury_type *sale = NULL; - int maxlux = 0; - int maxluxuries = get_maxluxuries(); - - if (maxluxuries==0) return 0; - recurse_regions(rd, &rlist, f_nolux); - if (mlux==0) { - int i = 0; - mlux = (const luxury_type **)gc_add(calloc(maxluxuries, sizeof(const luxury_type *))); - ltypes = (const luxury_type **)gc_add(calloc(maxluxuries, sizeof(const luxury_type *))); - for (sale=luxurytypes;sale;sale=sale->next) { - ltypes[i++] = sale; - } - } - else { - int i; - for (i=0;i!=maxluxuries;++i) mlux[i] = 0; - } - for (rl=rlist;rl;rl=rl->next) { - region * r = rl->data; - direction_t d; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * nr = rconnect(r, d); - if (nr && nr->land && nr->land->demands) { - struct demand * dmd; - for (dmd = nr->land->demands;dmd;dmd=dmd->next) { - if (dmd->value == 0) { - int i; - for (i=0;i!=maxluxuries;++i) { - if (mlux[i]==NULL) { - maxlux = i; - mlux[i] = dmd->type; - break; - } else if (mlux[i]==dmd->type) { - break; - } - } - break; - } - } - } - } - freset(r, RF_MARK); /* undo recursive marker */ - } - if (maxlux<2) { - int i; - for (i=maxlux;i!=2;++i) { - int j; - do { - int k = rng_int() % maxluxuries; - mlux[i] = ltypes[k]; - for (j=0;j!=i;++j) { - if (mlux[j]==mlux[i]) break; - } - } while (j!=i); - } - maxlux = 2; - } - for (rl=rlist;rl;rl=rl->next) { - region * r = rl->data; - if (!fval(r, RF_CHAOTIC)) { - log_info((LOG_INFO1, "fixing demand in %s\n", regionname(r, NULL))); - } - sale = mlux[rng_int() % maxlux]; - if (sale) setluxuries(r, sale); - } - while (rlist) { - rl = rlist->next; - free(rlist); - rlist = rl; - } - return 0; -} - -/* nach 150 Runden ist Neustart erlaubt */ -#define MINAGE_MULTI 150 -newfaction * -read_newfactions(const char * filename) -{ - newfaction * newfactions = NULL; - FILE * F = fopen(filename, "r"); - char buf[1024]; - - if (F==NULL) return NULL; - for (;;) { - faction * f; - char race[20], email[64], lang[8], password[16]; - newfaction *nf, **nfi; - int bonus = 0, subscription = 0; - int alliance = 0; - - if (fgets(buf, sizeof(buf), F)==NULL) break; - - email[0] = '\0'; - password[0] = '\0'; - - if (sscanf(buf, "%54s %20s %8s %d %d %16s %d", email, race, lang, &bonus, &subscription, password, &alliance)<6) break; - if (email[0]=='\0') break; - if (password[0]=='\0') { - strcpy(password, itoa36(rng_int())); - strcat(password, itoa36(rng_int())); - } - for (f=factions;f;f=f->next) { - if (strcmp(f->email, email)==0 && f->subscription && f->ageunits) continue; /* skip the ones we've already got */ - for (nf=newfactions;nf;nf=nf->next) { - if (strcmp(nf->email, email)==0) break; - } - if (nf) continue; - nf = calloc(sizeof(newfaction), 1); - if (set_email(&nf->email, email)!=0) { - log_error(("Invalid email address for subscription %s: %s\n", - itoa36(subscription), email)); - continue; - } - nf->password = strdup(password); - nf->race = rc_find(race); - nf->subscription = subscription; - if (alliances!=NULL) { - struct alliance * al = findalliance(alliance); - if (al==NULL) { - char zText[64]; - sprintf(zText, "Allianz %d", alliance); - al = makealliance(alliance, zText); - } - nf->allies = al; - } else { - nf->allies = NULL; - } - if (nf->race==NULL) { - /* if the script didn't supply the race as a token, then it gives us a - * race in the default locale (which means that itis a UTF8 string) */ - nf->race = findrace(race, default_locale); - if (nf->race==NULL) { - char buffer[32]; - size_t outbytes = sizeof(buffer) - 1; - size_t inbytes = strlen(race); - unicode_latin1_to_utf8(buffer, &outbytes, race, &inbytes); - buffer[outbytes] = 0; - nf->race = findrace(buffer, default_locale); - if (nf->race==NULL) { - log_error(("new faction has unknown race '%s'.\n", race)); - free(nf); - continue; - } - } - } - nf->lang = find_locale(lang); - nf->bonus = bonus; - assert(nf->race && nf->email && nf->lang); - nfi = &newfactions; - while (*nfi) { - if ((*nfi)->race==nf->race) break; - nfi=&(*nfi)->next; - } - nf->next = *nfi; - *nfi = nf; - } - fclose(F); - return newfactions; -} - -extern int numnewbies; - -static const terrain_type * -preferred_terrain(const struct race * rc) -{ - terrain_t t = T_PLAIN; - if (rc==rc_find("dwarf")) t = T_MOUNTAIN; - if (rc==rc_find("insect")) t = T_DESERT; - if (rc==rc_find("halfling")) t = T_SWAMP; - if (rc==rc_find("troll")) t = T_MOUNTAIN; - return newterrain(t); -} - -#define REGIONS_PER_FACTION 2 -#define PLAYERS_PER_ISLAND 20 -#define MAXISLANDSIZE 50 -#define MINFACTIONS 1 -#define VOLCANO_CHANCE 100 - -static boolean -virgin_region(const region * r) -{ - direction_t d; - if (r==NULL) return true; - if (fval(r->terrain, FORBIDDEN_REGION)) return false; - if (r->units) return false; - for (d=0;d!=MAXDIRECTIONS;++d) { - const region * rn = rconnect(r, d); - if (rn) { - if (rn->age>r->age+1) return false; - if (rn->units) return false; - if (fval(rn->terrain, FORBIDDEN_REGION)) { - /* because it kinda sucks to have islands that are adjacent to a firewall */ - return false; - } - } - } - return true; -} - -void -get_island(region * root, region_list ** rlist) -{ - region_list ** rnext = rlist; - while (*rnext) rnext=&(*rnext)->next; - - fset(root, RF_MARK); - add_regionlist(rnext, root); - - while (*rnext) { - direction_t dir; - - region * rcurrent = (*rnext)->data; - rnext = &(*rnext)->next; - - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * r = rconnect(rcurrent, dir); - if (r!=NULL && r->land && !fval(r, RF_MARK)) { - fset(r, RF_MARK); - add_regionlist(rnext, r); - } - } - } - rnext=rlist; - while (*rnext) { - region_list * rptr = *rnext; - freset(rptr->data, RF_MARK); - rnext = &rptr->next; - } -} - -static void -get_island_info(region * root, int * size_p, int * inhabited_p, int * maxage_p) -{ - int size = 0, maxage = 0, inhabited = 0; - region_list * rlist = NULL; - region_list * island = NULL; - add_regionlist(&rlist, root); - island = rlist; - fset(root, RF_MARK); - while (rlist) { - direction_t d; - region * r = rlist->data; - if (r->units) { - unit * u; - for (u=r->units; u; u=u->next) { - if (!is_monsters(u->faction) && u->faction->age > maxage) { - maxage = u->faction->age; - } - } - ++inhabited; - } - ++size; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(r, d); - if (rn && !fval(rn, RF_MARK) && rn->land) { - region_list * rnew = malloc(sizeof(region_list)); - rnew->data = rn; - rnew->next = rlist->next; - rlist->next = rnew; - fset(rn, RF_MARK); - } - } - rlist = rlist->next; - } - for (rlist=island;rlist;rlist=rlist->next) { - freset(rlist->data, RF_MARK); - } - free_regionlist(island); - if (size_p) *size_p = size; - if (inhabited_p) *inhabited_p = inhabited; - if (maxage_p) *maxage_p = maxage; -} - -void -free_newfaction(newfaction * nf) -{ - free(nf->email); - free(nf->password); - free(nf); -} - -static void -frame_regions(int age, const terrain_type * terrain) -{ - plane * hplane = get_homeplane(); - region * r = regions; - for (r=regions;r;r=r->next) { - plane * pl = rplane(r); - direction_t d; - if (r->ageterrain == terrain) continue; - - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(r, d); - if (rn==NULL) { - int x = r->x + delta_x[d]; - int y = r->y + delta_y[d]; - pnormalize(&x, &y, pl); - rn = new_region(x, y, pl, 0); - terraform_region(rn, terrain); - rn->age=r->age; - } - } - } -} - -static void -prepare_starting_region(region * r) -{ - int n, t; - double p; - - assert(r->land); - - /* population between 30% and 60% of max */ - p = rng_double(); - n = (int)(r->terrain->size * (0.3 + p*0.3)); - rsetpeasants(r, n); - - /* trees: don't squash the peasants, and at least 5% should be forrest */ - t = (rtrees(r, 2) + rtrees(r, 1)/2) * TREESIZE; - if (t < r->terrain->size/20 || t+n > r->terrain->size) { - double p2 = 0.05 + rng_double()*(1.0-p-0.05); - int maxtrees = (int)(r->terrain->size/1.25/TREESIZE); /* 1.25 = each young tree will take 1/2 the space of old trees */ - int trees = (int)(p2 * maxtrees); - - rsettrees(r, 2, trees); - rsettrees(r, 1, trees/2); - rsettrees(r, 0, trees/4); - } - - /* horses: between 1% and 2% */ - p = rng_double(); - rsethorses(r, (int)(r->terrain->size * (0.01 + p*0.01))); - - if (!markets_module()) { - fix_demand(r); - } -} - -/** create new island with up to nsize players - * returns the number of players placed on the new island. - */ -int -autoseed(newfaction ** players, int nsize, int max_agediff) -{ - region * r = NULL; - region_list * rlist = NULL; - int rsize = 0, tsize = 0; - int isize = REGIONS_PER_FACTION; /* target size for the island */ - int psize = 0; /* players on this island */ - const terrain_type * volcano_terrain = get_terrain("volcano"); - static int nterrains = -1; - static const terrain_type ** terrainarr = 0; - static int * distribution; - - if (nterrains<0) { - int n = 0; - const terrain_type * terrain = terrains(); - for (nterrains=0;terrain;terrain=terrain->next) { - if (terrain->distribution) { - ++nterrains; - } - } - terrainarr = malloc(sizeof(terrain_type *) * nterrains); - distribution = malloc(sizeof(int) * nterrains); - for (terrain = terrains();terrain;terrain = terrain->next) { - if (terrain->distribution) { - terrainarr[n] = terrain; - distribution[n++] = terrain->distribution; - } - } - } - frame_regions(16, newterrain(T_FIREWALL)); - - if (listlen(*players)0) { - region * rmin = NULL; - plane * hplane = get_homeplane(); - /* find a spot that's adjacent to the previous island, but virgin. - * like the last land virgin ocean region adjacent to land. - */ - for (r=regions;r;r=r->next) { - struct plane * pl = rplane(r); - if (r->age<=max_agediff && r->terrain == newterrain(T_OCEAN) && pl==hplane && virgin_region(r)) { - direction_t d; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(r, d); - if (rn && rn->land && rn->age<=max_agediff && virgin_region(rn)) { - /* only expand islands that aren't single-islands and not too big already */ - int size, inhabitants, maxage; - get_island_info(rn, &size, &inhabitants, &maxage); - if (maxage<=max_agediff && size>=2 && sizenext) { - region * r = rlist->data; - unit * u; - for (u=r->units;u;u=u->next) { - f = u->faction; - if (!fval(f, FFL_MARK)) { - ++psize; - fset(f, FFL_MARK); - } - } - } - free_regionlist(rlist); - if (psize>0) for (f=factions;f;f=f->next) freset(f, FFL_MARK); - if (psizenext) { - struct plane * pl = rplane(r); - if (r->terrain == newterrain(T_OCEAN) && pl==hplane && (rmin==NULL || r->age<=max_agediff)) { - direction_t d; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(r, d); - if (rn==NULL) break; - } - if (d!=MAXDIRECTIONS) { - rmin=r; - dmin=d; - } - } - } - - /* create a new region where we found the empty spot, and make it the first - * in our island. island regions are kept in rlist, so only new regions can - * get populated, and old regions are not overwritten */ - if (rmin!=NULL) { - plane * pl = rplane(rmin); - int x = rmin->x + delta_x[dmin]; - int y = rmin->y + delta_y[dmin]; - pnormalize(&x, &y, pl); - assert(virgin_region(rconnect(rmin, dmin))); - r = new_region(x, y, pl, 0); - terraform_region(r, newterrain(T_OCEAN)); - } - } - if (r!=NULL) { - add_regionlist(&rlist, r); - fset(r, RF_MARK); - rsize = 1; - } - - while (rsize && (nsize || isize>=REGIONS_PER_FACTION)) { - int i = rng_int() % rsize; - region_list ** rnext = &rlist; - region_list * rfind; - direction_t d; - while (i--) rnext=&(*rnext)->next; - rfind = *rnext; - r = rfind->data; - freset(r, RF_MARK); - *rnext = rfind->next; - free(rfind); - --rsize; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(r, d); - if (rn && fval(rn, RF_MARK)) continue; - if (rn==NULL) { - plane * pl = rplane(r); - int x = r->x + delta_x[d]; - int y = r->y + delta_y[d]; - pnormalize(&x, &y, pl); - rn = new_region(x, y, pl, 0); - terraform_region(rn, newterrain(T_OCEAN)); - } - if (virgin_region(rn)) { - add_regionlist(&rlist, rn); - fset(rn, RF_MARK); - ++rsize; - } - } - if (volcano_terrain!=NULL && (rng_int() % VOLCANO_CHANCE == 0)) { - terraform_region(r, volcano_terrain); - } else if (nsize && (rng_int() % isize == 0 || rsize==0)) { - newfaction ** nfp, * nextf = *players; - faction * f; - unit * u; - - isize += REGIONS_PER_FACTION; - terraform_region(r, preferred_terrain(nextf->race)); - prepare_starting_region(r); - ++tsize; - assert(r->land && r->units==0); - u = addplayer(r, addfaction(nextf->email, nextf->password, nextf->race, - nextf->lang, nextf->subscription)); - f = u->faction; - fset(f, FFL_ISNEW); - f->alliance = nextf->allies; - log_printf("New faction (%s), %s at %s\n", itoa36(f->no), - f->email, regionname(r, NULL)); - if (f->subscription) { - sql_print(("UPDATE subscriptions SET status='ACTIVE', faction='%s', firstturn=%d, lastturn=%d, password='%s' WHERE id=%u;\n", - factionid(f), f->lastorders, f->lastorders, f->override, f->subscription)); - } - - /* remove duplicate email addresses */ - nfp = &nextf->next; - while (*nfp) { - newfaction * nf = *nfp; - if (strcmp(nextf->email, nf->email)==0) { - *nfp = nf->next; - free_newfaction(nf); - } - else nfp = &nf->next; - } - *players = nextf->next; - free_newfaction(nextf); - - ++psize; - --nsize; - --isize; - if (psize>=PLAYERS_PER_ISLAND) break; - } else { - terraform_region(r, random_terrain(terrainarr, distribution, nterrains)); - --isize; - } - } - - if (nsize!=0) { - log_error(("Could not place all factions on the same island as requested\n")); - } - - - if (rlist) { -#define MINOCEANDIST 3 -#define MAXOCEANDIST 6 -#define MAXFILLDIST 10 -#define SPECIALCHANCE 80 - region_list ** rbegin = &rlist; - int special = 1; - int oceandist = MINOCEANDIST + (rng_int() % (MAXOCEANDIST-MINOCEANDIST)); - while (oceandist--) { - region_list ** rend = rbegin; - while (*rend) rend=&(*rend)->next; - while (rbegin!=rend) { - direction_t d; - region * r = (*rbegin)->data; - rbegin=&(*rbegin)->next; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(r, d); - if (rn==NULL) { - const struct terrain_type * terrain = newterrain(T_OCEAN); - plane * pl = rplane(r); - int x = r->x + delta_x[d]; - int y = r->y + delta_y[d]; - pnormalize(&x, &y, pl); - rn = new_region(x, y, pl, 0); - if (rng_int() % SPECIALCHANCE < special) { - terrain = random_terrain(terrainarr, distribution, nterrains); - special = SPECIALCHANCE / 3; /* 33% chance auf noch eines */ - } else { - special = 1; - } - terraform_region(rn, terrain); - /* the new region has an extra 20% chance to have mallorn */ - if (rng_int() % 100 < 20) fset(r, RF_MALLORN); - add_regionlist(rend, rn); - } - } - } - - } - while (*rbegin) { - region * r = (*rbegin)->data; - plane * pl = rplane(r); - direction_t d; - rbegin=&(*rbegin)->next; - for (d=0;d!=MAXDIRECTIONS;++d) if (rconnect(r, d)==NULL) { - int i; - for (i=1;i!=MAXFILLDIST;++i) { - int x = r->x + delta_x[d]*i; - int y = r->y + delta_y[d]*i; - pnormalize(&x, &y, pl); - if (findregion(x, y)) { - break; - } - } - if (i!=MAXFILLDIST) { - while (--i) { - region * rn; - int x = r->x + delta_x[d]*i; - int y = r->y + delta_y[d]*i; - pnormalize(&x, &y, pl); - rn = new_region(x, y, pl, 0); - terraform_region(rn, newterrain(T_OCEAN)); - } - } - } - } - while (rlist) { - region_list * self = rlist; - rlist = rlist->next; - freset(self->data, RF_MARK); - free(self); - } - } - return tsize; -} - -region_list * regionqueue_push(region_list ** rlist, region * r) -{ - region_list * rnew = malloc(sizeof(region_list)); - rnew->data = r; - rnew->next = 0; - while (*rlist) { rlist = &(*rlist)->next; } - *rlist = rnew; - return rnew; -} - -region * regionqueue_pop(region_list ** rlist) -{ - if (*rlist) { - region * r = (*rlist)->data; - region_list * rpop = *rlist; - *rlist = rpop->next; - free(rpop); - return r; - } - return 0; -} - -#define GEOMAX 8 -static struct geo { - int distribution; - terrain_t type; -} geography_e3[GEOMAX] = { - { 8, T_OCEAN }, - { 3, T_SWAMP }, - { 1, T_VOLCANO }, - { 3, T_DESERT }, - { 4, T_HIGHLAND }, - { 3, T_MOUNTAIN }, - { 2, T_GLACIER }, - { 1, T_PLAIN } -}; - -const terrain_type * random_terrain_e3(direction_t dir) -{ - static const terrain_type ** terrainarr = 0; - static int * distribution = 0; - - if (!distribution) { - int n = 0; - - terrainarr = malloc(GEOMAX * sizeof(const terrain_type *)); - distribution = malloc(GEOMAX * sizeof(int)); - for (n=0;n!=GEOMAX;++n) { - terrainarr[n] = newterrain(geography_e3[n].type); - distribution[n] = geography_e3[n].distribution; - } - } - return random_terrain(terrainarr, distribution, GEOMAX); -} - -int -random_neighbours(region * r, region_list ** rlist, const terrain_type *(*terraformer)(direction_t)) -{ - int nsize = 0; - direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * rn = rconnect(r, dir); - if (rn==NULL) { - const terrain_type * terrain = terraformer(dir); - plane * pl = rplane(r); - int x = r->x + delta_x[dir]; - int y = r->y + delta_y[dir]; - pnormalize(&x, &y, pl); - rn = new_region(x, y, pl, 0); - terraform_region(rn, terrain); - regionqueue_push(rlist, rn); - if (rn->land) { - ++nsize; - } - } - } - return nsize; -} - -const terrain_type * get_ocean(direction_t dir) -{ - return newterrain(T_OCEAN); -} - -int region_quality(const region * r, region * rn[]) -{ - int n, result = 0; - - for (n=0;n!=MAXDIRECTIONS;++n) { - if (rn[n] && rn[n]->land) { - if (rn[n]->terrain==newterrain(T_VOLCANO)) { - /* nobody likes volcanoes */ - result -= 2000; - } - result += rn[n]->land->peasants; - } - } - return result; -} - -static void -oceans_around(region * r, region * rn[]) -{ - int n; - for (n=0;n!=MAXDIRECTIONS;++n) { - region * rx = rn[n]; - if (rx==NULL) { - plane * pl = rplane(r); - int x = r->x + delta_x[n]; - int y = r->y + delta_y[n]; - pnormalize(&x, &y, pl); - rx = new_region(x, y, pl, 0); - terraform_region(rx, newterrain(T_OCEAN)); - rn[n] = rx; - } - } -} - -static void -smooth_island(region_list * island) -{ - region * rn[MAXDIRECTIONS]; - region_list * rlist = NULL; - for (rlist=island;rlist;rlist=rlist->next) { - region * r = rlist->data; - int n, nland = 0; - - if (r->land) { - get_neighbours(r, rn); - for (n=0;n!=MAXDIRECTIONS && nland<=1;++n) { - if (rn[n]->land) { - ++nland; - r = rn[n]; - } - } - - if (nland==1) { - get_neighbours(r, rn); - oceans_around(r, rn); - for (n=0;n!=MAXDIRECTIONS;++n) { - int n1 = (n+1)%MAXDIRECTIONS; - int n2 = (n+1+MAXDIRECTIONS)%MAXDIRECTIONS; - if (!rn[n]->land && rn[n1]!=r && rn[n2]!=r) { - r = rlist->data; - runhash(r); - runhash(rn[n]); - SWAP_VARS(int, r->x, rn[n]->x); - SWAP_VARS(int, r->y, rn[n]->y); - rhash(r); - rhash(rn[n]); - rlist->data = r; - oceans_around(r, rn); - break; - } - } - } - } - } -} - -static void -starting_region(region * r, region * rn[]) -{ - unit * u; - int n; - - oceans_around(r, rn); - freset(r, RF_MARK); - for (n=0;n!=MAXDIRECTIONS;++n) { - freset(rn[n], RF_MARK); - } - terraform_region(r, newterrain(T_PLAIN)); - prepare_starting_region(r); - u = addplayer(r, addfaction("enno@eressea.de", itoa36(rng_int()), races, - default_locale, 0)); -} -/* E3A island generation */ -int -build_island_e3(int x, int y, int numfactions, int minsize) -{ -#define MIN_QUALITY 1000 - int nfactions = 0; - region_list * rlist = NULL; - region_list * island = NULL; - plane * pl = findplane(x, y); - region * r = findregion(x, y); - int nsize = 1; - int q, maxq = INT_MIN, minq = INT_MAX; - - if (!r) r = new_region(x, y, pl, 0); - assert(!r->units); - do { - terraform_region(r, random_terrain_e3(NODIRECTION)); - } while (!r->land); - - while (r) { - fset(r, RF_MARK); - if (r->land) { - if (nsizeminsize/2) { - for (rlist=island;rlist;rlist=rlist->next) { - r = rlist->data; - if (r->land && fval(r, RF_MARK)) { - region *rn[MAXDIRECTIONS]; - - get_neighbours(r, rn); - q = region_quality(r,rn); - if (q>=MIN_QUALITY && nfactionsnext) { - r = rlist->data; - if (!r->land && fval(r, RF_MARK)) { - region *rn[MAXDIRECTIONS]; - get_neighbours(r, rn); - q = region_quality(r, rn); - if (q>=MIN_QUALITY*4/3 && nfactionsnext) { - r = rlist->data; - if (r->units) { - region *rn[MAXDIRECTIONS]; - get_neighbours(r, rn); - q = region_quality(r, rn); - if (q-minq > (maxq-minq)*2/3) { - terraform_region(r, newterrain(T_HIGHLAND)); - prepare_starting_region(r); - } - r->land->money = 50000; /* 2% = 1000 silver */ - } else if (r->land) { - r->land->money *= 4; - } - } - return nfactions; -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "autoseed.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +const terrain_type * +random_terrain(const terrain_type * terrains[], int distribution[], int size) +{ + int ndistribution = size; + const terrain_type * terrain; + int n; + + if (distribution) { + ndistribution = 0; + for (n=0;n!=size;++n) { + ndistribution += distribution[n]; + } + } + + n = rng_int() % ndistribution; + if (distribution) { + int i; + for (i=0;i!=size;++i) { + n -= distribution[i]; + if (n<0) break; + } + assert(iresources;rm;rm=rm->next) { + if (rm->type->rtype==rtype) break; + } + if (!rm) { + add_resource(r, 1, base, 150, rtype); + } + return 0; +} + + +static int +count_demand(const region *r) +{ + struct demand *dmd; + int c = 0; + if (r->land) { + for (dmd=r->land->demands;dmd;dmd=dmd->next) c++; + } + return c; +} + +static int +recurse_regions(region *r, region_list **rlist, boolean(*fun)(const region *r)) +{ + if (!fun(r)) return 0; + else { + int len = 0; + direction_t d; + region_list * rl = calloc(sizeof(region_list), 1); + rl->next = *rlist; + rl->data = r; + (*rlist) = rl; + fset(r, RF_MARK); + for (d=0;d!=MAXDIRECTIONS;++d) { + region * nr = rconnect(r, d); + if (nr && !fval(nr, RF_MARK)) len += recurse_regions(nr, rlist, fun); + } + return len+1; + } +} + +static boolean +f_nolux(const region * r) +{ + if (r->land && count_demand(r) != get_maxluxuries()) return true; + return false; +} + +int +fix_demand(region *rd) +{ + region_list *rl, *rlist = NULL; + static const struct luxury_type **mlux = 0, ** ltypes; + const luxury_type *sale = NULL; + int maxlux = 0; + int maxluxuries = get_maxluxuries(); + + if (maxluxuries==0) return 0; + recurse_regions(rd, &rlist, f_nolux); + if (mlux==0) { + int i = 0; + mlux = (const luxury_type **)gc_add(calloc(maxluxuries, sizeof(const luxury_type *))); + ltypes = (const luxury_type **)gc_add(calloc(maxluxuries, sizeof(const luxury_type *))); + for (sale=luxurytypes;sale;sale=sale->next) { + ltypes[i++] = sale; + } + } + else { + int i; + for (i=0;i!=maxluxuries;++i) mlux[i] = 0; + } + for (rl=rlist;rl;rl=rl->next) { + region * r = rl->data; + direction_t d; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * nr = rconnect(r, d); + if (nr && nr->land && nr->land->demands) { + struct demand * dmd; + for (dmd = nr->land->demands;dmd;dmd=dmd->next) { + if (dmd->value == 0) { + int i; + for (i=0;i!=maxluxuries;++i) { + if (mlux[i]==NULL) { + maxlux = i; + mlux[i] = dmd->type; + break; + } else if (mlux[i]==dmd->type) { + break; + } + } + break; + } + } + } + } + freset(r, RF_MARK); /* undo recursive marker */ + } + if (maxlux<2) { + int i; + for (i=maxlux;i!=2;++i) { + int j; + do { + int k = rng_int() % maxluxuries; + mlux[i] = ltypes[k]; + for (j=0;j!=i;++j) { + if (mlux[j]==mlux[i]) break; + } + } while (j!=i); + } + maxlux = 2; + } + for (rl=rlist;rl;rl=rl->next) { + region * r = rl->data; + if (!fval(r, RF_CHAOTIC)) { + log_info((LOG_INFO1, "fixing demand in %s\n", regionname(r, NULL))); + } + sale = mlux[rng_int() % maxlux]; + if (sale) setluxuries(r, sale); + } + while (rlist) { + rl = rlist->next; + free(rlist); + rlist = rl; + } + return 0; +} + +/* nach 150 Runden ist Neustart erlaubt */ +#define MINAGE_MULTI 150 +newfaction * +read_newfactions(const char * filename) +{ + newfaction * newfactions = NULL; + FILE * F = fopen(filename, "r"); + char buf[1024]; + + if (F==NULL) return NULL; + for (;;) { + faction * f; + char race[20], email[64], lang[8], password[16]; + newfaction *nf, **nfi; + int bonus = 0, subscription = 0; + int alliance = 0; + + if (fgets(buf, sizeof(buf), F)==NULL) break; + + email[0] = '\0'; + password[0] = '\0'; + + if (sscanf(buf, "%54s %20s %8s %d %d %16s %d", email, race, lang, &bonus, &subscription, password, &alliance)<6) break; + if (email[0]=='\0') break; + if (password[0]=='\0') { + strcpy(password, itoa36(rng_int())); + strcat(password, itoa36(rng_int())); + } + for (f=factions;f;f=f->next) { + if (strcmp(f->email, email)==0 && f->subscription && f->ageunits) continue; /* skip the ones we've already got */ + for (nf=newfactions;nf;nf=nf->next) { + if (strcmp(nf->email, email)==0) break; + } + if (nf) continue; + nf = calloc(sizeof(newfaction), 1); + if (set_email(&nf->email, email)!=0) { + log_error(("Invalid email address for subscription %s: %s\n", + itoa36(subscription), email)); + continue; + } + nf->password = strdup(password); + nf->race = rc_find(race); + nf->subscription = subscription; + if (alliances!=NULL) { + struct alliance * al = findalliance(alliance); + if (al==NULL) { + char zText[64]; + sprintf(zText, "Allianz %d", alliance); + al = makealliance(alliance, zText); + } + nf->allies = al; + } else { + nf->allies = NULL; + } + if (nf->race==NULL) { + /* if the script didn't supply the race as a token, then it gives us a + * race in the default locale (which means that itis a UTF8 string) */ + nf->race = findrace(race, default_locale); + if (nf->race==NULL) { + char buffer[32]; + size_t outbytes = sizeof(buffer) - 1; + size_t inbytes = strlen(race); + unicode_latin1_to_utf8(buffer, &outbytes, race, &inbytes); + buffer[outbytes] = 0; + nf->race = findrace(buffer, default_locale); + if (nf->race==NULL) { + log_error(("new faction has unknown race '%s'.\n", race)); + free(nf); + continue; + } + } + } + nf->lang = find_locale(lang); + nf->bonus = bonus; + assert(nf->race && nf->email && nf->lang); + nfi = &newfactions; + while (*nfi) { + if ((*nfi)->race==nf->race) break; + nfi=&(*nfi)->next; + } + nf->next = *nfi; + *nfi = nf; + } + fclose(F); + return newfactions; +} + +extern int numnewbies; + +static const terrain_type * +preferred_terrain(const struct race * rc) +{ + terrain_t t = T_PLAIN; + if (rc==rc_find("dwarf")) t = T_MOUNTAIN; + if (rc==rc_find("insect")) t = T_DESERT; + if (rc==rc_find("halfling")) t = T_SWAMP; + if (rc==rc_find("troll")) t = T_MOUNTAIN; + return newterrain(t); +} + +#define REGIONS_PER_FACTION 2 +#define PLAYERS_PER_ISLAND 20 +#define MAXISLANDSIZE 50 +#define MINFACTIONS 1 +#define VOLCANO_CHANCE 100 + +static boolean +virgin_region(const region * r) +{ + direction_t d; + if (r==NULL) return true; + if (fval(r->terrain, FORBIDDEN_REGION)) return false; + if (r->units) return false; + for (d=0;d!=MAXDIRECTIONS;++d) { + const region * rn = rconnect(r, d); + if (rn) { + if (rn->age>r->age+1) return false; + if (rn->units) return false; + if (fval(rn->terrain, FORBIDDEN_REGION)) { + /* because it kinda sucks to have islands that are adjacent to a firewall */ + return false; + } + } + } + return true; +} + +void +get_island(region * root, region_list ** rlist) +{ + region_list ** rnext = rlist; + while (*rnext) rnext=&(*rnext)->next; + + fset(root, RF_MARK); + add_regionlist(rnext, root); + + while (*rnext) { + direction_t dir; + + region * rcurrent = (*rnext)->data; + rnext = &(*rnext)->next; + + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * r = rconnect(rcurrent, dir); + if (r!=NULL && r->land && !fval(r, RF_MARK)) { + fset(r, RF_MARK); + add_regionlist(rnext, r); + } + } + } + rnext=rlist; + while (*rnext) { + region_list * rptr = *rnext; + freset(rptr->data, RF_MARK); + rnext = &rptr->next; + } +} + +static void +get_island_info(region * root, int * size_p, int * inhabited_p, int * maxage_p) +{ + int size = 0, maxage = 0, inhabited = 0; + region_list * rlist = NULL; + region_list * island = NULL; + add_regionlist(&rlist, root); + island = rlist; + fset(root, RF_MARK); + while (rlist) { + direction_t d; + region * r = rlist->data; + if (r->units) { + unit * u; + for (u=r->units; u; u=u->next) { + if (!is_monsters(u->faction) && u->faction->age > maxage) { + maxage = u->faction->age; + } + } + ++inhabited; + } + ++size; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(r, d); + if (rn && !fval(rn, RF_MARK) && rn->land) { + region_list * rnew = malloc(sizeof(region_list)); + rnew->data = rn; + rnew->next = rlist->next; + rlist->next = rnew; + fset(rn, RF_MARK); + } + } + rlist = rlist->next; + } + for (rlist=island;rlist;rlist=rlist->next) { + freset(rlist->data, RF_MARK); + } + free_regionlist(island); + if (size_p) *size_p = size; + if (inhabited_p) *inhabited_p = inhabited; + if (maxage_p) *maxage_p = maxage; +} + +void +free_newfaction(newfaction * nf) +{ + free(nf->email); + free(nf->password); + free(nf); +} + +static void +frame_regions(int age, const terrain_type * terrain) +{ + plane * hplane = get_homeplane(); + region * r = regions; + for (r=regions;r;r=r->next) { + plane * pl = rplane(r); + direction_t d; + if (r->ageterrain == terrain) continue; + + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(r, d); + if (rn==NULL) { + int x = r->x + delta_x[d]; + int y = r->y + delta_y[d]; + pnormalize(&x, &y, pl); + rn = new_region(x, y, pl, 0); + terraform_region(rn, terrain); + rn->age=r->age; + } + } + } +} + +static void +prepare_starting_region(region * r) +{ + int n, t; + double p; + + assert(r->land); + + /* population between 30% and 60% of max */ + p = rng_double(); + n = (int)(r->terrain->size * (0.3 + p*0.3)); + rsetpeasants(r, n); + + /* trees: don't squash the peasants, and at least 5% should be forrest */ + t = (rtrees(r, 2) + rtrees(r, 1)/2) * TREESIZE; + if (t < r->terrain->size/20 || t+n > r->terrain->size) { + double p2 = 0.05 + rng_double()*(1.0-p-0.05); + int maxtrees = (int)(r->terrain->size/1.25/TREESIZE); /* 1.25 = each young tree will take 1/2 the space of old trees */ + int trees = (int)(p2 * maxtrees); + + rsettrees(r, 2, trees); + rsettrees(r, 1, trees/2); + rsettrees(r, 0, trees/4); + } + + /* horses: between 1% and 2% */ + p = rng_double(); + rsethorses(r, (int)(r->terrain->size * (0.01 + p*0.01))); + + if (!markets_module()) { + fix_demand(r); + } +} + +/** create new island with up to nsize players + * returns the number of players placed on the new island. + */ +int +autoseed(newfaction ** players, int nsize, int max_agediff) +{ + region * r = NULL; + region_list * rlist = NULL; + int rsize = 0, tsize = 0; + int isize = REGIONS_PER_FACTION; /* target size for the island */ + int psize = 0; /* players on this island */ + const terrain_type * volcano_terrain = get_terrain("volcano"); + static int nterrains = -1; + static const terrain_type ** terrainarr = 0; + static int * distribution; + + if (nterrains<0) { + int n = 0; + const terrain_type * terrain = terrains(); + for (nterrains=0;terrain;terrain=terrain->next) { + if (terrain->distribution) { + ++nterrains; + } + } + terrainarr = malloc(sizeof(terrain_type *) * nterrains); + distribution = malloc(sizeof(int) * nterrains); + for (terrain = terrains();terrain;terrain = terrain->next) { + if (terrain->distribution) { + terrainarr[n] = terrain; + distribution[n++] = terrain->distribution; + } + } + } + frame_regions(16, newterrain(T_FIREWALL)); + + if (listlen(*players)0) { + region * rmin = NULL; + plane * hplane = get_homeplane(); + /* find a spot that's adjacent to the previous island, but virgin. + * like the last land virgin ocean region adjacent to land. + */ + for (r=regions;r;r=r->next) { + struct plane * pl = rplane(r); + if (r->age<=max_agediff && r->terrain == newterrain(T_OCEAN) && pl==hplane && virgin_region(r)) { + direction_t d; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(r, d); + if (rn && rn->land && rn->age<=max_agediff && virgin_region(rn)) { + /* only expand islands that aren't single-islands and not too big already */ + int size, inhabitants, maxage; + get_island_info(rn, &size, &inhabitants, &maxage); + if (maxage<=max_agediff && size>=2 && sizenext) { + region * r = rlist->data; + unit * u; + for (u=r->units;u;u=u->next) { + f = u->faction; + if (!fval(f, FFL_MARK)) { + ++psize; + fset(f, FFL_MARK); + } + } + } + free_regionlist(rlist); + if (psize>0) for (f=factions;f;f=f->next) freset(f, FFL_MARK); + if (psizenext) { + struct plane * pl = rplane(r); + if (r->terrain == newterrain(T_OCEAN) && pl==hplane && (rmin==NULL || r->age<=max_agediff)) { + direction_t d; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(r, d); + if (rn==NULL) break; + } + if (d!=MAXDIRECTIONS) { + rmin=r; + dmin=d; + } + } + } + + /* create a new region where we found the empty spot, and make it the first + * in our island. island regions are kept in rlist, so only new regions can + * get populated, and old regions are not overwritten */ + if (rmin!=NULL) { + plane * pl = rplane(rmin); + int x = rmin->x + delta_x[dmin]; + int y = rmin->y + delta_y[dmin]; + pnormalize(&x, &y, pl); + assert(virgin_region(rconnect(rmin, dmin))); + r = new_region(x, y, pl, 0); + terraform_region(r, newterrain(T_OCEAN)); + } + } + if (r!=NULL) { + add_regionlist(&rlist, r); + fset(r, RF_MARK); + rsize = 1; + } + + while (rsize && (nsize || isize>=REGIONS_PER_FACTION)) { + int i = rng_int() % rsize; + region_list ** rnext = &rlist; + region_list * rfind; + direction_t d; + while (i--) rnext=&(*rnext)->next; + rfind = *rnext; + r = rfind->data; + freset(r, RF_MARK); + *rnext = rfind->next; + free(rfind); + --rsize; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(r, d); + if (rn && fval(rn, RF_MARK)) continue; + if (rn==NULL) { + plane * pl = rplane(r); + int x = r->x + delta_x[d]; + int y = r->y + delta_y[d]; + pnormalize(&x, &y, pl); + rn = new_region(x, y, pl, 0); + terraform_region(rn, newterrain(T_OCEAN)); + } + if (virgin_region(rn)) { + add_regionlist(&rlist, rn); + fset(rn, RF_MARK); + ++rsize; + } + } + if (volcano_terrain!=NULL && (rng_int() % VOLCANO_CHANCE == 0)) { + terraform_region(r, volcano_terrain); + } else if (nsize && (rng_int() % isize == 0 || rsize==0)) { + newfaction ** nfp, * nextf = *players; + faction * f; + unit * u; + + isize += REGIONS_PER_FACTION; + terraform_region(r, preferred_terrain(nextf->race)); + prepare_starting_region(r); + ++tsize; + assert(r->land && r->units==0); + u = addplayer(r, addfaction(nextf->email, nextf->password, nextf->race, + nextf->lang, nextf->subscription)); + f = u->faction; + fset(f, FFL_ISNEW); + f->alliance = nextf->allies; + log_printf("New faction (%s), %s at %s\n", itoa36(f->no), + f->email, regionname(r, NULL)); + if (f->subscription) { + sql_print(("UPDATE subscriptions SET status='ACTIVE', faction='%s', firstturn=%d, lastturn=%d, password='%s' WHERE id=%u;\n", + factionid(f), f->lastorders, f->lastorders, f->override, f->subscription)); + } + + /* remove duplicate email addresses */ + nfp = &nextf->next; + while (*nfp) { + newfaction * nf = *nfp; + if (strcmp(nextf->email, nf->email)==0) { + *nfp = nf->next; + free_newfaction(nf); + } + else nfp = &nf->next; + } + *players = nextf->next; + free_newfaction(nextf); + + ++psize; + --nsize; + --isize; + if (psize>=PLAYERS_PER_ISLAND) break; + } else { + terraform_region(r, random_terrain(terrainarr, distribution, nterrains)); + --isize; + } + } + + if (nsize!=0) { + log_error(("Could not place all factions on the same island as requested\n")); + } + + + if (rlist) { +#define MINOCEANDIST 3 +#define MAXOCEANDIST 6 +#define MAXFILLDIST 10 +#define SPECIALCHANCE 80 + region_list ** rbegin = &rlist; + int special = 1; + int oceandist = MINOCEANDIST + (rng_int() % (MAXOCEANDIST-MINOCEANDIST)); + while (oceandist--) { + region_list ** rend = rbegin; + while (*rend) rend=&(*rend)->next; + while (rbegin!=rend) { + direction_t d; + region * r = (*rbegin)->data; + rbegin=&(*rbegin)->next; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(r, d); + if (rn==NULL) { + const struct terrain_type * terrain = newterrain(T_OCEAN); + plane * pl = rplane(r); + int x = r->x + delta_x[d]; + int y = r->y + delta_y[d]; + pnormalize(&x, &y, pl); + rn = new_region(x, y, pl, 0); + if (rng_int() % SPECIALCHANCE < special) { + terrain = random_terrain(terrainarr, distribution, nterrains); + special = SPECIALCHANCE / 3; /* 33% chance auf noch eines */ + } else { + special = 1; + } + terraform_region(rn, terrain); + /* the new region has an extra 20% chance to have mallorn */ + if (rng_int() % 100 < 20) fset(r, RF_MALLORN); + add_regionlist(rend, rn); + } + } + } + + } + while (*rbegin) { + region * r = (*rbegin)->data; + plane * pl = rplane(r); + direction_t d; + rbegin=&(*rbegin)->next; + for (d=0;d!=MAXDIRECTIONS;++d) if (rconnect(r, d)==NULL) { + int i; + for (i=1;i!=MAXFILLDIST;++i) { + int x = r->x + delta_x[d]*i; + int y = r->y + delta_y[d]*i; + pnormalize(&x, &y, pl); + if (findregion(x, y)) { + break; + } + } + if (i!=MAXFILLDIST) { + while (--i) { + region * rn; + int x = r->x + delta_x[d]*i; + int y = r->y + delta_y[d]*i; + pnormalize(&x, &y, pl); + rn = new_region(x, y, pl, 0); + terraform_region(rn, newterrain(T_OCEAN)); + } + } + } + } + while (rlist) { + region_list * self = rlist; + rlist = rlist->next; + freset(self->data, RF_MARK); + free(self); + } + } + return tsize; +} + +region_list * regionqueue_push(region_list ** rlist, region * r) +{ + region_list * rnew = malloc(sizeof(region_list)); + rnew->data = r; + rnew->next = 0; + while (*rlist) { rlist = &(*rlist)->next; } + *rlist = rnew; + return rnew; +} + +region * regionqueue_pop(region_list ** rlist) +{ + if (*rlist) { + region * r = (*rlist)->data; + region_list * rpop = *rlist; + *rlist = rpop->next; + free(rpop); + return r; + } + return 0; +} + +#define GEOMAX 8 +static struct geo { + int distribution; + terrain_t type; +} geography_e3[GEOMAX] = { + { 8, T_OCEAN }, + { 3, T_SWAMP }, + { 1, T_VOLCANO }, + { 3, T_DESERT }, + { 4, T_HIGHLAND }, + { 3, T_MOUNTAIN }, + { 2, T_GLACIER }, + { 1, T_PLAIN } +}; + +const terrain_type * random_terrain_e3(direction_t dir) +{ + static const terrain_type ** terrainarr = 0; + static int * distribution = 0; + + if (!distribution) { + int n = 0; + + terrainarr = malloc(GEOMAX * sizeof(const terrain_type *)); + distribution = malloc(GEOMAX * sizeof(int)); + for (n=0;n!=GEOMAX;++n) { + terrainarr[n] = newterrain(geography_e3[n].type); + distribution[n] = geography_e3[n].distribution; + } + } + return random_terrain(terrainarr, distribution, GEOMAX); +} + +int +random_neighbours(region * r, region_list ** rlist, const terrain_type *(*terraformer)(direction_t)) +{ + int nsize = 0; + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * rn = rconnect(r, dir); + if (rn==NULL) { + const terrain_type * terrain = terraformer(dir); + plane * pl = rplane(r); + int x = r->x + delta_x[dir]; + int y = r->y + delta_y[dir]; + pnormalize(&x, &y, pl); + rn = new_region(x, y, pl, 0); + terraform_region(rn, terrain); + regionqueue_push(rlist, rn); + if (rn->land) { + ++nsize; + } + } + } + return nsize; +} + +const terrain_type * get_ocean(direction_t dir) +{ + return newterrain(T_OCEAN); +} + +int region_quality(const region * r, region * rn[]) +{ + int n, result = 0; + + for (n=0;n!=MAXDIRECTIONS;++n) { + if (rn[n] && rn[n]->land) { + if (rn[n]->terrain==newterrain(T_VOLCANO)) { + /* nobody likes volcanoes */ + result -= 2000; + } + result += rn[n]->land->peasants; + } + } + return result; +} + +static void +oceans_around(region * r, region * rn[]) +{ + int n; + for (n=0;n!=MAXDIRECTIONS;++n) { + region * rx = rn[n]; + if (rx==NULL) { + plane * pl = rplane(r); + int x = r->x + delta_x[n]; + int y = r->y + delta_y[n]; + pnormalize(&x, &y, pl); + rx = new_region(x, y, pl, 0); + terraform_region(rx, newterrain(T_OCEAN)); + rn[n] = rx; + } + } +} + +static void +smooth_island(region_list * island) +{ + region * rn[MAXDIRECTIONS]; + region_list * rlist = NULL; + for (rlist=island;rlist;rlist=rlist->next) { + region * r = rlist->data; + int n, nland = 0; + + if (r->land) { + get_neighbours(r, rn); + for (n=0;n!=MAXDIRECTIONS && nland<=1;++n) { + if (rn[n]->land) { + ++nland; + r = rn[n]; + } + } + + if (nland==1) { + get_neighbours(r, rn); + oceans_around(r, rn); + for (n=0;n!=MAXDIRECTIONS;++n) { + int n1 = (n+1)%MAXDIRECTIONS; + int n2 = (n+1+MAXDIRECTIONS)%MAXDIRECTIONS; + if (!rn[n]->land && rn[n1]!=r && rn[n2]!=r) { + r = rlist->data; + runhash(r); + runhash(rn[n]); + SWAP_VARS(int, r->x, rn[n]->x); + SWAP_VARS(int, r->y, rn[n]->y); + rhash(r); + rhash(rn[n]); + rlist->data = r; + oceans_around(r, rn); + break; + } + } + } + } + } +} + +static void +starting_region(region * r, region * rn[]) +{ + unit * u; + int n; + + oceans_around(r, rn); + freset(r, RF_MARK); + for (n=0;n!=MAXDIRECTIONS;++n) { + freset(rn[n], RF_MARK); + } + terraform_region(r, newterrain(T_PLAIN)); + prepare_starting_region(r); + u = addplayer(r, addfaction("enno@eressea.de", itoa36(rng_int()), races, + default_locale, 0)); +} +/* E3A island generation */ +int +build_island_e3(int x, int y, int numfactions, int minsize) +{ +#define MIN_QUALITY 1000 + int nfactions = 0; + region_list * rlist = NULL; + region_list * island = NULL; + plane * pl = findplane(x, y); + region * r = findregion(x, y); + int nsize = 1; + int q, maxq = INT_MIN, minq = INT_MAX; + + if (!r) r = new_region(x, y, pl, 0); + assert(!r->units); + do { + terraform_region(r, random_terrain_e3(NODIRECTION)); + } while (!r->land); + + while (r) { + fset(r, RF_MARK); + if (r->land) { + if (nsizeminsize/2) { + for (rlist=island;rlist;rlist=rlist->next) { + r = rlist->data; + if (r->land && fval(r, RF_MARK)) { + region *rn[MAXDIRECTIONS]; + + get_neighbours(r, rn); + q = region_quality(r,rn); + if (q>=MIN_QUALITY && nfactionsnext) { + r = rlist->data; + if (!r->land && fval(r, RF_MARK)) { + region *rn[MAXDIRECTIONS]; + get_neighbours(r, rn); + q = region_quality(r, rn); + if (q>=MIN_QUALITY*4/3 && nfactionsnext) { + r = rlist->data; + if (r->units) { + region *rn[MAXDIRECTIONS]; + get_neighbours(r, rn); + q = region_quality(r, rn); + if (q-minq > (maxq-minq)*2/3) { + terraform_region(r, newterrain(T_HIGHLAND)); + prepare_starting_region(r); + } + r->land->money = 50000; /* 2% = 1000 silver */ + } else if (r->land) { + r->land->money *= 4; + } + } + return nfactions; +} diff --git a/src/modules/autoseed.h b/src/modules/autoseed.h index 0fcb75da5..2c023f3f4 100644 --- a/src/modules/autoseed.h +++ b/src/modules/autoseed.h @@ -1,50 +1,50 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef _REGIONLIST_H -#define _REGIONLIST_H -#ifdef __cplusplus -extern "C" { -#endif - - -struct region_list; -struct newfaction; - -typedef struct newfaction { - struct newfaction * next; - char * email; - char * password; - const struct locale * lang; - const struct race * race; - int bonus; - int subscription; - boolean oldregions; - struct alliance * allies; -} newfaction; - -#define ISLANDSIZE 20 -#define TURNS_PER_ISLAND 5 - -extern int autoseed(newfaction ** players, int nsize, int max_agediff); -extern newfaction * read_newfactions(const char * filename); -extern void get_island(struct region * root, struct region_list ** rlist); -extern int fix_demand(struct region *r); -extern const struct terrain_type * random_terrain(const struct terrain_type * terrains[], int distribution[], int size); - -extern int seed_adamantium(struct region * r, int base); -extern int build_island_e3(int x, int y, int numfactions, int minsize); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef _REGIONLIST_H +#define _REGIONLIST_H +#ifdef __cplusplus +extern "C" { +#endif + + +struct region_list; +struct newfaction; + +typedef struct newfaction { + struct newfaction * next; + char * email; + char * password; + const struct locale * lang; + const struct race * race; + int bonus; + int subscription; + boolean oldregions; + struct alliance * allies; +} newfaction; + +#define ISLANDSIZE 20 +#define TURNS_PER_ISLAND 5 + +extern int autoseed(newfaction ** players, int nsize, int max_agediff); +extern newfaction * read_newfactions(const char * filename); +extern void get_island(struct region * root, struct region_list ** rlist); +extern int fix_demand(struct region *r); +extern const struct terrain_type * random_terrain(const struct terrain_type * terrains[], int distribution[], int size); + +extern int seed_adamantium(struct region * r, int base); +extern int build_island_e3(int x, int y, int numfactions, int minsize); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/dungeon.c b/src/modules/dungeon.c index a8275bbda..c8a5fb6a9 100644 --- a/src/modules/dungeon.c +++ b/src/modules/dungeon.c @@ -1,268 +1,268 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include - -#if DUNGEON_MODULE -#include "dungeon.h" -#include "gmcmd.h" - -#include -#include - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include - -/* libc includes */ -#include -#include -#include - -typedef struct treasure { - const struct item_type * itype; - int amount; - struct treasure * next; -} treasure; - -typedef struct monster { - const struct race * race; - double chance; - int maxunits; - int avgsize; - struct treasure * treasures; - struct monster * next; - struct itemtype_list * weapons; -} monster; - -typedef struct skilllimit { - skill_t skill; - int minskill; - int maxskill; - struct skilllimit * next; -} skilllimit; - -typedef struct dungeon { - int level; - int radius; - int size; - int maxpeople; - struct skilllimit * limits; - double connect; - struct monster * boss; - struct monster * monsters; - struct dungeon * next; -} dungeon; - -dungeon * dungeonstyles; - -region * -make_dungeon(const dungeon * data) -{ - int nb[2][3][2] = { - { { -1, 0 }, { 0, 1 }, { 1, -1 } }, - { { 1, 0 }, { -1, 1 }, { 0, -1 } } - }; - const struct race * bossrace = data->boss->race; - char name[128]; - int size = data->size; - int iterations = size * size; - unsigned int flags = PFL_NORECRUITS; - int n = 0; - struct faction * fmonsters = get_monsters(); - plane * p; - region *r, *center; - region * rnext; - region_list * iregion, * rlist = NULL; - const terrain_type * terrain_hell = get_terrain("hell"); - - assert(terrain_hell!=NULL); - sprintf(name, "Die Höhlen von %s", bossrace->generate_name(NULL)); - p = gm_addplane(data->radius, flags, name); - - center = findregion(p->minx+(p->maxx-p->minx)/2, p->miny+(p->maxy-p->miny)/2); - assert(center); - terraform_region(center, terrain_hell); - add_regionlist(&rlist, center); - rnext = r = center; - while (size>0 && iterations--) { - int d, o = rng_int() % 3; - for (d=0;d!=3;++d) { - int index = (d+o) % 3; - region * rn = findregion(r->x+nb[n][index][0], r->y+nb[n][index][1]); - assert(r->terrain==terrain_hell); - if (rn) { - if (rn->terrain==terrain_hell) { - rnext = rn; - } else if (fval(rn->terrain, SEA_REGION)) { - if (rng_int() % 100 < data->connect*100) { - terraform_region(rn, terrain_hell); - --size; - rnext = rn; - add_regionlist(&rlist, rn); - } - else terraform(rn, T_FIREWALL); - } - if (size == 0) break; - } - rn = findregion(r->x+nb[(n+1)%2][index][0], r->y+nb[(n+1)%2][index][1]); - if (rn && fval(rn->terrain, SEA_REGION)) { - terraform(rn, T_FIREWALL); - } - } - if (size==0) break; - if (r==rnext) { - /* error */ - break; - } - r = rnext; - n = (n+1) % 2; - } - - for (iregion=rlist;iregion;iregion=iregion->next) { - monster * m = data->monsters; - region * r = iregion->data; - while (m) { - if ((rng_int() % 100) < (m->chance * 100)) { - /* TODO: check maxunits. */ - treasure * loot = m->treasures; - struct itemtype_list * weapon = m->weapons; - int size = 1 + (rng_int() % m->avgsize) + (rng_int() % m->avgsize); - unit * u = createunit(r, fmonsters, size, m->race); - while (weapon) { - i_change(&u->items, weapon->type, size); - weapon = weapon->next; - } - while (loot) { - i_change(&u->items, loot->itype, loot->amount*size); - loot = loot->next; - } - } - m = m->next; - } - } - return center; -} - -void -make_dungeongate(region * source, region * target, const struct dungeon * d) -{ - building *bsource, *btarget; - - if (source==NULL || target==NULL || d==NULL) return; - bsource = new_building(bt_find("castle"), source, default_locale); - set_string(&bsource->name, "Pforte zur Hölle"); - bsource->size = 50; - add_trigger(&bsource->attribs, "timer", trigger_gate(bsource, target)); - add_trigger(&bsource->attribs, "create", trigger_unguard(bsource)); - fset(bsource, BLD_UNGUARDED); - - btarget = new_building(bt_find("castle"), target, default_locale); - set_string(&btarget->name, "Pforte zur Außenwelt"); - btarget->size = 50; - add_trigger(&btarget->attribs, "timer", trigger_gate(btarget, source)); - add_trigger(&btarget->attribs, "create", trigger_unguard(btarget)); - fset(btarget, BLD_UNGUARDED); -} - -static int -tagbegin(xml_stack *stack) -{ - xml_tag * tag = stack->tag; - if (strcmp(tag->name, "dungeon")==0) { - dungeon * d = (dungeon*)calloc(sizeof(dungeon), 1); - d->maxpeople = xml_ivalue(tag, "maxpeople"); - if (d->maxpeople==0) d->maxpeople = INT_MAX; - d->level = xml_ivalue(tag, "level"); - d->radius = xml_ivalue(tag, "radius"); - d->connect = xml_fvalue(tag, "connect"); - d->size = xml_ivalue(tag, "size"); - stack->state = d; - } else { - dungeon * d = (dungeon*)stack->state; - if (strcmp(tag->name, "skilllimit")==0) { - skill_t sk = sk_find(xml_value(tag, "name")); - if (sk!=NOSKILL) { - skilllimit * skl = calloc(sizeof(skilllimit), 1); - skl->skill = sk; - if (xml_value(tag, "max")!=NULL) { - skl->maxskill = xml_ivalue(tag, "max"); - } else skl->maxskill = INT_MAX; - if (xml_value(tag, "min")!=NULL) { - skl->minskill = xml_ivalue(tag, "min"); - } else skl->maxskill = INT_MIN; - skl->next = d->limits; - d->limits = skl; - } - } else if (strcmp(tag->name, "monster")==0) { - monster * m = calloc(sizeof(monster), 1); - m->race = rc_find(xml_value(tag, "race")); - m->chance = xml_fvalue(tag, "chance"); - m->avgsize = MAX(1, xml_ivalue(tag, "size")); - m->maxunits = MIN(1, xml_ivalue(tag, "maxunits")); - - if (m->race) { - if (xml_bvalue(tag, "boss")) { - d->boss = m; - } else { - m->next = d->monsters; - d->monsters = m; - } - } - } else if (strcmp(tag->name, "weapon")==0) { - monster * m = d->monsters; - itemtype_list * w = calloc(sizeof(itemtype_list), 1); - w->type = it_find(xml_value(tag, "type")); - if (w->type) { - w->next = m->weapons; - m->weapons = w; - } - } - } - return XML_OK; -} - -static int -tagend(xml_stack * stack) -{ - xml_tag * tag = stack->tag; - if (strcmp(tag->name, "dungeon")) { - dungeon * d = (dungeon*)stack->state; - stack->state = NULL; - d->next = dungeonstyles; - dungeonstyles = d; - } - return XML_OK; -} - -xml_callbacks xml_dungeon = { - tagbegin, tagend, NULL -}; - -void -register_dungeon(void) -{ - xml_register(&xml_dungeon, "eressea dungeon", 0); -} - -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include + +#if DUNGEON_MODULE +#include "dungeon.h" +#include "gmcmd.h" + +#include +#include + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include + +/* libc includes */ +#include +#include +#include + +typedef struct treasure { + const struct item_type * itype; + int amount; + struct treasure * next; +} treasure; + +typedef struct monster { + const struct race * race; + double chance; + int maxunits; + int avgsize; + struct treasure * treasures; + struct monster * next; + struct itemtype_list * weapons; +} monster; + +typedef struct skilllimit { + skill_t skill; + int minskill; + int maxskill; + struct skilllimit * next; +} skilllimit; + +typedef struct dungeon { + int level; + int radius; + int size; + int maxpeople; + struct skilllimit * limits; + double connect; + struct monster * boss; + struct monster * monsters; + struct dungeon * next; +} dungeon; + +dungeon * dungeonstyles; + +region * +make_dungeon(const dungeon * data) +{ + int nb[2][3][2] = { + { { -1, 0 }, { 0, 1 }, { 1, -1 } }, + { { 1, 0 }, { -1, 1 }, { 0, -1 } } + }; + const struct race * bossrace = data->boss->race; + char name[128]; + int size = data->size; + int iterations = size * size; + unsigned int flags = PFL_NORECRUITS; + int n = 0; + struct faction * fmonsters = get_monsters(); + plane * p; + region *r, *center; + region * rnext; + region_list * iregion, * rlist = NULL; + const terrain_type * terrain_hell = get_terrain("hell"); + + assert(terrain_hell!=NULL); + sprintf(name, "Die Höhlen von %s", bossrace->generate_name(NULL)); + p = gm_addplane(data->radius, flags, name); + + center = findregion(p->minx+(p->maxx-p->minx)/2, p->miny+(p->maxy-p->miny)/2); + assert(center); + terraform_region(center, terrain_hell); + add_regionlist(&rlist, center); + rnext = r = center; + while (size>0 && iterations--) { + int d, o = rng_int() % 3; + for (d=0;d!=3;++d) { + int index = (d+o) % 3; + region * rn = findregion(r->x+nb[n][index][0], r->y+nb[n][index][1]); + assert(r->terrain==terrain_hell); + if (rn) { + if (rn->terrain==terrain_hell) { + rnext = rn; + } else if (fval(rn->terrain, SEA_REGION)) { + if (rng_int() % 100 < data->connect*100) { + terraform_region(rn, terrain_hell); + --size; + rnext = rn; + add_regionlist(&rlist, rn); + } + else terraform(rn, T_FIREWALL); + } + if (size == 0) break; + } + rn = findregion(r->x+nb[(n+1)%2][index][0], r->y+nb[(n+1)%2][index][1]); + if (rn && fval(rn->terrain, SEA_REGION)) { + terraform(rn, T_FIREWALL); + } + } + if (size==0) break; + if (r==rnext) { + /* error */ + break; + } + r = rnext; + n = (n+1) % 2; + } + + for (iregion=rlist;iregion;iregion=iregion->next) { + monster * m = data->monsters; + region * r = iregion->data; + while (m) { + if ((rng_int() % 100) < (m->chance * 100)) { + /* TODO: check maxunits. */ + treasure * loot = m->treasures; + struct itemtype_list * weapon = m->weapons; + int size = 1 + (rng_int() % m->avgsize) + (rng_int() % m->avgsize); + unit * u = createunit(r, fmonsters, size, m->race); + while (weapon) { + i_change(&u->items, weapon->type, size); + weapon = weapon->next; + } + while (loot) { + i_change(&u->items, loot->itype, loot->amount*size); + loot = loot->next; + } + } + m = m->next; + } + } + return center; +} + +void +make_dungeongate(region * source, region * target, const struct dungeon * d) +{ + building *bsource, *btarget; + + if (source==NULL || target==NULL || d==NULL) return; + bsource = new_building(bt_find("castle"), source, default_locale); + set_string(&bsource->name, "Pforte zur Hölle"); + bsource->size = 50; + add_trigger(&bsource->attribs, "timer", trigger_gate(bsource, target)); + add_trigger(&bsource->attribs, "create", trigger_unguard(bsource)); + fset(bsource, BLD_UNGUARDED); + + btarget = new_building(bt_find("castle"), target, default_locale); + set_string(&btarget->name, "Pforte zur Außenwelt"); + btarget->size = 50; + add_trigger(&btarget->attribs, "timer", trigger_gate(btarget, source)); + add_trigger(&btarget->attribs, "create", trigger_unguard(btarget)); + fset(btarget, BLD_UNGUARDED); +} + +static int +tagbegin(xml_stack *stack) +{ + xml_tag * tag = stack->tag; + if (strcmp(tag->name, "dungeon")==0) { + dungeon * d = (dungeon*)calloc(sizeof(dungeon), 1); + d->maxpeople = xml_ivalue(tag, "maxpeople"); + if (d->maxpeople==0) d->maxpeople = INT_MAX; + d->level = xml_ivalue(tag, "level"); + d->radius = xml_ivalue(tag, "radius"); + d->connect = xml_fvalue(tag, "connect"); + d->size = xml_ivalue(tag, "size"); + stack->state = d; + } else { + dungeon * d = (dungeon*)stack->state; + if (strcmp(tag->name, "skilllimit")==0) { + skill_t sk = sk_find(xml_value(tag, "name")); + if (sk!=NOSKILL) { + skilllimit * skl = calloc(sizeof(skilllimit), 1); + skl->skill = sk; + if (xml_value(tag, "max")!=NULL) { + skl->maxskill = xml_ivalue(tag, "max"); + } else skl->maxskill = INT_MAX; + if (xml_value(tag, "min")!=NULL) { + skl->minskill = xml_ivalue(tag, "min"); + } else skl->maxskill = INT_MIN; + skl->next = d->limits; + d->limits = skl; + } + } else if (strcmp(tag->name, "monster")==0) { + monster * m = calloc(sizeof(monster), 1); + m->race = rc_find(xml_value(tag, "race")); + m->chance = xml_fvalue(tag, "chance"); + m->avgsize = MAX(1, xml_ivalue(tag, "size")); + m->maxunits = MIN(1, xml_ivalue(tag, "maxunits")); + + if (m->race) { + if (xml_bvalue(tag, "boss")) { + d->boss = m; + } else { + m->next = d->monsters; + d->monsters = m; + } + } + } else if (strcmp(tag->name, "weapon")==0) { + monster * m = d->monsters; + itemtype_list * w = calloc(sizeof(itemtype_list), 1); + w->type = it_find(xml_value(tag, "type")); + if (w->type) { + w->next = m->weapons; + m->weapons = w; + } + } + } + return XML_OK; +} + +static int +tagend(xml_stack * stack) +{ + xml_tag * tag = stack->tag; + if (strcmp(tag->name, "dungeon")) { + dungeon * d = (dungeon*)stack->state; + stack->state = NULL; + d->next = dungeonstyles; + dungeonstyles = d; + } + return XML_OK; +} + +xml_callbacks xml_dungeon = { + tagbegin, tagend, NULL +}; + +void +register_dungeon(void) +{ + xml_register(&xml_dungeon, "eressea dungeon", 0); +} + +#endif diff --git a/src/modules/dungeon.h b/src/modules/dungeon.h index b0526e5a9..12960cbdb 100644 --- a/src/modules/dungeon.h +++ b/src/modules/dungeon.h @@ -1,36 +1,36 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_MOD_DUNGEON -#define H_MOD_DUNGEON -#ifdef __cplusplus -extern "C" { -#endif - -#if DUNGEON_MODULE == 0 -#error "must define DUNGEON_MODULE to use this module" -#endif - -struct region; -struct plane; -struct building; -struct dungeon; - -extern struct dungeon * dungeonstyles; -extern struct region * make_dungeon(const struct dungeon*); -extern void make_dungeongate(struct region * source, struct region * target, const struct dungeon *); -extern void register_dungeon(void); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_MOD_DUNGEON +#define H_MOD_DUNGEON +#ifdef __cplusplus +extern "C" { +#endif + +#if DUNGEON_MODULE == 0 +#error "must define DUNGEON_MODULE to use this module" +#endif + +struct region; +struct plane; +struct building; +struct dungeon; + +extern struct dungeon * dungeonstyles; +extern struct region * make_dungeon(const struct dungeon*); +extern void make_dungeongate(struct region * source, struct region * target, const struct dungeon *); +extern void register_dungeon(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/gmcmd.c b/src/modules/gmcmd.c index 61b216e4e..ced1d27f9 100644 --- a/src/modules/gmcmd.c +++ b/src/modules/gmcmd.c @@ -1,772 +1,772 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "gmcmd.h" -#include - -/* misc includes */ -#include -#include -#include -#include - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -/** - ** at_permissions - **/ - -static void -mistake(const unit * u, struct order * ord, const char *comment) -{ - if (!is_monsters(u->faction)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "mistake", - "error", comment)); - } -} - -static void -write_permissions(const attrib * a, const void * owner, struct storage * store) -{ - a_write(store, (attrib*)a->data.v, owner); -} - -static int -read_permissions(attrib * a, void * owner, struct storage * store) -{ - attrib * attr = NULL; - a_read(store, &attr, NULL); - a->data.v = attr; - return AT_READ_OK; -} - -struct attrib_type at_permissions = { - "GM:permissions", - NULL, NULL, NULL, - write_permissions, read_permissions, - ATF_UNIQUE -}; - -attrib * -make_atpermissions(void) -{ - return a_new(&at_permissions); -} - -/** - ** GM: CREATE - **/ - -static void -write_gmcreate(const attrib * a, const void * owner, struct storage * store) -{ - const item_type * itype = (const item_type *)a->data.v; - assert(itype); - store->w_tok(store, resourcename(itype->rtype, 0)); -} - -static int -read_gmcreate(attrib * a, void * owner, struct storage * store) -{ - char zText[32]; - store->r_tok_buf(store, zText, sizeof(zText)); - a->data.v = it_find(zText); - if (a->data.v == NULL) { - log_error(("unknown itemtype %s in gmcreate attribute\n", zText)); - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -/* at_gmcreate specifies that the owner can create items of a particular type */ -attrib_type at_gmcreate = { - "GM:create", - NULL, NULL, NULL, - write_gmcreate, read_gmcreate -}; - -attrib * -make_atgmcreate(const struct item_type * itype) -{ - attrib * a = a_new(&at_gmcreate); - a->data.v = (void*)itype; - return a; -} - -static void -gm_create(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - int i; - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (permissions) permissions = (attrib*)permissions->data.v; - if (!permissions) return; - i = getint(); - - if (i>0) { - const char * iname = getstrtoken(); - const item_type * itype = finditemtype(iname, u->faction->locale); - if (itype==NULL) { - mistake(u, ord, "unknown item."); - } else { - attrib * a = a_find(permissions, &at_gmcreate); - - while (a && a->type==&at_gmcreate && a->data.v!=(void*)itype) a=a->next; - if (a) i_change(&u->items, itype, i); - else mistake(u, ord, "your faction cannot create this item."); - } - } -} - -static boolean -has_permission(const attrib * permissions, unsigned int key) -{ - return (find_key((attrib*)permissions->data.v, key) || - find_key((attrib*)permissions->data.v, atoi36("master"))); -} - -/** - ** GM: GATE - ** requires: permission-key "gmgate" - **/ -static void -gm_gate(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - const struct plane * pl = rplane(u->region); - int id = getid(); - int x = rel_to_abs(pl, u->faction, getint(), 0); - int y = rel_to_abs(pl, u->faction, getint(), 1); - building * b = findbuilding(id); - region * r; - - pnormalize(&x, &y, pl); - r = findregion(x, y); - if (b==NULL || r==NULL || pl!=rplane(b->region) || pl!=rplane(r)) { - mistake(u, ord, "the unit cannot transform this building."); - return; - } else { - /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (permissions && has_permission(permissions, atoi36("gmgate"))) { - remove_triggers(&b->attribs, "timer", &tt_gate); - remove_triggers(&b->attribs, "create", &tt_unguard); - if (r!=b->region) { - add_trigger(&b->attribs, "timer", trigger_gate(b, r)); - add_trigger(&b->attribs, "create", trigger_unguard(b)); - fset(b, BLD_UNGUARDED); - } - } - } -} - - -/** - ** GM: TERRAFORM - ** requires: permission-key "gmterf" - **/ -static void -gm_terraform(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - const struct plane * p = rplane(u->region); - int x = rel_to_abs(p, u->faction, getint(), 0); - int y = rel_to_abs(p, u->faction, getint(), 1); - const char * c = getstrtoken(); - variant token; - tnode * tokens = get_translations(u->faction->locale, UT_TERRAINS); - region * r; - pnormalize(&x, &y, p); - r = findregion(x, y); - - if (r==NULL || p!=rplane(r)) { - mistake(u, ord, "region is in another plane."); - return; - } else { - /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmterf"))) return; - } - - if (findtoken(tokens, c, &token)!=E_TOK_NOMATCH) { - const terrain_type * terrain = (const terrain_type *)token.v; - terraform_region(r, terrain); - } -} - -/** - ** GM: TELEPORT - ** requires: permission-key "gmtele" - **/ -static void -gm_teleport(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - const struct plane * p = rplane(u->region); - unit * to = findunit(getid()); - int x = rel_to_abs(p, u->faction, getint(), 0); - int y = rel_to_abs(p, u->faction, getint(), 1); - region * r = findregion(x, y); - - if (r==NULL || p!=rplane(r)) { - mistake(u, ord, "region is in another plane."); - } else if (to==NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } else if (rplane(to->region)!=rplane(r) && !ucontact(to, u)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", "target", to)); - } else { - /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmtele"))) { - mistake(u, ord, "permission denied."); - } - else move_unit(to, r, NULL); - } -} - -/** - ** GM: TELL PLANE - ** requires: permission-key "gmmsgr" - **/ -static void -gm_messageplane(const tnode * tnext, void * data, struct order * ord) -{ - unit * gm = (unit*)data; - const struct plane * p = rplane(gm->region); - const char * zmsg = getstrtoken(); - if (p==NULL) { - mistake(gm, ord, "In diese Ebene kann keine Nachricht gesandt werden."); - } else { - /* checking permissions */ - attrib * permissions = a_find(gm->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { - mistake(gm, ord, "permission denied."); - } - else { - message * msg = msg_message("msg_event", "string", zmsg); - faction * f; - region * r; - for (f=factions;f;f=f->next) { - freset(f, FFL_SELECT); - } - for (r=regions;r;r=r->next) { - unit * u; - if (rplane(r)!=p) continue; - for (u=r->units;u;u=u->next) if (!fval(u->faction, FFL_SELECT)) { - f = u->faction; - fset(f, FFL_SELECT); - add_message(&f->msgs, msg); - } - } - msg_release(msg); - } - } -} - -static void -gm_messagefaction(const tnode * tnext, void * data, struct order * ord) -{ - unit * gm = (unit*)data; - int n = getid(); - faction * f = findfaction(n); - const char * msg = getstrtoken(); - plane * p = rplane(gm->region); - attrib * permissions = a_find(gm->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { - mistake(gm, ord, "permission denied."); - return; - } - if (f!=NULL) { - region * r; - for (r=regions;r;r=r->next) if (rplane(r)==p) { - unit * u; - for (u=r->units;u;u=u->next) if (u->faction==f) { - add_message(&f->msgs, msg_message("msg_event", "string", msg)); - return; - } - } - } - mistake(gm, ord, "cannot send messages to this faction."); -} - -/** - ** GM: TELL REGION - ** requires: permission-key "gmmsgr" - **/ -static void -gm_messageregion(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - const struct plane * p = rplane(u->region); - int x = rel_to_abs(p, u->faction, getint(), 0); - int y = rel_to_abs(p, u->faction, getint(), 1); - const char * msg = getstrtoken(); - region * r = findregion(x, y); - - if (r==NULL || p!=rplane(r)) { - mistake(u, ord, "region is in another plane."); - } else { - /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { - mistake(u, ord, "permission denied."); - } - else { - add_message(&r->msgs, msg_message("msg_event", "string", msg)); - } - } -} - -/** - ** GM: KILL UNIT - ** requires: permission-key "gmkill" - **/ -static void -gm_killunit(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - const struct plane * p = rplane(u->region); - unit * target = findunit(getid()); - const char * msg = getstrtoken(); - region * r = target->region; - - if (r==NULL || p!=rplane(r)) { - mistake(u, ord, "region is in another plane."); - } else { - /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmkill"))) { - mistake(u, ord, "permission denied."); - } - else { - scale_number(target, 0); - ADDMSG(&target->faction->msgs, msg_message("killedbygm", - "region unit string", r, target, msg)); - } - } -} - - -/** - ** GM: KILL FACTION - ** requires: permission-key "gmmsgr" - **/ -static void -gm_killfaction(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - int n = getid(); - faction * f = findfaction(n); - const char * msg = getstrtoken(); - plane * p = rplane(u->region); - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmkill"))) { - mistake(u, ord, "permission denied."); - return; - } - if (f!=NULL) { - region * r; - for (r=regions;r;r=r->next) if (rplane(r)==p) { - unit * target; - for (target=r->units;target;target=target->next) { - if (target->faction==f) { - scale_number(target, 0); - ADDMSG(&target->faction->msgs, msg_message("killedbygm", - "region unit string", r, target, msg)); - return; - } - } - } - } - mistake(u, ord, "cannot remove a unit from this faction."); -} - -/** - ** GM: TELL - ** requires: permission-key "gmmsgr" - **/ -static void -gm_messageunit(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - const struct plane * p = rplane(u->region); - unit * target = findunit(getid()); - const char * msg = getstrtoken(); - region * r; - - if (target == NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return; - } - - r = target->region; - - if (r==NULL || p!=rplane(r)) { - mistake(u, ord, "region is in another plane."); - } else { - /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmmsgu"))) { - mistake(u, ord, "permission denied."); - } - else { - add_message(&target->faction->msgs, - msg_message("regionmessage", "region sender string", r, u, msg)); - } - } -} - -/** - ** GM: GIVE - ** requires: permission-key "gmgive" - **/ -static void -gm_give(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - unit * to = findunit(getid()); - int num = getint(); - const item_type * itype = finditemtype(getstrtoken(), u->faction->locale); - - if (to==NULL || rplane(to->region) != rplane(u->region)) { - /* unknown or in another plane */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } else if (itype==NULL || i_get(u->items, itype)==0) { - /* unknown or not enough */ - mistake(u, ord, "invalid item or item not found."); - } else { - /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmgive"))) { - mistake(u, ord, "permission denied."); - } - else { - int i = i_get(u->items, itype); - if (iitems, itype, -num); - i_change(&to->items, itype, num); - } - } - } -} - -/** - ** GM: TAKE - ** requires: permission-key "gmtake" - **/ -static void -gm_take(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - unit * to = findunit(getid()); - int num = getint(); - const item_type * itype = finditemtype(getstrtoken(), u->faction->locale); - - if (to==NULL || rplane(to->region) != rplane(u->region)) { - /* unknown or in another plane */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } else if (itype==NULL || i_get(to->items, itype)==0) { - /* unknown or not enough */ - mistake(u, ord, "invalid item or item not found."); - } else { - /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmtake"))) { - mistake(u, ord, "permission denied."); - } - else { - int i = i_get(to->items, itype); - if (iitems, itype, -num); - i_change(&u->items, itype, num); - } - } - } -} - -/** - ** GM: SKILL - ** requires: permission-key "gmskil" - **/ -static void -gm_skill(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - unit * to = findunit(getid()); - skill_t skill = findskill(getstrtoken(), u->faction->locale); - int num = getint(); - - if (to==NULL || rplane(to->region) != rplane(u->region)) { - /* unknown or in another plane */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } else if (skill==NOSKILL || skill==SK_MAGIC || skill==SK_ALCHEMY) { - /* unknown or not enough */ - mistake(u, ord, "unknown skill, or skill cannot be raised."); - } else if (num<0 || num>30) { - /* sanity check failed */ - mistake(u, ord, "invalid value."); - } else { - /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmskil"))) { - mistake(u, ord, "permission denied."); - } - else { - set_level(to, skill, num); - } - } -} - -static tnode g_keys; -static tnode g_root; -static tnode g_tell; -static tnode g_kill; - -void -register_gmcmd(void) -{ - at_register(&at_gmcreate); - at_register(&at_permissions); - add_command(&g_root, &g_keys, "gm", NULL); - add_command(&g_keys, NULL, "terraform", &gm_terraform); - add_command(&g_keys, NULL, "create", &gm_create); - add_command(&g_keys, NULL, "gate", &gm_gate); - add_command(&g_keys, NULL, "give", &gm_give); - add_command(&g_keys, NULL, "take", &gm_take); - add_command(&g_keys, NULL, "teleport", &gm_teleport); - add_command(&g_keys, NULL, "skill", &gm_skill); - add_command(&g_keys, &g_tell, "tell", NULL); - add_command(&g_tell, NULL, "region", &gm_messageregion); - add_command(&g_tell, NULL, "unit", &gm_messageunit); - add_command(&g_tell, NULL, "plane", &gm_messageplane); - add_command(&g_tell, NULL, "faction", &gm_messagefaction); - add_command(&g_keys, &g_kill, "kill", NULL); - add_command(&g_kill, NULL, "unit", &gm_killunit); - add_command(&g_kill, NULL, "faction", &gm_killfaction); -} - -/* - * execute gm-commands for all units in the game - */ - -void -gmcommands(void) -{ - region ** rp = ®ions; - while (*rp) { - region * r = *rp; - unit **up = &r->units; - while (*up) { - unit * u = *up; - struct order * ord; - for (ord = u->orders; ord; ord = ord->next) { - if (get_keyword(ord) == K_GM) { - do_command(&g_root, u, ord); - } - } - if (u==*up) up = &u->next; - } - if (*rp==r) rp = &r->next; - } -} - -#define EXTENSION 10000 - -faction * -gm_addquest(const char * email, const char * name, int radius, unsigned int flags) -{ - plane * pl; - watcher * w = calloc(sizeof(watcher), 1); - region * center; - boolean invalid = false; - int minx, miny, maxx, maxy, cx, cy; - int x; - faction * f; - - /* GM playfield */ - do { - minx = ((rng_int() % (2*EXTENSION)) - EXTENSION); - miny = ((rng_int() % (2*EXTENSION)) - EXTENSION); - for (x=0;!invalid && x<=radius*2;++x) { - int y; - for (y=0;!invalid && y<=radius*2;++y) { - region * r = findregion(minx+x, miny+y); - if (r) invalid = true; - } - } - } while (invalid); - maxx = minx+2*radius; cx = minx+radius; - maxy = miny+2*radius; cy = miny+radius; - pl = create_new_plane(rng_int(), name, minx, maxx, miny, maxy, flags); - center = new_region(cx, cy, pl, 0); - for (x=0;x<=2*radius;++x) { - int y; - for (y=0;y<=2*radius;++y) { - region * r = findregion(minx+x, miny+y); - if (!r) { - r = new_region(minx+x, miny+y, pl, 0); - } - freset(r, RF_ENCOUNTER); - if (distance(r, center)==radius) { - terraform_region(r, newterrain(T_FIREWALL)); - } else if (r==center) { - terraform_region(r, newterrain(T_PLAIN)); - } else { - terraform_region(r, newterrain(T_OCEAN)); - } - } - } - - /* watcher: */ - f = gm_addfaction(email, pl, center); - w->faction = f; - w->mode = see_unit; - w->next = pl->watchers; - pl->watchers = w; - - return f; -} - -faction * -gm_addfaction(const char * email, plane * p, region * r) -{ - attrib * a; - unit * u; - faction * f = calloc(1, sizeof(faction)); - - assert(p!=NULL); - - /* GM faction */ - a_add(&f->attribs, make_key(atoi36("quest"))); - f->banner = strdup("quest faction"); - f->name = strdup("quest faction"); - f->passw = strdup(itoa36(rng_int())); - f->override = strdup(itoa36(rng_int())); - if (set_email(&f->email, email)!=0) { - log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), email)); - } - f->race = new_race[RC_TEMPLATE]; - f->age = 0; - f->lastorders = turn; - f->alive = true; - f->locale = default_locale; - f->options = want(O_COMPRESS) | want(O_REPORT) | want(O_COMPUTER) | want(O_ADRESSEN); - { - faction * xist; - int id = atoi36("gm00")-1; - do { - xist = findfaction(++id); - } while (xist); - - f->no = id; - addlist(&factions, f); - fhash(f); - } - - /* generic permissions */ - a = a_add(&f->attribs, a_new(&at_permissions)); - if (a) { - attrib * ap = (attrib*)a->data.v; - const char* keys[] = { "gmterf", "gmtele", "gmgive", "gmskil", "gmtake", "gmmsgr", "gmmsgu", "gmgate", 0 }; - const char ** key_p = keys; - while (*key_p) { - add_key(&ap, atoi36(*key_p)); - ++key_p; - } - a_add(&ap, make_atgmcreate(resource2item(r_silver))); - - a->data.v = ap; - } - - /* one initial unit */ - u = create_unit(r, f, 1, new_race[RC_TEMPLATE], 1, "quest master", NULL); - u->irace = new_race[RC_GNOME]; - - return f; -} - -plane * -gm_addplane(int radius, unsigned int flags, const char * name) -{ - region * center; - plane * pl; - boolean invalid = false; - int minx, miny, maxx, maxy, cx, cy; - int x; - - /* GM playfield */ - do { - minx = (rng_int() % (2*EXTENSION)) - EXTENSION; - miny = (rng_int() % (2*EXTENSION)) - EXTENSION; - for (x=0;!invalid && x<=radius*2;++x) { - int y; - for (y=0;!invalid && y<=radius*2;++y) { - region * r = findregion(minx+x, miny+y); - if (r) invalid = true; - } - } - } while (invalid); - maxx = minx+2*radius; cx = minx+radius; - maxy = miny+2*radius; cy = miny+radius; - pl = create_new_plane(rng_int(), name, minx, maxx, miny, maxy, flags); - center = new_region(cx, cy, pl, 0); - for (x=0;x<=2*radius;++x) { - int y; - for (y=0;y<=2*radius;++y) { - region * r = findregion(minx+x, miny+y); - if (!r) r = new_region(minx+x, miny+y, pl, 0); - freset(r, RF_ENCOUNTER); - if (distance(r, center)==radius) { - terraform_region(r, newterrain(T_FIREWALL)); - } else if (r==center) { - terraform_region(r, newterrain(T_PLAIN)); - } else { - terraform_region(r, newterrain(T_OCEAN)); - } - } - } - return pl; -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "gmcmd.h" +#include + +/* misc includes */ +#include +#include +#include +#include + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +/** + ** at_permissions + **/ + +static void +mistake(const unit * u, struct order * ord, const char *comment) +{ + if (!is_monsters(u->faction)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "mistake", + "error", comment)); + } +} + +static void +write_permissions(const attrib * a, const void * owner, struct storage * store) +{ + a_write(store, (attrib*)a->data.v, owner); +} + +static int +read_permissions(attrib * a, void * owner, struct storage * store) +{ + attrib * attr = NULL; + a_read(store, &attr, NULL); + a->data.v = attr; + return AT_READ_OK; +} + +struct attrib_type at_permissions = { + "GM:permissions", + NULL, NULL, NULL, + write_permissions, read_permissions, + ATF_UNIQUE +}; + +attrib * +make_atpermissions(void) +{ + return a_new(&at_permissions); +} + +/** + ** GM: CREATE + **/ + +static void +write_gmcreate(const attrib * a, const void * owner, struct storage * store) +{ + const item_type * itype = (const item_type *)a->data.v; + assert(itype); + store->w_tok(store, resourcename(itype->rtype, 0)); +} + +static int +read_gmcreate(attrib * a, void * owner, struct storage * store) +{ + char zText[32]; + store->r_tok_buf(store, zText, sizeof(zText)); + a->data.v = it_find(zText); + if (a->data.v == NULL) { + log_error(("unknown itemtype %s in gmcreate attribute\n", zText)); + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +/* at_gmcreate specifies that the owner can create items of a particular type */ +attrib_type at_gmcreate = { + "GM:create", + NULL, NULL, NULL, + write_gmcreate, read_gmcreate +}; + +attrib * +make_atgmcreate(const struct item_type * itype) +{ + attrib * a = a_new(&at_gmcreate); + a->data.v = (void*)itype; + return a; +} + +static void +gm_create(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + int i; + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (permissions) permissions = (attrib*)permissions->data.v; + if (!permissions) return; + i = getint(); + + if (i>0) { + const char * iname = getstrtoken(); + const item_type * itype = finditemtype(iname, u->faction->locale); + if (itype==NULL) { + mistake(u, ord, "unknown item."); + } else { + attrib * a = a_find(permissions, &at_gmcreate); + + while (a && a->type==&at_gmcreate && a->data.v!=(void*)itype) a=a->next; + if (a) i_change(&u->items, itype, i); + else mistake(u, ord, "your faction cannot create this item."); + } + } +} + +static boolean +has_permission(const attrib * permissions, unsigned int key) +{ + return (find_key((attrib*)permissions->data.v, key) || + find_key((attrib*)permissions->data.v, atoi36("master"))); +} + +/** + ** GM: GATE + ** requires: permission-key "gmgate" + **/ +static void +gm_gate(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + const struct plane * pl = rplane(u->region); + int id = getid(); + int x = rel_to_abs(pl, u->faction, getint(), 0); + int y = rel_to_abs(pl, u->faction, getint(), 1); + building * b = findbuilding(id); + region * r; + + pnormalize(&x, &y, pl); + r = findregion(x, y); + if (b==NULL || r==NULL || pl!=rplane(b->region) || pl!=rplane(r)) { + mistake(u, ord, "the unit cannot transform this building."); + return; + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (permissions && has_permission(permissions, atoi36("gmgate"))) { + remove_triggers(&b->attribs, "timer", &tt_gate); + remove_triggers(&b->attribs, "create", &tt_unguard); + if (r!=b->region) { + add_trigger(&b->attribs, "timer", trigger_gate(b, r)); + add_trigger(&b->attribs, "create", trigger_unguard(b)); + fset(b, BLD_UNGUARDED); + } + } + } +} + + +/** + ** GM: TERRAFORM + ** requires: permission-key "gmterf" + **/ +static void +gm_terraform(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + const struct plane * p = rplane(u->region); + int x = rel_to_abs(p, u->faction, getint(), 0); + int y = rel_to_abs(p, u->faction, getint(), 1); + const char * c = getstrtoken(); + variant token; + tnode * tokens = get_translations(u->faction->locale, UT_TERRAINS); + region * r; + pnormalize(&x, &y, p); + r = findregion(x, y); + + if (r==NULL || p!=rplane(r)) { + mistake(u, ord, "region is in another plane."); + return; + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmterf"))) return; + } + + if (findtoken(tokens, c, &token)!=E_TOK_NOMATCH) { + const terrain_type * terrain = (const terrain_type *)token.v; + terraform_region(r, terrain); + } +} + +/** + ** GM: TELEPORT + ** requires: permission-key "gmtele" + **/ +static void +gm_teleport(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + const struct plane * p = rplane(u->region); + unit * to = findunit(getid()); + int x = rel_to_abs(p, u->faction, getint(), 0); + int y = rel_to_abs(p, u->faction, getint(), 1); + region * r = findregion(x, y); + + if (r==NULL || p!=rplane(r)) { + mistake(u, ord, "region is in another plane."); + } else if (to==NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } else if (rplane(to->region)!=rplane(r) && !ucontact(to, u)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", "target", to)); + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmtele"))) { + mistake(u, ord, "permission denied."); + } + else move_unit(to, r, NULL); + } +} + +/** + ** GM: TELL PLANE + ** requires: permission-key "gmmsgr" + **/ +static void +gm_messageplane(const tnode * tnext, void * data, struct order * ord) +{ + unit * gm = (unit*)data; + const struct plane * p = rplane(gm->region); + const char * zmsg = getstrtoken(); + if (p==NULL) { + mistake(gm, ord, "In diese Ebene kann keine Nachricht gesandt werden."); + } else { + /* checking permissions */ + attrib * permissions = a_find(gm->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { + mistake(gm, ord, "permission denied."); + } + else { + message * msg = msg_message("msg_event", "string", zmsg); + faction * f; + region * r; + for (f=factions;f;f=f->next) { + freset(f, FFL_SELECT); + } + for (r=regions;r;r=r->next) { + unit * u; + if (rplane(r)!=p) continue; + for (u=r->units;u;u=u->next) if (!fval(u->faction, FFL_SELECT)) { + f = u->faction; + fset(f, FFL_SELECT); + add_message(&f->msgs, msg); + } + } + msg_release(msg); + } + } +} + +static void +gm_messagefaction(const tnode * tnext, void * data, struct order * ord) +{ + unit * gm = (unit*)data; + int n = getid(); + faction * f = findfaction(n); + const char * msg = getstrtoken(); + plane * p = rplane(gm->region); + attrib * permissions = a_find(gm->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { + mistake(gm, ord, "permission denied."); + return; + } + if (f!=NULL) { + region * r; + for (r=regions;r;r=r->next) if (rplane(r)==p) { + unit * u; + for (u=r->units;u;u=u->next) if (u->faction==f) { + add_message(&f->msgs, msg_message("msg_event", "string", msg)); + return; + } + } + } + mistake(gm, ord, "cannot send messages to this faction."); +} + +/** + ** GM: TELL REGION + ** requires: permission-key "gmmsgr" + **/ +static void +gm_messageregion(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + const struct plane * p = rplane(u->region); + int x = rel_to_abs(p, u->faction, getint(), 0); + int y = rel_to_abs(p, u->faction, getint(), 1); + const char * msg = getstrtoken(); + region * r = findregion(x, y); + + if (r==NULL || p!=rplane(r)) { + mistake(u, ord, "region is in another plane."); + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { + mistake(u, ord, "permission denied."); + } + else { + add_message(&r->msgs, msg_message("msg_event", "string", msg)); + } + } +} + +/** + ** GM: KILL UNIT + ** requires: permission-key "gmkill" + **/ +static void +gm_killunit(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + const struct plane * p = rplane(u->region); + unit * target = findunit(getid()); + const char * msg = getstrtoken(); + region * r = target->region; + + if (r==NULL || p!=rplane(r)) { + mistake(u, ord, "region is in another plane."); + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmkill"))) { + mistake(u, ord, "permission denied."); + } + else { + scale_number(target, 0); + ADDMSG(&target->faction->msgs, msg_message("killedbygm", + "region unit string", r, target, msg)); + } + } +} + + +/** + ** GM: KILL FACTION + ** requires: permission-key "gmmsgr" + **/ +static void +gm_killfaction(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + int n = getid(); + faction * f = findfaction(n); + const char * msg = getstrtoken(); + plane * p = rplane(u->region); + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmkill"))) { + mistake(u, ord, "permission denied."); + return; + } + if (f!=NULL) { + region * r; + for (r=regions;r;r=r->next) if (rplane(r)==p) { + unit * target; + for (target=r->units;target;target=target->next) { + if (target->faction==f) { + scale_number(target, 0); + ADDMSG(&target->faction->msgs, msg_message("killedbygm", + "region unit string", r, target, msg)); + return; + } + } + } + } + mistake(u, ord, "cannot remove a unit from this faction."); +} + +/** + ** GM: TELL + ** requires: permission-key "gmmsgr" + **/ +static void +gm_messageunit(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + const struct plane * p = rplane(u->region); + unit * target = findunit(getid()); + const char * msg = getstrtoken(); + region * r; + + if (target == NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + + r = target->region; + + if (r==NULL || p!=rplane(r)) { + mistake(u, ord, "region is in another plane."); + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmmsgu"))) { + mistake(u, ord, "permission denied."); + } + else { + add_message(&target->faction->msgs, + msg_message("regionmessage", "region sender string", r, u, msg)); + } + } +} + +/** + ** GM: GIVE + ** requires: permission-key "gmgive" + **/ +static void +gm_give(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + unit * to = findunit(getid()); + int num = getint(); + const item_type * itype = finditemtype(getstrtoken(), u->faction->locale); + + if (to==NULL || rplane(to->region) != rplane(u->region)) { + /* unknown or in another plane */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } else if (itype==NULL || i_get(u->items, itype)==0) { + /* unknown or not enough */ + mistake(u, ord, "invalid item or item not found."); + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmgive"))) { + mistake(u, ord, "permission denied."); + } + else { + int i = i_get(u->items, itype); + if (iitems, itype, -num); + i_change(&to->items, itype, num); + } + } + } +} + +/** + ** GM: TAKE + ** requires: permission-key "gmtake" + **/ +static void +gm_take(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + unit * to = findunit(getid()); + int num = getint(); + const item_type * itype = finditemtype(getstrtoken(), u->faction->locale); + + if (to==NULL || rplane(to->region) != rplane(u->region)) { + /* unknown or in another plane */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } else if (itype==NULL || i_get(to->items, itype)==0) { + /* unknown or not enough */ + mistake(u, ord, "invalid item or item not found."); + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmtake"))) { + mistake(u, ord, "permission denied."); + } + else { + int i = i_get(to->items, itype); + if (iitems, itype, -num); + i_change(&u->items, itype, num); + } + } + } +} + +/** + ** GM: SKILL + ** requires: permission-key "gmskil" + **/ +static void +gm_skill(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + unit * to = findunit(getid()); + skill_t skill = findskill(getstrtoken(), u->faction->locale); + int num = getint(); + + if (to==NULL || rplane(to->region) != rplane(u->region)) { + /* unknown or in another plane */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } else if (skill==NOSKILL || skill==SK_MAGIC || skill==SK_ALCHEMY) { + /* unknown or not enough */ + mistake(u, ord, "unknown skill, or skill cannot be raised."); + } else if (num<0 || num>30) { + /* sanity check failed */ + mistake(u, ord, "invalid value."); + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmskil"))) { + mistake(u, ord, "permission denied."); + } + else { + set_level(to, skill, num); + } + } +} + +static tnode g_keys; +static tnode g_root; +static tnode g_tell; +static tnode g_kill; + +void +register_gmcmd(void) +{ + at_register(&at_gmcreate); + at_register(&at_permissions); + add_command(&g_root, &g_keys, "gm", NULL); + add_command(&g_keys, NULL, "terraform", &gm_terraform); + add_command(&g_keys, NULL, "create", &gm_create); + add_command(&g_keys, NULL, "gate", &gm_gate); + add_command(&g_keys, NULL, "give", &gm_give); + add_command(&g_keys, NULL, "take", &gm_take); + add_command(&g_keys, NULL, "teleport", &gm_teleport); + add_command(&g_keys, NULL, "skill", &gm_skill); + add_command(&g_keys, &g_tell, "tell", NULL); + add_command(&g_tell, NULL, "region", &gm_messageregion); + add_command(&g_tell, NULL, "unit", &gm_messageunit); + add_command(&g_tell, NULL, "plane", &gm_messageplane); + add_command(&g_tell, NULL, "faction", &gm_messagefaction); + add_command(&g_keys, &g_kill, "kill", NULL); + add_command(&g_kill, NULL, "unit", &gm_killunit); + add_command(&g_kill, NULL, "faction", &gm_killfaction); +} + +/* + * execute gm-commands for all units in the game + */ + +void +gmcommands(void) +{ + region ** rp = ®ions; + while (*rp) { + region * r = *rp; + unit **up = &r->units; + while (*up) { + unit * u = *up; + struct order * ord; + for (ord = u->orders; ord; ord = ord->next) { + if (get_keyword(ord) == K_GM) { + do_command(&g_root, u, ord); + } + } + if (u==*up) up = &u->next; + } + if (*rp==r) rp = &r->next; + } +} + +#define EXTENSION 10000 + +faction * +gm_addquest(const char * email, const char * name, int radius, unsigned int flags) +{ + plane * pl; + watcher * w = calloc(sizeof(watcher), 1); + region * center; + boolean invalid = false; + int minx, miny, maxx, maxy, cx, cy; + int x; + faction * f; + + /* GM playfield */ + do { + minx = ((rng_int() % (2*EXTENSION)) - EXTENSION); + miny = ((rng_int() % (2*EXTENSION)) - EXTENSION); + for (x=0;!invalid && x<=radius*2;++x) { + int y; + for (y=0;!invalid && y<=radius*2;++y) { + region * r = findregion(minx+x, miny+y); + if (r) invalid = true; + } + } + } while (invalid); + maxx = minx+2*radius; cx = minx+radius; + maxy = miny+2*radius; cy = miny+radius; + pl = create_new_plane(rng_int(), name, minx, maxx, miny, maxy, flags); + center = new_region(cx, cy, pl, 0); + for (x=0;x<=2*radius;++x) { + int y; + for (y=0;y<=2*radius;++y) { + region * r = findregion(minx+x, miny+y); + if (!r) { + r = new_region(minx+x, miny+y, pl, 0); + } + freset(r, RF_ENCOUNTER); + if (distance(r, center)==radius) { + terraform_region(r, newterrain(T_FIREWALL)); + } else if (r==center) { + terraform_region(r, newterrain(T_PLAIN)); + } else { + terraform_region(r, newterrain(T_OCEAN)); + } + } + } + + /* watcher: */ + f = gm_addfaction(email, pl, center); + w->faction = f; + w->mode = see_unit; + w->next = pl->watchers; + pl->watchers = w; + + return f; +} + +faction * +gm_addfaction(const char * email, plane * p, region * r) +{ + attrib * a; + unit * u; + faction * f = calloc(1, sizeof(faction)); + + assert(p!=NULL); + + /* GM faction */ + a_add(&f->attribs, make_key(atoi36("quest"))); + f->banner = strdup("quest faction"); + f->name = strdup("quest faction"); + f->passw = strdup(itoa36(rng_int())); + f->override = strdup(itoa36(rng_int())); + if (set_email(&f->email, email)!=0) { + log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), email)); + } + f->race = new_race[RC_TEMPLATE]; + f->age = 0; + f->lastorders = turn; + f->alive = true; + f->locale = default_locale; + f->options = want(O_COMPRESS) | want(O_REPORT) | want(O_COMPUTER) | want(O_ADRESSEN); + { + faction * xist; + int id = atoi36("gm00")-1; + do { + xist = findfaction(++id); + } while (xist); + + f->no = id; + addlist(&factions, f); + fhash(f); + } + + /* generic permissions */ + a = a_add(&f->attribs, a_new(&at_permissions)); + if (a) { + attrib * ap = (attrib*)a->data.v; + const char* keys[] = { "gmterf", "gmtele", "gmgive", "gmskil", "gmtake", "gmmsgr", "gmmsgu", "gmgate", 0 }; + const char ** key_p = keys; + while (*key_p) { + add_key(&ap, atoi36(*key_p)); + ++key_p; + } + a_add(&ap, make_atgmcreate(resource2item(r_silver))); + + a->data.v = ap; + } + + /* one initial unit */ + u = create_unit(r, f, 1, new_race[RC_TEMPLATE], 1, "quest master", NULL); + u->irace = new_race[RC_GNOME]; + + return f; +} + +plane * +gm_addplane(int radius, unsigned int flags, const char * name) +{ + region * center; + plane * pl; + boolean invalid = false; + int minx, miny, maxx, maxy, cx, cy; + int x; + + /* GM playfield */ + do { + minx = (rng_int() % (2*EXTENSION)) - EXTENSION; + miny = (rng_int() % (2*EXTENSION)) - EXTENSION; + for (x=0;!invalid && x<=radius*2;++x) { + int y; + for (y=0;!invalid && y<=radius*2;++y) { + region * r = findregion(minx+x, miny+y); + if (r) invalid = true; + } + } + } while (invalid); + maxx = minx+2*radius; cx = minx+radius; + maxy = miny+2*radius; cy = miny+radius; + pl = create_new_plane(rng_int(), name, minx, maxx, miny, maxy, flags); + center = new_region(cx, cy, pl, 0); + for (x=0;x<=2*radius;++x) { + int y; + for (y=0;y<=2*radius;++y) { + region * r = findregion(minx+x, miny+y); + if (!r) r = new_region(minx+x, miny+y, pl, 0); + freset(r, RF_ENCOUNTER); + if (distance(r, center)==radius) { + terraform_region(r, newterrain(T_FIREWALL)); + } else if (r==center) { + terraform_region(r, newterrain(T_PLAIN)); + } else { + terraform_region(r, newterrain(T_OCEAN)); + } + } + } + return pl; +} diff --git a/src/modules/gmcmd.h b/src/modules/gmcmd.h index 2e830b51c..143e126f4 100644 --- a/src/modules/gmcmd.h +++ b/src/modules/gmcmd.h @@ -1,48 +1,48 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_MOD_GMCMD -#define H_MOD_GMCMD -#ifdef __cplusplus -extern "C" { -#endif - -struct plane; -struct attrib; -struct unit; -struct faction; -struct region; - -extern void register_gmcmd(void); -/* initialize this module */ - -extern void gmcommands(void); -/* execute commands */ - -extern struct faction * gm_addfaction(const char * email, struct plane * p, struct region * r); -extern struct plane * gm_addplane(int radius, unsigned int flags, const char * name); - -/* - * doesn't belong in here: - */ -struct attrib * find_key(struct attrib * attribs, int key); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_MOD_GMCMD +#define H_MOD_GMCMD +#ifdef __cplusplus +extern "C" { +#endif + +struct plane; +struct attrib; +struct unit; +struct faction; +struct region; + +extern void register_gmcmd(void); +/* initialize this module */ + +extern void gmcommands(void); +/* execute commands */ + +extern struct faction * gm_addfaction(const char * email, struct plane * p, struct region * r); +extern struct plane * gm_addplane(int radius, unsigned int flags, const char * name); + +/* + * doesn't belong in here: + */ +struct attrib * find_key(struct attrib * attribs, int key); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/museum.c b/src/modules/museum.c index 7186f177d..c89a51d6b 100644 --- a/src/modules/museum.c +++ b/src/modules/museum.c @@ -1,396 +1,396 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include - -#include - -#if MUSEUM_MODULE -#include "museum.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -#define PFL_MUSEUM PFL_NOMONSTERS | PFL_NORECRUITS | PFL_NOGIVE | PFL_NOATTACK | PFL_NOTERRAIN | PFL_NOMAGIC | PFL_NOSTEALTH | PFL_NOTEACH | PFL_NOBUILD | PFL_NOFEED - -attrib_type at_museumexit = { - "museumexit", NULL, NULL, NULL, a_writeshorts, a_readshorts -}; - -static void -a_initmuseumgivebackcookie(attrib *a) -{ - a->data.v = calloc(1,sizeof(museumgivebackcookie)); -} - -static void -a_finalizemuseumgivebackcookie(attrib *a) -{ - free(a->data.v); -} - -static void -a_writemuseumgivebackcookie(const attrib * a, const void * owner, struct storage * store) -{ - museumgivebackcookie *gbc = (museumgivebackcookie *)a->data.v; - store->w_int(store, gbc->warden_no); - store->w_int(store, gbc->cookie); -} - -static int -a_readmuseumgivebackcookie(attrib *a, void * owner, struct storage * store) -{ - museumgivebackcookie *gbc = (museumgivebackcookie *)a->data.v; - gbc->warden_no = store->r_int(store); - gbc->cookie = store->r_int(store); - return AT_READ_OK; -} - -attrib_type at_museumgivebackcookie = { - "museumgivebackcookie", - a_initmuseumgivebackcookie, - a_finalizemuseumgivebackcookie, - NULL, - a_writemuseumgivebackcookie, - a_readmuseumgivebackcookie -}; - -attrib_type at_warden = { - "itemwarden", NULL, NULL, NULL, a_writeint, a_readint -}; - -static void -a_initmuseumgiveback(attrib *a) -{ - a->data.v = calloc(1, sizeof(museumgiveback)); -} - -static void -a_finalizemuseumgiveback(attrib *a) -{ - museumgiveback *gb = (museumgiveback *)a->data.v; - i_freeall(&gb->items); - free(a->data.v); -} - -static void -a_writemuseumgiveback(const attrib * a, const void * owner, struct storage * store) -{ - museumgiveback *gb = (museumgiveback *)a->data.v; - store->w_int(store, gb->cookie); - write_items(store, gb->items); -} - -static int -a_readmuseumgiveback(attrib *a, void * owner, struct storage * store) -{ - museumgiveback *gb = (museumgiveback *)a->data.v; - gb->cookie = store->r_int(store); - read_items(store, &gb->items); - return AT_READ_OK; -} - -attrib_type at_museumgiveback = { - "museumgiveback", - a_initmuseumgiveback, - a_finalizemuseumgiveback, - NULL, - a_writemuseumgiveback, - a_readmuseumgiveback -}; - -void -warden_add_give(unit *src, unit *u, const item_type *itype, int n) -{ - attrib *aw = a_find(u->attribs, &at_warden); - museumgiveback *gb = NULL; - museumgivebackcookie *gbc; - attrib *a; - - /* has the giver a cookie corresponding to the warden */ - for(a = a_find(src->attribs, &at_museumgivebackcookie); a && a->type==&at_museumgivebackcookie; a=a->next) { - if(((museumgivebackcookie *)(a->data.v))->warden_no == u->no) break; - } - - /* if not give it one */ - if (a==NULL || a->type!=&at_museumgivebackcookie) { - a = a_add(&src->attribs, a_new(&at_museumgivebackcookie)); - gbc = (museumgivebackcookie *)a->data.v; - gbc->warden_no = u->no; - gbc->cookie = aw->data.i; - assert(aw->data.i < INT_MAX); - aw->data.i++; - } else { - gbc = (museumgivebackcookie *)(a->data.v); - } - - /* now we search for the warden's corresponding item list */ - for (a = a_find(u->attribs, &at_museumgiveback); a && a->type==&at_museumgiveback; a=a->next) { - gb = (museumgiveback *)a->data.v; - if (gb->cookie == gbc->cookie) { - break; - } - } - - /* if there's none, give it one */ - if (!gb) { - a = a_add(&u->attribs, a_new(&at_museumgiveback)); - gb = (museumgiveback *)a->data.v; - gb->cookie = gbc->cookie; - } - - /* now register the items */ - i_change(&gb->items, itype, n); - - /* done */ - - /* this has a caveat: If the src-unit is destroyed while inside - * the museum, the corresponding itemlist of the warden will never - * be removed. to circumvent that in a generic way will be extremly - * difficult. */ -} - -void -create_museum(void) -{ -#if 0 /* TODO: move this to LUA. It should be possible. */ - unsigned int museum_id = hashstring("museum"); - plane *museum = getplanebyid(museum_id); - region *r; - building *b; - const terrain_type * terrain_hall = get_terrain("hall1"); - const terrain_type * terrain_corridor = get_terrain("corridor1"); - - assert(terrain_corridor && terrain_hall); - - if (!museum) { - museum = create_new_plane(museum_id, "Museum", 9500, 9550, - 9500, 9550, PFL_MUSEUM); - } - - if (findregion(9525, 9525) == NULL) { - /* Eingangshalle */ - r = new_region(9525, 9525, 0); - terraform_region(r, terrain_hall); - r->planep = museum; - rsetname(r, "Eingangshalle"); - rsethorses(r, 0); - rsetmoney(r, 0); - rsetpeasants(r, 0); - set_string(&r->display, "Die Eingangshalle des Großen Museum der 1. Welt ist bereits jetzt ein beeindruckender Anblick. Obwohl das Museum noch nicht eröffnet ist, vermittelt sie bereits einen Flair exotischer Welten. In den Boden ist ein großer Kompass eingelassen, der den Besuchern bei Orientierung helfen soll."); - } - - r = findregion(9526, 9525); - if(!r) { - /* Lounge */ - r = new_region(9526, 9525, 0); - terraform_region(r, terrain_hall); - r->planep = museum; - rsetname(r, "Lounge"); - rsethorses(r, 0); - rsetmoney(r, 0); - rsetpeasants(r, 0); - set_string(&r->display, "Die Lounge des großen Museums ist ein Platz, in dem sich die Besucher treffen, um die Eindrücke, die sie gewonnen haben, zu verarbeiten. Gemütliche Sitzgruppen laden zum Verweilen ein."); - } - - r = findregion(9526, 9525); - if(!r->buildings) { - const building_type * bt_generic = bt_find("generic"); - b = new_building(bt_generic, r, NULL); - set_string(&b->name, "Séparée im dämonischen Stil"); - set_string(&b->display, "Diese ganz im dämonischen Stil gehaltene Sitzgruppe ist ganz in dunklen Schwarztönen gehalten. Muster fremdartiger Runen bedecken das merkwürdig geformte Mobiliar, das unangenehm lebendig wirkt."); - - b = new_building(bt_generic, r, NULL); - set_string(&b->name, "Séparée im elfischen Stil"); - set_string(&b->display, "Ganz in Grün- und Brauntönen gehalten wirkt die Sitzgruppe fast lebendig. Bei näherer Betrachtung erschließt sich dem Betrachter, daß sie tatsächlich aus lebenden Pflanzen erstellt ist. So ist der Tisch aus einem eizigen Baum gewachsen, und die Polster bestehen aus weichen Grassoden. Ein wunderschön gemusterter Webteppich mit tausenden naturgetreu eingestickter Blumensarten bedeckt den Boden."); - - b = new_building(bt_generic, r, NULL); - set_string(&b->name, "Séparée im halblingschen Stil"); - set_string(&b->display, "Dieses rustikale Mobiliar ist aus einem einzigen, gewaltigen Baum hergestellt worden. Den Stamm haben fleißige Halblinge der Länge nach gevierteilt und aus den vier langen Viertelstämmen die Sitzbänke geschnitzt, während der verbleibende Stumpf als Tisch dient. Schon von weitem steigen dem Besucher die Gerüche der Köstlichkeiten entgegen, die auf dem Tisch stapeln."); - - b = new_building(bt_generic, r, NULL); - set_string(&b->name, "Séparée im orkischen Stil"); - set_string(&b->display, "Grobgeschreinerte, elfenhautbespannte Stühle und ein Tisch aus Knochen, über deren Herkunft man sich lieber keine Gedanken macht, bilden die Sitzgruppe im orkischen Stil. Überall haben Orks ihre Namen, und anderes wenig zitierenswertes in das Holz und Gebein geritzt."); - - b = new_building(bt_generic, r, NULL); - set_string(&b->name, "Séparée im Meermenschenstil"); - set_string(&b->display, "Ganz in Blau- und Grüntönen gehalten, mit Algen und Muscheln verziert wirken die aus altem Meerholz geschnitzten Stühle immer ein wenig feucht. Seltsammerweise hat der schwere aus alten Planken gezimmerte Tisch einen Mast mit kompletten Segel in der Mitte."); - - b = new_building(bt_generic, r, NULL); - set_string(&b->name, "Séparée im Katzenstil"); - set_string(&b->display, "Die Wände dieses Séparée sind aus dunklem Holz. Was aus der Ferne wie ein chaotisch durchbrochenes Flechtwerk wirkt, entpuppt sich bei näherer Betrachtung als eine bis in winzige Details gestaltete dschungelartige Landschaft, in die eine Vielzahl von kleinen Bildergeschichten eingewoben sind. Wie es scheint hat sich der Künstler Mühe gegeben wirklich jedes Katzenvolk Eresseas zu porträtieren. Das schummrige Innere wird von einem Kamin dominiert, vor dem einige Sessel und weiche Kissen zu einem gemütlichen Nickerchen einladen. Feiner Anduner Sisal bezieht die Lehnen der Sessel und verlockt dazu, seine Krallen hinein zu versenken. Auf einem kleinen Ecktisch steht ein großer Korb mit roten Wollknäulen und grauen und braunen Spielmäusen."); - } else { - for(b=r->buildings; b; b=b->next) { - b->size = b->type->maxsize; - } - } - - r = findregion(9524, 9526); - if(!r) { - r = new_region(9524, 9526, 0); - terraform_region(r, terrain_corridor); - r->planep = museum; - rsetname(r, "Nördliche Promenade"); - rsethorses(r, 0); - rsetmoney(r, 0); - rsetpeasants(r, 0); - set_string(&r->display, "Die Nördliche Promenade führt direkt in den naturgeschichtlichen Teil des Museums."); - } - r = findregion(9525, 9524); - if(!r) { - r = new_region(9525, 9524, 0); - terraform_region(r, terrain_corridor); - r->planep = museum; - rsetname(r, "Südliche Promenade"); - rsethorses(r, 0); - rsetmoney(r, 0); - rsetpeasants(r, 0); - set_string(&r->display, "Die Südliche Promenade führt den Besucher in den kulturgeschichtlichen Teil des Museums."); - } -#endif -} - -static int -use_museumexitticket(unit *u, const struct item_type *itype, int amount, order * ord) -{ - attrib *a; - region *r; - unit *warden = findunit(atoi36("mwar")); - int unit_cookie; - - unused(amount); - - /* Prüfen ob in Eingangshalle */ - if(u->region->x != 9525 || u->region->y != 9525) { - cmistake(u, ord, 266, MSG_MAGIC); - return 0; - } - - a = a_find(u->attribs, &at_museumexit); assert(a); - r = findregion(a->data.sa[0], a->data.sa[1]); assert(r); - a_remove(&u->attribs, a); - - /* Übergebene Gegenstände zurückgeben */ - - a = a_find(u->attribs, &at_museumgivebackcookie); - unit_cookie = a->data.i; - a_remove(&u->attribs, a); - - if (a) { - for(a = a_find(warden->attribs, &at_museumgiveback); a && a->type==&at_museumgiveback; a = a->next) { - if(((museumgiveback *)(a->data.v))->cookie == unit_cookie) break; - } - if (a && a->type==&at_museumgiveback) { - museumgiveback *gb = (museumgiveback *)(a->data.v); - item *it; - - for (it = gb->items; it; it = it->next) { - i_change(&u->items, it->type, it->number); - } - ADDMSG(&u->faction->msgs, msg_message("museumgiveback", "region unit sender items", r, u, warden, gb->items)); - a_remove(&warden->attribs, a); - } - } - - /* Benutzer zurück teleportieren */ - move_unit(u, r, NULL); - - /* Exitticket abziehen */ - i_change(&u->items, itype, -1); - - return 0; -} - -static int -use_museumticket(unit *u, const struct item_type *itype, int amount, order * ord) -{ - attrib *a; - region *r = u->region; - plane * pl = rplane(r); - - unused(amount); - - /* Prüfen ob in normaler Plane und nur eine Person */ - if (pl != get_homeplane()) { - cmistake(u, ord, 265, MSG_MAGIC); - return 0; - } - if(u->number != 1) { - cmistake(u, ord, 267, MSG_MAGIC); - return 0; - } - if (has_horses(u)) { - cmistake(u, ord, 272, MSG_MAGIC); - return 0; - } - - /* In diesem Attribut merken wir uns, wohin die Einheit zurückgesetzt - * wird, wenn sie das Museum verläßt. */ - - a = a_add(&u->attribs, a_new(&at_museumexit)); - a->data.sa[0] = (short)r->x; - a->data.sa[1] = (short)r->y; - - /* Benutzer in die Halle teleportieren */ - move_unit(u, findregion(9525, 9525), NULL); - - /* Ticket abziehen */ - i_change(&u->items, itype, -1); - - /* Benutzer ein Exitticket geben */ - i_change(&u->items, itype, 1); - - return 0; -} - -void -register_museum(void) -{ - at_register(&at_warden); - at_register(&at_museumexit); - at_register(&at_museumgivebackcookie); - at_register(&at_museumgiveback); - - register_item_use(use_museumticket, "use_museumticket"); - register_item_use(use_museumexitticket, "use_museumexitticket"); -} - -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include + +#include + +#if MUSEUM_MODULE +#include "museum.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +#define PFL_MUSEUM PFL_NOMONSTERS | PFL_NORECRUITS | PFL_NOGIVE | PFL_NOATTACK | PFL_NOTERRAIN | PFL_NOMAGIC | PFL_NOSTEALTH | PFL_NOTEACH | PFL_NOBUILD | PFL_NOFEED + +attrib_type at_museumexit = { + "museumexit", NULL, NULL, NULL, a_writeshorts, a_readshorts +}; + +static void +a_initmuseumgivebackcookie(attrib *a) +{ + a->data.v = calloc(1,sizeof(museumgivebackcookie)); +} + +static void +a_finalizemuseumgivebackcookie(attrib *a) +{ + free(a->data.v); +} + +static void +a_writemuseumgivebackcookie(const attrib * a, const void * owner, struct storage * store) +{ + museumgivebackcookie *gbc = (museumgivebackcookie *)a->data.v; + store->w_int(store, gbc->warden_no); + store->w_int(store, gbc->cookie); +} + +static int +a_readmuseumgivebackcookie(attrib *a, void * owner, struct storage * store) +{ + museumgivebackcookie *gbc = (museumgivebackcookie *)a->data.v; + gbc->warden_no = store->r_int(store); + gbc->cookie = store->r_int(store); + return AT_READ_OK; +} + +attrib_type at_museumgivebackcookie = { + "museumgivebackcookie", + a_initmuseumgivebackcookie, + a_finalizemuseumgivebackcookie, + NULL, + a_writemuseumgivebackcookie, + a_readmuseumgivebackcookie +}; + +attrib_type at_warden = { + "itemwarden", NULL, NULL, NULL, a_writeint, a_readint +}; + +static void +a_initmuseumgiveback(attrib *a) +{ + a->data.v = calloc(1, sizeof(museumgiveback)); +} + +static void +a_finalizemuseumgiveback(attrib *a) +{ + museumgiveback *gb = (museumgiveback *)a->data.v; + i_freeall(&gb->items); + free(a->data.v); +} + +static void +a_writemuseumgiveback(const attrib * a, const void * owner, struct storage * store) +{ + museumgiveback *gb = (museumgiveback *)a->data.v; + store->w_int(store, gb->cookie); + write_items(store, gb->items); +} + +static int +a_readmuseumgiveback(attrib *a, void * owner, struct storage * store) +{ + museumgiveback *gb = (museumgiveback *)a->data.v; + gb->cookie = store->r_int(store); + read_items(store, &gb->items); + return AT_READ_OK; +} + +attrib_type at_museumgiveback = { + "museumgiveback", + a_initmuseumgiveback, + a_finalizemuseumgiveback, + NULL, + a_writemuseumgiveback, + a_readmuseumgiveback +}; + +void +warden_add_give(unit *src, unit *u, const item_type *itype, int n) +{ + attrib *aw = a_find(u->attribs, &at_warden); + museumgiveback *gb = NULL; + museumgivebackcookie *gbc; + attrib *a; + + /* has the giver a cookie corresponding to the warden */ + for(a = a_find(src->attribs, &at_museumgivebackcookie); a && a->type==&at_museumgivebackcookie; a=a->next) { + if(((museumgivebackcookie *)(a->data.v))->warden_no == u->no) break; + } + + /* if not give it one */ + if (a==NULL || a->type!=&at_museumgivebackcookie) { + a = a_add(&src->attribs, a_new(&at_museumgivebackcookie)); + gbc = (museumgivebackcookie *)a->data.v; + gbc->warden_no = u->no; + gbc->cookie = aw->data.i; + assert(aw->data.i < INT_MAX); + aw->data.i++; + } else { + gbc = (museumgivebackcookie *)(a->data.v); + } + + /* now we search for the warden's corresponding item list */ + for (a = a_find(u->attribs, &at_museumgiveback); a && a->type==&at_museumgiveback; a=a->next) { + gb = (museumgiveback *)a->data.v; + if (gb->cookie == gbc->cookie) { + break; + } + } + + /* if there's none, give it one */ + if (!gb) { + a = a_add(&u->attribs, a_new(&at_museumgiveback)); + gb = (museumgiveback *)a->data.v; + gb->cookie = gbc->cookie; + } + + /* now register the items */ + i_change(&gb->items, itype, n); + + /* done */ + + /* this has a caveat: If the src-unit is destroyed while inside + * the museum, the corresponding itemlist of the warden will never + * be removed. to circumvent that in a generic way will be extremly + * difficult. */ +} + +void +create_museum(void) +{ +#if 0 /* TODO: move this to LUA. It should be possible. */ + unsigned int museum_id = hashstring("museum"); + plane *museum = getplanebyid(museum_id); + region *r; + building *b; + const terrain_type * terrain_hall = get_terrain("hall1"); + const terrain_type * terrain_corridor = get_terrain("corridor1"); + + assert(terrain_corridor && terrain_hall); + + if (!museum) { + museum = create_new_plane(museum_id, "Museum", 9500, 9550, + 9500, 9550, PFL_MUSEUM); + } + + if (findregion(9525, 9525) == NULL) { + /* Eingangshalle */ + r = new_region(9525, 9525, 0); + terraform_region(r, terrain_hall); + r->planep = museum; + rsetname(r, "Eingangshalle"); + rsethorses(r, 0); + rsetmoney(r, 0); + rsetpeasants(r, 0); + set_string(&r->display, "Die Eingangshalle des Großen Museum der 1. Welt ist bereits jetzt ein beeindruckender Anblick. Obwohl das Museum noch nicht eröffnet ist, vermittelt sie bereits einen Flair exotischer Welten. In den Boden ist ein großer Kompass eingelassen, der den Besuchern bei Orientierung helfen soll."); + } + + r = findregion(9526, 9525); + if(!r) { + /* Lounge */ + r = new_region(9526, 9525, 0); + terraform_region(r, terrain_hall); + r->planep = museum; + rsetname(r, "Lounge"); + rsethorses(r, 0); + rsetmoney(r, 0); + rsetpeasants(r, 0); + set_string(&r->display, "Die Lounge des großen Museums ist ein Platz, in dem sich die Besucher treffen, um die Eindrücke, die sie gewonnen haben, zu verarbeiten. Gemütliche Sitzgruppen laden zum Verweilen ein."); + } + + r = findregion(9526, 9525); + if(!r->buildings) { + const building_type * bt_generic = bt_find("generic"); + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im dämonischen Stil"); + set_string(&b->display, "Diese ganz im dämonischen Stil gehaltene Sitzgruppe ist ganz in dunklen Schwarztönen gehalten. Muster fremdartiger Runen bedecken das merkwürdig geformte Mobiliar, das unangenehm lebendig wirkt."); + + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im elfischen Stil"); + set_string(&b->display, "Ganz in Grün- und Brauntönen gehalten wirkt die Sitzgruppe fast lebendig. Bei näherer Betrachtung erschließt sich dem Betrachter, daß sie tatsächlich aus lebenden Pflanzen erstellt ist. So ist der Tisch aus einem eizigen Baum gewachsen, und die Polster bestehen aus weichen Grassoden. Ein wunderschön gemusterter Webteppich mit tausenden naturgetreu eingestickter Blumensarten bedeckt den Boden."); + + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im halblingschen Stil"); + set_string(&b->display, "Dieses rustikale Mobiliar ist aus einem einzigen, gewaltigen Baum hergestellt worden. Den Stamm haben fleißige Halblinge der Länge nach gevierteilt und aus den vier langen Viertelstämmen die Sitzbänke geschnitzt, während der verbleibende Stumpf als Tisch dient. Schon von weitem steigen dem Besucher die Gerüche der Köstlichkeiten entgegen, die auf dem Tisch stapeln."); + + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im orkischen Stil"); + set_string(&b->display, "Grobgeschreinerte, elfenhautbespannte Stühle und ein Tisch aus Knochen, über deren Herkunft man sich lieber keine Gedanken macht, bilden die Sitzgruppe im orkischen Stil. Überall haben Orks ihre Namen, und anderes wenig zitierenswertes in das Holz und Gebein geritzt."); + + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im Meermenschenstil"); + set_string(&b->display, "Ganz in Blau- und Grüntönen gehalten, mit Algen und Muscheln verziert wirken die aus altem Meerholz geschnitzten Stühle immer ein wenig feucht. Seltsammerweise hat der schwere aus alten Planken gezimmerte Tisch einen Mast mit kompletten Segel in der Mitte."); + + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im Katzenstil"); + set_string(&b->display, "Die Wände dieses Séparée sind aus dunklem Holz. Was aus der Ferne wie ein chaotisch durchbrochenes Flechtwerk wirkt, entpuppt sich bei näherer Betrachtung als eine bis in winzige Details gestaltete dschungelartige Landschaft, in die eine Vielzahl von kleinen Bildergeschichten eingewoben sind. Wie es scheint hat sich der Künstler Mühe gegeben wirklich jedes Katzenvolk Eresseas zu porträtieren. Das schummrige Innere wird von einem Kamin dominiert, vor dem einige Sessel und weiche Kissen zu einem gemütlichen Nickerchen einladen. Feiner Anduner Sisal bezieht die Lehnen der Sessel und verlockt dazu, seine Krallen hinein zu versenken. Auf einem kleinen Ecktisch steht ein großer Korb mit roten Wollknäulen und grauen und braunen Spielmäusen."); + } else { + for(b=r->buildings; b; b=b->next) { + b->size = b->type->maxsize; + } + } + + r = findregion(9524, 9526); + if(!r) { + r = new_region(9524, 9526, 0); + terraform_region(r, terrain_corridor); + r->planep = museum; + rsetname(r, "Nördliche Promenade"); + rsethorses(r, 0); + rsetmoney(r, 0); + rsetpeasants(r, 0); + set_string(&r->display, "Die Nördliche Promenade führt direkt in den naturgeschichtlichen Teil des Museums."); + } + r = findregion(9525, 9524); + if(!r) { + r = new_region(9525, 9524, 0); + terraform_region(r, terrain_corridor); + r->planep = museum; + rsetname(r, "Südliche Promenade"); + rsethorses(r, 0); + rsetmoney(r, 0); + rsetpeasants(r, 0); + set_string(&r->display, "Die Südliche Promenade führt den Besucher in den kulturgeschichtlichen Teil des Museums."); + } +#endif +} + +static int +use_museumexitticket(unit *u, const struct item_type *itype, int amount, order * ord) +{ + attrib *a; + region *r; + unit *warden = findunit(atoi36("mwar")); + int unit_cookie; + + unused(amount); + + /* Prüfen ob in Eingangshalle */ + if(u->region->x != 9525 || u->region->y != 9525) { + cmistake(u, ord, 266, MSG_MAGIC); + return 0; + } + + a = a_find(u->attribs, &at_museumexit); assert(a); + r = findregion(a->data.sa[0], a->data.sa[1]); assert(r); + a_remove(&u->attribs, a); + + /* Übergebene Gegenstände zurückgeben */ + + a = a_find(u->attribs, &at_museumgivebackcookie); + unit_cookie = a->data.i; + a_remove(&u->attribs, a); + + if (a) { + for(a = a_find(warden->attribs, &at_museumgiveback); a && a->type==&at_museumgiveback; a = a->next) { + if(((museumgiveback *)(a->data.v))->cookie == unit_cookie) break; + } + if (a && a->type==&at_museumgiveback) { + museumgiveback *gb = (museumgiveback *)(a->data.v); + item *it; + + for (it = gb->items; it; it = it->next) { + i_change(&u->items, it->type, it->number); + } + ADDMSG(&u->faction->msgs, msg_message("museumgiveback", "region unit sender items", r, u, warden, gb->items)); + a_remove(&warden->attribs, a); + } + } + + /* Benutzer zurück teleportieren */ + move_unit(u, r, NULL); + + /* Exitticket abziehen */ + i_change(&u->items, itype, -1); + + return 0; +} + +static int +use_museumticket(unit *u, const struct item_type *itype, int amount, order * ord) +{ + attrib *a; + region *r = u->region; + plane * pl = rplane(r); + + unused(amount); + + /* Prüfen ob in normaler Plane und nur eine Person */ + if (pl != get_homeplane()) { + cmistake(u, ord, 265, MSG_MAGIC); + return 0; + } + if(u->number != 1) { + cmistake(u, ord, 267, MSG_MAGIC); + return 0; + } + if (has_horses(u)) { + cmistake(u, ord, 272, MSG_MAGIC); + return 0; + } + + /* In diesem Attribut merken wir uns, wohin die Einheit zurückgesetzt + * wird, wenn sie das Museum verläßt. */ + + a = a_add(&u->attribs, a_new(&at_museumexit)); + a->data.sa[0] = (short)r->x; + a->data.sa[1] = (short)r->y; + + /* Benutzer in die Halle teleportieren */ + move_unit(u, findregion(9525, 9525), NULL); + + /* Ticket abziehen */ + i_change(&u->items, itype, -1); + + /* Benutzer ein Exitticket geben */ + i_change(&u->items, itype, 1); + + return 0; +} + +void +register_museum(void) +{ + at_register(&at_warden); + at_register(&at_museumexit); + at_register(&at_museumgivebackcookie); + at_register(&at_museumgiveback); + + register_item_use(use_museumticket, "use_museumticket"); + register_item_use(use_museumexitticket, "use_museumexitticket"); +} + +#endif diff --git a/src/modules/museum.h b/src/modules/museum.h index bcf8457ef..940327042 100644 --- a/src/modules/museum.h +++ b/src/modules/museum.h @@ -1,53 +1,53 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef HEADER_MUSEUM_H -#define HEADER_MUSEUM_H -#ifdef __cplusplus -extern "C" { -#endif - -#if MUSEUM_MODULE == 0 -#error "must define MUSEUM_MODULE to use this module" -#endif - -extern struct attrib_type at_warden; -extern struct attrib_type at_museumexit; -extern struct attrib_type at_museumgivebackcookie; -extern struct attrib_type at_museumgiveback; - -typedef struct { - int warden_no; - int cookie; -} museumgivebackcookie; - -typedef struct { - int cookie; - struct item *items; -} museumgiveback; - -extern void register_museum(void); -extern void create_museum(void); -extern void warden_add_give(struct unit *src, struct unit *u, const struct item_type *itype, int n); - -#ifdef __cplusplus -} -#endif - - -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef HEADER_MUSEUM_H +#define HEADER_MUSEUM_H +#ifdef __cplusplus +extern "C" { +#endif + +#if MUSEUM_MODULE == 0 +#error "must define MUSEUM_MODULE to use this module" +#endif + +extern struct attrib_type at_warden; +extern struct attrib_type at_museumexit; +extern struct attrib_type at_museumgivebackcookie; +extern struct attrib_type at_museumgiveback; + +typedef struct { + int warden_no; + int cookie; +} museumgivebackcookie; + +typedef struct { + int cookie; + struct item *items; +} museumgiveback; + +extern void register_museum(void); +extern void create_museum(void); +extern void warden_add_give(struct unit *src, struct unit *u, const struct item_type *itype, int n); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/src/modules/oceannames.c b/src/modules/oceannames.c index b52eddec3..c39c21516 100644 --- a/src/modules/oceannames.c +++ b/src/modules/oceannames.c @@ -1,126 +1,126 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "oceannames.h" - -/* kernel includes */ -#include -#include - -/* util includes */ -#include - -/* libc includes */ -#include -#include - -typedef struct namehash { - struct namehash * next; - const char * name; -} namehash; - -#define NMAXHASH 1023 -namehash names[NMAXHASH]; - -void nhash(const char * name); - -typedef struct oceanname { - struct oceanname * next; - struct faction_list * factions; - const char * name; -} oceanname; - -static void -free_names(attrib * a) -{ - oceanname * data = (oceanname*)a->data.v; - while (a->data.v) { - a->data.v = data->next; - free(data); - } -} - -struct attrib_type at_oceanname = { "names", NULL, free_names, NULL/*, write_names, read_names, ATF_UNIQUE */}; - -const char * -get_oceanname(const struct region * r, const struct faction * f) -{ - attrib * a = a_find(r->attribs, &at_oceanname); - if (a) { - oceanname * names = (oceanname*)a->data.v; - while (names) { - faction_list * fl = names->factions; - while (fl) { - if (fl->data==f) return names->name; - fl=fl->next; - } - names = names->next; - } - } - return NULL; -} - -void -nameocean(struct region *r, struct faction * f, const char * newname) -{ - attrib * a = a_find(r->attribs, &at_oceanname); - if (!a && newname) a = a_add(&r->attribs, a_new(&at_oceanname)); - if (a) { - faction_list **oldf = NULL, **newf = NULL; - faction_list * fl = NULL; - oceanname * names = (oceanname*)a->data.v; - while ((names && (!newf && newname)) || !oldf) { - faction_list ** fli = &names->factions; - if (oldf==NULL) while (*fli) { - if ((*fli)->data==f) { - oldf = fli; - break; - } - fli=&(*fli)->next; - } - if (newname && !newf && !strcmp(names->name, newname)) { - newf = fli; - } - names = names->next; - } - - if (oldf) { - fl = *oldf; - *oldf = fl->next; - } else if (newname) { - fl = calloc(1, sizeof(faction_list)); - } - - if (newf) { - fl->data = f; - fl->next = *newf; - *newf = fl; - } else if (newname) { - oceanname * nm = calloc(1, sizeof(oceanname)); - nm->factions = fl; - fl->data = f; - fl->next = NULL; - nm->next = (oceanname*)a->data.v; - a->data.v = nm; - } else if (fl) { - free(fl); - } - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "oceannames.h" + +/* kernel includes */ +#include +#include + +/* util includes */ +#include + +/* libc includes */ +#include +#include + +typedef struct namehash { + struct namehash * next; + const char * name; +} namehash; + +#define NMAXHASH 1023 +namehash names[NMAXHASH]; + +void nhash(const char * name); + +typedef struct oceanname { + struct oceanname * next; + struct faction_list * factions; + const char * name; +} oceanname; + +static void +free_names(attrib * a) +{ + oceanname * data = (oceanname*)a->data.v; + while (a->data.v) { + a->data.v = data->next; + free(data); + } +} + +struct attrib_type at_oceanname = { "names", NULL, free_names, NULL/*, write_names, read_names, ATF_UNIQUE */}; + +const char * +get_oceanname(const struct region * r, const struct faction * f) +{ + attrib * a = a_find(r->attribs, &at_oceanname); + if (a) { + oceanname * names = (oceanname*)a->data.v; + while (names) { + faction_list * fl = names->factions; + while (fl) { + if (fl->data==f) return names->name; + fl=fl->next; + } + names = names->next; + } + } + return NULL; +} + +void +nameocean(struct region *r, struct faction * f, const char * newname) +{ + attrib * a = a_find(r->attribs, &at_oceanname); + if (!a && newname) a = a_add(&r->attribs, a_new(&at_oceanname)); + if (a) { + faction_list **oldf = NULL, **newf = NULL; + faction_list * fl = NULL; + oceanname * names = (oceanname*)a->data.v; + while ((names && (!newf && newname)) || !oldf) { + faction_list ** fli = &names->factions; + if (oldf==NULL) while (*fli) { + if ((*fli)->data==f) { + oldf = fli; + break; + } + fli=&(*fli)->next; + } + if (newname && !newf && !strcmp(names->name, newname)) { + newf = fli; + } + names = names->next; + } + + if (oldf) { + fl = *oldf; + *oldf = fl->next; + } else if (newname) { + fl = calloc(1, sizeof(faction_list)); + } + + if (newf) { + fl->data = f; + fl->next = *newf; + *newf = fl; + } else if (newname) { + oceanname * nm = calloc(1, sizeof(oceanname)); + nm->factions = fl; + fl->data = f; + fl->next = NULL; + nm->next = (oceanname*)a->data.v; + a->data.v = nm; + } else if (fl) { + free(fl); + } + } +} diff --git a/src/modules/oceannames.h b/src/modules/oceannames.h index ed5e4b5cc..625979f56 100644 --- a/src/modules/oceannames.h +++ b/src/modules/oceannames.h @@ -1,32 +1,32 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_MOD_OCEANNAMES -#define H_MOD_OCEANNAMES -#ifdef __cplusplus -extern "C" { -#endif - -struct faction; -struct region; -extern const char * get_oceanname(const struct region * r, const struct faction * f); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_MOD_OCEANNAMES +#define H_MOD_OCEANNAMES +#ifdef __cplusplus +extern "C" { +#endif + +struct faction; +struct region; +extern const char * get_oceanname(const struct region * r, const struct faction * f); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/score.c b/src/modules/score.c index 46b61f418..a58bc6c89 100644 --- a/src/modules/score.c +++ b/src/modules/score.c @@ -1,212 +1,212 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#if SCORE_MODULE -#include "score.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include - -/* libc includes */ -#include - -int -average_score_of_age(int age, int a) -{ - faction *f; - int sum = 0, count = 0; - - for (f = factions; f; f = f->next) { - if (!is_monsters(f) && f->race != new_race[RC_TEMPLATE] && f->age <= age + a && f->age >= age - a) { - sum += f->score; - count++; - } - } - - if (count == 0) { - return 0; - } - return sum / count; -} - -void -score(void) -{ - FILE *scoreFP; - region *r; - faction *fc; - int allscores = 0; - char path[MAX_PATH]; - - for (fc = factions; fc; fc = fc->next) fc->score = 0; - - for (r = regions; r; r = r->next) { - unit * u; - building * b; - ship * s; - - if (rule_region_owners()) { - fc = region_get_owner(r); - if (fc) fc->score += 10; - } - - for (b = r->buildings; b; b = b->next) { - u = building_owner(b); - if (u!=NULL) { - faction * fbo = u->faction; - - if (fbo) { - fbo->score += b->size * 5; - } - } - } - - for (s = r->ships; s; s = s->next) { - unit * cap = shipowner(s); - if (cap && cap->faction) { - cap->faction->score += s->size * 2; - } - } - - for (u = r->units; u; u = u->next) { - item * itm; - int itemscore = 0; - int i; - faction * f = u->faction; - - if (f==NULL || u->race == new_race[RC_SPELL] || u->race == new_race[RC_BIRTHDAYDRAGON]) { - continue; - } - - if (old_race(u->race) <= RC_AQUARIAN) { - f->score += (u->race->recruitcost * u->number) / 50; - } - f->score += get_money(u) / 50; - for (itm=u->items; itm; itm=itm->next) { - itemscore += itm->number * itm->type->score; - } - f->score += itemscore / 10; - - for (i=0;i!=u->skill_size;++i) { - skill * sv = u->skills+i; - switch (sv->id) { - case SK_MAGIC: - f->score += (int)(u->number * pow(sv->level, 4)); - break; - case SK_TACTICS: - f->score += (int)(u->number * pow(sv->level, 3)); - break; - case SK_SPY: - case SK_ALCHEMY: - case SK_HERBALISM: - f->score += (int)(u->number * pow(sv->level, 2.5)); - break; - default: - f->score += (int)(u->number * pow(sv->level, 2.5) / 10); - break; - } - } - } - } - - for (fc = factions; fc; fc = fc->next) { - fc->score = fc->score / 5; - if (!is_monsters(fc) && fc->race != new_race[RC_TEMPLATE]) { - allscores += fc->score; - } - } - if (allscores == 0) { - allscores = 1; - } - - sprintf(path, "%s/score", basepath()); - scoreFP = fopen(path, "w"); - if (scoreFP) { - const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; - faction * f; - fwrite(utf8_bom, 1, 3, scoreFP); - for (f = factions; f; f = f->next) if (f->num_total != 0) { - fprintf(scoreFP, "%8d (%8d/%4.2f%%/%5.2f) %30.30s (%3.3s) %5s (%3d)\n", - f->score, f->score - average_score_of_age(f->age, f->age / 24 + 1), - ((float) f->score / (float) allscores) * 100.0, - (float) f->score / f->num_total, - f->name, LOC(default_locale, rc_name(f->race, 0)), factionid(f), f->age); - } - fclose(scoreFP); - } - if (alliances!=NULL) { - alliance *a; - const item_type * token = it_find("conquesttoken"); - - sprintf(path, "%s/score.alliances", basepath()); - scoreFP = fopen(path, "w"); - if (scoreFP) { - const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; - fwrite(utf8_bom, 1, 3, scoreFP); - - fprintf(scoreFP, "# alliance:factions:persons:score\n"); - - for (a = alliances; a; a = a->next) { - int alliance_score = 0, alliance_number = 0, alliance_factions = 0; - int grails = 0; - faction * f; - - for (f = factions; f; f = f->next) { - if (f->alliance && f->alliance == a) { - alliance_factions++; - alliance_score += f->score; - alliance_number += f->num_total; - if (token!=NULL) { - unit * u = f->units; - while (u!=NULL) { - item ** iitem = i_find(&u->items, token); - if (iitem!=NULL && *iitem!=NULL) { - grails += (*iitem)->number; - } - u=u->nextF; - } - } - } - } - - fprintf(scoreFP, "%d:%d:%d:%d", a->id, alliance_factions, alliance_number, alliance_score); - if (token!=NULL) fprintf(scoreFP, ":%d", grails); - fputc('\n', scoreFP); - } - fclose(scoreFP); - } - } -} - -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#if SCORE_MODULE +#include "score.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include + +/* libc includes */ +#include + +int +average_score_of_age(int age, int a) +{ + faction *f; + int sum = 0, count = 0; + + for (f = factions; f; f = f->next) { + if (!is_monsters(f) && f->race != new_race[RC_TEMPLATE] && f->age <= age + a && f->age >= age - a) { + sum += f->score; + count++; + } + } + + if (count == 0) { + return 0; + } + return sum / count; +} + +void +score(void) +{ + FILE *scoreFP; + region *r; + faction *fc; + int allscores = 0; + char path[MAX_PATH]; + + for (fc = factions; fc; fc = fc->next) fc->score = 0; + + for (r = regions; r; r = r->next) { + unit * u; + building * b; + ship * s; + + if (rule_region_owners()) { + fc = region_get_owner(r); + if (fc) fc->score += 10; + } + + for (b = r->buildings; b; b = b->next) { + u = building_owner(b); + if (u!=NULL) { + faction * fbo = u->faction; + + if (fbo) { + fbo->score += b->size * 5; + } + } + } + + for (s = r->ships; s; s = s->next) { + unit * cap = shipowner(s); + if (cap && cap->faction) { + cap->faction->score += s->size * 2; + } + } + + for (u = r->units; u; u = u->next) { + item * itm; + int itemscore = 0; + int i; + faction * f = u->faction; + + if (f==NULL || u->race == new_race[RC_SPELL] || u->race == new_race[RC_BIRTHDAYDRAGON]) { + continue; + } + + if (old_race(u->race) <= RC_AQUARIAN) { + f->score += (u->race->recruitcost * u->number) / 50; + } + f->score += get_money(u) / 50; + for (itm=u->items; itm; itm=itm->next) { + itemscore += itm->number * itm->type->score; + } + f->score += itemscore / 10; + + for (i=0;i!=u->skill_size;++i) { + skill * sv = u->skills+i; + switch (sv->id) { + case SK_MAGIC: + f->score += (int)(u->number * pow(sv->level, 4)); + break; + case SK_TACTICS: + f->score += (int)(u->number * pow(sv->level, 3)); + break; + case SK_SPY: + case SK_ALCHEMY: + case SK_HERBALISM: + f->score += (int)(u->number * pow(sv->level, 2.5)); + break; + default: + f->score += (int)(u->number * pow(sv->level, 2.5) / 10); + break; + } + } + } + } + + for (fc = factions; fc; fc = fc->next) { + fc->score = fc->score / 5; + if (!is_monsters(fc) && fc->race != new_race[RC_TEMPLATE]) { + allscores += fc->score; + } + } + if (allscores == 0) { + allscores = 1; + } + + sprintf(path, "%s/score", basepath()); + scoreFP = fopen(path, "w"); + if (scoreFP) { + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + faction * f; + fwrite(utf8_bom, 1, 3, scoreFP); + for (f = factions; f; f = f->next) if (f->num_total != 0) { + fprintf(scoreFP, "%8d (%8d/%4.2f%%/%5.2f) %30.30s (%3.3s) %5s (%3d)\n", + f->score, f->score - average_score_of_age(f->age, f->age / 24 + 1), + ((float) f->score / (float) allscores) * 100.0, + (float) f->score / f->num_total, + f->name, LOC(default_locale, rc_name(f->race, 0)), factionid(f), f->age); + } + fclose(scoreFP); + } + if (alliances!=NULL) { + alliance *a; + const item_type * token = it_find("conquesttoken"); + + sprintf(path, "%s/score.alliances", basepath()); + scoreFP = fopen(path, "w"); + if (scoreFP) { + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + fwrite(utf8_bom, 1, 3, scoreFP); + + fprintf(scoreFP, "# alliance:factions:persons:score\n"); + + for (a = alliances; a; a = a->next) { + int alliance_score = 0, alliance_number = 0, alliance_factions = 0; + int grails = 0; + faction * f; + + for (f = factions; f; f = f->next) { + if (f->alliance && f->alliance == a) { + alliance_factions++; + alliance_score += f->score; + alliance_number += f->num_total; + if (token!=NULL) { + unit * u = f->units; + while (u!=NULL) { + item ** iitem = i_find(&u->items, token); + if (iitem!=NULL && *iitem!=NULL) { + grails += (*iitem)->number; + } + u=u->nextF; + } + } + } + } + + fprintf(scoreFP, "%d:%d:%d:%d", a->id, alliance_factions, alliance_number, alliance_score); + if (token!=NULL) fprintf(scoreFP, ":%d", grails); + fputc('\n', scoreFP); + } + fclose(scoreFP); + } + } +} + +#endif diff --git a/src/modules/score.h b/src/modules/score.h index 335afc23d..b9c502c8d 100644 --- a/src/modules/score.h +++ b/src/modules/score.h @@ -1,36 +1,36 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef SCORE_H -#define SCORE_H -#ifdef __cplusplus -extern "C" { -#endif - -#if SCORE_MODULE == 0 -#error "must define SCORE_MODULE to use this module" -#endif - - -extern void score(void); -extern int average_score_of_age(int age, int a); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef SCORE_H +#define SCORE_H +#ifdef __cplusplus +extern "C" { +#endif + +#if SCORE_MODULE == 0 +#error "must define SCORE_MODULE to use this module" +#endif + + +extern void score(void); +extern int average_score_of_age(int age, int a); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/weather.c b/src/modules/weather.c index 03b5b035c..98bab62d0 100644 --- a/src/modules/weather.c +++ b/src/modules/weather.c @@ -1,141 +1,141 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifdef WEATHER - -#include -#include -#include "weather.h" - -/* libc includes */ -#include - -weather * -create_weather(region *r, weather_t type) - -{ - weather *w; - - w = calloc(1, sizeof(weather)); - w->center[0] = r->x; - w->center[1] = r->y; - w->type = type; - w->move[0] = (rng_int()%3) - 1; - w->move[1] = (rng_int()%3) - 1; - - switch(type) { - case WEATHER_STORM: - w->radius = rng_int()%2+1; - break; - case WEATHER_HURRICANE: - w->radius = 1; - break; - default: - w->radius = 0; - } - - addlist(&weathers, w); - - return w; -} - -double -distance(int x1, int y1, int x2, int y2) - -{ - return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); -} - -/* Diese Funktion ermittelt für jede Region, welches Wetter in ihr - herrscht. Die Wettertypen sind dabei nach ihrer Reihenfolge in der - enumeration priorisiert. - - - Einladen - set_weather(); - - Eigentliche Auswertung - - Veränderungen des Wetters - set_weather(); - - Report generieren - - Abspeichern - - Diese Routine ist sehr rechenaufwendig! -*/ - -void -set_weather(void) - -{ - weather_t i; - weather *w; - short x, y; - int d; - region *r; - - for(r=regions;r;r=r->next) { - r->weathertype = WEATHER_NONE; - } - - for(i = 0; i < MAXWEATHERS; i++) { - for(w = weathers; w; w = w->next) { - if(w->type == i) { - for(x=w->center[0]-w->radius; x<=w->center[0]+w->radius; x++) { - for(y=w->center[1]-w->radius; y<=w->center[1]+w->radius; y++) { - d = distance(w->center[0], w->center[1], x, y); - if(floor(d+0.5) <= w->radius) { - r = findregion(x,y); - if(r) { - r->weathertype = w->type; - } - } - } - } - } - } - } -} - -void -move_weather(void) - -{ - weather *w, *wnext; - region *r; - - for(w = weathers; w;) { - wnext = w->next; - w->center[0] = w->center[0] + w->move[0]; - w->center[1] = w->center[1] + w->move[1]; - r = findregion(w->center[0], w->center[1]); - if(!r || rng_int()%100 < 5) { - removelist(&weathers, w); - } - w = wnext; - } -} - -#else -#include -static const char* copyright = "(c) Eressea PBEM 2000"; - -void -init_weather(void) -{ - fputs(copyright, stderr); - /* TODO: Initialization */ -} -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifdef WEATHER + +#include +#include +#include "weather.h" + +/* libc includes */ +#include + +weather * +create_weather(region *r, weather_t type) + +{ + weather *w; + + w = calloc(1, sizeof(weather)); + w->center[0] = r->x; + w->center[1] = r->y; + w->type = type; + w->move[0] = (rng_int()%3) - 1; + w->move[1] = (rng_int()%3) - 1; + + switch(type) { + case WEATHER_STORM: + w->radius = rng_int()%2+1; + break; + case WEATHER_HURRICANE: + w->radius = 1; + break; + default: + w->radius = 0; + } + + addlist(&weathers, w); + + return w; +} + +double +distance(int x1, int y1, int x2, int y2) + +{ + return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); +} + +/* Diese Funktion ermittelt für jede Region, welches Wetter in ihr + herrscht. Die Wettertypen sind dabei nach ihrer Reihenfolge in der + enumeration priorisiert. + + - Einladen + set_weather(); + - Eigentliche Auswertung + - Veränderungen des Wetters + set_weather(); + - Report generieren + - Abspeichern + + Diese Routine ist sehr rechenaufwendig! +*/ + +void +set_weather(void) + +{ + weather_t i; + weather *w; + short x, y; + int d; + region *r; + + for(r=regions;r;r=r->next) { + r->weathertype = WEATHER_NONE; + } + + for(i = 0; i < MAXWEATHERS; i++) { + for(w = weathers; w; w = w->next) { + if(w->type == i) { + for(x=w->center[0]-w->radius; x<=w->center[0]+w->radius; x++) { + for(y=w->center[1]-w->radius; y<=w->center[1]+w->radius; y++) { + d = distance(w->center[0], w->center[1], x, y); + if(floor(d+0.5) <= w->radius) { + r = findregion(x,y); + if(r) { + r->weathertype = w->type; + } + } + } + } + } + } + } +} + +void +move_weather(void) + +{ + weather *w, *wnext; + region *r; + + for(w = weathers; w;) { + wnext = w->next; + w->center[0] = w->center[0] + w->move[0]; + w->center[1] = w->center[1] + w->move[1]; + r = findregion(w->center[0], w->center[1]); + if(!r || rng_int()%100 < 5) { + removelist(&weathers, w); + } + w = wnext; + } +} + +#else +#include +static const char* copyright = "(c) Eressea PBEM 2000"; + +void +init_weather(void) +{ + fputs(copyright, stderr); + /* TODO: Initialization */ +} +#endif diff --git a/src/modules/weather.h b/src/modules/weather.h index 6ec87dd14..60800c7e9 100644 --- a/src/modules/weather.h +++ b/src/modules/weather.h @@ -1,54 +1,54 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_MOD_WEATHER_H -#define H_MOD_WEATHER_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WEATHER -# error "the weather system is disabled" -#endif - -enum { - WEATHER_NONE, - WEATHER_STORM, - WEATHER_HURRICANE, - MAXWEATHERS -}; - -typedef unsigned char weather_t; - -typedef struct weather { - struct weather *next; - weather_t type; /* Typ der Wetterzone */ - int center[2]; /* Koordinaten des Zentrums */ - int radius; - int move[2]; -} weather; - -weather *weathers; - -void set_weather(void); -void move_weather(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_MOD_WEATHER_H +#define H_MOD_WEATHER_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WEATHER +# error "the weather system is disabled" +#endif + +enum { + WEATHER_NONE, + WEATHER_STORM, + WEATHER_HURRICANE, + MAXWEATHERS +}; + +typedef unsigned char weather_t; + +typedef struct weather { + struct weather *next; + weather_t type; /* Typ der Wetterzone */ + int center[2]; /* Koordinaten des Zentrums */ + int radius; + int move[2]; +} weather; + +weather *weathers; + +void set_weather(void); +void move_weather(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/wormhole.c b/src/modules/wormhole.c index 1ad7c93bf..144c0656a 100644 --- a/src/modules/wormhole.c +++ b/src/modules/wormhole.c @@ -1,221 +1,222 @@ -/* vi: set ts=2: - +-------------------+ - | | Christian Schlittchen - | Eressea PBEM host | Enno Rehling - | (c) 1998 - 2004 | Katja Zedel - | | - +-------------------+ - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "settings.h" - -#include "wormhole.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include - -/* libc includes */ -#include -#include - -static boolean -good_region(const region * r) -{ - return (!fval(r, RF_CHAOTIC) && r->age>30 && rplane(r)==NULL && r->units!=NULL && r->land!=NULL); -} - -static int -cmp_age(const void * v1, const void *v2) -{ - const region * r1 = (const region*)v1; - const region * r2 = (const region*)v2; - if (r1->ageage) return -1; - if (r1->age>r2->age) return 1; - return 0; -} - -typedef struct wormhole_data { - building * entry; - region * exit; -} wormhole_data; - -static void -wormhole_init(struct attrib *a) -{ - a->data.v = calloc(1, sizeof(wormhole_data)); -} - -static void -wormhole_done(struct attrib * a) -{ - free(a->data.v); -} - -static int -wormhole_age(struct attrib * a) -{ - wormhole_data * data = (wormhole_data*)a->data.v; - int maxtransport = data->entry->size; - region * r = data->entry->region; - unit * u = r->units; - - for (;u!=NULL && maxtransport!=0;u=u->next) { - if (u->building==data->entry) { - message * m = NULL; - if (u->number>maxtransport || has_limited_skills(u)) { - m = msg_message("wormhole_requirements", "unit region", u, u->region); - } else if (data->exit!=NULL) { - move_unit(u, data->exit, NULL); - maxtransport -= u->number; - m = msg_message("wormhole_exit", "unit region", u, data->exit); - add_message(&data->exit->msgs, m); - } - if (m!=NULL) { - add_message(&u->faction->msgs, m); - msg_release(m); - } - } - } - - remove_building(&r->buildings, data->entry); - ADDMSG(&r->msgs, msg_message("wormhole_dissolve", "region", r)); - - /* age returns 0 if the attribute needs to be removed, !=0 otherwise */ - return AT_AGE_KEEP; -} - -static void -wormhole_write(const struct attrib * a, const void * owner, struct storage * store) -{ - wormhole_data * data = (wormhole_data*)a->data.v; - write_building_reference(data->entry, store); - write_region_reference(data->exit, store); -} - -/** conversion code, turn 573, 2008-05-23 */ -static int -resolve_exit(variant id, void * address) -{ - building * b = findbuilding(id.i); - region ** rp = address; - if (b) { - *rp = b->region; - return 0; - } - *rp = NULL; - return -1; -} - -static int -wormhole_read(struct attrib * a, void * owner, struct storage * store) -{ - wormhole_data * data = (wormhole_data*)a->data.v; - resolve_fun resolver = (store->versionversionentry, store, read_building_reference, resolve_building); - int rr = read_reference(&data->exit, store, reader, resolver); - if (rb==0 && rr==0) { - if (!data->exit || !data->entry) { - return AT_READ_FAIL; - } - } - return AT_READ_OK; -} - -static attrib_type at_wormhole = { - "wormhole", - wormhole_init, - wormhole_done, - wormhole_age, - wormhole_write, - wormhole_read, - ATF_UNIQUE -}; - -static void -make_wormhole(const building_type * bt_wormhole, region * r1, region * r2) -{ - building * b1 = new_building(bt_wormhole, r1, default_locale); - building * b2 = new_building(bt_wormhole, r2, default_locale); - attrib * a1 = a_add(&b1->attribs, a_new(&at_wormhole)); - attrib * a2 = a_add(&b2->attribs, a_new(&at_wormhole)); - wormhole_data * d1 = (wormhole_data*)a1->data.v; - wormhole_data * d2 = (wormhole_data*)a2->data.v; - d1->entry = b1; - d2->entry = b2; - d1->exit = b2->region; - d2->exit = b1->region; - b1->size = bt_wormhole->maxsize; - b2->size = bt_wormhole->maxsize; - ADDMSG(&r1->msgs, msg_message("wormhole_appear", "region", r1)); - ADDMSG(&r2->msgs, msg_message("wormhole_appear", "region", r2)); -} - -void -create_wormholes(void) -{ -#define WORMHOLE_CHANCE 10000 - const building_type * bt_wormhole = bt_find("wormhole"); - region_list *rptr, * rlist = NULL; - region * r = regions; - int i = 0, count = 0; - region ** match; - - if (bt_wormhole==NULL) return; - /* - * select a list of regions. we'll sort them by age later. - */ - while (r!=NULL) { - int next = rng_int() % (2*WORMHOLE_CHANCE); - while (r!=NULL && (next!=0 || !good_region(r))) { - if (good_region(r)) { - --next; - } - r=r->next; - } - if (r==NULL) break; - add_regionlist(&rlist, r); - ++count; - r=r->next; - } - - if (count<2) return; - - match = (region**)malloc(sizeof(region*) * count); - rptr = rlist; - while (i!=count) { - match[i++] = rptr->data; - rptr = rptr->next; - } - qsort(match, count, sizeof(region *), cmp_age); - free_regionlist(rlist); - - count /= 2; - for (i=0;i!=count;++i) { - make_wormhole(bt_wormhole, match[i], match[i+count]); - } -} - -void -register_wormholes(void) -{ - at_register(&at_wormhole); -} +/* vi: set ts=2: + +-------------------+ + | | Christian Schlittchen + | Eressea PBEM host | Enno Rehling + | (c) 1998 - 2004 | Katja Zedel + | | + +-------------------+ + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "settings.h" + +#include "wormhole.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include + +static boolean +good_region(const region * r) +{ + return (!fval(r, RF_CHAOTIC) && r->age>30 && rplane(r)==NULL && r->units!=NULL && r->land!=NULL); +} + +static int +cmp_age(const void * v1, const void *v2) +{ + const region * r1 = (const region*)v1; + const region * r2 = (const region*)v2; + if (r1->ageage) return -1; + if (r1->age>r2->age) return 1; + return 0; +} + +typedef struct wormhole_data { + building * entry; + region * exit; +} wormhole_data; + +static void +wormhole_init(struct attrib *a) +{ + a->data.v = calloc(1, sizeof(wormhole_data)); +} + +static void +wormhole_done(struct attrib * a) +{ + free(a->data.v); +} + +static int +wormhole_age(struct attrib * a) +{ + wormhole_data * data = (wormhole_data*)a->data.v; + int maxtransport = data->entry->size; + region * r = data->entry->region; + unit * u = r->units; + + for (;u!=NULL && maxtransport!=0;u=u->next) { + if (u->building==data->entry) { + message * m = NULL; + if (u->number>maxtransport || has_limited_skills(u)) { + m = msg_message("wormhole_requirements", "unit region", u, u->region); + } else if (data->exit!=NULL) { + move_unit(u, data->exit, NULL); + maxtransport -= u->number; + m = msg_message("wormhole_exit", "unit region", u, data->exit); + add_message(&data->exit->msgs, m); + } + if (m!=NULL) { + add_message(&u->faction->msgs, m); + msg_release(m); + } + } + } + + remove_building(&r->buildings, data->entry); + ADDMSG(&r->msgs, msg_message("wormhole_dissolve", "region", r)); + + /* age returns 0 if the attribute needs to be removed, !=0 otherwise */ + return AT_AGE_KEEP; +} + +static void +wormhole_write(const struct attrib * a, const void * owner, struct storage * store) +{ + wormhole_data * data = (wormhole_data*)a->data.v; + write_building_reference(data->entry, store); + write_region_reference(data->exit, store); +} + +/** conversion code, turn 573, 2008-05-23 */ +static int +resolve_exit(variant id, void * address) +{ + building * b = findbuilding(id.i); + region ** rp = address; + if (b) { + *rp = b->region; + return 0; + } + *rp = NULL; + return -1; +} + +static int +wormhole_read(struct attrib * a, void * owner, struct storage * store) +{ + wormhole_data * data = (wormhole_data*)a->data.v; + resolve_fun resolver = (store->versionversionentry, store, read_building_reference, resolve_building); + int rr = read_reference(&data->exit, store, reader, resolver); + if (rb==0 && rr==0) { + if (!data->exit || !data->entry) { + return AT_READ_FAIL; + } + } + return AT_READ_OK; +} + +static attrib_type at_wormhole = { + "wormhole", + wormhole_init, + wormhole_done, + wormhole_age, + wormhole_write, + wormhole_read, + ATF_UNIQUE +}; + +static void +make_wormhole(const building_type * bt_wormhole, region * r1, region * r2) +{ + building * b1 = new_building(bt_wormhole, r1, default_locale); + building * b2 = new_building(bt_wormhole, r2, default_locale); + attrib * a1 = a_add(&b1->attribs, a_new(&at_wormhole)); + attrib * a2 = a_add(&b2->attribs, a_new(&at_wormhole)); + wormhole_data * d1 = (wormhole_data*)a1->data.v; + wormhole_data * d2 = (wormhole_data*)a2->data.v; + d1->entry = b1; + d2->entry = b2; + d1->exit = b2->region; + d2->exit = b1->region; + b1->size = bt_wormhole->maxsize; + b2->size = bt_wormhole->maxsize; + ADDMSG(&r1->msgs, msg_message("wormhole_appear", "region", r1)); + ADDMSG(&r2->msgs, msg_message("wormhole_appear", "region", r2)); +} + +void +create_wormholes(void) +{ +#define WORMHOLE_CHANCE 10000 + const building_type * bt_wormhole = bt_find("wormhole"); + region_list *rptr, * rlist = NULL; + region * r = regions; + int i = 0, count = 0; + region ** match; + + if (bt_wormhole==NULL) return; + /* + * select a list of regions. we'll sort them by age later. + */ + while (r!=NULL) { + int next = rng_int() % (2*WORMHOLE_CHANCE); + while (r!=NULL && (next!=0 || !good_region(r))) { + if (good_region(r)) { + --next; + } + r=r->next; + } + if (r==NULL) break; + add_regionlist(&rlist, r); + ++count; + r=r->next; + } + + if (count<2) return; + + match = (region**)malloc(sizeof(region*) * count); + rptr = rlist; + while (i!=count) { + match[i++] = rptr->data; + rptr = rptr->next; + } + qsort(match, count, sizeof(region *), cmp_age); + free_regionlist(rlist); + + count /= 2; + for (i=0;i!=count;++i) { + make_wormhole(bt_wormhole, match[i], match[i+count]); + } +} + +void +register_wormholes(void) +{ + at_register(&at_wormhole); +} diff --git a/src/modules/wormhole.h b/src/modules/wormhole.h index dea7a6aab..9bb5507f1 100644 --- a/src/modules/wormhole.h +++ b/src/modules/wormhole.h @@ -1,31 +1,31 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_MOD_WORMHOLE -#define H_MOD_WORMHOLE -#ifdef __cplusplus -extern "C" { -#endif - - extern void create_wormholes(void); - extern void register_wormholes(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_MOD_WORMHOLE +#define H_MOD_WORMHOLE +#ifdef __cplusplus +extern "C" { +#endif + + extern void create_wormholes(void); + extern void register_wormholes(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/xecmd.c b/src/modules/xecmd.c index b181766b2..9a1f7765f 100644 --- a/src/modules/xecmd.c +++ b/src/modules/xecmd.c @@ -1,111 +1,111 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include - -#if XECMD_MODULE -#include "xecmd.h" - -#include - -#include "xecmd.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -static void -xe_givelaen(unit *u, struct order * ord) -{ - unit *u2 =getunitg(u->region, u->faction); - - if(!u2) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return; - } - i_change(&u2->items, olditemtype[I_LAEN], 5); -} - -static void -xe_givepotion(unit *u, struct order *ord) -{ - unit *u2 =getunitg(u->region, u->faction); - - if(!u2) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return; - } - i_change(&u2->items, it_find("skillpotion"), 1); -} - -static void -xe_giveballon(unit *u, struct order *ord) -{ - unit *u2 = getunitg(u->region, u->faction); - ship *sh; - - if (!u2) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return; - } - - sh = new_ship(st_find("balloon"), u2->faction->locale, u2->region); - sh->size = 5; - ship_setname(sh, "Xontormia-Ballon"); - leave(u2, false); - u2->ship = sh; - fset(u2, UFL_OWNER); -} - -int -xecmd(unit * u, order * ord) -{ - faction *f = u->faction; - - if (a_find(f->attribs, &at_xontormiaexpress)) { - if (get_keyword(ord) == K_XE) { - init_tokens(ord); - skip_token(); - switch(findparam(getstrtoken(),f->locale)) { - case P_XEPOTION: - xe_givepotion(u, ord); - break; - case P_XEBALLOON: - xe_giveballon(u, ord); - break; - case P_XELAEN: - xe_givelaen(u, ord); - break; - } - } - } - return 0; -} - -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include + +#if XECMD_MODULE +#include "xecmd.h" + +#include + +#include "xecmd.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +static void +xe_givelaen(unit *u, struct order * ord) +{ + unit *u2 =getunitg(u->region, u->faction); + + if(!u2) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + i_change(&u2->items, olditemtype[I_LAEN], 5); +} + +static void +xe_givepotion(unit *u, struct order *ord) +{ + unit *u2 =getunitg(u->region, u->faction); + + if(!u2) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + i_change(&u2->items, it_find("skillpotion"), 1); +} + +static void +xe_giveballon(unit *u, struct order *ord) +{ + unit *u2 = getunitg(u->region, u->faction); + ship *sh; + + if (!u2) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + + sh = new_ship(st_find("balloon"), u2->faction->locale, u2->region); + sh->size = 5; + ship_setname(sh, "Xontormia-Ballon"); + leave(u2, false); + u2->ship = sh; + fset(u2, UFL_OWNER); +} + +int +xecmd(unit * u, order * ord) +{ + faction *f = u->faction; + + if (a_find(f->attribs, &at_xontormiaexpress)) { + if (get_keyword(ord) == K_XE) { + init_tokens(ord); + skip_token(); + switch(findparam(getstrtoken(),f->locale)) { + case P_XEPOTION: + xe_givepotion(u, ord); + break; + case P_XEBALLOON: + xe_giveballon(u, ord); + break; + case P_XELAEN: + xe_givelaen(u, ord); + break; + } + } + } + return 0; +} + +#endif diff --git a/src/modules/xecmd.h b/src/modules/xecmd.h index a964d38da..65712f877 100644 --- a/src/modules/xecmd.h +++ b/src/modules/xecmd.h @@ -1,27 +1,27 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_MOD_XECMD_H -#define H_MOD_XECMD_H -#ifdef __cplusplus -extern "C" { -#endif - -#if XECMD_MODULE -int xecmd(struct unit * u, struct order * ord); -#endif - -#ifdef __cplusplus -} -#endif -#endif - +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_MOD_XECMD_H +#define H_MOD_XECMD_H +#ifdef __cplusplus +extern "C" { +#endif + +#if XECMD_MODULE +int xecmd(struct unit * u, struct order * ord); +#endif + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/modules/xmas.c b/src/modules/xmas.c index 01f0b4297..3fa8796c8 100644 --- a/src/modules/xmas.c +++ b/src/modules/xmas.c @@ -1,82 +1,82 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "xmas.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include - -static int -xmasgate_handle(trigger * t, void * data) -{ - return -1; -} - -static void -xmasgate_write(const trigger * t, struct storage * store) -{ - building *b = (building *)t->data.v; - store->w_tok(store, itoa36(b->no)); -} - -static int -xmasgate_read(trigger * t, struct storage * store) -{ - int bc = read_reference(&t->data.v, store, read_building_reference, resolve_building); - if (bc==0 && !t->data.v) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -struct trigger_type tt_xmasgate = { - "xmasgate", - NULL, - NULL, - xmasgate_handle, - xmasgate_write, - xmasgate_read -}; - -trigger * -trigger_xmasgate(building * b) -{ - trigger * t = t_new(&tt_xmasgate); - t->data.v = b; - return t; -} - -void -register_xmas(void) -{ - tt_register(&tt_xmasgate); -} - +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "xmas.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include + +static int +xmasgate_handle(trigger * t, void * data) +{ + return -1; +} + +static void +xmasgate_write(const trigger * t, struct storage * store) +{ + building *b = (building *)t->data.v; + store->w_tok(store, itoa36(b->no)); +} + +static int +xmasgate_read(trigger * t, struct storage * store) +{ + int bc = read_reference(&t->data.v, store, read_building_reference, resolve_building); + if (bc==0 && !t->data.v) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +struct trigger_type tt_xmasgate = { + "xmasgate", + NULL, + NULL, + xmasgate_handle, + xmasgate_write, + xmasgate_read +}; + +trigger * +trigger_xmasgate(building * b) +{ + trigger * t = t_new(&tt_xmasgate); + t->data.v = b; + return t; +} + +void +register_xmas(void) +{ + tt_register(&tt_xmasgate); +} + diff --git a/src/modules/xmas.h b/src/modules/xmas.h index 334ab8b38..7201aee6c 100644 --- a/src/modules/xmas.h +++ b/src/modules/xmas.h @@ -1,29 +1,29 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_MOD_XMAS -#define H_MOD_XMAS -#ifdef __cplusplus -extern "C" { -#endif - -struct region; -struct unit; - -extern struct trigger *trigger_xmasgate(struct building * b); - -extern void register_xmas(void); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_MOD_XMAS +#define H_MOD_XMAS +#ifdef __cplusplus +extern "C" { +#endif + +struct region; +struct unit; + +extern struct trigger *trigger_xmasgate(struct building * b); + +extern void register_xmas(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/platform.h b/src/platform.h index 721006b7b..8596a9ab0 100644 --- a/src/platform.h +++ b/src/platform.h @@ -1,282 +1,286 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef CONFIG_H -#define CONFIG_H - -#ifdef _MSC_VER -# define VC_EXTRALEAN -# define WIN32_LEAN_AND_MEAN -# include -# undef MOUSE_MOVED -# define STDIO_CP 1252 /* log.c, convert to console character set */ -# pragma warning (disable: 4201 4214 4514 4115 4711) -# pragma warning(disable: 4056) -/* warning C4056: overflow in floating point constant arithmetic */ -# pragma warning(disable: 4201) -/* warning C4201: nonstandard extension used : nameless struct/union */ -# pragma warning(disable: 4214) -/* warning C4214: nonstandard extension used : bit field types other than int */ -# pragma warning(disable: 4100) -/* warning C4100: : unreferenced formal parameter */ -# pragma warning(disable: 4996) - -/* warning C4100: was declared deprecated */ -#ifndef _CRT_SECURE_NO_DEPRECATE -# define _CRT_SECURE_NO_DEPRECATE -#endif - -/* http://msdn2.microsoft.com/en-us/library/ms235505(VS.80).aspx */ -#ifndef _CRT_DISABLE_PERFCRIT_LOCKS -# define _CRT_DISABLE_PERFCRIT_LOCKS -#endif - -#endif /* _MSC_VER_ */ - - -#ifdef __cplusplus -# include -# include -extern "C" { -#else -# include -# include -#endif - -/**** **** - ** Debugging Libraries ** - **** ****/ -#if defined __GNUC__ -# define HAVE_INLINE -# define INLINE_FUNCTION static __inline -#endif - -/* define USE_DMALLOC to enable use of the dmalloc library */ -#ifdef USE_DMALLOC -# include -# include -# include -#endif - -/* define CRTDBG to enable MSVC CRT Debug library functions */ -#if defined(_DEBUG) && defined(_MSC_VER) && defined(CRTDBG) -# include -# define _CRTDBG_MAP_ALLOC -#endif - -/**** **** - ** Architecture Dependent ** - **** ****/ - -/* für solaris: */ -#ifdef SOLARIS -# define _SYS_PROCSET_H -# define _XOPEN_SOURCE -#endif - -#ifdef __GNUC__ -# ifndef _BSD_SOURCE -# define _BSD_SOURCE -# define __USE_BSD -# endif -/* # include */ -# include /* strncasecmp-Prototyp */ -#endif - -#ifdef _BSD_SOURCE -# define __EXTENSIONS__ -#endif - -#ifdef WIN32 -# define HAVE__MKDIR_WITHOUT_PERMISSION -# define HAVE__SLEEP_MSEC -#endif - -#if defined(__USE_SVID) || defined(_BSD_SOURCE) || defined(__USE_XOPEN_EXTENDED) || defined(_BE_SETUP_H) || defined(CYGWIN) -# include -# define HAVE_UNISTD_H -# define HAVE_STRCASECMP -# define HAVE_STRNCASECMP -# define HAVE_ACCESS -# define HAVE_STAT -typedef struct stat stat_type; -# include -# define HAVE_STRDUP -# define HAVE_SNPRINTF -#ifdef _POSIX_SOURCE /* MINGW doesn't seem to have these */ -# define HAVE_EXECINFO -# define HAVE_MKDIR_WITH_PERMISSION -# define HAVE_SIGACTION -# define HAVE_LINK -# define HAVE_SLEEP -#endif -#endif - -/* egcpp 4 dos */ -#ifdef MSDOS -# include -# define HAVE_MKDIR_WITH_PERMISSION -#endif - -/* lcc-win32 */ -#ifdef __LCC__ -# include -# include -# include -# define HAVE_ACCESS -# define HAVE_STAT -typedef struct stat stat_type; -# define HAVE_STRICMP -# define HAVE_STRNICMP -# define HAVE_STRDUP -# define HAVE_SLEEP -# define snprintf _snprintf -# define HAVE_SNPRINTF -# undef HAVE_STRCASECMP -# undef HAVE_STRNCASECMP -# define R_OK 4 -#endif - -/* Microsoft Visual C */ -#ifdef _MSC_VER -# include /* must be included here so strdup is not redefined */ -# define R_OK 4 -# define HAVE_INLINE -# define INLINE_FUNCTION __inline - -# define snprintf _snprintf -# define HAVE_SNPRINTF - -/* MSVC has _access, not access */ -#ifndef access -# define access(f, m) _access(f, m) -#endif -#define HAVE_ACCESS - -/* MSVC has _stat, not stat */ -# define HAVE_STAT -#include -# define stat(a, b) _stat(a, b) -typedef struct _stat stat_type; - -/* MSVC has _strdup */ -# define strdup _strdup -# define HAVE_STRDUP - -# define stricmp(a, b) _stricmp(a, b) -# define HAVE_STRICMP - -# define strnicmp(a, b, c) _strnicmp(a, b, c) -# define HAVE_STRNICMP -# undef HAVE_STRCASECMP -# undef HAVE_STRNCASECMP -#endif - -/* replacements for missing functions: */ - -#ifndef HAVE_STRCASECMP -# if defined(HAVE_STRICMP) -# define strcasecmp stricmp -# elif defined(HAVE__STRICMP) -# define strcasecmp _stricmp -# endif -#endif - -#ifndef HAVE_STRNCASECMP -# if defined(HAVE_STRNICMP) -# define strncasecmp strnicmp -# elif defined(HAVE__STRNICMP) -# define strncasecmp _strnicmp -# endif -#endif - -#ifdef HAVE_MKDIR_WITH_PERMISSION -# define makedir(d, p) mkdir(d, p) -#elif defined(HAVE_MKDIR_WITHOUT_PERMISSION) -# define makedir(d, p) mkdir(d) -#elif defined(HAVE__MKDIR_WITHOUT_PERMISSION) -_CRTIMP int __cdecl _mkdir(const char *); -# define makedir(d, p) _mkdir(d) -#endif - -#ifndef HAVE_STRDUP -extern char * strdup(const char *s); -#endif - -#ifndef HAVE_SLEEP -#ifdef HAVE__SLEEP_MSEC -# define sleep(sec) _sleep(1000*sec) -#elif defined(HAVE__SLEEP) -# define sleep(sec) _sleep(sec) -#endif -#endif - -#if !defined(MAX_PATH) -# if defined(PATH_MAX) -# define MAX_PATH PATH_MAX -# else -# define MAX_PATH 1024 -# endif -#endif - -/**** **** - ** min/max macros ** - **** ****/ -#ifndef NOMINMAX -#ifndef MIN -# define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif -#ifndef MAX -# define MAX(a,b) ((a) > (b) ? (a) : (b)) -#endif -#endif - -#if defined (__GNUC__) -# define unused(a) /* unused: a */ -#elif defined (ghs) || defined (__hpux) || defined (__sgi) || defined (__DECCXX) || defined (__KCC) || defined (__rational__) || defined (__USLC__) || defined (ACE_RM544) -# define unused(a) do {/* null */} while (&a == 0) -#else /* ghs || __GNUC__ || ..... */ -# define unused(a) (a) -#endif /* ghs || __GNUC__ || ..... */ - -/**** **** - ** The Eressea boolean type ** - **** ****/ -#if defined(BOOLEAN) -# define boolean BOOLEAN -#else - typedef int boolean; /* not bool! wrong size. */ -#endif -#ifndef __cplusplus -# define false ((boolean)0) -# define true ((boolean)!false) -#endif -#ifdef __cplusplus -} -#endif - -#ifndef INLINE_FUNCTION -# define INLINE_FUNCTION -#endif - -#define iswxspace(c) (c==160 || iswspace(c)) -#define isxspace(c) (c==160 || isspace(c)) - -#define TOLUA_CAST (char*) -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CONFIG_H +#define CONFIG_H + +#define HAVE_LIBXML +#undef HAVE_TINYXML +#define HAVE_CURSES + +#ifdef _MSC_VER +# define VC_EXTRALEAN +# define WIN32_LEAN_AND_MEAN +# include +# undef MOUSE_MOVED +# define STDIO_CP 1252 /* log.c, convert to console character set */ +# pragma warning (disable: 4201 4214 4514 4115 4711) +# pragma warning(disable: 4056) +/* warning C4056: overflow in floating point constant arithmetic */ +# pragma warning(disable: 4201) +/* warning C4201: nonstandard extension used : nameless struct/union */ +# pragma warning(disable: 4214) +/* warning C4214: nonstandard extension used : bit field types other than int */ +# pragma warning(disable: 4100) +/* warning C4100: : unreferenced formal parameter */ +# pragma warning(disable: 4996) + +/* warning C4100: was declared deprecated */ +#ifndef _CRT_SECURE_NO_DEPRECATE +# define _CRT_SECURE_NO_DEPRECATE +#endif + +/* http://msdn2.microsoft.com/en-us/library/ms235505(VS.80).aspx */ +#ifndef _CRT_DISABLE_PERFCRIT_LOCKS +# define _CRT_DISABLE_PERFCRIT_LOCKS +#endif + +#endif /* _MSC_VER_ */ + + +#ifdef __cplusplus +# include +# include +extern "C" { +#else +# include +# include +#endif + +/**** **** + ** Debugging Libraries ** + **** ****/ +#if defined __GNUC__ +# define HAVE_INLINE +# define INLINE_FUNCTION static __inline +#endif + +/* define USE_DMALLOC to enable use of the dmalloc library */ +#ifdef USE_DMALLOC +# include +# include +# include +#endif + +/* define CRTDBG to enable MSVC CRT Debug library functions */ +#if defined(_DEBUG) && defined(_MSC_VER) && defined(CRTDBG) +# include +# define _CRTDBG_MAP_ALLOC +#endif + +/**** **** + ** Architecture Dependent ** + **** ****/ + +/* für solaris: */ +#ifdef SOLARIS +# define _SYS_PROCSET_H +# define _XOPEN_SOURCE +#endif + +#ifdef __GNUC__ +# ifndef _BSD_SOURCE +# define _BSD_SOURCE +# define __USE_BSD +# endif +/* # include */ +# include /* strncasecmp-Prototyp */ +#endif + +#ifdef _BSD_SOURCE +# define __EXTENSIONS__ +#endif + +#ifdef WIN32 +# define HAVE__MKDIR_WITHOUT_PERMISSION +# define HAVE__SLEEP_MSEC +#endif + +#if defined(__USE_SVID) || defined(_BSD_SOURCE) || defined(__USE_XOPEN_EXTENDED) || defined(_BE_SETUP_H) || defined(CYGWIN) +# include +# define HAVE_UNISTD_H +# define HAVE_STRCASECMP +# define HAVE_STRNCASECMP +# define HAVE_ACCESS +# define HAVE_STAT +typedef struct stat stat_type; +# include +# define HAVE_STRDUP +# define HAVE_SNPRINTF +#ifdef _POSIX_SOURCE /* MINGW doesn't seem to have these */ +# define HAVE_EXECINFO +# define HAVE_MKDIR_WITH_PERMISSION +# define HAVE_SIGACTION +# define HAVE_LINK +# define HAVE_SLEEP +#endif +#endif + +/* egcpp 4 dos */ +#ifdef MSDOS +# include +# define HAVE_MKDIR_WITH_PERMISSION +#endif + +/* lcc-win32 */ +#ifdef __LCC__ +# include +# include +# include +# define HAVE_ACCESS +# define HAVE_STAT +typedef struct stat stat_type; +# define HAVE_STRICMP +# define HAVE_STRNICMP +# define HAVE_STRDUP +# define HAVE_SLEEP +# define snprintf _snprintf +# define HAVE_SNPRINTF +# undef HAVE_STRCASECMP +# undef HAVE_STRNCASECMP +# define R_OK 4 +#endif + +/* Microsoft Visual C */ +#ifdef _MSC_VER +# include /* must be included here so strdup is not redefined */ +# define R_OK 4 +# define HAVE_INLINE +# define INLINE_FUNCTION __inline + +# define snprintf _snprintf +# define HAVE_SNPRINTF + +/* MSVC has _access, not access */ +#ifndef access +# define access(f, m) _access(f, m) +#endif +#define HAVE_ACCESS + +/* MSVC has _stat, not stat */ +# define HAVE_STAT +#include +# define stat(a, b) _stat(a, b) +typedef struct _stat stat_type; + +/* MSVC has _strdup */ +# define strdup _strdup +# define HAVE_STRDUP + +# define stricmp(a, b) _stricmp(a, b) +# define HAVE_STRICMP + +# define strnicmp(a, b, c) _strnicmp(a, b, c) +# define HAVE_STRNICMP +# undef HAVE_STRCASECMP +# undef HAVE_STRNCASECMP +#endif + +/* replacements for missing functions: */ + +#ifndef HAVE_STRCASECMP +# if defined(HAVE_STRICMP) +# define strcasecmp stricmp +# elif defined(HAVE__STRICMP) +# define strcasecmp _stricmp +# endif +#endif + +#ifndef HAVE_STRNCASECMP +# if defined(HAVE_STRNICMP) +# define strncasecmp strnicmp +# elif defined(HAVE__STRNICMP) +# define strncasecmp _strnicmp +# endif +#endif + +#ifdef HAVE_MKDIR_WITH_PERMISSION +# define makedir(d, p) mkdir(d, p) +#elif defined(HAVE_MKDIR_WITHOUT_PERMISSION) +# define makedir(d, p) mkdir(d) +#elif defined(HAVE__MKDIR_WITHOUT_PERMISSION) +_CRTIMP int __cdecl _mkdir(const char *); +# define makedir(d, p) _mkdir(d) +#endif + +#ifndef HAVE_STRDUP +extern char * strdup(const char *s); +#endif + +#ifndef HAVE_SLEEP +#ifdef HAVE__SLEEP_MSEC +# define sleep(sec) _sleep(1000*sec) +#elif defined(HAVE__SLEEP) +# define sleep(sec) _sleep(sec) +#endif +#endif + +#if !defined(MAX_PATH) +# if defined(PATH_MAX) +# define MAX_PATH PATH_MAX +# else +# define MAX_PATH 1024 +# endif +#endif + +/**** **** + ** min/max macros ** + **** ****/ +#ifndef NOMINMAX +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef MAX +# define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif +#endif + +#if defined (__GNUC__) +# define unused(a) /* unused: a */ +#elif defined (ghs) || defined (__hpux) || defined (__sgi) || defined (__DECCXX) || defined (__KCC) || defined (__rational__) || defined (__USLC__) || defined (ACE_RM544) +# define unused(a) do {/* null */} while (&a == 0) +#else /* ghs || __GNUC__ || ..... */ +# define unused(a) (a) +#endif /* ghs || __GNUC__ || ..... */ + +/**** **** + ** The Eressea boolean type ** + **** ****/ +#if defined(BOOLEAN) +# define boolean BOOLEAN +#else + typedef int boolean; /* not bool! wrong size. */ +#endif +#ifndef __cplusplus +# define false ((boolean)0) +# define true ((boolean)!false) +#endif +#ifdef __cplusplus +} +#endif + +#ifndef INLINE_FUNCTION +# define INLINE_FUNCTION +#endif + +#define iswxspace(c) (c==160 || iswspace(c)) +#define isxspace(c) (c==160 || isspace(c)) + +#define TOLUA_CAST (char*) +#endif + diff --git a/src/settings.h b/src/settings.h index c866d648e..b791c45e2 100644 --- a/src/settings.h +++ b/src/settings.h @@ -1,63 +1,55 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -/* - * Contains defines for the "free" game (Eressea) . - * Include this file from settings.h to make eressea work. - */ -#define ENTERTAINFRACTION 20 -#define TEACHDIFFERENCE 2 -#define GUARD_DISABLES_RECRUIT 1 -#define GUARD_DISABLES_PRODUCTION 1 -#define RESOURCE_QUANTITY 0.5 -#define RECRUITFRACTION 40 /* 100/RECRUITFRACTION% */ -#define COMBAT_TURNS 5 -#define NEWATSROI 0 - -/* Vermehrungsrate Bauern in 1/10000. -* Evt. Berechnungsfehler, reale Vermehrungsraten scheinen höher. */ -#define PEASANTGROWTH 10 -#define BATTLE_KILLS_PEASANTS 20 -#define PEASANTLUCK 10 - -#define HUNGER_REDUCES_SKILL /* Hunger reduziert den Talentwert - auf die Hälfte */ - -#define ASTRAL_ITEM_RESTRICTIONS /* keine grossen dinge im astralraum */ -#define NEW_DAEMONHUNGER_RULE -#define NEW_COMBATSKILLS_RULE -#define ROW_FACTOR 3 /* factor for combat row advancement rule */ - -/* optional game components. TODO: These should either be - * configuration variables (XML), script extensions (lua), - * or both. We don't want separate binaries for different games - */ -#define SCORE_MODULE 1 -#define MUSEUM_MODULE 1 -#define ARENA_MODULE 1 -#define XECMD_MODULE 1 -#define DUNGEON_MODULE 0 -#define CHANGED_CROSSBOWS 0 /* use the WTF_ARMORPIERCING flag */ -#undef GLOBAL_WARMING /* number of turns before global warming sets in */ - -#define SIMPLE_COMBAT -#define SIMPLE_ESCAPE - -#if defined(BINDINGS_LUABIND) -# undef BINDINGS_TOLUA -#elif defined(BINDINGS_TOLUA) -# undef BINDINGS_LUABIND -#else -# define BINDINGS_TOLUA /* new default */ -#endif - -#undef REGIONOWNERS /* (WIP) region-owner uses HELP_TRAVEL to control entry to region */ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +/* + * Contains defines for the "free" game (Eressea) . + * Include this file from settings.h to make eressea work. + */ +#define ENTERTAINFRACTION 20 +#define TEACHDIFFERENCE 2 +#define GUARD_DISABLES_RECRUIT 1 +#define GUARD_DISABLES_PRODUCTION 1 +#define RESOURCE_QUANTITY 0.5 +#define RECRUITFRACTION 40 /* 100/RECRUITFRACTION% */ +#define COMBAT_TURNS 5 +#define NEWATSROI 0 + +/* Vermehrungsrate Bauern in 1/10000. +* Evt. Berechnungsfehler, reale Vermehrungsraten scheinen höher. */ +#define PEASANTGROWTH 10 +#define BATTLE_KILLS_PEASANTS 20 +#define PEASANTLUCK 10 + +#define HUNGER_REDUCES_SKILL /* Hunger reduziert den Talentwert + auf die Hälfte */ + +#define ASTRAL_ITEM_RESTRICTIONS /* keine grossen dinge im astralraum */ +#define NEW_DAEMONHUNGER_RULE +#define NEW_COMBATSKILLS_RULE +#define ROW_FACTOR 3 /* factor for combat row advancement rule */ + +/* optional game components. TODO: These should either be + * configuration variables (XML), script extensions (lua), + * or both. We don't want separate binaries for different games + */ +#define SCORE_MODULE 1 +#define MUSEUM_MODULE 1 +#define ARENA_MODULE 1 +#define XECMD_MODULE 1 +#define DUNGEON_MODULE 0 +#define CHANGED_CROSSBOWS 0 /* use the WTF_ARMORPIERCING flag */ +#undef GLOBAL_WARMING /* number of turns before global warming sets in */ + +#define SIMPLE_COMBAT +#define SIMPLE_ESCAPE + +#undef REGIONOWNERS /* (WIP) region-owner uses HELP_TRAVEL to control entry to region */ diff --git a/src/stdafx.h b/src/stdafx.h index f6db3cac1..0fd846fd4 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -1 +1 @@ -/* empty, only used in non-msvc builds */ +/* empty, only used in non-msvc builds */ diff --git a/src/tests.c b/src/tests.c index 27f28b791..3fc765b9d 100644 --- a/src/tests.c +++ b/src/tests.c @@ -1,127 +1,127 @@ -#include -#include - -#include -#include "tests.h" - -CuSuite* get_base36_suite(void); -CuSuite* get_curse_suite(void); -CuSuite* get_market_suite(void); -CuSuite* get_laws_suite(void); - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int RunAllTests(void) { - CuString *output = CuStringNew(); - CuSuite* suite = CuSuiteNew(); - - init_resources(); - - CuSuiteAddSuite(suite, get_base36_suite()); - CuSuiteAddSuite(suite, get_curse_suite()); - CuSuiteAddSuite(suite, get_market_suite()); - CuSuiteAddSuite(suite, get_laws_suite()); - - CuSuiteRun(suite); - CuSuiteSummary(suite, output); - CuSuiteDetails(suite, output); - printf("%s\n", output->buffer); - return suite->failCount; -} - -struct race * test_create_race(const char * name) -{ - race * rc = rc_add(rc_new("human")); - return rc; -} - -struct region * test_create_region(int x, int y, const struct terrain_type * terrain) -{ - region * r = new_region(x, y, NULL, 0); - terraform_region(r, terrain); - rsettrees(r, 0, 0); - rsettrees(r, 1, 0); - rsettrees(r, 2, 0); - rsethorses(r, 0); - rsetpeasants(r, terrain->size); - return r; -} - -struct faction * test_create_faction(const struct race * rc) -{ - faction * f = addfaction("nobody@eressea.de", NULL, rc, default_locale, 0); - return f; -} - -struct unit * test_create_unit(struct faction * f, struct region * r) -{ - unit * u = create_unit(r, f, 1, f->race, 0, 0, 0); - return u; -} - -void test_cleanup(void) { - global.functions.maintenance = NULL; - global.functions.wage = NULL; - free_gamedata(); -} - -/** creates a small world and some stuff in it. - * two terrains: 'plain' and 'ocean' - * one race: 'human' - * one ship_type: 'boat' - * one building_type: 'castle' - * in 0.0 and 1.0 is an island of two plains, around it is ocean. - */ -void test_create_world(void) -{ - terrain_type * t_plain, * t_ocean; - region * island[2]; - race * rc_human; - int i; - building_type * btype; - ship_type * stype; - - t_plain = calloc(1, sizeof(terrain_type)); - t_plain->_name = strdup("plain"); - t_plain->flags = LAND_REGION|FOREST_REGION|WALK_INTO; - register_terrain(t_plain); - - t_ocean = calloc(1, sizeof(terrain_type)); - t_ocean->_name = strdup("ocean"); - t_ocean->flags = SEA_REGION|SAIL_INTO|SWIM_INTO; - register_terrain(t_ocean); - - island[0] = test_create_region(0, 0, t_plain); - island[1] = test_create_region(1, 0, t_plain); - for (i=0;i!=2;++i) { - direction_t j; - region * r = island[i]; - for (j=0;j!=MAXDIRECTIONS;++j) { - region * rn = r_connect(r, j); - if (!rn) { - rn = test_create_region(r->x+delta_x[j], r->y+delta_y[j], t_ocean); - } - } - } - - rc_human = rc_add(rc_new("human")); - rc_human->maintenance = 10; - - btype = calloc(sizeof(building_type), 1); - btype->_name = strdup("castle"); - bt_register(btype); - - stype = calloc(sizeof(ship_type), 1); - stype->name[0] = strdup("boat"); - stype->name[1] = strdup("boat_p"); - st_register(stype); - -} +#include +#include + +#include +#include "tests.h" + +CuSuite* get_base36_suite(void); +CuSuite* get_curse_suite(void); +CuSuite* get_market_suite(void); +CuSuite* get_laws_suite(void); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int RunAllTests(void) { + CuString *output = CuStringNew(); + CuSuite* suite = CuSuiteNew(); + + init_resources(); + + CuSuiteAddSuite(suite, get_base36_suite()); + CuSuiteAddSuite(suite, get_curse_suite()); + CuSuiteAddSuite(suite, get_market_suite()); + CuSuiteAddSuite(suite, get_laws_suite()); + + CuSuiteRun(suite); + CuSuiteSummary(suite, output); + CuSuiteDetails(suite, output); + printf("%s\n", output->buffer); + return suite->failCount; +} + +struct race * test_create_race(const char * name) +{ + race * rc = rc_add(rc_new("human")); + return rc; +} + +struct region * test_create_region(int x, int y, const struct terrain_type * terrain) +{ + region * r = new_region(x, y, NULL, 0); + terraform_region(r, terrain); + rsettrees(r, 0, 0); + rsettrees(r, 1, 0); + rsettrees(r, 2, 0); + rsethorses(r, 0); + rsetpeasants(r, terrain->size); + return r; +} + +struct faction * test_create_faction(const struct race * rc) +{ + faction * f = addfaction("nobody@eressea.de", NULL, rc, default_locale, 0); + return f; +} + +struct unit * test_create_unit(struct faction * f, struct region * r) +{ + unit * u = create_unit(r, f, 1, f->race, 0, 0, 0); + return u; +} + +void test_cleanup(void) { + global.functions.maintenance = NULL; + global.functions.wage = NULL; + free_gamedata(); +} + +/** creates a small world and some stuff in it. + * two terrains: 'plain' and 'ocean' + * one race: 'human' + * one ship_type: 'boat' + * one building_type: 'castle' + * in 0.0 and 1.0 is an island of two plains, around it is ocean. + */ +void test_create_world(void) +{ + terrain_type * t_plain, * t_ocean; + region * island[2]; + race * rc_human; + int i; + building_type * btype; + ship_type * stype; + + t_plain = calloc(1, sizeof(terrain_type)); + t_plain->_name = strdup("plain"); + t_plain->flags = LAND_REGION|FOREST_REGION|WALK_INTO; + register_terrain(t_plain); + + t_ocean = calloc(1, sizeof(terrain_type)); + t_ocean->_name = strdup("ocean"); + t_ocean->flags = SEA_REGION|SAIL_INTO|SWIM_INTO; + register_terrain(t_ocean); + + island[0] = test_create_region(0, 0, t_plain); + island[1] = test_create_region(1, 0, t_plain); + for (i=0;i!=2;++i) { + direction_t j; + region * r = island[i]; + for (j=0;j!=MAXDIRECTIONS;++j) { + region * rn = r_connect(r, j); + if (!rn) { + rn = test_create_region(r->x+delta_x[j], r->y+delta_y[j], t_ocean); + } + } + } + + rc_human = rc_add(rc_new("human")); + rc_human->maintenance = 10; + + btype = calloc(sizeof(building_type), 1); + btype->_name = strdup("castle"); + bt_register(btype); + + stype = calloc(sizeof(ship_type), 1); + stype->name[0] = strdup("boat"); + stype->name[1] = strdup("boat_p"); + st_register(stype); + +} diff --git a/src/tests.h b/src/tests.h index 1bf6a1304..a7510d75c 100644 --- a/src/tests.h +++ b/src/tests.h @@ -1,21 +1,21 @@ -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef DISABLE_TESTS -void test_cleanup(void); - -struct race * test_create_race(const char * name); -struct region * test_create_region(int x, int y, const struct terrain_type * terrain); -struct faction * test_create_faction(const struct race * rc); -struct unit * test_create_unit(struct faction * f, struct region * r); -void test_create_world(void); - -int RunAllTests(void); -#else -#define RunAllTests() 0 -#endif - -#ifdef __cplusplus -} -#endif +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DISABLE_TESTS +void test_cleanup(void); + +struct race * test_create_race(const char * name); +struct region * test_create_region(int x, int y, const struct terrain_type * terrain); +struct faction * test_create_faction(const struct race * rc); +struct unit * test_create_unit(struct faction * f, struct region * r); +void test_create_world(void); + +int RunAllTests(void); +#else +#define RunAllTests() 0 +#endif + +#ifdef __cplusplus +} +#endif diff --git a/src/triggers/changefaction.c b/src/triggers/changefaction.c index e704dd241..b3df84b58 100644 --- a/src/triggers/changefaction.c +++ b/src/triggers/changefaction.c @@ -1,114 +1,114 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "changefaction.h" - -/* kernel includes */ -#include -#include -#include /* FIXME: resolve_faction */ - -/* util includes */ -#include -#include -#include -#include -#include -#include - -/* ansi includes */ -#include -#include -#include - - -#include -/*** - ** restore a mage that was turned into a toad - **/ - -typedef struct changefaction_data { - struct unit * unit; - struct faction * faction; -} changefaction_data; - -static void -changefaction_init(trigger * t) -{ - t->data.v = calloc(sizeof(changefaction_data), 1); -} - -static void -changefaction_free(trigger * t) -{ - free(t->data.v); -} - -static int -changefaction_handle(trigger * t, void * data) -{ - /* call an event handler on changefaction. - * data.v -> ( variant event, int timer ) - */ - changefaction_data * td = (changefaction_data*)t->data.v; - if (td->unit && td->faction) { - u_setfaction(td->unit, td->faction); - } else { - log_error(("could not perform changefaction::handle()\n")); - } - unused(data); - return 0; -} - -static void -changefaction_write(const trigger * t, struct storage * store) -{ - changefaction_data * td = (changefaction_data*)t->data.v; - write_unit_reference(td->unit, store); - write_faction_reference(td->faction, store); -} - -static int -changefaction_read(trigger * t, struct storage * store) -{ - changefaction_data * td = (changefaction_data*)t->data.v; - read_reference(&td->unit, store, read_unit_reference, resolve_unit); - read_reference(&td->faction, store, read_faction_reference, resolve_faction); - return AT_READ_OK; -} - -trigger_type tt_changefaction = { - "changefaction", - changefaction_init, - changefaction_free, - changefaction_handle, - changefaction_write, - changefaction_read -}; - -trigger * -trigger_changefaction(unit * u, struct faction * f) -{ - trigger * t = t_new(&tt_changefaction); - changefaction_data * td = (changefaction_data*)t->data.v; - td->unit = u; - td->faction = f; - return t; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "changefaction.h" + +/* kernel includes */ +#include +#include +#include /* FIXME: resolve_faction */ + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* ansi includes */ +#include +#include +#include + + +#include +/*** + ** restore a mage that was turned into a toad + **/ + +typedef struct changefaction_data { + struct unit * unit; + struct faction * faction; +} changefaction_data; + +static void +changefaction_init(trigger * t) +{ + t->data.v = calloc(sizeof(changefaction_data), 1); +} + +static void +changefaction_free(trigger * t) +{ + free(t->data.v); +} + +static int +changefaction_handle(trigger * t, void * data) +{ + /* call an event handler on changefaction. + * data.v -> ( variant event, int timer ) + */ + changefaction_data * td = (changefaction_data*)t->data.v; + if (td->unit && td->faction) { + u_setfaction(td->unit, td->faction); + } else { + log_error(("could not perform changefaction::handle()\n")); + } + unused(data); + return 0; +} + +static void +changefaction_write(const trigger * t, struct storage * store) +{ + changefaction_data * td = (changefaction_data*)t->data.v; + write_unit_reference(td->unit, store); + write_faction_reference(td->faction, store); +} + +static int +changefaction_read(trigger * t, struct storage * store) +{ + changefaction_data * td = (changefaction_data*)t->data.v; + read_reference(&td->unit, store, read_unit_reference, resolve_unit); + read_reference(&td->faction, store, read_faction_reference, resolve_faction); + return AT_READ_OK; +} + +trigger_type tt_changefaction = { + "changefaction", + changefaction_init, + changefaction_free, + changefaction_handle, + changefaction_write, + changefaction_read +}; + +trigger * +trigger_changefaction(unit * u, struct faction * f) +{ + trigger * t = t_new(&tt_changefaction); + changefaction_data * td = (changefaction_data*)t->data.v; + td->unit = u; + td->faction = f; + return t; +} diff --git a/src/triggers/changefaction.h b/src/triggers/changefaction.h index dd2a302c5..c46deea55 100644 --- a/src/triggers/changefaction.h +++ b/src/triggers/changefaction.h @@ -1,39 +1,39 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef CHANGEFACTION_H -#define CHANGEFACTION_H -#ifdef __cplusplus -extern "C" { -#endif - -/* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; - -struct unit; -struct faction; - -extern struct trigger_type tt_changefaction; - -extern struct trigger * trigger_changefaction(struct unit * u, struct faction * f); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CHANGEFACTION_H +#define CHANGEFACTION_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; + +struct unit; +struct faction; + +extern struct trigger_type tt_changefaction; + +extern struct trigger * trigger_changefaction(struct unit * u, struct faction * f); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/changerace.c b/src/triggers/changerace.c index db5904d23..35effa513 100644 --- a/src/triggers/changerace.c +++ b/src/triggers/changerace.c @@ -1,120 +1,120 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "changerace.h" - -/* kernel includes */ -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include - -/* ansi includes */ -#include -#include -#include - - -#include -/*** - ** 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(sizeof(changerace_data), 1); -} - -static void -changerace_free(trigger * t) -{ - free(t->data.v); -} - -static int -changerace_handle(trigger * t, void * data) -{ - /* call an event handler on changerace. - * data.v -> ( variant event, int timer ) - */ - changerace_data * td = (changerace_data*)t->data.v; - if (td->u) { - if (td->race!=NULL) td->u->race = td->race; - if (td->irace!=NULL) td->u->irace = td->irace; - } else { - log_error(("could not perform changerace::handle()\n")); - } - unused(data); - return 0; -} - -static void -changerace_write(const trigger * t, struct storage * store) -{ - changerace_data * td = (changerace_data*)t->data.v; - write_unit_reference(td->u, store); - write_race_reference(td->race, store); - write_race_reference(td->irace, store); -} - -static int -changerace_read(trigger * t, struct storage * store) -{ - changerace_data * td = (changerace_data*)t->data.v; - read_reference(&td->u, store, read_unit_reference, resolve_unit); - td->race = (const struct race*)read_race_reference(store).v; - td->irace = (const struct race*)read_race_reference(store).v; - return AT_READ_OK; -} - -trigger_type tt_changerace = { - "changerace", - changerace_init, - changerace_free, - changerace_handle, - changerace_write, - changerace_read -}; - -trigger * -trigger_changerace(struct unit * u, const struct race * prace, const struct race * irace) -{ - trigger * t = t_new(&tt_changerace); - changerace_data * td = (changerace_data*)t->data.v; - - assert(u->race==u_irace(u) || "!changerace-triggers cannot stack!"); - td->u = u; - td->race = prace; - td->irace = irace; - return t; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "changerace.h" + +/* kernel includes */ +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* ansi includes */ +#include +#include +#include + + +#include +/*** + ** 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(sizeof(changerace_data), 1); +} + +static void +changerace_free(trigger * t) +{ + free(t->data.v); +} + +static int +changerace_handle(trigger * t, void * data) +{ + /* call an event handler on changerace. + * data.v -> ( variant event, int timer ) + */ + changerace_data * td = (changerace_data*)t->data.v; + if (td->u) { + if (td->race!=NULL) td->u->race = td->race; + if (td->irace!=NULL) td->u->irace = td->irace; + } else { + log_error(("could not perform changerace::handle()\n")); + } + unused(data); + return 0; +} + +static void +changerace_write(const trigger * t, struct storage * store) +{ + changerace_data * td = (changerace_data*)t->data.v; + write_unit_reference(td->u, store); + write_race_reference(td->race, store); + write_race_reference(td->irace, store); +} + +static int +changerace_read(trigger * t, struct storage * store) +{ + changerace_data * td = (changerace_data*)t->data.v; + read_reference(&td->u, store, read_unit_reference, resolve_unit); + td->race = (const struct race*)read_race_reference(store).v; + td->irace = (const struct race*)read_race_reference(store).v; + return AT_READ_OK; +} + +trigger_type tt_changerace = { + "changerace", + changerace_init, + changerace_free, + changerace_handle, + changerace_write, + changerace_read +}; + +trigger * +trigger_changerace(struct unit * u, const struct race * prace, const struct race * irace) +{ + trigger * t = t_new(&tt_changerace); + changerace_data * td = (changerace_data*)t->data.v; + + assert(u->race==u_irace(u) || "!changerace-triggers cannot stack!"); + td->u = u; + td->race = prace; + td->irace = irace; + return t; +} diff --git a/src/triggers/changerace.h b/src/triggers/changerace.h index dc2c55111..91ff8c975 100644 --- a/src/triggers/changerace.h +++ b/src/triggers/changerace.h @@ -1,37 +1,37 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef CHANGERACE_H -#define CHANGERACE_H -#ifdef __cplusplus -extern "C" { -#endif - -/* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; -struct unit; - -extern struct trigger_type tt_changerace; - -extern struct trigger * trigger_changerace(struct unit * u, const struct race *urace, const struct race *irace); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CHANGERACE_H +#define CHANGERACE_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; +struct unit; + +extern struct trigger_type tt_changerace; + +extern struct trigger * trigger_changerace(struct unit * u, const struct race *urace, const struct race *irace); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/clonedied.c b/src/triggers/clonedied.c index 98f156afd..9463bd7ac 100644 --- a/src/triggers/clonedied.c +++ b/src/triggers/clonedied.c @@ -1,95 +1,95 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "clonedied.h" - -/* kernel includes */ -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -/** - clonedied. - - This trigger ist called when a clone of a mage dies. - It simply removes the clone-attribute from the mage. - */ - -static int -clonedied_handle(trigger * t, void * data) -{ - /* destroy the unit */ - unit * u = (unit*)t->data.v; - if (u) { - attrib *a = a_find(u->attribs, &at_clone); - if(a) a_remove(&u->attribs, a); - } else - log_error(("could not perform clonedied::handle()\n")); - unused(data); - return 0; -} - -static void -clonedied_write(const trigger * t, struct storage * store) -{ - unit * u = (unit*)t->data.v; - write_unit_reference(u, store); -} - -static int -clonedied_read(trigger * t, struct storage * store) -{ - int result = read_reference(&t->data.v, store, read_unit_reference, resolve_unit); - if (result==0 && t->data.v==NULL) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -trigger_type tt_clonedied = { - "clonedied", - NULL, - NULL, - clonedied_handle, - clonedied_write, - clonedied_read -}; - -trigger * -trigger_clonedied(unit * u) -{ - trigger * t = t_new(&tt_clonedied); - t->data.v = (void*)u; - return t; -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "clonedied.h" + +/* kernel includes */ +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +/** + clonedied. + + This trigger ist called when a clone of a mage dies. + It simply removes the clone-attribute from the mage. + */ + +static int +clonedied_handle(trigger * t, void * data) +{ + /* destroy the unit */ + unit * u = (unit*)t->data.v; + if (u) { + attrib *a = a_find(u->attribs, &at_clone); + if(a) a_remove(&u->attribs, a); + } else + log_error(("could not perform clonedied::handle()\n")); + unused(data); + return 0; +} + +static void +clonedied_write(const trigger * t, struct storage * store) +{ + unit * u = (unit*)t->data.v; + write_unit_reference(u, store); +} + +static int +clonedied_read(trigger * t, struct storage * store) +{ + int result = read_reference(&t->data.v, store, read_unit_reference, resolve_unit); + if (result==0 && t->data.v==NULL) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +trigger_type tt_clonedied = { + "clonedied", + NULL, + NULL, + clonedied_handle, + clonedied_write, + clonedied_read +}; + +trigger * +trigger_clonedied(unit * u) +{ + trigger * t = t_new(&tt_clonedied); + t->data.v = (void*)u; + return t; +} + diff --git a/src/triggers/clonedied.h b/src/triggers/clonedied.h index 607a1c415..36dbf718f 100644 --- a/src/triggers/clonedied.h +++ b/src/triggers/clonedied.h @@ -1,36 +1,36 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef CLONEDIED_H -#define CLONEDIED_H -#ifdef __cplusplus -extern "C" { -#endif - -struct trigger_type; -struct trigger; - -struct unit; - -extern struct trigger_type tt_clonedied; -extern struct trigger * trigger_clonedied(struct unit * u); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CLONEDIED_H +#define CLONEDIED_H +#ifdef __cplusplus +extern "C" { +#endif + +struct trigger_type; +struct trigger; + +struct unit; + +extern struct trigger_type tt_clonedied; +extern struct trigger * trigger_clonedied(struct unit * u); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/createcurse.c b/src/triggers/createcurse.c index 085b08317..8d0b9a593 100644 --- a/src/triggers/createcurse.c +++ b/src/triggers/createcurse.c @@ -1,157 +1,157 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "createcurse.h" - -/* kernel includes */ -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include - -/* ansi includes */ -#include -#include -#include - - -#include -/*** - ** restore a mage that was turned into a toad - **/ - -typedef struct createcurse_data { - struct unit * mage; - struct unit * target; - const curse_type * type; - double vigour; - int duration; - double effect; - int men; -} createcurse_data; - -static void -createcurse_init(trigger * t) -{ - t->data.v = calloc(sizeof(createcurse_data), 1); -} - -static void -createcurse_free(trigger * t) -{ - free(t->data.v); -} - -static int -createcurse_handle(trigger * t, void * data) -{ - /* call an event handler on createcurse. - * data.v -> ( variant event, int timer ) - */ - createcurse_data * td = (createcurse_data*)t->data.v; - if (td->mage && td->target && td->mage->number && td->target->number) { - create_curse(td->mage, &td->target->attribs, - td->type, td->vigour, td->duration, td->effect, td->men); - } else { - log_error(("could not perform createcurse::handle()\n")); - } - unused(data); - return 0; -} - -static void -createcurse_write(const trigger * t, struct storage * store) -{ - createcurse_data * td = (createcurse_data*)t->data.v; - write_unit_reference(td->mage, store); - write_unit_reference(td->target, store); - store->w_tok(store, td->type->cname); - store->w_flt(store, (float)td->vigour); - store->w_int(store, td->duration); - store->w_flt(store, (float)td->effect); - store->w_int(store, td->men); -} - -static int -createcurse_read(trigger * t, struct storage * store) -{ - createcurse_data * td = (createcurse_data*)t->data.v; - char zText[128]; - - read_reference(&td->mage, store, read_unit_reference, resolve_unit); - read_reference(&td->target, store, read_unit_reference, resolve_unit); - - if (store->versionr_int(store); - id2 = store->r_int(store); - assert(id2==0); - td->vigour = store->r_flt(store); - td->duration = store->r_int(store); - td->effect = store->r_int(store); - td->men = store->r_int(store); - td->type = ct_find(oldcursename(id1)); - } else { - store->r_tok_buf(store, zText, sizeof(zText)); - td->type = ct_find(zText); - td->vigour = store->r_flt(store); - td->duration = store->r_int(store); - if (store->versioneffect = (double)store->r_int(store); - } else { - td->effect = store->r_flt(store); - } - td->men = store->r_int(store); - } - return AT_READ_OK; -} - -trigger_type tt_createcurse = { - "createcurse", - createcurse_init, - createcurse_free, - createcurse_handle, - createcurse_write, - createcurse_read -}; - -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); - createcurse_data * td = (createcurse_data*)t->data.v; - td->mage = mage; - td->target = target; - td->type = ct; - td->vigour = vigour; - td->duration = duration; - td->effect = effect; - td->men = men; - return t; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "createcurse.h" + +/* kernel includes */ +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* ansi includes */ +#include +#include +#include + + +#include +/*** + ** restore a mage that was turned into a toad + **/ + +typedef struct createcurse_data { + struct unit * mage; + struct unit * target; + const curse_type * type; + double vigour; + int duration; + double effect; + int men; +} createcurse_data; + +static void +createcurse_init(trigger * t) +{ + t->data.v = calloc(sizeof(createcurse_data), 1); +} + +static void +createcurse_free(trigger * t) +{ + free(t->data.v); +} + +static int +createcurse_handle(trigger * t, void * data) +{ + /* call an event handler on createcurse. + * data.v -> ( variant event, int timer ) + */ + createcurse_data * td = (createcurse_data*)t->data.v; + if (td->mage && td->target && td->mage->number && td->target->number) { + create_curse(td->mage, &td->target->attribs, + td->type, td->vigour, td->duration, td->effect, td->men); + } else { + log_error(("could not perform createcurse::handle()\n")); + } + unused(data); + return 0; +} + +static void +createcurse_write(const trigger * t, struct storage * store) +{ + createcurse_data * td = (createcurse_data*)t->data.v; + write_unit_reference(td->mage, store); + write_unit_reference(td->target, store); + store->w_tok(store, td->type->cname); + store->w_flt(store, (float)td->vigour); + store->w_int(store, td->duration); + store->w_flt(store, (float)td->effect); + store->w_int(store, td->men); +} + +static int +createcurse_read(trigger * t, struct storage * store) +{ + createcurse_data * td = (createcurse_data*)t->data.v; + char zText[128]; + + read_reference(&td->mage, store, read_unit_reference, resolve_unit); + read_reference(&td->target, store, read_unit_reference, resolve_unit); + + if (store->versionr_int(store); + id2 = store->r_int(store); + assert(id2==0); + td->vigour = store->r_flt(store); + td->duration = store->r_int(store); + td->effect = store->r_int(store); + td->men = store->r_int(store); + td->type = ct_find(oldcursename(id1)); + } else { + store->r_tok_buf(store, zText, sizeof(zText)); + td->type = ct_find(zText); + td->vigour = store->r_flt(store); + td->duration = store->r_int(store); + if (store->versioneffect = (double)store->r_int(store); + } else { + td->effect = store->r_flt(store); + } + td->men = store->r_int(store); + } + return AT_READ_OK; +} + +trigger_type tt_createcurse = { + "createcurse", + createcurse_init, + createcurse_free, + createcurse_handle, + createcurse_write, + createcurse_read +}; + +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); + createcurse_data * td = (createcurse_data*)t->data.v; + td->mage = mage; + td->target = target; + td->type = ct; + td->vigour = vigour; + td->duration = duration; + td->effect = effect; + td->men = men; + return t; +} diff --git a/src/triggers/createcurse.h b/src/triggers/createcurse.h index bc3d2e797..47cc07203 100644 --- a/src/triggers/createcurse.h +++ b/src/triggers/createcurse.h @@ -1,40 +1,40 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef CREATECURSE_H -#define CREATECURSE_H -#ifdef __cplusplus -extern "C" { -#endif - -/* all types we use are defined here to reduce dependencies */ -struct curse_type; -struct trigger_type; -struct trigger; -struct region; -struct faction; -struct unit; - -extern struct trigger_type tt_createcurse; - -extern struct trigger * trigger_createcurse(struct unit * mage, struct unit * target, const struct curse_type * ct, double vigour, int duration, double effect, int men); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CREATECURSE_H +#define CREATECURSE_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct curse_type; +struct trigger_type; +struct trigger; +struct region; +struct faction; +struct unit; + +extern struct trigger_type tt_createcurse; + +extern struct trigger * trigger_createcurse(struct unit * mage, struct unit * target, const struct curse_type * ct, double vigour, int duration, double effect, int men); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/createunit.c b/src/triggers/createunit.c index 48610c9d1..0aacf0da3 100644 --- a/src/triggers/createunit.c +++ b/src/triggers/createunit.c @@ -1,130 +1,130 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "createunit.h" - -/* kernel includes */ -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include - -/* ansi includes */ -#include -#include -#include - - -#include -/*** - ** restore a mage that was turned into a toad - **/ - -typedef struct createunit_data { - struct region * r; - struct faction * f; - const struct race * race; - int number; -} createunit_data; - -static void -createunit_init(trigger * t) -{ - t->data.v = calloc(sizeof(createunit_data), 1); -} - -static void -createunit_free(trigger * t) -{ - free(t->data.v); -} - -static int -createunit_handle(trigger * t, void * data) -{ - /* call an event handler on createunit. - * data.v -> ( variant event, int timer ) - */ - createunit_data * td = (createunit_data*)t->data.v; - if (td->r!=NULL && td->f!=NULL) { - create_unit(td->r, td->f, td->number, td->race, 0, NULL, NULL); - } else { - log_error(("could not perform createunit::handle()\n")); - } - unused(data); - return 0; -} - -static void -createunit_write(const trigger * t, struct storage * store) -{ - createunit_data * td = (createunit_data*)t->data.v; - write_faction_reference(td->f, store); - write_region_reference(td->r, store); - write_race_reference(td->race, store); - store->w_int(store, td->number); -} - -static int -createunit_read(trigger * t, struct storage * store) -{ - createunit_data * td = (createunit_data*)t->data.v; - - int uc = read_reference(&td->f, store, read_faction_reference, resolve_faction); - int rc = read_reference(&td->r, store, read_region_reference, RESOLVE_REGION(store->version)); - td->race = (const struct race*)read_race_reference(store).v; - - if (uc==0 && rc==0) { - if (!td->f || !td->r) return AT_READ_FAIL; - } - td->number = store->r_int(store); - - return AT_READ_OK; -} - -trigger_type tt_createunit = { - "createunit", - createunit_init, - createunit_free, - createunit_handle, - createunit_write, - createunit_read -}; - -trigger * -trigger_createunit(region * r, struct faction * f, const struct race * rc, int number) -{ - trigger * t = t_new(&tt_createunit); - createunit_data * td = (createunit_data*)t->data.v; - td->r = r; - td->f = f; - td->race = rc; - td->number = number; - return t; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "createunit.h" + +/* kernel includes */ +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* ansi includes */ +#include +#include +#include + + +#include +/*** + ** restore a mage that was turned into a toad + **/ + +typedef struct createunit_data { + struct region * r; + struct faction * f; + const struct race * race; + int number; +} createunit_data; + +static void +createunit_init(trigger * t) +{ + t->data.v = calloc(sizeof(createunit_data), 1); +} + +static void +createunit_free(trigger * t) +{ + free(t->data.v); +} + +static int +createunit_handle(trigger * t, void * data) +{ + /* call an event handler on createunit. + * data.v -> ( variant event, int timer ) + */ + createunit_data * td = (createunit_data*)t->data.v; + if (td->r!=NULL && td->f!=NULL) { + create_unit(td->r, td->f, td->number, td->race, 0, NULL, NULL); + } else { + log_error(("could not perform createunit::handle()\n")); + } + unused(data); + return 0; +} + +static void +createunit_write(const trigger * t, struct storage * store) +{ + createunit_data * td = (createunit_data*)t->data.v; + write_faction_reference(td->f, store); + write_region_reference(td->r, store); + write_race_reference(td->race, store); + store->w_int(store, td->number); +} + +static int +createunit_read(trigger * t, struct storage * store) +{ + createunit_data * td = (createunit_data*)t->data.v; + + int uc = read_reference(&td->f, store, read_faction_reference, resolve_faction); + int rc = read_reference(&td->r, store, read_region_reference, RESOLVE_REGION(store->version)); + td->race = (const struct race*)read_race_reference(store).v; + + if (uc==0 && rc==0) { + if (!td->f || !td->r) return AT_READ_FAIL; + } + td->number = store->r_int(store); + + return AT_READ_OK; +} + +trigger_type tt_createunit = { + "createunit", + createunit_init, + createunit_free, + createunit_handle, + createunit_write, + createunit_read +}; + +trigger * +trigger_createunit(region * r, struct faction * f, const struct race * rc, int number) +{ + trigger * t = t_new(&tt_createunit); + createunit_data * td = (createunit_data*)t->data.v; + td->r = r; + td->f = f; + td->race = rc; + td->number = number; + return t; +} diff --git a/src/triggers/createunit.h b/src/triggers/createunit.h index 7dd6894f2..c26a7be6b 100644 --- a/src/triggers/createunit.h +++ b/src/triggers/createunit.h @@ -1,39 +1,39 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef CREATEUNIT_H -#define CREATEUNIT_H -#ifdef __cplusplus -extern "C" { -#endif - -/* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; -struct region; -struct faction; -struct unit; - -extern struct trigger_type tt_createunit; - -extern struct trigger * trigger_createunit(struct region * r, struct faction * f, const struct race * rc, int number); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CREATEUNIT_H +#define CREATEUNIT_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; +struct region; +struct faction; +struct unit; + +extern struct trigger_type tt_createunit; + +extern struct trigger * trigger_createunit(struct region * r, struct faction * f, const struct race * rc, int number); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/gate.c b/src/triggers/gate.c index ef1344495..2de707ad8 100644 --- a/src/triggers/gate.c +++ b/src/triggers/gate.c @@ -1,117 +1,117 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ -#include -#include -#include "gate.h" - -/* kernel includes */ -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include - -/* libc includes */ -#include - -typedef struct gate_data { - struct building * gate; - struct region * target; -} gate_data; - -static int -gate_handle(trigger * t, void * data) -{ - /* call an event handler on gate. - * data.v -> ( variant event, int timer ) - */ - gate_data * gd = (gate_data*)t->data.v; - struct building * b = gd->gate; - struct region * r = gd->target; - - if (b && b->region && r) { - unit ** up = &b->region->units; - while (*up) { - unit * u = *up; - if (u->building==b) move_unit(u, r, NULL); - if (*up==u) up = &u->next; - } - } else { - log_error(("could not perform gate::handle()\n")); - return -1; - } - unused(data); - return 0; -} - -static void -gate_write(const trigger * t, struct storage * store) -{ - gate_data * gd = (gate_data*)t->data.v; - building * b = gd->gate; - region * r = gd->target; - - write_building_reference(b, store); - write_region_reference(r, store); -} - -static int -gate_read(trigger * t, struct storage * store) -{ - gate_data * gd = (gate_data*)t->data.v; - - int bc = read_reference(&gd->gate, store, read_building_reference, resolve_building); - int rc = read_reference(&gd->target, store, read_region_reference, RESOLVE_REGION(store->version)); - - if (bc==0 && rc==0) { - if (!gd->gate || !gd->target) return AT_READ_FAIL; - } - return AT_READ_OK; -} - -static void -gate_init(trigger * t) -{ - t->data.v = calloc(sizeof(gate_data), 1); -} - -static void -gate_done(trigger * t) -{ - free(t->data.v); -} - - -struct trigger_type tt_gate = { - "gate", - gate_init, - gate_done, - gate_handle, - gate_write, - gate_read -}; - -trigger * -trigger_gate(building * b, region * target) -{ - trigger * t = t_new(&tt_gate); - gate_data * td = (gate_data*)t->data.v; - td->gate = b; - td->target = target; - return t; -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#include +#include +#include "gate.h" + +/* kernel includes */ +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include + +/* libc includes */ +#include + +typedef struct gate_data { + struct building * gate; + struct region * target; +} gate_data; + +static int +gate_handle(trigger * t, void * data) +{ + /* call an event handler on gate. + * data.v -> ( variant event, int timer ) + */ + gate_data * gd = (gate_data*)t->data.v; + struct building * b = gd->gate; + struct region * r = gd->target; + + if (b && b->region && r) { + unit ** up = &b->region->units; + while (*up) { + unit * u = *up; + if (u->building==b) move_unit(u, r, NULL); + if (*up==u) up = &u->next; + } + } else { + log_error(("could not perform gate::handle()\n")); + return -1; + } + unused(data); + return 0; +} + +static void +gate_write(const trigger * t, struct storage * store) +{ + gate_data * gd = (gate_data*)t->data.v; + building * b = gd->gate; + region * r = gd->target; + + write_building_reference(b, store); + write_region_reference(r, store); +} + +static int +gate_read(trigger * t, struct storage * store) +{ + gate_data * gd = (gate_data*)t->data.v; + + int bc = read_reference(&gd->gate, store, read_building_reference, resolve_building); + int rc = read_reference(&gd->target, store, read_region_reference, RESOLVE_REGION(store->version)); + + if (bc==0 && rc==0) { + if (!gd->gate || !gd->target) return AT_READ_FAIL; + } + return AT_READ_OK; +} + +static void +gate_init(trigger * t) +{ + t->data.v = calloc(sizeof(gate_data), 1); +} + +static void +gate_done(trigger * t) +{ + free(t->data.v); +} + + +struct trigger_type tt_gate = { + "gate", + gate_init, + gate_done, + gate_handle, + gate_write, + gate_read +}; + +trigger * +trigger_gate(building * b, region * target) +{ + trigger * t = t_new(&tt_gate); + gate_data * td = (gate_data*)t->data.v; + td->gate = b; + td->target = target; + return t; +} diff --git a/src/triggers/gate.h b/src/triggers/gate.h index 677118330..5ed82d778 100644 --- a/src/triggers/gate.h +++ b/src/triggers/gate.h @@ -1,32 +1,32 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef GATE_H -#define GATE_H -#ifdef __cplusplus -extern "C" { -#endif - -/* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; -struct region; -struct building; - -extern struct trigger_type tt_gate; - -extern struct trigger * trigger_gate(struct building * b, struct region * r); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef GATE_H +#define GATE_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; +struct region; +struct building; + +extern struct trigger_type tt_gate; + +extern struct trigger * trigger_gate(struct building * b, struct region * r); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/giveitem.c b/src/triggers/giveitem.c index 53a06f24b..e5709f16a 100644 --- a/src/triggers/giveitem.c +++ b/src/triggers/giveitem.c @@ -1,124 +1,124 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "giveitem.h" - -/* kernel includes */ -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include - -/* ansi includes */ -#include -#include -#include - -/*** - ** give an item to someone - **/ - -typedef struct giveitem_data { - struct unit * u; - const struct item_type * itype; - int number; -} giveitem_data; - -static void -giveitem_init(trigger * t) -{ - t->data.v = calloc(sizeof(giveitem_data), 1); -} - -static void -giveitem_free(trigger * t) -{ - free(t->data.v); -} - -static int -giveitem_handle(trigger * t, void * data) -{ - /* call an event handler on giveitem. - * data.v -> ( variant event, int timer ) - */ - giveitem_data * td = (giveitem_data*)t->data.v; - if (td->u && td->u->number) { - i_change(&td->u->items, td->itype, td->number); - } else { - log_error(("could not perform giveitem::handle()\n")); - } - unused(data); - return 0; -} - -static void -giveitem_write(const trigger * t, struct storage * store) -{ - giveitem_data * td = (giveitem_data*)t->data.v; - write_unit_reference(td->u, store); - store->w_int(store, td->number); - store->w_tok(store, td->itype->rtype->_name[0]); -} - -static int -giveitem_read(trigger * t, struct storage * store) -{ - giveitem_data * td = (giveitem_data*)t->data.v; - char zText[128]; - - int result = read_reference(&td->u, store, read_unit_reference, resolve_unit); - - td->number = store->r_int(store); - store->r_tok_buf(store, zText, sizeof(zText)); - td->itype = it_find(zText); - assert(td->itype); - - if (result==0 && td->u==NULL) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -trigger_type tt_giveitem = { - "giveitem", - giveitem_init, - giveitem_free, - giveitem_handle, - giveitem_write, - giveitem_read -}; - -trigger * -trigger_giveitem(unit * u, const item_type * itype, int number) -{ - trigger * t = t_new(&tt_giveitem); - giveitem_data * td = (giveitem_data*)t->data.v; - td->number = number; - td->u = u; - td->itype = itype; - return t; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "giveitem.h" + +/* kernel includes */ +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* ansi includes */ +#include +#include +#include + +/*** + ** give an item to someone + **/ + +typedef struct giveitem_data { + struct unit * u; + const struct item_type * itype; + int number; +} giveitem_data; + +static void +giveitem_init(trigger * t) +{ + t->data.v = calloc(sizeof(giveitem_data), 1); +} + +static void +giveitem_free(trigger * t) +{ + free(t->data.v); +} + +static int +giveitem_handle(trigger * t, void * data) +{ + /* call an event handler on giveitem. + * data.v -> ( variant event, int timer ) + */ + giveitem_data * td = (giveitem_data*)t->data.v; + if (td->u && td->u->number) { + i_change(&td->u->items, td->itype, td->number); + } else { + log_error(("could not perform giveitem::handle()\n")); + } + unused(data); + return 0; +} + +static void +giveitem_write(const trigger * t, struct storage * store) +{ + giveitem_data * td = (giveitem_data*)t->data.v; + write_unit_reference(td->u, store); + store->w_int(store, td->number); + store->w_tok(store, td->itype->rtype->_name[0]); +} + +static int +giveitem_read(trigger * t, struct storage * store) +{ + giveitem_data * td = (giveitem_data*)t->data.v; + char zText[128]; + + int result = read_reference(&td->u, store, read_unit_reference, resolve_unit); + + td->number = store->r_int(store); + store->r_tok_buf(store, zText, sizeof(zText)); + td->itype = it_find(zText); + assert(td->itype); + + if (result==0 && td->u==NULL) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +trigger_type tt_giveitem = { + "giveitem", + giveitem_init, + giveitem_free, + giveitem_handle, + giveitem_write, + giveitem_read +}; + +trigger * +trigger_giveitem(unit * u, const item_type * itype, int number) +{ + trigger * t = t_new(&tt_giveitem); + giveitem_data * td = (giveitem_data*)t->data.v; + td->number = number; + td->u = u; + td->itype = itype; + return t; +} diff --git a/src/triggers/giveitem.h b/src/triggers/giveitem.h index 048b4a5cd..a9c021a86 100644 --- a/src/triggers/giveitem.h +++ b/src/triggers/giveitem.h @@ -1,38 +1,38 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef GIVEITEM_H -#define GIVEITEM_H -#ifdef __cplusplus -extern "C" { -#endif - -/* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; -struct unit; -struct item_type; - -extern struct trigger_type tt_giveitem; - -extern struct trigger * trigger_giveitem(struct unit * mage, const struct item_type * itype, int number); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef GIVEITEM_H +#define GIVEITEM_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; +struct unit; +struct item_type; + +extern struct trigger_type tt_giveitem; + +extern struct trigger * trigger_giveitem(struct unit * mage, const struct item_type * itype, int number); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/killunit.c b/src/triggers/killunit.c index b1d5a4064..9ac360bdf 100644 --- a/src/triggers/killunit.c +++ b/src/triggers/killunit.c @@ -1,87 +1,87 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "killunit.h" - -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include - -#include -#include -/*** - ** killunit - **/ - -static int -killunit_handle(trigger * t, void * data) -{ - /* call an event handler on killunit. - * data.v -> ( variant event, int timer ) - */ - unit * u = (unit*)t->data.v; - if (u) { - /* we can't remove_unit() here, because that's what's calling us. */ - set_number(u, 0); - } - unused(data); - return 0; -} - -static void -killunit_write(const trigger * t, struct storage * store) -{ - unit * u = (unit*)t->data.v; - write_unit_reference(u, store); -} - -static int -killunit_read(trigger * t, struct storage * store) -{ - int result = read_reference(&t->data.v, store, read_unit_reference, resolve_unit); - if (result==0 && t->data.v==NULL) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -trigger_type tt_killunit = { - "killunit", - NULL, - NULL, - killunit_handle, - killunit_write, - killunit_read -}; - -trigger * -trigger_killunit(unit * u) -{ - trigger * t = t_new(&tt_killunit); - t->data.v = (void*)u; - return t; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "killunit.h" + +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +#include +#include +/*** + ** killunit + **/ + +static int +killunit_handle(trigger * t, void * data) +{ + /* call an event handler on killunit. + * data.v -> ( variant event, int timer ) + */ + unit * u = (unit*)t->data.v; + if (u) { + /* we can't remove_unit() here, because that's what's calling us. */ + set_number(u, 0); + } + unused(data); + return 0; +} + +static void +killunit_write(const trigger * t, struct storage * store) +{ + unit * u = (unit*)t->data.v; + write_unit_reference(u, store); +} + +static int +killunit_read(trigger * t, struct storage * store) +{ + int result = read_reference(&t->data.v, store, read_unit_reference, resolve_unit); + if (result==0 && t->data.v==NULL) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +trigger_type tt_killunit = { + "killunit", + NULL, + NULL, + killunit_handle, + killunit_write, + killunit_read +}; + +trigger * +trigger_killunit(unit * u) +{ + trigger * t = t_new(&tt_killunit); + t->data.v = (void*)u; + return t; +} diff --git a/src/triggers/killunit.h b/src/triggers/killunit.h index f9aa652fa..9f42fd4cf 100644 --- a/src/triggers/killunit.h +++ b/src/triggers/killunit.h @@ -1,36 +1,36 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef KILLUNIT_H -#define KILLUNIT_H -#ifdef __cplusplus -extern "C" { -#endif - -struct trigger_type; -struct trigger; - -struct unit; - -extern struct trigger_type tt_killunit; -extern struct trigger * trigger_killunit(struct unit * u); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef KILLUNIT_H +#define KILLUNIT_H +#ifdef __cplusplus +extern "C" { +#endif + +struct trigger_type; +struct trigger; + +struct unit; + +extern struct trigger_type tt_killunit; +extern struct trigger * trigger_killunit(struct unit * u); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/removecurse.c b/src/triggers/removecurse.c index 0377974cf..994aa2cdd 100644 --- a/src/triggers/removecurse.c +++ b/src/triggers/removecurse.c @@ -1,114 +1,114 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "removecurse.h" - -/* kernel includes */ -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include - -/* ansi includes */ -#include -#include -#include - - -#include - -typedef struct removecurse_data { - curse * curse; - unit * target; -} removecurse_data; - -static void -removecurse_init(trigger * t) -{ - t->data.v = calloc(sizeof(removecurse_data), 1); -} - -static void -removecurse_free(trigger * t) -{ - free(t->data.v); -} - -static int -removecurse_handle(trigger * t, void * data) -{ - /* call an event handler on removecurse. - * data.v -> ( variant event, int timer ) - */ - removecurse_data * td = (removecurse_data*)t->data.v; - if (td->curse && td->target) { - attrib * a = a_select(td->target->attribs, td->curse, cmp_curse); - if (a) { - a_remove(&td->target->attribs, a); - } - else log_error(("could not perform removecurse::handle()\n")); - } - unused(data); - return 0; -} - -static void -removecurse_write(const trigger * t, struct storage * store) -{ - removecurse_data * td = (removecurse_data*)t->data.v; - store->w_tok(store, td->target?itoa36(td->target->no):0); - store->w_int(store, td->curse?td->curse->no:0); -} - -static int -removecurse_read(trigger * t, struct storage * store) -{ - removecurse_data * td = (removecurse_data*)t->data.v; - - read_reference(&td->target, store, read_unit_reference, resolve_unit); - read_reference(&td->curse, store, read_int, resolve_curse); - - return AT_READ_OK; -} - -trigger_type tt_removecurse = { - "removecurse", - removecurse_init, - removecurse_free, - removecurse_handle, - removecurse_write, - removecurse_read -}; - -trigger * -trigger_removecurse(curse * c, unit * target) -{ - trigger * t = t_new(&tt_removecurse); - removecurse_data * td = (removecurse_data*)t->data.v; - td->curse = c; - td->target = target; - return t; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "removecurse.h" + +/* kernel includes */ +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* ansi includes */ +#include +#include +#include + + +#include + +typedef struct removecurse_data { + curse * curse; + unit * target; +} removecurse_data; + +static void +removecurse_init(trigger * t) +{ + t->data.v = calloc(sizeof(removecurse_data), 1); +} + +static void +removecurse_free(trigger * t) +{ + free(t->data.v); +} + +static int +removecurse_handle(trigger * t, void * data) +{ + /* call an event handler on removecurse. + * data.v -> ( variant event, int timer ) + */ + removecurse_data * td = (removecurse_data*)t->data.v; + if (td->curse && td->target) { + attrib * a = a_select(td->target->attribs, td->curse, cmp_curse); + if (a) { + a_remove(&td->target->attribs, a); + } + else log_error(("could not perform removecurse::handle()\n")); + } + unused(data); + return 0; +} + +static void +removecurse_write(const trigger * t, struct storage * store) +{ + removecurse_data * td = (removecurse_data*)t->data.v; + store->w_tok(store, td->target?itoa36(td->target->no):0); + store->w_int(store, td->curse?td->curse->no:0); +} + +static int +removecurse_read(trigger * t, struct storage * store) +{ + removecurse_data * td = (removecurse_data*)t->data.v; + + read_reference(&td->target, store, read_unit_reference, resolve_unit); + read_reference(&td->curse, store, read_int, resolve_curse); + + return AT_READ_OK; +} + +trigger_type tt_removecurse = { + "removecurse", + removecurse_init, + removecurse_free, + removecurse_handle, + removecurse_write, + removecurse_read +}; + +trigger * +trigger_removecurse(curse * c, unit * target) +{ + trigger * t = t_new(&tt_removecurse); + removecurse_data * td = (removecurse_data*)t->data.v; + td->curse = c; + td->target = target; + return t; +} diff --git a/src/triggers/removecurse.h b/src/triggers/removecurse.h index 0a89a5e97..7615b87eb 100644 --- a/src/triggers/removecurse.h +++ b/src/triggers/removecurse.h @@ -1,39 +1,39 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef REMOVECURSE_H -#define REMOVECURSE_H -#ifdef __cplusplus -extern "C" { -#endif - -/* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; - -struct unit; -struct curse; - -extern struct trigger_type tt_removecurse; - -extern struct trigger * trigger_removecurse(struct curse * c, struct unit * target); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef REMOVECURSE_H +#define REMOVECURSE_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; + +struct unit; +struct curse; + +extern struct trigger_type tt_removecurse; + +extern struct trigger * trigger_removecurse(struct curse * c, struct unit * target); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/shock.c b/src/triggers/shock.c index 4cb361478..06f15f47d 100644 --- a/src/triggers/shock.c +++ b/src/triggers/shock.c @@ -1,148 +1,148 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "shock.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -/*** - ** shock - **/ - -/* ------------------------------------------------------------- */ -/* do_shock - Schockt die Einheit, z.B. bei Verlust eines */ -/* Vertrauten. */ -/* ------------------------------------------------------------- */ - -static void -do_shock(unit *u, const char *reason) -{ - int i; - - if (u->number > 0) { - /* HP - Verlust */ - u->hp = (unit_max_hp(u) * u->number)/10; - u->hp = MAX(1, u->hp); - } - - /* Aura - Verlust */ - if (is_mage(u)) { - set_spellpoints(u, max_spellpoints(u->region,u)/10); - } - - /* Evt. Talenttageverlust */ - for (i=0;i!=u->skill_size;++i) if (rng_int()%5==0) { - skill * sv = u->skills+i; - int weeks = (sv->level * sv->level - sv->level) / 2; - int change = (weeks+9) / 10; - reduce_skill(u, sv, change); - } - - /* Dies ist ein Hack, um das skillmod und familiar-Attribut beim Mage - * zu löschen wenn der Familiar getötet wird. Da sollten wir über eine - * saubere Implementation nachdenken. */ - - if (strcmp(reason, "trigger")==0) { - remove_familiar(u); - } - if (u->faction!=NULL) { - ADDMSG(&u->faction->msgs, msg_message("shock", - "mage reason", u, strdup(reason))); - } -} - -static int -shock_handle(trigger * t, void * data) -{ - /* destroy the unit */ - unit * u = (unit*)t->data.v; - if (u && u->number) { - do_shock(u, "trigger"); - } - unused(data); - return 0; -} - -static void -shock_write(const trigger * t, struct storage * store) -{ - unit * u = (unit*)t->data.v; - trigger * next = t->next; - while (next) { - /* make sure it is unique! */ - if (next->type==t->type && next->data.v==t->data.v) break; - next=next->next; - } - if (next && u) { - log_error(("more than one shock-attribut for %s on a unit. FIXED.\n", - unitid(u))); - write_unit_reference(NULL, store); - } else { - write_unit_reference(u, store); - } -} - -static int -shock_read(trigger * t, struct storage * store) -{ - int result = read_reference(&t->data.v, store, read_unit_reference, resolve_unit); - if (result==0 && t->data.v==NULL) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -trigger_type tt_shock = { - "shock", - NULL, - NULL, - shock_handle, - shock_write, - shock_read -}; - -trigger * -trigger_shock(unit * u) -{ - trigger * t = t_new(&tt_shock); - t->data.v = (void*)u; - return t; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "shock.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +/*** + ** shock + **/ + +/* ------------------------------------------------------------- */ +/* do_shock - Schockt die Einheit, z.B. bei Verlust eines */ +/* Vertrauten. */ +/* ------------------------------------------------------------- */ + +static void +do_shock(unit *u, const char *reason) +{ + int i; + + if (u->number > 0) { + /* HP - Verlust */ + u->hp = (unit_max_hp(u) * u->number)/10; + u->hp = MAX(1, u->hp); + } + + /* Aura - Verlust */ + if (is_mage(u)) { + set_spellpoints(u, max_spellpoints(u->region,u)/10); + } + + /* Evt. Talenttageverlust */ + for (i=0;i!=u->skill_size;++i) if (rng_int()%5==0) { + skill * sv = u->skills+i; + int weeks = (sv->level * sv->level - sv->level) / 2; + int change = (weeks+9) / 10; + reduce_skill(u, sv, change); + } + + /* Dies ist ein Hack, um das skillmod und familiar-Attribut beim Mage + * zu löschen wenn der Familiar getötet wird. Da sollten wir über eine + * saubere Implementation nachdenken. */ + + if (strcmp(reason, "trigger")==0) { + remove_familiar(u); + } + if (u->faction!=NULL) { + ADDMSG(&u->faction->msgs, msg_message("shock", + "mage reason", u, strdup(reason))); + } +} + +static int +shock_handle(trigger * t, void * data) +{ + /* destroy the unit */ + unit * u = (unit*)t->data.v; + if (u && u->number) { + do_shock(u, "trigger"); + } + unused(data); + return 0; +} + +static void +shock_write(const trigger * t, struct storage * store) +{ + unit * u = (unit*)t->data.v; + trigger * next = t->next; + while (next) { + /* make sure it is unique! */ + if (next->type==t->type && next->data.v==t->data.v) break; + next=next->next; + } + if (next && u) { + log_error(("more than one shock-attribut for %s on a unit. FIXED.\n", + unitid(u))); + write_unit_reference(NULL, store); + } else { + write_unit_reference(u, store); + } +} + +static int +shock_read(trigger * t, struct storage * store) +{ + int result = read_reference(&t->data.v, store, read_unit_reference, resolve_unit); + if (result==0 && t->data.v==NULL) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +trigger_type tt_shock = { + "shock", + NULL, + NULL, + shock_handle, + shock_write, + shock_read +}; + +trigger * +trigger_shock(unit * u) +{ + trigger * t = t_new(&tt_shock); + t->data.v = (void*)u; + return t; +} diff --git a/src/triggers/shock.h b/src/triggers/shock.h index 07e59cb30..382b65eb9 100644 --- a/src/triggers/shock.h +++ b/src/triggers/shock.h @@ -1,36 +1,36 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_TRG_SHOCK_H -#define H_TRG_SHOCK_H -#ifdef __cplusplus -extern "C" { -#endif - -struct trigger_type; -struct trigger; - -struct unit; - -extern struct trigger_type tt_shock; -extern struct trigger * trigger_shock(struct unit * u); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_TRG_SHOCK_H +#define H_TRG_SHOCK_H +#ifdef __cplusplus +extern "C" { +#endif + +struct trigger_type; +struct trigger; + +struct unit; + +extern struct trigger_type tt_shock; +extern struct trigger * trigger_shock(struct unit * u); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/timeout.c b/src/triggers/timeout.c index e0770ed39..2e0157508 100644 --- a/src/triggers/timeout.c +++ b/src/triggers/timeout.c @@ -1,113 +1,113 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "timeout.h" - -/* util includes */ -#include -#include -#include -#include - -#include -#include -/*** - ** timeout - **/ - -typedef struct timeout_data { - trigger * triggers; - int timer; - variant trigger_data; -} timeout_data; - -static void -timeout_init(trigger * t) -{ - t->data.v = calloc(sizeof(timeout_data), 1); -} - -static void -timeout_free(trigger * t) -{ - timeout_data * td = (timeout_data*)t->data.v; - free_triggers(td->triggers); - free(t->data.v); -} - -static int -timeout_handle(trigger * t, void * data) -{ - /* call an event handler on timeout. - * data.v -> ( variant event, int timer ) - */ - timeout_data * td = (timeout_data*)t->data.v; - if (--td->timer==0) { - handle_triggers(&td->triggers, NULL); - return -1; - } - unused(data); - return 0; -} - -static void -timeout_write(const trigger * t, struct storage * store) -{ - timeout_data * td = (timeout_data*)t->data.v; - store->w_int(store, td->timer); - write_triggers(store, td->triggers); -} - -static int -timeout_read(trigger * t, struct storage * store) -{ - timeout_data * td = (timeout_data*)t->data.v; - td->timer = store->r_int(store); - read_triggers(store, &td->triggers); - if (td->timer>20) { - trigger * tr = td->triggers; - log_warning(("there is a timeout lasting for another %d turns\n", td->timer)); - while (tr) { - log_warning((" timeout triggers: %s\n", tr->type->name)); - tr = tr->next; - } - } - if (td->triggers!=NULL && td->timer>0) return AT_READ_OK; - return AT_READ_FAIL; -} - -trigger_type tt_timeout = { - "timeout", - timeout_init, - timeout_free, - timeout_handle, - timeout_write, - timeout_read -}; - -trigger * -trigger_timeout(int time, trigger * callbacks) -{ - trigger * t = t_new(&tt_timeout); - timeout_data * td = (timeout_data*)t->data.v; - td->triggers = callbacks; - td->timer = time; - return t; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "timeout.h" + +/* util includes */ +#include +#include +#include +#include + +#include +#include +/*** + ** timeout + **/ + +typedef struct timeout_data { + trigger * triggers; + int timer; + variant trigger_data; +} timeout_data; + +static void +timeout_init(trigger * t) +{ + t->data.v = calloc(sizeof(timeout_data), 1); +} + +static void +timeout_free(trigger * t) +{ + timeout_data * td = (timeout_data*)t->data.v; + free_triggers(td->triggers); + free(t->data.v); +} + +static int +timeout_handle(trigger * t, void * data) +{ + /* call an event handler on timeout. + * data.v -> ( variant event, int timer ) + */ + timeout_data * td = (timeout_data*)t->data.v; + if (--td->timer==0) { + handle_triggers(&td->triggers, NULL); + return -1; + } + unused(data); + return 0; +} + +static void +timeout_write(const trigger * t, struct storage * store) +{ + timeout_data * td = (timeout_data*)t->data.v; + store->w_int(store, td->timer); + write_triggers(store, td->triggers); +} + +static int +timeout_read(trigger * t, struct storage * store) +{ + timeout_data * td = (timeout_data*)t->data.v; + td->timer = store->r_int(store); + read_triggers(store, &td->triggers); + if (td->timer>20) { + trigger * tr = td->triggers; + log_warning(("there is a timeout lasting for another %d turns\n", td->timer)); + while (tr) { + log_warning((" timeout triggers: %s\n", tr->type->name)); + tr = tr->next; + } + } + if (td->triggers!=NULL && td->timer>0) return AT_READ_OK; + return AT_READ_FAIL; +} + +trigger_type tt_timeout = { + "timeout", + timeout_init, + timeout_free, + timeout_handle, + timeout_write, + timeout_read +}; + +trigger * +trigger_timeout(int time, trigger * callbacks) +{ + trigger * t = t_new(&tt_timeout); + timeout_data * td = (timeout_data*)t->data.v; + td->triggers = callbacks; + td->timer = time; + return t; +} diff --git a/src/triggers/timeout.h b/src/triggers/timeout.h index 3f9f122ef..e62bef26e 100644 --- a/src/triggers/timeout.h +++ b/src/triggers/timeout.h @@ -1,35 +1,35 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_TRG_TIMEOUT_H -#define H_TRG_TIMEOUT_H -#ifdef __cplusplus -extern "C" { -#endif - -struct trigger_type; -struct trigger; - -extern struct trigger_type tt_timeout; - -extern struct trigger * trigger_timeout(int time, struct trigger * callbacks); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_TRG_TIMEOUT_H +#define H_TRG_TIMEOUT_H +#ifdef __cplusplus +extern "C" { +#endif + +struct trigger_type; +struct trigger; + +extern struct trigger_type tt_timeout; + +extern struct trigger * trigger_timeout(int time, struct trigger * callbacks); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/triggers.c b/src/triggers/triggers.c index 7df6cffc1..4d974f975 100644 --- a/src/triggers/triggers.c +++ b/src/triggers/triggers.c @@ -1,60 +1,60 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include - -/* triggers includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include - -/* libc includes */ -#include - -void -register_triggers(void) -{ - if (verbosity>=2) printf("- registering triggers\n"); - tt_register(&tt_changefaction); - tt_register(&tt_changerace); - tt_register(&tt_createcurse); - tt_register(&tt_createunit); - tt_register(&tt_gate); - tt_register(&tt_unguard); - tt_register(&tt_giveitem); - tt_register(&tt_killunit); - tt_register(&tt_removecurse); - tt_register(&tt_shock); - tt_register(&tt_unitmessage); - tt_register(&tt_timeout); - tt_register(&tt_clonedied); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include + +/* triggers includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include + +/* libc includes */ +#include + +void +register_triggers(void) +{ + if (verbosity>=2) printf("- registering triggers\n"); + tt_register(&tt_changefaction); + tt_register(&tt_changerace); + tt_register(&tt_createcurse); + tt_register(&tt_createunit); + tt_register(&tt_gate); + tt_register(&tt_unguard); + tt_register(&tt_giveitem); + tt_register(&tt_killunit); + tt_register(&tt_removecurse); + tt_register(&tt_shock); + tt_register(&tt_unitmessage); + tt_register(&tt_timeout); + tt_register(&tt_clonedied); +} diff --git a/src/triggers/triggers.h b/src/triggers/triggers.h index def5f4072..bb6f81d30 100644 --- a/src/triggers/triggers.h +++ b/src/triggers/triggers.h @@ -1,30 +1,30 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_TRG_TRIGGERS -#define H_TRG_TRIGGERS -#ifdef __cplusplus -extern "C" { -#endif - -void register_triggers(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_TRG_TRIGGERS +#define H_TRG_TRIGGERS +#ifdef __cplusplus +extern "C" { +#endif + +void register_triggers(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/unguard.c b/src/triggers/unguard.c index 1c4cb42ea..079d93218 100644 --- a/src/triggers/unguard.c +++ b/src/triggers/unguard.c @@ -1,77 +1,77 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ -#include -#include -#include "unguard.h" - -/* kernel includes */ -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include - -/* libc includes */ -#include - -static int -unguard_handle(trigger * t, void * data) -{ - building * b = (building*)t->data.v; - - if (b) { - fset(b, BLD_UNGUARDED); - } else { - log_error(("could not perform unguard::handle()\n")); - return -1; - } - unused(data); - return 0; -} - -static void -unguard_write(const trigger * t, struct storage * store) -{ - write_building_reference((building*)t->data.v, store); -} - -static int -unguard_read(trigger * t, struct storage * store) -{ - int rb = read_reference(&t->data.v, store, read_building_reference, resolve_building); - if (rb==0 && !t->data.v) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -struct trigger_type tt_unguard = { - "building", - NULL, - NULL, - unguard_handle, - unguard_write, - unguard_read -}; - -trigger * -trigger_unguard(building * b) -{ - trigger * t = t_new(&tt_unguard); - t->data.v = (void*)b; - return t; -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#include +#include +#include "unguard.h" + +/* kernel includes */ +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include + +/* libc includes */ +#include + +static int +unguard_handle(trigger * t, void * data) +{ + building * b = (building*)t->data.v; + + if (b) { + fset(b, BLD_UNGUARDED); + } else { + log_error(("could not perform unguard::handle()\n")); + return -1; + } + unused(data); + return 0; +} + +static void +unguard_write(const trigger * t, struct storage * store) +{ + write_building_reference((building*)t->data.v, store); +} + +static int +unguard_read(trigger * t, struct storage * store) +{ + int rb = read_reference(&t->data.v, store, read_building_reference, resolve_building); + if (rb==0 && !t->data.v) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +struct trigger_type tt_unguard = { + "building", + NULL, + NULL, + unguard_handle, + unguard_write, + unguard_read +}; + +trigger * +trigger_unguard(building * b) +{ + trigger * t = t_new(&tt_unguard); + t->data.v = (void*)b; + return t; +} diff --git a/src/triggers/unguard.h b/src/triggers/unguard.h index 7748e5a92..a5ad8c3d7 100644 --- a/src/triggers/unguard.h +++ b/src/triggers/unguard.h @@ -1,32 +1,32 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef UNGUARD_H -#define UNGUARD_H -#ifdef __cplusplus -extern "C" { -#endif - -/* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; -struct region; -struct building; - -extern struct trigger_type tt_unguard; - -extern struct trigger * trigger_unguard(struct building * b); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef UNGUARD_H +#define UNGUARD_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; +struct region; +struct building; + +extern struct trigger_type tt_unguard; + +extern struct trigger * trigger_unguard(struct building * b); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/unitmessage.c b/src/triggers/unitmessage.c index f1d7d7dbf..ca7b0d7c2 100644 --- a/src/triggers/unitmessage.c +++ b/src/triggers/unitmessage.c @@ -1,123 +1,123 @@ -/* vi: set ts=2: -+-------------------+ Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -+-------------------+ -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "unitmessage.h" - -/* kernel includes */ -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* ansi includes */ -#include -#include -#include -#include - -/*** -** give an item to someone -**/ - -typedef struct unitmessage_data { - struct unit * target; - char * string; - int type; - int level; -} unitmessage_data; - -static void -unitmessage_init(trigger * t) -{ - t->data.v = calloc(sizeof(unitmessage_data), 1); -} - -static void -unitmessage_free(trigger * t) -{ - unitmessage_data * sd = (unitmessage_data*)t->data.v; - free(sd->string); - free(t->data.v); -} - -static int -unitmessage_handle(trigger * t, void * data) -{ - /* call an event handler on unitmessage. - * data.v -> ( variant event, int timer ) - */ - unitmessage_data * td = (unitmessage_data*)t->data.v; - if (td->target && td->target->no) { - struct faction * f = td->target->faction; - addmessage(td->target->region, f, LOC(f->locale, td->string), td->type, td->level); - } - unused(data); - return 0; -} - -static void -unitmessage_write(const trigger * t, struct storage * store) -{ - unitmessage_data * td = (unitmessage_data*)t->data.v; - write_unit_reference(td->target, store); - store->w_tok(store, td->string); - store->w_int(store, td->type); - store->w_int(store, td->level); -} - -static int -unitmessage_read(trigger * t, struct storage * store) -{ - unitmessage_data * td = (unitmessage_data*)t->data.v; - char zText[256]; - - int result = read_reference(&td->target, store, read_unit_reference, resolve_unit); - - td->string = store->r_tok(store); - td->type = store->r_int(store); - td->level = store->r_int(store); - td->string = strdup(zText); - - if (result==0 && td->target==NULL) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -trigger_type tt_unitmessage = { - "unitmessage", - unitmessage_init, - unitmessage_free, - unitmessage_handle, - unitmessage_write, - unitmessage_read -}; - -trigger * -trigger_unitmessage(unit * target, const char * string, int type, int level) -{ - trigger * t = t_new(&tt_unitmessage); - unitmessage_data * td = (unitmessage_data*)t->data.v; - td->target = target; - td->string = strdup(string); - td->type = type; - td->level = level; - return t; -} +/* vi: set ts=2: ++-------------------+ Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel ++-------------------+ +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "unitmessage.h" + +/* kernel includes */ +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* ansi includes */ +#include +#include +#include +#include + +/*** +** give an item to someone +**/ + +typedef struct unitmessage_data { + struct unit * target; + char * string; + int type; + int level; +} unitmessage_data; + +static void +unitmessage_init(trigger * t) +{ + t->data.v = calloc(sizeof(unitmessage_data), 1); +} + +static void +unitmessage_free(trigger * t) +{ + unitmessage_data * sd = (unitmessage_data*)t->data.v; + free(sd->string); + free(t->data.v); +} + +static int +unitmessage_handle(trigger * t, void * data) +{ + /* call an event handler on unitmessage. + * data.v -> ( variant event, int timer ) + */ + unitmessage_data * td = (unitmessage_data*)t->data.v; + if (td->target && td->target->no) { + struct faction * f = td->target->faction; + addmessage(td->target->region, f, LOC(f->locale, td->string), td->type, td->level); + } + unused(data); + return 0; +} + +static void +unitmessage_write(const trigger * t, struct storage * store) +{ + unitmessage_data * td = (unitmessage_data*)t->data.v; + write_unit_reference(td->target, store); + store->w_tok(store, td->string); + store->w_int(store, td->type); + store->w_int(store, td->level); +} + +static int +unitmessage_read(trigger * t, struct storage * store) +{ + unitmessage_data * td = (unitmessage_data*)t->data.v; + char zText[256]; + + int result = read_reference(&td->target, store, read_unit_reference, resolve_unit); + + td->string = store->r_tok(store); + td->type = store->r_int(store); + td->level = store->r_int(store); + td->string = strdup(zText); + + if (result==0 && td->target==NULL) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +trigger_type tt_unitmessage = { + "unitmessage", + unitmessage_init, + unitmessage_free, + unitmessage_handle, + unitmessage_write, + unitmessage_read +}; + +trigger * +trigger_unitmessage(unit * target, const char * string, int type, int level) +{ + trigger * t = t_new(&tt_unitmessage); + unitmessage_data * td = (unitmessage_data*)t->data.v; + td->target = target; + td->string = strdup(string); + td->type = type; + td->level = level; + return t; +} diff --git a/src/triggers/unitmessage.h b/src/triggers/unitmessage.h index dcc8df47d..5833e4645 100644 --- a/src/triggers/unitmessage.h +++ b/src/triggers/unitmessage.h @@ -1,36 +1,36 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef UNITMESSAGE_H -#define UNITMESSAGE_H -#ifdef __cplusplus -extern "C" { -#endif - -/* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; -struct unit; - -extern struct trigger_type tt_unitmessage; -extern struct trigger * trigger_unitmessage(struct unit * target, const char * string, int type, int level); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef UNITMESSAGE_H +#define UNITMESSAGE_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; +struct unit; + +extern struct trigger_type tt_unitmessage; +extern struct trigger * trigger_unitmessage(struct unit * target, const char * string, int type, int level); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util.vcproj b/src/util.vcproj index b501b3566..8517f8c19 100644 --- a/src/util.vcproj +++ b/src/util.vcproj @@ -1,418 +1,418 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/util.vcxproj b/src/util.vcxproj index a86de3fc2..6c774d665 100644 --- a/src/util.vcxproj +++ b/src/util.vcxproj @@ -1,159 +1,160 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {F70CFB27-8A2F-E447-B452-4E1C590EDA6D} - util - Win32Proj - - - - StaticLibrary - MultiByte - - - StaticLibrary - MultiByte - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - - - - /MP %(AdditionalOptions) - Disabled - .;../../external;%(AdditionalIncludeDirectories) - WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - true - - - Level4 - true - EditAndContinue - - - WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - ..;.;%(AdditionalIncludeDirectories) - - - $(OutDir)util.lib - - - - - Full - .;../../external;%(AdditionalIncludeDirectories) - WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) - true - MultiThreadedDLL - true - - - Level4 - - - - - WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) - ..;.;%(AdditionalIncludeDirectories) - - - $(OutDir)util.lib - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + + {F70CFB27-8A2F-E447-B452-4E1C590EDA6D} + util + Win32Proj + + + + StaticLibrary + MultiByte + + + StaticLibrary + MultiByte + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + $(Configuration)\$(ProjectName)\ + + + + /MP %(AdditionalOptions) + Disabled + .;../../external;../../external/lua/src;../../external/pdcurses;..\..\external\libxml2\include;%(AdditionalIncludeDirectories) + WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + true + + + Level4 + true + EditAndContinue + + + WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + ..;.;%(AdditionalIncludeDirectories) + + + $(OutDir)util.lib + + + + + Full + .;../../external;../../external/lua/src;../../external/pdcurses;..\..\external\libxml2\include;%(AdditionalIncludeDirectories) + WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + + + Level4 + + + + + WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) + ..;.;%(AdditionalIncludeDirectories) + + + $(OutDir)util.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/util.vcxproj.filters b/src/util.vcxproj.filters index 4f0d43ac5..237444227 100644 --- a/src/util.vcxproj.filters +++ b/src/util.vcxproj.filters @@ -1,203 +1,203 @@ - - - - - {93caffaa-508e-4e78-b1ba-5a8d6aa4ab9a} - h;hpp;hxx;hm;inl;inc;xsd - - - {77dd9146-7564-475b-a364-b1610046b1bb} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - + + + + + {93caffaa-508e-4e78-b1ba-5a8d6aa4ab9a} + h;hpp;hxx;hm;inl;inc;xsd + + + {77dd9146-7564-475b-a364-b1610046b1bb} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + \ No newline at end of file diff --git a/src/util/argstack.c b/src/util/argstack.c index 614a18def..a938d77ec 100644 --- a/src/util/argstack.c +++ b/src/util/argstack.c @@ -1,66 +1,66 @@ -#include "argstack.h" -#include - -#define ARGSTKSIZE 16 -typedef struct arguments { - int n; - struct value { - int type; - union { - double number; - const char * str; - void * data; - } value; - } stack[ARGSTKSIZE]; -} arguments; - -void arg_init(struct arguments * arg) { - arg->n = 0; -} - -void arg_done(struct arguments * arg) { - arg = arg; -} - -void arg_pushuserdata(struct arguments * arg, int type, void * data) { - assert(arg->nstack[arg->n].type = type; - arg->stack[arg->n].value.data = data; - ++arg->n; -} - -void arg_pushstring(struct arguments * arg, const char * str) { - assert(arg->nstack[arg->n].type = ARG_TSTRING; - arg->stack[arg->n].value.str = str; - ++arg->n; -} - -void arg_pushnumber(struct arguments * arg, double number) { - assert(arg->nstack[arg->n].type = ARG_TSTRING; - arg->stack[arg->n].value.number = number; - ++arg->n; -} - -int arg_size(struct arguments * arg) { - return arg->n; -} - -void * arg_touserdata(struct arguments * arg, int idx, int type) { - assert(arg->n>idx && idx>=0); - assert(arg->stack[arg->n].type==type); - return arg->stack[arg->n].value.data; -} - -double arg_tonumber(struct arguments * arg, int idx) { - assert(arg->n>idx && idx>=0); - assert(arg->stack[arg->n].type==ARG_TNUMBER); - return arg->stack[arg->n].value.number; -} - -const char * arg_tostring(struct arguments * arg, int idx) { - assert(arg->n>idx && idx>=0); - assert(arg->stack[arg->n].type==ARG_TSTRING); - return arg->stack[arg->n].value.str; -} +#include "argstack.h" +#include + +#define ARGSTKSIZE 16 +typedef struct arguments { + int n; + struct value { + int type; + union { + double number; + const char * str; + void * data; + } value; + } stack[ARGSTKSIZE]; +} arguments; + +void arg_init(struct arguments * arg) { + arg->n = 0; +} + +void arg_done(struct arguments * arg) { + arg = arg; +} + +void arg_pushuserdata(struct arguments * arg, int type, void * data) { + assert(arg->nstack[arg->n].type = type; + arg->stack[arg->n].value.data = data; + ++arg->n; +} + +void arg_pushstring(struct arguments * arg, const char * str) { + assert(arg->nstack[arg->n].type = ARG_TSTRING; + arg->stack[arg->n].value.str = str; + ++arg->n; +} + +void arg_pushnumber(struct arguments * arg, double number) { + assert(arg->nstack[arg->n].type = ARG_TSTRING; + arg->stack[arg->n].value.number = number; + ++arg->n; +} + +int arg_size(struct arguments * arg) { + return arg->n; +} + +void * arg_touserdata(struct arguments * arg, int idx, int type) { + assert(arg->n>idx && idx>=0); + assert(arg->stack[arg->n].type==type); + return arg->stack[arg->n].value.data; +} + +double arg_tonumber(struct arguments * arg, int idx) { + assert(arg->n>idx && idx>=0); + assert(arg->stack[arg->n].type==ARG_TNUMBER); + return arg->stack[arg->n].value.number; +} + +const char * arg_tostring(struct arguments * arg, int idx) { + assert(arg->n>idx && idx>=0); + assert(arg->stack[arg->n].type==ARG_TSTRING); + return arg->stack[arg->n].value.str; +} diff --git a/src/util/argstack.h b/src/util/argstack.h index b4a0dc420..4ce6738ec 100644 --- a/src/util/argstack.h +++ b/src/util/argstack.h @@ -1,27 +1,27 @@ -#ifndef UTIL_ARG_H -#define UTIL_ARG_H -#ifdef __cplusplus -extern "C" { -#endif - -struct arguments; - -#define ARG_TNUMBER -1 -#define ARG_TSTRING -2 - -void arg_init(struct arguments * arg); -void arg_done(struct arguments * arg); - -void arg_push(struct arguments * arg, int type, void * data); -void arg_pushstring(struct arguments * arg, const char * str); -void arg_pushnumber(struct arguments * arg, double number); - -int arg_size(struct arguments * arg); -void * arg_touserdata(struct arguments * arg, int idx, int type); -double arg_tonumber(struct arguments * arg, int idx); -const char * arg_tostring(struct arguments * arg, int idx); - -#ifdef __cplusplus -} -#endif -#endif +#ifndef UTIL_ARG_H +#define UTIL_ARG_H +#ifdef __cplusplus +extern "C" { +#endif + +struct arguments; + +#define ARG_TNUMBER -1 +#define ARG_TSTRING -2 + +void arg_init(struct arguments * arg); +void arg_done(struct arguments * arg); + +void arg_push(struct arguments * arg, int type, void * data); +void arg_pushstring(struct arguments * arg, const char * str); +void arg_pushnumber(struct arguments * arg, double number); + +int arg_size(struct arguments * arg); +void * arg_touserdata(struct arguments * arg, int idx, int type); +double arg_tonumber(struct arguments * arg, int idx); +const char * arg_tostring(struct arguments * arg, int idx); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/attrib.c b/src/util/attrib.c index 97d3a0d97..18c4937af 100644 --- a/src/util/attrib.c +++ b/src/util/attrib.c @@ -1,322 +1,322 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "attrib.h" - -#include "log.h" -#include "storage.h" - -#include -#include -#include - -#define MAXATHASH 61 -attrib_type * at_hash[MAXATHASH]; - -static unsigned int -__at_hashkey(const char* s) -{ - int key = 0; - size_t i = strlen(s); - - while (i>0) { - key = (s[--i] + key*37); - } - return key & 0x7fffffff; -} - -void -at_register(attrib_type * at) -{ - attrib_type * find; - - if (at->read==NULL) { - log_warning(("registering non-persistent attribute %s.\n", at->name)); - } - at->hashkey = __at_hashkey(at->name); - find = at_hash[at->hashkey % MAXATHASH]; - while (find && at->hashkey!=find->hashkey) find = find->nexthash; - if (find && find==at) { - log_warning(("attribute '%s' was registered more than once\n", at->name)); - return; - } else { - assert(!find || !"hashkey is already in use"); - } - at->nexthash = at_hash[at->hashkey % MAXATHASH]; - at_hash[at->hashkey % MAXATHASH] = at; -} - -static attrib_type * -at_find(unsigned int hk) -{ - const char* translate[3][2] = { - { "zielregion", "targetregion" }, /* remapping: from 'zielregion, heute targetregion */ - { "verzaubert", "curse" }, /* remapping: früher verzaubert, jetzt curse */ - { NULL, NULL } - }; - attrib_type * find = at_hash[hk % MAXATHASH]; - while (find && hk!=find->hashkey) find = find->nexthash; - if (!find) { - int i = 0; - while (translate[i][0]) { - if (__at_hashkey(translate[i][0])==hk) - return at_find(__at_hashkey(translate[i][1])); - ++i; - } - } - return find; -} - -attrib * -a_select(attrib * a, const void * data, boolean(*compare)(const attrib *, const void *)) -{ - while (a && !compare(a, data)) a = a->next; - return a; -} - -attrib * -a_find(attrib * a, const attrib_type * at) -{ - while (a && a->type!=at) a = a->nexttype; - return a; -} - -const attrib * -a_findc(const attrib * a, const attrib_type * at) -{ - while (a && a->type!=at) a = a->nexttype; - return a; -} - -static attrib * -a_insert(attrib * head, attrib * a) -{ - attrib ** pa=&head->next; - - assert(!(a->type->flags & ATF_UNIQUE)); - assert(head && head->type==a->type); - - while (*pa && (*pa)->type==a->type) { - pa = &(*pa)->next; - } - a->next = *pa; - return *pa = a; -} - -attrib * -a_add(attrib ** pa, attrib * a) -{ - attrib * first = *pa; - assert(a->next==NULL && a->nexttype==NULL); - - if (first==NULL) return *pa = a; - if (first->type==a->type) { - return a_insert(first, a); - } - for (;;) { - attrib * next = first->nexttype; - if (next==NULL) { - /* the type is not in the list, append it behind the last type */ - attrib ** insert = &first->next; - first->nexttype = a; - while (*insert) insert = &(*insert)->next; - *insert = a; - break; - } - if (next->type==a->type) { - return a_insert(next, a); - } - first = next; - } - return a; -} - -void -a_free(attrib * a) -{ - const attrib_type * at = a->type; - if (at->finalize) at->finalize(a); - free(a); -} - -static int -a_unlink(attrib ** pa, attrib * a) -{ - attrib ** pnexttype = pa; - attrib ** pnext = NULL; - - assert(a!=NULL); - while (*pnexttype) { - attrib * next = *pnexttype; - if (next->type==a->type) break; - pnexttype = &next->nexttype; - pnext = &next->next; - } - if (*pnexttype && (*pnexttype)->type==a->type) { - if (*pnexttype==a) { - *pnexttype = a->next; - if (a->next!=a->nexttype) { - a->next->nexttype = a->nexttype; - } - if (pnext==NULL) return 1; - while (*pnext && (*pnext)->type!=a->type) pnext = &(*pnext)->next; - } else { - pnext = &(*pnexttype)->next; - } - while (*pnext && (*pnext)->type==a->type) { - if (*pnext==a) { - *pnext = a->next; - return 1; - } - pnext = &(*pnext)->next; - } - } - return 0; -} - -int -a_remove(attrib ** pa, attrib * a) -{ - int ok; - assert(a!=NULL); - ok = a_unlink(pa, a); - if (ok) a_free(a); - return ok; -} - -void -a_removeall(attrib **pa, const attrib_type * at) -{ - attrib ** pnexttype = pa; - attrib ** pnext = NULL; - - while (*pnexttype) { - attrib * next = *pnexttype; - if (next->type==at) break; - pnexttype = &next->nexttype; - pnext = &next->next; - } - if (*pnexttype && (*pnexttype)->type==at) { - attrib * a = *pnexttype; - - *pnexttype = a->nexttype; - if (pnext) { - while (*pnext && (*pnext)->type!=at) pnext = &(*pnext)->next; - *pnext = a->nexttype; - } - while (a && a->type==at) { - attrib * ra = a; - a = a->next; - a_free(ra); - } - } -} - -attrib * -a_new(const attrib_type * at) -{ - attrib * a = (attrib*)calloc(1, sizeof(attrib)); - assert(at!=NULL); - a->type = at; - if (at->initialize) at->initialize(a); - return a; -} - -int -a_age(attrib ** p) -{ - attrib ** ap = p; - /* Attribute altern, und die Entfernung (age()==0) eines Attributs - * hat Einfluß auf den Besitzer */ - while(*ap) { - attrib * a = *ap; - if (a->type->age) { - int result = a->type->age(a); - assert(result>=0 || !"age() returned a negative value"); - if (result==0) { - a_remove(p, a); - continue; - } - } - ap = &a->next; - } - return (*p!=NULL); -} - -int -a_read(struct storage * store, attrib ** attribs, void * owner) -{ - int key, retval = AT_READ_OK; - char zText[128]; - strcpy(zText, "unknown"); - - key = -1; - store->r_tok_buf(store, zText, sizeof(zText)); - if (strcmp(zText, "end")==0) return retval; - else key = __at_hashkey(zText); - - while(key!=-1) { - attrib_type * at = at_find(key); - if (!at) { - fprintf(stderr, "attribute hash: %d (%s)\n", key, zText); - assert(at || !"attribute not registered"); - } - if (at->read) { - attrib * na = a_new(at); - int i = at->read(na, owner, store); - switch (i) { - case AT_READ_OK: - a_add(attribs, na); - break; - case AT_READ_FAIL: - retval = AT_READ_FAIL; - a_free(na); - break; - default: - assert(!"invalid return value"); - break; - } - } else { - assert(!"fehler: keine laderoutine für attribut"); - } - - store->r_tok_buf(store, zText, sizeof(zText)); - if (!strcmp(zText, "end")) break; - key = __at_hashkey(zText); - } - return retval; -} - -void -a_write(struct storage * store, const attrib * attribs, const void * owner) -{ - const attrib * na = attribs; - - while(na) { - if (na->type->write) { - assert(na->type->hashkey || !"attribute not registered"); - store->w_tok(store, na->type->name); - na->type->write(na, owner, store); - na = na->next; - } else { - na = na->nexttype; - } - } - store->w_tok(store, "end"); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "attrib.h" + +#include "log.h" +#include "storage.h" + +#include +#include +#include + +#define MAXATHASH 61 +attrib_type * at_hash[MAXATHASH]; + +static unsigned int +__at_hashkey(const char* s) +{ + int key = 0; + size_t i = strlen(s); + + while (i>0) { + key = (s[--i] + key*37); + } + return key & 0x7fffffff; +} + +void +at_register(attrib_type * at) +{ + attrib_type * find; + + if (at->read==NULL) { + log_warning(("registering non-persistent attribute %s.\n", at->name)); + } + at->hashkey = __at_hashkey(at->name); + find = at_hash[at->hashkey % MAXATHASH]; + while (find && at->hashkey!=find->hashkey) find = find->nexthash; + if (find && find==at) { + log_warning(("attribute '%s' was registered more than once\n", at->name)); + return; + } else { + assert(!find || !"hashkey is already in use"); + } + at->nexthash = at_hash[at->hashkey % MAXATHASH]; + at_hash[at->hashkey % MAXATHASH] = at; +} + +static attrib_type * +at_find(unsigned int hk) +{ + const char* translate[3][2] = { + { "zielregion", "targetregion" }, /* remapping: from 'zielregion, heute targetregion */ + { "verzaubert", "curse" }, /* remapping: früher verzaubert, jetzt curse */ + { NULL, NULL } + }; + attrib_type * find = at_hash[hk % MAXATHASH]; + while (find && hk!=find->hashkey) find = find->nexthash; + if (!find) { + int i = 0; + while (translate[i][0]) { + if (__at_hashkey(translate[i][0])==hk) + return at_find(__at_hashkey(translate[i][1])); + ++i; + } + } + return find; +} + +attrib * +a_select(attrib * a, const void * data, boolean(*compare)(const attrib *, const void *)) +{ + while (a && !compare(a, data)) a = a->next; + return a; +} + +attrib * +a_find(attrib * a, const attrib_type * at) +{ + while (a && a->type!=at) a = a->nexttype; + return a; +} + +const attrib * +a_findc(const attrib * a, const attrib_type * at) +{ + while (a && a->type!=at) a = a->nexttype; + return a; +} + +static attrib * +a_insert(attrib * head, attrib * a) +{ + attrib ** pa=&head->next; + + assert(!(a->type->flags & ATF_UNIQUE)); + assert(head && head->type==a->type); + + while (*pa && (*pa)->type==a->type) { + pa = &(*pa)->next; + } + a->next = *pa; + return *pa = a; +} + +attrib * +a_add(attrib ** pa, attrib * a) +{ + attrib * first = *pa; + assert(a->next==NULL && a->nexttype==NULL); + + if (first==NULL) return *pa = a; + if (first->type==a->type) { + return a_insert(first, a); + } + for (;;) { + attrib * next = first->nexttype; + if (next==NULL) { + /* the type is not in the list, append it behind the last type */ + attrib ** insert = &first->next; + first->nexttype = a; + while (*insert) insert = &(*insert)->next; + *insert = a; + break; + } + if (next->type==a->type) { + return a_insert(next, a); + } + first = next; + } + return a; +} + +void +a_free(attrib * a) +{ + const attrib_type * at = a->type; + if (at->finalize) at->finalize(a); + free(a); +} + +static int +a_unlink(attrib ** pa, attrib * a) +{ + attrib ** pnexttype = pa; + attrib ** pnext = NULL; + + assert(a!=NULL); + while (*pnexttype) { + attrib * next = *pnexttype; + if (next->type==a->type) break; + pnexttype = &next->nexttype; + pnext = &next->next; + } + if (*pnexttype && (*pnexttype)->type==a->type) { + if (*pnexttype==a) { + *pnexttype = a->next; + if (a->next!=a->nexttype) { + a->next->nexttype = a->nexttype; + } + if (pnext==NULL) return 1; + while (*pnext && (*pnext)->type!=a->type) pnext = &(*pnext)->next; + } else { + pnext = &(*pnexttype)->next; + } + while (*pnext && (*pnext)->type==a->type) { + if (*pnext==a) { + *pnext = a->next; + return 1; + } + pnext = &(*pnext)->next; + } + } + return 0; +} + +int +a_remove(attrib ** pa, attrib * a) +{ + int ok; + assert(a!=NULL); + ok = a_unlink(pa, a); + if (ok) a_free(a); + return ok; +} + +void +a_removeall(attrib **pa, const attrib_type * at) +{ + attrib ** pnexttype = pa; + attrib ** pnext = NULL; + + while (*pnexttype) { + attrib * next = *pnexttype; + if (next->type==at) break; + pnexttype = &next->nexttype; + pnext = &next->next; + } + if (*pnexttype && (*pnexttype)->type==at) { + attrib * a = *pnexttype; + + *pnexttype = a->nexttype; + if (pnext) { + while (*pnext && (*pnext)->type!=at) pnext = &(*pnext)->next; + *pnext = a->nexttype; + } + while (a && a->type==at) { + attrib * ra = a; + a = a->next; + a_free(ra); + } + } +} + +attrib * +a_new(const attrib_type * at) +{ + attrib * a = (attrib*)calloc(1, sizeof(attrib)); + assert(at!=NULL); + a->type = at; + if (at->initialize) at->initialize(a); + return a; +} + +int +a_age(attrib ** p) +{ + attrib ** ap = p; + /* Attribute altern, und die Entfernung (age()==0) eines Attributs + * hat Einfluß auf den Besitzer */ + while(*ap) { + attrib * a = *ap; + if (a->type->age) { + int result = a->type->age(a); + assert(result>=0 || !"age() returned a negative value"); + if (result==0) { + a_remove(p, a); + continue; + } + } + ap = &a->next; + } + return (*p!=NULL); +} + +int +a_read(struct storage * store, attrib ** attribs, void * owner) +{ + int key, retval = AT_READ_OK; + char zText[128]; + strcpy(zText, "unknown"); + + key = -1; + store->r_tok_buf(store, zText, sizeof(zText)); + if (strcmp(zText, "end")==0) return retval; + else key = __at_hashkey(zText); + + while(key!=-1) { + attrib_type * at = at_find(key); + if (!at) { + fprintf(stderr, "attribute hash: %d (%s)\n", key, zText); + assert(at || !"attribute not registered"); + } + if (at->read) { + attrib * na = a_new(at); + int i = at->read(na, owner, store); + switch (i) { + case AT_READ_OK: + a_add(attribs, na); + break; + case AT_READ_FAIL: + retval = AT_READ_FAIL; + a_free(na); + break; + default: + assert(!"invalid return value"); + break; + } + } else { + assert(!"fehler: keine laderoutine für attribut"); + } + + store->r_tok_buf(store, zText, sizeof(zText)); + if (!strcmp(zText, "end")) break; + key = __at_hashkey(zText); + } + return retval; +} + +void +a_write(struct storage * store, const attrib * attribs, const void * owner) +{ + const attrib * na = attribs; + + while(na) { + if (na->type->write) { + assert(na->type->hashkey || !"attribute not registered"); + store->w_tok(store, na->type->name); + na->type->write(na, owner, store); + na = na->next; + } else { + na = na->nexttype; + } + } + store->w_tok(store, "end"); +} diff --git a/src/util/attrib.h b/src/util/attrib.h index f5c6648fb..638505a67 100644 --- a/src/util/attrib.h +++ b/src/util/attrib.h @@ -1,93 +1,93 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef ATTRIB_H -#define ATTRIB_H -#ifdef __cplusplus -extern "C" { -#endif - -struct storage; -typedef void (*afun)(void); - -typedef struct attrib { - const struct attrib_type * type; - union { - afun f; - void * v; - int i; - float flt; - char c; - short s; - short sa[2]; - char ca[4]; - } data; - /* internal data, do not modify: */ - struct attrib * next; /* next attribute in the list */ - struct attrib * nexttype; /* skip to attribute of a different type */ -} attrib; - -#define ATF_UNIQUE (1<<0) /* only one per attribute-list */ -#define ATF_PRESERVE (1<<1) /* preserve order in list. append to back */ -#define ATF_USER_DEFINED (1<<2) /* use this to make udf */ - -typedef struct attrib_type { - const char* name; - void (*initialize)(struct attrib *); - void (*finalize)(struct attrib *); - int (*age)(struct attrib *); - /* age returns 0 if the attribute needs to be removed, !=0 otherwise */ - void (*write)(const struct attrib *, const void * owner, struct storage *); - int (*read)(struct attrib *, void * owner, struct storage *); /* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */ - unsigned int flags; - /* ---- internal data, do not modify: ---- */ - struct attrib_type * nexthash; - unsigned int hashkey; -} attrib_type; - -extern void at_register(attrib_type * at); - -extern attrib * a_select(attrib * a, const void * data, boolean(*compare)(const attrib *, const void *)); -extern attrib * a_find(attrib * a, const attrib_type * at); -extern const attrib * a_findc(const attrib * a, const attrib_type * at); -extern attrib * a_add(attrib ** pa, attrib * at); -extern int a_remove(attrib ** pa, attrib * at); -extern void a_removeall(attrib ** a, const attrib_type * at); -extern attrib * a_new(const attrib_type * at); -extern void a_free(attrib * a); - -extern int a_age(attrib ** attribs); -extern int a_read(struct storage * store, attrib ** attribs, void * owner); -extern void a_write(struct storage * store, const attrib * attribs, const void * owner); - -#define DEFAULT_AGE NULL -#define DEFAULT_INIT NULL -#define DEFAULT_FINALIZE NULL -#define NO_WRITE NULL -#define NO_READ NULL - -#define AT_READ_OK 0 -#define AT_READ_FAIL -1 - -#define AT_AGE_REMOVE 0 /* remove the attribute after calling age() */ -#define AT_AGE_KEEP 1 /* keep the attribute for another turn */ - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef ATTRIB_H +#define ATTRIB_H +#ifdef __cplusplus +extern "C" { +#endif + +struct storage; +typedef void (*afun)(void); + +typedef struct attrib { + const struct attrib_type * type; + union { + afun f; + void * v; + int i; + float flt; + char c; + short s; + short sa[2]; + char ca[4]; + } data; + /* internal data, do not modify: */ + struct attrib * next; /* next attribute in the list */ + struct attrib * nexttype; /* skip to attribute of a different type */ +} attrib; + +#define ATF_UNIQUE (1<<0) /* only one per attribute-list */ +#define ATF_PRESERVE (1<<1) /* preserve order in list. append to back */ +#define ATF_USER_DEFINED (1<<2) /* use this to make udf */ + +typedef struct attrib_type { + const char* name; + void (*initialize)(struct attrib *); + void (*finalize)(struct attrib *); + int (*age)(struct attrib *); + /* age returns 0 if the attribute needs to be removed, !=0 otherwise */ + void (*write)(const struct attrib *, const void * owner, struct storage *); + int (*read)(struct attrib *, void * owner, struct storage *); /* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */ + unsigned int flags; + /* ---- internal data, do not modify: ---- */ + struct attrib_type * nexthash; + unsigned int hashkey; +} attrib_type; + +extern void at_register(attrib_type * at); + +extern attrib * a_select(attrib * a, const void * data, boolean(*compare)(const attrib *, const void *)); +extern attrib * a_find(attrib * a, const attrib_type * at); +extern const attrib * a_findc(const attrib * a, const attrib_type * at); +extern attrib * a_add(attrib ** pa, attrib * at); +extern int a_remove(attrib ** pa, attrib * at); +extern void a_removeall(attrib ** a, const attrib_type * at); +extern attrib * a_new(const attrib_type * at); +extern void a_free(attrib * a); + +extern int a_age(attrib ** attribs); +extern int a_read(struct storage * store, attrib ** attribs, void * owner); +extern void a_write(struct storage * store, const attrib * attribs, const void * owner); + +#define DEFAULT_AGE NULL +#define DEFAULT_INIT NULL +#define DEFAULT_FINALIZE NULL +#define NO_WRITE NULL +#define NO_READ NULL + +#define AT_READ_OK 0 +#define AT_READ_FAIL -1 + +#define AT_AGE_REMOVE 0 /* remove the attribute after calling age() */ +#define AT_AGE_KEEP 1 /* keep the attribute for another turn */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/base36.c b/src/util/base36.c index 3c795077a..a1477e34c 100644 --- a/src/util/base36.c +++ b/src/util/base36.c @@ -1,115 +1,115 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "base36.h" - -#include -#include -#include - -int -atoi36(const char * str) -{ - /* cannot use strtol, because invalid strings will cause crash */ - const unsigned char * s = (const unsigned char *)str; - int i = 0, sign = 1; - assert(s); - if(!(*s)) return 0; - - while(isxspace(*(unsigned char*)s)) ++s; - if (*s == '-') { - sign = -1; - ++s; - } - while(isalnum(*(unsigned char*)s)) { - if (isupper(*(unsigned char*)s)) i = i*36 + (*s)-'A' + 10; - else if (islower(*(unsigned char*)s)) i=i*36 + (*s)-'a' + 10; - else if (isdigit(*(unsigned char*)s)) i=i*36 + (*s)-'0'; - else - break; - ++s; - } - if (i<0) return 0; - return i * sign; -} - -const char* -itoab(int i, int base) -{ - static char **as = NULL; /* STATIC_RETURN: used for return, not across calls */ - char * s, * dst; - static int index = 0; /* STATIC_XCALL: used across calls */ - int neg = 0; - - if (!as) { - int j; - char * x = (char*)calloc(sizeof(char), 8*4); /* STATIC_LEAK: malloc in static variable */ - as = (char **)calloc(sizeof(char*), 4); - for (j=0;j!=4;++j) as[j] = x+j*8; - } - s = as[index]; - index = (index+1) & 3; /* quick for % 4 */ - dst = s+7; - (*dst--)=0; - if (i!=0) { - if (i<0) { - i=-i; - neg = 1; - } - while (i) { - int x = i % base; - i = i / base; - if (x<10) *(dst--) = (char)('0' + x); - else if ('a' + x - 10 == 'l') *(dst--) = 'L'; - else *(dst--) = (char)('a' + (x-10)); - } - if (neg) *(dst) = '-'; - else ++dst; - } - else *dst = '0'; - - return dst; -} - -const char* -itoa36(int i) -{ - return itoab(i, 36); -} - -const char* -itoa10(int i) -{ - return itoab(i, 10); -} - -int -i10toi36(int i) -{ - int r = 0; - while(i) { - r = r*36 + i % 10; - i = i / 10; - } - return r; -} - -#ifndef DISABLE_TESTS -#include "base36_test.c" -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "base36.h" + +#include +#include +#include + +int +atoi36(const char * str) +{ + /* cannot use strtol, because invalid strings will cause crash */ + const unsigned char * s = (const unsigned char *)str; + int i = 0, sign = 1; + assert(s); + if(!(*s)) return 0; + + while(isxspace(*(unsigned char*)s)) ++s; + if (*s == '-') { + sign = -1; + ++s; + } + while(isalnum(*(unsigned char*)s)) { + if (isupper(*(unsigned char*)s)) i = i*36 + (*s)-'A' + 10; + else if (islower(*(unsigned char*)s)) i=i*36 + (*s)-'a' + 10; + else if (isdigit(*(unsigned char*)s)) i=i*36 + (*s)-'0'; + else + break; + ++s; + } + if (i<0) return 0; + return i * sign; +} + +const char* +itoab(int i, int base) +{ + static char **as = NULL; /* STATIC_RETURN: used for return, not across calls */ + char * s, * dst; + static int index = 0; /* STATIC_XCALL: used across calls */ + int neg = 0; + + if (!as) { + int j; + char * x = (char*)calloc(sizeof(char), 8*4); /* STATIC_LEAK: malloc in static variable */ + as = (char **)calloc(sizeof(char*), 4); + for (j=0;j!=4;++j) as[j] = x+j*8; + } + s = as[index]; + index = (index+1) & 3; /* quick for % 4 */ + dst = s+7; + (*dst--)=0; + if (i!=0) { + if (i<0) { + i=-i; + neg = 1; + } + while (i) { + int x = i % base; + i = i / base; + if (x<10) *(dst--) = (char)('0' + x); + else if ('a' + x - 10 == 'l') *(dst--) = 'L'; + else *(dst--) = (char)('a' + (x-10)); + } + if (neg) *(dst) = '-'; + else ++dst; + } + else *dst = '0'; + + return dst; +} + +const char* +itoa36(int i) +{ + return itoab(i, 36); +} + +const char* +itoa10(int i) +{ + return itoab(i, 10); +} + +int +i10toi36(int i) +{ + int r = 0; + while(i) { + r = r*36 + i % 10; + i = i / 10; + } + return r; +} + +#ifndef DISABLE_TESTS +#include "base36_test.c" +#endif diff --git a/src/util/base36.h b/src/util/base36.h index e11be7ec2..5018a0028 100644 --- a/src/util/base36.h +++ b/src/util/base36.h @@ -1,34 +1,34 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_UTIL_BASE36 -#define H_UTIL_BASE36 -#ifdef __cplusplus -extern "C" { -#endif - -extern int atoi36(const char * s); -extern const char* itoab(int i, int base); -extern const char* itoa36(int i); -extern const char* itoa10(int i); -extern int i10toi36(int i); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_UTIL_BASE36 +#define H_UTIL_BASE36 +#ifdef __cplusplus +extern "C" { +#endif + +extern int atoi36(const char * s); +extern const char* itoab(int i, int base); +extern const char* itoa36(int i); +extern const char* itoa10(int i); +extern int i10toi36(int i); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/base36_test.c b/src/util/base36_test.c index c11847ad7..74a43685b 100644 --- a/src/util/base36_test.c +++ b/src/util/base36_test.c @@ -1,27 +1,27 @@ -#include - -static void test_atoi36(CuTest * tc) { - CuAssertIntEquals(tc, 0, atoi36("0")); - CuAssertIntEquals(tc, 666, atoi36("ii")); - CuAssertIntEquals(tc, -10, atoi36("-a")); - CuAssertIntEquals(tc, -1, atoi36("-1")); - CuAssertIntEquals(tc, -10, atoi("-10")); - CuAssertIntEquals(tc, -10, atoi("-10")); -} - -static void test_itoa36(CuTest * tc) { - CuAssertStrEquals(tc, itoa36(0), "0"); - CuAssertStrEquals(tc, itoa10(INT_MAX), "2147483647"); - CuAssertStrEquals(tc, itoab(-1, 5), "-1"); - CuAssertStrEquals(tc, itoa36(-1), "-1"); - CuAssertStrEquals(tc, itoa36(-10), "-a"); - CuAssertStrEquals(tc, itoa36(666), "ii"); -} - -CuSuite* get_base36_suite(void) -{ - CuSuite* suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, test_itoa36); - SUITE_ADD_TEST(suite, test_atoi36); - return suite; -} +#include + +static void test_atoi36(CuTest * tc) { + CuAssertIntEquals(tc, 0, atoi36("0")); + CuAssertIntEquals(tc, 666, atoi36("ii")); + CuAssertIntEquals(tc, -10, atoi36("-a")); + CuAssertIntEquals(tc, -1, atoi36("-1")); + CuAssertIntEquals(tc, -10, atoi("-10")); + CuAssertIntEquals(tc, -10, atoi("-10")); +} + +static void test_itoa36(CuTest * tc) { + CuAssertStrEquals(tc, itoa36(0), "0"); + CuAssertStrEquals(tc, itoa10(INT_MAX), "2147483647"); + CuAssertStrEquals(tc, itoab(-1, 5), "-1"); + CuAssertStrEquals(tc, itoa36(-1), "-1"); + CuAssertStrEquals(tc, itoa36(-10), "-a"); + CuAssertStrEquals(tc, itoa36(666), "ii"); +} + +CuSuite* get_base36_suite(void) +{ + CuSuite* suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_itoa36); + SUITE_ADD_TEST(suite, test_atoi36); + return suite; +} diff --git a/src/util/bsdstring.c b/src/util/bsdstring.c index 84802c70e..548961db2 100644 --- a/src/util/bsdstring.c +++ b/src/util/bsdstring.c @@ -1,88 +1,88 @@ -#include -#include -#include -#include - -#ifndef HAVE_INLINE -#include "bsdstring.h" -#endif - -INLINE_FUNCTION int -wrptr(char ** ptr, size_t * size, int bytes) -{ - assert(bytes>=0 || !"you're not using snprintf right, maybe?"); - - if (bytes==0) { - return 0; - } - if (bytes<0) { - *size = 0; - return EINVAL; - } - if (bytes<=*(int*)size) { - *ptr += bytes; - *size -= bytes; - return 0; - } - - *ptr += *size; - *size = 0; - return ENAMETOOLONG; -} - -#if !defined(HAVE_STRLCPY) -INLINE_FUNCTION size_t -strlcpy(char *dst, const char *src, size_t siz) /* copied from OpenBSD source code */ -{ - register char *d = dst; - register const char *s = src; - register size_t n = siz; - - /* Copy as many bytes as will fit */ - if (n != 0 && --n != 0) { - do { - if ((*d++ = *s++) == 0) - break; - } while (--n != 0); - } - - /* Not enough room in dst, add NUL and traverse rest of src */ - if (n == 0) { - if (siz != 0) - *d = '\0'; /* NUL-terminate dst */ - while (*s++) - ; - } - - return(s - src - 1); /* count does not include NUL */ -} - - -INLINE_FUNCTION size_t -strlcat(char * dst, const char * src, size_t siz) -{ - register char *d = dst; - register const char *s = src; - register size_t n = siz; - size_t dlen; - - /* Find the end of dst and adjust bytes left but don't go past end */ - while (*d != '\0' && n-- != 0) - d++; - dlen = d - dst; - n = siz - dlen; - - if (n == 0) - return(dlen + strlen(s)); - while (*s != '\0') { - if (n != 1) { - *d++ = *s; - n--; - } - s++; - } - *d = '\0'; - - return(dlen + (s - src)); /* count does not include NUL */ -} -#endif +#include +#include +#include +#include + +#ifndef HAVE_INLINE +#include "bsdstring.h" +#endif + +INLINE_FUNCTION int +wrptr(char ** ptr, size_t * size, int bytes) +{ + assert(bytes>=0 || !"you're not using snprintf right, maybe?"); + + if (bytes==0) { + return 0; + } + if (bytes<0) { + *size = 0; + return EINVAL; + } + if (bytes<=*(int*)size) { + *ptr += bytes; + *size -= bytes; + return 0; + } + + *ptr += *size; + *size = 0; + return ENAMETOOLONG; +} + +#if !defined(HAVE_STRLCPY) +INLINE_FUNCTION size_t +strlcpy(char *dst, const char *src, size_t siz) /* copied from OpenBSD source code */ +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} + + +INLINE_FUNCTION size_t +strlcat(char * dst, const char * src, size_t siz) +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (*d != '\0' && n-- != 0) + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} +#endif diff --git a/src/util/bsdstring.h b/src/util/bsdstring.h index ca0e94188..e6858b9d4 100644 --- a/src/util/bsdstring.h +++ b/src/util/bsdstring.h @@ -1,23 +1,23 @@ -#ifndef UTIL_BSDSTRING_H -#define UTIL_BSDSTRING_H - -#ifdef HAVE_INLINE -# include "bsdstring.c" -#else - extern size_t strlcpy(char *dst, const char *src, size_t siz); - extern size_t strlcat(char * dst, const char * src, size_t siz); - extern int wrptr(char ** ptr, size_t * size, int bytes); -#endif - -#if !defined(HAVE_STRLCPY) -# define HAVE_STRLCPY -#endif - -#define WARN_STATIC_BUFFER() log_warning(("static buffer too small in %s:%d\n", __FILE__, __LINE__)) - -#if !defined(HAVE_STRLPRINTF) -# define HAVE_STRLPRINTF -# define slprintf snprintf -#endif - -#endif +#ifndef UTIL_BSDSTRING_H +#define UTIL_BSDSTRING_H + +#ifdef HAVE_INLINE +# include "bsdstring.c" +#else + extern size_t strlcpy(char *dst, const char *src, size_t siz); + extern size_t strlcat(char * dst, const char * src, size_t siz); + extern int wrptr(char ** ptr, size_t * size, int bytes); +#endif + +#if !defined(HAVE_STRLCPY) +# define HAVE_STRLCPY +#endif + +#define WARN_STATIC_BUFFER() log_warning(("static buffer too small in %s:%d\n", __FILE__, __LINE__)) + +#if !defined(HAVE_STRLPRINTF) +# define HAVE_STRLPRINTF +# define slprintf snprintf +#endif + +#endif diff --git a/src/util/console.c b/src/util/console.c index 62353604a..b5237d786 100644 --- a/src/util/console.c +++ b/src/util/console.c @@ -1,247 +1,247 @@ -#include -#include "console.h" - -/* lua includes */ -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include - -/*** Lua Console ***/ -/* -** this macro defines a function to show the prompt and reads the -** next line for manual input -*/ -/* maximum length of an input line */ -#ifndef LUA_MAXINPUT -#define LUA_MAXINPUT 512 -#endif - -#if defined(LUA_USE_READLINE) -#include -#include -#include -#define default_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) -#define lua_saveline(L,idx) \ - if (lua_strlen(L,idx) > 0) /* non-empty line? */ \ - add_history(lua_tostring(L, idx)); /* add it to history */ -#define lua_freeline(L,b) ((void)L, free(b)) -#else -#define default_readline(L,b,p) \ - ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ - fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ -#define lua_saveline(L,idx) { (void)L; (void)idx; } -#define lua_freeline(L,b) { (void)L; (void)b; } -#endif - -static int (*my_readline)(lua_State *l, char *, size_t, const char *prompt) = NULL; -static int lua_readline(lua_State *l, char *b, const char *prompt) -{ - if (my_readline) { - return my_readline(l, b, LUA_MAXINPUT, prompt); - } else { - return default_readline(l, b, prompt); - } -} - -void set_readline(readline foo) { - my_readline = foo; -} - -#ifndef PROMPT -#define PROMPT "E> " -#endif - -#ifndef PROMPT2 -#define PROMPT2 ".. " -#endif - -/* BAD hack, all this action stuff. */ -#define STATESTACK_MAX 16 -static lua_State * state_stack[STATESTACK_MAX]; -int state_stack_top = -1; - -static const char *progname = "eressea"; - -static void -lstop(lua_State *l, lua_Debug *ar) -{ - (void)ar; /* unused arg. */ - lua_sethook(l, NULL, 0, 0); - luaL_error(l, "interrupted!"); -} - -static void -laction(int i) -{ - signal(i, SIG_DFL); /* if another SIGINT happens before lstop, - terminate process (default action) */ - assert(state_stack_top>=0 && state_stack_top'") == NULL) return 0; - - lua_pop(L, 1); - return 1; -} - - -static int pushline (lua_State *L, int firstline) { - char buffer[LUA_MAXINPUT]; - char *b = buffer; - size_t l; - const char *prmt = get_prompt(L, firstline); - if (lua_readline(L, b, prmt) == 0) - return 0; /* no input */ - l = strlen(b); - if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ - b[l-1] = '\0'; /* remove it */ - if (firstline && b[0] == '=') /* first line starts with `=' ? */ - lua_pushfstring(L, "return %s", b+1); /* change it to `return' */ - else - lua_pushstring(L, b); - lua_freeline(L, b); - return 1; -} - - -static int loadline (lua_State *L) { - int status; - lua_settop(L, 0); - if (!pushline(L, 1)) - return -1; /* no input */ - for (;;) { /* repeat until gets a complete line */ - status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); - if (!incomplete(L, status)) break; /* cannot try to add lines? */ - if (!pushline(L, 0)) /* no more input? */ - return -1; - lua_pushliteral(L, "\n"); /* add a new line... */ - lua_insert(L, -2); /* ...between the two lines */ - lua_concat(L, 3); /* join them */ - } - lua_saveline(L, 1); - lua_remove(L, 1); /* remove line */ - return status; -} - -static void dotty (lua_State *L) { - int status; - const char *oldprogname = progname; - progname = NULL; - while ((status = loadline(L)) != -1) { - if (status == 0) status = docall(L, 0, 0); - report(L, status); - if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ - lua_getglobal(L, "print"); - lua_insert(L, 1); - if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) - l_message(progname, lua_pushfstring(L, - "error calling " LUA_QL("print") " (%s)", - lua_tostring(L, -1))); - } - } - lua_settop(L, 0); /* clear stack */ - fputs("\n", stdout); - fflush(stdout); - progname = oldprogname; -} - -int -lua_console(lua_State * L) -{ - dotty(L); - return 0; -} - -int -lua_do(lua_State * L) -{ - int status = loadline(L); - if (status != -1) { - if (status == 0) status = docall(L, 0, 0); - report(L, status); - if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ - lua_getglobal(L, "print"); - lua_insert(L, 1); - if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) - l_message(NULL, lua_pushfstring(L, "error calling `print' (%s)", - lua_tostring(L, -1))); - } - } - lua_settop(L, 0); /* clear stack */ - return 0; -} +#include +#include "console.h" + +/* lua includes */ +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +/*** Lua Console ***/ +/* +** this macro defines a function to show the prompt and reads the +** next line for manual input +*/ +/* maximum length of an input line */ +#ifndef LUA_MAXINPUT +#define LUA_MAXINPUT 512 +#endif + +#if defined(LUA_USE_READLINE) +#include +#include +#include +#define default_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) +#define lua_saveline(L,idx) \ + if (lua_strlen(L,idx) > 0) /* non-empty line? */ \ + add_history(lua_tostring(L, idx)); /* add it to history */ +#define lua_freeline(L,b) ((void)L, free(b)) +#else +#define default_readline(L,b,p) \ + ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ + fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ +#define lua_saveline(L,idx) { (void)L; (void)idx; } +#define lua_freeline(L,b) { (void)L; (void)b; } +#endif + +static int (*my_readline)(lua_State *l, char *, size_t, const char *prompt) = NULL; +static int lua_readline(lua_State *l, char *b, const char *prompt) +{ + if (my_readline) { + return my_readline(l, b, LUA_MAXINPUT, prompt); + } else { + return default_readline(l, b, prompt); + } +} + +void set_readline(readline foo) { + my_readline = foo; +} + +#ifndef PROMPT +#define PROMPT "E> " +#endif + +#ifndef PROMPT2 +#define PROMPT2 ".. " +#endif + +/* BAD hack, all this action stuff. */ +#define STATESTACK_MAX 16 +static lua_State * state_stack[STATESTACK_MAX]; +int state_stack_top = -1; + +static const char *progname = "eressea"; + +static void +lstop(lua_State *l, lua_Debug *ar) +{ + (void)ar; /* unused arg. */ + lua_sethook(l, NULL, 0, 0); + luaL_error(l, "interrupted!"); +} + +static void +laction(int i) +{ + signal(i, SIG_DFL); /* if another SIGINT happens before lstop, + terminate process (default action) */ + assert(state_stack_top>=0 && state_stack_top'") == NULL) return 0; + + lua_pop(L, 1); + return 1; +} + + +static int pushline (lua_State *L, int firstline) { + char buffer[LUA_MAXINPUT]; + char *b = buffer; + size_t l; + const char *prmt = get_prompt(L, firstline); + if (lua_readline(L, b, prmt) == 0) + return 0; /* no input */ + l = strlen(b); + if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ + b[l-1] = '\0'; /* remove it */ + if (firstline && b[0] == '=') /* first line starts with `=' ? */ + lua_pushfstring(L, "return %s", b+1); /* change it to `return' */ + else + lua_pushstring(L, b); + lua_freeline(L, b); + return 1; +} + + +static int loadline (lua_State *L) { + int status; + lua_settop(L, 0); + if (!pushline(L, 1)) + return -1; /* no input */ + for (;;) { /* repeat until gets a complete line */ + status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); + if (!incomplete(L, status)) break; /* cannot try to add lines? */ + if (!pushline(L, 0)) /* no more input? */ + return -1; + lua_pushliteral(L, "\n"); /* add a new line... */ + lua_insert(L, -2); /* ...between the two lines */ + lua_concat(L, 3); /* join them */ + } + lua_saveline(L, 1); + lua_remove(L, 1); /* remove line */ + return status; +} + +static void dotty (lua_State *L) { + int status; + const char *oldprogname = progname; + progname = NULL; + while ((status = loadline(L)) != -1) { + if (status == 0) status = docall(L, 0, 0); + report(L, status); + if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ + lua_getglobal(L, "print"); + lua_insert(L, 1); + if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) + l_message(progname, lua_pushfstring(L, + "error calling " LUA_QL("print") " (%s)", + lua_tostring(L, -1))); + } + } + lua_settop(L, 0); /* clear stack */ + fputs("\n", stdout); + fflush(stdout); + progname = oldprogname; +} + +int +lua_console(lua_State * L) +{ + dotty(L); + return 0; +} + +int +lua_do(lua_State * L) +{ + int status = loadline(L); + if (status != -1) { + if (status == 0) status = docall(L, 0, 0); + report(L, status); + if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ + lua_getglobal(L, "print"); + lua_insert(L, 1); + if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) + l_message(NULL, lua_pushfstring(L, "error calling `print' (%s)", + lua_tostring(L, -1))); + } + } + lua_settop(L, 0); /* clear stack */ + return 0; +} diff --git a/src/util/console.h b/src/util/console.h index d5821135b..2249927dd 100644 --- a/src/util/console.h +++ b/src/util/console.h @@ -1,37 +1,37 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_LUA_CONSOLE -#define H_LUA_CONSOLE -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - - extern int lua_console(struct lua_State * L); - extern int lua_do(struct lua_State * L); - - typedef int (*readline)(struct lua_State *, char *, size_t, const char *); - extern void set_readline(readline foo); - -#ifdef __cplusplus -} -#endif - -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_LUA_CONSOLE +#define H_LUA_CONSOLE +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + + extern int lua_console(struct lua_State * L); + extern int lua_do(struct lua_State * L); + + typedef int (*readline)(struct lua_State *, char *, size_t, const char *); + extern void set_readline(readline foo); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/util/crmessage.c b/src/util/crmessage.c index 6cb1ba349..6d10406fb 100644 --- a/src/util/crmessage.c +++ b/src/util/crmessage.c @@ -1,159 +1,159 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - -*/ - -#include -#include "crmessage.h" - -#include "message.h" -#include "goodies.h" -#include "log.h" - -#include -#include -#include -#include - -/** type to string conversion **/ -typedef struct tsf_list { - struct tsf_list * next; - const char * name; - tostring_f fun; -} tsf_list; - -static tsf_list * tostringfs; - -static tostring_f -tsf_find(const char * name) -{ - if (name!=NULL) { - tsf_list * tsf; - for (tsf=tostringfs;tsf;tsf=tsf->next) { - if (!strcmp(tsf->name, name)) return tsf->fun; - } - } - return NULL; -} - -void -tsf_register(const char * name, tostring_f fun) -{ - tsf_list * tsf; - for (tsf=tostringfs;tsf;tsf=tsf->next) { - if (!strcmp(tsf->name, name)) break; - } - if (tsf==NULL) { - tsf = malloc(sizeof(tsf_list)); - tsf->fun = fun; - tsf->name = name; - tsf->next = tostringfs; - tostringfs = tsf; - } -} - -/** crmesssage **/ -typedef struct crmessage_type { - const struct message_type * mtype; - tostring_f * renderers; - struct crmessage_type * next; -} crmessage_type; - -#define CRMAXHASH 63 -static crmessage_type * crtypes[CRMAXHASH]; - -static crmessage_type * -crt_find(const struct message_type * mtype) -{ - unsigned int hash = hashstring(mtype->name) % CRMAXHASH; - crmessage_type * found = NULL; - crmessage_type * type = crtypes[hash]; - while (type) { - if (type->mtype==mtype) found = type; - type = type->next; - } - return found; -} - -void -crt_register(const struct message_type * mtype) -{ - unsigned int hash = hashstring(mtype->name) % CRMAXHASH; - crmessage_type * crt = crtypes[hash]; - while (crt && crt->mtype!=mtype) { - crt = crt->next; - } - if (!crt) { - int i; - crt = malloc(sizeof(crmessage_type)); - crt->mtype = mtype; - crt->next = crtypes[hash]; - crtypes[hash] = crt; - if(mtype->nparameters > 0) { - crt->renderers = malloc(sizeof(tostring_f)*mtype->nparameters); - } else { - crt->renderers = NULL; - } - - /* can be scrapped for memory vs. speed */ - for (i=0;i!=mtype->nparameters;++i) { - crt->renderers[i] = tsf_find(mtype->types[i]->name); - } - } -} - -int -cr_render(const message * msg, char * buffer, const void * userdata) -{ - int i; - char * c = buffer; - struct crmessage_type * crt = crt_find(msg->type); - - if (crt==NULL) return -1; - for (i=0;i!=msg->type->nparameters;++i) { - if (crt->renderers[i]==NULL) { - log_error(("No renderer for argument %s:%s of \"%s\"\n", - msg->type->pnames[i], msg->type->types[i]->name, msg->type->name)); - continue; /* strcpy(c, (const char*)msg->locale_string(u->faction->locale, parameters[i])); */ - } else { - if (crt->renderers[i](msg->parameters[i], c, userdata)!=0) continue; - } - c += strlen(c); - sprintf(c, ";%s\n", msg->type->pnames[i]); - c += strlen(c); - } - return 0; -} - -int -cr_string(variant var, char * buffer, const void * userdata) -{ - sprintf(buffer, "\"%s\"", (const char *)var.v); - unused(userdata); - return 0; -} - -int -cr_int(variant var, char * buffer, const void * userdata) -{ - sprintf(buffer, "%d", var.i); - unused(userdata); - return 0; -} - -int -cr_ignore(variant var, char * buffer, const void * userdata) -{ - unused(var); - unused(buffer); - unused(userdata); - return -1; -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + +*/ + +#include +#include "crmessage.h" + +#include "message.h" +#include "goodies.h" +#include "log.h" + +#include +#include +#include +#include + +/** type to string conversion **/ +typedef struct tsf_list { + struct tsf_list * next; + const char * name; + tostring_f fun; +} tsf_list; + +static tsf_list * tostringfs; + +static tostring_f +tsf_find(const char * name) +{ + if (name!=NULL) { + tsf_list * tsf; + for (tsf=tostringfs;tsf;tsf=tsf->next) { + if (!strcmp(tsf->name, name)) return tsf->fun; + } + } + return NULL; +} + +void +tsf_register(const char * name, tostring_f fun) +{ + tsf_list * tsf; + for (tsf=tostringfs;tsf;tsf=tsf->next) { + if (!strcmp(tsf->name, name)) break; + } + if (tsf==NULL) { + tsf = malloc(sizeof(tsf_list)); + tsf->fun = fun; + tsf->name = name; + tsf->next = tostringfs; + tostringfs = tsf; + } +} + +/** crmesssage **/ +typedef struct crmessage_type { + const struct message_type * mtype; + tostring_f * renderers; + struct crmessage_type * next; +} crmessage_type; + +#define CRMAXHASH 63 +static crmessage_type * crtypes[CRMAXHASH]; + +static crmessage_type * +crt_find(const struct message_type * mtype) +{ + unsigned int hash = hashstring(mtype->name) % CRMAXHASH; + crmessage_type * found = NULL; + crmessage_type * type = crtypes[hash]; + while (type) { + if (type->mtype==mtype) found = type; + type = type->next; + } + return found; +} + +void +crt_register(const struct message_type * mtype) +{ + unsigned int hash = hashstring(mtype->name) % CRMAXHASH; + crmessage_type * crt = crtypes[hash]; + while (crt && crt->mtype!=mtype) { + crt = crt->next; + } + if (!crt) { + int i; + crt = malloc(sizeof(crmessage_type)); + crt->mtype = mtype; + crt->next = crtypes[hash]; + crtypes[hash] = crt; + if(mtype->nparameters > 0) { + crt->renderers = malloc(sizeof(tostring_f)*mtype->nparameters); + } else { + crt->renderers = NULL; + } + + /* can be scrapped for memory vs. speed */ + for (i=0;i!=mtype->nparameters;++i) { + crt->renderers[i] = tsf_find(mtype->types[i]->name); + } + } +} + +int +cr_render(const message * msg, char * buffer, const void * userdata) +{ + int i; + char * c = buffer; + struct crmessage_type * crt = crt_find(msg->type); + + if (crt==NULL) return -1; + for (i=0;i!=msg->type->nparameters;++i) { + if (crt->renderers[i]==NULL) { + log_error(("No renderer for argument %s:%s of \"%s\"\n", + msg->type->pnames[i], msg->type->types[i]->name, msg->type->name)); + continue; /* strcpy(c, (const char*)msg->locale_string(u->faction->locale, parameters[i])); */ + } else { + if (crt->renderers[i](msg->parameters[i], c, userdata)!=0) continue; + } + c += strlen(c); + sprintf(c, ";%s\n", msg->type->pnames[i]); + c += strlen(c); + } + return 0; +} + +int +cr_string(variant var, char * buffer, const void * userdata) +{ + sprintf(buffer, "\"%s\"", (const char *)var.v); + unused(userdata); + return 0; +} + +int +cr_int(variant var, char * buffer, const void * userdata) +{ + sprintf(buffer, "%d", var.i); + unused(userdata); + return 0; +} + +int +cr_ignore(variant var, char * buffer, const void * userdata) +{ + unused(var); + unused(buffer); + unused(userdata); + return -1; +} diff --git a/src/util/crmessage.h b/src/util/crmessage.h index 7861aaffe..6b0583d18 100644 --- a/src/util/crmessage.h +++ b/src/util/crmessage.h @@ -1,39 +1,39 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_UTIL_CRMESSAGE -#define H_UTIL_CRMESSAGE - -#include "variant.h" -#ifdef __cplusplus -extern "C" { -#endif - -struct locale; -struct message; -struct message_type; - -typedef int (*tostring_f)(variant data, char * buffer, const void * userdata); -extern void tsf_register(const char * name, tostring_f fun); - /* registers a new type->string-function */ - -extern int cr_string(variant v, char * buffer, const void * userdata); -extern int cr_int(variant v, char * buffer, const void * userdata); -extern int cr_ignore(variant v, char * buffer, const void * userdata); - -extern void crt_register(const struct message_type * mtype); -extern int cr_render(const struct message * msg, char * buffer, const void * userdata); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_UTIL_CRMESSAGE +#define H_UTIL_CRMESSAGE + +#include "variant.h" +#ifdef __cplusplus +extern "C" { +#endif + +struct locale; +struct message; +struct message_type; + +typedef int (*tostring_f)(variant data, char * buffer, const void * userdata); +extern void tsf_register(const char * name, tostring_f fun); + /* registers a new type->string-function */ + +extern int cr_string(variant v, char * buffer, const void * userdata); +extern int cr_int(variant v, char * buffer, const void * userdata); +extern int cr_ignore(variant v, char * buffer, const void * userdata); + +extern void crt_register(const struct message_type * mtype); +extern int cr_render(const struct message * msg, char * buffer, const void * userdata); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/cvector.c b/src/util/cvector.c index 27c395908..fbbd10f8c 100644 --- a/src/util/cvector.c +++ b/src/util/cvector.c @@ -1,97 +1,97 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "cvector.h" -#include "rng.h" - -#include -#include -#include -#include - -void -cv_init(cvector * cv) -{ - cv->begin = 0; - cv->end = 0; - cv->space = 0; -} - -cvector * -cv_kill(cvector * cv) -{ - if (cv->begin) free(cv->begin); - cv_init(cv); - return cv; -} - -size_t -cv_size(cvector * cv) -{ - return cv->end - cv->begin; -} - -void -cv_reserve(cvector * cv, size_t size) -{ - size_t count = cv->end - cv->begin; - cv->begin = realloc(cv->begin, size * sizeof(void *)); - - cv->space = size; - cv->end = cv->begin + count; -} - -void -cv_pushback(cvector * cv, void *u) -{ - if (cv->space == cv_size(cv)) - cv_reserve(cv, cv->space ? cv->space * 2 : 2); - *(cv->end++) = u; -} - -int -__cv_scramblecmp(const void *p1, const void *p2) -{ - return *((long *) p1) - *((long *) p2); -} - -#define addptr(p,i) ((void *)(((char *)p) + i)) - -/** randomly shuffle an array - * for correctness, see Donald E. Knuth, The Art of Computer Programming - */ -static void -__cv_scramble(void *v1, size_t n, size_t width) -{ - size_t i; - void * temp = malloc(width); - for (i=0;i!=n;++i) { - size_t j = i + (rng_int() % (n-i)); - memcpy(temp, addptr(v1, i*width), width); - memcpy(addptr(v1, i*width), addptr(v1, j*width), width); - memcpy(addptr(v1, j*width), temp, width); - } - free(temp); -} - -void -v_scramble(void **begin, void **end) -{ - __cv_scramble(begin, end - begin, sizeof(void *)); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "cvector.h" +#include "rng.h" + +#include +#include +#include +#include + +void +cv_init(cvector * cv) +{ + cv->begin = 0; + cv->end = 0; + cv->space = 0; +} + +cvector * +cv_kill(cvector * cv) +{ + if (cv->begin) free(cv->begin); + cv_init(cv); + return cv; +} + +size_t +cv_size(cvector * cv) +{ + return cv->end - cv->begin; +} + +void +cv_reserve(cvector * cv, size_t size) +{ + size_t count = cv->end - cv->begin; + cv->begin = realloc(cv->begin, size * sizeof(void *)); + + cv->space = size; + cv->end = cv->begin + count; +} + +void +cv_pushback(cvector * cv, void *u) +{ + if (cv->space == cv_size(cv)) + cv_reserve(cv, cv->space ? cv->space * 2 : 2); + *(cv->end++) = u; +} + +int +__cv_scramblecmp(const void *p1, const void *p2) +{ + return *((long *) p1) - *((long *) p2); +} + +#define addptr(p,i) ((void *)(((char *)p) + i)) + +/** randomly shuffle an array + * for correctness, see Donald E. Knuth, The Art of Computer Programming + */ +static void +__cv_scramble(void *v1, size_t n, size_t width) +{ + size_t i; + void * temp = malloc(width); + for (i=0;i!=n;++i) { + size_t j = i + (rng_int() % (n-i)); + memcpy(temp, addptr(v1, i*width), width); + memcpy(addptr(v1, i*width), addptr(v1, j*width), width); + memcpy(addptr(v1, j*width), temp, width); + } + free(temp); +} + +void +v_scramble(void **begin, void **end) +{ + __cv_scramble(begin, end - begin, sizeof(void *)); +} diff --git a/src/util/cvector.h b/src/util/cvector.h index c0e50944d..6b647e580 100644 --- a/src/util/cvector.h +++ b/src/util/cvector.h @@ -1,61 +1,61 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef CVECTOR_H -#define CVECTOR_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WIN32 -#ifndef __cdecl -#define __cdecl -#endif -#endif - -#include -typedef struct cvector cvector; - -struct cvector { - void **begin; - void **end; - size_t space; -}; - -typedef int (__cdecl * v_sort_fun) (const void *, const void *); - -void cv_init(cvector * cv); -cvector *cv_kill(cvector * cv); -size_t cv_size(cvector * cv); -void cv_reserve(cvector * cv, size_t size); -void cv_pushback(cvector * cv, void *u); -void v_scramble(void **begin, void **end); - -#define cv_remove(c, i) { void** x = v_find((c)->begin, (c)->end, (i)); if (x) { *x = *(c)->end; (c)->end--; } } -#define cv_foreach(item, vector) \ -{ \ - void **iterator; \ - for (iterator = (vector).begin; iterator<(vector).end; ++iterator) \ - { \ - (item) = *iterator; -#define cv_next(item) } } - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CVECTOR_H +#define CVECTOR_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WIN32 +#ifndef __cdecl +#define __cdecl +#endif +#endif + +#include +typedef struct cvector cvector; + +struct cvector { + void **begin; + void **end; + size_t space; +}; + +typedef int (__cdecl * v_sort_fun) (const void *, const void *); + +void cv_init(cvector * cv); +cvector *cv_kill(cvector * cv); +size_t cv_size(cvector * cv); +void cv_reserve(cvector * cv, size_t size); +void cv_pushback(cvector * cv, void *u); +void v_scramble(void **begin, void **end); + +#define cv_remove(c, i) { void** x = v_find((c)->begin, (c)->end, (i)); if (x) { *x = *(c)->end; (c)->end--; } } +#define cv_foreach(item, vector) \ +{ \ + void **iterator; \ + for (iterator = (vector).begin; iterator<(vector).end; ++iterator) \ + { \ + (item) = *iterator; +#define cv_next(item) } } + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/dice.c b/src/util/dice.c index bf8593d0c..8e9fc5df5 100644 --- a/src/util/dice.c +++ b/src/util/dice.c @@ -1,97 +1,97 @@ -/* vi: set ts=2: - * - * - * Eressea PB(E)M host Copyright (C) 1998 - * Enno Rehling (rehling@usa.net) - * Christian Schlittchen (corwin@amber.kn-bremen.de) - * Katja Zedel (katze@felidae.kn-bremen.de) - * Henning Peters (faroul@beyond.kn-bremen.de) - * - * based on: - * - * Atlantis v1.0 13 September 1993 Copyright 1993 by Russell Wallace - * Atlantis v1.7 Copyright 1996 by Alex Schröder - * - * This program may not be used, modified or distributed. It may not be - * sold or used commercially without prior written permission from the - * authors. - */ - -#include -#include "rng.h" - -#include -#include -#include - -/** rolls a number of n-sided dice. - * Usage: 3d6-3d4+5 = dice(3,6)-dice(3,4)+5 */ -int -dice(int count, int value) -{ - int d = 0, c; - - if (value<=0) return 0; /* (enno) %0 geht nicht. echt wahr. */ - if (count >= 0) - for (c = count; c > 0; c--) - d += rng_int() % value + 1; - else - for (c = count; c < 0; c++) - d -= rng_int() % value + 1; - - return d; -} - -static int -term_eval(const char **sptr) -{ - const char *c = *sptr; - int m = 0, d = 0, k = 0, term = 1, multi = 1; - int state = 1; - - for (;;) { - if (isdigit(*(unsigned char*)c)) { - k = k*10+(*c-'0'); - } - else if (*c=='+' || *c=='-' || *c==0 || *c=='*' || *c==')' || *c=='(') { - if (state==1) /* konstante k addieren */ - m+=k*multi; - else if (state==2) { /* dDk */ - int i; - if (k == 0) k = 6; /* 3d == 3d6 */ - for (i=0;i!=d;++i) m += (1 + rng_int() % k)*multi; - } - else assert(!"dice_rand: illegal token"); - if (*c=='*') { - term *= m; - m = 0; - } - k = d = 0; - state = 1; - multi = (*c=='-')?-1:1; - - if (*c=='(') { - ++c; - k = term_eval(&c); - } - else if (*c==0 || *c==')') { - break; - } - } else if (*c=='d' || *c=='D') { - if (k==0) k = 1; /* d9 == 1d9 */ - assert(state==1 || !"dice_rand: illegal token"); - d = k; - k = 0; - state=2; - } - c++; - } - *sptr = c; - return m*term; -} - -int -dice_rand(const char *s) -{ - return term_eval(&s); -} +/* vi: set ts=2: + * + * + * Eressea PB(E)M host Copyright (C) 1998 + * Enno Rehling (rehling@usa.net) + * Christian Schlittchen (corwin@amber.kn-bremen.de) + * Katja Zedel (katze@felidae.kn-bremen.de) + * Henning Peters (faroul@beyond.kn-bremen.de) + * + * based on: + * + * Atlantis v1.0 13 September 1993 Copyright 1993 by Russell Wallace + * Atlantis v1.7 Copyright 1996 by Alex Schröder + * + * This program may not be used, modified or distributed. It may not be + * sold or used commercially without prior written permission from the + * authors. + */ + +#include +#include "rng.h" + +#include +#include +#include + +/** rolls a number of n-sided dice. + * Usage: 3d6-3d4+5 = dice(3,6)-dice(3,4)+5 */ +int +dice(int count, int value) +{ + int d = 0, c; + + if (value<=0) return 0; /* (enno) %0 geht nicht. echt wahr. */ + if (count >= 0) + for (c = count; c > 0; c--) + d += rng_int() % value + 1; + else + for (c = count; c < 0; c++) + d -= rng_int() % value + 1; + + return d; +} + +static int +term_eval(const char **sptr) +{ + const char *c = *sptr; + int m = 0, d = 0, k = 0, term = 1, multi = 1; + int state = 1; + + for (;;) { + if (isdigit(*(unsigned char*)c)) { + k = k*10+(*c-'0'); + } + else if (*c=='+' || *c=='-' || *c==0 || *c=='*' || *c==')' || *c=='(') { + if (state==1) /* konstante k addieren */ + m+=k*multi; + else if (state==2) { /* dDk */ + int i; + if (k == 0) k = 6; /* 3d == 3d6 */ + for (i=0;i!=d;++i) m += (1 + rng_int() % k)*multi; + } + else assert(!"dice_rand: illegal token"); + if (*c=='*') { + term *= m; + m = 0; + } + k = d = 0; + state = 1; + multi = (*c=='-')?-1:1; + + if (*c=='(') { + ++c; + k = term_eval(&c); + } + else if (*c==0 || *c==')') { + break; + } + } else if (*c=='d' || *c=='D') { + if (k==0) k = 1; /* d9 == 1d9 */ + assert(state==1 || !"dice_rand: illegal token"); + d = k; + k = 0; + state=2; + } + c++; + } + *sptr = c; + return m*term; +} + +int +dice_rand(const char *s) +{ + return term_eval(&s); +} diff --git a/src/util/encoding.h b/src/util/encoding.h new file mode 100644 index 000000000..f2cc22d5f --- /dev/null +++ b/src/util/encoding.h @@ -0,0 +1,19 @@ +#ifndef ENCODING_H +#define ENCODING_H +#ifdef __cplusplus +extern "C" { +#endif + +enum { + ENCODING_ERROR = -1, + ENCODING_NONE = 0, + ENCODING_8859_1 = 1, + ENCODING_UTF8 = 10 +}; + +int get_encoding_by_name(const char * name); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/event.c b/src/util/event.c index 50f652ec2..977af7ffe 100644 --- a/src/util/event.c +++ b/src/util/event.c @@ -1,270 +1,270 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "event.h" - -/* util includes */ -#include "attrib.h" -#include "log.h" -#include "storage.h" - -/* libc includes */ -#include -#include -#include -#include - -void -write_triggers(struct storage * store, const trigger * t) -{ - while (t) { - if (t->type->write) { - store->w_tok(store, t->type->name); - t->type->write(t, store); - } - t = t->next; - } - store->w_tok(store, "end"); -} - -int -read_triggers(struct storage * store, trigger ** tp) -{ - for (;;) { - trigger_type * ttype; - char zText[128]; - - store->r_tok_buf(store, zText, sizeof(zText)); - if (!strcmp(zText, "end")) break; - ttype = tt_find(zText); - assert(ttype || !"unknown trigger-type"); - *tp = t_new(ttype); - if (ttype->read) { - int i = ttype->read(*tp, store); - switch (i) { - case AT_READ_OK: - tp = &(*tp)->next; - break; - case AT_READ_FAIL: - t_free(*tp); - *tp = NULL; - break; - default: - assert(!"invalid return value"); - break; - } - } - } - return 0; -} - -trigger * -t_new(trigger_type * ttype) -{ - trigger * t = calloc(sizeof(trigger), 1); - t->type=ttype; - if (ttype->initialize) ttype->initialize(t); - return t; -} - -void -t_free(trigger * t) -{ - if (t->type->finalize) t->type->finalize(t); -} - -void -free_triggers(trigger * triggers) -{ - while (triggers) { - trigger * t = triggers; - triggers = t->next; - t_free(t); - } -} - -int -handle_triggers(trigger ** triggers, void * param) -{ - trigger ** tp = triggers; - while (*tp) { - trigger * t = *tp; - if (t->type->handle(t, param)!=0) { - *tp=t->next; - t_free(t); - } - else tp=&t->next; - } - return (*triggers!=NULL); -} - -/*** - ** at_eventhandler - **/ - -typedef struct handler_info { - char * event; - trigger * triggers; -} handler_info; - -static void -init_handler(attrib * a) { - a->data.v = calloc(sizeof(handler_info), 1); -} - -static void -free_handler(attrib * a) { - handler_info *hi = (handler_info*)a->data.v; - free_triggers(hi->triggers); - free(hi->event); - free(hi); -} - -static void -write_handler(const attrib * a, const void * owner, struct storage * store) -{ - handler_info *hi = (handler_info*)a->data.v; - store->w_tok(store, hi->event); - write_triggers(store, hi->triggers); -} - -static int -read_handler(attrib * a, void * owner, struct storage * store) -{ - char zText[128]; - handler_info *hi = (handler_info*)a->data.v; - - store->r_tok_buf(store, zText, sizeof(zText)); - hi->event = strdup(zText); - read_triggers(store, &hi->triggers); - if (hi->triggers!=NULL) { - return AT_READ_OK; - } - return AT_READ_FAIL; -} - -attrib_type at_eventhandler = { - "eventhandler", - init_handler, - free_handler, - NULL, - write_handler, - read_handler -}; - -struct trigger ** -get_triggers(struct attrib * ap, const char * eventname) -{ - handler_info * td = NULL; - attrib * a = a_find(ap, &at_eventhandler); - while (a!=NULL && a->type==&at_eventhandler) { - td = (handler_info *)a->data.v; - if (strcmp(td->event, eventname)==0) { - return &td->triggers; - } - a = a->next; - } - return NULL; -} - -void -add_trigger(struct attrib ** ap, const char * eventname, struct trigger * t) -{ - trigger ** tp; - handler_info * td = NULL; - attrib * a = a_find(*ap, &at_eventhandler); - assert(t->next==NULL); - while (a!=NULL && a->type==&at_eventhandler) { - td = (handler_info *)a->data.v; - if (!strcmp(td->event, eventname)) { - break; - } - a = a->next; - } - if (a==NULL || a->type!=&at_eventhandler) { - a = a_add(ap, a_new(&at_eventhandler)); - td = (handler_info *)a->data.v; - td->event = strdup(eventname); - } - tp = &td->triggers; - while (*tp) tp=&(*tp)->next; - *tp = t; -} - -void -handle_event(attrib * attribs, const char * eventname, void * data) -{ - while (attribs) { - if (attribs->type==&at_eventhandler) break; - attribs = attribs->nexttype; - } - while (attribs && attribs->type==&at_eventhandler) { - handler_info * tl = (handler_info*)attribs->data.v; - if (!strcmp(tl->event, eventname)) { - handler_info * tl = (handler_info*)attribs->data.v; - handle_triggers(&tl->triggers, data); - break; - } - attribs = attribs->next; - } -} - -void -t_add(struct trigger ** tlist, struct trigger * t) -{ - while (*tlist) tlist = &(*tlist)->next; - *tlist = t; -} - -static trigger_type * triggertypes; - -void -tt_register(trigger_type * tt) -{ - tt->next = triggertypes; - triggertypes = tt; -} - -trigger_type * -tt_find(const char * name) -{ - trigger_type * tt = triggertypes; - while (tt && strcmp(tt->name, name)) tt = tt->next; - return tt; -} - -void -remove_triggers(struct attrib ** ap, const char * eventname, const trigger_type * tt) -{ - trigger ** tp = get_triggers(*ap, eventname); - if(tp == NULL) return; - while (*tp) { - /* first, remove all gate-triggers */ - trigger * t = *tp; - if (t->type == tt) { - *tp = t->next; - t_free(t); - } else tp = &t->next; - } -} - -/*** - ** default events - **/ - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "event.h" + +/* util includes */ +#include "attrib.h" +#include "log.h" +#include "storage.h" + +/* libc includes */ +#include +#include +#include +#include + +void +write_triggers(struct storage * store, const trigger * t) +{ + while (t) { + if (t->type->write) { + store->w_tok(store, t->type->name); + t->type->write(t, store); + } + t = t->next; + } + store->w_tok(store, "end"); +} + +int +read_triggers(struct storage * store, trigger ** tp) +{ + for (;;) { + trigger_type * ttype; + char zText[128]; + + store->r_tok_buf(store, zText, sizeof(zText)); + if (!strcmp(zText, "end")) break; + ttype = tt_find(zText); + assert(ttype || !"unknown trigger-type"); + *tp = t_new(ttype); + if (ttype->read) { + int i = ttype->read(*tp, store); + switch (i) { + case AT_READ_OK: + tp = &(*tp)->next; + break; + case AT_READ_FAIL: + t_free(*tp); + *tp = NULL; + break; + default: + assert(!"invalid return value"); + break; + } + } + } + return 0; +} + +trigger * +t_new(trigger_type * ttype) +{ + trigger * t = calloc(sizeof(trigger), 1); + t->type=ttype; + if (ttype->initialize) ttype->initialize(t); + return t; +} + +void +t_free(trigger * t) +{ + if (t->type->finalize) t->type->finalize(t); +} + +void +free_triggers(trigger * triggers) +{ + while (triggers) { + trigger * t = triggers; + triggers = t->next; + t_free(t); + } +} + +int +handle_triggers(trigger ** triggers, void * param) +{ + trigger ** tp = triggers; + while (*tp) { + trigger * t = *tp; + if (t->type->handle(t, param)!=0) { + *tp=t->next; + t_free(t); + } + else tp=&t->next; + } + return (*triggers!=NULL); +} + +/*** + ** at_eventhandler + **/ + +typedef struct handler_info { + char * event; + trigger * triggers; +} handler_info; + +static void +init_handler(attrib * a) { + a->data.v = calloc(sizeof(handler_info), 1); +} + +static void +free_handler(attrib * a) { + handler_info *hi = (handler_info*)a->data.v; + free_triggers(hi->triggers); + free(hi->event); + free(hi); +} + +static void +write_handler(const attrib * a, const void * owner, struct storage * store) +{ + handler_info *hi = (handler_info*)a->data.v; + store->w_tok(store, hi->event); + write_triggers(store, hi->triggers); +} + +static int +read_handler(attrib * a, void * owner, struct storage * store) +{ + char zText[128]; + handler_info *hi = (handler_info*)a->data.v; + + store->r_tok_buf(store, zText, sizeof(zText)); + hi->event = strdup(zText); + read_triggers(store, &hi->triggers); + if (hi->triggers!=NULL) { + return AT_READ_OK; + } + return AT_READ_FAIL; +} + +attrib_type at_eventhandler = { + "eventhandler", + init_handler, + free_handler, + NULL, + write_handler, + read_handler +}; + +struct trigger ** +get_triggers(struct attrib * ap, const char * eventname) +{ + handler_info * td = NULL; + attrib * a = a_find(ap, &at_eventhandler); + while (a!=NULL && a->type==&at_eventhandler) { + td = (handler_info *)a->data.v; + if (strcmp(td->event, eventname)==0) { + return &td->triggers; + } + a = a->next; + } + return NULL; +} + +void +add_trigger(struct attrib ** ap, const char * eventname, struct trigger * t) +{ + trigger ** tp; + handler_info * td = NULL; + attrib * a = a_find(*ap, &at_eventhandler); + assert(t->next==NULL); + while (a!=NULL && a->type==&at_eventhandler) { + td = (handler_info *)a->data.v; + if (!strcmp(td->event, eventname)) { + break; + } + a = a->next; + } + if (a==NULL || a->type!=&at_eventhandler) { + a = a_add(ap, a_new(&at_eventhandler)); + td = (handler_info *)a->data.v; + td->event = strdup(eventname); + } + tp = &td->triggers; + while (*tp) tp=&(*tp)->next; + *tp = t; +} + +void +handle_event(attrib * attribs, const char * eventname, void * data) +{ + while (attribs) { + if (attribs->type==&at_eventhandler) break; + attribs = attribs->nexttype; + } + while (attribs && attribs->type==&at_eventhandler) { + handler_info * tl = (handler_info*)attribs->data.v; + if (!strcmp(tl->event, eventname)) { + handler_info * tl = (handler_info*)attribs->data.v; + handle_triggers(&tl->triggers, data); + break; + } + attribs = attribs->next; + } +} + +void +t_add(struct trigger ** tlist, struct trigger * t) +{ + while (*tlist) tlist = &(*tlist)->next; + *tlist = t; +} + +static trigger_type * triggertypes; + +void +tt_register(trigger_type * tt) +{ + tt->next = triggertypes; + triggertypes = tt; +} + +trigger_type * +tt_find(const char * name) +{ + trigger_type * tt = triggertypes; + while (tt && strcmp(tt->name, name)) tt = tt->next; + return tt; +} + +void +remove_triggers(struct attrib ** ap, const char * eventname, const trigger_type * tt) +{ + trigger ** tp = get_triggers(*ap, eventname); + if(tp == NULL) return; + while (*tp) { + /* first, remove all gate-triggers */ + trigger * t = *tp; + if (t->type == tt) { + *tp = t->next; + t_free(t); + } else tp = &t->next; + } +} + +/*** + ** default events + **/ + diff --git a/src/util/event.h b/src/util/event.h index 23f272952..6c5566c34 100644 --- a/src/util/event.h +++ b/src/util/event.h @@ -1,80 +1,80 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef EVENT_H -#define EVENT_H -#ifdef __cplusplus -extern "C" { -#endif - -#include "variant.h" - -struct attrib; -struct trigger; -struct storage; - -typedef struct trigger_type { - const char * name; - void (*initialize)(struct trigger *); - void (*finalize)(struct trigger *); - int (*handle)(struct trigger *, void *); - void (*write)(const struct trigger *, struct storage * store); - int (*read)(struct trigger *, struct storage * store); - - struct trigger_type * next; -} trigger_type; - -extern trigger_type * tt_find(const char * name); -extern void tt_register(trigger_type * ttype); - -typedef struct trigger { - struct trigger_type * type; - struct trigger * next; - - variant data; -} trigger; - -typedef struct event_arg { - const char * type; - variant data; -} event_arg; - -extern trigger * t_new(trigger_type * ttype); -extern void t_free(trigger * t); -extern void t_add(trigger ** tlist, trigger * t); -/** add and handle triggers **/ - -/* add a trigger to a list of attributes */ -extern void add_trigger(struct attrib ** ap, const char * eventname, struct trigger * t); -extern void remove_triggers(struct attrib ** ap, const char * eventname, const trigger_type * tt); -extern struct trigger ** get_triggers(struct attrib * ap, const char * eventname); -/* calls handle() for each of these. e.g. used in timeout */ -extern void handle_event(struct attrib * attribs, const char * eventname, void * data); - -/* functions for making complex triggers: */ -extern void free_triggers(trigger * triggers); /* release all these triggers */ -extern void write_triggers(struct storage * store, const trigger * t); -extern int read_triggers(struct storage * store, trigger ** tp); -extern int handle_triggers(trigger ** triggers, void * data); - -extern struct attrib_type at_eventhandler; - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef EVENT_H +#define EVENT_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "variant.h" + +struct attrib; +struct trigger; +struct storage; + +typedef struct trigger_type { + const char * name; + void (*initialize)(struct trigger *); + void (*finalize)(struct trigger *); + int (*handle)(struct trigger *, void *); + void (*write)(const struct trigger *, struct storage * store); + int (*read)(struct trigger *, struct storage * store); + + struct trigger_type * next; +} trigger_type; + +extern trigger_type * tt_find(const char * name); +extern void tt_register(trigger_type * ttype); + +typedef struct trigger { + struct trigger_type * type; + struct trigger * next; + + variant data; +} trigger; + +typedef struct event_arg { + const char * type; + variant data; +} event_arg; + +extern trigger * t_new(trigger_type * ttype); +extern void t_free(trigger * t); +extern void t_add(trigger ** tlist, trigger * t); +/** add and handle triggers **/ + +/* add a trigger to a list of attributes */ +extern void add_trigger(struct attrib ** ap, const char * eventname, struct trigger * t); +extern void remove_triggers(struct attrib ** ap, const char * eventname, const trigger_type * tt); +extern struct trigger ** get_triggers(struct attrib * ap, const char * eventname); +/* calls handle() for each of these. e.g. used in timeout */ +extern void handle_event(struct attrib * attribs, const char * eventname, void * data); + +/* functions for making complex triggers: */ +extern void free_triggers(trigger * triggers); /* release all these triggers */ +extern void write_triggers(struct storage * store, const trigger * t); +extern int read_triggers(struct storage * store, trigger ** tp); +extern int handle_triggers(trigger ** triggers, void * data); + +extern struct attrib_type at_eventhandler; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/eventbus.c b/src/util/eventbus.c index 77e81b578..e9cdebbee 100644 --- a/src/util/eventbus.c +++ b/src/util/eventbus.c @@ -1,56 +1,56 @@ -#include -#include "eventbus.h" - -/* -** first iteration. it is slow, and a proof of the concept - the simplest -** thing that would work, a.k.a. should be refectored when required. -*/ - -typedef struct listener { - struct listener * next; - event_handler callback; - event_arg_free destroy; - void * sender; - char * event; - void * arguments; -} listener; - -static listener * listeners; - -void -eventbus_fire(void * sender, const char * event, void * args) -{ - listener * lst = listeners; - while (lst) { - int i = strcmp(lst->event, event); - if (i>0) break; - if (i==0) { - if (!lst->sender || lst->sender==sender) { - lst->callback(sender, event, args); - } - } - lst = lst->next; - } -} - -void -eventbus_register(void * sender, const char * event, event_handler cb, event_arg_free arg_free, void * args) -{ - listener * lst; - listener ** lstp = &listeners; - while (*lstp) { - lst = *lstp; - if (strcmp(lst->event, event)>=0) { - break; - } - lstp=&lst->next; - } - lst = malloc(sizeof(listener)); - lst->sender = sender; - lst->arguments = args; - lst->callback = cb; - lst->destroy = arg_free; - lst->event = strdup(event); - lst->next = *lstp; - *lstp = lst; -} +#include +#include "eventbus.h" + +/* +** first iteration. it is slow, and a proof of the concept - the simplest +** thing that would work, a.k.a. should be refectored when required. +*/ + +typedef struct listener { + struct listener * next; + event_handler callback; + event_arg_free destroy; + void * sender; + char * event; + void * arguments; +} listener; + +static listener * listeners; + +void +eventbus_fire(void * sender, const char * event, void * args) +{ + listener * lst = listeners; + while (lst) { + int i = strcmp(lst->event, event); + if (i>0) break; + if (i==0) { + if (!lst->sender || lst->sender==sender) { + lst->callback(sender, event, args); + } + } + lst = lst->next; + } +} + +void +eventbus_register(void * sender, const char * event, event_handler cb, event_arg_free arg_free, void * args) +{ + listener * lst; + listener ** lstp = &listeners; + while (*lstp) { + lst = *lstp; + if (strcmp(lst->event, event)>=0) { + break; + } + lstp=&lst->next; + } + lst = malloc(sizeof(listener)); + lst->sender = sender; + lst->arguments = args; + lst->callback = cb; + lst->destroy = arg_free; + lst->event = strdup(event); + lst->next = *lstp; + *lstp = lst; +} diff --git a/src/util/eventbus.h b/src/util/eventbus.h index b217c686c..d7352cb51 100644 --- a/src/util/eventbus.h +++ b/src/util/eventbus.h @@ -1,29 +1,29 @@ -/* vi: set ts=2: - +-------------------+ - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2010 | Christian Schlittchen - | | - +-------------------+ - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_UTIL_EVTBUS -#define H_UTIL_EVTBUS - - -#ifdef __cplusplus -extern "C" { -#endif - - typedef void (*event_handler)(void *, const char *, void *); - typedef void (*event_arg_free)(void *); - void eventbus_fire(void * sender, const char * event, void * args); - void eventbus_register(void * sender, const char * event, event_handler callback, event_arg_free arg_free, void * args); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2010 | Christian Schlittchen + | | + +-------------------+ + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_UTIL_EVTBUS +#define H_UTIL_EVTBUS + + +#ifdef __cplusplus +extern "C" { +#endif + + typedef void (*event_handler)(void *, const char *, void *); + typedef void (*event_arg_free)(void *); + void eventbus_fire(void * sender, const char * event, void * args); + void eventbus_register(void * sender, const char * event, event_handler callback, event_arg_free arg_free, void * args); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/filereader.c b/src/util/filereader.c index 26c745851..0b309959a 100644 --- a/src/util/filereader.c +++ b/src/util/filereader.c @@ -1,314 +1,314 @@ -#include -#include "filereader.h" - -#include -#include - -#include - -#include -#include - -#define COMMENT_CHAR ';' -#define CONTINUE_CHAR '\\' -#define MAXLINE 4096*16 -static char lbuf[MAXLINE]; -static char fbuf[MAXLINE]; - -static void -unicode_warning(const char * bp) -{ - log_warning(("invalid sequence in UTF-8 string: %s\n", bp)); -} - -INLINE_FUNCTION int -eatwhite(const char * ptr, size_t * total_size) -{ - int ret = 0; - - *total_size = 0; - - while (*ptr) { - ucs4_t ucs; - size_t size = 0; - ret = unicode_utf8_to_ucs4(&ucs, ptr, &size); - if (ret!=0) break; - if (!iswxspace((wint_t)ucs)) break; - *total_size += size; - ptr += size; - } - return ret; -} - -static const char * -getbuf_latin1(FILE * F) -{ - boolean cont = false; - char quote = 0; - boolean comment = false; - char * cp = fbuf; - char * tail = lbuf+MAXLINE-2; - - tail[1] = '@'; /* if this gets overwritten by fgets then the line was very long. */ - do { - const char * bp = fgets(lbuf, MAXLINE, F); - - if (bp==NULL) return NULL; - while (*bp && isxspace(*(unsigned char*)bp)) ++bp; /* eatwhite */ - - comment = (boolean)(comment && cont); - - if (tail[1]==0) { - /* we read he maximum number of bytes! */ - if (tail[0]!='\n') { - /* it wasn't enough space to finish the line, eat the rest */ - for (;;) { - tail[1] = '@'; - bp = fgets(lbuf, MAXLINE, F); - if (bp==NULL) return NULL; - if (tail[1]) { - /* read enough this time to end the line */ - break; - } - } - comment = false; - cont = false; - bp = NULL; - continue; - } else { - tail[1] = '@'; - } - } - cont = false; - while (*bp && cp0) cp+=ret; - else { - log_error(("input data was not iso-8859-1! assuming utf-8\n")); - return NULL; - } - - ++bp; - continue; - } - } - if (cp==fbuf+MAXLINE) { - --cp; - } - *cp=0; - } while (cont || cp==fbuf); - return fbuf; -} - -static const char * -getbuf_utf8(FILE * F) -{ - boolean cont = false; - char quote = 0; - boolean comment = false; - char * cp = fbuf; - char * tail = lbuf+MAXLINE-2; - - tail[1] = '@'; /* if this gets overwritten by fgets then the line was very long. */ - do { - const char * bp = fgets(lbuf, MAXLINE, F); - size_t white; - if (bp==NULL) { - return NULL; - } - - eatwhite(bp, &white); /* decoding errors will get caught later on, don't have to check */ - bp += white; - - comment = (boolean)(comment && cont); - - if (tail[1]==0) { - /* we read he maximum number of bytes! */ - if (tail[0]!='\n') { - /* it wasn't enough space to finish the line, eat the rest */ - for (;;) { - tail[1] = '@'; - bp = fgets(lbuf, MAXLINE, F); - if (bp==NULL) return NULL; - if (tail[1]) { - /* read enough this time to end the line */ - break; - } - } - comment = false; - cont = false; - bp = NULL; - continue; - } else { - tail[1] = '@'; - } - } - cont = false; - while (*bp && cp +#include "filereader.h" + +#include +#include + +#include + +#include +#include + +#define COMMENT_CHAR ';' +#define CONTINUE_CHAR '\\' +#define MAXLINE 4096*16 +static char lbuf[MAXLINE]; +static char fbuf[MAXLINE]; + +static void +unicode_warning(const char * bp) +{ + log_warning(("invalid sequence in UTF-8 string: %s\n", bp)); +} + +INLINE_FUNCTION int +eatwhite(const char * ptr, size_t * total_size) +{ + int ret = 0; + + *total_size = 0; + + while (*ptr) { + ucs4_t ucs; + size_t size = 0; + ret = unicode_utf8_to_ucs4(&ucs, ptr, &size); + if (ret!=0) break; + if (!iswxspace((wint_t)ucs)) break; + *total_size += size; + ptr += size; + } + return ret; +} + +static const char * +getbuf_latin1(FILE * F) +{ + boolean cont = false; + char quote = 0; + boolean comment = false; + char * cp = fbuf; + char * tail = lbuf+MAXLINE-2; + + tail[1] = '@'; /* if this gets overwritten by fgets then the line was very long. */ + do { + const char * bp = fgets(lbuf, MAXLINE, F); + + if (bp==NULL) return NULL; + while (*bp && isxspace(*(unsigned char*)bp)) ++bp; /* eatwhite */ + + comment = (boolean)(comment && cont); + + if (tail[1]==0) { + /* we read he maximum number of bytes! */ + if (tail[0]!='\n') { + /* it wasn't enough space to finish the line, eat the rest */ + for (;;) { + tail[1] = '@'; + bp = fgets(lbuf, MAXLINE, F); + if (bp==NULL) return NULL; + if (tail[1]) { + /* read enough this time to end the line */ + break; + } + } + comment = false; + cont = false; + bp = NULL; + continue; + } else { + tail[1] = '@'; + } + } + cont = false; + while (*bp && cp0) cp+=ret; + else { + log_error(("input data was not iso-8859-1! assuming utf-8\n")); + return NULL; + } + + ++bp; + continue; + } + } + if (cp==fbuf+MAXLINE) { + --cp; + } + *cp=0; + } while (cont || cp==fbuf); + return fbuf; +} + +static const char * +getbuf_utf8(FILE * F) +{ + boolean cont = false; + char quote = 0; + boolean comment = false; + char * cp = fbuf; + char * tail = lbuf+MAXLINE-2; + + tail[1] = '@'; /* if this gets overwritten by fgets then the line was very long. */ + do { + const char * bp = fgets(lbuf, MAXLINE, F); + size_t white; + if (bp==NULL) { + return NULL; + } + + eatwhite(bp, &white); /* decoding errors will get caught later on, don't have to check */ + bp += white; + + comment = (boolean)(comment && cont); + + if (tail[1]==0) { + /* we read he maximum number of bytes! */ + if (tail[0]!='\n') { + /* it wasn't enough space to finish the line, eat the rest */ + for (;;) { + tail[1] = '@'; + bp = fgets(lbuf, MAXLINE, F); + if (bp==NULL) return NULL; + if (tail[1]) { + /* read enough this time to end the line */ + break; + } + } + comment = false; + cont = false; + bp = NULL; + continue; + } else { + tail[1] = '@'; + } + } + cont = false; + while (*bp && cp -* | | Enno Rehling -* | Eressea PBEM host | Katja Zedel -* | (c) 1998 - 2005 | -* | | This program may not be used, modified or distributed -* +-------------------+ without prior permission by the authors of Eressea. -* -*/ -#ifndef UTIL_FILEREADER_H -#define UTIL_FILEREADER_H -#ifdef __cplusplus -extern "C" { -#endif - -const char * getbuf(FILE *, int encoding); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: +* +-------------------+ Christian Schlittchen +* | | Enno Rehling +* | Eressea PBEM host | Katja Zedel +* | (c) 1998 - 2005 | +* | | This program may not be used, modified or distributed +* +-------------------+ without prior permission by the authors of Eressea. +* +*/ +#ifndef UTIL_FILEREADER_H +#define UTIL_FILEREADER_H +#ifdef __cplusplus +extern "C" { +#endif + +const char * getbuf(FILE *, int encoding); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/functions.c b/src/util/functions.c index 81b9face6..e8f488333 100644 --- a/src/util/functions.c +++ b/src/util/functions.c @@ -1,74 +1,74 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "functions.h" - -/* libc includes */ -#include -#include - - - -typedef struct function_list { - struct function_list * next; - pf_generic fun; - const char * name; -} function_list; - -static function_list * functionlist; - -pf_generic -get_function(const char * name) -{ - function_list * fl = functionlist; - if (name==NULL) return NULL; - while (fl && strcmp(fl->name, name)!=0) fl=fl->next; - if (fl) return fl->fun; - return NULL; -} - -const char * -get_functionname(pf_generic fun) -{ - function_list * fl = functionlist; - while (fl && fl->fun!=fun) fl=fl->next; - if (fl) return fl->name; - return NULL; -} - -void -register_function(pf_generic fun, const char * name) -{ - function_list * fl = calloc(sizeof(function_list), 1); - fl->next = functionlist; - fl->fun = fun; - fl->name = strdup(name); - functionlist = fl; -} - -void -list_registered_functions(void) -{ - function_list * fl = functionlist; - - while(fl) { - printf("%s\n", fl->name); - fl = fl->next; - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "functions.h" + +/* libc includes */ +#include +#include + + + +typedef struct function_list { + struct function_list * next; + pf_generic fun; + const char * name; +} function_list; + +static function_list * functionlist; + +pf_generic +get_function(const char * name) +{ + function_list * fl = functionlist; + if (name==NULL) return NULL; + while (fl && strcmp(fl->name, name)!=0) fl=fl->next; + if (fl) return fl->fun; + return NULL; +} + +const char * +get_functionname(pf_generic fun) +{ + function_list * fl = functionlist; + while (fl && fl->fun!=fun) fl=fl->next; + if (fl) return fl->name; + return NULL; +} + +void +register_function(pf_generic fun, const char * name) +{ + function_list * fl = calloc(sizeof(function_list), 1); + fl->next = functionlist; + fl->fun = fun; + fl->name = strdup(name); + functionlist = fl; +} + +void +list_registered_functions(void) +{ + function_list * fl = functionlist; + + while(fl) { + printf("%s\n", fl->name); + fl = fl->next; + } +} diff --git a/src/util/functions.h b/src/util/functions.h index f8fd090a6..da80ddeba 100644 --- a/src/util/functions.h +++ b/src/util/functions.h @@ -1,35 +1,35 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef FUNCTIONS_H -#define FUNCTIONS_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*pf_generic)(void); - -extern const char *get_functionname(pf_generic fun); -extern pf_generic get_function(const char * name); -extern void register_function(pf_generic fun, const char * name); -extern void list_registered_functions(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef FUNCTIONS_H +#define FUNCTIONS_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*pf_generic)(void); + +extern const char *get_functionname(pf_generic fun); +extern pf_generic get_function(const char * name); +extern void register_function(pf_generic fun, const char * name); +extern void list_registered_functions(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/goodies.c b/src/util/goodies.c index 231bbd9e9..c49d02772 100644 --- a/src/util/goodies.c +++ b/src/util/goodies.c @@ -1,128 +1,154 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "goodies.h" - -#include "unicode.h" - -/* libc includes */ -#include -#include -#include - -/* Simple Integer-Liste */ - -int * -intlist_init(void) -{ - return (calloc(1, sizeof(int))); -} - -int * -intlist_add(int *i_p, int i) -{ - i_p[0]++; - i_p = realloc(i_p, (i_p[0]+1) * sizeof(int)); - - i_p[i_p[0]] = i; - return (i_p); -} - -int * -intlist_find(int *i_p, int fi) -{ - int i; - - for(i=1; i <= i_p[0]; i++) { - if(i_p[i] == fi) return (&i_p[i]); - } - return NULL; -} - -char * -set_string (char **s, const char *neu) -{ - if (neu==NULL) { - free(*s); - *s = NULL; - } else if (*s == NULL) { - *s = malloc(strlen(neu)+1); - strcpy(*s, neu); - } else { - *s = realloc(*s, strlen(neu) + 1); - strcpy(*s, neu); - } - return *s; -} - - -static int -spc_email_isvalid(const char *address) -{ - int count = 0; - const char *c, *domain; - static const char *rfc822_specials = "()<>@,;:\\\"[]"; /* STATIC_CONST: contains a constant value */ - - /* first we validate the name portion (name@domain) */ - for (c = address; *c; c++) { - if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == - '\"')) { - while (*++c) { - if (*c == '\"') break; - if (*c == '\\' && (*++c == ' ')) continue; - if (*c <= ' ' || *c >= 127) return 0; - } - if (!*c++) return 0; - if (*c == '@') break; - if (*c != '.') return 0; - continue; - } - if (*c == '@') break; - if (*c <= ' ' || *c >= 127) return 0; - if (strchr(rfc822_specials, *c)) return 0; - } - if (c == address || *(c - 1) == '.') return 0; - - /* next we validate the domain portion (name@domain) */ - if (!*(domain = ++c)) return 0; - do { - if (*c == '.') { - if (c == domain || *(c - 1) == '.') return 0; - count++; - } - if (*c <= ' ' || *c >= 127) return 0; - if (strchr(rfc822_specials, *c)) return 0; - } while (*++c); - - return (count >= 1); -} - -int -set_email(char** pemail, const char *newmail) -{ - if (newmail && *newmail) { - if (spc_email_isvalid(newmail)<=0) return -1; - } - if (*pemail) free(*pemail); - *pemail = 0; - if (newmail) { - *pemail = strdup(newmail); - } - return 0; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "goodies.h" + +#include "unicode.h" + +/* libc includes */ +#include +#include +#include + +/* Simple Integer-Liste */ + +int * +intlist_init(void) +{ + return (calloc(1, sizeof(int))); +} + +int * +intlist_add(int *i_p, int i) +{ + i_p[0]++; + i_p = realloc(i_p, (i_p[0]+1) * sizeof(int)); + + i_p[i_p[0]] = i; + return (i_p); +} + +int * +intlist_find(int *i_p, int fi) +{ + int i; + + for(i=1; i <= i_p[0]; i++) { + if(i_p[i] == fi) return (&i_p[i]); + } + return NULL; +} + +char * +set_string (char **s, const char *neu) +{ + if (neu==NULL) { + free(*s); + *s = NULL; + } else if (*s == NULL) { + *s = malloc(strlen(neu)+1); + strcpy(*s, neu); + } else { + *s = realloc(*s, strlen(neu) + 1); + strcpy(*s, neu); + } + return *s; +} + + +static int +spc_email_isvalid(const char *address) +{ + int count = 0; + const char *c, *domain; + static const char *rfc822_specials = "()<>@,;:\\\"[]"; /* STATIC_CONST: contains a constant value */ + + /* first we validate the name portion (name@domain) */ + for (c = address; *c; c++) { + if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == + '\"')) { + while (*++c) { + if (*c == '\"') break; + if (*c == '\\' && (*++c == ' ')) continue; + if (*c <= ' ' || *c >= 127) return 0; + } + if (!*c++) return 0; + if (*c == '@') break; + if (*c != '.') return 0; + continue; + } + if (*c == '@') break; + if (*c <= ' ' || *c >= 127) return 0; + if (strchr(rfc822_specials, *c)) return 0; + } + if (c == address || *(c - 1) == '.') return 0; + + /* next we validate the domain portion (name@domain) */ + if (!*(domain = ++c)) return 0; + do { + if (*c == '.') { + if (c == domain || *(c - 1) == '.') return 0; + count++; + } + if (*c <= ' ' || *c >= 127) return 0; + if (strchr(rfc822_specials, *c)) return 0; + } while (*++c); + + return (count >= 1); +} + +int +set_email(char** pemail, const char *newmail) +{ + if (newmail && *newmail) { + if (spc_email_isvalid(newmail)<=0) return -1; + } + if (*pemail) free(*pemail); + *pemail = 0; + if (newmail) { + *pemail = strdup(newmail); + } + return 0; +} + +#include "encoding.h" +#include + +static struct { + int encoding; + const char * names; +} encodings[] = { + { ENCODING_UTF8, " utf8 utf-8 UTF8 UTF-8 "}, + { ENCODING_8859_1, " iso8859-1 latin1 latin-1 iso-8859-1 ISO8859-1 LATIN1 LATIN-1 ISO-8859-1 "}, + { ENCODING_NONE, 0 } +}; + +int +get_encoding_by_name(const char * name) +{ + char str[32]; + int i; + snprintf(str, 32, " %s ", name); + for (i=0;encodings[i].encoding!=ENCODING_NONE;++i) { + if (strstr(encodings[i].names, str)) { + return encodings[i].encoding; + } + } + return ENCODING_NONE; +} diff --git a/src/util/goodies.h b/src/util/goodies.h index aabf0cb4b..50dc7cb40 100644 --- a/src/util/goodies.h +++ b/src/util/goodies.h @@ -1,63 +1,63 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef GOODIES_H -#define GOODIES_H -#ifdef __cplusplus -extern "C" { -#endif - -extern char * set_string(char **s, const char *neu); -extern int set_email(char** pemail, const char *newmail); - -extern int *intlist_init(void); -extern int *intlist_add(int *i_p, int i); -extern int *intlist_find(int *i_p, int i); - -#ifdef HAVE_INLINE -# include "strings.c" -#else -extern unsigned int hashstring(const char* s); -extern const char *escape_string(const char * str, char * buffer, unsigned int len); -extern unsigned int jenkins_hash(unsigned int a); -extern unsigned int wang_hash(unsigned int a); -#endif - -/* benchmark for units: - * JENKINS_HASH: 5.25 misses/hit (with good cache behavior) - * WANG_HASH: 5.33 misses/hit (with good cache behavior) - * KNUTH_HASH: 1.93 misses/hit (with bad cache behavior) - * CF_HASH: fucking awful! - */ -#define KNUTH_HASH1(a, m) ((a) % m) -#define KNUTH_HASH2(a, m) (m - 2 - a % (m-2)) -#define CF_HASH1(a, m) ((a) % m) -#define CF_HASH2(a, m) (8 - ((a) & 7)) -#define JENKINS_HASH1(a, m) (jenkins_hash(a) % m) -#define JENKINS_HASH2(a, m) 1 -#define WANG_HASH1(a, m) (wang_hash(a) % m) -#define WANG_HASH2(a, m) 1 - -#define HASH1 JENKINS_HASH1 -#define HASH2 JENKINS_HASH2 - -#define SWAP_VARS(T, a, b) { T x = a; a = b; b = x; } -#ifdef __cplusplus -} -#endif -#endif /* GOODIES_H */ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef GOODIES_H +#define GOODIES_H +#ifdef __cplusplus +extern "C" { +#endif + +extern char * set_string(char **s, const char *neu); +extern int set_email(char** pemail, const char *newmail); + +extern int *intlist_init(void); +extern int *intlist_add(int *i_p, int i); +extern int *intlist_find(int *i_p, int i); + +#ifdef HAVE_INLINE +# include "strings.c" +#else +extern unsigned int hashstring(const char* s); +extern const char *escape_string(const char * str, char * buffer, unsigned int len); +extern unsigned int jenkins_hash(unsigned int a); +extern unsigned int wang_hash(unsigned int a); +#endif + +/* benchmark for units: + * JENKINS_HASH: 5.25 misses/hit (with good cache behavior) + * WANG_HASH: 5.33 misses/hit (with good cache behavior) + * KNUTH_HASH: 1.93 misses/hit (with bad cache behavior) + * CF_HASH: fucking awful! + */ +#define KNUTH_HASH1(a, m) ((a) % m) +#define KNUTH_HASH2(a, m) (m - 2 - a % (m-2)) +#define CF_HASH1(a, m) ((a) % m) +#define CF_HASH2(a, m) (8 - ((a) & 7)) +#define JENKINS_HASH1(a, m) (jenkins_hash(a) % m) +#define JENKINS_HASH2(a, m) 1 +#define WANG_HASH1(a, m) (wang_hash(a) % m) +#define WANG_HASH2(a, m) 1 + +#define HASH1 JENKINS_HASH1 +#define HASH2 JENKINS_HASH2 + +#define SWAP_VARS(T, a, b) { T x = a; a = b; b = x; } +#ifdef __cplusplus +} +#endif +#endif /* GOODIES_H */ diff --git a/src/util/graph.c b/src/util/graph.c index 9ea181466..3e6f7aec1 100644 --- a/src/util/graph.c +++ b/src/util/graph.c @@ -1,203 +1,203 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - */ - -/* This is a very simple graph library. It is not optimized in any - way, and relies heavily on the vset and stack routines. */ - -#include -#include "vset.h" -#include "graph.h" - -void -graph_init(graph *g) -{ - vset_init(&g->nodes); - vset_init(&g->edges); -} - -void -graph_free(graph *g) -{ - vset_destroy(&g->nodes); - vset_destroy(&g->edges); -} - -void -graph_add_node(graph *g, node *n) -{ - vset_add(&g->nodes, n); -} - -void -graph_add_edge(graph *g, edge *v) -{ - vset_add(&g->nodes, v); -} - -void -graph_remove_node(graph *g, node *n) -{ - unsigned int i; - - for(i=0; i != g->edges.size; ++i) { - edge *v = g->edges.data[i]; - if(v->node1 == n || v->node2 == n) { - vset_erase(&g->nodes, v); - i--; - } - } - vset_erase(&g->nodes, n); -} - -node * -graph_find_node(graph *g, void *object) -{ - unsigned int i; - - for(i=0; i != g->nodes.size; ++i) { - node *node = g->nodes.data[i]; - if(node->object == object) { - return g->nodes.data[i]; - } - } - return NULL; -} - -/* The vset returned has to freed externally, else this will be a - memory leak. */ - -vset * -graph_neighbours(graph *g, node *n) -{ - unsigned int i; - vset * vs = malloc(sizeof(vs)); - vset_init(vs); - for(i=0; i != g->edges.size; ++i) { - edge *v = g->edges.data[i]; - if(v->node1 == n && vset_count(vs, v->node2) == 0) { - vset_add(vs, v->node2); - } else if(v->node2 == n && vset_count(vs, v->node1) == 0) { - vset_add(vs, v->node1); - } - } - - return vs; -} - -void -graph_resetmarkers(graph *g) -{ - unsigned int i; - - for(i=0; i != g->nodes.size; ++i) { - node *node = g->nodes.data[i]; - node->marker = 0; - } - for(i=0; i != g->edges.size; ++i) { - edge *edge = g->edges.data[i]; - edge->marker = 0; - } -} - -/* The vset returned has to freed externally, else this will be a - memory leak. */ - -vset * -graph_connected_nodes(graph *g, node *n) -{ - vset * vs = malloc(sizeof(vset)); - vset s; - - vset_init(vs); - vset_init(&s); - graph_resetmarkers(g); - vset_add(vs, n); - n->marker = 1; - vset_add(&s, n); - while(s.size > 0) { - node *n = vset_pop(&s); - vset *vs_nb = graph_neighbours(g, n); - unsigned int i; - for(i=0; i != vs_nb->size; ++i) { - node *nb = vs_nb->data[i]; - if(nb->marker == 0) { - nb->marker = 1; - vset_add(vs, nb); - vset_add(&s, nb); - } - } - vset_destroy(vs_nb); - free(vs_nb); - } - - vset_destroy(&s); - - return vs; -} - -/* The vset returned has to freed externally, else this will be a - memory leak. */ - -vset * -graph_disjunct_graphs(graph *g) -{ - vset * dg = malloc(sizeof(vset)); - vset nodes; - - vset_init(dg); - vset_init(&nodes); - vset_concat(&nodes, &g->nodes); - - while(nodes.size > 0) { - graph *gt = malloc(sizeof(graph)); - vset s; - unsigned int i; - node *start; - - graph_init(gt); - start = vset_pop(&nodes); - graph_resetmarkers(g); - graph_add_node(gt, start); - start->marker = 1; - vset_init(&s); - vset_add(&s,start); - while(s.size > 0) { - vset * nbs = graph_neighbours(g,vset_pop(&s)); - for(i=0; i != nbs->size; ++i) { - node *nb = nbs->data[i]; - if(nb->marker == 0) { - nb->marker = 1; - graph_add_node(gt,nb); - vset_erase(&nodes,nb); - vset_add(&s,nb); - } - } - vset_destroy(nbs); free(nbs); - } - - vset_destroy(&s); - - for(i=0;i != g->edges.size; ++i) { - edge *v = g->edges.data[i]; - if(vset_count(&g->nodes, v->node1)) { - graph_add_edge(gt, v); - } - } - - vset_add(dg, gt); - } - - vset_destroy(&nodes); - - return dg; -} - +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + */ + +/* This is a very simple graph library. It is not optimized in any + way, and relies heavily on the vset and stack routines. */ + +#include +#include "vset.h" +#include "graph.h" + +void +graph_init(graph *g) +{ + vset_init(&g->nodes); + vset_init(&g->edges); +} + +void +graph_free(graph *g) +{ + vset_destroy(&g->nodes); + vset_destroy(&g->edges); +} + +void +graph_add_node(graph *g, node *n) +{ + vset_add(&g->nodes, n); +} + +void +graph_add_edge(graph *g, edge *v) +{ + vset_add(&g->nodes, v); +} + +void +graph_remove_node(graph *g, node *n) +{ + unsigned int i; + + for(i=0; i != g->edges.size; ++i) { + edge *v = g->edges.data[i]; + if(v->node1 == n || v->node2 == n) { + vset_erase(&g->nodes, v); + i--; + } + } + vset_erase(&g->nodes, n); +} + +node * +graph_find_node(graph *g, void *object) +{ + unsigned int i; + + for(i=0; i != g->nodes.size; ++i) { + node *node = g->nodes.data[i]; + if(node->object == object) { + return g->nodes.data[i]; + } + } + return NULL; +} + +/* The vset returned has to freed externally, else this will be a + memory leak. */ + +vset * +graph_neighbours(graph *g, node *n) +{ + unsigned int i; + vset * vs = malloc(sizeof(vs)); + vset_init(vs); + for(i=0; i != g->edges.size; ++i) { + edge *v = g->edges.data[i]; + if(v->node1 == n && vset_count(vs, v->node2) == 0) { + vset_add(vs, v->node2); + } else if(v->node2 == n && vset_count(vs, v->node1) == 0) { + vset_add(vs, v->node1); + } + } + + return vs; +} + +void +graph_resetmarkers(graph *g) +{ + unsigned int i; + + for(i=0; i != g->nodes.size; ++i) { + node *node = g->nodes.data[i]; + node->marker = 0; + } + for(i=0; i != g->edges.size; ++i) { + edge *edge = g->edges.data[i]; + edge->marker = 0; + } +} + +/* The vset returned has to freed externally, else this will be a + memory leak. */ + +vset * +graph_connected_nodes(graph *g, node *n) +{ + vset * vs = malloc(sizeof(vset)); + vset s; + + vset_init(vs); + vset_init(&s); + graph_resetmarkers(g); + vset_add(vs, n); + n->marker = 1; + vset_add(&s, n); + while(s.size > 0) { + node *n = vset_pop(&s); + vset *vs_nb = graph_neighbours(g, n); + unsigned int i; + for(i=0; i != vs_nb->size; ++i) { + node *nb = vs_nb->data[i]; + if(nb->marker == 0) { + nb->marker = 1; + vset_add(vs, nb); + vset_add(&s, nb); + } + } + vset_destroy(vs_nb); + free(vs_nb); + } + + vset_destroy(&s); + + return vs; +} + +/* The vset returned has to freed externally, else this will be a + memory leak. */ + +vset * +graph_disjunct_graphs(graph *g) +{ + vset * dg = malloc(sizeof(vset)); + vset nodes; + + vset_init(dg); + vset_init(&nodes); + vset_concat(&nodes, &g->nodes); + + while(nodes.size > 0) { + graph *gt = malloc(sizeof(graph)); + vset s; + unsigned int i; + node *start; + + graph_init(gt); + start = vset_pop(&nodes); + graph_resetmarkers(g); + graph_add_node(gt, start); + start->marker = 1; + vset_init(&s); + vset_add(&s,start); + while(s.size > 0) { + vset * nbs = graph_neighbours(g,vset_pop(&s)); + for(i=0; i != nbs->size; ++i) { + node *nb = nbs->data[i]; + if(nb->marker == 0) { + nb->marker = 1; + graph_add_node(gt,nb); + vset_erase(&nodes,nb); + vset_add(&s,nb); + } + } + vset_destroy(nbs); free(nbs); + } + + vset_destroy(&s); + + for(i=0;i != g->edges.size; ++i) { + edge *v = g->edges.data[i]; + if(vset_count(&g->nodes, v->node1)) { + graph_add_edge(gt, v); + } + } + + vset_add(dg, gt); + } + + vset_destroy(&nodes); + + return dg; +} + diff --git a/src/util/graph.h b/src/util/graph.h index e5480d1ab..e5398b3a0 100644 --- a/src/util/graph.h +++ b/src/util/graph.h @@ -1,38 +1,38 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - */ - -#ifndef GRAPH_H -#define GRAPH_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct node { - int marker; - void *object; -} node; - -typedef struct edge { - int marker; - node *node1; - node *node2; -} edge; - -typedef struct graph { - vset nodes; - vset edges; -} graph; - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + */ + +#ifndef GRAPH_H +#define GRAPH_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct node { + int marker; + void *object; +} node; + +typedef struct edge { + int marker; + node *node1; + node *node2; +} edge; + +typedef struct graph { + vset nodes; + vset edges; +} graph; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/language.c b/src/util/language.c index 298cf92b0..d5842142b 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -1,252 +1,252 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "language.h" -#include "language_struct.h" - -#include "log.h" -#include "goodies.h" -#include "umlaut.h" - -#include -#include -#include -#include - -/** importing **/ - -locale * default_locale; -locale * locales; - -unsigned int -locale_hashkey(const locale * lang) -{ - assert(lang); - return lang->hashkey; -} - -locale * -find_locale(const char * name) -{ - unsigned int hkey = hashstring(name); - locale * l = locales; - while (l && l->hashkey!=hkey) l=l->next; - return l; -} - -static int nextlocaleindex = 0; - -locale * -make_locale(const char * name) -{ - unsigned int hkey = hashstring(name); - locale * l = (locale *)calloc(sizeof(locale), 1); - locale ** lp = &locales; - - while (*lp && (*lp)->hashkey!=hkey) lp=&(*lp)->next; - if (*lp) { - return *lp; - } - - l->hashkey = hkey; - l->name = strdup(name); - l->next = NULL; - l->index = nextlocaleindex++; - assert(nextlocaleindex<=MAXLOCALES); - *lp = l; - if (default_locale==NULL) default_locale = l; - return l; -} - -/** creates a list of locales - * This function takes a comma-delimited list of locale-names and creates - * the locales using the make_locale function (useful for ini-files). - * For maximum performance, locales should be created in order of popularity. - */ -void -make_locales(const char * str) -{ - const char * tok = str; - while (*tok) { - char zText[32]; - while (*tok && *tok !=',') ++tok; - strncpy(zText, str, tok-str); - zText[tok-str] = 0; - make_locale(zText); - if (*tok) { - str = ++tok; - } - } -} - -static FILE * s_debug = NULL; -static char * s_logfile = NULL; - -void -debug_language(const char * log) -{ - s_logfile = strdup(log); -} - -const char * -locale_getstring(const locale * lang, const char * key) -{ - unsigned int hkey = hashstring(key); - unsigned int id = hkey & (SMAXHASH-1); - const struct locale_str * find; - - assert(lang); - if (key==NULL || *key==0) return NULL; - find = lang->strings[id]; - while (find) { - if (find->hashkey == hkey) { - if (find->nexthash==NULL) { - /* if this is the only entry with this hash, fine. */ - assert(strcmp(key, find->key)==0); - return find->str; - } - if (strcmp(key, find->key)==0) { - return find->str; - } - } - find = find->nexthash; - } - return NULL; -} - -const char * -locale_string(const locale * lang, const char * key) -{ - assert(lang!=0); - - if (key!=NULL) { - unsigned int hkey = hashstring(key); - unsigned int id = hkey & (SMAXHASH-1); - struct locale_str * find; - - if (*key==0) return NULL; - if (lang == NULL) return key; - find = lang->strings[id]; - while (find) { - if (find->hashkey == hkey) { - if (find->nexthash==NULL) { - /* if this is the only entry with this hash, fine. */ - assert(strcmp(key, find->key)==0); - break; - } - if (strcmp(key, find->key)==0) break; - } - find = find->nexthash; - } - if (!find) { - const char * s = key; - log_warning(("missing translation for \"%s\" in locale %s\n", key, lang->name)); - if (lang!=default_locale) { - s = locale_string(default_locale, key); - } - if (s_logfile) { - s_debug = s_debug?s_debug:fopen(s_logfile, "w"); - if (s_debug) { - fprintf(s_debug, "%s;%s;%s\n", key, lang->name, s); - fflush(s_debug); - locale_setstring((struct locale*)lang, key, s); - } - } - return s; - } - return find->str; - } - return NULL; -} - -void -locale_setstring(locale * lang, const char * key, const char * value) -{ - unsigned int hkey = hashstring(key); - unsigned int id = hkey & (SMAXHASH-1); - struct locale_str * find; - if (lang==NULL) lang=default_locale; - find = lang->strings[id]; - while (find) { - if (find->hashkey==hkey && strcmp(key, find->key)==0) break; - find = find->nexthash; - } - if (!find) { - find = calloc(1, sizeof(struct locale_str)); - find->nexthash = lang->strings[id]; - lang->strings[id] = find; - find->hashkey = hkey; - find->key = strdup(key); - find->str = strdup(value); - } - else { - if (strcmp(find->str, value)!=0) { - log_error(("Duplicate key %s for '%s' and '%s'\n", key, value, find->str)); - } - assert(!strcmp(find->str, value) || !"duplicate string for key"); - } -} - -const char * -locale_name(const locale * lang) -{ - assert(lang); - return lang->name; -} - -char * -mkname_buf(const char * space, const char * name, char * buffer) -{ - if (space && *space) { - sprintf(buffer, "%s::%s", space, name); - } else { - strcpy(buffer, name); - } - return buffer; -} - -const char * -mkname(const char * space, const char * name) -{ - static char zBuffer[128]; /* STATIC_RESULT: used for return, not across calls */ - return mkname_buf(space, name, zBuffer); -} - -locale * -nextlocale(const struct locale * lang) -{ - return lang->next; -} - -typedef struct lstr { - tnode tokens[UT_MAX]; -} lstr; - -static lstr lstrs[MAXLOCALES]; - -struct tnode * -get_translations(const struct locale * lang, int index) -{ - assert(lang); - assert(lang->indexindexindex].tokens+index; - } - return lstrs[0].tokens+index; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "language.h" +#include "language_struct.h" + +#include "log.h" +#include "goodies.h" +#include "umlaut.h" + +#include +#include +#include +#include + +/** importing **/ + +locale * default_locale; +locale * locales; + +unsigned int +locale_hashkey(const locale * lang) +{ + assert(lang); + return lang->hashkey; +} + +locale * +find_locale(const char * name) +{ + unsigned int hkey = hashstring(name); + locale * l = locales; + while (l && l->hashkey!=hkey) l=l->next; + return l; +} + +static int nextlocaleindex = 0; + +locale * +make_locale(const char * name) +{ + unsigned int hkey = hashstring(name); + locale * l = (locale *)calloc(sizeof(locale), 1); + locale ** lp = &locales; + + while (*lp && (*lp)->hashkey!=hkey) lp=&(*lp)->next; + if (*lp) { + return *lp; + } + + l->hashkey = hkey; + l->name = strdup(name); + l->next = NULL; + l->index = nextlocaleindex++; + assert(nextlocaleindex<=MAXLOCALES); + *lp = l; + if (default_locale==NULL) default_locale = l; + return l; +} + +/** creates a list of locales + * This function takes a comma-delimited list of locale-names and creates + * the locales using the make_locale function (useful for ini-files). + * For maximum performance, locales should be created in order of popularity. + */ +void +make_locales(const char * str) +{ + const char * tok = str; + while (*tok) { + char zText[32]; + while (*tok && *tok !=',') ++tok; + strncpy(zText, str, tok-str); + zText[tok-str] = 0; + make_locale(zText); + if (*tok) { + str = ++tok; + } + } +} + +static FILE * s_debug = NULL; +static char * s_logfile = NULL; + +void +debug_language(const char * log) +{ + s_logfile = strdup(log); +} + +const char * +locale_getstring(const locale * lang, const char * key) +{ + unsigned int hkey = hashstring(key); + unsigned int id = hkey & (SMAXHASH-1); + const struct locale_str * find; + + assert(lang); + if (key==NULL || *key==0) return NULL; + find = lang->strings[id]; + while (find) { + if (find->hashkey == hkey) { + if (find->nexthash==NULL) { + /* if this is the only entry with this hash, fine. */ + assert(strcmp(key, find->key)==0); + return find->str; + } + if (strcmp(key, find->key)==0) { + return find->str; + } + } + find = find->nexthash; + } + return NULL; +} + +const char * +locale_string(const locale * lang, const char * key) +{ + assert(lang!=0); + + if (key!=NULL) { + unsigned int hkey = hashstring(key); + unsigned int id = hkey & (SMAXHASH-1); + struct locale_str * find; + + if (*key==0) return NULL; + if (lang == NULL) return key; + find = lang->strings[id]; + while (find) { + if (find->hashkey == hkey) { + if (find->nexthash==NULL) { + /* if this is the only entry with this hash, fine. */ + assert(strcmp(key, find->key)==0); + break; + } + if (strcmp(key, find->key)==0) break; + } + find = find->nexthash; + } + if (!find) { + const char * s = key; + log_warning(("missing translation for \"%s\" in locale %s\n", key, lang->name)); + if (lang!=default_locale) { + s = locale_string(default_locale, key); + } + if (s_logfile) { + s_debug = s_debug?s_debug:fopen(s_logfile, "w"); + if (s_debug) { + fprintf(s_debug, "%s;%s;%s\n", key, lang->name, s); + fflush(s_debug); + locale_setstring((struct locale*)lang, key, s); + } + } + return s; + } + return find->str; + } + return NULL; +} + +void +locale_setstring(locale * lang, const char * key, const char * value) +{ + unsigned int hkey = hashstring(key); + unsigned int id = hkey & (SMAXHASH-1); + struct locale_str * find; + if (lang==NULL) lang=default_locale; + find = lang->strings[id]; + while (find) { + if (find->hashkey==hkey && strcmp(key, find->key)==0) break; + find = find->nexthash; + } + if (!find) { + find = calloc(1, sizeof(struct locale_str)); + find->nexthash = lang->strings[id]; + lang->strings[id] = find; + find->hashkey = hkey; + find->key = strdup(key); + find->str = strdup(value); + } + else { + if (strcmp(find->str, value)!=0) { + log_error(("Duplicate key %s for '%s' and '%s'\n", key, value, find->str)); + } + assert(!strcmp(find->str, value) || !"duplicate string for key"); + } +} + +const char * +locale_name(const locale * lang) +{ + assert(lang); + return lang->name; +} + +char * +mkname_buf(const char * space, const char * name, char * buffer) +{ + if (space && *space) { + sprintf(buffer, "%s::%s", space, name); + } else { + strcpy(buffer, name); + } + return buffer; +} + +const char * +mkname(const char * space, const char * name) +{ + static char zBuffer[128]; /* STATIC_RESULT: used for return, not across calls */ + return mkname_buf(space, name, zBuffer); +} + +locale * +nextlocale(const struct locale * lang) +{ + return lang->next; +} + +typedef struct lstr { + tnode tokens[UT_MAX]; +} lstr; + +static lstr lstrs[MAXLOCALES]; + +struct tnode * +get_translations(const struct locale * lang, int index) +{ + assert(lang); + assert(lang->indexindexindex].tokens+index; + } + return lstrs[0].tokens+index; +} diff --git a/src/util/language.h b/src/util/language.h index a051bc6f0..b1ad422bf 100644 --- a/src/util/language.h +++ b/src/util/language.h @@ -1,69 +1,69 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef MY_LOCALE_H -#define MY_LOCALE_H -#ifdef __cplusplus -extern "C" { -#endif - -struct locale; - -/** managing multiple locales: **/ -extern struct locale * find_locale(const char * name); -extern struct locale * make_locale(const char * key); - -/** operations on locales: **/ -extern void locale_setstring(struct locale * lang, const char * key, const char * value); -extern const char * locale_getstring(const struct locale * lang, const char * key); -extern const char * locale_string(const struct locale * lang, const char * key); /* does fallback */ -extern unsigned int locale_hashkey(const struct locale * lang); -extern const char * locale_name(const struct locale * lang); - -extern const char * mkname(const char * namespc, const char * key); -extern char * mkname_buf(const char * namespc, const char * key, char * buffer); - -extern void debug_language(const char * log); -extern void make_locales(const char * str); - -#define LOC(lang, s) (lang?locale_string(lang, s):s) - -extern struct locale * default_locale; -extern struct locale * locales; -extern struct locale * nextlocale(const struct locale * lang); - -enum { - UT_PARAMS, - UT_KEYWORDS, - UT_SKILLS, - UT_RACES, - UT_OPTIONS, - UT_DIRECTIONS, - UT_ARCHETYPES, - UT_MAGIC, - UT_TERRAINS, - UT_SPECDIR, - UT_MAX -}; - -struct tnode * get_translations(const struct locale * lang, int index); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef MY_LOCALE_H +#define MY_LOCALE_H +#ifdef __cplusplus +extern "C" { +#endif + +struct locale; + +/** managing multiple locales: **/ +extern struct locale * find_locale(const char * name); +extern struct locale * make_locale(const char * key); + +/** operations on locales: **/ +extern void locale_setstring(struct locale * lang, const char * key, const char * value); +extern const char * locale_getstring(const struct locale * lang, const char * key); +extern const char * locale_string(const struct locale * lang, const char * key); /* does fallback */ +extern unsigned int locale_hashkey(const struct locale * lang); +extern const char * locale_name(const struct locale * lang); + +extern const char * mkname(const char * namespc, const char * key); +extern char * mkname_buf(const char * namespc, const char * key, char * buffer); + +extern void debug_language(const char * log); +extern void make_locales(const char * str); + +#define LOC(lang, s) (lang?locale_string(lang, s):s) + +extern struct locale * default_locale; +extern struct locale * locales; +extern struct locale * nextlocale(const struct locale * lang); + +enum { + UT_PARAMS, + UT_KEYWORDS, + UT_SKILLS, + UT_RACES, + UT_OPTIONS, + UT_DIRECTIONS, + UT_ARCHETYPES, + UT_MAGIC, + UT_TERRAINS, + UT_SPECDIR, + UT_MAX +}; + +struct tnode * get_translations(const struct locale * lang, int index); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/language_struct.h b/src/util/language_struct.h index 1f09a071b..700464eb8 100644 --- a/src/util/language_struct.h +++ b/src/util/language_struct.h @@ -1,28 +1,28 @@ -#ifndef CLASS_LANGUAGE_STRUCT -#define CLASS_LANGUAGE_STRUCT - -/* This file should not be included by anything in the server. If you - * feel that you need to include it, it's a sure sign that you're trying to - * do something BAD. */ - -#define MAXLOCALES 3 -#define SMAXHASH 2048 -typedef struct locale_str { - unsigned int hashkey; - struct locale_str * nexthash; - char * str; - char * key; -} locale_str; - -typedef struct locale { - int index; - struct locale * next; - unsigned int hashkey; - const char * name; - struct locale_str * strings[SMAXHASH]; -} locale; - -extern locale * default_locale; -extern locale * locales; - -#endif +#ifndef CLASS_LANGUAGE_STRUCT +#define CLASS_LANGUAGE_STRUCT + +/* This file should not be included by anything in the server. If you + * feel that you need to include it, it's a sure sign that you're trying to + * do something BAD. */ + +#define MAXLOCALES 3 +#define SMAXHASH 2048 +typedef struct locale_str { + unsigned int hashkey; + struct locale_str * nexthash; + char * str; + char * key; +} locale_str; + +typedef struct locale { + int index; + struct locale * next; + unsigned int hashkey; + const char * name; + struct locale_str * strings[SMAXHASH]; +} locale; + +extern locale * default_locale; +extern locale * locales; + +#endif diff --git a/src/util/listbox.c b/src/util/listbox.c index 508d5bd3c..330b877c8 100644 --- a/src/util/listbox.c +++ b/src/util/listbox.c @@ -1,191 +1,191 @@ -/* vi: set ts=2: -* +-------------------+ Christian Schlittchen -* | | Enno Rehling -* | Eressea PBEM host | Katja Zedel -* | (c) 1998 - 2006 | -* | | This program may not be used, modified or distributed -* +-------------------+ without prior permission by the authors of Eressea. -* -*/ - -/* wenn platform.h nicht vor curses included wird, kompiliert es unter windows nicht */ -#include -#include - -#include "listbox.h" - -#include -#include - -void -insert_selection(list_selection ** p_sel, list_selection * prev, const char * str, void * payload) -{ - list_selection * sel = calloc(sizeof(list_selection), 1); - sel->str = strdup(str); - sel->data = payload; - if (*p_sel) { - list_selection * s; - sel->next = *p_sel; - sel->prev = sel->next->prev; - sel->next->prev=sel; - if (sel->prev) { - sel->prev->next = sel; - sel->index=sel->prev->index+1; - } - for (s=sel->next;s;s=s->next) { - s->index = s->prev->index+1; - } - *p_sel = sel; - } else { - *p_sel = sel; - sel->prev = prev; - if (prev) sel->index=prev->index+1; - } -} - -list_selection ** -push_selection(list_selection ** p_sel, char * str, void * payload) -{ - list_selection * sel = calloc(sizeof(list_selection), 1); - list_selection * prev = NULL; - sel->str = str; - sel->data = payload; - while (*p_sel) { - prev = *p_sel; - p_sel=&prev->next; - } - *p_sel = sel; - if (prev) { - sel->prev = prev; - sel->index = prev->index+1; - } - return p_sel; -} - -#define SX (stdscr->_maxx) -#define SY (stdscr->_maxy) - -list_selection * -do_selection(list_selection * sel, const char * title, void (*perform)(list_selection *, void *), void * data) -{ - WINDOW * wn; - boolean update = true; - list_selection *s; - list_selection *top = sel; - list_selection *current = top; - int i; - int height = 0, width = (int)strlen(title)+8; - for (s=sel;s;s=s->next) { - if ((int)strlen(s->str)>width) width = (int)strlen(s->str); - ++height; - } - if (height==0 || width==0) return NULL; - if (width+3>SX) width=SX-4; - if (height+2>SY) height=SY-2; - - wn = newwin(height+2, width+4, (SY - height - 2) / 2, (SX - width - 4) / 2); - - for (;;) { - int input; - if (update) { - for (s=top;s!=NULL && top->index+height!=s->index;s=s->next) { - i = s->index-top->index; - wmove(wn, i + 1, 4); - waddnstr(wn, s->str, -1); - wclrtoeol(wn); - } - wborder(wn, 0, 0, 0, 0, 0, 0, 0, 0); - mvwprintw(wn, 0, 2, "[ %s ]", title); - update = false; - } - i = current->index-top->index; - wattron(wn, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - wmove(wn, i + 1, 2); - waddstr(wn, "->"); - wmove(wn, i + 1, 4); - waddnstr(wn, current->str, -1); - wattroff(wn, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - - wrefresh(wn); - - input = getch(); - - wmove(wn, i + 1, 2); - waddstr(wn, " "); - wmove(wn, i + 1, 4); - waddnstr(wn, current->str, width); - - switch (input) { - case KEY_NPAGE: - for (i=0;i!=height/2;++i) { - if (current->next) { - current = current->next; - if (current->index-height>=top->index) { - top=current; - update = true; - } - } - } - break; - case KEY_PPAGE: - for (i=0;i!=height/2;++i) { - if (current->prev) { - if (current==top) { - top = sel; - while (top->index+heightindex) top=top->next; - update = true; - } - current = current->prev; - } - } - break; - case KEY_DOWN: - if (current->next) { - current = current->next; - if (current->index-height>=top->index) { - top=current; - update = true; - } - } - break; - case KEY_UP: - if (current->prev) { - if (current==top) { - top = sel; - while (top->index+heightindex) top=top->next; - update = true; - } - current = current->prev; - } - break; - case 27: - case 'q': - delwin(wn); - return NULL; - case 10: - case 13: - if (perform) perform(current, data); - else { - delwin(wn); - return current; - } - break; - default: - s = current->next; - if (s==NULL) s = top; - while (s!=current) { - if (tolower(s->str[0])==tolower(input)) { - current = s; - update = true; - } else { - s = s->next; - if (s==NULL) s = top; - } - } - if (current->index-height>=top->index) { - top=current; - update = true; - } - } - } -} +/* vi: set ts=2: +* +-------------------+ Christian Schlittchen +* | | Enno Rehling +* | Eressea PBEM host | Katja Zedel +* | (c) 1998 - 2006 | +* | | This program may not be used, modified or distributed +* +-------------------+ without prior permission by the authors of Eressea. +* +*/ + +/* wenn platform.h nicht vor curses included wird, kompiliert es unter windows nicht */ +#include +#include + +#include "listbox.h" + +#include +#include + +void +insert_selection(list_selection ** p_sel, list_selection * prev, const char * str, void * payload) +{ + list_selection * sel = calloc(sizeof(list_selection), 1); + sel->str = strdup(str); + sel->data = payload; + if (*p_sel) { + list_selection * s; + sel->next = *p_sel; + sel->prev = sel->next->prev; + sel->next->prev=sel; + if (sel->prev) { + sel->prev->next = sel; + sel->index=sel->prev->index+1; + } + for (s=sel->next;s;s=s->next) { + s->index = s->prev->index+1; + } + *p_sel = sel; + } else { + *p_sel = sel; + sel->prev = prev; + if (prev) sel->index=prev->index+1; + } +} + +list_selection ** +push_selection(list_selection ** p_sel, char * str, void * payload) +{ + list_selection * sel = calloc(sizeof(list_selection), 1); + list_selection * prev = NULL; + sel->str = str; + sel->data = payload; + while (*p_sel) { + prev = *p_sel; + p_sel=&prev->next; + } + *p_sel = sel; + if (prev) { + sel->prev = prev; + sel->index = prev->index+1; + } + return p_sel; +} + +#define SX (stdscr->_maxx) +#define SY (stdscr->_maxy) + +list_selection * +do_selection(list_selection * sel, const char * title, void (*perform)(list_selection *, void *), void * data) +{ + WINDOW * wn; + boolean update = true; + list_selection *s; + list_selection *top = sel; + list_selection *current = top; + int i; + int height = 0, width = (int)strlen(title)+8; + for (s=sel;s;s=s->next) { + if ((int)strlen(s->str)>width) width = (int)strlen(s->str); + ++height; + } + if (height==0 || width==0) return NULL; + if (width+3>SX) width=SX-4; + if (height+2>SY) height=SY-2; + + wn = newwin(height+2, width+4, (SY - height - 2) / 2, (SX - width - 4) / 2); + + for (;;) { + int input; + if (update) { + for (s=top;s!=NULL && top->index+height!=s->index;s=s->next) { + i = s->index-top->index; + wmove(wn, i + 1, 4); + waddnstr(wn, s->str, -1); + wclrtoeol(wn); + } + wborder(wn, 0, 0, 0, 0, 0, 0, 0, 0); + mvwprintw(wn, 0, 2, "[ %s ]", title); + update = false; + } + i = current->index-top->index; + wattron(wn, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + wmove(wn, i + 1, 2); + waddstr(wn, "->"); + wmove(wn, i + 1, 4); + waddnstr(wn, current->str, -1); + wattroff(wn, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + + wrefresh(wn); + + input = getch(); + + wmove(wn, i + 1, 2); + waddstr(wn, " "); + wmove(wn, i + 1, 4); + waddnstr(wn, current->str, width); + + switch (input) { + case KEY_NPAGE: + for (i=0;i!=height/2;++i) { + if (current->next) { + current = current->next; + if (current->index-height>=top->index) { + top=current; + update = true; + } + } + } + break; + case KEY_PPAGE: + for (i=0;i!=height/2;++i) { + if (current->prev) { + if (current==top) { + top = sel; + while (top->index+heightindex) top=top->next; + update = true; + } + current = current->prev; + } + } + break; + case KEY_DOWN: + if (current->next) { + current = current->next; + if (current->index-height>=top->index) { + top=current; + update = true; + } + } + break; + case KEY_UP: + if (current->prev) { + if (current==top) { + top = sel; + while (top->index+heightindex) top=top->next; + update = true; + } + current = current->prev; + } + break; + case 27: + case 'q': + delwin(wn); + return NULL; + case 10: + case 13: + if (perform) perform(current, data); + else { + delwin(wn); + return current; + } + break; + default: + s = current->next; + if (s==NULL) s = top; + while (s!=current) { + if (tolower(s->str[0])==tolower(input)) { + current = s; + update = true; + } else { + s = s->next; + if (s==NULL) s = top; + } + } + if (current->index-height>=top->index) { + top=current; + update = true; + } + } + } +} diff --git a/src/util/listbox.h b/src/util/listbox.h index ab2c7f9bc..5ff85f1b1 100644 --- a/src/util/listbox.h +++ b/src/util/listbox.h @@ -1,16 +1,16 @@ -#ifndef CURSES_LISTBOX -#define CURSES_LISTBOX - -typedef struct list_selection { - struct list_selection * next; - struct list_selection * prev; - int index; - char * str; - void * data; -} list_selection; - -extern struct list_selection * do_selection(struct list_selection * sel, const char * title, void (*perform)(struct list_selection *, void *), void * data); -extern struct list_selection ** push_selection(struct list_selection ** p_sel, char * str, void * payload); -extern void insert_selection(struct list_selection ** p_sel, struct list_selection * prev, const char * str, void * payload); - -#endif /* CURSES_LISTBOX */ +#ifndef CURSES_LISTBOX +#define CURSES_LISTBOX + +typedef struct list_selection { + struct list_selection * next; + struct list_selection * prev; + int index; + char * str; + void * data; +} list_selection; + +extern struct list_selection * do_selection(struct list_selection * sel, const char * title, void (*perform)(struct list_selection *, void *), void * data); +extern struct list_selection ** push_selection(struct list_selection ** p_sel, char * str, void * payload); +extern void insert_selection(struct list_selection ** p_sel, struct list_selection * prev, const char * str, void * payload); + +#endif /* CURSES_LISTBOX */ diff --git a/src/util/lists.c b/src/util/lists.c index cff4b287c..7411406b2 100644 --- a/src/util/lists.c +++ b/src/util/lists.c @@ -1,143 +1,143 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include - -#include -#include "lists.h" - -void -addlist(void *l1, void *p1) -{ - - /* add entry p to the end of list l */ - - void_list **l; - void_list *p, *q; - - l = (void_list **)l1; - p = (void_list *)p1; - assert(p->next == 0); - - if (*l) { - for (q = *l; q->next; q = q->next) - assert(q); - q->next = p; - } else - *l = p; -} - -void -choplist(void * a, void * b) -{ - void_list **l = (void_list**)a, *p = (void_list*)b; - /* remove entry p from list l - when called, a pointer to p must be - * kept in order to use (and free) p; if omitted, this will be a - * memory leak */ - - void_list **q; - - for (q = l; *q; q = &((*q)->next)) { - if (*q == p) { - *q = p->next; - p->next = 0; - break; - } - } -} - -void -translist(void *l1, void *l2, void *p) -{ - - /* remove entry p from list l1 and add it at the end of list l2 */ - - choplist(l1, p); - addlist(l2, p); -} - -void -insertlist(void_list ** l, void_list * p) -{ - - /* insert entry p at the beginning of list l */ - - p->next = *l; - *l = p; - -} - -void -removelist(void *l, void *p) -{ - - /* remove entry p from list l; free p */ - - choplist(l, p); - free(p); -} - -void -freelist(void *p1) -{ - - /* remove all entries following and including entry p from a listlist */ - - void_list *p, *p2; - - p = (void_list *)p1; - - while (p) { - p2 = p->next; - free(p); - p = p2; - } -} - -unsigned int -listlen(void *l) -{ - - /* count entries p in list l */ - - unsigned int i; - void_list *p; - - for (p = (void_list *)l, i = 0; p; p = p->next, i++); - return i; -} - -/* Hilfsfunktion, um das Debugging zu erleichtern. Statt print - * (cast)foo->next->next->next->next nur noch - * print (cast)listelem(foo, 3) */ - -void * -listelem(void *l, int n) -{ - int i=0; - - while(i < n && l != NULL) { - l = ((void_list *)l)->next; - i++; - } - - return l; -} - - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include + +#include +#include "lists.h" + +void +addlist(void *l1, void *p1) +{ + + /* add entry p to the end of list l */ + + void_list **l; + void_list *p, *q; + + l = (void_list **)l1; + p = (void_list *)p1; + assert(p->next == 0); + + if (*l) { + for (q = *l; q->next; q = q->next) + assert(q); + q->next = p; + } else + *l = p; +} + +void +choplist(void * a, void * b) +{ + void_list **l = (void_list**)a, *p = (void_list*)b; + /* remove entry p from list l - when called, a pointer to p must be + * kept in order to use (and free) p; if omitted, this will be a + * memory leak */ + + void_list **q; + + for (q = l; *q; q = &((*q)->next)) { + if (*q == p) { + *q = p->next; + p->next = 0; + break; + } + } +} + +void +translist(void *l1, void *l2, void *p) +{ + + /* remove entry p from list l1 and add it at the end of list l2 */ + + choplist(l1, p); + addlist(l2, p); +} + +void +insertlist(void_list ** l, void_list * p) +{ + + /* insert entry p at the beginning of list l */ + + p->next = *l; + *l = p; + +} + +void +removelist(void *l, void *p) +{ + + /* remove entry p from list l; free p */ + + choplist(l, p); + free(p); +} + +void +freelist(void *p1) +{ + + /* remove all entries following and including entry p from a listlist */ + + void_list *p, *p2; + + p = (void_list *)p1; + + while (p) { + p2 = p->next; + free(p); + p = p2; + } +} + +unsigned int +listlen(void *l) +{ + + /* count entries p in list l */ + + unsigned int i; + void_list *p; + + for (p = (void_list *)l, i = 0; p; p = p->next, i++); + return i; +} + +/* Hilfsfunktion, um das Debugging zu erleichtern. Statt print + * (cast)foo->next->next->next->next nur noch + * print (cast)listelem(foo, 3) */ + +void * +listelem(void *l, int n) +{ + int i=0; + + while(i < n && l != NULL) { + l = ((void_list *)l)->next; + i++; + } + + return l; +} + + diff --git a/src/util/lists.h b/src/util/lists.h index 588cc4878..1fe3638d6 100644 --- a/src/util/lists.h +++ b/src/util/lists.h @@ -1,55 +1,55 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef LISTS_H -#define LISTS_H -#ifdef __cplusplus -extern "C" { -#endif - -#include - -typedef struct void_list { - struct void_list * next; - void * data; -} void_list; - -#define list_foreach(type, list, item) item=list; while (item!=NULL) { type* __next__=item->next; -#define list_continue(item) { item=__next__; continue; } -#define list_next(item) item=__next__; } - -void addlist(void *l1, void *p1); -void choplist(void * l, void * p); -void translist(void *l1, void *l2, void *p); -#ifndef MALLOCDBG -void freelist(void *p1); -void removelist(void *l, void *p); -#else -#define freelist(p) { while (p) { void * p2 = p->next; free(p); p = p2; } } -#define removelist(l,p) { choplist(l, p); free(p); } -#endif - -unsigned int listlen(void *l); -#define addlist2(l, p) (*l = p, l = &p->next) - -void *listelem(void *l, int n); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef LISTS_H +#define LISTS_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef struct void_list { + struct void_list * next; + void * data; +} void_list; + +#define list_foreach(type, list, item) item=list; while (item!=NULL) { type* __next__=item->next; +#define list_continue(item) { item=__next__; continue; } +#define list_next(item) item=__next__; } + +void addlist(void *l1, void *p1); +void choplist(void * l, void * p); +void translist(void *l1, void *l2, void *p); +#ifndef MALLOCDBG +void freelist(void *p1); +void removelist(void *l, void *p); +#else +#define freelist(p) { while (p) { void * p2 = p->next; free(p); p = p2; } } +#define removelist(l,p) { choplist(l, p); free(p); } +#endif + +unsigned int listlen(void *l); +#define addlist2(l, p) (*l = p, l = &p->next) + +void *listelem(void *l, int n); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/log.c b/src/util/log.c index 7b5b22ff6..92c4c3ef8 100644 --- a/src/util/log.c +++ b/src/util/log.c @@ -1,288 +1,288 @@ -/* vi: set ts=2: -+-------------------+ Christian Schlittchen -| | Enno Rehling -| Eressea PBEM host | Katja Zedel -| (c) 1998 - 2003 | Henning Peters -| | Ingo Wilken -+-------------------+ Stefan Reich - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ -#include -#include "log.h" -#include "unicode.h" - -#include -#include -#include -#include -#include - -/* TODO: set from external function */ -int log_flags = LOG_FLUSH|LOG_CPERROR|LOG_CPWARNING; -#ifdef STDIO_CP -static int stdio_codepage = STDIO_CP; -#else -static int stdio_codepage = 0; -#endif -static FILE * logfile; - -#define MAXLENGTH 4096 /* because I am lazy, CP437 output is limited to this many chars */ -void -log_flush(void) -{ - fflush(logfile); -} - -void -log_puts(const char * str) -{ - fflush(stdout); - if (!logfile) logfile = stderr; - fputs(str, logfile); -} - -static int -cp_convert(const char * format, char * buffer, size_t length, int codepage) -{ - /* when console output on MSDOS, convert to codepage */ - const char * input = format; - char * pos = buffer; - - while (pos+1=level) { - fprintf(logfile, "INFO[%u]: ", level); - va_start(marker, format); - vfprintf(logfile, format, marker); - va_end(marker); - if (logfile!=stderr) { - if (stderr_level>=level) { - fprintf(stderr, "INFO[%u]: ", level); - va_start(marker, format); - if (stdio_codepage) { - char buffer[MAXLENGTH]; - char converted[MAXLENGTH]; - - vsnprintf(buffer, sizeof(buffer), format, marker); - if (cp_convert(buffer, converted, MAXLENGTH, stdio_codepage)==0) { - fputs(converted, stderr); - } else { - /* fall back to non-converted output */ - va_end(marker); - va_start(marker, format); - vfprintf(stderr, format, marker); - } - } else { - vfprintf(stderr, format, marker); - } - va_end(marker); - } - if (log_flags & LOG_FLUSH) { - log_flush(); - } - } - } -} +/* vi: set ts=2: ++-------------------+ Christian Schlittchen +| | Enno Rehling +| Eressea PBEM host | Katja Zedel +| (c) 1998 - 2003 | Henning Peters +| | Ingo Wilken ++-------------------+ Stefan Reich + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ +#include +#include "log.h" +#include "unicode.h" + +#include +#include +#include +#include +#include + +/* TODO: set from external function */ +int log_flags = LOG_FLUSH|LOG_CPERROR|LOG_CPWARNING; +#ifdef STDIO_CP +static int stdio_codepage = STDIO_CP; +#else +static int stdio_codepage = 0; +#endif +static FILE * logfile; + +#define MAXLENGTH 4096 /* because I am lazy, CP437 output is limited to this many chars */ +void +log_flush(void) +{ + fflush(logfile); +} + +void +log_puts(const char * str) +{ + fflush(stdout); + if (!logfile) logfile = stderr; + fputs(str, logfile); +} + +static int +cp_convert(const char * format, char * buffer, size_t length, int codepage) +{ + /* when console output on MSDOS, convert to codepage */ + const char * input = format; + char * pos = buffer; + + while (pos+1=level) { + fprintf(logfile, "INFO[%u]: ", level); + va_start(marker, format); + vfprintf(logfile, format, marker); + va_end(marker); + if (logfile!=stderr) { + if (stderr_level>=level) { + fprintf(stderr, "INFO[%u]: ", level); + va_start(marker, format); + if (stdio_codepage) { + char buffer[MAXLENGTH]; + char converted[MAXLENGTH]; + + vsnprintf(buffer, sizeof(buffer), format, marker); + if (cp_convert(buffer, converted, MAXLENGTH, stdio_codepage)==0) { + fputs(converted, stderr); + } else { + /* fall back to non-converted output */ + va_end(marker); + va_start(marker, format); + vfprintf(stderr, format, marker); + } + } else { + vfprintf(stderr, format, marker); + } + va_end(marker); + } + if (log_flags & LOG_FLUSH) { + log_flush(); + } + } + } +} diff --git a/src/util/log.h b/src/util/log.h index 87a35dfee..0fc454610 100644 --- a/src/util/log.h +++ b/src/util/log.h @@ -1,45 +1,45 @@ -/* vi: set ts=2: -+-------------------+ Christian Schlittchen -| | Enno Rehling -| Eressea PBEM host | Katja Zedel -| (c) 1998 - 2003 | Henning Peters -| | Ingo Wilken -+-------------------+ Stefan Reich - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ -#ifndef H_UTIL_LOG -#define H_UTIL_LOG -#ifdef __cplusplus -extern "C" { -#endif - - extern void log_open(const char * filename); - extern void log_printf(const char * str, ...); - extern void log_puts(const char * str); - extern void log_close(void); - extern void log_flush(void); - extern void log_stdio(FILE * io, const char * format, ...); - -#define log_warning(x) _log_warn x -#define log_error(x) _log_error x -#define log_info(x) _log_info x - - /* use macros above instead of these: */ - extern void _log_warn(const char * format, ...); - extern void _log_error(const char * format, ...); - extern void _log_info(unsigned int flag, const char * format, ...); - -#define LOG_FLUSH 0x01 -#define LOG_CPWARNING 0x02 -#define LOG_CPERROR 0x04 -#define LOG_INFO1 0x08 -#define LOG_INFO2 0x10 -#define LOG_INFO3 0x20 - - extern int log_flags; -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: ++-------------------+ Christian Schlittchen +| | Enno Rehling +| Eressea PBEM host | Katja Zedel +| (c) 1998 - 2003 | Henning Peters +| | Ingo Wilken ++-------------------+ Stefan Reich + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ +#ifndef H_UTIL_LOG +#define H_UTIL_LOG +#ifdef __cplusplus +extern "C" { +#endif + + extern void log_open(const char * filename); + extern void log_printf(const char * str, ...); + extern void log_puts(const char * str); + extern void log_close(void); + extern void log_flush(void); + extern void log_stdio(FILE * io, const char * format, ...); + +#define log_warning(x) _log_warn x +#define log_error(x) _log_error x +#define log_info(x) _log_info x + + /* use macros above instead of these: */ + extern void _log_warn(const char * format, ...); + extern void _log_error(const char * format, ...); + extern void _log_info(unsigned int flag, const char * format, ...); + +#define LOG_FLUSH 0x01 +#define LOG_CPWARNING 0x02 +#define LOG_CPERROR 0x04 +#define LOG_INFO1 0x08 +#define LOG_INFO2 0x10 +#define LOG_INFO3 0x20 + + extern int log_flags; +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/message.c b/src/util/message.c index 243b6ba40..cf3048512 100644 --- a/src/util/message.c +++ b/src/util/message.c @@ -1,237 +1,237 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - -*/ - -#include -#include "message.h" - -#include "goodies.h" -#include "log.h" - -/* libc includes */ -#include -#include -#include -#include -#include - -void (*msg_log_create)(const struct message * msg) = 0; - -const char * -mt_name(const message_type* mtype) -{ - return mtype->name; -} - -message_type * -mt_new(const char * name, const char * args[]) -{ - int i, nparameters = 0; - message_type * mtype = (message_type *)malloc(sizeof(message_type)); - - assert(name!=NULL); - if (name==NULL) { - log_error(("Trying to create message_type with name=0x0\n")); - return NULL; - } - if (args!=NULL) for (nparameters=0;args[nparameters];++nparameters); - - mtype->name = strdup(name); - mtype->nparameters = nparameters; - if (nparameters > 0) { - mtype->pnames = (const char**)malloc(sizeof(char*) * nparameters); - mtype->types = (const arg_type**)malloc(sizeof(arg_type*) * nparameters); - } else { - mtype->pnames = NULL; - mtype->types = NULL; - } - if (args!=NULL) for (i=0;args[i];++i) { - const char * x = args[i]; - const char * spos = strchr(x, ':'); - if (spos==NULL) { - mtype->pnames[i] = strdup(x); - mtype->types[i] = NULL; - } else { - char * cp = strncpy((char*)malloc(spos-x+1), x, spos-x); - cp[spos-x] = '\0'; - mtype->pnames[i] = cp; - mtype->types[i] = find_argtype(spos+1); - if (mtype->types[i]==NULL) { - log_error(("unknown argument type %s for message type %s\n", - spos+1, mtype->name)); - } - assert(mtype->types[i]); - } - } - return mtype; -} - -message_type * -mt_new_va(const char * name, ...) -{ - const char * args[16]; - int i = 0; - va_list marker; - - va_start(marker, name); - for (;;) { - const char * c = va_arg(marker, const char*); - args[i++] = c; - if (c==NULL) break; - } - va_end(marker); - return mt_new(name, args); -} - -arg_type * argtypes = NULL; - -void -register_argtype(const char * name, void(*free_arg)(variant), variant (*copy_arg)(variant), variant_type type) -{ - arg_type * atype = (arg_type *)malloc(sizeof(arg_type)); - atype->name = name; - atype->next = argtypes; - atype->release = free_arg; - atype->copy = copy_arg; - atype->vtype = type; - argtypes = atype; -} - -const arg_type * -find_argtype(const char * name) -{ - arg_type * atype = argtypes; - while (atype!=NULL) { - if (strcmp(atype->name, name)==0) return atype; - atype = atype->next; - } - return NULL; -} - -static variant -copy_arg(const arg_type * atype, variant data) -{ - assert(atype!=NULL); - if (atype->copy==NULL) return data; - return atype->copy(data); -} - -static void -free_arg(const arg_type * atype, variant data) -{ - assert(atype!=NULL); - if (atype->release) atype->release(data); -} - -message * -msg_create(const struct message_type * mtype, variant args[]) -{ - int i; - message * msg = (message *)malloc(sizeof(message)); - - assert(mtype!=NULL); - if (mtype==NULL) { - log_error(("Trying to create message with type=0x0\n")); - return NULL; - } - msg->type = mtype; - msg->parameters = (variant*)calloc(mtype->nparameters, sizeof(variant)); - msg->refcount=1; - for (i=0;i!=mtype->nparameters;++i) { - msg->parameters[i] = copy_arg(mtype->types[i], args[i]); - } - if (msg_log_create) msg_log_create(msg); - return msg; -} - -typedef struct messagetype_list { - struct messagetype_list * next; - const struct message_type * data; -} messagetype_list; - -#define MT_MAXHASH 1021 -static messagetype_list * messagetypes[MT_MAXHASH]; - -const message_type * -mt_find(const char * name) -{ - const struct message_type * found = NULL; - unsigned int hash = hashstring(name) % MT_MAXHASH; - messagetype_list * type = messagetypes[hash]; - while (type) { - if (strcmp(type->data->name, name)==0) { - if (found==NULL) found = type->data; - break; - } - type = type->next; - } - return found; -} - -static unsigned int -mt_id(const message_type * mtype) -{ - unsigned int key = 0; - size_t i = strlen(mtype->name); - - while (i>0) { - key = (mtype->name[--i] + key*37); - } - return key % 0x7FFFFFFF; -} - - -const message_type * -mt_register(message_type * type) -{ - unsigned int hash = hashstring(type->name) % MT_MAXHASH; - messagetype_list * mtl = messagetypes[hash]; - - while (mtl && mtl->data!=type) mtl=mtl->next; - if (mtl==NULL) { - mtl = (messagetype_list*)malloc(sizeof(messagetype_list)); - mtl->data = type; - mtl->next = messagetypes[hash]; - messagetypes[hash] = mtl; - type->key = mt_id(type); - } - return type; -} - -void -msg_free(message *msg) -{ - int i; - assert(msg->refcount==0); - for (i=0;i!=msg->type->nparameters;++i) { - free_arg(msg->type->types[i], msg->parameters[i]); - } - free((void*)msg->parameters); - free(msg); -} - -void -msg_release(struct message * msg) -{ - assert(msg->refcount>0); - if (--msg->refcount>0) return; - msg_free(msg); -} - -struct message * -msg_addref(struct message * msg) -{ - assert(msg->refcount>0); - ++msg->refcount; - return msg; -} - +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + +*/ + +#include +#include "message.h" + +#include "goodies.h" +#include "log.h" + +/* libc includes */ +#include +#include +#include +#include +#include + +void (*msg_log_create)(const struct message * msg) = 0; + +const char * +mt_name(const message_type* mtype) +{ + return mtype->name; +} + +message_type * +mt_new(const char * name, const char * args[]) +{ + int i, nparameters = 0; + message_type * mtype = (message_type *)malloc(sizeof(message_type)); + + assert(name!=NULL); + if (name==NULL) { + log_error(("Trying to create message_type with name=0x0\n")); + return NULL; + } + if (args!=NULL) for (nparameters=0;args[nparameters];++nparameters); + + mtype->name = strdup(name); + mtype->nparameters = nparameters; + if (nparameters > 0) { + mtype->pnames = (const char**)malloc(sizeof(char*) * nparameters); + mtype->types = (const arg_type**)malloc(sizeof(arg_type*) * nparameters); + } else { + mtype->pnames = NULL; + mtype->types = NULL; + } + if (args!=NULL) for (i=0;args[i];++i) { + const char * x = args[i]; + const char * spos = strchr(x, ':'); + if (spos==NULL) { + mtype->pnames[i] = strdup(x); + mtype->types[i] = NULL; + } else { + char * cp = strncpy((char*)malloc(spos-x+1), x, spos-x); + cp[spos-x] = '\0'; + mtype->pnames[i] = cp; + mtype->types[i] = find_argtype(spos+1); + if (mtype->types[i]==NULL) { + log_error(("unknown argument type %s for message type %s\n", + spos+1, mtype->name)); + } + assert(mtype->types[i]); + } + } + return mtype; +} + +message_type * +mt_new_va(const char * name, ...) +{ + const char * args[16]; + int i = 0; + va_list marker; + + va_start(marker, name); + for (;;) { + const char * c = va_arg(marker, const char*); + args[i++] = c; + if (c==NULL) break; + } + va_end(marker); + return mt_new(name, args); +} + +arg_type * argtypes = NULL; + +void +register_argtype(const char * name, void(*free_arg)(variant), variant (*copy_arg)(variant), variant_type type) +{ + arg_type * atype = (arg_type *)malloc(sizeof(arg_type)); + atype->name = name; + atype->next = argtypes; + atype->release = free_arg; + atype->copy = copy_arg; + atype->vtype = type; + argtypes = atype; +} + +const arg_type * +find_argtype(const char * name) +{ + arg_type * atype = argtypes; + while (atype!=NULL) { + if (strcmp(atype->name, name)==0) return atype; + atype = atype->next; + } + return NULL; +} + +static variant +copy_arg(const arg_type * atype, variant data) +{ + assert(atype!=NULL); + if (atype->copy==NULL) return data; + return atype->copy(data); +} + +static void +free_arg(const arg_type * atype, variant data) +{ + assert(atype!=NULL); + if (atype->release) atype->release(data); +} + +message * +msg_create(const struct message_type * mtype, variant args[]) +{ + int i; + message * msg = (message *)malloc(sizeof(message)); + + assert(mtype!=NULL); + if (mtype==NULL) { + log_error(("Trying to create message with type=0x0\n")); + return NULL; + } + msg->type = mtype; + msg->parameters = (variant*)calloc(mtype->nparameters, sizeof(variant)); + msg->refcount=1; + for (i=0;i!=mtype->nparameters;++i) { + msg->parameters[i] = copy_arg(mtype->types[i], args[i]); + } + if (msg_log_create) msg_log_create(msg); + return msg; +} + +typedef struct messagetype_list { + struct messagetype_list * next; + const struct message_type * data; +} messagetype_list; + +#define MT_MAXHASH 1021 +static messagetype_list * messagetypes[MT_MAXHASH]; + +const message_type * +mt_find(const char * name) +{ + const struct message_type * found = NULL; + unsigned int hash = hashstring(name) % MT_MAXHASH; + messagetype_list * type = messagetypes[hash]; + while (type) { + if (strcmp(type->data->name, name)==0) { + if (found==NULL) found = type->data; + break; + } + type = type->next; + } + return found; +} + +static unsigned int +mt_id(const message_type * mtype) +{ + unsigned int key = 0; + size_t i = strlen(mtype->name); + + while (i>0) { + key = (mtype->name[--i] + key*37); + } + return key % 0x7FFFFFFF; +} + + +const message_type * +mt_register(message_type * type) +{ + unsigned int hash = hashstring(type->name) % MT_MAXHASH; + messagetype_list * mtl = messagetypes[hash]; + + while (mtl && mtl->data!=type) mtl=mtl->next; + if (mtl==NULL) { + mtl = (messagetype_list*)malloc(sizeof(messagetype_list)); + mtl->data = type; + mtl->next = messagetypes[hash]; + messagetypes[hash] = mtl; + type->key = mt_id(type); + } + return type; +} + +void +msg_free(message *msg) +{ + int i; + assert(msg->refcount==0); + for (i=0;i!=msg->type->nparameters;++i) { + free_arg(msg->type->types[i], msg->parameters[i]); + } + free((void*)msg->parameters); + free(msg); +} + +void +msg_release(struct message * msg) +{ + assert(msg->refcount>0); + if (--msg->refcount>0) return; + msg_free(msg); +} + +struct message * +msg_addref(struct message * msg) +{ + assert(msg->refcount>0); + ++msg->refcount; + return msg; +} + diff --git a/src/util/message.h b/src/util/message.h index 021283903..060d71301 100644 --- a/src/util/message.h +++ b/src/util/message.h @@ -1,71 +1,71 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ -#ifndef UTIL_MESSAGE_H -#define UTIL_MESSAGE_H - -#include "variant.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct locale; - -typedef struct arg_type { - struct arg_type * next; - variant_type vtype; - const char * name; - void (*release)(variant); - variant (*copy)(variant); -} arg_type; - -typedef struct message_type { - unsigned int key; - const char * name; - int nparameters; - const char ** pnames; - const struct arg_type ** types; -} message_type; - -typedef struct message { - const struct message_type * type; - variant * parameters; - int refcount; -} message; - -extern struct message_type * mt_new(const char * name, const char ** args); -extern struct message_type * mt_new_va(const char * name, ...); - /* mt_new("simple_sentence", "subject:string", "predicate:string", - * "object:string", "lang:locale", NULL); */ - -extern struct message * msg_create(const struct message_type * type, variant args[]); - /* msg_create(&mt_simplesentence, "enno", "eats", "chocolate", &locale_de); - * parameters must be in the same order as they were for mt_new! */ - -extern void msg_release(struct message * msg); -extern struct message * msg_addref(struct message * msg); - -extern const char * mt_name(const struct message_type* mtype); - -/** message_type registry (optional): **/ -extern const struct message_type * mt_register(struct message_type *); -extern const struct message_type * mt_find(const char *); - -extern void register_argtype(const char * name, void(*free_arg)(variant), variant (*copy_arg)(variant), variant_type); -extern const struct arg_type * find_argtype(const char * name); - -extern void (*msg_log_create)(const struct message * msg); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#ifndef UTIL_MESSAGE_H +#define UTIL_MESSAGE_H + +#include "variant.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct locale; + +typedef struct arg_type { + struct arg_type * next; + variant_type vtype; + const char * name; + void (*release)(variant); + variant (*copy)(variant); +} arg_type; + +typedef struct message_type { + unsigned int key; + const char * name; + int nparameters; + const char ** pnames; + const struct arg_type ** types; +} message_type; + +typedef struct message { + const struct message_type * type; + variant * parameters; + int refcount; +} message; + +extern struct message_type * mt_new(const char * name, const char ** args); +extern struct message_type * mt_new_va(const char * name, ...); + /* mt_new("simple_sentence", "subject:string", "predicate:string", + * "object:string", "lang:locale", NULL); */ + +extern struct message * msg_create(const struct message_type * type, variant args[]); + /* msg_create(&mt_simplesentence, "enno", "eats", "chocolate", &locale_de); + * parameters must be in the same order as they were for mt_new! */ + +extern void msg_release(struct message * msg); +extern struct message * msg_addref(struct message * msg); + +extern const char * mt_name(const struct message_type* mtype); + +/** message_type registry (optional): **/ +extern const struct message_type * mt_register(struct message_type *); +extern const struct message_type * mt_find(const char *); + +extern void register_argtype(const char * name, void(*free_arg)(variant), variant (*copy_arg)(variant), variant_type); +extern const struct arg_type * find_argtype(const char * name); + +extern void (*msg_log_create)(const struct message * msg); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/nrmessage.c b/src/util/nrmessage.c index 0086159d5..50587deb8 100644 --- a/src/util/nrmessage.c +++ b/src/util/nrmessage.c @@ -1,174 +1,174 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - -*/ - -#include -#include "nrmessage.h" -#include "nrmessage_struct.h" - -/* util includes */ -#include "bsdstring.h" -#include "log.h" -#include "message.h" -#include "language.h" -#include "translation.h" -#include "goodies.h" - -/* libc includes */ -#include -#include -#include - -#define NRT_MAXHASH 1021 -static nrmessage_type * nrtypes[NRT_MAXHASH]; - -const char * -nrt_string(const struct nrmessage_type *type) -{ - return type->string; -} - -nrmessage_type * -nrt_find(const struct locale * lang, const struct message_type * mtype) -{ - nrmessage_type * found = NULL; - unsigned int hash = hashstring(mtype->name) % NRT_MAXHASH; - nrmessage_type * type = nrtypes[hash]; - while (type) { - if (type->mtype==mtype) { - if (found==NULL) found = type; - else if (type->lang==NULL) found = type; - if (lang==type->lang) { - found = type; - break; - } - } - type = type->next; - } - if (!found) { - log_warning(("could not find nr-type %s for locale %s\n", - mtype->name, locale_name(lang))); - } - if (lang && found && found->lang!=lang) { - log_warning(("could not find nr-type %s for locale %s, using %s\n", - mtype->name, locale_name(lang), locale_name(found->lang))); - } - return found; -} - -nrsection * sections; - -const nrsection * -section_find(const char * name) -{ - nrsection ** mcp = §ions; - if (name==NULL) return NULL; - for (;*mcp;mcp=&(*mcp)->next) { - nrsection * mc = *mcp; - if (!strcmp(mc->name, name)) break; - } - return *mcp; -} - -const nrsection * -section_add(const char * name) -{ - nrsection ** mcp = §ions; - if (name==NULL) return NULL; - for (;*mcp;mcp=&(*mcp)->next) { - nrsection * mc = *mcp; - if (!strcmp(mc->name, name)) break; - } - if (!*mcp) { - nrsection * mc = calloc(sizeof(nrsection), 1); - mc->name = strdup(name); - *mcp = mc; - } - return *mcp; -} - -void -nrt_register(const struct message_type * mtype, const struct locale * lang, const char * string, int level, const char * section) -{ - unsigned int hash = hashstring(mtype->name) % NRT_MAXHASH; - nrmessage_type * nrt = nrtypes[hash]; - while (nrt && (nrt->lang!=lang || nrt->mtype!=mtype)) { - nrt = nrt->next; - } - if (nrt) { - log_error(("duplicate message-type %s\n", mtype->name)); - assert(!nrt || !"trying to register same nr-type twice"); - } else { - int i; - char zNames[256]; - char * c = zNames; - nrt = malloc(sizeof(nrmessage_type)); - nrt->lang = lang; - nrt->mtype = mtype; - nrt->next = nrtypes[hash]; - nrt->level=level; - if (section) { - const nrsection * s = section_find(section); - if (s==NULL) { - s = section_add(section); - } - nrt->section = s->name; - } - else nrt->section = NULL; - nrtypes[hash] = nrt; - assert(string && *string); - nrt->string = strdup(string); - *c = '\0'; - for (i=0;i!=mtype->nparameters;++i) { - if (i!=0) *c++ = ' '; - c+= strlen(strcpy(c, mtype->pnames[i])); - } - nrt->vars = strdup(zNames); - } -} - -size_t -nr_render(const struct message * msg, const struct locale * lang, char * buffer, size_t size, const void * userdata) -{ - struct nrmessage_type * nrt = nrt_find(lang, msg->type); - - if (nrt) { - const char * m = translate(nrt->string, userdata, nrt->vars, msg->parameters); - if (m) { - return strlcpy((char*)buffer, m, size); - } else { - log_error(("Couldn't render message %s\n", nrt->mtype->name)); - } - } - if (size>0 && buffer) buffer[0] = 0; - return 0; -} - -int -nr_level(const struct message *msg) -{ - nrmessage_type * nrt = nrt_find(NULL, msg->type); - return nrt?nrt->level:0; -} - -const char * -nr_section(const struct message *msg) -{ - nrmessage_type * nrt = nrt_find(default_locale, msg->type); - return nrt?nrt->section:NULL; -} - -const char * -nrt_section(const nrmessage_type * nrt) -{ - return nrt?nrt->section:NULL; -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + +*/ + +#include +#include "nrmessage.h" +#include "nrmessage_struct.h" + +/* util includes */ +#include "bsdstring.h" +#include "log.h" +#include "message.h" +#include "language.h" +#include "translation.h" +#include "goodies.h" + +/* libc includes */ +#include +#include +#include + +#define NRT_MAXHASH 1021 +static nrmessage_type * nrtypes[NRT_MAXHASH]; + +const char * +nrt_string(const struct nrmessage_type *type) +{ + return type->string; +} + +nrmessage_type * +nrt_find(const struct locale * lang, const struct message_type * mtype) +{ + nrmessage_type * found = NULL; + unsigned int hash = hashstring(mtype->name) % NRT_MAXHASH; + nrmessage_type * type = nrtypes[hash]; + while (type) { + if (type->mtype==mtype) { + if (found==NULL) found = type; + else if (type->lang==NULL) found = type; + if (lang==type->lang) { + found = type; + break; + } + } + type = type->next; + } + if (!found) { + log_warning(("could not find nr-type %s for locale %s\n", + mtype->name, locale_name(lang))); + } + if (lang && found && found->lang!=lang) { + log_warning(("could not find nr-type %s for locale %s, using %s\n", + mtype->name, locale_name(lang), locale_name(found->lang))); + } + return found; +} + +nrsection * sections; + +const nrsection * +section_find(const char * name) +{ + nrsection ** mcp = §ions; + if (name==NULL) return NULL; + for (;*mcp;mcp=&(*mcp)->next) { + nrsection * mc = *mcp; + if (!strcmp(mc->name, name)) break; + } + return *mcp; +} + +const nrsection * +section_add(const char * name) +{ + nrsection ** mcp = §ions; + if (name==NULL) return NULL; + for (;*mcp;mcp=&(*mcp)->next) { + nrsection * mc = *mcp; + if (!strcmp(mc->name, name)) break; + } + if (!*mcp) { + nrsection * mc = calloc(sizeof(nrsection), 1); + mc->name = strdup(name); + *mcp = mc; + } + return *mcp; +} + +void +nrt_register(const struct message_type * mtype, const struct locale * lang, const char * string, int level, const char * section) +{ + unsigned int hash = hashstring(mtype->name) % NRT_MAXHASH; + nrmessage_type * nrt = nrtypes[hash]; + while (nrt && (nrt->lang!=lang || nrt->mtype!=mtype)) { + nrt = nrt->next; + } + if (nrt) { + log_error(("duplicate message-type %s\n", mtype->name)); + assert(!nrt || !"trying to register same nr-type twice"); + } else { + int i; + char zNames[256]; + char * c = zNames; + nrt = malloc(sizeof(nrmessage_type)); + nrt->lang = lang; + nrt->mtype = mtype; + nrt->next = nrtypes[hash]; + nrt->level=level; + if (section) { + const nrsection * s = section_find(section); + if (s==NULL) { + s = section_add(section); + } + nrt->section = s->name; + } + else nrt->section = NULL; + nrtypes[hash] = nrt; + assert(string && *string); + nrt->string = strdup(string); + *c = '\0'; + for (i=0;i!=mtype->nparameters;++i) { + if (i!=0) *c++ = ' '; + c+= strlen(strcpy(c, mtype->pnames[i])); + } + nrt->vars = strdup(zNames); + } +} + +size_t +nr_render(const struct message * msg, const struct locale * lang, char * buffer, size_t size, const void * userdata) +{ + struct nrmessage_type * nrt = nrt_find(lang, msg->type); + + if (nrt) { + const char * m = translate(nrt->string, userdata, nrt->vars, msg->parameters); + if (m) { + return strlcpy((char*)buffer, m, size); + } else { + log_error(("Couldn't render message %s\n", nrt->mtype->name)); + } + } + if (size>0 && buffer) buffer[0] = 0; + return 0; +} + +int +nr_level(const struct message *msg) +{ + nrmessage_type * nrt = nrt_find(NULL, msg->type); + return nrt?nrt->level:0; +} + +const char * +nr_section(const struct message *msg) +{ + nrmessage_type * nrt = nrt_find(default_locale, msg->type); + return nrt?nrt->section:NULL; +} + +const char * +nrt_section(const nrmessage_type * nrt) +{ + return nrt?nrt->section:NULL; +} diff --git a/src/util/nrmessage.h b/src/util/nrmessage.h index f36d8e79f..53a1fdc78 100644 --- a/src/util/nrmessage.h +++ b/src/util/nrmessage.h @@ -1,56 +1,56 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_UTIL_NRMESSAGE -#define H_UTIL_NRMESSAGE -#ifdef __cplusplus -extern "C" { -#endif - -struct locale; -struct message; -struct message_type; -struct nrmessage_type; - -typedef struct nrsection { - char * name; - struct nrsection * next; -} nrsection; - -extern nrsection * sections; - -extern void nrt_register(const struct message_type * mtype, - const struct locale * lang, const char * script, - int level, const char * section); -extern struct nrmessage_type * nrt_find(const struct locale *, - const struct message_type *); -extern const char * nrt_string(const struct nrmessage_type *type); -extern const char * nrt_section(const struct nrmessage_type * mt); - -extern size_t nr_render(const struct message * msg, const struct locale * lang, - char * buffer, size_t size, const void * userdata); -extern int nr_level(const struct message *msg); -extern const char * nr_section(const struct message *msg); - - -/* before: - * fogblock;movement:0;de;{unit} konnte von {region} nicht nach {$dir direction} ausreisen, der Nebel war zu dicht. - * after: - * fogblock:movement:0 - * $unit($unit) konnte von $region($region) nicht nach $direction($direction) ausreisen, der Nebel war zu dicht. - * unit:unit region:region direction:int - */ - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_UTIL_NRMESSAGE +#define H_UTIL_NRMESSAGE +#ifdef __cplusplus +extern "C" { +#endif + +struct locale; +struct message; +struct message_type; +struct nrmessage_type; + +typedef struct nrsection { + char * name; + struct nrsection * next; +} nrsection; + +extern nrsection * sections; + +extern void nrt_register(const struct message_type * mtype, + const struct locale * lang, const char * script, + int level, const char * section); +extern struct nrmessage_type * nrt_find(const struct locale *, + const struct message_type *); +extern const char * nrt_string(const struct nrmessage_type *type); +extern const char * nrt_section(const struct nrmessage_type * mt); + +extern size_t nr_render(const struct message * msg, const struct locale * lang, + char * buffer, size_t size, const void * userdata); +extern int nr_level(const struct message *msg); +extern const char * nr_section(const struct message *msg); + + +/* before: + * fogblock;movement:0;de;{unit} konnte von {region} nicht nach {$dir direction} ausreisen, der Nebel war zu dicht. + * after: + * fogblock:movement:0 + * $unit($unit) konnte von $region($region) nicht nach $direction($direction) ausreisen, der Nebel war zu dicht. + * unit:unit region:region direction:int + */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/nrmessage_struct.h b/src/util/nrmessage_struct.h index ac14bef82..3d36249df 100644 --- a/src/util/nrmessage_struct.h +++ b/src/util/nrmessage_struct.h @@ -1,20 +1,20 @@ -#ifndef CLASS_NRMESSAGE_STRUCT -#define CLASS_NRMESSAGE_STRUCT - -/* This file should not be included by anything in the server. If you - * feel that you need to include it, it's a sure sign that you're trying to - * do something BAD. */ - -typedef struct nrmessage_type { - const struct message_type * mtype; - const struct locale * lang; - const char * string; - const char * vars; - struct nrmessage_type * next; - int level; - const char * section; -} nrmessage_type; - -extern nrmessage_type * get_nrmessagetypes(void); - -#endif +#ifndef CLASS_NRMESSAGE_STRUCT +#define CLASS_NRMESSAGE_STRUCT + +/* This file should not be included by anything in the server. If you + * feel that you need to include it, it's a sure sign that you're trying to + * do something BAD. */ + +typedef struct nrmessage_type { + const struct message_type * mtype; + const struct locale * lang; + const char * string; + const char * vars; + struct nrmessage_type * next; + int level; + const char * section; +} nrmessage_type; + +extern nrmessage_type * get_nrmessagetypes(void); + +#endif diff --git a/src/util/parser.c b/src/util/parser.c index 1dfff3798..f9944b9a6 100644 --- a/src/util/parser.c +++ b/src/util/parser.c @@ -1,195 +1,195 @@ -#include -#include "parser.h" -#include "unicode.h" -#include "log.h" - -#include -#include -#include - -#define SPACE_REPLACEMENT '~' -#define ESCAPE_CHAR '\\' -#define MAXTOKENSIZE 8192 - -typedef struct parser_state { - const char *current_token; - char * current_cmd; - struct parser_state * next; -} parser_state; - -static parser_state * state; - -static int -eatwhitespace_c(const char ** str_p) -{ - int ret = 0; - ucs4_t ucs; - size_t len; - const char * str = *str_p; - - /* skip over potential whitespace */ - for (;;) { - unsigned char utf8_character = (unsigned char)*str; - if (~utf8_character & 0x80) { - if (!iswxspace(utf8_character)) break; - ++str; - } else { - ret = unicode_utf8_to_ucs4(&ucs, str, &len); - if (ret!=0) { - log_warning(("illegal character sequence in UTF8 string: %s\n", str)); - break; - } - if (!iswxspace((wint_t)ucs)) break; - str+=len; - } - } - *str_p = str; - return ret; -} - -void -init_tokens_str(const char * initstr, char * cmd) -{ - if (state==NULL) { - state = malloc(sizeof(parser_state)); - } - else if (state->current_cmd) free(state->current_cmd); - state->current_cmd = cmd; - state->current_token = initstr; -} - -void -parser_pushstate(void) -{ - parser_state * new_state = malloc(sizeof(parser_state)); - new_state->current_cmd = NULL; - new_state->current_token = NULL; - new_state->next = state; - state = new_state; -} - -void -parser_popstate(void) -{ - parser_state * new_state = state->next; - if (state->current_cmd!=NULL) free(state->current_cmd); - free(state); - state = new_state; -} - -boolean -parser_end(void) -{ - eatwhitespace_c(&state->current_token); - return *state->current_token == 0; -} - -void -skip_token(void) -{ - char quotechar = 0; - eatwhitespace_c(&state->current_token); - - while (*state->current_token) { - ucs4_t ucs; - size_t len; - - unsigned char utf8_character = (unsigned char)state->current_token[0]; - if (~utf8_character & 0x80) { - ucs = utf8_character; - ++state->current_token; - } else { - int ret = unicode_utf8_to_ucs4(&ucs, state->current_token, &len); - if (ret==0) { - state->current_token+=len; - } else { - log_warning(("illegal character sequence in UTF8 string: %s\n", state->current_token)); - } - } - if (iswxspace((wint_t)ucs) && quotechar==0) { - return; - } else { - switch(utf8_character) { - case '"': - case '\'': - if (utf8_character==quotechar) return; - quotechar = utf8_character; - break; - case ESCAPE_CHAR: - ++state->current_token; - break; - } - } - } -} - -const char * -parse_token(const char ** str) -{ - static char lbuf[MAXTOKENSIZE]; /* STATIC_RESULT: used for return, not across calls */ - char * cursor = lbuf; - char quotechar = 0; - boolean escape = false; - const char * ctoken = *str; - - assert(ctoken); - - eatwhitespace_c(&ctoken); - while (*ctoken && cursor-lbuf < MAXTOKENSIZE-1) { - ucs4_t ucs; - size_t len; - boolean copy = false; - - unsigned char utf8_character = *(unsigned char *)ctoken; - if (~utf8_character & 0x80) { - ucs = utf8_character; - len = 1; - } else { - int ret = unicode_utf8_to_ucs4(&ucs, ctoken, &len); - if (ret!=0) { - log_warning(("illegal character sequence in UTF8 string: %s\n", ctoken)); - break; - } - } - if (escape) { - copy = true; - escape = false; - } else if (iswxspace((wint_t)ucs)) { - if (quotechar==0) break; - copy = true; - } else if (utf8_character=='"' || utf8_character=='\'') { - if (utf8_character==quotechar) { - ++ctoken; - break; - } else if (quotechar==0) { - quotechar = utf8_character; - ++ctoken; - } else { - *cursor++ = *ctoken++; - } - } else if (utf8_character==SPACE_REPLACEMENT) { - *cursor++ = ' '; - ++ctoken; - } else if (utf8_character==ESCAPE_CHAR) { - escape = true; - ++ctoken; - } else { - copy = true; - } - if (copy) { - memcpy(cursor, ctoken, len); - cursor+=len; - ctoken+=len; - } - } - - *cursor = '\0'; - *str = ctoken; - return lbuf; -} - -const char * -getstrtoken(void) -{ - return parse_token((const char **)&state->current_token); -} +#include +#include "parser.h" +#include "unicode.h" +#include "log.h" + +#include +#include +#include + +#define SPACE_REPLACEMENT '~' +#define ESCAPE_CHAR '\\' +#define MAXTOKENSIZE 8192 + +typedef struct parser_state { + const char *current_token; + char * current_cmd; + struct parser_state * next; +} parser_state; + +static parser_state * state; + +static int +eatwhitespace_c(const char ** str_p) +{ + int ret = 0; + ucs4_t ucs; + size_t len; + const char * str = *str_p; + + /* skip over potential whitespace */ + for (;;) { + unsigned char utf8_character = (unsigned char)*str; + if (~utf8_character & 0x80) { + if (!iswxspace(utf8_character)) break; + ++str; + } else { + ret = unicode_utf8_to_ucs4(&ucs, str, &len); + if (ret!=0) { + log_warning(("illegal character sequence in UTF8 string: %s\n", str)); + break; + } + if (!iswxspace((wint_t)ucs)) break; + str+=len; + } + } + *str_p = str; + return ret; +} + +void +init_tokens_str(const char * initstr, char * cmd) +{ + if (state==NULL) { + state = malloc(sizeof(parser_state)); + } + else if (state->current_cmd) free(state->current_cmd); + state->current_cmd = cmd; + state->current_token = initstr; +} + +void +parser_pushstate(void) +{ + parser_state * new_state = malloc(sizeof(parser_state)); + new_state->current_cmd = NULL; + new_state->current_token = NULL; + new_state->next = state; + state = new_state; +} + +void +parser_popstate(void) +{ + parser_state * new_state = state->next; + if (state->current_cmd!=NULL) free(state->current_cmd); + free(state); + state = new_state; +} + +boolean +parser_end(void) +{ + eatwhitespace_c(&state->current_token); + return *state->current_token == 0; +} + +void +skip_token(void) +{ + char quotechar = 0; + eatwhitespace_c(&state->current_token); + + while (*state->current_token) { + ucs4_t ucs; + size_t len; + + unsigned char utf8_character = (unsigned char)state->current_token[0]; + if (~utf8_character & 0x80) { + ucs = utf8_character; + ++state->current_token; + } else { + int ret = unicode_utf8_to_ucs4(&ucs, state->current_token, &len); + if (ret==0) { + state->current_token+=len; + } else { + log_warning(("illegal character sequence in UTF8 string: %s\n", state->current_token)); + } + } + if (iswxspace((wint_t)ucs) && quotechar==0) { + return; + } else { + switch(utf8_character) { + case '"': + case '\'': + if (utf8_character==quotechar) return; + quotechar = utf8_character; + break; + case ESCAPE_CHAR: + ++state->current_token; + break; + } + } + } +} + +const char * +parse_token(const char ** str) +{ + static char lbuf[MAXTOKENSIZE]; /* STATIC_RESULT: used for return, not across calls */ + char * cursor = lbuf; + char quotechar = 0; + boolean escape = false; + const char * ctoken = *str; + + assert(ctoken); + + eatwhitespace_c(&ctoken); + while (*ctoken && cursor-lbuf < MAXTOKENSIZE-1) { + ucs4_t ucs; + size_t len; + boolean copy = false; + + unsigned char utf8_character = *(unsigned char *)ctoken; + if (~utf8_character & 0x80) { + ucs = utf8_character; + len = 1; + } else { + int ret = unicode_utf8_to_ucs4(&ucs, ctoken, &len); + if (ret!=0) { + log_warning(("illegal character sequence in UTF8 string: %s\n", ctoken)); + break; + } + } + if (escape) { + copy = true; + escape = false; + } else if (iswxspace((wint_t)ucs)) { + if (quotechar==0) break; + copy = true; + } else if (utf8_character=='"' || utf8_character=='\'') { + if (utf8_character==quotechar) { + ++ctoken; + break; + } else if (quotechar==0) { + quotechar = utf8_character; + ++ctoken; + } else { + *cursor++ = *ctoken++; + } + } else if (utf8_character==SPACE_REPLACEMENT) { + *cursor++ = ' '; + ++ctoken; + } else if (utf8_character==ESCAPE_CHAR) { + escape = true; + ++ctoken; + } else { + copy = true; + } + if (copy) { + memcpy(cursor, ctoken, len); + cursor+=len; + ctoken+=len; + } + } + + *cursor = '\0'; + *str = ctoken; + return lbuf; +} + +const char * +getstrtoken(void) +{ + return parse_token((const char **)&state->current_token); +} diff --git a/src/util/parser.h b/src/util/parser.h index fecb5ff9f..d856ef9cb 100644 --- a/src/util/parser.h +++ b/src/util/parser.h @@ -1,29 +1,29 @@ -/* vi: set ts=2: - * +-------------------+ Christian Schlittchen - * | | Enno Rehling - * | Eressea PBEM host | Katja Zedel - * | (c) 1998 - 2007 | - * | | This program may not be used, modified or distributed - * +-------------------+ without prior permission by the authors of Eressea. - * - */ - -#ifndef UTIL_PARSER_H -#define UTIL_PARSER_H -#ifdef __cplusplus -extern "C" { -#endif - -extern void init_tokens_str(const char * initstr, char * cmd); /* initialize token parsing, take ownership of cmd */ -extern void skip_token(void); -extern const char * parse_token(const char ** str); -extern void parser_pushstate(void); -extern void parser_popstate(void); -extern boolean parser_end(void); -extern const char *getstrtoken(void); - -#ifdef __cplusplus -} -#endif - -#endif +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2007 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +#ifndef UTIL_PARSER_H +#define UTIL_PARSER_H +#ifdef __cplusplus +extern "C" { +#endif + +extern void init_tokens_str(const char * initstr, char * cmd); /* initialize token parsing, take ownership of cmd */ +extern void skip_token(void); +extern const char * parse_token(const char ** str); +extern void parser_pushstate(void); +extern void parser_popstate(void); +extern boolean parser_end(void); +extern const char *getstrtoken(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/util/patricia.c b/src/util/patricia.c index 4189f146b..cafd71e3a 100644 --- a/src/util/patricia.c +++ b/src/util/patricia.c @@ -1,236 +1,236 @@ -#include - -#include -#include -#include - -#include "patricia.h" - -#define MAXKEYLEN 128 - -/* TODO: custom memory management to optimize cache layout, or use arrays. */ - -/* NOTE: The structure saves an extra 0 delimiter for the key. Technically - * this wouldn't be necessary (because we know its' length from data[0]), - * but it makes it possible for trie_getkey to return a key without making - * a copy or have a cumbersome (const char**, size_t*) interface. - * +-----------+-------------+------+------------+ - * data: | keylen(1) | key(keylen) | 0(1) | data(size) | - * +-----------+-------------+------+------------+ - */ - -struct trie_node { - struct trie_node *l, *r; - char * data; - unsigned int bitpos; -}; - -#if 1 -#define get_bit(c, s, p) (unsigned int)((((p)>>3)>(unsigned int)(s))?0:((c)[(p)>>3]>>((p)&7)&1)) -#else -unsigned int get_bit(const char * c, size_t s, unsigned int p) -{ - if ((p>>3)>=(unsigned int)s) return 0; - return ((c)[p>>3]>>(p&7)&1); -} -#endif -#define node_bit(n, p) get_bit((n)->data+1, (n)->data[0], (p)) - -trie_node * trie_insert(trie_node **root_p, const char * key, const void * data, size_t size) -{ - trie_node * new_node; - size_t keylen = strlen(key); - trie_node ** insert_p = root_p, *node = *insert_p; - unsigned int p, bit=0; - - assert(keylenbitpos) { - insert_p = bit?&node->r:&node->l; - node = *insert_p; - if (node==NULL) { - continue; - } - } - - /* if we are looking at a back-node, we need to add our node before it. */ - if (p>=node->bitpos) { - /* find the point p where both differ. */ - if (keylen==(unsigned int)node->data[0] && strncmp(key, node->data+1, keylen)==0) { - /* we are trying to insert the same key again */ - - return node; - } - do { - ++p; - bit = get_bit(key, keylen, p); - } while (node_bit(node, p)==bit); - break; - } - - /* if instead we differ before reaching the end of the current prefix, we must split. - * we insert our node before the current one and re-attach it. */ - if (node_bit(node, p)!=bit) { - break; - } - } - - new_node = (trie_node *)malloc(sizeof(trie_node)); - new_node->bitpos = p; - new_node->data = malloc(keylen+2+size); - new_node->data[0] = (char)keylen; - memcpy(new_node->data+1, key, keylen+1); - if (data!=NULL && size>0) { - /* if data is NULL then the user only wanted some space that they're going to write to later */ - /* if size is 0 then the user is using the trie as a set, not a map */ - memcpy(new_node->data+2+keylen, data, size); - } - if (bit) { - new_node->l = node; - new_node->r = new_node; /* loop the 1-bit to ourselves, search will end */ - } else { - new_node->l = new_node; /* loop the 0-bit to ourselves, search will end */ - new_node->r = node; - } - *insert_p = new_node; - return new_node; -} - -void trie_remove(trie_node **root_p, trie_node *pos) -{ - if (pos!=NULL) { - const char * key = trie_getkey(pos); - size_t keylen = pos->data[0]; - trie_node ** node_p = root_p; - trie_node * node = *root_p; - - while (node) { - int bit; - trie_node ** next_p; - trie_node * next; - - if (node == pos) { - if (node->l==node) { - *node_p = node->r; - break; - } else if (node->r==node) { - *node_p = node->l; - break; - } - } - - bit = get_bit(key, keylen, node->bitpos); - next_p = bit?&node->r:&node->l; - next = *next_p; - if (next == pos && next->bitpos<=node->bitpos) { - /* the element that has a back-pointer to pos gets swapped with pos */ - char * data = pos->data; - pos->data = node->data; - node->data = data; - - /* finally, find the back-pointer to node and set it to pos */ - next_p = bit?&node->l:&node->r; /* NB: this is the OTHER child of node */ - next = *next_p; - key = trie_getkey(node); - keylen = (unsigned int)node->data[0]; - while (next) { - int new_bit; - if (next==node) { - *next_p = pos; - break; - } - new_bit = get_bit(key, keylen, next->bitpos); - next_p = new_bit?&next->r:&next->l; - next = *next_p; - } - *node_p = bit?node->l:node->r; - break; - } - node = *next_p; - node_p = next_p; - } - free(node->data); - free(node); - } -} - -void trie_debug(trie_node * root) -{ - const char * l = root->l?trie_getkey(root->l):"?"; - const char * r = root->r?trie_getkey(root->r):"?"; - printf("%s %d | %s | %s\n", trie_getkey(root), root->bitpos, l, r); - if (root->l && root->l->bitpos > root->bitpos) trie_debug(root->l); - if (root->r && root->r->bitpos > root->bitpos) trie_debug(root->r); -} - -trie_node * trie_find(trie_node *root, const char *key) -{ - trie_node * node = root; - size_t keylen = strlen(key); - - while (node) { - int bit = get_bit(key, keylen, node->bitpos); - trie_node * next = bit?node->r:node->l; - - if (next!=NULL) { - if (node->bitpos>=next->bitpos) { - if (keylen==(unsigned int)next->data[0] && strncmp(key, next->data+1, keylen)==0) { - return next; - } - next = NULL; - } - } - node = next; - } - return NULL; -} - -trie_node * trie_find_prefix(trie_node *root, const char *key) -{ - trie_node * node = root; - size_t keylen = strlen(key); - - while (node) { - int bit = get_bit(key, keylen, node->bitpos); - trie_node * next = bit?node->r:node->l; - - if (next!=NULL) { - if (node->bitpos>=next->bitpos) { - if (keylen<=(unsigned int)next->data[0] && strncmp(key, next->data+1, keylen)==0) { - return next; - } - next = NULL; - } - } - node = next; - } - return NULL; -} - -void * trie_getdata(trie_node * node) -{ - return node->data+2+node->data[0]; -} - -const char * trie_getkey(trie_node * node) -{ - return node->data+1; -} - -void trie_free(trie_node * root) -{ - if (root) { - if (root->l && root->l->bitpos>root->bitpos) trie_free(root->l); - if (root->r && root->r->bitpos>root->bitpos) trie_free(root->r); - free(root); - } -} +#include + +#include +#include +#include + +#include "patricia.h" + +#define MAXKEYLEN 128 + +/* TODO: custom memory management to optimize cache layout, or use arrays. */ + +/* NOTE: The structure saves an extra 0 delimiter for the key. Technically + * this wouldn't be necessary (because we know its' length from data[0]), + * but it makes it possible for trie_getkey to return a key without making + * a copy or have a cumbersome (const char**, size_t*) interface. + * +-----------+-------------+------+------------+ + * data: | keylen(1) | key(keylen) | 0(1) | data(size) | + * +-----------+-------------+------+------------+ + */ + +struct trie_node { + struct trie_node *l, *r; + char * data; + unsigned int bitpos; +}; + +#if 1 +#define get_bit(c, s, p) (unsigned int)((((p)>>3)>(unsigned int)(s))?0:((c)[(p)>>3]>>((p)&7)&1)) +#else +unsigned int get_bit(const char * c, size_t s, unsigned int p) +{ + if ((p>>3)>=(unsigned int)s) return 0; + return ((c)[p>>3]>>(p&7)&1); +} +#endif +#define node_bit(n, p) get_bit((n)->data+1, (n)->data[0], (p)) + +trie_node * trie_insert(trie_node **root_p, const char * key, const void * data, size_t size) +{ + trie_node * new_node; + size_t keylen = strlen(key); + trie_node ** insert_p = root_p, *node = *insert_p; + unsigned int p, bit=0; + + assert(keylenbitpos) { + insert_p = bit?&node->r:&node->l; + node = *insert_p; + if (node==NULL) { + continue; + } + } + + /* if we are looking at a back-node, we need to add our node before it. */ + if (p>=node->bitpos) { + /* find the point p where both differ. */ + if (keylen==(unsigned int)node->data[0] && strncmp(key, node->data+1, keylen)==0) { + /* we are trying to insert the same key again */ + + return node; + } + do { + ++p; + bit = get_bit(key, keylen, p); + } while (node_bit(node, p)==bit); + break; + } + + /* if instead we differ before reaching the end of the current prefix, we must split. + * we insert our node before the current one and re-attach it. */ + if (node_bit(node, p)!=bit) { + break; + } + } + + new_node = (trie_node *)malloc(sizeof(trie_node)); + new_node->bitpos = p; + new_node->data = malloc(keylen+2+size); + new_node->data[0] = (char)keylen; + memcpy(new_node->data+1, key, keylen+1); + if (data!=NULL && size>0) { + /* if data is NULL then the user only wanted some space that they're going to write to later */ + /* if size is 0 then the user is using the trie as a set, not a map */ + memcpy(new_node->data+2+keylen, data, size); + } + if (bit) { + new_node->l = node; + new_node->r = new_node; /* loop the 1-bit to ourselves, search will end */ + } else { + new_node->l = new_node; /* loop the 0-bit to ourselves, search will end */ + new_node->r = node; + } + *insert_p = new_node; + return new_node; +} + +void trie_remove(trie_node **root_p, trie_node *pos) +{ + if (pos!=NULL) { + const char * key = trie_getkey(pos); + size_t keylen = pos->data[0]; + trie_node ** node_p = root_p; + trie_node * node = *root_p; + + while (node) { + int bit; + trie_node ** next_p; + trie_node * next; + + if (node == pos) { + if (node->l==node) { + *node_p = node->r; + break; + } else if (node->r==node) { + *node_p = node->l; + break; + } + } + + bit = get_bit(key, keylen, node->bitpos); + next_p = bit?&node->r:&node->l; + next = *next_p; + if (next == pos && next->bitpos<=node->bitpos) { + /* the element that has a back-pointer to pos gets swapped with pos */ + char * data = pos->data; + pos->data = node->data; + node->data = data; + + /* finally, find the back-pointer to node and set it to pos */ + next_p = bit?&node->l:&node->r; /* NB: this is the OTHER child of node */ + next = *next_p; + key = trie_getkey(node); + keylen = (unsigned int)node->data[0]; + while (next) { + int new_bit; + if (next==node) { + *next_p = pos; + break; + } + new_bit = get_bit(key, keylen, next->bitpos); + next_p = new_bit?&next->r:&next->l; + next = *next_p; + } + *node_p = bit?node->l:node->r; + break; + } + node = *next_p; + node_p = next_p; + } + free(node->data); + free(node); + } +} + +void trie_debug(trie_node * root) +{ + const char * l = root->l?trie_getkey(root->l):"?"; + const char * r = root->r?trie_getkey(root->r):"?"; + printf("%s %d | %s | %s\n", trie_getkey(root), root->bitpos, l, r); + if (root->l && root->l->bitpos > root->bitpos) trie_debug(root->l); + if (root->r && root->r->bitpos > root->bitpos) trie_debug(root->r); +} + +trie_node * trie_find(trie_node *root, const char *key) +{ + trie_node * node = root; + size_t keylen = strlen(key); + + while (node) { + int bit = get_bit(key, keylen, node->bitpos); + trie_node * next = bit?node->r:node->l; + + if (next!=NULL) { + if (node->bitpos>=next->bitpos) { + if (keylen==(unsigned int)next->data[0] && strncmp(key, next->data+1, keylen)==0) { + return next; + } + next = NULL; + } + } + node = next; + } + return NULL; +} + +trie_node * trie_find_prefix(trie_node *root, const char *key) +{ + trie_node * node = root; + size_t keylen = strlen(key); + + while (node) { + int bit = get_bit(key, keylen, node->bitpos); + trie_node * next = bit?node->r:node->l; + + if (next!=NULL) { + if (node->bitpos>=next->bitpos) { + if (keylen<=(unsigned int)next->data[0] && strncmp(key, next->data+1, keylen)==0) { + return next; + } + next = NULL; + } + } + node = next; + } + return NULL; +} + +void * trie_getdata(trie_node * node) +{ + return node->data+2+node->data[0]; +} + +const char * trie_getkey(trie_node * node) +{ + return node->data+1; +} + +void trie_free(trie_node * root) +{ + if (root) { + if (root->l && root->l->bitpos>root->bitpos) trie_free(root->l); + if (root->r && root->r->bitpos>root->bitpos) trie_free(root->r); + free(root); + } +} diff --git a/src/util/patricia.h b/src/util/patricia.h index f01be96be..42efa89fc 100644 --- a/src/util/patricia.h +++ b/src/util/patricia.h @@ -1,21 +1,21 @@ -#ifndef H_PATRICIA -#define H_PATRICIA -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct trie_node trie_node; - -trie_node * trie_insert(trie_node **root, const char *key, const void *data, size_t size); -trie_node * trie_find(trie_node *root, const char *key); -void * trie_getdata(trie_node *node); -const char * trie_getkey(trie_node *node); -void trie_free(trie_node * root); -void trie_remove(trie_node **root_p, trie_node *pos); -void trie_debug(trie_node * root); -trie_node * trie_find_prefix(trie_node *root, const char *key); - -#ifdef __cplusplus -} -#endif -#endif +#ifndef H_PATRICIA +#define H_PATRICIA +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct trie_node trie_node; + +trie_node * trie_insert(trie_node **root, const char *key, const void *data, size_t size); +trie_node * trie_find(trie_node *root, const char *key); +void * trie_getdata(trie_node *node); +const char * trie_getkey(trie_node *node); +void trie_free(trie_node * root); +void trie_remove(trie_node **root_p, trie_node *pos); +void trie_debug(trie_node * root); +trie_node * trie_find_prefix(trie_node *root, const char *key); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/rand.c b/src/util/rand.c index 9694c182c..92f2b927a 100644 --- a/src/util/rand.c +++ b/src/util/rand.c @@ -1,72 +1,72 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "rand.h" -#include "rng.h" - -#include -#include -#include -#include -#include - -#define M_PIl 3.1415926535897932384626433832795029L /* pi */ - -/* NormalRand aus python, random.py geklaut, dort ist Referenz auf -* den Algorithmus. mu = Mittelwert, sigma = Standardabweichung. -* http://de.wikipedia.org/wiki/Standardabweichung#Diskrete_Gleichverteilung.2C_W.C3.BCrfel -*/ -double -normalvariate(double mu, double sigma) -{ - static const double NV_MAGICCONST = 1.7155277699214135; /* STATIC_CONST: a constant */ - double z; - for (;;) { - double u1 = rng_double(); - double u2 = 1.0 - rng_double(); - z = NV_MAGICCONST*(u1-0.5)/u2; - if (z*z/4.0 <= -log(u2)) { - break; - } - } - return mu+z*sigma; -} - -int -ntimespprob(int n, double p, double mod) -{ - int count = 0; - int i; - - for(i=0; i0; i++) { - if(rng_double() < p) { - count++; - p += mod; - } - } - return count; -} - -boolean -chance(double x) -{ - if (x>=1.0) return true; - return rng_double() < x; -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "rand.h" +#include "rng.h" + +#include +#include +#include +#include +#include + +#define M_PIl 3.1415926535897932384626433832795029L /* pi */ + +/* NormalRand aus python, random.py geklaut, dort ist Referenz auf +* den Algorithmus. mu = Mittelwert, sigma = Standardabweichung. +* http://de.wikipedia.org/wiki/Standardabweichung#Diskrete_Gleichverteilung.2C_W.C3.BCrfel +*/ +double +normalvariate(double mu, double sigma) +{ + static const double NV_MAGICCONST = 1.7155277699214135; /* STATIC_CONST: a constant */ + double z; + for (;;) { + double u1 = rng_double(); + double u2 = 1.0 - rng_double(); + z = NV_MAGICCONST*(u1-0.5)/u2; + if (z*z/4.0 <= -log(u2)) { + break; + } + } + return mu+z*sigma; +} + +int +ntimespprob(int n, double p, double mod) +{ + int count = 0; + int i; + + for(i=0; i0; i++) { + if(rng_double() < p) { + count++; + p += mod; + } + } + return count; +} + +boolean +chance(double x) +{ + if (x>=1.0) return true; + return rng_double() < x; +} + diff --git a/src/util/rand.h b/src/util/rand.h index 2c9d6e96b..8e6999619 100644 --- a/src/util/rand.h +++ b/src/util/rand.h @@ -1,37 +1,37 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef RAND_H -#define RAND_H -#ifdef __cplusplus -extern "C" { -#endif - - /* in dice.c: */ - extern int dice_rand(const char *str); - extern int dice(int count, int value); - - /* in rand.c: */ - extern double normalvariate(double mu, double sigma); - extern int ntimespprob(int n, double p, double mod); - extern boolean chance(double x); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef RAND_H +#define RAND_H +#ifdef __cplusplus +extern "C" { +#endif + + /* in dice.c: */ + extern int dice_rand(const char *str); + extern int dice(int count, int value); + + /* in rand.c: */ + extern double normalvariate(double mu, double sigma); + extern int ntimespprob(int n, double p, double mod); + extern boolean chance(double x); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/resolve.c b/src/util/resolve.c index 224fbff52..0166da066 100644 --- a/src/util/resolve.c +++ b/src/util/resolve.c @@ -1,96 +1,96 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include -#include "resolve.h" -#include "storage.h" -#include "variant.h" - -typedef struct unresolved { - void * ptrptr; - /* address to pass to the resolve-function */ - variant data; - /* information on how to resolve the missing object */ - resolve_fun resolve; - /* function to resolve the unknown object */ -} unresolved; - -#define BLOCKSIZE 1024 -static unresolved * ur_list; -static unresolved * ur_begin; -static unresolved * ur_current; - -variant -read_int(struct storage * store) -{ - variant var; - var.i = store->r_int(store); - return var; -} - -int -read_reference(void * address, storage * store, read_fun reader, resolve_fun resolver) -{ - variant var = reader(store); - int result = resolver(var, address); - if (result!=0) { - ur_add(var, address, resolver); - } - return result; -} - -void -ur_add(variant data, void * ptrptr, resolve_fun fun) -{ - if (ur_list==NULL) { - ur_list = malloc(BLOCKSIZE*sizeof(unresolved)); - ur_begin = ur_current = ur_list; - } - else if (ur_current-ur_begin==BLOCKSIZE-1) { - ur_begin = malloc(BLOCKSIZE*sizeof(unresolved)); - ur_current->data.v = ur_begin; - ur_current = ur_begin; - } - ur_current->data = data; - ur_current->resolve = fun; - ur_current->ptrptr = ptrptr; - - ++ur_current; - ur_current->resolve = NULL; - ur_current->data.v = NULL; -} - -void -resolve(void) -{ - unresolved * ur = ur_list; - while (ur) { - if (ur->resolve==NULL) { - ur = ur->data.v; - free(ur_list); - ur_list = ur; - continue; - } - ur->resolve(ur->data, ur->ptrptr); - ++ur; - } - free(ur_list); - ur_list = NULL; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include +#include "resolve.h" +#include "storage.h" +#include "variant.h" + +typedef struct unresolved { + void * ptrptr; + /* address to pass to the resolve-function */ + variant data; + /* information on how to resolve the missing object */ + resolve_fun resolve; + /* function to resolve the unknown object */ +} unresolved; + +#define BLOCKSIZE 1024 +static unresolved * ur_list; +static unresolved * ur_begin; +static unresolved * ur_current; + +variant +read_int(struct storage * store) +{ + variant var; + var.i = store->r_int(store); + return var; +} + +int +read_reference(void * address, storage * store, read_fun reader, resolve_fun resolver) +{ + variant var = reader(store); + int result = resolver(var, address); + if (result!=0) { + ur_add(var, address, resolver); + } + return result; +} + +void +ur_add(variant data, void * ptrptr, resolve_fun fun) +{ + if (ur_list==NULL) { + ur_list = malloc(BLOCKSIZE*sizeof(unresolved)); + ur_begin = ur_current = ur_list; + } + else if (ur_current-ur_begin==BLOCKSIZE-1) { + ur_begin = malloc(BLOCKSIZE*sizeof(unresolved)); + ur_current->data.v = ur_begin; + ur_current = ur_begin; + } + ur_current->data = data; + ur_current->resolve = fun; + ur_current->ptrptr = ptrptr; + + ++ur_current; + ur_current->resolve = NULL; + ur_current->data.v = NULL; +} + +void +resolve(void) +{ + unresolved * ur = ur_list; + while (ur) { + if (ur->resolve==NULL) { + ur = ur->data.v; + free(ur_list); + ur_list = ur; + continue; + } + ur->resolve(ur->data, ur->ptrptr); + ++ur; + } + free(ur_list); + ur_list = NULL; +} diff --git a/src/util/resolve.h b/src/util/resolve.h index c6deb4f77..f52345e68 100644 --- a/src/util/resolve.h +++ b/src/util/resolve.h @@ -1,41 +1,41 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef RESOLVE_H -#define RESOLVE_H - -#include "variant.h" -struct storage; - -#ifdef __cplusplus -extern "C" { -#endif - - typedef int (*resolve_fun)(variant data, void * address); - typedef variant (*read_fun)(struct storage* store); - extern int read_reference(void * address, struct storage * store, read_fun reader, resolve_fun resolver); - - extern void ur_add(variant data, void * address, resolve_fun fun); - extern void resolve(void); - - extern variant read_int(struct storage * store); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef RESOLVE_H +#define RESOLVE_H + +#include "variant.h" +struct storage; + +#ifdef __cplusplus +extern "C" { +#endif + + typedef int (*resolve_fun)(variant data, void * address); + typedef variant (*read_fun)(struct storage* store); + extern int read_reference(void * address, struct storage * store, read_fun reader, resolve_fun resolver); + + extern void ur_add(variant data, void * address, resolve_fun fun); + extern void resolve(void); + + extern variant read_int(struct storage * store); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/rng.h b/src/util/rng.h index 3ef39d49e..5092a32d4 100644 --- a/src/util/rng.h +++ b/src/util/rng.h @@ -1,45 +1,45 @@ -/* vi: set ts=2: - * +-------------------+ Christian Schlittchen - * | | Enno Rehling - * | Eressea PBEM host | Katja Zedel - * | (c) 1998 - 2005 | - * | | This program may not be used, modified or distributed - * +-------------------+ without prior permission by the authors of Eressea. - * - */ -#ifndef UTIL_RNG_H -#define UTIL_RNG_H -#ifdef __cplusplus -extern "C" { -#endif - -#define RNG_MT - -#ifdef RNG_MT - /* initializes mt[N] with a seed */ - extern void init_genrand(unsigned long s); - - /* generates a random number on [0,0xffffffff]-interval */ - extern unsigned long genrand_int32(void); - - /* generates a random number on [0,1)-real-interval */ - extern double genrand_real2(void); - - /* generates a random number on [0,0x7fffffff]-interval */ - long genrand_int31(void); - -# define rng_init(seed) init_genrand(seed) -# define rng_int genrand_int31 -# define rng_double genrand_real2 -# define RNG_RAND_MAX 0x7fffffff -#else -# include -# define rng_init(seed) srand(seed) -# define rng_int rand() -# define rng_double ((rand()%RAND_MAX)/(double)RAND_MAX) -# define RNG_RAND_MAX RAND_MAX -#endif -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2005 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ +#ifndef UTIL_RNG_H +#define UTIL_RNG_H +#ifdef __cplusplus +extern "C" { +#endif + +#define RNG_MT + +#ifdef RNG_MT + /* initializes mt[N] with a seed */ + extern void init_genrand(unsigned long s); + + /* generates a random number on [0,0xffffffff]-interval */ + extern unsigned long genrand_int32(void); + + /* generates a random number on [0,1)-real-interval */ + extern double genrand_real2(void); + + /* generates a random number on [0,0x7fffffff]-interval */ + long genrand_int31(void); + +# define rng_init(seed) init_genrand(seed) +# define rng_int genrand_int31 +# define rng_double genrand_real2 +# define RNG_RAND_MAX 0x7fffffff +#else +# include +# define rng_init(seed) srand(seed) +# define rng_int rand() +# define rng_double ((rand()%RAND_MAX)/(double)RAND_MAX) +# define RNG_RAND_MAX RAND_MAX +#endif +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/sql.c b/src/util/sql.c index 9f653e8af..42018f50b 100644 --- a/src/util/sql.c +++ b/src/util/sql.c @@ -1,82 +1,82 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "sql.h" - -#include "log.h" - -#include -#include -#include - -static FILE * sqlstream = NULL; -static char * sqlfilename = NULL; - -void -sql_init(const char * filename) -{ - if (sqlfilename!=NULL) free(sqlfilename); - sqlfilename = strdup(filename); -} - -void -_sql_print(const char * format, ...) -{ - if (!sqlstream && sqlfilename) { - sqlstream=fopen(sqlfilename, "wt+"); - free(sqlfilename); - sqlfilename=NULL; - } - if (sqlstream!=NULL) { - va_list marker; - va_start(marker, format); - vfprintf(sqlstream, format, marker); - va_end(marker); - } -} - -void -sql_done(void) -{ - if (sqlstream) fclose(sqlstream); - if (sqlfilename) free(sqlfilename); - sqlstream=NULL; - sqlfilename=NULL; -} - -const char * -sqlquote(const char * str) -{ -#define BUFFERS 4 -#define BUFSIZE 1024 - static char sqlstring[BUFSIZE*BUFFERS]; /* STATIC_RESULT: used for return, not across calls */ - static int index = 0; /* STATIC_XCALL: used across calls */ - char * start = sqlstring+index*BUFSIZE; - char * o = start; - const char * i = str; - while (*i && o-start < BUFSIZE-1) { - if (*i!='\'' && *i!='\"') { - *o++ = *i++; - } else ++i; - } - *o = '\0'; - index = (index+1) % BUFFERS; - return start; -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "sql.h" + +#include "log.h" + +#include +#include +#include + +static FILE * sqlstream = NULL; +static char * sqlfilename = NULL; + +void +sql_init(const char * filename) +{ + if (sqlfilename!=NULL) free(sqlfilename); + sqlfilename = strdup(filename); +} + +void +_sql_print(const char * format, ...) +{ + if (!sqlstream && sqlfilename) { + sqlstream=fopen(sqlfilename, "wt+"); + free(sqlfilename); + sqlfilename=NULL; + } + if (sqlstream!=NULL) { + va_list marker; + va_start(marker, format); + vfprintf(sqlstream, format, marker); + va_end(marker); + } +} + +void +sql_done(void) +{ + if (sqlstream) fclose(sqlstream); + if (sqlfilename) free(sqlfilename); + sqlstream=NULL; + sqlfilename=NULL; +} + +const char * +sqlquote(const char * str) +{ +#define BUFFERS 4 +#define BUFSIZE 1024 + static char sqlstring[BUFSIZE*BUFFERS]; /* STATIC_RESULT: used for return, not across calls */ + static int index = 0; /* STATIC_XCALL: used across calls */ + char * start = sqlstring+index*BUFSIZE; + char * o = start; + const char * i = str; + while (*i && o-start < BUFSIZE-1) { + if (*i!='\'' && *i!='\"') { + *o++ = *i++; + } else ++i; + } + *o = '\0'; + index = (index+1) % BUFFERS; + return start; +} + diff --git a/src/util/sql.h b/src/util/sql.h index b16fa7930..d0e9f813a 100644 --- a/src/util/sql.h +++ b/src/util/sql.h @@ -1,35 +1,35 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_UTIL_SQL -#define H_UTIL_SQL -#ifdef __cplusplus -extern "C" { -#endif - - extern void sql_init(const char * filename); - extern void sql_done(void); - extern const char * sqlquote(const char * str); - extern void _sql_print(const char * format, ...); - -#define sql_print(x) _sql_print x - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_UTIL_SQL +#define H_UTIL_SQL +#ifdef __cplusplus +extern "C" { +#endif + + extern void sql_init(const char * filename); + extern void sql_done(void); + extern const char * sqlquote(const char * str); + extern void _sql_print(const char * format, ...); + +#define sql_print(x) _sql_print x + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/storage.h b/src/util/storage.h index 96b62216b..678d377e8 100644 --- a/src/util/storage.h +++ b/src/util/storage.h @@ -1,48 +1,48 @@ -#ifndef STORAGE_H -#define STORAGE_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct storage { - /* separator for readable files: */ - int (*w_brk)(struct storage *); - /* integer values: */ - int (*w_int)(struct storage *, int arg); - int (*r_int)(struct storage *); - /* float values: */ - int (*w_flt)(struct storage *, float arg); - float (*r_flt)(struct storage *); - /* id values: */ - int (*w_id)(struct storage *, int arg); - int (*r_id)(struct storage *); - /* tokens that contain no whitespace: */ - int (*w_tok)(struct storage *, const char * tok); - char *(*r_tok)(struct storage *); - void (*r_tok_buf)(struct storage *, char * result, size_t size); - /* strings that need to be quoted: */ - int (*w_str)(struct storage *, const char * tok); - char * (*r_str)(struct storage *); - void (*r_str_buf)(struct storage *, char * result, size_t size); - /* binary data: */ - int (*w_bin)(struct storage *, void * arg, size_t size); - void (*r_bin)(struct storage *, void * result, size_t size); - - int (*open)(struct storage *, const char * filename, int mode); - int (*close)(struct storage *); - - int encoding; - int version; - void * userdata; -} storage; - -#define IO_READ 0x01 -#define IO_WRITE 0x02 -#define IO_BINARY 0x04 -#define IO_TEXT 0x08 -#define IO_DEFAULT IO_BINARY - -#ifdef __cplusplus -} -#endif -#endif +#ifndef STORAGE_H +#define STORAGE_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct storage { + /* separator for readable files: */ + int (*w_brk)(struct storage *); + /* integer values: */ + int (*w_int)(struct storage *, int arg); + int (*r_int)(struct storage *); + /* float values: */ + int (*w_flt)(struct storage *, float arg); + float (*r_flt)(struct storage *); + /* id values: */ + int (*w_id)(struct storage *, int arg); + int (*r_id)(struct storage *); + /* tokens that contain no whitespace: */ + int (*w_tok)(struct storage *, const char * tok); + char *(*r_tok)(struct storage *); + void (*r_tok_buf)(struct storage *, char * result, size_t size); + /* strings that need to be quoted: */ + int (*w_str)(struct storage *, const char * tok); + char * (*r_str)(struct storage *); + void (*r_str_buf)(struct storage *, char * result, size_t size); + /* binary data: */ + int (*w_bin)(struct storage *, void * arg, size_t size); + void (*r_bin)(struct storage *, void * result, size_t size); + + int (*open)(struct storage *, const char * filename, int mode); + int (*close)(struct storage *); + + int encoding; + int version; + void * userdata; +} storage; + +#define IO_READ 0x01 +#define IO_WRITE 0x02 +#define IO_BINARY 0x04 +#define IO_TEXT 0x08 +#define IO_DEFAULT IO_BINARY + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/strings.c b/src/util/strings.c index 390bc5462..fca7308e9 100644 --- a/src/util/strings.c +++ b/src/util/strings.c @@ -1,132 +1,132 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include - -/* libc includes */ -#include - -INLINE_FUNCTION unsigned int -hashstring(const char* s) -{ - unsigned int key = 0; - while (*s) { - key = key*37 + *s++; - } - return key & 0x7FFFFFFF; -} - -/* -static const char * -escape_string_inplace(char * buffer, unsigned int len, unsigned int offset) -{ -#define MAXQUOTES 32 - char * o; - char * d[MAXQUOTES+1]; - int i = 0; - - o = strchr(buffer, '"'); - if (!o) { - return buffer; - } - - while (*o && i0) { - const char * src = d[i]; - char * dst = d[i] + i + offset; - size_t mlen = d[i+1] - d[i]; - memmove(dst--, src, mlen); - *dst = '\\'; - } - return buffer; -} -*/ - -INLINE_FUNCTION const char * -escape_string(const char * str, char * buffer, unsigned int len) -{ - const char * start = strchr(str, '\"'); - if (start) { - static char s_buffer[4096]; /* STATIC_RESULT: used for return, not across calls */ - const char * p; - char * o; - size_t skip = start-str; - - if (buffer==NULL) { - buffer = s_buffer; - len = sizeof(s_buffer); - } - memcpy(buffer, str, skip); - o = buffer + skip; - p = str + skip; - do { - if (*p == '\"' || *p=='\\') { - if (len<2) { - *o = '\0'; - break; - } - (*o++) = '\\'; - len -= 2; - } else { - if (len<1) { - *o = '\0'; - break; - } - --len; - } - (*o++) = (*p); - } while (*p++); - return buffer; - } - return str; -} - -INLINE_FUNCTION unsigned int jenkins_hash(unsigned int a) -{ - a = (a+0x7ed55d16) + (a<<12); - a = (a^0xc761c23c) ^ (a>>19); - a = (a+0x165667b1) + (a<<5); - a = (a+0xd3a2646c) ^ (a<<9); - a = (a+0xfd7046c5) + (a<<3); - a = (a^0xb55a4f09) ^ (a>>16); - return a; -} - -INLINE_FUNCTION unsigned int wang_hash(unsigned int a) -{ - a = ~a + (a << 15); // a = (a << 15) - a - 1; - a = a ^ (a >> 12); - a = a + (a << 2); - a = a ^ (a >> 4); - a = a * 2057; // a = (a + (a << 3)) + (a << 11); - a = a ^ (a >> 16); - return a; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include + +/* libc includes */ +#include + +INLINE_FUNCTION unsigned int +hashstring(const char* s) +{ + unsigned int key = 0; + while (*s) { + key = key*37 + *s++; + } + return key & 0x7FFFFFFF; +} + +/* +static const char * +escape_string_inplace(char * buffer, unsigned int len, unsigned int offset) +{ +#define MAXQUOTES 32 + char * o; + char * d[MAXQUOTES+1]; + int i = 0; + + o = strchr(buffer, '"'); + if (!o) { + return buffer; + } + + while (*o && i0) { + const char * src = d[i]; + char * dst = d[i] + i + offset; + size_t mlen = d[i+1] - d[i]; + memmove(dst--, src, mlen); + *dst = '\\'; + } + return buffer; +} +*/ + +INLINE_FUNCTION const char * +escape_string(const char * str, char * buffer, unsigned int len) +{ + const char * start = strchr(str, '\"'); + if (start) { + static char s_buffer[4096]; /* STATIC_RESULT: used for return, not across calls */ + const char * p; + char * o; + size_t skip = start-str; + + if (buffer==NULL) { + buffer = s_buffer; + len = sizeof(s_buffer); + } + memcpy(buffer, str, skip); + o = buffer + skip; + p = str + skip; + do { + if (*p == '\"' || *p=='\\') { + if (len<2) { + *o = '\0'; + break; + } + (*o++) = '\\'; + len -= 2; + } else { + if (len<1) { + *o = '\0'; + break; + } + --len; + } + (*o++) = (*p); + } while (*p++); + return buffer; + } + return str; +} + +INLINE_FUNCTION unsigned int jenkins_hash(unsigned int a) +{ + a = (a+0x7ed55d16) + (a<<12); + a = (a^0xc761c23c) ^ (a>>19); + a = (a+0x165667b1) + (a<<5); + a = (a+0xd3a2646c) ^ (a<<9); + a = (a+0xfd7046c5) + (a<<3); + a = (a^0xb55a4f09) ^ (a>>16); + return a; +} + +INLINE_FUNCTION unsigned int wang_hash(unsigned int a) +{ + a = ~a + (a << 15); // a = (a << 15) - a - 1; + a = a ^ (a >> 12); + a = a + (a << 2); + a = a ^ (a >> 4); + a = a * 2057; // a = (a + (a << 3)) + (a << 11); + a = a ^ (a >> 16); + return a; +} diff --git a/src/util/strncpy.c b/src/util/strncpy.c index 8da32d488..4c8d22099 100644 --- a/src/util/strncpy.c +++ b/src/util/strncpy.c @@ -1,22 +1,22 @@ - -/* - * Faster replacement for ISO-C strncpy, does not pad with zeros - */ - -#include - -char * -strncpy(char *to, const char *from, size_t size) -{ - char *t = to, *f = (char *)from; - int copied = 0; - - while(copied < size) { - *t = *f; - if(*f == '\0') break; - t++; f++; copied++; - } - - return to; -} - + +/* + * Faster replacement for ISO-C strncpy, does not pad with zeros + */ + +#include + +char * +strncpy(char *to, const char *from, size_t size) +{ + char *t = to, *f = (char *)from; + int copied = 0; + + while(copied < size) { + *t = *f; + if(*f == '\0') break; + t++; f++; copied++; + } + + return to; +} + diff --git a/src/util/translation.c b/src/util/translation.c index b92246a19..7385893fb 100644 --- a/src/util/translation.c +++ b/src/util/translation.c @@ -1,488 +1,488 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ -#include - -#include "translation.h" -#include "log.h" -#include "bsdstring.h" - -/* libc includes */ -#include -#include -#include -#include -#include - -/** - ** simple operand stack - **/ - -typedef struct opstack { - variant * begin; - variant * top; - int size; -} opstack; - -variant -opstack_pop(opstack ** stackp) -{ - opstack * stack = *stackp; - - assert(stack); - assert(stack->top>stack->begin); - return *(--stack->top); -} - -void -opstack_push(opstack ** stackp, variant data) -{ - opstack * stack = *stackp; - if (stack==NULL) { - stack = (opstack*)malloc(sizeof(opstack)); - stack->size = 1; - stack->begin = malloc(sizeof(variant) * stack->size); - stack->top = stack->begin; - *stackp = stack; - } - if (stack->top - stack->begin == stack->size) { - size_t pos = stack->top - stack->begin; - stack->size += stack->size; - stack->begin = realloc(stack->begin, sizeof(variant) * stack->size); - stack->top = stack->begin + pos; - } - *stack->top++ = data; -} - -/** - ** static buffer malloc - **/ - -#define BBUFSIZE 128*1024 -static struct { - char * begin; - char * end; - char * last; - char * current; -} buffer; - -char * -balloc(size_t size) -{ - static int init = 0; /* STATIC_XCALL: used across calls */ - if (!init) { - init = 1; - buffer.current = buffer.begin = malloc(BBUFSIZE); - buffer.end = buffer.begin + BBUFSIZE; - } - if (buffer.current + size > buffer.end) { - /* out of memory! */ - return NULL; - } - buffer.last = buffer.current; - buffer.current +=size; - return buffer.last; -} - -void -bfree(char * c) -/* only release this memory if it was part of the last allocation - * that's a joke, but who cares. - */ -{ - if (c>=buffer.last && cvalue = value; - var->symbol = symbol; - - var->next = variables; - variables = var; -} - -static variable * -find_variable(const char * symbol) -{ - variable * var = variables; - while (var) { - if (!strcmp(var->symbol, symbol)) break; - var = var->next; - } - return var; -} - -/** - ** constant values - **/ - -typedef struct function { - struct function * next; - const char * symbol; - evalfun parse; -} function; - -static function * functions; - -static void -free_functions(void) -{ - while (functions) { - function * fun = functions; - functions = fun->next; - free(fun); - } -} - -void -add_function(const char * symbol, evalfun parse) -{ - function * fun = (function*)malloc(sizeof(function)); - - fun->parse = parse; - fun->symbol = symbol; - - fun->next = functions; - functions = fun; -} - -static function * -find_function(const char * symbol) -{ - function * fun = functions; - while (fun) { - if (!strcmp(fun->symbol, symbol)) break; - fun = fun->next; - } - return fun; -} - -static const char * parse(opstack **, const char* in, const void *); -/* static const char * sample = "\"enno and $bool($if($eq($i,0),\"noone else\",\"$i other people\"))\""; */ - -static const char * -parse_symbol(opstack ** stack, const char* in, const void * userdata) -/* in is the symbol name and following text, starting after the $ - * result goes on the stack - */ -{ - boolean braces = false; - char symbol[32]; - char *cp = symbol; /* current position */ - - if (*in=='{') { - braces = true; - ++in; - } - while (isalnum(*in) || *in=='.') *cp++ = *in++; - *cp = '\0'; - /* symbol will now contain the symbol name */ - if (*in=='(') { - /* it's a function we need to parse, start by reading the parameters */ - function * foo; - while (*in != ')') { - in = parse(stack, ++in, userdata); /* will push the result on the stack */ - if (in==NULL) return NULL; - } - ++in; - foo = find_function(symbol); - if (foo==NULL) { - log_error(("parser does not know about \"%s\" function.\n", symbol)); - return NULL; - } - foo->parse(stack, userdata); /* will pop parameters from stack (reverse order!) and push the result */ - } else { - variable * var = find_variable(symbol); - if (braces && *in=='}') { - ++in; - } - /* it's a constant (variable is a misnomer, but heck, const was taken;)) */ - if (var==NULL) { - log_error(("parser does not know about \"%s\" variable.\n", symbol)); - return NULL; - } - opush(stack, var->value); - } - return in; -} - -#define TOKENSIZE 4096 -static const char * -parse_string(opstack ** stack, const char* in, const void * userdata) /* (char*) -> char* */ -{ - char * c; - char * buffer = balloc(TOKENSIZE); - size_t size = TOKENSIZE - 1; - const char * ic = in; - char * oc = buffer; - /* mode flags */ - boolean f_escape = false; - boolean bDone = false; - variant var; - - while (*ic && !bDone) { - if (f_escape) { - f_escape = false; - switch (*ic) { - case 'n': - if (size>0) { *oc++='\n'; --size; } - break; - case 't': - if (size>0) { *oc++='\t'; --size; } - break; - default: - if (size>0) { *oc++=*ic++; --size; } - } - } else { - int ch = (unsigned char)(*ic); - int bytes; - - switch (ch) { - case '\\': - f_escape = true; - ++ic; - break; - case '"': - bDone = true; - ++ic; - break; - case '$': - ic = parse_symbol(stack, ++ic, userdata); - if (ic==NULL) return NULL; - c = (char*)opop_v(stack); - bytes = (int)strlcpy(oc, c, size); - if (bytes<(int)size) oc += bytes; - else oc += size; - bfree(c); - break; - default: - if (size>0) { *oc++=*ic++; --size; } - else ++ic; - } - } - } - *oc++ = '\0'; - bfree(oc); - var.v = buffer; - opush(stack, var); - return ic; -} - -static const char * -parse_int(opstack ** stack, const char * in) -{ - int k = 0; - int vz = 1; - boolean ok = false; - variant var; - do { - switch (*in) { - case '+': - ++in; - break; - case '-': - ++in; - vz=vz*-1; - break; - default: - ok = true; - } - } while (!ok); - while (isdigit(*(unsigned char*)in)) { - k = k * 10 + (*in++)-'0'; - } - var.i = k*vz; - opush(stack, var); - return in; -} - - -static const char * -parse(opstack ** stack, const char* inn, const void * userdata) -{ - const char * b = inn; - while (*b) { - switch (*b) { - case '"': - return parse_string(stack, ++b, userdata); - break; - case '$': - return parse_symbol(stack, ++b, userdata); - break; - default: - if (isdigit(*(unsigned char*)b) || *b=='-' || *b=='+') { - return parse_int(stack, b); - } - else ++b; - } - } - log_error(("could not parse \"%s\". Probably invalid message syntax.", inn)); - return NULL; -} - -const char * -translate(const char* format, const void * userdata, const char* vars, variant args[]) -{ - int i = 0; - const char *ic = vars; - char symbol[32]; - char *oc = symbol; - opstack * stack = NULL; - const char * rv; - - brelease(); - free_variables(); - - assert(format); - assert(*ic == 0 || isalnum(*ic)); - while (*ic) { - *oc++ = *ic++; - if (!isalnum(*ic)) { - variant x = args[i++]; - *oc = '\0'; - oc = symbol; - add_variable(strcpy(balloc(strlen(symbol)+1), symbol), x); - while (*ic && !isalnum(*ic)) ++ic; - } - } - - if (format[0]=='"') { - rv = parse(&stack, format, userdata); - } - else { - rv = parse_string(&stack, format, userdata); - } - if (rv!=NULL) { - if (rv[0]) { - log_error(("residual data after parsing: %s\n", rv)); - } - rv = (const char*)opop(&stack).v; - free(stack->begin); - free(stack); - } - return rv; -} - -static void -eval_lt(opstack ** stack, const void * userdata) /* (int, int) -> int */ -{ - int a = opop_i(stack); - int b = opop_i(stack); - int rval = (b int */ -{ - int a = opop_i(stack); - int b = opop_i(stack); - int rval = (a==b)?1:0; - opush_i(stack, rval); - unused(userdata); -} - -static void -eval_add(opstack ** stack, const void * userdata) /* (int, int) -> int */ -{ - int a = opop_i(stack); - int b = opop_i(stack); - opush_i(stack, a+b); - unused(userdata); -} - -static void -eval_isnull(opstack ** stack, const void * userdata) /* (int, int) -> int */ -{ - void * a = opop_v(stack); - opush_i(stack, (a==NULL)?1:0); - unused(userdata); -} - -static void -eval_if(opstack ** stack, const void * userdata) /* (int, int) -> int */ -{ - void * a = opop_v(stack); - void * b = opop_v(stack); - int cond = opop_i(stack); - opush_v(stack, cond?b:a); - unused(userdata); -} - -static void -eval_strlen(opstack ** stack, const void * userdata) /* string -> int */ -{ - const char * c = (const char *)opop_v(stack); - opush_i(stack, c?(int)strlen(c):0); - unused(userdata); -} - -#include "base36.h" -static void -eval_int(opstack ** stack, const void * userdata) -{ - int i = opop_i(stack); - const char * c = itoa10(i); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -void -translation_init(void) -{ - add_function("lt", &eval_lt); - add_function("eq", &eval_eq); - add_function("int", &eval_int); - add_function("add", &eval_add); - add_function("strlen", &eval_strlen); - add_function("if", &eval_if); - add_function("isnull", &eval_isnull); -} - -void -translation_done(void) -{ - free_functions(); - free(buffer.begin); -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#include + +#include "translation.h" +#include "log.h" +#include "bsdstring.h" + +/* libc includes */ +#include +#include +#include +#include +#include + +/** + ** simple operand stack + **/ + +typedef struct opstack { + variant * begin; + variant * top; + int size; +} opstack; + +variant +opstack_pop(opstack ** stackp) +{ + opstack * stack = *stackp; + + assert(stack); + assert(stack->top>stack->begin); + return *(--stack->top); +} + +void +opstack_push(opstack ** stackp, variant data) +{ + opstack * stack = *stackp; + if (stack==NULL) { + stack = (opstack*)malloc(sizeof(opstack)); + stack->size = 1; + stack->begin = malloc(sizeof(variant) * stack->size); + stack->top = stack->begin; + *stackp = stack; + } + if (stack->top - stack->begin == stack->size) { + size_t pos = stack->top - stack->begin; + stack->size += stack->size; + stack->begin = realloc(stack->begin, sizeof(variant) * stack->size); + stack->top = stack->begin + pos; + } + *stack->top++ = data; +} + +/** + ** static buffer malloc + **/ + +#define BBUFSIZE 128*1024 +static struct { + char * begin; + char * end; + char * last; + char * current; +} buffer; + +char * +balloc(size_t size) +{ + static int init = 0; /* STATIC_XCALL: used across calls */ + if (!init) { + init = 1; + buffer.current = buffer.begin = malloc(BBUFSIZE); + buffer.end = buffer.begin + BBUFSIZE; + } + if (buffer.current + size > buffer.end) { + /* out of memory! */ + return NULL; + } + buffer.last = buffer.current; + buffer.current +=size; + return buffer.last; +} + +void +bfree(char * c) +/* only release this memory if it was part of the last allocation + * that's a joke, but who cares. + */ +{ + if (c>=buffer.last && cvalue = value; + var->symbol = symbol; + + var->next = variables; + variables = var; +} + +static variable * +find_variable(const char * symbol) +{ + variable * var = variables; + while (var) { + if (!strcmp(var->symbol, symbol)) break; + var = var->next; + } + return var; +} + +/** + ** constant values + **/ + +typedef struct function { + struct function * next; + const char * symbol; + evalfun parse; +} function; + +static function * functions; + +static void +free_functions(void) +{ + while (functions) { + function * fun = functions; + functions = fun->next; + free(fun); + } +} + +void +add_function(const char * symbol, evalfun parse) +{ + function * fun = (function*)malloc(sizeof(function)); + + fun->parse = parse; + fun->symbol = symbol; + + fun->next = functions; + functions = fun; +} + +static function * +find_function(const char * symbol) +{ + function * fun = functions; + while (fun) { + if (!strcmp(fun->symbol, symbol)) break; + fun = fun->next; + } + return fun; +} + +static const char * parse(opstack **, const char* in, const void *); +/* static const char * sample = "\"enno and $bool($if($eq($i,0),\"noone else\",\"$i other people\"))\""; */ + +static const char * +parse_symbol(opstack ** stack, const char* in, const void * userdata) +/* in is the symbol name and following text, starting after the $ + * result goes on the stack + */ +{ + boolean braces = false; + char symbol[32]; + char *cp = symbol; /* current position */ + + if (*in=='{') { + braces = true; + ++in; + } + while (isalnum(*in) || *in=='.') *cp++ = *in++; + *cp = '\0'; + /* symbol will now contain the symbol name */ + if (*in=='(') { + /* it's a function we need to parse, start by reading the parameters */ + function * foo; + while (*in != ')') { + in = parse(stack, ++in, userdata); /* will push the result on the stack */ + if (in==NULL) return NULL; + } + ++in; + foo = find_function(symbol); + if (foo==NULL) { + log_error(("parser does not know about \"%s\" function.\n", symbol)); + return NULL; + } + foo->parse(stack, userdata); /* will pop parameters from stack (reverse order!) and push the result */ + } else { + variable * var = find_variable(symbol); + if (braces && *in=='}') { + ++in; + } + /* it's a constant (variable is a misnomer, but heck, const was taken;)) */ + if (var==NULL) { + log_error(("parser does not know about \"%s\" variable.\n", symbol)); + return NULL; + } + opush(stack, var->value); + } + return in; +} + +#define TOKENSIZE 4096 +static const char * +parse_string(opstack ** stack, const char* in, const void * userdata) /* (char*) -> char* */ +{ + char * c; + char * buffer = balloc(TOKENSIZE); + size_t size = TOKENSIZE - 1; + const char * ic = in; + char * oc = buffer; + /* mode flags */ + boolean f_escape = false; + boolean bDone = false; + variant var; + + while (*ic && !bDone) { + if (f_escape) { + f_escape = false; + switch (*ic) { + case 'n': + if (size>0) { *oc++='\n'; --size; } + break; + case 't': + if (size>0) { *oc++='\t'; --size; } + break; + default: + if (size>0) { *oc++=*ic++; --size; } + } + } else { + int ch = (unsigned char)(*ic); + int bytes; + + switch (ch) { + case '\\': + f_escape = true; + ++ic; + break; + case '"': + bDone = true; + ++ic; + break; + case '$': + ic = parse_symbol(stack, ++ic, userdata); + if (ic==NULL) return NULL; + c = (char*)opop_v(stack); + bytes = (int)strlcpy(oc, c, size); + if (bytes<(int)size) oc += bytes; + else oc += size; + bfree(c); + break; + default: + if (size>0) { *oc++=*ic++; --size; } + else ++ic; + } + } + } + *oc++ = '\0'; + bfree(oc); + var.v = buffer; + opush(stack, var); + return ic; +} + +static const char * +parse_int(opstack ** stack, const char * in) +{ + int k = 0; + int vz = 1; + boolean ok = false; + variant var; + do { + switch (*in) { + case '+': + ++in; + break; + case '-': + ++in; + vz=vz*-1; + break; + default: + ok = true; + } + } while (!ok); + while (isdigit(*(unsigned char*)in)) { + k = k * 10 + (*in++)-'0'; + } + var.i = k*vz; + opush(stack, var); + return in; +} + + +static const char * +parse(opstack ** stack, const char* inn, const void * userdata) +{ + const char * b = inn; + while (*b) { + switch (*b) { + case '"': + return parse_string(stack, ++b, userdata); + break; + case '$': + return parse_symbol(stack, ++b, userdata); + break; + default: + if (isdigit(*(unsigned char*)b) || *b=='-' || *b=='+') { + return parse_int(stack, b); + } + else ++b; + } + } + log_error(("could not parse \"%s\". Probably invalid message syntax.", inn)); + return NULL; +} + +const char * +translate(const char* format, const void * userdata, const char* vars, variant args[]) +{ + int i = 0; + const char *ic = vars; + char symbol[32]; + char *oc = symbol; + opstack * stack = NULL; + const char * rv; + + brelease(); + free_variables(); + + assert(format); + assert(*ic == 0 || isalnum(*ic)); + while (*ic) { + *oc++ = *ic++; + if (!isalnum(*ic)) { + variant x = args[i++]; + *oc = '\0'; + oc = symbol; + add_variable(strcpy(balloc(strlen(symbol)+1), symbol), x); + while (*ic && !isalnum(*ic)) ++ic; + } + } + + if (format[0]=='"') { + rv = parse(&stack, format, userdata); + } + else { + rv = parse_string(&stack, format, userdata); + } + if (rv!=NULL) { + if (rv[0]) { + log_error(("residual data after parsing: %s\n", rv)); + } + rv = (const char*)opop(&stack).v; + free(stack->begin); + free(stack); + } + return rv; +} + +static void +eval_lt(opstack ** stack, const void * userdata) /* (int, int) -> int */ +{ + int a = opop_i(stack); + int b = opop_i(stack); + int rval = (b int */ +{ + int a = opop_i(stack); + int b = opop_i(stack); + int rval = (a==b)?1:0; + opush_i(stack, rval); + unused(userdata); +} + +static void +eval_add(opstack ** stack, const void * userdata) /* (int, int) -> int */ +{ + int a = opop_i(stack); + int b = opop_i(stack); + opush_i(stack, a+b); + unused(userdata); +} + +static void +eval_isnull(opstack ** stack, const void * userdata) /* (int, int) -> int */ +{ + void * a = opop_v(stack); + opush_i(stack, (a==NULL)?1:0); + unused(userdata); +} + +static void +eval_if(opstack ** stack, const void * userdata) /* (int, int) -> int */ +{ + void * a = opop_v(stack); + void * b = opop_v(stack); + int cond = opop_i(stack); + opush_v(stack, cond?b:a); + unused(userdata); +} + +static void +eval_strlen(opstack ** stack, const void * userdata) /* string -> int */ +{ + const char * c = (const char *)opop_v(stack); + opush_i(stack, c?(int)strlen(c):0); + unused(userdata); +} + +#include "base36.h" +static void +eval_int(opstack ** stack, const void * userdata) +{ + int i = opop_i(stack); + const char * c = itoa10(i); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +void +translation_init(void) +{ + add_function("lt", &eval_lt); + add_function("eq", &eval_eq); + add_function("int", &eval_int); + add_function("add", &eval_add); + add_function("strlen", &eval_strlen); + add_function("if", &eval_if); + add_function("isnull", &eval_isnull); +} + +void +translation_done(void) +{ + free_functions(); + free(buffer.begin); +} diff --git a/src/util/translation.h b/src/util/translation.h index 6aa6dd28d..572d5b7b7 100644 --- a/src/util/translation.h +++ b/src/util/translation.h @@ -1,45 +1,45 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_UTIL_TRANSLATION -#define H_UTIL_TRANSLATION -#ifdef __cplusplus -extern "C" { -#endif - -#include "variant.h" -struct opstack; -extern void opstack_push(struct opstack ** stack, variant data); -#define opush_i(stack, x) { variant localvar; localvar.i = x; opstack_push(stack, localvar); } -#define opush_v(stack, x) { variant localvar; localvar.v = x; opstack_push(stack, localvar); } -#define opush(stack, i) opstack_push(stack, i) - -extern variant opstack_pop(struct opstack ** stack); -#define opop_v(stack) opstack_pop(stack).v -#define opop_i(stack) opstack_pop(stack).i -#define opop(stack) opstack_pop(stack) - -extern void translation_init(void); -extern void translation_done(void); -extern const char * translate(const char* format, const void * userdata, const char* vars, variant args[]); - -/* eval_x functions */ -typedef void (*evalfun)(struct opstack ** stack, const void *); -extern void add_function(const char * symbol, evalfun parse); - -/* transient memory blocks */ -extern char * balloc(size_t size); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_UTIL_TRANSLATION +#define H_UTIL_TRANSLATION +#ifdef __cplusplus +extern "C" { +#endif + +#include "variant.h" +struct opstack; +extern void opstack_push(struct opstack ** stack, variant data); +#define opush_i(stack, x) { variant localvar; localvar.i = x; opstack_push(stack, localvar); } +#define opush_v(stack, x) { variant localvar; localvar.v = x; opstack_push(stack, localvar); } +#define opush(stack, i) opstack_push(stack, i) + +extern variant opstack_pop(struct opstack ** stack); +#define opop_v(stack) opstack_pop(stack).v +#define opop_i(stack) opstack_pop(stack).i +#define opop(stack) opstack_pop(stack) + +extern void translation_init(void); +extern void translation_done(void); +extern const char * translate(const char* format, const void * userdata, const char* vars, variant args[]); + +/* eval_x functions */ +typedef void (*evalfun)(struct opstack ** stack, const void *); +extern void add_function(const char * symbol, evalfun parse); + +/* transient memory blocks */ +extern char * balloc(size_t size); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/umlaut.c b/src/util/umlaut.c index 67bd03964..a29b16635 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -1,160 +1,160 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "umlaut.h" - -#include "log.h" -#include "unicode.h" - -#include -#include -#include -#include - -typedef struct tref { - struct tref * nexthash; - ucs4_t ucs; - struct tnode * node; -} tref; - -#define LEAF 1 /* leaf node for a word. always matches */ -#define SHARED 2 /* at least two words share the node */ - -void -addtoken(tnode * root, const char * str, variant id) -{ - static const struct replace { /* STATIC_CONST: constant value */ - ucs4_t ucs; - const char str[3]; - } replace[] = { - /* match lower-case (!) umlauts and others to transcriptions */ - { 228, "AE"}, /* auml */ - { 246, "OE"}, /* ouml */ - { 252, "UE"}, /* uuml */ - { 223, "SS"}, /* szlig */ - { 230, "AE"}, /* norsk */ - { 248, "OE"}, /* norsk */ - { 229, "AA"}, /* norsk */ - { 0, "" } - }; - - if (!*str) { - root->id = id; - root->flags |= LEAF; - } else { - tref * next; - int ret, index, i = 0; - ucs4_t ucs, lcs; - size_t len; - - ret = unicode_utf8_to_ucs4(&ucs, str, &len); - assert(ret==0 || !"invalid utf8 string"); - lcs = ucs; - -#if NODEHASHSIZE == 8 - index = ucs & 7; -#else - index = ucs % NODEHASHSIZE; -#endif - assert(index>=0); - next = root->next[index]; - if (!(root->flags & LEAF)) root->id = id; - while (next && next->ucs != ucs) next = next->nexthash; - if (!next) { - tref * ref; - tnode * node = calloc(1, sizeof(tnode)); - - if (ucs<'a' || ucs>'z') { - lcs = towlower((wint_t)ucs); - } - if (ucs==lcs) { - ucs = towupper((wint_t)ucs); - } - - ref = malloc(sizeof(tref)); - ref->ucs = ucs; - ref->node = node; - ref->nexthash=root->next[index]; - root->next[index] = ref; - - /* try lower/upper casing the character, and try again */ - if (ucs!=lcs) { -#if NODEHASHSIZE == 8 - index = lcs & 7; -#else - index = lcs % NODEHASHSIZE; -#endif - ref = malloc(sizeof(tref)); - ref->ucs = lcs; - ref->node = node; - ref->nexthash = root->next[index]; - root->next[index] = ref; - } - next=ref; - } else { - next->node->flags |= SHARED; - if ((next->node->flags & LEAF) == 0) next->node->id.v = NULL; /* why?*/ - } - addtoken(next->node, str+len, id); - while (replace[i].str[0]) { - if (lcs==replace[i].ucs) { - char zText[1024]; - memcpy(zText, replace[i].str, 3); - strcpy(zText+2, (const char*)str+len); - addtoken(root, zText, id); - break; - } - ++i; - } - } -} - -int -findtoken(const tnode * tk, const char * str, variant* result) -{ - if (!str || *str==0) return E_TOK_NOMATCH; - - do { - int index; - const tref * ref; - ucs4_t ucs; - size_t len; - int ret = unicode_utf8_to_ucs4(&ucs, str, &len); - - if (ret!=0) { - /* encoding is broken. youch */ - return E_TOK_NOMATCH; - } -#if NODEHASHSIZE == 8 - index = ucs & 7; -#else - index = ucs % NODEHASHSIZE; -#endif - ref = tk->next[index]; - while (ref && ref->ucs!=ucs) ref = ref->nexthash; - str+=len; - if (!ref) return E_TOK_NOMATCH; - tk = ref->node; - } while (*str); - if (tk) { - *result = tk->id; - return E_TOK_SUCCESS; - } - return E_TOK_NOMATCH; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "umlaut.h" + +#include "log.h" +#include "unicode.h" + +#include +#include +#include +#include + +typedef struct tref { + struct tref * nexthash; + ucs4_t ucs; + struct tnode * node; +} tref; + +#define LEAF 1 /* leaf node for a word. always matches */ +#define SHARED 2 /* at least two words share the node */ + +void +addtoken(tnode * root, const char * str, variant id) +{ + static const struct replace { /* STATIC_CONST: constant value */ + ucs4_t ucs; + const char str[3]; + } replace[] = { + /* match lower-case (!) umlauts and others to transcriptions */ + { 228, "AE"}, /* auml */ + { 246, "OE"}, /* ouml */ + { 252, "UE"}, /* uuml */ + { 223, "SS"}, /* szlig */ + { 230, "AE"}, /* norsk */ + { 248, "OE"}, /* norsk */ + { 229, "AA"}, /* norsk */ + { 0, "" } + }; + + if (!*str) { + root->id = id; + root->flags |= LEAF; + } else { + tref * next; + int ret, index, i = 0; + ucs4_t ucs, lcs; + size_t len; + + ret = unicode_utf8_to_ucs4(&ucs, str, &len); + assert(ret==0 || !"invalid utf8 string"); + lcs = ucs; + +#if NODEHASHSIZE == 8 + index = ucs & 7; +#else + index = ucs % NODEHASHSIZE; +#endif + assert(index>=0); + next = root->next[index]; + if (!(root->flags & LEAF)) root->id = id; + while (next && next->ucs != ucs) next = next->nexthash; + if (!next) { + tref * ref; + tnode * node = calloc(1, sizeof(tnode)); + + if (ucs<'a' || ucs>'z') { + lcs = towlower((wint_t)ucs); + } + if (ucs==lcs) { + ucs = towupper((wint_t)ucs); + } + + ref = malloc(sizeof(tref)); + ref->ucs = ucs; + ref->node = node; + ref->nexthash=root->next[index]; + root->next[index] = ref; + + /* try lower/upper casing the character, and try again */ + if (ucs!=lcs) { +#if NODEHASHSIZE == 8 + index = lcs & 7; +#else + index = lcs % NODEHASHSIZE; +#endif + ref = malloc(sizeof(tref)); + ref->ucs = lcs; + ref->node = node; + ref->nexthash = root->next[index]; + root->next[index] = ref; + } + next=ref; + } else { + next->node->flags |= SHARED; + if ((next->node->flags & LEAF) == 0) next->node->id.v = NULL; /* why?*/ + } + addtoken(next->node, str+len, id); + while (replace[i].str[0]) { + if (lcs==replace[i].ucs) { + char zText[1024]; + memcpy(zText, replace[i].str, 3); + strcpy(zText+2, (const char*)str+len); + addtoken(root, zText, id); + break; + } + ++i; + } + } +} + +int +findtoken(const tnode * tk, const char * str, variant* result) +{ + if (!str || *str==0) return E_TOK_NOMATCH; + + do { + int index; + const tref * ref; + ucs4_t ucs; + size_t len; + int ret = unicode_utf8_to_ucs4(&ucs, str, &len); + + if (ret!=0) { + /* encoding is broken. youch */ + return E_TOK_NOMATCH; + } +#if NODEHASHSIZE == 8 + index = ucs & 7; +#else + index = ucs % NODEHASHSIZE; +#endif + ref = tk->next[index]; + while (ref && ref->ucs!=ucs) ref = ref->nexthash; + str+=len; + if (!ref) return E_TOK_NOMATCH; + tk = ref->node; + } while (*str); + if (tk) { + *result = tk->id; + return E_TOK_SUCCESS; + } + return E_TOK_NOMATCH; +} diff --git a/src/util/umlaut.h b/src/util/umlaut.h index a89f3df77..e1085eb1a 100644 --- a/src/util/umlaut.h +++ b/src/util/umlaut.h @@ -1,51 +1,51 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef _UMLAUT_H -#define _UMLAUT_H - -#include "variant.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define E_TOK_NOMATCH (-1) -#define E_TOK_SUCCESS 0 -#define NODEHASHSIZE 8 -struct tref; - -typedef struct tnode { - struct tref * next[NODEHASHSIZE]; - unsigned char flags; - variant id; -} tnode; - -int findtoken(const struct tnode * tk, const char * str, variant* result); -void addtoken(struct tnode * root, const char * str, variant id); - -typedef struct local_names { - struct local_names * next; - const struct locale * lang; - struct tnode names; -} local_names; - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef _UMLAUT_H +#define _UMLAUT_H + +#include "variant.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define E_TOK_NOMATCH (-1) +#define E_TOK_SUCCESS 0 +#define NODEHASHSIZE 8 +struct tref; + +typedef struct tnode { + struct tref * next[NODEHASHSIZE]; + unsigned char flags; + variant id; +} tnode; + +int findtoken(const struct tnode * tk, const char * str, variant* result); +void addtoken(struct tnode * root, const char * str, variant id); + +typedef struct local_names { + struct local_names * next; + const struct locale * lang; + struct tnode names; +} local_names; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/unicode.c b/src/util/unicode.c index adda90870..d23b3b8f8 100644 --- a/src/util/unicode.c +++ b/src/util/unicode.c @@ -1,436 +1,436 @@ -/* vi: set ts=2: - * +-------------------+ Christian Schlittchen - * | | Enno Rehling - * | Eressea PBEM host | Katja Zedel - * | (c) 1998 - 2007 | - * | | This program may not be used, modified or distributed - * +-------------------+ without prior permission by the authors of Eressea. - * - */ - -#include -#include "unicode.h" - -#include -#include - -#define B00000000 0x00 -#define B10000000 0x80 -#define B11000000 0xC0 -#define B11100000 0xE0 -#define B11110000 0xF0 -#define B11111000 0xF8 -#define B11111100 0xFC -#define B11111110 0xFE - -#define B00111111 0x3F -#define B00011111 0x1F -#define B00001111 0x0F -#define B00000111 0x07 -#define B00000011 0x03 -#define B00000001 0x01 - -int -unicode_utf8_tolower(utf8_t *op, size_t outlen, const utf8_t *ip) -{ - while (*ip) { - ucs4_t ucs = *ip; - ucs4_t low; - size_t size = 1; - - if (ucs & 0x80) { - int ret = unicode_utf8_to_ucs4(&ucs, ip, &size); - if (ret!=0) { - return ret; - } - } - if (size>outlen) { - return ENOMEM; - } - low = towlower((wint_t)ucs); - if (low==ucs) { - memcpy(op, ip, size); - ip += size; - op += size; - outlen -=size; - } else { - ip += size; - unicode_ucs4_to_utf8(op, &size, low); - op += size; - outlen -=size; - } - } - - if (outlen<=0) { - return ENOMEM; - } - *op = 0; - return 0; -} - -int -unicode_latin1_to_utf8(utf8_t *out, size_t *outlen, const char *in, size_t *inlen) -{ - int is = (int)*inlen; - int os = (int)*outlen; - const char * ip = in; - utf8_t * op = out; - - while (ip-in 0xBF) { - if (op-out>=os-1) break; - *op++ = 0xC3; - *op++ = c-64; - } else if (c>0x7F) { - if (op-out>=os-1) break; - *op++ = 0xC2; - *op++ = c; - } else { - if (op-out>=os) break; - *op++ = c; - } - ++ip; - } - *outlen = op-out; - *inlen = ip-in; - return (int)*outlen; -} - -int -unicode_utf8_strcasecmp(const utf8_t * a, const char * b) -{ - while (*a && *b) { - int ret; - size_t size; - ucs4_t ucsa = *a, ucsb = *b; - - if (ucsa & 0x80) { - ret = unicode_utf8_to_ucs4(&ucsa, a, &size); - if (ret!=0) return -1; - a += size; - } else ++a; - if (ucsb & 0x80) { - ret = unicode_utf8_to_ucs4(&ucsb, b, &size); - if (ret!=0) return -1; - b += size; - } else ++b; - - if (ucsb!=ucsa) { - ucsb = towlower((wint_t)ucsb); - ucsa = towlower((wint_t)ucsa); - if (ucsbucsa) return -1; - } - } - if (*b) return -1; - if (*a) return 1; - return 0; -} - -/* Convert a UCS-4 character to UTF-8. */ -int -unicode_ucs4_to_utf8 (utf8_t *utf8_character, size_t *size, ucs4_t ucs4_character) -{ - int utf8_bytes; - - if (ucs4_character <= 0x0000007F) { - /* 0xxxxxxx */ - utf8_bytes = 1; - utf8_character[0] = (char) ucs4_character; - } - else if (ucs4_character <= 0x000007FF) { - /* 110xxxxx 10xxxxxx */ - utf8_bytes = 2; - utf8_character[0] = (char) ((ucs4_character >> 6) | B11000000); - utf8_character[1] = (char) ((ucs4_character & B00111111) | B10000000); - } - else if (ucs4_character <= 0x0000FFFF) { - /* 1110xxxx 10xxxxxx 10xxxxxx */ - utf8_bytes = 3; - utf8_character[0] = (char) ((ucs4_character >> 12) | B11100000); - utf8_character[1] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); - utf8_character[2] = (char) ((ucs4_character & B00111111) | B10000000); - } - else if (ucs4_character <= 0x001FFFFF) { - /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ - utf8_bytes = 4; - utf8_character[0] = (char) ((ucs4_character >> 18) | B11110000); - utf8_character[1] = (char) (((ucs4_character >> 12) & B00111111) | B10000000); - utf8_character[2] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); - utf8_character[3] = (char) ((ucs4_character & B00111111) | B10000000); - } - else if (ucs4_character <= 0x03FFFFFF) { - /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ - utf8_bytes = 5; - utf8_character[0] = (char) ((ucs4_character >> 24) | B11111000); - utf8_character[1] = (char) (((ucs4_character >> 18) & B00111111) | B10000000); - utf8_character[2] = (char) (((ucs4_character >> 12) & B00111111) | B10000000); - utf8_character[3] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); - utf8_character[4] = (char) ((ucs4_character & B00111111) | B10000000); - } - else if (ucs4_character <= 0x7FFFFFFF) { - /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ - utf8_bytes = 6; - utf8_character[0] = (char) ((ucs4_character >> 30) | B11111100); - utf8_character[1] = (char) (((ucs4_character >> 24) & B00111111) | B10000000); - utf8_character[2] = (char) (((ucs4_character >> 18) & B00111111) | B10000000); - utf8_character[3] = (char) (((ucs4_character >> 12) & B00111111) | B10000000); - utf8_character[4] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); - utf8_character[5] = (char) ((ucs4_character & B00111111) | B10000000); - } - else { - return EILSEQ; - } - - *size = utf8_bytes; - - return 0; -} - - -/* Convert a UTF-8 encoded character to UCS-4. */ -int -unicode_utf8_to_ucs4(ucs4_t *ucs4_character, const utf8_t *utf8_string, - size_t *length) -{ - utf8_t utf8_character = utf8_string[0]; - - /* Is the character in the ASCII range? If so, just copy it to the - output. */ - if (~utf8_character & 0x80) - { - *ucs4_character = utf8_character; - *length = 1; - } - else if ((utf8_character & 0xE0) == 0xC0) - { - /* A two-byte UTF-8 sequence. Make sure the other byte is good. */ - if (utf8_string[1] != '\0' && - (utf8_string[1] & 0xC0) != 0x80) - { - return EILSEQ; - } - - *ucs4_character = - ((utf8_string[1] & 0x3F) << 0) + - ((utf8_character & 0x1F) << 6); - *length = 2; - } - else if ((utf8_character & 0xF0) == 0xE0) - { - /* A three-byte UTF-8 sequence. Make sure the other bytes are - good. */ - if ((utf8_string[1] != '\0') && - (utf8_string[1] & 0xC0) != 0x80 && - (utf8_string[2] != '\0') && - (utf8_string[2] & 0xC0) != 0x80) - { - return EILSEQ; - } - - *ucs4_character = - ((utf8_string[2] & 0x3F) << 0) + - ((utf8_string[1] & 0x3F) << 6) + - ((utf8_character & 0x0F) << 12); - *length = 3; - } - else if ((utf8_character & 0xF8) == 0xF0) - { - /* A four-byte UTF-8 sequence. Make sure the other bytes are - good. */ - if ((utf8_string[1] != '\0') && - (utf8_string[1] & 0xC0) != 0x80 && - (utf8_string[2] != '\0') && - (utf8_string[2] & 0xC0) != 0x80 && - (utf8_string[3] != '\0') && - (utf8_string[3] & 0xC0) != 0x80) - { - return EILSEQ; - } - - *ucs4_character = - ((utf8_string[3] & 0x3F) << 0) + - ((utf8_string[2] & 0x3F) << 6) + - ((utf8_string[1] & 0x3F) << 12) + - ((utf8_character & 0x07) << 18); - *length = 4; - } - else if ((utf8_character & 0xFC) == 0xF8) - { - /* A five-byte UTF-8 sequence. Make sure the other bytes are - good. */ - if ((utf8_string[1] != '\0') && - (utf8_string[1] & 0xC0) != 0x80 && - (utf8_string[2] != '\0') && - (utf8_string[2] & 0xC0) != 0x80 && - (utf8_string[3] != '\0') && - (utf8_string[3] & 0xC0) != 0x80 && - (utf8_string[4] != '\0') && - (utf8_string[4] & 0xC0) != 0x80) - { - return EILSEQ; - } - - *ucs4_character = - ((utf8_string[4] & 0x3F) << 0) + - ((utf8_string[3] & 0x3F) << 6) + - ((utf8_string[2] & 0x3F) << 12) + - ((utf8_string[1] & 0x3F) << 18) + - ((utf8_character & 0x03) << 24); - *length = 5; - } - else if ((utf8_character & 0xFE) == 0xFC) - { - /* A six-byte UTF-8 sequence. Make sure the other bytes are - good. */ - if ((utf8_string[1] != '\0') && - (utf8_string[1] & 0xC0) != 0x80 && - (utf8_string[2] != '\0') && - (utf8_string[2] & 0xC0) != 0x80 && - (utf8_string[3] != '\0') && - (utf8_string[3] & 0xC0) != 0x80 && - (utf8_string[4] != '\0') && - (utf8_string[4] & 0xC0) != 0x80 && - (utf8_string[5] != '\0') && - (utf8_string[5] & 0xC0) != 0x80) - { - return EILSEQ; - } - - *ucs4_character = - ((utf8_string[5] & 0x3F) << 0) + - ((utf8_string[4] & 0x3F) << 6) + - ((utf8_string[3] & 0x3F) << 12) + - ((utf8_string[2] & 0x3F) << 18) + - ((utf8_string[1] & 0x3F) << 24) + - ((utf8_character & 0x01) << 30); - *length = 6; - } - else - { - return EILSEQ; - } - - return 0; -} - -/** Convert a UTF-8 encoded character to CP437. */ -int -unicode_utf8_to_cp437(char *cp_character, const utf8_t *utf8_string, - size_t *length) -{ - ucs4_t ucs4_character; - int result; - - result = unicode_utf8_to_ucs4(&ucs4_character, utf8_string, length); - if (result!=0) { - /* pass decoding characters upstream */ - return result; - } - - if (ucs4_character<0x7F) { - *cp_character = (char)ucs4_character; - } else { - struct { ucs4_t ucs4; unsigned char cp437; } xref[160] = { - {0x00A0, 255}, {0x00A1, 173}, {0x00A2, 155}, {0x00A3, 156}, - {0x00A5, 157}, {0x00A7, 21}, {0x00AA, 166}, {0x00AB, 174}, - {0x00AC, 170}, {0x00B0, 248}, {0x00B1, 241}, {0x00B2, 253}, - {0x00B5, 230}, {0x00B6, 20}, {0x00B7, 250}, {0x00BA, 167}, - {0x00BB, 175}, {0x00BC, 172}, {0x00BD, 171}, {0x00BF, 168}, - {0x00C4, 142}, {0x00C5, 143}, {0x00C6, 146}, {0x00C7, 128}, - {0x00C9, 144}, {0x00D1, 165}, {0x00D6, 153}, {0x00DC, 154}, - {0x00DF, 225}, {0x00E0, 133}, {0x00E1, 160}, {0x00E2, 131}, - {0x00E4, 132}, {0x00E5, 134}, {0x00E6, 145}, {0x00E7, 135}, - {0x00E8, 138}, {0x00E9, 130}, {0x00EA, 136}, {0x00EB, 137}, - {0x00EC, 141}, {0x00ED, 161}, {0x00EE, 140}, {0x00EF, 139}, - {0x00F1, 164}, {0x00F2, 149}, {0x00F3, 162}, {0x00F4, 147}, - {0x00F6, 148}, {0x00F7, 246}, {0x00F9, 151}, {0x00FA, 163}, - {0x00FB, 150}, {0x00FC, 129}, {0x00FF, 152}, {0x0192, 159}, - {0x0393, 226}, {0x0398, 233}, {0x03A3, 228}, {0x03A6, 232}, - {0x03A9, 234}, {0x03B1, 224}, {0x03B4, 235}, {0x03B5, 238}, - {0x03C0, 227}, {0x03C3, 229}, {0x03C4, 231}, {0x03C6, 237}, - {0x2022, 7}, {0x203C, 19}, {0x207F, 252}, {0x20A7, 158}, - {0x2190, 27}, {0x2191, 24}, {0x2192, 26}, {0x2193, 25}, - {0x2194, 29}, {0x2195, 18}, {0x21A8, 23}, {0x2219, 249}, - {0x221A, 251}, {0x221E, 236}, {0x221F, 28}, {0x2229, 239}, - {0x2248, 247}, {0x2261, 240}, {0x2264, 243}, {0x2265, 242}, - {0x2302, 127}, {0x2310, 169}, {0x2320, 244}, {0x2321, 245}, - {0x2500, 196}, {0x2502, 179}, {0x250C, 218}, {0x2510, 191}, - {0x2514, 192}, {0x2518, 217}, {0x251C, 195}, {0x2524, 180}, - {0x252C, 194}, {0x2534, 193}, {0x253C, 197}, {0x2550, 205}, - {0x2551, 186}, {0x2552, 213}, {0x2553, 214}, {0x2554, 201}, - {0x2555, 184}, {0x2556, 183}, {0x2557, 187}, {0x2558, 212}, - {0x2559, 211}, {0x255A, 200}, {0x255B, 190}, {0x255C, 189}, - {0x255D, 188}, {0x255E, 198}, {0x255F, 199}, {0x2560, 204}, - {0x2561, 181}, {0x2562, 182}, {0x2563, 185}, {0x2564, 209}, - {0x2565, 210}, {0x2566, 203}, {0x2567, 207}, {0x2568, 208}, - {0x2569, 202}, {0x256A, 216}, {0x256B, 215}, {0x256C, 206}, - {0x2580, 223}, {0x2584, 220}, {0x2588, 219}, {0x258C, 221}, - {0x2590, 222}, {0x2591, 176}, {0x2592, 177}, {0x2593, 178}, - {0x25A0, 254}, {0x25AC, 22}, {0x25B2, 30}, {0x25BA, 16}, - {0x25BC, 31}, {0x25C4, 17}, {0x25CB, 9}, {0x25D8, 8}, - {0x25D9, 10}, {0x263A, 1}, {0x263B, 2}, {0x263C, 15}, - {0x2640, 12}, {0x2642, 11}, {0x2660, 6}, {0x2663, 5}, - {0x2665, 3}, {0x2666, 4}, {0x266A, 13}, {0x266B, 14} - }; - int l=0, r=160; - while (l!=r) { - int m = (l+r)/2; - if (xref[m].ucs4==ucs4_character) { - *cp_character = (char)xref[m].cp437; - break; - } - else if (xref[m].ucs4=0xA0) { - *cp_character = (char)ucs4_character; - } else { - struct { ucs4_t ucs4; unsigned char cp; } xref[] = { - {0x20ac, 0x80}, {0x0081, 0x81}, {0x201a, 0x82}, {0x0192, 0x83}, - {0x201e, 0x84}, {0x2026, 0x85}, {0x2020, 0x86}, {0x2021, 0x87}, - {0x02c6, 0x88}, {0x2030, 0x89}, {0x0160, 0x8a}, {0x2039, 0x8b}, - {0x0152, 0x8c}, {0x008d, 0x8d}, {0x017d, 0x8e}, {0x008f, 0x8f}, - {0x0090, 0x90}, {0x2018, 0x91}, {0x2019, 0x92}, {0x201c, 0x93}, - {0x201d, 0x94}, {0x2022, 0x95}, {0x2013, 0x96}, {0x2014, 0x97}, - {0x02dc, 0x98}, {0x2122, 0x99}, {0x0161, 0x9a}, {0x203a, 0x9b}, - {0x0153, 0x9c}, {0x009d, 0x9d}, {0x017e, 0x9e}, {0x0178, 0x9f} - }; - int l=0, r=sizeof(xref)/sizeof(xref[0]); - while (l!=r) { - int m = (l+r)/2; - if (xref[m].ucs4==ucs4_character) { - *cp_character = (char)xref[m].cp; - break; - } - else if (xref[m].ucs4 + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2007 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +#include +#include "unicode.h" + +#include +#include + +#define B00000000 0x00 +#define B10000000 0x80 +#define B11000000 0xC0 +#define B11100000 0xE0 +#define B11110000 0xF0 +#define B11111000 0xF8 +#define B11111100 0xFC +#define B11111110 0xFE + +#define B00111111 0x3F +#define B00011111 0x1F +#define B00001111 0x0F +#define B00000111 0x07 +#define B00000011 0x03 +#define B00000001 0x01 + +int +unicode_utf8_tolower(utf8_t *op, size_t outlen, const utf8_t *ip) +{ + while (*ip) { + ucs4_t ucs = *ip; + ucs4_t low; + size_t size = 1; + + if (ucs & 0x80) { + int ret = unicode_utf8_to_ucs4(&ucs, ip, &size); + if (ret!=0) { + return ret; + } + } + if (size>outlen) { + return ENOMEM; + } + low = towlower((wint_t)ucs); + if (low==ucs) { + memcpy(op, ip, size); + ip += size; + op += size; + outlen -=size; + } else { + ip += size; + unicode_ucs4_to_utf8(op, &size, low); + op += size; + outlen -=size; + } + } + + if (outlen<=0) { + return ENOMEM; + } + *op = 0; + return 0; +} + +int +unicode_latin1_to_utf8(utf8_t *out, size_t *outlen, const char *in, size_t *inlen) +{ + int is = (int)*inlen; + int os = (int)*outlen; + const char * ip = in; + utf8_t * op = out; + + while (ip-in 0xBF) { + if (op-out>=os-1) break; + *op++ = 0xC3; + *op++ = c-64; + } else if (c>0x7F) { + if (op-out>=os-1) break; + *op++ = 0xC2; + *op++ = c; + } else { + if (op-out>=os) break; + *op++ = c; + } + ++ip; + } + *outlen = op-out; + *inlen = ip-in; + return (int)*outlen; +} + +int +unicode_utf8_strcasecmp(const utf8_t * a, const char * b) +{ + while (*a && *b) { + int ret; + size_t size; + ucs4_t ucsa = *a, ucsb = *b; + + if (ucsa & 0x80) { + ret = unicode_utf8_to_ucs4(&ucsa, a, &size); + if (ret!=0) return -1; + a += size; + } else ++a; + if (ucsb & 0x80) { + ret = unicode_utf8_to_ucs4(&ucsb, b, &size); + if (ret!=0) return -1; + b += size; + } else ++b; + + if (ucsb!=ucsa) { + ucsb = towlower((wint_t)ucsb); + ucsa = towlower((wint_t)ucsa); + if (ucsbucsa) return -1; + } + } + if (*b) return -1; + if (*a) return 1; + return 0; +} + +/* Convert a UCS-4 character to UTF-8. */ +int +unicode_ucs4_to_utf8 (utf8_t *utf8_character, size_t *size, ucs4_t ucs4_character) +{ + int utf8_bytes; + + if (ucs4_character <= 0x0000007F) { + /* 0xxxxxxx */ + utf8_bytes = 1; + utf8_character[0] = (char) ucs4_character; + } + else if (ucs4_character <= 0x000007FF) { + /* 110xxxxx 10xxxxxx */ + utf8_bytes = 2; + utf8_character[0] = (char) ((ucs4_character >> 6) | B11000000); + utf8_character[1] = (char) ((ucs4_character & B00111111) | B10000000); + } + else if (ucs4_character <= 0x0000FFFF) { + /* 1110xxxx 10xxxxxx 10xxxxxx */ + utf8_bytes = 3; + utf8_character[0] = (char) ((ucs4_character >> 12) | B11100000); + utf8_character[1] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); + utf8_character[2] = (char) ((ucs4_character & B00111111) | B10000000); + } + else if (ucs4_character <= 0x001FFFFF) { + /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_bytes = 4; + utf8_character[0] = (char) ((ucs4_character >> 18) | B11110000); + utf8_character[1] = (char) (((ucs4_character >> 12) & B00111111) | B10000000); + utf8_character[2] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); + utf8_character[3] = (char) ((ucs4_character & B00111111) | B10000000); + } + else if (ucs4_character <= 0x03FFFFFF) { + /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_bytes = 5; + utf8_character[0] = (char) ((ucs4_character >> 24) | B11111000); + utf8_character[1] = (char) (((ucs4_character >> 18) & B00111111) | B10000000); + utf8_character[2] = (char) (((ucs4_character >> 12) & B00111111) | B10000000); + utf8_character[3] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); + utf8_character[4] = (char) ((ucs4_character & B00111111) | B10000000); + } + else if (ucs4_character <= 0x7FFFFFFF) { + /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_bytes = 6; + utf8_character[0] = (char) ((ucs4_character >> 30) | B11111100); + utf8_character[1] = (char) (((ucs4_character >> 24) & B00111111) | B10000000); + utf8_character[2] = (char) (((ucs4_character >> 18) & B00111111) | B10000000); + utf8_character[3] = (char) (((ucs4_character >> 12) & B00111111) | B10000000); + utf8_character[4] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); + utf8_character[5] = (char) ((ucs4_character & B00111111) | B10000000); + } + else { + return EILSEQ; + } + + *size = utf8_bytes; + + return 0; +} + + +/* Convert a UTF-8 encoded character to UCS-4. */ +int +unicode_utf8_to_ucs4(ucs4_t *ucs4_character, const utf8_t *utf8_string, + size_t *length) +{ + utf8_t utf8_character = utf8_string[0]; + + /* Is the character in the ASCII range? If so, just copy it to the + output. */ + if (~utf8_character & 0x80) + { + *ucs4_character = utf8_character; + *length = 1; + } + else if ((utf8_character & 0xE0) == 0xC0) + { + /* A two-byte UTF-8 sequence. Make sure the other byte is good. */ + if (utf8_string[1] != '\0' && + (utf8_string[1] & 0xC0) != 0x80) + { + return EILSEQ; + } + + *ucs4_character = + ((utf8_string[1] & 0x3F) << 0) + + ((utf8_character & 0x1F) << 6); + *length = 2; + } + else if ((utf8_character & 0xF0) == 0xE0) + { + /* A three-byte UTF-8 sequence. Make sure the other bytes are + good. */ + if ((utf8_string[1] != '\0') && + (utf8_string[1] & 0xC0) != 0x80 && + (utf8_string[2] != '\0') && + (utf8_string[2] & 0xC0) != 0x80) + { + return EILSEQ; + } + + *ucs4_character = + ((utf8_string[2] & 0x3F) << 0) + + ((utf8_string[1] & 0x3F) << 6) + + ((utf8_character & 0x0F) << 12); + *length = 3; + } + else if ((utf8_character & 0xF8) == 0xF0) + { + /* A four-byte UTF-8 sequence. Make sure the other bytes are + good. */ + if ((utf8_string[1] != '\0') && + (utf8_string[1] & 0xC0) != 0x80 && + (utf8_string[2] != '\0') && + (utf8_string[2] & 0xC0) != 0x80 && + (utf8_string[3] != '\0') && + (utf8_string[3] & 0xC0) != 0x80) + { + return EILSEQ; + } + + *ucs4_character = + ((utf8_string[3] & 0x3F) << 0) + + ((utf8_string[2] & 0x3F) << 6) + + ((utf8_string[1] & 0x3F) << 12) + + ((utf8_character & 0x07) << 18); + *length = 4; + } + else if ((utf8_character & 0xFC) == 0xF8) + { + /* A five-byte UTF-8 sequence. Make sure the other bytes are + good. */ + if ((utf8_string[1] != '\0') && + (utf8_string[1] & 0xC0) != 0x80 && + (utf8_string[2] != '\0') && + (utf8_string[2] & 0xC0) != 0x80 && + (utf8_string[3] != '\0') && + (utf8_string[3] & 0xC0) != 0x80 && + (utf8_string[4] != '\0') && + (utf8_string[4] & 0xC0) != 0x80) + { + return EILSEQ; + } + + *ucs4_character = + ((utf8_string[4] & 0x3F) << 0) + + ((utf8_string[3] & 0x3F) << 6) + + ((utf8_string[2] & 0x3F) << 12) + + ((utf8_string[1] & 0x3F) << 18) + + ((utf8_character & 0x03) << 24); + *length = 5; + } + else if ((utf8_character & 0xFE) == 0xFC) + { + /* A six-byte UTF-8 sequence. Make sure the other bytes are + good. */ + if ((utf8_string[1] != '\0') && + (utf8_string[1] & 0xC0) != 0x80 && + (utf8_string[2] != '\0') && + (utf8_string[2] & 0xC0) != 0x80 && + (utf8_string[3] != '\0') && + (utf8_string[3] & 0xC0) != 0x80 && + (utf8_string[4] != '\0') && + (utf8_string[4] & 0xC0) != 0x80 && + (utf8_string[5] != '\0') && + (utf8_string[5] & 0xC0) != 0x80) + { + return EILSEQ; + } + + *ucs4_character = + ((utf8_string[5] & 0x3F) << 0) + + ((utf8_string[4] & 0x3F) << 6) + + ((utf8_string[3] & 0x3F) << 12) + + ((utf8_string[2] & 0x3F) << 18) + + ((utf8_string[1] & 0x3F) << 24) + + ((utf8_character & 0x01) << 30); + *length = 6; + } + else + { + return EILSEQ; + } + + return 0; +} + +/** Convert a UTF-8 encoded character to CP437. */ +int +unicode_utf8_to_cp437(char *cp_character, const utf8_t *utf8_string, + size_t *length) +{ + ucs4_t ucs4_character; + int result; + + result = unicode_utf8_to_ucs4(&ucs4_character, utf8_string, length); + if (result!=0) { + /* pass decoding characters upstream */ + return result; + } + + if (ucs4_character<0x7F) { + *cp_character = (char)ucs4_character; + } else { + struct { ucs4_t ucs4; unsigned char cp437; } xref[160] = { + {0x00A0, 255}, {0x00A1, 173}, {0x00A2, 155}, {0x00A3, 156}, + {0x00A5, 157}, {0x00A7, 21}, {0x00AA, 166}, {0x00AB, 174}, + {0x00AC, 170}, {0x00B0, 248}, {0x00B1, 241}, {0x00B2, 253}, + {0x00B5, 230}, {0x00B6, 20}, {0x00B7, 250}, {0x00BA, 167}, + {0x00BB, 175}, {0x00BC, 172}, {0x00BD, 171}, {0x00BF, 168}, + {0x00C4, 142}, {0x00C5, 143}, {0x00C6, 146}, {0x00C7, 128}, + {0x00C9, 144}, {0x00D1, 165}, {0x00D6, 153}, {0x00DC, 154}, + {0x00DF, 225}, {0x00E0, 133}, {0x00E1, 160}, {0x00E2, 131}, + {0x00E4, 132}, {0x00E5, 134}, {0x00E6, 145}, {0x00E7, 135}, + {0x00E8, 138}, {0x00E9, 130}, {0x00EA, 136}, {0x00EB, 137}, + {0x00EC, 141}, {0x00ED, 161}, {0x00EE, 140}, {0x00EF, 139}, + {0x00F1, 164}, {0x00F2, 149}, {0x00F3, 162}, {0x00F4, 147}, + {0x00F6, 148}, {0x00F7, 246}, {0x00F9, 151}, {0x00FA, 163}, + {0x00FB, 150}, {0x00FC, 129}, {0x00FF, 152}, {0x0192, 159}, + {0x0393, 226}, {0x0398, 233}, {0x03A3, 228}, {0x03A6, 232}, + {0x03A9, 234}, {0x03B1, 224}, {0x03B4, 235}, {0x03B5, 238}, + {0x03C0, 227}, {0x03C3, 229}, {0x03C4, 231}, {0x03C6, 237}, + {0x2022, 7}, {0x203C, 19}, {0x207F, 252}, {0x20A7, 158}, + {0x2190, 27}, {0x2191, 24}, {0x2192, 26}, {0x2193, 25}, + {0x2194, 29}, {0x2195, 18}, {0x21A8, 23}, {0x2219, 249}, + {0x221A, 251}, {0x221E, 236}, {0x221F, 28}, {0x2229, 239}, + {0x2248, 247}, {0x2261, 240}, {0x2264, 243}, {0x2265, 242}, + {0x2302, 127}, {0x2310, 169}, {0x2320, 244}, {0x2321, 245}, + {0x2500, 196}, {0x2502, 179}, {0x250C, 218}, {0x2510, 191}, + {0x2514, 192}, {0x2518, 217}, {0x251C, 195}, {0x2524, 180}, + {0x252C, 194}, {0x2534, 193}, {0x253C, 197}, {0x2550, 205}, + {0x2551, 186}, {0x2552, 213}, {0x2553, 214}, {0x2554, 201}, + {0x2555, 184}, {0x2556, 183}, {0x2557, 187}, {0x2558, 212}, + {0x2559, 211}, {0x255A, 200}, {0x255B, 190}, {0x255C, 189}, + {0x255D, 188}, {0x255E, 198}, {0x255F, 199}, {0x2560, 204}, + {0x2561, 181}, {0x2562, 182}, {0x2563, 185}, {0x2564, 209}, + {0x2565, 210}, {0x2566, 203}, {0x2567, 207}, {0x2568, 208}, + {0x2569, 202}, {0x256A, 216}, {0x256B, 215}, {0x256C, 206}, + {0x2580, 223}, {0x2584, 220}, {0x2588, 219}, {0x258C, 221}, + {0x2590, 222}, {0x2591, 176}, {0x2592, 177}, {0x2593, 178}, + {0x25A0, 254}, {0x25AC, 22}, {0x25B2, 30}, {0x25BA, 16}, + {0x25BC, 31}, {0x25C4, 17}, {0x25CB, 9}, {0x25D8, 8}, + {0x25D9, 10}, {0x263A, 1}, {0x263B, 2}, {0x263C, 15}, + {0x2640, 12}, {0x2642, 11}, {0x2660, 6}, {0x2663, 5}, + {0x2665, 3}, {0x2666, 4}, {0x266A, 13}, {0x266B, 14} + }; + int l=0, r=160; + while (l!=r) { + int m = (l+r)/2; + if (xref[m].ucs4==ucs4_character) { + *cp_character = (char)xref[m].cp437; + break; + } + else if (xref[m].ucs4=0xA0) { + *cp_character = (char)ucs4_character; + } else { + struct { ucs4_t ucs4; unsigned char cp; } xref[] = { + {0x20ac, 0x80}, {0x0081, 0x81}, {0x201a, 0x82}, {0x0192, 0x83}, + {0x201e, 0x84}, {0x2026, 0x85}, {0x2020, 0x86}, {0x2021, 0x87}, + {0x02c6, 0x88}, {0x2030, 0x89}, {0x0160, 0x8a}, {0x2039, 0x8b}, + {0x0152, 0x8c}, {0x008d, 0x8d}, {0x017d, 0x8e}, {0x008f, 0x8f}, + {0x0090, 0x90}, {0x2018, 0x91}, {0x2019, 0x92}, {0x201c, 0x93}, + {0x201d, 0x94}, {0x2022, 0x95}, {0x2013, 0x96}, {0x2014, 0x97}, + {0x02dc, 0x98}, {0x2122, 0x99}, {0x0161, 0x9a}, {0x203a, 0x9b}, + {0x0153, 0x9c}, {0x009d, 0x9d}, {0x017e, 0x9e}, {0x0178, 0x9f} + }; + int l=0, r=sizeof(xref)/sizeof(xref[0]); + while (l!=r) { + int m = (l+r)/2; + if (xref[m].ucs4==ucs4_character) { + *cp_character = (char)xref[m].cp; + break; + } + else if (xref[m].ucs4 - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef _UNICODE_H -#define _UNICODE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#define USE_UNICODE - typedef unsigned long ucs4_t; - typedef char utf8_t; - - extern int unicode_utf8_to_cp437(char *result, const utf8_t *utf8_string, size_t *length); - extern int unicode_utf8_to_cp1252(char *result, const utf8_t *utf8_string, size_t *length); - extern int unicode_utf8_to_ucs4(ucs4_t *result, const utf8_t *utf8_string, size_t *length); - extern int unicode_ucs4_to_utf8 (utf8_t *result, size_t *size, ucs4_t ucs4_character); - extern int unicode_utf8_strcasecmp(const utf8_t * a, const utf8_t * b); - extern int unicode_latin1_to_utf8(utf8_t *out, size_t *outlen, const char *in, size_t *inlen); - extern int unicode_utf8_tolower(utf8_t *out, size_t outlen, const utf8_t *in); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef _UNICODE_H +#define _UNICODE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#define USE_UNICODE + typedef unsigned long ucs4_t; + typedef char utf8_t; + + extern int unicode_utf8_to_cp437(char *result, const utf8_t *utf8_string, size_t *length); + extern int unicode_utf8_to_cp1252(char *result, const utf8_t *utf8_string, size_t *length); + extern int unicode_utf8_to_ucs4(ucs4_t *result, const utf8_t *utf8_string, size_t *length); + extern int unicode_ucs4_to_utf8 (utf8_t *result, size_t *size, ucs4_t ucs4_character); + extern int unicode_utf8_strcasecmp(const utf8_t * a, const utf8_t * b); + extern int unicode_latin1_to_utf8(utf8_t *out, size_t *outlen, const char *in, size_t *inlen); + extern int unicode_utf8_tolower(utf8_t *out, size_t outlen, const utf8_t *in); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/variant.h b/src/util/variant.h index 62fe323c6..7caa3e94a 100644 --- a/src/util/variant.h +++ b/src/util/variant.h @@ -1,24 +1,24 @@ -#ifndef STRUCT_VARIANT_H -#define STRUCT_VARIANT_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef union variant { - void *v; - int i; - char c; - short s; - short sa[2]; - char ca[4]; - float f; -} variant; - -typedef enum variant_type { - VAR_NONE, VAR_INT, VAR_VOIDPTR, VAR_CHAR, VAR_SHORT, VAR_SHORTA, VAR_CHARA, VAR_FLOAT -} variant_type; - -#ifdef __cplusplus -} -#endif -#endif +#ifndef STRUCT_VARIANT_H +#define STRUCT_VARIANT_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef union variant { + void *v; + int i; + char c; + short s; + short sa[2]; + char ca[4]; + float f; +} variant; + +typedef enum variant_type { + VAR_NONE, VAR_INT, VAR_VOIDPTR, VAR_CHAR, VAR_SHORT, VAR_SHORTA, VAR_CHARA, VAR_FLOAT +} variant_type; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/vmap.c b/src/util/vmap.c index 6ca8f473d..b24355844 100644 --- a/src/util/vmap.c +++ b/src/util/vmap.c @@ -1,146 +1,146 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifdef _MSC_VER -#pragma warning (disable: 4711) -#endif - -#include -#include -#include -#include -#include "vmap.h" - -size_t -vmap_lowerbound(const vmap * vm, const int key) -/* returns the index of the entry which has the greatest key that is less or - * equal to 'key' */ -{ - vmapentry *first = vm->data, *middle; - unsigned int half, len = vm->size; - while (len > 0) { - half = len / 2; - middle = first; - middle += half; - if (middle->key < key) { - first = middle + 1; - len = len - half - 1; - } else - len = half; - } - return first - vm->data; -} - -void -vmap_init(vmap * map) -{ - map->size = 0; /* !! */ - map->maxsize = 4; - map->data = calloc(4, sizeof(vmapentry)); -} - -size_t -vmap_upperbound(const vmap * vm, const int key) -/* returns the index of the entry which has the smallest key that is greater - * or equal to 'key' */ -{ - unsigned int half, len = vm->size; - vmapentry *first = vm->data, *middle; - while (len > 0) { - half = len / 2; - middle = first; - middle += half; - if (key < middle->key) - len = half; - else { - first = middle + 1; - len = len - half - 1; - } - } - return first - vm->data; -} - -size_t -vmap_get(vmap * vm, const int key) -{ - size_t insert = vmap_lowerbound(vm, key); - vmapentry *at; - - /* make sure it's a unique key: */ - if (insert != vm->size && vm->data[insert].key == key) - return insert; - /* insert at this position: */ - if (vm->size == vm->maxsize) { - /* need more space */ - vm->maxsize *= 2; - vm->data = realloc(vm->data, vm->maxsize * sizeof(vmapentry)); - } - at = vm->data + insert; - memmove(at + 1, at, (vm->size - insert) * sizeof(vmapentry)); /* !1.3! */ - at->key = key; - at->value = 0; - ++vm->size; - return insert; -} - -size_t -vmap_insert(vmap * vm, const int key, void *data) -/* inserts an object into the vmap, identifies it with the 'key' which must be - * unique, and returns the vmapentry it created. */ -{ - size_t insert = vmap_lowerbound(vm, key); - vmapentry *at; - - /* make sure it's a unique key: */ - assert(insert == vm->size || vm->data[insert].key != key); - /* insert at this position: */ - if (vm->size == vm->maxsize) { - /* need more space */ - vm->maxsize = vm->maxsize ? (vm->maxsize * 2) : 4; - vm->data = realloc(vm->data, vm->maxsize * sizeof(vmapentry)); - } - at = vm->data + insert; - memmove(at + 1, at, (vm->size - insert) * sizeof(vmapentry)); - at->key = key; - at->value = data; - ++vm->size; - return insert; -} - -size_t -vmap_find(const vmap * vm, const int key) -/* returns the index of the vmapentry that's identified by the key or size (a - * past-the-end value) if it is not found. */ -{ - vmapentry *first = vm->data, *middle; - unsigned int half, len = vm->size; - while (len > 0) { - half = len / 2; - middle = first; - middle += half; - if (middle->key < key) { - first = middle + 1; - len = len - half - 1; - } else - len = half; - } - if (first != vm->data + vm->size && first->key == key) - return first - vm->data; - else - return vm->size; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifdef _MSC_VER +#pragma warning (disable: 4711) +#endif + +#include +#include +#include +#include +#include "vmap.h" + +size_t +vmap_lowerbound(const vmap * vm, const int key) +/* returns the index of the entry which has the greatest key that is less or + * equal to 'key' */ +{ + vmapentry *first = vm->data, *middle; + unsigned int half, len = vm->size; + while (len > 0) { + half = len / 2; + middle = first; + middle += half; + if (middle->key < key) { + first = middle + 1; + len = len - half - 1; + } else + len = half; + } + return first - vm->data; +} + +void +vmap_init(vmap * map) +{ + map->size = 0; /* !! */ + map->maxsize = 4; + map->data = calloc(4, sizeof(vmapentry)); +} + +size_t +vmap_upperbound(const vmap * vm, const int key) +/* returns the index of the entry which has the smallest key that is greater + * or equal to 'key' */ +{ + unsigned int half, len = vm->size; + vmapentry *first = vm->data, *middle; + while (len > 0) { + half = len / 2; + middle = first; + middle += half; + if (key < middle->key) + len = half; + else { + first = middle + 1; + len = len - half - 1; + } + } + return first - vm->data; +} + +size_t +vmap_get(vmap * vm, const int key) +{ + size_t insert = vmap_lowerbound(vm, key); + vmapentry *at; + + /* make sure it's a unique key: */ + if (insert != vm->size && vm->data[insert].key == key) + return insert; + /* insert at this position: */ + if (vm->size == vm->maxsize) { + /* need more space */ + vm->maxsize *= 2; + vm->data = realloc(vm->data, vm->maxsize * sizeof(vmapentry)); + } + at = vm->data + insert; + memmove(at + 1, at, (vm->size - insert) * sizeof(vmapentry)); /* !1.3! */ + at->key = key; + at->value = 0; + ++vm->size; + return insert; +} + +size_t +vmap_insert(vmap * vm, const int key, void *data) +/* inserts an object into the vmap, identifies it with the 'key' which must be + * unique, and returns the vmapentry it created. */ +{ + size_t insert = vmap_lowerbound(vm, key); + vmapentry *at; + + /* make sure it's a unique key: */ + assert(insert == vm->size || vm->data[insert].key != key); + /* insert at this position: */ + if (vm->size == vm->maxsize) { + /* need more space */ + vm->maxsize = vm->maxsize ? (vm->maxsize * 2) : 4; + vm->data = realloc(vm->data, vm->maxsize * sizeof(vmapentry)); + } + at = vm->data + insert; + memmove(at + 1, at, (vm->size - insert) * sizeof(vmapentry)); + at->key = key; + at->value = data; + ++vm->size; + return insert; +} + +size_t +vmap_find(const vmap * vm, const int key) +/* returns the index of the vmapentry that's identified by the key or size (a + * past-the-end value) if it is not found. */ +{ + vmapentry *first = vm->data, *middle; + unsigned int half, len = vm->size; + while (len > 0) { + half = len / 2; + middle = first; + middle += half; + if (middle->key < key) { + first = middle + 1; + len = len - half - 1; + } else + len = half; + } + if (first != vm->data + vm->size && first->key == key) + return first - vm->data; + else + return vm->size; +} diff --git a/src/util/vmap.h b/src/util/vmap.h index 872d4db35..e38b5c52f 100644 --- a/src/util/vmap.h +++ b/src/util/vmap.h @@ -1,47 +1,47 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef VMAP_H -#define VMAP_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct vmapentry vmapentry; -struct vmapentry { - int key; - void *value; -}; -typedef struct vmap vmap; -struct vmap { - vmapentry *data; - unsigned int size; - unsigned int maxsize; -}; - -size_t vmap_lowerbound(const vmap * vm, const int key); -size_t vmap_upperbound(const vmap * vm, const int key); -size_t vmap_insert(vmap * vm, const int key, void *data); -size_t vmap_find(const vmap * vm, const int key); -size_t vmap_get(vmap * vm, const int key); -void vmap_init(vmap * vm); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef VMAP_H +#define VMAP_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct vmapentry vmapentry; +struct vmapentry { + int key; + void *value; +}; +typedef struct vmap vmap; +struct vmap { + vmapentry *data; + unsigned int size; + unsigned int maxsize; +}; + +size_t vmap_lowerbound(const vmap * vm, const int key); +size_t vmap_upperbound(const vmap * vm, const int key); +size_t vmap_insert(vmap * vm, const int key, void *data); +size_t vmap_find(const vmap * vm, const int key); +size_t vmap_get(vmap * vm, const int key); +void vmap_init(vmap * vm); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/vset.c b/src/util/vset.c index f4bac1bb0..693490392 100644 --- a/src/util/vset.c +++ b/src/util/vset.c @@ -1,104 +1,104 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "vset.h" - -void -vset_init(vset * s) -{ - s->data = 0; - s->size = 0; - s->maxsize = 0; -} - -void -vset_destroy(vset * s) -{ - if (s->data) - free(s->data); -} - -int -vset_erase(vset * s, void *item) -{ - size_t i; - - for (i = 0; i != s->size; ++i) - if (s->data[i] == item) { - s->size--; - s->data[i] = s->data[s->size]; - return 1; - } - return 0; -} - -size_t -vset_add(vset * s, void *item) -{ - size_t i; - - if (!s->data) { - s->size = 0; - s->maxsize = 4; - s->data = calloc(4, sizeof(void *)); - } - for (i = 0; i != s->size; ++i) - if (s->data[i] == item) - return i; - if (s->size == s->maxsize) { - s->maxsize *= 2; - s->data = realloc(s->data, s->maxsize * sizeof(void *)); - } - s->data[s->size] = item; - ++s->size; - return s->size - 1; -} - -void * -vset_pop(vset *s) -{ - if(s->size == 0) return NULL; - s->size--; - return s->data[s->size+1]; -} - -int -vset_count(vset *s, void *item) -{ - size_t i; - int c = 0; - - for(i = 0; i != s->size; ++i) { - if(s->data[i] == item) c++; - } - - return c; -} - -void -vset_concat(vset *to, vset *from) -{ - size_t i; - - for(i=0; i != from->size; ++i) { - vset_add(to, from->data[i]); - } -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "vset.h" + +void +vset_init(vset * s) +{ + s->data = 0; + s->size = 0; + s->maxsize = 0; +} + +void +vset_destroy(vset * s) +{ + if (s->data) + free(s->data); +} + +int +vset_erase(vset * s, void *item) +{ + size_t i; + + for (i = 0; i != s->size; ++i) + if (s->data[i] == item) { + s->size--; + s->data[i] = s->data[s->size]; + return 1; + } + return 0; +} + +size_t +vset_add(vset * s, void *item) +{ + size_t i; + + if (!s->data) { + s->size = 0; + s->maxsize = 4; + s->data = calloc(4, sizeof(void *)); + } + for (i = 0; i != s->size; ++i) + if (s->data[i] == item) + return i; + if (s->size == s->maxsize) { + s->maxsize *= 2; + s->data = realloc(s->data, s->maxsize * sizeof(void *)); + } + s->data[s->size] = item; + ++s->size; + return s->size - 1; +} + +void * +vset_pop(vset *s) +{ + if(s->size == 0) return NULL; + s->size--; + return s->data[s->size+1]; +} + +int +vset_count(vset *s, void *item) +{ + size_t i; + int c = 0; + + for(i = 0; i != s->size; ++i) { + if(s->data[i] == item) c++; + } + + return c; +} + +void +vset_concat(vset *to, vset *from) +{ + size_t i; + + for(i=0; i != from->size; ++i) { + vset_add(to, from->data[i]); + } +} + diff --git a/src/util/vset.h b/src/util/vset.h index 30a045ceb..917180d4b 100644 --- a/src/util/vset.h +++ b/src/util/vset.h @@ -1,43 +1,43 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef VOIDPTR_SETS -#define VOIDPTR_SETS -#ifdef __cplusplus -extern "C" { -#endif - -#include -typedef struct vset vset; -struct vset { - void **data; - size_t size; - size_t maxsize; -}; -extern void vset_init(vset * s); -extern void vset_destroy(vset * s); -extern size_t vset_add(vset * s, void *); -extern int vset_erase(vset * s, void *); -extern int vset_count(vset *s, void * i); -extern void *vset_pop(vset *s); -extern void vset_concat(vset *to, vset *from); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef VOIDPTR_SETS +#define VOIDPTR_SETS +#ifdef __cplusplus +extern "C" { +#endif + +#include +typedef struct vset vset; +struct vset { + void **data; + size_t size; + size_t maxsize; +}; +extern void vset_init(vset * s); +extern void vset_destroy(vset * s); +extern size_t vset_add(vset * s, void *); +extern int vset_erase(vset * s, void *); +extern int vset_count(vset *s, void * i); +extern void *vset_pop(vset *s); +extern void vset_concat(vset *to, vset *from); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/windir.c b/src/util/windir.c index 9d62f8360..4bdaadaf5 100644 --- a/src/util/windir.c +++ b/src/util/windir.c @@ -1,56 +1,56 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifdef _MSC_VER -#include - -#include -#include -#include "windir.h" - -DIR * -opendir(const char *name) -{ - static DIR direct; /* STATIC_RESULT: used for return, not across calls */ - - direct.first = 1; - _searchenv(name, "ERESSEA_PATH", direct.name); - if (*direct.name != '\0') - return &direct; - return NULL; -} - -struct dirent * -readdir(DIR * thedir) -{ - static struct _finddata_t ft; /* STATIC_RESULT: used for return, not across calls */ - static struct dirent de; /* STATIC_RESULT: used for return, not across calls */ - char where[_MAX_PATH]; - - strcat(strcpy(where, thedir->name), "/*"); - if (thedir->first) { - thedir->first = 0; - de.hnd = _findfirst(where, &ft); - } else { - if (_findnext(de.hnd, &ft) != 0) - return NULL; - } - _splitpath(ft.name, de.d_drive, de.d_dir, de.d_name, de.d_ext); - return &de; -} -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifdef _MSC_VER +#include + +#include +#include +#include "windir.h" + +DIR * +opendir(const char *name) +{ + static DIR direct; /* STATIC_RESULT: used for return, not across calls */ + + direct.first = 1; + _searchenv(name, "ERESSEA_PATH", direct.name); + if (*direct.name != '\0') + return &direct; + return NULL; +} + +struct dirent * +readdir(DIR * thedir) +{ + static struct _finddata_t ft; /* STATIC_RESULT: used for return, not across calls */ + static struct dirent de; /* STATIC_RESULT: used for return, not across calls */ + char where[_MAX_PATH]; + + strcat(strcpy(where, thedir->name), "/*"); + if (thedir->first) { + thedir->first = 0; + de.hnd = _findfirst(where, &ft); + } else { + if (_findnext(de.hnd, &ft) != 0) + return NULL; + } + _splitpath(ft.name, de.d_drive, de.d_dir, de.d_name, de.d_ext); + return &de; +} +#endif diff --git a/src/util/windir.h b/src/util/windir.h index de9851aa9..77aed13c1 100644 --- a/src/util/windir.h +++ b/src/util/windir.h @@ -1,50 +1,50 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef WINDIR_H -#define WINDIR_H - -#ifdef _MSC_VER -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -typedef struct DIR { - char name[_MAX_PATH]; - int first; -} DIR; - -typedef struct dirent { - char d_path[_MAX_PATH]; - char d_name[_MAX_FNAME]; - char d_drive[_MAX_DRIVE]; - char d_dir[_MAX_DIR]; - char d_ext[_MAX_EXT]; - intptr_t hnd; -} dirent; - -DIR *opendir(const char *name); -struct dirent *readdir(DIR * thedir); - -#ifdef __cplusplus -} -#endif -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef WINDIR_H +#define WINDIR_H + +#ifdef _MSC_VER +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +typedef struct DIR { + char name[_MAX_PATH]; + int first; +} DIR; + +typedef struct dirent { + char d_path[_MAX_PATH]; + char d_name[_MAX_FNAME]; + char d_drive[_MAX_DRIVE]; + char d_dir[_MAX_DIR]; + char d_ext[_MAX_EXT]; + intptr_t hnd; +} dirent; + +DIR *opendir(const char *name); +struct dirent *readdir(DIR * thedir); + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/src/util/xml.c b/src/util/xml.c index e05019d7e..32792baf6 100644 --- a/src/util/xml.c +++ b/src/util/xml.c @@ -1,139 +1,145 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ -#include -#include "xml.h" - -/* util includes */ -#include "log.h" - -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include - -const xmlChar * -xml_i(double number) -{ - static char buffer[128]; - snprintf(buffer, sizeof(buffer), "%.0lf", number); - return (const xmlChar *)buffer; -} - -int -xml_ivalue(xmlNodePtr node, const char * name, int dflt) -{ - int i = dflt; - xmlChar * propValue = xmlGetProp(node, BAD_CAST name); - if (propValue!=NULL) { - i = atoi((const char*)propValue); - xmlFree(propValue); - } - return i; -} - -boolean -xml_bvalue(xmlNodePtr node, const char * name, boolean dflt) -{ - boolean result = dflt; - xmlChar * propValue = xmlGetProp(node, BAD_CAST name); - if (propValue!=NULL) { - if (strcmp((const char*)propValue, "no")==0) result = false; - else if (strcmp((const char*)propValue, "yes")==0) result = true; - else if (strcmp((const char*)propValue, "false")==0) result = false; - else if (strcmp((const char*)propValue, "true")==0) result = true; - else if (strcmp((const char*)propValue, "1")==0) { - log_warning(("boolean value is '1': %s::%s\n", node->name, name)); - result = true; - } - else if (strcmp((const char*)propValue, "0")==0) { - log_warning(("boolean value is '0': %s::%s\n", node->name, name)); - result = false; - } - xmlFree(propValue); - } - return result; -} - -double -xml_fvalue(xmlNodePtr node, const char * name, double dflt) -{ - double result = dflt; - xmlChar * propValue = xmlGetProp(node, BAD_CAST name); - if (propValue!=NULL) { - result = atof((const char*)propValue); - xmlFree(propValue); - } - return result; -} - -/* new xml functions */ -/* libxml includes */ -#include -#include -#include - -typedef struct xml_reader { - struct xml_reader * next; - xml_callback callback; -} xml_reader; - -static xml_reader * xmlReaders; - -void -xml_register_callback(xml_callback callback) -{ - xml_reader * reader = (xml_reader *)malloc(sizeof(xml_reader)); - xml_reader ** insert = &xmlReaders; - reader->callback = callback; - reader->next = NULL; - - while (*insert) insert = &(*insert)->next; - *insert = reader; -} - -int -read_xml(const char * filename, const char * catalog) -{ - xml_reader * reader = xmlReaders; - xmlDocPtr doc; - - if (catalog) { - xmlLoadCatalog(catalog); - } -#ifdef XML_PARSE_XINCLUDE - doc = xmlReadFile(filename, NULL, XML_PARSE_XINCLUDE); -#else - doc = xmlParseFile(filename); -#endif - if (doc==NULL) { - log_error(("could not open %s\n", filename)); - return -1; - } - - xmlXIncludeProcess(doc); - - while (reader!=NULL) { - int i = reader->callback(doc); - if (i!=0) { - return i; - } - reader = reader->next; - } - xmlFreeDoc(doc); - return 0; -} - +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#include +#include "xml.h" + +/* util includes */ +#include "log.h" + +#ifdef HAVE_LIBXML +#include +#include +#endif + +/* libc includes */ +#include +#include +#include +#include +#include + +#ifdef HAVE_LIBXML +const xmlChar * +xml_i(double number) +{ + static char buffer[128]; + snprintf(buffer, sizeof(buffer), "%.0lf", number); + return (const xmlChar *)buffer; +} + +int +xml_ivalue(xmlNodePtr node, const char * name, int dflt) +{ + int i = dflt; + xmlChar * propValue = xmlGetProp(node, BAD_CAST name); + if (propValue!=NULL) { + i = atoi((const char*)propValue); + xmlFree(propValue); + } + return i; +} + +boolean +xml_bvalue(xmlNodePtr node, const char * name, boolean dflt) +{ + boolean result = dflt; + xmlChar * propValue = xmlGetProp(node, BAD_CAST name); + if (propValue!=NULL) { + if (strcmp((const char*)propValue, "no")==0) result = false; + else if (strcmp((const char*)propValue, "yes")==0) result = true; + else if (strcmp((const char*)propValue, "false")==0) result = false; + else if (strcmp((const char*)propValue, "true")==0) result = true; + else if (strcmp((const char*)propValue, "1")==0) { + log_warning(("boolean value is '1': %s::%s\n", node->name, name)); + result = true; + } + else if (strcmp((const char*)propValue, "0")==0) { + log_warning(("boolean value is '0': %s::%s\n", node->name, name)); + result = false; + } + xmlFree(propValue); + } + return result; +} + +double +xml_fvalue(xmlNodePtr node, const char * name, double dflt) +{ + double result = dflt; + xmlChar * propValue = xmlGetProp(node, BAD_CAST name); + if (propValue!=NULL) { + result = atof((const char*)propValue); + xmlFree(propValue); + } + return result; +} + +/* new xml functions */ +/* libxml includes */ +#include +#include +#include + +typedef struct xml_reader { + struct xml_reader * next; + xml_callback callback; +} xml_reader; + +static xml_reader * xmlReaders; + +void +xml_register_callback(xml_callback callback) +{ + xml_reader * reader = (xml_reader *)malloc(sizeof(xml_reader)); + xml_reader ** insert = &xmlReaders; + reader->callback = callback; + reader->next = NULL; + + while (*insert) insert = &(*insert)->next; + *insert = reader; +} +#endif + +int +read_xml(const char * filename, const char * catalog) +{ +#ifdef HAVE_LIBXML + xml_reader * reader = xmlReaders; + xmlDocPtr doc; + + if (catalog) { + xmlLoadCatalog(catalog); + } +#ifdef XML_PARSE_XINCLUDE + doc = xmlReadFile(filename, NULL, XML_PARSE_XINCLUDE); +#else + doc = xmlParseFile(filename); +#endif + if (doc==NULL) { + log_error(("could not open %s\n", filename)); + return -1; + } + + xmlXIncludeProcess(doc); + + while (reader!=NULL) { + int i = reader->callback(doc); + if (i!=0) { + return i; + } + reader = reader->next; + } + xmlFreeDoc(doc); +#endif + return 0; +} + diff --git a/src/util/xml.h b/src/util/xml.h index 540b886e9..1feb3dcfa 100644 --- a/src/util/xml.h +++ b/src/util/xml.h @@ -1,36 +1,36 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_UTIL_XML -#define H_UTIL_XML - - -#ifdef __cplusplus -extern "C" { -#endif - - /* new xml functions: */ -#include - - typedef int (*xml_callback)(xmlDocPtr); - extern void xml_register_callback(xml_callback callback); - extern int read_xml(const char * filename, const char * catalog); - extern double xml_fvalue(xmlNodePtr node, const char * name, double dflt); - extern int xml_ivalue(xmlNodePtr node, const char * name, int dflt); - extern boolean xml_bvalue(xmlNodePtr node, const char * name, boolean dflt); - - const xmlChar * xml_i(double number); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_UTIL_XML +#define H_UTIL_XML + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef HAVE_LIBXML +#include + typedef int (*xml_callback)(xmlDocPtr); + extern void xml_register_callback(xml_callback callback); + extern double xml_fvalue(xmlNodePtr node, const char * name, double dflt); + extern int xml_ivalue(xmlNodePtr node, const char * name, int dflt); + extern boolean xml_bvalue(xmlNodePtr node, const char * name, boolean dflt); + const xmlChar * xml_i(double number); +#endif + + extern int read_xml(const char * filename, const char * catalog); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tools/atoi36.c b/tools/atoi36.c index a935e7650..6b11ded07 100644 --- a/tools/atoi36.c +++ b/tools/atoi36.c @@ -1,35 +1,35 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2001 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include -#include -#include - -int main(int argc, char**argv) -{ - int i=1, reverse = 0; - if (strstr(argv[0], "itoa36")) reverse=1; - if (argc>1) { - if (strcmp(argv[1], "-r")==0) { - i=2; - reverse=1; - } - } - for (;i!=argc;++i) { - if (reverse) { - printf("%s -> %s\n", argv[i], itoa36(atoi(argv[i]))); - } - else printf("%s -> %d\n", argv[i], atoi36(argv[i])); - } - return 0; -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2001 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include +#include + +int main(int argc, char**argv) +{ + int i=1, reverse = 0; + if (strstr(argv[0], "itoa36")) reverse=1; + if (argc>1) { + if (strcmp(argv[1], "-r")==0) { + i=2; + reverse=1; + } + } + for (;i!=argc;++i) { + if (reverse) { + printf("%s -> %s\n", argv[i], itoa36(atoi(argv[i]))); + } + else printf("%s -> %d\n", argv[i], atoi36(argv[i])); + } + return 0; +} diff --git a/tools/gethash.c b/tools/gethash.c index 65fc1ef76..63f04713f 100644 --- a/tools/gethash.c +++ b/tools/gethash.c @@ -1,23 +1,23 @@ -#include -#include -#include - -int main(int argc, char ** argv) -{ - char key[4]; - char code[4]; - char result[4]; - int a, i, rot; - for (a=1;a +#include +#include + +int main(int argc, char ** argv) +{ + char key[4]; + char code[4]; + char result[4]; + int a, i, rot; + for (a=1;a - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2001 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - - */ - -#include -#include -#include - -static char *dwarf_syllable1[] = -{ - "B", "D", "F", "G", "Gl", "H", "K", "L", "M", "N", "R", "S", "T", "Th", "V", -}; - -static char *dwarf_syllable2[] = -{ - "a", "e", "i", "o", "oi", "u", -}; - -static char *dwarf_syllable3[] = -{ - "bur", "fur", "gan", "gnus", "gnar", "li", "lin", "lir", "mli", "nar", "nus", "rin", "ran", "sin", "sil", "sur", -}; - -static char *elf_syllable1[] = -{ - "Al", "An", "Bal", "Bel", "Cal", "Cel", "El", "Elr", "Elv", "Eow", "Ear", "F", "Fal", "Fel", "Fin", "G", "Gal", "Gel", "Gl", "Is", "Lan", "Leg", "Lom", "N", "Nal", "Nel", "S", "Sal", "Sel", "T", "Tal", "Tel", "Thr", "Tin", -}; - -static char *elf_syllable2[] = -{ - "a", "adrie", "ara", "e", "ebri", "ele", "ere", "i", "io", "ithra", "ilma", "il-Ga", "ili", "o", "orfi", "u", "y", -}; - -static char *elf_syllable3[] = -{ - "l", "las", "lad", "ldor", "ldur", "linde", "lith", "mir", "n", "nd", "ndel", "ndil", "ndir", "nduil", "ng", "mbor", "r", "rith", "ril", "riand", "rion", "s", "thien", "viel", "wen", "wyn", -}; - -static char *gnome_syllable1[] = -{ - "Aar", "An", "Ar", "As", "C", "H", "Han", "Har", "Hel", "Iir", "J", "Jan", "Jar", "K", "L", "M", "Mar", "N", "Nik", "Os", "Ol", "P", "R", "S", "Sam", "San", "T", "Ter", "Tom", "Ul", "V", "W", "Y", -}; - -static char *gnome_syllable2[] = -{ - "a", "aa", "ai", "e", "ei", "i", "o", "uo", "u", "uu", -}; - -static char *gnome_syllable3[] = -{ - "ron", "re", "la", "ki", "kseli", "ksi", "ku", "ja", "ta", "na", "namari", "neli", "nika", "nikki", "nu", "nukka", "ka", "ko", "li", "kki", "rik", "po", "to", "pekka", "rjaana", "rjatta", "rjukka", "la", "lla", "lli", "mo", "nni", -}; - -static char *hobbit_syllable1[] = -{ - "B", "Ber", "Br", "D", "Der", "Dr", "F", "Fr", "G", "H", "L", "Ler", "M", "Mer", "N", "P", "Pr", "Per", "R", "S", "T", "W", -}; - -static char *hobbit_syllable2[] = -{ - "a", "e", "i", "ia", "o", "oi", "u", -}; - -static char *hobbit_syllable3[] = -{ - "bo", "ck", "decan", "degar", "do", "doc", "go", "grin", "lba", "lbo", "lda", "ldo", "lla", "ll", "lo", "m", "mwise", "nac", "noc", "nwise", "p", "ppin", "pper", "tho", "to", -}; - -static char *human_syllable1[] = -{ - "Ab", "Ac", "Ad", "Af", "Agr", "Ast", "As", "Al", "Adw", "Adr", "Ar", "B", "Br", "C", "Cr", "Ch", "Cad", "D", "Dr", "Dw", "Ed", "Eth", "Et", "Er", "El", "Eow", "F", "Fr", "G", "Gr", "Gw", "Gal", "Gl", "H", "Ha", "Ib", "Jer", "K", "Ka", "Ked", "L", "Loth", "Lar", "Leg", "M", "Mir", "N", "Nyd", "Ol", "Oc", "On", "P", "Pr", "R", "Rh", "S", "Sev", "T", "Tr", "Th", "V", "Y", "Z", "W", "Wic", -}; - -static char *human_syllable2[] = -{ - "a", "ae", "au", "ao", "are", "ale", "ali", "ay", "ardo", "e", "ei", "ea", "eri", "era", "ela", "eli", "enda", "erra", "i", "ia", "ie", "ire", "ira", "ila", "ili", "ira", "igo", "o", "oa", "oi", "oe", "ore", "u", "y", -}; - -static char *human_syllable3[] = -{ - "a", "and", "b", "bwyn", "baen", "bard", "c", "ctred", "cred", "ch", "can", "d", "dan", "don", "der", "dric", "dfrid", "dus", "f", "g", "gord", "gan", "l", "li", "lgrin", "lin", "lith", "lath", "loth", "ld", "ldric", "ldan", "m", "mas", "mos", "mar", "mond", "n", "nydd", "nidd", "nnon", "nwan", "nyth", "nad", "nn", "nnor", "nd", "p", "r", "ron", "rd", "s", "sh", "seth", "sean", "t", "th", "tha", "tlan", "trem", "tram", "v", "vudd", "w", "wan", "win", "wyn", "wyr", "wyr", "wyth", -}; - -static char *orc_syllable1[] = -{ - "B", "Er", "G", "Gr", "H", "P", "Pr", "R", "V", "Vr", "T", "Tr", "M", "Dr", -}; - -static char *orc_syllable2[] = -{ - "a", "i", "o", "oo", "u", "ui", -}; - -static char *orc_syllable3[] = -{ - "dash", "dish", "dush", "gar", "gor", "gdush", "lo", "gdish", "k", "lg", "nak", "rag", "rbag", "rg", "rk", "ng", "nk", "rt", "ol", "urk", "shnak", "mog", "mak", "rak", -}; - -static char *entish_syllable1[] = -{ - "Baum","Wurzel","Rinden","Ast","Blatt", -}; - -static char *entish_syllable2[] = -{ - "-", -}; - -static char *entish_syllable3[] = -{ - "Hüter","Pflanzer","Hirte","Wächter","Wachser","Beschützer", -}; - -static char *cthuloid_syllable1[] = -{ - "Cth","Az","Fth","Ts","Xo","Q'N","R'L","Ghata","L","Zz","Fl","Cl","S","Y", -}; - -static char *cthuloid_syllable2[] = -{ - "nar","loi","ul","lu","noth","thon","ath","'N","rhy","oth","aza","agn","oa","og", -}; - -static char *cthuloid_syllable3[] = -{ - "l","a","u","oa","oggua","oth","ath","aggua","lu","lo","loth","lotha","agn","axl", -}; - -static char * -create_random_name(race_t race) -{ - static char name[64]; - - switch (race) - { - case RC_DWARF: - strcpy(name, dwarf_syllable1[rng_int()%(sizeof(dwarf_syllable1) / sizeof(char*))]); - strcat(name, dwarf_syllable2[rand()%(sizeof(dwarf_syllable2) / sizeof(char*))]); - strcat(name, dwarf_syllable3[rand()%(sizeof(dwarf_syllable3) / sizeof(char*))]); - break; - case RC_ELF: - strcpy(name, elf_syllable1[rand()%(sizeof(elf_syllable1) / sizeof(char*))]); - strcat(name, elf_syllable2[rand()%(sizeof(elf_syllable2) / sizeof(char*))]); - strcat(name, elf_syllable3[rand()%(sizeof(elf_syllable3) / sizeof(char*))]); - break; -/* - case RACE_GNOME: - strcpy(name, gnome_syllable1[rand()%(sizeof(gnome_syllable1) / sizeof(char*))]); - strcat(name, gnome_syllable2[rand()%(sizeof(gnome_syllable2) / sizeof(char*))]); - strcat(name, gnome_syllable3[rand()%(sizeof(gnome_syllable3) / sizeof(char*))]); - break; -*/ - case RC_HALFLING: - strcpy(name, hobbit_syllable1[rand()%(sizeof(hobbit_syllable1) / sizeof(char*))]); - strcat(name, hobbit_syllable2[rand()%(sizeof(hobbit_syllable2) / sizeof(char*))]); - strcat(name, hobbit_syllable3[rand()%(sizeof(hobbit_syllable3) / sizeof(char*))]); - break; - case RC_HUMAN: - case RC_AQUARIAN: - case RC_CAT: - strcpy(name, human_syllable1[rand()%(sizeof(human_syllable1) / sizeof(char*))]); - strcat(name, human_syllable2[rand()%(sizeof(human_syllable2) / sizeof(char*))]); - strcat(name, human_syllable3[rand()%(sizeof(human_syllable3) / sizeof(char*))]); - break; - case RC_ORC: - case RC_TROLL: - case RC_GOBLIN: - strcpy(name, orc_syllable1[rand()%(sizeof(orc_syllable1) / sizeof(char*))]); - strcat(name, orc_syllable2[rand()%(sizeof(orc_syllable2) / sizeof(char*))]); - strcat(name, orc_syllable3[rand()%(sizeof(orc_syllable3) / sizeof(char*))]); - break; -/* - case RC_TREEMAN: - strcpy(name, entish_syllable1[rand()%(sizeof(entish_syllable1) / sizeof(char*))]); - strcat(name, entish_syllable2[rand()%(sizeof(entish_syllable2) / sizeof(char*))]); - strcat(name, entish_syllable3[rand()%(sizeof(entish_syllable3) / sizeof(char*))]); - break; -*/ - case RC_DAEMON: - case RC_INSECT: - strcpy(name, cthuloid_syllable1[rand()%(sizeof(cthuloid_syllable1) / sizeof(char*))]); - strcat(name, cthuloid_syllable2[rand()%(sizeof(cthuloid_syllable2) / sizeof(char*))]); - strcat(name, cthuloid_syllable3[rand()%(sizeof(cthuloid_syllable3) / sizeof(char*))]); - break; - default: - name[0] = 0; - break; - } - - return name; -} - -int -main(void) -{ - race_t race; - - for(race=0; race<11; race++) { - int i; - printf("%d:", (int)race); - for(i=0;i<20;i++) { - printf(" %s", create_random_name(race)); - } - printf("\n"); - } - - return 0; -} - +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2001 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ + +#include +#include +#include + +static char *dwarf_syllable1[] = +{ + "B", "D", "F", "G", "Gl", "H", "K", "L", "M", "N", "R", "S", "T", "Th", "V", +}; + +static char *dwarf_syllable2[] = +{ + "a", "e", "i", "o", "oi", "u", +}; + +static char *dwarf_syllable3[] = +{ + "bur", "fur", "gan", "gnus", "gnar", "li", "lin", "lir", "mli", "nar", "nus", "rin", "ran", "sin", "sil", "sur", +}; + +static char *elf_syllable1[] = +{ + "Al", "An", "Bal", "Bel", "Cal", "Cel", "El", "Elr", "Elv", "Eow", "Ear", "F", "Fal", "Fel", "Fin", "G", "Gal", "Gel", "Gl", "Is", "Lan", "Leg", "Lom", "N", "Nal", "Nel", "S", "Sal", "Sel", "T", "Tal", "Tel", "Thr", "Tin", +}; + +static char *elf_syllable2[] = +{ + "a", "adrie", "ara", "e", "ebri", "ele", "ere", "i", "io", "ithra", "ilma", "il-Ga", "ili", "o", "orfi", "u", "y", +}; + +static char *elf_syllable3[] = +{ + "l", "las", "lad", "ldor", "ldur", "linde", "lith", "mir", "n", "nd", "ndel", "ndil", "ndir", "nduil", "ng", "mbor", "r", "rith", "ril", "riand", "rion", "s", "thien", "viel", "wen", "wyn", +}; + +static char *gnome_syllable1[] = +{ + "Aar", "An", "Ar", "As", "C", "H", "Han", "Har", "Hel", "Iir", "J", "Jan", "Jar", "K", "L", "M", "Mar", "N", "Nik", "Os", "Ol", "P", "R", "S", "Sam", "San", "T", "Ter", "Tom", "Ul", "V", "W", "Y", +}; + +static char *gnome_syllable2[] = +{ + "a", "aa", "ai", "e", "ei", "i", "o", "uo", "u", "uu", +}; + +static char *gnome_syllable3[] = +{ + "ron", "re", "la", "ki", "kseli", "ksi", "ku", "ja", "ta", "na", "namari", "neli", "nika", "nikki", "nu", "nukka", "ka", "ko", "li", "kki", "rik", "po", "to", "pekka", "rjaana", "rjatta", "rjukka", "la", "lla", "lli", "mo", "nni", +}; + +static char *hobbit_syllable1[] = +{ + "B", "Ber", "Br", "D", "Der", "Dr", "F", "Fr", "G", "H", "L", "Ler", "M", "Mer", "N", "P", "Pr", "Per", "R", "S", "T", "W", +}; + +static char *hobbit_syllable2[] = +{ + "a", "e", "i", "ia", "o", "oi", "u", +}; + +static char *hobbit_syllable3[] = +{ + "bo", "ck", "decan", "degar", "do", "doc", "go", "grin", "lba", "lbo", "lda", "ldo", "lla", "ll", "lo", "m", "mwise", "nac", "noc", "nwise", "p", "ppin", "pper", "tho", "to", +}; + +static char *human_syllable1[] = +{ + "Ab", "Ac", "Ad", "Af", "Agr", "Ast", "As", "Al", "Adw", "Adr", "Ar", "B", "Br", "C", "Cr", "Ch", "Cad", "D", "Dr", "Dw", "Ed", "Eth", "Et", "Er", "El", "Eow", "F", "Fr", "G", "Gr", "Gw", "Gal", "Gl", "H", "Ha", "Ib", "Jer", "K", "Ka", "Ked", "L", "Loth", "Lar", "Leg", "M", "Mir", "N", "Nyd", "Ol", "Oc", "On", "P", "Pr", "R", "Rh", "S", "Sev", "T", "Tr", "Th", "V", "Y", "Z", "W", "Wic", +}; + +static char *human_syllable2[] = +{ + "a", "ae", "au", "ao", "are", "ale", "ali", "ay", "ardo", "e", "ei", "ea", "eri", "era", "ela", "eli", "enda", "erra", "i", "ia", "ie", "ire", "ira", "ila", "ili", "ira", "igo", "o", "oa", "oi", "oe", "ore", "u", "y", +}; + +static char *human_syllable3[] = +{ + "a", "and", "b", "bwyn", "baen", "bard", "c", "ctred", "cred", "ch", "can", "d", "dan", "don", "der", "dric", "dfrid", "dus", "f", "g", "gord", "gan", "l", "li", "lgrin", "lin", "lith", "lath", "loth", "ld", "ldric", "ldan", "m", "mas", "mos", "mar", "mond", "n", "nydd", "nidd", "nnon", "nwan", "nyth", "nad", "nn", "nnor", "nd", "p", "r", "ron", "rd", "s", "sh", "seth", "sean", "t", "th", "tha", "tlan", "trem", "tram", "v", "vudd", "w", "wan", "win", "wyn", "wyr", "wyr", "wyth", +}; + +static char *orc_syllable1[] = +{ + "B", "Er", "G", "Gr", "H", "P", "Pr", "R", "V", "Vr", "T", "Tr", "M", "Dr", +}; + +static char *orc_syllable2[] = +{ + "a", "i", "o", "oo", "u", "ui", +}; + +static char *orc_syllable3[] = +{ + "dash", "dish", "dush", "gar", "gor", "gdush", "lo", "gdish", "k", "lg", "nak", "rag", "rbag", "rg", "rk", "ng", "nk", "rt", "ol", "urk", "shnak", "mog", "mak", "rak", +}; + +static char *entish_syllable1[] = +{ + "Baum","Wurzel","Rinden","Ast","Blatt", +}; + +static char *entish_syllable2[] = +{ + "-", +}; + +static char *entish_syllable3[] = +{ + "Hüter","Pflanzer","Hirte","Wächter","Wachser","Beschützer", +}; + +static char *cthuloid_syllable1[] = +{ + "Cth","Az","Fth","Ts","Xo","Q'N","R'L","Ghata","L","Zz","Fl","Cl","S","Y", +}; + +static char *cthuloid_syllable2[] = +{ + "nar","loi","ul","lu","noth","thon","ath","'N","rhy","oth","aza","agn","oa","og", +}; + +static char *cthuloid_syllable3[] = +{ + "l","a","u","oa","oggua","oth","ath","aggua","lu","lo","loth","lotha","agn","axl", +}; + +static char * +create_random_name(race_t race) +{ + static char name[64]; + + switch (race) + { + case RC_DWARF: + strcpy(name, dwarf_syllable1[rng_int()%(sizeof(dwarf_syllable1) / sizeof(char*))]); + strcat(name, dwarf_syllable2[rand()%(sizeof(dwarf_syllable2) / sizeof(char*))]); + strcat(name, dwarf_syllable3[rand()%(sizeof(dwarf_syllable3) / sizeof(char*))]); + break; + case RC_ELF: + strcpy(name, elf_syllable1[rand()%(sizeof(elf_syllable1) / sizeof(char*))]); + strcat(name, elf_syllable2[rand()%(sizeof(elf_syllable2) / sizeof(char*))]); + strcat(name, elf_syllable3[rand()%(sizeof(elf_syllable3) / sizeof(char*))]); + break; +/* + case RACE_GNOME: + strcpy(name, gnome_syllable1[rand()%(sizeof(gnome_syllable1) / sizeof(char*))]); + strcat(name, gnome_syllable2[rand()%(sizeof(gnome_syllable2) / sizeof(char*))]); + strcat(name, gnome_syllable3[rand()%(sizeof(gnome_syllable3) / sizeof(char*))]); + break; +*/ + case RC_HALFLING: + strcpy(name, hobbit_syllable1[rand()%(sizeof(hobbit_syllable1) / sizeof(char*))]); + strcat(name, hobbit_syllable2[rand()%(sizeof(hobbit_syllable2) / sizeof(char*))]); + strcat(name, hobbit_syllable3[rand()%(sizeof(hobbit_syllable3) / sizeof(char*))]); + break; + case RC_HUMAN: + case RC_AQUARIAN: + case RC_CAT: + strcpy(name, human_syllable1[rand()%(sizeof(human_syllable1) / sizeof(char*))]); + strcat(name, human_syllable2[rand()%(sizeof(human_syllable2) / sizeof(char*))]); + strcat(name, human_syllable3[rand()%(sizeof(human_syllable3) / sizeof(char*))]); + break; + case RC_ORC: + case RC_TROLL: + case RC_GOBLIN: + strcpy(name, orc_syllable1[rand()%(sizeof(orc_syllable1) / sizeof(char*))]); + strcat(name, orc_syllable2[rand()%(sizeof(orc_syllable2) / sizeof(char*))]); + strcat(name, orc_syllable3[rand()%(sizeof(orc_syllable3) / sizeof(char*))]); + break; +/* + case RC_TREEMAN: + strcpy(name, entish_syllable1[rand()%(sizeof(entish_syllable1) / sizeof(char*))]); + strcat(name, entish_syllable2[rand()%(sizeof(entish_syllable2) / sizeof(char*))]); + strcat(name, entish_syllable3[rand()%(sizeof(entish_syllable3) / sizeof(char*))]); + break; +*/ + case RC_DAEMON: + case RC_INSECT: + strcpy(name, cthuloid_syllable1[rand()%(sizeof(cthuloid_syllable1) / sizeof(char*))]); + strcat(name, cthuloid_syllable2[rand()%(sizeof(cthuloid_syllable2) / sizeof(char*))]); + strcat(name, cthuloid_syllable3[rand()%(sizeof(cthuloid_syllable3) / sizeof(char*))]); + break; + default: + name[0] = 0; + break; + } + + return name; +} + +int +main(void) +{ + race_t race; + + for(race=0; race<11; race++) { + int i; + printf("%d:", (int)race); + for(i=0;i<20;i++) { + printf(" %s", create_random_name(race)); + } + printf("\n"); + } + + return 0; +} + From a5e712580fe271463c828da2e36dfe542bfa806c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 8 Aug 2010 01:06:34 -0700 Subject: [PATCH 003/400] undo more CRLF screwups. --- res/armor/chainmail.xml | 18 +- res/armor/laenmail.xml | 18 +- res/armor/laenshield.xml | 18 +- res/armor/plate.xml | 20 +- res/armor/rustychainmail.xml | 20 +- res/armor/rustyshield.xml | 18 +- res/armor/shield.xml | 18 +- res/calendar.xml | 46 +- res/common/armor.xml | 20 +- res/common/buildings.xml | 342 +- res/common/construction.xml | 20 +- res/common/herbs.xml | 178 +- res/common/items.xml | 312 +- res/common/luxuries.xml | 52 +- res/common/potions.xml | 394 +- res/common/resources.xml | 30 +- res/common/weapons.xml | 48 +- res/de/strings.xml | 14964 ++++++++++++------------ res/en/strings.xml | 3360 +++--- res/equipment.xml | 798 +- res/fr/strings.xml | 4164 +++---- res/messages.xml | 17036 ++++++++++++++-------------- res/prefixes.xml | 62 +- res/resources/horse.xml | 22 +- res/resources/hp.xml | 10 +- res/resources/iron.xml | 24 +- res/resources/laen.xml | 20 +- res/resources/log.xml | 26 +- res/resources/mallorn.xml | 26 +- res/resources/mallornseed.xml | 12 +- res/resources/peasant.xml | 10 +- res/resources/seed.xml | 12 +- res/resources/stone.xml | 22 +- res/ships.xml | 166 +- res/spells.xml | 408 +- res/spoils.xml | 118 +- res/terrains.xml | 168 +- res/weapons/axe.xml | 28 +- res/weapons/bow.xml | 26 +- res/weapons/catapult.xml | 28 +- res/weapons/crossbow.xml | 26 +- res/weapons/firesword.xml | 20 +- res/weapons/greatbow.xml | 36 +- res/weapons/greatsword.xml | 26 +- res/weapons/halberd.xml | 30 +- res/weapons/laensword.xml | 24 +- res/weapons/lance.xml | 26 +- res/weapons/mallornbow.xml | 32 +- res/weapons/mallorncrossbow.xml | 26 +- res/weapons/mallornlance.xml | 26 +- res/weapons/mallornspear.xml | 28 +- res/weapons/rep_crossbow.xml | 32 +- res/weapons/runesword.xml | 20 +- res/weapons/rustyaxe.xml | 28 +- res/weapons/rustygreatsword.xml | 24 +- res/weapons/rustyhalberd.xml | 30 +- res/weapons/rustysword.xml | 24 +- res/weapons/spear.xml | 28 +- res/weapons/sword.xml | 24 +- scripts/callbacks.lua | 22 +- scripts/default.lua | 242 +- scripts/dumptable.lua | 190 +- scripts/gates.lua | 50 +- scripts/init.lua | 86 +- scripts/multis.lua | 202 +- scripts/resources.lua | 178 +- scripts/schema.sql | 12 +- scripts/setup.lua | 32 +- scripts/spells.lua | 302 +- scripts/tests/common.lua | 1286 +-- scripts/tests/spells.lua | 128 +- src/attributes/aggressive.h | 66 +- src/attributes/alliance.c | 68 +- src/attributes/alliance.h | 62 +- src/attributes/attributes.c | 162 +- src/attributes/attributes.h | 62 +- src/attributes/fleechance.c | 90 +- src/attributes/fleechance.h | 66 +- src/attributes/follow.c | 92 +- src/attributes/follow.h | 70 +- src/attributes/giveitem.c | 270 +- src/attributes/giveitem.h | 72 +- src/attributes/gm.c | 122 +- src/attributes/gm.h | 72 +- src/attributes/hate.c | 140 +- src/attributes/hate.h | 70 +- src/attributes/iceberg.c | 84 +- src/attributes/iceberg.h | 66 +- src/attributes/key.c | 118 +- src/attributes/key.h | 70 +- src/attributes/matmod.c | 80 +- src/attributes/matmod.h | 74 +- src/attributes/moved.c | 126 +- src/attributes/moved.h | 74 +- src/attributes/movement.c | 118 +- src/attributes/movement.h | 66 +- src/attributes/object.c | 534 +- src/attributes/object.h | 76 +- src/attributes/orcification.c | 80 +- src/attributes/orcification.h | 56 +- src/attributes/otherfaction.c | 160 +- src/attributes/otherfaction.h | 66 +- src/attributes/overrideroads.c | 58 +- src/attributes/overrideroads.h | 62 +- src/attributes/racename.c | 114 +- src/attributes/racename.h | 74 +- src/attributes/raceprefix.c | 120 +- src/attributes/raceprefix.h | 66 +- src/attributes/reduceproduction.c | 102 +- src/attributes/reduceproduction.h | 64 +- src/attributes/targetregion.c | 122 +- src/attributes/targetregion.h | 68 +- src/attributes/viewrange.c | 154 +- src/attributes/viewrange.h | 70 +- src/bindings/bind_attrib.c | 744 +- src/bindings/bind_attrib.h | 48 +- src/bindings/bind_building.c | 513 +- src/bindings/bind_building.h | 46 +- src/bindings/bind_faction.c | 1122 +- src/bindings/bind_faction.h | 48 +- src/bindings/bind_gmtool.c | 532 +- src/bindings/bind_gmtool.h | 20 +- src/bindings/bind_hashtable.c | 374 +- src/bindings/bind_hashtable.h | 48 +- src/bindings/bind_message.c | 696 +- src/bindings/bind_message.h | 44 +- src/bindings/bind_region.c | 1392 +-- src/bindings/bind_region.h | 46 +- src/bindings/bind_ship.c | 364 +- src/bindings/bind_ship.h | 46 +- src/bindings/bind_sqlite.c | 200 +- src/bindings/bind_storage.c | 288 +- src/bindings/bind_storage.h | 44 +- src/bindings/bind_unit.c | 2052 ++-- src/bindings/bind_unit.h | 52 +- src/bindings/bindings.c | 2322 ++-- src/bindings/bindings.h | 54 +- src/bindings/helpers.c | 1328 +-- src/bindings/helpers.h | 46 +- src/build/atoi36.c | 12 +- src/build/external.c | 36 +- src/build/gamecode.c | 160 +- src/build/kernel.c | 111 +- src/build/lib.c | 17 +- src/build/stdafx.c | 2 +- src/build/stdafx.h | 4 +- src/build/util.c | 80 +- src/eressea.c | 423 +- src/eressea.h | 30 +- src/gamecode/archetype.c | 336 +- src/gamecode/archetype.h | 102 +- src/gamecode/creation.c | 146 +- src/gamecode/creation.h | 60 +- src/gamecode/creport.c | 3215 +++--- src/gamecode/creport.h | 58 +- src/gamecode/economy.c | 6926 +++++------ src/gamecode/economy.h | 120 +- src/gamecode/give.c | 876 +- src/gamecode/give.h | 52 +- src/gamecode/items.c | 526 +- src/gamecode/items.h | 48 +- src/gamecode/laws.c | 8446 +++++++------- src/gamecode/laws.h | 94 +- src/gamecode/laws_test.c | 296 +- src/gamecode/market.c | 368 +- src/gamecode/market.h | 50 +- src/gamecode/market_test.c | 132 +- src/gamecode/monster.c | 454 +- src/gamecode/monster.h | 62 +- src/gamecode/randenc.c | 2544 ++--- src/gamecode/randenc.h | 62 +- src/gamecode/report.c | 4869 ++++---- src/gamecode/report.h | 50 +- src/gamecode/spy.c | 964 +- src/gamecode/spy.h | 80 +- src/gamecode/study.c | 1586 +-- src/gamecode/study.h | 90 +- src/gamecode/summary.c | 826 +- src/gamecode/summary.h | 50 +- src/gmtool.c | 2594 ++--- src/gmtool.h | 82 +- src/gmtool_structs.h | 204 +- src/items/artrewards.c | 314 +- src/items/artrewards.h | 60 +- src/items/demonseye.c | 128 +- src/items/demonseye.h | 60 +- src/items/itemtypes.c | 76 +- src/items/itemtypes.h | 50 +- src/items/phoenixcompass.c | 258 +- src/items/phoenixcompass.h | 60 +- src/items/seed.c | 200 +- src/items/seed.h | 70 +- src/items/speedsail.c | 146 +- src/items/speedsail.h | 60 +- src/items/studypotion.c | 116 +- src/items/studypotion.h | 60 +- src/items/weapons.c | 310 +- src/items/weapons.h | 48 +- src/items/xerewards.c | 182 +- src/items/xerewards.h | 60 +- src/kernel/alchemy.c | 676 +- src/kernel/alchemy.h | 140 +- src/kernel/alliance.c | 1096 +- src/kernel/alliance.h | 136 +- src/kernel/battle.c | 8742 +++++++------- src/kernel/battle.h | 542 +- src/kernel/binarystore.c | 585 +- src/kernel/binarystore.h | 46 +- src/kernel/build.c | 2699 ++--- src/kernel/build.h | 198 +- src/kernel/building.c | 1390 +-- src/kernel/building.h | 354 +- src/kernel/calendar.c | 118 +- src/kernel/calendar.h | 90 +- src/kernel/command.c | 206 +- src/kernel/command.h | 78 +- src/kernel/config.c | 6546 +++++------ src/kernel/config.h | 920 +- src/kernel/connection.c | 1226 +- src/kernel/connection.h | 282 +- src/kernel/curse.c | 1642 +-- src/kernel/curse.h | 660 +- src/kernel/curse_test.c | 46 +- src/kernel/equipment.c | 440 +- src/kernel/equipment.h | 146 +- src/kernel/faction.c | 1014 +- src/kernel/faction.h | 322 +- src/kernel/group.c | 486 +- src/kernel/group.h | 102 +- src/kernel/item.c | 2371 ++-- src/kernel/item.h | 714 +- src/kernel/magic.c | 5846 +++++----- src/kernel/magic.h | 790 +- src/kernel/message.c | 566 +- src/kernel/message.h | 122 +- src/kernel/move.c | 5296 ++++----- src/kernel/move.h | 142 +- src/kernel/names.c | 966 +- src/kernel/names.h | 74 +- src/kernel/objtypes.h | 80 +- src/kernel/order.c | 1034 +- src/kernel/order.h | 122 +- src/kernel/pathfinder.c | 400 +- src/kernel/pathfinder.h | 84 +- src/kernel/plane.c | 652 +- src/kernel/plane.h | 168 +- src/kernel/player.c | 202 +- src/kernel/player.h | 86 +- src/kernel/pool.c | 524 +- src/kernel/pool.h | 124 +- src/kernel/race.c | 592 +- src/kernel/race.h | 384 +- src/kernel/region.c | 3216 +++--- src/kernel/region.h | 600 +- src/kernel/render.h | 56 +- src/kernel/reports.c | 4372 +++---- src/kernel/reports.h | 280 +- src/kernel/resources.c | 416 +- src/kernel/resources.h | 126 +- src/kernel/save.c | 3779 +++--- src/kernel/save.h | 146 +- src/kernel/ship.c | 675 +- src/kernel/ship.h | 254 +- src/kernel/skill.c | 630 +- src/kernel/skill.h | 132 +- src/kernel/spell.c | 368 +- src/kernel/spell.h | 318 +- src/kernel/spellid.h | 352 +- src/kernel/sqlite.c | 514 +- src/kernel/teleport.c | 456 +- src/kernel/teleport.h | 82 +- src/kernel/terrain.c | 316 +- src/kernel/terrain.h | 166 +- src/kernel/terrainid.h | 96 +- src/kernel/textstore.c | 413 +- src/kernel/textstore.h | 46 +- src/kernel/types.h | 814 +- src/kernel/unit.c | 3486 +++--- src/kernel/unit.h | 474 +- src/kernel/version.h | 142 +- src/kernel/xmlkernel.h | 58 +- src/kernel/xmlreader.c | 4360 +++---- src/kernel/xmlreader.h | 55 +- src/modules/arena.c | 1054 +- src/modules/arena.h | 78 +- src/modules/autoseed.c | 2046 ++-- src/modules/autoseed.h | 100 +- src/modules/dungeon.c | 536 +- src/modules/dungeon.h | 72 +- src/modules/gmcmd.c | 1544 +-- src/modules/gmcmd.h | 96 +- src/modules/museum.c | 792 +- src/modules/museum.h | 106 +- src/modules/oceannames.c | 252 +- src/modules/oceannames.h | 64 +- src/modules/score.c | 424 +- src/modules/score.h | 72 +- src/modules/weather.c | 282 +- src/modules/weather.h | 108 +- src/modules/wormhole.c | 443 +- src/modules/wormhole.h | 62 +- src/modules/xecmd.c | 222 +- src/modules/xecmd.h | 54 +- src/modules/xmas.c | 164 +- src/modules/xmas.h | 58 +- src/platform.h | 568 +- src/settings.h | 118 +- src/stdafx.h | 2 +- src/tests.c | 254 +- src/tests.h | 42 +- src/triggers/changefaction.c | 228 +- src/triggers/changefaction.h | 78 +- src/triggers/changerace.c | 240 +- src/triggers/changerace.h | 74 +- src/triggers/clonedied.c | 190 +- src/triggers/clonedied.h | 72 +- src/triggers/createcurse.c | 314 +- src/triggers/createcurse.h | 80 +- src/triggers/createunit.c | 260 +- src/triggers/createunit.h | 78 +- src/triggers/gate.c | 234 +- src/triggers/gate.h | 64 +- src/triggers/giveitem.c | 248 +- src/triggers/giveitem.h | 76 +- src/triggers/killunit.c | 174 +- src/triggers/killunit.h | 72 +- src/triggers/removecurse.c | 228 +- src/triggers/removecurse.h | 78 +- src/triggers/shock.c | 296 +- src/triggers/shock.h | 72 +- src/triggers/timeout.c | 226 +- src/triggers/timeout.h | 70 +- src/triggers/triggers.c | 120 +- src/triggers/triggers.h | 60 +- src/triggers/unguard.c | 154 +- src/triggers/unguard.h | 64 +- src/triggers/unitmessage.c | 246 +- src/triggers/unitmessage.h | 72 +- src/util/argstack.c | 132 +- src/util/argstack.h | 54 +- src/util/attrib.c | 644 +- src/util/attrib.h | 186 +- src/util/base36.c | 230 +- src/util/base36.h | 68 +- src/util/base36_test.c | 54 +- src/util/bsdstring.c | 176 +- src/util/bsdstring.h | 46 +- src/util/console.c | 494 +- src/util/console.h | 74 +- src/util/crmessage.c | 318 +- src/util/crmessage.h | 78 +- src/util/cvector.c | 194 +- src/util/cvector.h | 122 +- src/util/dice.c | 194 +- src/util/encoding.h | 38 +- src/util/event.c | 540 +- src/util/event.h | 160 +- src/util/eventbus.c | 112 +- src/util/eventbus.h | 58 +- src/util/filereader.c | 628 +- src/util/filereader.h | 42 +- src/util/functions.c | 148 +- src/util/functions.h | 70 +- src/util/goodies.c | 282 +- src/util/goodies.h | 126 +- src/util/graph.c | 406 +- src/util/graph.h | 76 +- src/util/language.c | 504 +- src/util/language.h | 138 +- src/util/language_struct.h | 56 +- src/util/listbox.c | 382 +- src/util/listbox.h | 32 +- src/util/lists.c | 286 +- src/util/lists.h | 110 +- src/util/log.c | 576 +- src/util/log.h | 90 +- src/util/message.c | 474 +- src/util/message.h | 142 +- src/util/nrmessage.c | 348 +- src/util/nrmessage.h | 112 +- src/util/nrmessage_struct.h | 40 +- src/util/parser.c | 390 +- src/util/parser.h | 58 +- src/util/patricia.c | 472 +- src/util/patricia.h | 42 +- src/util/rand.c | 144 +- src/util/rand.h | 74 +- src/util/resolve.c | 192 +- src/util/resolve.h | 82 +- src/util/rng.h | 90 +- src/util/sql.c | 164 +- src/util/sql.h | 70 +- src/util/storage.h | 96 +- src/util/strings.c | 264 +- src/util/strncpy.c | 44 +- src/util/translation.c | 976 +- src/util/translation.h | 90 +- src/util/umlaut.c | 320 +- src/util/umlaut.h | 102 +- src/util/unicode.c | 872 +- src/util/unicode.h | 84 +- src/util/variant.h | 48 +- src/util/vmap.c | 292 +- src/util/vmap.h | 94 +- src/util/vset.c | 208 +- src/util/vset.h | 86 +- src/util/windir.c | 112 +- src/util/windir.h | 100 +- src/util/xml.c | 284 +- src/util/xml.h | 72 +- tools/atoi36.c | 70 +- tools/gethash.c | 46 +- tools/namegen.c | 436 +- 413 files changed, 105706 insertions(+), 105752 deletions(-) diff --git a/res/armor/chainmail.xml b/res/armor/chainmail.xml index a20c4f8ac..81152f89e 100644 --- a/res/armor/chainmail.xml +++ b/res/armor/chainmail.xml @@ -1,9 +1,9 @@ - - - - - - - - - + + + + + + + + + diff --git a/res/armor/laenmail.xml b/res/armor/laenmail.xml index ec70f3d29..bdcf6b7e1 100644 --- a/res/armor/laenmail.xml +++ b/res/armor/laenmail.xml @@ -1,9 +1,9 @@ - - - - - - - - - + + + + + + + + + diff --git a/res/armor/laenshield.xml b/res/armor/laenshield.xml index c24fe8884..f5eb2d783 100644 --- a/res/armor/laenshield.xml +++ b/res/armor/laenshield.xml @@ -1,9 +1,9 @@ - - - - - - - - - + + + + + + + + + diff --git a/res/armor/plate.xml b/res/armor/plate.xml index 414b96ff3..eb10f6359 100644 --- a/res/armor/plate.xml +++ b/res/armor/plate.xml @@ -1,10 +1,10 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/res/armor/rustychainmail.xml b/res/armor/rustychainmail.xml index 6cf2a7f47..a52b4db7b 100644 --- a/res/armor/rustychainmail.xml +++ b/res/armor/rustychainmail.xml @@ -1,10 +1,10 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/res/armor/rustyshield.xml b/res/armor/rustyshield.xml index d1f4fcbb6..4c34f7ee1 100644 --- a/res/armor/rustyshield.xml +++ b/res/armor/rustyshield.xml @@ -1,9 +1,9 @@ - - - - - - - - - + + + + + + + + + diff --git a/res/armor/shield.xml b/res/armor/shield.xml index ceff1f5b7..9a72baf9a 100644 --- a/res/armor/shield.xml +++ b/res/armor/shield.xml @@ -1,9 +1,9 @@ - - - - - - - - - + + + + + + + + + diff --git a/res/calendar.xml b/res/calendar.xml index 9c99fd2dc..42f83d58b 100644 --- a/res/calendar.xml +++ b/res/calendar.xml @@ -1,23 +1,23 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/common/armor.xml b/res/common/armor.xml index 69e9d2abe..58abae47f 100644 --- a/res/common/armor.xml +++ b/res/common/armor.xml @@ -1,10 +1,10 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/res/common/buildings.xml b/res/common/buildings.xml index a6c647417..5c52bfbb3 100644 --- a/res/common/buildings.xml +++ b/res/common/buildings.xml @@ -1,171 +1,171 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/common/construction.xml b/res/common/construction.xml index dbb718dad..95dcb6a33 100644 --- a/res/common/construction.xml +++ b/res/common/construction.xml @@ -1,10 +1,10 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/res/common/herbs.xml b/res/common/herbs.xml index 7f15009a7..d7d0ef2e6 100644 --- a/res/common/herbs.xml +++ b/res/common/herbs.xml @@ -1,89 +1,89 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/common/items.xml b/res/common/items.xml index c3a7c7b7d..7c57a8184 100644 --- a/res/common/items.xml +++ b/res/common/items.xml @@ -1,156 +1,156 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/common/luxuries.xml b/res/common/luxuries.xml index 22479231c..bdf9c110b 100644 --- a/res/common/luxuries.xml +++ b/res/common/luxuries.xml @@ -1,26 +1,26 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/common/potions.xml b/res/common/potions.xml index 72246a6d0..f444e5a94 100644 --- a/res/common/potions.xml +++ b/res/common/potions.xml @@ -1,197 +1,197 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/common/resources.xml b/res/common/resources.xml index 55563010e..bc39933e6 100644 --- a/res/common/resources.xml +++ b/res/common/resources.xml @@ -1,15 +1,15 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/res/common/weapons.xml b/res/common/weapons.xml index 2988a830c..e91b15e69 100644 --- a/res/common/weapons.xml +++ b/res/common/weapons.xml @@ -1,24 +1,24 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/de/strings.xml b/res/de/strings.xml index 615cee645..d3900f625 100644 --- a/res/de/strings.xml +++ b/res/de/strings.xml @@ -1,7482 +1,7482 @@ - - - - - Wirbel - vortex - remous - - - Ein Wirbel aus reinem Chaos zieht über die Region - A vortex of pure chaos energy pulls over the region - - - Wabernde grüne Schwaden treiben durch den Nebel und - verdichten sich zu einer unheimlichen Kreatur, die nur aus einem langen - Ruderschwanz und einem riesigen runden Maul zu bestehen scheint. - Wobbling green vapours drift through the mists to form an eldritch creature that seems to be entirely made up of huge jaws and a long tail. - - - - Keine Informationen über diese Rasse verfügbar. - No information available for this race. - - - Singdrachen sind von der Größe eines ausgewachsenden Tigers. Ihre Färbung reicht von schillerndem Rot, über dunkles Grün bis hin zu tiefem Schwarz. Alle bekannten Drachen dieser Art weisen eine hohe Intelligenz und ein hohes Maß an magischen Fähigkeiten auf. Wie Ihre großen Verwandten verfügen sie über einen Feuerodem. Sie lieben den Gesang und das üppige Mahl. Von Zeit zu Zeit gehen sie eine engen magisches Bund zu einem Magier ein. Wenn dies geschieht, so steht dem Magier ein äußerst loyaler und lohnender Vertrauter zur Seite. - - Song Dragons are roughly the size of a fully grown tiger. Their coloring ranges from bright red, through a dark green shade to a deep black. All known dragons of this species display a high level of intelligence and highly developed magical skills. Like their larger cousins, Song Dragons posess a firegland. They love singing and a good meal. From time to time one of these magnificent creatures will bond with a mage. When this happens, the mage is assured of a most loyal and useful familiar at his side. - - - Dieses mystische Wesen lebt bevorzugt in den tiefsten Wäldern und - vermag sich hervorragend vor den Augen anderer zu verbergen. Nur - selten schließt sich ein Einhorn einem Magier an, jedoch wenn das - geschieht ist es ein mächtiger Verbündeter, der auch über eigene Magie - verfügt. - - - Der Adler ist ein ausgezeichneter Späher, fliegend überquert er sogar - kurze Meerengen, doch ist er hoch oben am Himmel auch sehr exponiert, - was ihn beim Rasten zu einem leichten Ziel macht. - - - Der Luchs ist bekannt für seine Geschicklichkeit im Verbergen und - Beobachten. Mit ein wenig Geduld kann er zu einem hervorragenden - Späher ausgebildet werden. Im Kampf verteidigt er sich mit seinen - scharfen Krallen und weiß seine Gewandheit zu nutzen. - - - Diese großen Wölfe sind nicht alle so wild und böse wie in den - Legenden berichtet, und einige von ihnen schließen sich auch guten - Magiern bereitwillig an und sind ihnen dann treue Gefährten. - - - 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. - - - - - Das Horn eines Trolles. Kein Troll würde sich lebend davon trennen. - The horn of an adult troll. No troll would ever part with this while he's alive. - - - Beim Barte des Proheten! Ach nein, Zwergen. Irgendetwas riecht hier ranzig. - Sniff... Bleah. Don't they ever wash these? - - - Diese Amulett ist ein hervorragender Fokus für alle Heilzauber. Ein - mit diesem Fokus gewirkter Heilzauber wird mit größerer - Warscheinlichkeit Erfolgreich sein und doppelt so viele Leute heilen - können. - - - Der Kopf eines toten Drachens oder Wyrms. Man sagt, es ruhen magische Kräfte darin. - The head of a dead dragon or wyrm. They say that it has magical powers. - - - Munition für Katapulte. - Ammunition for catapults. - - - Ein Elfenpferd wird sich nur den wenigsten jemals anschließen. Hat es - jedoch seine Scheu überwunden ist es ein sehr wertvoller Gefährte. Ein - Elfenpferd ist schneller als ein Pferd. Zudem hilft es seinem Reiter - im Kampf und unterstützt ihn mit seiner Magie. Es sind schwarze - Elfenpferde bekannt, die sich sogar Orks angeschlossen haben. - - - Die rötlich glühende Klinge dieser furchterregenden magischen Waffe - ist mit dunklen Runen bedeckt. Nur die erfahrendsten Schwertkämpfer - vermögen ihre Kraft zu zähmen, doch in ihrer Hand vermag dem - Runenschwert nichts zu widerstehen - selbst magische Rüstungen - durchdringt es ohne Schwierigkeiten - und den Geist des Kämpfers füllt - es mit unterschütterlicher Zuversicht. - - - This enchanted dragon-eye has to be eaten by the leader of your forces - on the eve before battle. During the night he gains insight into the - dreams of the enemy leaders and may potentially glean a decisive - advantage. - Dieses verzauberte Drachenauge muß vor dem Abend einer Schlacht vom - Heerführer verzehrt werden. Während der Nacht wird er dann Einblick in - die Träume der feindlichen Heerführer erhalten und so möglicherweise - einen entscheidenden Vorteil im kommenden Gefecht erlangen. - - - This artifact grants its wearer the strength of a cavetroll. He will - be able to carry fifty times as much as normal and also in combat his - enhanced strength and tough troll skin will serve him well. - Dieses magische Artefakt verleiht seinem Träger die Stärke eines - ausgewachsenen Höhlentrolls. Seine Tragkraft erhöht sich auf das - 50fache und auch im Kampf werden sich die erhöhte Kraft und die - trollisch zähe Haut positiv auswirken. - - - It may look like just another quartz, but your magician will tell you - tha great power emenates from these crystals. Using it at the begining - of a week will release a strong negative energy that reduce the - power of all spells cast in the region during that week. - Für den ungeübten Betrachter mag der Antimagiekristall wie ein - gewöhnlicher Quarzkristall ausschauen, doch ein Magier spürt, das ihm - ganz besondere Kräfte innewohnen. Durch spezielle Rituale antimagisch - aufgeladen wird der Kristall, wenn er zu feinem Staub zermahlen und - verteilt wird, die beim Zaubern freigesetzten magischen Energien - aufsaugen und die Kraft aller Zauber reduzieren, welche in der betreffenden - Woche in der Region gezaubert werden. - - - A ring of power increases a magician's power. The level of all the - spells - he casts will be increased by one without increasing their costs. - Ein Ring der Macht verstärkt die Kraft des Magiers. Jeder Zauber wird, - ohne das sich die Kosten erhöhen, so gezaubert als hätte der Magier - eine Stufe mehr. - - - Herbs stored in this bag will be much better preserved. - Kräuter, die in diesem Beutelchen aufbewahrt werden, sind erheblich - besser konserviert. - - - This bag encloses a dimensional fold, which can store up to 200 - stones of weight without any extra burden on the bearer. Large items - such as horses or carts cannot be placed inside. - Dieser Beutel umschließt eine kleine Dimensionsfalte, in der bis - zu 200 Gewichtseinheiten transportiert werden können, ohne dass - sie auf das Traggewicht angerechnet werden. Pferde und andere - Lebewesen sowie besonders sperrige Dinge (Wagen und Katapulte) können - nicht in dem Beutel transportiert werden. Auch ist es nicht möglich, - einen Zauberbeutel in einem anderen zu transportieren. Der Beutel - selber wiegt 1 GE. - - - These leather boots are embroidere with unicorn hair and allow - their wearer to walk at twice his normal speed. - Diese aus Leder gefertigten und mit Einhornfell verzierten Stiefel - ermöglichen es ihrem Träger, sich mit der doppelten Geschwindigkeit - fortzubewegen, wenn er zu Fuß reist. - - - The flaming sword gives its bearer an attack of 3d6+10 plus - an additional fireball causing 2d6 damage to 1-10 victims. - Using a flaming sword requires a minimum skill of 7. It grants an - additional +1 to your skill and your resistance to magic will be - increased. - Ein Flammenschwert gibt dem Träger, der kein Magier sein muß, - zusätzlich zu seinem normalen Angriff (3d6+10) einen kleinen - Feuerballangriff, der bei 1-10 Opfern 2d6 magischen Schaden - verursacht. Um ein Flammenschwert führen zu können, muss man - mindestens Hiebwaffen 7 haben, dann verleiht es einem auch - einen zusätzlichen Kampfbonus von +1. Ein Flammenschwert - erhöht die Magieresistenz seines Trägers wie ein Laenschwert. - - - The magic in this ring makes the fingers ten times more nimble. a - craftsman can produce ten times his normal quota, and other abilities - might also be improved. - Der Zauber in diesem Ring bewirkt eine um das zehnfache verbesserte - Geschicklichkeit und Gewandheit der Finger. Handwerker können somit - das zehnfache produzieren, und bei einigen anderen Tätigkeiten könnte - dies ebenfalls von Nutzen sein. - - - This magical artifact has been used since ancient times by Elves to - conceal themselves from their enemies. Other races have also learned - the value of these rings after encountering Elves - after all the ring - makes its wearer invisible to normal eyes, and only magical methods - enable the wearer to be discovered. - Dieses magische Artefakt wurde seit Urzeiten von den Elfen benutzt, - auf der Jagd oder um sich vor Feinden zu verbergen. Doch auch andere - Rassen haben nach der Begegnung mit den Elfenvölkern den Wert des Rings - schnell schätzen gelernt - schließlich macht er den Träger für jedes - noch so scharfe Auge unsichtbar - nur mit magischen Mitteln ist der - Verborgene noch zu entdecken. - - - Das Amulett erlaubt es dem Träger, alle Einheiten, die durch einen - Ring der Unsichtbarkeit geschützt sind, zu sehen. Einheiten allerdings, - die sich mit ihrem Tarnungs-Talent verstecken, bleiben weiterhin - unentdeckt. Die Herstellung des Amulettes kostet 3000 Silber. - - - Dieser Tiegel enthält die seltenste alchemistische Substanz - Eresseas, den Krötenschleim. Angeblich soll der Krötenschleim eine - aussergewöhnlich hohe magische Absorbtionskraft besitzen und deswegen - in obskuren magischen Ritualen Verwendung finden. - - - Die Kröte ist eine der seltensten Rassen Eresseas. Man munkelt, - sie würde nur auf magische Weise entstehen. In einer uralten - Abhandlung über Magie aus der Bibliothek der Akademie von Xontormia - wird die Theorie aufgestellt, das die Kröte die ins morphische Feld - des Magiers übertragene Manifestation eines implodierten - Zauberfeldes sein könnte. Vieleicht deswegen ist die Kröte auch - gegen Zauber weitaus widerstandsfähiger als die normalen Rassen - Eresseas, leider aber auch weitaus unmagischer als diese. Die - Kröte kann schon aufgrund ihrer Größe und der fehlenden Hände - nur unter Schwierigkeiten normale Tätigkeiten ausüben. Der - einzige Vorteil ihrer geringen Größe ist, dass sie sich leichter - verstecken kann. - - - Dieses magische Szepter, ein Geschenk Igjarjuks, sorgt für große - Verwirrung und Gedächtnisverlust. Syntax: BENUTZE "Szepter der - Tränen" - - - Setzt eine Einheit dieses Segel auf einem Schiff, so erhöht - sich dessen Reichweite permanent um 1 Region. - A unit setting this sail on a ship temporarily will permanently - increase the ship's range by 1. - - - Im Mistelzweig ruht eine magische - Kraft der besonderer Art. Der Anwender wird von seinen - Feinden in Frieden gelassen, eine Woche lang läßt jeder - Kämpfer ihn unbeschadet seines Weges ziehen. - The magical misteltoe has a wonderous - property: It's use will make one person able to escape - unharmed from every conflict, no enemy will lay hand on - the bearer for one week. - - - - - - Kein Magiegebiet - no magic school - - - Illaun - Illaun - - - Tybied - Tybied - - - Cerddor - Cerddor - - - Gwyrrd - Gwyrrd - - - Draig - Draig - - - - - Tresen - counter - - - - wenige - few - - - - viele - many - - - - relativ viele - rather many - - - - sehr wenige - very few - - - - sehr viele - a great many - beaucoup de - - - - (trauernd) - (in mourning) - - - Beschreibung: - Description: - - - Art: - Type: - - - Komponenten: - Components: - - - Modifikationen: - Modifications: - - - Stufe: - Level: - - - Rang: - Rank: - - - Syntax: - Syntax: - - - - Geboten wird für - Traders can sell - - - und für - and - - - . - . - - - , für - , - - - - , im - , to the - - - und im - and to the - - - Einheit - Unit - - - Partei - Faction - - - hier_passwort_eintragen - insert_your_password_here - - - - Baum - tree - - - - Bäume - trees - - - - Mallornbaum - mallorn tree - - - - Mallornbäume - mallorn trees - - - - - - Nordwestküste - - - Nordostküste - - - Ostküste - - - Südostküste - - - Südwestküste - - - Westküste - - - - - AUSWERTUNG - - - COMPUTER - - - ZUGVORLAGE - - - SILBERPOOL - - - STATISTIK - - - DEBUG - - - ZIPPED - - - ZEITUNG - - - MATERIALPOOL - - - ADRESSEN - - - BZIP2 - - - PUNKTE - - - TALENTVERSCHIEBUNGEN - - - - - ein fliegender Teppich - - - ein Ballon - - - eine Karavelle - - - ein Boot - - - ein Langboot - - - ein Drachenschiff - - - eine Trireme - - - - fliegender Teppich - flying carpet - - - Ballon - - - Karavelle - - - Boot - - - Langboot - - - Drachenschiff - - - Trireme - - - - - Mahlstrom - - - Ozean - - - Ebene - - - Wald - - - Sumpf - - - Wüste - - - Hochland - - - Berge - - - Gletscher - - - Gletscher - - - Feuerwand - - - Vulkan - - - Nebel - - - Eisberg - - - Dichter Nebel - - - Ebene aus Feuer und Dunkelheit - - - Aktiver Vulkan - - - Halle - - - Gang - - - Wand - - - Magischer Sturm - - - - ein %s - - - %s - - - die Ebene von %s - - - der Wald von %s - - - der Sumpf von %s - - - die Wüste von %s - - - das Hochland von %s - - - das Bergland von %s - - - der Gletscher von %s - - - eine %s - - - der Vulkan von %s - - - ein %s - - - der Eisberg von %s - the glacier of %s - - - der Gletscher von %s - the glacier of %s - - - %s - - - eine %s - - - der Vulkan von %s - - - die %s - - - die %s - - - eine mächtige Mauer - - - ein %s - - - - Krater - - - Pforte - - - Kohlenstück - - - Kohlenstücke - - - - - Westen - - - Nordwesten - - - Nordosten - - - Osten - - - Südwesten - - - Südosten - - - - NW - - - NO - - - Ost - - - SO - - - SW - - - West - - - - - ein unbekanntes Gebäude - an unknown building - - - ein unbekannter zauber - an unknown spell - - - ein unbekanntes Schiff - an unknown ship - - - eine unbekannte Einheit - an unknown unit - - - einer unbekannten Einheit - an unknown unit - - - - - Ereignisse - - - Botschaften - - - Warnungen und Fehler - - - Wirtschaft und Handel - - - Rohstoffe und Produktion - - - Magie und Artefakte - - - Reisen und Bewegung - - - Lehren und Lernen - - - Kämpfe - - - Verschiedenes - - - Neue Zauber - - - Neue Tränke - New Potions - - - - - Burg - - - Leuchtturm - - - Wurmloch - wormhole - - - Bergwerk - - - Steinbruch - - - Hafen - - - Akademie - - - Magierturm - - - Schmiede - - - Sägewerk - - - Pferdezucht - - - Monument - - - Damm - - - Karawanserei - - - Tunnel - - - Taverne - - - Steinkreis - - - Gesegneter Steinkreis - - - Traumschlößchen - - - Struktur - - - Akademie der Künste - academy of arts - - - Skulptur - sculpture - - - - - Zauberstab - - - Zauberstäbe - - - - - Grundmauern - - - Handelsposten - - - Befestigung - - - Turm - - - Burg - - - Festung - - - Zitadelle - - - - - Pyramide - pyramid - - - Pyramide - pyramid - - - - - Sphäre der Unsichtbarkeit - sphere of invisibility - - - Sphären der Unsichtbarkeit - spheres of invisibility - - - Kraut - - - Kräuterbeutel - - - Kräuterbeutel - - - Phiole - - - Phiolen - - - Katapultmunition - ammunition - - - Katapultmunition - ammunition - - - Sonnensegel - solar sail - - - Sonnensegel - solar sails - - - Weihnachtsbaum - christmas tree - - - Weihnachtsbäume - christmas trees - - - Sternenstaub - stardust - - - Sternenstaub - stardust - - - Papyrus - papyrus - - - Papyri - papyri - - - Elfenohr - elven ear - - - Elfenohren - elven ears - - - Dämonenblut - demon blood - - - Dämonenblut - demon blood - - - Goblinkopf - goblin head - - - Goblinköpfe - goblinheads - - - Zwergenbart - dwarven beard - - - Zwergenbärte - dwarven beards - - - Halblingfuß - halfling foot - - - Halblingfüße - halfling feet - - - Menschenskalp - human scalp - - - Menschenskalpe - human scalps - - - Meermenschschuppe - aquarian scale - - - Meermenschschuppen - aquarian scales - - - Insektenfühler - insect antenna - - - Insektenfühler - insect antenna - - - Katzenschwanz - cat tail - - - Katzenschwänze - cat tails - - - Orkhauer - orc tusk - - - Orkhauer - orc tusks - - - Trollhorn - troll horn - - - Trollhörner - troll horns - - - Feder des Phönix - feather of the phoenix - - - Federn des Phönix - feathers of the phoenix - - - - - Silber - - - Silber - - - Trefferpunkt - - - Trefferpunkte - - - Aura - - - Aura - - - permanente Aura - - - permanente Aura - - - Bauer - - - Bauern - - - Einheit - - - Einheiten - - - Person - - - Personen - - - - - Runenschwert - - - Runenschwerter - - - Eisen - - - Eisen - - - Holz - - - Holz - - - Stein - - - Steine - - - Wagen - - - Wagen - - - Katapult - - - Katapulte - - - Schwert - - - Schwerter - - - Speer - - - Speere - - - Mallornspeer - - - Mallornspeere - - - Armbrust - - - Armbrüste - - - Mallornarmbrust - - - Mallornarmbrüste - - - Bogen - - - Bögen - - - Mallornbogen - - - Mallornbögen - - - - Kettenhemd - - - Kettenhemden - - - Schuppenpanzer - - - Schuppenpanzer - - - Plattenpanzer - - - Plattenpanzer - - - Balsam - - - Balsam - - - Gewürz - - - Gewürze - - - Juwel - - - Juwelen - - - Myrrhe - - - Myrrhe - - - Öl - - - Öl - - - Seide - - - Seide - - - Weihrauch - - - Weihrauch - - - Flammenschwert - - - Flammenschwerter - - - Bihänder - - - Bihänder - - - Kriegsaxt - axe - - - Kriegsäxte - axes - - - Elfenbogen - - - Elfenbögen - - - Laenschwert - - - Laenschwerter - - - Laenschild - - - Laenschilde - - - Laenkettenhemd - - - Laenkettenhemden - - - Laen - - - Laen - - - Schild - - - Schilde - - - Hellebarde - - - Hellebarden - - - Lanze - - - Lanzen - - - Mallornlanze - - - Mallornlanzen - - - Mallorn - - - Mallorn - - - Keks - - - Kekse - - - Apfel - - - Äpfel - - - Nuß - - - Nüsse - - - Mandelkern - - - Mandelkerne - - - Drachenblut - - - Drachenblut - - - Feenstiefel - - - Feenstiefel - - - Heiltrank - - - Heiltränke - - - Antimagiekristall - - - Antimagiekristalle - - - Tiegel mit Krötenschleim - - - Tiegel mit Krötenschleim - - - Amulett - - - Amulette - - - Amulett der Keuschheit - - - Amulette der Keuschheit - - - Amulett der Heilung - - - Amulette der Heilung - - - Amulett des Treffens - - - Amulette des Treffens - - - Amulett des wahren Sehens - - - Amulette des wahren Sehens - - - Katzenamulett - - - Katzenamulette - - - Ring der Unsichtbarkeit - - - Ringe der Unsichtbarkeit - - - Ring der Macht - - - Ringe der Macht - - - Ring der flinken Finger - - - Ringe der flinken Finger - - - Pferd - - - Pferde - - - Magischer Kräuterbeutel - - - Magische Kräuterbeutel - - - Silberbeutel - - - Silberkassette - - - Drachenhort - - - Drachenkopf - - - Drachenköpfe - - - Auge des Drachen - - - Augen des Drachen - - - Schartiges Schwert - - - Schartige Schwerter - - - Rostiger Schild - - - Rostige Schilde - - - Rostige Hellebarde - rusty halberd - - - Rostige Hellebarden - rusty halberds - - - Rostige Kriegsaxt - rusty axe - - - Rostige Kriegsäxte - rusty axes - - - Rostiger Zweihänder - rusty claymore - - - Rostige Zweihänder - rusty claymores - - - Rostiges Kettenhemd - - - Rostige Kettenhemden - - - Beutel des negativen Gewichts - - - Beutel des negativen Gewichts - - - Ring der Regeneration - - - Ringe der Regeneration - - - Amulett der Dunkelheit - - - Amulette der Dunkelheit - - - Zauberbeutel - - - Zauberbeutel - - - Traumauge - - - Traumaugen - - - Seeschlangenkopf - - - Seeschlangenköpfe - - - Aurafocus - - - Aurafocuse - - - Akkredition des Xontormia-Expreß - - - Akkreditionen des Xontormia-Expreß - - - Szepter der Tränen - wand of tears - - - Szepter der Tränen - wands of tears - - - Schneeball - snowball - - - Schneebälle - snowball - - - Schneemann - snowman - - - Schneemänner - snowmen - - - Gürtel der Trollstärke - - - Gürtel der Trollstärke - - - Elfenpferd - - - Elfenpferde - - - Pegasus - - - Pegasi - - - Delphin - - - Delphine - - - Eintrittskarte des Großen Museum - - - Eintrittskarten des Großen Museum - - - Rückkehrticket des Großen Museum - - - Rückkehrtickets des Großen Museum - - - Astralkristall - - - Astralkristalle - - - Talenttrunk - - - Talenttrünke - - - Same - - - Samen - - - Mallornsame - - - Mallornsamen - - - Feuerwerk - - - Feuerwerke - - - Lebkuchenherz mit der Aufschrift 'Erz und - Stein, das ist fein' - - - Lebkuchenherzen mit der Aufschrift 'Erz und - Stein, das ist fein' - - - Schlüssel - key - - - Schlüssel - keys - - - Achatener Schlüssel - agate key - - - Achatene Schlüssel - agate keys - - - Saphirner Schlüssel - sapphire key - - - Saphirne Schlüssel - sapphire keys - - - - - Flachwurz - - - Würziger Wagemut - - - Eulenauge - - - Grüner Spinnerich - - - Blauer Baumringel - - - Elfenlieb - - - Gurgelkraut - - - Knotiger Saugwurz - - - Blasenmorchel - - - Wasserfinder - - - Kakteenschwitz - - - Sandfäule - - - Windbeutel - - - Fjordwuchs - - - Alraune - - - Steinbeißer - - - Spaltwachs - - - Höhlenglimm - - - Eisblume - - - Weißer Wüterich - - - Schneekristall - - - - - Flachwurz - - - Würzige Wagemut - - - Eulenaugen - - - Grüne Spinneriche - - - Blaue Baumringel - - - Elfenlieb - - - Gurgelkräuter - - - Knotige Saugwurze - - - Blasenmorcheln - - - Wasserfinder - - - Kakteenschwitze - - - Sandfäulen - - - Windbeutel - - - Fjordwuchse - - - Alraunen - - - Steinbeißer - - - Spaltwachse - - - Höhlenglimme - - - Eisblumen - - - Weiße Wüteriche - - - Schneekristalle - - - - Siebenmeilentee - - - Goliathwasser - - - Wasser des Lebens - - - Schaffenstrunk - - - Wundsalbe - - - Bauernblut - - - Gehirnschmalz - - - Dumpfbackenbrot - - - Nestwärme - - - Pferdeglück - - - Berserkerblut - - - Bauernlieb - - - Trank der Wahrheit - - - Elixier der Macht - - - Heiltrank - - - - Siebenmeilentees - - - Goliathwasser - - - Wasser des Lebens - - - Schaffenstrünke - - - Wundsalben - - - Bauernblut - - - Gehirnschmalz - - - Dumpfbackenbrote - - - Nestwärme - - - Pferdeglück - - - Berserkerblut - - - Bauernlieb - - - Tränke der Wahrheit - - - Elixiere der Macht - - - Heiltränke - - - - - Gürtel der Heldentaten - - - Gürtel der Heldentaten - - - - - AGGRESSIV - - - JEDEM - - - ALLES - - - ANZAHL - - - AURA - - - BÄUME - - - BAUERN - - - BEISTAND - - - BEWACHEN - - - BURG - - - DEFENSIV - - - EINHEIT - - - ERESSEA - - - FLIEHE - - - FREMDES - - - GEBÄUDE - - - GEGENSTÄNDE - - - GIB - - - GNADE - - - HELFE - - - HINTEN - - - HINTER - - - KOMMANDO - - - KRÄUTER - - - DURCHREISE - TRAVEL - - - KÄMPFE - - - NICHT - - - NÄCHSTER - - - PARTEI - - - PARTEITARNUNG - - - PAUSE - - - PERSONEN - - - PRIVAT - - - REGION - - - SCHIFF - - - SILBER - - - STRAßEN - - - STUFE - - - TEMPORÄRE - - - TRÄNKE - - - UM - - - VOR - - - VORNE - - - ZAUBER - - - - XETRANK - XEPOTION - - - XEBALLON - XEBALLOON - - - XELAEN - XELAEN - - - - - Alchemie - - - Armbrustschießen - - - Ausdauer - - - Bergbau - - - Bogenschießen - - - Burgenbau - - - Handeln - - - Hiebwaffen - - - Holzfällen - - - Katapultbedienung - - - Kräuterkunde - - - Magie - - - Pferdedressur - - - Reiten - - - Rüstungsbau - - - Schiffbau - - - Segeln - - - Spionage - - - Stangenwaffen - - - Steinbau - - - Steuereintreiben - - - Straßenbau - - - Taktik - - - Tarnung - - - Unterhaltung - - - Waffenbau - - - Waffenloser Kampf - - - Wagenbau - - - Wahrnehmung - - - - - - // - - - BANNER - - - ARBEITEN - - - WARTEN - WAIT - - - ATTACKIEREN - - - BIETEN - - - BEANSPRUCHEN - CLAIM - - - BEKLAUEN - - - BELAGERE - - - BENENNEN - - - BENUTZEN - - - BESCHREIBEN - - - BETRETEN - - - BEWACHEN - - - BOTSCHAFT - - - ENDE - - - FAHREN - - - NUMMER - - - FRIEDEN - PEACE - - - KRIEG - WAR - - - FOLGEN - - - FORSCHEN - - - HELFEN - - - KÄMPFEN - - - KAMPFZAUBER - - - KAUFEN - - - KONTAKTIEREN - - - LEHREN - - - LERNEN - - - LIEFERE - - - MACHEN - - - NACH - - - XONTORMIA - XONTORMIA - - - ALLIANZ - ALLIANCE - - - BEFÖRDERUNG - PROMOTION - - - BEZAHLEN - PAY - - - PFLANZEN - - - PRÄFIX - - - SYNONYM - - - INFO - - - PASSWORT - - - REKRUTIEREN - - - RESERVIEREN - - - ROUTE - - - SABOTIEREN - - - OPTION - - - SPIONIEREN - - - STIRB - - - TARNEN - - - TRANSPORTIEREN - - - TREIBEN - - - UNTERHALTEN - - - VERKAUFEN - - - VERLASSEN - - - VERGESSEN - - - ZAUBERE - - - ZEIGEN - - - ZERSTÖREN - - - ZÜCHTEN - - - DEFAULT - - - REPORT - - - XML - XML - - - URSPRUNG - - - EMAIL - - - PIRATERIE - - - LOCALE - - - NEUSTART - - - GRUPPE - - - OPFERE - - - BETEN - - - SORTIEREN - - - JIHAD - - - GM - - - WERWESEN - - - - - Optionen - - - Stufe - - - Aktueller Status - - - Benötigte Kräuter - - - im Bau - - - beschädigt - - - Unglücklicherweise wurde deine Partei - ausgelöscht. Du kannst gerne an einer anderen Stelle wieder - einsteigen. Melde Dich einfach wieder an. - - - Talente - - - hat - - - Größe - - - Zauber - - - Kampfzauber - - - keiner - - - Liste aller Adressen - - - anonym - - - Angriff - - - Verteidigung - - - Rüstung - - - Schaden - - - - - Deine Partei hat letzte Runde keinen Zug - abgegeben! - - - - - Schneemann - snowman - - - Schneemänner - snowmen - - - Klon - clone - - - Klone - clones - - - Klonen - clones - - - Klonen - clone - - - - Schablone - template - - - Schablonen - templates - - - Schablonen - templates - - - Schablonen - template - - - - Gnom - gnome - - - Gnome - gnomes - - - Gnomen - gnomes - - - Gnomen - gnome - - - - Museumsgeist - museumghost - - - Museumsgeister - museumghosts - - - Museumsgeistern - museumghosts - - - Museumsgeister - museumghost - - - - Ghast - ghast - - - Ghaste - ghasts - - - Ghasten - ghasts - - - Ghast - ghast - - - - Ghoul - ghoul - - - Ghoule - ghouls - - - Ghoulen - ghouls - - - Ghoul - ghoul - - - - Juju-Zombie - juju-zombie - - - Juju-Zombies - juju-zombies - - - Juju-Zombies - juju-zombies - - - Juju-Zombie - juju-zombie - - - - Zombie - zombie - - - Zombies - zombies - - - Zombies - zombies - - - Zombie - zombie - - - - Skelettherr - skeleton lord - - - Skelettherren - skeleton lords - - - Skelettherren - skeleton lords - - - Skelettherren - skeleton lord - - - - Skelett - skeleton - - - Skelette - skeletons - - - Skeletten - skeletons - - - Skelett - skeleton - - - - Zentaur - centaur - - - Zentauren - centaurs - - - Zentauren - centaurs - - - Zentauren - centaur - - - - Schattenritter - shadow knight - - - Schattenritter - shadow knight - - - Schattenrittern - shadow knights - - - Schattenritter - shadow knight - - - - Seeschlange - sea serpent - - - Seeschlangen - sea serpents - - - Seeschlangen - sea serpents - - - Seeschlangen - sea serpent - - - - Krake - kraken - - - Kraken - krakens - - - Kraken - krakens - - - Kraken - kraken - - - - Riesenschildkröte - giant turtle - - - Riesenschildkröten - giant turtles - - - Riesenschildkröten - giant turtles - - - Riesenschildkröten - giant turtle - - - - Delphin - dolphin - - - Delphine - dolphins - - - Delphinen - dolphins - - - Delphin - dolphin - - - - Tiger - tiger - - - Tiger - tiger - - - Tigern - tigers - - - Tiger - tiger - - - - Höllenkatze - hellcat - - - Höllenkatzen - hellcats - - - Höllenkatzen - hellcats - - - Höllenkatzen - hellcat - - - - Eule - owl - - - Eulen - owls - - - Eulen - owls - - - Eulen - owl - - - - Fee - fairy - - - Feen - fairies - - - Feen - fairies - - - Feen - fairy - - - - Traumkatze - dreamcat - - - Traumkatzen - dreamcats - - - Traumkatzen - dreamcats - - - Traumkatzen - dreamcat - - - - Teufelchen - imp - - - Teufelchen - imps - - - Teufelchen - imps - - - Teufelchen- - imp - - - - Geist - ghost - - - Geister - ghosts - - - Geistern - ghosts - - - Geister - ghost - - - - Warg - direwolf - - - Warge - direwolves - - - Wargen - direwolves - - - Warg - direwolf - - - - Einhorn - unicorn - - - Einhörner - unicorns - - - Einhörnern - unicorns - - - Einhorn - unicorn - - - - Nymphe - nymph - - - Nymphen - nymphs - - - Nymphen - nymphs - - - Nymphen - nymph - - - - Singdrache - song dragon - - - Singdrachen - song dragons - - - Singdrachen - song dragons - - - Singdrachen - song dragon - - - - Ratte - rat - - - Ratten - rats - - - Ratten - rats - - - Ratten - rat - - - - Adler - eagle - - - Adler - eagles - - - Adlern - eagles - - - Adler - eagle - - - - Tunnelwurm - tunnelworm - - - Tunnelwürmer - tunnelworms - - - Tunnelwürmern - tunnelworms - - - Tunnelwurm - tunnelworm - - - - Luchs - lynx - - - Luchse - lynx - - - Luchsen - lynx - - - Luchs - lynx - - - - Wolf - wolf - - - Wölfe - wolves - - - Wölfen - wolves - - - Wolfs - wolf - - - - Bauer - peasant - - - Bauern - peasants - - - Bauern - peasants - - - Bauern - peasant - - - - Hirntöter - braineater - - - Hirntöter - braineaters - - - Hirntöter - braineaters - - - Hirntöter - braineater - - - - Schlumpf - smurf - - - Schlümpfe - smurfs - - - Schlumpf - smurf - - - Schlümpfen - smurfs - - - - Kröte - toad - - - Kröten - toads - - - Kröten - toads - - - Kröten - toad - - - - Alp - nightmare - - - Alps - nightmaress - - - Alps - nightmares - - - Alp - nightmare - - - - Bergwächter - mountainguard - - - Bergwächter - mountainguard - - - Bergwächtern - mountainguards - - - Bergwächter - mountainguard - - - - Schattenmeister - shadowmaster - - - Schattenmeister - shadowmaster - - - Schattenmeistern - shadowmasters - - - Schattenmeister - shadowmaster - - - - Schattendämon - shadowdemon - - - Schattendämonen - shadowdemons - - - Schattendämonen - shadowdemons - - - Schattendämon - shadowdemon - - - - Steingolem - stone golem - - - Steingolems - stone golems - - - Steingolems - stone golems - - - Steingolem - stone golem - - - - Eisengolem - irongolem - - - Eisengolems - irongolems - - - Eisengolems - irongolems - - - Eisengolem - irongolem - - - - Zauber - spell - - - Zauber - spell - - - Zauber - spell - - - Zauber - spell - - - - Spezial - special - - - Spezial - special - - - Spezial - special - - - Spezial - special - - - - Dracoid - dracoid - - - Dracoide - dracoids - - - Dracoiden - dracoids - - - Dracoiden - dracoid - - - - Katzendrache - catdragon - - - Katzendrachen - catdragons - - - Katzendrachen - catdragons - - - Katzendrachen - catdragon - - - - Ent - ent - - - Ents - ents - - - Ents - ents - - - Ent - ent - - - - Schattendrache - shadow dragon - - - Schattendrachen - shadow dragons - - - Schattendrachen - shadow dragons - - - Schattendrachen - shadow dragon - - - - Todesflatter - darkbat - - - Todesflattern - darkbats - - - Todesflattern - darkbats - - - Todesflatter - darkbat - - - - Alptraum - nightmare - - - Alpträume - nightmares - - - Alpträumen - nightmares - - - Alptraum - nightmare - - - - Nachteinhorn - vampiric unicorn - - - Nachteinhörner - vampiric unicorns - - - Nachteinhörnern - vampiric unicorns - - - Nachteinhorn - vampiric unicorn - - - - Wyrm - wyrm - - - Wyrme - wyrms - - - Wyrmen - wyrms - - - Wyrm - wyrm - - - - Drache - dragon - - - Drachen - dragons - - - Drachen - dragons - - - Drachen - dragon - - - - Jungdrache - young dragon - - - Jungdrachen - young dragons - - - Jungdrachen - young dragons - - - Jungdrachen - young dragon - - - - Phönix - phoenix - - - Phönixe - phoenixes - - - Phönixen - phoenixes - - - Phönix - phoenix - - - - Illusion - illusion - - - Illusionen - illusions - - - Illusions - illusions - - - Illusions - illusion - - - - Spinx - sphinx - - - Spinxen - sphinxs - - - Spinxen - sphinx - - - Spinx - sphinx - - - - kleiner Scarabäus - little scarab - - - kleine Scarabäen - little scarab - - - kleinen Scarabäen - little scarab - - - kleine Scarabäen - little scarab - - - - grüner Scarabäus - green scarab - - - grüne Scarabäen - green scarab - - - grünen Scarabäen - green scarab - - - grünen Scarabäen - green scarab - - - - blauer Scarabäus - blue scarab - - - blaue Scarabäen - blue scarabs - - - blauen Scarabäen - blue scarab - - - blaue Scarabäen - blue scarab - - - - roter Scarabäus - red scarab - - - rote Scarabäen - red scarabs - - - roten Scarabäen - red scarab - - - rote Scarabäen - red scarab - - - - Untoter Pharao - undead Pharaoh - - - Untoter Pharaonen - undead Pharaohs - - - Untoten Pharao - undead Pharaoh - - - Untote Pharaonen - undead Pharaoh - - - - Mumie - mummy - - - Mumien - mummys - - - Mumien - mummy - - - Mumien - mummy - - - - Untoter - undead - - - Untote - undead - - - Untoten - undead - - - Untoten - undead - - - - Apepschlange - apepsnake - - - Apepschlangen - apepsnakes - - - Apepschlangen - apepsnakes - - - Apepschlange - apepsnake - - - - Apophis - apophis - - - Apophis - apophis - - - Apophis - apophis - - - Apophis - apophis - - - - Meermensch - aquarian - - - Meermenschen - aquarians - - - Meermenschen - aquarians - - - Meermenschen - aquarian - - - - Katze - cat - - - Katzen - cats - - - Katzen - cats - - - Katzen - cats - - - - Halbling - halfling - - - Halblinge - halflings - - - Halblingen - halflings - - - Halblings - halfling - - - - Insekt - insect - - - Insekten - insects - - - Insekten - insects - - - Insekten - insect - - - - Dämon - demon - - - Dämonen - demons - - - Dämonen - demons - - - Dämonen - demon - - - - Troll - troll - - - Trolle - trolls - - - Trollen - trolls - - - Troll - troll - - - - Mensch - human - - - Menschen - humans - - - Menschen - humans - - - Menschen - human - - - - Goblin - goblin - - - Goblins - goblins - - - Goblins - goblins - - - Goblin - goblin - - - - Ork - orc - - - Orks - orcs - - - Orks - orcs - - - Ork - orc - - - - Snotling - snotling - - - Snotlinge - snotlings - - - Snotlingen - snotlings - - - Snotling - snotling - - - - Snotling - snotling - - - Snotlinge - snotlings - - - Snotlingen - snotlings - - - Snotling - snotling - - - - Elf - elf - - - Elfen - elves - - - Elfen - elves - - - Elfen - elves - - - - Zwerg - dwarf - - - Zwerge - dwarves - - - Zwergen - dwarves - - - Zwergen - dwarf - - - - - - sehr stark - critically wounded - - - stark - heavily wounded - - - schwer verwundet - badly wounded - - - verwundet - wounded - - - erschöpft - exhausted - - - - - For Seven Mile Tea, boil up a Cobalt Fungus and pour the resulting brew into a Windbag. Catch and filter the liquid that drips out and administer it. This tea allows up to ten men to move as fast as a horse. - Für den Siebenmeilentee koche man einen Blauen Baumringel auf und gieße dieses Gebräu in einen Windbeutel. Das heraustropfende Wasser fange man auf, filtere es und verabreiche es alsdann. Durch diesen Tee können bis zu zehn Menschen schnell wie ein Pferd laufen. - - - 'First roast the Gurgelkraut quickly and add some Fjordwuchs to spice it up. Let it all boil slowly until almost all liquid has evaporated. Leave the mash overnight and finally squeeze it the next morning until a thick fluid drips out.' The liquid thus produced, 'Goliath Water' as we call it, is enough for 10 men and gives each man the carrying capacity of a horse for one week. - Zuerst brate man das Gurgelkraut leicht an und würze das Zeug mit ein wenig Fjordwuchs. Man lasse alles so lange kochen, bis fast alle Flüssigkeit verdampft ist. Diesen Brei stelle man über Nacht raus. Am nächsten Morgen presse man den Brei aus. Die so gewonnene Flüssigkeit, Goliathwasser genannt, verleiht bis zu zehn Männern die Tragkraft eines Pferdes. - - - The "Water of Life" allows living trees to be created from logs. A Knotroot and Elvendear are heated until one can just still keep one's finger in. This is then poured into a jar and allowed to cool slowly. The extract is sufficient for 10 pieces of wood. - Das 'Wasser des Lebens' ist in der Lage, aus gefällten Baumstämmen wieder lebende Bäume zu machen. Dazu wird ein knotiger Saugwurz zusammen mit einem Elfenlieb erwärmt, so daß man gerade noch den Finger reinhalten kann. Dies gieße man in ein Gefäß und lasse es langsam abkühlen. Der Extrakt reicht für 10 Holzstämme. - - - Allow a Tangy Temerity to simmer for three hours in a litre of water, then add a grated Mandrake, and sprinkle in a Gapgrowth harvested at full moon. The whole brew should then be allowed to stew for three days in a warm place. This potion increases the strength and endurance of ten men so that they can achieve twice as much in a week. - Man lasse einen Würzigen Wagemut drei Stunden lang in einem Liter Wasser köcheln. Dann gebe man eine geriebene Alraune dazu und bestreue das ganze mit bei Vollmond geerntetem Spaltwachs. Nun lasse man den Sud drei Tage an einem dunklen und warmen Ort ziehen und seie dann die Flüssigkeit ab. Dieser Schaffenstrunk erhöht die Kraft und Ausdauer von zehn Männern, so daß sie doppelt soviel schaffen können wie sonst. - - - When one is severely wounded after a hard battle it is advisable to have some Ointment to hand. Applied to wounds, this magical paste closes them in the blink of an eye. For the preparation the alchemist requires a cobalt fungus, tangy temerity, and white hemlock. A dose of the potion heals up to 400 hitpoints. - Ist man nach einem einem harten Kampf schwer verwundet, ist es ratsam, etwas Wundsalbe parat zu haben. Streicht man diese magische Paste auf die Wunden, schließen sich diese augenblicklich. Für die Herstellung benötigt der Alchemist nebst einem Blauen Baumringel einen Würzigen Wagemut und einen Weißen Wüterich. Eine solche Portion heilt bis zu 400 Lebenspunkte. - - - Knowledge of this potion is amongst the most dangerous and secret wisdom of the alchemist. Snatched from the darkest hells, the knowledge of this formula enables the production of an elixer which serves Demons as nourishment. If used by normal beings it leads to a swift death and eternal undeath. The creation requires Fjord Fungus together with some Cave Lichen and Cobalt Fungus, and an unfortunate peasant from the region, who is killed in the bloody days-long ritual. One vial of the potion satisfies the hunger of 100 Demons for a week. - Zu den gefährlichsten und geheimsten Wissen der Alchemisten zählt die Kenntnis um diesen Trank. Den finstersten Höllen entrissen, ermöglicht die Kenntnis dieser Formel die Herstellung eines Elixiers, welches Dämonen als Nahrung dient. Von normalen Lebewesen eingenommen, führt es zu schnellem Tod und ewigen Nichtleben. Die Herstellung benötigt nebst Fjordwuchs, etwas Höhlenglimm und einem Blauen Baumringel auch einen Bauern aus der Region, welcher in einem tagelangen blutigen Ritual getötet wird. Ein Fläschchen des Tranks kann den Hunger von 100 Dämonen für eine Woche stillen. - - - To create the brain wax potion, mix the juice of a waterfinder with quite a bit of grated windbag and a pinch of bugleweed. Let this steep for just a minute. When the liquid is only lukewarm, add some rock weed. Using a large spoon, stirr exactly seven times clockwise and then seven times counterclockwise. Fill the vial when the liquid has gone still. The juice gives ten people a 33% chance of an additional attempt at learning a skill. - Für das Gehirnschmalz verrühre man den Saft eines Wasserfinders mit recht viel geriebenem Windbeutel und ein wenig Gurgelkraut. Dies lasse man kurz aufwallen. Wenn die Flüssigkeit nur noch handwarm ist, gebe man etwas Steinbeißer dazu. Das ganze muß genau siebenmal rechtsherum und siebenmal linksherum mit einem großen Löffel gerührt werden. Wenn keine Bewegung mehr zu erkennen ist, fülle man den Saft ab. Der Saft gibt mit einer Chance von 1/3 bis zu zehn Personen einen zusätzlichen Lernversuch. - - - A duncebun is a nasty piece of work, negating any attempt at learning a skill, or even causing the subject to forget things! For ten servings knead a rasped fjord fungus, an abraded owlsgaze and a finely sliced spider ivy to a smooth dough. Bake for an hour at moderate heat and brush the result with some cave lichen. Who eats this bread will not learn what he's attempting to learn, and, in case there is no attempt to learn anything, will forget a week's worth of study in his best skill. - Das Dumpfbackenbrot ist eine sehr gemeine Sache, macht es doch jeden Lernerfolg zunichte oder läßt einen gar Dinge vergessen! Für zehn Portionen verknete man einen geriebenen Fjordwuchs, einen zerstoßenes Eulenauge und einen kleingeschnittenen Grünen Spinnerich zu einem geschmeidigen Teig. Diesen backe man eine Stunde lang bei guter Hitze und bestreiche das Ergebnis mit etwas Höhlenglimm. Wer dieses Brot gegessen hat, kann eine Woche lang nichts lernen, und so er nichts zu lernen versucht, wird er gar eine Woche seiner besten Fähigkeit vergessen. - - - A potion of nest warmth allows an insect to recruit outside of a desert region in winter. The learned alchemist prepares this by taking a peyote, mixing it with a portion of gapgrowth which has been gathered during a clear, starry night. To dispell winter, add some blossoms of the ice begonia in the mix, and stirr everything together with a spider ivy until it turns a nice shade of violet. One vial supplies an entire region for a whole week. - Nestwärme erlaubt es einem Insekt, im Winter außerhalb von Wüsten neue Rekruten anzuwerben. Zur Zubereitung nimmt der geübte Alchemist einen Kakteenschwitz, vermischt ihn mit einer Portion Spaltwachs, die in einer sternklaren Nacht gesammelt wurde, gibt zur Vertreibung des Winters einige Blütenblätter der Eisblume in den Sud, und rührt alles mit einem grünen Spinnerich bis es eine violette Farbe annimmt. Ein Trank reicht eine Woche lang für eine ganze Region. - - - To make a horsepower potion, chop a peyote, a cobalt fungus and some knotroot, and boil it in a bucketful of water. Then add some sand reeker and let the mixture steep for three days. Finally one gives this to the horses to drink, to double their procreation. - Für das Pferdeglück zerhacke man einen Kakteenschwitz, einen blauen Baumringel und etwas knotigen Saugwurz und koche das ganze mit einem Eimer Wasser auf. Dann füge man etwas Sandfäule dazu und lasse diesen Sud drei Tage lang ziehen. Letztlich gebe man es den Pferden zu trinken, auf daß sie sich doppelt so schnell vermehren. - - - The use of the berserkers blood potion is advised to increase one's warriors abilities to new heights. To create this, one needs a white hemlock, some flatroot, sand reeker and a mandrake. All ingredients have to be sliced as finely as possible, after which it is boiled for two hours. The cooled brew is strained through a cloth. The resulting juice is enough to improve up to ten warriors. - Will man seine Krieger zu Höchstleistungen antreiben, sei das Berserkerblut empfohlen. Um es herzustellen, braucht man einen Weißen Wüterich, etwas Flachwurz, Sandfäule und eine Alraune. Alle Zutaten müssen möglichst klein geschnitten und anschließend zwei Stunden lang gekocht werden. Den abgekühlten Brei gebe man in ein Tuch und presse ihn aus. Der so gewonnene Saft reicht aus, um zehn Kämpfer besser angreifen zu lassen. - - - The peasant love potion enamors both Man and Woman to the same degree and results in a strong wish for children. For a big portion scoop out a mandrake, fill it with finely chopped bubblemorel, elvendear and snowcrystal petal, sprinkle grated rock weed on top and let it simmer on low heat for twenty hours. The potion can grant up to 1000 peasants the happiness of twins. - Das Bauernlieb betört Mann und Frau gleichwohl und läßt in ihnen den Wunsch nach Kindern anwachsen. Für eine große Portion höhle man eine Alraune aus, gebe kleingehackten Blasenmorchel, Elfenlieb und Schneekristall dazu, streue ein wenig geriebenen Steinbeißer darüber und lasse dieses zwanzig Stunden lang auf kleiner Flamme kochen. Bis zu 1000 Bauern vermag der Trank das Glück von Zwillinge zu bescheren. - - - This simple but very potent brew sharpens the senses of anyone that drinks of it and makes him able to see through even the most complex illusions for one week. - Dieses wirkungsvolle einfache Gebräu schärft die Sinne des Trinkenden derart, daß er in der Lage ist, eine Woche lang auch die komplexesten Illusionen zu durchschauen. - - - One of the most rare and prized of all alchemist elixers, this potion grants the user a dragon's power for a few weeks. The potion increases the life-energy of a maximum of ten people fivefold. The effect is strongest right after drinking and slowly decreases over time. To brew this potion the alchemist needs an elvendear, a windbag, a piece of waterfinder and a spider ivy. Finally he dusts it with some minced bubblemorel and stirrs the powder into some dragon's blood. - Eines der seltensten und wertvollsten alchemistischen Elixiere, verleiht dieser Trank dem Anwender für einige Wochen die Kraft eines Drachen. Der Trank erhöht die Lebensenergie von maximal zehn Personen auf das fünffache. Die Wirkung ist direkt nach der Einnahme am stärksten und klingt danach langsam ab. Zur Herstellung benötigt der Alchemist ein Elfenlieb, einen Windbeutel, ein Stück Wasserfinder und einen Grünen Spinnerich. Über dieses Mischung streue er schließlich einen zerriebenen Blasenmorchel und rühre dieses Pulver unter etwas Drachenblut. - - - For a healing potion one takes the peel of a windbag and some bugleweed, stirr in some chopped elvendear and sprinkle it with the blossoms of an ice begonia. This has to cook through for four days, while a gapgrowth has to be added on the second day. Then one carefully scoops off the top layer of liquid. One such potion gives four men (or one man four times) a 50% chance to survive otherwise lethal wounds. The potion is automatically used in case of injury. - Für einen Heiltrank nehme man die Schale eines Windbeutels und etwas Gurgelkraut, rühre eine kleingehacktes Elfenlieb dazu und bestreue alles mit den Blüten einer Eisblume. Dies muß vier Tage lang gären, wobei man am zweiten Tag einen Spaltwachs dazutun muß. Dann ziehe man vorsichtig den oben schwimmenden Saft ab. Ein solcher Trank gibt vier Männern (oder einem Mann vier mal) im Kampf eine Chance von 50%, sonst tödliche Wunden zu überleben. Der Trank wird von ihnen automatisch bei Verletzung angewandt. - - - - - Erschaffe einen Ring der Macht - Create A Ring Of Power - - - Schild des Fisches - Shield Of The Fish - - - Runen des Schutzes - Protective Runes - - - Ruf der Realität - Call Of Reality - - - Astraler Ruf - Astral Call - - - Magiefresser - Destroy Magic - - - Mauern der Ewigkeit - Eternal Walls - - - Stehle Aura - Steal Aura - - - Schutzzauber - Resist Magic - - - Astraler Blick - Astral Gaze - - - Auratransfer - Transfer Aura - - - Monster friedlich stimmen - Calm Monster - - - Luftschiff - Airship - - - Lied der Verführung - Song Of Seduction - - - Schaler Wein - Hangover - - - Aushorchen - sound_out - - - Kriegsgesang - Song Of War - - - Gesang der Angst - Song Of Fear - - - Lied des Ortes analysieren - Analysis - - - Schockwelle - Shockwave - - - Fluch brechen - Negate Curse - - - Erschaffe ein Amulett der Keuschheit - Create An Amulet Of Chastity - - - Beschleunigung - Acceleration - - - Großer Drachenodem - Powerful Dragonbreath - - - Opfere Kraft - Sacrifice Strength - - - Belebtes Gestein - Living Rock - - - Gesang der Melancholie - Song of Melancholy - - - Gesang des wachen Geistes - Song Of The Youthful Spirit - - - Gesang des schwachen Geistes - Song Of The Aging Spirit - - - Gesang der Friedfertigkeit - Song Of Peace - - - Gesang der Versklavung - Song Of Slavery - - - Hohe Kunst der Überzeugung - Song Of Slavery - - - Zeitdehnung - Double Time - - - Vertrauten rufen - Summon Familiar - - - Rüstschild - Shield Shine - - - Wyrmtransformation - Wyrmtransformation - - - Schattenodem - Shadowbreath - - - Feuersturm - Firestorm - - - Feuerwalze - Immolation - - - Eisnebel - Coldfront - - - Säurenebel - Acid Rain - - - Furchteinflößende Aura - Panic - - - Meteorregen - Meteor Shower - - - Schattenruf - Shadow Call - - - Erschaffe einen Ring der Regeneration - Create A Ring Of Regeneration - - - Mob aufwiegeln - Mob Rule - - - Aufruhr beschwichtigen - Calm Riot - - - Aufruhr verursachen - Riot - - - Blick in die Realität - Gaze Upon Reality - - - Störe Astrale Integrität - Astral Disruption - - - Eisiger Drachenodem - Icy Dragonbreath - - - Eisiger Drachenodem - Icy Dragonbreath - - - Erschaffe ein Runenschwert - Create A Runesword - - - Erschaffe einen Beutel des Negativen Gewichts - Create A Bag Of Holding - - - Erschaffe einen Aurafocus - Create An Aurafocus - - - Erschaffe Antimagiekristall - Create An Antimagic Crystal - - - Astrale Schwächezone - Antimagic - - - Astraler Ausgang - Astral Exit - - - Astraler Weg - Astral Path - - - Beute Bewahren - Save Spoils - - - Schutz vor Magie - Protection from Magic - - - Wunderdoktor - Miracle Doctor - - - Schleieraura - Concealing Aura - - - Magie analysieren - Analyze Magic - - - Hohes Lied der Gaukelei - Song of Generosity - - - Gesang des Werbens - Song of Courting - - - Schleieraura - Veil - - - Lied der Heilung - Blessed Harvest - - - Gesang der Furcht - Song of Terror - - - Segen der Erde - Blessed Harvest - - - Heldengesang - Epic Heroes - - - Gesang des Lebens analysieren - Analyze Song of Life - - - Bannlied - Countersong - - - Gesang des Auratransfers - Hymn of Aura Sharing - - - Gesang der Verwirrung - Song of Confusion - - - Plappermaul - Blabbermouth - - - Regentanz - Rain Dance - - - Gaukeleien - Jugglery - - - Friedenslied - Appeasing Song - - - Viehheilung - Cattle Healing - - - Erschaffe Steingolems - Create Stone Golems - - - Erschaffe Eisengolems - Create Iron Golems - - - Hainzauber - Grove Of Oak Trees - - - Rostregen - Rain Of Rust - - - Firuns Fell - Firun's Coat - - - Hagel - Hail - - - Seelenkopie - Doppelganger - - - Irrlichter - Wisps - - - Schlechte Träume - Bad Dreams - - - Bergwächter - Mountain Guardian - - - Magischer Pfad - Magic Path - - - Tor in die Ebene der Hitze - Great Drought - - - Wurzeln der Magie - Roots Of Magic - - - Mahlstrom - Maelstrom - - - Windschild - Air Shield - - - Segne Mallornstecken - Bless Mallorn Logs - - - Beschwörung eines - Wasserelementares - Summon Water Elemental - - - Heilung - Heal - - - Wirbelwind - Whirlwind - - - Astralschutzgeister - Astral Guardian Spirits - - - Meditation - Meditate - - - Beschwöre einen Erdelementar - Summon Earth Elemental - - - Beschwöre einen Sturmelementar - Summon Storm Elemental - - - Erschaffe ein Amulett des wahren - Sehens - Create An Amulet Of True Sight - - - Erschaffe einen Ring der - Unsichtbarkeit - Create A Ring Of Invisibility - - - Miriams flinke Finger - Quick Fingers - - - Heimstein - Homestone - - - Wolfsgeheul - Timber Wolves - - - Blick des Basilisken - Gaze Of The Basilisk - - - Starkes Tor und feste Mauer - Strong Wall And Sturdy Gate - - - Geister bannen - Banish Spirits - - - Lebenslied festigen - Silence Dissonance - - - Ritual der Aufnahme - Rit of Acceptance - - - Weg der Bäume - Path Of Trees - - - Sog des Lebens - Ties Of Life - - - Heiliger Boden - Sacred Ground - - - Erschaffe einen magischen - Kräuterbeutel - Create A Magical Herb Pouch - - - Erwecke Ents - Awakening Of The Ents - - - Vertrauten binden - Bind Familiar - - - Segne Steinkreis - Bless Stone Circle - - - Rindenhaut - Barkskin - - - Verwünschung - Hex - - - Kleine Flüche - Minor Curses - - - Feuerball - Fireball - - - Gabe des Chaos - Chaos Gift - - - Kleines Blutopfer - Lesser Sacrifice - - - Blutrausch - Blood Frenzy - - - Chaosfluch - Chaos Curse - - - Mächte des Todes - Animate Dead - - - Rosthauch - Winds Of Rust - - - Machtübertragung - Transfer Power - - - Feuerwand - Wall Of Fire - - - Fluch der Pestilenz - Curse Of Pestilence - - - Wahnsinn des Krieges - Madness of War - - - Beschwöre Schattendämonen - Summon Shadowdemons - - - Beschwörung eines Hitzeelementar - Summon Fire Elemental - - - Untote Helden - Undead Heroes - - - Erschaffe einen Gürtel der - Trollstärke - Create A Belt Of Troll - Strength - - - Astraler Riss - Astral Leak - - - Astrales Chaos - Astral Chaos - - - Feuerteufel - Fire Fiend - - - Pentagramm - Pentagram - - - Unheilige Kraft - Unholy Strength - - - Todeswolke - Death Cloud - - - Drachenruf - Call Dragons - - - Beschwöre Schattenmeister - Summon Shadowmasters - - - Erschaffe ein Flammenschwert - Create A Flamesword - - - Vertrauten rufen - Call Familiar - - - Chaossog - Chaos Gate - - - Traumsenden - Dream - - - Wahrsagen - Divination - - - Schattenritter - Shadow Knights - - - Grauen der Schlacht - Unspeakable Horrors - - - Seelenfrieden - Eternal Rest - - - Traumschlößchen - Castle Of Illusion - - - Traum der Magie - Dream Of Magic - - - Gestaltwandlung - Shapeshift - - - Traumlesen - Read Dreams - - - Schwere Glieder - Tiredness - - - Wiederbelebung - Resurrection - - - Traumbilder analysieren - Analyse Dreams - - - Schlechter Schlaf - Insomnia - - - Schlaf - Sleep - - - Traumdeuten - Mind Probe - - - Alp - Nightmare - - - Erschaffe ein Traumauge - Create a Visioneye - - - Erschaffe eine Sphäre der Unsichtbarkeit - Create a Sphere of Invisbility - - - Schöne Träume - Pleasant Dreams - - - Traumbilder entwirren - Remove Dreams - - - Vertrauten rufen - Call Familiar - - - Tod des Geistes - Mental Death - - - Süße Träume - Sweet Dreams - - - Traum von den Göttern - Dream of the gods - - - Göttliches Netz - Web of the Gods - - - Kraft der Natur - force of nature - - - Gesang der Götter - Song of the Gods - - - Göttliche Macht - Power of the Gods - - - - - Tötet die Feinde mit Säure. - Kills enemies with acid. - - - Tötet die Feinde mit Kälte. - Kills enemies with cold. - - - Tötet die Feinde mit Feuer. - Kills enemies with fire. - - - Verletzt alle Gegner. - Injures all enemies. - - - Ruft Schattenwesen. - Calls beings from shadow. - - - Panik. - Panic. - - - Entzieht Talentstufen und macht Schaden wie Großer Odem. - - - Dieser Zauber bewirkt eine schwere Störung des Astralraums. Innerhalb eines astralen Radius von Stufe/5 Regionen werden alle Astralwesen, die dem Zauber nicht wiederstehen können, aus der astralen Ebene geschleudert. Der astrale Kontakt mit allen betroffenen Regionen ist für Stufe/3 Wochen gestört. - - - - Diese vor dem Kampf zu zaubernde Ritual gibt den eigenen Truppen - einen zusätzlichen Bonus auf ihre Rüstung. Jeder Treffer - reduziert die Kraft des Zaubers, so dass der Schild sich irgendwann - im Kampf auflösen wird. - - - - - Dieser Zauber beschleunigt einige Kämpfer auf der eigenen Seite - so, dass sie während des gesamten Kampfes in einer Kampfrunde zweimal - angreifen können. - - - - - Dieser Zauber vermag dem Gegner ein geringfügig versetztes Bild der - eigenen Truppen vorzuspiegeln, so wie der Fisch im Wasser auch nicht - dort ist wo er zu sein scheint. Von jedem Treffer kann so die Hälfte - des Schadens unschädlich abgeleitet werden. Doch hält der Schild nur - einige Hundert Schwerthiebe aus, danach wird er sich auflösen. - Je stärker der Magier, desto mehr Schaden hält der Schild aus. - - - - - Zeichnet man diese Runen auf die Wände eines Gebäudes oder auf die - Planken eines Schiffes, so wird es schwerer durch Zauber zu - beeinflussen sein. Jedes Ritual erhöht die Widerstandskraft des - Gebäudes oder Schiffes gegen Verzauberung um 20%. - Werden mehrere Schutzzauber übereinander gelegt, so addiert - sich ihre Wirkung, doch ein hundertprozentiger Schutz läßt sich so - nicht erreichen. Der Zauber hält mindestens drei Wochen an, je nach - Talent des Magiers aber auch viel länger. - - - - - Mit Hilfe dieses Zauber kann der Magier eigene Aura im Verhältnis - 2:1 auf einen anderen Magier des gleichen Magiegebietes oder im - Verhältnis 3:1 auf einen Magier eines anderen Magiegebietes - übertragen. - - - - - Der Magier kann kurzzeitig in die Astralebene blicken und erfährt - so alle Einheiten innerhalb eines astralen Radius von Stufe/5 Regionen. - - - - - Mit Hilfe dieses magischen Gesangs kann der Magier eine Region in - Aufruhr wieder beruhigen. Die Bauernhorden werden sich verlaufen - und wieder auf ihre Felder zurückkehren. - - - - Aus 'Wanderungen' von Firudin dem Weisen: - 'In Weilersweide, nahe dem Wytharhafen, liegt ein kleiner Gasthof, der - nur wenig besucht ist. Niemanden bekannt ist, das dieser Hof - bis vor einigen Jahren die Bleibe des verbannten Wanderpredigers Grauwolf - war. Nachdem er bei einer seiner berüchtigten flammenden Reden fast die - gesammte Bauernschaft angeworben hatte, wurde er wegen Aufruhr verurteilt - und verbannt. Nur zögerlich war er bereit mir das Geheimniss seiner - Überzeugungskraft zu lehren.' - - - - Dieser mächtige Bann raubt dem Opfer seinen freien Willen - und unterwirft sie den Befehlen des Barden. Für einige Zeit wird das Opfer - sich völlig von seinen eigenen Leuten abwenden und der Partei des Barden - zugehörig fühlen. - - - - - Dieser mächtige Bann verhindert jegliche Attacken. Niemand in der - ganzen Region ist fähig seine Waffe gegen irgendjemanden zu erheben. - Die Wirkung kann etliche Wochen andauern. - - - - - Dieses Lied, das in die magische Essenz der Region gewoben wird, - schwächt die natürliche Widerstandskraft gegen eine - Verzauberung einmalig um 15%. Nur die Verbündeten des Barden - (HELFE BEWACHE) sind gegen die Wirkung des Gesangs gefeit. - - - - - Mit diesem Gesang verbreitet der Barde eine melancholische, traurige - Stimmung unter den Bauern. Einige Wochen lang werden sie sich in ihre - Hütten zurückziehen und kein Silber in den Theatern und Tavernen lassen. - - - - - Dieses magische Lied wird, einmal mit Inbrunst gesungen, sich in der - Region fortpflanzen, von Mund zu Mund springen und eine Zeitlang - überall zu vernehmen sein. Nach wie vielen Wochen der Gesang aus dem - Gedächnis der Region entschwunden ist, ist von dem Geschick des Barden - abhängig. Bis das Lied ganz verklungen ist, wird seine Magie allen - Verbündeten des Barden (HELFE BEWACHE), und natürlich auch seinen - eigenem Volk, einen einmaligen Bonus von 15% - auf die natürliche Widerstandskraft gegen eine Verzauberung - verleihen. - - - - - Mit Hilfe dieses magischen Gesangs überzeugt der Magier die Bauern - der Region, sich ihm anzuschließen. Die Bauern werden ihre Heimat jedoch - nicht verlassen, und keine ihrer Besitztümer fortgeben. Jede Woche - werden zudem einige der Bauern den Bann abwerfen und auf ihre Felder - zurückkehren. Wie viele Bauern sich dem Magier anschließen hängt von der - Kraft seines Gesangs ab. - - - - - Einem erfahrenen Magier wird irgendwann auf seinen Wanderungen ein - ungewöhnliches Exemplar einer Gattung begegnen, welches sich dem - Magier anschließen wird. - - - - - Dieses Ritual ermöglicht es, eine Einheit, egal welcher Art, in die - eigene Partei aufzunehmen. Der um Aufnahme Bittende muss dazu willig - und bereit sein, seiner alten Partei abzuschwören. Dies bezeugt er - durch KONTAKTIEREn des Magiers. Auch wird er die Woche über - ausschliesslich mit Vorbereitungen auf das Ritual beschäftigt sein. - Das Ritual wird fehlschlagen, wenn er zu stark an seine alte Partei - gebunden ist, dieser etwa Dienst für seine teuere Ausbildung - schuldet. Der das Ritual leitende Magier muss für die permanente - Bindung des Aufnahmewilligen an seine Partei naturgemäß auch - permanente Aura aufwenden. Pro Stufe und pro 1 permanente Aura kann - er eine Person aufnehmen. - - - - - Jede Verzauberung beeinflußt das Lebenslied, schwächt und verzerrt es. - Der kundige Barde kann versuchen, das Lebenslied aufzufangen und zu - verstärken und die Veränderungen aus dem Lied zu tilgen. - - - - - Wie Lebewesen, so haben auch Schiffe und Gebäude und sogar Regionen - ihr eigenes Lied, wenn auch viel schwächer und schwerer zu hören. - Und so, wie wie aus dem Lebenslied einer Person erkannt werden kann, - ob diese unter einem Zauber steht, so ist dies auch bei Burgen, - Schiffen oder Regionen möglich. - - - - - Dieser Kriegsgesang sät Panik in der Front der Gegner und schwächt - so ihre Kampfkraft erheblich. Angst wird ihren Schwertarm schwächen - und Furcht ihren Schildarm lähmen. - - - - - Wie viele magischen Gesänge, so entstammt auch dieser den altem - Wissen der Katzen, die schon immer um die machtvolle Wirkung der - Stimme wussten. Mit diesem Lied wird die Stimmung der Krieger - aufgepeitscht, sie gar in wilde Raserrei und Blutrausch versetzt. - Ungeachtet eigener Schmerzen werden sie kämpfen bis zum - Tode und niemals fliehen. Während ihre Attacke verstärkt ist - achten sie kaum auf sich selbst. - - - - - Erliegt die Einheit dem Zauber, so wird sie dem Magier alles erzählen, - was sie über die gefragte Region weiß. Ist in der Region niemand - ihrer Partei, so weiß sie nichts zu berichten. Auch kann sie nur das - erzählen, was sie selber sehen könnte. - - - - - Aufzeichung des Vortrags von Selen Ard'Ragorn in Bar'Glingal: - 'Es heiss, dieser Spruch wäre wohl in den Spelunken der Westgassen - entstanden, doch es kann genausogut in jedem andern verrufenen - Viertel gewesen sein. Seine wichtigste Zutat ist etwa ein Fass - schlechtesten Weines, je billiger und ungesunder, desto - wirkungsvoller wird die Essenz. Die Kunst, diesen Wein in pure - Essenz zu destillieren, die weitaus anspruchsvoller als das einfache - Rezeptmischen eines Alchemisten ist, und diese dergestalt zu binden - und konservieren, das sie sich nicht gleich wieder verflüchtigt, wie - es ihre Natur wäre, ja, dies ist etwas, das nur ein Meister des - Cerddor vollbringen kann. Nun besitzt Ihr eine kleine Phiola mit - einer rubinrotschimmernden - nun, nicht flüssig, doch auch nicht - ganz Dunst - nennen wir es einfach nur Elixier. Doch nicht dies ist - die wahre Herausforderung, sodann muss, da sich ihre Wirkung leicht - verflüchtigt, diese innerhalb weniger Tage unbemerkt in das Getränk - des Opfers geträufelt werden. Ihr Meister der Betöhrung und - Verführung, hier nun könnt Ihr Eure ganze Kunst unter Beweis - stellen. Doch gebt Acht, nicht unbedacht selbst von dem Elixier zu - kosten, denn wer einmal gekostet hat, der kann vom Weine nicht mehr - lassen, und er säuft sicherlich eine volle Woche lang. Jedoch nicht - die Verführung zum Trunke ist die wahre Gefahr, die dem Elixier - innewohnt, sondern das der Trunkenheit so sicher ein gar - fürchterliches Leid des Kopfes folgen wird, wie der Tag auf die - Nacht folgt. Und er wird gar sicherlich von seiner besten Fähigkeit - einige Tage bis hin zu den Studien zweier Wochen vergessen haben. - Noch ein Wort der Warnung: Dieses ist sehr aufwendig, und so Ihr - noch weitere Zauber in der selben Woche wirken wollt, so werden sie Euch - schwerer fallen.' - - - - - Mit diesem Lied kann eine Einheit derartig betört werden, so dass - sie dem Barden den größten Teil ihres Bargelds und ihres Besitzes - schenkt. Sie behält jedoch immer soviel, wie sie zum Überleben - braucht. - - - - - Dieser einschmeichelnde Gesang kann fast jedes intelligente Monster - zähmen. Es wird von Angriffen auf den Magier absehen und auch seine - Begleiter nicht anrühren. Doch sollte man sich nicht täuschen, es - wird dennoch ein unberechenbares Wesen bleiben. - - - - - Dieser Zauber ermöglicht es dem Träumer, den Schlaf aller nichtaliierten - Einheiten (HELFE BEWACHE) in der Region so stark zu stören, das sie - vorübergehend einen Teil ihrer Erinnerungen verlieren. - - - - - Dieser mächtige Zauber kann einen Magier vor dem sicheren Tod - bewahren. Der Magier erschafft anhand einer kleinen Blutprobe einen - Klon von sich, und legt diesen in ein Bad aus Drachenblut und verdünntem - Wasser des Lebens. - Anschließend transferiert er in einem aufwändigen Ritual einen Teil - seiner Seele in den Klon. Stirbt der Magier, reist seine Seele in den - Klon und der erschaffene Körper dient nun dem Magier als neues Gefäß. - Es besteht allerdings eine geringer Wahrscheinlichkeit, dass die Seele - nach dem Tod zu schwach ist, das neue Gefäß zu erreichen. - - - - - Der Zauberer spricht eine Beschwörung über einen Teil der Region, - und in der Folgewoche entstehen dort Irrlichter. - Wer durch diese Nebel wandert, wird von Visionen geplagt und - in die Irre geleitet. - - - - - Dieses mächtige Ritual öffnet ein Tor in die Elementarebene der - Hitze. Eine grosse Dürre kommt über das Land. Bauern, Tiere und - Pflanzen der Region kämpfen um das nackte Überleben, aber eine - solche Dürre überlebt wohl nur die Hälfte aller Lebewesen. - Der Landstrich kann über Jahre hinaus von den Folgen einer - solchen Dürre betroffen sein. - - - - - Mit Hilfe dieses aufwändigen Rituals läßt der Druide einen Teil seiner Kraft - dauerhaft in den Boden und die Wälder der Region fliessen. Dadurch wird - das Gleichgewicht der Natur in der Region für immer verändert, und in - Zukunft werden nur noch die anspruchsvollen, aber kräftigen - Mallorngewächse in der Region gedeihen. - - - - - Dieses Ritual beschört einen großen Wasserelementar aus den - Tiefen des Ozeans. Der Elementar erzeugt einen gewaltigen - Strudel, einen Mahlstrom, welcher alle Schiffe, die ihn passieren, - schwer beschädigen kann. - - - - - Mit Hilfe dieses Zaubers kann sich der Magier permanent in einen - mächtigen Wyrm verwandeln. Der Magier behält seine Talente und - Möglichkeiten, bekommt jedoch die Kampf- und Bewegungseigenschaften - eines Wyrms. Der Odem des Wyrms wird sich mit steigendem Magie-Talent - verbessern. Der Zauber ist sehr kraftraubend und der Wyrm wird einige - Zeit brauchen, um sich zu erholen. - - - - - Mit Hilfe dieses magischen Gesangs versetzt der Magier eine ganze - Region in Aufruhr. Rebellierende Bauernhorden machen jedes Besteuern - unmöglich, kaum jemand wird mehr für Gaukeleien Geld spenden und - es können keine neuen Leute angeworben werden. Nach einigen Wochen - beruhigt sich der Mob wieder. - - - - - Der Magier kann mit Hilfe dieses Zaubers aus der Astral- in die - materielle Ebene blicken und die Regionen und Einheiten genau - erkennen. - - - - - Einem erfahrenen Magier wird irgendwann auf seinen Wanderungen ein - ungewöhnliches Exemplar einer Gattung begegnen, welches sich dem - Magier anschließen wird. - - - - - Dieses kräftezehrende Ritual beschwört mit Hilfe einer Kugel aus - konzentriertem Laen einen gewaltigen Erdelementar und bannt ihn - in ein Gebäude. Dem Elementar kann dann befohlen werden, das - Gebäude mitsamt aller Bewohner in eine Nachbarregion zu tragen. - Die Stärke des beschworenen Elementars hängt vom Talent des - Magiers ab: Der Elementar kann maximal [Stufe-12]*250 Größeneinheiten - große Gebäude versetzen. Das Gebäude wird diese Prozedur nicht - unbeschädigt überstehen. - - - - Dieses Amulett in Gestalt einer orkischen Matrone - unterdrückt den Fortpflanzungstrieb eines einzelnen Orks sehr - zuverlässig. - Ein Ork mit Amulett der Keuschheit wird sich nicht mehr vermehren. - - - Dieser Zauber ermöglicht dem Magier, gezielt eine - bestimmte Verzauberung einer Einheit, eines Schiffes, Gebäudes oder auch - der Region aufzulösen. - This spell allows a magician to remove a specific - enchantment from a unit, ship, bulding or region. - - - Ein Schauer von Meteoren regnet über das Schlachtfeld. - A meteor shower rains down on the battlefield. - - - 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. - 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. - - - Mit dieser Formel bindet der Magier auf ewig die - Kräfte - der Erde in die Mauern des Gebäudes. Ein solchermaßen verzaubertes - Gebäude - ist gegen den Zahn der Zeit geschützt und benötigt keinen Unterhalt - mehr. - With this spell, the magician binds the power of the - earth into the walls of a building for all eternity. Such a building is - immune to the sands of time and needs no maintenance cost. - - - Ein Magier, der sich in der astralen Ebene befindet, - kann mit Hilfe dieses Zaubers andere Einheiten zu sich holen. Der Magier - kann (Stufe-3)*15 GE durch das kurzzeitig entstehende Tor schicken. Ist - der Magier erfahren genug, den Zauber auf Stufen von 13 oder mehr zu - zaubern, kann er andere Einheiten auch gegen ihren Willen auf die - andere - Ebene zwingen. - A magician in the astral plane can summon units from - the - material world. The magician can bring (level-3)*15 GE through the - temporary portal. If he is experienced enough to cast the spell at at - least level 13, he can even summon units against their will. - - - Ein Magier, welcher sich in der materiellen Welt - befindet, kann er mit Hilfe dieses Zaubers Einheiten aus der - angrenzenden - Astralwelt herbeiholen. Ist der Magier erfahren genug, den Zauber auf - Stufen von 13 oder mehr zu zaubern, kann er andere Einheiten auch gegen - ihren Willen in die materielle Welt zwingen. - A magician in the material world can summon units from - the adjacent part of the astral plane. If he is experienced enough to - cast - the spell at at least level 13, he can even summon units against their - will. - - - Mit Hilfe dieses Zaubers kann der Magier einem anderen - Magier seine Aura gegen dessen Willen entziehen und sich selber - zuführen. - Aided by this spell, a magician can steal another - magician's aura against his will. - - - Diese magischen Runen bringen ein Boot oder Langboot - für - eine Woche zum fliegen. Damit kann dann auch Land überquert werden. Die - Zuladung von Langbooten ist unter der Einwirkung dieses Zaubers auf 100 - Gewichtseinheiten begrenzt. Für die Farbe der Runen muss eine spezielle - Tinte aus einem Windbeutel und einem Schneekristall angerührt werden. - These magic runes allow a boat or longboat to fly for - a - week. The boat can only carry 100 weight units. The enchanted ink's - components include a windbag and a snowcrystal petal. - - - Diese praktische Anwendung des theoretischen Wissens um - Raum und Zeit ermöglicht es, den Zeitfluß für einige Personen zu - verändern. Auf diese Weise veränderte Personen bekommen für einige - Wochen doppelt soviele Bewegungspunkte und doppelt soviele Angriffe - pro Runde. - Abstract theories of space and time at last find - practical application in this spell which warps the very fabric of - time around a person. Such a person has twice as many movement points - and doubles their attacks per round for a few weeks. - - - Dieser Zauber läßt eine Welle aus purer Kraft über die - gegnerischen Reihen hinwegfegen. Viele Kämpfer wird der Schock so - benommen machen, daß sie für einen kurzen Moment nicht angreifen - können. - A wave of pure force spreads out from the magician, - crashing into the enemy ranks. Many warriors are thrown off balance and - are briefly unable to attack. - - - Mit diesem Zauber kann der Magier eine Zone der - astralen - Schwächung erzeugen, ein lokales Ungleichgewicht im Astralen Feld. - Dieses - Zone wird bestrebt sein, wieder in den Gleichgewichtszustand zu - gelangen. - Dazu wird sie jedem in dieser Region gesprochenen Zauber einen Teil - seiner Stärke entziehen, die schwächeren gar ganz absorbieren. - This spell allows a magician to create a local - instability in the astral field. This zone needs to return to its - equilibrium, soaking up part of the power of all spells cast in the - region - - or even all of some of the weaker ones. - - - Dieser Zauber ermöglicht dem Magier, Verzauberungen - einer Einheit, eines Schiffes, Gebäudes oder auch der Region aufzulösen. - This spell lets a magician destroy spells on a ship, - building or region. - - - Dieser Zauber verstärkt die natürliche - Widerstandskraft - gegen Magie. Eine so geschützte Einheit ist auch gegen Kampfmagie - weniger - empfindlich. Pro Stufe reicht die Kraft des Magiers aus, um 5 Personen - zu - schützen. - This spell enhances natural magic resistence. - Protected - units are less vulnerable to battle magic. The spell protects 5 people - per - level. - - - Alte arkane Formeln ermöglichen es dem Magier, sich - und - andere in die astrale Ebene zu schicken. Der Magier kann (Stufe-3)*15 GE - durch das kurzzeitig entstehende Tor schicken. Ist der Magier erfahren - genug, den Zauber auf Stufen von 11 oder mehr zu zaubern, kann er andere - Einheiten auch gegen ihren Willen auf die andere Ebene zwingen. - Ancient arcane formulae permit the magician to - transport - himself or other units into the astral plane. The magician can transport - (level-3) * 15 GE through the transient portal. If the magician is - experienced enough to cast level 11 spells, he can also transport units - against their will. - - - Der Magier konzentriert sich auf die Struktur der - Realität und kann so die astrale Ebene verlassen. Er kann insgesamt - (Stufe-3)*15 GE durch das kurzzeitig entstehende Tor schicken. Ist der - Magier erfahren genug, den Zauber auf Stufen von 11 oder mehr zu - zaubern, - kann er andere Einheiten auch gegen ihren Willen auf die andere Ebene - zwingen. - By concentrating on the structure of reality, the - magician can breach it and thus briefly make a gateway to leave the - astral - plane. He can transport up to (level-3)*15 GE through the portal. If the - magician is able to cast at at least level 11, he can even transport - other - units against their will. - - - Mit diesem Spruch kann der Magier versuchen, die - Verzauberungen - eines einzelnen angegebenen Objekts zu erkennen. Von - allen Sprüchen, - die seine eigenen Fähigkeiten nicht überschreiten, wird - er einen - Eindruck ihres Wirkens erhalten können. Bei stärkeren - Sprüchen - benötigt er ein wenig Glück für eine gelungene Analyse. - With this spell the magician can try to identify the - enchantments of - a single object. He will get an impression of the - operation of all - spells that don't exceed his own capabilities. For more - powerful - spells he will need some luck for a successful analysis. - - - Dieser Zauber wird die gesamte Ausrüstung der - Zieleinheit für - einige Zeit vor den Blicken anderer verschleiern. Der - Zauber - schützt nicht vor Dieben und Spionen. - This spell will hide the whole equipment of a target - unit from the - looks of others. It will not protect against thieves or - spies. - - - Dieser Zauber legt ein antimagisches Feld um die Magier der Feinde - und behindert ihre Zauber erheblich. Nur wenige werden die Kraft - besitzen, das Feld zu durchdringen und ihren Truppen in der Schlacht - zu helfen. - This spell creates an antimagic field around the mages of the enemies - and considerably hinders their spells. Only few will have the power to - break through the field and be able to help their troops in battle. - - - Dieser Zauber verhindert, dass ein Teil der sonst im Kampf zerstörten - Gegenstände beschädigt wird. Die Verluste reduzieren sich um 5% pro - Stufe des Zaubers bis zu einem Minimum von 25%. - This spell prevents damage to a portion of the items that would - otherwise be lost in battle. The loss of items is reduced by 5% for - every level of the spell, up to a minimum of 25%. - - - - Dieses Lied zähmt selbst den wildesten - Ork und macht ihn friedfertig und sanftmütig. Jeder - Gedanke, dem Sänger zu schaden, wird ihm entfallen. - Unbehelligt kann der Magier in eine Nachbarregion - ziehen. - This little melody calms even the - wildest orc to a gentle and serene creature who will not - even think about putting the singer to harm. The magician - may travel to a neighboring region without being - harassed by annoying troublemakers. - - - Nicht nur der Feldscher kann den - Verwundeten einer Schlacht helfen. Die Barden kennen - verschiedene Lieder, die die Selbstheilungskräfte des - Körpers unterstützen. Dieses Lied vermag Wunden zu - schließen, gebrochene Knochen zu richten und selbst - abgetrennte Glieder wieder zu regenerieren. - The field medic isn't the only one - capable of tending the wounds of battle. The bards know - a number of magic melodies to enhance the natural - healing process of the body. This song is able to close - wounds, mend fractured bones and even regenerate lost - lims. - - - Ein gar machtvoller Gesang aus den - Überlieferungen der Katzen, der tief in die Herzen der - Feinde dringt und ihnen Mut und Hoffnung raubt. Furcht - wird sie zittern lassen und Panik ihre Gedanken - beherrschen. Voller Angst werden sie versuchen, den - gräßlichen Gesängen zu entrinnen und fliehen. - This antique, powerful song, passed - down by the cats, will penetrate the hearts of the enemy - and bereave them of courage and hope. Both their minds - and bodies will be ruled by panic. Shivering with fear, - they will flee from the dreadful chants and try to make - their escape. - - - Aus den uralten Gesängen der Katzen - entstammt dieses magisches Lied, welches vor einem - Kampfe eingesetzt, einem entscheidende strategische - Vorteile bringen kann. Wer unter den Einfluss dieses - Gesangs gelangt, der wird seiner Umgebung nicht achtend - der Melodie folgen, sein Geist wird verwirrt und - sprunghaft plötzlichen Eingebungen nachgeben. So sollen - schon einst wohlgeordnete Heere plötzlich ihre Schützen - weit vorne und ihre Kavallerie bei den Lagerwachen - kartenspielend wiedergefunden haben (oder ihren Anführer - schlafend im lange verlassenen Lager, wie es in den - Großen Kriegen der Alten Welt wirklich geschehen sein - soll). - If is used before battle, this chant, - taken from the ancient tunes of the cats, might give you - the critical tactical advantage. Those under the spell's - influence will act uncoordinated and inconsequent due to - the nonsensical ideas planted into their minds through - the melody. So it is supposed to have come to pass that - well-organized armies found their archers up at the - front (while the cavalry was back at the camp playing - cards) or that even a famous general overslept a battle - in his tent, as tale-tellers claim it really happened - during the Great Wars in the Old World. - - - Dieser alte Schlachtengesang hebt die - Moral der eigenen Truppen und und hilft ihnen auch der - angsteinflößenden Aura dämonischer und untoter Wesen zu - widerstehen. Ein derartig gefestigter Krieger wird auch - in schwierigen Situationen nicht die Flucht ergreifen - und sein überlegtes Verhalten wird ihm manch Vorteil in - der Verteidigung geben. - This ancient battle chant lifts the - spirit of your troops and helps them withstand even the - fear-inspiring aura of demonic and undead beings. A - fighter thus fortified against evil will not flee even - in the face of terror, and his defenses will be strengthened. - - - Mit Hilfe dieses Zaubers kann der - Magier eigene Aura im Verhältnis 2:1 auf einen anderen - Magier des gleichen Magiegebietes übertragen. - This spell enables the wizard to - transfer aura at a rate of 2:1 to another sorcerer of - the same school of magic. - - - Alle lebenden Wesen haben ein eigenes - individuelles Lebenslied. Nicht zwei Lieder gleichen - sich, auch wenn sich alle Lieder einer Art ähneln. Jeder - Zauber verändert dieses Lied auf die eine oder andere - Art und gibt sich damit zu erkennen. Dieser Gesang - hilft, jene Veränderungen im Lebenslied einer Person zu - erlauschen, welche magischer Natur sind. Alle - Verzauberungen, die nicht stärker maskiert sind als Eure - Fähigkeit, werdet Ihr so entschlüsseln und demaskieren - können. - Each and every living being has its - own, individual 'life-song'. No two of these songs are - alike, even though songs of creatures of the same - species are similar. Every spell alters this song of - life in one way or the other and this can be identified. - By casting this spell, the bard can detect all those - magic variations in a person's 'life-song'. You will be - able to decipher all enchantments or spells, which - aren't disguised beyond your capability. - - - Dieser schrille Gesang hallt über das - ganze Schlachtfeld. Die besonderen Dissonanzen in den - Melodien machen es Magier fast unmöglich, sich auf ihre - Zauber zu konzentrieren. - The screeching sounds of this melody - can be heard across the whole battlefield. Wizards - exposed to these special dissonances find it nearly - impossible to concentrate on their spells. - - - Die verzauberte Einheit beginnt - hemmungslos zu plappern und erzählt welche Talente sie - kann, was für Gegenstände sie mit sich führt und sollte - sie magisch begabt sein, sogar welche Zauber sie - beherrscht. Leider beeinflußt dieser Zauber nicht das - Gedächnis, und so wird sie sich im nachhinein wohl - bewußt werden, dass sie zuviel erzählt hat. - The persons of the bewitched unit - starts to babble without control about what it is said, - speaking about their talents, the objects they carry or - wear and if the unit is a magician, he or she will even list - the spells they know. Unfortunately, this spell does not - influence the memory of the subjects and afterwards, the - enchanted will realize that they probably talked too - much. - - - Man befeuchte einen kluftfreien Block - aus feinkristallinen Gestein mit einer Phiole des - Lebenswassers bis dieses vollständig vom Gestein - aufgesogen wurde. Sodann richte man seine Kraft auf die - sich bildende feine Aura des Lebens und forme der - ungebundenen Kraft ein Gehäuse. Je mehr Kraft der Magier - investiert, desto mehr Golems können geschaffen werden, - bevor die Aura sich verflüchtigt. Jeder Golem hat jede - Runde eine Chance von 10 Prozent zu Staub zu zerfallen. - Gibt man den Golems die Befehle MACHE BURG oder MACHE - STRASSE, so werden pro Golem 4 Steine verbaut und der - Golem löst sich auf. - 'Take a flawless block of crystaline - stone and humidify it with a vial of Water Of Life until - the potion has been soaked up completely. Then focus - your power on the forming aura of life and shape a - container for the unbound forces'. The more power a magician - invests, the more golems can be created before the aura - dissipates. Every week, there is a 10 percent chance - that the golem will crumble to dust. If you command a - golem to 'MAKE CASTLE' or 'MAKE ROAD', it will turn - itself into 4 stones that it uses in construction, and - disintegrate afterwards. - - - Je mehr Kraft der Magier investiert, - desto mehr Golems können geschaffen werden. Jeder Golem - hat jede Runde eine Chance von 15 Prozent zu Staub zu - zerfallen. Gibt man den Golems den Befehl MACHE - SCHWERT/BIHÄNDER oder MACHE - SCHILD/KETTENHEMD/PLATTENPANZER, so werden pro Golem 4 - Eisenbarren verbaut und der Golem löst sich auf. - The more power a magician invests, the - more golems can be created before the aura dissipates. - Each golem has a 15% chance per week to turn to dust. If - you command a golem to 'MAKE SWORD/MAKE CLAYMORE' or - 'MAKE SHIELD/CHAINMAIL/PLATEMAIL',it will work 5 iron - ingots and disintegrate afterwards. - - - Wo sonst aus einem - Stecken nur ein Baum sprießen konnte, so treibt nun jeder - Ast Wurzeln. - Every branch becomes a sturdy - oak where before only one could be grown from a log. - - - Mit diesem Ritual wird eine dunkle - Gewitterfront beschworen, die sich - unheilverkündend über der Region auftürmt. Der - magische Regen wird alles Erz rosten lassen. - Eisenwaffen und Rüstungen werden schartig und rostig. - Die Zerstörungskraft des - Regens ist von der investierten Kraft des - Magiers abhängig. Für jede Stufe können bis zu - 10 Eisenwaffen betroffen werden. Ein Ring der - Macht verstärkt die Wirkung wie eine zusätzliche - Stufe. - This ritual conjurs up a dark - thunderstorm that affects a whole region. The - magic rain will let rust any ore. Iron weapons and - armor will get rusty. The exact number of - items affected by the rain depends on the - ammount of power invested by the magician. Up to ten - weapons can be destroyed per level - a Ring Of - Power increases the effect like an additional - level. - - - Dieser Zauber ermöglicht es dem Magier - Insekten auf magische Weise vor der lähmenden - Kälte der Gletscher zu bewahren. Sie können - Gletscher betreten und dort normal agieren. Der - Spruch wirkt auf Stufe*10 Insekten. Ein Ring der - Macht erhöht die Menge der verzauberbaren - Insekten zusätzlich um 10. - This spell enables the druid to - magically protect insects from the paralysing - cold of a glacier. Under the effect of this - spell, insects are able to enter glaciers and - act normally there. Ten insects per level can be - protected in this way. A Ring Of Power increases - the number by additional ten. - - - Im Kampf ruft der Magier die - Elementargeister der Kälte an und bindet sie an - sich. Sodann kann er ihnen befehlen, den Gegner - mit Hagelkörnern und Eisbrocken zuzusetzen. - During a battle the druid calls the - Elemental Spirits Of Cold and binds them to - himself. Then he commands them to attack his - foes with hail and ice missiles. - - - Erschafft einen Wächtergeist, der - in Gletschern und Bergen Eisen- und Laenabbau durch - nichtalliierte Parteien (HELFE BEWACHE) verhindert, - solange er die Region bewacht. Der Bergwächter ist - an den Ort der Beschwörung gebunden. - Creates a guardian spirit on a - mountain or glacier that keeps all factions that - are not allied (HELP GUARD) from mining iron or - laen as long as it guards the region. The - Mountain Guardian is bound to the location where - it has been summoned. - - - Durch Ausführung dieser Rituale ist - der Magier in der Lage einen mächtigen - Erdelementar zu beschwören. Solange dieser in - den Boden gebannt ist, wird kein Regen die Wege - aufweichen und kein Fluß Brücken zerstören - können. Alle Reisende erhalten damit die - gleichen Vorteile, die sonst nur ein ausgebautes - gepflastertes Straßennetz bietet. Selbst Sümpfe - und Gletscher können so verzaubert werden. Je - mehr Kraft der Magier in den Bann legt, desto - länger bleibt die Straße bestehen. - By performing these rituals the druid - is able to summon a powerful earth elemental. As - long as this elemental remains bound to a - region, no rain can turn a path into mud and no - river can destroy a bridge. All travelers in - this region gain the same advantages as if they - were travelling on a road. Even swamps and - glaciers can be enchanted in this way. The more - power the druid invests, the longer the roads - remain intact. - - - Die Anrufung der Elementargeister des - Windes beschwört plötzliche Windböen, kleine - Windhosen und Luftlöcher herauf, die die - gegnerischen Schützen behindern werden. - Calling the Elemental Spirits Of Wind - conjurs up sudden breezes, small whirlwinds and - minor turbulences that will hinder enemy - archers. - - - Diese Ritual verstärkt die Wirkung des - magischen Trankes um ein vielfaches. Wo sonst aus einem - Stecken nur ein Baum sprießen konnte, so treibt nun jeder - Ast Wurzeln. - This ritual greatly increases the - effect of the potion. Now every branch becomes a mallorn - tree where before only one could be grown from a log. - - - Der Magier zwingt mit diesem Ritual - die Elementargeister des Wassers in seinen - Dienst und bringt sie dazu, das angegebene - Schiff schneller durch das Wasser zu tragen. - Zudem wird das Schiff nicht durch ungünstige - Winde oder Strömungen beeinträchtigt. - While being aboard a ship, the druid - uses this ritual to force the Elemental Spirits - Of Water to serve him and commands them to carry - the ship across the water at a higher speed. In - addition, the ship will not be affected by - unfavourable winds or currents. - - - Nicht nur der Feldscher kann den - Verwundeten einer Schlacht helfen. Druiden - vermögen mittels einer Beschwörung der - Elementargeister des Lebens Wunden zu schließen, - gebrochene Knochen zu richten und selbst - abgetrennte Glieder wieder zu regenerieren. - Combat medics are not the only ones - who can help those who got injured during a - battle. Druids are, with the help of a summons - of - the Elemental Spirits Of Life, able to heal - wounds, mend broken bones or even regenerate - separated limbs as well. - - - Diese Beschwörung öffnet ein Tor in - die Ebene der Elementargeister des Windes. - Sofort erheben sich in der Umgebung des Tors - starke Winde oder gar Stürme und behindern alle - Schützen einer Schlacht. - This summons opens a gate to the plane - of Elemental Spirits Of Wind. Immediately, - strong winds or even storms will rise near the - gate and hinder all archers during a battle. - - - Dieses Ritual beschwört einige - Elementargeister der Magie und schickt sie in - die Reihen der feindlichen Magier. Diesen wird - das Zaubern für die Dauer des Kampfes deutlich - schwerer fallen. - This ritual summons some Elemental - Spirits Of Magic and sends them into the ranks - of the enemy mages. Casting spells will be much - harder for them during the battle. - - - Mit Hilfe dieses Zaubers kann der - Magier eigene Aura im Verhältnis 2:1 auf einen - anderen Magier des gleichen Magiegebietes - übertragen. - The caster can transfer aura at a - ratio of 2:1 to another member of the same - school of magic with the help of this spell. - - - Der Druide beschwört mit diesem Ritual - einen Elementargeist der Erde und bringt ihn - dazu, die Erde erbeben zu lassen. Dieses - Erdbeben wird alle Gebäude in der Region - beschädigen. - With this ritual the druid summons an - Elemental Spirit Of Earth that brings the ground - to shake. This earthquake damages all buildings - in the target region. - - - Die Beschwörung von Elementargeistern - der Stürme ist ein uraltes Ritual. Der Druide - bannt die Elementare in die Segel der Schiffe, - wo sie helfen, das Schiff mit hoher - Geschwindigkeit über die Wellen zu tragen. Je - mehr Kraft der Druide in den Zauber investiert, - desto größer ist die Zahl der Elementargeister, - die sich bannen lassen. Für jedes Schiff wird - ein Elementargeist benötigt. - Calling the Elemental Spirits Of Storm - is an ancient ritual. The druid binds the - elementals to a ship's sails where they can help - to carry the vessel across the waves at an - amazing speed. The more power the druid invests, - the greater is the number of spirits bound. Each - ship needs an own spirit. - - - Mit diesem Spruch erzeugt man ein Runenschwert. Die - Klinge des schwarzen Schwertes ist mit alten, magischen Runen verziert, - und ein seltsames Eigenleben erfüllt die warme Klinge. Um es zu - benutzen, - muss man ein Schwertkämpfer von beachtlichem Talent (7) sein. Der - Träger - des Runenschwertes erhält einen Talentbonus von +4 im Kampf und wird so - gut wie immun gegen alle Formen von Magie. - This spell creates a magical sword. It requires a - skill - of at least 7, but adds +4 to the combat skill of its' owner as well as - making them almost immune against magical attacks. - - - Dieser Beutel umschließt eine kleine Dimensionsfalte, - in - der bis zu 200 Gewichtseinheiten transportiert werden können, ohne dass - sie auf das Traggewicht angerechnet werden. Pferde und andere Lebewesen - sowie besonders sperrige Dinge (Wagen und Katapulte) können nicht in dem - Beutel transportiert werden. Auch ist es nicht möglich, einen - Zauberbeutel in einem anderen zu transportieren. Der Beutel selber wiegt - 1 - GE. - This bag encloses a dimensional rift in which up to - 200 - units of weight can be carries. Horses and other large objects cannot be - put into the bag. The bag itself has a weight of 1. - - - Dieses mächtige Ritual erschafft einen Ring der Macht. - Ein Ring der Macht erhöht die Stärke jedes Zaubers, den sein Träger - zaubert, als wäre der Magier eine Stufe besser. - A ring of power adds +1 to the power of each spell - cast - by its' wearer. - - - Der Spruch ermöglicht es einem Magier, - ein Amulett des Wahren Sehens zu erschaffen. Das - Amulett erlaubt es dem Träger, alle Einheiten, - die durch einen Ring der Unsichtbarkeit - geschützt sind, zu sehen. Einheiten allerdings, - die sich mit ihrem Tarnungs-Talent verstecken, - bleiben weiterhin unentdeckt. - This spell enables the caster to - create an Amulet Of True Sight. Wearing such an - amulet, a person can discover anyone wearing a - Ring of Invisibility. Anyway, units concealed by - the use of their stealth skill will remain - undiscovered. - - - Mit Hilfe dieses Zauber entzieht der Magier einem - Quarzkristall all seine magischen Energien. Der Kristall wird dann, wenn - er zu feinem Staub zermahlen und verteilt wird, die beim Zaubern - freigesetzten magischen Energien aufsaugen und die Kraft aller Zauber - reduzieren, welche in der betreffenden Woche in der Region gezaubert - werden. - This spell creates a portable crystal of antimagic - which can be used by anybody to reduce or even eliminate the power of - all spells cast in the region during the same week. - - - Die berühmte Bardin Miriam bhean'Meddaf war bekannt - für ihr außergewöhnliches Geschick mit der Harfe. Ihre Finger sollen - sich so schnell über die Saiten bewegt haben, das sie nicht mehr - erkennbar waren. Dieser Zauber, der recht einfach in einen Silberring - zu bannen ist, bewirkt eine um das zehnfache verbesserte - Geschicklichkeit und Gewandheit der Finger. (Das soll sie auch an - anderer Stelle ausgenutzt haben, ihr Ruf als Falschspielerin war - berüchtigt). Handwerker können somit das zehnfache produzieren, - und bei einigen anderen Tätigkeiten könnte dies ebenfalls von Nutzen - sein. - The famous bard Mirim was known for exceptionally - limber - play of the harp. Her spell, which is easy to ban into a little silver - ring, increases the wearer's dexterity by a factor of ten, which is siad - to be useful to both craftsmen and shady natures. - - - Mit diesem Spruch kann der Zauberer - einen Ring der Unsichtbarkeit erschaffen. Der - Träger des Ringes wird für alle Einheiten - anderer Parteien unsichtbar, egal wie gut ihre - Wahrnehmung auch sein mag. In einer unsichtbaren - Einheit muss jede Person einen Ring tragen. - With this spell the caster can create - a Ring Of Invisibility. The wearer of this ring - will be invisible to all units of other - factions, no matter how good their perception - skill may be. In an invisible unit, each person - must wear a Ring Of Invisibility. - - - Mit dieser Formel bindet der Magier - auf ewig die Kräfte der Erde in die Mauern der - Burg, in der er sich gerade befindet. Weder - magisch noch mit schwerem Geschütz können - derartig gestärkte Mauern zerstört werden, und - auch das Alter setzt ihnen weniger zu. Das - Gebäude bietet sodann auch einen besseren Schutz - gegen Angriffe mit dem Schwert wie mit Magie. - With this spell the druid eternally - binds the powers of earth to the walls of the - castle in which he currently is. No magic and no - ballistic attacks will ever be able to destroy a - wall that has been fortified in this way and the - castle will also be less affected by aging. In - addition, the building will provide a better - protection against attacks by sword or by magic. - - - Nicht wenige Druiden freunden sich im - Laufe ihres Lebens in der Natur mit den ältesten - Freunden der großen Völker an. Sie erlernen, mit - einem einzigen heulenden Ruf viele ihrer Freunde - herbeizurufen, um ihnen im Kampf beizustehen. - During their life in the wilderness, - many druids make friends with the wolves who are - the oldest friends of the great races. They - learn to call many of them with a single howl to - aid them in combat. - - - Dieser schwierige, aber effektive - Kampfzauber benutzt die Elementargeister des - Steins, um eine Reihe von Gegnern für die Dauer - des Kampfes in Stein zu verwandeln. Die - betroffenen Personen werden nicht mehr kämpfen, - können jedoch auch nicht verwundet werden. - This complicated but effective spell - uses the Elemental Spirits Of Stone to turn a - number of enemies to stone for the duration of - combat. The affected persons won't be able to - fight any more, but they can't be wounded - either. - - - Mit dieser Formel bindet der Magier zu - Beginn eines Kampfes einige Elementargeister des - Fels in die Mauern des Gebäudes, in dem er sich - gerade befindet. Das Gebäude bietet sodann einen - besseren Schutz gegen Angriffe mit dem Schwert - wie mit Magie. - At the beginning of a battle, the - magician binds some Elemental Spirits Of Rock to - the walls of the builing in which he currently - is. The structure will then provide a better - protection against attacks by sword or by magic. - - - Wie die alten Lehren der Druiden - berichten, besteht das, was die normalen Wesen - Magie nennen, aus Elementargeistern. Der Magier - beschwört und bannt diese in eine Form, um den - gewünschten Effekt zu erzielen. Dieses Ritual - nun vermag es, in diese Welt gerufene - Elementargeister zu vertreiben, um so ein Objekt - von Magie zu befreien. - Old legends of the druids say that - what normal people call 'magic' consists of - elemental spirits. A magician summons these - spirits and binds them to various forms to - achieve the desired effects. This ritual is able - to expel any elemental spirits that have been - summoned to this world and thereby dispels any - magic on the target. - - - Große Macht liegt in Orten, an denen - das Leben pulsiert. Der Druide kann diese Kraft - sammeln und so ein Tor in die Welt der - Geistwesen erschaffen. Der Druide kann dann - Stufe*5 Gewichtseinheiten durch das Tor - entsenden. - A great power lies within those places - that are pulsing with life. A druid can focus - this power and thereby create a gate into the - World Of Spirits. He can then send level*5 - weight units of living or dead matter through - the gate. - - - Ein Druide, den es in die Welt der - Geister verschlagen hat, kann mit Hilfe dieses - Zaubers Stufe*5 Gewichtseinheiten in einen Wald - auf der materiellen Welt zurückschicken. - A druid who has traveled to the World - Of Spirits can use this spell to send level*5 - weight units of living or dead matter back to a - forest in the material world. - - - Dieses Ritual beschwört verschiedene - Naturgeister in den Boden der Region, welche - diese fortan bewachen. In einer so gesegneten - Region werden niemals wieder die Toten ihre - Gräber verlassen, und anderswo entstandene - Untote werden sie wann immer möglich meiden. - This ritual binds various rural - spirits to a specific territory to guard the - land. In a region blessed in this way the dead - won't ever rise from their graves again. - Existing undead also shun the sacred grounds and - will avoid entering the protected area whenever - possible. - - - Der Druide nehme etwas präpariertes - Leder, welches er in einem großen Ritual der - Reinigung von allen unreinen Geistern befreie, - und binde dann einige kleine Geister der Luft - und des Wassers in das Material. Aus dem so - vorbereiteten Leder fertige er nun ein kleines - Beutelchen, welches in ihm aufbewahrte Kräuter - besser zu konservieren vermag. - The druid takes some specially - prepared leather and performes a great ritual - during which the leather is cleansed of all - impure spirits. Then he binds some minor spirits - of air and water to the material. After - completing this process, the druid works the - enchanted leather into a small pouch which is - suitable to contain herbs, for it is able to - preserve them for a long time and prevents rot. - - - Mit Hilfe dieses Zaubers weckt der - Druide die in den Wälder der Region - schlummernden Ents aus ihrem äonenlangen Schlaf. - Die wilden Baumwesen werden sich ihm anschließen - und ihm beistehen, jedoch nach einiger Zeit - wieder in Schlummer verfallen. - With the help of this spell the druid - awakens the ents who are slumbering in the - forests of a region from aeons of sleep. These - strange tree-creatures will join him and aid his - cause, but after a while they will sink back - into their slumber. - - - Einem erfahrenen Druidem wird - irgendwann auf seinen Wanderungen ein - ungewöhnliches Exemplar einer Gattung begegnen, - welches sich dem Druiden anschließen wird. - Once during his travels, the seasoned - druid will meet an extraordinary creature of its - species that will join him. - - - Dieses Ritual segnet einen Steinkreis, - der zuvor aus Steinen und etwas Holz gebaut - werden muss. Die Segnung des Druiden macht aus - dem Kreis eine mächtige Stätte magischen - Wirkens, die Schutz vor Magie und erhöhte Aura- - Regeneration bewirkt. Man sagt, Jungfrauen seien - in der Umgebung von Steinkreisen seltsame Wesen - begegnet. - This ritual blesses a circle of stones - that has to be constructed from stones and some - wood before. The druid's blessing turns the - circle into a place of great magic that is - suitable for rituals of all kinds. It protects - from hostile magic and improves aura - regeneration. Virgins are said to have been - visited by strange creatures in the vicinity of - these places. - - - Das Ziel des Zauberers wird von einer - harmlosen Verwünschung heimgesucht. - The target of this spell becomes - subject to a harmless curse. - - - Dieses vor dem Kampf zu zaubernde Ritual gibt den - eigenen Truppen einen zusätzlichen Bonus auf ihre Rüstung. Jeder - Treffer reduziert die Kraft des Zaubers, so dass der Schild sich - irgendwann im Kampf auflösen wird. - Performing this ritual before going into battle gives - your troups an additional bonus to their armor. Every hit reduces the - energy of the spell, dissolving it at some point during battle. - - - Der Zauberer schleudert fokussiertes - Chaos in die Reihen der Gegner. Das ballförmige - Chaos wird jeden verwunden, den es trifft. - The sorcerer hurls a ball of - concentrated chaos into the ranks of his - enemies. It will seriously hurt anyone who gets - hit. - - - Der Magier öffnet seinen Geist den - Sphären des Chaos und wird so für einige Zeit - über mehr magische Kraft verfügen. Doch die - Hilfe der Herren der Sphären hat seinen Preis, - und so wird die Phase der Macht abgelöst von - einer Phase der Schwäche. - The sorcerer opens his mind to the - Spheres Of Chaos so that he can access a greater - ammount of magical power for a while. But the - help of the Chaos Lords has its price - and so - the period of power will be followed by a period - of weakness. - - - Mit diesem Ritual kann der Magier - einen Teil seiner Lebensenergie opfern, um dafür - an magischer Kraft zu gewinnen. Erfahrene - Ritualmagier berichten, das sich das Ritual, - einmal initiiert, nur schlecht steuern ließe und - die Menge der so gewonnenen Kraft stark - schwankt. So steht im 'Buch des Blutes' - geschrieben: 'So richte Er aus das Zeichen der - vier Elemente im Kreis des Werdens und Vergehens - und Weihe ein jedes mit einem Tropfen Blut. - Sodann begebe Er in der Mitten der Ewigen Vierer - sich und lasse Leben verrinnen, auf das Kraft - geboren werde.' - With this ritual the sorcerer can - sacrifice part of his life force in order to - gain raw astral power. Experienced mages report - that this ritual, once started, is hard to - control and that the ammount of power gained in - this way varies. - - - In diesem blutigen Ritual opfert der - Magier vor der Schlacht ein Neugeborenes vor den - Augen seiner Armee. Die so gerufenen Blutgeister - werden von den Soldaten Besitz ergreifen und sie - in einen Blutrausch versetzen. - During this bloody ritual the sorcerer - sacrifices a newborn child before a battle right - in front of his army. In this way he attracts - spirits of blood that will take control of the - soldiers who are present and force them into a - blood frenzy. - - - Dieser heimtückische Fluch - beeinträchtigt die magischen Fähigkeiten des - Opfers erheblich. Eine chaosmagische Zone um das - Opfer vermindert seine Konzentrationsfähigkeit - und macht es ihm sehr schwer Zauber zu wirken. - This wicked curse affects the magical - abilities of the target. A field of raw chaos - magic around the target lessens its - concentration and makes it very hard to cast any - spells. - - - Nächtelang muss der Schwarzmagier - durch die Friedhöfe und Gräberfelder der Region - ziehen um dann die ausgegrabenen Leichen beleben - zu können. Die Untoten werden ihm zu Diensten - sein, doch sei der Unkundige gewarnt, dass die - Beschwörung der Mächte des Todes ein - zweischneidiges Schwert sein kann. - For many nights the sorcerer has to - roam the graveyards and former battlefields of a - region in order to find corpses to animate. The - Undead will serve his will, but beware! Dealing - with the mysteries of unlife can be a dangerous - thing. - - - Mit diesem Ritual wird eine dunkle - Gewitterfront beschworen, die sich - unheilverkündend über der Region auftürmt. Der - magische Regen wird alles Erz rosten lassen und - so viele Waffen des Gegners zerstören. - This ritual conjurs up a dark - thunderstorm that affects a whole region. The - magic rain will let rust any ore and thus - destroy many weapons of the enemy. - - - Mit Hilfe dieses Zaubers kann der - Magier eigene Aura im Verhältnis 2:1 auf einen - anderen Magier des gleichen Magiegebietes - übertragen. - With the help of this spell, the - caster can transfer aura at a ratio of 2:1 to - another member of the same school of magic. - - - Der Zauberer erschafft eine Wand aus - Feuer in der angegebenen Richtung. Sie verletzt - jeden, der sie durchschreitet. - The spell creates an opaque wall of - fire in the gives direction that will harm - anyone passing through it. - - - In einem aufwendigen Ritual opfert der - Schwarzmagier einige Bauern und verteilt dann - die Leichen auf magische Weise in den Brunnen - der Region. - In a complicated ritual the sorcerer - sacrifices the lives of ten peasants and - magically spreads their corpses within the wells - of a region. - - - Vor den Augen der feindlichen Soldaten - opfert der Schwarzmagier die zehn Bauern in - einem blutigen, grausamen Ritual und beschwört - auf diese Weise Geister des Wahnsinns über die - feindlichen Truppen. Diese werden im Kampf - verwirrt reagieren und nicht in der Lage sein, - den Anweisungen ihrer Offiziere zu folgen. - Before the eyes of the enemy soldiers - the sorcerer sacrifices ten peasants in a bloody - ritual and thereby summons spirits of madness - upon the enemy troops. The enemy soldiers will - be in confusion during battle and no more be - able to follow the commands of their leaders. - - - Mit Hilfe dunkler Rituale beschwört - der Zauberer Dämonen aus der Sphäre der - Schatten. Diese gefürchteten Wesen können sich - fast unsichtbar unter den Lebenden bewegen, ihre - finstere Aura ist jedoch für jeden spürbar. Im - Kampf sind Schattendämonen gefürchtete Gegner. - Sie sind schwer zu treffen und entziehen ihrem - Gegner Kraft. - With the help of dark rituals the - sorcerer summons demons from the Sphere Of - Shadows. These fearsome creatures can walk - almost unseen among the living, but their dark - aura can be sensed by everyone. Shadow demons - are feared in combat for they are hard to hit - and have the ability to drain strength from - their victims. - - - Dieses Ritual beschwört wütende Elementargeister der - Hitze. Eine Dürre sucht das Land heim. Bäume verdorren, Tiere - verenden, und die Ernte fällt aus. Für Tagelöhner gibt es kaum noch - Arbeit in der Landwirtschaft zu finden. - This Ritual summons an angry elemental spirit that - puts a drought on the entire region. Trees wither, animals die of - thirst and the harvest is destroyed. Workers find little to no work - in farming. - - - Dieses Ritual bindet die bereits - entfliehenden Seelen einiger Kampfopfer an ihren - toten Körper, wodurch sie zu untoten Leben - wiedererweckt werden. Ob sie ehemals auf der - Seite des Feindes oder der eigenen kämpften, ist - für das Ritual ohne belang. - This ritual binds the escaping souls - of some casualties back to their dead bodies and - thus condemns them to an undead existance under - the control of the sorcerer. The ritual affects - the corpses of allies and foes alike - no matter - on which side of the battle the soldiers fought - before their death. - - - Dieses magische Artefakt verleiht dem - Träger die Stärke eines ausgewachsenen - Höhlentrolls. Seine Tragkraft erhöht sich auf - das 50fache und auch im Kampf werden sich die - erhöhte Kraft und die trollisch zähe Haut - positiv auswirken. - This artifact gives the one wearing it - the strength of a cavetroll. He will be able to - carry fifty times as much as normal and also in - combat his enhanced strength and tough troll - skin will serve him well. - - - Der Schwarzmagier kann mit diesem - dunklen Ritual einen Riss in das Gefüge der - Magie bewirken, der alle magische Kraft aus der - Region reißen wird. Alle magisch begabten in der - Region werden einen Großteil ihrer Aura - verlieren. - With this dark ritual the - chaossorcerer causes a deep rift to appear in - the astral balance that will tear all magical - power from a region. All spellcasters in that - region will lose most of their aura. - - - Dieses Ritual, ausgeführt vor einem - Kampf, verwirbelt die astralen Energien auf dem - Schlachtfeld und macht es so feindlichen Magier - schwieriger, ihre Zauber zu wirken. - This ritual, performed before a - battle, causes the astral energies on the - battlefield to whirl and churn and thereby makes - spellcasting more difficult for the enemy mages. - - - Diese Elementarbeschwörung ruft einen - Feuerteufel herbei, ein Wesen aus den tiefsten - Niederungen der Flammenhöllen. Der Feuerteufel - wird sich begierig auf die Wälder der Region - stürzen und sie in Flammen setzen. - This elemental summoning calls a fire - fiend, a creature from the deepest hell. The - demon will eagerly rush into the forests of a - region and set them ablaze. - - - Genau um Mitternacht, wenn die Kräfte - der Finsternis am größten sind, kann auch ein - Schwarzmagier seine Kräfte nutzen um - Verzauberungen aufzuheben. Dazu zeichnet er ein - Pentagramm in das verzauberte Objekt und beginnt - mit einer Anrufung der Herren der Finsternis. - Die Herren werden ihm beistehen, doch ob es ihm - gelingt, den Zauber zu lösen, hängt allein von - seiner eigenen Kraft ab. - At midnight, when the Powers of - Darkness are at their peak, the sorcerer can use - his powers to destroy enchantments. In order to - do so, he draws a pentagram on a surface of the - enchanted object and begins calling the Lords Of - Darkness. The Lords will aid him, but whether he - is able to undo the target spell or not depends - upon his own power. - - - Nur geflüstert wird dieses Ritual an - den dunklen Akademien an die Adepten - weitergegeben, gehört es doch zu den - finstersten, die je niedergeschrieben wurden. - Durch die Anrufung unheiliger Dämonen wird die - Kraft der lebenden Toten verstärkt und sie - verwandeln sich in untote Monster großer Kraft. - Only whispered the knowledge of - performing this ritual is passed to the adepts - of the dark academies, for it is one of the - darkest that has ever been written down. By - calling unholy demons the strength of the living - dead is greatly increased and they are turned - into undead monsters of immense power. - - - Mit einem düsteren Ritual und unter - Opferung seines eigenen Blutes beschwört der - Schwarzmagier einen großen Geist von der - Elementarebene der Gifte. Der Geist manifestiert - sich als giftgrüner Schwaden über der Region und - wird allen, die mit ihm in Kontakt kommen, - Schaden zufügen. - By performing a gruesome ritual and - sacrificing his own blood the Sorcerer conjurs - up a spirit from the Elemental Plane Of Poison. - It will take the form of a green cloud of toxic - gases that envelops a whole region and that will - harm anyone within. - - - Mit diesem dunklen Ritual erzeugt der - Magier einen Köder, der für Drachen einfach - unwiderstehlich riecht. Ob die Drachen aus der - Umgebung oder aus der Sphäre des Chaos stammen, - konnte noch nicht erforscht werden. Es soll - beides bereits vorgekommen sein. Der Köder hält - etwa 6 Wochen, muss aber in einem - drachengenehmen Terrain platziert werden. - Performing this dark ritual, the - sorcerer creates a bait that exhales an - irresistable scent to dragons. It is not known - whether the dragons come from surrounding - regions or if they have their origin in the - Sphere Of Chaos. The bait will exist for about - six weeks, but it must be placed in a tarrain - that is suitable for dragons. - - - Mit Hilfe dunkler Rituale beschwört - der Zauberer Dämonen aus der Sphäre der - Schatten. Diese gefürchteten Wesen können sich - fast unsichtbar unter den Lebenden bewegen, ihre - finstere Aura ist jedoch für jeden spürbar. Im - Kampf sind Schattenmeister gefürchtete Gegner. - Sie sind schwer zu treffen und entziehen ihrem - Gegner Kraft und Leben. - With the help of dark rituals the - sorcerer summons demons from the Sphere Of - Shadows. These fearsome creatures can walk - almost unseen among the living, but their dark - aura can be sensed by everyone. Shadowmasters - are feared in combat for they are hard to hit - and have the ability to drain strength and life - force from their victims. - - - 'Und so reibe das Blut eines wilden - Kämpfers in den Stahl der Klinge und beginne die - Anrufung der Sphären des Chaos. Und hast du - alles zu ihrem Wohlgefallen getan, so werden sie - einen niederen der ihren senden, das Schwert mit - seiner Macht zu beseelen...' - 'So take the blood of a fierce warrior - and apply it to the steel of the blade. Then - start calling the Spheres Of Chaos. If you did - everything to their pleasure, they will send a - minor one of their kind to fulfill the sword - with his power.' - - - Einem erfahrenen Magier wird - irgendwann auf seinen Wanderungen ein - ungewöhnliches Exemplar einer Gattung begegnen, - welches sich dem Magier anschließen wird. - During their travel, seasoned - magicians will occasionally befriend an extraordinary - creature of an unusual species that will join them. - - - Durch das Opfern von 200 Bauern kann - der Chaosmagier ein Tor zur astralen Welt - öffnen. Das Tor kann in der Folgewoche verwendet - werden, es löst sich am Ende der Folgewoche auf. - By sacrificing the lives of 200 - peasants, the chaossorcerer is able to open a - planar gate. This gate can be used during the - following week to transfer units to the astral - plane. It dissipates at the end of the following - week. - - - Der Zauberer sendet dem Ziel des - Spruches einen Traum. - The mentalist sends a dream to the - target of the spell. - Le mentaliste envoie un rêve à la - cible du sort. - - - Dieser Zauber vermag dem Gegner ein - geringfügig versetztes Bild der eigenen Truppen - vorzuspiegeln. Die Schattenritter haben keinen - effektiven Angriff und Verwundungen im Kampf - zerstören sie sofort. - This spell creates illusionary - duplicates of allied troops. The shadow knights - can't do real damage and are instantly destroyed - if wounded. - Ce sort crée des copies illusoires de - troupes alliées. Les guerriers illusoires ne - peuvent faire de dégats réels et sont - instantanément détruits lorsqu'ils sont blessés. - - - Der Traumweber beschwört vor dem - Kampf grauenerregende Trugbilder herauf, die - viele Gegner in Panik versetzen. Die Betroffenen - werden versuchen, vor den Trugbildern zu - fliehen. - Before a battle the mentalist creates - terrifying illusions of hideous creatures that - will cause panic among the enemies. Those who - believe in the illusions will try to flee from - battle. - - - Dieses magische Ritual beruhigt die - gequälten Seelen der gewaltsam zu Tode - gekommenen und ermöglicht es ihnen so, ihre - letzte Reise in die Anderlande zu beginnen. Je - Stufe des Zaubers werden ungefähr 50 Seelen ihre - Ruhe finden. Der Zauber vermag nicht, bereits - wieder auferstandene lebende Tote zu erlösen, da - deren Bindung an diese Welt zu stark ist. - This ritual calms the tortured souls - of those who died a violent death and finally - releases them to the Otherlands. About 50 souls - per level of the spell will be released. The - spell will not affect existing undead, because - they are too strongly tied to the Material - World. - - - Mit Hilfe dieses Zaubers kann der - Traumweber die Illusion eines beliebigen - Gebäudes erzeugen. Die Illusion kann betreten - werden, ist aber ansonsten funktionslos und - benötigt auch keinen Unterhalt. Sie wird einige - Wochen bestehen bleiben. - With this spell the mentalist can - create the illusion of any building. The - illusion can be entered, but it has no function - and requires no maintenance. It will remain - existing for several weeks. - - - Mit Hilfe dieses Zaubers kann der - Traumweber eigene Aura im Verhältnis 2:1 auf - einen anderen Traumweber übertragen. - With the help of this spell the - mentalist can transfer aura at a ratio of 2:1 to - another mentalist. - - - Mit Hilfe dieses arkanen Rituals - vermag der Traumweber die wahre Gestalt einer - Gruppe - zu verschleiern. Unbedarften Beobachtern - erscheint - sie dann als einer anderen Rasse zugehörig. - With the help of this ritual the - mentalist is able to conceal the true form of a - target unit. To unknowing observers all persons - in the target unit appear to be of a different - race. - - - Dieser Zauber ermöglicht es dem - Traumweber, in die Träume einer Einheit - einzudringen und so einen Bericht über die - Umgebung zu erhalten. - This spell enables the mentalist to - penetrate the dreams of a target unit and gather - information about that unit's surroundings. He - will receive a report from the corresponding - region. - - - Dieser Kampfzauber führt dazu, dass - einige Gegner im Kampf unter schwerer Müdigkeit - leiden. Die Soldaten verschlafen manchmal ihren - Angriff und verteidigen sich schlechter. - This combat spell causes several - enemies to suffer from an unnatural tiredness - during combat. The soldiers will defend - themselves worse than normal and sometimes sink - into a slumber instead of attacking. - - - Stirbt ein Krieger im Kampf so macht - sich seine Seele auf die lange Wanderung zu den - Sternen. Mit Hilfe eines Rituals kann ein - Traumweber versuchen, die Seele wieder - einzufangen und in den Körper des Verstorbenen - zurückzubringen. Zwar heilt der Zauber keine - körperlichen Verwundungen, doch ein Behandelter - wird den Kampf überleben. - When a warrior dies in a battle, his - soul begins its long journey to the stars. With - the help of this ritual, the mentalist can try - to catch those escaping souls and bring them - back to their bodies. The spell does not heal - physical injuries, but an affected person will - survive the battle. - - - Mit diesem Spruch kann der Traumweber - versuchen, die Verzauberungen einer einzelnen - Einheit zu erkennen. Von allen Sprüchen, die - seine eigenen Fähigkeiten nicht überschreiten, - wird er einen Eindruck ihres Wirkens erhalten - können. Bei stärkeren Sprüchen benötigt er ein - wenig Glück für eine gelungene Analyse. - With this spell the mentalist can - attempt to detect enchantments on a target unit. - He will get an idea of the effect of all spells - that don't exceed his own abilities. If a spell - is stronger, it takes a little luck for a - successful analysis. - - - Dieser Zauber führt in der betroffenen - Region für einige Wochen zu Schlaflosigkeit und - Unruhe. Den Betroffenen fällt das Lernen - deutlich schwerer. - This spell causes insomnia and - restlessness in a whole region for several - weeks. All affected persons will learn much - slower than normal. - - - Dieser Zauber läßt einige feindliche - Kämpfer einschlafen. Schlafende Kämpfer greifen - nicht an und verteidigen sich schlechter, sie - wachen jedoch auf, sobald sie im Kampf getroffen - werden. - This spell causes several enemies to - fall asleep. Sleeping warriors don't attack and - defend themselves worse than normal, but they'll - wake up if they get hit during combat. - - - Mit diesem Zauber dringt der - Traumweber in die Gedanken und Traumwelt seines - Opfers ein und kann so seine intimsten - Geheimnisse ausspähen. Seine Fähigkeiten, seinen - Besitz und seine Parteizugehörigkeit wird nicht - länger ungewiss sein. - With this spell the mentalist - penetrates the thoughts and dreams of his victim - to reveal his most intimate secrets. The - target's faction, skills and possessions will no - longer be unknown. - - - Der Magier beschwört ein kleines Monster, einen Alp. Dieses bewegt sich - langsam auf sein Opfer zu (das sich an einem beliebigen Ort an der Welt - befinden kann, der Magier oder seine Partei braucht es nicht zu sehen). - Sobald das Opfer erreicht ist, wird es gnadenlos gequält, und nur durch - einen starken Gegenzauber oder den Tod des beschwörenden Magiers kann - das Opfer wieder Frieden finden. Bei der Beschwörung des Alps verliert - der Magier einen kleinen Teil seiner Aura für immer. - The magician spawns a little monster, a nightmare. The nightmare slowly - approaches its victim (which may be at an arbitrary place in eressea, it - is not needed for the magician or his party to see the victim). As soon - as - the victim is reached the nightmare starts to torment it without mercy, - only a powerfull counter spell or the death of the casting magician can - redeem - the victim. When spawning the nightmare the magician loses a small amount - of - his aura forever. - - - Ein mit diesem Zauber belegtes Drachenauge, welches zum Abendmahle - verzehrt wird, erlaubt es dem Benutzer, in die Träume einer anderen - Person einzudringen und diese zu lesen. Lange Zeit wurde eine solche - Fähigkeit für nutzlos erachtet, bis die ehemalige waldelfische - Magistra für Kampfmagie, Liarana Sonnentau von der Akademie Thall, - eine besondere Anwendung vorstellte: Feldherren träumen vor großen - Kämpfen oft unruhig und verraten im Traum ihre Pläne. Dies kann dem - Anwender einen großen Vorteil im kommenden Kampf geben. Aber Vorsicht: - Die Interpretation von Träumen ist eine schwierige Angelegenheit. - An enchanted eye of a dragon gives the person who eats it for supper the - power to see - other people's dreams. For a long time this abillity was counted as - beeing - useless until - the former elfish mistress for theurgy of war, Liarana Sonnentau from - the - academy Thall, - presented a special appliance for this artefact: Before a battle - captains - often have an - uncomfortable sleep and betray their plans in their dreams. This might - give the user of - the artefact a small advantage in the upcoming battle, but be warned: - Interpreting dreams - is a difficult exercise. - - - Mit diesem Spruch kann der Zauberer eine Sphäre der - Unsichtbarkeit - erschaffen. Die Späre macht ihren Träger sowie neunundneunzig weitere - Personen in derselben Einheit unsichtbar. - Using this spell the magician can create a Sphere of - Invisibility. This artefact hides the person bearing it and one hundred - persons in the same unit. - - - Dieser Zauber ermöglicht es dem - Traumweber, den Schlaf aller aliierten Einheiten - in - der Region so zu beeinflussen, dass sie für - einige - Zeit einen Bonus in allen Talenten bekommen. - This spell allows the mentalist to - influence the sleep of all allied units in a - region - in such a way that they will gain a bonus to all - talents for some time. - - - Dieser Zauber ermöglicht es dem - Traumweber die natürlichen und aufgezwungenen - Traumbilder einer Person, eines Gebäudes, - Schiffes oder einer Region zu unterscheiden und - diese zu entwirren. - This spell allows the mentalist to - distinguish between the natural and unnatural - dreams of a person, a ship, a building or a - region and remove those that are of magical - origin. - - - Aus 'Die Gesänge der Alten' von - Firudin dem Weisen: 'Diese verführerische kleine Melodie - und einige einschmeichelnde Worte überwinden das - Misstrauen der Bauern im Nu. Begeistert werden sie sich - Euch anschliessen und selbst Haus und Hof in Stich - lassen.' - From the 'Songs of the Elder' by - Firudin the Sage: 'This enticing little melody and its - ingratiating words will lure the peasants in no time. - They will leave home and hearth to follow your lead.' - - - Dieser fröhliche Gesang wird sich wie - ein Gerücht in der Region ausbreiten und alle Welt in - Feierlaune versetzten. Überall werden Tavernen und - Theater gut gefüllt sein und selbst die Bettler satt - werden. - This joyous song will spread like - wildfire throughout the region and cause festive spirits - in all the population. All the taverns and theaters will - be packed to the brim and even the beggars will not go - hungry. - - - Einem erfahrenen Magier wird - irgendwann auf seinen Wanderungen ein ungewöhnliches - Exemplar einer Gattung begegnen, welches sich dem Magier - anschließen wird. - Once during his travels, the seasoned - magician will meet an extraordinary creature of its species - that will join him. - - - Mit diesem Zauber greift der Magier - direkt den Geist seiner Gegner an. Ein Schlag aus - astraler und elektrischer Energie trifft die Gegner, - wird die Magieresistenz durchbrochen, verliert ein Opfer - permanent einen Teil seiner Erinnerungen. Wird es zu oft - ein Opfer dieses Zaubers kann es daran sterben. - With this spell the mentalist directly - attacks his enemies' souls. A blast of astral and - electrical energy strikes the foes. If a victim fails to - resist the magic, he will permanently lose part of his - memories. Being the target of this spell for too many - times may result in death. - - - Dieser Zauber - dessen Anwendung in - den meisten Kulturen streng verboten ist - löst im Opfer - ein unkontrollierbares Verlangen nach körperlicher Liebe - aus. Die betroffenen Personen werden sich Hals über Kopf - in ein Liebesabenteuer stürzen, zu blind vor Verlangen, - um an etwas anderes zu denken. Meistens bereuen sie es - einige Wochen später... - This spell - whose use is forbidden in - most cultures - creates an uncontrollable desire for - physical love in the victim. The affected persons will - rush head over heels into a love affair, unable to think - of anything else. Most of them will regret this a few - months later... - - - - - - Winter - winter - - - Sommer - summer - - - Frühling - spring - - - Herbst - fall - - - die erste Woche - the first week - - - die zweite Woche - the second week - - - die letzte Woche - the last week - - - der ersten Woche - of the first week - - - der zweiten Woche - of the second week - - - der letzten Woche - of the third week - - - Feldsegen - harvest moon - - - Nebeltage - impenetrable fog - - - Sturmmond - storm moon - - - Herdfeuer - hearth fire - - - Eiswind - icewind - - - Schneebann - snowbane - - - Blütenregen - flowerrain - - - Mond der milden Winde - mild winds - - - Sonnenfeuer - sunfire - - - des zweiten Zeitalters - the second age - - - neuer Zeitrechnung - of the new age - - - - - - Gemein - common - - - Kein Magiegebiet - no magic school yet - - - Illaun - Illaun - - - Tybied - Tybied - - - Gwyrrd - Gwyrrd - - - Cerddor - Cerddor - - - Draig - Draig - - - - - Baum - tree - - - Bäume - trees - - - - Mallornbaum - mallorn tree - - - Mallornbäume - mallorn trees - - - ALLIANZ - ALLIANCE - - - AUSSTOSSEN - KICK - - - NEU - NEW - - - KOMMANDO - COMMAND - - - VERLASSEN - LEAVE - - - BEITRETEN - JOIN - - - EINLADEN - INVITE - - - Steine - stones - - - - Pferde - horses - - - Bauern - peasants - - - Silber - silver - - - Laen - laen - - - - Schößlinge - saplings - - - - Mallornschößlinge - mallorn saplings - - - - Bäume - trees - - - - Mallorn - mallorn - - - - Eisen - iron - - - - Winter - winter - - - - Frühling - spring - - - - Sommer - summer - - - - Herbst - autumn - - - - Vorlage für den nächsten Zug: - Template for the next turn: - - - - Wir schreiben %s des Monats %s im Jahre %d %s. - It is %s of the month of %s in the %d. year of %s. - - - - Wir schreiben %s des Monats %s im Jahre %d %s. Es ist - %s. - It is %s of the month of %s in the %d. year of %s. It is - %s. - - - - aggressiv - aggressive - - - - vorne - front - - - - hinten - rear - - - - defensiv - defensive - - - - flieht - fleeing - - - - kämpft nicht - not fighting - - - - bekommt keine Hilfe - gets no aid - - - - Attacke gegen: - Attacked against - - - - Kämpft gegen: - Fighting against - - - - Hilft: - Helping - - - - Heer - army - - - - Unbekannte Partei - unknown faction - - - einer unbekannten Partei - an unknown faction - - - und - and - - - - Das Schiff des Elfen hat ein rotes Segel - - - - Der Zwerg hat eine Nuss dabei - - - - Die Katze führt eine Hellebarde - - - - Das Schiff mit dem grünen Segel liegt links neben dem - mit - einem weissen Segel - - - - Auf dem Schiff mit grünen Segeln kam der Speerkämpfer - - - - Der Krieger mit dem Kreis im Wappen hat einen Keks - - - - Der Krieger des mittleren Schiffs hat ein Schwert - - - - Auf dem gelben Segel prankt ein Kreuz als Wappen - - - - Der Mensch kam mit dem ersten Schiff - - - - Das Schiff mit dem Stern im Wappen liegt neben dem der - einen Mandelkern hat - - - - Das Schiff des Kriegers, der ein Apfel hat, liegt neben - dem, der ein Kreuz als Wappen hat - - - - Der Krieger mit dem Turm im Wappen trägt eine Axt - - - - Das Schiff des Menschen liegt neben dem blauen Schiff - - - - Das Insekt trägt einen Baum als Wappen - - - - Das Schiff mit dem Stern im Wappen liegt neben dem des - Kriegers, der einen Zweihänder führt - - - - Held - hero - - - - Helden - heroes - - - - - - Dunkel - dark - - - - Schwarz - black - - - - Licht - light - - - - Flammen - flame - - - - Eis - ice - - - - Klein - gully - - - - Hoch - high - - - - Hügel - hill - - - - Berg - mountain - - - - Wald - wood - - - - Sumpf - swamp - - - - Schnee - snow - - - - Sonnen - sun - - - - Mond - moon - - - - See - sea - - - - Tal - valley - - - - Schatten - shadow - - - - Höhlen - cave - - - - Blut - blood - - - - Wild - wild - - - - Chaos - chaos - - - - Nacht - night - - - - Nebel - mist - - - - Grau - grey - - - - Frost - cold - - - - Finster - gloom - - - - Düster - black - - - - Sternen - star - - - - - 'Ho ho ho!' Ein dicker Gnom fliegt auf einem von - 8 Jungdrachen gezogenen Schlitten durch die Nacht und vermacht Deiner - Partei ein Sonnensegel. (Um das Segel einer Einheit zu geben, gib - ihr den Befehl 'BEANSPRUCHE 1 Sonnensegel'). - 'Ho ho ho!' A fat little gnome Gnom on a sled - pulled by 8 young dragons flies through the stary night and presents - your faction with a solar sail. (To claim this item, one of your units - must issue the order 'CLAIM 1 solar sail'. - - - - 'Ho ho ho!' Ein dicker Gnom fliegt auf einem von - 8 Jungdrachen gezogenen Schlitten durch die Nacht und vermacht Deiner - Partei eine Phiole mit Sternenstaub. (Informationen dazu gibt es mit - BEANSPRUCHE und ZEIGE). - 'Ho ho ho!' A fat little gnome Gnom on a sled - pulled by 8 young dragons flies through the stary night and presents - your faction with a vial of stardust. (To get more information about - this item, use the CLAIM and SHOW commands). - - - - 'Ho ho ho!' Ein dicker Gnom fliegt auf einem von - 8 Jungdrachen gezogenen Schlitten durch die Nacht und vermacht Deiner - Partei einen wundervoll geschmueckten Weihnachtsbaum. (Informationen dazu gibt es mit - BEANSPRUCHE und ZEIGE). - 'Ho ho ho!' A fat little gnome Gnom on a sled - pulled by 8 young dragons flies through the stary night and presents - your faction with a beautifully decorated tree. (To get more information about - this item, use the CLAIM and SHOW commands). - - - - Gral - grail - - - - Grale - grails - - - - Lerntrank - brain boost - - - - Lerntränke - brain boosts - - - - GE je - stone per - - - - GE je - stones per - - - - GE - stone - - - - GE - stones - - - - bewacht die Region - guards the region - - - - und - and - - - - Dorfbewohner - Villagers - - - - Bauernmob - Angry mob - - - - Aufgebrachte Bauern - Furious peasants - - - - Söldner - Mercenaries - - - - Sumpfbewohner - Swamp people - - - - Waldbewohner - Woodsmen - - - - Nomaden - Nomads - - - - Eisleute - Ice people - - - - Bergbewohner - Mountain people - - - - Magie der Elemente - Magic of the Elements - - - - Schwerter, Armbrüste, Langbögen - Swords, Crossbows and Longbows - - - - Gorms Almanach der Rationellen Kriegsführung - Gorm's Almanach of Rational War - - - - Katamarane, Koggen, Karavellen - The dragonship, the caravell and the longboat - - - - Wege der Sterne - Ways of the Start - - - - Nadishahs Kleine Gift- und Kräuterkunde - Nadishah's collected lore on poisonous and beneficial herbs - - - - Mandricks Kompendium der Alchemie - Mandrick's alchemistic compendium - - - - Die Konstruktion der Burgen und Schlösser von Zentralandune - - - - Die Esse - - - - Über die Gewinnung von Erzen - - - - Barinions Lieder, eine Einführung für Unbedarfte - - - - die Ruine eines alten Tempels - the ruins of an ancient temple - - - - eine alte Burgruine - the ruins of a castle - - - - ein zerfallenes Bauernhaus - a dilapitated farm - - - - eine Leiche am Wegesrand - a corpse by the wayside - - - - eine Leiche am Wegesrand - a corpse by the wayside - - - - Feuerdrache - fire dragon - - - - Ein Alp starb, ohne sein Ziel zu erreichen. - An alp died before it reached its target. - - - - unbewaffnet - unarmed - - - - Trefferpunkte - hitpoints - - - - Rüstung - armor - - - - Angriff - attack - - - - Angriffe - attacks - - - - Verteidigung - defense - - - - Kann Waffen benutzen. - May use weapons. - - - - Ist durch Stichwaffen, Bögen und Armbrüste schwer zu verwunden. - Is hard to hit by piercing weapons. - - - - Ist durch Hiebwaffen schwer zu verwunden. - Is hard to hit by slashing weapons. - - - - Ist durch Schlagwaffen und Katapulte schwer zu verwunden. - Is hard to hit by blunt weapons and catapults. - - - - ein Angriff mit der Waffe oder unbewaffnet - an attack with a weapon or an unarmed attack - - - - ein unbewaffneter Angriff - an unarmed attack - - - - ein magischer Angriff - a magical attack - - - - Klon von %s - Clone of %s - - - - ein Angriff, der Gebäudeschaden verursacht - an attack causing structural damage to buildings - - - - Präkampfzauber - pre-combat spell - - - - Postkampfzauber - post-combat spell - - - - Kampfzauber - combat spell - - - - Normaler Zauber - regular spell - - - - Es ist Winter, und Insekten können nur in Wüsten oder mit Hilfe des Nestwärme-Tranks Personen rekrutieren. - It is winter, and insects can only recruit in deserts or with the aid of nestwarmth potions. - - - - Es ist Spätherbst, und diese Woche ist die letzte vor dem Winter, in der Insekten rekrutieren können. - - - - Eigentümer - Owner - - - - - eine Straße - a road - - - - Straßen - roads - - - - Straße - road - - - - eine zu %d%% vollendete Straße - a road that is %d%% complete - - - - ein Straßenanschluß - a connection to another road - - - - eine unvollständige Straße - an incomplete road - - - - Wand - wall - - - - eine Wand - a wall - - - - Feuerwand - firewall - - - - eine Feuerwand - a firewall - - - - Nebelwand - wall of fog - - - - eine Nebelwand - a wall of fog - - - - Irrlichter - wisps - - - - eine Gruppe von Irrlichtern - a cloud of wisps - - - - gewaltiges offenes Tor - massive open door - - - - ein gewaltiges offenes Tor - a massive open door - - - - gewaltiges verschlossenes Tor - massive locked door - - - - ein gewaltiges verschlossenes Tor - a massive locked door - - - - Illusionswand - illusionary wall - - - - eine Illusionswand - an illusionary wall - - - - - - Die Region ist verwüstet, der Boden karg. - The region is ravaged, the ground infertile. - - - - Einheit-Nr - unitid - - - - Schiff-Nr - shipid - - - - völker - tribes - - - - Gebäude-Nr - buildingid - - - - - Aura - aura - - - - Rasse - race - - - - Zauber-ID - spellid - - - - Richtung - direction - - - - Gebäudetyp - buildingtype - - - - + + + + + Wirbel + vortex + remous + + + Ein Wirbel aus reinem Chaos zieht über die Region + A vortex of pure chaos energy pulls over the region + + + Wabernde grüne Schwaden treiben durch den Nebel und + verdichten sich zu einer unheimlichen Kreatur, die nur aus einem langen + Ruderschwanz und einem riesigen runden Maul zu bestehen scheint. + Wobbling green vapours drift through the mists to form an eldritch creature that seems to be entirely made up of huge jaws and a long tail. + + + + Keine Informationen über diese Rasse verfügbar. + No information available for this race. + + + Singdrachen sind von der Größe eines ausgewachsenden Tigers. Ihre Färbung reicht von schillerndem Rot, über dunkles Grün bis hin zu tiefem Schwarz. Alle bekannten Drachen dieser Art weisen eine hohe Intelligenz und ein hohes Maß an magischen Fähigkeiten auf. Wie Ihre großen Verwandten verfügen sie über einen Feuerodem. Sie lieben den Gesang und das üppige Mahl. Von Zeit zu Zeit gehen sie eine engen magisches Bund zu einem Magier ein. Wenn dies geschieht, so steht dem Magier ein äußerst loyaler und lohnender Vertrauter zur Seite. + + Song Dragons are roughly the size of a fully grown tiger. Their coloring ranges from bright red, through a dark green shade to a deep black. All known dragons of this species display a high level of intelligence and highly developed magical skills. Like their larger cousins, Song Dragons posess a firegland. They love singing and a good meal. From time to time one of these magnificent creatures will bond with a mage. When this happens, the mage is assured of a most loyal and useful familiar at his side. + + + Dieses mystische Wesen lebt bevorzugt in den tiefsten Wäldern und + vermag sich hervorragend vor den Augen anderer zu verbergen. Nur + selten schließt sich ein Einhorn einem Magier an, jedoch wenn das + geschieht ist es ein mächtiger Verbündeter, der auch über eigene Magie + verfügt. + + + Der Adler ist ein ausgezeichneter Späher, fliegend überquert er sogar + kurze Meerengen, doch ist er hoch oben am Himmel auch sehr exponiert, + was ihn beim Rasten zu einem leichten Ziel macht. + + + Der Luchs ist bekannt für seine Geschicklichkeit im Verbergen und + Beobachten. Mit ein wenig Geduld kann er zu einem hervorragenden + Späher ausgebildet werden. Im Kampf verteidigt er sich mit seinen + scharfen Krallen und weiß seine Gewandheit zu nutzen. + + + Diese großen Wölfe sind nicht alle so wild und böse wie in den + Legenden berichtet, und einige von ihnen schließen sich auch guten + Magiern bereitwillig an und sind ihnen dann treue Gefährten. + + + 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. + + + + + Das Horn eines Trolles. Kein Troll würde sich lebend davon trennen. + The horn of an adult troll. No troll would ever part with this while he's alive. + + + Beim Barte des Proheten! Ach nein, Zwergen. Irgendetwas riecht hier ranzig. + Sniff... Bleah. Don't they ever wash these? + + + Diese Amulett ist ein hervorragender Fokus für alle Heilzauber. Ein + mit diesem Fokus gewirkter Heilzauber wird mit größerer + Warscheinlichkeit Erfolgreich sein und doppelt so viele Leute heilen + können. + + + Der Kopf eines toten Drachens oder Wyrms. Man sagt, es ruhen magische Kräfte darin. + The head of a dead dragon or wyrm. They say that it has magical powers. + + + Munition für Katapulte. + Ammunition for catapults. + + + Ein Elfenpferd wird sich nur den wenigsten jemals anschließen. Hat es + jedoch seine Scheu überwunden ist es ein sehr wertvoller Gefährte. Ein + Elfenpferd ist schneller als ein Pferd. Zudem hilft es seinem Reiter + im Kampf und unterstützt ihn mit seiner Magie. Es sind schwarze + Elfenpferde bekannt, die sich sogar Orks angeschlossen haben. + + + Die rötlich glühende Klinge dieser furchterregenden magischen Waffe + ist mit dunklen Runen bedeckt. Nur die erfahrendsten Schwertkämpfer + vermögen ihre Kraft zu zähmen, doch in ihrer Hand vermag dem + Runenschwert nichts zu widerstehen - selbst magische Rüstungen + durchdringt es ohne Schwierigkeiten - und den Geist des Kämpfers füllt + es mit unterschütterlicher Zuversicht. + + + This enchanted dragon-eye has to be eaten by the leader of your forces + on the eve before battle. During the night he gains insight into the + dreams of the enemy leaders and may potentially glean a decisive + advantage. + Dieses verzauberte Drachenauge muß vor dem Abend einer Schlacht vom + Heerführer verzehrt werden. Während der Nacht wird er dann Einblick in + die Träume der feindlichen Heerführer erhalten und so möglicherweise + einen entscheidenden Vorteil im kommenden Gefecht erlangen. + + + This artifact grants its wearer the strength of a cavetroll. He will + be able to carry fifty times as much as normal and also in combat his + enhanced strength and tough troll skin will serve him well. + Dieses magische Artefakt verleiht seinem Träger die Stärke eines + ausgewachsenen Höhlentrolls. Seine Tragkraft erhöht sich auf das + 50fache und auch im Kampf werden sich die erhöhte Kraft und die + trollisch zähe Haut positiv auswirken. + + + It may look like just another quartz, but your magician will tell you + tha great power emenates from these crystals. Using it at the begining + of a week will release a strong negative energy that reduce the + power of all spells cast in the region during that week. + Für den ungeübten Betrachter mag der Antimagiekristall wie ein + gewöhnlicher Quarzkristall ausschauen, doch ein Magier spürt, das ihm + ganz besondere Kräfte innewohnen. Durch spezielle Rituale antimagisch + aufgeladen wird der Kristall, wenn er zu feinem Staub zermahlen und + verteilt wird, die beim Zaubern freigesetzten magischen Energien + aufsaugen und die Kraft aller Zauber reduzieren, welche in der betreffenden + Woche in der Region gezaubert werden. + + + A ring of power increases a magician's power. The level of all the + spells + he casts will be increased by one without increasing their costs. + Ein Ring der Macht verstärkt die Kraft des Magiers. Jeder Zauber wird, + ohne das sich die Kosten erhöhen, so gezaubert als hätte der Magier + eine Stufe mehr. + + + Herbs stored in this bag will be much better preserved. + Kräuter, die in diesem Beutelchen aufbewahrt werden, sind erheblich + besser konserviert. + + + This bag encloses a dimensional fold, which can store up to 200 + stones of weight without any extra burden on the bearer. Large items + such as horses or carts cannot be placed inside. + Dieser Beutel umschließt eine kleine Dimensionsfalte, in der bis + zu 200 Gewichtseinheiten transportiert werden können, ohne dass + sie auf das Traggewicht angerechnet werden. Pferde und andere + Lebewesen sowie besonders sperrige Dinge (Wagen und Katapulte) können + nicht in dem Beutel transportiert werden. Auch ist es nicht möglich, + einen Zauberbeutel in einem anderen zu transportieren. Der Beutel + selber wiegt 1 GE. + + + These leather boots are embroidere with unicorn hair and allow + their wearer to walk at twice his normal speed. + Diese aus Leder gefertigten und mit Einhornfell verzierten Stiefel + ermöglichen es ihrem Träger, sich mit der doppelten Geschwindigkeit + fortzubewegen, wenn er zu Fuß reist. + + + The flaming sword gives its bearer an attack of 3d6+10 plus + an additional fireball causing 2d6 damage to 1-10 victims. + Using a flaming sword requires a minimum skill of 7. It grants an + additional +1 to your skill and your resistance to magic will be + increased. + Ein Flammenschwert gibt dem Träger, der kein Magier sein muß, + zusätzlich zu seinem normalen Angriff (3d6+10) einen kleinen + Feuerballangriff, der bei 1-10 Opfern 2d6 magischen Schaden + verursacht. Um ein Flammenschwert führen zu können, muss man + mindestens Hiebwaffen 7 haben, dann verleiht es einem auch + einen zusätzlichen Kampfbonus von +1. Ein Flammenschwert + erhöht die Magieresistenz seines Trägers wie ein Laenschwert. + + + The magic in this ring makes the fingers ten times more nimble. a + craftsman can produce ten times his normal quota, and other abilities + might also be improved. + Der Zauber in diesem Ring bewirkt eine um das zehnfache verbesserte + Geschicklichkeit und Gewandheit der Finger. Handwerker können somit + das zehnfache produzieren, und bei einigen anderen Tätigkeiten könnte + dies ebenfalls von Nutzen sein. + + + This magical artifact has been used since ancient times by Elves to + conceal themselves from their enemies. Other races have also learned + the value of these rings after encountering Elves - after all the ring + makes its wearer invisible to normal eyes, and only magical methods + enable the wearer to be discovered. + Dieses magische Artefakt wurde seit Urzeiten von den Elfen benutzt, + auf der Jagd oder um sich vor Feinden zu verbergen. Doch auch andere + Rassen haben nach der Begegnung mit den Elfenvölkern den Wert des Rings + schnell schätzen gelernt - schließlich macht er den Träger für jedes + noch so scharfe Auge unsichtbar - nur mit magischen Mitteln ist der + Verborgene noch zu entdecken. + + + Das Amulett erlaubt es dem Träger, alle Einheiten, die durch einen + Ring der Unsichtbarkeit geschützt sind, zu sehen. Einheiten allerdings, + die sich mit ihrem Tarnungs-Talent verstecken, bleiben weiterhin + unentdeckt. Die Herstellung des Amulettes kostet 3000 Silber. + + + Dieser Tiegel enthält die seltenste alchemistische Substanz + Eresseas, den Krötenschleim. Angeblich soll der Krötenschleim eine + aussergewöhnlich hohe magische Absorbtionskraft besitzen und deswegen + in obskuren magischen Ritualen Verwendung finden. + + + Die Kröte ist eine der seltensten Rassen Eresseas. Man munkelt, + sie würde nur auf magische Weise entstehen. In einer uralten + Abhandlung über Magie aus der Bibliothek der Akademie von Xontormia + wird die Theorie aufgestellt, das die Kröte die ins morphische Feld + des Magiers übertragene Manifestation eines implodierten + Zauberfeldes sein könnte. Vieleicht deswegen ist die Kröte auch + gegen Zauber weitaus widerstandsfähiger als die normalen Rassen + Eresseas, leider aber auch weitaus unmagischer als diese. Die + Kröte kann schon aufgrund ihrer Größe und der fehlenden Hände + nur unter Schwierigkeiten normale Tätigkeiten ausüben. Der + einzige Vorteil ihrer geringen Größe ist, dass sie sich leichter + verstecken kann. + + + Dieses magische Szepter, ein Geschenk Igjarjuks, sorgt für große + Verwirrung und Gedächtnisverlust. Syntax: BENUTZE "Szepter der + Tränen" + + + Setzt eine Einheit dieses Segel auf einem Schiff, so erhöht + sich dessen Reichweite permanent um 1 Region. + A unit setting this sail on a ship temporarily will permanently + increase the ship's range by 1. + + + Im Mistelzweig ruht eine magische + Kraft der besonderer Art. Der Anwender wird von seinen + Feinden in Frieden gelassen, eine Woche lang läßt jeder + Kämpfer ihn unbeschadet seines Weges ziehen. + The magical misteltoe has a wonderous + property: It's use will make one person able to escape + unharmed from every conflict, no enemy will lay hand on + the bearer for one week. + + + + + + Kein Magiegebiet + no magic school + + + Illaun + Illaun + + + Tybied + Tybied + + + Cerddor + Cerddor + + + Gwyrrd + Gwyrrd + + + Draig + Draig + + + + + Tresen + counter + + + + wenige + few + + + + viele + many + + + + relativ viele + rather many + + + + sehr wenige + very few + + + + sehr viele + a great many + beaucoup de + + + + (trauernd) + (in mourning) + + + Beschreibung: + Description: + + + Art: + Type: + + + Komponenten: + Components: + + + Modifikationen: + Modifications: + + + Stufe: + Level: + + + Rang: + Rank: + + + Syntax: + Syntax: + + + + Geboten wird für + Traders can sell + + + und für + and + + + . + . + + + , für + , + + + + , im + , to the + + + und im + and to the + + + Einheit + Unit + + + Partei + Faction + + + hier_passwort_eintragen + insert_your_password_here + + + + Baum + tree + + + + Bäume + trees + + + + Mallornbaum + mallorn tree + + + + Mallornbäume + mallorn trees + + + + + + Nordwestküste + + + Nordostküste + + + Ostküste + + + Südostküste + + + Südwestküste + + + Westküste + + + + + AUSWERTUNG + + + COMPUTER + + + ZUGVORLAGE + + + SILBERPOOL + + + STATISTIK + + + DEBUG + + + ZIPPED + + + ZEITUNG + + + MATERIALPOOL + + + ADRESSEN + + + BZIP2 + + + PUNKTE + + + TALENTVERSCHIEBUNGEN + + + + + ein fliegender Teppich + + + ein Ballon + + + eine Karavelle + + + ein Boot + + + ein Langboot + + + ein Drachenschiff + + + eine Trireme + + + + fliegender Teppich + flying carpet + + + Ballon + + + Karavelle + + + Boot + + + Langboot + + + Drachenschiff + + + Trireme + + + + + Mahlstrom + + + Ozean + + + Ebene + + + Wald + + + Sumpf + + + Wüste + + + Hochland + + + Berge + + + Gletscher + + + Gletscher + + + Feuerwand + + + Vulkan + + + Nebel + + + Eisberg + + + Dichter Nebel + + + Ebene aus Feuer und Dunkelheit + + + Aktiver Vulkan + + + Halle + + + Gang + + + Wand + + + Magischer Sturm + + + + ein %s + + + %s + + + die Ebene von %s + + + der Wald von %s + + + der Sumpf von %s + + + die Wüste von %s + + + das Hochland von %s + + + das Bergland von %s + + + der Gletscher von %s + + + eine %s + + + der Vulkan von %s + + + ein %s + + + der Eisberg von %s + the glacier of %s + + + der Gletscher von %s + the glacier of %s + + + %s + + + eine %s + + + der Vulkan von %s + + + die %s + + + die %s + + + eine mächtige Mauer + + + ein %s + + + + Krater + + + Pforte + + + Kohlenstück + + + Kohlenstücke + + + + + Westen + + + Nordwesten + + + Nordosten + + + Osten + + + Südwesten + + + Südosten + + + + NW + + + NO + + + Ost + + + SO + + + SW + + + West + + + + + ein unbekanntes Gebäude + an unknown building + + + ein unbekannter zauber + an unknown spell + + + ein unbekanntes Schiff + an unknown ship + + + eine unbekannte Einheit + an unknown unit + + + einer unbekannten Einheit + an unknown unit + + + + + Ereignisse + + + Botschaften + + + Warnungen und Fehler + + + Wirtschaft und Handel + + + Rohstoffe und Produktion + + + Magie und Artefakte + + + Reisen und Bewegung + + + Lehren und Lernen + + + Kämpfe + + + Verschiedenes + + + Neue Zauber + + + Neue Tränke + New Potions + + + + + Burg + + + Leuchtturm + + + Wurmloch + wormhole + + + Bergwerk + + + Steinbruch + + + Hafen + + + Akademie + + + Magierturm + + + Schmiede + + + Sägewerk + + + Pferdezucht + + + Monument + + + Damm + + + Karawanserei + + + Tunnel + + + Taverne + + + Steinkreis + + + Gesegneter Steinkreis + + + Traumschlößchen + + + Struktur + + + Akademie der Künste + academy of arts + + + Skulptur + sculpture + + + + + Zauberstab + + + Zauberstäbe + + + + + Grundmauern + + + Handelsposten + + + Befestigung + + + Turm + + + Burg + + + Festung + + + Zitadelle + + + + + Pyramide + pyramid + + + Pyramide + pyramid + + + + + Sphäre der Unsichtbarkeit + sphere of invisibility + + + Sphären der Unsichtbarkeit + spheres of invisibility + + + Kraut + + + Kräuterbeutel + + + Kräuterbeutel + + + Phiole + + + Phiolen + + + Katapultmunition + ammunition + + + Katapultmunition + ammunition + + + Sonnensegel + solar sail + + + Sonnensegel + solar sails + + + Weihnachtsbaum + christmas tree + + + Weihnachtsbäume + christmas trees + + + Sternenstaub + stardust + + + Sternenstaub + stardust + + + Papyrus + papyrus + + + Papyri + papyri + + + Elfenohr + elven ear + + + Elfenohren + elven ears + + + Dämonenblut + demon blood + + + Dämonenblut + demon blood + + + Goblinkopf + goblin head + + + Goblinköpfe + goblinheads + + + Zwergenbart + dwarven beard + + + Zwergenbärte + dwarven beards + + + Halblingfuß + halfling foot + + + Halblingfüße + halfling feet + + + Menschenskalp + human scalp + + + Menschenskalpe + human scalps + + + Meermenschschuppe + aquarian scale + + + Meermenschschuppen + aquarian scales + + + Insektenfühler + insect antenna + + + Insektenfühler + insect antenna + + + Katzenschwanz + cat tail + + + Katzenschwänze + cat tails + + + Orkhauer + orc tusk + + + Orkhauer + orc tusks + + + Trollhorn + troll horn + + + Trollhörner + troll horns + + + Feder des Phönix + feather of the phoenix + + + Federn des Phönix + feathers of the phoenix + + + + + Silber + + + Silber + + + Trefferpunkt + + + Trefferpunkte + + + Aura + + + Aura + + + permanente Aura + + + permanente Aura + + + Bauer + + + Bauern + + + Einheit + + + Einheiten + + + Person + + + Personen + + + + + Runenschwert + + + Runenschwerter + + + Eisen + + + Eisen + + + Holz + + + Holz + + + Stein + + + Steine + + + Wagen + + + Wagen + + + Katapult + + + Katapulte + + + Schwert + + + Schwerter + + + Speer + + + Speere + + + Mallornspeer + + + Mallornspeere + + + Armbrust + + + Armbrüste + + + Mallornarmbrust + + + Mallornarmbrüste + + + Bogen + + + Bögen + + + Mallornbogen + + + Mallornbögen + + + + Kettenhemd + + + Kettenhemden + + + Schuppenpanzer + + + Schuppenpanzer + + + Plattenpanzer + + + Plattenpanzer + + + Balsam + + + Balsam + + + Gewürz + + + Gewürze + + + Juwel + + + Juwelen + + + Myrrhe + + + Myrrhe + + + Öl + + + Öl + + + Seide + + + Seide + + + Weihrauch + + + Weihrauch + + + Flammenschwert + + + Flammenschwerter + + + Bihänder + + + Bihänder + + + Kriegsaxt + axe + + + Kriegsäxte + axes + + + Elfenbogen + + + Elfenbögen + + + Laenschwert + + + Laenschwerter + + + Laenschild + + + Laenschilde + + + Laenkettenhemd + + + Laenkettenhemden + + + Laen + + + Laen + + + Schild + + + Schilde + + + Hellebarde + + + Hellebarden + + + Lanze + + + Lanzen + + + Mallornlanze + + + Mallornlanzen + + + Mallorn + + + Mallorn + + + Keks + + + Kekse + + + Apfel + + + Äpfel + + + Nuß + + + Nüsse + + + Mandelkern + + + Mandelkerne + + + Drachenblut + + + Drachenblut + + + Feenstiefel + + + Feenstiefel + + + Heiltrank + + + Heiltränke + + + Antimagiekristall + + + Antimagiekristalle + + + Tiegel mit Krötenschleim + + + Tiegel mit Krötenschleim + + + Amulett + + + Amulette + + + Amulett der Keuschheit + + + Amulette der Keuschheit + + + Amulett der Heilung + + + Amulette der Heilung + + + Amulett des Treffens + + + Amulette des Treffens + + + Amulett des wahren Sehens + + + Amulette des wahren Sehens + + + Katzenamulett + + + Katzenamulette + + + Ring der Unsichtbarkeit + + + Ringe der Unsichtbarkeit + + + Ring der Macht + + + Ringe der Macht + + + Ring der flinken Finger + + + Ringe der flinken Finger + + + Pferd + + + Pferde + + + Magischer Kräuterbeutel + + + Magische Kräuterbeutel + + + Silberbeutel + + + Silberkassette + + + Drachenhort + + + Drachenkopf + + + Drachenköpfe + + + Auge des Drachen + + + Augen des Drachen + + + Schartiges Schwert + + + Schartige Schwerter + + + Rostiger Schild + + + Rostige Schilde + + + Rostige Hellebarde + rusty halberd + + + Rostige Hellebarden + rusty halberds + + + Rostige Kriegsaxt + rusty axe + + + Rostige Kriegsäxte + rusty axes + + + Rostiger Zweihänder + rusty claymore + + + Rostige Zweihänder + rusty claymores + + + Rostiges Kettenhemd + + + Rostige Kettenhemden + + + Beutel des negativen Gewichts + + + Beutel des negativen Gewichts + + + Ring der Regeneration + + + Ringe der Regeneration + + + Amulett der Dunkelheit + + + Amulette der Dunkelheit + + + Zauberbeutel + + + Zauberbeutel + + + Traumauge + + + Traumaugen + + + Seeschlangenkopf + + + Seeschlangenköpfe + + + Aurafocus + + + Aurafocuse + + + Akkredition des Xontormia-Expreß + + + Akkreditionen des Xontormia-Expreß + + + Szepter der Tränen + wand of tears + + + Szepter der Tränen + wands of tears + + + Schneeball + snowball + + + Schneebälle + snowball + + + Schneemann + snowman + + + Schneemänner + snowmen + + + Gürtel der Trollstärke + + + Gürtel der Trollstärke + + + Elfenpferd + + + Elfenpferde + + + Pegasus + + + Pegasi + + + Delphin + + + Delphine + + + Eintrittskarte des Großen Museum + + + Eintrittskarten des Großen Museum + + + Rückkehrticket des Großen Museum + + + Rückkehrtickets des Großen Museum + + + Astralkristall + + + Astralkristalle + + + Talenttrunk + + + Talenttrünke + + + Same + + + Samen + + + Mallornsame + + + Mallornsamen + + + Feuerwerk + + + Feuerwerke + + + Lebkuchenherz mit der Aufschrift 'Erz und + Stein, das ist fein' + + + Lebkuchenherzen mit der Aufschrift 'Erz und + Stein, das ist fein' + + + Schlüssel + key + + + Schlüssel + keys + + + Achatener Schlüssel + agate key + + + Achatene Schlüssel + agate keys + + + Saphirner Schlüssel + sapphire key + + + Saphirne Schlüssel + sapphire keys + + + + + Flachwurz + + + Würziger Wagemut + + + Eulenauge + + + Grüner Spinnerich + + + Blauer Baumringel + + + Elfenlieb + + + Gurgelkraut + + + Knotiger Saugwurz + + + Blasenmorchel + + + Wasserfinder + + + Kakteenschwitz + + + Sandfäule + + + Windbeutel + + + Fjordwuchs + + + Alraune + + + Steinbeißer + + + Spaltwachs + + + Höhlenglimm + + + Eisblume + + + Weißer Wüterich + + + Schneekristall + + + + + Flachwurz + + + Würzige Wagemut + + + Eulenaugen + + + Grüne Spinneriche + + + Blaue Baumringel + + + Elfenlieb + + + Gurgelkräuter + + + Knotige Saugwurze + + + Blasenmorcheln + + + Wasserfinder + + + Kakteenschwitze + + + Sandfäulen + + + Windbeutel + + + Fjordwuchse + + + Alraunen + + + Steinbeißer + + + Spaltwachse + + + Höhlenglimme + + + Eisblumen + + + Weiße Wüteriche + + + Schneekristalle + + + + Siebenmeilentee + + + Goliathwasser + + + Wasser des Lebens + + + Schaffenstrunk + + + Wundsalbe + + + Bauernblut + + + Gehirnschmalz + + + Dumpfbackenbrot + + + Nestwärme + + + Pferdeglück + + + Berserkerblut + + + Bauernlieb + + + Trank der Wahrheit + + + Elixier der Macht + + + Heiltrank + + + + Siebenmeilentees + + + Goliathwasser + + + Wasser des Lebens + + + Schaffenstrünke + + + Wundsalben + + + Bauernblut + + + Gehirnschmalz + + + Dumpfbackenbrote + + + Nestwärme + + + Pferdeglück + + + Berserkerblut + + + Bauernlieb + + + Tränke der Wahrheit + + + Elixiere der Macht + + + Heiltränke + + + + + Gürtel der Heldentaten + + + Gürtel der Heldentaten + + + + + AGGRESSIV + + + JEDEM + + + ALLES + + + ANZAHL + + + AURA + + + BÄUME + + + BAUERN + + + BEISTAND + + + BEWACHEN + + + BURG + + + DEFENSIV + + + EINHEIT + + + ERESSEA + + + FLIEHE + + + FREMDES + + + GEBÄUDE + + + GEGENSTÄNDE + + + GIB + + + GNADE + + + HELFE + + + HINTEN + + + HINTER + + + KOMMANDO + + + KRÄUTER + + + DURCHREISE + TRAVEL + + + KÄMPFE + + + NICHT + + + NÄCHSTER + + + PARTEI + + + PARTEITARNUNG + + + PAUSE + + + PERSONEN + + + PRIVAT + + + REGION + + + SCHIFF + + + SILBER + + + STRAßEN + + + STUFE + + + TEMPORÄRE + + + TRÄNKE + + + UM + + + VOR + + + VORNE + + + ZAUBER + + + + XETRANK + XEPOTION + + + XEBALLON + XEBALLOON + + + XELAEN + XELAEN + + + + + Alchemie + + + Armbrustschießen + + + Ausdauer + + + Bergbau + + + Bogenschießen + + + Burgenbau + + + Handeln + + + Hiebwaffen + + + Holzfällen + + + Katapultbedienung + + + Kräuterkunde + + + Magie + + + Pferdedressur + + + Reiten + + + Rüstungsbau + + + Schiffbau + + + Segeln + + + Spionage + + + Stangenwaffen + + + Steinbau + + + Steuereintreiben + + + Straßenbau + + + Taktik + + + Tarnung + + + Unterhaltung + + + Waffenbau + + + Waffenloser Kampf + + + Wagenbau + + + Wahrnehmung + + + + + + // + + + BANNER + + + ARBEITEN + + + WARTEN + WAIT + + + ATTACKIEREN + + + BIETEN + + + BEANSPRUCHEN + CLAIM + + + BEKLAUEN + + + BELAGERE + + + BENENNEN + + + BENUTZEN + + + BESCHREIBEN + + + BETRETEN + + + BEWACHEN + + + BOTSCHAFT + + + ENDE + + + FAHREN + + + NUMMER + + + FRIEDEN + PEACE + + + KRIEG + WAR + + + FOLGEN + + + FORSCHEN + + + HELFEN + + + KÄMPFEN + + + KAMPFZAUBER + + + KAUFEN + + + KONTAKTIEREN + + + LEHREN + + + LERNEN + + + LIEFERE + + + MACHEN + + + NACH + + + XONTORMIA + XONTORMIA + + + ALLIANZ + ALLIANCE + + + BEFÖRDERUNG + PROMOTION + + + BEZAHLEN + PAY + + + PFLANZEN + + + PRÄFIX + + + SYNONYM + + + INFO + + + PASSWORT + + + REKRUTIEREN + + + RESERVIEREN + + + ROUTE + + + SABOTIEREN + + + OPTION + + + SPIONIEREN + + + STIRB + + + TARNEN + + + TRANSPORTIEREN + + + TREIBEN + + + UNTERHALTEN + + + VERKAUFEN + + + VERLASSEN + + + VERGESSEN + + + ZAUBERE + + + ZEIGEN + + + ZERSTÖREN + + + ZÜCHTEN + + + DEFAULT + + + REPORT + + + XML + XML + + + URSPRUNG + + + EMAIL + + + PIRATERIE + + + LOCALE + + + NEUSTART + + + GRUPPE + + + OPFERE + + + BETEN + + + SORTIEREN + + + JIHAD + + + GM + + + WERWESEN + + + + + Optionen + + + Stufe + + + Aktueller Status + + + Benötigte Kräuter + + + im Bau + + + beschädigt + + + Unglücklicherweise wurde deine Partei + ausgelöscht. Du kannst gerne an einer anderen Stelle wieder + einsteigen. Melde Dich einfach wieder an. + + + Talente + + + hat + + + Größe + + + Zauber + + + Kampfzauber + + + keiner + + + Liste aller Adressen + + + anonym + + + Angriff + + + Verteidigung + + + Rüstung + + + Schaden + + + + + Deine Partei hat letzte Runde keinen Zug + abgegeben! + + + + + Schneemann + snowman + + + Schneemänner + snowmen + + + Klon + clone + + + Klone + clones + + + Klonen + clones + + + Klonen + clone + + + + Schablone + template + + + Schablonen + templates + + + Schablonen + templates + + + Schablonen + template + + + + Gnom + gnome + + + Gnome + gnomes + + + Gnomen + gnomes + + + Gnomen + gnome + + + + Museumsgeist + museumghost + + + Museumsgeister + museumghosts + + + Museumsgeistern + museumghosts + + + Museumsgeister + museumghost + + + + Ghast + ghast + + + Ghaste + ghasts + + + Ghasten + ghasts + + + Ghast + ghast + + + + Ghoul + ghoul + + + Ghoule + ghouls + + + Ghoulen + ghouls + + + Ghoul + ghoul + + + + Juju-Zombie + juju-zombie + + + Juju-Zombies + juju-zombies + + + Juju-Zombies + juju-zombies + + + Juju-Zombie + juju-zombie + + + + Zombie + zombie + + + Zombies + zombies + + + Zombies + zombies + + + Zombie + zombie + + + + Skelettherr + skeleton lord + + + Skelettherren + skeleton lords + + + Skelettherren + skeleton lords + + + Skelettherren + skeleton lord + + + + Skelett + skeleton + + + Skelette + skeletons + + + Skeletten + skeletons + + + Skelett + skeleton + + + + Zentaur + centaur + + + Zentauren + centaurs + + + Zentauren + centaurs + + + Zentauren + centaur + + + + Schattenritter + shadow knight + + + Schattenritter + shadow knight + + + Schattenrittern + shadow knights + + + Schattenritter + shadow knight + + + + Seeschlange + sea serpent + + + Seeschlangen + sea serpents + + + Seeschlangen + sea serpents + + + Seeschlangen + sea serpent + + + + Krake + kraken + + + Kraken + krakens + + + Kraken + krakens + + + Kraken + kraken + + + + Riesenschildkröte + giant turtle + + + Riesenschildkröten + giant turtles + + + Riesenschildkröten + giant turtles + + + Riesenschildkröten + giant turtle + + + + Delphin + dolphin + + + Delphine + dolphins + + + Delphinen + dolphins + + + Delphin + dolphin + + + + Tiger + tiger + + + Tiger + tiger + + + Tigern + tigers + + + Tiger + tiger + + + + Höllenkatze + hellcat + + + Höllenkatzen + hellcats + + + Höllenkatzen + hellcats + + + Höllenkatzen + hellcat + + + + Eule + owl + + + Eulen + owls + + + Eulen + owls + + + Eulen + owl + + + + Fee + fairy + + + Feen + fairies + + + Feen + fairies + + + Feen + fairy + + + + Traumkatze + dreamcat + + + Traumkatzen + dreamcats + + + Traumkatzen + dreamcats + + + Traumkatzen + dreamcat + + + + Teufelchen + imp + + + Teufelchen + imps + + + Teufelchen + imps + + + Teufelchen- + imp + + + + Geist + ghost + + + Geister + ghosts + + + Geistern + ghosts + + + Geister + ghost + + + + Warg + direwolf + + + Warge + direwolves + + + Wargen + direwolves + + + Warg + direwolf + + + + Einhorn + unicorn + + + Einhörner + unicorns + + + Einhörnern + unicorns + + + Einhorn + unicorn + + + + Nymphe + nymph + + + Nymphen + nymphs + + + Nymphen + nymphs + + + Nymphen + nymph + + + + Singdrache + song dragon + + + Singdrachen + song dragons + + + Singdrachen + song dragons + + + Singdrachen + song dragon + + + + Ratte + rat + + + Ratten + rats + + + Ratten + rats + + + Ratten + rat + + + + Adler + eagle + + + Adler + eagles + + + Adlern + eagles + + + Adler + eagle + + + + Tunnelwurm + tunnelworm + + + Tunnelwürmer + tunnelworms + + + Tunnelwürmern + tunnelworms + + + Tunnelwurm + tunnelworm + + + + Luchs + lynx + + + Luchse + lynx + + + Luchsen + lynx + + + Luchs + lynx + + + + Wolf + wolf + + + Wölfe + wolves + + + Wölfen + wolves + + + Wolfs + wolf + + + + Bauer + peasant + + + Bauern + peasants + + + Bauern + peasants + + + Bauern + peasant + + + + Hirntöter + braineater + + + Hirntöter + braineaters + + + Hirntöter + braineaters + + + Hirntöter + braineater + + + + Schlumpf + smurf + + + Schlümpfe + smurfs + + + Schlumpf + smurf + + + Schlümpfen + smurfs + + + + Kröte + toad + + + Kröten + toads + + + Kröten + toads + + + Kröten + toad + + + + Alp + nightmare + + + Alps + nightmaress + + + Alps + nightmares + + + Alp + nightmare + + + + Bergwächter + mountainguard + + + Bergwächter + mountainguard + + + Bergwächtern + mountainguards + + + Bergwächter + mountainguard + + + + Schattenmeister + shadowmaster + + + Schattenmeister + shadowmaster + + + Schattenmeistern + shadowmasters + + + Schattenmeister + shadowmaster + + + + Schattendämon + shadowdemon + + + Schattendämonen + shadowdemons + + + Schattendämonen + shadowdemons + + + Schattendämon + shadowdemon + + + + Steingolem + stone golem + + + Steingolems + stone golems + + + Steingolems + stone golems + + + Steingolem + stone golem + + + + Eisengolem + irongolem + + + Eisengolems + irongolems + + + Eisengolems + irongolems + + + Eisengolem + irongolem + + + + Zauber + spell + + + Zauber + spell + + + Zauber + spell + + + Zauber + spell + + + + Spezial + special + + + Spezial + special + + + Spezial + special + + + Spezial + special + + + + Dracoid + dracoid + + + Dracoide + dracoids + + + Dracoiden + dracoids + + + Dracoiden + dracoid + + + + Katzendrache + catdragon + + + Katzendrachen + catdragons + + + Katzendrachen + catdragons + + + Katzendrachen + catdragon + + + + Ent + ent + + + Ents + ents + + + Ents + ents + + + Ent + ent + + + + Schattendrache + shadow dragon + + + Schattendrachen + shadow dragons + + + Schattendrachen + shadow dragons + + + Schattendrachen + shadow dragon + + + + Todesflatter + darkbat + + + Todesflattern + darkbats + + + Todesflattern + darkbats + + + Todesflatter + darkbat + + + + Alptraum + nightmare + + + Alpträume + nightmares + + + Alpträumen + nightmares + + + Alptraum + nightmare + + + + Nachteinhorn + vampiric unicorn + + + Nachteinhörner + vampiric unicorns + + + Nachteinhörnern + vampiric unicorns + + + Nachteinhorn + vampiric unicorn + + + + Wyrm + wyrm + + + Wyrme + wyrms + + + Wyrmen + wyrms + + + Wyrm + wyrm + + + + Drache + dragon + + + Drachen + dragons + + + Drachen + dragons + + + Drachen + dragon + + + + Jungdrache + young dragon + + + Jungdrachen + young dragons + + + Jungdrachen + young dragons + + + Jungdrachen + young dragon + + + + Phönix + phoenix + + + Phönixe + phoenixes + + + Phönixen + phoenixes + + + Phönix + phoenix + + + + Illusion + illusion + + + Illusionen + illusions + + + Illusions + illusions + + + Illusions + illusion + + + + Spinx + sphinx + + + Spinxen + sphinxs + + + Spinxen + sphinx + + + Spinx + sphinx + + + + kleiner Scarabäus + little scarab + + + kleine Scarabäen + little scarab + + + kleinen Scarabäen + little scarab + + + kleine Scarabäen + little scarab + + + + grüner Scarabäus + green scarab + + + grüne Scarabäen + green scarab + + + grünen Scarabäen + green scarab + + + grünen Scarabäen + green scarab + + + + blauer Scarabäus + blue scarab + + + blaue Scarabäen + blue scarabs + + + blauen Scarabäen + blue scarab + + + blaue Scarabäen + blue scarab + + + + roter Scarabäus + red scarab + + + rote Scarabäen + red scarabs + + + roten Scarabäen + red scarab + + + rote Scarabäen + red scarab + + + + Untoter Pharao + undead Pharaoh + + + Untoter Pharaonen + undead Pharaohs + + + Untoten Pharao + undead Pharaoh + + + Untote Pharaonen + undead Pharaoh + + + + Mumie + mummy + + + Mumien + mummys + + + Mumien + mummy + + + Mumien + mummy + + + + Untoter + undead + + + Untote + undead + + + Untoten + undead + + + Untoten + undead + + + + Apepschlange + apepsnake + + + Apepschlangen + apepsnakes + + + Apepschlangen + apepsnakes + + + Apepschlange + apepsnake + + + + Apophis + apophis + + + Apophis + apophis + + + Apophis + apophis + + + Apophis + apophis + + + + Meermensch + aquarian + + + Meermenschen + aquarians + + + Meermenschen + aquarians + + + Meermenschen + aquarian + + + + Katze + cat + + + Katzen + cats + + + Katzen + cats + + + Katzen + cats + + + + Halbling + halfling + + + Halblinge + halflings + + + Halblingen + halflings + + + Halblings + halfling + + + + Insekt + insect + + + Insekten + insects + + + Insekten + insects + + + Insekten + insect + + + + Dämon + demon + + + Dämonen + demons + + + Dämonen + demons + + + Dämonen + demon + + + + Troll + troll + + + Trolle + trolls + + + Trollen + trolls + + + Troll + troll + + + + Mensch + human + + + Menschen + humans + + + Menschen + humans + + + Menschen + human + + + + Goblin + goblin + + + Goblins + goblins + + + Goblins + goblins + + + Goblin + goblin + + + + Ork + orc + + + Orks + orcs + + + Orks + orcs + + + Ork + orc + + + + Snotling + snotling + + + Snotlinge + snotlings + + + Snotlingen + snotlings + + + Snotling + snotling + + + + Snotling + snotling + + + Snotlinge + snotlings + + + Snotlingen + snotlings + + + Snotling + snotling + + + + Elf + elf + + + Elfen + elves + + + Elfen + elves + + + Elfen + elves + + + + Zwerg + dwarf + + + Zwerge + dwarves + + + Zwergen + dwarves + + + Zwergen + dwarf + + + + + + sehr stark + critically wounded + + + stark + heavily wounded + + + schwer verwundet + badly wounded + + + verwundet + wounded + + + erschöpft + exhausted + + + + + For Seven Mile Tea, boil up a Cobalt Fungus and pour the resulting brew into a Windbag. Catch and filter the liquid that drips out and administer it. This tea allows up to ten men to move as fast as a horse. + Für den Siebenmeilentee koche man einen Blauen Baumringel auf und gieße dieses Gebräu in einen Windbeutel. Das heraustropfende Wasser fange man auf, filtere es und verabreiche es alsdann. Durch diesen Tee können bis zu zehn Menschen schnell wie ein Pferd laufen. + + + 'First roast the Gurgelkraut quickly and add some Fjordwuchs to spice it up. Let it all boil slowly until almost all liquid has evaporated. Leave the mash overnight and finally squeeze it the next morning until a thick fluid drips out.' The liquid thus produced, 'Goliath Water' as we call it, is enough for 10 men and gives each man the carrying capacity of a horse for one week. + Zuerst brate man das Gurgelkraut leicht an und würze das Zeug mit ein wenig Fjordwuchs. Man lasse alles so lange kochen, bis fast alle Flüssigkeit verdampft ist. Diesen Brei stelle man über Nacht raus. Am nächsten Morgen presse man den Brei aus. Die so gewonnene Flüssigkeit, Goliathwasser genannt, verleiht bis zu zehn Männern die Tragkraft eines Pferdes. + + + The "Water of Life" allows living trees to be created from logs. A Knotroot and Elvendear are heated until one can just still keep one's finger in. This is then poured into a jar and allowed to cool slowly. The extract is sufficient for 10 pieces of wood. + Das 'Wasser des Lebens' ist in der Lage, aus gefällten Baumstämmen wieder lebende Bäume zu machen. Dazu wird ein knotiger Saugwurz zusammen mit einem Elfenlieb erwärmt, so daß man gerade noch den Finger reinhalten kann. Dies gieße man in ein Gefäß und lasse es langsam abkühlen. Der Extrakt reicht für 10 Holzstämme. + + + Allow a Tangy Temerity to simmer for three hours in a litre of water, then add a grated Mandrake, and sprinkle in a Gapgrowth harvested at full moon. The whole brew should then be allowed to stew for three days in a warm place. This potion increases the strength and endurance of ten men so that they can achieve twice as much in a week. + Man lasse einen Würzigen Wagemut drei Stunden lang in einem Liter Wasser köcheln. Dann gebe man eine geriebene Alraune dazu und bestreue das ganze mit bei Vollmond geerntetem Spaltwachs. Nun lasse man den Sud drei Tage an einem dunklen und warmen Ort ziehen und seie dann die Flüssigkeit ab. Dieser Schaffenstrunk erhöht die Kraft und Ausdauer von zehn Männern, so daß sie doppelt soviel schaffen können wie sonst. + + + When one is severely wounded after a hard battle it is advisable to have some Ointment to hand. Applied to wounds, this magical paste closes them in the blink of an eye. For the preparation the alchemist requires a cobalt fungus, tangy temerity, and white hemlock. A dose of the potion heals up to 400 hitpoints. + Ist man nach einem einem harten Kampf schwer verwundet, ist es ratsam, etwas Wundsalbe parat zu haben. Streicht man diese magische Paste auf die Wunden, schließen sich diese augenblicklich. Für die Herstellung benötigt der Alchemist nebst einem Blauen Baumringel einen Würzigen Wagemut und einen Weißen Wüterich. Eine solche Portion heilt bis zu 400 Lebenspunkte. + + + Knowledge of this potion is amongst the most dangerous and secret wisdom of the alchemist. Snatched from the darkest hells, the knowledge of this formula enables the production of an elixer which serves Demons as nourishment. If used by normal beings it leads to a swift death and eternal undeath. The creation requires Fjord Fungus together with some Cave Lichen and Cobalt Fungus, and an unfortunate peasant from the region, who is killed in the bloody days-long ritual. One vial of the potion satisfies the hunger of 100 Demons for a week. + Zu den gefährlichsten und geheimsten Wissen der Alchemisten zählt die Kenntnis um diesen Trank. Den finstersten Höllen entrissen, ermöglicht die Kenntnis dieser Formel die Herstellung eines Elixiers, welches Dämonen als Nahrung dient. Von normalen Lebewesen eingenommen, führt es zu schnellem Tod und ewigen Nichtleben. Die Herstellung benötigt nebst Fjordwuchs, etwas Höhlenglimm und einem Blauen Baumringel auch einen Bauern aus der Region, welcher in einem tagelangen blutigen Ritual getötet wird. Ein Fläschchen des Tranks kann den Hunger von 100 Dämonen für eine Woche stillen. + + + To create the brain wax potion, mix the juice of a waterfinder with quite a bit of grated windbag and a pinch of bugleweed. Let this steep for just a minute. When the liquid is only lukewarm, add some rock weed. Using a large spoon, stirr exactly seven times clockwise and then seven times counterclockwise. Fill the vial when the liquid has gone still. The juice gives ten people a 33% chance of an additional attempt at learning a skill. + Für das Gehirnschmalz verrühre man den Saft eines Wasserfinders mit recht viel geriebenem Windbeutel und ein wenig Gurgelkraut. Dies lasse man kurz aufwallen. Wenn die Flüssigkeit nur noch handwarm ist, gebe man etwas Steinbeißer dazu. Das ganze muß genau siebenmal rechtsherum und siebenmal linksherum mit einem großen Löffel gerührt werden. Wenn keine Bewegung mehr zu erkennen ist, fülle man den Saft ab. Der Saft gibt mit einer Chance von 1/3 bis zu zehn Personen einen zusätzlichen Lernversuch. + + + A duncebun is a nasty piece of work, negating any attempt at learning a skill, or even causing the subject to forget things! For ten servings knead a rasped fjord fungus, an abraded owlsgaze and a finely sliced spider ivy to a smooth dough. Bake for an hour at moderate heat and brush the result with some cave lichen. Who eats this bread will not learn what he's attempting to learn, and, in case there is no attempt to learn anything, will forget a week's worth of study in his best skill. + Das Dumpfbackenbrot ist eine sehr gemeine Sache, macht es doch jeden Lernerfolg zunichte oder läßt einen gar Dinge vergessen! Für zehn Portionen verknete man einen geriebenen Fjordwuchs, einen zerstoßenes Eulenauge und einen kleingeschnittenen Grünen Spinnerich zu einem geschmeidigen Teig. Diesen backe man eine Stunde lang bei guter Hitze und bestreiche das Ergebnis mit etwas Höhlenglimm. Wer dieses Brot gegessen hat, kann eine Woche lang nichts lernen, und so er nichts zu lernen versucht, wird er gar eine Woche seiner besten Fähigkeit vergessen. + + + A potion of nest warmth allows an insect to recruit outside of a desert region in winter. The learned alchemist prepares this by taking a peyote, mixing it with a portion of gapgrowth which has been gathered during a clear, starry night. To dispell winter, add some blossoms of the ice begonia in the mix, and stirr everything together with a spider ivy until it turns a nice shade of violet. One vial supplies an entire region for a whole week. + Nestwärme erlaubt es einem Insekt, im Winter außerhalb von Wüsten neue Rekruten anzuwerben. Zur Zubereitung nimmt der geübte Alchemist einen Kakteenschwitz, vermischt ihn mit einer Portion Spaltwachs, die in einer sternklaren Nacht gesammelt wurde, gibt zur Vertreibung des Winters einige Blütenblätter der Eisblume in den Sud, und rührt alles mit einem grünen Spinnerich bis es eine violette Farbe annimmt. Ein Trank reicht eine Woche lang für eine ganze Region. + + + To make a horsepower potion, chop a peyote, a cobalt fungus and some knotroot, and boil it in a bucketful of water. Then add some sand reeker and let the mixture steep for three days. Finally one gives this to the horses to drink, to double their procreation. + Für das Pferdeglück zerhacke man einen Kakteenschwitz, einen blauen Baumringel und etwas knotigen Saugwurz und koche das ganze mit einem Eimer Wasser auf. Dann füge man etwas Sandfäule dazu und lasse diesen Sud drei Tage lang ziehen. Letztlich gebe man es den Pferden zu trinken, auf daß sie sich doppelt so schnell vermehren. + + + The use of the berserkers blood potion is advised to increase one's warriors abilities to new heights. To create this, one needs a white hemlock, some flatroot, sand reeker and a mandrake. All ingredients have to be sliced as finely as possible, after which it is boiled for two hours. The cooled brew is strained through a cloth. The resulting juice is enough to improve up to ten warriors. + Will man seine Krieger zu Höchstleistungen antreiben, sei das Berserkerblut empfohlen. Um es herzustellen, braucht man einen Weißen Wüterich, etwas Flachwurz, Sandfäule und eine Alraune. Alle Zutaten müssen möglichst klein geschnitten und anschließend zwei Stunden lang gekocht werden. Den abgekühlten Brei gebe man in ein Tuch und presse ihn aus. Der so gewonnene Saft reicht aus, um zehn Kämpfer besser angreifen zu lassen. + + + The peasant love potion enamors both Man and Woman to the same degree and results in a strong wish for children. For a big portion scoop out a mandrake, fill it with finely chopped bubblemorel, elvendear and snowcrystal petal, sprinkle grated rock weed on top and let it simmer on low heat for twenty hours. The potion can grant up to 1000 peasants the happiness of twins. + Das Bauernlieb betört Mann und Frau gleichwohl und läßt in ihnen den Wunsch nach Kindern anwachsen. Für eine große Portion höhle man eine Alraune aus, gebe kleingehackten Blasenmorchel, Elfenlieb und Schneekristall dazu, streue ein wenig geriebenen Steinbeißer darüber und lasse dieses zwanzig Stunden lang auf kleiner Flamme kochen. Bis zu 1000 Bauern vermag der Trank das Glück von Zwillinge zu bescheren. + + + This simple but very potent brew sharpens the senses of anyone that drinks of it and makes him able to see through even the most complex illusions for one week. + Dieses wirkungsvolle einfache Gebräu schärft die Sinne des Trinkenden derart, daß er in der Lage ist, eine Woche lang auch die komplexesten Illusionen zu durchschauen. + + + One of the most rare and prized of all alchemist elixers, this potion grants the user a dragon's power for a few weeks. The potion increases the life-energy of a maximum of ten people fivefold. The effect is strongest right after drinking and slowly decreases over time. To brew this potion the alchemist needs an elvendear, a windbag, a piece of waterfinder and a spider ivy. Finally he dusts it with some minced bubblemorel and stirrs the powder into some dragon's blood. + Eines der seltensten und wertvollsten alchemistischen Elixiere, verleiht dieser Trank dem Anwender für einige Wochen die Kraft eines Drachen. Der Trank erhöht die Lebensenergie von maximal zehn Personen auf das fünffache. Die Wirkung ist direkt nach der Einnahme am stärksten und klingt danach langsam ab. Zur Herstellung benötigt der Alchemist ein Elfenlieb, einen Windbeutel, ein Stück Wasserfinder und einen Grünen Spinnerich. Über dieses Mischung streue er schließlich einen zerriebenen Blasenmorchel und rühre dieses Pulver unter etwas Drachenblut. + + + For a healing potion one takes the peel of a windbag and some bugleweed, stirr in some chopped elvendear and sprinkle it with the blossoms of an ice begonia. This has to cook through for four days, while a gapgrowth has to be added on the second day. Then one carefully scoops off the top layer of liquid. One such potion gives four men (or one man four times) a 50% chance to survive otherwise lethal wounds. The potion is automatically used in case of injury. + Für einen Heiltrank nehme man die Schale eines Windbeutels und etwas Gurgelkraut, rühre eine kleingehacktes Elfenlieb dazu und bestreue alles mit den Blüten einer Eisblume. Dies muß vier Tage lang gären, wobei man am zweiten Tag einen Spaltwachs dazutun muß. Dann ziehe man vorsichtig den oben schwimmenden Saft ab. Ein solcher Trank gibt vier Männern (oder einem Mann vier mal) im Kampf eine Chance von 50%, sonst tödliche Wunden zu überleben. Der Trank wird von ihnen automatisch bei Verletzung angewandt. + + + + + Erschaffe einen Ring der Macht + Create A Ring Of Power + + + Schild des Fisches + Shield Of The Fish + + + Runen des Schutzes + Protective Runes + + + Ruf der Realität + Call Of Reality + + + Astraler Ruf + Astral Call + + + Magiefresser + Destroy Magic + + + Mauern der Ewigkeit + Eternal Walls + + + Stehle Aura + Steal Aura + + + Schutzzauber + Resist Magic + + + Astraler Blick + Astral Gaze + + + Auratransfer + Transfer Aura + + + Monster friedlich stimmen + Calm Monster + + + Luftschiff + Airship + + + Lied der Verführung + Song Of Seduction + + + Schaler Wein + Hangover + + + Aushorchen + sound_out + + + Kriegsgesang + Song Of War + + + Gesang der Angst + Song Of Fear + + + Lied des Ortes analysieren + Analysis + + + Schockwelle + Shockwave + + + Fluch brechen + Negate Curse + + + Erschaffe ein Amulett der Keuschheit + Create An Amulet Of Chastity + + + Beschleunigung + Acceleration + + + Großer Drachenodem + Powerful Dragonbreath + + + Opfere Kraft + Sacrifice Strength + + + Belebtes Gestein + Living Rock + + + Gesang der Melancholie + Song of Melancholy + + + Gesang des wachen Geistes + Song Of The Youthful Spirit + + + Gesang des schwachen Geistes + Song Of The Aging Spirit + + + Gesang der Friedfertigkeit + Song Of Peace + + + Gesang der Versklavung + Song Of Slavery + + + Hohe Kunst der Überzeugung + Song Of Slavery + + + Zeitdehnung + Double Time + + + Vertrauten rufen + Summon Familiar + + + Rüstschild + Shield Shine + + + Wyrmtransformation + Wyrmtransformation + + + Schattenodem + Shadowbreath + + + Feuersturm + Firestorm + + + Feuerwalze + Immolation + + + Eisnebel + Coldfront + + + Säurenebel + Acid Rain + + + Furchteinflößende Aura + Panic + + + Meteorregen + Meteor Shower + + + Schattenruf + Shadow Call + + + Erschaffe einen Ring der Regeneration + Create A Ring Of Regeneration + + + Mob aufwiegeln + Mob Rule + + + Aufruhr beschwichtigen + Calm Riot + + + Aufruhr verursachen + Riot + + + Blick in die Realität + Gaze Upon Reality + + + Störe Astrale Integrität + Astral Disruption + + + Eisiger Drachenodem + Icy Dragonbreath + + + Eisiger Drachenodem + Icy Dragonbreath + + + Erschaffe ein Runenschwert + Create A Runesword + + + Erschaffe einen Beutel des Negativen Gewichts + Create A Bag Of Holding + + + Erschaffe einen Aurafocus + Create An Aurafocus + + + Erschaffe Antimagiekristall + Create An Antimagic Crystal + + + Astrale Schwächezone + Antimagic + + + Astraler Ausgang + Astral Exit + + + Astraler Weg + Astral Path + + + Beute Bewahren + Save Spoils + + + Schutz vor Magie + Protection from Magic + + + Wunderdoktor + Miracle Doctor + + + Schleieraura + Concealing Aura + + + Magie analysieren + Analyze Magic + + + Hohes Lied der Gaukelei + Song of Generosity + + + Gesang des Werbens + Song of Courting + + + Schleieraura + Veil + + + Lied der Heilung + Blessed Harvest + + + Gesang der Furcht + Song of Terror + + + Segen der Erde + Blessed Harvest + + + Heldengesang + Epic Heroes + + + Gesang des Lebens analysieren + Analyze Song of Life + + + Bannlied + Countersong + + + Gesang des Auratransfers + Hymn of Aura Sharing + + + Gesang der Verwirrung + Song of Confusion + + + Plappermaul + Blabbermouth + + + Regentanz + Rain Dance + + + Gaukeleien + Jugglery + + + Friedenslied + Appeasing Song + + + Viehheilung + Cattle Healing + + + Erschaffe Steingolems + Create Stone Golems + + + Erschaffe Eisengolems + Create Iron Golems + + + Hainzauber + Grove Of Oak Trees + + + Rostregen + Rain Of Rust + + + Firuns Fell + Firun's Coat + + + Hagel + Hail + + + Seelenkopie + Doppelganger + + + Irrlichter + Wisps + + + Schlechte Träume + Bad Dreams + + + Bergwächter + Mountain Guardian + + + Magischer Pfad + Magic Path + + + Tor in die Ebene der Hitze + Great Drought + + + Wurzeln der Magie + Roots Of Magic + + + Mahlstrom + Maelstrom + + + Windschild + Air Shield + + + Segne Mallornstecken + Bless Mallorn Logs + + + Beschwörung eines + Wasserelementares + Summon Water Elemental + + + Heilung + Heal + + + Wirbelwind + Whirlwind + + + Astralschutzgeister + Astral Guardian Spirits + + + Meditation + Meditate + + + Beschwöre einen Erdelementar + Summon Earth Elemental + + + Beschwöre einen Sturmelementar + Summon Storm Elemental + + + Erschaffe ein Amulett des wahren + Sehens + Create An Amulet Of True Sight + + + Erschaffe einen Ring der + Unsichtbarkeit + Create A Ring Of Invisibility + + + Miriams flinke Finger + Quick Fingers + + + Heimstein + Homestone + + + Wolfsgeheul + Timber Wolves + + + Blick des Basilisken + Gaze Of The Basilisk + + + Starkes Tor und feste Mauer + Strong Wall And Sturdy Gate + + + Geister bannen + Banish Spirits + + + Lebenslied festigen + Silence Dissonance + + + Ritual der Aufnahme + Rit of Acceptance + + + Weg der Bäume + Path Of Trees + + + Sog des Lebens + Ties Of Life + + + Heiliger Boden + Sacred Ground + + + Erschaffe einen magischen + Kräuterbeutel + Create A Magical Herb Pouch + + + Erwecke Ents + Awakening Of The Ents + + + Vertrauten binden + Bind Familiar + + + Segne Steinkreis + Bless Stone Circle + + + Rindenhaut + Barkskin + + + Verwünschung + Hex + + + Kleine Flüche + Minor Curses + + + Feuerball + Fireball + + + Gabe des Chaos + Chaos Gift + + + Kleines Blutopfer + Lesser Sacrifice + + + Blutrausch + Blood Frenzy + + + Chaosfluch + Chaos Curse + + + Mächte des Todes + Animate Dead + + + Rosthauch + Winds Of Rust + + + Machtübertragung + Transfer Power + + + Feuerwand + Wall Of Fire + + + Fluch der Pestilenz + Curse Of Pestilence + + + Wahnsinn des Krieges + Madness of War + + + Beschwöre Schattendämonen + Summon Shadowdemons + + + Beschwörung eines Hitzeelementar + Summon Fire Elemental + + + Untote Helden + Undead Heroes + + + Erschaffe einen Gürtel der + Trollstärke + Create A Belt Of Troll + Strength + + + Astraler Riss + Astral Leak + + + Astrales Chaos + Astral Chaos + + + Feuerteufel + Fire Fiend + + + Pentagramm + Pentagram + + + Unheilige Kraft + Unholy Strength + + + Todeswolke + Death Cloud + + + Drachenruf + Call Dragons + + + Beschwöre Schattenmeister + Summon Shadowmasters + + + Erschaffe ein Flammenschwert + Create A Flamesword + + + Vertrauten rufen + Call Familiar + + + Chaossog + Chaos Gate + + + Traumsenden + Dream + + + Wahrsagen + Divination + + + Schattenritter + Shadow Knights + + + Grauen der Schlacht + Unspeakable Horrors + + + Seelenfrieden + Eternal Rest + + + Traumschlößchen + Castle Of Illusion + + + Traum der Magie + Dream Of Magic + + + Gestaltwandlung + Shapeshift + + + Traumlesen + Read Dreams + + + Schwere Glieder + Tiredness + + + Wiederbelebung + Resurrection + + + Traumbilder analysieren + Analyse Dreams + + + Schlechter Schlaf + Insomnia + + + Schlaf + Sleep + + + Traumdeuten + Mind Probe + + + Alp + Nightmare + + + Erschaffe ein Traumauge + Create a Visioneye + + + Erschaffe eine Sphäre der Unsichtbarkeit + Create a Sphere of Invisbility + + + Schöne Träume + Pleasant Dreams + + + Traumbilder entwirren + Remove Dreams + + + Vertrauten rufen + Call Familiar + + + Tod des Geistes + Mental Death + + + Süße Träume + Sweet Dreams + + + Traum von den Göttern + Dream of the gods + + + Göttliches Netz + Web of the Gods + + + Kraft der Natur + force of nature + + + Gesang der Götter + Song of the Gods + + + Göttliche Macht + Power of the Gods + + + + + Tötet die Feinde mit Säure. + Kills enemies with acid. + + + Tötet die Feinde mit Kälte. + Kills enemies with cold. + + + Tötet die Feinde mit Feuer. + Kills enemies with fire. + + + Verletzt alle Gegner. + Injures all enemies. + + + Ruft Schattenwesen. + Calls beings from shadow. + + + Panik. + Panic. + + + Entzieht Talentstufen und macht Schaden wie Großer Odem. + + + Dieser Zauber bewirkt eine schwere Störung des Astralraums. Innerhalb eines astralen Radius von Stufe/5 Regionen werden alle Astralwesen, die dem Zauber nicht wiederstehen können, aus der astralen Ebene geschleudert. Der astrale Kontakt mit allen betroffenen Regionen ist für Stufe/3 Wochen gestört. + + + + Diese vor dem Kampf zu zaubernde Ritual gibt den eigenen Truppen + einen zusätzlichen Bonus auf ihre Rüstung. Jeder Treffer + reduziert die Kraft des Zaubers, so dass der Schild sich irgendwann + im Kampf auflösen wird. + + + + + Dieser Zauber beschleunigt einige Kämpfer auf der eigenen Seite + so, dass sie während des gesamten Kampfes in einer Kampfrunde zweimal + angreifen können. + + + + + Dieser Zauber vermag dem Gegner ein geringfügig versetztes Bild der + eigenen Truppen vorzuspiegeln, so wie der Fisch im Wasser auch nicht + dort ist wo er zu sein scheint. Von jedem Treffer kann so die Hälfte + des Schadens unschädlich abgeleitet werden. Doch hält der Schild nur + einige Hundert Schwerthiebe aus, danach wird er sich auflösen. + Je stärker der Magier, desto mehr Schaden hält der Schild aus. + + + + + Zeichnet man diese Runen auf die Wände eines Gebäudes oder auf die + Planken eines Schiffes, so wird es schwerer durch Zauber zu + beeinflussen sein. Jedes Ritual erhöht die Widerstandskraft des + Gebäudes oder Schiffes gegen Verzauberung um 20%. + Werden mehrere Schutzzauber übereinander gelegt, so addiert + sich ihre Wirkung, doch ein hundertprozentiger Schutz läßt sich so + nicht erreichen. Der Zauber hält mindestens drei Wochen an, je nach + Talent des Magiers aber auch viel länger. + + + + + Mit Hilfe dieses Zauber kann der Magier eigene Aura im Verhältnis + 2:1 auf einen anderen Magier des gleichen Magiegebietes oder im + Verhältnis 3:1 auf einen Magier eines anderen Magiegebietes + übertragen. + + + + + Der Magier kann kurzzeitig in die Astralebene blicken und erfährt + so alle Einheiten innerhalb eines astralen Radius von Stufe/5 Regionen. + + + + + Mit Hilfe dieses magischen Gesangs kann der Magier eine Region in + Aufruhr wieder beruhigen. Die Bauernhorden werden sich verlaufen + und wieder auf ihre Felder zurückkehren. + + + + Aus 'Wanderungen' von Firudin dem Weisen: + 'In Weilersweide, nahe dem Wytharhafen, liegt ein kleiner Gasthof, der + nur wenig besucht ist. Niemanden bekannt ist, das dieser Hof + bis vor einigen Jahren die Bleibe des verbannten Wanderpredigers Grauwolf + war. Nachdem er bei einer seiner berüchtigten flammenden Reden fast die + gesammte Bauernschaft angeworben hatte, wurde er wegen Aufruhr verurteilt + und verbannt. Nur zögerlich war er bereit mir das Geheimniss seiner + Überzeugungskraft zu lehren.' + + + + Dieser mächtige Bann raubt dem Opfer seinen freien Willen + und unterwirft sie den Befehlen des Barden. Für einige Zeit wird das Opfer + sich völlig von seinen eigenen Leuten abwenden und der Partei des Barden + zugehörig fühlen. + + + + + Dieser mächtige Bann verhindert jegliche Attacken. Niemand in der + ganzen Region ist fähig seine Waffe gegen irgendjemanden zu erheben. + Die Wirkung kann etliche Wochen andauern. + + + + + Dieses Lied, das in die magische Essenz der Region gewoben wird, + schwächt die natürliche Widerstandskraft gegen eine + Verzauberung einmalig um 15%. Nur die Verbündeten des Barden + (HELFE BEWACHE) sind gegen die Wirkung des Gesangs gefeit. + + + + + Mit diesem Gesang verbreitet der Barde eine melancholische, traurige + Stimmung unter den Bauern. Einige Wochen lang werden sie sich in ihre + Hütten zurückziehen und kein Silber in den Theatern und Tavernen lassen. + + + + + Dieses magische Lied wird, einmal mit Inbrunst gesungen, sich in der + Region fortpflanzen, von Mund zu Mund springen und eine Zeitlang + überall zu vernehmen sein. Nach wie vielen Wochen der Gesang aus dem + Gedächnis der Region entschwunden ist, ist von dem Geschick des Barden + abhängig. Bis das Lied ganz verklungen ist, wird seine Magie allen + Verbündeten des Barden (HELFE BEWACHE), und natürlich auch seinen + eigenem Volk, einen einmaligen Bonus von 15% + auf die natürliche Widerstandskraft gegen eine Verzauberung + verleihen. + + + + + Mit Hilfe dieses magischen Gesangs überzeugt der Magier die Bauern + der Region, sich ihm anzuschließen. Die Bauern werden ihre Heimat jedoch + nicht verlassen, und keine ihrer Besitztümer fortgeben. Jede Woche + werden zudem einige der Bauern den Bann abwerfen und auf ihre Felder + zurückkehren. Wie viele Bauern sich dem Magier anschließen hängt von der + Kraft seines Gesangs ab. + + + + + Einem erfahrenen Magier wird irgendwann auf seinen Wanderungen ein + ungewöhnliches Exemplar einer Gattung begegnen, welches sich dem + Magier anschließen wird. + + + + + Dieses Ritual ermöglicht es, eine Einheit, egal welcher Art, in die + eigene Partei aufzunehmen. Der um Aufnahme Bittende muss dazu willig + und bereit sein, seiner alten Partei abzuschwören. Dies bezeugt er + durch KONTAKTIEREn des Magiers. Auch wird er die Woche über + ausschliesslich mit Vorbereitungen auf das Ritual beschäftigt sein. + Das Ritual wird fehlschlagen, wenn er zu stark an seine alte Partei + gebunden ist, dieser etwa Dienst für seine teuere Ausbildung + schuldet. Der das Ritual leitende Magier muss für die permanente + Bindung des Aufnahmewilligen an seine Partei naturgemäß auch + permanente Aura aufwenden. Pro Stufe und pro 1 permanente Aura kann + er eine Person aufnehmen. + + + + + Jede Verzauberung beeinflußt das Lebenslied, schwächt und verzerrt es. + Der kundige Barde kann versuchen, das Lebenslied aufzufangen und zu + verstärken und die Veränderungen aus dem Lied zu tilgen. + + + + + Wie Lebewesen, so haben auch Schiffe und Gebäude und sogar Regionen + ihr eigenes Lied, wenn auch viel schwächer und schwerer zu hören. + Und so, wie wie aus dem Lebenslied einer Person erkannt werden kann, + ob diese unter einem Zauber steht, so ist dies auch bei Burgen, + Schiffen oder Regionen möglich. + + + + + Dieser Kriegsgesang sät Panik in der Front der Gegner und schwächt + so ihre Kampfkraft erheblich. Angst wird ihren Schwertarm schwächen + und Furcht ihren Schildarm lähmen. + + + + + Wie viele magischen Gesänge, so entstammt auch dieser den altem + Wissen der Katzen, die schon immer um die machtvolle Wirkung der + Stimme wussten. Mit diesem Lied wird die Stimmung der Krieger + aufgepeitscht, sie gar in wilde Raserrei und Blutrausch versetzt. + Ungeachtet eigener Schmerzen werden sie kämpfen bis zum + Tode und niemals fliehen. Während ihre Attacke verstärkt ist + achten sie kaum auf sich selbst. + + + + + Erliegt die Einheit dem Zauber, so wird sie dem Magier alles erzählen, + was sie über die gefragte Region weiß. Ist in der Region niemand + ihrer Partei, so weiß sie nichts zu berichten. Auch kann sie nur das + erzählen, was sie selber sehen könnte. + + + + + Aufzeichung des Vortrags von Selen Ard'Ragorn in Bar'Glingal: + 'Es heiss, dieser Spruch wäre wohl in den Spelunken der Westgassen + entstanden, doch es kann genausogut in jedem andern verrufenen + Viertel gewesen sein. Seine wichtigste Zutat ist etwa ein Fass + schlechtesten Weines, je billiger und ungesunder, desto + wirkungsvoller wird die Essenz. Die Kunst, diesen Wein in pure + Essenz zu destillieren, die weitaus anspruchsvoller als das einfache + Rezeptmischen eines Alchemisten ist, und diese dergestalt zu binden + und konservieren, das sie sich nicht gleich wieder verflüchtigt, wie + es ihre Natur wäre, ja, dies ist etwas, das nur ein Meister des + Cerddor vollbringen kann. Nun besitzt Ihr eine kleine Phiola mit + einer rubinrotschimmernden - nun, nicht flüssig, doch auch nicht + ganz Dunst - nennen wir es einfach nur Elixier. Doch nicht dies ist + die wahre Herausforderung, sodann muss, da sich ihre Wirkung leicht + verflüchtigt, diese innerhalb weniger Tage unbemerkt in das Getränk + des Opfers geträufelt werden. Ihr Meister der Betöhrung und + Verführung, hier nun könnt Ihr Eure ganze Kunst unter Beweis + stellen. Doch gebt Acht, nicht unbedacht selbst von dem Elixier zu + kosten, denn wer einmal gekostet hat, der kann vom Weine nicht mehr + lassen, und er säuft sicherlich eine volle Woche lang. Jedoch nicht + die Verführung zum Trunke ist die wahre Gefahr, die dem Elixier + innewohnt, sondern das der Trunkenheit so sicher ein gar + fürchterliches Leid des Kopfes folgen wird, wie der Tag auf die + Nacht folgt. Und er wird gar sicherlich von seiner besten Fähigkeit + einige Tage bis hin zu den Studien zweier Wochen vergessen haben. + Noch ein Wort der Warnung: Dieses ist sehr aufwendig, und so Ihr + noch weitere Zauber in der selben Woche wirken wollt, so werden sie Euch + schwerer fallen.' + + + + + Mit diesem Lied kann eine Einheit derartig betört werden, so dass + sie dem Barden den größten Teil ihres Bargelds und ihres Besitzes + schenkt. Sie behält jedoch immer soviel, wie sie zum Überleben + braucht. + + + + + Dieser einschmeichelnde Gesang kann fast jedes intelligente Monster + zähmen. Es wird von Angriffen auf den Magier absehen und auch seine + Begleiter nicht anrühren. Doch sollte man sich nicht täuschen, es + wird dennoch ein unberechenbares Wesen bleiben. + + + + + Dieser Zauber ermöglicht es dem Träumer, den Schlaf aller nichtaliierten + Einheiten (HELFE BEWACHE) in der Region so stark zu stören, das sie + vorübergehend einen Teil ihrer Erinnerungen verlieren. + + + + + Dieser mächtige Zauber kann einen Magier vor dem sicheren Tod + bewahren. Der Magier erschafft anhand einer kleinen Blutprobe einen + Klon von sich, und legt diesen in ein Bad aus Drachenblut und verdünntem + Wasser des Lebens. + Anschließend transferiert er in einem aufwändigen Ritual einen Teil + seiner Seele in den Klon. Stirbt der Magier, reist seine Seele in den + Klon und der erschaffene Körper dient nun dem Magier als neues Gefäß. + Es besteht allerdings eine geringer Wahrscheinlichkeit, dass die Seele + nach dem Tod zu schwach ist, das neue Gefäß zu erreichen. + + + + + Der Zauberer spricht eine Beschwörung über einen Teil der Region, + und in der Folgewoche entstehen dort Irrlichter. + Wer durch diese Nebel wandert, wird von Visionen geplagt und + in die Irre geleitet. + + + + + Dieses mächtige Ritual öffnet ein Tor in die Elementarebene der + Hitze. Eine grosse Dürre kommt über das Land. Bauern, Tiere und + Pflanzen der Region kämpfen um das nackte Überleben, aber eine + solche Dürre überlebt wohl nur die Hälfte aller Lebewesen. + Der Landstrich kann über Jahre hinaus von den Folgen einer + solchen Dürre betroffen sein. + + + + + Mit Hilfe dieses aufwändigen Rituals läßt der Druide einen Teil seiner Kraft + dauerhaft in den Boden und die Wälder der Region fliessen. Dadurch wird + das Gleichgewicht der Natur in der Region für immer verändert, und in + Zukunft werden nur noch die anspruchsvollen, aber kräftigen + Mallorngewächse in der Region gedeihen. + + + + + Dieses Ritual beschört einen großen Wasserelementar aus den + Tiefen des Ozeans. Der Elementar erzeugt einen gewaltigen + Strudel, einen Mahlstrom, welcher alle Schiffe, die ihn passieren, + schwer beschädigen kann. + + + + + Mit Hilfe dieses Zaubers kann sich der Magier permanent in einen + mächtigen Wyrm verwandeln. Der Magier behält seine Talente und + Möglichkeiten, bekommt jedoch die Kampf- und Bewegungseigenschaften + eines Wyrms. Der Odem des Wyrms wird sich mit steigendem Magie-Talent + verbessern. Der Zauber ist sehr kraftraubend und der Wyrm wird einige + Zeit brauchen, um sich zu erholen. + + + + + Mit Hilfe dieses magischen Gesangs versetzt der Magier eine ganze + Region in Aufruhr. Rebellierende Bauernhorden machen jedes Besteuern + unmöglich, kaum jemand wird mehr für Gaukeleien Geld spenden und + es können keine neuen Leute angeworben werden. Nach einigen Wochen + beruhigt sich der Mob wieder. + + + + + Der Magier kann mit Hilfe dieses Zaubers aus der Astral- in die + materielle Ebene blicken und die Regionen und Einheiten genau + erkennen. + + + + + Einem erfahrenen Magier wird irgendwann auf seinen Wanderungen ein + ungewöhnliches Exemplar einer Gattung begegnen, welches sich dem + Magier anschließen wird. + + + + + Dieses kräftezehrende Ritual beschwört mit Hilfe einer Kugel aus + konzentriertem Laen einen gewaltigen Erdelementar und bannt ihn + in ein Gebäude. Dem Elementar kann dann befohlen werden, das + Gebäude mitsamt aller Bewohner in eine Nachbarregion zu tragen. + Die Stärke des beschworenen Elementars hängt vom Talent des + Magiers ab: Der Elementar kann maximal [Stufe-12]*250 Größeneinheiten + große Gebäude versetzen. Das Gebäude wird diese Prozedur nicht + unbeschädigt überstehen. + + + + Dieses Amulett in Gestalt einer orkischen Matrone + unterdrückt den Fortpflanzungstrieb eines einzelnen Orks sehr + zuverlässig. + Ein Ork mit Amulett der Keuschheit wird sich nicht mehr vermehren. + + + Dieser Zauber ermöglicht dem Magier, gezielt eine + bestimmte Verzauberung einer Einheit, eines Schiffes, Gebäudes oder auch + der Region aufzulösen. + This spell allows a magician to remove a specific + enchantment from a unit, ship, bulding or region. + + + Ein Schauer von Meteoren regnet über das Schlachtfeld. + A meteor shower rains down on the battlefield. + + + 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. + 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. + + + Mit dieser Formel bindet der Magier auf ewig die + Kräfte + der Erde in die Mauern des Gebäudes. Ein solchermaßen verzaubertes + Gebäude + ist gegen den Zahn der Zeit geschützt und benötigt keinen Unterhalt + mehr. + With this spell, the magician binds the power of the + earth into the walls of a building for all eternity. Such a building is + immune to the sands of time and needs no maintenance cost. + + + Ein Magier, der sich in der astralen Ebene befindet, + kann mit Hilfe dieses Zaubers andere Einheiten zu sich holen. Der Magier + kann (Stufe-3)*15 GE durch das kurzzeitig entstehende Tor schicken. Ist + der Magier erfahren genug, den Zauber auf Stufen von 13 oder mehr zu + zaubern, kann er andere Einheiten auch gegen ihren Willen auf die + andere + Ebene zwingen. + A magician in the astral plane can summon units from + the + material world. The magician can bring (level-3)*15 GE through the + temporary portal. If he is experienced enough to cast the spell at at + least level 13, he can even summon units against their will. + + + Ein Magier, welcher sich in der materiellen Welt + befindet, kann er mit Hilfe dieses Zaubers Einheiten aus der + angrenzenden + Astralwelt herbeiholen. Ist der Magier erfahren genug, den Zauber auf + Stufen von 13 oder mehr zu zaubern, kann er andere Einheiten auch gegen + ihren Willen in die materielle Welt zwingen. + A magician in the material world can summon units from + the adjacent part of the astral plane. If he is experienced enough to + cast + the spell at at least level 13, he can even summon units against their + will. + + + Mit Hilfe dieses Zaubers kann der Magier einem anderen + Magier seine Aura gegen dessen Willen entziehen und sich selber + zuführen. + Aided by this spell, a magician can steal another + magician's aura against his will. + + + Diese magischen Runen bringen ein Boot oder Langboot + für + eine Woche zum fliegen. Damit kann dann auch Land überquert werden. Die + Zuladung von Langbooten ist unter der Einwirkung dieses Zaubers auf 100 + Gewichtseinheiten begrenzt. Für die Farbe der Runen muss eine spezielle + Tinte aus einem Windbeutel und einem Schneekristall angerührt werden. + These magic runes allow a boat or longboat to fly for + a + week. The boat can only carry 100 weight units. The enchanted ink's + components include a windbag and a snowcrystal petal. + + + Diese praktische Anwendung des theoretischen Wissens um + Raum und Zeit ermöglicht es, den Zeitfluß für einige Personen zu + verändern. Auf diese Weise veränderte Personen bekommen für einige + Wochen doppelt soviele Bewegungspunkte und doppelt soviele Angriffe + pro Runde. + Abstract theories of space and time at last find + practical application in this spell which warps the very fabric of + time around a person. Such a person has twice as many movement points + and doubles their attacks per round for a few weeks. + + + Dieser Zauber läßt eine Welle aus purer Kraft über die + gegnerischen Reihen hinwegfegen. Viele Kämpfer wird der Schock so + benommen machen, daß sie für einen kurzen Moment nicht angreifen + können. + A wave of pure force spreads out from the magician, + crashing into the enemy ranks. Many warriors are thrown off balance and + are briefly unable to attack. + + + Mit diesem Zauber kann der Magier eine Zone der + astralen + Schwächung erzeugen, ein lokales Ungleichgewicht im Astralen Feld. + Dieses + Zone wird bestrebt sein, wieder in den Gleichgewichtszustand zu + gelangen. + Dazu wird sie jedem in dieser Region gesprochenen Zauber einen Teil + seiner Stärke entziehen, die schwächeren gar ganz absorbieren. + This spell allows a magician to create a local + instability in the astral field. This zone needs to return to its + equilibrium, soaking up part of the power of all spells cast in the + region + - or even all of some of the weaker ones. + + + Dieser Zauber ermöglicht dem Magier, Verzauberungen + einer Einheit, eines Schiffes, Gebäudes oder auch der Region aufzulösen. + This spell lets a magician destroy spells on a ship, + building or region. + + + Dieser Zauber verstärkt die natürliche + Widerstandskraft + gegen Magie. Eine so geschützte Einheit ist auch gegen Kampfmagie + weniger + empfindlich. Pro Stufe reicht die Kraft des Magiers aus, um 5 Personen + zu + schützen. + This spell enhances natural magic resistence. + Protected + units are less vulnerable to battle magic. The spell protects 5 people + per + level. + + + Alte arkane Formeln ermöglichen es dem Magier, sich + und + andere in die astrale Ebene zu schicken. Der Magier kann (Stufe-3)*15 GE + durch das kurzzeitig entstehende Tor schicken. Ist der Magier erfahren + genug, den Zauber auf Stufen von 11 oder mehr zu zaubern, kann er andere + Einheiten auch gegen ihren Willen auf die andere Ebene zwingen. + Ancient arcane formulae permit the magician to + transport + himself or other units into the astral plane. The magician can transport + (level-3) * 15 GE through the transient portal. If the magician is + experienced enough to cast level 11 spells, he can also transport units + against their will. + + + Der Magier konzentriert sich auf die Struktur der + Realität und kann so die astrale Ebene verlassen. Er kann insgesamt + (Stufe-3)*15 GE durch das kurzzeitig entstehende Tor schicken. Ist der + Magier erfahren genug, den Zauber auf Stufen von 11 oder mehr zu + zaubern, + kann er andere Einheiten auch gegen ihren Willen auf die andere Ebene + zwingen. + By concentrating on the structure of reality, the + magician can breach it and thus briefly make a gateway to leave the + astral + plane. He can transport up to (level-3)*15 GE through the portal. If the + magician is able to cast at at least level 11, he can even transport + other + units against their will. + + + Mit diesem Spruch kann der Magier versuchen, die + Verzauberungen + eines einzelnen angegebenen Objekts zu erkennen. Von + allen Sprüchen, + die seine eigenen Fähigkeiten nicht überschreiten, wird + er einen + Eindruck ihres Wirkens erhalten können. Bei stärkeren + Sprüchen + benötigt er ein wenig Glück für eine gelungene Analyse. + With this spell the magician can try to identify the + enchantments of + a single object. He will get an impression of the + operation of all + spells that don't exceed his own capabilities. For more + powerful + spells he will need some luck for a successful analysis. + + + Dieser Zauber wird die gesamte Ausrüstung der + Zieleinheit für + einige Zeit vor den Blicken anderer verschleiern. Der + Zauber + schützt nicht vor Dieben und Spionen. + This spell will hide the whole equipment of a target + unit from the + looks of others. It will not protect against thieves or + spies. + + + Dieser Zauber legt ein antimagisches Feld um die Magier der Feinde + und behindert ihre Zauber erheblich. Nur wenige werden die Kraft + besitzen, das Feld zu durchdringen und ihren Truppen in der Schlacht + zu helfen. + This spell creates an antimagic field around the mages of the enemies + and considerably hinders their spells. Only few will have the power to + break through the field and be able to help their troops in battle. + + + Dieser Zauber verhindert, dass ein Teil der sonst im Kampf zerstörten + Gegenstände beschädigt wird. Die Verluste reduzieren sich um 5% pro + Stufe des Zaubers bis zu einem Minimum von 25%. + This spell prevents damage to a portion of the items that would + otherwise be lost in battle. The loss of items is reduced by 5% for + every level of the spell, up to a minimum of 25%. + + + + Dieses Lied zähmt selbst den wildesten + Ork und macht ihn friedfertig und sanftmütig. Jeder + Gedanke, dem Sänger zu schaden, wird ihm entfallen. + Unbehelligt kann der Magier in eine Nachbarregion + ziehen. + This little melody calms even the + wildest orc to a gentle and serene creature who will not + even think about putting the singer to harm. The magician + may travel to a neighboring region without being + harassed by annoying troublemakers. + + + Nicht nur der Feldscher kann den + Verwundeten einer Schlacht helfen. Die Barden kennen + verschiedene Lieder, die die Selbstheilungskräfte des + Körpers unterstützen. Dieses Lied vermag Wunden zu + schließen, gebrochene Knochen zu richten und selbst + abgetrennte Glieder wieder zu regenerieren. + The field medic isn't the only one + capable of tending the wounds of battle. The bards know + a number of magic melodies to enhance the natural + healing process of the body. This song is able to close + wounds, mend fractured bones and even regenerate lost + lims. + + + Ein gar machtvoller Gesang aus den + Überlieferungen der Katzen, der tief in die Herzen der + Feinde dringt und ihnen Mut und Hoffnung raubt. Furcht + wird sie zittern lassen und Panik ihre Gedanken + beherrschen. Voller Angst werden sie versuchen, den + gräßlichen Gesängen zu entrinnen und fliehen. + This antique, powerful song, passed + down by the cats, will penetrate the hearts of the enemy + and bereave them of courage and hope. Both their minds + and bodies will be ruled by panic. Shivering with fear, + they will flee from the dreadful chants and try to make + their escape. + + + Aus den uralten Gesängen der Katzen + entstammt dieses magisches Lied, welches vor einem + Kampfe eingesetzt, einem entscheidende strategische + Vorteile bringen kann. Wer unter den Einfluss dieses + Gesangs gelangt, der wird seiner Umgebung nicht achtend + der Melodie folgen, sein Geist wird verwirrt und + sprunghaft plötzlichen Eingebungen nachgeben. So sollen + schon einst wohlgeordnete Heere plötzlich ihre Schützen + weit vorne und ihre Kavallerie bei den Lagerwachen + kartenspielend wiedergefunden haben (oder ihren Anführer + schlafend im lange verlassenen Lager, wie es in den + Großen Kriegen der Alten Welt wirklich geschehen sein + soll). + If is used before battle, this chant, + taken from the ancient tunes of the cats, might give you + the critical tactical advantage. Those under the spell's + influence will act uncoordinated and inconsequent due to + the nonsensical ideas planted into their minds through + the melody. So it is supposed to have come to pass that + well-organized armies found their archers up at the + front (while the cavalry was back at the camp playing + cards) or that even a famous general overslept a battle + in his tent, as tale-tellers claim it really happened + during the Great Wars in the Old World. + + + Dieser alte Schlachtengesang hebt die + Moral der eigenen Truppen und und hilft ihnen auch der + angsteinflößenden Aura dämonischer und untoter Wesen zu + widerstehen. Ein derartig gefestigter Krieger wird auch + in schwierigen Situationen nicht die Flucht ergreifen + und sein überlegtes Verhalten wird ihm manch Vorteil in + der Verteidigung geben. + This ancient battle chant lifts the + spirit of your troops and helps them withstand even the + fear-inspiring aura of demonic and undead beings. A + fighter thus fortified against evil will not flee even + in the face of terror, and his defenses will be strengthened. + + + Mit Hilfe dieses Zaubers kann der + Magier eigene Aura im Verhältnis 2:1 auf einen anderen + Magier des gleichen Magiegebietes übertragen. + This spell enables the wizard to + transfer aura at a rate of 2:1 to another sorcerer of + the same school of magic. + + + Alle lebenden Wesen haben ein eigenes + individuelles Lebenslied. Nicht zwei Lieder gleichen + sich, auch wenn sich alle Lieder einer Art ähneln. Jeder + Zauber verändert dieses Lied auf die eine oder andere + Art und gibt sich damit zu erkennen. Dieser Gesang + hilft, jene Veränderungen im Lebenslied einer Person zu + erlauschen, welche magischer Natur sind. Alle + Verzauberungen, die nicht stärker maskiert sind als Eure + Fähigkeit, werdet Ihr so entschlüsseln und demaskieren + können. + Each and every living being has its + own, individual 'life-song'. No two of these songs are + alike, even though songs of creatures of the same + species are similar. Every spell alters this song of + life in one way or the other and this can be identified. + By casting this spell, the bard can detect all those + magic variations in a person's 'life-song'. You will be + able to decipher all enchantments or spells, which + aren't disguised beyond your capability. + + + Dieser schrille Gesang hallt über das + ganze Schlachtfeld. Die besonderen Dissonanzen in den + Melodien machen es Magier fast unmöglich, sich auf ihre + Zauber zu konzentrieren. + The screeching sounds of this melody + can be heard across the whole battlefield. Wizards + exposed to these special dissonances find it nearly + impossible to concentrate on their spells. + + + Die verzauberte Einheit beginnt + hemmungslos zu plappern und erzählt welche Talente sie + kann, was für Gegenstände sie mit sich führt und sollte + sie magisch begabt sein, sogar welche Zauber sie + beherrscht. Leider beeinflußt dieser Zauber nicht das + Gedächnis, und so wird sie sich im nachhinein wohl + bewußt werden, dass sie zuviel erzählt hat. + The persons of the bewitched unit + starts to babble without control about what it is said, + speaking about their talents, the objects they carry or + wear and if the unit is a magician, he or she will even list + the spells they know. Unfortunately, this spell does not + influence the memory of the subjects and afterwards, the + enchanted will realize that they probably talked too + much. + + + Man befeuchte einen kluftfreien Block + aus feinkristallinen Gestein mit einer Phiole des + Lebenswassers bis dieses vollständig vom Gestein + aufgesogen wurde. Sodann richte man seine Kraft auf die + sich bildende feine Aura des Lebens und forme der + ungebundenen Kraft ein Gehäuse. Je mehr Kraft der Magier + investiert, desto mehr Golems können geschaffen werden, + bevor die Aura sich verflüchtigt. Jeder Golem hat jede + Runde eine Chance von 10 Prozent zu Staub zu zerfallen. + Gibt man den Golems die Befehle MACHE BURG oder MACHE + STRASSE, so werden pro Golem 4 Steine verbaut und der + Golem löst sich auf. + 'Take a flawless block of crystaline + stone and humidify it with a vial of Water Of Life until + the potion has been soaked up completely. Then focus + your power on the forming aura of life and shape a + container for the unbound forces'. The more power a magician + invests, the more golems can be created before the aura + dissipates. Every week, there is a 10 percent chance + that the golem will crumble to dust. If you command a + golem to 'MAKE CASTLE' or 'MAKE ROAD', it will turn + itself into 4 stones that it uses in construction, and + disintegrate afterwards. + + + Je mehr Kraft der Magier investiert, + desto mehr Golems können geschaffen werden. Jeder Golem + hat jede Runde eine Chance von 15 Prozent zu Staub zu + zerfallen. Gibt man den Golems den Befehl MACHE + SCHWERT/BIHÄNDER oder MACHE + SCHILD/KETTENHEMD/PLATTENPANZER, so werden pro Golem 4 + Eisenbarren verbaut und der Golem löst sich auf. + The more power a magician invests, the + more golems can be created before the aura dissipates. + Each golem has a 15% chance per week to turn to dust. If + you command a golem to 'MAKE SWORD/MAKE CLAYMORE' or + 'MAKE SHIELD/CHAINMAIL/PLATEMAIL',it will work 5 iron + ingots and disintegrate afterwards. + + + Wo sonst aus einem + Stecken nur ein Baum sprießen konnte, so treibt nun jeder + Ast Wurzeln. + Every branch becomes a sturdy + oak where before only one could be grown from a log. + + + Mit diesem Ritual wird eine dunkle + Gewitterfront beschworen, die sich + unheilverkündend über der Region auftürmt. Der + magische Regen wird alles Erz rosten lassen. + Eisenwaffen und Rüstungen werden schartig und rostig. + Die Zerstörungskraft des + Regens ist von der investierten Kraft des + Magiers abhängig. Für jede Stufe können bis zu + 10 Eisenwaffen betroffen werden. Ein Ring der + Macht verstärkt die Wirkung wie eine zusätzliche + Stufe. + This ritual conjurs up a dark + thunderstorm that affects a whole region. The + magic rain will let rust any ore. Iron weapons and + armor will get rusty. The exact number of + items affected by the rain depends on the + ammount of power invested by the magician. Up to ten + weapons can be destroyed per level - a Ring Of + Power increases the effect like an additional + level. + + + Dieser Zauber ermöglicht es dem Magier + Insekten auf magische Weise vor der lähmenden + Kälte der Gletscher zu bewahren. Sie können + Gletscher betreten und dort normal agieren. Der + Spruch wirkt auf Stufe*10 Insekten. Ein Ring der + Macht erhöht die Menge der verzauberbaren + Insekten zusätzlich um 10. + This spell enables the druid to + magically protect insects from the paralysing + cold of a glacier. Under the effect of this + spell, insects are able to enter glaciers and + act normally there. Ten insects per level can be + protected in this way. A Ring Of Power increases + the number by additional ten. + + + Im Kampf ruft der Magier die + Elementargeister der Kälte an und bindet sie an + sich. Sodann kann er ihnen befehlen, den Gegner + mit Hagelkörnern und Eisbrocken zuzusetzen. + During a battle the druid calls the + Elemental Spirits Of Cold and binds them to + himself. Then he commands them to attack his + foes with hail and ice missiles. + + + Erschafft einen Wächtergeist, der + in Gletschern und Bergen Eisen- und Laenabbau durch + nichtalliierte Parteien (HELFE BEWACHE) verhindert, + solange er die Region bewacht. Der Bergwächter ist + an den Ort der Beschwörung gebunden. + Creates a guardian spirit on a + mountain or glacier that keeps all factions that + are not allied (HELP GUARD) from mining iron or + laen as long as it guards the region. The + Mountain Guardian is bound to the location where + it has been summoned. + + + Durch Ausführung dieser Rituale ist + der Magier in der Lage einen mächtigen + Erdelementar zu beschwören. Solange dieser in + den Boden gebannt ist, wird kein Regen die Wege + aufweichen und kein Fluß Brücken zerstören + können. Alle Reisende erhalten damit die + gleichen Vorteile, die sonst nur ein ausgebautes + gepflastertes Straßennetz bietet. Selbst Sümpfe + und Gletscher können so verzaubert werden. Je + mehr Kraft der Magier in den Bann legt, desto + länger bleibt die Straße bestehen. + By performing these rituals the druid + is able to summon a powerful earth elemental. As + long as this elemental remains bound to a + region, no rain can turn a path into mud and no + river can destroy a bridge. All travelers in + this region gain the same advantages as if they + were travelling on a road. Even swamps and + glaciers can be enchanted in this way. The more + power the druid invests, the longer the roads + remain intact. + + + Die Anrufung der Elementargeister des + Windes beschwört plötzliche Windböen, kleine + Windhosen und Luftlöcher herauf, die die + gegnerischen Schützen behindern werden. + Calling the Elemental Spirits Of Wind + conjurs up sudden breezes, small whirlwinds and + minor turbulences that will hinder enemy + archers. + + + Diese Ritual verstärkt die Wirkung des + magischen Trankes um ein vielfaches. Wo sonst aus einem + Stecken nur ein Baum sprießen konnte, so treibt nun jeder + Ast Wurzeln. + This ritual greatly increases the + effect of the potion. Now every branch becomes a mallorn + tree where before only one could be grown from a log. + + + Der Magier zwingt mit diesem Ritual + die Elementargeister des Wassers in seinen + Dienst und bringt sie dazu, das angegebene + Schiff schneller durch das Wasser zu tragen. + Zudem wird das Schiff nicht durch ungünstige + Winde oder Strömungen beeinträchtigt. + While being aboard a ship, the druid + uses this ritual to force the Elemental Spirits + Of Water to serve him and commands them to carry + the ship across the water at a higher speed. In + addition, the ship will not be affected by + unfavourable winds or currents. + + + Nicht nur der Feldscher kann den + Verwundeten einer Schlacht helfen. Druiden + vermögen mittels einer Beschwörung der + Elementargeister des Lebens Wunden zu schließen, + gebrochene Knochen zu richten und selbst + abgetrennte Glieder wieder zu regenerieren. + Combat medics are not the only ones + who can help those who got injured during a + battle. Druids are, with the help of a summons + of + the Elemental Spirits Of Life, able to heal + wounds, mend broken bones or even regenerate + separated limbs as well. + + + Diese Beschwörung öffnet ein Tor in + die Ebene der Elementargeister des Windes. + Sofort erheben sich in der Umgebung des Tors + starke Winde oder gar Stürme und behindern alle + Schützen einer Schlacht. + This summons opens a gate to the plane + of Elemental Spirits Of Wind. Immediately, + strong winds or even storms will rise near the + gate and hinder all archers during a battle. + + + Dieses Ritual beschwört einige + Elementargeister der Magie und schickt sie in + die Reihen der feindlichen Magier. Diesen wird + das Zaubern für die Dauer des Kampfes deutlich + schwerer fallen. + This ritual summons some Elemental + Spirits Of Magic and sends them into the ranks + of the enemy mages. Casting spells will be much + harder for them during the battle. + + + Mit Hilfe dieses Zaubers kann der + Magier eigene Aura im Verhältnis 2:1 auf einen + anderen Magier des gleichen Magiegebietes + übertragen. + The caster can transfer aura at a + ratio of 2:1 to another member of the same + school of magic with the help of this spell. + + + Der Druide beschwört mit diesem Ritual + einen Elementargeist der Erde und bringt ihn + dazu, die Erde erbeben zu lassen. Dieses + Erdbeben wird alle Gebäude in der Region + beschädigen. + With this ritual the druid summons an + Elemental Spirit Of Earth that brings the ground + to shake. This earthquake damages all buildings + in the target region. + + + Die Beschwörung von Elementargeistern + der Stürme ist ein uraltes Ritual. Der Druide + bannt die Elementare in die Segel der Schiffe, + wo sie helfen, das Schiff mit hoher + Geschwindigkeit über die Wellen zu tragen. Je + mehr Kraft der Druide in den Zauber investiert, + desto größer ist die Zahl der Elementargeister, + die sich bannen lassen. Für jedes Schiff wird + ein Elementargeist benötigt. + Calling the Elemental Spirits Of Storm + is an ancient ritual. The druid binds the + elementals to a ship's sails where they can help + to carry the vessel across the waves at an + amazing speed. The more power the druid invests, + the greater is the number of spirits bound. Each + ship needs an own spirit. + + + Mit diesem Spruch erzeugt man ein Runenschwert. Die + Klinge des schwarzen Schwertes ist mit alten, magischen Runen verziert, + und ein seltsames Eigenleben erfüllt die warme Klinge. Um es zu + benutzen, + muss man ein Schwertkämpfer von beachtlichem Talent (7) sein. Der + Träger + des Runenschwertes erhält einen Talentbonus von +4 im Kampf und wird so + gut wie immun gegen alle Formen von Magie. + This spell creates a magical sword. It requires a + skill + of at least 7, but adds +4 to the combat skill of its' owner as well as + making them almost immune against magical attacks. + + + Dieser Beutel umschließt eine kleine Dimensionsfalte, + in + der bis zu 200 Gewichtseinheiten transportiert werden können, ohne dass + sie auf das Traggewicht angerechnet werden. Pferde und andere Lebewesen + sowie besonders sperrige Dinge (Wagen und Katapulte) können nicht in dem + Beutel transportiert werden. Auch ist es nicht möglich, einen + Zauberbeutel in einem anderen zu transportieren. Der Beutel selber wiegt + 1 + GE. + This bag encloses a dimensional rift in which up to + 200 + units of weight can be carries. Horses and other large objects cannot be + put into the bag. The bag itself has a weight of 1. + + + Dieses mächtige Ritual erschafft einen Ring der Macht. + Ein Ring der Macht erhöht die Stärke jedes Zaubers, den sein Träger + zaubert, als wäre der Magier eine Stufe besser. + A ring of power adds +1 to the power of each spell + cast + by its' wearer. + + + Der Spruch ermöglicht es einem Magier, + ein Amulett des Wahren Sehens zu erschaffen. Das + Amulett erlaubt es dem Träger, alle Einheiten, + die durch einen Ring der Unsichtbarkeit + geschützt sind, zu sehen. Einheiten allerdings, + die sich mit ihrem Tarnungs-Talent verstecken, + bleiben weiterhin unentdeckt. + This spell enables the caster to + create an Amulet Of True Sight. Wearing such an + amulet, a person can discover anyone wearing a + Ring of Invisibility. Anyway, units concealed by + the use of their stealth skill will remain + undiscovered. + + + Mit Hilfe dieses Zauber entzieht der Magier einem + Quarzkristall all seine magischen Energien. Der Kristall wird dann, wenn + er zu feinem Staub zermahlen und verteilt wird, die beim Zaubern + freigesetzten magischen Energien aufsaugen und die Kraft aller Zauber + reduzieren, welche in der betreffenden Woche in der Region gezaubert + werden. + This spell creates a portable crystal of antimagic + which can be used by anybody to reduce or even eliminate the power of + all spells cast in the region during the same week. + + + Die berühmte Bardin Miriam bhean'Meddaf war bekannt + für ihr außergewöhnliches Geschick mit der Harfe. Ihre Finger sollen + sich so schnell über die Saiten bewegt haben, das sie nicht mehr + erkennbar waren. Dieser Zauber, der recht einfach in einen Silberring + zu bannen ist, bewirkt eine um das zehnfache verbesserte + Geschicklichkeit und Gewandheit der Finger. (Das soll sie auch an + anderer Stelle ausgenutzt haben, ihr Ruf als Falschspielerin war + berüchtigt). Handwerker können somit das zehnfache produzieren, + und bei einigen anderen Tätigkeiten könnte dies ebenfalls von Nutzen + sein. + The famous bard Mirim was known for exceptionally + limber + play of the harp. Her spell, which is easy to ban into a little silver + ring, increases the wearer's dexterity by a factor of ten, which is siad + to be useful to both craftsmen and shady natures. + + + Mit diesem Spruch kann der Zauberer + einen Ring der Unsichtbarkeit erschaffen. Der + Träger des Ringes wird für alle Einheiten + anderer Parteien unsichtbar, egal wie gut ihre + Wahrnehmung auch sein mag. In einer unsichtbaren + Einheit muss jede Person einen Ring tragen. + With this spell the caster can create + a Ring Of Invisibility. The wearer of this ring + will be invisible to all units of other + factions, no matter how good their perception + skill may be. In an invisible unit, each person + must wear a Ring Of Invisibility. + + + Mit dieser Formel bindet der Magier + auf ewig die Kräfte der Erde in die Mauern der + Burg, in der er sich gerade befindet. Weder + magisch noch mit schwerem Geschütz können + derartig gestärkte Mauern zerstört werden, und + auch das Alter setzt ihnen weniger zu. Das + Gebäude bietet sodann auch einen besseren Schutz + gegen Angriffe mit dem Schwert wie mit Magie. + With this spell the druid eternally + binds the powers of earth to the walls of the + castle in which he currently is. No magic and no + ballistic attacks will ever be able to destroy a + wall that has been fortified in this way and the + castle will also be less affected by aging. In + addition, the building will provide a better + protection against attacks by sword or by magic. + + + Nicht wenige Druiden freunden sich im + Laufe ihres Lebens in der Natur mit den ältesten + Freunden der großen Völker an. Sie erlernen, mit + einem einzigen heulenden Ruf viele ihrer Freunde + herbeizurufen, um ihnen im Kampf beizustehen. + During their life in the wilderness, + many druids make friends with the wolves who are + the oldest friends of the great races. They + learn to call many of them with a single howl to + aid them in combat. + + + Dieser schwierige, aber effektive + Kampfzauber benutzt die Elementargeister des + Steins, um eine Reihe von Gegnern für die Dauer + des Kampfes in Stein zu verwandeln. Die + betroffenen Personen werden nicht mehr kämpfen, + können jedoch auch nicht verwundet werden. + This complicated but effective spell + uses the Elemental Spirits Of Stone to turn a + number of enemies to stone for the duration of + combat. The affected persons won't be able to + fight any more, but they can't be wounded + either. + + + Mit dieser Formel bindet der Magier zu + Beginn eines Kampfes einige Elementargeister des + Fels in die Mauern des Gebäudes, in dem er sich + gerade befindet. Das Gebäude bietet sodann einen + besseren Schutz gegen Angriffe mit dem Schwert + wie mit Magie. + At the beginning of a battle, the + magician binds some Elemental Spirits Of Rock to + the walls of the builing in which he currently + is. The structure will then provide a better + protection against attacks by sword or by magic. + + + Wie die alten Lehren der Druiden + berichten, besteht das, was die normalen Wesen + Magie nennen, aus Elementargeistern. Der Magier + beschwört und bannt diese in eine Form, um den + gewünschten Effekt zu erzielen. Dieses Ritual + nun vermag es, in diese Welt gerufene + Elementargeister zu vertreiben, um so ein Objekt + von Magie zu befreien. + Old legends of the druids say that + what normal people call 'magic' consists of + elemental spirits. A magician summons these + spirits and binds them to various forms to + achieve the desired effects. This ritual is able + to expel any elemental spirits that have been + summoned to this world and thereby dispels any + magic on the target. + + + Große Macht liegt in Orten, an denen + das Leben pulsiert. Der Druide kann diese Kraft + sammeln und so ein Tor in die Welt der + Geistwesen erschaffen. Der Druide kann dann + Stufe*5 Gewichtseinheiten durch das Tor + entsenden. + A great power lies within those places + that are pulsing with life. A druid can focus + this power and thereby create a gate into the + World Of Spirits. He can then send level*5 + weight units of living or dead matter through + the gate. + + + Ein Druide, den es in die Welt der + Geister verschlagen hat, kann mit Hilfe dieses + Zaubers Stufe*5 Gewichtseinheiten in einen Wald + auf der materiellen Welt zurückschicken. + A druid who has traveled to the World + Of Spirits can use this spell to send level*5 + weight units of living or dead matter back to a + forest in the material world. + + + Dieses Ritual beschwört verschiedene + Naturgeister in den Boden der Region, welche + diese fortan bewachen. In einer so gesegneten + Region werden niemals wieder die Toten ihre + Gräber verlassen, und anderswo entstandene + Untote werden sie wann immer möglich meiden. + This ritual binds various rural + spirits to a specific territory to guard the + land. In a region blessed in this way the dead + won't ever rise from their graves again. + Existing undead also shun the sacred grounds and + will avoid entering the protected area whenever + possible. + + + Der Druide nehme etwas präpariertes + Leder, welches er in einem großen Ritual der + Reinigung von allen unreinen Geistern befreie, + und binde dann einige kleine Geister der Luft + und des Wassers in das Material. Aus dem so + vorbereiteten Leder fertige er nun ein kleines + Beutelchen, welches in ihm aufbewahrte Kräuter + besser zu konservieren vermag. + The druid takes some specially + prepared leather and performes a great ritual + during which the leather is cleansed of all + impure spirits. Then he binds some minor spirits + of air and water to the material. After + completing this process, the druid works the + enchanted leather into a small pouch which is + suitable to contain herbs, for it is able to + preserve them for a long time and prevents rot. + + + Mit Hilfe dieses Zaubers weckt der + Druide die in den Wälder der Region + schlummernden Ents aus ihrem äonenlangen Schlaf. + Die wilden Baumwesen werden sich ihm anschließen + und ihm beistehen, jedoch nach einiger Zeit + wieder in Schlummer verfallen. + With the help of this spell the druid + awakens the ents who are slumbering in the + forests of a region from aeons of sleep. These + strange tree-creatures will join him and aid his + cause, but after a while they will sink back + into their slumber. + + + Einem erfahrenen Druidem wird + irgendwann auf seinen Wanderungen ein + ungewöhnliches Exemplar einer Gattung begegnen, + welches sich dem Druiden anschließen wird. + Once during his travels, the seasoned + druid will meet an extraordinary creature of its + species that will join him. + + + Dieses Ritual segnet einen Steinkreis, + der zuvor aus Steinen und etwas Holz gebaut + werden muss. Die Segnung des Druiden macht aus + dem Kreis eine mächtige Stätte magischen + Wirkens, die Schutz vor Magie und erhöhte Aura- + Regeneration bewirkt. Man sagt, Jungfrauen seien + in der Umgebung von Steinkreisen seltsame Wesen + begegnet. + This ritual blesses a circle of stones + that has to be constructed from stones and some + wood before. The druid's blessing turns the + circle into a place of great magic that is + suitable for rituals of all kinds. It protects + from hostile magic and improves aura + regeneration. Virgins are said to have been + visited by strange creatures in the vicinity of + these places. + + + Das Ziel des Zauberers wird von einer + harmlosen Verwünschung heimgesucht. + The target of this spell becomes + subject to a harmless curse. + + + Dieses vor dem Kampf zu zaubernde Ritual gibt den + eigenen Truppen einen zusätzlichen Bonus auf ihre Rüstung. Jeder + Treffer reduziert die Kraft des Zaubers, so dass der Schild sich + irgendwann im Kampf auflösen wird. + Performing this ritual before going into battle gives + your troups an additional bonus to their armor. Every hit reduces the + energy of the spell, dissolving it at some point during battle. + + + Der Zauberer schleudert fokussiertes + Chaos in die Reihen der Gegner. Das ballförmige + Chaos wird jeden verwunden, den es trifft. + The sorcerer hurls a ball of + concentrated chaos into the ranks of his + enemies. It will seriously hurt anyone who gets + hit. + + + Der Magier öffnet seinen Geist den + Sphären des Chaos und wird so für einige Zeit + über mehr magische Kraft verfügen. Doch die + Hilfe der Herren der Sphären hat seinen Preis, + und so wird die Phase der Macht abgelöst von + einer Phase der Schwäche. + The sorcerer opens his mind to the + Spheres Of Chaos so that he can access a greater + ammount of magical power for a while. But the + help of the Chaos Lords has its price - and so + the period of power will be followed by a period + of weakness. + + + Mit diesem Ritual kann der Magier + einen Teil seiner Lebensenergie opfern, um dafür + an magischer Kraft zu gewinnen. Erfahrene + Ritualmagier berichten, das sich das Ritual, + einmal initiiert, nur schlecht steuern ließe und + die Menge der so gewonnenen Kraft stark + schwankt. So steht im 'Buch des Blutes' + geschrieben: 'So richte Er aus das Zeichen der + vier Elemente im Kreis des Werdens und Vergehens + und Weihe ein jedes mit einem Tropfen Blut. + Sodann begebe Er in der Mitten der Ewigen Vierer + sich und lasse Leben verrinnen, auf das Kraft + geboren werde.' + With this ritual the sorcerer can + sacrifice part of his life force in order to + gain raw astral power. Experienced mages report + that this ritual, once started, is hard to + control and that the ammount of power gained in + this way varies. + + + In diesem blutigen Ritual opfert der + Magier vor der Schlacht ein Neugeborenes vor den + Augen seiner Armee. Die so gerufenen Blutgeister + werden von den Soldaten Besitz ergreifen und sie + in einen Blutrausch versetzen. + During this bloody ritual the sorcerer + sacrifices a newborn child before a battle right + in front of his army. In this way he attracts + spirits of blood that will take control of the + soldiers who are present and force them into a + blood frenzy. + + + Dieser heimtückische Fluch + beeinträchtigt die magischen Fähigkeiten des + Opfers erheblich. Eine chaosmagische Zone um das + Opfer vermindert seine Konzentrationsfähigkeit + und macht es ihm sehr schwer Zauber zu wirken. + This wicked curse affects the magical + abilities of the target. A field of raw chaos + magic around the target lessens its + concentration and makes it very hard to cast any + spells. + + + Nächtelang muss der Schwarzmagier + durch die Friedhöfe und Gräberfelder der Region + ziehen um dann die ausgegrabenen Leichen beleben + zu können. Die Untoten werden ihm zu Diensten + sein, doch sei der Unkundige gewarnt, dass die + Beschwörung der Mächte des Todes ein + zweischneidiges Schwert sein kann. + For many nights the sorcerer has to + roam the graveyards and former battlefields of a + region in order to find corpses to animate. The + Undead will serve his will, but beware! Dealing + with the mysteries of unlife can be a dangerous + thing. + + + Mit diesem Ritual wird eine dunkle + Gewitterfront beschworen, die sich + unheilverkündend über der Region auftürmt. Der + magische Regen wird alles Erz rosten lassen und + so viele Waffen des Gegners zerstören. + This ritual conjurs up a dark + thunderstorm that affects a whole region. The + magic rain will let rust any ore and thus + destroy many weapons of the enemy. + + + Mit Hilfe dieses Zaubers kann der + Magier eigene Aura im Verhältnis 2:1 auf einen + anderen Magier des gleichen Magiegebietes + übertragen. + With the help of this spell, the + caster can transfer aura at a ratio of 2:1 to + another member of the same school of magic. + + + Der Zauberer erschafft eine Wand aus + Feuer in der angegebenen Richtung. Sie verletzt + jeden, der sie durchschreitet. + The spell creates an opaque wall of + fire in the gives direction that will harm + anyone passing through it. + + + In einem aufwendigen Ritual opfert der + Schwarzmagier einige Bauern und verteilt dann + die Leichen auf magische Weise in den Brunnen + der Region. + In a complicated ritual the sorcerer + sacrifices the lives of ten peasants and + magically spreads their corpses within the wells + of a region. + + + Vor den Augen der feindlichen Soldaten + opfert der Schwarzmagier die zehn Bauern in + einem blutigen, grausamen Ritual und beschwört + auf diese Weise Geister des Wahnsinns über die + feindlichen Truppen. Diese werden im Kampf + verwirrt reagieren und nicht in der Lage sein, + den Anweisungen ihrer Offiziere zu folgen. + Before the eyes of the enemy soldiers + the sorcerer sacrifices ten peasants in a bloody + ritual and thereby summons spirits of madness + upon the enemy troops. The enemy soldiers will + be in confusion during battle and no more be + able to follow the commands of their leaders. + + + Mit Hilfe dunkler Rituale beschwört + der Zauberer Dämonen aus der Sphäre der + Schatten. Diese gefürchteten Wesen können sich + fast unsichtbar unter den Lebenden bewegen, ihre + finstere Aura ist jedoch für jeden spürbar. Im + Kampf sind Schattendämonen gefürchtete Gegner. + Sie sind schwer zu treffen und entziehen ihrem + Gegner Kraft. + With the help of dark rituals the + sorcerer summons demons from the Sphere Of + Shadows. These fearsome creatures can walk + almost unseen among the living, but their dark + aura can be sensed by everyone. Shadow demons + are feared in combat for they are hard to hit + and have the ability to drain strength from + their victims. + + + Dieses Ritual beschwört wütende Elementargeister der + Hitze. Eine Dürre sucht das Land heim. Bäume verdorren, Tiere + verenden, und die Ernte fällt aus. Für Tagelöhner gibt es kaum noch + Arbeit in der Landwirtschaft zu finden. + This Ritual summons an angry elemental spirit that + puts a drought on the entire region. Trees wither, animals die of + thirst and the harvest is destroyed. Workers find little to no work + in farming. + + + Dieses Ritual bindet die bereits + entfliehenden Seelen einiger Kampfopfer an ihren + toten Körper, wodurch sie zu untoten Leben + wiedererweckt werden. Ob sie ehemals auf der + Seite des Feindes oder der eigenen kämpften, ist + für das Ritual ohne belang. + This ritual binds the escaping souls + of some casualties back to their dead bodies and + thus condemns them to an undead existance under + the control of the sorcerer. The ritual affects + the corpses of allies and foes alike - no matter + on which side of the battle the soldiers fought + before their death. + + + Dieses magische Artefakt verleiht dem + Träger die Stärke eines ausgewachsenen + Höhlentrolls. Seine Tragkraft erhöht sich auf + das 50fache und auch im Kampf werden sich die + erhöhte Kraft und die trollisch zähe Haut + positiv auswirken. + This artifact gives the one wearing it + the strength of a cavetroll. He will be able to + carry fifty times as much as normal and also in + combat his enhanced strength and tough troll + skin will serve him well. + + + Der Schwarzmagier kann mit diesem + dunklen Ritual einen Riss in das Gefüge der + Magie bewirken, der alle magische Kraft aus der + Region reißen wird. Alle magisch begabten in der + Region werden einen Großteil ihrer Aura + verlieren. + With this dark ritual the + chaossorcerer causes a deep rift to appear in + the astral balance that will tear all magical + power from a region. All spellcasters in that + region will lose most of their aura. + + + Dieses Ritual, ausgeführt vor einem + Kampf, verwirbelt die astralen Energien auf dem + Schlachtfeld und macht es so feindlichen Magier + schwieriger, ihre Zauber zu wirken. + This ritual, performed before a + battle, causes the astral energies on the + battlefield to whirl and churn and thereby makes + spellcasting more difficult for the enemy mages. + + + Diese Elementarbeschwörung ruft einen + Feuerteufel herbei, ein Wesen aus den tiefsten + Niederungen der Flammenhöllen. Der Feuerteufel + wird sich begierig auf die Wälder der Region + stürzen und sie in Flammen setzen. + This elemental summoning calls a fire + fiend, a creature from the deepest hell. The + demon will eagerly rush into the forests of a + region and set them ablaze. + + + Genau um Mitternacht, wenn die Kräfte + der Finsternis am größten sind, kann auch ein + Schwarzmagier seine Kräfte nutzen um + Verzauberungen aufzuheben. Dazu zeichnet er ein + Pentagramm in das verzauberte Objekt und beginnt + mit einer Anrufung der Herren der Finsternis. + Die Herren werden ihm beistehen, doch ob es ihm + gelingt, den Zauber zu lösen, hängt allein von + seiner eigenen Kraft ab. + At midnight, when the Powers of + Darkness are at their peak, the sorcerer can use + his powers to destroy enchantments. In order to + do so, he draws a pentagram on a surface of the + enchanted object and begins calling the Lords Of + Darkness. The Lords will aid him, but whether he + is able to undo the target spell or not depends + upon his own power. + + + Nur geflüstert wird dieses Ritual an + den dunklen Akademien an die Adepten + weitergegeben, gehört es doch zu den + finstersten, die je niedergeschrieben wurden. + Durch die Anrufung unheiliger Dämonen wird die + Kraft der lebenden Toten verstärkt und sie + verwandeln sich in untote Monster großer Kraft. + Only whispered the knowledge of + performing this ritual is passed to the adepts + of the dark academies, for it is one of the + darkest that has ever been written down. By + calling unholy demons the strength of the living + dead is greatly increased and they are turned + into undead monsters of immense power. + + + Mit einem düsteren Ritual und unter + Opferung seines eigenen Blutes beschwört der + Schwarzmagier einen großen Geist von der + Elementarebene der Gifte. Der Geist manifestiert + sich als giftgrüner Schwaden über der Region und + wird allen, die mit ihm in Kontakt kommen, + Schaden zufügen. + By performing a gruesome ritual and + sacrificing his own blood the Sorcerer conjurs + up a spirit from the Elemental Plane Of Poison. + It will take the form of a green cloud of toxic + gases that envelops a whole region and that will + harm anyone within. + + + Mit diesem dunklen Ritual erzeugt der + Magier einen Köder, der für Drachen einfach + unwiderstehlich riecht. Ob die Drachen aus der + Umgebung oder aus der Sphäre des Chaos stammen, + konnte noch nicht erforscht werden. Es soll + beides bereits vorgekommen sein. Der Köder hält + etwa 6 Wochen, muss aber in einem + drachengenehmen Terrain platziert werden. + Performing this dark ritual, the + sorcerer creates a bait that exhales an + irresistable scent to dragons. It is not known + whether the dragons come from surrounding + regions or if they have their origin in the + Sphere Of Chaos. The bait will exist for about + six weeks, but it must be placed in a tarrain + that is suitable for dragons. + + + Mit Hilfe dunkler Rituale beschwört + der Zauberer Dämonen aus der Sphäre der + Schatten. Diese gefürchteten Wesen können sich + fast unsichtbar unter den Lebenden bewegen, ihre + finstere Aura ist jedoch für jeden spürbar. Im + Kampf sind Schattenmeister gefürchtete Gegner. + Sie sind schwer zu treffen und entziehen ihrem + Gegner Kraft und Leben. + With the help of dark rituals the + sorcerer summons demons from the Sphere Of + Shadows. These fearsome creatures can walk + almost unseen among the living, but their dark + aura can be sensed by everyone. Shadowmasters + are feared in combat for they are hard to hit + and have the ability to drain strength and life + force from their victims. + + + 'Und so reibe das Blut eines wilden + Kämpfers in den Stahl der Klinge und beginne die + Anrufung der Sphären des Chaos. Und hast du + alles zu ihrem Wohlgefallen getan, so werden sie + einen niederen der ihren senden, das Schwert mit + seiner Macht zu beseelen...' + 'So take the blood of a fierce warrior + and apply it to the steel of the blade. Then + start calling the Spheres Of Chaos. If you did + everything to their pleasure, they will send a + minor one of their kind to fulfill the sword + with his power.' + + + Einem erfahrenen Magier wird + irgendwann auf seinen Wanderungen ein + ungewöhnliches Exemplar einer Gattung begegnen, + welches sich dem Magier anschließen wird. + During their travel, seasoned + magicians will occasionally befriend an extraordinary + creature of an unusual species that will join them. + + + Durch das Opfern von 200 Bauern kann + der Chaosmagier ein Tor zur astralen Welt + öffnen. Das Tor kann in der Folgewoche verwendet + werden, es löst sich am Ende der Folgewoche auf. + By sacrificing the lives of 200 + peasants, the chaossorcerer is able to open a + planar gate. This gate can be used during the + following week to transfer units to the astral + plane. It dissipates at the end of the following + week. + + + Der Zauberer sendet dem Ziel des + Spruches einen Traum. + The mentalist sends a dream to the + target of the spell. + Le mentaliste envoie un rêve à la + cible du sort. + + + Dieser Zauber vermag dem Gegner ein + geringfügig versetztes Bild der eigenen Truppen + vorzuspiegeln. Die Schattenritter haben keinen + effektiven Angriff und Verwundungen im Kampf + zerstören sie sofort. + This spell creates illusionary + duplicates of allied troops. The shadow knights + can't do real damage and are instantly destroyed + if wounded. + Ce sort crée des copies illusoires de + troupes alliées. Les guerriers illusoires ne + peuvent faire de dégats réels et sont + instantanément détruits lorsqu'ils sont blessés. + + + Der Traumweber beschwört vor dem + Kampf grauenerregende Trugbilder herauf, die + viele Gegner in Panik versetzen. Die Betroffenen + werden versuchen, vor den Trugbildern zu + fliehen. + Before a battle the mentalist creates + terrifying illusions of hideous creatures that + will cause panic among the enemies. Those who + believe in the illusions will try to flee from + battle. + + + Dieses magische Ritual beruhigt die + gequälten Seelen der gewaltsam zu Tode + gekommenen und ermöglicht es ihnen so, ihre + letzte Reise in die Anderlande zu beginnen. Je + Stufe des Zaubers werden ungefähr 50 Seelen ihre + Ruhe finden. Der Zauber vermag nicht, bereits + wieder auferstandene lebende Tote zu erlösen, da + deren Bindung an diese Welt zu stark ist. + This ritual calms the tortured souls + of those who died a violent death and finally + releases them to the Otherlands. About 50 souls + per level of the spell will be released. The + spell will not affect existing undead, because + they are too strongly tied to the Material + World. + + + Mit Hilfe dieses Zaubers kann der + Traumweber die Illusion eines beliebigen + Gebäudes erzeugen. Die Illusion kann betreten + werden, ist aber ansonsten funktionslos und + benötigt auch keinen Unterhalt. Sie wird einige + Wochen bestehen bleiben. + With this spell the mentalist can + create the illusion of any building. The + illusion can be entered, but it has no function + and requires no maintenance. It will remain + existing for several weeks. + + + Mit Hilfe dieses Zaubers kann der + Traumweber eigene Aura im Verhältnis 2:1 auf + einen anderen Traumweber übertragen. + With the help of this spell the + mentalist can transfer aura at a ratio of 2:1 to + another mentalist. + + + Mit Hilfe dieses arkanen Rituals + vermag der Traumweber die wahre Gestalt einer + Gruppe + zu verschleiern. Unbedarften Beobachtern + erscheint + sie dann als einer anderen Rasse zugehörig. + With the help of this ritual the + mentalist is able to conceal the true form of a + target unit. To unknowing observers all persons + in the target unit appear to be of a different + race. + + + Dieser Zauber ermöglicht es dem + Traumweber, in die Träume einer Einheit + einzudringen und so einen Bericht über die + Umgebung zu erhalten. + This spell enables the mentalist to + penetrate the dreams of a target unit and gather + information about that unit's surroundings. He + will receive a report from the corresponding + region. + + + Dieser Kampfzauber führt dazu, dass + einige Gegner im Kampf unter schwerer Müdigkeit + leiden. Die Soldaten verschlafen manchmal ihren + Angriff und verteidigen sich schlechter. + This combat spell causes several + enemies to suffer from an unnatural tiredness + during combat. The soldiers will defend + themselves worse than normal and sometimes sink + into a slumber instead of attacking. + + + Stirbt ein Krieger im Kampf so macht + sich seine Seele auf die lange Wanderung zu den + Sternen. Mit Hilfe eines Rituals kann ein + Traumweber versuchen, die Seele wieder + einzufangen und in den Körper des Verstorbenen + zurückzubringen. Zwar heilt der Zauber keine + körperlichen Verwundungen, doch ein Behandelter + wird den Kampf überleben. + When a warrior dies in a battle, his + soul begins its long journey to the stars. With + the help of this ritual, the mentalist can try + to catch those escaping souls and bring them + back to their bodies. The spell does not heal + physical injuries, but an affected person will + survive the battle. + + + Mit diesem Spruch kann der Traumweber + versuchen, die Verzauberungen einer einzelnen + Einheit zu erkennen. Von allen Sprüchen, die + seine eigenen Fähigkeiten nicht überschreiten, + wird er einen Eindruck ihres Wirkens erhalten + können. Bei stärkeren Sprüchen benötigt er ein + wenig Glück für eine gelungene Analyse. + With this spell the mentalist can + attempt to detect enchantments on a target unit. + He will get an idea of the effect of all spells + that don't exceed his own abilities. If a spell + is stronger, it takes a little luck for a + successful analysis. + + + Dieser Zauber führt in der betroffenen + Region für einige Wochen zu Schlaflosigkeit und + Unruhe. Den Betroffenen fällt das Lernen + deutlich schwerer. + This spell causes insomnia and + restlessness in a whole region for several + weeks. All affected persons will learn much + slower than normal. + + + Dieser Zauber läßt einige feindliche + Kämpfer einschlafen. Schlafende Kämpfer greifen + nicht an und verteidigen sich schlechter, sie + wachen jedoch auf, sobald sie im Kampf getroffen + werden. + This spell causes several enemies to + fall asleep. Sleeping warriors don't attack and + defend themselves worse than normal, but they'll + wake up if they get hit during combat. + + + Mit diesem Zauber dringt der + Traumweber in die Gedanken und Traumwelt seines + Opfers ein und kann so seine intimsten + Geheimnisse ausspähen. Seine Fähigkeiten, seinen + Besitz und seine Parteizugehörigkeit wird nicht + länger ungewiss sein. + With this spell the mentalist + penetrates the thoughts and dreams of his victim + to reveal his most intimate secrets. The + target's faction, skills and possessions will no + longer be unknown. + + + Der Magier beschwört ein kleines Monster, einen Alp. Dieses bewegt sich + langsam auf sein Opfer zu (das sich an einem beliebigen Ort an der Welt + befinden kann, der Magier oder seine Partei braucht es nicht zu sehen). + Sobald das Opfer erreicht ist, wird es gnadenlos gequält, und nur durch + einen starken Gegenzauber oder den Tod des beschwörenden Magiers kann + das Opfer wieder Frieden finden. Bei der Beschwörung des Alps verliert + der Magier einen kleinen Teil seiner Aura für immer. + The magician spawns a little monster, a nightmare. The nightmare slowly + approaches its victim (which may be at an arbitrary place in eressea, it + is not needed for the magician or his party to see the victim). As soon + as + the victim is reached the nightmare starts to torment it without mercy, + only a powerfull counter spell or the death of the casting magician can + redeem + the victim. When spawning the nightmare the magician loses a small amount + of + his aura forever. + + + Ein mit diesem Zauber belegtes Drachenauge, welches zum Abendmahle + verzehrt wird, erlaubt es dem Benutzer, in die Träume einer anderen + Person einzudringen und diese zu lesen. Lange Zeit wurde eine solche + Fähigkeit für nutzlos erachtet, bis die ehemalige waldelfische + Magistra für Kampfmagie, Liarana Sonnentau von der Akademie Thall, + eine besondere Anwendung vorstellte: Feldherren träumen vor großen + Kämpfen oft unruhig und verraten im Traum ihre Pläne. Dies kann dem + Anwender einen großen Vorteil im kommenden Kampf geben. Aber Vorsicht: + Die Interpretation von Träumen ist eine schwierige Angelegenheit. + An enchanted eye of a dragon gives the person who eats it for supper the + power to see + other people's dreams. For a long time this abillity was counted as + beeing + useless until + the former elfish mistress for theurgy of war, Liarana Sonnentau from + the + academy Thall, + presented a special appliance for this artefact: Before a battle + captains + often have an + uncomfortable sleep and betray their plans in their dreams. This might + give the user of + the artefact a small advantage in the upcoming battle, but be warned: + Interpreting dreams + is a difficult exercise. + + + Mit diesem Spruch kann der Zauberer eine Sphäre der + Unsichtbarkeit + erschaffen. Die Späre macht ihren Träger sowie neunundneunzig weitere + Personen in derselben Einheit unsichtbar. + Using this spell the magician can create a Sphere of + Invisibility. This artefact hides the person bearing it and one hundred + persons in the same unit. + + + Dieser Zauber ermöglicht es dem + Traumweber, den Schlaf aller aliierten Einheiten + in + der Region so zu beeinflussen, dass sie für + einige + Zeit einen Bonus in allen Talenten bekommen. + This spell allows the mentalist to + influence the sleep of all allied units in a + region + in such a way that they will gain a bonus to all + talents for some time. + + + Dieser Zauber ermöglicht es dem + Traumweber die natürlichen und aufgezwungenen + Traumbilder einer Person, eines Gebäudes, + Schiffes oder einer Region zu unterscheiden und + diese zu entwirren. + This spell allows the mentalist to + distinguish between the natural and unnatural + dreams of a person, a ship, a building or a + region and remove those that are of magical + origin. + + + Aus 'Die Gesänge der Alten' von + Firudin dem Weisen: 'Diese verführerische kleine Melodie + und einige einschmeichelnde Worte überwinden das + Misstrauen der Bauern im Nu. Begeistert werden sie sich + Euch anschliessen und selbst Haus und Hof in Stich + lassen.' + From the 'Songs of the Elder' by + Firudin the Sage: 'This enticing little melody and its + ingratiating words will lure the peasants in no time. + They will leave home and hearth to follow your lead.' + + + Dieser fröhliche Gesang wird sich wie + ein Gerücht in der Region ausbreiten und alle Welt in + Feierlaune versetzten. Überall werden Tavernen und + Theater gut gefüllt sein und selbst die Bettler satt + werden. + This joyous song will spread like + wildfire throughout the region and cause festive spirits + in all the population. All the taverns and theaters will + be packed to the brim and even the beggars will not go + hungry. + + + Einem erfahrenen Magier wird + irgendwann auf seinen Wanderungen ein ungewöhnliches + Exemplar einer Gattung begegnen, welches sich dem Magier + anschließen wird. + Once during his travels, the seasoned + magician will meet an extraordinary creature of its species + that will join him. + + + Mit diesem Zauber greift der Magier + direkt den Geist seiner Gegner an. Ein Schlag aus + astraler und elektrischer Energie trifft die Gegner, + wird die Magieresistenz durchbrochen, verliert ein Opfer + permanent einen Teil seiner Erinnerungen. Wird es zu oft + ein Opfer dieses Zaubers kann es daran sterben. + With this spell the mentalist directly + attacks his enemies' souls. A blast of astral and + electrical energy strikes the foes. If a victim fails to + resist the magic, he will permanently lose part of his + memories. Being the target of this spell for too many + times may result in death. + + + Dieser Zauber - dessen Anwendung in + den meisten Kulturen streng verboten ist - löst im Opfer + ein unkontrollierbares Verlangen nach körperlicher Liebe + aus. Die betroffenen Personen werden sich Hals über Kopf + in ein Liebesabenteuer stürzen, zu blind vor Verlangen, + um an etwas anderes zu denken. Meistens bereuen sie es + einige Wochen später... + This spell - whose use is forbidden in + most cultures - creates an uncontrollable desire for + physical love in the victim. The affected persons will + rush head over heels into a love affair, unable to think + of anything else. Most of them will regret this a few + months later... + + + + + + Winter + winter + + + Sommer + summer + + + Frühling + spring + + + Herbst + fall + + + die erste Woche + the first week + + + die zweite Woche + the second week + + + die letzte Woche + the last week + + + der ersten Woche + of the first week + + + der zweiten Woche + of the second week + + + der letzten Woche + of the third week + + + Feldsegen + harvest moon + + + Nebeltage + impenetrable fog + + + Sturmmond + storm moon + + + Herdfeuer + hearth fire + + + Eiswind + icewind + + + Schneebann + snowbane + + + Blütenregen + flowerrain + + + Mond der milden Winde + mild winds + + + Sonnenfeuer + sunfire + + + des zweiten Zeitalters + the second age + + + neuer Zeitrechnung + of the new age + + + + + + Gemein + common + + + Kein Magiegebiet + no magic school yet + + + Illaun + Illaun + + + Tybied + Tybied + + + Gwyrrd + Gwyrrd + + + Cerddor + Cerddor + + + Draig + Draig + + + + + Baum + tree + + + Bäume + trees + + + + Mallornbaum + mallorn tree + + + Mallornbäume + mallorn trees + + + ALLIANZ + ALLIANCE + + + AUSSTOSSEN + KICK + + + NEU + NEW + + + KOMMANDO + COMMAND + + + VERLASSEN + LEAVE + + + BEITRETEN + JOIN + + + EINLADEN + INVITE + + + Steine + stones + + + + Pferde + horses + + + Bauern + peasants + + + Silber + silver + + + Laen + laen + + + + Schößlinge + saplings + + + + Mallornschößlinge + mallorn saplings + + + + Bäume + trees + + + + Mallorn + mallorn + + + + Eisen + iron + + + + Winter + winter + + + + Frühling + spring + + + + Sommer + summer + + + + Herbst + autumn + + + + Vorlage für den nächsten Zug: + Template for the next turn: + + + + Wir schreiben %s des Monats %s im Jahre %d %s. + It is %s of the month of %s in the %d. year of %s. + + + + Wir schreiben %s des Monats %s im Jahre %d %s. Es ist + %s. + It is %s of the month of %s in the %d. year of %s. It is + %s. + + + + aggressiv + aggressive + + + + vorne + front + + + + hinten + rear + + + + defensiv + defensive + + + + flieht + fleeing + + + + kämpft nicht + not fighting + + + + bekommt keine Hilfe + gets no aid + + + + Attacke gegen: + Attacked against + + + + Kämpft gegen: + Fighting against + + + + Hilft: + Helping + + + + Heer + army + + + + Unbekannte Partei + unknown faction + + + einer unbekannten Partei + an unknown faction + + + und + and + + + + Das Schiff des Elfen hat ein rotes Segel + + + + Der Zwerg hat eine Nuss dabei + + + + Die Katze führt eine Hellebarde + + + + Das Schiff mit dem grünen Segel liegt links neben dem + mit + einem weissen Segel + + + + Auf dem Schiff mit grünen Segeln kam der Speerkämpfer + + + + Der Krieger mit dem Kreis im Wappen hat einen Keks + + + + Der Krieger des mittleren Schiffs hat ein Schwert + + + + Auf dem gelben Segel prankt ein Kreuz als Wappen + + + + Der Mensch kam mit dem ersten Schiff + + + + Das Schiff mit dem Stern im Wappen liegt neben dem der + einen Mandelkern hat + + + + Das Schiff des Kriegers, der ein Apfel hat, liegt neben + dem, der ein Kreuz als Wappen hat + + + + Der Krieger mit dem Turm im Wappen trägt eine Axt + + + + Das Schiff des Menschen liegt neben dem blauen Schiff + + + + Das Insekt trägt einen Baum als Wappen + + + + Das Schiff mit dem Stern im Wappen liegt neben dem des + Kriegers, der einen Zweihänder führt + + + + Held + hero + + + + Helden + heroes + + + + + + Dunkel + dark + + + + Schwarz + black + + + + Licht + light + + + + Flammen + flame + + + + Eis + ice + + + + Klein + gully + + + + Hoch + high + + + + Hügel + hill + + + + Berg + mountain + + + + Wald + wood + + + + Sumpf + swamp + + + + Schnee + snow + + + + Sonnen + sun + + + + Mond + moon + + + + See + sea + + + + Tal + valley + + + + Schatten + shadow + + + + Höhlen + cave + + + + Blut + blood + + + + Wild + wild + + + + Chaos + chaos + + + + Nacht + night + + + + Nebel + mist + + + + Grau + grey + + + + Frost + cold + + + + Finster + gloom + + + + Düster + black + + + + Sternen + star + + + + + 'Ho ho ho!' Ein dicker Gnom fliegt auf einem von + 8 Jungdrachen gezogenen Schlitten durch die Nacht und vermacht Deiner + Partei ein Sonnensegel. (Um das Segel einer Einheit zu geben, gib + ihr den Befehl 'BEANSPRUCHE 1 Sonnensegel'). + 'Ho ho ho!' A fat little gnome Gnom on a sled + pulled by 8 young dragons flies through the stary night and presents + your faction with a solar sail. (To claim this item, one of your units + must issue the order 'CLAIM 1 solar sail'. + + + + 'Ho ho ho!' Ein dicker Gnom fliegt auf einem von + 8 Jungdrachen gezogenen Schlitten durch die Nacht und vermacht Deiner + Partei eine Phiole mit Sternenstaub. (Informationen dazu gibt es mit + BEANSPRUCHE und ZEIGE). + 'Ho ho ho!' A fat little gnome Gnom on a sled + pulled by 8 young dragons flies through the stary night and presents + your faction with a vial of stardust. (To get more information about + this item, use the CLAIM and SHOW commands). + + + + 'Ho ho ho!' Ein dicker Gnom fliegt auf einem von + 8 Jungdrachen gezogenen Schlitten durch die Nacht und vermacht Deiner + Partei einen wundervoll geschmueckten Weihnachtsbaum. (Informationen dazu gibt es mit + BEANSPRUCHE und ZEIGE). + 'Ho ho ho!' A fat little gnome Gnom on a sled + pulled by 8 young dragons flies through the stary night and presents + your faction with a beautifully decorated tree. (To get more information about + this item, use the CLAIM and SHOW commands). + + + + Gral + grail + + + + Grale + grails + + + + Lerntrank + brain boost + + + + Lerntränke + brain boosts + + + + GE je + stone per + + + + GE je + stones per + + + + GE + stone + + + + GE + stones + + + + bewacht die Region + guards the region + + + + und + and + + + + Dorfbewohner + Villagers + + + + Bauernmob + Angry mob + + + + Aufgebrachte Bauern + Furious peasants + + + + Söldner + Mercenaries + + + + Sumpfbewohner + Swamp people + + + + Waldbewohner + Woodsmen + + + + Nomaden + Nomads + + + + Eisleute + Ice people + + + + Bergbewohner + Mountain people + + + + Magie der Elemente + Magic of the Elements + + + + Schwerter, Armbrüste, Langbögen + Swords, Crossbows and Longbows + + + + Gorms Almanach der Rationellen Kriegsführung + Gorm's Almanach of Rational War + + + + Katamarane, Koggen, Karavellen + The dragonship, the caravell and the longboat + + + + Wege der Sterne + Ways of the Start + + + + Nadishahs Kleine Gift- und Kräuterkunde + Nadishah's collected lore on poisonous and beneficial herbs + + + + Mandricks Kompendium der Alchemie + Mandrick's alchemistic compendium + + + + Die Konstruktion der Burgen und Schlösser von Zentralandune + + + + Die Esse + + + + Über die Gewinnung von Erzen + + + + Barinions Lieder, eine Einführung für Unbedarfte + + + + die Ruine eines alten Tempels + the ruins of an ancient temple + + + + eine alte Burgruine + the ruins of a castle + + + + ein zerfallenes Bauernhaus + a dilapitated farm + + + + eine Leiche am Wegesrand + a corpse by the wayside + + + + eine Leiche am Wegesrand + a corpse by the wayside + + + + Feuerdrache + fire dragon + + + + Ein Alp starb, ohne sein Ziel zu erreichen. + An alp died before it reached its target. + + + + unbewaffnet + unarmed + + + + Trefferpunkte + hitpoints + + + + Rüstung + armor + + + + Angriff + attack + + + + Angriffe + attacks + + + + Verteidigung + defense + + + + Kann Waffen benutzen. + May use weapons. + + + + Ist durch Stichwaffen, Bögen und Armbrüste schwer zu verwunden. + Is hard to hit by piercing weapons. + + + + Ist durch Hiebwaffen schwer zu verwunden. + Is hard to hit by slashing weapons. + + + + Ist durch Schlagwaffen und Katapulte schwer zu verwunden. + Is hard to hit by blunt weapons and catapults. + + + + ein Angriff mit der Waffe oder unbewaffnet + an attack with a weapon or an unarmed attack + + + + ein unbewaffneter Angriff + an unarmed attack + + + + ein magischer Angriff + a magical attack + + + + Klon von %s + Clone of %s + + + + ein Angriff, der Gebäudeschaden verursacht + an attack causing structural damage to buildings + + + + Präkampfzauber + pre-combat spell + + + + Postkampfzauber + post-combat spell + + + + Kampfzauber + combat spell + + + + Normaler Zauber + regular spell + + + + Es ist Winter, und Insekten können nur in Wüsten oder mit Hilfe des Nestwärme-Tranks Personen rekrutieren. + It is winter, and insects can only recruit in deserts or with the aid of nestwarmth potions. + + + + Es ist Spätherbst, und diese Woche ist die letzte vor dem Winter, in der Insekten rekrutieren können. + + + + Eigentümer + Owner + + + + + eine Straße + a road + + + + Straßen + roads + + + + Straße + road + + + + eine zu %d%% vollendete Straße + a road that is %d%% complete + + + + ein Straßenanschluß + a connection to another road + + + + eine unvollständige Straße + an incomplete road + + + + Wand + wall + + + + eine Wand + a wall + + + + Feuerwand + firewall + + + + eine Feuerwand + a firewall + + + + Nebelwand + wall of fog + + + + eine Nebelwand + a wall of fog + + + + Irrlichter + wisps + + + + eine Gruppe von Irrlichtern + a cloud of wisps + + + + gewaltiges offenes Tor + massive open door + + + + ein gewaltiges offenes Tor + a massive open door + + + + gewaltiges verschlossenes Tor + massive locked door + + + + ein gewaltiges verschlossenes Tor + a massive locked door + + + + Illusionswand + illusionary wall + + + + eine Illusionswand + an illusionary wall + + + + + + Die Region ist verwüstet, der Boden karg. + The region is ravaged, the ground infertile. + + + + Einheit-Nr + unitid + + + + Schiff-Nr + shipid + + + + völker + tribes + + + + Gebäude-Nr + buildingid + + + + + Aura + aura + + + + Rasse + race + + + + Zauber-ID + spellid + + + + Richtung + direction + + + + Gebäudetyp + buildingtype + + + + diff --git a/res/en/strings.xml b/res/en/strings.xml index 6d1a56ebe..893007b43 100644 --- a/res/en/strings.xml +++ b/res/en/strings.xml @@ -1,1680 +1,1680 @@ - - - - - - - ADDRESSES - - - REPORT - - - BZIP2 - - - COMPUTER - - - DEBUG - - - ITEMPOOL - - - SCORE - - - SILVERPOOL - - - STATISTICS - - - EXPRESS - - - ZIPPED - - - TEMPLATE - - - SKILLCHANGES - - - - INFO - - - - - caravel - - - boat - - - longboat - - - dragonship - - - trireme - - - balloon - - - - - a caravel - - - a boat - - - a longboat - - - a balloon - - - a dragonship - - - a trireme - - - - - active volcano - - - corridor - - - desert - - - firewall - - - fog - - - forest - - - glacier - - - glacier - - - hallway - - - hell - - - highland - - - iceberg - - - maelstrom - - - mountain - - - ocean - - - plain - - - swamp - - - thick fog - - - volcano - - - magical storm - - - - the volcano of %s - - - a %s - - - the deserts of %s - - - a %s - - - fog_trail %s - - - the forests of %s - - - the glacier of %s - - - Wall - - - the %s - - - %s - - - the highlands of %s - - - a %s - - - the mountains of %s - - - the %s - - - the plain of %s - - - the swamps of %s - - - %s - - - the volcano of %s - - - a %s - - - - caldera - - - portal - - - - - NW - - - NE - - - East - - - SE - - - SW - - - West - - - - west - - - northwest - - - northeast - - - east - - - southwest - - - southeast - - - - an unknown unit - - - - Dispatches - - - Events - - - Warnings and Errors - - - Economy and Trade - - - Resources and Production - - - Magic and Artefacts - - - Movement and Travel - - - Learning and Teaching - - - Battles - - - Miscellaneous - - - New Spells - - - - - academy - - - blessed stonecircle - - - caravanserei - - - dam - - - structure - - - harbour - - - fairy castle - - - inn - - - lighthouse - - - mage tower - - - mine - - - monument - - - quarry - - - sawmill - - - smithy - - - stable - - - stonecircle - - - tunnel - - - - - foundation - - - tradepost - - - fortification - - - tower - - - castle - - - fortress - - - citadel - - - - - herb - - - vial - - - vials - - - - - silver - - - silver - - - hp - - - hps - - - aura - - - auras - - - permaura - - - permauras - - - peasant - - - peasants - - - - - almond - - - almonds - - - amulet - - - amulets - - - antimagic crystal - - - antimagic crystals - - - amulet of chastity - - - amulets of chastity - - - amulet of the kitten - - - amulets of the kitten - - - amulet of darkness - - - amulets of darkness - - - amulet of gathering - - - amulets of gathering - - - amulet of healing - - - amulets of healing - - - amulet of true seeing - - - amulets of true seeing - - - apple - - - apples - - - aurafocus - - - aurafocuses - - - axe - - - axes - - - bow - - - bows - - - cart - - - carts - - - catapult - - - catapults - - - chainmail - - - chainmails - - - cookie - - - cookies - - - crossbow - - - crossbows - - - dolphin - - - dolphins - - - dragonblood - - - dragonblood - - - dragonhead - - - dragonheads - - - dragonhoard - - - dreameye - - - dreameyes - - - elven horse - - - elven horses - - - eye of dragon - - - eye of dragons - - - fairy boots - - - fairy boots - - - flaming sword - - - flaming swords - - - elven bow - - - elven bows - - - claymore - - - claymores - - - halberd - - - halberds - - - healingpotion - - - healingpotions - - - herbbag - - - herbbags - - - horse - - - horses - - - iron - - - iron - - - laen - - - laen - - - laen chainmail - - - laen chainmails - - - laen shield - - - laen shields - - - laen sword - - - laen swords - - - lance - - - lances - - - wood - - - wood - - - magic bag - - - magic bags - - - bag of conservation - - - bags of conservation - - - mallorn - - - mallorn - - - mallorn bow - - - mallorn bows - - - mallorn crossbow - - - mallorn crossbows - - - mallorn lance - - - mallorn lances - - - mallorn spear - - - mallorn spear - - - silverbag - - - silverchest - - - returnticket for the grand museum - - - returntickets for the grand museum - - - ticket to the grand museum - - - tickets to the grand museum - - - nut - - - nuts - - - pegasus - - - pegasi - - - man - - - men - - - platemail - - - platemails - - - pangolin - - - pangolins - - - presspass - - - presspasses - - - ring of invisibility - - - rings of invisibility - - - ring of power - - - rings of power - - - ring of quick fingers - - - rings of quick fingers - - - ring of regeneration - - - rings of regeneration - - - runesword - - - runeswords - - - rustychainmail - - - rustychainmails - - - rusty shield - - - rusty shields - - - rusty sword - - - rusty swords - - - seaserpenthead - - - seaserpentheads - - - shield - - - shields - - - sack of holding - - - sacks of holding - - - spear - - - spears - - - stone - - - stones - - - sword - - - swords - - - pot of toadslime - - - pots of toadslime - - - trollbelt - - - trollbelts - - - unit - - - units - - - potion of skills - - - potions of skills - - - astralcrystal - - - astralcrystals - - - seed - - - seeds - - - mallorn seed - - - mallorn seeds - - - firework - - - fireworks - - - gingerbread heart - - - gingerbread hearts - - - - - balm - - - spice - - - gem - - - gems - - - myrrh - - - oil - - - silk - - - incense - - - balm - - - spice - - - myrrh - - - oil - - - silk - - - incense - - - - - Belt of Heroic Legends - - - Belts of Heroic Legends - - - - - flatroot - - - flatroots - - - tangy temerity - - - tangy temerities - - - owlsgaze - - - owlsgazes - - - spider ivy - - - spider ivies - - - cobalt fungus - - - cobalt fungi - - - elvendear - - - elvendears - - - bugleweed - - - bugleweeds - - - knotroot - - - knotroots - - - bubblemorel - - - bubblemorels - - - waterfinder - - - waterfinders - - - peyote - - - peyote - - - sand reeker - - - sand reekers - - - windbag - - - windbags - - - fjord fungus - - - fjord fungi - - - mandrake - - - mandrakes - - - rock weed - - - rock weed - - - gapgrowth - - - gapgrowths - - - cave lichen - - - cave lichen - - - ice begonia - - - ice begonias - - - white hemlock - - - white hemlocks - - - snowcrystal petal - - - snowcrystal petals - - - seven mile tea - - - seven mile teas - - - goliath water - - - goliath waters - - - water of life - - - waters of life - - - busybeer - - - busybeers - - - ointment - - - ointments - - - peasant blood - - - peasant bloods - - - brain wax - - - brain waxes - - - duncebun - - - duncebuns - - - potion of nest warmth - - - potions of nest warmth - - - horsepower potion - - - horsepower potions - - - berserkers blood potion - - - berserkers blood potions - - - peasant love potion - - - peasant love potion - - - potion of truth - - - potions of truth - - - elixir of power - - - elixirs of power - - - healing potion - - - healing potions - - - - - AGGRESSIVE - - - ALL - - - EACH - - - NUMBER - - - AURA - - - TREES - - - PEASANTS - - - AID - - - GUARD - - - CASTLE - - - DEFENSIVE - - - UNIT - - - ERESSEA - - - FLEE - - - FOREIGN - - - BUILDING - - - ITEMS - - - GIVE - - - MERCY - - - HELP - - - REAR - - - AFTER - - - CONTROL - - - HERBS - - - COMBAT - - - NOT - - - NEXT - - - FACTION - - - FACTIONSTEALTH - - - PAUSE - - - MEN - - - PRIVATE - - - REGION - - - SHIP - - - SILVER - - - ROADS - - - LEVEL - - - TEMPORARY - - - POTIONS - - - FOR - - - BEFORE - - - FRONT - - - SPELLS - - - - - alchemy - - - armoursmithing - - - bow - - - masonry - - - cartmaking - - - catapult - - - crossbow - - - entertainment - - - espionage - - - forestry - - - herbalism - - - magic - - - melee - - - mining - - - perception - - - polearm - - - quarrying - - - riding - - - roadwork - - - sailing - - - shipcraft - - - endurance - - - stealth - - - tactics - - - taxation - - - trade - - - taming - - - unarmed combat - - - weaponsmithing - - - - - - // - - - WORK - - - ATTACK - - - BANNER - - - STEAL - - - BESIEGE - - - NAME - - - USE - - - DESCRIBE - - - PRAY - - - ENTER - - - GUARD - - - BID - - - MESSAGE - - - DEFAULT - - - EMAIL - - - END - - - RIDE - - - FOLLOW - - - RESEARCH - - - GM - - - GROUP - - - HELP - - - JIHAD - - - COMBATSPELL - - - BUY - - - CONTACT - - - COMBAT - - - TEACH - - - LEARN - - - SUPPLY - - - LOCALE - - - MAKE - - - MOVE - - - RESTART - - - NUMBER - - - SACRIFICE - - - OPTION - - - PASSWORD - - - PLANT - - - PIRACY - - - PREFIX - - - RECRUIT - - - REPORT - - - RESERVE - - - ROUTE - - - SABOTAGE - - - SORT - - - SPY - - - QUIT - - - SYNONYM - - - HIDE - - - CARRY - - - TAX - - - ENTERTAIN - - - ORIGIN - - - FORGET - - - SELL - - - LEAVE - - - CAST - - - SHOW - - - DESTROY - - - GROW - - - LYCANTROPE - - - - - Options - - - Level - - - Political Status - - - Herbs required - - - under construction - - - damage - - - Your faction has been eliminated. We hope that you had a good time, and if you liked the game, you should sign up and play again. - - - - skills - - - has - - - size - - - spells - - - combat spells - - - none - - - Addresses - - - anonymous - - - attack - - - defense - - - armour - - - damage - - - - - wand - - - wands - - - - - - northwest coast - - - northeast coast - - - east coast - - - southeast coast - - - southwest coast - - - west coast - - - - - No orders were received for your faction! - - - - - Mistelzweig - mistletoe - - - Mistelzweige - mistletoes - - + + + + + + + ADDRESSES + + + REPORT + + + BZIP2 + + + COMPUTER + + + DEBUG + + + ITEMPOOL + + + SCORE + + + SILVERPOOL + + + STATISTICS + + + EXPRESS + + + ZIPPED + + + TEMPLATE + + + SKILLCHANGES + + + + INFO + + + + + caravel + + + boat + + + longboat + + + dragonship + + + trireme + + + balloon + + + + + a caravel + + + a boat + + + a longboat + + + a balloon + + + a dragonship + + + a trireme + + + + + active volcano + + + corridor + + + desert + + + firewall + + + fog + + + forest + + + glacier + + + glacier + + + hallway + + + hell + + + highland + + + iceberg + + + maelstrom + + + mountain + + + ocean + + + plain + + + swamp + + + thick fog + + + volcano + + + magical storm + + + + the volcano of %s + + + a %s + + + the deserts of %s + + + a %s + + + fog_trail %s + + + the forests of %s + + + the glacier of %s + + + Wall + + + the %s + + + %s + + + the highlands of %s + + + a %s + + + the mountains of %s + + + the %s + + + the plain of %s + + + the swamps of %s + + + %s + + + the volcano of %s + + + a %s + + + + caldera + + + portal + + + + + NW + + + NE + + + East + + + SE + + + SW + + + West + + + + west + + + northwest + + + northeast + + + east + + + southwest + + + southeast + + + + an unknown unit + + + + Dispatches + + + Events + + + Warnings and Errors + + + Economy and Trade + + + Resources and Production + + + Magic and Artefacts + + + Movement and Travel + + + Learning and Teaching + + + Battles + + + Miscellaneous + + + New Spells + + + + + academy + + + blessed stonecircle + + + caravanserei + + + dam + + + structure + + + harbour + + + fairy castle + + + inn + + + lighthouse + + + mage tower + + + mine + + + monument + + + quarry + + + sawmill + + + smithy + + + stable + + + stonecircle + + + tunnel + + + + + foundation + + + tradepost + + + fortification + + + tower + + + castle + + + fortress + + + citadel + + + + + herb + + + vial + + + vials + + + + + silver + + + silver + + + hp + + + hps + + + aura + + + auras + + + permaura + + + permauras + + + peasant + + + peasants + + + + + almond + + + almonds + + + amulet + + + amulets + + + antimagic crystal + + + antimagic crystals + + + amulet of chastity + + + amulets of chastity + + + amulet of the kitten + + + amulets of the kitten + + + amulet of darkness + + + amulets of darkness + + + amulet of gathering + + + amulets of gathering + + + amulet of healing + + + amulets of healing + + + amulet of true seeing + + + amulets of true seeing + + + apple + + + apples + + + aurafocus + + + aurafocuses + + + axe + + + axes + + + bow + + + bows + + + cart + + + carts + + + catapult + + + catapults + + + chainmail + + + chainmails + + + cookie + + + cookies + + + crossbow + + + crossbows + + + dolphin + + + dolphins + + + dragonblood + + + dragonblood + + + dragonhead + + + dragonheads + + + dragonhoard + + + dreameye + + + dreameyes + + + elven horse + + + elven horses + + + eye of dragon + + + eye of dragons + + + fairy boots + + + fairy boots + + + flaming sword + + + flaming swords + + + elven bow + + + elven bows + + + claymore + + + claymores + + + halberd + + + halberds + + + healingpotion + + + healingpotions + + + herbbag + + + herbbags + + + horse + + + horses + + + iron + + + iron + + + laen + + + laen + + + laen chainmail + + + laen chainmails + + + laen shield + + + laen shields + + + laen sword + + + laen swords + + + lance + + + lances + + + wood + + + wood + + + magic bag + + + magic bags + + + bag of conservation + + + bags of conservation + + + mallorn + + + mallorn + + + mallorn bow + + + mallorn bows + + + mallorn crossbow + + + mallorn crossbows + + + mallorn lance + + + mallorn lances + + + mallorn spear + + + mallorn spear + + + silverbag + + + silverchest + + + returnticket for the grand museum + + + returntickets for the grand museum + + + ticket to the grand museum + + + tickets to the grand museum + + + nut + + + nuts + + + pegasus + + + pegasi + + + man + + + men + + + platemail + + + platemails + + + pangolin + + + pangolins + + + presspass + + + presspasses + + + ring of invisibility + + + rings of invisibility + + + ring of power + + + rings of power + + + ring of quick fingers + + + rings of quick fingers + + + ring of regeneration + + + rings of regeneration + + + runesword + + + runeswords + + + rustychainmail + + + rustychainmails + + + rusty shield + + + rusty shields + + + rusty sword + + + rusty swords + + + seaserpenthead + + + seaserpentheads + + + shield + + + shields + + + sack of holding + + + sacks of holding + + + spear + + + spears + + + stone + + + stones + + + sword + + + swords + + + pot of toadslime + + + pots of toadslime + + + trollbelt + + + trollbelts + + + unit + + + units + + + potion of skills + + + potions of skills + + + astralcrystal + + + astralcrystals + + + seed + + + seeds + + + mallorn seed + + + mallorn seeds + + + firework + + + fireworks + + + gingerbread heart + + + gingerbread hearts + + + + + balm + + + spice + + + gem + + + gems + + + myrrh + + + oil + + + silk + + + incense + + + balm + + + spice + + + myrrh + + + oil + + + silk + + + incense + + + + + Belt of Heroic Legends + + + Belts of Heroic Legends + + + + + flatroot + + + flatroots + + + tangy temerity + + + tangy temerities + + + owlsgaze + + + owlsgazes + + + spider ivy + + + spider ivies + + + cobalt fungus + + + cobalt fungi + + + elvendear + + + elvendears + + + bugleweed + + + bugleweeds + + + knotroot + + + knotroots + + + bubblemorel + + + bubblemorels + + + waterfinder + + + waterfinders + + + peyote + + + peyote + + + sand reeker + + + sand reekers + + + windbag + + + windbags + + + fjord fungus + + + fjord fungi + + + mandrake + + + mandrakes + + + rock weed + + + rock weed + + + gapgrowth + + + gapgrowths + + + cave lichen + + + cave lichen + + + ice begonia + + + ice begonias + + + white hemlock + + + white hemlocks + + + snowcrystal petal + + + snowcrystal petals + + + seven mile tea + + + seven mile teas + + + goliath water + + + goliath waters + + + water of life + + + waters of life + + + busybeer + + + busybeers + + + ointment + + + ointments + + + peasant blood + + + peasant bloods + + + brain wax + + + brain waxes + + + duncebun + + + duncebuns + + + potion of nest warmth + + + potions of nest warmth + + + horsepower potion + + + horsepower potions + + + berserkers blood potion + + + berserkers blood potions + + + peasant love potion + + + peasant love potion + + + potion of truth + + + potions of truth + + + elixir of power + + + elixirs of power + + + healing potion + + + healing potions + + + + + AGGRESSIVE + + + ALL + + + EACH + + + NUMBER + + + AURA + + + TREES + + + PEASANTS + + + AID + + + GUARD + + + CASTLE + + + DEFENSIVE + + + UNIT + + + ERESSEA + + + FLEE + + + FOREIGN + + + BUILDING + + + ITEMS + + + GIVE + + + MERCY + + + HELP + + + REAR + + + AFTER + + + CONTROL + + + HERBS + + + COMBAT + + + NOT + + + NEXT + + + FACTION + + + FACTIONSTEALTH + + + PAUSE + + + MEN + + + PRIVATE + + + REGION + + + SHIP + + + SILVER + + + ROADS + + + LEVEL + + + TEMPORARY + + + POTIONS + + + FOR + + + BEFORE + + + FRONT + + + SPELLS + + + + + alchemy + + + armoursmithing + + + bow + + + masonry + + + cartmaking + + + catapult + + + crossbow + + + entertainment + + + espionage + + + forestry + + + herbalism + + + magic + + + melee + + + mining + + + perception + + + polearm + + + quarrying + + + riding + + + roadwork + + + sailing + + + shipcraft + + + endurance + + + stealth + + + tactics + + + taxation + + + trade + + + taming + + + unarmed combat + + + weaponsmithing + + + + + + // + + + WORK + + + ATTACK + + + BANNER + + + STEAL + + + BESIEGE + + + NAME + + + USE + + + DESCRIBE + + + PRAY + + + ENTER + + + GUARD + + + BID + + + MESSAGE + + + DEFAULT + + + EMAIL + + + END + + + RIDE + + + FOLLOW + + + RESEARCH + + + GM + + + GROUP + + + HELP + + + JIHAD + + + COMBATSPELL + + + BUY + + + CONTACT + + + COMBAT + + + TEACH + + + LEARN + + + SUPPLY + + + LOCALE + + + MAKE + + + MOVE + + + RESTART + + + NUMBER + + + SACRIFICE + + + OPTION + + + PASSWORD + + + PLANT + + + PIRACY + + + PREFIX + + + RECRUIT + + + REPORT + + + RESERVE + + + ROUTE + + + SABOTAGE + + + SORT + + + SPY + + + QUIT + + + SYNONYM + + + HIDE + + + CARRY + + + TAX + + + ENTERTAIN + + + ORIGIN + + + FORGET + + + SELL + + + LEAVE + + + CAST + + + SHOW + + + DESTROY + + + GROW + + + LYCANTROPE + + + + + Options + + + Level + + + Political Status + + + Herbs required + + + under construction + + + damage + + + Your faction has been eliminated. We hope that you had a good time, and if you liked the game, you should sign up and play again. + + + + skills + + + has + + + size + + + spells + + + combat spells + + + none + + + Addresses + + + anonymous + + + attack + + + defense + + + armour + + + damage + + + + + wand + + + wands + + + + + + northwest coast + + + northeast coast + + + east coast + + + southeast coast + + + southwest coast + + + west coast + + + + + No orders were received for your faction! + + + + + Mistelzweig + mistletoe + + + Mistelzweige + mistletoes + + diff --git a/res/equipment.xml b/res/equipment.xml index a175af7b9..935de5806 100644 --- a/res/equipment.xml +++ b/res/equipment.xml @@ -1,399 +1,399 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/fr/strings.xml b/res/fr/strings.xml index ff2bdf205..850085eaf 100644 --- a/res/fr/strings.xml +++ b/res/fr/strings.xml @@ -1,2082 +1,2082 @@ - - - - - - PASSAGE - - - XEPOTION - - - XEBALLON - - - XELAEN - - - GUERRE - - - PAIX - - - XONTORMIA - - - ALLIANCE - - - ADRESSES - - - RAPPORT - - - BZIP2 - - - ORDINATEUR - - - DEBOGUER - - - RESSOURCES COMMUNES - - - SCORE - - - ARGENT COMMUN - - - STATISTIQUES - - - EXPRESS - - - ZIPPE - - - MODELE - - - MODIFICATIONS - - - - INFO - - - - - nef - - - chaloupe - - - barge - - - drakkar - - - galère - - - ballon - - - - - une nef - - - une chaloupe - - - une barge - - - un ballon - - - un drakkar - - - une galère - - - - - volcan actif - - - couloir - - - désert - - - mur de feu - - - brume - - - forêt - - - glacier - - - vestibule - - - l'enfer - - - colline - - - iceberg - - - maelström - - - montagne - - - océan - - - plaine - - - marais - - - brouillard - - - volcan - - - tempête magique - - - - le volcan %s - - - un %s - - - le désert de %s - - - un %s - - - fog_trail %s - - - la forêt de %s - - - le glacier de %s - - - le %s - - - %s - - - les collines de %s - - - un %s - - - un %s - - - les montagnes de %s - - - l'%s - - - la plaine de %s - - - les marais de %s - - - %s - - - le volcan de %s - - - une %s - - - - caldera - - - portail - - - - - NO - - - NE - - - Est - - - SE - - - SO - - - Ouest - - - - ouest - - - nord-ouest - - - nord-est - - - est - - - sud-ouest - - - sud-est - - - - une unité inconnue - - - - Messages et Evénements - - - Avertissements et Erreurs - - - Economie et Commerce - - - Ressources et Production - - - Magie et Reliques - - - Déplacements et Voyages - - - Apprentissage et Enseignement - - - Batailles - - - Divers - - - Nouveaux Sorts - - - - - université - - - cromlech sacré - - - caravansérail - - - barrage - - - bâtiment - - - port - - - château illusoire - - - auberge - - - phare - - - donjon - - - mine - - - monument - - - carrière - - - scierie - - - forge - - - écurie - - - cromlech - - - tunnel - - - - - palissade - - - comptoir - - - rempart - - - tour - - - château - - - place-forte - - - citadelle - - - - - plante - - - fiole - - - fioles - - - - - écu - - - écus - - - point de vie - - - points de vie - - - aura - - - aura - - - aura permanente - - - aura permanente - - - paysan - - - paysans - - - - - amande - - - amandes - - - amulette - - - amulettes - - - cristal antimagie - - - cristaux antimagie - - - amulette de chasteté - - - amulettes de chasteté - - - amulette du chaton - - - amulettes du chaton - - - amulette de ténèbres - - - amulettes de ténèbres - - - amulette de rassemblement - - - amulettes de rassemblement - - - amulette de soin - - - amulettes de soin - - - amulette de vérité - - - amulettes de vérité - - - pomme - - - pommes - - - focus - - - foci - - - hache - - - haches - - - arc - - - arcs - - - chariot - - - chariots - - - catapulte - - - catapultes - - - cotte de mailles - - - cottes de mailles - - - gâteau - - - gâteaux - - - arbalète - - - arbalètes - - - dauphin - - - dauphins - - - sang de dragon - - - sang de dragon - - - tête de dragon - - - têtes de dragons - - - trésor de dragon - - - oniroeil - - - oniryeux - - - cheval elfique - - - chevaux elfiques - - - oeil de dragon - - - yeux de dragon - - - bottes elfiques - - - bottes elfiques - - - épée ardente - - - épées ardentes - - - grand arc - - - grands arcs - - - claymore - - - claymores - - - halebarde - - - halebardes - - - potion de soin - - - potions de soin - - - sac de plantes - - - sacs de plantes - - - cheval - - - chevaux - - - lingot - - - lingots - - - laen - - - laen - - - cotte en laen - - - cottes en laen - - - bouclier en laen - - - boucliers en laen - - - épée en laen - - - épées en laen - - - lance - - - lances - - - stère - - - stères - - - sac magique - - - sacs magiques - - - sac de conservation - - - sacs de conservation - - - mallorn - - - mallorn - - - arc en mallorn - - - arcs en mallorn - - - arbalète en mallorn - - - arbalètes en mallorn - - - lance en mallorn - - - lances en mallorn - - - épieu en mallorn - - - épieux en mallorn - - - bourse - - - cassette - - - returnticket for the grand museum - - - returntickets for the grand museum - - - ticket to the grand museum - - - tickets to the grand museum - - - noix - - - noix - - - pégase - - - pégases - - - homme - - - hommes - - - armure de plates - - - armures de plates - - - carte de presse - - - cartes de presse - - - anneau d'invisibilité - - - anneaux d'invisibilité - - - anneau de pouvoir - - - anneaux de pouvoir - - - anneau de dextérité - - - anneaux de dextérité - - - anneau de régénération - - - anneaux de régénération - - - épée runique - - - épées runiques - - - cotte de mailles rouillée - - - cottes de mailles rouillées - - - bouclier rouillé - - - boucliers rouillés - - - épée rouillée - - - épées rouillées - - - tête de serpent de mer - - - têtes de serpents de mer - - - bouclier - - - boucliers - - - sac de contenance - - - sacs de contenance - - - épieu - - - épieux - - - pierre - - - pierres - - - épée - - - épées - - - pot de bave de crapaud - - - pots de bave de crapaud - - - ceinture de troll - - - ceintures de trolls - - - unité - - - unités - - - potion de compétences - - - potions de compétences - - - cristal astral - - - cristaux astraux - - - graine - - - graines - - - graine de mallorn - - - graines de mallorn - - - feu d'artifice - - - feux d'artifice - - - coeur de pain d'épices - - - coeurs de pain d'épices - - - - - baume - - - épices - - - joyau - - - joyaux - - - myrrhe - - - huile - - - soie - - - encens - - - baume - - - épices - - - myrrhe - - - huile - - - soie - - - encens - - - - - Ceinture des Légendes - - - Ceintures des Légendes - - - - - astragale - - - astragales - - - méritoine - - - méritoines - - - oeil de hibou - - - yeux de hibou - - - soie d'araignée - - - soies d'araignée - - - obbadion - - - obbadions - - - cheveux d'elfe - - - cheveux d'elfe - - - ortigal - - - ortigals - - - tubercule de respiplante - - - tubercules de respiplante - - - oreille de morille - - - oreilles de morille - - - hydropousse - - - hydropousses - - - ossiphage - - - ossiphages - - - fleur de souffre - - - fleurs de souffre - - - feuille de Tshaï - - - feuilles de Tshaï - - - bélidane - - - bélidanes - - - racine de mandragore - - - racines de mandragore - - - percepierre - - - percepierres - - - tanemiel - - - tanemiels - - - boralme - - - boralmes - - - ficoïde à cristaux - - - ficoïdes à cristaux - - - blémissure - - - blémissures - - - rose des neiges - - - roses des neiges - - - thé de sept lieues - - - thé de sept lieues - - - breuvage de Goliath - - - breuvage de Goliath - - - élixir de vie - - - élixir de vie - - - vin du travail acharné - - - vin du travail acharné - - - onguent de soin - - - onguents de soin - - - fiole d'essence vitale - - - fioles d'essence vitale - - - huile de cogitation - - - huile de cogitation - - - petit pain rance - - - petits pains rances - - - extrait de canicule - - - extraits de canicule - - - fourrage de l'étalon - - - fourrage de l'étalon - - - vin de folie - - - vin de folie - - - philtre d'amour - - - philtres d'amour - - - sirop de claivoyance - - - sirops de claivoyance - - - elixir d'endurance - - - elixir d'endurance - - - potion de survie - - - potions de survie - - - - - AGRESSIF - - - TOUT - - - NOMBRE - - - AURA - - - ARBRES - - - PAYSANS - - - SOUTIEN - - - GUARDE - - - CHATEAU - - - DEFENSIF - - - UNITE - - - ERESSEA - - - FUITE - - - ETRANGER - - - BATIMENT - - - OBJETS - - - DONNER - - - PITIE - - - AIDE - - - DERRIERE - - - APRES - - - CONTROLE - - - PLANTES - - - COMBAT - - - NON - - - SUIVANT - - - FACTION - - - CAMOUFLAGE - - - PAUSE - - - HOMMES - - - PRIVE - - - REGION - - - BATEAU - - - ECUS - - - ROUTES - - - NIVEAU - - - TEMPORAIRE - - - POTIONS - - - POUR - - - AVANT - - - DEVANT - - - SORTS - - - - - alchimie - - - armurier - - - arc - - - maçon - - - charron - - - catapulte - - - arbalète - - - divertissement - - - espionnage - - - bucheron - - - herboriste - - - magie - - - mêlée - - - mineur - - - observation - - - hast - - - perrayeur - - - équitation - - - cantonnier - - - navigation - - - charpentier - - - endurance - - - discrétion - - - tactique - - - percepteur - - - commerce - - - dresseur - - - mains-nues - - - fourbisseur - - - - - - // - - - TRAVAILLER - - - ATTAQUER - - - ANNONCE - - - VOLER - - - ASSIEGER - - - NOMMER - - - UTILISER - - - DECRIRE - - - PRIER - - - ENTRER - - - GUARDER - - - OFFRIR - - - MESSAGE - - - DEFAUT - - - EMAIL - - - FIN - - - CHEVAUCHER - - - SUIVRE - - - CHERCHER - - - GM - - - GROUPER - - - AIDER - - - JIHAD - - - PREPARER - - - ACHETER - - - CONTACTER - - - COMBATTRE - - - ENSEIGNER - - - APPRENDRE - - - FOURNIR - - - LOCAL - - - FAIRE - - - ALLER - - - RECOMMENCER - - - NOMBRE - - - SACRIFIER - - - OPTION - - - PASSWORD - - - PLANTER - - - PIRATERIE - - - PREFIXE - - - RECRUTER - - - RAPPORT - - - RESERVER - - - TRAJET - - - SABOTER - - - TRIER - - - ESPIONNER - - - ABANDONNER - - - SYNONYME - - - CACHER - - - TRANSPORTER - - - TAXER - - - DIVERTIR - - - ORIGINE - - - OUBLIER - - - VENDRE - - - SORTIR - - - INCANTER - - - MONTRER - - - DETRUIRE - - - ACCROITRE - - - METAMORPHOSE - - - - - sangsunicornes - - - sangsunicorne - - - cauchemars - - - cauchemar - - - ombreillards - - - ombreillard - - - draco tenebrae - - - draco tenebrae - - - nains - - - nain - - - elfes - - - elfe - - - orques - - - orque - - - snotlings - - - snotling - - - gobelins - - - gobelin - - - humains - - - humain - - - trolls - - - troll - - - démons - - - démons - - - insectes - - - insecte - - - hobbits - - - hobbit - - - chats - - - chat - - - atlantes - - - atlante - - - morts-vivants - - - mort-vivant - - - illusions - - - illusion - - - dragonnets - - - dragonnet - - - dragons - - - dragon - - - wyrms - - - wyrm - - - ents - - - ent - - - dragons-chats - - - dragon-chat - - - draconiens - - - draconien - - - spéciaux - - - spécial - - - enchantements - - - enchantement - - - golems de fer - - - golem de fer - - - golems de pierre - - - golem de pierre - - - ombres - - - ombre - - - lémures - - - lémure - - - yétis - - - yéti - - - quauquemaires - - - quauquemaire - - - crapauds - - - crapaud - - - céphalophages - - - céphalophage - - - paysans - - - paysan - - - wargs - - - warg - - - lynx - - - lynx - - - vers des profondeurs - - - ver des profondeurs - - - rats - - - rat - - - dragons chinois - - - dragon chinois - - - loups - - - loup - - - fantômes - - - fantôme - - - chats des rêves - - - chat des rêves - - - chats de l'Enfer - - - chat de l'Enfer - - - tigres - - - tigre - - - dauphins - - - dauphin - - - tortues géantes - - - tortue géante - - - krakens - - - kraken - - - serpents de mer - - - serpent de mer - - - guerriers illusoires - - - guerrier illusoire - - - diablotins - - - diablotin - - - nymphes - - - nymphe - - - licornes - - - licorne - - - hiboux - - - hibou - - - fées - - - fée - - - aigles - - - aigle - - - centaures - - - centaure - - - squelettes - - - squelette - - - liches - - - liche - - - zombies - - - zombie - - - zombies juju - - - zombie juju - - - goules - - - goule - - - spectres - - - spectre - - - fantômes du musée - - - fantôme du musée - - - gnomes - - - gnome - - - modèles - - - modèle - - - métamorphes - - - métamorphe - - - - - - Options - - - Niveau - - - Statut Politique - - - Plantes nécessaires - - - en construction - - - de dégâts - - - Votre faction a été éliminée. Nous espérons que vous vous êtes bien amusé malgré tout, et vous encourageons à vous réincrire pour une nouvelle partie. - - - - compétences - - - possessions - - - taille - - - sorts - - - sorts de combat - - - aucun - - - Adresses - - - anonyme - - - attaque - - - défense - - - armure - - - dégâts - - - - - baguette - - - baguettes - - - - - - côte nord-ouest - - - côte nord-est - - - côte est - - - côte sud-est - - - côte sud-ouest - - - côte ouest - - - - Aucun ordre reçu pour votre faction ! - - + + + + + + PASSAGE + + + XEPOTION + + + XEBALLON + + + XELAEN + + + GUERRE + + + PAIX + + + XONTORMIA + + + ALLIANCE + + + ADRESSES + + + RAPPORT + + + BZIP2 + + + ORDINATEUR + + + DEBOGUER + + + RESSOURCES COMMUNES + + + SCORE + + + ARGENT COMMUN + + + STATISTIQUES + + + EXPRESS + + + ZIPPE + + + MODELE + + + MODIFICATIONS + + + + INFO + + + + + nef + + + chaloupe + + + barge + + + drakkar + + + galère + + + ballon + + + + + une nef + + + une chaloupe + + + une barge + + + un ballon + + + un drakkar + + + une galère + + + + + volcan actif + + + couloir + + + désert + + + mur de feu + + + brume + + + forêt + + + glacier + + + vestibule + + + l'enfer + + + colline + + + iceberg + + + maelström + + + montagne + + + océan + + + plaine + + + marais + + + brouillard + + + volcan + + + tempête magique + + + + le volcan %s + + + un %s + + + le désert de %s + + + un %s + + + fog_trail %s + + + la forêt de %s + + + le glacier de %s + + + le %s + + + %s + + + les collines de %s + + + un %s + + + un %s + + + les montagnes de %s + + + l'%s + + + la plaine de %s + + + les marais de %s + + + %s + + + le volcan de %s + + + une %s + + + + caldera + + + portail + + + + + NO + + + NE + + + Est + + + SE + + + SO + + + Ouest + + + + ouest + + + nord-ouest + + + nord-est + + + est + + + sud-ouest + + + sud-est + + + + une unité inconnue + + + + Messages et Evénements + + + Avertissements et Erreurs + + + Economie et Commerce + + + Ressources et Production + + + Magie et Reliques + + + Déplacements et Voyages + + + Apprentissage et Enseignement + + + Batailles + + + Divers + + + Nouveaux Sorts + + + + + université + + + cromlech sacré + + + caravansérail + + + barrage + + + bâtiment + + + port + + + château illusoire + + + auberge + + + phare + + + donjon + + + mine + + + monument + + + carrière + + + scierie + + + forge + + + écurie + + + cromlech + + + tunnel + + + + + palissade + + + comptoir + + + rempart + + + tour + + + château + + + place-forte + + + citadelle + + + + + plante + + + fiole + + + fioles + + + + + écu + + + écus + + + point de vie + + + points de vie + + + aura + + + aura + + + aura permanente + + + aura permanente + + + paysan + + + paysans + + + + + amande + + + amandes + + + amulette + + + amulettes + + + cristal antimagie + + + cristaux antimagie + + + amulette de chasteté + + + amulettes de chasteté + + + amulette du chaton + + + amulettes du chaton + + + amulette de ténèbres + + + amulettes de ténèbres + + + amulette de rassemblement + + + amulettes de rassemblement + + + amulette de soin + + + amulettes de soin + + + amulette de vérité + + + amulettes de vérité + + + pomme + + + pommes + + + focus + + + foci + + + hache + + + haches + + + arc + + + arcs + + + chariot + + + chariots + + + catapulte + + + catapultes + + + cotte de mailles + + + cottes de mailles + + + gâteau + + + gâteaux + + + arbalète + + + arbalètes + + + dauphin + + + dauphins + + + sang de dragon + + + sang de dragon + + + tête de dragon + + + têtes de dragons + + + trésor de dragon + + + oniroeil + + + oniryeux + + + cheval elfique + + + chevaux elfiques + + + oeil de dragon + + + yeux de dragon + + + bottes elfiques + + + bottes elfiques + + + épée ardente + + + épées ardentes + + + grand arc + + + grands arcs + + + claymore + + + claymores + + + halebarde + + + halebardes + + + potion de soin + + + potions de soin + + + sac de plantes + + + sacs de plantes + + + cheval + + + chevaux + + + lingot + + + lingots + + + laen + + + laen + + + cotte en laen + + + cottes en laen + + + bouclier en laen + + + boucliers en laen + + + épée en laen + + + épées en laen + + + lance + + + lances + + + stère + + + stères + + + sac magique + + + sacs magiques + + + sac de conservation + + + sacs de conservation + + + mallorn + + + mallorn + + + arc en mallorn + + + arcs en mallorn + + + arbalète en mallorn + + + arbalètes en mallorn + + + lance en mallorn + + + lances en mallorn + + + épieu en mallorn + + + épieux en mallorn + + + bourse + + + cassette + + + returnticket for the grand museum + + + returntickets for the grand museum + + + ticket to the grand museum + + + tickets to the grand museum + + + noix + + + noix + + + pégase + + + pégases + + + homme + + + hommes + + + armure de plates + + + armures de plates + + + carte de presse + + + cartes de presse + + + anneau d'invisibilité + + + anneaux d'invisibilité + + + anneau de pouvoir + + + anneaux de pouvoir + + + anneau de dextérité + + + anneaux de dextérité + + + anneau de régénération + + + anneaux de régénération + + + épée runique + + + épées runiques + + + cotte de mailles rouillée + + + cottes de mailles rouillées + + + bouclier rouillé + + + boucliers rouillés + + + épée rouillée + + + épées rouillées + + + tête de serpent de mer + + + têtes de serpents de mer + + + bouclier + + + boucliers + + + sac de contenance + + + sacs de contenance + + + épieu + + + épieux + + + pierre + + + pierres + + + épée + + + épées + + + pot de bave de crapaud + + + pots de bave de crapaud + + + ceinture de troll + + + ceintures de trolls + + + unité + + + unités + + + potion de compétences + + + potions de compétences + + + cristal astral + + + cristaux astraux + + + graine + + + graines + + + graine de mallorn + + + graines de mallorn + + + feu d'artifice + + + feux d'artifice + + + coeur de pain d'épices + + + coeurs de pain d'épices + + + + + baume + + + épices + + + joyau + + + joyaux + + + myrrhe + + + huile + + + soie + + + encens + + + baume + + + épices + + + myrrhe + + + huile + + + soie + + + encens + + + + + Ceinture des Légendes + + + Ceintures des Légendes + + + + + astragale + + + astragales + + + méritoine + + + méritoines + + + oeil de hibou + + + yeux de hibou + + + soie d'araignée + + + soies d'araignée + + + obbadion + + + obbadions + + + cheveux d'elfe + + + cheveux d'elfe + + + ortigal + + + ortigals + + + tubercule de respiplante + + + tubercules de respiplante + + + oreille de morille + + + oreilles de morille + + + hydropousse + + + hydropousses + + + ossiphage + + + ossiphages + + + fleur de souffre + + + fleurs de souffre + + + feuille de Tshaï + + + feuilles de Tshaï + + + bélidane + + + bélidanes + + + racine de mandragore + + + racines de mandragore + + + percepierre + + + percepierres + + + tanemiel + + + tanemiels + + + boralme + + + boralmes + + + ficoïde à cristaux + + + ficoïdes à cristaux + + + blémissure + + + blémissures + + + rose des neiges + + + roses des neiges + + + thé de sept lieues + + + thé de sept lieues + + + breuvage de Goliath + + + breuvage de Goliath + + + élixir de vie + + + élixir de vie + + + vin du travail acharné + + + vin du travail acharné + + + onguent de soin + + + onguents de soin + + + fiole d'essence vitale + + + fioles d'essence vitale + + + huile de cogitation + + + huile de cogitation + + + petit pain rance + + + petits pains rances + + + extrait de canicule + + + extraits de canicule + + + fourrage de l'étalon + + + fourrage de l'étalon + + + vin de folie + + + vin de folie + + + philtre d'amour + + + philtres d'amour + + + sirop de claivoyance + + + sirops de claivoyance + + + elixir d'endurance + + + elixir d'endurance + + + potion de survie + + + potions de survie + + + + + AGRESSIF + + + TOUT + + + NOMBRE + + + AURA + + + ARBRES + + + PAYSANS + + + SOUTIEN + + + GUARDE + + + CHATEAU + + + DEFENSIF + + + UNITE + + + ERESSEA + + + FUITE + + + ETRANGER + + + BATIMENT + + + OBJETS + + + DONNER + + + PITIE + + + AIDE + + + DERRIERE + + + APRES + + + CONTROLE + + + PLANTES + + + COMBAT + + + NON + + + SUIVANT + + + FACTION + + + CAMOUFLAGE + + + PAUSE + + + HOMMES + + + PRIVE + + + REGION + + + BATEAU + + + ECUS + + + ROUTES + + + NIVEAU + + + TEMPORAIRE + + + POTIONS + + + POUR + + + AVANT + + + DEVANT + + + SORTS + + + + + alchimie + + + armurier + + + arc + + + maçon + + + charron + + + catapulte + + + arbalète + + + divertissement + + + espionnage + + + bucheron + + + herboriste + + + magie + + + mêlée + + + mineur + + + observation + + + hast + + + perrayeur + + + équitation + + + cantonnier + + + navigation + + + charpentier + + + endurance + + + discrétion + + + tactique + + + percepteur + + + commerce + + + dresseur + + + mains-nues + + + fourbisseur + + + + + + // + + + TRAVAILLER + + + ATTAQUER + + + ANNONCE + + + VOLER + + + ASSIEGER + + + NOMMER + + + UTILISER + + + DECRIRE + + + PRIER + + + ENTRER + + + GUARDER + + + OFFRIR + + + MESSAGE + + + DEFAUT + + + EMAIL + + + FIN + + + CHEVAUCHER + + + SUIVRE + + + CHERCHER + + + GM + + + GROUPER + + + AIDER + + + JIHAD + + + PREPARER + + + ACHETER + + + CONTACTER + + + COMBATTRE + + + ENSEIGNER + + + APPRENDRE + + + FOURNIR + + + LOCAL + + + FAIRE + + + ALLER + + + RECOMMENCER + + + NOMBRE + + + SACRIFIER + + + OPTION + + + PASSWORD + + + PLANTER + + + PIRATERIE + + + PREFIXE + + + RECRUTER + + + RAPPORT + + + RESERVER + + + TRAJET + + + SABOTER + + + TRIER + + + ESPIONNER + + + ABANDONNER + + + SYNONYME + + + CACHER + + + TRANSPORTER + + + TAXER + + + DIVERTIR + + + ORIGINE + + + OUBLIER + + + VENDRE + + + SORTIR + + + INCANTER + + + MONTRER + + + DETRUIRE + + + ACCROITRE + + + METAMORPHOSE + + + + + sangsunicornes + + + sangsunicorne + + + cauchemars + + + cauchemar + + + ombreillards + + + ombreillard + + + draco tenebrae + + + draco tenebrae + + + nains + + + nain + + + elfes + + + elfe + + + orques + + + orque + + + snotlings + + + snotling + + + gobelins + + + gobelin + + + humains + + + humain + + + trolls + + + troll + + + démons + + + démons + + + insectes + + + insecte + + + hobbits + + + hobbit + + + chats + + + chat + + + atlantes + + + atlante + + + morts-vivants + + + mort-vivant + + + illusions + + + illusion + + + dragonnets + + + dragonnet + + + dragons + + + dragon + + + wyrms + + + wyrm + + + ents + + + ent + + + dragons-chats + + + dragon-chat + + + draconiens + + + draconien + + + spéciaux + + + spécial + + + enchantements + + + enchantement + + + golems de fer + + + golem de fer + + + golems de pierre + + + golem de pierre + + + ombres + + + ombre + + + lémures + + + lémure + + + yétis + + + yéti + + + quauquemaires + + + quauquemaire + + + crapauds + + + crapaud + + + céphalophages + + + céphalophage + + + paysans + + + paysan + + + wargs + + + warg + + + lynx + + + lynx + + + vers des profondeurs + + + ver des profondeurs + + + rats + + + rat + + + dragons chinois + + + dragon chinois + + + loups + + + loup + + + fantômes + + + fantôme + + + chats des rêves + + + chat des rêves + + + chats de l'Enfer + + + chat de l'Enfer + + + tigres + + + tigre + + + dauphins + + + dauphin + + + tortues géantes + + + tortue géante + + + krakens + + + kraken + + + serpents de mer + + + serpent de mer + + + guerriers illusoires + + + guerrier illusoire + + + diablotins + + + diablotin + + + nymphes + + + nymphe + + + licornes + + + licorne + + + hiboux + + + hibou + + + fées + + + fée + + + aigles + + + aigle + + + centaures + + + centaure + + + squelettes + + + squelette + + + liches + + + liche + + + zombies + + + zombie + + + zombies juju + + + zombie juju + + + goules + + + goule + + + spectres + + + spectre + + + fantômes du musée + + + fantôme du musée + + + gnomes + + + gnome + + + modèles + + + modèle + + + métamorphes + + + métamorphe + + + + + + Options + + + Niveau + + + Statut Politique + + + Plantes nécessaires + + + en construction + + + de dégâts + + + Votre faction a été éliminée. Nous espérons que vous vous êtes bien amusé malgré tout, et vous encourageons à vous réincrire pour une nouvelle partie. + + + + compétences + + + possessions + + + taille + + + sorts + + + sorts de combat + + + aucun + + + Adresses + + + anonyme + + + attaque + + + défense + + + armure + + + dégâts + + + + + baguette + + + baguettes + + + + + + côte nord-ouest + + + côte nord-est + + + côte est + + + côte sud-est + + + côte sud-ouest + + + côte ouest + + + + Aucun ordre reçu pour votre faction ! + + diff --git a/res/messages.xml b/res/messages.xml index 7e9822511..533ec1418 100644 --- a/res/messages.xml +++ b/res/messages.xml @@ -1,8518 +1,8518 @@ - - - - - - - Ein Alp starb in $region($region), ohne sein Ziel zu erreichen. - An alp died in $region($region) before reaching its target. - - - - - - "Einheiten können die folgenden Gegenstände beanspruchen: $resources($items)" - "Units can claim the following items: $resources($items)" - - - - - - - - "$if($isnull($region),"Es","In $region($region)") wurde$if($eq($number,1),"","n") $int($number) $race($race,$number) gesichtet." - "$if($isnull($region),"","In $region($region), ")$int($number) $race($race,$number) were discovered." - - - - - - - "$unit($mage) läßt einen Teil seiner selbst in die Erde fliessen. Die Bäume, die Transformation überlebt haben, erscheinen nun viel kräftiger." - "The power of $unit($mage) flows into the region and the trees which survived the spell appear stronger now." - "The power of $unit($mage) flows into the region and the trees which survived the spell appear stronger now." - - - - - - - "$unit($mage) beschwört einen Luftgeist, der die $ship($ship) in die Wolken hebt." - "$unit($mage) summons a wind spirit that lifts the $ship($ship) into the clouds." - - - - - - "$unit($mage) beschwört einen Schleier der Verwirrung." - "$unit($mage) summons a fog of confusion." - - - - - Eine Feuerwand blockiert die Ein- und Ausreise. ($int36($id)) - - - - - Der Magier besitzt die Gabe des Chaos. ($int36($id)) - The magician possesses the gift of Chaos. ($int36($id)) - - - - Dieser mächtige Bann scheint die Einheit ihres freien Willens zu berauben. Solange der Zauber wirkt, wird sie nur den Befehlen ihres neuen Herrn gehorchen. ($int36($id)) - - - - Dieser Beeinflussungszauber scheint die Einheit einem ganz bestimmten Volk wohlgesonnen zu machen. ($int36($id)) - - - - Dieser Zauber verursacht einen gigantischen magischen Strudel. Der Mahlstrom wird alle Schiffe, die in seinen Sog geraten, schwer beschädigen. ($int36($id)) - - - - Heilung ist in dieser Region magisch beeinflusst. ($int36($id)) - - - - Dieses Schiff hat sich verfahren. ($int36($id)) - - - - - - - - "$unit($unit) ist im Traum eine Fee erschienen. ($int36($id))" - "In a dream, a fairy appears to $unit($unit). ($int36($id))" - - - - - - - "$unit($unit) wird von bösen Alpträumen geplagt. ($int36($id))" - "$unit($unit) is haunted by terrbile nightmares. ($int36($id))" - - - - - - - "$unit($unit) wird von einem glitzernden Funkenregen umgeben. ($int36($id))" - "$unit($unit) is surrounded by a shower of glittering sparkles. ($int36($id))" - - - - - - - "Ein schimmernder Lichterkranz umgibt $unit($unit). ($int36($id))" - "A circle of shimmering lights surrounds $unit($unit). ($int36($id))" - - - - - - - "Eine Melodie erklingt, und $unit($unit) tanzt bis spät in die Nacht hinein. ($int36($id))" - "A haunting melody fills the air, and $unit($unit) dances until late into the night. ($int36($id))" - - - - - - - "$unit($unit) findet eine kleine Flöte, die eine wundersame Melodie spielt. ($int36($id))" - "$unit($unit) finds a small flute that plays a beautiful melody. ($int36($id))" - - - - - - - "Die Frauen des nahegelegenen Dorfes bewundern $unit($unit) verstohlen. ($int36($id))" - "The women of the nearby village cast furtive looks at $unit($unit). ($int36($id))" - - - - - - - "Eine Gruppe vorbeiziehender Bergarbeiter rufen $unit($unit) eindeutig Zweideutiges nach. ($int36($id))" - "A group of passing miners makes passes at $unit($unit). ($int36($id))" - - - - - - - "$unit($unit) bekommt von einer Schlange einen Apfel angeboten. ($int36($id))" - "A large green snake offers $unit($unit) a fine-looking apple. ($int36($id))" - - - - - - "A spell is deflecting magical energies and weakening all other spells cast in the region. ($int36($id))" - "Dieser Zauber scheint magische Energien irgendwie abzuleiten und so alle in der Region gezauberten Sprüche in ihrer Wirkung zu schwächen oder ganz zu verhindern. ($int36($id))" - - - - - - - "Ein Einhorn berührt $unit($unit) mit seinem Horn und verschwindet kurz darauf im Unterholz. ($int36($id))" - "A unicorn touches $unit($unit) with its horn and vanishes into the forest quickly after. ($int36($id))" - - - - - - - "Vogelzwitschern begleitet $unit($unit) auf all seinen Wegen. ($int36($id))" - "Bird songs follow $unit($unit) on all his travels. ($int36($id))" - - - - - - - "Leuchtende Blumen erblühen rund um das Lager von $unit($unit). ($int36($id))" - "Brightly coloured flowers pop up all around $unit($unit)'s camp. ($int36($id))" - - - - - - - "Über $unit($unit) zieht eine Gruppe Geier ihre Kreise. ($int36($id))" - "A group of vultures circles above $unit($unit). ($int36($id))" - - - - - - - "Der Kopf von $unit($unit) hat sich in einen grinsenden Totenschädel verwandelt. ($int36($id))" - "The head of $unit($unit) has turned into a madly grinning skull. ($int36($id))" - - - - - - - "Ratten folgen $unit($unit) auf Schritt und Tritt. ($int36($id))" - "Rats follow $unit($unit)'s every step. ($int36($id))" - - - - - - - "Pestbeulen befallen den Körper von $unit($unit). ($int36($id))" - "The body of $unit($unit) is disfigured by hideous boils. ($int36($id))" - - - - - - - "Eine dunkle Fee erscheint $unit($unit) im Schlaf. Sie ist von schauriger Schönheit. ($int36($id))" - "A dark and mysterious fairy appears before $unit($unit). She is of bewitching beauty. ($int36($id))" - - - - - - - "Fäulnisgeruch dringt $unit($unit) aus allen Körperöffnungen. ($int36($id))" - "The stench of decay is poring from all the orifices of $unit($unit). ($int36($id))" - - - - - - - - "$unit($unit) mag $faction($faction) zu mögen. ($int36($id))" - "$unit($unit) likes $faction($faction). ($int36($id))" - - - - - - - - "$unit($unit) scheint $race($race, 0) zu mögen. ($int36($id))" - "$unit($unit) seems to like $race($race, 0). ($int36($id))" - - - - - - - - "$unit($unit) ist ungewöhnlich ungeschickt in $skill($skill). ($int36($id))" - "$unit($unit) has some troubles with $skill($skill). ($int36($id))" - - - - - - - - "$unit($unit) ist ungewöhnlich geschickt in $skill($skill). ($int36($id))" - "$unit($unit) is incredibly skilled at $skill($skill). ($int36($id))" - - - - - - - - "$unit($unit) wird noch $int($duration) $if($eq($duration,1), "Woche", "Wochen") unter unserem Bann stehen. ($int36($id))" - "$unit($unit) will be under our influence for $int($duration) more $if($eq($duration,1), "week", "weeks"). ($int36($id))" - - - - - - - - - "$int($number) $if($eq($number,1), "Person", "Personen") von $unit($unit) $if($eq($number,1), "ist", "sind") noch $int($duration) $if($eq($duration,1), "Woche", "Wochen") beschleunigt. ($int36($id))" - "$int($number) $if($eq($number,1), "member", "members") of $unit($unit) $if($eq($number,1), "is", "are") accelerated for $int($duration) more $if($eq($duration,1), "week", "weeks"). ($int36($id))" - - - - - - - - "$int($number) $if($eq($number,1), "Person", "Personen") von $unit($unit) $if($eq($number,1), "fühlt", "fühlen") sich vor Kälte geschützt. ($int36($id))" - "$int($number) $if($eq($number,1), "member", "members") of $unit($unit) $if($eq($number,1), "is", "are") protected from the cold. ($int36($id))" - - - - - - "Ein unbekannter Zauber liegt auf dem Schiff. ($int36($id))" - "An unknown spell lies on this ship. ($int36($id))" - - - - - - "Ein unbekannter Zauber liegt auf der Einheit. ($int36($id))" - "An unknown spell lies on this unit. ($int36($id))" - - - - - - "Ein unbekannter Zauber liegt auf dem Gebäude. ($int36($id))" - "An unknown spell lies on this building. ($int36($id))" - - - - - - "Ein unbekannter Zauber liegt auf der Region. ($int36($id))" - "An unknown spell lies on this region. ($int36($id))" - - - - - - "Eine Wolke negativer Energie liegt über der Region. ($int36($id))" - "A fog of negative energy enshrouds the region. ($int36($id))" - "A fog of negative energy enshrouds the region. ($int36($id))" - - - - - - "Die Leute strotzen nur so vor Kraft. ($int36($id))" - "Testosterone levels are at an all-time high. ($int36($id))" - - - - - - - "$unit($unit) wird von einem Alp geritten. ($int36($id))" - "$unit($unit) is chased by a nightmare. ($int36($id))" - - - - - - - "$unit($unit) stürzt sich von einem amourösen Abenteuer ins nächste. ($int36($id))" - "$unit($unit) goes from one amourous adventure to another. ($int36($id))" - "$unit($unit) goes from one amourous adventure to another. ($int36($id))" - - - - - - - "$unit($unit) kann sich kaum konzentrieren. ($int36($id))" - "$unit($unit) can hardly focus on anything. ($int36($id))" - "$unit($unit) can hardly focus on anything. ($int36($id))" - - - - - - - "Die Ausrüstung von $unit($unit) scheint unsichtbar. ($int36($id))" - "$unit($unit)'s equipment is invisible. ($int36($id))" - "$unit($unit)'s equipment is invisible. ($int36($id))" - - - - - - "Die natürliche Widerstandskraft gegen Verzauberung ist gestärkt. ($int36($id))" - "($int36($id))" - "The magical resistance has been strengthened. ($int36($id))" - - - - - - "Die natürliche Widerstandskraft gegen Verzauberung bestimmter Einheiten in dieser Region wurde gestärkt. ($int36($id))" - "($int36($id))" - "The magical resistance of some units in this region was boosted. ($int36($id))" - - - - - - "Die natürliche Widerstandskraft gegen Verzauberung bestimmter Einheiten in dieser Region wurde geschwächt. ($int36($id))" - "The magical resistance of some units in this region was weakened. ($int36($id))" - "($int36($id))" - - - - - - "Diese Mauern wirken, als wären sie direkt aus der Erde gewachsen und nicht erbaut. ($int36($id))" - "These walls appear to have grown straight out of the earth. ($int36($id))" - "($int36($id))" - - - - - - "Ein magischer Schimmer liegt auf diesen Mauern. ($int36($id))" - "A magical shimmer lies on these walls. ($int36($id))" - "($int36($id))" - - - - - - "Die Straßen sind erstaunlich trocken und gut begehbar, doch an manchen Stellen bilden sich wieder die erste Schlammlöcher. ($int36($id))" - "The roads are extremely dry and well-kept, but some areas show the first signs of potholes reappearing. ($int36($id))" - "($int36($id))" - - - - - - "Die Straßen sind erstaunlich trocken und gut begehbar. ($int36($id))" - "The roads are extremely dry and well-kept. ($int36($id))" - "($int36($id))" - - - - - - "Albträume plagen die Leute. ($int36($id))" - "Nightmares plague the population. ($int36($id))" - "($int36($id))" - - - - - - "Die Leute haben schöne Träume. ($int36($id))" - "($int36($id))" - "The people in this region have sweet dreams. ($int36($id))" - - - - - - "Diese Region wurde von den Göttern verflucht. Das Meer ist eine ekelige Brühe, braunschwarze, stinkende Gase steigen aus den unergründlichen Tiefen hervor, und untote Seeungeheuer, Schiffe zerfressend und giftige grüne Galle geifernd, sind der Schrecken aller Seeleute, die diese Gewässer durchqueren. Niemand kann hier lange überleben. ($int36($id))" - "($int36($id))" - "This region was cursed by the gods. The sea is a foul cesspool, noxious gases rise from the deep, undead seamonsters attack all ships. Noone can live here for long. ($int36($id))" - - - - - - "Diese Region wurde von den Göttern verflucht. Stinkende Nebel ziehen über die tote Erde und furchtbare Kreaturen ziehen über das Land. Die Brunnen sind vergiftet, und die wenigen essbaren Früchte sind von einem rosa Pilz überzogen. Niemand kann hier lange überleben. ($int36($id))" - "($int36($id))" - "This region was cursed by the gods. Noone can live here for long. ($int36($id))" - - - - - - "Ein Schleier der Verwirrung liegt über der Region. ($int36($id))" - "($int36($id))" - "A veil of confusion lies over the region. ($int36($id))" - - - - - - "In der Region treibt ein Giftelementar sein Unwesen. ($int36($id))" - "A poison elemental is spreading pestilence and death. ($int36($id))" - - - - - - "Die ganze Region ist von einer friedlichen Stimmung erfasst. ($int36($id))" - "($int36($id))" - "Everyone in this region seems to be in a peacful mood. ($int36($id))" - - - - - - "Es herrscht eine fröhliche und ausgelassene Stimmung. ($int36($id))" - "($int36($id))" - "Everyone in this region seems to be having a very good time. ($int36($id))" - - - - - - "Die Bauern sind unzufrieden. ($int36($id))" - "($int36($id))" - "The peasants are upset. ($int36($id))" - - - - - - "Alle Leute in der Region haben Schlafstörungen. ($int36($id))" - "($int36($id))" - "People in this region suffer from insomnia. ($int36($id))" - - - - - - "In dieser Gegend herrscht eine Dürre. ($int36($id))" - "($int36($id))" - "This region was hit by a drought. ($int36($id))" - - - - - - "In dieser Gegend steht das Korn besonders gut im Feld. ($int36($id))" - "($int36($id))" - "The grain in this region is especially healthy. ($int36($id))" - - - - - - "Die Winde scheinen dieses Schiff besonders zu beguenstigen. ($int36($id))" - "($int36($id))" - "The winds seem to favor this ship. ($int36($id))" - - - - - - "Untote schrecken vor dieser Region zurück. ($int36($id))" - "($int36($id))" - "The undead turn away from this region. ($int36($id))" - - - - - - "Der Zahn der Zeit kann diesen Mauern nichts anhaben. ($int36($id))" - "($int36($id))" - "Time cannot touch these walls. ($int36($id))" - - - - - - "Dichte Nebel bedecken diese Woche die Region. Keine Einheit schafft es, diese Nebel zu durchdringen und die Region zu verlassen. ($int36($id))" - "heavy fog makes it impossible to leave the region. ($int36($id))" - "heavy fog makes it impossible to leave the region. ($int36($id))" - - - - - - - "$unit($unit) setzt ein Sonnensegel. Die Geschwindigkeit des Schiffes erhöht um $int($speed)." - "$unit($unit) sets a solar sail. The ship's speed is increased by $int($speed)." - "$unit($unit) sets a solar sail. The ship's speed is increased by $int($speed)." - - - - - - "Interner Fehler: Meldung '$name' nicht definiert." - "Internal Error: Message '$name' is undefined." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Interner Fehler: Meldung '$name' nicht definiert." - "$unit($unit) in $region($region): '$order($command)' - Internal Error: Message '$name' is undefined." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier ist kein passendes Schloss." - "$unit($unit) in $region($region): '$order($command)' - No fitting lock can be found here." - "$unit($unit) in $region($region): '$order($command)' - No fitting lock can be found here." - - - - - - - - "$unit($unit) öffnet eines der Schlösser in $region($region) mit $if($eq($key,1),"dem Achatenen Schlüssel","dem Saphirnen Schlüssel")." - "$unit($unit) unlocks one of the locks in $region($region) with $if($eq($key,1),"the Agate Key","the Sapphire Key")." - "$unit($unit) unlocks one of the locks in $region($region) with $if($eq($key,1),"the Agate Key","the Sapphire Key")." - - - - - - - - "$unit($unit) verschließt eines der Schlösser in $region($region) mit $if($eq($key,1),"dem Achatenen Schlüssel","dem Saphirnen Schlüssel")." - "$unit($unit) locks one of the locks in $region($region) with $if($eq($key,1),"the Agate Key","the Sapphire Key")." - "$unit($unit) locks one of the locks in $region($region) with $if($eq($key,1),"the Agate Key","the Sapphire Key")." - - - - - - - "$unit($unit) in $region($region) verwandelt sich in ein Werwesen." - "$unit($unit) in $region($region) becomes a lycantrope." - "$unit($unit) in $region($region) becomes a lycantrope." - - - - - - - "SIEG! $if($eq($n,1), "Die Partei $winners hat", "Die Parteien $winners haben") die Siegbedingung für die erforderliche Zeit erfüllt. Das Spiel ist damit beendet." - "VICTORY! $if($eq($n,1), "The faction $winners has", "The factions $winners have") fulfilled the victory condition for the necessary time. The game is over." - "VICTORY! $if($eq($n,1), "The faction $winners has", "The factions $winners have") fulfilled the victory condition for the necessary time. The game is over." - - - - - - "Achtung: $faction($faction) hat die Siegbedingungen erfüllt und wird in $if($eq($remain,1),"einer Woche","$int($remain) Wochen") zum Sieger erklärt werden." - "Attention: $faction($faction) has fulfilled the victory condition and will be declared winner in $if($eq($remain,1),"one week","$int($remain) weeks")." - "Attention: $faction($faction) has fulfilled the victory condition and will be declared winner in $if($eq($remain,1),"one week","$int($remain) weeks")." - - - - - - - - "$unit($unit) wurde in $region($region) von einem GM gelöscht: \"$string\"." - "$unit($unit) in $region($region) was removed by a GM: \"$string\"." - "$unit($unit) in $region($region) was removed by a GM: \"$string\"." - - - - - - - - "$resource($item,1) (Gewicht: $weight($weight)): $description" - "$resource($item,1) (weight: $weight($weight)): $description" - - - - - "Ein Hauch des Lebens liegt über der Welt und alle Wesen fühlen sich frisch und erholt." - "Life itself touches the world and all beings are healed." - "Life itself touches the world and all beings are healed." - - - - - - - - "$unit($unit) hat Glück und findet einen Hort von $int($amount) $resource($item,$amount)." - "$unit($unit) luckily finds a cache of $int($amount) $resource($item,$amount)." - "$unit($unit) luckily finds a cache of $int($amount) $resource($item,$amount)." - - - - - - "$unit($unit) brennt ein großes Feuerwerk ab und Kaskaden bunter Sterne, leuchtende Wasserfälle aus Licht und strahlende Feuerdrachen erhellen den Himmel." - "A large firework is visible all over the sky." - "A large firework is visible all over the sky." - - - - - - - "In $region($region) wird ein großes Feuerwerk abgebrannt, welches noch hier zu bewundern ist. Kaskaden bunter Sterne, leuchtende Wasserfälle aus Licht und strahlende Feuerdrachen erhellen den Himmel." - "A large firework, visible all over the sky, has been started in $region($region)." - "A large firework, visible all over the sky, has been started in $region($region)." - - - - - - - "Zur Feier des Geburtstags von ${name} brennt $unit($unit) ein großes Feuerwerk ab. Kaskaden bunter Sterne, leuchtende Wasserfälle aus Licht und strahlende Feuerdrachen erhellen den Himmel." - "A large firework in honor of ${name} is visible all over the sky." - "A large firework in honor of ${name} is visible all over the sky." - - - - - - - - "Zur Feier des Geburtstags von ${name} wird in $region($region) ein großes Feuerwerk abgebrannt, welches noch hier zu bewundern ist. Kaskaden bunter Sterne, leuchtende Wasserfälle aus Licht und strahlende Feuerdrachen erhellen den Himmel." - "A large firework in honor of ${name}, visible all over the sky, has been started in $region($region)." - "A large firework in honor of ${name}, visible all over the sky, has been started in $region($region)." - - - - - - - "$int36($unit.id($unit))/$int($index) erzielt einen kritischen Treffer." - "$int36($unit.id($unit))/$int($index) does critical damage." - "$int36($unit.id($unit))/$int($index) does critical damage." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) muß mindestens 2 Stufen besser sein als $unit($student)." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) needs to be at least 2 levels better than $unit($student)." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) needs to be at least 2 levels better than $unit($student)." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($student) lernt nicht." - "$unit($unit) in $region($region): '$order($command)' - $unit($student) is not learning." - "$unit($unit) in $region($region): '$order($command)' - $unit($student) is not learning." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dafür braucht die Einheit $resources($required)." - "$unit($unit) in $region($region): '$order($command)' - for this, the unit needs $resources($required)." - "$unit($unit) in $region($region): '$order($command)' - for this, the unit needs $resources($required)." - - - - - - $trailto($region) - $trailto($region) - - - - - - - "Deine Partei hat $int($units) Migranten und kann maximal $int($maxunits) Migranten aufnehmen." - "Your faction has $int($units) migrants out of a possible total of $int($maxunits)." - - - - - - - - - "Seit $int($age) Wochen Mitglied der Allianz '$name ($int36($id))', angeführt von $faction($leader)." - "Member of '$name ($int36($id))' for $int($age) weeks, led by $faction($leader)." - - - - - - - "Deine Partei hat $int($units) Helden und kann maximal $int($maxunits) Helden ernennen." - "Your faction has promoted $int($units) heroes out of a possible total of $int($maxunits)." - - - - - - - "Deine Partei hat $int($population) Personen in $int($units) Einheiten." - "Your faction has $int($population) people in $int($units) units." - - - - - - "Statistik für $region($region):" - "Statistics for $region($region):" - - - - - - "Unterhaltung: max. $int($max) Silber" - "Entertainment: max. $int($max) silver" - - - - - - "Moral der Bauern: $int($morale)" - "Peasant morale: $int($morale)" - - - - - - "Luxusgüter zum angegebenen Preis: $int($max)" - "Luxury goods at this price: $int($max)" - - - - - - "Lohn für Arbeit: $int($max) Silber" - "Worker salary: $int($max) silver" - - - - - - "Bauerneinnahmen: $int($max) Silber" - "Peasant wages: $int($max) silver" - - - - - - "Personen: $int($max)" - "People: $int($max)" - "People: $int($max)" - - - - - - "Rekruten: max. $int($max) Bauern" - "Recruits: $int($max) peasants" - "Recruits: $int($max) peasants" - - - - - - - "Deine Partei hat $int($score) Punkte. Der Durchschnitt für Parteien ähnlichen Alters ist $int($average) Punkte." - "Your faction has a score of $int($score). The average score for similar factions is $int($average)." - "Your faction has a score of $int($score). The average score for similar factions is $int($average)." - - - - - - - "Report für $game, $date" - "Report for $game, $date" - "Report for $game, $date" - - - - - - - "Im $direction($dir) der Region liegt $trailto($region)" - "To the $direction($dir) lies $trailto($region)" - - - - - - - "$resource($product,0) $int($price) Silber" - "$resource($product,0) for $int($price) silver" - "$resource($product,0) for $int($price) silver" - - - - - - - "Auf dem Markt wird für $resource($product,0) $int($price) Silber verlangt." - "Le marché local offre la $resource($product,0) au prix de $int($price) écus." - "The local market offers $resource($product,0) at a price of $int($price) silver." - - - - - - - "Auf dem Markt werden $resource($p1,0) und $resource($p2,0) feilgeboten." - "The local market offers $resource($p1,0) and $resource($p2,0)." - - - - - - "Auf dem Markt wird $resource($p1,0) feilgeboten." - "The local market offers $resource($p1,0)." - - - - - - "Dein Passwort lautet ${password}." - "Your password is ${password}." - "Your password is ${password}." - - - - - - "Die Mannschaft krank vom vergifteten Wasser, Planken, Ruder und Segel zerfressen von den Wassern des verfluchten Meeres, ergibt sich die $ship($ship) in ihr Schicksal und sinkt." - "Her sailors sick from the poisened ocean, planks, rudder und sails corroded by the waters of the cursed ocean, the $ship($ship) finally succumbs to her destiny and sinks." - - - - - - "$unit($unit) benutzt einen Talenttrunk und fühlt, wie sein Wissen zunimmt." - "$unit($unit) uses a potion of skills and feels his knowledge grow." - "$unit($unit) uses a potion of skills and feels his knowledge grow." - - - - - - - "$unit($unit) benutzt einen Astralkristall und gewinnt $int($aura) Aura hinzu." - "$unit($unit) uses an astralcrystal and gains $int($aura) aura." - "$unit($unit) uses an astralcrystal and gains $int($aura) aura." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieses Luxusgut wird hier nicht verkauft." - "$unit($unit) in $region($region): '$order($command)' - These goods are not on sale here." - "$unit($unit) in $region($region): '$order($command)' - These goods are not on sale here." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dazu benötigt man $resource($missing,0)." - "$unit($unit) in $region($region): '$order($command)' - This requires $resource($missing,0)." - "$unit($unit) in $region($region): '$order($command)' - This requires $resource($missing,0)." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) nehmen nichts an." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) will not accept anything." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) will not accept anything." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können nicht neu gruppiert werden." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot be regrouped." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot be regrouped." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können nichts stehelen." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot steal anything." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot steal anything." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) geben nichts weg." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) do not give things away." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) do not give things away." - - - - - - - - "Eine Botschaft von $unit.dative($sender) aus $region($region): '$string'" - "A message by $unit($sender) from $region($region): '$string'" - - - - - - - - - "In $region($region) erhielt $unit($unit) eine Botschaft von $unit.dative($sender): '$string'" - "In $region($region), $unit($unit) received a message by $unit($sender): '$string'" - - - - - - - - - "In $region($region) erhielt $unit($unit) von $unit.dative($sender) $resources($items)" - "In $region($region), $unit($unit) received $resources($items) from $unit($sender)" - - - - - - "$building($building) hat diese Woche nicht funktioniert, da zu Beginn der Woche der Unterhalt nicht gezahlt werden konnte." - "$building($building) was nonfunctional because upkeep could not be paid at the beginning of the week." - - - - - - "Plötzlich löst sich $building($building) in kleine Traumwolken auf." - "$building($building) suddenly dissolves into small pink clouds." - - - - - - "Für das Gebäude $building($building) konnte die ganze Woche kein Unterhalt bezahlt werden." - "Upkeep for $building($building) could not be paid all week." - - - - - - - - - "In $region($region) stürzte $building($building) ein.$if($road," Beim Einsturz wurde die halbe Straße vernichtet.","")$if($opfer," $int($opfer) Opfer $if($eq($opfer,1),"ist","sind") zu beklagen.","")" - "$building($building) in $region($region) collapses.$if($opfer," There are $int($opfer) caualties.","")" - "$building($building) in $region($region) collapses.$if($opfer," There are $int($opfer) caualties.","")" - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - In der Ebene der Herausforderung kann niemand rekrutiert werden." - "$unit($unit) in $region($region): '$order($command)' - You cannot recruit in this plane." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die einheit kann sich nicht so gut tarnen." - "$unit($unit) in $region($region): '$order($command)' -The unit cannot hide that well." - - - - - - - - "$ship($ship) was destroyed by $unit($unit)." - "$ship($ship) wurde von $unit($unit) zerstört." - - - - - - - - "$unit($unit) could not destroy $ship($ship)." - "$unit($unit) konnte $ship($ship) nicht zerstören." - - - - - - - - "$unit($unit) was detected while trying to destroy $ship($ship)." - "$unit($unit) wurde beim Versuch $ship($ship) zu zerstören entdeckt." - - - - - - - "Somebody attempted to destroy $ship($ship)." - "Es wurde versucht, $ship($ship) zu zerstören." - - - - - - - "$ship($ship) was destroyed." - "$ship($ship) wurde zerstört." - - - - - - - - - "$int($amount) Personen von $unit($unit) ertrinken.$if($isnull($region),""," Die Einheit rettet sich nach $region($region).")" - - - - - - - - "$unit($unit) ueberlebt unbeschadet und rettet sich nach $region($region)." - - - - - - - - "$ship($ship) versinkt in den Fluten von $region($region)." - - - - - - - - "$unit($unit) wurde beim versenken von $ship($ship) entdeckt." - - - - - - - - - "$unit($unit) entdeckte $unit($saboteur) beim versenken von $ship($ship)." - - - - - - - - "$unit($unit) ertrinkt in $region($region)." - "$unit($unit) drowns in in $region($region)." - - - - - - - - - "$int($amount) Personen in $unit($unit) in $region($region) ertrinken." - "$int($amount) people in $unit($unit) in $region($region) drown." - "$int($amount) people in $unit($unit) in $region($region) drown." - - - - - - - "$unit($unit) nimmt Schaden auf dem Wasser in $region($region)." - "$unit($unit) is taking damage on the water." - "$unit($unit) is taking damage on the water." - - - - - - "$unit($unit) schwenkt sein Szepter und sorgt für Verwirrung und Chaos in der Region." - - - - - - - - - "$unit($unit) stolpert bei der Erforschung der Region über $localize($location). Nähere Durchsuchung fördert ein zerfleddertes altes Buch mit dem Titel '$localize($book)' zu Tage. Der Wissensschub ist enorm." - - - - "Ein Alp hat sein Opfer gefunden und springt auf den Rücken von $unit($target)!" - - - - - - - - "$unit($unit) fühlt sich von starken magischen Energien durchströmt. ($int36($id))" - "Powerful magical energies are pulsing through $unit($unit). ($int36($id))" - - - - - - - - "$unit($unit) hat Schwierigkeiten seine magischen Energien zu sammeln. ($int36($id))" - - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($amount) Krieger sind für einen Moment benommen." - "$unit($mage) casts $spell($spell): $int($amount) fighters were momentarily stunned." - - - - - - - - "$unit($mage) besänftigt den Bauernaufstand in $region($region)." - "$unit($mage) quells the uprising in $region($region)." - - - - - - - - "$unit($mage) rief in $region($region) einen Riss in dem Gefüge der Magie hervor, der alle magische Kraft aus der Region riss." - - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden in Schlaf versetzt." - "$unit($mage) casts $spell($spell): $int($amount) fighters have fallen asleep." - - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($amount) Kriegern wurde ihre Lebenskraft entzogen." - "$unit($mage) casts $spell($spell): $int($amount) fighters had their life energy drained." - - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($amount) Kriegern wurden versteinert." - "$unit($mage) casts $spell($spell): $int($amount) fighters were petrified." - - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden in einen Blutrausch versetzt." - "$unit($mage) casts $spell($spell): $int($amount) fighters went into a mindless rage." - - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden eingeschüchtert." - "$unit($mage) casts $spell($spell): $int($amount) fighters were intimidated." - - - - - - - - "$unit($mage) zaubert $spell($spell), aber es gab niemanden, der beeinflusst werden konnte." - "$unit($mage) casts $spell($spell), but nobody is impressed." - - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden von Furcht gepackt." - "$unit($mage) casts $spell($spell): $int($amount) fighters were consumed by fear." - - - - - - - - "$unit($mage) zaubert $spell($spell): Das Kampfgetümmel erstirbt und er kann unbehelligt seines Weges ziehen." - "$unit($mage) casts $spell($spell): The noise of the battle dies down and he is able to slip away unharmed." - - - - - - - - "$unit($mage) zaubert $spell($spell): Ein Sturm kommt auf und die Schützen können kaum noch zielen." - "$unit($mage) casts $spell($spell): Strong stormwinds are blowing and the archers are having a hard time aiming." - - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($amount) Krieger schleppten sich müde in den Kampf." - "$unit($mage) casts $spell($spell): $int($amount) fighters had trouble staying awake." - - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden moralisch gestärkt." - "$unit($mage) casts $spell($spell): $int($amount) fighters had their moral boosted." - - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden magisch beschleunigt." - "$unit($mage) casts $spell($spell): $int($amount) fighters were magically accelerated." - - - - - - - "$unit($mage) ruft ein fürchterliches Unwetter über seine Feinde, doch es gab niemanden mehr, den dies treffen konnte." - - - - - - - "$unit($mage) ruft ein fürchterliches Unwetter über seine Feinde, doch der magische Regen zeigt keinen Effekt." - - - - - - - "$unit($mage) ruft ein fürchterliches Unwetter über seine Feinde. Der magischen Regen lässt alles Eisen rosten." - - - - - - - - - "$unit($mage) beschwört den Alp $unit($alp) für $unit($target)." - "$unit($mage) summons the alp $unit($alp) for $unit($target)." - - - - - - - - "$unit($mage) kümmert sich um die Verletzten und heilt $int($amount) Verwundete." - "$unit($mage) sees after the wounded and heals $int($amount)." - - - - - - - - - "$unit($mage) kümmert sich um die Verletzten und benutzt ein $resource($item,1), um den Zauber zu verstärken. $int($amount) Verwundete werden geheilt." - "$unit($mage) sees after the wounded and heals $int($amount). A $resource($item,1) improves the spell." - - - - - - - - - "Mit einem Ritual bindet $unit($mage) die magischen Kräfte der Erde von $region($region) in die Mauern von $building($building)." - "$unit($mage) performs a ritual that binds the magical forces of $region($region) into the walls of $building($building)." - - - - - - - - - "$unit($mage) opfert $unit($target) $int($amount) Aura." - "$unit($mage) sacrifices $int($amount) aura for $unit($target)." - - - - - - - - "$unit($mage) beginnt ein Ritual der Wiederbelebung. $int($amount) Krieger stehen von den Toten auf." - "$unit($mage) begins a ritual of resurrection. $int($amount) warriors rise from the dead." - - - - - - - - - "$unit($mage) beginnt ein Ritual der Wiederbelebung und benutzt ein $resource($item,1), um den Zauber zu verstärken. $int($amount) Krieger stehen von den Toten auf." - "$unit($mage) begins a ritual of resurrection using a $resource($item,1). $int($amount) warriors rise from the dead." - - - - - - - "$unit($mage) öffnet ein Chaostor." - "$unit($mage) opens a chaos gate." - - - - "Ein Wirbel aus blendendem Licht erscheint." - "A vortex of blinding light appears." - - - - - - - - "$unit($mage) kann in $region($region) keine Untoten rufen." - "$unit($mage) cannot summon any undead in $region($region)." - - - - - - - - - "$unit($mage) erweckt in $region($region) $int($amount) Untote aus ihren Gräbern." - "$unit($mage) calls $int($amount) undead from their graves in $region($region)." - - - - - - - - "$unit($mage) stört in $region($region) die Ruhe der Toten." - "$unit($mage) communicates with the dead in $region($region)." - - - - - - - "$unit($unit) gelingt es, durch die Nebel auf die Realität zu blicken." - "$unit($unit) manages to catch a glimpse of reality through the fog." - - - - - - - - "$unit($mage) konnte $int($amount) $if($eq($amount,1),"Bauer","Bauern") anwerben." - "$unit($mage) managed to recruit $int($amount) $if($eq($amount,1),"peasant","peasants")." - - - - - - "Ein bohrender Schmerz durchzuckt $unit($unit), Verwirrung macht sich breit." - "Pain pulses through $unit($unit), confusion spreads." - - - - - - ""AAAAAAAGHHHHHH!" - Ein Schrei durchzieht die Region, $unit($unit) windet sich vor Schmerz." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Eine höhere Macht hindert $unit($unit) daran, das Objekt zu übergeben. 'ES IST DEINS, MEIN KIND. DEINS GANZ ALLEIN'." - - - - - - - "$unit($unit) sendet ein Stoßgebet an den Herrn der Schreie." - - - - - - - "Der Eisberg $region($region) schmilzt." - "The iceberg $region($region) melts." - "The iceberg $region($region) melts." - - - - - - "Der Gletscher von $region($region) bricht und treibt davon." - "The glacier in $region($region) breaks up and drifts away." - "The glacier in $region($region) breaks up and drifts away." - - - - - - "Der Eisberg $region($region) treibt an eine Küste." - "The iceberg $region($region) drifts onto a coast." - "The iceberg $region($region) drifts onto a coast." - - - - - - "Die $ship($ship) wird bei einer Kollision mit einem Eisberg zerstört." - "The $ship($ship) has been destroyed by a collision with an iceberg." - "The $ship($ship) has been destroyed by a collision with an iceberg." - - - - - - "Die $ship($ship) wird bei einer Kollision mit einem Eisberg beschädigt." - "The $ship($ship) has been damaged by a collision with an iceberg." - "The $ship($ship) has been damaged by a collision with an iceberg." - - - - - - - "Die $ship($ship) treibt nach $direction($dir)." - "The ship $ship($ship) drifts to the $direction($dir)." - "The ship $ship($ship) drifts to the $direction($dir)." - - - - - - - "Der Eisberg $region($region) treibt nach $direction($dir)." - "The iceberg $region($region) drifts $direction($dir)." - "The iceberg $region($region) drifts $direction($dir)." - - - - - - "Wir erklären allen $race($race,2) den heiligen Krieg." - "We declare jihad on all $race($race,2)." - - - - - - "Die Götter erhören $unit($unit)." - "The Gods have listened to $unit($unit)." - "The Gods have listened to $unit($unit)." - - - - - - - "Die Götter gewähren uns die Kraft eines $special($int($level))." - "The Gods grant us the powers of $special ($int($level))." - "The Gods grant us the powers of $special ($int($level))." - - - - - - "Die Götter gewähren uns die Kraft eines ${special}." - "The Gods grant us the powers of ${special}." - "The Gods grant us the powers of ${special}." - - - - - - - - - - "$unit($unit) verlor $int($fallen) Personen$if($alive,", $int($alive) überlebten","")$if($run," und $int($run) flohen$if($isnull($runto),""," nach $region($runto)")","")." - "$unit($unit) lost $int($fallen) people$if($alive,", $int($alive) survived","")$if($run," and $int($run) fled$if($isnull($runto),""," to $region($runto)")","")." - - - - - - - - "$unit($unit) erzielte $int($hits) Treffer und tötete $int($kills) Gegner." - "$unit($unit) hit $int($hits) times and killed $int($kills) enemies." - "$unit($unit) hit $int($hits) times and killed $int($kills) enemies." - - - - - - "$string" - "$string" - - - - - - - "Heer $int($index): $name" - "Army $int($index): $name" - - - - - - - "Verwundert blicken die Bauern von $region($region) auf ein neues Gebäude." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) gewinnt durch das Ritual $int($amount) Aura." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) receives $int($amount) aura." - - - - - - - - "$unit($mage) beschwört Naturgeister in den Boden von $region($region)." - "$unit($mage) summons natural spirits into the ground of $region($region)." - - - - - - - - - "$unit($mage) verwandelt $int($amount) aus $unit($target) in $race($race,0)." - "$unit($mage) transforms $int($amount) from $unit($target) into $race($race,0)." - - - - - - - - "$unit($mage) verwandelt $unit($target) in $race($race,0)." - "$unit($mage) tranforms $unit($target) to $race($race,0)." - - - - - - "$unit($mage) erlöst die gequälten Seelen der Toten." - "$unit($mage) redeems the tormented souls of the dead." - - - - - - "$unit($mage) verwandelt sich in einen Wyrm." - "$unit($mage) turns into a wyrm." - - - - - - - "$unit($mage) ruft Irrlichter in $region($region)." - "$unit($mage) summons wisps in $region($region)." - "$unit($mage) summons wisps in $region($region)." - - - - - - - "$unit($mage) erschafft in $region($region) eine Wand aus Feuer." - "$unit($mage) creates a wall of fire in $region($region)." - "$unit($mage) creates a wall of fire in $region($region)." - - - - - - - "$unit($mage) wiegelt in $region($region) die Bauern zum Aufstand auf." - "$unit($mage) incites a revolt among the peasants of $region($region)." - - - - - - - - - "$unit($mage) wiegelt in $region($region) $int($amount) Bauern zum Aufstand auf." - "$unit($mage) incites a revolt among $int($amount) peasants of $region($region)." - - - - - - - - "$unit($mage) sorgt in $region($region) für Trübsal unter den Bauern." - "$unit($mage) causes great sadness among the peasants of $region($region)." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier erschafft ein Traumgebäude." - "$unit($unit) in $region($region): '$order($command)' - The magician creates an illusionary building." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) kann keine $race($race,1)-Gestalt annehmen." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Elementar ist zu klein, um das Gebäude zu tragen." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Elementar weigert sich, nach $direction($direction) zu gehen." - "$unit($unit) in $region($region): '$order($command)' - The elemental refuses to go $direction($direction)." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) ist von unserer Art, das Ritual wäre verschwendete Aura." - "$unit($unit) in $region($region): '$order($command)' - $unit($target) is one of our kind, we should not waste aura on this." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) wird von uns aufgenommen." - "$unit($unit) in $region($region): '$order($command)' - $unit($target) has become one of our kind." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) ruft Drachen nach $region($target)." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) calls dragons to $region($target)." - - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) erschafft $int($amount) ${object}." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) creates $int($amount) ${object}." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) creates $int($amount) ${object}." - - - - - - - - "Ein Beben erschüttert $building($building). Viele kleine Pseudopodien erheben das Gebäude und tragen es in Richtung $direction($direction)." - - - - - - - - "$unit($unit) benutzt in $region($region) ein Traumauge." - "$unit($unit) uses a dreameye in $region($region)." - - - - - - - "$unit($unit) benutzt in $region($region) einen Antimagiekristall." - "$unit($unit) uses an antimagic crystal in $region($region)." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Sphären des Chaos geben dem Magier einen Teil ihrer Kraft." - "$unit($unit) in $region($region): '$order($command)' - The sphere of chaos returns a part of his power to the magician." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier konnte keinen Fluch zerstören." - "$unit($unit) in $region($region): '$order($command)' - The magician could not destroy any magic." - - - - - - - - "In $region($region) dehnt $unit($unit) die Zeit für $int($amount) Personen." - "In $region($region), $unit($unit) bends time for $int($amount) men." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier zerstört $int($succ) Flüche auf ${target}." - "$unit($unit) in $region($region): '$order($command)' - The magician destroys $int($succ) spells on ${target}." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier zerstört den Fluch($id) auf ${target}." - "$unit($unit) in $region($region): '$order($command)' - The magician destroys the spell on ${target}." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Zauber ist nicht stark genug, um den Fluch auf ${target} zu zerstören." - "$unit($unit) in $region($region): '$order($command)' - The spell is not strong enough to destroy the curse on ${target}." - - - - - - - "$unit($mage) beschwört einen Giftelementar in $region($region)." - "$unit($mage) summons a poison elemental in $region($region)." - - - - - - - - "$unit($unit) in $region($region) wird von einem Unbekannten verflucht." - "$unit($unit) in $region($region) was cursed by an unknown magician." - - - - - - - - "$unit($mage) belegt $unit($target) mit einem Zauber." - "$unit($mage) puts a spell on $unit($target)." - - - - - - - "$unit($mage) belegt $unit($target) mit einem Kälteschutz." - "$unit($mage) puts protection from cold on $unit($target)." - - - - - - - "$unit($mage) legt einen Rosthauch auf $unit($target), doch der Rosthauch fand keine Nahrung." - "$unit($mage) puts a spell of rust on $unit($target), but it shows no effect." - - - - - - - - "$unit($mage) legt einen Rosthauch auf $unit($target). $int($amount) Waffen wurden vom Rost zerfressen." - "$unit($mage) puts a spell of rust on $unit($target). $int($amount) weapons are eaten by rust." - - - - - - - $if($isnull($mage),"Ein unentdeckter Magier",$unit($mage)) erschuf einen heiligen Hain von $int($amount) Schößlingen. - $if($isnull($mage),"An unknown magician ",$unit($mage)) created a holy forest of $int($amount) young trees. - - - - - - "$if($isnull($mage),"Ein unentdeckter Magier",$unit($mage)) segnet in einem kurzen Ritual die Felder." - "$if($isnull($mage),"an unseen magician",$unit($mage)) blesses the fields in a short ritual." - - - - - - "$unit($mage) beschwört die Mächte des Wassers und ein gigantischer Strudel bildet sich." - "$unit($mage) summons the power of the seas and a giant maelstrom forms." - - - - - - - "$unit($mage) belebt $int($amount) Bäume." - "$unit($mage) revives $int($amount) trees." - - - - - - - "$unit($mage) sorgt für trockene Straßen in $region($region)." - "$unit($mage) creates dry and well-repaired roads in $region($region)." - - - - - - - "$unit($mage) erfleht den Segen der Götter des Windes und des Wassers für $ship($ship)." - "$unit($mage) asks the gods of wind and water on behalf of the $ship($ship)." - - - - - - - - "$unit($unit) transferiert $int($aura) Aura auf $unit($target)." - "$unit($unit) transfers $int($aura) Aura to $unit($target)." - "$unit($unit) transfers $int($aura) Aura to $unit($target)." - - - - - - - - "$unit($mage) entzieht $unit($target) $int($aura) Aura." - "$unit($mage) draws $int($aura) aura from $unit($target)." - - - - - - - "$unit($unit) fühlt seine magischen Kräfte schwinden und verliert $int($aura) Aura." - "$unit($unit) feels the powers of magic fade and loses $int($aura) aura." - - - - - - "$unit($unit) fühlt sich einen Moment seltsam geschwächt." - "$unit($unit) fühlt strangely weakened." - - - - - - - "$unit($unit) konnte $unit($target) keine Aura entziehen." - "$unit($unit) could not draw aura from $unit($target)." - - - - - - - - "$unit($unit) wurde von $region($source) nach $unit($target) teleportiert." - "$unit($unit) was teleported from $region($source) to $unit($target)." - - - - - - - - - "$unit($mage) fand heraus, dass auf $ship($ship) der Zauber $curse($curse) liegt, der noch etwa $int($months) Wochen bestehen bleibt." - "$unit($mage) discovers that $ship($ship) is charmed with $curse($curse), which will last for, about $int($months) more weeks." - - - - - - - - - "$unit($mage) fand heraus, dass auf $building($building) der Zauber $curse($curse) liegt, der noch etwa $int($months) Wochen bestehen bleibt." - "$unit($mage) discovers that $building($building) is charmed with $curse($curse), which will last for, about $int($months) more weeks." - - - - - - - - - "$unit($mage) fand heraus, dass auf $unit($unit) der Zauber $curse($curse) liegt, der noch etwa $int($months) Wochen bestehen bleibt." - "$unit($mage) discovers that $unit($unit) is charmed with $curse($curse) that will last for about $int($months) more weeks." - - - - - - - - - "$unit($mage) fand heraus, dass auf $region($region) der Zauber $curse($curse) liegt, der noch etwa $int($months) Wochen bestehen bleibt." - "$unit($mage) discovers that $region($region) is charmed with $curse($curse), which will last for, about $int($months) more weeks." - - - - - - - - "$unit($mage) fand heraus, dass auf $ship($ship) der Zauber $curse($curse) liegt, dessen Kraft ausreicht, um noch Jahrhunderte bestehen zu bleiben." - "$unit($mage) discovers that $ship($ship) is charmed with $curse($curse), which will last for centuries." - - - - - - - - "$unit($mage) fand heraus, dass auf $building($building) der Zauber $curse($curse) liegt, dessen Kraft ausreicht, um noch Jahrhunderte bestehen zu bleiben." - "$unit($mage) discovers that $building($building) is charmed with $curse($curse), which will last for centuries." - - - - - - - - "$unit($mage) fand heraus, dass auf $unit($unit) der Zauber $curse($curse) liegt, dessen Kraft ausreicht, um noch Jahrhunderte bestehen zu bleiben." - "$unit($mage) discovers that $unit($unit) is charmed with $curse($curse), which will last for centuries." - - - - - - - - "$unit($mage) fand heraus, dass auf $region($region) der Zauber $curse($curse) liegt, dessen Kraft ausreicht, um noch Jahrhunderte bestehen zu bleiben." - "$unit($mage) discovers that $region($region) is charmed with $curse($curse), which will last for centuries." - - - - - - - "$unit($mage) meint, dass auf $ship($ship) ein Zauber liegt, konnte aber über den Zauber nichts herausfinden." - "It appears to $unit($mage) that $ship($ship) is charmed, but no details have been revealed." - "It appears to $unit($mage) that $ship($ship) is charmed, but no details have been revealed." - - - - - - - "$unit($mage) meint, dass auf $building($building) ein Zauber liegt, konnte aber über den Zauber nichts herausfinden." - "It appears to $unit($mage) that $building($building) is charmed, but no details have been revealed." - "It appears to $unit($mage) that $building($building) is charmed, but no details have been revealed." - - - - - - - "$unit($mage) meint, dass $unit($unit) verzaubert ist, konnte aber über den Zauber nichts herausfinden." - "It appears to $unit($mage) that $unit($unit) is charmed, but no details have been revealed." - "It appears to $unit($mage) that $unit($unit) is charmed, but no details have been revealed." - - - - - - - "$unit($mage) meint, dass auf $region($region) ein Zauber liegt, konnte aber über den Zauber nichts herausfinden." - "It appears to $unit($mage) that $region($region) is charmed, but no details have been revealed." - "It appears to $unit($mage) that $region($region) is charmed, but no details have been revealed." - - - - - - - "$unit($mage) meint, dass auf $ship($ship) kein Zauber liegt." - "It appears to $unit($mage) that $ship($ship) is not charmed." - "It appears to $unit($mage) that $ship($ship) is not charmed." - - - - - - - "$unit($mage) meint, dass auf $building($building) kein Zauber liegt." - "It appears to $unit($mage) that $building($building) is not charmed." - "It appears to $unit($mage) that $building($building) is not charmed." - - - - - - - "$unit($mage) meint, dass auf $unit($target) kein Zauber liegt." - "It appears to $unit($mage) that $unit($target) is not charmed." - "It appears to $unit($mage) that $unit($target) is not charmed." - - - - - - - "$unit($mage) meint, dass auf $region($region) kein Zauber liegt." - "It appears to $unit($mage) that $region($region) is not charmed." - "It appears to $unit($mage) that $region($region) is not charmed." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Region konnte nicht verzaubert werden." - "$unit($unit) in $region($region): '$order($command)' - The region could not be charmed." - "$unit($unit) in $region($region): '$order($command)' - The region could not be charmed." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $ship($ship) widersteht dem Zauber." - "$unit($unit) in $region($region): '$order($command)' - $ship($ship) resists the spell." - "$unit($unit) in $region($region): '$order($command)' - $ship($ship) resists the spell." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Gebäude $int36($id) konnte nicht verzaubert werden." - "$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be charmed." - "$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be charmed." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) widersteht dem Zauber." - "$unit($unit) in $region($region): '$order($command)' - $unit($target) resists the spell." - "$unit($unit) in $region($region): '$order($command)' - $unit($target) resists the spell." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Schiff $int36($id) wurde nicht gefunden." - "$unit($unit) in $region($region): '$order($command)' - Ship $int36($id) could not be located." - "$unit($unit) in $region($region): '$order($command)' - Ship $int36($id) could not be located." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Gebäude $int36($id) wurde nicht gefunden." - "$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be located." - "$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be located." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Einheit $id wurde nicht gefunden." - "$unit($unit) in $region($region): '$order($command)' - Unit $id could not be located." - "$unit($unit) in $region($region): '$order($command)' - Unit $id could not be located." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es wurde kein Ziel gefunden." - "$unit($unit) in $region($region): '$order($command)' - The spell could not find a target." - - - - - - - "$unit($mage) erleidet durch den Tod seines Vertrauten einen Schock." - "$unit($mage) receives a shock when his familiar dies." - - - - - - - - "$unit($unit) schafft es nicht, genug Kraft aufzubringen, um $spell($spell) auf Stufe $int($level) zu zaubern." - "$unit($unit) cannot muster enough energy to cast $spell($spell) on level $level($level)." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Für diesen Zauber fehlen noch $resources($list)." - "$unit($unit) in $region($region): '$order($command)' - Casting this spell requires an additional $resources($list)." - - - - - - - - "$unit($unit) hat nicht genügend Komponenten um $spell($spell) auf Stufe $int($level) zu zaubern." - "$unit($unit) has insufficient components to cast $spell($spell) on level $int($level)." - - - - - - - - "$unit($unit) unterläuft in $region($region) beim Zaubern von $spell($spell) ein Patzer." - "$unit($unit) fumbles while casting $spell($spell) in $region($region)." - - - - - - - - "Als $unit($unit) in $region($region) versucht, $spell($spell) zu zaubern, scheint plötzlich ein Beben durch die magische Essenz zu laufen und ein furchtbarer Sog versucht $unit($unit) in eine andere Dimension zu ziehen. Mit letzter Kraft gelingt es $unit($unit) sich zu retten." - "When $unit($unit) in $region($region) tries to cast $spell($spell), a sudden disturbance ripples through the magical realm and a terrible force attempts to drag the magician to another dimension. However, with a final effort of strength, $unit($unit) manages to save himself." - - - - - - - - "Als $unit($unit) in $region($region) versucht, $spell($spell) zu zaubern erhebt sich plötzlich ein dunkler Wind. Bizarre geisterhafte Gestalten kreisen um den Magier und scheinen sich von den magischen Energien des Zaubers zu ernähren. Mit letzter Kraft gelingt es $unit($unit) dennoch den Spruch zu zaubern." - "When $unit($unit) in $region($region) tries to cast $spell($spell), strong winds suddenly rise. Bizare ghostlike creatures circle around the magician and seem to be leeching his magical energy. However, with a final effort of strength, $unit($unit) manages to complete the spell." - - - - - - - - "Eine Botschaft von $unit.dative($unit) in $region($region): 'Ups! Quack, Quack!'" - "A message from $unit($unit) in $region($region): 'Oops! Croak, Croak!'" - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($mage) kann Zauber, die durch $unit($unit) gewirkt werden, nicht zusätzlich in die Ferne richten." - "$unit($unit) in $region($region): '$order($command)' - $unit($mage) cannot direct spells that are channeled through $unit($unit) into distant regions." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($mage) kann nicht genug Energie aufbringen, um diesen Spruch durch $unit($unit) zu wirken." - "$unit($unit) in $region($region): '$order($command)' - $unit($mage) cannot raise enough energy to channel the spell through $unit($unit)." - - - - - - - - "$unit($mage) ruft einen Vertrauten. $race($race, 0) können $skills lernen." - "$unit($mage) summons a familiar. $race($race, 0) can learn ${skills}." - - - - - - - - "$unit($unit) hat einen feuchtfröhlichen Abend in der Taverne verbracht. Ausser einem fürchterlichen Brummschädel ist da auch noch das dumme Gefühl $unit($mage) seine ganze Lebensgeschichte erzählt zu haben." - - - - - - - "$unit($unit) hat einen feuchtfröhlichen Abend in der - Taverne verbracht. Ausser einem fürchterlichen Brummschädel ist da auch - noch das dumme Gefühl die ganze Taverne mit seiner Lebensgeschichte - unterhalten zu haben." - - - - - - - - - "$unit($mage) gelingt es $unit($unit) zu verzaubern. $unit($unit) wird für etwa $int($duration) Wochen unseren Befehlen gehorchen." - - - - - - - - - "$unit($unit) gelingt es $spell($spell) zu zaubern, doch der Spruch zeigt keine Wirkung." - "$unit($unit) manages to cast $spell($spell), but the spell seems to have no effect." - - - - - - - - "$unit($unit) fühlt sich nach dem Zaubern von $spell($spell) viel erschöpfter als sonst und hat das Gefühl, dass alle weiteren Zauber deutlich mehr Kraft als normalerweise kosten werden." - "$unit($unit) feels far more exhausted than he should after casting $spell($spell) and assumes that any following spells will cost far more energy than usual." - - - - - - - "$unit($unit) in $region($region) hat rasende Kopfschmerzen und kann sich nicht mehr richtig konzentrieren. Irgendwas bei diesem Zauber ist fürchterlich schiefgelaufen." - "$unit($unit) in $region($region) is hit by a massive headacheand cannot concentrate on the spell. Some part of this ritual has gone very wrong indeed." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier verfängt sich in seinem eigenen Zauber." - - - "In der Region erstrahlen des Nachts bunte Lichter, Gloeckchen klingeln und frohes Kindergelaechter klingt durch den Wald." - "At night, colourful lights can be seen in this region, bells are a-ringing and the laughter of happy children seems to be everywhere in the forests." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Zauber von $unit.dative($unit) war viel zu schwach und löst sich gleich wieder auf." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) verzaubert ${target}." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) puts a spell on ${target}." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) gelingt es zwar die Region zu verzaubern, aber irgendwas ging schief." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) manages to put a spell on the region, but something went wrong nonetheless." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) gelingt es die Region zu verzaubern." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) puts a spell on the region." - - - - - - - "$unit($mage) erhöht die Körperkraft von $unit.dative($target) beträchtlich." - "$unit($mage) increases the strength of $unit($target) dramatically." - - - - - - - - "$unit($unit) in $region($region) regeneriert $int($amount) Aura." - "$unit($unit) régénère $int($amount) aura en $region($region)." - "$unit($unit) regenerates $int($amount) aura in $region($region)." - - - - - - "$string" - "$string" - - - - - - - - - "$unit($unit) in $region($region) verbraucht $int($cost) Silber für das Studium von $skill($skill)." - "$unit($unit) dépense $int($cost) écus en $region($region) pour apprendre $skill($skill)." - "$unit($unit) spends $int($cost) silver in $region($region) to study $skill($skill)." - - - - - - - "$unit($teacher) kann durch Dumpfbackenbrot nur $int($amount) Schüler lehren." - "Due to the effect of duncebuns, $unit($teacher) can only teach $int($amount) students." - - - - - - - - - "$unit($teacher) lehrt $unit($student) $skill($skill) auf Stufe $int($level)." - "$unit($teacher) teaches $unit($student) $skill($skill) to level $int($level)." - "$unit($teacher) teaches $unit($student) $skill($skill) to level $int($level)." - - - - - - - - "$unit($teacher) lehrt $unit($student) $skill($skill)." - "$unit($teacher) teaches $unit($student) $skill($skill)." - "$unit($teacher) teaches $unit($student) $skill($skill)." - - - - - - "$string" - "$string" - - - - - - - - "$unit($unit) verkauft $int($amount) $resource($resource,$amount)." - "$unit($unit) sells $int($amount) $resource($resource,$amount)." - "$unit($unit) sells $int($amount) $resource($resource,$amount)." - - - - - - - - "$unit($unit) kauft $int($amount) $resource($resource,$amount)." - "$unit($unit) buys $int($amount) $resource($resource,$amount)." - "$unit($unit) buys $int($amount) $resource($resource,$amount)." - - - - - - - "$unit($unit) bezahlt $int($money) Silber für den Kauf von Luxusgütern." - "$unit($unit) pays $int($money) silver for luxury items." - "$unit($unit) pays $int($money) silver for luxury items." - - - - - - - - "$unit($unit) verdient in $region($region) $int($amount) Silber durch den Verkauf von Luxusgütern." - "$unit($unit) earned $int($amount) silver in $region($region) by selling luxury items." - "$unit($unit) earned $int($amount) silver in $region($region) by selling luxury items." - - - - - - - - - "$unit($unit) arbeitet in $region($region) für einen Lohn von $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber." - "$unit($unit) works in $region($region) for a wage of $int($amount) $if($eq($wanted,$amount),""," out of $int($wanted)") silver." - "$unit($unit) works in $region($region) for a wage of $int($amount) $if($eq($wanted,$amount),""," out of $int($wanted)") silver." - - - - - - - - "$unit($unit) arbeitet in $region($region) für einen Lohn von $int($amount) Silber." - "In $region($region), $unit($unit) works for a wage of $int($amount) silver." - - - - - - - - - "$unit($unit) verdient in $region($region) $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber durch Unterhaltung." - "In $region($region), $unit($unit) earns only $int($amount) instead of$if($eq($wanted,$amount),""," of$if($eq($wanted,$amount),""," of $int($wanted)") ") with entertainment." - - - - - - - - "$unit($unit) fängt in $region($region) Fische im Wert von $int($amount) Silber." - "In $region($region), $unit($unit) catches fish worth $int($amount) silver." - - - - - - - - "$unit($unit) verdient in $region($region) $int($amount) Silber durch Unterhaltung." - "$unit($unit) earns $int($amount) in $region($region) with entertainment." - "$unit($unit) earns $int($amount) in $region($region) with entertainment." - - - - - - - - - "$unit($unit) verdient in $region($region) $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber durch Zauberei." - - - - - - - - "$unit($unit) verdient in $region($region) $int($amount) Silber durch Zauberei." - "$unit($unit) earns $int($amount) silver through simple magical services in $region($region)." - - - - - - - - - "$unit($unit) klaut in $region($region) $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber." - "$unit($unit) steals only $int($amount) silver instead of$if($eq($wanted,$amount),""," of$if($eq($wanted,$amount),""," of $int($wanted)") ") in $region($region)." - "$unit($unit) steals only $int($amount) silver instead of$if($eq($wanted,$amount),""," of$if($eq($wanted,$amount),""," of $int($wanted)") ") in $region($region)." - - - - - - - - "$unit($unit) klaut in $region($region) $int($amount) Silber." - "$unit($unit) steals $int($amount) silver in $region($region)." - - - - - - - - - "$unit($unit) treibt in $region($region) Steuern in Höhe von $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber ein." - "$unit($unit) collects taxes of only $int($amount) instead of$if($eq($wanted,$amount),""," of$if($eq($wanted,$amount),""," of $int($wanted)") ") silver in $region($region)." - - - - - - - - "$unit($unit) treibt in $region($region) Steuern in Höhe von $int($amount) Silber ein." - "$unit($unit) collects taxes of $int($amount) silver in $region($region)." - - - - - - - - - - "$unit($unit) verdient$if($eq($mode,4)," am Handel","") in $region($region) $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber$if($eq($mode,1)," durch Unterhaltung",$if($eq($mode,2)," durch Steuern",$if($eq($mode,3)," durch Handel",$if($eq($mode,5)," durch Diebstahl",$if($eq($mode,6)," durch Zauberei","")))))." - "$unit($unit) earns $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") in $region($region)." - "$unit($unit) earns $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") in $region($region)." - - - - - - - - - "$unit($unit) in $region($region) findet $int($amount) $resource($herb,$amount)." - "$unit($unit) in $region($region) finds $int($amount) $resource($herb,$amount)." - "$unit($unit) in $region($region) finds $int($amount) $resource($herb,$amount)." - - - - - - - "$unit($unit) züchtet $int($amount) Pferde." - "$unit($unit) breeds $int($amount) horses." - "$unit($unit) breeds $int($amount) horses." - - - - - - - - - "$unit($unit) pflanzt in $region($region) $int($amount) $resource($herb,$amount)." - "$unit($unit) plants $int($amount) $resource($herb,$amount) in $region($region)." - "$unit($unit) plants $int($amount) $resource($herb,$amount) in $region($region)." - - - - - - - "$unit($unit) in $region($region) entdeckt eine Laenader." - "$unit($unit) discovers laen in $region($region)." - - - - - - "Die Laenader in $region($region) ist erschöpft." - "There is no more laen in $region($region)." - - - - - - - - "$unit($unit) in $region($region) hat ein zu niedriges Talent, um $resource($resource,0) abzubauen." - "$unit($unit) in $region($region) is not proficient enough to produce $resource($resource,0)." - "$unit($unit) in $region($region) is not proficient enough to produce $resource($resource,0)." - - - - - - - - - - "$unit($unit) in $region($region) produziert $int($amount)$if($eq($wanted,$amount),""," von $int($wanted)") $resource($resource,$wanted)." - "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." - "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." - - - - - - - - - - "$unit($unit) in $region($region) produziert $int($amount)$if($eq($wanted,$amount),""," von $int($wanted)") $resource($resource,$wanted)." - "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." - "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." - - - - - - - - "$unit($unit) baut für $int($size) an $building($building) weiter." - "$unit($unit) builds $int($size) more on $building($building)." - "$unit($unit) builds $int($size) more on $building($building)." - - - - - - - - "$unit($unit) baut für $int($size) an $ship($ship) weiter." - "$unit($unit) builds $int($size) more on $ship($ship)." - "$unit($unit) builds $int($size) more on $ship($ship)." - - - - - - "$string" - "$string" - - - - - - - "$unit($unit) stirbt beim Versuch, die Feuerwand nach $region($region) zu durchqueren." - "$unit($unit) dies trying to cross the wall of fire into $region($region)." - "$unit($unit) dies trying to cross the wall of fire into $region($region)." - - - - - - - "$unit($unit) erleidet beim Durchqueren der Feuerwand nach $region($region) schwere Verbrennungen." - "$unit($unit) steps through the wall of fire into $region($region) and receives severe burn damage." - "$unit($unit) steps through the wall of fire into $region($region) and receives severe burn damage." - - - - - - - - - "$unit($unit) transportiert $unit($target) von $region($start) nach $region($end)." - "$unit($unit) transported $unit($target) from $region($start) to $region($end)." - "$unit($unit) transported $unit($target) from $region($start) to $region($end)." - - - - - - - - - - "$unit($unit) $if($eq($mode,1),"reitet", "wandert") von $region($start) nach $region($end).$if($isnull($regions),""," Dabei wurde $trail($regions) durchquert.")" - "$unit($unit) $if($eq($mode,1),"chevauche", "marche") de $region($start) vers $region($end) trans $trail($regions)" - "$unit($unit) $if($eq($mode,1),"rides", "walks") from $region($start) to $region($end)$if($isnull($regions),""," by way of $trail($regions)")." - - - - - - - "$unit($unit) entdeckt dass im $direction($direction) $terrain($region) ist." - "$unit($unit) discovered that an ocean lies in the $direction($direction)." - "$unit($unit) discovered that an ocean lies in the $direction($direction)." - - - - - - - "$unit($unit) entdeckt, dass $region($region) $terrain($region) ist." - "$unit($unit) discovered that $region($region) is $terrain($region)." - "$unit($unit) discovered that $region($region) is $terrain($region)." - - - - - - - "$unit($unit) ist in dieser Runde gelandet und kann nicht weiter ins Landesinnere nach $region($region) vorstossen." - "$unit($unit) has just landed and cannot continue moving to $region($region)." - "$unit($unit) has just landed and cannot continue moving to $region($region)." - - - - - - "Die Mannschaft der $ship($ship) kann in letzter Sekunde verhindern, dass das Schiff auf Land aufläuft." - "In the very last moment, the crew of the $ship($ship) saved the ship from grounding." - "In the very last moment, the crew of the $ship($ship) saved the ship from grounding." - - - - - - - "Die $ship($ship) konnte in $region($region) nicht einreisen, die Küste ist zu gefährlich für das Schiff." - "The $ship($ship) could not berth in $region($region). The coast is too dangerous for the vessel." - "The $ship($ship) could not berth in $region($region). The coast is too dangerous for the vessel." - - - - - - - "Die Mannschaft der $ship($ship) weigert sich, nach $direction($direction) zu reisen." - " The crew of the $ship($ship) refuses to travel to the$direction($direction)." - " The crew of the $ship($ship) refuses to travel to the$direction($direction)." - - - - - - - "Die Mannschaft der $ship($ship) weigert sich, nach $region($region) zu reisen." - "The crew of the $ship($ship) refuses to travel to $region($region)." - "The crew of the $ship($ship) refuses to travel to $region($region)." - - - - - - - "$unit($unit) weigert sich, nach $direction($direction) zu reisen." - "$unit($unit) refuses to travel to the$direction($direction)." - "$unit($unit) refuses to travel to the$direction($direction)." - - - - - - - "$unit($unit) weigert sich, nach $region($region) zu reisen." - "$unit($unit) refuses to travel to $region($region)." - "$unit($unit) refuses to travel to $region($region)." - - - - - - - "Die $ship($ship) konnte $region($region) nicht verlassen." - "The $ship($ship) could not leave $region($region)." - "The $ship($ship) could not leave $region($region)." - - - - - - - - "$unit($unit) wurde in $region($region) von $unit.dative($guard) aufgehalten." - "$unit($unit) was kept in $region($region) by $unit($guard)." - "$unit($unit) was kept in $region($region) by $unit($guard)." - - - - - - "Wir haben den Krieg mit $faction($faction) beendet." - "We declared peace with $faction($faction)." - "We declared peace with $faction($faction)." - - - - - - "$faction($faction) hat den Krieg mit uns beendet." - "$faction($faction) has declared peace with us." - "$faction($faction) has declared peace with us." - - - - - - "Wir haben $faction($faction) den Krieg erklärt." - "We declared war on $faction($faction)." - "We declared war on $faction($faction)." - - - - - - "$faction($faction) hat uns den Krieg erklärt." - "$faction($faction) has declared war on us." - "$faction($faction) has declared war on us." - - - - - - - - "$unit($unit) konnte nicht von $region($region) nach $region($target) reisen, da der Besitzer der Region es verhinderte." - "$unit($unit) could not travel from $region($region) to $region($target) because the owner denied entrance." - - - - - - - "$unit($unit) konnte aus $region($region) nicht ausreisen." - "$unit($unit) could not leave $region($region)." - "$unit($unit) could not leave $region($region)." - - - - - - - "$unit($follower) ist $unit($unit) gefolgt." - "$unit($follower) followed $unit($unit)." - "$unit($follower) followed $unit($unit)." - - - - - - - "$unit($follower) konnte $unit($unit) nicht folgen." - "$unit($follower) could not follow $unit($unit)." - "$unit($follower) could not follow $unit($unit)." - - - - - - - "$unit($unit) entdeckt, dass es keinen Weg nach $direction($direction) gibt." - "$unit($unit) discovers that there is no route going $direction($direction)." - "$unit($unit) discovers that there is no route going $direction($direction)." - - - - - - - - "$unit($unit) konnte von $region($region) nicht nach $direction($direction) ausreisen, der Nebel war zu dicht." - "$unit($unit) could not travel $direction($direction) from $region($region), the fog was too dense." - - - - - - "$string" - "$string" - - - - - - "In $region($region) erschienen die Herren der Bäume." - "In $region($region), the lords of the trees have risen." - "In $region($region), the lords of the trees have risen." - - - - - - "In $region($region) erhoben sich die Toten aus den Gräbern." - "The dead rise from their graves in $region($region)." - - - - - - - - "$unit($unit) vermehrt sich um $int($amount) $race($race,$amount)." - "$unit($unit) breeds $int($amount) new $race($race,$amount)." - "$unit($unit) breeds $int($amount) new $race($race,$amount)." - - - - - "Die Partei bekommt einen Spitznamen." - "Your faction received a nickname." - - - - - - - "Die Partei bekommt von $unit.dative($unit) in $region($region) einen Spitznamen." - "Your faction received a nickname from $unit($unit)." - - - - - - - "$building($building) in $region($region) bekommt einen Spitznamen." - "$building($building) in $region($region) received a nickname." - - - - - - - - "$building($building) in $region($region) bekommt von $unit.dative($renamer) einen Spitznamen." - "$building($building) in $region($region) received a nickname from $unit($renamer)." - - - - - - - "Die $ship($ship) in $region($region) bekommt einen Spitznamen." - "$ship($ship) in $region($region) received a nickname." - - - - - - - - "Die $ship($ship) in $region($region) bekommt von $unit.dative($renamer) einen Spitznamen." - "$ship($ship) in $region($region) received a nickname from $unit($renamer)." - - - - - - - "$unit($renamed) in $region($region) bekommt einen Spitznamen." - "$unit($renamed) in $region($region) received a nickname." - - - - - - - - "$unit($renamed) in $region($region) bekommt von $unit.dative($renamer) einen Spitznamen." - "$unit($renamed) in $region($region) received a nickname from $unit($renamer)." - - - - - - "$if($eq($dead,1),"Ein Bauer","$int($dead) Bauern") verhungert." - "$if($eq($dead,1),"One peasant starves","$int($dead) peasants starve")." - "$if($eq($dead,1),"One peasant starves","$int($dead) peasants starve")." - - - - - - "Der Vulkan in $region($region) bricht aus." - "The volcano in $region($region) breaks out." - "The volcano in $region($region) breaks out." - - - - - - - "Der Vulkan in $region($regionv) bricht aus. Die Lavamassen verwüsten $region($regionn)." - "The volcano in $region($regionv) breaks out. The lava devastates $region($regionn)." - "The volcano in $region($regionv) breaks out. The lava devastates $region($regionn)." - - - - - - - - "Beim Vulkanausbruch in $region($region) sterben $int($dead) Personen in $unit($unit)." - "$int($dead) people in $unit($unit) perisch when the volcano in $region($region) breaks out." - "$int($dead) people in $unit($unit) perisch when the volcano in $region($region) breaks out." - - - - - - "Aus dem Vulkankrater von $region($region) steigt kein Rauch mehr." - "The volcano of $region($region) stops releasing smoke." - "The volcano of $region($region) stops releasing smoke." - - - - - - "Aus dem Vulkankrater von $region($region) steigt plötzlich Rauch." - "Columns of smoke are released by the volcano of $region($region)." - "Columns of smoke are released by the volcano of $region($region)." - - - - - - - "$unit($unit) in $region($region) desertiert." - "$unit($unit) in $region($region) abandons your cause." - "$unit($unit) in $region($region) abandons your cause." - - - - - - - - "$unit($unit) reißt die Straße zwischen $region($from) und $region($to) ein." - "$unit($unit) demolishes the road between $region($from) and $region($to)." - "$unit($unit) demolishes the road between $region($from) and $region($to)." - - - - - - - "$unit($unit) in $region($region) kann keine Kräuter finden." - "$unit($unit) could not find any herbs in $region($region)." - "$unit($unit) could not find any herbs in $region($region)." - - - - - - - - - "$unit($unit) in $region($region) stellt fest, dass es hier $localize($amount) $resource($herb,0) gibt." - "$unit($unit) discovers that $localize($amount) $resource($herb,0) grow in $region($region)." - - - - - - - "$unit($unit) reißt einen Teil von $building($building) ein." - "$unit($unit) tears down parts of $building($building)." - - - - - - - "$unit($unit) zerstört $building($building)." - "$unit($unit) destroys $building($building)." - "$unit($unit) destroys $building($building)." - - - - - - - - "$unit($unit) erweitert in $region($region) das Straßennetz um $int($size)." - "$unit($unit) extends the road network in $region($region) by $int($size)." - "$unit($unit) extends the road network in $region($region) by $int($size)." - - - - - - - - "$unit($unit) $if($eq($amount,1),"schließt","schließen") sich $int($amount) $resource($rtype,$amount) an." - "$int($amount) $resource($rtype,$amount) $if($eq($amount,1),"joins","join") $unit($unit)." - - - - - - - "$unit($mage) legt einen Schleier um die Ausrüstung von $unit.dative($target)." - "$unit($mage) shrouds the equipment of $unit($target) in shadows." - - - - - - - - "Die $ship($ship) in $region($region) entdeckt ein Opfer im $direction($dir)." - "The $ship($ship) in $region($region) made $direction($dir) a target." - "The $ship($ship) in $region($region) made $direction($dir) a target." - - - - - - - "Die $ship($ship) in $region($region) kann keine Schiffe aufbringen." - "The $ship($ship) could not capture other ships in $region($region)." - "The $ship($ship) could not capture other ships in $region($region)." - - - - - - "Langsam kehren andere Völker nach $region($region) zurück." - "Little by little, people return to $region($region)." - "Little by little, people return to $region($region)." - - - - - - "Vor den vielen Orks in $region($region) fliehen die anderen Einwohner." - "People $region($region) flee from an Orc superiority." - "People $region($region) flee from an Orc superiority." - - - - - - - - "$unit($unit) in $region($region) beschädigt die $ship($ship)." - "$unit($unit) in $region($region) damages the $ship($ship)." - - - - - - - - "$unit($unit) in $region($region) versenkt die $ship($ship)." - "$unit($unit) sunk $ship($ship) in $region($region)." - "$unit($unit) sunk $ship($ship) in $region($region)." - - - - - - "$unit($unit) marschiert in eine Antimagiezone und löst sich auf." - "$unit($unit) walks into an antimagical zone and dissolves." - - - - - - "$unit($unit) hat sich unbemerkt verflüchtigt." - "$unit($unit) has dissolved without a trace." - "$unit($unit) has dissolved without a trace." - - - - - - "$unit($unit) wird sich bald verflüchtigen." - "$unit($unit) will dissolve soon." - "$unit($unit) will dissolve soon." - - - - - - - "$int($amount) Bauern flohen aus Furcht vor $unit($unit)." - "$int($amount) peasants fled in fear of $unit($unit)." - "$int($amount) peasants fled in fear of $unit($unit)." - - - - - - - - "$int($amount) Bauern werden zu $race($race,0) und schliessen sich $unit($unit) an." - "$int($amount) peasants become $race($race,0) and join the ranks of $unit($unit)." - - - - - - - "$unit($unit) verspeiste $int($amount) Pferde." - "$unit($unit) ate $int($amount) horses." - - - - - - - "$unit($unit) verspeiste $int($amount) Bauern." - "$unit($unit) ate $int($amount) peasants." - "$unit($unit) ate $int($amount) peasants." - - - - - - - "ERESSEA $int36($faction) \"${password}\" - Deine Befehle hatten ein falsches Passwort." - "ERESSEA $int36($faction) \"${password}\" - Your orders had the wrong password." - - - - - - "Das Passwort für diese Partei lautet ${value}." - "Le mot de passe de cette faction est '${value}'" - "The password of this faction is '$value'." - - - - - - "Die Reportadresse wurde nicht geändert, '${value}' ist keine gültige email." - " Address not changed, '$value' is an invalid email." - " Address not changed, '$value' is an invalid email." - - - - - - "Die Reportadresse wurde auf ${value} geändert." - " Address has been changed to '$value'." - " Address has been changed to '$value'." - - - - - - "Das Banner wurde auf '$value' geändert." - "Banner has been changed to '$value'." - "Banner has been changed to '$value'." - - - - - - - - - "Eine Partei muß mindestens $int($turns) Wochen alt sein, bevor sie angegriffen oder bestohlen werden kann." - "A faction must be at least $int($turns) weeks old before it can be attacked or stolen from." - - - - - - - - "$unit($unit) wurden in $region($region) $int($amount) Silberstücke geklaut." - "In $region($region), thieves stole $int($amount) silver from $unit($unit)." - "In $region($region), thieves stole $int($amount) silver from $unit($unit)." - - - - - - - "$unit($target) ertappte $unit($unit) beim versuchten Diebstahl." - "$unit($target) caught $unit($unit) in attempted theft." - "$unit($target) caught $unit($unit) in attempted theft." - - - - - - - "$unit($unit) wurde von $unit.dative($target) beim versuchten Diebstahl ertappt." - "$unit($unit) was caught by $unit($target) in attempted theft." - "$unit($unit) was caught by $unit($target) in attempted theft." - - - - - - "$unit($unit) fühlt sich beobachtet." - "$unit($unit) feels watched." - "$unit($unit) feels watched." - - - - - - - "$unit($unit) gelang es nicht, sich nahe genug an $unit($target) heranzuschleichen." - "$unit($unit) could not sneak close enough to $unit($target)." - "$unit($unit) could not sneak close enough to $unit($target)." - - - - - - - "$unit($spy) gelang es nicht, etwas über $unit($target) herauszufinden." - "$unit($spy) could not find out anything about $unit($target)." - "$unit($spy) could not find out anything about $unit($target)." - - - - - - - - "$unit($spy) gelang es, Informationen über $unit($target) ($status) herauszubekommen." - "$unit($spy) managed to gather information about $unit($target)." - - - - - - - "$unit($target) ist ein $type-Magier." - "$unit($target) is a $type-magician" - - - - - - - "$unit($target) beherrscht ${skills}." - "$unit($target) has the skills ${skills}." - - - - - - - "Im Gepäck von $unit($target) sind $resources($items)." - "$unit($target) carries $resources($items)" - - - - - - - "$unit($target) gehört der Partei $faction($faction) an." - "$unit($target) belongs to $faction($faction)." - - - - - - - "$unit($target) fühlt sich $if($isnull($spy),"","durch $unit($spy) ")beobachtet." - "$unit($target) feels watched by $unit($spy)." - "$unit($target) feels watched by $unit($spy)." - - - - - - - - "$faction($from) gibt ein Almosen von $int($amount) Silber an $faction($to)." - "$faction($from) donates $int($amount) silver to $faction($to)." - "$faction($from) donates $int($amount) silver to $faction($to)." - - - - - - - - "$unit($unit) vergißt durch Dumpfbackenbrot $int($weeks) Wochen des Talentes $skill($skill)." - "$unit($unit) eats a Dumpfbackenbrot and forgets $int($weeks) weeks worth of $skill($skill)." - "$unit($unit) eats a Dumpfbackenbrot and forgets $int($weeks) weeks worth of $skill($skill)." - - - - - - - "$unit($unit) in $region($region) wird durch unzureichende Nahrung geschwächt." - "$unit($unit) is weakened due to malnourishment." - "$unit($unit) is weakened due to malnourishment." - - - - - - - - - "$unit($unit) verliert in $region($region) $int($dead) von $int($add($live,$dead)) Personen durch Unterernährung." - "$unit($unit) loses $int($dead) of $int($add($live,$dead)) people due to starvation in $region($region)." - "$unit($unit) loses $int($dead) of $int($add($live,$dead)) people due to starvation in $region($region)." - - - - - - - - "$unit($unit): '$order($command)' - Die Einheit benutzt bereits $resource($using,0)." - "$unit($unit): '$order($command)' - The unit already uses $resource($using,0)." - "$unit($unit): '$order($command)' - The unit already uses $resource($using,0)." - - - - - - "Die $ship($ship) ist zu stark beschädigt und sinkt." - "The $ship($ship) suffers too heavy damage and sinks." - "The $ship($ship) suffers too heavy damage and sinks." - - - - - - - "Die $ship($ship) entdeckt, dass $region($region) Festland ist." - "The $ship($ship) discovers that $region($region) has no shore." - - - - - - - - "Die $ship($ship) fliegt von $region($from) nach $region($to)." - "The $ship($ship) flies from $region($from) to $region($to)." - - - - - - - - "Die $ship($ship) segelt von $region($from) nach $region($to)." - "The $ship($ship) sails from $region($from) to $region($to)." - - - - - - - - "Die $ship($ship) wird in $region($region) von Stürmen abgetrieben$if($sink," und sinkt","")." - "The $ship($ship) in $region($region) drifts in heavy storm$if($sink," and sinks","")." - "The $ship($ship) in $region($region) drifts in heavy storm$if($sink," and sinks","")." - - - - - - - - - "Die $ship($ship) fährt in den Mahlstrom von $region($region) und nimmt $int($damage) Schaden$if($sink," und sinkt","")." - "The $ship($ship) sails into the maelstrom of $region($region) and takes $int($damage) damage$if($sink,". The ship sinks","")." - - - - - - - "$unit($unit) vergißt $skill($skill)." - "$unit($unit) forgets $skill($skill)." - "$unit($unit) forgets $skill($skill)." - - - - - - - "$unit($unit) gibt das Kommando an $unit($recipient)." - "$unit($unit) gave control to $unit($recipient)." - "$unit($unit) gave control to $unit($recipient)." - - - - - - - - "$unit($unit) gibt $int($amount) Dumpfbackenbrot an $unit($recipient)." - "$unit($unit) administers $int($amount) duncebuns to $unit($recipient)." - - - - - - - - - "$unit($unit) in $region($region) rekrutiert $int($amount) von $int($want) Personen." - "$unit($unit) in $region($region) recruits $int($amount) $int($want) people." - "$unit($unit) in $region($region) recruits $int($amount) $int($want) people." - - - - - - - - "$unit($unit) belagert $building($building). Dabei richten die Katapulte Zerstörungen von $int($destruction) Größenpunkten an." - "$building($building) is under siege by $unit($unit). During siege, catapults caused $int($destruction) points destruction." - "$building($building) is under siege by $unit($unit). During siege, catapults caused $int($destruction) points destruction." - - - - - - - "$unit($unit) belagert $building($building)." - "$building($building) is under siege by $unit($unit)." - - - - - - - - "$unit($unit) ertrinkt beim Untergang der $ship($ship) in $region($region)." - "$unit($unit) drowns when $ship($ship) in $region($region) sinks." - "$unit($unit) drowns when $ship($ship) in $region($region) sinks." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht bewachen, da sie versucht zu fliehen." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot guard the region because it's trying to flee." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot guard the region because it's trying to flee." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann den Befehl in dieser Runde nicht ausführen, da sie an einem Kampf teilgenommen hat." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot execute this command because it has been in combat." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot execute this command because it has been in combat." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Gebäude kann nur einmal pro Runde erweitert werden." - "$unit($unit) in $region($region): '$order($command)' - Thhe building can be expanded only once per turn." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieses Objekt ist unzerstörbar." - "$unit($unit) in $region($region): '$order($command)' - This object is indestructible." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Ohne Zutaten kann ein Alchemist nichts herstellen." - "$unit($unit) in $region($region): '$order($command)' - Ohne Zutaten kann ein Alchemist nichts herstellen." - "$unit($unit) in $region($region): '$order($command)' - Without ingredients an alchemist can not produce anything." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nicht alle Zutaten vorhanden." - "$unit($unit) in $region($region): '$order($command)' - Nicht alle Zutaten vorhanden." - "$unit($unit) in $region($region): '$order($command)' - Not all ingredients present." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Eine Partei kann nur einmal neu starten." - "$unit($unit) in $region($region): '$order($command)' - Restart can only be used once." - "$unit($unit) in $region($region): '$order($command)' - Restart can only be used once." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Werwesen können nicht arbeiten." - "$unit($unit) in $region($region): '$order($command)' - Lycantropes don't work." - "$unit($unit) in $region($region): '$order($command)' - Lycantropes don't work." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Werwesen können nicht mit anderen Personen gemischt werden." - "$unit($unit) in $region($region): '$order($command)' - Lycantropes may not be mixed with normal people." - "$unit($unit) in $region($region): '$order($command)' - Lycantropes may not be mixed with normal people." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann sich nicht verwandeln." - "$unit($unit) in $region($region): '$order($command)' - This unit can not change shape." - "$unit($unit) in $region($region): '$order($command)' - This unit can not change shape." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diese Einheit ist kein Werwesen." - "$unit($unit) in $region($region): '$order($command)' - This unit is not in lycantropic form." - "$unit($unit) in $region($region): '$order($command)' - This unit is not in lycantropic form." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diese Einheit ist schon ein Werwesen." - "$unit($unit) in $region($region): '$order($command)' - This unit already assumed lycantropic form." - "$unit($unit) in $region($region): '$order($command)' - This unit already assumed lycantropic form." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieses Talent kann nicht höher gelernt werden." - "$unit($unit) in $region($region): '$order($command)' - This skill cannot be raised any higher." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Snotlinge sind zu dumm, um auf den Feldern zu arbeiten." - "$unit($unit) in $region($region): '$order($command)' - We snotlings is too stupid fer dat!" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Partei muß mindestens 9 Wochen alt sein, um einen Neustart zu versuchen." - "$unit($unit) in $region($region): '$order($command)' - Your faction is not old enough to start over." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Optionen ZIP und BZIP2 können nur um, nicht ausgeschaltet werden." - "$unit($unit) in $region($region): '$order($command)' - options ZIP and BZIP2 can only be switched, not turned off." - "$unit($unit) in $region($region): '$order($command)' - options ZIP and BZIP2 can only be switched, not turned off." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Einheiten einer Partei, die noch immun gegen Angriffe ist, dürfen nicht bewachen." - "$unit($unit) in $region($region): '$order($command)' - units of a faction that can't be attacked may not guard." - "$unit($unit) in $region($region): '$order($command)' - units of a faction that can't be attacked may not guard." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - In dieser Region kann man nichts verkaufen." - "$unit($unit) in $region($region): '$order($command)' - there is no trade in this region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Bereits ein Synonym gesetzt." - "$unit($unit) in $region($region): '$order($command)' - synonym already set." - "$unit($unit) in $region($region): '$order($command)' - synonym already set." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Kein Synonym angegeben." - "$unit($unit) in $region($region): '$order($command)' - synonym missing." - "$unit($unit) in $region($region): '$order($command)' - synonym missing." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Ungültiges Synonym." - "$unit($unit) in $region($region): '$order($command)' - invalid synonym." - "$unit($unit) in $region($region): '$order($command)' - invalid synonym." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Ungültiges Prefix." - "$unit($unit) in $region($region): '$order($command)' - invalid prefix." - "$unit($unit) in $region($region): '$order($command)' - invalid prefix." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier hat bereits einen Klon." - "$unit($unit) in $region($region): '$order($command)' - The magician already has a clone." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Gebäude auf dem Ozean können nicht betreten werden." - "$unit($unit) in $region($region): '$order($command)' - Buildings on the ocean may not be entered." - "$unit($unit) in $region($region): '$order($command)' - Buildings on the ocean may not be entered." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier werden niemals Bäume wachsen." - "$unit($unit) in $region($region): '$order($command)' - Trees won't grow here." - "$unit($unit) in $region($region): '$order($command)' - Trees won't grow here." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nur ein Magier kann einen Astralkristall benutzen." - "$unit($unit) in $region($region): '$order($command)' - Only mages may use an astralcrystal." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Verbände können nur zwischen Einheiten derselben Partei gebildet werden." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist in keinem Verband." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Eine Einheit kann nur in einem Verband Mitglied sein." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Wie sollen wir uns tarnen?" - "$unit($unit) in $region($region): '$order($command)' - What should we disguise us as?" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Wieviel sollen wir einreißen?" - "$unit($unit) in $region($region): '$order($command)' - How much shall we tear down?" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dorthin können wir die Einheit nicht transportieren." - "$unit($unit) in $region($region): '$order($command)' - We cannot transport this unit there." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit transportiert uns nicht." - "$unit($unit) in $region($region): '$order($command)' - the unit is not transporting us." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diese Einheit kennt keine Trankrezepte." - "$unit($unit) in $region($region): '$order($command)' - This unit knows no recipes for potions." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nur noch nicht gestärkte Untote können das Ziel dieses Zaubers sein." - "$unit($unit) in $region($region): '$order($command)' - Undead can only be affected once by this spell." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Passwort darf nur Buchstaben und Ziffern enthalten." - "$unit($unit) in $region($region): '$order($command)' - Your password may only contain alphanumeric symbols." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Gegen diese Rasse kann kein Jihad ausgerufen werden." - "$unit($unit) in $region($region): '$order($command)' - You cannot start a jihad against this race." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Gegen welche Rasse soll der Jihad ausgerufen werden?" - "$unit($unit) in $region($region): '$order($command)' - What race did you want the jihad to be against?" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dazu muss erst die Spezialeigenschaft erworben werden." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Name und Beschreibung des Gebäudes können nicht geändert werden." - "$unit($unit) in $region($region): '$order($command)' - You cannot change the name and description of this building." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das kann die Einheit nicht." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier kann man keine Schiffe bauen." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier kann man keine Gebäude errichten." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht unterrichten." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier kann man nicht unterrichten." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Pferde müssen leider draußen bleiben." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier kann man niemanden angreifen." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier kann man niemanden bestehlen." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier kann man nicht zaubern." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier kann man nichts übergeben." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nur eine Einzelperson kann das Ticket benutzen." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Gegenstand funktioniert nur in der Eingangshalle." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Gegenstand funktioniert nur in der normalen Welt." - "$unit($unit) in $region($region): '$order($command)' - This item only works in the normal world." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieses Gut hat die Einheit nicht." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have this good." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieses Gut wird hier produziert." - "$unit($unit) in $region($region): '$order($command)' - This good is not produced here." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Partei kann keine weiteren Wyrme besitzen." - "$unit($unit) in $region($region): '$order($command)' - The faction cannot contain any more wyrms." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Vor den Besitzer eines Schiffes oder Gebäudes kann nicht sortiert werden." - "$unit($unit) in $region($region): '$order($command)' - You cannot sort before the owner of a ship or a building." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Besitzer eines Schiffes oder Gebäudes kann nicht neu sortiert werden." - "$unit($unit) in $region($region): '$order($command)' - The owner of a ship or a building cannot be sorted." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Befehl ist nur auf Einheiten innerhalb des selben Gebäudes oder Schiffes anwendbar." - "$unit($unit) in $region($region): '$order($command)' - That order only applies to units in the same building or ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Zieleinheit ist ungültig." - "$unit($unit) in $region($region): '$order($command)' - The target unit is invalid." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Ungültiges Locale." - "$unit($unit) in $region($region): '$order($command)' - Invalid locale." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Um soetwas kann man nicht beten." - "$unit($unit) in $region($region): '$order($command)' - You cannot pray for this." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Soetwas kann man nicht opfern." - "$unit($unit) in $region($region): '$order($command)' - You cannot sacrifice this." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Auraangabe fehlerhaft oder zuwenig Aura." - "$unit($unit) in $region($region): '$order($command)' - Invalid aura specification or too little aura." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier ist nicht stark genug, sich den Göttern zu opfern." - "$unit($unit) in $region($region): '$order($command)' - This magician is not strong enough to be sacrificed to the gods." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Was und wieviel soll geopfert werden?" - "$unit($unit) in $region($region): '$order($command)' - What and how much should be sacrificed?" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diese Kraft können selbst die Götter nicht mehr mächtiger machen." - "$unit($unit) in $region($region): '$order($command)' - Even the gods cannot improve this power." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nicht genug Karma." - "$unit($unit) in $region($region): '$order($command)' - Not enough karma." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff kann nicht aufs offene Meer hinaus segeln." - "$unit($unit) in $region($region): '$order($command)' - The ship cannot sail into the open seas." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Partei muß mindestens 10 Runden alt sein." - "$unit($unit) in $region($region): '$order($command)' - The faction has to be 10 turns old." - "$unit($unit) in $region($region): '$order($command)' - The faction has to be 10 turns old." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Partei hat schon einen Namen." - "$unit($unit) in $region($region): '$order($command)' - The faction is already named." - "$unit($unit) in $region($region): '$order($command)' - The faction is already named." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Gebäude hat schon einen Namen." - "$unit($unit) in $region($region): '$order($command)' - The building is already named." - "$unit($unit) in $region($region): '$order($command)' - The building is already named." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff hat schon einen Namen." - "$unit($unit) in $region($region): '$order($command)' - The ship is already named." - "$unit($unit) in $region($region): '$order($command)' - The ship is already named." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat schon einen Namen." - "$unit($unit) in $region($region): '$order($command)' - The unit is already named." - "$unit($unit) in $region($region): '$order($command)' - The unit is already named." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Keine gültige Rasse angegeben." - "$unit($unit) in $region($region): '$order($command)' - You did not specify a valid race." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit muß sich an Land befinden." - "$unit($unit) in $region($region): '$order($command)' - The unit must be on land." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $building($building) ist kein Steinkreis." - "$unit($unit) in $region($region): '$order($command)' - $building($building) is not a stonecircle." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $building($building) muss vor der Weihe fertiggestellt sein." - "$unit($unit) in $region($region): '$order($command)' - $building($building) has to be complete before it can be blessed." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - In $region($target) sind keine Gräber." - "$unit($unit) in $region($region): '$order($command)' - There are no graves in $region($target)." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Partei muß mindestens 81 Wochen alt sein, um einen Neustart mit einer anderen Rasse zu versuchen." - "$unit($unit) in $region($region): '$order($command)' - The faction must be at least 81 weeks old to restart with a new race." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Soll eine Einheit oder ein Schiff verfolgt werden?" - "$unit($unit) in $region($region): '$order($command)' - Is this unit or ship supposed to be followed?" - "$unit($unit) in $region($region): '$order($command)' - Is this unit or ship supposed to be followed?" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Soll eine Einheit oder ein Schiff eine neue Nummer bekommen?" - "$unit($unit) in $region($region): '$order($command)' - Is this unit or ship supposed to get a new number?" - "$unit($unit) in $region($region): '$order($command)' - Is this unit or ship supposed to get a new number?" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier können nur Orks rekrutiert werden." - "$unit($unit) in $region($region): '$order($command)' - You can recruit only Orcs here." - "$unit($unit) in $region($region): '$order($command)' - You can recruit only Orcs here." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Region befindet sich in Aufruhr." - "$unit($unit) in $region($region): '$order($command)' - There are riots in this region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Gebäude ist noch nicht fertig gebaut." - "$unit($unit) in $region($region): '$order($command)' - The building is not finished yet." - "$unit($unit) in $region($region): '$order($command)' - The building is not finished yet." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Für das Gebäude wurde noch kein Unterhalt bezahlt." - "$unit($unit) in $region($region): '$order($command)' - Maintenance has not been paid yet." - "$unit($unit) in $region($region): '$order($command)' - Maintenance has not been paid yet." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist mit Ausschiffen beschäftigt.." - "$unit($unit) in $region($region): '$order($command)' - The unit is busy disembarking." - "$unit($unit) in $region($region): '$order($command)' - The unit is busy disembarking." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Typ Einheit kann keine Schiffe betreten." - "$unit($unit) in $region($region): '$order($command)' - Swimmers cannot enter ships." - "$unit($unit) in $region($region): '$order($command)' - Swimmers cannot enter ships." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Typ Einheit kann keine Gebäude betreten." - "$unit($unit) in $region($region): '$order($command)' - this type of unit cannot enter a building." - "$unit($unit) in $region($region): '$order($command)' - this type of unit cannot enter a building." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit oder ihre Tiere würden dort nicht überleben." - "$unit($unit) in $region($region): '$order($command)' - The unit or its animals would not survive there." - "$unit($unit) in $region($region): '$order($command)' - The unit or its animals would not survive there." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dorthin kann die Einheit uns nicht transportieren." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot transport us to this place." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot transport us to this place." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $building($building) wird belagert." - "$unit($unit) in $region($region): '$order($command)' - $building($building) is under siege." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Eintritt in $building($building) wurde verwehrt." - "$unit($unit) in $region($region): '$order($command)' - Entrance to $building($building) was denied." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Ein Vertrauter wird beschworen, verschwindet jedoch wieder, als er keine Verbindung zu seinem Element herstellen kann." - "$unit($unit) in $region($region): '$order($command)' - A familiar is summoned, but disappears again when it cannot get in contact with its natural element." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nur normale Personen können Steuern eintreiben." - "$unit($unit) in $region($region): '$order($command)' - Only normal characters can collect taxes." - "$unit($unit) in $region($region): '$order($command)' - Only normal characters can collect taxes." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dafür braucht ein Einheit mindestens Kräuterkunde 7." - "$unit($unit) in $region($region): '$order($command)' - A skill of herbalism 7 or higher is required." - "$unit($unit) in $region($region): '$order($command)' - A skill of herbalism 7 or higher is required." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Einheiten in den hinteren Reihen können nicht angreifen." - "$unit($unit) in $region($region): '$order($command)' - Units cannot attack from the second row." - "$unit($unit) in $region($region): '$order($command)' - Units cannot attack from the second row." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - unbekannter Kampfstatus." - "$unit($unit) in $region($region): '$order($command)' - unknown combat status." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht bewaffnet und kampffähig." - "$unit($unit) in $region($region): '$order($command)' - The unit is not armed and ready to fight." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Partei hat bereits ein Magiegebiet." - "$unit($unit) in $region($region): '$order($command)' - The faction has already chosen a magical school." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können nicht arbeiten." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot work." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot work." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hungernde Soldaten kämpfen nicht." - "$unit($unit) in $region($region): '$order($command)' - Starving units do not fight." - "$unit($unit) in $region($region): '$order($command)' - Starving units do not fight." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hungernde Einheiten können nicht zaubern." - "$unit($unit) in $region($region): '$order($command)' - Starving units cannot cast spells." - "$unit($unit) in $region($region): '$order($command)' - Starving units cannot cast spells." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hungernde Einheiten können nicht bewachen." - "$unit($unit) in $region($region): '$order($command)' - Starving units cannot guard." - "$unit($unit) in $region($region): '$order($command)' - Starving units cannot guard." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Zeige alle was?" - "$unit($unit) in $region($region): '$order($command)' - Show all what?" - "$unit($unit) in $region($region): '$order($command)' - Show all what?" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht bauen." - "$unit($unit) in $region($region): '$order($command)' - You cannot build such a thing." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Im astralen Nebel konnte niemand entdeckt werden." - "$unit($unit) in $region($region): '$order($command)' - Noone could be seen in th astral fog." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Ein Zauber in dieser Region verhindert das." - "$unit($unit) in $region($region): '$order($command)' - There is an active spell in this region that prevents this." - "$unit($unit) in $region($region): '$order($command)' - There is an active spell in this region that prevents this." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nur im Astralraum gezaubert werden." - "$unit($unit) in $region($region): '$order($command)' - This spell can only be cast in the astral plane." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier gibt es keine Verbindung zur astralen Welt." - "$unit($unit) in $region($region): '$order($command)' - There is no connection to the astral plane here." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Von hier aus kann man die astrale Ebene nicht erreichen." - "$unit($unit) in $region($region): '$order($command)' - You cannot reach the astral plane from here." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Einheit ist kein Magier." - "$unit($unit) in $region($region): '$order($command)' - Unit is not a magician." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Parameter nicht korrekt angegeben." - "$unit($unit) in $region($region): '$order($command)' - Incorrect parameter." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier befindet sich nicht auf einem Schiff." - "$unit($unit) in $region($region): '$order($command)' - The magician is not on board a ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Auf dem Schiff liegt bereits so ein Zauber." - "$unit($unit) in $region($region): '$order($command)' - The ship is already under this spell." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es ist zu gefährlich, ein sturmgepeitschtes Schiff fliegen zu lassen." - "$unit($unit) in $region($region): '$order($command)' - It is too dangerous to fly the ship in the storm." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Syntax Error." - "$unit($unit) in $region($region): '$order($command)' - Syntax Error." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Auraangabe fehlerhaft." - "$unit($unit) in $region($region): '$order($command)' - wrong Aura values." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Zu dieser Einheit kann keine Aura übertragen werden." - "$unit($unit) in $region($region): '$order($command)' - You cannot pass aura on to this unit." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Auf dem Gebäude liegt bereits so ein Zauber." - "$unit($unit) in $region($region): '$order($command)' - There is alrady a spell on that building." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nicht auf hoher See gezaubert werden." - "$unit($unit) in $region($region): '$order($command)' - This spell cannot be cast while you are on the ocean." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nicht auf Monster gezaubert werden." - "$unit($unit) in $region($region): '$order($command)' - This spell cannot be cast on monsters." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nicht auf Untote gezaubert werden." - "$unit($unit) in $region($region): '$order($command)' - This spell cannot be cast on undead." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Stimmung in der Region ist so schlecht, dass niemand auf den Zauber reagiert." - "$unit($unit) in $region($region): '$order($command)' - The mood in this region is so bad that nobody reacts t the spell." - - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) wusste trotz intensivem Verhör nichts über $region($tregion) zu berichten." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - So viele Persoenen übersteigen die Kräfte des Magiers." - "$unit($unit) in $region($region): '$order($command)' -This many people exceed the powers of the magician." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) hat unaufkündbare Bindungen an seine alte Partei." - "$unit($unit) in $region($region): '$order($command)' - $unit($target) have unbreakable prior commitments to their faction." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber gelingt nur in einer Ozeanregion." - "$unit($unit) in $region($region): '$order($command)' - This spell works only in an ocean region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - In einer Region ohne Bäume kann man diesen Zauber nicht wirken." - "$unit($unit) in $region($region): '$order($command)' - You cannot cast this spell in a region without trees." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Ziel wurde vergessen." - "$unit($unit) in $region($region): '$order($command)' - No target has been supplied." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das ist keine gültige Rasse." - "$unit($unit) in $region($region): '$order($command)' - This is not a valid race." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Rasse und Zieleinheit wurden vergessen." - "$unit($unit) in $region($region): '$order($command)' - Race and target unit have not been supplied." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die maximale Aura reicht nicht für diesen Zauber." - "$unit($unit) in $region($region): '$order($command)' - Magician's maximum Aura is not high enough for this spell." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier hat bereits einen Vertrauten." - "$unit($unit) in $region($region): '$order($command)' - The magician already has a familiar." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Flammen finden keine Nahrung. Das Feuer erlischt, ohne Schaden anzurichten." - "$unit($unit) in $region($region): '$order($command)' - The flames find no kindling. The fire dies quickly, causing no damage whatsoever." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Um einen Heimstein zu erschaffen, muß der Zauberer in einer Burg sein." - "$unit($unit) in $region($region): '$order($command)' - The magician has to be in a castle to create a homestone." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das ist keine Waldregion." - "$unit($unit) in $region($region): '$order($command)' - This is not a forest region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dorthin führt kein Weg." - "$unit($unit) in $region($region): '$order($command)' - No way is leading in this direction." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Zielregion wurde nicht korrekt angegeben." - "$unit($unit) in $region($region): '$order($command)' - Target region was supplied incorrectly." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Zauber funktioniert nur in der Geisterwelt." - "$unit($unit) in $region($region): '$order($command)' - This spell will only work in the realm of spirits." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Wege zwischen Geisterwelt und Realität scheinen blockiert zu sein." - "$unit($unit) in $region($region): '$order($command)' - The paths to the spirit world seem to be blocked." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Zauber funktioniert nur in Wäldern." - "$unit($unit) in $region($region): '$order($command)' - This spell works only in forests." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Zauber funktioniert nur in der materiellen Welt." - "$unit($unit) in $region($region): '$order($command)' - This spell works only in the material world." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Selbst der mächtigste Magier der Welt könnte keinen Ozean austrocknen lassen." - "$unit($unit) in $region($region): '$order($command)' - Even the gods cannot dry out an entire ocean." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nicht im Sumpf gezaubert werden." - "$unit($unit) in $region($region): '$order($command)' - You cannot cast this spell in a swamp." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nur auf Land gelegt werden." - "$unit($unit) in $region($region): '$order($command)' - This spell works only ashore." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Zauber scheint ungewöhnlich schwach zu sein. Irgendetwas hat die magischen Energien abgeleitet." - "$unit($unit) in $region($region): '$order($command)' - the spell seems exceptionally weak. Something has interfred with the magical energies." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann den Befehl in dieser Runde nicht ausführen, da sie sich bewegt hat." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot execute this command because it has moved." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit bewegt sich nicht." - "$unit($unit) in $region($region): '$order($command)' - The unit does not move." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier befindet sich nicht auf einem Schiff." - "$unit($unit) in $region($region): '$order($command)' - The magician is not on board a ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff kann in diese Richtung nicht ablegen." - "$unit($unit) in $region($region): '$order($command)' - The ship cannot leave in this direction." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dazu muß sich der Magier in der Burg oder an Bord des Schiffes befinden." - "$unit($unit) in $region($region): '$order($command)' - To do this, the magician has to be in a castle or on board a ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Zauber schlägt fehl." - "$unit($unit) in $region($region): '$order($command)' - The spell fails." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieses Magiegebiet kann die Einheit nicht lernen." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot learn this magic sphere." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es wurde kein Magiegebiet angegeben." - "$unit($unit) in $region($region): '$order($command)' - No magic sphere was supplied." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diesen Spruch kann der Vertraute nicht zaubern." - "$unit($unit) in $region($region): '$order($command)' - the familiar cannot cast this spell." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diesen Spruch kann man nicht in die Ferne richten." - "$unit($unit) in $region($region): '$order($command)' - You cannot cast this spell on a distant target." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diesen Spruch kann man nicht auf einem sich bewegenden Schiff stehend zaubern." - "$unit($unit) in $region($region): '$order($command)' - You cannot cast this spell while standing on a moving ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber ist nur im Kampf sinnvoll." - "$unit($unit) in $region($region): '$order($command)' - this spell makes only sense in combat." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Selbst in der Bibliothek von Xontormia konnte dieser Spruch nicht gefunden werden." - "$unit($unit) in $region($region): '$order($command)' - Even in the Xontormia Library, this spell could not be found." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es wurde kein Zauber angegeben." - "$unit($unit) in $region($region): '$order($command)' - There was no spell supplied." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diesen Kampfzauber gibt es nicht." - "$unit($unit) in $region($region): '$order($command)' - This combat spell does not exist." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Bauern nehmen dieses großzügige Geschenk nicht an." - "$unit($unit) in $region($region): '$order($command)' - The peasants did not accept this gracious gift." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diesen Zauber kennt die Einheit nicht." - "$unit($unit) in $region($region): '$order($command)' - The unit does not know this spell." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es konnten keine Luxusgüter verkauft werden." - "$unit($unit) in $region($region): '$order($command)' - No luxury items could be sold." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit geht nicht zu den Bauern." - "$unit($unit) in $region($region): '$order($command)' - The unit does not go to the peasants." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diese Rasse kann eine Burg nicht belagern." - "$unit($unit) in $region($region): '$order($command)' - This race cannot siege a castle." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Trank bekommt der Einheit nicht." - "$unit($unit) in $region($region): '$order($command)' - The unit disagreed with the potion." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Nestwärme kann nur von Insektenvölkern benutzt werden." - "$unit($unit) in $region($region): '$order($command)' - this potion can only be used by insects." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Heiltrank wird automatisch bei Bedarf benutzt." - "$unit($unit) in $region($region): '$order($command)' - This healing potion will be automatically used when needed." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit besitzt den Trank nicht." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have this potion." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es konnten keine Luxusgüter gekauft werden." - "$unit($unit) in $region($region): '$order($command)' - No luxury items could be bought." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es konnten keine Personen übergeben werden." - "$unit($unit) in $region($region): '$order($command)' - No person could be handed over." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Magier arbeiten grundsätzlich nur alleine!" - "$unit($unit) in $region($region): '$order($command)' - Magicians always work alone!" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Partei hat ein anderes Magiegebiet." - "$unit($unit) in $region($region): '$order($command)' - The faction has a different magic sphere." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Zuviele Alchemisten in der Partei." - "$unit($unit) in $region($region): '$order($command)' - Too many alchemists in the faction." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Zuviele Magier in der Partei." - "$unit($unit) in $region($region): '$order($command)' - Too many magicians in the faction." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hochqualifizierte Personen weigern sich, für andere Parteien zu arbeiten." - "$unit($unit) in $region($region): '$order($command)' - Highly qualified people refuse to work for other parties." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit schließt sich den Bauern an." - "$unit($unit) in $region($region): '$order($command)' - The unit joins the local peasants." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit springt über Bord und ertrinkt." - "$unit($unit) in $region($region): '$order($command)' - The unit jumps over board and drowns." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Region wird bewacht." - "$unit($unit) in $region($region): '$order($command)' - The region is guarded." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Unbekannte Option." - "$unit($unit) in $region($region): '$order($command)' - Unknown Option." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit wird belagert." - "$unit($unit) in $region($region): '$order($command)' - The unit is under siege." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Zum Straßenbau braucht man Steine." - "$unit($unit) in $region($region): '$order($command)' - You need stones to build a road." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Wohin soll die Botschaft gehen?" - "$unit($unit) in $region($region): '$order($command)' - Who is supposed to get this message?" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht der Burgherr." - "$unit($unit) in $region($region): '$order($command)' - The unit is not in command of a castle." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht Burgherr der größten Burg in der Region." - "$unit($unit) in $region($region): '$order($command)' - The unit is not in command of the largest castle in the region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht der Kapitän des Schiffes." - "$unit($unit) in $region($region): '$order($command)' - The unit is not captain of a ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist in keiner Burg." - "$unit($unit) in $region($region): '$order($command)' - The unit is not in a castle." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist auf keinem Schiff." - "$unit($unit) in $region($region): '$order($command)' - The unit is not on board a ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist auf einem Schiff." - "$unit($unit) in $region($region): '$order($command)' - The unit is on board a ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat zuwenig Silber, um zu rekrutieren." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough silver for recruiting." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht mehr genug Kristalle für so viele Personen." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough crystals left for this many people." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit befindet sich weder in einer Burg noch auf einem Schiff." - "$unit($unit) in $region($region): '$order($command)' - The unit is neither in a castle nor on board a ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Unterschiedliche Typen können nicht gemischt werden." - "$unit($unit) in $region($region): '$order($command)' - Different types do not mix." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Uns gehört nichts, was man abreißen oder versenken könnte." - "$unit($unit) in $region($region): '$order($command)' - We do not have anything that could be demolished." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Unbekannter Hilfe-Modus." - "$unit($unit) in $region($region): '$order($command)' - Unknown Help- Mode." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Unbekannte Meldungs-Option." - "$unit($unit) in $region($region): '$order($command)' - Unknown Report-Option." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Um in Wüsten Straßen bauen zu können, muß zuerst eine Karawanserei errichtet werden." - "$unit($unit) in $region($region): '$order($command)' - You've got to build a caravansary before building roads through deserts." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Um in Sümpfen Straßen bauen zu können, muß zuerst ein Damm errichtet werden." - "$unit($unit) in $region($region): '$order($command)' - You've got to build a dam before building roads through swamps." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - So viele Leute kann die Partei nicht aufnehmen." - "$unit($unit) in $region($region): '$order($command)' - The faction cannot hire so many strangers." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - So viele Fremde kann die Partei nicht aufnehmen." - "$unit($unit) in $region($region): '$order($command)' - The faction cannot hire so many strangers." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - So viele Fremde kann Deine Partei nicht aufnehmen." - "$unit($unit) in $region($region): '$order($command)' - Your faction cannot hire so many strangers." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht verkaufen." - "$unit($unit) in $region($region): '$order($command)' - You cannot sell this." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht machen." - "$unit($unit) in $region($region): '$order($command)' - You cannot produce this." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht auf dem Markt kaufen." - "$unit($unit) in $region($region): '$order($command)' - You cannot buy that on a market place." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - So etwas hat die Einheit nicht." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have such a thing." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Pferde kann man nur in einer Pferdezucht züchten." - "$unit($unit) in $region($region): '$order($command)' - You can breed horses only in a stable." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - So etwas gibt es hier nicht." - "$unit($unit) in $region($region): '$order($command)' - That resource does not exist in this region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Personen können nur an Menschen übergeben werden." - "$unit($unit) in $region($region): '$order($command)' - Characters can be given only to Human parties." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Ohne einen Handelsposten gibt es keinen Markt." - "$unit($unit) in $region($region): '$order($command)' - There is no marketplace without at least a tradepost." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nur Elfen können diese Bögen herstellen." - "$unit($unit) in $region($region): '$order($command)' - Only Elves can make these bows." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nur die EMail-Adresse angeben!" - "$unit($unit) in $region($region): '$order($command)' - Submit only email-address, please!" - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nummer kann nicht vergeben werden." - "$unit($unit) in $region($region): '$order($command)' - Number can not be assigned." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nummer ist schon belegt." - "$unit($unit) in $region($region): '$order($command)' - Number is already in use." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nummer ist nicht im gültigen Bereich." - "$unit($unit) in $region($region): '$order($command)' - Number is not valid." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nichts angegeben, was wir übergeben sollen." - "$unit($unit) in $region($region): '$order($command)' - Item to be handed over was not supplied." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Namen dürfen keine Klammern enthalten." - "$unit($unit) in $region($region): '$order($command)' - Names may not contain parenthesis." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Nachricht zu lang - gekürzt." - "$unit($unit) in $region($region): '$order($command)' - Message has been cut (too long).." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Man muß angeben, ob eine Burg, ein Schiff, eine Region oder eine Einheit beschrieben werden soll." - "$unit($unit) in $region($region): '$order($command)' - Specify if description is for a castle, a ship, a region or a unit." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Man muß angeben, ob eine Burg, ein Schiff, eine Einheit, eine Region oder eine Partei benannt werden soll." - "$unit($unit) in $region($region): '$order($command)' - Specify if a castle, a ship, a region or a unit is supposed to be named." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es sind keine Kräuter zu finden." - "$unit($unit) in $region($region): '$order($command)' - No herbs could be found." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Man braucht mindestens zwei Pferde, um sie zu züchten." - "$unit($unit) in $region($region): '$order($command)' - You need at least two horses to breed more." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Magier müssen zum studieren allein sein." - "$unit($unit) in $region($region): '$order($command)' - When studying, magicians need to be alone." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Leere Einheiten können nicht übergeben werden." - "$unit($unit) in $region($region): '$order($command)' - Empty units can not be handed over." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Laen kann nur in einem Bergwerk abgebaut werden." - "$unit($unit) in $region($region): '$order($command)' - Laen can be excavated only in a mine." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Keiner hier kann Straßen bauen." - "$unit($unit) in $region($region): '$order($command)' - Nobody here can build roads." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann keine weiteren Güter handeln." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot trade any more goods." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Keiner hier kann ein Gebäude errichten." - "$unit($unit) in $region($region): '$order($command)' - Nobody here can construct a building." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Keiner hier ist gelernter Schiffbauer." - "$unit($unit) in $region($region): '$order($command)' - Nobody here is a skilled ship builder." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit will nicht transportiert werden." - "$unit($unit) in $region($region): '$order($command)' - The unit doen not want to be transported." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Insekten können im Winter nur in Wüsten rekrutiert werden." - "$unit($unit) in $region($region): '$order($command)' - In winter, insects can be recruited only in deserts." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - In Gletschern können keine Insekten rekrutiert werden." - "$unit($unit) in $region($region): '$order($command)' - Insects cannot be recruited in glaciers." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - In dieser Einheit gibt es niemanden, den man transferieren könnte." - "$unit($unit) in $region($region): '$order($command)' - Nobody in this unit can be transferred." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Illusionen können eine Region nicht bewachen." - "$unit($unit) in $region($region): '$order($command)' - Illusions cannot guard a region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier kann man keine Straße bauen." - "$unit($unit) in $region($region): '$order($command)' - You cannot build a road here." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier gibt es schon einen Hafen." - "$unit($unit) in $region($region): '$order($command)' - There is already a port in this region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier gibt es keine Bauern." - "$unit($unit) in $region($region): '$order($command)' - There are no peasants in this region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier gibt es keinen normalen Wald." - "$unit($unit) in $region($region): '$order($command)' - There is no normal forest in this region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Hier gibt es keine Mallornbäume." - "$unit($unit) in $region($region): '$order($command)' - There are no Mallorn trees here." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit fährt nicht mit uns." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have a RIDE-order." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Geldgebot fehlt." - "$unit($unit) in $region($region): '$order($command)' - Money offer is missing." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht genügend Materialien für den Schiffbau." - "$unit($unit) in $region($region): '$order($command)' - the unit is lacking materials to build the ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Für das Elixier benötigt man Drachenblut." - "$unit($unit) in $region($region): '$order($command)' - Dragon blood is required for this elixir." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Falsches Passwort." - "$unit($unit) in $region($region): '$order($command)' - Wrong password." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es wurde keine EMail-Adresse angegeben." - "$unit($unit) in $region($region): '$order($command)' - No email-address was supplied." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es wurde kein Name angegeben." - "$unit($unit) in $region($region): '$order($command)' - No name was supplied." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es konnte kein Bauer gefangen werden." - "$unit($unit) in $region($region): '$order($command)' - No peasant could be caught." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es gibt keine Abstimmung mit dieser Nummer." - "$unit($unit) in $region($region): '$order($command)' - There is no agreement with this number." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Einheit muß zuerst die Region bewachen." - "$unit($unit) in $region($region): '$order($command)' - first, the unit must guard the region." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Einheit ist nicht bewaffnet und kampffähig." - "$unit($unit) in $region($region): '$order($command)' - The unit is not armed and fighting fit." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Ein Schiff oder eine Burg muß angegeben werden." - "$unit($unit) in $region($region): '$order($command)' - A ship or a castle must be supplied." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Ein Fluch verhindert die Übergabe." - "$unit($unit) in $region($region): '$order($command)' - A curse prevented the transfer from happening." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieses Talent wurde nicht erkannt." - "$unit($unit) in $region($region): '$order($command)' - The skill could not be recognized." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieses Talent kann die Einheit nicht lernen." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot learn this skill." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diesen Gegenstand kann man nicht benutzen." - "$unit($unit) in $region($region): '$order($command)' - This item cannot be used." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit nimmt niemanden an." - "$unit($unit) in $region($region): '$order($command)' - This unit does not take anybody." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Eine hungernde Einheit kann niemanden weggeben." - "$unit($unit) in $region($region): '$order($command)' - Hungry units cannot give anybody away." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diese Einheit kann niemanden weggeben." - "$unit($unit) in $region($region): '$order($command)' - This unit cannot give anybody away." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) hat keinen Kontakt mit uns aufgenommen." - "$unit($unit) in $region($region): '$order($command)' - $unit($target) did not contact us." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es kann hier kein Kontakt zur Astralwelt aufgenommen werden." - "$unit($unit) in $region($region): '$order($command)' - There is no connection to the astral plane." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) hat keinen Kontakt mit uns aufgenommen und widersteht dem Zauber." - "$unit($unit) in $region($region): '$order($command)' - $unit($target) did not contact us, and resists the spell." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) hat keinen Kontakt mit uns aufgenommen, aber widersteht dem Zauber nicht." - "$unit($unit) in $region($region): '$order($command)' - $unit($target) did not contact us, but cannot resist the spell." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Richtung wurde nicht erkannt." - "$unit($unit) in $region($region): '$order($command)' - Direction was not recognized." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Richtung '$dirname' wurde nicht erkannt." - "$unit($unit) in $region($region): '$order($command)' - Direction '$dirname' was not recognized." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Region wird von Nichtalliierten bewacht." - "$unit($unit) in $region($region): '$order($command)' - This region is guarded by a non allied faction." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Region wird von $unit($guard), einer nichtalliierten Einheit, bewacht." - "$unit($unit) in $region($region): '$order($command)' - This region is guarded by $unit($guard), a non-allied unit." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Pferde würden ertrinken." - "$unit($unit) in $region($region): '$order($command)' - The horses would drown." - "$unit($unit) in $region($region): '$order($command)' - The horses would drown." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Partei wurde nicht gefunden." - "$unit($unit) in $region($region): '$order($command)' - The faction could not be found." - "$unit($unit) in $region($region): '$order($command)' - The faction could not be found." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Lernkosten können nicht bezahlt werden." - "$unit($unit) in $region($region): '$order($command)' - Tuition was too high to be paid." - "$unit($unit) in $region($region): '$order($command)' - Tuition was too high to be paid." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Gegenstand kann nur in der realen Welt benutzt werden." - "$unit($unit) in $region($region): '$order($command)' - This object can only be used in the real world." - "$unit($unit) in $region($region): '$order($command)' - This object can only be used in the real world." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) ist nicht ausreichend getarnt." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) is not sufficiently stealthy." - "$unit($unit) in $region($region): '$order($command)' - $unit($unit) is not sufficiently stealthy." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit wurde nicht gefunden." - "$unit($unit) in $region($region): '$order($command)' - The unit could not be found." - "$unit($unit) in $region($region): '$order($command)' - The unit could not be found." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Einheit kann nichts gegeben werden." - "$unit($unit) in $region($region): '$order($command)' - You cannot give anything to this unit." - - - - - - - - - "$unit($mage) horcht $unit($unit) über $region($tregion) aus." - "$unit($mage) questions $unit($unit) about $region($tregion)." - - - - - - - - "$unit($mage) verschafft $unit($unit) einige feuchtfröhliche Stunden mit heftigen Nachwirkungen." - "$unit($mage) invites $unit($unit) for a few too many drinks and a massive hangover." - - - - - - - "$unit($unit) hat höllische Kopfschmerzen und kann sich an die vergangene Woche nicht mehr erinnern. Nur noch daran, wie alles mit einer fröhlichen Feier in irgendeiner Taverne anfing...." - "$unit($unit) has a splitting headache and can hardly remember last week. Except that it all started in the tavern..." - - - - - - - - "$unit($mage) besänftigt $unit($unit)." - "$unit($mage) calms $unit($unit)." - - - - - - - "$unit($unit) verfiel dem Glücksspiel und hat fast sein ganzes Hab und gut verspielt." - "$unit($unit) gambles for high stakes and loses almost everything." - - - - - - - - - "$unit($unit) schenkt $unit($mage) $resources($items)." - "$unit($unit) gives $unit($mage) $resources($items)." - - - - - - - - - "$unit($mage) läßt $unit($target) als $race($race,$unit.size($target)) erscheinen." - "$unit($mage) makes $unit($target) appear as $race($race,$unit.size($target))." - - - - - - - "$unit($unit) wird kurz von einem magischen Licht umhüllt." - "$unit($unit) is briefly surrounded by a magical light." - - - - - - - - "$unit($unit) konnte nur $int($ships) von $int($maxships) Schiffen verzaubern." - "$unit($unit) could only enchant $int($ships) of $int($maxships) ships." - - - - - - "$unit($unit) beschwört einen magischen Wind, der die Schiffe über das Wasser treibt." - "$unit($unit) calls up a magical storm that whips the ship over the waters." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit weiß nichts über Botanik." - "$unit($unit) in $region($region): '$order($command)' - The unit does not know anything about herbalism." - "$unit($unit) in $region($region): '$order($command)' - The unit does not know anything about herbalism." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit weiß nicht, wie man gaukelt." - "$unit($unit) in $region($region): '$order($command)' - The unit does not know how to entertain." - "$unit($unit) in $region($region): '$order($command)' - The unit does not know how to entertain." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit trägt zuviel Gewicht, um sich bewegen zu können." - "$unit($unit) in $region($region): '$order($command)' - The unit is too heavily loaded to move." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann soviele Pferde nicht bändigen." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot tame that many horses." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann sich nicht fortbewegen." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot move." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht handeln." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot trade." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann keine Tränke herstellen." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot make potions." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann keine weiteren langen Befehle ausführen." - "$unit($unit) in $region($region): '$order($command)' - The unit is exhausted from battle." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht genug Silber." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough silver." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough silver." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht erfahren genug dafür." - "$unit($unit) in $region($region): '$order($command)' - The unit is not experienced enough to do this." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht der Eigentümer." - "$unit($unit) in $region($region): '$order($command)' - The unit is not he owner." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht bewaffnet und kampffähig." - "$unit($unit) in $region($region): '$order($command)' - The unit is not armed and fighting fit." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist mit uns alliiert." - "$unit($unit) in $region($region): '$order($command)' - This unit is one of our allies." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist in keiner Taverne." - "$unit($unit) in $region($region): '$order($command)' - The unit is not in a tavern." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist eine der unsrigen." - "$unit($unit) in $region($region): '$order($command)' - This unit is one of our own." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist auf hoher See." - "$unit($unit) in $region($region): '$order($command)' - The unit is off shore." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat soetwas nicht." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have this." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht genug Wagenlenker oder zuviel andere Fracht, um die Wagen aufzuladen." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough coachmen or too much freights to lad the wagons." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht genug Silber." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough silver." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat keinen Kontakt mit uns aufgenommen." - "$unit($unit) in $region($region): '$order($command)' - The unit did not contact us." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat keine Spionage gelernt." - "$unit($unit) in $region($region): '$order($command)' - The unit has not yet learned espionage." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat keine Kräuter." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have any herbs." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat diesen Trank nicht." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have this potion." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat diesen Gegenstand nicht." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have this item." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat diesen Gegenstand zwar, aber sämtliche $int($reservation) $resource($resource,$reservation) sind reserviert." - "$unit($unit) in $region($region): '$order($command)' - The unit has this item, but all $int($reservation) $resource($resource,$reservation) are reserved." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat diese Kräuter nicht." - "$unit($unit) in $region($region): '$order($command)' - The unit does not have these herbs." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Einheiten dürfen nicht mehr als $int($maxsize) Personen enthalten." - "$unit($unit) in $region($region): '$order($command)' - Units may not have more than $int($maxsize) members." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit darf nicht an Bord kommen, da sie das Schiff überladen würde." - "$unit($unit) in $region($region): '$order($command)' - The unit cannot go aboard, the ship would be overloaded." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit darf nicht an Bord kommen." - "$unit($unit) in $region($region): '$order($command)' - This unit has no permission to come on board." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit befindet sich nicht in unserer Burg." - "$unit($unit) in $region($region): '$order($command)' - The unit is not in our castle." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit befindet sich nicht an Bord unseres Schiffes." - "$unit($unit) in $region($region): '$order($command)' - The unit is not on board our ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Burg wurde nicht gefunden." - "$unit($unit) in $region($region): '$order($command)' - The castle could not be found." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Botschaft enthält keinen Text." - "$unit($unit) in $region($region): '$order($command)' - The message does not contain text." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Bauern sind schlecht gelaunt." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Anzahl zu verkaufender Produkte fehlt." - "$unit($unit) in $region($region): '$order($command)' - The amount of items for sale is missing." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Anzahl zu kaufender Produkte fehlt." - "$unit($unit) in $region($region): '$order($command)' - The amount of items to buy is missing." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Fluch verhindert das." - "$unit($unit) in $region($region): '$order($command)' - The escape prevented that from happening." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Belagerungszustand macht Spionage unmöglich." - "$unit($unit) in $region($region): '$order($command)' - Espionage was not possible due to siege." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Belagerungszustand macht die Kontaktaufnahme unmöglich." - "$unit($unit) in $region($region): '$order($command)' - Contact was not possible due to siege." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Befehl wurde nicht erkannt." - "$unit($unit) in $region($region): '$order($command)' - Unknown command." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dazu gibt es keine Informationen." - "$unit($unit) in $region($region): '$order($command)' - There is no information available for the request." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff wurde nicht gefunden." - "$unit($unit) in $region($region): '$order($command)' - The ship could not be found." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff muß erst verlassen werden." - "$unit($unit) in $region($region): '$order($command)' - First you have to leave the ship." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff ist zu schwer beladen, um in See zu stechen." - "$unit($unit) in $region($region): '$order($command)' - The ship is too heavily loaded to sail." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $ship($ship) ist zu groß, um fliegen zu können." - "$unit($unit) in $region($region): '$order($command)' - $ship($ship) is too bulky to fly." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff ist schon fertig." - "$unit($unit) in $region($region): '$order($command)' - The ship is already completed." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff ist noch nicht fertig gebaut." - "$unit($unit) in $region($region): '$order($command)' - The ship has not yet been completed." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff ist auf hoher See." - "$unit($unit) in $region($region): '$order($command)' - The ship is off shore." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff hat sich bereits bewegt." - "$unit($unit) in $region($region): '$order($command)' - The ship has moved already." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Besitzer muss das Gebäude zuerst verlassen." - "$unit($unit) in $region($region): '$order($command)' - The owner must first LEAVE the building." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff gehört uns nicht." - "$unit($unit) in $region($region): '$order($command)' - The ship is not ours." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Gebäude gehört uns nicht." - "$unit($unit) in $region($region): '$order($command)' - The building is not ours." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Schiff befindet sich auf hoher See." - "$unit($unit) in $region($region): '$order($command)' - The ship is still off shore." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das macht wenig Sinn." - "$unit($unit) in $region($region): '$order($command)' - That does not make much sense." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das kann man nicht sabotieren." - "$unit($unit) in $region($region): '$order($command)' - That cannot be sabotaged." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das ist sinnlos." - "$unit($unit) in $region($region): '$order($command)' - That is useless." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das geht nicht mehr." - "$unit($unit) in $region($region): '$order($command)' - This is no longer possible." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Gebäude wurde nicht gefunden." - "$unit($unit) in $region($region): '$order($command)' - Building could not be found." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Gebäude gehört uns nicht." - "$unit($unit) in $region($region): '$order($command)' - The building is not ours." - "$unit($unit) in $region($region): '$order($command)' - The building is not ours." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Das Gebäude ist bereits fertig." - "$unit($unit) in $region($region): '$order($command)' - The building is already completed." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht unterrichtet werden." - "$unit($unit) in $region($region): '$order($command)' - this unit cannot be taught." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Beschreibung zu lang - gekürzt." - "$unit($unit) in $region($region): '$order($command)' - Description has been cut (too long)." - "$unit($unit) in $region($region): '$order($command)' - Description has been cut (too long)." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Auf hoher See kann man nicht bewachen." - "$unit($unit) in $region($region): '$order($command)' - You cannot guard off shore." - "$unit($unit) in $region($region): '$order($command)' - You cannot guard off shore." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Auf dem Schiff befinden sich zuwenig erfahrene Seeleute." - "$unit($unit) in $region($region): '$order($command)' - There are not enough experienced sailors on board the ship." - "$unit($unit) in $region($region): '$order($command)' - There are not enough experienced sailors on board the ship." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - ${error}." - "$unit($unit) in $region($region): '$order($command)' - ${error}." - - - - - - - "$unit($unit) benutzt ein $resource($item,1)." - "$unit($unit) uses a $resource($item,1)." - "$unit($unit) uses a $resource($item,1)." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $resource($item,0) können nur von Ein-Personen Einheiten benutzt werden." - "$unit($unit) in $region($region): '$order($command)' - $resource($item,0) can only be used by single-person units." - "$unit($unit) in $region($region): '$order($command)' - $resource($item,0) can only be used by single-person units." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist noch zu erschöpft vom Einmarsch um zu attackieren." - "'$order($command)' - $unit($unit) marched into $region($region) during the last turn and is too exhausted to attack." - "'$order($command)' - $unit($unit) marched into $region($region) during the last turn and is too exhausted to attack." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) sind friedliebend und attackieren niemand." - "'$order($command)' - $race($race,0) are peace-loving and will not attack anyone." - "'$order($command)' - $race($race,0) are peace-loving and will not attack anyone." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit steht nicht im benötigten Gebäude, $localize($building)." - "$unit($unit) in $region($region): '$order($command)' - The unit must be in a $localize($building) to produce this." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dazu braucht man das Talent $skill($skill)." - "$unit($unit) in $region($region): '$order($command)' - this requires the skill $skill($skill)." - - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Man benötigt mindestens $int($minskill) $skill($skill), um $resource($product,0) zu pflanzen." - "$unit($unit) in $region($region): '$order($command)' - At least $skill($skill) $int($minskill) is needed for planting $resource($product,0)." - "$unit($unit) in $region($region): '$order($command)' - At least $skill($skill) $int($minskill) is needed for planting $resource($product,0)." - - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Man benötigt mindestens $int($minskill) $skill($skill), um $resource($product,0) zu produzieren." - "$unit($unit) in $region($region): '$order($command)' - You need at least $int($minskill) $skill($skill), to produce $resource($product,0)." - - - - - - "$string" - "$string" - - - - - - "$string" - "$string" - - - - - - "$string" - "$string" - - - - - - - - "$unit($unit) übergibt $int($amount) Person$if($eq($amount,1),"","en") an $unit($target)." - "$unit($unit) transfers $int($amount) person$if($eq($amount,1),"","s") to $unit($target)." - - - - - - - - - - "$unit($unit) übergibt $int($amount) $resource($resource,$amount) an $unit($target)." - "$unit($unit) gives $int($amount) $resource($resource,$amount) to $unit($target)." - - - - - - - - - - "$unit($target) erhält $int($amount) $resource($resource,$amount) von $unit($unit)." - "$unit($target) receives $int($amount) $resource($resource,$amount) from $unit($unit)." - - - - - - - - "$unit($unit) übergibt $int($amount) Person$if($eq($amount,1),"","en") an die Bauern." - "$unit($unit) transfers $int($amount) person$if($eq($amount,1),"","s") to the local peasants." - - - - - - - - - "$unit($unit) übergibt $int($amount) $resource($resource,$amount) an die Bauern." - "$unit($unit) gives $int($amount) $resource($resource,$amount) to the local peasants." - - - - - - - - "$unit($unit) bezahlt den Unterhalt von $building($building)." - "$unit($unit) pays the maintenance for $building($building)." - "$unit($unit) pays the maintenance for $building($building)." - - - - - - - - "$unit($unit) fehlen $resource($item,0) für den Betrieb von $building($building)." - "$unit($unit) lacks $resource($item,0) to operate $building($building)." - - - - - - - "$unit($unit) kann den Unterhalt von $building($building) nicht bezahlen." - "$unit($unit) cannot pay the maintenance for $building($building)." - "$unit($unit) cannot pay the maintenance for $building($building)." - - - - - - "Der Unterhalt von $building($building) konnte nur verspätet gezahlt werden, das Gebäude war diese Woche nicht funktionstüchtig." - "The upkeep for $building($building) was paid late, the building was not operational this week." - "The upkeep for $building($building) was paid late, the building was not operational this week." - - - - - - - - "$unit($unit) verdient am Handel in $region($region) Steuern in Höhe von $int($amount) Silber." - "$unit($unit) collected $int($amount) silver trade tax in $region($region)." - "$unit($unit) collected $int($amount) silver trade tax in $region($region)." - - - - - - - "$unit($unit) benutzt $resource($potion,1)." - "$unit($unit) uses $resource($potion,1)." - "$unit($unit) uses $resource($potion,1)." - - - - - - "Hier wütete die Pest, und $int($dead) Bauern starben." - "The region is visited by the plague and $int($dead) peasants died." - "The region is visited by the plague and $int($dead) peasants died." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Um in Gletschern Straßen bauen zu können, muß zuerst ein Tunnel errichtet werden." - "$unit($unit) in $region($region): '$order($command)' - You've got to build a tunnel before building roads through glaciers." - "$unit($unit) in $region($region): '$order($command)' - You've got to build a tunnel before building roads through glaciers." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Syntax: MAGIEGEBIET [1-5]." - "$unit($unit) in $region($region): '$order($command)' - Syntax: MAGIC SPHERE [1-5]." - "$unit($unit) in $region($region): '$order($command)' - Syntax: MAGIC SPHERE [1-5]." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Deine Partei muss mindestens $int($turns) alt sein, um etwas an andere Parteien übergeben zu können." - "$unit($unit) in $region($region): '$order($command)' - Your faction must be at least $int($turns) weeks old to give something to another faction." - "$unit($unit) in $region($region): '$order($command)' - Your faction must be at least $int($turns) weeks old to give something to another faction." - - - - - - "Bitte sende die Befehle nächste Runde ein, wenn du weiterspielen möchtest." - "Merci d'envoyer vos ordres pour le tour suivant si vous désirez continuer à jouer." - "Please send in orders for the next turn if you want to continue playing." - - - - - - - "Deine Partei ist noch $int($turns) Wochen immun gegen Angriffe." - "Votre faction est immunisée contre les agressions durant $int($turns) semaines encore." - "Your faction is immune against assaults for $int($turns) more weeks." - - - - - - - - "$faction($member) ist mit $int($votes) Stimmen aus $alliance($alliance) ausgeschlossen worden." - "$faction($member) was kicked from $alliance($alliance) by $int($votes) of the alliance's members." - "$faction($member) was kicked from $alliance($alliance) by $int($votes) of the alliance's members." - - - - - - "$alliance($alliance) scheidet aus dem Spiel aus, nachdem alle Tempel verloren gingen." - "$alliance($alliance) has to leave the game after all their temples were lost." - "$alliance($alliance) has to leave the game after all their temples were lost." - - - - - - - "$int($votes) Mitglieder von $alliance($alliance) haben versucht, Deine Partei aus der Allianz auszuschliessen." - "$int($votes) members of $alliance($alliance) tried to kick you out of the alliance." - "$int($votes) members of $alliance($alliance) tried to kick you out of the alliance." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - In dieser Regione können Pyramiden gebaut werden." - "$unit($unit) in $region($region): '$order($command)' - Pyramids may be build in this region." - "$unit($unit) in $region($region): '$order($command)' - Pyramids may be build in this region." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Auf $ship($ship) liegt beeits ein Zauber." - "$unit($unit) in $region($region): '$order($command)' - There is already a spell on $ship($ship)." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es ist zu gefährlich, diesen Zauber auf das fliegende Schiff $ship($ship) zu legen." - "$unit($unit) in $region($region): '$order($command)' - It is far too dangerous to put this spell on the flying ship $ship($ship)." - - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - In dieser Region können keine Pyramiden gebaut werden. Die nächste Pyramidenregion ist zwischen $int($mindist) und $int($maxdist) Regionen entfernt." - "$unit($unit) in $region($region): '$order($command)' - No pyramids may be build in this region. The closest region to build a pyramid in is between $int($mindist) and $int($maxdist) regions away." - "$unit($unit) in $region($region): '$order($command)' - No pyramids may be build in this region. The closest region to build a pyramid in is between $int($mindist) and $int($maxdist) regions away." - - - - - - - - "$unit($unit) kann in $region($region) nicht durch das Wurmloch reisen, da die Einheit entweder zu gross ist oder teure Talente besitzt." - "$unit($unit) cannot travel through the wormhole in $region($region) because the unit is either too big or has restricted skills." - "$unit($unit) cannot travel through the wormhole in $region($region) because the unit is either too big or has restricted skills." - - - - - - - "$unit($unit) reist durch ein Wurmloch nach $region($region)." - "$unit($unit) travels through a wormhole to $region($region)." - "$unit($unit) travels through a wormhole to $region($region)." - - - - - - "In $region($region) erscheint ein Wurmloch." - "A wormhole appears in $region($region)." - "A wormhole appears in $region($region)." - - - - - - "Das Wurmloch in $region($region) schließt sich." - "The wormhole in $region($region) disappears." - "The wormhole in $region($region) disappears." - - - - - - - "$int($amount) Krieger von $unit($unit) benutzen ihre Flammenschwerter." - "$int($amount) fighters of $unit($unit) are using their flaming sword." - - - - - - - "$int($amount) Krieger von $unit($unit) feuern ihre Katapulte ab." - "$int($amount) fighters of $unit($unit) launch their catapults." - - - - - - "Der Kampf wurde ausgelöst von ${factions}." - "The battle was initiated by ${factions}." - - - - - - "$unit($unit) konnte durch einen Heiltrank überleben." - "$unit($unit) was saved by a haling potion." - - - - - - "$unit($unit) konnte dem Gegner eine Falle stellen." - "$unit($unit) lured the enemy into an ambush." - - - - - - "$unit($unit) überrascht den Gegner." - "$unit($unit) surprises the enemies." - - - - - - - "$unit($unit) versucht $spell($spell) zu zaubern, doch der Zauber schlägt fehl!" - "$unit($unit) tries to cast $spell($spell), but the spell fails!" - - - - - "Der Kampf wurde abgebrochen, da alle Verteidiger flohen." - "The battle was aborted because all enemies escaped." - - - - - - "... in der $int($row). Kampflinie:" - "... in combat rank $int($row):" - - - - - - - "$unit($mage) zaubert $spell($spell), aber niemand war in Reichweite." - "$unit($mage) casts $spell($spell), but nobody was in range." - - - - - - "Einheiten nach dem Kampf:" - "Units after the battle:" - - - - - - "" - "" - - - - - - - - - "$unit($mage) ruft $int($amount) $race($race, $amount) zu Hilfe." - "$unit($mage) calls for the help of $int($amount) $race($race, $amount)." - - - - - - - "$unit($mage) beschwört Trugbilder herauf." - "$unit($mage) summons a mirage." - - - - - - - "$unit($mage) murmelt eine düster klingende Formel. Ein plötzlicher Tumult entsteht, der sich jedoch schnell wieder legt." - - - - - - - "$unit($mage) murmelt eine düster klingende Formel. Ein plötzlicher Tumult entsteht und bringt die Kampfaufstellung durcheinander." - - - - - - - "$unit($mage) stimmt einen seltsamen Gesang an. Ein plötzlicher Tumult entsteht, der sich jedoch schnell wieder legt." - - - - - - - "$unit($mage) stimmt einen seltsamen Gesang an. Ein plötzlicher Tumult entsteht und bringt die Kampfaufstellung durcheinander." - "$unit($mage) begins a mysterious chant. great confusion sweeps through the ranks of the enemy." - - - - - - - - "$unit($mage) läßt die Mauern von $building($building) in einem unheimlichen magischen Licht erglühen." - - - - - - - "Einheiten vor der $int($turn). Runde:" - "Units before turn $int($turn):" - - - - - - "In $region($region) findet ein Kampf statt." - "There is a battle in $region($region)." - - - - - - - - "$unit($mage) zaubert $spell($spell): $int($dead) $if($eq($dead,1),"Krieger wurde", "Krieger wurden") getötet." - "$unit($mage) casts $spell($spell): $int($dead) $if($eq($dead,1),"enemy was", "enemies were") killed." - - - - - - - - "$unit($mage) läßt die Erde in $region($region) erzittern." - "$unit($mage) shakes the earth in $region($region)." - - - - - - - - "$unit($mage) verflucht das Land in $region($region), und eine Dürreperiode beginnt." - "$unit($mage) puts a curse on the lands of $region($region) and a drought sets in." - - - - - - - "$unit($mage) erschafft einen Klon." - "$unit($mage) creates a clone." - - - - - - - - - "$unit($mage) verliert sich in die Träume von $unit($unit) und erhält einen Eindruck von $region($region)." - - - - - - - - - "$unit($mage) verschafft $unit($unit) ein schönes Nachtleben in $region($region)." - - - - - - - - "$unit($mage) sorgt für schlechten Schlaf in $region($region)." - - - - - - - - - "$unit($mage) beschwört $int($amount) $race($race,$amount)." - "$unit($mage) summons $int($amount) $race($race,$amount)." - - - - - - - - - "$unit($mage) erschafft in $region($region) eine verheerende Feuersbrunst. $int($amount) Bäume fallen den Flammen zum Opfer." - "$unit($mage) creates a flaming inferno in $region($region). $int($amount) trees fall vistim to the flames." - - - - - - - - "Mit einem Ritual bindet $unit($mage) die magischen Kräfte der Erde in die Mauern von $building($building)." - - - - - - - - "$unit($mage) weight $building($building)." - "$unit($mage) blesses $building($building)." - - - - - - - - "$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Eis schmilzt und verwandelt sich in Morast. Reißende Ströme spülen die mageren Felder weg und ersäufen Mensch und Tier. Was an Bauten nicht den Fluten zum Opfer fiel, verschlingt der Morast. Die sengende Hitze verändert die Region für immer." - - - - - - - - "$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Die Felder verdorren und Pferde verdursten. Die Hungersnot kostet vielen Bauern das Leben. Vertrocknete Bäume recken ihre kahlen Zweige in den blauen Himmel, von dem erbarmungslos die sengende Sonne brennt." - - - - - - - - "$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Die Felder verdorren und Pferde verdursten. Die Hungersnot kostet vielen Bauern das Leben. Vertrocknete Bäume recken ihre kahlen Zweige in den blauen Himmel, von dem erbarmungslos die sengende Sonne brennt. Die Dürre verändert die Region für immer." - - - - - - - - "$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Das Eis zerbricht und eine gewaltige Flutwelle verschlingt die Region." - - - - "Die Darbietungen eines fahrenden Gauklers begeistern die Leute. Die fröhliche und ausgelassene Stimmung seiner Lieder überträgt sich auf alle Zuhörer." - "A touring minstrel entertains the locals. The joyous and generous disposition of his songs prove infectious." - - - - - - - "Die Darbietungen von $unit($mage) begeistern die Leute. Die fröhliche und ausgelassene Stimmung seiner Lieder überträgt sich auf alle Zuhörer." - "$unit($mage) entertains the locals. The joyous and generous disposition of his songs prove infectious." - - - "In der Luft liegt ein wunderschönes Lied, dessen friedfertiger Stimmung sich niemand entziehen kann. Einige Leute werfen sogar ihre Waffen weg." - "A wondrous song fills the air and enchants the public. The song's peaceful melody makes several listeners drop their weapon." - - - - - - "Die Gesangskunst von $unit($mage) begeistert die Leute. Die friedfertige Stimmung des Lieds überträgt sich auf alle Zuhörer. Einige werfen ihre Waffen weg." - "The marvelous singing of $unit($mage) enchants the public. The song's peaceful melody makes several listeners drop their weapon." - - - - - - - "$unit($mage) beschwört $int($number) Dämonen aus dem Reich der Schatten." - "$unit($mage) summons $int($number) demons from the realm of shadows." - - - - - - - - "$unit($mage) zaubert $spell($spell)." - "$unit($mage) casts $spell($spell)." - - - - - - - - - - "$unit($mage) zaubert $spell($spell). $int($amount) Krieger verloren Erinnerungen, $int($dead) wurden getötet." - - - - - - - - - "$unit($mage) zaubert $spell($spell). $int($amount) Krieger verloren kurzzeitig ihr Gedächtnis." - "$unit($mage) casts $spell($spell). $int($amount) fighters are temporarily losing some of their memories." - - - - - - - - - "$unit($mage) ruft $int($amount) $race($race, 0) zu Hilfe." - - - - - - - - "$unit($unit) tötete $int($dead) Krieger." - "$unit($unit) killed $int($dead) opponents." - - - - - - - - - - "Heer $int($index)($abbrev): $int($dead) Tote, $int($fled) Geflohene, $int($survived) Überlebende." - "Army $int($index)($abbrev): $int($dead) dead, $int($fled) fled, $int($survived) survivors." - - - - - - - - "$unit($mage) in $region($region): '$order($command)' - Dieser Zauber kann nicht mit Stufenangabe gezaubert werden." - "$unit($mage) in $region($region): '$order($command)' - This spell cannot be cast with variable level." - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dorthin führt kein Weg." - "$unit($unit) in $region($region): '$order($command)' - There is no way leading there." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Zu $region($target) kann kein Kontakt hergestellt werden." - "$unit($unit) in $region($region): '$order($command)' - $region($target) could not be contacted." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit $unit($target) hat keinen Kontakt mit uns aufgenommen." - "$unit($unit) in $region($region): '$order($command)' - The unit $unit($target) did not contact us." - - - - - - - - - "Antimagie von $unit.dative($self) blockiert in $region($region) einen Zauber von $unit.dative($mage)." - "In $region($region), anti-magic from $unit($self) blocks the spell of $unit($mage)." - - - - - - - - - "$unit($self) schwächt in $region($region) einen Zauber von $unit.dative($mage) durch Antimagie ab." - "In $region($region), anti-magic from $unit($self) reduces the effect of $unit($mage)'s spell." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $int($pacified) Regionen wurden befriedet." - "$unit($unit) in $region($region): '$order($command)' - $int($pacified) regions have been pacified." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Keine Region konnte befriedet werden." - "$unit($unit) in $region($region): '$order($command)' - No region could be pacified." - - - - - - - - "$unit($unit) in $region($region) bläst das Horn des Tanzes. In der ganzen Region breitet sich eine friedliche Feststimmmung aus." - "$unit($unit) in $region($region) blows the Horn of Dancing. Peaceful harmony spreads over the region." - - - - - - - - "$unit($unit) in $region($region) bläst das Horn des Tanzes, doch niemand hier lässt sich von Stimmung anstecken." - "$unit($unit) in $region($region) blows the Horn of Dancing, but nobody here gets into the mood." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die $ship($ship) wird jetzt schneller ihr Ziel erreichen." - "$unit($unit) in $region($region): '$order($command)' - The $ship($ship) will now be faster." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Magier fühlt sich durch den Trank magische gestärkt." - "$unit($unit) in $region($region): '$order($command)' - The mage is magically invigorated." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Ausser sich vor Furcht geben die Bauern dem Barden $int($money) Silber." - "$unit($unit) in $region($region): '$order($command)' - Stricken with fear the peasants give the bard $int($money) silver." - - - - - - - - "$unit($unit) spielt einen Dudelsack. Ausser sich vor Furcht geben die Bauern $int($money) Silber." - "$unit($unit) plays the bagpipe. Stricken with fear the peasants give $int($money) silver." - - - - - - - - "$unit($unit) in $region($region) erschafft eine Akademie der Künste." - "$unit($unit) in $region($region) creates an academy of arts." - - - - - - - - "$unit($unit) in $region($region) erschafft eine Skulptur." - "$unit($unit) in $region($region) creates a sculpture." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Region ist zu weit entfernt." - "$unit($unit) in $region($region): '$order($command)' - That region is too far away." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Wege aus dieser Region sind blockiert." - "$unit($unit) in $region($region): '$order($command)' - The connections from to this regions are blocked." - - - - - - - "$unit($unit) erscheint plötzlich." - "$unit($unit) appears." - - - - - - - "$unit($unit) wird durchscheinend und verschwindet." - "$unit($unit) disappears." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) ist zu schwer." - "$unit($unit) in $region($region): '$order($command)' - $unit($target) is too heavy." - - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Partei hat bereits $int($count) von $int($max) Helden." - "$unit($unit) in $region($region): '$order($command)' - The faction already has $int($count) of $int($max) heroes." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können keine Helden erwählen." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot be heroes." - - - - - - - - "$unit($unit) wird mit $int($cost) Silber zum Helden ernannt." - "$unit($unit) uses $int($cost) silber for a promotion." - - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nur $int($have) von $int($cost) benötigtem Silber." - "$unit($unit) in $region($region): '$order($command)' - The unit has $int($have) of $int($cost) silver required." - - - - - - - "Eine gewaltige Flutwelle verschlingt $region($region) und alle Bewohner." - "A tidal wave wipes out $region($region) and all who lived there." - - - - - - - - "Eine gewaltige Flutwelle verschlingt $unit($unit) in $region($region)." - "A tidal wave wipes out $region($region) and kills $unit($unit)." - - - - - - - - "$unit($unit) reaktiviert den astralen Schutzschild in $region($region)." - "$unit($unit) reactivates the astral protection shield in $region($region)." - - - - - - - - - - "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"kehrte auf seine", "kehrten auf ihre") Felder zurück." - "$unit($unit) in $region($region): $int($number) $race($race,$number) returned to the fields." - - - - - - - - - - "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"wurde zum Baum", "wurden zu Bäumen")." - "$unit($unit) in $region($region): $int($number) $race($race,$number) turned into $if($eq($number,1),"a tree", "trees")." - - - - - - - - - - "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"verfaulte", "verfaulten")." - "$unit($unit) in $region($region): $int($number) $race($race,$number) whithered and died." - - - - - - - - - - "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"zerfiel", "zerfielen") zu Staub." - "$unit($unit) in $region($region): $int($number) $race($race,$number) turned to dust." - - - - - - - - - - "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"verschwand", "verschwanden") über Nacht." - "$unit($unit) in $region($region): $int($number) $race($race,$number) disappearedin the night." - - - - - - - - - "Der Waldbrand in $region($region) griff auch auf $region($next) über, und $int($trees) verbrannten." - "The fire in $region($region) spread to $region($next) and $int($trees) were burnt." - - - - - - - - "$unit($mage) ruft in $region($region) eine Pest hervor." - "$unit($mage) sends the plague on $region($region)." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Eine Partei darf nicht aus mehr als $int($allowed) Einheiten bestehen." - "$unit($unit) in $region($region): '$order($command)' - A faction may not consist of more than $int($allowed) units." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Eine Allianz darf aus nicht mehr als $int($allowed) Einheiten bestehen." - "$unit($unit) in $region($region): '$order($command)' - An alliance may not consist of more than $int($allowed) units." - - - - - - - - - - "$unit($unit) in $region($region): $int($amount) $resource($item,$amount) zerfallen zu Staub." - "$unit($unit) in $region($region): $int($amount) $resource($item,$amount) turn to dust." - - - - - - - - - "Die $ship($ship) ist mit gutem Wind gesegnet$if($lt($duration,3),", doch der Zauber beginnt sich bereits aufzulösen",""). ($int36($id))" - "The $ship($ship) is blessed with favourable winds$if($lt($duration,3),", but the spell is starting to wear thin",""). ($int36($id))" - - - - - - - "Kräftige Stürme haben dieses Schiff in die Luft gehoben. ($int36($id))" - "Powerful storms have lifted this ship high into the air. ($int36($id))" - - - - - - - "Mächtige Magie verhindert den Kontakt zur Realität. ($int36($id))" - "Powerful magic disrupts our contact with reality. ($int36($id))" - - - - - - - - "Ein silberner Schimmer umgibt die $ship($ship). ($int36($id))" - "A silvery shimmer surrounds the $ship($ship). ($int36($id))" - - - - - - - - "Auf den Mauern von $building($building) erkennt man seltsame Runen. ($int36($id))" - "The walls of $building($building) are inscribed with strange runes. ($int36($id))" - - - - - - - - - "$unit($mage) erschafft $int($number) $resource($item,$number)." - "$unit($mage) creates $int($number) $resource($item,$number)." - - - - - - - - "Auf den Planken von $ship($ship) erkennt man seltsame Runen. ($int36($id))" - "The plank of $ship($ship) are inscribed with strange runes. ($int36($id))" - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Kompassnadel springt wild hin und her und es lässt sich keine Richtung erkennen." - "$unit($unit) in $region($region): '$order($command)' - The needle jumps wildly and there is no specific direction recognizable." - "$unit($unit) in $region($region): '$order($command)' - The needle jumps wildly and there is no specific direction recognizable." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Die Kompassnadel zeigt nach $direction($dir)." - "$unit($unit) in $region($region): '$order($command)' - The needle points $direction($dir)." - "$unit($unit) in $region($region): '$order($command)' - The needle points $direction($dir)." - - - - - - - - "$unit($unit) wird aus der astralen Ebene nach $region($region) geschleudert." - "$unit($unit) is sent from the astral plain to $region($region)." - "$unit($unit) is sent from the astral plain to $region($region)." - - - - - - - - "$unit($target) wird von $unit($unit) in eine andere Welt geschleudert." - "$unit($unit) sends $unit($target) to another world." - "$unit($unit) sends $unit($target) to another world." - - - - - - - - "$unit($unit) versuchte erfolglos, $unit($target) in eine andere Welt zu schleudern." - "$unit($unit) tried but failed to send $unit($target) to another world." - "$unit($unit) tried but failed to send $unit($target) to another world." - - - - - - - "NUMMER PARTEI $int36($id): Die Partei kann nicht mehr als einmal ihre Nummer wecheln." - "NUMBER FACTION $int36($id): Your faction can only change its number once." - - - - - - - "NUMMER PARTEI $int36($id): Diese Nummer wird von einer anderen Partei benutzt." - "NUMBER FACTION $int36($id): This number is being used by another faction." - - - - - - - - "Eine Botschaft von $unit($unit): '$message'" - "A message from $unit($unit): '$message'" - - - - - - - - "Plötzlich stolpert $unit($unit) über einige $localize($name). Nach kurzem Zögern entschließen die $localize($name), sich Deiner Partei anzuschließen." - - - - - - - "$unit($unit) entdeckt ein kleines Dorf. Die meisten Häuser wurden durch einen über die Ufer getretenen Fluß zerstört. Eine Gruppe der verzweifelten Menschen schließt sich deiner Partei an." - "$unit($unit) discovers a small village. Most of the houses have been destroyed by flooding, and a group of the distressed villagers join your faction." - - - - "Ein Bauernmob erhebt sich und macht Jagd auf Schwarzmagier." - "An angry mob forms and hunts practitioners of the dark arts." - - - - - - - "Vertrauter von $unit($unit)" - "Familiar of $unit($unit)" - - - - - - - - - "$unit($unit) rekrutiert $int($amount) $localize($archetype)." - "$unit($unit) recruits $int($amount) $localize($archetype)." - - - - - - - "Dein Passwort enthält Zeichen, die bei der Nachsendung von Reports Probleme bereiten können. Bitte beachte, dass Passwortenur aus Buchstaben von A bis Z und Zahlen bestehen dürfen. Dein neues Passwort ist '${newpass}'." - "Your password was changed because it contained illegal characters. Legal passwords may only contain numbers and letters from A to Z. Your new Password is '${newpass}'." - - - - "Miiauuuuuu..." - "Meeoooooow..." - - - - - - - "Die Götter segnen $unit($unit) mit der richtigen Rasse." - "The gods are blessing $unit($unit) with the correct race." - - - - - - - "Der Versuch, die Greifenschwingen zu benutzen, schlug fehl. $unit($unit) konnte die Ebene der Herausforderung nicht verlassen." - - - - - - - "$unit($unit) springt in die ewigen Feuer des Kraters." - - - - - - - - "$unit($unit) springt in die ewigen Feuer des Kraters." - - - - - - - - "In $region($region) erklingt die Stimme des Torwächters: 'Nur wer ohne materielle Güter und noch lernbegierig ist, der darf die Ebene der Herausforderung betreten. Und vergiß nicht mein Trinkgeld.'. $unit($unit) erhielt keinen Einlaß." - - - - - - - - "In $region($region) öffnet sich ein Portal. Eine Stimme ertönt, und spricht: 'Willkommen in der Ebene der Herausforderung'. $unit($unit) durchschreitet das Tor zu einer anderen Welt." - - - - - - - "$unit($unit) scheint von einer seltsamen Krankheit befallen." - "$unit($unit) is stricken by a strange disease." - - - - - - - - - "$unit($unit) erbeutet $int($amount) $resource($item,$amount)." - "$unit($unit) collects $int($amount) $resource($item,$amount)." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es ist so schön friedlich, man möchte hier niemanden angreifen." - "$unit($unit) in $region($region): '$order($command)' - It's so quiet and peaceful, nobody wants to attack anybody right now." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können nichts lernen." - "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot study." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Migranten können keine kostenpflichtigen Talente lernen." - "$unit($unit) in $region($region): '$order($command)' - Migrants cannot study this." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es kann maximal $int($amount) Magier pro Partei geben." - "$unit($unit) in $region($region): '$order($command)' - There may not be more tha $int($amount) magicians in your faction." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Es kann maximal $int($amount) Alchemisten pro Partei geben." - "$unit($unit) in $region($region): '$order($command)' - There may not be more tha $int($amount) alchemists in your faction." - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - $unit($target) versteht unsere Art von Magie nicht." - "$unit($unit) in $region($region): '$order($command)' - $unit($target) does not understand our kind of magic." - - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Der Kapitän muß ein Segeltalent von mindestens $int($value) haben, um $ship($ship) zu befehligen." - "$unit($unit) in $region($region): '$order($command)' - The captain needs a sailing skill of at least $int($value), to command $ship($ship)." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - In dieser Region gibt es keine Brücken und Straßen mehr zu bauen." - "$unit($unit) in $region($region): '$order($command)' - the roads and bridges in this region are complete." - - - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Um $localize($name) zu bauen, braucht man ein Talent von mindestens $int($value)." - "$unit($unit) in $region($region): '$order($command)' - To build $localize($name) requires a skill of at least $int($value)." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Diese Einheit kämpft nicht." - "$unit($unit) in $region($region): '$order($command)' - This unit will not fight." - - - - - - - - - "$unit($unit) erhielt $resources($items) von der $ship($ship)." - "$unit($unit) received $resources($items) from the $ship($ship)." - - - - - - - - - "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nciht auf Untote gezaubert werden." - - - - - - - - "Achtung: $faction($faction) hat seit $int($turns) Wochen keine - Züge eingeschickt und könnte dadurch in Kürze aus dem Spiel - ausscheiden." - "Warning: $faction($faction) has not been sending in - orders for $int($turns) turns and may be leaving the game soon." - - - + + + + + + + Ein Alp starb in $region($region), ohne sein Ziel zu erreichen. + An alp died in $region($region) before reaching its target. + + + + + + "Einheiten können die folgenden Gegenstände beanspruchen: $resources($items)" + "Units can claim the following items: $resources($items)" + + + + + + + + "$if($isnull($region),"Es","In $region($region)") wurde$if($eq($number,1),"","n") $int($number) $race($race,$number) gesichtet." + "$if($isnull($region),"","In $region($region), ")$int($number) $race($race,$number) were discovered." + + + + + + + "$unit($mage) läßt einen Teil seiner selbst in die Erde fliessen. Die Bäume, die Transformation überlebt haben, erscheinen nun viel kräftiger." + "The power of $unit($mage) flows into the region and the trees which survived the spell appear stronger now." + "The power of $unit($mage) flows into the region and the trees which survived the spell appear stronger now." + + + + + + + "$unit($mage) beschwört einen Luftgeist, der die $ship($ship) in die Wolken hebt." + "$unit($mage) summons a wind spirit that lifts the $ship($ship) into the clouds." + + + + + + "$unit($mage) beschwört einen Schleier der Verwirrung." + "$unit($mage) summons a fog of confusion." + + + + + Eine Feuerwand blockiert die Ein- und Ausreise. ($int36($id)) + + + + + Der Magier besitzt die Gabe des Chaos. ($int36($id)) + The magician possesses the gift of Chaos. ($int36($id)) + + + + Dieser mächtige Bann scheint die Einheit ihres freien Willens zu berauben. Solange der Zauber wirkt, wird sie nur den Befehlen ihres neuen Herrn gehorchen. ($int36($id)) + + + + Dieser Beeinflussungszauber scheint die Einheit einem ganz bestimmten Volk wohlgesonnen zu machen. ($int36($id)) + + + + Dieser Zauber verursacht einen gigantischen magischen Strudel. Der Mahlstrom wird alle Schiffe, die in seinen Sog geraten, schwer beschädigen. ($int36($id)) + + + + Heilung ist in dieser Region magisch beeinflusst. ($int36($id)) + + + + Dieses Schiff hat sich verfahren. ($int36($id)) + + + + + + + + "$unit($unit) ist im Traum eine Fee erschienen. ($int36($id))" + "In a dream, a fairy appears to $unit($unit). ($int36($id))" + + + + + + + "$unit($unit) wird von bösen Alpträumen geplagt. ($int36($id))" + "$unit($unit) is haunted by terrbile nightmares. ($int36($id))" + + + + + + + "$unit($unit) wird von einem glitzernden Funkenregen umgeben. ($int36($id))" + "$unit($unit) is surrounded by a shower of glittering sparkles. ($int36($id))" + + + + + + + "Ein schimmernder Lichterkranz umgibt $unit($unit). ($int36($id))" + "A circle of shimmering lights surrounds $unit($unit). ($int36($id))" + + + + + + + "Eine Melodie erklingt, und $unit($unit) tanzt bis spät in die Nacht hinein. ($int36($id))" + "A haunting melody fills the air, and $unit($unit) dances until late into the night. ($int36($id))" + + + + + + + "$unit($unit) findet eine kleine Flöte, die eine wundersame Melodie spielt. ($int36($id))" + "$unit($unit) finds a small flute that plays a beautiful melody. ($int36($id))" + + + + + + + "Die Frauen des nahegelegenen Dorfes bewundern $unit($unit) verstohlen. ($int36($id))" + "The women of the nearby village cast furtive looks at $unit($unit). ($int36($id))" + + + + + + + "Eine Gruppe vorbeiziehender Bergarbeiter rufen $unit($unit) eindeutig Zweideutiges nach. ($int36($id))" + "A group of passing miners makes passes at $unit($unit). ($int36($id))" + + + + + + + "$unit($unit) bekommt von einer Schlange einen Apfel angeboten. ($int36($id))" + "A large green snake offers $unit($unit) a fine-looking apple. ($int36($id))" + + + + + + "A spell is deflecting magical energies and weakening all other spells cast in the region. ($int36($id))" + "Dieser Zauber scheint magische Energien irgendwie abzuleiten und so alle in der Region gezauberten Sprüche in ihrer Wirkung zu schwächen oder ganz zu verhindern. ($int36($id))" + + + + + + + "Ein Einhorn berührt $unit($unit) mit seinem Horn und verschwindet kurz darauf im Unterholz. ($int36($id))" + "A unicorn touches $unit($unit) with its horn and vanishes into the forest quickly after. ($int36($id))" + + + + + + + "Vogelzwitschern begleitet $unit($unit) auf all seinen Wegen. ($int36($id))" + "Bird songs follow $unit($unit) on all his travels. ($int36($id))" + + + + + + + "Leuchtende Blumen erblühen rund um das Lager von $unit($unit). ($int36($id))" + "Brightly coloured flowers pop up all around $unit($unit)'s camp. ($int36($id))" + + + + + + + "Über $unit($unit) zieht eine Gruppe Geier ihre Kreise. ($int36($id))" + "A group of vultures circles above $unit($unit). ($int36($id))" + + + + + + + "Der Kopf von $unit($unit) hat sich in einen grinsenden Totenschädel verwandelt. ($int36($id))" + "The head of $unit($unit) has turned into a madly grinning skull. ($int36($id))" + + + + + + + "Ratten folgen $unit($unit) auf Schritt und Tritt. ($int36($id))" + "Rats follow $unit($unit)'s every step. ($int36($id))" + + + + + + + "Pestbeulen befallen den Körper von $unit($unit). ($int36($id))" + "The body of $unit($unit) is disfigured by hideous boils. ($int36($id))" + + + + + + + "Eine dunkle Fee erscheint $unit($unit) im Schlaf. Sie ist von schauriger Schönheit. ($int36($id))" + "A dark and mysterious fairy appears before $unit($unit). She is of bewitching beauty. ($int36($id))" + + + + + + + "Fäulnisgeruch dringt $unit($unit) aus allen Körperöffnungen. ($int36($id))" + "The stench of decay is poring from all the orifices of $unit($unit). ($int36($id))" + + + + + + + + "$unit($unit) mag $faction($faction) zu mögen. ($int36($id))" + "$unit($unit) likes $faction($faction). ($int36($id))" + + + + + + + + "$unit($unit) scheint $race($race, 0) zu mögen. ($int36($id))" + "$unit($unit) seems to like $race($race, 0). ($int36($id))" + + + + + + + + "$unit($unit) ist ungewöhnlich ungeschickt in $skill($skill). ($int36($id))" + "$unit($unit) has some troubles with $skill($skill). ($int36($id))" + + + + + + + + "$unit($unit) ist ungewöhnlich geschickt in $skill($skill). ($int36($id))" + "$unit($unit) is incredibly skilled at $skill($skill). ($int36($id))" + + + + + + + + "$unit($unit) wird noch $int($duration) $if($eq($duration,1), "Woche", "Wochen") unter unserem Bann stehen. ($int36($id))" + "$unit($unit) will be under our influence for $int($duration) more $if($eq($duration,1), "week", "weeks"). ($int36($id))" + + + + + + + + + "$int($number) $if($eq($number,1), "Person", "Personen") von $unit($unit) $if($eq($number,1), "ist", "sind") noch $int($duration) $if($eq($duration,1), "Woche", "Wochen") beschleunigt. ($int36($id))" + "$int($number) $if($eq($number,1), "member", "members") of $unit($unit) $if($eq($number,1), "is", "are") accelerated for $int($duration) more $if($eq($duration,1), "week", "weeks"). ($int36($id))" + + + + + + + + "$int($number) $if($eq($number,1), "Person", "Personen") von $unit($unit) $if($eq($number,1), "fühlt", "fühlen") sich vor Kälte geschützt. ($int36($id))" + "$int($number) $if($eq($number,1), "member", "members") of $unit($unit) $if($eq($number,1), "is", "are") protected from the cold. ($int36($id))" + + + + + + "Ein unbekannter Zauber liegt auf dem Schiff. ($int36($id))" + "An unknown spell lies on this ship. ($int36($id))" + + + + + + "Ein unbekannter Zauber liegt auf der Einheit. ($int36($id))" + "An unknown spell lies on this unit. ($int36($id))" + + + + + + "Ein unbekannter Zauber liegt auf dem Gebäude. ($int36($id))" + "An unknown spell lies on this building. ($int36($id))" + + + + + + "Ein unbekannter Zauber liegt auf der Region. ($int36($id))" + "An unknown spell lies on this region. ($int36($id))" + + + + + + "Eine Wolke negativer Energie liegt über der Region. ($int36($id))" + "A fog of negative energy enshrouds the region. ($int36($id))" + "A fog of negative energy enshrouds the region. ($int36($id))" + + + + + + "Die Leute strotzen nur so vor Kraft. ($int36($id))" + "Testosterone levels are at an all-time high. ($int36($id))" + + + + + + + "$unit($unit) wird von einem Alp geritten. ($int36($id))" + "$unit($unit) is chased by a nightmare. ($int36($id))" + + + + + + + "$unit($unit) stürzt sich von einem amourösen Abenteuer ins nächste. ($int36($id))" + "$unit($unit) goes from one amourous adventure to another. ($int36($id))" + "$unit($unit) goes from one amourous adventure to another. ($int36($id))" + + + + + + + "$unit($unit) kann sich kaum konzentrieren. ($int36($id))" + "$unit($unit) can hardly focus on anything. ($int36($id))" + "$unit($unit) can hardly focus on anything. ($int36($id))" + + + + + + + "Die Ausrüstung von $unit($unit) scheint unsichtbar. ($int36($id))" + "$unit($unit)'s equipment is invisible. ($int36($id))" + "$unit($unit)'s equipment is invisible. ($int36($id))" + + + + + + "Die natürliche Widerstandskraft gegen Verzauberung ist gestärkt. ($int36($id))" + "($int36($id))" + "The magical resistance has been strengthened. ($int36($id))" + + + + + + "Die natürliche Widerstandskraft gegen Verzauberung bestimmter Einheiten in dieser Region wurde gestärkt. ($int36($id))" + "($int36($id))" + "The magical resistance of some units in this region was boosted. ($int36($id))" + + + + + + "Die natürliche Widerstandskraft gegen Verzauberung bestimmter Einheiten in dieser Region wurde geschwächt. ($int36($id))" + "The magical resistance of some units in this region was weakened. ($int36($id))" + "($int36($id))" + + + + + + "Diese Mauern wirken, als wären sie direkt aus der Erde gewachsen und nicht erbaut. ($int36($id))" + "These walls appear to have grown straight out of the earth. ($int36($id))" + "($int36($id))" + + + + + + "Ein magischer Schimmer liegt auf diesen Mauern. ($int36($id))" + "A magical shimmer lies on these walls. ($int36($id))" + "($int36($id))" + + + + + + "Die Straßen sind erstaunlich trocken und gut begehbar, doch an manchen Stellen bilden sich wieder die erste Schlammlöcher. ($int36($id))" + "The roads are extremely dry and well-kept, but some areas show the first signs of potholes reappearing. ($int36($id))" + "($int36($id))" + + + + + + "Die Straßen sind erstaunlich trocken und gut begehbar. ($int36($id))" + "The roads are extremely dry and well-kept. ($int36($id))" + "($int36($id))" + + + + + + "Albträume plagen die Leute. ($int36($id))" + "Nightmares plague the population. ($int36($id))" + "($int36($id))" + + + + + + "Die Leute haben schöne Träume. ($int36($id))" + "($int36($id))" + "The people in this region have sweet dreams. ($int36($id))" + + + + + + "Diese Region wurde von den Göttern verflucht. Das Meer ist eine ekelige Brühe, braunschwarze, stinkende Gase steigen aus den unergründlichen Tiefen hervor, und untote Seeungeheuer, Schiffe zerfressend und giftige grüne Galle geifernd, sind der Schrecken aller Seeleute, die diese Gewässer durchqueren. Niemand kann hier lange überleben. ($int36($id))" + "($int36($id))" + "This region was cursed by the gods. The sea is a foul cesspool, noxious gases rise from the deep, undead seamonsters attack all ships. Noone can live here for long. ($int36($id))" + + + + + + "Diese Region wurde von den Göttern verflucht. Stinkende Nebel ziehen über die tote Erde und furchtbare Kreaturen ziehen über das Land. Die Brunnen sind vergiftet, und die wenigen essbaren Früchte sind von einem rosa Pilz überzogen. Niemand kann hier lange überleben. ($int36($id))" + "($int36($id))" + "This region was cursed by the gods. Noone can live here for long. ($int36($id))" + + + + + + "Ein Schleier der Verwirrung liegt über der Region. ($int36($id))" + "($int36($id))" + "A veil of confusion lies over the region. ($int36($id))" + + + + + + "In der Region treibt ein Giftelementar sein Unwesen. ($int36($id))" + "A poison elemental is spreading pestilence and death. ($int36($id))" + + + + + + "Die ganze Region ist von einer friedlichen Stimmung erfasst. ($int36($id))" + "($int36($id))" + "Everyone in this region seems to be in a peacful mood. ($int36($id))" + + + + + + "Es herrscht eine fröhliche und ausgelassene Stimmung. ($int36($id))" + "($int36($id))" + "Everyone in this region seems to be having a very good time. ($int36($id))" + + + + + + "Die Bauern sind unzufrieden. ($int36($id))" + "($int36($id))" + "The peasants are upset. ($int36($id))" + + + + + + "Alle Leute in der Region haben Schlafstörungen. ($int36($id))" + "($int36($id))" + "People in this region suffer from insomnia. ($int36($id))" + + + + + + "In dieser Gegend herrscht eine Dürre. ($int36($id))" + "($int36($id))" + "This region was hit by a drought. ($int36($id))" + + + + + + "In dieser Gegend steht das Korn besonders gut im Feld. ($int36($id))" + "($int36($id))" + "The grain in this region is especially healthy. ($int36($id))" + + + + + + "Die Winde scheinen dieses Schiff besonders zu beguenstigen. ($int36($id))" + "($int36($id))" + "The winds seem to favor this ship. ($int36($id))" + + + + + + "Untote schrecken vor dieser Region zurück. ($int36($id))" + "($int36($id))" + "The undead turn away from this region. ($int36($id))" + + + + + + "Der Zahn der Zeit kann diesen Mauern nichts anhaben. ($int36($id))" + "($int36($id))" + "Time cannot touch these walls. ($int36($id))" + + + + + + "Dichte Nebel bedecken diese Woche die Region. Keine Einheit schafft es, diese Nebel zu durchdringen und die Region zu verlassen. ($int36($id))" + "heavy fog makes it impossible to leave the region. ($int36($id))" + "heavy fog makes it impossible to leave the region. ($int36($id))" + + + + + + + "$unit($unit) setzt ein Sonnensegel. Die Geschwindigkeit des Schiffes erhöht um $int($speed)." + "$unit($unit) sets a solar sail. The ship's speed is increased by $int($speed)." + "$unit($unit) sets a solar sail. The ship's speed is increased by $int($speed)." + + + + + + "Interner Fehler: Meldung '$name' nicht definiert." + "Internal Error: Message '$name' is undefined." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Interner Fehler: Meldung '$name' nicht definiert." + "$unit($unit) in $region($region): '$order($command)' - Internal Error: Message '$name' is undefined." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier ist kein passendes Schloss." + "$unit($unit) in $region($region): '$order($command)' - No fitting lock can be found here." + "$unit($unit) in $region($region): '$order($command)' - No fitting lock can be found here." + + + + + + + + "$unit($unit) öffnet eines der Schlösser in $region($region) mit $if($eq($key,1),"dem Achatenen Schlüssel","dem Saphirnen Schlüssel")." + "$unit($unit) unlocks one of the locks in $region($region) with $if($eq($key,1),"the Agate Key","the Sapphire Key")." + "$unit($unit) unlocks one of the locks in $region($region) with $if($eq($key,1),"the Agate Key","the Sapphire Key")." + + + + + + + + "$unit($unit) verschließt eines der Schlösser in $region($region) mit $if($eq($key,1),"dem Achatenen Schlüssel","dem Saphirnen Schlüssel")." + "$unit($unit) locks one of the locks in $region($region) with $if($eq($key,1),"the Agate Key","the Sapphire Key")." + "$unit($unit) locks one of the locks in $region($region) with $if($eq($key,1),"the Agate Key","the Sapphire Key")." + + + + + + + "$unit($unit) in $region($region) verwandelt sich in ein Werwesen." + "$unit($unit) in $region($region) becomes a lycantrope." + "$unit($unit) in $region($region) becomes a lycantrope." + + + + + + + "SIEG! $if($eq($n,1), "Die Partei $winners hat", "Die Parteien $winners haben") die Siegbedingung für die erforderliche Zeit erfüllt. Das Spiel ist damit beendet." + "VICTORY! $if($eq($n,1), "The faction $winners has", "The factions $winners have") fulfilled the victory condition for the necessary time. The game is over." + "VICTORY! $if($eq($n,1), "The faction $winners has", "The factions $winners have") fulfilled the victory condition for the necessary time. The game is over." + + + + + + "Achtung: $faction($faction) hat die Siegbedingungen erfüllt und wird in $if($eq($remain,1),"einer Woche","$int($remain) Wochen") zum Sieger erklärt werden." + "Attention: $faction($faction) has fulfilled the victory condition and will be declared winner in $if($eq($remain,1),"one week","$int($remain) weeks")." + "Attention: $faction($faction) has fulfilled the victory condition and will be declared winner in $if($eq($remain,1),"one week","$int($remain) weeks")." + + + + + + + + "$unit($unit) wurde in $region($region) von einem GM gelöscht: \"$string\"." + "$unit($unit) in $region($region) was removed by a GM: \"$string\"." + "$unit($unit) in $region($region) was removed by a GM: \"$string\"." + + + + + + + + "$resource($item,1) (Gewicht: $weight($weight)): $description" + "$resource($item,1) (weight: $weight($weight)): $description" + + + + + "Ein Hauch des Lebens liegt über der Welt und alle Wesen fühlen sich frisch und erholt." + "Life itself touches the world and all beings are healed." + "Life itself touches the world and all beings are healed." + + + + + + + + "$unit($unit) hat Glück und findet einen Hort von $int($amount) $resource($item,$amount)." + "$unit($unit) luckily finds a cache of $int($amount) $resource($item,$amount)." + "$unit($unit) luckily finds a cache of $int($amount) $resource($item,$amount)." + + + + + + "$unit($unit) brennt ein großes Feuerwerk ab und Kaskaden bunter Sterne, leuchtende Wasserfälle aus Licht und strahlende Feuerdrachen erhellen den Himmel." + "A large firework is visible all over the sky." + "A large firework is visible all over the sky." + + + + + + + "In $region($region) wird ein großes Feuerwerk abgebrannt, welches noch hier zu bewundern ist. Kaskaden bunter Sterne, leuchtende Wasserfälle aus Licht und strahlende Feuerdrachen erhellen den Himmel." + "A large firework, visible all over the sky, has been started in $region($region)." + "A large firework, visible all over the sky, has been started in $region($region)." + + + + + + + "Zur Feier des Geburtstags von ${name} brennt $unit($unit) ein großes Feuerwerk ab. Kaskaden bunter Sterne, leuchtende Wasserfälle aus Licht und strahlende Feuerdrachen erhellen den Himmel." + "A large firework in honor of ${name} is visible all over the sky." + "A large firework in honor of ${name} is visible all over the sky." + + + + + + + + "Zur Feier des Geburtstags von ${name} wird in $region($region) ein großes Feuerwerk abgebrannt, welches noch hier zu bewundern ist. Kaskaden bunter Sterne, leuchtende Wasserfälle aus Licht und strahlende Feuerdrachen erhellen den Himmel." + "A large firework in honor of ${name}, visible all over the sky, has been started in $region($region)." + "A large firework in honor of ${name}, visible all over the sky, has been started in $region($region)." + + + + + + + "$int36($unit.id($unit))/$int($index) erzielt einen kritischen Treffer." + "$int36($unit.id($unit))/$int($index) does critical damage." + "$int36($unit.id($unit))/$int($index) does critical damage." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) muß mindestens 2 Stufen besser sein als $unit($student)." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) needs to be at least 2 levels better than $unit($student)." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) needs to be at least 2 levels better than $unit($student)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($student) lernt nicht." + "$unit($unit) in $region($region): '$order($command)' - $unit($student) is not learning." + "$unit($unit) in $region($region): '$order($command)' - $unit($student) is not learning." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dafür braucht die Einheit $resources($required)." + "$unit($unit) in $region($region): '$order($command)' - for this, the unit needs $resources($required)." + "$unit($unit) in $region($region): '$order($command)' - for this, the unit needs $resources($required)." + + + + + + $trailto($region) + $trailto($region) + + + + + + + "Deine Partei hat $int($units) Migranten und kann maximal $int($maxunits) Migranten aufnehmen." + "Your faction has $int($units) migrants out of a possible total of $int($maxunits)." + + + + + + + + + "Seit $int($age) Wochen Mitglied der Allianz '$name ($int36($id))', angeführt von $faction($leader)." + "Member of '$name ($int36($id))' for $int($age) weeks, led by $faction($leader)." + + + + + + + "Deine Partei hat $int($units) Helden und kann maximal $int($maxunits) Helden ernennen." + "Your faction has promoted $int($units) heroes out of a possible total of $int($maxunits)." + + + + + + + "Deine Partei hat $int($population) Personen in $int($units) Einheiten." + "Your faction has $int($population) people in $int($units) units." + + + + + + "Statistik für $region($region):" + "Statistics for $region($region):" + + + + + + "Unterhaltung: max. $int($max) Silber" + "Entertainment: max. $int($max) silver" + + + + + + "Moral der Bauern: $int($morale)" + "Peasant morale: $int($morale)" + + + + + + "Luxusgüter zum angegebenen Preis: $int($max)" + "Luxury goods at this price: $int($max)" + + + + + + "Lohn für Arbeit: $int($max) Silber" + "Worker salary: $int($max) silver" + + + + + + "Bauerneinnahmen: $int($max) Silber" + "Peasant wages: $int($max) silver" + + + + + + "Personen: $int($max)" + "People: $int($max)" + "People: $int($max)" + + + + + + "Rekruten: max. $int($max) Bauern" + "Recruits: $int($max) peasants" + "Recruits: $int($max) peasants" + + + + + + + "Deine Partei hat $int($score) Punkte. Der Durchschnitt für Parteien ähnlichen Alters ist $int($average) Punkte." + "Your faction has a score of $int($score). The average score for similar factions is $int($average)." + "Your faction has a score of $int($score). The average score for similar factions is $int($average)." + + + + + + + "Report für $game, $date" + "Report for $game, $date" + "Report for $game, $date" + + + + + + + "Im $direction($dir) der Region liegt $trailto($region)" + "To the $direction($dir) lies $trailto($region)" + + + + + + + "$resource($product,0) $int($price) Silber" + "$resource($product,0) for $int($price) silver" + "$resource($product,0) for $int($price) silver" + + + + + + + "Auf dem Markt wird für $resource($product,0) $int($price) Silber verlangt." + "Le marché local offre la $resource($product,0) au prix de $int($price) écus." + "The local market offers $resource($product,0) at a price of $int($price) silver." + + + + + + + "Auf dem Markt werden $resource($p1,0) und $resource($p2,0) feilgeboten." + "The local market offers $resource($p1,0) and $resource($p2,0)." + + + + + + "Auf dem Markt wird $resource($p1,0) feilgeboten." + "The local market offers $resource($p1,0)." + + + + + + "Dein Passwort lautet ${password}." + "Your password is ${password}." + "Your password is ${password}." + + + + + + "Die Mannschaft krank vom vergifteten Wasser, Planken, Ruder und Segel zerfressen von den Wassern des verfluchten Meeres, ergibt sich die $ship($ship) in ihr Schicksal und sinkt." + "Her sailors sick from the poisened ocean, planks, rudder und sails corroded by the waters of the cursed ocean, the $ship($ship) finally succumbs to her destiny and sinks." + + + + + + "$unit($unit) benutzt einen Talenttrunk und fühlt, wie sein Wissen zunimmt." + "$unit($unit) uses a potion of skills and feels his knowledge grow." + "$unit($unit) uses a potion of skills and feels his knowledge grow." + + + + + + + "$unit($unit) benutzt einen Astralkristall und gewinnt $int($aura) Aura hinzu." + "$unit($unit) uses an astralcrystal and gains $int($aura) aura." + "$unit($unit) uses an astralcrystal and gains $int($aura) aura." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Luxusgut wird hier nicht verkauft." + "$unit($unit) in $region($region): '$order($command)' - These goods are not on sale here." + "$unit($unit) in $region($region): '$order($command)' - These goods are not on sale here." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dazu benötigt man $resource($missing,0)." + "$unit($unit) in $region($region): '$order($command)' - This requires $resource($missing,0)." + "$unit($unit) in $region($region): '$order($command)' - This requires $resource($missing,0)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) nehmen nichts an." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) will not accept anything." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) will not accept anything." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können nicht neu gruppiert werden." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot be regrouped." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot be regrouped." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können nichts stehelen." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot steal anything." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot steal anything." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) geben nichts weg." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) do not give things away." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) do not give things away." + + + + + + + + "Eine Botschaft von $unit.dative($sender) aus $region($region): '$string'" + "A message by $unit($sender) from $region($region): '$string'" + + + + + + + + + "In $region($region) erhielt $unit($unit) eine Botschaft von $unit.dative($sender): '$string'" + "In $region($region), $unit($unit) received a message by $unit($sender): '$string'" + + + + + + + + + "In $region($region) erhielt $unit($unit) von $unit.dative($sender) $resources($items)" + "In $region($region), $unit($unit) received $resources($items) from $unit($sender)" + + + + + + "$building($building) hat diese Woche nicht funktioniert, da zu Beginn der Woche der Unterhalt nicht gezahlt werden konnte." + "$building($building) was nonfunctional because upkeep could not be paid at the beginning of the week." + + + + + + "Plötzlich löst sich $building($building) in kleine Traumwolken auf." + "$building($building) suddenly dissolves into small pink clouds." + + + + + + "Für das Gebäude $building($building) konnte die ganze Woche kein Unterhalt bezahlt werden." + "Upkeep for $building($building) could not be paid all week." + + + + + + + + + "In $region($region) stürzte $building($building) ein.$if($road," Beim Einsturz wurde die halbe Straße vernichtet.","")$if($opfer," $int($opfer) Opfer $if($eq($opfer,1),"ist","sind") zu beklagen.","")" + "$building($building) in $region($region) collapses.$if($opfer," There are $int($opfer) caualties.","")" + "$building($building) in $region($region) collapses.$if($opfer," There are $int($opfer) caualties.","")" + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In der Ebene der Herausforderung kann niemand rekrutiert werden." + "$unit($unit) in $region($region): '$order($command)' - You cannot recruit in this plane." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die einheit kann sich nicht so gut tarnen." + "$unit($unit) in $region($region): '$order($command)' -The unit cannot hide that well." + + + + + + + + "$ship($ship) was destroyed by $unit($unit)." + "$ship($ship) wurde von $unit($unit) zerstört." + + + + + + + + "$unit($unit) could not destroy $ship($ship)." + "$unit($unit) konnte $ship($ship) nicht zerstören." + + + + + + + + "$unit($unit) was detected while trying to destroy $ship($ship)." + "$unit($unit) wurde beim Versuch $ship($ship) zu zerstören entdeckt." + + + + + + + "Somebody attempted to destroy $ship($ship)." + "Es wurde versucht, $ship($ship) zu zerstören." + + + + + + + "$ship($ship) was destroyed." + "$ship($ship) wurde zerstört." + + + + + + + + + "$int($amount) Personen von $unit($unit) ertrinken.$if($isnull($region),""," Die Einheit rettet sich nach $region($region).")" + + + + + + + + "$unit($unit) ueberlebt unbeschadet und rettet sich nach $region($region)." + + + + + + + + "$ship($ship) versinkt in den Fluten von $region($region)." + + + + + + + + "$unit($unit) wurde beim versenken von $ship($ship) entdeckt." + + + + + + + + + "$unit($unit) entdeckte $unit($saboteur) beim versenken von $ship($ship)." + + + + + + + + "$unit($unit) ertrinkt in $region($region)." + "$unit($unit) drowns in in $region($region)." + + + + + + + + + "$int($amount) Personen in $unit($unit) in $region($region) ertrinken." + "$int($amount) people in $unit($unit) in $region($region) drown." + "$int($amount) people in $unit($unit) in $region($region) drown." + + + + + + + "$unit($unit) nimmt Schaden auf dem Wasser in $region($region)." + "$unit($unit) is taking damage on the water." + "$unit($unit) is taking damage on the water." + + + + + + "$unit($unit) schwenkt sein Szepter und sorgt für Verwirrung und Chaos in der Region." + + + + + + + + + "$unit($unit) stolpert bei der Erforschung der Region über $localize($location). Nähere Durchsuchung fördert ein zerfleddertes altes Buch mit dem Titel '$localize($book)' zu Tage. Der Wissensschub ist enorm." + + + + "Ein Alp hat sein Opfer gefunden und springt auf den Rücken von $unit($target)!" + + + + + + + + "$unit($unit) fühlt sich von starken magischen Energien durchströmt. ($int36($id))" + "Powerful magical energies are pulsing through $unit($unit). ($int36($id))" + + + + + + + + "$unit($unit) hat Schwierigkeiten seine magischen Energien zu sammeln. ($int36($id))" + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger sind für einen Moment benommen." + "$unit($mage) casts $spell($spell): $int($amount) fighters were momentarily stunned." + + + + + + + + "$unit($mage) besänftigt den Bauernaufstand in $region($region)." + "$unit($mage) quells the uprising in $region($region)." + + + + + + + + "$unit($mage) rief in $region($region) einen Riss in dem Gefüge der Magie hervor, der alle magische Kraft aus der Region riss." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden in Schlaf versetzt." + "$unit($mage) casts $spell($spell): $int($amount) fighters have fallen asleep." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Kriegern wurde ihre Lebenskraft entzogen." + "$unit($mage) casts $spell($spell): $int($amount) fighters had their life energy drained." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Kriegern wurden versteinert." + "$unit($mage) casts $spell($spell): $int($amount) fighters were petrified." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden in einen Blutrausch versetzt." + "$unit($mage) casts $spell($spell): $int($amount) fighters went into a mindless rage." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden eingeschüchtert." + "$unit($mage) casts $spell($spell): $int($amount) fighters were intimidated." + + + + + + + + "$unit($mage) zaubert $spell($spell), aber es gab niemanden, der beeinflusst werden konnte." + "$unit($mage) casts $spell($spell), but nobody is impressed." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden von Furcht gepackt." + "$unit($mage) casts $spell($spell): $int($amount) fighters were consumed by fear." + + + + + + + + "$unit($mage) zaubert $spell($spell): Das Kampfgetümmel erstirbt und er kann unbehelligt seines Weges ziehen." + "$unit($mage) casts $spell($spell): The noise of the battle dies down and he is able to slip away unharmed." + + + + + + + + "$unit($mage) zaubert $spell($spell): Ein Sturm kommt auf und die Schützen können kaum noch zielen." + "$unit($mage) casts $spell($spell): Strong stormwinds are blowing and the archers are having a hard time aiming." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger schleppten sich müde in den Kampf." + "$unit($mage) casts $spell($spell): $int($amount) fighters had trouble staying awake." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden moralisch gestärkt." + "$unit($mage) casts $spell($spell): $int($amount) fighters had their moral boosted." + + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($amount) Krieger wurden magisch beschleunigt." + "$unit($mage) casts $spell($spell): $int($amount) fighters were magically accelerated." + + + + + + + "$unit($mage) ruft ein fürchterliches Unwetter über seine Feinde, doch es gab niemanden mehr, den dies treffen konnte." + + + + + + + "$unit($mage) ruft ein fürchterliches Unwetter über seine Feinde, doch der magische Regen zeigt keinen Effekt." + + + + + + + "$unit($mage) ruft ein fürchterliches Unwetter über seine Feinde. Der magischen Regen lässt alles Eisen rosten." + + + + + + + + + "$unit($mage) beschwört den Alp $unit($alp) für $unit($target)." + "$unit($mage) summons the alp $unit($alp) for $unit($target)." + + + + + + + + "$unit($mage) kümmert sich um die Verletzten und heilt $int($amount) Verwundete." + "$unit($mage) sees after the wounded and heals $int($amount)." + + + + + + + + + "$unit($mage) kümmert sich um die Verletzten und benutzt ein $resource($item,1), um den Zauber zu verstärken. $int($amount) Verwundete werden geheilt." + "$unit($mage) sees after the wounded and heals $int($amount). A $resource($item,1) improves the spell." + + + + + + + + + "Mit einem Ritual bindet $unit($mage) die magischen Kräfte der Erde von $region($region) in die Mauern von $building($building)." + "$unit($mage) performs a ritual that binds the magical forces of $region($region) into the walls of $building($building)." + + + + + + + + + "$unit($mage) opfert $unit($target) $int($amount) Aura." + "$unit($mage) sacrifices $int($amount) aura for $unit($target)." + + + + + + + + "$unit($mage) beginnt ein Ritual der Wiederbelebung. $int($amount) Krieger stehen von den Toten auf." + "$unit($mage) begins a ritual of resurrection. $int($amount) warriors rise from the dead." + + + + + + + + + "$unit($mage) beginnt ein Ritual der Wiederbelebung und benutzt ein $resource($item,1), um den Zauber zu verstärken. $int($amount) Krieger stehen von den Toten auf." + "$unit($mage) begins a ritual of resurrection using a $resource($item,1). $int($amount) warriors rise from the dead." + + + + + + + "$unit($mage) öffnet ein Chaostor." + "$unit($mage) opens a chaos gate." + + + + "Ein Wirbel aus blendendem Licht erscheint." + "A vortex of blinding light appears." + + + + + + + + "$unit($mage) kann in $region($region) keine Untoten rufen." + "$unit($mage) cannot summon any undead in $region($region)." + + + + + + + + + "$unit($mage) erweckt in $region($region) $int($amount) Untote aus ihren Gräbern." + "$unit($mage) calls $int($amount) undead from their graves in $region($region)." + + + + + + + + "$unit($mage) stört in $region($region) die Ruhe der Toten." + "$unit($mage) communicates with the dead in $region($region)." + + + + + + + "$unit($unit) gelingt es, durch die Nebel auf die Realität zu blicken." + "$unit($unit) manages to catch a glimpse of reality through the fog." + + + + + + + + "$unit($mage) konnte $int($amount) $if($eq($amount,1),"Bauer","Bauern") anwerben." + "$unit($mage) managed to recruit $int($amount) $if($eq($amount,1),"peasant","peasants")." + + + + + + "Ein bohrender Schmerz durchzuckt $unit($unit), Verwirrung macht sich breit." + "Pain pulses through $unit($unit), confusion spreads." + + + + + + ""AAAAAAAGHHHHHH!" - Ein Schrei durchzieht die Region, $unit($unit) windet sich vor Schmerz." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Eine höhere Macht hindert $unit($unit) daran, das Objekt zu übergeben. 'ES IST DEINS, MEIN KIND. DEINS GANZ ALLEIN'." + + + + + + + "$unit($unit) sendet ein Stoßgebet an den Herrn der Schreie." + + + + + + + "Der Eisberg $region($region) schmilzt." + "The iceberg $region($region) melts." + "The iceberg $region($region) melts." + + + + + + "Der Gletscher von $region($region) bricht und treibt davon." + "The glacier in $region($region) breaks up and drifts away." + "The glacier in $region($region) breaks up and drifts away." + + + + + + "Der Eisberg $region($region) treibt an eine Küste." + "The iceberg $region($region) drifts onto a coast." + "The iceberg $region($region) drifts onto a coast." + + + + + + "Die $ship($ship) wird bei einer Kollision mit einem Eisberg zerstört." + "The $ship($ship) has been destroyed by a collision with an iceberg." + "The $ship($ship) has been destroyed by a collision with an iceberg." + + + + + + "Die $ship($ship) wird bei einer Kollision mit einem Eisberg beschädigt." + "The $ship($ship) has been damaged by a collision with an iceberg." + "The $ship($ship) has been damaged by a collision with an iceberg." + + + + + + + "Die $ship($ship) treibt nach $direction($dir)." + "The ship $ship($ship) drifts to the $direction($dir)." + "The ship $ship($ship) drifts to the $direction($dir)." + + + + + + + "Der Eisberg $region($region) treibt nach $direction($dir)." + "The iceberg $region($region) drifts $direction($dir)." + "The iceberg $region($region) drifts $direction($dir)." + + + + + + "Wir erklären allen $race($race,2) den heiligen Krieg." + "We declare jihad on all $race($race,2)." + + + + + + "Die Götter erhören $unit($unit)." + "The Gods have listened to $unit($unit)." + "The Gods have listened to $unit($unit)." + + + + + + + "Die Götter gewähren uns die Kraft eines $special($int($level))." + "The Gods grant us the powers of $special ($int($level))." + "The Gods grant us the powers of $special ($int($level))." + + + + + + "Die Götter gewähren uns die Kraft eines ${special}." + "The Gods grant us the powers of ${special}." + "The Gods grant us the powers of ${special}." + + + + + + + + + + "$unit($unit) verlor $int($fallen) Personen$if($alive,", $int($alive) überlebten","")$if($run," und $int($run) flohen$if($isnull($runto),""," nach $region($runto)")","")." + "$unit($unit) lost $int($fallen) people$if($alive,", $int($alive) survived","")$if($run," and $int($run) fled$if($isnull($runto),""," to $region($runto)")","")." + + + + + + + + "$unit($unit) erzielte $int($hits) Treffer und tötete $int($kills) Gegner." + "$unit($unit) hit $int($hits) times and killed $int($kills) enemies." + "$unit($unit) hit $int($hits) times and killed $int($kills) enemies." + + + + + + "$string" + "$string" + + + + + + + "Heer $int($index): $name" + "Army $int($index): $name" + + + + + + + "Verwundert blicken die Bauern von $region($region) auf ein neues Gebäude." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) gewinnt durch das Ritual $int($amount) Aura." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) receives $int($amount) aura." + + + + + + + + "$unit($mage) beschwört Naturgeister in den Boden von $region($region)." + "$unit($mage) summons natural spirits into the ground of $region($region)." + + + + + + + + + "$unit($mage) verwandelt $int($amount) aus $unit($target) in $race($race,0)." + "$unit($mage) transforms $int($amount) from $unit($target) into $race($race,0)." + + + + + + + + "$unit($mage) verwandelt $unit($target) in $race($race,0)." + "$unit($mage) tranforms $unit($target) to $race($race,0)." + + + + + + "$unit($mage) erlöst die gequälten Seelen der Toten." + "$unit($mage) redeems the tormented souls of the dead." + + + + + + "$unit($mage) verwandelt sich in einen Wyrm." + "$unit($mage) turns into a wyrm." + + + + + + + "$unit($mage) ruft Irrlichter in $region($region)." + "$unit($mage) summons wisps in $region($region)." + "$unit($mage) summons wisps in $region($region)." + + + + + + + "$unit($mage) erschafft in $region($region) eine Wand aus Feuer." + "$unit($mage) creates a wall of fire in $region($region)." + "$unit($mage) creates a wall of fire in $region($region)." + + + + + + + "$unit($mage) wiegelt in $region($region) die Bauern zum Aufstand auf." + "$unit($mage) incites a revolt among the peasants of $region($region)." + + + + + + + + + "$unit($mage) wiegelt in $region($region) $int($amount) Bauern zum Aufstand auf." + "$unit($mage) incites a revolt among $int($amount) peasants of $region($region)." + + + + + + + + "$unit($mage) sorgt in $region($region) für Trübsal unter den Bauern." + "$unit($mage) causes great sadness among the peasants of $region($region)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier erschafft ein Traumgebäude." + "$unit($unit) in $region($region): '$order($command)' - The magician creates an illusionary building." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) kann keine $race($race,1)-Gestalt annehmen." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Elementar ist zu klein, um das Gebäude zu tragen." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Elementar weigert sich, nach $direction($direction) zu gehen." + "$unit($unit) in $region($region): '$order($command)' - The elemental refuses to go $direction($direction)." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) ist von unserer Art, das Ritual wäre verschwendete Aura." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) is one of our kind, we should not waste aura on this." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) wird von uns aufgenommen." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) has become one of our kind." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) ruft Drachen nach $region($target)." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) calls dragons to $region($target)." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) erschafft $int($amount) ${object}." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) creates $int($amount) ${object}." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) creates $int($amount) ${object}." + + + + + + + + "Ein Beben erschüttert $building($building). Viele kleine Pseudopodien erheben das Gebäude und tragen es in Richtung $direction($direction)." + + + + + + + + "$unit($unit) benutzt in $region($region) ein Traumauge." + "$unit($unit) uses a dreameye in $region($region)." + + + + + + + "$unit($unit) benutzt in $region($region) einen Antimagiekristall." + "$unit($unit) uses an antimagic crystal in $region($region)." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Sphären des Chaos geben dem Magier einen Teil ihrer Kraft." + "$unit($unit) in $region($region): '$order($command)' - The sphere of chaos returns a part of his power to the magician." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier konnte keinen Fluch zerstören." + "$unit($unit) in $region($region): '$order($command)' - The magician could not destroy any magic." + + + + + + + + "In $region($region) dehnt $unit($unit) die Zeit für $int($amount) Personen." + "In $region($region), $unit($unit) bends time for $int($amount) men." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier zerstört $int($succ) Flüche auf ${target}." + "$unit($unit) in $region($region): '$order($command)' - The magician destroys $int($succ) spells on ${target}." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier zerstört den Fluch($id) auf ${target}." + "$unit($unit) in $region($region): '$order($command)' - The magician destroys the spell on ${target}." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Zauber ist nicht stark genug, um den Fluch auf ${target} zu zerstören." + "$unit($unit) in $region($region): '$order($command)' - The spell is not strong enough to destroy the curse on ${target}." + + + + + + + "$unit($mage) beschwört einen Giftelementar in $region($region)." + "$unit($mage) summons a poison elemental in $region($region)." + + + + + + + + "$unit($unit) in $region($region) wird von einem Unbekannten verflucht." + "$unit($unit) in $region($region) was cursed by an unknown magician." + + + + + + + + "$unit($mage) belegt $unit($target) mit einem Zauber." + "$unit($mage) puts a spell on $unit($target)." + + + + + + + "$unit($mage) belegt $unit($target) mit einem Kälteschutz." + "$unit($mage) puts protection from cold on $unit($target)." + + + + + + + "$unit($mage) legt einen Rosthauch auf $unit($target), doch der Rosthauch fand keine Nahrung." + "$unit($mage) puts a spell of rust on $unit($target), but it shows no effect." + + + + + + + + "$unit($mage) legt einen Rosthauch auf $unit($target). $int($amount) Waffen wurden vom Rost zerfressen." + "$unit($mage) puts a spell of rust on $unit($target). $int($amount) weapons are eaten by rust." + + + + + + + $if($isnull($mage),"Ein unentdeckter Magier",$unit($mage)) erschuf einen heiligen Hain von $int($amount) Schößlingen. + $if($isnull($mage),"An unknown magician ",$unit($mage)) created a holy forest of $int($amount) young trees. + + + + + + "$if($isnull($mage),"Ein unentdeckter Magier",$unit($mage)) segnet in einem kurzen Ritual die Felder." + "$if($isnull($mage),"an unseen magician",$unit($mage)) blesses the fields in a short ritual." + + + + + + "$unit($mage) beschwört die Mächte des Wassers und ein gigantischer Strudel bildet sich." + "$unit($mage) summons the power of the seas and a giant maelstrom forms." + + + + + + + "$unit($mage) belebt $int($amount) Bäume." + "$unit($mage) revives $int($amount) trees." + + + + + + + "$unit($mage) sorgt für trockene Straßen in $region($region)." + "$unit($mage) creates dry and well-repaired roads in $region($region)." + + + + + + + "$unit($mage) erfleht den Segen der Götter des Windes und des Wassers für $ship($ship)." + "$unit($mage) asks the gods of wind and water on behalf of the $ship($ship)." + + + + + + + + "$unit($unit) transferiert $int($aura) Aura auf $unit($target)." + "$unit($unit) transfers $int($aura) Aura to $unit($target)." + "$unit($unit) transfers $int($aura) Aura to $unit($target)." + + + + + + + + "$unit($mage) entzieht $unit($target) $int($aura) Aura." + "$unit($mage) draws $int($aura) aura from $unit($target)." + + + + + + + "$unit($unit) fühlt seine magischen Kräfte schwinden und verliert $int($aura) Aura." + "$unit($unit) feels the powers of magic fade and loses $int($aura) aura." + + + + + + "$unit($unit) fühlt sich einen Moment seltsam geschwächt." + "$unit($unit) fühlt strangely weakened." + + + + + + + "$unit($unit) konnte $unit($target) keine Aura entziehen." + "$unit($unit) could not draw aura from $unit($target)." + + + + + + + + "$unit($unit) wurde von $region($source) nach $unit($target) teleportiert." + "$unit($unit) was teleported from $region($source) to $unit($target)." + + + + + + + + + "$unit($mage) fand heraus, dass auf $ship($ship) der Zauber $curse($curse) liegt, der noch etwa $int($months) Wochen bestehen bleibt." + "$unit($mage) discovers that $ship($ship) is charmed with $curse($curse), which will last for, about $int($months) more weeks." + + + + + + + + + "$unit($mage) fand heraus, dass auf $building($building) der Zauber $curse($curse) liegt, der noch etwa $int($months) Wochen bestehen bleibt." + "$unit($mage) discovers that $building($building) is charmed with $curse($curse), which will last for, about $int($months) more weeks." + + + + + + + + + "$unit($mage) fand heraus, dass auf $unit($unit) der Zauber $curse($curse) liegt, der noch etwa $int($months) Wochen bestehen bleibt." + "$unit($mage) discovers that $unit($unit) is charmed with $curse($curse) that will last for about $int($months) more weeks." + + + + + + + + + "$unit($mage) fand heraus, dass auf $region($region) der Zauber $curse($curse) liegt, der noch etwa $int($months) Wochen bestehen bleibt." + "$unit($mage) discovers that $region($region) is charmed with $curse($curse), which will last for, about $int($months) more weeks." + + + + + + + + "$unit($mage) fand heraus, dass auf $ship($ship) der Zauber $curse($curse) liegt, dessen Kraft ausreicht, um noch Jahrhunderte bestehen zu bleiben." + "$unit($mage) discovers that $ship($ship) is charmed with $curse($curse), which will last for centuries." + + + + + + + + "$unit($mage) fand heraus, dass auf $building($building) der Zauber $curse($curse) liegt, dessen Kraft ausreicht, um noch Jahrhunderte bestehen zu bleiben." + "$unit($mage) discovers that $building($building) is charmed with $curse($curse), which will last for centuries." + + + + + + + + "$unit($mage) fand heraus, dass auf $unit($unit) der Zauber $curse($curse) liegt, dessen Kraft ausreicht, um noch Jahrhunderte bestehen zu bleiben." + "$unit($mage) discovers that $unit($unit) is charmed with $curse($curse), which will last for centuries." + + + + + + + + "$unit($mage) fand heraus, dass auf $region($region) der Zauber $curse($curse) liegt, dessen Kraft ausreicht, um noch Jahrhunderte bestehen zu bleiben." + "$unit($mage) discovers that $region($region) is charmed with $curse($curse), which will last for centuries." + + + + + + + "$unit($mage) meint, dass auf $ship($ship) ein Zauber liegt, konnte aber über den Zauber nichts herausfinden." + "It appears to $unit($mage) that $ship($ship) is charmed, but no details have been revealed." + "It appears to $unit($mage) that $ship($ship) is charmed, but no details have been revealed." + + + + + + + "$unit($mage) meint, dass auf $building($building) ein Zauber liegt, konnte aber über den Zauber nichts herausfinden." + "It appears to $unit($mage) that $building($building) is charmed, but no details have been revealed." + "It appears to $unit($mage) that $building($building) is charmed, but no details have been revealed." + + + + + + + "$unit($mage) meint, dass $unit($unit) verzaubert ist, konnte aber über den Zauber nichts herausfinden." + "It appears to $unit($mage) that $unit($unit) is charmed, but no details have been revealed." + "It appears to $unit($mage) that $unit($unit) is charmed, but no details have been revealed." + + + + + + + "$unit($mage) meint, dass auf $region($region) ein Zauber liegt, konnte aber über den Zauber nichts herausfinden." + "It appears to $unit($mage) that $region($region) is charmed, but no details have been revealed." + "It appears to $unit($mage) that $region($region) is charmed, but no details have been revealed." + + + + + + + "$unit($mage) meint, dass auf $ship($ship) kein Zauber liegt." + "It appears to $unit($mage) that $ship($ship) is not charmed." + "It appears to $unit($mage) that $ship($ship) is not charmed." + + + + + + + "$unit($mage) meint, dass auf $building($building) kein Zauber liegt." + "It appears to $unit($mage) that $building($building) is not charmed." + "It appears to $unit($mage) that $building($building) is not charmed." + + + + + + + "$unit($mage) meint, dass auf $unit($target) kein Zauber liegt." + "It appears to $unit($mage) that $unit($target) is not charmed." + "It appears to $unit($mage) that $unit($target) is not charmed." + + + + + + + "$unit($mage) meint, dass auf $region($region) kein Zauber liegt." + "It appears to $unit($mage) that $region($region) is not charmed." + "It appears to $unit($mage) that $region($region) is not charmed." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Region konnte nicht verzaubert werden." + "$unit($unit) in $region($region): '$order($command)' - The region could not be charmed." + "$unit($unit) in $region($region): '$order($command)' - The region could not be charmed." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $ship($ship) widersteht dem Zauber." + "$unit($unit) in $region($region): '$order($command)' - $ship($ship) resists the spell." + "$unit($unit) in $region($region): '$order($command)' - $ship($ship) resists the spell." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Gebäude $int36($id) konnte nicht verzaubert werden." + "$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be charmed." + "$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be charmed." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) widersteht dem Zauber." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) resists the spell." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) resists the spell." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Schiff $int36($id) wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - Ship $int36($id) could not be located." + "$unit($unit) in $region($region): '$order($command)' - Ship $int36($id) could not be located." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Gebäude $int36($id) wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be located." + "$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be located." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Einheit $id wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - Unit $id could not be located." + "$unit($unit) in $region($region): '$order($command)' - Unit $id could not be located." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es wurde kein Ziel gefunden." + "$unit($unit) in $region($region): '$order($command)' - The spell could not find a target." + + + + + + + "$unit($mage) erleidet durch den Tod seines Vertrauten einen Schock." + "$unit($mage) receives a shock when his familiar dies." + + + + + + + + "$unit($unit) schafft es nicht, genug Kraft aufzubringen, um $spell($spell) auf Stufe $int($level) zu zaubern." + "$unit($unit) cannot muster enough energy to cast $spell($spell) on level $level($level)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Für diesen Zauber fehlen noch $resources($list)." + "$unit($unit) in $region($region): '$order($command)' - Casting this spell requires an additional $resources($list)." + + + + + + + + "$unit($unit) hat nicht genügend Komponenten um $spell($spell) auf Stufe $int($level) zu zaubern." + "$unit($unit) has insufficient components to cast $spell($spell) on level $int($level)." + + + + + + + + "$unit($unit) unterläuft in $region($region) beim Zaubern von $spell($spell) ein Patzer." + "$unit($unit) fumbles while casting $spell($spell) in $region($region)." + + + + + + + + "Als $unit($unit) in $region($region) versucht, $spell($spell) zu zaubern, scheint plötzlich ein Beben durch die magische Essenz zu laufen und ein furchtbarer Sog versucht $unit($unit) in eine andere Dimension zu ziehen. Mit letzter Kraft gelingt es $unit($unit) sich zu retten." + "When $unit($unit) in $region($region) tries to cast $spell($spell), a sudden disturbance ripples through the magical realm and a terrible force attempts to drag the magician to another dimension. However, with a final effort of strength, $unit($unit) manages to save himself." + + + + + + + + "Als $unit($unit) in $region($region) versucht, $spell($spell) zu zaubern erhebt sich plötzlich ein dunkler Wind. Bizarre geisterhafte Gestalten kreisen um den Magier und scheinen sich von den magischen Energien des Zaubers zu ernähren. Mit letzter Kraft gelingt es $unit($unit) dennoch den Spruch zu zaubern." + "When $unit($unit) in $region($region) tries to cast $spell($spell), strong winds suddenly rise. Bizare ghostlike creatures circle around the magician and seem to be leeching his magical energy. However, with a final effort of strength, $unit($unit) manages to complete the spell." + + + + + + + + "Eine Botschaft von $unit.dative($unit) in $region($region): 'Ups! Quack, Quack!'" + "A message from $unit($unit) in $region($region): 'Oops! Croak, Croak!'" + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($mage) kann Zauber, die durch $unit($unit) gewirkt werden, nicht zusätzlich in die Ferne richten." + "$unit($unit) in $region($region): '$order($command)' - $unit($mage) cannot direct spells that are channeled through $unit($unit) into distant regions." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($mage) kann nicht genug Energie aufbringen, um diesen Spruch durch $unit($unit) zu wirken." + "$unit($unit) in $region($region): '$order($command)' - $unit($mage) cannot raise enough energy to channel the spell through $unit($unit)." + + + + + + + + "$unit($mage) ruft einen Vertrauten. $race($race, 0) können $skills lernen." + "$unit($mage) summons a familiar. $race($race, 0) can learn ${skills}." + + + + + + + + "$unit($unit) hat einen feuchtfröhlichen Abend in der Taverne verbracht. Ausser einem fürchterlichen Brummschädel ist da auch noch das dumme Gefühl $unit($mage) seine ganze Lebensgeschichte erzählt zu haben." + + + + + + + "$unit($unit) hat einen feuchtfröhlichen Abend in der + Taverne verbracht. Ausser einem fürchterlichen Brummschädel ist da auch + noch das dumme Gefühl die ganze Taverne mit seiner Lebensgeschichte + unterhalten zu haben." + + + + + + + + + "$unit($mage) gelingt es $unit($unit) zu verzaubern. $unit($unit) wird für etwa $int($duration) Wochen unseren Befehlen gehorchen." + + + + + + + + + "$unit($unit) gelingt es $spell($spell) zu zaubern, doch der Spruch zeigt keine Wirkung." + "$unit($unit) manages to cast $spell($spell), but the spell seems to have no effect." + + + + + + + + "$unit($unit) fühlt sich nach dem Zaubern von $spell($spell) viel erschöpfter als sonst und hat das Gefühl, dass alle weiteren Zauber deutlich mehr Kraft als normalerweise kosten werden." + "$unit($unit) feels far more exhausted than he should after casting $spell($spell) and assumes that any following spells will cost far more energy than usual." + + + + + + + "$unit($unit) in $region($region) hat rasende Kopfschmerzen und kann sich nicht mehr richtig konzentrieren. Irgendwas bei diesem Zauber ist fürchterlich schiefgelaufen." + "$unit($unit) in $region($region) is hit by a massive headacheand cannot concentrate on the spell. Some part of this ritual has gone very wrong indeed." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier verfängt sich in seinem eigenen Zauber." + + + "In der Region erstrahlen des Nachts bunte Lichter, Gloeckchen klingeln und frohes Kindergelaechter klingt durch den Wald." + "At night, colourful lights can be seen in this region, bells are a-ringing and the laughter of happy children seems to be everywhere in the forests." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Zauber von $unit.dative($unit) war viel zu schwach und löst sich gleich wieder auf." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) verzaubert ${target}." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) puts a spell on ${target}." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) gelingt es zwar die Region zu verzaubern, aber irgendwas ging schief." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) manages to put a spell on the region, but something went wrong nonetheless." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) gelingt es die Region zu verzaubern." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) puts a spell on the region." + + + + + + + "$unit($mage) erhöht die Körperkraft von $unit.dative($target) beträchtlich." + "$unit($mage) increases the strength of $unit($target) dramatically." + + + + + + + + "$unit($unit) in $region($region) regeneriert $int($amount) Aura." + "$unit($unit) régénère $int($amount) aura en $region($region)." + "$unit($unit) regenerates $int($amount) aura in $region($region)." + + + + + + "$string" + "$string" + + + + + + + + + "$unit($unit) in $region($region) verbraucht $int($cost) Silber für das Studium von $skill($skill)." + "$unit($unit) dépense $int($cost) écus en $region($region) pour apprendre $skill($skill)." + "$unit($unit) spends $int($cost) silver in $region($region) to study $skill($skill)." + + + + + + + "$unit($teacher) kann durch Dumpfbackenbrot nur $int($amount) Schüler lehren." + "Due to the effect of duncebuns, $unit($teacher) can only teach $int($amount) students." + + + + + + + + + "$unit($teacher) lehrt $unit($student) $skill($skill) auf Stufe $int($level)." + "$unit($teacher) teaches $unit($student) $skill($skill) to level $int($level)." + "$unit($teacher) teaches $unit($student) $skill($skill) to level $int($level)." + + + + + + + + "$unit($teacher) lehrt $unit($student) $skill($skill)." + "$unit($teacher) teaches $unit($student) $skill($skill)." + "$unit($teacher) teaches $unit($student) $skill($skill)." + + + + + + "$string" + "$string" + + + + + + + + "$unit($unit) verkauft $int($amount) $resource($resource,$amount)." + "$unit($unit) sells $int($amount) $resource($resource,$amount)." + "$unit($unit) sells $int($amount) $resource($resource,$amount)." + + + + + + + + "$unit($unit) kauft $int($amount) $resource($resource,$amount)." + "$unit($unit) buys $int($amount) $resource($resource,$amount)." + "$unit($unit) buys $int($amount) $resource($resource,$amount)." + + + + + + + "$unit($unit) bezahlt $int($money) Silber für den Kauf von Luxusgütern." + "$unit($unit) pays $int($money) silver for luxury items." + "$unit($unit) pays $int($money) silver for luxury items." + + + + + + + + "$unit($unit) verdient in $region($region) $int($amount) Silber durch den Verkauf von Luxusgütern." + "$unit($unit) earned $int($amount) silver in $region($region) by selling luxury items." + "$unit($unit) earned $int($amount) silver in $region($region) by selling luxury items." + + + + + + + + + "$unit($unit) arbeitet in $region($region) für einen Lohn von $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber." + "$unit($unit) works in $region($region) for a wage of $int($amount) $if($eq($wanted,$amount),""," out of $int($wanted)") silver." + "$unit($unit) works in $region($region) for a wage of $int($amount) $if($eq($wanted,$amount),""," out of $int($wanted)") silver." + + + + + + + + "$unit($unit) arbeitet in $region($region) für einen Lohn von $int($amount) Silber." + "In $region($region), $unit($unit) works for a wage of $int($amount) silver." + + + + + + + + + "$unit($unit) verdient in $region($region) $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber durch Unterhaltung." + "In $region($region), $unit($unit) earns only $int($amount) instead of$if($eq($wanted,$amount),""," of$if($eq($wanted,$amount),""," of $int($wanted)") ") with entertainment." + + + + + + + + "$unit($unit) fängt in $region($region) Fische im Wert von $int($amount) Silber." + "In $region($region), $unit($unit) catches fish worth $int($amount) silver." + + + + + + + + "$unit($unit) verdient in $region($region) $int($amount) Silber durch Unterhaltung." + "$unit($unit) earns $int($amount) in $region($region) with entertainment." + "$unit($unit) earns $int($amount) in $region($region) with entertainment." + + + + + + + + + "$unit($unit) verdient in $region($region) $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber durch Zauberei." + + + + + + + + "$unit($unit) verdient in $region($region) $int($amount) Silber durch Zauberei." + "$unit($unit) earns $int($amount) silver through simple magical services in $region($region)." + + + + + + + + + "$unit($unit) klaut in $region($region) $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber." + "$unit($unit) steals only $int($amount) silver instead of$if($eq($wanted,$amount),""," of$if($eq($wanted,$amount),""," of $int($wanted)") ") in $region($region)." + "$unit($unit) steals only $int($amount) silver instead of$if($eq($wanted,$amount),""," of$if($eq($wanted,$amount),""," of $int($wanted)") ") in $region($region)." + + + + + + + + "$unit($unit) klaut in $region($region) $int($amount) Silber." + "$unit($unit) steals $int($amount) silver in $region($region)." + + + + + + + + + "$unit($unit) treibt in $region($region) Steuern in Höhe von $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber ein." + "$unit($unit) collects taxes of only $int($amount) instead of$if($eq($wanted,$amount),""," of$if($eq($wanted,$amount),""," of $int($wanted)") ") silver in $region($region)." + + + + + + + + "$unit($unit) treibt in $region($region) Steuern in Höhe von $int($amount) Silber ein." + "$unit($unit) collects taxes of $int($amount) silver in $region($region)." + + + + + + + + + + "$unit($unit) verdient$if($eq($mode,4)," am Handel","") in $region($region) $int($amount)$if($eq($wanted,$amount),""," statt $int($wanted)") Silber$if($eq($mode,1)," durch Unterhaltung",$if($eq($mode,2)," durch Steuern",$if($eq($mode,3)," durch Handel",$if($eq($mode,5)," durch Diebstahl",$if($eq($mode,6)," durch Zauberei","")))))." + "$unit($unit) earns $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") in $region($region)." + "$unit($unit) earns $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") in $region($region)." + + + + + + + + + "$unit($unit) in $region($region) findet $int($amount) $resource($herb,$amount)." + "$unit($unit) in $region($region) finds $int($amount) $resource($herb,$amount)." + "$unit($unit) in $region($region) finds $int($amount) $resource($herb,$amount)." + + + + + + + "$unit($unit) züchtet $int($amount) Pferde." + "$unit($unit) breeds $int($amount) horses." + "$unit($unit) breeds $int($amount) horses." + + + + + + + + + "$unit($unit) pflanzt in $region($region) $int($amount) $resource($herb,$amount)." + "$unit($unit) plants $int($amount) $resource($herb,$amount) in $region($region)." + "$unit($unit) plants $int($amount) $resource($herb,$amount) in $region($region)." + + + + + + + "$unit($unit) in $region($region) entdeckt eine Laenader." + "$unit($unit) discovers laen in $region($region)." + + + + + + "Die Laenader in $region($region) ist erschöpft." + "There is no more laen in $region($region)." + + + + + + + + "$unit($unit) in $region($region) hat ein zu niedriges Talent, um $resource($resource,0) abzubauen." + "$unit($unit) in $region($region) is not proficient enough to produce $resource($resource,0)." + "$unit($unit) in $region($region) is not proficient enough to produce $resource($resource,0)." + + + + + + + + + + "$unit($unit) in $region($region) produziert $int($amount)$if($eq($wanted,$amount),""," von $int($wanted)") $resource($resource,$wanted)." + "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." + "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." + + + + + + + + + + "$unit($unit) in $region($region) produziert $int($amount)$if($eq($wanted,$amount),""," von $int($wanted)") $resource($resource,$wanted)." + "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." + "$unit($unit) in $region($region) produces $int($amount)$if($eq($wanted,$amount),""," of $int($wanted)") $resource($resource,$amount)." + + + + + + + + "$unit($unit) baut für $int($size) an $building($building) weiter." + "$unit($unit) builds $int($size) more on $building($building)." + "$unit($unit) builds $int($size) more on $building($building)." + + + + + + + + "$unit($unit) baut für $int($size) an $ship($ship) weiter." + "$unit($unit) builds $int($size) more on $ship($ship)." + "$unit($unit) builds $int($size) more on $ship($ship)." + + + + + + "$string" + "$string" + + + + + + + "$unit($unit) stirbt beim Versuch, die Feuerwand nach $region($region) zu durchqueren." + "$unit($unit) dies trying to cross the wall of fire into $region($region)." + "$unit($unit) dies trying to cross the wall of fire into $region($region)." + + + + + + + "$unit($unit) erleidet beim Durchqueren der Feuerwand nach $region($region) schwere Verbrennungen." + "$unit($unit) steps through the wall of fire into $region($region) and receives severe burn damage." + "$unit($unit) steps through the wall of fire into $region($region) and receives severe burn damage." + + + + + + + + + "$unit($unit) transportiert $unit($target) von $region($start) nach $region($end)." + "$unit($unit) transported $unit($target) from $region($start) to $region($end)." + "$unit($unit) transported $unit($target) from $region($start) to $region($end)." + + + + + + + + + + "$unit($unit) $if($eq($mode,1),"reitet", "wandert") von $region($start) nach $region($end).$if($isnull($regions),""," Dabei wurde $trail($regions) durchquert.")" + "$unit($unit) $if($eq($mode,1),"chevauche", "marche") de $region($start) vers $region($end) trans $trail($regions)" + "$unit($unit) $if($eq($mode,1),"rides", "walks") from $region($start) to $region($end)$if($isnull($regions),""," by way of $trail($regions)")." + + + + + + + "$unit($unit) entdeckt dass im $direction($direction) $terrain($region) ist." + "$unit($unit) discovered that an ocean lies in the $direction($direction)." + "$unit($unit) discovered that an ocean lies in the $direction($direction)." + + + + + + + "$unit($unit) entdeckt, dass $region($region) $terrain($region) ist." + "$unit($unit) discovered that $region($region) is $terrain($region)." + "$unit($unit) discovered that $region($region) is $terrain($region)." + + + + + + + "$unit($unit) ist in dieser Runde gelandet und kann nicht weiter ins Landesinnere nach $region($region) vorstossen." + "$unit($unit) has just landed and cannot continue moving to $region($region)." + "$unit($unit) has just landed and cannot continue moving to $region($region)." + + + + + + "Die Mannschaft der $ship($ship) kann in letzter Sekunde verhindern, dass das Schiff auf Land aufläuft." + "In the very last moment, the crew of the $ship($ship) saved the ship from grounding." + "In the very last moment, the crew of the $ship($ship) saved the ship from grounding." + + + + + + + "Die $ship($ship) konnte in $region($region) nicht einreisen, die Küste ist zu gefährlich für das Schiff." + "The $ship($ship) could not berth in $region($region). The coast is too dangerous for the vessel." + "The $ship($ship) could not berth in $region($region). The coast is too dangerous for the vessel." + + + + + + + "Die Mannschaft der $ship($ship) weigert sich, nach $direction($direction) zu reisen." + " The crew of the $ship($ship) refuses to travel to the$direction($direction)." + " The crew of the $ship($ship) refuses to travel to the$direction($direction)." + + + + + + + "Die Mannschaft der $ship($ship) weigert sich, nach $region($region) zu reisen." + "The crew of the $ship($ship) refuses to travel to $region($region)." + "The crew of the $ship($ship) refuses to travel to $region($region)." + + + + + + + "$unit($unit) weigert sich, nach $direction($direction) zu reisen." + "$unit($unit) refuses to travel to the$direction($direction)." + "$unit($unit) refuses to travel to the$direction($direction)." + + + + + + + "$unit($unit) weigert sich, nach $region($region) zu reisen." + "$unit($unit) refuses to travel to $region($region)." + "$unit($unit) refuses to travel to $region($region)." + + + + + + + "Die $ship($ship) konnte $region($region) nicht verlassen." + "The $ship($ship) could not leave $region($region)." + "The $ship($ship) could not leave $region($region)." + + + + + + + + "$unit($unit) wurde in $region($region) von $unit.dative($guard) aufgehalten." + "$unit($unit) was kept in $region($region) by $unit($guard)." + "$unit($unit) was kept in $region($region) by $unit($guard)." + + + + + + "Wir haben den Krieg mit $faction($faction) beendet." + "We declared peace with $faction($faction)." + "We declared peace with $faction($faction)." + + + + + + "$faction($faction) hat den Krieg mit uns beendet." + "$faction($faction) has declared peace with us." + "$faction($faction) has declared peace with us." + + + + + + "Wir haben $faction($faction) den Krieg erklärt." + "We declared war on $faction($faction)." + "We declared war on $faction($faction)." + + + + + + "$faction($faction) hat uns den Krieg erklärt." + "$faction($faction) has declared war on us." + "$faction($faction) has declared war on us." + + + + + + + + "$unit($unit) konnte nicht von $region($region) nach $region($target) reisen, da der Besitzer der Region es verhinderte." + "$unit($unit) could not travel from $region($region) to $region($target) because the owner denied entrance." + + + + + + + "$unit($unit) konnte aus $region($region) nicht ausreisen." + "$unit($unit) could not leave $region($region)." + "$unit($unit) could not leave $region($region)." + + + + + + + "$unit($follower) ist $unit($unit) gefolgt." + "$unit($follower) followed $unit($unit)." + "$unit($follower) followed $unit($unit)." + + + + + + + "$unit($follower) konnte $unit($unit) nicht folgen." + "$unit($follower) could not follow $unit($unit)." + "$unit($follower) could not follow $unit($unit)." + + + + + + + "$unit($unit) entdeckt, dass es keinen Weg nach $direction($direction) gibt." + "$unit($unit) discovers that there is no route going $direction($direction)." + "$unit($unit) discovers that there is no route going $direction($direction)." + + + + + + + + "$unit($unit) konnte von $region($region) nicht nach $direction($direction) ausreisen, der Nebel war zu dicht." + "$unit($unit) could not travel $direction($direction) from $region($region), the fog was too dense." + + + + + + "$string" + "$string" + + + + + + "In $region($region) erschienen die Herren der Bäume." + "In $region($region), the lords of the trees have risen." + "In $region($region), the lords of the trees have risen." + + + + + + "In $region($region) erhoben sich die Toten aus den Gräbern." + "The dead rise from their graves in $region($region)." + + + + + + + + "$unit($unit) vermehrt sich um $int($amount) $race($race,$amount)." + "$unit($unit) breeds $int($amount) new $race($race,$amount)." + "$unit($unit) breeds $int($amount) new $race($race,$amount)." + + + + + "Die Partei bekommt einen Spitznamen." + "Your faction received a nickname." + + + + + + + "Die Partei bekommt von $unit.dative($unit) in $region($region) einen Spitznamen." + "Your faction received a nickname from $unit($unit)." + + + + + + + "$building($building) in $region($region) bekommt einen Spitznamen." + "$building($building) in $region($region) received a nickname." + + + + + + + + "$building($building) in $region($region) bekommt von $unit.dative($renamer) einen Spitznamen." + "$building($building) in $region($region) received a nickname from $unit($renamer)." + + + + + + + "Die $ship($ship) in $region($region) bekommt einen Spitznamen." + "$ship($ship) in $region($region) received a nickname." + + + + + + + + "Die $ship($ship) in $region($region) bekommt von $unit.dative($renamer) einen Spitznamen." + "$ship($ship) in $region($region) received a nickname from $unit($renamer)." + + + + + + + "$unit($renamed) in $region($region) bekommt einen Spitznamen." + "$unit($renamed) in $region($region) received a nickname." + + + + + + + + "$unit($renamed) in $region($region) bekommt von $unit.dative($renamer) einen Spitznamen." + "$unit($renamed) in $region($region) received a nickname from $unit($renamer)." + + + + + + "$if($eq($dead,1),"Ein Bauer","$int($dead) Bauern") verhungert." + "$if($eq($dead,1),"One peasant starves","$int($dead) peasants starve")." + "$if($eq($dead,1),"One peasant starves","$int($dead) peasants starve")." + + + + + + "Der Vulkan in $region($region) bricht aus." + "The volcano in $region($region) breaks out." + "The volcano in $region($region) breaks out." + + + + + + + "Der Vulkan in $region($regionv) bricht aus. Die Lavamassen verwüsten $region($regionn)." + "The volcano in $region($regionv) breaks out. The lava devastates $region($regionn)." + "The volcano in $region($regionv) breaks out. The lava devastates $region($regionn)." + + + + + + + + "Beim Vulkanausbruch in $region($region) sterben $int($dead) Personen in $unit($unit)." + "$int($dead) people in $unit($unit) perisch when the volcano in $region($region) breaks out." + "$int($dead) people in $unit($unit) perisch when the volcano in $region($region) breaks out." + + + + + + "Aus dem Vulkankrater von $region($region) steigt kein Rauch mehr." + "The volcano of $region($region) stops releasing smoke." + "The volcano of $region($region) stops releasing smoke." + + + + + + "Aus dem Vulkankrater von $region($region) steigt plötzlich Rauch." + "Columns of smoke are released by the volcano of $region($region)." + "Columns of smoke are released by the volcano of $region($region)." + + + + + + + "$unit($unit) in $region($region) desertiert." + "$unit($unit) in $region($region) abandons your cause." + "$unit($unit) in $region($region) abandons your cause." + + + + + + + + "$unit($unit) reißt die Straße zwischen $region($from) und $region($to) ein." + "$unit($unit) demolishes the road between $region($from) and $region($to)." + "$unit($unit) demolishes the road between $region($from) and $region($to)." + + + + + + + "$unit($unit) in $region($region) kann keine Kräuter finden." + "$unit($unit) could not find any herbs in $region($region)." + "$unit($unit) could not find any herbs in $region($region)." + + + + + + + + + "$unit($unit) in $region($region) stellt fest, dass es hier $localize($amount) $resource($herb,0) gibt." + "$unit($unit) discovers that $localize($amount) $resource($herb,0) grow in $region($region)." + + + + + + + "$unit($unit) reißt einen Teil von $building($building) ein." + "$unit($unit) tears down parts of $building($building)." + + + + + + + "$unit($unit) zerstört $building($building)." + "$unit($unit) destroys $building($building)." + "$unit($unit) destroys $building($building)." + + + + + + + + "$unit($unit) erweitert in $region($region) das Straßennetz um $int($size)." + "$unit($unit) extends the road network in $region($region) by $int($size)." + "$unit($unit) extends the road network in $region($region) by $int($size)." + + + + + + + + "$unit($unit) $if($eq($amount,1),"schließt","schließen") sich $int($amount) $resource($rtype,$amount) an." + "$int($amount) $resource($rtype,$amount) $if($eq($amount,1),"joins","join") $unit($unit)." + + + + + + + "$unit($mage) legt einen Schleier um die Ausrüstung von $unit.dative($target)." + "$unit($mage) shrouds the equipment of $unit($target) in shadows." + + + + + + + + "Die $ship($ship) in $region($region) entdeckt ein Opfer im $direction($dir)." + "The $ship($ship) in $region($region) made $direction($dir) a target." + "The $ship($ship) in $region($region) made $direction($dir) a target." + + + + + + + "Die $ship($ship) in $region($region) kann keine Schiffe aufbringen." + "The $ship($ship) could not capture other ships in $region($region)." + "The $ship($ship) could not capture other ships in $region($region)." + + + + + + "Langsam kehren andere Völker nach $region($region) zurück." + "Little by little, people return to $region($region)." + "Little by little, people return to $region($region)." + + + + + + "Vor den vielen Orks in $region($region) fliehen die anderen Einwohner." + "People $region($region) flee from an Orc superiority." + "People $region($region) flee from an Orc superiority." + + + + + + + + "$unit($unit) in $region($region) beschädigt die $ship($ship)." + "$unit($unit) in $region($region) damages the $ship($ship)." + + + + + + + + "$unit($unit) in $region($region) versenkt die $ship($ship)." + "$unit($unit) sunk $ship($ship) in $region($region)." + "$unit($unit) sunk $ship($ship) in $region($region)." + + + + + + "$unit($unit) marschiert in eine Antimagiezone und löst sich auf." + "$unit($unit) walks into an antimagical zone and dissolves." + + + + + + "$unit($unit) hat sich unbemerkt verflüchtigt." + "$unit($unit) has dissolved without a trace." + "$unit($unit) has dissolved without a trace." + + + + + + "$unit($unit) wird sich bald verflüchtigen." + "$unit($unit) will dissolve soon." + "$unit($unit) will dissolve soon." + + + + + + + "$int($amount) Bauern flohen aus Furcht vor $unit($unit)." + "$int($amount) peasants fled in fear of $unit($unit)." + "$int($amount) peasants fled in fear of $unit($unit)." + + + + + + + + "$int($amount) Bauern werden zu $race($race,0) und schliessen sich $unit($unit) an." + "$int($amount) peasants become $race($race,0) and join the ranks of $unit($unit)." + + + + + + + "$unit($unit) verspeiste $int($amount) Pferde." + "$unit($unit) ate $int($amount) horses." + + + + + + + "$unit($unit) verspeiste $int($amount) Bauern." + "$unit($unit) ate $int($amount) peasants." + "$unit($unit) ate $int($amount) peasants." + + + + + + + "ERESSEA $int36($faction) \"${password}\" - Deine Befehle hatten ein falsches Passwort." + "ERESSEA $int36($faction) \"${password}\" - Your orders had the wrong password." + + + + + + "Das Passwort für diese Partei lautet ${value}." + "Le mot de passe de cette faction est '${value}'" + "The password of this faction is '$value'." + + + + + + "Die Reportadresse wurde nicht geändert, '${value}' ist keine gültige email." + " Address not changed, '$value' is an invalid email." + " Address not changed, '$value' is an invalid email." + + + + + + "Die Reportadresse wurde auf ${value} geändert." + " Address has been changed to '$value'." + " Address has been changed to '$value'." + + + + + + "Das Banner wurde auf '$value' geändert." + "Banner has been changed to '$value'." + "Banner has been changed to '$value'." + + + + + + + + + "Eine Partei muß mindestens $int($turns) Wochen alt sein, bevor sie angegriffen oder bestohlen werden kann." + "A faction must be at least $int($turns) weeks old before it can be attacked or stolen from." + + + + + + + + "$unit($unit) wurden in $region($region) $int($amount) Silberstücke geklaut." + "In $region($region), thieves stole $int($amount) silver from $unit($unit)." + "In $region($region), thieves stole $int($amount) silver from $unit($unit)." + + + + + + + "$unit($target) ertappte $unit($unit) beim versuchten Diebstahl." + "$unit($target) caught $unit($unit) in attempted theft." + "$unit($target) caught $unit($unit) in attempted theft." + + + + + + + "$unit($unit) wurde von $unit.dative($target) beim versuchten Diebstahl ertappt." + "$unit($unit) was caught by $unit($target) in attempted theft." + "$unit($unit) was caught by $unit($target) in attempted theft." + + + + + + "$unit($unit) fühlt sich beobachtet." + "$unit($unit) feels watched." + "$unit($unit) feels watched." + + + + + + + "$unit($unit) gelang es nicht, sich nahe genug an $unit($target) heranzuschleichen." + "$unit($unit) could not sneak close enough to $unit($target)." + "$unit($unit) could not sneak close enough to $unit($target)." + + + + + + + "$unit($spy) gelang es nicht, etwas über $unit($target) herauszufinden." + "$unit($spy) could not find out anything about $unit($target)." + "$unit($spy) could not find out anything about $unit($target)." + + + + + + + + "$unit($spy) gelang es, Informationen über $unit($target) ($status) herauszubekommen." + "$unit($spy) managed to gather information about $unit($target)." + + + + + + + "$unit($target) ist ein $type-Magier." + "$unit($target) is a $type-magician" + + + + + + + "$unit($target) beherrscht ${skills}." + "$unit($target) has the skills ${skills}." + + + + + + + "Im Gepäck von $unit($target) sind $resources($items)." + "$unit($target) carries $resources($items)" + + + + + + + "$unit($target) gehört der Partei $faction($faction) an." + "$unit($target) belongs to $faction($faction)." + + + + + + + "$unit($target) fühlt sich $if($isnull($spy),"","durch $unit($spy) ")beobachtet." + "$unit($target) feels watched by $unit($spy)." + "$unit($target) feels watched by $unit($spy)." + + + + + + + + "$faction($from) gibt ein Almosen von $int($amount) Silber an $faction($to)." + "$faction($from) donates $int($amount) silver to $faction($to)." + "$faction($from) donates $int($amount) silver to $faction($to)." + + + + + + + + "$unit($unit) vergißt durch Dumpfbackenbrot $int($weeks) Wochen des Talentes $skill($skill)." + "$unit($unit) eats a Dumpfbackenbrot and forgets $int($weeks) weeks worth of $skill($skill)." + "$unit($unit) eats a Dumpfbackenbrot and forgets $int($weeks) weeks worth of $skill($skill)." + + + + + + + "$unit($unit) in $region($region) wird durch unzureichende Nahrung geschwächt." + "$unit($unit) is weakened due to malnourishment." + "$unit($unit) is weakened due to malnourishment." + + + + + + + + + "$unit($unit) verliert in $region($region) $int($dead) von $int($add($live,$dead)) Personen durch Unterernährung." + "$unit($unit) loses $int($dead) of $int($add($live,$dead)) people due to starvation in $region($region)." + "$unit($unit) loses $int($dead) of $int($add($live,$dead)) people due to starvation in $region($region)." + + + + + + + + "$unit($unit): '$order($command)' - Die Einheit benutzt bereits $resource($using,0)." + "$unit($unit): '$order($command)' - The unit already uses $resource($using,0)." + "$unit($unit): '$order($command)' - The unit already uses $resource($using,0)." + + + + + + "Die $ship($ship) ist zu stark beschädigt und sinkt." + "The $ship($ship) suffers too heavy damage and sinks." + "The $ship($ship) suffers too heavy damage and sinks." + + + + + + + "Die $ship($ship) entdeckt, dass $region($region) Festland ist." + "The $ship($ship) discovers that $region($region) has no shore." + + + + + + + + "Die $ship($ship) fliegt von $region($from) nach $region($to)." + "The $ship($ship) flies from $region($from) to $region($to)." + + + + + + + + "Die $ship($ship) segelt von $region($from) nach $region($to)." + "The $ship($ship) sails from $region($from) to $region($to)." + + + + + + + + "Die $ship($ship) wird in $region($region) von Stürmen abgetrieben$if($sink," und sinkt","")." + "The $ship($ship) in $region($region) drifts in heavy storm$if($sink," and sinks","")." + "The $ship($ship) in $region($region) drifts in heavy storm$if($sink," and sinks","")." + + + + + + + + + "Die $ship($ship) fährt in den Mahlstrom von $region($region) und nimmt $int($damage) Schaden$if($sink," und sinkt","")." + "The $ship($ship) sails into the maelstrom of $region($region) and takes $int($damage) damage$if($sink,". The ship sinks","")." + + + + + + + "$unit($unit) vergißt $skill($skill)." + "$unit($unit) forgets $skill($skill)." + "$unit($unit) forgets $skill($skill)." + + + + + + + "$unit($unit) gibt das Kommando an $unit($recipient)." + "$unit($unit) gave control to $unit($recipient)." + "$unit($unit) gave control to $unit($recipient)." + + + + + + + + "$unit($unit) gibt $int($amount) Dumpfbackenbrot an $unit($recipient)." + "$unit($unit) administers $int($amount) duncebuns to $unit($recipient)." + + + + + + + + + "$unit($unit) in $region($region) rekrutiert $int($amount) von $int($want) Personen." + "$unit($unit) in $region($region) recruits $int($amount) $int($want) people." + "$unit($unit) in $region($region) recruits $int($amount) $int($want) people." + + + + + + + + "$unit($unit) belagert $building($building). Dabei richten die Katapulte Zerstörungen von $int($destruction) Größenpunkten an." + "$building($building) is under siege by $unit($unit). During siege, catapults caused $int($destruction) points destruction." + "$building($building) is under siege by $unit($unit). During siege, catapults caused $int($destruction) points destruction." + + + + + + + "$unit($unit) belagert $building($building)." + "$building($building) is under siege by $unit($unit)." + + + + + + + + "$unit($unit) ertrinkt beim Untergang der $ship($ship) in $region($region)." + "$unit($unit) drowns when $ship($ship) in $region($region) sinks." + "$unit($unit) drowns when $ship($ship) in $region($region) sinks." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht bewachen, da sie versucht zu fliehen." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot guard the region because it's trying to flee." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot guard the region because it's trying to flee." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann den Befehl in dieser Runde nicht ausführen, da sie an einem Kampf teilgenommen hat." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot execute this command because it has been in combat." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot execute this command because it has been in combat." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Gebäude kann nur einmal pro Runde erweitert werden." + "$unit($unit) in $region($region): '$order($command)' - Thhe building can be expanded only once per turn." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Objekt ist unzerstörbar." + "$unit($unit) in $region($region): '$order($command)' - This object is indestructible." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ohne Zutaten kann ein Alchemist nichts herstellen." + "$unit($unit) in $region($region): '$order($command)' - Ohne Zutaten kann ein Alchemist nichts herstellen." + "$unit($unit) in $region($region): '$order($command)' - Without ingredients an alchemist can not produce anything." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nicht alle Zutaten vorhanden." + "$unit($unit) in $region($region): '$order($command)' - Nicht alle Zutaten vorhanden." + "$unit($unit) in $region($region): '$order($command)' - Not all ingredients present." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Eine Partei kann nur einmal neu starten." + "$unit($unit) in $region($region): '$order($command)' - Restart can only be used once." + "$unit($unit) in $region($region): '$order($command)' - Restart can only be used once." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Werwesen können nicht arbeiten." + "$unit($unit) in $region($region): '$order($command)' - Lycantropes don't work." + "$unit($unit) in $region($region): '$order($command)' - Lycantropes don't work." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Werwesen können nicht mit anderen Personen gemischt werden." + "$unit($unit) in $region($region): '$order($command)' - Lycantropes may not be mixed with normal people." + "$unit($unit) in $region($region): '$order($command)' - Lycantropes may not be mixed with normal people." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann sich nicht verwandeln." + "$unit($unit) in $region($region): '$order($command)' - This unit can not change shape." + "$unit($unit) in $region($region): '$order($command)' - This unit can not change shape." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diese Einheit ist kein Werwesen." + "$unit($unit) in $region($region): '$order($command)' - This unit is not in lycantropic form." + "$unit($unit) in $region($region): '$order($command)' - This unit is not in lycantropic form." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diese Einheit ist schon ein Werwesen." + "$unit($unit) in $region($region): '$order($command)' - This unit already assumed lycantropic form." + "$unit($unit) in $region($region): '$order($command)' - This unit already assumed lycantropic form." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Talent kann nicht höher gelernt werden." + "$unit($unit) in $region($region): '$order($command)' - This skill cannot be raised any higher." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Snotlinge sind zu dumm, um auf den Feldern zu arbeiten." + "$unit($unit) in $region($region): '$order($command)' - We snotlings is too stupid fer dat!" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei muß mindestens 9 Wochen alt sein, um einen Neustart zu versuchen." + "$unit($unit) in $region($region): '$order($command)' - Your faction is not old enough to start over." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Optionen ZIP und BZIP2 können nur um, nicht ausgeschaltet werden." + "$unit($unit) in $region($region): '$order($command)' - options ZIP and BZIP2 can only be switched, not turned off." + "$unit($unit) in $region($region): '$order($command)' - options ZIP and BZIP2 can only be switched, not turned off." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Einheiten einer Partei, die noch immun gegen Angriffe ist, dürfen nicht bewachen." + "$unit($unit) in $region($region): '$order($command)' - units of a faction that can't be attacked may not guard." + "$unit($unit) in $region($region): '$order($command)' - units of a faction that can't be attacked may not guard." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In dieser Region kann man nichts verkaufen." + "$unit($unit) in $region($region): '$order($command)' - there is no trade in this region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Bereits ein Synonym gesetzt." + "$unit($unit) in $region($region): '$order($command)' - synonym already set." + "$unit($unit) in $region($region): '$order($command)' - synonym already set." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Kein Synonym angegeben." + "$unit($unit) in $region($region): '$order($command)' - synonym missing." + "$unit($unit) in $region($region): '$order($command)' - synonym missing." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ungültiges Synonym." + "$unit($unit) in $region($region): '$order($command)' - invalid synonym." + "$unit($unit) in $region($region): '$order($command)' - invalid synonym." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ungültiges Prefix." + "$unit($unit) in $region($region): '$order($command)' - invalid prefix." + "$unit($unit) in $region($region): '$order($command)' - invalid prefix." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier hat bereits einen Klon." + "$unit($unit) in $region($region): '$order($command)' - The magician already has a clone." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Gebäude auf dem Ozean können nicht betreten werden." + "$unit($unit) in $region($region): '$order($command)' - Buildings on the ocean may not be entered." + "$unit($unit) in $region($region): '$order($command)' - Buildings on the ocean may not be entered." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier werden niemals Bäume wachsen." + "$unit($unit) in $region($region): '$order($command)' - Trees won't grow here." + "$unit($unit) in $region($region): '$order($command)' - Trees won't grow here." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nur ein Magier kann einen Astralkristall benutzen." + "$unit($unit) in $region($region): '$order($command)' - Only mages may use an astralcrystal." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Verbände können nur zwischen Einheiten derselben Partei gebildet werden." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist in keinem Verband." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Eine Einheit kann nur in einem Verband Mitglied sein." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Wie sollen wir uns tarnen?" + "$unit($unit) in $region($region): '$order($command)' - What should we disguise us as?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Wieviel sollen wir einreißen?" + "$unit($unit) in $region($region): '$order($command)' - How much shall we tear down?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dorthin können wir die Einheit nicht transportieren." + "$unit($unit) in $region($region): '$order($command)' - We cannot transport this unit there." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit transportiert uns nicht." + "$unit($unit) in $region($region): '$order($command)' - the unit is not transporting us." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diese Einheit kennt keine Trankrezepte." + "$unit($unit) in $region($region): '$order($command)' - This unit knows no recipes for potions." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nur noch nicht gestärkte Untote können das Ziel dieses Zaubers sein." + "$unit($unit) in $region($region): '$order($command)' - Undead can only be affected once by this spell." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Passwort darf nur Buchstaben und Ziffern enthalten." + "$unit($unit) in $region($region): '$order($command)' - Your password may only contain alphanumeric symbols." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Gegen diese Rasse kann kein Jihad ausgerufen werden." + "$unit($unit) in $region($region): '$order($command)' - You cannot start a jihad against this race." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Gegen welche Rasse soll der Jihad ausgerufen werden?" + "$unit($unit) in $region($region): '$order($command)' - What race did you want the jihad to be against?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dazu muss erst die Spezialeigenschaft erworben werden." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Name und Beschreibung des Gebäudes können nicht geändert werden." + "$unit($unit) in $region($region): '$order($command)' - You cannot change the name and description of this building." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das kann die Einheit nicht." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man keine Schiffe bauen." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man keine Gebäude errichten." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht unterrichten." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man nicht unterrichten." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Pferde müssen leider draußen bleiben." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man niemanden angreifen." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man niemanden bestehlen." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man nicht zaubern." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man nichts übergeben." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nur eine Einzelperson kann das Ticket benutzen." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Gegenstand funktioniert nur in der Eingangshalle." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Gegenstand funktioniert nur in der normalen Welt." + "$unit($unit) in $region($region): '$order($command)' - This item only works in the normal world." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Gut hat die Einheit nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have this good." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Gut wird hier produziert." + "$unit($unit) in $region($region): '$order($command)' - This good is not produced here." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei kann keine weiteren Wyrme besitzen." + "$unit($unit) in $region($region): '$order($command)' - The faction cannot contain any more wyrms." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Vor den Besitzer eines Schiffes oder Gebäudes kann nicht sortiert werden." + "$unit($unit) in $region($region): '$order($command)' - You cannot sort before the owner of a ship or a building." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Besitzer eines Schiffes oder Gebäudes kann nicht neu sortiert werden." + "$unit($unit) in $region($region): '$order($command)' - The owner of a ship or a building cannot be sorted." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Befehl ist nur auf Einheiten innerhalb des selben Gebäudes oder Schiffes anwendbar." + "$unit($unit) in $region($region): '$order($command)' - That order only applies to units in the same building or ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Zieleinheit ist ungültig." + "$unit($unit) in $region($region): '$order($command)' - The target unit is invalid." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ungültiges Locale." + "$unit($unit) in $region($region): '$order($command)' - Invalid locale." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Um soetwas kann man nicht beten." + "$unit($unit) in $region($region): '$order($command)' - You cannot pray for this." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Soetwas kann man nicht opfern." + "$unit($unit) in $region($region): '$order($command)' - You cannot sacrifice this." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Auraangabe fehlerhaft oder zuwenig Aura." + "$unit($unit) in $region($region): '$order($command)' - Invalid aura specification or too little aura." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier ist nicht stark genug, sich den Göttern zu opfern." + "$unit($unit) in $region($region): '$order($command)' - This magician is not strong enough to be sacrificed to the gods." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Was und wieviel soll geopfert werden?" + "$unit($unit) in $region($region): '$order($command)' - What and how much should be sacrificed?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diese Kraft können selbst die Götter nicht mehr mächtiger machen." + "$unit($unit) in $region($region): '$order($command)' - Even the gods cannot improve this power." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nicht genug Karma." + "$unit($unit) in $region($region): '$order($command)' - Not enough karma." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff kann nicht aufs offene Meer hinaus segeln." + "$unit($unit) in $region($region): '$order($command)' - The ship cannot sail into the open seas." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei muß mindestens 10 Runden alt sein." + "$unit($unit) in $region($region): '$order($command)' - The faction has to be 10 turns old." + "$unit($unit) in $region($region): '$order($command)' - The faction has to be 10 turns old." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei hat schon einen Namen." + "$unit($unit) in $region($region): '$order($command)' - The faction is already named." + "$unit($unit) in $region($region): '$order($command)' - The faction is already named." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Gebäude hat schon einen Namen." + "$unit($unit) in $region($region): '$order($command)' - The building is already named." + "$unit($unit) in $region($region): '$order($command)' - The building is already named." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff hat schon einen Namen." + "$unit($unit) in $region($region): '$order($command)' - The ship is already named." + "$unit($unit) in $region($region): '$order($command)' - The ship is already named." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat schon einen Namen." + "$unit($unit) in $region($region): '$order($command)' - The unit is already named." + "$unit($unit) in $region($region): '$order($command)' - The unit is already named." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Keine gültige Rasse angegeben." + "$unit($unit) in $region($region): '$order($command)' - You did not specify a valid race." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit muß sich an Land befinden." + "$unit($unit) in $region($region): '$order($command)' - The unit must be on land." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $building($building) ist kein Steinkreis." + "$unit($unit) in $region($region): '$order($command)' - $building($building) is not a stonecircle." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $building($building) muss vor der Weihe fertiggestellt sein." + "$unit($unit) in $region($region): '$order($command)' - $building($building) has to be complete before it can be blessed." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In $region($target) sind keine Gräber." + "$unit($unit) in $region($region): '$order($command)' - There are no graves in $region($target)." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei muß mindestens 81 Wochen alt sein, um einen Neustart mit einer anderen Rasse zu versuchen." + "$unit($unit) in $region($region): '$order($command)' - The faction must be at least 81 weeks old to restart with a new race." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Soll eine Einheit oder ein Schiff verfolgt werden?" + "$unit($unit) in $region($region): '$order($command)' - Is this unit or ship supposed to be followed?" + "$unit($unit) in $region($region): '$order($command)' - Is this unit or ship supposed to be followed?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Soll eine Einheit oder ein Schiff eine neue Nummer bekommen?" + "$unit($unit) in $region($region): '$order($command)' - Is this unit or ship supposed to get a new number?" + "$unit($unit) in $region($region): '$order($command)' - Is this unit or ship supposed to get a new number?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier können nur Orks rekrutiert werden." + "$unit($unit) in $region($region): '$order($command)' - You can recruit only Orcs here." + "$unit($unit) in $region($region): '$order($command)' - You can recruit only Orcs here." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Region befindet sich in Aufruhr." + "$unit($unit) in $region($region): '$order($command)' - There are riots in this region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Gebäude ist noch nicht fertig gebaut." + "$unit($unit) in $region($region): '$order($command)' - The building is not finished yet." + "$unit($unit) in $region($region): '$order($command)' - The building is not finished yet." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Für das Gebäude wurde noch kein Unterhalt bezahlt." + "$unit($unit) in $region($region): '$order($command)' - Maintenance has not been paid yet." + "$unit($unit) in $region($region): '$order($command)' - Maintenance has not been paid yet." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist mit Ausschiffen beschäftigt.." + "$unit($unit) in $region($region): '$order($command)' - The unit is busy disembarking." + "$unit($unit) in $region($region): '$order($command)' - The unit is busy disembarking." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Typ Einheit kann keine Schiffe betreten." + "$unit($unit) in $region($region): '$order($command)' - Swimmers cannot enter ships." + "$unit($unit) in $region($region): '$order($command)' - Swimmers cannot enter ships." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Typ Einheit kann keine Gebäude betreten." + "$unit($unit) in $region($region): '$order($command)' - this type of unit cannot enter a building." + "$unit($unit) in $region($region): '$order($command)' - this type of unit cannot enter a building." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit oder ihre Tiere würden dort nicht überleben." + "$unit($unit) in $region($region): '$order($command)' - The unit or its animals would not survive there." + "$unit($unit) in $region($region): '$order($command)' - The unit or its animals would not survive there." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dorthin kann die Einheit uns nicht transportieren." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot transport us to this place." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot transport us to this place." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $building($building) wird belagert." + "$unit($unit) in $region($region): '$order($command)' - $building($building) is under siege." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Eintritt in $building($building) wurde verwehrt." + "$unit($unit) in $region($region): '$order($command)' - Entrance to $building($building) was denied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ein Vertrauter wird beschworen, verschwindet jedoch wieder, als er keine Verbindung zu seinem Element herstellen kann." + "$unit($unit) in $region($region): '$order($command)' - A familiar is summoned, but disappears again when it cannot get in contact with its natural element." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nur normale Personen können Steuern eintreiben." + "$unit($unit) in $region($region): '$order($command)' - Only normal characters can collect taxes." + "$unit($unit) in $region($region): '$order($command)' - Only normal characters can collect taxes." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dafür braucht ein Einheit mindestens Kräuterkunde 7." + "$unit($unit) in $region($region): '$order($command)' - A skill of herbalism 7 or higher is required." + "$unit($unit) in $region($region): '$order($command)' - A skill of herbalism 7 or higher is required." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Einheiten in den hinteren Reihen können nicht angreifen." + "$unit($unit) in $region($region): '$order($command)' - Units cannot attack from the second row." + "$unit($unit) in $region($region): '$order($command)' - Units cannot attack from the second row." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - unbekannter Kampfstatus." + "$unit($unit) in $region($region): '$order($command)' - unknown combat status." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht bewaffnet und kampffähig." + "$unit($unit) in $region($region): '$order($command)' - The unit is not armed and ready to fight." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei hat bereits ein Magiegebiet." + "$unit($unit) in $region($region): '$order($command)' - The faction has already chosen a magical school." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können nicht arbeiten." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot work." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot work." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hungernde Soldaten kämpfen nicht." + "$unit($unit) in $region($region): '$order($command)' - Starving units do not fight." + "$unit($unit) in $region($region): '$order($command)' - Starving units do not fight." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hungernde Einheiten können nicht zaubern." + "$unit($unit) in $region($region): '$order($command)' - Starving units cannot cast spells." + "$unit($unit) in $region($region): '$order($command)' - Starving units cannot cast spells." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hungernde Einheiten können nicht bewachen." + "$unit($unit) in $region($region): '$order($command)' - Starving units cannot guard." + "$unit($unit) in $region($region): '$order($command)' - Starving units cannot guard." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Zeige alle was?" + "$unit($unit) in $region($region): '$order($command)' - Show all what?" + "$unit($unit) in $region($region): '$order($command)' - Show all what?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht bauen." + "$unit($unit) in $region($region): '$order($command)' - You cannot build such a thing." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Im astralen Nebel konnte niemand entdeckt werden." + "$unit($unit) in $region($region): '$order($command)' - Noone could be seen in th astral fog." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ein Zauber in dieser Region verhindert das." + "$unit($unit) in $region($region): '$order($command)' - There is an active spell in this region that prevents this." + "$unit($unit) in $region($region): '$order($command)' - There is an active spell in this region that prevents this." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nur im Astralraum gezaubert werden." + "$unit($unit) in $region($region): '$order($command)' - This spell can only be cast in the astral plane." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier gibt es keine Verbindung zur astralen Welt." + "$unit($unit) in $region($region): '$order($command)' - There is no connection to the astral plane here." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Von hier aus kann man die astrale Ebene nicht erreichen." + "$unit($unit) in $region($region): '$order($command)' - You cannot reach the astral plane from here." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Einheit ist kein Magier." + "$unit($unit) in $region($region): '$order($command)' - Unit is not a magician." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Parameter nicht korrekt angegeben." + "$unit($unit) in $region($region): '$order($command)' - Incorrect parameter." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier befindet sich nicht auf einem Schiff." + "$unit($unit) in $region($region): '$order($command)' - The magician is not on board a ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Auf dem Schiff liegt bereits so ein Zauber." + "$unit($unit) in $region($region): '$order($command)' - The ship is already under this spell." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es ist zu gefährlich, ein sturmgepeitschtes Schiff fliegen zu lassen." + "$unit($unit) in $region($region): '$order($command)' - It is too dangerous to fly the ship in the storm." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Syntax Error." + "$unit($unit) in $region($region): '$order($command)' - Syntax Error." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Auraangabe fehlerhaft." + "$unit($unit) in $region($region): '$order($command)' - wrong Aura values." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Zu dieser Einheit kann keine Aura übertragen werden." + "$unit($unit) in $region($region): '$order($command)' - You cannot pass aura on to this unit." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Auf dem Gebäude liegt bereits so ein Zauber." + "$unit($unit) in $region($region): '$order($command)' - There is alrady a spell on that building." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nicht auf hoher See gezaubert werden." + "$unit($unit) in $region($region): '$order($command)' - This spell cannot be cast while you are on the ocean." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nicht auf Monster gezaubert werden." + "$unit($unit) in $region($region): '$order($command)' - This spell cannot be cast on monsters." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nicht auf Untote gezaubert werden." + "$unit($unit) in $region($region): '$order($command)' - This spell cannot be cast on undead." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Stimmung in der Region ist so schlecht, dass niemand auf den Zauber reagiert." + "$unit($unit) in $region($region): '$order($command)' - The mood in this region is so bad that nobody reacts t the spell." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) wusste trotz intensivem Verhör nichts über $region($tregion) zu berichten." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So viele Persoenen übersteigen die Kräfte des Magiers." + "$unit($unit) in $region($region): '$order($command)' -This many people exceed the powers of the magician." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) hat unaufkündbare Bindungen an seine alte Partei." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) have unbreakable prior commitments to their faction." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber gelingt nur in einer Ozeanregion." + "$unit($unit) in $region($region): '$order($command)' - This spell works only in an ocean region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In einer Region ohne Bäume kann man diesen Zauber nicht wirken." + "$unit($unit) in $region($region): '$order($command)' - You cannot cast this spell in a region without trees." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Ziel wurde vergessen." + "$unit($unit) in $region($region): '$order($command)' - No target has been supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das ist keine gültige Rasse." + "$unit($unit) in $region($region): '$order($command)' - This is not a valid race." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Rasse und Zieleinheit wurden vergessen." + "$unit($unit) in $region($region): '$order($command)' - Race and target unit have not been supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die maximale Aura reicht nicht für diesen Zauber." + "$unit($unit) in $region($region): '$order($command)' - Magician's maximum Aura is not high enough for this spell." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier hat bereits einen Vertrauten." + "$unit($unit) in $region($region): '$order($command)' - The magician already has a familiar." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Flammen finden keine Nahrung. Das Feuer erlischt, ohne Schaden anzurichten." + "$unit($unit) in $region($region): '$order($command)' - The flames find no kindling. The fire dies quickly, causing no damage whatsoever." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Um einen Heimstein zu erschaffen, muß der Zauberer in einer Burg sein." + "$unit($unit) in $region($region): '$order($command)' - The magician has to be in a castle to create a homestone." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das ist keine Waldregion." + "$unit($unit) in $region($region): '$order($command)' - This is not a forest region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dorthin führt kein Weg." + "$unit($unit) in $region($region): '$order($command)' - No way is leading in this direction." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Zielregion wurde nicht korrekt angegeben." + "$unit($unit) in $region($region): '$order($command)' - Target region was supplied incorrectly." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Zauber funktioniert nur in der Geisterwelt." + "$unit($unit) in $region($region): '$order($command)' - This spell will only work in the realm of spirits." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Wege zwischen Geisterwelt und Realität scheinen blockiert zu sein." + "$unit($unit) in $region($region): '$order($command)' - The paths to the spirit world seem to be blocked." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Zauber funktioniert nur in Wäldern." + "$unit($unit) in $region($region): '$order($command)' - This spell works only in forests." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Zauber funktioniert nur in der materiellen Welt." + "$unit($unit) in $region($region): '$order($command)' - This spell works only in the material world." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Selbst der mächtigste Magier der Welt könnte keinen Ozean austrocknen lassen." + "$unit($unit) in $region($region): '$order($command)' - Even the gods cannot dry out an entire ocean." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nicht im Sumpf gezaubert werden." + "$unit($unit) in $region($region): '$order($command)' - You cannot cast this spell in a swamp." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nur auf Land gelegt werden." + "$unit($unit) in $region($region): '$order($command)' - This spell works only ashore." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Zauber scheint ungewöhnlich schwach zu sein. Irgendetwas hat die magischen Energien abgeleitet." + "$unit($unit) in $region($region): '$order($command)' - the spell seems exceptionally weak. Something has interfred with the magical energies." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann den Befehl in dieser Runde nicht ausführen, da sie sich bewegt hat." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot execute this command because it has moved." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit bewegt sich nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not move." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier befindet sich nicht auf einem Schiff." + "$unit($unit) in $region($region): '$order($command)' - The magician is not on board a ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff kann in diese Richtung nicht ablegen." + "$unit($unit) in $region($region): '$order($command)' - The ship cannot leave in this direction." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dazu muß sich der Magier in der Burg oder an Bord des Schiffes befinden." + "$unit($unit) in $region($region): '$order($command)' - To do this, the magician has to be in a castle or on board a ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Zauber schlägt fehl." + "$unit($unit) in $region($region): '$order($command)' - The spell fails." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Magiegebiet kann die Einheit nicht lernen." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot learn this magic sphere." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es wurde kein Magiegebiet angegeben." + "$unit($unit) in $region($region): '$order($command)' - No magic sphere was supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diesen Spruch kann der Vertraute nicht zaubern." + "$unit($unit) in $region($region): '$order($command)' - the familiar cannot cast this spell." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diesen Spruch kann man nicht in die Ferne richten." + "$unit($unit) in $region($region): '$order($command)' - You cannot cast this spell on a distant target." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diesen Spruch kann man nicht auf einem sich bewegenden Schiff stehend zaubern." + "$unit($unit) in $region($region): '$order($command)' - You cannot cast this spell while standing on a moving ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber ist nur im Kampf sinnvoll." + "$unit($unit) in $region($region): '$order($command)' - this spell makes only sense in combat." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Selbst in der Bibliothek von Xontormia konnte dieser Spruch nicht gefunden werden." + "$unit($unit) in $region($region): '$order($command)' - Even in the Xontormia Library, this spell could not be found." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es wurde kein Zauber angegeben." + "$unit($unit) in $region($region): '$order($command)' - There was no spell supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diesen Kampfzauber gibt es nicht." + "$unit($unit) in $region($region): '$order($command)' - This combat spell does not exist." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Bauern nehmen dieses großzügige Geschenk nicht an." + "$unit($unit) in $region($region): '$order($command)' - The peasants did not accept this gracious gift." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diesen Zauber kennt die Einheit nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not know this spell." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es konnten keine Luxusgüter verkauft werden." + "$unit($unit) in $region($region): '$order($command)' - No luxury items could be sold." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit geht nicht zu den Bauern." + "$unit($unit) in $region($region): '$order($command)' - The unit does not go to the peasants." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diese Rasse kann eine Burg nicht belagern." + "$unit($unit) in $region($region): '$order($command)' - This race cannot siege a castle." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Trank bekommt der Einheit nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit disagreed with the potion." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Nestwärme kann nur von Insektenvölkern benutzt werden." + "$unit($unit) in $region($region): '$order($command)' - this potion can only be used by insects." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Heiltrank wird automatisch bei Bedarf benutzt." + "$unit($unit) in $region($region): '$order($command)' - This healing potion will be automatically used when needed." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit besitzt den Trank nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have this potion." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es konnten keine Luxusgüter gekauft werden." + "$unit($unit) in $region($region): '$order($command)' - No luxury items could be bought." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es konnten keine Personen übergeben werden." + "$unit($unit) in $region($region): '$order($command)' - No person could be handed over." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Magier arbeiten grundsätzlich nur alleine!" + "$unit($unit) in $region($region): '$order($command)' - Magicians always work alone!" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei hat ein anderes Magiegebiet." + "$unit($unit) in $region($region): '$order($command)' - The faction has a different magic sphere." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Zuviele Alchemisten in der Partei." + "$unit($unit) in $region($region): '$order($command)' - Too many alchemists in the faction." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Zuviele Magier in der Partei." + "$unit($unit) in $region($region): '$order($command)' - Too many magicians in the faction." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hochqualifizierte Personen weigern sich, für andere Parteien zu arbeiten." + "$unit($unit) in $region($region): '$order($command)' - Highly qualified people refuse to work for other parties." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit schließt sich den Bauern an." + "$unit($unit) in $region($region): '$order($command)' - The unit joins the local peasants." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit springt über Bord und ertrinkt." + "$unit($unit) in $region($region): '$order($command)' - The unit jumps over board and drowns." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Region wird bewacht." + "$unit($unit) in $region($region): '$order($command)' - The region is guarded." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Unbekannte Option." + "$unit($unit) in $region($region): '$order($command)' - Unknown Option." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit wird belagert." + "$unit($unit) in $region($region): '$order($command)' - The unit is under siege." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Zum Straßenbau braucht man Steine." + "$unit($unit) in $region($region): '$order($command)' - You need stones to build a road." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Wohin soll die Botschaft gehen?" + "$unit($unit) in $region($region): '$order($command)' - Who is supposed to get this message?" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht der Burgherr." + "$unit($unit) in $region($region): '$order($command)' - The unit is not in command of a castle." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht Burgherr der größten Burg in der Region." + "$unit($unit) in $region($region): '$order($command)' - The unit is not in command of the largest castle in the region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht der Kapitän des Schiffes." + "$unit($unit) in $region($region): '$order($command)' - The unit is not captain of a ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist in keiner Burg." + "$unit($unit) in $region($region): '$order($command)' - The unit is not in a castle." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist auf keinem Schiff." + "$unit($unit) in $region($region): '$order($command)' - The unit is not on board a ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist auf einem Schiff." + "$unit($unit) in $region($region): '$order($command)' - The unit is on board a ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat zuwenig Silber, um zu rekrutieren." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough silver for recruiting." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht mehr genug Kristalle für so viele Personen." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough crystals left for this many people." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit befindet sich weder in einer Burg noch auf einem Schiff." + "$unit($unit) in $region($region): '$order($command)' - The unit is neither in a castle nor on board a ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Unterschiedliche Typen können nicht gemischt werden." + "$unit($unit) in $region($region): '$order($command)' - Different types do not mix." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Uns gehört nichts, was man abreißen oder versenken könnte." + "$unit($unit) in $region($region): '$order($command)' - We do not have anything that could be demolished." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Unbekannter Hilfe-Modus." + "$unit($unit) in $region($region): '$order($command)' - Unknown Help- Mode." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Unbekannte Meldungs-Option." + "$unit($unit) in $region($region): '$order($command)' - Unknown Report-Option." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Um in Wüsten Straßen bauen zu können, muß zuerst eine Karawanserei errichtet werden." + "$unit($unit) in $region($region): '$order($command)' - You've got to build a caravansary before building roads through deserts." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Um in Sümpfen Straßen bauen zu können, muß zuerst ein Damm errichtet werden." + "$unit($unit) in $region($region): '$order($command)' - You've got to build a dam before building roads through swamps." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So viele Leute kann die Partei nicht aufnehmen." + "$unit($unit) in $region($region): '$order($command)' - The faction cannot hire so many strangers." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So viele Fremde kann die Partei nicht aufnehmen." + "$unit($unit) in $region($region): '$order($command)' - The faction cannot hire so many strangers." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So viele Fremde kann Deine Partei nicht aufnehmen." + "$unit($unit) in $region($region): '$order($command)' - Your faction cannot hire so many strangers." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht verkaufen." + "$unit($unit) in $region($region): '$order($command)' - You cannot sell this." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht machen." + "$unit($unit) in $region($region): '$order($command)' - You cannot produce this." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht auf dem Markt kaufen." + "$unit($unit) in $region($region): '$order($command)' - You cannot buy that on a market place." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So etwas hat die Einheit nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have such a thing." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Pferde kann man nur in einer Pferdezucht züchten." + "$unit($unit) in $region($region): '$order($command)' - You can breed horses only in a stable." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - So etwas gibt es hier nicht." + "$unit($unit) in $region($region): '$order($command)' - That resource does not exist in this region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Personen können nur an Menschen übergeben werden." + "$unit($unit) in $region($region): '$order($command)' - Characters can be given only to Human parties." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ohne einen Handelsposten gibt es keinen Markt." + "$unit($unit) in $region($region): '$order($command)' - There is no marketplace without at least a tradepost." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nur Elfen können diese Bögen herstellen." + "$unit($unit) in $region($region): '$order($command)' - Only Elves can make these bows." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nur die EMail-Adresse angeben!" + "$unit($unit) in $region($region): '$order($command)' - Submit only email-address, please!" + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nummer kann nicht vergeben werden." + "$unit($unit) in $region($region): '$order($command)' - Number can not be assigned." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nummer ist schon belegt." + "$unit($unit) in $region($region): '$order($command)' - Number is already in use." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nummer ist nicht im gültigen Bereich." + "$unit($unit) in $region($region): '$order($command)' - Number is not valid." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nichts angegeben, was wir übergeben sollen." + "$unit($unit) in $region($region): '$order($command)' - Item to be handed over was not supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Namen dürfen keine Klammern enthalten." + "$unit($unit) in $region($region): '$order($command)' - Names may not contain parenthesis." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Nachricht zu lang - gekürzt." + "$unit($unit) in $region($region): '$order($command)' - Message has been cut (too long).." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Man muß angeben, ob eine Burg, ein Schiff, eine Region oder eine Einheit beschrieben werden soll." + "$unit($unit) in $region($region): '$order($command)' - Specify if description is for a castle, a ship, a region or a unit." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Man muß angeben, ob eine Burg, ein Schiff, eine Einheit, eine Region oder eine Partei benannt werden soll." + "$unit($unit) in $region($region): '$order($command)' - Specify if a castle, a ship, a region or a unit is supposed to be named." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es sind keine Kräuter zu finden." + "$unit($unit) in $region($region): '$order($command)' - No herbs could be found." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Man braucht mindestens zwei Pferde, um sie zu züchten." + "$unit($unit) in $region($region): '$order($command)' - You need at least two horses to breed more." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Magier müssen zum studieren allein sein." + "$unit($unit) in $region($region): '$order($command)' - When studying, magicians need to be alone." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Leere Einheiten können nicht übergeben werden." + "$unit($unit) in $region($region): '$order($command)' - Empty units can not be handed over." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Laen kann nur in einem Bergwerk abgebaut werden." + "$unit($unit) in $region($region): '$order($command)' - Laen can be excavated only in a mine." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Keiner hier kann Straßen bauen." + "$unit($unit) in $region($region): '$order($command)' - Nobody here can build roads." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann keine weiteren Güter handeln." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot trade any more goods." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Keiner hier kann ein Gebäude errichten." + "$unit($unit) in $region($region): '$order($command)' - Nobody here can construct a building." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Keiner hier ist gelernter Schiffbauer." + "$unit($unit) in $region($region): '$order($command)' - Nobody here is a skilled ship builder." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit will nicht transportiert werden." + "$unit($unit) in $region($region): '$order($command)' - The unit doen not want to be transported." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Insekten können im Winter nur in Wüsten rekrutiert werden." + "$unit($unit) in $region($region): '$order($command)' - In winter, insects can be recruited only in deserts." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In Gletschern können keine Insekten rekrutiert werden." + "$unit($unit) in $region($region): '$order($command)' - Insects cannot be recruited in glaciers." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In dieser Einheit gibt es niemanden, den man transferieren könnte." + "$unit($unit) in $region($region): '$order($command)' - Nobody in this unit can be transferred." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Illusionen können eine Region nicht bewachen." + "$unit($unit) in $region($region): '$order($command)' - Illusions cannot guard a region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier kann man keine Straße bauen." + "$unit($unit) in $region($region): '$order($command)' - You cannot build a road here." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier gibt es schon einen Hafen." + "$unit($unit) in $region($region): '$order($command)' - There is already a port in this region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier gibt es keine Bauern." + "$unit($unit) in $region($region): '$order($command)' - There are no peasants in this region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier gibt es keinen normalen Wald." + "$unit($unit) in $region($region): '$order($command)' - There is no normal forest in this region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Hier gibt es keine Mallornbäume." + "$unit($unit) in $region($region): '$order($command)' - There are no Mallorn trees here." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit fährt nicht mit uns." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have a RIDE-order." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Geldgebot fehlt." + "$unit($unit) in $region($region): '$order($command)' - Money offer is missing." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht genügend Materialien für den Schiffbau." + "$unit($unit) in $region($region): '$order($command)' - the unit is lacking materials to build the ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Für das Elixier benötigt man Drachenblut." + "$unit($unit) in $region($region): '$order($command)' - Dragon blood is required for this elixir." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Falsches Passwort." + "$unit($unit) in $region($region): '$order($command)' - Wrong password." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es wurde keine EMail-Adresse angegeben." + "$unit($unit) in $region($region): '$order($command)' - No email-address was supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es wurde kein Name angegeben." + "$unit($unit) in $region($region): '$order($command)' - No name was supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es konnte kein Bauer gefangen werden." + "$unit($unit) in $region($region): '$order($command)' - No peasant could be caught." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es gibt keine Abstimmung mit dieser Nummer." + "$unit($unit) in $region($region): '$order($command)' - There is no agreement with this number." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Einheit muß zuerst die Region bewachen." + "$unit($unit) in $region($region): '$order($command)' - first, the unit must guard the region." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Einheit ist nicht bewaffnet und kampffähig." + "$unit($unit) in $region($region): '$order($command)' - The unit is not armed and fighting fit." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ein Schiff oder eine Burg muß angegeben werden." + "$unit($unit) in $region($region): '$order($command)' - A ship or a castle must be supplied." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ein Fluch verhindert die Übergabe." + "$unit($unit) in $region($region): '$order($command)' - A curse prevented the transfer from happening." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Talent wurde nicht erkannt." + "$unit($unit) in $region($region): '$order($command)' - The skill could not be recognized." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieses Talent kann die Einheit nicht lernen." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot learn this skill." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diesen Gegenstand kann man nicht benutzen." + "$unit($unit) in $region($region): '$order($command)' - This item cannot be used." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit nimmt niemanden an." + "$unit($unit) in $region($region): '$order($command)' - This unit does not take anybody." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Eine hungernde Einheit kann niemanden weggeben." + "$unit($unit) in $region($region): '$order($command)' - Hungry units cannot give anybody away." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diese Einheit kann niemanden weggeben." + "$unit($unit) in $region($region): '$order($command)' - This unit cannot give anybody away." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) hat keinen Kontakt mit uns aufgenommen." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) did not contact us." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es kann hier kein Kontakt zur Astralwelt aufgenommen werden." + "$unit($unit) in $region($region): '$order($command)' - There is no connection to the astral plane." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) hat keinen Kontakt mit uns aufgenommen und widersteht dem Zauber." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) did not contact us, and resists the spell." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) hat keinen Kontakt mit uns aufgenommen, aber widersteht dem Zauber nicht." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) did not contact us, but cannot resist the spell." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Richtung wurde nicht erkannt." + "$unit($unit) in $region($region): '$order($command)' - Direction was not recognized." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Richtung '$dirname' wurde nicht erkannt." + "$unit($unit) in $region($region): '$order($command)' - Direction '$dirname' was not recognized." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Region wird von Nichtalliierten bewacht." + "$unit($unit) in $region($region): '$order($command)' - This region is guarded by a non allied faction." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Region wird von $unit($guard), einer nichtalliierten Einheit, bewacht." + "$unit($unit) in $region($region): '$order($command)' - This region is guarded by $unit($guard), a non-allied unit." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Pferde würden ertrinken." + "$unit($unit) in $region($region): '$order($command)' - The horses would drown." + "$unit($unit) in $region($region): '$order($command)' - The horses would drown." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - The faction could not be found." + "$unit($unit) in $region($region): '$order($command)' - The faction could not be found." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Lernkosten können nicht bezahlt werden." + "$unit($unit) in $region($region): '$order($command)' - Tuition was too high to be paid." + "$unit($unit) in $region($region): '$order($command)' - Tuition was too high to be paid." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Gegenstand kann nur in der realen Welt benutzt werden." + "$unit($unit) in $region($region): '$order($command)' - This object can only be used in the real world." + "$unit($unit) in $region($region): '$order($command)' - This object can only be used in the real world." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) ist nicht ausreichend getarnt." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) is not sufficiently stealthy." + "$unit($unit) in $region($region): '$order($command)' - $unit($unit) is not sufficiently stealthy." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - The unit could not be found." + "$unit($unit) in $region($region): '$order($command)' - The unit could not be found." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Einheit kann nichts gegeben werden." + "$unit($unit) in $region($region): '$order($command)' - You cannot give anything to this unit." + + + + + + + + + "$unit($mage) horcht $unit($unit) über $region($tregion) aus." + "$unit($mage) questions $unit($unit) about $region($tregion)." + + + + + + + + "$unit($mage) verschafft $unit($unit) einige feuchtfröhliche Stunden mit heftigen Nachwirkungen." + "$unit($mage) invites $unit($unit) for a few too many drinks and a massive hangover." + + + + + + + "$unit($unit) hat höllische Kopfschmerzen und kann sich an die vergangene Woche nicht mehr erinnern. Nur noch daran, wie alles mit einer fröhlichen Feier in irgendeiner Taverne anfing...." + "$unit($unit) has a splitting headache and can hardly remember last week. Except that it all started in the tavern..." + + + + + + + + "$unit($mage) besänftigt $unit($unit)." + "$unit($mage) calms $unit($unit)." + + + + + + + "$unit($unit) verfiel dem Glücksspiel und hat fast sein ganzes Hab und gut verspielt." + "$unit($unit) gambles for high stakes and loses almost everything." + + + + + + + + + "$unit($unit) schenkt $unit($mage) $resources($items)." + "$unit($unit) gives $unit($mage) $resources($items)." + + + + + + + + + "$unit($mage) läßt $unit($target) als $race($race,$unit.size($target)) erscheinen." + "$unit($mage) makes $unit($target) appear as $race($race,$unit.size($target))." + + + + + + + "$unit($unit) wird kurz von einem magischen Licht umhüllt." + "$unit($unit) is briefly surrounded by a magical light." + + + + + + + + "$unit($unit) konnte nur $int($ships) von $int($maxships) Schiffen verzaubern." + "$unit($unit) could only enchant $int($ships) of $int($maxships) ships." + + + + + + "$unit($unit) beschwört einen magischen Wind, der die Schiffe über das Wasser treibt." + "$unit($unit) calls up a magical storm that whips the ship over the waters." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit weiß nichts über Botanik." + "$unit($unit) in $region($region): '$order($command)' - The unit does not know anything about herbalism." + "$unit($unit) in $region($region): '$order($command)' - The unit does not know anything about herbalism." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit weiß nicht, wie man gaukelt." + "$unit($unit) in $region($region): '$order($command)' - The unit does not know how to entertain." + "$unit($unit) in $region($region): '$order($command)' - The unit does not know how to entertain." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit trägt zuviel Gewicht, um sich bewegen zu können." + "$unit($unit) in $region($region): '$order($command)' - The unit is too heavily loaded to move." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann soviele Pferde nicht bändigen." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot tame that many horses." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann sich nicht fortbewegen." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot move." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht handeln." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot trade." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann keine Tränke herstellen." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot make potions." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann keine weiteren langen Befehle ausführen." + "$unit($unit) in $region($region): '$order($command)' - The unit is exhausted from battle." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht genug Silber." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough silver." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough silver." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht erfahren genug dafür." + "$unit($unit) in $region($region): '$order($command)' - The unit is not experienced enough to do this." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht der Eigentümer." + "$unit($unit) in $region($region): '$order($command)' - The unit is not he owner." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist nicht bewaffnet und kampffähig." + "$unit($unit) in $region($region): '$order($command)' - The unit is not armed and fighting fit." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist mit uns alliiert." + "$unit($unit) in $region($region): '$order($command)' - This unit is one of our allies." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist in keiner Taverne." + "$unit($unit) in $region($region): '$order($command)' - The unit is not in a tavern." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist eine der unsrigen." + "$unit($unit) in $region($region): '$order($command)' - This unit is one of our own." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist auf hoher See." + "$unit($unit) in $region($region): '$order($command)' - The unit is off shore." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat soetwas nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have this." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht genug Wagenlenker oder zuviel andere Fracht, um die Wagen aufzuladen." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough coachmen or too much freights to lad the wagons." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nicht genug Silber." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have enough silver." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat keinen Kontakt mit uns aufgenommen." + "$unit($unit) in $region($region): '$order($command)' - The unit did not contact us." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat keine Spionage gelernt." + "$unit($unit) in $region($region): '$order($command)' - The unit has not yet learned espionage." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat keine Kräuter." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have any herbs." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat diesen Trank nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have this potion." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat diesen Gegenstand nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have this item." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat diesen Gegenstand zwar, aber sämtliche $int($reservation) $resource($resource,$reservation) sind reserviert." + "$unit($unit) in $region($region): '$order($command)' - The unit has this item, but all $int($reservation) $resource($resource,$reservation) are reserved." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat diese Kräuter nicht." + "$unit($unit) in $region($region): '$order($command)' - The unit does not have these herbs." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Einheiten dürfen nicht mehr als $int($maxsize) Personen enthalten." + "$unit($unit) in $region($region): '$order($command)' - Units may not have more than $int($maxsize) members." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit darf nicht an Bord kommen, da sie das Schiff überladen würde." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot go aboard, the ship would be overloaded." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit darf nicht an Bord kommen." + "$unit($unit) in $region($region): '$order($command)' - This unit has no permission to come on board." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit befindet sich nicht in unserer Burg." + "$unit($unit) in $region($region): '$order($command)' - The unit is not in our castle." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit befindet sich nicht an Bord unseres Schiffes." + "$unit($unit) in $region($region): '$order($command)' - The unit is not on board our ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Burg wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - The castle could not be found." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Botschaft enthält keinen Text." + "$unit($unit) in $region($region): '$order($command)' - The message does not contain text." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Bauern sind schlecht gelaunt." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Anzahl zu verkaufender Produkte fehlt." + "$unit($unit) in $region($region): '$order($command)' - The amount of items for sale is missing." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Anzahl zu kaufender Produkte fehlt." + "$unit($unit) in $region($region): '$order($command)' - The amount of items to buy is missing." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Fluch verhindert das." + "$unit($unit) in $region($region): '$order($command)' - The escape prevented that from happening." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Belagerungszustand macht Spionage unmöglich." + "$unit($unit) in $region($region): '$order($command)' - Espionage was not possible due to siege." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Belagerungszustand macht die Kontaktaufnahme unmöglich." + "$unit($unit) in $region($region): '$order($command)' - Contact was not possible due to siege." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Befehl wurde nicht erkannt." + "$unit($unit) in $region($region): '$order($command)' - Unknown command." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dazu gibt es keine Informationen." + "$unit($unit) in $region($region): '$order($command)' - There is no information available for the request." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - The ship could not be found." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff muß erst verlassen werden." + "$unit($unit) in $region($region): '$order($command)' - First you have to leave the ship." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff ist zu schwer beladen, um in See zu stechen." + "$unit($unit) in $region($region): '$order($command)' - The ship is too heavily loaded to sail." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $ship($ship) ist zu groß, um fliegen zu können." + "$unit($unit) in $region($region): '$order($command)' - $ship($ship) is too bulky to fly." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff ist schon fertig." + "$unit($unit) in $region($region): '$order($command)' - The ship is already completed." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff ist noch nicht fertig gebaut." + "$unit($unit) in $region($region): '$order($command)' - The ship has not yet been completed." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff ist auf hoher See." + "$unit($unit) in $region($region): '$order($command)' - The ship is off shore." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff hat sich bereits bewegt." + "$unit($unit) in $region($region): '$order($command)' - The ship has moved already." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Besitzer muss das Gebäude zuerst verlassen." + "$unit($unit) in $region($region): '$order($command)' - The owner must first LEAVE the building." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff gehört uns nicht." + "$unit($unit) in $region($region): '$order($command)' - The ship is not ours." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Gebäude gehört uns nicht." + "$unit($unit) in $region($region): '$order($command)' - The building is not ours." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Schiff befindet sich auf hoher See." + "$unit($unit) in $region($region): '$order($command)' - The ship is still off shore." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das macht wenig Sinn." + "$unit($unit) in $region($region): '$order($command)' - That does not make much sense." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das kann man nicht sabotieren." + "$unit($unit) in $region($region): '$order($command)' - That cannot be sabotaged." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das ist sinnlos." + "$unit($unit) in $region($region): '$order($command)' - That is useless." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das geht nicht mehr." + "$unit($unit) in $region($region): '$order($command)' - This is no longer possible." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Gebäude wurde nicht gefunden." + "$unit($unit) in $region($region): '$order($command)' - Building could not be found." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Gebäude gehört uns nicht." + "$unit($unit) in $region($region): '$order($command)' - The building is not ours." + "$unit($unit) in $region($region): '$order($command)' - The building is not ours." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Das Gebäude ist bereits fertig." + "$unit($unit) in $region($region): '$order($command)' - The building is already completed." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht unterrichtet werden." + "$unit($unit) in $region($region): '$order($command)' - this unit cannot be taught." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Beschreibung zu lang - gekürzt." + "$unit($unit) in $region($region): '$order($command)' - Description has been cut (too long)." + "$unit($unit) in $region($region): '$order($command)' - Description has been cut (too long)." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Auf hoher See kann man nicht bewachen." + "$unit($unit) in $region($region): '$order($command)' - You cannot guard off shore." + "$unit($unit) in $region($region): '$order($command)' - You cannot guard off shore." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Auf dem Schiff befinden sich zuwenig erfahrene Seeleute." + "$unit($unit) in $region($region): '$order($command)' - There are not enough experienced sailors on board the ship." + "$unit($unit) in $region($region): '$order($command)' - There are not enough experienced sailors on board the ship." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - ${error}." + "$unit($unit) in $region($region): '$order($command)' - ${error}." + + + + + + + "$unit($unit) benutzt ein $resource($item,1)." + "$unit($unit) uses a $resource($item,1)." + "$unit($unit) uses a $resource($item,1)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $resource($item,0) können nur von Ein-Personen Einheiten benutzt werden." + "$unit($unit) in $region($region): '$order($command)' - $resource($item,0) can only be used by single-person units." + "$unit($unit) in $region($region): '$order($command)' - $resource($item,0) can only be used by single-person units." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit ist noch zu erschöpft vom Einmarsch um zu attackieren." + "'$order($command)' - $unit($unit) marched into $region($region) during the last turn and is too exhausted to attack." + "'$order($command)' - $unit($unit) marched into $region($region) during the last turn and is too exhausted to attack." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) sind friedliebend und attackieren niemand." + "'$order($command)' - $race($race,0) are peace-loving and will not attack anyone." + "'$order($command)' - $race($race,0) are peace-loving and will not attack anyone." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit steht nicht im benötigten Gebäude, $localize($building)." + "$unit($unit) in $region($region): '$order($command)' - The unit must be in a $localize($building) to produce this." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dazu braucht man das Talent $skill($skill)." + "$unit($unit) in $region($region): '$order($command)' - this requires the skill $skill($skill)." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Man benötigt mindestens $int($minskill) $skill($skill), um $resource($product,0) zu pflanzen." + "$unit($unit) in $region($region): '$order($command)' - At least $skill($skill) $int($minskill) is needed for planting $resource($product,0)." + "$unit($unit) in $region($region): '$order($command)' - At least $skill($skill) $int($minskill) is needed for planting $resource($product,0)." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Man benötigt mindestens $int($minskill) $skill($skill), um $resource($product,0) zu produzieren." + "$unit($unit) in $region($region): '$order($command)' - You need at least $int($minskill) $skill($skill), to produce $resource($product,0)." + + + + + + "$string" + "$string" + + + + + + "$string" + "$string" + + + + + + "$string" + "$string" + + + + + + + + "$unit($unit) übergibt $int($amount) Person$if($eq($amount,1),"","en") an $unit($target)." + "$unit($unit) transfers $int($amount) person$if($eq($amount,1),"","s") to $unit($target)." + + + + + + + + + + "$unit($unit) übergibt $int($amount) $resource($resource,$amount) an $unit($target)." + "$unit($unit) gives $int($amount) $resource($resource,$amount) to $unit($target)." + + + + + + + + + + "$unit($target) erhält $int($amount) $resource($resource,$amount) von $unit($unit)." + "$unit($target) receives $int($amount) $resource($resource,$amount) from $unit($unit)." + + + + + + + + "$unit($unit) übergibt $int($amount) Person$if($eq($amount,1),"","en") an die Bauern." + "$unit($unit) transfers $int($amount) person$if($eq($amount,1),"","s") to the local peasants." + + + + + + + + + "$unit($unit) übergibt $int($amount) $resource($resource,$amount) an die Bauern." + "$unit($unit) gives $int($amount) $resource($resource,$amount) to the local peasants." + + + + + + + + "$unit($unit) bezahlt den Unterhalt von $building($building)." + "$unit($unit) pays the maintenance for $building($building)." + "$unit($unit) pays the maintenance for $building($building)." + + + + + + + + "$unit($unit) fehlen $resource($item,0) für den Betrieb von $building($building)." + "$unit($unit) lacks $resource($item,0) to operate $building($building)." + + + + + + + "$unit($unit) kann den Unterhalt von $building($building) nicht bezahlen." + "$unit($unit) cannot pay the maintenance for $building($building)." + "$unit($unit) cannot pay the maintenance for $building($building)." + + + + + + "Der Unterhalt von $building($building) konnte nur verspätet gezahlt werden, das Gebäude war diese Woche nicht funktionstüchtig." + "The upkeep for $building($building) was paid late, the building was not operational this week." + "The upkeep for $building($building) was paid late, the building was not operational this week." + + + + + + + + "$unit($unit) verdient am Handel in $region($region) Steuern in Höhe von $int($amount) Silber." + "$unit($unit) collected $int($amount) silver trade tax in $region($region)." + "$unit($unit) collected $int($amount) silver trade tax in $region($region)." + + + + + + + "$unit($unit) benutzt $resource($potion,1)." + "$unit($unit) uses $resource($potion,1)." + "$unit($unit) uses $resource($potion,1)." + + + + + + "Hier wütete die Pest, und $int($dead) Bauern starben." + "The region is visited by the plague and $int($dead) peasants died." + "The region is visited by the plague and $int($dead) peasants died." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Um in Gletschern Straßen bauen zu können, muß zuerst ein Tunnel errichtet werden." + "$unit($unit) in $region($region): '$order($command)' - You've got to build a tunnel before building roads through glaciers." + "$unit($unit) in $region($region): '$order($command)' - You've got to build a tunnel before building roads through glaciers." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Syntax: MAGIEGEBIET [1-5]." + "$unit($unit) in $region($region): '$order($command)' - Syntax: MAGIC SPHERE [1-5]." + "$unit($unit) in $region($region): '$order($command)' - Syntax: MAGIC SPHERE [1-5]." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Deine Partei muss mindestens $int($turns) alt sein, um etwas an andere Parteien übergeben zu können." + "$unit($unit) in $region($region): '$order($command)' - Your faction must be at least $int($turns) weeks old to give something to another faction." + "$unit($unit) in $region($region): '$order($command)' - Your faction must be at least $int($turns) weeks old to give something to another faction." + + + + + + "Bitte sende die Befehle nächste Runde ein, wenn du weiterspielen möchtest." + "Merci d'envoyer vos ordres pour le tour suivant si vous désirez continuer à jouer." + "Please send in orders for the next turn if you want to continue playing." + + + + + + + "Deine Partei ist noch $int($turns) Wochen immun gegen Angriffe." + "Votre faction est immunisée contre les agressions durant $int($turns) semaines encore." + "Your faction is immune against assaults for $int($turns) more weeks." + + + + + + + + "$faction($member) ist mit $int($votes) Stimmen aus $alliance($alliance) ausgeschlossen worden." + "$faction($member) was kicked from $alliance($alliance) by $int($votes) of the alliance's members." + "$faction($member) was kicked from $alliance($alliance) by $int($votes) of the alliance's members." + + + + + + "$alliance($alliance) scheidet aus dem Spiel aus, nachdem alle Tempel verloren gingen." + "$alliance($alliance) has to leave the game after all their temples were lost." + "$alliance($alliance) has to leave the game after all their temples were lost." + + + + + + + "$int($votes) Mitglieder von $alliance($alliance) haben versucht, Deine Partei aus der Allianz auszuschliessen." + "$int($votes) members of $alliance($alliance) tried to kick you out of the alliance." + "$int($votes) members of $alliance($alliance) tried to kick you out of the alliance." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In dieser Regione können Pyramiden gebaut werden." + "$unit($unit) in $region($region): '$order($command)' - Pyramids may be build in this region." + "$unit($unit) in $region($region): '$order($command)' - Pyramids may be build in this region." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Auf $ship($ship) liegt beeits ein Zauber." + "$unit($unit) in $region($region): '$order($command)' - There is already a spell on $ship($ship)." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es ist zu gefährlich, diesen Zauber auf das fliegende Schiff $ship($ship) zu legen." + "$unit($unit) in $region($region): '$order($command)' - It is far too dangerous to put this spell on the flying ship $ship($ship)." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In dieser Region können keine Pyramiden gebaut werden. Die nächste Pyramidenregion ist zwischen $int($mindist) und $int($maxdist) Regionen entfernt." + "$unit($unit) in $region($region): '$order($command)' - No pyramids may be build in this region. The closest region to build a pyramid in is between $int($mindist) and $int($maxdist) regions away." + "$unit($unit) in $region($region): '$order($command)' - No pyramids may be build in this region. The closest region to build a pyramid in is between $int($mindist) and $int($maxdist) regions away." + + + + + + + + "$unit($unit) kann in $region($region) nicht durch das Wurmloch reisen, da die Einheit entweder zu gross ist oder teure Talente besitzt." + "$unit($unit) cannot travel through the wormhole in $region($region) because the unit is either too big or has restricted skills." + "$unit($unit) cannot travel through the wormhole in $region($region) because the unit is either too big or has restricted skills." + + + + + + + "$unit($unit) reist durch ein Wurmloch nach $region($region)." + "$unit($unit) travels through a wormhole to $region($region)." + "$unit($unit) travels through a wormhole to $region($region)." + + + + + + "In $region($region) erscheint ein Wurmloch." + "A wormhole appears in $region($region)." + "A wormhole appears in $region($region)." + + + + + + "Das Wurmloch in $region($region) schließt sich." + "The wormhole in $region($region) disappears." + "The wormhole in $region($region) disappears." + + + + + + + "$int($amount) Krieger von $unit($unit) benutzen ihre Flammenschwerter." + "$int($amount) fighters of $unit($unit) are using their flaming sword." + + + + + + + "$int($amount) Krieger von $unit($unit) feuern ihre Katapulte ab." + "$int($amount) fighters of $unit($unit) launch their catapults." + + + + + + "Der Kampf wurde ausgelöst von ${factions}." + "The battle was initiated by ${factions}." + + + + + + "$unit($unit) konnte durch einen Heiltrank überleben." + "$unit($unit) was saved by a haling potion." + + + + + + "$unit($unit) konnte dem Gegner eine Falle stellen." + "$unit($unit) lured the enemy into an ambush." + + + + + + "$unit($unit) überrascht den Gegner." + "$unit($unit) surprises the enemies." + + + + + + + "$unit($unit) versucht $spell($spell) zu zaubern, doch der Zauber schlägt fehl!" + "$unit($unit) tries to cast $spell($spell), but the spell fails!" + + + + + "Der Kampf wurde abgebrochen, da alle Verteidiger flohen." + "The battle was aborted because all enemies escaped." + + + + + + "... in der $int($row). Kampflinie:" + "... in combat rank $int($row):" + + + + + + + "$unit($mage) zaubert $spell($spell), aber niemand war in Reichweite." + "$unit($mage) casts $spell($spell), but nobody was in range." + + + + + + "Einheiten nach dem Kampf:" + "Units after the battle:" + + + + + + "" + "" + + + + + + + + + "$unit($mage) ruft $int($amount) $race($race, $amount) zu Hilfe." + "$unit($mage) calls for the help of $int($amount) $race($race, $amount)." + + + + + + + "$unit($mage) beschwört Trugbilder herauf." + "$unit($mage) summons a mirage." + + + + + + + "$unit($mage) murmelt eine düster klingende Formel. Ein plötzlicher Tumult entsteht, der sich jedoch schnell wieder legt." + + + + + + + "$unit($mage) murmelt eine düster klingende Formel. Ein plötzlicher Tumult entsteht und bringt die Kampfaufstellung durcheinander." + + + + + + + "$unit($mage) stimmt einen seltsamen Gesang an. Ein plötzlicher Tumult entsteht, der sich jedoch schnell wieder legt." + + + + + + + "$unit($mage) stimmt einen seltsamen Gesang an. Ein plötzlicher Tumult entsteht und bringt die Kampfaufstellung durcheinander." + "$unit($mage) begins a mysterious chant. great confusion sweeps through the ranks of the enemy." + + + + + + + + "$unit($mage) läßt die Mauern von $building($building) in einem unheimlichen magischen Licht erglühen." + + + + + + + "Einheiten vor der $int($turn). Runde:" + "Units before turn $int($turn):" + + + + + + "In $region($region) findet ein Kampf statt." + "There is a battle in $region($region)." + + + + + + + + "$unit($mage) zaubert $spell($spell): $int($dead) $if($eq($dead,1),"Krieger wurde", "Krieger wurden") getötet." + "$unit($mage) casts $spell($spell): $int($dead) $if($eq($dead,1),"enemy was", "enemies were") killed." + + + + + + + + "$unit($mage) läßt die Erde in $region($region) erzittern." + "$unit($mage) shakes the earth in $region($region)." + + + + + + + + "$unit($mage) verflucht das Land in $region($region), und eine Dürreperiode beginnt." + "$unit($mage) puts a curse on the lands of $region($region) and a drought sets in." + + + + + + + "$unit($mage) erschafft einen Klon." + "$unit($mage) creates a clone." + + + + + + + + + "$unit($mage) verliert sich in die Träume von $unit($unit) und erhält einen Eindruck von $region($region)." + + + + + + + + + "$unit($mage) verschafft $unit($unit) ein schönes Nachtleben in $region($region)." + + + + + + + + "$unit($mage) sorgt für schlechten Schlaf in $region($region)." + + + + + + + + + "$unit($mage) beschwört $int($amount) $race($race,$amount)." + "$unit($mage) summons $int($amount) $race($race,$amount)." + + + + + + + + + "$unit($mage) erschafft in $region($region) eine verheerende Feuersbrunst. $int($amount) Bäume fallen den Flammen zum Opfer." + "$unit($mage) creates a flaming inferno in $region($region). $int($amount) trees fall vistim to the flames." + + + + + + + + "Mit einem Ritual bindet $unit($mage) die magischen Kräfte der Erde in die Mauern von $building($building)." + + + + + + + + "$unit($mage) weight $building($building)." + "$unit($mage) blesses $building($building)." + + + + + + + + "$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Eis schmilzt und verwandelt sich in Morast. Reißende Ströme spülen die mageren Felder weg und ersäufen Mensch und Tier. Was an Bauten nicht den Fluten zum Opfer fiel, verschlingt der Morast. Die sengende Hitze verändert die Region für immer." + + + + + + + + "$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Die Felder verdorren und Pferde verdursten. Die Hungersnot kostet vielen Bauern das Leben. Vertrocknete Bäume recken ihre kahlen Zweige in den blauen Himmel, von dem erbarmungslos die sengende Sonne brennt." + + + + + + + + "$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Die Felder verdorren und Pferde verdursten. Die Hungersnot kostet vielen Bauern das Leben. Vertrocknete Bäume recken ihre kahlen Zweige in den blauen Himmel, von dem erbarmungslos die sengende Sonne brennt. Die Dürre verändert die Region für immer." + + + + + + + + "$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Das Eis zerbricht und eine gewaltige Flutwelle verschlingt die Region." + + + + "Die Darbietungen eines fahrenden Gauklers begeistern die Leute. Die fröhliche und ausgelassene Stimmung seiner Lieder überträgt sich auf alle Zuhörer." + "A touring minstrel entertains the locals. The joyous and generous disposition of his songs prove infectious." + + + + + + + "Die Darbietungen von $unit($mage) begeistern die Leute. Die fröhliche und ausgelassene Stimmung seiner Lieder überträgt sich auf alle Zuhörer." + "$unit($mage) entertains the locals. The joyous and generous disposition of his songs prove infectious." + + + "In der Luft liegt ein wunderschönes Lied, dessen friedfertiger Stimmung sich niemand entziehen kann. Einige Leute werfen sogar ihre Waffen weg." + "A wondrous song fills the air and enchants the public. The song's peaceful melody makes several listeners drop their weapon." + + + + + + "Die Gesangskunst von $unit($mage) begeistert die Leute. Die friedfertige Stimmung des Lieds überträgt sich auf alle Zuhörer. Einige werfen ihre Waffen weg." + "The marvelous singing of $unit($mage) enchants the public. The song's peaceful melody makes several listeners drop their weapon." + + + + + + + "$unit($mage) beschwört $int($number) Dämonen aus dem Reich der Schatten." + "$unit($mage) summons $int($number) demons from the realm of shadows." + + + + + + + + "$unit($mage) zaubert $spell($spell)." + "$unit($mage) casts $spell($spell)." + + + + + + + + + + "$unit($mage) zaubert $spell($spell). $int($amount) Krieger verloren Erinnerungen, $int($dead) wurden getötet." + + + + + + + + + "$unit($mage) zaubert $spell($spell). $int($amount) Krieger verloren kurzzeitig ihr Gedächtnis." + "$unit($mage) casts $spell($spell). $int($amount) fighters are temporarily losing some of their memories." + + + + + + + + + "$unit($mage) ruft $int($amount) $race($race, 0) zu Hilfe." + + + + + + + + "$unit($unit) tötete $int($dead) Krieger." + "$unit($unit) killed $int($dead) opponents." + + + + + + + + + + "Heer $int($index)($abbrev): $int($dead) Tote, $int($fled) Geflohene, $int($survived) Überlebende." + "Army $int($index)($abbrev): $int($dead) dead, $int($fled) fled, $int($survived) survivors." + + + + + + + + "$unit($mage) in $region($region): '$order($command)' - Dieser Zauber kann nicht mit Stufenangabe gezaubert werden." + "$unit($mage) in $region($region): '$order($command)' - This spell cannot be cast with variable level." + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dorthin führt kein Weg." + "$unit($unit) in $region($region): '$order($command)' - There is no way leading there." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Zu $region($target) kann kein Kontakt hergestellt werden." + "$unit($unit) in $region($region): '$order($command)' - $region($target) could not be contacted." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit $unit($target) hat keinen Kontakt mit uns aufgenommen." + "$unit($unit) in $region($region): '$order($command)' - The unit $unit($target) did not contact us." + + + + + + + + + "Antimagie von $unit.dative($self) blockiert in $region($region) einen Zauber von $unit.dative($mage)." + "In $region($region), anti-magic from $unit($self) blocks the spell of $unit($mage)." + + + + + + + + + "$unit($self) schwächt in $region($region) einen Zauber von $unit.dative($mage) durch Antimagie ab." + "In $region($region), anti-magic from $unit($self) reduces the effect of $unit($mage)'s spell." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $int($pacified) Regionen wurden befriedet." + "$unit($unit) in $region($region): '$order($command)' - $int($pacified) regions have been pacified." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Keine Region konnte befriedet werden." + "$unit($unit) in $region($region): '$order($command)' - No region could be pacified." + + + + + + + + "$unit($unit) in $region($region) bläst das Horn des Tanzes. In der ganzen Region breitet sich eine friedliche Feststimmmung aus." + "$unit($unit) in $region($region) blows the Horn of Dancing. Peaceful harmony spreads over the region." + + + + + + + + "$unit($unit) in $region($region) bläst das Horn des Tanzes, doch niemand hier lässt sich von Stimmung anstecken." + "$unit($unit) in $region($region) blows the Horn of Dancing, but nobody here gets into the mood." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die $ship($ship) wird jetzt schneller ihr Ziel erreichen." + "$unit($unit) in $region($region): '$order($command)' - The $ship($ship) will now be faster." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Magier fühlt sich durch den Trank magische gestärkt." + "$unit($unit) in $region($region): '$order($command)' - The mage is magically invigorated." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Ausser sich vor Furcht geben die Bauern dem Barden $int($money) Silber." + "$unit($unit) in $region($region): '$order($command)' - Stricken with fear the peasants give the bard $int($money) silver." + + + + + + + + "$unit($unit) spielt einen Dudelsack. Ausser sich vor Furcht geben die Bauern $int($money) Silber." + "$unit($unit) plays the bagpipe. Stricken with fear the peasants give $int($money) silver." + + + + + + + + "$unit($unit) in $region($region) erschafft eine Akademie der Künste." + "$unit($unit) in $region($region) creates an academy of arts." + + + + + + + + "$unit($unit) in $region($region) erschafft eine Skulptur." + "$unit($unit) in $region($region) creates a sculpture." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Region ist zu weit entfernt." + "$unit($unit) in $region($region): '$order($command)' - That region is too far away." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Wege aus dieser Region sind blockiert." + "$unit($unit) in $region($region): '$order($command)' - The connections from to this regions are blocked." + + + + + + + "$unit($unit) erscheint plötzlich." + "$unit($unit) appears." + + + + + + + "$unit($unit) wird durchscheinend und verschwindet." + "$unit($unit) disappears." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) ist zu schwer." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) is too heavy." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Partei hat bereits $int($count) von $int($max) Helden." + "$unit($unit) in $region($region): '$order($command)' - The faction already has $int($count) of $int($max) heroes." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können keine Helden erwählen." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot be heroes." + + + + + + + + "$unit($unit) wird mit $int($cost) Silber zum Helden ernannt." + "$unit($unit) uses $int($cost) silber for a promotion." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Einheit hat nur $int($have) von $int($cost) benötigtem Silber." + "$unit($unit) in $region($region): '$order($command)' - The unit has $int($have) of $int($cost) silver required." + + + + + + + "Eine gewaltige Flutwelle verschlingt $region($region) und alle Bewohner." + "A tidal wave wipes out $region($region) and all who lived there." + + + + + + + + "Eine gewaltige Flutwelle verschlingt $unit($unit) in $region($region)." + "A tidal wave wipes out $region($region) and kills $unit($unit)." + + + + + + + + "$unit($unit) reaktiviert den astralen Schutzschild in $region($region)." + "$unit($unit) reactivates the astral protection shield in $region($region)." + + + + + + + + + + "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"kehrte auf seine", "kehrten auf ihre") Felder zurück." + "$unit($unit) in $region($region): $int($number) $race($race,$number) returned to the fields." + + + + + + + + + + "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"wurde zum Baum", "wurden zu Bäumen")." + "$unit($unit) in $region($region): $int($number) $race($race,$number) turned into $if($eq($number,1),"a tree", "trees")." + + + + + + + + + + "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"verfaulte", "verfaulten")." + "$unit($unit) in $region($region): $int($number) $race($race,$number) whithered and died." + + + + + + + + + + "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"zerfiel", "zerfielen") zu Staub." + "$unit($unit) in $region($region): $int($number) $race($race,$number) turned to dust." + + + + + + + + + + "$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),"verschwand", "verschwanden") über Nacht." + "$unit($unit) in $region($region): $int($number) $race($race,$number) disappearedin the night." + + + + + + + + + "Der Waldbrand in $region($region) griff auch auf $region($next) über, und $int($trees) verbrannten." + "The fire in $region($region) spread to $region($next) and $int($trees) were burnt." + + + + + + + + "$unit($mage) ruft in $region($region) eine Pest hervor." + "$unit($mage) sends the plague on $region($region)." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Eine Partei darf nicht aus mehr als $int($allowed) Einheiten bestehen." + "$unit($unit) in $region($region): '$order($command)' - A faction may not consist of more than $int($allowed) units." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Eine Allianz darf aus nicht mehr als $int($allowed) Einheiten bestehen." + "$unit($unit) in $region($region): '$order($command)' - An alliance may not consist of more than $int($allowed) units." + + + + + + + + + + "$unit($unit) in $region($region): $int($amount) $resource($item,$amount) zerfallen zu Staub." + "$unit($unit) in $region($region): $int($amount) $resource($item,$amount) turn to dust." + + + + + + + + + "Die $ship($ship) ist mit gutem Wind gesegnet$if($lt($duration,3),", doch der Zauber beginnt sich bereits aufzulösen",""). ($int36($id))" + "The $ship($ship) is blessed with favourable winds$if($lt($duration,3),", but the spell is starting to wear thin",""). ($int36($id))" + + + + + + + "Kräftige Stürme haben dieses Schiff in die Luft gehoben. ($int36($id))" + "Powerful storms have lifted this ship high into the air. ($int36($id))" + + + + + + + "Mächtige Magie verhindert den Kontakt zur Realität. ($int36($id))" + "Powerful magic disrupts our contact with reality. ($int36($id))" + + + + + + + + "Ein silberner Schimmer umgibt die $ship($ship). ($int36($id))" + "A silvery shimmer surrounds the $ship($ship). ($int36($id))" + + + + + + + + "Auf den Mauern von $building($building) erkennt man seltsame Runen. ($int36($id))" + "The walls of $building($building) are inscribed with strange runes. ($int36($id))" + + + + + + + + + "$unit($mage) erschafft $int($number) $resource($item,$number)." + "$unit($mage) creates $int($number) $resource($item,$number)." + + + + + + + + "Auf den Planken von $ship($ship) erkennt man seltsame Runen. ($int36($id))" + "The plank of $ship($ship) are inscribed with strange runes. ($int36($id))" + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Kompassnadel springt wild hin und her und es lässt sich keine Richtung erkennen." + "$unit($unit) in $region($region): '$order($command)' - The needle jumps wildly and there is no specific direction recognizable." + "$unit($unit) in $region($region): '$order($command)' - The needle jumps wildly and there is no specific direction recognizable." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Die Kompassnadel zeigt nach $direction($dir)." + "$unit($unit) in $region($region): '$order($command)' - The needle points $direction($dir)." + "$unit($unit) in $region($region): '$order($command)' - The needle points $direction($dir)." + + + + + + + + "$unit($unit) wird aus der astralen Ebene nach $region($region) geschleudert." + "$unit($unit) is sent from the astral plain to $region($region)." + "$unit($unit) is sent from the astral plain to $region($region)." + + + + + + + + "$unit($target) wird von $unit($unit) in eine andere Welt geschleudert." + "$unit($unit) sends $unit($target) to another world." + "$unit($unit) sends $unit($target) to another world." + + + + + + + + "$unit($unit) versuchte erfolglos, $unit($target) in eine andere Welt zu schleudern." + "$unit($unit) tried but failed to send $unit($target) to another world." + "$unit($unit) tried but failed to send $unit($target) to another world." + + + + + + + "NUMMER PARTEI $int36($id): Die Partei kann nicht mehr als einmal ihre Nummer wecheln." + "NUMBER FACTION $int36($id): Your faction can only change its number once." + + + + + + + "NUMMER PARTEI $int36($id): Diese Nummer wird von einer anderen Partei benutzt." + "NUMBER FACTION $int36($id): This number is being used by another faction." + + + + + + + + "Eine Botschaft von $unit($unit): '$message'" + "A message from $unit($unit): '$message'" + + + + + + + + "Plötzlich stolpert $unit($unit) über einige $localize($name). Nach kurzem Zögern entschließen die $localize($name), sich Deiner Partei anzuschließen." + + + + + + + "$unit($unit) entdeckt ein kleines Dorf. Die meisten Häuser wurden durch einen über die Ufer getretenen Fluß zerstört. Eine Gruppe der verzweifelten Menschen schließt sich deiner Partei an." + "$unit($unit) discovers a small village. Most of the houses have been destroyed by flooding, and a group of the distressed villagers join your faction." + + + + "Ein Bauernmob erhebt sich und macht Jagd auf Schwarzmagier." + "An angry mob forms and hunts practitioners of the dark arts." + + + + + + + "Vertrauter von $unit($unit)" + "Familiar of $unit($unit)" + + + + + + + + + "$unit($unit) rekrutiert $int($amount) $localize($archetype)." + "$unit($unit) recruits $int($amount) $localize($archetype)." + + + + + + + "Dein Passwort enthält Zeichen, die bei der Nachsendung von Reports Probleme bereiten können. Bitte beachte, dass Passwortenur aus Buchstaben von A bis Z und Zahlen bestehen dürfen. Dein neues Passwort ist '${newpass}'." + "Your password was changed because it contained illegal characters. Legal passwords may only contain numbers and letters from A to Z. Your new Password is '${newpass}'." + + + + "Miiauuuuuu..." + "Meeoooooow..." + + + + + + + "Die Götter segnen $unit($unit) mit der richtigen Rasse." + "The gods are blessing $unit($unit) with the correct race." + + + + + + + "Der Versuch, die Greifenschwingen zu benutzen, schlug fehl. $unit($unit) konnte die Ebene der Herausforderung nicht verlassen." + + + + + + + "$unit($unit) springt in die ewigen Feuer des Kraters." + + + + + + + + "$unit($unit) springt in die ewigen Feuer des Kraters." + + + + + + + + "In $region($region) erklingt die Stimme des Torwächters: 'Nur wer ohne materielle Güter und noch lernbegierig ist, der darf die Ebene der Herausforderung betreten. Und vergiß nicht mein Trinkgeld.'. $unit($unit) erhielt keinen Einlaß." + + + + + + + + "In $region($region) öffnet sich ein Portal. Eine Stimme ertönt, und spricht: 'Willkommen in der Ebene der Herausforderung'. $unit($unit) durchschreitet das Tor zu einer anderen Welt." + + + + + + + "$unit($unit) scheint von einer seltsamen Krankheit befallen." + "$unit($unit) is stricken by a strange disease." + + + + + + + + + "$unit($unit) erbeutet $int($amount) $resource($item,$amount)." + "$unit($unit) collects $int($amount) $resource($item,$amount)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es ist so schön friedlich, man möchte hier niemanden angreifen." + "$unit($unit) in $region($region): '$order($command)' - It's so quiet and peaceful, nobody wants to attack anybody right now." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) können nichts lernen." + "$unit($unit) in $region($region): '$order($command)' - $race($race,0) cannot study." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Migranten können keine kostenpflichtigen Talente lernen." + "$unit($unit) in $region($region): '$order($command)' - Migrants cannot study this." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es kann maximal $int($amount) Magier pro Partei geben." + "$unit($unit) in $region($region): '$order($command)' - There may not be more tha $int($amount) magicians in your faction." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Es kann maximal $int($amount) Alchemisten pro Partei geben." + "$unit($unit) in $region($region): '$order($command)' - There may not be more tha $int($amount) alchemists in your faction." + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - $unit($target) versteht unsere Art von Magie nicht." + "$unit($unit) in $region($region): '$order($command)' - $unit($target) does not understand our kind of magic." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Der Kapitän muß ein Segeltalent von mindestens $int($value) haben, um $ship($ship) zu befehligen." + "$unit($unit) in $region($region): '$order($command)' - The captain needs a sailing skill of at least $int($value), to command $ship($ship)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - In dieser Region gibt es keine Brücken und Straßen mehr zu bauen." + "$unit($unit) in $region($region): '$order($command)' - the roads and bridges in this region are complete." + + + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Um $localize($name) zu bauen, braucht man ein Talent von mindestens $int($value)." + "$unit($unit) in $region($region): '$order($command)' - To build $localize($name) requires a skill of at least $int($value)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Diese Einheit kämpft nicht." + "$unit($unit) in $region($region): '$order($command)' - This unit will not fight." + + + + + + + + + "$unit($unit) erhielt $resources($items) von der $ship($ship)." + "$unit($unit) received $resources($items) from the $ship($ship)." + + + + + + + + + "$unit($unit) in $region($region): '$order($command)' - Dieser Zauber kann nciht auf Untote gezaubert werden." + + + + + + + + "Achtung: $faction($faction) hat seit $int($turns) Wochen keine + Züge eingeschickt und könnte dadurch in Kürze aus dem Spiel + ausscheiden." + "Warning: $faction($faction) has not been sending in + orders for $int($turns) turns and may be leaving the game soon." + + + diff --git a/res/prefixes.xml b/res/prefixes.xml index 596c16afe..0e8e9587a 100644 --- a/res/prefixes.xml +++ b/res/prefixes.xml @@ -1,31 +1,31 @@ - - - Dunkel - Licht - Klein - Hoch - Huegel - Berg - Wald - Sumpf - Schnee - Sonnen - Mond - See - Tal - Schatten - Hoehlen - Blut - Wild - Chaos - Nacht - Nebel - Grau - Frost - Finster - Duester - flame - ice - star - black - + + + Dunkel + Licht + Klein + Hoch + Huegel + Berg + Wald + Sumpf + Schnee + Sonnen + Mond + See + Tal + Schatten + Hoehlen + Blut + Wild + Chaos + Nacht + Nebel + Grau + Frost + Finster + Duester + flame + ice + star + black + diff --git a/res/resources/horse.xml b/res/resources/horse.xml index b5498ab2a..abf6d856d 100644 --- a/res/resources/horse.xml +++ b/res/resources/horse.xml @@ -1,11 +1,11 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/res/resources/hp.xml b/res/resources/hp.xml index 95ff2200b..fb1b6e32f 100644 --- a/res/resources/hp.xml +++ b/res/resources/hp.xml @@ -1,5 +1,5 @@ - - - - - + + + + + diff --git a/res/resources/iron.xml b/res/resources/iron.xml index 89ae30198..94dbc6390 100644 --- a/res/resources/iron.xml +++ b/res/resources/iron.xml @@ -1,12 +1,12 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/res/resources/laen.xml b/res/resources/laen.xml index 1814bbf1a..efb13c5ed 100644 --- a/res/resources/laen.xml +++ b/res/resources/laen.xml @@ -1,10 +1,10 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/res/resources/log.xml b/res/resources/log.xml index a1b719c33..c017682fc 100644 --- a/res/resources/log.xml +++ b/res/resources/log.xml @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/res/resources/mallorn.xml b/res/resources/mallorn.xml index faddfde3e..e5c01506b 100644 --- a/res/resources/mallorn.xml +++ b/res/resources/mallorn.xml @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/res/resources/mallornseed.xml b/res/resources/mallornseed.xml index 25b0c2cf8..1c7c1a800 100644 --- a/res/resources/mallornseed.xml +++ b/res/resources/mallornseed.xml @@ -1,6 +1,6 @@ - - - - - - + + + + + + diff --git a/res/resources/peasant.xml b/res/resources/peasant.xml index ab60d333e..32e1e1ca1 100644 --- a/res/resources/peasant.xml +++ b/res/resources/peasant.xml @@ -1,5 +1,5 @@ - - - - - + + + + + diff --git a/res/resources/seed.xml b/res/resources/seed.xml index 62efedf4e..2193fb8c8 100644 --- a/res/resources/seed.xml +++ b/res/resources/seed.xml @@ -1,6 +1,6 @@ - - - - - - + + + + + + diff --git a/res/resources/stone.xml b/res/resources/stone.xml index 2ea5401c1..eed2fd2df 100644 --- a/res/resources/stone.xml +++ b/res/resources/stone.xml @@ -1,11 +1,11 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/res/ships.xml b/res/ships.xml index 763fee3f3..6c6821be4 100644 --- a/res/ships.xml +++ b/res/ships.xml @@ -1,83 +1,83 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/spells.xml b/res/spells.xml index 72f834bba..080365c55 100644 --- a/res/spells.xml +++ b/res/spells.xml @@ -1,204 +1,204 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/spoils.xml b/res/spoils.xml index 585372527..952971cab 100644 --- a/res/spoils.xml +++ b/res/spoils.xml @@ -1,59 +1,59 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/terrains.xml b/res/terrains.xml index d3896193b..edd8895ab 100644 --- a/res/terrains.xml +++ b/res/terrains.xml @@ -1,84 +1,84 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/weapons/axe.xml b/res/weapons/axe.xml index 5f784865d..7ee77b21e 100644 --- a/res/weapons/axe.xml +++ b/res/weapons/axe.xml @@ -1,14 +1,14 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/res/weapons/bow.xml b/res/weapons/bow.xml index 0e57cfdf9..c64392966 100644 --- a/res/weapons/bow.xml +++ b/res/weapons/bow.xml @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/res/weapons/catapult.xml b/res/weapons/catapult.xml index 4ae3324da..2ea16d9a2 100644 --- a/res/weapons/catapult.xml +++ b/res/weapons/catapult.xml @@ -1,14 +1,14 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/res/weapons/crossbow.xml b/res/weapons/crossbow.xml index 76e7e36ff..318628b81 100644 --- a/res/weapons/crossbow.xml +++ b/res/weapons/crossbow.xml @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/res/weapons/firesword.xml b/res/weapons/firesword.xml index 72dbb11d1..9e8284fe6 100644 --- a/res/weapons/firesword.xml +++ b/res/weapons/firesword.xml @@ -1,10 +1,10 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/res/weapons/greatbow.xml b/res/weapons/greatbow.xml index 0af009a6b..542bd41a8 100644 --- a/res/weapons/greatbow.xml +++ b/res/weapons/greatbow.xml @@ -1,18 +1,18 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/res/weapons/greatsword.xml b/res/weapons/greatsword.xml index ed1ea5118..481ff680c 100644 --- a/res/weapons/greatsword.xml +++ b/res/weapons/greatsword.xml @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/res/weapons/halberd.xml b/res/weapons/halberd.xml index 0875f69c5..bf3fb4af7 100644 --- a/res/weapons/halberd.xml +++ b/res/weapons/halberd.xml @@ -1,15 +1,15 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/res/weapons/laensword.xml b/res/weapons/laensword.xml index cc037f11a..31ec8b9e6 100644 --- a/res/weapons/laensword.xml +++ b/res/weapons/laensword.xml @@ -1,12 +1,12 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/res/weapons/lance.xml b/res/weapons/lance.xml index 31146f7ce..1271c48f9 100644 --- a/res/weapons/lance.xml +++ b/res/weapons/lance.xml @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/res/weapons/mallornbow.xml b/res/weapons/mallornbow.xml index 12c6e374b..f61ea8e97 100644 --- a/res/weapons/mallornbow.xml +++ b/res/weapons/mallornbow.xml @@ -1,16 +1,16 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/res/weapons/mallorncrossbow.xml b/res/weapons/mallorncrossbow.xml index ddf501046..8d4a5027b 100644 --- a/res/weapons/mallorncrossbow.xml +++ b/res/weapons/mallorncrossbow.xml @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/res/weapons/mallornlance.xml b/res/weapons/mallornlance.xml index 20ec02b93..88973f3e0 100644 --- a/res/weapons/mallornlance.xml +++ b/res/weapons/mallornlance.xml @@ -1,13 +1,13 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/res/weapons/mallornspear.xml b/res/weapons/mallornspear.xml index e0680bd6c..8c3782e4c 100644 --- a/res/weapons/mallornspear.xml +++ b/res/weapons/mallornspear.xml @@ -1,14 +1,14 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/res/weapons/rep_crossbow.xml b/res/weapons/rep_crossbow.xml index 98b64dc37..1e550a190 100644 --- a/res/weapons/rep_crossbow.xml +++ b/res/weapons/rep_crossbow.xml @@ -1,16 +1,16 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/res/weapons/runesword.xml b/res/weapons/runesword.xml index 9f99df003..566fe1589 100644 --- a/res/weapons/runesword.xml +++ b/res/weapons/runesword.xml @@ -1,10 +1,10 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/res/weapons/rustyaxe.xml b/res/weapons/rustyaxe.xml index 73905f0e7..5399de62d 100644 --- a/res/weapons/rustyaxe.xml +++ b/res/weapons/rustyaxe.xml @@ -1,14 +1,14 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/res/weapons/rustygreatsword.xml b/res/weapons/rustygreatsword.xml index 736a40172..ac1385b11 100644 --- a/res/weapons/rustygreatsword.xml +++ b/res/weapons/rustygreatsword.xml @@ -1,12 +1,12 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/res/weapons/rustyhalberd.xml b/res/weapons/rustyhalberd.xml index 9c227ad62..4f237b989 100644 --- a/res/weapons/rustyhalberd.xml +++ b/res/weapons/rustyhalberd.xml @@ -1,15 +1,15 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/res/weapons/rustysword.xml b/res/weapons/rustysword.xml index be139b8df..f73dcd6e2 100644 --- a/res/weapons/rustysword.xml +++ b/res/weapons/rustysword.xml @@ -1,12 +1,12 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/res/weapons/spear.xml b/res/weapons/spear.xml index 4f628408d..c6479707a 100644 --- a/res/weapons/spear.xml +++ b/res/weapons/spear.xml @@ -1,14 +1,14 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/res/weapons/sword.xml b/res/weapons/sword.xml index 0276acb39..0d3830e2e 100644 --- a/res/weapons/sword.xml +++ b/res/weapons/sword.xml @@ -1,12 +1,12 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/scripts/callbacks.lua b/scripts/callbacks.lua index 636607829..33d34e4b5 100644 --- a/scripts/callbacks.lua +++ b/scripts/callbacks.lua @@ -1,11 +1,11 @@ -callbacks = {} - -callbacks["attrib_init"] = function(attr) - if attr.name ~= nil then - local init = callbacks["init_" .. attr.name] - if init ~=nil then - init(attr) - end - end -end - +callbacks = {} + +callbacks["attrib_init"] = function(attr) + if attr.name ~= nil then + local init = callbacks["init_" .. attr.name] + if init ~=nil then + init(attr) + end + end +end + diff --git a/scripts/default.lua b/scripts/default.lua index fd6361db6..7afd5fa8b 100644 --- a/scripts/default.lua +++ b/scripts/default.lua @@ -1,121 +1,121 @@ -function change_locales(localechange) - for loc, flist in pairs(localechange) do - for index, name in pairs(flist) do - f = get_faction(atoi36(name)) - if f ~= nil then - f.locale = loc - print("LOCALECHANGE ", f, loc) - end - end - end -end - -function dbupdate() - update_scores() - edb = db.open(config.basepath.."/eressea.db") - if edb~=nil then - edb:update_factions() - edb:update_scores() - else - print("could no open "..config.basepath.."/eressea.db") - end -end - -function nmr_check(maxnmrs) - local nmrs = get_nmrs(1) - if nmrs >= maxnmrs then - print("Shit. More than " .. maxnmrs .. " factions with 1 NMR (" .. nmrs .. ")") - write_summary() - write_game("aborted.dat") - return -1 - end - print (nmrs .. " Factions with 1 NMR") - return 0 -end - -function open_game(turn) - file = "" .. get_turn() - if read_game(file .. ".dat", "binary")~=0 then - return read_game(file, "text") - end - return 0 -end - -function write_emails(locales) - local files = {} - local key - local locale - local file - for key, locale in pairs(locales) do - files[locale] = io.open(config.basepath .. "/emails." .. locale, "w") - end - - local faction - for faction in factions() do - if faction.email~="" then - files[faction.locale]:write(faction.email .. "\n") - end - end - - for key, file in pairs(files) do - file:close() - end -end - -function write_addresses() - local file - local faction - - file = io.open(config.basepath .. "/adressen", "w") - for faction in factions() do - -- print(faction.id .. " - " .. faction.locale) - file:write(tostring(faction) .. ":" .. faction.email .. ":" .. faction.info .. "\n") - end - - file:close() -end - -function write_aliases() - local file - local faction - - file = io.open(config.basepath .. "/aliases", "w") - for faction in factions() do - local unit - if faction.email ~= "" then - file:write("partei-" .. itoa36(faction.id) .. ": " .. faction.email .. "\n") - for unit in faction.units do - file:write("einheit-" .. itoa36(unit.id) .. ": " .. faction.email .. "\n") - end - end - end - - file:close() -end - -function write_files(locales) - write_passwords() - write_reports() - write_summary() - -- write_emails(locales) - -- write_aliases() - -- write_addresses() -end - -function write_scores() - scores = {} - for r in regions() do - f = r.owner - if f~=nil then - value = scores[f.id] - if value==nil then value=0 end - value = value + r:get_resource("money")/100 - scores[f.id] = value - end - end - for f in factions() do - score=scores[f.id] - if score==nil then score=0 end - print(math.floor(score)..":"..f.name..":"..itoa36(f.id)) - end -end +function change_locales(localechange) + for loc, flist in pairs(localechange) do + for index, name in pairs(flist) do + f = get_faction(atoi36(name)) + if f ~= nil then + f.locale = loc + print("LOCALECHANGE ", f, loc) + end + end + end +end + +function dbupdate() + update_scores() + edb = db.open(config.basepath.."/eressea.db") + if edb~=nil then + edb:update_factions() + edb:update_scores() + else + print("could no open "..config.basepath.."/eressea.db") + end +end + +function nmr_check(maxnmrs) + local nmrs = get_nmrs(1) + if nmrs >= maxnmrs then + print("Shit. More than " .. maxnmrs .. " factions with 1 NMR (" .. nmrs .. ")") + write_summary() + write_game("aborted.dat") + return -1 + end + print (nmrs .. " Factions with 1 NMR") + return 0 +end + +function open_game(turn) + file = "" .. get_turn() + if read_game(file .. ".dat", "binary")~=0 then + return read_game(file, "text") + end + return 0 +end + +function write_emails(locales) + local files = {} + local key + local locale + local file + for key, locale in pairs(locales) do + files[locale] = io.open(config.basepath .. "/emails." .. locale, "w") + end + + local faction + for faction in factions() do + if faction.email~="" then + files[faction.locale]:write(faction.email .. "\n") + end + end + + for key, file in pairs(files) do + file:close() + end +end + +function write_addresses() + local file + local faction + + file = io.open(config.basepath .. "/adressen", "w") + for faction in factions() do + -- print(faction.id .. " - " .. faction.locale) + file:write(tostring(faction) .. ":" .. faction.email .. ":" .. faction.info .. "\n") + end + + file:close() +end + +function write_aliases() + local file + local faction + + file = io.open(config.basepath .. "/aliases", "w") + for faction in factions() do + local unit + if faction.email ~= "" then + file:write("partei-" .. itoa36(faction.id) .. ": " .. faction.email .. "\n") + for unit in faction.units do + file:write("einheit-" .. itoa36(unit.id) .. ": " .. faction.email .. "\n") + end + end + end + + file:close() +end + +function write_files(locales) + write_passwords() + write_reports() + write_summary() + -- write_emails(locales) + -- write_aliases() + -- write_addresses() +end + +function write_scores() + scores = {} + for r in regions() do + f = r.owner + if f~=nil then + value = scores[f.id] + if value==nil then value=0 end + value = value + r:get_resource("money")/100 + scores[f.id] = value + end + end + for f in factions() do + score=scores[f.id] + if score==nil then score=0 end + print(math.floor(score)..":"..f.name..":"..itoa36(f.id)) + end +end diff --git a/scripts/dumptable.lua b/scripts/dumptable.lua index ecddbdfa0..58f10e8df 100644 --- a/scripts/dumptable.lua +++ b/scripts/dumptable.lua @@ -1,95 +1,95 @@ ---------------------------------------------- --- Return indentation string for passed level ---------------------------------------------- -local function tabs(i) - return string.rep(".",i).." " -- Dots followed by a space -end - ------------------------------------------------------------ --- Return string representation of parameter's value & type ------------------------------------------------------------ -local function toStrType(t) - local function fttu2hex(t) -- Grab hex value from tostring() output - local str = tostring(t); - if str == nil then - return "tostring() failure! \n" - else - local str2 = string.match(str,"[ :][ (](%x+)") - if str2 == nil then - return "string.match() failure: "..str.."\n" - else - return "0x"..str2 - end - end - end - -- Stringify a value of a given type using a table of functions keyed - -- by the name of the type (Lua's version of C's switch() statement). - local stringify = { - -- Keys are all possible strings that type() may return, - -- per http://www.lua.org/manual/5.1/manual.html#pdf-type. - ["nil"] = function(v) return "nil (nil)" end, - ["string"] = function(v) return '"'..v..'" (string)' end, - ["number"] = function(v) return v.." (number)" end, - ["boolean"] = function(v) return tostring(v).." (boolean)" end, - ["function"] = function(v) return fttu2hex(v).." (function)" end, - ["table"] = function(v) return fttu2hex(v).." (table)" end, - ["thread"] = function(v) return fttu2hex(v).." (thread)" end, - ["userdata"] = function(v) return fttu2hex(v).." (userdata)" end - } - return stringify[type(t)](t) -end - -------------------------------------- --- Count elements in the passed table -------------------------------------- -local function lenTable(t) -- What Lua builtin does this simple thing? - local n=0 -- '#' doesn't work with mixed key types - if ("table" == type(t)) then - for key in pairs(t) do -- Just count 'em - n = n + 1 - end - return n - else - return nil - end -end - --------------------------------- --- Pretty-print the passed table --------------------------------- -local function do_dumptable(t, indent, seen) - -- "seen" is an initially empty table used to track all tables - -- that have been dumped so far. No table is dumped twice. - -- This also keeps the code from following self-referential loops, - -- the need for which was found when first dumping "_G". - if ("table" == type(t)) then -- Dump passed table - seen[t] = 1 - if (indent == 0) then - print ("The passed table has "..lenTable(t).." entries:") - indent = 1 - end - for f,v in pairsByKeys(t) do - if ("table" == type(v)) and (seen[v] == nil) then -- Recurse - print( tabs(indent)..toStrType(f).." has "..lenTable(v).." entries: {") - do_dumptable(v, indent+1, seen) - print( tabs(indent).."}" ) - else - print( tabs(indent)..toStrType(f).." = "..toStrType(v)) - end - end - else - print (tabs(indent).."Not a table!") - end -end - --------------------------------- --- Wrapper to handle persistence --------------------------------- -function dumptable(t) -- Only global declaration in the package - -- This wrapper exists only to set the environment for the first run: - -- The second param is the indentation level. - -- The third param is the list of tables dumped during this call. - -- Getting this list allocated and freed was a pain, and this - -- wrapper was the best solution I came up with... - return do_dumptable(t, 0, {}) -end +--------------------------------------------- +-- Return indentation string for passed level +--------------------------------------------- +local function tabs(i) + return string.rep(".",i).." " -- Dots followed by a space +end + +----------------------------------------------------------- +-- Return string representation of parameter's value & type +----------------------------------------------------------- +local function toStrType(t) + local function fttu2hex(t) -- Grab hex value from tostring() output + local str = tostring(t); + if str == nil then + return "tostring() failure! \n" + else + local str2 = string.match(str,"[ :][ (](%x+)") + if str2 == nil then + return "string.match() failure: "..str.."\n" + else + return "0x"..str2 + end + end + end + -- Stringify a value of a given type using a table of functions keyed + -- by the name of the type (Lua's version of C's switch() statement). + local stringify = { + -- Keys are all possible strings that type() may return, + -- per http://www.lua.org/manual/5.1/manual.html#pdf-type. + ["nil"] = function(v) return "nil (nil)" end, + ["string"] = function(v) return '"'..v..'" (string)' end, + ["number"] = function(v) return v.." (number)" end, + ["boolean"] = function(v) return tostring(v).." (boolean)" end, + ["function"] = function(v) return fttu2hex(v).." (function)" end, + ["table"] = function(v) return fttu2hex(v).." (table)" end, + ["thread"] = function(v) return fttu2hex(v).." (thread)" end, + ["userdata"] = function(v) return fttu2hex(v).." (userdata)" end + } + return stringify[type(t)](t) +end + +------------------------------------- +-- Count elements in the passed table +------------------------------------- +local function lenTable(t) -- What Lua builtin does this simple thing? + local n=0 -- '#' doesn't work with mixed key types + if ("table" == type(t)) then + for key in pairs(t) do -- Just count 'em + n = n + 1 + end + return n + else + return nil + end +end + +-------------------------------- +-- Pretty-print the passed table +-------------------------------- +local function do_dumptable(t, indent, seen) + -- "seen" is an initially empty table used to track all tables + -- that have been dumped so far. No table is dumped twice. + -- This also keeps the code from following self-referential loops, + -- the need for which was found when first dumping "_G". + if ("table" == type(t)) then -- Dump passed table + seen[t] = 1 + if (indent == 0) then + print ("The passed table has "..lenTable(t).." entries:") + indent = 1 + end + for f,v in pairsByKeys(t) do + if ("table" == type(v)) and (seen[v] == nil) then -- Recurse + print( tabs(indent)..toStrType(f).." has "..lenTable(v).." entries: {") + do_dumptable(v, indent+1, seen) + print( tabs(indent).."}" ) + else + print( tabs(indent)..toStrType(f).." = "..toStrType(v)) + end + end + else + print (tabs(indent).."Not a table!") + end +end + +-------------------------------- +-- Wrapper to handle persistence +-------------------------------- +function dumptable(t) -- Only global declaration in the package + -- This wrapper exists only to set the environment for the first run: + -- The second param is the indentation level. + -- The third param is the list of tables dumped during this call. + -- Getting this list allocated and freed was a pain, and this + -- wrapper was the best solution I came up with... + return do_dumptable(t, 0, {}) +end diff --git a/scripts/gates.lua b/scripts/gates.lua index e02c0f326..aeb1e2a3c 100644 --- a/scripts/gates.lua +++ b/scripts/gates.lua @@ -1,25 +1,25 @@ --- implements gates and travel between them --- used in HSE and Eressea - -function gate_travel(b, units) - -- we've found which units we want to exchange, now swap them: - local u - for key, u in pairs(units) do - u.region = b.region - u.building = b - end -end - -function gate_units(b, maxsize) - local size = maxsize - local units = {} - local u - - for u in b.units do - if u.number<=size and u.weight<=u.capacity then - units[u] = u - size = size - u.number - end - end - return units -end +-- implements gates and travel between them +-- used in HSE and Eressea + +function gate_travel(b, units) + -- we've found which units we want to exchange, now swap them: + local u + for key, u in pairs(units) do + u.region = b.region + u.building = b + end +end + +function gate_units(b, maxsize) + local size = maxsize + local units = {} + local u + + for u in b.units do + if u.number<=size and u.weight<=u.capacity then + units[u] = u + size = size - u.number + end + end + return units +end diff --git a/scripts/init.lua b/scripts/init.lua index 0b9c150c6..ae39c50b2 100644 --- a/scripts/init.lua +++ b/scripts/init.lua @@ -1,43 +1,43 @@ -require(config.game .. ".modules") -require "default" -require "resources" - -function run_editor() - local turn = get_turn() - if turn==0 then - turn = read_turn() - set_turn(turn) - end - read_game(turn .. ".dat") - gmtool.editor() -end - -function run_tests() - print("running tests") - require "lunit" - lunit.clearstats() - local argv = tests or {} - local stats = lunit.main(argv) - if stats.errors > 0 or stats.failed > 0 then - return 1 - end - return 0 -end - -function run_turn() - require(config.game .. ".main") - - local turn = get_turn() - if turn==0 then - turn = read_turn() - set_turn(turn) - end - - orderfile = orderfile or config.basepath .. '/orders.' .. turn - print("executing turn " .. get_turn() .. " with " .. orderfile) - local result = process(orderfile) - if result==0 then - dbupdate() - end - return result -end +require(config.game .. ".modules") +require "default" +require "resources" + +function run_editor() + local turn = get_turn() + if turn==0 then + turn = read_turn() + set_turn(turn) + end + read_game(turn .. ".dat") + gmtool.editor() +end + +function run_tests() + print("running tests") + require "lunit" + lunit.clearstats() + local argv = tests or {} + local stats = lunit.main(argv) + if stats.errors > 0 or stats.failed > 0 then + return 1 + end + return 0 +end + +function run_turn() + require(config.game .. ".main") + + local turn = get_turn() + if turn==0 then + turn = read_turn() + set_turn(turn) + end + + orderfile = orderfile or config.basepath .. '/orders.' .. turn + print("executing turn " .. get_turn() .. " with " .. orderfile) + local result = process(orderfile) + if result==0 then + dbupdate() + end + return result +end diff --git a/scripts/multis.lua b/scripts/multis.lua index a090f8d3c..ad0b77783 100644 --- a/scripts/multis.lua +++ b/scripts/multis.lua @@ -1,101 +1,101 @@ -function kill_nonstarters() - for f in factions() do - if f.lastturn==1 then - kill_faction(f, true) - end - end -end - -function kill_multis(multis, destructive) - for idx, fno in ipairs(multis) do - local f = get_faction(fno) - if f~=nil and f.email=="doppelspieler@eressea.de" then - kill_faction(f, destructive) - end - end -end - -function mark_multis(multis, block) - if multis~=nil then - for idx, fno in ipairs(multis) do - local f = get_faction(fno) - if f~=nil and f.email~="doppelspieler@eressea.de" then - print("* multi-player " .. tostring(f)) - mark_multi(f, block) - end - end - end -end - --- destroy a faction --- destructive: kill all of its buildings and the home region, too. - -function kill_faction(f, destructive) - for u in f.units do - local r = u.region - local b = u.building - unit.destroy(u) - if destructive and b~=nil then - building.destroy(b) - local nuke = true - for v in r.units do - if v.faction.id~=f.id then - -- print("cannot nuke: " .. tostring(v.faction)) - nuke = false - break - end - end - r.terrain_name = nil - if nuke and num_oceans(r)<=1 then - -- print("nuke!") - r.terrain = "ocean" - else - -- print("cannot nuke: > 1 oceans") - r.terrain = "glacier" - r.peasants = 10 - r:set_resource("money", 100) - b = building.create(r, "monument") - b.size = 1 - b.name = "Memento Mori" - b.info = "Eine kleine " .. translate("race::" .. f.race .."_x") .. "-Statue erinnert hier an ein verschwundenes Volk" - end - end - end - faction.destroy(f) -end - -local function mark_multi(f, block) - f.password = "doppelspieler" - f.email = "doppelspieler@eressea.de" - f.banner = "Diese Partei steht wegen vermuteten Doppelspiels unter Beobachtung." - for u in f.units do - u.race_name = "toad" - if block and u.building~=nil then - local found = false - for u2 in u.region.units do - if u2.faction.id~=u.faction.id then - found = true - break - end - end - if not found then - u.region.terrain_name = "firewall" - u.region:set_flag(2) -- RF_BLOCKED - end - end - end -end - -local function num_oceans(r) - local oceans = 0 - local p = r:next(5) - for d = 0,5 do - local n = r:next(d) - if p.terrain~="ocean" and n.terrain=="ocean" then - oceans = oceans +1 - end - p = n - end - return oceans -end - +function kill_nonstarters() + for f in factions() do + if f.lastturn==1 then + kill_faction(f, true) + end + end +end + +function kill_multis(multis, destructive) + for idx, fno in ipairs(multis) do + local f = get_faction(fno) + if f~=nil and f.email=="doppelspieler@eressea.de" then + kill_faction(f, destructive) + end + end +end + +function mark_multis(multis, block) + if multis~=nil then + for idx, fno in ipairs(multis) do + local f = get_faction(fno) + if f~=nil and f.email~="doppelspieler@eressea.de" then + print("* multi-player " .. tostring(f)) + mark_multi(f, block) + end + end + end +end + +-- destroy a faction +-- destructive: kill all of its buildings and the home region, too. + +function kill_faction(f, destructive) + for u in f.units do + local r = u.region + local b = u.building + unit.destroy(u) + if destructive and b~=nil then + building.destroy(b) + local nuke = true + for v in r.units do + if v.faction.id~=f.id then + -- print("cannot nuke: " .. tostring(v.faction)) + nuke = false + break + end + end + r.terrain_name = nil + if nuke and num_oceans(r)<=1 then + -- print("nuke!") + r.terrain = "ocean" + else + -- print("cannot nuke: > 1 oceans") + r.terrain = "glacier" + r.peasants = 10 + r:set_resource("money", 100) + b = building.create(r, "monument") + b.size = 1 + b.name = "Memento Mori" + b.info = "Eine kleine " .. translate("race::" .. f.race .."_x") .. "-Statue erinnert hier an ein verschwundenes Volk" + end + end + end + faction.destroy(f) +end + +local function mark_multi(f, block) + f.password = "doppelspieler" + f.email = "doppelspieler@eressea.de" + f.banner = "Diese Partei steht wegen vermuteten Doppelspiels unter Beobachtung." + for u in f.units do + u.race_name = "toad" + if block and u.building~=nil then + local found = false + for u2 in u.region.units do + if u2.faction.id~=u.faction.id then + found = true + break + end + end + if not found then + u.region.terrain_name = "firewall" + u.region:set_flag(2) -- RF_BLOCKED + end + end + end +end + +local function num_oceans(r) + local oceans = 0 + local p = r:next(5) + for d = 0,5 do + local n = r:next(d) + if p.terrain~="ocean" and n.terrain=="ocean" then + oceans = oceans +1 + end + p = n + end + return oceans +end + diff --git a/scripts/resources.lua b/scripts/resources.lua index a861f53e4..688fe3d1d 100644 --- a/scripts/resources.lua +++ b/scripts/resources.lua @@ -1,89 +1,89 @@ -function peasant_getresource(u) - return u.region:get_resource("peasant") -end - -function peasant_changeresource(u, delta) - local p = u.region:get_resource("peasant") - p = p + delta - if p < 0 then - p = 0 - end - u.region:set_resource("peasant", p) - return p -end - -function hp_getresource(u) - return u.hp -end - -function hp_changeresource(u, delta) - local hp = u.hp + delta - - if hp < u.number then - if hp < 0 then - hp = 0 - end - u.number = hp - end - u.hp = hp - return hp -end - -function horse_limit(r) - return r:get_resource("horse") -end - -function horse_produce(r, n) - local horses = r:get_resource("horse") - if horses>=n then - r:set_resource("horse", horses-n) - else - r:set_resource("horse", 0) - end -end - -function log_limit(r) --- if r:get_flag(1) then -- RF_MALLORN --- return 0 --- end - return r:get_resource("tree") + r:get_resource("sapling") -end - -function log_produce(r, n) - local trees = r:get_resource("tree") - if trees>=n then - r:set_resource("tree", trees-n) - else - r:set_resource("tree", 0) - n = n - trees - trees = r:get_resource("sapling") - if trees>=n then - r:set_resource("sapling", trees-n) - else - r:set_resource("sapling", 0) - end - end -end - -function mallorn_limit(r) - if not r:get_flag(1) then -- RF_MALLORN - return 0 - end - return r:get_resource("tree") + r:get_resource("sapling") -end - -function mallorn_produce(r, n) - local trees = r:get_resource("tree") - if trees>=n then - r:set_resource("tree", trees-n) - else - r:set_resource("tree", 0) - n = n - trees - trees = r:get_resource("sapling") - if trees>=n then - r:set_resource("sapling", trees-n) - else - r:set_resource("sapling", 0) - end - end -end +function peasant_getresource(u) + return u.region:get_resource("peasant") +end + +function peasant_changeresource(u, delta) + local p = u.region:get_resource("peasant") + p = p + delta + if p < 0 then + p = 0 + end + u.region:set_resource("peasant", p) + return p +end + +function hp_getresource(u) + return u.hp +end + +function hp_changeresource(u, delta) + local hp = u.hp + delta + + if hp < u.number then + if hp < 0 then + hp = 0 + end + u.number = hp + end + u.hp = hp + return hp +end + +function horse_limit(r) + return r:get_resource("horse") +end + +function horse_produce(r, n) + local horses = r:get_resource("horse") + if horses>=n then + r:set_resource("horse", horses-n) + else + r:set_resource("horse", 0) + end +end + +function log_limit(r) +-- if r:get_flag(1) then -- RF_MALLORN +-- return 0 +-- end + return r:get_resource("tree") + r:get_resource("sapling") +end + +function log_produce(r, n) + local trees = r:get_resource("tree") + if trees>=n then + r:set_resource("tree", trees-n) + else + r:set_resource("tree", 0) + n = n - trees + trees = r:get_resource("sapling") + if trees>=n then + r:set_resource("sapling", trees-n) + else + r:set_resource("sapling", 0) + end + end +end + +function mallorn_limit(r) + if not r:get_flag(1) then -- RF_MALLORN + return 0 + end + return r:get_resource("tree") + r:get_resource("sapling") +end + +function mallorn_produce(r, n) + local trees = r:get_resource("tree") + if trees>=n then + r:set_resource("tree", trees-n) + else + r:set_resource("tree", 0) + n = n - trees + trees = r:get_resource("sapling") + if trees>=n then + r:set_resource("sapling", trees-n) + else + r:set_resource("sapling", 0) + end + end +end diff --git a/scripts/schema.sql b/scripts/schema.sql index e136bb822..f2b88d16e 100644 --- a/scripts/schema.sql +++ b/scripts/schema.sql @@ -1,6 +1,6 @@ -CREATE TABLE email(id INTEGER PRIMARY KEY, md5 VARCHAR(32) UNIQUE NOT NULL, email VARCHAR(32), bounces INT DEFAULT 0, confirmed TIMESTAMP DEFAULT NULL); -CREATE TABLE faction (id INTEGER PRIMARY KEY, user_id INTEGER REFERENCES user(id), no INTEGER, name VARCHAR(64), game_id INTEGER REFERENCES game(id), race VARCHAR(10), lang CHAR(2)); -CREATE TABLE faction_email (faction_id INTEGER REFERENCES faction(id), email_id INTEGER REFERENCES email(id)); -CREATE TABLE game (id INTEGER PRIMARY KEY, name VARCHAR(20), last_turn INTEGER); -CREATE TABLE score (turn INTEGER, faction_id INTEGER REFERENCES faction(id), value INTEGER, UNIQUE(turn, faction_id)); -CREATE TABLE user(id INTEGER PRIMARY KEY, email_id INTEGER REFERENCES email(id), creation TIMESTAMP DEFAULT CURRENT_TIMESTAMP); +CREATE TABLE email(id INTEGER PRIMARY KEY, md5 VARCHAR(32) UNIQUE NOT NULL, email VARCHAR(32), bounces INT DEFAULT 0, confirmed TIMESTAMP DEFAULT NULL); +CREATE TABLE faction (id INTEGER PRIMARY KEY, user_id INTEGER REFERENCES user(id), no INTEGER, name VARCHAR(64), game_id INTEGER REFERENCES game(id), race VARCHAR(10), lang CHAR(2)); +CREATE TABLE faction_email (faction_id INTEGER REFERENCES faction(id), email_id INTEGER REFERENCES email(id)); +CREATE TABLE game (id INTEGER PRIMARY KEY, name VARCHAR(20), last_turn INTEGER); +CREATE TABLE score (turn INTEGER, faction_id INTEGER REFERENCES faction(id), value INTEGER, UNIQUE(turn, faction_id)); +CREATE TABLE user(id INTEGER PRIMARY KEY, email_id INTEGER REFERENCES email(id), creation TIMESTAMP DEFAULT CURRENT_TIMESTAMP); diff --git a/scripts/setup.lua b/scripts/setup.lua index 0c3603707..e4bfb726b 100644 --- a/scripts/setup.lua +++ b/scripts/setup.lua @@ -1,16 +1,16 @@ -local srcpath = config.source_dir -local respath = srcpath .. '/' .. config.game .. '/res/' -local paths = { config.game..'/scripts/?.lua';'lunit/?.lua','external/lunit/?.lua','scripts/?.lua';'scripts/?' } - -tests = {'common'} -for idx, test in pairs(tests) do - tests[idx] = srcpath .. '/scripts/tests/' .. test .. '.lua' -end - -for idx, path in pairs(paths) do - package.path = srcpath .. '/' .. path .. ';' .. package.path -end - -read_xml(respath..'config-'..config.game..'.xml', respath..'catalog-'..config.game..'.xml') - -require "init" +local srcpath = config.source_dir +local respath = srcpath .. '/' .. config.game .. '/res/' +local paths = { config.game..'/scripts/?.lua';'lunit/?.lua','external/lunit/?.lua','scripts/?.lua';'scripts/?' } + +tests = {'common'} +for idx, test in pairs(tests) do + tests[idx] = srcpath .. '/scripts/tests/' .. test .. '.lua' +end + +for idx, path in pairs(paths) do + package.path = srcpath .. '/' .. path .. ';' .. package.path +end + +read_xml(respath..'config-'..config.game..'.xml', respath..'catalog-'..config.game..'.xml') + +require "init" diff --git a/scripts/spells.lua b/scripts/spells.lua index 4ab08459a..8269e72e6 100644 --- a/scripts/spells.lua +++ b/scripts/spells.lua @@ -1,151 +1,151 @@ -function creation_message(mage, type, number) - local msg = message.create("item_create_spell") - msg:set_unit("mage", mage) - msg:set_int("number", number) - msg:set_resource("item", type) - return msg -end - -local function create_item(mage, level, name, number) - local count = number or 1 - mage:add_item(name, count); - local msg = creation_message(mage, name, count) - msg:send_faction(mage.faction) - return level -end - --- Wasser des Lebens -function create_potion_p2(r, mage, level, force) - return create_item(mage, level, "p2", level) -end - --- Siebenmeilentee -function create_potion_p0(r, mage, level, force) - return create_item(mage, level, "p0", level) -end - --- Wundsalbe -function create_potion_ointment(r, mage, level, force) - return create_item(mage, level, "ointment", level) -end - --- Bauernblut -function create_potion_peasantblood(r, mage, level, force) - return create_item(mage, level, "peasantblood", level) -end - --- Pferdeglück -function create_potion_p9(r, mage, level, force) - return create_item(mage, level, "p9", level) -end - --- Schaffenstrunk -function create_potion_p3(r, mage, level, force) - return create_item(mage, level, "p3", level) -end - --- Heiltrank -function create_potion_p14(r, mage, level, force) - return create_item(mage, level, "p14", level) -end - --- Elixier der Macht -function create_potion_p13(r, mage, level, force) - return create_item(mage, level, "p13", level) -end - --- Erschaffe ein Flammenschwert -function create_firesword(r, mage, level, force) - return create_item(mage, level, "firesword") -end - --- Erschaffe einen Gürtel der Trollstärke -function create_trollbelt(r, mage, level, force) - return create_item(mage, level, "trollbelt") -end - --- Erschaffe einen Ring der Unsichtbarkeit -function create_roi(r, mage, level, force) - return create_item(mage, level, "roi") -end - --- Erschaffe einen Ring der flinken Finger -function create_roqf(r, mage, level, force) - return create_item(mage, level, "roqf") -end - --- Erschaffe ein Amulett des wahren Sehens -function create_aots(r, mage, level, force) - return create_item(mage, level, "aots") -end - --- Erschaffe einen magischen Kräuterbeutel -function create_magicherbbag(r, mage, level, force) - return create_item(mage, level, "magicherbbag") -end - --- Erschaffe einen Taktikkristal -function create_dreameye(r, mage, level, force) - return create_item(mage, level, "dreameye") -end - --- Erschaffe einen Antimagiekristall -function create_antimagic(r, mage, level, force) - return create_item(mage, level, "antimagic") -end - --- Erschaffe eine Sphäre der Unsichtbarkeit -function create_invisibility_sphere(r, mage, level, force) - return create_item(mage, level, "sphereofinv") -end - --- Erschaffe einen Gürtel der Keuschheit -function create_chastitybelt(r, mage, level, force) - return create_item(mage, level, "ao_chastity") -end - --- Erschaffe ein Runenschwert -function create_runesword(r, mage, level, force) - return create_item(mage, level, "runesword") -end - --- Erschaffe ein Aurafokus -function create_focus(r, mage, level, force) - return create_item(mage, level, "aurafocus") -end - --- Erschaffe einen Ring der Macht -function create_rop(r, mage, level, force) - return create_item(mage, level, "rop") -end - --- Erschaffe einen Ring der Regeneration -function create_ror(r, mage, level, force) - return create_item(mage, level, "ror") -end - --- Erschaffe einen Zauberbeutel -function create_bagofholding(r, mage, level, force) - return create_item(mage, level, "magicbag") -end - --- TODO: -function earn_silver(r, mage, level, force) - local money = r:get_resource("money") - local wanted = 50 * force - local amount = wanted - if wanted > money then - amount = money - end - r:set_resource("money", money - amount) - mage:add_item("money", amount) - - local msg = message.create("income") - msg:set_unit("unit", mage) - msg:set_region("region", r) - msg:set_int("mode", 6) - msg:set_int("wanted", wanted) - msg:set_int("amount", amount) - msg:send_faction(mage.faction) - return level -end +function creation_message(mage, type, number) + local msg = message.create("item_create_spell") + msg:set_unit("mage", mage) + msg:set_int("number", number) + msg:set_resource("item", type) + return msg +end + +local function create_item(mage, level, name, number) + local count = number or 1 + mage:add_item(name, count); + local msg = creation_message(mage, name, count) + msg:send_faction(mage.faction) + return level +end + +-- Wasser des Lebens +function create_potion_p2(r, mage, level, force) + return create_item(mage, level, "p2", level) +end + +-- Siebenmeilentee +function create_potion_p0(r, mage, level, force) + return create_item(mage, level, "p0", level) +end + +-- Wundsalbe +function create_potion_ointment(r, mage, level, force) + return create_item(mage, level, "ointment", level) +end + +-- Bauernblut +function create_potion_peasantblood(r, mage, level, force) + return create_item(mage, level, "peasantblood", level) +end + +-- Pferdeglück +function create_potion_p9(r, mage, level, force) + return create_item(mage, level, "p9", level) +end + +-- Schaffenstrunk +function create_potion_p3(r, mage, level, force) + return create_item(mage, level, "p3", level) +end + +-- Heiltrank +function create_potion_p14(r, mage, level, force) + return create_item(mage, level, "p14", level) +end + +-- Elixier der Macht +function create_potion_p13(r, mage, level, force) + return create_item(mage, level, "p13", level) +end + +-- Erschaffe ein Flammenschwert +function create_firesword(r, mage, level, force) + return create_item(mage, level, "firesword") +end + +-- Erschaffe einen Gürtel der Trollstärke +function create_trollbelt(r, mage, level, force) + return create_item(mage, level, "trollbelt") +end + +-- Erschaffe einen Ring der Unsichtbarkeit +function create_roi(r, mage, level, force) + return create_item(mage, level, "roi") +end + +-- Erschaffe einen Ring der flinken Finger +function create_roqf(r, mage, level, force) + return create_item(mage, level, "roqf") +end + +-- Erschaffe ein Amulett des wahren Sehens +function create_aots(r, mage, level, force) + return create_item(mage, level, "aots") +end + +-- Erschaffe einen magischen Kräuterbeutel +function create_magicherbbag(r, mage, level, force) + return create_item(mage, level, "magicherbbag") +end + +-- Erschaffe einen Taktikkristal +function create_dreameye(r, mage, level, force) + return create_item(mage, level, "dreameye") +end + +-- Erschaffe einen Antimagiekristall +function create_antimagic(r, mage, level, force) + return create_item(mage, level, "antimagic") +end + +-- Erschaffe eine Sphäre der Unsichtbarkeit +function create_invisibility_sphere(r, mage, level, force) + return create_item(mage, level, "sphereofinv") +end + +-- Erschaffe einen Gürtel der Keuschheit +function create_chastitybelt(r, mage, level, force) + return create_item(mage, level, "ao_chastity") +end + +-- Erschaffe ein Runenschwert +function create_runesword(r, mage, level, force) + return create_item(mage, level, "runesword") +end + +-- Erschaffe ein Aurafokus +function create_focus(r, mage, level, force) + return create_item(mage, level, "aurafocus") +end + +-- Erschaffe einen Ring der Macht +function create_rop(r, mage, level, force) + return create_item(mage, level, "rop") +end + +-- Erschaffe einen Ring der Regeneration +function create_ror(r, mage, level, force) + return create_item(mage, level, "ror") +end + +-- Erschaffe einen Zauberbeutel +function create_bagofholding(r, mage, level, force) + return create_item(mage, level, "magicbag") +end + +-- TODO: +function earn_silver(r, mage, level, force) + local money = r:get_resource("money") + local wanted = 50 * force + local amount = wanted + if wanted > money then + amount = money + end + r:set_resource("money", money - amount) + mage:add_item("money", amount) + + local msg = message.create("income") + msg:set_unit("unit", mage) + msg:set_region("region", r) + msg:set_int("mode", 6) + msg:set_int("wanted", wanted) + msg:set_int("amount", amount) + msg:send_faction(mage.faction) + return level +end diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index b6ea04082..9e0ff43db 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -1,643 +1,643 @@ -require "lunit" - -function setup() - free_game() -end - -function one_unit(r, f) - local u = unit.create(f, r, 1) - u:add_item("money", u.number * 100) - u:clear_orders() - return u -end - -function two_units(r, f1, f2) - return one_unit(r, f1), one_unit(r, f2) -end - -function two_factions() - local f1 = faction.create("noreply@eressea.de", "human", "de") - f1.id = 1 - local f2 = faction.create("noreply@eressea.de", "orc", "de") - f2.id = 2 - return f1, f2 -end - -module( "common", package.seeall, lunit.testcase ) - -function DISABLE_test_eventbus_fire() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - local u = unit.create(f, r) - - function compare_f(u, event, f) - assert_equal(u.faction, f) - end - eventbus.register(u, "weird", compare_f) - eventbus.fire(u, "weird", f) -end - -function test_fleeing_units_can_be_transported() - local r = region.create(0, 0, "plain") - local r1 = region.create(1, 0, "plain") - local f1, f2 = two_factions() - local u1, u2 = two_units(r, f1, f2) - local u3 = one_unit(r, f2) - u1.number = 100 - u1:add_order("ATTACKIEREN " .. itoa36(u2.id)) - u2.number = 100 - u2:add_order("FAHREN " .. itoa36(u3.id)) - u3.number = 100 - u3:add_order("KAEMPFE FLIEHE") - u3:add_order("TRANSPORT " .. itoa36(u2.id)) - u3:add_order("NACH O ") - u3:set_skill("riding", 2) - u3:add_item("horse", u2.number) - u3:add_order("KAEMPFE FLIEHE") - process_orders() - assert_equal(u3.region.id, r1.id, "transporter did not move") - assert_equal(u2.region.id, r1.id, "transported unit did not move") -end - -function test_plane() - local pl = plane.create(0, -3, -3, 7, 7) - local nx, ny = plane.normalize(pl, 4, 4) - assert_equal(nx, -3, "normalization failed") - assert_equal(ny, -3, "normalization failed") - local f = faction.create("noreply@eressea.de", "human", "de") - f.id = atoi36("tpla") - local r, x, y - for x = -3, 3 do for y = -3, 3 do - r = region.create(x, y, "plain") - if (x==y) then - local u = unit.create(f, r, 1) - end - end end -end - -function test_pure() - free_game() - local r = region.create(0, 0, "plain") - assert_not_equal(nil, r) - assert_equal(r, get_region(0, 0)) -end - -function test_read_write() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - local u = unit.create(f, r) - u.number = 2 - local fno = f.id - local uno = u.id - local result = 0 - assert_equal(r.terrain, "plain") - result = write_game("test_read_write.dat", "binary") - assert_equal(result, 0) - assert_not_equal(get_region(0, 0), nil) - assert_not_equal(get_faction(fno), nil) - assert_not_equal(get_unit(uno), nil) - r = nil - f = nil - u = nil - free_game() - assert_equal(get_region(0, 0), nil) - assert_equal(nil, get_faction(fno)) - assert_equal(nil, get_unit(uno)) - result = read_game("test_read_write.dat", "binary") - assert_equal(0, result) - assert_not_equal(nil, get_region(0, 0)) - assert_not_equal(nil, get_faction(fno)) - assert_not_equal(nil, get_unit(uno)) - free_game() -end - -function test_gmtool() - free_game() - local r1 = region.create(1, 0, "plain") - local r2 = region.create(1, 1, "plain") - local r3 = region.create(1, 2, "plain") - gmtool.open() - gmtool.select(r1, true) - gmtool.select_at(0, 1, true) - gmtool.select(r2, true) - gmtool.select_at(0, 2, true) - gmtool.select(r3, false) - gmtool.select(r3, true) - gmtool.select_at(0, 3, false) - gmtool.select(r3, false) - - local selections = 0 - for r in gmtool.get_selection() do - selections=selections+1 - end - assert_equal(2, selections) - assert_equal(nil, gmtool.get_cursor()) - - gmtool.close() -end - -function test_faction() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - assert(f) - f.info = "Spazz" - assert(f.info=="Spazz") - f:add_item("donotwant", 42) - f:add_item("stone", 42) - f:add_item("sword", 42) - local items = 0 - for u in f.items do - items = items + 1 - end - assert(items==2) - unit.create(f, r) - unit.create(f, r) - local units = 0 - for u in f.units do - units = units + 1 - end - assert(units==2) -end - -function test_unit() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - local u = unit.create(f, r) - u.number = 20 - u.name = "Enno" - assert(u.name=="Enno") - u.info = "Spazz" - assert(u.info=="Spazz") - u:add_item("sword", 4) - assert(u:get_item("sword")==4) - assert(u:get_pooled("sword")==4) - u:use_pooled("sword", 2) - assert(u:get_item("sword")==2) -end - -function test_region() - free_game() - local r = region.create(0, 0, "plain") - r:set_resource("horse", 42) - r:set_resource("money", 45) - r:set_resource("peasant", 200) - assert(r:get_resource("horse") == 42) - assert(r:get_resource("money") == 45) - assert(r:get_resource("peasant") == 200) - r.name = nil - r.info = nil - assert(r.name=="") - assert(r.info=="") - r.name = "Alabasterheim" - r.info = "Hier wohnen die siebzehn Zwerge" - assert(tostring(r) == "Alabasterheim (0,0)") -end - -function test_building() - free_game() - local u - local f = faction.create("noreply@eressea.de", "human", "de") - local r = region.create(0, 0, "plain") - local b = building.create(r, "castle") - u = unit.create(f, r) - u.number = 1 - u.building = b - u = unit.create(f, r) - u.number = 2 - -- u.building = b - u = unit.create(f, r) - u.number = 3 - u.building = b - local units = 0 - for u in b.units do - units = units + 1 - end - assert(units==2) - local r2 = region.create(0, 1, "plain") - assert(b.region==r) - b.region = r2 - assert(b.region==r2) - assert(r2.buildings()==b) -end - -function test_message() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - local u = unit.create(f, r) - local msg = message.create("item_create_spell") - msg:set_unit("mage", u) - msg:set_int("number", 1) - msg:set_resource("item", "sword") - msg:send_region(r) - msg:send_faction(f) - - return msg -end - -function test_hashtable() - free_game() - local f = faction.create("noreply@eressea.de", "human", "de") - f.objects:set("enno", "smart guy") - f.objects:set("age", 10) - assert(f.objects:get("jesus") == nil) - assert(f.objects:get("enno") == "smart guy") - assert(f.objects:get("age") == 10) - f.objects:set("age", nil) - assert(f.objects:get("age") == nil) -end - -function test_events() - local fail = 1 - local function msg_handler(u, evt) - str = evt:get(0) - u2 = evt:get(1) - assert(u2~=nil) - assert(str=="Du Elf stinken") - message_unit(u, u2, "thanks unit, i got your message: " .. str) - message_faction(u, u2.faction, "thanks faction, i got your message: " .. str) - message_region(u, "thanks region, i got your message: " .. str) - fail = 0 - end - - plain = region.create(0, 0, "plain") - skill = 8 - - f = faction.create("noreply@eressea.de", "orc", "de") - f.age = 20 - - u = unit.create(f, plain) - u.number = 1 - u:add_item("money", u.number*100) - u:clear_orders() - u:add_order("NUMMER PARTEI test") - u:add_handler("message", msg_handler) - msg = "BOTSCHAFT EINHEIT " .. itoa36(u.id) .. " Du~Elf~stinken" - f = faction.create("noreply@eressea.de", "elf", "de") - f.age = 20 - - u = unit.create(f, plain) - u.number = 1 - u:add_item("money", u.number*100) - u:clear_orders() - u:add_order("NUMMER PARTEI eviL") - u:add_order(msg) - process_orders() - assert(fail==0) -end - -function test_recruit2() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - local u = unit.create(f, r) - u.number = 1 - u:add_item("money", 2000) - u:clear_orders() - u:add_order("MACHE TEMP 1") - u:add_order("REKRUTIERE 1 Elf") - u:add_order("REKRUTIERE 1 mensch") - u:add_order("REKRUTIERE 1") - process_orders() -end - -function test_guard() - free_game() - region.create(1, 0, "plain") - local r = region.create(0, 0, "plain") - local f1 = faction.create("noreply@eressea.de", "human", "de") - f1.age = 20 - local u1 = unit.create(f1, r, 1) - u1:add_item("sword", 10) - u1:add_item("money", 10) - u1:set_skill("melee", 10) - u1:clear_orders() - u1:add_order("NACH O") - - local f2 = faction.create("noreply@eressea.de", "human", "de") - f2.age = 20 - local u2 = unit.create(f2, r, 1) - local u3 = unit.create(f2, r, 1) - local b = building.create(r, "castle") - b.size = 10 - u2.building = b - u3.building = b - u2:clear_orders() - u2:add_order("ATTACKIEREN " .. itoa36(u1.id)) -- you will die... - u2:add_item("money", 100) - u3:add_item("money", 100) - process_orders() - assert_equal(r.id, u1.region.id, "unit may not move after combat") -end - -function test_recruit() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - local u = unit.create(f, r) - u.number = 1 - local n = 3 - r:set_resource("peasant", 200) - u:clear_orders() - u:add_item("money", 110*n+20) - u:add_order("REKRUTIERE " .. n) - process_orders() - assert(u.number == n+1) - local p = r:get_resource("peasant") - assert(p<200 and p>=200-n) - -- assert(u:get_item("money")==10) -end - -function test_produce() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - local u = unit.create(f, r, 1) - u:clear_orders() - u:set_skill("weaponsmithing", 3) - u:add_item("iron", 2) - u:add_item("money", u.number * 10) - u:add_order("MACHE Schwert") - process_orders() - assert(u:get_item("iron")==1) - assert(u:get_item("sword")==1) -end - -function test_work() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - f.id = 42 - local u = unit.create(f, r, 1) - u:add_item("money", u.number * 10) -- humans cost 10 - u:set_skill("herbalism", 5) - u:clear_orders() - u:add_order("ARBEITEN") - process_orders() - assert(u:get_item("money")>=10) -end - -function test_upkeep() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - f.id = 42 - local u = unit.create(f, r, 5) - u:add_item("money", u.number * 11) - u:clear_orders() - u:add_order("LERNE Waffenbau") - process_orders() - assert(u:get_item("money")==u.number) -end - -function test_id() - free_game() - local r = region.create(0, 0, "plain") - - local f = faction.create("noreply@eressea.de", "human", "de") - f.id = atoi36("42") - assert(get_faction(42)~=f) - assert(get_faction("42")==f) - assert(get_faction(atoi36("42"))==f) - - local u = unit.create(f, r, 1) - u.id = atoi36("42") - assert(get_unit(42)~=u) - assert(get_unit("42")==u) - assert(get_unit(atoi36("42"))==u) - - local b = building.create(r, "castle") - -- b.id = atoi36("42") - local fortytwo = itoa36(b.id) - assert(get_building(fortytwo)==b) - assert(get_building(atoi36(fortytwo))==b) - - local s = ship.create(r, "canoe") - if (s==nil) then - s = ship.create(r, "boat") - end - -- s.id = atoi36("42") - local fortytwo = itoa36(s.id) - assert(get_ship(fortytwo)==s) - assert(get_ship(atoi36(fortytwo))==s) -end - -function test_herbalism() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - f.id = 42 - local u = unit.create(f, r, 1) - u:add_item("money", u.number * 100) - u:set_skill("herbalism", 5) - u:clear_orders() - u:add_order("MACHE Samen") - process_orders() -end - -function test_mallorn() - free_game() - local r = region.create(0, 0, "plain") - r:set_flag(1, false) -- not mallorn - r:set_resource("tree", 100) - assert(r:get_resource("tree")==100) - local m = region.create(0, 0, "plain") - m:set_flag(1, true) -- not mallorn - m:set_resource("tree", 100) - assert(m:get_resource("tree")==100) - - local f = faction.create("noreply@eressea.de", "human", "de") - - local u1 = unit.create(f, r, 1) - u1:add_item("money", u1.number * 100) - u1:set_skill("forestry", 2) - u1:clear_orders() - u1:add_order("MACHE HOLZ") - - local u2 = unit.create(f, m, 1) - u2:add_item("money", u2.number * 100) - u2:set_skill("forestry", 2) - u2:clear_orders() - u2:add_order("MACHE HOLZ") - - local u3 = unit.create(f, m, 1) - u3:add_item("money", u3.number * 100) - u3:set_skill("forestry", 2) - u3:clear_orders() - u3:add_order("MACHE Mallorn") - process_orders() - assert(u1:get_item("log")==2) - assert(u2:get_item("log")==2) - assert(u3:get_item("mallorn")==1) -end - -function test_coordinate_translation() - local pl = plane.create(1, 500, 500, 1001, 1001) -- astralraum - local pe = plane.create(1, -8761, 3620, 23, 23) -- eternath - local r = region.create(1000, 1000, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - assert_not_equal(nil, r) - assert_equal(r.x, 1000) - assert_equal(r.y, 1000) - local nx, ny = plane.normalize(pl, r.x, r.y) - assert_equal(nx, 1000) - assert_equal(ny, 1000) - local r1 = region.create(500, 500, "plain") - f:set_origin(r1) - nx, ny = f:normalize(r1) - assert_equal(0, nx) - assert_equal(0, ny) - local r0 = region.create(0, 0, "plain") - nx, ny = f:normalize(r0) - assert_equal(0, nx) - assert_equal(0, ny) - nx, ny = f:normalize(r) - assert_equal(500, nx) - assert_equal(500, ny) - local rn = region.create(1010, 1010, "plain") - nx, ny = f:normalize(rn) - assert_equal(-491, nx) - assert_equal(-491, ny) - - local re = region.create(-8760, 3541, "plain") -- eternath - nx, ny = f:normalize(rn) - assert_equal(-491, nx) - assert_equal(-491, ny) -end - -function test_control() - free_game() - local u1, u2 = two_units(region.create(0, 0, "plain"), two_factions()) - local r = u1.region - local b = building.create(r, "castle") - u1.building = b - u2.building = b - assert_equal(u1, b.owner) - u1:clear_orders() - u1:add_order("GIB " .. itoa36(u2.id) .. " KOMMANDO") - u1:add_order("VERLASSE") - process_orders() - assert_equal(u2, b.owner) -end - -function test_storage() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - f.id = 42 - local u = unit.create(f, r, 1) - u:add_item("money", u.number * 100) - store = storage.create("test.unit.dat", "wb") - assert_not_equal(store, nil) - store:write_unit(u) - store:close() - free_game() - -- recreate world: - r = region.create(0, 0, "plain") - f = faction.create("noreply@eressea.de", "human", "de") - f.id = 42 - store = storage.create("test.unit.dat", "rb") - assert(store) - u = store:read_unit() - store:close() - assert(u) - assert(u:get_item("money") == u.number * 100) -end - -function test_building_other() - local r = region.create(0,0, "plain") - local f1 = faction.create("noreply@eressea.de", "human", "de") - local f2 = faction.create("noreply@eressea.de", "human", "de") - local b = building.create(r, "castle") - b.size = 10 - local u1 = unit.create(f1, r, 3) - u1.building = b - u1:add_item("money", 100) - - local u2 = unit.create(f2, r, 3) - u2:set_skill("building", 10) - u2:add_item("money", 100) - u2:add_item("stone", 100) - u2:clear_orders() - u2:add_order("MACHEN BURG " .. itoa36(b.id)) - process_orders() - assert_not_equal(10, b.size) -end - -function test_config() - assert_not_equal(nil, config.basepath) - assert_not_equal(nil, config.locales) -end - -function test_guard_resources() - -- this is not quite http://bugs.eressea.de/view.php?id=1756 - local r = region.create(0,0, "mountain") - local f1 = faction.create("noreply@eressea.de", "human", "de") - f1.age=20 - local f2 = faction.create("noreply@eressea.de", "human", "de") - f2.age=20 - local u1 = unit.create(f1, r, 1) - u1:add_item("money", 100) - u1:set_skill("melee", 3) - u1:add_item("sword", 1) - u1:clear_orders() - u1:add_order("BEWACHEN") - - local u2 = unit.create(f2, r, 1) - u2:add_item("money", 100) - u2:set_skill("mining", 3) - u2:clear_orders() - u2:add_order("MACHEN EISEN") - - process_orders() - local iron = u2:get_item("iron") - process_orders() - assert_equal(iron, u2:get_item("iron")) -end - -local function is_flag_set(flags, flag) - return math.mod(flags, flag*2) - math.mod(flags, flag) == flag; -end - -function test_hero_hero_transfer() - local r = region.create(0,0, "mountain") - local f = faction.create("noreply@eressea.de", "human", "de") - f.age=20 - local UFL_HERO = 128 - - local u1 = unit.create(f, r, 1) - local u2 = unit.create(f, r, 1) - u1:add_item("money", 10000) - u1.flags = u1.flags + UFL_HERO - u2.flags = u2.flags + UFL_HERO - u1:clear_orders() - u1:add_order("GIB " .. itoa36(u2.id) .. " 1 PERSONEN") - u1:add_order("REKRUTIEREN 1") - process_orders() - assert_equal(1, u1.number) - assert_equal(2, u2.number) - assert_false(is_flag_set(u1.flags, 128), 128, "recruiting into an empty hero unit should not create a hero") - assert_true(is_flag_set(u2.flags, 128), 128, "unit is not a hero?") -end - -function test_hero_normal_transfer() - local r = region.create(0,0, "mountain") - local f = faction.create("noreply@eressea.de", "human", "de") - f.age=20 - local UFL_HERO = 128 - - local u1 = unit.create(f, r, 1) - local u2 = unit.create(f, r, 1) - u1:add_item("money", 10000) - u1.flags = u1.flags + UFL_HERO - u1:clear_orders() - u1:add_order("GIB " .. itoa36(u2.id) .. " 1 PERSONEN") - process_orders() - assert_equal(1, u1.number) - assert_equal(1, u2.number) - assert_true(is_flag_set(u1.flags, 128), "unit is not a hero?") - assert_false(is_flag_set(u2.flags, 128), "unit turned into a hero") -end +require "lunit" + +function setup() + free_game() +end + +function one_unit(r, f) + local u = unit.create(f, r, 1) + u:add_item("money", u.number * 100) + u:clear_orders() + return u +end + +function two_units(r, f1, f2) + return one_unit(r, f1), one_unit(r, f2) +end + +function two_factions() + local f1 = faction.create("noreply@eressea.de", "human", "de") + f1.id = 1 + local f2 = faction.create("noreply@eressea.de", "orc", "de") + f2.id = 2 + return f1, f2 +end + +module( "common", package.seeall, lunit.testcase ) + +function DISABLE_test_eventbus_fire() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r) + + function compare_f(u, event, f) + assert_equal(u.faction, f) + end + eventbus.register(u, "weird", compare_f) + eventbus.fire(u, "weird", f) +end + +function test_fleeing_units_can_be_transported() + local r = region.create(0, 0, "plain") + local r1 = region.create(1, 0, "plain") + local f1, f2 = two_factions() + local u1, u2 = two_units(r, f1, f2) + local u3 = one_unit(r, f2) + u1.number = 100 + u1:add_order("ATTACKIEREN " .. itoa36(u2.id)) + u2.number = 100 + u2:add_order("FAHREN " .. itoa36(u3.id)) + u3.number = 100 + u3:add_order("KAEMPFE FLIEHE") + u3:add_order("TRANSPORT " .. itoa36(u2.id)) + u3:add_order("NACH O ") + u3:set_skill("riding", 2) + u3:add_item("horse", u2.number) + u3:add_order("KAEMPFE FLIEHE") + process_orders() + assert_equal(u3.region.id, r1.id, "transporter did not move") + assert_equal(u2.region.id, r1.id, "transported unit did not move") +end + +function test_plane() + local pl = plane.create(0, -3, -3, 7, 7) + local nx, ny = plane.normalize(pl, 4, 4) + assert_equal(nx, -3, "normalization failed") + assert_equal(ny, -3, "normalization failed") + local f = faction.create("noreply@eressea.de", "human", "de") + f.id = atoi36("tpla") + local r, x, y + for x = -3, 3 do for y = -3, 3 do + r = region.create(x, y, "plain") + if (x==y) then + local u = unit.create(f, r, 1) + end + end end +end + +function test_pure() + free_game() + local r = region.create(0, 0, "plain") + assert_not_equal(nil, r) + assert_equal(r, get_region(0, 0)) +end + +function test_read_write() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r) + u.number = 2 + local fno = f.id + local uno = u.id + local result = 0 + assert_equal(r.terrain, "plain") + result = write_game("test_read_write.dat", "binary") + assert_equal(result, 0) + assert_not_equal(get_region(0, 0), nil) + assert_not_equal(get_faction(fno), nil) + assert_not_equal(get_unit(uno), nil) + r = nil + f = nil + u = nil + free_game() + assert_equal(get_region(0, 0), nil) + assert_equal(nil, get_faction(fno)) + assert_equal(nil, get_unit(uno)) + result = read_game("test_read_write.dat", "binary") + assert_equal(0, result) + assert_not_equal(nil, get_region(0, 0)) + assert_not_equal(nil, get_faction(fno)) + assert_not_equal(nil, get_unit(uno)) + free_game() +end + +function test_gmtool() + free_game() + local r1 = region.create(1, 0, "plain") + local r2 = region.create(1, 1, "plain") + local r3 = region.create(1, 2, "plain") + gmtool.open() + gmtool.select(r1, true) + gmtool.select_at(0, 1, true) + gmtool.select(r2, true) + gmtool.select_at(0, 2, true) + gmtool.select(r3, false) + gmtool.select(r3, true) + gmtool.select_at(0, 3, false) + gmtool.select(r3, false) + + local selections = 0 + for r in gmtool.get_selection() do + selections=selections+1 + end + assert_equal(2, selections) + assert_equal(nil, gmtool.get_cursor()) + + gmtool.close() +end + +function test_faction() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + assert(f) + f.info = "Spazz" + assert(f.info=="Spazz") + f:add_item("donotwant", 42) + f:add_item("stone", 42) + f:add_item("sword", 42) + local items = 0 + for u in f.items do + items = items + 1 + end + assert(items==2) + unit.create(f, r) + unit.create(f, r) + local units = 0 + for u in f.units do + units = units + 1 + end + assert(units==2) +end + +function test_unit() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r) + u.number = 20 + u.name = "Enno" + assert(u.name=="Enno") + u.info = "Spazz" + assert(u.info=="Spazz") + u:add_item("sword", 4) + assert(u:get_item("sword")==4) + assert(u:get_pooled("sword")==4) + u:use_pooled("sword", 2) + assert(u:get_item("sword")==2) +end + +function test_region() + free_game() + local r = region.create(0, 0, "plain") + r:set_resource("horse", 42) + r:set_resource("money", 45) + r:set_resource("peasant", 200) + assert(r:get_resource("horse") == 42) + assert(r:get_resource("money") == 45) + assert(r:get_resource("peasant") == 200) + r.name = nil + r.info = nil + assert(r.name=="") + assert(r.info=="") + r.name = "Alabasterheim" + r.info = "Hier wohnen die siebzehn Zwerge" + assert(tostring(r) == "Alabasterheim (0,0)") +end + +function test_building() + free_game() + local u + local f = faction.create("noreply@eressea.de", "human", "de") + local r = region.create(0, 0, "plain") + local b = building.create(r, "castle") + u = unit.create(f, r) + u.number = 1 + u.building = b + u = unit.create(f, r) + u.number = 2 + -- u.building = b + u = unit.create(f, r) + u.number = 3 + u.building = b + local units = 0 + for u in b.units do + units = units + 1 + end + assert(units==2) + local r2 = region.create(0, 1, "plain") + assert(b.region==r) + b.region = r2 + assert(b.region==r2) + assert(r2.buildings()==b) +end + +function test_message() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r) + local msg = message.create("item_create_spell") + msg:set_unit("mage", u) + msg:set_int("number", 1) + msg:set_resource("item", "sword") + msg:send_region(r) + msg:send_faction(f) + + return msg +end + +function test_hashtable() + free_game() + local f = faction.create("noreply@eressea.de", "human", "de") + f.objects:set("enno", "smart guy") + f.objects:set("age", 10) + assert(f.objects:get("jesus") == nil) + assert(f.objects:get("enno") == "smart guy") + assert(f.objects:get("age") == 10) + f.objects:set("age", nil) + assert(f.objects:get("age") == nil) +end + +function test_events() + local fail = 1 + local function msg_handler(u, evt) + str = evt:get(0) + u2 = evt:get(1) + assert(u2~=nil) + assert(str=="Du Elf stinken") + message_unit(u, u2, "thanks unit, i got your message: " .. str) + message_faction(u, u2.faction, "thanks faction, i got your message: " .. str) + message_region(u, "thanks region, i got your message: " .. str) + fail = 0 + end + + plain = region.create(0, 0, "plain") + skill = 8 + + f = faction.create("noreply@eressea.de", "orc", "de") + f.age = 20 + + u = unit.create(f, plain) + u.number = 1 + u:add_item("money", u.number*100) + u:clear_orders() + u:add_order("NUMMER PARTEI test") + u:add_handler("message", msg_handler) + msg = "BOTSCHAFT EINHEIT " .. itoa36(u.id) .. " Du~Elf~stinken" + f = faction.create("noreply@eressea.de", "elf", "de") + f.age = 20 + + u = unit.create(f, plain) + u.number = 1 + u:add_item("money", u.number*100) + u:clear_orders() + u:add_order("NUMMER PARTEI eviL") + u:add_order(msg) + process_orders() + assert(fail==0) +end + +function test_recruit2() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r) + u.number = 1 + u:add_item("money", 2000) + u:clear_orders() + u:add_order("MACHE TEMP 1") + u:add_order("REKRUTIERE 1 Elf") + u:add_order("REKRUTIERE 1 mensch") + u:add_order("REKRUTIERE 1") + process_orders() +end + +function test_guard() + free_game() + region.create(1, 0, "plain") + local r = region.create(0, 0, "plain") + local f1 = faction.create("noreply@eressea.de", "human", "de") + f1.age = 20 + local u1 = unit.create(f1, r, 1) + u1:add_item("sword", 10) + u1:add_item("money", 10) + u1:set_skill("melee", 10) + u1:clear_orders() + u1:add_order("NACH O") + + local f2 = faction.create("noreply@eressea.de", "human", "de") + f2.age = 20 + local u2 = unit.create(f2, r, 1) + local u3 = unit.create(f2, r, 1) + local b = building.create(r, "castle") + b.size = 10 + u2.building = b + u3.building = b + u2:clear_orders() + u2:add_order("ATTACKIEREN " .. itoa36(u1.id)) -- you will die... + u2:add_item("money", 100) + u3:add_item("money", 100) + process_orders() + assert_equal(r.id, u1.region.id, "unit may not move after combat") +end + +function test_recruit() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r) + u.number = 1 + local n = 3 + r:set_resource("peasant", 200) + u:clear_orders() + u:add_item("money", 110*n+20) + u:add_order("REKRUTIERE " .. n) + process_orders() + assert(u.number == n+1) + local p = r:get_resource("peasant") + assert(p<200 and p>=200-n) + -- assert(u:get_item("money")==10) +end + +function test_produce() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u:clear_orders() + u:set_skill("weaponsmithing", 3) + u:add_item("iron", 2) + u:add_item("money", u.number * 10) + u:add_order("MACHE Schwert") + process_orders() + assert(u:get_item("iron")==1) + assert(u:get_item("sword")==1) +end + +function test_work() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + f.id = 42 + local u = unit.create(f, r, 1) + u:add_item("money", u.number * 10) -- humans cost 10 + u:set_skill("herbalism", 5) + u:clear_orders() + u:add_order("ARBEITEN") + process_orders() + assert(u:get_item("money")>=10) +end + +function test_upkeep() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + f.id = 42 + local u = unit.create(f, r, 5) + u:add_item("money", u.number * 11) + u:clear_orders() + u:add_order("LERNE Waffenbau") + process_orders() + assert(u:get_item("money")==u.number) +end + +function test_id() + free_game() + local r = region.create(0, 0, "plain") + + local f = faction.create("noreply@eressea.de", "human", "de") + f.id = atoi36("42") + assert(get_faction(42)~=f) + assert(get_faction("42")==f) + assert(get_faction(atoi36("42"))==f) + + local u = unit.create(f, r, 1) + u.id = atoi36("42") + assert(get_unit(42)~=u) + assert(get_unit("42")==u) + assert(get_unit(atoi36("42"))==u) + + local b = building.create(r, "castle") + -- b.id = atoi36("42") + local fortytwo = itoa36(b.id) + assert(get_building(fortytwo)==b) + assert(get_building(atoi36(fortytwo))==b) + + local s = ship.create(r, "canoe") + if (s==nil) then + s = ship.create(r, "boat") + end + -- s.id = atoi36("42") + local fortytwo = itoa36(s.id) + assert(get_ship(fortytwo)==s) + assert(get_ship(atoi36(fortytwo))==s) +end + +function test_herbalism() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + f.id = 42 + local u = unit.create(f, r, 1) + u:add_item("money", u.number * 100) + u:set_skill("herbalism", 5) + u:clear_orders() + u:add_order("MACHE Samen") + process_orders() +end + +function test_mallorn() + free_game() + local r = region.create(0, 0, "plain") + r:set_flag(1, false) -- not mallorn + r:set_resource("tree", 100) + assert(r:get_resource("tree")==100) + local m = region.create(0, 0, "plain") + m:set_flag(1, true) -- not mallorn + m:set_resource("tree", 100) + assert(m:get_resource("tree")==100) + + local f = faction.create("noreply@eressea.de", "human", "de") + + local u1 = unit.create(f, r, 1) + u1:add_item("money", u1.number * 100) + u1:set_skill("forestry", 2) + u1:clear_orders() + u1:add_order("MACHE HOLZ") + + local u2 = unit.create(f, m, 1) + u2:add_item("money", u2.number * 100) + u2:set_skill("forestry", 2) + u2:clear_orders() + u2:add_order("MACHE HOLZ") + + local u3 = unit.create(f, m, 1) + u3:add_item("money", u3.number * 100) + u3:set_skill("forestry", 2) + u3:clear_orders() + u3:add_order("MACHE Mallorn") + process_orders() + assert(u1:get_item("log")==2) + assert(u2:get_item("log")==2) + assert(u3:get_item("mallorn")==1) +end + +function test_coordinate_translation() + local pl = plane.create(1, 500, 500, 1001, 1001) -- astralraum + local pe = plane.create(1, -8761, 3620, 23, 23) -- eternath + local r = region.create(1000, 1000, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + assert_not_equal(nil, r) + assert_equal(r.x, 1000) + assert_equal(r.y, 1000) + local nx, ny = plane.normalize(pl, r.x, r.y) + assert_equal(nx, 1000) + assert_equal(ny, 1000) + local r1 = region.create(500, 500, "plain") + f:set_origin(r1) + nx, ny = f:normalize(r1) + assert_equal(0, nx) + assert_equal(0, ny) + local r0 = region.create(0, 0, "plain") + nx, ny = f:normalize(r0) + assert_equal(0, nx) + assert_equal(0, ny) + nx, ny = f:normalize(r) + assert_equal(500, nx) + assert_equal(500, ny) + local rn = region.create(1010, 1010, "plain") + nx, ny = f:normalize(rn) + assert_equal(-491, nx) + assert_equal(-491, ny) + + local re = region.create(-8760, 3541, "plain") -- eternath + nx, ny = f:normalize(rn) + assert_equal(-491, nx) + assert_equal(-491, ny) +end + +function test_control() + free_game() + local u1, u2 = two_units(region.create(0, 0, "plain"), two_factions()) + local r = u1.region + local b = building.create(r, "castle") + u1.building = b + u2.building = b + assert_equal(u1, b.owner) + u1:clear_orders() + u1:add_order("GIB " .. itoa36(u2.id) .. " KOMMANDO") + u1:add_order("VERLASSE") + process_orders() + assert_equal(u2, b.owner) +end + +function test_storage() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + f.id = 42 + local u = unit.create(f, r, 1) + u:add_item("money", u.number * 100) + store = storage.create("test.unit.dat", "wb") + assert_not_equal(store, nil) + store:write_unit(u) + store:close() + free_game() + -- recreate world: + r = region.create(0, 0, "plain") + f = faction.create("noreply@eressea.de", "human", "de") + f.id = 42 + store = storage.create("test.unit.dat", "rb") + assert(store) + u = store:read_unit() + store:close() + assert(u) + assert(u:get_item("money") == u.number * 100) +end + +function test_building_other() + local r = region.create(0,0, "plain") + local f1 = faction.create("noreply@eressea.de", "human", "de") + local f2 = faction.create("noreply@eressea.de", "human", "de") + local b = building.create(r, "castle") + b.size = 10 + local u1 = unit.create(f1, r, 3) + u1.building = b + u1:add_item("money", 100) + + local u2 = unit.create(f2, r, 3) + u2:set_skill("building", 10) + u2:add_item("money", 100) + u2:add_item("stone", 100) + u2:clear_orders() + u2:add_order("MACHEN BURG " .. itoa36(b.id)) + process_orders() + assert_not_equal(10, b.size) +end + +function test_config() + assert_not_equal(nil, config.basepath) + assert_not_equal(nil, config.locales) +end + +function test_guard_resources() + -- this is not quite http://bugs.eressea.de/view.php?id=1756 + local r = region.create(0,0, "mountain") + local f1 = faction.create("noreply@eressea.de", "human", "de") + f1.age=20 + local f2 = faction.create("noreply@eressea.de", "human", "de") + f2.age=20 + local u1 = unit.create(f1, r, 1) + u1:add_item("money", 100) + u1:set_skill("melee", 3) + u1:add_item("sword", 1) + u1:clear_orders() + u1:add_order("BEWACHEN") + + local u2 = unit.create(f2, r, 1) + u2:add_item("money", 100) + u2:set_skill("mining", 3) + u2:clear_orders() + u2:add_order("MACHEN EISEN") + + process_orders() + local iron = u2:get_item("iron") + process_orders() + assert_equal(iron, u2:get_item("iron")) +end + +local function is_flag_set(flags, flag) + return math.mod(flags, flag*2) - math.mod(flags, flag) == flag; +end + +function test_hero_hero_transfer() + local r = region.create(0,0, "mountain") + local f = faction.create("noreply@eressea.de", "human", "de") + f.age=20 + local UFL_HERO = 128 + + local u1 = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + u1:add_item("money", 10000) + u1.flags = u1.flags + UFL_HERO + u2.flags = u2.flags + UFL_HERO + u1:clear_orders() + u1:add_order("GIB " .. itoa36(u2.id) .. " 1 PERSONEN") + u1:add_order("REKRUTIEREN 1") + process_orders() + assert_equal(1, u1.number) + assert_equal(2, u2.number) + assert_false(is_flag_set(u1.flags, 128), 128, "recruiting into an empty hero unit should not create a hero") + assert_true(is_flag_set(u2.flags, 128), 128, "unit is not a hero?") +end + +function test_hero_normal_transfer() + local r = region.create(0,0, "mountain") + local f = faction.create("noreply@eressea.de", "human", "de") + f.age=20 + local UFL_HERO = 128 + + local u1 = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + u1:add_item("money", 10000) + u1.flags = u1.flags + UFL_HERO + u1:clear_orders() + u1:add_order("GIB " .. itoa36(u2.id) .. " 1 PERSONEN") + process_orders() + assert_equal(1, u1.number) + assert_equal(1, u2.number) + assert_true(is_flag_set(u1.flags, 128), "unit is not a hero?") + assert_false(is_flag_set(u2.flags, 128), "unit turned into a hero") +end diff --git a/scripts/tests/spells.lua b/scripts/tests/spells.lua index c88b70abf..e71935aa8 100644 --- a/scripts/tests/spells.lua +++ b/scripts/tests/spells.lua @@ -1,64 +1,64 @@ -require "lunit" - -module( "spells", package.seeall, lunit.testcase ) - -function setup() - free_game() -end - -function test_roi() - local r = region.create(0,0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - local u = unit.create(f, r, 1) - u.race = "elf" - u:set_skill("magic", 10) - u:add_item("money", 3010) - u.magic = "tybied" - u.aura = 200 - u.ship = s1 - u:add_spell("create_roi") - u:clear_orders() - u:add_order("ZAUBERE 'Erschaffe einen Ring der Unsichtbarkeit' ") - process_orders() - write_reports() - assert_equal(1, u:get_item("roi")) -end - -function test_blessedharvest_lasts_n_turn() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "halfling", "de") - local u = unit.create(f, r) - r:set_resource("peasant", 100) - r:set_resource("money", 0) - u:add_item("money", 1000) - u.magic = "gwyrrd" - u.race = "dwarf" - u:set_skill("magic", 20) - u.aura = 200 - u:add_spell("raindance") - u:add_spell("blessedharvest") - u:clear_orders() - local level = 5 - u:add_order("ZAUBERE STUFE " .. level .. " Regentanz") - assert_equal(0, r:get_resource("money"), 0) - - local m = 0 - local p = 100 - for i=1,level+2 do - process_orders() - local income = p * 12 - p = r:get_resource("peasant") - income = income - p * 10 - m = m + income - -- print(i, m, p, r:get_resource("money")) - if (i>level+1) then - assert_not_equal(m, r:get_resource("money")) - else - assert_equal(m, r:get_resource("money")) - end - u:clear_orders() - u:add_order("ARBEITEN") --- u:add_spell("raindance") - end -end +require "lunit" + +module( "spells", package.seeall, lunit.testcase ) + +function setup() + free_game() +end + +function test_roi() + local r = region.create(0,0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u.race = "elf" + u:set_skill("magic", 10) + u:add_item("money", 3010) + u.magic = "tybied" + u.aura = 200 + u.ship = s1 + u:add_spell("create_roi") + u:clear_orders() + u:add_order("ZAUBERE 'Erschaffe einen Ring der Unsichtbarkeit' ") + process_orders() + write_reports() + assert_equal(1, u:get_item("roi")) +end + +function test_blessedharvest_lasts_n_turn() + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "halfling", "de") + local u = unit.create(f, r) + r:set_resource("peasant", 100) + r:set_resource("money", 0) + u:add_item("money", 1000) + u.magic = "gwyrrd" + u.race = "dwarf" + u:set_skill("magic", 20) + u.aura = 200 + u:add_spell("raindance") + u:add_spell("blessedharvest") + u:clear_orders() + local level = 5 + u:add_order("ZAUBERE STUFE " .. level .. " Regentanz") + assert_equal(0, r:get_resource("money"), 0) + + local m = 0 + local p = 100 + for i=1,level+2 do + process_orders() + local income = p * 12 + p = r:get_resource("peasant") + income = income - p * 10 + m = m + income + -- print(i, m, p, r:get_resource("money")) + if (i>level+1) then + assert_not_equal(m, r:get_resource("money")) + else + assert_equal(m, r:get_resource("money")) + end + u:clear_orders() + u:add_order("ARBEITEN") +-- u:add_spell("raindance") + end +end diff --git a/src/attributes/aggressive.h b/src/attributes/aggressive.h index bcd173cd7..dd6060637 100644 --- a/src/attributes/aggressive.h +++ b/src/attributes/aggressive.h @@ -1,33 +1,33 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_AGGRESSIVE -#define H_ATTRIBUTE_AGGRESSIVE -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_aggressive; -extern struct attrib * make_aggressive(double probability); -extern void init_aggressive(void); - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_AGGRESSIVE +#define H_ATTRIBUTE_AGGRESSIVE +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_aggressive; +extern struct attrib * make_aggressive(double probability); +extern void init_aggressive(void); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/alliance.c b/src/attributes/alliance.c index c0fd3a9a7..526ec18db 100644 --- a/src/attributes/alliance.c +++ b/src/attributes/alliance.c @@ -1,34 +1,34 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "alliance.h" - -#include -#include - -attrib_type at_alliance = { - "alliance", - NULL, - NULL, - NULL, - a_writeint, - a_readint, - ATF_UNIQUE -}; +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "alliance.h" + +#include +#include + +attrib_type at_alliance = { + "alliance", + NULL, + NULL, + NULL, + a_writeint, + a_readint, + ATF_UNIQUE +}; diff --git a/src/attributes/alliance.h b/src/attributes/alliance.h index d89f70989..42336c47b 100644 --- a/src/attributes/alliance.h +++ b/src/attributes/alliance.h @@ -1,31 +1,31 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_ALLIANCE -#define H_ATTRIBUTE_ALLIANCE -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_alliance; - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_ALLIANCE +#define H_ATTRIBUTE_ALLIANCE +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_alliance; + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/attributes.c b/src/attributes/attributes.c index 0efc00aba..8e9d4a0cd 100644 --- a/src/attributes/attributes.c +++ b/src/attributes/attributes.c @@ -1,81 +1,81 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "attributes.h" - -/* attributes includes */ -#include "follow.h" -#include "gm.h" -#include "hate.h" -#include "iceberg.h" -#include "key.h" -#include "moved.h" -#include "movement.h" -#include "object.h" -#include "orcification.h" -#include "otherfaction.h" -#include "overrideroads.h" -#include "racename.h" -#include "raceprefix.h" -#include "reduceproduction.h" -#include "targetregion.h" -#ifdef WDW_PYRAMID -# include "alliance.h" -#endif - -/* kernel includes */ -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include - -attrib_type at_unitdissolve = { - "unitdissolve", NULL, NULL, NULL, a_writechars, a_readchars -}; - -void -register_attributes(void) -{ - at_register(&at_object); - at_register(&at_unitdissolve); - at_register(&at_overrideroads); - at_register(&at_raceprefix); - at_register(&at_iceberg); - at_register(&at_key); - at_register(&at_gm); - at_register(&at_follow); - at_register(&at_targetregion); - at_register(&at_orcification); - at_register(&at_hate); - at_register(&at_reduceproduction); - at_register(&at_otherfaction); - at_register(&at_racename); - at_register(&at_movement); - at_register(&at_moved); - -#ifdef WDW_PYRAMID - at_register(&at_alliance); -#endif /* WDW_PYRAMID */ -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "attributes.h" + +/* attributes includes */ +#include "follow.h" +#include "gm.h" +#include "hate.h" +#include "iceberg.h" +#include "key.h" +#include "moved.h" +#include "movement.h" +#include "object.h" +#include "orcification.h" +#include "otherfaction.h" +#include "overrideroads.h" +#include "racename.h" +#include "raceprefix.h" +#include "reduceproduction.h" +#include "targetregion.h" +#ifdef WDW_PYRAMID +# include "alliance.h" +#endif + +/* kernel includes */ +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include + +attrib_type at_unitdissolve = { + "unitdissolve", NULL, NULL, NULL, a_writechars, a_readchars +}; + +void +register_attributes(void) +{ + at_register(&at_object); + at_register(&at_unitdissolve); + at_register(&at_overrideroads); + at_register(&at_raceprefix); + at_register(&at_iceberg); + at_register(&at_key); + at_register(&at_gm); + at_register(&at_follow); + at_register(&at_targetregion); + at_register(&at_orcification); + at_register(&at_hate); + at_register(&at_reduceproduction); + at_register(&at_otherfaction); + at_register(&at_racename); + at_register(&at_movement); + at_register(&at_moved); + +#ifdef WDW_PYRAMID + at_register(&at_alliance); +#endif /* WDW_PYRAMID */ +} diff --git a/src/attributes/attributes.h b/src/attributes/attributes.h index 76ba24069..594ecf3f3 100644 --- a/src/attributes/attributes.h +++ b/src/attributes/attributes.h @@ -1,31 +1,31 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_ATTRIBUTES -#define H_ATTRIBUTE_ATTRIBUTES -#ifdef __cplusplus -extern "C" { -#endif - -extern void register_attributes(void); - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_ATTRIBUTES +#define H_ATTRIBUTE_ATTRIBUTES +#ifdef __cplusplus +extern "C" { +#endif + +extern void register_attributes(void); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/fleechance.c b/src/attributes/fleechance.c index cb092c7d1..24062bd55 100644 --- a/src/attributes/fleechance.c +++ b/src/attributes/fleechance.c @@ -1,45 +1,45 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "fleechance.h" - -#include - -attrib_type at_fleechance = { - "fleechance", - NULL, - NULL, - NULL, - NULL, - NULL, -}; - -attrib * -make_fleechance(float fleechance) -{ - attrib * a = a_new(&at_fleechance); - a->data.flt = fleechance; - return a; -} - -void -init_fleechance(void) -{ - at_register(&at_fleechance); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "fleechance.h" + +#include + +attrib_type at_fleechance = { + "fleechance", + NULL, + NULL, + NULL, + NULL, + NULL, +}; + +attrib * +make_fleechance(float fleechance) +{ + attrib * a = a_new(&at_fleechance); + a->data.flt = fleechance; + return a; +} + +void +init_fleechance(void) +{ + at_register(&at_fleechance); +} diff --git a/src/attributes/fleechance.h b/src/attributes/fleechance.h index d26b4095e..482b1ad64 100644 --- a/src/attributes/fleechance.h +++ b/src/attributes/fleechance.h @@ -1,33 +1,33 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_FLEECHANCE -#define H_ATTRIBUTE_FLEECHANCE -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_fleechance; - -extern struct attrib * make_fleechance(float fleechance); -extern void init_fleechance(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_FLEECHANCE +#define H_ATTRIBUTE_FLEECHANCE +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_fleechance; + +extern struct attrib * make_fleechance(float fleechance); +extern void init_fleechance(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/attributes/follow.c b/src/attributes/follow.c index 519372830..d080a0d49 100644 --- a/src/attributes/follow.c +++ b/src/attributes/follow.c @@ -1,46 +1,46 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "follow.h" - -#include -#include - -#include -#include -#include - -static int -read_follow(attrib * a, void * owner, struct storage * store) -{ - read_unit_reference(store); /* skip it */ - return AT_READ_FAIL; -} - -attrib_type at_follow = { - "follow", NULL, NULL, NULL, NULL, read_follow -}; - -attrib * -make_follow(struct unit * u) -{ - attrib * a = a_new(&at_follow); - a->data.v = u; - return a; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "follow.h" + +#include +#include + +#include +#include +#include + +static int +read_follow(attrib * a, void * owner, struct storage * store) +{ + read_unit_reference(store); /* skip it */ + return AT_READ_FAIL; +} + +attrib_type at_follow = { + "follow", NULL, NULL, NULL, NULL, read_follow +}; + +attrib * +make_follow(struct unit * u) +{ + attrib * a = a_new(&at_follow); + a->data.v = u; + return a; +} diff --git a/src/attributes/follow.h b/src/attributes/follow.h index f619842d8..0328949cc 100644 --- a/src/attributes/follow.h +++ b/src/attributes/follow.h @@ -1,35 +1,35 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_FOLLOW -#define H_ATTRIBUTE_FOLLOW -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_follow; - -struct unit; - -extern struct attrib * make_follow(struct unit * u); - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_FOLLOW +#define H_ATTRIBUTE_FOLLOW +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_follow; + +struct unit; + +extern struct attrib * make_follow(struct unit * u); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/giveitem.c b/src/attributes/giveitem.c index ed393e28e..db0b136eb 100644 --- a/src/attributes/giveitem.c +++ b/src/attributes/giveitem.c @@ -1,135 +1,135 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "giveitem.h" -#include - -/* kernel includes */ -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include - -typedef struct give_data { - struct building * building; - struct item * items; -} give_data; - -static void -a_writegive(const attrib * a, const void * owner, struct storage * store) -{ - give_data * gdata = (give_data*)a->data.v; - item * itm; - write_building_reference(gdata->building, store); - for (itm=gdata->items;itm;itm=itm->next) { - store->w_tok(store, resourcename(itm->type->rtype, 0)); - store->w_int(store, itm->number); - } - store->w_tok(store, "end"); -} - -static int -a_readgive(attrib * a, void * owner, struct storage * store) -{ - give_data * gdata = (give_data*)a->data.v; - variant var; - char zText[32]; - - var.i = store->r_id(store); - if (var.i>0) { - gdata->building = findbuilding(var.i); - if (gdata->building==NULL) { - ur_add(var, &gdata->building, resolve_building); - } - } else { - gdata->building=NULL; - } - for (;;) { - int i; - store->r_tok_buf(store, zText, sizeof(zText)); - if (!strcmp("end", zText)) break; - i = store->r_int(store); - if (i==0) i_add(&gdata->items, i_new(it_find(zText), i)); - } - return AT_READ_OK; -} - -static void -a_initgive(struct attrib * a) -{ - a->data.v = calloc(sizeof(give_data), 1); -} - -static void -a_finalizegive(struct attrib * a) -{ - free(a->data.v); -} - -static int -a_giveitem(attrib * a) -{ - give_data * gdata = (give_data*)a->data.v; - region * r; - unit * u; - if (gdata->building==NULL || gdata->items==NULL) return 0; - r = gdata->building->region; - u = building_owner(gdata->building); - if (u==NULL) return 1; - while (gdata->items) { - item * itm = gdata->items; - i_change(&u->items, itm->type, itm->number); - i_free(i_remove(&gdata->items, itm)); - } - return 0; -} - -attrib_type at_giveitem = { - "giveitem", - a_initgive, a_finalizegive, - a_giveitem, - a_writegive, a_readgive -}; - -attrib * -make_giveitem(struct building * b, struct item * ip) -{ - attrib * a = a_new(&at_giveitem); - give_data * gd = (give_data*)a->data.v; - gd->building = b; - gd->items = ip; - return a; -} - -void -init_giveitem(void) -{ - at_register(&at_giveitem); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "giveitem.h" +#include + +/* kernel includes */ +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include + +typedef struct give_data { + struct building * building; + struct item * items; +} give_data; + +static void +a_writegive(const attrib * a, const void * owner, struct storage * store) +{ + give_data * gdata = (give_data*)a->data.v; + item * itm; + write_building_reference(gdata->building, store); + for (itm=gdata->items;itm;itm=itm->next) { + store->w_tok(store, resourcename(itm->type->rtype, 0)); + store->w_int(store, itm->number); + } + store->w_tok(store, "end"); +} + +static int +a_readgive(attrib * a, void * owner, struct storage * store) +{ + give_data * gdata = (give_data*)a->data.v; + variant var; + char zText[32]; + + var.i = store->r_id(store); + if (var.i>0) { + gdata->building = findbuilding(var.i); + if (gdata->building==NULL) { + ur_add(var, &gdata->building, resolve_building); + } + } else { + gdata->building=NULL; + } + for (;;) { + int i; + store->r_tok_buf(store, zText, sizeof(zText)); + if (!strcmp("end", zText)) break; + i = store->r_int(store); + if (i==0) i_add(&gdata->items, i_new(it_find(zText), i)); + } + return AT_READ_OK; +} + +static void +a_initgive(struct attrib * a) +{ + a->data.v = calloc(sizeof(give_data), 1); +} + +static void +a_finalizegive(struct attrib * a) +{ + free(a->data.v); +} + +static int +a_giveitem(attrib * a) +{ + give_data * gdata = (give_data*)a->data.v; + region * r; + unit * u; + if (gdata->building==NULL || gdata->items==NULL) return 0; + r = gdata->building->region; + u = building_owner(gdata->building); + if (u==NULL) return 1; + while (gdata->items) { + item * itm = gdata->items; + i_change(&u->items, itm->type, itm->number); + i_free(i_remove(&gdata->items, itm)); + } + return 0; +} + +attrib_type at_giveitem = { + "giveitem", + a_initgive, a_finalizegive, + a_giveitem, + a_writegive, a_readgive +}; + +attrib * +make_giveitem(struct building * b, struct item * ip) +{ + attrib * a = a_new(&at_giveitem); + give_data * gd = (give_data*)a->data.v; + gd->building = b; + gd->items = ip; + return a; +} + +void +init_giveitem(void) +{ + at_register(&at_giveitem); +} diff --git a/src/attributes/giveitem.h b/src/attributes/giveitem.h index 673738960..e45d3df56 100644 --- a/src/attributes/giveitem.h +++ b/src/attributes/giveitem.h @@ -1,36 +1,36 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_GIVEITEM -#define H_ATTRIBUTE_GIVEITEM -#ifdef __cplusplus -extern "C" { -#endif - -struct building; -struct item; - -extern struct attrib_type at_giveitem; - -extern struct attrib * make_giveitem(struct building * b, struct item * items); -extern void init_giveitem(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_GIVEITEM +#define H_ATTRIBUTE_GIVEITEM +#ifdef __cplusplus +extern "C" { +#endif + +struct building; +struct item; + +extern struct attrib_type at_giveitem; + +extern struct attrib * make_giveitem(struct building * b, struct item * items); +extern void init_giveitem(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/attributes/gm.c b/src/attributes/gm.c index 9f2514e17..bf062722a 100644 --- a/src/attributes/gm.c +++ b/src/attributes/gm.c @@ -1,61 +1,61 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "gm.h" - -/* kernel includes */ -#include - -/* util includes */ -#include -#include - -static void -write_gm(const attrib * a, const void * owner, struct storage * store) -{ - write_plane_reference((plane*)a->data.v, store); -} - -static int -read_gm(attrib * a, void * owner, struct storage * store) -{ - plane * pl; - int result = read_plane_reference(&pl, store); - a->data.v = pl; - return result; -} - - -attrib_type at_gm = { - "gm", - NULL, - NULL, - NULL, - write_gm, - read_gm, -}; - -attrib * -make_gm(const struct plane * pl) -{ - attrib * a = a_new(&at_gm); - a->data.v = (void*)pl; - return a; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "gm.h" + +/* kernel includes */ +#include + +/* util includes */ +#include +#include + +static void +write_gm(const attrib * a, const void * owner, struct storage * store) +{ + write_plane_reference((plane*)a->data.v, store); +} + +static int +read_gm(attrib * a, void * owner, struct storage * store) +{ + plane * pl; + int result = read_plane_reference(&pl, store); + a->data.v = pl; + return result; +} + + +attrib_type at_gm = { + "gm", + NULL, + NULL, + NULL, + write_gm, + read_gm, +}; + +attrib * +make_gm(const struct plane * pl) +{ + attrib * a = a_new(&at_gm); + a->data.v = (void*)pl; + return a; +} diff --git a/src/attributes/gm.h b/src/attributes/gm.h index 757092d43..341b4d76a 100644 --- a/src/attributes/gm.h +++ b/src/attributes/gm.h @@ -1,36 +1,36 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_GM -#define H_ATTRIBUTE_GM -#ifdef __cplusplus -extern "C" { -#endif - -/* this is an attribute used by the kernel (isallied) */ - -struct plane; -extern struct attrib_type at_gm; - -extern struct attrib * make_gm(const struct plane *pl); - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_GM +#define H_ATTRIBUTE_GM +#ifdef __cplusplus +extern "C" { +#endif + +/* this is an attribute used by the kernel (isallied) */ + +struct plane; +extern struct attrib_type at_gm; + +extern struct attrib * make_gm(const struct plane *pl); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/hate.c b/src/attributes/hate.c index 5b0e55423..545eec8e1 100644 --- a/src/attributes/hate.c +++ b/src/attributes/hate.c @@ -1,70 +1,70 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "hate.h" - -#include -#include - -#include -#include -#include - -static int -verify_hate(attrib * a) -{ - if (a->data.v==NULL) { - return 0; - } - return 1; -} - -static void -write_hate(const attrib * a, const void * owner, struct storage * store) -{ - write_unit_reference((unit*)a->data.v, store); -} - -static int -read_hate(attrib * a, void * owner, struct storage * store) -{ - int result = read_reference(&a->data.v, store, read_unit_reference, resolve_unit); - if (result==0 && !a->data.v) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -attrib_type at_hate = { - "hates", - NULL, - NULL, - verify_hate, - write_hate, - read_hate, -}; - -attrib * -make_hate(struct unit * u) -{ - attrib * a = a_new(&at_hate); - a->data.v = u; - return a; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "hate.h" + +#include +#include + +#include +#include +#include + +static int +verify_hate(attrib * a) +{ + if (a->data.v==NULL) { + return 0; + } + return 1; +} + +static void +write_hate(const attrib * a, const void * owner, struct storage * store) +{ + write_unit_reference((unit*)a->data.v, store); +} + +static int +read_hate(attrib * a, void * owner, struct storage * store) +{ + int result = read_reference(&a->data.v, store, read_unit_reference, resolve_unit); + if (result==0 && !a->data.v) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +attrib_type at_hate = { + "hates", + NULL, + NULL, + verify_hate, + write_hate, + read_hate, +}; + +attrib * +make_hate(struct unit * u) +{ + attrib * a = a_new(&at_hate); + a->data.v = u; + return a; +} diff --git a/src/attributes/hate.h b/src/attributes/hate.h index cda5d000c..e58c6205b 100644 --- a/src/attributes/hate.h +++ b/src/attributes/hate.h @@ -1,35 +1,35 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_HATE -#define H_ATTRIBUTE_HATE -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_hate; - -struct unit; - -extern struct attrib * make_hate(struct unit * u); - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_HATE +#define H_ATTRIBUTE_HATE +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_hate; + +struct unit; + +extern struct attrib * make_hate(struct unit * u); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/iceberg.c b/src/attributes/iceberg.c index 37a26e197..cb0efc7f3 100644 --- a/src/attributes/iceberg.c +++ b/src/attributes/iceberg.c @@ -1,42 +1,42 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "iceberg.h" - -#include -#include - -attrib_type at_iceberg = { - "iceberg_drift", - NULL, - NULL, - NULL, - a_writeint, - a_readint, - ATF_UNIQUE -}; - -attrib * -make_iceberg(direction_t dir) -{ - attrib * a = a_new(&at_iceberg); - a->data.i = (int)dir; - return a; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "iceberg.h" + +#include +#include + +attrib_type at_iceberg = { + "iceberg_drift", + NULL, + NULL, + NULL, + a_writeint, + a_readint, + ATF_UNIQUE +}; + +attrib * +make_iceberg(direction_t dir) +{ + attrib * a = a_new(&at_iceberg); + a->data.i = (int)dir; + return a; +} diff --git a/src/attributes/iceberg.h b/src/attributes/iceberg.h index 8356d2365..2f99d60dd 100644 --- a/src/attributes/iceberg.h +++ b/src/attributes/iceberg.h @@ -1,33 +1,33 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_ICEBERG -#define H_ATTRIBUTE_ICEBERG -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_iceberg; - -extern struct attrib * make_iceberg(direction_t dir); - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_ICEBERG +#define H_ATTRIBUTE_ICEBERG +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_iceberg; + +extern struct attrib * make_iceberg(direction_t dir); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/key.c b/src/attributes/key.c index 3d5d77469..ea612b01a 100644 --- a/src/attributes/key.c +++ b/src/attributes/key.c @@ -1,59 +1,59 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "key.h" - -#include -#include - -attrib_type at_key = { - "key", - NULL, - NULL, - NULL, - a_writeint, - a_readint, -}; - -attrib * -add_key(attrib ** alist, int key) -{ - attrib * a = find_key(*alist, key); - if (a==NULL) a = a_add(alist, make_key(key)); - return a; -} - -attrib * -make_key(int key) -{ - attrib * a = a_new(&at_key); - a->data.i = key; - return a; -} - -attrib * -find_key(attrib * alist, int key) -{ - attrib * a = a_find(alist, &at_key); - while (a && a->type==&at_key && a->data.i != key) { - a = a->next; - } - return (a && a->type==&at_key)?a:NULL; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "key.h" + +#include +#include + +attrib_type at_key = { + "key", + NULL, + NULL, + NULL, + a_writeint, + a_readint, +}; + +attrib * +add_key(attrib ** alist, int key) +{ + attrib * a = find_key(*alist, key); + if (a==NULL) a = a_add(alist, make_key(key)); + return a; +} + +attrib * +make_key(int key) +{ + attrib * a = a_new(&at_key); + a->data.i = key; + return a; +} + +attrib * +find_key(attrib * alist, int key) +{ + attrib * a = a_find(alist, &at_key); + while (a && a->type==&at_key && a->data.i != key) { + a = a->next; + } + return (a && a->type==&at_key)?a:NULL; +} diff --git a/src/attributes/key.h b/src/attributes/key.h index 00fc3bdf1..112bbe581 100644 --- a/src/attributes/key.h +++ b/src/attributes/key.h @@ -1,35 +1,35 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_KEY -#define H_ATTRIBUTE_KEY -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_key; - -extern struct attrib * make_key(int key); -extern struct attrib * find_key(struct attrib * alist, int key); -extern struct attrib * add_key(struct attrib ** alist, int key); - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_KEY +#define H_ATTRIBUTE_KEY +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_key; + +extern struct attrib * make_key(int key); +extern struct attrib * find_key(struct attrib * alist, int key); +extern struct attrib * add_key(struct attrib ** alist, int key); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/matmod.c b/src/attributes/matmod.c index 8dd9af252..8f8f6bec8 100644 --- a/src/attributes/matmod.c +++ b/src/attributes/matmod.c @@ -1,40 +1,40 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "matmod.h" - -#include - -attrib_type at_matmod = { - "matmod", - NULL, - NULL, - NULL, - NULL, - NULL, - ATF_PRESERVE -}; - -attrib * -make_matmod(mm_fun function) -{ - attrib * a = a_new(&at_matmod); - a->data.f = (void(*)(void))function; - return a; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "matmod.h" + +#include + +attrib_type at_matmod = { + "matmod", + NULL, + NULL, + NULL, + NULL, + NULL, + ATF_PRESERVE +}; + +attrib * +make_matmod(mm_fun function) +{ + attrib * a = a_new(&at_matmod); + a->data.f = (void(*)(void))function; + return a; +} diff --git a/src/attributes/matmod.h b/src/attributes/matmod.h index 4c683842c..e32b6a94c 100644 --- a/src/attributes/matmod.h +++ b/src/attributes/matmod.h @@ -1,37 +1,37 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_MATMOD -#define H_ATTRIBUTE_MATMOD - -#ifdef __cplusplus -extern "C" { -#endif - -struct resource_type; -struct unit; -typedef int (*mm_fun)(const struct unit * u, const struct resource_type * rtype, int value); - -extern struct attrib_type at_matmod; -extern struct attrib * make_matmod(mm_fun function); - -#ifdef __cplusplus -} -#endif - -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_MATMOD +#define H_ATTRIBUTE_MATMOD + +#ifdef __cplusplus +extern "C" { +#endif + +struct resource_type; +struct unit; +typedef int (*mm_fun)(const struct unit * u, const struct resource_type * rtype, int value); + +extern struct attrib_type at_matmod; +extern struct attrib * make_matmod(mm_fun function); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/attributes/moved.c b/src/attributes/moved.c index 18b5ad2ec..08c11ac1e 100644 --- a/src/attributes/moved.c +++ b/src/attributes/moved.c @@ -1,63 +1,63 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "moved.h" - -#include -#include - -static int -age_moved(attrib * a) -{ - --a->data.i; - return a->data.i > 0; -} - -static void -write_moved(const attrib * a, const void * owner, struct storage * store) -{ - store->w_int(store, a->data.i); -} - -static int -read_moved(attrib * a, void * owner, struct storage * store) -{ - a->data.i = store->r_int(store); - if (a->data.i !=0 ) return AT_READ_OK; - else return AT_READ_FAIL; -} - -attrib_type at_moved = { - "moved", NULL, NULL, age_moved, write_moved, read_moved -}; - -boolean -get_moved(attrib ** alist) -{ - return a_find(*alist, &at_moved) ? true : false; -} - -void -set_moved(attrib ** alist) -{ - attrib * a = a_find(*alist, &at_moved); - if (a==NULL) a = a_add(alist, a_new(&at_moved)); - a->data.i = 2; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "moved.h" + +#include +#include + +static int +age_moved(attrib * a) +{ + --a->data.i; + return a->data.i > 0; +} + +static void +write_moved(const attrib * a, const void * owner, struct storage * store) +{ + store->w_int(store, a->data.i); +} + +static int +read_moved(attrib * a, void * owner, struct storage * store) +{ + a->data.i = store->r_int(store); + if (a->data.i !=0 ) return AT_READ_OK; + else return AT_READ_FAIL; +} + +attrib_type at_moved = { + "moved", NULL, NULL, age_moved, write_moved, read_moved +}; + +boolean +get_moved(attrib ** alist) +{ + return a_find(*alist, &at_moved) ? true : false; +} + +void +set_moved(attrib ** alist) +{ + attrib * a = a_find(*alist, &at_moved); + if (a==NULL) a = a_add(alist, a_new(&at_moved)); + a->data.i = 2; +} diff --git a/src/attributes/moved.h b/src/attributes/moved.h index 1727829da..af84797ea 100644 --- a/src/attributes/moved.h +++ b/src/attributes/moved.h @@ -1,37 +1,37 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_MOVED -#define H_ATTRIBUTE_MOVED -#ifdef __cplusplus -extern "C" { -#endif - -struct attrib; -struct attrib_type; - -extern boolean get_moved(struct attrib ** alist); -extern void set_moved(struct attrib ** alist); - -extern struct attrib_type at_moved; - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_MOVED +#define H_ATTRIBUTE_MOVED +#ifdef __cplusplus +extern "C" { +#endif + +struct attrib; +struct attrib_type; + +extern boolean get_moved(struct attrib ** alist); +extern void set_moved(struct attrib ** alist); + +extern struct attrib_type at_moved; + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/movement.c b/src/attributes/movement.c index 9834928e5..125fbf779 100644 --- a/src/attributes/movement.c +++ b/src/attributes/movement.c @@ -1,59 +1,59 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "movement.h" - -#include -#include - -static void -write_movement(const attrib * a, const void * owner, struct storage * store) -{ - store->w_int(store, a->data.i); -} - -static int -read_movement(attrib * a, void * owner, struct storage * store) -{ - a->data.i = store->r_int(store); - if (a->data.i !=0 ) return AT_READ_OK; - else return AT_READ_FAIL; -} - -attrib_type at_movement = { - "movement", NULL, NULL, NULL, write_movement, read_movement -}; - -boolean -get_movement(attrib * const * alist, int type) -{ - const attrib * a = a_findc(*alist, &at_movement); - if (a==NULL) return false; - if (a->data.i & type) return true; - return false; -} - -void -set_movement(attrib ** alist, int type) -{ - attrib * a = a_find(*alist, &at_movement); - if (a==NULL) a = a_add(alist, a_new(&at_movement)); - a->data.i |= type; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "movement.h" + +#include +#include + +static void +write_movement(const attrib * a, const void * owner, struct storage * store) +{ + store->w_int(store, a->data.i); +} + +static int +read_movement(attrib * a, void * owner, struct storage * store) +{ + a->data.i = store->r_int(store); + if (a->data.i !=0 ) return AT_READ_OK; + else return AT_READ_FAIL; +} + +attrib_type at_movement = { + "movement", NULL, NULL, NULL, write_movement, read_movement +}; + +boolean +get_movement(attrib * const * alist, int type) +{ + const attrib * a = a_findc(*alist, &at_movement); + if (a==NULL) return false; + if (a->data.i & type) return true; + return false; +} + +void +set_movement(attrib ** alist, int type) +{ + attrib * a = a_find(*alist, &at_movement); + if (a==NULL) a = a_add(alist, a_new(&at_movement)); + a->data.i |= type; +} diff --git a/src/attributes/movement.h b/src/attributes/movement.h index dde7c98d4..53ae8f923 100644 --- a/src/attributes/movement.h +++ b/src/attributes/movement.h @@ -1,33 +1,33 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_MOVEMENT -#define H_ATTRIBUTE_MOVEMENT -#ifdef __cplusplus -extern "C" { -#endif - -extern boolean get_movement(struct attrib * const * alist, int type); -extern void set_movement(struct attrib ** alist, int type); - -extern struct attrib_type at_movement; - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_MOVEMENT +#define H_ATTRIBUTE_MOVEMENT +#ifdef __cplusplus +extern "C" { +#endif + +extern boolean get_movement(struct attrib * const * alist, int type); +extern void set_movement(struct attrib ** alist, int type); + +extern struct attrib_type at_movement; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/attributes/object.c b/src/attributes/object.c index d03a5f32c..033fd8b32 100644 --- a/src/attributes/object.c +++ b/src/attributes/object.c @@ -1,267 +1,267 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "object.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include - -/* stdc includes */ -#include -#include - -typedef struct object_data { - object_type type; - char * name; - union { - int i; - char * str; - double real; - struct unit * u; - struct region * r; - struct building * b; - struct ship * sh; - struct faction * f; - } data; -} object_data; - -static void -object_write(const attrib * a, const void * owner, struct storage * store) -{ - const object_data * data = (object_data *)a->data.v; - int type = (int)data->type; - store->w_tok(store, data->name); - store->w_int(store, type); - switch (data->type) { - case TINTEGER: - store->w_int(store, data->data.i); - break; - case TREAL: - store->w_flt(store, (float)data->data.real); - break; - case TSTRING: - store->w_str(store, data->data.str); - break; - case TUNIT: - write_unit_reference(data->data.u, store ); - break; - case TFACTION: - write_faction_reference(data->data.f, store); - break; - case TBUILDING: - write_building_reference(data->data.b, store); - break; - case TSHIP: - /* write_ship_reference(data->data.sh, store); */ - assert(!"not implemented"); - break; - case TREGION: - write_region_reference(data->data.r, store); - break; - case TNONE: - break; - default: - assert(!"illegal type in object-attribute"); - } -} - -static int -object_read(attrib *a, void * owner, struct storage * store) -{ - object_data * data = (object_data *)a->data.v; - int result; - - data->name = store->r_str(store); - data->type = (object_type)store->r_int(store); - switch (data->type) { - case TINTEGER: - data->data.i = store->r_int(store); - break; - case TREAL: - data->data.real = store->r_flt(store); - break; - case TSTRING: - data->data.str = store->r_str(store); - break; - case TBUILDING: - result = read_reference(&data->data.b, store, read_building_reference, resolve_building); - if (result==0 && !data->data.b) { - return AT_READ_FAIL; - } - break; - case TUNIT: - result = read_reference(&data->data.u, store, read_unit_reference, resolve_unit); - if (result==0 && !data->data.u) { - return AT_READ_FAIL; - } - break; - case TFACTION: - result = read_reference(&data->data.f, store, read_faction_reference, resolve_faction); - if (result==0 && !data->data.f) { - return AT_READ_FAIL; - } - break; - case TREGION: - result = read_reference(&data->data.r, store, read_region_reference, RESOLVE_REGION(store->version)); - if (result==0 && !data->data.r) { - return AT_READ_FAIL; - } - break; - case TSHIP: - /* return read_ship_reference(&data->data.sh, store); */ - assert(!"not implemented"); - break; - case TNONE: - break; - default: - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -static void -object_init(attrib * a) -{ - object_data * data; - a->data.v = malloc(sizeof(object_data)); - data = (object_data *)a->data.v; - data->type = TNONE; -} - -static void -object_done(attrib * a) -{ - object_data * data = (object_data *)a->data.v; - if (data->type == TSTRING) free(data->data.str); - free(data->name); - free(a->data.v); -} - -attrib_type at_object = { - "object", object_init, object_done, NULL, - object_write, object_read -}; - -const char * -object_name(const attrib * a) -{ - object_data * data = (object_data *)a->data.v; - return data->name; -} - -struct attrib * -object_create(const char * name, object_type type, variant value) -{ - attrib * a = a_new(&at_object); - object_data * data = (object_data *)a->data.v; - data->name = strdup(name); - - object_set(a, type, value); - return a; -} - -void -object_set(attrib * a, object_type type, variant value) -{ - object_data * data = (object_data *)a->data.v; - - if (data->type==TSTRING) free(data->data.str); - data->type = type; - switch (type) { - case TSTRING: - data->data.str = value.v?strdup(value.v):NULL; - break; - case TINTEGER: - data->data.i = value.i; - break; - case TREAL: - data->data.real = value.f; - break; - case TREGION: - data->data.r = (region*)value.v; - break; - case TBUILDING: - data->data.b = (building*)value.v; - break; - case TFACTION: - data->data.f = (faction*)value.v; - break; - case TUNIT: - data->data.u = (unit*)value.v; - break; - case TSHIP: - data->data.sh = (ship*)value.v; - break; - case TNONE: - break; - default: - assert(!"invalid object-type"); - break; - } -} - -void -object_get(const struct attrib * a, object_type * type, variant * value) -{ - object_data * data = (object_data *)a->data.v; - *type = data->type; - switch (data->type) { - case TSTRING: - value->v = data->data.str; - break; - case TINTEGER: - value->i = data->data.i; - break; - case TREAL: - value->f = (float)data->data.real; - break; - case TREGION: - value->v = data->data.r; - break; - case TBUILDING: - value->v = data->data.b; - break; - case TFACTION: - value->v = data->data.f; - break; - case TUNIT: - value->v = data->data.u; - break; - case TSHIP: - value->v = data->data.sh; - break; - case TNONE: - break; - default: - assert(!"invalid object-type"); - break; - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "object.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include + +/* stdc includes */ +#include +#include + +typedef struct object_data { + object_type type; + char * name; + union { + int i; + char * str; + double real; + struct unit * u; + struct region * r; + struct building * b; + struct ship * sh; + struct faction * f; + } data; +} object_data; + +static void +object_write(const attrib * a, const void * owner, struct storage * store) +{ + const object_data * data = (object_data *)a->data.v; + int type = (int)data->type; + store->w_tok(store, data->name); + store->w_int(store, type); + switch (data->type) { + case TINTEGER: + store->w_int(store, data->data.i); + break; + case TREAL: + store->w_flt(store, (float)data->data.real); + break; + case TSTRING: + store->w_str(store, data->data.str); + break; + case TUNIT: + write_unit_reference(data->data.u, store ); + break; + case TFACTION: + write_faction_reference(data->data.f, store); + break; + case TBUILDING: + write_building_reference(data->data.b, store); + break; + case TSHIP: + /* write_ship_reference(data->data.sh, store); */ + assert(!"not implemented"); + break; + case TREGION: + write_region_reference(data->data.r, store); + break; + case TNONE: + break; + default: + assert(!"illegal type in object-attribute"); + } +} + +static int +object_read(attrib *a, void * owner, struct storage * store) +{ + object_data * data = (object_data *)a->data.v; + int result; + + data->name = store->r_str(store); + data->type = (object_type)store->r_int(store); + switch (data->type) { + case TINTEGER: + data->data.i = store->r_int(store); + break; + case TREAL: + data->data.real = store->r_flt(store); + break; + case TSTRING: + data->data.str = store->r_str(store); + break; + case TBUILDING: + result = read_reference(&data->data.b, store, read_building_reference, resolve_building); + if (result==0 && !data->data.b) { + return AT_READ_FAIL; + } + break; + case TUNIT: + result = read_reference(&data->data.u, store, read_unit_reference, resolve_unit); + if (result==0 && !data->data.u) { + return AT_READ_FAIL; + } + break; + case TFACTION: + result = read_reference(&data->data.f, store, read_faction_reference, resolve_faction); + if (result==0 && !data->data.f) { + return AT_READ_FAIL; + } + break; + case TREGION: + result = read_reference(&data->data.r, store, read_region_reference, RESOLVE_REGION(store->version)); + if (result==0 && !data->data.r) { + return AT_READ_FAIL; + } + break; + case TSHIP: + /* return read_ship_reference(&data->data.sh, store); */ + assert(!"not implemented"); + break; + case TNONE: + break; + default: + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +static void +object_init(attrib * a) +{ + object_data * data; + a->data.v = malloc(sizeof(object_data)); + data = (object_data *)a->data.v; + data->type = TNONE; +} + +static void +object_done(attrib * a) +{ + object_data * data = (object_data *)a->data.v; + if (data->type == TSTRING) free(data->data.str); + free(data->name); + free(a->data.v); +} + +attrib_type at_object = { + "object", object_init, object_done, NULL, + object_write, object_read +}; + +const char * +object_name(const attrib * a) +{ + object_data * data = (object_data *)a->data.v; + return data->name; +} + +struct attrib * +object_create(const char * name, object_type type, variant value) +{ + attrib * a = a_new(&at_object); + object_data * data = (object_data *)a->data.v; + data->name = strdup(name); + + object_set(a, type, value); + return a; +} + +void +object_set(attrib * a, object_type type, variant value) +{ + object_data * data = (object_data *)a->data.v; + + if (data->type==TSTRING) free(data->data.str); + data->type = type; + switch (type) { + case TSTRING: + data->data.str = value.v?strdup(value.v):NULL; + break; + case TINTEGER: + data->data.i = value.i; + break; + case TREAL: + data->data.real = value.f; + break; + case TREGION: + data->data.r = (region*)value.v; + break; + case TBUILDING: + data->data.b = (building*)value.v; + break; + case TFACTION: + data->data.f = (faction*)value.v; + break; + case TUNIT: + data->data.u = (unit*)value.v; + break; + case TSHIP: + data->data.sh = (ship*)value.v; + break; + case TNONE: + break; + default: + assert(!"invalid object-type"); + break; + } +} + +void +object_get(const struct attrib * a, object_type * type, variant * value) +{ + object_data * data = (object_data *)a->data.v; + *type = data->type; + switch (data->type) { + case TSTRING: + value->v = data->data.str; + break; + case TINTEGER: + value->i = data->data.i; + break; + case TREAL: + value->f = (float)data->data.real; + break; + case TREGION: + value->v = data->data.r; + break; + case TBUILDING: + value->v = data->data.b; + break; + case TFACTION: + value->v = data->data.f; + break; + case TUNIT: + value->v = data->data.u; + break; + case TSHIP: + value->v = data->data.sh; + break; + case TNONE: + break; + default: + assert(!"invalid object-type"); + break; + } +} diff --git a/src/attributes/object.h b/src/attributes/object.h index 61c13cb5d..c0ebcab7e 100644 --- a/src/attributes/object.h +++ b/src/attributes/object.h @@ -1,38 +1,38 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_ATTRIBUTE_OBJECT -#define H_ATTRIBUTE_OBJECT - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - TNONE = 0, TINTEGER = 1, TREAL = 2, TSTRING = 3, - TUNIT = 10, TFACTION = 11, TREGION = 12, TBUILDING = 13, TSHIP = 14, -} object_type; - -extern struct attrib_type at_object; - -extern struct attrib * object_create(const char * name, object_type type, variant value); -extern void object_get(const struct attrib * a, object_type * type, variant * value); -extern void object_set(struct attrib * a, object_type type, variant value); -extern const char * object_name(const struct attrib * a); - -#ifdef __cplusplus -} -#endif -#endif - +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_ATTRIBUTE_OBJECT +#define H_ATTRIBUTE_OBJECT + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + TNONE = 0, TINTEGER = 1, TREAL = 2, TSTRING = 3, + TUNIT = 10, TFACTION = 11, TREGION = 12, TBUILDING = 13, TSHIP = 14, +} object_type; + +extern struct attrib_type at_object; + +extern struct attrib * object_create(const char * name, object_type type, variant value); +extern void object_get(const struct attrib * a, object_type * type, variant * value); +extern void object_set(struct attrib * a, object_type type, variant value); +extern const char * object_name(const struct attrib * a); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/orcification.c b/src/attributes/orcification.c index 1e2b8822b..745d13e24 100644 --- a/src/attributes/orcification.c +++ b/src/attributes/orcification.c @@ -1,40 +1,40 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "orcification.h" - -#include -#include - -/* - * simple attributes that do not yet have their own file - */ - -attrib_type at_orcification = { - "orcification", NULL, NULL, NULL, a_writeint, a_readint, ATF_UNIQUE -}; - -attrib * -make_orcification(int orcification) -{ - attrib * a = a_new(&at_orcification); - a->data.i = orcification; - return a; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "orcification.h" + +#include +#include + +/* + * simple attributes that do not yet have their own file + */ + +attrib_type at_orcification = { + "orcification", NULL, NULL, NULL, a_writeint, a_readint, ATF_UNIQUE +}; + +attrib * +make_orcification(int orcification) +{ + attrib * a = a_new(&at_orcification); + a->data.i = orcification; + return a; +} diff --git a/src/attributes/orcification.h b/src/attributes/orcification.h index 51a167276..285e9414e 100644 --- a/src/attributes/orcification.h +++ b/src/attributes/orcification.h @@ -1,28 +1,28 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifdef __cplusplus -extern "C" { -#endif -extern struct attrib_type at_orcification; - -extern struct attrib * make_orcification(int orcification); - -#ifdef __cplusplus -} -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifdef __cplusplus +extern "C" { +#endif +extern struct attrib_type at_orcification; + +extern struct attrib * make_orcification(int orcification); + +#ifdef __cplusplus +} +#endif diff --git a/src/attributes/otherfaction.c b/src/attributes/otherfaction.c index c970b4ed2..14c4a3d03 100644 --- a/src/attributes/otherfaction.c +++ b/src/attributes/otherfaction.c @@ -1,80 +1,80 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "otherfaction.h" - -#include -#include -#include -#include -#include - -/* - * simple attributes that do not yet have their own file - */ - - -void -write_of(const struct attrib * a, const void * owner, struct storage * store) -{ - const faction * f = (faction*)a->data.v; - store->w_int(store, f->no); -} - -int -read_of(struct attrib * a, void * owner, struct storage * store) /* return 1 on success, 0 if attrib needs removal */ -{ - int of = store->r_int(store); - a->data.v = findfaction(of); - if (a->data.v) return AT_READ_OK; - return AT_READ_FAIL; -} - -attrib_type at_otherfaction = { - "otherfaction", NULL, NULL, NULL, write_of, read_of, ATF_UNIQUE -}; - -struct faction * - get_otherfaction(const struct attrib * a) -{ - return (faction*)(a->data.v); -} - -struct attrib * - make_otherfaction(struct faction * f) -{ - attrib * a = a_new(&at_otherfaction); - a->data.v = (void*)f; - return a; -} - -faction * -visible_faction(const faction *f, const unit * u) -{ - if (f==NULL || !alliedunit(u, f, HELP_FSTEALTH)) { - attrib *a = a_find(u->attribs, &at_otherfaction); - if (a) { - faction *fv = get_otherfaction(a); - assert (fv != NULL); /* fv should never be NULL! */ - return fv; - } - } - return u->faction; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "otherfaction.h" + +#include +#include +#include +#include +#include + +/* + * simple attributes that do not yet have their own file + */ + + +void +write_of(const struct attrib * a, const void * owner, struct storage * store) +{ + const faction * f = (faction*)a->data.v; + store->w_int(store, f->no); +} + +int +read_of(struct attrib * a, void * owner, struct storage * store) /* return 1 on success, 0 if attrib needs removal */ +{ + int of = store->r_int(store); + a->data.v = findfaction(of); + if (a->data.v) return AT_READ_OK; + return AT_READ_FAIL; +} + +attrib_type at_otherfaction = { + "otherfaction", NULL, NULL, NULL, write_of, read_of, ATF_UNIQUE +}; + +struct faction * + get_otherfaction(const struct attrib * a) +{ + return (faction*)(a->data.v); +} + +struct attrib * + make_otherfaction(struct faction * f) +{ + attrib * a = a_new(&at_otherfaction); + a->data.v = (void*)f; + return a; +} + +faction * +visible_faction(const faction *f, const unit * u) +{ + if (f==NULL || !alliedunit(u, f, HELP_FSTEALTH)) { + attrib *a = a_find(u->attribs, &at_otherfaction); + if (a) { + faction *fv = get_otherfaction(a); + assert (fv != NULL); /* fv should never be NULL! */ + return fv; + } + } + return u->faction; +} diff --git a/src/attributes/otherfaction.h b/src/attributes/otherfaction.h index 79c6b24ad..4fe99f295 100644 --- a/src/attributes/otherfaction.h +++ b/src/attributes/otherfaction.h @@ -1,33 +1,33 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifdef __cplusplus -extern "C" { -#endif - -struct faction; -struct attrib; -extern struct attrib_type at_otherfaction; - -extern struct faction * get_otherfaction(const struct attrib * a); -extern struct attrib * make_otherfaction(struct faction * f); -extern struct faction * visible_faction(const struct faction *f, const struct unit * u); - -#ifdef __cplusplus -extern "C" { -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifdef __cplusplus +extern "C" { +#endif + +struct faction; +struct attrib; +extern struct attrib_type at_otherfaction; + +extern struct faction * get_otherfaction(const struct attrib * a); +extern struct attrib * make_otherfaction(struct faction * f); +extern struct faction * visible_faction(const struct faction *f, const struct unit * u); + +#ifdef __cplusplus +extern "C" { +#endif diff --git a/src/attributes/overrideroads.c b/src/attributes/overrideroads.c index e1dc75b3d..96803a2a9 100644 --- a/src/attributes/overrideroads.c +++ b/src/attributes/overrideroads.c @@ -1,29 +1,29 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "overrideroads.h" - -#include -#include - -attrib_type at_overrideroads = { - "roads_override", NULL, NULL, NULL, &a_writestring, &a_readstring -}; - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "overrideroads.h" + +#include +#include + +attrib_type at_overrideroads = { + "roads_override", NULL, NULL, NULL, &a_writestring, &a_readstring +}; + diff --git a/src/attributes/overrideroads.h b/src/attributes/overrideroads.h index 731c9eee9..a9322c598 100644 --- a/src/attributes/overrideroads.h +++ b/src/attributes/overrideroads.h @@ -1,31 +1,31 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_OVERRRIDEROADS -#define H_ATTRIBUTE_OVERRRIDEROADS -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_overrideroads; - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_OVERRRIDEROADS +#define H_ATTRIBUTE_OVERRRIDEROADS +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_overrideroads; + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/racename.c b/src/attributes/racename.c index 09a7e9e22..39ba6b4fa 100644 --- a/src/attributes/racename.c +++ b/src/attributes/racename.c @@ -1,57 +1,57 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "racename.h" - -#include -#include - -/* libc includes */ -#include -#include - -attrib_type at_racename = { - "racename", NULL, a_finalizestring, NULL, a_writestring, a_readstring -}; - -const char * -get_racename(attrib * alist) -{ - attrib * a = a_find(alist, &at_racename); - if (a) return (const char *)a->data.v; - return NULL; -} - -void -set_racename(attrib ** palist, const char * name) -{ - attrib * a = a_find(*palist, &at_racename); - if (!a && name) { - a = a_add(palist, a_new(&at_racename)); - a->data.v = strdup(name); - } else if (a && !name) { - a_remove(palist, a); - } else if (a) { - if (strcmp(a->data.v, name)!=0) { - free(a->data.v); - a->data.v = strdup(name); - } - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "racename.h" + +#include +#include + +/* libc includes */ +#include +#include + +attrib_type at_racename = { + "racename", NULL, a_finalizestring, NULL, a_writestring, a_readstring +}; + +const char * +get_racename(attrib * alist) +{ + attrib * a = a_find(alist, &at_racename); + if (a) return (const char *)a->data.v; + return NULL; +} + +void +set_racename(attrib ** palist, const char * name) +{ + attrib * a = a_find(*palist, &at_racename); + if (!a && name) { + a = a_add(palist, a_new(&at_racename)); + a->data.v = strdup(name); + } else if (a && !name) { + a_remove(palist, a); + } else if (a) { + if (strcmp(a->data.v, name)!=0) { + free(a->data.v); + a->data.v = strdup(name); + } + } +} diff --git a/src/attributes/racename.h b/src/attributes/racename.h index 224494706..04b271e35 100644 --- a/src/attributes/racename.h +++ b/src/attributes/racename.h @@ -1,37 +1,37 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_RACENAME_H -#define H_ATTRIBUTE_RACENAME_H -#ifdef __cplusplus -extern "C" { -#endif - -struct attrib_type; -struct attrib; - -extern void set_racename(struct attrib ** palist, const char * name); -extern const char * get_racename(struct attrib * alist); - -extern struct attrib_type at_racename; - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_RACENAME_H +#define H_ATTRIBUTE_RACENAME_H +#ifdef __cplusplus +extern "C" { +#endif + +struct attrib_type; +struct attrib; + +extern void set_racename(struct attrib ** palist, const char * name); +extern const char * get_racename(struct attrib * alist); + +extern struct attrib_type at_racename; + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/raceprefix.c b/src/attributes/raceprefix.c index 9eccf7a87..3c15a93a0 100644 --- a/src/attributes/raceprefix.c +++ b/src/attributes/raceprefix.c @@ -1,60 +1,60 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "raceprefix.h" -#include - -#include - -#include -#include - -attrib_type at_raceprefix = { - "raceprefix", NULL, a_finalizestring, NULL, a_writestring, a_readstring, ATF_UNIQUE -}; - -void -set_prefix(attrib ** ap, const char * str) -{ - attrib * a = a_find(*ap, &at_raceprefix); - if (a==NULL) { - a = a_add(ap, a_new(&at_raceprefix)); - } else { - free(a->data.v); - } - assert(a->type==&at_raceprefix); - a->data.v = strdup(str); -} - -const char * -get_prefix(const attrib * a) -{ - char * str; - a = a_findc(a, &at_raceprefix); - if (a==NULL) return NULL; - str = (char *)a->data.v; - /* conversion of old prefixes */ - if (strncmp(str, "prefix_", 7)==0) { - ((attrib*)a)->data.v = strdup(str+7); - free(str); - str = (char *)a->data.v; - } - return str; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "raceprefix.h" +#include + +#include + +#include +#include + +attrib_type at_raceprefix = { + "raceprefix", NULL, a_finalizestring, NULL, a_writestring, a_readstring, ATF_UNIQUE +}; + +void +set_prefix(attrib ** ap, const char * str) +{ + attrib * a = a_find(*ap, &at_raceprefix); + if (a==NULL) { + a = a_add(ap, a_new(&at_raceprefix)); + } else { + free(a->data.v); + } + assert(a->type==&at_raceprefix); + a->data.v = strdup(str); +} + +const char * +get_prefix(const attrib * a) +{ + char * str; + a = a_findc(a, &at_raceprefix); + if (a==NULL) return NULL; + str = (char *)a->data.v; + /* conversion of old prefixes */ + if (strncmp(str, "prefix_", 7)==0) { + ((attrib*)a)->data.v = strdup(str+7); + free(str); + str = (char *)a->data.v; + } + return str; +} diff --git a/src/attributes/raceprefix.h b/src/attributes/raceprefix.h index ec5c44398..f3fb85e7d 100644 --- a/src/attributes/raceprefix.h +++ b/src/attributes/raceprefix.h @@ -1,33 +1,33 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_RACEPREFIX -#define H_ATTRIBUTE_RACEPREFIX -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_raceprefix; -extern void set_prefix(struct attrib ** ap, const char * str); -extern const char * get_prefix(const struct attrib * a); - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_RACEPREFIX +#define H_ATTRIBUTE_RACEPREFIX +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_raceprefix; +extern void set_prefix(struct attrib ** ap, const char * str); +extern const char * get_prefix(const struct attrib * a); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/reduceproduction.c b/src/attributes/reduceproduction.c index ef240b7a8..3f1ef5ac9 100644 --- a/src/attributes/reduceproduction.c +++ b/src/attributes/reduceproduction.c @@ -1,51 +1,51 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "reduceproduction.h" -#include -#include - -static int -age_reduceproduction(attrib *a) -{ - int reduce = 100 - (5 * --a->data.sa[1]); - if (reduce < 10) reduce = 10; - a->data.sa[0] = (short)reduce; - return (a->data.sa[1]>0)?AT_AGE_KEEP:AT_AGE_REMOVE; -} - -attrib_type at_reduceproduction = { - "reduceproduction", - NULL, - NULL, - age_reduceproduction, - a_writeshorts, - a_readshorts, - ATF_UNIQUE -}; - -attrib * -make_reduceproduction(int percent, int time) -{ - attrib * a = a_new(&at_reduceproduction); - a->data.sa[0] = (short)percent; - a->data.sa[1] = (short)time; - return a; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "reduceproduction.h" +#include +#include + +static int +age_reduceproduction(attrib *a) +{ + int reduce = 100 - (5 * --a->data.sa[1]); + if (reduce < 10) reduce = 10; + a->data.sa[0] = (short)reduce; + return (a->data.sa[1]>0)?AT_AGE_KEEP:AT_AGE_REMOVE; +} + +attrib_type at_reduceproduction = { + "reduceproduction", + NULL, + NULL, + age_reduceproduction, + a_writeshorts, + a_readshorts, + ATF_UNIQUE +}; + +attrib * +make_reduceproduction(int percent, int time) +{ + attrib * a = a_new(&at_reduceproduction); + a->data.sa[0] = (short)percent; + a->data.sa[1] = (short)time; + return a; +} diff --git a/src/attributes/reduceproduction.h b/src/attributes/reduceproduction.h index 913b3075d..4bee20399 100644 --- a/src/attributes/reduceproduction.h +++ b/src/attributes/reduceproduction.h @@ -1,32 +1,32 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_REDUCEPRODUCTION -#define H_ATTRIBUTE_REDUCEPRODUCTION -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib * make_reduceproduction(int percent, int time); -extern struct attrib_type at_reduceproduction; - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_REDUCEPRODUCTION +#define H_ATTRIBUTE_REDUCEPRODUCTION +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib * make_reduceproduction(int percent, int time); +extern struct attrib_type at_reduceproduction; + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/targetregion.c b/src/attributes/targetregion.c index a9a31557c..d182e7fff 100644 --- a/src/attributes/targetregion.c +++ b/src/attributes/targetregion.c @@ -1,61 +1,61 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "targetregion.h" - -#include -#include -#include -#include - -#include -#include -#include - -static void -write_targetregion(const attrib * a, const void * owner, struct storage * store) -{ - write_region_reference((region*)a->data.v, store); -} - -static int -read_targetregion(attrib * a, void * owner, struct storage * store) -{ - int result = read_reference(&a->data.v, store, read_region_reference, RESOLVE_REGION(store->version)); - if (result==0 && !a->data.v) return AT_READ_FAIL; - return AT_READ_OK; -} - -attrib_type at_targetregion = { - "targetregion", - NULL, - NULL, - NULL, - write_targetregion, - read_targetregion, - ATF_UNIQUE -}; - -attrib * -make_targetregion(struct region * r) -{ - attrib * a = a_new(&at_targetregion); - a->data.v = r; - return a; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "targetregion.h" + +#include +#include +#include +#include + +#include +#include +#include + +static void +write_targetregion(const attrib * a, const void * owner, struct storage * store) +{ + write_region_reference((region*)a->data.v, store); +} + +static int +read_targetregion(attrib * a, void * owner, struct storage * store) +{ + int result = read_reference(&a->data.v, store, read_region_reference, RESOLVE_REGION(store->version)); + if (result==0 && !a->data.v) return AT_READ_FAIL; + return AT_READ_OK; +} + +attrib_type at_targetregion = { + "targetregion", + NULL, + NULL, + NULL, + write_targetregion, + read_targetregion, + ATF_UNIQUE +}; + +attrib * +make_targetregion(struct region * r) +{ + attrib * a = a_new(&at_targetregion); + a->data.v = r; + return a; +} diff --git a/src/attributes/targetregion.h b/src/attributes/targetregion.h index 2eff0ec54..d35aeba06 100644 --- a/src/attributes/targetregion.h +++ b/src/attributes/targetregion.h @@ -1,34 +1,34 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_TARGETREGION -#define H_ATTRIBUTE_TARGETREGION -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_targetregion; - -struct region; -extern struct attrib * make_targetregion(struct region *); - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_TARGETREGION +#define H_ATTRIBUTE_TARGETREGION +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_targetregion; + +struct region; +extern struct attrib * make_targetregion(struct region *); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/attributes/viewrange.c b/src/attributes/viewrange.c index 059ae8d3c..e44f2ca00 100644 --- a/src/attributes/viewrange.c +++ b/src/attributes/viewrange.c @@ -1,77 +1,77 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "viewrange.h" - -/* util includes */ -#include -#include -#include - -/* libc includes */ -#include - -static void -a_writefunction(const struct attrib * a, const void * owner, struct storage * store) -{ - const char * str = get_functionname((pf_generic)a->data.f); - store->w_tok(store, str); -} - -static int -a_readfunction(struct attrib *a, void * owner, struct storage * store) -/* return 1 on success, 0 if attrib needs removal */ -{ - char buf[64]; - store->r_tok_buf(store, buf, sizeof(buf)); - a->data.f = get_function(buf); - return AT_READ_OK; -} - -attrib_type at_viewrange = { - "viewrange", - NULL, - NULL, - NULL, - a_writefunction, - a_readfunction, -}; - -attrib * -add_viewrange(attrib ** alist, const char *function) -{ - attrib * a = a_find(*alist, &at_viewrange); - if (a==NULL) a = a_add(alist, make_viewrange(function)); - return a; -} - -attrib * -make_viewrange(const char *function) -{ - attrib * a = a_new(&at_viewrange); - a->data.f = get_function(function); - assert(a->data.f); - return a; -} - -void -init_viewrange(void) -{ - at_register(&at_viewrange); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "viewrange.h" + +/* util includes */ +#include +#include +#include + +/* libc includes */ +#include + +static void +a_writefunction(const struct attrib * a, const void * owner, struct storage * store) +{ + const char * str = get_functionname((pf_generic)a->data.f); + store->w_tok(store, str); +} + +static int +a_readfunction(struct attrib *a, void * owner, struct storage * store) +/* return 1 on success, 0 if attrib needs removal */ +{ + char buf[64]; + store->r_tok_buf(store, buf, sizeof(buf)); + a->data.f = get_function(buf); + return AT_READ_OK; +} + +attrib_type at_viewrange = { + "viewrange", + NULL, + NULL, + NULL, + a_writefunction, + a_readfunction, +}; + +attrib * +add_viewrange(attrib ** alist, const char *function) +{ + attrib * a = a_find(*alist, &at_viewrange); + if (a==NULL) a = a_add(alist, make_viewrange(function)); + return a; +} + +attrib * +make_viewrange(const char *function) +{ + attrib * a = a_new(&at_viewrange); + a->data.f = get_function(function); + assert(a->data.f); + return a; +} + +void +init_viewrange(void) +{ + at_register(&at_viewrange); +} diff --git a/src/attributes/viewrange.h b/src/attributes/viewrange.h index c3cb3b6d0..8f8ec1c55 100644 --- a/src/attributes/viewrange.h +++ b/src/attributes/viewrange.h @@ -1,35 +1,35 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_VIEWRANGE -#define H_ATTRIBUTE_VIEWRANGE -#ifdef __cplusplus -extern "C" { -#endif - -extern struct attrib_type at_viewrange; - -extern struct attrib * make_viewrange(const char *function); -extern struct attrib * add_viewrange(struct attrib ** alist, const char *function); -extern void init_viewrange(void); - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ATTRIBUTE_VIEWRANGE +#define H_ATTRIBUTE_VIEWRANGE +#ifdef __cplusplus +extern "C" { +#endif + +extern struct attrib_type at_viewrange; + +extern struct attrib * make_viewrange(const char *function); +extern struct attrib * add_viewrange(struct attrib ** alist, const char *function); +extern void init_viewrange(void); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/bindings/bind_attrib.c b/src/bindings/bind_attrib.c index 503d4ab97..f92bcb99e 100644 --- a/src/bindings/bind_attrib.c +++ b/src/bindings/bind_attrib.c @@ -1,372 +1,372 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2010 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include "bind_attrib.h" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -static void -init_ext(attrib * a) { - lua_State * L = (lua_State *)global.vm_state; - - lua_pushstring(L, "callbacks"); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_istable(L, -1)) { - lua_pushstring(L, "attrib_init"); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, -1)) { - lua_rawgeti(L, LUA_REGISTRYINDEX, a->data.i); - if (lua_pcall(L, 1, 0, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("attrib_init '%d': %s.\n", a->data.i, error)); - } - } - } -} - -static void -free_ext(attrib * a) { - lua_State * L = (lua_State *)global.vm_state; - if (a->data.i>0) { - luaL_unref(L, LUA_REGISTRYINDEX, a->data.i); - } -} - -static int -age_ext(attrib * a) { - return AT_AGE_KEEP; -} - -static void -write_ext_i(lua_State * L, const char * name, bson_buffer * bb) -{ - int type = lua_type(L, -1); - switch (type) { - case LUA_TNUMBER: - { - double value = tolua_tonumber(L, -1, 0); - bson_append_double(bb, name, value); - } - break; - case LUA_TSTRING: - { - const char * value = tolua_tostring(L, -1, 0); - bson_append_string(bb, name, value); - } - break; - case LUA_TTABLE: - { - int n = luaL_getn(L, -1); - if (n) { - bson_buffer * arr = bson_append_start_array(bb, name); - int i; - for (i=0;i!=n;++i) { - char num[12]; - bson_numstr(num, i); - lua_rawgeti(L, -1, i+1); - write_ext_i(L, num, arr); - lua_pop(L, 1); - } - bson_append_finish_object(arr); - } else { - bson_buffer * sub = bson_append_start_object(bb, name); - lua_pushnil(L); /* first key */ - while (lua_next(L, -2) != 0) { - const char * key; - /* uses 'key' (at index -2) and 'value' (at index -1) */ - lua_pushvalue(L, -2); - key = lua_tolstring(L, -1, 0); - lua_pushvalue(L, -2); - if (key) { - write_ext_i(L, key, sub); - } - /* removes 'value'; keeps 'key' for next iteration */ - lua_pop(L, 3); - } - bson_append_finish_object(sub); - } - } - break; - case LUA_TUSERDATA: - { - tolua_Error tolua_err; - if (tolua_isusertype(L, -1, "unit", 0, &tolua_err)) { - unit * u = (unit *)tolua_tousertype(L, -1, 0); - bson_oid_t oid; - oid.ints[0] = TYP_UNIT; - oid.ints[1] = u->no; - bson_append_oid(bb, name, &oid); - } else if (tolua_isusertype(L, -1, "region", 0, &tolua_err)) { - region * r = (region *)tolua_tousertype(L, -1, 0); - bson_oid_t oid; - oid.ints[0] = TYP_REGION; - oid.ints[1] = r->uid; - bson_append_oid(bb, name, &oid); - } else if (tolua_isusertype(L, -1, "ship", 0, &tolua_err)) { - ship * sh = (ship *)tolua_tousertype(L, -1, 0); - bson_oid_t oid; - oid.ints[0] = TYP_SHIP; - oid.ints[1] = sh->no; - bson_append_oid(bb, name, &oid); - } else if (tolua_isusertype(L, -1, "building", 0, &tolua_err)) { - building * b = (building *)tolua_tousertype(L, -1, 0); - bson_oid_t oid; - oid.ints[0] = TYP_BUILDING; - oid.ints[1] = b->no; - bson_append_oid(bb, name, &oid); - } else { - log_error(("unsuported type.\n")); - bson_append_null(bb, name); - } - } - break; - default: - bson_append_null(bb, name); - break; - } -} - -static void -write_ext(const attrib * a, const void * owner, struct storage * store) { - lua_State * L = (lua_State *)global.vm_state; - if (a->data.i>0) { - int handle = a->data.i; - bson_buffer bb; - bson b; - - bson_buffer_init( & bb ); - lua_rawgeti(L, LUA_REGISTRYINDEX, handle); - write_ext_i(L, "_data", &bb); - bson_from_buffer(&b, &bb); - store->w_int(store, bson_size(&b)); - store->w_bin(store, b.data, bson_size(&b)); - bson_destroy(&b); - } -} - -static int -read_ext_i(lua_State * L, bson_iterator * it, bson_type type) -{ - switch (type) { - case bson_double: - { - lua_pushnumber(L, bson_iterator_double(it)); - } - break; - case bson_string: - { - lua_pushstring(L, bson_iterator_string(it)); - } - break; - case bson_array: - { - bson_iterator sub; - int err; - bson_iterator_subiterator(it, &sub); - lua_newtable(L); - if (bson_iterator_more(&sub)) { - bson_type ctype; - for (ctype = bson_iterator_next(&sub); bson_iterator_more(&sub); ctype = bson_iterator_next(&sub)) { - int i = atoi(bson_iterator_key(&sub)); - err = read_ext_i(L, &sub, ctype); - if (err) { - lua_pop(L, 1); - return err; - } - lua_rawseti(L, -2, i+1); - } - } - } - break; - case bson_object: - { - bson_iterator sub; - int err; - bson_iterator_subiterator(it, &sub); - lua_newtable(L); - if (bson_iterator_more(&sub)) { - bson_type ctype; - for (ctype = bson_iterator_next(&sub); bson_iterator_more(&sub); ctype = bson_iterator_next(&sub)) { - lua_pushstring(L, bson_iterator_key(&sub)); - err = read_ext_i(L, &sub, ctype); - if (err) { - lua_pop(L, 1); - return err; - } - lua_rawset(L, -3); - } - } - } - break; - case bson_oid: - { - bson_oid_t * oid = bson_iterator_oid(it); - if (oid->ints[0]==TYP_UNIT) { - unit * u = findunit(oid->ints[1]); - if (u) tolua_pushusertype(L, u, "unit"); - else lua_pushnil(L); - } else if (oid->ints[0]==TYP_REGION) { - region * r = findregionbyid(oid->ints[1]); - if (r) tolua_pushusertype(L, r, "region"); - else lua_pushnil(L); - } else if (oid->ints[0]==TYP_SHIP) { - ship * sh = findship(oid->ints[1]); - if (sh) tolua_pushusertype(L, sh, "ship"); - else lua_pushnil(L); - } else if (oid->ints[0]==TYP_BUILDING) { - building * b = findbuilding(oid->ints[1]); - if (b) tolua_pushusertype(L, b, "building"); - else lua_pushnil(L); - } - else { - log_error(("unknown oid %d %d %d\n", oid->ints[0], oid->ints[3], oid->ints[2])); - lua_pushnil(L); - } - } - break; - case bson_null: - lua_pushnil(L); - break; - case bson_eoo: - return EFAULT; - default: - return EINVAL; - } - return 0; -} - -static int -resolve_bson(variant data, void * address) -{ - lua_State * L = (lua_State *)global.vm_state; - bson b; - int err; - bson_iterator it; - attrib * a = (attrib*)address; - char * buffer = data.v; - - bson_init(&b, buffer, 1); - bson_iterator_init(&it, b.data); - err = read_ext_i(L, &it, bson_iterator_next(&it)); - a->data.i = luaL_ref(L, LUA_REGISTRYINDEX); - bson_destroy(&b); - return err?AT_READ_FAIL:AT_READ_OK; -} - -static int -read_ext(attrib * a, void * owner, struct storage * store) { - variant data; - int len = store->r_int(store); - data.v = bson_malloc(len); - store->r_bin(store, data.v, (size_t)len); - a->data.v = 0; - ur_add(data, a, resolve_bson); - return AT_READ_OK; -}; - -attrib_type at_lua_ext = { - "lua", init_ext, free_ext, age_ext, write_ext, read_ext -}; - -static int -tolua_attrib_create(lua_State* L) -{ - attrib ** ap = NULL; - tolua_Error tolua_err; - - if (tolua_isusertype(L, 1, TOLUA_CAST "unit", 0, &tolua_err)) { - unit * u = (unit *)tolua_tousertype(L, 1, 0); - ap = &u->attribs; - } - if (ap) { - attrib * a = a_new(&at_lua_ext); - int handle; - - lua_pushvalue(L, 2); - handle = luaL_ref(L, LUA_REGISTRYINDEX); - a->data.i = handle; - - a_add(ap, a); - tolua_pushusertype(L, (void*)a, TOLUA_CAST "attrib"); - return 1; - } - return 0; -} - -int -tolua_attrib_data(lua_State * L) -{ - attrib * a = (attrib *)tolua_tousertype(L, 1, 0); - if (a && a->data.i) { - lua_rawgeti(L, LUA_REGISTRYINDEX, a->data.i); - return 1; - } - return 0; -} - -attrib * -tolua_get_lua_ext(struct attrib * alist) -{ - while (alist && alist->type!=&at_lua_ext) alist = alist->next; - return alist; -} - -int -tolua_attriblist_next(lua_State *L) -{ - attrib** attrib_ptr = (attrib **)lua_touserdata(L, lua_upvalueindex(1)); - attrib * a = *attrib_ptr; - if (a != NULL) { - tolua_pushusertype(L, (void*)a, TOLUA_CAST "attrib"); - *attrib_ptr = tolua_get_lua_ext(a->next); - return 1; - } - else return 0; /* no more values to return */ -} - - -void -tolua_attrib_open(lua_State* L) -{ - at_register(&at_lua_ext); - - tolua_usertype(L, TOLUA_CAST "attrib"); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_cclass(L, TOLUA_CAST "attrib", TOLUA_CAST "attrib", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "attrib"); - { - tolua_function(L, TOLUA_CAST "create", &tolua_attrib_create); - tolua_variable(L, TOLUA_CAST "data", &tolua_attrib_data, NULL); - } - tolua_endmodule(L); - } - tolua_endmodule(L); -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2010 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bind_attrib.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +static void +init_ext(attrib * a) { + lua_State * L = (lua_State *)global.vm_state; + + lua_pushstring(L, "callbacks"); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_istable(L, -1)) { + lua_pushstring(L, "attrib_init"); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, -1)) { + lua_rawgeti(L, LUA_REGISTRYINDEX, a->data.i); + if (lua_pcall(L, 1, 0, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("attrib_init '%d': %s.\n", a->data.i, error)); + } + } + } +} + +static void +free_ext(attrib * a) { + lua_State * L = (lua_State *)global.vm_state; + if (a->data.i>0) { + luaL_unref(L, LUA_REGISTRYINDEX, a->data.i); + } +} + +static int +age_ext(attrib * a) { + return AT_AGE_KEEP; +} + +static void +write_ext_i(lua_State * L, const char * name, bson_buffer * bb) +{ + int type = lua_type(L, -1); + switch (type) { + case LUA_TNUMBER: + { + double value = tolua_tonumber(L, -1, 0); + bson_append_double(bb, name, value); + } + break; + case LUA_TSTRING: + { + const char * value = tolua_tostring(L, -1, 0); + bson_append_string(bb, name, value); + } + break; + case LUA_TTABLE: + { + int n = luaL_getn(L, -1); + if (n) { + bson_buffer * arr = bson_append_start_array(bb, name); + int i; + for (i=0;i!=n;++i) { + char num[12]; + bson_numstr(num, i); + lua_rawgeti(L, -1, i+1); + write_ext_i(L, num, arr); + lua_pop(L, 1); + } + bson_append_finish_object(arr); + } else { + bson_buffer * sub = bson_append_start_object(bb, name); + lua_pushnil(L); /* first key */ + while (lua_next(L, -2) != 0) { + const char * key; + /* uses 'key' (at index -2) and 'value' (at index -1) */ + lua_pushvalue(L, -2); + key = lua_tolstring(L, -1, 0); + lua_pushvalue(L, -2); + if (key) { + write_ext_i(L, key, sub); + } + /* removes 'value'; keeps 'key' for next iteration */ + lua_pop(L, 3); + } + bson_append_finish_object(sub); + } + } + break; + case LUA_TUSERDATA: + { + tolua_Error tolua_err; + if (tolua_isusertype(L, -1, "unit", 0, &tolua_err)) { + unit * u = (unit *)tolua_tousertype(L, -1, 0); + bson_oid_t oid; + oid.ints[0] = TYP_UNIT; + oid.ints[1] = u->no; + bson_append_oid(bb, name, &oid); + } else if (tolua_isusertype(L, -1, "region", 0, &tolua_err)) { + region * r = (region *)tolua_tousertype(L, -1, 0); + bson_oid_t oid; + oid.ints[0] = TYP_REGION; + oid.ints[1] = r->uid; + bson_append_oid(bb, name, &oid); + } else if (tolua_isusertype(L, -1, "ship", 0, &tolua_err)) { + ship * sh = (ship *)tolua_tousertype(L, -1, 0); + bson_oid_t oid; + oid.ints[0] = TYP_SHIP; + oid.ints[1] = sh->no; + bson_append_oid(bb, name, &oid); + } else if (tolua_isusertype(L, -1, "building", 0, &tolua_err)) { + building * b = (building *)tolua_tousertype(L, -1, 0); + bson_oid_t oid; + oid.ints[0] = TYP_BUILDING; + oid.ints[1] = b->no; + bson_append_oid(bb, name, &oid); + } else { + log_error(("unsuported type.\n")); + bson_append_null(bb, name); + } + } + break; + default: + bson_append_null(bb, name); + break; + } +} + +static void +write_ext(const attrib * a, const void * owner, struct storage * store) { + lua_State * L = (lua_State *)global.vm_state; + if (a->data.i>0) { + int handle = a->data.i; + bson_buffer bb; + bson b; + + bson_buffer_init( & bb ); + lua_rawgeti(L, LUA_REGISTRYINDEX, handle); + write_ext_i(L, "_data", &bb); + bson_from_buffer(&b, &bb); + store->w_int(store, bson_size(&b)); + store->w_bin(store, b.data, bson_size(&b)); + bson_destroy(&b); + } +} + +static int +read_ext_i(lua_State * L, bson_iterator * it, bson_type type) +{ + switch (type) { + case bson_double: + { + lua_pushnumber(L, bson_iterator_double(it)); + } + break; + case bson_string: + { + lua_pushstring(L, bson_iterator_string(it)); + } + break; + case bson_array: + { + bson_iterator sub; + int err; + bson_iterator_subiterator(it, &sub); + lua_newtable(L); + if (bson_iterator_more(&sub)) { + bson_type ctype; + for (ctype = bson_iterator_next(&sub); bson_iterator_more(&sub); ctype = bson_iterator_next(&sub)) { + int i = atoi(bson_iterator_key(&sub)); + err = read_ext_i(L, &sub, ctype); + if (err) { + lua_pop(L, 1); + return err; + } + lua_rawseti(L, -2, i+1); + } + } + } + break; + case bson_object: + { + bson_iterator sub; + int err; + bson_iterator_subiterator(it, &sub); + lua_newtable(L); + if (bson_iterator_more(&sub)) { + bson_type ctype; + for (ctype = bson_iterator_next(&sub); bson_iterator_more(&sub); ctype = bson_iterator_next(&sub)) { + lua_pushstring(L, bson_iterator_key(&sub)); + err = read_ext_i(L, &sub, ctype); + if (err) { + lua_pop(L, 1); + return err; + } + lua_rawset(L, -3); + } + } + } + break; + case bson_oid: + { + bson_oid_t * oid = bson_iterator_oid(it); + if (oid->ints[0]==TYP_UNIT) { + unit * u = findunit(oid->ints[1]); + if (u) tolua_pushusertype(L, u, "unit"); + else lua_pushnil(L); + } else if (oid->ints[0]==TYP_REGION) { + region * r = findregionbyid(oid->ints[1]); + if (r) tolua_pushusertype(L, r, "region"); + else lua_pushnil(L); + } else if (oid->ints[0]==TYP_SHIP) { + ship * sh = findship(oid->ints[1]); + if (sh) tolua_pushusertype(L, sh, "ship"); + else lua_pushnil(L); + } else if (oid->ints[0]==TYP_BUILDING) { + building * b = findbuilding(oid->ints[1]); + if (b) tolua_pushusertype(L, b, "building"); + else lua_pushnil(L); + } + else { + log_error(("unknown oid %d %d %d\n", oid->ints[0], oid->ints[3], oid->ints[2])); + lua_pushnil(L); + } + } + break; + case bson_null: + lua_pushnil(L); + break; + case bson_eoo: + return EFAULT; + default: + return EINVAL; + } + return 0; +} + +static int +resolve_bson(variant data, void * address) +{ + lua_State * L = (lua_State *)global.vm_state; + bson b; + int err; + bson_iterator it; + attrib * a = (attrib*)address; + char * buffer = data.v; + + bson_init(&b, buffer, 1); + bson_iterator_init(&it, b.data); + err = read_ext_i(L, &it, bson_iterator_next(&it)); + a->data.i = luaL_ref(L, LUA_REGISTRYINDEX); + bson_destroy(&b); + return err?AT_READ_FAIL:AT_READ_OK; +} + +static int +read_ext(attrib * a, void * owner, struct storage * store) { + variant data; + int len = store->r_int(store); + data.v = bson_malloc(len); + store->r_bin(store, data.v, (size_t)len); + a->data.v = 0; + ur_add(data, a, resolve_bson); + return AT_READ_OK; +}; + +attrib_type at_lua_ext = { + "lua", init_ext, free_ext, age_ext, write_ext, read_ext +}; + +static int +tolua_attrib_create(lua_State* L) +{ + attrib ** ap = NULL; + tolua_Error tolua_err; + + if (tolua_isusertype(L, 1, TOLUA_CAST "unit", 0, &tolua_err)) { + unit * u = (unit *)tolua_tousertype(L, 1, 0); + ap = &u->attribs; + } + if (ap) { + attrib * a = a_new(&at_lua_ext); + int handle; + + lua_pushvalue(L, 2); + handle = luaL_ref(L, LUA_REGISTRYINDEX); + a->data.i = handle; + + a_add(ap, a); + tolua_pushusertype(L, (void*)a, TOLUA_CAST "attrib"); + return 1; + } + return 0; +} + +int +tolua_attrib_data(lua_State * L) +{ + attrib * a = (attrib *)tolua_tousertype(L, 1, 0); + if (a && a->data.i) { + lua_rawgeti(L, LUA_REGISTRYINDEX, a->data.i); + return 1; + } + return 0; +} + +attrib * +tolua_get_lua_ext(struct attrib * alist) +{ + while (alist && alist->type!=&at_lua_ext) alist = alist->next; + return alist; +} + +int +tolua_attriblist_next(lua_State *L) +{ + attrib** attrib_ptr = (attrib **)lua_touserdata(L, lua_upvalueindex(1)); + attrib * a = *attrib_ptr; + if (a != NULL) { + tolua_pushusertype(L, (void*)a, TOLUA_CAST "attrib"); + *attrib_ptr = tolua_get_lua_ext(a->next); + return 1; + } + else return 0; /* no more values to return */ +} + + +void +tolua_attrib_open(lua_State* L) +{ + at_register(&at_lua_ext); + + tolua_usertype(L, TOLUA_CAST "attrib"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, TOLUA_CAST "attrib", TOLUA_CAST "attrib", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "attrib"); + { + tolua_function(L, TOLUA_CAST "create", &tolua_attrib_create); + tolua_variable(L, TOLUA_CAST "data", &tolua_attrib_data, NULL); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_attrib.h b/src/bindings/bind_attrib.h index 758ab62d6..d4ce7bf95 100644 --- a/src/bindings/bind_attrib.h +++ b/src/bindings/bind_attrib.h @@ -1,24 +1,24 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2010 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct attrib; - void tolua_attrib_open(struct lua_State *L); - struct attrib * tolua_get_lua_ext(struct attrib * alist); - int tolua_attriblist_next(struct lua_State *L); - -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2010 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct attrib; + void tolua_attrib_open(struct lua_State *L); + struct attrib * tolua_get_lua_ext(struct attrib * alist); + int tolua_attriblist_next(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_building.c b/src/bindings/bind_building.c index 8fadae4c1..e5c9efde3 100644 --- a/src/bindings/bind_building.c +++ b/src/bindings/bind_building.c @@ -1,258 +1,255 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include "bind_building.h" -#include "bind_unit.h" - -#include -#include -#include -#include - -#include - -#include -#include - -int tolua_buildinglist_next(lua_State *L) -{ - building** building_ptr = (building **)lua_touserdata(L, lua_upvalueindex(1)); - building * u = *building_ptr; - if (u != NULL) { - tolua_pushusertype(L, (void*)u, TOLUA_CAST "building"); - *building_ptr = u->next; - return 1; - } - else return 0; /* no more values to return */ -} - - -static int -tolua_building_addaction(lua_State* L) -{ - building* self = (building*)tolua_tousertype(L, 1, 0); - const char * fname = tolua_tostring(L, 2, 0); - const char * param = tolua_tostring(L, 3, 0); - - building_addaction(self, fname, param); - - return 0; -} - -static int -tolua_building_get_objects(lua_State* L) -{ - building * self = (building *)tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); - return 1; -} - -static int tolua_building_get_region(lua_State* L) -{ - building* self = (building*) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, building_getregion(self), TOLUA_CAST "region"); - return 1; -} - -static int tolua_building_set_region(lua_State* L) -{ - building* self = (building*)tolua_tousertype(L, 1, 0); - building_setregion(self, (region*)tolua_tousertype(L, 2, 0)); - return 0; -} - - -static int tolua_building_get_info(lua_State* L) -{ - building* self = (building*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->display); - return 1; -} - -static int tolua_building_set_info(lua_State* L) -{ - building* self = (building*)tolua_tousertype(L, 1, 0); - const char * info = tolua_tostring(L, 2, 0); - free(self->display); - if (info) self->display = strdup(info); - else self->display = NULL; - return 0; -} - -static int tolua_building_get_name(lua_State* L) -{ - building* self = (building*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, building_getname(self)); - return 1; -} - -static int tolua_building_set_name(lua_State* L) -{ - building* self = (building*)tolua_tousertype(L, 1, 0); - building_setname(self, tolua_tostring(L, 2, 0)); - return 0; -} - -static int tolua_building_get_size(lua_State* L) -{ - building* self = (building*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, self->size); - return 1; -} - -static int tolua_building_set_size(lua_State* L) -{ - building* self = (building*)tolua_tousertype(L, 1, 0); - self->size = (int)tolua_tonumber(L, 2, 0); - return 0; -} - -static int -tolua_building_get_units(lua_State* L) -{ - building * self = (building *)tolua_tousertype(L, 1, 0); - unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); - unit * u = self->region->units; - - while (u && u->building!=self) u = u->next; - luaL_getmetatable(L, "unit"); - lua_setmetatable(L, -2); - - *unit_ptr = u; - - lua_pushcclosure(L, tolua_unitlist_nextb, 1); - return 1; -} - -static int -tolua_building_get_id(lua_State* L) -{ - building * self = (building *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->no); - return 1; -} - -static int -tolua_building_get_type(lua_State* L) -{ - building * self = (building *)tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->type->_name); - return 1; -} - -static int -tolua_building_get_typename(lua_State* L) -{ - building * b = (building *)tolua_tousertype(L, 1, 0); - if (b) { - int size = (int)tolua_tonumber(L, 2, b->size); - tolua_pushstring(L, buildingtype(b->type, b, size)); - return 1; - } - return 0; -} - -static int -tolua_building_get_owner(lua_State* L) -{ - building* b = (building*) tolua_tousertype(L, 1, 0); - unit * u = b?building_owner(b):NULL; - tolua_pushusertype(L, u, TOLUA_CAST "unit"); - return 1; -} - -static int -tolua_building_set_owner(lua_State* L) -{ - building* b = (building*) tolua_tousertype(L, 1, 0); - unit * u = (unit *)tolua_tousertype(L, 2, 0); - unit * o = b?building_owner(b):NULL; - if (o && o!=u) { - freset(o, UFL_OWNER); - } - if (u) { - fset(u, UFL_OWNER); - } - return 0; -} - -static int -tolua_building_create(lua_State* L) -{ - region * r = (region *)tolua_tousertype(L, 1, 0); - const char * bname = tolua_tostring(L, 2, 0); - if (bname) { - const building_type * btype = bt_find(bname); - if (btype) { - building * b = new_building(btype, r, default_locale); - tolua_pushusertype(L, (void*)b, TOLUA_CAST "building"); - return 1; - } - } - return 0; -} - -static int -tolua_building_tostring(lua_State *L) -{ - building * self = (building *)tolua_tousertype(L, 1, 0); - lua_pushstring(L, buildingname(self)); - return 1; -} - -static int -tolua_building_destroy(lua_State *L) -{ - building * self = (building *)tolua_tousertype(L, 1, 0); - remove_building(&self->region->buildings, self); - return 0; -} - -void -tolua_building_open(lua_State* L) -{ - /* register user types */ - tolua_usertype(L, TOLUA_CAST "building"); - tolua_usertype(L, TOLUA_CAST "building_list"); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_cclass(L, TOLUA_CAST "building", TOLUA_CAST "building", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "building"); - { - tolua_function(L, TOLUA_CAST "create", tolua_building_create); - tolua_function(L, TOLUA_CAST "destroy", tolua_building_destroy); - tolua_function(L, TOLUA_CAST "__tostring", tolua_building_tostring); - - tolua_variable(L, TOLUA_CAST "id", tolua_building_get_id, NULL); - tolua_variable(L, TOLUA_CAST "owner", tolua_building_get_owner, tolua_building_set_owner); - tolua_variable(L, TOLUA_CAST "type", tolua_building_get_type, NULL); - tolua_variable(L, TOLUA_CAST "name", tolua_building_get_name, tolua_building_set_name); - tolua_variable(L, TOLUA_CAST "info", tolua_building_get_info, tolua_building_set_info); - tolua_variable(L, TOLUA_CAST "units", tolua_building_get_units, NULL); - tolua_variable(L, TOLUA_CAST "region", tolua_building_get_region, tolua_building_set_region); - tolua_variable(L, TOLUA_CAST "size", tolua_building_get_size, tolua_building_set_size); - tolua_function(L, TOLUA_CAST "add_action", tolua_building_addaction); - tolua_function(L, TOLUA_CAST "get_typename", tolua_building_get_typename); -#ifdef TODO - .property("type", &building_gettype) - .def_readwrite("size", &building::size) -#endif - tolua_variable(L, TOLUA_CAST "objects", tolua_building_get_objects, 0); - - } - tolua_endmodule(L); - } - tolua_endmodule(L); -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bind_building.h" +#include "bind_unit.h" + +#include +#include +#include + +#include +#include + +int tolua_buildinglist_next(lua_State *L) +{ + building** building_ptr = (building **)lua_touserdata(L, lua_upvalueindex(1)); + building * u = *building_ptr; + if (u != NULL) { + tolua_pushusertype(L, (void*)u, TOLUA_CAST "building"); + *building_ptr = u->next; + return 1; + } + else return 0; /* no more values to return */ +} + + +static int +tolua_building_addaction(lua_State* L) +{ + building* self = (building*)tolua_tousertype(L, 1, 0); + const char * fname = tolua_tostring(L, 2, 0); + const char * param = tolua_tostring(L, 3, 0); + + building_addaction(self, fname, param); + + return 0; +} + +static int +tolua_building_get_objects(lua_State* L) +{ + building * self = (building *)tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); + return 1; +} + +static int tolua_building_get_region(lua_State* L) +{ + building* self = (building*) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, building_getregion(self), TOLUA_CAST "region"); + return 1; +} + +static int tolua_building_set_region(lua_State* L) +{ + building* self = (building*)tolua_tousertype(L, 1, 0); + building_setregion(self, (region*)tolua_tousertype(L, 2, 0)); + return 0; +} + + +static int tolua_building_get_info(lua_State* L) +{ + building* self = (building*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->display); + return 1; +} + +static int tolua_building_set_info(lua_State* L) +{ + building* self = (building*)tolua_tousertype(L, 1, 0); + const char * info = tolua_tostring(L, 2, 0); + free(self->display); + if (info) self->display = strdup(info); + else self->display = NULL; + return 0; +} + +static int tolua_building_get_name(lua_State* L) +{ + building* self = (building*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, building_getname(self)); + return 1; +} + +static int tolua_building_set_name(lua_State* L) +{ + building* self = (building*)tolua_tousertype(L, 1, 0); + building_setname(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int tolua_building_get_size(lua_State* L) +{ + building* self = (building*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, self->size); + return 1; +} + +static int tolua_building_set_size(lua_State* L) +{ + building* self = (building*)tolua_tousertype(L, 1, 0); + self->size = (int)tolua_tonumber(L, 2, 0); + return 0; +} + +static int +tolua_building_get_units(lua_State* L) +{ + building * self = (building *)tolua_tousertype(L, 1, 0); + unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); + unit * u = self->region->units; + + while (u && u->building!=self) u = u->next; + luaL_getmetatable(L, "unit"); + lua_setmetatable(L, -2); + + *unit_ptr = u; + + lua_pushcclosure(L, tolua_unitlist_nextb, 1); + return 1; +} + +static int +tolua_building_get_id(lua_State* L) +{ + building * self = (building *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->no); + return 1; +} + +static int +tolua_building_get_type(lua_State* L) +{ + building * self = (building *)tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->type->_name); + return 1; +} + +static int +tolua_building_get_typename(lua_State* L) +{ + building * b = (building *)tolua_tousertype(L, 1, 0); + if (b) { + int size = (int)tolua_tonumber(L, 2, b->size); + tolua_pushstring(L, buildingtype(b->type, b, size)); + return 1; + } + return 0; +} + +static int +tolua_building_get_owner(lua_State* L) +{ + building* b = (building*) tolua_tousertype(L, 1, 0); + unit * u = b?building_owner(b):NULL; + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + return 1; +} + +static int +tolua_building_set_owner(lua_State* L) +{ + building* b = (building*) tolua_tousertype(L, 1, 0); + unit * u = (unit *)tolua_tousertype(L, 2, 0); + unit * o = b?building_owner(b):NULL; + if (o && o!=u) { + freset(o, UFL_OWNER); + } + if (u) { + fset(u, UFL_OWNER); + } + return 0; +} + +static int +tolua_building_create(lua_State* L) +{ + region * r = (region *)tolua_tousertype(L, 1, 0); + const char * bname = tolua_tostring(L, 2, 0); + if (bname) { + const building_type * btype = bt_find(bname); + if (btype) { + building * b = new_building(btype, r, default_locale); + tolua_pushusertype(L, (void*)b, TOLUA_CAST "building"); + return 1; + } + } + return 0; +} + +static int +tolua_building_tostring(lua_State *L) +{ + building * self = (building *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, buildingname(self)); + return 1; +} + +static int +tolua_building_destroy(lua_State *L) +{ + building * self = (building *)tolua_tousertype(L, 1, 0); + remove_building(&self->region->buildings, self); + return 0; +} + +void +tolua_building_open(lua_State* L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "building"); + tolua_usertype(L, TOLUA_CAST "building_list"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, TOLUA_CAST "building", TOLUA_CAST "building", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "building"); + { + tolua_function(L, TOLUA_CAST "create", tolua_building_create); + tolua_function(L, TOLUA_CAST "destroy", tolua_building_destroy); + tolua_function(L, TOLUA_CAST "__tostring", tolua_building_tostring); + + tolua_variable(L, TOLUA_CAST "id", tolua_building_get_id, NULL); + tolua_variable(L, TOLUA_CAST "owner", tolua_building_get_owner, tolua_building_set_owner); + tolua_variable(L, TOLUA_CAST "type", tolua_building_get_type, NULL); + tolua_variable(L, TOLUA_CAST "name", tolua_building_get_name, tolua_building_set_name); + tolua_variable(L, TOLUA_CAST "info", tolua_building_get_info, tolua_building_set_info); + tolua_variable(L, TOLUA_CAST "units", tolua_building_get_units, NULL); + tolua_variable(L, TOLUA_CAST "region", tolua_building_get_region, tolua_building_set_region); + tolua_variable(L, TOLUA_CAST "size", tolua_building_get_size, tolua_building_set_size); + tolua_function(L, TOLUA_CAST "add_action", tolua_building_addaction); + tolua_function(L, TOLUA_CAST "get_typename", tolua_building_get_typename); +#ifdef TODO + .property("type", &building_gettype) + .def_readwrite("size", &building::size) +#endif + tolua_variable(L, TOLUA_CAST "objects", tolua_building_get_objects, 0); + + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_building.h b/src/bindings/bind_building.h index 3f87c4952..a6168b66c 100644 --- a/src/bindings/bind_building.h +++ b/src/bindings/bind_building.h @@ -1,23 +1,23 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - int tolua_buildinglist_next(struct lua_State *L); - void tolua_building_open(struct lua_State *L); - -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + int tolua_buildinglist_next(struct lua_State *L); + void tolua_building_open(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_faction.c b/src/bindings/bind_faction.c index 0931298b1..44caf3618 100644 --- a/src/bindings/bind_faction.c +++ b/src/bindings/bind_faction.c @@ -1,561 +1,561 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include "bind_faction.h" -#include "bind_unit.h" -#include "bindings.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - - -int tolua_factionlist_next(lua_State *L) -{ - faction** faction_ptr = (faction **)lua_touserdata(L, lua_upvalueindex(1)); - faction * f = *faction_ptr; - if (f != NULL) { - tolua_pushusertype(L, (void*)f, TOLUA_CAST "faction"); - *faction_ptr = f->next; - return 1; - } - else return 0; /* no more values to return */ -} - -int tolua_factionlist_iter(lua_State *L) -{ - faction_list** faction_ptr = (faction_list **)lua_touserdata(L, lua_upvalueindex(1)); - faction_list* flist = *faction_ptr; - if (flist != NULL) { - tolua_pushusertype(L, (void*)flist->data, TOLUA_CAST "faction"); - *faction_ptr = flist->next; - return 1; - } - else return 0; /* no more values to return */ -} - -static int tolua_faction_get_units(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); - - luaL_getmetatable(L, TOLUA_CAST "unit"); - lua_setmetatable(L, -2); - - *unit_ptr = self->units; - - lua_pushcclosure(L, tolua_unitlist_nextf, 1); - return 1; -} - -int tolua_faction_add_item(lua_State *L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - const char * iname = tolua_tostring(L, 2, 0); - int number = (int)tolua_tonumber(L, 3, 0); - int result = -1; - - if (iname!=NULL) { - const item_type * itype = it_find(iname); - if (itype!=NULL) { - item * i = i_change(&self->items, itype, number); - result = i?i->number:0; - } // if (itype!=NULL) - } - lua_pushnumber(L, result); - return 1; -} - -static int -tolua_faction_get_maxheroes(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)maxheroes(self)); - return 1; -} - -static int -tolua_faction_get_heroes(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)countheroes(self)); - return 1; -} - -static int -tolua_faction_get_score(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->score); - return 1; -} - -static int -tolua_faction_get_id(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->no); - return 1; -} - -static int -tolua_faction_set_id(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - int id = (int)tolua_tonumber(L, 2, 0); - if (findfaction(id)==NULL) { - renumber_faction(self, id); - lua_pushboolean(L, 1); - } else { - lua_pushboolean(L, 0); - } - return 1; -} - -static int -tolua_faction_get_age(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->age); - return 1; -} - -static int -tolua_faction_set_age(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - int age = (int)tolua_tonumber(L, 2, 0); - self->age = age; - return 0; -} - -static int -tolua_faction_get_flags(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->flags); - return 1; -} - -static int -tolua_faction_get_options(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->options); - return 1; -} - -static int -tolua_faction_set_options(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - int options = (int)tolua_tonumber(L, 2, self->options); - self->options = options; - return 1; -} - -static int -tolua_faction_get_lastturn(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->lastorders); - return 1; -} - -static int -tolua_faction_set_lastturn(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - if (self) { - self->lastorders = (int)tolua_tonumber(L, 2, self->lastorders); - } - return 0; -} - -static int -tolua_faction_renumber(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - int no = (int)tolua_tonumber(L, 2, 0); - - renumber_faction(self, no); - return 0; -} - -static int -tolua_faction_get_objects(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); - return 1; -} - -static int -tolua_faction_get_policy(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - faction * other = (faction *)tolua_tousertype(L, 2, 0); - const char * policy = tolua_tostring(L, 3, 0); - - int result = 0, mode; - for (mode=0;helpmodes[mode].name!=NULL;++mode) { - if (strcmp(policy, helpmodes[mode].name)==0) { - result = get_alliance(self, other) & mode; - break; - } - } - - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - - -static int -tolua_faction_set_policy(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - faction * other = (faction *)tolua_tousertype(L, 2, 0); - const char * policy = tolua_tostring(L, 3, 0); - int value = tolua_toboolean(L, 4, 0); - - int mode; - for (mode=0;helpmodes[mode].name!=NULL;++mode) { - if (strcmp(policy, helpmodes[mode].name)==0) { - if (value) { - set_alliance(self, other, get_alliance(self, other) | helpmodes[mode].status); - } else { - set_alliance(self, other, get_alliance(self, other) & ~helpmodes[mode].status); - } - break; - } - } - - return 0; -} - -static int -tolua_faction_normalize(lua_State* L) -{ - faction * f = (faction *)tolua_tousertype(L, 1, 0); - region * r = (region * )tolua_tousertype(L, 2, 0); - if (r) { - plane * pl = rplane(r); - int nx = r->x, ny = r->y; - pnormalize(&nx, &ny, pl); - adjust_coordinates(f, &nx, &ny, pl, r); - tolua_pushnumber(L, (lua_Number)nx); - tolua_pushnumber(L, (lua_Number)ny); - return 2; - } - return 0; -} - -static int -tolua_faction_set_origin(lua_State* L) -{ - faction * f = (faction *)tolua_tousertype(L, 1, 0); - region * r = (region *)tolua_tousertype(L, 2, 0); - plane * pl = rplane(r); - int id = pl?pl->id:0; - - set_ursprung(f, id, r->x - plane_center_x(pl), r->y - plane_center_y(pl)); - return 0; -} - -static int -tolua_faction_get_origin(lua_State* L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - - ursprung * origin = self->ursprung; - int x, y; - while (origin!=NULL && origin->id!=0) { - origin = origin->next; - } - if (origin) { - x = origin->x; - y = origin->y; - } else { - x = 0; - y = 0; - } - - tolua_pushnumber(L, (lua_Number)x); - tolua_pushnumber(L, (lua_Number)y); - return 2; -} - -static int -tolua_faction_destroy(lua_State* L) -{ - faction* f = (faction*) tolua_tousertype(L, 1, 0); - destroyfaction(f); - return 0; -} - -static int -tolua_faction_create(lua_State* L) -{ - const char * email = tolua_tostring(L, 1, 0); - const char * racename = tolua_tostring(L, 2, 0); - const char * lang = tolua_tostring(L, 3, 0); - struct locale * loc = find_locale(lang); - faction * f = NULL; - const struct race * frace = rc_find(racename); - if (frace==NULL) frace = findrace(racename, find_locale("de")); - if (frace==NULL) frace = findrace(racename, find_locale("en")); - if (frace!=NULL) { - f = addfaction(email, NULL, frace, loc, 0); - } - if (!f) { - log_error(("faction.create(%s, %s, %s)\n", email, racename, lang)); - } - tolua_pushusertype(L, f, TOLUA_CAST "faction"); - return 1; -} - -static int tolua_faction_get_password(lua_State* L) -{ - faction* self = (faction*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, faction_getpassword(self)); - return 1; -} - -static int tolua_faction_set_password(lua_State* L) -{ - faction* self = (faction*)tolua_tousertype(L, 1, 0); - faction_setpassword(self, tolua_tostring(L, 2, 0)); - return 0; -} - -static int tolua_faction_get_email(lua_State* L) -{ - faction* self = (faction*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, faction_getemail(self)); - return 1; -} - -static int tolua_faction_set_email(lua_State* L) -{ - faction* self = (faction*)tolua_tousertype(L, 1, 0); - faction_setemail(self, tolua_tostring(L, 2, 0)); - return 0; -} - -static int tolua_faction_get_locale(lua_State* L) -{ - faction* self = (faction*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, locale_name(self->locale)); - return 1; -} - -static int tolua_faction_set_locale(lua_State* L) -{ - faction* self = (faction*)tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - self->locale = find_locale(name); - return 0; -} - -static int tolua_faction_get_race(lua_State* L) -{ - faction* self = (faction*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->race->_name[0]); - return 1; -} - -static int tolua_faction_set_race(lua_State* L) -{ - faction* self = (faction*)tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - race * rc = rc_find(name); - if (rc!=NULL) { - self->race = rc; - } - - return 0; -} - -static int tolua_faction_get_name(lua_State* L) -{ - faction* self = (faction*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, faction_getname(self)); - return 1; -} - -static int tolua_faction_set_name(lua_State* L) -{ - faction* self = (faction*)tolua_tousertype(L, 1, 0); - faction_setname(self, tolua_tostring(L, 2, 0)); - return 0; -} - -static int tolua_faction_get_uid(lua_State* L) -{ - faction* f = (faction*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, f->subscription); - return 1; -} - -static int tolua_faction_set_uid(lua_State* L) -{ - faction* f = (faction*)tolua_tousertype(L, 1, 0); - f->subscription = (int)tolua_tonumber(L, 2, 0); - return 0; -} - -static int tolua_faction_get_info(lua_State* L) -{ - faction* self = (faction*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, faction_getbanner(self)); - return 1; -} - -static int tolua_faction_set_info(lua_State* L) -{ - faction* self = (faction*)tolua_tousertype(L, 1, 0); - faction_setbanner(self, tolua_tostring(L, 2, 0)); - return 0; -} - -static int tolua_faction_get_alliance(lua_State* L) -{ - faction* self = (faction*) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, f_get_alliance(self), TOLUA_CAST "alliance"); - return 1; -} - -static int tolua_faction_set_alliance(lua_State* L) -{ - faction* self = (faction*)tolua_tousertype(L, 1, 0); - alliance* alli = (alliance*)tolua_tousertype(L, 2, 0); - - setalliance(self, alli); - - return 0; -} - -static int tolua_faction_get_items(lua_State* L) -{ - faction* self = (faction*)tolua_tousertype(L, 1, 0); - item ** item_ptr = (item **)lua_newuserdata(L, sizeof(item *)); - - luaL_getmetatable(L, TOLUA_CAST "item"); - lua_setmetatable(L, -2); - - *item_ptr = self->items; - - lua_pushcclosure(L, tolua_itemlist_next, 1); - - return 1; -} - -static int -tolua_faction_tostring(lua_State *L) -{ - faction * self = (faction *)tolua_tousertype(L, 1, 0); - lua_pushstring(L, factionname(self)); - return 1; -} - -static int tolua_faction_get_spells(lua_State* L) -{ - faction* self = (faction*)tolua_tousertype(L, 1, 0); - spell_list * slist = self->spellbook; - if (slist) { - spell_list ** spell_ptr = (spell_list **)lua_newuserdata(L, sizeof(spell_list *)); - luaL_getmetatable(L, TOLUA_CAST "spell_list"); - lua_setmetatable(L, -2); - - *spell_ptr = slist; - lua_pushcclosure(L, tolua_spelllist_next, 1); - return 1; - } - - lua_pushnil(L); - return 1; -} - -void -tolua_faction_open(lua_State* L) -{ - /* register user types */ - tolua_usertype(L, TOLUA_CAST "faction"); - tolua_usertype(L, TOLUA_CAST "faction_list"); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_cclass(L, TOLUA_CAST "faction", TOLUA_CAST "faction", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "faction"); - { - tolua_function(L, TOLUA_CAST "__tostring", tolua_faction_tostring); - - tolua_variable(L, TOLUA_CAST "id", tolua_faction_get_id, tolua_faction_set_id); - tolua_variable(L, TOLUA_CAST "uid", &tolua_faction_get_uid, &tolua_faction_set_uid); - tolua_variable(L, TOLUA_CAST "name", &tolua_faction_get_name, &tolua_faction_set_name); - tolua_variable(L, TOLUA_CAST "info", &tolua_faction_get_info, &tolua_faction_set_info); - tolua_variable(L, TOLUA_CAST "units", tolua_faction_get_units, NULL); - tolua_variable(L, TOLUA_CAST "heroes", tolua_faction_get_heroes, NULL); - tolua_variable(L, TOLUA_CAST "spells", tolua_faction_get_spells, 0); - tolua_variable(L, TOLUA_CAST "maxheroes", tolua_faction_get_maxheroes, NULL); - tolua_variable(L, TOLUA_CAST "password", tolua_faction_get_password, tolua_faction_set_password); - tolua_variable(L, TOLUA_CAST "email", tolua_faction_get_email, tolua_faction_set_email); - tolua_variable(L, TOLUA_CAST "locale", tolua_faction_get_locale, tolua_faction_set_locale); - tolua_variable(L, TOLUA_CAST "race", tolua_faction_get_race, tolua_faction_set_race); - tolua_variable(L, TOLUA_CAST "alliance", tolua_faction_get_alliance, tolua_faction_set_alliance); - tolua_variable(L, TOLUA_CAST "score", tolua_faction_get_score, NULL); - tolua_variable(L, TOLUA_CAST "age", tolua_faction_get_age, tolua_faction_set_age); - tolua_variable(L, TOLUA_CAST "options", tolua_faction_get_options, tolua_faction_set_options); - tolua_variable(L, TOLUA_CAST "flags", tolua_faction_get_flags, NULL); - tolua_variable(L, TOLUA_CAST "lastturn", tolua_faction_get_lastturn, tolua_faction_set_lastturn); - - tolua_function(L, TOLUA_CAST "set_policy", &tolua_faction_set_policy); - tolua_function(L, TOLUA_CAST "get_policy", &tolua_faction_get_policy); - tolua_function(L, TOLUA_CAST "get_origin", &tolua_faction_get_origin); - tolua_function(L, TOLUA_CAST "set_origin", &tolua_faction_set_origin); - tolua_function(L, TOLUA_CAST "normalize", &tolua_faction_normalize); - - tolua_function(L, TOLUA_CAST "add_item", tolua_faction_add_item); - tolua_variable(L, TOLUA_CAST "items", tolua_faction_get_items, NULL); - - tolua_function(L, TOLUA_CAST "renumber", &tolua_faction_renumber); - tolua_function(L, TOLUA_CAST "create", &tolua_faction_create); - tolua_function(L, TOLUA_CAST "destroy", &tolua_faction_destroy); -#ifdef TODO - def("faction_origin", &faction_getorigin, pure_out_value(_2) + pure_out_value(_3)), - - .def_readwrite("subscription", &faction::subscription) - - .property("x", &faction_getorigin_x, &faction_setorigin_x) - .property("y", &faction_getorigin_y, &faction_setorigin_y) - - .def("add_notice", &faction_addnotice) -#endif - tolua_variable(L, TOLUA_CAST "objects", tolua_faction_get_objects, NULL); - } - tolua_endmodule(L); - } - tolua_endmodule(L); -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bind_faction.h" +#include "bind_unit.h" +#include "bindings.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +int tolua_factionlist_next(lua_State *L) +{ + faction** faction_ptr = (faction **)lua_touserdata(L, lua_upvalueindex(1)); + faction * f = *faction_ptr; + if (f != NULL) { + tolua_pushusertype(L, (void*)f, TOLUA_CAST "faction"); + *faction_ptr = f->next; + return 1; + } + else return 0; /* no more values to return */ +} + +int tolua_factionlist_iter(lua_State *L) +{ + faction_list** faction_ptr = (faction_list **)lua_touserdata(L, lua_upvalueindex(1)); + faction_list* flist = *faction_ptr; + if (flist != NULL) { + tolua_pushusertype(L, (void*)flist->data, TOLUA_CAST "faction"); + *faction_ptr = flist->next; + return 1; + } + else return 0; /* no more values to return */ +} + +static int tolua_faction_get_units(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); + + luaL_getmetatable(L, TOLUA_CAST "unit"); + lua_setmetatable(L, -2); + + *unit_ptr = self->units; + + lua_pushcclosure(L, tolua_unitlist_nextf, 1); + return 1; +} + +int tolua_faction_add_item(lua_State *L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + const char * iname = tolua_tostring(L, 2, 0); + int number = (int)tolua_tonumber(L, 3, 0); + int result = -1; + + if (iname!=NULL) { + const item_type * itype = it_find(iname); + if (itype!=NULL) { + item * i = i_change(&self->items, itype, number); + result = i?i->number:0; + } // if (itype!=NULL) + } + lua_pushnumber(L, result); + return 1; +} + +static int +tolua_faction_get_maxheroes(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)maxheroes(self)); + return 1; +} + +static int +tolua_faction_get_heroes(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)countheroes(self)); + return 1; +} + +static int +tolua_faction_get_score(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->score); + return 1; +} + +static int +tolua_faction_get_id(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->no); + return 1; +} + +static int +tolua_faction_set_id(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + int id = (int)tolua_tonumber(L, 2, 0); + if (findfaction(id)==NULL) { + renumber_faction(self, id); + lua_pushboolean(L, 1); + } else { + lua_pushboolean(L, 0); + } + return 1; +} + +static int +tolua_faction_get_age(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->age); + return 1; +} + +static int +tolua_faction_set_age(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + int age = (int)tolua_tonumber(L, 2, 0); + self->age = age; + return 0; +} + +static int +tolua_faction_get_flags(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->flags); + return 1; +} + +static int +tolua_faction_get_options(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->options); + return 1; +} + +static int +tolua_faction_set_options(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + int options = (int)tolua_tonumber(L, 2, self->options); + self->options = options; + return 1; +} + +static int +tolua_faction_get_lastturn(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->lastorders); + return 1; +} + +static int +tolua_faction_set_lastturn(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + if (self) { + self->lastorders = (int)tolua_tonumber(L, 2, self->lastorders); + } + return 0; +} + +static int +tolua_faction_renumber(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + int no = (int)tolua_tonumber(L, 2, 0); + + renumber_faction(self, no); + return 0; +} + +static int +tolua_faction_get_objects(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); + return 1; +} + +static int +tolua_faction_get_policy(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + faction * other = (faction *)tolua_tousertype(L, 2, 0); + const char * policy = tolua_tostring(L, 3, 0); + + int result = 0, mode; + for (mode=0;helpmodes[mode].name!=NULL;++mode) { + if (strcmp(policy, helpmodes[mode].name)==0) { + result = get_alliance(self, other) & mode; + break; + } + } + + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + + +static int +tolua_faction_set_policy(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + faction * other = (faction *)tolua_tousertype(L, 2, 0); + const char * policy = tolua_tostring(L, 3, 0); + int value = tolua_toboolean(L, 4, 0); + + int mode; + for (mode=0;helpmodes[mode].name!=NULL;++mode) { + if (strcmp(policy, helpmodes[mode].name)==0) { + if (value) { + set_alliance(self, other, get_alliance(self, other) | helpmodes[mode].status); + } else { + set_alliance(self, other, get_alliance(self, other) & ~helpmodes[mode].status); + } + break; + } + } + + return 0; +} + +static int +tolua_faction_normalize(lua_State* L) +{ + faction * f = (faction *)tolua_tousertype(L, 1, 0); + region * r = (region * )tolua_tousertype(L, 2, 0); + if (r) { + plane * pl = rplane(r); + int nx = r->x, ny = r->y; + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl, r); + tolua_pushnumber(L, (lua_Number)nx); + tolua_pushnumber(L, (lua_Number)ny); + return 2; + } + return 0; +} + +static int +tolua_faction_set_origin(lua_State* L) +{ + faction * f = (faction *)tolua_tousertype(L, 1, 0); + region * r = (region *)tolua_tousertype(L, 2, 0); + plane * pl = rplane(r); + int id = pl?pl->id:0; + + set_ursprung(f, id, r->x - plane_center_x(pl), r->y - plane_center_y(pl)); + return 0; +} + +static int +tolua_faction_get_origin(lua_State* L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + + ursprung * origin = self->ursprung; + int x, y; + while (origin!=NULL && origin->id!=0) { + origin = origin->next; + } + if (origin) { + x = origin->x; + y = origin->y; + } else { + x = 0; + y = 0; + } + + tolua_pushnumber(L, (lua_Number)x); + tolua_pushnumber(L, (lua_Number)y); + return 2; +} + +static int +tolua_faction_destroy(lua_State* L) +{ + faction* f = (faction*) tolua_tousertype(L, 1, 0); + destroyfaction(f); + return 0; +} + +static int +tolua_faction_create(lua_State* L) +{ + const char * email = tolua_tostring(L, 1, 0); + const char * racename = tolua_tostring(L, 2, 0); + const char * lang = tolua_tostring(L, 3, 0); + struct locale * loc = find_locale(lang); + faction * f = NULL; + const struct race * frace = rc_find(racename); + if (frace==NULL) frace = findrace(racename, find_locale("de")); + if (frace==NULL) frace = findrace(racename, find_locale("en")); + if (frace!=NULL) { + f = addfaction(email, NULL, frace, loc, 0); + } + if (!f) { + log_error(("faction.create(%s, %s, %s)\n", email, racename, lang)); + } + tolua_pushusertype(L, f, TOLUA_CAST "faction"); + return 1; +} + +static int tolua_faction_get_password(lua_State* L) +{ + faction* self = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, faction_getpassword(self)); + return 1; +} + +static int tolua_faction_set_password(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + faction_setpassword(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int tolua_faction_get_email(lua_State* L) +{ + faction* self = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, faction_getemail(self)); + return 1; +} + +static int tolua_faction_set_email(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + faction_setemail(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int tolua_faction_get_locale(lua_State* L) +{ + faction* self = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, locale_name(self->locale)); + return 1; +} + +static int tolua_faction_set_locale(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + self->locale = find_locale(name); + return 0; +} + +static int tolua_faction_get_race(lua_State* L) +{ + faction* self = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->race->_name[0]); + return 1; +} + +static int tolua_faction_set_race(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + race * rc = rc_find(name); + if (rc!=NULL) { + self->race = rc; + } + + return 0; +} + +static int tolua_faction_get_name(lua_State* L) +{ + faction* self = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, faction_getname(self)); + return 1; +} + +static int tolua_faction_set_name(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + faction_setname(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int tolua_faction_get_uid(lua_State* L) +{ + faction* f = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, f->subscription); + return 1; +} + +static int tolua_faction_set_uid(lua_State* L) +{ + faction* f = (faction*)tolua_tousertype(L, 1, 0); + f->subscription = (int)tolua_tonumber(L, 2, 0); + return 0; +} + +static int tolua_faction_get_info(lua_State* L) +{ + faction* self = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, faction_getbanner(self)); + return 1; +} + +static int tolua_faction_set_info(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + faction_setbanner(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int tolua_faction_get_alliance(lua_State* L) +{ + faction* self = (faction*) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, f_get_alliance(self), TOLUA_CAST "alliance"); + return 1; +} + +static int tolua_faction_set_alliance(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + alliance* alli = (alliance*)tolua_tousertype(L, 2, 0); + + setalliance(self, alli); + + return 0; +} + +static int tolua_faction_get_items(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + item ** item_ptr = (item **)lua_newuserdata(L, sizeof(item *)); + + luaL_getmetatable(L, TOLUA_CAST "item"); + lua_setmetatable(L, -2); + + *item_ptr = self->items; + + lua_pushcclosure(L, tolua_itemlist_next, 1); + + return 1; +} + +static int +tolua_faction_tostring(lua_State *L) +{ + faction * self = (faction *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, factionname(self)); + return 1; +} + +static int tolua_faction_get_spells(lua_State* L) +{ + faction* self = (faction*)tolua_tousertype(L, 1, 0); + spell_list * slist = self->spellbook; + if (slist) { + spell_list ** spell_ptr = (spell_list **)lua_newuserdata(L, sizeof(spell_list *)); + luaL_getmetatable(L, TOLUA_CAST "spell_list"); + lua_setmetatable(L, -2); + + *spell_ptr = slist; + lua_pushcclosure(L, tolua_spelllist_next, 1); + return 1; + } + + lua_pushnil(L); + return 1; +} + +void +tolua_faction_open(lua_State* L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "faction"); + tolua_usertype(L, TOLUA_CAST "faction_list"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, TOLUA_CAST "faction", TOLUA_CAST "faction", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "faction"); + { + tolua_function(L, TOLUA_CAST "__tostring", tolua_faction_tostring); + + tolua_variable(L, TOLUA_CAST "id", tolua_faction_get_id, tolua_faction_set_id); + tolua_variable(L, TOLUA_CAST "uid", &tolua_faction_get_uid, &tolua_faction_set_uid); + tolua_variable(L, TOLUA_CAST "name", &tolua_faction_get_name, &tolua_faction_set_name); + tolua_variable(L, TOLUA_CAST "info", &tolua_faction_get_info, &tolua_faction_set_info); + tolua_variable(L, TOLUA_CAST "units", tolua_faction_get_units, NULL); + tolua_variable(L, TOLUA_CAST "heroes", tolua_faction_get_heroes, NULL); + tolua_variable(L, TOLUA_CAST "spells", tolua_faction_get_spells, 0); + tolua_variable(L, TOLUA_CAST "maxheroes", tolua_faction_get_maxheroes, NULL); + tolua_variable(L, TOLUA_CAST "password", tolua_faction_get_password, tolua_faction_set_password); + tolua_variable(L, TOLUA_CAST "email", tolua_faction_get_email, tolua_faction_set_email); + tolua_variable(L, TOLUA_CAST "locale", tolua_faction_get_locale, tolua_faction_set_locale); + tolua_variable(L, TOLUA_CAST "race", tolua_faction_get_race, tolua_faction_set_race); + tolua_variable(L, TOLUA_CAST "alliance", tolua_faction_get_alliance, tolua_faction_set_alliance); + tolua_variable(L, TOLUA_CAST "score", tolua_faction_get_score, NULL); + tolua_variable(L, TOLUA_CAST "age", tolua_faction_get_age, tolua_faction_set_age); + tolua_variable(L, TOLUA_CAST "options", tolua_faction_get_options, tolua_faction_set_options); + tolua_variable(L, TOLUA_CAST "flags", tolua_faction_get_flags, NULL); + tolua_variable(L, TOLUA_CAST "lastturn", tolua_faction_get_lastturn, tolua_faction_set_lastturn); + + tolua_function(L, TOLUA_CAST "set_policy", &tolua_faction_set_policy); + tolua_function(L, TOLUA_CAST "get_policy", &tolua_faction_get_policy); + tolua_function(L, TOLUA_CAST "get_origin", &tolua_faction_get_origin); + tolua_function(L, TOLUA_CAST "set_origin", &tolua_faction_set_origin); + tolua_function(L, TOLUA_CAST "normalize", &tolua_faction_normalize); + + tolua_function(L, TOLUA_CAST "add_item", tolua_faction_add_item); + tolua_variable(L, TOLUA_CAST "items", tolua_faction_get_items, NULL); + + tolua_function(L, TOLUA_CAST "renumber", &tolua_faction_renumber); + tolua_function(L, TOLUA_CAST "create", &tolua_faction_create); + tolua_function(L, TOLUA_CAST "destroy", &tolua_faction_destroy); +#ifdef TODO + def("faction_origin", &faction_getorigin, pure_out_value(_2) + pure_out_value(_3)), + + .def_readwrite("subscription", &faction::subscription) + + .property("x", &faction_getorigin_x, &faction_setorigin_x) + .property("y", &faction_getorigin_y, &faction_setorigin_y) + + .def("add_notice", &faction_addnotice) +#endif + tolua_variable(L, TOLUA_CAST "objects", tolua_faction_get_objects, NULL); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_faction.h b/src/bindings/bind_faction.h index e4148e016..c89750062 100644 --- a/src/bindings/bind_faction.h +++ b/src/bindings/bind_faction.h @@ -1,24 +1,24 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - int tolua_factionlist_next(struct lua_State *L); - int tolua_factionlist_iter(struct lua_State *L); - void tolua_faction_open(struct lua_State *L); - -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + int tolua_factionlist_next(struct lua_State *L); + int tolua_factionlist_iter(struct lua_State *L); + void tolua_faction_open(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_gmtool.c b/src/bindings/bind_gmtool.c index 2e6924a5e..6b57d1740 100644 --- a/src/bindings/bind_gmtool.c +++ b/src/bindings/bind_gmtool.c @@ -1,266 +1,266 @@ -#include -#include - -#include "bind_gmtool.h" -#include "../gmtool.h" -#include "../gmtool_structs.h" - -#include -#include -#include -#include - -#include -#include - -static int -tolua_run_mapper(lua_State* L) -{ - run_mapper(); - return 0; -} - -static int -tolua_highlight_region(lua_State* L) -{ - region * r = tolua_tousertype(L, 1, 0); - int select = tolua_toboolean(L, 2, 0); - highlight_region(r, select); - return 0; -} - -static int -tolua_current_region(lua_State* L) -{ - map_region * mr = cursor_region(¤t_state->display, ¤t_state->cursor); - tolua_pushusertype(L, mr?mr->r:NULL, TOLUA_CAST "region"); - return 1; -} - - -static int -tolua_select_coordinate(lua_State* L) -{ - int nx = (int)tolua_tonumber(L, 1, 0); - int ny = (int)tolua_tonumber(L, 2, 0); - int select = tolua_toboolean(L, 3, 0); - if (current_state) { - select_coordinate(current_state->selected, nx, ny, select); - } - return 0; -} - -static int -tolua_select_region(lua_State* L) -{ - region * r = tolua_tousertype(L, 1, 0); - int select = tolua_toboolean(L, 2, 0); - if (current_state && r) { - select_coordinate(current_state->selected, r->x, r->y, select); - } - return 0; -} - -typedef struct tag_iterator { - selection * list; - tag * node; - region * r; - int hash; -} tag_iterator; - -void -tag_advance(tag_iterator * iter) -{ - while (iter->hash!=MAXTHASH) { - if (iter->node) { - iter->node = iter->node->nexthash; - } - while (!iter->node && iter->hash != MAXTHASH) { - if (++iter->hash != MAXTHASH) { - iter->node = iter->list->tags[iter->hash]; - } - } - if (iter->node) { - iter->r = findregion(iter->node->coord.x, iter->node->coord.y); - if (iter->r) { - break; - } - } - } -} - -void -tag_rewind(tag_iterator * iter) -{ - if (iter->list) { - iter->r = NULL; - iter->node = iter->list->tags[0]; - iter->hash = 0; - if (iter->node) { - iter->r = findregion(iter->node->coord.x, iter->node->coord.y); - } - if (!iter->r) { - tag_advance(iter); - } - } else { - iter->node = 0; - iter->hash = MAXTHASH; - } -} - -static int -tolua_tags_next(lua_State *L) -{ - tag_iterator * iter = (tag_iterator *)lua_touserdata(L, lua_upvalueindex(1)); - if (iter->node) { - tolua_pushusertype(L, (void*)iter->r, TOLUA_CAST "region"); - tag_advance(iter); - return 1; - } - else { - return 0; /* no more values to return */ - } -} - -static int -tolua_selected_regions(lua_State* L) -{ - tag_iterator * iter = (tag_iterator*)lua_newuserdata(L, sizeof(tag_iterator)); - - luaL_getmetatable(L, "tag_iterator"); - lua_setmetatable(L, -2); - - iter->list = current_state->selected; - tag_rewind(iter); - - lua_pushcclosure(L, tolua_tags_next, 1); - return 1; -} - -static int -tolua_state_open(lua_State* L) -{ - unused(L); - state_open(); - return 0; -} - -static int -tolua_state_close(lua_State* L) -{ - unused(L); - state_close(current_state); - return 0; -} - -static int -tolua_make_island(lua_State * L) -{ - int x = (int)tolua_tonumber(L, 1, 0); - int y = (int)tolua_tonumber(L, 2, 0); - int s = (int)tolua_tonumber(L, 3, 0); - int n = (int)tolua_tonumber(L, 4, s / 3); - - n = build_island_e3(x, y, n, s); - tolua_pushnumber(L, n); - return 1; -} - -static int paint_handle; -static struct lua_State * paint_state; - -static void -lua_paint_info(struct window * wnd, const struct state * st) -{ - struct lua_State * L = paint_state; - int nx = st->cursor.x, ny = st->cursor.y; - pnormalize(&nx, &ny, st->cursor.pl); - lua_rawgeti(L, LUA_REGISTRYINDEX, paint_handle); - tolua_pushnumber(L, nx); - tolua_pushnumber(L, ny); - if (lua_pcall(L, 2, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("paint function failed: %s\n", error)); - lua_pop(L, 1); - tolua_error(L, TOLUA_CAST "event handler call failed", NULL); - } else { - const char* result = lua_tostring(L, -1); - WINDOW * win = wnd->handle; - int size = getmaxx(win)-2; - int line = 0, maxline = getmaxy(win)-2; - const char * str = result; - wxborder(win); - - while (*str && line +#include + +#include "bind_gmtool.h" +#include "../gmtool.h" +#include "../gmtool_structs.h" + +#include +#include +#include +#include + +#include +#include + +static int +tolua_run_mapper(lua_State* L) +{ + run_mapper(); + return 0; +} + +static int +tolua_highlight_region(lua_State* L) +{ + region * r = tolua_tousertype(L, 1, 0); + int select = tolua_toboolean(L, 2, 0); + highlight_region(r, select); + return 0; +} + +static int +tolua_current_region(lua_State* L) +{ + map_region * mr = cursor_region(¤t_state->display, ¤t_state->cursor); + tolua_pushusertype(L, mr?mr->r:NULL, TOLUA_CAST "region"); + return 1; +} + + +static int +tolua_select_coordinate(lua_State* L) +{ + int nx = (int)tolua_tonumber(L, 1, 0); + int ny = (int)tolua_tonumber(L, 2, 0); + int select = tolua_toboolean(L, 3, 0); + if (current_state) { + select_coordinate(current_state->selected, nx, ny, select); + } + return 0; +} + +static int +tolua_select_region(lua_State* L) +{ + region * r = tolua_tousertype(L, 1, 0); + int select = tolua_toboolean(L, 2, 0); + if (current_state && r) { + select_coordinate(current_state->selected, r->x, r->y, select); + } + return 0; +} + +typedef struct tag_iterator { + selection * list; + tag * node; + region * r; + int hash; +} tag_iterator; + +void +tag_advance(tag_iterator * iter) +{ + while (iter->hash!=MAXTHASH) { + if (iter->node) { + iter->node = iter->node->nexthash; + } + while (!iter->node && iter->hash != MAXTHASH) { + if (++iter->hash != MAXTHASH) { + iter->node = iter->list->tags[iter->hash]; + } + } + if (iter->node) { + iter->r = findregion(iter->node->coord.x, iter->node->coord.y); + if (iter->r) { + break; + } + } + } +} + +void +tag_rewind(tag_iterator * iter) +{ + if (iter->list) { + iter->r = NULL; + iter->node = iter->list->tags[0]; + iter->hash = 0; + if (iter->node) { + iter->r = findregion(iter->node->coord.x, iter->node->coord.y); + } + if (!iter->r) { + tag_advance(iter); + } + } else { + iter->node = 0; + iter->hash = MAXTHASH; + } +} + +static int +tolua_tags_next(lua_State *L) +{ + tag_iterator * iter = (tag_iterator *)lua_touserdata(L, lua_upvalueindex(1)); + if (iter->node) { + tolua_pushusertype(L, (void*)iter->r, TOLUA_CAST "region"); + tag_advance(iter); + return 1; + } + else { + return 0; /* no more values to return */ + } +} + +static int +tolua_selected_regions(lua_State* L) +{ + tag_iterator * iter = (tag_iterator*)lua_newuserdata(L, sizeof(tag_iterator)); + + luaL_getmetatable(L, "tag_iterator"); + lua_setmetatable(L, -2); + + iter->list = current_state->selected; + tag_rewind(iter); + + lua_pushcclosure(L, tolua_tags_next, 1); + return 1; +} + +static int +tolua_state_open(lua_State* L) +{ + unused(L); + state_open(); + return 0; +} + +static int +tolua_state_close(lua_State* L) +{ + unused(L); + state_close(current_state); + return 0; +} + +static int +tolua_make_island(lua_State * L) +{ + int x = (int)tolua_tonumber(L, 1, 0); + int y = (int)tolua_tonumber(L, 2, 0); + int s = (int)tolua_tonumber(L, 3, 0); + int n = (int)tolua_tonumber(L, 4, s / 3); + + n = build_island_e3(x, y, n, s); + tolua_pushnumber(L, n); + return 1; +} + +static int paint_handle; +static struct lua_State * paint_state; + +static void +lua_paint_info(struct window * wnd, const struct state * st) +{ + struct lua_State * L = paint_state; + int nx = st->cursor.x, ny = st->cursor.y; + pnormalize(&nx, &ny, st->cursor.pl); + lua_rawgeti(L, LUA_REGISTRYINDEX, paint_handle); + tolua_pushnumber(L, nx); + tolua_pushnumber(L, ny); + if (lua_pcall(L, 2, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("paint function failed: %s\n", error)); + lua_pop(L, 1); + tolua_error(L, TOLUA_CAST "event handler call failed", NULL); + } else { + const char* result = lua_tostring(L, -1); + WINDOW * win = wnd->handle; + int size = getmaxx(win)-2; + int line = 0, maxline = getmaxy(win)-2; + const char * str = result; + wxborder(win); + + while (*str && line -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include "bind_hashtable.h" - -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include - -#include - -static int -tolua_hashtable_get(lua_State* L) -{ - hashtable self = (hashtable) tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - attrib * a = a_find(*self, &at_object); - - for (; a && a->type == &at_object; a = a->next) { - const char * obj_name = object_name(a); - if (obj_name && name && strcmp(obj_name, name) == 0) { - variant val; - object_type type; - - object_get(a, &type, &val); - switch (type) { - case TNONE: - lua_pushnil(L); - break; - case TINTEGER: - lua_pushnumber(L, (lua_Number)val.i); - break; - case TREAL: - lua_pushnumber(L, (lua_Number)val.f); - break; - case TREGION: - tolua_pushusertype(L, val.v, TOLUA_CAST "region"); - break; - case TBUILDING: - tolua_pushusertype(L, val.v, TOLUA_CAST "building"); - break; - case TUNIT: - tolua_pushusertype(L, val.v, TOLUA_CAST "unit"); - break; - case TSHIP: - tolua_pushusertype(L, val.v, TOLUA_CAST "ship"); - break; - case TSTRING: - tolua_pushstring(L, (const char*) val.v); - break; - default: - assert(!"not implemented"); - } - return 1; - } - } - lua_pushnil(L); - return 1; -} - -static int -tolua_hashtable_set_number(lua_State* L) -{ - hashtable self = (hashtable) tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - lua_Number value = tolua_tonumber(L, 3, 0); - attrib * a = a_find(*self, &at_object); - variant val; - - val.f = (float)value; - - for (; a && a->type == &at_object; a = a->next) { - if (strcmp(object_name(a), name) == 0) { - object_set(a, TREAL, val); - return 0; - } - } - - a = a_add(self, object_create(name, TREAL, val)); - return 0; -} - -static int -tolua_hashtable_set_string(lua_State* L) -{ - hashtable self = (hashtable) tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - const char * value = tolua_tostring(L, 3, 0); - attrib * a = a_find(*self, &at_object); - variant val; - - val.v = strdup(value); - - for (; a && a->type == &at_object; a = a->next) { - if (strcmp(object_name(a), name) == 0) { - object_set(a, TSTRING, val); - return 0; - } - } - - a = a_add(self, object_create(name, TSTRING, val)); - return 0; -} - -static int -tolua_hashtable_set_usertype(lua_State* L, int type) -{ - hashtable self = (hashtable) tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - unit * value = tolua_tousertype(L, 3, 0); - attrib * a = a_find(*self, &at_object); - variant val; - - val.v = value; - - for (; a && a->type == &at_object; a = a->next) { - if (strcmp(object_name(a), name) == 0) { - object_set(a, type, val); - return 0; - } - } - - a = a_add(self, object_create(name, type, val)); - return 0; -} - - -static int -tolua_hashtable_set(lua_State* L) -{ - tolua_Error tolua_err; - if (tolua_isnumber(L, 3, 0, &tolua_err)) { - return tolua_hashtable_set_number(L); - } else if (tolua_isusertype(L, 3, TOLUA_CAST "unit", 0, &tolua_err)) { - return tolua_hashtable_set_usertype(L, TUNIT); - } else if (tolua_isusertype(L, 3, TOLUA_CAST "faction", 0, &tolua_err)) { - return tolua_hashtable_set_usertype(L, TFACTION); - } else if (tolua_isusertype(L, 3, TOLUA_CAST "ship", 0, &tolua_err)) { - return tolua_hashtable_set_usertype(L, TSHIP); - } else if (tolua_isusertype(L, 3, TOLUA_CAST "building", 0, &tolua_err)) { - return tolua_hashtable_set_usertype(L, TBUILDING); - } else if (tolua_isusertype(L, 3, TOLUA_CAST "region", 0, &tolua_err)) { - return tolua_hashtable_set_usertype(L, TREGION); - } - return tolua_hashtable_set_string(L); -} - - - -void -tolua_hashtable_open(lua_State* L) -{ - /* register user types */ - tolua_usertype(L, TOLUA_CAST "hashtable"); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_cclass(L, TOLUA_CAST "hashtable", TOLUA_CAST "hashtable", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "hashtable"); - { - tolua_function(L, TOLUA_CAST "get", tolua_hashtable_get); - tolua_function(L, TOLUA_CAST "set", tolua_hashtable_set); - } - tolua_endmodule(L); - } - tolua_endmodule(L); -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bind_hashtable.h" + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include + +static int +tolua_hashtable_get(lua_State* L) +{ + hashtable self = (hashtable) tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + attrib * a = a_find(*self, &at_object); + + for (; a && a->type == &at_object; a = a->next) { + const char * obj_name = object_name(a); + if (obj_name && name && strcmp(obj_name, name) == 0) { + variant val; + object_type type; + + object_get(a, &type, &val); + switch (type) { + case TNONE: + lua_pushnil(L); + break; + case TINTEGER: + lua_pushnumber(L, (lua_Number)val.i); + break; + case TREAL: + lua_pushnumber(L, (lua_Number)val.f); + break; + case TREGION: + tolua_pushusertype(L, val.v, TOLUA_CAST "region"); + break; + case TBUILDING: + tolua_pushusertype(L, val.v, TOLUA_CAST "building"); + break; + case TUNIT: + tolua_pushusertype(L, val.v, TOLUA_CAST "unit"); + break; + case TSHIP: + tolua_pushusertype(L, val.v, TOLUA_CAST "ship"); + break; + case TSTRING: + tolua_pushstring(L, (const char*) val.v); + break; + default: + assert(!"not implemented"); + } + return 1; + } + } + lua_pushnil(L); + return 1; +} + +static int +tolua_hashtable_set_number(lua_State* L) +{ + hashtable self = (hashtable) tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + lua_Number value = tolua_tonumber(L, 3, 0); + attrib * a = a_find(*self, &at_object); + variant val; + + val.f = (float)value; + + for (; a && a->type == &at_object; a = a->next) { + if (strcmp(object_name(a), name) == 0) { + object_set(a, TREAL, val); + return 0; + } + } + + a = a_add(self, object_create(name, TREAL, val)); + return 0; +} + +static int +tolua_hashtable_set_string(lua_State* L) +{ + hashtable self = (hashtable) tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + const char * value = tolua_tostring(L, 3, 0); + attrib * a = a_find(*self, &at_object); + variant val; + + val.v = strdup(value); + + for (; a && a->type == &at_object; a = a->next) { + if (strcmp(object_name(a), name) == 0) { + object_set(a, TSTRING, val); + return 0; + } + } + + a = a_add(self, object_create(name, TSTRING, val)); + return 0; +} + +static int +tolua_hashtable_set_usertype(lua_State* L, int type) +{ + hashtable self = (hashtable) tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + unit * value = tolua_tousertype(L, 3, 0); + attrib * a = a_find(*self, &at_object); + variant val; + + val.v = value; + + for (; a && a->type == &at_object; a = a->next) { + if (strcmp(object_name(a), name) == 0) { + object_set(a, type, val); + return 0; + } + } + + a = a_add(self, object_create(name, type, val)); + return 0; +} + + +static int +tolua_hashtable_set(lua_State* L) +{ + tolua_Error tolua_err; + if (tolua_isnumber(L, 3, 0, &tolua_err)) { + return tolua_hashtable_set_number(L); + } else if (tolua_isusertype(L, 3, TOLUA_CAST "unit", 0, &tolua_err)) { + return tolua_hashtable_set_usertype(L, TUNIT); + } else if (tolua_isusertype(L, 3, TOLUA_CAST "faction", 0, &tolua_err)) { + return tolua_hashtable_set_usertype(L, TFACTION); + } else if (tolua_isusertype(L, 3, TOLUA_CAST "ship", 0, &tolua_err)) { + return tolua_hashtable_set_usertype(L, TSHIP); + } else if (tolua_isusertype(L, 3, TOLUA_CAST "building", 0, &tolua_err)) { + return tolua_hashtable_set_usertype(L, TBUILDING); + } else if (tolua_isusertype(L, 3, TOLUA_CAST "region", 0, &tolua_err)) { + return tolua_hashtable_set_usertype(L, TREGION); + } + return tolua_hashtable_set_string(L); +} + + + +void +tolua_hashtable_open(lua_State* L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "hashtable"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, TOLUA_CAST "hashtable", TOLUA_CAST "hashtable", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "hashtable"); + { + tolua_function(L, TOLUA_CAST "get", tolua_hashtable_get); + tolua_function(L, TOLUA_CAST "set", tolua_hashtable_set); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_hashtable.h b/src/bindings/bind_hashtable.h index 266b9027e..d137638f2 100644 --- a/src/bindings/bind_hashtable.h +++ b/src/bindings/bind_hashtable.h @@ -1,24 +1,24 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - void tolua_hashtable_open(struct lua_State *L); - - typedef struct attrib ** hashtable; - -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + void tolua_hashtable_open(struct lua_State *L); + + typedef struct attrib ** hashtable; + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_message.c b/src/bindings/bind_message.c index f2de9538a..44c5eb0e7 100644 --- a/src/bindings/bind_message.c +++ b/src/bindings/bind_message.c @@ -1,348 +1,348 @@ -#include -#include - -// kernel includes -#include -#include -#include -#include -#include -#include - -// util includes -#include - -// lua includes -#include -#include - -#include - -#define E_OK 0 -#define E_INVALID_MESSAGE 1 -#define E_INVALID_PARAMETER_NAME 2 -#define E_INVALID_PARAMETER_TYPE 3 -#define E_INVALID_PARAMETER_VALUE 4 - -typedef struct lua_message { - const message_type * mtype; - message * msg; - variant * args; -} lua_message; - -int -mtype_get_param(const message_type * mtype, const char * param) -{ - int i; - for (i=0;i!=mtype->nparameters;++i) { - if (strcmp(mtype->pnames[i], param)==0) { - return i; - } - } - return mtype->nparameters; -} - -static lua_message * -msg_create_message(const char *type) -{ - lua_message * lmsg = malloc(sizeof(lua_message)); - lmsg->msg = 0; - lmsg->args = 0; - lmsg->mtype = mt_find(type); - if (lmsg->mtype) { - lmsg->args = (variant*)calloc(lmsg->mtype->nparameters, sizeof(variant)); - } - return lmsg; -} - -/* - static void -msg_destroy_message(lua_message * msg) -{ - if (msg->msg) msg_release(msg->msg); - if (msg->mtype) { - int i; - for (i=0;i!=msg->mtype->nparameters;++i) { - if (msg->mtype->types[i]->release) { - msg->mtype->types[i]->release(msg->args[i]); - } - } - } -} -*/ -int -msg_set_resource(lua_message * msg, const char * param, const char * resname) -{ - if (msg->mtype) { - int i = mtype_get_param(msg->mtype, param); - if (i==msg->mtype->nparameters) { - return E_INVALID_PARAMETER_NAME; - } - if (strcmp(msg->mtype->types[i]->name, "resource")!=0) { - return E_INVALID_PARAMETER_TYPE; - } - - msg->args[i].v = (void*)rt_find(resname); - - return E_OK; - } - return E_INVALID_MESSAGE; -} - -int -msg_set_unit(lua_message * msg, const char * param, const unit * u) -{ - if (msg->mtype) { - int i = mtype_get_param(msg->mtype, param); - - if (i==msg->mtype->nparameters) { - return E_INVALID_PARAMETER_NAME; - } - if (strcmp(msg->mtype->types[i]->name, "unit")!=0) { - return E_INVALID_PARAMETER_TYPE; - } - - msg->args[i].v = (void*)u; - - return E_OK; - } - return E_INVALID_MESSAGE; -} - -int -msg_set_region(lua_message * msg, const char * param, const region * r) -{ - if (msg->mtype) { - int i = mtype_get_param(msg->mtype, param); - - if (i==msg->mtype->nparameters) { - return E_INVALID_PARAMETER_NAME; - } - if (strcmp(msg->mtype->types[i]->name, "region")!=0) { - return E_INVALID_PARAMETER_TYPE; - } - - msg->args[i].v = (void*)r; - - return E_OK; - } - return E_INVALID_MESSAGE; -} - -int -msg_set_string(lua_message * msg, const char * param, const char * value) -{ - if (msg->mtype) { - int i = mtype_get_param(msg->mtype, param); - variant var; - - if (i==msg->mtype->nparameters) { - return E_INVALID_PARAMETER_NAME; - } - if (strcmp(msg->mtype->types[i]->name, "string")!=0) { - return E_INVALID_PARAMETER_TYPE; - } - - var.v = (void*)value; - msg->args[i] = msg->mtype->types[i]->copy(var); - - return E_OK; - } - return E_INVALID_MESSAGE; -} - -int -msg_set_int(lua_message * msg, const char * param, int value) -{ - if (msg->mtype) { - int i = mtype_get_param(msg->mtype, param); - if (i==msg->mtype->nparameters) { - return E_INVALID_PARAMETER_NAME; - } - if (strcmp(msg->mtype->types[i]->name, "int")!=0) { - return E_INVALID_PARAMETER_TYPE; - } - - msg->args[i].i = value; - - return E_OK; - } - return E_INVALID_MESSAGE; -} - -int -msg_send_faction(lua_message * msg, faction * f) -{ - assert(f); - assert(msg); - - if (msg->mtype) { - if (msg->msg==NULL) { - msg->msg = msg_create(msg->mtype, msg->args); - } - add_message(&f->msgs, msg->msg); - return E_OK; - } - return E_INVALID_MESSAGE; -} - -int -msg_send_region(lua_message * lmsg, region * r) -{ - if (lmsg->mtype) { - if (lmsg->msg==NULL) { - lmsg->msg = msg_create(lmsg->mtype, lmsg->args); - } - add_message(&r->msgs, lmsg->msg); - return E_OK; - } - return E_INVALID_MESSAGE; -} - - -static int -tolua_msg_create(lua_State * L) -{ - const char * type = tolua_tostring(L, 1, 0); - lua_message * lmsg = msg_create_message(type); - tolua_pushusertype(L, (void*)lmsg, TOLUA_CAST "message"); - return 1; -} -static int -tolua_msg_set_string(lua_State * L) -{ - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - const char * param = tolua_tostring(L, 2, 0); - const char * value = tolua_tostring(L, 3, 0); - int result = msg_set_string(lmsg, param, value); - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_msg_set_int(lua_State * L) -{ - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - const char * param = tolua_tostring(L, 2, 0); - int value = (int)tolua_tonumber(L, 3, 0); - int result = msg_set_int(lmsg, param, value); - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_msg_set_resource(lua_State * L) -{ - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - const char * param = tolua_tostring(L, 2, 0); - const char * value = tolua_tostring(L, 3, 0); - int result = msg_set_resource(lmsg, param, value); - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_msg_set_unit(lua_State * L) -{ - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - const char * param = tolua_tostring(L, 2, 0); - unit * value = (unit *)tolua_tousertype(L, 3, 0); - int result = msg_set_unit(lmsg, param, value); - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_msg_set_region(lua_State * L) -{ - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - const char * param = tolua_tostring(L, 2, 0); - region * value = (region *)tolua_tousertype(L, 3, 0); - int result = msg_set_region(lmsg, param, value); - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_msg_set(lua_State * L) -{ - tolua_Error err; - if (tolua_isnumber(L, 3, 0, &err)) { - return tolua_msg_set_int(L); - } else if (tolua_isusertype(L, 3, TOLUA_CAST "region", 0, &err)) { - return tolua_msg_set_region(L); - } else if (tolua_isusertype(L, 3, TOLUA_CAST "unit", 0, &err)) { - return tolua_msg_set_unit(L); - } - tolua_pushnumber(L, (lua_Number)-1); - return 1; -} - -static int -tolua_msg_send_region(lua_State * L) -{ - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - region * r = (region *)tolua_tousertype(L, 2, 0); - int result = msg_send_region(lmsg, r); - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_msg_report_action(lua_State * L) -{ - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - region * r = (region *)tolua_tousertype(L, 2, 0); - unit * u = (unit *)tolua_tousertype(L, 3, 0); - int result, flags = (int)tolua_tonumber(L, 4, 0); - if (lmsg->msg==NULL) { - lmsg->msg = msg_create(lmsg->mtype, lmsg->args); - } - result = report_action(r, u, lmsg->msg, flags); - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_msg_send_faction(lua_State * L) -{ - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - faction * f = (faction *)tolua_tousertype(L, 2, 0); - if (f && lmsg) { - int result = msg_send_faction(lmsg, f); - tolua_pushnumber(L, (lua_Number)result); - return 1; - } - return 0; -} - -void -tolua_message_open(lua_State* L) -{ - /* register user types */ - tolua_usertype(L, TOLUA_CAST "message"); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_function(L, TOLUA_CAST "message", tolua_msg_create); - - tolua_cclass(L, TOLUA_CAST "message", TOLUA_CAST "message", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "message"); - { - tolua_function(L, TOLUA_CAST "set", tolua_msg_set); - tolua_function(L, TOLUA_CAST "set_unit", tolua_msg_set_unit); - tolua_function(L, TOLUA_CAST "set_region", tolua_msg_set_region); - tolua_function(L, TOLUA_CAST "set_resource", tolua_msg_set_resource); - tolua_function(L, TOLUA_CAST "set_int", tolua_msg_set_int); - tolua_function(L, TOLUA_CAST "set_string", tolua_msg_set_string); - tolua_function(L, TOLUA_CAST "send_faction", tolua_msg_send_faction); - tolua_function(L, TOLUA_CAST "send_region", tolua_msg_send_region); - tolua_function(L, TOLUA_CAST "report_action", tolua_msg_report_action); - - tolua_function(L, TOLUA_CAST "create", tolua_msg_create); - } - tolua_endmodule(L); - } - tolua_endmodule(L); -} +#include +#include + +// kernel includes +#include +#include +#include +#include +#include +#include + +// util includes +#include + +// lua includes +#include +#include + +#include + +#define E_OK 0 +#define E_INVALID_MESSAGE 1 +#define E_INVALID_PARAMETER_NAME 2 +#define E_INVALID_PARAMETER_TYPE 3 +#define E_INVALID_PARAMETER_VALUE 4 + +typedef struct lua_message { + const message_type * mtype; + message * msg; + variant * args; +} lua_message; + +int +mtype_get_param(const message_type * mtype, const char * param) +{ + int i; + for (i=0;i!=mtype->nparameters;++i) { + if (strcmp(mtype->pnames[i], param)==0) { + return i; + } + } + return mtype->nparameters; +} + +static lua_message * +msg_create_message(const char *type) +{ + lua_message * lmsg = malloc(sizeof(lua_message)); + lmsg->msg = 0; + lmsg->args = 0; + lmsg->mtype = mt_find(type); + if (lmsg->mtype) { + lmsg->args = (variant*)calloc(lmsg->mtype->nparameters, sizeof(variant)); + } + return lmsg; +} + +/* + static void +msg_destroy_message(lua_message * msg) +{ + if (msg->msg) msg_release(msg->msg); + if (msg->mtype) { + int i; + for (i=0;i!=msg->mtype->nparameters;++i) { + if (msg->mtype->types[i]->release) { + msg->mtype->types[i]->release(msg->args[i]); + } + } + } +} +*/ +int +msg_set_resource(lua_message * msg, const char * param, const char * resname) +{ + if (msg->mtype) { + int i = mtype_get_param(msg->mtype, param); + if (i==msg->mtype->nparameters) { + return E_INVALID_PARAMETER_NAME; + } + if (strcmp(msg->mtype->types[i]->name, "resource")!=0) { + return E_INVALID_PARAMETER_TYPE; + } + + msg->args[i].v = (void*)rt_find(resname); + + return E_OK; + } + return E_INVALID_MESSAGE; +} + +int +msg_set_unit(lua_message * msg, const char * param, const unit * u) +{ + if (msg->mtype) { + int i = mtype_get_param(msg->mtype, param); + + if (i==msg->mtype->nparameters) { + return E_INVALID_PARAMETER_NAME; + } + if (strcmp(msg->mtype->types[i]->name, "unit")!=0) { + return E_INVALID_PARAMETER_TYPE; + } + + msg->args[i].v = (void*)u; + + return E_OK; + } + return E_INVALID_MESSAGE; +} + +int +msg_set_region(lua_message * msg, const char * param, const region * r) +{ + if (msg->mtype) { + int i = mtype_get_param(msg->mtype, param); + + if (i==msg->mtype->nparameters) { + return E_INVALID_PARAMETER_NAME; + } + if (strcmp(msg->mtype->types[i]->name, "region")!=0) { + return E_INVALID_PARAMETER_TYPE; + } + + msg->args[i].v = (void*)r; + + return E_OK; + } + return E_INVALID_MESSAGE; +} + +int +msg_set_string(lua_message * msg, const char * param, const char * value) +{ + if (msg->mtype) { + int i = mtype_get_param(msg->mtype, param); + variant var; + + if (i==msg->mtype->nparameters) { + return E_INVALID_PARAMETER_NAME; + } + if (strcmp(msg->mtype->types[i]->name, "string")!=0) { + return E_INVALID_PARAMETER_TYPE; + } + + var.v = (void*)value; + msg->args[i] = msg->mtype->types[i]->copy(var); + + return E_OK; + } + return E_INVALID_MESSAGE; +} + +int +msg_set_int(lua_message * msg, const char * param, int value) +{ + if (msg->mtype) { + int i = mtype_get_param(msg->mtype, param); + if (i==msg->mtype->nparameters) { + return E_INVALID_PARAMETER_NAME; + } + if (strcmp(msg->mtype->types[i]->name, "int")!=0) { + return E_INVALID_PARAMETER_TYPE; + } + + msg->args[i].i = value; + + return E_OK; + } + return E_INVALID_MESSAGE; +} + +int +msg_send_faction(lua_message * msg, faction * f) +{ + assert(f); + assert(msg); + + if (msg->mtype) { + if (msg->msg==NULL) { + msg->msg = msg_create(msg->mtype, msg->args); + } + add_message(&f->msgs, msg->msg); + return E_OK; + } + return E_INVALID_MESSAGE; +} + +int +msg_send_region(lua_message * lmsg, region * r) +{ + if (lmsg->mtype) { + if (lmsg->msg==NULL) { + lmsg->msg = msg_create(lmsg->mtype, lmsg->args); + } + add_message(&r->msgs, lmsg->msg); + return E_OK; + } + return E_INVALID_MESSAGE; +} + + +static int +tolua_msg_create(lua_State * L) +{ + const char * type = tolua_tostring(L, 1, 0); + lua_message * lmsg = msg_create_message(type); + tolua_pushusertype(L, (void*)lmsg, TOLUA_CAST "message"); + return 1; +} +static int +tolua_msg_set_string(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + const char * param = tolua_tostring(L, 2, 0); + const char * value = tolua_tostring(L, 3, 0); + int result = msg_set_string(lmsg, param, value); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_msg_set_int(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + const char * param = tolua_tostring(L, 2, 0); + int value = (int)tolua_tonumber(L, 3, 0); + int result = msg_set_int(lmsg, param, value); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_msg_set_resource(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + const char * param = tolua_tostring(L, 2, 0); + const char * value = tolua_tostring(L, 3, 0); + int result = msg_set_resource(lmsg, param, value); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_msg_set_unit(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + const char * param = tolua_tostring(L, 2, 0); + unit * value = (unit *)tolua_tousertype(L, 3, 0); + int result = msg_set_unit(lmsg, param, value); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_msg_set_region(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + const char * param = tolua_tostring(L, 2, 0); + region * value = (region *)tolua_tousertype(L, 3, 0); + int result = msg_set_region(lmsg, param, value); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_msg_set(lua_State * L) +{ + tolua_Error err; + if (tolua_isnumber(L, 3, 0, &err)) { + return tolua_msg_set_int(L); + } else if (tolua_isusertype(L, 3, TOLUA_CAST "region", 0, &err)) { + return tolua_msg_set_region(L); + } else if (tolua_isusertype(L, 3, TOLUA_CAST "unit", 0, &err)) { + return tolua_msg_set_unit(L); + } + tolua_pushnumber(L, (lua_Number)-1); + return 1; +} + +static int +tolua_msg_send_region(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + region * r = (region *)tolua_tousertype(L, 2, 0); + int result = msg_send_region(lmsg, r); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_msg_report_action(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + region * r = (region *)tolua_tousertype(L, 2, 0); + unit * u = (unit *)tolua_tousertype(L, 3, 0); + int result, flags = (int)tolua_tonumber(L, 4, 0); + if (lmsg->msg==NULL) { + lmsg->msg = msg_create(lmsg->mtype, lmsg->args); + } + result = report_action(r, u, lmsg->msg, flags); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_msg_send_faction(lua_State * L) +{ + lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); + faction * f = (faction *)tolua_tousertype(L, 2, 0); + if (f && lmsg) { + int result = msg_send_faction(lmsg, f); + tolua_pushnumber(L, (lua_Number)result); + return 1; + } + return 0; +} + +void +tolua_message_open(lua_State* L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "message"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_function(L, TOLUA_CAST "message", tolua_msg_create); + + tolua_cclass(L, TOLUA_CAST "message", TOLUA_CAST "message", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "message"); + { + tolua_function(L, TOLUA_CAST "set", tolua_msg_set); + tolua_function(L, TOLUA_CAST "set_unit", tolua_msg_set_unit); + tolua_function(L, TOLUA_CAST "set_region", tolua_msg_set_region); + tolua_function(L, TOLUA_CAST "set_resource", tolua_msg_set_resource); + tolua_function(L, TOLUA_CAST "set_int", tolua_msg_set_int); + tolua_function(L, TOLUA_CAST "set_string", tolua_msg_set_string); + tolua_function(L, TOLUA_CAST "send_faction", tolua_msg_send_faction); + tolua_function(L, TOLUA_CAST "send_region", tolua_msg_send_region); + tolua_function(L, TOLUA_CAST "report_action", tolua_msg_report_action); + + tolua_function(L, TOLUA_CAST "create", tolua_msg_create); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_message.h b/src/bindings/bind_message.h index fa39bbe4f..ed9aab133 100644 --- a/src/bindings/bind_message.h +++ b/src/bindings/bind_message.h @@ -1,22 +1,22 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - void tolua_message_open(struct lua_State *L); - -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + void tolua_message_open(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_region.c b/src/bindings/bind_region.c index c80f8e0d7..19ec1dedb 100644 --- a/src/bindings/bind_region.c +++ b/src/bindings/bind_region.c @@ -1,696 +1,696 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include "bind_region.h" -#include "bind_unit.h" -#include "bind_ship.h" -#include "bind_building.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include - -int tolua_regionlist_next(lua_State *L) -{ - region** region_ptr = (region **)lua_touserdata(L, lua_upvalueindex(1)); - region * r = *region_ptr; - if (r != NULL) { - tolua_pushusertype(L, (void*)r, TOLUA_CAST "region"); - *region_ptr = r->next; - return 1; - } - else return 0; /* no more values to return */ -} - -static int -tolua_region_get_id(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->uid); - return 1; -} - -static int -tolua_region_get_x(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->x); - return 1; -} - -static int -tolua_region_get_y(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->y); - return 1; -} - -static int -tolua_region_get_plane(lua_State* L) -{ - region * r = (region *)tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, rplane(r), TOLUA_CAST "plane"); - return 1; -} - -static int -tolua_region_get_terrain(lua_State* L) -{ - region* self = (region*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->terrain->_name); - return 1; -} - -static int -tolua_region_set_terrain(lua_State* L) -{ - region* r = (region*) tolua_tousertype(L, 1, 0); - const char * tname = tolua_tostring(L, 2, 0); - if (tname) { - const terrain_type * terrain = get_terrain(tname); - if (terrain) { - terraform_region(r, terrain); - } - } - return 0; -} - -static int -tolua_region_get_terrainname(lua_State* L) -{ - region* self = (region*) tolua_tousertype(L, 1, 0); - attrib * a = a_find(self->attribs, &at_racename); - if (a) { - tolua_pushstring(L, get_racename(a)); - return 1; - } - return 0; -} - -static int -tolua_region_set_owner(lua_State* L) -{ - region* r = (region*) tolua_tousertype(L, 1, 0); - struct faction* f = (struct faction*) tolua_tousertype(L, 2, 0); - if (r) { - region_set_owner(r, f, turn); - } - return 0; -} - -static int -tolua_region_get_owner(lua_State* L) -{ - region* r = (region*) tolua_tousertype(L, 1, 0); - if (r) { - struct faction * f = region_get_owner(r); - tolua_pushusertype(L, f, TOLUA_CAST "faction"); - return 1; - } - return 0; -} - -static int -tolua_region_set_terrainname(lua_State* L) -{ - region* self = (region*) tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - if (name==NULL) { - a_removeall(&self->attribs, &at_racename); - } else { - set_racename(&self->attribs, name); - } - return 0; -} - -static int tolua_region_get_info(lua_State* L) -{ - region* self = (region*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, region_getinfo(self)); - return 1; -} - -static int tolua_region_set_info(lua_State* L) -{ - region* self = (region*)tolua_tousertype(L, 1, 0); - region_setinfo(self, tolua_tostring(L, 2, 0)); - return 0; -} - - -static int tolua_region_get_name(lua_State* L) -{ - region* self = (region*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, region_getname(self)); - return 1; -} - -static int tolua_region_set_name(lua_State* L) -{ - region* self = (region*)tolua_tousertype(L, 1, 0); - region_setname(self, tolua_tostring(L, 2, 0)); - return 0; -} - - -static int tolua_region_get_morale(lua_State* L) -{ - region* r = (region*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, region_get_morale(r)); - return 1; -} - -static int tolua_region_set_morale(lua_State* L) -{ - region* r = (region*)tolua_tousertype(L, 1, 0); - region_set_morale(r, (int)tolua_tonumber(L, 2, 0), turn); - return 0; -} - -static int tolua_region_get_flag(lua_State* L) -{ - region* self = (region*)tolua_tousertype(L, 1, 0); - int bit = (int)tolua_tonumber(L, 2, 0); - - lua_pushboolean(L, (self->flags & (1<land) { - const item_type * lux = r_luxury(r); - if (lux) { - const char * name = lux->rtype->_name[0]; - tolua_pushstring(L, name); - return 1; - } - } - return 0; -} - -static int tolua_region_set_luxury(lua_State* L) -{ - region* r = (region*)tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - if (r->land && name) { - const item_type * lux = r_luxury(r); - const item_type * itype = it_find(name); - if (lux && itype && lux!=itype) { - r_setdemand(r, lux->rtype->ltype, 1); - r_setdemand(r, itype->rtype->ltype, 0); - } - } - return 0; -} - -static int tolua_region_set_herb(lua_State* L) -{ - region* r = (region*)tolua_tousertype(L, 1, 0); - if (r->land) { - const char * name = tolua_tostring(L, 2, 0); - const item_type * itype = it_find(name); - if (itype && (itype->flags&ITF_HERB)) { - r->land->herbtype = itype; - } - } - return 0; -} - -static int tolua_region_get_herb(lua_State* L) -{ - region* r = (region*)tolua_tousertype(L, 1, 0); - if (r->land && r->land->herbtype) { - const char * name = r->land->herbtype->rtype->_name[0]; - tolua_pushstring(L, name); - return 1; - } - return 0; -} - -static int tolua_region_get_next(lua_State* L) -{ - region* self = (region*)tolua_tousertype(L, 1, 0); - direction_t dir = (direction_t)tolua_tonumber(L, 2, 0); - - if (dir>=0 && dirflags |= (1<flags &= ~(1<resources;rm;rm=rm->next) { - if (rm->type->rtype==rtype) { - tolua_pushnumber(L, (lua_Number)rm->level); - return 1; - } - } - } - return 0; -} - -#define LUA_ASSERT(c, s) if (!(c)) { log_error(("%s(%d): %s\n", __FILE__, __LINE__, (s))); return 0; } -static int -tolua_region_get_resource(lua_State* L) -{ - region * r; - const char * type; - const resource_type * rtype; - int result = 0; - - r = (region *)tolua_tousertype(L, 1, 0); - LUA_ASSERT(r!=NULL, "invalid parameter"); - type = tolua_tostring(L, 2, 0); - LUA_ASSERT(type!=NULL, "invalid parameter"); - rtype = rt_find(type); - - if (!rtype) { - if (strcmp(type, "seed")==0) result = rtrees(r, 0); - if (strcmp(type, "sapling")==0) result = rtrees(r, 1); - if (strcmp(type, "tree")==0) result = rtrees(r, 2); - if (strcmp(type, "grave")==0) result = deathcount(r); - if (strcmp(type, "chaos")==0) result = chaoscount(r); - } else { - result = region_getresource(r, rtype); - } - - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_region_set_resource(lua_State* L) -{ - region * r = (region *)tolua_tousertype(L, 1, 0); - const char * type = tolua_tostring(L, 2, 0); - int value = (int)tolua_tonumber(L, 3, 0); - const resource_type * rtype = rt_find(type); - - if (rtype!=NULL) { - region_setresource(r, rtype, value); - } else { - if (strcmp(type, "seed")==0) { - rsettrees(r, 0, value); - } else if (strcmp(type, "sapling")==0) { - rsettrees(r, 1, value); - } else if (strcmp(type, "tree")==0) { - rsettrees(r, 2, value); - } else if (strcmp(type, "grave")==0) { - int fallen = value-deathcount(r); - deathcounts(r, fallen); - } else if (strcmp(type, "chaos")==0) { - int fallen = value-chaoscount(r); - chaoscounts(r, fallen); - } - } - return 0; -} - -static int -tolua_region_get_objects(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); - return 1; -} - -static int -tolua_region_destroy(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - remove_region(®ions, self); - return 0; -} - -static int -tolua_region_create(lua_State* L) -{ - int x = (int)tolua_tonumber(L, 1, 0); - int y = (int)tolua_tonumber(L, 2, 0); - const char * tname = tolua_tostring(L, 3, 0); - if (tname) { - plane * pl = findplane(x, y); - const terrain_type * terrain = get_terrain(tname); - region * r, * result; - if (!terrain) { - return 0; - } - - assert(!pnormalize(&x, &y, pl)); - r = result = findregion(x, y); - - if (terrain==NULL && r!=NULL && r->units!=NULL) { - /* TODO: error message */ - result = NULL; - } else if (r==NULL) { - result = new_region(x, y, pl, 0); - } - if (result) { - terraform_region(result, terrain); - } - fix_demand(result); - - tolua_pushusertype(L, result, TOLUA_CAST "region"); - return 1; - } - return 0; -} - -static int tolua_region_get_units(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); - - luaL_getmetatable(L, "unit"); - lua_setmetatable(L, -2); - - *unit_ptr = self->units; - - lua_pushcclosure(L, tolua_unitlist_next, 1); - return 1; -} - -static int tolua_region_get_buildings(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - building ** building_ptr = (building**)lua_newuserdata(L, sizeof(building *)); - - luaL_getmetatable(L, "building"); - lua_setmetatable(L, -2); - - *building_ptr = self->buildings; - - lua_pushcclosure(L, tolua_buildinglist_next, 1); - return 1; -} - -static int tolua_region_get_ships(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - ship ** ship_ptr = (ship**)lua_newuserdata(L, sizeof(ship *)); - - luaL_getmetatable(L, "ship"); - lua_setmetatable(L, -2); - - *ship_ptr = self->ships; - - lua_pushcclosure(L, tolua_shiplist_next, 1); - return 1; -} - -static int tolua_region_get_age(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - - if (self) { - lua_pushnumber(L, self->age); - return 1; - } - return 0; -} - -static int -tolua_region_getkey(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - - int flag = atoi36(name); - attrib * a = find_key(self->attribs, flag); - lua_pushboolean(L, a!=NULL); - - return 1; -} - -static int -tolua_region_setkey(lua_State* L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - int value = tolua_toboolean(L, 3, 0); - - int flag = atoi36(name); - attrib * a = find_key(self->attribs, flag); - if (a==NULL && value) { - add_key(&self->attribs, flag); - } else if (a!=NULL && !value) { - a_remove(&self->attribs, a); - } - return 0; -} - -static int -tolua_region_tostring(lua_State *L) -{ - region * self = (region *)tolua_tousertype(L, 1, 0); - lua_pushstring(L, regionname(self, NULL)); - return 1; -} - -static int -tolua_plane_get(lua_State* L) -{ - int id = (int)tolua_tonumber(L, 1, 0); - plane * pl = getplanebyid(id); - - tolua_pushusertype(L, pl, TOLUA_CAST "plane"); - return 1; -} - -static int -tolua_plane_create(lua_State* L) -{ - int id = (int)tolua_tonumber(L, 1, 0); - int x = (int)tolua_tonumber(L, 2, 0); - int y = (int)tolua_tonumber(L, 3, 0); - int width = (int)tolua_tonumber(L, 4, 0); - int height = (int)tolua_tonumber(L, 5, 0); - const char * name = tolua_tostring(L, 6, 0); - plane * pl; - - pl = create_new_plane(id, name, x, x+width-1, y, y+height-1, 0); - - tolua_pushusertype(L, pl, TOLUA_CAST "plane"); - return 1; -} - -static int tolua_plane_get_name(lua_State* L) -{ - plane* self = (plane*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->name); - return 1; -} - -static int tolua_plane_set_name(lua_State* L) -{ - plane* self = (plane*)tolua_tousertype(L, 1, 0); - const char * str = tolua_tostring(L, 2, 0); - free(self->name); - if (str) self->name = strdup(str); - else self->name = 0; - return 0; -} - -static int -tolua_plane_get_id(lua_State* L) -{ - plane * self = (plane *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->id); - return 1; -} - -static int -tolua_plane_normalize(lua_State* L) -{ - plane * self = (plane *)tolua_tousertype(L, 1, 0); - int x = (int)tolua_tonumber(L, 2, 0); - int y = (int)tolua_tonumber(L, 3, 0); - pnormalize(&x, &y, self); - tolua_pushnumber(L, (lua_Number)x); - tolua_pushnumber(L, (lua_Number)y); - return 2; -} - -static int -tolua_plane_tostring(lua_State *L) -{ - plane * self = (plane *)tolua_tousertype(L, 1, 0); - lua_pushstring(L, self->name); - return 1; -} - -static int -tolua_plane_get_size(lua_State *L) -{ - plane * pl = (plane *)tolua_tousertype(L, 1, 0); - lua_pushnumber(L, plane_width(pl)); - lua_pushnumber(L, plane_height(pl)); - return 2; -} - -static int -tolua_distance(lua_State *L) -{ - int x1 = (int)tolua_tonumber(L, 1, 0); - int y1 = (int)tolua_tonumber(L, 2, 0); - int x2 = (int)tolua_tonumber(L, 3, 0); - int y2 = (int)tolua_tonumber(L, 4, 0); - plane * pl = (plane *)tolua_tousertype(L, 5, 0); - int result; - - if (!pl) pl = get_homeplane(); - pnormalize(&x1, &y1, pl); - pnormalize(&x2, &y2, pl); - result = koor_distance(x1, y1, x2, y2); - lua_pushnumber(L, result); - return 1; -} - -void -tolua_region_open(lua_State* L) -{ - /* register user types */ - tolua_usertype(L, TOLUA_CAST "region"); - tolua_usertype(L, TOLUA_CAST "plane"); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_function(L, TOLUA_CAST "distance", tolua_distance); - - tolua_cclass(L, TOLUA_CAST "region", TOLUA_CAST "region", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "region"); - { - tolua_function(L, TOLUA_CAST "create", tolua_region_create); - tolua_function(L, TOLUA_CAST "destroy", tolua_region_destroy); - tolua_function(L, TOLUA_CAST "__tostring", tolua_region_tostring); - - tolua_variable(L, TOLUA_CAST "id", tolua_region_get_id, NULL); - tolua_variable(L, TOLUA_CAST "x", tolua_region_get_x, NULL); - tolua_variable(L, TOLUA_CAST "y", tolua_region_get_y, NULL); - tolua_variable(L, TOLUA_CAST "plane", tolua_region_get_plane, NULL); - tolua_variable(L, TOLUA_CAST "name", tolua_region_get_name, tolua_region_set_name); - tolua_variable(L, TOLUA_CAST "morale", tolua_region_get_morale, tolua_region_set_morale); - tolua_variable(L, TOLUA_CAST "info", tolua_region_get_info, tolua_region_set_info); - tolua_variable(L, TOLUA_CAST "units", tolua_region_get_units, NULL); - tolua_variable(L, TOLUA_CAST "ships", tolua_region_get_ships, NULL); - tolua_variable(L, TOLUA_CAST "age", tolua_region_get_age, NULL); - tolua_variable(L, TOLUA_CAST "buildings", tolua_region_get_buildings, NULL); - tolua_variable(L, TOLUA_CAST "terrain", tolua_region_get_terrain, tolua_region_set_terrain); - tolua_function(L, TOLUA_CAST "get_resourcelevel", tolua_region_get_resourcelevel); - tolua_function(L, TOLUA_CAST "get_resource", tolua_region_get_resource); - tolua_function(L, TOLUA_CAST "set_resource", tolua_region_set_resource); - tolua_function(L, TOLUA_CAST "get_flag", tolua_region_get_flag); - tolua_function(L, TOLUA_CAST "set_flag", tolua_region_set_flag); - tolua_function(L, TOLUA_CAST "next", tolua_region_get_next); - tolua_variable(L, TOLUA_CAST "adj", tolua_region_get_adj, NULL); - - tolua_variable(L, TOLUA_CAST "luxury", &tolua_region_get_luxury, &tolua_region_set_luxury); - tolua_variable(L, TOLUA_CAST "herb", &tolua_region_get_herb, &tolua_region_set_herb); - - tolua_variable(L, TOLUA_CAST "terrain_name", &tolua_region_get_terrainname, &tolua_region_set_terrainname); - tolua_variable(L, TOLUA_CAST "owner", &tolua_region_get_owner, &tolua_region_set_owner); - - tolua_function(L, TOLUA_CAST "get_key", tolua_region_getkey); - tolua_function(L, TOLUA_CAST "set_key", tolua_region_setkey); -#if 0 - .def("add_notice", ®ion_addnotice) - .def("add_direction", ®ion_adddirection) - .def("move", ®ion_move) - .def("get_road", ®ion_getroad) - .def("set_road", ®ion_setroad) - .def("next", ®ion_next) - .def("add_item", ®ion_additem) - .property("items", ®ion_items, return_stl_iterator) - .property("plane_id", ®ion_plane) -#endif - tolua_variable(L, TOLUA_CAST "objects", tolua_region_get_objects, 0); - } - tolua_endmodule(L); - - tolua_cclass(L, TOLUA_CAST "plane", TOLUA_CAST "plane", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "plane"); - { - tolua_function(L, TOLUA_CAST "create", tolua_plane_create); - tolua_function(L, TOLUA_CAST "get", tolua_plane_get); - tolua_function(L, TOLUA_CAST "__tostring", tolua_plane_tostring); - - tolua_function(L, TOLUA_CAST "size", tolua_plane_get_size); - tolua_variable(L, TOLUA_CAST "id", tolua_plane_get_id, NULL); - tolua_function(L, TOLUA_CAST "normalize", tolua_plane_normalize); - tolua_variable(L, TOLUA_CAST "name", tolua_plane_get_name, tolua_plane_set_name); - } - tolua_endmodule(L); - } - tolua_endmodule(L); -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bind_region.h" +#include "bind_unit.h" +#include "bind_ship.h" +#include "bind_building.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +int tolua_regionlist_next(lua_State *L) +{ + region** region_ptr = (region **)lua_touserdata(L, lua_upvalueindex(1)); + region * r = *region_ptr; + if (r != NULL) { + tolua_pushusertype(L, (void*)r, TOLUA_CAST "region"); + *region_ptr = r->next; + return 1; + } + else return 0; /* no more values to return */ +} + +static int +tolua_region_get_id(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->uid); + return 1; +} + +static int +tolua_region_get_x(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->x); + return 1; +} + +static int +tolua_region_get_y(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->y); + return 1; +} + +static int +tolua_region_get_plane(lua_State* L) +{ + region * r = (region *)tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, rplane(r), TOLUA_CAST "plane"); + return 1; +} + +static int +tolua_region_get_terrain(lua_State* L) +{ + region* self = (region*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->terrain->_name); + return 1; +} + +static int +tolua_region_set_terrain(lua_State* L) +{ + region* r = (region*) tolua_tousertype(L, 1, 0); + const char * tname = tolua_tostring(L, 2, 0); + if (tname) { + const terrain_type * terrain = get_terrain(tname); + if (terrain) { + terraform_region(r, terrain); + } + } + return 0; +} + +static int +tolua_region_get_terrainname(lua_State* L) +{ + region* self = (region*) tolua_tousertype(L, 1, 0); + attrib * a = a_find(self->attribs, &at_racename); + if (a) { + tolua_pushstring(L, get_racename(a)); + return 1; + } + return 0; +} + +static int +tolua_region_set_owner(lua_State* L) +{ + region* r = (region*) tolua_tousertype(L, 1, 0); + struct faction* f = (struct faction*) tolua_tousertype(L, 2, 0); + if (r) { + region_set_owner(r, f, turn); + } + return 0; +} + +static int +tolua_region_get_owner(lua_State* L) +{ + region* r = (region*) tolua_tousertype(L, 1, 0); + if (r) { + struct faction * f = region_get_owner(r); + tolua_pushusertype(L, f, TOLUA_CAST "faction"); + return 1; + } + return 0; +} + +static int +tolua_region_set_terrainname(lua_State* L) +{ + region* self = (region*) tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + if (name==NULL) { + a_removeall(&self->attribs, &at_racename); + } else { + set_racename(&self->attribs, name); + } + return 0; +} + +static int tolua_region_get_info(lua_State* L) +{ + region* self = (region*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, region_getinfo(self)); + return 1; +} + +static int tolua_region_set_info(lua_State* L) +{ + region* self = (region*)tolua_tousertype(L, 1, 0); + region_setinfo(self, tolua_tostring(L, 2, 0)); + return 0; +} + + +static int tolua_region_get_name(lua_State* L) +{ + region* self = (region*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, region_getname(self)); + return 1; +} + +static int tolua_region_set_name(lua_State* L) +{ + region* self = (region*)tolua_tousertype(L, 1, 0); + region_setname(self, tolua_tostring(L, 2, 0)); + return 0; +} + + +static int tolua_region_get_morale(lua_State* L) +{ + region* r = (region*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, region_get_morale(r)); + return 1; +} + +static int tolua_region_set_morale(lua_State* L) +{ + region* r = (region*)tolua_tousertype(L, 1, 0); + region_set_morale(r, (int)tolua_tonumber(L, 2, 0), turn); + return 0; +} + +static int tolua_region_get_flag(lua_State* L) +{ + region* self = (region*)tolua_tousertype(L, 1, 0); + int bit = (int)tolua_tonumber(L, 2, 0); + + lua_pushboolean(L, (self->flags & (1<land) { + const item_type * lux = r_luxury(r); + if (lux) { + const char * name = lux->rtype->_name[0]; + tolua_pushstring(L, name); + return 1; + } + } + return 0; +} + +static int tolua_region_set_luxury(lua_State* L) +{ + region* r = (region*)tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + if (r->land && name) { + const item_type * lux = r_luxury(r); + const item_type * itype = it_find(name); + if (lux && itype && lux!=itype) { + r_setdemand(r, lux->rtype->ltype, 1); + r_setdemand(r, itype->rtype->ltype, 0); + } + } + return 0; +} + +static int tolua_region_set_herb(lua_State* L) +{ + region* r = (region*)tolua_tousertype(L, 1, 0); + if (r->land) { + const char * name = tolua_tostring(L, 2, 0); + const item_type * itype = it_find(name); + if (itype && (itype->flags&ITF_HERB)) { + r->land->herbtype = itype; + } + } + return 0; +} + +static int tolua_region_get_herb(lua_State* L) +{ + region* r = (region*)tolua_tousertype(L, 1, 0); + if (r->land && r->land->herbtype) { + const char * name = r->land->herbtype->rtype->_name[0]; + tolua_pushstring(L, name); + return 1; + } + return 0; +} + +static int tolua_region_get_next(lua_State* L) +{ + region* self = (region*)tolua_tousertype(L, 1, 0); + direction_t dir = (direction_t)tolua_tonumber(L, 2, 0); + + if (dir>=0 && dirflags |= (1<flags &= ~(1<resources;rm;rm=rm->next) { + if (rm->type->rtype==rtype) { + tolua_pushnumber(L, (lua_Number)rm->level); + return 1; + } + } + } + return 0; +} + +#define LUA_ASSERT(c, s) if (!(c)) { log_error(("%s(%d): %s\n", __FILE__, __LINE__, (s))); return 0; } +static int +tolua_region_get_resource(lua_State* L) +{ + region * r; + const char * type; + const resource_type * rtype; + int result = 0; + + r = (region *)tolua_tousertype(L, 1, 0); + LUA_ASSERT(r!=NULL, "invalid parameter"); + type = tolua_tostring(L, 2, 0); + LUA_ASSERT(type!=NULL, "invalid parameter"); + rtype = rt_find(type); + + if (!rtype) { + if (strcmp(type, "seed")==0) result = rtrees(r, 0); + if (strcmp(type, "sapling")==0) result = rtrees(r, 1); + if (strcmp(type, "tree")==0) result = rtrees(r, 2); + if (strcmp(type, "grave")==0) result = deathcount(r); + if (strcmp(type, "chaos")==0) result = chaoscount(r); + } else { + result = region_getresource(r, rtype); + } + + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_region_set_resource(lua_State* L) +{ + region * r = (region *)tolua_tousertype(L, 1, 0); + const char * type = tolua_tostring(L, 2, 0); + int value = (int)tolua_tonumber(L, 3, 0); + const resource_type * rtype = rt_find(type); + + if (rtype!=NULL) { + region_setresource(r, rtype, value); + } else { + if (strcmp(type, "seed")==0) { + rsettrees(r, 0, value); + } else if (strcmp(type, "sapling")==0) { + rsettrees(r, 1, value); + } else if (strcmp(type, "tree")==0) { + rsettrees(r, 2, value); + } else if (strcmp(type, "grave")==0) { + int fallen = value-deathcount(r); + deathcounts(r, fallen); + } else if (strcmp(type, "chaos")==0) { + int fallen = value-chaoscount(r); + chaoscounts(r, fallen); + } + } + return 0; +} + +static int +tolua_region_get_objects(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); + return 1; +} + +static int +tolua_region_destroy(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + remove_region(®ions, self); + return 0; +} + +static int +tolua_region_create(lua_State* L) +{ + int x = (int)tolua_tonumber(L, 1, 0); + int y = (int)tolua_tonumber(L, 2, 0); + const char * tname = tolua_tostring(L, 3, 0); + if (tname) { + plane * pl = findplane(x, y); + const terrain_type * terrain = get_terrain(tname); + region * r, * result; + if (!terrain) { + return 0; + } + + assert(!pnormalize(&x, &y, pl)); + r = result = findregion(x, y); + + if (terrain==NULL && r!=NULL && r->units!=NULL) { + /* TODO: error message */ + result = NULL; + } else if (r==NULL) { + result = new_region(x, y, pl, 0); + } + if (result) { + terraform_region(result, terrain); + } + fix_demand(result); + + tolua_pushusertype(L, result, TOLUA_CAST "region"); + return 1; + } + return 0; +} + +static int tolua_region_get_units(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); + + luaL_getmetatable(L, "unit"); + lua_setmetatable(L, -2); + + *unit_ptr = self->units; + + lua_pushcclosure(L, tolua_unitlist_next, 1); + return 1; +} + +static int tolua_region_get_buildings(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + building ** building_ptr = (building**)lua_newuserdata(L, sizeof(building *)); + + luaL_getmetatable(L, "building"); + lua_setmetatable(L, -2); + + *building_ptr = self->buildings; + + lua_pushcclosure(L, tolua_buildinglist_next, 1); + return 1; +} + +static int tolua_region_get_ships(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + ship ** ship_ptr = (ship**)lua_newuserdata(L, sizeof(ship *)); + + luaL_getmetatable(L, "ship"); + lua_setmetatable(L, -2); + + *ship_ptr = self->ships; + + lua_pushcclosure(L, tolua_shiplist_next, 1); + return 1; +} + +static int tolua_region_get_age(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + + if (self) { + lua_pushnumber(L, self->age); + return 1; + } + return 0; +} + +static int +tolua_region_getkey(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + + int flag = atoi36(name); + attrib * a = find_key(self->attribs, flag); + lua_pushboolean(L, a!=NULL); + + return 1; +} + +static int +tolua_region_setkey(lua_State* L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + int value = tolua_toboolean(L, 3, 0); + + int flag = atoi36(name); + attrib * a = find_key(self->attribs, flag); + if (a==NULL && value) { + add_key(&self->attribs, flag); + } else if (a!=NULL && !value) { + a_remove(&self->attribs, a); + } + return 0; +} + +static int +tolua_region_tostring(lua_State *L) +{ + region * self = (region *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, regionname(self, NULL)); + return 1; +} + +static int +tolua_plane_get(lua_State* L) +{ + int id = (int)tolua_tonumber(L, 1, 0); + plane * pl = getplanebyid(id); + + tolua_pushusertype(L, pl, TOLUA_CAST "plane"); + return 1; +} + +static int +tolua_plane_create(lua_State* L) +{ + int id = (int)tolua_tonumber(L, 1, 0); + int x = (int)tolua_tonumber(L, 2, 0); + int y = (int)tolua_tonumber(L, 3, 0); + int width = (int)tolua_tonumber(L, 4, 0); + int height = (int)tolua_tonumber(L, 5, 0); + const char * name = tolua_tostring(L, 6, 0); + plane * pl; + + pl = create_new_plane(id, name, x, x+width-1, y, y+height-1, 0); + + tolua_pushusertype(L, pl, TOLUA_CAST "plane"); + return 1; +} + +static int tolua_plane_get_name(lua_State* L) +{ + plane* self = (plane*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->name); + return 1; +} + +static int tolua_plane_set_name(lua_State* L) +{ + plane* self = (plane*)tolua_tousertype(L, 1, 0); + const char * str = tolua_tostring(L, 2, 0); + free(self->name); + if (str) self->name = strdup(str); + else self->name = 0; + return 0; +} + +static int +tolua_plane_get_id(lua_State* L) +{ + plane * self = (plane *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->id); + return 1; +} + +static int +tolua_plane_normalize(lua_State* L) +{ + plane * self = (plane *)tolua_tousertype(L, 1, 0); + int x = (int)tolua_tonumber(L, 2, 0); + int y = (int)tolua_tonumber(L, 3, 0); + pnormalize(&x, &y, self); + tolua_pushnumber(L, (lua_Number)x); + tolua_pushnumber(L, (lua_Number)y); + return 2; +} + +static int +tolua_plane_tostring(lua_State *L) +{ + plane * self = (plane *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, self->name); + return 1; +} + +static int +tolua_plane_get_size(lua_State *L) +{ + plane * pl = (plane *)tolua_tousertype(L, 1, 0); + lua_pushnumber(L, plane_width(pl)); + lua_pushnumber(L, plane_height(pl)); + return 2; +} + +static int +tolua_distance(lua_State *L) +{ + int x1 = (int)tolua_tonumber(L, 1, 0); + int y1 = (int)tolua_tonumber(L, 2, 0); + int x2 = (int)tolua_tonumber(L, 3, 0); + int y2 = (int)tolua_tonumber(L, 4, 0); + plane * pl = (plane *)tolua_tousertype(L, 5, 0); + int result; + + if (!pl) pl = get_homeplane(); + pnormalize(&x1, &y1, pl); + pnormalize(&x2, &y2, pl); + result = koor_distance(x1, y1, x2, y2); + lua_pushnumber(L, result); + return 1; +} + +void +tolua_region_open(lua_State* L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "region"); + tolua_usertype(L, TOLUA_CAST "plane"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_function(L, TOLUA_CAST "distance", tolua_distance); + + tolua_cclass(L, TOLUA_CAST "region", TOLUA_CAST "region", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "region"); + { + tolua_function(L, TOLUA_CAST "create", tolua_region_create); + tolua_function(L, TOLUA_CAST "destroy", tolua_region_destroy); + tolua_function(L, TOLUA_CAST "__tostring", tolua_region_tostring); + + tolua_variable(L, TOLUA_CAST "id", tolua_region_get_id, NULL); + tolua_variable(L, TOLUA_CAST "x", tolua_region_get_x, NULL); + tolua_variable(L, TOLUA_CAST "y", tolua_region_get_y, NULL); + tolua_variable(L, TOLUA_CAST "plane", tolua_region_get_plane, NULL); + tolua_variable(L, TOLUA_CAST "name", tolua_region_get_name, tolua_region_set_name); + tolua_variable(L, TOLUA_CAST "morale", tolua_region_get_morale, tolua_region_set_morale); + tolua_variable(L, TOLUA_CAST "info", tolua_region_get_info, tolua_region_set_info); + tolua_variable(L, TOLUA_CAST "units", tolua_region_get_units, NULL); + tolua_variable(L, TOLUA_CAST "ships", tolua_region_get_ships, NULL); + tolua_variable(L, TOLUA_CAST "age", tolua_region_get_age, NULL); + tolua_variable(L, TOLUA_CAST "buildings", tolua_region_get_buildings, NULL); + tolua_variable(L, TOLUA_CAST "terrain", tolua_region_get_terrain, tolua_region_set_terrain); + tolua_function(L, TOLUA_CAST "get_resourcelevel", tolua_region_get_resourcelevel); + tolua_function(L, TOLUA_CAST "get_resource", tolua_region_get_resource); + tolua_function(L, TOLUA_CAST "set_resource", tolua_region_set_resource); + tolua_function(L, TOLUA_CAST "get_flag", tolua_region_get_flag); + tolua_function(L, TOLUA_CAST "set_flag", tolua_region_set_flag); + tolua_function(L, TOLUA_CAST "next", tolua_region_get_next); + tolua_variable(L, TOLUA_CAST "adj", tolua_region_get_adj, NULL); + + tolua_variable(L, TOLUA_CAST "luxury", &tolua_region_get_luxury, &tolua_region_set_luxury); + tolua_variable(L, TOLUA_CAST "herb", &tolua_region_get_herb, &tolua_region_set_herb); + + tolua_variable(L, TOLUA_CAST "terrain_name", &tolua_region_get_terrainname, &tolua_region_set_terrainname); + tolua_variable(L, TOLUA_CAST "owner", &tolua_region_get_owner, &tolua_region_set_owner); + + tolua_function(L, TOLUA_CAST "get_key", tolua_region_getkey); + tolua_function(L, TOLUA_CAST "set_key", tolua_region_setkey); +#if 0 + .def("add_notice", ®ion_addnotice) + .def("add_direction", ®ion_adddirection) + .def("move", ®ion_move) + .def("get_road", ®ion_getroad) + .def("set_road", ®ion_setroad) + .def("next", ®ion_next) + .def("add_item", ®ion_additem) + .property("items", ®ion_items, return_stl_iterator) + .property("plane_id", ®ion_plane) +#endif + tolua_variable(L, TOLUA_CAST "objects", tolua_region_get_objects, 0); + } + tolua_endmodule(L); + + tolua_cclass(L, TOLUA_CAST "plane", TOLUA_CAST "plane", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "plane"); + { + tolua_function(L, TOLUA_CAST "create", tolua_plane_create); + tolua_function(L, TOLUA_CAST "get", tolua_plane_get); + tolua_function(L, TOLUA_CAST "__tostring", tolua_plane_tostring); + + tolua_function(L, TOLUA_CAST "size", tolua_plane_get_size); + tolua_variable(L, TOLUA_CAST "id", tolua_plane_get_id, NULL); + tolua_function(L, TOLUA_CAST "normalize", tolua_plane_normalize); + tolua_variable(L, TOLUA_CAST "name", tolua_plane_get_name, tolua_plane_set_name); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_region.h b/src/bindings/bind_region.h index 002411e51..f8d0c8e2a 100644 --- a/src/bindings/bind_region.h +++ b/src/bindings/bind_region.h @@ -1,23 +1,23 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - void tolua_region_open(struct lua_State *L); - int tolua_regionlist_next(struct lua_State *L); - -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + void tolua_region_open(struct lua_State *L); + int tolua_regionlist_next(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_ship.c b/src/bindings/bind_ship.c index 053718091..b5a0e90a3 100644 --- a/src/bindings/bind_ship.c +++ b/src/bindings/bind_ship.c @@ -1,182 +1,182 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include "bind_ship.h" -#include "bind_unit.h" - -#include -#include -#include -#include -#include - -#include - -#include -#include - -int tolua_shiplist_next(lua_State *L) -{ - ship** ship_ptr = (ship **)lua_touserdata(L, lua_upvalueindex(1)); - ship * u = *ship_ptr; - if (u != NULL) { - tolua_pushusertype(L, (void*)u, TOLUA_CAST "ship"); - *ship_ptr = u->next; - return 1; - } - else return 0; /* no more values to return */ -} - -static int -tolua_ship_get_id(lua_State* L) -{ - ship * self = (ship *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->no); - return 1; -} - -static int tolua_ship_get_name(lua_State* L) -{ - ship* self = (ship*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, ship_getname(self)); - return 1; -} - -static int tolua_ship_get_region(lua_State* L) -{ - ship* self = (ship*) tolua_tousertype(L, 1, 0); - if (self) { - tolua_pushusertype(L, self->region, TOLUA_CAST "region"); - return 1; - } - return 0; -} - -static int tolua_ship_set_region(lua_State* L) -{ - ship* self = (ship*) tolua_tousertype(L, 1, 0); - region * r = (region*) tolua_tousertype(L, 1, 0); - if (self) { - move_ship(self, self->region, r, NULL); - } - return 0; -} - -static int tolua_ship_set_name(lua_State* L) -{ - ship* self = (ship*)tolua_tousertype(L, 1, 0); - ship_setname(self, tolua_tostring(L, 2, 0)); - return 0; -} - -static int -tolua_ship_get_units(lua_State* L) -{ - ship * self = (ship *)tolua_tousertype(L, 1, 0); - unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); - unit * u = self->region->units; - - while (u && u->ship!=self) u = u->next; - luaL_getmetatable(L, TOLUA_CAST "unit"); - lua_setmetatable(L, -2); - - *unit_ptr = u; - - lua_pushcclosure(L, tolua_unitlist_nexts, 1); - return 1; -} - -static int -tolua_ship_get_objects(lua_State* L) -{ - ship * self = (ship *)tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); - return 1; -} - -static int -tolua_ship_create(lua_State* L) -{ - region * r = (region *)tolua_tousertype(L, 1, 0); - const char * sname = tolua_tostring(L, 2, 0); - if (sname) { - const ship_type * stype = st_find(sname); - if (stype) { - ship * sh = new_ship(stype, default_locale, r); - sh->size = stype->construction->maxsize; - tolua_pushusertype(L, (void*)sh, TOLUA_CAST "ship"); - return 1; - } - } - return 0; -} - -static int - -tolua_ship_tostring(lua_State *L) -{ - ship * self = (ship *)tolua_tousertype(L, 1, 0); - lua_pushstring(L, shipname(self)); - return 1; -} - -static int tolua_ship_get_flags(lua_State* L) -{ - ship* self = (ship*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->flags); - return 1; -} - -static int tolua_ship_set_flags(lua_State* L) -{ - ship* self = (ship*)tolua_tousertype(L, 1, 0); - self->flags = (int)tolua_tonumber(L, 2, 0); - return 0; -} - - -void -tolua_ship_open(lua_State* L) -{ - /* register user types */ - tolua_usertype(L, TOLUA_CAST "ship"); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_cclass(L, TOLUA_CAST "ship", TOLUA_CAST "ship", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "ship"); - { - tolua_function(L, TOLUA_CAST "__tostring", tolua_ship_tostring); - tolua_variable(L, TOLUA_CAST "id", tolua_ship_get_id, NULL); - tolua_variable(L, TOLUA_CAST "name", tolua_ship_get_name, tolua_ship_set_name); - tolua_variable(L, TOLUA_CAST "units", tolua_ship_get_units, NULL); - tolua_variable(L, TOLUA_CAST "flags", &tolua_ship_get_flags, tolua_ship_set_flags); - tolua_variable(L, TOLUA_CAST "region", tolua_ship_get_region, tolua_ship_set_region); -#ifdef TODO - .property("type", &ship_gettype) - .property("weight", &ship_getweight) - .property("capacity", &ship_getcapacity) - .property("maxsize", &ship_maxsize) - .def_readwrite("damage", &ship::damage) - .def_readwrite("size", &ship::size) - .def_readwrite("coast", &ship::coast) -#endif - tolua_variable(L, TOLUA_CAST "objects", tolua_ship_get_objects, 0); - - tolua_function(L, TOLUA_CAST "create", tolua_ship_create); - } - tolua_endmodule(L); - } - tolua_endmodule(L); -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bind_ship.h" +#include "bind_unit.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include + +int tolua_shiplist_next(lua_State *L) +{ + ship** ship_ptr = (ship **)lua_touserdata(L, lua_upvalueindex(1)); + ship * u = *ship_ptr; + if (u != NULL) { + tolua_pushusertype(L, (void*)u, TOLUA_CAST "ship"); + *ship_ptr = u->next; + return 1; + } + else return 0; /* no more values to return */ +} + +static int +tolua_ship_get_id(lua_State* L) +{ + ship * self = (ship *)tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->no); + return 1; +} + +static int tolua_ship_get_name(lua_State* L) +{ + ship* self = (ship*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, ship_getname(self)); + return 1; +} + +static int tolua_ship_get_region(lua_State* L) +{ + ship* self = (ship*) tolua_tousertype(L, 1, 0); + if (self) { + tolua_pushusertype(L, self->region, TOLUA_CAST "region"); + return 1; + } + return 0; +} + +static int tolua_ship_set_region(lua_State* L) +{ + ship* self = (ship*) tolua_tousertype(L, 1, 0); + region * r = (region*) tolua_tousertype(L, 1, 0); + if (self) { + move_ship(self, self->region, r, NULL); + } + return 0; +} + +static int tolua_ship_set_name(lua_State* L) +{ + ship* self = (ship*)tolua_tousertype(L, 1, 0); + ship_setname(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int +tolua_ship_get_units(lua_State* L) +{ + ship * self = (ship *)tolua_tousertype(L, 1, 0); + unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); + unit * u = self->region->units; + + while (u && u->ship!=self) u = u->next; + luaL_getmetatable(L, TOLUA_CAST "unit"); + lua_setmetatable(L, -2); + + *unit_ptr = u; + + lua_pushcclosure(L, tolua_unitlist_nexts, 1); + return 1; +} + +static int +tolua_ship_get_objects(lua_State* L) +{ + ship * self = (ship *)tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); + return 1; +} + +static int +tolua_ship_create(lua_State* L) +{ + region * r = (region *)tolua_tousertype(L, 1, 0); + const char * sname = tolua_tostring(L, 2, 0); + if (sname) { + const ship_type * stype = st_find(sname); + if (stype) { + ship * sh = new_ship(stype, default_locale, r); + sh->size = stype->construction->maxsize; + tolua_pushusertype(L, (void*)sh, TOLUA_CAST "ship"); + return 1; + } + } + return 0; +} + +static int + +tolua_ship_tostring(lua_State *L) +{ + ship * self = (ship *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, shipname(self)); + return 1; +} + +static int tolua_ship_get_flags(lua_State* L) +{ + ship* self = (ship*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->flags); + return 1; +} + +static int tolua_ship_set_flags(lua_State* L) +{ + ship* self = (ship*)tolua_tousertype(L, 1, 0); + self->flags = (int)tolua_tonumber(L, 2, 0); + return 0; +} + + +void +tolua_ship_open(lua_State* L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "ship"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, TOLUA_CAST "ship", TOLUA_CAST "ship", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "ship"); + { + tolua_function(L, TOLUA_CAST "__tostring", tolua_ship_tostring); + tolua_variable(L, TOLUA_CAST "id", tolua_ship_get_id, NULL); + tolua_variable(L, TOLUA_CAST "name", tolua_ship_get_name, tolua_ship_set_name); + tolua_variable(L, TOLUA_CAST "units", tolua_ship_get_units, NULL); + tolua_variable(L, TOLUA_CAST "flags", &tolua_ship_get_flags, tolua_ship_set_flags); + tolua_variable(L, TOLUA_CAST "region", tolua_ship_get_region, tolua_ship_set_region); +#ifdef TODO + .property("type", &ship_gettype) + .property("weight", &ship_getweight) + .property("capacity", &ship_getcapacity) + .property("maxsize", &ship_maxsize) + .def_readwrite("damage", &ship::damage) + .def_readwrite("size", &ship::size) + .def_readwrite("coast", &ship::coast) +#endif + tolua_variable(L, TOLUA_CAST "objects", tolua_ship_get_objects, 0); + + tolua_function(L, TOLUA_CAST "create", tolua_ship_create); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_ship.h b/src/bindings/bind_ship.h index a3daf5436..7c9426fce 100644 --- a/src/bindings/bind_ship.h +++ b/src/bindings/bind_ship.h @@ -1,23 +1,23 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - int tolua_shiplist_next(struct lua_State *L); - void tolua_ship_open(struct lua_State *L); - -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + int tolua_shiplist_next(struct lua_State *L); + void tolua_ship_open(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_sqlite.c b/src/bindings/bind_sqlite.c index a35e5723a..ce7f1aed4 100644 --- a/src/bindings/bind_sqlite.c +++ b/src/bindings/bind_sqlite.c @@ -1,100 +1,100 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include - -#include "bind_unit.h" -#include "bindings.h" - -#include -#include -#include - -#define LTYPE_DB TOLUA_CAST "db" - -extern int db_update_factions(sqlite3 * db, boolean force); -static int -tolua_db_update_factions(lua_State* L) -{ - sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); - db_update_factions(db, tolua_toboolean(L, 2, 0)); - return 0; -} - -extern int db_update_scores(sqlite3 * db, boolean force); -static int -tolua_db_update_scores(lua_State* L) -{ - sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); - db_update_scores(db, tolua_toboolean(L, 2, 0)); - return 0; -} - -static int -tolua_db_execute(lua_State* L) -{ - sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); - const char * sql = tolua_tostring(L, 2, 0); - - int res = sqlite3_exec(db, sql, 0, 0, 0); - - tolua_pushnumber(L, (LUA_NUMBER)res); - return 1; -} - -static int -tolua_db_close(lua_State* L) -{ - sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); - sqlite3_close(db); - return 0; -} - -static int -tolua_db_create(lua_State* L) -{ - sqlite3 * db; - const char * dbname = tolua_tostring(L, 1, 0); - int result = sqlite3_open_v2(dbname, &db, SQLITE_OPEN_READWRITE, 0); - if (result==SQLITE_OK) { - tolua_pushusertype(L, (void*)db, LTYPE_DB); - return 1; - } - return 0; -} - -int -tolua_sqlite_open(lua_State * L) -{ - /* register user types */ - - tolua_usertype(L, LTYPE_DB); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_cclass(L, LTYPE_DB, LTYPE_DB, TOLUA_CAST "", NULL); - tolua_beginmodule(L, LTYPE_DB); - { - tolua_function(L, TOLUA_CAST "open", &tolua_db_create); - tolua_function(L, TOLUA_CAST "close", &tolua_db_close); - - tolua_function(L, TOLUA_CAST "update_factions", &tolua_db_update_factions); - tolua_function(L, TOLUA_CAST "update_scores", &tolua_db_update_scores); - tolua_function(L, TOLUA_CAST "execute", &tolua_db_execute); - } - tolua_endmodule(L); - - } - tolua_endmodule(L); - return 0; -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include + +#include "bind_unit.h" +#include "bindings.h" + +#include +#include +#include + +#define LTYPE_DB TOLUA_CAST "db" + +extern int db_update_factions(sqlite3 * db, boolean force); +static int +tolua_db_update_factions(lua_State* L) +{ + sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); + db_update_factions(db, tolua_toboolean(L, 2, 0)); + return 0; +} + +extern int db_update_scores(sqlite3 * db, boolean force); +static int +tolua_db_update_scores(lua_State* L) +{ + sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); + db_update_scores(db, tolua_toboolean(L, 2, 0)); + return 0; +} + +static int +tolua_db_execute(lua_State* L) +{ + sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); + const char * sql = tolua_tostring(L, 2, 0); + + int res = sqlite3_exec(db, sql, 0, 0, 0); + + tolua_pushnumber(L, (LUA_NUMBER)res); + return 1; +} + +static int +tolua_db_close(lua_State* L) +{ + sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); + sqlite3_close(db); + return 0; +} + +static int +tolua_db_create(lua_State* L) +{ + sqlite3 * db; + const char * dbname = tolua_tostring(L, 1, 0); + int result = sqlite3_open_v2(dbname, &db, SQLITE_OPEN_READWRITE, 0); + if (result==SQLITE_OK) { + tolua_pushusertype(L, (void*)db, LTYPE_DB); + return 1; + } + return 0; +} + +int +tolua_sqlite_open(lua_State * L) +{ + /* register user types */ + + tolua_usertype(L, LTYPE_DB); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, LTYPE_DB, LTYPE_DB, TOLUA_CAST "", NULL); + tolua_beginmodule(L, LTYPE_DB); + { + tolua_function(L, TOLUA_CAST "open", &tolua_db_create); + tolua_function(L, TOLUA_CAST "close", &tolua_db_close); + + tolua_function(L, TOLUA_CAST "update_factions", &tolua_db_update_factions); + tolua_function(L, TOLUA_CAST "update_scores", &tolua_db_update_scores); + tolua_function(L, TOLUA_CAST "execute", &tolua_db_execute); + } + tolua_endmodule(L); + + } + tolua_endmodule(L); + return 0; +} diff --git a/src/bindings/bind_storage.c b/src/bindings/bind_storage.c index 2f5675cb5..23b9a0a5a 100644 --- a/src/bindings/bind_storage.c +++ b/src/bindings/bind_storage.c @@ -1,144 +1,144 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "bind_storage.h" - -#include -#include -#include -#include - -#include - -#include -#include - - -static int -tolua_storage_create(lua_State* L) -{ - const char * filename = tolua_tostring(L, 1, 0); - const char * type = tolua_tostring(L, 2, "rb"); - storage * store = 0; - int mode = IO_READ; - if (strchr(type, 't')) { - store = malloc(sizeof(text_store)); - memcpy(store, &text_store, sizeof(text_store)); - } else { - store = malloc(sizeof(binary_store)); - memcpy(store, &binary_store, sizeof(binary_store)); - } - if (strchr(type, 'r')) mode = IO_READ; - if (strchr(type, 'w')) mode = IO_WRITE; - store->open(store, filename, mode); - tolua_pushusertype(L, (void*)store, TOLUA_CAST "storage"); - return 1; -} - -static int -tolua_storage_read_unit(lua_State *L) -{ - storage * self = (storage *)tolua_tousertype(L, 1, 0); - struct unit * u = read_unit(self); - tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); - return 1; -} - -static int -tolua_storage_write_unit(lua_State *L) -{ - storage * self = (storage *)tolua_tousertype(L, 1, 0); - struct unit * u = (struct unit *)tolua_tousertype(L, 2, 0); - write_unit(self, u); - return 0; -} - - -static int -tolua_storage_read_float(lua_State *L) -{ - storage * self = (storage *)tolua_tousertype(L, 1, 0); - float num = self->r_flt(self); - tolua_pushnumber(L, (lua_Number)num); - return 1; -} - -static int -tolua_storage_read_int(lua_State *L) -{ - storage * self = (storage *)tolua_tousertype(L, 1, 0); - int num = self->r_int(self); - tolua_pushnumber(L, (lua_Number)num); - return 1; -} - -static int -tolua_storage_write(lua_State *L) -{ - storage * self = (storage *)tolua_tousertype(L, 1, 0); - if (tolua_isnumber(L, 2, 0, 0)) { - lua_Number num = tolua_tonumber(L, 2, 0); - double n; - if (modf(num, &n)==0.0) { - self->w_int(self, (int)num); - } else { - self->w_flt(self, (float)num); - } - } - return 0; -} - -static int -tolua_storage_tostring(lua_State *L) -{ - storage * self = (storage *)tolua_tousertype(L, 1, 0); - char name[64]; - snprintf(name, sizeof(name), "", self->encoding, self->version); - lua_pushstring(L, name); - return 1; -} - -static int -tolua_storage_close(lua_State *L) -{ - storage * self = (storage *)tolua_tousertype(L, 1, 0); - self->close(self); - return 0; -} - -void -tolua_storage_open(lua_State* L) -{ - /* register user types */ - tolua_usertype(L, TOLUA_CAST "storage"); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_cclass(L, TOLUA_CAST "storage", TOLUA_CAST "storage", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "storage"); - { - tolua_function(L, TOLUA_CAST "__tostring", tolua_storage_tostring); - tolua_function(L, TOLUA_CAST "write", tolua_storage_write); - tolua_function(L, TOLUA_CAST "read_int", tolua_storage_read_int); - tolua_function(L, TOLUA_CAST "read_float", tolua_storage_read_float); - tolua_function(L, TOLUA_CAST "write_unit", tolua_storage_write_unit); - tolua_function(L, TOLUA_CAST "read_unit", tolua_storage_read_unit); - tolua_function(L, TOLUA_CAST "close", tolua_storage_close); - tolua_function(L, TOLUA_CAST "create", tolua_storage_create); - } - tolua_endmodule(L); - } - tolua_endmodule(L); -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "bind_storage.h" + +#include +#include +#include +#include + +#include + +#include +#include + + +static int +tolua_storage_create(lua_State* L) +{ + const char * filename = tolua_tostring(L, 1, 0); + const char * type = tolua_tostring(L, 2, "rb"); + storage * store = 0; + int mode = IO_READ; + if (strchr(type, 't')) { + store = malloc(sizeof(text_store)); + memcpy(store, &text_store, sizeof(text_store)); + } else { + store = malloc(sizeof(binary_store)); + memcpy(store, &binary_store, sizeof(binary_store)); + } + if (strchr(type, 'r')) mode = IO_READ; + if (strchr(type, 'w')) mode = IO_WRITE; + store->open(store, filename, mode); + tolua_pushusertype(L, (void*)store, TOLUA_CAST "storage"); + return 1; +} + +static int +tolua_storage_read_unit(lua_State *L) +{ + storage * self = (storage *)tolua_tousertype(L, 1, 0); + struct unit * u = read_unit(self); + tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); + return 1; +} + +static int +tolua_storage_write_unit(lua_State *L) +{ + storage * self = (storage *)tolua_tousertype(L, 1, 0); + struct unit * u = (struct unit *)tolua_tousertype(L, 2, 0); + write_unit(self, u); + return 0; +} + + +static int +tolua_storage_read_float(lua_State *L) +{ + storage * self = (storage *)tolua_tousertype(L, 1, 0); + float num = self->r_flt(self); + tolua_pushnumber(L, (lua_Number)num); + return 1; +} + +static int +tolua_storage_read_int(lua_State *L) +{ + storage * self = (storage *)tolua_tousertype(L, 1, 0); + int num = self->r_int(self); + tolua_pushnumber(L, (lua_Number)num); + return 1; +} + +static int +tolua_storage_write(lua_State *L) +{ + storage * self = (storage *)tolua_tousertype(L, 1, 0); + if (tolua_isnumber(L, 2, 0, 0)) { + lua_Number num = tolua_tonumber(L, 2, 0); + double n; + if (modf(num, &n)==0.0) { + self->w_int(self, (int)num); + } else { + self->w_flt(self, (float)num); + } + } + return 0; +} + +static int +tolua_storage_tostring(lua_State *L) +{ + storage * self = (storage *)tolua_tousertype(L, 1, 0); + char name[64]; + snprintf(name, sizeof(name), "", self->encoding, self->version); + lua_pushstring(L, name); + return 1; +} + +static int +tolua_storage_close(lua_State *L) +{ + storage * self = (storage *)tolua_tousertype(L, 1, 0); + self->close(self); + return 0; +} + +void +tolua_storage_open(lua_State* L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "storage"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, TOLUA_CAST "storage", TOLUA_CAST "storage", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "storage"); + { + tolua_function(L, TOLUA_CAST "__tostring", tolua_storage_tostring); + tolua_function(L, TOLUA_CAST "write", tolua_storage_write); + tolua_function(L, TOLUA_CAST "read_int", tolua_storage_read_int); + tolua_function(L, TOLUA_CAST "read_float", tolua_storage_read_float); + tolua_function(L, TOLUA_CAST "write_unit", tolua_storage_write_unit); + tolua_function(L, TOLUA_CAST "read_unit", tolua_storage_read_unit); + tolua_function(L, TOLUA_CAST "close", tolua_storage_close); + tolua_function(L, TOLUA_CAST "create", tolua_storage_create); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_storage.h b/src/bindings/bind_storage.h index e47aba558..fd79c7ca8 100644 --- a/src/bindings/bind_storage.h +++ b/src/bindings/bind_storage.h @@ -1,22 +1,22 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - void tolua_storage_open(struct lua_State *L); - -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + void tolua_storage_open(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 56a81bf3e..9de137d90 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -1,1026 +1,1026 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include - -#include "bind_unit.h" -#include "bind_attrib.h" -#include "bindings.h" - -// attributes includes -#include -#include - -// kernel includes -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// util includes -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -static int -tolua_unit_get_objects(lua_State* L) -{ - unit * self = (unit *)tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); - return 1; -} - - -static int -tolua_unit_get_attribs(lua_State* L) -{ - unit * self = (unit *)tolua_tousertype(L, 1, 0); - attrib ** attrib_ptr = (attrib**)lua_newuserdata(L, sizeof(attrib *)); - attrib * a = tolua_get_lua_ext(self->attribs); - - luaL_getmetatable(L, "attrib"); - lua_setmetatable(L, -2); - - *attrib_ptr = a; - - lua_pushcclosure(L, tolua_attriblist_next, 1); - return 1; -} - -int tolua_unitlist_nextf(lua_State *L) -{ - unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); - unit * u = *unit_ptr; - if (u != NULL) { - tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); - *unit_ptr = u->nextF; - return 1; - } - else return 0; /* no more values to return */ -} - -int tolua_unitlist_nextb(lua_State *L) -{ - unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); - unit * u = *unit_ptr; - if (u != NULL) { - unit * unext = u->next; - tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); - - while (unext && unext->building!=u->building) { - unext = unext->next; - } - *unit_ptr = unext; - - return 1; - } - else return 0; /* no more values to return */ -} - -int tolua_unitlist_nexts(lua_State *L) -{ - unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); - unit * u = *unit_ptr; - if (u != NULL) { - unit * unext = u->next; - tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); - - while (unext && unext->ship!=u->ship) { - unext = unext->next; - } - *unit_ptr = unext; - - return 1; - } - else return 0; /* no more values to return */ -} - -int tolua_unitlist_next(lua_State *L) -{ - unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); - unit * u = *unit_ptr; - if (u != NULL) { - tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); - *unit_ptr = u->next; - return 1; - } - else return 0; /* no more values to return */ -} - - -static int tolua_unit_get_name(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->name); - return 1; -} - -static int tolua_unit_set_name(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - unit_setname(self, tolua_tostring(L, 2, 0)); - return 0; -} - -static int tolua_unit_get_info(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, unit_getinfo(self)); - return 1; -} - -static int tolua_unit_set_info(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - unit_setinfo(self, tolua_tostring(L, 2, 0)); - return 0; -} - -static int tolua_unit_get_id(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)unit_getid(self)); - return 1; -} - -static int tolua_unit_set_id(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - unit_setid(self, (int)tolua_tonumber(L, 2, 0)); - return 0; -} - -static int tolua_unit_get_hpmax(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)unit_max_hp(self)); - return 1; -} - -static int tolua_unit_get_hp(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)unit_gethp(self)); - return 1; -} - -static int tolua_unit_set_hp(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - unit_sethp(self, (int)tolua_tonumber(L, 2, 0)); - return 0; -} - -static int tolua_unit_get_number(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->number); - return 1; -} - -static int tolua_unit_set_number(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - int number = (int)tolua_tonumber(L, 2, 0); - if (self->number==0) { - set_number(self, number); - self->hp = unit_max_hp(self) * number; - } else { - scale_number(self, number); - } - return 0; -} - -static int tolua_unit_get_flags(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->flags); - return 1; -} - -static int tolua_unit_set_flags(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - self->flags = (int)tolua_tonumber(L, 2, 0); - return 0; -} - -static const char * -unit_getmagic(const unit * u) -{ - sc_mage * mage = get_mage(u); - return mage?magic_school[mage->magietyp]:NULL; -} - -static int tolua_unit_get_magic(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - lua_pushstring(L, unit_getmagic(self)); - return 1; -} - -static void -unit_setmagic(unit * u, const char * type) -{ - sc_mage * mage = get_mage(u); - magic_t mtype; - for (mtype=0;mtype!=MAXMAGIETYP;++mtype) { - if (strcmp(magic_school[mtype], type)==0) break; - } - if (mtype==MAXMAGIETYP) return; - if (mage==NULL) { - mage = create_mage(u, mtype); - } -} - -static int tolua_unit_set_magic(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * type = tolua_tostring(L, 2, 0); - unit_setmagic(self, type); - return 0; -} - -static int tolua_unit_get_aura(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)get_spellpoints(self)); - return 1; -} - -static int tolua_unit_set_aura(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - set_spellpoints(self, (int)tolua_tonumber(L, 2, 0)); - return 0; -} - -static int tolua_unit_get_age(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->age); - return 1; -} - -static int tolua_unit_set_age(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - self->age = (short)tolua_tonumber(L, 2, 0); - return 0; -} - -static int tolua_unit_get_status(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)unit_getstatus(self)); - return 1; -} - -static int tolua_unit_set_status(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - unit_setstatus(self, (status_t)tolua_tonumber(L, 2, 0)); - return 0; -} - -static int -tolua_unit_get_item(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * iname = tolua_tostring(L, 2, 0); - int result = -1; - - if (iname!=NULL) { - const item_type * itype = it_find(iname); - if (itype!=NULL) { - result = i_get(self->items, itype); - } - } - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_unit_add_item(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * iname = tolua_tostring(L, 2, 0); - int number = (int)tolua_tonumber(L, 3, 0); - int result = -1; - - if (iname!=NULL) { - const item_type * itype = it_find(iname); - if (itype!=NULL) { - item * i = i_change(&self->items, itype, number); - result = i?i->number:0; - } - } - lua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_unit_getskill(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * skname = tolua_tostring(L, 2, 0); - skill_t sk = sk_find(skname); - int value = -1; - if (sk!=NOSKILL) { - skill * sv = get_skill(self, sk); - if (sv) { - value = sv->level; - } - else value = 0; - } - lua_pushnumber(L, (lua_Number)value); - return 1; -} - -static int -tolua_unit_effskill(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * skname = tolua_tostring(L, 2, 0); - skill_t sk = sk_find(skname); - int value = (sk==NOSKILL)?-1:eff_skill(self, sk, self->region); - lua_pushnumber(L, (lua_Number)value); - return 1; -} - -typedef struct fctr_data { - unit * target; - int fhandle; -} fctr_data; - -typedef struct event { - struct event_arg * args; - char * msg; -} event; - -int -fctr_handle(struct trigger * tp, void * data) -{ - trigger * t = tp; - event evt = { 0 }; - fctr_data * fd = (fctr_data*)t->data.v; - lua_State * L = (lua_State *)global.vm_state; - unit * u = fd->target; - - evt.args = (event_arg*)data; - lua_rawgeti(L, LUA_REGISTRYINDEX, fd->fhandle); - tolua_pushusertype(L, u, TOLUA_CAST "unit"); - tolua_pushusertype(L, &evt, TOLUA_CAST "event"); - if (lua_pcall(L, 2, 0, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("event (%s): %s\n", unitname(u), error)); - lua_pop(L, 1); - tolua_error(L, TOLUA_CAST "event handler call failed", NULL); - } - - return 0; -} - -static void -fctr_init(trigger * t) -{ - t->data.v = calloc(sizeof(fctr_data), 1); -} - -static void -fctr_done(trigger * t) -{ - fctr_data * fd = (fctr_data*)t->data.v; - lua_State * L = (lua_State *)global.vm_state; - luaL_unref(L, LUA_REGISTRYINDEX, fd->fhandle); - free(fd); -} - -static struct trigger_type tt_lua = { - "lua_event", - fctr_init, - fctr_done, - fctr_handle -}; - -static trigger * -trigger_lua(struct unit * u, int handle) -{ - trigger * t = t_new(&tt_lua); - fctr_data * td = (fctr_data*)t->data.v; - td->target = u; - td->fhandle = handle; - return t; -} - -static int -tolua_unit_addhandler(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * ename = tolua_tostring(L, 2, 0); - int handle; - - lua_pushvalue(L, 3); - handle = luaL_ref(L, LUA_REGISTRYINDEX); - add_trigger(&self->attribs, ename, trigger_lua(self, handle)); - - return 0; -} - -static int -tolua_unit_addnotice(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * str = tolua_tostring(L, 2, 0); - - addmessage(self->region, self->faction, str, MSG_MESSAGE, ML_IMPORTANT); - return 0; -} - -static void -unit_castspell(unit * u, const char * name) -{ - spell_list * slist = spells; - while (slist!=NULL) { - spell * sp = slist->data; - if (strcmp(name, sp->sname)==0) { - castorder * co = (castorder*)malloc(sizeof(castorder)); - co->distance = 0; - co->familiar = NULL; - co->force = sp->level; - co->level = sp->level; - co->magician.u = u; - co->order = NULL; - co->par = NULL; - co->rt = u->region; - co->sp = sp; - if (sp->sp_function==NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); - co->level = 0; - } else { - sp->sp_function(co); - } - free(co); - } - slist=slist->next; - } -} - -static int -tolua_unit_castspell(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * str = tolua_tostring(L, 2, 0); - unit_castspell(self, str); - return 0; -} - -static void -unit_addspell(unit * u, const char * name) -{ - int add = 0; - sc_mage * m = get_mage(u); - spell_list * slist = spells; - spell_list ** starget = NULL; - spell * spadd = NULL; - while (slist!=NULL) { - spell * sp = slist->data; - if (strcmp(name, sp->sname)==0) { - starget = get_spelllist(m, u->faction); - if (m->magietyp==sp->magietyp) spadd = sp; - else if (!spadd) spadd = sp; - add = 1; - } - slist=slist->next; - } - if (!spadd) log_error(("spell %s could not be found\n", name)); - else add_spell(starget, spadd); -} - -static int -tolua_unit_addspell(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * str = tolua_tostring(L, 2, 0); - unit_addspell(self, str); - return 0; -} - -static void -unit_removespell(unit * u, const spell * sp) -{ - spell_list ** isptr; - isptr = get_spelllist(get_mage(u), u->faction); - - while (*isptr && (*isptr)->data != sp) { - isptr = &(*isptr)->next; - } - if (*isptr) { - spell_list * sptr = *isptr; - *isptr = sptr->next; - free(sptr); - } -} - -static int -tolua_unit_removespell(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - spell * sp = (spell*)tolua_tousertype(L, 2, 0); - unit_removespell(self, sp); - return 0; -} - -static int -tolua_unit_set_racename(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * str = tolua_tostring(L, 2, 0); - - set_racename(&self->attribs, str); - return 0; -} - -static int -tolua_unit_get_racename(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - attrib * a = a_find(self->attribs, &at_racename); - if (a) { - tolua_pushstring(L, get_racename(a)); - return 1; - } - return 0; -} - -static int -tolua_unit_setskill(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * skname = tolua_tostring(L, 2, 0); - int level = (int)tolua_tonumber(L, 3, 0); - skill_t sk = sk_find(skname); - if (sk!=NOSKILL) { - set_level(self, sk, level); - } else { - level = -1; - } - lua_pushnumber(L, (lua_Number)level); - return 1; -} - -static int -tolua_unit_use_pooled(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * iname = tolua_tostring(L, 2, 0); - int number = (int)tolua_tonumber(L, 3, 0); - const resource_type * rtype = rt_find(iname); - int result = -1; - if (rtype!=NULL) { - result = use_pooled(self, rtype, GET_DEFAULT, number); - } - lua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_unit_get_pooled(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * iname = tolua_tostring(L, 2, 0); - const resource_type * rtype = rt_find(iname); - int result = -1; - if (rtype!=NULL) { - result = get_pooled(self, rtype, GET_DEFAULT, INT_MAX); - } - lua_pushnumber(L, (lua_Number)result); - return 1; -} - -static unit * -unit_getfamiliar(const unit * u) -{ - attrib * a = a_find(u->attribs, &at_familiar); - if (a!=NULL) { - return (unit*)a->data.v; - } - return NULL; -} - -static int tolua_unit_get_familiar(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, unit_getfamiliar(self), TOLUA_CAST "unit"); - return 1; -} - -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)); - return 0; -} - -static int tolua_unit_get_building(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, self->building, TOLUA_CAST "building"); - return 1; -} - -static void -unit_setbuilding(unit * u, building * b) -{ - leave(u, true); - if (b && u->region!=b->region) { - move_unit(u, b->region, NULL); - } - u->building = b; -} - -static int tolua_unit_set_building(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - if (self->faction) { - unit_setbuilding(self, (building *)tolua_tousertype(L, 2, 0)); - } - return 0; -} - -static int tolua_unit_get_ship(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, self->ship, TOLUA_CAST "ship"); - return 1; -} - -static void -unit_setship(unit * u, ship * s) -{ - leave(u, true); - if (s && u->region!=s->region) { - move_unit(u, s->region, NULL); - } - u->ship = s; -} - -static int tolua_unit_set_ship(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - if (self->faction) { - unit_setship(self, (ship *)tolua_tousertype(L, 2, 0)); - } - return 0; -} - -static int tolua_unit_get_region(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, self->region, TOLUA_CAST "region"); - return 1; -} - -static void -unit_setregion(unit * u, region * r) -{ - move_unit(u, r, NULL); -} - -static int tolua_unit_set_region(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - unit_setregion(self, (region *)tolua_tousertype(L, 2, 0)); - return 0; -} - -static int tolua_unit_add_order(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * str = tolua_tostring(L, 2, 0); - order * ord = parse_order(str, self->faction->locale); - unit_addorder(self, ord); - return 0; -} - -static int tolua_unit_clear_orders(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - free_orders(&self->orders); - return 0; -} - -static int tolua_unit_get_items(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - - item ** item_ptr = (item **)lua_newuserdata(L, sizeof(item *)); - - luaL_getmetatable(L, TOLUA_CAST "item"); - lua_setmetatable(L, -2); - - *item_ptr = self->items; - - lua_pushcclosure(L, tolua_itemlist_next, 1); - - return 1; -} - -static int tolua_unit_get_spells(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - sc_mage * mage = get_mage(self); - - if (mage) { - spell_list ** slist = get_spelllist(mage, self->faction); - assert(slist); - if (slist) { - spell_list ** spell_ptr = (spell_list **)lua_newuserdata(L, sizeof(spell_list *)); - luaL_getmetatable(L, TOLUA_CAST "spell_list"); - lua_setmetatable(L, -2); - - *spell_ptr = *slist; - lua_pushcclosure(L, tolua_spelllist_next, 1); - return 1; - } - } - - lua_pushnil(L); - return 1; -} - -static int tolua_unit_get_orders(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - - order ** order_ptr = (order **)lua_newuserdata(L, sizeof(order *)); - - luaL_getmetatable(L, TOLUA_CAST "order"); - lua_setmetatable(L, -2); - - *order_ptr = self->orders; - - lua_pushcclosure(L, tolua_orderlist_next, 1); - - return 1; -} - -static int tolua_unit_get_flag(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - int flag = atoi36(name); - attrib * a = find_key(self->attribs, flag); - lua_pushboolean(L, (a!=NULL)); - return 1; -} - -static int tolua_unit_set_flag(lua_State* L) -{ - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - int value = (int)tolua_tonumber(L, 3, 0); - int flag = atoi36(name); - attrib * a = find_key(self->attribs, flag); - if (a==NULL && value) { - add_key(&self->attribs, flag); - } else if (a!=NULL && !value) { - a_remove(&self->attribs, a); - } - return 0; -} - -static int tolua_unit_get_weight(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)unit_getweight(self)); - return 1; -} - -static int tolua_unit_get_capacity(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)unit_getcapacity(self)); - return 1; -} - -static int tolua_unit_get_faction(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void*)self->faction, TOLUA_CAST "faction"); - return 1; -} - -static int tolua_unit_set_faction(lua_State* L) -{ - unit * self = (unit*) tolua_tousertype(L, 1, 0); - faction * f = (faction *)tolua_tousertype(L, 2, 0); - u_setfaction(self, f); - return 0; -} - -static int tolua_unit_get_race(lua_State* L) -{ - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->race->_name[0]); - return 1; -} - -static int tolua_unit_set_race(lua_State* L) -{ - unit * self = (unit*) tolua_tousertype(L, 1, 0); - const char * rcname = tolua_tostring(L, 2, 0); - race * rc = rc_find(rcname); - if (rc!=NULL) { - if (count_unit(self)) --self->faction->no_units; - if (self->irace==self->race) self->irace = NULL; - self->race = rc; - if (count_unit(self)) --self->faction->no_units; - } - return 0; -} - -static int -tolua_unit_destroy(lua_State* L) -{ - unit * self = (unit *)tolua_tousertype(L, 1, 0); - if (self) { - remove_unit(&self->region->units, self); - } - return 0; -} - -static int -tolua_unit_create(lua_State* L) -{ - faction * f = (faction *)tolua_tousertype(L, 1, 0); - region * r = (region *)tolua_tousertype(L, 2, 0); - int num = (int)tolua_tonumber(L, 3, 1); - if (f && r) { - const race * rc = f->race; - const char * rcname = tolua_tostring(L, 4, NULL); - if (rcname) rc = rc_find(rcname); - if (rc) { - unit * u = create_unit(r, f, num, rc, 0, NULL, NULL); - tolua_pushusertype(L, u, TOLUA_CAST "unit"); - return 1; - } - } - return 0; -} - -static int -tolua_unit_tostring(lua_State *L) -{ - unit * self = (unit *)tolua_tousertype(L, 1, 0); - lua_pushstring(L, unitname(self)); - return 1; -} - -static int -tolua_event_gettype(lua_State *L) -{ - event * self = (event *)tolua_tousertype(L, 1, 0); - int index = (int)tolua_tonumber(L, 2, 0); - lua_pushstring(L, self->args[index].type); - return 1; -} - -static int -tolua_event_get(lua_State *L) -{ - struct event * self = (struct event *)tolua_tousertype(L, 1, 0); - int index = (int)tolua_tonumber(L, 2, 0); - - event_arg * arg = self->args+index; - - if (arg->type) { - if (strcmp(arg->type, "string")==0) { - tolua_pushstring(L, (const char *)arg->data.v); - } else if (strcmp(arg->type, "int")==0) { - tolua_pushnumber(L, (lua_Number)arg->data.i); - } else if (strcmp(arg->type, "float")==0) { - tolua_pushnumber(L, (lua_Number)arg->data.f); - } else { - /* this is pretty lazy */ - tolua_pushusertype(L, (void*)arg->data.v, TOLUA_CAST arg->type); - } - return 1; - } - tolua_error(L, TOLUA_CAST "invalid type argument for event", NULL); - return 0; -} - -void -tolua_unit_open(lua_State * L) -{ - /* register user types */ - tolua_usertype(L, TOLUA_CAST "unit"); - tolua_usertype(L, TOLUA_CAST "unit_list"); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_cclass(L, TOLUA_CAST "event", TOLUA_CAST "event", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "event"); - { - tolua_function(L, TOLUA_CAST "get_type", &tolua_event_gettype); - tolua_function(L, TOLUA_CAST "get", &tolua_event_get); - } - tolua_endmodule(L); - - tolua_cclass(L, TOLUA_CAST "unit", TOLUA_CAST "unit", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "unit"); - { - tolua_function(L, TOLUA_CAST "__tostring", &tolua_unit_tostring); - tolua_function(L, TOLUA_CAST "create", &tolua_unit_create); - tolua_function(L, TOLUA_CAST "destroy", &tolua_unit_destroy); - - tolua_variable(L, TOLUA_CAST "name", &tolua_unit_get_name, tolua_unit_set_name); - tolua_variable(L, TOLUA_CAST "faction", &tolua_unit_get_faction, tolua_unit_set_faction); - tolua_variable(L, TOLUA_CAST "id", &tolua_unit_get_id, tolua_unit_set_id); - tolua_variable(L, TOLUA_CAST "info", &tolua_unit_get_info, tolua_unit_set_info); - tolua_variable(L, TOLUA_CAST "hp", &tolua_unit_get_hp, tolua_unit_set_hp); - tolua_variable(L, TOLUA_CAST "status", &tolua_unit_get_status, tolua_unit_set_status); - tolua_variable(L, TOLUA_CAST "familiar", &tolua_unit_get_familiar, tolua_unit_set_familiar); - - tolua_variable(L, TOLUA_CAST "weight", &tolua_unit_get_weight, 0); - tolua_variable(L, TOLUA_CAST "capacity", &tolua_unit_get_capacity, 0); - - tolua_function(L, TOLUA_CAST "add_order", &tolua_unit_add_order); - tolua_function(L, TOLUA_CAST "clear_orders", &tolua_unit_clear_orders); - tolua_variable(L, TOLUA_CAST "orders", &tolua_unit_get_orders, 0); - - // key-attributes for named flags: - tolua_function(L, TOLUA_CAST "set_flag", &tolua_unit_set_flag); - tolua_function(L, TOLUA_CAST "get_flag", &tolua_unit_get_flag); - tolua_variable(L, TOLUA_CAST "flags", &tolua_unit_get_flags, &tolua_unit_set_flags); - tolua_variable(L, TOLUA_CAST "age", &tolua_unit_get_age, tolua_unit_set_age); - - // items: - tolua_function(L, TOLUA_CAST "get_item", &tolua_unit_get_item); - tolua_function(L, TOLUA_CAST "add_item", &tolua_unit_add_item); - tolua_variable(L, TOLUA_CAST "items", &tolua_unit_get_items, 0); - tolua_function(L, TOLUA_CAST "get_pooled", &tolua_unit_get_pooled); - tolua_function(L, TOLUA_CAST "use_pooled", &tolua_unit_use_pooled); - - // skills: - tolua_function(L, TOLUA_CAST "get_skill", &tolua_unit_getskill); - tolua_function(L, TOLUA_CAST "eff_skill", &tolua_unit_effskill); - tolua_function(L, TOLUA_CAST "set_skill", &tolua_unit_setskill); - - tolua_function(L, TOLUA_CAST "add_notice", &tolua_unit_addnotice); - - // npc logic: - tolua_function(L, TOLUA_CAST "add_handler", &tolua_unit_addhandler); - - tolua_variable(L, TOLUA_CAST "race_name", &tolua_unit_get_racename, &tolua_unit_set_racename); - tolua_function(L, TOLUA_CAST "add_spell", &tolua_unit_addspell); - tolua_function(L, TOLUA_CAST "remove_spell", &tolua_unit_removespell); - tolua_function(L, TOLUA_CAST "cast_spell", &tolua_unit_castspell); - - tolua_variable(L, TOLUA_CAST "magic", &tolua_unit_get_magic, tolua_unit_set_magic); - tolua_variable(L, TOLUA_CAST "aura", &tolua_unit_get_aura, tolua_unit_set_aura); - tolua_variable(L, TOLUA_CAST "building", &tolua_unit_get_building, tolua_unit_set_building); - tolua_variable(L, TOLUA_CAST "ship", &tolua_unit_get_ship, tolua_unit_set_ship); - tolua_variable(L, TOLUA_CAST "region", &tolua_unit_get_region, tolua_unit_set_region); - tolua_variable(L, TOLUA_CAST "spells", &tolua_unit_get_spells, 0); - tolua_variable(L, TOLUA_CAST "number", &tolua_unit_get_number, tolua_unit_set_number); - tolua_variable(L, TOLUA_CAST "race", &tolua_unit_get_race, tolua_unit_set_race); - tolua_variable(L, TOLUA_CAST "hp_max", &tolua_unit_get_hpmax, 0); - - tolua_variable(L, TOLUA_CAST "objects", &tolua_unit_get_objects, 0); - tolua_variable(L, TOLUA_CAST "attribs", &tolua_unit_get_attribs, 0); - } - tolua_endmodule(L); - } - tolua_endmodule(L); -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include + +#include "bind_unit.h" +#include "bind_attrib.h" +#include "bindings.h" + +// attributes includes +#include +#include + +// kernel includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// util includes +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +static int +tolua_unit_get_objects(lua_State* L) +{ + unit * self = (unit *)tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); + return 1; +} + + +static int +tolua_unit_get_attribs(lua_State* L) +{ + unit * self = (unit *)tolua_tousertype(L, 1, 0); + attrib ** attrib_ptr = (attrib**)lua_newuserdata(L, sizeof(attrib *)); + attrib * a = tolua_get_lua_ext(self->attribs); + + luaL_getmetatable(L, "attrib"); + lua_setmetatable(L, -2); + + *attrib_ptr = a; + + lua_pushcclosure(L, tolua_attriblist_next, 1); + return 1; +} + +int tolua_unitlist_nextf(lua_State *L) +{ + unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); + unit * u = *unit_ptr; + if (u != NULL) { + tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); + *unit_ptr = u->nextF; + return 1; + } + else return 0; /* no more values to return */ +} + +int tolua_unitlist_nextb(lua_State *L) +{ + unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); + unit * u = *unit_ptr; + if (u != NULL) { + unit * unext = u->next; + tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); + + while (unext && unext->building!=u->building) { + unext = unext->next; + } + *unit_ptr = unext; + + return 1; + } + else return 0; /* no more values to return */ +} + +int tolua_unitlist_nexts(lua_State *L) +{ + unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); + unit * u = *unit_ptr; + if (u != NULL) { + unit * unext = u->next; + tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); + + while (unext && unext->ship!=u->ship) { + unext = unext->next; + } + *unit_ptr = unext; + + return 1; + } + else return 0; /* no more values to return */ +} + +int tolua_unitlist_next(lua_State *L) +{ + unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); + unit * u = *unit_ptr; + if (u != NULL) { + tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); + *unit_ptr = u->next; + return 1; + } + else return 0; /* no more values to return */ +} + + +static int tolua_unit_get_name(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->name); + return 1; +} + +static int tolua_unit_set_name(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit_setname(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int tolua_unit_get_info(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, unit_getinfo(self)); + return 1; +} + +static int tolua_unit_set_info(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit_setinfo(self, tolua_tostring(L, 2, 0)); + return 0; +} + +static int tolua_unit_get_id(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)unit_getid(self)); + return 1; +} + +static int tolua_unit_set_id(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit_setid(self, (int)tolua_tonumber(L, 2, 0)); + return 0; +} + +static int tolua_unit_get_hpmax(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)unit_max_hp(self)); + return 1; +} + +static int tolua_unit_get_hp(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)unit_gethp(self)); + return 1; +} + +static int tolua_unit_set_hp(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit_sethp(self, (int)tolua_tonumber(L, 2, 0)); + return 0; +} + +static int tolua_unit_get_number(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->number); + return 1; +} + +static int tolua_unit_set_number(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + int number = (int)tolua_tonumber(L, 2, 0); + if (self->number==0) { + set_number(self, number); + self->hp = unit_max_hp(self) * number; + } else { + scale_number(self, number); + } + return 0; +} + +static int tolua_unit_get_flags(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->flags); + return 1; +} + +static int tolua_unit_set_flags(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + self->flags = (int)tolua_tonumber(L, 2, 0); + return 0; +} + +static const char * +unit_getmagic(const unit * u) +{ + sc_mage * mage = get_mage(u); + return mage?magic_school[mage->magietyp]:NULL; +} + +static int tolua_unit_get_magic(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + lua_pushstring(L, unit_getmagic(self)); + return 1; +} + +static void +unit_setmagic(unit * u, const char * type) +{ + sc_mage * mage = get_mage(u); + magic_t mtype; + for (mtype=0;mtype!=MAXMAGIETYP;++mtype) { + if (strcmp(magic_school[mtype], type)==0) break; + } + if (mtype==MAXMAGIETYP) return; + if (mage==NULL) { + mage = create_mage(u, mtype); + } +} + +static int tolua_unit_set_magic(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * type = tolua_tostring(L, 2, 0); + unit_setmagic(self, type); + return 0; +} + +static int tolua_unit_get_aura(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)get_spellpoints(self)); + return 1; +} + +static int tolua_unit_set_aura(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + set_spellpoints(self, (int)tolua_tonumber(L, 2, 0)); + return 0; +} + +static int tolua_unit_get_age(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->age); + return 1; +} + +static int tolua_unit_set_age(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + self->age = (short)tolua_tonumber(L, 2, 0); + return 0; +} + +static int tolua_unit_get_status(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)unit_getstatus(self)); + return 1; +} + +static int tolua_unit_set_status(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit_setstatus(self, (status_t)tolua_tonumber(L, 2, 0)); + return 0; +} + +static int +tolua_unit_get_item(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * iname = tolua_tostring(L, 2, 0); + int result = -1; + + if (iname!=NULL) { + const item_type * itype = it_find(iname); + if (itype!=NULL) { + result = i_get(self->items, itype); + } + } + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_unit_add_item(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * iname = tolua_tostring(L, 2, 0); + int number = (int)tolua_tonumber(L, 3, 0); + int result = -1; + + if (iname!=NULL) { + const item_type * itype = it_find(iname); + if (itype!=NULL) { + item * i = i_change(&self->items, itype, number); + result = i?i->number:0; + } + } + lua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_unit_getskill(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * skname = tolua_tostring(L, 2, 0); + skill_t sk = sk_find(skname); + int value = -1; + if (sk!=NOSKILL) { + skill * sv = get_skill(self, sk); + if (sv) { + value = sv->level; + } + else value = 0; + } + lua_pushnumber(L, (lua_Number)value); + return 1; +} + +static int +tolua_unit_effskill(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * skname = tolua_tostring(L, 2, 0); + skill_t sk = sk_find(skname); + int value = (sk==NOSKILL)?-1:eff_skill(self, sk, self->region); + lua_pushnumber(L, (lua_Number)value); + return 1; +} + +typedef struct fctr_data { + unit * target; + int fhandle; +} fctr_data; + +typedef struct event { + struct event_arg * args; + char * msg; +} event; + +int +fctr_handle(struct trigger * tp, void * data) +{ + trigger * t = tp; + event evt = { 0 }; + fctr_data * fd = (fctr_data*)t->data.v; + lua_State * L = (lua_State *)global.vm_state; + unit * u = fd->target; + + evt.args = (event_arg*)data; + lua_rawgeti(L, LUA_REGISTRYINDEX, fd->fhandle); + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + tolua_pushusertype(L, &evt, TOLUA_CAST "event"); + if (lua_pcall(L, 2, 0, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("event (%s): %s\n", unitname(u), error)); + lua_pop(L, 1); + tolua_error(L, TOLUA_CAST "event handler call failed", NULL); + } + + return 0; +} + +static void +fctr_init(trigger * t) +{ + t->data.v = calloc(sizeof(fctr_data), 1); +} + +static void +fctr_done(trigger * t) +{ + fctr_data * fd = (fctr_data*)t->data.v; + lua_State * L = (lua_State *)global.vm_state; + luaL_unref(L, LUA_REGISTRYINDEX, fd->fhandle); + free(fd); +} + +static struct trigger_type tt_lua = { + "lua_event", + fctr_init, + fctr_done, + fctr_handle +}; + +static trigger * +trigger_lua(struct unit * u, int handle) +{ + trigger * t = t_new(&tt_lua); + fctr_data * td = (fctr_data*)t->data.v; + td->target = u; + td->fhandle = handle; + return t; +} + +static int +tolua_unit_addhandler(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * ename = tolua_tostring(L, 2, 0); + int handle; + + lua_pushvalue(L, 3); + handle = luaL_ref(L, LUA_REGISTRYINDEX); + add_trigger(&self->attribs, ename, trigger_lua(self, handle)); + + return 0; +} + +static int +tolua_unit_addnotice(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * str = tolua_tostring(L, 2, 0); + + addmessage(self->region, self->faction, str, MSG_MESSAGE, ML_IMPORTANT); + return 0; +} + +static void +unit_castspell(unit * u, const char * name) +{ + spell_list * slist = spells; + while (slist!=NULL) { + spell * sp = slist->data; + if (strcmp(name, sp->sname)==0) { + castorder * co = (castorder*)malloc(sizeof(castorder)); + co->distance = 0; + co->familiar = NULL; + co->force = sp->level; + co->level = sp->level; + co->magician.u = u; + co->order = NULL; + co->par = NULL; + co->rt = u->region; + co->sp = sp; + if (sp->sp_function==NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + co->level = 0; + } else { + sp->sp_function(co); + } + free(co); + } + slist=slist->next; + } +} + +static int +tolua_unit_castspell(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * str = tolua_tostring(L, 2, 0); + unit_castspell(self, str); + return 0; +} + +static void +unit_addspell(unit * u, const char * name) +{ + int add = 0; + sc_mage * m = get_mage(u); + spell_list * slist = spells; + spell_list ** starget = NULL; + spell * spadd = NULL; + while (slist!=NULL) { + spell * sp = slist->data; + if (strcmp(name, sp->sname)==0) { + starget = get_spelllist(m, u->faction); + if (m->magietyp==sp->magietyp) spadd = sp; + else if (!spadd) spadd = sp; + add = 1; + } + slist=slist->next; + } + if (!spadd) log_error(("spell %s could not be found\n", name)); + else add_spell(starget, spadd); +} + +static int +tolua_unit_addspell(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * str = tolua_tostring(L, 2, 0); + unit_addspell(self, str); + return 0; +} + +static void +unit_removespell(unit * u, const spell * sp) +{ + spell_list ** isptr; + isptr = get_spelllist(get_mage(u), u->faction); + + while (*isptr && (*isptr)->data != sp) { + isptr = &(*isptr)->next; + } + if (*isptr) { + spell_list * sptr = *isptr; + *isptr = sptr->next; + free(sptr); + } +} + +static int +tolua_unit_removespell(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + spell * sp = (spell*)tolua_tousertype(L, 2, 0); + unit_removespell(self, sp); + return 0; +} + +static int +tolua_unit_set_racename(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * str = tolua_tostring(L, 2, 0); + + set_racename(&self->attribs, str); + return 0; +} + +static int +tolua_unit_get_racename(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + attrib * a = a_find(self->attribs, &at_racename); + if (a) { + tolua_pushstring(L, get_racename(a)); + return 1; + } + return 0; +} + +static int +tolua_unit_setskill(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * skname = tolua_tostring(L, 2, 0); + int level = (int)tolua_tonumber(L, 3, 0); + skill_t sk = sk_find(skname); + if (sk!=NOSKILL) { + set_level(self, sk, level); + } else { + level = -1; + } + lua_pushnumber(L, (lua_Number)level); + return 1; +} + +static int +tolua_unit_use_pooled(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * iname = tolua_tostring(L, 2, 0); + int number = (int)tolua_tonumber(L, 3, 0); + const resource_type * rtype = rt_find(iname); + int result = -1; + if (rtype!=NULL) { + result = use_pooled(self, rtype, GET_DEFAULT, number); + } + lua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_unit_get_pooled(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * iname = tolua_tostring(L, 2, 0); + const resource_type * rtype = rt_find(iname); + int result = -1; + if (rtype!=NULL) { + result = get_pooled(self, rtype, GET_DEFAULT, INT_MAX); + } + lua_pushnumber(L, (lua_Number)result); + return 1; +} + +static unit * +unit_getfamiliar(const unit * u) +{ + attrib * a = a_find(u->attribs, &at_familiar); + if (a!=NULL) { + return (unit*)a->data.v; + } + return NULL; +} + +static int tolua_unit_get_familiar(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, unit_getfamiliar(self), TOLUA_CAST "unit"); + return 1; +} + +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)); + return 0; +} + +static int tolua_unit_get_building(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, self->building, TOLUA_CAST "building"); + return 1; +} + +static void +unit_setbuilding(unit * u, building * b) +{ + leave(u, true); + if (b && u->region!=b->region) { + move_unit(u, b->region, NULL); + } + u->building = b; +} + +static int tolua_unit_set_building(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + if (self->faction) { + unit_setbuilding(self, (building *)tolua_tousertype(L, 2, 0)); + } + return 0; +} + +static int tolua_unit_get_ship(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, self->ship, TOLUA_CAST "ship"); + return 1; +} + +static void +unit_setship(unit * u, ship * s) +{ + leave(u, true); + if (s && u->region!=s->region) { + move_unit(u, s->region, NULL); + } + u->ship = s; +} + +static int tolua_unit_set_ship(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + if (self->faction) { + unit_setship(self, (ship *)tolua_tousertype(L, 2, 0)); + } + return 0; +} + +static int tolua_unit_get_region(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, self->region, TOLUA_CAST "region"); + return 1; +} + +static void +unit_setregion(unit * u, region * r) +{ + move_unit(u, r, NULL); +} + +static int tolua_unit_set_region(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit_setregion(self, (region *)tolua_tousertype(L, 2, 0)); + return 0; +} + +static int tolua_unit_add_order(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * str = tolua_tostring(L, 2, 0); + order * ord = parse_order(str, self->faction->locale); + unit_addorder(self, ord); + return 0; +} + +static int tolua_unit_clear_orders(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + free_orders(&self->orders); + return 0; +} + +static int tolua_unit_get_items(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + + item ** item_ptr = (item **)lua_newuserdata(L, sizeof(item *)); + + luaL_getmetatable(L, TOLUA_CAST "item"); + lua_setmetatable(L, -2); + + *item_ptr = self->items; + + lua_pushcclosure(L, tolua_itemlist_next, 1); + + return 1; +} + +static int tolua_unit_get_spells(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + sc_mage * mage = get_mage(self); + + if (mage) { + spell_list ** slist = get_spelllist(mage, self->faction); + assert(slist); + if (slist) { + spell_list ** spell_ptr = (spell_list **)lua_newuserdata(L, sizeof(spell_list *)); + luaL_getmetatable(L, TOLUA_CAST "spell_list"); + lua_setmetatable(L, -2); + + *spell_ptr = *slist; + lua_pushcclosure(L, tolua_spelllist_next, 1); + return 1; + } + } + + lua_pushnil(L); + return 1; +} + +static int tolua_unit_get_orders(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + + order ** order_ptr = (order **)lua_newuserdata(L, sizeof(order *)); + + luaL_getmetatable(L, TOLUA_CAST "order"); + lua_setmetatable(L, -2); + + *order_ptr = self->orders; + + lua_pushcclosure(L, tolua_orderlist_next, 1); + + return 1; +} + +static int tolua_unit_get_flag(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + int flag = atoi36(name); + attrib * a = find_key(self->attribs, flag); + lua_pushboolean(L, (a!=NULL)); + return 1; +} + +static int tolua_unit_set_flag(lua_State* L) +{ + unit* self = (unit*)tolua_tousertype(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + int value = (int)tolua_tonumber(L, 3, 0); + int flag = atoi36(name); + attrib * a = find_key(self->attribs, flag); + if (a==NULL && value) { + add_key(&self->attribs, flag); + } else if (a!=NULL && !value) { + a_remove(&self->attribs, a); + } + return 0; +} + +static int tolua_unit_get_weight(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)unit_getweight(self)); + return 1; +} + +static int tolua_unit_get_capacity(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)unit_getcapacity(self)); + return 1; +} + +static int tolua_unit_get_faction(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, (void*)self->faction, TOLUA_CAST "faction"); + return 1; +} + +static int tolua_unit_set_faction(lua_State* L) +{ + unit * self = (unit*) tolua_tousertype(L, 1, 0); + faction * f = (faction *)tolua_tousertype(L, 2, 0); + u_setfaction(self, f); + return 0; +} + +static int tolua_unit_get_race(lua_State* L) +{ + unit* self = (unit*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->race->_name[0]); + return 1; +} + +static int tolua_unit_set_race(lua_State* L) +{ + unit * self = (unit*) tolua_tousertype(L, 1, 0); + const char * rcname = tolua_tostring(L, 2, 0); + race * rc = rc_find(rcname); + if (rc!=NULL) { + if (count_unit(self)) --self->faction->no_units; + if (self->irace==self->race) self->irace = NULL; + self->race = rc; + if (count_unit(self)) --self->faction->no_units; + } + return 0; +} + +static int +tolua_unit_destroy(lua_State* L) +{ + unit * self = (unit *)tolua_tousertype(L, 1, 0); + if (self) { + remove_unit(&self->region->units, self); + } + return 0; +} + +static int +tolua_unit_create(lua_State* L) +{ + faction * f = (faction *)tolua_tousertype(L, 1, 0); + region * r = (region *)tolua_tousertype(L, 2, 0); + int num = (int)tolua_tonumber(L, 3, 1); + if (f && r) { + const race * rc = f->race; + const char * rcname = tolua_tostring(L, 4, NULL); + if (rcname) rc = rc_find(rcname); + if (rc) { + unit * u = create_unit(r, f, num, rc, 0, NULL, NULL); + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + return 1; + } + } + return 0; +} + +static int +tolua_unit_tostring(lua_State *L) +{ + unit * self = (unit *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, unitname(self)); + return 1; +} + +static int +tolua_event_gettype(lua_State *L) +{ + event * self = (event *)tolua_tousertype(L, 1, 0); + int index = (int)tolua_tonumber(L, 2, 0); + lua_pushstring(L, self->args[index].type); + return 1; +} + +static int +tolua_event_get(lua_State *L) +{ + struct event * self = (struct event *)tolua_tousertype(L, 1, 0); + int index = (int)tolua_tonumber(L, 2, 0); + + event_arg * arg = self->args+index; + + if (arg->type) { + if (strcmp(arg->type, "string")==0) { + tolua_pushstring(L, (const char *)arg->data.v); + } else if (strcmp(arg->type, "int")==0) { + tolua_pushnumber(L, (lua_Number)arg->data.i); + } else if (strcmp(arg->type, "float")==0) { + tolua_pushnumber(L, (lua_Number)arg->data.f); + } else { + /* this is pretty lazy */ + tolua_pushusertype(L, (void*)arg->data.v, TOLUA_CAST arg->type); + } + return 1; + } + tolua_error(L, TOLUA_CAST "invalid type argument for event", NULL); + return 0; +} + +void +tolua_unit_open(lua_State * L) +{ + /* register user types */ + tolua_usertype(L, TOLUA_CAST "unit"); + tolua_usertype(L, TOLUA_CAST "unit_list"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, TOLUA_CAST "event", TOLUA_CAST "event", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "event"); + { + tolua_function(L, TOLUA_CAST "get_type", &tolua_event_gettype); + tolua_function(L, TOLUA_CAST "get", &tolua_event_get); + } + tolua_endmodule(L); + + tolua_cclass(L, TOLUA_CAST "unit", TOLUA_CAST "unit", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "unit"); + { + tolua_function(L, TOLUA_CAST "__tostring", &tolua_unit_tostring); + tolua_function(L, TOLUA_CAST "create", &tolua_unit_create); + tolua_function(L, TOLUA_CAST "destroy", &tolua_unit_destroy); + + tolua_variable(L, TOLUA_CAST "name", &tolua_unit_get_name, tolua_unit_set_name); + tolua_variable(L, TOLUA_CAST "faction", &tolua_unit_get_faction, tolua_unit_set_faction); + tolua_variable(L, TOLUA_CAST "id", &tolua_unit_get_id, tolua_unit_set_id); + tolua_variable(L, TOLUA_CAST "info", &tolua_unit_get_info, tolua_unit_set_info); + tolua_variable(L, TOLUA_CAST "hp", &tolua_unit_get_hp, tolua_unit_set_hp); + tolua_variable(L, TOLUA_CAST "status", &tolua_unit_get_status, tolua_unit_set_status); + tolua_variable(L, TOLUA_CAST "familiar", &tolua_unit_get_familiar, tolua_unit_set_familiar); + + tolua_variable(L, TOLUA_CAST "weight", &tolua_unit_get_weight, 0); + tolua_variable(L, TOLUA_CAST "capacity", &tolua_unit_get_capacity, 0); + + tolua_function(L, TOLUA_CAST "add_order", &tolua_unit_add_order); + tolua_function(L, TOLUA_CAST "clear_orders", &tolua_unit_clear_orders); + tolua_variable(L, TOLUA_CAST "orders", &tolua_unit_get_orders, 0); + + // key-attributes for named flags: + tolua_function(L, TOLUA_CAST "set_flag", &tolua_unit_set_flag); + tolua_function(L, TOLUA_CAST "get_flag", &tolua_unit_get_flag); + tolua_variable(L, TOLUA_CAST "flags", &tolua_unit_get_flags, &tolua_unit_set_flags); + tolua_variable(L, TOLUA_CAST "age", &tolua_unit_get_age, tolua_unit_set_age); + + // items: + tolua_function(L, TOLUA_CAST "get_item", &tolua_unit_get_item); + tolua_function(L, TOLUA_CAST "add_item", &tolua_unit_add_item); + tolua_variable(L, TOLUA_CAST "items", &tolua_unit_get_items, 0); + tolua_function(L, TOLUA_CAST "get_pooled", &tolua_unit_get_pooled); + tolua_function(L, TOLUA_CAST "use_pooled", &tolua_unit_use_pooled); + + // skills: + tolua_function(L, TOLUA_CAST "get_skill", &tolua_unit_getskill); + tolua_function(L, TOLUA_CAST "eff_skill", &tolua_unit_effskill); + tolua_function(L, TOLUA_CAST "set_skill", &tolua_unit_setskill); + + tolua_function(L, TOLUA_CAST "add_notice", &tolua_unit_addnotice); + + // npc logic: + tolua_function(L, TOLUA_CAST "add_handler", &tolua_unit_addhandler); + + tolua_variable(L, TOLUA_CAST "race_name", &tolua_unit_get_racename, &tolua_unit_set_racename); + tolua_function(L, TOLUA_CAST "add_spell", &tolua_unit_addspell); + tolua_function(L, TOLUA_CAST "remove_spell", &tolua_unit_removespell); + tolua_function(L, TOLUA_CAST "cast_spell", &tolua_unit_castspell); + + tolua_variable(L, TOLUA_CAST "magic", &tolua_unit_get_magic, tolua_unit_set_magic); + tolua_variable(L, TOLUA_CAST "aura", &tolua_unit_get_aura, tolua_unit_set_aura); + tolua_variable(L, TOLUA_CAST "building", &tolua_unit_get_building, tolua_unit_set_building); + tolua_variable(L, TOLUA_CAST "ship", &tolua_unit_get_ship, tolua_unit_set_ship); + tolua_variable(L, TOLUA_CAST "region", &tolua_unit_get_region, tolua_unit_set_region); + tolua_variable(L, TOLUA_CAST "spells", &tolua_unit_get_spells, 0); + tolua_variable(L, TOLUA_CAST "number", &tolua_unit_get_number, tolua_unit_set_number); + tolua_variable(L, TOLUA_CAST "race", &tolua_unit_get_race, tolua_unit_set_race); + tolua_variable(L, TOLUA_CAST "hp_max", &tolua_unit_get_hpmax, 0); + + tolua_variable(L, TOLUA_CAST "objects", &tolua_unit_get_objects, 0); + tolua_variable(L, TOLUA_CAST "attribs", &tolua_unit_get_attribs, 0); + } + tolua_endmodule(L); + } + tolua_endmodule(L); +} diff --git a/src/bindings/bind_unit.h b/src/bindings/bind_unit.h index 011e17af0..767f4bfd6 100644 --- a/src/bindings/bind_unit.h +++ b/src/bindings/bind_unit.h @@ -1,26 +1,26 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - int tolua_unitlist_nextb(struct lua_State *L); - int tolua_unitlist_nexts(struct lua_State *L); - int tolua_unitlist_nextf(struct lua_State *L); - int tolua_unitlist_next(struct lua_State *L); - void tolua_unit_open(struct lua_State *L); - -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + int tolua_unitlist_nextb(struct lua_State *L); + int tolua_unitlist_nexts(struct lua_State *L); + int tolua_unitlist_nextf(struct lua_State *L); + int tolua_unitlist_next(struct lua_State *L); + void tolua_unit_open(struct lua_State *L); + +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index 831d68477..fa1947c54 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -1,1163 +1,1159 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include "bindings.h" -#include "bind_unit.h" -#include "bind_faction.h" -#include "bind_region.h" -#include "helpers.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -int -log_lua_error(lua_State * L) -{ - const char* error = lua_tostring(L, -1); - - log_error(("LUA call failed.\n%s\n", error)); - lua_pop(L, 1); - - return 1; -} - -int tolua_orderlist_next(lua_State *L) -{ - order** order_ptr = (order **)lua_touserdata(L, lua_upvalueindex(1)); - order* ord = *order_ptr; - if (ord != NULL) { - char cmd[8192]; - write_order(ord, cmd, sizeof(cmd)); - tolua_pushstring(L, cmd); - *order_ptr = ord->next; - return 1; - } - else return 0; /* no more values to return */ -} - -int tolua_spelllist_next(lua_State *L) -{ - spell_list** spell_ptr = (spell_list **)lua_touserdata(L, lua_upvalueindex(1)); - spell_list* slist = *spell_ptr; - if (slist != NULL) { - tolua_pushusertype(L, slist->data, TOLUA_CAST "spell"); - *spell_ptr = slist->next; - return 1; - } - else return 0; /* no more values to return */ -} - -int tolua_itemlist_next(lua_State *L) -{ - item** item_ptr = (item **)lua_touserdata(L, lua_upvalueindex(1)); - item* itm = *item_ptr; - if (itm != NULL) { - tolua_pushstring(L, itm->type->rtype->_name[0]); - *item_ptr = itm->next; - return 1; - } - else return 0; /* no more values to return */ -} - -static int -tolua_autoseed(lua_State * L) -{ - const char * filename = tolua_tostring(L, 1, 0); - int new_island = tolua_toboolean(L, 2, 0); - newfaction * players = read_newfactions(filename); - - if (players!=NULL) { - while (players) { - int n = listlen(players); - int k = (n+ISLANDSIZE-1)/ISLANDSIZE; - k = n / k; - n = autoseed(&players, k, new_island?0:TURNS_PER_ISLAND); - if (n==0) { - break; - } - } - } - return 0; -} - - -static int -tolua_getkey(lua_State* L) -{ - const char * name = tolua_tostring(L, 1, 0); - - int flag = atoi36(name); - attrib * a = find_key(global.attribs, flag); - lua_pushboolean(L, a!=NULL); - - return 1; -} - -static int -tolua_translate(lua_State* L) -{ - const char * str = tolua_tostring(L, 1, 0); - const char * lang = tolua_tostring(L, 2, 0); - struct locale * loc = lang?find_locale(lang):default_locale; - if (loc) { - str = locale_string(loc, str); - tolua_pushstring(L, str); - return 1; - } - return 0; -} - -static int -tolua_setkey(lua_State* L) -{ - const char * name = tolua_tostring(L, 1, 0); - int value = tolua_toboolean(L, 2, 0); - - int flag = atoi36(name); - attrib * a = find_key(global.attribs, flag); - if (a==NULL && value) { - add_key(&global.attribs, flag); - } else if (a!=NULL && !value) { - a_remove(&global.attribs, a); - } - - return 0; -} - -static int -tolua_rng_int(lua_State* L) -{ - lua_pushnumber(L, (lua_Number)rng_int()); - return 1; -} - -static int -tolua_read_orders(lua_State* L) -{ - const char * filename = tolua_tostring(L, 1, 0); - int result = readorders(filename); - lua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_message_unit(lua_State* L) -{ - unit * sender = (unit *)tolua_tousertype(L, 1, 0); - unit * target = (unit *)tolua_tousertype(L, 2, 0); - const char * str = tolua_tostring(L, 3, 0); - if (!target) tolua_error(L, TOLUA_CAST "target is nil", NULL); - if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); - deliverMail(target->faction, sender->region, sender, str, target); - return 0; -} - -static int -tolua_message_faction(lua_State * L) -{ - unit * sender = (unit *)tolua_tousertype(L, 1, 0); - faction * target = (faction *)tolua_tousertype(L, 2, 0); - const char * str = tolua_tostring(L, 3, 0); - if (!target) tolua_error(L, TOLUA_CAST "target is nil", NULL); - if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); - - deliverMail(target, sender->region, sender, str, NULL); - return 0; -} - -static int -tolua_message_region(lua_State * L) -{ - unit * sender = (unit *)tolua_tousertype(L, 1, 0); - const char * str = tolua_tostring(L, 2, 0); - - if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); - ADDMSG(&sender->region->msgs, msg_message("mail_result", "unit message", sender, str)); - - return 0; -} - -static int -tolua_update_guards(lua_State * L) -{ - update_guards(); - return 0; -} - -static int -tolua_set_turn(lua_State * L) -{ - turn = (int)tolua_tonumber(L, 1, 0); - return 0; -} - -static int -tolua_get_turn(lua_State * L) -{ - tolua_pushnumber(L, (lua_Number)turn); - return 1; -} - -static int -tolua_atoi36(lua_State * L) -{ - const char * s = tolua_tostring(L, 1, 0); - tolua_pushnumber(L, (lua_Number)atoi36(s)); - return 1; -} - -static int -tolua_itoa36(lua_State * L) -{ - int i = (int)tolua_tonumber(L, 1, 0); - tolua_pushstring(L, itoa36(i)); - return 1; -} - -static int -tolua_dice_rand(lua_State * L) -{ - const char * s = tolua_tostring(L, 1, 0); - tolua_pushnumber(L, dice_rand(s)); - return 1; -} - -static int -tolua_addequipment(lua_State * L) -{ - const char * eqname = tolua_tostring(L, 1, 0); - const char * iname = tolua_tostring(L, 2, 0); - const char * value = tolua_tostring(L, 3, 0); - int result = -1; - if (iname!=NULL) { - const struct item_type * itype = it_find(iname); - if (itype!=NULL) { - equipment_setitem(create_equipment(eqname), itype, value); - result = 0; - } - } - lua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_get_season(lua_State * L) -{ - int turnno = (int)tolua_tonumber(L, 1, 0); - gamedate gd; - get_gamedate(turnno, &gd); - tolua_pushstring(L, seasonnames[gd.season]); - return 1; -} - -static int -tolua_create_curse(lua_State * L) -{ - unit * u = (unit *)tolua_tousertype(L, 1, 0); - tolua_Error tolua_err; - attrib ** ap = NULL; - - if (tolua_isusertype(L, 2, TOLUA_CAST "unit", 0, &tolua_err)) { - unit * target = (unit *)tolua_tousertype(L, 2, 0); - if (target) ap = &target->attribs; - } else if (tolua_isusertype(L, 2, TOLUA_CAST "region", 0, &tolua_err)) { - region * target = (region *)tolua_tousertype(L, 2, 0); - if (target) ap = &target->attribs; - } else if (tolua_isusertype(L, 2, TOLUA_CAST "ship", 0, &tolua_err)) { - ship * target = (ship *)tolua_tousertype(L, 2, 0); - if (target) ap = &target->attribs; - } else if (tolua_isusertype(L, 2, TOLUA_CAST "building", 0, &tolua_err)) { - building * target = (building *)tolua_tousertype(L, 2, 0); - if (target) ap = &target->attribs; - } - if (ap) { - const char * cname = tolua_tostring(L, 3, 0); - const curse_type * ctype = ct_find(cname); - if (ctype) { - double vigour = tolua_tonumber(L, 4, 0); - int duration = (int)tolua_tonumber(L, 5, 0); - double effect = tolua_tonumber(L, 6, 0); - int men = (int)tolua_tonumber(L, 7, 0); /* optional */ - curse * c = create_curse(u, ap, ctype, vigour, duration, effect, men); - - if (c) { - tolua_pushboolean(L, true); - return 1; - } - } - } - tolua_pushboolean(L, false); - return 1; -} - -static int -tolua_learn_skill(lua_State * L) -{ - unit * u = (unit *)tolua_tousertype(L, 1, 0); - const char * skname = tolua_tostring(L, 2, 0); - float chances = (float)tolua_tonumber(L, 3, 0); - skill_t sk = sk_find(skname); - if (sk!=NOSKILL) { - learn_skill(u, sk, chances); - } - return 0; -} - -static int -tolua_update_scores(lua_State * L) -{ - score(); - return 0; -} - -static int -tolua_update_owners(lua_State * L) -{ - region * r; - for (r=regions;r;r=r->next) { - update_owners(r); - } - return 0; -} - -static int -tolua_update_subscriptions(lua_State * L) -{ - update_subscriptions(); - return 0; -} - -static int -tolua_remove_empty_units(lua_State * L) -{ - remove_empty_units(); - return 0; -} - -static int -tolua_get_nmrs(lua_State * L) -{ - int result = -1; - int n = (int)tolua_tonumber(L, 1, 0); - if (n>=0 && n<=NMRTimeout()) { - if (nmrs==NULL) { - update_nmrs(); - } - result = nmrs[n]; - } - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_equipunit(lua_State * L) -{ - unit * u = (unit *)tolua_tousertype(L, 1, 0); - const char * eqname = tolua_tostring(L, 2, 0); - - equip_unit(u, get_equipment(eqname)); - - return 0; -} - -static int -tolua_equipment_setitem(lua_State * L) -{ - int result = -1; - const char * eqname = tolua_tostring(L, 1, 0); - const char * iname = tolua_tostring(L, 2, 0); - const char * value = tolua_tostring(L, 3, 0); - if (iname!=NULL) { - const struct item_type * itype = it_find(iname); - if (itype!=NULL) { - equipment_setitem(create_equipment(eqname), itype, value); - result = 0; - } - } - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -#ifdef TODO_FOSS -static int -tolua_levitate_ship(lua_State * L) -{ - ship * sh = (ship *)tolua_tousertype(L, 1, 0); - unit * mage = (unit *)tolua_tousertype(L, 2, 0); - double power = (double)tolua_tonumber(L, 3, 0); - int duration = (int)tolua_tonumber(L, 4, 0); - int cno = levitate_ship(sh, mage, power, duration); - tolua_pushnumber(L, (lua_Number)cno); - return 1; -} -#endif - -static int -tolua_spawn_braineaters(lua_State * L) -{ - float chance = (float)tolua_tonumber(L, 1, 0); - spawn_braineaters(chance); - return 0; -} - -static int -tolua_init_reports(lua_State* L) -{ - int result = init_reports(); - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_write_report(lua_State* L) -{ - faction * f = (faction * )tolua_tousertype(L, 1, 0); - time_t ltime = time(0); - int result = write_reports(f, ltime); - - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_write_reports(lua_State* L) -{ - int result; - - init_reports(); - result = reports(); - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static void -reset_game(void) -{ - region * r; - faction * f; - for (r=regions;r;r=r->next) { - unit * u; - building * b; - r->flags &= RF_SAVEMASK; - for (u=r->units;u;u=u->next) { - u->flags &= UFL_SAVEMASK; - } - for (b=r->buildings;b;b=b->next) { - b->flags &= BLD_SAVEMASK; - } - - if (r->land && r->land->ownership && r->land->ownership->owner) { - faction * owner = r->land->ownership->owner; - if (owner==get_monsters()) { - /* some compat-fix, i believe. */ - owner = update_owners(r); - } - if (owner) { - fset(r, RF_GUARDED); - } - } - } - for (f=factions;f;f=f->next) { - f->flags &= FFL_SAVEMASK; - } -} - -static int -tolua_process_orders(lua_State* L) -{ - ++turn; - reset_game(); - processorders(); - return 0; -} - -static int -tolua_write_passwords(lua_State* L) -{ - int result = writepasswd(); - lua_pushnumber(L, (lua_Number)result); - return 0; -} - -static struct summary * sum_begin = 0; - -static int -tolua_init_summary(lua_State* L) -{ - sum_begin = make_summary(); - return 0; -} - -static int -tolua_write_summary(lua_State* L) -{ - if (sum_begin) { - struct summary * sum_end = make_summary(); - report_summary(sum_end, sum_begin, false); - report_summary(sum_end, sum_begin, true); - return 0; - } - return 0; -} - -static int -tolua_free_game(lua_State* L) -{ - free_gamedata(); - return 0; -} - -static int -tolua_write_map(lua_State* L) -{ - const char * filename = tolua_tostring(L, 1, 0); - if (filename) { - crwritemap(filename); - } - return 0; -} - -static int -tolua_write_game(lua_State* L) -{ - const char * filename = tolua_tostring(L, 1, 0); - const char * mode = tolua_tostring(L, 2, 0); - - int result, m = IO_BINARY; - if (mode && strcmp(mode, "text")==0) m = IO_TEXT; - remove_empty_factions(); - result = writegame(filename, m); - - tolua_pushnumber(L, (lua_Number)result); - return 1; -} - -static int -tolua_read_game(lua_State* L) -{ - const char * filename = tolua_tostring(L, 1, 0); - const char * mode = tolua_tostring(L, 2, 0); - - int rv, m = IO_BINARY; - if (mode && strcmp(mode, "text")==0) m = IO_TEXT; - rv = readgame(filename, m, false); - - tolua_pushnumber(L, (lua_Number)rv); - return 1; -} - -static int -tolua_read_turn(lua_State* L) -{ - int cturn = current_turn(); - tolua_pushnumber(L, (lua_Number)cturn); - return 1; -} - -static int -tolua_get_faction(lua_State* L) -{ - int no = tolua_toid(L, 1, 0); - faction * f = findfaction(no); - - tolua_pushusertype(L, f, TOLUA_CAST "faction"); - return 1; -} - -static int -tolua_get_region(lua_State* L) -{ - int x = (int)tolua_tonumber(L, 1, 0); - int y = (int)tolua_tonumber(L, 2, 0); - region * r; - - assert(!pnormalize(&x, &y, findplane(x, y))); - r = findregion(x, y); - - tolua_pushusertype(L, r, TOLUA_CAST "region"); - return 1; -} - -static int -tolua_get_region_byid(lua_State* L) -{ - int uid = (int)tolua_tonumber(L, 1, 0); - region * r = findregionbyid(uid); - - tolua_pushusertype(L, r, TOLUA_CAST "region"); - return 1; -} - -static int -tolua_get_building(lua_State* L) -{ - int no = tolua_toid(L, 1, 0); - building * b = findbuilding(no); - - tolua_pushusertype(L, b, TOLUA_CAST "building"); - return 1; -} - -static int -tolua_get_ship(lua_State* L) -{ - int no = tolua_toid(L, 1, 0); - ship * sh = findship(no); - - tolua_pushusertype(L, sh, TOLUA_CAST "ship"); - return 1; -} - -static int -tolua_get_alliance(lua_State* L) -{ - int no = tolua_toid(L, 1, 0); - alliance * f = findalliance(no); - - tolua_pushusertype(L, f, TOLUA_CAST "alliance"); - return 1; -} - -static int -tolua_get_unit(lua_State* L) -{ - int no = tolua_toid(L, 1, 0); - unit * u = findunit(no); - - tolua_pushusertype(L, u, TOLUA_CAST "unit"); - return 1; -} - -static int -tolua_alliance_create(lua_State* L) -{ - int id = (int)tolua_tonumber(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - - alliance * alli = makealliance(id, name); - - tolua_pushusertype(L, alli, TOLUA_CAST "alliance"); - return 1; -} - -static int -tolua_get_regions(lua_State* L) -{ - region ** region_ptr = (region**)lua_newuserdata(L, sizeof(region *)); - - luaL_getmetatable(L, "region"); - lua_setmetatable(L, -2); - - *region_ptr = regions; - - lua_pushcclosure(L, tolua_regionlist_next, 1); - return 1; -} - -static int -tolua_get_factions(lua_State* L) -{ - faction ** faction_ptr = (faction**)lua_newuserdata(L, sizeof(faction *)); - - luaL_getmetatable(L, "faction"); - lua_setmetatable(L, -2); - - *faction_ptr = factions; - - lua_pushcclosure(L, tolua_factionlist_next, 1); - return 1; -} - -static int -tolua_get_alliance_factions(lua_State* L) -{ - alliance * self = (alliance *)tolua_tousertype(L, 1, 0); - faction_list ** faction_ptr = (faction_list**)lua_newuserdata(L, sizeof(faction_list *)); - - luaL_getmetatable(L, "faction_list"); - lua_setmetatable(L, -2); - - *faction_ptr = self->members; - - lua_pushcclosure(L, tolua_factionlist_iter, 1); - return 1; -} - -static int tolua_get_alliance_id(lua_State* L) -{ - alliance* self = (alliance*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->id); - return 1; -} - -static int tolua_get_alliance_name(lua_State* L) -{ - alliance* self = (alliance*) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->name); - return 1; -} - -static int tolua_set_alliance_name(lua_State* L) -{ - alliance* self = (alliance*)tolua_tousertype(L, 1, 0); - alliance_setname(self, tolua_tostring(L, 2, 0)); - return 0; -} - -#ifdef HAVE_LIBXML -#include -#endif -#include -#include -#include - -static int -tolua_write_spells(lua_State* L) -{ -#ifdef HAVE_LIBXML - spell_f fun = (spell_f)get_function("lua_castspell"); - const char * filename = "magic.xml"; - xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); - xmlNodePtr root = xmlNewNode(NULL, BAD_CAST "spells"); - spell_list * splist; - - for (splist=spells; splist; splist=splist->next) { - spell * sp = splist->data; - if (sp->sp_function!=fun) { - int combat = 0; - xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "spell"); - xmlNewProp(node, BAD_CAST "name", BAD_CAST sp->sname); - xmlNewProp(node, BAD_CAST "type", BAD_CAST magic_school[sp->magietyp]); - xmlNewProp(node, BAD_CAST "rank", xml_i(sp->rank)); - xmlNewProp(node, BAD_CAST "level", xml_i(sp->level)); - xmlNewProp(node, BAD_CAST "index", xml_i(sp->id)); - if (sp->syntax) xmlNewProp(node, BAD_CAST "syntax", BAD_CAST sp->syntax); - if (sp->parameter) xmlNewProp(node, BAD_CAST "parameters", BAD_CAST sp->parameter); - if (sp->components) { - spell_component * comp = sp->components; - for (;comp->type!=0;++comp) { - static const char * costs[] = { "fixed", "level", "linear" }; - xmlNodePtr cnode = xmlNewNode(NULL, BAD_CAST "resource"); - xmlNewProp(cnode, BAD_CAST "name", BAD_CAST comp->type->_name[0]); - xmlNewProp(cnode, BAD_CAST "amount", xml_i(comp->amount)); - xmlNewProp(cnode, BAD_CAST "cost", BAD_CAST costs[comp->cost]); - xmlAddChild(node, cnode); - } - } - - if (sp->sptyp & TESTCANSEE) { - xmlNewProp(node, BAD_CAST "los", BAD_CAST "true"); - } - if (sp->sptyp & ONSHIPCAST) { - xmlNewProp(node, BAD_CAST "ship", BAD_CAST "true"); - } - if (sp->sptyp & OCEANCASTABLE) { - xmlNewProp(node, BAD_CAST "ocean", BAD_CAST "true"); - } - if (sp->sptyp & FARCASTING) { - xmlNewProp(node, BAD_CAST "far", BAD_CAST "true"); - } - if (sp->sptyp & SPELLLEVEL) { - xmlNewProp(node, BAD_CAST "variable", BAD_CAST "true"); - } - - if (sp->sptyp & POSTCOMBATSPELL) combat = 3; - else if (sp->sptyp & COMBATSPELL) combat = 2; - else if (sp->sptyp & PRECOMBATSPELL) combat = 1; - if (combat) { - xmlNewProp(node, BAD_CAST "combat", xml_i(combat)); - } - xmlAddChild(root, node); - } - } - xmlDocSetRootElement(doc, root); - xmlKeepBlanksDefault(0); - xmlSaveFormatFileEnc(filename, doc, "utf-8", 1); - xmlFreeDoc(doc); -#endif - return 0; -} - -static int -tolua_get_locales(lua_State *L) -{ - const struct locale * lang; - int i = 0, n = 0; - - for (lang = locales;lang;lang = nextlocale(lang)) ++n; - lua_createtable(L, n, 0); - - for (lang = locales;lang;lang = nextlocale(lang)) { - tolua_pushstring(L, TOLUA_CAST locale_name(lang)); - lua_rawseti(L, -2, ++i); - } - return 1; -} - -static int -tolua_get_spell_text(lua_State *L) -{ - const struct locale * loc = default_locale; - spell * self = (spell *)tolua_tousertype(L, 1, 0); - lua_pushstring(L, spell_info(self, loc)); - return 1; -} - -static int -tolua_get_spell_school(lua_State *L) -{ - spell * self = (spell *)tolua_tousertype(L, 1, 0); - lua_pushstring(L, magic_school[self->magietyp]); - return 1; -} - -static int -tolua_get_spell_level(lua_State *L) -{ - spell * self = (spell *)tolua_tousertype(L, 1, 0); - lua_pushnumber(L, self->level); - return 1; -} - -static int -tolua_get_spell_name(lua_State *L) -{ - const struct locale * lang = default_locale; - spell * self = (spell *)tolua_tousertype(L, 1, 0); - lua_pushstring(L, spell_name(self, lang)); - return 1; -} - -static int tolua_get_spells(lua_State* L) -{ - spell_list * slist = spells; - if (slist) { - spell_list ** spell_ptr = (spell_list **)lua_newuserdata(L, sizeof(spell_list *)); - luaL_getmetatable(L, "spell_list"); - lua_setmetatable(L, -2); - - *spell_ptr = slist; - lua_pushcclosure(L, tolua_spelllist_next, 1); - return 1; - } - - lua_pushnil(L); - return 1; -} - -int -tolua_read_xml(lua_State* L) -{ - const char * filename = tolua_tostring(L, 1, 0); - const char * catalog = tolua_tostring(L, 2, 0); - init_data(filename, catalog); - return 0; -} - -int tolua_process_markets(lua_State* L) { - do_markets(); - return 0; -} - -int tolua_process_produce(lua_State* L) { - region * r; - for (r=regions;r;r=r->next) { - produce(r); - } - return 0; -} - -typedef struct event_args { - int hfunction; - int hargs; - const char * sendertype; -} event_args; - -static void args_free(void * udata) -{ - free(udata); -} - -static void event_cb(void * sender, const char * event, void * udata) { - lua_State * L = (lua_State *)global.vm_state; - event_args * args = (event_args *)udata; - int nargs = 2; - - lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); - if (sender && args->sendertype) { - tolua_pushusertype(L, sender, TOLUA_CAST args->sendertype); - } else { - lua_pushnil(L); - } - tolua_pushstring(L, event); - if (args->hargs) { - lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); - ++nargs; - } - lua_pcall(L, nargs, 0, 0); -} - -static int -tolua_eventbus_register(lua_State * L) -{ - /* parameters: - ** 1: sender (usertype) - ** 2: event (string) - ** 3: handler (function) - ** 4: arguments (any, *optional*) - */ - void * sender = tolua_tousertype(L, 1, 0); - const char * event = tolua_tostring(L, 2, 0); - event_args * args = malloc(sizeof(event_args)); - - args->sendertype = sender?tolua_typename(L, 1):NULL; - lua_pushvalue(L, 3); - args->hfunction = luaL_ref(L, LUA_REGISTRYINDEX); - if (lua_type(L, 4)!=LUA_TNONE) { - lua_pushvalue(L, 4); - args->hargs = luaL_ref(L, LUA_REGISTRYINDEX); - } else { - args->hargs = 0; - } - eventbus_register(sender, event, &event_cb, &args_free, args); - return 0; -} - -static int -tolua_eventbus_fire(lua_State * L) -{ - void * sender = tolua_tousertype(L, 1, 0); - const char * event = tolua_tostring(L, 2, 0); - void * args = NULL; - eventbus_fire(sender, event, args); - return 0; -} - -static void -parse_inifile(lua_State* L, dictionary * d, const char * section) -{ - int i; - size_t len = strlen(section); - for (i=0;d && i!=d->n;++i) { - const char * key = d->key[i]; - - if (strncmp(section, key, len)==0 && key[len]==':') { - const char * str_value = d->val[i]; - char * endp; - double num_value = strtod(str_value, &endp); - lua_pushstring(L, key + len + 1); - if (*endp) { - tolua_pushstring(L, str_value); - } else { - tolua_pushnumber(L, num_value); - } - lua_rawset(L,-3); - } - } - /* special case */ - lua_pushstring(L, "basepath"); - lua_pushstring(L, basepath()); - lua_rawset(L,-3); -} - -int -tolua_eressea_open(lua_State* L) -{ - tolua_open(L); - - /* register user types */ - tolua_usertype(L, TOLUA_CAST "spell"); - tolua_usertype(L, TOLUA_CAST "spell_list"); - tolua_usertype(L, TOLUA_CAST "order"); - tolua_usertype(L, TOLUA_CAST "item"); - tolua_usertype(L, TOLUA_CAST "alliance"); - tolua_usertype(L, TOLUA_CAST "event"); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_module(L, "process", 0); - tolua_beginmodule(L, "process"); - { - tolua_function(L, "markets", &tolua_process_markets); - tolua_function(L, "produce", &tolua_process_produce); - } - tolua_endmodule(L); - - tolua_cclass(L, TOLUA_CAST "alliance", TOLUA_CAST "alliance", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "alliance"); - { - tolua_variable(L, TOLUA_CAST "name", tolua_get_alliance_name, tolua_set_alliance_name); - tolua_variable(L, TOLUA_CAST "id", tolua_get_alliance_id, NULL); - tolua_variable(L, TOLUA_CAST "factions", &tolua_get_alliance_factions, NULL); - tolua_function(L, TOLUA_CAST "create", tolua_alliance_create); - } - tolua_endmodule(L); - - tolua_cclass(L, TOLUA_CAST "spell", TOLUA_CAST "spell", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "spell"); - { - tolua_function(L, TOLUA_CAST "__tostring", tolua_get_spell_name); - tolua_variable(L, TOLUA_CAST "name", tolua_get_spell_name, 0); - tolua_variable(L, TOLUA_CAST "school", tolua_get_spell_school, 0); - tolua_variable(L, TOLUA_CAST "level", tolua_get_spell_level, 0); - tolua_variable(L, TOLUA_CAST "text", tolua_get_spell_text, 0); - } - tolua_endmodule(L); - - tolua_module(L, TOLUA_CAST "eventbus", 1); - tolua_beginmodule(L, TOLUA_CAST "eventbus"); - { - tolua_function(L, TOLUA_CAST "register", &tolua_eventbus_register); - tolua_function(L, TOLUA_CAST "fire", &tolua_eventbus_fire); - } - tolua_endmodule(L); - - tolua_module(L, TOLUA_CAST "config", 1); - tolua_beginmodule(L, TOLUA_CAST "config"); - { - parse_inifile(L, global.inifile, "config"); - tolua_variable(L, TOLUA_CAST "locales", &tolua_get_locales, 0); - } - tolua_endmodule(L); - - tolua_function(L, TOLUA_CAST "get_region_by_id", tolua_get_region_byid); - tolua_function(L, TOLUA_CAST "get_faction", tolua_get_faction); - tolua_function(L, TOLUA_CAST "get_unit", tolua_get_unit); - tolua_function(L, TOLUA_CAST "get_alliance", tolua_get_alliance); - tolua_function(L, TOLUA_CAST "get_ship", tolua_get_ship), - tolua_function(L, TOLUA_CAST "get_building", tolua_get_building), - tolua_function(L, TOLUA_CAST "get_region", tolua_get_region), - - // deprecated_function(L, TOLUA_CAST "add_faction"); - // deprecated_function(L, TOLUA_CAST "faction_origin"); - tolua_function(L, TOLUA_CAST "factions", tolua_get_factions); - tolua_function(L, TOLUA_CAST "regions", tolua_get_regions); - - tolua_function(L, TOLUA_CAST "read_turn", tolua_read_turn); - tolua_function(L, TOLUA_CAST "read_game", tolua_read_game); - tolua_function(L, TOLUA_CAST "write_game", tolua_write_game); - tolua_function(L, TOLUA_CAST "free_game", tolua_free_game); - tolua_function(L, TOLUA_CAST "write_map", &tolua_write_map); - - tolua_function(L, TOLUA_CAST "read_orders", tolua_read_orders); - tolua_function(L, TOLUA_CAST "process_orders", tolua_process_orders); - - tolua_function(L, TOLUA_CAST "init_reports", tolua_init_reports); - tolua_function(L, TOLUA_CAST "write_reports", tolua_write_reports); - tolua_function(L, TOLUA_CAST "write_report", tolua_write_report); - - tolua_function(L, TOLUA_CAST "init_summary", tolua_init_summary); - tolua_function(L, TOLUA_CAST "write_summary", tolua_write_summary); - tolua_function(L, TOLUA_CAST "write_passwords", tolua_write_passwords), - - tolua_function(L, TOLUA_CAST "message_unit", tolua_message_unit); - tolua_function(L, TOLUA_CAST "message_faction", tolua_message_faction); - tolua_function(L, TOLUA_CAST "message_region", tolua_message_region); - - /* scripted monsters */ - tolua_function(L, TOLUA_CAST "spawn_braineaters", tolua_spawn_braineaters); - -#ifdef TODO_FOSS - /* spells and stuff */ - tolua_function(L, TOLUA_CAST "levitate_ship", tolua_levitate_ship); -#endif - - tolua_function(L, TOLUA_CAST "update_guards", tolua_update_guards); - - tolua_function(L, TOLUA_CAST "set_turn", &tolua_set_turn); - tolua_function(L, TOLUA_CAST "get_turn", &tolua_get_turn); - tolua_function(L, TOLUA_CAST "get_season", tolua_get_season); - - tolua_function(L, TOLUA_CAST "equipment_setitem", tolua_equipment_setitem); - tolua_function(L, TOLUA_CAST "equip_unit", tolua_equipunit); - tolua_function(L, TOLUA_CAST "add_equipment", tolua_addequipment); - - tolua_function(L, TOLUA_CAST "atoi36", tolua_atoi36); - tolua_function(L, TOLUA_CAST "itoa36", tolua_itoa36); - tolua_function(L, TOLUA_CAST "dice_roll", tolua_dice_rand); - - tolua_function(L, TOLUA_CAST "get_nmrs", tolua_get_nmrs); - tolua_function(L, TOLUA_CAST "remove_empty_units", tolua_remove_empty_units); - - tolua_function(L, TOLUA_CAST "update_subscriptions", tolua_update_subscriptions); - tolua_function(L, TOLUA_CAST "update_scores", tolua_update_scores); - tolua_function(L, TOLUA_CAST "update_owners", tolua_update_owners); - - tolua_function(L, TOLUA_CAST "learn_skill", tolua_learn_skill); - tolua_function(L, TOLUA_CAST "create_curse", tolua_create_curse); - - tolua_function(L, TOLUA_CAST "autoseed", tolua_autoseed); - - tolua_function(L, TOLUA_CAST "get_key", tolua_getkey); - tolua_function(L, TOLUA_CAST "set_key", tolua_setkey); - - tolua_function(L, TOLUA_CAST "translate", &tolua_translate); - - tolua_function(L, TOLUA_CAST "rng_int", tolua_rng_int); - - tolua_function(L, TOLUA_CAST "spells", tolua_get_spells); - tolua_function(L, TOLUA_CAST "write_spells", tolua_write_spells); - - tolua_function(L, TOLUA_CAST "read_xml", tolua_read_xml); - - } - tolua_endmodule(L); - return 1; -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bindings.h" +#include "bind_unit.h" +#include "bind_faction.h" +#include "bind_region.h" +#include "helpers.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +int +log_lua_error(lua_State * L) +{ + const char* error = lua_tostring(L, -1); + + log_error(("LUA call failed.\n%s\n", error)); + lua_pop(L, 1); + + return 1; +} + +int tolua_orderlist_next(lua_State *L) +{ + order** order_ptr = (order **)lua_touserdata(L, lua_upvalueindex(1)); + order* ord = *order_ptr; + if (ord != NULL) { + char cmd[8192]; + write_order(ord, cmd, sizeof(cmd)); + tolua_pushstring(L, cmd); + *order_ptr = ord->next; + return 1; + } + else return 0; /* no more values to return */ +} + +int tolua_spelllist_next(lua_State *L) +{ + spell_list** spell_ptr = (spell_list **)lua_touserdata(L, lua_upvalueindex(1)); + spell_list* slist = *spell_ptr; + if (slist != NULL) { + tolua_pushusertype(L, slist->data, TOLUA_CAST "spell"); + *spell_ptr = slist->next; + return 1; + } + else return 0; /* no more values to return */ +} + +int tolua_itemlist_next(lua_State *L) +{ + item** item_ptr = (item **)lua_touserdata(L, lua_upvalueindex(1)); + item* itm = *item_ptr; + if (itm != NULL) { + tolua_pushstring(L, itm->type->rtype->_name[0]); + *item_ptr = itm->next; + return 1; + } + else return 0; /* no more values to return */ +} + +static int +tolua_autoseed(lua_State * L) +{ + const char * filename = tolua_tostring(L, 1, 0); + int new_island = tolua_toboolean(L, 2, 0); + newfaction * players = read_newfactions(filename); + + if (players!=NULL) { + while (players) { + int n = listlen(players); + int k = (n+ISLANDSIZE-1)/ISLANDSIZE; + k = n / k; + n = autoseed(&players, k, new_island?0:TURNS_PER_ISLAND); + if (n==0) { + break; + } + } + } + return 0; +} + + +static int +tolua_getkey(lua_State* L) +{ + const char * name = tolua_tostring(L, 1, 0); + + int flag = atoi36(name); + attrib * a = find_key(global.attribs, flag); + lua_pushboolean(L, a!=NULL); + + return 1; +} + +static int +tolua_translate(lua_State* L) +{ + const char * str = tolua_tostring(L, 1, 0); + const char * lang = tolua_tostring(L, 2, 0); + struct locale * loc = lang?find_locale(lang):default_locale; + if (loc) { + str = locale_string(loc, str); + tolua_pushstring(L, str); + return 1; + } + return 0; +} + +static int +tolua_setkey(lua_State* L) +{ + const char * name = tolua_tostring(L, 1, 0); + int value = tolua_toboolean(L, 2, 0); + + int flag = atoi36(name); + attrib * a = find_key(global.attribs, flag); + if (a==NULL && value) { + add_key(&global.attribs, flag); + } else if (a!=NULL && !value) { + a_remove(&global.attribs, a); + } + + return 0; +} + +static int +tolua_rng_int(lua_State* L) +{ + lua_pushnumber(L, (lua_Number)rng_int()); + return 1; +} + +static int +tolua_read_orders(lua_State* L) +{ + const char * filename = tolua_tostring(L, 1, 0); + int result = readorders(filename); + lua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_message_unit(lua_State* L) +{ + unit * sender = (unit *)tolua_tousertype(L, 1, 0); + unit * target = (unit *)tolua_tousertype(L, 2, 0); + const char * str = tolua_tostring(L, 3, 0); + if (!target) tolua_error(L, TOLUA_CAST "target is nil", NULL); + if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); + deliverMail(target->faction, sender->region, sender, str, target); + return 0; +} + +static int +tolua_message_faction(lua_State * L) +{ + unit * sender = (unit *)tolua_tousertype(L, 1, 0); + faction * target = (faction *)tolua_tousertype(L, 2, 0); + const char * str = tolua_tostring(L, 3, 0); + if (!target) tolua_error(L, TOLUA_CAST "target is nil", NULL); + if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); + + deliverMail(target, sender->region, sender, str, NULL); + return 0; +} + +static int +tolua_message_region(lua_State * L) +{ + unit * sender = (unit *)tolua_tousertype(L, 1, 0); + const char * str = tolua_tostring(L, 2, 0); + + if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); + ADDMSG(&sender->region->msgs, msg_message("mail_result", "unit message", sender, str)); + + return 0; +} + +static int +tolua_update_guards(lua_State * L) +{ + update_guards(); + return 0; +} + +static int +tolua_set_turn(lua_State * L) +{ + turn = (int)tolua_tonumber(L, 1, 0); + return 0; +} + +static int +tolua_get_turn(lua_State * L) +{ + tolua_pushnumber(L, (lua_Number)turn); + return 1; +} + +static int +tolua_atoi36(lua_State * L) +{ + const char * s = tolua_tostring(L, 1, 0); + tolua_pushnumber(L, (lua_Number)atoi36(s)); + return 1; +} + +static int +tolua_itoa36(lua_State * L) +{ + int i = (int)tolua_tonumber(L, 1, 0); + tolua_pushstring(L, itoa36(i)); + return 1; +} + +static int +tolua_dice_rand(lua_State * L) +{ + const char * s = tolua_tostring(L, 1, 0); + tolua_pushnumber(L, dice_rand(s)); + return 1; +} + +static int +tolua_addequipment(lua_State * L) +{ + const char * eqname = tolua_tostring(L, 1, 0); + const char * iname = tolua_tostring(L, 2, 0); + const char * value = tolua_tostring(L, 3, 0); + int result = -1; + if (iname!=NULL) { + const struct item_type * itype = it_find(iname); + if (itype!=NULL) { + equipment_setitem(create_equipment(eqname), itype, value); + result = 0; + } + } + lua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_get_season(lua_State * L) +{ + int turnno = (int)tolua_tonumber(L, 1, 0); + gamedate gd; + get_gamedate(turnno, &gd); + tolua_pushstring(L, seasonnames[gd.season]); + return 1; +} + +static int +tolua_create_curse(lua_State * L) +{ + unit * u = (unit *)tolua_tousertype(L, 1, 0); + tolua_Error tolua_err; + attrib ** ap = NULL; + + if (tolua_isusertype(L, 2, TOLUA_CAST "unit", 0, &tolua_err)) { + unit * target = (unit *)tolua_tousertype(L, 2, 0); + if (target) ap = &target->attribs; + } else if (tolua_isusertype(L, 2, TOLUA_CAST "region", 0, &tolua_err)) { + region * target = (region *)tolua_tousertype(L, 2, 0); + if (target) ap = &target->attribs; + } else if (tolua_isusertype(L, 2, TOLUA_CAST "ship", 0, &tolua_err)) { + ship * target = (ship *)tolua_tousertype(L, 2, 0); + if (target) ap = &target->attribs; + } else if (tolua_isusertype(L, 2, TOLUA_CAST "building", 0, &tolua_err)) { + building * target = (building *)tolua_tousertype(L, 2, 0); + if (target) ap = &target->attribs; + } + if (ap) { + const char * cname = tolua_tostring(L, 3, 0); + const curse_type * ctype = ct_find(cname); + if (ctype) { + double vigour = tolua_tonumber(L, 4, 0); + int duration = (int)tolua_tonumber(L, 5, 0); + double effect = tolua_tonumber(L, 6, 0); + int men = (int)tolua_tonumber(L, 7, 0); /* optional */ + curse * c = create_curse(u, ap, ctype, vigour, duration, effect, men); + + if (c) { + tolua_pushboolean(L, true); + return 1; + } + } + } + tolua_pushboolean(L, false); + return 1; +} + +static int +tolua_learn_skill(lua_State * L) +{ + unit * u = (unit *)tolua_tousertype(L, 1, 0); + const char * skname = tolua_tostring(L, 2, 0); + float chances = (float)tolua_tonumber(L, 3, 0); + skill_t sk = sk_find(skname); + if (sk!=NOSKILL) { + learn_skill(u, sk, chances); + } + return 0; +} + +static int +tolua_update_scores(lua_State * L) +{ + score(); + return 0; +} + +static int +tolua_update_owners(lua_State * L) +{ + region * r; + for (r=regions;r;r=r->next) { + update_owners(r); + } + return 0; +} + +static int +tolua_update_subscriptions(lua_State * L) +{ + update_subscriptions(); + return 0; +} + +static int +tolua_remove_empty_units(lua_State * L) +{ + remove_empty_units(); + return 0; +} + +static int +tolua_get_nmrs(lua_State * L) +{ + int result = -1; + int n = (int)tolua_tonumber(L, 1, 0); + if (n>=0 && n<=NMRTimeout()) { + if (nmrs==NULL) { + update_nmrs(); + } + result = nmrs[n]; + } + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_equipunit(lua_State * L) +{ + unit * u = (unit *)tolua_tousertype(L, 1, 0); + const char * eqname = tolua_tostring(L, 2, 0); + + equip_unit(u, get_equipment(eqname)); + + return 0; +} + +static int +tolua_equipment_setitem(lua_State * L) +{ + int result = -1; + const char * eqname = tolua_tostring(L, 1, 0); + const char * iname = tolua_tostring(L, 2, 0); + const char * value = tolua_tostring(L, 3, 0); + if (iname!=NULL) { + const struct item_type * itype = it_find(iname); + if (itype!=NULL) { + equipment_setitem(create_equipment(eqname), itype, value); + result = 0; + } + } + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +#ifdef TODO_FOSS +static int +tolua_levitate_ship(lua_State * L) +{ + ship * sh = (ship *)tolua_tousertype(L, 1, 0); + unit * mage = (unit *)tolua_tousertype(L, 2, 0); + double power = (double)tolua_tonumber(L, 3, 0); + int duration = (int)tolua_tonumber(L, 4, 0); + int cno = levitate_ship(sh, mage, power, duration); + tolua_pushnumber(L, (lua_Number)cno); + return 1; +} +#endif + +static int +tolua_spawn_braineaters(lua_State * L) +{ + float chance = (float)tolua_tonumber(L, 1, 0); + spawn_braineaters(chance); + return 0; +} + +static int +tolua_init_reports(lua_State* L) +{ + int result = init_reports(); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_write_report(lua_State* L) +{ + faction * f = (faction * )tolua_tousertype(L, 1, 0); + time_t ltime = time(0); + int result = write_reports(f, ltime); + + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_write_reports(lua_State* L) +{ + int result; + + init_reports(); + result = reports(); + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static void +reset_game(void) +{ + region * r; + faction * f; + for (r=regions;r;r=r->next) { + unit * u; + building * b; + r->flags &= RF_SAVEMASK; + for (u=r->units;u;u=u->next) { + u->flags &= UFL_SAVEMASK; + } + for (b=r->buildings;b;b=b->next) { + b->flags &= BLD_SAVEMASK; + } + + if (r->land && r->land->ownership && r->land->ownership->owner) { + faction * owner = r->land->ownership->owner; + if (owner==get_monsters()) { + /* some compat-fix, i believe. */ + owner = update_owners(r); + } + if (owner) { + fset(r, RF_GUARDED); + } + } + } + for (f=factions;f;f=f->next) { + f->flags &= FFL_SAVEMASK; + } +} + +static int +tolua_process_orders(lua_State* L) +{ + ++turn; + reset_game(); + processorders(); + return 0; +} + +static int +tolua_write_passwords(lua_State* L) +{ + int result = writepasswd(); + lua_pushnumber(L, (lua_Number)result); + return 0; +} + +static struct summary * sum_begin = 0; + +static int +tolua_init_summary(lua_State* L) +{ + sum_begin = make_summary(); + return 0; +} + +static int +tolua_write_summary(lua_State* L) +{ + if (sum_begin) { + struct summary * sum_end = make_summary(); + report_summary(sum_end, sum_begin, false); + report_summary(sum_end, sum_begin, true); + return 0; + } + return 0; +} + +static int +tolua_free_game(lua_State* L) +{ + free_gamedata(); + return 0; +} + +static int +tolua_write_map(lua_State* L) +{ + const char * filename = tolua_tostring(L, 1, 0); + if (filename) { + crwritemap(filename); + } + return 0; +} + +static int +tolua_write_game(lua_State* L) +{ + const char * filename = tolua_tostring(L, 1, 0); + const char * mode = tolua_tostring(L, 2, 0); + + int result, m = IO_BINARY; + if (mode && strcmp(mode, "text")==0) m = IO_TEXT; + remove_empty_factions(); + result = writegame(filename, m); + + tolua_pushnumber(L, (lua_Number)result); + return 1; +} + +static int +tolua_read_game(lua_State* L) +{ + const char * filename = tolua_tostring(L, 1, 0); + const char * mode = tolua_tostring(L, 2, 0); + + int rv, m = IO_BINARY; + if (mode && strcmp(mode, "text")==0) m = IO_TEXT; + rv = readgame(filename, m, false); + + tolua_pushnumber(L, (lua_Number)rv); + return 1; +} + +static int +tolua_read_turn(lua_State* L) +{ + int cturn = current_turn(); + tolua_pushnumber(L, (lua_Number)cturn); + return 1; +} + +static int +tolua_get_faction(lua_State* L) +{ + int no = tolua_toid(L, 1, 0); + faction * f = findfaction(no); + + tolua_pushusertype(L, f, TOLUA_CAST "faction"); + return 1; +} + +static int +tolua_get_region(lua_State* L) +{ + int x = (int)tolua_tonumber(L, 1, 0); + int y = (int)tolua_tonumber(L, 2, 0); + region * r; + + assert(!pnormalize(&x, &y, findplane(x, y))); + r = findregion(x, y); + + tolua_pushusertype(L, r, TOLUA_CAST "region"); + return 1; +} + +static int +tolua_get_region_byid(lua_State* L) +{ + int uid = (int)tolua_tonumber(L, 1, 0); + region * r = findregionbyid(uid); + + tolua_pushusertype(L, r, TOLUA_CAST "region"); + return 1; +} + +static int +tolua_get_building(lua_State* L) +{ + int no = tolua_toid(L, 1, 0); + building * b = findbuilding(no); + + tolua_pushusertype(L, b, TOLUA_CAST "building"); + return 1; +} + +static int +tolua_get_ship(lua_State* L) +{ + int no = tolua_toid(L, 1, 0); + ship * sh = findship(no); + + tolua_pushusertype(L, sh, TOLUA_CAST "ship"); + return 1; +} + +static int +tolua_get_alliance(lua_State* L) +{ + int no = tolua_toid(L, 1, 0); + alliance * f = findalliance(no); + + tolua_pushusertype(L, f, TOLUA_CAST "alliance"); + return 1; +} + +static int +tolua_get_unit(lua_State* L) +{ + int no = tolua_toid(L, 1, 0); + unit * u = findunit(no); + + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + return 1; +} + +static int +tolua_alliance_create(lua_State* L) +{ + int id = (int)tolua_tonumber(L, 1, 0); + const char * name = tolua_tostring(L, 2, 0); + + alliance * alli = makealliance(id, name); + + tolua_pushusertype(L, alli, TOLUA_CAST "alliance"); + return 1; +} + +static int +tolua_get_regions(lua_State* L) +{ + region ** region_ptr = (region**)lua_newuserdata(L, sizeof(region *)); + + luaL_getmetatable(L, "region"); + lua_setmetatable(L, -2); + + *region_ptr = regions; + + lua_pushcclosure(L, tolua_regionlist_next, 1); + return 1; +} + +static int +tolua_get_factions(lua_State* L) +{ + faction ** faction_ptr = (faction**)lua_newuserdata(L, sizeof(faction *)); + + luaL_getmetatable(L, "faction"); + lua_setmetatable(L, -2); + + *faction_ptr = factions; + + lua_pushcclosure(L, tolua_factionlist_next, 1); + return 1; +} + +static int +tolua_get_alliance_factions(lua_State* L) +{ + alliance * self = (alliance *)tolua_tousertype(L, 1, 0); + faction_list ** faction_ptr = (faction_list**)lua_newuserdata(L, sizeof(faction_list *)); + + luaL_getmetatable(L, "faction_list"); + lua_setmetatable(L, -2); + + *faction_ptr = self->members; + + lua_pushcclosure(L, tolua_factionlist_iter, 1); + return 1; +} + +static int tolua_get_alliance_id(lua_State* L) +{ + alliance* self = (alliance*) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number)self->id); + return 1; +} + +static int tolua_get_alliance_name(lua_State* L) +{ + alliance* self = (alliance*) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->name); + return 1; +} + +static int tolua_set_alliance_name(lua_State* L) +{ + alliance* self = (alliance*)tolua_tousertype(L, 1, 0); + alliance_setname(self, tolua_tostring(L, 2, 0)); + return 0; +} + +#include +#include +#include +#include + +static int +tolua_write_spells(lua_State* L) +{ + spell_f fun = (spell_f)get_function("lua_castspell"); + const char * filename = "magic.xml"; + xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); + xmlNodePtr root = xmlNewNode(NULL, BAD_CAST "spells"); + spell_list * splist; + + for (splist=spells; splist; splist=splist->next) { + spell * sp = splist->data; + if (sp->sp_function!=fun) { + int combat = 0; + xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "spell"); + xmlNewProp(node, BAD_CAST "name", BAD_CAST sp->sname); + xmlNewProp(node, BAD_CAST "type", BAD_CAST magic_school[sp->magietyp]); + xmlNewProp(node, BAD_CAST "rank", xml_i(sp->rank)); + xmlNewProp(node, BAD_CAST "level", xml_i(sp->level)); + xmlNewProp(node, BAD_CAST "index", xml_i(sp->id)); + if (sp->syntax) xmlNewProp(node, BAD_CAST "syntax", BAD_CAST sp->syntax); + if (sp->parameter) xmlNewProp(node, BAD_CAST "parameters", BAD_CAST sp->parameter); + if (sp->components) { + spell_component * comp = sp->components; + for (;comp->type!=0;++comp) { + static const char * costs[] = { "fixed", "level", "linear" }; + xmlNodePtr cnode = xmlNewNode(NULL, BAD_CAST "resource"); + xmlNewProp(cnode, BAD_CAST "name", BAD_CAST comp->type->_name[0]); + xmlNewProp(cnode, BAD_CAST "amount", xml_i(comp->amount)); + xmlNewProp(cnode, BAD_CAST "cost", BAD_CAST costs[comp->cost]); + xmlAddChild(node, cnode); + } + } + + if (sp->sptyp & TESTCANSEE) { + xmlNewProp(node, BAD_CAST "los", BAD_CAST "true"); + } + if (sp->sptyp & ONSHIPCAST) { + xmlNewProp(node, BAD_CAST "ship", BAD_CAST "true"); + } + if (sp->sptyp & OCEANCASTABLE) { + xmlNewProp(node, BAD_CAST "ocean", BAD_CAST "true"); + } + if (sp->sptyp & FARCASTING) { + xmlNewProp(node, BAD_CAST "far", BAD_CAST "true"); + } + if (sp->sptyp & SPELLLEVEL) { + xmlNewProp(node, BAD_CAST "variable", BAD_CAST "true"); + } + + if (sp->sptyp & POSTCOMBATSPELL) combat = 3; + else if (sp->sptyp & COMBATSPELL) combat = 2; + else if (sp->sptyp & PRECOMBATSPELL) combat = 1; + if (combat) { + xmlNewProp(node, BAD_CAST "combat", xml_i(combat)); + } + xmlAddChild(root, node); + } + } + xmlDocSetRootElement(doc, root); + xmlKeepBlanksDefault(0); + xmlSaveFormatFileEnc(filename, doc, "utf-8", 1); + xmlFreeDoc(doc); + return 0; +} + +static int +tolua_get_locales(lua_State *L) +{ + const struct locale * lang; + int i = 0, n = 0; + + for (lang = locales;lang;lang = nextlocale(lang)) ++n; + lua_createtable(L, n, 0); + + for (lang = locales;lang;lang = nextlocale(lang)) { + tolua_pushstring(L, TOLUA_CAST locale_name(lang)); + lua_rawseti(L, -2, ++i); + } + return 1; +} + +static int +tolua_get_spell_text(lua_State *L) +{ + const struct locale * loc = default_locale; + spell * self = (spell *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, spell_info(self, loc)); + return 1; +} + +static int +tolua_get_spell_school(lua_State *L) +{ + spell * self = (spell *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, magic_school[self->magietyp]); + return 1; +} + +static int +tolua_get_spell_level(lua_State *L) +{ + spell * self = (spell *)tolua_tousertype(L, 1, 0); + lua_pushnumber(L, self->level); + return 1; +} + +static int +tolua_get_spell_name(lua_State *L) +{ + const struct locale * lang = default_locale; + spell * self = (spell *)tolua_tousertype(L, 1, 0); + lua_pushstring(L, spell_name(self, lang)); + return 1; +} + +static int tolua_get_spells(lua_State* L) +{ + spell_list * slist = spells; + if (slist) { + spell_list ** spell_ptr = (spell_list **)lua_newuserdata(L, sizeof(spell_list *)); + luaL_getmetatable(L, "spell_list"); + lua_setmetatable(L, -2); + + *spell_ptr = slist; + lua_pushcclosure(L, tolua_spelllist_next, 1); + return 1; + } + + lua_pushnil(L); + return 1; +} + +int +tolua_read_xml(lua_State* L) +{ + const char * filename = tolua_tostring(L, 1, 0); + const char * catalog = tolua_tostring(L, 2, 0); + init_data(filename, catalog); + return 0; +} + +int tolua_process_markets(lua_State* L) { + do_markets(); + return 0; +} + +int tolua_process_produce(lua_State* L) { + region * r; + for (r=regions;r;r=r->next) { + produce(r); + } + return 0; +} + +typedef struct event_args { + int hfunction; + int hargs; + const char * sendertype; +} event_args; + +static void args_free(void * udata) +{ + free(udata); +} + +static void event_cb(void * sender, const char * event, void * udata) { + lua_State * L = (lua_State *)global.vm_state; + event_args * args = (event_args *)udata; + int nargs = 2; + + lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); + if (sender && args->sendertype) { + tolua_pushusertype(L, sender, TOLUA_CAST args->sendertype); + } else { + lua_pushnil(L); + } + tolua_pushstring(L, event); + if (args->hargs) { + lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); + ++nargs; + } + lua_pcall(L, nargs, 0, 0); +} + +static int +tolua_eventbus_register(lua_State * L) +{ + /* parameters: + ** 1: sender (usertype) + ** 2: event (string) + ** 3: handler (function) + ** 4: arguments (any, *optional*) + */ + void * sender = tolua_tousertype(L, 1, 0); + const char * event = tolua_tostring(L, 2, 0); + event_args * args = malloc(sizeof(event_args)); + + args->sendertype = sender?tolua_typename(L, 1):NULL; + lua_pushvalue(L, 3); + args->hfunction = luaL_ref(L, LUA_REGISTRYINDEX); + if (lua_type(L, 4)!=LUA_TNONE) { + lua_pushvalue(L, 4); + args->hargs = luaL_ref(L, LUA_REGISTRYINDEX); + } else { + args->hargs = 0; + } + eventbus_register(sender, event, &event_cb, &args_free, args); + return 0; +} + +static int +tolua_eventbus_fire(lua_State * L) +{ + void * sender = tolua_tousertype(L, 1, 0); + const char * event = tolua_tostring(L, 2, 0); + void * args = NULL; + eventbus_fire(sender, event, args); + return 0; +} + +static void +parse_inifile(lua_State* L, dictionary * d, const char * section) +{ + int i; + size_t len = strlen(section); + for (i=0;d && i!=d->n;++i) { + const char * key = d->key[i]; + + if (strncmp(section, key, len)==0 && key[len]==':') { + const char * str_value = d->val[i]; + char * endp; + double num_value = strtod(str_value, &endp); + lua_pushstring(L, key + len + 1); + if (*endp) { + tolua_pushstring(L, str_value); + } else { + tolua_pushnumber(L, num_value); + } + lua_rawset(L,-3); + } + } + /* special case */ + lua_pushstring(L, "basepath"); + lua_pushstring(L, basepath()); + lua_rawset(L,-3); +} + +int +tolua_eressea_open(lua_State* L) +{ + tolua_open(L); + + /* register user types */ + tolua_usertype(L, TOLUA_CAST "spell"); + tolua_usertype(L, TOLUA_CAST "spell_list"); + tolua_usertype(L, TOLUA_CAST "order"); + tolua_usertype(L, TOLUA_CAST "item"); + tolua_usertype(L, TOLUA_CAST "alliance"); + tolua_usertype(L, TOLUA_CAST "event"); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_module(L, "process", 0); + tolua_beginmodule(L, "process"); + { + tolua_function(L, "markets", &tolua_process_markets); + tolua_function(L, "produce", &tolua_process_produce); + } + tolua_endmodule(L); + + tolua_cclass(L, TOLUA_CAST "alliance", TOLUA_CAST "alliance", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "alliance"); + { + tolua_variable(L, TOLUA_CAST "name", tolua_get_alliance_name, tolua_set_alliance_name); + tolua_variable(L, TOLUA_CAST "id", tolua_get_alliance_id, NULL); + tolua_variable(L, TOLUA_CAST "factions", &tolua_get_alliance_factions, NULL); + tolua_function(L, TOLUA_CAST "create", tolua_alliance_create); + } + tolua_endmodule(L); + + tolua_cclass(L, TOLUA_CAST "spell", TOLUA_CAST "spell", TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "spell"); + { + tolua_function(L, TOLUA_CAST "__tostring", tolua_get_spell_name); + tolua_variable(L, TOLUA_CAST "name", tolua_get_spell_name, 0); + tolua_variable(L, TOLUA_CAST "school", tolua_get_spell_school, 0); + tolua_variable(L, TOLUA_CAST "level", tolua_get_spell_level, 0); + tolua_variable(L, TOLUA_CAST "text", tolua_get_spell_text, 0); + } + tolua_endmodule(L); + + tolua_module(L, TOLUA_CAST "eventbus", 1); + tolua_beginmodule(L, TOLUA_CAST "eventbus"); + { + tolua_function(L, TOLUA_CAST "register", &tolua_eventbus_register); + tolua_function(L, TOLUA_CAST "fire", &tolua_eventbus_fire); + } + tolua_endmodule(L); + + tolua_module(L, TOLUA_CAST "config", 1); + tolua_beginmodule(L, TOLUA_CAST "config"); + { + parse_inifile(L, global.inifile, "config"); + tolua_variable(L, TOLUA_CAST "locales", &tolua_get_locales, 0); + } + tolua_endmodule(L); + + tolua_function(L, TOLUA_CAST "get_region_by_id", tolua_get_region_byid); + tolua_function(L, TOLUA_CAST "get_faction", tolua_get_faction); + tolua_function(L, TOLUA_CAST "get_unit", tolua_get_unit); + tolua_function(L, TOLUA_CAST "get_alliance", tolua_get_alliance); + tolua_function(L, TOLUA_CAST "get_ship", tolua_get_ship), + tolua_function(L, TOLUA_CAST "get_building", tolua_get_building), + tolua_function(L, TOLUA_CAST "get_region", tolua_get_region), + + // deprecated_function(L, TOLUA_CAST "add_faction"); + // deprecated_function(L, TOLUA_CAST "faction_origin"); + tolua_function(L, TOLUA_CAST "factions", tolua_get_factions); + tolua_function(L, TOLUA_CAST "regions", tolua_get_regions); + + tolua_function(L, TOLUA_CAST "read_turn", tolua_read_turn); + tolua_function(L, TOLUA_CAST "read_game", tolua_read_game); + tolua_function(L, TOLUA_CAST "write_game", tolua_write_game); + tolua_function(L, TOLUA_CAST "free_game", tolua_free_game); + tolua_function(L, TOLUA_CAST "write_map", &tolua_write_map); + + tolua_function(L, TOLUA_CAST "read_orders", tolua_read_orders); + tolua_function(L, TOLUA_CAST "process_orders", tolua_process_orders); + + tolua_function(L, TOLUA_CAST "init_reports", tolua_init_reports); + tolua_function(L, TOLUA_CAST "write_reports", tolua_write_reports); + tolua_function(L, TOLUA_CAST "write_report", tolua_write_report); + + tolua_function(L, TOLUA_CAST "init_summary", tolua_init_summary); + tolua_function(L, TOLUA_CAST "write_summary", tolua_write_summary); + tolua_function(L, TOLUA_CAST "write_passwords", tolua_write_passwords), + + tolua_function(L, TOLUA_CAST "message_unit", tolua_message_unit); + tolua_function(L, TOLUA_CAST "message_faction", tolua_message_faction); + tolua_function(L, TOLUA_CAST "message_region", tolua_message_region); + + /* scripted monsters */ + tolua_function(L, TOLUA_CAST "spawn_braineaters", tolua_spawn_braineaters); + +#ifdef TODO_FOSS + /* spells and stuff */ + tolua_function(L, TOLUA_CAST "levitate_ship", tolua_levitate_ship); +#endif + + tolua_function(L, TOLUA_CAST "update_guards", tolua_update_guards); + + tolua_function(L, TOLUA_CAST "set_turn", &tolua_set_turn); + tolua_function(L, TOLUA_CAST "get_turn", &tolua_get_turn); + tolua_function(L, TOLUA_CAST "get_season", tolua_get_season); + + tolua_function(L, TOLUA_CAST "equipment_setitem", tolua_equipment_setitem); + tolua_function(L, TOLUA_CAST "equip_unit", tolua_equipunit); + tolua_function(L, TOLUA_CAST "add_equipment", tolua_addequipment); + + tolua_function(L, TOLUA_CAST "atoi36", tolua_atoi36); + tolua_function(L, TOLUA_CAST "itoa36", tolua_itoa36); + tolua_function(L, TOLUA_CAST "dice_roll", tolua_dice_rand); + + tolua_function(L, TOLUA_CAST "get_nmrs", tolua_get_nmrs); + tolua_function(L, TOLUA_CAST "remove_empty_units", tolua_remove_empty_units); + + tolua_function(L, TOLUA_CAST "update_subscriptions", tolua_update_subscriptions); + tolua_function(L, TOLUA_CAST "update_scores", tolua_update_scores); + tolua_function(L, TOLUA_CAST "update_owners", tolua_update_owners); + + tolua_function(L, TOLUA_CAST "learn_skill", tolua_learn_skill); + tolua_function(L, TOLUA_CAST "create_curse", tolua_create_curse); + + tolua_function(L, TOLUA_CAST "autoseed", tolua_autoseed); + + tolua_function(L, TOLUA_CAST "get_key", tolua_getkey); + tolua_function(L, TOLUA_CAST "set_key", tolua_setkey); + + tolua_function(L, TOLUA_CAST "translate", &tolua_translate); + + tolua_function(L, TOLUA_CAST "rng_int", tolua_rng_int); + + tolua_function(L, TOLUA_CAST "spells", tolua_get_spells); + tolua_function(L, TOLUA_CAST "write_spells", tolua_write_spells); + + tolua_function(L, TOLUA_CAST "read_xml", tolua_read_xml); + + } + tolua_endmodule(L); + return 1; +} diff --git a/src/bindings/bindings.h b/src/bindings/bindings.h index 0cc1a1d42..5ed8d6232 100644 --- a/src/bindings/bindings.h +++ b/src/bindings/bindings.h @@ -1,27 +1,27 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - int tolua_sqlite_open(struct lua_State * L); - int tolua_eressea_open(struct lua_State* L); - int tolua_spelllist_next(struct lua_State *L); - int tolua_itemlist_next(struct lua_State *L); - int tolua_orderlist_next(struct lua_State *L); - - int log_lua_error(struct lua_State * L); -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + int tolua_sqlite_open(struct lua_State * L); + int tolua_eressea_open(struct lua_State* L); + int tolua_spelllist_next(struct lua_State *L); + int tolua_itemlist_next(struct lua_State *L); + int tolua_orderlist_next(struct lua_State *L); + + int log_lua_error(struct lua_State * L); +#ifdef __cplusplus +} +#endif diff --git a/src/bindings/helpers.c b/src/bindings/helpers.c index db1aaa6e9..6395bce35 100644 --- a/src/bindings/helpers.c +++ b/src/bindings/helpers.c @@ -1,664 +1,664 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include "helpers.h" -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include - -static int -lua_giveitem(unit * s, unit * d, const item_type * itype, int n, struct order * ord) -{ - lua_State * L = (lua_State *)global.vm_state; - char fname[64]; - int result = -1; - const char * iname = itype->rtype->_name[0]; - - assert(s!=NULL); - strcat(strcpy(fname, iname), "_give"); - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, s, TOLUA_CAST "unit"); - tolua_pushusertype(L, d, TOLUA_CAST "unit"); - tolua_pushstring(L, iname); - tolua_pushnumber(L, (lua_Number)n); - - if (lua_pcall(L, 4, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("unit %s calling '%s': %s.\n", - unitname(s), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("unit %s trying to call '%s' : not a function.\n", - unitname(s), fname)); - lua_pop(L, 1); - } - - return result; -} - -static int -limit_resource(const region * r, const resource_type * rtype) -{ - char fname[64]; - int result = -1; - lua_State * L = (lua_State *)global.vm_state; - - snprintf(fname, sizeof(fname), "%s_limit", rtype->_name[0]); - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); - - if (lua_pcall(L, 1, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("limit(%s) calling '%s': %s.\n", - regionname(r, NULL), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("limit(%s) calling '%s': not a function.\n", - regionname(r, NULL), fname)); - lua_pop(L, 1); - } - - return result; -} - -static void -produce_resource(region * r, const resource_type * rtype, int norders) -{ - lua_State * L = (lua_State *)global.vm_state; - char fname[64]; - snprintf(fname, sizeof(fname), "%s_produce", rtype->_name[0]); - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); - tolua_pushnumber(L, (lua_Number)norders); - - if (lua_pcall(L, 2, 0, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("produce(%s) calling '%s': %s.\n", - regionname(r, NULL), fname, error)); - lua_pop(L, 1); - } - } else { - log_error(("produce(%s) calling '%s': not a function.\n", - regionname(r, NULL), fname)); - lua_pop(L, 1); - } -} - - -static int -lc_age(struct attrib * a) -{ - building_action * data = (building_action*)a->data.v; - const char * fname = data->fname; - const char * fparam = data->param; - building * b = data->b; - int result = -1; - - assert(b!=NULL); - if (fname!=NULL) { - lua_State * L = (lua_State *)global.vm_state; - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); - if (fparam) { - tolua_pushstring(L, fparam); - } - - if (lua_pcall(L, fparam?2:1, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("lc_age(%s) calling '%s': %s.\n", - buildingname(b), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("lc_age(%s) calling '%s': not a function.\n", - buildingname(b), fname)); - lua_pop(L, 1); - } - } - return (result!=0)?AT_AGE_KEEP:AT_AGE_REMOVE; -} - -static void push_param(lua_State * L, char c, spllprm * param) -{ - if (c=='u') tolua_pushusertype(L, param->data.u, "unit"); - else if (c=='b') tolua_pushusertype(L, param->data.b, "building"); - else if (c=='s') tolua_pushusertype(L, param->data.sh, "ship"); - else if (c=='r') tolua_pushusertype(L, param->data.sh, "region"); - else if (c=='c') tolua_pushstring(L, param->data.s); - else { - log_error(("unsupported syntax %c.\n", c)); - lua_pushnil(L); - } -} - -/** callback to use lua for spell functions */ -static int -lua_callspell(castorder *co) -{ - lua_State * L = (lua_State *)global.vm_state; - const char * fname = co->sp->sname; - unit * mage = co->familiar?co->familiar:co->magician.u; - int result = -1; - const char * hashpos = strchr(fname, '#'); - char fbuf[64]; - - if (hashpos!=NULL) { - ptrdiff_t len = hashpos - fname; - assert(len<(ptrdiff_t)sizeof(fbuf)); - strncpy(fbuf, fname, len); - fbuf[len] = '\0'; - fname = fbuf; - } - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - int nparam = 4; - tolua_pushusertype(L, co->rt, TOLUA_CAST "region"); - tolua_pushusertype(L, mage, TOLUA_CAST "unit"); - tolua_pushnumber(L, (lua_Number)co->level); - tolua_pushnumber(L, (lua_Number)co->force); - if (co->sp->parameter && co->par->length) { - const char * synp = co->sp->parameter; - int i = 0; - ++nparam; - lua_newtable(L); - while (*synp&&ipar->length) { - spllprm * param = co->par->param[i]; - char c = *synp; - if (c=='+') { - push_param(L, *(synp-1), param); - } else { - push_param(L, c, param); - ++synp; - } - lua_rawseti(L, -2, ++i); - } - } - - if (lua_pcall(L, nparam, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("spell(%s) calling '%s': %s.\n", - unitname(mage), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("spell(%s) calling '%s': not a function.\n", - unitname(mage), fname)); - lua_pop(L, 1); - } - - return result; -} - -/** callback to initialize a familiar from lua. */ -static void -lua_initfamiliar(unit * u) -{ - lua_State * L = (lua_State *)global.vm_state; - char fname[64]; - int result = -1; - snprintf(fname, sizeof(fname), "initfamiliar_%s", u->race->_name[0]); - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, u, TOLUA_CAST "unit"); - - if (lua_pcall(L, 1, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("familiar(%s) calling '%s': %s.\n", - unitname(u), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_warning(("familiar(%s) calling '%s': not a function.\n", - unitname(u), fname)); - lua_pop(L, 1); - } - - create_mage(u, M_GRAY); - - snprintf(fname, sizeof(fname), "%s_familiar", u->race->_name[0]); - equip_unit(u, get_equipment(fname)); -} - -static int -lua_changeresource(unit * u, const struct resource_type * rtype, int delta) -{ - lua_State * L = (lua_State *)global.vm_state; - int result = -1; - char fname[64]; - snprintf(fname, sizeof(fname), "%s_changeresource", rtype->_name[0]); - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, u, TOLUA_CAST "unit"); - tolua_pushnumber(L, (lua_Number)delta); - - if (lua_pcall(L, 2, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("change(%s) calling '%s': %s.\n", - unitname(u), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("change(%s) calling '%s': not a function.\n", - unitname(u), fname)); - lua_pop(L, 1); - } - - return result; -} - -static int -lua_getresource(unit * u, const struct resource_type * rtype) -{ - lua_State * L = (lua_State *)global.vm_state; - int result = -1; - char fname[64]; - snprintf(fname, sizeof(fname), "%s_getresource", rtype->_name[0]); - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, u, TOLUA_CAST "unit"); - - if (lua_pcall(L, 1, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("get(%s) calling '%s': %s.\n", - unitname(u), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("get(%s) calling '%s': not a function.\n", - unitname(u), fname)); - lua_pop(L, 1); - } - - return result; -} - -static boolean -lua_canuse_item(const unit * u, const struct item_type * itype) -{ - static int function_exists = 1; - boolean result = true; - - if (function_exists) { - lua_State * L = (lua_State *)global.vm_state; - const char * fname = "item_canuse"; - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); - tolua_pushstring(L, itype->rtype->_name[0]); - - if (lua_pcall(L, 2, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("get(%s) calling '%s': %s.\n", - unitname(u), fname, error)); - lua_pop(L, 1); - } else { - result = lua_toboolean(L, -1); - lua_pop(L, 1); - } - } else { - function_exists = 0; - log_error(("get(%s) calling '%s': not a function.\n", - unitname(u), fname)); - lua_pop(L, 1); - } - } - return result; -} - -static int -lua_wage(const region * r, const faction * f, const race * rc, int in_turn) -{ - lua_State * L = (lua_State *)global.vm_state; - const char * fname = "wage"; - int result = -1; - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); - tolua_pushusertype(L, (void *)f, TOLUA_CAST "faction"); - tolua_pushstring(L, rc?rc->_name[0]:0); - tolua_pushnumber(L, (lua_Number)in_turn); - - if (lua_pcall(L, 3, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("wage(%s) calling '%s': %s.\n", - regionname(r, NULL), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("wage(%s) calling '%s': not a function.\n", - regionname(r, NULL), fname)); - lua_pop(L, 1); - } - - return result; -} - -static void -lua_agebuilding(building * b) -{ - lua_State * L = (lua_State *)global.vm_state; - char fname[64]; - - snprintf(fname, sizeof(fname), "age_%s", b->type->_name); - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); - - if (lua_pcall(L, 1, 0, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("agebuilding(%s) calling '%s': %s.\n", - buildingname(b), fname, error)); - lua_pop(L, 1); - } - } else { - log_error(("agebuilding(%s) calling '%s': not a function.\n", - buildingname(b), fname)); - lua_pop(L, 1); - } -} - -static int -lua_building_protection(building * b, unit * u) -{ - lua_State * L = (lua_State *)global.vm_state; - const char * fname = "building_protection"; - int result = 0; - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); - tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); - - if (lua_pcall(L, 2, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("building_protection(%s, %s) calling '%s': %s.\n", - buildingname(b), unitname(u), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("building_protection(%s, %s) calling '%s': not a function.\n", - buildingname(b), unitname(u), fname)); - lua_pop(L, 1); - } - return result; -} - -static double -lua_building_taxes(building * b, int level) -{ - lua_State * L = (lua_State *)global.vm_state; - const char * fname = "building_taxes"; - double result = 0.0F; - int type; - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - type=lua_type(L, 1); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); - tolua_pushnumber(L, level); - - if (lua_pcall(L, 2, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("building_taxes(%s) calling '%s': %s.\n", - buildingname(b), fname, error)); - lua_pop(L, 1); - } else { - result = (double)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("building_taxes(%s) calling '%s': not a function.\n", - buildingname(b), fname)); - lua_pop(L, 1); - } - return result; -} - -static int -lua_maintenance(const unit * u) -{ - lua_State * L = (lua_State *)global.vm_state; - const char * fname = "maintenance"; - int result = -1; - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); - - if (lua_pcall(L, 1, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("maintenance(%s) calling '%s': %s.\n", - unitname(u), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("maintenance(%s) calling '%s': not a function.\n", - unitname(u), fname)); - lua_pop(L, 1); - } - - return result; -} - -static void -lua_equipmentcallback(const struct equipment * eq, unit * u) -{ - lua_State * L = (lua_State *)global.vm_state; - char fname[64]; - int result = -1; - snprintf(fname, sizeof(fname), "equip_%s", eq->name); - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); - - if (lua_pcall(L, 1, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("equip(%s) calling '%s': %s.\n", - unitname(u), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("equip(%s) calling '%s': not a function.\n", - unitname(u), fname)); - lua_pop(L, 1); - } -} - -/** callback for an item-use function written in lua. */ -int -lua_useitem(struct unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - lua_State * L = (lua_State *)global.vm_state; - int result = 0; - char fname[64]; - snprintf(fname, sizeof(fname), "use_%s", itype->rtype->_name[0]); - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); - tolua_pushnumber(L, (lua_Number)amount); - - if (lua_pcall(L, 2, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("use(%s) calling '%s': %s.\n", - unitname(u), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("use(%s) calling '%s': not a function.\n", - unitname(u), fname)); - lua_pop(L, 1); - } - - return result; -} - -static int -lua_recruit(struct unit * u, const struct archetype * arch, int amount) -{ - lua_State * L = (lua_State *)global.vm_state; - int result = 0; - char fname[64]; - snprintf(fname, sizeof(fname), "recruit_%s", arch->name[0]); - - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { - tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); - tolua_pushnumber(L, (lua_Number)amount); - - if (lua_pcall(L, 2, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("use(%s) calling '%s': %s.\n", - unitname(u), fname, error)); - lua_pop(L, 1); - } else { - result = (int)lua_tonumber(L, -1); - lua_pop(L, 1); - } - } else { - log_error(("use(%s) calling '%s': not a function.\n", - unitname(u), fname)); - lua_pop(L, 1); - } - return result; -} - -int -tolua_toid(lua_State* L, int idx, int def) -{ - int no = 0; - int type = lua_type(L, idx); - if (type==LUA_TNUMBER) { - no = (int)tolua_tonumber(L, idx, def); - } else { - const char * str = tolua_tostring(L, idx, NULL); - no = str?atoi36(str):def; - } - return no; -} - -void -register_tolua_helpers(void) -{ - at_building_action.age = lc_age; - - register_function((pf_generic)&lua_building_protection, TOLUA_CAST "lua_building_protection"); - register_function((pf_generic)&lua_building_taxes, TOLUA_CAST "lua_building_taxes"); - register_function((pf_generic)&lua_agebuilding, TOLUA_CAST "lua_agebuilding"); - register_function((pf_generic)&lua_recruit, TOLUA_CAST "lua_recruit"); - register_function((pf_generic)&lua_callspell, TOLUA_CAST "lua_castspell"); - register_function((pf_generic)&lua_initfamiliar, TOLUA_CAST "lua_initfamiliar"); - register_item_use(&lua_useitem, TOLUA_CAST "lua_useitem"); - register_function((pf_generic)&lua_getresource, TOLUA_CAST "lua_getresource"); - register_function((pf_generic)&lua_canuse_item, TOLUA_CAST "lua_canuse_item"); - register_function((pf_generic)&lua_changeresource, TOLUA_CAST "lua_changeresource"); - register_function((pf_generic)&lua_equipmentcallback, TOLUA_CAST "lua_equip"); - - register_function((pf_generic)&lua_wage, TOLUA_CAST "lua_wage"); - register_function((pf_generic)&lua_maintenance, TOLUA_CAST "lua_maintenance"); - - - register_function((pf_generic)produce_resource, TOLUA_CAST "lua_produceresource"); - register_function((pf_generic)limit_resource, TOLUA_CAST "lua_limitresource"); - register_item_give(lua_giveitem, TOLUA_CAST "lua_giveitem"); -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include "helpers.h" +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +static int +lua_giveitem(unit * s, unit * d, const item_type * itype, int n, struct order * ord) +{ + lua_State * L = (lua_State *)global.vm_state; + char fname[64]; + int result = -1; + const char * iname = itype->rtype->_name[0]; + + assert(s!=NULL); + strcat(strcpy(fname, iname), "_give"); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, s, TOLUA_CAST "unit"); + tolua_pushusertype(L, d, TOLUA_CAST "unit"); + tolua_pushstring(L, iname); + tolua_pushnumber(L, (lua_Number)n); + + if (lua_pcall(L, 4, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("unit %s calling '%s': %s.\n", + unitname(s), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("unit %s trying to call '%s' : not a function.\n", + unitname(s), fname)); + lua_pop(L, 1); + } + + return result; +} + +static int +limit_resource(const region * r, const resource_type * rtype) +{ + char fname[64]; + int result = -1; + lua_State * L = (lua_State *)global.vm_state; + + snprintf(fname, sizeof(fname), "%s_limit", rtype->_name[0]); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); + + if (lua_pcall(L, 1, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("limit(%s) calling '%s': %s.\n", + regionname(r, NULL), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("limit(%s) calling '%s': not a function.\n", + regionname(r, NULL), fname)); + lua_pop(L, 1); + } + + return result; +} + +static void +produce_resource(region * r, const resource_type * rtype, int norders) +{ + lua_State * L = (lua_State *)global.vm_state; + char fname[64]; + snprintf(fname, sizeof(fname), "%s_produce", rtype->_name[0]); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); + tolua_pushnumber(L, (lua_Number)norders); + + if (lua_pcall(L, 2, 0, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("produce(%s) calling '%s': %s.\n", + regionname(r, NULL), fname, error)); + lua_pop(L, 1); + } + } else { + log_error(("produce(%s) calling '%s': not a function.\n", + regionname(r, NULL), fname)); + lua_pop(L, 1); + } +} + + +static int +lc_age(struct attrib * a) +{ + building_action * data = (building_action*)a->data.v; + const char * fname = data->fname; + const char * fparam = data->param; + building * b = data->b; + int result = -1; + + assert(b!=NULL); + if (fname!=NULL) { + lua_State * L = (lua_State *)global.vm_state; + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); + if (fparam) { + tolua_pushstring(L, fparam); + } + + if (lua_pcall(L, fparam?2:1, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("lc_age(%s) calling '%s': %s.\n", + buildingname(b), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("lc_age(%s) calling '%s': not a function.\n", + buildingname(b), fname)); + lua_pop(L, 1); + } + } + return (result!=0)?AT_AGE_KEEP:AT_AGE_REMOVE; +} + +static void push_param(lua_State * L, char c, spllprm * param) +{ + if (c=='u') tolua_pushusertype(L, param->data.u, "unit"); + else if (c=='b') tolua_pushusertype(L, param->data.b, "building"); + else if (c=='s') tolua_pushusertype(L, param->data.sh, "ship"); + else if (c=='r') tolua_pushusertype(L, param->data.sh, "region"); + else if (c=='c') tolua_pushstring(L, param->data.s); + else { + log_error(("unsupported syntax %c.\n", c)); + lua_pushnil(L); + } +} + +/** callback to use lua for spell functions */ +static int +lua_callspell(castorder *co) +{ + lua_State * L = (lua_State *)global.vm_state; + const char * fname = co->sp->sname; + unit * mage = co->familiar?co->familiar:co->magician.u; + int result = -1; + const char * hashpos = strchr(fname, '#'); + char fbuf[64]; + + if (hashpos!=NULL) { + ptrdiff_t len = hashpos - fname; + assert(len<(ptrdiff_t)sizeof(fbuf)); + strncpy(fbuf, fname, len); + fbuf[len] = '\0'; + fname = fbuf; + } + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + int nparam = 4; + tolua_pushusertype(L, co->rt, TOLUA_CAST "region"); + tolua_pushusertype(L, mage, TOLUA_CAST "unit"); + tolua_pushnumber(L, (lua_Number)co->level); + tolua_pushnumber(L, (lua_Number)co->force); + if (co->sp->parameter && co->par->length) { + const char * synp = co->sp->parameter; + int i = 0; + ++nparam; + lua_newtable(L); + while (*synp&&ipar->length) { + spllprm * param = co->par->param[i]; + char c = *synp; + if (c=='+') { + push_param(L, *(synp-1), param); + } else { + push_param(L, c, param); + ++synp; + } + lua_rawseti(L, -2, ++i); + } + } + + if (lua_pcall(L, nparam, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("spell(%s) calling '%s': %s.\n", + unitname(mage), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("spell(%s) calling '%s': not a function.\n", + unitname(mage), fname)); + lua_pop(L, 1); + } + + return result; +} + +/** callback to initialize a familiar from lua. */ +static void +lua_initfamiliar(unit * u) +{ + lua_State * L = (lua_State *)global.vm_state; + char fname[64]; + int result = -1; + snprintf(fname, sizeof(fname), "initfamiliar_%s", u->race->_name[0]); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + + if (lua_pcall(L, 1, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("familiar(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_warning(("familiar(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } + + create_mage(u, M_GRAY); + + snprintf(fname, sizeof(fname), "%s_familiar", u->race->_name[0]); + equip_unit(u, get_equipment(fname)); +} + +static int +lua_changeresource(unit * u, const struct resource_type * rtype, int delta) +{ + lua_State * L = (lua_State *)global.vm_state; + int result = -1; + char fname[64]; + snprintf(fname, sizeof(fname), "%s_changeresource", rtype->_name[0]); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + tolua_pushnumber(L, (lua_Number)delta); + + if (lua_pcall(L, 2, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("change(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("change(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } + + return result; +} + +static int +lua_getresource(unit * u, const struct resource_type * rtype) +{ + lua_State * L = (lua_State *)global.vm_state; + int result = -1; + char fname[64]; + snprintf(fname, sizeof(fname), "%s_getresource", rtype->_name[0]); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + + if (lua_pcall(L, 1, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("get(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("get(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } + + return result; +} + +static boolean +lua_canuse_item(const unit * u, const struct item_type * itype) +{ + static int function_exists = 1; + boolean result = true; + + if (function_exists) { + lua_State * L = (lua_State *)global.vm_state; + const char * fname = "item_canuse"; + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); + tolua_pushstring(L, itype->rtype->_name[0]); + + if (lua_pcall(L, 2, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("get(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = lua_toboolean(L, -1); + lua_pop(L, 1); + } + } else { + function_exists = 0; + log_error(("get(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } + } + return result; +} + +static int +lua_wage(const region * r, const faction * f, const race * rc, int in_turn) +{ + lua_State * L = (lua_State *)global.vm_state; + const char * fname = "wage"; + int result = -1; + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); + tolua_pushusertype(L, (void *)f, TOLUA_CAST "faction"); + tolua_pushstring(L, rc?rc->_name[0]:0); + tolua_pushnumber(L, (lua_Number)in_turn); + + if (lua_pcall(L, 3, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("wage(%s) calling '%s': %s.\n", + regionname(r, NULL), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("wage(%s) calling '%s': not a function.\n", + regionname(r, NULL), fname)); + lua_pop(L, 1); + } + + return result; +} + +static void +lua_agebuilding(building * b) +{ + lua_State * L = (lua_State *)global.vm_state; + char fname[64]; + + snprintf(fname, sizeof(fname), "age_%s", b->type->_name); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); + + if (lua_pcall(L, 1, 0, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("agebuilding(%s) calling '%s': %s.\n", + buildingname(b), fname, error)); + lua_pop(L, 1); + } + } else { + log_error(("agebuilding(%s) calling '%s': not a function.\n", + buildingname(b), fname)); + lua_pop(L, 1); + } +} + +static int +lua_building_protection(building * b, unit * u) +{ + lua_State * L = (lua_State *)global.vm_state; + const char * fname = "building_protection"; + int result = 0; + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); + + if (lua_pcall(L, 2, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("building_protection(%s, %s) calling '%s': %s.\n", + buildingname(b), unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("building_protection(%s, %s) calling '%s': not a function.\n", + buildingname(b), unitname(u), fname)); + lua_pop(L, 1); + } + return result; +} + +static double +lua_building_taxes(building * b, int level) +{ + lua_State * L = (lua_State *)global.vm_state; + const char * fname = "building_taxes"; + double result = 0.0F; + int type; + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + type=lua_type(L, 1); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); + tolua_pushnumber(L, level); + + if (lua_pcall(L, 2, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("building_taxes(%s) calling '%s': %s.\n", + buildingname(b), fname, error)); + lua_pop(L, 1); + } else { + result = (double)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("building_taxes(%s) calling '%s': not a function.\n", + buildingname(b), fname)); + lua_pop(L, 1); + } + return result; +} + +static int +lua_maintenance(const unit * u) +{ + lua_State * L = (lua_State *)global.vm_state; + const char * fname = "maintenance"; + int result = -1; + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); + + if (lua_pcall(L, 1, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("maintenance(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("maintenance(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } + + return result; +} + +static void +lua_equipmentcallback(const struct equipment * eq, unit * u) +{ + lua_State * L = (lua_State *)global.vm_state; + char fname[64]; + int result = -1; + snprintf(fname, sizeof(fname), "equip_%s", eq->name); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); + + if (lua_pcall(L, 1, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("equip(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("equip(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } +} + +/** callback for an item-use function written in lua. */ +int +lua_useitem(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + lua_State * L = (lua_State *)global.vm_state; + int result = 0; + char fname[64]; + snprintf(fname, sizeof(fname), "use_%s", itype->rtype->_name[0]); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); + tolua_pushnumber(L, (lua_Number)amount); + + if (lua_pcall(L, 2, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("use(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("use(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } + + return result; +} + +static int +lua_recruit(struct unit * u, const struct archetype * arch, int amount) +{ + lua_State * L = (lua_State *)global.vm_state; + int result = 0; + char fname[64]; + snprintf(fname, sizeof(fname), "recruit_%s", arch->name[0]); + + lua_pushstring(L, fname); + lua_rawget(L, LUA_GLOBALSINDEX); + if (lua_isfunction(L, 1)) { + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); + tolua_pushnumber(L, (lua_Number)amount); + + if (lua_pcall(L, 2, 1, 0)!=0) { + const char* error = lua_tostring(L, -1); + log_error(("use(%s) calling '%s': %s.\n", + unitname(u), fname, error)); + lua_pop(L, 1); + } else { + result = (int)lua_tonumber(L, -1); + lua_pop(L, 1); + } + } else { + log_error(("use(%s) calling '%s': not a function.\n", + unitname(u), fname)); + lua_pop(L, 1); + } + return result; +} + +int +tolua_toid(lua_State* L, int idx, int def) +{ + int no = 0; + int type = lua_type(L, idx); + if (type==LUA_TNUMBER) { + no = (int)tolua_tonumber(L, idx, def); + } else { + const char * str = tolua_tostring(L, idx, NULL); + no = str?atoi36(str):def; + } + return no; +} + +void +register_tolua_helpers(void) +{ + at_building_action.age = lc_age; + + register_function((pf_generic)&lua_building_protection, TOLUA_CAST "lua_building_protection"); + register_function((pf_generic)&lua_building_taxes, TOLUA_CAST "lua_building_taxes"); + register_function((pf_generic)&lua_agebuilding, TOLUA_CAST "lua_agebuilding"); + register_function((pf_generic)&lua_recruit, TOLUA_CAST "lua_recruit"); + register_function((pf_generic)&lua_callspell, TOLUA_CAST "lua_castspell"); + register_function((pf_generic)&lua_initfamiliar, TOLUA_CAST "lua_initfamiliar"); + register_item_use(&lua_useitem, TOLUA_CAST "lua_useitem"); + register_function((pf_generic)&lua_getresource, TOLUA_CAST "lua_getresource"); + register_function((pf_generic)&lua_canuse_item, TOLUA_CAST "lua_canuse_item"); + register_function((pf_generic)&lua_changeresource, TOLUA_CAST "lua_changeresource"); + register_function((pf_generic)&lua_equipmentcallback, TOLUA_CAST "lua_equip"); + + register_function((pf_generic)&lua_wage, TOLUA_CAST "lua_wage"); + register_function((pf_generic)&lua_maintenance, TOLUA_CAST "lua_maintenance"); + + + register_function((pf_generic)produce_resource, TOLUA_CAST "lua_produceresource"); + register_function((pf_generic)limit_resource, TOLUA_CAST "lua_limitresource"); + register_item_give(lua_giveitem, TOLUA_CAST "lua_giveitem"); +} diff --git a/src/bindings/helpers.h b/src/bindings/helpers.h index 4e0da152f..8d3370650 100644 --- a/src/bindings/helpers.h +++ b/src/bindings/helpers.h @@ -1,23 +1,23 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - void register_tolua_helpers(void); - int tolua_toid(struct lua_State* L, int idx, int def); - -#ifdef __cplusplus -} -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + void register_tolua_helpers(void); + int tolua_toid(struct lua_State* L, int idx, int def); + +#ifdef __cplusplus +} +#endif diff --git a/src/build/atoi36.c b/src/build/atoi36.c index 7965d78f6..4f896a1e7 100644 --- a/src/build/atoi36.c +++ b/src/build/atoi36.c @@ -1,6 +1,6 @@ -#include "common/settings.h" -#include "common/config.h" -#include "stdafx.h" - -#include "common/util/base36.c" -#include "tools/atoi36.c" +#include "common/settings.h" +#include "common/config.h" +#include "stdafx.h" + +#include "common/util/base36.c" +#include "tools/atoi36.c" diff --git a/src/build/external.c b/src/build/external.c index 010ac20db..a882ce3fe 100644 --- a/src/build/external.c +++ b/src/build/external.c @@ -1,18 +1,18 @@ -#include -#include -#include "stdafx.h" - -#pragma warning(push) -#pragma warning(disable: 4244) -#pragma warning(disable: 4127) -#include -#pragma warning(pop) - -#include - -#include -#include - -#ifndef DISABLE_TESTS -#include -#endif +#include +#include +#include "stdafx.h" + +#pragma warning(push) +#pragma warning(disable: 4244) +#pragma warning(disable: 4127) +#include +#pragma warning(pop) + +#include + +#include +#include + +#ifndef DISABLE_TESTS +#include +#endif diff --git a/src/build/gamecode.c b/src/build/gamecode.c index 2d3dfbdfd..63120bde0 100644 --- a/src/build/gamecode.c +++ b/src/build/gamecode.c @@ -1,80 +1,80 @@ -#include -#include -#include "stdafx.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_CURSES -#include -#endif - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include "stdafx.h" + +#ifdef BINDINGS_TOLUA +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/src/build/kernel.c b/src/build/kernel.c index 4fa586933..9ac333f94 100644 --- a/src/build/kernel.c +++ b/src/build/kernel.c @@ -1,58 +1,53 @@ -#include -#include -#include "stdafx.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_LIBXML -#include -#else -void register_xmlreader(void) {} -void enable_xml_gamecode(void) {} -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include "stdafx.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/src/build/lib.c b/src/build/lib.c index 0d6fcdf13..18624376a 100644 --- a/src/build/lib.c +++ b/src/build/lib.c @@ -1,10 +1,7 @@ -#include -#include -#include "stdafx.h" - -#ifdef HAVE_CURSES -#include -#include -#endif - -#include +#include +#include +#include "stdafx.h" + +#include +#include +#include diff --git a/src/build/stdafx.c b/src/build/stdafx.c index a27b824da..fd4f341c7 100644 --- a/src/build/stdafx.c +++ b/src/build/stdafx.c @@ -1 +1 @@ -#include "stdafx.h" +#include "stdafx.h" diff --git a/src/build/stdafx.h b/src/build/stdafx.h index 338582b17..b0d94063d 100644 --- a/src/build/stdafx.h +++ b/src/build/stdafx.h @@ -1,2 +1,2 @@ -#include -#include +#include +#include diff --git a/src/build/util.c b/src/build/util.c index eb602ec6e..dfae8d012 100644 --- a/src/build/util.c +++ b/src/build/util.c @@ -1,40 +1,40 @@ -#include -#include -#include "stdafx.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef HAVE_INLINE -#include -#endif - -#ifdef __GNUC__ -#include -#endif +#include +#include +#include "stdafx.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef HAVE_INLINE +#include +#endif + +#ifdef __GNUC__ +#include +#endif diff --git a/src/eressea.c b/src/eressea.c index a23bb99f4..3a8dd4740 100644 --- a/src/eressea.c +++ b/src/eressea.c @@ -1,211 +1,212 @@ -#include -#include "settings.h" -#include "eressea.h" - -#include -#include -#include - -/* lua includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_CURSES -#include -#endif - -#if MUSEUM_MODULE -#include -#endif -#if ARENA_MODULE -#include -#endif -#include -#include -#ifdef HAVE_LIBXML -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -static const struct { - const char * name; - int (*func)(lua_State *); -} lualibs[] = { - {"", luaopen_base}, - {LUA_TABLIBNAME, luaopen_table}, - {LUA_IOLIBNAME, luaopen_io}, - {LUA_STRLIBNAME, luaopen_string}, - {LUA_MATHLIBNAME, luaopen_math}, - {LUA_LOADLIBNAME, luaopen_package}, - {LUA_DBLIBNAME, luaopen_debug}, -#if LUA_VERSION_NUM>=501 - {LUA_OSLIBNAME, luaopen_os}, -#endif - { NULL, NULL } -}; - -static void -openlibs(lua_State * L) -{ - int i; - for (i=0;lualibs[i].func;++i) { - lua_pushcfunction(L, lualibs[i].func); - lua_pushstring(L, lualibs[i].name); - lua_call(L, 1, 0); - } -} - -static void -lua_done(lua_State * L) -{ - lua_close(L); -} - -static lua_State * -lua_init(void) -{ - lua_State * L = lua_open(); - - openlibs(L); - register_tolua_helpers(); - tolua_eressea_open(L); - tolua_sqlite_open(L); - tolua_unit_open(L); - tolua_building_open(L); - tolua_ship_open(L); - tolua_region_open(L); - tolua_faction_open(L); - tolua_attrib_open(L); - tolua_unit_open(L); - tolua_message_open(L); - tolua_hashtable_open(L); -#ifdef HAVE_CURSES - tolua_gmtool_open(L); -#endif - tolua_storage_open(L); - return L; -} - -static void -game_done(void) -{ -#ifdef CLEANUP_CODE - /* Diese Routine enfernt allen allokierten Speicher wieder. Das ist nur - * zum Debugging interessant, wenn man Leak Detection hat, und nach - * nicht freigegebenem Speicher sucht, der nicht bis zum Ende benötigt - * wird (temporäre Hilsstrukturen) */ - - free_game(); - - creport_cleanup(); -#ifdef REPORT_FORMAT_NR - report_cleanup(); -#endif - calendar_cleanup(); -#endif -} - -static void -game_init(void) -{ - register_triggers(); - register_xmas(); - - register_reports(); - register_nr(); - register_cr(); - - debug_language("locales.log"); - register_names(); - register_resources(); - register_buildings(); - register_itemfunctions(); -#if DUNGEON_MODULE - register_dungeon(); -#endif -#if MUSEUM_MODULE - register_museum(); -#endif -#if ARENA_MODULE - register_arena(); -#endif - register_wormholes(); - - register_itemtypes(); - register_xmlreader(); - register_archetypes(); - enable_xml_gamecode(); - register_attributes(); - register_gmcmd(); - -} - -int eressea_init(void) -{ - global.vm_state = lua_init(); - kernel_init(); - game_init(); - - return 0; -} - -void eressea_done(void) -{ - game_done(); - kernel_done(); - lua_done((lua_State *)global.vm_state); -} - -int eressea_run(const char * luafile, const char * entry_point) -{ - int err; - lua_State * L = (lua_State *)global.vm_state; - /* run the main script */ - if (luafile) { - lua_getglobal(L, "dofile"); - lua_pushstring(L, luafile); - err = lua_pcall(L, 1, 0, 0); - if (err != 0) { - log_lua_error(L); - abort(); - return err; - } - } - if (entry_point) { - lua_getglobal(L, entry_point); - err = lua_pcall(L, 0, 1, 0); - if (err != 0) { - log_lua_error(L); - abort(); - return err; - } - } else { - err = lua_console(L); - } - return err; -} +#include +#include "settings.h" +#include "eressea.h" + +#include +#include +#include + +/* lua includes */ +#ifdef BINDINGS_TOLUA +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // BINDINGS_TOLUA + +#if MUSEUM_MODULE +#include +#endif +#if ARENA_MODULE +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static const struct { + const char * name; + int (*func)(lua_State *); +} lualibs[] = { + {"", luaopen_base}, + {LUA_TABLIBNAME, luaopen_table}, + {LUA_IOLIBNAME, luaopen_io}, + {LUA_STRLIBNAME, luaopen_string}, + {LUA_MATHLIBNAME, luaopen_math}, + {LUA_LOADLIBNAME, luaopen_package}, + {LUA_DBLIBNAME, luaopen_debug}, +#if LUA_VERSION_NUM>=501 + {LUA_OSLIBNAME, luaopen_os}, +#endif + { NULL, NULL } +}; + +static void +openlibs(lua_State * L) +{ + int i; + for (i=0;lualibs[i].func;++i) { + lua_pushcfunction(L, lualibs[i].func); + lua_pushstring(L, lualibs[i].name); + lua_call(L, 1, 0); + } +} + +static void +lua_done(lua_State * L) +{ + lua_close(L); +} + +static lua_State * +lua_init(void) +{ + lua_State * L = lua_open(); + + openlibs(L); +#ifdef BINDINGS_TOLUA + register_tolua_helpers(); + tolua_eressea_open(L); + tolua_sqlite_open(L); + tolua_unit_open(L); + tolua_building_open(L); + tolua_ship_open(L); + tolua_region_open(L); + tolua_faction_open(L); + tolua_attrib_open(L); + tolua_unit_open(L); + tolua_message_open(L); + tolua_hashtable_open(L); + tolua_gmtool_open(L); + tolua_storage_open(L); +#endif + return L; +} + +static void +game_done(void) +{ +#ifdef CLEANUP_CODE + /* Diese Routine enfernt allen allokierten Speicher wieder. Das ist nur + * zum Debugging interessant, wenn man Leak Detection hat, und nach + * nicht freigegebenem Speicher sucht, der nicht bis zum Ende benötigt + * wird (temporäre Hilsstrukturen) */ + + free_game(); + + creport_cleanup(); +#ifdef REPORT_FORMAT_NR + report_cleanup(); +#endif + calendar_cleanup(); +#endif +} + +static void +game_init(void) +{ + register_triggers(); + register_xmas(); + + register_reports(); + register_nr(); + register_cr(); + register_xr(); + + debug_language("locales.log"); + register_names(); + register_resources(); + register_buildings(); + register_itemfunctions(); +#if DUNGEON_MODULE + register_dungeon(); +#endif +#if MUSEUM_MODULE + register_museum(); +#endif +#if ARENA_MODULE + register_arena(); +#endif + register_wormholes(); + + register_itemtypes(); + register_xmlreader(); + register_archetypes(); + enable_xml_gamecode(); + + register_attributes(); + register_gmcmd(); + +} + +int eressea_init(void) +{ + global.vm_state = lua_init(); + kernel_init(); + game_init(); + + return 0; +} + +void eressea_done(void) +{ + game_done(); + kernel_done(); + lua_done((lua_State *)global.vm_state); +} + +int eressea_run(const char * luafile, const char * entry_point) +{ + int err; + lua_State * L = (lua_State *)global.vm_state; + /* run the main script */ + if (luafile) { + lua_getglobal(L, "dofile"); + lua_pushstring(L, luafile); + err = lua_pcall(L, 1, 0, 0); + if (err != 0) { + log_lua_error(L); + abort(); + return err; + } + } + if (entry_point) { + lua_getglobal(L, entry_point); + err = lua_pcall(L, 0, 1, 0); + if (err != 0) { + log_lua_error(L); + abort(); + return err; + } + } else { + err = lua_console(L); + } + return err; +} diff --git a/src/eressea.h b/src/eressea.h index d41339422..c2d15d458 100644 --- a/src/eressea.h +++ b/src/eressea.h @@ -1,15 +1,15 @@ -#ifndef H_ERESSEA_LIB -#define H_ERESSEA_LIB -#ifdef __cplusplus -extern "C" { -#endif - -int eressea_init(void); -void eressea_done(void); -int eressea_run(const char * luafile, const char * entry_point); - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef H_ERESSEA_LIB +#define H_ERESSEA_LIB +#ifdef __cplusplus +extern "C" { +#endif + +int eressea_init(void); +void eressea_done(void); +int eressea_run(const char * luafile, const char * entry_point); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/gamecode/archetype.c b/src/gamecode/archetype.c index 6d634f56a..8f82e7d31 100644 --- a/src/gamecode/archetype.c +++ b/src/gamecode/archetype.c @@ -1,171 +1,165 @@ -#include -#include -#include "archetype.h" - -/* kernel includes */ -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include - -#ifdef HAVE_LIBXML -/* libxml includes */ -#include -#include -#include -#endif - -/* libc includes */ -#include -#include - -static struct archetype * archetypes; - -struct attrib_type at_recruit = { - "recruit", NULL, NULL, NULL, NULL, NULL, ATF_UNIQUE -}; - -const struct archetype * -find_archetype(const char * s, const struct locale * lang) -{ - struct tnode * tokens = get_translations(lang, UT_ARCHETYPES); - variant token; - - if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { - return (const struct archetype *)token.v; - } - return NULL; -} - -void -register_archetype(archetype * arch) -{ - arch->next = archetypes; - archetypes = arch; -} - -void -init_archetypes(void) -{ - const struct locale * lang = locales; - for (;lang;lang=nextlocale(lang)) { - variant var; - archetype * arch = archetypes; - struct tnode * tokens = get_translations(lang, UT_ARCHETYPES); - for (;arch;arch=arch->next) { - const char *s1, *s2; - var.v = arch; - - s1 = LOC(lang, arch->name[0]); - addtoken(tokens, s1, var); - s2 = LOC(lang, arch->name[1]); - if (strcmp(s2, s1)!=0) { - addtoken(tokens, s2, var); - } - } - } -} - -#ifdef HAVE_LIBXML -static int -parse_archetypes(xmlDocPtr doc) -{ - char zName[64]; - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr result = xmlXPathEvalExpression(BAD_CAST "/eressea/archetypes/archetype", xpath); - xmlNodeSetPtr nodes = result->nodesetval; - - xmlChar * propValue; - if (nodes) { - int i; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr node = nodes->nodeTab[i]; - xmlNodePtr child; - archetype * arch = calloc(1, sizeof(archetype)); - xmlXPathObjectPtr sub; - - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - arch->name[0] = strdup((const char *)propValue); - sprintf(zName, "%s_p", arch->name[0]); - arch->name[1] = strdup(zName); - xmlFree(propValue); - - propValue = xmlGetProp(node, BAD_CAST "equip"); - if (propValue!=NULL) { - arch->equip = get_equipment((const char*)propValue); - xmlFree(propValue); - } else { - arch->equip = get_equipment(arch->name[0]); - } - - propValue = xmlGetProp(node, BAD_CAST "building"); - if (propValue!=NULL) { - arch->btype = bt_find((const char*)propValue); - xmlFree(propValue); - } - - arch->size = xml_ivalue(node, "cost", 0); - - for (child=node->children;child;child=child->next) { - if (strcmp((const char *)child->name, "function")==0) { - xmlChar * propName = xmlGetProp(child, BAD_CAST "name"); - xmlChar * propValue = xmlGetProp(child, BAD_CAST "value"); - if (strcmp((const char *)propName, "create")) { - pf_generic foo = get_function((const char *)propValue); - arch->exec = (archetype_function)foo; - } - xmlFree(propValue); - xmlFree(propName); - } - } - xpath->node = node; - sub = xmlXPathEvalExpression(BAD_CAST "allow|deny", xpath); - if (sub->nodesetval && sub->nodesetval->nodeNr) { - int k; - arch->rules = calloc(sub->nodesetval->nodeNr+1, sizeof(rule)); - for (k=0;k!=sub->nodesetval->nodeNr;++k) { - xmlNodePtr rule = sub->nodesetval->nodeTab[k]; - arch->rules[k].allow = (rule->name[0]=='a'); - - propValue = xmlGetProp(rule, BAD_CAST "property"); - arch->rules[k].property = strdup((const char *)propValue); - xmlFree(propValue); - - propValue = xmlGetProp(rule, BAD_CAST "value"); - arch->rules[k].value = strdup((const char *)propValue); - xmlFree(propValue); - } - } - xmlXPathFreeObject(sub); - - xpath->node = node; - sub = xmlXPathEvalExpression(BAD_CAST "construction", xpath); - if (sub->nodesetval) { - xml_readconstruction(xpath, sub->nodesetval, &arch->ctype); - } - xmlXPathFreeObject(sub); - register_archetype(arch); - } - } - xmlXPathFreeObject(result); - - xmlXPathFreeContext(xpath); - return 0; -} -#endif - -void -register_archetypes(void) -{ -#ifdef HAVE_LIBXML - xml_register_callback(parse_archetypes); -#endif -} +#include +#include +#include "archetype.h" + +/* kernel includes */ +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include + +/* libxml includes */ +#include +#include +#include + +/* libc includes */ +#include +#include + +static struct archetype * archetypes; + +struct attrib_type at_recruit = { + "recruit", NULL, NULL, NULL, NULL, NULL, ATF_UNIQUE +}; + +const struct archetype * +find_archetype(const char * s, const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_ARCHETYPES); + variant token; + + if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { + return (const struct archetype *)token.v; + } + return NULL; +} + +void +register_archetype(archetype * arch) +{ + arch->next = archetypes; + archetypes = arch; +} + +void +init_archetypes(void) +{ + const struct locale * lang = locales; + for (;lang;lang=nextlocale(lang)) { + variant var; + archetype * arch = archetypes; + struct tnode * tokens = get_translations(lang, UT_ARCHETYPES); + for (;arch;arch=arch->next) { + const char *s1, *s2; + var.v = arch; + + s1 = LOC(lang, arch->name[0]); + addtoken(tokens, s1, var); + s2 = LOC(lang, arch->name[1]); + if (strcmp(s2, s1)!=0) { + addtoken(tokens, s2, var); + } + } + } +} + +static int +parse_archetypes(xmlDocPtr doc) +{ + char zName[64]; + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr result = xmlXPathEvalExpression(BAD_CAST "/eressea/archetypes/archetype", xpath); + xmlNodeSetPtr nodes = result->nodesetval; + + xmlChar * propValue; + if (nodes) { + int i; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + xmlNodePtr child; + archetype * arch = calloc(1, sizeof(archetype)); + xmlXPathObjectPtr sub; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + arch->name[0] = strdup((const char *)propValue); + sprintf(zName, "%s_p", arch->name[0]); + arch->name[1] = strdup(zName); + xmlFree(propValue); + + propValue = xmlGetProp(node, BAD_CAST "equip"); + if (propValue!=NULL) { + arch->equip = get_equipment((const char*)propValue); + xmlFree(propValue); + } else { + arch->equip = get_equipment(arch->name[0]); + } + + propValue = xmlGetProp(node, BAD_CAST "building"); + if (propValue!=NULL) { + arch->btype = bt_find((const char*)propValue); + xmlFree(propValue); + } + + arch->size = xml_ivalue(node, "cost", 0); + + for (child=node->children;child;child=child->next) { + if (strcmp((const char *)child->name, "function")==0) { + xmlChar * propName = xmlGetProp(child, BAD_CAST "name"); + xmlChar * propValue = xmlGetProp(child, BAD_CAST "value"); + if (strcmp((const char *)propName, "create")) { + pf_generic foo = get_function((const char *)propValue); + arch->exec = (archetype_function)foo; + } + xmlFree(propValue); + xmlFree(propName); + } + } + xpath->node = node; + sub = xmlXPathEvalExpression(BAD_CAST "allow|deny", xpath); + if (sub->nodesetval && sub->nodesetval->nodeNr) { + int k; + arch->rules = calloc(sub->nodesetval->nodeNr+1, sizeof(rule)); + for (k=0;k!=sub->nodesetval->nodeNr;++k) { + xmlNodePtr rule = sub->nodesetval->nodeTab[k]; + arch->rules[k].allow = (rule->name[0]=='a'); + + propValue = xmlGetProp(rule, BAD_CAST "property"); + arch->rules[k].property = strdup((const char *)propValue); + xmlFree(propValue); + + propValue = xmlGetProp(rule, BAD_CAST "value"); + arch->rules[k].value = strdup((const char *)propValue); + xmlFree(propValue); + } + } + xmlXPathFreeObject(sub); + + xpath->node = node; + sub = xmlXPathEvalExpression(BAD_CAST "construction", xpath); + if (sub->nodesetval) { + xml_readconstruction(xpath, sub->nodesetval, &arch->ctype); + } + xmlXPathFreeObject(sub); + register_archetype(arch); + } + } + xmlXPathFreeObject(result); + + xmlXPathFreeContext(xpath); + return 0; +} + +void +register_archetypes(void) +{ + xml_register_callback(parse_archetypes); +} diff --git a/src/gamecode/archetype.h b/src/gamecode/archetype.h index 40bd4fb90..358946ccd 100644 --- a/src/gamecode/archetype.h +++ b/src/gamecode/archetype.h @@ -1,51 +1,51 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2007 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifndef H_GC_ARCHETYPE -#define H_GC_ARCHETYPE - -#ifdef __cplusplus -extern "C" { -#endif - - typedef struct rule { - boolean allow; - char * property; - char * value; - } rule; - - struct archetype; - typedef int (*archetype_function)(struct unit * u, const struct archetype *, int); - - typedef struct archetype { - struct archetype * next; - char * name[2]; - int size; - struct building_type * btype; - struct equipment * equip; - struct construction * ctype; - struct rule * rules; - archetype_function exec; - } archetype; - - extern const struct archetype * find_archetype(const char * s, const struct locale * lang); - extern void init_archetypes(void); - extern void register_archetype(struct archetype * arch); - extern void register_archetypes(void); - - extern struct attrib_type at_recruit; - -#ifdef __cplusplus -} -#endif - -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2007 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifndef H_GC_ARCHETYPE +#define H_GC_ARCHETYPE + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct rule { + boolean allow; + char * property; + char * value; + } rule; + + struct archetype; + typedef int (*archetype_function)(struct unit * u, const struct archetype *, int); + + typedef struct archetype { + struct archetype * next; + char * name[2]; + int size; + struct building_type * btype; + struct equipment * equip; + struct construction * ctype; + struct rule * rules; + archetype_function exec; + } archetype; + + extern const struct archetype * find_archetype(const char * s, const struct locale * lang); + extern void init_archetypes(void); + extern void register_archetype(struct archetype * arch); + extern void register_archetypes(void); + + extern struct attrib_type at_recruit; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/gamecode/creation.c b/src/gamecode/creation.c index f9878b922..b22dedaa8 100644 --- a/src/gamecode/creation.c +++ b/src/gamecode/creation.c @@ -1,73 +1,73 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "creation.h" -#include "monster.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include -#include -#include - -faction * -createmonsters(int no) -{ - faction *f = findfaction(no); - - if (f) { - puts("* Fehler! Die Monster Partei gibt es schon."); - return f; - } - f = (faction *) calloc(1, sizeof(faction)); - f->no = no; - /* alles ist auf null gesetzt, ausser dem folgenden. achtung - partei - * no 0 muss keine orders einreichen! */ - - f->email = strdup("monsters@eressea.de"); - f->name = strdup("Monster"); - f->alive = 1; - f->options = (char)(1< + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "creation.h" +#include "monster.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +faction * +createmonsters(int no) +{ + faction *f = findfaction(no); + + if (f) { + puts("* Fehler! Die Monster Partei gibt es schon."); + return f; + } + f = (faction *) calloc(1, sizeof(faction)); + f->no = no; + /* alles ist auf null gesetzt, ausser dem folgenden. achtung - partei + * no 0 muss keine orders einreichen! */ + + f->email = strdup("monsters@eressea.de"); + f->name = strdup("Monster"); + f->alive = 1; + f->options = (char)(1< - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_GC_CREATION -#define H_GC_CREATION -#ifdef __cplusplus -extern "C" { -#endif - -struct faction * createmonsters(int no); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_GC_CREATION +#define H_GC_CREATION +#ifdef __cplusplus +extern "C" { +#endif + +struct faction * createmonsters(int no); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index d8fc76390..edef15247 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -1,1607 +1,1608 @@ -/* vi: set ts=2: -+-------------------+ Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -+-------------------+ -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "creport.h" - -/* tweakable features */ -#define RENDER_CRMESSAGES -#define BUFFERSIZE 32768 -#define RESOURCECOMPAT - -/* modules include */ -#include - -/* attributes include */ -#include -#include -#include -#include -#include - -/* gamecode includes */ -#include "laws.h" -#include "economy.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include -#include - -/* imports */ -extern int verbosity; -boolean opt_cr_absolute_coords = false; - -/* globals */ -#define C_REPORT_VERSION 66 - -#define TAG_LOCALE "de" -#ifdef TAG_LOCALE -static const char * -crtag(const char * key) -{ - static const struct locale * lang = NULL; - if (!lang) lang = find_locale(TAG_LOCALE); - return locale_string(lang, key); -} -#else -#define crtag(x) (x) -#endif -/* - * translation table - */ -typedef struct translation { - struct translation * next; - char * key; - const char * value; -} translation; - -#define TRANSMAXHASH 257 -static translation * translation_table[TRANSMAXHASH]; -static translation * junkyard; - -static const char * -add_translation(const char * key, const char * value) -{ - int kk = ((key[0] << 5) + key[0]) % TRANSMAXHASH; - translation * t = translation_table[kk]; - while (t && strcmp(t->key, key)!=0) t=t->next; - if (!t) { - if (junkyard) { - t = junkyard; - junkyard = junkyard->next; - } else t = malloc(sizeof(translation)); - t->key = strdup(key); - t->value = value; - t->next = translation_table[kk]; - translation_table[kk] = t; - } - return crtag(key); -} - -static void -write_translations(FILE * F) -{ - int i; - fputs("TRANSLATION\n", F); - for (i=0;i!=TRANSMAXHASH;++i) { - translation * t = translation_table[i]; - while (t) { - fprintf(F, "\"%s\";%s\n", t->value, crtag(t->key)); - t = t->next; - } - } -} - -static void -reset_translations(void) -{ - int i; - for (i=0;i!=TRANSMAXHASH;++i) { - translation * t = translation_table[i]; - while (t) { - translation * c = t->next; - free(t->key); - t->next = junkyard; - junkyard = t; - t = c; - } - translation_table[i] = 0; - } -} - -#include - -static void -print_items(FILE * F, item * items, const struct locale * lang) -{ - item * itm; - - for (itm=items; itm; itm=itm->next) { - int in = itm->number; - const char * ic = resourcename(itm->type->rtype, 0); - if (itm==items) fputs("GEGENSTAENDE\n", F); - fprintf(F, "%d;%s\n", in, add_translation(ic, LOC(lang, ic))); - } -} - -static void -cr_output_curses(FILE * F, const faction * viewer, const void * obj, typ_t typ) -{ - boolean header = false; - attrib *a = NULL; - int self = 0; - region *r; - - /* Die Sichtbarkeit eines Zaubers und die Zaubermeldung sind bei - * Gebäuden und Schiffen je nach, ob man Besitzer ist, verschieden. - * Bei Einheiten sieht man Wirkungen auf eigene Einheiten immer. - * Spezialfälle (besonderes Talent, verursachender Magier usw. werde - * bei jedem curse gesondert behandelt. */ - if (typ == TYP_SHIP){ - ship * sh = (ship*)obj; - unit * owner = shipowner(sh); - a = sh->attribs; - r = sh->region; - if (owner != NULL) { - if (owner->faction == viewer){ - self = 2; - } else { /* steht eine person der Partei auf dem Schiff? */ - unit *u = NULL; - for (u = r->units; u; u = u->next) { - if (u->ship == sh) { - self = 1; - break; - } - } - } - } - } else if (typ == TYP_BUILDING) { - building * b = (building*)obj; - unit * owner = building_owner(b); - a = b->attribs; - r = b->region; - if (owner != NULL){ - if (owner->faction == viewer){ - self = 2; - } else { /* steht eine Person der Partei in der Burg? */ - unit *u = NULL; - for (u = r->units; u; u = u->next) { - if (u->building == b) { - self = 1; - break; - } - } - } - } - } else if (typ == TYP_UNIT) { - unit *u = (unit *)obj; - a = u->attribs; - r = u->region; - if (u->faction == viewer) { - self = 2; - } - } else if (typ == TYP_REGION) { - r = (region *)obj; - a = r->attribs; - } else { - /* fehler */ - } - - while (a) { - if (fval(a->type, ATF_CURSE)) { - curse * c = (curse *)a->data.v; - message * msg; - - if (c->type->cansee) { - self = c->type->cansee(viewer, obj, typ, c, self); - } - msg = msg_curse(c, obj, typ, self); - - if (msg) { - char buf[BUFFERSIZE]; - if (!header) { - header = 1; - fputs("EFFECTS\n", F); - } - nr_render(msg, viewer->locale, buf, sizeof(buf), viewer); - fprintf(F, "\"%s\"\n", buf); - msg_release(msg); - } - } else if (a->type==&at_effect && self) { - effect_data * data = (effect_data *)a->data.v; - if (data->value>0) { - const char * key = resourcename(data->type->itype->rtype, 0); - if (!header) { - header = 1; - fputs("EFFECTS\n", F); - } - fprintf(F, "\"%d %s\"\n", data->value, add_translation(key, locale_string(default_locale, key))); - } - } - a = a->next; - } -} - -static int -cr_unit(variant var, char * buffer, const void * userdata) -{ - unit * u = (unit *)var.v; - sprintf(buffer, "%d", u?u->no:-1); - return 0; -} - -static int -cr_ship(variant var, char * buffer, const void * userdata) -{ - ship * u = (ship *)var.v; - sprintf(buffer, "%d", u?u->no:-1); - return 0; -} - -static int -cr_building(variant var, char * buffer, const void * userdata) -{ - building * u = (building *)var.v; - sprintf(buffer, "%d", u?u->no:-1); - return 0; -} - -static int -cr_faction(variant var, char * buffer, const void * userdata) -{ - faction * f = (faction *)var.v; - sprintf(buffer, "%d", f?f->no:-1); - return 0; -} - -static int -cr_region(variant var, char * buffer, const void * userdata) -{ - const faction * report = (const faction*)userdata; - region * r = (region *)var.v; - if (r) { - plane * pl = rplane(r); - int nx = r->x, ny = r->y; - pnormalize(&nx, &ny, pl); - adjust_coordinates(report, &nx, &ny, pl, r); - sprintf(buffer, "%d %d %d", nx, ny, plane_id(pl)); - return 0; - } - return -1; -} - -static int -cr_resource(variant var, char * buffer, const void * userdata) -{ - const faction * report = (const faction*)userdata; - const resource_type * r = (const resource_type *)var.v; - if (r) { - const char * key = resourcename(r, 0); - sprintf(buffer, "\"%s\"", - add_translation(key, locale_string(report->locale, key))); - return 0; - } - return -1; -} - -static int -cr_race(variant var, char * buffer, const void * userdata) -{ - const faction * report = (const faction*)userdata; - const struct race * rc = (const race *)var.v; - const char * key = rc_name(rc, 0); - sprintf(buffer, "\"%s\"", - add_translation(key, locale_string(report->locale, key))); - return 0; -} - -static int -cr_alliance(variant var, char * buffer, const void * userdata) -{ - const alliance * al = (const alliance *)var.v; - if (al!=NULL) { - sprintf(buffer, "%d", al->id); - } - unused(userdata); - return 0; -} - -static int -cr_skill(variant var, char * buffer, const void * userdata) -{ - const faction * report = (const faction*)userdata; - skill_t sk = (skill_t)var.i; - if (sk!=NOSKILL) sprintf(buffer, "\"%s\"", - add_translation(mkname("skill", skillnames[sk]), skillname(sk, report->locale))); - else strcpy(buffer, "\"\""); - return 0; -} - -static int -cr_order(variant var, char * buffer, const void * userdata) -{ - order * ord = (order*)var.v; - if (ord!=NULL) { - char * wp = buffer; - char * cmd = getcommand(ord); - const char * rp = cmd; - - *wp++ = '\"'; - while (*rp) { - switch (*rp) { - case '\"': - case '\\': - *wp++ = '\\'; - default: - *wp++ = *rp++; - } - } - *wp++ = '\"'; - *wp++ = 0; - - free(cmd); - } - else strcpy(buffer, "\"\""); - return 0; -} - -static int -cr_resources(variant var, char * buffer, const void * userdata) -{ - faction * f = (faction*)userdata; - resource * rlist = (resource*)var.v; - char * wp = buffer; - if (rlist!=NULL) { - const char * name = resourcename(rlist->type, rlist->number!=1); - wp += sprintf(wp, "\"%d %s", rlist->number, add_translation(name, LOC(f->locale, name))); - for (;;) { - rlist = rlist->next; - if (rlist==NULL) break; - name = resourcename(rlist->type, rlist->number!=1); - wp += sprintf(wp, ", %d %s", rlist->number, add_translation(name, LOC(f->locale, name))); - } - strcat(wp, "\""); - } - return 0; -} - -static int -cr_regions(variant var, char * buffer, const void * userdata) -{ - faction * f = (faction*)userdata; - const arg_regions * rdata = (const arg_regions *)var.v; - - if (rdata!=NULL && rdata->nregions>0) { - region * r = rdata->regions[0]; - plane * pl = rplane(r); - int i, z = plane_id(pl); - char * wp = buffer; - int nx = r->x, ny = r->y; - - pnormalize(&nx, &ny, pl); - adjust_coordinates(f, &nx, &ny, pl, r); - wp += sprintf(wp, "\"%d %d %d", nx, ny, z); - for (i=1;i!=rdata->nregions;++i) { - r = rdata->regions[i]; - pl = rplane(r); - z = plane_id(pl); - wp += sprintf(wp, ", %d %d %d", nx, ny, z); - } - strcat(wp, "\""); - } else { - strcpy(buffer, "\"\""); - } - return 0; -} - -static int -cr_spell(variant var, char * buffer, const void * userdata) -{ - const faction * report = (const faction*)userdata; - spell * sp = (spell*)var.v; - if (sp!=NULL) sprintf(buffer, "\"%s\"", spell_name(sp, report->locale)); - else strcpy(buffer, "\"\""); - return 0; -} - -static int -cr_curse(variant var, char * buffer, const void * userdata) -{ - const faction * report = (const faction*)userdata; - const curse_type * ctype = (const curse_type*)var.v; - if (ctype!=NULL) { - sprintf(buffer, "\"%s\"", curse_name(ctype, report->locale)); - } else strcpy(buffer, "\"\""); - return 0; -} - -/*static int msgno; */ - -#define MTMAXHASH 1021 - -static struct known_mtype { - const struct message_type * mtype; - struct known_mtype * nexthash; -} * mtypehash[MTMAXHASH]; - -static void -report_crtypes(FILE * F, const struct locale* lang) -{ - int i; - for (i=0;i!=MTMAXHASH;++i) { - struct known_mtype * kmt; - for (kmt=mtypehash[i];kmt;kmt=kmt->nexthash) { - const struct nrmessage_type * nrt = nrt_find(lang, kmt->mtype); - if (nrt) { - unsigned int hash = kmt->mtype->key; - fprintf(F, "MESSAGETYPE %d\n", hash); - fputc('\"', F); - fputs(escape_string(nrt_string(nrt), NULL, 0), F); - fputs("\";text\n", F); - fprintf(F, "\"%s\";section\n", nrt_section(nrt)); - } - } - while (mtypehash[i]) { - kmt = mtypehash[i]; - mtypehash[i] = mtypehash[i]->nexthash; - free(kmt); - } - } -} - -static unsigned int -messagehash(const struct message * msg) -{ - variant var; - var.v = (void *)msg; - return (unsigned int)var.i; -} - -static void -render_messages(FILE * F, faction * f, message_list *msgs) -{ - struct mlist* m = msgs->begin; - while (m) { - char crbuffer[BUFFERSIZE]; /* gross, wegen spionage-messages :-( */ - boolean printed = false; - const struct message_type * mtype = m->msg->type; - unsigned int hash = mtype->key; -#ifdef RENDER_CRMESSAGES - char nrbuffer[1024*32]; - nrbuffer[0] = '\0'; - if (nr_render(m->msg, f->locale, nrbuffer, sizeof(nrbuffer), f)>=0) { - fprintf(F, "MESSAGE %u\n", messagehash(m->msg)); - fprintf(F, "%d;type\n", hash); - fwritestr(F, nrbuffer); - fputs(";rendered\n", F); - printed = true; - } -#endif - crbuffer[0] = '\0'; - if (cr_render(m->msg, crbuffer, (const void*)f)==0) { - if (!printed) fprintf(F, "MESSAGE %u\n", messagehash(m->msg)); - if (crbuffer[0]) fputs(crbuffer, F); - } else { - log_error(("could not render cr-message %p: %s\n", m->msg, m->msg->type->name)); - } - if (printed) { - unsigned int ihash = hash % MTMAXHASH; - struct known_mtype * kmt = mtypehash[ihash]; - while (kmt && kmt->mtype != mtype) kmt = kmt->nexthash; - if (kmt==NULL) { - kmt = (struct known_mtype*)malloc(sizeof(struct known_mtype)); - kmt->nexthash = mtypehash[ihash]; - kmt->mtype = mtype; - mtypehash[ihash] = kmt; - } - } - m = m->next; - } -} - -static void -cr_output_messages(FILE * F, message_list *msgs, faction * f) -{ - if (msgs) render_messages(F, f, msgs); -} - -/* prints a building */ -static void -cr_output_building(FILE * F, building * b, const unit * owner, int fno, faction *f) -{ - const char * bname, * billusion; - - fprintf(F, "BURG %d\n", b->no); - - report_building(b, &bname, &billusion); - if (billusion) { - fprintf(F, "\"%s\";Typ\n", add_translation(billusion, LOC(f->locale, billusion))); - if (owner && owner->faction==f) { - fprintf(F, "\"%s\";wahrerTyp\n", add_translation(bname, LOC(f->locale, bname))); - } - } else { - fprintf(F, "\"%s\";Typ\n", add_translation(bname, LOC(f->locale, bname))); - } - 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 ? owner->no : -1); - if (fno >= 0) - fprintf(F, "%d;Partei\n", fno); - if (b->besieged) - fprintf(F, "%d;Belagerer\n", b->besieged); - cr_output_curses(F, f, b, TYP_BUILDING); -} -/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ - -/* prints a ship */ -static void -cr_output_ship(FILE * F, 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); - if (sh->display && sh->display[0]) - fprintf(F, "\"%s\";Beschr\n", sh->display); - fprintf(F, "\"%s\";Typ\n", add_translation(sh->type->name[0], locale_string(f->locale, sh->type->name[0]))); - fprintf(F, "%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); - } - if (u) - fprintf(F, "%d;Kapitaen\n", u ? u->no : -1); - 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)); - } - /* shore */ - w = NODIRECTION; - if (!fval(r->terrain, SEA_REGION)) w = sh->coast; - if (w != NODIRECTION) - fprintf(F, "%d;Kueste\n", w); - - cr_output_curses(F, f, sh, TYP_SHIP); -} - -static void -fwriteorder(FILE * F, const struct order * ord, const struct locale * lang, boolean escape) -{ - char ebuf[1024]; - char obuf[1024]; - const char * str = obuf; - fputc('"', F); - write_order(ord, obuf, sizeof(obuf)); - if (escape) { - str = escape_string(obuf, ebuf, sizeof(ebuf)); - } - if (str[0]) fputs(str, F); - fputc('"', F); -} - -static void cr_output_spells(FILE * F, spell_list * slist, const faction * f, int maxlevel) -{ - if (slist) { - fprintf(F, "SPRUECHE\n"); - for (;slist; slist = slist->next) { - spell * sp = slist->data; - if (sp->level <= maxlevel) { - const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, f->locale)); - fprintf(F, "\"%s\"\n", name); - } - } - } -} - -/* prints all that belongs to a unit */ -static void -cr_output_unit(FILE * F, const region * r, - const faction * f, /* observers faction */ - const unit * u, int mode) -{ - /* Race attributes are always plural and item attributes always - * singular */ - const char * str; - const item_type * lasttype; - int pr; - item *itm, *show; - building * b; - const char * pzTmp; - skill * sv; - const attrib *a_fshidden = NULL; - boolean itemcloak = false; - static const curse_type * itemcloak_ct = 0; - static boolean init = false; - item result[MAX_INVENTORY]; - - if (fval(u->race, RCF_INVISIBLE)) return; - - if (!init) { - init = true; - itemcloak_ct = ct_find("itemcloak"); - } - if (itemcloak_ct!=NULL) { - itemcloak = curse_active(get_curse(u->attribs, itemcloak_ct)); - } - - assert(u && u->number); - - fprintf(F, "EINHEIT %d\n", u->no); - fprintf(F, "\"%s\";Name\n", u->name); - str = u_description(u, f->locale); - if (str) { - fprintf(F, "\"%s\";Beschr\n", str); - } - { - /* print faction information */ - const faction * sf = visible_faction(f, u); - const char * prefix = raceprefix(u); - if (u->faction == f || omniscient(f)) { - const attrib * a_otherfaction = a_find(u->attribs, &at_otherfaction); - const faction * otherfaction = a_otherfaction?get_otherfaction(a_otherfaction):NULL; - /* my own faction, full info */ - const attrib *a = NULL; - unit * mage; - - if (fval(u, UFL_GROUP)) a = a_find(u->attribs, &at_group); - if (a!=NULL) { - const group * g = (const group*)a->data.v; - fprintf(F, "%d;gruppe\n", g->gid); - } - fprintf(F, "%d;Partei\n", u->faction->no); - if (sf!=u->faction) fprintf(F, "%d;Verkleidung\n", sf->no); - if (fval(u, UFL_ANON_FACTION)) - fprintf(F, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION))); - if (otherfaction) { - if (otherfaction!=u->faction) { - fprintf(F, "%d;Anderepartei\n", otherfaction->no); - } - } - mage = get_familiar_mage(u); - if (mage) { - fprintf(F, "%u;familiarmage\n", mage->no); - } - } else { - if (fval(u, UFL_ANON_FACTION)) { - /* faction info is hidden */ - fprintf(F, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION))); - } else { - const attrib * a_otherfaction = a_find(u->attribs, &at_otherfaction); - const faction * otherfaction = a_otherfaction?get_otherfaction(a_otherfaction):NULL; - /* other unit. show visible faction, not u->faction */ - fprintf(F, "%d;Partei\n", sf->no); - if (sf == f) { - fprintf(F, "1;Verraeter\n"); - } - if (a_otherfaction) { - if (otherfaction!=u->faction) { - if (alliedunit(u, f, HELP_FSTEALTH)) { - fprintf(F, "%d;Anderepartei\n", otherfaction->no); - } - } - } - } - } - if (prefix) { - prefix = mkname("prefix", prefix); - fprintf(F, "\"%s\";typprefix\n", add_translation(prefix, LOC(f->locale, prefix))); - } - } - if (u->faction != f && a_fshidden - && a_fshidden->data.ca[0] == 1 && effskill(u, SK_STEALTH) >= 6) { - fprintf(F, "-1;Anzahl\n"); - } else { - fprintf(F, "%d;Anzahl\n", u->number); - } - - pzTmp = get_racename(u->attribs); - if (pzTmp) { - fprintf(F, "\"%s\";Typ\n", pzTmp); - if (u->faction==f && fval(u->race, RCF_SHAPESHIFTANY)) { - const char * zRace = rc_name(u->race, 1); - fprintf(F, "\"%s\";wahrerTyp\n", - add_translation(zRace, locale_string(f->locale, zRace))); - } - } else { - const race * irace = u_irace(u); - const char * zRace = rc_name(irace, 1); - fprintf(F, "\"%s\";Typ\n", - add_translation(zRace, locale_string(f->locale, zRace))); - if (u->faction==f && irace!=u->race) { - assert(skill_enabled[SK_STEALTH] || !"we're resetting this on load, so.. ircase should never be used"); - zRace = rc_name(u->race, 1); - fprintf(F, "\"%s\";wahrerTyp\n", - add_translation(zRace, locale_string(f->locale, zRace))); - } - } - - if (u->building) { - assert(u->building->region); - fprintf(F, "%d;Burg\n", u->building->no); - } - if (u->ship) { - assert(u->ship->region); - fprintf(F, "%d;Schiff\n", u->ship->no); - } - if (is_guard(u, GUARD_ALL)!=0) { - fprintf(F, "%d;bewacht\n", 1); - } - if ((b=usiege(u))!=NULL) { - fprintf(F, "%d;belagert\n", b->no); - } - /* additional information for own units */ - if (u->faction == f || omniscient(f)) { - order * ord; - const char *xc; - const char * c; - int i; - - i = ualias(u); - if (i>0) - fprintf(F, "%d;temp\n", i); - else if (i<0) - fprintf(F, "%d;alias\n", -i); - i = get_money(u); - fprintf(F, "%d;Kampfstatus\n", u->status); - fprintf(F, "%d;weight\n", weight(u)); - if (fval(u, UFL_NOAID)) { - fputs("1;unaided\n", F); - } - if (fval(u, UFL_STEALTH)) { - i = u_geteffstealth(u); - if (i >= 0) { - fprintf(F, "%d;Tarnung\n", i); - } - } - xc = uprivate(u); - if (xc) { - fprintf(F, "\"%s\";privat\n", xc); - } - c = hp_status(u); - if (c && *c && (u->faction == f || omniscient(f))) { - fprintf(F, "\"%s\";hp\n", add_translation(c, locale_string(u->faction->locale, c))); - } - if (fval(u, UFL_HERO)) { - fputs("1;hero\n", F); - } - - if (fval(u, UFL_HUNGER) && (u->faction == f)) { - fputs("1;hunger\n", F); - } - if (is_mage(u)) { - fprintf(F, "%d;Aura\n", get_spellpoints(u)); - fprintf(F, "%d;Auramax\n", max_spellpoints(u->region,u)); - } - /* default commands */ - fprintf(F, "COMMANDS\n"); - for (ord = u->old_orders; ord; ord = ord->next) { - /* this new order will replace the old defaults */ - if (is_persistent(ord)) { - fwriteorder(F, ord, f->locale, true); - fputc('\n', F); - } - } - for (ord = u->orders; ord; ord = ord->next) { - if (u->old_orders && is_repeated(ord)) continue; /* unit has defaults */ - if (is_persistent(ord)) { - fwriteorder(F, ord, f->locale, true); - fputc('\n', F); - } - } - - /* talents */ - pr = 0; - for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - if (sv->level>0) { - skill_t sk = sv->id; - int esk = eff_skill(u, sk, r); - if (!pr) { - pr = 1; - fprintf(F, "TALENTE\n"); - } - fprintf(F, "%d %d;%s\n", u->number*level_days(sv->level), esk, - add_translation(mkname("skill", skillnames[sk]), skillname(sk, f->locale))); - } - } - /* spells */ - if (is_mage(u)) { - sc_mage * mage = get_mage(u); - spell_list ** slistp = get_spelllist(mage, u->faction); - int i, maxlevel = effskill(u, SK_MAGIC); - - cr_output_spells(F, *slistp, f, maxlevel); - - for (i=0;i!=MAXCOMBATSPELLS;++i) { - const spell * sp = mage->combatspells[i].sp; - if (sp) { - const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, f->locale)); - fprintf(F, "KAMPFZAUBER %d\n", i); - fprintf(F, "\"%s\";name\n", name); - fprintf(F, "%d;level\n", mage->combatspells[i].level); - } - } - } - } - /* items */ - pr = 0; - if (f == u->faction || omniscient(u->faction)) { - show = u->items; - } else if (itemcloak==false && mode>=see_unit && !(a_fshidden - && a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) - { - int n = report_items(u->items, result, MAX_INVENTORY, u, f); - assert(n>=0); - if (n>0) show = result; - else show = NULL; - } else { - show = NULL; - } - lasttype = NULL; - for (itm=show; itm; itm=itm->next) { - const char * ic; - int in; - assert(itm->type!=lasttype || !"error: list contains two objects of the same item"); - report_item(u, itm, f, NULL, &ic, &in, true); - if (in==0) continue; - if (!pr) { - pr = 1; - fputs("GEGENSTAENDE\n", F); - } - fprintf(F, "%d;%s\n", in, add_translation(ic, locale_string(f->locale, ic))); - } - - cr_output_curses(F, f, u, TYP_UNIT); -} -/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ - -/* prints allies */ -static void -show_allies_cr(FILE * F, const faction * f, const ally * sf) -{ - for (; sf; sf = sf->next) if (sf->faction) { - int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); - if (mode!=0 && sf->status>0) { - fprintf(F, "ALLIANZ %d\n", sf->faction->no); - fprintf(F, "\"%s\";Parteiname\n", sf->faction->name); - fprintf(F, "%d;Status\n", sf->status & HELP_ALL); - } - } -} - -/* prints allies */ -static void -show_alliances_cr(FILE * F, const faction * f) -{ - alliance * al = f_get_alliance(f); - if (al) { - faction * lead = alliance_get_leader(al); - assert(lead); - fprintf(F, "ALLIANCE %d\n", al->id); - fprintf(F, "\"%s\";name\n", al->name); - fprintf(F, "%d;leader\n", lead->no); - } -} - -/* prints all visible spells in a region */ -static void -show_active_spells(const region * r) -{ - char fogwall[MAXDIRECTIONS]; -#ifdef TODO /* alte Regionszauberanzeigen umstellen */ - unit *u; - int env = 0; -#endif - memset(fogwall, 0, sizeof(char) * MAXDIRECTIONS); - -} -/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ - -/* this is a copy of laws.c->find_address output changed. */ -static void -cr_find_address(FILE * F, const faction * uf, const faction_list * addresses) -{ - const faction_list * flist = addresses; - while (flist!=NULL) { - const faction * f = flist->data; - if (uf!=f) { - fprintf(F, "PARTEI %d\n", f->no); - fprintf(F, "\"%s\";Parteiname\n", f->name); - if (f->email) fprintf(F, "\"%s\";email\n", f->email); - if (f->banner) fprintf(F, "\"%s\";banner\n", f->banner); - fprintf(F, "\"%s\";locale\n", locale_name(f->locale)); - if (f->alliance && f->alliance==uf->alliance) { - fprintf(F, "%d;alliance\n", f->alliance->id); - } - } - flist = flist->next; - } -} -/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ - -static void -cr_reportspell(FILE * F, spell *sp, const struct locale * lang) -{ - int k; - const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, lang)); - - fprintf(F, "ZAUBER %d\n", hashstring(sp->sname)); - fprintf(F, "\"%s\";name\n", name); - fprintf(F, "%d;level\n", sp->level); - fprintf(F, "%d;rank\n", sp->rank); - fprintf(F, "\"%s\";info\n", spell_info(sp, lang)); - if (sp->parameter) fprintf(F, "\"%s\";syntax\n", sp->parameter); - else fputs("\"\";syntax\n", F); - - if (sp->sptyp & PRECOMBATSPELL) fputs("\"precombat\";class\n", F); - else if (sp->sptyp & COMBATSPELL) fputs("\"combat\";class\n", F); - else if (sp->sptyp & POSTCOMBATSPELL) fputs("\"postcombat\";class\n", F); - else fputs("\"normal\";class\n", F); - - if (sp->sptyp & FARCASTING) fputs("1;far\n", F); - if (sp->sptyp & OCEANCASTABLE) fputs("1;ocean\n", F); - if (sp->sptyp & ONSHIPCAST) fputs("1;ship\n", F); - if (!(sp->sptyp & NOTFAMILIARCAST)) fputs("1;familiar\n", F); - fputs("KOMPONENTEN\n", F); - - for (k = 0; sp->components[k].type; ++k) { - const resource_type * rtype = sp->components[k].type; - int itemanz = sp->components[k].amount; - int costtyp = sp->components[k].cost; - if (itemanz > 0) { - const char * name = resourcename(rtype, 0); - fprintf(F, "%d %d;%s\n", itemanz, costtyp == SPC_LEVEL || costtyp == SPC_LINEAR, - add_translation(name, LOC(lang, name))); - } - } -} - -static char * -cr_output_resource(char * buf, const char * name, const struct locale * loc, int amount, int level) -{ - buf += sprintf(buf, "RESOURCE %u\n", hashstring(name)); - buf += sprintf(buf, "\"%s\";type\n", add_translation(name, LOC(loc, name))); - if (amount>=0) { - if (level>=0) buf += sprintf(buf, "%d;skill\n", level); - buf += sprintf(buf, "%d;number\n", amount); - } - return buf; -} - -static void -cr_borders(seen_region ** seen, const region * r, const faction * f, int seemode, FILE * F) -{ - direction_t d; - int g = 0; - for (d = 0; d != MAXDIRECTIONS; d++) - { /* Nachbarregionen, die gesehen werden, ermitteln */ - const region * r2 = rconnect(r, d); - const connection * b; - if (!r2) continue; - if (seemode==see_neighbour) { - seen_region * sr = find_seen(seen, r2); - if (sr==NULL || sr->mode<=see_neighbour) continue; - } - b = get_borders(r, r2); - while (b) { - boolean cs = b->type->fvisible(b, f, r); - - if (!cs) { - cs = b->type->rvisible(b, r); - if (!cs) { - unit * us = r->units; - while (us && !cs) { - if (us->faction==f) { - cs = b->type->uvisible(b, us); - if (cs) break; - } - us=us->next; - } - } - } - if (cs) { - const char * bname = mkname("border", b->type->name(b, r, f, GF_PURE)); - fprintf(F, "GRENZE %d\n", ++g); - fprintf(F, "\"%s\";typ\n", LOC(default_locale, bname)); - fprintf(F, "%d;richtung\n", d); - if (!b->type->transparent(b, f)) fputs("1;opaque\n", F); - /* hack: */ - if (b->type==&bt_road) { - int p = rroad(r, d)*100/r->terrain->max_road; - fprintf(F, "%d;prozent\n", p); - } - } - b = b->next; - } - } -} - -static void -cr_output_resources(FILE * F, report_context * ctx, seen_region * sr) -{ - char cbuf[BUFFERSIZE], *pos = cbuf; - region * r = sr->r; - faction * f = ctx->f; - resource_report result[MAX_RAWMATERIALS]; - int n, size = report_resources(sr, result, MAX_RAWMATERIALS, f); - -#ifdef RESOURCECOMPAT - int trees = rtrees(r, 2); - int saplings = rtrees(r, 1); - - if (trees > 0) fprintf(F, "%d;Baeume\n", trees); - if (saplings > 0) fprintf(F, "%d;Schoesslinge\n", saplings); - if (fval(r, RF_MALLORN) && (trees > 0 || saplings > 0)) - fprintf(F, "1;Mallorn\n"); - for (n=0;n=0 && result[n].number>=0) { - fprintf(F, "%d;%s\n", result[n].number, crtag(result[n].name)); - } - } -#endif - - for (n=0;n=0) { - pos = cr_output_resource(pos, result[n].name, f->locale, result[n].number, result[n].level); - } - } - if (pos!=cbuf) fputs(cbuf, F); -} - -static void -cr_region_header(FILE * F, int plid, int nx, int ny, unsigned int uid) -{ - if (plid==0) { - fprintf(F, "REGION %d %d\n", nx, ny); - } else { - fprintf(F, "REGION %d %d %d\n", nx, ny, plid); - } - if (uid) fprintf(F, "%d;id\n", uid); -} - -static void -cr_output_region(FILE * F, report_context * ctx, seen_region * sr) -{ - faction * f = ctx->f; - region * r = sr->r; - plane * pl = rplane(r); - int plid = plane_id(pl), nx, ny; - const char * tname; - int oc[4][2], o = 0; - int uid = r->uid; - -#ifdef OCEAN_NEIGHBORS_GET_NO_ID - if (sr->mode<=see_neighbour && !r->land) { - uid = 0; - } -#endif - - if (opt_cr_absolute_coords) { - nx = r->x; - ny = r->y; - } else { - nx = r->x, ny = r->y; - pnormalize(&nx, &ny, pl); - adjust_coordinates(f, &nx, &ny, pl, r); - } - - if (pl) { - if (ny==pl->maxy) { - oc[o][0] = nx; - oc[o++][1] = pl->miny-1; - } - if (nx==pl->maxx) { - oc[o][0] = pl->minx-1; - oc[o++][1] = ny; - } - if (ny==pl->miny) { - oc[o][0] = nx; - oc[o++][1] = pl->maxy+1; - } - if (nx==pl->minx) { - oc[o][0] = pl->maxx+1; - oc[o++][1] = ny; - } - } - while (o--) { - cr_region_header(F, plid, oc[o][0], oc[o][1], uid); - fputs("\"wrap\";visibility\n", F); - } - - cr_region_header(F, plid, nx, ny, uid); - - if (r->land) { - const char * str = rname(r, f->locale); - if (str && str[0]) { - fprintf(F, "\"%s\";Name\n", str); - } - } - tname = terrain_name(r); - - fprintf(F, "\"%s\";Terrain\n", add_translation(tname, locale_string(f->locale, tname))); - if (sr->mode!=see_unit) fprintf(F, "\"%s\";visibility\n", visibility[sr->mode]); - if (sr->mode == see_neighbour) { - cr_borders(ctx->seen, r, f, sr->mode, F); - } else { - building * b; - ship * sh; - unit * u; - int stealthmod = stealth_modifier(sr->mode); - - if (r->display && r->display[0]) - fprintf(F, "\"%s\";Beschr\n", r->display); - if (fval(r->terrain, LAND_REGION)) { - fprintf(F, "%d;Bauern\n", rpeasants(r)); - if(fval(r, RF_ORCIFIED)) { - fprintf(F, "1;Verorkt\n"); - } - fprintf(F, "%d;Pferde\n", rhorses(r)); - - if (sr->mode>=see_unit) { - if (rule_region_owners()) { - faction * owner = region_get_owner(r); - if (owner) { - fprintf(F, "%d;owner\n", owner->no); - } - } - fprintf(F, "%d;Silber\n", rmoney(r)); - if (skill_enabled[SK_ENTERTAINMENT]) { - fprintf(F, "%d;Unterh\n", entertainmoney(r)); - } - if (is_cursed(r->attribs, C_RIOT, 0)){ - fputs("0;Rekruten\n", F); - } else { - fprintf(F, "%d;Rekruten\n", rpeasants(r) / RECRUITFRACTION); - } - if (production(r)) { - int p_wage = wage(r, NULL, NULL, turn+1); - fprintf(F, "%d;Lohn\n", p_wage); - if (is_mourning(r, turn+1)) { - fputs("1;mourning\n", F); - } - } - if (r->land->ownership) { - fprintf(F, "%d;morale\n", r->land->morale); - } - } - - /* this writes both some tags (RESOURCECOMPAT) and a block. - * must not write any blocks before it */ - cr_output_resources(F, ctx, sr); - - if (sr->mode>=see_unit) { - /* trade */ - if (markets_module() && r->land) { - const item_type * lux = r_luxury(r); - const item_type * herb = r->land->herbtype; - if (lux || herb) { - fputs("PREISE\n", F); - if (lux) { - const char * ch = resourcename(lux->rtype, 0); - fprintf(F, "%d;%s\n", 1, add_translation(ch, locale_string(f->locale, ch))); - } - if (herb) { - const char * ch = resourcename(herb->rtype, 0); - fprintf(F, "%d;%s\n", 1, add_translation(ch, locale_string(f->locale, ch))); - } - } - } else if (rpeasants(r)/TRADE_FRACTION > 0) { - struct demand * dmd = r->land->demands; - fputs("PREISE\n", F); - while (dmd) { - const char * ch = resourcename(dmd->type->itype->rtype, 0); - fprintf(F, "%d;%s\n", (dmd->value - ? dmd->value*dmd->type->price - : -dmd->type->price), - add_translation(ch, locale_string(f->locale, ch))); - dmd=dmd->next; - } - } - } - } - if (r->land) { - print_items(F, r->land->items, f->locale); - } - cr_output_curses(F, f, r, TYP_REGION); - cr_borders(ctx->seen, r, f, sr->mode, F); - if (sr->mode==see_unit && is_astral(r) && !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) - { - /* Sonderbehandlung Teleport-Ebene */ - region_list *rl = astralregions(r, inhabitable); - - if (rl) { - region_list *rl2 = rl; - while(rl2) { - region * r = rl2->data; - int nx = r->x, ny = r->y; - plane * plx = rplane(r); - - pnormalize(&nx, &ny, plx); - adjust_coordinates(f, &nx, &ny, plx, r); - fprintf(F, "SCHEMEN %d %d\n", nx, ny); - fprintf(F, "\"%s\";Name\n", rname(r, f->locale)); - rl2 = rl2->next; - } - free_regionlist(rl); - } - } - - /* describe both passed and inhabited regions */ - show_active_spells(r); - if (fval(r, RF_TRAVELUNIT)) { - boolean seeunits = false, seeships = false; - const attrib * ru; - /* show units pulled through region */ - for (ru = a_find(r->attribs, &at_travelunit); ru && ru->type==&at_travelunit; ru = ru->next) { - unit * u = (unit*)ru->data.v; - if (cansee_durchgezogen(f, r, u, 0) && r!=u->region) { - if (!u->ship || !fval(u, UFL_OWNER)) continue; - if (!seeships) fprintf(F, "DURCHSCHIFFUNG\n"); - seeships = true; - fprintf(F, "\"%s\"\n", shipname(u->ship)); - } - } - for (ru = a_find(r->attribs, &at_travelunit); ru && ru->type==&at_travelunit; ru = ru->next) { - unit * u = (unit*)ru->data.v; - if (cansee_durchgezogen(f, r, u, 0) && r!=u->region) { - if (u->ship) continue; - if (!seeunits) fprintf(F, "DURCHREISE\n"); - seeunits = true; - fprintf(F, "\"%s\"\n", unitname(u)); - } - } - } - cr_output_messages(F, r->msgs, f); - { - message_list * mlist = r_getmessages(r, f); - if (mlist) cr_output_messages(F, mlist, f); - } - /* buildings */ - for (b = rbuildings(r); b; b = b->next) { - int fno = -1; - u = building_owner(b); - if (u && !fval(u, UFL_ANON_FACTION)) { - const faction * sf = visible_faction(f,u); - fno = sf->no; - } - cr_output_building(F, b, u, fno, f); - } - - /* ships */ - for (sh = r->ships; sh; sh = sh->next) { - int fno = -1; - u = shipowner(sh); - if (u && !fval(u, UFL_ANON_FACTION)) { - const faction * sf = visible_faction(f,u); - fno = sf->no; - } - - cr_output_ship(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))) { - cr_output_unit(F, r, f, u, sr->mode); - } - } - } -} - -/* main function of the creport. creates the header and traverses all regions */ -static int -report_computer(const char * filename, report_context * ctx, const char * charset) -{ - static int era = -1; - int i; - faction * f = ctx->f; - const char * prefix; - region * r; - const char * mailto = locale_string(f->locale, "mailto"); - const attrib * a; - seen_region * sr = NULL; -#if SCORE_MODULE - int score = 0, avgscore = 0; -#endif - int enc = get_encoding_by_name(charset); - FILE * F = fopen(filename, "wt"); - - if (era<0) { - era = get_param_int(global.parameters, "world.era", 2); - } - if (F==NULL) { - perror(filename); - return -1; - } else if (enc==ENCODING_UTF8) { - const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; - fwrite(utf8_bom, 1, 3, F); - } - - /* must call this to get all the neighbour regions */ - /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ - /* initialisations, header and lists */ - - fprintf(F, "VERSION %d\n", C_REPORT_VERSION); - fprintf(F, "\"%s\";charset\n", charset); - fprintf(F, "\"%s\";locale\n", locale_name(f->locale)); - fprintf(F, "%d;noskillpoints\n", 1); - fprintf(F, "%ld;date\n", ctx->report_time); - fprintf(F, "\"%s\";Spiel\n", global.gamename); - fprintf(F, "\"%s\";Konfiguration\n", "Standard"); - fprintf(F, "\"%s\";Koordinaten\n", "Hex"); - fprintf(F, "%d;Basis\n", 36); - fprintf(F, "%d;Runde\n", turn); - fprintf(F, "%d;Zeitalter\n", era); - if (mailto!=NULL) { - fprintf(F, "\"%s\";mailto\n", mailto); - fprintf(F, "\"%s\";mailcmd\n", locale_string(f->locale, "mailcmd")); - } - - show_alliances_cr(F, f); - - fprintf(F, "PARTEI %d\n", f->no); - fprintf(F, "\"%s\";locale\n", locale_name(f->locale)); - if (f_get_alliance(f)) { - fprintf(F, "%d;alliance\n", f->alliance->id); - fprintf(F, "%d;joined\n", f->alliance_joindate); - } - fprintf(F, "%d;age\n", f->age); - fprintf(F, "%d;Optionen\n", f->options); -#if SCORE_MODULE - if (f->options & want(O_SCORE) && f->age>DISPLAYSCORE) { - score = f->score; - avgscore = average_score_of_age(f->age, f->age / 24 + 1); - } - fprintf(F, "%d;Punkte\n", score); - fprintf(F, "%d;Punktedurchschnitt\n", avgscore); -#endif - { - const char * zRace = rc_name(f->race, 1); - fprintf(F, "\"%s\";Typ\n", add_translation(zRace, LOC(f->locale, zRace))); - } - prefix = get_prefix(f->attribs); - if (prefix!=NULL) { - prefix = mkname("prefix", prefix); - fprintf(F, "\"%s\";typprefix\n", - add_translation(prefix, LOC(f->locale, prefix))); - } - fprintf(F, "%d;Rekrutierungskosten\n", f->race->recruitcost); - fprintf(F, "%d;Anzahl Personen\n", count_all(f)); - fprintf(F, "\"%s\";Magiegebiet\n", magic_school[f->magiegebiet]); - - if (f->race == new_race[RC_HUMAN]) { - fprintf(F, "%d;Anzahl Immigranten\n", count_migrants(f)); - fprintf(F, "%d;Max. Immigranten\n", count_maxmigrants(f)); - } - - i = countheroes(f); - if (i>0) fprintf(F, "%d;heroes\n", i); - i = maxheroes(f); - if (i>0) fprintf(F, "%d;max_heroes\n", i); - - if (f->age > 1 && f->lastorders != turn) { - fprintf(F, "%d;nmr\n", turn-f->lastorders); - } - - fprintf(F, "\"%s\";Parteiname\n", f->name); - fprintf(F, "\"%s\";email\n", f->email); - if (f->banner) fprintf(F, "\"%s\";banner\n", f->banner); - print_items(F, f->items, f->locale); - fputs("OPTIONEN\n", F); - for (i=0;i!=MAXOPTIONS;++i) { - int flag = want(i); - if (options[i]) { - fprintf(F, "%d;%s\n", (f->options&flag)?1:0, options[i]); - } else if (f->options&flag) { - f->options &= (~flag); - } - } - show_allies_cr(F, f, f->allies); - { - group * g; - for (g=f->groups;g;g=g->next) { - - fprintf(F, "GRUPPE %d\n", g->gid); - fprintf(F, "\"%s\";name\n", g->name); - prefix = get_prefix(g->attribs); - if (prefix!=NULL) { - prefix = mkname("prefix", prefix); - fprintf(F, "\"%s\";typprefix\n", - add_translation(prefix, LOC(f->locale, prefix))); - } - show_allies_cr(F, f, g->allies); - } - } - - cr_output_messages(F, f->msgs, f); - { - struct bmsg * bm; - for (bm=f->battles;bm;bm=bm->next) { - plane * pl = rplane(bm->r); - int plid = plane_id(pl); - region * r = bm->r; - int nx = r->x, ny = r->y; - - pnormalize(&nx, &ny, pl); - adjust_coordinates(f, &nx, &ny, pl, r); - if (!plid) fprintf(F, "BATTLE %d %d\n", nx, ny); - else { - fprintf(F, "BATTLE %d %d %d\n", nx, ny, plid); - } - cr_output_messages(F, bm->msgs, f); - } - } - - cr_find_address(F, f, ctx->addresses); - a = a_find(f->attribs, &at_reportspell); - while (a && a->type==&at_reportspell) { - spell *sp = (spell *)a->data.v; - cr_reportspell(F, sp, f->locale); - a = a->next; - } - for (a=a_find(f->attribs, &at_showitem);a && a->type==&at_showitem;a=a->next) { - const potion_type * ptype = resource2potion(((const item_type*)a->data.v)->rtype); - const char * ch; - const char * description = NULL; - - if (ptype==NULL) continue; - ch = resourcename(ptype->itype->rtype, 0); - fprintf(F, "TRANK %d\n", hashstring(ch)); - fprintf(F, "\"%s\";Name\n", add_translation(ch, locale_string(f->locale, ch))); - fprintf(F, "%d;Stufe\n", ptype->level); - - if (description==NULL) { - const char * pname = resourcename(ptype->itype->rtype, 0); - const char * potiontext = mkname("potion", pname); - description = LOC(f->locale, potiontext); - } - - fprintf(F, "\"%s\";Beschr\n", description); - if (ptype->itype->construction) { - requirement * m = ptype->itype->construction->materials; - - fprintf(F, "ZUTATEN\n"); - - while (m->number) { - ch = resourcename(m->rtype, 0); - fprintf(F, "\"%s\"\n", add_translation(ch, locale_string(f->locale, ch))); - m++; - } - } - } - - /* traverse all regions */ - for (r=ctx->first;sr==NULL && r!=ctx->last;r=r->next) { - sr = find_seen(ctx->seen, r); - } - for (;sr!=NULL;sr=sr->next) { - cr_output_region(F, ctx, sr); - } - report_crtypes(F, f->locale); - write_translations(F); - reset_translations(); - fclose(F); - return 0; -} - -int -crwritemap(const char * filename) -{ - FILE * F = fopen(filename, "w"); - region * r; - - fprintf(F, "VERSION %d\n", C_REPORT_VERSION); - fputs("\"UTF-8\";charset\n", F); - - for (r=regions;r;r=r->next) { - plane * pl = rplane(r); - int plid = plane_id(pl); - if (plid) { - fprintf(F, "REGION %d %d %d\n", r->x, r->y, plid); - } else { - fprintf(F, "REGION %d %d\n", r->x, r->y); - } - fprintf(F, "\"%s\";Name\n\"%s\";Terrain\n", rname(r, default_locale), LOC(default_locale, terrain_name(r))); - } - fclose(F); - return 0; -} - -void -register_cr(void) -{ - tsf_register("report", &cr_ignore); - tsf_register("string", &cr_string); - tsf_register("order", &cr_order); - tsf_register("spell", &cr_spell); - tsf_register("curse", &cr_curse); - tsf_register("int", &cr_int); - tsf_register("unit", &cr_unit); - tsf_register("region", &cr_region); - tsf_register("faction", &cr_faction); - tsf_register("ship", &cr_ship); - tsf_register("building", &cr_building); - tsf_register("skill", &cr_skill); - tsf_register("resource", &cr_resource); - tsf_register("race", &cr_race); - tsf_register("direction", &cr_int); - tsf_register("alliance", &cr_alliance); - tsf_register("resources", &cr_resources); - tsf_register("items", &cr_resources); - tsf_register("regions", &cr_regions); - - if (!nocr) register_reporttype("cr", &report_computer, 1<next; - free(t); - } - junkyard = 0; -} - - +/* vi: set ts=2: ++-------------------+ Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel ++-------------------+ +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "creport.h" + +/* tweakable features */ +#define RENDER_CRMESSAGES +#define BUFFERSIZE 32768 +#define RESOURCECOMPAT + +/* modules include */ +#include + +/* attributes include */ +#include +#include +#include +#include +#include + +/* gamecode includes */ +#include "laws.h" +#include "economy.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include +#include + +/* imports */ +extern int verbosity; +boolean opt_cr_absolute_coords = false; + +/* globals */ +#define C_REPORT_VERSION 66 + +#define TAG_LOCALE "de" +#ifdef TAG_LOCALE +static const char * +crtag(const char * key) +{ + static const struct locale * lang = NULL; + if (!lang) lang = find_locale(TAG_LOCALE); + return locale_string(lang, key); +} +#else +#define crtag(x) (x) +#endif +/* + * translation table + */ +typedef struct translation { + struct translation * next; + char * key; + const char * value; +} translation; + +#define TRANSMAXHASH 257 +static translation * translation_table[TRANSMAXHASH]; +static translation * junkyard; + +static const char * +add_translation(const char * key, const char * value) +{ + int kk = ((key[0] << 5) + key[0]) % TRANSMAXHASH; + translation * t = translation_table[kk]; + while (t && strcmp(t->key, key)!=0) t=t->next; + if (!t) { + if (junkyard) { + t = junkyard; + junkyard = junkyard->next; + } else t = malloc(sizeof(translation)); + t->key = strdup(key); + t->value = value; + t->next = translation_table[kk]; + translation_table[kk] = t; + } + return crtag(key); +} + +static void +write_translations(FILE * F) +{ + int i; + fputs("TRANSLATION\n", F); + for (i=0;i!=TRANSMAXHASH;++i) { + translation * t = translation_table[i]; + while (t) { + fprintf(F, "\"%s\";%s\n", t->value, crtag(t->key)); + t = t->next; + } + } +} + +static void +reset_translations(void) +{ + int i; + for (i=0;i!=TRANSMAXHASH;++i) { + translation * t = translation_table[i]; + while (t) { + translation * c = t->next; + free(t->key); + t->next = junkyard; + junkyard = t; + t = c; + } + translation_table[i] = 0; + } +} + +#include + +static void +print_items(FILE * F, item * items, const struct locale * lang) +{ + item * itm; + + for (itm=items; itm; itm=itm->next) { + int in = itm->number; + const char * ic = resourcename(itm->type->rtype, 0); + if (itm==items) fputs("GEGENSTAENDE\n", F); + fprintf(F, "%d;%s\n", in, add_translation(ic, LOC(lang, ic))); + } +} + +static void +cr_output_curses(FILE * F, const faction * viewer, const void * obj, typ_t typ) +{ + boolean header = false; + attrib *a = NULL; + int self = 0; + region *r; + + /* Die Sichtbarkeit eines Zaubers und die Zaubermeldung sind bei + * Gebäuden und Schiffen je nach, ob man Besitzer ist, verschieden. + * Bei Einheiten sieht man Wirkungen auf eigene Einheiten immer. + * Spezialfälle (besonderes Talent, verursachender Magier usw. werde + * bei jedem curse gesondert behandelt. */ + if (typ == TYP_SHIP){ + ship * sh = (ship*)obj; + unit * owner = shipowner(sh); + a = sh->attribs; + r = sh->region; + if (owner != NULL) { + if (owner->faction == viewer){ + self = 2; + } else { /* steht eine person der Partei auf dem Schiff? */ + unit *u = NULL; + for (u = r->units; u; u = u->next) { + if (u->ship == sh) { + self = 1; + break; + } + } + } + } + } else if (typ == TYP_BUILDING) { + building * b = (building*)obj; + unit * owner = building_owner(b); + a = b->attribs; + r = b->region; + if (owner != NULL){ + if (owner->faction == viewer){ + self = 2; + } else { /* steht eine Person der Partei in der Burg? */ + unit *u = NULL; + for (u = r->units; u; u = u->next) { + if (u->building == b) { + self = 1; + break; + } + } + } + } + } else if (typ == TYP_UNIT) { + unit *u = (unit *)obj; + a = u->attribs; + r = u->region; + if (u->faction == viewer) { + self = 2; + } + } else if (typ == TYP_REGION) { + r = (region *)obj; + a = r->attribs; + } else { + /* fehler */ + } + + while (a) { + if (fval(a->type, ATF_CURSE)) { + curse * c = (curse *)a->data.v; + message * msg; + + if (c->type->cansee) { + self = c->type->cansee(viewer, obj, typ, c, self); + } + msg = msg_curse(c, obj, typ, self); + + if (msg) { + char buf[BUFFERSIZE]; + if (!header) { + header = 1; + fputs("EFFECTS\n", F); + } + nr_render(msg, viewer->locale, buf, sizeof(buf), viewer); + fprintf(F, "\"%s\"\n", buf); + msg_release(msg); + } + } else if (a->type==&at_effect && self) { + effect_data * data = (effect_data *)a->data.v; + if (data->value>0) { + const char * key = resourcename(data->type->itype->rtype, 0); + if (!header) { + header = 1; + fputs("EFFECTS\n", F); + } + fprintf(F, "\"%d %s\"\n", data->value, add_translation(key, locale_string(default_locale, key))); + } + } + a = a->next; + } +} + +static int +cr_unit(variant var, char * buffer, const void * userdata) +{ + unit * u = (unit *)var.v; + sprintf(buffer, "%d", u?u->no:-1); + return 0; +} + +static int +cr_ship(variant var, char * buffer, const void * userdata) +{ + ship * u = (ship *)var.v; + sprintf(buffer, "%d", u?u->no:-1); + return 0; +} + +static int +cr_building(variant var, char * buffer, const void * userdata) +{ + building * u = (building *)var.v; + sprintf(buffer, "%d", u?u->no:-1); + return 0; +} + +static int +cr_faction(variant var, char * buffer, const void * userdata) +{ + faction * f = (faction *)var.v; + sprintf(buffer, "%d", f?f->no:-1); + return 0; +} + +static int +cr_region(variant var, char * buffer, const void * userdata) +{ + const faction * report = (const faction*)userdata; + region * r = (region *)var.v; + if (r) { + plane * pl = rplane(r); + int nx = r->x, ny = r->y; + pnormalize(&nx, &ny, pl); + adjust_coordinates(report, &nx, &ny, pl, r); + sprintf(buffer, "%d %d %d", nx, ny, plane_id(pl)); + return 0; + } + return -1; +} + +static int +cr_resource(variant var, char * buffer, const void * userdata) +{ + const faction * report = (const faction*)userdata; + const resource_type * r = (const resource_type *)var.v; + if (r) { + const char * key = resourcename(r, 0); + sprintf(buffer, "\"%s\"", + add_translation(key, locale_string(report->locale, key))); + return 0; + } + return -1; +} + +static int +cr_race(variant var, char * buffer, const void * userdata) +{ + const faction * report = (const faction*)userdata; + const struct race * rc = (const race *)var.v; + const char * key = rc_name(rc, 0); + sprintf(buffer, "\"%s\"", + add_translation(key, locale_string(report->locale, key))); + return 0; +} + +static int +cr_alliance(variant var, char * buffer, const void * userdata) +{ + const alliance * al = (const alliance *)var.v; + if (al!=NULL) { + sprintf(buffer, "%d", al->id); + } + unused(userdata); + return 0; +} + +static int +cr_skill(variant var, char * buffer, const void * userdata) +{ + const faction * report = (const faction*)userdata; + skill_t sk = (skill_t)var.i; + if (sk!=NOSKILL) sprintf(buffer, "\"%s\"", + add_translation(mkname("skill", skillnames[sk]), skillname(sk, report->locale))); + else strcpy(buffer, "\"\""); + return 0; +} + +static int +cr_order(variant var, char * buffer, const void * userdata) +{ + order * ord = (order*)var.v; + if (ord!=NULL) { + char * wp = buffer; + char * cmd = getcommand(ord); + const char * rp = cmd; + + *wp++ = '\"'; + while (*rp) { + switch (*rp) { + case '\"': + case '\\': + *wp++ = '\\'; + default: + *wp++ = *rp++; + } + } + *wp++ = '\"'; + *wp++ = 0; + + free(cmd); + } + else strcpy(buffer, "\"\""); + return 0; +} + +static int +cr_resources(variant var, char * buffer, const void * userdata) +{ + faction * f = (faction*)userdata; + resource * rlist = (resource*)var.v; + char * wp = buffer; + if (rlist!=NULL) { + const char * name = resourcename(rlist->type, rlist->number!=1); + wp += sprintf(wp, "\"%d %s", rlist->number, add_translation(name, LOC(f->locale, name))); + for (;;) { + rlist = rlist->next; + if (rlist==NULL) break; + name = resourcename(rlist->type, rlist->number!=1); + wp += sprintf(wp, ", %d %s", rlist->number, add_translation(name, LOC(f->locale, name))); + } + strcat(wp, "\""); + } + return 0; +} + +static int +cr_regions(variant var, char * buffer, const void * userdata) +{ + faction * f = (faction*)userdata; + const arg_regions * rdata = (const arg_regions *)var.v; + + if (rdata!=NULL && rdata->nregions>0) { + region * r = rdata->regions[0]; + plane * pl = rplane(r); + int i, z = plane_id(pl); + char * wp = buffer; + int nx = r->x, ny = r->y; + + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl, r); + wp += sprintf(wp, "\"%d %d %d", nx, ny, z); + for (i=1;i!=rdata->nregions;++i) { + r = rdata->regions[i]; + pl = rplane(r); + z = plane_id(pl); + wp += sprintf(wp, ", %d %d %d", nx, ny, z); + } + strcat(wp, "\""); + } else { + strcpy(buffer, "\"\""); + } + return 0; +} + +static int +cr_spell(variant var, char * buffer, const void * userdata) +{ + const faction * report = (const faction*)userdata; + spell * sp = (spell*)var.v; + if (sp!=NULL) sprintf(buffer, "\"%s\"", spell_name(sp, report->locale)); + else strcpy(buffer, "\"\""); + return 0; +} + +static int +cr_curse(variant var, char * buffer, const void * userdata) +{ + const faction * report = (const faction*)userdata; + const curse_type * ctype = (const curse_type*)var.v; + if (ctype!=NULL) { + sprintf(buffer, "\"%s\"", curse_name(ctype, report->locale)); + } else strcpy(buffer, "\"\""); + return 0; +} + +/*static int msgno; */ + +#define MTMAXHASH 1021 + +static struct known_mtype { + const struct message_type * mtype; + struct known_mtype * nexthash; +} * mtypehash[MTMAXHASH]; + +static void +report_crtypes(FILE * F, const struct locale* lang) +{ + int i; + for (i=0;i!=MTMAXHASH;++i) { + struct known_mtype * kmt; + for (kmt=mtypehash[i];kmt;kmt=kmt->nexthash) { + const struct nrmessage_type * nrt = nrt_find(lang, kmt->mtype); + if (nrt) { + unsigned int hash = kmt->mtype->key; + fprintf(F, "MESSAGETYPE %d\n", hash); + fputc('\"', F); + fputs(escape_string(nrt_string(nrt), NULL, 0), F); + fputs("\";text\n", F); + fprintf(F, "\"%s\";section\n", nrt_section(nrt)); + } + } + while (mtypehash[i]) { + kmt = mtypehash[i]; + mtypehash[i] = mtypehash[i]->nexthash; + free(kmt); + } + } +} + +static unsigned int +messagehash(const struct message * msg) +{ + variant var; + var.v = (void *)msg; + return (unsigned int)var.i; +} + +static void +render_messages(FILE * F, faction * f, message_list *msgs) +{ + struct mlist* m = msgs->begin; + while (m) { + char crbuffer[BUFFERSIZE]; /* gross, wegen spionage-messages :-( */ + boolean printed = false; + const struct message_type * mtype = m->msg->type; + unsigned int hash = mtype->key; +#ifdef RENDER_CRMESSAGES + char nrbuffer[1024*32]; + nrbuffer[0] = '\0'; + if (nr_render(m->msg, f->locale, nrbuffer, sizeof(nrbuffer), f)>=0) { + fprintf(F, "MESSAGE %u\n", messagehash(m->msg)); + fprintf(F, "%d;type\n", hash); + fwritestr(F, nrbuffer); + fputs(";rendered\n", F); + printed = true; + } +#endif + crbuffer[0] = '\0'; + if (cr_render(m->msg, crbuffer, (const void*)f)==0) { + if (!printed) fprintf(F, "MESSAGE %u\n", messagehash(m->msg)); + if (crbuffer[0]) fputs(crbuffer, F); + } else { + log_error(("could not render cr-message %p: %s\n", m->msg, m->msg->type->name)); + } + if (printed) { + unsigned int ihash = hash % MTMAXHASH; + struct known_mtype * kmt = mtypehash[ihash]; + while (kmt && kmt->mtype != mtype) kmt = kmt->nexthash; + if (kmt==NULL) { + kmt = (struct known_mtype*)malloc(sizeof(struct known_mtype)); + kmt->nexthash = mtypehash[ihash]; + kmt->mtype = mtype; + mtypehash[ihash] = kmt; + } + } + m = m->next; + } +} + +static void +cr_output_messages(FILE * F, message_list *msgs, faction * f) +{ + if (msgs) render_messages(F, f, msgs); +} + +/* prints a building */ +static void +cr_output_building(FILE * F, building * b, const unit * owner, int fno, faction *f) +{ + const char * bname, * billusion; + + fprintf(F, "BURG %d\n", b->no); + + report_building(b, &bname, &billusion); + if (billusion) { + fprintf(F, "\"%s\";Typ\n", add_translation(billusion, LOC(f->locale, billusion))); + if (owner && owner->faction==f) { + fprintf(F, "\"%s\";wahrerTyp\n", add_translation(bname, LOC(f->locale, bname))); + } + } else { + fprintf(F, "\"%s\";Typ\n", add_translation(bname, LOC(f->locale, bname))); + } + 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 ? owner->no : -1); + if (fno >= 0) + fprintf(F, "%d;Partei\n", fno); + if (b->besieged) + fprintf(F, "%d;Belagerer\n", b->besieged); + cr_output_curses(F, f, b, TYP_BUILDING); +} +/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ + +/* prints a ship */ +static void +cr_output_ship(FILE * F, 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); + if (sh->display && sh->display[0]) + fprintf(F, "\"%s\";Beschr\n", sh->display); + fprintf(F, "\"%s\";Typ\n", add_translation(sh->type->name[0], locale_string(f->locale, sh->type->name[0]))); + fprintf(F, "%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); + } + if (u) + fprintf(F, "%d;Kapitaen\n", u ? u->no : -1); + 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)); + } + /* shore */ + w = NODIRECTION; + if (!fval(r->terrain, SEA_REGION)) w = sh->coast; + if (w != NODIRECTION) + fprintf(F, "%d;Kueste\n", w); + + cr_output_curses(F, f, sh, TYP_SHIP); +} + +static void +fwriteorder(FILE * F, const struct order * ord, const struct locale * lang, boolean escape) +{ + char ebuf[1024]; + char obuf[1024]; + const char * str = obuf; + fputc('"', F); + write_order(ord, obuf, sizeof(obuf)); + if (escape) { + str = escape_string(obuf, ebuf, sizeof(ebuf)); + } + if (str[0]) fputs(str, F); + fputc('"', F); +} + +static void cr_output_spells(FILE * F, spell_list * slist, const faction * f, int maxlevel) +{ + if (slist) { + fprintf(F, "SPRUECHE\n"); + for (;slist; slist = slist->next) { + spell * sp = slist->data; + if (sp->level <= maxlevel) { + const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, f->locale)); + fprintf(F, "\"%s\"\n", name); + } + } + } +} + +/* prints all that belongs to a unit */ +static void +cr_output_unit(FILE * F, const region * r, + const faction * f, /* observers faction */ + const unit * u, int mode) +{ + /* Race attributes are always plural and item attributes always + * singular */ + const char * str; + const item_type * lasttype; + int pr; + item *itm, *show; + building * b; + const char * pzTmp; + skill * sv; + const attrib *a_fshidden = NULL; + boolean itemcloak = false; + static const curse_type * itemcloak_ct = 0; + static boolean init = false; + item result[MAX_INVENTORY]; + + if (fval(u->race, RCF_INVISIBLE)) return; + + if (!init) { + init = true; + itemcloak_ct = ct_find("itemcloak"); + } + if (itemcloak_ct!=NULL) { + itemcloak = curse_active(get_curse(u->attribs, itemcloak_ct)); + } + + assert(u && u->number); + + fprintf(F, "EINHEIT %d\n", u->no); + fprintf(F, "\"%s\";Name\n", u->name); + str = u_description(u, f->locale); + if (str) { + fprintf(F, "\"%s\";Beschr\n", str); + } + { + /* print faction information */ + const faction * sf = visible_faction(f, u); + const char * prefix = raceprefix(u); + if (u->faction == f || omniscient(f)) { + const attrib * a_otherfaction = a_find(u->attribs, &at_otherfaction); + const faction * otherfaction = a_otherfaction?get_otherfaction(a_otherfaction):NULL; + /* my own faction, full info */ + const attrib *a = NULL; + unit * mage; + + if (fval(u, UFL_GROUP)) a = a_find(u->attribs, &at_group); + if (a!=NULL) { + const group * g = (const group*)a->data.v; + fprintf(F, "%d;gruppe\n", g->gid); + } + fprintf(F, "%d;Partei\n", u->faction->no); + if (sf!=u->faction) fprintf(F, "%d;Verkleidung\n", sf->no); + if (fval(u, UFL_ANON_FACTION)) + fprintf(F, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION))); + if (otherfaction) { + if (otherfaction!=u->faction) { + fprintf(F, "%d;Anderepartei\n", otherfaction->no); + } + } + mage = get_familiar_mage(u); + if (mage) { + fprintf(F, "%u;familiarmage\n", mage->no); + } + } else { + if (fval(u, UFL_ANON_FACTION)) { + /* faction info is hidden */ + fprintf(F, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION))); + } else { + const attrib * a_otherfaction = a_find(u->attribs, &at_otherfaction); + const faction * otherfaction = a_otherfaction?get_otherfaction(a_otherfaction):NULL; + /* other unit. show visible faction, not u->faction */ + fprintf(F, "%d;Partei\n", sf->no); + if (sf == f) { + fprintf(F, "1;Verraeter\n"); + } + if (a_otherfaction) { + if (otherfaction!=u->faction) { + if (alliedunit(u, f, HELP_FSTEALTH)) { + fprintf(F, "%d;Anderepartei\n", otherfaction->no); + } + } + } + } + } + if (prefix) { + prefix = mkname("prefix", prefix); + fprintf(F, "\"%s\";typprefix\n", add_translation(prefix, LOC(f->locale, prefix))); + } + } + if (u->faction != f && a_fshidden + && a_fshidden->data.ca[0] == 1 && effskill(u, SK_STEALTH) >= 6) { + fprintf(F, "-1;Anzahl\n"); + } else { + fprintf(F, "%d;Anzahl\n", u->number); + } + + pzTmp = get_racename(u->attribs); + if (pzTmp) { + fprintf(F, "\"%s\";Typ\n", pzTmp); + if (u->faction==f && fval(u->race, RCF_SHAPESHIFTANY)) { + const char * zRace = rc_name(u->race, 1); + fprintf(F, "\"%s\";wahrerTyp\n", + add_translation(zRace, locale_string(f->locale, zRace))); + } + } else { + const race * irace = u_irace(u); + const char * zRace = rc_name(irace, 1); + fprintf(F, "\"%s\";Typ\n", + add_translation(zRace, locale_string(f->locale, zRace))); + if (u->faction==f && irace!=u->race) { + assert(skill_enabled[SK_STEALTH] || !"we're resetting this on load, so.. ircase should never be used"); + zRace = rc_name(u->race, 1); + fprintf(F, "\"%s\";wahrerTyp\n", + add_translation(zRace, locale_string(f->locale, zRace))); + } + } + + if (u->building) { + assert(u->building->region); + fprintf(F, "%d;Burg\n", u->building->no); + } + if (u->ship) { + assert(u->ship->region); + fprintf(F, "%d;Schiff\n", u->ship->no); + } + if (is_guard(u, GUARD_ALL)!=0) { + fprintf(F, "%d;bewacht\n", 1); + } + if ((b=usiege(u))!=NULL) { + fprintf(F, "%d;belagert\n", b->no); + } + /* additional information for own units */ + if (u->faction == f || omniscient(f)) { + order * ord; + const char *xc; + const char * c; + int i; + + i = ualias(u); + if (i>0) + fprintf(F, "%d;temp\n", i); + else if (i<0) + fprintf(F, "%d;alias\n", -i); + i = get_money(u); + fprintf(F, "%d;Kampfstatus\n", u->status); + fprintf(F, "%d;weight\n", weight(u)); + if (fval(u, UFL_NOAID)) { + fputs("1;unaided\n", F); + } + if (fval(u, UFL_STEALTH)) { + i = u_geteffstealth(u); + if (i >= 0) { + fprintf(F, "%d;Tarnung\n", i); + } + } + xc = uprivate(u); + if (xc) { + fprintf(F, "\"%s\";privat\n", xc); + } + c = hp_status(u); + if (c && *c && (u->faction == f || omniscient(f))) { + fprintf(F, "\"%s\";hp\n", add_translation(c, locale_string(u->faction->locale, c))); + } + if (fval(u, UFL_HERO)) { + fputs("1;hero\n", F); + } + + if (fval(u, UFL_HUNGER) && (u->faction == f)) { + fputs("1;hunger\n", F); + } + if (is_mage(u)) { + fprintf(F, "%d;Aura\n", get_spellpoints(u)); + fprintf(F, "%d;Auramax\n", max_spellpoints(u->region,u)); + } + /* default commands */ + fprintf(F, "COMMANDS\n"); + for (ord = u->old_orders; ord; ord = ord->next) { + /* this new order will replace the old defaults */ + if (is_persistent(ord)) { + fwriteorder(F, ord, f->locale, true); + fputc('\n', F); + } + } + for (ord = u->orders; ord; ord = ord->next) { + if (u->old_orders && is_repeated(ord)) continue; /* unit has defaults */ + if (is_persistent(ord)) { + fwriteorder(F, ord, f->locale, true); + fputc('\n', F); + } + } + + /* talents */ + pr = 0; + for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { + if (sv->level>0) { + skill_t sk = sv->id; + int esk = eff_skill(u, sk, r); + if (!pr) { + pr = 1; + fprintf(F, "TALENTE\n"); + } + fprintf(F, "%d %d;%s\n", u->number*level_days(sv->level), esk, + add_translation(mkname("skill", skillnames[sk]), skillname(sk, f->locale))); + } + } + /* spells */ + if (is_mage(u)) { + sc_mage * mage = get_mage(u); + spell_list ** slistp = get_spelllist(mage, u->faction); + int i, maxlevel = effskill(u, SK_MAGIC); + + cr_output_spells(F, *slistp, f, maxlevel); + + for (i=0;i!=MAXCOMBATSPELLS;++i) { + const spell * sp = mage->combatspells[i].sp; + if (sp) { + const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, f->locale)); + fprintf(F, "KAMPFZAUBER %d\n", i); + fprintf(F, "\"%s\";name\n", name); + fprintf(F, "%d;level\n", mage->combatspells[i].level); + } + } + } + } + /* items */ + pr = 0; + if (f == u->faction || omniscient(u->faction)) { + show = u->items; + } else if (itemcloak==false && mode>=see_unit && !(a_fshidden + && a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) + { + int n = report_items(u->items, result, MAX_INVENTORY, u, f); + assert(n>=0); + if (n>0) show = result; + else show = NULL; + } else { + show = NULL; + } + lasttype = NULL; + for (itm=show; itm; itm=itm->next) { + const char * ic; + int in; + assert(itm->type!=lasttype || !"error: list contains two objects of the same item"); + report_item(u, itm, f, NULL, &ic, &in, true); + if (in==0) continue; + if (!pr) { + pr = 1; + fputs("GEGENSTAENDE\n", F); + } + fprintf(F, "%d;%s\n", in, add_translation(ic, locale_string(f->locale, ic))); + } + + cr_output_curses(F, f, u, TYP_UNIT); +} +/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ + +/* prints allies */ +static void +show_allies_cr(FILE * F, const faction * f, const ally * sf) +{ + for (; sf; sf = sf->next) if (sf->faction) { + int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); + if (mode!=0 && sf->status>0) { + fprintf(F, "ALLIANZ %d\n", sf->faction->no); + fprintf(F, "\"%s\";Parteiname\n", sf->faction->name); + fprintf(F, "%d;Status\n", sf->status & HELP_ALL); + } + } +} + +/* prints allies */ +static void +show_alliances_cr(FILE * F, const faction * f) +{ + alliance * al = f_get_alliance(f); + if (al) { + faction * lead = alliance_get_leader(al); + assert(lead); + fprintf(F, "ALLIANCE %d\n", al->id); + fprintf(F, "\"%s\";name\n", al->name); + fprintf(F, "%d;leader\n", lead->no); + } +} + +/* prints all visible spells in a region */ +static void +show_active_spells(const region * r) +{ + char fogwall[MAXDIRECTIONS]; +#ifdef TODO /* alte Regionszauberanzeigen umstellen */ + unit *u; + int env = 0; +#endif + memset(fogwall, 0, sizeof(char) * MAXDIRECTIONS); + +} +/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ + +/* this is a copy of laws.c->find_address output changed. */ +static void +cr_find_address(FILE * F, const faction * uf, const faction_list * addresses) +{ + const faction_list * flist = addresses; + while (flist!=NULL) { + const faction * f = flist->data; + if (uf!=f) { + fprintf(F, "PARTEI %d\n", f->no); + fprintf(F, "\"%s\";Parteiname\n", f->name); + if (f->email) fprintf(F, "\"%s\";email\n", f->email); + if (f->banner) fprintf(F, "\"%s\";banner\n", f->banner); + fprintf(F, "\"%s\";locale\n", locale_name(f->locale)); + if (f->alliance && f->alliance==uf->alliance) { + fprintf(F, "%d;alliance\n", f->alliance->id); + } + } + flist = flist->next; + } +} +/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ + +static void +cr_reportspell(FILE * F, spell *sp, const struct locale * lang) +{ + int k; + const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, lang)); + + fprintf(F, "ZAUBER %d\n", hashstring(sp->sname)); + fprintf(F, "\"%s\";name\n", name); + fprintf(F, "%d;level\n", sp->level); + fprintf(F, "%d;rank\n", sp->rank); + fprintf(F, "\"%s\";info\n", spell_info(sp, lang)); + if (sp->parameter) fprintf(F, "\"%s\";syntax\n", sp->parameter); + else fputs("\"\";syntax\n", F); + + if (sp->sptyp & PRECOMBATSPELL) fputs("\"precombat\";class\n", F); + else if (sp->sptyp & COMBATSPELL) fputs("\"combat\";class\n", F); + else if (sp->sptyp & POSTCOMBATSPELL) fputs("\"postcombat\";class\n", F); + else fputs("\"normal\";class\n", F); + + if (sp->sptyp & FARCASTING) fputs("1;far\n", F); + if (sp->sptyp & OCEANCASTABLE) fputs("1;ocean\n", F); + if (sp->sptyp & ONSHIPCAST) fputs("1;ship\n", F); + if (!(sp->sptyp & NOTFAMILIARCAST)) fputs("1;familiar\n", F); + fputs("KOMPONENTEN\n", F); + + for (k = 0; sp->components[k].type; ++k) { + const resource_type * rtype = sp->components[k].type; + int itemanz = sp->components[k].amount; + int costtyp = sp->components[k].cost; + if (itemanz > 0) { + const char * name = resourcename(rtype, 0); + fprintf(F, "%d %d;%s\n", itemanz, costtyp == SPC_LEVEL || costtyp == SPC_LINEAR, + add_translation(name, LOC(lang, name))); + } + } +} + +static char * +cr_output_resource(char * buf, const char * name, const struct locale * loc, int amount, int level) +{ + buf += sprintf(buf, "RESOURCE %u\n", hashstring(name)); + buf += sprintf(buf, "\"%s\";type\n", add_translation(name, LOC(loc, name))); + if (amount>=0) { + if (level>=0) buf += sprintf(buf, "%d;skill\n", level); + buf += sprintf(buf, "%d;number\n", amount); + } + return buf; +} + +static void +cr_borders(seen_region ** seen, const region * r, const faction * f, int seemode, FILE * F) +{ + direction_t d; + int g = 0; + for (d = 0; d != MAXDIRECTIONS; d++) + { /* Nachbarregionen, die gesehen werden, ermitteln */ + const region * r2 = rconnect(r, d); + const connection * b; + if (!r2) continue; + if (seemode==see_neighbour) { + seen_region * sr = find_seen(seen, r2); + if (sr==NULL || sr->mode<=see_neighbour) continue; + } + b = get_borders(r, r2); + while (b) { + boolean cs = b->type->fvisible(b, f, r); + + if (!cs) { + cs = b->type->rvisible(b, r); + if (!cs) { + unit * us = r->units; + while (us && !cs) { + if (us->faction==f) { + cs = b->type->uvisible(b, us); + if (cs) break; + } + us=us->next; + } + } + } + if (cs) { + const char * bname = mkname("border", b->type->name(b, r, f, GF_PURE)); + fprintf(F, "GRENZE %d\n", ++g); + fprintf(F, "\"%s\";typ\n", LOC(default_locale, bname)); + fprintf(F, "%d;richtung\n", d); + if (!b->type->transparent(b, f)) fputs("1;opaque\n", F); + /* hack: */ + if (b->type==&bt_road) { + int p = rroad(r, d)*100/r->terrain->max_road; + fprintf(F, "%d;prozent\n", p); + } + } + b = b->next; + } + } +} + +static void +cr_output_resources(FILE * F, report_context * ctx, seen_region * sr) +{ + char cbuf[BUFFERSIZE], *pos = cbuf; + region * r = sr->r; + faction * f = ctx->f; + resource_report result[MAX_RAWMATERIALS]; + int n, size = report_resources(sr, result, MAX_RAWMATERIALS, f); + +#ifdef RESOURCECOMPAT + int trees = rtrees(r, 2); + int saplings = rtrees(r, 1); + + if (trees > 0) fprintf(F, "%d;Baeume\n", trees); + if (saplings > 0) fprintf(F, "%d;Schoesslinge\n", saplings); + if (fval(r, RF_MALLORN) && (trees > 0 || saplings > 0)) + fprintf(F, "1;Mallorn\n"); + for (n=0;n=0 && result[n].number>=0) { + fprintf(F, "%d;%s\n", result[n].number, crtag(result[n].name)); + } + } +#endif + + for (n=0;n=0) { + pos = cr_output_resource(pos, result[n].name, f->locale, result[n].number, result[n].level); + } + } + if (pos!=cbuf) fputs(cbuf, F); +} + +static void +cr_region_header(FILE * F, int plid, int nx, int ny, unsigned int uid) +{ + if (plid==0) { + fprintf(F, "REGION %d %d\n", nx, ny); + } else { + fprintf(F, "REGION %d %d %d\n", nx, ny, plid); + } + if (uid) fprintf(F, "%d;id\n", uid); +} + +static void +cr_output_region(FILE * F, report_context * ctx, seen_region * sr) +{ + faction * f = ctx->f; + region * r = sr->r; + plane * pl = rplane(r); + int plid = plane_id(pl), nx, ny; + const char * tname; + int oc[4][2], o = 0; + int uid = r->uid; + +#ifdef OCEAN_NEIGHBORS_GET_NO_ID + if (sr->mode<=see_neighbour && !r->land) { + uid = 0; + } +#endif + + if (opt_cr_absolute_coords) { + nx = r->x; + ny = r->y; + } else { + nx = r->x, ny = r->y; + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl, r); + } + + if (pl) { + if (ny==pl->maxy) { + oc[o][0] = nx; + oc[o++][1] = pl->miny-1; + } + if (nx==pl->maxx) { + oc[o][0] = pl->minx-1; + oc[o++][1] = ny; + } + if (ny==pl->miny) { + oc[o][0] = nx; + oc[o++][1] = pl->maxy+1; + } + if (nx==pl->minx) { + oc[o][0] = pl->maxx+1; + oc[o++][1] = ny; + } + } + while (o--) { + cr_region_header(F, plid, oc[o][0], oc[o][1], uid); + fputs("\"wrap\";visibility\n", F); + } + + cr_region_header(F, plid, nx, ny, uid); + + if (r->land) { + const char * str = rname(r, f->locale); + if (str && str[0]) { + fprintf(F, "\"%s\";Name\n", str); + } + } + tname = terrain_name(r); + + fprintf(F, "\"%s\";Terrain\n", add_translation(tname, locale_string(f->locale, tname))); + if (sr->mode!=see_unit) fprintf(F, "\"%s\";visibility\n", visibility[sr->mode]); + if (sr->mode == see_neighbour) { + cr_borders(ctx->seen, r, f, sr->mode, F); + } else { + building * b; + ship * sh; + unit * u; + int stealthmod = stealth_modifier(sr->mode); + + if (r->display && r->display[0]) + fprintf(F, "\"%s\";Beschr\n", r->display); + if (fval(r->terrain, LAND_REGION)) { + fprintf(F, "%d;Bauern\n", rpeasants(r)); + if(fval(r, RF_ORCIFIED)) { + fprintf(F, "1;Verorkt\n"); + } + fprintf(F, "%d;Pferde\n", rhorses(r)); + + if (sr->mode>=see_unit) { + if (rule_region_owners()) { + faction * owner = region_get_owner(r); + if (owner) { + fprintf(F, "%d;owner\n", owner->no); + } + } + fprintf(F, "%d;Silber\n", rmoney(r)); + if (skill_enabled[SK_ENTERTAINMENT]) { + fprintf(F, "%d;Unterh\n", entertainmoney(r)); + } + if (is_cursed(r->attribs, C_RIOT, 0)){ + fputs("0;Rekruten\n", F); + } else { + fprintf(F, "%d;Rekruten\n", rpeasants(r) / RECRUITFRACTION); + } + if (production(r)) { + int p_wage = wage(r, NULL, NULL, turn+1); + fprintf(F, "%d;Lohn\n", p_wage); + if (is_mourning(r, turn+1)) { + fputs("1;mourning\n", F); + } + } + if (r->land->ownership) { + fprintf(F, "%d;morale\n", r->land->morale); + } + } + + /* this writes both some tags (RESOURCECOMPAT) and a block. + * must not write any blocks before it */ + cr_output_resources(F, ctx, sr); + + if (sr->mode>=see_unit) { + /* trade */ + if (markets_module() && r->land) { + const item_type * lux = r_luxury(r); + const item_type * herb = r->land->herbtype; + if (lux || herb) { + fputs("PREISE\n", F); + if (lux) { + const char * ch = resourcename(lux->rtype, 0); + fprintf(F, "%d;%s\n", 1, add_translation(ch, locale_string(f->locale, ch))); + } + if (herb) { + const char * ch = resourcename(herb->rtype, 0); + fprintf(F, "%d;%s\n", 1, add_translation(ch, locale_string(f->locale, ch))); + } + } + } else if (rpeasants(r)/TRADE_FRACTION > 0) { + struct demand * dmd = r->land->demands; + fputs("PREISE\n", F); + while (dmd) { + const char * ch = resourcename(dmd->type->itype->rtype, 0); + fprintf(F, "%d;%s\n", (dmd->value + ? dmd->value*dmd->type->price + : -dmd->type->price), + add_translation(ch, locale_string(f->locale, ch))); + dmd=dmd->next; + } + } + } + } + if (r->land) { + print_items(F, r->land->items, f->locale); + } + cr_output_curses(F, f, r, TYP_REGION); + cr_borders(ctx->seen, r, f, sr->mode, F); + if (sr->mode==see_unit && is_astral(r) && !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) + { + /* Sonderbehandlung Teleport-Ebene */ + region_list *rl = astralregions(r, inhabitable); + + if (rl) { + region_list *rl2 = rl; + while(rl2) { + region * r = rl2->data; + int nx = r->x, ny = r->y; + plane * plx = rplane(r); + + pnormalize(&nx, &ny, plx); + adjust_coordinates(f, &nx, &ny, plx, r); + fprintf(F, "SCHEMEN %d %d\n", nx, ny); + fprintf(F, "\"%s\";Name\n", rname(r, f->locale)); + rl2 = rl2->next; + } + free_regionlist(rl); + } + } + + /* describe both passed and inhabited regions */ + show_active_spells(r); + if (fval(r, RF_TRAVELUNIT)) { + boolean seeunits = false, seeships = false; + const attrib * ru; + /* show units pulled through region */ + for (ru = a_find(r->attribs, &at_travelunit); ru && ru->type==&at_travelunit; ru = ru->next) { + unit * u = (unit*)ru->data.v; + if (cansee_durchgezogen(f, r, u, 0) && r!=u->region) { + if (!u->ship || !fval(u, UFL_OWNER)) continue; + if (!seeships) fprintf(F, "DURCHSCHIFFUNG\n"); + seeships = true; + fprintf(F, "\"%s\"\n", shipname(u->ship)); + } + } + for (ru = a_find(r->attribs, &at_travelunit); ru && ru->type==&at_travelunit; ru = ru->next) { + unit * u = (unit*)ru->data.v; + if (cansee_durchgezogen(f, r, u, 0) && r!=u->region) { + if (u->ship) continue; + if (!seeunits) fprintf(F, "DURCHREISE\n"); + seeunits = true; + fprintf(F, "\"%s\"\n", unitname(u)); + } + } + } + cr_output_messages(F, r->msgs, f); + { + message_list * mlist = r_getmessages(r, f); + if (mlist) cr_output_messages(F, mlist, f); + } + /* buildings */ + for (b = rbuildings(r); b; b = b->next) { + int fno = -1; + u = building_owner(b); + if (u && !fval(u, UFL_ANON_FACTION)) { + const faction * sf = visible_faction(f,u); + fno = sf->no; + } + cr_output_building(F, b, u, fno, f); + } + + /* ships */ + for (sh = r->ships; sh; sh = sh->next) { + int fno = -1; + u = shipowner(sh); + if (u && !fval(u, UFL_ANON_FACTION)) { + const faction * sf = visible_faction(f,u); + fno = sf->no; + } + + cr_output_ship(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))) { + cr_output_unit(F, r, f, u, sr->mode); + } + } + } +} + +/* main function of the creport. creates the header and traverses all regions */ +static int +report_computer(const char * filename, report_context * ctx, const char * charset) +{ + static int era = -1; + int i; + faction * f = ctx->f; + const char * prefix; + region * r; + const char * mailto = locale_string(f->locale, "mailto"); + const attrib * a; + seen_region * sr = NULL; +#if SCORE_MODULE + int score = 0, avgscore = 0; +#endif + int enc = xmlParseCharEncoding(charset); + FILE * F = fopen(filename, "wt"); + + if (era<0) { + era = get_param_int(global.parameters, "world.era", 2); + } + if (F==NULL) { + perror(filename); + return -1; + } else if (enc==XML_CHAR_ENCODING_UTF8) { + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + fwrite(utf8_bom, 1, 3, F); + } + + /* must call this to get all the neighbour regions */ + /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ + /* initialisations, header and lists */ + + fprintf(F, "VERSION %d\n", C_REPORT_VERSION); + fprintf(F, "\"%s\";charset\n", charset); + fprintf(F, "\"%s\";locale\n", locale_name(f->locale)); + fprintf(F, "%d;noskillpoints\n", 1); + fprintf(F, "%ld;date\n", ctx->report_time); + fprintf(F, "\"%s\";Spiel\n", global.gamename); + fprintf(F, "\"%s\";Konfiguration\n", "Standard"); + fprintf(F, "\"%s\";Koordinaten\n", "Hex"); + fprintf(F, "%d;Basis\n", 36); + fprintf(F, "%d;Runde\n", turn); + fprintf(F, "%d;Zeitalter\n", era); + if (mailto!=NULL) { + fprintf(F, "\"%s\";mailto\n", mailto); + fprintf(F, "\"%s\";mailcmd\n", locale_string(f->locale, "mailcmd")); + } + + show_alliances_cr(F, f); + + fprintf(F, "PARTEI %d\n", f->no); + fprintf(F, "\"%s\";locale\n", locale_name(f->locale)); + if (f_get_alliance(f)) { + fprintf(F, "%d;alliance\n", f->alliance->id); + fprintf(F, "%d;joined\n", f->alliance_joindate); + } + fprintf(F, "%d;age\n", f->age); + fprintf(F, "%d;Optionen\n", f->options); +#if SCORE_MODULE + if (f->options & want(O_SCORE) && f->age>DISPLAYSCORE) { + score = f->score; + avgscore = average_score_of_age(f->age, f->age / 24 + 1); + } + fprintf(F, "%d;Punkte\n", score); + fprintf(F, "%d;Punktedurchschnitt\n", avgscore); +#endif + { + const char * zRace = rc_name(f->race, 1); + fprintf(F, "\"%s\";Typ\n", add_translation(zRace, LOC(f->locale, zRace))); + } + prefix = get_prefix(f->attribs); + if (prefix!=NULL) { + prefix = mkname("prefix", prefix); + fprintf(F, "\"%s\";typprefix\n", + add_translation(prefix, LOC(f->locale, prefix))); + } + fprintf(F, "%d;Rekrutierungskosten\n", f->race->recruitcost); + fprintf(F, "%d;Anzahl Personen\n", count_all(f)); + fprintf(F, "\"%s\";Magiegebiet\n", magic_school[f->magiegebiet]); + + if (f->race == new_race[RC_HUMAN]) { + fprintf(F, "%d;Anzahl Immigranten\n", count_migrants(f)); + fprintf(F, "%d;Max. Immigranten\n", count_maxmigrants(f)); + } + + i = countheroes(f); + if (i>0) fprintf(F, "%d;heroes\n", i); + i = maxheroes(f); + if (i>0) fprintf(F, "%d;max_heroes\n", i); + + if (f->age > 1 && f->lastorders != turn) { + fprintf(F, "%d;nmr\n", turn-f->lastorders); + } + + fprintf(F, "\"%s\";Parteiname\n", f->name); + fprintf(F, "\"%s\";email\n", f->email); + if (f->banner) fprintf(F, "\"%s\";banner\n", f->banner); + print_items(F, f->items, f->locale); + fputs("OPTIONEN\n", F); + for (i=0;i!=MAXOPTIONS;++i) { + int flag = want(i); + if (options[i]) { + fprintf(F, "%d;%s\n", (f->options&flag)?1:0, options[i]); + } else if (f->options&flag) { + f->options &= (~flag); + } + } + show_allies_cr(F, f, f->allies); + { + group * g; + for (g=f->groups;g;g=g->next) { + + fprintf(F, "GRUPPE %d\n", g->gid); + fprintf(F, "\"%s\";name\n", g->name); + prefix = get_prefix(g->attribs); + if (prefix!=NULL) { + prefix = mkname("prefix", prefix); + fprintf(F, "\"%s\";typprefix\n", + add_translation(prefix, LOC(f->locale, prefix))); + } + show_allies_cr(F, f, g->allies); + } + } + + cr_output_messages(F, f->msgs, f); + { + struct bmsg * bm; + for (bm=f->battles;bm;bm=bm->next) { + plane * pl = rplane(bm->r); + int plid = plane_id(pl); + region * r = bm->r; + int nx = r->x, ny = r->y; + + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl, r); + if (!plid) fprintf(F, "BATTLE %d %d\n", nx, ny); + else { + fprintf(F, "BATTLE %d %d %d\n", nx, ny, plid); + } + cr_output_messages(F, bm->msgs, f); + } + } + + cr_find_address(F, f, ctx->addresses); + a = a_find(f->attribs, &at_reportspell); + while (a && a->type==&at_reportspell) { + spell *sp = (spell *)a->data.v; + cr_reportspell(F, sp, f->locale); + a = a->next; + } + for (a=a_find(f->attribs, &at_showitem);a && a->type==&at_showitem;a=a->next) { + const potion_type * ptype = resource2potion(((const item_type*)a->data.v)->rtype); + const char * ch; + const char * description = NULL; + + if (ptype==NULL) continue; + ch = resourcename(ptype->itype->rtype, 0); + fprintf(F, "TRANK %d\n", hashstring(ch)); + fprintf(F, "\"%s\";Name\n", add_translation(ch, locale_string(f->locale, ch))); + fprintf(F, "%d;Stufe\n", ptype->level); + + if (description==NULL) { + const char * pname = resourcename(ptype->itype->rtype, 0); + const char * potiontext = mkname("potion", pname); + description = LOC(f->locale, potiontext); + } + + fprintf(F, "\"%s\";Beschr\n", description); + if (ptype->itype->construction) { + requirement * m = ptype->itype->construction->materials; + + fprintf(F, "ZUTATEN\n"); + + while (m->number) { + ch = resourcename(m->rtype, 0); + fprintf(F, "\"%s\"\n", add_translation(ch, locale_string(f->locale, ch))); + m++; + } + } + } + + /* traverse all regions */ + for (r=ctx->first;sr==NULL && r!=ctx->last;r=r->next) { + sr = find_seen(ctx->seen, r); + } + for (;sr!=NULL;sr=sr->next) { + cr_output_region(F, ctx, sr); + } + report_crtypes(F, f->locale); + write_translations(F); + reset_translations(); + fclose(F); + return 0; +} + +int +crwritemap(const char * filename) +{ + FILE * F = fopen(filename, "w"); + region * r; + + fprintf(F, "VERSION %d\n", C_REPORT_VERSION); + fputs("\"UTF-8\";charset\n", F); + + for (r=regions;r;r=r->next) { + plane * pl = rplane(r); + int plid = plane_id(pl); + if (plid) { + fprintf(F, "REGION %d %d %d\n", r->x, r->y, plid); + } else { + fprintf(F, "REGION %d %d\n", r->x, r->y); + } + fprintf(F, "\"%s\";Name\n\"%s\";Terrain\n", rname(r, default_locale), LOC(default_locale, terrain_name(r))); + } + fclose(F); + return 0; +} + +void +register_cr(void) +{ + tsf_register("report", &cr_ignore); + tsf_register("string", &cr_string); + tsf_register("order", &cr_order); + tsf_register("spell", &cr_spell); + tsf_register("curse", &cr_curse); + tsf_register("int", &cr_int); + tsf_register("unit", &cr_unit); + tsf_register("region", &cr_region); + tsf_register("faction", &cr_faction); + tsf_register("ship", &cr_ship); + tsf_register("building", &cr_building); + tsf_register("skill", &cr_skill); + tsf_register("resource", &cr_resource); + tsf_register("race", &cr_race); + tsf_register("direction", &cr_int); + tsf_register("alliance", &cr_alliance); + tsf_register("resources", &cr_resources); + tsf_register("items", &cr_resources); + tsf_register("regions", &cr_regions); + + if (!nocr) register_reporttype("cr", &report_computer, 1<next; + free(t); + } + junkyard = 0; +} + + diff --git a/src/gamecode/creport.h b/src/gamecode/creport.h index cfe84d8aa..473f1f0bc 100644 --- a/src/gamecode/creport.h +++ b/src/gamecode/creport.h @@ -1,29 +1,29 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ -#ifndef H_GC_CREPORT -#define H_GC_CREPORT -#ifdef __cplusplus -extern "C" { -#endif - -#include - -extern void creport_cleanup(void); -extern void register_cr(void); - -extern int crwritemap(const char * filename); - -#ifdef __cplusplus -} -#endif -#endif - +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#ifndef H_GC_CREPORT +#define H_GC_CREPORT +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern void creport_cleanup(void); +extern void register_cr(void); + +extern int crwritemap(const char * filename); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index 5a06f2a0b..53000af93 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -1,3463 +1,3463 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#pragma region includes - -#include -#include -#include "economy.h" - -/* gamecode includes */ -#include "archetype.h" -#include "give.h" -#include "laws.h" -#include "randenc.h" -#include "spy.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -/* libs includes */ -#include -#include -#include -#include -#include - -#pragma endregion - -typedef struct request { - struct request * next; - struct unit * unit; - struct order * ord; - int qty; - int no; - union { - boolean goblin; /* stealing */ - const struct luxury_type * ltype; /* trading */ - } type; -} request; - -static int working; - -static request entertainers[1024]; -static request *nextentertainer; -static int entertaining; - -static int norders; -static request *oa; - -#define RECRUIT_MERGE 1 -#define RECRUIT_CLASSIC 2 -#define RECRUIT_ARCHETYPES 4 -static int rules_recruit = -1; - -static void recruit_init(void) -{ - if (rules_recruit<0) { - rules_recruit = 0; - if (get_param_int(global.parameters, "recruit.allow_merge", 1)) { - rules_recruit |= RECRUIT_MERGE; - } - if (get_param_int(global.parameters, "recruit.classic", 1)) { - rules_recruit |= RECRUIT_CLASSIC; - } - if (get_param_int(global.parameters, "recruit.archetype", 0)) { - rules_recruit |= RECRUIT_ARCHETYPES; - } - } -} - -int -income(const unit * u) -{ - switch(old_race(u->race)) { - case RC_FIREDRAGON: - return 150 * u->number; - case RC_DRAGON: - return 1000 * u->number; - case RC_WYRM: - return 5000 * u->number; - } - return 20 * u->number; -} - -static void -scramble(void *data, int n, size_t width) -{ - int j; - char temp[64]; - assert(width<=sizeof(temp)); - for (j=0;j!=n;++j) { - int k = rng_int() % n; - if (k==j) continue; - memcpy(temp, (char*)data+j*width, width); - memcpy((char*)data+j*width, (char*)data+k*width, width); - memcpy((char*)data+k*width, temp, width); - } -} - -static void -expandorders(region * r, request * requests) -{ - unit *u; - request *o; - - /* Alle Units ohne request haben ein -1, alle units mit orders haben ein - * 0 hier stehen */ - - for (u = r->units; u; u = u->next) - u->n = -1; - - norders = 0; - - for (o = requests; o; o = o->next) { - if (o->qty > 0) { - norders += o->qty; - } - } - - if (norders > 0) { - int i = 0; - oa = (request *) calloc(norders, sizeof(request)); - for (o = requests; o; o = o->next) { - if (o->qty > 0) { - int j; - for (j = o->qty; j; j--) { - oa[i] = *o; - oa[i].unit->n = 0; - i++; - } - } - } - scramble(oa, norders, sizeof(request)); - } else { - oa = NULL; - } - while (requests) { - request * o = requests->next; - free_order(requests->ord); - free(requests); - requests = o; - } -} -/* ------------------------------------------------------------- */ - -static void -change_level(unit * u, skill_t sk, int bylevel) -{ - skill * sv = get_skill(u, sk); - assert(bylevel>0); - if (sv==0) sv = add_skill(u, sk); - sk_set(sv, sv->level+bylevel); -} - -typedef struct recruitment { - struct recruitment * next; - faction * f; - request * requests; - int total, assigned; -} recruitment; - -static recruitment * -select_recruitment(request ** rop, int (*quantify)(const struct race*, int), int * total) -{ - recruitment * recruits = NULL; - - while (*rop) { - recruitment * rec = recruits; - request * ro = *rop; - unit * u = ro->unit; - const race * rc = u->race; - int qty = quantify(rc, ro->qty); - - if (qty<0) { - rop = &ro->next; /* skip this one */ - } else { - *rop = ro->next; /* remove this one */ - while (rec && rec->f!=u->faction) rec = rec->next; - if (rec==NULL) { - rec = malloc(sizeof(recruitment)); - rec->f = u->faction; - rec->total = 0; - rec->assigned = 0; - rec->requests = NULL; - rec->next = recruits; - recruits = rec; - } - *total += qty; - rec->total += qty; - ro->next = rec->requests; - rec->requests = ro; - } - } - return recruits; -} - -static void -add_recruits(unit * u, int number, int wanted) -{ - region * r = u->region; - assert(number<=wanted); - if (number > 0) { - unit * unew; - char equipment[64]; - - if (u->number==0) { - set_number(u, number); - u->hp = number * unit_max_hp(u); - unew = u; - } else { - unew = create_unit(r, u->faction, number, u->race, 0, NULL, u); - } - - snprintf(equipment, sizeof(equipment), "new_%s_unit", u->race->_name[0]); - equip_unit(unew, get_equipment(equipment)); - - - if (unew->race->ec_flags & ECF_REC_HORSES) { - change_level(unew, SK_RIDING, 1); - } - - if (unew!=u) { - transfermen(unew, u, unew->number); - remove_unit(&r->units, unew); - } - } - if (number < wanted) { - ADDMSG(&u->faction->msgs, msg_message("recruit", - "unit region amount want", u, r, number, wanted)); - } -} - -static int -any_recruiters(const struct race * rc, int qty) -{ - return (int)(qty * 2 * rc->recruit_multi); -} - -static int -peasant_recruiters(const struct race * rc, int qty) -{ - if (rc->ec_flags & ECF_REC_ETHEREAL) return -1; - if (rc->ec_flags & ECF_REC_HORSES) return -1; - return (int)(qty * 2 * rc->recruit_multi); -} - -static int -horse_recruiters(const struct race * rc, int qty) -{ - if (rc->ec_flags & ECF_REC_ETHEREAL) return -1; - if (rc->ec_flags & ECF_REC_HORSES) return (int)(qty * 2 * rc->recruit_multi); - return -1; -} - -static int -do_recruiting(recruitment * recruits, int available) -{ - recruitment * rec; - int recruited = 0; - - while (available>0) { - int n = 0; - int rest, mintotal = INT_MAX; - - for (rec=recruits;rec!=NULL;rec=rec->next) { - int want = rec->total - rec->assigned; - if (want>0) { - if (mintotal>want) mintotal = want; - ++n; - } - } - if (n==0) break; - if (mintotal*n>available) { - mintotal = available/n; - } - rest = available - mintotal*n; - - for (rec=recruits;rec!=NULL;rec=rec->next) { - int want = rec->total - rec->assigned; - - if (want>0) { - int get = mintotal; - if (want>mintotal && restassigned += get; - } - } - } - - for (rec=recruits;rec!=NULL;rec=rec->next) { - request * req; - int get = rec->assigned; - - for (req=rec->requests;req;req=req->next) { - unit * u = req->unit; - const race * rc = u->race; /* race is set in recruit() */ - int number, dec; - float multi = 2.0F * rc->recruit_multi; - - number = MIN(req->qty, (int)(get / multi)); - if (rc->recruitcost) { - int afford = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, number*rc->recruitcost) / rc->recruitcost; - number = MIN(number, afford); - use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, rc->recruitcost*number); - } - if (u->number+number>UNIT_MAXSIZE) { - ADDMSG(&u->faction->msgs, msg_feedback(u, req->ord, "error_unit_size", "maxsize", UNIT_MAXSIZE)); - number = UNIT_MAXSIZE-u->number; - assert(number>=0); - } - add_recruits(u, number, req->qty); - dec = (int)(number * multi); - if ((rc->ec_flags & ECF_REC_ETHEREAL)==0) { - recruited += dec; - } - - get -= dec; - } - } - return recruited; -} - -static void -feedback_give_not_allowed(unit * u, order * ord) -{ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_give_forbidden", "")); -} - -static boolean check_give(unit * u, unit * u2, const item_type * itype, int mask) -{ - if (u2) { - if (u->faction!=u2->faction) { - int rule = rule_give(); - if (itype) { - assert(mask==0); - if (itype->rtype->ltype) mask |= GIVE_LUXURIES; - else if (fval(itype, ITF_HERB)) mask |= GIVE_HERBS; - else mask |= GIVE_GOODS; - } - return (rule&mask)!=0; - } - } else { - int rule = rule_give(); - return (rule & GIVE_PEASANTS)!=0; - } - return true; -} - -void -free_recruitments(recruitment * recruits) -{ - while (recruits) { - recruitment * rec = recruits; - recruits = rec->next; - while (rec->requests) { - request * req = rec->requests; - rec->requests = req->next; - free(req); - } - free(rec); - } -} - -/* Rekrutierung */ -static void -expandrecruit(region * r, request * recruitorders) -{ - recruitment * recruits = NULL; - - int orc_total = 0; - - /* centaurs: */ - recruits = select_recruitment(&recruitorders, horse_recruiters, &orc_total); - if (recruits) { - int recruited, horses = rhorses(r) * 2; - if (orc_total0) { - rsetpeasants(r, peasants - recruited/2); - } - free_recruitments(recruits); - } - - assert(recruitorders==NULL); -} - -static int -recruit_cost(const faction * f, const race * rc) -{ - if (is_monsters(f) || f->race==rc) { - return rc->recruitcost; - } else if (valid_race(f, rc)) { - return rc->recruitcost; -/* return get_param_int(f->race->parameters, "other_cost", -1); */ - } - return -1; -} - -static void -recruit(unit * u, struct order * ord, request ** recruitorders) -{ - int n; - region * r = u->region; - plane * pl; - request *o; - int recruitcost = -1; - const faction * f = u->faction; - const struct race * rc = u->race; - const char * str; - - init_tokens(ord); - skip_token(); - n = getuint(); - - if (u->number==0) { - str = getstrtoken(); - if (str && str[0]) { - /* Monster dürfen REKRUTIERE 15 dracoid machen - * also: secondary race */ - rc = findrace(str, f->locale); - if (rc!=NULL) { - recruitcost = recruit_cost(f, rc); - } - } - } - if (recruitcost<0) { - rc = u->race; - recruitcost = recruit_cost(f, rc); - } - u->race = rc; - assert(rc && recruitcost>=0); - -#if GUARD_DISABLES_RECRUIT - /* this is a very special case because the recruiting unit may be empty - * at this point and we have to look at the creating unit instead. This - * is done in cansee, which is called indirectly by is_guarded(). */ - if (is_guarded(r, u, GUARD_RECRUIT)) { - cmistake(u, ord, 70, MSG_EVENT); - return; - } -#endif - - if (rc == new_race[RC_INSECT]) { - gamedate date; - get_gamedate(turn, &date); - if (date.season == 0 && r->terrain != newterrain(T_DESERT)) { -#ifdef INSECT_POTION - boolean usepotion = false; - unit *u2; - - for (u2 = r->units; u2; u2 = u2->next) - if (fval(u2, UFL_WARMTH)) { - usepotion = true; - break; - } - if (!usepotion) -#endif - { - cmistake(u, ord, 98, MSG_EVENT); - return; - } - } - /* in Gletschern, Eisbergen gar nicht rekrutieren */ - if (r_insectstalled(r)) { - cmistake(u, ord, 97, MSG_EVENT); - return; - } - } - if (is_cursed(r->attribs, C_RIOT, 0)) { - /* Die Region befindet sich in Aufruhr */ - cmistake(u, ord, 237, MSG_EVENT); - return; - } - - if (!(rc->ec_flags & ECF_REC_HORSES) && fval(r, RF_ORCIFIED)) { - if (rc != new_race[RC_ORC]) - { - cmistake(u, ord, 238, MSG_EVENT); - return; - } - } - - if (recruitcost) { - pl = getplane(r); - if (pl && fval(pl, PFL_NORECRUITS)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "error_pflnorecruit", "")); - return; - } - - if (get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, recruitcost) < recruitcost) { - cmistake(u, ord, 142, MSG_EVENT); - return; - } - } - if (!playerrace(rc) || idle(u->faction)) { - cmistake(u, ord, 139, MSG_EVENT); - return; - } - - if (has_skill(u, SK_MAGIC)) { - /* error158;de;{unit} in {region}: '{command}' - Magier arbeiten - * grundsätzlich nur alleine! */ - cmistake(u, ord, 158, MSG_EVENT); - return; - } - if (has_skill(u, SK_ALCHEMY) - && count_skill(u->faction, SK_ALCHEMY) + n > - skill_limit(u->faction, SK_ALCHEMY)) - { - cmistake(u, ord, 156, MSG_EVENT); - return; - } - if (recruitcost>0) { - int pooled = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, recruitcost * n); - n = MIN(n, pooled / recruitcost); - } - - u->wants = n; - - if (!n) { - cmistake(u, ord, 142, MSG_EVENT); - return; - } - - o = (request *) calloc(1, sizeof(request)); - o->qty = n; - o->unit = u; - o->ord = copy_order(ord); - addlist(recruitorders, o); -} - -static void -friendly_takeover(region * r, faction * f) -{ - int morale = region_get_morale(r); - region_set_owner(r, f, turn); - if (morale>0) { - morale = MAX(0, morale-MORALE_TRANSFER); - region_set_morale(r, morale, turn); - } -} - -static void -give_control(unit * u, unit * u2) -{ - if (u->building && u->faction!=u2->faction && rule_region_owners()) { - region * r = u->region; - faction * f = region_get_owner(r); - if (f==u->faction) { - building * b = largestbuilding(r, &cmp_current_owner, false); - if (b==u->building) { - friendly_takeover(r, u2->faction); - } - } - } - freset(u, UFL_OWNER); - fset(u2, UFL_OWNER); -} - -int -give_control_cmd(unit * u, order * ord) -{ - region * r = u->region; - unit *u2; - const char * s; - param_t p; - - init_tokens(ord); - skip_token(); - u2 = getunit(r, u->faction); - s = getstrtoken(); - p = findparam(s, u->faction->locale); - - /* first, do all the ones that do not require HELP_GIVE or CONTACT */ - if (p == P_CONTROL) { - message * msg; - - if (!u2) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } - else if (!u->building && !u->ship) { - cmistake(u, ord, 140, MSG_EVENT); - } - else if (u->building && u2->building != u->building) { - cmistake(u, ord, 33, MSG_EVENT); - } - else if (u->ship && u2->ship != u->ship) { - cmistake(u, ord, 32, MSG_EVENT); - } - else if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 49, MSG_EVENT); - } - else { - give_control(u, u2); - - msg = msg_message("givecommand", "unit recipient", u, u2); - add_message(&u->faction->msgs, msg); - if (u->faction != u2->faction) { - add_message(&u2->faction->msgs, msg); - } - msg_release(msg); - } - } - return 0; -} - -static void -give_cmd(unit * u, order * ord) -{ - region * r = u->region; - unit *u2; - const char *s; - int i, n; - const item_type * itype; - param_t p; - plane * pl; - - init_tokens(ord); - skip_token(); - u2 = getunit(r, u->faction); - s = getstrtoken(); - p = findparam(s, u->faction->locale); - - /* first, do all the ones that do not require HELP_GIVE or CONTACT */ - if (p == P_CONTROL) { - /* handled in give_control_cmd */ - return; - } - - if (!u2 && !getunitpeasants) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return; - } - - if (!check_give(u, u2, NULL, GIVE_ALLITEMS)) { - feedback_give_not_allowed(u, ord); - return; - } - - /* Damit Tarner nicht durch die Fehlermeldung enttarnt werden können */ - if (u2 && !alliedunit(u2, u->faction, HELP_GIVE) && !cansee(u->faction,r,u2,0) && !ucontact(u2, u) && !fval(u2, UFL_TAKEALL)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return; - } - if (u == u2) { - cmistake(u, ord, 8, MSG_COMMERCE); - return; - } - - /* UFL_TAKEALL ist ein grober Hack. Generalisierung tut not, ist aber nicht - * wirklich einfach. */ - pl = rplane(r); - if (pl && fval(pl, PFL_NOGIVE) && (!u2 || !fval(u2, UFL_TAKEALL))) { - cmistake(u, ord, 268, MSG_COMMERCE); - return; - } - - if (u2 && u2->race == new_race[RC_SPELL]) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return; - } - - else if (u2 && !alliedunit(u2, u->faction, HELP_GIVE) && !ucontact(u2, u)) { - cmistake(u, ord, 40, MSG_COMMERCE); - return; - } - - else if (p == P_HERBS) { - boolean given = false; - if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_nogive", "race", u->race)); - return; - } - if (!check_give(u, u2, NULL, GIVE_HERBS)) { - feedback_give_not_allowed(u, ord); - return; - } - if (u2 && !(u2->race->ec_flags & GETITEM)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_notake", "race", u2->race)); - return; - } - if (!u2) { - if (!getunitpeasants) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return; - } - } - if (u->items) { - item **itmp=&u->items; - while (*itmp) { - item * itm = *itmp; - const item_type * itype = itm->type; - if (fval(itype, ITF_HERB) && itm->number>0) { - /* give_item ändert im fall,das man alles übergibt, die - * item-liste der unit, darum continue vor pointerumsetzten */ - if (give_item(itm->number, itm->type, u, u2, ord)==0) { - given = true; - if (*itmp!=itm) continue; - continue; - } - } - itmp = &itm->next; - } - } - if (!given) cmistake(u, ord, 38, MSG_COMMERCE); - return; - } - - else if (p == P_ZAUBER) { - cmistake(u, ord, 7, MSG_COMMERCE); - /* geht nimmer */ - return; - } - - else if (p == P_UNIT) { /* Einheiten uebergeben */ - if (!(u->race->ec_flags & GIVEUNIT)) { - cmistake(u, ord, 167, MSG_COMMERCE); - return; - } - - give_unit(u, u2, ord); - return; - } - - else if (p==P_ANY) { - const char * s = getstrtoken(); - - if (!check_give(u, u2, NULL, GIVE_ALLITEMS)) { - feedback_give_not_allowed(u, ord); - return; - } - if (*s == 0) { /* Alle Gegenstände übergeben */ - - /* do these checks once, not for each item we have: */ - if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_nogive", "race", u->race)); - return; - } - if (u2 && !(u2->race->ec_flags & GETITEM)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_notake", "race", u2->race)); - return; - } - - /* für alle items einmal prüfen, ob wir mehr als von diesem Typ - * reserviert ist besitzen und diesen Teil dann übergeben */ - if (u->items) { - item **itmp=&u->items; - while (*itmp) { - item * itm = *itmp; - const item_type * itype = itm->type; - if (itm->number > 0 && itm->number - get_reservation(u, itype->rtype) > 0) { - n = itm->number - get_reservation(u, itype->rtype); - if (give_item(n, itype, u, u2, ord)==0) { - if (*itmp!=itm) continue; - } - } - itmp = &itm->next; - } - } - return; - } - else { - param_t p2 = findparam(s, u->faction->locale); - - if (p2 == P_PERSON) { - if (!(u->race->ec_flags & GIVEPERSON)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_noregroup", "race", u->race)); - return; - } - n = u->number; - give_men(n, u, u2, ord); - return; - } - - if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_nogive", "race", u->race)); - return; - } - if (u2 && !(u2->race->ec_flags & GETITEM)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_notake", "race", u2->race)); - return; - } - - itype = finditemtype(s, u->faction->locale); - if (itype!=NULL) { - item * i = *i_find(&u->items, itype); - if (i!=NULL) { - if (check_give(u, u2, itype, 0)) { - n = i->number - get_reservation(u, itype->rtype); - give_item(n, itype, u, u2, ord); - } else { - feedback_give_not_allowed(u, ord); - } - return; - } - } - } - } else if (p==P_EACH) { - if (u2==NULL) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "peasants_give_invalid", "")); - return; - } - s = getstrtoken(); /* skip one ahead to get the amount. */ - } - - n = atoip((const char *)s); /* n: Anzahl */ - if (p==P_EACH) { - n *= u2->number; - } - s = getstrtoken(); - - if (s == NULL) { - cmistake(u, ord, 113, MSG_COMMERCE); - return; - } - - i = findparam(s, u->faction->locale); - if (i == P_PERSON) { - if (!(u->race->ec_flags & GIVEPERSON)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_noregroup", "race", u->race)); - return; - } - give_men(n, u, u2, ord); - return; - } - - if (u2!=NULL) { - if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_nogive", "race", u->race)); - return; - } - if (!(u2->race->ec_flags & GETITEM)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_notake", "race", u2->race)); - return; - } - } - - itype = finditemtype(s, u->faction->locale); - if (itype!=NULL) { - if (check_give(u, u2, itype, 0)) { - give_item(n, itype, u, u2, ord); - } else { - feedback_give_not_allowed(u, ord); - } - return; - } - cmistake(u, ord, 123, MSG_COMMERCE); -} - -static int -forget_cmd(unit * u, order * ord) -{ - skill_t sk; - const char *s; - - if (is_cursed(u->attribs, C_SLAVE, 0)) { - /* charmed units shouldn't be losing their skills */ - return 0; - } - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - if ((sk = findskill(s, u->faction->locale)) != NOSKILL) { - ADDMSG(&u->faction->msgs, - msg_message("forget", "unit skill", u, sk)); - set_level(u, sk, 0); - } - return 0; -} - -void -add_spende(faction * f1, faction * f2, int amount, region * r) -{ - donation *sp; - - sp = r->donations; - - while (sp) { - if (sp->f1 == f1 && sp->f2 == f2) { - sp->amount += amount; - return; - } - sp = sp->next; - } - - sp = calloc(1, sizeof(donation)); - sp->f1 = f1; - sp->f2 = f2; - sp->amount = amount; - sp->next = r->donations; - r->donations = sp; -} - -static boolean -maintain(building * b, boolean first) -/* first==false -> take money from wherever you can */ -{ - int c; - region * r = b->region; - boolean paid = true, work = first; - unit * u; - if (fval(b, BLD_MAINTAINED) || b->type==NULL || b->type->maintenance==NULL || is_cursed(b->attribs, C_NOCOST, 0)) { - fset(b, BLD_MAINTAINED); - fset(b, BLD_WORKING); - return true; - } - if (fval(b, BLD_DONTPAY)) { - return false; - } - u = building_owner(b); - if (u==NULL) return false; - for (c=0;b->type->maintenance[c].number;++c) { - const maintenance * m = b->type->maintenance+c; - int need = m->number; - - if (fval(m, MTF_VARIABLE)) need = need * b->size; - if (u) { - /* first ist im ersten versuch true, im zweiten aber false! Das - * bedeutet, das in der Runde in die Region geschafften Resourcen - * nicht genutzt werden können, weil die reserviert sind! */ - if (!first) need -= get_pooled(u, m->rtype, GET_ALL, need); - else need -= get_pooled(u, m->rtype, GET_DEFAULT, need); - if (!first && need > 0) { - unit * ua; - for (ua=r->units;ua;ua=ua->next) freset(ua->faction, FFL_SELECT); - fset(u->faction, FFL_SELECT); /* hat schon */ - for (ua=r->units;ua;ua=ua->next) { - if (!fval(ua->faction, FFL_SELECT) && (ua->faction == u->faction || alliedunit(ua, u->faction, HELP_MONEY))) { - need -= get_pooled(ua, m->rtype, GET_ALL, need); - fset(ua->faction, FFL_SELECT); - if (need<=0) break; - } - } - } - if (need > 0) { - if (!fval(m, MTF_VITAL)) work = false; - else { - paid = false; - break; - } - } - } - } - if (paid && c>0) { - /* TODO: wieviel von was wurde bezahlt */ - if (first) { - ADDMSG(&u->faction->msgs, msg_message("maintenance", "unit building", u, b)); - } else { - ADDMSG(&u->faction->msgs, msg_message("maintenance_late", "building", b)); - } - fset(b, BLD_MAINTAINED); - if (work) { - fset(b, BLD_WORKING); - } - for (c=0;b->type->maintenance[c].number;++c) { - const maintenance * m = b->type->maintenance+c; - int cost = m->number; - - if (!fval(m, MTF_VITAL) && !work) continue; - if (fval(m, MTF_VARIABLE)) cost = cost * b->size; - - if (!first) cost -= use_pooled(u, m->rtype, GET_ALL, cost); - else cost -= use_pooled(u, m->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, cost); - if (!first && cost > 0) { - unit * ua; - for (ua=r->units;ua;ua=ua->next) freset(ua->faction, FFL_SELECT); - fset(u->faction, FFL_SELECT); /* hat schon */ - for (ua=r->units;ua;ua=ua->next) { - if (!fval(ua->faction, FFL_SELECT) && alliedunit(ua, u->faction, HELP_MONEY)) { - int give = use_pooled(ua, m->rtype, GET_ALL, cost); - if (!give) continue; - cost -= give; - fset(ua->faction, FFL_SELECT); - if (m->rtype==r_silver) add_spende(ua->faction, u->faction, give, r); - if (cost<=0) break; - } - } - } - assert(cost==0); - } - } else { - ADDMSG(&u->faction->msgs, - msg_message("maintenancefail", "unit building", u, b)); - return false; - } - return true; -} - -#ifdef COLLAPSE_CHANCE -static void -gebaeude_stuerzt_ein(region * r, building * b) -{ - unit *u; - int n, i; - int opfer = 0; - int road = 0; - struct message * msg; - - for (u = r->units; u; u = u->next) { - if (u->building == b) { - int loss = 0; - - fset(u->faction, FFL_MARK); - freset(u, UFL_OWNER); - leave(r,u); - n = u->number; -#ifdef COLLAPSE_SURVIVAL - for (i = 0; i < n; i++) { - if (rng_double() >= COLLAPSE_SURVIVAL) { - ++loss; - } - } -#endif - scale_number(u, u->number - loss); - opfer += loss; - } - } - - msg = msg_message("buildingcrash", "region building opfer road", r, b, opfer, road); - add_message(&r->msgs, msg); - for (u=r->units; u; u=u->next) { - faction * f = u->faction; - if (fval(f, FFL_MARK)) { - freset(u->faction, FFL_MARK); - add_message(&f->msgs, msg); - } - } - msg_release(msg); - remove_building(&r->buildings, b); -} -#endif - -void -maintain_buildings(region * r, boolean crash) -{ - building **bp = &r->buildings; - while (*bp) { - building * b = *bp; - boolean maintained = maintain(b, !crash); - - /* the second time, send a message */ - if (crash) { -#ifdef COLLAPSE_CHANCE - if (!maintained && (rng_double() < COLLAPSE_CHANCE)) { - gebaeude_stuerzt_ein(r, b); - continue; - } -#endif - if (!fval(b, BLD_WORKING)) { - unit * u = building_owner(b); - const char * msgtype = maintained?"maintenance_nowork":"maintenance_none"; - struct message * msg = msg_message(msgtype, "building", b); - - if (u) { - add_message(&u->faction->msgs, msg); - r_addmessage(r, u->faction, msg); - } else { - add_message(&r->msgs, msg); - } - msg_release(msg); - } - } - bp=&b->next; - } -} - -static int -recruit_archetype(unit * u, order * ord) -{ - boolean merge = (u->number>0); - int want; - const char * s; - - if (rules_recruit<0) recruit_init(); - - init_tokens(ord); - skip_token(); - want = getuint(); - s = getstrtoken(); - if (want>0 && s && s[0]) { - int n = want; - const archetype * arch = find_archetype(s, u->faction->locale); - attrib * a = NULL; - - if ((rules_recruit&RECRUIT_MERGE)==0 && merge) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_must_be_new", "")); - /* TODO: error message */ - return 0; - } - - if (arch==NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unknown_archetype", "name", s)); - /* TODO: error message */ - return 0; - } - if (arch->rules) { - /* Simple allow/deny style restrictions for archetypes (let only humans - * recruit gamedesigners, etc). These need to be more powerful to be - * useful, and the current way they are implemented is not, but the - * general idea strikes me as good. Also, feedback should be configurable - * for each failed rule. - */ - int k; - for (k=0;arch->rules[k].property;++k) { - boolean match = false; - if (arch->rules[k].value[0]=='*') match = true; - else if (strcmp(arch->rules[k].property, "race")==0) { - const race * rc = rc_find(arch->rules[k].value); - assert(rc); - if (rc==u->race) match = true; - } else if (strcmp(arch->rules[k].property, "building")==0) { - const building_type * btype = bt_find(arch->rules[k].value); - assert(btype); - if (u->building && u->building->type==btype) match = true; - } - if (match) { - if (arch->rules[k].allow) break; - else { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "recruit_rule_fail", - "property value", arch->rules[k].property, arch->rules[k].value)); - /* TODO: error message */ - return 0; - } - } - } - } - if (arch->btype) { - if (u->building==NULL || u->building->type!=arch->btype) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_must_be_in_building", "type", arch->btype)); - /* TODO: error message */ - return 0; - } - if (arch->size) { - int maxsize = u->building->size; - attrib * a = a_find(u->building->attribs, &at_recruit); - if (a!=NULL) { - maxsize -= a->data.i; - } - n = MIN(maxsize/arch->size, n); - if (n<=0) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "recruit_capacity_exhausted", "building", u->building)); - /* TODO: error message */ - return 0; - } - } - } - - n = build(u, arch->ctype, 0, n); - if (n>0) { - unit * u2; - if (merge) { - u2 = create_unit(u->region, u->faction, 0, u->race, 0, 0, u); - } else { - u2 = u; - } - if (arch->exec) { - n = arch->exec(u2, arch, n); - } - else { - set_number(u2, n); - equip_unit(u2, arch->equip); - u2->hp = n * unit_max_hp(u2); - if (arch->size) { - if (a==NULL) a = a_add(&u->building->attribs, a_new(&at_recruit)); - a->data.i += n*arch->size; - } - } - ADDMSG(&u->faction->msgs, msg_message("recruit_archetype", - "unit amount archetype", u, n, arch->name[n==1])); - if (u!=u2 && u->race==u2->race) { - transfermen(u2, u, u2->number); - } - return n; - } else switch(n) { - case ENOMATERIALS: - ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, arch->ctype, want)); - break; - case ELOWSKILL: - case ENEEDSKILL: - /* no skill, or not enough skill points to build */ - cmistake(u, ord, 50, MSG_PRODUCE); - break; - case EBUILDINGREQ: - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "building_needed", "building", arch->ctype->btype->_name)); - break; - default: - assert(!"unhandled return value from build() in recruit_archetype"); - } - return 0; - } - return -1; -} - -int recruit_archetypes(void) -{ - if (rules_recruit<0) recruit_init(); - return (rules_recruit&RECRUIT_ARCHETYPES)!=0; -} - -void -economics(region *r) -{ - unit *u; - request *recruitorders = NULL; - - /* Geben vor Selbstmord (doquit)! Hier alle unmittelbaren Befehle. - * Rekrutieren vor allen Einnahmequellen. Bewachen JA vor Steuern - * eintreiben. */ - - for (u = r->units; u; u = u->next) { - order * ord; - boolean destroyed = false; - if (u->number>0) { - for (ord = u->orders; ord; ord = ord->next) { - switch (get_keyword(ord)) { - case K_DESTROY: - if (!destroyed) { - if (destroy_cmd(u, ord)!=0) ord = NULL; - destroyed = true; - } - break; - - case K_GIVE: - case K_LIEFERE: - give_cmd(u, ord); - break; - - case K_FORGET: - forget_cmd(u, ord); - break; - - } - if (u->orders==NULL) break; - } - } - } - /* RECRUIT orders */ - - if (rules_recruit<0) recruit_init(); - for (u = r->units; u; u = u->next) { - order * ord; - - if ((rules_recruit&RECRUIT_MERGE) || u->number==0) { - for (ord = u->orders; ord; ord = ord->next) { - if (get_keyword(ord) == K_RECRUIT) { - if (rules_recruit&RECRUIT_ARCHETYPES) { - if (recruit_archetype(u, ord)>=0) { - continue; - } - } - if (rules_recruit&RECRUIT_CLASSIC) { - recruit(u, ord, &recruitorders); - } - break; - } - } - } - } - - if (recruitorders) expandrecruit(r, recruitorders); - remove_empty_units_in_region(r); -} -/* ------------------------------------------------------------- */ - - -static void -manufacture(unit * u, const item_type * itype, int want) -{ - int n; - int skill; - int minskill = itype->construction->minskill; - skill_t sk = itype->construction->skill; - - skill = effskill(u, sk); - skill = skillmod(itype->rtype->attribs, u, u->region, sk, skill, SMF_PRODUCTION); - - if (skill < 0) { - /* an error occured */ - int err = -skill; - cmistake(u, u->thisorder, err, MSG_PRODUCE); - return; - } - - if (want==0) { - want = maxbuild(u, itype->construction); - } - n = build(u, itype->construction, 0, want); - switch (n) { - case ENEEDSKILL: - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "skill_needed", "skill", sk)); - return; - case EBUILDINGREQ: - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "building_needed", "building", itype->construction->btype->_name)); - return; - case ELOWSKILL: - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "manufacture_skills", "skill minskill product", - sk, minskill, itype->rtype, 1)); - return; - case ENOMATERIALS: - ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, itype->construction, want)); - return; - } - if (n>0) { - i_change(&u->items, itype, n); - if (want==INT_MAX) want = n; - ADDMSG(&u->faction->msgs, msg_message("manufacture", - "unit region amount wanted resource", u, u->region, n, want, itype->rtype)); - } else { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_cannotmake", "")); - } -} - -typedef struct allocation { - struct allocation * next; - int want, get; - double save; - unsigned int flags; - unit * unit; -} allocation; -#define new_allocation() calloc(sizeof(allocation), 1) -#define free_allocation(a) free(a) - -typedef struct allocation_list { - struct allocation_list * next; - allocation * data; - const resource_type * type; -} allocation_list; - -static allocation_list * allocations; - -static boolean -can_guard(const unit * guard, const unit * u) -{ - if (fval(guard, UFL_ISNEW)) return false; - if (guard->number<=0 || !cansee(guard->faction, guard->region, u, 0)) return false; - if (besieged(guard) || !(fval(guard->race, RCF_UNARMEDGUARD) || armedmen(guard, true))) return false; - - return !alliedunit(guard, u->faction, HELP_GUARD); -} - -enum { - AFL_DONE = 1<<0, - AFL_LOWSKILL = 1<<1 -}; - -static void -allocate_resource(unit * u, const resource_type * rtype, int want) -{ - const item_type * itype = resource2item(rtype); - region * r = u->region; - int busy = u->number; - int dm = 0; - allocation_list * alist; - allocation * al; - attrib * a = a_find(rtype->attribs, &at_resourcelimit); - resource_limit * rdata = (resource_limit*)a->data.v; - int amount, skill; - - /* momentan kann man keine ressourcen abbauen, wenn man dafür - * Materialverbrauch hat: */ - assert(itype!=NULL && (itype->construction==NULL || itype->construction->materials==NULL)); - assert(rdata!=NULL); - - if (rdata->limit!=NULL) { - int avail = rdata->limit(r, rtype); - if (avail<=0) { - cmistake(u, u->thisorder, 121, MSG_PRODUCE); - return; - } - } - - if (besieged(u)) { - cmistake(u, u->thisorder, 60, MSG_PRODUCE); - return; - } - - if (rdata->modifiers) { - resource_mod * mod = rdata->modifiers; - for (;mod->flags!=0;++mod) { - if (mod->flags & RMF_REQUIREDBUILDING) { - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - if (mod->btype && mod->btype!=btype) { - cmistake(u, u->thisorder, 104, MSG_PRODUCE); - return; - } - } - } - } - - if (rdata->guard!=0) { - unit * u2; - for (u2 = r->units; u2; u2 = u2->next) { - if (is_guard(u2, rdata->guard)!=0 && can_guard(u2, u)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "region_guarded", "guard", u2)); - return; - } - } - } - - /* Bergwächter können Abbau von Eisen/Laen durch Bewachen verhindern. - * Als magische Wesen 'sehen' Bergwächter alles und werden durch - * Belagerung nicht aufgehalten. (Ansonsten wie oben bei Elfen anpassen). - */ - if (itype == olditemtype[I_IRON] || itype == olditemtype[I_LAEN]) { - unit * u2; - for (u2 = r->units; u2; u2 = u2->next ) { - if (is_guard(u, GUARD_MINING) - && !fval(u2, UFL_ISNEW) - && u2->number - && !alliedunit(u2, u->faction, HELP_GUARD)) - { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "region_guarded", "guard", u2)); - return; - } - } - } - - assert(itype->construction->skill!=0 || "limited resource needs a required skill for making it"); - skill = eff_skill(u, itype->construction->skill, u->region); - if (skill == 0) { - skill_t sk = itype->construction->skill; - add_message(&u->faction->msgs, - msg_feedback(u, u->thisorder, "skill_needed", "skill", sk)); - return; - } - if (skill < itype->construction->minskill) { - skill_t sk = itype->construction->skill; - add_message(&u->faction->msgs, - msg_feedback(u, u->thisorder, "manufacture_skills", "skill minskill product", - sk, itype->construction->minskill, itype->rtype)); - return; - } else { - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - - if (rdata->modifiers) { - resource_mod * mod = rdata->modifiers; - for (;mod->flags!=0;++mod) { - if (mod->flags & RMF_SKILL) { - if (mod->btype==NULL || mod->btype==btype) { - if (mod->race==NULL || mod->race==u->race) { - skill += mod->value.i; - } - } - } - } - } - } - amount = skill * u->number; - /* nun ist amount die Gesamtproduktion der Einheit (in punkten) */ - - /* mit Flinkfingerring verzehnfacht sich die Produktion */ - amount += skill * MIN(u->number, get_item(u, I_RING_OF_NIMBLEFINGER)) * (roqf_factor()-1); - - /* Schaffenstrunk: */ - if ((dm = get_effect(u, oldpotiontype[P_DOMORE])) != 0) { - dm = MIN(dm, u->number); - change_effect(u, oldpotiontype[P_DOMORE], -dm); - amount += dm * skill; /* dm Personen produzieren doppelt */ - } - - amount /= itype->construction->minskill; - - /* Limitierung durch Parameter m. */ - if (want > 0 && want < amount) amount = want; - - busy = (amount + skill - 1) / skill; /* wieviel leute tun etwas? */ - - alist = allocations; - while (alist && alist->type!=rtype) alist = alist->next; - if (!alist) { - alist = calloc(sizeof(struct allocation_list), 1); - alist->next = allocations; - alist->type = rtype; - allocations = alist; - } - al = new_allocation(); - al->want = amount; - al->save = 1.0; - al->next = alist->data; - al->unit = u; - alist->data = al; - - if (rdata->modifiers) { - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - - resource_mod * mod = rdata->modifiers; - for (;mod->flags!=0;++mod) { - if (mod->flags & RMF_SAVEMATERIAL) { - if (mod->btype==NULL || mod->btype==btype) { - if (mod->race==NULL || mod->race==u->race) { - al->save *= mod->value.f; - } - } - } - } - } -} - -static int -required(int want, double save) -{ - int norders = (int)(want * save); - if (norders < want*save) ++norders; - return norders; -} - -static void -leveled_allocation(const resource_type * rtype, region * r, allocation * alist) -{ - const item_type * itype = resource2item(rtype); - rawmaterial * rm = rm_get(r, rtype); - int need; - boolean first = true; - - if (rm!=NULL) { - do { - int avail = rm->amount; - int norders = 0; - allocation * al; - - if(avail <= 0) { - for (al=alist;al;al=al->next) { - al->get = 0; - } - break; - } - - assert(avail>0); - - for (al=alist;al;al=al->next) if (!fval(al, AFL_DONE)) { - int req = required(al->want-al->get, al->save); - assert(al->get<=al->want && al->get >= 0); - if (eff_skill(al->unit, itype->construction->skill, r) - >= rm->level+itype->construction->minskill-1) { - if (req) { - norders += req; - } else { - fset(al, AFL_DONE); - } - } else { - fset(al, AFL_DONE); - if (first) fset(al, AFL_LOWSKILL); - } - } - need = norders; - - avail = MIN(avail, norders); - if (need>0) { - int use = 0; - for (al=alist;al;al=al->next) if (!fval(al, AFL_DONE)) { - if (avail > 0) { - int want = required(al->want-al->get, al->save); - int x = avail*want/norders; - /* Wenn Rest, dann würfeln, ob ich was bekomme: */ - if (rng_int() % norders < (avail*want) % norders) - ++x; - avail -= x; - use += x; - norders -= want; - need -= x; - al->get = MIN(al->want, al->get+(int)(x/al->save)); - } - } - if (use) { - assert(use<=rm->amount); - rm->type->use(rm, r, use); - } - assert(avail==0 || norders==0); - } - first = false; - } while (need>0); - } -} - -static void -attrib_allocation(const resource_type * rtype, region * r, allocation * alist) -{ - allocation * al; - int norders = 0; - attrib * a = a_find(rtype->attribs, &at_resourcelimit); - resource_limit * rdata = (resource_limit*)a->data.v; - int avail = rdata->value; - - for (al=alist;al;al=al->next) { - norders += required(al->want, al->save); - } - - if (rdata->limit) { - avail = rdata->limit(r, rtype); - if (avail < 0) avail = 0; - } - - avail = MIN(avail, norders); - for (al=alist;al;al=al->next) { - if (avail > 0) { - int want = required(al->want, al->save); - int x = avail*want/norders; - /* Wenn Rest, dann würfeln, ob ich was bekomme: */ - if (rng_int() % norders < (avail*want) % norders) - ++x; - avail -= x; - norders -= want; - al->get = MIN(al->want, (int)(x/al->save)); - if (rdata->produce) { - int use = required(al->get, al->save); - if (use) rdata->produce(r, rtype, use); - } - } - } - assert(avail==0 || norders==0); -} - -typedef void (*allocate_function)(const resource_type *, struct region *, struct allocation *); - -static allocate_function -get_allocator(const struct resource_type * rtype) -{ - attrib * a = a_find(rtype->attribs, &at_resourcelimit); - - if (a!=NULL) { - resource_limit * rdata = (resource_limit*)a->data.v; - if (rdata->value>0 || rdata->limit!=NULL) { - return attrib_allocation; - } - return leveled_allocation; - } - return NULL; -} - -void -split_allocations(region * r) -{ - allocation_list ** p_alist=&allocations; - freset(r, RF_SELECT); - while (*p_alist) { - allocation_list * alist = *p_alist; - const resource_type * rtype = alist->type; - allocate_function alloc = get_allocator(rtype); - const item_type * itype = resource2item(rtype); - allocation ** p_al = &alist->data; - - freset(r, RF_SELECT); - alloc(rtype, r, alist->data); - - while (*p_al) { - allocation * al = *p_al; - if (al->get) { - assert(itype || !"not implemented for non-items"); - i_change(&al->unit->items, itype, al->get); - produceexp(al->unit, itype->construction->skill, al->unit->number); - fset(r, RF_SELECT); - } - if (al->want==INT_MAX) al->want = al->get; - if (fval(al, AFL_LOWSKILL)) { - ADDMSG(&al->unit->faction->msgs, - msg_message("produce_lowskill", "unit region resource", - al->unit, al->unit->region, rtype)); - } else { - ADDMSG(&al->unit->faction->msgs, msg_message("produce", - "unit region amount wanted resource", - al->unit, al->unit->region, al->get, al->want, rtype)); - } - *p_al=al->next; - free_allocation(al); - } - *p_alist=alist->next; - free(alist); - } - allocations = NULL; -} - -static void -create_potion(unit * u, const potion_type * ptype, int want) -{ - int built; - - if (want==0) { - want = maxbuild(u, ptype->itype->construction); - } - built = build(u, ptype->itype->construction, 0, want); - switch (built) { - case ELOWSKILL: - case ENEEDSKILL: - /* no skill, or not enough skill points to build */ - cmistake(u, u->thisorder, 50, MSG_PRODUCE); - break; - case EBUILDINGREQ: - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "building_needed", "building", ptype->itype->construction->btype->_name)); - break; - case ECOMPLETE: - assert(0); - break; - case ENOMATERIALS: - /* something missing from the list of materials */ - ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, ptype->itype->construction, want)); - return; - break; - default: - i_change(&u->items, ptype->itype, built); - if (want==INT_MAX) want = built; - ADDMSG(&u->faction->msgs, msg_message("manufacture", - "unit region amount wanted resource", u, u->region, built, want, ptype->itype->rtype)); - break; - } -} - -static void -create_item(unit * u, const item_type * itype, int want) -{ - if (itype->construction && fval(itype->rtype, RTF_LIMITED)) { -#if GUARD_DISABLES_PRODUCTION == 1 - if (is_guarded(u->region, u, GUARD_PRODUCE)) { - cmistake(u, u->thisorder, 70, MSG_EVENT); - return; - } -#endif - allocate_resource(u, itype->rtype, want); - } else { - const potion_type * ptype = resource2potion(itype->rtype); - if (ptype!=NULL) create_potion(u, ptype, want); - else if (itype->construction && itype->construction->materials) manufacture(u, itype, want); - else { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_cannotmake", "")); - } - } -} - -int -make_cmd(unit * u, struct order * ord) -{ - region * r = u->region; - const building_type * btype; - const ship_type * stype; - param_t p; - int m; - const item_type * itype; - const char *s; - const struct locale * lang = u->faction->locale; - char ibuf[16]; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - m = atoi((const char *)s); - sprintf(ibuf, "%d", m); - if (!strcmp(ibuf, (const char *)s)) { - /* first came a want-paramter */ - s = getstrtoken(); - } else { - m = INT_MAX; - } - - p = findparam(s, u->faction->locale); - - /* MACHE TEMP kann hier schon gar nicht auftauchen, weil diese nicht in - * thisorder abgespeichert werden - und auf den ist getstrtoken() beim - * aufruf von make geeicht */ - - if (p == P_ROAD) { - plane * pl = rplane(r); - if (pl && fval(pl, PFL_NOBUILD)) { - cmistake(u, ord, 275, MSG_PRODUCE); - } else { - direction_t d = finddirection(getstrtoken(), u->faction->locale); - if (d!=NODIRECTION) { - build_road(r, u, m, d); - } else { - /* Die Richtung wurde nicht erkannt */ - cmistake(u, ord, 71, MSG_PRODUCE); - } - } - return 0; - } else if (p == P_SHIP) { - plane * pl = rplane(r); - if (pl && fval(pl, PFL_NOBUILD)) { - cmistake(u, ord, 276, MSG_PRODUCE); - } else { - continue_ship(r, u, m); - } - return 0; - } else if (p == P_HERBS) { - herbsearch(r, u, m); - return 0; - } - - /* since the string can match several objects, like in 'academy' and - * 'academy of arts', we need to figure out what the player meant. - * This is not 100% safe. - */ - stype = findshiptype(s, lang); - btype = findbuildingtype(s, lang); - itype = finditemtype(s, lang); - - if (itype!=NULL && (btype!=NULL || stype!=NULL)) { - if (itype->construction==NULL) { - /* if the item cannot be made, we probably didn't mean to make it */ - itype = NULL; - } else if (stype!=NULL) { - const char * sname = LOC(lang, stype->name[0]); - const char * iname = LOC(lang, resourcename(itype->rtype, 0)); - if (strlen(iname)_name); - const char * iname = LOC(lang, resourcename(itype->rtype, 0)); - if (strlen(iname)_name); - const char * sname = LOC(lang, stype->name[0]); - if (strlen(sname)faction->msgs, msg_feedback(u, ord, "error_cannotmake", "")); - } - - return 0; -} -/* ------------------------------------------------------------- */ - -static void -free_luxuries(struct attrib * a) -{ - item * itm = (item*)a->data.v; - a->data.v = NULL; - i_freeall(&itm); -} - -const attrib_type at_luxuries = { - "luxuries", NULL, free_luxuries, NULL, NULL, NULL -}; - -static void -expandbuying(region * r, request * buyorders) -{ - int max_products; - unit *u; - static struct trade { - const luxury_type * type; - int number; - int multi; - } *trades, *trade; - static int ntrades=0; - int i, j; - const luxury_type * ltype; - - if (ntrades==0) { - for (ltype=luxurytypes;ltype;ltype=ltype->next) - ++ntrades; - trades = gc_add(calloc(sizeof(struct trade), ntrades)); - for (i=0, ltype=luxurytypes;i!=ntrades;++i, ltype=ltype->next) - trades[i].type = ltype; - } - for (i=0;i!=ntrades;++i) { - trades[i].number = 0; - trades[i].multi = 1; - } - - if (!buyorders) return; - - /* Initialisation. multiplier ist der Multiplikator auf den - * Verkaufspreis. Für max_products Produkte kauft man das Produkt zum - * einfachen Verkaufspreis, danach erhöht sich der Multiplikator um 1. - * counter ist ein Zähler, der die gekauften Produkte zählt. money - * wird für die debug message gebraucht. */ - - max_products = rpeasants(r) / TRADE_FRACTION; - - /* Kauf - auch so programmiert, daß er leicht erweiterbar auf mehrere - * Güter pro Monat ist. j sind die Befehle, i der Index des - * gehandelten Produktes. */ - if (max_products>0) { - expandorders(r, buyorders); - if (!norders) return; - - for (j = 0; j != norders; j++) { - int price, multi; - ltype = oa[j].type.ltype; - trade = trades; - while (trade->type!=ltype) ++trade; - multi = trade->multi; - price = ltype->price * multi; - - if (get_pooled(oa[j].unit, oldresourcetype[R_SILVER], GET_DEFAULT, price) >= price) { - unit * u = oa[j].unit; - item * items; - - /* litems zählt die Güter, die verkauft wurden, u->n das Geld, das - * verdient wurde. Dies muß gemacht werden, weil der Preis ständig sinkt, - * man sich also das verdiente Geld und die verkauften Produkte separat - * merken muß. */ - attrib * a = a_find(u->attribs, &at_luxuries); - if (a==NULL) a = a_add(&u->attribs, a_new(&at_luxuries)); - - items = a->data.v; - i_change(&items, ltype->itype, 1); - a->data.v = items; - i_change(&oa[j].unit->items, ltype->itype, 1); - use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, price); - if (u->n < 0) - u->n = 0; - u->n += price; - - rsetmoney(r, rmoney(r) + price); - - /* Falls mehr als max_products Bauern ein Produkt verkauft haben, steigt - * der Preis Multiplikator für das Produkt um den Faktor 1. Der Zähler - * wird wieder auf 0 gesetzt. */ - if (++trade->number == max_products) { - trade->number = 0; - ++trade->multi; - } - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - } - } - free(oa); - - /* Ausgabe an Einheiten */ - - for (u = r->units; u; u = u->next) { - attrib * a = a_find(u->attribs, &at_luxuries); - item * itm; - if (a==NULL) continue; - ADDMSG(&u->faction->msgs, msg_message("buy", "unit money", u, u->n)); - for (itm=(item*)a->data.v; itm; itm=itm->next) { - if (itm->number) { - ADDMSG(&u->faction->msgs, msg_message("buyamount", - "unit amount resource", u, itm->number, itm->type->rtype)); - } - } - a_remove(&u->attribs, a); - } - } -} - -attrib_type at_trades = { - "trades", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - NO_WRITE, - NO_READ -}; - -static void -buy(unit * u, request ** buyorders, struct order * ord) -{ - region * r = u->region; - int n, k; - request *o; - attrib * a; - const item_type * itype = NULL; - const luxury_type * ltype = NULL; - if (u->ship && is_guarded(r, u, GUARD_CREWS)) { - cmistake(u, ord, 69, MSG_INCOME); - return; - } - if (u->ship && is_guarded(r, u, GUARD_CREWS)) { - cmistake(u, ord, 69, MSG_INCOME); - return; - } - /* Im Augenblick kann man nur 1 Produkt kaufen. expandbuying ist aber - * schon dafür ausgerüstet, mehrere Produkte zu kaufen. */ - - init_tokens(ord); - skip_token(); - n = getuint(); - if (!n) { - cmistake(u, ord, 26, MSG_COMMERCE); - return; - } - if (besieged(u)) { - /* Belagerte Einheiten können nichts kaufen. */ - cmistake(u, ord, 60, MSG_COMMERCE); - return; - } - - if (u->race == new_race[RC_INSECT]) { - /* entweder man ist insekt, oder... */ - if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT) && !rbuildings(r)) { - cmistake(u, ord, 119, MSG_COMMERCE); - return; - } - } else { - /* ...oder in der Region muß es eine Burg geben. */ - building * b; - static const struct building_type * bt_castle; - if (!bt_castle) bt_castle = bt_find("castle"); - for (b=r->buildings;b;b=b->next) { - if (b->type==bt_castle && b->size>=2) break; - } - if (b==NULL) { - cmistake(u, ord, 119, MSG_COMMERCE); - return; - } - } - - /* Ein Händler kann nur 10 Güter pro Talentpunkt handeln. */ - k = u->number * 10 * eff_skill(u, SK_TRADE, r); - - /* hat der Händler bereits gehandelt, muss die Menge der bereits - * verkauften/gekauften Güter abgezogen werden */ - a = a_find(u->attribs, &at_trades); - if (!a) { - a = a_add(&u->attribs, a_new(&at_trades)); - } else { - k -= a->data.i; - } - - n = MIN(n, k); - - if (!n) { - cmistake(u, ord, 102, MSG_COMMERCE); - return; - } - - assert(n>=0); - /* die Menge der verkauften Güter merken */ - a->data.i += n; - - itype = finditemtype(getstrtoken(), u->faction->locale); - if (itype!=NULL) { - ltype = resource2luxury(itype->rtype); - if (ltype==NULL) { - cmistake(u, ord, 124, MSG_COMMERCE); - return; - } - } - if (r_demand(r, ltype)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "luxury_notsold", "")); - return; - } - o = (request *) calloc(1, sizeof(request)); - o->type.ltype = ltype; /* sollte immer gleich sein */ - - o->unit = u; - o->qty = n; - addlist(buyorders, o); -} -/* ------------------------------------------------------------- */ - -/* Steuersätze in % bei Burggröße */ -static int tax_per_size[7] = -{0, 6, 12, 18, 24, 30, 36}; - -static void -expandselling(region * r, request * sellorders, int limit) -{ - int money, price, j, max_products; - /* int m, n = 0; */ - int maxsize = 0, maxeffsize = 0; - int taxcollected = 0; - int hafencollected = 0; - unit *maxowner = (unit *) NULL; - building *maxb = (building *) NULL; - building *b; - unit *u; - unit *hafenowner; - static int *counter; - static int ncounter = 0; - - if (ncounter==0) { - const luxury_type * ltype; - for (ltype=luxurytypes;ltype;ltype=ltype->next) ++ncounter; - counter=(int*)gc_add(calloc(sizeof(int), ncounter)); - } else { - memset(counter, 0, sizeof(int)*ncounter); - } - - if (!sellorders) { /* NEIN, denn Insekten können in || !r->buildings) */ - return; /* Sümpfen und Wüsten auch so handeln */ - } - /* Stelle Eigentümer der größten Burg fest. Bekommt Steuern aus jedem - * Verkauf. Wenn zwei Burgen gleicher Größe bekommt gar keiner etwas. */ - - for (b = rbuildings(r); b; b = b->next) { - if (b->size > maxsize && building_owner(b) != NULL - && b->type == bt_find("castle")) { - maxb = b; - maxsize = b->size; - maxowner = building_owner(b); - } else if (b->size == maxsize && b->type == bt_find("castle")) { - maxb = (building *) NULL; - maxowner = (unit *) NULL; - } - } - - hafenowner = owner_buildingtyp(r, bt_find("harbour")); - - if (maxb != (building *) NULL && maxowner != (unit *) NULL) { - maxeffsize = buildingeffsize(maxb, false); - if (maxeffsize == 0) { - maxb = (building *) NULL; - maxowner = (unit *) NULL; - } - } - /* Die Region muss genug Geld haben, um die Produkte kaufen zu können. */ - - money = rmoney(r); - - /* max_products sind 1/100 der Bevölkerung, falls soviele Produkte - * verkauft werden - counter[] - sinkt die Nachfrage um 1 Punkt. - * multiplier speichert r->demand für die debug message ab. */ - - max_products = rpeasants(r) / TRADE_FRACTION; - if (max_products <= 0) return; - - if (r->terrain == newterrain(T_DESERT) && buildingtype_exists(r, bt_find("caravan"), true)) { - max_products = rpeasants(r) * 2 / TRADE_FRACTION; - } - /* Verkauf: so programmiert, dass er leicht auf mehrere Gueter pro - * Runde erweitert werden kann. */ - - expandorders(r, sellorders); - if (!norders) return; - - for (j = 0; j != norders; j++) { - static const luxury_type * search=NULL; - const luxury_type * ltype = oa[j].type.ltype; - int multi = r_demand(r, ltype); - static int i=-1; - int use = 0; - if (search!=ltype) { - i=0; - for (search=luxurytypes;search!=ltype;search=search->next) ++i; - } - if (counter[i]>=limit) continue; - if (counter[i]+1 > max_products && multi > 1) --multi; - price = ltype->price * multi; - - if (money >= price) { - int abgezogenhafen = 0; - int abgezogensteuer = 0; - unit * u = oa[j].unit; - item * itm; - attrib * a = a_find(u->attribs, &at_luxuries); - if (a==NULL) a = a_add(&u->attribs, a_new(&at_luxuries)); - itm = (item *)a->data.v; - i_change(&itm, ltype->itype, 1); - a->data.v = itm; - ++use; - if (u->n < 0) - u->n = 0; - - if (hafenowner != NULL) { - if (hafenowner->faction != u->faction) { - abgezogenhafen = price / 10; - hafencollected += abgezogenhafen; - price -= abgezogenhafen; - money -= abgezogenhafen; - } - } - if (maxb != NULL) { - if (maxowner->faction != u->faction) { - abgezogensteuer = price * tax_per_size[maxeffsize] / 100; - taxcollected += abgezogensteuer; - price -= abgezogensteuer; - money -= abgezogensteuer; - } - } - u->n += price; - change_money(u, price); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - - /* r->money -= price; --- dies wird eben nicht ausgeführt, denn die - * Produkte können auch als Steuern eingetrieben werden. In der Region - * wurden Silberstücke gegen Luxusgüter des selben Wertes eingetauscht! - * Falls mehr als max_products Kunden ein Produkt gekauft haben, sinkt - * die Nachfrage für das Produkt um 1. Der Zähler wird wieder auf 0 - * gesetzt. */ - - if (++counter[i] > max_products) { - int d = r_demand(r, ltype); - if (d > 1) { - r_setdemand(r, ltype, d-1); - } - counter[i] = 0; - } - } - if (use>0) { -#ifdef NDEBUG - use_pooled(oa[j].unit, ltype->itype->rtype, GET_DEFAULT, use); -#else - /* int i = */ use_pooled(oa[j].unit, ltype->itype->rtype, GET_DEFAULT, use); - /* assert(i==use); */ -#endif - } - } - free(oa); - - /* Steuern. Hier werden die Steuern dem Besitzer der größten Burg gegeben. */ - - if (maxowner) { - if (taxcollected > 0) { - change_money(maxowner, (int) taxcollected); - add_income(maxowner, IC_TRADETAX, taxcollected, taxcollected); - /* TODO: Meldung - * "%s verdient %d Silber durch den Handel in %s.", - * unitname(maxowner), (int) taxcollected, regionname(r)); */ - } - } - if (hafenowner) { - if (hafencollected > 0) { - change_money(hafenowner, (int) hafencollected); - add_income(hafenowner, IC_TRADETAX, hafencollected, hafencollected); - } - } - /* Berichte an die Einheiten */ - - for (u = r->units; u; u = u->next) { - - attrib * a = a_find(u->attribs, &at_luxuries); - item * itm; - if (a==NULL) continue; - for (itm=(item*)a->data.v; itm; itm=itm->next) { - if (itm->number) { - ADDMSG(&u->faction->msgs, msg_message("sellamount", - "unit amount resource", u, itm->number, itm->type->rtype)); - } - } - a_remove(&u->attribs, a); - add_income(u, IC_TRADE, u->n, u->n); - } -} - -static boolean - sell(unit * u, request ** sellorders, struct order * ord) -{ - boolean unlimited = true; - const item_type * itype; - const luxury_type * ltype=NULL; - int n; - region * r = u->region; - const char *s; - - if (u->ship && is_guarded(r, u, GUARD_CREWS)) { - cmistake(u, ord, 69, MSG_INCOME); - return false; - } - /* sellorders sind KEIN array, weil für alle items DIE SELBE resource - * (das geld der region) aufgebraucht wird. */ - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - if (findparam(s, u->faction->locale) == P_ANY) { - unlimited = false; - n = rpeasants(r) / TRADE_FRACTION; - if (r->terrain == newterrain(T_DESERT) && buildingtype_exists(r, bt_find("caravan"), true)) - n *= 2; - if (n==0) { - cmistake(u, ord, 303, MSG_COMMERCE); - return false; - } - } else { - n = atoi((const char *)s); - if (n==0) { - cmistake(u, ord, 27, MSG_COMMERCE); - return false; - } - } - /* Belagerte Einheiten können nichts verkaufen. */ - - if (besieged(u)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "error60", "")); - return false; - } - /* In der Region muß es eine Burg geben. */ - - if (u->race == new_race[RC_INSECT]) { - if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT) && !rbuildings(r)) { - cmistake(u, ord, 119, MSG_COMMERCE); - return false; - } - } else { - /* ...oder in der Region muß es eine Burg geben. */ - building * b; - static const struct building_type * bt_castle; - if (!bt_castle) bt_castle = bt_find("castle"); - for (b=r->buildings;b;b=b->next) { - if (b->type==bt_castle && b->size>=2) break; - } - if (b==NULL) { - cmistake(u, ord, 119, MSG_COMMERCE); - return false; - } - } - - /* Ein Händler kann nur 10 Güter pro Talentpunkt verkaufen. */ - - n = MIN(n, u->number * 10 * eff_skill(u, SK_TRADE, r)); - - if (!n) { - cmistake(u, ord, 54, MSG_COMMERCE); - return false; - } - s=getstrtoken(); - itype = finditemtype(s, u->faction->locale); - if (itype!=NULL) ltype = resource2luxury(itype->rtype); - if (ltype==NULL) { - cmistake(u, ord, 126, MSG_COMMERCE); - return false; - } - else { - attrib * a; - request *o; - int k, available; - - if (!r_demand(r, ltype)) { - cmistake(u, ord, 263, MSG_COMMERCE); - return false; - } - available = get_pooled(u, itype->rtype, GET_DEFAULT, INT_MAX); - - /* Wenn andere Einheiten das selbe verkaufen, muß ihr Zeug abgezogen - * werden damit es nicht zweimal verkauft wird: */ - for (o=*sellorders;o;o=o->next) { - if (o->type.ltype==ltype && o->unit->faction == u->faction) { - int fpool = o->qty - get_pooled(o->unit, itype->rtype, GET_RESERVE, INT_MAX); - available -= MAX(0, fpool); - } - } - - n = MIN(n, available); - - if (n <= 0) { - cmistake(u, ord, 264, MSG_COMMERCE); - return false; - } - /* Hier wird request->type verwendet, weil die obere limit durch - * das silber gegeben wird (region->money), welches für alle - * (!) produkte als summe gilt, als nicht wie bei der - * produktion, wo für jedes produkt einzeln eine obere limite - * existiert, so dass man arrays von orders machen kann. */ - - /* Ein Händler kann nur 10 Güter pro Talentpunkt handeln. */ - k = u->number * 10 * eff_skill(u, SK_TRADE, r); - - /* hat der Händler bereits gehandelt, muss die Menge der bereits - * verkauften/gekauften Güter abgezogen werden */ - a = a_find(u->attribs, &at_trades); - if (!a) { - a = a_add(&u->attribs, a_new(&at_trades)); - } else { - k -= a->data.i; - } - - n = MIN(n, k); - assert(n>=0); - /* die Menge der verkauften Güter merken */ - a->data.i += n; - o = (request *) calloc(1, sizeof(request)); - o->unit = u; - o->qty = n; - o->type.ltype = ltype; - addlist(sellorders, o); - - return unlimited; - } -} -/* ------------------------------------------------------------- */ - -static void -expandstealing(region * r, request * stealorders) -{ - int i; - - expandorders(r, stealorders); - if (!norders) return; - - /* Für jede unit in der Region wird Geld geklaut, wenn sie Opfer eines - * Beklauen-Orders ist. Jedes Opfer muß einzeln behandelt werden. - * - * u ist die beklaute unit. oa.unit ist die klauende unit. - */ - - for (i = 0; i != norders && oa[i].unit->n <= oa[i].unit->wants; i++) { - unit *u = findunitg(oa[i].no, r); - int n = 0; - if (u && u->region==r) { - n = get_pooled(u, r_silver, GET_ALL, INT_MAX); - } -#ifndef GOBLINKILL - if (oa[i].type.goblin) { /* Goblin-Spezialklau */ - int uct = 0; - unit *u2; - assert(effskill(oa[i].unit, SK_STEALTH)>=4 || !"this goblin\'s skill is too low"); - for (u2 = r->units; u2; u2 = u2->next) { - if (u2->faction == u->faction) { - uct += maintenance_cost(u2); - } - } - n -= uct * 2; - } -#endif - if (n>10 && rplane(r) && (rplane(r)->flags & PFL_NOALLIANCES)) { - /* In Questen nur reduziertes Klauen */ - n = 10; - } - if (n > 0) { - n = MIN(n, oa[i].unit->wants); - use_pooled(u, r_silver, GET_ALL, n); - oa[i].unit->n = n; - change_money(oa[i].unit, n); - ADDMSG(&u->faction->msgs, msg_message("stealeffect", "unit region amount", u, u->region, n)); - } - add_income(oa[i].unit, IC_STEAL, oa[i].unit->wants, oa[i].unit->n); - fset(oa[i].unit, UFL_LONGACTION|UFL_NOTMOVING); - } - free(oa); -} - -/* ------------------------------------------------------------- */ -static void -plant(region *r, unit *u, int raw) -{ - int n, i, skill, planted = 0; - const item_type * itype; - static const resource_type * rt_water = NULL; - if (rt_water==NULL) rt_water = rt_find("p2"); - - assert(rt_water!=NULL); - if (!fval(r->terrain, LAND_REGION)) { - return; - } - if (rherbtype(r) == NULL) { - cmistake(u, u->thisorder, 108, MSG_PRODUCE); - return; - } - - /* Skill prüfen */ - skill = eff_skill(u, SK_HERBALISM, r); - itype = rherbtype(r); - if (skill < 6) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "plant_skills", - "skill minskill product", SK_HERBALISM, 6, itype->rtype, 1)); - return; - } - /* Wasser des Lebens prüfen */ - if (get_pooled(u, rt_water, GET_DEFAULT, 1) == 0) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "resource_missing", "missing", rt_water)); - return; - } - n = get_pooled(u, itype->rtype, GET_DEFAULT, skill*u->number); - /* Kräuter prüfen */ - if (n==0) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "resource_missing", "missing", - itype->rtype)); - return; - } - - n = MIN(skill*u->number, n); - n = MIN(raw, n); - /* Für jedes Kraut Talent*10% Erfolgschance. */ - for(i = n; i>0; i--) { - if (rng_int()%10 < skill) planted++; - } - produceexp(u, SK_HERBALISM, u->number); - - /* Alles ok. Abziehen. */ - use_pooled(u, rt_water, GET_DEFAULT, 1); - use_pooled(u, itype->rtype, GET_DEFAULT, n); - rsetherbs(r, rherbs(r)+planted); - ADDMSG(&u->faction->msgs, msg_message("plant", "unit region amount herb", - u, r, planted, itype->rtype)); -} - -static void -planttrees(region *r, unit *u, int raw) -{ - int n, i, skill, planted = 0; - const resource_type * rtype; - - if (!fval(r->terrain, LAND_REGION)) { - return; - } - - /* Mallornbäume kann man nur in Mallornregionen züchten */ - if (fval(r, RF_MALLORN)) { - rtype = rt_mallornseed; - } else { - rtype = rt_seed; - } - - /* Skill prüfen */ - skill = eff_skill(u, SK_HERBALISM, r); - if (skill < 6) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "plant_skills", - "skill minskill product", SK_HERBALISM, 6, rtype, 1)); - return; - } - if (fval(r, RF_MALLORN) && skill < 7 ) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "plant_skills", - "skill minskill product", SK_HERBALISM, 7, rtype, 1)); - return; - } - - /* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */ - raw = MIN(raw, skill*u->number); - n = get_pooled(u, rtype, GET_DEFAULT, raw); - if (n==0) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype)); - return; - } - n = MIN(raw, n); - - /* Für jeden Samen Talent*10% Erfolgschance. */ - for(i = n; i>0; i--) { - if (rng_int()%10 < skill) planted++; - } - rsettrees(r, 0, rtrees(r, 0)+planted); - - /* Alles ok. Abziehen. */ - produceexp(u, SK_HERBALISM, u->number); - use_pooled(u, rtype, GET_DEFAULT, n); - - ADDMSG(&u->faction->msgs, msg_message("plant", - "unit region amount herb", u, r, planted, rtype)); -} - -/* züchte bäume */ -static void -breedtrees(region *r, unit *u, int raw) -{ - int n, i, skill, planted = 0; - const resource_type * rtype; - static int gamecookie = -1; - static int current_season; - - if (gamecookie!=global.cookie) { - gamedate date; - get_gamedate(turn, &date); - current_season = date.season; - gamecookie = global.cookie; - } - - /* Bäume züchten geht nur im Frühling */ - if (current_season != SEASON_SPRING){ - planttrees(r, u, raw); - return; - } - - if (!fval(r->terrain, LAND_REGION)) { - return; - } - - /* Mallornbäume kann man nur in Mallornregionen züchten */ - if (fval(r, RF_MALLORN)) { - rtype = rt_mallornseed; - } else { - rtype = rt_seed; - } - - /* Skill prüfen */ - skill = eff_skill(u, SK_HERBALISM, r); - if (skill < 12) { - planttrees(r, u, raw); - return; - } - - /* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */ - raw = MIN(skill*u->number, raw); - n = get_pooled(u, rtype, GET_DEFAULT, raw); - /* Samen prüfen */ - if (n==0) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype)); - return; - } - n = MIN(raw, n); - - /* Für jeden Samen Talent*5% Erfolgschance. */ - for(i = n; i>0; i--) { - if (rng_int()%100 < skill*5) planted++; - } - rsettrees(r, 1, rtrees(r, 1)+planted); - - /* Alles ok. Abziehen. */ - produceexp(u, SK_HERBALISM, u->number); - use_pooled(u, rtype, GET_DEFAULT, n); - - ADDMSG(&u->faction->msgs, msg_message("plant", - "unit region amount herb", u, r, planted, rtype)); -} - -/* züchte pferde */ -static void -breedhorses(region *r, unit *u) -{ - int n, c; - int gezuechtet = 0; - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - - if (btype!=bt_find("stables")) { - cmistake(u, u->thisorder, 122, MSG_PRODUCE); - return; - } - if (get_item(u, I_HORSE) < 2) { - cmistake(u, u->thisorder, 107, MSG_PRODUCE); - return; - } - n = MIN(u->number * eff_skill(u, SK_HORSE_TRAINING, r), get_item(u, I_HORSE)); - - for (c = 0; c < n; c++) { - if (rng_int() % 100 < eff_skill(u, SK_HORSE_TRAINING, r)) { - i_change(&u->items, olditemtype[I_HORSE], 1); - gezuechtet++; - } - } - - produceexp(u, SK_HORSE_TRAINING, u->number); - - ADDMSG(&u->faction->msgs, msg_message("raised", - "unit amount", u, gezuechtet)); -} - -static void -breed_cmd(unit *u, struct order * ord) -{ - int m; - const char *s; - param_t p; - region *r = u->region; - const resource_type * rtype = NULL; - - if (r->land==NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); - return; - } - - /* züchte [] */ - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - m = atoi((const char *)s); - if (m!=0) { - /* first came a want-paramter */ - s = getstrtoken(); - } else { - m = INT_MAX; - } - - if (!s[0]) { - p = P_ANY; - } else { - p = findparam(s, u->faction->locale); - } - - switch (p) { - case P_HERBS: - plant(r, u, m); - break; - case P_TREES: - breedtrees(r, u, m); - break; - default: - if (p!=P_ANY) { - rtype = findresourcetype(s, u->faction->locale); - if (rtype==rt_mallornseed || rtype==rt_seed) { - breedtrees(r, u, m); - break; - } else if (rtype!=oldresourcetype[R_HORSE]) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_cannotmake", "")); - break; - } - } - breedhorses(r, u); - break; - } -} - -static const char * -rough_amount(int a, int m) - -{ - int p = (a * 100)/m; - - if (p < 10) { - return "sehr wenige"; - } else if (p < 30) { - return "wenige"; - } else if (p < 60) { - return "relativ viele"; - } else if (p < 90) { - return "viele"; - } - return "sehr viele"; -} - -static void -research_cmd(unit *u, struct order * ord) -{ - region *r = u->region; - - init_tokens(ord); - skip_token(); - /* - const char *s = getstrtoken(); - - if (findparam(s, u->faction->locale) == P_HERBS) { */ - - if (eff_skill(u, SK_HERBALISM, r) < 7) { - cmistake(u, ord, 227, MSG_EVENT); - return; - } - - produceexp(u, SK_HERBALISM, u->number); - - if (rherbs(r) > 0) { - const item_type *itype = rherbtype(r); - - if (itype != NULL) { - ADDMSG(&u->faction->msgs, msg_message("researchherb", - "unit region amount herb", - u, r, rough_amount(rherbs(r), 100), itype->rtype)); - } else { - ADDMSG(&u->faction->msgs, msg_message("researchherb_none", - "unit region", u, r)); - } - } else { - ADDMSG(&u->faction->msgs, msg_message("researchherb_none", - "unit region", u, r)); - } -} - -static int -max_skill(region * r, faction * f, skill_t sk) -{ - unit *u; - int w = 0; - - for (u = r->units; u; u = u->next) { - if (u->faction == f) { - if (eff_skill(u, sk, r) > w) { - w = eff_skill(u, sk, r); - } - } - } - - return w; -} - -static void -steal_cmd(unit * u, struct order * ord, request ** stealorders) -{ - int n, i, id; - boolean goblin = false; - request * o; - unit * u2 = NULL; - region * r = u->region; - faction * f = NULL; - plane * pl; - - assert(skill_enabled[SK_PERCEPTION] && skill_enabled[SK_STEALTH]); - - if (!fval(u->race, RCF_CANSTEAL)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_nosteal", "race", u->race)); - return; - } - - if (fval(r->terrain, SEA_REGION) && u->race != new_race[RC_AQUARIAN]) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); - return; - } - - pl = rplane(r); - if (pl && fval(pl, PFL_NOATTACK)) { - cmistake(u, ord, 270, MSG_INCOME); - return; - } - - init_tokens(ord); - skip_token(); - id = read_unitid(u->faction, r); - u2 = findunitr(r, id); - - if (u2 && u2->region==u->region) { - f = u2->faction; - } else { - f = dfindhash(id); - } - - for (u2=r->units;u2;u2=u2->next) { - if (u2->faction == f && cansee(u->faction, r, u2, 0)) break; - } - - if (!u2) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return; - } - - if (IsImmune(u2->faction)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "newbie_immunity_error", - "turns", NewbieImmunity())); - return; - } - - if (u->faction->alliance && u->faction->alliance == u2->faction->alliance) { - cmistake(u, ord, 47, MSG_INCOME); - return; - } - - assert(u->region==u2->region); - if (!can_contact(r, u, u2)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error60", "")); - return; - } - - n = eff_skill(u, SK_STEALTH, r) - max_skill(r, f, SK_PERCEPTION); - - if (n <= 0) { - /* Wahrnehmung == Tarnung */ - if (u->race != new_race[RC_GOBLIN] || eff_skill(u, SK_STEALTH, r) <= 3) { - ADDMSG(&u->faction->msgs, msg_message("stealfail", "unit target", u, u2)); - if (n==0) { - ADDMSG(&u2->faction->msgs, msg_message("stealdetect", "unit", u2)); - } else { - ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target", u, u2)); - } - return; - } else { - ADDMSG(&u->faction->msgs, msg_message("stealfatal", "unit target", u, u2)); - ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target", u, u2)); - n = 1; - goblin = true; - } - } - - i = MIN(u->number, get_item(u, I_RING_OF_NIMBLEFINGER)); - if (i > 0) { - n *= STEALINCOME * (u->number + i * (roqf_factor()-1)); - } else { - n *= u->number * STEALINCOME; - } - - u->wants = n; - - /* wer dank unsichtbarkeitsringen klauen kann, muss nicht unbedingt ein - * guter dieb sein, schliesslich macht man immer noch sehr viel laerm */ - - o = (request *) calloc(1, sizeof(request)); - o->unit = u; - o->qty = 1; /* Betrag steht in u->wants */ - o->no = u2->no; - o->type.goblin = goblin; /* Merken, wenn Goblin-Spezialklau */ - addlist(stealorders, o); - - /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ - - produceexp(u, SK_STEALTH, MIN(n, u->number)); -} -/* ------------------------------------------------------------- */ - - -static void -expandentertainment(region * r) -{ - unit *u; - int m = entertainmoney(r); - request *o; - - for (o = &entertainers[0]; o != nextentertainer; ++o) { - double part = m / (double) entertaining; - u = o->unit; - if (entertaining <= m) - u->n = o->qty; - else - u->n = (int) (o->qty * part); - change_money(u, u->n); - rsetmoney(r, rmoney(r) - u->n); - m -= u->n; - entertaining -= o->qty; - - /* Nur soviel PRODUCEEXP wie auch tatsächlich gemacht wurde */ - produceexp(u, SK_ENTERTAINMENT, MIN(u->n, u->number)); - add_income(u, IC_ENTERTAIN, o->qty, u->n); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - } -} - -void -entertain_cmd(unit * u, struct order * ord) -{ - region * r = u->region; - int max_e; - request *o; - static int entertainbase = 0; - static int entertainperlevel = 0; - - if (!entertainbase) { - const char * str = get_param(global.parameters, "entertain.base"); - entertainbase = str?atoi(str):0; - } - if (!entertainperlevel) { - const char * str = get_param(global.parameters, "entertain.perlevel"); - entertainperlevel = str?atoi(str):0; - } - if (fval(u, UFL_WERE)) { - cmistake(u, ord, 58, MSG_INCOME); - return; - } - if (!effskill(u, SK_ENTERTAINMENT)) { - cmistake(u, ord, 58, MSG_INCOME); - return; - } - if (besieged(u)) { - cmistake(u, ord, 60, MSG_INCOME); - return; - } - if (u->ship && is_guarded(r, u, GUARD_CREWS)) { - cmistake(u, ord, 69, MSG_INCOME); - return; - } - if (is_cursed(r->attribs, C_DEPRESSION, 0)) { - cmistake(u, ord, 28, MSG_INCOME); - return; - } - - u->wants = u->number * (entertainbase + effskill(u, SK_ENTERTAINMENT) - * entertainperlevel); - - init_tokens(ord); - skip_token(); - max_e = getuint(); - if (max_e != 0) { - u->wants = MIN(u->wants,max_e); - } - o = nextentertainer++; - o->unit = u; - o->qty = u->wants; - entertaining += o->qty; -} - -/** - * \return number of working spaces taken by players - */ -static void -expandwork(region * r, request * work_begin, request * work_end, int maxwork) -{ - int earnings; - /* n: verbleibende Einnahmen */ - /* fishes: maximale Arbeiter */ - int jobs = maxwork; - int p_wage = wage(r, NULL, NULL, turn); - int money = rmoney(r); - request *o; - - for (o = work_begin; o != work_end; ++o) { - unit * u = o->unit; - int workers; - - if (u->number == 0) continue; - - if (jobs>=working) workers = u->number; - else { - workers = u->number * jobs / working; - if (rng_int() % working < (u->number * jobs) % working) workers++; - } - - assert(workers>=0); - - u->n = workers * wage(u->region, u->faction, u->race, turn); - - jobs -= workers; - assert(jobs>=0); - - change_money(u, u->n); - working -= o->unit->number; - add_income(u, IC_WORK, o->qty, u->n); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - } - - if (jobs>rpeasants(r)) { - jobs = rpeasants(r); - } - earnings = jobs * p_wage; - if (rule_blessed_harvest()==HARVEST_TAXES) { - /* E3 rules */ - static const curse_type * blessedharvest_ct; - if (!blessedharvest_ct) { - blessedharvest_ct = ct_find("blessedharvest"); - } - if (blessedharvest_ct && r->attribs) { - int happy = (int)curse_geteffect(get_curse(r->attribs, blessedharvest_ct)); - happy = MIN(happy, jobs); - earnings += happy; - } - } - rsetmoney(r, money + earnings); -} - -static int -do_work(unit * u, order * ord, request * o) -{ - if (playerrace(u->race)) { - region * r = u->region; - int w; - - if (fval(u, UFL_WERE)) { - if (ord) cmistake(u, ord, 313, MSG_INCOME); - return -1; - } - if (besieged(u)) { - if (ord) cmistake(u, ord, 60, MSG_INCOME); - return -1; - } - if (u->ship && is_guarded(r, u, GUARD_CREWS)) { - if (ord) cmistake(u, ord, 69, MSG_INCOME); - return -1; - } - w = wage(r, u->faction, u->race, turn); - u->wants = u->number * w; - o->unit = u; - o->qty = u->number * w; - working += u->number; - return 0; - } - else if (ord && !is_monsters(u->faction)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_cantwork", "race", u->race)); - } - return -1; -} - -static void -expandtax(region * r, request * taxorders) -{ - unit *u; - int i; - - expandorders(r, taxorders); - if (!norders) return; - - for (i = 0; i != norders && rmoney(r) > TAXFRACTION; i++) { - change_money(oa[i].unit, TAXFRACTION); - oa[i].unit->n += TAXFRACTION; - rsetmoney(r, rmoney(r) -TAXFRACTION); - } - free(oa); - - for (u = r->units; u; u = u->next) { - if (u->n >= 0) { - add_income(u, IC_TAX, u->wants, u->n); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - } - } -} - -void -tax_cmd(unit * u, struct order * ord, request ** taxorders) -{ - /* Steuern werden noch vor der Forschung eingetrieben */ - region * r = u->region; - unit *u2; - int n; - request *o; - int max; - - if (!humanoidrace(u->race) && !is_monsters(u->faction)) { - cmistake(u, ord, 228, MSG_INCOME); - return; - } - - if (fval(u, UFL_WERE)) { - cmistake(u, ord, 228, MSG_INCOME); - return; - } - - if (besieged(u)) { - cmistake(u, ord, 60, MSG_INCOME); - return; - } - n = armedmen(u, false); - - if (!n) { - cmistake(u, ord, 48, MSG_INCOME); - return; - } - - init_tokens(ord); - skip_token(); - max = getuint(); - - if (max == 0) max = INT_MAX; - if (!playerrace(u->race)) { - u->wants = MIN(income(u), max); - } else { - u->wants = MIN(n * eff_skill(u, SK_TAXING, r) * 20, max); - } - - u2 = is_guarded(r, u, GUARD_TAX); - if (u2) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "region_guarded", "guard", u2)); - return; - } - - /* die einnahmen werden in fraktionen von 10 silber eingeteilt: diese - * fraktionen werden dann bei eintreiben unter allen eintreibenden - * einheiten aufgeteilt. */ - - o = (request *) calloc(1, sizeof(request)); - o->qty = u->wants / TAXFRACTION; - o->unit = u; - addlist(taxorders, o); - return; -} - -#define MAX_WORKERS 2048 -void -auto_work(region * r) -{ - request workers[MAX_WORKERS]; - request * nextworker = workers; - unit * u; - - for (u=r->units;u;u=u->next) { - if (!(u->flags & UFL_LONGACTION) && !is_monsters(u->faction)) { - if (do_work(u, NULL, nextworker)==0) { - assert(nextworker-workersfaction!=f) return; - - maxsize = buildingeffsize(b, false); - if (maxsize>0) { - double taxfactor = money * b->type->taxes(b, maxsize); - double morale = money * region_get_morale(r) * MORALE_TAX_FACTOR; - if (taxfactor>morale) taxfactor = morale; - if (taxfactor>0) { - int taxmoney = (int)taxfactor; - change_money(u, taxmoney); - rsetmoney(r, money - taxmoney); - ADDMSG(&u->faction->msgs, msg_message("income_tax", - "unit region amount", u, r, taxmoney)); - } - } -} - -void -produce(struct region *r) -{ - request workers[MAX_WORKERS]; - request *taxorders, *sellorders, *stealorders, *buyorders; - unit *u; - int todo; - static int rule_autowork = -1; - boolean limited = true; - request * nextworker = workers; - assert(r); - - /* das sind alles befehle, die 30 tage brauchen, und die in thisorder - * stehen! von allen 30-tage befehlen wird einfach der letzte verwendet - * (dosetdefaults). - * - * kaufen vor einnahmequellen. da man in einer region dasselbe produkt - * nicht kaufen und verkaufen kann, ist die reihenfolge wegen der - * produkte egal. nicht so wegen dem geld. - * - * lehren vor lernen. */ - - if (rule_autowork<0) { - rule_autowork = get_param_int(global.parameters, "work.auto", 0); - } - - assert(rmoney(r) >= 0); - assert(rpeasants(r) >= 0); - - if (r->land && rule_auto_taxation()) { - /* new taxation rules, region owners make money based on morale and building */ - peasant_taxes(r); - } - - buyorders = 0; - sellorders = 0; - working = 0; - nextentertainer = &entertainers[0]; - entertaining = 0; - taxorders = 0; - stealorders = 0; - - for (u = r->units; u; u = u->next) { - order * ord; - boolean trader = false; - - if (u->race == new_race[RC_SPELL] || fval(u, UFL_LONGACTION)) - continue; - - if (u->race == new_race[RC_INSECT] && r_insectstalled(r) && - !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) - continue; - - if (fval(u, UFL_LONGACTION) && u->thisorder==NULL) { - cmistake(u, u->thisorder, 52, MSG_PRODUCE); - continue; - } - - for (ord = u->orders;ord;ord=ord->next) { - switch (get_keyword(ord)) { - case K_BUY: - buy(u, &buyorders, ord); - trader = true; - break; - case K_SELL: - /* sell returns true if the sale is not limited - * by the region limit */ - limited &= !sell(u, &sellorders, ord); - trader = true; - break; - } - } - if (trader) { - attrib * a = a_find(u->attribs, &at_trades); - if (a && a->data.i) { - produceexp(u, SK_TRADE, u->number); - } - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - continue; - } - - todo = get_keyword(u->thisorder); - if (todo == NOKEYWORD) continue; - - if (fval(r->terrain, SEA_REGION) && u->race != new_race[RC_AQUARIAN] - && !(u->race->flags & RCF_SWIM) - && todo != K_STEAL && todo != K_SPY && todo != K_SABOTAGE) - continue; - - switch (todo) { - - case K_ENTERTAIN: - entertain_cmd(u, u->thisorder); - break; - - case K_WORK: - if (!rule_autowork && do_work(u, u->thisorder, nextworker)==0) { - assert(nextworker-workersthisorder, &taxorders); - break; - - case K_STEAL: - steal_cmd(u, u->thisorder, &stealorders); - break; - - case K_SPY: - spy_cmd(u, u->thisorder); - break; - - case K_SABOTAGE: - sabotage_cmd(u, u->thisorder); - break; - - case K_PLANT: - case K_BREED: - breed_cmd(u, u->thisorder); - break; - - case K_RESEARCH: - research_cmd(u, u->thisorder); - break; - } - } - - /* Entertainment (expandentertainment) und Besteuerung (expandtax) vor den - * Befehlen, die den Bauern mehr Geld geben, damit man aus den Zahlen der - * letzten Runde berechnen kann, wieviel die Bauern für Unterhaltung - * auszugeben bereit sind. */ - if (entertaining) expandentertainment(r); - if (!rule_autowork) { - expandwork(r, workers, nextworker, maxworkingpeasants(r)); - } - if (taxorders) expandtax(r, taxorders); - - /* An erster Stelle Kaufen (expandbuying), die Bauern so Geld bekommen, um - * nachher zu beim Verkaufen (expandselling) den Spielern abkaufen zu - * können. */ - - if (buyorders) expandbuying(r, buyorders); - - if (sellorders) { - int limit = rpeasants(r) / TRADE_FRACTION; - if (r->terrain == newterrain(T_DESERT) && buildingtype_exists(r, bt_find("caravan"), true)) - limit *= 2; - expandselling(r, sellorders, limited?limit:INT_MAX); - } - - /* Die Spieler sollen alles Geld verdienen, bevor sie beklaut werden - * (expandstealing). */ - - if (stealorders) expandstealing(r, stealorders); - - assert(rmoney(r) >= 0); - assert(rpeasants(r) >= 0); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#pragma region includes + +#include +#include +#include "economy.h" + +/* gamecode includes */ +#include "archetype.h" +#include "give.h" +#include "laws.h" +#include "randenc.h" +#include "spy.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +/* libs includes */ +#include +#include +#include +#include +#include + +#pragma endregion + +typedef struct request { + struct request * next; + struct unit * unit; + struct order * ord; + int qty; + int no; + union { + boolean goblin; /* stealing */ + const struct luxury_type * ltype; /* trading */ + } type; +} request; + +static int working; + +static request entertainers[1024]; +static request *nextentertainer; +static int entertaining; + +static int norders; +static request *oa; + +#define RECRUIT_MERGE 1 +#define RECRUIT_CLASSIC 2 +#define RECRUIT_ARCHETYPES 4 +static int rules_recruit = -1; + +static void recruit_init(void) +{ + if (rules_recruit<0) { + rules_recruit = 0; + if (get_param_int(global.parameters, "recruit.allow_merge", 1)) { + rules_recruit |= RECRUIT_MERGE; + } + if (get_param_int(global.parameters, "recruit.classic", 1)) { + rules_recruit |= RECRUIT_CLASSIC; + } + if (get_param_int(global.parameters, "recruit.archetype", 0)) { + rules_recruit |= RECRUIT_ARCHETYPES; + } + } +} + +int +income(const unit * u) +{ + switch(old_race(u->race)) { + case RC_FIREDRAGON: + return 150 * u->number; + case RC_DRAGON: + return 1000 * u->number; + case RC_WYRM: + return 5000 * u->number; + } + return 20 * u->number; +} + +static void +scramble(void *data, int n, size_t width) +{ + int j; + char temp[64]; + assert(width<=sizeof(temp)); + for (j=0;j!=n;++j) { + int k = rng_int() % n; + if (k==j) continue; + memcpy(temp, (char*)data+j*width, width); + memcpy((char*)data+j*width, (char*)data+k*width, width); + memcpy((char*)data+k*width, temp, width); + } +} + +static void +expandorders(region * r, request * requests) +{ + unit *u; + request *o; + + /* Alle Units ohne request haben ein -1, alle units mit orders haben ein + * 0 hier stehen */ + + for (u = r->units; u; u = u->next) + u->n = -1; + + norders = 0; + + for (o = requests; o; o = o->next) { + if (o->qty > 0) { + norders += o->qty; + } + } + + if (norders > 0) { + int i = 0; + oa = (request *) calloc(norders, sizeof(request)); + for (o = requests; o; o = o->next) { + if (o->qty > 0) { + int j; + for (j = o->qty; j; j--) { + oa[i] = *o; + oa[i].unit->n = 0; + i++; + } + } + } + scramble(oa, norders, sizeof(request)); + } else { + oa = NULL; + } + while (requests) { + request * o = requests->next; + free_order(requests->ord); + free(requests); + requests = o; + } +} +/* ------------------------------------------------------------- */ + +static void +change_level(unit * u, skill_t sk, int bylevel) +{ + skill * sv = get_skill(u, sk); + assert(bylevel>0); + if (sv==0) sv = add_skill(u, sk); + sk_set(sv, sv->level+bylevel); +} + +typedef struct recruitment { + struct recruitment * next; + faction * f; + request * requests; + int total, assigned; +} recruitment; + +static recruitment * +select_recruitment(request ** rop, int (*quantify)(const struct race*, int), int * total) +{ + recruitment * recruits = NULL; + + while (*rop) { + recruitment * rec = recruits; + request * ro = *rop; + unit * u = ro->unit; + const race * rc = u->race; + int qty = quantify(rc, ro->qty); + + if (qty<0) { + rop = &ro->next; /* skip this one */ + } else { + *rop = ro->next; /* remove this one */ + while (rec && rec->f!=u->faction) rec = rec->next; + if (rec==NULL) { + rec = malloc(sizeof(recruitment)); + rec->f = u->faction; + rec->total = 0; + rec->assigned = 0; + rec->requests = NULL; + rec->next = recruits; + recruits = rec; + } + *total += qty; + rec->total += qty; + ro->next = rec->requests; + rec->requests = ro; + } + } + return recruits; +} + +static void +add_recruits(unit * u, int number, int wanted) +{ + region * r = u->region; + assert(number<=wanted); + if (number > 0) { + unit * unew; + char equipment[64]; + + if (u->number==0) { + set_number(u, number); + u->hp = number * unit_max_hp(u); + unew = u; + } else { + unew = create_unit(r, u->faction, number, u->race, 0, NULL, u); + } + + snprintf(equipment, sizeof(equipment), "new_%s_unit", u->race->_name[0]); + equip_unit(unew, get_equipment(equipment)); + + + if (unew->race->ec_flags & ECF_REC_HORSES) { + change_level(unew, SK_RIDING, 1); + } + + if (unew!=u) { + transfermen(unew, u, unew->number); + remove_unit(&r->units, unew); + } + } + if (number < wanted) { + ADDMSG(&u->faction->msgs, msg_message("recruit", + "unit region amount want", u, r, number, wanted)); + } +} + +static int +any_recruiters(const struct race * rc, int qty) +{ + return (int)(qty * 2 * rc->recruit_multi); +} + +static int +peasant_recruiters(const struct race * rc, int qty) +{ + if (rc->ec_flags & ECF_REC_ETHEREAL) return -1; + if (rc->ec_flags & ECF_REC_HORSES) return -1; + return (int)(qty * 2 * rc->recruit_multi); +} + +static int +horse_recruiters(const struct race * rc, int qty) +{ + if (rc->ec_flags & ECF_REC_ETHEREAL) return -1; + if (rc->ec_flags & ECF_REC_HORSES) return (int)(qty * 2 * rc->recruit_multi); + return -1; +} + +static int +do_recruiting(recruitment * recruits, int available) +{ + recruitment * rec; + int recruited = 0; + + while (available>0) { + int n = 0; + int rest, mintotal = INT_MAX; + + for (rec=recruits;rec!=NULL;rec=rec->next) { + int want = rec->total - rec->assigned; + if (want>0) { + if (mintotal>want) mintotal = want; + ++n; + } + } + if (n==0) break; + if (mintotal*n>available) { + mintotal = available/n; + } + rest = available - mintotal*n; + + for (rec=recruits;rec!=NULL;rec=rec->next) { + int want = rec->total - rec->assigned; + + if (want>0) { + int get = mintotal; + if (want>mintotal && restassigned += get; + } + } + } + + for (rec=recruits;rec!=NULL;rec=rec->next) { + request * req; + int get = rec->assigned; + + for (req=rec->requests;req;req=req->next) { + unit * u = req->unit; + const race * rc = u->race; /* race is set in recruit() */ + int number, dec; + float multi = 2.0F * rc->recruit_multi; + + number = MIN(req->qty, (int)(get / multi)); + if (rc->recruitcost) { + int afford = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, number*rc->recruitcost) / rc->recruitcost; + number = MIN(number, afford); + use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, rc->recruitcost*number); + } + if (u->number+number>UNIT_MAXSIZE) { + ADDMSG(&u->faction->msgs, msg_feedback(u, req->ord, "error_unit_size", "maxsize", UNIT_MAXSIZE)); + number = UNIT_MAXSIZE-u->number; + assert(number>=0); + } + add_recruits(u, number, req->qty); + dec = (int)(number * multi); + if ((rc->ec_flags & ECF_REC_ETHEREAL)==0) { + recruited += dec; + } + + get -= dec; + } + } + return recruited; +} + +static void +feedback_give_not_allowed(unit * u, order * ord) +{ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_give_forbidden", "")); +} + +static boolean check_give(unit * u, unit * u2, const item_type * itype, int mask) +{ + if (u2) { + if (u->faction!=u2->faction) { + int rule = rule_give(); + if (itype) { + assert(mask==0); + if (itype->rtype->ltype) mask |= GIVE_LUXURIES; + else if (fval(itype, ITF_HERB)) mask |= GIVE_HERBS; + else mask |= GIVE_GOODS; + } + return (rule&mask)!=0; + } + } else { + int rule = rule_give(); + return (rule & GIVE_PEASANTS)!=0; + } + return true; +} + +void +free_recruitments(recruitment * recruits) +{ + while (recruits) { + recruitment * rec = recruits; + recruits = rec->next; + while (rec->requests) { + request * req = rec->requests; + rec->requests = req->next; + free(req); + } + free(rec); + } +} + +/* Rekrutierung */ +static void +expandrecruit(region * r, request * recruitorders) +{ + recruitment * recruits = NULL; + + int orc_total = 0; + + /* centaurs: */ + recruits = select_recruitment(&recruitorders, horse_recruiters, &orc_total); + if (recruits) { + int recruited, horses = rhorses(r) * 2; + if (orc_total0) { + rsetpeasants(r, peasants - recruited/2); + } + free_recruitments(recruits); + } + + assert(recruitorders==NULL); +} + +static int +recruit_cost(const faction * f, const race * rc) +{ + if (is_monsters(f) || f->race==rc) { + return rc->recruitcost; + } else if (valid_race(f, rc)) { + return rc->recruitcost; +/* return get_param_int(f->race->parameters, "other_cost", -1); */ + } + return -1; +} + +static void +recruit(unit * u, struct order * ord, request ** recruitorders) +{ + int n; + region * r = u->region; + plane * pl; + request *o; + int recruitcost = -1; + const faction * f = u->faction; + const struct race * rc = u->race; + const char * str; + + init_tokens(ord); + skip_token(); + n = getuint(); + + if (u->number==0) { + str = getstrtoken(); + if (str && str[0]) { + /* Monster dürfen REKRUTIERE 15 dracoid machen + * also: secondary race */ + rc = findrace(str, f->locale); + if (rc!=NULL) { + recruitcost = recruit_cost(f, rc); + } + } + } + if (recruitcost<0) { + rc = u->race; + recruitcost = recruit_cost(f, rc); + } + u->race = rc; + assert(rc && recruitcost>=0); + +#if GUARD_DISABLES_RECRUIT + /* this is a very special case because the recruiting unit may be empty + * at this point and we have to look at the creating unit instead. This + * is done in cansee, which is called indirectly by is_guarded(). */ + if (is_guarded(r, u, GUARD_RECRUIT)) { + cmistake(u, ord, 70, MSG_EVENT); + return; + } +#endif + + if (rc == new_race[RC_INSECT]) { + gamedate date; + get_gamedate(turn, &date); + if (date.season == 0 && r->terrain != newterrain(T_DESERT)) { +#ifdef INSECT_POTION + boolean usepotion = false; + unit *u2; + + for (u2 = r->units; u2; u2 = u2->next) + if (fval(u2, UFL_WARMTH)) { + usepotion = true; + break; + } + if (!usepotion) +#endif + { + cmistake(u, ord, 98, MSG_EVENT); + return; + } + } + /* in Gletschern, Eisbergen gar nicht rekrutieren */ + if (r_insectstalled(r)) { + cmistake(u, ord, 97, MSG_EVENT); + return; + } + } + if (is_cursed(r->attribs, C_RIOT, 0)) { + /* Die Region befindet sich in Aufruhr */ + cmistake(u, ord, 237, MSG_EVENT); + return; + } + + if (!(rc->ec_flags & ECF_REC_HORSES) && fval(r, RF_ORCIFIED)) { + if (rc != new_race[RC_ORC]) + { + cmistake(u, ord, 238, MSG_EVENT); + return; + } + } + + if (recruitcost) { + pl = getplane(r); + if (pl && fval(pl, PFL_NORECRUITS)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "error_pflnorecruit", "")); + return; + } + + if (get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, recruitcost) < recruitcost) { + cmistake(u, ord, 142, MSG_EVENT); + return; + } + } + if (!playerrace(rc) || idle(u->faction)) { + cmistake(u, ord, 139, MSG_EVENT); + return; + } + + if (has_skill(u, SK_MAGIC)) { + /* error158;de;{unit} in {region}: '{command}' - Magier arbeiten + * grundsätzlich nur alleine! */ + cmistake(u, ord, 158, MSG_EVENT); + return; + } + if (has_skill(u, SK_ALCHEMY) + && count_skill(u->faction, SK_ALCHEMY) + n > + skill_limit(u->faction, SK_ALCHEMY)) + { + cmistake(u, ord, 156, MSG_EVENT); + return; + } + if (recruitcost>0) { + int pooled = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, recruitcost * n); + n = MIN(n, pooled / recruitcost); + } + + u->wants = n; + + if (!n) { + cmistake(u, ord, 142, MSG_EVENT); + return; + } + + o = (request *) calloc(1, sizeof(request)); + o->qty = n; + o->unit = u; + o->ord = copy_order(ord); + addlist(recruitorders, o); +} + +static void +friendly_takeover(region * r, faction * f) +{ + int morale = region_get_morale(r); + region_set_owner(r, f, turn); + if (morale>0) { + morale = MAX(0, morale-MORALE_TRANSFER); + region_set_morale(r, morale, turn); + } +} + +static void +give_control(unit * u, unit * u2) +{ + if (u->building && u->faction!=u2->faction && rule_region_owners()) { + region * r = u->region; + faction * f = region_get_owner(r); + if (f==u->faction) { + building * b = largestbuilding(r, &cmp_current_owner, false); + if (b==u->building) { + friendly_takeover(r, u2->faction); + } + } + } + freset(u, UFL_OWNER); + fset(u2, UFL_OWNER); +} + +int +give_control_cmd(unit * u, order * ord) +{ + region * r = u->region; + unit *u2; + const char * s; + param_t p; + + init_tokens(ord); + skip_token(); + u2 = getunit(r, u->faction); + s = getstrtoken(); + p = findparam(s, u->faction->locale); + + /* first, do all the ones that do not require HELP_GIVE or CONTACT */ + if (p == P_CONTROL) { + message * msg; + + if (!u2) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } + else if (!u->building && !u->ship) { + cmistake(u, ord, 140, MSG_EVENT); + } + else if (u->building && u2->building != u->building) { + cmistake(u, ord, 33, MSG_EVENT); + } + else if (u->ship && u2->ship != u->ship) { + cmistake(u, ord, 32, MSG_EVENT); + } + else if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 49, MSG_EVENT); + } + else { + give_control(u, u2); + + msg = msg_message("givecommand", "unit recipient", u, u2); + add_message(&u->faction->msgs, msg); + if (u->faction != u2->faction) { + add_message(&u2->faction->msgs, msg); + } + msg_release(msg); + } + } + return 0; +} + +static void +give_cmd(unit * u, order * ord) +{ + region * r = u->region; + unit *u2; + const char *s; + int i, n; + const item_type * itype; + param_t p; + plane * pl; + + init_tokens(ord); + skip_token(); + u2 = getunit(r, u->faction); + s = getstrtoken(); + p = findparam(s, u->faction->locale); + + /* first, do all the ones that do not require HELP_GIVE or CONTACT */ + if (p == P_CONTROL) { + /* handled in give_control_cmd */ + return; + } + + if (!u2 && !getunitpeasants) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + + if (!check_give(u, u2, NULL, GIVE_ALLITEMS)) { + feedback_give_not_allowed(u, ord); + return; + } + + /* Damit Tarner nicht durch die Fehlermeldung enttarnt werden können */ + if (u2 && !alliedunit(u2, u->faction, HELP_GIVE) && !cansee(u->faction,r,u2,0) && !ucontact(u2, u) && !fval(u2, UFL_TAKEALL)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + if (u == u2) { + cmistake(u, ord, 8, MSG_COMMERCE); + return; + } + + /* UFL_TAKEALL ist ein grober Hack. Generalisierung tut not, ist aber nicht + * wirklich einfach. */ + pl = rplane(r); + if (pl && fval(pl, PFL_NOGIVE) && (!u2 || !fval(u2, UFL_TAKEALL))) { + cmistake(u, ord, 268, MSG_COMMERCE); + return; + } + + if (u2 && u2->race == new_race[RC_SPELL]) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + + else if (u2 && !alliedunit(u2, u->faction, HELP_GIVE) && !ucontact(u2, u)) { + cmistake(u, ord, 40, MSG_COMMERCE); + return; + } + + else if (p == P_HERBS) { + boolean given = false; + if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_nogive", "race", u->race)); + return; + } + if (!check_give(u, u2, NULL, GIVE_HERBS)) { + feedback_give_not_allowed(u, ord); + return; + } + if (u2 && !(u2->race->ec_flags & GETITEM)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_notake", "race", u2->race)); + return; + } + if (!u2) { + if (!getunitpeasants) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + } + if (u->items) { + item **itmp=&u->items; + while (*itmp) { + item * itm = *itmp; + const item_type * itype = itm->type; + if (fval(itype, ITF_HERB) && itm->number>0) { + /* give_item ändert im fall,das man alles übergibt, die + * item-liste der unit, darum continue vor pointerumsetzten */ + if (give_item(itm->number, itm->type, u, u2, ord)==0) { + given = true; + if (*itmp!=itm) continue; + continue; + } + } + itmp = &itm->next; + } + } + if (!given) cmistake(u, ord, 38, MSG_COMMERCE); + return; + } + + else if (p == P_ZAUBER) { + cmistake(u, ord, 7, MSG_COMMERCE); + /* geht nimmer */ + return; + } + + else if (p == P_UNIT) { /* Einheiten uebergeben */ + if (!(u->race->ec_flags & GIVEUNIT)) { + cmistake(u, ord, 167, MSG_COMMERCE); + return; + } + + give_unit(u, u2, ord); + return; + } + + else if (p==P_ANY) { + const char * s = getstrtoken(); + + if (!check_give(u, u2, NULL, GIVE_ALLITEMS)) { + feedback_give_not_allowed(u, ord); + return; + } + if (*s == 0) { /* Alle Gegenstände übergeben */ + + /* do these checks once, not for each item we have: */ + if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_nogive", "race", u->race)); + return; + } + if (u2 && !(u2->race->ec_flags & GETITEM)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_notake", "race", u2->race)); + return; + } + + /* für alle items einmal prüfen, ob wir mehr als von diesem Typ + * reserviert ist besitzen und diesen Teil dann übergeben */ + if (u->items) { + item **itmp=&u->items; + while (*itmp) { + item * itm = *itmp; + const item_type * itype = itm->type; + if (itm->number > 0 && itm->number - get_reservation(u, itype->rtype) > 0) { + n = itm->number - get_reservation(u, itype->rtype); + if (give_item(n, itype, u, u2, ord)==0) { + if (*itmp!=itm) continue; + } + } + itmp = &itm->next; + } + } + return; + } + else { + param_t p2 = findparam(s, u->faction->locale); + + if (p2 == P_PERSON) { + if (!(u->race->ec_flags & GIVEPERSON)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_noregroup", "race", u->race)); + return; + } + n = u->number; + give_men(n, u, u2, ord); + return; + } + + if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_nogive", "race", u->race)); + return; + } + if (u2 && !(u2->race->ec_flags & GETITEM)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_notake", "race", u2->race)); + return; + } + + itype = finditemtype(s, u->faction->locale); + if (itype!=NULL) { + item * i = *i_find(&u->items, itype); + if (i!=NULL) { + if (check_give(u, u2, itype, 0)) { + n = i->number - get_reservation(u, itype->rtype); + give_item(n, itype, u, u2, ord); + } else { + feedback_give_not_allowed(u, ord); + } + return; + } + } + } + } else if (p==P_EACH) { + if (u2==NULL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "peasants_give_invalid", "")); + return; + } + s = getstrtoken(); /* skip one ahead to get the amount. */ + } + + n = atoip((const char *)s); /* n: Anzahl */ + if (p==P_EACH) { + n *= u2->number; + } + s = getstrtoken(); + + if (s == NULL) { + cmistake(u, ord, 113, MSG_COMMERCE); + return; + } + + i = findparam(s, u->faction->locale); + if (i == P_PERSON) { + if (!(u->race->ec_flags & GIVEPERSON)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_noregroup", "race", u->race)); + return; + } + give_men(n, u, u2, ord); + return; + } + + if (u2!=NULL) { + if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_nogive", "race", u->race)); + return; + } + if (!(u2->race->ec_flags & GETITEM)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_notake", "race", u2->race)); + return; + } + } + + itype = finditemtype(s, u->faction->locale); + if (itype!=NULL) { + if (check_give(u, u2, itype, 0)) { + give_item(n, itype, u, u2, ord); + } else { + feedback_give_not_allowed(u, ord); + } + return; + } + cmistake(u, ord, 123, MSG_COMMERCE); +} + +static int +forget_cmd(unit * u, order * ord) +{ + skill_t sk; + const char *s; + + if (is_cursed(u->attribs, C_SLAVE, 0)) { + /* charmed units shouldn't be losing their skills */ + return 0; + } + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + if ((sk = findskill(s, u->faction->locale)) != NOSKILL) { + ADDMSG(&u->faction->msgs, + msg_message("forget", "unit skill", u, sk)); + set_level(u, sk, 0); + } + return 0; +} + +void +add_spende(faction * f1, faction * f2, int amount, region * r) +{ + donation *sp; + + sp = r->donations; + + while (sp) { + if (sp->f1 == f1 && sp->f2 == f2) { + sp->amount += amount; + return; + } + sp = sp->next; + } + + sp = calloc(1, sizeof(donation)); + sp->f1 = f1; + sp->f2 = f2; + sp->amount = amount; + sp->next = r->donations; + r->donations = sp; +} + +static boolean +maintain(building * b, boolean first) +/* first==false -> take money from wherever you can */ +{ + int c; + region * r = b->region; + boolean paid = true, work = first; + unit * u; + if (fval(b, BLD_MAINTAINED) || b->type==NULL || b->type->maintenance==NULL || is_cursed(b->attribs, C_NOCOST, 0)) { + fset(b, BLD_MAINTAINED); + fset(b, BLD_WORKING); + return true; + } + if (fval(b, BLD_DONTPAY)) { + return false; + } + u = building_owner(b); + if (u==NULL) return false; + for (c=0;b->type->maintenance[c].number;++c) { + const maintenance * m = b->type->maintenance+c; + int need = m->number; + + if (fval(m, MTF_VARIABLE)) need = need * b->size; + if (u) { + /* first ist im ersten versuch true, im zweiten aber false! Das + * bedeutet, das in der Runde in die Region geschafften Resourcen + * nicht genutzt werden können, weil die reserviert sind! */ + if (!first) need -= get_pooled(u, m->rtype, GET_ALL, need); + else need -= get_pooled(u, m->rtype, GET_DEFAULT, need); + if (!first && need > 0) { + unit * ua; + for (ua=r->units;ua;ua=ua->next) freset(ua->faction, FFL_SELECT); + fset(u->faction, FFL_SELECT); /* hat schon */ + for (ua=r->units;ua;ua=ua->next) { + if (!fval(ua->faction, FFL_SELECT) && (ua->faction == u->faction || alliedunit(ua, u->faction, HELP_MONEY))) { + need -= get_pooled(ua, m->rtype, GET_ALL, need); + fset(ua->faction, FFL_SELECT); + if (need<=0) break; + } + } + } + if (need > 0) { + if (!fval(m, MTF_VITAL)) work = false; + else { + paid = false; + break; + } + } + } + } + if (paid && c>0) { + /* TODO: wieviel von was wurde bezahlt */ + if (first) { + ADDMSG(&u->faction->msgs, msg_message("maintenance", "unit building", u, b)); + } else { + ADDMSG(&u->faction->msgs, msg_message("maintenance_late", "building", b)); + } + fset(b, BLD_MAINTAINED); + if (work) { + fset(b, BLD_WORKING); + } + for (c=0;b->type->maintenance[c].number;++c) { + const maintenance * m = b->type->maintenance+c; + int cost = m->number; + + if (!fval(m, MTF_VITAL) && !work) continue; + if (fval(m, MTF_VARIABLE)) cost = cost * b->size; + + if (!first) cost -= use_pooled(u, m->rtype, GET_ALL, cost); + else cost -= use_pooled(u, m->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, cost); + if (!first && cost > 0) { + unit * ua; + for (ua=r->units;ua;ua=ua->next) freset(ua->faction, FFL_SELECT); + fset(u->faction, FFL_SELECT); /* hat schon */ + for (ua=r->units;ua;ua=ua->next) { + if (!fval(ua->faction, FFL_SELECT) && alliedunit(ua, u->faction, HELP_MONEY)) { + int give = use_pooled(ua, m->rtype, GET_ALL, cost); + if (!give) continue; + cost -= give; + fset(ua->faction, FFL_SELECT); + if (m->rtype==r_silver) add_spende(ua->faction, u->faction, give, r); + if (cost<=0) break; + } + } + } + assert(cost==0); + } + } else { + ADDMSG(&u->faction->msgs, + msg_message("maintenancefail", "unit building", u, b)); + return false; + } + return true; +} + +#ifdef COLLAPSE_CHANCE +static void +gebaeude_stuerzt_ein(region * r, building * b) +{ + unit *u; + int n, i; + int opfer = 0; + int road = 0; + struct message * msg; + + for (u = r->units; u; u = u->next) { + if (u->building == b) { + int loss = 0; + + fset(u->faction, FFL_MARK); + freset(u, UFL_OWNER); + leave(r,u); + n = u->number; +#ifdef COLLAPSE_SURVIVAL + for (i = 0; i < n; i++) { + if (rng_double() >= COLLAPSE_SURVIVAL) { + ++loss; + } + } +#endif + scale_number(u, u->number - loss); + opfer += loss; + } + } + + msg = msg_message("buildingcrash", "region building opfer road", r, b, opfer, road); + add_message(&r->msgs, msg); + for (u=r->units; u; u=u->next) { + faction * f = u->faction; + if (fval(f, FFL_MARK)) { + freset(u->faction, FFL_MARK); + add_message(&f->msgs, msg); + } + } + msg_release(msg); + remove_building(&r->buildings, b); +} +#endif + +void +maintain_buildings(region * r, boolean crash) +{ + building **bp = &r->buildings; + while (*bp) { + building * b = *bp; + boolean maintained = maintain(b, !crash); + + /* the second time, send a message */ + if (crash) { +#ifdef COLLAPSE_CHANCE + if (!maintained && (rng_double() < COLLAPSE_CHANCE)) { + gebaeude_stuerzt_ein(r, b); + continue; + } +#endif + if (!fval(b, BLD_WORKING)) { + unit * u = building_owner(b); + const char * msgtype = maintained?"maintenance_nowork":"maintenance_none"; + struct message * msg = msg_message(msgtype, "building", b); + + if (u) { + add_message(&u->faction->msgs, msg); + r_addmessage(r, u->faction, msg); + } else { + add_message(&r->msgs, msg); + } + msg_release(msg); + } + } + bp=&b->next; + } +} + +static int +recruit_archetype(unit * u, order * ord) +{ + boolean merge = (u->number>0); + int want; + const char * s; + + if (rules_recruit<0) recruit_init(); + + init_tokens(ord); + skip_token(); + want = getuint(); + s = getstrtoken(); + if (want>0 && s && s[0]) { + int n = want; + const archetype * arch = find_archetype(s, u->faction->locale); + attrib * a = NULL; + + if ((rules_recruit&RECRUIT_MERGE)==0 && merge) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_must_be_new", "")); + /* TODO: error message */ + return 0; + } + + if (arch==NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unknown_archetype", "name", s)); + /* TODO: error message */ + return 0; + } + if (arch->rules) { + /* Simple allow/deny style restrictions for archetypes (let only humans + * recruit gamedesigners, etc). These need to be more powerful to be + * useful, and the current way they are implemented is not, but the + * general idea strikes me as good. Also, feedback should be configurable + * for each failed rule. + */ + int k; + for (k=0;arch->rules[k].property;++k) { + boolean match = false; + if (arch->rules[k].value[0]=='*') match = true; + else if (strcmp(arch->rules[k].property, "race")==0) { + const race * rc = rc_find(arch->rules[k].value); + assert(rc); + if (rc==u->race) match = true; + } else if (strcmp(arch->rules[k].property, "building")==0) { + const building_type * btype = bt_find(arch->rules[k].value); + assert(btype); + if (u->building && u->building->type==btype) match = true; + } + if (match) { + if (arch->rules[k].allow) break; + else { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "recruit_rule_fail", + "property value", arch->rules[k].property, arch->rules[k].value)); + /* TODO: error message */ + return 0; + } + } + } + } + if (arch->btype) { + if (u->building==NULL || u->building->type!=arch->btype) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_must_be_in_building", "type", arch->btype)); + /* TODO: error message */ + return 0; + } + if (arch->size) { + int maxsize = u->building->size; + attrib * a = a_find(u->building->attribs, &at_recruit); + if (a!=NULL) { + maxsize -= a->data.i; + } + n = MIN(maxsize/arch->size, n); + if (n<=0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "recruit_capacity_exhausted", "building", u->building)); + /* TODO: error message */ + return 0; + } + } + } + + n = build(u, arch->ctype, 0, n); + if (n>0) { + unit * u2; + if (merge) { + u2 = create_unit(u->region, u->faction, 0, u->race, 0, 0, u); + } else { + u2 = u; + } + if (arch->exec) { + n = arch->exec(u2, arch, n); + } + else { + set_number(u2, n); + equip_unit(u2, arch->equip); + u2->hp = n * unit_max_hp(u2); + if (arch->size) { + if (a==NULL) a = a_add(&u->building->attribs, a_new(&at_recruit)); + a->data.i += n*arch->size; + } + } + ADDMSG(&u->faction->msgs, msg_message("recruit_archetype", + "unit amount archetype", u, n, arch->name[n==1])); + if (u!=u2 && u->race==u2->race) { + transfermen(u2, u, u2->number); + } + return n; + } else switch(n) { + case ENOMATERIALS: + ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, arch->ctype, want)); + break; + case ELOWSKILL: + case ENEEDSKILL: + /* no skill, or not enough skill points to build */ + cmistake(u, ord, 50, MSG_PRODUCE); + break; + case EBUILDINGREQ: + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "building_needed", "building", arch->ctype->btype->_name)); + break; + default: + assert(!"unhandled return value from build() in recruit_archetype"); + } + return 0; + } + return -1; +} + +int recruit_archetypes(void) +{ + if (rules_recruit<0) recruit_init(); + return (rules_recruit&RECRUIT_ARCHETYPES)!=0; +} + +void +economics(region *r) +{ + unit *u; + request *recruitorders = NULL; + + /* Geben vor Selbstmord (doquit)! Hier alle unmittelbaren Befehle. + * Rekrutieren vor allen Einnahmequellen. Bewachen JA vor Steuern + * eintreiben. */ + + for (u = r->units; u; u = u->next) { + order * ord; + boolean destroyed = false; + if (u->number>0) { + for (ord = u->orders; ord; ord = ord->next) { + switch (get_keyword(ord)) { + case K_DESTROY: + if (!destroyed) { + if (destroy_cmd(u, ord)!=0) ord = NULL; + destroyed = true; + } + break; + + case K_GIVE: + case K_LIEFERE: + give_cmd(u, ord); + break; + + case K_FORGET: + forget_cmd(u, ord); + break; + + } + if (u->orders==NULL) break; + } + } + } + /* RECRUIT orders */ + + if (rules_recruit<0) recruit_init(); + for (u = r->units; u; u = u->next) { + order * ord; + + if ((rules_recruit&RECRUIT_MERGE) || u->number==0) { + for (ord = u->orders; ord; ord = ord->next) { + if (get_keyword(ord) == K_RECRUIT) { + if (rules_recruit&RECRUIT_ARCHETYPES) { + if (recruit_archetype(u, ord)>=0) { + continue; + } + } + if (rules_recruit&RECRUIT_CLASSIC) { + recruit(u, ord, &recruitorders); + } + break; + } + } + } + } + + if (recruitorders) expandrecruit(r, recruitorders); + remove_empty_units_in_region(r); +} +/* ------------------------------------------------------------- */ + + +static void +manufacture(unit * u, const item_type * itype, int want) +{ + int n; + int skill; + int minskill = itype->construction->minskill; + skill_t sk = itype->construction->skill; + + skill = effskill(u, sk); + skill = skillmod(itype->rtype->attribs, u, u->region, sk, skill, SMF_PRODUCTION); + + if (skill < 0) { + /* an error occured */ + int err = -skill; + cmistake(u, u->thisorder, err, MSG_PRODUCE); + return; + } + + if (want==0) { + want = maxbuild(u, itype->construction); + } + n = build(u, itype->construction, 0, want); + switch (n) { + case ENEEDSKILL: + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "skill_needed", "skill", sk)); + return; + case EBUILDINGREQ: + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "building_needed", "building", itype->construction->btype->_name)); + return; + case ELOWSKILL: + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "manufacture_skills", "skill minskill product", + sk, minskill, itype->rtype, 1)); + return; + case ENOMATERIALS: + ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, itype->construction, want)); + return; + } + if (n>0) { + i_change(&u->items, itype, n); + if (want==INT_MAX) want = n; + ADDMSG(&u->faction->msgs, msg_message("manufacture", + "unit region amount wanted resource", u, u->region, n, want, itype->rtype)); + } else { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_cannotmake", "")); + } +} + +typedef struct allocation { + struct allocation * next; + int want, get; + double save; + unsigned int flags; + unit * unit; +} allocation; +#define new_allocation() calloc(sizeof(allocation), 1) +#define free_allocation(a) free(a) + +typedef struct allocation_list { + struct allocation_list * next; + allocation * data; + const resource_type * type; +} allocation_list; + +static allocation_list * allocations; + +static boolean +can_guard(const unit * guard, const unit * u) +{ + if (fval(guard, UFL_ISNEW)) return false; + if (guard->number<=0 || !cansee(guard->faction, guard->region, u, 0)) return false; + if (besieged(guard) || !(fval(guard->race, RCF_UNARMEDGUARD) || armedmen(guard, true))) return false; + + return !alliedunit(guard, u->faction, HELP_GUARD); +} + +enum { + AFL_DONE = 1<<0, + AFL_LOWSKILL = 1<<1 +}; + +static void +allocate_resource(unit * u, const resource_type * rtype, int want) +{ + const item_type * itype = resource2item(rtype); + region * r = u->region; + int busy = u->number; + int dm = 0; + allocation_list * alist; + allocation * al; + attrib * a = a_find(rtype->attribs, &at_resourcelimit); + resource_limit * rdata = (resource_limit*)a->data.v; + int amount, skill; + + /* momentan kann man keine ressourcen abbauen, wenn man dafür + * Materialverbrauch hat: */ + assert(itype!=NULL && (itype->construction==NULL || itype->construction->materials==NULL)); + assert(rdata!=NULL); + + if (rdata->limit!=NULL) { + int avail = rdata->limit(r, rtype); + if (avail<=0) { + cmistake(u, u->thisorder, 121, MSG_PRODUCE); + return; + } + } + + if (besieged(u)) { + cmistake(u, u->thisorder, 60, MSG_PRODUCE); + return; + } + + if (rdata->modifiers) { + resource_mod * mod = rdata->modifiers; + for (;mod->flags!=0;++mod) { + if (mod->flags & RMF_REQUIREDBUILDING) { + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + if (mod->btype && mod->btype!=btype) { + cmistake(u, u->thisorder, 104, MSG_PRODUCE); + return; + } + } + } + } + + if (rdata->guard!=0) { + unit * u2; + for (u2 = r->units; u2; u2 = u2->next) { + if (is_guard(u2, rdata->guard)!=0 && can_guard(u2, u)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "region_guarded", "guard", u2)); + return; + } + } + } + + /* Bergwächter können Abbau von Eisen/Laen durch Bewachen verhindern. + * Als magische Wesen 'sehen' Bergwächter alles und werden durch + * Belagerung nicht aufgehalten. (Ansonsten wie oben bei Elfen anpassen). + */ + if (itype == olditemtype[I_IRON] || itype == olditemtype[I_LAEN]) { + unit * u2; + for (u2 = r->units; u2; u2 = u2->next ) { + if (is_guard(u, GUARD_MINING) + && !fval(u2, UFL_ISNEW) + && u2->number + && !alliedunit(u2, u->faction, HELP_GUARD)) + { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "region_guarded", "guard", u2)); + return; + } + } + } + + assert(itype->construction->skill!=0 || "limited resource needs a required skill for making it"); + skill = eff_skill(u, itype->construction->skill, u->region); + if (skill == 0) { + skill_t sk = itype->construction->skill; + add_message(&u->faction->msgs, + msg_feedback(u, u->thisorder, "skill_needed", "skill", sk)); + return; + } + if (skill < itype->construction->minskill) { + skill_t sk = itype->construction->skill; + add_message(&u->faction->msgs, + msg_feedback(u, u->thisorder, "manufacture_skills", "skill minskill product", + sk, itype->construction->minskill, itype->rtype)); + return; + } else { + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + + if (rdata->modifiers) { + resource_mod * mod = rdata->modifiers; + for (;mod->flags!=0;++mod) { + if (mod->flags & RMF_SKILL) { + if (mod->btype==NULL || mod->btype==btype) { + if (mod->race==NULL || mod->race==u->race) { + skill += mod->value.i; + } + } + } + } + } + } + amount = skill * u->number; + /* nun ist amount die Gesamtproduktion der Einheit (in punkten) */ + + /* mit Flinkfingerring verzehnfacht sich die Produktion */ + amount += skill * MIN(u->number, get_item(u, I_RING_OF_NIMBLEFINGER)) * (roqf_factor()-1); + + /* Schaffenstrunk: */ + if ((dm = get_effect(u, oldpotiontype[P_DOMORE])) != 0) { + dm = MIN(dm, u->number); + change_effect(u, oldpotiontype[P_DOMORE], -dm); + amount += dm * skill; /* dm Personen produzieren doppelt */ + } + + amount /= itype->construction->minskill; + + /* Limitierung durch Parameter m. */ + if (want > 0 && want < amount) amount = want; + + busy = (amount + skill - 1) / skill; /* wieviel leute tun etwas? */ + + alist = allocations; + while (alist && alist->type!=rtype) alist = alist->next; + if (!alist) { + alist = calloc(sizeof(struct allocation_list), 1); + alist->next = allocations; + alist->type = rtype; + allocations = alist; + } + al = new_allocation(); + al->want = amount; + al->save = 1.0; + al->next = alist->data; + al->unit = u; + alist->data = al; + + if (rdata->modifiers) { + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + + resource_mod * mod = rdata->modifiers; + for (;mod->flags!=0;++mod) { + if (mod->flags & RMF_SAVEMATERIAL) { + if (mod->btype==NULL || mod->btype==btype) { + if (mod->race==NULL || mod->race==u->race) { + al->save *= mod->value.f; + } + } + } + } + } +} + +static int +required(int want, double save) +{ + int norders = (int)(want * save); + if (norders < want*save) ++norders; + return norders; +} + +static void +leveled_allocation(const resource_type * rtype, region * r, allocation * alist) +{ + const item_type * itype = resource2item(rtype); + rawmaterial * rm = rm_get(r, rtype); + int need; + boolean first = true; + + if (rm!=NULL) { + do { + int avail = rm->amount; + int norders = 0; + allocation * al; + + if(avail <= 0) { + for (al=alist;al;al=al->next) { + al->get = 0; + } + break; + } + + assert(avail>0); + + for (al=alist;al;al=al->next) if (!fval(al, AFL_DONE)) { + int req = required(al->want-al->get, al->save); + assert(al->get<=al->want && al->get >= 0); + if (eff_skill(al->unit, itype->construction->skill, r) + >= rm->level+itype->construction->minskill-1) { + if (req) { + norders += req; + } else { + fset(al, AFL_DONE); + } + } else { + fset(al, AFL_DONE); + if (first) fset(al, AFL_LOWSKILL); + } + } + need = norders; + + avail = MIN(avail, norders); + if (need>0) { + int use = 0; + for (al=alist;al;al=al->next) if (!fval(al, AFL_DONE)) { + if (avail > 0) { + int want = required(al->want-al->get, al->save); + int x = avail*want/norders; + /* Wenn Rest, dann würfeln, ob ich was bekomme: */ + if (rng_int() % norders < (avail*want) % norders) + ++x; + avail -= x; + use += x; + norders -= want; + need -= x; + al->get = MIN(al->want, al->get+(int)(x/al->save)); + } + } + if (use) { + assert(use<=rm->amount); + rm->type->use(rm, r, use); + } + assert(avail==0 || norders==0); + } + first = false; + } while (need>0); + } +} + +static void +attrib_allocation(const resource_type * rtype, region * r, allocation * alist) +{ + allocation * al; + int norders = 0; + attrib * a = a_find(rtype->attribs, &at_resourcelimit); + resource_limit * rdata = (resource_limit*)a->data.v; + int avail = rdata->value; + + for (al=alist;al;al=al->next) { + norders += required(al->want, al->save); + } + + if (rdata->limit) { + avail = rdata->limit(r, rtype); + if (avail < 0) avail = 0; + } + + avail = MIN(avail, norders); + for (al=alist;al;al=al->next) { + if (avail > 0) { + int want = required(al->want, al->save); + int x = avail*want/norders; + /* Wenn Rest, dann würfeln, ob ich was bekomme: */ + if (rng_int() % norders < (avail*want) % norders) + ++x; + avail -= x; + norders -= want; + al->get = MIN(al->want, (int)(x/al->save)); + if (rdata->produce) { + int use = required(al->get, al->save); + if (use) rdata->produce(r, rtype, use); + } + } + } + assert(avail==0 || norders==0); +} + +typedef void (*allocate_function)(const resource_type *, struct region *, struct allocation *); + +static allocate_function +get_allocator(const struct resource_type * rtype) +{ + attrib * a = a_find(rtype->attribs, &at_resourcelimit); + + if (a!=NULL) { + resource_limit * rdata = (resource_limit*)a->data.v; + if (rdata->value>0 || rdata->limit!=NULL) { + return attrib_allocation; + } + return leveled_allocation; + } + return NULL; +} + +void +split_allocations(region * r) +{ + allocation_list ** p_alist=&allocations; + freset(r, RF_SELECT); + while (*p_alist) { + allocation_list * alist = *p_alist; + const resource_type * rtype = alist->type; + allocate_function alloc = get_allocator(rtype); + const item_type * itype = resource2item(rtype); + allocation ** p_al = &alist->data; + + freset(r, RF_SELECT); + alloc(rtype, r, alist->data); + + while (*p_al) { + allocation * al = *p_al; + if (al->get) { + assert(itype || !"not implemented for non-items"); + i_change(&al->unit->items, itype, al->get); + produceexp(al->unit, itype->construction->skill, al->unit->number); + fset(r, RF_SELECT); + } + if (al->want==INT_MAX) al->want = al->get; + if (fval(al, AFL_LOWSKILL)) { + ADDMSG(&al->unit->faction->msgs, + msg_message("produce_lowskill", "unit region resource", + al->unit, al->unit->region, rtype)); + } else { + ADDMSG(&al->unit->faction->msgs, msg_message("produce", + "unit region amount wanted resource", + al->unit, al->unit->region, al->get, al->want, rtype)); + } + *p_al=al->next; + free_allocation(al); + } + *p_alist=alist->next; + free(alist); + } + allocations = NULL; +} + +static void +create_potion(unit * u, const potion_type * ptype, int want) +{ + int built; + + if (want==0) { + want = maxbuild(u, ptype->itype->construction); + } + built = build(u, ptype->itype->construction, 0, want); + switch (built) { + case ELOWSKILL: + case ENEEDSKILL: + /* no skill, or not enough skill points to build */ + cmistake(u, u->thisorder, 50, MSG_PRODUCE); + break; + case EBUILDINGREQ: + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "building_needed", "building", ptype->itype->construction->btype->_name)); + break; + case ECOMPLETE: + assert(0); + break; + case ENOMATERIALS: + /* something missing from the list of materials */ + ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, ptype->itype->construction, want)); + return; + break; + default: + i_change(&u->items, ptype->itype, built); + if (want==INT_MAX) want = built; + ADDMSG(&u->faction->msgs, msg_message("manufacture", + "unit region amount wanted resource", u, u->region, built, want, ptype->itype->rtype)); + break; + } +} + +static void +create_item(unit * u, const item_type * itype, int want) +{ + if (itype->construction && fval(itype->rtype, RTF_LIMITED)) { +#if GUARD_DISABLES_PRODUCTION == 1 + if (is_guarded(u->region, u, GUARD_PRODUCE)) { + cmistake(u, u->thisorder, 70, MSG_EVENT); + return; + } +#endif + allocate_resource(u, itype->rtype, want); + } else { + const potion_type * ptype = resource2potion(itype->rtype); + if (ptype!=NULL) create_potion(u, ptype, want); + else if (itype->construction && itype->construction->materials) manufacture(u, itype, want); + else { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_cannotmake", "")); + } + } +} + +int +make_cmd(unit * u, struct order * ord) +{ + region * r = u->region; + const building_type * btype; + const ship_type * stype; + param_t p; + int m; + const item_type * itype; + const char *s; + const struct locale * lang = u->faction->locale; + char ibuf[16]; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + m = atoi((const char *)s); + sprintf(ibuf, "%d", m); + if (!strcmp(ibuf, (const char *)s)) { + /* first came a want-paramter */ + s = getstrtoken(); + } else { + m = INT_MAX; + } + + p = findparam(s, u->faction->locale); + + /* MACHE TEMP kann hier schon gar nicht auftauchen, weil diese nicht in + * thisorder abgespeichert werden - und auf den ist getstrtoken() beim + * aufruf von make geeicht */ + + if (p == P_ROAD) { + plane * pl = rplane(r); + if (pl && fval(pl, PFL_NOBUILD)) { + cmistake(u, ord, 275, MSG_PRODUCE); + } else { + direction_t d = finddirection(getstrtoken(), u->faction->locale); + if (d!=NODIRECTION) { + build_road(r, u, m, d); + } else { + /* Die Richtung wurde nicht erkannt */ + cmistake(u, ord, 71, MSG_PRODUCE); + } + } + return 0; + } else if (p == P_SHIP) { + plane * pl = rplane(r); + if (pl && fval(pl, PFL_NOBUILD)) { + cmistake(u, ord, 276, MSG_PRODUCE); + } else { + continue_ship(r, u, m); + } + return 0; + } else if (p == P_HERBS) { + herbsearch(r, u, m); + return 0; + } + + /* since the string can match several objects, like in 'academy' and + * 'academy of arts', we need to figure out what the player meant. + * This is not 100% safe. + */ + stype = findshiptype(s, lang); + btype = findbuildingtype(s, lang); + itype = finditemtype(s, lang); + + if (itype!=NULL && (btype!=NULL || stype!=NULL)) { + if (itype->construction==NULL) { + /* if the item cannot be made, we probably didn't mean to make it */ + itype = NULL; + } else if (stype!=NULL) { + const char * sname = LOC(lang, stype->name[0]); + const char * iname = LOC(lang, resourcename(itype->rtype, 0)); + if (strlen(iname)_name); + const char * iname = LOC(lang, resourcename(itype->rtype, 0)); + if (strlen(iname)_name); + const char * sname = LOC(lang, stype->name[0]); + if (strlen(sname)faction->msgs, msg_feedback(u, ord, "error_cannotmake", "")); + } + + return 0; +} +/* ------------------------------------------------------------- */ + +static void +free_luxuries(struct attrib * a) +{ + item * itm = (item*)a->data.v; + a->data.v = NULL; + i_freeall(&itm); +} + +const attrib_type at_luxuries = { + "luxuries", NULL, free_luxuries, NULL, NULL, NULL +}; + +static void +expandbuying(region * r, request * buyorders) +{ + int max_products; + unit *u; + static struct trade { + const luxury_type * type; + int number; + int multi; + } *trades, *trade; + static int ntrades=0; + int i, j; + const luxury_type * ltype; + + if (ntrades==0) { + for (ltype=luxurytypes;ltype;ltype=ltype->next) + ++ntrades; + trades = gc_add(calloc(sizeof(struct trade), ntrades)); + for (i=0, ltype=luxurytypes;i!=ntrades;++i, ltype=ltype->next) + trades[i].type = ltype; + } + for (i=0;i!=ntrades;++i) { + trades[i].number = 0; + trades[i].multi = 1; + } + + if (!buyorders) return; + + /* Initialisation. multiplier ist der Multiplikator auf den + * Verkaufspreis. Für max_products Produkte kauft man das Produkt zum + * einfachen Verkaufspreis, danach erhöht sich der Multiplikator um 1. + * counter ist ein Zähler, der die gekauften Produkte zählt. money + * wird für die debug message gebraucht. */ + + max_products = rpeasants(r) / TRADE_FRACTION; + + /* Kauf - auch so programmiert, daß er leicht erweiterbar auf mehrere + * Güter pro Monat ist. j sind die Befehle, i der Index des + * gehandelten Produktes. */ + if (max_products>0) { + expandorders(r, buyorders); + if (!norders) return; + + for (j = 0; j != norders; j++) { + int price, multi; + ltype = oa[j].type.ltype; + trade = trades; + while (trade->type!=ltype) ++trade; + multi = trade->multi; + price = ltype->price * multi; + + if (get_pooled(oa[j].unit, oldresourcetype[R_SILVER], GET_DEFAULT, price) >= price) { + unit * u = oa[j].unit; + item * items; + + /* litems zählt die Güter, die verkauft wurden, u->n das Geld, das + * verdient wurde. Dies muß gemacht werden, weil der Preis ständig sinkt, + * man sich also das verdiente Geld und die verkauften Produkte separat + * merken muß. */ + attrib * a = a_find(u->attribs, &at_luxuries); + if (a==NULL) a = a_add(&u->attribs, a_new(&at_luxuries)); + + items = a->data.v; + i_change(&items, ltype->itype, 1); + a->data.v = items; + i_change(&oa[j].unit->items, ltype->itype, 1); + use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, price); + if (u->n < 0) + u->n = 0; + u->n += price; + + rsetmoney(r, rmoney(r) + price); + + /* Falls mehr als max_products Bauern ein Produkt verkauft haben, steigt + * der Preis Multiplikator für das Produkt um den Faktor 1. Der Zähler + * wird wieder auf 0 gesetzt. */ + if (++trade->number == max_products) { + trade->number = 0; + ++trade->multi; + } + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + } + } + free(oa); + + /* Ausgabe an Einheiten */ + + for (u = r->units; u; u = u->next) { + attrib * a = a_find(u->attribs, &at_luxuries); + item * itm; + if (a==NULL) continue; + ADDMSG(&u->faction->msgs, msg_message("buy", "unit money", u, u->n)); + for (itm=(item*)a->data.v; itm; itm=itm->next) { + if (itm->number) { + ADDMSG(&u->faction->msgs, msg_message("buyamount", + "unit amount resource", u, itm->number, itm->type->rtype)); + } + } + a_remove(&u->attribs, a); + } + } +} + +attrib_type at_trades = { + "trades", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +static void +buy(unit * u, request ** buyorders, struct order * ord) +{ + region * r = u->region; + int n, k; + request *o; + attrib * a; + const item_type * itype = NULL; + const luxury_type * ltype = NULL; + if (u->ship && is_guarded(r, u, GUARD_CREWS)) { + cmistake(u, ord, 69, MSG_INCOME); + return; + } + if (u->ship && is_guarded(r, u, GUARD_CREWS)) { + cmistake(u, ord, 69, MSG_INCOME); + return; + } + /* Im Augenblick kann man nur 1 Produkt kaufen. expandbuying ist aber + * schon dafür ausgerüstet, mehrere Produkte zu kaufen. */ + + init_tokens(ord); + skip_token(); + n = getuint(); + if (!n) { + cmistake(u, ord, 26, MSG_COMMERCE); + return; + } + if (besieged(u)) { + /* Belagerte Einheiten können nichts kaufen. */ + cmistake(u, ord, 60, MSG_COMMERCE); + return; + } + + if (u->race == new_race[RC_INSECT]) { + /* entweder man ist insekt, oder... */ + if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT) && !rbuildings(r)) { + cmistake(u, ord, 119, MSG_COMMERCE); + return; + } + } else { + /* ...oder in der Region muß es eine Burg geben. */ + building * b; + static const struct building_type * bt_castle; + if (!bt_castle) bt_castle = bt_find("castle"); + for (b=r->buildings;b;b=b->next) { + if (b->type==bt_castle && b->size>=2) break; + } + if (b==NULL) { + cmistake(u, ord, 119, MSG_COMMERCE); + return; + } + } + + /* Ein Händler kann nur 10 Güter pro Talentpunkt handeln. */ + k = u->number * 10 * eff_skill(u, SK_TRADE, r); + + /* hat der Händler bereits gehandelt, muss die Menge der bereits + * verkauften/gekauften Güter abgezogen werden */ + a = a_find(u->attribs, &at_trades); + if (!a) { + a = a_add(&u->attribs, a_new(&at_trades)); + } else { + k -= a->data.i; + } + + n = MIN(n, k); + + if (!n) { + cmistake(u, ord, 102, MSG_COMMERCE); + return; + } + + assert(n>=0); + /* die Menge der verkauften Güter merken */ + a->data.i += n; + + itype = finditemtype(getstrtoken(), u->faction->locale); + if (itype!=NULL) { + ltype = resource2luxury(itype->rtype); + if (ltype==NULL) { + cmistake(u, ord, 124, MSG_COMMERCE); + return; + } + } + if (r_demand(r, ltype)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "luxury_notsold", "")); + return; + } + o = (request *) calloc(1, sizeof(request)); + o->type.ltype = ltype; /* sollte immer gleich sein */ + + o->unit = u; + o->qty = n; + addlist(buyorders, o); +} +/* ------------------------------------------------------------- */ + +/* Steuersätze in % bei Burggröße */ +static int tax_per_size[7] = +{0, 6, 12, 18, 24, 30, 36}; + +static void +expandselling(region * r, request * sellorders, int limit) +{ + int money, price, j, max_products; + /* int m, n = 0; */ + int maxsize = 0, maxeffsize = 0; + int taxcollected = 0; + int hafencollected = 0; + unit *maxowner = (unit *) NULL; + building *maxb = (building *) NULL; + building *b; + unit *u; + unit *hafenowner; + static int *counter; + static int ncounter = 0; + + if (ncounter==0) { + const luxury_type * ltype; + for (ltype=luxurytypes;ltype;ltype=ltype->next) ++ncounter; + counter=(int*)gc_add(calloc(sizeof(int), ncounter)); + } else { + memset(counter, 0, sizeof(int)*ncounter); + } + + if (!sellorders) { /* NEIN, denn Insekten können in || !r->buildings) */ + return; /* Sümpfen und Wüsten auch so handeln */ + } + /* Stelle Eigentümer der größten Burg fest. Bekommt Steuern aus jedem + * Verkauf. Wenn zwei Burgen gleicher Größe bekommt gar keiner etwas. */ + + for (b = rbuildings(r); b; b = b->next) { + if (b->size > maxsize && building_owner(b) != NULL + && b->type == bt_find("castle")) { + maxb = b; + maxsize = b->size; + maxowner = building_owner(b); + } else if (b->size == maxsize && b->type == bt_find("castle")) { + maxb = (building *) NULL; + maxowner = (unit *) NULL; + } + } + + hafenowner = owner_buildingtyp(r, bt_find("harbour")); + + if (maxb != (building *) NULL && maxowner != (unit *) NULL) { + maxeffsize = buildingeffsize(maxb, false); + if (maxeffsize == 0) { + maxb = (building *) NULL; + maxowner = (unit *) NULL; + } + } + /* Die Region muss genug Geld haben, um die Produkte kaufen zu können. */ + + money = rmoney(r); + + /* max_products sind 1/100 der Bevölkerung, falls soviele Produkte + * verkauft werden - counter[] - sinkt die Nachfrage um 1 Punkt. + * multiplier speichert r->demand für die debug message ab. */ + + max_products = rpeasants(r) / TRADE_FRACTION; + if (max_products <= 0) return; + + if (r->terrain == newterrain(T_DESERT) && buildingtype_exists(r, bt_find("caravan"), true)) { + max_products = rpeasants(r) * 2 / TRADE_FRACTION; + } + /* Verkauf: so programmiert, dass er leicht auf mehrere Gueter pro + * Runde erweitert werden kann. */ + + expandorders(r, sellorders); + if (!norders) return; + + for (j = 0; j != norders; j++) { + static const luxury_type * search=NULL; + const luxury_type * ltype = oa[j].type.ltype; + int multi = r_demand(r, ltype); + static int i=-1; + int use = 0; + if (search!=ltype) { + i=0; + for (search=luxurytypes;search!=ltype;search=search->next) ++i; + } + if (counter[i]>=limit) continue; + if (counter[i]+1 > max_products && multi > 1) --multi; + price = ltype->price * multi; + + if (money >= price) { + int abgezogenhafen = 0; + int abgezogensteuer = 0; + unit * u = oa[j].unit; + item * itm; + attrib * a = a_find(u->attribs, &at_luxuries); + if (a==NULL) a = a_add(&u->attribs, a_new(&at_luxuries)); + itm = (item *)a->data.v; + i_change(&itm, ltype->itype, 1); + a->data.v = itm; + ++use; + if (u->n < 0) + u->n = 0; + + if (hafenowner != NULL) { + if (hafenowner->faction != u->faction) { + abgezogenhafen = price / 10; + hafencollected += abgezogenhafen; + price -= abgezogenhafen; + money -= abgezogenhafen; + } + } + if (maxb != NULL) { + if (maxowner->faction != u->faction) { + abgezogensteuer = price * tax_per_size[maxeffsize] / 100; + taxcollected += abgezogensteuer; + price -= abgezogensteuer; + money -= abgezogensteuer; + } + } + u->n += price; + change_money(u, price); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + + /* r->money -= price; --- dies wird eben nicht ausgeführt, denn die + * Produkte können auch als Steuern eingetrieben werden. In der Region + * wurden Silberstücke gegen Luxusgüter des selben Wertes eingetauscht! + * Falls mehr als max_products Kunden ein Produkt gekauft haben, sinkt + * die Nachfrage für das Produkt um 1. Der Zähler wird wieder auf 0 + * gesetzt. */ + + if (++counter[i] > max_products) { + int d = r_demand(r, ltype); + if (d > 1) { + r_setdemand(r, ltype, d-1); + } + counter[i] = 0; + } + } + if (use>0) { +#ifdef NDEBUG + use_pooled(oa[j].unit, ltype->itype->rtype, GET_DEFAULT, use); +#else + /* int i = */ use_pooled(oa[j].unit, ltype->itype->rtype, GET_DEFAULT, use); + /* assert(i==use); */ +#endif + } + } + free(oa); + + /* Steuern. Hier werden die Steuern dem Besitzer der größten Burg gegeben. */ + + if (maxowner) { + if (taxcollected > 0) { + change_money(maxowner, (int) taxcollected); + add_income(maxowner, IC_TRADETAX, taxcollected, taxcollected); + /* TODO: Meldung + * "%s verdient %d Silber durch den Handel in %s.", + * unitname(maxowner), (int) taxcollected, regionname(r)); */ + } + } + if (hafenowner) { + if (hafencollected > 0) { + change_money(hafenowner, (int) hafencollected); + add_income(hafenowner, IC_TRADETAX, hafencollected, hafencollected); + } + } + /* Berichte an die Einheiten */ + + for (u = r->units; u; u = u->next) { + + attrib * a = a_find(u->attribs, &at_luxuries); + item * itm; + if (a==NULL) continue; + for (itm=(item*)a->data.v; itm; itm=itm->next) { + if (itm->number) { + ADDMSG(&u->faction->msgs, msg_message("sellamount", + "unit amount resource", u, itm->number, itm->type->rtype)); + } + } + a_remove(&u->attribs, a); + add_income(u, IC_TRADE, u->n, u->n); + } +} + +static boolean + sell(unit * u, request ** sellorders, struct order * ord) +{ + boolean unlimited = true; + const item_type * itype; + const luxury_type * ltype=NULL; + int n; + region * r = u->region; + const char *s; + + if (u->ship && is_guarded(r, u, GUARD_CREWS)) { + cmistake(u, ord, 69, MSG_INCOME); + return false; + } + /* sellorders sind KEIN array, weil für alle items DIE SELBE resource + * (das geld der region) aufgebraucht wird. */ + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + if (findparam(s, u->faction->locale) == P_ANY) { + unlimited = false; + n = rpeasants(r) / TRADE_FRACTION; + if (r->terrain == newterrain(T_DESERT) && buildingtype_exists(r, bt_find("caravan"), true)) + n *= 2; + if (n==0) { + cmistake(u, ord, 303, MSG_COMMERCE); + return false; + } + } else { + n = atoi((const char *)s); + if (n==0) { + cmistake(u, ord, 27, MSG_COMMERCE); + return false; + } + } + /* Belagerte Einheiten können nichts verkaufen. */ + + if (besieged(u)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "error60", "")); + return false; + } + /* In der Region muß es eine Burg geben. */ + + if (u->race == new_race[RC_INSECT]) { + if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT) && !rbuildings(r)) { + cmistake(u, ord, 119, MSG_COMMERCE); + return false; + } + } else { + /* ...oder in der Region muß es eine Burg geben. */ + building * b; + static const struct building_type * bt_castle; + if (!bt_castle) bt_castle = bt_find("castle"); + for (b=r->buildings;b;b=b->next) { + if (b->type==bt_castle && b->size>=2) break; + } + if (b==NULL) { + cmistake(u, ord, 119, MSG_COMMERCE); + return false; + } + } + + /* Ein Händler kann nur 10 Güter pro Talentpunkt verkaufen. */ + + n = MIN(n, u->number * 10 * eff_skill(u, SK_TRADE, r)); + + if (!n) { + cmistake(u, ord, 54, MSG_COMMERCE); + return false; + } + s=getstrtoken(); + itype = finditemtype(s, u->faction->locale); + if (itype!=NULL) ltype = resource2luxury(itype->rtype); + if (ltype==NULL) { + cmistake(u, ord, 126, MSG_COMMERCE); + return false; + } + else { + attrib * a; + request *o; + int k, available; + + if (!r_demand(r, ltype)) { + cmistake(u, ord, 263, MSG_COMMERCE); + return false; + } + available = get_pooled(u, itype->rtype, GET_DEFAULT, INT_MAX); + + /* Wenn andere Einheiten das selbe verkaufen, muß ihr Zeug abgezogen + * werden damit es nicht zweimal verkauft wird: */ + for (o=*sellorders;o;o=o->next) { + if (o->type.ltype==ltype && o->unit->faction == u->faction) { + int fpool = o->qty - get_pooled(o->unit, itype->rtype, GET_RESERVE, INT_MAX); + available -= MAX(0, fpool); + } + } + + n = MIN(n, available); + + if (n <= 0) { + cmistake(u, ord, 264, MSG_COMMERCE); + return false; + } + /* Hier wird request->type verwendet, weil die obere limit durch + * das silber gegeben wird (region->money), welches für alle + * (!) produkte als summe gilt, als nicht wie bei der + * produktion, wo für jedes produkt einzeln eine obere limite + * existiert, so dass man arrays von orders machen kann. */ + + /* Ein Händler kann nur 10 Güter pro Talentpunkt handeln. */ + k = u->number * 10 * eff_skill(u, SK_TRADE, r); + + /* hat der Händler bereits gehandelt, muss die Menge der bereits + * verkauften/gekauften Güter abgezogen werden */ + a = a_find(u->attribs, &at_trades); + if (!a) { + a = a_add(&u->attribs, a_new(&at_trades)); + } else { + k -= a->data.i; + } + + n = MIN(n, k); + assert(n>=0); + /* die Menge der verkauften Güter merken */ + a->data.i += n; + o = (request *) calloc(1, sizeof(request)); + o->unit = u; + o->qty = n; + o->type.ltype = ltype; + addlist(sellorders, o); + + return unlimited; + } +} +/* ------------------------------------------------------------- */ + +static void +expandstealing(region * r, request * stealorders) +{ + int i; + + expandorders(r, stealorders); + if (!norders) return; + + /* Für jede unit in der Region wird Geld geklaut, wenn sie Opfer eines + * Beklauen-Orders ist. Jedes Opfer muß einzeln behandelt werden. + * + * u ist die beklaute unit. oa.unit ist die klauende unit. + */ + + for (i = 0; i != norders && oa[i].unit->n <= oa[i].unit->wants; i++) { + unit *u = findunitg(oa[i].no, r); + int n = 0; + if (u && u->region==r) { + n = get_pooled(u, r_silver, GET_ALL, INT_MAX); + } +#ifndef GOBLINKILL + if (oa[i].type.goblin) { /* Goblin-Spezialklau */ + int uct = 0; + unit *u2; + assert(effskill(oa[i].unit, SK_STEALTH)>=4 || !"this goblin\'s skill is too low"); + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->faction == u->faction) { + uct += maintenance_cost(u2); + } + } + n -= uct * 2; + } +#endif + if (n>10 && rplane(r) && (rplane(r)->flags & PFL_NOALLIANCES)) { + /* In Questen nur reduziertes Klauen */ + n = 10; + } + if (n > 0) { + n = MIN(n, oa[i].unit->wants); + use_pooled(u, r_silver, GET_ALL, n); + oa[i].unit->n = n; + change_money(oa[i].unit, n); + ADDMSG(&u->faction->msgs, msg_message("stealeffect", "unit region amount", u, u->region, n)); + } + add_income(oa[i].unit, IC_STEAL, oa[i].unit->wants, oa[i].unit->n); + fset(oa[i].unit, UFL_LONGACTION|UFL_NOTMOVING); + } + free(oa); +} + +/* ------------------------------------------------------------- */ +static void +plant(region *r, unit *u, int raw) +{ + int n, i, skill, planted = 0; + const item_type * itype; + static const resource_type * rt_water = NULL; + if (rt_water==NULL) rt_water = rt_find("p2"); + + assert(rt_water!=NULL); + if (!fval(r->terrain, LAND_REGION)) { + return; + } + if (rherbtype(r) == NULL) { + cmistake(u, u->thisorder, 108, MSG_PRODUCE); + return; + } + + /* Skill prüfen */ + skill = eff_skill(u, SK_HERBALISM, r); + itype = rherbtype(r); + if (skill < 6) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "plant_skills", + "skill minskill product", SK_HERBALISM, 6, itype->rtype, 1)); + return; + } + /* Wasser des Lebens prüfen */ + if (get_pooled(u, rt_water, GET_DEFAULT, 1) == 0) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "resource_missing", "missing", rt_water)); + return; + } + n = get_pooled(u, itype->rtype, GET_DEFAULT, skill*u->number); + /* Kräuter prüfen */ + if (n==0) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "resource_missing", "missing", + itype->rtype)); + return; + } + + n = MIN(skill*u->number, n); + n = MIN(raw, n); + /* Für jedes Kraut Talent*10% Erfolgschance. */ + for(i = n; i>0; i--) { + if (rng_int()%10 < skill) planted++; + } + produceexp(u, SK_HERBALISM, u->number); + + /* Alles ok. Abziehen. */ + use_pooled(u, rt_water, GET_DEFAULT, 1); + use_pooled(u, itype->rtype, GET_DEFAULT, n); + rsetherbs(r, rherbs(r)+planted); + ADDMSG(&u->faction->msgs, msg_message("plant", "unit region amount herb", + u, r, planted, itype->rtype)); +} + +static void +planttrees(region *r, unit *u, int raw) +{ + int n, i, skill, planted = 0; + const resource_type * rtype; + + if (!fval(r->terrain, LAND_REGION)) { + return; + } + + /* Mallornbäume kann man nur in Mallornregionen züchten */ + if (fval(r, RF_MALLORN)) { + rtype = rt_mallornseed; + } else { + rtype = rt_seed; + } + + /* Skill prüfen */ + skill = eff_skill(u, SK_HERBALISM, r); + if (skill < 6) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "plant_skills", + "skill minskill product", SK_HERBALISM, 6, rtype, 1)); + return; + } + if (fval(r, RF_MALLORN) && skill < 7 ) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "plant_skills", + "skill minskill product", SK_HERBALISM, 7, rtype, 1)); + return; + } + + /* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */ + raw = MIN(raw, skill*u->number); + n = get_pooled(u, rtype, GET_DEFAULT, raw); + if (n==0) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype)); + return; + } + n = MIN(raw, n); + + /* Für jeden Samen Talent*10% Erfolgschance. */ + for(i = n; i>0; i--) { + if (rng_int()%10 < skill) planted++; + } + rsettrees(r, 0, rtrees(r, 0)+planted); + + /* Alles ok. Abziehen. */ + produceexp(u, SK_HERBALISM, u->number); + use_pooled(u, rtype, GET_DEFAULT, n); + + ADDMSG(&u->faction->msgs, msg_message("plant", + "unit region amount herb", u, r, planted, rtype)); +} + +/* züchte bäume */ +static void +breedtrees(region *r, unit *u, int raw) +{ + int n, i, skill, planted = 0; + const resource_type * rtype; + static int gamecookie = -1; + static int current_season; + + if (gamecookie!=global.cookie) { + gamedate date; + get_gamedate(turn, &date); + current_season = date.season; + gamecookie = global.cookie; + } + + /* Bäume züchten geht nur im Frühling */ + if (current_season != SEASON_SPRING){ + planttrees(r, u, raw); + return; + } + + if (!fval(r->terrain, LAND_REGION)) { + return; + } + + /* Mallornbäume kann man nur in Mallornregionen züchten */ + if (fval(r, RF_MALLORN)) { + rtype = rt_mallornseed; + } else { + rtype = rt_seed; + } + + /* Skill prüfen */ + skill = eff_skill(u, SK_HERBALISM, r); + if (skill < 12) { + planttrees(r, u, raw); + return; + } + + /* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */ + raw = MIN(skill*u->number, raw); + n = get_pooled(u, rtype, GET_DEFAULT, raw); + /* Samen prüfen */ + if (n==0) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype)); + return; + } + n = MIN(raw, n); + + /* Für jeden Samen Talent*5% Erfolgschance. */ + for(i = n; i>0; i--) { + if (rng_int()%100 < skill*5) planted++; + } + rsettrees(r, 1, rtrees(r, 1)+planted); + + /* Alles ok. Abziehen. */ + produceexp(u, SK_HERBALISM, u->number); + use_pooled(u, rtype, GET_DEFAULT, n); + + ADDMSG(&u->faction->msgs, msg_message("plant", + "unit region amount herb", u, r, planted, rtype)); +} + +/* züchte pferde */ +static void +breedhorses(region *r, unit *u) +{ + int n, c; + int gezuechtet = 0; + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + + if (btype!=bt_find("stables")) { + cmistake(u, u->thisorder, 122, MSG_PRODUCE); + return; + } + if (get_item(u, I_HORSE) < 2) { + cmistake(u, u->thisorder, 107, MSG_PRODUCE); + return; + } + n = MIN(u->number * eff_skill(u, SK_HORSE_TRAINING, r), get_item(u, I_HORSE)); + + for (c = 0; c < n; c++) { + if (rng_int() % 100 < eff_skill(u, SK_HORSE_TRAINING, r)) { + i_change(&u->items, olditemtype[I_HORSE], 1); + gezuechtet++; + } + } + + produceexp(u, SK_HORSE_TRAINING, u->number); + + ADDMSG(&u->faction->msgs, msg_message("raised", + "unit amount", u, gezuechtet)); +} + +static void +breed_cmd(unit *u, struct order * ord) +{ + int m; + const char *s; + param_t p; + region *r = u->region; + const resource_type * rtype = NULL; + + if (r->land==NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); + return; + } + + /* züchte [] */ + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + m = atoi((const char *)s); + if (m!=0) { + /* first came a want-paramter */ + s = getstrtoken(); + } else { + m = INT_MAX; + } + + if (!s[0]) { + p = P_ANY; + } else { + p = findparam(s, u->faction->locale); + } + + switch (p) { + case P_HERBS: + plant(r, u, m); + break; + case P_TREES: + breedtrees(r, u, m); + break; + default: + if (p!=P_ANY) { + rtype = findresourcetype(s, u->faction->locale); + if (rtype==rt_mallornseed || rtype==rt_seed) { + breedtrees(r, u, m); + break; + } else if (rtype!=oldresourcetype[R_HORSE]) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_cannotmake", "")); + break; + } + } + breedhorses(r, u); + break; + } +} + +static const char * +rough_amount(int a, int m) + +{ + int p = (a * 100)/m; + + if (p < 10) { + return "sehr wenige"; + } else if (p < 30) { + return "wenige"; + } else if (p < 60) { + return "relativ viele"; + } else if (p < 90) { + return "viele"; + } + return "sehr viele"; +} + +static void +research_cmd(unit *u, struct order * ord) +{ + region *r = u->region; + + init_tokens(ord); + skip_token(); + /* + const char *s = getstrtoken(); + + if (findparam(s, u->faction->locale) == P_HERBS) { */ + + if (eff_skill(u, SK_HERBALISM, r) < 7) { + cmistake(u, ord, 227, MSG_EVENT); + return; + } + + produceexp(u, SK_HERBALISM, u->number); + + if (rherbs(r) > 0) { + const item_type *itype = rherbtype(r); + + if (itype != NULL) { + ADDMSG(&u->faction->msgs, msg_message("researchherb", + "unit region amount herb", + u, r, rough_amount(rherbs(r), 100), itype->rtype)); + } else { + ADDMSG(&u->faction->msgs, msg_message("researchherb_none", + "unit region", u, r)); + } + } else { + ADDMSG(&u->faction->msgs, msg_message("researchherb_none", + "unit region", u, r)); + } +} + +static int +max_skill(region * r, faction * f, skill_t sk) +{ + unit *u; + int w = 0; + + for (u = r->units; u; u = u->next) { + if (u->faction == f) { + if (eff_skill(u, sk, r) > w) { + w = eff_skill(u, sk, r); + } + } + } + + return w; +} + +static void +steal_cmd(unit * u, struct order * ord, request ** stealorders) +{ + int n, i, id; + boolean goblin = false; + request * o; + unit * u2 = NULL; + region * r = u->region; + faction * f = NULL; + plane * pl; + + assert(skill_enabled[SK_PERCEPTION] && skill_enabled[SK_STEALTH]); + + if (!fval(u->race, RCF_CANSTEAL)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_nosteal", "race", u->race)); + return; + } + + if (fval(r->terrain, SEA_REGION) && u->race != new_race[RC_AQUARIAN]) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); + return; + } + + pl = rplane(r); + if (pl && fval(pl, PFL_NOATTACK)) { + cmistake(u, ord, 270, MSG_INCOME); + return; + } + + init_tokens(ord); + skip_token(); + id = read_unitid(u->faction, r); + u2 = findunitr(r, id); + + if (u2 && u2->region==u->region) { + f = u2->faction; + } else { + f = dfindhash(id); + } + + for (u2=r->units;u2;u2=u2->next) { + if (u2->faction == f && cansee(u->faction, r, u2, 0)) break; + } + + if (!u2) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + + if (IsImmune(u2->faction)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "newbie_immunity_error", + "turns", NewbieImmunity())); + return; + } + + if (u->faction->alliance && u->faction->alliance == u2->faction->alliance) { + cmistake(u, ord, 47, MSG_INCOME); + return; + } + + assert(u->region==u2->region); + if (!can_contact(r, u, u2)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error60", "")); + return; + } + + n = eff_skill(u, SK_STEALTH, r) - max_skill(r, f, SK_PERCEPTION); + + if (n <= 0) { + /* Wahrnehmung == Tarnung */ + if (u->race != new_race[RC_GOBLIN] || eff_skill(u, SK_STEALTH, r) <= 3) { + ADDMSG(&u->faction->msgs, msg_message("stealfail", "unit target", u, u2)); + if (n==0) { + ADDMSG(&u2->faction->msgs, msg_message("stealdetect", "unit", u2)); + } else { + ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target", u, u2)); + } + return; + } else { + ADDMSG(&u->faction->msgs, msg_message("stealfatal", "unit target", u, u2)); + ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target", u, u2)); + n = 1; + goblin = true; + } + } + + i = MIN(u->number, get_item(u, I_RING_OF_NIMBLEFINGER)); + if (i > 0) { + n *= STEALINCOME * (u->number + i * (roqf_factor()-1)); + } else { + n *= u->number * STEALINCOME; + } + + u->wants = n; + + /* wer dank unsichtbarkeitsringen klauen kann, muss nicht unbedingt ein + * guter dieb sein, schliesslich macht man immer noch sehr viel laerm */ + + o = (request *) calloc(1, sizeof(request)); + o->unit = u; + o->qty = 1; /* Betrag steht in u->wants */ + o->no = u2->no; + o->type.goblin = goblin; /* Merken, wenn Goblin-Spezialklau */ + addlist(stealorders, o); + + /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ + + produceexp(u, SK_STEALTH, MIN(n, u->number)); +} +/* ------------------------------------------------------------- */ + + +static void +expandentertainment(region * r) +{ + unit *u; + int m = entertainmoney(r); + request *o; + + for (o = &entertainers[0]; o != nextentertainer; ++o) { + double part = m / (double) entertaining; + u = o->unit; + if (entertaining <= m) + u->n = o->qty; + else + u->n = (int) (o->qty * part); + change_money(u, u->n); + rsetmoney(r, rmoney(r) - u->n); + m -= u->n; + entertaining -= o->qty; + + /* Nur soviel PRODUCEEXP wie auch tatsächlich gemacht wurde */ + produceexp(u, SK_ENTERTAINMENT, MIN(u->n, u->number)); + add_income(u, IC_ENTERTAIN, o->qty, u->n); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + } +} + +void +entertain_cmd(unit * u, struct order * ord) +{ + region * r = u->region; + int max_e; + request *o; + static int entertainbase = 0; + static int entertainperlevel = 0; + + if (!entertainbase) { + const char * str = get_param(global.parameters, "entertain.base"); + entertainbase = str?atoi(str):0; + } + if (!entertainperlevel) { + const char * str = get_param(global.parameters, "entertain.perlevel"); + entertainperlevel = str?atoi(str):0; + } + if (fval(u, UFL_WERE)) { + cmistake(u, ord, 58, MSG_INCOME); + return; + } + if (!effskill(u, SK_ENTERTAINMENT)) { + cmistake(u, ord, 58, MSG_INCOME); + return; + } + if (besieged(u)) { + cmistake(u, ord, 60, MSG_INCOME); + return; + } + if (u->ship && is_guarded(r, u, GUARD_CREWS)) { + cmistake(u, ord, 69, MSG_INCOME); + return; + } + if (is_cursed(r->attribs, C_DEPRESSION, 0)) { + cmistake(u, ord, 28, MSG_INCOME); + return; + } + + u->wants = u->number * (entertainbase + effskill(u, SK_ENTERTAINMENT) + * entertainperlevel); + + init_tokens(ord); + skip_token(); + max_e = getuint(); + if (max_e != 0) { + u->wants = MIN(u->wants,max_e); + } + o = nextentertainer++; + o->unit = u; + o->qty = u->wants; + entertaining += o->qty; +} + +/** + * \return number of working spaces taken by players + */ +static void +expandwork(region * r, request * work_begin, request * work_end, int maxwork) +{ + int earnings; + /* n: verbleibende Einnahmen */ + /* fishes: maximale Arbeiter */ + int jobs = maxwork; + int p_wage = wage(r, NULL, NULL, turn); + int money = rmoney(r); + request *o; + + for (o = work_begin; o != work_end; ++o) { + unit * u = o->unit; + int workers; + + if (u->number == 0) continue; + + if (jobs>=working) workers = u->number; + else { + workers = u->number * jobs / working; + if (rng_int() % working < (u->number * jobs) % working) workers++; + } + + assert(workers>=0); + + u->n = workers * wage(u->region, u->faction, u->race, turn); + + jobs -= workers; + assert(jobs>=0); + + change_money(u, u->n); + working -= o->unit->number; + add_income(u, IC_WORK, o->qty, u->n); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + } + + if (jobs>rpeasants(r)) { + jobs = rpeasants(r); + } + earnings = jobs * p_wage; + if (rule_blessed_harvest()==HARVEST_TAXES) { + /* E3 rules */ + static const curse_type * blessedharvest_ct; + if (!blessedharvest_ct) { + blessedharvest_ct = ct_find("blessedharvest"); + } + if (blessedharvest_ct && r->attribs) { + int happy = (int)curse_geteffect(get_curse(r->attribs, blessedharvest_ct)); + happy = MIN(happy, jobs); + earnings += happy; + } + } + rsetmoney(r, money + earnings); +} + +static int +do_work(unit * u, order * ord, request * o) +{ + if (playerrace(u->race)) { + region * r = u->region; + int w; + + if (fval(u, UFL_WERE)) { + if (ord) cmistake(u, ord, 313, MSG_INCOME); + return -1; + } + if (besieged(u)) { + if (ord) cmistake(u, ord, 60, MSG_INCOME); + return -1; + } + if (u->ship && is_guarded(r, u, GUARD_CREWS)) { + if (ord) cmistake(u, ord, 69, MSG_INCOME); + return -1; + } + w = wage(r, u->faction, u->race, turn); + u->wants = u->number * w; + o->unit = u; + o->qty = u->number * w; + working += u->number; + return 0; + } + else if (ord && !is_monsters(u->faction)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_cantwork", "race", u->race)); + } + return -1; +} + +static void +expandtax(region * r, request * taxorders) +{ + unit *u; + int i; + + expandorders(r, taxorders); + if (!norders) return; + + for (i = 0; i != norders && rmoney(r) > TAXFRACTION; i++) { + change_money(oa[i].unit, TAXFRACTION); + oa[i].unit->n += TAXFRACTION; + rsetmoney(r, rmoney(r) -TAXFRACTION); + } + free(oa); + + for (u = r->units; u; u = u->next) { + if (u->n >= 0) { + add_income(u, IC_TAX, u->wants, u->n); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + } + } +} + +void +tax_cmd(unit * u, struct order * ord, request ** taxorders) +{ + /* Steuern werden noch vor der Forschung eingetrieben */ + region * r = u->region; + unit *u2; + int n; + request *o; + int max; + + if (!humanoidrace(u->race) && !is_monsters(u->faction)) { + cmistake(u, ord, 228, MSG_INCOME); + return; + } + + if (fval(u, UFL_WERE)) { + cmistake(u, ord, 228, MSG_INCOME); + return; + } + + if (besieged(u)) { + cmistake(u, ord, 60, MSG_INCOME); + return; + } + n = armedmen(u, false); + + if (!n) { + cmistake(u, ord, 48, MSG_INCOME); + return; + } + + init_tokens(ord); + skip_token(); + max = getuint(); + + if (max == 0) max = INT_MAX; + if (!playerrace(u->race)) { + u->wants = MIN(income(u), max); + } else { + u->wants = MIN(n * eff_skill(u, SK_TAXING, r) * 20, max); + } + + u2 = is_guarded(r, u, GUARD_TAX); + if (u2) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "region_guarded", "guard", u2)); + return; + } + + /* die einnahmen werden in fraktionen von 10 silber eingeteilt: diese + * fraktionen werden dann bei eintreiben unter allen eintreibenden + * einheiten aufgeteilt. */ + + o = (request *) calloc(1, sizeof(request)); + o->qty = u->wants / TAXFRACTION; + o->unit = u; + addlist(taxorders, o); + return; +} + +#define MAX_WORKERS 2048 +void +auto_work(region * r) +{ + request workers[MAX_WORKERS]; + request * nextworker = workers; + unit * u; + + for (u=r->units;u;u=u->next) { + if (!(u->flags & UFL_LONGACTION) && !is_monsters(u->faction)) { + if (do_work(u, NULL, nextworker)==0) { + assert(nextworker-workersfaction!=f) return; + + maxsize = buildingeffsize(b, false); + if (maxsize>0) { + double taxfactor = money * b->type->taxes(b, maxsize); + double morale = money * region_get_morale(r) * MORALE_TAX_FACTOR; + if (taxfactor>morale) taxfactor = morale; + if (taxfactor>0) { + int taxmoney = (int)taxfactor; + change_money(u, taxmoney); + rsetmoney(r, money - taxmoney); + ADDMSG(&u->faction->msgs, msg_message("income_tax", + "unit region amount", u, r, taxmoney)); + } + } +} + +void +produce(struct region *r) +{ + request workers[MAX_WORKERS]; + request *taxorders, *sellorders, *stealorders, *buyorders; + unit *u; + int todo; + static int rule_autowork = -1; + boolean limited = true; + request * nextworker = workers; + assert(r); + + /* das sind alles befehle, die 30 tage brauchen, und die in thisorder + * stehen! von allen 30-tage befehlen wird einfach der letzte verwendet + * (dosetdefaults). + * + * kaufen vor einnahmequellen. da man in einer region dasselbe produkt + * nicht kaufen und verkaufen kann, ist die reihenfolge wegen der + * produkte egal. nicht so wegen dem geld. + * + * lehren vor lernen. */ + + if (rule_autowork<0) { + rule_autowork = get_param_int(global.parameters, "work.auto", 0); + } + + assert(rmoney(r) >= 0); + assert(rpeasants(r) >= 0); + + if (r->land && rule_auto_taxation()) { + /* new taxation rules, region owners make money based on morale and building */ + peasant_taxes(r); + } + + buyorders = 0; + sellorders = 0; + working = 0; + nextentertainer = &entertainers[0]; + entertaining = 0; + taxorders = 0; + stealorders = 0; + + for (u = r->units; u; u = u->next) { + order * ord; + boolean trader = false; + + if (u->race == new_race[RC_SPELL] || fval(u, UFL_LONGACTION)) + continue; + + if (u->race == new_race[RC_INSECT] && r_insectstalled(r) && + !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) + continue; + + if (fval(u, UFL_LONGACTION) && u->thisorder==NULL) { + cmistake(u, u->thisorder, 52, MSG_PRODUCE); + continue; + } + + for (ord = u->orders;ord;ord=ord->next) { + switch (get_keyword(ord)) { + case K_BUY: + buy(u, &buyorders, ord); + trader = true; + break; + case K_SELL: + /* sell returns true if the sale is not limited + * by the region limit */ + limited &= !sell(u, &sellorders, ord); + trader = true; + break; + } + } + if (trader) { + attrib * a = a_find(u->attribs, &at_trades); + if (a && a->data.i) { + produceexp(u, SK_TRADE, u->number); + } + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + continue; + } + + todo = get_keyword(u->thisorder); + if (todo == NOKEYWORD) continue; + + if (fval(r->terrain, SEA_REGION) && u->race != new_race[RC_AQUARIAN] + && !(u->race->flags & RCF_SWIM) + && todo != K_STEAL && todo != K_SPY && todo != K_SABOTAGE) + continue; + + switch (todo) { + + case K_ENTERTAIN: + entertain_cmd(u, u->thisorder); + break; + + case K_WORK: + if (!rule_autowork && do_work(u, u->thisorder, nextworker)==0) { + assert(nextworker-workersthisorder, &taxorders); + break; + + case K_STEAL: + steal_cmd(u, u->thisorder, &stealorders); + break; + + case K_SPY: + spy_cmd(u, u->thisorder); + break; + + case K_SABOTAGE: + sabotage_cmd(u, u->thisorder); + break; + + case K_PLANT: + case K_BREED: + breed_cmd(u, u->thisorder); + break; + + case K_RESEARCH: + research_cmd(u, u->thisorder); + break; + } + } + + /* Entertainment (expandentertainment) und Besteuerung (expandtax) vor den + * Befehlen, die den Bauern mehr Geld geben, damit man aus den Zahlen der + * letzten Runde berechnen kann, wieviel die Bauern für Unterhaltung + * auszugeben bereit sind. */ + if (entertaining) expandentertainment(r); + if (!rule_autowork) { + expandwork(r, workers, nextworker, maxworkingpeasants(r)); + } + if (taxorders) expandtax(r, taxorders); + + /* An erster Stelle Kaufen (expandbuying), die Bauern so Geld bekommen, um + * nachher zu beim Verkaufen (expandselling) den Spielern abkaufen zu + * können. */ + + if (buyorders) expandbuying(r, buyorders); + + if (sellorders) { + int limit = rpeasants(r) / TRADE_FRACTION; + if (r->terrain == newterrain(T_DESERT) && buildingtype_exists(r, bt_find("caravan"), true)) + limit *= 2; + expandselling(r, sellorders, limited?limit:INT_MAX); + } + + /* Die Spieler sollen alles Geld verdienen, bevor sie beklaut werden + * (expandstealing). */ + + if (stealorders) expandstealing(r, stealorders); + + assert(rmoney(r) >= 0); + assert(rpeasants(r) >= 0); +} diff --git a/src/gamecode/economy.h b/src/gamecode/economy.h index 7bc7d78e7..db8359a63 100644 --- a/src/gamecode/economy.h +++ b/src/gamecode/economy.h @@ -1,60 +1,60 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_GC_ECONOMY -#define H_GC_ECONOMY -#ifdef __cplusplus -extern "C" { -#endif - -/* Welchen Teil des Silbers die Bauern fuer Unterhaltung ausgeben (1/20), und - * wiviel Silber ein Unterhalter pro Talentpunkt bekommt. */ - -/* Wieviele Silbermuenzen jeweils auf einmal "getaxed" werden. */ - -#define TAXFRACTION 10 - -/* Wieviel Silber pro Talentpunkt geklaut wird. */ - -#define STEALINCOME 50 - -/* Teil der Bauern, welche Luxusgueter kaufen und verkaufen (1/100). */ - -#define TRADE_FRACTION 100 - -extern int income(const struct unit * u); - -/* Wieviel Fremde eine Partei pro Woche aufnehmen kann */ -#define MAXNEWBIES 5 - -void economics(struct region *r); -void produce(struct region *r); -void auto_work(struct region * r); - -enum { IC_WORK, IC_ENTERTAIN, IC_TAX, IC_TRADE, IC_TRADETAX, IC_STEAL, IC_MAGIC }; -void maintain_buildings(struct region * r, boolean crash); -extern void add_spende(struct faction * f1, struct faction * f2, int betrag, struct region * r); -extern int make_cmd(struct unit * u, struct order * ord); -extern void split_allocations(struct region * r); -extern int recruit_archetypes(void); -extern int give_control_cmd(struct unit * u, struct order * ord); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_GC_ECONOMY +#define H_GC_ECONOMY +#ifdef __cplusplus +extern "C" { +#endif + +/* Welchen Teil des Silbers die Bauern fuer Unterhaltung ausgeben (1/20), und + * wiviel Silber ein Unterhalter pro Talentpunkt bekommt. */ + +/* Wieviele Silbermuenzen jeweils auf einmal "getaxed" werden. */ + +#define TAXFRACTION 10 + +/* Wieviel Silber pro Talentpunkt geklaut wird. */ + +#define STEALINCOME 50 + +/* Teil der Bauern, welche Luxusgueter kaufen und verkaufen (1/100). */ + +#define TRADE_FRACTION 100 + +extern int income(const struct unit * u); + +/* Wieviel Fremde eine Partei pro Woche aufnehmen kann */ +#define MAXNEWBIES 5 + +void economics(struct region *r); +void produce(struct region *r); +void auto_work(struct region * r); + +enum { IC_WORK, IC_ENTERTAIN, IC_TAX, IC_TRADE, IC_TRADETAX, IC_STEAL, IC_MAGIC }; +void maintain_buildings(struct region * r, boolean crash); +extern void add_spende(struct faction * f1, struct faction * f2, int betrag, struct region * r); +extern int make_cmd(struct unit * u, struct order * ord); +extern void split_allocations(struct region * r); +extern int recruit_archetypes(void); +extern int give_control_cmd(struct unit * u, struct order * ord); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/give.c b/src/gamecode/give.c index 9777a3bee..0bc783645 100644 --- a/src/gamecode/give.c +++ b/src/gamecode/give.c @@ -1,438 +1,438 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - - */ -#include -#include -#include "give.h" - -#include "economy.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* attributes includes */ -#include -#include - -/* util includes */ -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -/* Wieviel Fremde eine Partei pro Woche aufnehmen kangiven */ -#define MAXNEWBIES 5 -#define RESERVE_DONATIONS /* shall we reserve objects given to us by other factions? */ -#define RESERVE_GIVE /* reserve anything that's given from one unit to another? */ - - -static int -GiveRestriction(void) { - static int value = -1; - if (value<0) { - const char * str = get_param(global.parameters, "GiveRestriction"); - value = str?atoi(str):0; - } - return value; -} - -static void -add_give(unit * u, unit * u2, int given, int received, const resource_type * rtype, struct order * ord, int error) -{ - if (error) { - cmistake(u, ord, error, MSG_COMMERCE); - } - else if (u2==NULL) { - ADDMSG(&u->faction->msgs, - msg_message("give_peasants", "unit resource amount", - u, rtype, given)); - } else if (u2->faction!=u->faction) { - message * msg; - - msg = msg_message("give", "unit target resource amount", u, u2, rtype, given); - add_message(&u->faction->msgs, msg); - msg_release(msg); - - msg = msg_message("receive", "unit target resource amount", u, u2, rtype, received); - add_message(&u2->faction->msgs, msg); - msg_release(msg); - } -} - -static boolean -limited_give(const item_type * type) -{ - /* trade only money 2:1, if at all */ - return (type == i_silver); -} - -int give_quota(const unit * src, const unit * dst, const item_type * type, int n) -{ - static float divisor = -1; - - if (divisor==0 || !limited_give(type)) { - return n; - } - if (dst && src && src->faction!=dst->faction) { - if (divisor<0) { - divisor = get_param_flt(global.parameters, "rules.items.give_divisor", 1); - assert(divisor==0 || divisor>=1); - } - if (divisor>=1) { - /* predictable > correct: */ - int x = (int)(n/divisor); - return x; - } - } - return n; -} - -int -give_item(int want, const item_type * itype, unit * src, unit * dest, struct order * ord) -{ - short error = 0; - int n, r; - - assert(itype!=NULL); - n = get_pooled(src, item2resource(itype), GET_DEFAULT, want); - n = MIN(want, n); - r = n; - if (dest && src->faction != dest->faction && src->faction->age < GiveRestriction()) { - if (ord!=NULL) { - ADDMSG(&src->faction->msgs, msg_feedback(src, ord, "giverestriction", - "turns", GiveRestriction())); - } - return -1; - } else if (n == 0) { - int reserve = get_reservation(src, itype->rtype); - if (reserve) { - msg_feedback(src, ord, "nogive_reserved", "resource reservation", - itype->rtype, reserve); - return -1; - } - error = 36; - } else if (itype->flags & ITF_CURSED) { - error = 25; - } else if (itype->give==NULL || itype->give(src, dest, itype, n, ord)!=0) { - int use = use_pooled(src, item2resource(itype), GET_SLACK, n); - if (useitems, itype, r); -#ifdef RESERVE_GIVE -#ifdef RESERVE_DONATIONS - change_reservation(dest, item2resource(itype), r); -#else - if (src->faction==dest->faction) { - change_reservation(dest, item2resource(itype), r); - } -#endif -#endif -#if MUSEUM_MODULE && defined(TODO) - /* TODO: use a trigger for the museum warden! */ - if (a_find(dest->attribs, &at_warden)) { - warden_add_give(src, dest, itype, r); - } -#endif - handle_event(dest->attribs, "receive", src); - } - handle_event(src->attribs, "give", dest); - } - add_give(src, dest, n, r, item2resource(itype), ord, error); - if (error) return -1; - return 0; -} - -void -give_men(int n, unit * u, unit * u2, struct order * ord) -{ - ship *sh; - int k = 0; - int error = 0; - - if (u2 && u->faction != u2->faction && u->faction->age < GiveRestriction()) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "giverestriction", - "turns", GiveRestriction())); - return; - } else if (u == u2) { - error = 10; - } else if (!u2 && u->race == new_race[RC_SNOTLING]) { - /* snotlings may not be given to the peasants. */ - error = 307; - } else if (u2 && u2->number && (fval(u, UFL_HERO) != fval(u2, UFL_HERO))) { - /* heroes may not be given to non-heroes and vice versa*/ - error = 75; - } else if (unit_has_cursed_item(u) || (u2 && unit_has_cursed_item(u2))) { - error = 78; - } else if (fval(u, UFL_LOCKED) || is_cursed(u->attribs, C_SLAVE, 0)) { - error = 74; - } else if (u2 && fval(u, UFL_HUNGER)) { - /* hungry people cannot be given away */ - error = 73; - } else if (u2 && (fval(u2, UFL_LOCKED)|| is_cursed(u2->attribs, C_SLAVE, 0))) { - error = 75; - } else if (u2 && !ucontact(u2, u)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", "target", u2)); - error = -1; - } else if (u2 && (has_skill(u, SK_MAGIC) || has_skill(u2, SK_MAGIC))) { - /* cannot give units to and from magicians */ - error = 158; - } else if (u2 && (fval(u, UFL_WERE) != fval(u2, UFL_WERE))) { - /* werewolves can't be given to non-werewolves and vice-versa */ - error = 312; - } else if (u2 && u2->number!=0 && u2->race != u->race) { - log_warning(("faction %s attempts to give %s to %s.\n", - itoa36(u->faction->no), u->race->_name[0], - u2->race->_name[1])); - error = 139; - } else if (u2!=NULL && (get_racename(u2->attribs) || get_racename(u->attribs))) { - error = 139; - } else if (u2 && u2->faction!=u->faction && !rule_transfermen()) { - error = 74; - } else { - if (n > u->number) n = u->number; - if (u2 && n+u2->number > UNIT_MAXSIZE) { - n = UNIT_MAXSIZE-u2->number; - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_unit_size", "maxsize", UNIT_MAXSIZE)); - assert(n>=0); - } - if (n == 0) { - error = 96; - } else if (u2 && u->faction != u2->faction) { - if (u2->faction->newbies + n > MAXNEWBIES) { - error = 129; - } else if (u->race != u2->faction->race) { - if (u2->faction->race != new_race[RC_HUMAN]) { - error = 120; - } else if (count_migrants(u2->faction) + n > count_maxmigrants(u2->faction)) { - error = 128; - } - else if (has_limited_skills(u) || has_limited_skills(u2)) { - error = 154; - } else if (u2->number!=0) { - error = 139; - } - } - } - } - - if (u2 && (has_skill(u, SK_ALCHEMY) || has_skill(u2, SK_ALCHEMY))) { - k = count_skill(u2->faction, SK_ALCHEMY); - - /* Falls die Zieleinheit keine Alchemisten sind, werden sie nun - * welche. */ - if (!has_skill(u2, SK_ALCHEMY) && has_skill(u, SK_ALCHEMY)) - k += u2->number; - - /* Wenn in eine Alchemisteneinheit Personen verschoben werden */ - if (has_skill(u2, SK_ALCHEMY) && !has_skill(u, SK_ALCHEMY)) - k += n; - - /* Wenn Parteigrenzen überschritten werden */ - if (u2->faction != u->faction) - k += n; - - /* wird das Alchemistenmaximum ueberschritten ? */ - - if (k > skill_limit(u2->faction, SK_ALCHEMY)) { - error = 156; - } - } - - if (error==0) { - if (u2 && u2->number == 0) { - set_racename(&u2->attribs, get_racename(u->attribs)); - u2->race = u->race; - u2->irace = u->irace; - if (fval(u, UFL_HERO)) fset(u2, UFL_HERO); - else freset(u2, UFL_HERO); - } - - if (u2) { - if (u2->number!=0 && recruit_archetypes()) { - /* must have same set of skills */ - boolean okay = false; - if (u->skill_size==u2->skill_size) { - int i; - for (i=0;i!=u->skill_size;++i) { - int j; - for (j=0;j!=u2->skill_size;++j) { - if (u->skills[i].id==u2->skills[j].id) break; - } - if (j!=u2->skill_size) break; - } - if (i==u->skill_size) okay = true; - } - if (!okay) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "give_cannot_merge", "")); - } - } - - - /* Einheiten von Schiffen können nicht NACH in von - * Nicht-alliierten bewachten Regionen ausführen */ - sh = leftship(u); - if (sh) set_leftship(u2, sh); - - transfermen(u, u2, n); - if (u->faction != u2->faction) { - u2->faction->newbies += n; - } - } else { - if (getunitpeasants) { -#ifdef ORCIFICATION - if (u->race == new_race[RC_SNOTLING] && !fval(u->region, RF_ORCIFIED)) { - attrib *a = a_find(u->region->attribs, &at_orcification); - if (!a) a = a_add(&u->region->attribs, a_new(&at_orcification)); - a->data.i += n; - } -#endif - transfermen(u, NULL, n); - } else { - error = 159; - } - } - } - if (error>0) { - cmistake(u, ord, error, MSG_COMMERCE); - } else if (!u2) { - ADDMSG(&u->faction->msgs, - msg_message("give_person_peasants", "unit amount", u, n)); - } else if (u2->faction!=u->faction) { - message * msg = msg_message("give_person", "unit target amount", u, u2, n); - add_message(&u->faction->msgs, msg); - add_message(&u2->faction->msgs, msg); - msg_release(msg); - } -} - -void -give_unit(unit * u, unit * u2, order * ord) -{ - region * r = u->region; - int n = u->number; - - if (!rule_transfermen() && u->faction!=u2->faction) { - cmistake(u, ord, 74, MSG_COMMERCE); - return; - } - - if (u && unit_has_cursed_item(u)) { - cmistake(u, ord, 78, MSG_COMMERCE); - return; - } - - if (fval(u, UFL_HERO)) { - cmistake(u, ord, 75, MSG_COMMERCE); - return; - } - if (fval(u, UFL_LOCKED) || fval(u, UFL_HUNGER)) { - cmistake(u, ord, 74, MSG_COMMERCE); - return; - } - - if (u2 == NULL) { - if (fval(r->terrain, SEA_REGION)) { - cmistake(u, ord, 152, MSG_COMMERCE); - } else if (getunitpeasants) { - unit *u3; - - for(u3 = r->units; u3; u3 = u3->next) - if(u3->faction == u->faction && u != u3) break; - - if(u3) { - while (u->items) { - item * iold = i_remove(&u->items, u->items); - item * inew = *i_find(&u3->items, iold->type); - if (inew==NULL) i_add(&u3->items, iold); - else { - inew->number += iold->number; - i_free(iold); - } - } - } - give_men(u->number, u, NULL, ord); - cmistake(u, ord, 153, MSG_COMMERCE); - } else { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } - return; - } - - if (!alliedunit(u2, u->faction, HELP_GIVE) && ucontact(u2, u) == 0) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", "target", u2)); - return; - } - if (u->number == 0) { - cmistake(u, ord, 105, MSG_COMMERCE); - return; - } - if (u2->faction->newbies + n > MAXNEWBIES) { - cmistake(u, ord, 129, MSG_COMMERCE); - return; - } - if (u->race != u2->faction->race) { - if (u2->faction->race != new_race[RC_HUMAN]) { - cmistake(u, ord, 120, MSG_COMMERCE); - return; - } - if (count_migrants(u2->faction) + u->number > count_maxmigrants(u2->faction)) { - cmistake(u, ord, 128, MSG_COMMERCE); - return; - } - if (has_limited_skills(u)) { - cmistake(u, ord, 154, MSG_COMMERCE); - return; - } - } - if (has_skill(u, SK_MAGIC)) { - sc_mage * mage; - if (count_skill(u2->faction, SK_MAGIC) + u->number > - skill_limit(u2->faction, SK_MAGIC)) - { - cmistake(u, ord, 155, MSG_COMMERCE); - return; - } - mage = get_mage(u); - if (!mage || u2->faction->magiegebiet != mage->magietyp) { - cmistake(u, ord, 157, MSG_COMMERCE); - return; - } - } - if (has_skill(u, SK_ALCHEMY) - && count_skill(u2->faction, SK_ALCHEMY) + u->number > - skill_limit(u2->faction, SK_ALCHEMY)) - { - cmistake(u, ord, 156, MSG_COMMERCE); - return; - } - add_give(u, u2, 1, 1, r_unit, ord, 0); - u_setfaction(u, u2->faction); - u2->faction->newbies += n; -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ +#include +#include +#include "give.h" + +#include "economy.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* attributes includes */ +#include +#include + +/* util includes */ +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +/* Wieviel Fremde eine Partei pro Woche aufnehmen kangiven */ +#define MAXNEWBIES 5 +#define RESERVE_DONATIONS /* shall we reserve objects given to us by other factions? */ +#define RESERVE_GIVE /* reserve anything that's given from one unit to another? */ + + +static int +GiveRestriction(void) { + static int value = -1; + if (value<0) { + const char * str = get_param(global.parameters, "GiveRestriction"); + value = str?atoi(str):0; + } + return value; +} + +static void +add_give(unit * u, unit * u2, int given, int received, const resource_type * rtype, struct order * ord, int error) +{ + if (error) { + cmistake(u, ord, error, MSG_COMMERCE); + } + else if (u2==NULL) { + ADDMSG(&u->faction->msgs, + msg_message("give_peasants", "unit resource amount", + u, rtype, given)); + } else if (u2->faction!=u->faction) { + message * msg; + + msg = msg_message("give", "unit target resource amount", u, u2, rtype, given); + add_message(&u->faction->msgs, msg); + msg_release(msg); + + msg = msg_message("receive", "unit target resource amount", u, u2, rtype, received); + add_message(&u2->faction->msgs, msg); + msg_release(msg); + } +} + +static boolean +limited_give(const item_type * type) +{ + /* trade only money 2:1, if at all */ + return (type == i_silver); +} + +int give_quota(const unit * src, const unit * dst, const item_type * type, int n) +{ + static float divisor = -1; + + if (divisor==0 || !limited_give(type)) { + return n; + } + if (dst && src && src->faction!=dst->faction) { + if (divisor<0) { + divisor = get_param_flt(global.parameters, "rules.items.give_divisor", 1); + assert(divisor==0 || divisor>=1); + } + if (divisor>=1) { + /* predictable > correct: */ + int x = (int)(n/divisor); + return x; + } + } + return n; +} + +int +give_item(int want, const item_type * itype, unit * src, unit * dest, struct order * ord) +{ + short error = 0; + int n, r; + + assert(itype!=NULL); + n = get_pooled(src, item2resource(itype), GET_DEFAULT, want); + n = MIN(want, n); + r = n; + if (dest && src->faction != dest->faction && src->faction->age < GiveRestriction()) { + if (ord!=NULL) { + ADDMSG(&src->faction->msgs, msg_feedback(src, ord, "giverestriction", + "turns", GiveRestriction())); + } + return -1; + } else if (n == 0) { + int reserve = get_reservation(src, itype->rtype); + if (reserve) { + msg_feedback(src, ord, "nogive_reserved", "resource reservation", + itype->rtype, reserve); + return -1; + } + error = 36; + } else if (itype->flags & ITF_CURSED) { + error = 25; + } else if (itype->give==NULL || itype->give(src, dest, itype, n, ord)!=0) { + int use = use_pooled(src, item2resource(itype), GET_SLACK, n); + if (useitems, itype, r); +#ifdef RESERVE_GIVE +#ifdef RESERVE_DONATIONS + change_reservation(dest, item2resource(itype), r); +#else + if (src->faction==dest->faction) { + change_reservation(dest, item2resource(itype), r); + } +#endif +#endif +#if MUSEUM_MODULE && defined(TODO) + /* TODO: use a trigger for the museum warden! */ + if (a_find(dest->attribs, &at_warden)) { + warden_add_give(src, dest, itype, r); + } +#endif + handle_event(dest->attribs, "receive", src); + } + handle_event(src->attribs, "give", dest); + } + add_give(src, dest, n, r, item2resource(itype), ord, error); + if (error) return -1; + return 0; +} + +void +give_men(int n, unit * u, unit * u2, struct order * ord) +{ + ship *sh; + int k = 0; + int error = 0; + + if (u2 && u->faction != u2->faction && u->faction->age < GiveRestriction()) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "giverestriction", + "turns", GiveRestriction())); + return; + } else if (u == u2) { + error = 10; + } else if (!u2 && u->race == new_race[RC_SNOTLING]) { + /* snotlings may not be given to the peasants. */ + error = 307; + } else if (u2 && u2->number && (fval(u, UFL_HERO) != fval(u2, UFL_HERO))) { + /* heroes may not be given to non-heroes and vice versa*/ + error = 75; + } else if (unit_has_cursed_item(u) || (u2 && unit_has_cursed_item(u2))) { + error = 78; + } else if (fval(u, UFL_LOCKED) || is_cursed(u->attribs, C_SLAVE, 0)) { + error = 74; + } else if (u2 && fval(u, UFL_HUNGER)) { + /* hungry people cannot be given away */ + error = 73; + } else if (u2 && (fval(u2, UFL_LOCKED)|| is_cursed(u2->attribs, C_SLAVE, 0))) { + error = 75; + } else if (u2 && !ucontact(u2, u)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", "target", u2)); + error = -1; + } else if (u2 && (has_skill(u, SK_MAGIC) || has_skill(u2, SK_MAGIC))) { + /* cannot give units to and from magicians */ + error = 158; + } else if (u2 && (fval(u, UFL_WERE) != fval(u2, UFL_WERE))) { + /* werewolves can't be given to non-werewolves and vice-versa */ + error = 312; + } else if (u2 && u2->number!=0 && u2->race != u->race) { + log_warning(("faction %s attempts to give %s to %s.\n", + itoa36(u->faction->no), u->race->_name[0], + u2->race->_name[1])); + error = 139; + } else if (u2!=NULL && (get_racename(u2->attribs) || get_racename(u->attribs))) { + error = 139; + } else if (u2 && u2->faction!=u->faction && !rule_transfermen()) { + error = 74; + } else { + if (n > u->number) n = u->number; + if (u2 && n+u2->number > UNIT_MAXSIZE) { + n = UNIT_MAXSIZE-u2->number; + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_unit_size", "maxsize", UNIT_MAXSIZE)); + assert(n>=0); + } + if (n == 0) { + error = 96; + } else if (u2 && u->faction != u2->faction) { + if (u2->faction->newbies + n > MAXNEWBIES) { + error = 129; + } else if (u->race != u2->faction->race) { + if (u2->faction->race != new_race[RC_HUMAN]) { + error = 120; + } else if (count_migrants(u2->faction) + n > count_maxmigrants(u2->faction)) { + error = 128; + } + else if (has_limited_skills(u) || has_limited_skills(u2)) { + error = 154; + } else if (u2->number!=0) { + error = 139; + } + } + } + } + + if (u2 && (has_skill(u, SK_ALCHEMY) || has_skill(u2, SK_ALCHEMY))) { + k = count_skill(u2->faction, SK_ALCHEMY); + + /* Falls die Zieleinheit keine Alchemisten sind, werden sie nun + * welche. */ + if (!has_skill(u2, SK_ALCHEMY) && has_skill(u, SK_ALCHEMY)) + k += u2->number; + + /* Wenn in eine Alchemisteneinheit Personen verschoben werden */ + if (has_skill(u2, SK_ALCHEMY) && !has_skill(u, SK_ALCHEMY)) + k += n; + + /* Wenn Parteigrenzen überschritten werden */ + if (u2->faction != u->faction) + k += n; + + /* wird das Alchemistenmaximum ueberschritten ? */ + + if (k > skill_limit(u2->faction, SK_ALCHEMY)) { + error = 156; + } + } + + if (error==0) { + if (u2 && u2->number == 0) { + set_racename(&u2->attribs, get_racename(u->attribs)); + u2->race = u->race; + u2->irace = u->irace; + if (fval(u, UFL_HERO)) fset(u2, UFL_HERO); + else freset(u2, UFL_HERO); + } + + if (u2) { + if (u2->number!=0 && recruit_archetypes()) { + /* must have same set of skills */ + boolean okay = false; + if (u->skill_size==u2->skill_size) { + int i; + for (i=0;i!=u->skill_size;++i) { + int j; + for (j=0;j!=u2->skill_size;++j) { + if (u->skills[i].id==u2->skills[j].id) break; + } + if (j!=u2->skill_size) break; + } + if (i==u->skill_size) okay = true; + } + if (!okay) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "give_cannot_merge", "")); + } + } + + + /* Einheiten von Schiffen können nicht NACH in von + * Nicht-alliierten bewachten Regionen ausführen */ + sh = leftship(u); + if (sh) set_leftship(u2, sh); + + transfermen(u, u2, n); + if (u->faction != u2->faction) { + u2->faction->newbies += n; + } + } else { + if (getunitpeasants) { +#ifdef ORCIFICATION + if (u->race == new_race[RC_SNOTLING] && !fval(u->region, RF_ORCIFIED)) { + attrib *a = a_find(u->region->attribs, &at_orcification); + if (!a) a = a_add(&u->region->attribs, a_new(&at_orcification)); + a->data.i += n; + } +#endif + transfermen(u, NULL, n); + } else { + error = 159; + } + } + } + if (error>0) { + cmistake(u, ord, error, MSG_COMMERCE); + } else if (!u2) { + ADDMSG(&u->faction->msgs, + msg_message("give_person_peasants", "unit amount", u, n)); + } else if (u2->faction!=u->faction) { + message * msg = msg_message("give_person", "unit target amount", u, u2, n); + add_message(&u->faction->msgs, msg); + add_message(&u2->faction->msgs, msg); + msg_release(msg); + } +} + +void +give_unit(unit * u, unit * u2, order * ord) +{ + region * r = u->region; + int n = u->number; + + if (!rule_transfermen() && u->faction!=u2->faction) { + cmistake(u, ord, 74, MSG_COMMERCE); + return; + } + + if (u && unit_has_cursed_item(u)) { + cmistake(u, ord, 78, MSG_COMMERCE); + return; + } + + if (fval(u, UFL_HERO)) { + cmistake(u, ord, 75, MSG_COMMERCE); + return; + } + if (fval(u, UFL_LOCKED) || fval(u, UFL_HUNGER)) { + cmistake(u, ord, 74, MSG_COMMERCE); + return; + } + + if (u2 == NULL) { + if (fval(r->terrain, SEA_REGION)) { + cmistake(u, ord, 152, MSG_COMMERCE); + } else if (getunitpeasants) { + unit *u3; + + for(u3 = r->units; u3; u3 = u3->next) + if(u3->faction == u->faction && u != u3) break; + + if(u3) { + while (u->items) { + item * iold = i_remove(&u->items, u->items); + item * inew = *i_find(&u3->items, iold->type); + if (inew==NULL) i_add(&u3->items, iold); + else { + inew->number += iold->number; + i_free(iold); + } + } + } + give_men(u->number, u, NULL, ord); + cmistake(u, ord, 153, MSG_COMMERCE); + } else { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } + return; + } + + if (!alliedunit(u2, u->faction, HELP_GIVE) && ucontact(u2, u) == 0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", "target", u2)); + return; + } + if (u->number == 0) { + cmistake(u, ord, 105, MSG_COMMERCE); + return; + } + if (u2->faction->newbies + n > MAXNEWBIES) { + cmistake(u, ord, 129, MSG_COMMERCE); + return; + } + if (u->race != u2->faction->race) { + if (u2->faction->race != new_race[RC_HUMAN]) { + cmistake(u, ord, 120, MSG_COMMERCE); + return; + } + if (count_migrants(u2->faction) + u->number > count_maxmigrants(u2->faction)) { + cmistake(u, ord, 128, MSG_COMMERCE); + return; + } + if (has_limited_skills(u)) { + cmistake(u, ord, 154, MSG_COMMERCE); + return; + } + } + if (has_skill(u, SK_MAGIC)) { + sc_mage * mage; + if (count_skill(u2->faction, SK_MAGIC) + u->number > + skill_limit(u2->faction, SK_MAGIC)) + { + cmistake(u, ord, 155, MSG_COMMERCE); + return; + } + mage = get_mage(u); + if (!mage || u2->faction->magiegebiet != mage->magietyp) { + cmistake(u, ord, 157, MSG_COMMERCE); + return; + } + } + if (has_skill(u, SK_ALCHEMY) + && count_skill(u2->faction, SK_ALCHEMY) + u->number > + skill_limit(u2->faction, SK_ALCHEMY)) + { + cmistake(u, ord, 156, MSG_COMMERCE); + return; + } + add_give(u, u2, 1, 1, r_unit, ord, 0); + u_setfaction(u, u2->faction); + u2->faction->newbies += n; +} diff --git a/src/gamecode/give.h b/src/gamecode/give.h index afd456340..9f4e16a64 100644 --- a/src/gamecode/give.h +++ b/src/gamecode/give.h @@ -1,26 +1,26 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - - */ -#ifndef H_GC_GIVE -#define H_GC_GIVE -#ifdef __cplusplus -extern "C" { -#endif - - extern int give_item(int want, const struct item_type * itype, struct unit * src, struct unit * dest, struct order * ord); - extern void give_men(int n, struct unit * u, struct unit * u2, struct order * ord); - extern void give_unit(struct unit * u, struct unit * u2, struct order * ord); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ +#ifndef H_GC_GIVE +#define H_GC_GIVE +#ifdef __cplusplus +extern "C" { +#endif + + extern int give_item(int want, const struct item_type * itype, struct unit * src, struct unit * dest, struct order * ord); + extern void give_men(int n, struct unit * u, struct unit * u2, struct order * ord); + extern void give_unit(struct unit * u, struct unit * u2, struct order * ord); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/items.c b/src/gamecode/items.c index b23fc5cc3..0a6d00a65 100644 --- a/src/gamecode/items.c +++ b/src/gamecode/items.c @@ -1,263 +1,263 @@ -#include -#include -#include "items.h" - -#include "study.h" -#include "curses.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -/* BEGIN studypotion */ -#define MAXGAIN 15 -static int -use_studypotion(struct unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - if (get_keyword(u->thisorder) == K_STUDY) { - skill_t sk; - skill * sv; - - init_tokens(u->thisorder); - skip_token(); - sk = findskill(getstrtoken(), u->faction->locale); - sv = get_skill(u, sk); - - if (sv && sv->level > 2) { - /* TODO: message */ - } else if (study_cost(u, sk)>0) { - /* TODO: message */ - } else { - attrib * a = a_find(u->attribs, &at_learning); - teaching_info * teach; - if (a==NULL) { - a = a_add(&u->attribs, a_new(&at_learning)); - } - teach = (teaching_info*) a->data.v; - if (amount>MAXGAIN) amount = MAXGAIN; - teach->value += amount * 30; - if (teach->value > MAXGAIN * 30) { - teach->value = MAXGAIN * 30; - } - i_change(&u->items, itype, -amount); - return 0; - } - } - return EUNUSABLE; -} -/* END studypotion */ - -/* BEGIN speedsail */ -#define SPEEDSAIL_EFFECT 1 -static int -use_speedsail(struct unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - curse *c; - double effect; - ship * sh = u->ship; - if (!sh) { - cmistake(u, ord, 20, MSG_MOVE); - return -1; - } - - effect = SPEEDSAIL_EFFECT; - c = create_curse(u, &sh->attribs, ct_find("shipspeedup"), 20, INT_MAX, effect, 0); - c_setflag(c, CURSE_NOAGE); - - ADDMSG(&u->faction->msgs, msg_message("use_speedsail", "unit speed", u, SPEEDSAIL_EFFECT)); - use_pooled(u, itype->rtype, GET_DEFAULT, 1); - - return 0; -} -/* END speedsail */ - -/* ------------------------------------------------------------- */ -/* Kann auch von Nichtmagiern benutzt werden, erzeugt eine -* Antimagiezone, die zwei Runden bestehen bleibt */ -static int -use_antimagiccrystal(unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - region * r = u->region; - const resource_type * rt_crystal = NULL; - int i; - - if (rt_crystal == NULL) { - rt_crystal = rt_find("antimagic"); - assert(rt_crystal!=NULL); - } - for (i=0;i!=amount;++i) { - int effect, duration = 2; - double force; - spell *sp = find_spell(M_NONE, "antimagiczone"); - attrib ** ap = &r->attribs; - unused(ord); - assert(sp); - - /* Reduziert die Stärke jedes Spruchs um effect */ - effect = sp->level; - - /* Hält Sprüche bis zu einem summierten Gesamtlevel von power aus. - * Jeder Zauber reduziert die 'Lebenskraft' (vigour) der Antimagiezone - * um seine Stufe */ - force = sp->level * 20; /* Stufe 5 =~ 100 */ - - /* Regionszauber auflösen */ - while (*ap && force > 0) { - curse * c; - attrib * a = *ap; - if (!fval(a->type, ATF_CURSE)) { - do { ap = &(*ap)->next; } while (*ap && a->type==(*ap)->type); - continue; - } - c = (curse*)a->data.v; - - /* Immunität prüfen */ - if (c_flags(c) & CURSE_IMMUNE) { - do { ap = &(*ap)->next; } while (*ap && a->type==(*ap)->type); - continue; - } - - force = destr_curse(c, effect, force); - if(c->vigour <= 0) { - a_remove(&r->attribs, a); - } - if(*ap) ap = &(*ap)->next; - } - - if (force > 0) { - create_curse(u, &r->attribs, ct_find("antimagiczone"), force, duration, effect, 0); - } - } - use_pooled(u, rt_crystal, GET_DEFAULT, amount); - ADDMSG(&u->faction->msgs, msg_message("use_antimagiccrystal", - "unit region", u, r)); - return 0; -} - -static int -use_instantartsculpture(struct unit * u, const struct item_type * itype, - int amount, struct order * ord) -{ - building *b; - - if(u->region->land == NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); - return -1; - } - - b = new_building(bt_find("artsculpture"), u->region, u->faction->locale); - b->size = 100; - - ADDMSG(&u->region->msgs, msg_message("artsculpture_create", "unit region", - u, u->region)); - - use_pooled(u, itype->rtype, GET_DEFAULT, 1); - - return 0; -} - -static int -use_instantartacademy(struct unit * u, const struct item_type * itype, - int amount, struct order * ord) -{ - building *b; - - if(u->region->land == NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); - return -1; - } - - b = new_building(bt_find("artacademy"), u->region, u->faction->locale); - b->size = 100; - - ADDMSG(&u->region->msgs, msg_message( - "artacademy_create", "unit region", u, u->region)); - - use_pooled(u, itype->rtype, GET_DEFAULT, 1); - - return 0; -} - -#define BAGPIPEFRACTION dice_rand("2d4+2") -#define BAGPIPEDURATION dice_rand("2d10+4") - -static int -use_bagpipeoffear(struct unit * u, const struct item_type * itype, - int amount, struct order * ord) -{ - int money; - - if (get_curse(u->region->attribs, ct_find("depression"))) { - cmistake(u, ord, 58, MSG_MAGIC); - return -1; - } - - money = entertainmoney(u->region)/BAGPIPEFRACTION; - change_money(u, money); - rsetmoney(u->region, rmoney(u->region) - money); - - create_curse(u, &u->region->attribs, ct_find("depression"), - 20, BAGPIPEDURATION, 0.0, 0); - - ADDMSG(&u->faction->msgs, msg_message("bagpipeoffear_faction", - "unit region command money", u, u->region, ord, money)); - - ADDMSG(&u->region->msgs, msg_message("bagpipeoffear_region", - "unit money", u, money)); - - return 0; -} - -static int -use_aurapotion50(struct unit * u, const struct item_type * itype, - int amount, struct order * ord) -{ - if (!is_mage(u)) { - cmistake(u, ord, 214, MSG_MAGIC); - return -1; - } - - change_spellpoints(u, 50); - - ADDMSG(&u->faction->msgs, msg_message("aurapotion50", - "unit region command", u, u->region, ord)); - - use_pooled(u, itype->rtype, GET_DEFAULT, 1); - - return 0; -} - - -void -register_itemfunctions(void) -{ - register_demonseye(); - register_item_use(use_antimagiccrystal, "use_antimagiccrystal"); - register_item_use(use_instantartsculpture, "use_instantartsculpture"); - register_item_use(use_studypotion, "use_studypotion"); - register_item_use(use_speedsail, "use_speedsail"); - register_item_use(use_instantartacademy, "use_instantartacademy"); - register_item_use(use_bagpipeoffear, "use_bagpipeoffear"); - register_item_use(use_aurapotion50, "use_aurapotion50"); -} +#include +#include +#include "items.h" + +#include "study.h" +#include "curses.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +/* BEGIN studypotion */ +#define MAXGAIN 15 +static int +use_studypotion(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + if (get_keyword(u->thisorder) == K_STUDY) { + skill_t sk; + skill * sv; + + init_tokens(u->thisorder); + skip_token(); + sk = findskill(getstrtoken(), u->faction->locale); + sv = get_skill(u, sk); + + if (sv && sv->level > 2) { + /* TODO: message */ + } else if (study_cost(u, sk)>0) { + /* TODO: message */ + } else { + attrib * a = a_find(u->attribs, &at_learning); + teaching_info * teach; + if (a==NULL) { + a = a_add(&u->attribs, a_new(&at_learning)); + } + teach = (teaching_info*) a->data.v; + if (amount>MAXGAIN) amount = MAXGAIN; + teach->value += amount * 30; + if (teach->value > MAXGAIN * 30) { + teach->value = MAXGAIN * 30; + } + i_change(&u->items, itype, -amount); + return 0; + } + } + return EUNUSABLE; +} +/* END studypotion */ + +/* BEGIN speedsail */ +#define SPEEDSAIL_EFFECT 1 +static int +use_speedsail(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + curse *c; + double effect; + ship * sh = u->ship; + if (!sh) { + cmistake(u, ord, 20, MSG_MOVE); + return -1; + } + + effect = SPEEDSAIL_EFFECT; + c = create_curse(u, &sh->attribs, ct_find("shipspeedup"), 20, INT_MAX, effect, 0); + c_setflag(c, CURSE_NOAGE); + + ADDMSG(&u->faction->msgs, msg_message("use_speedsail", "unit speed", u, SPEEDSAIL_EFFECT)); + use_pooled(u, itype->rtype, GET_DEFAULT, 1); + + return 0; +} +/* END speedsail */ + +/* ------------------------------------------------------------- */ +/* Kann auch von Nichtmagiern benutzt werden, erzeugt eine +* Antimagiezone, die zwei Runden bestehen bleibt */ +static int +use_antimagiccrystal(unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + region * r = u->region; + const resource_type * rt_crystal = NULL; + int i; + + if (rt_crystal == NULL) { + rt_crystal = rt_find("antimagic"); + assert(rt_crystal!=NULL); + } + for (i=0;i!=amount;++i) { + int effect, duration = 2; + double force; + spell *sp = find_spell(M_NONE, "antimagiczone"); + attrib ** ap = &r->attribs; + unused(ord); + assert(sp); + + /* Reduziert die Stärke jedes Spruchs um effect */ + effect = sp->level; + + /* Hält Sprüche bis zu einem summierten Gesamtlevel von power aus. + * Jeder Zauber reduziert die 'Lebenskraft' (vigour) der Antimagiezone + * um seine Stufe */ + force = sp->level * 20; /* Stufe 5 =~ 100 */ + + /* Regionszauber auflösen */ + while (*ap && force > 0) { + curse * c; + attrib * a = *ap; + if (!fval(a->type, ATF_CURSE)) { + do { ap = &(*ap)->next; } while (*ap && a->type==(*ap)->type); + continue; + } + c = (curse*)a->data.v; + + /* Immunität prüfen */ + if (c_flags(c) & CURSE_IMMUNE) { + do { ap = &(*ap)->next; } while (*ap && a->type==(*ap)->type); + continue; + } + + force = destr_curse(c, effect, force); + if(c->vigour <= 0) { + a_remove(&r->attribs, a); + } + if(*ap) ap = &(*ap)->next; + } + + if (force > 0) { + create_curse(u, &r->attribs, ct_find("antimagiczone"), force, duration, effect, 0); + } + } + use_pooled(u, rt_crystal, GET_DEFAULT, amount); + ADDMSG(&u->faction->msgs, msg_message("use_antimagiccrystal", + "unit region", u, r)); + return 0; +} + +static int +use_instantartsculpture(struct unit * u, const struct item_type * itype, + int amount, struct order * ord) +{ + building *b; + + if(u->region->land == NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); + return -1; + } + + b = new_building(bt_find("artsculpture"), u->region, u->faction->locale); + b->size = 100; + + ADDMSG(&u->region->msgs, msg_message("artsculpture_create", "unit region", + u, u->region)); + + use_pooled(u, itype->rtype, GET_DEFAULT, 1); + + return 0; +} + +static int +use_instantartacademy(struct unit * u, const struct item_type * itype, + int amount, struct order * ord) +{ + building *b; + + if(u->region->land == NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); + return -1; + } + + b = new_building(bt_find("artacademy"), u->region, u->faction->locale); + b->size = 100; + + ADDMSG(&u->region->msgs, msg_message( + "artacademy_create", "unit region", u, u->region)); + + use_pooled(u, itype->rtype, GET_DEFAULT, 1); + + return 0; +} + +#define BAGPIPEFRACTION dice_rand("2d4+2") +#define BAGPIPEDURATION dice_rand("2d10+4") + +static int +use_bagpipeoffear(struct unit * u, const struct item_type * itype, + int amount, struct order * ord) +{ + int money; + + if (get_curse(u->region->attribs, ct_find("depression"))) { + cmistake(u, ord, 58, MSG_MAGIC); + return -1; + } + + money = entertainmoney(u->region)/BAGPIPEFRACTION; + change_money(u, money); + rsetmoney(u->region, rmoney(u->region) - money); + + create_curse(u, &u->region->attribs, ct_find("depression"), + 20, BAGPIPEDURATION, 0.0, 0); + + ADDMSG(&u->faction->msgs, msg_message("bagpipeoffear_faction", + "unit region command money", u, u->region, ord, money)); + + ADDMSG(&u->region->msgs, msg_message("bagpipeoffear_region", + "unit money", u, money)); + + return 0; +} + +static int +use_aurapotion50(struct unit * u, const struct item_type * itype, + int amount, struct order * ord) +{ + if (!is_mage(u)) { + cmistake(u, ord, 214, MSG_MAGIC); + return -1; + } + + change_spellpoints(u, 50); + + ADDMSG(&u->faction->msgs, msg_message("aurapotion50", + "unit region command", u, u->region, ord)); + + use_pooled(u, itype->rtype, GET_DEFAULT, 1); + + return 0; +} + + +void +register_itemfunctions(void) +{ + register_demonseye(); + register_item_use(use_antimagiccrystal, "use_antimagiccrystal"); + register_item_use(use_instantartsculpture, "use_instantartsculpture"); + register_item_use(use_studypotion, "use_studypotion"); + register_item_use(use_speedsail, "use_speedsail"); + register_item_use(use_instantartacademy, "use_instantartacademy"); + register_item_use(use_bagpipeoffear, "use_bagpipeoffear"); + register_item_use(use_aurapotion50, "use_aurapotion50"); +} diff --git a/src/gamecode/items.h b/src/gamecode/items.h index 8dd11a6e1..5de50e512 100644 --- a/src/gamecode/items.h +++ b/src/gamecode/items.h @@ -1,24 +1,24 @@ -/* vi: set ts=2: -+-------------------+ Christian Schlittchen -| | Enno Rehling -| Eressea PBEM host | Katja Zedel -| (c) 1998 - 2003 | Henning Peters -| | Ingo Wilken -+-------------------+ Stefan Reich - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifndef H_KRNL_ITEMS -#define H_KRNL_ITEMS -#ifdef __cplusplus -extern "C" { -#endif - - extern void register_itemfunctions(void); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: ++-------------------+ Christian Schlittchen +| | Enno Rehling +| Eressea PBEM host | Katja Zedel +| (c) 1998 - 2003 | Henning Peters +| | Ingo Wilken ++-------------------+ Stefan Reich + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifndef H_KRNL_ITEMS +#define H_KRNL_ITEMS +#ifdef __cplusplus +extern "C" { +#endif + + extern void register_itemfunctions(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 39a66964b..c5cb1173e 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -1,4223 +1,4223 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#pragma region includes - -#include -#include -#include "laws.h" - -#include -#include - -/* gamecode includes */ -#include "economy.h" -#include "archetype.h" -#include "monster.h" -#include "randenc.h" -#include "spy.h" -#include "study.h" -#include "market.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for volcanoes in emigration (needs a flag) */ -#include - -/* attributes includes */ -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include -#include - -#include - -#pragma endregion - -/* chance that a peasant dies of starvation: */ -#define PEASANT_STARVATION_CHANCE 0.9F -/* Pferdevermehrung */ -#define HORSEGROWTH 4 -/* Wanderungschance pro Pferd */ -#define HORSEMOVE 3 -/* Vermehrungschance pro Baum */ -#define FORESTGROWTH 10000 /* In Millionstel */ - -/** Ausbreitung und Vermehrung */ -#define MAXDEMAND 25 -#define DMRISE 0.1F /* weekly chance that demand goes up */ -#define DMRISEHAFEN 0.2F /* weekly chance that demand goes up with harbor */ - - -/* - exported global symbols ----------------------------------- */ -boolean nobattle = false; -boolean nomonsters = false; -/* ------------------------------------------------------------- */ - -static int -RemoveNMRNewbie(void) { - static int value = -1; - if (value<0) { - value = get_param_int(global.parameters, "nmr.removenewbie", 0); - } - return value; -} - -static void -restart_race(unit *u, const race * rc) -{ - faction * oldf = u->faction; - faction *f = addfaction(oldf->email, oldf->passw, rc, oldf->locale, oldf->subscription); - unit * nu = addplayer(u->region, f); - order ** ordp = &u->orders; - f->subscription = u->faction->subscription; - f->age = u->faction->age; - fset(f, FFL_RESTART); - if (f->subscription) { - sql_print(("UPDATE subscriptions set faction='%s', race='%s' where id=%u;\n", - itoa36(f->no), dbrace(rc), f->subscription)); - } - f->magiegebiet = u->faction->magiegebiet; - f->options = u->faction->options; - free_orders(&nu->orders); - nu->orders = u->orders; - u->orders = NULL; - while (*ordp) { - order * ord = *ordp; - if (get_keyword(ord) != K_RESTART) { - *ordp = ord->next; - ord->next = NULL; - if (u->thisorder == ord) set_order(&u->thisorder, NULL); - } else { - ordp = &ord->next; - } - } - destroyfaction(u->faction); -} - -static void -checkorders(void) -{ - faction *f; - - if (verbosity>=1) puts(" - Warne spaete Spieler..."); - for (f = factions; f; f = f->next) - if (!is_monsters(f) && turn - f->lastorders == NMRTimeout() - 1) - ADDMSG(&f->msgs, msg_message("turnreminder", "")); -} - -static boolean -help_money(const unit * u) -{ - if (u->race->ec_flags & GIVEITEM) return true; - return false; -} - -static void -help_feed(unit * donor, unit * u, int * need_p) -{ - int need = *need_p; - int give = get_money(donor) - lifestyle(donor); - give = MIN(need, give); - - if (give>0) { - change_money(donor, -give); - change_money(u, give); - need -= give; - add_spende(donor->faction, u->faction, give, donor->region); - } - *need_p = need; -} - -static void -get_food(region *r) -{ - plane * pl = rplane(r); - unit *u; - int peasantfood = rpeasants(r)*10; - static int food_rules = -1; - - if (food_rules<0) { - food_rules = get_param_int(global.parameters, "rules.economy.food", 0); - } - - /* 1. Versorgung von eigenen Einheiten. Das vorhandene Silber - * wird zunächst so auf die Einheiten aufgeteilt, dass idealerweise - * jede Einheit genug Silber für ihren Unterhalt hat. */ - - for (u = r->units; u; u = u->next) { - int need = lifestyle(u); - - /* Erstmal zurücksetzen */ - freset(u, UFL_HUNGER); - - if (u->ship && (u->ship->flags&SF_FISHING)) { - unit * v; - int c = 2; - for (v=u;c>0 && v;v=v->next) { - if (v->ship==u->ship) { - int get = 0; - if (v->number<=c) { - get = lifestyle(v); - } else { - get = lifestyle(v) * c / v->number; - } - if (get) { - change_money(v, get); - } - } - c -= v->number; - } - u->ship->flags -= SF_FISHING; - } - - if (food_rules&1) { - faction * owner = region_get_owner(r); - /* if the region is owned, and the owner is nice, then we'll get - * food from the peasants - should not be used with WORK */ - if (owner!=NULL && (get_alliance(owner, u->faction) & HELP_MONEY)) { - int rm = rmoney(r); - int use = MIN(rm, need); - rsetmoney(r, rm-use); - need -= use; - } - } - - need -= get_money(u); - if (need > 0) { - unit *v; - - for (v = r->units; need && v; v = v->next) { - if (v->faction == u->faction && help_money(v)) { - int give = get_money(v) - lifestyle(v); - give = MIN(need, give); - if (give>0) { - change_money(v, -give); - change_money(u, give); - need -= give; - } - } - } - } - } - - /* 2. Versorgung durch Fremde. Das Silber alliierter Einheiten wird - * entsprechend verteilt. */ - for (u = r->units; u; u = u->next) { - int need = lifestyle(u); - faction * f = u->faction; - - need -= MAX(0, get_money(u)); - - if (need > 0) { - unit *v; - - if (food_rules&2) { - /* the owner of the region is the first faction to help out when you're hungry */ - faction * owner = region_get_owner(r); - if (owner && owner!=u->faction) { - for (v=r->units;v;v=v->next) { - if (v->faction==owner && alliedunit(v, f, HELP_MONEY) && help_money(v)) { - help_feed(v, u, &need); - break; - } - } - } - } - for (v = r->units; need && v; v = v->next) { - if (v->faction != f && alliedunit(v, f, HELP_MONEY) && help_money(v)) { - help_feed(v, u, &need); - } - } - - /* Die Einheit hat nicht genug Geld zusammengekratzt und - * nimmt Schaden: */ - if (need > 0) { - int lspp = lifestyle(u)/u->number; - if (lspp > 0) { - int number = (need+lspp-1)/lspp; - if (hunger(number, u)) fset(u, UFL_HUNGER); - } - } - } - } - - /* 3. bestimmen, wie viele Bauern gefressen werden. - * bei fehlenden Bauern den Dämon hungern lassen - */ - for (u = r->units; u; u = u->next) { - if (u->race == new_race[RC_DAEMON]) { - unit * donor = r->units; - int hungry = u->number; - - while (donor!=NULL && hungry>0) { - /* always start with the first known unit that may have some blood */ - static const struct potion_type * pt_blood; - if (pt_blood==NULL) { - const item_type * it_blood = it_find("peasantblood"); - if (it_blood) pt_blood = it_blood->rtype->ptype; - } - if (pt_blood!=NULL) { - while (donor!=NULL) { - if (donor->race==new_race[RC_DAEMON]) { - if (get_effect(donor, pt_blood)) { - /* if he's in our faction, drain him: */ - if (donor->faction==u->faction) break; - } - } - donor = donor->next; - } - if (donor != NULL) { - int blut = get_effect(donor, pt_blood); - blut = MIN(blut, hungry); - change_effect(donor, pt_blood, -blut); - hungry -= blut; - } - } - } - if (pl == NULL || !fval(pl, PFL_NOFEED)) { - if (peasantfood>=hungry) { - peasantfood -= hungry; - hungry = 0; - } else { - hungry -= peasantfood; - peasantfood = 0; - } - if (hungry > 0) { - static int demon_hunger = -1; - if (demon_hunger<0) { - demon_hunger = get_param_int(global.parameters, "hunger.demons", 0); - } - if (demon_hunger==0) { - /* nicht gefütterte dämonen hungern */ -#ifdef PEASANT_HUNGRY_DAEMONS_HAVE_FULL_SKILLS - /* wdw special rule */ - hunger(hungry, u); -#else - if (hunger(hungry, u)) fset(u, UFL_HUNGER); -#endif - /* used to be: hunger(hungry, u); */ - } else { - /* no damage, but set the hungry-flag */ - fset(u, UFL_HUNGER); - } - } - } - } - } - rsetpeasants(r, peasantfood/10); - - /* 3. Von den überlebenden das Geld abziehen: */ - for (u = r->units; u; u = u->next) { - int need = MIN(get_money(u), lifestyle(u)); - change_money(u, -need); - } -} - -static void -age_unit(region * r, unit * u) -{ - if (u->race == new_race[RC_SPELL]) { - if (--u->age <= 0) { - remove_unit(&r->units, u); - } - } else { - ++u->age; - if (u->number>0 && u->race->age) { - u->race->age(u); - } - } -#ifdef ASTRAL_ITEM_RESTRICTIONS - if (u->region && is_astral(u->region)) { - item ** itemp = &u->items; - while (*itemp) { - item * itm = *itemp; - if ((itm->type->flags & ITF_NOTLOST) == 0) { - if (itm->type->flags & (ITF_BIG|ITF_ANIMAL|ITF_CURSED)) { - ADDMSG(&u->faction->msgs, msg_message("itemcrumble", "unit region item amount", - u, u->region, itm->type->rtype, itm->number)); - i_free(i_remove(itemp, itm)); - continue; - } - } - itemp=&itm->next; - } - } -#endif -} - - -static void -live(region * r) -{ - unit **up = &r->units; - - get_food(r); - - while (*up) { - unit * u = *up; - /* IUW: age_unit() kann u loeschen, u->next ist dann - * undefiniert, also muessen wir hier schon das nächste - * Element bestimmen */ - - int effect = get_effect(u, oldpotiontype[P_FOOL]); - if (effect > 0) { /* Trank "Dumpfbackenbrot" */ - skill * sv = u->skills, * sb = NULL; - while (sv!=u->skills+u->skill_size) { - if (sb==NULL || skill_compare(sv, sb)>0) { - sb = sv; - } - ++sv; - } - /* bestes Talent raussuchen */ - if (sb!=NULL) { - int weeks = MIN(effect, u->number); - reduce_skill(u, sb, weeks); - ADDMSG(&u->faction->msgs, msg_message("dumbeffect", - "unit weeks skill", u, weeks, (skill_t)sb->id)); - } /* sonst Glück gehabt: wer nix weiß, kann nix vergessen... */ - change_effect(u, oldpotiontype[P_FOOL], -effect); - } - age_unit(r, u); - if (*up==u) up=&u->next; - } -} - -/* - * This procedure calculates the number of emigrating peasants for the given - * region r. There are two incentives for peasants to emigrate: - * 1) They prefer the less crowded areas. - * Example: mountains, 700 peasants (max 1000), 70% inhabited - * plain, 5000 peasants (max 10000), 50% inhabited - * 700*(PEASANTSWANDER_WEIGHT/100)*((70-50)/100) peasants wander - * from mountains to plain. - * Effect : peasents will leave densely populated regions. - * 2) Peasants prefer richer neighbour regions. - * Example: region A, 700 peasants, wealth $10500, $15 per head - * region B, 2500 peasants, wealth $25000, $10 per head - * Some peasants will emigrate from B to A because $15 > $10 - * exactly: 2500*(PEASANTSGREED_WEIGHT1/100)*((15-10)/100) - * Not taken in consideration: - * - movement because of monsters. - * - movement because of wars - * - movement because of low loyalty relating to present parties. - */ - -#define MAX_EMIGRATION(p) ((p)/MAXDIRECTIONS) -#define MAX_IMMIGRATION(p) ((p)*2/3) - -static void -calculate_emigration(region *r) -{ - int i; - int maxp = maxworkingpeasants(r); - int rp = rpeasants(r); - int max_immigrants = MAX_IMMIGRATION(maxp-rp); - - if (r->terrain == newterrain(T_VOLCANO) || r->terrain == newterrain(T_VOLCANO_SMOKING)) { - max_immigrants = max_immigrants/10; - } - - for (i = 0; max_immigrants>0 && i != MAXDIRECTIONS; i++) { - int dir = (turn+i) % MAXDIRECTIONS; - region *rc = rconnect(r, (direction_t)dir); - - if (rc != NULL && fval(rc->terrain, LAND_REGION)) { - int rp2 = rpeasants(rc); - int maxp2 = maxworkingpeasants(rc); - int max_emigration = MAX_EMIGRATION(rp2-maxp2); - - if (max_emigration>0) { - max_emigration = MIN(max_emigration, max_immigrants); - r->land->newpeasants += max_emigration; - rc->land->newpeasants -= max_emigration; - max_immigrants -= max_emigration; - } - } - } -} - -/** Bauern vermehren sich */ - -static void -peasants(region * r) -{ - int peasants = rpeasants(r); - int money = rmoney(r); - int maxp = production(r) * MAXPEASANTS_PER_AREA; - int n, satiated; - int dead = 0; - - /* Bis zu 1000 Bauern können Zwillinge bekommen oder 1000 Bauern - * wollen nicht! */ - - if (peasants>0) { - int glueck = 0; - double fraction = peasants * 0.0001F * PEASANTGROWTH; - int births = (int)fraction; - attrib * a = a_find(r->attribs, &at_peasantluck); - - if (rng_double()<(fraction-births)) { - /* because we don't want regions that never grow pga. rounding. */ - ++births; - } - if (a!=NULL) { - glueck = a->data.i * 1000; - } - - for (n = peasants; n; --n) { - int chances = 0; - - if (glueck>0) { - --glueck; - chances += PEASANTLUCK; - } - - while (chances--) { - if (rng_int() % 10000 < PEASANTGROWTH) { - /* Only raise with 75% chance if peasants have - * reached 90% of maxpopulation */ - if (peasants/(float)maxp < 0.9 || chance(PEASANTFORCE)) { - ++births; - } - } - } - } - peasants += births; - } - - /* Alle werden satt, oder halt soviele für die es auch Geld gibt */ - - satiated = MIN(peasants, money / maintenance_cost(NULL)); - rsetmoney(r, money - satiated * maintenance_cost(NULL)); - - /* Von denjenigen, die nicht satt geworden sind, verhungert der - * Großteil. dead kann nie größer als rpeasants(r) - satiated werden, - * so dass rpeasants(r) >= 0 bleiben muß. */ - - /* Es verhungert maximal die unterernährten Bevölkerung. */ - - n = MIN(peasants - satiated, rpeasants(r)); - dead += (int)(0.5F + n * PEASANT_STARVATION_CHANCE); - - if (dead > 0) { - message * msg = add_message(&r->msgs, msg_message("phunger", "dead", dead)); - msg_release(msg); - peasants -= dead; - } - - rsetpeasants(r, peasants); -} - -/* ------------------------------------------------------------- */ - -typedef struct migration { - struct migration * next; - region * r; - int horses; - int trees; -} migration; - -#define MSIZE 1023 -migration * migrants[MSIZE]; -migration * free_migrants; - -static migration * -get_migrants(region * r) -{ - int key = reg_hashkey(r); - int index = key % MSIZE; - migration * m = migrants[index]; - while (m && m->r != r) - m = m->next; - if (m == NULL) { - /* Es gibt noch keine Migration. Also eine erzeugen - */ - m = free_migrants; - if (!m) m = calloc(1, sizeof(migration)); - else { - free_migrants = free_migrants->next; - m->horses = 0; - m->trees = 0; - } - m->r = r; - m->next = migrants[index]; - migrants[index] = m; - } - return m; -} - -static void -migrate(region * r) -{ - int key = reg_hashkey(r); - int index = key % MSIZE; - migration ** hp = &migrants[index]; - fset(r, RF_MIGRATION); - while (*hp && (*hp)->r != r) hp = &(*hp)->next; - if (*hp) { - migration * m = *hp; - rsethorses(r, rhorses(r) + m->horses); - /* Was macht das denn hier? - * Baumwanderung wird in trees() gemacht. - * wer fragt das? Die Baumwanderung war abhängig von der - * Auswertungsreihenfolge der regionen, - * das hatte ich geändert. jemand hat es wieder gelöscht, toll. - * ich habe es wieder aktiviert, muß getestet werden. - */ - *hp = m->next; - m->next = free_migrants; - free_migrants = m; - } -} - -static void -horses(region * r) -{ - int horses, maxhorses; - direction_t n; - - /* Logistisches Wachstum, Optimum bei halbem Maximalbesatz. */ - maxhorses = maxworkingpeasants(r)/10; - maxhorses = MAX(0, maxhorses); - horses = rhorses(r); - if (horses > 0) { - if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { - rsethorses(r, (int)(horses*0.9F)); - } else if (maxhorses) { - int i; - double growth = (RESOURCE_QUANTITY * HORSEGROWTH * 200 * (maxhorses-horses))/maxhorses; - - if (growth>0) { - if (a_find(r->attribs, &at_horseluck)) growth *= 2; - /* printf("Horses: <%d> %d -> ", growth, horses); */ - i = (int)(0.5F + (horses * 0.0001F) * growth); - /* printf("%d\n", horses); */ - rsethorses(r, horses + i); - } - } - } - - /* Pferde wandern in Nachbarregionen. - * Falls die Nachbarregion noch berechnet - * werden muß, wird eine migration-Struktur gebildet, - * die dann erst in die Berechnung der Nachbarstruktur einfließt. - */ - - for(n = 0; n != MAXDIRECTIONS; n++) { - region * r2 = rconnect(r, n); - if (r2 && fval(r2->terrain, WALK_INTO)) { - int pt = (rhorses(r) * HORSEMOVE)/100; - pt = (int)normalvariate(pt, pt/4.0); - pt = MAX(0, pt); - if (fval(r2, RF_MIGRATION)) - rsethorses(r2, rhorses(r2) + pt); - else { - migration * nb; - /* haben wir die Migration schonmal benutzt? - * wenn nicht, müssen wir sie suchen. - * Wandernde Pferde vermehren sich nicht. - */ - nb = get_migrants(r2); - nb->horses += pt; - } - /* Wandernde Pferde sollten auch abgezogen werden */ - rsethorses(r, rhorses(r) - pt); - } - } - assert(rhorses(r) >= 0); -} - -static int -count_race(const region *r, const race *rc) -{ - unit *u; - int c = 0; - - for(u = r->units; u; u=u->next) - if(u->race == rc) c += u->number; - - return c; -} - -extern struct attrib_type at_germs; - -static void -growing_trees_e3(region * r, const int current_season, const int last_weeks_season) -{ - const static int transform[4][3] = { - { -1, -1, 0 }, - { TREE_SEED, TREE_SAPLING, 2 }, - { TREE_SAPLING, TREE_TREE, 2 }, - { TREE_TREE, TREE_SEED, 2 } - }; - - if (r->land && current_season!=last_weeks_season && transform[current_season][2]) { - int src_type = transform[current_season][0]; - int dst_type = transform[current_season][1]; - int src = rtrees(r, src_type); - int dst = rtrees(r, dst_type); - int grow = src/transform[current_season][2]; - if (grow>0) { - if (src_type!=TREE_TREE) { - rsettrees(r, src_type, src-grow); - } - rsettrees(r, dst_type, dst+grow); - - if (dst_type==TREE_SEED && r->terrain->size) { - region * rn[MAXDIRECTIONS]; - int d; - double fgrow = grow/(double)MAXDIRECTIONS; - - get_neighbours(r, rn); - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rx = rn[d]; - if (rx && rx->land) { - double scale = 1.0; - int g; - double fg, ch; - int seeds = rtrees(rx, dst_type); - - if (r->terrain->size>rx->terrain->size) { - scale = (scale * rx->terrain->size)/r->terrain->size; - } - fg = scale * fgrow; - g = (int)fg; - ch = fg - g; - if (chance(ch)) ++g; - if (g>0) { - rsettrees(rx, dst_type, seeds + g); - } - } - } - } - } - } -} - -static void -growing_trees(region * r, const int current_season, const int last_weeks_season) -{ - int growth, grownup_trees, i, seeds, sprout; - direction_t d; - attrib *a; - - if(current_season == SEASON_SUMMER || current_season == SEASON_AUTUMN) { - double seedchance = 0.01F * RESOURCE_QUANTITY; - int elves = count_race(r, new_race[RC_ELF]); - - a = a_find(r->attribs, &at_germs); - if(a && last_weeks_season == SEASON_SPRING) { - /* ungekeimte Samen bleiben erhalten, Sprößlinge wachsen */ - sprout = MIN(a->data.sa[1], rtrees(r, 1)); - /* aus dem gesamt Sprößlingepool abziehen */ - rsettrees(r, 1, rtrees(r, 1) - sprout); - /* zu den Bäumen hinzufügen */ - rsettrees(r, 2, rtrees(r, 2) + sprout); - - a_removeall(&r->attribs, &at_germs); - } - - if(is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { - rsettrees(r, 1, (int)(rtrees(r, 1) * 0.9)); - rsettrees(r, 2, (int)(rtrees(r, 2) * 0.9)); - return; - } - - if (production(r) <= 0) return; - - /* Grundchance 1.0% */ - /* Jeder Elf in der Region erhöht die Chance marginal */ - elves = MIN(elves, (production(r)*MAXPEASANTS_PER_AREA)/8); - if (elves) { - seedchance += 1.0-pow(0.99999, elves * RESOURCE_QUANTITY); - } - grownup_trees = rtrees(r, 2); - seeds = 0; - - if (grownup_trees>0) { - double remainder = seedchance*grownup_trees; - seeds = (int)(remainder); - remainder -= seeds; - if (chance(remainder)) { - ++seeds; - } - if (seeds>0) { - seeds += rtrees(r, 0); - rsettrees(r, 0, seeds); - } - } - - /* Bäume breiten sich in Nachbarregionen aus. */ - - /* Gesamtzahl der Samen: - * bis zu 6% (FORESTGROWTH*3) der Bäume samen in die Nachbarregionen */ - seeds = (rtrees(r, 2) * FORESTGROWTH * 3)/1000000; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * r2 = rconnect(r, d); - if (r2 && fval(r2->terrain, LAND_REGION) && r2->terrain->size) { - /* Eine Landregion, wir versuchen Samen zu verteilen: - * Die Chance, das Samen ein Stück Boden finden, in dem sie - * keimen können, hängt von der Bewuchsdichte und der - * verfügbaren Fläche ab. In Gletschern gibt es weniger - * Möglichkeiten als in Ebenen. */ - sprout = 0; - seedchance = (1000 * maxworkingpeasants(r2)) / r2->terrain->size; - for(i=0; iattribs, C_CURSED_BY_THE_GODS, 0)) return; - - /* in at_germs merken uns die Zahl der Samen und Sprößlinge, die - * dieses Jahr älter werden dürfen, damit nicht ein Same im selben - * Zyklus zum Baum werden kann */ - a = a_find(r->attribs, &at_germs); - if(!a) { - a = a_add(&r->attribs, a_new(&at_germs)); - a->data.sa[0] = (short)rtrees(r, 0); - a->data.sa[1] = (short)rtrees(r, 1); - } - /* wir haben 6 Wochen zum wachsen, jeder Same/Sproß hat 18% Chance - * zu wachsen, damit sollten nach 5-6 Wochen alle gewachsen sein */ - growth = 1800; - - /* Samenwachstum */ - - /* Raubbau abfangen, es dürfen nie mehr Samen wachsen, als aktuell - * in der Region sind */ - seeds = MIN(a->data.sa[0], rtrees(r, 0)); - sprout = 0; - - for(i=0;idata.sa[0] = (short)(seeds - sprout); - /* aus dem gesamt Samenpool abziehen */ - rsettrees(r, 0, rtrees(r, 0) - sprout); - /* zu den Sprößlinge hinzufügen */ - rsettrees(r, 1, rtrees(r, 1) + sprout); - - /* Baumwachstum */ - - /* hier gehen wir davon aus, das Jungbäume nicht ohne weiteres aus - * der Region entfernt werden können, da Jungbäume in der gleichen - * Runde nachwachsen, wir also nicht mehr zwischen diesjährigen und - * 'alten' Jungbäumen unterscheiden könnten */ - sprout = MIN(a->data.sa[1], rtrees(r, 1)); - grownup_trees = 0; - - for(i=0;idata.sa[1] = (short)(sprout - grownup_trees); - /* aus dem gesamt Sprößlingepool abziehen */ - rsettrees(r, 1, rtrees(r, 1) - grownup_trees); - /* zu den Bäumen hinzufügen */ - rsettrees(r, 2, rtrees(r, 2) + grownup_trees); - } -} - -static void -growing_herbs(region * r, const int current_season, const int last_weeks_season) -{ - /* Jetzt die Kräutervermehrung. Vermehrt wird logistisch: - * - * Jedes Kraut hat eine Wahrscheinlichkeit von (100-(vorhandene - * Kräuter))% sich zu vermehren. */ - if (current_season != SEASON_WINTER) { - int i; - for (i = rherbs(r); i > 0; i--) { - if (rng_int()%100 < (100-rherbs(r))) rsetherbs(r, (short)(rherbs(r)+1)); - } - } -} - -void -demographics(void) -{ - region *r; - static int last_weeks_season = -1; - static int current_season = -1; - - if (current_season<0) { - gamedate date; - get_gamedate(turn, &date); - current_season = date.season; - get_gamedate(turn-1, &date); - last_weeks_season = date.season; - } - - for (r = regions; r; r = r->next) { - ++r->age; /* also oceans. no idea why we didn't always do that */ - live(r); - /* check_split_dragons(); */ - - if (!fval(r->terrain, SEA_REGION)) { - /* die Nachfrage nach Produkten steigt. */ - struct demand * dmd; - if (r->land) { - static int plant_rules = -1; - - if (plant_rules<0) { - plant_rules = get_param_int(global.parameters, "rules.economy.grow", 0); - } - for (dmd=r->land->demands;dmd;dmd=dmd->next) { - if (dmd->value>0 && dmd->value < MAXDEMAND) { - float rise = DMRISE; - if (buildingtype_exists(r, bt_find("harbour"), true)) rise = DMRISEHAFEN; - if (rng_double()value; - } - } - /* Seuchen erst nachdem die Bauern sich vermehrt haben - * und gewandert sind */ - - calculate_emigration(r); - peasants(r); - if (r->age>20) { - plagues(r, false); - } - horses(r); - if (plant_rules==0) { /* E1 */ - growing_trees(r, current_season, last_weeks_season); - growing_herbs(r, current_season, last_weeks_season); - } else { /* E3 */ - growing_trees_e3(r, current_season, last_weeks_season); - } - } - - update_resources(r); - if (r->land) migrate(r); - } - } - while (free_migrants) { - migration * m = free_migrants->next; - free(free_migrants); - free_migrants = m; - }; - if (verbosity>=1) putchar('\n'); - - remove_empty_units(); - - if (verbosity>=1) puts(" - Einwanderung..."); - for (r = regions; r; r = r->next) { - if (r->land && r->land->newpeasants) { - int rp = rpeasants(r) + r->land->newpeasants; - rsetpeasants(r, MAX(0, rp)); - } - } - - checkorders(); -} -/* ------------------------------------------------------------- */ - -static int -modify(int i) -{ - int c; - - c = i * 2 / 3; - - if (c >= 1) { - return (c + rng_int() % c); - } else { - return (i); - } -} - -static void -inactivefaction(faction * f) -{ - FILE *inactiveFILE; - char zText[128]; - - sprintf(zText, "%s/%s", datapath(), "inactive"); - inactiveFILE = fopen(zText, "a"); - - if (inactiveFILE) { - fprintf(inactiveFILE, "%s:%s:%d:%d\n", - factionid(f), - LOC(default_locale, rc_name(f->race, 1)), - modify(count_all(f)), - turn - f->lastorders); - - fclose(inactiveFILE); - } -} - -static void -transfer_faction(faction *f, faction *f2) -{ - unit *u, *un; - - for (u = f->units; u;) { - un = u->nextF; - if(!unit_has_cursed_item(u) - && !has_skill(u, SK_MAGIC) - && !has_skill(u, SK_ALCHEMY)) { - u_setfaction(u, f2); - } - u = un; - } -} - -static int -restart_cmd(unit * u, struct order * ord) -{ - init_tokens(ord); - skip_token(); /* skip keyword */ - - if (!fval(u->region->terrain, LAND_REGION)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); - } else { - const char * s_race = getstrtoken(), * s_pass; - const race * frace = findrace(s_race, u->faction->locale); - - if (!frace) { - frace = u->faction->race; - s_pass = s_race; - } else { - s_pass = getstrtoken(); - } - - if (u->faction->age > 3 && fval(u->faction, FFL_RESTART)) { - cmistake(u, ord, 314, MSG_EVENT); - return 0; - } - - if (/* frace != u->faction->race && */ u->faction->age < 81) { - cmistake(u, ord, 241, MSG_EVENT); - return 0; - } - - if (!playerrace(frace)) { - cmistake(u, ord, 243, MSG_EVENT); - return 0; - } - - if (!checkpasswd(u->faction, (const char *)s_pass, false)) { - cmistake(u, ord, 86, MSG_EVENT); - log_warning(("RESTART with wrong password, faction %s, pass %s\n", - factionid(u->faction), s_pass)); - return 0; - } - restart_race(u, frace); - return -1; - } - return 0; -} - -static boolean -EnhancedQuit(void) -{ - static int value = -1; - if (value<0) { - const char * str = get_param(global.parameters, "alliance.transferquit"); - value = (str!=0 && strcmp(str, "true")==0); - } - return value; -} - -static int -quit_cmd(unit * u, struct order * ord) -{ - faction * f = u->faction; - const char * passwd; - - init_tokens(ord); - skip_token(); /* skip keyword */ - - passwd = getstrtoken(); - if (checkpasswd(f, (const char *)passwd, false)) { - if (EnhancedQuit()) { - int f2_id = getid(); - if (f2_id>0) { - faction *f2 = findfaction(f2_id); - - if(f2 == NULL) { - cmistake(u, ord, 66, MSG_EVENT); - return 0; - } else if (!u->faction->alliance || u->faction->alliance != f2->alliance) { - cmistake(u, ord, 315, MSG_EVENT); - return 0; - } else if(!alliedfaction(NULL, f, f2, HELP_MONEY)) { - cmistake(u, ord, 316, MSG_EVENT); - return 0; - } else { - variant var; - var.i = f2_id; - a_add(&f->attribs, object_create("quit", TINTEGER, var)); - } - } - } - fset(f, FFL_QUIT); - } else { - char buffer[64]; - write_order(ord, buffer, sizeof(buffer)); - cmistake(u, ord, 86, MSG_EVENT); - log_warning(("QUIT with illegal password for faction %s: %s\n", - factionid(f), buffer)); - } - return 0; -} - -static void -quit(void) -{ - faction ** fptr = &factions; - while (*fptr) { - faction * f = *fptr; - if (f->flags & FFL_QUIT) { - if (EnhancedQuit()) { - /* this doesn't work well (use object_name()) */ - attrib * a = a_find(f->attribs, &at_object); - if (a) { - variant var; - object_type type; - var.i = 0; - object_get(a, &type, &var); - assert(var.i && type==TINTEGER); - if (var.i) { - int f2_id = var.i; - faction *f2 = findfaction(f2_id); - - assert(f2_id>0); - assert(f2!=NULL); - transfer_faction(f, f2); - } - } - } - destroyfaction(f); - } - if (*fptr==f) fptr=&f->next; - } -} - -int dropouts[2]; -int * age = NULL; - -static void -nmr_death(faction * f) -{ - static int rule = -1; - if (rule<0) rule = get_param_int(global.parameters, "rules.nmr.destroy", 0); - if (rule) { - unit * u; - for (u=f->units;u;u=u->nextF) { - if (u->building && fval(u, UFL_OWNER)) { - remove_building(&u->region->buildings, u->building); - } - } - } -} - -static void -parse_restart(void) -{ - region *r; - faction *f; - - /* Sterben erst nachdem man allen anderen gegeben hat - bzw. man kann - * alles machen, was nicht ein dreißigtägiger Befehl ist. */ - - for (r = regions; r; r = r->next) { - unit * u, * un; - for (u = r->units; u;) { - order * ord; - - un = u->next; - for (ord = u->orders; ord!=NULL; ord = ord->next) { - if (get_keyword(ord) == K_RESTART) { - if (u->number > 0) { - if (restart_cmd(u, ord)!=0) { - break; - } - } - } - } - u = un; - } - } - - if (verbosity>=1) puts(" - beseitige Spieler, die sich zu lange nicht mehr gemeldet haben..."); - - for (f = factions; f; f = f->next) { - if(fval(f, FFL_NOIDLEOUT)) f->lastorders = turn; - if (NMRTimeout()>0 && turn - f->lastorders >= NMRTimeout()) { - nmr_death(f); - destroyfaction(f); - continue; - } - if (fval(f, FFL_OVERRIDE)) { - free(f->override); - f->override = strdup(itoa36(rng_int())); - freset(f, FFL_OVERRIDE); - } - if (turn!=f->lastorders) { - char info[256]; - sprintf(info, "%d Einheiten, %d Personen, %d Silber", - f->no_units, f->num_total, f->money); - if (f->subscription) { - sql_print(("UPDATE subscriptions SET lastturn=%d, password='%s', info='%s' WHERE id=%u;\n", - f->lastorders, f->override, info, f->subscription)); - } - } else { - if (f->subscription) { - sql_print(("UPDATE subscriptions SET status='ACTIVE', lastturn=%d, firstturn=greatest(firstturn,%d), password='%s' WHERE id=%u;\n", - f->lastorders, f->lastorders-f->age, - f->override, f->subscription)); - } - } - - if (NMRTimeout()>0 && turn - f->lastorders >= (NMRTimeout() - 1)) { - inactivefaction(f); - continue; - } - } - if (verbosity>=1) { - puts(" - beseitige Spieler, die sich nach der Anmeldung nicht " - "gemeldet haben..."); - } - - age = calloc(MAX(4,turn+1), sizeof(int)); - for (f = factions; f; f = f->next) if (!is_monsters(f)) { - if (RemoveNMRNewbie() && !fval(f, FFL_NOIDLEOUT)) { - if (f->age>=0 && f->age <= turn) ++age[f->age]; - if (f->age == 2 || f->age == 3) { - if (f->lastorders == turn - 2) { - destroyfaction(f); - ++dropouts[f->age-2]; - continue; - } - } - } - } - - if (verbosity>=1) puts(" - beseitige leere Einheiten und leere Parteien..."); - remove_empty_units(); -} -/* ------------------------------------------------------------- */ - -/* HELFE partei [] [NICHT] */ - -static int -ally_cmd(unit * u, struct order * ord) -{ - ally * sf, ** sfp; - faction *f; - int keyword, not_kw; - const char *s; - - init_tokens(ord); - skip_token(); - f = getfaction(); - - if (f==NULL || is_monsters(f)) { - cmistake(u, ord, 66, MSG_EVENT); - return 0; - } - if (f == u->faction) return 0; - - s = getstrtoken(); - - if (!s[0]) - keyword = P_ANY; - else - keyword = findparam(s, u->faction->locale); - - sfp = &u->faction->allies; - if (fval(u, UFL_GROUP)) { - attrib * a = a_find(u->attribs, &at_group); - if (a) sfp = &((group*)a->data.v)->allies; - } - for (sf=*sfp; sf; sf = sf->next) - if (sf->faction == f) - break; /* Gleich die passende raussuchen, wenn vorhanden */ - - not_kw = getparam(u->faction->locale); /* HELFE partei [modus] NICHT */ - - if (!sf) { - if (keyword == P_NOT || not_kw == P_NOT) { - /* Wir helfen der Partei gar nicht... */ - return 0; - } else { - sf = calloc(1, sizeof(ally)); - sf->faction = f; - sf->status = 0; - addlist(sfp, sf); - } - } - switch (keyword) { - case P_NOT: - sf->status = 0; - break; - - case NOPARAM: - cmistake(u, ord, 137, MSG_EVENT); - return 0; - - case P_ANY: - if (not_kw == P_NOT) - sf->status = 0; - else - sf->status = HELP_ALL; - break; - - case P_TRAVEL: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_TRAVEL); - else - sf->status = sf->status | HELP_TRAVEL; - break; - - case P_GIVE: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_GIVE); - else - sf->status = sf->status | HELP_GIVE; - break; - - case P_MONEY: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_MONEY); - else - sf->status = sf->status | HELP_MONEY; - break; - - case P_FIGHT: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_FIGHT); - else - sf->status = sf->status | HELP_FIGHT; - break; - - case P_FACTIONSTEALTH: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_FSTEALTH); - else - sf->status = sf->status | HELP_FSTEALTH; - break; - - case P_GUARD: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_GUARD); - else - sf->status = sf->status | HELP_GUARD; - break; - } - - sf->status &= HelpMask(); - - if (sf->status == 0) { /* Alle HELPs geloescht */ - removelist(sfp, sf); - } - return 0; -} - -static struct local_names * pnames; - -static void -init_prefixnames(void) -{ - int i; - for (i=0;localenames[i];++i) { - const struct locale * lang = find_locale(localenames[i]); - boolean exist = false; - struct local_names * in = pnames; - - while (in!=NULL) { - if (in->lang==lang) { - exist = true; - break; - } - in = in->next; - } - if (in==NULL) in = calloc(sizeof(local_names), 1); - in->next = pnames; - in->lang = lang; - - if (!exist) { - int key; - for (key=0;race_prefixes[key];++key) { - variant var; - const char * pname = locale_string(lang, mkname("prefix", race_prefixes[key])); - if (findtoken(&in->names, pname, &var)==E_TOK_NOMATCH || var.i!=key) { - var.i = key; - addtoken(&in->names, pname, var); - addtoken(&in->names, locale_string(lang, mkname("prefix", race_prefixes[key])), var); - } - } - } - pnames = in; - } -} - -static int -prefix_cmd(unit * u, struct order * ord) -{ - attrib **ap; - const char *s; - local_names * in = pnames; - variant var; - const struct locale * lang = u->faction->locale; - - while (in!=NULL) { - if (in->lang==lang) break; - in = in->next; - } - if (in==NULL) { - init_prefixnames(); - for (in=pnames;in->lang!=lang;in=in->next) ; - } - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - if (!*s) { - attrib *a = NULL; - if (fval(u, UFL_GROUP)) { - a = a_find(u->attribs, &at_group); - } - if (a) { - group * g = (group*)a->data.v; - a_removeall(&g->attribs, &at_raceprefix); - } else { - a_removeall(&u->faction->attribs, &at_raceprefix); - } - return 0; - } - - if (findtoken(&in->names, s, &var)==E_TOK_NOMATCH) { - return 0; - } else if (race_prefixes[var.i] == NULL) { - cmistake(u, ord, 299, MSG_EVENT); - } else { - ap = &u->faction->attribs; - if (fval(u, UFL_GROUP)) { - attrib * a = a_find(u->attribs, &at_group); - group * g = (group*)a->data.v; - if (a) ap = &g->attribs; - } - set_prefix(ap, race_prefixes[var.i]); - } - return 0; -} - - -static cmp_building_cb -get_cmp_region_owner(void) -{ - if (rule_region_owners()) { - return &cmp_current_owner; - } else { - return &cmp_wage; - } -} - -static int -display_cmd(unit * u, struct order * ord) -{ - building * b = u->building; - char **s = NULL; - region * r = u->region; - - init_tokens(ord); - skip_token(); - - switch (getparam(u->faction->locale)) { - case P_BUILDING: - case P_GEBAEUDE: - if (!b) { - cmistake(u, ord, 145, MSG_PRODUCE); - break; - } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 5, MSG_PRODUCE); - break; - } - if (!fval(b->type, BTF_NAMECHANGE) && b->display && b->display[0] != 0) { - cmistake(u, ord, 278, MSG_EVENT); - break; - } - s = &b->display; - break; - - case P_SHIP: - if (!u->ship) { - cmistake(u, ord, 144, MSG_PRODUCE); - break; - } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 12, MSG_PRODUCE); - break; - } - s = &u->ship->display; - break; - - case P_UNIT: - s = &u->display; - break; - - case P_PRIVAT: - { - const char *d = getstrtoken(); - if(d == NULL || *d == 0) { - usetprivate(u, NULL); - } else { - usetprivate(u, d); - } - } - break; - - case P_REGION: - if (!b) { - cmistake(u, ord, 145, MSG_EVENT); - break; - } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 148, MSG_EVENT); - break; - } - if (b != largestbuilding(r, get_cmp_region_owner(), false)) { - cmistake(u, ord, 147, MSG_EVENT); - break; - } - s = &r->display; - break; - - default: - cmistake(u, ord, 110, MSG_EVENT); - break; - } - - if (s!=NULL) { - const char * s2 = getstrtoken(); - - free(*s); - *s = strdup(s2); - if (strlen(s2)>=DISPLAYSIZE) { - (*s)[DISPLAYSIZE] = 0; - } - } - - return 0; -} - -static boolean -renamed_building(const building * b) -{ - const struct locale * lang = locales; - for (;lang;lang=nextlocale(lang)) { - const char * bdname = LOC(lang, b->type->_name); - size_t bdlen = strlen(bdname); - if (strlen(b->name)>=bdlen && strncmp(b->name, bdname, bdlen)==0) { - return false; - } - } - return true; -} - -static int -rename_cmd(unit * u, order * ord, char **s, const char * s2) -{ - if (!s2[0]) { - cmistake(u, ord, 84, MSG_EVENT); - return 0; - } - - /* TODO: Validate to make sure people don't have illegal characters in - * names, phishing-style? () come to mind. */ - - free(*s); - *s = strdup(s2); - if (strlen(s2)>=NAMESIZE) { - (*s)[NAMESIZE] = 0; - } - return 0; -} - -static int -rename_building(unit * u, order * ord, building * b, const char * name) { - unit * owner = b?building_owner(b):0; - boolean foreign = owner && owner->faction==u->faction; - - if (!b) { - cmistake(u, ord, u->building?6:145, MSG_EVENT); - return -1; - } - - if (!fval(b->type, BTF_NAMECHANGE) && renamed_building(b)) { - cmistake(u, ord, 278, MSG_EVENT); - return -1; - } - - if (foreign) { - unit *uo; - - if (renamed_building(b)) { - cmistake(u, ord, 246, MSG_EVENT); - return -1; - } - - uo = building_owner(b); - if (uo) { - if (cansee(uo->faction, u->region, u, 0)) { - ADDMSG(&uo->faction->msgs, msg_message("renamed_building_seen", - "building renamer region", b, u, u->region)); - } else { - ADDMSG(&uo->faction->msgs, msg_message("renamed_building_notseen", - "building region", b, u->region)); - } - } - } else { - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 148, MSG_PRODUCE); - return -1; - } - } - - return rename_cmd(u, ord, &b->name, getstrtoken()); -} - -static int -name_cmd(unit * u, struct order * ord) -{ - building * b = u->building; - region * r = u->region; - char **s = NULL; - param_t p; - boolean foreign = false; - - init_tokens(ord); - skip_token(); - p = getparam(u->faction->locale); - - if (p == P_FOREIGN) { - foreign = true; - p = getparam(u->faction->locale); - } - - switch (p) { - case P_ALLIANCE: - if (foreign==false && f_get_alliance(u->faction)) { - alliance * al = u->faction->alliance; - faction * lead = alliance_get_leader(al); - if (lead==u->faction) { - s = &al->name; - } - } - break; - case P_BUILDING: - case P_GEBAEUDE: - if (foreign) { - b = getbuilding(u->region); - } - - return rename_building(u, ord, b, getstrtoken()); - - case P_FACTION: - if (foreign == true) { - faction *f; - - f = getfaction(); - if (!f) { - cmistake(u, ord, 66, MSG_EVENT); - break; - } - if (f->age < 10) { - cmistake(u, ord, 248, MSG_EVENT); - break; - } else { - const struct locale * lang = locales; - for (;lang;lang=nextlocale(lang)) { - const char * fdname = LOC(lang, "factiondefault"); - size_t fdlen = strlen(fdname); - if (strlen(f->name)>=fdlen && strncmp(f->name, fdname, fdlen)==0) { - break; - } - } - if (lang==NULL) { - cmistake(u, ord, 247, MSG_EVENT); - break; - } - } - if (cansee(f, r, u, 0)) { - ADDMSG(&f->msgs, msg_message("renamed_faction_seen", "unit region", u, r)); - } else { - ADDMSG(&f->msgs, msg_message("renamed_faction_notseen", "", r)); - } - s = &f->name; - } else { - s = &u->faction->name; - } - break; - - case P_SHIP: - if (foreign == true) { - ship *sh = getship(r); - unit *uo; - - if (!sh) { - cmistake(u, ord, 20, MSG_EVENT); - break; - } else { - const struct locale * lang = locales; - for (;lang;lang=nextlocale(lang)) { - const char * sdname = LOC(lang, sh->type->name[0]); - size_t sdlen = strlen(sdname); - if (strlen(sh->name)>=sdlen && strncmp(sh->name, sdname, sdlen)==0) { - break; - } - - sdname = LOC(lang, parameters[P_SHIP]); - sdlen = strlen(sdname); - if (strlen(sh->name)>=sdlen && strncmp(sh->name, sdname, sdlen)==0) { - break; - } - - } - if (lang==NULL) { - cmistake(u, ord, 245, MSG_EVENT); - break; - } - } - uo = shipowner(sh); - if (uo) { - if (cansee(uo->faction, r, u, 0)) { - ADDMSG(&uo->faction->msgs, msg_message("renamed_ship_seen", - "ship renamer region", sh, u, r)); - } else { - ADDMSG(&uo->faction->msgs, msg_message("renamed_ship_notseen", - "ship region", sh, r)); - } - } - s = &sh->name; - } else { - if (!u->ship) { - cmistake(u, ord, 144, MSG_PRODUCE); - break; - } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 12, MSG_PRODUCE); - break; - } - s = &u->ship->name; - } - break; - - case P_UNIT: - if (foreign == true) { - unit *u2 = getunit(r, u->faction); - - if (!u2 || !cansee(u->faction, r, u2, 0)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - break; - } else { - const char * udefault = LOC(u2->faction->locale, "unitdefault"); - size_t udlen = strlen(udefault); - size_t unlen = strlen(u2->name); - if (unlen>=udlen && strncmp(u2->name, udefault, udlen)!=0) { - cmistake(u2, ord, 244, MSG_EVENT); - break; - } - } - if (cansee(u2->faction, r, u, 0)) { - ADDMSG(&u2->faction->msgs, msg_message("renamed_seen", - "renamer renamed region", u, u2, r)); - } else { - ADDMSG(&u2->faction->msgs, msg_message("renamed_notseen", - "renamed region", u2, r)); - } - s = &u2->name; - } else { - s = &u->name; - } - break; - - case P_REGION: - if (!b) { - cmistake(u, ord, 145, MSG_EVENT); - break; - } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 148, MSG_EVENT); - break; - } - - if (b != largestbuilding(r, get_cmp_region_owner(), false)) { - cmistake(u, ord, 147, MSG_EVENT); - break; - } - s = &r->land->name; - break; - - case P_GROUP: - { - attrib * a = NULL; - if (fval(u, UFL_GROUP)) a = a_find(u->attribs, &at_group); - if (a) { - group * g = (group*)a->data.v; - s = &g->name; - break; - } else { - cmistake(u, ord, 109, MSG_EVENT); - break; - } - } - break; - default: - cmistake(u, ord, 109, MSG_EVENT); - break; - } - - if (s!=NULL) { - return rename_cmd(u, ord, s, getstrtoken()); - } - - return 0; -} -/* ------------------------------------------------------------- */ - -void -deliverMail(faction * f, region * r, unit * u, const char *s, unit * receiver) -{ - if (!cansee(f, r, u, 0)) { - u = NULL; - } - if (!receiver) { /* BOTSCHAFT an PARTEI */ - ADDMSG(&f->msgs, msg_message("regionmessage", "region sender string", r, u, s)); - } else { /* BOTSCHAFT an EINHEIT */ - ADDMSG(&f->msgs, msg_message("unitmessage", "region unit sender string", r, receiver, u, s)); - } -} - -static void -mailunit(region * r, unit * u, int n, struct order * ord, const char * s) -{ - unit * u2 = findunitr(r,n); - - if (u2 && cansee(u->faction, r, u2, 0)) { - deliverMail(u2->faction, r, u, s, u2); - /* now done in prepare_mail_cmd */ - } - else { - /* Immer eine Meldung - sonst könnte man so getarnte EHs enttarnen: - * keine Meldung -> EH hier. */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } -} - -static void -mailfaction(unit * u, int n, struct order * ord, const char * s) -{ - faction *f; - - f = findfaction(n); - if (f && n>0) - deliverMail(f, u->region, u, s, NULL); - else - cmistake(u, ord, 66, MSG_MESSAGE); -} - -static int -mail_cmd(unit * u, struct order * ord) -{ - region * r = u->region; - unit *u2; - const char *s; - int n, cont; - - init_tokens(ord); - skip_token(); /* skip the keyword */ - s = getstrtoken(); - - /* Falls kein Parameter, ist das eine Einheitsnummer; - * das Füllwort "AN" muß wegfallen, da gültige Nummer! */ - - do { - cont = 0; - switch (findparam(s, u->faction->locale)) { - case P_REGION: - /* können alle Einheiten in der Region sehen */ - s = getstrtoken(); - if (!s[0]) { - cmistake(u, ord, 30, MSG_MESSAGE); - break; - } else { - ADDMSG(&r->msgs, msg_message("mail_result", "unit message", u, s)); - return 0; - } - - case P_FACTION: - { - boolean see = false; - - n = getfactionid(); - - for(u2=r->units; u2; u2=u2->next) { - if(u2->faction->no == n && seefaction(u->faction, r, u2, 0)) { - see = true; - break; - } - } - - if(see == false) { - cmistake(u, ord, 66, MSG_MESSAGE); - break; - } - - s = getstrtoken(); - if (!s[0]) { - cmistake(u, ord, 30, MSG_MESSAGE); - break; - } - mailfaction(u, n, ord, s); - return 0; - } - - case P_UNIT: - { - boolean see = false; - n = getid(); - - for (u2=r->units; u2; u2=u2->next) { - if (u2->no == n && cansee(u->faction, r, u2, 0)) { - see = true; - break; - } - } - - if (see == false) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return 0; - } - - s = getstrtoken(); - if (!s[0]) { - cmistake(u, ord, 30, MSG_MESSAGE); - break; - } else { - attrib * a = a_find(u2->attribs, &at_eventhandler); - if (a!=NULL) { - event_arg args[3]; - args[0].data.v = (void*)s; - args[0].type = "string"; - args[1].data.v = (void*)u; - args[1].type = "unit"; - args[2].type = NULL; - handle_event(a, "message", args); - } - - mailunit(r, u, n, ord, s); - } - return 0; - } - - case P_BUILDING: - case P_GEBAEUDE: - { - building *b = getbuilding(r); - - if(!b) { - cmistake(u, ord, 6, MSG_MESSAGE); - break; - } - - s = getstrtoken(); - - if (!s[0]) { - cmistake(u, ord, 30, MSG_MESSAGE); - break; - } - - for (u2 = r->units; u2; u2 = u2->next) freset(u2->faction, FFL_SELECT); - - for (u2=r->units; u2; u2=u2->next) { - if(u2->building == b && !fval(u2->faction, FFL_SELECT) - && cansee(u->faction, r, u2, 0)) { - mailunit(r, u, u2->no, ord, s); - fset(u2->faction, FFL_SELECT); - } - } - return 0; - } - - case P_SHIP: - { - ship *sh = getship(r); - - if(!sh) { - cmistake(u, ord, 20, MSG_MESSAGE); - break; - } - - s = getstrtoken(); - - if (!s[0]) { - cmistake(u, ord, 30, MSG_MESSAGE); - break; - } - - for (u2 = r->units; u2; u2 = u2->next) freset(u2->faction, FFL_SELECT); - - for(u2=r->units; u2; u2=u2->next) { - if(u2->ship == sh && !fval(u2->faction, FFL_SELECT) && cansee(u->faction, r, u2, 0)) { - mailunit(r, u, u2->no, ord, s); - fset(u2->faction, FFL_SELECT); - } - } - return 0; - } - - default: - /* possibly filler token? */ - s = getstrtoken(); - if (s && *s) cont = 1; - break; - } - } while (cont); - cmistake(u, ord, 149, MSG_MESSAGE); - return 0; -} -/* ------------------------------------------------------------- */ - -static int -banner_cmd(unit * u, struct order * ord) -{ - init_tokens(ord); - skip_token(); - - free(u->faction->banner); - u->faction->banner = strdup(getstrtoken()); - add_message(&u->faction->msgs, msg_message("changebanner", "value", - u->faction->banner)); - - return 0; -} - -static int -email_cmd(unit * u, struct order * ord) -{ - const char * s; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - if (!s[0]) { - cmistake(u, ord, 85, MSG_EVENT); - } else { - faction * f = u->faction; - if (set_email(&f->email, (const char *)s)!=0) { - log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), s)); - ADDMSG(&f->msgs, msg_message("changemail_invalid", "value", s)); - } else { - ADDMSG(&f->msgs, msg_message("changemail", "value", f->email)); - } - } - return 0; -} - -static int -password_cmd(unit * u, struct order * ord) -{ - char pwbuf[32]; - int i; - const char * s; - boolean pwok = true; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - if (!s || !*s) { - for(i=0; i<6; i++) pwbuf[i] = (char)(97 + rng_int() % 26); - pwbuf[6] = 0; - } else { - char *c; - - strlcpy(pwbuf, (const char *)s, 31); - pwbuf[31] = 0; - c = pwbuf; - while (*c && pwok) { - if (!isalnum(*(unsigned char*)c)) pwok = false; - c++; - } - } - free(u->faction->passw); - if (pwok == false) { - cmistake(u, ord, 283, MSG_EVENT); - u->faction->passw = strdup(itoa36(rng_int())); - } else { - u->faction->passw = strdup(pwbuf); - } - fset(u->faction, FFL_OVERRIDE); - ADDMSG(&u->faction->msgs, msg_message("changepasswd", - "value", u->faction->passw)); - return 0; -} - -static int -send_cmd(unit * u, struct order * ord) -{ - const char * s; - int option; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - option = findoption(s, u->faction->locale); - - if (option == -1) { - cmistake(u, ord, 135, MSG_EVENT); - } else { - if (getparam(u->faction->locale) == P_NOT) { - if (option == O_COMPRESS || option == O_BZIP2) { - cmistake(u, ord, 305, MSG_EVENT); - } else { - u->faction->options = u->faction->options & ~(1<faction->options = u->faction->options | (1<faction->options &= ~(1<faction->options &= ~(1<items, itype); - if (i==0) { - if (u->region->land!=NULL) { - i = i_get(u->region->land->items, itype); - } - if (i==0) { - i = i_get(u->faction->items, itype); - if (i==0) return false; - } - } - } - - name = resourcename(itype->rtype, 0); - key = mkname("iteminfo", name); - info = locale_getstring(f->locale, key); - - if (info==NULL) { - info = locale_string(f->locale, mkname("iteminfo", "no_info")); - } - ADDMSG(&f->msgs, msg_message("displayitem", "weight item description", - itype->weight, itype->rtype, info)); - - return true; -} - -static boolean -display_potion(faction *f, unit *u, const potion_type * ptype) -{ - attrib *a; - - if (ptype==NULL) return false; - else { - int i = i_get(u->items, ptype->itype); - if (i==0 && 2*ptype->level > effskill(u,SK_ALCHEMY)) { - return false; - } - } - - a = a_find(f->attribs, &at_showitem); - while (a && a->data.v != ptype) a=a->next; - if (!a) { - a = a_add(&f->attribs, a_new(&at_showitem)); - a->data.v = (void*) ptype->itype; - } - - return true; -} - -static boolean -display_race(faction *f, unit *u, const race * rc) -{ - const char *name, *key; - const char *info; - int a, at_count; - char buf[2048], * bufp = buf; - size_t size = sizeof(buf) - 1; - int bytes; - - if (u && u->race != rc) return false; - name = rc_name(rc, 0); - - bytes = slprintf(bufp, size, "%s: ", LOC(f->locale, name)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - key = mkname("raceinfo", rc->_name[0]); - info = locale_getstring(f->locale, key); - if (info==NULL) { - info = locale_string(f->locale, mkname("raceinfo", "no_info")); - } - - bytes = (int)strlcpy(bufp, info, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - /* hp_p : Trefferpunkte */ - bytes = snprintf(bufp, size, " %d %s", rc->hitpoints, LOC(f->locale, "stat_hitpoints")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - /* b_attacke : Angriff */ - bytes = snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_attack"), (rc->at_default+rc->at_bonus)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - /* b_defense : Verteidigung */ - bytes = snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_defense"), (rc->df_default+rc->df_bonus)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - /* b_armor : Rüstung */ - if (rc->armor > 0) { - bytes = snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_armor"), rc->armor); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - - if (size>1) { - *bufp++ ='.'; - --size; - } else WARN_STATIC_BUFFER(); - - /* b_damage : Schaden */ - at_count=0; - for (a = 0; a < 6; a++) { - if (rc->attack[a].type != AT_NONE){ - at_count++; - } - } - if (rc->battle_flags & BF_EQUIPMENT) { - bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_equipment")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (rc->battle_flags & BF_RES_PIERCE) { - bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_pierce")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (rc->battle_flags & BF_RES_CUT) { - bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_cut")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (rc->battle_flags & BF_RES_BASH) { - bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_bash")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - - bytes = snprintf(bufp, size, " %d %s", at_count, LOC(f->locale, (at_count==1)?"stat_attack":"stat_attacks")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - for (a = 0; a < 6; a++) { - if (rc->attack[a].type != AT_NONE){ - if (a!=0) bytes = (int)strlcpy(bufp, ", ", size); - else bytes = (int)strlcpy(bufp, ": ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - switch(rc->attack[a].type) { - case AT_STANDARD: - bytes = snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_standard"), rc->def_damage); - break; - case AT_NATURAL: - bytes = snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_natural"), rc->attack[a].data.dice); - break; - case AT_SPELL: - case AT_COMBATSPELL: - case AT_DRAIN_ST: - case AT_DAZZLE: - bytes = snprintf(bufp, size, "%s", LOC(f->locale, "attack_magical")); - break; - case AT_STRUCTURAL: - bytes = snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_structural"), rc->attack[a].data.dice); - break; - default: - bytes = 0; - } - - if (bytes && wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - - if (size>1) { - *bufp++ = '.'; - --size; - } else WARN_STATIC_BUFFER(); - - *bufp = 0; - addmessage(0, f, buf, MSG_EVENT, ML_IMPORTANT); - - return true; -} - -static void -reshow(unit * u, struct order * ord, const char * s, param_t p) -{ - int skill, c; - const potion_type * ptype; - const item_type * itype; - const spell * sp; - const race * rc; - - switch (p) { - case P_ZAUBER: - a_removeall(&u->faction->attribs, &at_seenspell); - break; - case P_POTIONS: - skill = effskill(u, SK_ALCHEMY); - c = 0; - for (ptype = potiontypes; ptype!=NULL; ptype=ptype->next) { - if (ptype->level * 2 <= skill) { - c += display_potion(u->faction, u, ptype); - } - } - if (c == 0) cmistake(u, ord, 285, MSG_EVENT); - break; - case NOPARAM: - /* check if it's an item */ - itype = finditemtype(s, u->faction->locale); - if (itype!=NULL) { - ptype = resource2potion(item2resource(itype)); - if (ptype!=NULL) { - if (display_potion(u->faction, u, ptype)) break; - } else { - if (display_item(u->faction, u, itype)) break; - } - } - /* try for a spell */ - sp = get_spellfromtoken(u, s, u->faction->locale); - if (sp!=NULL && u_hasspell(u, sp)) { - attrib *a = a_find(u->faction->attribs, &at_seenspell); - while (a!=NULL && a->type==&at_seenspell && a->data.v!=sp) a = a->next; - if (a!=NULL) a_remove(&u->faction->attribs, a); - break; - } - /* last, check if it's a race. */ - rc = findrace(s, u->faction->locale); - if (rc != NULL) { - if (display_race(u->faction, u, rc)) break; - } - cmistake(u, ord, 21, MSG_EVENT); - break; - default: - cmistake(u, ord, 222, MSG_EVENT); - break; - } -} - -static int -promotion_cmd(unit * u, struct order * ord) -{ - int money, people; - - if (fval(u, UFL_HERO)) { - /* TODO: message "is already a hero" */ - return 0; - } - - if (maxheroes(u->faction) < countheroes(u->faction)+u->number) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_maxed", "max count", - maxheroes(u->faction), countheroes(u->faction))); - return 0; - } - if (!valid_race(u->faction, u->race)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_race", "race", - u->race)); - return 0; - } - people = count_all(u->faction) * u->number; - money = get_pooled(u, i_silver->rtype, GET_ALL, people); - - if (people>money) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_cost", "cost have", - people, money)); - return 0; - } - use_pooled(u, i_silver->rtype, GET_ALL, people); - fset(u, UFL_HERO); - ADDMSG(&u->faction->msgs, msg_message("hero_promotion", "unit cost", - u, people)); - return 0; -} - -static int -group_cmd(unit * u, struct order * ord) -{ - const char * s; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - join_group(u, s); - return 0; -} - -static int -origin_cmd(unit * u, struct order * ord) -{ - short px, py; - - init_tokens(ord); - skip_token(); - - px = (short)getint(); - py = (short)getint(); - - set_ursprung(u->faction, getplaneid(u->region), px, py); - return 0; -} - -static int -guard_off_cmd(unit * u, struct order * ord) -{ - assert(get_keyword(ord)==K_GUARD); - init_tokens(ord); - skip_token(); - - if (getparam(u->faction->locale) == P_NOT) { - setguard(u, GUARD_NONE); - } - return 0; -} - -static int -reshow_cmd(unit * u, struct order * ord) -{ - const char * s; - param_t p = NOPARAM; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - if (findparam(s, u->faction->locale) == P_ANY) { - p = getparam(u->faction->locale); - s = NULL; - } - - reshow(u, ord, s, p); - return 0; -} - -static int -status_cmd(unit * u, struct order * ord) -{ - const char * param; - - init_tokens(ord); - skip_token(); - - param = getstrtoken(); - switch (findparam(param, u->faction->locale)) { - case P_NOT: - setstatus(u, ST_AVOID); - break; - case P_BEHIND: - setstatus(u, ST_BEHIND); - break; - case P_FLEE: - setstatus(u, ST_FLEE); - break; - case P_CHICKEN: - setstatus(u, ST_CHICKEN); - break; - case P_AGGRO: - setstatus(u, ST_AGGRO); - break; - case P_VORNE: - setstatus(u, ST_FIGHT); - break; - case P_HELP: - if (getparam(u->faction->locale) == P_NOT) { - fset(u, UFL_NOAID); - } else { - freset(u, UFL_NOAID); - } - break; - default: - if (param[0]) { - add_message(&u->faction->msgs, - msg_feedback(u, ord, "unknown_status", "")); - } else { - setstatus(u, ST_FIGHT); - } - } - return 0; -} - -static int -combatspell_cmd(unit * u, struct order * ord) -{ - const char * s; - int level = 0; - spell * spell; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - /* KAMPFZAUBER [NICHT] löscht alle gesetzten Kampfzauber */ - if (!s || *s == 0 || findparam(s, u->faction->locale) == P_NOT) { - unset_combatspell(u, 0); - return 0; - } - - /* Optional: STUFE n */ - if (findparam(s, u->faction->locale) == P_LEVEL) { - /* Merken, setzen kommt erst später */ - level = getint(); - level = MAX(0, level); - s = getstrtoken(); - } - - spell = get_spellfromtoken(u, s, u->faction->locale); - - if(!spell){ - cmistake(u, ord, 173, MSG_MAGIC); - return 0; - } - - s = getstrtoken(); - - if (findparam(s, u->faction->locale) == P_NOT) { - /* KAMPFZAUBER "" NICHT löscht diesen speziellen - * Kampfzauber */ - unset_combatspell(u, spell); - return 0; - } else { - /* KAMPFZAUBER "" setzt diesen Kampfzauber */ - set_combatspell(u, spell, ord, level); - } - - return 0; -} - -/* ------------------------------------------------------------- */ -/* Beachten: einige Monster sollen auch unbewaffent die Region bewachen - * können */ - -enum { E_GUARD_OK, E_GUARD_UNARMED, E_GUARD_NEWBIE, E_GUARD_FLEEING }; - -static int -can_start_guarding(const unit * u) -{ - if (u->status>=ST_FLEE) return E_GUARD_FLEEING; - if (fval(u->race, RCF_UNARMEDGUARD)) return E_GUARD_OK; - if (!armedmen(u, true)) return E_GUARD_UNARMED; - if (IsImmune(u->faction)) return E_GUARD_NEWBIE; - return E_GUARD_OK; -} - -void -update_guards(void) -{ - const region *r; - - for (r = regions; r; r = r->next) { - unit *u; - for (u = r->units; u; u = u->next) { - if (fval(u, UFL_GUARD)) { - if (can_start_guarding(u)!=E_GUARD_OK) { - setguard(u, GUARD_NONE); - } else { - attrib * a = a_find(u->attribs, &at_guard); - if (a && a->data.i==(int)guard_flags(u)) { - /* this is really rather not necessary */ - a_remove(&u->attribs, a); - } - } - } - } - } -} - -static int -guard_on_cmd(unit * u, struct order * ord) -{ - assert(get_keyword(ord)==K_GUARD); - - init_tokens(ord); - skip_token(); - - /* GUARD NOT is handled in goard_off_cmd earlier in the turn */ - if (getparam(u->faction->locale) == P_NOT) return 0; - - if (fval(u->region->terrain, SEA_REGION)) { - cmistake(u, ord, 2, MSG_EVENT); - } else { - if (fval(u, UFL_MOVED)) { - cmistake(u, ord, 187, MSG_EVENT); - } else if (fval(u->race, RCF_ILLUSIONARY) || u->race == new_race[RC_SPELL]) { - cmistake(u, ord, 95, MSG_EVENT); - } else { - /* Monster der Monsterpartei dürfen immer bewachen */ - if (is_monsters(u->faction)) { - guard(u, GUARD_ALL); - } else { - int err = can_start_guarding(u); - if (err==E_GUARD_OK) { - guard(u, GUARD_ALL); - } else if (err==E_GUARD_UNARMED) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_unarmed", "")); - } else if (err==E_GUARD_FLEEING) { - cmistake(u, ord, 320, MSG_EVENT); - } else if (err==E_GUARD_NEWBIE) { - cmistake(u, ord, 304, MSG_EVENT); - } - } - } - } - return 0; -} - -static void -sinkships(region * r) -{ - ship **shp = &r->ships; - - while (*shp) { - ship * sh = *shp; - if (fval(r->terrain, SEA_REGION) && (!enoughsailors(sh, r) || get_captain(sh)==NULL)) { - /* Schiff nicht seetüchtig */ - damage_ship(sh, 0.30); - } - if (shipowner(sh)==NULL) { - damage_ship(sh, 0.05); - } - if (sh->damage >= sh->size * DAMAGE_SCALE) { - remove_ship(shp, sh); - } - if (*shp==sh) shp=&sh->next; - } -} - -/* The following functions do not really belong here: */ -#include -#include - -static attrib_type at_number = { - "faction_renum", - NULL, NULL, NULL, NULL, NULL, - ATF_UNIQUE -}; - -static void -renumber_factions(void) - /* gibt parteien neue nummern */ -{ - struct renum { - struct renum * next; - int want; - faction * faction; - attrib * attrib; - } * renum = NULL, * rp; - faction * f; - for (f=factions;f;f=f->next) { - attrib * a = a_find(f->attribs, &at_number); - int want; - struct renum ** rn; - faction * old; - - if (!a) continue; - want = a->data.i; - if (fval(f, FFL_NEWID)) { - ADDMSG(&f->msgs, msg_message("renumber_twice", "id", want)); - continue; - } - old = findfaction(want); - if (old) { - a_remove(&f->attribs, a); - ADDMSG(&f->msgs, msg_message("renumber_inuse", "id", want)); - continue; - } - if (!faction_id_is_unused(want)) { - a_remove(&f->attribs, a); - ADDMSG(&f->msgs, msg_message("renumber_inuse", "id", want)); - continue; - } - for (rn=&renum; *rn; rn=&(*rn)->next) { - if ((*rn)->want>=want) break; - } - if (*rn && (*rn)->want==want) { - ADDMSG(&f->msgs, msg_message("renumber_inuse", "id", want)); - } else { - struct renum * r = calloc(sizeof(struct renum), 1); - r->next = *rn; - r->attrib = a; - r->faction = f; - r->want = want; - *rn = r; - } - } - for (rp=renum;rp;rp=rp->next) { - f = rp->faction; - a_remove(&f->attribs, rp->attrib); - renumber_faction(f, rp->want); - } - while (renum) { - rp = renum->next; - free(renum); - renum = rp; - } -} - -static void -reorder(void) -{ - region * r; - for (r=regions;r;r=r->next) { - unit ** up=&r->units; - boolean sorted=false; - while (*up) { - unit * u = *up; - if (!fval(u, UFL_MARK)) { - struct order * ord; - for (ord = u->orders;ord;ord=ord->next) { - if (get_keyword(ord)==K_SORT) { - const char * s; - param_t p; - int id; - unit *v; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - p = findparam(s, u->faction->locale); - id = getid(); - v = findunit(id); - - if (v==NULL || v->faction!=u->faction || v->region!=r) { - cmistake(u, ord, 258, MSG_EVENT); - } else if (v->building != u->building || v->ship!=u->ship) { - cmistake(u, ord, 259, MSG_EVENT); - } else if (fval(u, UFL_OWNER)) { - cmistake(u, ord, 260, MSG_EVENT); - } else if (v == u) { - cmistake(u, ord, 10, MSG_EVENT); - } else { - switch(p) { - case P_AFTER: - *up = u->next; - u->next = v->next; - v->next = u; - break; - case P_BEFORE: - if (fval(v, UFL_OWNER)) { - cmistake(v, ord, 261, MSG_EVENT); - } else { - unit ** vp=&r->units; - while (*vp!=v) vp=&(*vp)->next; - *vp = u; - *up = u->next; - u->next = v; - } - break; - } - fset(u, UFL_MARK); - sorted = true; - } - break; - } - } - } - if (u==*up) up=&u->next; - } - if (sorted) { - unit * u; - for (u=r->units;u;u=u->next) freset(u, UFL_MARK); - } - } -} - -#if 0 -/* Aus Gebäude weisen, VERBANNE */ -static void -evict(void) -{ - region *r; - strlist *S; - unit * u; - - for (r=regions;r;r=r->next) { - for (u=r->units;u;u=u->next) { - for (S = u->orders; S; S = S->next) if (get_keyword(ord)==K_EVICT) { - int id; - unit *u2; - /* Nur der Kapitän bzw Burgherr kann jemanden rausschmeißen */ - if(!fval(u, UFL_OWNER)) { - /* Die Einheit ist nicht der Eigentümer */ - cmistake(u,ord,49,MSG_EVENT); - continue; - } - init_tokens(ord); - skip_token(); - id = getid(); - u2 = findunit(id); - - if (u2==NULL) { - /* Einheit nicht gefunden */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - continue; - } - - if (u->building){ - /* in der selben Burg? */ - if (u->building != u2->building){ - /* nicht in Burg */ - cmistake(u,ord,33,MSG_EVENT); - continue; - } - leave_building(u2); - /* meldung an beide */ - } - - if (u->ship){ - if (u->ship != u2->ship){ - /* nicht an Bord */ - cmistake(u, ord, 32, MSG_EVENT); - continue; - } - leave_ship(u2); - /* meldung an beide */ - } - } - } - } -} -#endif - - -static int -renumber_cmd(unit * u, order * ord) -{ - const char * s; - int i; - faction * f = u->faction; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - switch(findparam(s, u->faction->locale)) { - - case P_FACTION: - s = getstrtoken(); - if (s && *s) { - int id = atoi36((const char *)s); - attrib * a = a_find(f->attribs, &at_number); - if (!a) a = a_add(&f->attribs, a_new(&at_number)); - a->data.i = id; - } - break; - - case P_UNIT: - s = getstrtoken(); - if (s == NULL || *s == 0) { - i = newunitid(); - } else { - i = atoi36((const char *)s); - if (i<=0 || i>MAX_UNIT_NR) { - cmistake(u, ord, 114, MSG_EVENT); - break; - } - - if (forbiddenid(i)) { - cmistake(u, ord, 116, MSG_EVENT); - break; - } - - if (findunitg(i, u->region)) { - cmistake(u, ord, 115, MSG_EVENT); - break; - } - } - uunhash(u); - if (!ualias(u)) { - attrib *a = a_add(&u->attribs, a_new(&at_alias)); - a->data.i = -u->no; - } - u->no = i; - uhash(u); - break; - - case P_SHIP: - if (!u->ship) { - cmistake(u, ord, 144, MSG_EVENT); - break; - } - if (u->ship->coast != NODIRECTION) { - cmistake(u, ord, 116, MSG_EVENT); - break; - } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 146, MSG_EVENT); - break; - } - s = getstrtoken(); - if (s == NULL || *s == 0) { - i = newcontainerid(); - } else { - i = atoi36((const char *)s); - if (i<=0 || i>MAX_CONTAINER_NR) { - cmistake(u,ord,114,MSG_EVENT); - break; - } - if (findship(i) || findbuilding(i)) { - cmistake(u, ord, 115, MSG_EVENT); - break; - } - } - sunhash(u->ship); - u->ship->no = i; - shash(u->ship); - break; - case P_BUILDING: - case P_GEBAEUDE: - if (!u->building) { - cmistake(u,ord,145,MSG_EVENT); - break; - } - if(!fval(u, UFL_OWNER)) { - cmistake(u,ord,148,MSG_EVENT); - break; - } - s = getstrtoken(); - if(*s == 0) { - i = newcontainerid(); - } else { - i = atoi36((const char *)s); - if (i<=0 || i>MAX_CONTAINER_NR) { - cmistake(u,ord,114,MSG_EVENT); - break; - } - if(findship(i) || findbuilding(i)) { - cmistake(u,ord,115,MSG_EVENT); - break; - } - } - bunhash(u->building); - u->building->no = i; - bhash(u->building); - break; - - default: - cmistake(u, ord, 239, MSG_EVENT); - } - return 0; -} - -static building * -age_building(building * b) -{ - static boolean init = false; - static const building_type * bt_blessed; - static const curse_type * ct_astralblock; - if (!init) { - init = true; - bt_blessed = bt_find("blessedstonecircle"); - ct_astralblock = ct_find("astralblock"); - } - - /* blesses stone circles create an astral protection in the astral region - * above the shield, which prevents chaos suction and other spells. - * The shield is created when a magician enters the blessed stone circle, - * and lasts for as long as his skill level / 2 is, at no mana cost. - * - * TODO: this would be nicer in a btype->age function, but we don't have it. - */ - if (ct_astralblock && bt_blessed && b->type==bt_blessed) { - region * r = b->region; - region * rt = r_standard_to_astral(r); - unit * u, * mage = NULL; - - if (fval(rt->terrain, FORBIDDEN_REGION)) rt = NULL; - /* step 1: give unicorns to people in the building, - * find out if there's a magician in there. */ - for (u=r->units;u;u=u->next) { - if (b==u->building && inside_building(u)) { - if (!(u->race->ec_flags & GIVEITEM)==0) { - int n, unicorns = 0; - for (n=0; n!=u->number; ++n) { - if (chance(0.02)) { - i_change(&u->items, olditemtype[I_ELVENHORSE], 1); - ++unicorns; - } - if (unicorns) { - ADDMSG(&u->faction->msgs, msg_message("scunicorn", - "unit amount rtype", u, unicorns, - olditemtype[I_ELVENHORSE]->rtype)); - } - } - } - if (mage==NULL && is_mage(u)) { - mage = u; - } - } - } - - /* if there's a magician, and a connection to astral space, create the - * curse. */ - if (rt!=NULL && mage!=NULL) { - curse * c = get_curse(rt->attribs, ct_astralblock); - if (c==NULL) { - if (mage!=NULL) { - int sk = effskill(mage, SK_MAGIC); - double effect; - effect = 100; - /* the mage reactivates the circle */ - c = create_curse(mage, &rt->attribs, ct_astralblock, - (float)MAX(1, sk), MAX(1, sk/2), effect, 0); - ADDMSG(&r->msgs, msg_message("astralshield_activate", - "region unit", r, mage)); - } - } else if (mage!=NULL) { - int sk = effskill(mage, SK_MAGIC); - c->duration = MAX(c->duration, sk/2); - c->vigour = MAX(c->vigour, sk); - } - } - } - - a_age(&b->attribs); - handle_event(b->attribs, "timer", b); - - if (b->type->age) { - b->type->age(b); - } - - return b; -} - -static double rc_popularity(const struct race * rc) -{ - int pop = get_param_int(rc->parameters, "morale", MORALE_AVERAGE); - return 1.0/(pop-MORALE_COOLDOWN); /* 10 turns average */ -} - -static void age_region(region * r) -{ - a_age(&r->attribs); - handle_event(r->attribs, "timer", r); - - if (!r->land) return; - - if (r->land->ownership && r->land->ownership->owner) { - int stability = turn - r->land->ownership->morale_turn; - int maxmorale = MORALE_DEFAULT; - building * b = largestbuilding(r, &cmp_taxes, false); - if (b) { - int bsize = buildingeffsize(b, false); - maxmorale = (int)(0.5 + b->type->taxes(b, bsize+1) / MORALE_TAX_FACTOR); - } - if (r->land->moraleMORALE_COOLDOWN && r->land->ownership->owner && r->land->moraleland->ownership->owner->race); - if (is_cursed(r->attribs, C_GENEROUS, 0)) { - ch *= 1.2; /* 20% improvement */ - } - if (stability>=MORALE_AVERAGE*2 || chance(ch)) { - region_set_morale(r, r->land->morale+1, turn); - } - } - } else if (r->land->morale>maxmorale) { - region_set_morale(r, r->land->morale-1, turn); - } - } else if (r->land->morale>MORALE_DEFAULT) { - region_set_morale(r, r->land->morale-1, turn); - } -} - -static void -ageing(void) -{ - faction *f; - region *r; - - /* altern spezieller Attribute, die eine Sonderbehandlung brauchen? */ - for(r=regions;r;r=r->next) { - unit *u; - - for (u=r->units;u;u=u->next) { - /* Goliathwasser */ - int i = get_effect(u, oldpotiontype[P_STRONG]); - if (i > 0){ - change_effect(u, oldpotiontype[P_STRONG], -1 * MIN(u->number, i)); - } - /* Berserkerblut*/ - i = get_effect(u, oldpotiontype[P_BERSERK]); - if (i > 0){ - change_effect(u, oldpotiontype[P_BERSERK], -1 * MIN(u->number, i)); - } - - if (is_cursed(u->attribs, C_OLDRACE, 0)){ - curse *c = get_curse(u->attribs, ct_find("oldrace")); - if (c->duration == 1 && !(c_flags(c) & CURSE_NOAGE)) { - u->race = new_race[curse_geteffect_int(c)]; - u->irace = NULL; - } - } - } - } - - /* Borders */ - age_borders(); - - /* Factions */ - for (f=factions;f;f=f->next) { - a_age(&f->attribs); - handle_event(f->attribs, "timer", f); - } - - /* Regionen */ - for (r=regions;r;r=r->next) { - building ** bp; - unit ** up; - ship ** sp; - - age_region(r); - - /* Einheiten */ - for (up=&r->units;*up;) { - unit * u = *up; - a_age(&u->attribs); - if (u==*up) handle_event(u->attribs, "timer", u); - if (u==*up) up = &(*up)->next; - } - - /* Schiffe */ - for (sp=&r->ships;*sp;) { - ship * s = *sp; - a_age(&s->attribs); - if (s==*sp) handle_event(s->attribs, "timer", s); - if (s==*sp) sp = &(*sp)->next; - } - - /* Gebäude */ - for (bp=&r->buildings;*bp;) { - building * b = *bp; - age_building(b); - if (b==*bp) bp = &b->next; - } - - if (rule_region_owners()) { - update_owners(r); - } - } -} - -static int -maxunits(const faction *f) -{ - int flimit = rule_faction_limit(); - int alimit = rule_alliance_limit(); - if (alimit==0) { - return flimit; - } - if (flimit==0) { - return alimit; - } - return MIN(alimit, flimit); -} - -int -checkunitnumber(const faction *f, int add) -{ - int alimit, flimit; - - alimit = rule_alliance_limit(); - if (alimit) { - /* if unitsperalliance is true, maxunits returns the - number of units allowed in an alliance */ - faction *f2; - int unitsinalliance = add; - - for (f2 = factions; f2; f2 = f2->next) { - if (f->alliance == f2->alliance) { - unitsinalliance += f2->no_units; - } - if (unitsinalliance > alimit) { - return 1; - } - } - } - - flimit = rule_faction_limit(); - if (flimit) { - if (f->no_units + add > flimit) { - return 2; - } - } - - return 0; -} - -static void -new_units(void) -{ - region *r; - unit *u, *u2; - - /* neue einheiten werden gemacht und ihre befehle (bis zum "ende" zu - * ihnen rueberkopiert, damit diese einheiten genauso wie die alten - * einheiten verwendet werden koennen. */ - - for (r = regions; r; r = r->next) { - for (u = r->units; u; u = u->next) { - order ** ordp = &u->orders; - - /* this needs to happen very early in the game somewhere. since this is - ** pretty much the first function called per turn, and I am lazy, I - ** decree that it goes here */ - if (u->flags&UFL_GUARD) { - fset(r, RF_GUARDED); - } - - while (*ordp) { - order * makeord = *ordp; - if (get_keyword(makeord) == K_MAKE) { - init_tokens(makeord); - skip_token(); - if (getparam(u->faction->locale) == P_TEMP) { - const char * token; - char * name = NULL; - 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 (get_keyword(ord) == K_END) break; - *ordp = ord->next; - ord->next = NULL; - free_order(ord); - } - continue; - } - alias = getid(); - - token = getstrtoken(); - if (token && token[0]) { - name = strdup(token); - } - u2 = create_unit(r, u->faction, 0, u->faction->race, alias, name, u); - if (name!=NULL) free(name); - 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 (get_keyword(ord) == K_END) break; - *ordp = ord->next; - ord->next = NULL; - *newordersp = ord; - newordersp = &ord->next; - } - } - } - if (*ordp==makeord) ordp=&makeord->next; - } - } - } -} - -static void -setdefaults(unit *u) -{ - order *ord; - boolean trade = false; - boolean hunger = LongHunger(u); - - freset(u, UFL_LONGACTION); - if (hunger) { - /* Hungernde Einheiten führen NUR den default-Befehl aus */ - set_order(&u->thisorder, default_order(u->faction->locale)); - } - /* check all orders for a potential new long order this round: */ - for (ord = u->orders; ord; ord = ord->next) { - if (u->old_orders && is_repeated(ord)) { - /* this new order will replace the old defaults */ - free_orders(&u->old_orders); - if (hunger) break; - } - if (hunger) continue; - - if (is_exclusive(ord)) { - /* Über dieser Zeile nur Befehle, die auch eine idle Faction machen darf */ - if (idle(u->faction)) { - set_order(&u->thisorder, default_order(u->faction->locale)); - } else { - set_order(&u->thisorder, copy_order(ord)); - } - break; - } else { - keyword_t keyword = get_keyword(ord); - switch (keyword) { - /* Wenn gehandelt wird, darf kein langer Befehl ausgeführt - * werden. Da Handel erst nach anderen langen Befehlen kommt, - * muß das vorher abgefangen werden. Wir merken uns also - * hier, ob die Einheit handelt. */ - case NOKEYWORD: - cmistake(u, ord, 22, MSG_EVENT); - break; - case K_BUY: - case K_SELL: - /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht - * werden. */ - trade = true; - break; - - case K_CAST: - /* dient dazu, das neben Zaubern kein weiterer Befehl - * ausgeführt werden kann, Zaubern ist ein kurzer Befehl */ - set_order(&u->thisorder, NULL); - break; - - case K_WEREWOLF: - set_order(&u->thisorder, copy_order(ord)); - break; - - /* Wird je diese Ausschliesslichkeit aufgehoben, muss man aufpassen - * mit der Reihenfolge von Kaufen, Verkaufen etc., damit es Spielern - * nicht moeglich ist, Schulden zu machen. */ - } - } - } - - if (hunger) return; - - /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht - * werden. */ - - if (trade == true) { - /* fset(u, UFL_LONGACTION|UFL_NOTMOVING); */ - set_order(&u->thisorder, NULL); - } -} - -static int -use_item(unit * u, const item_type * itype, int amount, struct order * ord) -{ - int i; - int target = read_unitid(u->faction, u->region); - - i = get_pooled(u, itype->rtype, GET_DEFAULT, amount); - - if (amount>i) { - amount = i; - } - if (amount==0) { - cmistake(u, ord, 43, MSG_PRODUCE); - return ENOITEM; - } - - if (target==-1) { - if (itype->use==NULL) { - cmistake(u, ord, 76, MSG_PRODUCE); - return EUNUSABLE; - } - return itype->use(u, itype, amount, ord); - } else { - if (itype->useonother==NULL) { - cmistake(u, ord, 76, MSG_PRODUCE); - return EUNUSABLE; - } - return itype->useonother(u, target, itype, amount, ord); - } -} - - -static double -heal_factor(const unit * u) -{ - static float elf_regen = -1; - switch(old_race(u->race)) { - case RC_TROLL: - case RC_DAEMON: - return 1.5; - case RC_GOBLIN: - return 2.0; - case RC_ELF: - if (elf_regen<0) elf_regen = get_param_flt(u->race->parameters, "regen.forest", 1.0F); - if (elf_regen!=1.0 && r_isforest(u->region)) { - return elf_regen; - } - return 1.0; - } - return 1.0; -} - -static void -monthly_healing(void) -{ - region *r; - static const curse_type * heal_ct = NULL; - if (heal_ct==NULL) heal_ct = ct_find("healingzone"); - - for (r = regions; r; r = r->next) { - unit *u; - double healingcurse = 0; - - if (heal_ct!=NULL) { - /* bonus zurücksetzen */ - curse * c = get_curse(r->attribs, heal_ct); - if (c!=NULL) { - healingcurse = curse_geteffect(c); - } - } - for (u = r->units; u; u = u->next) { - int umhp = unit_max_hp(u) * u->number; - double p = 1.0; - - /* hp über Maximum bauen sich ab. Wird zb durch Elixier der Macht - * oder verändertes Ausdauertalent verursacht */ - if (u->hp > umhp) { - u->hp -= (int) ceil((u->hp - umhp) / 2.0); - if (u->hp < umhp) u->hp = umhp; - continue; - } - - if (u->race->flags & RCF_NOHEAL) continue; - if (fval(u, UFL_HUNGER)) continue; - - if (fval(r->terrain, SEA_REGION) && u->ship==NULL && !(canswim(u) || canfly(u))) { - continue; - } - - p *= heal_factor(u); - if (u->hp < umhp) { -#ifdef NEW_DAEMONHUNGER_RULE - double maxheal = MAX(u->number, umhp/20.0); -#else - double maxheal = MAX(u->number, umhp/10.0); -#endif - int addhp; - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - if (btype == bt_find("inn")) { - p *= 1.5; - } - /* pro punkt 5% höher */ - p *= (1.0 + healingcurse * 0.05); - - maxheal = p * maxheal; - addhp = (int)maxheal; - maxheal -= addhp; - if (maxheal>0.0 && chance(maxheal)) ++addhp; - - /* Aufaddieren der geheilten HP. */ - u->hp = MIN(u->hp + addhp, umhp); - - /* soll man an negativer regeneration sterben können? */ - assert(u->hp > 0); - } - } - } -} - -static void -remove_exclusive(order ** ordp) -{ - while (*ordp) { - order * ord = *ordp; - if (is_exclusive(ord)) { - *ordp = ord->next; - ord->next = NULL; - free_order(ord); - } else { - ordp = &ord->next; - } - } -} - -static void -defaultorders (void) -{ - region *r; - for (r=regions;r;r=r->next) { - unit *u; - for (u=r->units;u;u=u->next) { - boolean neworders = false; - order ** ordp = &u->orders; - while (*ordp!=NULL) { - order * ord = *ordp; - if (get_keyword(ord)==K_DEFAULT) { - char lbuf[8192]; - order * new_order; - init_tokens(ord); - skip_token(); /* skip the keyword */ - strcpy(lbuf, getstrtoken()); - new_order = parse_order(lbuf, u->faction->locale); - *ordp = ord->next; - ord->next = NULL; - free_order(ord); - if (!neworders) { - /* lange Befehle aus orders und old_orders löschen zu gunsten des neuen */ - remove_exclusive(&u->orders); - remove_exclusive(&u->old_orders); - neworders = true; - ordp = &u->orders; /* we could have broken ordp */ - } - if (new_order) addlist(&u->old_orders, new_order); - } - else ordp = &ord->next; - } - } - } -} - -/* ************************************************************ */ -/* GANZ WICHTIG! ALLE GEÄNDERTEN SPRÜCHE NEU ANZEIGEN */ -/* GANZ WICHTIG! FÜGT AUCH NEUE ZAUBER IN DIE LISTE DER BEKANNTEN EIN */ -/* ************************************************************ */ -#define MAXMAGES 128 /* should be enough */ -static void -update_spells(void) -{ - faction * f; - - for (f=factions;f;f=f->next) { - if (f->magiegebiet!=M_NONE && !is_monsters(f)) { - unit * mages[MAXMAGES]; - unit *u; - int maxlevel = 0, n = 0, i; - - for (u=f->units;u;u=u->nextF) { - if (u->number>0) { - sc_mage *mage = get_mage(u); - if (mage) { - int level = eff_skill(u, SK_MAGIC, u->region); - if (level>maxlevel) maxlevel = level; - assert(nf->max_spelllevel) { - update_spellbook(f, maxlevel); - for (i=0;i!=n;++i) { - sc_mage *mage = get_mage(mages[i]); - while (mage->spells) { - spell_list * slist = mage->spells; - mage->spells = slist->next; - free(slist); - } - } - } - for (i=0;i!=n;++i) { - updatespelllist(mages[i]); - } - } - } -} - -static void -age_factions(void) -{ - faction *f; - - for (f = factions; f; f = f->next) { - ++f->age; - if (f->age+1 < NewbieImmunity()) { - ADDMSG(&f->msgs, msg_message("newbieimmunity", "turns", - NewbieImmunity() - f->age - 1)); - } - } -} - -static int -use_cmd(unit * u, struct order * ord) -{ - const char * t; - int n; - const item_type * itype; - - init_tokens(ord); - skip_token(); - - t = getstrtoken(); - n = atoi((const char *)t); - if (n==0) { - if (findparam(t, u->faction->locale) == P_ANY) { - /* BENUTZE ALLES Yanxspirit */ - n = INT_MAX; - t = getstrtoken(); - } else { - /* BENUTZE Yanxspirit */ - n = 1; - } - } else { - /* BENUTZE 42 Yanxspirit */ - t = getstrtoken(); - } - itype = finditemtype(t, u->faction->locale); - - if (itype!=NULL) { - int i = use_item(u, itype, n, ord); - assert(i<=0 || !"use_item should not return positive values."); - if (i>0) { - log_error(("use_item returned a value>0 for %s\n", resourcename(itype->rtype, 0))); - } - } else { - cmistake(u, ord, 43, MSG_PRODUCE); - } - return 0; -} - -static int -pay_cmd(unit * u, struct order * ord) -{ - if (!u->building) { - cmistake(u, ord, 6, MSG_EVENT); - } else { - param_t p; - init_tokens(ord); - skip_token(); - p = getparam(u->faction->locale); - if (p==P_NOT) { - unit * owner = building_owner(u->building); - if (owner->faction!=u->faction) { - cmistake(u, ord, 1222, MSG_EVENT); - } else { - u->building->flags |= BLD_DONTPAY; - } - } - } - return 0; -} - -static int -claim_cmd(unit * u, struct order * ord) -{ - const char * t; - int n; - const item_type * itype; - - init_tokens(ord); - skip_token(); - - t = getstrtoken(); - n = atoi((const char *)t); - if (n==0) { - n = 1; - } else { - t = getstrtoken(); - } - itype = finditemtype(t, u->faction->locale); - - if (itype!=NULL) { - item ** iclaim = i_find(&u->faction->items, itype); - if (iclaim!=NULL && *iclaim!=NULL) { - n = MIN(n, (*iclaim)->number); - i_change(iclaim, itype, -n); - i_change(&u->items, itype, n); - } - } else { - cmistake(u, ord, 43, MSG_PRODUCE); - } - return 0; -} - -enum { - PROC_THISORDER = 1<<0, - PROC_LONGORDER = 1<<1 -}; -typedef struct processor { - struct processor * next; - int priority; - enum { PR_GLOBAL, PR_REGION_PRE, PR_UNIT, PR_ORDER, PR_REGION_POST } type; - unsigned int flags; - union { - struct { - keyword_t kword; - int (*process)(struct unit *, struct order *); - } per_order; - struct { - void (*process)(struct unit *); - } per_unit; - struct { - void (*process)(struct region *); - } per_region; - struct { - void (*process)(void); - } global; - } data; - const char * name; -} processor; - -static processor * processors; - -processor * -add_proc(int priority, const char * name, int type) -{ - processor **pproc = &processors; - processor *proc; - - while (*pproc) { - proc = *pproc; - if (proc->priority>priority) break; - else if (proc->priority==priority && proc->type>=type) break; - pproc = &proc->next; - } - - proc = malloc(sizeof(processor)); - proc->priority = priority; - proc->type = type; - proc->name = name; - proc->next = *pproc; - *pproc = proc; - return proc; -} - -void -add_proc_order(int priority, keyword_t kword, int (*parser)(struct unit *, struct order *), unsigned int flags, const char * name) -{ - if (!global.disabled[kword]) { - processor * proc = add_proc(priority, name, PR_ORDER); - if (proc) { - proc->data.per_order.process = parser; - proc->data.per_order.kword = kword; - proc->flags = flags; - } - } -} - -void -add_proc_global(int priority, void (*process)(void), const char * name) -{ - processor * proc = add_proc(priority, name, PR_GLOBAL); - if (proc) { - proc->data.global.process = process; - } -} - -void -add_proc_region(int priority, void (*process)(region *), const char * name) -{ - processor * proc = add_proc(priority, name, PR_REGION_PRE); - if (proc) { - proc->data.per_region.process = process; - } -} - -void -add_proc_postregion(int priority, void (*process)(region *), const char * name) -{ - processor * proc = add_proc(priority, name, PR_REGION_POST); - if (proc) { - proc->data.per_region.process = process; - } -} - -void -add_proc_unit(int priority, void (*process)(unit *), const char * name) -{ - processor * proc = add_proc(priority, name, PR_UNIT); - if (proc) { - proc->data.per_unit.process = process; - } -} - -/* per priority, execute processors in order from PR_GLOBAL down to PR_ORDER */ -void -process(void) -{ - processor *proc = processors; - faction * f; - - while (proc) { - int prio = proc->priority; - region *r; - processor *pglobal = proc; - - if (verbosity>=3) printf("- Step %u\n", prio); - while (proc && proc->priority==prio) { - if (proc->name && verbosity>=1) log_stdio(stdout, " - %s\n", proc->name); - proc = proc->next; - } - - while (pglobal && pglobal->priority==prio && pglobal->type==PR_GLOBAL) { - pglobal->data.global.process(); - pglobal = pglobal->next; - } - if (pglobal==NULL || pglobal->priority!=prio) continue; - - for (r = regions; r; r = r->next) { - unit *u; - processor *pregion = pglobal; - - while (pregion && pregion->priority==prio && pregion->type==PR_REGION_PRE) { - pregion->data.per_region.process(r); - pregion = pregion->next; - } - if (pregion==NULL || pregion->priority!=prio) continue; - - if (r->units) { - for (u=r->units;u;u=u->next) { - processor *porder, *punit = pregion; - - while (punit && punit->priority==prio && punit->type==PR_UNIT) { - punit->data.per_unit.process(u); - punit = punit->next; - } - if (punit==NULL || punit->priority!=prio) continue; - - porder = punit; - while (porder && porder->priority==prio && porder->type==PR_ORDER) { - order ** ordp = &u->orders; - if (porder->flags & PROC_THISORDER) ordp = &u->thisorder; - while (*ordp) { - order * ord = *ordp; - if (get_keyword(ord) == porder->data.per_order.kword) { - if (porder->flags & PROC_LONGORDER) { - if (u->number==0) { - ord = NULL; - } else if (u->race == new_race[RC_INSECT] && r_insectstalled(r) && !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) { - ord = NULL; - } else if (LongHunger(u)) { - cmistake(u, ord, 224, MSG_MAGIC); - ord = NULL; - } else if (fval(u, UFL_LONGACTION)) { - cmistake(u, ord, 52, MSG_PRODUCE); - ord = NULL; - } else if (fval(r->terrain, SEA_REGION) && u->race != new_race[RC_AQUARIAN] && !(u->race->flags & RCF_SWIM)) { - /* error message disabled by popular demand */ - ord = NULL; - } - } - if (ord) { - porder->data.per_order.process(u, ord); - } - } - if (!ord || *ordp==ord) ordp=&(*ordp)->next; - } - porder = porder->next; - } - } - } - - while (pregion && pregion->priority==prio && pregion->type!=PR_REGION_POST) { - pregion = pregion->next; - } - - while (pregion && pregion->priority==prio && pregion->type==PR_REGION_POST) { - pregion->data.per_region.process(r); - pregion = pregion->next; - } - if (pregion==NULL || pregion->priority!=prio) continue; - - } - } - - if (verbosity>=3) printf("\n - Leere Gruppen loeschen...\n"); - for (f=factions; f; f=f->next) { - group ** gp = &f->groups; - while (*gp) { - group * g = *gp; - if (g->members==0) { - *gp = g->next; - free_group(g); - } else - gp = &g->next; - } - } - -} - -static void enter_1(region * r) { do_misc(r, false); } -static void enter_2(region * r) { do_misc(r, true); } -static void maintain_buildings_1(region * r) { maintain_buildings(r, false); } -#ifdef COLLAPSE_CHANCE -static void maintain_buildings_2(region * r) { maintain_buildings(r,true); } -#endif -static void reset_moved(unit * u) { freset(u, UFL_MOVED); } - -/** warn about passwords that are not US ASCII. - * even though passwords are technically UTF8 strings, the server receives - * them as part of the Subject of an email when reports are requested. - * This means that we need to limit them to ASCII characters until that - * mechanism has been changed. - */ -static int -warn_password(void) -{ - faction * f = factions; - while (f) { - boolean pwok = true; - const char * c = f->passw; - while (*c && pwok) { - if (!isalnum((unsigned char)*c)) pwok = false; - c++; - } - if (!pwok) { - free(f->passw); - f->passw = strdup(itoa36(rng_int())); - ADDMSG(&f->msgs, msg_message("illegal_password", "newpass", f->passw)); - } - f = f->next; - } - return 0; -} - -void -init_processor(void) -{ - int p; - - p = 10; - add_proc_global(p, &new_units, "Neue Einheiten erschaffen"); - - p+=10; - add_proc_unit(p, &setdefaults, "Default-Befehle"); - add_proc_order(p, K_BANNER, &banner_cmd, 0, NULL); - add_proc_order(p, K_EMAIL, &email_cmd, 0, NULL); - add_proc_order(p, K_PASSWORD, &password_cmd, 0, NULL); - add_proc_order(p, K_SEND, &send_cmd, 0, NULL); - add_proc_order(p, K_GROUP, &group_cmd, 0, NULL); - - p+=10; - add_proc_unit(p, &reset_moved, "Instant-Befehle"); - add_proc_order(p, K_QUIT, &quit_cmd, 0, NULL); - add_proc_order(p, K_URSPRUNG, &origin_cmd, 0, NULL); - add_proc_order(p, K_ALLY, &ally_cmd, 0, NULL); - add_proc_order(p, K_PREFIX, &prefix_cmd, 0, NULL); - add_proc_order(p, K_SETSTEALTH, &setstealth_cmd, 0, NULL); - add_proc_order(p, K_STATUS, &status_cmd, 0, NULL); - add_proc_order(p, K_COMBATSPELL, &combatspell_cmd, 0, NULL); - add_proc_order(p, K_DISPLAY, &display_cmd, 0, NULL); - add_proc_order(p, K_NAME, &name_cmd, 0, NULL); - add_proc_order(p, K_GUARD, &guard_off_cmd, 0, NULL); - add_proc_order(p, K_RESHOW, &reshow_cmd, 0, NULL); - - if (get_param_int(global.parameters, "rules.alliances", 0)==1) { - p+=10; - add_proc_global(p, &alliance_cmd, NULL); - } - - p+=10; - add_proc_global(p, &age_factions, "Parteienalter++"); - add_proc_order(p, K_MAIL, &mail_cmd, 0, "Botschaften"); - - p+=10; /* all claims must be done before we can USE */ - add_proc_region(p, &enter_1, "Kontaktieren & Betreten (1. Versuch)"); - add_proc_order(p, K_USE, &use_cmd, 0, "Benutzen"); - - if (!global.disabled[K_GM]) { - add_proc_global(p, &gmcommands, "GM Kommandos"); - } - - p += 10; /* in case it has any effects on alliance victories */ - add_proc_order(p, K_GIVE, &give_control_cmd, 0, "GIB KOMMANDO"); - - p += 10; /* in case it has any effects on alliance victories */ - add_proc_order(p, K_LEAVE, &leave_cmd, 0, "Verlassen"); - - if (!nobattle) { - add_proc_region(p, &do_battle, "Attackieren"); - } - - if (!global.disabled[K_BESIEGE]) { - p+=10; - add_proc_region(p, &do_siege, "Belagern"); - } - - p+=10; /* can't allow reserve before siege (weapons) */ - add_proc_region(p, &enter_1, "Kontaktieren & Betreten (2. Versuch)"); - add_proc_order(p, K_RESERVE, &reserve_cmd, 0, "Reservieren"); - add_proc_order(p, K_CLAIM, &claim_cmd, 0, NULL); - add_proc_unit(p, &follow_unit, "Folge auf Einheiten setzen"); - - p+=10; /* rest rng again before economics */ - add_proc_region(p, &economics, "Zerstoeren, Geben, Rekrutieren, Vergessen"); - - p+=10; - if (!global.disabled[K_PAY]) { - add_proc_order(p, K_PAY, &pay_cmd, 0, "Gebaeudeunterhalt (disable)"); - } - add_proc_postregion(p, &maintain_buildings_1, "Gebaeudeunterhalt (1. Versuch)"); - - p+=10; /* QUIT fuer sich alleine */ - add_proc_global(p, &quit, "Sterben"); - if (!global.disabled[K_RESTART]) { - add_proc_global(p, &parse_restart, "Neustart"); - } - - if (!global.disabled[K_CAST]) { - p+=10; - add_proc_global(p, &magic, "Zaubern"); - } - - p+=10; - add_proc_order(p, K_TEACH, &teach_cmd, PROC_THISORDER|PROC_LONGORDER, "Lehren"); - p+=10; - add_proc_order(p, K_STUDY, &learn_cmd, PROC_THISORDER|PROC_LONGORDER, "Lernen"); - - p+=10; - add_proc_order(p, K_MAKE, &make_cmd, PROC_THISORDER|PROC_LONGORDER, "Produktion"); - add_proc_postregion(p, &produce, "Arbeiten, Handel, Rekruten"); - add_proc_postregion(p, &split_allocations, "Produktion II"); - - p+=10; - add_proc_region(p, &enter_2, "Kontaktieren & Betreten (3. Versuch)"); - - p+=10; - add_proc_region(p, &sinkships, "Schiffe sinken"); - - p+=10; - add_proc_global(p, &movement, "Bewegungen"); - - if (get_param_int(global.parameters, "work.auto", 0)) { - p+=10; - add_proc_region(p, &auto_work, "Arbeiten (auto)"); - } - - p+=10; - add_proc_order(p, K_GUARD, &guard_on_cmd, 0, "Bewache (an)"); -#if XECMD_MODULE - /* can do together with guard */ - add_proc_order(p, K_XE, &xecmd, 0, "Zeitung"); -#endif - - p+=10; - add_proc_global(p, &encounters, "Zufallsbegegnungen"); - p+=10; - add_proc_unit(p, &monster_kills_peasants, "Monster fressen und vertreiben Bauern"); - - p+=10; - add_proc_global(p, &randomevents, "Zufallsereignisse"); - - p+=10; - - add_proc_global(p, &monthly_healing, "Regeneration (HP)"); - add_proc_global(p, ®eneration_magiepunkte, "Regeneration (Aura)"); - if (!global.disabled[K_DEFAULT]) { - add_proc_global(p, &defaultorders, "Defaults setzen"); - } - add_proc_global(p, &demographics, "Nahrung, Seuchen, Wachstum, Wanderung"); - -#ifdef COLLAPSE_CHANCE - p+=10; - add_proc_region(p, &maintain_buildings_2, "Gebaeudeunterhalt (2. Versuch)"); -#endif - - if (!global.disabled[K_SORT]) { - p+=10; - add_proc_global(p, &reorder, "Einheiten sortieren"); - } - add_proc_order(p, K_PROMOTION, &promotion_cmd, 0, "Heldenbefoerderung"); - if (!global.disabled[K_NUMBER]) { - add_proc_order(p, K_NUMBER, &renumber_cmd, 0, "Neue Nummern (Einheiten)"); - p+=10; - add_proc_global(p, &renumber_factions, "Neue Nummern"); - } -} - -void -processorders (void) -{ - static int init = 0; - - if (!init) { - init_processor(); - init = 1; - } - update_spells(); - process(); - /*************************************************/ - - if (get_param_int(global.parameters, "modules.markets", 0)) { - do_markets(); - } - - if (verbosity>=1) puts(" - Attribute altern"); - ageing(); - remove_empty_units(); - - /* must happen AFTER age, because that would destroy them right away */ - if (get_param_int(global.parameters, "modules.wormholes", 0)) { - create_wormholes(); - } - - /* immer ausführen, wenn neue Sprüche dazugekommen sind, oder sich - * Beschreibungen geändert haben */ - update_spells(); - warn_password(); -} - -int -writepasswd(void) -{ - FILE * F; - char zText[128]; - - sprintf(zText, "%s/passwd", basepath()); - F = cfopen(zText, "w"); - if (F) { - faction *f; - puts("writing passwords..."); - - for (f = factions; f; f = f->next) { - fprintf(F, "%s:%s:%s:%s:%u\n", - factionid(f), f->email, f->passw, f->override, f->subscription); - } - fclose(F); - return 0; - } - return 1; -} - -void -update_subscriptions(void) -{ - FILE * F; - char zText[MAX_PATH]; - faction * f; - strcat(strcpy(zText, basepath()), "/subscriptions"); - F = fopen(zText, "r"); - if (F==NULL) { - log_warning((0, "could not open %s.\n", zText)); - return; - } - for (;;) { - char zFaction[5]; - int subscription, fno; - if (fscanf(F, "%d %s", &subscription, zFaction)<=0) break; - fno = atoi36(zFaction); - f = findfaction(fno); - if (f!=NULL) { - f->subscription=subscription; - } - } - fclose(F); - - sprintf(zText, "subscriptions.%u", turn); - F = fopen(zText, "w"); - for (f=factions;f!=NULL;f=f->next) { - fprintf(F, "%s:%u:%s:%s:%s:%u:\n", - itoa36(f->no), f->subscription, f->email, f->override, - dbrace(f->race), f->lastorders); - } - fclose(F); -} - -int -init_data(const char * filename, const char * catalog) -{ - int l; - - l = read_xml(filename, catalog); - if (l) return l; - - init_locales(); - init_archetypes(); - - if (turn<0) { - turn = first_turn; - } - return 0; -} - -#ifndef DISABLE_TESTS -#include "laws_test.c" -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#pragma region includes + +#include +#include +#include "laws.h" + +#include +#include + +/* gamecode includes */ +#include "economy.h" +#include "archetype.h" +#include "monster.h" +#include "randenc.h" +#include "spy.h" +#include "study.h" +#include "market.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for volcanoes in emigration (needs a flag) */ +#include + +/* attributes includes */ +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#pragma endregion + +/* chance that a peasant dies of starvation: */ +#define PEASANT_STARVATION_CHANCE 0.9F +/* Pferdevermehrung */ +#define HORSEGROWTH 4 +/* Wanderungschance pro Pferd */ +#define HORSEMOVE 3 +/* Vermehrungschance pro Baum */ +#define FORESTGROWTH 10000 /* In Millionstel */ + +/** Ausbreitung und Vermehrung */ +#define MAXDEMAND 25 +#define DMRISE 0.1F /* weekly chance that demand goes up */ +#define DMRISEHAFEN 0.2F /* weekly chance that demand goes up with harbor */ + + +/* - exported global symbols ----------------------------------- */ +boolean nobattle = false; +boolean nomonsters = false; +/* ------------------------------------------------------------- */ + +static int +RemoveNMRNewbie(void) { + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "nmr.removenewbie", 0); + } + return value; +} + +static void +restart_race(unit *u, const race * rc) +{ + faction * oldf = u->faction; + faction *f = addfaction(oldf->email, oldf->passw, rc, oldf->locale, oldf->subscription); + unit * nu = addplayer(u->region, f); + order ** ordp = &u->orders; + f->subscription = u->faction->subscription; + f->age = u->faction->age; + fset(f, FFL_RESTART); + if (f->subscription) { + sql_print(("UPDATE subscriptions set faction='%s', race='%s' where id=%u;\n", + itoa36(f->no), dbrace(rc), f->subscription)); + } + f->magiegebiet = u->faction->magiegebiet; + f->options = u->faction->options; + free_orders(&nu->orders); + nu->orders = u->orders; + u->orders = NULL; + while (*ordp) { + order * ord = *ordp; + if (get_keyword(ord) != K_RESTART) { + *ordp = ord->next; + ord->next = NULL; + if (u->thisorder == ord) set_order(&u->thisorder, NULL); + } else { + ordp = &ord->next; + } + } + destroyfaction(u->faction); +} + +static void +checkorders(void) +{ + faction *f; + + if (verbosity>=1) puts(" - Warne spaete Spieler..."); + for (f = factions; f; f = f->next) + if (!is_monsters(f) && turn - f->lastorders == NMRTimeout() - 1) + ADDMSG(&f->msgs, msg_message("turnreminder", "")); +} + +static boolean +help_money(const unit * u) +{ + if (u->race->ec_flags & GIVEITEM) return true; + return false; +} + +static void +help_feed(unit * donor, unit * u, int * need_p) +{ + int need = *need_p; + int give = get_money(donor) - lifestyle(donor); + give = MIN(need, give); + + if (give>0) { + change_money(donor, -give); + change_money(u, give); + need -= give; + add_spende(donor->faction, u->faction, give, donor->region); + } + *need_p = need; +} + +static void +get_food(region *r) +{ + plane * pl = rplane(r); + unit *u; + int peasantfood = rpeasants(r)*10; + static int food_rules = -1; + + if (food_rules<0) { + food_rules = get_param_int(global.parameters, "rules.economy.food", 0); + } + + /* 1. Versorgung von eigenen Einheiten. Das vorhandene Silber + * wird zunächst so auf die Einheiten aufgeteilt, dass idealerweise + * jede Einheit genug Silber für ihren Unterhalt hat. */ + + for (u = r->units; u; u = u->next) { + int need = lifestyle(u); + + /* Erstmal zurücksetzen */ + freset(u, UFL_HUNGER); + + if (u->ship && (u->ship->flags&SF_FISHING)) { + unit * v; + int c = 2; + for (v=u;c>0 && v;v=v->next) { + if (v->ship==u->ship) { + int get = 0; + if (v->number<=c) { + get = lifestyle(v); + } else { + get = lifestyle(v) * c / v->number; + } + if (get) { + change_money(v, get); + } + } + c -= v->number; + } + u->ship->flags -= SF_FISHING; + } + + if (food_rules&1) { + faction * owner = region_get_owner(r); + /* if the region is owned, and the owner is nice, then we'll get + * food from the peasants - should not be used with WORK */ + if (owner!=NULL && (get_alliance(owner, u->faction) & HELP_MONEY)) { + int rm = rmoney(r); + int use = MIN(rm, need); + rsetmoney(r, rm-use); + need -= use; + } + } + + need -= get_money(u); + if (need > 0) { + unit *v; + + for (v = r->units; need && v; v = v->next) { + if (v->faction == u->faction && help_money(v)) { + int give = get_money(v) - lifestyle(v); + give = MIN(need, give); + if (give>0) { + change_money(v, -give); + change_money(u, give); + need -= give; + } + } + } + } + } + + /* 2. Versorgung durch Fremde. Das Silber alliierter Einheiten wird + * entsprechend verteilt. */ + for (u = r->units; u; u = u->next) { + int need = lifestyle(u); + faction * f = u->faction; + + need -= MAX(0, get_money(u)); + + if (need > 0) { + unit *v; + + if (food_rules&2) { + /* the owner of the region is the first faction to help out when you're hungry */ + faction * owner = region_get_owner(r); + if (owner && owner!=u->faction) { + for (v=r->units;v;v=v->next) { + if (v->faction==owner && alliedunit(v, f, HELP_MONEY) && help_money(v)) { + help_feed(v, u, &need); + break; + } + } + } + } + for (v = r->units; need && v; v = v->next) { + if (v->faction != f && alliedunit(v, f, HELP_MONEY) && help_money(v)) { + help_feed(v, u, &need); + } + } + + /* Die Einheit hat nicht genug Geld zusammengekratzt und + * nimmt Schaden: */ + if (need > 0) { + int lspp = lifestyle(u)/u->number; + if (lspp > 0) { + int number = (need+lspp-1)/lspp; + if (hunger(number, u)) fset(u, UFL_HUNGER); + } + } + } + } + + /* 3. bestimmen, wie viele Bauern gefressen werden. + * bei fehlenden Bauern den Dämon hungern lassen + */ + for (u = r->units; u; u = u->next) { + if (u->race == new_race[RC_DAEMON]) { + unit * donor = r->units; + int hungry = u->number; + + while (donor!=NULL && hungry>0) { + /* always start with the first known unit that may have some blood */ + static const struct potion_type * pt_blood; + if (pt_blood==NULL) { + const item_type * it_blood = it_find("peasantblood"); + if (it_blood) pt_blood = it_blood->rtype->ptype; + } + if (pt_blood!=NULL) { + while (donor!=NULL) { + if (donor->race==new_race[RC_DAEMON]) { + if (get_effect(donor, pt_blood)) { + /* if he's in our faction, drain him: */ + if (donor->faction==u->faction) break; + } + } + donor = donor->next; + } + if (donor != NULL) { + int blut = get_effect(donor, pt_blood); + blut = MIN(blut, hungry); + change_effect(donor, pt_blood, -blut); + hungry -= blut; + } + } + } + if (pl == NULL || !fval(pl, PFL_NOFEED)) { + if (peasantfood>=hungry) { + peasantfood -= hungry; + hungry = 0; + } else { + hungry -= peasantfood; + peasantfood = 0; + } + if (hungry > 0) { + static int demon_hunger = -1; + if (demon_hunger<0) { + demon_hunger = get_param_int(global.parameters, "hunger.demons", 0); + } + if (demon_hunger==0) { + /* nicht gefütterte dämonen hungern */ +#ifdef PEASANT_HUNGRY_DAEMONS_HAVE_FULL_SKILLS + /* wdw special rule */ + hunger(hungry, u); +#else + if (hunger(hungry, u)) fset(u, UFL_HUNGER); +#endif + /* used to be: hunger(hungry, u); */ + } else { + /* no damage, but set the hungry-flag */ + fset(u, UFL_HUNGER); + } + } + } + } + } + rsetpeasants(r, peasantfood/10); + + /* 3. Von den überlebenden das Geld abziehen: */ + for (u = r->units; u; u = u->next) { + int need = MIN(get_money(u), lifestyle(u)); + change_money(u, -need); + } +} + +static void +age_unit(region * r, unit * u) +{ + if (u->race == new_race[RC_SPELL]) { + if (--u->age <= 0) { + remove_unit(&r->units, u); + } + } else { + ++u->age; + if (u->number>0 && u->race->age) { + u->race->age(u); + } + } +#ifdef ASTRAL_ITEM_RESTRICTIONS + if (u->region && is_astral(u->region)) { + item ** itemp = &u->items; + while (*itemp) { + item * itm = *itemp; + if ((itm->type->flags & ITF_NOTLOST) == 0) { + if (itm->type->flags & (ITF_BIG|ITF_ANIMAL|ITF_CURSED)) { + ADDMSG(&u->faction->msgs, msg_message("itemcrumble", "unit region item amount", + u, u->region, itm->type->rtype, itm->number)); + i_free(i_remove(itemp, itm)); + continue; + } + } + itemp=&itm->next; + } + } +#endif +} + + +static void +live(region * r) +{ + unit **up = &r->units; + + get_food(r); + + while (*up) { + unit * u = *up; + /* IUW: age_unit() kann u loeschen, u->next ist dann + * undefiniert, also muessen wir hier schon das nächste + * Element bestimmen */ + + int effect = get_effect(u, oldpotiontype[P_FOOL]); + if (effect > 0) { /* Trank "Dumpfbackenbrot" */ + skill * sv = u->skills, * sb = NULL; + while (sv!=u->skills+u->skill_size) { + if (sb==NULL || skill_compare(sv, sb)>0) { + sb = sv; + } + ++sv; + } + /* bestes Talent raussuchen */ + if (sb!=NULL) { + int weeks = MIN(effect, u->number); + reduce_skill(u, sb, weeks); + ADDMSG(&u->faction->msgs, msg_message("dumbeffect", + "unit weeks skill", u, weeks, (skill_t)sb->id)); + } /* sonst Glück gehabt: wer nix weiß, kann nix vergessen... */ + change_effect(u, oldpotiontype[P_FOOL], -effect); + } + age_unit(r, u); + if (*up==u) up=&u->next; + } +} + +/* + * This procedure calculates the number of emigrating peasants for the given + * region r. There are two incentives for peasants to emigrate: + * 1) They prefer the less crowded areas. + * Example: mountains, 700 peasants (max 1000), 70% inhabited + * plain, 5000 peasants (max 10000), 50% inhabited + * 700*(PEASANTSWANDER_WEIGHT/100)*((70-50)/100) peasants wander + * from mountains to plain. + * Effect : peasents will leave densely populated regions. + * 2) Peasants prefer richer neighbour regions. + * Example: region A, 700 peasants, wealth $10500, $15 per head + * region B, 2500 peasants, wealth $25000, $10 per head + * Some peasants will emigrate from B to A because $15 > $10 + * exactly: 2500*(PEASANTSGREED_WEIGHT1/100)*((15-10)/100) + * Not taken in consideration: + * - movement because of monsters. + * - movement because of wars + * - movement because of low loyalty relating to present parties. + */ + +#define MAX_EMIGRATION(p) ((p)/MAXDIRECTIONS) +#define MAX_IMMIGRATION(p) ((p)*2/3) + +static void +calculate_emigration(region *r) +{ + int i; + int maxp = maxworkingpeasants(r); + int rp = rpeasants(r); + int max_immigrants = MAX_IMMIGRATION(maxp-rp); + + if (r->terrain == newterrain(T_VOLCANO) || r->terrain == newterrain(T_VOLCANO_SMOKING)) { + max_immigrants = max_immigrants/10; + } + + for (i = 0; max_immigrants>0 && i != MAXDIRECTIONS; i++) { + int dir = (turn+i) % MAXDIRECTIONS; + region *rc = rconnect(r, (direction_t)dir); + + if (rc != NULL && fval(rc->terrain, LAND_REGION)) { + int rp2 = rpeasants(rc); + int maxp2 = maxworkingpeasants(rc); + int max_emigration = MAX_EMIGRATION(rp2-maxp2); + + if (max_emigration>0) { + max_emigration = MIN(max_emigration, max_immigrants); + r->land->newpeasants += max_emigration; + rc->land->newpeasants -= max_emigration; + max_immigrants -= max_emigration; + } + } + } +} + +/** Bauern vermehren sich */ + +static void +peasants(region * r) +{ + int peasants = rpeasants(r); + int money = rmoney(r); + int maxp = production(r) * MAXPEASANTS_PER_AREA; + int n, satiated; + int dead = 0; + + /* Bis zu 1000 Bauern können Zwillinge bekommen oder 1000 Bauern + * wollen nicht! */ + + if (peasants>0) { + int glueck = 0; + double fraction = peasants * 0.0001F * PEASANTGROWTH; + int births = (int)fraction; + attrib * a = a_find(r->attribs, &at_peasantluck); + + if (rng_double()<(fraction-births)) { + /* because we don't want regions that never grow pga. rounding. */ + ++births; + } + if (a!=NULL) { + glueck = a->data.i * 1000; + } + + for (n = peasants; n; --n) { + int chances = 0; + + if (glueck>0) { + --glueck; + chances += PEASANTLUCK; + } + + while (chances--) { + if (rng_int() % 10000 < PEASANTGROWTH) { + /* Only raise with 75% chance if peasants have + * reached 90% of maxpopulation */ + if (peasants/(float)maxp < 0.9 || chance(PEASANTFORCE)) { + ++births; + } + } + } + } + peasants += births; + } + + /* Alle werden satt, oder halt soviele für die es auch Geld gibt */ + + satiated = MIN(peasants, money / maintenance_cost(NULL)); + rsetmoney(r, money - satiated * maintenance_cost(NULL)); + + /* Von denjenigen, die nicht satt geworden sind, verhungert der + * Großteil. dead kann nie größer als rpeasants(r) - satiated werden, + * so dass rpeasants(r) >= 0 bleiben muß. */ + + /* Es verhungert maximal die unterernährten Bevölkerung. */ + + n = MIN(peasants - satiated, rpeasants(r)); + dead += (int)(0.5F + n * PEASANT_STARVATION_CHANCE); + + if (dead > 0) { + message * msg = add_message(&r->msgs, msg_message("phunger", "dead", dead)); + msg_release(msg); + peasants -= dead; + } + + rsetpeasants(r, peasants); +} + +/* ------------------------------------------------------------- */ + +typedef struct migration { + struct migration * next; + region * r; + int horses; + int trees; +} migration; + +#define MSIZE 1023 +migration * migrants[MSIZE]; +migration * free_migrants; + +static migration * +get_migrants(region * r) +{ + int key = reg_hashkey(r); + int index = key % MSIZE; + migration * m = migrants[index]; + while (m && m->r != r) + m = m->next; + if (m == NULL) { + /* Es gibt noch keine Migration. Also eine erzeugen + */ + m = free_migrants; + if (!m) m = calloc(1, sizeof(migration)); + else { + free_migrants = free_migrants->next; + m->horses = 0; + m->trees = 0; + } + m->r = r; + m->next = migrants[index]; + migrants[index] = m; + } + return m; +} + +static void +migrate(region * r) +{ + int key = reg_hashkey(r); + int index = key % MSIZE; + migration ** hp = &migrants[index]; + fset(r, RF_MIGRATION); + while (*hp && (*hp)->r != r) hp = &(*hp)->next; + if (*hp) { + migration * m = *hp; + rsethorses(r, rhorses(r) + m->horses); + /* Was macht das denn hier? + * Baumwanderung wird in trees() gemacht. + * wer fragt das? Die Baumwanderung war abhängig von der + * Auswertungsreihenfolge der regionen, + * das hatte ich geändert. jemand hat es wieder gelöscht, toll. + * ich habe es wieder aktiviert, muß getestet werden. + */ + *hp = m->next; + m->next = free_migrants; + free_migrants = m; + } +} + +static void +horses(region * r) +{ + int horses, maxhorses; + direction_t n; + + /* Logistisches Wachstum, Optimum bei halbem Maximalbesatz. */ + maxhorses = maxworkingpeasants(r)/10; + maxhorses = MAX(0, maxhorses); + horses = rhorses(r); + if (horses > 0) { + if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { + rsethorses(r, (int)(horses*0.9F)); + } else if (maxhorses) { + int i; + double growth = (RESOURCE_QUANTITY * HORSEGROWTH * 200 * (maxhorses-horses))/maxhorses; + + if (growth>0) { + if (a_find(r->attribs, &at_horseluck)) growth *= 2; + /* printf("Horses: <%d> %d -> ", growth, horses); */ + i = (int)(0.5F + (horses * 0.0001F) * growth); + /* printf("%d\n", horses); */ + rsethorses(r, horses + i); + } + } + } + + /* Pferde wandern in Nachbarregionen. + * Falls die Nachbarregion noch berechnet + * werden muß, wird eine migration-Struktur gebildet, + * die dann erst in die Berechnung der Nachbarstruktur einfließt. + */ + + for(n = 0; n != MAXDIRECTIONS; n++) { + region * r2 = rconnect(r, n); + if (r2 && fval(r2->terrain, WALK_INTO)) { + int pt = (rhorses(r) * HORSEMOVE)/100; + pt = (int)normalvariate(pt, pt/4.0); + pt = MAX(0, pt); + if (fval(r2, RF_MIGRATION)) + rsethorses(r2, rhorses(r2) + pt); + else { + migration * nb; + /* haben wir die Migration schonmal benutzt? + * wenn nicht, müssen wir sie suchen. + * Wandernde Pferde vermehren sich nicht. + */ + nb = get_migrants(r2); + nb->horses += pt; + } + /* Wandernde Pferde sollten auch abgezogen werden */ + rsethorses(r, rhorses(r) - pt); + } + } + assert(rhorses(r) >= 0); +} + +static int +count_race(const region *r, const race *rc) +{ + unit *u; + int c = 0; + + for(u = r->units; u; u=u->next) + if(u->race == rc) c += u->number; + + return c; +} + +extern struct attrib_type at_germs; + +static void +growing_trees_e3(region * r, const int current_season, const int last_weeks_season) +{ + const static int transform[4][3] = { + { -1, -1, 0 }, + { TREE_SEED, TREE_SAPLING, 2 }, + { TREE_SAPLING, TREE_TREE, 2 }, + { TREE_TREE, TREE_SEED, 2 } + }; + + if (r->land && current_season!=last_weeks_season && transform[current_season][2]) { + int src_type = transform[current_season][0]; + int dst_type = transform[current_season][1]; + int src = rtrees(r, src_type); + int dst = rtrees(r, dst_type); + int grow = src/transform[current_season][2]; + if (grow>0) { + if (src_type!=TREE_TREE) { + rsettrees(r, src_type, src-grow); + } + rsettrees(r, dst_type, dst+grow); + + if (dst_type==TREE_SEED && r->terrain->size) { + region * rn[MAXDIRECTIONS]; + int d; + double fgrow = grow/(double)MAXDIRECTIONS; + + get_neighbours(r, rn); + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rx = rn[d]; + if (rx && rx->land) { + double scale = 1.0; + int g; + double fg, ch; + int seeds = rtrees(rx, dst_type); + + if (r->terrain->size>rx->terrain->size) { + scale = (scale * rx->terrain->size)/r->terrain->size; + } + fg = scale * fgrow; + g = (int)fg; + ch = fg - g; + if (chance(ch)) ++g; + if (g>0) { + rsettrees(rx, dst_type, seeds + g); + } + } + } + } + } + } +} + +static void +growing_trees(region * r, const int current_season, const int last_weeks_season) +{ + int growth, grownup_trees, i, seeds, sprout; + direction_t d; + attrib *a; + + if(current_season == SEASON_SUMMER || current_season == SEASON_AUTUMN) { + double seedchance = 0.01F * RESOURCE_QUANTITY; + int elves = count_race(r, new_race[RC_ELF]); + + a = a_find(r->attribs, &at_germs); + if(a && last_weeks_season == SEASON_SPRING) { + /* ungekeimte Samen bleiben erhalten, Sprößlinge wachsen */ + sprout = MIN(a->data.sa[1], rtrees(r, 1)); + /* aus dem gesamt Sprößlingepool abziehen */ + rsettrees(r, 1, rtrees(r, 1) - sprout); + /* zu den Bäumen hinzufügen */ + rsettrees(r, 2, rtrees(r, 2) + sprout); + + a_removeall(&r->attribs, &at_germs); + } + + if(is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { + rsettrees(r, 1, (int)(rtrees(r, 1) * 0.9)); + rsettrees(r, 2, (int)(rtrees(r, 2) * 0.9)); + return; + } + + if (production(r) <= 0) return; + + /* Grundchance 1.0% */ + /* Jeder Elf in der Region erhöht die Chance marginal */ + elves = MIN(elves, (production(r)*MAXPEASANTS_PER_AREA)/8); + if (elves) { + seedchance += 1.0-pow(0.99999, elves * RESOURCE_QUANTITY); + } + grownup_trees = rtrees(r, 2); + seeds = 0; + + if (grownup_trees>0) { + double remainder = seedchance*grownup_trees; + seeds = (int)(remainder); + remainder -= seeds; + if (chance(remainder)) { + ++seeds; + } + if (seeds>0) { + seeds += rtrees(r, 0); + rsettrees(r, 0, seeds); + } + } + + /* Bäume breiten sich in Nachbarregionen aus. */ + + /* Gesamtzahl der Samen: + * bis zu 6% (FORESTGROWTH*3) der Bäume samen in die Nachbarregionen */ + seeds = (rtrees(r, 2) * FORESTGROWTH * 3)/1000000; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * r2 = rconnect(r, d); + if (r2 && fval(r2->terrain, LAND_REGION) && r2->terrain->size) { + /* Eine Landregion, wir versuchen Samen zu verteilen: + * Die Chance, das Samen ein Stück Boden finden, in dem sie + * keimen können, hängt von der Bewuchsdichte und der + * verfügbaren Fläche ab. In Gletschern gibt es weniger + * Möglichkeiten als in Ebenen. */ + sprout = 0; + seedchance = (1000 * maxworkingpeasants(r2)) / r2->terrain->size; + for(i=0; iattribs, C_CURSED_BY_THE_GODS, 0)) return; + + /* in at_germs merken uns die Zahl der Samen und Sprößlinge, die + * dieses Jahr älter werden dürfen, damit nicht ein Same im selben + * Zyklus zum Baum werden kann */ + a = a_find(r->attribs, &at_germs); + if(!a) { + a = a_add(&r->attribs, a_new(&at_germs)); + a->data.sa[0] = (short)rtrees(r, 0); + a->data.sa[1] = (short)rtrees(r, 1); + } + /* wir haben 6 Wochen zum wachsen, jeder Same/Sproß hat 18% Chance + * zu wachsen, damit sollten nach 5-6 Wochen alle gewachsen sein */ + growth = 1800; + + /* Samenwachstum */ + + /* Raubbau abfangen, es dürfen nie mehr Samen wachsen, als aktuell + * in der Region sind */ + seeds = MIN(a->data.sa[0], rtrees(r, 0)); + sprout = 0; + + for(i=0;idata.sa[0] = (short)(seeds - sprout); + /* aus dem gesamt Samenpool abziehen */ + rsettrees(r, 0, rtrees(r, 0) - sprout); + /* zu den Sprößlinge hinzufügen */ + rsettrees(r, 1, rtrees(r, 1) + sprout); + + /* Baumwachstum */ + + /* hier gehen wir davon aus, das Jungbäume nicht ohne weiteres aus + * der Region entfernt werden können, da Jungbäume in der gleichen + * Runde nachwachsen, wir also nicht mehr zwischen diesjährigen und + * 'alten' Jungbäumen unterscheiden könnten */ + sprout = MIN(a->data.sa[1], rtrees(r, 1)); + grownup_trees = 0; + + for(i=0;idata.sa[1] = (short)(sprout - grownup_trees); + /* aus dem gesamt Sprößlingepool abziehen */ + rsettrees(r, 1, rtrees(r, 1) - grownup_trees); + /* zu den Bäumen hinzufügen */ + rsettrees(r, 2, rtrees(r, 2) + grownup_trees); + } +} + +static void +growing_herbs(region * r, const int current_season, const int last_weeks_season) +{ + /* Jetzt die Kräutervermehrung. Vermehrt wird logistisch: + * + * Jedes Kraut hat eine Wahrscheinlichkeit von (100-(vorhandene + * Kräuter))% sich zu vermehren. */ + if (current_season != SEASON_WINTER) { + int i; + for (i = rherbs(r); i > 0; i--) { + if (rng_int()%100 < (100-rherbs(r))) rsetherbs(r, (short)(rherbs(r)+1)); + } + } +} + +void +demographics(void) +{ + region *r; + static int last_weeks_season = -1; + static int current_season = -1; + + if (current_season<0) { + gamedate date; + get_gamedate(turn, &date); + current_season = date.season; + get_gamedate(turn-1, &date); + last_weeks_season = date.season; + } + + for (r = regions; r; r = r->next) { + ++r->age; /* also oceans. no idea why we didn't always do that */ + live(r); + /* check_split_dragons(); */ + + if (!fval(r->terrain, SEA_REGION)) { + /* die Nachfrage nach Produkten steigt. */ + struct demand * dmd; + if (r->land) { + static int plant_rules = -1; + + if (plant_rules<0) { + plant_rules = get_param_int(global.parameters, "rules.economy.grow", 0); + } + for (dmd=r->land->demands;dmd;dmd=dmd->next) { + if (dmd->value>0 && dmd->value < MAXDEMAND) { + float rise = DMRISE; + if (buildingtype_exists(r, bt_find("harbour"), true)) rise = DMRISEHAFEN; + if (rng_double()value; + } + } + /* Seuchen erst nachdem die Bauern sich vermehrt haben + * und gewandert sind */ + + calculate_emigration(r); + peasants(r); + if (r->age>20) { + plagues(r, false); + } + horses(r); + if (plant_rules==0) { /* E1 */ + growing_trees(r, current_season, last_weeks_season); + growing_herbs(r, current_season, last_weeks_season); + } else { /* E3 */ + growing_trees_e3(r, current_season, last_weeks_season); + } + } + + update_resources(r); + if (r->land) migrate(r); + } + } + while (free_migrants) { + migration * m = free_migrants->next; + free(free_migrants); + free_migrants = m; + }; + if (verbosity>=1) putchar('\n'); + + remove_empty_units(); + + if (verbosity>=1) puts(" - Einwanderung..."); + for (r = regions; r; r = r->next) { + if (r->land && r->land->newpeasants) { + int rp = rpeasants(r) + r->land->newpeasants; + rsetpeasants(r, MAX(0, rp)); + } + } + + checkorders(); +} +/* ------------------------------------------------------------- */ + +static int +modify(int i) +{ + int c; + + c = i * 2 / 3; + + if (c >= 1) { + return (c + rng_int() % c); + } else { + return (i); + } +} + +static void +inactivefaction(faction * f) +{ + FILE *inactiveFILE; + char zText[128]; + + sprintf(zText, "%s/%s", datapath(), "inactive"); + inactiveFILE = fopen(zText, "a"); + + if (inactiveFILE) { + fprintf(inactiveFILE, "%s:%s:%d:%d\n", + factionid(f), + LOC(default_locale, rc_name(f->race, 1)), + modify(count_all(f)), + turn - f->lastorders); + + fclose(inactiveFILE); + } +} + +static void +transfer_faction(faction *f, faction *f2) +{ + unit *u, *un; + + for (u = f->units; u;) { + un = u->nextF; + if(!unit_has_cursed_item(u) + && !has_skill(u, SK_MAGIC) + && !has_skill(u, SK_ALCHEMY)) { + u_setfaction(u, f2); + } + u = un; + } +} + +static int +restart_cmd(unit * u, struct order * ord) +{ + init_tokens(ord); + skip_token(); /* skip keyword */ + + if (!fval(u->region->terrain, LAND_REGION)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); + } else { + const char * s_race = getstrtoken(), * s_pass; + const race * frace = findrace(s_race, u->faction->locale); + + if (!frace) { + frace = u->faction->race; + s_pass = s_race; + } else { + s_pass = getstrtoken(); + } + + if (u->faction->age > 3 && fval(u->faction, FFL_RESTART)) { + cmistake(u, ord, 314, MSG_EVENT); + return 0; + } + + if (/* frace != u->faction->race && */ u->faction->age < 81) { + cmistake(u, ord, 241, MSG_EVENT); + return 0; + } + + if (!playerrace(frace)) { + cmistake(u, ord, 243, MSG_EVENT); + return 0; + } + + if (!checkpasswd(u->faction, (const char *)s_pass, false)) { + cmistake(u, ord, 86, MSG_EVENT); + log_warning(("RESTART with wrong password, faction %s, pass %s\n", + factionid(u->faction), s_pass)); + return 0; + } + restart_race(u, frace); + return -1; + } + return 0; +} + +static boolean +EnhancedQuit(void) +{ + static int value = -1; + if (value<0) { + const char * str = get_param(global.parameters, "alliance.transferquit"); + value = (str!=0 && strcmp(str, "true")==0); + } + return value; +} + +static int +quit_cmd(unit * u, struct order * ord) +{ + faction * f = u->faction; + const char * passwd; + + init_tokens(ord); + skip_token(); /* skip keyword */ + + passwd = getstrtoken(); + if (checkpasswd(f, (const char *)passwd, false)) { + if (EnhancedQuit()) { + int f2_id = getid(); + if (f2_id>0) { + faction *f2 = findfaction(f2_id); + + if(f2 == NULL) { + cmistake(u, ord, 66, MSG_EVENT); + return 0; + } else if (!u->faction->alliance || u->faction->alliance != f2->alliance) { + cmistake(u, ord, 315, MSG_EVENT); + return 0; + } else if(!alliedfaction(NULL, f, f2, HELP_MONEY)) { + cmistake(u, ord, 316, MSG_EVENT); + return 0; + } else { + variant var; + var.i = f2_id; + a_add(&f->attribs, object_create("quit", TINTEGER, var)); + } + } + } + fset(f, FFL_QUIT); + } else { + char buffer[64]; + write_order(ord, buffer, sizeof(buffer)); + cmistake(u, ord, 86, MSG_EVENT); + log_warning(("QUIT with illegal password for faction %s: %s\n", + factionid(f), buffer)); + } + return 0; +} + +static void +quit(void) +{ + faction ** fptr = &factions; + while (*fptr) { + faction * f = *fptr; + if (f->flags & FFL_QUIT) { + if (EnhancedQuit()) { + /* this doesn't work well (use object_name()) */ + attrib * a = a_find(f->attribs, &at_object); + if (a) { + variant var; + object_type type; + var.i = 0; + object_get(a, &type, &var); + assert(var.i && type==TINTEGER); + if (var.i) { + int f2_id = var.i; + faction *f2 = findfaction(f2_id); + + assert(f2_id>0); + assert(f2!=NULL); + transfer_faction(f, f2); + } + } + } + destroyfaction(f); + } + if (*fptr==f) fptr=&f->next; + } +} + +int dropouts[2]; +int * age = NULL; + +static void +nmr_death(faction * f) +{ + static int rule = -1; + if (rule<0) rule = get_param_int(global.parameters, "rules.nmr.destroy", 0); + if (rule) { + unit * u; + for (u=f->units;u;u=u->nextF) { + if (u->building && fval(u, UFL_OWNER)) { + remove_building(&u->region->buildings, u->building); + } + } + } +} + +static void +parse_restart(void) +{ + region *r; + faction *f; + + /* Sterben erst nachdem man allen anderen gegeben hat - bzw. man kann + * alles machen, was nicht ein dreißigtägiger Befehl ist. */ + + for (r = regions; r; r = r->next) { + unit * u, * un; + for (u = r->units; u;) { + order * ord; + + un = u->next; + for (ord = u->orders; ord!=NULL; ord = ord->next) { + if (get_keyword(ord) == K_RESTART) { + if (u->number > 0) { + if (restart_cmd(u, ord)!=0) { + break; + } + } + } + } + u = un; + } + } + + if (verbosity>=1) puts(" - beseitige Spieler, die sich zu lange nicht mehr gemeldet haben..."); + + for (f = factions; f; f = f->next) { + if(fval(f, FFL_NOIDLEOUT)) f->lastorders = turn; + if (NMRTimeout()>0 && turn - f->lastorders >= NMRTimeout()) { + nmr_death(f); + destroyfaction(f); + continue; + } + if (fval(f, FFL_OVERRIDE)) { + free(f->override); + f->override = strdup(itoa36(rng_int())); + freset(f, FFL_OVERRIDE); + } + if (turn!=f->lastorders) { + char info[256]; + sprintf(info, "%d Einheiten, %d Personen, %d Silber", + f->no_units, f->num_total, f->money); + if (f->subscription) { + sql_print(("UPDATE subscriptions SET lastturn=%d, password='%s', info='%s' WHERE id=%u;\n", + f->lastorders, f->override, info, f->subscription)); + } + } else { + if (f->subscription) { + sql_print(("UPDATE subscriptions SET status='ACTIVE', lastturn=%d, firstturn=greatest(firstturn,%d), password='%s' WHERE id=%u;\n", + f->lastorders, f->lastorders-f->age, + f->override, f->subscription)); + } + } + + if (NMRTimeout()>0 && turn - f->lastorders >= (NMRTimeout() - 1)) { + inactivefaction(f); + continue; + } + } + if (verbosity>=1) { + puts(" - beseitige Spieler, die sich nach der Anmeldung nicht " + "gemeldet haben..."); + } + + age = calloc(MAX(4,turn+1), sizeof(int)); + for (f = factions; f; f = f->next) if (!is_monsters(f)) { + if (RemoveNMRNewbie() && !fval(f, FFL_NOIDLEOUT)) { + if (f->age>=0 && f->age <= turn) ++age[f->age]; + if (f->age == 2 || f->age == 3) { + if (f->lastorders == turn - 2) { + destroyfaction(f); + ++dropouts[f->age-2]; + continue; + } + } + } + } + + if (verbosity>=1) puts(" - beseitige leere Einheiten und leere Parteien..."); + remove_empty_units(); +} +/* ------------------------------------------------------------- */ + +/* HELFE partei [] [NICHT] */ + +static int +ally_cmd(unit * u, struct order * ord) +{ + ally * sf, ** sfp; + faction *f; + int keyword, not_kw; + const char *s; + + init_tokens(ord); + skip_token(); + f = getfaction(); + + if (f==NULL || is_monsters(f)) { + cmistake(u, ord, 66, MSG_EVENT); + return 0; + } + if (f == u->faction) return 0; + + s = getstrtoken(); + + if (!s[0]) + keyword = P_ANY; + else + keyword = findparam(s, u->faction->locale); + + sfp = &u->faction->allies; + if (fval(u, UFL_GROUP)) { + attrib * a = a_find(u->attribs, &at_group); + if (a) sfp = &((group*)a->data.v)->allies; + } + for (sf=*sfp; sf; sf = sf->next) + if (sf->faction == f) + break; /* Gleich die passende raussuchen, wenn vorhanden */ + + not_kw = getparam(u->faction->locale); /* HELFE partei [modus] NICHT */ + + if (!sf) { + if (keyword == P_NOT || not_kw == P_NOT) { + /* Wir helfen der Partei gar nicht... */ + return 0; + } else { + sf = calloc(1, sizeof(ally)); + sf->faction = f; + sf->status = 0; + addlist(sfp, sf); + } + } + switch (keyword) { + case P_NOT: + sf->status = 0; + break; + + case NOPARAM: + cmistake(u, ord, 137, MSG_EVENT); + return 0; + + case P_ANY: + if (not_kw == P_NOT) + sf->status = 0; + else + sf->status = HELP_ALL; + break; + + case P_TRAVEL: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_TRAVEL); + else + sf->status = sf->status | HELP_TRAVEL; + break; + + case P_GIVE: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_GIVE); + else + sf->status = sf->status | HELP_GIVE; + break; + + case P_MONEY: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_MONEY); + else + sf->status = sf->status | HELP_MONEY; + break; + + case P_FIGHT: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_FIGHT); + else + sf->status = sf->status | HELP_FIGHT; + break; + + case P_FACTIONSTEALTH: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_FSTEALTH); + else + sf->status = sf->status | HELP_FSTEALTH; + break; + + case P_GUARD: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_GUARD); + else + sf->status = sf->status | HELP_GUARD; + break; + } + + sf->status &= HelpMask(); + + if (sf->status == 0) { /* Alle HELPs geloescht */ + removelist(sfp, sf); + } + return 0; +} + +static struct local_names * pnames; + +static void +init_prefixnames(void) +{ + int i; + for (i=0;localenames[i];++i) { + const struct locale * lang = find_locale(localenames[i]); + boolean exist = false; + struct local_names * in = pnames; + + while (in!=NULL) { + if (in->lang==lang) { + exist = true; + break; + } + in = in->next; + } + if (in==NULL) in = calloc(sizeof(local_names), 1); + in->next = pnames; + in->lang = lang; + + if (!exist) { + int key; + for (key=0;race_prefixes[key];++key) { + variant var; + const char * pname = locale_string(lang, mkname("prefix", race_prefixes[key])); + if (findtoken(&in->names, pname, &var)==E_TOK_NOMATCH || var.i!=key) { + var.i = key; + addtoken(&in->names, pname, var); + addtoken(&in->names, locale_string(lang, mkname("prefix", race_prefixes[key])), var); + } + } + } + pnames = in; + } +} + +static int +prefix_cmd(unit * u, struct order * ord) +{ + attrib **ap; + const char *s; + local_names * in = pnames; + variant var; + const struct locale * lang = u->faction->locale; + + while (in!=NULL) { + if (in->lang==lang) break; + in = in->next; + } + if (in==NULL) { + init_prefixnames(); + for (in=pnames;in->lang!=lang;in=in->next) ; + } + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + if (!*s) { + attrib *a = NULL; + if (fval(u, UFL_GROUP)) { + a = a_find(u->attribs, &at_group); + } + if (a) { + group * g = (group*)a->data.v; + a_removeall(&g->attribs, &at_raceprefix); + } else { + a_removeall(&u->faction->attribs, &at_raceprefix); + } + return 0; + } + + if (findtoken(&in->names, s, &var)==E_TOK_NOMATCH) { + return 0; + } else if (race_prefixes[var.i] == NULL) { + cmistake(u, ord, 299, MSG_EVENT); + } else { + ap = &u->faction->attribs; + if (fval(u, UFL_GROUP)) { + attrib * a = a_find(u->attribs, &at_group); + group * g = (group*)a->data.v; + if (a) ap = &g->attribs; + } + set_prefix(ap, race_prefixes[var.i]); + } + return 0; +} + + +static cmp_building_cb +get_cmp_region_owner(void) +{ + if (rule_region_owners()) { + return &cmp_current_owner; + } else { + return &cmp_wage; + } +} + +static int +display_cmd(unit * u, struct order * ord) +{ + building * b = u->building; + char **s = NULL; + region * r = u->region; + + init_tokens(ord); + skip_token(); + + switch (getparam(u->faction->locale)) { + case P_BUILDING: + case P_GEBAEUDE: + if (!b) { + cmistake(u, ord, 145, MSG_PRODUCE); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 5, MSG_PRODUCE); + break; + } + if (!fval(b->type, BTF_NAMECHANGE) && b->display && b->display[0] != 0) { + cmistake(u, ord, 278, MSG_EVENT); + break; + } + s = &b->display; + break; + + case P_SHIP: + if (!u->ship) { + cmistake(u, ord, 144, MSG_PRODUCE); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 12, MSG_PRODUCE); + break; + } + s = &u->ship->display; + break; + + case P_UNIT: + s = &u->display; + break; + + case P_PRIVAT: + { + const char *d = getstrtoken(); + if(d == NULL || *d == 0) { + usetprivate(u, NULL); + } else { + usetprivate(u, d); + } + } + break; + + case P_REGION: + if (!b) { + cmistake(u, ord, 145, MSG_EVENT); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 148, MSG_EVENT); + break; + } + if (b != largestbuilding(r, get_cmp_region_owner(), false)) { + cmistake(u, ord, 147, MSG_EVENT); + break; + } + s = &r->display; + break; + + default: + cmistake(u, ord, 110, MSG_EVENT); + break; + } + + if (s!=NULL) { + const char * s2 = getstrtoken(); + + free(*s); + *s = strdup(s2); + if (strlen(s2)>=DISPLAYSIZE) { + (*s)[DISPLAYSIZE] = 0; + } + } + + return 0; +} + +static boolean +renamed_building(const building * b) +{ + const struct locale * lang = locales; + for (;lang;lang=nextlocale(lang)) { + const char * bdname = LOC(lang, b->type->_name); + size_t bdlen = strlen(bdname); + if (strlen(b->name)>=bdlen && strncmp(b->name, bdname, bdlen)==0) { + return false; + } + } + return true; +} + +static int +rename_cmd(unit * u, order * ord, char **s, const char * s2) +{ + if (!s2[0]) { + cmistake(u, ord, 84, MSG_EVENT); + return 0; + } + + /* TODO: Validate to make sure people don't have illegal characters in + * names, phishing-style? () come to mind. */ + + free(*s); + *s = strdup(s2); + if (strlen(s2)>=NAMESIZE) { + (*s)[NAMESIZE] = 0; + } + return 0; +} + +static int +rename_building(unit * u, order * ord, building * b, const char * name) { + unit * owner = b?building_owner(b):0; + boolean foreign = owner && owner->faction==u->faction; + + if (!b) { + cmistake(u, ord, u->building?6:145, MSG_EVENT); + return -1; + } + + if (!fval(b->type, BTF_NAMECHANGE) && renamed_building(b)) { + cmistake(u, ord, 278, MSG_EVENT); + return -1; + } + + if (foreign) { + unit *uo; + + if (renamed_building(b)) { + cmistake(u, ord, 246, MSG_EVENT); + return -1; + } + + uo = building_owner(b); + if (uo) { + if (cansee(uo->faction, u->region, u, 0)) { + ADDMSG(&uo->faction->msgs, msg_message("renamed_building_seen", + "building renamer region", b, u, u->region)); + } else { + ADDMSG(&uo->faction->msgs, msg_message("renamed_building_notseen", + "building region", b, u->region)); + } + } + } else { + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 148, MSG_PRODUCE); + return -1; + } + } + + return rename_cmd(u, ord, &b->name, getstrtoken()); +} + +static int +name_cmd(unit * u, struct order * ord) +{ + building * b = u->building; + region * r = u->region; + char **s = NULL; + param_t p; + boolean foreign = false; + + init_tokens(ord); + skip_token(); + p = getparam(u->faction->locale); + + if (p == P_FOREIGN) { + foreign = true; + p = getparam(u->faction->locale); + } + + switch (p) { + case P_ALLIANCE: + if (foreign==false && f_get_alliance(u->faction)) { + alliance * al = u->faction->alliance; + faction * lead = alliance_get_leader(al); + if (lead==u->faction) { + s = &al->name; + } + } + break; + case P_BUILDING: + case P_GEBAEUDE: + if (foreign) { + b = getbuilding(u->region); + } + + return rename_building(u, ord, b, getstrtoken()); + + case P_FACTION: + if (foreign == true) { + faction *f; + + f = getfaction(); + if (!f) { + cmistake(u, ord, 66, MSG_EVENT); + break; + } + if (f->age < 10) { + cmistake(u, ord, 248, MSG_EVENT); + break; + } else { + const struct locale * lang = locales; + for (;lang;lang=nextlocale(lang)) { + const char * fdname = LOC(lang, "factiondefault"); + size_t fdlen = strlen(fdname); + if (strlen(f->name)>=fdlen && strncmp(f->name, fdname, fdlen)==0) { + break; + } + } + if (lang==NULL) { + cmistake(u, ord, 247, MSG_EVENT); + break; + } + } + if (cansee(f, r, u, 0)) { + ADDMSG(&f->msgs, msg_message("renamed_faction_seen", "unit region", u, r)); + } else { + ADDMSG(&f->msgs, msg_message("renamed_faction_notseen", "", r)); + } + s = &f->name; + } else { + s = &u->faction->name; + } + break; + + case P_SHIP: + if (foreign == true) { + ship *sh = getship(r); + unit *uo; + + if (!sh) { + cmistake(u, ord, 20, MSG_EVENT); + break; + } else { + const struct locale * lang = locales; + for (;lang;lang=nextlocale(lang)) { + const char * sdname = LOC(lang, sh->type->name[0]); + size_t sdlen = strlen(sdname); + if (strlen(sh->name)>=sdlen && strncmp(sh->name, sdname, sdlen)==0) { + break; + } + + sdname = LOC(lang, parameters[P_SHIP]); + sdlen = strlen(sdname); + if (strlen(sh->name)>=sdlen && strncmp(sh->name, sdname, sdlen)==0) { + break; + } + + } + if (lang==NULL) { + cmistake(u, ord, 245, MSG_EVENT); + break; + } + } + uo = shipowner(sh); + if (uo) { + if (cansee(uo->faction, r, u, 0)) { + ADDMSG(&uo->faction->msgs, msg_message("renamed_ship_seen", + "ship renamer region", sh, u, r)); + } else { + ADDMSG(&uo->faction->msgs, msg_message("renamed_ship_notseen", + "ship region", sh, r)); + } + } + s = &sh->name; + } else { + if (!u->ship) { + cmistake(u, ord, 144, MSG_PRODUCE); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 12, MSG_PRODUCE); + break; + } + s = &u->ship->name; + } + break; + + case P_UNIT: + if (foreign == true) { + unit *u2 = getunit(r, u->faction); + + if (!u2 || !cansee(u->faction, r, u2, 0)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + break; + } else { + const char * udefault = LOC(u2->faction->locale, "unitdefault"); + size_t udlen = strlen(udefault); + size_t unlen = strlen(u2->name); + if (unlen>=udlen && strncmp(u2->name, udefault, udlen)!=0) { + cmistake(u2, ord, 244, MSG_EVENT); + break; + } + } + if (cansee(u2->faction, r, u, 0)) { + ADDMSG(&u2->faction->msgs, msg_message("renamed_seen", + "renamer renamed region", u, u2, r)); + } else { + ADDMSG(&u2->faction->msgs, msg_message("renamed_notseen", + "renamed region", u2, r)); + } + s = &u2->name; + } else { + s = &u->name; + } + break; + + case P_REGION: + if (!b) { + cmistake(u, ord, 145, MSG_EVENT); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 148, MSG_EVENT); + break; + } + + if (b != largestbuilding(r, get_cmp_region_owner(), false)) { + cmistake(u, ord, 147, MSG_EVENT); + break; + } + s = &r->land->name; + break; + + case P_GROUP: + { + attrib * a = NULL; + if (fval(u, UFL_GROUP)) a = a_find(u->attribs, &at_group); + if (a) { + group * g = (group*)a->data.v; + s = &g->name; + break; + } else { + cmistake(u, ord, 109, MSG_EVENT); + break; + } + } + break; + default: + cmistake(u, ord, 109, MSG_EVENT); + break; + } + + if (s!=NULL) { + return rename_cmd(u, ord, s, getstrtoken()); + } + + return 0; +} +/* ------------------------------------------------------------- */ + +void +deliverMail(faction * f, region * r, unit * u, const char *s, unit * receiver) +{ + if (!cansee(f, r, u, 0)) { + u = NULL; + } + if (!receiver) { /* BOTSCHAFT an PARTEI */ + ADDMSG(&f->msgs, msg_message("regionmessage", "region sender string", r, u, s)); + } else { /* BOTSCHAFT an EINHEIT */ + ADDMSG(&f->msgs, msg_message("unitmessage", "region unit sender string", r, receiver, u, s)); + } +} + +static void +mailunit(region * r, unit * u, int n, struct order * ord, const char * s) +{ + unit * u2 = findunitr(r,n); + + if (u2 && cansee(u->faction, r, u2, 0)) { + deliverMail(u2->faction, r, u, s, u2); + /* now done in prepare_mail_cmd */ + } + else { + /* Immer eine Meldung - sonst könnte man so getarnte EHs enttarnen: + * keine Meldung -> EH hier. */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } +} + +static void +mailfaction(unit * u, int n, struct order * ord, const char * s) +{ + faction *f; + + f = findfaction(n); + if (f && n>0) + deliverMail(f, u->region, u, s, NULL); + else + cmistake(u, ord, 66, MSG_MESSAGE); +} + +static int +mail_cmd(unit * u, struct order * ord) +{ + region * r = u->region; + unit *u2; + const char *s; + int n, cont; + + init_tokens(ord); + skip_token(); /* skip the keyword */ + s = getstrtoken(); + + /* Falls kein Parameter, ist das eine Einheitsnummer; + * das Füllwort "AN" muß wegfallen, da gültige Nummer! */ + + do { + cont = 0; + switch (findparam(s, u->faction->locale)) { + case P_REGION: + /* können alle Einheiten in der Region sehen */ + s = getstrtoken(); + if (!s[0]) { + cmistake(u, ord, 30, MSG_MESSAGE); + break; + } else { + ADDMSG(&r->msgs, msg_message("mail_result", "unit message", u, s)); + return 0; + } + + case P_FACTION: + { + boolean see = false; + + n = getfactionid(); + + for(u2=r->units; u2; u2=u2->next) { + if(u2->faction->no == n && seefaction(u->faction, r, u2, 0)) { + see = true; + break; + } + } + + if(see == false) { + cmistake(u, ord, 66, MSG_MESSAGE); + break; + } + + s = getstrtoken(); + if (!s[0]) { + cmistake(u, ord, 30, MSG_MESSAGE); + break; + } + mailfaction(u, n, ord, s); + return 0; + } + + case P_UNIT: + { + boolean see = false; + n = getid(); + + for (u2=r->units; u2; u2=u2->next) { + if (u2->no == n && cansee(u->faction, r, u2, 0)) { + see = true; + break; + } + } + + if (see == false) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return 0; + } + + s = getstrtoken(); + if (!s[0]) { + cmistake(u, ord, 30, MSG_MESSAGE); + break; + } else { + attrib * a = a_find(u2->attribs, &at_eventhandler); + if (a!=NULL) { + event_arg args[3]; + args[0].data.v = (void*)s; + args[0].type = "string"; + args[1].data.v = (void*)u; + args[1].type = "unit"; + args[2].type = NULL; + handle_event(a, "message", args); + } + + mailunit(r, u, n, ord, s); + } + return 0; + } + + case P_BUILDING: + case P_GEBAEUDE: + { + building *b = getbuilding(r); + + if(!b) { + cmistake(u, ord, 6, MSG_MESSAGE); + break; + } + + s = getstrtoken(); + + if (!s[0]) { + cmistake(u, ord, 30, MSG_MESSAGE); + break; + } + + for (u2 = r->units; u2; u2 = u2->next) freset(u2->faction, FFL_SELECT); + + for (u2=r->units; u2; u2=u2->next) { + if(u2->building == b && !fval(u2->faction, FFL_SELECT) + && cansee(u->faction, r, u2, 0)) { + mailunit(r, u, u2->no, ord, s); + fset(u2->faction, FFL_SELECT); + } + } + return 0; + } + + case P_SHIP: + { + ship *sh = getship(r); + + if(!sh) { + cmistake(u, ord, 20, MSG_MESSAGE); + break; + } + + s = getstrtoken(); + + if (!s[0]) { + cmistake(u, ord, 30, MSG_MESSAGE); + break; + } + + for (u2 = r->units; u2; u2 = u2->next) freset(u2->faction, FFL_SELECT); + + for(u2=r->units; u2; u2=u2->next) { + if(u2->ship == sh && !fval(u2->faction, FFL_SELECT) && cansee(u->faction, r, u2, 0)) { + mailunit(r, u, u2->no, ord, s); + fset(u2->faction, FFL_SELECT); + } + } + return 0; + } + + default: + /* possibly filler token? */ + s = getstrtoken(); + if (s && *s) cont = 1; + break; + } + } while (cont); + cmistake(u, ord, 149, MSG_MESSAGE); + return 0; +} +/* ------------------------------------------------------------- */ + +static int +banner_cmd(unit * u, struct order * ord) +{ + init_tokens(ord); + skip_token(); + + free(u->faction->banner); + u->faction->banner = strdup(getstrtoken()); + add_message(&u->faction->msgs, msg_message("changebanner", "value", + u->faction->banner)); + + return 0; +} + +static int +email_cmd(unit * u, struct order * ord) +{ + const char * s; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + if (!s[0]) { + cmistake(u, ord, 85, MSG_EVENT); + } else { + faction * f = u->faction; + if (set_email(&f->email, (const char *)s)!=0) { + log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), s)); + ADDMSG(&f->msgs, msg_message("changemail_invalid", "value", s)); + } else { + ADDMSG(&f->msgs, msg_message("changemail", "value", f->email)); + } + } + return 0; +} + +static int +password_cmd(unit * u, struct order * ord) +{ + char pwbuf[32]; + int i; + const char * s; + boolean pwok = true; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + if (!s || !*s) { + for(i=0; i<6; i++) pwbuf[i] = (char)(97 + rng_int() % 26); + pwbuf[6] = 0; + } else { + char *c; + + strlcpy(pwbuf, (const char *)s, 31); + pwbuf[31] = 0; + c = pwbuf; + while (*c && pwok) { + if (!isalnum(*(unsigned char*)c)) pwok = false; + c++; + } + } + free(u->faction->passw); + if (pwok == false) { + cmistake(u, ord, 283, MSG_EVENT); + u->faction->passw = strdup(itoa36(rng_int())); + } else { + u->faction->passw = strdup(pwbuf); + } + fset(u->faction, FFL_OVERRIDE); + ADDMSG(&u->faction->msgs, msg_message("changepasswd", + "value", u->faction->passw)); + return 0; +} + +static int +send_cmd(unit * u, struct order * ord) +{ + const char * s; + int option; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + option = findoption(s, u->faction->locale); + + if (option == -1) { + cmistake(u, ord, 135, MSG_EVENT); + } else { + if (getparam(u->faction->locale) == P_NOT) { + if (option == O_COMPRESS || option == O_BZIP2) { + cmistake(u, ord, 305, MSG_EVENT); + } else { + u->faction->options = u->faction->options & ~(1<faction->options = u->faction->options | (1<faction->options &= ~(1<faction->options &= ~(1<items, itype); + if (i==0) { + if (u->region->land!=NULL) { + i = i_get(u->region->land->items, itype); + } + if (i==0) { + i = i_get(u->faction->items, itype); + if (i==0) return false; + } + } + } + + name = resourcename(itype->rtype, 0); + key = mkname("iteminfo", name); + info = locale_getstring(f->locale, key); + + if (info==NULL) { + info = locale_string(f->locale, mkname("iteminfo", "no_info")); + } + ADDMSG(&f->msgs, msg_message("displayitem", "weight item description", + itype->weight, itype->rtype, info)); + + return true; +} + +static boolean +display_potion(faction *f, unit *u, const potion_type * ptype) +{ + attrib *a; + + if (ptype==NULL) return false; + else { + int i = i_get(u->items, ptype->itype); + if (i==0 && 2*ptype->level > effskill(u,SK_ALCHEMY)) { + return false; + } + } + + a = a_find(f->attribs, &at_showitem); + while (a && a->data.v != ptype) a=a->next; + if (!a) { + a = a_add(&f->attribs, a_new(&at_showitem)); + a->data.v = (void*) ptype->itype; + } + + return true; +} + +static boolean +display_race(faction *f, unit *u, const race * rc) +{ + const char *name, *key; + const char *info; + int a, at_count; + char buf[2048], * bufp = buf; + size_t size = sizeof(buf) - 1; + int bytes; + + if (u && u->race != rc) return false; + name = rc_name(rc, 0); + + bytes = slprintf(bufp, size, "%s: ", LOC(f->locale, name)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + key = mkname("raceinfo", rc->_name[0]); + info = locale_getstring(f->locale, key); + if (info==NULL) { + info = locale_string(f->locale, mkname("raceinfo", "no_info")); + } + + bytes = (int)strlcpy(bufp, info, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + /* hp_p : Trefferpunkte */ + bytes = snprintf(bufp, size, " %d %s", rc->hitpoints, LOC(f->locale, "stat_hitpoints")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + /* b_attacke : Angriff */ + bytes = snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_attack"), (rc->at_default+rc->at_bonus)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + /* b_defense : Verteidigung */ + bytes = snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_defense"), (rc->df_default+rc->df_bonus)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + /* b_armor : Rüstung */ + if (rc->armor > 0) { + bytes = snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_armor"), rc->armor); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + if (size>1) { + *bufp++ ='.'; + --size; + } else WARN_STATIC_BUFFER(); + + /* b_damage : Schaden */ + at_count=0; + for (a = 0; a < 6; a++) { + if (rc->attack[a].type != AT_NONE){ + at_count++; + } + } + if (rc->battle_flags & BF_EQUIPMENT) { + bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_equipment")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (rc->battle_flags & BF_RES_PIERCE) { + bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_pierce")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (rc->battle_flags & BF_RES_CUT) { + bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_cut")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (rc->battle_flags & BF_RES_BASH) { + bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_bash")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + bytes = snprintf(bufp, size, " %d %s", at_count, LOC(f->locale, (at_count==1)?"stat_attack":"stat_attacks")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + for (a = 0; a < 6; a++) { + if (rc->attack[a].type != AT_NONE){ + if (a!=0) bytes = (int)strlcpy(bufp, ", ", size); + else bytes = (int)strlcpy(bufp, ": ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + switch(rc->attack[a].type) { + case AT_STANDARD: + bytes = snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_standard"), rc->def_damage); + break; + case AT_NATURAL: + bytes = snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_natural"), rc->attack[a].data.dice); + break; + case AT_SPELL: + case AT_COMBATSPELL: + case AT_DRAIN_ST: + case AT_DAZZLE: + bytes = snprintf(bufp, size, "%s", LOC(f->locale, "attack_magical")); + break; + case AT_STRUCTURAL: + bytes = snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_structural"), rc->attack[a].data.dice); + break; + default: + bytes = 0; + } + + if (bytes && wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + + if (size>1) { + *bufp++ = '.'; + --size; + } else WARN_STATIC_BUFFER(); + + *bufp = 0; + addmessage(0, f, buf, MSG_EVENT, ML_IMPORTANT); + + return true; +} + +static void +reshow(unit * u, struct order * ord, const char * s, param_t p) +{ + int skill, c; + const potion_type * ptype; + const item_type * itype; + const spell * sp; + const race * rc; + + switch (p) { + case P_ZAUBER: + a_removeall(&u->faction->attribs, &at_seenspell); + break; + case P_POTIONS: + skill = effskill(u, SK_ALCHEMY); + c = 0; + for (ptype = potiontypes; ptype!=NULL; ptype=ptype->next) { + if (ptype->level * 2 <= skill) { + c += display_potion(u->faction, u, ptype); + } + } + if (c == 0) cmistake(u, ord, 285, MSG_EVENT); + break; + case NOPARAM: + /* check if it's an item */ + itype = finditemtype(s, u->faction->locale); + if (itype!=NULL) { + ptype = resource2potion(item2resource(itype)); + if (ptype!=NULL) { + if (display_potion(u->faction, u, ptype)) break; + } else { + if (display_item(u->faction, u, itype)) break; + } + } + /* try for a spell */ + sp = get_spellfromtoken(u, s, u->faction->locale); + if (sp!=NULL && u_hasspell(u, sp)) { + attrib *a = a_find(u->faction->attribs, &at_seenspell); + while (a!=NULL && a->type==&at_seenspell && a->data.v!=sp) a = a->next; + if (a!=NULL) a_remove(&u->faction->attribs, a); + break; + } + /* last, check if it's a race. */ + rc = findrace(s, u->faction->locale); + if (rc != NULL) { + if (display_race(u->faction, u, rc)) break; + } + cmistake(u, ord, 21, MSG_EVENT); + break; + default: + cmistake(u, ord, 222, MSG_EVENT); + break; + } +} + +static int +promotion_cmd(unit * u, struct order * ord) +{ + int money, people; + + if (fval(u, UFL_HERO)) { + /* TODO: message "is already a hero" */ + return 0; + } + + if (maxheroes(u->faction) < countheroes(u->faction)+u->number) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_maxed", "max count", + maxheroes(u->faction), countheroes(u->faction))); + return 0; + } + if (!valid_race(u->faction, u->race)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_race", "race", + u->race)); + return 0; + } + people = count_all(u->faction) * u->number; + money = get_pooled(u, i_silver->rtype, GET_ALL, people); + + if (people>money) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_cost", "cost have", + people, money)); + return 0; + } + use_pooled(u, i_silver->rtype, GET_ALL, people); + fset(u, UFL_HERO); + ADDMSG(&u->faction->msgs, msg_message("hero_promotion", "unit cost", + u, people)); + return 0; +} + +static int +group_cmd(unit * u, struct order * ord) +{ + const char * s; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + join_group(u, s); + return 0; +} + +static int +origin_cmd(unit * u, struct order * ord) +{ + short px, py; + + init_tokens(ord); + skip_token(); + + px = (short)getint(); + py = (short)getint(); + + set_ursprung(u->faction, getplaneid(u->region), px, py); + return 0; +} + +static int +guard_off_cmd(unit * u, struct order * ord) +{ + assert(get_keyword(ord)==K_GUARD); + init_tokens(ord); + skip_token(); + + if (getparam(u->faction->locale) == P_NOT) { + setguard(u, GUARD_NONE); + } + return 0; +} + +static int +reshow_cmd(unit * u, struct order * ord) +{ + const char * s; + param_t p = NOPARAM; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + if (findparam(s, u->faction->locale) == P_ANY) { + p = getparam(u->faction->locale); + s = NULL; + } + + reshow(u, ord, s, p); + return 0; +} + +static int +status_cmd(unit * u, struct order * ord) +{ + const char * param; + + init_tokens(ord); + skip_token(); + + param = getstrtoken(); + switch (findparam(param, u->faction->locale)) { + case P_NOT: + setstatus(u, ST_AVOID); + break; + case P_BEHIND: + setstatus(u, ST_BEHIND); + break; + case P_FLEE: + setstatus(u, ST_FLEE); + break; + case P_CHICKEN: + setstatus(u, ST_CHICKEN); + break; + case P_AGGRO: + setstatus(u, ST_AGGRO); + break; + case P_VORNE: + setstatus(u, ST_FIGHT); + break; + case P_HELP: + if (getparam(u->faction->locale) == P_NOT) { + fset(u, UFL_NOAID); + } else { + freset(u, UFL_NOAID); + } + break; + default: + if (param[0]) { + add_message(&u->faction->msgs, + msg_feedback(u, ord, "unknown_status", "")); + } else { + setstatus(u, ST_FIGHT); + } + } + return 0; +} + +static int +combatspell_cmd(unit * u, struct order * ord) +{ + const char * s; + int level = 0; + spell * spell; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + /* KAMPFZAUBER [NICHT] löscht alle gesetzten Kampfzauber */ + if (!s || *s == 0 || findparam(s, u->faction->locale) == P_NOT) { + unset_combatspell(u, 0); + return 0; + } + + /* Optional: STUFE n */ + if (findparam(s, u->faction->locale) == P_LEVEL) { + /* Merken, setzen kommt erst später */ + level = getint(); + level = MAX(0, level); + s = getstrtoken(); + } + + spell = get_spellfromtoken(u, s, u->faction->locale); + + if(!spell){ + cmistake(u, ord, 173, MSG_MAGIC); + return 0; + } + + s = getstrtoken(); + + if (findparam(s, u->faction->locale) == P_NOT) { + /* KAMPFZAUBER "" NICHT löscht diesen speziellen + * Kampfzauber */ + unset_combatspell(u, spell); + return 0; + } else { + /* KAMPFZAUBER "" setzt diesen Kampfzauber */ + set_combatspell(u, spell, ord, level); + } + + return 0; +} + +/* ------------------------------------------------------------- */ +/* Beachten: einige Monster sollen auch unbewaffent die Region bewachen + * können */ + +enum { E_GUARD_OK, E_GUARD_UNARMED, E_GUARD_NEWBIE, E_GUARD_FLEEING }; + +static int +can_start_guarding(const unit * u) +{ + if (u->status>=ST_FLEE) return E_GUARD_FLEEING; + if (fval(u->race, RCF_UNARMEDGUARD)) return E_GUARD_OK; + if (!armedmen(u, true)) return E_GUARD_UNARMED; + if (IsImmune(u->faction)) return E_GUARD_NEWBIE; + return E_GUARD_OK; +} + +void +update_guards(void) +{ + const region *r; + + for (r = regions; r; r = r->next) { + unit *u; + for (u = r->units; u; u = u->next) { + if (fval(u, UFL_GUARD)) { + if (can_start_guarding(u)!=E_GUARD_OK) { + setguard(u, GUARD_NONE); + } else { + attrib * a = a_find(u->attribs, &at_guard); + if (a && a->data.i==(int)guard_flags(u)) { + /* this is really rather not necessary */ + a_remove(&u->attribs, a); + } + } + } + } + } +} + +static int +guard_on_cmd(unit * u, struct order * ord) +{ + assert(get_keyword(ord)==K_GUARD); + + init_tokens(ord); + skip_token(); + + /* GUARD NOT is handled in goard_off_cmd earlier in the turn */ + if (getparam(u->faction->locale) == P_NOT) return 0; + + if (fval(u->region->terrain, SEA_REGION)) { + cmistake(u, ord, 2, MSG_EVENT); + } else { + if (fval(u, UFL_MOVED)) { + cmistake(u, ord, 187, MSG_EVENT); + } else if (fval(u->race, RCF_ILLUSIONARY) || u->race == new_race[RC_SPELL]) { + cmistake(u, ord, 95, MSG_EVENT); + } else { + /* Monster der Monsterpartei dürfen immer bewachen */ + if (is_monsters(u->faction)) { + guard(u, GUARD_ALL); + } else { + int err = can_start_guarding(u); + if (err==E_GUARD_OK) { + guard(u, GUARD_ALL); + } else if (err==E_GUARD_UNARMED) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_unarmed", "")); + } else if (err==E_GUARD_FLEEING) { + cmistake(u, ord, 320, MSG_EVENT); + } else if (err==E_GUARD_NEWBIE) { + cmistake(u, ord, 304, MSG_EVENT); + } + } + } + } + return 0; +} + +static void +sinkships(region * r) +{ + ship **shp = &r->ships; + + while (*shp) { + ship * sh = *shp; + if (fval(r->terrain, SEA_REGION) && (!enoughsailors(sh, r) || get_captain(sh)==NULL)) { + /* Schiff nicht seetüchtig */ + damage_ship(sh, 0.30); + } + if (shipowner(sh)==NULL) { + damage_ship(sh, 0.05); + } + if (sh->damage >= sh->size * DAMAGE_SCALE) { + remove_ship(shp, sh); + } + if (*shp==sh) shp=&sh->next; + } +} + +/* The following functions do not really belong here: */ +#include +#include + +static attrib_type at_number = { + "faction_renum", + NULL, NULL, NULL, NULL, NULL, + ATF_UNIQUE +}; + +static void +renumber_factions(void) + /* gibt parteien neue nummern */ +{ + struct renum { + struct renum * next; + int want; + faction * faction; + attrib * attrib; + } * renum = NULL, * rp; + faction * f; + for (f=factions;f;f=f->next) { + attrib * a = a_find(f->attribs, &at_number); + int want; + struct renum ** rn; + faction * old; + + if (!a) continue; + want = a->data.i; + if (fval(f, FFL_NEWID)) { + ADDMSG(&f->msgs, msg_message("renumber_twice", "id", want)); + continue; + } + old = findfaction(want); + if (old) { + a_remove(&f->attribs, a); + ADDMSG(&f->msgs, msg_message("renumber_inuse", "id", want)); + continue; + } + if (!faction_id_is_unused(want)) { + a_remove(&f->attribs, a); + ADDMSG(&f->msgs, msg_message("renumber_inuse", "id", want)); + continue; + } + for (rn=&renum; *rn; rn=&(*rn)->next) { + if ((*rn)->want>=want) break; + } + if (*rn && (*rn)->want==want) { + ADDMSG(&f->msgs, msg_message("renumber_inuse", "id", want)); + } else { + struct renum * r = calloc(sizeof(struct renum), 1); + r->next = *rn; + r->attrib = a; + r->faction = f; + r->want = want; + *rn = r; + } + } + for (rp=renum;rp;rp=rp->next) { + f = rp->faction; + a_remove(&f->attribs, rp->attrib); + renumber_faction(f, rp->want); + } + while (renum) { + rp = renum->next; + free(renum); + renum = rp; + } +} + +static void +reorder(void) +{ + region * r; + for (r=regions;r;r=r->next) { + unit ** up=&r->units; + boolean sorted=false; + while (*up) { + unit * u = *up; + if (!fval(u, UFL_MARK)) { + struct order * ord; + for (ord = u->orders;ord;ord=ord->next) { + if (get_keyword(ord)==K_SORT) { + const char * s; + param_t p; + int id; + unit *v; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + p = findparam(s, u->faction->locale); + id = getid(); + v = findunit(id); + + if (v==NULL || v->faction!=u->faction || v->region!=r) { + cmistake(u, ord, 258, MSG_EVENT); + } else if (v->building != u->building || v->ship!=u->ship) { + cmistake(u, ord, 259, MSG_EVENT); + } else if (fval(u, UFL_OWNER)) { + cmistake(u, ord, 260, MSG_EVENT); + } else if (v == u) { + cmistake(u, ord, 10, MSG_EVENT); + } else { + switch(p) { + case P_AFTER: + *up = u->next; + u->next = v->next; + v->next = u; + break; + case P_BEFORE: + if (fval(v, UFL_OWNER)) { + cmistake(v, ord, 261, MSG_EVENT); + } else { + unit ** vp=&r->units; + while (*vp!=v) vp=&(*vp)->next; + *vp = u; + *up = u->next; + u->next = v; + } + break; + } + fset(u, UFL_MARK); + sorted = true; + } + break; + } + } + } + if (u==*up) up=&u->next; + } + if (sorted) { + unit * u; + for (u=r->units;u;u=u->next) freset(u, UFL_MARK); + } + } +} + +#if 0 +/* Aus Gebäude weisen, VERBANNE */ +static void +evict(void) +{ + region *r; + strlist *S; + unit * u; + + for (r=regions;r;r=r->next) { + for (u=r->units;u;u=u->next) { + for (S = u->orders; S; S = S->next) if (get_keyword(ord)==K_EVICT) { + int id; + unit *u2; + /* Nur der Kapitän bzw Burgherr kann jemanden rausschmeißen */ + if(!fval(u, UFL_OWNER)) { + /* Die Einheit ist nicht der Eigentümer */ + cmistake(u,ord,49,MSG_EVENT); + continue; + } + init_tokens(ord); + skip_token(); + id = getid(); + u2 = findunit(id); + + if (u2==NULL) { + /* Einheit nicht gefunden */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + continue; + } + + if (u->building){ + /* in der selben Burg? */ + if (u->building != u2->building){ + /* nicht in Burg */ + cmistake(u,ord,33,MSG_EVENT); + continue; + } + leave_building(u2); + /* meldung an beide */ + } + + if (u->ship){ + if (u->ship != u2->ship){ + /* nicht an Bord */ + cmistake(u, ord, 32, MSG_EVENT); + continue; + } + leave_ship(u2); + /* meldung an beide */ + } + } + } + } +} +#endif + + +static int +renumber_cmd(unit * u, order * ord) +{ + const char * s; + int i; + faction * f = u->faction; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + switch(findparam(s, u->faction->locale)) { + + case P_FACTION: + s = getstrtoken(); + if (s && *s) { + int id = atoi36((const char *)s); + attrib * a = a_find(f->attribs, &at_number); + if (!a) a = a_add(&f->attribs, a_new(&at_number)); + a->data.i = id; + } + break; + + case P_UNIT: + s = getstrtoken(); + if (s == NULL || *s == 0) { + i = newunitid(); + } else { + i = atoi36((const char *)s); + if (i<=0 || i>MAX_UNIT_NR) { + cmistake(u, ord, 114, MSG_EVENT); + break; + } + + if (forbiddenid(i)) { + cmistake(u, ord, 116, MSG_EVENT); + break; + } + + if (findunitg(i, u->region)) { + cmistake(u, ord, 115, MSG_EVENT); + break; + } + } + uunhash(u); + if (!ualias(u)) { + attrib *a = a_add(&u->attribs, a_new(&at_alias)); + a->data.i = -u->no; + } + u->no = i; + uhash(u); + break; + + case P_SHIP: + if (!u->ship) { + cmistake(u, ord, 144, MSG_EVENT); + break; + } + if (u->ship->coast != NODIRECTION) { + cmistake(u, ord, 116, MSG_EVENT); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 146, MSG_EVENT); + break; + } + s = getstrtoken(); + if (s == NULL || *s == 0) { + i = newcontainerid(); + } else { + i = atoi36((const char *)s); + if (i<=0 || i>MAX_CONTAINER_NR) { + cmistake(u,ord,114,MSG_EVENT); + break; + } + if (findship(i) || findbuilding(i)) { + cmistake(u, ord, 115, MSG_EVENT); + break; + } + } + sunhash(u->ship); + u->ship->no = i; + shash(u->ship); + break; + case P_BUILDING: + case P_GEBAEUDE: + if (!u->building) { + cmistake(u,ord,145,MSG_EVENT); + break; + } + if(!fval(u, UFL_OWNER)) { + cmistake(u,ord,148,MSG_EVENT); + break; + } + s = getstrtoken(); + if(*s == 0) { + i = newcontainerid(); + } else { + i = atoi36((const char *)s); + if (i<=0 || i>MAX_CONTAINER_NR) { + cmistake(u,ord,114,MSG_EVENT); + break; + } + if(findship(i) || findbuilding(i)) { + cmistake(u,ord,115,MSG_EVENT); + break; + } + } + bunhash(u->building); + u->building->no = i; + bhash(u->building); + break; + + default: + cmistake(u, ord, 239, MSG_EVENT); + } + return 0; +} + +static building * +age_building(building * b) +{ + static boolean init = false; + static const building_type * bt_blessed; + static const curse_type * ct_astralblock; + if (!init) { + init = true; + bt_blessed = bt_find("blessedstonecircle"); + ct_astralblock = ct_find("astralblock"); + } + + /* blesses stone circles create an astral protection in the astral region + * above the shield, which prevents chaos suction and other spells. + * The shield is created when a magician enters the blessed stone circle, + * and lasts for as long as his skill level / 2 is, at no mana cost. + * + * TODO: this would be nicer in a btype->age function, but we don't have it. + */ + if (ct_astralblock && bt_blessed && b->type==bt_blessed) { + region * r = b->region; + region * rt = r_standard_to_astral(r); + unit * u, * mage = NULL; + + if (fval(rt->terrain, FORBIDDEN_REGION)) rt = NULL; + /* step 1: give unicorns to people in the building, + * find out if there's a magician in there. */ + for (u=r->units;u;u=u->next) { + if (b==u->building && inside_building(u)) { + if (!(u->race->ec_flags & GIVEITEM)==0) { + int n, unicorns = 0; + for (n=0; n!=u->number; ++n) { + if (chance(0.02)) { + i_change(&u->items, olditemtype[I_ELVENHORSE], 1); + ++unicorns; + } + if (unicorns) { + ADDMSG(&u->faction->msgs, msg_message("scunicorn", + "unit amount rtype", u, unicorns, + olditemtype[I_ELVENHORSE]->rtype)); + } + } + } + if (mage==NULL && is_mage(u)) { + mage = u; + } + } + } + + /* if there's a magician, and a connection to astral space, create the + * curse. */ + if (rt!=NULL && mage!=NULL) { + curse * c = get_curse(rt->attribs, ct_astralblock); + if (c==NULL) { + if (mage!=NULL) { + int sk = effskill(mage, SK_MAGIC); + double effect; + effect = 100; + /* the mage reactivates the circle */ + c = create_curse(mage, &rt->attribs, ct_astralblock, + (float)MAX(1, sk), MAX(1, sk/2), effect, 0); + ADDMSG(&r->msgs, msg_message("astralshield_activate", + "region unit", r, mage)); + } + } else if (mage!=NULL) { + int sk = effskill(mage, SK_MAGIC); + c->duration = MAX(c->duration, sk/2); + c->vigour = MAX(c->vigour, sk); + } + } + } + + a_age(&b->attribs); + handle_event(b->attribs, "timer", b); + + if (b->type->age) { + b->type->age(b); + } + + return b; +} + +static double rc_popularity(const struct race * rc) +{ + int pop = get_param_int(rc->parameters, "morale", MORALE_AVERAGE); + return 1.0/(pop-MORALE_COOLDOWN); /* 10 turns average */ +} + +static void age_region(region * r) +{ + a_age(&r->attribs); + handle_event(r->attribs, "timer", r); + + if (!r->land) return; + + if (r->land->ownership && r->land->ownership->owner) { + int stability = turn - r->land->ownership->morale_turn; + int maxmorale = MORALE_DEFAULT; + building * b = largestbuilding(r, &cmp_taxes, false); + if (b) { + int bsize = buildingeffsize(b, false); + maxmorale = (int)(0.5 + b->type->taxes(b, bsize+1) / MORALE_TAX_FACTOR); + } + if (r->land->moraleMORALE_COOLDOWN && r->land->ownership->owner && r->land->moraleland->ownership->owner->race); + if (is_cursed(r->attribs, C_GENEROUS, 0)) { + ch *= 1.2; /* 20% improvement */ + } + if (stability>=MORALE_AVERAGE*2 || chance(ch)) { + region_set_morale(r, r->land->morale+1, turn); + } + } + } else if (r->land->morale>maxmorale) { + region_set_morale(r, r->land->morale-1, turn); + } + } else if (r->land->morale>MORALE_DEFAULT) { + region_set_morale(r, r->land->morale-1, turn); + } +} + +static void +ageing(void) +{ + faction *f; + region *r; + + /* altern spezieller Attribute, die eine Sonderbehandlung brauchen? */ + for(r=regions;r;r=r->next) { + unit *u; + + for (u=r->units;u;u=u->next) { + /* Goliathwasser */ + int i = get_effect(u, oldpotiontype[P_STRONG]); + if (i > 0){ + change_effect(u, oldpotiontype[P_STRONG], -1 * MIN(u->number, i)); + } + /* Berserkerblut*/ + i = get_effect(u, oldpotiontype[P_BERSERK]); + if (i > 0){ + change_effect(u, oldpotiontype[P_BERSERK], -1 * MIN(u->number, i)); + } + + if (is_cursed(u->attribs, C_OLDRACE, 0)){ + curse *c = get_curse(u->attribs, ct_find("oldrace")); + if (c->duration == 1 && !(c_flags(c) & CURSE_NOAGE)) { + u->race = new_race[curse_geteffect_int(c)]; + u->irace = NULL; + } + } + } + } + + /* Borders */ + age_borders(); + + /* Factions */ + for (f=factions;f;f=f->next) { + a_age(&f->attribs); + handle_event(f->attribs, "timer", f); + } + + /* Regionen */ + for (r=regions;r;r=r->next) { + building ** bp; + unit ** up; + ship ** sp; + + age_region(r); + + /* Einheiten */ + for (up=&r->units;*up;) { + unit * u = *up; + a_age(&u->attribs); + if (u==*up) handle_event(u->attribs, "timer", u); + if (u==*up) up = &(*up)->next; + } + + /* Schiffe */ + for (sp=&r->ships;*sp;) { + ship * s = *sp; + a_age(&s->attribs); + if (s==*sp) handle_event(s->attribs, "timer", s); + if (s==*sp) sp = &(*sp)->next; + } + + /* Gebäude */ + for (bp=&r->buildings;*bp;) { + building * b = *bp; + age_building(b); + if (b==*bp) bp = &b->next; + } + + if (rule_region_owners()) { + update_owners(r); + } + } +} + +static int +maxunits(const faction *f) +{ + int flimit = rule_faction_limit(); + int alimit = rule_alliance_limit(); + if (alimit==0) { + return flimit; + } + if (flimit==0) { + return alimit; + } + return MIN(alimit, flimit); +} + +int +checkunitnumber(const faction *f, int add) +{ + int alimit, flimit; + + alimit = rule_alliance_limit(); + if (alimit) { + /* if unitsperalliance is true, maxunits returns the + number of units allowed in an alliance */ + faction *f2; + int unitsinalliance = add; + + for (f2 = factions; f2; f2 = f2->next) { + if (f->alliance == f2->alliance) { + unitsinalliance += f2->no_units; + } + if (unitsinalliance > alimit) { + return 1; + } + } + } + + flimit = rule_faction_limit(); + if (flimit) { + if (f->no_units + add > flimit) { + return 2; + } + } + + return 0; +} + +static void +new_units(void) +{ + region *r; + unit *u, *u2; + + /* neue einheiten werden gemacht und ihre befehle (bis zum "ende" zu + * ihnen rueberkopiert, damit diese einheiten genauso wie die alten + * einheiten verwendet werden koennen. */ + + for (r = regions; r; r = r->next) { + for (u = r->units; u; u = u->next) { + order ** ordp = &u->orders; + + /* this needs to happen very early in the game somewhere. since this is + ** pretty much the first function called per turn, and I am lazy, I + ** decree that it goes here */ + if (u->flags&UFL_GUARD) { + fset(r, RF_GUARDED); + } + + while (*ordp) { + order * makeord = *ordp; + if (get_keyword(makeord) == K_MAKE) { + init_tokens(makeord); + skip_token(); + if (getparam(u->faction->locale) == P_TEMP) { + const char * token; + char * name = NULL; + 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 (get_keyword(ord) == K_END) break; + *ordp = ord->next; + ord->next = NULL; + free_order(ord); + } + continue; + } + alias = getid(); + + token = getstrtoken(); + if (token && token[0]) { + name = strdup(token); + } + u2 = create_unit(r, u->faction, 0, u->faction->race, alias, name, u); + if (name!=NULL) free(name); + 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 (get_keyword(ord) == K_END) break; + *ordp = ord->next; + ord->next = NULL; + *newordersp = ord; + newordersp = &ord->next; + } + } + } + if (*ordp==makeord) ordp=&makeord->next; + } + } + } +} + +static void +setdefaults(unit *u) +{ + order *ord; + boolean trade = false; + boolean hunger = LongHunger(u); + + freset(u, UFL_LONGACTION); + if (hunger) { + /* Hungernde Einheiten führen NUR den default-Befehl aus */ + set_order(&u->thisorder, default_order(u->faction->locale)); + } + /* check all orders for a potential new long order this round: */ + for (ord = u->orders; ord; ord = ord->next) { + if (u->old_orders && is_repeated(ord)) { + /* this new order will replace the old defaults */ + free_orders(&u->old_orders); + if (hunger) break; + } + if (hunger) continue; + + if (is_exclusive(ord)) { + /* Über dieser Zeile nur Befehle, die auch eine idle Faction machen darf */ + if (idle(u->faction)) { + set_order(&u->thisorder, default_order(u->faction->locale)); + } else { + set_order(&u->thisorder, copy_order(ord)); + } + break; + } else { + keyword_t keyword = get_keyword(ord); + switch (keyword) { + /* Wenn gehandelt wird, darf kein langer Befehl ausgeführt + * werden. Da Handel erst nach anderen langen Befehlen kommt, + * muß das vorher abgefangen werden. Wir merken uns also + * hier, ob die Einheit handelt. */ + case NOKEYWORD: + cmistake(u, ord, 22, MSG_EVENT); + break; + case K_BUY: + case K_SELL: + /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht + * werden. */ + trade = true; + break; + + case K_CAST: + /* dient dazu, das neben Zaubern kein weiterer Befehl + * ausgeführt werden kann, Zaubern ist ein kurzer Befehl */ + set_order(&u->thisorder, NULL); + break; + + case K_WEREWOLF: + set_order(&u->thisorder, copy_order(ord)); + break; + + /* Wird je diese Ausschliesslichkeit aufgehoben, muss man aufpassen + * mit der Reihenfolge von Kaufen, Verkaufen etc., damit es Spielern + * nicht moeglich ist, Schulden zu machen. */ + } + } + } + + if (hunger) return; + + /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht + * werden. */ + + if (trade == true) { + /* fset(u, UFL_LONGACTION|UFL_NOTMOVING); */ + set_order(&u->thisorder, NULL); + } +} + +static int +use_item(unit * u, const item_type * itype, int amount, struct order * ord) +{ + int i; + int target = read_unitid(u->faction, u->region); + + i = get_pooled(u, itype->rtype, GET_DEFAULT, amount); + + if (amount>i) { + amount = i; + } + if (amount==0) { + cmistake(u, ord, 43, MSG_PRODUCE); + return ENOITEM; + } + + if (target==-1) { + if (itype->use==NULL) { + cmistake(u, ord, 76, MSG_PRODUCE); + return EUNUSABLE; + } + return itype->use(u, itype, amount, ord); + } else { + if (itype->useonother==NULL) { + cmistake(u, ord, 76, MSG_PRODUCE); + return EUNUSABLE; + } + return itype->useonother(u, target, itype, amount, ord); + } +} + + +static double +heal_factor(const unit * u) +{ + static float elf_regen = -1; + switch(old_race(u->race)) { + case RC_TROLL: + case RC_DAEMON: + return 1.5; + case RC_GOBLIN: + return 2.0; + case RC_ELF: + if (elf_regen<0) elf_regen = get_param_flt(u->race->parameters, "regen.forest", 1.0F); + if (elf_regen!=1.0 && r_isforest(u->region)) { + return elf_regen; + } + return 1.0; + } + return 1.0; +} + +static void +monthly_healing(void) +{ + region *r; + static const curse_type * heal_ct = NULL; + if (heal_ct==NULL) heal_ct = ct_find("healingzone"); + + for (r = regions; r; r = r->next) { + unit *u; + double healingcurse = 0; + + if (heal_ct!=NULL) { + /* bonus zurücksetzen */ + curse * c = get_curse(r->attribs, heal_ct); + if (c!=NULL) { + healingcurse = curse_geteffect(c); + } + } + for (u = r->units; u; u = u->next) { + int umhp = unit_max_hp(u) * u->number; + double p = 1.0; + + /* hp über Maximum bauen sich ab. Wird zb durch Elixier der Macht + * oder verändertes Ausdauertalent verursacht */ + if (u->hp > umhp) { + u->hp -= (int) ceil((u->hp - umhp) / 2.0); + if (u->hp < umhp) u->hp = umhp; + continue; + } + + if (u->race->flags & RCF_NOHEAL) continue; + if (fval(u, UFL_HUNGER)) continue; + + if (fval(r->terrain, SEA_REGION) && u->ship==NULL && !(canswim(u) || canfly(u))) { + continue; + } + + p *= heal_factor(u); + if (u->hp < umhp) { +#ifdef NEW_DAEMONHUNGER_RULE + double maxheal = MAX(u->number, umhp/20.0); +#else + double maxheal = MAX(u->number, umhp/10.0); +#endif + int addhp; + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + if (btype == bt_find("inn")) { + p *= 1.5; + } + /* pro punkt 5% höher */ + p *= (1.0 + healingcurse * 0.05); + + maxheal = p * maxheal; + addhp = (int)maxheal; + maxheal -= addhp; + if (maxheal>0.0 && chance(maxheal)) ++addhp; + + /* Aufaddieren der geheilten HP. */ + u->hp = MIN(u->hp + addhp, umhp); + + /* soll man an negativer regeneration sterben können? */ + assert(u->hp > 0); + } + } + } +} + +static void +remove_exclusive(order ** ordp) +{ + while (*ordp) { + order * ord = *ordp; + if (is_exclusive(ord)) { + *ordp = ord->next; + ord->next = NULL; + free_order(ord); + } else { + ordp = &ord->next; + } + } +} + +static void +defaultorders (void) +{ + region *r; + for (r=regions;r;r=r->next) { + unit *u; + for (u=r->units;u;u=u->next) { + boolean neworders = false; + order ** ordp = &u->orders; + while (*ordp!=NULL) { + order * ord = *ordp; + if (get_keyword(ord)==K_DEFAULT) { + char lbuf[8192]; + order * new_order; + init_tokens(ord); + skip_token(); /* skip the keyword */ + strcpy(lbuf, getstrtoken()); + new_order = parse_order(lbuf, u->faction->locale); + *ordp = ord->next; + ord->next = NULL; + free_order(ord); + if (!neworders) { + /* lange Befehle aus orders und old_orders löschen zu gunsten des neuen */ + remove_exclusive(&u->orders); + remove_exclusive(&u->old_orders); + neworders = true; + ordp = &u->orders; /* we could have broken ordp */ + } + if (new_order) addlist(&u->old_orders, new_order); + } + else ordp = &ord->next; + } + } + } +} + +/* ************************************************************ */ +/* GANZ WICHTIG! ALLE GEÄNDERTEN SPRÜCHE NEU ANZEIGEN */ +/* GANZ WICHTIG! FÜGT AUCH NEUE ZAUBER IN DIE LISTE DER BEKANNTEN EIN */ +/* ************************************************************ */ +#define MAXMAGES 128 /* should be enough */ +static void +update_spells(void) +{ + faction * f; + + for (f=factions;f;f=f->next) { + if (f->magiegebiet!=M_NONE && !is_monsters(f)) { + unit * mages[MAXMAGES]; + unit *u; + int maxlevel = 0, n = 0, i; + + for (u=f->units;u;u=u->nextF) { + if (u->number>0) { + sc_mage *mage = get_mage(u); + if (mage) { + int level = eff_skill(u, SK_MAGIC, u->region); + if (level>maxlevel) maxlevel = level; + assert(nf->max_spelllevel) { + update_spellbook(f, maxlevel); + for (i=0;i!=n;++i) { + sc_mage *mage = get_mage(mages[i]); + while (mage->spells) { + spell_list * slist = mage->spells; + mage->spells = slist->next; + free(slist); + } + } + } + for (i=0;i!=n;++i) { + updatespelllist(mages[i]); + } + } + } +} + +static void +age_factions(void) +{ + faction *f; + + for (f = factions; f; f = f->next) { + ++f->age; + if (f->age+1 < NewbieImmunity()) { + ADDMSG(&f->msgs, msg_message("newbieimmunity", "turns", + NewbieImmunity() - f->age - 1)); + } + } +} + +static int +use_cmd(unit * u, struct order * ord) +{ + const char * t; + int n; + const item_type * itype; + + init_tokens(ord); + skip_token(); + + t = getstrtoken(); + n = atoi((const char *)t); + if (n==0) { + if (findparam(t, u->faction->locale) == P_ANY) { + /* BENUTZE ALLES Yanxspirit */ + n = INT_MAX; + t = getstrtoken(); + } else { + /* BENUTZE Yanxspirit */ + n = 1; + } + } else { + /* BENUTZE 42 Yanxspirit */ + t = getstrtoken(); + } + itype = finditemtype(t, u->faction->locale); + + if (itype!=NULL) { + int i = use_item(u, itype, n, ord); + assert(i<=0 || !"use_item should not return positive values."); + if (i>0) { + log_error(("use_item returned a value>0 for %s\n", resourcename(itype->rtype, 0))); + } + } else { + cmistake(u, ord, 43, MSG_PRODUCE); + } + return 0; +} + +static int +pay_cmd(unit * u, struct order * ord) +{ + if (!u->building) { + cmistake(u, ord, 6, MSG_EVENT); + } else { + param_t p; + init_tokens(ord); + skip_token(); + p = getparam(u->faction->locale); + if (p==P_NOT) { + unit * owner = building_owner(u->building); + if (owner->faction!=u->faction) { + cmistake(u, ord, 1222, MSG_EVENT); + } else { + u->building->flags |= BLD_DONTPAY; + } + } + } + return 0; +} + +static int +claim_cmd(unit * u, struct order * ord) +{ + const char * t; + int n; + const item_type * itype; + + init_tokens(ord); + skip_token(); + + t = getstrtoken(); + n = atoi((const char *)t); + if (n==0) { + n = 1; + } else { + t = getstrtoken(); + } + itype = finditemtype(t, u->faction->locale); + + if (itype!=NULL) { + item ** iclaim = i_find(&u->faction->items, itype); + if (iclaim!=NULL && *iclaim!=NULL) { + n = MIN(n, (*iclaim)->number); + i_change(iclaim, itype, -n); + i_change(&u->items, itype, n); + } + } else { + cmistake(u, ord, 43, MSG_PRODUCE); + } + return 0; +} + +enum { + PROC_THISORDER = 1<<0, + PROC_LONGORDER = 1<<1 +}; +typedef struct processor { + struct processor * next; + int priority; + enum { PR_GLOBAL, PR_REGION_PRE, PR_UNIT, PR_ORDER, PR_REGION_POST } type; + unsigned int flags; + union { + struct { + keyword_t kword; + int (*process)(struct unit *, struct order *); + } per_order; + struct { + void (*process)(struct unit *); + } per_unit; + struct { + void (*process)(struct region *); + } per_region; + struct { + void (*process)(void); + } global; + } data; + const char * name; +} processor; + +static processor * processors; + +processor * +add_proc(int priority, const char * name, int type) +{ + processor **pproc = &processors; + processor *proc; + + while (*pproc) { + proc = *pproc; + if (proc->priority>priority) break; + else if (proc->priority==priority && proc->type>=type) break; + pproc = &proc->next; + } + + proc = malloc(sizeof(processor)); + proc->priority = priority; + proc->type = type; + proc->name = name; + proc->next = *pproc; + *pproc = proc; + return proc; +} + +void +add_proc_order(int priority, keyword_t kword, int (*parser)(struct unit *, struct order *), unsigned int flags, const char * name) +{ + if (!global.disabled[kword]) { + processor * proc = add_proc(priority, name, PR_ORDER); + if (proc) { + proc->data.per_order.process = parser; + proc->data.per_order.kword = kword; + proc->flags = flags; + } + } +} + +void +add_proc_global(int priority, void (*process)(void), const char * name) +{ + processor * proc = add_proc(priority, name, PR_GLOBAL); + if (proc) { + proc->data.global.process = process; + } +} + +void +add_proc_region(int priority, void (*process)(region *), const char * name) +{ + processor * proc = add_proc(priority, name, PR_REGION_PRE); + if (proc) { + proc->data.per_region.process = process; + } +} + +void +add_proc_postregion(int priority, void (*process)(region *), const char * name) +{ + processor * proc = add_proc(priority, name, PR_REGION_POST); + if (proc) { + proc->data.per_region.process = process; + } +} + +void +add_proc_unit(int priority, void (*process)(unit *), const char * name) +{ + processor * proc = add_proc(priority, name, PR_UNIT); + if (proc) { + proc->data.per_unit.process = process; + } +} + +/* per priority, execute processors in order from PR_GLOBAL down to PR_ORDER */ +void +process(void) +{ + processor *proc = processors; + faction * f; + + while (proc) { + int prio = proc->priority; + region *r; + processor *pglobal = proc; + + if (verbosity>=3) printf("- Step %u\n", prio); + while (proc && proc->priority==prio) { + if (proc->name && verbosity>=1) log_stdio(stdout, " - %s\n", proc->name); + proc = proc->next; + } + + while (pglobal && pglobal->priority==prio && pglobal->type==PR_GLOBAL) { + pglobal->data.global.process(); + pglobal = pglobal->next; + } + if (pglobal==NULL || pglobal->priority!=prio) continue; + + for (r = regions; r; r = r->next) { + unit *u; + processor *pregion = pglobal; + + while (pregion && pregion->priority==prio && pregion->type==PR_REGION_PRE) { + pregion->data.per_region.process(r); + pregion = pregion->next; + } + if (pregion==NULL || pregion->priority!=prio) continue; + + if (r->units) { + for (u=r->units;u;u=u->next) { + processor *porder, *punit = pregion; + + while (punit && punit->priority==prio && punit->type==PR_UNIT) { + punit->data.per_unit.process(u); + punit = punit->next; + } + if (punit==NULL || punit->priority!=prio) continue; + + porder = punit; + while (porder && porder->priority==prio && porder->type==PR_ORDER) { + order ** ordp = &u->orders; + if (porder->flags & PROC_THISORDER) ordp = &u->thisorder; + while (*ordp) { + order * ord = *ordp; + if (get_keyword(ord) == porder->data.per_order.kword) { + if (porder->flags & PROC_LONGORDER) { + if (u->number==0) { + ord = NULL; + } else if (u->race == new_race[RC_INSECT] && r_insectstalled(r) && !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) { + ord = NULL; + } else if (LongHunger(u)) { + cmistake(u, ord, 224, MSG_MAGIC); + ord = NULL; + } else if (fval(u, UFL_LONGACTION)) { + cmistake(u, ord, 52, MSG_PRODUCE); + ord = NULL; + } else if (fval(r->terrain, SEA_REGION) && u->race != new_race[RC_AQUARIAN] && !(u->race->flags & RCF_SWIM)) { + /* error message disabled by popular demand */ + ord = NULL; + } + } + if (ord) { + porder->data.per_order.process(u, ord); + } + } + if (!ord || *ordp==ord) ordp=&(*ordp)->next; + } + porder = porder->next; + } + } + } + + while (pregion && pregion->priority==prio && pregion->type!=PR_REGION_POST) { + pregion = pregion->next; + } + + while (pregion && pregion->priority==prio && pregion->type==PR_REGION_POST) { + pregion->data.per_region.process(r); + pregion = pregion->next; + } + if (pregion==NULL || pregion->priority!=prio) continue; + + } + } + + if (verbosity>=3) printf("\n - Leere Gruppen loeschen...\n"); + for (f=factions; f; f=f->next) { + group ** gp = &f->groups; + while (*gp) { + group * g = *gp; + if (g->members==0) { + *gp = g->next; + free_group(g); + } else + gp = &g->next; + } + } + +} + +static void enter_1(region * r) { do_misc(r, false); } +static void enter_2(region * r) { do_misc(r, true); } +static void maintain_buildings_1(region * r) { maintain_buildings(r, false); } +#ifdef COLLAPSE_CHANCE +static void maintain_buildings_2(region * r) { maintain_buildings(r,true); } +#endif +static void reset_moved(unit * u) { freset(u, UFL_MOVED); } + +/** warn about passwords that are not US ASCII. + * even though passwords are technically UTF8 strings, the server receives + * them as part of the Subject of an email when reports are requested. + * This means that we need to limit them to ASCII characters until that + * mechanism has been changed. + */ +static int +warn_password(void) +{ + faction * f = factions; + while (f) { + boolean pwok = true; + const char * c = f->passw; + while (*c && pwok) { + if (!isalnum((unsigned char)*c)) pwok = false; + c++; + } + if (!pwok) { + free(f->passw); + f->passw = strdup(itoa36(rng_int())); + ADDMSG(&f->msgs, msg_message("illegal_password", "newpass", f->passw)); + } + f = f->next; + } + return 0; +} + +void +init_processor(void) +{ + int p; + + p = 10; + add_proc_global(p, &new_units, "Neue Einheiten erschaffen"); + + p+=10; + add_proc_unit(p, &setdefaults, "Default-Befehle"); + add_proc_order(p, K_BANNER, &banner_cmd, 0, NULL); + add_proc_order(p, K_EMAIL, &email_cmd, 0, NULL); + add_proc_order(p, K_PASSWORD, &password_cmd, 0, NULL); + add_proc_order(p, K_SEND, &send_cmd, 0, NULL); + add_proc_order(p, K_GROUP, &group_cmd, 0, NULL); + + p+=10; + add_proc_unit(p, &reset_moved, "Instant-Befehle"); + add_proc_order(p, K_QUIT, &quit_cmd, 0, NULL); + add_proc_order(p, K_URSPRUNG, &origin_cmd, 0, NULL); + add_proc_order(p, K_ALLY, &ally_cmd, 0, NULL); + add_proc_order(p, K_PREFIX, &prefix_cmd, 0, NULL); + add_proc_order(p, K_SETSTEALTH, &setstealth_cmd, 0, NULL); + add_proc_order(p, K_STATUS, &status_cmd, 0, NULL); + add_proc_order(p, K_COMBATSPELL, &combatspell_cmd, 0, NULL); + add_proc_order(p, K_DISPLAY, &display_cmd, 0, NULL); + add_proc_order(p, K_NAME, &name_cmd, 0, NULL); + add_proc_order(p, K_GUARD, &guard_off_cmd, 0, NULL); + add_proc_order(p, K_RESHOW, &reshow_cmd, 0, NULL); + + if (get_param_int(global.parameters, "rules.alliances", 0)==1) { + p+=10; + add_proc_global(p, &alliance_cmd, NULL); + } + + p+=10; + add_proc_global(p, &age_factions, "Parteienalter++"); + add_proc_order(p, K_MAIL, &mail_cmd, 0, "Botschaften"); + + p+=10; /* all claims must be done before we can USE */ + add_proc_region(p, &enter_1, "Kontaktieren & Betreten (1. Versuch)"); + add_proc_order(p, K_USE, &use_cmd, 0, "Benutzen"); + + if (!global.disabled[K_GM]) { + add_proc_global(p, &gmcommands, "GM Kommandos"); + } + + p += 10; /* in case it has any effects on alliance victories */ + add_proc_order(p, K_GIVE, &give_control_cmd, 0, "GIB KOMMANDO"); + + p += 10; /* in case it has any effects on alliance victories */ + add_proc_order(p, K_LEAVE, &leave_cmd, 0, "Verlassen"); + + if (!nobattle) { + add_proc_region(p, &do_battle, "Attackieren"); + } + + if (!global.disabled[K_BESIEGE]) { + p+=10; + add_proc_region(p, &do_siege, "Belagern"); + } + + p+=10; /* can't allow reserve before siege (weapons) */ + add_proc_region(p, &enter_1, "Kontaktieren & Betreten (2. Versuch)"); + add_proc_order(p, K_RESERVE, &reserve_cmd, 0, "Reservieren"); + add_proc_order(p, K_CLAIM, &claim_cmd, 0, NULL); + add_proc_unit(p, &follow_unit, "Folge auf Einheiten setzen"); + + p+=10; /* rest rng again before economics */ + add_proc_region(p, &economics, "Zerstoeren, Geben, Rekrutieren, Vergessen"); + + p+=10; + if (!global.disabled[K_PAY]) { + add_proc_order(p, K_PAY, &pay_cmd, 0, "Gebaeudeunterhalt (disable)"); + } + add_proc_postregion(p, &maintain_buildings_1, "Gebaeudeunterhalt (1. Versuch)"); + + p+=10; /* QUIT fuer sich alleine */ + add_proc_global(p, &quit, "Sterben"); + if (!global.disabled[K_RESTART]) { + add_proc_global(p, &parse_restart, "Neustart"); + } + + if (!global.disabled[K_CAST]) { + p+=10; + add_proc_global(p, &magic, "Zaubern"); + } + + p+=10; + add_proc_order(p, K_TEACH, &teach_cmd, PROC_THISORDER|PROC_LONGORDER, "Lehren"); + p+=10; + add_proc_order(p, K_STUDY, &learn_cmd, PROC_THISORDER|PROC_LONGORDER, "Lernen"); + + p+=10; + add_proc_order(p, K_MAKE, &make_cmd, PROC_THISORDER|PROC_LONGORDER, "Produktion"); + add_proc_postregion(p, &produce, "Arbeiten, Handel, Rekruten"); + add_proc_postregion(p, &split_allocations, "Produktion II"); + + p+=10; + add_proc_region(p, &enter_2, "Kontaktieren & Betreten (3. Versuch)"); + + p+=10; + add_proc_region(p, &sinkships, "Schiffe sinken"); + + p+=10; + add_proc_global(p, &movement, "Bewegungen"); + + if (get_param_int(global.parameters, "work.auto", 0)) { + p+=10; + add_proc_region(p, &auto_work, "Arbeiten (auto)"); + } + + p+=10; + add_proc_order(p, K_GUARD, &guard_on_cmd, 0, "Bewache (an)"); +#if XECMD_MODULE + /* can do together with guard */ + add_proc_order(p, K_XE, &xecmd, 0, "Zeitung"); +#endif + + p+=10; + add_proc_global(p, &encounters, "Zufallsbegegnungen"); + p+=10; + add_proc_unit(p, &monster_kills_peasants, "Monster fressen und vertreiben Bauern"); + + p+=10; + add_proc_global(p, &randomevents, "Zufallsereignisse"); + + p+=10; + + add_proc_global(p, &monthly_healing, "Regeneration (HP)"); + add_proc_global(p, ®eneration_magiepunkte, "Regeneration (Aura)"); + if (!global.disabled[K_DEFAULT]) { + add_proc_global(p, &defaultorders, "Defaults setzen"); + } + add_proc_global(p, &demographics, "Nahrung, Seuchen, Wachstum, Wanderung"); + +#ifdef COLLAPSE_CHANCE + p+=10; + add_proc_region(p, &maintain_buildings_2, "Gebaeudeunterhalt (2. Versuch)"); +#endif + + if (!global.disabled[K_SORT]) { + p+=10; + add_proc_global(p, &reorder, "Einheiten sortieren"); + } + add_proc_order(p, K_PROMOTION, &promotion_cmd, 0, "Heldenbefoerderung"); + if (!global.disabled[K_NUMBER]) { + add_proc_order(p, K_NUMBER, &renumber_cmd, 0, "Neue Nummern (Einheiten)"); + p+=10; + add_proc_global(p, &renumber_factions, "Neue Nummern"); + } +} + +void +processorders (void) +{ + static int init = 0; + + if (!init) { + init_processor(); + init = 1; + } + update_spells(); + process(); + /*************************************************/ + + if (get_param_int(global.parameters, "modules.markets", 0)) { + do_markets(); + } + + if (verbosity>=1) puts(" - Attribute altern"); + ageing(); + remove_empty_units(); + + /* must happen AFTER age, because that would destroy them right away */ + if (get_param_int(global.parameters, "modules.wormholes", 0)) { + create_wormholes(); + } + + /* immer ausführen, wenn neue Sprüche dazugekommen sind, oder sich + * Beschreibungen geändert haben */ + update_spells(); + warn_password(); +} + +int +writepasswd(void) +{ + FILE * F; + char zText[128]; + + sprintf(zText, "%s/passwd", basepath()); + F = cfopen(zText, "w"); + if (F) { + faction *f; + puts("writing passwords..."); + + for (f = factions; f; f = f->next) { + fprintf(F, "%s:%s:%s:%s:%u\n", + factionid(f), f->email, f->passw, f->override, f->subscription); + } + fclose(F); + return 0; + } + return 1; +} + +void +update_subscriptions(void) +{ + FILE * F; + char zText[MAX_PATH]; + faction * f; + strcat(strcpy(zText, basepath()), "/subscriptions"); + F = fopen(zText, "r"); + if (F==NULL) { + log_warning((0, "could not open %s.\n", zText)); + return; + } + for (;;) { + char zFaction[5]; + int subscription, fno; + if (fscanf(F, "%d %s", &subscription, zFaction)<=0) break; + fno = atoi36(zFaction); + f = findfaction(fno); + if (f!=NULL) { + f->subscription=subscription; + } + } + fclose(F); + + sprintf(zText, "subscriptions.%u", turn); + F = fopen(zText, "w"); + for (f=factions;f!=NULL;f=f->next) { + fprintf(F, "%s:%u:%s:%s:%s:%u:\n", + itoa36(f->no), f->subscription, f->email, f->override, + dbrace(f->race), f->lastorders); + } + fclose(F); +} + +int +init_data(const char * filename, const char * catalog) +{ + int l; + + l = read_xml(filename, catalog); + if (l) return l; + + init_locales(); + init_archetypes(); + + if (turn<0) { + turn = first_turn; + } + return 0; +} + +#ifndef DISABLE_TESTS +#include "laws_test.c" +#endif diff --git a/src/gamecode/laws.h b/src/gamecode/laws.h index 7b1e12cb0..5aa7d6f94 100644 --- a/src/gamecode/laws.h +++ b/src/gamecode/laws.h @@ -1,47 +1,47 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_GC_LAWS -#define H_GC_LAWS -#ifdef __cplusplus -extern "C" { -#endif - -extern int writepasswd(void); -int getoption(void); -int wanderoff(struct region * r, int p); -void demographics(void); -void last_orders(void); -void find_address(void); -void update_guards(void); -void update_subscriptions(void); -void deliverMail(struct faction * f, struct region * r, struct unit * u, const char *s, struct unit * receiver); -int init_data(const char * filename, const char * catalog); - -/* eressea-specific. put somewhere else, please. */ -void processorders(void); -extern struct attrib_type at_germs; - -extern int dropouts[2]; -extern int * age; - -#ifdef __cplusplus -} -#endif - -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_GC_LAWS +#define H_GC_LAWS +#ifdef __cplusplus +extern "C" { +#endif + +extern int writepasswd(void); +int getoption(void); +int wanderoff(struct region * r, int p); +void demographics(void); +void last_orders(void); +void find_address(void); +void update_guards(void); +void update_subscriptions(void); +void deliverMail(struct faction * f, struct region * r, struct unit * u, const char *s, struct unit * receiver); +int init_data(const char * filename, const char * catalog); + +/* eressea-specific. put somewhere else, please. */ +void processorders(void); +extern struct attrib_type at_germs; + +extern int dropouts[2]; +extern int * age; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/gamecode/laws_test.c b/src/gamecode/laws_test.c index f836ff784..2bc958813 100644 --- a/src/gamecode/laws_test.c +++ b/src/gamecode/laws_test.c @@ -1,148 +1,148 @@ -/* this file should only be included by laws.c, never compiled on its own - * (it does not even include all the headers needed to do so). -**/ -#include - -static void test_new_building_can_be_renamed(CuTest * tc) { - region * r; - building * b; - building_type * btype = bt_find("castle"); - - test_cleanup(); - test_create_world(); - r = findregion(-1, 0); - - b = new_building(btype, r, default_locale); - CuAssertTrue(tc, !renamed_building(b)); -} - -static void test_fishing_feeds_2_people(CuTest * tc) { - region * r; - faction * f; - unit * u; - ship * sh; - - test_cleanup(); - test_create_world(); - r = findregion(-1, 0); - CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ - f = test_create_faction(rc_find("human")); - u = test_create_unit(f, r); - sh = new_ship(st_find("boat"), NULL, r); - u->ship = sh; - i_change(&u->items, it_find("money"), 42); - - scale_number(u, 1); - sh->flags |= SF_FISHING; - get_food(r); - CuAssertIntEquals(tc, 42, i_get(u->items, it_find("money"))); - - scale_number(u, 2); - sh->flags |= SF_FISHING; - get_food(r); - CuAssertIntEquals(tc, 42, i_get(u->items, it_find("money"))); - - scale_number(u, 3); - sh->flags |= SF_FISHING; - get_food(r); - CuAssertIntEquals(tc, 32, i_get(u->items, it_find("money"))); - -} - -static int not_so_hungry(const unit * u) { - return 6 * u->number; -} - -static void test_fishing_does_not_give_goblins_money(CuTest * tc) { - region * r; - faction * f; - unit * u; - ship * sh; - - test_cleanup(); - test_create_world(); - - r = findregion(-1, 0); - CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ - f = test_create_faction(rc_find("human")); - u = test_create_unit(f, r); - sh = new_ship(st_find("boat"), NULL, r); - u->ship = sh; - i_change(&u->items, it_find("money"), 42); - - global.functions.maintenance = not_so_hungry; - scale_number(u, 2); - sh->flags |= SF_FISHING; - get_food(r); - CuAssertIntEquals(tc, 42, i_get(u->items, it_find("money"))); - -} - -static void test_fishing_gets_reset(CuTest * tc) { - region * r; - faction * f; - unit * u; - ship * sh; - - test_cleanup(); - test_create_world(); - r = findregion(-1, 0); - CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ - f = test_create_faction(rc_find("human")); - u = test_create_unit(f, r); - sh = new_ship(st_find("boat"), NULL, r); - u->ship = sh; - i_change(&u->items, it_find("money"), 42); - - scale_number(u, 1); - sh->flags |= SF_FISHING; - get_food(r); - CuAssertIntEquals(tc, 42, i_get(u->items, it_find("money"))); - - scale_number(u, 1); - get_food(r); - CuAssertIntEquals(tc, 32, i_get(u->items, it_find("money"))); - -} - -static void test_unit_limit(CuTest * tc) { - set_param(&global.parameters, "rules.limit.faction", "250"); - CuAssertIntEquals(tc, 250, rule_faction_limit()); - - set_param(&global.parameters, "rules.limit.faction", "200"); - CuAssertIntEquals(tc, 200, rule_faction_limit()); - - set_param(&global.parameters, "rules.limit.alliance", "250"); - CuAssertIntEquals(tc, 250, rule_alliance_limit()); - -} - -extern int checkunitnumber(const faction *f, int add); -static void test_cannot_create_unit_above_limit(CuTest * tc) { - faction * f; - - test_cleanup(); - test_create_world(); - f = test_create_faction(rc_find("human")); - set_param(&global.parameters, "rules.limit.faction", "4"); - - CuAssertIntEquals(tc, 0, checkunitnumber(f, 4)); - CuAssertIntEquals(tc, 2, checkunitnumber(f, 5)); - - set_param(&global.parameters, "rules.limit.alliance", "3"); - CuAssertIntEquals(tc, 0, checkunitnumber(f, 3)); - CuAssertIntEquals(tc, 1, checkunitnumber(f, 4)); -} - - -CuSuite* get_laws_suite(void) -{ - CuSuite* suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, &test_new_building_can_be_renamed); - SUITE_ADD_TEST(suite, &test_fishing_feeds_2_people); - SUITE_ADD_TEST(suite, &test_fishing_does_not_give_goblins_money); - SUITE_ADD_TEST(suite, &test_fishing_gets_reset); - SUITE_ADD_TEST(suite, &test_unit_limit); - SUITE_ADD_TEST(suite, &test_cannot_create_unit_above_limit); - return suite; -} +/* this file should only be included by laws.c, never compiled on its own + * (it does not even include all the headers needed to do so). +**/ +#include + +static void test_new_building_can_be_renamed(CuTest * tc) { + region * r; + building * b; + building_type * btype = bt_find("castle"); + + test_cleanup(); + test_create_world(); + r = findregion(-1, 0); + + b = new_building(btype, r, default_locale); + CuAssertTrue(tc, !renamed_building(b)); +} + +static void test_fishing_feeds_2_people(CuTest * tc) { + region * r; + faction * f; + unit * u; + ship * sh; + + test_cleanup(); + test_create_world(); + r = findregion(-1, 0); + CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ + f = test_create_faction(rc_find("human")); + u = test_create_unit(f, r); + sh = new_ship(st_find("boat"), NULL, r); + u->ship = sh; + i_change(&u->items, it_find("money"), 42); + + scale_number(u, 1); + sh->flags |= SF_FISHING; + get_food(r); + CuAssertIntEquals(tc, 42, i_get(u->items, it_find("money"))); + + scale_number(u, 2); + sh->flags |= SF_FISHING; + get_food(r); + CuAssertIntEquals(tc, 42, i_get(u->items, it_find("money"))); + + scale_number(u, 3); + sh->flags |= SF_FISHING; + get_food(r); + CuAssertIntEquals(tc, 32, i_get(u->items, it_find("money"))); + +} + +static int not_so_hungry(const unit * u) { + return 6 * u->number; +} + +static void test_fishing_does_not_give_goblins_money(CuTest * tc) { + region * r; + faction * f; + unit * u; + ship * sh; + + test_cleanup(); + test_create_world(); + + r = findregion(-1, 0); + CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ + f = test_create_faction(rc_find("human")); + u = test_create_unit(f, r); + sh = new_ship(st_find("boat"), NULL, r); + u->ship = sh; + i_change(&u->items, it_find("money"), 42); + + global.functions.maintenance = not_so_hungry; + scale_number(u, 2); + sh->flags |= SF_FISHING; + get_food(r); + CuAssertIntEquals(tc, 42, i_get(u->items, it_find("money"))); + +} + +static void test_fishing_gets_reset(CuTest * tc) { + region * r; + faction * f; + unit * u; + ship * sh; + + test_cleanup(); + test_create_world(); + r = findregion(-1, 0); + CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ + f = test_create_faction(rc_find("human")); + u = test_create_unit(f, r); + sh = new_ship(st_find("boat"), NULL, r); + u->ship = sh; + i_change(&u->items, it_find("money"), 42); + + scale_number(u, 1); + sh->flags |= SF_FISHING; + get_food(r); + CuAssertIntEquals(tc, 42, i_get(u->items, it_find("money"))); + + scale_number(u, 1); + get_food(r); + CuAssertIntEquals(tc, 32, i_get(u->items, it_find("money"))); + +} + +static void test_unit_limit(CuTest * tc) { + set_param(&global.parameters, "rules.limit.faction", "250"); + CuAssertIntEquals(tc, 250, rule_faction_limit()); + + set_param(&global.parameters, "rules.limit.faction", "200"); + CuAssertIntEquals(tc, 200, rule_faction_limit()); + + set_param(&global.parameters, "rules.limit.alliance", "250"); + CuAssertIntEquals(tc, 250, rule_alliance_limit()); + +} + +extern int checkunitnumber(const faction *f, int add); +static void test_cannot_create_unit_above_limit(CuTest * tc) { + faction * f; + + test_cleanup(); + test_create_world(); + f = test_create_faction(rc_find("human")); + set_param(&global.parameters, "rules.limit.faction", "4"); + + CuAssertIntEquals(tc, 0, checkunitnumber(f, 4)); + CuAssertIntEquals(tc, 2, checkunitnumber(f, 5)); + + set_param(&global.parameters, "rules.limit.alliance", "3"); + CuAssertIntEquals(tc, 0, checkunitnumber(f, 3)); + CuAssertIntEquals(tc, 1, checkunitnumber(f, 4)); +} + + +CuSuite* get_laws_suite(void) +{ + CuSuite* suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, &test_new_building_can_be_renamed); + SUITE_ADD_TEST(suite, &test_fishing_feeds_2_people); + SUITE_ADD_TEST(suite, &test_fishing_does_not_give_goblins_money); + SUITE_ADD_TEST(suite, &test_fishing_gets_reset); + SUITE_ADD_TEST(suite, &test_unit_limit); + SUITE_ADD_TEST(suite, &test_cannot_create_unit_above_limit); + return suite; +} diff --git a/src/gamecode/market.c b/src/gamecode/market.c index 037936a29..34d13172e 100644 --- a/src/gamecode/market.c +++ b/src/gamecode/market.c @@ -1,184 +1,184 @@ -/* vi: set ts=2: -+-------------------+ Christian Schlittchen -| | Enno Rehling -| Eressea PBEM host | Katja Zedel -| (c) 1998 - 2003 | Henning Peters -| | Ingo Wilken -+-------------------+ Stefan Reich - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. - -*/ -#include -#include -#include "market.h" - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -static unsigned int -get_markets(region * r, unit ** results, size_t size) -{ - unsigned int n = 0; - building * b; - static building_type * btype; - if (!btype) btype = bt_find("market"); - if (!btype) return 0; - for (b=r->buildings;nnext) { - if (b->type==btype && (b->flags&BLD_WORKING) && b->size>=b->type->maxsize) { - unit * u = building_owner(b); - unsigned int i; - for (i=0;u && i!=n;++i) { - /* only one market per faction */ - if (results[i]->faction==u->faction) u = NULL; - } - if (u) { - results[n++] = u; - } - } - } - return n; -} - - -static void -free_market(attrib * a) -{ - item * items = (item *)a->data.v; - i_freeall(&items); - a->data.v = 0; -} - -attrib_type at_market = { - "script", - NULL, free_market, NULL, - NULL, NULL, ATF_UNIQUE -}; - -static int rc_luxury_trade(const struct race * rc) -{ - if (rc) { - return get_param_int(rc->parameters, "luxury_trade", 1000); - } - return 1000; -} - -static int rc_herb_trade(const struct race * rc) -{ - if (rc) { - return get_param_int(rc->parameters, "herb_trade", 500); - } - return 500; -} - -#define MAX_MARKETS 128 -#define MIN_PEASANTS 50 /* if there are at least this many peasants, you will get 1 good */ - -void do_markets(void) -{ - unit_list * traders = 0; - unit * markets[MAX_MARKETS]; - region * r; - for (r=regions;r;r=r->next) { - if (r->land) { - faction * f = region_get_owner(r); - const struct race * rc = f?f->race:NULL; - int p = rpeasants(r); - int numlux = rc_luxury_trade(rc), numherbs = rc_herb_trade(rc); - numlux = (p+numlux-MIN_PEASANTS)/numlux; - numherbs = (p+numherbs-MIN_PEASANTS)/numherbs; - if (numlux>0 || numherbs>0) { - int d, nmarkets = 0; - const item_type * lux = r_luxury(r); - const item_type * herb = r->land->herbtype; - - nmarkets += get_markets(r, markets+nmarkets, MAX_MARKETS-nmarkets); - for (d=0;d!=MAXDIRECTIONS;++d) { - region * r2 = rconnect(r, d); - if (r2 && r2->buildings) { - nmarkets += get_markets(r2, markets+nmarkets, MAX_MARKETS-nmarkets); - } - } - if (nmarkets) { - while (lux && numlux--) { - int n = rng_int() % nmarkets; - unit * u = markets[n]; - item * items; - attrib * a = a_find(u->attribs, &at_market); - if (a==NULL) { - unit_list * ulist = malloc(sizeof(unit_list)); - a = a_add(&u->attribs, a_new(&at_market)); - ulist->next = traders; - ulist->data = u; - traders = ulist; - } - items = (item *)a->data.v; - i_change(&items, lux, 1); - a->data.v = items; - /* give 1 luxury */ - } - while (herb && numherbs--) { - int n = rng_int() % nmarkets; - unit * u = markets[n]; - item * items; - attrib * a = a_find(u->attribs, &at_market); - if (a==NULL) { - unit_list * ulist = malloc(sizeof(unit_list)); - a = a_add(&u->attribs, a_new(&at_market)); - ulist->next = traders; - ulist->data = u; - traders = ulist; - } - items = (item *)a->data.v; - i_change(&items, herb, 1); - a->data.v = items; - /* give 1 herb */ - } - } - } - } - } - - while (traders) { - unit_list * trade = traders; - unit * u = trade->data; - attrib * a = a_find(u->attribs, &at_market); - item * items = a->data.v; - - a->data.v = NULL; - while (items) { - item * itm = items; - items = itm->next; - - if (itm->number) { - ADDMSG(&u->faction->msgs, msg_message("buyamount", - "unit amount resource", u, itm->number, itm->type->rtype)); - itm->next = NULL; - i_add(&u->items, itm); - } else { - i_free(itm); - } - } - - traders = trade->next; - - a_remove(&u->attribs, a); - free(trade); - } -} -#ifndef DISABLE_TESTS -#include "market_test.c" -#endif +/* vi: set ts=2: ++-------------------+ Christian Schlittchen +| | Enno Rehling +| Eressea PBEM host | Katja Zedel +| (c) 1998 - 2003 | Henning Peters +| | Ingo Wilken ++-------------------+ Stefan Reich + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. + +*/ +#include +#include +#include "market.h" + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +static unsigned int +get_markets(region * r, unit ** results, size_t size) +{ + unsigned int n = 0; + building * b; + static building_type * btype; + if (!btype) btype = bt_find("market"); + if (!btype) return 0; + for (b=r->buildings;nnext) { + if (b->type==btype && (b->flags&BLD_WORKING) && b->size>=b->type->maxsize) { + unit * u = building_owner(b); + unsigned int i; + for (i=0;u && i!=n;++i) { + /* only one market per faction */ + if (results[i]->faction==u->faction) u = NULL; + } + if (u) { + results[n++] = u; + } + } + } + return n; +} + + +static void +free_market(attrib * a) +{ + item * items = (item *)a->data.v; + i_freeall(&items); + a->data.v = 0; +} + +attrib_type at_market = { + "script", + NULL, free_market, NULL, + NULL, NULL, ATF_UNIQUE +}; + +static int rc_luxury_trade(const struct race * rc) +{ + if (rc) { + return get_param_int(rc->parameters, "luxury_trade", 1000); + } + return 1000; +} + +static int rc_herb_trade(const struct race * rc) +{ + if (rc) { + return get_param_int(rc->parameters, "herb_trade", 500); + } + return 500; +} + +#define MAX_MARKETS 128 +#define MIN_PEASANTS 50 /* if there are at least this many peasants, you will get 1 good */ + +void do_markets(void) +{ + unit_list * traders = 0; + unit * markets[MAX_MARKETS]; + region * r; + for (r=regions;r;r=r->next) { + if (r->land) { + faction * f = region_get_owner(r); + const struct race * rc = f?f->race:NULL; + int p = rpeasants(r); + int numlux = rc_luxury_trade(rc), numherbs = rc_herb_trade(rc); + numlux = (p+numlux-MIN_PEASANTS)/numlux; + numherbs = (p+numherbs-MIN_PEASANTS)/numherbs; + if (numlux>0 || numherbs>0) { + int d, nmarkets = 0; + const item_type * lux = r_luxury(r); + const item_type * herb = r->land->herbtype; + + nmarkets += get_markets(r, markets+nmarkets, MAX_MARKETS-nmarkets); + for (d=0;d!=MAXDIRECTIONS;++d) { + region * r2 = rconnect(r, d); + if (r2 && r2->buildings) { + nmarkets += get_markets(r2, markets+nmarkets, MAX_MARKETS-nmarkets); + } + } + if (nmarkets) { + while (lux && numlux--) { + int n = rng_int() % nmarkets; + unit * u = markets[n]; + item * items; + attrib * a = a_find(u->attribs, &at_market); + if (a==NULL) { + unit_list * ulist = malloc(sizeof(unit_list)); + a = a_add(&u->attribs, a_new(&at_market)); + ulist->next = traders; + ulist->data = u; + traders = ulist; + } + items = (item *)a->data.v; + i_change(&items, lux, 1); + a->data.v = items; + /* give 1 luxury */ + } + while (herb && numherbs--) { + int n = rng_int() % nmarkets; + unit * u = markets[n]; + item * items; + attrib * a = a_find(u->attribs, &at_market); + if (a==NULL) { + unit_list * ulist = malloc(sizeof(unit_list)); + a = a_add(&u->attribs, a_new(&at_market)); + ulist->next = traders; + ulist->data = u; + traders = ulist; + } + items = (item *)a->data.v; + i_change(&items, herb, 1); + a->data.v = items; + /* give 1 herb */ + } + } + } + } + } + + while (traders) { + unit_list * trade = traders; + unit * u = trade->data; + attrib * a = a_find(u->attribs, &at_market); + item * items = a->data.v; + + a->data.v = NULL; + while (items) { + item * itm = items; + items = itm->next; + + if (itm->number) { + ADDMSG(&u->faction->msgs, msg_message("buyamount", + "unit amount resource", u, itm->number, itm->type->rtype)); + itm->next = NULL; + i_add(&u->items, itm); + } else { + i_free(itm); + } + } + + traders = trade->next; + + a_remove(&u->attribs, a); + free(trade); + } +} +#ifndef DISABLE_TESTS +#include "market_test.c" +#endif diff --git a/src/gamecode/market.h b/src/gamecode/market.h index b66f27350..e45fbb7a1 100644 --- a/src/gamecode/market.h +++ b/src/gamecode/market.h @@ -1,25 +1,25 @@ -/* vi: set ts=2: -+-------------------+ Christian Schlittchen -| | Enno Rehling -| Eressea PBEM host | Katja Zedel -| (c) 1998 - 2003 | Henning Peters -| | Ingo Wilken -+-------------------+ Stefan Reich - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. - -*/ -#ifndef H_GC_MARKET -#define H_GC_MARKET -#ifdef __cplusplus -extern "C" { -#endif - struct building; - - extern void do_markets(void); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: ++-------------------+ Christian Schlittchen +| | Enno Rehling +| Eressea PBEM host | Katja Zedel +| (c) 1998 - 2003 | Henning Peters +| | Ingo Wilken ++-------------------+ Stefan Reich + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. + +*/ +#ifndef H_GC_MARKET +#define H_GC_MARKET +#ifdef __cplusplus +extern "C" { +#endif + struct building; + + extern void do_markets(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/market_test.c b/src/gamecode/market_test.c index 44dc677d3..6b993dc83 100644 --- a/src/gamecode/market_test.c +++ b/src/gamecode/market_test.c @@ -1,66 +1,66 @@ -#include - -#include -#include - -static void market_curse(CuTest * tc) { - region * r; - building * b; - unit * u; - faction * f; - int x, y; - const char * names[4] = { "herb", "herbs", "balm", "balms" }; - terrain_type * terrain; - resource_type * hres = new_resourcetype(names, 0, RTF_ITEM|RTF_POOLED); - item_type * htype = new_itemtype(hres, ITF_HERB, 0, 0); - resource_type * lres = new_resourcetype(names+2, 0, RTF_ITEM|RTF_POOLED); - item_type * ltype = new_itemtype(lres, ITF_NONE, 0, 0); - luxury_type * lux = new_luxurytype(ltype, 0); - building_type * btype; - race * rc = rc_add(rc_new("human")); - struct locale * lang = make_locale("en"); - - free_gamedata(); - - set_param(&global.parameters, "rules.region_owners", "1"); - - btype = calloc(sizeof(building_type), 1); - btype->_name = "market"; - bt_register(btype); - - terrain = calloc(1, sizeof(terrain_type)); - terrain->_name = strdup("plain"); - register_terrain(terrain); - terrain->flags = LAND_REGION|WALK_INTO; - - for (x=0;x!=3;++x) { - for (y=0;y!=3;++y) { - r = new_region(x, y, NULL, 0); - terraform_region(r, terrain); - rsetpeasants(r, 5000); - r_setdemand(r, lux, 0); - rsetherbtype(r, htype); - } - } - r = findregion(1, 1); - b = new_building(btype, r, lang); - b->flags |= BLD_WORKING; - b->size = b->type->maxsize; - - f = addfaction("nobody@eressea.de", NULL, rc, default_locale, 0); - u = create_unit(r, f, 1, f->race, 0, 0, 0); - u->building = b; - u->flags |= UFL_OWNER; - - do_markets(); - - CuAssertIntEquals(tc, 70, i_get(u->items, htype)); - CuAssertIntEquals(tc, 35, i_get(u->items, ltype)); -} - -CuSuite* get_market_suite(void) -{ - CuSuite* suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, market_curse); - return suite; -} +#include + +#include +#include + +static void market_curse(CuTest * tc) { + region * r; + building * b; + unit * u; + faction * f; + int x, y; + const char * names[4] = { "herb", "herbs", "balm", "balms" }; + terrain_type * terrain; + resource_type * hres = new_resourcetype(names, 0, RTF_ITEM|RTF_POOLED); + item_type * htype = new_itemtype(hres, ITF_HERB, 0, 0); + resource_type * lres = new_resourcetype(names+2, 0, RTF_ITEM|RTF_POOLED); + item_type * ltype = new_itemtype(lres, ITF_NONE, 0, 0); + luxury_type * lux = new_luxurytype(ltype, 0); + building_type * btype; + race * rc = rc_add(rc_new("human")); + struct locale * lang = make_locale("en"); + + free_gamedata(); + + set_param(&global.parameters, "rules.region_owners", "1"); + + btype = calloc(sizeof(building_type), 1); + btype->_name = "market"; + bt_register(btype); + + terrain = calloc(1, sizeof(terrain_type)); + terrain->_name = strdup("plain"); + register_terrain(terrain); + terrain->flags = LAND_REGION|WALK_INTO; + + for (x=0;x!=3;++x) { + for (y=0;y!=3;++y) { + r = new_region(x, y, NULL, 0); + terraform_region(r, terrain); + rsetpeasants(r, 5000); + r_setdemand(r, lux, 0); + rsetherbtype(r, htype); + } + } + r = findregion(1, 1); + b = new_building(btype, r, lang); + b->flags |= BLD_WORKING; + b->size = b->type->maxsize; + + f = addfaction("nobody@eressea.de", NULL, rc, default_locale, 0); + u = create_unit(r, f, 1, f->race, 0, 0, 0); + u->building = b; + u->flags |= UFL_OWNER; + + do_markets(); + + CuAssertIntEquals(tc, 70, i_get(u->items, htype)); + CuAssertIntEquals(tc, 35, i_get(u->items, ltype)); +} + +CuSuite* get_market_suite(void) +{ + CuSuite* suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, market_curse); + return suite; +} diff --git a/src/gamecode/monster.c b/src/gamecode/monster.c index 2a0e0d5da..50436a947 100644 --- a/src/gamecode/monster.c +++ b/src/gamecode/monster.c @@ -1,227 +1,227 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "monster.h" - -/* gamecode includes */ -#include "economy.h" -#include "give.h" - -/* triggers includes */ -#include - -/* attributes includes */ -#include -#include - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -#define MOVECHANCE 25 /* chance fuer bewegung */ - -#define MAXILLUSION_TEXTS 3 - -boolean -monster_is_waiting(const unit * u) -{ - if (fval(u, UFL_ISNEW|UFL_MOVED)) return true; - return false; -} - -static void -eaten_by_monster(unit * u) -{ - /* adjustment for smaller worlds */ - static double multi = 0.0; - int n = 0; - int horse = 0; - - if (multi==0.0) { - multi = RESOURCE_QUANTITY * newterrain(T_PLAIN)->size / 10000.0; - } - - switch (old_race(u->race)) { - case RC_FIREDRAGON: - n = rng_int()%80 * u->number; - horse = get_item(u, I_HORSE); - break; - case RC_DRAGON: - n = rng_int()%200 * u->number; - horse = get_item(u, I_HORSE); - break; - case RC_WYRM: - n = rng_int()%500 * u->number; - horse = get_item(u, I_HORSE); - break; - default: - n = rng_int()%(u->number/20+1); - } - - n = (int)(n * multi); - if (n > 0) { - n = lovar(n); - n = MIN(rpeasants(u->region), n); - - if (n > 0) { - deathcounts(u->region, n); - rsetpeasants(u->region, rpeasants(u->region) - n); - ADDMSG(&u->region->msgs, msg_message("eatpeasants", "unit amount", u, n)); - } - } - if (horse > 0) { - set_item(u, I_HORSE, 0); - ADDMSG(&u->region->msgs, msg_message("eathorse", "unit amount", u, horse)); - } -} - -static void -absorbed_by_monster(unit * u) -{ - int n; - - switch (old_race(u->race)) { - default: - n = rng_int()%(u->number/20+1); - } - - if(n > 0) { - n = lovar(n); - n = MIN(rpeasants(u->region), n); - if (n > 0){ - rsetpeasants(u->region, rpeasants(u->region) - n); - scale_number(u, u->number + n); - ADDMSG(&u->region->msgs, msg_message("absorbpeasants", - "unit race amount", u, u->race, n)); - } - } -} - -static int -scareaway(region * r, int anzahl) -{ - int n, p, diff = 0, emigrants[MAXDIRECTIONS]; - direction_t d; - - anzahl = MIN(MAX(1, anzahl),rpeasants(r)); - - /* Wandern am Ende der Woche (normal) oder wegen Monster. Die - * Wanderung wird erst am Ende von demographics () ausgefuehrt. - * emigrants[] ist local, weil r->newpeasants durch die Monster - * vielleicht schon hochgezaehlt worden ist. */ - - for (d = 0; d != MAXDIRECTIONS; d++) - emigrants[d] = 0; - - p = rpeasants(r); - assert(p >= 0 && anzahl >= 0); - for (n = MIN(p, anzahl); n; n--) { - direction_t dir = (direction_t)(rng_int() % MAXDIRECTIONS); - region * rc = rconnect(r, dir); - - if (rc && fval(rc->terrain, LAND_REGION)) { - ++diff; - rc->land->newpeasants++; - emigrants[dir]++; - } - } - rsetpeasants(r, p-diff); - assert(p >= diff); - return diff; -} - -static void -scared_by_monster(unit * u) -{ - int n; - - switch (old_race(u->race)) { - case RC_FIREDRAGON: - n = rng_int()%160 * u->number; - break; - case RC_DRAGON: - n = rng_int()%400 * u->number; - break; - case RC_WYRM: - n = rng_int()%1000 * u->number; - break; - default: - n = rng_int()%(u->number/4+1); - } - - if(n > 0) { - n = lovar(n); - n = MIN(rpeasants(u->region), n); - if(n > 0) { - n = scareaway(u->region, n); - if(n > 0) { - ADDMSG(&u->region->msgs, msg_message("fleescared", - "amount unit", n, u)); - } - } - } -} - -void -monster_kills_peasants(unit * u) -{ - if (!monster_is_waiting(u)) { - if (u->race->flags & RCF_SCAREPEASANTS) { - scared_by_monster(u); - } - if (u->race->flags & RCF_KILLPEASANTS) { - eaten_by_monster(u); - } - if (u->race->flags & RCF_ABSORBPEASANTS) { - absorbed_by_monster(u); - } - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "monster.h" + +/* gamecode includes */ +#include "economy.h" +#include "give.h" + +/* triggers includes */ +#include + +/* attributes includes */ +#include +#include + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +#define MOVECHANCE 25 /* chance fuer bewegung */ + +#define MAXILLUSION_TEXTS 3 + +boolean +monster_is_waiting(const unit * u) +{ + if (fval(u, UFL_ISNEW|UFL_MOVED)) return true; + return false; +} + +static void +eaten_by_monster(unit * u) +{ + /* adjustment for smaller worlds */ + static double multi = 0.0; + int n = 0; + int horse = 0; + + if (multi==0.0) { + multi = RESOURCE_QUANTITY * newterrain(T_PLAIN)->size / 10000.0; + } + + switch (old_race(u->race)) { + case RC_FIREDRAGON: + n = rng_int()%80 * u->number; + horse = get_item(u, I_HORSE); + break; + case RC_DRAGON: + n = rng_int()%200 * u->number; + horse = get_item(u, I_HORSE); + break; + case RC_WYRM: + n = rng_int()%500 * u->number; + horse = get_item(u, I_HORSE); + break; + default: + n = rng_int()%(u->number/20+1); + } + + n = (int)(n * multi); + if (n > 0) { + n = lovar(n); + n = MIN(rpeasants(u->region), n); + + if (n > 0) { + deathcounts(u->region, n); + rsetpeasants(u->region, rpeasants(u->region) - n); + ADDMSG(&u->region->msgs, msg_message("eatpeasants", "unit amount", u, n)); + } + } + if (horse > 0) { + set_item(u, I_HORSE, 0); + ADDMSG(&u->region->msgs, msg_message("eathorse", "unit amount", u, horse)); + } +} + +static void +absorbed_by_monster(unit * u) +{ + int n; + + switch (old_race(u->race)) { + default: + n = rng_int()%(u->number/20+1); + } + + if(n > 0) { + n = lovar(n); + n = MIN(rpeasants(u->region), n); + if (n > 0){ + rsetpeasants(u->region, rpeasants(u->region) - n); + scale_number(u, u->number + n); + ADDMSG(&u->region->msgs, msg_message("absorbpeasants", + "unit race amount", u, u->race, n)); + } + } +} + +static int +scareaway(region * r, int anzahl) +{ + int n, p, diff = 0, emigrants[MAXDIRECTIONS]; + direction_t d; + + anzahl = MIN(MAX(1, anzahl),rpeasants(r)); + + /* Wandern am Ende der Woche (normal) oder wegen Monster. Die + * Wanderung wird erst am Ende von demographics () ausgefuehrt. + * emigrants[] ist local, weil r->newpeasants durch die Monster + * vielleicht schon hochgezaehlt worden ist. */ + + for (d = 0; d != MAXDIRECTIONS; d++) + emigrants[d] = 0; + + p = rpeasants(r); + assert(p >= 0 && anzahl >= 0); + for (n = MIN(p, anzahl); n; n--) { + direction_t dir = (direction_t)(rng_int() % MAXDIRECTIONS); + region * rc = rconnect(r, dir); + + if (rc && fval(rc->terrain, LAND_REGION)) { + ++diff; + rc->land->newpeasants++; + emigrants[dir]++; + } + } + rsetpeasants(r, p-diff); + assert(p >= diff); + return diff; +} + +static void +scared_by_monster(unit * u) +{ + int n; + + switch (old_race(u->race)) { + case RC_FIREDRAGON: + n = rng_int()%160 * u->number; + break; + case RC_DRAGON: + n = rng_int()%400 * u->number; + break; + case RC_WYRM: + n = rng_int()%1000 * u->number; + break; + default: + n = rng_int()%(u->number/4+1); + } + + if(n > 0) { + n = lovar(n); + n = MIN(rpeasants(u->region), n); + if(n > 0) { + n = scareaway(u->region, n); + if(n > 0) { + ADDMSG(&u->region->msgs, msg_message("fleescared", + "amount unit", n, u)); + } + } + } +} + +void +monster_kills_peasants(unit * u) +{ + if (!monster_is_waiting(u)) { + if (u->race->flags & RCF_SCAREPEASANTS) { + scared_by_monster(u); + } + if (u->race->flags & RCF_KILLPEASANTS) { + eaten_by_monster(u); + } + if (u->race->flags & RCF_ABSORBPEASANTS) { + absorbed_by_monster(u); + } + } +} diff --git a/src/gamecode/monster.h b/src/gamecode/monster.h index 5431d580a..54e5fec10 100644 --- a/src/gamecode/monster.h +++ b/src/gamecode/monster.h @@ -1,31 +1,31 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_GC_MONSTER -#define H_GC_MONSTER -#ifdef __cplusplus -extern "C" { -#endif - -void monster_kills_peasants(struct unit * u); -boolean monster_is_waiting(const struct unit * u); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_GC_MONSTER +#define H_GC_MONSTER +#ifdef __cplusplus +extern "C" { +#endif + +void monster_kills_peasants(struct unit * u); +boolean monster_is_waiting(const struct unit * u); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/randenc.c b/src/gamecode/randenc.c index 1cd766a66..a80eddea0 100644 --- a/src/gamecode/randenc.c +++ b/src/gamecode/randenc.c @@ -1,1272 +1,1272 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "randenc.h" - -#include "economy.h" -#include "monster.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* attributes includes */ -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include - -#include -extern struct attrib_type at_unitdissolve; -extern struct attrib_type at_orcification; - -/* In a->data.ca[1] steht der Prozentsatz mit dem sich die Einheit - * auflöst, in a->data.ca[0] kann angegeben werden, wohin die Personen - * verschwinden. Passiert bereits in der ersten Runde! */ -static void -dissolve_units(void) -{ - region *r; - unit *u; - int n; - int i; - - for (r=regions;r;r=r->next) { - for (u=r->units;u;u=u->next) { - attrib * a = a_find(u->attribs, &at_unitdissolve); - if (a) { - message * msg; - - if (u->age == 0 && a->data.ca[1] < 100) continue; - - /* TODO: Durch einzelne Berechnung ersetzen */ - if (a->data.ca[1] == 100) { - n = u->number; - } else { - n = 0; - for (i=0;inumber;i++) { - if (rng_int()%100 < a->data.ca[1]) n++; - } - } - - /* wenn keiner verschwindet, auch keine Meldung */ - if (n == 0) { - continue; - } - - scale_number(u, u->number - n); - - switch(a->data.ca[0]) { - case 1: - rsetpeasants(r, rpeasants(r) + n); - msg = msg_message("dissolve_units_1", "unit region number race", u, r, n, u->race); - break; - case 2: - if (r->land && !fval(r, RF_MALLORN)) { - rsettrees(r, 2, rtrees(r,2) + n); - msg = msg_message("dissolve_units_2", "unit region number race", u, r, n, u->race); - } else { - msg = msg_message("dissolve_units_3", "unit region number race", u, r, n, u->race); - } - break; - default: - if (u->race == new_race[RC_STONEGOLEM] || u->race == new_race[RC_IRONGOLEM]) { - msg = msg_message("dissolve_units_4", "unit region number race", u, r, n, u->race); - } else { - msg = msg_message("dissolve_units_5", "unit region number race", u, r, n, u->race); - } - break; - } - - add_message(&u->faction->msgs, msg); - msg_release(msg); - } - } - } - - remove_empty_units(); -} - -static int -improve_all(faction * f, skill_t sk, int by_weeks) -{ - unit *u; - boolean ret = by_weeks; - - for (u = f->units; u; u = u->nextF) { - if (has_skill(u, sk)) { - int weeks = 0; - for (;weeks!=by_weeks;++weeks) { - learn_skill(u, sk, 1.0); - ret = 0; - } - } - } - - return ret; -} - -void -find_manual(region * r, unit * u) -{ - char zLocation[32]; - char zBook[32]; - skill_t skill = NOSKILL; - message * msg; - - switch (rng_int() % 36) { - case 0: - skill = SK_MAGIC; - break; - case 1: - case 2: - case 3: - case 4: - skill = SK_WEAPONSMITH; - break; - case 5: - case 6: - skill = SK_TACTICS; - break; - case 7: - case 8: - case 9: - case 10: - skill = SK_SHIPBUILDING; - break; - case 11: - case 12: - case 13: - case 14: - skill = SK_SAILING; - break; - case 15: - case 16: - case 17: - skill = SK_HERBALISM; - break; - case 18: - case 19: - skill = SK_ALCHEMY; - break; - case 20: - case 21: - case 22: - case 23: - skill = SK_BUILDING; - break; - case 24: - case 25: - case 26: - case 27: - skill = SK_ARMORER; - break; - case 28: - case 29: - case 30: - case 31: - skill = SK_MINING; - break; - case 32: - case 33: - case 34: - case 35: - skill = SK_ENTERTAINMENT; - break; - } - - snprintf(zLocation, sizeof(zLocation), "manual_location_%d", (int)(rng_int() % 4)); - snprintf(zBook, sizeof(zLocation), "manual_title_%s", skillnames[skill]); - - msg = msg_message("find_manual", "unit location book", u, zLocation, zBook); - r_addmessage(r, u->faction, msg); - msg_release(msg); - - if (improve_all(u->faction, skill, 3) == 3) { - int i; - for (i=0;i!=9;++i) learn_skill(u, skill, 1.0); - } -} - -static void -get_villagers(region * r, unit * u) -{ - unit *newunit; - message * msg = msg_message("encounter_villagers", "unit", u); - const char * name = LOC(u->faction->locale, "villagers"); - - r_addmessage(r, u->faction, msg); - msg_release(msg); - - newunit = create_unit(r, u->faction, rng_int() % 20 + 3, u->faction->race, 0, name, u); - leave(newunit, true); - fset(newunit, UFL_ISNEW|UFL_MOVED); - equip_unit(newunit, get_equipment("random_villagers")); -} - -static void -get_allies(region * r, unit * u) -{ - unit *newunit = NULL; - const char * name; - const char * equip; - int number; - message * msg; - - assert(u->number); - - switch (rterrain(r)) { - case T_PLAIN: - if (!r_isforest(r)) { - if (get_money(u) / u->number < 100 + rng_int() % 200) - return; - name = "random_plain_men"; - equip = "random_plain"; - number = rng_int() % 8 + 2; - break; - } else { - if (eff_skill(u, SK_LONGBOW, r) < 3 - && eff_skill(u, SK_HERBALISM, r) < 2 - && eff_skill(u, SK_MAGIC, r) < 2) { - return; - } - name = "random_forest_men"; - equip = "random_forest"; - number = rng_int() % 6 + 2; - } - break; - - case T_SWAMP: - if (eff_skill(u, SK_MELEE, r) <= 1) { - return; - } - name = "random_swamp_men"; - equip = "random_swamp"; - number = rng_int() % 6 + 2; - break; - - case T_DESERT: - if (eff_skill(u, SK_RIDING, r) <= 2) { - return; - } - name = "random_desert_men"; - equip = "random_desert"; - number = rng_int() % 12 + 2; - break; - - case T_HIGHLAND: - if (eff_skill(u, SK_MELEE, r) <= 1) { - return; - } - name = "random_highland_men"; - equip = "random_highland"; - number = rng_int() % 8 + 2; - break; - - case T_MOUNTAIN: - if (eff_skill(u, SK_MELEE, r) <= 1 || eff_skill(u, SK_TRADE, r) <= 2) { - return; - } - name = "random_mountain_men"; - equip = "random_mountain"; - number = rng_int() % 6 + 2; - break; - - case T_GLACIER: - if (eff_skill(u, SK_MELEE, r) <= 1 || eff_skill(u, SK_TRADE, r) <= 1) { - return; - } - name = "random_glacier_men"; - equip = "random_glacier"; - number = rng_int() % 4 + 2; - break; - - default: - return; - } - - newunit = create_unit(r, u->faction, number, u->faction->race, 0, LOC(u->faction->locale, name), u); - equip_unit(newunit, get_equipment(equip)); - - u_setfaction(newunit, u->faction); - set_racename(&newunit->attribs, get_racename(u->attribs)); - if (u->race->flags & RCF_SHAPESHIFT) { - newunit->irace = u->irace; - } - if (fval(u, UFL_ANON_FACTION)) fset(newunit, UFL_ANON_FACTION); - fset(newunit, UFL_ISNEW); - - msg = msg_message("encounter_allies", "unit name", u, name); - r_addmessage(r, u->faction, msg); - msg_release(msg); -} - -static void -encounter(region * r, unit * u) -{ - if (!fval(r, RF_ENCOUNTER)) return; - freset(r, RF_ENCOUNTER); - if (rng_int() % 100>=ENCCHANCE) return; - switch (rng_int() % 3) { - case 0: - find_manual(r, u); - break; - case 1: - get_villagers(r, u); - break; - case 2: - get_allies(r, u); - break; - } -} - -void -encounters(void) -{ - region *r; - - for (r = regions; r; r = r->next) { - if (!fval(r->terrain, SEA_REGION) && fval(r, RF_ENCOUNTER)) { - int c = 0; - unit * u; - for (u = r->units; u; u = u->next) { - c += u->number; - } - - if (c > 0) { - int i = 0; - int n = rng_int() % c; - - for (u = r->units; u; u = u->next) { - if (i+u->number>n) break; - i+=u->number; - } - assert(u && u->number); - encounter(r, u); - } - } - } -} - -static const terrain_type * -chaosterrain(void) -{ - static const terrain_type ** types; - static int numtypes; - - if (numtypes==0) { - const terrain_type * terrain; - for (terrain=terrains();terrain!=NULL;terrain=terrain->next) { - if (fval(terrain, LAND_REGION) && terrain->herbs) { - ++numtypes; - } - } - types = malloc(sizeof(terrain_type)*numtypes); - numtypes = 0; - for (terrain=terrains();terrain!=NULL;terrain=terrain->next) { - if (fval(terrain, LAND_REGION) && terrain->herbs) { - types[numtypes++] = terrain; - } - } - } - return types[rng_int() % numtypes]; -} - - -static unit * -random_unit(const region * r) -{ - int c = 0; - int n; - unit *u; - - for (u = r->units; u; u = u->next) { - if (u->race != new_race[RC_SPELL]) { - c += u->number; - } - } - - if (c == 0) { - return NULL; - } - n = rng_int() % c; - c = 0; - u = r->units; - - while (u && c < n) { - if (u->race != new_race[RC_SPELL]) { - c += u->number; - } - u = u->next; - } - - return u; -} - -void -chaos(region * r) -{ - if (rng_int() % 100 < 8) { - switch (rng_int() % 3) { - case 0: /* Untote */ - if (!fval(r->terrain, SEA_REGION)) { - unit * u = random_unit(r); - if (u && playerrace(u->race)) { - ADDMSG(&u->faction->msgs, msg_message("chaos_disease", "unit", u)); - u_setfaction(u, get_monsters()); - u->race = new_race[RC_GHOUL]; - } - } - break; - case 1: /* Drachen */ - if (random_unit(r)) { - int mfac = 0; - unit * u; - switch (rng_int() % 3) { - case 0: - mfac = 100; - u = createunit(r, get_monsters(), rng_int() % 8 + 1, new_race[RC_FIREDRAGON]); - break; - case 1: - mfac = 500; - u = createunit(r, get_monsters(), rng_int() % 4 + 1, new_race[RC_DRAGON]); - break; - default: - mfac = 1000; - u = createunit(r, get_monsters(), rng_int() % 2 + 1, new_race[RC_WYRM]); - break; - } - if (mfac) set_money(u, u->number * (rng_int() % mfac)); - fset(u, UFL_ISNEW|UFL_MOVED); - } - case 2: /* Terrainveränderung */ - if (!fval(r->terrain, FORBIDDEN_REGION)) { - if (!fval(r->terrain, SEA_REGION)) { - direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * rn = rconnect(r, dir); - if (rn && fval(rn->terrain, SEA_REGION)) break; - } - if (dir!=MAXDIRECTIONS) { - ship * sh = r->ships; - unit ** up; - - while (sh) { - ship * nsh = sh->next; - damage_ship(sh, 0.50); - if (sh->damage >= sh->size * DAMAGE_SCALE) { - remove_ship(&sh->region->ships, sh); - } - sh = nsh; - } - - for (up = &r->units; *up;) { - unit * u = *up; - if (u->race != new_race[RC_SPELL] && u->ship == 0 && !canfly(u)) { - ADDMSG(&u->faction->msgs, msg_message("tidalwave_kill", "region unit", r, u)); - remove_unit(up, u); - } - if (*up==u) up = &u->next; - } - ADDMSG(&r->msgs, msg_message("tidalwave", "region", r)); - - while (r->buildings) { - remove_building(&r->buildings, r->buildings); - } - terraform_region(r, newterrain(T_OCEAN)); - } - } else { - direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * rn = rconnect(r, dir); - if (rn && fval(rn->terrain, SEA_REGION)) break; - } - if (dir!=MAXDIRECTIONS) { - terraform_region(r, chaosterrain()); - } - } - } - } - } -} - - -static int -nb_armor(const unit *u, int index) -{ - const item * itm; - int av = 0; - int s = 0, a = 0; - - if (!(u->race->battle_flags & BF_EQUIPMENT)) return 0; - - /* Normale Rüstung */ - - for (itm=u->items;itm;itm=itm->next) { - const armor_type * atype = itm->type->rtype->atype; - if (atype!=NULL) { - int * schutz = &a; - if (atype->flags & ATF_SHIELD) schutz = &s; - if (*schutz <= index) { - *schutz += itm->number; - if (*schutz > index) { - av += atype->prot; - } - } - } - } - return av; -} - -static int -damage_unit(unit *u, const char *dam, boolean physical, boolean magic) -{ - int *hp = malloc(u->number * sizeof(int)); - int h; - int i, dead = 0, hp_rem = 0, heiltrank; - double magres = magic_resistance(u); - - assert(u->number); - if (fval(u->race, RCF_ILLUSIONARY) || u->race == new_race[RC_SPELL]) { - return 0; - } - - h = u->hp/u->number; - /* HP verteilen */ - for (i=0; inumber; i++) hp[i] = h; - h = u->hp - (u->number * h); - for (i=0; inumber; i++) { - int damage = dice_rand(dam); - if (magic) damage = (int)(damage * (1.0 - magres)); - if (physical) damage -= nb_armor(u, i); - hp[i] -= damage; - } - - /* Auswirkungen */ - for (i=0; inumber; i++) { - if (hp[i] <= 0){ - heiltrank = 0; - - /* Sieben Leben */ - if (old_race(u->race) == RC_CAT && (chance(1.0 / 7))) { - hp[i] = u->hp/u->number; - hp_rem += hp[i]; - continue; - } - - /* Heiltrank */ - if (oldpotiontype[P_HEAL]) { - if (get_effect(u, oldpotiontype[P_HEAL]) > 0) { - change_effect(u, oldpotiontype[P_HEAL], -1); - heiltrank = 1; - } else if (i_get(u->items, oldpotiontype[P_HEAL]->itype) > 0) { - i_change(&u->items, oldpotiontype[P_HEAL]->itype, -1); - change_effect(u, oldpotiontype[P_HEAL], 3); - heiltrank = 1; - } - if (heiltrank && (chance(0.50))) { - hp[i] = u->hp/u->number; - hp_rem += hp[i]; - continue; - } - } - dead++; - } else { - hp_rem += hp[i]; - } - } - - scale_number(u, u->number - dead); - u->hp = hp_rem; - - free(hp); - - return dead; -} - -void -drown(region *r) -{ - if (fval(r->terrain, SEA_REGION)) { - unit ** up = up=&r->units; - while (*up) { - unit *u = *up; - int amphibian_level = 0; - if (u->ship || u->race == new_race[RC_SPELL] || u->number==0) { - up=&u->next; - continue; - } - - if (amphibian_level) { - int dead = damage_unit(u, "5d1", false, false); - if (dead) { - ADDMSG(&u->faction->msgs, msg_message("drown_amphibian_dead", - "amount unit region", dead, u, r)); - } else { - ADDMSG(&u->faction->msgs, msg_message("drown_amphibian_nodead", - "unit region",u, r)); - } - } else if (!(canswim(u) || canfly(u))) { - scale_number(u, 0); - ADDMSG(&u->faction->msgs, msg_message("drown", "unit region", u, r)); - } - if (*up==u) up=&u->next; - } - remove_empty_units_in_region(r); - } -} - -region * -rrandneighbour(region *r) -{ - direction_t i; - region *rc = NULL; - int rr, c = 0; - - /* Nachsehen, wieviele Regionen in Frage kommen */ - - for (i = 0; i != MAXDIRECTIONS; i++) { - c++; - } - /* Zufällig eine auswählen */ - - rr = rng_int() % c; - - /* Durchzählen */ - - c = -1; - for (i = 0; i != MAXDIRECTIONS; i++) { - rc = rconnect(r, i); - c++; - if (c == rr) break; - } - assert(i!=MAXDIRECTIONS); - return rc; -} - -static void -volcano_destruction(region * volcano, region * r, region * rn, const char * damage) -{ - attrib * a; - unit ** up; - int percent = 25, time = 6 + rng_int()%12; - - rsettrees(r, 2, 0); - rsettrees(r, 1, 0); - rsettrees(r, 0, 0); - - a = a_find(r->attribs, &at_reduceproduction); - if (!a) { - a = make_reduceproduction(percent, time); - } else { - /* Produktion vierteln ... */ - a->data.sa[0] = (short)percent; - /* Für 6-17 Runden */ - a->data.sa[1] = (short)(a->data.sa[1] + time); - } - - /* Personen bekommen 4W10 Punkte Schaden. */ - - for (up=&r->units; *up;) { - unit * u = *up; - if (u->number) { - int dead = damage_unit(u, damage, true, false); - if (dead) { - ADDMSG(&u->faction->msgs, msg_message("volcano_dead", - "unit region dead", u, volcano, dead)); - } - if (r==volcano && !fval(u->faction, FFL_SELECT)) { - fset(u->faction, FFL_SELECT); - if (rn) { - ADDMSG(&u->faction->msgs, msg_message("volcanooutbreak", - "regionv regionn", r, rn)); - } else { - ADDMSG(&u->faction->msgs, msg_message("volcanooutbreaknn", - "region", r)); - } - } - } - if (u==*up) up=&u->next; - } - - remove_empty_units_in_region(r); -} - -void -volcano_outbreak(region *r) -{ - region *rn; - unit *u; - faction *f; - - for (f=NULL,u=r->units; u; u=u->next) { - if (f!=u->faction) { - f = u->faction; - freset(f, FFL_SELECT); - } - } - - /* Zufällige Nachbarregion verwüsten */ - rn = rrandneighbour(r); - - volcano_destruction(r, r, rn, "4d10"); - if (rn) { - volcano_destruction(r, rn, NULL, "3d10"); - } -} - -static void -melt_iceberg(region *r) -{ - attrib *a; - unit *u; - - for (u=r->units; u; u=u->next) freset(u->faction, FFL_SELECT); - for (u=r->units; u; u=u->next) if (!fval(u->faction, FFL_SELECT)) { - fset(u->faction, FFL_SELECT); - ADDMSG(&u->faction->msgs, msg_message("iceberg_melt", "region", r)); - } - - /* driftrichtung löschen */ - a = a_find(r->attribs, &at_iceberg); - if (a) a_remove(&r->attribs, a); - - /* Gebäude löschen */ - while (r->buildings) { - remove_building(&r->buildings, r->buildings); - } - - /* in Ozean wandeln */ - terraform_region(r, newterrain(T_OCEAN)); - - /* Einheiten, die nicht schwimmen können oder in Schiffen sind, - * ertrinken */ - drown(r); -} - -static void -move_iceberg(region *r) -{ - attrib *a; - direction_t dir; - region *rc; - - a = a_find(r->attribs, &at_iceberg); - if (!a) { - dir = (direction_t)(rng_int()%MAXDIRECTIONS); - a = a_add(&r->attribs, make_iceberg(dir)); - } else { - if (rng_int()%100 < 20) { - dir = (direction_t)(rng_int()%MAXDIRECTIONS); - a->data.i = dir; - } else { - dir = (direction_t)a->data.i; - } - } - - rc = rconnect(r, dir); - - if (rc && !fval(rc->terrain, ARCTIC_REGION)) { - if (fval(rc->terrain, SEA_REGION)) { /* Eisberg treibt */ - ship *sh, *shn; - unit *u; - int x, y; - - - for (u=r->units; u; u=u->next) freset(u->faction, FFL_SELECT); - for (u=r->units; u; u=u->next) if (!fval(u->faction, FFL_SELECT)) { - fset(u->faction, FFL_SELECT); - ADDMSG(&u->faction->msgs, msg_message("iceberg_drift", - "region dir", r, dir)); - } - - x = r->x; - y = r->y; - - runhash(r); - runhash(rc); - r->x = rc->x; - r->y = rc->y; - rc->x = x; - rc->y = y; - rhash(rc); - rhash(r); - - /* rc ist der Ozean (Ex-Eisberg), r der Eisberg (Ex-Ozean) */ - - /* Schiffe aus dem Zielozean werden in den Eisberg transferiert - * und nehmen Schaden. */ - - for (sh = r->ships; sh; sh=sh->next) freset(sh, SF_SELECT); - - for (sh = r->ships; sh; sh = sh->next) { - /* Meldung an Kapitän */ - damage_ship(sh, 0.10); - fset(sh, SF_SELECT); - } - - /* Personen, Schiffe und Gebäude verschieben */ - while (rc->buildings) { - rc->buildings->region = r; - translist(&rc->buildings, &r->buildings, rc->buildings); - } - while (rc->ships) { - fset(rc->ships, SF_SELECT); - damage_ship(rc->ships, 0.10); - move_ship(rc->ships, rc, r, NULL); - } - while (rc->units) { - building * b = rc->units->building; - u = rc->units; - move_unit(rc->units, r, NULL); - u->building = b; /* move_unit macht ein leave() */ - } - - /* Beschädigte Schiffe können sinken */ - - for (sh = r->ships; sh;) { - shn = sh->next; - if (fval(sh, SF_SELECT)) { - u = captain(sh); - if (sh->damage>=sh->size * DAMAGE_SCALE) { - if (u!=NULL) { - ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg_des", - "ship", sh)); - } - remove_ship(&sh->region->ships, sh); - } else if (u!=NULL) { - ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg", - "ship", sh)); - } - } - sh = shn; - } - - } else if (rng_int()%100 < 20) { /* Eisberg bleibt als Gletscher liegen */ - unit *u; - - rsetterrain(r, T_GLACIER); - a_remove(&r->attribs, a); - - for (u=r->units; u; u=u->next) freset(u->faction, FFL_SELECT); - for (u=r->units; u; u=u->next) if (!fval(u->faction, FFL_SELECT)) { - fset(u->faction, FFL_SELECT); - ADDMSG(&u->faction->msgs, msg_message("iceberg_land", "region", r)); - } - } - } -} - -static void -move_icebergs(void) -{ - region *r; - - for (r=regions; r; r=r->next) { - if (r->terrain == newterrain(T_ICEBERG) && !fval(r, RF_SELECT)) { - int select = rng_int() % 10; - if (select < 4) { - /* 4% chance */ - fset(r, RF_SELECT); - melt_iceberg(r); - } else if (select<64) { - /* 60% chance */ - fset(r, RF_SELECT); - move_iceberg(r); - } - } - } -} - -void -create_icebergs(void) -{ - region *r; - - for (r=regions; r; r=r->next) { - if (r->terrain == newterrain(T_ICEBERG_SLEEP) && chance(0.05)) { - boolean has_ocean_neighbour = false; - direction_t dir; - region *rc; - unit *u; - - freset(r, RF_SELECT); - for (dir=0; dir < MAXDIRECTIONS; dir++) { - rc = rconnect(r, dir); - if (rc && fval(rc->terrain, SEA_REGION)) { - has_ocean_neighbour = true; - break; - } - } - if (!has_ocean_neighbour) continue; - - rsetterrain(r, T_ICEBERG); - - fset(r, RF_SELECT); - move_iceberg(r); - - for (u=r->units; u; u=u->next) { - freset(u->faction, FFL_SELECT); - } - for (u=r->units; u; u=u->next) { - if (!fval(u->faction, FFL_SELECT)) { - fset(u->faction, FFL_SELECT); - ADDMSG(&u->faction->msgs, msg_message("iceberg_create", "region", r)); - } - } - } - } -} - -static void -godcurse(void) -{ - region *r; - - for (r=regions; r; r=r->next) { - if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { - unit * u; - for(u=r->units; u; u=u->next) { - skill * sv = u->skills; - while (sv!=u->skills+u->skill_size) { - int weeks = 1+rng_int()%3; - reduce_skill(u, sv, weeks); - ++sv; - } - } - if (fval(r->terrain, SEA_REGION)) { - ship *sh; - for (sh = r->ships; sh;) { - ship *shn = sh->next; - damage_ship(sh, 0.10); - if (sh->damage>=sh->size * DAMAGE_SCALE) { - unit * u = shipowner(sh); - if (u) ADDMSG(&u->faction->msgs, - msg_message("godcurse_destroy_ship", "ship", sh)); - remove_ship(&sh->region->ships, sh); - } - sh = shn; - } - } - } - } - -} - -/** handles the "orcish" curse that makes units grow like old orks - * This would probably be better handled in an age-function for the curse, - * but it's now being called by randomevents() - */ -static void -orc_growth(void) -{ - region * r; - for (r = regions; r; r = r->next) { - unit *u; - for (u = r->units; u; u = u->next) { - static boolean init = false; - static const curse_type *ct_orcish = 0; - curse *c = 0; - if (!init) { - init = true; - ct_orcish = ct_find("orcish"); - } - if (ct_orcish) c = get_curse(u->attribs, ct_orcish); - - if (c && !has_skill(u, SK_MAGIC) && !has_skill(u, SK_ALCHEMY) && !fval(u, UFL_HERO)) { - int n; - int increase = 0; - int num = get_cursedmen(u, c); - double prob = curse_geteffect(c); - - for (n = (num - get_item(u, I_CHASTITY_BELT)); n > 0; n--) { - if (chance(prob)) { - ++increase; - } - } - if (increase) { - unit * u2 = create_unit(r, u->faction, increase, u->race, 0, NULL, u); - transfermen(u2, u, u2->number); - - ADDMSG(&u->faction->msgs, msg_message("orcgrowth", - "unit amount race", u, increase, u->race)); - } - } - } - } -} - -/** Talente von Dämonen verschieben sich. - */ -static void -demon_skillchanges(void) -{ - region * r; - - for (r = regions; r; r = r->next) { - unit * u; - for (u = r->units; u; u = u->next) { - if (u->race == new_race[RC_DAEMON]) { - skill * sv = u->skills; - int upchance = 15; - int downchance = 10; - - if (fval(u, UFL_HUNGER)) { - /* hungry demons only go down, never up in skill */ - static int rule_hunger = -1; - if (rule_hunger<0) { - rule_hunger = get_param_int(global.parameters, "hunger.demon.skill", 0); - } - if (rule_hunger) { - upchance = 0; - downchance = 15; - } - } - - while (sv!=u->skills+u->skill_size) { - int roll = rng_int() % 100; - if (sv->level>0 && roll < upchance+downchance) { - int weeks = 1+rng_int()%3; - if (roll < downchance) { - reduce_skill(u, sv, weeks); - if (sv->level<1) { - /* demons should never forget below 1 */ - set_level(u, sv->id, 1); - } - } else { - while (weeks--) learn_skill(u, sv->id, 1.0); - } - if (sv->old>sv->level) { - if (verbosity>=3) { - log_printf("%s dropped from %u to %u:%u in %s\n", - unitname(u), sv->old, sv->level, sv->weeks, skillname(sv->id, NULL)); - } - } - } - ++sv; - } - } - } - } -} - -/** Eisberge entstehen und bewegen sich. - * Einheiten die im Wasser landen, ertrinken. - */ -static void -icebergs(void) -{ - region * r; - create_icebergs(); - move_icebergs(); - for (r=regions; r; r=r->next) { - drown(r); - } -} - -#ifdef HERBS_ROT -static void -rotting_herbs(void) -{ - static int rule_rot = -1; - region * r; - - if (rule_rot<0) { - rule_rot = get_param_int(global.parameters, "rules.economy.herbrot", HERBROTCHANCE); - } - if (rule_rot==0) return; - - for (r = regions; r; r = r->next) { - unit * u; - for (u = r->units; u; u=u->next) { - item **itmp = &u->items, *hbag = *i_find(itmp, olditemtype[I_SACK_OF_CONSERVATION]); - int rot_chance = rule_rot; - - if (hbag) rot_chance = (rot_chance*2)/5; - while (*itmp) { - item * itm = *itmp; - int n = itm->number; - double k = n*rot_chance/100.0; - if (fval(itm->type, ITF_HERB)) { - double nv = normalvariate(k, k/4); - int inv = (int)nv; - int delta = MIN(n, inv); - if (i_change(itmp, itm->type, -delta)==NULL) { - continue; - } - } - itmp = &itm->next; - } - } - } -} -#endif - -void -randomevents(void) -{ - region *r; - - icebergs(); - godcurse(); - orc_growth(); - demon_skillchanges(); - - /* Orkifizierte Regionen mutieren und mutieren zurück */ - - for (r = regions; r; r = r->next) { - if (fval(r, RF_ORCIFIED)) { - direction_t dir; - double probability = 0.0; - for (dir = 0; dir < MAXDIRECTIONS; dir++) { - region *rc = rconnect(r, dir); - if (rc && rpeasants(rc) > 0 && !fval(rc, RF_ORCIFIED)) probability += 0.02; - } - if (chance(probability)) { - ADDMSG(&r->msgs, msg_message("deorcified", "region", r)); - freset(r, RF_ORCIFIED); - } - } else { - attrib *a = a_find(r->attribs, &at_orcification); - if (a!=NULL) { - double probability = 0.0; - if (rpeasants(r) <= 0) continue; - probability = a->data.i/(double)rpeasants(r); - if (chance(probability)) { - fset(r, RF_ORCIFIED); - a_remove(&r->attribs, a); - ADDMSG(&r->msgs, msg_message("orcified", "region", r)); - } else { - a->data.i -= MAX(10,a->data.i/10); - if (a->data.i <= 0) a_remove(&r->attribs, a); - } - } - } - } - - /* Vulkane qualmen, brechen aus ... */ - for (r = regions; r; r = r->next) { - if (r->terrain == newterrain(T_VOLCANO_SMOKING)) { - if (a_find(r->attribs, &at_reduceproduction)) { - ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r)); - rsetterrain(r, T_VOLCANO); - } else { - if (rng_int()%100 < 12) { - ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r)); - rsetterrain(r, T_VOLCANO); - } else if (r->age>20 && rng_int()%100 < 8) { - volcano_outbreak(r); - } - } - } else if (r->terrain == newterrain(T_VOLCANO)) { - if (rng_int()%100 < 4) { - ADDMSG(&r->msgs, msg_message("volcanostartsmoke", "region", r)); - rsetterrain(r, T_VOLCANO_SMOKING); - } - } - } - - /* Monumente zerfallen, Schiffe verfaulen */ - - for (r = regions; r; r = r->next) { - building ** blist = &r->buildings; - while (*blist) { - building * b = *blist; - if (fval(b->type, BTF_DECAY) && !building_owner(b)) { - b->size -= MAX(1, (b->size * 20) / 100); - if (b->size == 0) { - remove_building(blist, r->buildings); - } - } - if (*blist==b) blist=&b->next; - } - } - - /* monster-einheiten desertieren */ - for (r = regions; r; r=r->next) { - unit *u; - - for (u=r->units; u; u=u->next) { - if (u->faction && !is_monsters(u->faction) - && (u->race->flags & RCF_DESERT)) { - if (fval(u, UFL_ISNEW)) continue; - if (rng_int()%100 < 5) { - ADDMSG(&u->faction->msgs, msg_message("desertion", - "unit region", u, r)); - u_setfaction(u, get_monsters()); - } - } - } - } - - /* Chaos */ - for (r = regions; r; r = r->next) { - int i; - - if (fval(r, RF_CHAOTIC)) { - chaos(r); - } - i = chaoscount(r); - if (i) { - chaoscounts(r, -(int) (i * ((double) (rng_int() % 10)) / 100.0)); - } - } -#ifdef HERBS_ROT - rotting_herbs(); -#endif - - dissolve_units(); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "randenc.h" + +#include "economy.h" +#include "monster.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* attributes includes */ +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +#include +extern struct attrib_type at_unitdissolve; +extern struct attrib_type at_orcification; + +/* In a->data.ca[1] steht der Prozentsatz mit dem sich die Einheit + * auflöst, in a->data.ca[0] kann angegeben werden, wohin die Personen + * verschwinden. Passiert bereits in der ersten Runde! */ +static void +dissolve_units(void) +{ + region *r; + unit *u; + int n; + int i; + + for (r=regions;r;r=r->next) { + for (u=r->units;u;u=u->next) { + attrib * a = a_find(u->attribs, &at_unitdissolve); + if (a) { + message * msg; + + if (u->age == 0 && a->data.ca[1] < 100) continue; + + /* TODO: Durch einzelne Berechnung ersetzen */ + if (a->data.ca[1] == 100) { + n = u->number; + } else { + n = 0; + for (i=0;inumber;i++) { + if (rng_int()%100 < a->data.ca[1]) n++; + } + } + + /* wenn keiner verschwindet, auch keine Meldung */ + if (n == 0) { + continue; + } + + scale_number(u, u->number - n); + + switch(a->data.ca[0]) { + case 1: + rsetpeasants(r, rpeasants(r) + n); + msg = msg_message("dissolve_units_1", "unit region number race", u, r, n, u->race); + break; + case 2: + if (r->land && !fval(r, RF_MALLORN)) { + rsettrees(r, 2, rtrees(r,2) + n); + msg = msg_message("dissolve_units_2", "unit region number race", u, r, n, u->race); + } else { + msg = msg_message("dissolve_units_3", "unit region number race", u, r, n, u->race); + } + break; + default: + if (u->race == new_race[RC_STONEGOLEM] || u->race == new_race[RC_IRONGOLEM]) { + msg = msg_message("dissolve_units_4", "unit region number race", u, r, n, u->race); + } else { + msg = msg_message("dissolve_units_5", "unit region number race", u, r, n, u->race); + } + break; + } + + add_message(&u->faction->msgs, msg); + msg_release(msg); + } + } + } + + remove_empty_units(); +} + +static int +improve_all(faction * f, skill_t sk, int by_weeks) +{ + unit *u; + boolean ret = by_weeks; + + for (u = f->units; u; u = u->nextF) { + if (has_skill(u, sk)) { + int weeks = 0; + for (;weeks!=by_weeks;++weeks) { + learn_skill(u, sk, 1.0); + ret = 0; + } + } + } + + return ret; +} + +void +find_manual(region * r, unit * u) +{ + char zLocation[32]; + char zBook[32]; + skill_t skill = NOSKILL; + message * msg; + + switch (rng_int() % 36) { + case 0: + skill = SK_MAGIC; + break; + case 1: + case 2: + case 3: + case 4: + skill = SK_WEAPONSMITH; + break; + case 5: + case 6: + skill = SK_TACTICS; + break; + case 7: + case 8: + case 9: + case 10: + skill = SK_SHIPBUILDING; + break; + case 11: + case 12: + case 13: + case 14: + skill = SK_SAILING; + break; + case 15: + case 16: + case 17: + skill = SK_HERBALISM; + break; + case 18: + case 19: + skill = SK_ALCHEMY; + break; + case 20: + case 21: + case 22: + case 23: + skill = SK_BUILDING; + break; + case 24: + case 25: + case 26: + case 27: + skill = SK_ARMORER; + break; + case 28: + case 29: + case 30: + case 31: + skill = SK_MINING; + break; + case 32: + case 33: + case 34: + case 35: + skill = SK_ENTERTAINMENT; + break; + } + + snprintf(zLocation, sizeof(zLocation), "manual_location_%d", (int)(rng_int() % 4)); + snprintf(zBook, sizeof(zLocation), "manual_title_%s", skillnames[skill]); + + msg = msg_message("find_manual", "unit location book", u, zLocation, zBook); + r_addmessage(r, u->faction, msg); + msg_release(msg); + + if (improve_all(u->faction, skill, 3) == 3) { + int i; + for (i=0;i!=9;++i) learn_skill(u, skill, 1.0); + } +} + +static void +get_villagers(region * r, unit * u) +{ + unit *newunit; + message * msg = msg_message("encounter_villagers", "unit", u); + const char * name = LOC(u->faction->locale, "villagers"); + + r_addmessage(r, u->faction, msg); + msg_release(msg); + + newunit = create_unit(r, u->faction, rng_int() % 20 + 3, u->faction->race, 0, name, u); + leave(newunit, true); + fset(newunit, UFL_ISNEW|UFL_MOVED); + equip_unit(newunit, get_equipment("random_villagers")); +} + +static void +get_allies(region * r, unit * u) +{ + unit *newunit = NULL; + const char * name; + const char * equip; + int number; + message * msg; + + assert(u->number); + + switch (rterrain(r)) { + case T_PLAIN: + if (!r_isforest(r)) { + if (get_money(u) / u->number < 100 + rng_int() % 200) + return; + name = "random_plain_men"; + equip = "random_plain"; + number = rng_int() % 8 + 2; + break; + } else { + if (eff_skill(u, SK_LONGBOW, r) < 3 + && eff_skill(u, SK_HERBALISM, r) < 2 + && eff_skill(u, SK_MAGIC, r) < 2) { + return; + } + name = "random_forest_men"; + equip = "random_forest"; + number = rng_int() % 6 + 2; + } + break; + + case T_SWAMP: + if (eff_skill(u, SK_MELEE, r) <= 1) { + return; + } + name = "random_swamp_men"; + equip = "random_swamp"; + number = rng_int() % 6 + 2; + break; + + case T_DESERT: + if (eff_skill(u, SK_RIDING, r) <= 2) { + return; + } + name = "random_desert_men"; + equip = "random_desert"; + number = rng_int() % 12 + 2; + break; + + case T_HIGHLAND: + if (eff_skill(u, SK_MELEE, r) <= 1) { + return; + } + name = "random_highland_men"; + equip = "random_highland"; + number = rng_int() % 8 + 2; + break; + + case T_MOUNTAIN: + if (eff_skill(u, SK_MELEE, r) <= 1 || eff_skill(u, SK_TRADE, r) <= 2) { + return; + } + name = "random_mountain_men"; + equip = "random_mountain"; + number = rng_int() % 6 + 2; + break; + + case T_GLACIER: + if (eff_skill(u, SK_MELEE, r) <= 1 || eff_skill(u, SK_TRADE, r) <= 1) { + return; + } + name = "random_glacier_men"; + equip = "random_glacier"; + number = rng_int() % 4 + 2; + break; + + default: + return; + } + + newunit = create_unit(r, u->faction, number, u->faction->race, 0, LOC(u->faction->locale, name), u); + equip_unit(newunit, get_equipment(equip)); + + u_setfaction(newunit, u->faction); + set_racename(&newunit->attribs, get_racename(u->attribs)); + if (u->race->flags & RCF_SHAPESHIFT) { + newunit->irace = u->irace; + } + if (fval(u, UFL_ANON_FACTION)) fset(newunit, UFL_ANON_FACTION); + fset(newunit, UFL_ISNEW); + + msg = msg_message("encounter_allies", "unit name", u, name); + r_addmessage(r, u->faction, msg); + msg_release(msg); +} + +static void +encounter(region * r, unit * u) +{ + if (!fval(r, RF_ENCOUNTER)) return; + freset(r, RF_ENCOUNTER); + if (rng_int() % 100>=ENCCHANCE) return; + switch (rng_int() % 3) { + case 0: + find_manual(r, u); + break; + case 1: + get_villagers(r, u); + break; + case 2: + get_allies(r, u); + break; + } +} + +void +encounters(void) +{ + region *r; + + for (r = regions; r; r = r->next) { + if (!fval(r->terrain, SEA_REGION) && fval(r, RF_ENCOUNTER)) { + int c = 0; + unit * u; + for (u = r->units; u; u = u->next) { + c += u->number; + } + + if (c > 0) { + int i = 0; + int n = rng_int() % c; + + for (u = r->units; u; u = u->next) { + if (i+u->number>n) break; + i+=u->number; + } + assert(u && u->number); + encounter(r, u); + } + } + } +} + +static const terrain_type * +chaosterrain(void) +{ + static const terrain_type ** types; + static int numtypes; + + if (numtypes==0) { + const terrain_type * terrain; + for (terrain=terrains();terrain!=NULL;terrain=terrain->next) { + if (fval(terrain, LAND_REGION) && terrain->herbs) { + ++numtypes; + } + } + types = malloc(sizeof(terrain_type)*numtypes); + numtypes = 0; + for (terrain=terrains();terrain!=NULL;terrain=terrain->next) { + if (fval(terrain, LAND_REGION) && terrain->herbs) { + types[numtypes++] = terrain; + } + } + } + return types[rng_int() % numtypes]; +} + + +static unit * +random_unit(const region * r) +{ + int c = 0; + int n; + unit *u; + + for (u = r->units; u; u = u->next) { + if (u->race != new_race[RC_SPELL]) { + c += u->number; + } + } + + if (c == 0) { + return NULL; + } + n = rng_int() % c; + c = 0; + u = r->units; + + while (u && c < n) { + if (u->race != new_race[RC_SPELL]) { + c += u->number; + } + u = u->next; + } + + return u; +} + +void +chaos(region * r) +{ + if (rng_int() % 100 < 8) { + switch (rng_int() % 3) { + case 0: /* Untote */ + if (!fval(r->terrain, SEA_REGION)) { + unit * u = random_unit(r); + if (u && playerrace(u->race)) { + ADDMSG(&u->faction->msgs, msg_message("chaos_disease", "unit", u)); + u_setfaction(u, get_monsters()); + u->race = new_race[RC_GHOUL]; + } + } + break; + case 1: /* Drachen */ + if (random_unit(r)) { + int mfac = 0; + unit * u; + switch (rng_int() % 3) { + case 0: + mfac = 100; + u = createunit(r, get_monsters(), rng_int() % 8 + 1, new_race[RC_FIREDRAGON]); + break; + case 1: + mfac = 500; + u = createunit(r, get_monsters(), rng_int() % 4 + 1, new_race[RC_DRAGON]); + break; + default: + mfac = 1000; + u = createunit(r, get_monsters(), rng_int() % 2 + 1, new_race[RC_WYRM]); + break; + } + if (mfac) set_money(u, u->number * (rng_int() % mfac)); + fset(u, UFL_ISNEW|UFL_MOVED); + } + case 2: /* Terrainveränderung */ + if (!fval(r->terrain, FORBIDDEN_REGION)) { + if (!fval(r->terrain, SEA_REGION)) { + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * rn = rconnect(r, dir); + if (rn && fval(rn->terrain, SEA_REGION)) break; + } + if (dir!=MAXDIRECTIONS) { + ship * sh = r->ships; + unit ** up; + + while (sh) { + ship * nsh = sh->next; + damage_ship(sh, 0.50); + if (sh->damage >= sh->size * DAMAGE_SCALE) { + remove_ship(&sh->region->ships, sh); + } + sh = nsh; + } + + for (up = &r->units; *up;) { + unit * u = *up; + if (u->race != new_race[RC_SPELL] && u->ship == 0 && !canfly(u)) { + ADDMSG(&u->faction->msgs, msg_message("tidalwave_kill", "region unit", r, u)); + remove_unit(up, u); + } + if (*up==u) up = &u->next; + } + ADDMSG(&r->msgs, msg_message("tidalwave", "region", r)); + + while (r->buildings) { + remove_building(&r->buildings, r->buildings); + } + terraform_region(r, newterrain(T_OCEAN)); + } + } else { + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * rn = rconnect(r, dir); + if (rn && fval(rn->terrain, SEA_REGION)) break; + } + if (dir!=MAXDIRECTIONS) { + terraform_region(r, chaosterrain()); + } + } + } + } + } +} + + +static int +nb_armor(const unit *u, int index) +{ + const item * itm; + int av = 0; + int s = 0, a = 0; + + if (!(u->race->battle_flags & BF_EQUIPMENT)) return 0; + + /* Normale Rüstung */ + + for (itm=u->items;itm;itm=itm->next) { + const armor_type * atype = itm->type->rtype->atype; + if (atype!=NULL) { + int * schutz = &a; + if (atype->flags & ATF_SHIELD) schutz = &s; + if (*schutz <= index) { + *schutz += itm->number; + if (*schutz > index) { + av += atype->prot; + } + } + } + } + return av; +} + +static int +damage_unit(unit *u, const char *dam, boolean physical, boolean magic) +{ + int *hp = malloc(u->number * sizeof(int)); + int h; + int i, dead = 0, hp_rem = 0, heiltrank; + double magres = magic_resistance(u); + + assert(u->number); + if (fval(u->race, RCF_ILLUSIONARY) || u->race == new_race[RC_SPELL]) { + return 0; + } + + h = u->hp/u->number; + /* HP verteilen */ + for (i=0; inumber; i++) hp[i] = h; + h = u->hp - (u->number * h); + for (i=0; inumber; i++) { + int damage = dice_rand(dam); + if (magic) damage = (int)(damage * (1.0 - magres)); + if (physical) damage -= nb_armor(u, i); + hp[i] -= damage; + } + + /* Auswirkungen */ + for (i=0; inumber; i++) { + if (hp[i] <= 0){ + heiltrank = 0; + + /* Sieben Leben */ + if (old_race(u->race) == RC_CAT && (chance(1.0 / 7))) { + hp[i] = u->hp/u->number; + hp_rem += hp[i]; + continue; + } + + /* Heiltrank */ + if (oldpotiontype[P_HEAL]) { + if (get_effect(u, oldpotiontype[P_HEAL]) > 0) { + change_effect(u, oldpotiontype[P_HEAL], -1); + heiltrank = 1; + } else if (i_get(u->items, oldpotiontype[P_HEAL]->itype) > 0) { + i_change(&u->items, oldpotiontype[P_HEAL]->itype, -1); + change_effect(u, oldpotiontype[P_HEAL], 3); + heiltrank = 1; + } + if (heiltrank && (chance(0.50))) { + hp[i] = u->hp/u->number; + hp_rem += hp[i]; + continue; + } + } + dead++; + } else { + hp_rem += hp[i]; + } + } + + scale_number(u, u->number - dead); + u->hp = hp_rem; + + free(hp); + + return dead; +} + +void +drown(region *r) +{ + if (fval(r->terrain, SEA_REGION)) { + unit ** up = up=&r->units; + while (*up) { + unit *u = *up; + int amphibian_level = 0; + if (u->ship || u->race == new_race[RC_SPELL] || u->number==0) { + up=&u->next; + continue; + } + + if (amphibian_level) { + int dead = damage_unit(u, "5d1", false, false); + if (dead) { + ADDMSG(&u->faction->msgs, msg_message("drown_amphibian_dead", + "amount unit region", dead, u, r)); + } else { + ADDMSG(&u->faction->msgs, msg_message("drown_amphibian_nodead", + "unit region",u, r)); + } + } else if (!(canswim(u) || canfly(u))) { + scale_number(u, 0); + ADDMSG(&u->faction->msgs, msg_message("drown", "unit region", u, r)); + } + if (*up==u) up=&u->next; + } + remove_empty_units_in_region(r); + } +} + +region * +rrandneighbour(region *r) +{ + direction_t i; + region *rc = NULL; + int rr, c = 0; + + /* Nachsehen, wieviele Regionen in Frage kommen */ + + for (i = 0; i != MAXDIRECTIONS; i++) { + c++; + } + /* Zufällig eine auswählen */ + + rr = rng_int() % c; + + /* Durchzählen */ + + c = -1; + for (i = 0; i != MAXDIRECTIONS; i++) { + rc = rconnect(r, i); + c++; + if (c == rr) break; + } + assert(i!=MAXDIRECTIONS); + return rc; +} + +static void +volcano_destruction(region * volcano, region * r, region * rn, const char * damage) +{ + attrib * a; + unit ** up; + int percent = 25, time = 6 + rng_int()%12; + + rsettrees(r, 2, 0); + rsettrees(r, 1, 0); + rsettrees(r, 0, 0); + + a = a_find(r->attribs, &at_reduceproduction); + if (!a) { + a = make_reduceproduction(percent, time); + } else { + /* Produktion vierteln ... */ + a->data.sa[0] = (short)percent; + /* Für 6-17 Runden */ + a->data.sa[1] = (short)(a->data.sa[1] + time); + } + + /* Personen bekommen 4W10 Punkte Schaden. */ + + for (up=&r->units; *up;) { + unit * u = *up; + if (u->number) { + int dead = damage_unit(u, damage, true, false); + if (dead) { + ADDMSG(&u->faction->msgs, msg_message("volcano_dead", + "unit region dead", u, volcano, dead)); + } + if (r==volcano && !fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + if (rn) { + ADDMSG(&u->faction->msgs, msg_message("volcanooutbreak", + "regionv regionn", r, rn)); + } else { + ADDMSG(&u->faction->msgs, msg_message("volcanooutbreaknn", + "region", r)); + } + } + } + if (u==*up) up=&u->next; + } + + remove_empty_units_in_region(r); +} + +void +volcano_outbreak(region *r) +{ + region *rn; + unit *u; + faction *f; + + for (f=NULL,u=r->units; u; u=u->next) { + if (f!=u->faction) { + f = u->faction; + freset(f, FFL_SELECT); + } + } + + /* Zufällige Nachbarregion verwüsten */ + rn = rrandneighbour(r); + + volcano_destruction(r, r, rn, "4d10"); + if (rn) { + volcano_destruction(r, rn, NULL, "3d10"); + } +} + +static void +melt_iceberg(region *r) +{ + attrib *a; + unit *u; + + for (u=r->units; u; u=u->next) freset(u->faction, FFL_SELECT); + for (u=r->units; u; u=u->next) if (!fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + ADDMSG(&u->faction->msgs, msg_message("iceberg_melt", "region", r)); + } + + /* driftrichtung löschen */ + a = a_find(r->attribs, &at_iceberg); + if (a) a_remove(&r->attribs, a); + + /* Gebäude löschen */ + while (r->buildings) { + remove_building(&r->buildings, r->buildings); + } + + /* in Ozean wandeln */ + terraform_region(r, newterrain(T_OCEAN)); + + /* Einheiten, die nicht schwimmen können oder in Schiffen sind, + * ertrinken */ + drown(r); +} + +static void +move_iceberg(region *r) +{ + attrib *a; + direction_t dir; + region *rc; + + a = a_find(r->attribs, &at_iceberg); + if (!a) { + dir = (direction_t)(rng_int()%MAXDIRECTIONS); + a = a_add(&r->attribs, make_iceberg(dir)); + } else { + if (rng_int()%100 < 20) { + dir = (direction_t)(rng_int()%MAXDIRECTIONS); + a->data.i = dir; + } else { + dir = (direction_t)a->data.i; + } + } + + rc = rconnect(r, dir); + + if (rc && !fval(rc->terrain, ARCTIC_REGION)) { + if (fval(rc->terrain, SEA_REGION)) { /* Eisberg treibt */ + ship *sh, *shn; + unit *u; + int x, y; + + + for (u=r->units; u; u=u->next) freset(u->faction, FFL_SELECT); + for (u=r->units; u; u=u->next) if (!fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + ADDMSG(&u->faction->msgs, msg_message("iceberg_drift", + "region dir", r, dir)); + } + + x = r->x; + y = r->y; + + runhash(r); + runhash(rc); + r->x = rc->x; + r->y = rc->y; + rc->x = x; + rc->y = y; + rhash(rc); + rhash(r); + + /* rc ist der Ozean (Ex-Eisberg), r der Eisberg (Ex-Ozean) */ + + /* Schiffe aus dem Zielozean werden in den Eisberg transferiert + * und nehmen Schaden. */ + + for (sh = r->ships; sh; sh=sh->next) freset(sh, SF_SELECT); + + for (sh = r->ships; sh; sh = sh->next) { + /* Meldung an Kapitän */ + damage_ship(sh, 0.10); + fset(sh, SF_SELECT); + } + + /* Personen, Schiffe und Gebäude verschieben */ + while (rc->buildings) { + rc->buildings->region = r; + translist(&rc->buildings, &r->buildings, rc->buildings); + } + while (rc->ships) { + fset(rc->ships, SF_SELECT); + damage_ship(rc->ships, 0.10); + move_ship(rc->ships, rc, r, NULL); + } + while (rc->units) { + building * b = rc->units->building; + u = rc->units; + move_unit(rc->units, r, NULL); + u->building = b; /* move_unit macht ein leave() */ + } + + /* Beschädigte Schiffe können sinken */ + + for (sh = r->ships; sh;) { + shn = sh->next; + if (fval(sh, SF_SELECT)) { + u = captain(sh); + if (sh->damage>=sh->size * DAMAGE_SCALE) { + if (u!=NULL) { + ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg_des", + "ship", sh)); + } + remove_ship(&sh->region->ships, sh); + } else if (u!=NULL) { + ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg", + "ship", sh)); + } + } + sh = shn; + } + + } else if (rng_int()%100 < 20) { /* Eisberg bleibt als Gletscher liegen */ + unit *u; + + rsetterrain(r, T_GLACIER); + a_remove(&r->attribs, a); + + for (u=r->units; u; u=u->next) freset(u->faction, FFL_SELECT); + for (u=r->units; u; u=u->next) if (!fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + ADDMSG(&u->faction->msgs, msg_message("iceberg_land", "region", r)); + } + } + } +} + +static void +move_icebergs(void) +{ + region *r; + + for (r=regions; r; r=r->next) { + if (r->terrain == newterrain(T_ICEBERG) && !fval(r, RF_SELECT)) { + int select = rng_int() % 10; + if (select < 4) { + /* 4% chance */ + fset(r, RF_SELECT); + melt_iceberg(r); + } else if (select<64) { + /* 60% chance */ + fset(r, RF_SELECT); + move_iceberg(r); + } + } + } +} + +void +create_icebergs(void) +{ + region *r; + + for (r=regions; r; r=r->next) { + if (r->terrain == newterrain(T_ICEBERG_SLEEP) && chance(0.05)) { + boolean has_ocean_neighbour = false; + direction_t dir; + region *rc; + unit *u; + + freset(r, RF_SELECT); + for (dir=0; dir < MAXDIRECTIONS; dir++) { + rc = rconnect(r, dir); + if (rc && fval(rc->terrain, SEA_REGION)) { + has_ocean_neighbour = true; + break; + } + } + if (!has_ocean_neighbour) continue; + + rsetterrain(r, T_ICEBERG); + + fset(r, RF_SELECT); + move_iceberg(r); + + for (u=r->units; u; u=u->next) { + freset(u->faction, FFL_SELECT); + } + for (u=r->units; u; u=u->next) { + if (!fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + ADDMSG(&u->faction->msgs, msg_message("iceberg_create", "region", r)); + } + } + } + } +} + +static void +godcurse(void) +{ + region *r; + + for (r=regions; r; r=r->next) { + if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { + unit * u; + for(u=r->units; u; u=u->next) { + skill * sv = u->skills; + while (sv!=u->skills+u->skill_size) { + int weeks = 1+rng_int()%3; + reduce_skill(u, sv, weeks); + ++sv; + } + } + if (fval(r->terrain, SEA_REGION)) { + ship *sh; + for (sh = r->ships; sh;) { + ship *shn = sh->next; + damage_ship(sh, 0.10); + if (sh->damage>=sh->size * DAMAGE_SCALE) { + unit * u = shipowner(sh); + if (u) ADDMSG(&u->faction->msgs, + msg_message("godcurse_destroy_ship", "ship", sh)); + remove_ship(&sh->region->ships, sh); + } + sh = shn; + } + } + } + } + +} + +/** handles the "orcish" curse that makes units grow like old orks + * This would probably be better handled in an age-function for the curse, + * but it's now being called by randomevents() + */ +static void +orc_growth(void) +{ + region * r; + for (r = regions; r; r = r->next) { + unit *u; + for (u = r->units; u; u = u->next) { + static boolean init = false; + static const curse_type *ct_orcish = 0; + curse *c = 0; + if (!init) { + init = true; + ct_orcish = ct_find("orcish"); + } + if (ct_orcish) c = get_curse(u->attribs, ct_orcish); + + if (c && !has_skill(u, SK_MAGIC) && !has_skill(u, SK_ALCHEMY) && !fval(u, UFL_HERO)) { + int n; + int increase = 0; + int num = get_cursedmen(u, c); + double prob = curse_geteffect(c); + + for (n = (num - get_item(u, I_CHASTITY_BELT)); n > 0; n--) { + if (chance(prob)) { + ++increase; + } + } + if (increase) { + unit * u2 = create_unit(r, u->faction, increase, u->race, 0, NULL, u); + transfermen(u2, u, u2->number); + + ADDMSG(&u->faction->msgs, msg_message("orcgrowth", + "unit amount race", u, increase, u->race)); + } + } + } + } +} + +/** Talente von Dämonen verschieben sich. + */ +static void +demon_skillchanges(void) +{ + region * r; + + for (r = regions; r; r = r->next) { + unit * u; + for (u = r->units; u; u = u->next) { + if (u->race == new_race[RC_DAEMON]) { + skill * sv = u->skills; + int upchance = 15; + int downchance = 10; + + if (fval(u, UFL_HUNGER)) { + /* hungry demons only go down, never up in skill */ + static int rule_hunger = -1; + if (rule_hunger<0) { + rule_hunger = get_param_int(global.parameters, "hunger.demon.skill", 0); + } + if (rule_hunger) { + upchance = 0; + downchance = 15; + } + } + + while (sv!=u->skills+u->skill_size) { + int roll = rng_int() % 100; + if (sv->level>0 && roll < upchance+downchance) { + int weeks = 1+rng_int()%3; + if (roll < downchance) { + reduce_skill(u, sv, weeks); + if (sv->level<1) { + /* demons should never forget below 1 */ + set_level(u, sv->id, 1); + } + } else { + while (weeks--) learn_skill(u, sv->id, 1.0); + } + if (sv->old>sv->level) { + if (verbosity>=3) { + log_printf("%s dropped from %u to %u:%u in %s\n", + unitname(u), sv->old, sv->level, sv->weeks, skillname(sv->id, NULL)); + } + } + } + ++sv; + } + } + } + } +} + +/** Eisberge entstehen und bewegen sich. + * Einheiten die im Wasser landen, ertrinken. + */ +static void +icebergs(void) +{ + region * r; + create_icebergs(); + move_icebergs(); + for (r=regions; r; r=r->next) { + drown(r); + } +} + +#ifdef HERBS_ROT +static void +rotting_herbs(void) +{ + static int rule_rot = -1; + region * r; + + if (rule_rot<0) { + rule_rot = get_param_int(global.parameters, "rules.economy.herbrot", HERBROTCHANCE); + } + if (rule_rot==0) return; + + for (r = regions; r; r = r->next) { + unit * u; + for (u = r->units; u; u=u->next) { + item **itmp = &u->items, *hbag = *i_find(itmp, olditemtype[I_SACK_OF_CONSERVATION]); + int rot_chance = rule_rot; + + if (hbag) rot_chance = (rot_chance*2)/5; + while (*itmp) { + item * itm = *itmp; + int n = itm->number; + double k = n*rot_chance/100.0; + if (fval(itm->type, ITF_HERB)) { + double nv = normalvariate(k, k/4); + int inv = (int)nv; + int delta = MIN(n, inv); + if (i_change(itmp, itm->type, -delta)==NULL) { + continue; + } + } + itmp = &itm->next; + } + } + } +} +#endif + +void +randomevents(void) +{ + region *r; + + icebergs(); + godcurse(); + orc_growth(); + demon_skillchanges(); + + /* Orkifizierte Regionen mutieren und mutieren zurück */ + + for (r = regions; r; r = r->next) { + if (fval(r, RF_ORCIFIED)) { + direction_t dir; + double probability = 0.0; + for (dir = 0; dir < MAXDIRECTIONS; dir++) { + region *rc = rconnect(r, dir); + if (rc && rpeasants(rc) > 0 && !fval(rc, RF_ORCIFIED)) probability += 0.02; + } + if (chance(probability)) { + ADDMSG(&r->msgs, msg_message("deorcified", "region", r)); + freset(r, RF_ORCIFIED); + } + } else { + attrib *a = a_find(r->attribs, &at_orcification); + if (a!=NULL) { + double probability = 0.0; + if (rpeasants(r) <= 0) continue; + probability = a->data.i/(double)rpeasants(r); + if (chance(probability)) { + fset(r, RF_ORCIFIED); + a_remove(&r->attribs, a); + ADDMSG(&r->msgs, msg_message("orcified", "region", r)); + } else { + a->data.i -= MAX(10,a->data.i/10); + if (a->data.i <= 0) a_remove(&r->attribs, a); + } + } + } + } + + /* Vulkane qualmen, brechen aus ... */ + for (r = regions; r; r = r->next) { + if (r->terrain == newterrain(T_VOLCANO_SMOKING)) { + if (a_find(r->attribs, &at_reduceproduction)) { + ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r)); + rsetterrain(r, T_VOLCANO); + } else { + if (rng_int()%100 < 12) { + ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r)); + rsetterrain(r, T_VOLCANO); + } else if (r->age>20 && rng_int()%100 < 8) { + volcano_outbreak(r); + } + } + } else if (r->terrain == newterrain(T_VOLCANO)) { + if (rng_int()%100 < 4) { + ADDMSG(&r->msgs, msg_message("volcanostartsmoke", "region", r)); + rsetterrain(r, T_VOLCANO_SMOKING); + } + } + } + + /* Monumente zerfallen, Schiffe verfaulen */ + + for (r = regions; r; r = r->next) { + building ** blist = &r->buildings; + while (*blist) { + building * b = *blist; + if (fval(b->type, BTF_DECAY) && !building_owner(b)) { + b->size -= MAX(1, (b->size * 20) / 100); + if (b->size == 0) { + remove_building(blist, r->buildings); + } + } + if (*blist==b) blist=&b->next; + } + } + + /* monster-einheiten desertieren */ + for (r = regions; r; r=r->next) { + unit *u; + + for (u=r->units; u; u=u->next) { + if (u->faction && !is_monsters(u->faction) + && (u->race->flags & RCF_DESERT)) { + if (fval(u, UFL_ISNEW)) continue; + if (rng_int()%100 < 5) { + ADDMSG(&u->faction->msgs, msg_message("desertion", + "unit region", u, r)); + u_setfaction(u, get_monsters()); + } + } + } + } + + /* Chaos */ + for (r = regions; r; r = r->next) { + int i; + + if (fval(r, RF_CHAOTIC)) { + chaos(r); + } + i = chaoscount(r); + if (i) { + chaoscounts(r, -(int) (i * ((double) (rng_int() % 10)) / 100.0)); + } + } +#ifdef HERBS_ROT + rotting_herbs(); +#endif + + dissolve_units(); +} diff --git a/src/gamecode/randenc.h b/src/gamecode/randenc.h index e35dfa18f..31eb0f57f 100644 --- a/src/gamecode/randenc.h +++ b/src/gamecode/randenc.h @@ -1,31 +1,31 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_GC_RANDENC -#define H_GC_RANDENC -#ifdef __cplusplus -extern "C" { -#endif - -extern void encounters(void); -extern void randomevents(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_GC_RANDENC +#define H_GC_RANDENC +#ifdef __cplusplus +extern "C" { +#endif + +extern void encounters(void); +extern void randomevents(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/report.c b/src/gamecode/report.c index 0a94e674d..4d9308a41 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -1,2434 +1,2435 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#define ECHECK_VERSION "4.01" - -#include -#include - -/* modules includes */ -#include - -/* attributes includes */ -#include -#include -#include -#include -#include - -/* gamecode includes */ -#include "creport.h" -#include "economy.h" -#include "monster.h" -#include "laws.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_STAT -#include -#include -#endif - -extern int verbosity; -extern int *storms; -extern int weeks_per_month; -extern int months_per_year; - -static char * -gamedate_season(const struct locale * lang) -{ - static char buf[256]; - gamedate gd; - - get_gamedate(turn, &gd); - - sprintf(buf, (const char *)LOC(lang, "nr_calendar_season"), - LOC(lang, weeknames[gd.week]), - LOC(lang, monthnames[gd.month]), - gd.year, - agename?LOC(lang, agename):"", - LOC(lang, seasonnames[gd.season])); - - return buf; -} - -void -rpc(FILE * F, char c, size_t num) -{ - while(num > 0) { - putc(c, F); - num--; - } -} - -void -rnl(FILE * F) -{ - fputc('\n', F); -} - -static void -centre(FILE * F, const char *s, boolean breaking) -{ - /* Bei Namen die genau 80 Zeichen lang sind, kann es hier Probleme - * geben. Seltsamerweise wird i dann auf MAXINT oder aehnlich - * initialisiert. Deswegen keine Strings die laenger als REPORTWIDTH - * sind! */ - - if (breaking && REPORTWIDTH < strlen(s)) { - strlist *T, *SP = 0; - sparagraph(&SP, s, 0, 0); - T = SP; - while (SP) { - centre(F, SP->s, false); - SP = SP->next; - } - freestrlist(T); - } else { - rpc(F, ' ', (REPORTWIDTH - strlen(s)+1) / 2); - fputs(s, F); - putc('\n', F); - } -} - -static void -rparagraph(FILE *F, const char *str, ptrdiff_t indent, int hanging_indent, char mark) -{ - static const char * spaces = " "; - size_t length = REPORTWIDTH; - const char * end, * begin; - - /* find out if there's a mark + indent already encoded in the string. */ - if (!mark) { - const char * x = str; - while (*x == ' ') ++x; - indent += x - str; - if (x[0] && indent && x[1]==' ') { - indent += 2; - mark = x[0]; - str = x + 2; - hanging_indent -= 2; - } - } - begin = end = str; - - do { - const char * last_space = begin; - - if (mark && indent>=2) { - fwrite(spaces, sizeof(char), indent-2, F); - fputc(mark, F); - fputc(' ', F); - mark = 0; - } else if (begin==str) { - fwrite(spaces, sizeof(char), indent, F); - } else { - fwrite(spaces, sizeof(char), indent+ hanging_indent, F); - } - while (*end && end<=begin+length-indent) { - if (*end==' ') { - last_space = end; - } - ++end; - } - if (*end==0) last_space = end; - if (last_space==begin) { - /* there was no space in this line. clip it */ - last_space = end; - } - fwrite(begin, sizeof(char), last_space-begin, F); - begin = last_space; - while (*begin==' ') { - ++begin; - } - if (begin>end) begin = end; - fputc('\n', F); - } while (*begin); -} - -static void -nr_spell(FILE * F, spell *sp, const struct locale * lang) -{ - int bytes, k, itemanz, costtyp; - int dh = 0; - char buf[4096]; - char * bufp = buf; - size_t size = sizeof(buf) - 1; - const char * params = sp->parameter; - - rnl(F); - centre(F, spell_name(sp, lang), true); - rnl(F); - rparagraph(F, LOC(lang, "nr_spell_description"), 0, 0, 0); - rparagraph(F, spell_info(sp, lang), 2, 0, 0); - - bytes = (int)strlcpy(bufp, LOC(lang, "nr_spell_type"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (size) { *bufp++ = ' '; --size; } - if (sp->sptyp & PRECOMBATSPELL) { - bytes = (int)strlcpy(bufp, LOC(lang, "sptype_precombat"), size); - } else if (sp->sptyp & COMBATSPELL) { - bytes = (int)strlcpy(bufp, LOC(lang, "sptype_combat"), size); - } else if (sp->sptyp & POSTCOMBATSPELL) { - bytes = (int)strlcpy(bufp, LOC(lang, "sptype_postcombat"), size); - } else { - bytes = (int)strlcpy(bufp, LOC(lang, "sptype_normal"), size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - *bufp = 0; - rparagraph(F, buf, 0, 0, 0); - - sprintf(buf, "%s %d", LOC(lang, "nr_spell_level"), sp->level); - rparagraph(F, buf, 0, 0, 0); - - sprintf(buf, "%s %d", LOC(lang, "nr_spell_rank"), sp->rank); - rparagraph(F, buf, 0, 0, 0); - - rparagraph(F, LOC(lang, "nr_spell_components"), 0, 0, 0); - for (k = 0; sp->components[k].type; ++k) { - const resource_type * rtype = sp->components[k].type; - itemanz = sp->components[k].amount; - costtyp = sp->components[k].cost; - if (itemanz > 0) { - size = sizeof(buf) - 1; - bufp = buf; - if (sp->sptyp & SPELLLEVEL) { - bytes = snprintf(bufp, size, " %d %s", itemanz, LOC(lang, resourcename(rtype, itemanz!=1))); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR ) { - bytes = snprintf(bufp, size, " * %s", LOC(lang, "nr_level")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } else { - if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR ) { - itemanz *= sp->level; - } - bytes = snprintf(bufp, size, "%d %s", itemanz, LOC(lang, resourcename(rtype, itemanz!=1))); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - *bufp = 0; - rparagraph(F, buf, 2, 2, '-'); - } - } - - size = sizeof(buf) - 1; - bufp = buf; - bytes = (int)strlcpy(buf, LOC(lang, "nr_spell_modifiers"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (sp->sptyp & FARCASTING) { - bytes = (int)strlcpy(bufp, " Fernzauber", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - dh = 1; - } - if (sp->sptyp & OCEANCASTABLE) { - if (dh == 1) { - bytes = (int)strlcpy(bufp, ",", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - bytes = (int)strlcpy(bufp, " Seezauber", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - dh = 1; - } - if (sp->sptyp & ONSHIPCAST) { - if (dh == 1){ - bytes = (int)strlcpy(bufp, ",", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - bytes = (int)strlcpy(bufp, " Schiffszauber", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - dh = 1; - } - if (sp->sptyp & NOTFAMILIARCAST) { - if (dh == 1) { - bytes = (int)strlcpy(bufp, ", k", size); - } else { - bytes = (int)strlcpy(bufp, " K", size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, "ann nicht vom Vertrauten gezaubert werden", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - dh = 1; - } - if (dh == 0) { - bytes = (int)strlcpy(bufp, " Keine", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - *bufp = 0; - rparagraph(F, buf, 0, 0, 0); - - rparagraph(F, LOC(lang, "nr_spell_syntax"), 0, 0, 0); - - bufp = buf; - size = sizeof(buf) - 1; - - if (sp->sptyp & ISCOMBATSPELL) { - bytes = (int)strlcpy(bufp, LOC(lang, keywords[K_COMBATSPELL]), size); - } else { - bytes = (int)strlcpy(bufp, LOC(lang, keywords[K_CAST]), size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - /* Reihenfolge beachten: Erst REGION, dann STUFE! */ - if (sp->sptyp & FARCASTING) { - bytes = snprintf(bufp, size, " [%s x y]", LOC(lang, parameters[P_REGION])); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (sp->sptyp & SPELLLEVEL) { - bytes = snprintf(bufp, size, " [%s n]", LOC(lang, parameters[P_LEVEL])); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - - bytes = (int)snprintf(bufp, size, " \"%s\"", spell_name(sp, lang)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - while (params && *params) { - typedef struct starget { - param_t param; - int flag; - const char * vars; - } starget; - starget targets[] = { - { P_REGION, REGIONSPELL, NULL }, - { P_UNIT, UNITSPELL, "par_unit" }, - { P_SHIP, SHIPSPELL, "par_ship" }, - { P_BUILDING, BUILDINGSPELL, "par_building" }, - { 0, 0, NULL } - }; - starget * targetp; - char cp = *params++; - int i, maxparam = 0; - const char * locp; - const char * syntaxp = sp->syntax; - - if (cp=='u') { - targetp = targets+1; - locp = LOC(lang, targetp->vars); - bytes = (int)snprintf(bufp, size, " <%s>", locp); - if (*params=='+') { - ++params; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else if (cp=='s') { - targetp = targets+2; - locp = LOC(lang, targetp->vars); - bytes = (int)snprintf(bufp, size, " <%s>", locp); - if (*params=='+') { - ++params; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else if (cp=='r') { - bytes = (int)strlcpy(bufp, " ", size); - if (*params=='+') { - ++params; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " [ ...]", size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else if (cp=='b') { - targetp = targets+3; - locp = LOC(lang, targetp->vars); - bytes = (int)snprintf(bufp, size, " <%s>", locp); - if (*params=='+') { - ++params; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else if (cp=='k') { - if (*params=='c') { - /* skip over a potential id */ - ++params; - } - for (targetp=targets;targetp->flag;++targetp) { - if (sp->sptyp&targetp->flag) ++maxparam; - } - if (maxparam>1) { - bytes = (int)strlcpy(bufp, " (", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - i = 0; - for (targetp=targets;targetp->flag;++targetp) { - if (sp->sptyp&targetp->flag) { - if (i++!=0) { - bytes = (int)strlcpy(bufp, " |", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (targetp->param) { - locp = LOC(lang, targetp->vars); - bytes = (int)snprintf(bufp, size, " %s <%s>", parameters[targetp->param], locp); - if (*params=='+') { - ++params; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); - } - } else { - bytes = (int)snprintf(bufp, size, " %s", parameters[targetp->param]); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - if (maxparam>1) { - bytes = (int)strlcpy(bufp, " )", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } else if (cp=='i' || cp=='c') { - const char * cstr; - assert(syntaxp); - cstr = strchr(syntaxp, ':'); - if (!cstr) { - locp = LOC(lang, mkname("spellpar", syntaxp)); - } else { - char substr[32]; - strncpy(substr, syntaxp, cstr-syntaxp); - substr[cstr-syntaxp] = 0; - locp = LOC(lang, mkname("spellpar", substr)); - syntaxp = substr + 1; - } - bytes = (int)snprintf(bufp, size, " <%s>", locp); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - *bufp = 0; - rparagraph(F, buf, 2, 0, 0); - rnl(F); -} - -void -sparagraph(strlist ** SP, const char *s, int indent, char mark) -{ - - /* Die Liste SP wird mit dem String s aufgefuellt, mit indent und einer - * mark, falls angegeben. SP wurde also auf 0 gesetzt vor dem Aufruf. - * Vgl. spunit (). */ - - int i, j, width; - int firstline; - static char buf[REPORTWIDTH + 1]; - - width = REPORTWIDTH - indent; - firstline = 1; - - for (;;) { - i = 0; - - do { - j = i; - while (s[j] && s[j] != ' ') - j++; - if (j > width) { - - /* j zeigt auf das ende der aktuellen zeile, i zeigt auf den anfang der - * nächsten zeile. existiert ein wort am anfang der zeile, welches - * länger als eine zeile ist, muss dieses hier abgetrennt werden. */ - - if (i == 0) - i = width - 1; - break; - } - i = j + 1; - } - while (s[j]); - - for (j = 0; j != indent; j++) - buf[j] = ' '; - - if (firstline && mark) - buf[indent - 2] = mark; - - for (j = 0; j != i - 1; j++) - buf[indent + j] = s[j]; - buf[indent + j] = 0; - - addstrlist(SP, buf); - - if (s[i - 1] == 0) - break; - - s += i; - firstline = 0; - } -} - -int -hat_in_region(item_t it, region * r, faction * f) -{ - unit *u; - - for (u = r->units; u; u = u->next) { - if (u->faction == f && get_item(u, it) > 0) { - return 1; - } - } - return 0; -} - -static void -nr_curses(FILE *F, const faction *viewer, const void * obj, typ_t typ, int indent) -{ - attrib *a = NULL; - int self = 0; - region *r; - - /* Die Sichtbarkeit eines Zaubers und die Zaubermeldung sind bei - * Gebäuden und Schiffen je nach, ob man Besitzer ist, verschieden. - * Bei Einheiten sieht man Wirkungen auf eigene Einheiten immer. - * Spezialfälle (besonderes Talent, verursachender Magier usw. werde - * bei jedem curse gesondert behandelt. */ - if (typ == TYP_SHIP){ - ship * sh = (ship*)obj; - unit * owner = shipowner(sh); - a = sh->attribs; - r = sh->region; - if (owner) { - if (owner->faction == viewer){ - self = 2; - } else { /* steht eine person der Partei auf dem Schiff? */ - unit *u = NULL; - for (u = r->units; u; u = u->next) { - if (u->ship == sh) { - self = 1; - break; - } - } - } - } - } else if (typ == TYP_BUILDING) { - building * b = (building*)obj; - unit * owner; - a = b->attribs; - r = b->region; - if ((owner = building_owner(b)) != NULL){ - if (owner->faction == viewer){ - self = 2; - } else { /* steht eine Person der Partei in der Burg? */ - unit *u = NULL; - for (u = r->units; u; u = u->next) { - if (u->building == b) { - self = 1; - break; - } - } - } - } - } else if (typ == TYP_UNIT) { - unit *u = (unit *)obj; - a = u->attribs; - r = u->region; - if (u->faction == viewer){ - self = 2; - } - } else if (typ == TYP_REGION) { - r = (region *)obj; - a = r->attribs; - } else { - /* fehler */ - } - - for (;a;a=a->next) { - char buf[4096]; - - if (fval(a->type, ATF_CURSE)) { - curse *c = (curse *)a->data.v; - message * msg; - - if (c->type->cansee) { - self = c->type->cansee(viewer, obj, typ, c, self); - } - msg = msg_curse(c, obj, typ, self); - - if (msg) { - rnl(F); - nr_render(msg, viewer->locale, buf, sizeof(buf), viewer); - rparagraph(F, buf, indent, 2, 0); - msg_release(msg); - } - } else if (a->type==&at_effect && self) { - effect_data * data = (effect_data *)a->data.v; - if (data->value>0) { - sprintf(buf, "Auf der Einheit lieg%s %d Wirkung%s %s.", - (data->value==1 ? "t" : "en"), - data->value, - (data->value==1 ? "" : "en"), - LOC(default_locale, resourcename(data->type->itype->rtype, 0))); - rnl(F); - rparagraph(F, buf, indent, 2, 0); - } - } - } -} - -static void -rps_nowrap(FILE * F, const char *s) -{ - const char *x = s; - size_t indent = 0; - - while (*x++ == ' '); - indent = x - s - 1; - if (*(x - 1) && indent && *x == ' ') - indent += 2; - x = s; - while (*s) { - if (s == x) { - x = strchr(x + 1, ' '); - if (!x) - x = s + strlen(s); - } - rpc(F, *s++, 1); - } -} - -static void -nr_unit(FILE * F, const faction * f, const unit * u, int indent, int mode) -{ - attrib *a_otherfaction; - char marker; - int dh; - boolean isbattle = (boolean)(mode == see_battle); - char buf[8192]; - - if (fval(u->race, RCF_INVISIBLE)) return; - - { - rnl(F); - dh = bufunit(f, u, indent, mode, buf, sizeof(buf)); - } - - a_otherfaction = a_find(u->attribs, &at_otherfaction); - - if (u->faction == f) { - marker = '*'; - } else if ALLIED(u->faction, f) { - marker = 'o'; - } else if (a_otherfaction && f != u->faction && get_otherfaction(a_otherfaction) == f - && !fval(u, UFL_ANON_FACTION)) { - marker = '!'; - } else { - if (dh && !fval(u, UFL_ANON_FACTION)) { - marker = '+'; - } else { - marker = '-'; - } - } - rparagraph(F, buf, indent, 0, marker); - - if (!isbattle) { - nr_curses(F, f, u, TYP_UNIT, indent); - } -} - -static void -rp_messages(FILE * F, message_list * msgs, faction * viewer, int indent, boolean categorized) -{ - nrsection * section; - if (!msgs) return; - for (section = sections; section; section=section->next) { - int k = 0; - struct mlist * m = msgs->begin; - while (m) { - /* messagetype * mt = m->type; */ - if (!categorized || strcmp(nr_section(m->msg), section->name)==0) { - char lbuf[8192]; - - if (!k && categorized) { - const char * section_title; - char cat_identifier[24]; - - rnl(F); - sprintf(cat_identifier, "section_%s", section->name); - section_title = LOC(viewer->locale, cat_identifier); - centre(F, section_title, true); - rnl(F); - k = 1; - } - nr_render(m->msg, viewer->locale, lbuf, sizeof(lbuf), viewer); - rparagraph(F, lbuf, indent, 2, 0); - } - m = m->next; - } - if (!categorized) break; - } -} - -static void -rp_battles(FILE * F, faction * f) -{ - if (f->battles!=NULL) { - struct bmsg * bm = f->battles; - rnl(F); - centre(F, LOC(f->locale, "section_battle"), false); - rnl(F); - - while (bm) { - char buf[256]; - RENDER(f, buf, sizeof(buf), ("battle::header", "region", bm->r)); - rnl(F); - centre(F, buf, true); - rnl(F); - rp_messages(F, bm->msgs, f, 0, false); - bm = bm->next; - } - } -} - -static void -prices(FILE * F, const region * r, const faction * f) -{ - const luxury_type *sale=NULL; - struct demand * dmd; - message * m; - int bytes, n = 0; - char buf[4096], * bufp = buf; - size_t size = sizeof(buf) - 1; - - if (r->land==NULL || r->land->demands==NULL) return; - for (dmd=r->land->demands;dmd;dmd=dmd->next) { - if (dmd->value==0) sale = dmd->type; - else if (dmd->value > 0) n++; - } - assert(sale!=NULL); - - m = msg_message("nr_market_sale", "product price", - sale->itype->rtype, sale->price); - - bytes = (int)nr_render(m, f->locale, bufp, size, f); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - msg_release(m); - - if (n > 0) { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_intro"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - for (dmd=r->land->demands;dmd;dmd=dmd->next) if(dmd->value > 0) { - m = msg_message("nr_market_price", "product price", - dmd->type->itype->rtype, dmd->value * dmd->type->price); - bytes = (int)nr_render(m, f->locale, bufp, size, f); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - msg_release(m); - n--; - if (n == 0) { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_end"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - else if (n == 1) { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_final"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_next"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - } - /* Schreibe Paragraphen */ - *bufp = 0; - rparagraph(F, buf, 0, 0, 0); - -} - -boolean -see_border(const connection * b, const faction * f, const region * r) -{ - boolean cs = b->type->fvisible(b, f, r); - if (!cs) { - cs = b->type->rvisible(b, r); - if (!cs) { - const unit * us = r->units; - while (us && !cs) { - if (us->faction==f) { - cs = b->type->uvisible(b, us); - if (cs) break; - } - us=us->next; - } - } - } - return cs; -} - -static void -describe(FILE * F, const seen_region * sr, faction * f) -{ - const region * r = sr->r; - int n; - boolean dh; - direction_t d; - int trees; - int saplings; - attrib *a; - const char *tname; - struct edge { - struct edge * next; - char * name; - boolean transparent; - boolean block; - boolean exist[MAXDIRECTIONS]; - direction_t lastd; - } * edges = NULL, * e; - boolean see[MAXDIRECTIONS]; - char buf[8192]; - char * bufp = buf; - size_t size = sizeof(buf); - int bytes; - - for (d = 0; d != MAXDIRECTIONS; d++) { - /* Nachbarregionen, die gesehen werden, ermitteln */ - region *r2 = rconnect(r, d); - connection *b; - see[d] = true; - if (!r2) continue; - for (b=get_borders(r, r2);b;) { - struct edge * e = edges; - boolean transparent = b->type->transparent(b, f); - const char * name = b->type->name(b, r, f, GF_DETAILED|GF_ARTICLE); - - if (!transparent) see[d] = false; - if (!see_border(b, f, r)) { - b = b->next; - continue; - } - while (e && (e->transparent != transparent || strcmp(name,e->name))) e = e->next; - if (!e) { - e = calloc(sizeof(struct edge), 1); - e->name = strdup(name); - e->transparent = transparent; - e->next = edges; - edges = e; - } - e->lastd=d; - e->exist[d] = true; - b = b->next; - } - } - - bytes = (int)f_regionid(r, f, bufp, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (sr->mode==see_travel) { - bytes = (int)strlcpy(bufp, " (durchgereist)", size); - } - else if (sr->mode==see_neighbour) { - bytes = (int)strlcpy(bufp, " (benachbart)", size); - } - else if (sr->mode==see_lighthouse) { - bytes = (int)strlcpy(bufp, " (vom Turm erblickt)", size); - } else { - bytes = 0; - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - /* Terrain */ - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - tname = terrain_name(r); - bytes = (int)strlcpy(bufp, LOC(f->locale, tname), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - /* Trees */ - trees = rtrees(r,2); - saplings = rtrees(r,1); - if (production(r)) { - if (trees > 0 || saplings > 0) { - bytes = snprintf(bufp, size, ", %d/%d ", trees, saplings); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (fval(r, RF_MALLORN)) { - if (trees == 1) { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_mallorntree"), size); - } else { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_mallorntree_p"), size); - } - } - else if (trees == 1) { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_tree"), size); - } else { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_tree_p"), size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - - /* iron & stone */ - if (sr->mode==see_unit && f != (faction *) NULL) { - resource_report result[MAX_RAWMATERIALS]; - int n, numresults = report_resources(sr, result, MAX_RAWMATERIALS, f); - - for (n=0;n=0 && result[n].level>=0) { - bytes = snprintf(bufp, size, ", %d %s/%d", result[n].number, - LOC(f->locale, result[n].name), result[n].level); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - } - - /* peasants & silver */ - if (rpeasants(r)) { - int n = rpeasants(r); - bytes = snprintf(bufp, size, ", %d", n); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (r->land->ownership) { - const char * str = locale_string(f->locale, mkname("morale", itoa10(r->land->morale))); - bytes = snprintf(bufp, size, " %s", str); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (fval(r, RF_ORCIFIED)) { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - bytes = (int)strlcpy(bufp, LOC(f->locale, n==1?"rc_orc":"rc_orc_p"), size); - } else { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, n==1?"peasant":"peasant_p"), size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (is_mourning(r, turn+1)) { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_mourning"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - if (rmoney(r) && sr->mode>=see_travel) { - bytes = snprintf(bufp, size, ", %d ", rmoney(r)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, resourcename(oldresourcetype[R_SILVER], rmoney(r)!=1)), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - /* Pferde */ - - if (rhorses(r)) { - bytes = snprintf(bufp, size, ", %d ", rhorses(r)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, resourcename(oldresourcetype[R_HORSE], (rhorses(r)>1)?GR_PLURAL:0)), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - - if (r->display && r->display[0]) { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, r->display, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - n = r->display[strlen(r->display) - 1]; - if (n != '!' && n != '?' && n != '.') { - bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - - if (rule_region_owners()) { - const faction * owner = region_get_owner(r); - if (owner!=NULL) { - bytes = snprintf(bufp, size, " Die Region ist im Besitz von %s.", - factionname(owner)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - a = a_find(r->attribs, &at_overrideroads); - - if (a) { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, (char *)a->data.v, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else { - int nrd = 0; - - /* Nachbarregionen, die gesehen werden, ermitteln */ - for (d = 0; d != MAXDIRECTIONS; d++) { - if (see[d] && rconnect(r, d)) nrd++; - } - /* list directions */ - - dh = false; - for (d = 0; d != MAXDIRECTIONS; d++) if (see[d]) { - region * r2 = rconnect(r, d); - if(!r2) continue; - nrd--; - if (dh) { - char regname[4096]; - if (nrd == 0) { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nb_final"), size); - } else { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nb_next"), size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, directions[d]), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - f_regionid(r2, f, regname, sizeof(regname)); - bytes = snprintf(bufp, size, trailinto(r2, f->locale), regname); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - else { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - MSG(("nr_vicinitystart", "dir region", d, r2), bufp, size, f->locale, f); - bufp += strlen(bufp); - dh = true; - } - } - /* Spezielle Richtungen */ - for (a = a_find(r->attribs, &at_direction);a && a->type==&at_direction;a=a->next) { - spec_direction * d = (spec_direction *)(a->data.v); - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, d->desc), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " (\"", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, d->keyword), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, "\")", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - dh = 1; - } - } - rnl(F); - *bufp = 0; - rparagraph(F, buf, 0, 0, 0); - - if (sr->mode==see_unit && is_astral(r) && - !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) { - /* Sonderbehandlung Teleport-Ebene */ - region_list *rl = astralregions(r, inhabitable); - region_list *rl2; - - if (rl) { - bufp = buf; - size = sizeof(buf) - 1; - bytes = (int)strlcpy(bufp, "Schemen der Regionen ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - rl2 = rl; - while (rl2) { - bytes = (int)f_regionid(rl2->data, f, bufp, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - rl2 = rl2->next; - if (rl2) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - bytes = (int)strlcpy(bufp, " sind erkennbar.", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - free_regionlist(rl); - /* Schreibe Paragraphen */ - rnl(F); - *bufp = 0; - rparagraph(F, buf, 0, 0, 0); - } - } - - n = 0; - - /* Wirkungen permanenter Sprüche */ - nr_curses(F, f, r, TYP_REGION,0); - - /* Produktionsreduktion */ - a = a_find(r->attribs, &at_reduceproduction); - if (a) { - const char * str = LOC(f->locale, "nr_reduced_production"); - rparagraph(F, str, 0, 0, 0); - } - - if (edges) rnl(F); - for (e=edges;e;e=e->next) { - boolean first = true; - bufp = buf; - size = sizeof(buf) - 1; - for (d=0;d!=MAXDIRECTIONS;++d) { - if (!e->exist[d]) continue; - if (first) bytes = (int)strlcpy(bufp, "Im ", size); - else if (e->lastd==d) bytes = (int)strlcpy(bufp, " und im ", size); - else bytes = (int)strlcpy(bufp, ", im ", size ); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, directions[d]), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - first = false; - } - if (!e->transparent) bytes = (int)strlcpy(bufp, " versperrt ", size); - else bytes = (int)strlcpy(bufp, " befindet sich ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, e->name, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (!e->transparent) bytes = (int)strlcpy(bufp, " die Sicht.", size); - else bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - *bufp = 0; - rparagraph(F, buf, 0, 0, 0); - } - if (edges) { - while (edges) { - e = edges->next; - free(edges->name); - free(edges); - edges = e; - } - } -} - -static void -statistics(FILE * F, const region * r, const faction * f) -{ - const unit *u; - int number = 0, p = rpeasants(r); - message * m; - item *itm, *items = NULL; - char buf[4096]; - - /* count */ - for (u = r->units; u; u = u->next) { - if (u->faction == f && !fval(u->race, RCF_INVISIBLE)) { - for (itm=u->items;itm;itm=itm->next) { - i_change(&items, itm->type, itm->number); - } - number += u->number; - } - } - /* print */ - rnl(F); - m = msg_message("nr_stat_header", "region", r); - nr_render(m, f->locale, buf, sizeof(buf), f); - msg_release(m); - rparagraph(F, buf, 0, 0, 0); - rnl(F); - - /* Region */ - if (skill_enabled[SK_ENTERTAINMENT] && fval(r->terrain, LAND_REGION) && rmoney(r)) { - m = msg_message("nr_stat_maxentertainment", "max", entertainmoney(r)); - nr_render(m, f->locale, buf, sizeof(buf), f); - rparagraph(F, buf, 2, 2, 0); - msg_release(m); - } - if (production(r) && (!fval(r->terrain, SEA_REGION) || f->race == new_race[RC_AQUARIAN])) { - if (markets_module()) { /* hack */ - m = msg_message("nr_stat_salary_new", "max", wage(r, NULL, NULL, turn+1)); - } else { - m = msg_message("nr_stat_salary", "max", wage(r, f, f->race, turn+1)); - } - nr_render(m, f->locale, buf, sizeof(buf), f); - rparagraph(F, buf, 2, 2, 0); - msg_release(m); - } - - if (p) { - m = msg_message("nr_stat_recruits", "max", p / RECRUITFRACTION); - nr_render(m, f->locale, buf, sizeof(buf), f); - rparagraph(F, buf, 2, 2, 0); - msg_release(m); - - if (!markets_module()) { - if (buildingtype_exists(r, bt_find("caravan"), true)) { - m = msg_message("nr_stat_luxuries", "max", - (p * 2) / TRADE_FRACTION); - } else { - m = msg_message("nr_stat_luxuries", "max", - p / TRADE_FRACTION); - } - nr_render(m, f->locale, buf, sizeof(buf), f); - rparagraph(F, buf, 2, 2, 0); - msg_release(m); - } - - if (r->land->ownership) { - m = msg_message("nr_stat_morale", "morale", r->land->morale); - nr_render(m, f->locale, buf, sizeof(buf), f); - rparagraph(F, buf, 2, 2, 0); - msg_release(m); - } - - - } - /* info about units */ - - m = msg_message("nr_stat_people", "max", number); - nr_render(m, f->locale, buf, sizeof(buf), f); - rparagraph(F, buf, 2, 2, 0); - msg_release(m); - - for (itm = items; itm; itm=itm->next) { - sprintf(buf, "%s: %d", - LOC(f->locale, resourcename(itm->type->rtype, GR_PLURAL)), - itm->number); - rparagraph(F, buf, 2, 2, 0); - } - while (items) i_free(i_remove(&items, items)); -} - -static void -durchreisende(FILE * F, const region * r, const faction * f) -{ - if (fval(r, RF_TRAVELUNIT)) { - attrib *abegin = a_find(r->attribs, &at_travelunit), *a; - int counter = 0, maxtravel = 0; - char buf[8192]; - char * bufp = buf; - int bytes; - size_t size = sizeof(buf) - 1; - - /* How many are we listing? For grammar. */ - for (a = abegin; a && a->type==&at_travelunit; a = a->next) { - unit * u = (unit*)a->data.v; - - if (r!=u->region && (u->ship==NULL || fval(u, UFL_OWNER))) { - if (cansee_durchgezogen(f, r, u, 0)) { - ++maxtravel; - } - } - } - - if (maxtravel==0) { - return; - } - - /* Auflisten. */ - rnl(F); - - for (a = abegin; a && a->type==&at_travelunit; a = a->next) { - unit * u = (unit*)a->data.v; - - if (r!=u->region && (u->ship==NULL || fval(u, UFL_OWNER))) { - if (cansee_durchgezogen(f, r, u, 0)) { - ++counter; - if (u->ship != NULL) { - if (counter == 1) { - bytes = (int)strlcpy(bufp, "Die ", size); - } else { - bytes = (int)strlcpy(bufp, "die ", size); - } - if (wrptr(&bufp, &size, bytes)!=0) { - WARN_STATIC_BUFFER(); - break; - } - bytes = (int)strlcpy(bufp, shipname(u->ship), size); - } else { - bytes = (int)strlcpy(bufp, unitname(u), size); - } - if (wrptr(&bufp, &size, bytes)!=0) { - WARN_STATIC_BUFFER(); - break; - } - - if (counter + 1 < maxtravel) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) { - WARN_STATIC_BUFFER(); - break; - } - } else if (counter + 1 == maxtravel) { - bytes = (int)strlcpy(bufp, LOC(f->locale, "list_and"), size); - if (wrptr(&bufp, &size, bytes)!=0) { - WARN_STATIC_BUFFER(); - break; - } - } - } - } - } - /* TODO: finish localization */ - if (maxtravel == 1) { - bytes = (int)strlcpy(bufp, " hat die Region durchquert.", size); - } else { - bytes = (int)strlcpy(bufp, " haben die Region durchquert.", size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - *bufp = 0; - rparagraph(F, buf, 0, 0, 0); - } -} - -static int -buildingmaintenance(const building * b, const resource_type * rtype) -{ - const building_type * bt = b->type; - int c, cost=0; - static boolean init = false; - static const curse_type * nocost_ct; - if (!init) { init = true; nocost_ct = ct_find("nocostbuilding"); } - if (curse_active(get_curse(b->attribs, nocost_ct))) { - return 0; - } - for (c=0;bt->maintenance && bt->maintenance[c].number;++c) { - const maintenance * m = bt->maintenance + c; - if (m->rtype==rtype) { - if (fval(m, MTF_VARIABLE)) - cost += (b->size * m->number); - else - cost += m->number; - } - } - return cost; -} - -static int -report_template(const char * filename, report_context * ctx, const char * charset) -{ - faction * f = ctx->f; - region *r; - FILE * F = fopen(filename, "wt"); - seen_region * sr = NULL; - char buf[8192], * bufp; - size_t size; - int bytes; - - int enc = get_encoding_by_name(charset); - - if (F==NULL) { - perror(filename); - return -1; - } - - if (enc==ENCODING_UTF8) { - const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; - fwrite(utf8_bom, 1, 3, F); - } - - rps_nowrap(F, ""); - rnl(F); - rps_nowrap(F, LOC(f->locale, "nr_template")); - rnl(F); - rps_nowrap(F, ""); - rnl(F); - - sprintf(buf, "%s %s \"%s\"", LOC(f->locale, "ERESSEA"), factionid(f), LOC(f->locale, "enterpasswd")); - rps_nowrap(F, buf); - rnl(F); - - rps_nowrap(F, ""); - rnl(F); - sprintf(buf, "; ECHECK -l -w4 -r%d -v%s", f->race->recruitcost, ECHECK_VERSION); - /* -v3.4: ECheck Version 3.4.x */ - rps_nowrap(F, buf); - rnl(F); - - for (r=ctx->first; sr==NULL && r!=ctx->last; r=r->next) { - sr = find_seen(ctx->seen, r); - } - - for (;sr!=NULL;sr=sr->next) { - region * r = sr->r; - unit *u; - int dh = 0; - - if (sr->modeunits; u; u = u->next) { - if (u->faction == f && !fval(u->race, RCF_INVISIBLE)) { - order * ord; - if (!dh) { - plane * pl = getplane(r); - int nx = r->x, ny = r->y; - - pnormalize(&nx, &ny, pl); - adjust_coordinates(f, &nx, &ny, pl, r); - rps_nowrap(F, ""); - rnl(F); - if (pl && pl->id != 0) { - sprintf(buf, "%s %d,%d,%d ; %s", LOC(f->locale, parameters[P_REGION]), - nx, ny, pl->id, rname(r, f->locale)); - } else { - sprintf(buf, "%s %d,%d ; %s", LOC(f->locale, parameters[P_REGION]), - nx, ny, rname(r, f->locale)); - } - rps_nowrap(F, buf); - rnl(F); - sprintf(buf,"; ECheck Lohn %d", wage(r, f, f->race, turn+1)); - rps_nowrap(F, buf); - rnl(F); - rps_nowrap(F, ""); - rnl(F); - } - dh = 1; - - bufp = buf; - size = sizeof(buf) - 1; - bytes = snprintf(bufp, size, "%s %s; %s [%d,%d$", - LOC(u->faction->locale, parameters[P_UNIT]), - unitid(u), u->name, u->number, get_money(u)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (u->building != NULL && fval(u, UFL_OWNER)) { - building * b = u->building; - int cost = buildingmaintenance(b, r_silver); - - if (cost > 0) { - bytes = (int)strlcpy(bufp, ",U", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, itoa10(cost), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } else if (u->ship) { - if (fval(u, UFL_OWNER)) { - bytes = (int)strlcpy(bufp, ",S", size); - } else { - bytes = (int)strlcpy(bufp, ",s", size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, shipid(u->ship), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (lifestyle(u) == 0) { - bytes = (int)strlcpy(bufp, ",I", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - bytes = (int)strlcpy(bufp, "]", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - *bufp = 0; - rps_nowrap(F, buf); - rnl(F); - - for (ord = u->old_orders; ord; ord = ord->next) { - /* this new order will replace the old defaults */ - strcpy(buf, " "); - write_order(ord, buf+2, sizeof(buf)-2); - rps_nowrap(F, buf); - rnl(F); - } - for (ord = u->orders; ord; ord = ord->next) { - if (u->old_orders && is_repeated(ord)) continue; /* unit has defaults */ - if (is_persistent(ord)) { - strcpy(buf, " "); - write_order(ord, buf+2, sizeof(buf)-2); - rps_nowrap(F, buf); - rnl(F); - } - } - - /* If the lastorder begins with an @ it should have - * been printed in the loop before. */ - } - } - } - rps_nowrap(F, ""); - rnl(F); - strcpy(buf, LOC(f->locale, parameters[P_NEXT])); - rps_nowrap(F, buf); - rnl(F); - fclose(F); - return 0; -} - -static void -show_allies(const faction * f, const ally * allies, char * buf, size_t size) -{ - int allierte = 0; - int i=0, h, hh = 0; - int bytes, dh = 0; - const ally * sf; - char * bufp = buf; /* buf already contains data */ - - --size; /* leave room for a null-terminator */ - - for (sf = allies; sf; sf = sf->next) { - int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); - if (mode > 0) ++allierte; - } - - for (sf = allies; sf; sf = sf->next) { - int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); - if (mode <= 0) continue; - i++; - if (dh) { - if (i == allierte) { - bytes = (int)strlcpy(bufp, LOC(f->locale, "list_and"), size); - } else { - bytes = (int)strlcpy(bufp, ", ", size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - dh = 1; - hh = 0; - bytes = (int)strlcpy(bufp, factionname(sf->faction), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " (", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if ((mode & HELP_ALL) == HELP_ALL) { - bytes = (int)strlcpy(bufp, "Alles", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else { - for (h = 1; h < HELP_ALL; h *= 2) { - int p = MAXPARAMS; - if ((mode & h) == h) { - switch (h) { - case HELP_TRAVEL: - p = P_TRAVEL; - break; - case HELP_MONEY: - p = P_MONEY; - break; - case HELP_FIGHT: - p = P_FIGHT; - break; - case HELP_GIVE: - p = P_GIVE; - break; - case HELP_GUARD: - p = P_GUARD; - break; - case HELP_FSTEALTH: - p = P_FACTIONSTEALTH; - break; - } - } - if (p!=MAXPARAMS) { - if (hh) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - bytes = (int)strlcpy(bufp, parameters[p], size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - hh = 1; - } - } - } - bytes = (int)strlcpy(bufp, ")", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - *bufp = 0; -} - -static void -allies(FILE * F, const faction * f) -{ - const group * g = f->groups; - char buf[16384]; - - if (f->allies) { - int bytes; - size_t size = sizeof(buf); - if (!f->allies->next) { - bytes = (int)strlcpy(buf, "Wir helfen der Partei ", size); - } else { - bytes = (int)strlcpy(buf, "Wir helfen den Parteien ", size); - } - size -= bytes; - show_allies(f, f->allies, buf + bytes, size); - rparagraph(F, buf, 0, 0, 0); - rnl(F); - } - - while (g) { - if (g->allies) { - int bytes; - size_t size = sizeof(buf); - if (!g->allies->next) { - bytes = snprintf(buf, size, "%s hilft der Partei ", g->name); - } else { - bytes = snprintf(buf, size, "%s hilft den Parteien ", g->name); - } - size -= bytes; - show_allies(f, g->allies, buf + bytes, size); - rparagraph(F, buf, 0, 0, 0); - rnl(F); - } - g = g->next; - } -} - -static void -guards(FILE * F, const region * r, const faction * see) -{ - /* die Partei see sieht dies; wegen - * "unbekannte Partei", wenn man es selbst ist... */ - - faction* guardians[512]; - - int nextguard = 0; - - unit *u; - int i; - - boolean tarned = false; - /* Bewachung */ - - for (u = r->units; u; u = u->next) { - if (is_guard(u, GUARD_ALL)!=0) { - faction *f = u->faction; - faction *fv = visible_faction(see, u); - - if(fv != f && see != fv) { - f = fv; - } - - if (f != see && fval(u, UFL_ANON_FACTION)) { - tarned=true; - } else { - for (i=0;i!=nextguard;++i) if (guardians[i]==f) break; - if (i==nextguard) { - guardians[nextguard++] = f; - } - } - } - } - - if (nextguard || tarned) { - char buf[8192]; - char * bufp = buf; - size_t size = sizeof(buf) - 1; - int bytes; - - bytes = (int)strlcpy(bufp, "Die Region wird von ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - for (i = 0; i!=nextguard+(tarned?1:0); ++i) { - if (i!=0) { - if (i == nextguard-(tarned?0:1)) { - bytes = (int)strlcpy(bufp, LOC(see->locale, "list_and"), size); - } else { - bytes = (int)strlcpy(bufp, ", ", size); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (ilocale, "nr_addresses"), false); - rnl(F); - - while (flist!=NULL) { - const faction * f = flist->data; - if (!is_monsters(f)) { - char buf[8192]; - char label = '-'; - - sprintf(buf, "%s: %s; %s", factionname(f), f->email, f->banner?f->banner:""); - if (uf==f) label = '*'; - else if (ALLIED(uf, f)) label = 'o'; - else if (alliedfaction(NULL, uf, f, HELP_ALL)) label = '+'; - rparagraph(F, buf, 4, 0, label); - - } - flist = flist->next; - } - rnl(F); - rpline(F); -} - -static void -nr_ship(FILE * F, const seen_region * sr, const ship * sh, const faction * f, const unit * captain) -{ - const region * r = sr->r; - char buffer[8192], * bufp = buffer; - size_t size = sizeof(buffer) - 1; - int bytes; - char ch; - - rnl(F); - - if (captain && captain->faction == f) { - int n = 0, p = 0; - getshipweight(sh, &n, &p); - n = (n+99) / 100; /* 1 Silber = 1 GE */ - - bytes = snprintf(bufp, size, "%s, %s, (%d/%d)", shipname(sh), - LOC(f->locale, sh->type->name[0]), n, shipcapacity(sh) / 100); - } else { - bytes = snprintf(bufp, size, "%s, %s", shipname(sh), LOC(f->locale, sh->type->name[0])); - } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - assert(sh->type->construction->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */ - if (sh->size!=sh->type->construction->maxsize) { - bytes = snprintf(bufp, size, ", %s (%d/%d)", - LOC(f->locale, "nr_undercons"), sh->size, - sh->type->construction->maxsize); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (sh->damage) { - int percent = (sh->damage*100+DAMAGE_SCALE-1)/(sh->size*DAMAGE_SCALE); - bytes = snprintf(bufp, size, ", %d%% %s", percent, LOC(f->locale, "nr_damaged")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (!fval(r->terrain, SEA_REGION)) { - if (sh->coast != NODIRECTION) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, coasts[sh->coast]), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - ch = 0; - if (sh->display && sh->display[0]) { - bytes = (int)strlcpy(bufp, "; ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, sh->display, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - ch = sh->display[strlen(sh->display) - 1]; - } - if (ch != '!' && ch != '?' && ch != '.') { - bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - *bufp = 0; - rparagraph(F, buffer, 2, 0, 0); - - nr_curses(F, f, sh, TYP_SHIP, 4); -} - -static void -nr_building(FILE *F, const seen_region * sr, const building * b, const faction * f) -{ - int i, bytes; - const char * name, * bname, * billusion = NULL; - const struct locale * lang = NULL; - char buffer[8192], * bufp = buffer; - size_t size = sizeof(buffer) - 1; - - rnl(F); - - if (f) lang = f->locale; - - bytes = snprintf(bufp, size, "%s, %s %d, ", buildingname(b), LOC(f->locale, "nr_size"), b->size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - report_building(b, &bname, &billusion); - name = LOC(lang, billusion?billusion:bname); - bytes = (int)strlcpy(bufp, name, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (billusion) { - unit * owner = building_owner(b); - if (owner && owner->faction==f) { - /* illusion. report real type */ - name = LOC(lang, bname); - bytes = snprintf(bufp, size, " (%s)", name); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - - if (b->size < b->type->maxsize) { - bytes = (int)strlcpy(bufp, " (im Bau)", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - - if (b->besieged > 0 && sr->mode>=see_lighthouse) { - bytes = (int)strlcpy(bufp, ", belagert von ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, itoa10(b->besieged), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " Personen ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (b->besieged >= b->size * SIEGEFACTOR) { - bytes = (int)strlcpy(bufp, "(abgeschnitten)", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - i = 0; - if (b->display && b->display[0]) { - bytes = (int)strlcpy(bufp, "; ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, b->display, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - i = b->display[strlen(b->display) - 1]; - } - -#ifdef WDW_PYRAMID - - if (i != '!' && i != '?' && i != '.') { - scat(", "); - } - - if (b->type == bt_find("pyramid")) { - unit * owner = building_owner(b); - scat("Größenstufe "); - icat(wdw_pyramid_level(b)); - scat("."); - - if (owner && owner->faction==f) { - const construction *ctype = b->type->construction; - int completed = b->size; - int c; - - scat(" Baukosten pro Größenpunkt: "); - - while(ctype->improvement != NULL && - ctype->improvement != ctype && - ctype->maxsize > 0 && - ctype->maxsize <= completed) - { - completed -= ctype->maxsize; - ctype = ctype->improvement; - } - - assert(ctype->materials != NULL); - - for (c=0;ctype->materials[c].number;c++) { - const resource_type * rtype = ctype->materials[c].rtype; - int number = ctype->materials[c].number; - - if(c > 0) { - scat(", "); - } - icat(number); - scat(" "); - scat(locale_string(lang, resourcename(rtype, number!=1?GR_PLURAL:0))); - } - - scat("."); - - scat(" Erforderlicher Talentwert: "); - icat(b->type->construction->minskill); - scat("."); - } - } - -#else - - if (i != '!' && i != '?' && i != '.') { - bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - -#endif - *bufp = 0; - rparagraph(F, buffer, 2, 0, 0); - - if (sr->modelocale, bufp, size, f); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - msg_release(m); - - rparagraph(F, buf, 0, 0, 0); -} - -int -report_plaintext(const char * filename, report_context * ctx, const char * charset) -{ - int flag = 0; - char ch; - int anyunits, no_units, no_people; - const struct region *r; - faction * f = ctx->f; - unit *u; - char pzTime[64]; - attrib *a; - message * m; - unsigned char op; - int bytes, ix = want(O_STATISTICS); - int wants_stats = (f->options & ix); - FILE * F = fopen(filename, "wt"); - seen_region * sr = NULL; - char buf[8192]; - char * bufp; - int enc = get_encoding_by_name(charset); - size_t size; - - /* static variables can cope with writing for different turns */ - static int thisseason = -1; - static int nextseason = -1; - static int gamecookie = -1; - if (gamecookie!=global.cookie) { - gamedate date; - get_gamedate(turn+1, &date); - thisseason = date.season; - get_gamedate(turn+2, &date); - nextseason = date.season; - gamecookie = global.cookie; - } - - if (F==NULL) { - perror(filename); - return -1; - } - if (enc==ENCODING_UTF8) { - const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; - fwrite(utf8_bom, 1, 3, F); - } - - strftime(pzTime, 64, "%A, %d. %B %Y, %H:%M", localtime(&ctx->report_time)); - m = msg_message("nr_header_date", "game date", global.gamename, pzTime); - nr_render(m, f->locale, buf, sizeof(buf), f); - msg_release(m); - centre(F, buf, true); - - centre(F, gamedate_season(f->locale), true); - rnl(F); - sprintf(buf, "%s, %s/%s (%s)", factionname(f), - LOC(f->locale, rc_name(f->race, 1)), - LOC(f->locale, mkname("school", magic_school[f->magiegebiet])), - f->email); - centre(F, buf, true); - if (f_get_alliance(f)) { - centre(F, alliancename(f->alliance), true); - } - - if (f->age <= 2) { - const char * s; - if (f->age <= 1) { - ADDMSG(&f->msgs, msg_message("changepasswd", - "value", f->passw)); - } - RENDER(f, buf, sizeof(buf), ("newbie_password", "password", f->passw)); - rnl(F); - centre(F, buf, true); - s = locale_getstring(f->locale, "newbie_info_1"); - if (s) { - rnl(F); - centre(F, s, true); - } - s = locale_getstring(f->locale, "newbie_info_2"); - if (s) { - rnl(F); - centre(F, s, true); - } - if ((f->options & want(O_COMPUTER)) == 0) { - f->options |= want(O_COMPUTER); - s = locale_getstring(f->locale, "newbie_info_3"); - if (s) { - rnl(F); - centre(F, s, true); - } - } - } - rnl(F); -#if SCORE_MODULE - if (f->options & want(O_SCORE) && f->age > DISPLAYSCORE) { - RENDER(f, buf, sizeof(buf), ("nr_score", "score average", f->score, average_score_of_age(f->age, f->age / 24 + 1))); - centre(F, buf, true); - } -#endif -#ifdef COUNT_AGAIN - no_units = 0; - no_people = 0; - for (u=f->units;u;u=u->nextF) { - if (playerrace(u->race)) { - ++no_people; - no_units += u->number; - assert(f==u->faction); - } - } - if (no_units!=f->no_units) { - f->no_units = no_units; - } - if (no_people!=f->num_people) { - f->num_people = no_people; - } -#else - no_units = f->no_units; - no_people = f->num_people; -#endif - m = msg_message("nr_population", "population units", no_people, no_units); - nr_render(m, f->locale, buf, sizeof(buf), f); - msg_release(m); - centre(F, buf, true); - if (f->race == new_race[RC_HUMAN]) { - int maxmig = count_maxmigrants(f); - if (maxmig>0) { - m = msg_message("nr_migrants", "units maxunits", count_migrants(f), maxmig); - nr_render(m, f->locale, buf, sizeof(buf), f); - msg_release(m); - centre(F, buf, true); - } - } - if (f_get_alliance(f)) { - m = msg_message("nr_alliance", "leader name id age", alliance_get_leader(f->alliance), f->alliance->name, f->alliance->id, turn-f->alliance_joindate); - nr_render(m, f->locale, buf, sizeof(buf), f); - msg_release(m); - centre(F, buf, true); - } - { - int maxh = maxheroes(f); - if (maxh) { - message * msg = msg_message("nr_heroes", "units maxunits", countheroes(f), maxh); - nr_render(msg, f->locale, buf, sizeof(buf), f); - msg_release(msg); - centre(F, buf, true); - } - } - - if (f->items!=NULL) { - message * msg = msg_message("nr_claims", "items", f->items); - nr_render(msg, f->locale, buf, sizeof(buf), f); - msg_release(msg); - rnl(F); - centre(F, buf, true); - } - - /* Insekten-Winter-Warnung */ - if (f->race == new_race[RC_INSECT]) { - if (thisseason == 0) { - centre(F, LOC(f->locale, "nr_insectwinter"), true); - rnl(F); - } else { - if (nextseason == 0) { - centre(F, LOC(f->locale, "nr_insectfall"), true); - rnl(F); - } - } - } - - bufp = buf; - size = sizeof(buf) - 1; - bytes = snprintf(buf, size,"%s:", LOC(f->locale, "nr_options")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - for (op = 0; op != MAXOPTIONS; op++) { - if (f->options & want(op) && options[op]) { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, options[op]), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - flag++; - } - } - if (flag > 0) { - rnl(F); - *bufp = 0; - centre(F, buf, true); - } - - rp_messages(F, f->msgs, f, 0, true); - rp_battles(F, f); - a = a_find(f->attribs, &at_reportspell); - if (a) { - rnl(F); - centre(F, LOC(f->locale, "section_newspells"), true); - while (a && a->type==&at_reportspell) { - spell *sp = (spell *)a->data.v; - nr_spell(F, sp, f->locale); - a = a->next; - } - } - - ch = 0; - for (a=a_find(f->attribs, &at_showitem);a && a->type==&at_showitem;a=a->next) { - const potion_type * ptype = resource2potion(((const item_type*)a->data.v)->rtype); - const char * description = NULL; - if (ptype!=NULL) { - const char * pname = resourcename(ptype->itype->rtype, 0); - - if (ch==0) { - rnl(F); - centre(F, LOC(f->locale, "section_newpotions"), true); - ch = 1; - } - - rnl(F); - centre(F, LOC(f->locale, pname), true); - snprintf(buf, sizeof(buf), "%s %d", LOC(f->locale, "nr_level"), ptype->level); - centre(F, buf, true); - rnl(F); - - bufp = buf; - size = sizeof(buf) - 1; - bytes = snprintf(bufp, size, "%s: ", LOC(f->locale, "nr_herbsrequired")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (ptype->itype->construction) { - requirement * m = ptype->itype->construction->materials; - while (m->number) { - bytes = (int)strlcpy(bufp, LOC(f->locale, resourcename(m->rtype, 0)), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - ++m; - if (m->number) - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - *bufp = 0; - centre(F, buf, true); - rnl(F); - if (description==NULL) { - const char * potiontext = mkname("potion", pname); - description = LOC(f->locale, potiontext); - } - centre(F, description, true); - } - } - rnl(F); - centre(F, LOC(f->locale, "nr_alliances"), false); - rnl(F); - - allies(F, f); - - rpline(F); - - anyunits = 0; - - for (r=ctx->first;sr==NULL && r!=ctx->last;r=r->next) { - sr = find_seen(ctx->seen, r); - } - for (;sr!=NULL;sr=sr->next) { - region * r = sr->r; - int stealthmod = stealth_modifier(sr->mode); - building * b = r->buildings; - ship * sh = r->ships; - - if (sr->modemode==see_unit) { - anyunits = 1; - describe(F, sr, f); - if (markets_module() && r->land) { - const item_type * lux = r_luxury(r); - const item_type * herb = r->land->herbtype; - message * m = 0; - if (herb && lux) { - m = msg_message("nr_market_info_p", "p1 p2", - lux?lux->rtype:0, herb?herb->rtype:0); - } else if (lux || herb) { - m = msg_message("nr_market_info_s", "p1", - lux?lux->rtype:herb->rtype); - } - if (m) { - rnl(F); - nr_paragraph(F, m, f); - } - // - } else { - if (!fval(r->terrain, SEA_REGION) && rpeasants(r)/TRADE_FRACTION > 0) { - rnl(F); - prices(F, r, f); - } - } - guards(F, r, f); - durchreisende(F, r, f); - } - else { - if (sr->mode==see_far) { - describe(F, sr, f); - guards(F, r, f); - durchreisende(F, r, f); - } - else if (sr->mode==see_lighthouse) { - describe(F, sr, f); - durchreisende(F, r, f); - } else { - describe(F, sr, f); - durchreisende(F, r, f); - } - } - /* Statistik */ - - if (wants_stats && sr->mode==see_unit) - statistics(F, r, f); - - /* Nachrichten an REGION in der Region */ - - if (sr->mode==see_unit || sr->mode==see_travel) { - message_list * mlist = r_getmessages(r, f); - rp_messages(F, r->msgs, f, 0, true); - if (mlist) rp_messages(F, mlist, f, 0, true); - } - - /* report all units. they are pre-sorted in an efficient manner */ - u = r->units; - while (b) { - while (b && (!u || u->building!=b)) { - nr_building(F, sr, b, f); - b = b->next; - } - if (b) { - nr_building(F, sr, b, f); - while (u && u->building==b) { - nr_unit(F, f, u, 6, sr->mode); - u = u->next; - } - b = b->next; - } - } - while (u && !u->ship) { - if (stealthmod>INT_MIN) { - if (u->faction == f || cansee(f, r, u, stealthmod)) { - nr_unit(F, f, u, 4, sr->mode); - } - } - assert(!u->building); - u = u->next; - } - while (sh) { - while (sh && (!u || u->ship!=sh)) { - nr_ship(F, sr, sh, f, NULL); - sh = sh->next; - } - if (sh) { - nr_ship(F, sr, sh, f, u); - while (u && u->ship==sh) { - nr_unit(F, f, u, 6, sr->mode); - u = u->next; - } - sh = sh->next; - } - } - - assert(!u); - - rnl(F); - rpline(F); - } - if (!is_monsters(f)) { - if (!anyunits) { - rnl(F); - rparagraph(F, LOC(f->locale, "nr_youaredead"), 0, 2, 0); - } else { - list_address(F, f, ctx->addresses); - } - } - fclose(F); - return 0; -} - -void -base36conversion(void) -{ - region * r; - for (r=regions;r;r=r->next) { - unit * u; - for (u=r->units;u;u=u->next) { - if (forbiddenid(u->no)) { - uunhash(u); - u->no = newunitid(); - uhash(u); - } - } - } -} - -#define FMAXHASH 1021 - -struct fsee { - struct fsee * nexthash; - faction * f; - struct see { - struct see * next; - faction * seen; - unit * proof; - } * see; -} * fsee[FMAXHASH]; - -#define REPORT_NR (1 << O_REPORT) -#define REPORT_CR (1 << O_COMPUTER) -#define REPORT_ZV (1 << O_ZUGVORLAGE) -#define REPORT_ZIP (1 << O_COMPRESS) -#define REPORT_BZIP2 (1 << O_BZIP2) - - -unit * -can_find(faction * f, faction * f2) -{ - int key = f->no % FMAXHASH; - struct fsee * fs = fsee[key]; - struct see * ss; - if (f==f2) return f->units; - while (fs && fs->f!=f) fs=fs->nexthash; - if (!fs) return NULL; - ss=fs->see; - while (ss && ss->seen!=f2) ss=ss->next; - if (ss) { - /* bei TARNE PARTEI yxz muss die Partei von unit proof nicht - * wirklich Partei f2 sein! */ - /* assert(ss->proof->faction==f2); */ - return ss->proof; - } - return NULL; -} - -static void -add_find(faction * f, unit * u, faction *f2) -{ - /* faction f sees f2 through u */ - int key = f->no % FMAXHASH; - struct fsee ** fp = &fsee[key]; - struct fsee * fs; - struct see ** sp; - struct see * ss; - while (*fp && (*fp)->f!=f) fp=&(*fp)->nexthash; - if (!*fp) { - fs = *fp = calloc(sizeof(struct fsee), 1); - fs->f = f; - } else fs = *fp; - sp = &fs->see; - while (*sp && (*sp)->seen!=f2) sp=&(*sp)->next; - if (!*sp) { - ss = *sp = calloc(sizeof(struct see), 1); - ss->proof = u; - ss->seen = f2; - } else ss = *sp; - ss->proof = u; -} - -static void -update_find(void) -{ - region * r; - static boolean initial = true; - - if (initial) for (r=regions;r;r=r->next) { - unit * u; - for (u=r->units;u;u=u->next) { - faction * lastf = u->faction; - unit * u2; - for (u2=r->units;u2;u2=u2->next) { - if (u2->faction==lastf || u2->faction==u->faction) - continue; - if (seefaction(u->faction, r, u2, 0)) { - faction *fv = visible_faction(u->faction, u2); - lastf = fv; - add_find(u->faction, u2, fv); - } - } - } - } - initial = false; -} - -boolean -kann_finden(faction * f1, faction * f2) -{ - update_find(); - return (boolean)(can_find(f1, f2)!=NULL); -} - -/******* end summary ******/ - -void -register_nr(void) -{ - if (!nocr) register_reporttype("nr", &report_plaintext, 1<nexthash; - free(fsee[i]); - fsee[i] = fs; - } - } -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#define ECHECK_VERSION "4.01" + +#include +#include + +/* modules includes */ +#include + +/* attributes includes */ +#include +#include +#include +#include +#include + +/* gamecode includes */ +#include "creport.h" +#include "economy.h" +#include "monster.h" +#include "laws.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_STAT +#include +#include +#endif + +extern int verbosity; +extern int *storms; +extern int weeks_per_month; +extern int months_per_year; + +static char * +gamedate_season(const struct locale * lang) +{ + static char buf[256]; + gamedate gd; + + get_gamedate(turn, &gd); + + sprintf(buf, (const char *)LOC(lang, "nr_calendar_season"), + LOC(lang, weeknames[gd.week]), + LOC(lang, monthnames[gd.month]), + gd.year, + agename?LOC(lang, agename):"", + LOC(lang, seasonnames[gd.season])); + + return buf; +} + +void +rpc(FILE * F, char c, size_t num) +{ + while(num > 0) { + putc(c, F); + num--; + } +} + +void +rnl(FILE * F) +{ + fputc('\n', F); +} + +static void +centre(FILE * F, const char *s, boolean breaking) +{ + /* Bei Namen die genau 80 Zeichen lang sind, kann es hier Probleme + * geben. Seltsamerweise wird i dann auf MAXINT oder aehnlich + * initialisiert. Deswegen keine Strings die laenger als REPORTWIDTH + * sind! */ + + if (breaking && REPORTWIDTH < strlen(s)) { + strlist *T, *SP = 0; + sparagraph(&SP, s, 0, 0); + T = SP; + while (SP) { + centre(F, SP->s, false); + SP = SP->next; + } + freestrlist(T); + } else { + rpc(F, ' ', (REPORTWIDTH - strlen(s)+1) / 2); + fputs(s, F); + putc('\n', F); + } +} + +static void +rparagraph(FILE *F, const char *str, ptrdiff_t indent, int hanging_indent, char mark) +{ + static const char * spaces = " "; + size_t length = REPORTWIDTH; + const char * end, * begin; + + /* find out if there's a mark + indent already encoded in the string. */ + if (!mark) { + const char * x = str; + while (*x == ' ') ++x; + indent += x - str; + if (x[0] && indent && x[1]==' ') { + indent += 2; + mark = x[0]; + str = x + 2; + hanging_indent -= 2; + } + } + begin = end = str; + + do { + const char * last_space = begin; + + if (mark && indent>=2) { + fwrite(spaces, sizeof(char), indent-2, F); + fputc(mark, F); + fputc(' ', F); + mark = 0; + } else if (begin==str) { + fwrite(spaces, sizeof(char), indent, F); + } else { + fwrite(spaces, sizeof(char), indent+ hanging_indent, F); + } + while (*end && end<=begin+length-indent) { + if (*end==' ') { + last_space = end; + } + ++end; + } + if (*end==0) last_space = end; + if (last_space==begin) { + /* there was no space in this line. clip it */ + last_space = end; + } + fwrite(begin, sizeof(char), last_space-begin, F); + begin = last_space; + while (*begin==' ') { + ++begin; + } + if (begin>end) begin = end; + fputc('\n', F); + } while (*begin); +} + +static void +nr_spell(FILE * F, spell *sp, const struct locale * lang) +{ + int bytes, k, itemanz, costtyp; + int dh = 0; + char buf[4096]; + char * bufp = buf; + size_t size = sizeof(buf) - 1; + const char * params = sp->parameter; + + rnl(F); + centre(F, spell_name(sp, lang), true); + rnl(F); + rparagraph(F, LOC(lang, "nr_spell_description"), 0, 0, 0); + rparagraph(F, spell_info(sp, lang), 2, 0, 0); + + bytes = (int)strlcpy(bufp, LOC(lang, "nr_spell_type"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (size) { *bufp++ = ' '; --size; } + if (sp->sptyp & PRECOMBATSPELL) { + bytes = (int)strlcpy(bufp, LOC(lang, "sptype_precombat"), size); + } else if (sp->sptyp & COMBATSPELL) { + bytes = (int)strlcpy(bufp, LOC(lang, "sptype_combat"), size); + } else if (sp->sptyp & POSTCOMBATSPELL) { + bytes = (int)strlcpy(bufp, LOC(lang, "sptype_postcombat"), size); + } else { + bytes = (int)strlcpy(bufp, LOC(lang, "sptype_normal"), size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + *bufp = 0; + rparagraph(F, buf, 0, 0, 0); + + sprintf(buf, "%s %d", LOC(lang, "nr_spell_level"), sp->level); + rparagraph(F, buf, 0, 0, 0); + + sprintf(buf, "%s %d", LOC(lang, "nr_spell_rank"), sp->rank); + rparagraph(F, buf, 0, 0, 0); + + rparagraph(F, LOC(lang, "nr_spell_components"), 0, 0, 0); + for (k = 0; sp->components[k].type; ++k) { + const resource_type * rtype = sp->components[k].type; + itemanz = sp->components[k].amount; + costtyp = sp->components[k].cost; + if (itemanz > 0) { + size = sizeof(buf) - 1; + bufp = buf; + if (sp->sptyp & SPELLLEVEL) { + bytes = snprintf(bufp, size, " %d %s", itemanz, LOC(lang, resourcename(rtype, itemanz!=1))); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR ) { + bytes = snprintf(bufp, size, " * %s", LOC(lang, "nr_level")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } else { + if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR ) { + itemanz *= sp->level; + } + bytes = snprintf(bufp, size, "%d %s", itemanz, LOC(lang, resourcename(rtype, itemanz!=1))); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + *bufp = 0; + rparagraph(F, buf, 2, 2, '-'); + } + } + + size = sizeof(buf) - 1; + bufp = buf; + bytes = (int)strlcpy(buf, LOC(lang, "nr_spell_modifiers"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (sp->sptyp & FARCASTING) { + bytes = (int)strlcpy(bufp, " Fernzauber", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + dh = 1; + } + if (sp->sptyp & OCEANCASTABLE) { + if (dh == 1) { + bytes = (int)strlcpy(bufp, ",", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + bytes = (int)strlcpy(bufp, " Seezauber", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + dh = 1; + } + if (sp->sptyp & ONSHIPCAST) { + if (dh == 1){ + bytes = (int)strlcpy(bufp, ",", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + bytes = (int)strlcpy(bufp, " Schiffszauber", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + dh = 1; + } + if (sp->sptyp & NOTFAMILIARCAST) { + if (dh == 1) { + bytes = (int)strlcpy(bufp, ", k", size); + } else { + bytes = (int)strlcpy(bufp, " K", size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, "ann nicht vom Vertrauten gezaubert werden", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + dh = 1; + } + if (dh == 0) { + bytes = (int)strlcpy(bufp, " Keine", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + *bufp = 0; + rparagraph(F, buf, 0, 0, 0); + + rparagraph(F, LOC(lang, "nr_spell_syntax"), 0, 0, 0); + + bufp = buf; + size = sizeof(buf) - 1; + + if (sp->sptyp & ISCOMBATSPELL) { + bytes = (int)strlcpy(bufp, LOC(lang, keywords[K_COMBATSPELL]), size); + } else { + bytes = (int)strlcpy(bufp, LOC(lang, keywords[K_CAST]), size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + /* Reihenfolge beachten: Erst REGION, dann STUFE! */ + if (sp->sptyp & FARCASTING) { + bytes = snprintf(bufp, size, " [%s x y]", LOC(lang, parameters[P_REGION])); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (sp->sptyp & SPELLLEVEL) { + bytes = snprintf(bufp, size, " [%s n]", LOC(lang, parameters[P_LEVEL])); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + bytes = (int)snprintf(bufp, size, " \"%s\"", spell_name(sp, lang)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + while (params && *params) { + typedef struct starget { + param_t param; + int flag; + const char * vars; + } starget; + starget targets[] = { + { P_REGION, REGIONSPELL, NULL }, + { P_UNIT, UNITSPELL, "par_unit" }, + { P_SHIP, SHIPSPELL, "par_ship" }, + { P_BUILDING, BUILDINGSPELL, "par_building" }, + { 0, 0, NULL } + }; + starget * targetp; + char cp = *params++; + int i, maxparam = 0; + const char * locp; + const char * syntaxp = sp->syntax; + + if (cp=='u') { + targetp = targets+1; + locp = LOC(lang, targetp->vars); + bytes = (int)snprintf(bufp, size, " <%s>", locp); + if (*params=='+') { + ++params; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else if (cp=='s') { + targetp = targets+2; + locp = LOC(lang, targetp->vars); + bytes = (int)snprintf(bufp, size, " <%s>", locp); + if (*params=='+') { + ++params; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else if (cp=='r') { + bytes = (int)strlcpy(bufp, " ", size); + if (*params=='+') { + ++params; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " [ ...]", size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else if (cp=='b') { + targetp = targets+3; + locp = LOC(lang, targetp->vars); + bytes = (int)snprintf(bufp, size, " <%s>", locp); + if (*params=='+') { + ++params; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else if (cp=='k') { + if (*params=='c') { + /* skip over a potential id */ + ++params; + } + for (targetp=targets;targetp->flag;++targetp) { + if (sp->sptyp&targetp->flag) ++maxparam; + } + if (maxparam>1) { + bytes = (int)strlcpy(bufp, " (", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + i = 0; + for (targetp=targets;targetp->flag;++targetp) { + if (sp->sptyp&targetp->flag) { + if (i++!=0) { + bytes = (int)strlcpy(bufp, " |", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (targetp->param) { + locp = LOC(lang, targetp->vars); + bytes = (int)snprintf(bufp, size, " %s <%s>", parameters[targetp->param], locp); + if (*params=='+') { + ++params; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); + } + } else { + bytes = (int)snprintf(bufp, size, " %s", parameters[targetp->param]); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + if (maxparam>1) { + bytes = (int)strlcpy(bufp, " )", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } else if (cp=='i' || cp=='c') { + const char * cstr; + assert(syntaxp); + cstr = strchr(syntaxp, ':'); + if (!cstr) { + locp = LOC(lang, mkname("spellpar", syntaxp)); + } else { + char substr[32]; + strncpy(substr, syntaxp, cstr-syntaxp); + substr[cstr-syntaxp] = 0; + locp = LOC(lang, mkname("spellpar", substr)); + syntaxp = substr + 1; + } + bytes = (int)snprintf(bufp, size, " <%s>", locp); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + *bufp = 0; + rparagraph(F, buf, 2, 0, 0); + rnl(F); +} + +void +sparagraph(strlist ** SP, const char *s, int indent, char mark) +{ + + /* Die Liste SP wird mit dem String s aufgefuellt, mit indent und einer + * mark, falls angegeben. SP wurde also auf 0 gesetzt vor dem Aufruf. + * Vgl. spunit (). */ + + int i, j, width; + int firstline; + static char buf[REPORTWIDTH + 1]; + + width = REPORTWIDTH - indent; + firstline = 1; + + for (;;) { + i = 0; + + do { + j = i; + while (s[j] && s[j] != ' ') + j++; + if (j > width) { + + /* j zeigt auf das ende der aktuellen zeile, i zeigt auf den anfang der + * nächsten zeile. existiert ein wort am anfang der zeile, welches + * länger als eine zeile ist, muss dieses hier abgetrennt werden. */ + + if (i == 0) + i = width - 1; + break; + } + i = j + 1; + } + while (s[j]); + + for (j = 0; j != indent; j++) + buf[j] = ' '; + + if (firstline && mark) + buf[indent - 2] = mark; + + for (j = 0; j != i - 1; j++) + buf[indent + j] = s[j]; + buf[indent + j] = 0; + + addstrlist(SP, buf); + + if (s[i - 1] == 0) + break; + + s += i; + firstline = 0; + } +} + +int +hat_in_region(item_t it, region * r, faction * f) +{ + unit *u; + + for (u = r->units; u; u = u->next) { + if (u->faction == f && get_item(u, it) > 0) { + return 1; + } + } + return 0; +} + +static void +nr_curses(FILE *F, const faction *viewer, const void * obj, typ_t typ, int indent) +{ + attrib *a = NULL; + int self = 0; + region *r; + + /* Die Sichtbarkeit eines Zaubers und die Zaubermeldung sind bei + * Gebäuden und Schiffen je nach, ob man Besitzer ist, verschieden. + * Bei Einheiten sieht man Wirkungen auf eigene Einheiten immer. + * Spezialfälle (besonderes Talent, verursachender Magier usw. werde + * bei jedem curse gesondert behandelt. */ + if (typ == TYP_SHIP){ + ship * sh = (ship*)obj; + unit * owner = shipowner(sh); + a = sh->attribs; + r = sh->region; + if (owner) { + if (owner->faction == viewer){ + self = 2; + } else { /* steht eine person der Partei auf dem Schiff? */ + unit *u = NULL; + for (u = r->units; u; u = u->next) { + if (u->ship == sh) { + self = 1; + break; + } + } + } + } + } else if (typ == TYP_BUILDING) { + building * b = (building*)obj; + unit * owner; + a = b->attribs; + r = b->region; + if ((owner = building_owner(b)) != NULL){ + if (owner->faction == viewer){ + self = 2; + } else { /* steht eine Person der Partei in der Burg? */ + unit *u = NULL; + for (u = r->units; u; u = u->next) { + if (u->building == b) { + self = 1; + break; + } + } + } + } + } else if (typ == TYP_UNIT) { + unit *u = (unit *)obj; + a = u->attribs; + r = u->region; + if (u->faction == viewer){ + self = 2; + } + } else if (typ == TYP_REGION) { + r = (region *)obj; + a = r->attribs; + } else { + /* fehler */ + } + + for (;a;a=a->next) { + char buf[4096]; + + if (fval(a->type, ATF_CURSE)) { + curse *c = (curse *)a->data.v; + message * msg; + + if (c->type->cansee) { + self = c->type->cansee(viewer, obj, typ, c, self); + } + msg = msg_curse(c, obj, typ, self); + + if (msg) { + rnl(F); + nr_render(msg, viewer->locale, buf, sizeof(buf), viewer); + rparagraph(F, buf, indent, 2, 0); + msg_release(msg); + } + } else if (a->type==&at_effect && self) { + effect_data * data = (effect_data *)a->data.v; + if (data->value>0) { + sprintf(buf, "Auf der Einheit lieg%s %d Wirkung%s %s.", + (data->value==1 ? "t" : "en"), + data->value, + (data->value==1 ? "" : "en"), + LOC(default_locale, resourcename(data->type->itype->rtype, 0))); + rnl(F); + rparagraph(F, buf, indent, 2, 0); + } + } + } +} + +static void +rps_nowrap(FILE * F, const char *s) +{ + const char *x = s; + size_t indent = 0; + + while (*x++ == ' '); + indent = x - s - 1; + if (*(x - 1) && indent && *x == ' ') + indent += 2; + x = s; + while (*s) { + if (s == x) { + x = strchr(x + 1, ' '); + if (!x) + x = s + strlen(s); + } + rpc(F, *s++, 1); + } +} + +static void +nr_unit(FILE * F, const faction * f, const unit * u, int indent, int mode) +{ + attrib *a_otherfaction; + char marker; + int dh; + boolean isbattle = (boolean)(mode == see_battle); + char buf[8192]; + + if (fval(u->race, RCF_INVISIBLE)) return; + + { + rnl(F); + dh = bufunit(f, u, indent, mode, buf, sizeof(buf)); + } + + a_otherfaction = a_find(u->attribs, &at_otherfaction); + + if (u->faction == f) { + marker = '*'; + } else if ALLIED(u->faction, f) { + marker = 'o'; + } else if (a_otherfaction && f != u->faction && get_otherfaction(a_otherfaction) == f + && !fval(u, UFL_ANON_FACTION)) { + marker = '!'; + } else { + if (dh && !fval(u, UFL_ANON_FACTION)) { + marker = '+'; + } else { + marker = '-'; + } + } + rparagraph(F, buf, indent, 0, marker); + + if (!isbattle) { + nr_curses(F, f, u, TYP_UNIT, indent); + } +} + +static void +rp_messages(FILE * F, message_list * msgs, faction * viewer, int indent, boolean categorized) +{ + nrsection * section; + if (!msgs) return; + for (section = sections; section; section=section->next) { + int k = 0; + struct mlist * m = msgs->begin; + while (m) { + /* messagetype * mt = m->type; */ + if (!categorized || strcmp(nr_section(m->msg), section->name)==0) { + char lbuf[8192]; + + if (!k && categorized) { + const char * section_title; + char cat_identifier[24]; + + rnl(F); + sprintf(cat_identifier, "section_%s", section->name); + section_title = LOC(viewer->locale, cat_identifier); + centre(F, section_title, true); + rnl(F); + k = 1; + } + nr_render(m->msg, viewer->locale, lbuf, sizeof(lbuf), viewer); + rparagraph(F, lbuf, indent, 2, 0); + } + m = m->next; + } + if (!categorized) break; + } +} + +static void +rp_battles(FILE * F, faction * f) +{ + if (f->battles!=NULL) { + struct bmsg * bm = f->battles; + rnl(F); + centre(F, LOC(f->locale, "section_battle"), false); + rnl(F); + + while (bm) { + char buf[256]; + RENDER(f, buf, sizeof(buf), ("battle::header", "region", bm->r)); + rnl(F); + centre(F, buf, true); + rnl(F); + rp_messages(F, bm->msgs, f, 0, false); + bm = bm->next; + } + } +} + +static void +prices(FILE * F, const region * r, const faction * f) +{ + const luxury_type *sale=NULL; + struct demand * dmd; + message * m; + int bytes, n = 0; + char buf[4096], * bufp = buf; + size_t size = sizeof(buf) - 1; + + if (r->land==NULL || r->land->demands==NULL) return; + for (dmd=r->land->demands;dmd;dmd=dmd->next) { + if (dmd->value==0) sale = dmd->type; + else if (dmd->value > 0) n++; + } + assert(sale!=NULL); + + m = msg_message("nr_market_sale", "product price", + sale->itype->rtype, sale->price); + + bytes = (int)nr_render(m, f->locale, bufp, size, f); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + msg_release(m); + + if (n > 0) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_intro"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + for (dmd=r->land->demands;dmd;dmd=dmd->next) if(dmd->value > 0) { + m = msg_message("nr_market_price", "product price", + dmd->type->itype->rtype, dmd->value * dmd->type->price); + bytes = (int)nr_render(m, f->locale, bufp, size, f); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + msg_release(m); + n--; + if (n == 0) { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_end"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + else if (n == 1) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_final"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_next"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + } + /* Schreibe Paragraphen */ + *bufp = 0; + rparagraph(F, buf, 0, 0, 0); + +} + +boolean +see_border(const connection * b, const faction * f, const region * r) +{ + boolean cs = b->type->fvisible(b, f, r); + if (!cs) { + cs = b->type->rvisible(b, r); + if (!cs) { + const unit * us = r->units; + while (us && !cs) { + if (us->faction==f) { + cs = b->type->uvisible(b, us); + if (cs) break; + } + us=us->next; + } + } + } + return cs; +} + +static void +describe(FILE * F, const seen_region * sr, faction * f) +{ + const region * r = sr->r; + int n; + boolean dh; + direction_t d; + int trees; + int saplings; + attrib *a; + const char *tname; + struct edge { + struct edge * next; + char * name; + boolean transparent; + boolean block; + boolean exist[MAXDIRECTIONS]; + direction_t lastd; + } * edges = NULL, * e; + boolean see[MAXDIRECTIONS]; + char buf[8192]; + char * bufp = buf; + size_t size = sizeof(buf); + int bytes; + + for (d = 0; d != MAXDIRECTIONS; d++) { + /* Nachbarregionen, die gesehen werden, ermitteln */ + region *r2 = rconnect(r, d); + connection *b; + see[d] = true; + if (!r2) continue; + for (b=get_borders(r, r2);b;) { + struct edge * e = edges; + boolean transparent = b->type->transparent(b, f); + const char * name = b->type->name(b, r, f, GF_DETAILED|GF_ARTICLE); + + if (!transparent) see[d] = false; + if (!see_border(b, f, r)) { + b = b->next; + continue; + } + while (e && (e->transparent != transparent || strcmp(name,e->name))) e = e->next; + if (!e) { + e = calloc(sizeof(struct edge), 1); + e->name = strdup(name); + e->transparent = transparent; + e->next = edges; + edges = e; + } + e->lastd=d; + e->exist[d] = true; + b = b->next; + } + } + + bytes = (int)f_regionid(r, f, bufp, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (sr->mode==see_travel) { + bytes = (int)strlcpy(bufp, " (durchgereist)", size); + } + else if (sr->mode==see_neighbour) { + bytes = (int)strlcpy(bufp, " (benachbart)", size); + } + else if (sr->mode==see_lighthouse) { + bytes = (int)strlcpy(bufp, " (vom Turm erblickt)", size); + } else { + bytes = 0; + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + /* Terrain */ + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + tname = terrain_name(r); + bytes = (int)strlcpy(bufp, LOC(f->locale, tname), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + /* Trees */ + trees = rtrees(r,2); + saplings = rtrees(r,1); + if (production(r)) { + if (trees > 0 || saplings > 0) { + bytes = snprintf(bufp, size, ", %d/%d ", trees, saplings); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (fval(r, RF_MALLORN)) { + if (trees == 1) { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_mallorntree"), size); + } else { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_mallorntree_p"), size); + } + } + else if (trees == 1) { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_tree"), size); + } else { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_tree_p"), size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + + /* iron & stone */ + if (sr->mode==see_unit && f != (faction *) NULL) { + resource_report result[MAX_RAWMATERIALS]; + int n, numresults = report_resources(sr, result, MAX_RAWMATERIALS, f); + + for (n=0;n=0 && result[n].level>=0) { + bytes = snprintf(bufp, size, ", %d %s/%d", result[n].number, + LOC(f->locale, result[n].name), result[n].level); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + } + + /* peasants & silver */ + if (rpeasants(r)) { + int n = rpeasants(r); + bytes = snprintf(bufp, size, ", %d", n); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (r->land->ownership) { + const char * str = locale_string(f->locale, mkname("morale", itoa10(r->land->morale))); + bytes = snprintf(bufp, size, " %s", str); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (fval(r, RF_ORCIFIED)) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + bytes = (int)strlcpy(bufp, LOC(f->locale, n==1?"rc_orc":"rc_orc_p"), size); + } else { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, n==1?"peasant":"peasant_p"), size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (is_mourning(r, turn+1)) { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_mourning"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + if (rmoney(r) && sr->mode>=see_travel) { + bytes = snprintf(bufp, size, ", %d ", rmoney(r)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, resourcename(oldresourcetype[R_SILVER], rmoney(r)!=1)), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + /* Pferde */ + + if (rhorses(r)) { + bytes = snprintf(bufp, size, ", %d ", rhorses(r)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, resourcename(oldresourcetype[R_HORSE], (rhorses(r)>1)?GR_PLURAL:0)), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + + if (r->display && r->display[0]) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, r->display, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + n = r->display[strlen(r->display) - 1]; + if (n != '!' && n != '?' && n != '.') { + bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + + if (rule_region_owners()) { + const faction * owner = region_get_owner(r); + if (owner!=NULL) { + bytes = snprintf(bufp, size, " Die Region ist im Besitz von %s.", + factionname(owner)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + a = a_find(r->attribs, &at_overrideroads); + + if (a) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, (char *)a->data.v, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else { + int nrd = 0; + + /* Nachbarregionen, die gesehen werden, ermitteln */ + for (d = 0; d != MAXDIRECTIONS; d++) { + if (see[d] && rconnect(r, d)) nrd++; + } + /* list directions */ + + dh = false; + for (d = 0; d != MAXDIRECTIONS; d++) if (see[d]) { + region * r2 = rconnect(r, d); + if(!r2) continue; + nrd--; + if (dh) { + char regname[4096]; + if (nrd == 0) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nb_final"), size); + } else { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nb_next"), size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, directions[d]), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + f_regionid(r2, f, regname, sizeof(regname)); + bytes = snprintf(bufp, size, trailinto(r2, f->locale), regname); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + else { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + MSG(("nr_vicinitystart", "dir region", d, r2), bufp, size, f->locale, f); + bufp += strlen(bufp); + dh = true; + } + } + /* Spezielle Richtungen */ + for (a = a_find(r->attribs, &at_direction);a && a->type==&at_direction;a=a->next) { + spec_direction * d = (spec_direction *)(a->data.v); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, d->desc), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " (\"", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, d->keyword), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, "\")", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + dh = 1; + } + } + rnl(F); + *bufp = 0; + rparagraph(F, buf, 0, 0, 0); + + if (sr->mode==see_unit && is_astral(r) && + !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) { + /* Sonderbehandlung Teleport-Ebene */ + region_list *rl = astralregions(r, inhabitable); + region_list *rl2; + + if (rl) { + bufp = buf; + size = sizeof(buf) - 1; + bytes = (int)strlcpy(bufp, "Schemen der Regionen ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + rl2 = rl; + while (rl2) { + bytes = (int)f_regionid(rl2->data, f, bufp, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + rl2 = rl2->next; + if (rl2) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + bytes = (int)strlcpy(bufp, " sind erkennbar.", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + free_regionlist(rl); + /* Schreibe Paragraphen */ + rnl(F); + *bufp = 0; + rparagraph(F, buf, 0, 0, 0); + } + } + + n = 0; + + /* Wirkungen permanenter Sprüche */ + nr_curses(F, f, r, TYP_REGION,0); + + /* Produktionsreduktion */ + a = a_find(r->attribs, &at_reduceproduction); + if (a) { + const char * str = LOC(f->locale, "nr_reduced_production"); + rparagraph(F, str, 0, 0, 0); + } + + if (edges) rnl(F); + for (e=edges;e;e=e->next) { + boolean first = true; + bufp = buf; + size = sizeof(buf) - 1; + for (d=0;d!=MAXDIRECTIONS;++d) { + if (!e->exist[d]) continue; + if (first) bytes = (int)strlcpy(bufp, "Im ", size); + else if (e->lastd==d) bytes = (int)strlcpy(bufp, " und im ", size); + else bytes = (int)strlcpy(bufp, ", im ", size ); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, directions[d]), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + first = false; + } + if (!e->transparent) bytes = (int)strlcpy(bufp, " versperrt ", size); + else bytes = (int)strlcpy(bufp, " befindet sich ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, e->name, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (!e->transparent) bytes = (int)strlcpy(bufp, " die Sicht.", size); + else bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + *bufp = 0; + rparagraph(F, buf, 0, 0, 0); + } + if (edges) { + while (edges) { + e = edges->next; + free(edges->name); + free(edges); + edges = e; + } + } +} + +static void +statistics(FILE * F, const region * r, const faction * f) +{ + const unit *u; + int number = 0, p = rpeasants(r); + message * m; + item *itm, *items = NULL; + char buf[4096]; + + /* count */ + for (u = r->units; u; u = u->next) { + if (u->faction == f && !fval(u->race, RCF_INVISIBLE)) { + for (itm=u->items;itm;itm=itm->next) { + i_change(&items, itm->type, itm->number); + } + number += u->number; + } + } + /* print */ + rnl(F); + m = msg_message("nr_stat_header", "region", r); + nr_render(m, f->locale, buf, sizeof(buf), f); + msg_release(m); + rparagraph(F, buf, 0, 0, 0); + rnl(F); + + /* Region */ + if (skill_enabled[SK_ENTERTAINMENT] && fval(r->terrain, LAND_REGION) && rmoney(r)) { + m = msg_message("nr_stat_maxentertainment", "max", entertainmoney(r)); + nr_render(m, f->locale, buf, sizeof(buf), f); + rparagraph(F, buf, 2, 2, 0); + msg_release(m); + } + if (production(r) && (!fval(r->terrain, SEA_REGION) || f->race == new_race[RC_AQUARIAN])) { + if (markets_module()) { /* hack */ + m = msg_message("nr_stat_salary_new", "max", wage(r, NULL, NULL, turn+1)); + } else { + m = msg_message("nr_stat_salary", "max", wage(r, f, f->race, turn+1)); + } + nr_render(m, f->locale, buf, sizeof(buf), f); + rparagraph(F, buf, 2, 2, 0); + msg_release(m); + } + + if (p) { + m = msg_message("nr_stat_recruits", "max", p / RECRUITFRACTION); + nr_render(m, f->locale, buf, sizeof(buf), f); + rparagraph(F, buf, 2, 2, 0); + msg_release(m); + + if (!markets_module()) { + if (buildingtype_exists(r, bt_find("caravan"), true)) { + m = msg_message("nr_stat_luxuries", "max", + (p * 2) / TRADE_FRACTION); + } else { + m = msg_message("nr_stat_luxuries", "max", + p / TRADE_FRACTION); + } + nr_render(m, f->locale, buf, sizeof(buf), f); + rparagraph(F, buf, 2, 2, 0); + msg_release(m); + } + + if (r->land->ownership) { + m = msg_message("nr_stat_morale", "morale", r->land->morale); + nr_render(m, f->locale, buf, sizeof(buf), f); + rparagraph(F, buf, 2, 2, 0); + msg_release(m); + } + + + } + /* info about units */ + + m = msg_message("nr_stat_people", "max", number); + nr_render(m, f->locale, buf, sizeof(buf), f); + rparagraph(F, buf, 2, 2, 0); + msg_release(m); + + for (itm = items; itm; itm=itm->next) { + sprintf(buf, "%s: %d", + LOC(f->locale, resourcename(itm->type->rtype, GR_PLURAL)), + itm->number); + rparagraph(F, buf, 2, 2, 0); + } + while (items) i_free(i_remove(&items, items)); +} + +static void +durchreisende(FILE * F, const region * r, const faction * f) +{ + if (fval(r, RF_TRAVELUNIT)) { + attrib *abegin = a_find(r->attribs, &at_travelunit), *a; + int counter = 0, maxtravel = 0; + char buf[8192]; + char * bufp = buf; + int bytes; + size_t size = sizeof(buf) - 1; + + /* How many are we listing? For grammar. */ + for (a = abegin; a && a->type==&at_travelunit; a = a->next) { + unit * u = (unit*)a->data.v; + + if (r!=u->region && (u->ship==NULL || fval(u, UFL_OWNER))) { + if (cansee_durchgezogen(f, r, u, 0)) { + ++maxtravel; + } + } + } + + if (maxtravel==0) { + return; + } + + /* Auflisten. */ + rnl(F); + + for (a = abegin; a && a->type==&at_travelunit; a = a->next) { + unit * u = (unit*)a->data.v; + + if (r!=u->region && (u->ship==NULL || fval(u, UFL_OWNER))) { + if (cansee_durchgezogen(f, r, u, 0)) { + ++counter; + if (u->ship != NULL) { + if (counter == 1) { + bytes = (int)strlcpy(bufp, "Die ", size); + } else { + bytes = (int)strlcpy(bufp, "die ", size); + } + if (wrptr(&bufp, &size, bytes)!=0) { + WARN_STATIC_BUFFER(); + break; + } + bytes = (int)strlcpy(bufp, shipname(u->ship), size); + } else { + bytes = (int)strlcpy(bufp, unitname(u), size); + } + if (wrptr(&bufp, &size, bytes)!=0) { + WARN_STATIC_BUFFER(); + break; + } + + if (counter + 1 < maxtravel) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) { + WARN_STATIC_BUFFER(); + break; + } + } else if (counter + 1 == maxtravel) { + bytes = (int)strlcpy(bufp, LOC(f->locale, "list_and"), size); + if (wrptr(&bufp, &size, bytes)!=0) { + WARN_STATIC_BUFFER(); + break; + } + } + } + } + } + /* TODO: finish localization */ + if (maxtravel == 1) { + bytes = (int)strlcpy(bufp, " hat die Region durchquert.", size); + } else { + bytes = (int)strlcpy(bufp, " haben die Region durchquert.", size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + *bufp = 0; + rparagraph(F, buf, 0, 0, 0); + } +} + +static int +buildingmaintenance(const building * b, const resource_type * rtype) +{ + const building_type * bt = b->type; + int c, cost=0; + static boolean init = false; + static const curse_type * nocost_ct; + if (!init) { init = true; nocost_ct = ct_find("nocostbuilding"); } + if (curse_active(get_curse(b->attribs, nocost_ct))) { + return 0; + } + for (c=0;bt->maintenance && bt->maintenance[c].number;++c) { + const maintenance * m = bt->maintenance + c; + if (m->rtype==rtype) { + if (fval(m, MTF_VARIABLE)) + cost += (b->size * m->number); + else + cost += m->number; + } + } + return cost; +} + +static int +report_template(const char * filename, report_context * ctx, const char * charset) +{ + faction * f = ctx->f; + region *r; + FILE * F = fopen(filename, "wt"); + seen_region * sr = NULL; + char buf[8192], * bufp; + size_t size; + int bytes; + + int enc = xmlParseCharEncoding(charset); + + if (F==NULL) { + perror(filename); + return -1; + } + + if (enc==XML_CHAR_ENCODING_UTF8) { + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + fwrite(utf8_bom, 1, 3, F); + } + + rps_nowrap(F, ""); + rnl(F); + rps_nowrap(F, LOC(f->locale, "nr_template")); + rnl(F); + rps_nowrap(F, ""); + rnl(F); + + sprintf(buf, "%s %s \"%s\"", LOC(f->locale, "ERESSEA"), factionid(f), LOC(f->locale, "enterpasswd")); + rps_nowrap(F, buf); + rnl(F); + + rps_nowrap(F, ""); + rnl(F); + sprintf(buf, "; ECHECK -l -w4 -r%d -v%s", f->race->recruitcost, ECHECK_VERSION); + /* -v3.4: ECheck Version 3.4.x */ + rps_nowrap(F, buf); + rnl(F); + + for (r=ctx->first; sr==NULL && r!=ctx->last; r=r->next) { + sr = find_seen(ctx->seen, r); + } + + for (;sr!=NULL;sr=sr->next) { + region * r = sr->r; + unit *u; + int dh = 0; + + if (sr->modeunits; u; u = u->next) { + if (u->faction == f && !fval(u->race, RCF_INVISIBLE)) { + order * ord; + if (!dh) { + plane * pl = getplane(r); + int nx = r->x, ny = r->y; + + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl, r); + rps_nowrap(F, ""); + rnl(F); + if (pl && pl->id != 0) { + sprintf(buf, "%s %d,%d,%d ; %s", LOC(f->locale, parameters[P_REGION]), + nx, ny, pl->id, rname(r, f->locale)); + } else { + sprintf(buf, "%s %d,%d ; %s", LOC(f->locale, parameters[P_REGION]), + nx, ny, rname(r, f->locale)); + } + rps_nowrap(F, buf); + rnl(F); + sprintf(buf,"; ECheck Lohn %d", wage(r, f, f->race, turn+1)); + rps_nowrap(F, buf); + rnl(F); + rps_nowrap(F, ""); + rnl(F); + } + dh = 1; + + bufp = buf; + size = sizeof(buf) - 1; + bytes = snprintf(bufp, size, "%s %s; %s [%d,%d$", + LOC(u->faction->locale, parameters[P_UNIT]), + unitid(u), u->name, u->number, get_money(u)); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (u->building != NULL && fval(u, UFL_OWNER)) { + building * b = u->building; + int cost = buildingmaintenance(b, r_silver); + + if (cost > 0) { + bytes = (int)strlcpy(bufp, ",U", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, itoa10(cost), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } else if (u->ship) { + if (fval(u, UFL_OWNER)) { + bytes = (int)strlcpy(bufp, ",S", size); + } else { + bytes = (int)strlcpy(bufp, ",s", size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, shipid(u->ship), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (lifestyle(u) == 0) { + bytes = (int)strlcpy(bufp, ",I", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + bytes = (int)strlcpy(bufp, "]", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + *bufp = 0; + rps_nowrap(F, buf); + rnl(F); + + for (ord = u->old_orders; ord; ord = ord->next) { + /* this new order will replace the old defaults */ + strcpy(buf, " "); + write_order(ord, buf+2, sizeof(buf)-2); + rps_nowrap(F, buf); + rnl(F); + } + for (ord = u->orders; ord; ord = ord->next) { + if (u->old_orders && is_repeated(ord)) continue; /* unit has defaults */ + if (is_persistent(ord)) { + strcpy(buf, " "); + write_order(ord, buf+2, sizeof(buf)-2); + rps_nowrap(F, buf); + rnl(F); + } + } + + /* If the lastorder begins with an @ it should have + * been printed in the loop before. */ + } + } + } + rps_nowrap(F, ""); + rnl(F); + strcpy(buf, LOC(f->locale, parameters[P_NEXT])); + rps_nowrap(F, buf); + rnl(F); + fclose(F); + return 0; +} + +static void +show_allies(const faction * f, const ally * allies, char * buf, size_t size) +{ + int allierte = 0; + int i=0, h, hh = 0; + int bytes, dh = 0; + const ally * sf; + char * bufp = buf; /* buf already contains data */ + + --size; /* leave room for a null-terminator */ + + for (sf = allies; sf; sf = sf->next) { + int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); + if (mode > 0) ++allierte; + } + + for (sf = allies; sf; sf = sf->next) { + int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); + if (mode <= 0) continue; + i++; + if (dh) { + if (i == allierte) { + bytes = (int)strlcpy(bufp, LOC(f->locale, "list_and"), size); + } else { + bytes = (int)strlcpy(bufp, ", ", size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + dh = 1; + hh = 0; + bytes = (int)strlcpy(bufp, factionname(sf->faction), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " (", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if ((mode & HELP_ALL) == HELP_ALL) { + bytes = (int)strlcpy(bufp, "Alles", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else { + for (h = 1; h < HELP_ALL; h *= 2) { + int p = MAXPARAMS; + if ((mode & h) == h) { + switch (h) { + case HELP_TRAVEL: + p = P_TRAVEL; + break; + case HELP_MONEY: + p = P_MONEY; + break; + case HELP_FIGHT: + p = P_FIGHT; + break; + case HELP_GIVE: + p = P_GIVE; + break; + case HELP_GUARD: + p = P_GUARD; + break; + case HELP_FSTEALTH: + p = P_FACTIONSTEALTH; + break; + } + } + if (p!=MAXPARAMS) { + if (hh) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + bytes = (int)strlcpy(bufp, parameters[p], size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + hh = 1; + } + } + } + bytes = (int)strlcpy(bufp, ")", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + *bufp = 0; +} + +static void +allies(FILE * F, const faction * f) +{ + const group * g = f->groups; + char buf[16384]; + + if (f->allies) { + int bytes; + size_t size = sizeof(buf); + if (!f->allies->next) { + bytes = (int)strlcpy(buf, "Wir helfen der Partei ", size); + } else { + bytes = (int)strlcpy(buf, "Wir helfen den Parteien ", size); + } + size -= bytes; + show_allies(f, f->allies, buf + bytes, size); + rparagraph(F, buf, 0, 0, 0); + rnl(F); + } + + while (g) { + if (g->allies) { + int bytes; + size_t size = sizeof(buf); + if (!g->allies->next) { + bytes = snprintf(buf, size, "%s hilft der Partei ", g->name); + } else { + bytes = snprintf(buf, size, "%s hilft den Parteien ", g->name); + } + size -= bytes; + show_allies(f, g->allies, buf + bytes, size); + rparagraph(F, buf, 0, 0, 0); + rnl(F); + } + g = g->next; + } +} + +static void +guards(FILE * F, const region * r, const faction * see) +{ + /* die Partei see sieht dies; wegen + * "unbekannte Partei", wenn man es selbst ist... */ + + faction* guardians[512]; + + int nextguard = 0; + + unit *u; + int i; + + boolean tarned = false; + /* Bewachung */ + + for (u = r->units; u; u = u->next) { + if (is_guard(u, GUARD_ALL)!=0) { + faction *f = u->faction; + faction *fv = visible_faction(see, u); + + if(fv != f && see != fv) { + f = fv; + } + + if (f != see && fval(u, UFL_ANON_FACTION)) { + tarned=true; + } else { + for (i=0;i!=nextguard;++i) if (guardians[i]==f) break; + if (i==nextguard) { + guardians[nextguard++] = f; + } + } + } + } + + if (nextguard || tarned) { + char buf[8192]; + char * bufp = buf; + size_t size = sizeof(buf) - 1; + int bytes; + + bytes = (int)strlcpy(bufp, "Die Region wird von ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + for (i = 0; i!=nextguard+(tarned?1:0); ++i) { + if (i!=0) { + if (i == nextguard-(tarned?0:1)) { + bytes = (int)strlcpy(bufp, LOC(see->locale, "list_and"), size); + } else { + bytes = (int)strlcpy(bufp, ", ", size); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (ilocale, "nr_addresses"), false); + rnl(F); + + while (flist!=NULL) { + const faction * f = flist->data; + if (!is_monsters(f)) { + char buf[8192]; + char label = '-'; + + sprintf(buf, "%s: %s; %s", factionname(f), f->email, f->banner?f->banner:""); + if (uf==f) label = '*'; + else if (ALLIED(uf, f)) label = 'o'; + else if (alliedfaction(NULL, uf, f, HELP_ALL)) label = '+'; + rparagraph(F, buf, 4, 0, label); + + } + flist = flist->next; + } + rnl(F); + rpline(F); +} + +static void +nr_ship(FILE * F, const seen_region * sr, const ship * sh, const faction * f, const unit * captain) +{ + const region * r = sr->r; + char buffer[8192], * bufp = buffer; + size_t size = sizeof(buffer) - 1; + int bytes; + char ch; + + rnl(F); + + if (captain && captain->faction == f) { + int n = 0, p = 0; + getshipweight(sh, &n, &p); + n = (n+99) / 100; /* 1 Silber = 1 GE */ + + bytes = snprintf(bufp, size, "%s, %s, (%d/%d)", shipname(sh), + LOC(f->locale, sh->type->name[0]), n, shipcapacity(sh) / 100); + } else { + bytes = snprintf(bufp, size, "%s, %s", shipname(sh), LOC(f->locale, sh->type->name[0])); + } + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + assert(sh->type->construction->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (sh->size!=sh->type->construction->maxsize) { + bytes = snprintf(bufp, size, ", %s (%d/%d)", + LOC(f->locale, "nr_undercons"), sh->size, + sh->type->construction->maxsize); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (sh->damage) { + int percent = (sh->damage*100+DAMAGE_SCALE-1)/(sh->size*DAMAGE_SCALE); + bytes = snprintf(bufp, size, ", %d%% %s", percent, LOC(f->locale, "nr_damaged")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (!fval(r->terrain, SEA_REGION)) { + if (sh->coast != NODIRECTION) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, coasts[sh->coast]), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + ch = 0; + if (sh->display && sh->display[0]) { + bytes = (int)strlcpy(bufp, "; ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, sh->display, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + ch = sh->display[strlen(sh->display) - 1]; + } + if (ch != '!' && ch != '?' && ch != '.') { + bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + *bufp = 0; + rparagraph(F, buffer, 2, 0, 0); + + nr_curses(F, f, sh, TYP_SHIP, 4); +} + +static void +nr_building(FILE *F, const seen_region * sr, const building * b, const faction * f) +{ + int i, bytes; + const char * name, * bname, * billusion = NULL; + const struct locale * lang = NULL; + char buffer[8192], * bufp = buffer; + size_t size = sizeof(buffer) - 1; + + rnl(F); + + if (f) lang = f->locale; + + bytes = snprintf(bufp, size, "%s, %s %d, ", buildingname(b), LOC(f->locale, "nr_size"), b->size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + report_building(b, &bname, &billusion); + name = LOC(lang, billusion?billusion:bname); + bytes = (int)strlcpy(bufp, name, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (billusion) { + unit * owner = building_owner(b); + if (owner && owner->faction==f) { + /* illusion. report real type */ + name = LOC(lang, bname); + bytes = snprintf(bufp, size, " (%s)", name); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + + if (b->size < b->type->maxsize) { + bytes = (int)strlcpy(bufp, " (im Bau)", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + if (b->besieged > 0 && sr->mode>=see_lighthouse) { + bytes = (int)strlcpy(bufp, ", belagert von ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, itoa10(b->besieged), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " Personen ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (b->besieged >= b->size * SIEGEFACTOR) { + bytes = (int)strlcpy(bufp, "(abgeschnitten)", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + i = 0; + if (b->display && b->display[0]) { + bytes = (int)strlcpy(bufp, "; ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, b->display, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + i = b->display[strlen(b->display) - 1]; + } + +#ifdef WDW_PYRAMID + + if (i != '!' && i != '?' && i != '.') { + scat(", "); + } + + if (b->type == bt_find("pyramid")) { + unit * owner = building_owner(b); + scat("Größenstufe "); + icat(wdw_pyramid_level(b)); + scat("."); + + if (owner && owner->faction==f) { + const construction *ctype = b->type->construction; + int completed = b->size; + int c; + + scat(" Baukosten pro Größenpunkt: "); + + while(ctype->improvement != NULL && + ctype->improvement != ctype && + ctype->maxsize > 0 && + ctype->maxsize <= completed) + { + completed -= ctype->maxsize; + ctype = ctype->improvement; + } + + assert(ctype->materials != NULL); + + for (c=0;ctype->materials[c].number;c++) { + const resource_type * rtype = ctype->materials[c].rtype; + int number = ctype->materials[c].number; + + if(c > 0) { + scat(", "); + } + icat(number); + scat(" "); + scat(locale_string(lang, resourcename(rtype, number!=1?GR_PLURAL:0))); + } + + scat("."); + + scat(" Erforderlicher Talentwert: "); + icat(b->type->construction->minskill); + scat("."); + } + } + +#else + + if (i != '!' && i != '?' && i != '.') { + bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + +#endif + *bufp = 0; + rparagraph(F, buffer, 2, 0, 0); + + if (sr->modelocale, bufp, size, f); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + msg_release(m); + + rparagraph(F, buf, 0, 0, 0); +} + +int +report_plaintext(const char * filename, report_context * ctx, const char * charset) +{ + int flag = 0; + char ch; + int anyunits, no_units, no_people; + const struct region *r; + faction * f = ctx->f; + unit *u; + char pzTime[64]; + attrib *a; + message * m; + unsigned char op; + int bytes, ix = want(O_STATISTICS); + int wants_stats = (f->options & ix); + FILE * F = fopen(filename, "wt"); + seen_region * sr = NULL; + char buf[8192]; + char * bufp; + int enc = xmlParseCharEncoding(charset); + size_t size; + + /* static variables can cope with writing for different turns */ + static int thisseason = -1; + static int nextseason = -1; + static int gamecookie = -1; + if (gamecookie!=global.cookie) { + gamedate date; + get_gamedate(turn+1, &date); + thisseason = date.season; + get_gamedate(turn+2, &date); + nextseason = date.season; + gamecookie = global.cookie; + } + + if (F==NULL) { + perror(filename); + return -1; + } + if (enc==XML_CHAR_ENCODING_UTF8) { + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + fwrite(utf8_bom, 1, 3, F); + } + + strftime(pzTime, 64, "%A, %d. %B %Y, %H:%M", localtime(&ctx->report_time)); + m = msg_message("nr_header_date", "game date", global.gamename, pzTime); + nr_render(m, f->locale, buf, sizeof(buf), f); + msg_release(m); + centre(F, buf, true); + + centre(F, gamedate_season(f->locale), true); + rnl(F); + sprintf(buf, "%s, %s/%s (%s)", factionname(f), + LOC(f->locale, rc_name(f->race, 1)), + LOC(f->locale, mkname("school", magic_school[f->magiegebiet])), + f->email); + centre(F, buf, true); + if (f_get_alliance(f)) { + centre(F, alliancename(f->alliance), true); + } + + if (f->age <= 2) { + const char * s; + if (f->age <= 1) { + ADDMSG(&f->msgs, msg_message("changepasswd", + "value", f->passw)); + } + RENDER(f, buf, sizeof(buf), ("newbie_password", "password", f->passw)); + rnl(F); + centre(F, buf, true); + s = locale_getstring(f->locale, "newbie_info_1"); + if (s) { + rnl(F); + centre(F, s, true); + } + s = locale_getstring(f->locale, "newbie_info_2"); + if (s) { + rnl(F); + centre(F, s, true); + } + if ((f->options & want(O_COMPUTER)) == 0) { + f->options |= want(O_COMPUTER); + s = locale_getstring(f->locale, "newbie_info_3"); + if (s) { + rnl(F); + centre(F, s, true); + } + } + } + rnl(F); +#if SCORE_MODULE + if (f->options & want(O_SCORE) && f->age > DISPLAYSCORE) { + RENDER(f, buf, sizeof(buf), ("nr_score", "score average", f->score, average_score_of_age(f->age, f->age / 24 + 1))); + centre(F, buf, true); + } +#endif +#ifdef COUNT_AGAIN + no_units = 0; + no_people = 0; + for (u=f->units;u;u=u->nextF) { + if (playerrace(u->race)) { + ++no_people; + no_units += u->number; + assert(f==u->faction); + } + } + if (no_units!=f->no_units) { + f->no_units = no_units; + } + if (no_people!=f->num_people) { + f->num_people = no_people; + } +#else + no_units = f->no_units; + no_people = f->num_people; +#endif + m = msg_message("nr_population", "population units", no_people, no_units); + nr_render(m, f->locale, buf, sizeof(buf), f); + msg_release(m); + centre(F, buf, true); + if (f->race == new_race[RC_HUMAN]) { + int maxmig = count_maxmigrants(f); + if (maxmig>0) { + m = msg_message("nr_migrants", "units maxunits", count_migrants(f), maxmig); + nr_render(m, f->locale, buf, sizeof(buf), f); + msg_release(m); + centre(F, buf, true); + } + } + if (f_get_alliance(f)) { + m = msg_message("nr_alliance", "leader name id age", alliance_get_leader(f->alliance), f->alliance->name, f->alliance->id, turn-f->alliance_joindate); + nr_render(m, f->locale, buf, sizeof(buf), f); + msg_release(m); + centre(F, buf, true); + } + { + int maxh = maxheroes(f); + if (maxh) { + message * msg = msg_message("nr_heroes", "units maxunits", countheroes(f), maxh); + nr_render(msg, f->locale, buf, sizeof(buf), f); + msg_release(msg); + centre(F, buf, true); + } + } + + if (f->items!=NULL) { + message * msg = msg_message("nr_claims", "items", f->items); + nr_render(msg, f->locale, buf, sizeof(buf), f); + msg_release(msg); + rnl(F); + centre(F, buf, true); + } + + /* Insekten-Winter-Warnung */ + if (f->race == new_race[RC_INSECT]) { + if (thisseason == 0) { + centre(F, LOC(f->locale, "nr_insectwinter"), true); + rnl(F); + } else { + if (nextseason == 0) { + centre(F, LOC(f->locale, "nr_insectfall"), true); + rnl(F); + } + } + } + + bufp = buf; + size = sizeof(buf) - 1; + bytes = snprintf(buf, size,"%s:", LOC(f->locale, "nr_options")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + for (op = 0; op != MAXOPTIONS; op++) { + if (f->options & want(op) && options[op]) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, options[op]), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + flag++; + } + } + if (flag > 0) { + rnl(F); + *bufp = 0; + centre(F, buf, true); + } + + rp_messages(F, f->msgs, f, 0, true); + rp_battles(F, f); + a = a_find(f->attribs, &at_reportspell); + if (a) { + rnl(F); + centre(F, LOC(f->locale, "section_newspells"), true); + while (a && a->type==&at_reportspell) { + spell *sp = (spell *)a->data.v; + nr_spell(F, sp, f->locale); + a = a->next; + } + } + + ch = 0; + for (a=a_find(f->attribs, &at_showitem);a && a->type==&at_showitem;a=a->next) { + const potion_type * ptype = resource2potion(((const item_type*)a->data.v)->rtype); + const char * description = NULL; + if (ptype!=NULL) { + const char * pname = resourcename(ptype->itype->rtype, 0); + + if (ch==0) { + rnl(F); + centre(F, LOC(f->locale, "section_newpotions"), true); + ch = 1; + } + + rnl(F); + centre(F, LOC(f->locale, pname), true); + snprintf(buf, sizeof(buf), "%s %d", LOC(f->locale, "nr_level"), ptype->level); + centre(F, buf, true); + rnl(F); + + bufp = buf; + size = sizeof(buf) - 1; + bytes = snprintf(bufp, size, "%s: ", LOC(f->locale, "nr_herbsrequired")); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (ptype->itype->construction) { + requirement * m = ptype->itype->construction->materials; + while (m->number) { + bytes = (int)strlcpy(bufp, LOC(f->locale, resourcename(m->rtype, 0)), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + ++m; + if (m->number) + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + *bufp = 0; + centre(F, buf, true); + rnl(F); + if (description==NULL) { + const char * potiontext = mkname("potion", pname); + description = LOC(f->locale, potiontext); + } + centre(F, description, true); + } + } + rnl(F); + centre(F, LOC(f->locale, "nr_alliances"), false); + rnl(F); + + allies(F, f); + + rpline(F); + + anyunits = 0; + + for (r=ctx->first;sr==NULL && r!=ctx->last;r=r->next) { + sr = find_seen(ctx->seen, r); + } + for (;sr!=NULL;sr=sr->next) { + region * r = sr->r; + int stealthmod = stealth_modifier(sr->mode); + building * b = r->buildings; + ship * sh = r->ships; + + if (sr->modemode==see_unit) { + anyunits = 1; + describe(F, sr, f); + if (markets_module() && r->land) { + const item_type * lux = r_luxury(r); + const item_type * herb = r->land->herbtype; + message * m = 0; + if (herb && lux) { + m = msg_message("nr_market_info_p", "p1 p2", + lux?lux->rtype:0, herb?herb->rtype:0); + } else if (lux || herb) { + m = msg_message("nr_market_info_s", "p1", + lux?lux->rtype:herb->rtype); + } + if (m) { + rnl(F); + nr_paragraph(F, m, f); + } + // + } else { + if (!fval(r->terrain, SEA_REGION) && rpeasants(r)/TRADE_FRACTION > 0) { + rnl(F); + prices(F, r, f); + } + } + guards(F, r, f); + durchreisende(F, r, f); + } + else { + if (sr->mode==see_far) { + describe(F, sr, f); + guards(F, r, f); + durchreisende(F, r, f); + } + else if (sr->mode==see_lighthouse) { + describe(F, sr, f); + durchreisende(F, r, f); + } else { + describe(F, sr, f); + durchreisende(F, r, f); + } + } + /* Statistik */ + + if (wants_stats && sr->mode==see_unit) + statistics(F, r, f); + + /* Nachrichten an REGION in der Region */ + + if (sr->mode==see_unit || sr->mode==see_travel) { + message_list * mlist = r_getmessages(r, f); + rp_messages(F, r->msgs, f, 0, true); + if (mlist) rp_messages(F, mlist, f, 0, true); + } + + /* report all units. they are pre-sorted in an efficient manner */ + u = r->units; + while (b) { + while (b && (!u || u->building!=b)) { + nr_building(F, sr, b, f); + b = b->next; + } + if (b) { + nr_building(F, sr, b, f); + while (u && u->building==b) { + nr_unit(F, f, u, 6, sr->mode); + u = u->next; + } + b = b->next; + } + } + while (u && !u->ship) { + if (stealthmod>INT_MIN) { + if (u->faction == f || cansee(f, r, u, stealthmod)) { + nr_unit(F, f, u, 4, sr->mode); + } + } + assert(!u->building); + u = u->next; + } + while (sh) { + while (sh && (!u || u->ship!=sh)) { + nr_ship(F, sr, sh, f, NULL); + sh = sh->next; + } + if (sh) { + nr_ship(F, sr, sh, f, u); + while (u && u->ship==sh) { + nr_unit(F, f, u, 6, sr->mode); + u = u->next; + } + sh = sh->next; + } + } + + assert(!u); + + rnl(F); + rpline(F); + } + if (!is_monsters(f)) { + if (!anyunits) { + rnl(F); + rparagraph(F, LOC(f->locale, "nr_youaredead"), 0, 2, 0); + } else { + list_address(F, f, ctx->addresses); + } + } + fclose(F); + return 0; +} + +void +base36conversion(void) +{ + region * r; + for (r=regions;r;r=r->next) { + unit * u; + for (u=r->units;u;u=u->next) { + if (forbiddenid(u->no)) { + uunhash(u); + u->no = newunitid(); + uhash(u); + } + } + } +} + +#define FMAXHASH 1021 + +struct fsee { + struct fsee * nexthash; + faction * f; + struct see { + struct see * next; + faction * seen; + unit * proof; + } * see; +} * fsee[FMAXHASH]; + +#define REPORT_NR (1 << O_REPORT) +#define REPORT_CR (1 << O_COMPUTER) +#define REPORT_ZV (1 << O_ZUGVORLAGE) +#define REPORT_ZIP (1 << O_COMPRESS) +#define REPORT_BZIP2 (1 << O_BZIP2) + + +unit * +can_find(faction * f, faction * f2) +{ + int key = f->no % FMAXHASH; + struct fsee * fs = fsee[key]; + struct see * ss; + if (f==f2) return f->units; + while (fs && fs->f!=f) fs=fs->nexthash; + if (!fs) return NULL; + ss=fs->see; + while (ss && ss->seen!=f2) ss=ss->next; + if (ss) { + /* bei TARNE PARTEI yxz muss die Partei von unit proof nicht + * wirklich Partei f2 sein! */ + /* assert(ss->proof->faction==f2); */ + return ss->proof; + } + return NULL; +} + +static void +add_find(faction * f, unit * u, faction *f2) +{ + /* faction f sees f2 through u */ + int key = f->no % FMAXHASH; + struct fsee ** fp = &fsee[key]; + struct fsee * fs; + struct see ** sp; + struct see * ss; + while (*fp && (*fp)->f!=f) fp=&(*fp)->nexthash; + if (!*fp) { + fs = *fp = calloc(sizeof(struct fsee), 1); + fs->f = f; + } else fs = *fp; + sp = &fs->see; + while (*sp && (*sp)->seen!=f2) sp=&(*sp)->next; + if (!*sp) { + ss = *sp = calloc(sizeof(struct see), 1); + ss->proof = u; + ss->seen = f2; + } else ss = *sp; + ss->proof = u; +} + +static void +update_find(void) +{ + region * r; + static boolean initial = true; + + if (initial) for (r=regions;r;r=r->next) { + unit * u; + for (u=r->units;u;u=u->next) { + faction * lastf = u->faction; + unit * u2; + for (u2=r->units;u2;u2=u2->next) { + if (u2->faction==lastf || u2->faction==u->faction) + continue; + if (seefaction(u->faction, r, u2, 0)) { + faction *fv = visible_faction(u->faction, u2); + lastf = fv; + add_find(u->faction, u2, fv); + } + } + } + } + initial = false; +} + +boolean +kann_finden(faction * f1, faction * f2) +{ + update_find(); + return (boolean)(can_find(f1, f2)!=NULL); +} + +/******* end summary ******/ + +void +register_nr(void) +{ + if (!nocr) register_reporttype("nr", &report_plaintext, 1<nexthash; + free(fsee[i]); + fsee[i] = fs; + } + } +} + diff --git a/src/gamecode/report.h b/src/gamecode/report.h index 7ff7564dc..e294adf6d 100644 --- a/src/gamecode/report.h +++ b/src/gamecode/report.h @@ -1,25 +1,25 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ -#ifndef H_GC_REPORT -#define H_GC_REPORT -#ifdef __cplusplus -extern "C" { -#endif - - extern void register_nr(void); - extern void report_cleanup(void); - -#ifdef __cplusplus -} -#endif -#endif - +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#ifndef H_GC_REPORT +#define H_GC_REPORT +#ifdef __cplusplus +extern "C" { +#endif + + extern void register_nr(void); + extern void report_cleanup(void); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/gamecode/spy.c b/src/gamecode/spy.c index 14aea1786..fe665bda8 100644 --- a/src/gamecode/spy.c +++ b/src/gamecode/spy.c @@ -1,482 +1,482 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "spy.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* attributes includes */ -#include - -/* util includes */ -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include - -#include - -/* in spy steht der Unterschied zwischen Wahrnehmung des Opfers und -* Spionage des Spions */ -void -spy_message(int spy, const unit *u, const unit *target) -{ - const char * str = report_kampfstatus(target, u->faction->locale); - - ADDMSG(&u->faction->msgs, msg_message("spyreport", "spy target status", u, target, str)); - if (spy > 20) { - sc_mage * mage = get_mage(target); - /* bei Magiern Zaubersprüche und Magiegebiet */ - if (mage) { - ADDMSG(&u->faction->msgs, msg_message("spyreport_mage", "target type", target, magic_school[mage->magietyp])); - } - } - if (spy > 6) { - faction * fv = visible_faction(u->faction,target); - if (fv && fv!=target->faction) { - /* wahre Partei */ - ADDMSG(&u->faction->msgs, msg_message("spyreport_faction", "target faction", target, target->faction)); - } - } - if (spy > 0) { - int first = 1; - int found = 0; - skill * sv; - char buf[4096]; - - buf[0] = 0; - for (sv = target->skills;sv!=target->skills+target->skill_size;++sv) { - if (sv->level>0) { - found++; - if (first == 1) { - first = 0; - } else { - strncat(buf, ", ", sizeof(buf)); - } - strncat(buf, (const char *)skillname(sv->id, u->faction->locale), sizeof(buf)); - strncat(buf, " ", sizeof(buf)); - strncat(buf, itoa10(eff_skill(target, sv->id, target->region)), sizeof(buf)); - } - } - if (found) { - ADDMSG(&u->faction->msgs, msg_message("spyreport_skills", "target skills", target, buf)); - } - - if (target->items) { - ADDMSG(&u->faction->msgs, msg_message("spyreport_items", "target items", target, target->items)); - } - } -} - - -int -spy_cmd(unit * u, struct order * ord) -{ - unit *target; - int spy, observe; - double spychance, observechance; - region * r = u->region; - - init_tokens(ord); - skip_token(); - target = getunit(r, u->faction); - - if (!target) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); - return 0; - } - if (!can_contact(r, u, target)) { - cmistake(u, u->thisorder, 24, MSG_EVENT); - return 0; - } - if (eff_skill(u, SK_SPY, r) < 1) { - cmistake(u, u->thisorder, 39, MSG_EVENT); - return 0; - } - /* Die Grundchance für einen erfolgreichen Spionage-Versuch ist 10%. - * Für jeden Talentpunkt, den das Spionagetalent das Tarnungstalent - * des Opfers übersteigt, erhöht sich dieses um 5%*/ - spy = eff_skill(u, SK_SPY, r) - eff_skill(target, SK_STEALTH, r); - spychance = 0.1 + MAX(spy*0.05, 0.0); - - if (chance(spychance)) { - produceexp(u, SK_SPY, u->number); - spy_message(spy, u, target); - } else { - ADDMSG(&u->faction->msgs, msg_message("spyfail", "spy target", u, target)); - } - - /* der Spion kann identifiziert werden, wenn das Opfer bessere - * Wahrnehmung als das Ziel Tarnung + Spionage/2 hat */ - observe = eff_skill(target, SK_PERCEPTION, r) - - (effskill(u, SK_STEALTH) + eff_skill(u, SK_SPY, r)/2); - - if (invisible(u, target) >= u->number) { - observe = MIN(observe, 0); - } - - /* Anschließend wird - unabhängig vom Erfolg - gewürfelt, ob der - * Spionageversuch bemerkt wurde. Die Wahrscheinlich dafür ist (100 - - * SpionageSpion*5 + WahrnehmungOpfer*2)%. */ - observechance = 1.0 - (eff_skill(u, SK_SPY, r) * 0.05) - + (eff_skill(target, SK_PERCEPTION, r) * 0.02); - - if (chance(observechance)) { - ADDMSG(&target->faction->msgs, msg_message("spydetect", - "spy target", observe>0?u:NULL, target)); - } - return 0; -} - -void -set_factionstealth(unit * u, faction * f) -{ - region * lastr = NULL; - /* for all units mu of our faction, check all the units in the region - * they are in, if their visible faction is f, it's ok. use lastr to - * avoid testing the same region twice in a row. */ - unit * mu = u->faction->units; - while (mu!=NULL) { - if (mu->number && mu->region!=lastr) { - unit * ru = mu->region->units; - lastr = mu->region; - while (ru!=NULL) { - if (ru->number) { - faction * fv = visible_faction(f, ru); - if (fv==f) { - if (cansee(f, lastr, ru, 0)) break; - } - } - ru = ru->next; - } - if (ru!=NULL) break; - } - mu = mu->nextF; - } - if (mu!=NULL) { - attrib * a = a_find(u->attribs, &at_otherfaction); - if (!a) a = a_add(&u->attribs, make_otherfaction(f)); - else a->data.v = f; - } -} - -int -setstealth_cmd(unit * u, struct order * ord) -{ - const char *s; - int level; - const race * trace; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - /* Tarne ohne Parameter: Setzt maximale Tarnung */ - - if (s == NULL || *s == 0) { - u_seteffstealth(u, -1); - return 0; - } - - trace = findrace(s, u->faction->locale); - if (trace) { - /* Dämonen können sich nur als andere Spielerrassen tarnen */ - if (u->race == new_race[RC_DAEMON]) { - race_t allowed[] = { RC_DWARF, RC_ELF, RC_ORC, RC_GOBLIN, RC_HUMAN, - RC_TROLL, RC_DAEMON, RC_INSECT, RC_HALFLING, RC_CAT, RC_AQUARIAN, - NORACE }; - int i; - for (i=0;allowed[i]!=NORACE;++i) if (new_race[allowed[i]]==trace) break; - if (new_race[allowed[i]]==trace) { - u->irace = trace; - if (u->race->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs)) - set_racename(&u->attribs, NULL); - } - return 0; - } - - /* Singdrachen können sich nur als Drachen tarnen */ - if (u->race == new_race[RC_SONGDRAGON] || u->race == new_race[RC_BIRTHDAYDRAGON]) { - if (trace==new_race[RC_SONGDRAGON]||trace==new_race[RC_FIREDRAGON]||trace==new_race[RC_DRAGON]||trace==new_race[RC_WYRM]) { - u->irace = trace; - if (u->race->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs)) - set_racename(&u->attribs, NULL); - } - return 0; - } - - /* Dämomen und Illusionsparteien können sich als andere race tarnen */ - if (u->race->flags & RCF_SHAPESHIFT) { - if (playerrace(trace)) { - u->irace = trace; - if ((u->race->flags & RCF_SHAPESHIFTANY) && get_racename(u->attribs)) - set_racename(&u->attribs, NULL); - } - } - return 0; - } - - switch(findparam(s, u->faction->locale)) { - case P_FACTION: - /* TARNE PARTEI [NICHT|NUMMER abcd] */ - if (!rule_stealth_faction()) break; - s = getstrtoken(); - if(!s || *s == 0) { - fset(u, UFL_ANON_FACTION); - } else if (findparam(s, u->faction->locale) == P_NOT) { - freset(u, UFL_ANON_FACTION); - } else if (findkeyword(s, u->faction->locale) == K_NUMBER) { - const char *s2 = (const char *)getstrtoken(); - int nr = -1; - - if (s2) nr = atoi36(s2); - if (!s2 || *s2 == 0 || nr == u->faction->no) { - a_removeall(&u->attribs, &at_otherfaction); - } else { - struct faction * f = findfaction(nr); - if (f==NULL) { - cmistake(u, ord, 66, MSG_EVENT); - } else { - set_factionstealth(u, f); - } - } - } else { - cmistake(u, ord, 289, MSG_EVENT); - } - break; - case P_ANY: - /* TARNE ALLES (was nicht so alles geht?) */ - u_seteffstealth(u, -1); - break; - case P_NOT: - u_seteffstealth(u, -1); - break; - default: - if (isdigit(s[0])) { - /* Tarnungslevel setzen */ - level = atoi((const char *)s); - if (level > effskill(u, SK_STEALTH)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_lowstealth", "")); - return 0; - } - u_seteffstealth(u, level); - } else if (u->race->flags & RCF_SHAPESHIFTANY) { - set_racename(&u->attribs, s); - } - } - return 0; -} - -static int -crew_skill(region * r, faction * f, ship * sh, skill_t sk) -{ - int value = 0; - unit *u; - - for (u=r->units;u;u=u->next) { - if (u->ship == sh && u->faction == f) { - int s = eff_skill(u, sk, r); - value = MAX(s, value); - } - } - return value; -} - -static int -try_destruction(unit * u, unit * u2, const ship *sh, int skilldiff) -{ - const char *destruction_success_msg = "destroy_ship_0"; - const char *destruction_failed_msg = "destroy_ship_1"; - const char *destruction_detected_msg = "destroy_ship_2"; - const char *detect_failure_msg = "destroy_ship_3"; - const char *object_destroyed_msg = "destroy_ship_4"; - - if (skilldiff == 0) { - /* tell the unit that the attempt failed: */ - ADDMSG(&u->faction->msgs, msg_message(destruction_failed_msg, "ship unit", sh, u)); - /* tell the enemy about the attempt: */ - if (u2) { - ADDMSG(&u2->faction->msgs, msg_message(detect_failure_msg, "ship", sh)); - } - return 0; - } else if (skilldiff < 0) { - /* tell the unit that the attempt was detected: */ - ADDMSG(&u2->faction->msgs, msg_message(destruction_detected_msg, "ship unit", sh, u)); - /* tell the enemy whodunit: */ - if (u2) { - ADDMSG(&u2->faction->msgs, msg_message(detect_failure_msg, "ship", sh)); - } - return 0; - } else { - /* tell the unit that the attempt succeeded */ - ADDMSG(&u->faction->msgs, msg_message(destruction_success_msg, "ship unit", sh, u)); - if (u2) { - ADDMSG(&u2->faction->msgs, msg_message(object_destroyed_msg, "ship", sh)); - } - } - return 1; /* success */ -} - -static void -sink_ship(region * r, ship * sh, const char *name, unit * saboteur) -{ - unit **ui, *u; - region *safety = r; - int i; - direction_t d; - double probability = 0.0; - message * sink_msg = NULL; - faction * f; - - for (f=NULL,u=r->units;u;u=u->next) { - /* slight optimization to avoid dereferencing u->faction each time */ - if (f!=u->faction) { - f = u->faction; - freset(f, FFL_SELECT); - } - } - - /* figure out what a unit's chances of survival are: */ - if (!fval(r->terrain, SEA_REGION)) { - probability = CANAL_SWIMMER_CHANCE; - } else { - for (d = 0; d != MAXDIRECTIONS; ++d) { - region * rn = rconnect(r, d); - if (!fval(rn->terrain, SEA_REGION) && !move_blocked(NULL, r, rn)) { - safety = rn; - probability = OCEAN_SWIMMER_CHANCE; - break; - } - } - } - for (ui = &r->units; *ui; ui = &(*ui)->next) { - unit *u = *ui; - - /* inform this faction about the sinking ship: */ - if (!fval(u->faction, FFL_SELECT)) { - fset(u->faction, FFL_SELECT); - if (sink_msg==NULL) { - sink_msg = msg_message("sink_msg", "ship region", sh, r); - } - add_message(&f->msgs, sink_msg); - } - - if (u->ship == sh) { - int dead = 0; - message * msg; - - /* if this fails, I misunderstood something: */ - for (i = 0; i != u->number; ++i) - if (chance(probability)) - ++dead; - - if (dead != u->number) { - /* she will live. but her items get stripped */ - if (dead > 0) { - msg = msg_message("sink_lost_msg", "dead region unit", dead, safety, u); - } else { - msg = msg_message("sink_saved_msg", "region unit", safety, u); - } - set_leftship(u, u->ship); - u->ship = 0; - if (r != safety) { - setguard(u, GUARD_NONE); - } - while (u->items) { - i_remove(&u->items, u->items); - } - move_unit(u, safety, NULL); - } else { - msg = msg_message("sink_lost_msg", "dead region unit", dead, NULL, u); - } - add_message(&u->faction->msgs, msg); - msg_release(msg); - if (dead == u->number) { - /* the poor creature, she dies */ - if (remove_unit(ui, u)!=0) { - ui = &u->next; - } - } - } - } - if (sink_msg) msg_release(sink_msg); - /* finally, get rid of the ship */ - remove_ship(&sh->region->ships, sh); -} - -int -sabotage_cmd(unit * u, struct order * ord) -{ - const char *s; - int i; - ship *sh; - unit *u2; - char buffer[DISPLAYSIZE]; - region * r = u->region; - int skdiff; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - i = findparam(s, u->faction->locale); - - switch (i) { - case P_SHIP: - sh = u->ship; - if (!sh) { - cmistake(u, u->thisorder, 144, MSG_EVENT); - return 0; - } - u2 = shipowner(sh); - skdiff = eff_skill(u, SK_SPY, r)-crew_skill(r, u2->faction, sh, SK_PERCEPTION); - if (try_destruction(u, u2, sh, skdiff)) { - sink_ship(r, sh, buffer, u); - } - break; - default: - cmistake(u, u->thisorder, 9, MSG_EVENT); - return 0; - } - - return 0; -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "spy.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* attributes includes */ +#include + +/* util includes */ +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +#include + +/* in spy steht der Unterschied zwischen Wahrnehmung des Opfers und +* Spionage des Spions */ +void +spy_message(int spy, const unit *u, const unit *target) +{ + const char * str = report_kampfstatus(target, u->faction->locale); + + ADDMSG(&u->faction->msgs, msg_message("spyreport", "spy target status", u, target, str)); + if (spy > 20) { + sc_mage * mage = get_mage(target); + /* bei Magiern Zaubersprüche und Magiegebiet */ + if (mage) { + ADDMSG(&u->faction->msgs, msg_message("spyreport_mage", "target type", target, magic_school[mage->magietyp])); + } + } + if (spy > 6) { + faction * fv = visible_faction(u->faction,target); + if (fv && fv!=target->faction) { + /* wahre Partei */ + ADDMSG(&u->faction->msgs, msg_message("spyreport_faction", "target faction", target, target->faction)); + } + } + if (spy > 0) { + int first = 1; + int found = 0; + skill * sv; + char buf[4096]; + + buf[0] = 0; + for (sv = target->skills;sv!=target->skills+target->skill_size;++sv) { + if (sv->level>0) { + found++; + if (first == 1) { + first = 0; + } else { + strncat(buf, ", ", sizeof(buf)); + } + strncat(buf, (const char *)skillname(sv->id, u->faction->locale), sizeof(buf)); + strncat(buf, " ", sizeof(buf)); + strncat(buf, itoa10(eff_skill(target, sv->id, target->region)), sizeof(buf)); + } + } + if (found) { + ADDMSG(&u->faction->msgs, msg_message("spyreport_skills", "target skills", target, buf)); + } + + if (target->items) { + ADDMSG(&u->faction->msgs, msg_message("spyreport_items", "target items", target, target->items)); + } + } +} + + +int +spy_cmd(unit * u, struct order * ord) +{ + unit *target; + int spy, observe; + double spychance, observechance; + region * r = u->region; + + init_tokens(ord); + skip_token(); + target = getunit(r, u->faction); + + if (!target) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); + return 0; + } + if (!can_contact(r, u, target)) { + cmistake(u, u->thisorder, 24, MSG_EVENT); + return 0; + } + if (eff_skill(u, SK_SPY, r) < 1) { + cmistake(u, u->thisorder, 39, MSG_EVENT); + return 0; + } + /* Die Grundchance für einen erfolgreichen Spionage-Versuch ist 10%. + * Für jeden Talentpunkt, den das Spionagetalent das Tarnungstalent + * des Opfers übersteigt, erhöht sich dieses um 5%*/ + spy = eff_skill(u, SK_SPY, r) - eff_skill(target, SK_STEALTH, r); + spychance = 0.1 + MAX(spy*0.05, 0.0); + + if (chance(spychance)) { + produceexp(u, SK_SPY, u->number); + spy_message(spy, u, target); + } else { + ADDMSG(&u->faction->msgs, msg_message("spyfail", "spy target", u, target)); + } + + /* der Spion kann identifiziert werden, wenn das Opfer bessere + * Wahrnehmung als das Ziel Tarnung + Spionage/2 hat */ + observe = eff_skill(target, SK_PERCEPTION, r) + - (effskill(u, SK_STEALTH) + eff_skill(u, SK_SPY, r)/2); + + if (invisible(u, target) >= u->number) { + observe = MIN(observe, 0); + } + + /* Anschließend wird - unabhängig vom Erfolg - gewürfelt, ob der + * Spionageversuch bemerkt wurde. Die Wahrscheinlich dafür ist (100 - + * SpionageSpion*5 + WahrnehmungOpfer*2)%. */ + observechance = 1.0 - (eff_skill(u, SK_SPY, r) * 0.05) + + (eff_skill(target, SK_PERCEPTION, r) * 0.02); + + if (chance(observechance)) { + ADDMSG(&target->faction->msgs, msg_message("spydetect", + "spy target", observe>0?u:NULL, target)); + } + return 0; +} + +void +set_factionstealth(unit * u, faction * f) +{ + region * lastr = NULL; + /* for all units mu of our faction, check all the units in the region + * they are in, if their visible faction is f, it's ok. use lastr to + * avoid testing the same region twice in a row. */ + unit * mu = u->faction->units; + while (mu!=NULL) { + if (mu->number && mu->region!=lastr) { + unit * ru = mu->region->units; + lastr = mu->region; + while (ru!=NULL) { + if (ru->number) { + faction * fv = visible_faction(f, ru); + if (fv==f) { + if (cansee(f, lastr, ru, 0)) break; + } + } + ru = ru->next; + } + if (ru!=NULL) break; + } + mu = mu->nextF; + } + if (mu!=NULL) { + attrib * a = a_find(u->attribs, &at_otherfaction); + if (!a) a = a_add(&u->attribs, make_otherfaction(f)); + else a->data.v = f; + } +} + +int +setstealth_cmd(unit * u, struct order * ord) +{ + const char *s; + int level; + const race * trace; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + /* Tarne ohne Parameter: Setzt maximale Tarnung */ + + if (s == NULL || *s == 0) { + u_seteffstealth(u, -1); + return 0; + } + + trace = findrace(s, u->faction->locale); + if (trace) { + /* Dämonen können sich nur als andere Spielerrassen tarnen */ + if (u->race == new_race[RC_DAEMON]) { + race_t allowed[] = { RC_DWARF, RC_ELF, RC_ORC, RC_GOBLIN, RC_HUMAN, + RC_TROLL, RC_DAEMON, RC_INSECT, RC_HALFLING, RC_CAT, RC_AQUARIAN, + NORACE }; + int i; + for (i=0;allowed[i]!=NORACE;++i) if (new_race[allowed[i]]==trace) break; + if (new_race[allowed[i]]==trace) { + u->irace = trace; + if (u->race->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs)) + set_racename(&u->attribs, NULL); + } + return 0; + } + + /* Singdrachen können sich nur als Drachen tarnen */ + if (u->race == new_race[RC_SONGDRAGON] || u->race == new_race[RC_BIRTHDAYDRAGON]) { + if (trace==new_race[RC_SONGDRAGON]||trace==new_race[RC_FIREDRAGON]||trace==new_race[RC_DRAGON]||trace==new_race[RC_WYRM]) { + u->irace = trace; + if (u->race->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs)) + set_racename(&u->attribs, NULL); + } + return 0; + } + + /* Dämomen und Illusionsparteien können sich als andere race tarnen */ + if (u->race->flags & RCF_SHAPESHIFT) { + if (playerrace(trace)) { + u->irace = trace; + if ((u->race->flags & RCF_SHAPESHIFTANY) && get_racename(u->attribs)) + set_racename(&u->attribs, NULL); + } + } + return 0; + } + + switch(findparam(s, u->faction->locale)) { + case P_FACTION: + /* TARNE PARTEI [NICHT|NUMMER abcd] */ + if (!rule_stealth_faction()) break; + s = getstrtoken(); + if(!s || *s == 0) { + fset(u, UFL_ANON_FACTION); + } else if (findparam(s, u->faction->locale) == P_NOT) { + freset(u, UFL_ANON_FACTION); + } else if (findkeyword(s, u->faction->locale) == K_NUMBER) { + const char *s2 = (const char *)getstrtoken(); + int nr = -1; + + if (s2) nr = atoi36(s2); + if (!s2 || *s2 == 0 || nr == u->faction->no) { + a_removeall(&u->attribs, &at_otherfaction); + } else { + struct faction * f = findfaction(nr); + if (f==NULL) { + cmistake(u, ord, 66, MSG_EVENT); + } else { + set_factionstealth(u, f); + } + } + } else { + cmistake(u, ord, 289, MSG_EVENT); + } + break; + case P_ANY: + /* TARNE ALLES (was nicht so alles geht?) */ + u_seteffstealth(u, -1); + break; + case P_NOT: + u_seteffstealth(u, -1); + break; + default: + if (isdigit(s[0])) { + /* Tarnungslevel setzen */ + level = atoi((const char *)s); + if (level > effskill(u, SK_STEALTH)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_lowstealth", "")); + return 0; + } + u_seteffstealth(u, level); + } else if (u->race->flags & RCF_SHAPESHIFTANY) { + set_racename(&u->attribs, s); + } + } + return 0; +} + +static int +crew_skill(region * r, faction * f, ship * sh, skill_t sk) +{ + int value = 0; + unit *u; + + for (u=r->units;u;u=u->next) { + if (u->ship == sh && u->faction == f) { + int s = eff_skill(u, sk, r); + value = MAX(s, value); + } + } + return value; +} + +static int +try_destruction(unit * u, unit * u2, const ship *sh, int skilldiff) +{ + const char *destruction_success_msg = "destroy_ship_0"; + const char *destruction_failed_msg = "destroy_ship_1"; + const char *destruction_detected_msg = "destroy_ship_2"; + const char *detect_failure_msg = "destroy_ship_3"; + const char *object_destroyed_msg = "destroy_ship_4"; + + if (skilldiff == 0) { + /* tell the unit that the attempt failed: */ + ADDMSG(&u->faction->msgs, msg_message(destruction_failed_msg, "ship unit", sh, u)); + /* tell the enemy about the attempt: */ + if (u2) { + ADDMSG(&u2->faction->msgs, msg_message(detect_failure_msg, "ship", sh)); + } + return 0; + } else if (skilldiff < 0) { + /* tell the unit that the attempt was detected: */ + ADDMSG(&u2->faction->msgs, msg_message(destruction_detected_msg, "ship unit", sh, u)); + /* tell the enemy whodunit: */ + if (u2) { + ADDMSG(&u2->faction->msgs, msg_message(detect_failure_msg, "ship", sh)); + } + return 0; + } else { + /* tell the unit that the attempt succeeded */ + ADDMSG(&u->faction->msgs, msg_message(destruction_success_msg, "ship unit", sh, u)); + if (u2) { + ADDMSG(&u2->faction->msgs, msg_message(object_destroyed_msg, "ship", sh)); + } + } + return 1; /* success */ +} + +static void +sink_ship(region * r, ship * sh, const char *name, unit * saboteur) +{ + unit **ui, *u; + region *safety = r; + int i; + direction_t d; + double probability = 0.0; + message * sink_msg = NULL; + faction * f; + + for (f=NULL,u=r->units;u;u=u->next) { + /* slight optimization to avoid dereferencing u->faction each time */ + if (f!=u->faction) { + f = u->faction; + freset(f, FFL_SELECT); + } + } + + /* figure out what a unit's chances of survival are: */ + if (!fval(r->terrain, SEA_REGION)) { + probability = CANAL_SWIMMER_CHANCE; + } else { + for (d = 0; d != MAXDIRECTIONS; ++d) { + region * rn = rconnect(r, d); + if (!fval(rn->terrain, SEA_REGION) && !move_blocked(NULL, r, rn)) { + safety = rn; + probability = OCEAN_SWIMMER_CHANCE; + break; + } + } + } + for (ui = &r->units; *ui; ui = &(*ui)->next) { + unit *u = *ui; + + /* inform this faction about the sinking ship: */ + if (!fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + if (sink_msg==NULL) { + sink_msg = msg_message("sink_msg", "ship region", sh, r); + } + add_message(&f->msgs, sink_msg); + } + + if (u->ship == sh) { + int dead = 0; + message * msg; + + /* if this fails, I misunderstood something: */ + for (i = 0; i != u->number; ++i) + if (chance(probability)) + ++dead; + + if (dead != u->number) { + /* she will live. but her items get stripped */ + if (dead > 0) { + msg = msg_message("sink_lost_msg", "dead region unit", dead, safety, u); + } else { + msg = msg_message("sink_saved_msg", "region unit", safety, u); + } + set_leftship(u, u->ship); + u->ship = 0; + if (r != safety) { + setguard(u, GUARD_NONE); + } + while (u->items) { + i_remove(&u->items, u->items); + } + move_unit(u, safety, NULL); + } else { + msg = msg_message("sink_lost_msg", "dead region unit", dead, NULL, u); + } + add_message(&u->faction->msgs, msg); + msg_release(msg); + if (dead == u->number) { + /* the poor creature, she dies */ + if (remove_unit(ui, u)!=0) { + ui = &u->next; + } + } + } + } + if (sink_msg) msg_release(sink_msg); + /* finally, get rid of the ship */ + remove_ship(&sh->region->ships, sh); +} + +int +sabotage_cmd(unit * u, struct order * ord) +{ + const char *s; + int i; + ship *sh; + unit *u2; + char buffer[DISPLAYSIZE]; + region * r = u->region; + int skdiff; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + i = findparam(s, u->faction->locale); + + switch (i) { + case P_SHIP: + sh = u->ship; + if (!sh) { + cmistake(u, u->thisorder, 144, MSG_EVENT); + return 0; + } + u2 = shipowner(sh); + skdiff = eff_skill(u, SK_SPY, r)-crew_skill(r, u2->faction, sh, SK_PERCEPTION); + if (try_destruction(u, u2, sh, skdiff)) { + sink_ship(r, sh, buffer, u); + } + break; + default: + cmistake(u, u->thisorder, 9, MSG_EVENT); + return 0; + } + + return 0; +} + diff --git a/src/gamecode/spy.h b/src/gamecode/spy.h index 6d039ebd7..6c56eaa53 100644 --- a/src/gamecode/spy.h +++ b/src/gamecode/spy.h @@ -1,40 +1,40 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_SPY -#define H_KRNL_SPY -#ifdef __cplusplus -extern "C" { -#endif - -struct unit; -struct region; -struct strlist; - -extern int setstealth_cmd(struct unit * u, struct order * ord); -extern int spy_cmd(struct unit * u, struct order * ord); -extern int sabotage_cmd(struct unit * u, struct order * ord); -extern void spy_message(int spy, const struct unit *u, const struct unit *target); - -#define OCEAN_SWIMMER_CHANCE 0.1 -#define CANAL_SWIMMER_CHANCE 0.9 - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_SPY +#define H_KRNL_SPY +#ifdef __cplusplus +extern "C" { +#endif + +struct unit; +struct region; +struct strlist; + +extern int setstealth_cmd(struct unit * u, struct order * ord); +extern int spy_cmd(struct unit * u, struct order * ord); +extern int sabotage_cmd(struct unit * u, struct order * ord); +extern void spy_message(int spy, const struct unit *u, const struct unit *target); + +#define OCEAN_SWIMMER_CHANCE 0.1 +#define CANAL_SWIMMER_CHANCE 0.9 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gamecode/study.c b/src/gamecode/study.c index 38444e69a..32911c286 100644 --- a/src/gamecode/study.c +++ b/src/gamecode/study.c @@ -1,793 +1,793 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#define TEACH_ALL 1 -#define TEACH_FRIENDS - -#include -#include -#include "study.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include - -#define TEACHNUMBER 10 - -static skill_t -getskill(const struct locale * lang) -{ - return findskill(getstrtoken(), lang); -} - -magic_t -getmagicskill(const struct locale * lang) -{ - struct tnode * tokens = get_translations(lang, UT_MAGIC); - variant token; - const char * s = getstrtoken(); - - if (s && s[0]) { - if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { - return (magic_t)token.i; - } else { - char buffer[3]; - buffer[0] = s[0]; - buffer[1] = s[1]; - buffer[2] = '\0'; - if (findtoken(tokens, buffer, &token)==E_TOK_SUCCESS) { - return (magic_t)token.i; - } - } - } - return M_NONE; -} - -/* ------------------------------------------------------------- */ -/* Vertraute und Kröten sind keine Migranten */ -boolean -is_migrant(unit *u) -{ - if (u->race == u->faction->race) return false; - - if (fval(u->race, RCF_UNDEAD|RCF_ILLUSIONARY)) return false; - if (is_familiar(u)) return false; - if (u->race == new_race[RC_TOAD]) return false; - - return true; -} - -/* ------------------------------------------------------------- */ -boolean -magic_lowskill(unit *u) -{ - if (u->race == new_race[RC_TOAD]) return true; - return false; -} - -/* ------------------------------------------------------------- */ - -int -study_cost(unit *u, skill_t sk) -{ - static int cost[MAXSKILLS]; - int stufe, k = 50; - - if (cost[sk]==0) { - char buffer[256]; - sprintf(buffer, "skills.cost.%s", skillnames[sk]); - cost[sk] = get_param_int(global.parameters, buffer, -1); - } - if (cost[sk]>=0) return cost[sk]; - - switch (sk) { - case SK_SPY: - return 100; - break; - case SK_TACTICS: - case SK_HERBALISM: - case SK_ALCHEMY: - return 200; - break; - case SK_MAGIC: /* Die Magiekosten betragen 50+Summe(50*Stufe) */ - /* 'Stufe' ist dabei die nächste zu erreichende Stufe */ - stufe = 1 + get_level(u, SK_MAGIC); - return k*(1+((stufe+1)*stufe/2)); - break; - } - return 0; -} - -/* ------------------------------------------------------------- */ - -static void -init_learning(struct attrib * a) -{ - a->data.v = calloc(sizeof(teaching_info), 1); -} - -static void -done_learning(struct attrib * a) -{ - free(a->data.v); -} - -const attrib_type at_learning = { - "learning", - init_learning, done_learning, NULL, NULL, NULL, - ATF_UNIQUE -}; - -static int -study_days(unit * student, skill_t sk) -{ - int speed = 30; - if (student->race->study_speed) { - speed += student->race->study_speed[sk]; - if (speed<30) { - skill * sv = get_skill(student, sk); - if (sv==0) { - speed = 30; - } - } - } - return student->number * speed; -} - -static int -teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, - boolean report, int * academy) -{ - teaching_info * teach = NULL; - attrib * a; - int n; - - /* learning sind die Tage, die sie schon durch andere Lehrer zugute - * geschrieben bekommen haben. Total darf dies nicht über 30 Tage pro Mann - * steigen. - * - * n ist die Anzahl zusätzlich gelernter Tage. n darf max. die Differenz - * von schon gelernten Tagen zum MAX(30 Tage pro Mann) betragen. */ - - if (magic_lowskill(student)){ - cmistake(teacher, teacher->thisorder, 292, MSG_EVENT); - return 0; - } - - n = 30; - a = a_find(student->attribs, &at_learning); - if (a!=NULL) { - teach = (teaching_info*)a->data.v; - n -= teach->value; - } - - n = MIN(n, nteaching); - - if (n != 0) { - struct building * b = inside_building(teacher); - const struct building_type * btype = b?b->type:NULL; - int index = 0; - - if (teach==NULL) { - a = a_add(&student->attribs, a_new(&at_learning)); - teach = (teaching_info*)a->data.v; - } else { - while (teach->teachers[index] && index!=MAXTEACHERS) ++index; - } - if (indexteachers[index++] = teacher; - if (indexteachers[index] = NULL; - teach->value += n; - - /* Solange Akademien größenbeschränkt sind, sollte Lehrer und - * Student auch in unterschiedlichen Gebäuden stehen dürfen */ - if (btype == bt_find("academy") - && student->building && student->building->type == bt_find("academy")) - { - int j = study_cost(student, sk); - j = MAX(50, j * 2); - /* kann Einheit das zahlen? */ - if (get_pooled(student, oldresourcetype[R_SILVER], GET_DEFAULT, j) >= j) { - /* Jeder Schüler zusätzlich +10 Tage wenn in Uni. */ - teach->value += (n / 30) * 10; /* learning erhöhen */ - /* Lehrer zusätzlich +1 Tag pro Schüler. */ - if (academy) *academy += n; - } /* sonst nehmen sie nicht am Unterricht teil */ - } - - /* Teaching ist die Anzahl Leute, denen man noch was beibringen kann. Da - * hier nicht n verwendet wird, werden die Leute gezählt und nicht die - * effektiv gelernten Tage. -> FALSCH ? (ENNO) - * - * Eine Einheit A von 11 Mann mit Talent 0 profitiert vom ersten Lehrer B - * also 10x30=300 tage, und der zweite Lehrer C lehrt für nur noch 1x30=30 - * Tage (damit das Maximum von 11x30=330 nicht überschritten wird). - * - * Damit es aber in der Ausführung nicht auf die Reihenfolge drauf ankommt, - * darf der zweite Lehrer C keine weiteren Einheiten D mehr lehren. Also - * wird student 30 Tage gutgeschrieben, aber teaching sinkt auf 0 (300-11x30 <= - * 0). - * - * Sonst träte dies auf: - * - * A: lernt B: lehrt A C: lehrt A D D: lernt - * - * Wenn B vor C dran ist, lehrt C nur 30 Tage an A (wie oben) und - * 270 Tage an D. - * - * Ist C aber vor B dran, lehrt C 300 tage an A, und 0 tage an D, - * und B lehrt auch 0 tage an A. - * - * Deswegen darf C D nie lehren dürfen. - * - * -> Das ist wirr. wer hat das entworfen? - * Besser wäre, man macht erst vorab alle zuordnungen, und dann - * die Talentänderung (enno). - */ - - nteaching = MAX(0, nteaching - student->number * 30); - - } - return n; -} - -int -teach_cmd(unit * u, struct order * ord) -{ - static const curse_type * gbdream_ct = NULL; - plane * pl; - region * r = u->region; - int teaching, i, j, count, academy=0; - unit *u2; - skill_t sk = NOSKILL; - - if (gbdream_ct==0) gbdream_ct = ct_find("gbdream"); - if (gbdream_ct) { - if (get_curse(u->region->attribs, gbdream_ct)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "gbdream_noteach", "")); - return 0; - } - } - - if ((u->race->flags & RCF_NOTEACH) || fval(u, UFL_WERE)) { - cmistake(u, ord, 274, MSG_EVENT); - return 0; - } - - pl = rplane(r); - if (pl && fval(pl, PFL_NOTEACH)) { - cmistake(u, ord, 273, MSG_EVENT); - return 0; - } - - teaching = u->number * 30 * TEACHNUMBER; - - if ((i = get_effect(u, oldpotiontype[P_FOOL])) > 0) { /* Trank "Dumpfbackenbrot" */ - i = MIN(i, u->number * TEACHNUMBER); - /* Trank wirkt pro Schüler, nicht pro Lehrer */ - teaching -= i * 30; - change_effect(u, oldpotiontype[P_FOOL], -i); - j = teaching / 30; - ADDMSG(&u->faction->msgs, msg_message("teachdumb", - "teacher amount", u, j)); - } - if (teaching == 0) return 0; - - - u2 = 0; - count = 0; - - init_tokens(ord); - skip_token(); - -#if TEACH_ALL - if (getparam(u->faction->locale)==P_ANY) { - unit * student = r->units; - skill_t teachskill[MAXSKILLS]; - int i = 0; - do { - sk = getskill(u->faction->locale); - teachskill[i++]=sk; - } while (sk!=NOSKILL); - while (teaching && student) { - if (student->faction == u->faction) { -#ifdef NEW_DAEMONHUNGER_RULE - if (LongHunger(student)) continue; -#else - if (fval(student, UFL_HUNGER)) continue; -#endif - if (get_keyword(student->thisorder) == K_STUDY) { - /* Input ist nun von student->thisorder !! */ - init_tokens(student->thisorder); - skip_token(); - sk = getskill(student->faction->locale); - if (sk!=NOSKILL && teachskill[0]!=NOSKILL) { - for (i=0;teachskill[i]!=NOSKILL;++i) if (sk==teachskill[i]) break; - sk = teachskill[i]; - } - if (sk != NOSKILL && eff_skill_study(u, sk, r)-TEACHDIFFERENCE > eff_skill_study(student, sk, r)) { - teaching -= teach_unit(u, student, teaching, sk, true, &academy); - } - } - } - student = student->next; - } -#ifdef TEACH_FRIENDS - while (teaching && student) { - if (student->faction != u->faction && alliedunit(u, student->faction, HELP_GUARD)) { -#ifdef NEW_DAEMONHUNGER_RULE - if (LongHunger(student)) continue; -#else - if (fval(student, UFL_HUNGER)) continue; -#endif - if (get_keyword(student->thisorder) == K_STUDY) { - /* Input ist nun von student->thisorder !! */ - init_tokens(student->thisorder); - skip_token(); - sk = getskill(student->faction->locale); - if (sk != NOSKILL && eff_skill_study(u, sk, r)-TEACHDIFFERENCE >= eff_skill(student, sk, r)) { - teaching -= teach_unit(u, student, teaching, sk, true, &academy); - } - } - } - student = student->next; - } -#endif - } - else -#endif - { - char zOrder[4096]; - order * new_order; - - zOrder[0] = '\0'; - init_tokens(ord); - skip_token(); - - while (!parser_end()) { - unit * u2 = getunit(r, u->faction); - boolean feedback; - ++count; - - /* Falls die Unit nicht gefunden wird, Fehler melden */ - - if (!u2) { - char tbuf[20]; - const char * uid; - const char * token; - /* Finde den string, der den Fehler verursacht hat */ - parser_pushstate(); - init_tokens(ord); - skip_token(); - - for (j=0; j!=count-1; ++j) { - /* skip over the first 'count' units */ - getunit(r, u->faction); - } - - token = getstrtoken(); - - /* Beginne die Fehlermeldung */ - if (findparam(token, u->faction->locale) != P_TEMP) { - uid = token; - } else { - token = getstrtoken(); - sprintf(tbuf, "%s %s", LOC(u->faction->locale, - parameters[P_TEMP]), token); - uid = tbuf; - } - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unitnotfound_id", - "id", uid)); - - parser_popstate(); - continue; - } - - feedback = u->faction==u2->faction || alliedunit(u2, u->faction, HELP_GUARD); - - /* Neuen Befehl zusammenbauen. TEMP-Einheiten werden automatisch in - * ihre neuen Nummern übersetzt. */ - if (zOrder[0]) strcat(zOrder, " "); - strcat(zOrder, unitid(u2)); - - if (get_keyword(u2->thisorder) != K_STUDY) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "teach_nolearn", "student", u2)); - continue; - } - - /* Input ist nun von u2->thisorder !! */ - parser_pushstate(); - init_tokens(u2->thisorder); - skip_token(); - sk = getskill(u2->faction->locale); - parser_popstate(); - - if (sk == NOSKILL) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "teach_nolearn", "student", u2)); - continue; - } - - /* u is teacher, u2 is student */ - if (eff_skill_study(u2, sk, r) > eff_skill_study(u, sk, r)-TEACHDIFFERENCE) { - if (feedback) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "teach_asgood", "student", u2)); - } - continue; - } - if (sk == SK_MAGIC) { - /* ist der Magier schon spezialisiert, so versteht er nur noch - * Lehrer seines Gebietes */ - sc_mage * mage1 = get_mage(u); - sc_mage * mage2 = get_mage(u2); - if (!mage2 || !mage1 || (mage2->magietyp!=M_GRAY && mage1->magietyp!=mage2->magietyp)) { - if (feedback) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_different_magic", "target", u2)); - } - continue; - } - } - - teaching -= teach_unit(u, u2, teaching, sk, false, &academy); - } - new_order = create_order(K_TEACH, u->faction->locale, "%s", zOrder); - replace_order(&u->orders, ord, new_order); - free_order(new_order); /* parse_order & set_order have each increased the refcount */ - } - if (academy && sk!=NOSKILL) { - academy = academy/30; /* anzahl gelehrter wochen, max. 10 */ - learn_skill(u, sk, academy/30.0/TEACHNUMBER); - } - return 0; -} - -static double -study_speedup(unit * u) -{ -#define MINTURN 5 /* 5 */ -#define OFSTURN 2 /* 2 */ - if (turn>MINTURN) { - static int speed_rule = -1; - if (speed_rule<0) { - speed_rule = get_param_int(global.parameters, "study.speedup", 0); - } - if (speed_rule==1) { - double learn_age = OFSTURN; - int i; - for (i=0;i!=u->skill_size;++i) { - skill * sv = u->skills+i; - double learn_time = sv->level*(sv->level+1)/2.0; - learn_age += learn_time; - } - if (learn_age < turn) { - return 2.0-learn_age/turn; - } - } - } - return 1.0; -} - -int -learn_cmd(unit * u, order * ord) -{ - region *r = u->region; - int p; - magic_t mtyp; - int l; - int studycost, days; - double multi = 1.0; - attrib * a = NULL; - teaching_info * teach = NULL; - int money = 0; - skill_t sk; - int maxalchemy = 0; - static int learn_newskills = -1; - if (learn_newskills<0) { - const char * str = get_param(global.parameters, "study.newskills"); - if (str && strcmp(str, "false")==0) learn_newskills = 0; - else learn_newskills = 1; - } - - if ((u->race->flags & RCF_NOLEARN) || fval(u, UFL_WERE)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_race_nolearn", "race", u->race)); - return 0; - } - - init_tokens(ord); - skip_token(); - sk = getskill(u->faction->locale); - - if (sk < 0) { - cmistake(u, ord, 77, MSG_EVENT); - return 0; - } - if (SkillCap(sk) && SkillCap(sk) <= effskill(u, sk)) { - cmistake(u, ord, 771, MSG_EVENT); - return 0; - } - /* Hack: Talente mit Malus -99 können nicht gelernt werden */ - if (u->race->bonus[sk] == -99) { - cmistake(u, ord, 771, MSG_EVENT); - return 0; - } - if (learn_newskills==0) { - skill * sv = get_skill(u, sk); - if (sv==NULL) { - /* we can only learn skills we already have */ - cmistake(u, ord, 771, MSG_EVENT); - return 0; - } - } - - /* snotlings können Talente nur bis T8 lernen */ - if (u->race == new_race[RC_SNOTLING]){ - if (get_level(u, sk) >= 8){ - cmistake(u, ord, 308, MSG_EVENT); - return 0; - } - } - - p = studycost = study_cost(u, sk); - a = a_find(u->attribs, &at_learning); - if (a!=NULL) { - teach = (teaching_info*)a->data.v; - } - - /* keine kostenpflichtigen Talente für Migranten. Vertraute sind - * keine Migranten, wird in is_migrant abgefangen. Vorsicht, - * studycost darf hier noch nicht durch Akademie erhöht sein */ - if (studycost > 0 && !ExpensiveMigrants() && is_migrant(u)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_migrants_nolearn", "")); - return 0; - } - /* Akademie: */ - { - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - - if (btype == bt_find("academy")) { - studycost = MAX(50, studycost * 2); - } - } - - if (sk == SK_MAGIC) { - if (u->number > 1){ - cmistake(u, ord, 106, MSG_MAGIC); - return 0; - } - if (is_familiar(u)){ - /* Vertraute zählen nicht zu den Magiern einer Partei, - * können aber nur Graue Magie lernen */ - mtyp = M_GRAY; - if (!is_mage(u)) create_mage(u, mtyp); - } else if (!has_skill(u, SK_MAGIC)) { - int mmax = skill_limit(u->faction, SK_MAGIC); - /* Die Einheit ist noch kein Magier */ - if (count_skill(u->faction, SK_MAGIC) + u->number > mmax) - { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_magicians", "amount", mmax)); - return 0; - } - mtyp = getmagicskill(u->faction->locale); - if (mtyp == M_NONE || mtyp == M_GRAY) { - /* wurde kein Magiegebiet angegeben, wird davon - * ausgegangen, daß das normal gelernt werden soll */ - if(u->faction->magiegebiet != 0) { - mtyp = u->faction->magiegebiet; - } else { - /* Es wurde kein Magiegebiet angegeben und die Partei - * hat noch keins gewählt. */ - mtyp = getmagicskill(u->faction->locale); - if (mtyp==M_NONE) { - cmistake(u, ord, 178, MSG_MAGIC); - return 0; - } - } - } - if (mtyp != u->faction->magiegebiet){ - /* Es wurde versucht, ein anderes Magiegebiet zu lernen - * als das der Partei */ - if (u->faction->magiegebiet != 0){ - cmistake(u, ord, 179, MSG_MAGIC); - return 0; - } else { - /* Lernt zum ersten mal Magie und legt damit das - * Magiegebiet der Partei fest */ - u->faction->magiegebiet = mtyp; - } - } - if (!is_mage(u)) create_mage(u, mtyp); - } else { - /* ist schon ein Magier und kein Vertrauter */ - if (u->faction->magiegebiet == 0) { - /* die Partei hat noch kein Magiegebiet gewählt. */ - mtyp = getmagicskill(u->faction->locale); - if (mtyp == M_NONE){ - mtyp = getmagicskill(u->faction->locale); - if (mtyp==M_NONE) { - cmistake(u, ord, 178, MSG_MAGIC); - return 0; - } - } - /* Legt damit das Magiegebiet der Partei fest */ - u->faction->magiegebiet = mtyp; - } - } - } - if (sk == SK_ALCHEMY) { - maxalchemy = eff_skill(u, SK_ALCHEMY, r); - if (!has_skill(u, SK_ALCHEMY)) { - int amax = skill_limit(u->faction, SK_ALCHEMY); - if (count_skill(u->faction, SK_ALCHEMY) + u->number > amax) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_alchemists", "amount", amax)); - return 0; - } - } - } - if (studycost) { - int cost = studycost * u->number; - money = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, cost); - money = MIN(money, cost); - } - if (money < studycost * u->number) { - studycost = p; /* Ohne Univertreurung */ - money = MIN(money, studycost); - if (p>0 && money < studycost * u->number) { - cmistake(u, ord, 65, MSG_EVENT); - multi = money / (double)(studycost * u->number); - } - } - - if (teach==NULL) { - a = a_add(&u->attribs, a_new(&at_learning)); - teach = (teaching_info*)a->data.v; - teach->teachers[0] = 0; - } - if (money>0) { - use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, money); - ADDMSG(&u->faction->msgs, msg_message("studycost", - "unit region cost skill", u, u->region, money, sk)); - } - - if (get_effect(u, oldpotiontype[P_WISE])) { - l = MIN(u->number, get_effect(u, oldpotiontype[P_WISE])); - teach->value += l * 10; - change_effect(u, oldpotiontype[P_WISE], -l); - } - if (get_effect(u, oldpotiontype[P_FOOL])) { - l = MIN(u->number, get_effect(u, oldpotiontype[P_FOOL])); - teach->value -= l * 30; - change_effect(u, oldpotiontype[P_FOOL], -l); - } - - if (p != studycost) { - /* ist_in_gebaeude(r, u, BT_UNIVERSITAET) == 1) { */ - /* p ist Kosten ohne Uni, studycost mit; wenn - * p!=studycost, ist die Einheit zwangsweise - * in einer Uni */ - teach->value += u->number * 10; - } - - if (is_cursed(r->attribs, C_BADLEARN,0)) { - teach->value -= u->number * 10; - } - - multi *= study_speedup(u); - days = study_days(u, sk); - days = (int)((days + teach->value) * multi); - - /* the artacademy currently improves the learning of entertainment - of all units in the region, to be able to make it cumulative with - with an academy */ - - if (sk == SK_ENTERTAINMENT && buildingtype_exists(r, bt_find("artacademy"), false)) { - days *= 2; - } - - if (fval(u, UFL_HUNGER)) days /= 2; - - while (days) { - if (days>=u->number*30) { - learn_skill(u, sk, 1.0); - days -= u->number*30; - } else { - double chance = (double)days/u->number/30; - learn_skill(u, sk, chance); - days = 0; - } - } - if (a!=NULL) { - if (teach!=NULL) { - int index = 0; - while (teach->teachers[index] && index!=MAXTEACHERS) { - unit * teacher = teach->teachers[index++]; - if (teacher->faction != u->faction) { - boolean feedback = alliedunit(u, teacher->faction, HELP_GUARD); - if (feedback) { - ADDMSG(&teacher->faction->msgs, msg_message("teach_teacher", - "teacher student skill level", teacher, u, sk, - effskill(u, sk))); - } - ADDMSG(&u->faction->msgs, msg_message("teach_student", - "teacher student skill", teacher, u, sk)); - } - } - } - a_remove(&u->attribs, a); - a = NULL; - } - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - - /* Anzeigen neuer Tränke */ - /* Spruchlistenaktualiesierung ist in Regeneration */ - - if (sk == SK_ALCHEMY) { - const potion_type * ptype; - faction * f = u->faction; - int skill = eff_skill(u, SK_ALCHEMY, r); - if (skill>maxalchemy) { - for (ptype=potiontypes; ptype; ptype=ptype->next) { - if (skill == ptype->level * 2) { - attrib * a = a_find(f->attribs, &at_showitem); - while (a && a->type==&at_showitem && a->data.v != ptype) a=a->next; - if (a==NULL || a->type!=&at_showitem) { - a = a_add(&f->attribs, a_new(&at_showitem)); - a->data.v = (void*) ptype->itype; - } - } - } - } - } - else if (sk==SK_MAGIC) { - sc_mage * mage = get_mage(u); - if (!mage) { - mage = create_mage(u, u->faction->magiegebiet); - } - } - - return 0; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#define TEACH_ALL 1 +#define TEACH_FRIENDS + +#include +#include +#include "study.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include + +#define TEACHNUMBER 10 + +static skill_t +getskill(const struct locale * lang) +{ + return findskill(getstrtoken(), lang); +} + +magic_t +getmagicskill(const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_MAGIC); + variant token; + const char * s = getstrtoken(); + + if (s && s[0]) { + if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { + return (magic_t)token.i; + } else { + char buffer[3]; + buffer[0] = s[0]; + buffer[1] = s[1]; + buffer[2] = '\0'; + if (findtoken(tokens, buffer, &token)==E_TOK_SUCCESS) { + return (magic_t)token.i; + } + } + } + return M_NONE; +} + +/* ------------------------------------------------------------- */ +/* Vertraute und Kröten sind keine Migranten */ +boolean +is_migrant(unit *u) +{ + if (u->race == u->faction->race) return false; + + if (fval(u->race, RCF_UNDEAD|RCF_ILLUSIONARY)) return false; + if (is_familiar(u)) return false; + if (u->race == new_race[RC_TOAD]) return false; + + return true; +} + +/* ------------------------------------------------------------- */ +boolean +magic_lowskill(unit *u) +{ + if (u->race == new_race[RC_TOAD]) return true; + return false; +} + +/* ------------------------------------------------------------- */ + +int +study_cost(unit *u, skill_t sk) +{ + static int cost[MAXSKILLS]; + int stufe, k = 50; + + if (cost[sk]==0) { + char buffer[256]; + sprintf(buffer, "skills.cost.%s", skillnames[sk]); + cost[sk] = get_param_int(global.parameters, buffer, -1); + } + if (cost[sk]>=0) return cost[sk]; + + switch (sk) { + case SK_SPY: + return 100; + break; + case SK_TACTICS: + case SK_HERBALISM: + case SK_ALCHEMY: + return 200; + break; + case SK_MAGIC: /* Die Magiekosten betragen 50+Summe(50*Stufe) */ + /* 'Stufe' ist dabei die nächste zu erreichende Stufe */ + stufe = 1 + get_level(u, SK_MAGIC); + return k*(1+((stufe+1)*stufe/2)); + break; + } + return 0; +} + +/* ------------------------------------------------------------- */ + +static void +init_learning(struct attrib * a) +{ + a->data.v = calloc(sizeof(teaching_info), 1); +} + +static void +done_learning(struct attrib * a) +{ + free(a->data.v); +} + +const attrib_type at_learning = { + "learning", + init_learning, done_learning, NULL, NULL, NULL, + ATF_UNIQUE +}; + +static int +study_days(unit * student, skill_t sk) +{ + int speed = 30; + if (student->race->study_speed) { + speed += student->race->study_speed[sk]; + if (speed<30) { + skill * sv = get_skill(student, sk); + if (sv==0) { + speed = 30; + } + } + } + return student->number * speed; +} + +static int +teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, + boolean report, int * academy) +{ + teaching_info * teach = NULL; + attrib * a; + int n; + + /* learning sind die Tage, die sie schon durch andere Lehrer zugute + * geschrieben bekommen haben. Total darf dies nicht über 30 Tage pro Mann + * steigen. + * + * n ist die Anzahl zusätzlich gelernter Tage. n darf max. die Differenz + * von schon gelernten Tagen zum MAX(30 Tage pro Mann) betragen. */ + + if (magic_lowskill(student)){ + cmistake(teacher, teacher->thisorder, 292, MSG_EVENT); + return 0; + } + + n = 30; + a = a_find(student->attribs, &at_learning); + if (a!=NULL) { + teach = (teaching_info*)a->data.v; + n -= teach->value; + } + + n = MIN(n, nteaching); + + if (n != 0) { + struct building * b = inside_building(teacher); + const struct building_type * btype = b?b->type:NULL; + int index = 0; + + if (teach==NULL) { + a = a_add(&student->attribs, a_new(&at_learning)); + teach = (teaching_info*)a->data.v; + } else { + while (teach->teachers[index] && index!=MAXTEACHERS) ++index; + } + if (indexteachers[index++] = teacher; + if (indexteachers[index] = NULL; + teach->value += n; + + /* Solange Akademien größenbeschränkt sind, sollte Lehrer und + * Student auch in unterschiedlichen Gebäuden stehen dürfen */ + if (btype == bt_find("academy") + && student->building && student->building->type == bt_find("academy")) + { + int j = study_cost(student, sk); + j = MAX(50, j * 2); + /* kann Einheit das zahlen? */ + if (get_pooled(student, oldresourcetype[R_SILVER], GET_DEFAULT, j) >= j) { + /* Jeder Schüler zusätzlich +10 Tage wenn in Uni. */ + teach->value += (n / 30) * 10; /* learning erhöhen */ + /* Lehrer zusätzlich +1 Tag pro Schüler. */ + if (academy) *academy += n; + } /* sonst nehmen sie nicht am Unterricht teil */ + } + + /* Teaching ist die Anzahl Leute, denen man noch was beibringen kann. Da + * hier nicht n verwendet wird, werden die Leute gezählt und nicht die + * effektiv gelernten Tage. -> FALSCH ? (ENNO) + * + * Eine Einheit A von 11 Mann mit Talent 0 profitiert vom ersten Lehrer B + * also 10x30=300 tage, und der zweite Lehrer C lehrt für nur noch 1x30=30 + * Tage (damit das Maximum von 11x30=330 nicht überschritten wird). + * + * Damit es aber in der Ausführung nicht auf die Reihenfolge drauf ankommt, + * darf der zweite Lehrer C keine weiteren Einheiten D mehr lehren. Also + * wird student 30 Tage gutgeschrieben, aber teaching sinkt auf 0 (300-11x30 <= + * 0). + * + * Sonst träte dies auf: + * + * A: lernt B: lehrt A C: lehrt A D D: lernt + * + * Wenn B vor C dran ist, lehrt C nur 30 Tage an A (wie oben) und + * 270 Tage an D. + * + * Ist C aber vor B dran, lehrt C 300 tage an A, und 0 tage an D, + * und B lehrt auch 0 tage an A. + * + * Deswegen darf C D nie lehren dürfen. + * + * -> Das ist wirr. wer hat das entworfen? + * Besser wäre, man macht erst vorab alle zuordnungen, und dann + * die Talentänderung (enno). + */ + + nteaching = MAX(0, nteaching - student->number * 30); + + } + return n; +} + +int +teach_cmd(unit * u, struct order * ord) +{ + static const curse_type * gbdream_ct = NULL; + plane * pl; + region * r = u->region; + int teaching, i, j, count, academy=0; + unit *u2; + skill_t sk = NOSKILL; + + if (gbdream_ct==0) gbdream_ct = ct_find("gbdream"); + if (gbdream_ct) { + if (get_curse(u->region->attribs, gbdream_ct)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "gbdream_noteach", "")); + return 0; + } + } + + if ((u->race->flags & RCF_NOTEACH) || fval(u, UFL_WERE)) { + cmistake(u, ord, 274, MSG_EVENT); + return 0; + } + + pl = rplane(r); + if (pl && fval(pl, PFL_NOTEACH)) { + cmistake(u, ord, 273, MSG_EVENT); + return 0; + } + + teaching = u->number * 30 * TEACHNUMBER; + + if ((i = get_effect(u, oldpotiontype[P_FOOL])) > 0) { /* Trank "Dumpfbackenbrot" */ + i = MIN(i, u->number * TEACHNUMBER); + /* Trank wirkt pro Schüler, nicht pro Lehrer */ + teaching -= i * 30; + change_effect(u, oldpotiontype[P_FOOL], -i); + j = teaching / 30; + ADDMSG(&u->faction->msgs, msg_message("teachdumb", + "teacher amount", u, j)); + } + if (teaching == 0) return 0; + + + u2 = 0; + count = 0; + + init_tokens(ord); + skip_token(); + +#if TEACH_ALL + if (getparam(u->faction->locale)==P_ANY) { + unit * student = r->units; + skill_t teachskill[MAXSKILLS]; + int i = 0; + do { + sk = getskill(u->faction->locale); + teachskill[i++]=sk; + } while (sk!=NOSKILL); + while (teaching && student) { + if (student->faction == u->faction) { +#ifdef NEW_DAEMONHUNGER_RULE + if (LongHunger(student)) continue; +#else + if (fval(student, UFL_HUNGER)) continue; +#endif + if (get_keyword(student->thisorder) == K_STUDY) { + /* Input ist nun von student->thisorder !! */ + init_tokens(student->thisorder); + skip_token(); + sk = getskill(student->faction->locale); + if (sk!=NOSKILL && teachskill[0]!=NOSKILL) { + for (i=0;teachskill[i]!=NOSKILL;++i) if (sk==teachskill[i]) break; + sk = teachskill[i]; + } + if (sk != NOSKILL && eff_skill_study(u, sk, r)-TEACHDIFFERENCE > eff_skill_study(student, sk, r)) { + teaching -= teach_unit(u, student, teaching, sk, true, &academy); + } + } + } + student = student->next; + } +#ifdef TEACH_FRIENDS + while (teaching && student) { + if (student->faction != u->faction && alliedunit(u, student->faction, HELP_GUARD)) { +#ifdef NEW_DAEMONHUNGER_RULE + if (LongHunger(student)) continue; +#else + if (fval(student, UFL_HUNGER)) continue; +#endif + if (get_keyword(student->thisorder) == K_STUDY) { + /* Input ist nun von student->thisorder !! */ + init_tokens(student->thisorder); + skip_token(); + sk = getskill(student->faction->locale); + if (sk != NOSKILL && eff_skill_study(u, sk, r)-TEACHDIFFERENCE >= eff_skill(student, sk, r)) { + teaching -= teach_unit(u, student, teaching, sk, true, &academy); + } + } + } + student = student->next; + } +#endif + } + else +#endif + { + char zOrder[4096]; + order * new_order; + + zOrder[0] = '\0'; + init_tokens(ord); + skip_token(); + + while (!parser_end()) { + unit * u2 = getunit(r, u->faction); + boolean feedback; + ++count; + + /* Falls die Unit nicht gefunden wird, Fehler melden */ + + if (!u2) { + char tbuf[20]; + const char * uid; + const char * token; + /* Finde den string, der den Fehler verursacht hat */ + parser_pushstate(); + init_tokens(ord); + skip_token(); + + for (j=0; j!=count-1; ++j) { + /* skip over the first 'count' units */ + getunit(r, u->faction); + } + + token = getstrtoken(); + + /* Beginne die Fehlermeldung */ + if (findparam(token, u->faction->locale) != P_TEMP) { + uid = token; + } else { + token = getstrtoken(); + sprintf(tbuf, "%s %s", LOC(u->faction->locale, + parameters[P_TEMP]), token); + uid = tbuf; + } + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unitnotfound_id", + "id", uid)); + + parser_popstate(); + continue; + } + + feedback = u->faction==u2->faction || alliedunit(u2, u->faction, HELP_GUARD); + + /* Neuen Befehl zusammenbauen. TEMP-Einheiten werden automatisch in + * ihre neuen Nummern übersetzt. */ + if (zOrder[0]) strcat(zOrder, " "); + strcat(zOrder, unitid(u2)); + + if (get_keyword(u2->thisorder) != K_STUDY) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "teach_nolearn", "student", u2)); + continue; + } + + /* Input ist nun von u2->thisorder !! */ + parser_pushstate(); + init_tokens(u2->thisorder); + skip_token(); + sk = getskill(u2->faction->locale); + parser_popstate(); + + if (sk == NOSKILL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "teach_nolearn", "student", u2)); + continue; + } + + /* u is teacher, u2 is student */ + if (eff_skill_study(u2, sk, r) > eff_skill_study(u, sk, r)-TEACHDIFFERENCE) { + if (feedback) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "teach_asgood", "student", u2)); + } + continue; + } + if (sk == SK_MAGIC) { + /* ist der Magier schon spezialisiert, so versteht er nur noch + * Lehrer seines Gebietes */ + sc_mage * mage1 = get_mage(u); + sc_mage * mage2 = get_mage(u2); + if (!mage2 || !mage1 || (mage2->magietyp!=M_GRAY && mage1->magietyp!=mage2->magietyp)) { + if (feedback) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_different_magic", "target", u2)); + } + continue; + } + } + + teaching -= teach_unit(u, u2, teaching, sk, false, &academy); + } + new_order = create_order(K_TEACH, u->faction->locale, "%s", zOrder); + replace_order(&u->orders, ord, new_order); + free_order(new_order); /* parse_order & set_order have each increased the refcount */ + } + if (academy && sk!=NOSKILL) { + academy = academy/30; /* anzahl gelehrter wochen, max. 10 */ + learn_skill(u, sk, academy/30.0/TEACHNUMBER); + } + return 0; +} + +static double +study_speedup(unit * u) +{ +#define MINTURN 5 /* 5 */ +#define OFSTURN 2 /* 2 */ + if (turn>MINTURN) { + static int speed_rule = -1; + if (speed_rule<0) { + speed_rule = get_param_int(global.parameters, "study.speedup", 0); + } + if (speed_rule==1) { + double learn_age = OFSTURN; + int i; + for (i=0;i!=u->skill_size;++i) { + skill * sv = u->skills+i; + double learn_time = sv->level*(sv->level+1)/2.0; + learn_age += learn_time; + } + if (learn_age < turn) { + return 2.0-learn_age/turn; + } + } + } + return 1.0; +} + +int +learn_cmd(unit * u, order * ord) +{ + region *r = u->region; + int p; + magic_t mtyp; + int l; + int studycost, days; + double multi = 1.0; + attrib * a = NULL; + teaching_info * teach = NULL; + int money = 0; + skill_t sk; + int maxalchemy = 0; + static int learn_newskills = -1; + if (learn_newskills<0) { + const char * str = get_param(global.parameters, "study.newskills"); + if (str && strcmp(str, "false")==0) learn_newskills = 0; + else learn_newskills = 1; + } + + if ((u->race->flags & RCF_NOLEARN) || fval(u, UFL_WERE)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_race_nolearn", "race", u->race)); + return 0; + } + + init_tokens(ord); + skip_token(); + sk = getskill(u->faction->locale); + + if (sk < 0) { + cmistake(u, ord, 77, MSG_EVENT); + return 0; + } + if (SkillCap(sk) && SkillCap(sk) <= effskill(u, sk)) { + cmistake(u, ord, 771, MSG_EVENT); + return 0; + } + /* Hack: Talente mit Malus -99 können nicht gelernt werden */ + if (u->race->bonus[sk] == -99) { + cmistake(u, ord, 771, MSG_EVENT); + return 0; + } + if (learn_newskills==0) { + skill * sv = get_skill(u, sk); + if (sv==NULL) { + /* we can only learn skills we already have */ + cmistake(u, ord, 771, MSG_EVENT); + return 0; + } + } + + /* snotlings können Talente nur bis T8 lernen */ + if (u->race == new_race[RC_SNOTLING]){ + if (get_level(u, sk) >= 8){ + cmistake(u, ord, 308, MSG_EVENT); + return 0; + } + } + + p = studycost = study_cost(u, sk); + a = a_find(u->attribs, &at_learning); + if (a!=NULL) { + teach = (teaching_info*)a->data.v; + } + + /* keine kostenpflichtigen Talente für Migranten. Vertraute sind + * keine Migranten, wird in is_migrant abgefangen. Vorsicht, + * studycost darf hier noch nicht durch Akademie erhöht sein */ + if (studycost > 0 && !ExpensiveMigrants() && is_migrant(u)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_migrants_nolearn", "")); + return 0; + } + /* Akademie: */ + { + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + + if (btype == bt_find("academy")) { + studycost = MAX(50, studycost * 2); + } + } + + if (sk == SK_MAGIC) { + if (u->number > 1){ + cmistake(u, ord, 106, MSG_MAGIC); + return 0; + } + if (is_familiar(u)){ + /* Vertraute zählen nicht zu den Magiern einer Partei, + * können aber nur Graue Magie lernen */ + mtyp = M_GRAY; + if (!is_mage(u)) create_mage(u, mtyp); + } else if (!has_skill(u, SK_MAGIC)) { + int mmax = skill_limit(u->faction, SK_MAGIC); + /* Die Einheit ist noch kein Magier */ + if (count_skill(u->faction, SK_MAGIC) + u->number > mmax) + { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_magicians", "amount", mmax)); + return 0; + } + mtyp = getmagicskill(u->faction->locale); + if (mtyp == M_NONE || mtyp == M_GRAY) { + /* wurde kein Magiegebiet angegeben, wird davon + * ausgegangen, daß das normal gelernt werden soll */ + if(u->faction->magiegebiet != 0) { + mtyp = u->faction->magiegebiet; + } else { + /* Es wurde kein Magiegebiet angegeben und die Partei + * hat noch keins gewählt. */ + mtyp = getmagicskill(u->faction->locale); + if (mtyp==M_NONE) { + cmistake(u, ord, 178, MSG_MAGIC); + return 0; + } + } + } + if (mtyp != u->faction->magiegebiet){ + /* Es wurde versucht, ein anderes Magiegebiet zu lernen + * als das der Partei */ + if (u->faction->magiegebiet != 0){ + cmistake(u, ord, 179, MSG_MAGIC); + return 0; + } else { + /* Lernt zum ersten mal Magie und legt damit das + * Magiegebiet der Partei fest */ + u->faction->magiegebiet = mtyp; + } + } + if (!is_mage(u)) create_mage(u, mtyp); + } else { + /* ist schon ein Magier und kein Vertrauter */ + if (u->faction->magiegebiet == 0) { + /* die Partei hat noch kein Magiegebiet gewählt. */ + mtyp = getmagicskill(u->faction->locale); + if (mtyp == M_NONE){ + mtyp = getmagicskill(u->faction->locale); + if (mtyp==M_NONE) { + cmistake(u, ord, 178, MSG_MAGIC); + return 0; + } + } + /* Legt damit das Magiegebiet der Partei fest */ + u->faction->magiegebiet = mtyp; + } + } + } + if (sk == SK_ALCHEMY) { + maxalchemy = eff_skill(u, SK_ALCHEMY, r); + if (!has_skill(u, SK_ALCHEMY)) { + int amax = skill_limit(u->faction, SK_ALCHEMY); + if (count_skill(u->faction, SK_ALCHEMY) + u->number > amax) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_alchemists", "amount", amax)); + return 0; + } + } + } + if (studycost) { + int cost = studycost * u->number; + money = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, cost); + money = MIN(money, cost); + } + if (money < studycost * u->number) { + studycost = p; /* Ohne Univertreurung */ + money = MIN(money, studycost); + if (p>0 && money < studycost * u->number) { + cmistake(u, ord, 65, MSG_EVENT); + multi = money / (double)(studycost * u->number); + } + } + + if (teach==NULL) { + a = a_add(&u->attribs, a_new(&at_learning)); + teach = (teaching_info*)a->data.v; + teach->teachers[0] = 0; + } + if (money>0) { + use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, money); + ADDMSG(&u->faction->msgs, msg_message("studycost", + "unit region cost skill", u, u->region, money, sk)); + } + + if (get_effect(u, oldpotiontype[P_WISE])) { + l = MIN(u->number, get_effect(u, oldpotiontype[P_WISE])); + teach->value += l * 10; + change_effect(u, oldpotiontype[P_WISE], -l); + } + if (get_effect(u, oldpotiontype[P_FOOL])) { + l = MIN(u->number, get_effect(u, oldpotiontype[P_FOOL])); + teach->value -= l * 30; + change_effect(u, oldpotiontype[P_FOOL], -l); + } + + if (p != studycost) { + /* ist_in_gebaeude(r, u, BT_UNIVERSITAET) == 1) { */ + /* p ist Kosten ohne Uni, studycost mit; wenn + * p!=studycost, ist die Einheit zwangsweise + * in einer Uni */ + teach->value += u->number * 10; + } + + if (is_cursed(r->attribs, C_BADLEARN,0)) { + teach->value -= u->number * 10; + } + + multi *= study_speedup(u); + days = study_days(u, sk); + days = (int)((days + teach->value) * multi); + + /* the artacademy currently improves the learning of entertainment + of all units in the region, to be able to make it cumulative with + with an academy */ + + if (sk == SK_ENTERTAINMENT && buildingtype_exists(r, bt_find("artacademy"), false)) { + days *= 2; + } + + if (fval(u, UFL_HUNGER)) days /= 2; + + while (days) { + if (days>=u->number*30) { + learn_skill(u, sk, 1.0); + days -= u->number*30; + } else { + double chance = (double)days/u->number/30; + learn_skill(u, sk, chance); + days = 0; + } + } + if (a!=NULL) { + if (teach!=NULL) { + int index = 0; + while (teach->teachers[index] && index!=MAXTEACHERS) { + unit * teacher = teach->teachers[index++]; + if (teacher->faction != u->faction) { + boolean feedback = alliedunit(u, teacher->faction, HELP_GUARD); + if (feedback) { + ADDMSG(&teacher->faction->msgs, msg_message("teach_teacher", + "teacher student skill level", teacher, u, sk, + effskill(u, sk))); + } + ADDMSG(&u->faction->msgs, msg_message("teach_student", + "teacher student skill", teacher, u, sk)); + } + } + } + a_remove(&u->attribs, a); + a = NULL; + } + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + + /* Anzeigen neuer Tränke */ + /* Spruchlistenaktualiesierung ist in Regeneration */ + + if (sk == SK_ALCHEMY) { + const potion_type * ptype; + faction * f = u->faction; + int skill = eff_skill(u, SK_ALCHEMY, r); + if (skill>maxalchemy) { + for (ptype=potiontypes; ptype; ptype=ptype->next) { + if (skill == ptype->level * 2) { + attrib * a = a_find(f->attribs, &at_showitem); + while (a && a->type==&at_showitem && a->data.v != ptype) a=a->next; + if (a==NULL || a->type!=&at_showitem) { + a = a_add(&f->attribs, a_new(&at_showitem)); + a->data.v = (void*) ptype->itype; + } + } + } + } + } + else if (sk==SK_MAGIC) { + sc_mage * mage = get_mage(u); + if (!mage) { + mage = create_mage(u, u->faction->magiegebiet); + } + } + + return 0; +} diff --git a/src/gamecode/study.h b/src/gamecode/study.h index 83c39605a..6ea695a26 100644 --- a/src/gamecode/study.h +++ b/src/gamecode/study.h @@ -1,45 +1,45 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_STUDY -#define H_KRNL_STUDY - -#ifdef __cplusplus -extern "C" { -#endif - -extern int teach_cmd(struct unit * u, struct order * ord); -extern int learn_cmd(struct unit * u, struct order * ord); - -extern magic_t getmagicskill(const struct locale * lang); -extern boolean is_migrant(struct unit *u); -extern int study_cost(struct unit *u, skill_t talent); - -#define MAXTEACHERS 4 -typedef struct teaching_info { - struct unit * teachers[MAXTEACHERS]; - int value; -} teaching_info; - -extern const struct attrib_type at_learning; - -#ifdef __cplusplus -} -#endif - -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_STUDY +#define H_KRNL_STUDY + +#ifdef __cplusplus +extern "C" { +#endif + +extern int teach_cmd(struct unit * u, struct order * ord); +extern int learn_cmd(struct unit * u, struct order * ord); + +extern magic_t getmagicskill(const struct locale * lang); +extern boolean is_migrant(struct unit *u); +extern int study_cost(struct unit *u, skill_t talent); + +#define MAXTEACHERS 4 +typedef struct teaching_info { + struct unit * teachers[MAXTEACHERS]; + int value; +} teaching_info; + +extern const struct attrib_type at_learning; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/gamecode/summary.c b/src/gamecode/summary.c index 015ce278c..5e16a53c4 100644 --- a/src/gamecode/summary.c +++ b/src/gamecode/summary.c @@ -1,413 +1,413 @@ -/* vi: set ts=2: - * +-------------------+ Christian Schlittchen - * | | Enno Rehling - * | Eressea PBEM host | Katja Zedel - * | (c) 1998 - 2007 | - * | | This program may not be used, modified or distributed - * +-------------------+ without prior permission by the authors of Eressea. - * - */ - -/* wenn platform.h nicht vor curses included wird, kompiliert es unter windows nicht */ -#include -#include - -#include "summary.h" - -#include "laws.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#undef SUMMARY_BOM /* write a BOM in the summary file */ - -typedef struct summary { - int waffen; - int factions; - int ruestungen; - int schiffe; - int gebaeude; - int maxskill; - int heroes; - int inhabitedregions; - int peasants; - int nunits; - int playerpop; - double playermoney; - double peasantmoney; - int armed_men; - int poprace[MAXRACES]; - int factionrace[MAXRACES]; - int landregionen; - int regionen_mit_spielern; - int landregionen_mit_spielern; - int orkifizierte_regionen; - int inactive_volcanos; - int active_volcanos; - int spielerpferde; - int pferde; - struct language { - struct language * next; - int number; - const struct locale * locale; - } * languages; -} summary; - -static char * -pcomp(double i, double j) -{ - static char buf[32]; - sprintf(buf, "%.0f (%s%.0f)", i, (i>=j)?"+":"", i-j); - return buf; -} - -static char * -rcomp(int i, int j) -{ - static char buf[32]; - sprintf(buf, "%d (%s%d,%s%d%%)", - i, (i>=j)?"+":"", i-j, (i>=j)?"+":"",j?((i-j)*100)/j:0); - return buf; -} - - -static void -out_faction(FILE *file, const struct faction *f) -{ - if (alliances!=NULL) { - fprintf(file, "%s (%s/%d) (%.3s/%.3s), %d Einh., %d Pers., $%d, %d NMR\n", - f->name, itoa36(f->no), f_get_alliance(f)?f->alliance->id:0, - LOC(default_locale, rc_name(f->race, 0)), magic_school[f->magiegebiet], - f->no_units, f->num_total, f->money, turn - f->lastorders); - } else { - fprintf(file, "%s (%.3s/%.3s), %d Einh., %d Pers., $%d, %d NMR\n", - factionname(f), LOC(default_locale, rc_name(f->race, 0)), - magic_school[f->magiegebiet], f->no_units, f->num_total, f->money, - turn - f->lastorders); - } -} - -static char * -gamedate2(const struct locale * lang) -{ - static char buf[256]; - gamedate gd; - - get_gamedate(turn, &gd); - sprintf(buf, "in %s des Monats %s im Jahre %d %s.", - LOC(lang, weeknames2[gd.week]), - LOC(lang, monthnames[gd.month]), - gd.year, - agename?LOC(lang, agename):""); - return buf; -} - -static void -writeturn(void) -{ - char zText[MAX_PATH]; - FILE *f; - - sprintf(zText, "%s/datum", basepath()); - f = cfopen(zText, "w"); - if (!f) return; - fputs(gamedate2(default_locale), f); - fclose(f); - sprintf(zText, "%s/turn", basepath()); - f = cfopen(zText, "w"); - if (!f) return; - fprintf(f, "%d\n", turn); - fclose(f); -} - -void -report_summary(summary * s, summary * o, boolean full) -{ - FILE * F = NULL; - int i, newplayers = 0; - faction * f; - char zText[MAX_PATH]; - - if (full) { - sprintf(zText, "%s/parteien.full", basepath()); - } else { - sprintf(zText, "%s/parteien", basepath()); - } - F = cfopen(zText, "w"); - if (!F) return; -#ifdef SUMMARY_BOM - else { - const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; - fwrite(utf8_bom, 1, 3, F); - } -#endif - printf("Schreibe Zusammenfassung (parteien)...\n"); - fprintf(F, "%s\n%s\n\n", global.gamename, gamedate2(default_locale)); - fprintf(F, "Auswertung Nr: %d\n\n", turn); - fprintf(F, "Parteien: %s\n", pcomp(s->factions, o->factions)); - fprintf(F, "Einheiten: %s\n", pcomp(s->nunits, o->nunits)); - fprintf(F, "Spielerpopulation: %s\n", - pcomp(s->playerpop, o->playerpop)); - fprintf(F, " davon bewaffnet: %s\n", - pcomp(s->armed_men, o->armed_men)); - fprintf(F, " Helden: %s\n", pcomp(s->heroes, o->heroes)); - - if (full) { - fprintf(F, "Regionen: %d\n", listlen(regions)); - fprintf(F, "Bewohnte Regionen: %d\n", s->inhabitedregions); - fprintf(F, "Landregionen: %d\n", s->landregionen); - fprintf(F, "Spielerregionen: %d\n", s->regionen_mit_spielern); - fprintf(F, "Landspielerregionen: %d\n", s->landregionen_mit_spielern); - fprintf(F, "Orkifizierte Regionen: %d\n", s->orkifizierte_regionen); - fprintf(F, "Inaktive Vulkane: %d\n", s->inactive_volcanos); - fprintf(F, "Aktive Vulkane: %d\n\n", s->active_volcanos); - } - - for (i = 0; i < MAXRACES; i++) { - const race * rc = new_race[i]; - if (s->factionrace[i] && rc && playerrace(rc) - && i != RC_TEMPLATE && i != RC_CLONE) { - fprintf(F, "%13s%s: %s\n", LOC(default_locale, rc_name(rc, 3)), LOC(default_locale, "stat_tribe_p"), - pcomp(s->factionrace[i], o->factionrace[i])); - } - } - - if(full) { - fprintf(F, "\n"); - { - struct language * plang = s->languages; - while (plang!=NULL) { - struct language * olang = o->languages; - int nold = 0; - while (olang && olang->locale!=plang->locale) olang=olang->next; - if (olang) nold = olang->number; - fprintf(F, "Sprache %12s: %s\n", locale_name(plang->locale), - rcomp(plang->number, nold)); - plang=plang->next; - } - } - } - - fprintf(F, "\n"); - if (full) { - for (i = 0; i < MAXRACES; i++) { - const race * rc = new_race[i]; - if (s->poprace[i]) { - fprintf(F, "%20s: %s\n", LOC(default_locale, rc_name(rc, 1)), - rcomp(s->poprace[i], o->poprace[i])); - } - } - } else { - for (i = 0; i < MAXRACES; i++) { - const race * rc = new_race[i]; - if (s->poprace[i] && playerrace(rc) - && i != RC_TEMPLATE && i != RC_CLONE) { - fprintf(F, "%20s: %s\n", LOC(default_locale, rc_name(rc, 1)), - rcomp(s->poprace[i], o->poprace[i])); - } - } - } - - if (full) { - fprintf(F, "\nWaffen: %s\n", pcomp(s->waffen,o->waffen)); - fprintf(F, "Ruestungen: %s\n", - pcomp(s->ruestungen,o->ruestungen)); - fprintf(F, "ungezaehmte Pferde: %s\n", pcomp(s->pferde, o->pferde)); - fprintf(F, "gezaehmte Pferde: %s\n", - pcomp(s->spielerpferde,o->spielerpferde)); - fprintf(F, "Schiffe: %s\n", pcomp(s->schiffe, o->schiffe)); - fprintf(F, "Gebaeude: %s\n", pcomp(s->gebaeude, o->gebaeude)); - - fprintf(F, "\nBauernpopulation: %s\n", pcomp(s->peasants,o->peasants)); - - fprintf(F, "Population gesamt: %d\n\n", s->playerpop+s->peasants); - - fprintf(F, "Reichtum Spieler: %s Silber\n", - pcomp(s->playermoney,o->playermoney)); - fprintf(F, "Reichtum Bauern: %s Silber\n", - pcomp(s->peasantmoney, o->peasantmoney)); - fprintf(F, "Reichtum gesamt: %s Silber\n\n", - pcomp(s->playermoney+s->peasantmoney, o->playermoney+o->peasantmoney)); - } - - fprintf(F, "\n\n"); - - newplayers = update_nmrs(); - - for (i = 0; i <= NMRTimeout(); ++i) { - if (i == NMRTimeout()) { - fprintf(F, "+ NMR:\t\t %d\n", nmrs[i]); - } else { - fprintf(F, "%d NMR:\t\t %d\n", i, nmrs[i]); - } - } - if (age) { - if (age[2] != 0) { - fprintf(F, "Erstabgaben:\t %d%%\n", 100 - (dropouts[0] * 100 / age[2])); - } - if (age[3] != 0) { - fprintf(F, "Zweitabgaben:\t %d%%\n", 100 - (dropouts[1] * 100 / age[3])); - } - } - fprintf(F, "Neue Spieler:\t %d\n", newplayers); - - if (full) { - if (factions) - fprintf(F, "\nParteien:\n\n"); - - for (f = factions; f; f = f->next) { - out_faction(F, f); - } - - if (NMRTimeout() && full) { - fprintf(F, "\n\nFactions with NMRs:\n"); - for (i = NMRTimeout(); i > 0; --i) { - for(f=factions; f; f=f->next) { - if(i == NMRTimeout()) { - if(turn - f->lastorders >= i) { - out_faction(F, f); - } - } else { - if(turn - f->lastorders == i) { - out_faction(F, f); - } - } - } - } - } - } - - fclose(F); - - if (full) { - printf("writing date & turn\n"); - writeturn(); - } - free(nmrs); - nmrs = NULL; -} - -summary * -make_summary(void) -{ - faction *f; - region *r; - unit *u; - summary * s = calloc(1, sizeof(summary)); - - for (f = factions; f; f = f->next) { - const struct locale * lang = f->locale; - struct language * plang = s->languages; - while (plang && plang->locale != lang) plang=plang->next; - if (!plang) { - plang = calloc(sizeof(struct language), 1); - plang->next = s->languages; - s->languages = plang; - plang->locale = lang; - } - ++plang->number; - f->nregions = 0; - f->num_total = 0; - f->money = 0; - if (f->alive && f->units) { - s->factions++; - /* Problem mit Monsterpartei ... */ - if (!is_monsters(f)) { - s->factionrace[old_race(f->race)]++; - } - } - } - - /* Alles zählen */ - - for (r = regions; r; r = r->next) { - s->pferde += rhorses(r); - s->schiffe += listlen(r->ships); - s->gebaeude += listlen(r->buildings); - if (!fval(r->terrain, SEA_REGION)) { - s->landregionen++; - if (r->units) { - s->landregionen_mit_spielern++; - } - if (fval(r, RF_ORCIFIED)) { - s->orkifizierte_regionen++; - } - if (r->terrain == newterrain(T_VOLCANO)) { - s->inactive_volcanos++; - } else if (r->terrain == newterrain(T_VOLCANO_SMOKING)) { - s->active_volcanos++; - } - } - if (r->units) { - s->regionen_mit_spielern++; - } - if (rpeasants(r) || r->units) { - s->inhabitedregions++; - s->peasants += rpeasants(r); - s->peasantmoney += rmoney(r); - - /* Einheiten Info. nregions darf nur einmal pro Partei - * incrementiert werden. */ - - for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT); - for (u = r->units; u; u = u->next) { - f = u->faction; - if (!is_monsters(u->faction)) { - skill * sv; - item * itm; - - s->nunits++; - s->playerpop += u->number; - if (u->flags & UFL_HERO) { - s->heroes += u->number; - } - s->spielerpferde += get_item(u, I_HORSE); - s->playermoney += get_money(u); - s->armed_men += armedmen(u, true); - for (itm=u->items;itm;itm=itm->next) { - if (itm->type->rtype->wtype) { - s->waffen += itm->number; - } - if (itm->type->rtype->atype) { - s->ruestungen += itm->number; - } - } - - s->spielerpferde += get_item(u, I_HORSE); - - for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - skill_t sk = sv->id; - int aktskill = eff_skill(u, sk, r); - if (aktskill > s->maxskill) s->maxskill = aktskill; - } - if (!fval(f, FFL_SELECT)) { - f->nregions++; - fset(f, FFL_SELECT); - } - } - - f->num_total += u->number; - f->money += get_money(u); - s->poprace[old_race(u->race)] += u->number; - } - } - } - - return s; -} +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2007 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +/* wenn platform.h nicht vor curses included wird, kompiliert es unter windows nicht */ +#include +#include + +#include "summary.h" + +#include "laws.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#undef SUMMARY_BOM /* write a BOM in the summary file */ + +typedef struct summary { + int waffen; + int factions; + int ruestungen; + int schiffe; + int gebaeude; + int maxskill; + int heroes; + int inhabitedregions; + int peasants; + int nunits; + int playerpop; + double playermoney; + double peasantmoney; + int armed_men; + int poprace[MAXRACES]; + int factionrace[MAXRACES]; + int landregionen; + int regionen_mit_spielern; + int landregionen_mit_spielern; + int orkifizierte_regionen; + int inactive_volcanos; + int active_volcanos; + int spielerpferde; + int pferde; + struct language { + struct language * next; + int number; + const struct locale * locale; + } * languages; +} summary; + +static char * +pcomp(double i, double j) +{ + static char buf[32]; + sprintf(buf, "%.0f (%s%.0f)", i, (i>=j)?"+":"", i-j); + return buf; +} + +static char * +rcomp(int i, int j) +{ + static char buf[32]; + sprintf(buf, "%d (%s%d,%s%d%%)", + i, (i>=j)?"+":"", i-j, (i>=j)?"+":"",j?((i-j)*100)/j:0); + return buf; +} + + +static void +out_faction(FILE *file, const struct faction *f) +{ + if (alliances!=NULL) { + fprintf(file, "%s (%s/%d) (%.3s/%.3s), %d Einh., %d Pers., $%d, %d NMR\n", + f->name, itoa36(f->no), f_get_alliance(f)?f->alliance->id:0, + LOC(default_locale, rc_name(f->race, 0)), magic_school[f->magiegebiet], + f->no_units, f->num_total, f->money, turn - f->lastorders); + } else { + fprintf(file, "%s (%.3s/%.3s), %d Einh., %d Pers., $%d, %d NMR\n", + factionname(f), LOC(default_locale, rc_name(f->race, 0)), + magic_school[f->magiegebiet], f->no_units, f->num_total, f->money, + turn - f->lastorders); + } +} + +static char * +gamedate2(const struct locale * lang) +{ + static char buf[256]; + gamedate gd; + + get_gamedate(turn, &gd); + sprintf(buf, "in %s des Monats %s im Jahre %d %s.", + LOC(lang, weeknames2[gd.week]), + LOC(lang, monthnames[gd.month]), + gd.year, + agename?LOC(lang, agename):""); + return buf; +} + +static void +writeturn(void) +{ + char zText[MAX_PATH]; + FILE *f; + + sprintf(zText, "%s/datum", basepath()); + f = cfopen(zText, "w"); + if (!f) return; + fputs(gamedate2(default_locale), f); + fclose(f); + sprintf(zText, "%s/turn", basepath()); + f = cfopen(zText, "w"); + if (!f) return; + fprintf(f, "%d\n", turn); + fclose(f); +} + +void +report_summary(summary * s, summary * o, boolean full) +{ + FILE * F = NULL; + int i, newplayers = 0; + faction * f; + char zText[MAX_PATH]; + + if (full) { + sprintf(zText, "%s/parteien.full", basepath()); + } else { + sprintf(zText, "%s/parteien", basepath()); + } + F = cfopen(zText, "w"); + if (!F) return; +#ifdef SUMMARY_BOM + else { + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + fwrite(utf8_bom, 1, 3, F); + } +#endif + printf("Schreibe Zusammenfassung (parteien)...\n"); + fprintf(F, "%s\n%s\n\n", global.gamename, gamedate2(default_locale)); + fprintf(F, "Auswertung Nr: %d\n\n", turn); + fprintf(F, "Parteien: %s\n", pcomp(s->factions, o->factions)); + fprintf(F, "Einheiten: %s\n", pcomp(s->nunits, o->nunits)); + fprintf(F, "Spielerpopulation: %s\n", + pcomp(s->playerpop, o->playerpop)); + fprintf(F, " davon bewaffnet: %s\n", + pcomp(s->armed_men, o->armed_men)); + fprintf(F, " Helden: %s\n", pcomp(s->heroes, o->heroes)); + + if (full) { + fprintf(F, "Regionen: %d\n", listlen(regions)); + fprintf(F, "Bewohnte Regionen: %d\n", s->inhabitedregions); + fprintf(F, "Landregionen: %d\n", s->landregionen); + fprintf(F, "Spielerregionen: %d\n", s->regionen_mit_spielern); + fprintf(F, "Landspielerregionen: %d\n", s->landregionen_mit_spielern); + fprintf(F, "Orkifizierte Regionen: %d\n", s->orkifizierte_regionen); + fprintf(F, "Inaktive Vulkane: %d\n", s->inactive_volcanos); + fprintf(F, "Aktive Vulkane: %d\n\n", s->active_volcanos); + } + + for (i = 0; i < MAXRACES; i++) { + const race * rc = new_race[i]; + if (s->factionrace[i] && rc && playerrace(rc) + && i != RC_TEMPLATE && i != RC_CLONE) { + fprintf(F, "%13s%s: %s\n", LOC(default_locale, rc_name(rc, 3)), LOC(default_locale, "stat_tribe_p"), + pcomp(s->factionrace[i], o->factionrace[i])); + } + } + + if(full) { + fprintf(F, "\n"); + { + struct language * plang = s->languages; + while (plang!=NULL) { + struct language * olang = o->languages; + int nold = 0; + while (olang && olang->locale!=plang->locale) olang=olang->next; + if (olang) nold = olang->number; + fprintf(F, "Sprache %12s: %s\n", locale_name(plang->locale), + rcomp(plang->number, nold)); + plang=plang->next; + } + } + } + + fprintf(F, "\n"); + if (full) { + for (i = 0; i < MAXRACES; i++) { + const race * rc = new_race[i]; + if (s->poprace[i]) { + fprintf(F, "%20s: %s\n", LOC(default_locale, rc_name(rc, 1)), + rcomp(s->poprace[i], o->poprace[i])); + } + } + } else { + for (i = 0; i < MAXRACES; i++) { + const race * rc = new_race[i]; + if (s->poprace[i] && playerrace(rc) + && i != RC_TEMPLATE && i != RC_CLONE) { + fprintf(F, "%20s: %s\n", LOC(default_locale, rc_name(rc, 1)), + rcomp(s->poprace[i], o->poprace[i])); + } + } + } + + if (full) { + fprintf(F, "\nWaffen: %s\n", pcomp(s->waffen,o->waffen)); + fprintf(F, "Ruestungen: %s\n", + pcomp(s->ruestungen,o->ruestungen)); + fprintf(F, "ungezaehmte Pferde: %s\n", pcomp(s->pferde, o->pferde)); + fprintf(F, "gezaehmte Pferde: %s\n", + pcomp(s->spielerpferde,o->spielerpferde)); + fprintf(F, "Schiffe: %s\n", pcomp(s->schiffe, o->schiffe)); + fprintf(F, "Gebaeude: %s\n", pcomp(s->gebaeude, o->gebaeude)); + + fprintf(F, "\nBauernpopulation: %s\n", pcomp(s->peasants,o->peasants)); + + fprintf(F, "Population gesamt: %d\n\n", s->playerpop+s->peasants); + + fprintf(F, "Reichtum Spieler: %s Silber\n", + pcomp(s->playermoney,o->playermoney)); + fprintf(F, "Reichtum Bauern: %s Silber\n", + pcomp(s->peasantmoney, o->peasantmoney)); + fprintf(F, "Reichtum gesamt: %s Silber\n\n", + pcomp(s->playermoney+s->peasantmoney, o->playermoney+o->peasantmoney)); + } + + fprintf(F, "\n\n"); + + newplayers = update_nmrs(); + + for (i = 0; i <= NMRTimeout(); ++i) { + if (i == NMRTimeout()) { + fprintf(F, "+ NMR:\t\t %d\n", nmrs[i]); + } else { + fprintf(F, "%d NMR:\t\t %d\n", i, nmrs[i]); + } + } + if (age) { + if (age[2] != 0) { + fprintf(F, "Erstabgaben:\t %d%%\n", 100 - (dropouts[0] * 100 / age[2])); + } + if (age[3] != 0) { + fprintf(F, "Zweitabgaben:\t %d%%\n", 100 - (dropouts[1] * 100 / age[3])); + } + } + fprintf(F, "Neue Spieler:\t %d\n", newplayers); + + if (full) { + if (factions) + fprintf(F, "\nParteien:\n\n"); + + for (f = factions; f; f = f->next) { + out_faction(F, f); + } + + if (NMRTimeout() && full) { + fprintf(F, "\n\nFactions with NMRs:\n"); + for (i = NMRTimeout(); i > 0; --i) { + for(f=factions; f; f=f->next) { + if(i == NMRTimeout()) { + if(turn - f->lastorders >= i) { + out_faction(F, f); + } + } else { + if(turn - f->lastorders == i) { + out_faction(F, f); + } + } + } + } + } + } + + fclose(F); + + if (full) { + printf("writing date & turn\n"); + writeturn(); + } + free(nmrs); + nmrs = NULL; +} + +summary * +make_summary(void) +{ + faction *f; + region *r; + unit *u; + summary * s = calloc(1, sizeof(summary)); + + for (f = factions; f; f = f->next) { + const struct locale * lang = f->locale; + struct language * plang = s->languages; + while (plang && plang->locale != lang) plang=plang->next; + if (!plang) { + plang = calloc(sizeof(struct language), 1); + plang->next = s->languages; + s->languages = plang; + plang->locale = lang; + } + ++plang->number; + f->nregions = 0; + f->num_total = 0; + f->money = 0; + if (f->alive && f->units) { + s->factions++; + /* Problem mit Monsterpartei ... */ + if (!is_monsters(f)) { + s->factionrace[old_race(f->race)]++; + } + } + } + + /* Alles zählen */ + + for (r = regions; r; r = r->next) { + s->pferde += rhorses(r); + s->schiffe += listlen(r->ships); + s->gebaeude += listlen(r->buildings); + if (!fval(r->terrain, SEA_REGION)) { + s->landregionen++; + if (r->units) { + s->landregionen_mit_spielern++; + } + if (fval(r, RF_ORCIFIED)) { + s->orkifizierte_regionen++; + } + if (r->terrain == newterrain(T_VOLCANO)) { + s->inactive_volcanos++; + } else if (r->terrain == newterrain(T_VOLCANO_SMOKING)) { + s->active_volcanos++; + } + } + if (r->units) { + s->regionen_mit_spielern++; + } + if (rpeasants(r) || r->units) { + s->inhabitedregions++; + s->peasants += rpeasants(r); + s->peasantmoney += rmoney(r); + + /* Einheiten Info. nregions darf nur einmal pro Partei + * incrementiert werden. */ + + for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT); + for (u = r->units; u; u = u->next) { + f = u->faction; + if (!is_monsters(u->faction)) { + skill * sv; + item * itm; + + s->nunits++; + s->playerpop += u->number; + if (u->flags & UFL_HERO) { + s->heroes += u->number; + } + s->spielerpferde += get_item(u, I_HORSE); + s->playermoney += get_money(u); + s->armed_men += armedmen(u, true); + for (itm=u->items;itm;itm=itm->next) { + if (itm->type->rtype->wtype) { + s->waffen += itm->number; + } + if (itm->type->rtype->atype) { + s->ruestungen += itm->number; + } + } + + s->spielerpferde += get_item(u, I_HORSE); + + for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { + skill_t sk = sv->id; + int aktskill = eff_skill(u, sk, r); + if (aktskill > s->maxskill) s->maxskill = aktskill; + } + if (!fval(f, FFL_SELECT)) { + f->nregions++; + fset(f, FFL_SELECT); + } + } + + f->num_total += u->number; + f->money += get_money(u); + s->poprace[old_race(u->race)] += u->number; + } + } + } + + return s; +} diff --git a/src/gamecode/summary.h b/src/gamecode/summary.h index e1a665d53..f7419a30b 100644 --- a/src/gamecode/summary.h +++ b/src/gamecode/summary.h @@ -1,25 +1,25 @@ -/* vi: set ts=2: - * +-------------------+ Christian Schlittchen - * | | Enno Rehling - * | Eressea PBEM host | Katja Zedel - * | (c) 1998 - 2007 | - * | | This program may not be used, modified or distributed - * +-------------------+ without prior permission by the authors of Eressea. - * - */ - -#ifndef H_GC_SUMMARY -#define H_GC_SUMMARY - -#ifdef __cplusplus -extern "C" { -#endif - - struct summary; - extern void report_summary(struct summary * n, struct summary * o, boolean full); - extern struct summary * make_summary(void); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2007 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +#ifndef H_GC_SUMMARY +#define H_GC_SUMMARY + +#ifdef __cplusplus +extern "C" { +#endif + + struct summary; + extern void report_summary(struct summary * n, struct summary * o, boolean full); + extern struct summary * make_summary(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/gmtool.c b/src/gmtool.c index 2fab96186..5d1ce1227 100644 --- a/src/gmtool.c +++ b/src/gmtool.c @@ -1,1296 +1,1298 @@ -/* vi: set ts=2: - * +-------------------+ Christian Schlittchen - * | | Enno Rehling - * | Eressea PBEM host | Katja Zedel - * | (c) 1998 - 2006 | - * | | This program may not be used, modified or distributed - * +-------------------+ without prior permission by the authors of Eressea. - * - */ - -/* wenn platform.h nicht vor curses included wird, kompiliert es unter windows nicht */ -#include -#include -#include - -#include "gmtool.h" -#include "gmtool_structs.h" - -#include -#include -#if MUSEUM_MODULE -#include -#endif -#if ARENA_MODULE -#include -#endif -#include -#include -#if DUNGEON_MODULE -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -static int g_quit; -int force_color = 0; - -state * current_state = NULL; - -#define IFL_SHIPS (1<<0) -#define IFL_UNITS (1<<1) -#define IFL_FACTIONS (1<<2) -#define IFL_BUILDINGS (1<<3) - -static WINDOW * hstatus; - -static void -init_curses(void) -{ - short fg, bg; - initscr(); - - if (has_colors() || force_color) { - short bcol = COLOR_BLACK; - short hcol = COLOR_MAGENTA; - start_color(); -#ifdef WIN32 - /* looks crap on putty with TERM=linux */ - if (can_change_color()) { - init_color(COLOR_YELLOW, 1000, 1000, 0); - } -#endif - - for (fg=0;fg!=8;++fg) { - for (bg=0;bg!=2;++bg) { - init_pair(fg+8*bg, fg, bg?hcol:bcol); - } - } - - attrset(COLOR_PAIR(COLOR_BLACK)); - bkgd(' ' | COLOR_PAIR(COLOR_BLACK)); - bkgdset(' ' | COLOR_PAIR(COLOR_BLACK)); - } - - keypad(stdscr, TRUE); /* enable keyboard mapping */ - meta(stdscr, TRUE); - nonl(); /* tell curses not to do NL->CR/NL on output */ - cbreak(); /* take input chars one at a time, no wait for \n */ - noecho(); /* don't echo input */ - scrollok(stdscr, FALSE); - refresh(); -} - -void cnormalize(const coordinate * c, int * x, int * y) -{ - *x = c->x; - *y = c->y; - pnormalize(x, y, c->pl); -} - -map_region * -mr_get(const view * vi, int xofs, int yofs) -{ - return vi->regions + xofs + yofs * vi->size.width; -} - -static point * -coor2point(const coordinate * c, point * p) -{ - assert(c && p); - p->x = c->x * TWIDTH + c->y * TWIDTH / 2; - p->y = c->y * THEIGHT; - return p; -} - -static window * wnd_first, * wnd_last; - -static window * -win_create(WINDOW * hwin) -{ - window * wnd = calloc(1, sizeof(window)); - wnd->handle = hwin; - if (wnd_first!=NULL) { - wnd->next = wnd_first; - wnd_first->prev = wnd; - wnd_first = wnd; - } else { - wnd_first = wnd; - wnd_last = wnd; - } - return wnd; -} - -static void -untag_region(selection * s, int nx, int ny) -{ - unsigned int key = ((nx << 12) ^ ny); - tag ** tp = &s->tags[key & (MAXTHASH-1)]; - tag * t = NULL; - while (*tp) { - t = *tp; - if (t->coord.x==nx && t->coord.y==ny) break; - tp=&t->nexthash; - } - if (!*tp) return; - *tp = t->nexthash; - free(t); - return; -} - -static void -tag_region(selection * s, int nx, int ny) -{ - unsigned int key = ((nx << 12) ^ ny); - tag ** tp = &s->tags[key & (MAXTHASH-1)]; - while (*tp) { - tag * t = *tp; - if (t->coord.x==nx && t->coord.y==ny) return; - tp=&t->nexthash; - } - *tp = calloc(1, sizeof(tag)); - (*tp)->coord.x = nx; - (*tp)->coord.y = ny; - (*tp)->coord.pl = findplane(nx, ny); - return; -} - -static int -tagged_region(selection * s, int nx, int ny) -{ - unsigned int key = ((nx << 12) ^ ny); - tag ** tp = &s->tags[key & (MAXTHASH-1)]; - while (*tp) { - tag * t = *tp; - if (t->coord.x==nx && t->coord.y==ny) return 1; - tp=&t->nexthash; - } - return 0; -} - -static int -mr_tile(const map_region * mr, int highlight) -{ - int hl = 8 * highlight; - if (mr!=NULL && mr->r!=NULL) { - const region * r = mr->r; - switch (r->terrain->_name[0]) { - case 'o' : - return '.' | COLOR_PAIR(hl + COLOR_CYAN); - case 'd' : - return 'D' | COLOR_PAIR(hl + COLOR_YELLOW) | A_BOLD; - case 't' : - return '%' | COLOR_PAIR(hl + COLOR_YELLOW) | A_BOLD; - case 'f' : - if (r->terrain->_name[1]=='o') { /* fog */ - return '.' | COLOR_PAIR(hl + COLOR_YELLOW) | A_NORMAL; - } else if (r->terrain->_name[1]=='i') { /* firewall */ - return '%' | COLOR_PAIR(hl + COLOR_RED) | A_BOLD; - } - case 'h' : - return 'H' | COLOR_PAIR(hl + COLOR_YELLOW) | A_NORMAL; - case 'm' : - return '^' | COLOR_PAIR(hl + COLOR_WHITE) | A_NORMAL; - case 'p' : - if (r_isforest(r)) return '#' | COLOR_PAIR(hl + COLOR_GREEN) | A_NORMAL; - return '+' | COLOR_PAIR(hl + COLOR_GREEN) | A_BOLD; - case 'g' : - return '*' | COLOR_PAIR(hl + COLOR_WHITE) | A_BOLD; - case 's' : - return 'S' | COLOR_PAIR(hl + COLOR_MAGENTA) | A_NORMAL; - } - return r->terrain->_name[0] | COLOR_PAIR(hl + COLOR_RED); - } - return ' ' | COLOR_PAIR(hl + COLOR_WHITE); -} - -static void -paint_map(window * wnd, const state * st) -{ - WINDOW * win = wnd->handle; - int lines = getmaxy(win); - int cols = getmaxx(win); - int vx, vy; - - lines = lines/THEIGHT; - cols = cols/TWIDTH; - for (vy = 0; vy!=lines; ++vy) { - int yp = (lines - vy - 1) * THEIGHT; - for (vx = 0; vx!=cols; ++vx) { - map_region * mr = mr_get(&st->display, vx, vy); - int attr = 0; - int hl = 0; - int xp = vx * TWIDTH + (vy & 1) * TWIDTH/2; - int nx, ny; - if (mr) { - if (st) { - cnormalize(&mr->coord, &nx, &ny); - if (tagged_region(st->selected, nx, ny)) { - attr |= A_REVERSE; - } - } - if (mr->r && mr->r->flags & RF_MAPPER_HIGHLIGHT) hl = 1; - mvwaddch(win, yp, xp, mr_tile(mr, hl) | attr); - } - } - } -} - -map_region * -cursor_region(const view * v, const coordinate * c) -{ - coordinate relpos; - int cx, cy; - - if (c) { - relpos.x = c->x - v->topleft.x; - relpos.y = c->y - v->topleft.y; - cy = relpos.y; - cx = relpos.x + cy/2; - return mr_get(v, cx, cy); - } - return NULL; -} - -static void -draw_cursor(WINDOW * win, selection * s, const view * v, const coordinate * c, int show) -{ - int lines = getmaxy(win)/THEIGHT; - int xp, yp, nx, ny; - int attr = 0; - map_region * mr = cursor_region(v, c); - coordinate relpos; - int cx, cy; - - if (!mr) return; - - relpos.x = c->x - v->topleft.x; - relpos.y = c->y - v->topleft.y; - cy = relpos.y; - cx = relpos.x + cy/2; - - yp = (lines - cy - 1) * THEIGHT; - xp = cx * TWIDTH + (cy & 1) * TWIDTH/2; - cnormalize(&mr->coord, &nx, &ny); - if (s && tagged_region(s, nx, ny)) attr = A_REVERSE; - if (mr->r) { - int hl = 0; - if (mr->r->flags & RF_MAPPER_HIGHLIGHT) hl = 1; - mvwaddch(win, yp, xp, mr_tile(mr, hl) | attr); - } - else mvwaddch(win, yp, xp, ' ' | attr | COLOR_PAIR(COLOR_YELLOW)); - if (show) { - attr = A_BOLD; - mvwaddch(win, yp, xp-1, '<' | attr | COLOR_PAIR(COLOR_YELLOW)); - mvwaddch(win, yp, xp+1, '>' | attr | COLOR_PAIR(COLOR_YELLOW)); - } else { - attr = A_NORMAL; - mvwaddch(win, yp, xp-1, ' ' | attr | COLOR_PAIR(COLOR_WHITE)); - mvwaddch(win, yp, xp+1, ' ' | attr | COLOR_PAIR(COLOR_WHITE)); - } - wmove(win, yp, xp); - wnoutrefresh(win); -} - - - -static void -paint_status(window * wnd, const state * st) -{ - WINDOW * win = wnd->handle; - const char * name = ""; - int nx, ny, uid = 0; - const char * terrain = "----"; - map_region * mr = cursor_region(&st->display, &st->cursor); - if (mr && mr->r) { - uid = mr->r->uid; - if (mr->r->land) { - name = (const char *)mr->r->land->name; - } else { - name = mr->r->terrain->_name; - } - terrain = mr->r->terrain->_name; - } - cnormalize(&st->cursor, &nx, &ny); - mvwprintw(win, 0, 0, "%4d %4d | %.4s | %.20s (%d)", nx, ny, terrain, name, uid); - wclrtoeol(win); -} - -static boolean -handle_info_region(window * wnd, state * st, int c) -{ - return false; -} - -static void -paint_info_region(window * wnd, const state * st) -{ - WINDOW * win = wnd->handle; - int size = getmaxx(win)-2; - int line = 0, maxline = getmaxy(win)-2; - map_region * mr = cursor_region(&st->display, &st->cursor); - - unused(st); - werase(win); - wxborder(win); - if (mr && mr->r) { - const region * r = mr->r; - if (r->land) { - mvwaddnstr(win, line++, 1, (char *)r->land->name, size); - } else { - mvwaddnstr(win, line++, 1, r->terrain->_name, size); - } - line++; - mvwprintw(win, line++, 1, "%s, age %d", r->terrain->_name, r->age); - if (r->land) { - mvwprintw(win, line++, 1, "$:%6d P:%5d", r->land->money, r->land->peasants); - mvwprintw(win, line++, 1, "H:%6d %s:%5d", r->land->horses, (r->flags&RF_MALLORN)?"M":"T", r->land->trees[1]+r->land->trees[2]); - } - line++; - if (r->ships && (st->info_flags & IFL_SHIPS)) { - ship * sh; - wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - mvwaddnstr(win, line++, 1, "* ships:", size-5); - wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - for (sh=r->ships;sh && linenext) { - mvwprintw(win, line, 1, "%.4s ", itoa36(sh->no)); - mvwaddnstr(win, line++, 6, (char*)sh->type->name[0], size-5); - } - } - if (r->units && (st->info_flags & IFL_FACTIONS)) { - unit * u; - wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - mvwaddnstr(win, line++, 1, "* factions:", size-5); - wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - for (u=r->units;u && linenext) { - if (!fval(u->faction, FFL_MARK)) { - mvwprintw(win, line, 1, "%.4s ", itoa36(u->faction->no)); - mvwaddnstr(win, line++, 6, (char *)u->faction->name, size-5); - fset(u->faction, FFL_MARK); - } - } - for (u=r->units;u && linenext) { - freset(u->faction, FFL_MARK); - } - } - if (r->units && (st->info_flags & IFL_UNITS)) { - unit * u; - wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - mvwaddnstr(win, line++, 1, "* units:", size-5); - wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - for (u=r->units;u && linenext) { - mvwprintw(win, line, 1, "%.4s ", itoa36(u->no)); - mvwaddnstr(win, line++, 6, (char *)u->name, size-5); - } - } - } -} - -static void (*paint_info)(struct window * wnd, const struct state * st); - -static void -paint_info_default(window * wnd, const state * st) -{ - if (paint_info) paint_info(wnd, st); - else paint_info_region(wnd, st); -} - -void set_info_function(void (*callback)(struct window *, const struct state *)) -{ - paint_info = callback; -} - -static char * -askstring(WINDOW * win, const char * q, char * buffer, size_t size) -{ - werase(win); - mvwaddstr(win, 0, 0, (char*)q); - wmove(win, 0, (int)(strlen(q)+1)); - echo(); - wgetnstr(win, buffer, (int)size); - noecho(); - return buffer; -} - -static void -statusline(WINDOW * win, const char * str) -{ - mvwaddstr(win, 0, 0, (char*)str); - wclrtoeol(win); - wnoutrefresh(win); -} - -static void -terraform_at(coordinate * c, const terrain_type *terrain) -{ - if (terrain!=NULL) { - region * r; - int nx = c->x, ny = c->y; - pnormalize(&nx, &ny, c->pl); - r = findregion(nx, ny); - if (r==NULL) { - r = new_region(nx, ny, c->pl, 0); - } - terraform_region(r, terrain); - } -} - -static void -terraform_selection(selection * selected, const terrain_type *terrain) -{ - int i; - - if (terrain==NULL) return; - for (i=0;i!=MAXTHASH;++i) { - tag ** tp = &selected->tags[i]; - while (*tp) { - region * r; - tag * t = *tp; - int nx = t->coord.x, ny = t->coord.y; - plane * pl = t->coord.pl; - - pnormalize(&nx, &ny, pl); - r = findregion(nx, ny); - if (r==NULL) { - r = new_region(nx, ny, pl, 0); - } - terraform_region(r, terrain); - tp = &t->nexthash; - } - } -} - -static faction * -select_faction(state * st) -{ - list_selection *prev, *ilist = NULL, **iinsert; - list_selection *selected = NULL; - faction * f = factions; - - if (!f) return NULL; - iinsert = &ilist; - prev = ilist; - - while (f) { - char buffer[32]; - sprintf(buffer, "%.4s %.26s", itoa36(f->no), f->name); - insert_selection(iinsert, NULL, buffer, (void*)f); - f = f->next; - } - selected = do_selection(ilist, "Select Faction", NULL, NULL); - st->wnd_info->update |= 1; - st->wnd_map->update |= 1; - st->wnd_status->update |= 1; - - if (selected==NULL) return NULL; - return (faction*)selected->data; -} - -static const terrain_type * -select_terrain(state * st, const terrain_type * default_terrain) -{ - list_selection *prev, *ilist = NULL, **iinsert; - list_selection *selected = NULL; - const terrain_type * terrain = terrains(); - - if (!terrain) return NULL; - iinsert = &ilist; - prev = ilist; - - while (terrain) { - insert_selection(iinsert, NULL, terrain->_name, (void*)terrain); - terrain = terrain->next; - } - selected = do_selection(ilist, "Terrain", NULL, NULL); - st->wnd_info->update |= 1; - st->wnd_map->update |= 1; - st->wnd_status->update |= 1; - - if (selected==NULL) return NULL; - return (const terrain_type*)selected->data; -} - -static coordinate * -region2coord(const region * r, coordinate * c) -{ - c->x = r->x; - c->y = r->y; - c->pl = rplane(r); - return c; -} - -#ifdef __PDCURSES__ -#define FAST_UP CTL_UP -#define FAST_DOWN CTL_DOWN -#define FAST_LEFT CTL_LEFT -#define FAST_RIGHT CTL_RIGHT -#else -#define FAST_UP KEY_PPAGE -#define FAST_DOWN KEY_NPAGE -#define FAST_LEFT KEY_SLEFT -#define FAST_RIGHT KEY_SRIGHT -#endif - -void -highlight_region(region *r, int toggle) -{ - if (r!=NULL) { - if (toggle) r->flags |= RF_MAPPER_HIGHLIGHT; - else r->flags &= ~RF_MAPPER_HIGHLIGHT; - } -} - -void -select_coordinate(struct selection * selected, int nx, int ny, int toggle) -{ - if (toggle) tag_region(selected, nx, ny); - else untag_region(selected, nx, ny); -} - -enum { MODE_MARK, MODE_SELECT, MODE_UNMARK, MODE_UNSELECT }; - -static void -select_regions(state * st, int selectmode) -{ - char sbuffer[80]; - int findmode; - const char * statustext[] = { - "mark-", "select-", "unmark-", "deselect-" - }; - const char * status = statustext[selectmode]; - statusline(st->wnd_status->handle, status); - doupdate(); - findmode = getch(); - if (findmode=='n') { /* none */ - int i; - sprintf(sbuffer, "%snone", status); - statusline(st->wnd_status->handle, sbuffer); - if (selectmode&MODE_SELECT) { - for (i=0;i!=MAXTHASH;++i) { - tag ** tp = &st->selected->tags[i]; - while (*tp) { - tag * t = *tp; - *tp = t->nexthash; - free(t); - } - } - } else { - region * r; - for (r=regions;r;r=r->next) { - r->flags &= ~RF_MAPPER_HIGHLIGHT; - } - } - } - else if (findmode=='m') { - region * r; - sprintf(sbuffer, "%smonsters", status); - statusline(st->wnd_status->handle, sbuffer); - for (r=regions;r;r=r->next) { - unit * u = r->units; - for (;u;u=u->next) { - if (fval(u->faction, FFL_NPC)!=0) break; - } - if (u) { - 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=='p') { - region * r; - sprintf(sbuffer, "%splayers", status); - statusline(st->wnd_status->handle, sbuffer); - for (r=regions;r;r=r->next) { - unit * u = r->units; - for (;u;u=u->next) { - if (fval(u->faction, FFL_NPC)==0) break; - } - if (u) { - 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=='u') { - region * r; - sprintf(sbuffer, "%sunits", status); - statusline(st->wnd_status->handle, sbuffer); - for (r=regions;r;r=r->next) { - if (r->units) { - 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=='s') { - region * r; - sprintf(sbuffer, "%sships", status); - statusline(st->wnd_status->handle, sbuffer); - for (r=regions;r;r=r->next) { - if (r->ships) { - 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=='f') { - char fbuffer[12]; - sprintf(sbuffer, "%sfaction:", status); - askstring(st->wnd_status->handle, sbuffer, fbuffer, 12); - if (fbuffer[0]) { - faction * f = findfaction(atoi36(fbuffer)); - - if (f!=NULL) { - unit * u; - - sprintf(sbuffer, "%sfaction: %s", status, itoa36(f->no)); - statusline(st->wnd_status->handle, sbuffer); - for (u=f->units;u;u=u->nextF) { - region * r = u->region; - if (selectmode&MODE_SELECT) { - select_coordinate(st->selected, r->x, r->y, selectmode==MODE_SELECT); - } else { - highlight_region(r, selectmode==MODE_MARK); - } - } - } else { - statusline(st->wnd_status->handle, "faction not found."); - beep(); - return; - } - } - } - else if (findmode=='t') { - const struct terrain_type * terrain; - sprintf(sbuffer, "%sterrain: ", status); - statusline(st->wnd_status->handle, sbuffer); - terrain = select_terrain(st, NULL); - if (terrain!=NULL) { - region * r; - sprintf(sbuffer, "%sterrain: %s", status, terrain->_name); - statusline(st->wnd_status->handle, sbuffer); - for (r=regions;r;r=r->next) { - if (r->terrain==terrain) { - if (selectmode&MODE_SELECT) { - select_coordinate(st->selected, r->x, r->y, selectmode==MODE_SELECT); - } else { - highlight_region(r, selectmode==MODE_MARK); - } - } - } - } - } else { - statusline(st->wnd_status->handle, "unknown command."); - beep(); - return; - } - st->wnd_info->update |= 3; - st->wnd_status->update |= 3; - st->wnd_map->update |= 3; -} - -static void -handlekey(state * st, int c) -{ - window * wnd; - coordinate * cursor = &st->cursor; - static char locate[80]; - static int findmode = 0; - region *r; - char sbuffer[80]; - static char kbuffer[80]; - int n, nx, ny; - - switch(c) { - case FAST_RIGHT: - cursor->x+=10; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case FAST_LEFT: - cursor->x-=10; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case FAST_UP: - cursor->y+=10; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case FAST_DOWN: - cursor->y-=10; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case KEY_UP: - cursor->y++; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case KEY_DOWN: - cursor->y--; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case KEY_RIGHT: - cursor->x++; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case KEY_LEFT: - cursor->x--; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case 'S': - case KEY_SAVE: - case KEY_F(2): - /* if (st->modified) */ { - char datafile[MAX_PATH]; - - askstring(st->wnd_status->handle, "save as:", datafile, sizeof(datafile)); - if (strlen(datafile)>0) { - create_backup(datafile); - remove_empty_units(); - writegame(datafile, IO_DEFAULT); - st->modified = 0; - } - } - break; - case 'B': - /* - make_block(st->cursor.x, st->cursor.y, 6, select_terrain(st, NULL)); - */ - cnormalize(&st->cursor, &nx, &ny); - n = rng_int() % 8 + 8; - build_island_e3(nx, ny, n, n*3); - st->modified = 1; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - st->wnd_map->update |= 1; - break; - case 0x02: /* CTRL+b */ - cnormalize(&st->cursor, &nx, &ny); - make_block(nx, ny, 6, newterrain(T_OCEAN)); - st->modified = 1; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - st->wnd_map->update |= 1; - break; - case 0x09: /* tab = next selected*/ - if (regions!=NULL) { - map_region * mr = cursor_region(&st->display, cursor); - if (mr) { - region * first = mr->r; - region * cur = (first&&first->next)?first->next:regions; - - while (cur!=first) { - coordinate coord; - region2coord(cur, &coord); - cnormalize(&coord, &nx, &ny); - if (tagged_region(st->selected, nx, ny)) { - st->cursor = coord; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - } - cur = cur->next; - if (!cur && first) cur = regions; - } - } - } - break; - - case 'p': - if (planes) { - plane * pl = planes; - if (cursor->pl) { - while (pl && pl!=cursor->pl) { - pl = pl->next; - } - if (pl && pl->next) { - cursor->pl = pl->next; - } else { - cursor->pl = get_homeplane(); - } - } else { - cursor->pl = planes; - } - } - break; - - case 'a': - if (regions!=NULL) { - map_region * mr = cursor_region(&st->display, cursor); - if (mr && mr->r) { - region * cur = mr->r; - plane * pl = rplane(cur); - if (pl==NULL) { - cur = r_standard_to_astral(cur); - } else if (is_astral(cur)) { - cur = r_astral_to_standard(cur); - } else { - cur = NULL; - } - if (cur!=NULL) { - region2coord(cur, &st->cursor); - } else { - beep(); - } - } - } - break; - case 'g': - askstring(st->wnd_status->handle, "goto-x:", sbuffer, 12); - if (sbuffer[0]) { - askstring(st->wnd_status->handle, "goto-y:", sbuffer+16, 12); - if (sbuffer[16]) { - st->cursor.x = atoi(sbuffer); - st->cursor.y = atoi(sbuffer+16); - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - } - } - break; - case 0x14: /* C-t */ - terraform_at(&st->cursor, select_terrain(st, NULL)); - st->modified = 1; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - st->wnd_map->update |= 1; - break; - case 'I': - statusline(st->wnd_status->handle, "info-"); - doupdate(); - do { - c = getch(); - switch (c) { - case 's': - st->info_flags ^= IFL_SHIPS; - if (st->info_flags & IFL_SHIPS) statusline(st->wnd_status->handle, "info-ships true"); - else statusline(st->wnd_status->handle, "info-ships false"); - break; - case 'b': - st->info_flags ^= IFL_BUILDINGS; - if (st->info_flags & IFL_BUILDINGS) statusline(st->wnd_status->handle, "info-buildings true"); - else statusline(st->wnd_status->handle, "info-buildings false"); - case 'f': - st->info_flags ^= IFL_FACTIONS; - if (st->info_flags & IFL_FACTIONS) statusline(st->wnd_status->handle, "info-factions true"); - else statusline(st->wnd_status->handle, "info-factions false"); - break; - case 'u': - st->info_flags ^= IFL_UNITS; - if (st->info_flags & IFL_UNITS) statusline(st->wnd_status->handle, "info-units true"); - else statusline(st->wnd_status->handle, "info-units false"); - break; - case 27: /* esc */ - break; - default: - beep(); - c = 0; - } - } while (c==0); - break; - case 'L': - if (global.vm_state) { - move(0, 0); - refresh(); - lua_do((struct lua_State*)global.vm_state); - /* todo: do this from inside the script */ - clear(); - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - st->wnd_map->update |= 1; - } - break; - case 12: /* Ctrl-L */ - clear(); - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - st->wnd_map->update |= 1; - break; - case 'h': - select_regions(st, MODE_MARK); - break; - case 'H': - select_regions(st, MODE_UNMARK); - break; - case 't': - select_regions(st, MODE_SELECT); - break; - case 'T': - select_regions(st, MODE_UNSELECT); - break; - case ';': - statusline(st->wnd_status->handle, "tag-"); - doupdate(); - switch (getch()) { - case 't': - terraform_selection(st->selected, select_terrain(st, NULL)); - st->modified = 1; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - st->wnd_map->update |= 1; - break; - case 'm': - break; - default: - statusline(st->wnd_status->handle, "unknown command."); - beep(); - } - break; - case ' ': - cnormalize(cursor, &nx, &ny); - if (tagged_region(st->selected, nx, ny)) untag_region(st->selected, nx, ny); - else tag_region(st->selected, nx, ny); - break; - case 'A': - sprintf(sbuffer, "%s/newfactions", basepath()); - seed_players(sbuffer, false); - st->wnd_map->update |= 1; - break; - case '/': - statusline(st->wnd_status->handle, "find-"); - doupdate(); - findmode = getch(); - if (findmode=='r') { - askstring(st->wnd_status->handle, "find-region:", locate, sizeof(locate)); - } else if (findmode=='u') { - askstring(st->wnd_status->handle, "find-unit:", locate, sizeof(locate)); - } else if (findmode=='f') { - askstring(st->wnd_status->handle, "find-faction:", locate, sizeof(locate)); - } else if (findmode=='F') { - faction * f = select_faction(st); - if (f!=NULL) { - strcpy(locate, itoa36(f->no)); - findmode='f'; - } else { - break; - } - } else { - statusline(st->wnd_status->handle, "unknown command."); - beep(); - break; - } - /* achtung: fall-through ist absicht: */ - if (!strlen(locate)) break; - case 'n': - if (findmode=='u') { - unit * u = findunit(atoi36(locate)); - r = u?u->region:NULL; - } else if (findmode && regions!=NULL) { - struct faction * f = NULL; - map_region * mr = cursor_region(&st->display, cursor); - region * first = (mr && mr->r && mr->r->next)?mr->r->next:regions; - - if (findmode=='f') { - sprintf(sbuffer, "find-faction: %s", locate); - statusline(st->wnd_status->handle, sbuffer); - f = findfaction(atoi36(locate)); - if (f==NULL) { - statusline(st->wnd_status->handle, "faction not found."); - beep(); - break; - } - } - for (r=first;;) { - if (findmode=='r' && r->land && r->land->name && strstr((const char*)r->land->name, locate)) { - break; - } else if (findmode=='f') { - unit * u; - for (u=r->units;u;u=u->next) { - if (u->faction==f) { - break; - } - } - if (u) break; - } - r = r->next; - if (r==NULL) r = regions; - if (r==first) { - r = NULL; - statusline(st->wnd_status->handle, "not found."); - beep(); - break; - } - } - } else { - r = NULL; - } - if (r!=NULL) { - region2coord(r, &st->cursor); - } - break; - case 'Q': - g_quit = 1; - break; - default: - for (wnd=wnd_first;wnd!=NULL;wnd=wnd->next) { - if (wnd->handlekey) { - if (wnd->handlekey(wnd, st, c)) break; - } - } - if (wnd==NULL) { - if (kbuffer[0]==0) { - strcpy(kbuffer, "getch:"); - } - sprintf(sbuffer, " 0x%x", c); - strncat(kbuffer, sbuffer, sizeof(kbuffer)); - statusline(st->wnd_status->handle, kbuffer); - if (strlen(kbuffer)>70) kbuffer[0]=0; - } - break; - } -} - -static void -init_view(view * display, WINDOW * win) -{ - display->topleft.x = 1; - display->topleft.y = 1; - display->topleft.pl = get_homeplane(); - display->pl = get_homeplane(); - display->size.width = getmaxx(win)/TWIDTH; - display->size.height = getmaxy(win)/THEIGHT; - display->regions = calloc(display->size.height * display->size.width, sizeof(map_region)); -} - -static void -update_view(view * vi) -{ - int i, j; - for (i=0;i!=vi->size.width;++i) { - for (j=0;j!=vi->size.height;++j) { - map_region * mr = mr_get(vi, i, j); - mr->coord.x = vi->topleft.x + i - j/2; - mr->coord.y = vi->topleft.y + j; - mr->coord.pl = vi->pl; - pnormalize(&mr->coord.x, &mr->coord.y, mr->coord.pl); - mr->r = findregion(mr->coord.x, mr->coord.y); - } - } -} - -state * -state_open(void) -{ - state * st = calloc(sizeof(state), 1); - st->display.pl = get_homeplane(); - st->cursor.pl = get_homeplane(); - st->cursor.x = 0; - st->cursor.y = 0; - st->selected = calloc(1, sizeof(struct selection)); - st->modified = 0; - st->info_flags = 0xFFFFFFFF; - st->prev = current_state; - current_state = st; - return st; -} - -void -state_close(state * st) -{ - assert(st==current_state); - current_state = st->prev; - free(st); -} - -void -run_mapper(void) -{ - WINDOW * hwinstatus; - WINDOW * hwininfo; - WINDOW * hwinmap; - int width, height, x, y; - int split = 20, old_flags = log_flags; - state * st; - point tl; - - log_flags &= ~(LOG_CPERROR|LOG_CPWARNING); - init_curses(); - curs_set(1); - - set_readline(curses_readline); - - getbegyx(stdscr, x, y); - width = getmaxx(stdscr); - height = getmaxy(stdscr); - - hwinmap = subwin(stdscr, getmaxy(stdscr)-1, getmaxx(stdscr)-split, y, x); - hwininfo = subwin(stdscr, getmaxy(stdscr)-1, split, y, x+getmaxx(stdscr)-split); - hwinstatus = subwin(stdscr, 1, width, height-1, x); - - st = state_open(); - st->wnd_map = win_create(hwinmap); - st->wnd_map->paint = &paint_map; - st->wnd_map->update = 1; - st->wnd_info = win_create(hwininfo); - st->wnd_info->paint = &paint_info_default; - st->wnd_info->handlekey = &handle_info_region; - st->wnd_info->update = 1; - st->wnd_status = win_create(hwinstatus); - st->wnd_status->paint = &paint_status; - st->wnd_status->update = 1; - - init_view(&st->display, hwinmap); - coor2point(&st->display.topleft, &tl); - - hstatus = st->wnd_status->handle; /* the lua console needs this */ - - while (!g_quit) { - int c; - point p; - window * wnd; - view * vi = &st->display; - - getbegyx(hwinmap, x, y); - width = getmaxx(hwinmap)-x; - height = getmaxy(hwinmap)-y; - coor2point(&st->cursor, &p); - - if (st->cursor.pl != vi->pl) { - vi->pl = st->cursor.pl; - st->wnd_map->update |= 1; - } - if (p.y < tl.y) { - vi->topleft.y = st->cursor.y-vi->size.height/2; - st->wnd_map->update |= 1; - } - else if (p.y >= tl.y + vi->size.height * THEIGHT) { - vi->topleft.y = st->cursor.y-vi->size.height/2; - st->wnd_map->update |= 1; - } - if (p.x <= tl.x) { - vi->topleft.x = st->cursor.x+(st->cursor.y-vi->topleft.y)/2-vi->size.width / 2; - st->wnd_map->update |= 1; - } - else if (p.x >= tl.x + vi->size.width * TWIDTH-1) { - vi->topleft.x = st->cursor.x+(st->cursor.y-vi->topleft.y)/2-vi->size.width / 2; - st->wnd_map->update |= 1; - } - - if (st->wnd_map->update) { - update_view(vi); - coor2point(&vi->topleft, &tl); - } - for (wnd=wnd_last;wnd!=NULL;wnd=wnd->prev) { - if (wnd->update && wnd->paint) { - if (wnd->update & 1) { - wnd->paint(wnd, st); - wnoutrefresh(wnd->handle); - } - if (wnd->update & 2) { - touchwin(wnd->handle); - } - wnd->update = 0; - } - } - draw_cursor(st->wnd_map->handle, st->selected, vi, &st->cursor, 1); - doupdate(); - c = getch(); - draw_cursor(st->wnd_map->handle, st->selected, vi, &st->cursor, 0); - handlekey(st, c); - } - g_quit = 0; - set_readline(NULL); - curs_set(1); - endwin(); - log_flags = old_flags; - state_close(st); -} - -int -curses_readline(struct lua_State * L, char * buffer, size_t size, const char * prompt) -{ - unused(L); - askstring(hstatus, prompt, buffer, size); - return buffer[0]!=0; -} - - -void -seed_players(const char * filename, boolean new_island) -{ - newfaction * players = read_newfactions(filename); - if (players!=NULL) { - while (players) { - int n = listlen(players); - int k = (n+ISLANDSIZE-1)/ISLANDSIZE; - k = n / k; - n = autoseed(&players, k, new_island?0:TURNS_PER_ISLAND); - if (n==0) { - break; - } - } - } -} - -void -make_block(int x, int y, int radius, const struct terrain_type * terrain) -{ - int cx, cy; - region *r; - plane * pl = findplane(x, y); - - if (terrain==NULL) return; - - for (cx = x - radius; cx != x+radius; ++cx) { - for (cy = y - radius; cy != y+radius; ++cy) { - int nx = cx, ny = cy; - pnormalize(&nx, &ny, pl); - if (koor_distance(nx, ny, x, y) < radius) { - if (!findregion(nx, ny)) { - r = new_region(nx, ny, pl, 0); - terraform_region(r, terrain); - } - } - } - } -} +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2006 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +/* wenn platform.h nicht vor curses included wird, kompiliert es unter windows nicht */ +#include +#include +#include + +#include "gmtool.h" +#include "gmtool_structs.h" + +#include +#include +#if MUSEUM_MODULE +#include +#endif +#if ARENA_MODULE +#include +#endif +#include +#include +#if DUNGEON_MODULE +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +static int g_quit; +int force_color = 0; + +state * current_state = NULL; + +#define IFL_SHIPS (1<<0) +#define IFL_UNITS (1<<1) +#define IFL_FACTIONS (1<<2) +#define IFL_BUILDINGS (1<<3) + +static WINDOW * hstatus; + +static void +init_curses(void) +{ + short fg, bg; + initscr(); + + if (has_colors() || force_color) { + short bcol = COLOR_BLACK; + short hcol = COLOR_MAGENTA; + start_color(); +#ifdef WIN32 + /* looks crap on putty with TERM=linux */ + if (can_change_color()) { + init_color(COLOR_YELLOW, 1000, 1000, 0); + } +#endif + + for (fg=0;fg!=8;++fg) { + for (bg=0;bg!=2;++bg) { + init_pair(fg+8*bg, fg, bg?hcol:bcol); + } + } + + attrset(COLOR_PAIR(COLOR_BLACK)); + bkgd(' ' | COLOR_PAIR(COLOR_BLACK)); + bkgdset(' ' | COLOR_PAIR(COLOR_BLACK)); + } + + keypad(stdscr, TRUE); /* enable keyboard mapping */ + meta(stdscr, TRUE); + nonl(); /* tell curses not to do NL->CR/NL on output */ + cbreak(); /* take input chars one at a time, no wait for \n */ + noecho(); /* don't echo input */ + scrollok(stdscr, FALSE); + refresh(); +} + +void cnormalize(const coordinate * c, int * x, int * y) +{ + *x = c->x; + *y = c->y; + pnormalize(x, y, c->pl); +} + +map_region * +mr_get(const view * vi, int xofs, int yofs) +{ + return vi->regions + xofs + yofs * vi->size.width; +} + +static point * +coor2point(const coordinate * c, point * p) +{ + assert(c && p); + p->x = c->x * TWIDTH + c->y * TWIDTH / 2; + p->y = c->y * THEIGHT; + return p; +} + +static window * wnd_first, * wnd_last; + +static window * +win_create(WINDOW * hwin) +{ + window * wnd = calloc(1, sizeof(window)); + wnd->handle = hwin; + if (wnd_first!=NULL) { + wnd->next = wnd_first; + wnd_first->prev = wnd; + wnd_first = wnd; + } else { + wnd_first = wnd; + wnd_last = wnd; + } + return wnd; +} + +static void +untag_region(selection * s, int nx, int ny) +{ + unsigned int key = ((nx << 12) ^ ny); + tag ** tp = &s->tags[key & (MAXTHASH-1)]; + tag * t = NULL; + while (*tp) { + t = *tp; + if (t->coord.x==nx && t->coord.y==ny) break; + tp=&t->nexthash; + } + if (!*tp) return; + *tp = t->nexthash; + free(t); + return; +} + +static void +tag_region(selection * s, int nx, int ny) +{ + unsigned int key = ((nx << 12) ^ ny); + tag ** tp = &s->tags[key & (MAXTHASH-1)]; + while (*tp) { + tag * t = *tp; + if (t->coord.x==nx && t->coord.y==ny) return; + tp=&t->nexthash; + } + *tp = calloc(1, sizeof(tag)); + (*tp)->coord.x = nx; + (*tp)->coord.y = ny; + (*tp)->coord.pl = findplane(nx, ny); + return; +} + +static int +tagged_region(selection * s, int nx, int ny) +{ + unsigned int key = ((nx << 12) ^ ny); + tag ** tp = &s->tags[key & (MAXTHASH-1)]; + while (*tp) { + tag * t = *tp; + if (t->coord.x==nx && t->coord.y==ny) return 1; + tp=&t->nexthash; + } + return 0; +} + +static int +mr_tile(const map_region * mr, int highlight) +{ + int hl = 8 * highlight; + if (mr!=NULL && mr->r!=NULL) { + const region * r = mr->r; + switch (r->terrain->_name[0]) { + case 'o' : + return '.' | COLOR_PAIR(hl + COLOR_CYAN); + case 'd' : + return 'D' | COLOR_PAIR(hl + COLOR_YELLOW) | A_BOLD; + case 't' : + return '%' | COLOR_PAIR(hl + COLOR_YELLOW) | A_BOLD; + case 'f' : + if (r->terrain->_name[1]=='o') { /* fog */ + return '.' | COLOR_PAIR(hl + COLOR_YELLOW) | A_NORMAL; + } else if (r->terrain->_name[1]=='i') { /* firewall */ + return '%' | COLOR_PAIR(hl + COLOR_RED) | A_BOLD; + } + case 'h' : + return 'H' | COLOR_PAIR(hl + COLOR_YELLOW) | A_NORMAL; + case 'm' : + return '^' | COLOR_PAIR(hl + COLOR_WHITE) | A_NORMAL; + case 'p' : + if (r_isforest(r)) return '#' | COLOR_PAIR(hl + COLOR_GREEN) | A_NORMAL; + return '+' | COLOR_PAIR(hl + COLOR_GREEN) | A_BOLD; + case 'g' : + return '*' | COLOR_PAIR(hl + COLOR_WHITE) | A_BOLD; + case 's' : + return 'S' | COLOR_PAIR(hl + COLOR_MAGENTA) | A_NORMAL; + } + return r->terrain->_name[0] | COLOR_PAIR(hl + COLOR_RED); + } + return ' ' | COLOR_PAIR(hl + COLOR_WHITE); +} + +static void +paint_map(window * wnd, const state * st) +{ + WINDOW * win = wnd->handle; + int lines = getmaxy(win); + int cols = getmaxx(win); + int vx, vy; + + lines = lines/THEIGHT; + cols = cols/TWIDTH; + for (vy = 0; vy!=lines; ++vy) { + int yp = (lines - vy - 1) * THEIGHT; + for (vx = 0; vx!=cols; ++vx) { + map_region * mr = mr_get(&st->display, vx, vy); + int attr = 0; + int hl = 0; + int xp = vx * TWIDTH + (vy & 1) * TWIDTH/2; + int nx, ny; + if (mr) { + if (st) { + cnormalize(&mr->coord, &nx, &ny); + if (tagged_region(st->selected, nx, ny)) { + attr |= A_REVERSE; + } + } + if (mr->r && mr->r->flags & RF_MAPPER_HIGHLIGHT) hl = 1; + mvwaddch(win, yp, xp, mr_tile(mr, hl) | attr); + } + } + } +} + +map_region * +cursor_region(const view * v, const coordinate * c) +{ + coordinate relpos; + int cx, cy; + + if (c) { + relpos.x = c->x - v->topleft.x; + relpos.y = c->y - v->topleft.y; + cy = relpos.y; + cx = relpos.x + cy/2; + return mr_get(v, cx, cy); + } + return NULL; +} + +static void +draw_cursor(WINDOW * win, selection * s, const view * v, const coordinate * c, int show) +{ + int lines = getmaxy(win)/THEIGHT; + int xp, yp, nx, ny; + int attr = 0; + map_region * mr = cursor_region(v, c); + coordinate relpos; + int cx, cy; + + if (!mr) return; + + relpos.x = c->x - v->topleft.x; + relpos.y = c->y - v->topleft.y; + cy = relpos.y; + cx = relpos.x + cy/2; + + yp = (lines - cy - 1) * THEIGHT; + xp = cx * TWIDTH + (cy & 1) * TWIDTH/2; + cnormalize(&mr->coord, &nx, &ny); + if (s && tagged_region(s, nx, ny)) attr = A_REVERSE; + if (mr->r) { + int hl = 0; + if (mr->r->flags & RF_MAPPER_HIGHLIGHT) hl = 1; + mvwaddch(win, yp, xp, mr_tile(mr, hl) | attr); + } + else mvwaddch(win, yp, xp, ' ' | attr | COLOR_PAIR(COLOR_YELLOW)); + if (show) { + attr = A_BOLD; + mvwaddch(win, yp, xp-1, '<' | attr | COLOR_PAIR(COLOR_YELLOW)); + mvwaddch(win, yp, xp+1, '>' | attr | COLOR_PAIR(COLOR_YELLOW)); + } else { + attr = A_NORMAL; + mvwaddch(win, yp, xp-1, ' ' | attr | COLOR_PAIR(COLOR_WHITE)); + mvwaddch(win, yp, xp+1, ' ' | attr | COLOR_PAIR(COLOR_WHITE)); + } + wmove(win, yp, xp); + wnoutrefresh(win); +} + + + +static void +paint_status(window * wnd, const state * st) +{ + WINDOW * win = wnd->handle; + const char * name = ""; + int nx, ny, uid = 0; + const char * terrain = "----"; + map_region * mr = cursor_region(&st->display, &st->cursor); + if (mr && mr->r) { + uid = mr->r->uid; + if (mr->r->land) { + name = (const char *)mr->r->land->name; + } else { + name = mr->r->terrain->_name; + } + terrain = mr->r->terrain->_name; + } + cnormalize(&st->cursor, &nx, &ny); + mvwprintw(win, 0, 0, "%4d %4d | %.4s | %.20s (%d)", nx, ny, terrain, name, uid); + wclrtoeol(win); +} + +static boolean +handle_info_region(window * wnd, state * st, int c) +{ + return false; +} + +static void +paint_info_region(window * wnd, const state * st) +{ + WINDOW * win = wnd->handle; + int size = getmaxx(win)-2; + int line = 0, maxline = getmaxy(win)-2; + map_region * mr = cursor_region(&st->display, &st->cursor); + + unused(st); + werase(win); + wxborder(win); + if (mr && mr->r) { + const region * r = mr->r; + if (r->land) { + mvwaddnstr(win, line++, 1, (char *)r->land->name, size); + } else { + mvwaddnstr(win, line++, 1, r->terrain->_name, size); + } + line++; + mvwprintw(win, line++, 1, "%s, age %d", r->terrain->_name, r->age); + if (r->land) { + mvwprintw(win, line++, 1, "$:%6d P:%5d", r->land->money, r->land->peasants); + mvwprintw(win, line++, 1, "H:%6d %s:%5d", r->land->horses, (r->flags&RF_MALLORN)?"M":"T", r->land->trees[1]+r->land->trees[2]); + } + line++; + if (r->ships && (st->info_flags & IFL_SHIPS)) { + ship * sh; + wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + mvwaddnstr(win, line++, 1, "* ships:", size-5); + wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + for (sh=r->ships;sh && linenext) { + mvwprintw(win, line, 1, "%.4s ", itoa36(sh->no)); + mvwaddnstr(win, line++, 6, (char*)sh->type->name[0], size-5); + } + } + if (r->units && (st->info_flags & IFL_FACTIONS)) { + unit * u; + wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + mvwaddnstr(win, line++, 1, "* factions:", size-5); + wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + for (u=r->units;u && linenext) { + if (!fval(u->faction, FFL_MARK)) { + mvwprintw(win, line, 1, "%.4s ", itoa36(u->faction->no)); + mvwaddnstr(win, line++, 6, (char *)u->faction->name, size-5); + fset(u->faction, FFL_MARK); + } + } + for (u=r->units;u && linenext) { + freset(u->faction, FFL_MARK); + } + } + if (r->units && (st->info_flags & IFL_UNITS)) { + unit * u; + wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + mvwaddnstr(win, line++, 1, "* units:", size-5); + wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + for (u=r->units;u && linenext) { + mvwprintw(win, line, 1, "%.4s ", itoa36(u->no)); + mvwaddnstr(win, line++, 6, (char *)u->name, size-5); + } + } + } +} + +static void (*paint_info)(struct window * wnd, const struct state * st); + +static void +paint_info_default(window * wnd, const state * st) +{ + if (paint_info) paint_info(wnd, st); + else paint_info_region(wnd, st); +} + +void set_info_function(void (*callback)(struct window *, const struct state *)) +{ + paint_info = callback; +} + +static char * +askstring(WINDOW * win, const char * q, char * buffer, size_t size) +{ + werase(win); + mvwaddstr(win, 0, 0, (char*)q); + wmove(win, 0, (int)(strlen(q)+1)); + echo(); + wgetnstr(win, buffer, (int)size); + noecho(); + return buffer; +} + +static void +statusline(WINDOW * win, const char * str) +{ + mvwaddstr(win, 0, 0, (char*)str); + wclrtoeol(win); + wnoutrefresh(win); +} + +static void +terraform_at(coordinate * c, const terrain_type *terrain) +{ + if (terrain!=NULL) { + region * r; + int nx = c->x, ny = c->y; + pnormalize(&nx, &ny, c->pl); + r = findregion(nx, ny); + if (r==NULL) { + r = new_region(nx, ny, c->pl, 0); + } + terraform_region(r, terrain); + } +} + +static void +terraform_selection(selection * selected, const terrain_type *terrain) +{ + int i; + + if (terrain==NULL) return; + for (i=0;i!=MAXTHASH;++i) { + tag ** tp = &selected->tags[i]; + while (*tp) { + region * r; + tag * t = *tp; + int nx = t->coord.x, ny = t->coord.y; + plane * pl = t->coord.pl; + + pnormalize(&nx, &ny, pl); + r = findregion(nx, ny); + if (r==NULL) { + r = new_region(nx, ny, pl, 0); + } + terraform_region(r, terrain); + tp = &t->nexthash; + } + } +} + +static faction * +select_faction(state * st) +{ + list_selection *prev, *ilist = NULL, **iinsert; + list_selection *selected = NULL; + faction * f = factions; + + if (!f) return NULL; + iinsert = &ilist; + prev = ilist; + + while (f) { + char buffer[32]; + sprintf(buffer, "%.4s %.26s", itoa36(f->no), f->name); + insert_selection(iinsert, NULL, buffer, (void*)f); + f = f->next; + } + selected = do_selection(ilist, "Select Faction", NULL, NULL); + st->wnd_info->update |= 1; + st->wnd_map->update |= 1; + st->wnd_status->update |= 1; + + if (selected==NULL) return NULL; + return (faction*)selected->data; +} + +static const terrain_type * +select_terrain(state * st, const terrain_type * default_terrain) +{ + list_selection *prev, *ilist = NULL, **iinsert; + list_selection *selected = NULL; + const terrain_type * terrain = terrains(); + + if (!terrain) return NULL; + iinsert = &ilist; + prev = ilist; + + while (terrain) { + insert_selection(iinsert, NULL, terrain->_name, (void*)terrain); + terrain = terrain->next; + } + selected = do_selection(ilist, "Terrain", NULL, NULL); + st->wnd_info->update |= 1; + st->wnd_map->update |= 1; + st->wnd_status->update |= 1; + + if (selected==NULL) return NULL; + return (const terrain_type*)selected->data; +} + +static coordinate * +region2coord(const region * r, coordinate * c) +{ + c->x = r->x; + c->y = r->y; + c->pl = rplane(r); + return c; +} + +#ifdef __PDCURSES__ +#define FAST_UP CTL_UP +#define FAST_DOWN CTL_DOWN +#define FAST_LEFT CTL_LEFT +#define FAST_RIGHT CTL_RIGHT +#else +#define FAST_UP KEY_PPAGE +#define FAST_DOWN KEY_NPAGE +#define FAST_LEFT KEY_SLEFT +#define FAST_RIGHT KEY_SRIGHT +#endif + +void +highlight_region(region *r, int toggle) +{ + if (r!=NULL) { + if (toggle) r->flags |= RF_MAPPER_HIGHLIGHT; + else r->flags &= ~RF_MAPPER_HIGHLIGHT; + } +} + +void +select_coordinate(struct selection * selected, int nx, int ny, int toggle) +{ + if (toggle) tag_region(selected, nx, ny); + else untag_region(selected, nx, ny); +} + +enum { MODE_MARK, MODE_SELECT, MODE_UNMARK, MODE_UNSELECT }; + +static void +select_regions(state * st, int selectmode) +{ + char sbuffer[80]; + int findmode; + const char * statustext[] = { + "mark-", "select-", "unmark-", "deselect-" + }; + const char * status = statustext[selectmode]; + statusline(st->wnd_status->handle, status); + doupdate(); + findmode = getch(); + if (findmode=='n') { /* none */ + int i; + sprintf(sbuffer, "%snone", status); + statusline(st->wnd_status->handle, sbuffer); + if (selectmode&MODE_SELECT) { + for (i=0;i!=MAXTHASH;++i) { + tag ** tp = &st->selected->tags[i]; + while (*tp) { + tag * t = *tp; + *tp = t->nexthash; + free(t); + } + } + } else { + region * r; + for (r=regions;r;r=r->next) { + r->flags &= ~RF_MAPPER_HIGHLIGHT; + } + } + } + else if (findmode=='m') { + region * r; + sprintf(sbuffer, "%smonsters", status); + statusline(st->wnd_status->handle, sbuffer); + for (r=regions;r;r=r->next) { + unit * u = r->units; + for (;u;u=u->next) { + if (fval(u->faction, FFL_NPC)!=0) break; + } + if (u) { + 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=='p') { + region * r; + sprintf(sbuffer, "%splayers", status); + statusline(st->wnd_status->handle, sbuffer); + for (r=regions;r;r=r->next) { + unit * u = r->units; + for (;u;u=u->next) { + if (fval(u->faction, FFL_NPC)==0) break; + } + if (u) { + 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=='u') { + region * r; + sprintf(sbuffer, "%sunits", status); + statusline(st->wnd_status->handle, sbuffer); + for (r=regions;r;r=r->next) { + if (r->units) { + 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=='s') { + region * r; + sprintf(sbuffer, "%sships", status); + statusline(st->wnd_status->handle, sbuffer); + for (r=regions;r;r=r->next) { + if (r->ships) { + 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=='f') { + char fbuffer[12]; + sprintf(sbuffer, "%sfaction:", status); + askstring(st->wnd_status->handle, sbuffer, fbuffer, 12); + if (fbuffer[0]) { + faction * f = findfaction(atoi36(fbuffer)); + + if (f!=NULL) { + unit * u; + + sprintf(sbuffer, "%sfaction: %s", status, itoa36(f->no)); + statusline(st->wnd_status->handle, sbuffer); + for (u=f->units;u;u=u->nextF) { + region * r = u->region; + if (selectmode&MODE_SELECT) { + select_coordinate(st->selected, r->x, r->y, selectmode==MODE_SELECT); + } else { + highlight_region(r, selectmode==MODE_MARK); + } + } + } else { + statusline(st->wnd_status->handle, "faction not found."); + beep(); + return; + } + } + } + else if (findmode=='t') { + const struct terrain_type * terrain; + sprintf(sbuffer, "%sterrain: ", status); + statusline(st->wnd_status->handle, sbuffer); + terrain = select_terrain(st, NULL); + if (terrain!=NULL) { + region * r; + sprintf(sbuffer, "%sterrain: %s", status, terrain->_name); + statusline(st->wnd_status->handle, sbuffer); + for (r=regions;r;r=r->next) { + if (r->terrain==terrain) { + if (selectmode&MODE_SELECT) { + select_coordinate(st->selected, r->x, r->y, selectmode==MODE_SELECT); + } else { + highlight_region(r, selectmode==MODE_MARK); + } + } + } + } + } else { + statusline(st->wnd_status->handle, "unknown command."); + beep(); + return; + } + st->wnd_info->update |= 3; + st->wnd_status->update |= 3; + st->wnd_map->update |= 3; +} + +static void +handlekey(state * st, int c) +{ + window * wnd; + coordinate * cursor = &st->cursor; + static char locate[80]; + static int findmode = 0; + region *r; + char sbuffer[80]; + static char kbuffer[80]; + int n, nx, ny; + + switch(c) { + case FAST_RIGHT: + cursor->x+=10; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case FAST_LEFT: + cursor->x-=10; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case FAST_UP: + cursor->y+=10; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case FAST_DOWN: + cursor->y-=10; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case KEY_UP: + cursor->y++; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case KEY_DOWN: + cursor->y--; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case KEY_RIGHT: + cursor->x++; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case KEY_LEFT: + cursor->x--; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case 'S': + case KEY_SAVE: + case KEY_F(2): + /* if (st->modified) */ { + char datafile[MAX_PATH]; + + askstring(st->wnd_status->handle, "save as:", datafile, sizeof(datafile)); + if (strlen(datafile)>0) { + create_backup(datafile); + remove_empty_units(); + writegame(datafile, IO_DEFAULT); + st->modified = 0; + } + } + break; + case 'B': + /* + make_block(st->cursor.x, st->cursor.y, 6, select_terrain(st, NULL)); + */ + cnormalize(&st->cursor, &nx, &ny); + n = rng_int() % 8 + 8; + build_island_e3(nx, ny, n, n*3); + st->modified = 1; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + break; + case 0x02: /* CTRL+b */ + cnormalize(&st->cursor, &nx, &ny); + make_block(nx, ny, 6, newterrain(T_OCEAN)); + st->modified = 1; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + break; + case 0x09: /* tab = next selected*/ + if (regions!=NULL) { + map_region * mr = cursor_region(&st->display, cursor); + if (mr) { + region * first = mr->r; + region * cur = (first&&first->next)?first->next:regions; + + while (cur!=first) { + coordinate coord; + region2coord(cur, &coord); + cnormalize(&coord, &nx, &ny); + if (tagged_region(st->selected, nx, ny)) { + st->cursor = coord; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + } + cur = cur->next; + if (!cur && first) cur = regions; + } + } + } + break; + + case 'p': + if (planes) { + plane * pl = planes; + if (cursor->pl) { + while (pl && pl!=cursor->pl) { + pl = pl->next; + } + if (pl && pl->next) { + cursor->pl = pl->next; + } else { + cursor->pl = get_homeplane(); + } + } else { + cursor->pl = planes; + } + } + break; + + case 'a': + if (regions!=NULL) { + map_region * mr = cursor_region(&st->display, cursor); + if (mr && mr->r) { + region * cur = mr->r; + plane * pl = rplane(cur); + if (pl==NULL) { + cur = r_standard_to_astral(cur); + } else if (is_astral(cur)) { + cur = r_astral_to_standard(cur); + } else { + cur = NULL; + } + if (cur!=NULL) { + region2coord(cur, &st->cursor); + } else { + beep(); + } + } + } + break; + case 'g': + askstring(st->wnd_status->handle, "goto-x:", sbuffer, 12); + if (sbuffer[0]) { + askstring(st->wnd_status->handle, "goto-y:", sbuffer+16, 12); + if (sbuffer[16]) { + st->cursor.x = atoi(sbuffer); + st->cursor.y = atoi(sbuffer+16); + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + } + } + break; + case 0x14: /* C-t */ + terraform_at(&st->cursor, select_terrain(st, NULL)); + st->modified = 1; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + break; + case 'I': + statusline(st->wnd_status->handle, "info-"); + doupdate(); + do { + c = getch(); + switch (c) { + case 's': + st->info_flags ^= IFL_SHIPS; + if (st->info_flags & IFL_SHIPS) statusline(st->wnd_status->handle, "info-ships true"); + else statusline(st->wnd_status->handle, "info-ships false"); + break; + case 'b': + st->info_flags ^= IFL_BUILDINGS; + if (st->info_flags & IFL_BUILDINGS) statusline(st->wnd_status->handle, "info-buildings true"); + else statusline(st->wnd_status->handle, "info-buildings false"); + case 'f': + st->info_flags ^= IFL_FACTIONS; + if (st->info_flags & IFL_FACTIONS) statusline(st->wnd_status->handle, "info-factions true"); + else statusline(st->wnd_status->handle, "info-factions false"); + break; + case 'u': + st->info_flags ^= IFL_UNITS; + if (st->info_flags & IFL_UNITS) statusline(st->wnd_status->handle, "info-units true"); + else statusline(st->wnd_status->handle, "info-units false"); + break; + case 27: /* esc */ + break; + default: + beep(); + c = 0; + } + } while (c==0); + break; + case 'L': + if (global.vm_state) { + move(0, 0); + refresh(); + lua_do((struct lua_State*)global.vm_state); + /* todo: do this from inside the script */ + clear(); + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + } + break; + case 12: /* Ctrl-L */ + clear(); + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + break; + case 'h': + select_regions(st, MODE_MARK); + break; + case 'H': + select_regions(st, MODE_UNMARK); + break; + case 't': + select_regions(st, MODE_SELECT); + break; + case 'T': + select_regions(st, MODE_UNSELECT); + break; + case ';': + statusline(st->wnd_status->handle, "tag-"); + doupdate(); + switch (getch()) { + case 't': + terraform_selection(st->selected, select_terrain(st, NULL)); + st->modified = 1; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + break; + case 'm': + break; + default: + statusline(st->wnd_status->handle, "unknown command."); + beep(); + } + break; + case ' ': + cnormalize(cursor, &nx, &ny); + if (tagged_region(st->selected, nx, ny)) untag_region(st->selected, nx, ny); + else tag_region(st->selected, nx, ny); + break; + case 'A': + sprintf(sbuffer, "%s/newfactions", basepath()); + seed_players(sbuffer, false); + st->wnd_map->update |= 1; + break; + case '/': + statusline(st->wnd_status->handle, "find-"); + doupdate(); + findmode = getch(); + if (findmode=='r') { + askstring(st->wnd_status->handle, "find-region:", locate, sizeof(locate)); + } else if (findmode=='u') { + askstring(st->wnd_status->handle, "find-unit:", locate, sizeof(locate)); + } else if (findmode=='f') { + askstring(st->wnd_status->handle, "find-faction:", locate, sizeof(locate)); + } else if (findmode=='F') { + faction * f = select_faction(st); + if (f!=NULL) { + strcpy(locate, itoa36(f->no)); + findmode='f'; + } else { + break; + } + } else { + statusline(st->wnd_status->handle, "unknown command."); + beep(); + break; + } + /* achtung: fall-through ist absicht: */ + if (!strlen(locate)) break; + case 'n': + if (findmode=='u') { + unit * u = findunit(atoi36(locate)); + r = u?u->region:NULL; + } else if (findmode && regions!=NULL) { + struct faction * f = NULL; + map_region * mr = cursor_region(&st->display, cursor); + region * first = (mr && mr->r && mr->r->next)?mr->r->next:regions; + + if (findmode=='f') { + sprintf(sbuffer, "find-faction: %s", locate); + statusline(st->wnd_status->handle, sbuffer); + f = findfaction(atoi36(locate)); + if (f==NULL) { + statusline(st->wnd_status->handle, "faction not found."); + beep(); + break; + } + } + for (r=first;;) { + if (findmode=='r' && r->land && r->land->name && strstr((const char*)r->land->name, locate)) { + break; + } else if (findmode=='f') { + unit * u; + for (u=r->units;u;u=u->next) { + if (u->faction==f) { + break; + } + } + if (u) break; + } + r = r->next; + if (r==NULL) r = regions; + if (r==first) { + r = NULL; + statusline(st->wnd_status->handle, "not found."); + beep(); + break; + } + } + } else { + r = NULL; + } + if (r!=NULL) { + region2coord(r, &st->cursor); + } + break; + case 'Q': + g_quit = 1; + break; + default: + for (wnd=wnd_first;wnd!=NULL;wnd=wnd->next) { + if (wnd->handlekey) { + if (wnd->handlekey(wnd, st, c)) break; + } + } + if (wnd==NULL) { + if (kbuffer[0]==0) { + strcpy(kbuffer, "getch:"); + } + sprintf(sbuffer, " 0x%x", c); + strncat(kbuffer, sbuffer, sizeof(kbuffer)); + statusline(st->wnd_status->handle, kbuffer); + if (strlen(kbuffer)>70) kbuffer[0]=0; + } + break; + } +} + +static void +init_view(view * display, WINDOW * win) +{ + display->topleft.x = 1; + display->topleft.y = 1; + display->topleft.pl = get_homeplane(); + display->pl = get_homeplane(); + display->size.width = getmaxx(win)/TWIDTH; + display->size.height = getmaxy(win)/THEIGHT; + display->regions = calloc(display->size.height * display->size.width, sizeof(map_region)); +} + +static void +update_view(view * vi) +{ + int i, j; + for (i=0;i!=vi->size.width;++i) { + for (j=0;j!=vi->size.height;++j) { + map_region * mr = mr_get(vi, i, j); + mr->coord.x = vi->topleft.x + i - j/2; + mr->coord.y = vi->topleft.y + j; + mr->coord.pl = vi->pl; + pnormalize(&mr->coord.x, &mr->coord.y, mr->coord.pl); + mr->r = findregion(mr->coord.x, mr->coord.y); + } + } +} + +state * +state_open(void) +{ + state * st = calloc(sizeof(state), 1); + st->display.pl = get_homeplane(); + st->cursor.pl = get_homeplane(); + st->cursor.x = 0; + st->cursor.y = 0; + st->selected = calloc(1, sizeof(struct selection)); + st->modified = 0; + st->info_flags = 0xFFFFFFFF; + st->prev = current_state; + current_state = st; + return st; +} + +void +state_close(state * st) +{ + assert(st==current_state); + current_state = st->prev; + free(st); +} + +void +run_mapper(void) +{ + WINDOW * hwinstatus; + WINDOW * hwininfo; + WINDOW * hwinmap; + int width, height, x, y; + int split = 20, old_flags = log_flags; + state * st; + point tl; + + log_flags &= ~(LOG_CPERROR|LOG_CPWARNING); + init_curses(); + curs_set(1); + + set_readline(curses_readline); + + getbegyx(stdscr, x, y); + width = getmaxx(stdscr); + height = getmaxy(stdscr); + + hwinmap = subwin(stdscr, getmaxy(stdscr)-1, getmaxx(stdscr)-split, y, x); + hwininfo = subwin(stdscr, getmaxy(stdscr)-1, split, y, x+getmaxx(stdscr)-split); + hwinstatus = subwin(stdscr, 1, width, height-1, x); + + st = state_open(); + st->wnd_map = win_create(hwinmap); + st->wnd_map->paint = &paint_map; + st->wnd_map->update = 1; + st->wnd_info = win_create(hwininfo); + st->wnd_info->paint = &paint_info_default; + st->wnd_info->handlekey = &handle_info_region; + st->wnd_info->update = 1; + st->wnd_status = win_create(hwinstatus); + st->wnd_status->paint = &paint_status; + st->wnd_status->update = 1; + + init_view(&st->display, hwinmap); + coor2point(&st->display.topleft, &tl); + + hstatus = st->wnd_status->handle; /* the lua console needs this */ + + while (!g_quit) { + int c; + point p; + window * wnd; + view * vi = &st->display; + + getbegyx(hwinmap, x, y); + width = getmaxx(hwinmap)-x; + height = getmaxy(hwinmap)-y; + coor2point(&st->cursor, &p); + + if (st->cursor.pl != vi->pl) { + vi->pl = st->cursor.pl; + st->wnd_map->update |= 1; + } + if (p.y < tl.y) { + vi->topleft.y = st->cursor.y-vi->size.height/2; + st->wnd_map->update |= 1; + } + else if (p.y >= tl.y + vi->size.height * THEIGHT) { + vi->topleft.y = st->cursor.y-vi->size.height/2; + st->wnd_map->update |= 1; + } + if (p.x <= tl.x) { + vi->topleft.x = st->cursor.x+(st->cursor.y-vi->topleft.y)/2-vi->size.width / 2; + st->wnd_map->update |= 1; + } + else if (p.x >= tl.x + vi->size.width * TWIDTH-1) { + vi->topleft.x = st->cursor.x+(st->cursor.y-vi->topleft.y)/2-vi->size.width / 2; + st->wnd_map->update |= 1; + } + + if (st->wnd_map->update) { + update_view(vi); + coor2point(&vi->topleft, &tl); + } + for (wnd=wnd_last;wnd!=NULL;wnd=wnd->prev) { + if (wnd->update && wnd->paint) { + if (wnd->update & 1) { + wnd->paint(wnd, st); + wnoutrefresh(wnd->handle); + } + if (wnd->update & 2) { + touchwin(wnd->handle); + } + wnd->update = 0; + } + } + draw_cursor(st->wnd_map->handle, st->selected, vi, &st->cursor, 1); + doupdate(); + c = getch(); + draw_cursor(st->wnd_map->handle, st->selected, vi, &st->cursor, 0); + handlekey(st, c); + } + g_quit = 0; + set_readline(NULL); + curs_set(1); + endwin(); + log_flags = old_flags; + state_close(st); +} + +int +curses_readline(struct lua_State * L, char * buffer, size_t size, const char * prompt) +{ + unused(L); + askstring(hstatus, prompt, buffer, size); + return buffer[0]!=0; +} + + +void +seed_players(const char * filename, boolean new_island) +{ + newfaction * players = read_newfactions(filename); + if (players!=NULL) { + while (players) { + int n = listlen(players); + int k = (n+ISLANDSIZE-1)/ISLANDSIZE; + k = n / k; + n = autoseed(&players, k, new_island?0:TURNS_PER_ISLAND); + if (n==0) { + break; + } + } + } +} + +void +make_block(int x, int y, int radius, const struct terrain_type * terrain) +{ + int cx, cy; + region *r; + plane * pl = findplane(x, y); + + if (terrain==NULL) return; + + for (cx = x - radius; cx != x+radius; ++cx) { + for (cy = y - radius; cy != y+radius; ++cy) { + int nx = cx, ny = cy; + pnormalize(&nx, &ny, pl); + if (koor_distance(nx, ny, x, y) < radius) { + if (!findregion(nx, ny)) { + r = new_region(nx, ny, pl, 0); + terraform_region(r, terrain); + } + } + } + } +} diff --git a/src/gmtool.h b/src/gmtool.h index 717d3ab07..1912e03ee 100644 --- a/src/gmtool.h +++ b/src/gmtool.h @@ -1,41 +1,41 @@ -/* vi: set ts=2: - * +-------------------+ Christian Schlittchen - * | | Enno Rehling - * | Eressea PBEM host | Katja Zedel - * | (c) 1998 - 2006 | - * | | This program may not be used, modified or distributed - * +-------------------+ without prior permission by the authors of Eressea. - * - */ - -#ifndef H_GMTOOL -#define H_GMTOOL - -#ifdef __cplusplus -extern "C" { -#endif - struct lua_State; - struct selection; - struct state; - struct region; - - int gmmain(int argc, char *argv[]); - int curses_readline(struct lua_State * L, char * buffer, size_t size, const char * prompt); - - void highlight_region(struct region *r, int on); - void select_coordinate(struct selection * selected, int x, int y, int on); - void run_mapper(void); - - int force_color; - - struct state * state_open(void); - void state_close(struct state * ); - - void make_block(int x, int y, int radius, const struct terrain_type * terrain); - void seed_players(const char * filename, boolean new_island); - -#ifdef __cplusplus -} -#endif - -#endif +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2006 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +#ifndef H_GMTOOL +#define H_GMTOOL + +#ifdef __cplusplus +extern "C" { +#endif + struct lua_State; + struct selection; + struct state; + struct region; + + int gmmain(int argc, char *argv[]); + int curses_readline(struct lua_State * L, char * buffer, size_t size, const char * prompt); + + void highlight_region(struct region *r, int on); + void select_coordinate(struct selection * selected, int x, int y, int on); + void run_mapper(void); + + int force_color; + + struct state * state_open(void); + void state_close(struct state * ); + + void make_block(int x, int y, int radius, const struct terrain_type * terrain); + void seed_players(const char * filename, boolean new_island); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/gmtool_structs.h b/src/gmtool_structs.h index dbb715e4e..129be7775 100644 --- a/src/gmtool_structs.h +++ b/src/gmtool_structs.h @@ -1,102 +1,102 @@ -/* vi: set ts=2: - * +-------------------+ Christian Schlittchen - * | | Enno Rehling - * | Eressea PBEM host | Katja Zedel - * | (c) 1998 - 2006 | - * | | This program may not be used, modified or distributed - * +-------------------+ without prior permission by the authors of Eressea. - * - */ - -#ifndef H_GMTOOL_STRUCTS -#define H_GMTOOL_STRUCTS - -#ifdef __cplusplus -extern "C" { -#endif - -/* types imported from eressea: */ -struct region; - -typedef struct extent { - /* Ein Vektor */ - int width, height; -} extent; - -typedef struct point { - /* Eine Koordinate in einer Ascii-Karte */ - int x, y; -} point; - -typedef struct coordinate { - /* Eine Koordinate im Editor, nicht normalisiert */ - int x, y; - struct plane * pl; -} coordinate; - -typedef struct map_region { - struct region * r; - coordinate coord; -} map_region; - -typedef struct view { - struct map_region * regions; - struct plane * pl; - coordinate topleft; /* upper left corner in map. */ - extent size; /* dimensions. */ -} view; - -typedef struct tag { - coordinate coord; - struct tag * nexthash; -} tag; - -#define MAXTHASH 512 - -typedef struct selection { - tag * tags[MAXTHASH]; -} selection; - -typedef struct state { - coordinate cursor; - selection * selected; - struct state * prev; - view display; - int modified; - unsigned int info_flags; - struct window * wnd_info; - struct window * wnd_map; - struct window * wnd_status; -} state; - -typedef struct window { - boolean (*handlekey)(struct window * win, struct state * st, int key); - void (*paint)(struct window * win, const struct state * st); - - WINDOW * handle; - struct window * next; - struct window * prev; - boolean initialized; - int update; -} window; - -extern map_region * cursor_region(const view * v, const coordinate * c); -extern void cnormalize(const coordinate * c, int * x, int * y); -extern state * current_state; - -extern void set_info_function(void (*callback)(struct window *, const struct state *)); - -#define TWIDTH 2 /* width of tile */ -#define THEIGHT 1 /* height of tile */ - -#ifdef WIN32 -#define wxborder(win) wborder(win, 0, 0, 0, 0, 0, 0, 0, 0) -#else -#define wxborder(win) wborder(win, '|', '|', '-', '-', '+', '+', '+', '+') -#endif - -#ifdef __cplusplus -} -#endif - -#endif +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2006 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +#ifndef H_GMTOOL_STRUCTS +#define H_GMTOOL_STRUCTS + +#ifdef __cplusplus +extern "C" { +#endif + +/* types imported from eressea: */ +struct region; + +typedef struct extent { + /* Ein Vektor */ + int width, height; +} extent; + +typedef struct point { + /* Eine Koordinate in einer Ascii-Karte */ + int x, y; +} point; + +typedef struct coordinate { + /* Eine Koordinate im Editor, nicht normalisiert */ + int x, y; + struct plane * pl; +} coordinate; + +typedef struct map_region { + struct region * r; + coordinate coord; +} map_region; + +typedef struct view { + struct map_region * regions; + struct plane * pl; + coordinate topleft; /* upper left corner in map. */ + extent size; /* dimensions. */ +} view; + +typedef struct tag { + coordinate coord; + struct tag * nexthash; +} tag; + +#define MAXTHASH 512 + +typedef struct selection { + tag * tags[MAXTHASH]; +} selection; + +typedef struct state { + coordinate cursor; + selection * selected; + struct state * prev; + view display; + int modified; + unsigned int info_flags; + struct window * wnd_info; + struct window * wnd_map; + struct window * wnd_status; +} state; + +typedef struct window { + boolean (*handlekey)(struct window * win, struct state * st, int key); + void (*paint)(struct window * win, const struct state * st); + + WINDOW * handle; + struct window * next; + struct window * prev; + boolean initialized; + int update; +} window; + +extern map_region * cursor_region(const view * v, const coordinate * c); +extern void cnormalize(const coordinate * c, int * x, int * y); +extern state * current_state; + +extern void set_info_function(void (*callback)(struct window *, const struct state *)); + +#define TWIDTH 2 /* width of tile */ +#define THEIGHT 1 /* height of tile */ + +#ifdef WIN32 +#define wxborder(win) wborder(win, 0, 0, 0, 0, 0, 0, 0, 0) +#else +#define wxborder(win) wborder(win, '|', '|', '-', '-', '+', '+', '+', '+') +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/items/artrewards.c b/src/items/artrewards.c index d37077559..06b152f6b 100644 --- a/src/items/artrewards.c +++ b/src/items/artrewards.c @@ -1,157 +1,157 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "artrewards.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -#define HORNRANGE 10 -#define HORNDURATION 3 -#define HORNIMMUNITY 30 - -static int -age_peaceimmune(attrib * a) -{ - return (--a->data.i>0)?AT_AGE_KEEP:AT_AGE_REMOVE; -} - -static attrib_type at_peaceimmune = { - "peaceimmune", - NULL, NULL, - age_peaceimmune, - a_writeint, - a_readint -}; - -static int -use_hornofdancing(struct unit * u, const struct item_type * itype, - int amount, struct order * ord) -{ - region *r; - int regionsPacified = 0; - - for(r=regions; r; r=r->next) { - if(distance(u->region, r) < HORNRANGE) { - if(a_find(r->attribs, &at_peaceimmune) == NULL) { - attrib *a; - - create_curse(u, &r->attribs, ct_find("peacezone"), - 20, HORNDURATION, 1.0, 0); - - a = a_add(&r->attribs, a_new(&at_peaceimmune)); - a->data.i = HORNIMMUNITY; - - ADDMSG(&r->msgs, msg_message("hornofpeace_r_success", - "unit region", u, u->region)); - - regionsPacified++; - } else { - ADDMSG(&r->msgs, msg_message("hornofpeace_r_nosuccess", - "unit region", u, u->region)); - } - } - } - - if(regionsPacified > 0) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "hornofpeace_u_success", - "pacified", regionsPacified)); - } else { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "hornofpeace_u_nosuccess", "")); - } - - return 0; -} - -#define SPEEDUP 2 - - -static int -useonother_trappedairelemental(struct unit * u, int shipId, - const struct item_type * itype, - int amount, struct order * ord) -{ - curse *c; - ship *sh; - - if (shipId <= 0) { - cmistake(u, ord, 20, MSG_MOVE); - return -1; - } - - sh = findshipr(u->region, shipId); - if(!sh) { - cmistake(u, ord, 20, MSG_MOVE); - return -1; - } - - c = create_curse(u, &sh->attribs, ct_find("shipspeedup"), 20, INT_MAX, SPEEDUP, 0); - c_setflag(c, CURSE_NOAGE); - - ADDMSG(&u->faction->msgs, msg_message("trappedairelemental_success", - "unit region command ship", u, u->region, ord, sh)); - - use_pooled(u, itype->rtype, GET_DEFAULT, 1); - - return 0; -} - -static int -use_trappedairelemental(struct unit * u, - const struct item_type * itype, - int amount, struct order * ord) -{ - ship *sh = u->ship; - - if(sh == NULL) { - cmistake(u, ord, 20, MSG_MOVE); - return -1; - } - return useonother_trappedairelemental(u, sh->no, itype, amount,ord); -} - -void -register_artrewards(void) -{ - at_register(&at_peaceimmune); - register_item_use(use_hornofdancing, "use_hornofdancing"); - register_item_use(use_trappedairelemental, "use_trappedairelemental"); - register_item_useonother(useonother_trappedairelemental, "useonother_trappedairelemental"); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "artrewards.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +#define HORNRANGE 10 +#define HORNDURATION 3 +#define HORNIMMUNITY 30 + +static int +age_peaceimmune(attrib * a) +{ + return (--a->data.i>0)?AT_AGE_KEEP:AT_AGE_REMOVE; +} + +static attrib_type at_peaceimmune = { + "peaceimmune", + NULL, NULL, + age_peaceimmune, + a_writeint, + a_readint +}; + +static int +use_hornofdancing(struct unit * u, const struct item_type * itype, + int amount, struct order * ord) +{ + region *r; + int regionsPacified = 0; + + for(r=regions; r; r=r->next) { + if(distance(u->region, r) < HORNRANGE) { + if(a_find(r->attribs, &at_peaceimmune) == NULL) { + attrib *a; + + create_curse(u, &r->attribs, ct_find("peacezone"), + 20, HORNDURATION, 1.0, 0); + + a = a_add(&r->attribs, a_new(&at_peaceimmune)); + a->data.i = HORNIMMUNITY; + + ADDMSG(&r->msgs, msg_message("hornofpeace_r_success", + "unit region", u, u->region)); + + regionsPacified++; + } else { + ADDMSG(&r->msgs, msg_message("hornofpeace_r_nosuccess", + "unit region", u, u->region)); + } + } + } + + if(regionsPacified > 0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "hornofpeace_u_success", + "pacified", regionsPacified)); + } else { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "hornofpeace_u_nosuccess", "")); + } + + return 0; +} + +#define SPEEDUP 2 + + +static int +useonother_trappedairelemental(struct unit * u, int shipId, + const struct item_type * itype, + int amount, struct order * ord) +{ + curse *c; + ship *sh; + + if (shipId <= 0) { + cmistake(u, ord, 20, MSG_MOVE); + return -1; + } + + sh = findshipr(u->region, shipId); + if(!sh) { + cmistake(u, ord, 20, MSG_MOVE); + return -1; + } + + c = create_curse(u, &sh->attribs, ct_find("shipspeedup"), 20, INT_MAX, SPEEDUP, 0); + c_setflag(c, CURSE_NOAGE); + + ADDMSG(&u->faction->msgs, msg_message("trappedairelemental_success", + "unit region command ship", u, u->region, ord, sh)); + + use_pooled(u, itype->rtype, GET_DEFAULT, 1); + + return 0; +} + +static int +use_trappedairelemental(struct unit * u, + const struct item_type * itype, + int amount, struct order * ord) +{ + ship *sh = u->ship; + + if(sh == NULL) { + cmistake(u, ord, 20, MSG_MOVE); + return -1; + } + return useonother_trappedairelemental(u, sh->no, itype, amount,ord); +} + +void +register_artrewards(void) +{ + at_register(&at_peaceimmune); + register_item_use(use_hornofdancing, "use_hornofdancing"); + register_item_use(use_trappedairelemental, "use_trappedairelemental"); + register_item_useonother(useonother_trappedairelemental, "useonother_trappedairelemental"); +} diff --git a/src/items/artrewards.h b/src/items/artrewards.h index e8ef8c28e..552a3b27a 100644 --- a/src/items/artrewards.h +++ b/src/items/artrewards.h @@ -1,30 +1,30 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ITM_ARTREWARDS -#define H_ITM_ARTREWARDS -#ifdef __cplusplus -extern "C" { -#endif - -extern void register_artrewards(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ITM_ARTREWARDS +#define H_ITM_ARTREWARDS +#ifdef __cplusplus +extern "C" { +#endif + +extern void register_artrewards(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/demonseye.c b/src/items/demonseye.c index 1e3b6ec5f..6c6ddee15 100644 --- a/src/items/demonseye.c +++ b/src/items/demonseye.c @@ -1,64 +1,64 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "demonseye.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include - -/* libc includes */ -#include - -static int -summon_igjarjuk(struct unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - struct plane * p = rplane(u->region); - unused(amount); - unused(itype); - if (p!=NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "use_realworld_only", "")); - return EUNUSABLE; - } else { - assert(!"not implemented"); - return EUNUSABLE; - } -} - -static int -give_igjarjuk(struct unit * src, struct unit * d, const struct item_type * itype, int n, struct order * ord) -{ - ADDMSG(&src->faction->msgs, msg_feedback(src, ord, "error_giveeye", "")); - return 0; -} - -void -register_demonseye(void) -{ - register_item_use(summon_igjarjuk, "useigjarjuk"); - register_item_give(give_igjarjuk, "giveigjarjuk"); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "demonseye.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include + +/* libc includes */ +#include + +static int +summon_igjarjuk(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + struct plane * p = rplane(u->region); + unused(amount); + unused(itype); + if (p!=NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "use_realworld_only", "")); + return EUNUSABLE; + } else { + assert(!"not implemented"); + return EUNUSABLE; + } +} + +static int +give_igjarjuk(struct unit * src, struct unit * d, const struct item_type * itype, int n, struct order * ord) +{ + ADDMSG(&src->faction->msgs, msg_feedback(src, ord, "error_giveeye", "")); + return 0; +} + +void +register_demonseye(void) +{ + register_item_use(summon_igjarjuk, "useigjarjuk"); + register_item_give(give_igjarjuk, "giveigjarjuk"); +} diff --git a/src/items/demonseye.h b/src/items/demonseye.h index 636e6a6e8..be802d6dc 100644 --- a/src/items/demonseye.h +++ b/src/items/demonseye.h @@ -1,30 +1,30 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ITM_DEMONSEYE -#define H_ITM_DEMONSEYE -#ifdef __cplusplus -extern "C" { -#endif - -extern void register_demonseye(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ITM_DEMONSEYE +#define H_ITM_DEMONSEYE +#ifdef __cplusplus +extern "C" { +#endif + +extern void register_demonseye(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/itemtypes.c b/src/items/itemtypes.c index 765e5994c..af0efe305 100644 --- a/src/items/itemtypes.c +++ b/src/items/itemtypes.c @@ -1,38 +1,38 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "itemtypes.h" - -#include "xerewards.h" -#include "artrewards.h" -#include "phoenixcompass.h" -#include "weapons.h" -#include "seed.h" - -void -register_itemtypes(void) -{ - /* registering misc. functions */ - register_weapons(); - register_xerewards(); - register_artrewards(); - register_phoenixcompass(); -} - -void -init_itemtypes(void) -{ - init_seed(); - init_mallornseed(); -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "itemtypes.h" + +#include "xerewards.h" +#include "artrewards.h" +#include "phoenixcompass.h" +#include "weapons.h" +#include "seed.h" + +void +register_itemtypes(void) +{ + /* registering misc. functions */ + register_weapons(); + register_xerewards(); + register_artrewards(); + register_phoenixcompass(); +} + +void +init_itemtypes(void) +{ + init_seed(); + init_mallornseed(); +} diff --git a/src/items/itemtypes.h b/src/items/itemtypes.h index 55f006bc2..1cc8fecec 100644 --- a/src/items/itemtypes.h +++ b/src/items/itemtypes.h @@ -1,25 +1,25 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_ITM_ITEMS -#define H_ITM_ITEMS -#ifdef __cplusplus -extern "C" { -#endif - -extern void init_itemtypes(void); -extern void register_itemtypes(void); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_ITM_ITEMS +#define H_ITM_ITEMS +#ifdef __cplusplus +extern "C" { +#endif + +extern void init_itemtypes(void); +extern void register_itemtypes(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/phoenixcompass.c b/src/items/phoenixcompass.c index 0680aa539..ffe208797 100644 --- a/src/items/phoenixcompass.c +++ b/src/items/phoenixcompass.c @@ -1,129 +1,129 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "phoenixcompass.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -static int -use_phoenixcompass(struct unit * u, const struct item_type * itype, - int amount, struct order * ord) -{ - region *r; - unit *closest_phoenix = NULL; - int closest_phoenix_distance = INT_MAX; - boolean confusion = false; - direction_t direction; - unit *u2; - direction_t closest_neighbour_direction = 0; - static race * rc_phoenix = NULL; - - if (rc_phoenix==NULL) { - rc_phoenix = rc_find("phoenix"); - if (rc_phoenix==NULL) return 0; - } - - /* find the closest phoenix. */ - - for(r=regions; r; r=r->next) { - for(u2=r->units; u2; u2=u2->next) { - if (u2->race == rc_phoenix) { - if(closest_phoenix == NULL) { - closest_phoenix = u2; - closest_phoenix_distance = distance(u->region, closest_phoenix->region); - } else { - int dist = distance(u->region, r); - if(dist < closest_phoenix_distance) { - closest_phoenix = u2; - closest_phoenix_distance = dist; - confusion = false; - } else if(dist == closest_phoenix_distance) { - confusion = true; - } - } - } - } - } - - /* no phoenix found at all.* if confusion == true more than one phoenix - * at the same distance was found and the device is confused */ - - if(closest_phoenix == NULL - || closest_phoenix->region == u->region - || confusion == true) { - add_message(&u->faction->msgs, msg_message("phoenixcompass_confusion", - "unit region command", u, u->region, ord)); - return 0; - } - - /* else calculate the direction. this is tricky. we calculate the - * neighbouring region which is closest to the phoenix found. hardcoded - * for readability. */ - - for(direction = 0; direction < MAXDIRECTIONS; ++direction) { - region *neighbour; - int closest_neighbour_distance = INT_MAX; - - neighbour = r_connect(u->region, direction); - if(neighbour != NULL) { - int dist = distance(neighbour, closest_phoenix->region); - if(dist < closest_neighbour_distance) { - closest_neighbour_direction = direction; - closest_neighbour_distance = dist; - } else if(dist == closest_neighbour_distance && rng_int()%100 < 50) { - /* there can never be more than two neighbours with the same - * distance (except when you are standing in the same region - * as the phoenix, but that case has already been handled). - * therefore this simple solution is correct */ - closest_neighbour_direction = direction; - closest_neighbour_distance = dist; - } - } - } - - add_message(&u->faction->msgs, msg_message("phoenixcompass_success", - "unit region command dir", - u, u->region, ord, closest_neighbour_direction)); - - return 0; -} - -void -register_phoenixcompass(void) -{ - register_item_use(use_phoenixcompass, "use_phoenixcompass"); -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "phoenixcompass.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +static int +use_phoenixcompass(struct unit * u, const struct item_type * itype, + int amount, struct order * ord) +{ + region *r; + unit *closest_phoenix = NULL; + int closest_phoenix_distance = INT_MAX; + boolean confusion = false; + direction_t direction; + unit *u2; + direction_t closest_neighbour_direction = 0; + static race * rc_phoenix = NULL; + + if (rc_phoenix==NULL) { + rc_phoenix = rc_find("phoenix"); + if (rc_phoenix==NULL) return 0; + } + + /* find the closest phoenix. */ + + for(r=regions; r; r=r->next) { + for(u2=r->units; u2; u2=u2->next) { + if (u2->race == rc_phoenix) { + if(closest_phoenix == NULL) { + closest_phoenix = u2; + closest_phoenix_distance = distance(u->region, closest_phoenix->region); + } else { + int dist = distance(u->region, r); + if(dist < closest_phoenix_distance) { + closest_phoenix = u2; + closest_phoenix_distance = dist; + confusion = false; + } else if(dist == closest_phoenix_distance) { + confusion = true; + } + } + } + } + } + + /* no phoenix found at all.* if confusion == true more than one phoenix + * at the same distance was found and the device is confused */ + + if(closest_phoenix == NULL + || closest_phoenix->region == u->region + || confusion == true) { + add_message(&u->faction->msgs, msg_message("phoenixcompass_confusion", + "unit region command", u, u->region, ord)); + return 0; + } + + /* else calculate the direction. this is tricky. we calculate the + * neighbouring region which is closest to the phoenix found. hardcoded + * for readability. */ + + for(direction = 0; direction < MAXDIRECTIONS; ++direction) { + region *neighbour; + int closest_neighbour_distance = INT_MAX; + + neighbour = r_connect(u->region, direction); + if(neighbour != NULL) { + int dist = distance(neighbour, closest_phoenix->region); + if(dist < closest_neighbour_distance) { + closest_neighbour_direction = direction; + closest_neighbour_distance = dist; + } else if(dist == closest_neighbour_distance && rng_int()%100 < 50) { + /* there can never be more than two neighbours with the same + * distance (except when you are standing in the same region + * as the phoenix, but that case has already been handled). + * therefore this simple solution is correct */ + closest_neighbour_direction = direction; + closest_neighbour_distance = dist; + } + } + } + + add_message(&u->faction->msgs, msg_message("phoenixcompass_success", + "unit region command dir", + u, u->region, ord, closest_neighbour_direction)); + + return 0; +} + +void +register_phoenixcompass(void) +{ + register_item_use(use_phoenixcompass, "use_phoenixcompass"); +} + diff --git a/src/items/phoenixcompass.h b/src/items/phoenixcompass.h index 8bd634484..b99876056 100644 --- a/src/items/phoenixcompass.h +++ b/src/items/phoenixcompass.h @@ -1,30 +1,30 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ITM_PHOENIXCOMPASS -#define H_ITM_PHOENIXCOMPASS -#ifdef __cplusplus -extern "C" { -#endif - -extern void register_phoenixcompass(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ITM_PHOENIXCOMPASS +#define H_ITM_PHOENIXCOMPASS +#ifdef __cplusplus +extern "C" { +#endif + +extern void register_phoenixcompass(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/seed.c b/src/items/seed.c index 4bef3c496..3ad84e0c7 100644 --- a/src/items/seed.c +++ b/src/items/seed.c @@ -1,100 +1,100 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include - -#include "seed.h" - -/* kernel includes */ -#include -#include -#include -#include - -/* util includes */ -#include -#include - -/* libc includes */ -#include - -resource_type * rt_seed = 0; -resource_type * rt_mallornseed = 0; - -static void -produce_seeds(region * r, const resource_type * rtype, int norders) -{ - assert(rtype==rt_seed && r->land && r->land->trees[0] >= norders); - r->land->trees[0] -= norders; -} - -static int -limit_seeds(const region * r, const resource_type * rtype) -{ - assert(rtype==rt_seed); - if(fval(r, RF_MALLORN)) return 0; - return r->land?r->land->trees[0]:0; -} - -void -init_seed(void) -{ - attrib * a; - resource_limit * rdata; - - rt_seed = rt_find("seed"); - if (rt_seed!=NULL) { - a = a_add(&rt_seed->attribs, a_new(&at_resourcelimit)); - rdata = (resource_limit*)a->data.v; - rdata->limit = limit_seeds; - rdata->produce = produce_seeds; - } -} - -/* mallorn */ - -static void -produce_mallornseeds(region * r, const resource_type * rtype, int norders) -{ - assert(rtype==rt_mallornseed && r->land && r->land->trees[0] >= norders); - assert(fval(r, RF_MALLORN)); - r->land->trees[0] -= norders; -} - -static int -limit_mallornseeds(const region * r, const resource_type * rtype) -{ - assert(rtype==rt_mallornseed); - if (!fval(r, RF_MALLORN)) { - return 0; - } - return r->land?r->land->trees[0]:0; -} - -void -init_mallornseed(void) -{ - attrib * a; - resource_limit * rdata; - - rt_mallornseed = rt_find("mallornseed"); - if (rt_mallornseed!=NULL) { - rt_mallornseed->flags |= RTF_LIMITED; - rt_mallornseed->flags |= RTF_POOLED; - - a = a_add(&rt_mallornseed->attribs, a_new(&at_resourcelimit)); - rdata = (resource_limit*)a->data.v; - rdata->limit = limit_mallornseeds; - rdata->produce = produce_mallornseeds; - } -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include + +#include "seed.h" + +/* kernel includes */ +#include +#include +#include +#include + +/* util includes */ +#include +#include + +/* libc includes */ +#include + +resource_type * rt_seed = 0; +resource_type * rt_mallornseed = 0; + +static void +produce_seeds(region * r, const resource_type * rtype, int norders) +{ + assert(rtype==rt_seed && r->land && r->land->trees[0] >= norders); + r->land->trees[0] -= norders; +} + +static int +limit_seeds(const region * r, const resource_type * rtype) +{ + assert(rtype==rt_seed); + if(fval(r, RF_MALLORN)) return 0; + return r->land?r->land->trees[0]:0; +} + +void +init_seed(void) +{ + attrib * a; + resource_limit * rdata; + + rt_seed = rt_find("seed"); + if (rt_seed!=NULL) { + a = a_add(&rt_seed->attribs, a_new(&at_resourcelimit)); + rdata = (resource_limit*)a->data.v; + rdata->limit = limit_seeds; + rdata->produce = produce_seeds; + } +} + +/* mallorn */ + +static void +produce_mallornseeds(region * r, const resource_type * rtype, int norders) +{ + assert(rtype==rt_mallornseed && r->land && r->land->trees[0] >= norders); + assert(fval(r, RF_MALLORN)); + r->land->trees[0] -= norders; +} + +static int +limit_mallornseeds(const region * r, const resource_type * rtype) +{ + assert(rtype==rt_mallornseed); + if (!fval(r, RF_MALLORN)) { + return 0; + } + return r->land?r->land->trees[0]:0; +} + +void +init_mallornseed(void) +{ + attrib * a; + resource_limit * rdata; + + rt_mallornseed = rt_find("mallornseed"); + if (rt_mallornseed!=NULL) { + rt_mallornseed->flags |= RTF_LIMITED; + rt_mallornseed->flags |= RTF_POOLED; + + a = a_add(&rt_mallornseed->attribs, a_new(&at_resourcelimit)); + rdata = (resource_limit*)a->data.v; + rdata->limit = limit_mallornseeds; + rdata->produce = produce_mallornseeds; + } +} diff --git a/src/items/seed.h b/src/items/seed.h index d373bfe17..7905d8887 100644 --- a/src/items/seed.h +++ b/src/items/seed.h @@ -1,35 +1,35 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ITM_SEED -#define H_ITM_SEED -#ifdef __cplusplus -extern "C" { -#endif - - -extern struct resource_type * rt_seed; -extern void init_seed(void); - -extern struct resource_type * rt_mallornseed; -extern void init_mallornseed(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ITM_SEED +#define H_ITM_SEED +#ifdef __cplusplus +extern "C" { +#endif + + +extern struct resource_type * rt_seed; +extern void init_seed(void); + +extern struct resource_type * rt_mallornseed; +extern void init_mallornseed(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/speedsail.c b/src/items/speedsail.c index e8bbcf793..0d80e9158 100644 --- a/src/items/speedsail.c +++ b/src/items/speedsail.c @@ -1,73 +1,73 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "speedsail.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include - -/* libc includes */ -#include - -static int -use_speedsail(struct unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - struct plane * p = rplane(u->region); - unused(amount); - unused(itype); - if (p!=NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "use_realworld_only", "")); - } else { - if (u->ship) { - attrib * a = a_find(u->ship->attribs, &at_speedup); - if (a==NULL) { - a = a_add(&u->ship->attribs, a_new(&at_speedup)); - a->data.sa[0] = 50; /* speed */ - a->data.sa[1] = 50; /* decay */ - ADDMSG(&u->faction->msgs, msg_message("use_speedsail", "unit", u)); - /* Ticket abziehen */ - i_change(&u->items, itype, -1); - return 0; - } else { - cmistake(u, ord, 211, MSG_EVENT); - } - } else { - cmistake(u, ord, 144, MSG_EVENT); - } - } - return EUNUSABLE; -} - -void -register_speedsail(void) -{ - register_item_use(use_speedsail, "use_speedsail"); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "speedsail.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include + +/* libc includes */ +#include + +static int +use_speedsail(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + struct plane * p = rplane(u->region); + unused(amount); + unused(itype); + if (p!=NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "use_realworld_only", "")); + } else { + if (u->ship) { + attrib * a = a_find(u->ship->attribs, &at_speedup); + if (a==NULL) { + a = a_add(&u->ship->attribs, a_new(&at_speedup)); + a->data.sa[0] = 50; /* speed */ + a->data.sa[1] = 50; /* decay */ + ADDMSG(&u->faction->msgs, msg_message("use_speedsail", "unit", u)); + /* Ticket abziehen */ + i_change(&u->items, itype, -1); + return 0; + } else { + cmistake(u, ord, 211, MSG_EVENT); + } + } else { + cmistake(u, ord, 144, MSG_EVENT); + } + } + return EUNUSABLE; +} + +void +register_speedsail(void) +{ + register_item_use(use_speedsail, "use_speedsail"); +} diff --git a/src/items/speedsail.h b/src/items/speedsail.h index 08591893f..2539571a4 100644 --- a/src/items/speedsail.h +++ b/src/items/speedsail.h @@ -1,30 +1,30 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ITM_SPEEDVIAL -#define H_ITM_SPEEDVIAL -#ifdef __cplusplus -extern "C" { -#endif - -extern void register_speedsail(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ITM_SPEEDVIAL +#define H_ITM_SPEEDVIAL +#ifdef __cplusplus +extern "C" { +#endif + +extern void register_speedsail(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/studypotion.c b/src/items/studypotion.c index 113048ba7..91f7b84f3 100644 --- a/src/items/studypotion.c +++ b/src/items/studypotion.c @@ -1,58 +1,58 @@ -#include -#include -#include "studypotion.h" - -#include -#include -#include -#include -#include -#include - -#include -#include - -/* BEGIN it_studypotion */ -#define MAXGAIN 15 -static int -use_studypotion(struct unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - if (get_keyword(u->thisorder) == K_STUDY) { - skill_t sk; - skill * sv; - - init_tokens(u->thisorder); - skip_token(); - sk = findskill(getstrtoken(), u->faction->locale); - sv = get_skill(u, sk); - - if (sv && sv->level > 2) { - /* TODO: message */ - } else if (study_cost(u, sk)>0) { - /* TODO: message */ - } else { - attrib * a = a_find(u->attribs, &at_learning); - teaching_info * teach; - if (a==NULL) { - a = a_add(&u->attribs, a_new(&at_learning)); - } - teach = (teaching_info*) a->data.v; - if (amount>MAXGAIN) amount = MAXGAIN; - teach->value += amount * 30; - if (teach->value > MAXGAIN * 30) { - teach->value = MAXGAIN * 30; - } - i_change(&u->items, itype, -amount); - return 0; - } - } - return EUNUSABLE; -} - -void -register_studypotion(void) -{ - register_function((pf_generic)use_studypotion, "use_studypotion"); -} - -/* END it_studypotion */ +#include +#include +#include "studypotion.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* BEGIN it_studypotion */ +#define MAXGAIN 15 +static int +use_studypotion(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + if (get_keyword(u->thisorder) == K_STUDY) { + skill_t sk; + skill * sv; + + init_tokens(u->thisorder); + skip_token(); + sk = findskill(getstrtoken(), u->faction->locale); + sv = get_skill(u, sk); + + if (sv && sv->level > 2) { + /* TODO: message */ + } else if (study_cost(u, sk)>0) { + /* TODO: message */ + } else { + attrib * a = a_find(u->attribs, &at_learning); + teaching_info * teach; + if (a==NULL) { + a = a_add(&u->attribs, a_new(&at_learning)); + } + teach = (teaching_info*) a->data.v; + if (amount>MAXGAIN) amount = MAXGAIN; + teach->value += amount * 30; + if (teach->value > MAXGAIN * 30) { + teach->value = MAXGAIN * 30; + } + i_change(&u->items, itype, -amount); + return 0; + } + } + return EUNUSABLE; +} + +void +register_studypotion(void) +{ + register_function((pf_generic)use_studypotion, "use_studypotion"); +} + +/* END it_studypotion */ diff --git a/src/items/studypotion.h b/src/items/studypotion.h index 8131bb7fb..454f137c2 100644 --- a/src/items/studypotion.h +++ b/src/items/studypotion.h @@ -1,30 +1,30 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ITM_STUDYPOTION -#define H_ITM_STUDYPOTION -#ifdef __cplusplus -extern "C" { -#endif - - extern void register_studypotion(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ITM_STUDYPOTION +#define H_ITM_STUDYPOTION +#ifdef __cplusplus +extern "C" { +#endif + + extern void register_studypotion(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/weapons.c b/src/items/weapons.c index c3ac842cf..11c0379c8 100644 --- a/src/items/weapons.c +++ b/src/items/weapons.c @@ -1,155 +1,155 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "weapons.h" - -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include - -/* libc includes */ -#include -#include - -/* damage types */ - -static boolean -attack_firesword(const troop * at, const struct weapon_type * wtype, int *casualties) -{ - fighter *fi = at->fighter; - troop dt; - int killed = 0; - const char *damage = "2d8"; - int force = 1+rng_int()%10; - int enemies = count_enemies(fi->side->battle, fi, 0, 1, SELECT_ADVANCE|SELECT_DISTANCE); - - if (!enemies) { - if (casualties) *casualties = 0; - return true; /* if no enemy found, no use doing standarad attack */ - } - - if (fi->catmsg == -1) { - int i, k=0; - message * msg; - for (i=0;i<=at->index;++i) { - struct weapon * wp = fi->person[i].melee; - if (wp!=NULL && wp->type == wtype) ++k; - } - msg = msg_message("battle::useflamingsword", "amount unit", k, fi->unit); - message_all(fi->side->battle, msg); - msg_release(msg); - fi->catmsg = 0; - } - - do { - dt = select_enemy(fi, 0, 1, SELECT_ADVANCE|SELECT_DISTANCE); - assert(dt.fighter); - --force; - killed += terminate(dt, *at, AT_SPELL, damage, 1); - } while (force && killed < enemies); - if (casualties) *casualties = killed; - return true; -} - -#define CATAPULT_ATTACKS 6 - -static boolean -attack_catapult(const troop * at, const struct weapon_type * wtype, int * casualties) -{ - fighter *af = at->fighter; - unit *au = af->unit; - battle * b = af->side->battle; - troop dt; - int d = 0, enemies; - weapon * wp = af->person[at->index].missile; - static item_type * it_catapultammo = NULL; - if (it_catapultammo==NULL) { - it_catapultammo = it_find("catapultammo"); - } - - assert(wp->type==wtype); - assert(af->person[at->index].reload==0); - - if (it_catapultammo!=NULL) { - if (get_pooled(au, it_catapultammo->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, 1) <= 0) { - /* No ammo. Use other weapon if available. */ - return true; - } - } - - enemies = count_enemies(b, af, FIGHT_ROW, FIGHT_ROW, SELECT_ADVANCE); - enemies = MIN(enemies, CATAPULT_ATTACKS); - if (enemies==0) { - return true; /* allow further attacks */ - } - - if (af->catmsg == -1) { - int i, k=0; - message * msg; - - for (i=0;i<=at->index;++i) { - if (af->person[i].reload==0 && af->person[i].missile == wp) ++k; - } - msg = msg_message("battle::usecatapult", "amount unit", k, au); - message_all(b, msg); - msg_release(msg); - af->catmsg = 0; - } - - if (it_catapultammo!=NULL) { - use_pooled(au, it_catapultammo->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, 1); - } - - while (--enemies >= 0) { - /* Select defender */ - dt = select_enemy(af, FIGHT_ROW, FIGHT_ROW, SELECT_ADVANCE); - if (!dt.fighter) - break; - - /* If battle succeeds */ - if (hits(*at, dt, wp)) { - d += terminate(dt, *at, AT_STANDARD, wp->type->damage[0], true); -#ifdef CATAPULT_STRUCTURAL_DAMAGE - if (dt.fighter->unit->building && rng_int()%100 < 5) { - damage_building(b, dt.fighter->unit->building, 1); - } else if (dt.fighter->unit->ship && rng_int()%100 < 5) { - dt.fighter->unit->ship->damage+=DAMAGE_SCALE; - } -#endif - } - } - - if (casualties) *casualties = d; - return false; /* keine weitren attacken */ -} -void -register_weapons(void) -{ - register_function((pf_generic)attack_catapult, "attack_catapult"); - register_function((pf_generic)attack_firesword, "attack_firesword"); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "weapons.h" + +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include + +/* libc includes */ +#include +#include + +/* damage types */ + +static boolean +attack_firesword(const troop * at, const struct weapon_type * wtype, int *casualties) +{ + fighter *fi = at->fighter; + troop dt; + int killed = 0; + const char *damage = "2d8"; + int force = 1+rng_int()%10; + int enemies = count_enemies(fi->side->battle, fi, 0, 1, SELECT_ADVANCE|SELECT_DISTANCE); + + if (!enemies) { + if (casualties) *casualties = 0; + return true; /* if no enemy found, no use doing standarad attack */ + } + + if (fi->catmsg == -1) { + int i, k=0; + message * msg; + for (i=0;i<=at->index;++i) { + struct weapon * wp = fi->person[i].melee; + if (wp!=NULL && wp->type == wtype) ++k; + } + msg = msg_message("battle::useflamingsword", "amount unit", k, fi->unit); + message_all(fi->side->battle, msg); + msg_release(msg); + fi->catmsg = 0; + } + + do { + dt = select_enemy(fi, 0, 1, SELECT_ADVANCE|SELECT_DISTANCE); + assert(dt.fighter); + --force; + killed += terminate(dt, *at, AT_SPELL, damage, 1); + } while (force && killed < enemies); + if (casualties) *casualties = killed; + return true; +} + +#define CATAPULT_ATTACKS 6 + +static boolean +attack_catapult(const troop * at, const struct weapon_type * wtype, int * casualties) +{ + fighter *af = at->fighter; + unit *au = af->unit; + battle * b = af->side->battle; + troop dt; + int d = 0, enemies; + weapon * wp = af->person[at->index].missile; + static item_type * it_catapultammo = NULL; + if (it_catapultammo==NULL) { + it_catapultammo = it_find("catapultammo"); + } + + assert(wp->type==wtype); + assert(af->person[at->index].reload==0); + + if (it_catapultammo!=NULL) { + if (get_pooled(au, it_catapultammo->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, 1) <= 0) { + /* No ammo. Use other weapon if available. */ + return true; + } + } + + enemies = count_enemies(b, af, FIGHT_ROW, FIGHT_ROW, SELECT_ADVANCE); + enemies = MIN(enemies, CATAPULT_ATTACKS); + if (enemies==0) { + return true; /* allow further attacks */ + } + + if (af->catmsg == -1) { + int i, k=0; + message * msg; + + for (i=0;i<=at->index;++i) { + if (af->person[i].reload==0 && af->person[i].missile == wp) ++k; + } + msg = msg_message("battle::usecatapult", "amount unit", k, au); + message_all(b, msg); + msg_release(msg); + af->catmsg = 0; + } + + if (it_catapultammo!=NULL) { + use_pooled(au, it_catapultammo->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, 1); + } + + while (--enemies >= 0) { + /* Select defender */ + dt = select_enemy(af, FIGHT_ROW, FIGHT_ROW, SELECT_ADVANCE); + if (!dt.fighter) + break; + + /* If battle succeeds */ + if (hits(*at, dt, wp)) { + d += terminate(dt, *at, AT_STANDARD, wp->type->damage[0], true); +#ifdef CATAPULT_STRUCTURAL_DAMAGE + if (dt.fighter->unit->building && rng_int()%100 < 5) { + damage_building(b, dt.fighter->unit->building, 1); + } else if (dt.fighter->unit->ship && rng_int()%100 < 5) { + dt.fighter->unit->ship->damage+=DAMAGE_SCALE; + } +#endif + } + } + + if (casualties) *casualties = d; + return false; /* keine weitren attacken */ +} +void +register_weapons(void) +{ + register_function((pf_generic)attack_catapult, "attack_catapult"); + register_function((pf_generic)attack_firesword, "attack_firesword"); +} diff --git a/src/items/weapons.h b/src/items/weapons.h index 7ff4f0683..cc44aa390 100644 --- a/src/items/weapons.h +++ b/src/items/weapons.h @@ -1,24 +1,24 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_ITM_WEAPONS -#define H_ITM_WEAPONS -#ifdef __cplusplus -extern "C" { -#endif - -extern void register_weapons(void); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_ITM_WEAPONS +#define H_ITM_WEAPONS +#ifdef __cplusplus +extern "C" { +#endif + +extern void register_weapons(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/items/xerewards.c b/src/items/xerewards.c index 1e0140ac5..c7cda363a 100644 --- a/src/items/xerewards.c +++ b/src/items/xerewards.c @@ -1,91 +1,91 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "xerewards.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include - -/* libc includes */ -#include -#include -#include - -static int -use_skillpotion(struct unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - /* the problem with making this a lua function is that there's no way - * to get the list of skills for a unit. and with the way skills are - * currently saved, it doesn't look likely (can't make eressea::list - * from them) - */ - int n; - for (n=0;n!=amount;++n) { - skill * sv = u->skills; - while (sv!=u->skills+u->skill_size) { - int i; - for (i=0;i!=3;++i) learn_skill(u, sv->id, 1.0); - ++sv; - } - } - ADDMSG(&u->faction->msgs, msg_message("skillpotion_use", "unit", u)); - - res_changeitem(u, itype->rtype, -amount); - return 0; -} - -static int -use_manacrystal(struct unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - int i, sp = 0; - - if(!is_mage(u)) { - cmistake(u, u->thisorder, 295, MSG_EVENT); - return -1; - } - - for (i=0;i!=amount;++i) { - sp += MAX(25, max_spellpoints(u->region, u)/2); - change_spellpoints(u, sp); - } - - ADDMSG(&u->faction->msgs, msg_message("manacrystal_use", "unit aura", u, sp)); - - res_changeitem(u, itype->rtype, -amount); - return 0; -} - -void -register_xerewards(void) -{ - register_item_use(use_skillpotion, "use_skillpotion"); - register_item_use(use_manacrystal, "use_manacrystal"); -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "xerewards.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include + +/* libc includes */ +#include +#include +#include + +static int +use_skillpotion(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + /* the problem with making this a lua function is that there's no way + * to get the list of skills for a unit. and with the way skills are + * currently saved, it doesn't look likely (can't make eressea::list + * from them) + */ + int n; + for (n=0;n!=amount;++n) { + skill * sv = u->skills; + while (sv!=u->skills+u->skill_size) { + int i; + for (i=0;i!=3;++i) learn_skill(u, sv->id, 1.0); + ++sv; + } + } + ADDMSG(&u->faction->msgs, msg_message("skillpotion_use", "unit", u)); + + res_changeitem(u, itype->rtype, -amount); + return 0; +} + +static int +use_manacrystal(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + int i, sp = 0; + + if(!is_mage(u)) { + cmistake(u, u->thisorder, 295, MSG_EVENT); + return -1; + } + + for (i=0;i!=amount;++i) { + sp += MAX(25, max_spellpoints(u->region, u)/2); + change_spellpoints(u, sp); + } + + ADDMSG(&u->faction->msgs, msg_message("manacrystal_use", "unit aura", u, sp)); + + res_changeitem(u, itype->rtype, -amount); + return 0; +} + +void +register_xerewards(void) +{ + register_item_use(use_skillpotion, "use_skillpotion"); + register_item_use(use_manacrystal, "use_manacrystal"); +} + diff --git a/src/items/xerewards.h b/src/items/xerewards.h index c23d6014b..c914c5ed4 100644 --- a/src/items/xerewards.h +++ b/src/items/xerewards.h @@ -1,30 +1,30 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ITM_XEREWARDS -#define H_ITM_XEREWARDS -#ifdef __cplusplus -extern "C" { -#endif - -extern void register_xerewards(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_ITM_XEREWARDS +#define H_ITM_XEREWARDS +#ifdef __cplusplus +extern "C" { +#endif + +extern void register_xerewards(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/alchemy.c b/src/kernel/alchemy.c index f79d59abf..05f06471a 100644 --- a/src/kernel/alchemy.c +++ b/src/kernel/alchemy.c @@ -1,338 +1,338 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "alchemy.h" - -#include "item.h" -#include "faction.h" -#include "message.h" -#include "build.h" -#include "magic.h" -#include "region.h" -#include "pool.h" -#include "race.h" -#include "unit.h" -#include "skill.h" -#include "move.h" - -/* util includes */ -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -/* ------------------------------------------------------------- */ - -void -herbsearch(region * r, unit * u, int max) -{ - int herbsfound; - const item_type * whichherb; - - if (eff_skill(u, SK_HERBALISM, r) == 0) { - cmistake(u, u->thisorder, 59, MSG_PRODUCE); - return; - } - - if(is_guarded(r, u, GUARD_PRODUCE)) { - cmistake(u, u->thisorder, 70, MSG_EVENT); - return; - } - - whichherb = rherbtype(r); - if (whichherb == NULL) { - cmistake(u, u->thisorder, 108, MSG_PRODUCE); - return; - } - - if (max) max = MIN(max, rherbs(r)); - else max = rherbs(r); - herbsfound = ntimespprob(eff_skill(u, SK_HERBALISM, r) * u->number, - (double)rherbs(r)/100.0F, -0.01F); - herbsfound = MIN(herbsfound, max); - rsetherbs(r, rherbs(r)-herbsfound); - - if (herbsfound) { - produceexp(u, SK_HERBALISM, u->number); - i_change(&u->items, whichherb, herbsfound); - ADDMSG(&u->faction->msgs, msg_message("herbfound", - "unit region amount herb", u, r, herbsfound, whichherb->rtype)); - } else { - ADDMSG(&u->faction->msgs, msg_message("researchherb_none", - "unit region", u, u->region)); - } -} - -static int -begin_potion(unit * u, const potion_type * ptype, struct order *ord) -{ - static int rule_multipotion = -1; - assert(ptype!=NULL); - - if (rule_multipotion<0) { - /* should we allow multiple different potions to be used the same turn? */ - rule_multipotion = get_param_int(global.parameters, "rules.magic.multipotion", 0); - } - if (!rule_multipotion) { - const potion_type * use = ugetpotionuse(u); - if (use != NULL && use!=ptype) { - ADDMSG(&u->faction->msgs, - msg_message("errusingpotion", "unit using command", - u, use->itype->rtype, ord)); - return ECUSTOM; - } - } - return 0; -} - -static void -end_potion(unit * u, const potion_type * ptype, int amount) -{ - use_pooled(u, ptype->itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); - usetpotionuse(u, ptype); - - ADDMSG(&u->faction->msgs, msg_message("usepotion", - "unit potion", u, ptype->itype->rtype)); -} - -void -do_potion(unit * u, const potion_type * ptype, int amount) -{ - if (ptype==oldpotiontype[P_LIFE]) { - region * r = u->region; - int holz = 0; - static int tree_type = -1; - static int tree_count = -1; - if (tree_type<0) { - tree_type = get_param_int(global.parameters, "rules.magic.wol_type", 1); - tree_count = get_param_int(global.parameters, "rules.magic.wol_effect", 10); - } - /* mallorn is required to make mallorn forests, wood for regular ones */ - if (fval(r, RF_MALLORN)) { - holz = use_pooled(u, rt_find("mallorn"), - GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, tree_count*amount); - } else { - holz = use_pooled(u, rt_find("log"), - GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, tree_count*amount); - } - if (r->land==0) holz = 0; - if (holzfaction->msgs, msg_message("growtree_effect", - "mage amount", u, holz)); - } else if (ptype==oldpotiontype[P_HEILWASSER]) { - u->hp = MIN(unit_max_hp(u) * u->number, u->hp + 400 * amount); - } else if (ptype==oldpotiontype[P_PEOPLE]) { - region * r = u->region; - attrib * a = (attrib*)a_find(r->attribs, &at_peasantluck); - if (!a) a = a_add(&r->attribs, a_new(&at_peasantluck)); - a->data.i+=amount; - } else if (ptype==oldpotiontype[P_HORSE]) { - region * r = u->region; - attrib * a = (attrib*)a_find(r->attribs, &at_horseluck); - if (!a) a = a_add(&r->attribs, a_new(&at_horseluck)); - a->data.i+=amount; - } else if (ptype==oldpotiontype[P_WAHRHEIT]) { - fset(u, UFL_DISBELIEVES); - amount=1; - } else if (ptype==oldpotiontype[P_MACHT]) { - /* Verfünffacht die HP von max. 10 Personen in der Einheit */ - u->hp += MIN(u->number, 10*amount) * unit_max_hp(u) * 4; - } else { - change_effect(u, ptype, 10*amount); - } -} - -int -use_potion(unit * u, const item_type * itype, int amount, struct order *ord) -{ - const potion_type * ptype = resource2potion(itype->rtype); - - if (oldpotiontype[P_HEAL] && ptype==oldpotiontype[P_HEAL]) { - return EUNUSABLE; - } else { - int result = begin_potion(u, ptype, ord); - if (result) return result; - do_potion(u, ptype, amount); - end_potion(u, ptype, amount); - } - return 0; -} - -typedef struct potiondelay { - unit * u; - const potion_type * ptype; - int amount; -} potiondelay; - -static void init_potiondelay(attrib * a) { - a->data.v = malloc(sizeof(potiondelay)); -} - -static void free_potiondelay(attrib * a) { - free(a->data.v); -} - -static int age_potiondelay(attrib * a) { - potiondelay * pd = (potiondelay *)a->data.v; - do_potion(pd->u, pd->ptype, pd->amount); - return AT_AGE_REMOVE; -} - -/* TODO: - * - this should be a more general item_delay - * - it should not just happen in age(), but be done with eventhandling - */ -attrib_type at_potiondelay = { - "potiondelay", - init_potiondelay, - free_potiondelay, - age_potiondelay, 0, 0 -}; - -static attrib * -make_potiondelay(unit * u, const potion_type* ptype, int amount) -{ - attrib * a = a_new(&at_potiondelay); - potiondelay * pd = (potiondelay *)a->data.v; - pd->u = u; - pd->ptype = ptype; - pd->amount = amount; - return a; -} - -int -use_potion_delayed(unit * u, const item_type * itype, int amount, struct order *ord) -{ - const potion_type * ptype = resource2potion(itype->rtype); - int result = begin_potion(u, ptype, ord); - if (result) return result; - - a_add(&u->attribs, make_potiondelay(u, ptype, amount)); - - end_potion(u, ptype, amount); - return 0; -} - -/*****************/ -/* at_effect */ -/*****************/ - -static void -a_initeffect(attrib *a) -{ - a->data.v = calloc(sizeof(effect_data), 1); -} - -static void -a_finalizeeffect(attrib * a) -{ - free(a->data.v); -} - -static void -a_writeeffect(const attrib * a, const void * owner, struct storage * store) -{ - effect_data * edata = (effect_data*)a->data.v; - store->w_tok(store, resourcename(edata->type->itype->rtype, 0)); - store->w_int(store, edata->value); -} - -static int -a_readeffect(attrib *a, void * owner, struct storage * store) -{ - int power; - const item_type * itype; - effect_data * edata = (effect_data*)a->data.v; - char zText[32]; - - store->r_tok_buf(store, zText, sizeof(zText)); - itype = it_find(zText); - - power = store->r_int(store); - if (itype==NULL || itype->rtype==NULL || itype->rtype->ptype==NULL || power<=0) { - return AT_READ_FAIL; - } - edata->type = itype->rtype->ptype; - edata->value = power; - return AT_READ_OK; -} - -attrib_type at_effect = { - "effect", - a_initeffect, - a_finalizeeffect, - DEFAULT_AGE, - a_writeeffect, - a_readeffect, -}; - -int -get_effect(const unit * u, const potion_type * effect) -{ - const attrib * a; - for (a=a_find(u->attribs, &at_effect); a!=NULL && a->type==&at_effect; a=a->next) { - const effect_data * data = (const effect_data *)a->data.v; - if (data->type==effect) return data->value; - } - return 0; -} - -int -change_effect (unit * u, const potion_type * effect, int delta) -{ - if (delta!=0) { - attrib * a = a_find(u->attribs, &at_effect); - effect_data * data = NULL; - - while (a && a->type==&at_effect) { - data = (effect_data *)a->data.v; - if (data->type==effect) { - if (data->value+delta==0) { - a_remove(&u->attribs, a); - return 0; - } else { - data->value += delta; - return data->value; - } - } - a = a->next; - } - - a = a_add(&u->attribs, a_new(&at_effect)); - data = (effect_data*)a->data.v; - data->type = effect; - data->value = delta; - return data->value; - } - log_error(("change effect with delta==0 for unit %s\n", itoa36(u->no))); - return 0; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "alchemy.h" + +#include "item.h" +#include "faction.h" +#include "message.h" +#include "build.h" +#include "magic.h" +#include "region.h" +#include "pool.h" +#include "race.h" +#include "unit.h" +#include "skill.h" +#include "move.h" + +/* util includes */ +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +/* ------------------------------------------------------------- */ + +void +herbsearch(region * r, unit * u, int max) +{ + int herbsfound; + const item_type * whichherb; + + if (eff_skill(u, SK_HERBALISM, r) == 0) { + cmistake(u, u->thisorder, 59, MSG_PRODUCE); + return; + } + + if(is_guarded(r, u, GUARD_PRODUCE)) { + cmistake(u, u->thisorder, 70, MSG_EVENT); + return; + } + + whichherb = rherbtype(r); + if (whichherb == NULL) { + cmistake(u, u->thisorder, 108, MSG_PRODUCE); + return; + } + + if (max) max = MIN(max, rherbs(r)); + else max = rherbs(r); + herbsfound = ntimespprob(eff_skill(u, SK_HERBALISM, r) * u->number, + (double)rherbs(r)/100.0F, -0.01F); + herbsfound = MIN(herbsfound, max); + rsetherbs(r, rherbs(r)-herbsfound); + + if (herbsfound) { + produceexp(u, SK_HERBALISM, u->number); + i_change(&u->items, whichherb, herbsfound); + ADDMSG(&u->faction->msgs, msg_message("herbfound", + "unit region amount herb", u, r, herbsfound, whichherb->rtype)); + } else { + ADDMSG(&u->faction->msgs, msg_message("researchherb_none", + "unit region", u, u->region)); + } +} + +static int +begin_potion(unit * u, const potion_type * ptype, struct order *ord) +{ + static int rule_multipotion = -1; + assert(ptype!=NULL); + + if (rule_multipotion<0) { + /* should we allow multiple different potions to be used the same turn? */ + rule_multipotion = get_param_int(global.parameters, "rules.magic.multipotion", 0); + } + if (!rule_multipotion) { + const potion_type * use = ugetpotionuse(u); + if (use != NULL && use!=ptype) { + ADDMSG(&u->faction->msgs, + msg_message("errusingpotion", "unit using command", + u, use->itype->rtype, ord)); + return ECUSTOM; + } + } + return 0; +} + +static void +end_potion(unit * u, const potion_type * ptype, int amount) +{ + use_pooled(u, ptype->itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); + usetpotionuse(u, ptype); + + ADDMSG(&u->faction->msgs, msg_message("usepotion", + "unit potion", u, ptype->itype->rtype)); +} + +void +do_potion(unit * u, const potion_type * ptype, int amount) +{ + if (ptype==oldpotiontype[P_LIFE]) { + region * r = u->region; + int holz = 0; + static int tree_type = -1; + static int tree_count = -1; + if (tree_type<0) { + tree_type = get_param_int(global.parameters, "rules.magic.wol_type", 1); + tree_count = get_param_int(global.parameters, "rules.magic.wol_effect", 10); + } + /* mallorn is required to make mallorn forests, wood for regular ones */ + if (fval(r, RF_MALLORN)) { + holz = use_pooled(u, rt_find("mallorn"), + GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, tree_count*amount); + } else { + holz = use_pooled(u, rt_find("log"), + GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, tree_count*amount); + } + if (r->land==0) holz = 0; + if (holzfaction->msgs, msg_message("growtree_effect", + "mage amount", u, holz)); + } else if (ptype==oldpotiontype[P_HEILWASSER]) { + u->hp = MIN(unit_max_hp(u) * u->number, u->hp + 400 * amount); + } else if (ptype==oldpotiontype[P_PEOPLE]) { + region * r = u->region; + attrib * a = (attrib*)a_find(r->attribs, &at_peasantluck); + if (!a) a = a_add(&r->attribs, a_new(&at_peasantluck)); + a->data.i+=amount; + } else if (ptype==oldpotiontype[P_HORSE]) { + region * r = u->region; + attrib * a = (attrib*)a_find(r->attribs, &at_horseluck); + if (!a) a = a_add(&r->attribs, a_new(&at_horseluck)); + a->data.i+=amount; + } else if (ptype==oldpotiontype[P_WAHRHEIT]) { + fset(u, UFL_DISBELIEVES); + amount=1; + } else if (ptype==oldpotiontype[P_MACHT]) { + /* Verfünffacht die HP von max. 10 Personen in der Einheit */ + u->hp += MIN(u->number, 10*amount) * unit_max_hp(u) * 4; + } else { + change_effect(u, ptype, 10*amount); + } +} + +int +use_potion(unit * u, const item_type * itype, int amount, struct order *ord) +{ + const potion_type * ptype = resource2potion(itype->rtype); + + if (oldpotiontype[P_HEAL] && ptype==oldpotiontype[P_HEAL]) { + return EUNUSABLE; + } else { + int result = begin_potion(u, ptype, ord); + if (result) return result; + do_potion(u, ptype, amount); + end_potion(u, ptype, amount); + } + return 0; +} + +typedef struct potiondelay { + unit * u; + const potion_type * ptype; + int amount; +} potiondelay; + +static void init_potiondelay(attrib * a) { + a->data.v = malloc(sizeof(potiondelay)); +} + +static void free_potiondelay(attrib * a) { + free(a->data.v); +} + +static int age_potiondelay(attrib * a) { + potiondelay * pd = (potiondelay *)a->data.v; + do_potion(pd->u, pd->ptype, pd->amount); + return AT_AGE_REMOVE; +} + +/* TODO: + * - this should be a more general item_delay + * - it should not just happen in age(), but be done with eventhandling + */ +attrib_type at_potiondelay = { + "potiondelay", + init_potiondelay, + free_potiondelay, + age_potiondelay, 0, 0 +}; + +static attrib * +make_potiondelay(unit * u, const potion_type* ptype, int amount) +{ + attrib * a = a_new(&at_potiondelay); + potiondelay * pd = (potiondelay *)a->data.v; + pd->u = u; + pd->ptype = ptype; + pd->amount = amount; + return a; +} + +int +use_potion_delayed(unit * u, const item_type * itype, int amount, struct order *ord) +{ + const potion_type * ptype = resource2potion(itype->rtype); + int result = begin_potion(u, ptype, ord); + if (result) return result; + + a_add(&u->attribs, make_potiondelay(u, ptype, amount)); + + end_potion(u, ptype, amount); + return 0; +} + +/*****************/ +/* at_effect */ +/*****************/ + +static void +a_initeffect(attrib *a) +{ + a->data.v = calloc(sizeof(effect_data), 1); +} + +static void +a_finalizeeffect(attrib * a) +{ + free(a->data.v); +} + +static void +a_writeeffect(const attrib * a, const void * owner, struct storage * store) +{ + effect_data * edata = (effect_data*)a->data.v; + store->w_tok(store, resourcename(edata->type->itype->rtype, 0)); + store->w_int(store, edata->value); +} + +static int +a_readeffect(attrib *a, void * owner, struct storage * store) +{ + int power; + const item_type * itype; + effect_data * edata = (effect_data*)a->data.v; + char zText[32]; + + store->r_tok_buf(store, zText, sizeof(zText)); + itype = it_find(zText); + + power = store->r_int(store); + if (itype==NULL || itype->rtype==NULL || itype->rtype->ptype==NULL || power<=0) { + return AT_READ_FAIL; + } + edata->type = itype->rtype->ptype; + edata->value = power; + return AT_READ_OK; +} + +attrib_type at_effect = { + "effect", + a_initeffect, + a_finalizeeffect, + DEFAULT_AGE, + a_writeeffect, + a_readeffect, +}; + +int +get_effect(const unit * u, const potion_type * effect) +{ + const attrib * a; + for (a=a_find(u->attribs, &at_effect); a!=NULL && a->type==&at_effect; a=a->next) { + const effect_data * data = (const effect_data *)a->data.v; + if (data->type==effect) return data->value; + } + return 0; +} + +int +change_effect (unit * u, const potion_type * effect, int delta) +{ + if (delta!=0) { + attrib * a = a_find(u->attribs, &at_effect); + effect_data * data = NULL; + + while (a && a->type==&at_effect) { + data = (effect_data *)a->data.v; + if (data->type==effect) { + if (data->value+delta==0) { + a_remove(&u->attribs, a); + return 0; + } else { + data->value += delta; + return data->value; + } + } + a = a->next; + } + + a = a_add(&u->attribs, a_new(&at_effect)); + data = (effect_data*)a->data.v; + data->type = effect; + data->value = delta; + return data->value; + } + log_error(("change effect with delta==0 for unit %s\n", itoa36(u->no))); + return 0; +} diff --git a/src/kernel/alchemy.h b/src/kernel/alchemy.h index ba89d242b..128286cd1 100644 --- a/src/kernel/alchemy.h +++ b/src/kernel/alchemy.h @@ -1,70 +1,70 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_ALCHEMY_H -#define H_KRNL_ALCHEMY_H -#ifdef __cplusplus -extern "C" { -#endif - -enum { - /* Stufe 1 */ - P_FAST, - P_STRONG, - P_LIFE, - /* Stufe 2 */ - P_DOMORE, - P_HEILWASSER, - P_BAUERNBLUT, - /* Stufe 3 */ - P_WISE, /* 6 */ - P_FOOL, -#ifdef INSECT_POTION - P_WARMTH, -#else - P_STEEL, -#endif - P_HORSE, - P_BERSERK, /* 10 */ - /* Stufe 4 */ - P_PEOPLE, - P_WAHRHEIT, - P_MACHT, - P_HEAL, - MAX_POTIONS -}; - -extern void herbsearch(struct region * r, struct unit * u, int max); -extern int use_potion(struct unit * u, const struct item_type * itype, int amount, struct order *); -extern int use_potion_delayed(struct unit * u, const struct item_type * itype, int amount, struct order *); -extern void init_potions(void); - -extern int get_effect(const struct unit * u, const struct potion_type * effect); -extern int change_effect(struct unit * u, const struct potion_type * effect, int value); -extern struct attrib_type at_effect; - -/* rausnehmen, sobald man attribute splitten kann: */ -typedef struct effect_data { - const struct potion_type * type; - int value; -} effect_data; - -#ifdef __cplusplus -} -#endif -#endif /* ALCHEMY_H */ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_ALCHEMY_H +#define H_KRNL_ALCHEMY_H +#ifdef __cplusplus +extern "C" { +#endif + +enum { + /* Stufe 1 */ + P_FAST, + P_STRONG, + P_LIFE, + /* Stufe 2 */ + P_DOMORE, + P_HEILWASSER, + P_BAUERNBLUT, + /* Stufe 3 */ + P_WISE, /* 6 */ + P_FOOL, +#ifdef INSECT_POTION + P_WARMTH, +#else + P_STEEL, +#endif + P_HORSE, + P_BERSERK, /* 10 */ + /* Stufe 4 */ + P_PEOPLE, + P_WAHRHEIT, + P_MACHT, + P_HEAL, + MAX_POTIONS +}; + +extern void herbsearch(struct region * r, struct unit * u, int max); +extern int use_potion(struct unit * u, const struct item_type * itype, int amount, struct order *); +extern int use_potion_delayed(struct unit * u, const struct item_type * itype, int amount, struct order *); +extern void init_potions(void); + +extern int get_effect(const struct unit * u, const struct potion_type * effect); +extern int change_effect(struct unit * u, const struct potion_type * effect, int value); +extern struct attrib_type at_effect; + +/* rausnehmen, sobald man attribute splitten kann: */ +typedef struct effect_data { + const struct potion_type * type; + int value; +} effect_data; + +#ifdef __cplusplus +} +#endif +#endif /* ALCHEMY_H */ diff --git a/src/kernel/alliance.c b/src/kernel/alliance.c index f1d77b7b6..cec763793 100644 --- a/src/kernel/alliance.c +++ b/src/kernel/alliance.c @@ -1,548 +1,548 @@ -/* vi: set ts=2: -+-------------------+ Christian Schlittchen -| | Enno Rehling -| Eressea PBEM host | Katja Zedel -| (c) 1998 - 2003 | Henning Peters -| | Ingo Wilken -+-------------------+ Stefan Reich - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#pragma region includes - -#include -#include -#include "alliance.h" - -#include - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -#pragma endregion - -alliance * alliances = NULL; - -void -free_alliance(alliance * al) -{ - free(al->name); - while (al->members) { - faction_list * m = al->members; - al->members = m->next; - free(m); - } - free(al); -} - -alliance * -makealliance(int id, const char * name) -{ - alliance * al;; - - for (;;) { - if (id>0) { - for (al=alliances;al;al=al->next) { - if (al->id==id) { - id = 0; - break; - } - } - if (id>0) break; - } - id = id?id:(1 + (rng_int() % MAX_UNIT_NR)); - } - al = calloc(1, sizeof(alliance)); - al->id = id; - if (name) { - al->name = strdup(name); - } else { - al->flags |= ALF_NON_ALLIED; - } - al->next = alliances; - return alliances=al; -} - -alliance * -findalliance(int id) -{ - alliance * al; - for (al=alliances;al;al=al->next) { - if (al->id==id) return al; - } - return NULL; -} - -typedef struct alliance_transaction { - struct alliance_transaction * next; - unit * u; - order * ord; -// alliance * al; -// variant userdata; -} alliance_transaction; - -static struct alliance_transaction * transactions[ALLIANCE_MAX]; - - -faction * -alliance_get_leader(alliance * al) -{ - if (!al->_leader) { - if (al->members) { - al->_leader = al->members->data; - } - } - return al->_leader; -} - -static void -create_transaction(int type, unit * u, order * ord) -{ - alliance_transaction * tr = calloc(1, sizeof(alliance_transaction)); - tr->ord = ord; - tr->u = u; - tr->next = transactions[type]; - transactions[type] = tr; -} - -static void -cmd_kick(const tnode * tnext, void * data, struct order * ord) -{ - create_transaction(ALLIANCE_KICK, (unit*)data, ord); -} - -static void -cmd_leave(const tnode * tnext, void * data, struct order * ord) -{ - create_transaction(ALLIANCE_LEAVE, (unit*)data, ord); -} - -static void -cmd_transfer(const tnode * tnext, void * data, struct order * ord) -{ - create_transaction(ALLIANCE_TRANSFER, (unit*)data, ord); -} - -static void -cmd_new(const tnode * tnext, void * data, struct order * ord) -{ - create_transaction(ALLIANCE_NEW, (unit*)data, ord); -} - -static void -cmd_invite(const tnode * tnext, void * data, struct order * ord) -{ - create_transaction(ALLIANCE_INVITE, (unit*)data, ord); -} - -static void -cmd_join(const tnode * tnext, void * data, struct order * ord) -{ - create_transaction(ALLIANCE_JOIN, (unit*)data, ord); -} - -static void -perform_kick(void) -{ - alliance_transaction ** tap = transactions+ALLIANCE_KICK; - while (*tap) { - alliance_transaction * ta = *tap; - alliance * al = f_get_alliance(ta->u->faction); - - if (al && alliance_get_leader(al)==ta->u->faction) { - faction * f; - init_tokens(ta->ord); - skip_token(); - skip_token(); - f = getfaction(); - if (f && f_get_alliance(f)==al) { - setalliance(f, NULL); - } - } - *tap = ta->next; - free(ta); - } -} - -static void -perform_new(void) -{ - alliance_transaction ** tap = transactions+ALLIANCE_NEW; - while (*tap) { - alliance_transaction * ta = *tap; - alliance * al; - int id; - faction * f = ta->u->faction; - - init_tokens(ta->ord); - skip_token(); - skip_token(); - id = getid(); - - al = makealliance(id, itoa36(id)); - setalliance(f, al); - - *tap = ta->next; - free(ta); - } -} - -static void -perform_leave(void) -{ - alliance_transaction ** tap = transactions+ALLIANCE_LEAVE; - while (*tap) { - alliance_transaction * ta = *tap; - faction * f = ta->u->faction; - - setalliance(f, NULL); - - *tap = ta->next; - free(ta); - } -} - -static void -perform_transfer(void) -{ - alliance_transaction ** tap = transactions+ALLIANCE_TRANSFER; - while (*tap) { - alliance_transaction * ta = *tap; - alliance * al = f_get_alliance(ta->u->faction); - - if (al && alliance_get_leader(al)==ta->u->faction) { - faction * f; - init_tokens(ta->ord); - skip_token(); - skip_token(); - f = getfaction(); - if (f && f_get_alliance(f)==al) { - al->_leader = f; - } - } - *tap = ta->next; - free(ta); - } -} - -static void -perform_join(void) -{ - alliance_transaction ** tap = transactions+ALLIANCE_JOIN; - while (*tap) { - alliance_transaction * ta = *tap; - faction * fj = ta->u->faction; - int aid; - - init_tokens(ta->ord); - skip_token(); - skip_token(); - aid = getid(); - if (aid) { - alliance * al = findalliance(aid); - if (al && f_get_alliance(fj)!=al) { - alliance_transaction ** tip = transactions+ALLIANCE_INVITE; - alliance_transaction * ti = *tip; - while (ti) { - faction * fi = ti->u->faction; - if (fi && f_get_alliance(fi)==al) { - int fid; - init_tokens(ti->ord); - skip_token(); - skip_token(); - fid = getid(); - if (fid==fj->no) { - break; - } - } - tip = &ti->next; - ti = *tip; - } - if (ti) { - setalliance(fj, al); - *tip = ti->next; - free(ti); - } else { - /* TODO: error message */ - } - } - } - *tap = ta->next; - free(ta); - } -} - -static void -execute(const struct syntaxtree * syntax, keyword_t kwd) -{ - int run = 0; - - region ** rp = ®ions; - while (*rp) { - region * r = *rp; - unit **up = &r->units; - while (*up) { - unit * u = *up; - if (u->number) { - const struct locale * lang = u->faction->locale; - tnode * root = stree_find(syntax, lang); - order * ord; - for (ord = u->orders; ord; ord = ord->next) { - if (get_keyword(ord) == kwd) { - do_command(root, u, ord); - run = 1; - } - } - } - if (u==*up) up = &u->next; - } - if (*rp==r) rp = &r->next; - } - - if (run) { - perform_kick(); - perform_leave(); - perform_transfer(); - perform_new(); - perform_join(); - } -} - -void -alliance_cmd(void) -{ - static syntaxtree * stree = NULL; - if (stree==NULL) { - syntaxtree * slang = stree = stree_create(); - while (slang) { - // struct tnode * root = calloc(sizeof(tnode), 1); - struct tnode * leaf = calloc(sizeof(tnode), 1); - // add_command(root, leaf, LOC(slang->lang, "alliance"), NULL); - add_command(leaf, NULL, LOC(slang->lang, "new"), &cmd_new); - add_command(leaf, NULL, LOC(slang->lang, "invite"), &cmd_invite); - add_command(leaf, NULL, LOC(slang->lang, "join"), &cmd_join); - add_command(leaf, NULL, LOC(slang->lang, "kick"), &cmd_kick); - add_command(leaf, NULL, LOC(slang->lang, "leave"), &cmd_leave); - add_command(leaf, NULL, LOC(slang->lang, "command"), &cmd_transfer); - slang->root = leaf; - slang = slang->next; - } - } - execute(stree, K_ALLIANCE); - /* some may have been kicked, must remove f->alliance==NULL */ -} - -void -alliancejoin(void) -{ - static syntaxtree * stree = NULL; - if (stree==NULL) { - syntaxtree * slang = stree = stree_create(); - while (slang) { - struct tnode * root = calloc(sizeof(tnode), 1); - struct tnode * leaf = calloc(sizeof(tnode), 1); - add_command(root, leaf, LOC(slang->lang, "alliance"), NULL); - add_command(leaf, NULL, LOC(slang->lang, "join"), &cmd_join); - slang = slang->next; - } - } - execute(stree, K_ALLIANCE); -} - -void -setalliance(struct faction * f, alliance * al) -{ - faction_list * flist = NULL; - if (f->alliance==al) return; - if (f->alliance!=NULL) { - faction_list ** flistp = &f->alliance->members; - while (*flistp) { - faction_list * flist = *flistp; - if ((*flistp)->data==f) { - *flistp = flist->next; - break; - } - flistp = &flist->next; - } - - if (f->alliance->_leader==f) { - if (f->alliance->members) { - f->alliance->_leader = f->alliance->members->data; - } else { - f->alliance->_leader = NULL; - } - } - } - f->alliance = al; - f->alliance_joindate = turn; - if (al!=NULL) { - faction_list ** flistp = &al->members; - while (*flistp) { - flistp = &(*flistp)->next; - } - if (flist==NULL) { - flist = malloc(sizeof(faction_list)); - flist->data = f; - } - *flistp = flist; - flist->next = NULL; - if (al->_leader==NULL) { - al->_leader = f; - } - flist = NULL; - } - free(flist); -} - -const char * -alliancename(const alliance * al) -{ - typedef char name[OBJECTIDSIZE + 1]; - static name idbuf[8]; - static int nextbuf = 0; - - char *ibuf = idbuf[(++nextbuf) % 8]; - - if (al && al->name) { - snprintf(ibuf, sizeof(name), "%s (%s)", al->name, itoa36(al->id)); - ibuf[sizeof(name)-1] = 0; - } else { - return NULL; - } - return ibuf; -} - -void -alliancevictory(void) -{ - const struct building_type * btype = bt_find("stronghold"); - region * r = regions; - alliance * al = alliances; - if (btype==NULL) return; - while (r!=NULL) { - building * b = r->buildings; - while (b!=NULL) { - if (b->type==btype) { - unit * u = building_owner(b); - if (u) { - fset(u->faction->alliance, FFL_MARK); - } - } - b = b->next; - } - r=r->next; - } - while (al!=NULL) { - if (!fval(al, FFL_MARK)) { - faction_list * flist = al->members; - while (flist!=0) { - faction * f = flist->data; - if (f->alliance==al) { - ADDMSG(&f->msgs, msg_message("alliance::lost", - "alliance", al)); - destroyfaction(f); - } - flist = flist->next; - } - } else { - freset(al, FFL_MARK); - } - al = al->next; - } -} - -int -victorycondition(const alliance * al, const char * name) -{ - const char * gems[] = { "opal", "diamond", "zaphire", "topaz", "beryl", "agate", "garnet", "emerald", NULL }; - if (strcmp(name, "gems")==0) { - const char ** igem = gems; - - for (;*igem;++igem) { - const struct item_type * itype = it_find(*igem); - faction_list * flist = al->members; - boolean found = false; - - assert(itype!=NULL); - for (;flist && !found;flist=flist->next) { - unit * u = flist->data->units; - - for (;u;u=u->nextF) { - if (i_get(u->items, itype)>0) { - found = true; - break; - } - } - } - if (!found) return 0; - } - return 1; - - } else if (strcmp(name, "phoenix")==0) { - faction_list * flist = al->members; - for (;flist;flist=flist->next) { - faction * f = flist->data; - if (find_key(f->attribs, atoi36("phnx"))) { - return 1; - } - } - return 0; - - } else if (strcmp(name, "pyramid")==0) { - - /* Logik: - * - if (pyr > last_passed_size && pyr > all_others) { - * pyr->passed->counter++; - * for(all_other_pyrs) { - * pyr->passed->counter=0; - * } - * - * if(pyr->passed->counter >= 3) { - * set(pyr, passed); - * pyr->owner->set_attrib(pyra); - * } - * last_passed_size = pyr->size; - * } - */ - - faction_list * flist = al->members; - for (;flist;flist=flist->next) { - faction * f = flist->data; - if (find_key(f->attribs, atoi36("pyra"))) { - return 1; - } - } - return 0; - } - return -1; -} - -void alliance_setname(alliance * self, const char * name) -{ - free(self->name); - if (name) self->name = strdup(name); - else self->name = NULL; -} +/* vi: set ts=2: ++-------------------+ Christian Schlittchen +| | Enno Rehling +| Eressea PBEM host | Katja Zedel +| (c) 1998 - 2003 | Henning Peters +| | Ingo Wilken ++-------------------+ Stefan Reich + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#pragma region includes + +#include +#include +#include "alliance.h" + +#include + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +#pragma endregion + +alliance * alliances = NULL; + +void +free_alliance(alliance * al) +{ + free(al->name); + while (al->members) { + faction_list * m = al->members; + al->members = m->next; + free(m); + } + free(al); +} + +alliance * +makealliance(int id, const char * name) +{ + alliance * al;; + + for (;;) { + if (id>0) { + for (al=alliances;al;al=al->next) { + if (al->id==id) { + id = 0; + break; + } + } + if (id>0) break; + } + id = id?id:(1 + (rng_int() % MAX_UNIT_NR)); + } + al = calloc(1, sizeof(alliance)); + al->id = id; + if (name) { + al->name = strdup(name); + } else { + al->flags |= ALF_NON_ALLIED; + } + al->next = alliances; + return alliances=al; +} + +alliance * +findalliance(int id) +{ + alliance * al; + for (al=alliances;al;al=al->next) { + if (al->id==id) return al; + } + return NULL; +} + +typedef struct alliance_transaction { + struct alliance_transaction * next; + unit * u; + order * ord; +// alliance * al; +// variant userdata; +} alliance_transaction; + +static struct alliance_transaction * transactions[ALLIANCE_MAX]; + + +faction * +alliance_get_leader(alliance * al) +{ + if (!al->_leader) { + if (al->members) { + al->_leader = al->members->data; + } + } + return al->_leader; +} + +static void +create_transaction(int type, unit * u, order * ord) +{ + alliance_transaction * tr = calloc(1, sizeof(alliance_transaction)); + tr->ord = ord; + tr->u = u; + tr->next = transactions[type]; + transactions[type] = tr; +} + +static void +cmd_kick(const tnode * tnext, void * data, struct order * ord) +{ + create_transaction(ALLIANCE_KICK, (unit*)data, ord); +} + +static void +cmd_leave(const tnode * tnext, void * data, struct order * ord) +{ + create_transaction(ALLIANCE_LEAVE, (unit*)data, ord); +} + +static void +cmd_transfer(const tnode * tnext, void * data, struct order * ord) +{ + create_transaction(ALLIANCE_TRANSFER, (unit*)data, ord); +} + +static void +cmd_new(const tnode * tnext, void * data, struct order * ord) +{ + create_transaction(ALLIANCE_NEW, (unit*)data, ord); +} + +static void +cmd_invite(const tnode * tnext, void * data, struct order * ord) +{ + create_transaction(ALLIANCE_INVITE, (unit*)data, ord); +} + +static void +cmd_join(const tnode * tnext, void * data, struct order * ord) +{ + create_transaction(ALLIANCE_JOIN, (unit*)data, ord); +} + +static void +perform_kick(void) +{ + alliance_transaction ** tap = transactions+ALLIANCE_KICK; + while (*tap) { + alliance_transaction * ta = *tap; + alliance * al = f_get_alliance(ta->u->faction); + + if (al && alliance_get_leader(al)==ta->u->faction) { + faction * f; + init_tokens(ta->ord); + skip_token(); + skip_token(); + f = getfaction(); + if (f && f_get_alliance(f)==al) { + setalliance(f, NULL); + } + } + *tap = ta->next; + free(ta); + } +} + +static void +perform_new(void) +{ + alliance_transaction ** tap = transactions+ALLIANCE_NEW; + while (*tap) { + alliance_transaction * ta = *tap; + alliance * al; + int id; + faction * f = ta->u->faction; + + init_tokens(ta->ord); + skip_token(); + skip_token(); + id = getid(); + + al = makealliance(id, itoa36(id)); + setalliance(f, al); + + *tap = ta->next; + free(ta); + } +} + +static void +perform_leave(void) +{ + alliance_transaction ** tap = transactions+ALLIANCE_LEAVE; + while (*tap) { + alliance_transaction * ta = *tap; + faction * f = ta->u->faction; + + setalliance(f, NULL); + + *tap = ta->next; + free(ta); + } +} + +static void +perform_transfer(void) +{ + alliance_transaction ** tap = transactions+ALLIANCE_TRANSFER; + while (*tap) { + alliance_transaction * ta = *tap; + alliance * al = f_get_alliance(ta->u->faction); + + if (al && alliance_get_leader(al)==ta->u->faction) { + faction * f; + init_tokens(ta->ord); + skip_token(); + skip_token(); + f = getfaction(); + if (f && f_get_alliance(f)==al) { + al->_leader = f; + } + } + *tap = ta->next; + free(ta); + } +} + +static void +perform_join(void) +{ + alliance_transaction ** tap = transactions+ALLIANCE_JOIN; + while (*tap) { + alliance_transaction * ta = *tap; + faction * fj = ta->u->faction; + int aid; + + init_tokens(ta->ord); + skip_token(); + skip_token(); + aid = getid(); + if (aid) { + alliance * al = findalliance(aid); + if (al && f_get_alliance(fj)!=al) { + alliance_transaction ** tip = transactions+ALLIANCE_INVITE; + alliance_transaction * ti = *tip; + while (ti) { + faction * fi = ti->u->faction; + if (fi && f_get_alliance(fi)==al) { + int fid; + init_tokens(ti->ord); + skip_token(); + skip_token(); + fid = getid(); + if (fid==fj->no) { + break; + } + } + tip = &ti->next; + ti = *tip; + } + if (ti) { + setalliance(fj, al); + *tip = ti->next; + free(ti); + } else { + /* TODO: error message */ + } + } + } + *tap = ta->next; + free(ta); + } +} + +static void +execute(const struct syntaxtree * syntax, keyword_t kwd) +{ + int run = 0; + + region ** rp = ®ions; + while (*rp) { + region * r = *rp; + unit **up = &r->units; + while (*up) { + unit * u = *up; + if (u->number) { + const struct locale * lang = u->faction->locale; + tnode * root = stree_find(syntax, lang); + order * ord; + for (ord = u->orders; ord; ord = ord->next) { + if (get_keyword(ord) == kwd) { + do_command(root, u, ord); + run = 1; + } + } + } + if (u==*up) up = &u->next; + } + if (*rp==r) rp = &r->next; + } + + if (run) { + perform_kick(); + perform_leave(); + perform_transfer(); + perform_new(); + perform_join(); + } +} + +void +alliance_cmd(void) +{ + static syntaxtree * stree = NULL; + if (stree==NULL) { + syntaxtree * slang = stree = stree_create(); + while (slang) { + // struct tnode * root = calloc(sizeof(tnode), 1); + struct tnode * leaf = calloc(sizeof(tnode), 1); + // add_command(root, leaf, LOC(slang->lang, "alliance"), NULL); + add_command(leaf, NULL, LOC(slang->lang, "new"), &cmd_new); + add_command(leaf, NULL, LOC(slang->lang, "invite"), &cmd_invite); + add_command(leaf, NULL, LOC(slang->lang, "join"), &cmd_join); + add_command(leaf, NULL, LOC(slang->lang, "kick"), &cmd_kick); + add_command(leaf, NULL, LOC(slang->lang, "leave"), &cmd_leave); + add_command(leaf, NULL, LOC(slang->lang, "command"), &cmd_transfer); + slang->root = leaf; + slang = slang->next; + } + } + execute(stree, K_ALLIANCE); + /* some may have been kicked, must remove f->alliance==NULL */ +} + +void +alliancejoin(void) +{ + static syntaxtree * stree = NULL; + if (stree==NULL) { + syntaxtree * slang = stree = stree_create(); + while (slang) { + struct tnode * root = calloc(sizeof(tnode), 1); + struct tnode * leaf = calloc(sizeof(tnode), 1); + add_command(root, leaf, LOC(slang->lang, "alliance"), NULL); + add_command(leaf, NULL, LOC(slang->lang, "join"), &cmd_join); + slang = slang->next; + } + } + execute(stree, K_ALLIANCE); +} + +void +setalliance(struct faction * f, alliance * al) +{ + faction_list * flist = NULL; + if (f->alliance==al) return; + if (f->alliance!=NULL) { + faction_list ** flistp = &f->alliance->members; + while (*flistp) { + faction_list * flist = *flistp; + if ((*flistp)->data==f) { + *flistp = flist->next; + break; + } + flistp = &flist->next; + } + + if (f->alliance->_leader==f) { + if (f->alliance->members) { + f->alliance->_leader = f->alliance->members->data; + } else { + f->alliance->_leader = NULL; + } + } + } + f->alliance = al; + f->alliance_joindate = turn; + if (al!=NULL) { + faction_list ** flistp = &al->members; + while (*flistp) { + flistp = &(*flistp)->next; + } + if (flist==NULL) { + flist = malloc(sizeof(faction_list)); + flist->data = f; + } + *flistp = flist; + flist->next = NULL; + if (al->_leader==NULL) { + al->_leader = f; + } + flist = NULL; + } + free(flist); +} + +const char * +alliancename(const alliance * al) +{ + typedef char name[OBJECTIDSIZE + 1]; + static name idbuf[8]; + static int nextbuf = 0; + + char *ibuf = idbuf[(++nextbuf) % 8]; + + if (al && al->name) { + snprintf(ibuf, sizeof(name), "%s (%s)", al->name, itoa36(al->id)); + ibuf[sizeof(name)-1] = 0; + } else { + return NULL; + } + return ibuf; +} + +void +alliancevictory(void) +{ + const struct building_type * btype = bt_find("stronghold"); + region * r = regions; + alliance * al = alliances; + if (btype==NULL) return; + while (r!=NULL) { + building * b = r->buildings; + while (b!=NULL) { + if (b->type==btype) { + unit * u = building_owner(b); + if (u) { + fset(u->faction->alliance, FFL_MARK); + } + } + b = b->next; + } + r=r->next; + } + while (al!=NULL) { + if (!fval(al, FFL_MARK)) { + faction_list * flist = al->members; + while (flist!=0) { + faction * f = flist->data; + if (f->alliance==al) { + ADDMSG(&f->msgs, msg_message("alliance::lost", + "alliance", al)); + destroyfaction(f); + } + flist = flist->next; + } + } else { + freset(al, FFL_MARK); + } + al = al->next; + } +} + +int +victorycondition(const alliance * al, const char * name) +{ + const char * gems[] = { "opal", "diamond", "zaphire", "topaz", "beryl", "agate", "garnet", "emerald", NULL }; + if (strcmp(name, "gems")==0) { + const char ** igem = gems; + + for (;*igem;++igem) { + const struct item_type * itype = it_find(*igem); + faction_list * flist = al->members; + boolean found = false; + + assert(itype!=NULL); + for (;flist && !found;flist=flist->next) { + unit * u = flist->data->units; + + for (;u;u=u->nextF) { + if (i_get(u->items, itype)>0) { + found = true; + break; + } + } + } + if (!found) return 0; + } + return 1; + + } else if (strcmp(name, "phoenix")==0) { + faction_list * flist = al->members; + for (;flist;flist=flist->next) { + faction * f = flist->data; + if (find_key(f->attribs, atoi36("phnx"))) { + return 1; + } + } + return 0; + + } else if (strcmp(name, "pyramid")==0) { + + /* Logik: + * - if (pyr > last_passed_size && pyr > all_others) { + * pyr->passed->counter++; + * for(all_other_pyrs) { + * pyr->passed->counter=0; + * } + * + * if(pyr->passed->counter >= 3) { + * set(pyr, passed); + * pyr->owner->set_attrib(pyra); + * } + * last_passed_size = pyr->size; + * } + */ + + faction_list * flist = al->members; + for (;flist;flist=flist->next) { + faction * f = flist->data; + if (find_key(f->attribs, atoi36("pyra"))) { + return 1; + } + } + return 0; + } + return -1; +} + +void alliance_setname(alliance * self, const char * name) +{ + free(self->name); + if (name) self->name = strdup(name); + else self->name = NULL; +} diff --git a/src/kernel/alliance.h b/src/kernel/alliance.h index 7b77b6ea1..e9cab8b66 100644 --- a/src/kernel/alliance.h +++ b/src/kernel/alliance.h @@ -1,68 +1,68 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_ALLIANCE -#define H_KRNL_ALLIANCE -#ifdef __cplusplus -extern "C" { -#endif - -struct plane; -struct attrib; -struct unit; -struct faction; -struct region; -struct faction_list; - -enum { - ALLIANCE_KICK, - ALLIANCE_LEAVE, - ALLIANCE_TRANSFER, - ALLIANCE_NEW, - ALLIANCE_INVITE, - ALLIANCE_JOIN, - ALLIANCE_MAX -}; - -#define ALF_NON_ALLIED (1<<0) /* this alliance is just a default for a non-allied faction */ - -typedef struct alliance { - struct alliance * next; - struct faction * _leader; - struct faction_list * members; - unsigned int flags; - int id; - char * name; -} alliance; - -extern alliance * alliances; -extern alliance * findalliance(int id); -extern alliance * makealliance(int id, const char * name); -extern const char * alliancename(const struct alliance * al); -extern void setalliance(struct faction * f, alliance * al); -void free_alliance(struct alliance * al); -extern struct faction * alliance_get_leader(struct alliance * al); -extern void alliance_cmd(void); - -void alliance_setname(alliance * self, const char * name); -/* execute commands */ - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_ALLIANCE +#define H_KRNL_ALLIANCE +#ifdef __cplusplus +extern "C" { +#endif + +struct plane; +struct attrib; +struct unit; +struct faction; +struct region; +struct faction_list; + +enum { + ALLIANCE_KICK, + ALLIANCE_LEAVE, + ALLIANCE_TRANSFER, + ALLIANCE_NEW, + ALLIANCE_INVITE, + ALLIANCE_JOIN, + ALLIANCE_MAX +}; + +#define ALF_NON_ALLIED (1<<0) /* this alliance is just a default for a non-allied faction */ + +typedef struct alliance { + struct alliance * next; + struct faction * _leader; + struct faction_list * members; + unsigned int flags; + int id; + char * name; +} alliance; + +extern alliance * alliances; +extern alliance * findalliance(int id); +extern alliance * makealliance(int id, const char * name); +extern const char * alliancename(const struct alliance * al); +extern void setalliance(struct faction * f, alliance * al); +void free_alliance(struct alliance * al); +extern struct faction * alliance_get_leader(struct alliance * al); +extern void alliance_cmd(void); + +void alliance_setname(alliance * self, const char * name); +/* execute commands */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/battle.c b/src/kernel/battle.c index 85fc85db8..a4eadfcda 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -1,4371 +1,4371 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#pragma region includes - -#include -#include -#include "battle.h" - -#include "alchemy.h" -#include "alliance.h" -#include "build.h" -#include "building.h" -#include "curse.h" -#include "equipment.h" -#include "faction.h" -#include "group.h" -#include "item.h" -#include "magic.h" -#include "message.h" -#include "move.h" -#include "names.h" -#include "order.h" -#include "plane.h" -#include "race.h" -#include "region.h" -#include "reports.h" -#include "ship.h" -#include "skill.h" -#include "terrain.h" -#include "unit.h" - -/* attributes includes */ -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include - -#pragma endregion - -static FILE *bdebug; - -#define TACTICS_BONUS 1 /* when undefined, we have a tactics round. else this is the bonus tactics give */ -#define TACTICS_MODIFIER 1 /* modifier for generals in the fromt/rear */ - -#define CATAPULT_INITIAL_RELOAD 4 /* erster schuss in runde 1 + rng_int() % INITIAL */ -#define CATAPULT_STRUCTURAL_DAMAGE - -#define BASE_CHANCE 70 /* 70% Basis-Überlebenschance */ -#ifdef NEW_COMBATSKILLS_RULE -#define TDIFF_CHANGE 5 /* 5% höher pro Stufe */ -#define DAMAGE_QUOTIENT 2 /* damage += skilldiff/DAMAGE_QUOTIENT */ -#else -#define TDIFF_CHANGE 10 -# define DAMAGE_QUOTIENT 1 /* damage += skilldiff/DAMAGE_QUOTIENT */ -#endif - -#undef DEBUG_FAST /* should be disabled when b->fast and b->rowcache works */ -#define DEBUG_SELECT /* should be disabled if select_enemy works */ - -typedef enum combatmagic { - DO_PRECOMBATSPELL, - DO_POSTCOMBATSPELL -} combatmagic_t; - -/* globals */ -static int obs_count = 0; - -#define MINSPELLRANGE 1 -#define MAXSPELLRANGE 7 - -#ifndef ROW_FACTOR -# define ROW_FACTOR 10 -#endif -static const double EFFECT_PANIC_SPELL = 0.25; -static const double TROLL_REGENERATION = 0.10; - -/* Nach dem alten System: */ -static int missile_range[2] = {FIGHT_ROW, BEHIND_ROW}; -static int melee_range[2] = {FIGHT_ROW, FIGHT_ROW}; -static message * msg_separator; - -const troop no_troop = {0, 0}; - -static int max_turns = 0; -static int damage_rules = 0; -static int loot_rules = 0; -static int skill_formula = 0; - -#define FORMULA_ORIG 0 -#define FORMULA_NEW 1 - -#define LOOT_MONSTERS (1<<0) -#define LOOT_SELF (1<<1) /* code is mutually exclusive with LOOT_OTHERS */ -#define LOOT_OTHERS (1<<2) -#define LOOT_KEEPLOOT (1<<4) - -#define DAMAGE_CRITICAL (1<<0) -#define DAMAGE_MELEE_BONUS (1<<1) -#define DAMAGE_MISSILE_BONUS (1<<2) -#define DAMAGE_UNARMED_BONUS (1<<3) -#define DAMAGE_SKILL_BONUS (1<<4) -/** initialize rules from configuration. - */ -static void -static_rules(void) -{ - loot_rules = get_param_int(global.parameters, "rules.combat.loot", LOOT_MONSTERS|LOOT_OTHERS|LOOT_KEEPLOOT); - /* new formula to calculate to-hit-chance */ - skill_formula = get_param_int(global.parameters, "rules.combat.skill_formula", FORMULA_ORIG); - /* maximum number of combat turns */ - max_turns = get_param_int(global.parameters, "rules.combat.turns", COMBAT_TURNS); - /* damage calculation */ - if (get_param_int(global.parameters, "rules.combat.critical", 1)) { - damage_rules |= DAMAGE_CRITICAL; - } - if (get_param_int(global.parameters, "rules.combat.melee_bonus", 1)) { - damage_rules |= DAMAGE_MELEE_BONUS; - } - if (get_param_int(global.parameters, "rules.combat.missile_bonus", 1)) { - damage_rules |= DAMAGE_MISSILE_BONUS; - } - if (get_param_int(global.parameters, "rules.combat.unarmed_bonus", 1)) { - damage_rules |= DAMAGE_UNARMED_BONUS; - } - if (get_param_int(global.parameters, "rules.combat.skill_bonus", 1)) { - damage_rules |= DAMAGE_SKILL_BONUS; - } -} - -static int -army_index(side * s) -{ - return s->index; -} - -#ifndef SIMPLE_ESCAPE -region * -fleeregion(const unit * u) -{ - region *r = u->region; - region *neighbours[MAXDIRECTIONS]; - int c = 0; - direction_t i; - - if (u->ship && !fval(r->terrain, SEA_REGION)) - return NULL; - - if (u->ship && - !(u->race->flags & RCF_SWIM) && - !(u->race->flags & RCF_FLY)) { - return NULL; - } - - for (i = 0; i != MAXDIRECTIONS; ++i) { - region * r2 = rconnect(r, i); - if (r2) { - if (can_survive(u,r2) && !move_blocked(u, r, r2)) - neighbours[c++] = r2; - } - } - - if (!c) - return NULL; - return neighbours[rng_int() % c]; -} -#endif /* SIMPLE_ESCAPE */ - -static char * -sidename(side * s) -{ -#define SIDENAMEBUFLEN 256 - static int bufno; /* STATIC_XCALL: used across calls */ - static char sidename_buf[4][SIDENAMEBUFLEN]; /* STATIC_RESULT: used for return, not across calls */ - - bufno = bufno % 4; - if (s->stealthfaction) { - snprintf(sidename_buf[bufno], SIDENAMEBUFLEN, - "%s", factionname(s->stealthfaction)); - } else { - snprintf(sidename_buf[bufno], SIDENAMEBUFLEN, - "%s", factionname(s->faction)); - } - return sidename_buf[bufno++]; -} - -static const char * -sideabkz(side *s, boolean truename) -{ - static char sideabkz_buf[8]; /* STATIC_RESULT: used for return, not across calls */ - const faction * f = (s->stealthfaction && !truename)?s->stealthfaction:s->faction; - -#undef SIDE_ABKZ -#ifdef SIDE_ABKZ - abkz(f->name, sideabkz_buf, sizeof(sideabkz_buf), 3); -#else - strcpy(sideabkz_buf, itoa36(f->no)); -#endif - return sideabkz_buf; -} - -static void -message_faction(battle * b, faction * f, struct message * m) -{ - region * r = b->region; - - if (f->battles==NULL || f->battles->r!=r) { - struct bmsg * bm = calloc(1, sizeof(struct bmsg)); - bm->next = f->battles; - f->battles = bm; - bm->r = r; - } - add_message(&f->battles->msgs, m); -} - -int -armedmen(const unit * u, boolean siege_weapons) -{ - item * itm; - int n = 0; - if (!(urace(u)->flags & RCF_NOWEAPONS)) { - if (effskill(u, SK_WEAPONLESS)>=1) { - /* kann ohne waffen bewachen: fuer drachen */ - n = u->number; - } else { - /* alle Waffen werden gezaehlt, und dann wird auf die Anzahl - * Personen minimiert */ - for (itm=u->items;itm;itm=itm->next) { - const weapon_type * wtype = resource2weapon(itm->type->rtype); - if (wtype==NULL || (!siege_weapons && (wtype->flags & WTF_SIEGE))) continue; - if (effskill(u, wtype->skill) >= 1) n += itm->number; - /* if (effskill(u, wtype->skill) >= wtype->minskill) n += itm->number; */ - if (n>u->number) break; - } - n = MIN(n, u->number); - } - } - return n; -} - -void -message_all(battle * b, message * m) -{ - bfaction * bf; - plane * p = rplane(b->region); - watcher * w; - - for (bf = b->factions;bf;bf=bf->next) { - message_faction(b, bf->faction, m); - } - if (p) for (w=p->watchers;w;w=w->next) { - for (bf = b->factions;bf;bf=bf->next) if (bf->faction==w->faction) break; - if (bf==NULL) message_faction(b, w->faction, m); - } -} - -static void -fbattlerecord(battle * b, faction * f, const char *s) -{ - message * m = msg_message("battle_msg", "string", s); - message_faction(b, f, m); - msg_release(m); -} - -/* being an enemy or a friend is (and must always be!) symmetrical */ -#define enemy_i(as, di) (as->relations[di]&E_ENEMY) -#define friendly_i(as, di) (as->relations[di]&E_FRIEND) -#define enemy(as, ds) (as->relations[ds->index]&E_ENEMY) -#define friendly(as, ds) (as->relations[ds->index]&E_FRIEND) - -static boolean -set_enemy(side * as, side * ds, boolean attacking) -{ - int i; - for (i=0;i!=MAXSIDES;++i) { - if (ds->enemies[i]==NULL) ds->enemies[i]=as; - if (ds->enemies[i]==as) break; - } - for (i=0;i!=MAXSIDES;++i) { - if (as->enemies[i]==NULL) as->enemies[i]=ds; - if (as->enemies[i]==ds) break; - } - assert(i!=MAXSIDES); - if (attacking) as->relations[ds->index] |= E_ATTACKING; - if ((ds->relations[as->index] & E_ENEMY)==0) { - /* enemy-relation are always symmetrical */ - assert((as->relations[ds->index] & (E_ENEMY|E_FRIEND))==0); - ds->relations[as->index] |= E_ENEMY; - as->relations[ds->index] |= E_ENEMY; - return true; - } - return false; -} - -static void -set_friendly(side * as, side * ds) -{ - assert((as->relations[ds->index] & E_ENEMY)==0); - ds->relations[as->index] |= E_FRIEND; - as->relations[ds->index] |= E_FRIEND; -} - -static int -allysfm(const side * s, const faction * f, int mode) -{ - if (s->faction==f) return mode; - if (s->group) { - return alliedgroup(s->battle->plane, s->faction, f, s->group->allies, mode); - } - return alliedfaction(s->battle->plane, s->faction, f, mode); -} - -static int -allysf(const side * s, const faction * f) -{ - return allysfm(s, f, HELP_FIGHT); -} - -static int -dead_fighters(const fighter * df) -{ - return df->unit->number - df->alive - df->run.number; -} - -fighter * -select_corpse(battle * b, fighter * af) -/* Wählt eine Leiche aus, der af hilft. casualties ist die Anzahl der - * Toten auf allen Seiten (im Array). Wenn af == NULL, wird die - * Parteizugehörigkeit ignoriert, und irgendeine Leiche genommen. - * - * Untote werden nicht ausgewählt (casualties, not dead) */ -{ - int si, di, maxcasualties = 0; - fighter *df; - side *s; - - for (si=0;si!=b->nsides;++si) { - side * s = b->sides+si; - if (af==NULL || (!enemy_i(af->side, si) && allysf(af->side, s->faction))) { - maxcasualties += s->casualties; - } - } - di = rng_int() % maxcasualties; - for (s=b->sides;s!=b->sides+b->nsides;++s) { - for (df=s->fighters;df;df=df->next) { - /* Geflohene haben auch 0 hp, dürfen hier aber nicht ausgewählt - * werden! */ - int dead = dead_fighters(df); - if (!playerrace(df->unit->race)) continue; - - if (af && !helping(af->side, df->side)) - continue; - if (di < dead) { - return df; - } - di -= dead; - } - } - - return NULL; -} - -boolean -helping(const side * as, const side * ds) -{ - if (as->faction==ds->faction) return true; - return (boolean)(!enemy(as, ds) && allysf(as, ds->faction)); -} - -int -statusrow(int status) -{ - switch (status) { - case ST_AGGRO: - case ST_FIGHT: - return FIGHT_ROW; - case ST_BEHIND: - case ST_CHICKEN: - return BEHIND_ROW; - case ST_AVOID: - return AVOID_ROW; - case ST_FLEE: - return FLEE_ROW; - default: - assert(!"unknown combatrow"); - } - return FIGHT_ROW; -} - -static double -hpflee(int status) - /* if hp drop below this percentage, run away */ -{ - switch (status) { - case ST_AGGRO: - return 0.0; - case ST_FIGHT: - case ST_BEHIND: - return 0.2; - case ST_CHICKEN: - case ST_AVOID: - return 0.9; - case ST_FLEE: - return 1.0; - default: - assert(!"unknown combatrow"); - } - return 0.0; -} - -static int -get_row(const side * s, int row, const side * vs) -{ - boolean counted[MAXSIDES]; - int enemyfront = 0; - int line, result; - int retreat = 0; - int size[NUMROWS]; - int front = 0; - battle * b = s->battle; - - memset(counted, 0, sizeof(counted)); - memset(size, 0, sizeof(size)); - for (line=FIRST_ROW;line!=NUMROWS;++line) { - int si, sa_i; - /* how many enemies are there in the first row? */ - for (si=0;s->enemies[si];++si) { - side *se = s->enemies[si]; - if (se->size[line]>0) { - enemyfront += se->size[line]; - /* - s->nonblockers[line] (nicht, weil angreifer) */ - } - } - for (sa_i=0; sa_i!=b->nsides; ++sa_i) { - side * sa = b->sides+sa_i; - /* count people that like me, but don't like my enemy */ - if (friendly_i(s, sa_i) && enemy_i(vs, sa_i)) { - if (!counted[sa_i]) { - int i; - - for (i=0;i!=NUMROWS;++i) { - size[i] += sa->size[i] - sa->nonblockers[i]; - } - counted[sa_i] = true; - } - } - } - if (enemyfront) break; - } - if (enemyfront) { - for (line=FIRST_ROW;line!=NUMROWS;++line) { - front += size[line]; - if (!front || frontstatus); - if (vs==NULL) { - int i; - for (i=FIGHT_ROW;i!=row;++i) if (af->side->size[i]) break; - return FIGHT_ROW+(row-i); - } else { -#ifdef FASTROW - battle * b = vs->battle; - if (row!=b->rowcache.row || b->alive!=b->rowcache.alive || af->side!=b->rowcache.as || vs!=b->rowcache.vs) { - b->rowcache.alive = b->alive; - b->rowcache.as = af->side; - b->rowcache.vs = vs; - b->rowcache.row = row; - b->rowcache.result = get_row(af->side, row, vs); - return b->rowcache.result; - } -#ifdef DEBUG_FAST /* validation code */ - { - int i = get_row(af->side, row, vs); - assert(i==b->rowcache.result); - } -#endif - return b->rowcache.result; -#else - return get_row(af->side, row, vs); -#endif - } -} - -static void -reportcasualties(battle * b, fighter * fig, int dead) -{ - struct message * m; - region * r = NULL; - if (fig->alive == fig->unit->number) return; -#ifndef SIMPLE_ESCAPE - if (fig->run.region == NULL) { - fig->run.region = fleeregion(fig->unit); - if (fig->run.region == NULL) fig->run.region = b->region; - } - r = fig->run.region; -#endif /* SIMPLE_ESCAPE */ - m = msg_message("casualties", "unit runto run alive fallen", - fig->unit, r, fig->run.number, fig->alive, dead); - message_all(b, m); - msg_release(m); -} - -static int -contest_classic(int skilldiff, const armor_type * ar, const armor_type * sh) -{ - int p, vw = BASE_CHANCE - TDIFF_CHANGE * skilldiff; - double mod = 1.0; - - if (ar != NULL) - mod *= (1 + ar->penalty); - if (sh != NULL) - mod *= (1 + sh->penalty); - vw = (int)(100 - ((100 - vw) * mod)); - - do { - p = rng_int() % 100; - vw -= p; - } - while (vw >= 0 && p >= 90); - return (vw <= 0); -} - -/** new rule for Eressea 1.5 - * \param skilldiff - the attack skill with every modifier applied - */ -static int -contest_new(int skilldiff, const troop dt, const armor_type * ar, const armor_type * sh) -{ - double tohit = 0.5 + skilldiff * 0.1; - if (tohit<0.5) tohit = 0.5; - if (chance(tohit)) { - int defense = effskill(dt.fighter->unit, SK_STAMINA); - double tosave = defense * 0.05; - return !chance(tosave); - } - return 0; -} - -static int -contest(int skdiff, const troop dt, const armor_type * ar, const armor_type * sh) -{ - if (skill_formula==FORMULA_ORIG) { - return contest_classic(skdiff, ar, sh); - } else { - return contest_new(skdiff, dt, ar, sh); - } -} - -static boolean -is_riding(const troop t) { - if (t.fighter->building!=NULL) return false; - if (t.fighter->horses + t.fighter->elvenhorses > t.index) return true; - return false; -} - -static weapon * -preferred_weapon(const troop t, boolean attacking) -{ - weapon * missile = t.fighter->person[t.index].missile; - weapon * melee = t.fighter->person[t.index].melee; - if (attacking) { - if (melee==NULL || (missile && missile->attackskill>melee->attackskill)) { - return missile; - } - } else { - if (melee==NULL || (missile && missile->defenseskill>melee->defenseskill)) { - return missile; - } - } - return melee; -} - -static weapon * -select_weapon(const troop t, boolean attacking, boolean ismissile) - /* select the primary weapon for this trooper */ -{ - if (attacking) { - if (ismissile) { - /* from the back rows, have to use your missile weapon */ - return t.fighter->person[t.index].missile; - } - } else { - if (!ismissile) { - /* have to use your melee weapon if it's melee */ - return t.fighter->person[t.index].melee; - } - } - return preferred_weapon(t, attacking); -} - -static boolean -i_canuse(const unit * u, const item_type * itype) -{ - if (itype->canuse) { - return itype->canuse(u, itype); - } - return true; -} - -static int -weapon_skill(const weapon_type * wtype, const unit * u, boolean attacking) - /* the 'pure' skill when using this weapon to attack or defend. - * only undiscriminate modifiers (not affected by troops or enemies) - * are taken into account, e.g. no horses, magic, etc. */ -{ - int skill; - - if (wtype==NULL) { - skill = effskill(u, SK_WEAPONLESS); - if (skill<=0) { - /* wenn kein waffenloser kampf, dann den rassen-defaultwert */ - if (u->race == new_race[RC_ORC]) { - int sword = effskill(u, SK_MELEE); - int spear = effskill(u, SK_SPEAR); - skill = MAX(sword, spear) - 3; - if (attacking) { - skill = MAX(skill, u->race->at_default); - } else { - skill = MAX(skill, u->race->df_default); - } - } else { - if (attacking) { - skill = u->race->at_default; - } else { - skill = u->race->df_default; - } - } - } else { - /* der rassen-defaultwert kann höher sein als der Talentwert von - * waffenloser kampf */ - if (attacking) { - if (skill < u->race->at_default) skill = u->race->at_default; - } else { - if (skill < u->race->df_default) skill = u->race->df_default; - } - } - if (attacking) { - skill += u->race->at_bonus; - if (fval(u->region->terrain, SEA_REGION) && u->ship) skill += u->ship->type->at_bonus; - } else { - skill += u->race->df_bonus; - if (fval(u->region->terrain, SEA_REGION) && u->ship) skill += u->ship->type->df_bonus; - } - } else { - /* changed: if we own a weapon, we have at least a skill of 0 */ - if (!i_canuse(u, wtype->itype)) return -1; - skill = effskill(u, wtype->skill); - if (skill < wtype->minskill) skill = 0; - if (skill > 0) { - if (attacking) { - skill += u->race->at_bonus; - } else { - skill += u->race->df_bonus; - } - } - if (attacking) { - skill += wtype->offmod; - } else { - skill += wtype->defmod; - } - } - - return skill; -} - -static int CavalrySkill(void) -{ - static int skill = -1; - - if (skill<0) { - skill = get_param_int(global.parameters, "rules.cavalry.skill", 2); - } - return skill; -} - -#define BONUS_SKILL 1 -#define BONUS_DAMAGE 2 -static int -CavalryBonus(const unit * u, troop enemy, int type) -{ - static int mode = -1; - - if (mode<0) { - mode = get_param_int(global.parameters, "rules.cavalry.mode", 1); - } - if (mode==0) { - /* old rule, Eressea 1.0 compat */ - return (type==BONUS_SKILL)?2:0; - } else { - /* new rule, chargers in Eressea 1.1 */ - int skl = effskill(u, SK_RIDING); - /* only half against trolls */ - if (skl>0) { - if (type==BONUS_DAMAGE) { - int dmg = MIN(skl, 8); - if (enemy.fighter->unit->race==new_race[RC_TROLL]) { - dmg = dmg/4; - } else { - dmg = dmg/2; - } - return dmg; - } else { - skl = skl/2; - return MIN(skl, 4); - } - } - } - return 0; -} - -static int -weapon_effskill(troop t, troop enemy, const weapon * w, boolean attacking, boolean missile) - /* effektiver Waffenskill während des Kampfes */ -{ - /* In dieser Runde alle die Modifier berechnen, die fig durch die - * Waffen bekommt. */ - fighter * tf = t.fighter; - unit * tu = t.fighter->unit; - int skill; - const weapon_type * wtype = w?w->type:NULL; - - if (wtype==NULL) { - /* Ohne Waffe: Waffenlose Angriffe */ - skill = weapon_skill(NULL, tu, attacking); - } else { - if (attacking) { - skill = w->attackskill; - } else { - skill = w->defenseskill; - } - if (wtype->modifiers!=NULL) { - /* Pferdebonus, Lanzenbonus, usw. */ - int m; - unsigned int flags = WMF_SKILL|(attacking?WMF_OFFENSIVE:WMF_DEFENSIVE); - - if (is_riding(t)) flags |= WMF_RIDING; - else flags |= WMF_WALKING; - if (is_riding(enemy)) flags |= WMF_AGAINST_RIDING; - else flags |= WMF_AGAINST_WALKING; - - for (m=0;wtype->modifiers[m].value;++m) { - if ((wtype->modifiers[m].flags & flags) == flags) { - race_list * rlist = wtype->modifiers[m].races; - if (rlist!=NULL) { - while (rlist) { - if (rlist->data == tu->race) break; - rlist = rlist->next; - } - if (rlist==NULL) continue; - } - skill += wtype->modifiers[m].value; - } - } - } - } - - /* Burgenbonus, Pferdebonus */ - if (is_riding(t) && (wtype==NULL || (fval(wtype, WTF_HORSEBONUS) && !fval(wtype, WTF_MISSILE)))) { - skill += CavalryBonus(tu, enemy, BONUS_SKILL); - if (wtype) skill = skillmod(urace(tu)->attribs, tu, tu->region, wtype->skill, skill, SMF_RIDING); - } - - if (t.indexelvenhorses) { - /* Elfenpferde: Helfen dem Reiter, egal ob und welche Waffe. Das ist - * eleganter, und vor allem einfacher, sonst muß man noch ein - * WMF_ELVENHORSE einbauen. */ - skill += 2; - } - - if (skill>0 && !attacking && missile) { - /* - * Wenn ich verteidige, und nicht direkt meinem Feind gegenüberstehe, - * halbiert sich mein Skill: (z.B. gegen Fernkämpfer. Nahkämpfer - * können mich eh nicht treffen) - */ - skill /= 2; - } - return skill; -} - -static const armor_type * -select_armor(troop t, boolean shield) -{ - unsigned int type = shield?ATF_SHIELD:0; - unit * u = t.fighter->unit; - const armor * a = t.fighter->armors; - int geschuetzt = 0; - - /* some monsters should not use armor (dragons in chainmail? ha!) */ - if (!(u->race->battle_flags & BF_EQUIPMENT)) - return NULL; - - /* ... neither do werewolves */ - if (fval(u, UFL_WERE)) { - return NULL; - } - - for (;a;a=a->next) { - if ((a->atype->flags & ATF_SHIELD)==type) { - geschuetzt += a->count; - if (geschuetzt > t.index) { - /* unser Kandidat wird geschuetzt */ - return a->atype; - } - } - } - return NULL; -} - - -/* Hier ist zu beachten, ob und wie sich Zauber und Artefakte, die - * Rüstungschutz geben, addieren. - * - Artefakt I_TROLLBELT gibt Rüstung +1 - * - Zauber Rindenhaut gibt Rüstung +3 - */ -int -select_magicarmor(troop t) -{ - unit *u = t.fighter->unit; - int geschuetzt = 0; - int ma = 0; - - geschuetzt = MIN(get_item(u, I_TROLLBELT), u->number); - - if (geschuetzt > t.index) /* unser Kandidat wird geschuetzt */ - ma += 1; - - return ma; -} - -/* Sind side ds und Magier des meffect verbündet, dann return 1*/ -boolean -meffect_protection(battle * b, meffect * s, side * ds) -{ - if (!s->magician->alive) return false; - if (s->duration <= 0) return false; - if (enemy(s->magician->side, ds)) return false; - if (allysf(s->magician->side, ds->faction)) return true; - return false; -} - -/* Sind side as und Magier des meffect verfeindet, dann return 1*/ -boolean -meffect_blocked(battle *b, meffect *s, side *as) -{ - if (!s->magician->alive) return false; - if (s->duration <= 0) return false; - if (enemy(s->magician->side, as)) return true; - return false; -} - -/* rmfighter wird schon im PRAECOMBAT gebraucht, da gibt es noch keine - * troops */ -void -rmfighter(fighter *df, int i) -{ - side *ds = df->side; - - /* nicht mehr personen abziehen, als in der Einheit am Leben sind */ - assert(df->alive >= i); - assert(df->alive <= df->unit->number); - - /* erst ziehen wir die Anzahl der Personen von den Kämpfern in der - * Schlacht, dann von denen auf dieser Seite ab*/ - df->side->alive -= i; - df->side->battle->alive -= i; - - /* Dann die Kampfreihen aktualisieren */ - ds->size[SUM_ROW] -= i; - ds->size[statusrow(df->status)] -= i; - - /* Spezialwirkungen, z.B. Schattenritter */ - if (df->unit->race->battle_flags & BF_NOBLOCK) { - ds->nonblockers[SUM_ROW] -= i; - ds->nonblockers[statusrow(df->status)] -= i; - } - - /* und die Einheit selbst aktualisieren */ - df->alive -= i; -} - - -static void -rmtroop(troop dt) -{ - fighter *df = dt.fighter; - - /* troop ist immer eine einzele Person */ - rmfighter(df, 1); - - assert(dt.index >= 0 && dt.index < df->unit->number); - df->person[dt.index] = df->person[df->alive - df->removed]; - if (df->removed) { - df->person[df->alive - df->removed] = df->person[df->alive]; - } - df->person[df->alive].hp = 0; -} - -void -remove_troop(troop dt) -{ - fighter * df = dt.fighter; - struct person p = df->person[dt.index]; - battle * b = df->side->battle; -#ifdef FASTCOUNT - b->fast.alive = -1; /* invalidate cached value */ -#endif -#ifdef FASTROW - b->rowcache.alive = -1; /* invalidate cached value */ -#endif - ++df->removed; - ++df->side->removed; - df->person[dt.index] = df->person[df->alive-df->removed]; - df->person[df->alive - df->removed] = p; -} - -void -kill_troop(troop dt) -{ - fighter * df = dt.fighter; - unit * du = df->unit; - - rmtroop(dt); - if (!df->alive) { - char eqname[64]; - const struct equipment * eq; - if (du->race->itemdrop) { - item * drops = du->race->itemdrop(du->race, du->number-df->run.number); - - if (drops != NULL){ - i_merge(&du->items, &drops); - } - } - sprintf(eqname, "%s_spoils", du->race->_name[0]); - eq = get_equipment(eqname); - if (eq!=NULL) { - equip_items(&du->items, eq); - } - } -} - -/** reduces the target's exp by an equivalent of n points learning - * 30 points = 1 week - */ -void -drain_exp(struct unit *u, int n) -{ - skill_t sk = (skill_t)(rng_int() % MAXSKILLS); - skill_t ssk; - - ssk = sk; - - while (get_level(u, sk)==0) { - sk++; - if (sk == MAXSKILLS) - sk = 0; - if (sk == ssk) { - sk = NOSKILL; - break; - } - } - if (sk != NOSKILL) { - skill * sv = get_skill(u, sk); - while (n>0) { - if (n>=30*u->number) { - reduce_skill(u, sv, 1); - n-=30; - } else { - if (rng_int()%(30*u->number) 0.75) { - return "eine klaffende Wunde"; - } else if (q > 0.5) { - return "eine schwere Wunde"; - } else if (q > 0.25) { - return "eine Wunde"; - } - return "eine kleine Wunde"; -} - -static void vampirism(troop at, int damage) -{ - static int vampire = -1; - if (vampire<0) vampire = get_param_int(global.parameters, "rules.combat.demon_vampire", 0); - if (vampire>0) { - int gain = damage/vampire; - int chance = damage - vampire * gain; - if (chance>0 && (rng_int() % vampire < chance)) ++gain; - if (gain>0) { - int maxhp = unit_max_hp(at.fighter->unit); - at.fighter->person[at.index].hp = MIN(gain+at.fighter->person[at.index].hp, maxhp); - } - } -} - -static int -natural_armor(unit * du) -{ - static int * bonus = 0; - int an = du->race->armor; - if (bonus==0) { - bonus = calloc(sizeof(int), num_races); - } - if (bonus[du->race->index]==0) { - bonus[du->race->index] = get_param_int(du->race->parameters, "armor.stamina", -1); - if (bonus[du->race->index]==0) bonus[du->race->index] = -1; - } - if (bonus[du->race->index]>0) { - int sk = effskill(du, SK_STAMINA); - sk /= bonus[du->race->index]; - an += sk; - } - return an; -} - -boolean -terminate(troop dt, troop at, int type, const char *damage, boolean missile) -{ - item ** pitm; - fighter *df = dt.fighter; - fighter *af = at.fighter; - unit *au = af->unit; - unit *du = df->unit; - battle *b = df->side->battle; - int heiltrank = 0; - static int rule_armor = -1; - - /* Schild */ - void **si; - side *ds = df->side; - int hp; - - int ar = 0, an, am; - const armor_type * armor = select_armor(dt, true); - const armor_type * shield = select_armor(dt, false); - - const weapon_type *dwtype = NULL; - const weapon_type *awtype = NULL; - const weapon * weapon; - - int rda, sk = 0, sd; - boolean magic = false; - int da = dice_rand(damage); - - assert(du->number>0); -#ifdef SHOW_KILLS - ++at.fighter->hits; -#endif - - switch (type) { - case AT_STANDARD: - weapon = select_weapon(at, true, missile); - sk = weapon_effskill(at, dt, weapon, true, missile); - if (weapon) awtype = weapon->type; - if (awtype && fval(awtype, WTF_MAGICAL)) magic = true; - break; - case AT_NATURAL: - sk = weapon_effskill(at, dt, NULL, true, missile); - break; - case AT_SPELL: - case AT_COMBATSPELL: - magic = true; - break; - default: - break; - } - weapon = select_weapon(dt, false, true); /* missile=true to get the unmodified best weapon she has */ - sd = weapon_effskill(dt, at, weapon, false, false); - if (weapon!=NULL) dwtype=weapon->type; - - if (is_riding(at) && (awtype==NULL || (fval(awtype, WTF_HORSEBONUS) && !fval(awtype, WTF_MISSILE)))) { - da += CavalryBonus(au, dt, BONUS_DAMAGE); - } - - if (armor) { - ar += armor->prot; - if (armor->projectile>0 && chance(armor->projectile)) { - return false; - } - } - if (shield) { - ar += shield->prot; - if (shield->projectile>0 && chance(shield->projectile)) { - return false; - } - } - - /* natürliche Rüstung */ - an = natural_armor(du); - - /* magische Rüstung durch Artefakte oder Sprüche */ - /* Momentan nur Trollgürtel und Werwolf-Eigenschaft */ - am = select_magicarmor(dt); - -#if CHANGED_CROSSBOWS - if (awtype && fval(awtype, WTF_ARMORPIERCING)) { - /* crossbows */ - ar /= 2; - an /= 2; - } -#endif - - if (rule_armor<0) { - rule_armor = get_param_int(global.parameters, "rules.combat.nat_armor", 0); - } - if (rule_armor==0) { - /* natürliche Rüstung ist halbkumulativ */ - if (ar>0) { - ar += an/2; - } else { - ar = an; - } - } else { - /* use the higher value, add half the other value */ - ar = (ar>an)?(ar+an/2):(an+ar/2); - } - ar += am; - - if (type!=AT_COMBATSPELL && type!=AT_SPELL) { - if (damage_rules&DAMAGE_CRITICAL) { - double kritchance = (sk * 3 - sd) / 200.0; - - kritchance = MAX(kritchance, 0.005); - kritchance = MIN(0.9, kritchance); - - while (chance(kritchance)) { - if (bdebug) { - fprintf(bdebug, "%s/%d lands a critical hit\n", unitid(au), at.index); - } - da += dice_rand(damage); - } - } - - da += rc_specialdamage(au->race, du->race, awtype); - - if (awtype!=NULL && fval(awtype, WTF_MISSILE)) { - /* missile weapon bonus */ - if (damage_rules&DAMAGE_MISSILE_BONUS) { - da += af->person[at.index].damage_rear; - } - } else if (awtype==NULL) { - /* skill bonus for unarmed combat */ - if (damage_rules&DAMAGE_UNARMED_BONUS) { - da += effskill(au, SK_WEAPONLESS); - } - } else { - /* melee bonus */ - if (damage_rules&DAMAGE_MELEE_BONUS) { - da += af->person[at.index].damage; - } - } - - /* Skilldifferenzbonus */ - if (damage_rules&DAMAGE_SKILL_BONUS) { - da += MAX(0, (sk-sd)/DAMAGE_QUOTIENT); - } - } - - - if (magic) { - /* Magischer Schaden durch Spruch oder magische Waffe */ - double res = 1.0; - - /* magic_resistance gib x% Resistenzbonus zurück */ - res -= magic_resistance(du)*3.0; - - if (du->race->battle_flags & BF_EQUIPMENT) { -#ifdef TODO_RUNESWORD - /* Runenschwert gibt im Kampf 80% Resistenzbonus */ - if (dwp == WP_RUNESWORD) res -= 0.80; -#endif - /* der Effekt von Laen steigt nicht linear */ - if (armor && fval(armor, ATF_LAEN)) res *= (1-armor->magres); - if (shield && fval(shield, ATF_LAEN)) res *= (1-shield->magres); - if (dwtype) res *= (1-dwtype->magres); - } - - if (res > 0) { - da = (int) (MAX(da * res, 0)); - } - /* gegen Magie wirkt nur natürliche und magische Rüstung */ - ar = an+am; - } - - rda = MAX(da - ar,0); - - if ((du->race->battle_flags & BF_INV_NONMAGIC) && !magic) rda = 0; - else { - unsigned int i = 0; - if (du->race->battle_flags & BF_RES_PIERCE) i |= WTF_PIERCE; - if (du->race->battle_flags & BF_RES_CUT) i |= WTF_CUT; - if (du->race->battle_flags & BF_RES_BASH) i |= WTF_BLUNT; - - if (i && awtype && fval(awtype, i)) rda /= 2; - - /* Schilde */ - for (si = b->meffects.begin; si != b->meffects.end; ++si) { - meffect *meffect = *si; - if (meffect_protection(b, meffect, ds) != 0) { - assert(0 <= rda); /* rda sollte hier immer mindestens 0 sein */ - /* jeder Schaden wird um effect% reduziert bis der Schild duration - * Trefferpunkte aufgefangen hat */ - if (meffect->typ == SHIELD_REDUCE) { - hp = rda * (meffect->effect/100); - rda -= hp; - meffect->duration -= hp; - } - /* gibt Rüstung +effect für duration Treffer */ - if (meffect->typ == SHIELD_ARMOR) { - rda = MAX(rda - meffect->effect, 0); - meffect->duration--; - } - } - } - } - - assert(dt.indexnumber); - df->person[dt.index].hp -= rda; - if (au->race==new_race[RC_DAEMON]) { - vampirism(at, rda); - } - - if (df->person[dt.index].hp > 0) { /* Hat überlebt */ - if (bdebug) { - fprintf(bdebug, "Damage %d, armor %d: %d -> %d HP\n", - da, ar, df->person[dt.index].hp + rda, df->person[dt.index].hp); - } - if (au->race == new_race[RC_DAEMON]) { -#ifdef TODO_RUNESWORD - if (select_weapon(dt, 0, -1) == WP_RUNESWORD) continue; -#endif - if (!(df->person[dt.index].flags & (FL_COURAGE|FL_DAZZLED))) { - df->person[dt.index].flags |= FL_DAZZLED; - df->person[dt.index].defence--; - } - } - df->person[dt.index].flags = (df->person[dt.index].flags & ~FL_SLEEPING); - return false; - } - - /* Sieben Leben */ - if (du->race == new_race[RC_CAT] && (chance(1.0 / 7))) { - assert(dt.index>=0 && dt.indexnumber); - df->person[dt.index].hp = unit_max_hp(du); - return false; - } - - /* Heiltrank schluerfen und hoffen */ - if (oldpotiontype[P_HEAL]) { - if (get_effect(du, oldpotiontype[P_HEAL]) > 0) { - change_effect(du, oldpotiontype[P_HEAL], -1); - heiltrank = 1; - } else if (i_get(du->items, oldpotiontype[P_HEAL]->itype) > 0) { - i_change(&du->items, oldpotiontype[P_HEAL]->itype, -1); - change_effect(du, oldpotiontype[P_HEAL], 3); - heiltrank = 1; - } - if (heiltrank && (chance(0.50))) { - { - message * m = msg_message("battle::potionsave", "unit", du); - message_faction(b, du->faction, m); - msg_release(m); - } - assert(dt.index>=0 && dt.indexnumber); - df->person[dt.index].hp = du->race->hitpoints; - return false; - } - } -#ifdef SHOW_KILLS - ++at.fighter->kills; -#endif - - if (bdebug) { - fprintf(bdebug, "Damage %d, armor %d, type %d: %d -> %d HP, tot.\n", - da, ar, type, df->person[dt.index].hp + rda, df->person[dt.index].hp); - } - for (pitm=&du->items; *pitm; ) { - item * itm = *pitm; - const item_type * itype = itm->type; - if (!(itype->flags & ITF_CURSED) && dt.index < itm->number) { - /* 25% Grundchance, das ein Item kaputtgeht. */ - if (rng_int() % 4 < 1) { - i_change(pitm, itype, -1); - } - } - if (*pitm==itm) { - pitm = &itm->next; - } - } - kill_troop(dt); - - return true; -} - -static int -count_side(const side * s, const side * vs, int minrow, int maxrow, int select) -{ - fighter * fig; - int people = 0; - int unitrow[NUMROWS]; - - if (maxrowfighters; fig; fig = fig->next) { - if (fig->alive - fig->removed > 0) { - int row = statusrow(fig->status); - if (select&SELECT_ADVANCE) { - if (unitrow[row] == -1) { - unitrow[row] = get_unitrow(fig, vs); - } - row = unitrow[row]; - } - if (row >= minrow && row <= maxrow) { - people += fig->alive - fig->removed; - if (people>0 && (select&SELECT_FIND)) break; - } - } - } - return people; -} - -/* return the number of live allies warning: this function only considers -* troops that are still alive, not those that are still fighting although -* dead. */ -int -count_allies(const side * as, int minrow, int maxrow, int select, int allytype) -{ - battle *b = as->battle; - side *ds; - int count = 0; - - for (ds=b->sides;ds!=b->sides+b->nsides;++ds) { - if ((allytype==ALLY_ANY && helping(as, ds)) || (allytype==ALLY_SELF && as->faction==ds->faction)) { - count += count_side(ds, NULL, minrow, maxrow, select); - if (count>0 && (select&SELECT_FIND)) break; - } - } - return count; -} - -static int -count_enemies_i(battle * b, const fighter * af, int minrow, int maxrow, int select) -{ - side *es, *as = af->side; - int i = 0; - - for (es=b->sides;es!=b->sides+b->nsides;++es) { - if (as==NULL || enemy(es, as)) { - int offset = 0; - if (select&SELECT_DISTANCE) { - offset = get_unitrow(af, es) - FIGHT_ROW; - } - i += count_side(es, as, minrow-offset, maxrow-offset, select); - if (i>0 && (select&SELECT_FIND)) break; - } - } - return i; -} - -int -count_enemies(battle * b, const fighter * af, int minrow, int maxrow, int select) -{ -#ifdef FASTCOUNT - int sr = statusrow(af->status); - side *as = af->side; - - if (b->alive==b->fast.alive && as==b->fast.side && sr==b->fast.status && minrow==b->fast.minrow && maxrow==b->fast.maxrow) { - if (b->fast.enemies[select]>=0) { -#ifdef DEBUG_FAST - int i = count_enemies_i(b, af, minrow, maxrow, select); - assert(i==b->fast.enemies[select]); -#endif - return b->fast.enemies[select]; - } else if (select&SELECT_FIND) { - if (b->fast.enemies[select-SELECT_FIND]>=0) { -#ifdef DEBUG_FAST - int i = count_enemies_i(b, af, minrow, maxrow, select); - assert((i>0)==(b->fast.enemies[select-SELECT_FIND]>0)); -#endif - return b->fast.enemies[select-SELECT_FIND]; - } - } - } else if (select!=SELECT_FIND || b->alive!=b->fast.alive) { - b->fast.side = as; - b->fast.status = sr; - b->fast.minrow = minrow; - b->fast.alive=b->alive; - b->fast.maxrow = maxrow; - memset(b->fast.enemies, -1, sizeof(b->fast.enemies)); - } -#endif - if (maxrow>=FIRST_ROW) { - int i = count_enemies_i(b, af, minrow, maxrow, select); -#ifdef FASTCOUNT - b->fast.enemies[select] = i; -#endif - return i; - } - return 0; -} - -troop -select_enemy(fighter * af, int minrow, int maxrow, int select) -{ - side *as = af->side; - battle * b = as->battle; - int si, selected; - int enemies; -#ifdef DEBUG_SELECT - troop result = no_troop; -#endif - if (af->unit->race->flags & RCF_FLY) { - /* flying races ignore min- and maxrow and can attack anyone fighting - * them */ - minrow = FIGHT_ROW; - maxrow = BEHIND_ROW; - } - minrow = MAX(minrow, FIGHT_ROW); - - enemies = count_enemies(b, af, minrow, maxrow, select); - - /* Niemand ist in der angegebenen Entfernung? */ - if (enemies<=0) return no_troop; - - selected = rng_int() % enemies; - for (si=0;as->enemies[si];++si) { - side *ds = as->enemies[si]; - fighter * df; - int unitrow[NUMROWS]; - int offset = 0; - - if (select&SELECT_DISTANCE) offset = get_unitrow(af, ds) - FIGHT_ROW; - - if (select&SELECT_ADVANCE) { - int ui; - for (ui=0;ui!=NUMROWS;++ui) unitrow[ui] = -1; - } - - for (df=ds->fighters; df ; df = df->next) { - int dr; - - dr = statusrow(df->status); - if (select&SELECT_ADVANCE) { - if (unitrow[dr]<0) { - unitrow[dr] = get_unitrow(df, as); - } - dr = unitrow[dr]; - } - - if (select&SELECT_DISTANCE) dr += offset; - if (dr < minrow || dr > maxrow) continue; - if (df->alive - df->removed > selected) { -#ifdef DEBUG_SELECT - if (result.fighter==NULL) { - result.index = selected; - result.fighter = df; - } -#else - troop dt; - dt.index = selected; - dt.fighter = df; - return dt; -#endif - } - selected -= (df->alive - df->removed); - enemies -= (df->alive - df->removed); - } - } - if (enemies!=0) { - log_error(("select_enemies has a bug.\n")); - } -#ifdef DEBUG_SELECT - return result; -#else - assert(!selected); - return no_troop; -#endif -} - -static int -get_tactics(const side * as, const side * ds) -{ - battle * b = as->battle; - side *stac; - int result = 0; - int defense = 0; - - if (b->max_tactics > 0) { - for (stac=b->sides;stac!=b->sides+b->nsides;++stac) { - if (stac->leader.value > result && helping(stac, as)) { - assert(ds==NULL || !helping(stac, ds)); - result = stac->leader.value; - } - if (ds && stac->leader.value > defense && helping(stac, ds)) { - assert(!helping(stac, as)); - defense = stac->leader.value; - } - } - } - return result - defense; -} - -static troop -select_opponent(battle * b, troop at, int mindist, int maxdist) -{ - fighter * af = at.fighter; - troop dt; - - if (af->unit->race->flags & RCF_FLY) { - /* flying races ignore min- and maxrow and can attack anyone fighting - * them */ - dt = select_enemy(at.fighter, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); - } else { - mindist = MAX(mindist, FIGHT_ROW); - dt = select_enemy(at.fighter, mindist, maxdist, SELECT_ADVANCE); - } - - if (b->turn==0 && dt.fighter) { - int tactics_formula = -1; - - if (tactics_formula<0) { - tactics_formula = get_param_int(global.parameters, "rules.tactics.formula", 0); - } - if (tactics_formula==1) { - int tactics = get_tactics(at.fighter->side, dt.fighter->side); - - /* percentage chance to get this attack */ - if (tactics>0) { - double tacch = 0.1 * tactics; - if (fval(b->region->terrain, SEA_REGION)) { - ship * sh = at.fighter->unit->ship; - if (sh) tacch *= sh->type->tac_bonus; - } - if (!chance(tacch)) { - dt.fighter = NULL; - } - } else { - dt.fighter = NULL; - } - } - } - - return dt; -} - -/* - * Abfrage mit - * - * cvector *fgs=fighters(b,af,FIGHT_ROW,BEHIND_ROW, FS_HELP|FS_ENEMY); - * fighter *fig; - * - * Optional: Verwirbeln. Vorsicht: Aufwändig! - * v_scramble(fgs->begin, fgs->end); - * - * for (fig = fgs->begin; fig != fgs->end; ++fig) { - * fighter *df = *fig; - * - * } - * - * cv_kill(fgs); free(fgs); Nicht vergessen - */ - -cvector * -fighters(battle *b, const side * vs, int minrow, int maxrow, int mask) -{ - side * s; - cvector *fightervp = malloc(sizeof(cvector)); - - assert(vs!=NULL); - cv_init(fightervp); - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter *fig; - - if (mask==FS_ENEMY) { - if (!enemy(s, vs)) continue; - } else if (mask==FS_HELP) { - if (enemy(s, vs) || !allysf(s, vs->faction)) { - continue; - } - } else { - assert(mask==(FS_HELP|FS_ENEMY) || !"invalid alliance state"); - } - for (fig = s->fighters; fig; fig = fig->next) { - int row = get_unitrow(fig, vs); - if (row >= minrow && row <= maxrow) { - cv_pushback(fightervp, fig); - } - } - } - - return fightervp; -} - -static void -report_failed_spell(battle * b, unit * mage, const spell * sp) -{ - message * m = msg_message("battle::spell_failed", "unit spell", mage, sp); - message_all(b, m); - msg_release(m); -} - -void -do_combatmagic(battle *b, combatmagic_t was) -{ - side * s; - region *r = b->region; - castorder *co; - int level, rank, sl; - spellrank spellranks[MAX_SPELLRANK]; - - memset(spellranks, 0, sizeof(spellranks)); - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter * fig; - for (fig = s->fighters; fig; fig = fig->next) { - unit * mage = fig->unit; - - if (fig->alive <= 0) continue; /* fighter kann im Kampf getötet worden sein */ - - level = eff_skill(mage, SK_MAGIC, r); - if (level > 0) { - double power; - const spell *sp; - const struct locale * lang = mage->faction->locale; - order * ord; - - switch(was) { - case DO_PRECOMBATSPELL: - sp = get_combatspell(mage, 0); - sl = get_combatspelllevel(mage, 0); - break; - case DO_POSTCOMBATSPELL: - sp = get_combatspell(mage, 2); - sl = get_combatspelllevel(mage, 2); - break; - default: - /* Fehler! */ - return; - } - if (sp == NULL) - continue; - - ord = create_order(K_CAST, lang, "'%s'", spell_name(sp, lang)); - if (cancast(mage, sp, 1, 1, ord) == false) { - free_order(ord); - continue; - } - - level = eff_spelllevel(mage, sp, level, 1); - if (sl > 0) level = MIN(sl, level); - if (level < 0) { - report_failed_spell(b, mage, sp); - free_order(ord); - continue; - } - - power = spellpower(r, mage, sp, level, ord); - free_order(ord); - if (power <= 0) { /* Effekt von Antimagie */ - report_failed_spell(b, mage, sp); - pay_spell(mage, sp, level, 1); - } else if (fumble(r, mage, sp, sp->level) == true) { - report_failed_spell(b, mage, sp); - pay_spell(mage, sp, level, 1); - } else { - co = new_castorder(fig, 0, sp, r, level, power, 0, 0, 0); - add_castorder(&spellranks[sp->rank], co); - } - } - } - } - for (rank = 0; rank < MAX_SPELLRANK; rank++) { - for (co = spellranks[rank].begin; co; co = co->next) { - fighter * fig = co->magician.fig; - const spell * sp = co->sp; - int level = co->level; - double power = co->force; - - if (sp->sp_function==NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); - } else { - level = ((cspell_f)sp->sp_function)(fig, level, power, sp); - if (level > 0) { - pay_spell(fig->unit, sp, level, 1); - } - } - } - } - for (rank = 0; rank < MAX_SPELLRANK; rank++) { - free_castorders(spellranks[rank].begin); - } -} - -static void -combat_action(fighter * af, int turn) -{ -#ifndef SIMPLE_COMBAT - af->action_counter++; - af->side->bf->lastturn = turn; -#endif -} - - -static void -do_combatspell(troop at) -{ - const spell *sp; - fighter *fi = at.fighter; - unit *mage = fi->unit; - battle *b = fi->side->battle; - region *r = b->region; - int level; - double power; - int fumblechance = 0; - void **mg; - order * ord; - int sl; - const struct locale * lang = mage->faction->locale; - - sp = get_combatspell(mage, 1); - if (sp == NULL) { - fi->magic = 0; /* Hat keinen Kampfzauber, kämpft nichtmagisch weiter */ - return; - } - ord = create_order(K_CAST, lang, "'%s'", spell_name(sp, lang)); - if (cancast(mage, sp, 1, 1, ord) == false) { - fi->magic = 0; /* Kann nicht mehr Zaubern, kämpft nichtmagisch weiter */ - return; - } - - level = eff_spelllevel(mage, sp, fi->magic, 1); - if ((sl = get_combatspelllevel(mage, 1)) > 0) level = MIN(level, sl); - - if (fumble(r, mage, sp, sp->level) == true) { - report_failed_spell(b, mage, sp); - pay_spell(mage, sp, level, 1); - return; - } - - for (mg = b->meffects.begin; mg != b->meffects.end; ++mg) { - meffect *mblock = *mg; - if (mblock->typ == SHIELD_BLOCK) { - if (meffect_blocked(b, mblock, fi->side) != 0) { - fumblechance += mblock->duration; - mblock->duration -= mblock->effect; - } - } - } - - /* Antimagie die Fehlschlag erhöht */ - if (rng_int()%100 < fumblechance) { - report_failed_spell(b, mage, sp); - pay_spell(mage, sp, level, 1); - free_order(ord); - return; - } - power = spellpower(r, mage, sp, level, ord); - free_order(ord); - if (power <= 0) { /* Effekt von Antimagie */ - report_failed_spell(b, mage, sp); - pay_spell(mage, sp, level, 1); - return; - } - - if (sp->sp_function==NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); - } else { - level = ((cspell_f)sp->sp_function)(fi, level, power, sp); - if (level > 0) { - pay_spell(mage, sp, level, 1); - combat_action(at.fighter, b->turn); - } - } -} - - -/* Sonderattacken: Monster patzern nicht und zahlen auch keine - * Spruchkosten. Da die Spruchstärke direkt durch den Level bestimmt - * wird, wirkt auch keine Antimagie (wird sonst in spellpower - * gemacht) */ - -static void -do_extra_spell(troop at, const att *a) -{ - const spell *sp = a->data.sp; - fighter *fi = at.fighter; - double power; - - power = sp->level * MagicPower(); - if (sp->sp_function==NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); - } else { - ((cspell_f)sp->sp_function)(fi, sp->level, power, sp); - } -} - -static int -skilldiff(troop at, troop dt, int dist) -{ - fighter *af = at.fighter, *df = dt.fighter; - unit *au = af->unit, *du = df->unit; - int is_protected = 0, skdiff = 0; - weapon * awp = select_weapon(at, true, dist>1); - - skdiff += af->person[at.index].attack; - skdiff -= df->person[dt.index].defence; - - if (df->person[dt.index].flags & FL_SLEEPING) - skdiff += 2; - - /* Effekte durch Rassen */ - if (awp!=NULL && au->race == new_race[RC_HALFLING] && dragonrace(du->race)) { - skdiff += 5; - } - - if (au->race == new_race[RC_GOBLIN]) { - static int goblin_bonus = -1; - if (goblin_bonus<0) goblin_bonus = get_param_int(global.parameters, "rules.combat.goblinbonus", 10); - if (af->side->size[SUM_ROW] >= df->side->size[SUM_ROW] * goblin_bonus) { - skdiff += 1; - } - } - - if (df->building) { - boolean init = false; - static const curse_type * strongwall_ct, * magicwalls_ct; - if (!init) { - strongwall_ct = ct_find("strongwall"); - magicwalls_ct = ct_find("magicwalls"); - init=true; - } - if (df->building->type->protection) { - int beff = df->building->type->protection(df->building, du); - if (beff) { - skdiff -= beff; - is_protected = 2; - } - } - if (strongwall_ct) { - curse * c = get_curse(df->building->attribs, strongwall_ct); - if (curse_active(c)) { - /* wirkt auf alle Gebäude */ - skdiff -= curse_geteffect_int(c); - is_protected = 2; - } - } - if (magicwalls_ct && curse_active(get_curse(df->building->attribs, magicwalls_ct))) { - /* Verdoppelt Burgenbonus */ - skdiff -= buildingeffsize(df->building, false); - } - } - /* Goblin-Verteidigung - * ist direkt in der Rassentabelle als df_default - */ - - /* Effekte der Waffen */ - skdiff += weapon_effskill(at, dt, awp, true, dist>1); - if (awp && fval(awp->type, WTF_MISSILE)) { - skdiff -= is_protected; - if (awp->type->modifiers) { - int w; - for (w=0;awp->type->modifiers[w].value!=0;++w) { - if (awp->type->modifiers[w].flags & WMF_MISSILE_TARGET) { - /* skill decreases by targeting difficulty (bow -2, catapult -4) */ - skdiff -= awp->type->modifiers[w].value; - break; - } - } - } - } - if (skill_formula==FORMULA_ORIG) { - weapon * dwp = select_weapon(dt, false, dist>1); - skdiff -= weapon_effskill(dt, at, dwp, false, dist>1); - } - return skdiff; -} - -static int -setreload(troop at) -{ - fighter * af = at.fighter; - const weapon_type * wtype = af->person[at.index].missile->type; - if (wtype->reload == 0) return 0; - return af->person[at.index].reload = wtype->reload; -} - -int -getreload(troop at) -{ - return at.fighter->person[at.index].reload; -} - -static void -debug_hit(troop at, const weapon * awp, troop dt, const weapon * dwp, int skdiff, int dist, boolean success) -{ - fprintf(bdebug, "%.4s/%d [%6s/%d] %s %.4s/%d [%6s/%d] with %d, distance %d\n", - unitid(at.fighter->unit), at.index, - LOC(default_locale, awp ? resourcename(awp->type->itype->rtype, 0) : "unarmed"), - weapon_effskill(at, dt, awp, true, dist>1), - success?"hits":"misses", - unitid(dt.fighter->unit), dt.index, - LOC(default_locale, dwp ? resourcename(dwp->type->itype->rtype, 0) : "unarmed"), - weapon_effskill(dt, at, dwp, false, dist>1), - skdiff, dist); -} - -int -hits(troop at, troop dt, weapon * awp) -{ - fighter *af = at.fighter, *df = dt.fighter; - const armor_type * armor, * shield = 0; - int skdiff = 0; - int dist = get_unitrow(af, df->side) + get_unitrow(df, af->side) - 1; - weapon * dwp = select_weapon(dt, false, dist>1); - - if (!df->alive) return 0; - if (getreload(at)) return 0; - if (dist>1 && (awp == NULL || !fval(awp->type, WTF_MISSILE))) return 0; - - /* mark this person as hit. */ - df->person[dt.index].flags |= FL_HIT; - - if (af->person[at.index].flags & FL_STUNNED) { - af->person[at.index].flags &= ~FL_STUNNED; - return 0; - } - if ((af->person[at.index].flags & FL_TIRED && rng_int()%100 < 50) - || (af->person[at.index].flags & FL_SLEEPING)) - return 0; - - /* effect of sp_reeling_arrows combatspell */ - if (af->side->battle->reelarrow && awp && fval(awp->type, WTF_MISSILE) && rng_double() < 0.5) { - return 0; - } - - skdiff = skilldiff(at, dt, dist); - /* Verteidiger bekommt eine Rüstung */ - armor = select_armor(dt, true); - if (dwp==NULL || (dwp->type->flags & WTF_USESHIELD)) { - shield = select_armor(dt, false); - } - if (contest(skdiff, dt, armor, shield)) { - if (bdebug) { - debug_hit(at, awp, dt, dwp, skdiff, dist, true); - } - return 1; - } - if (bdebug) { - debug_hit(at, awp, dt, dwp, skdiff, dist, false); - } - return 0; -} - -void -dazzle(battle *b, troop *td) -{ - /* Nicht kumulativ ! */ - if(td->fighter->person[td->index].flags & FL_DAZZLED) return; - -#ifdef TODO_RUNESWORD - if (td->fighter->weapon[WP_RUNESWORD].count > td->index) { - return; - } -#endif - if (td->fighter->person[td->index].flags & FL_COURAGE) { - return; - } - - if (td->fighter->person[td->index].flags & FL_DAZZLED) { - return; - } - - td->fighter->person[td->index].flags |= FL_DAZZLED; - td->fighter->person[td->index].defence--; -} - -/* TODO: Gebäude/Schiffe sollten auch zerstörbar sein. Schwierig im Kampf, - * besonders bei Schiffen. */ - -void -damage_building(battle *b, building *bldg, int damage_abs) -{ - bldg->size = MAX(1, bldg->size-damage_abs); - - /* Wenn Burg, dann gucken, ob die Leute alle noch in das Gebäude passen. */ - - if (bldg->type->protection) { - side * s; - - bldg->sizeleft = bldg->size; - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter * fig; - for (fig=s->fighters;fig;fig=fig->next) { - if (fig->building == bldg) { - if (bldg->sizeleft >= fig->unit->number) { - fig->building = bldg; - bldg->sizeleft -= fig->unit->number; - } else { - fig->building = NULL; - } - } - } - } - } -} - -static int -attacks_per_round(troop t) -{ - return t.fighter->person[t.index].speed; -} - -static void -make_heroes(battle * b) -{ - side * s; - static int hero_speed = 0; - if (hero_speed==0) { - hero_speed = get_param_int(global.parameters, "rules.combat.herospeed", 10); - } - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter * fig; - for (fig=s->fighters;fig;fig=fig->next) { - unit * u = fig->unit; - if (fval(u, UFL_HERO)) { - int i; - assert(playerrace(u->race)); - for (i=0;i!=u->number;++i) { - fig->person[i].speed += (hero_speed-1); - } - } - } - } -} - -static void -attack(battle *b, troop ta, const att *a, int numattack) -{ - fighter *af = ta.fighter; - troop td; - unit *au = af->unit; - - switch(a->type) { - case AT_COMBATSPELL: - /* Magier versuchen immer erstmal zu zaubern, erst wenn das - * fehlschlägt, wird af->magic == 0 und der Magier kämpft - * konventionell weiter */ - if (numattack==0 && af->magic > 0) { - /* wenn der magier in die potenzielle Reichweite von Attacken des - * Feindes kommt, beginnt er auch bei einem Status von KAEMPFE NICHT, - * Kampfzauber zu schleudern: */ - if (count_enemies(b, af, melee_range[0], missile_range[1], SELECT_ADVANCE|SELECT_DISTANCE|SELECT_FIND)) { - do_combatspell(ta); - } - } - break; - case AT_STANDARD: /* Waffen, mag. Gegenstände, Kampfzauber */ - if (numattack > 0 || af->magic <= 0) { - weapon * wp = ta.fighter->person[ta.index].missile; - int melee = count_enemies(b, af, melee_range[0], melee_range[1], SELECT_ADVANCE|SELECT_DISTANCE|SELECT_FIND); - if (melee) wp = preferred_weapon(ta, true); - /* Sonderbehandlungen */ - - if (getreload(ta)) { - ta.fighter->person[ta.index].reload--; - } else { - boolean standard_attack = true; - boolean reload = false; - /* spezialattacken der waffe nur, wenn erste attacke in der runde. - * sonst helden mit feuerschwertern zu mächtig */ - if (numattack==0 && wp && wp->type->attack) { - int dead = 0; - standard_attack = wp->type->attack(&ta, wp->type, &dead); - if (!standard_attack) reload = true; - af->catmsg += dead; - if (!standard_attack && af->person[ta.index].last_action < b->turn) { - af->person[ta.index].last_action = b->turn; - combat_action(af, b->turn); - } - } - if (standard_attack) { - boolean missile = false; - if (wp && fval(wp->type, WTF_MISSILE)) missile = true; - if (missile) { - td = select_opponent(b, ta, missile_range[0], missile_range[1]); - } - else { - td = select_opponent(b, ta, melee_range[0], melee_range[1]); - } - if (!td.fighter) return; - if (ta.fighter->person[ta.index].last_action < b->turn) { - ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); - } - reload = true; - if (hits(ta, td, wp)) { - const char * d; - if (wp == NULL) d = au->race->def_damage; - else if (is_riding(ta)) d = wp->type->damage[1]; - else d = wp->type->damage[0]; - terminate(td, ta, a->type, d, missile); - } - } - if (reload && wp && wp->type->reload && !getreload(ta)) { - int i = setreload(ta); - if (bdebug) { - fprintf(bdebug, "%s/%d reloading %d turns\n", unitid(au), ta.index, i); - } - } - } - } - break; - case AT_SPELL: /* Extra-Sprüche. Kampfzauber in AT_COMBATSPELL! */ - do_extra_spell(ta, a); - break; - case AT_NATURAL: - td = select_opponent(b, ta, melee_range[0], melee_range[1]); - if (!td.fighter) return; - if(ta.fighter->person[ta.index].last_action < b->turn) { - ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); - } - if (hits(ta, td, NULL)) { - terminate(td, ta, a->type, a->data.dice, false); - } - break; - case AT_DRAIN_ST: - td = select_opponent(b, ta, melee_range[0], melee_range[1]); - if (!td.fighter) return; - if(ta.fighter->person[ta.index].last_action < b->turn) { - ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); - } - if (hits(ta, td, NULL)) { - int c = dice_rand(a->data.dice); - while(c > 0) { - if (rng_int()%2) { - td.fighter->person[td.index].attack -= 1; - } else { - td.fighter->person[td.index].defence -= 1; - } - c--; - } - } - break; - case AT_DRAIN_EXP: - td = select_opponent(b, ta, melee_range[0], melee_range[1]); - if (!td.fighter) return; - if(ta.fighter->person[ta.index].last_action < b->turn) { - ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); - } - if (hits(ta, td, NULL)) { - drain_exp(td.fighter->unit, dice_rand(a->data.dice)); - } - break; - case AT_DAZZLE: - td = select_opponent(b, ta, melee_range[0], melee_range[1]); - if (!td.fighter) return; - if(ta.fighter->person[ta.index].last_action < b->turn) { - ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); - } - if (hits(ta, td, NULL)) { - dazzle(b, &td); - } - break; - case AT_STRUCTURAL: - td = select_opponent(b, ta, melee_range[0], melee_range[1]); - if (!td.fighter) return; - if(ta.fighter->person[ta.index].last_action < b->turn) { - ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); - } - if (td.fighter->unit->ship) { - td.fighter->unit->ship->damage += DAMAGE_SCALE * dice_rand(a->data.dice); - } else if (td.fighter->unit->building) { - damage_building(b, td.fighter->unit->building, dice_rand(a->data.dice)); - } - } -} - -void -do_attack(fighter * af) -{ - troop ta; - unit *au = af->unit; - side *side = af->side; - battle *b = side->battle; - - ta.fighter = af; - - assert(au && au->number); - /* Da das Zuschlagen auf Einheiten und nicht auf den einzelnen - * Kämpfern beruht, darf die Reihenfolge und Größe der Einheit keine - * Rolle spielen, Das tut sie nur dann, wenn jeder, der am Anfang der - * Runde lebte, auch zuschlagen darf. Ansonsten ist der, der zufällig - * mit einer großen Einheit zuerst drankommt, extrem bevorteilt. */ - ta.index = af->fighting; - - while (ta.index--) { - /* Wir suchen eine beliebige Feind-Einheit aus. An der können - * wir feststellen, ob noch jemand da ist. */ - int apr, attacks = attacks_per_round(ta); - if (!count_enemies(b, af, FIGHT_ROW, LAST_ROW, SELECT_FIND)) break; - - for (apr=0;apr!=attacks;++apr) { - int a; - for (a=0; a!=10 && au->race->attack[a].type!=AT_NONE; ++a) { - if (apr>0) { - /* Wenn die Waffe nachladen muss, oder es sich nicht um einen - * Waffen-Angriff handelt, dann gilt der Speed nicht. */ - if (au->race->attack[a].type!=AT_STANDARD) continue; - else { - weapon * wp = preferred_weapon(ta, true); - if (wp!=NULL && wp->type->reload) continue; - } - } - attack(b, ta, &(au->race->attack[a]), apr); - } - } - } - /* Der letzte Katapultschütze setzt die - * Ladezeit neu und generiert die Meldung. */ - if (af->catmsg>=0) { - struct message * m = msg_message("battle::killed", "unit dead", au, af->catmsg); - message_all(b, m); - msg_release(m); - af->catmsg = -1; - } -} - -void -do_regenerate(fighter *af) -{ - troop ta; - unit *au = af->unit; - - ta.fighter = af; - ta.index = af->fighting; - - while(ta.index--) { - af->person[ta.index].hp += effskill(au, SK_STAMINA); - af->person[ta.index].hp = MIN(unit_max_hp(au), af->person[ta.index].hp); - } -} - -static void -add_tactics(tactics * ta, fighter * fig, int value) -{ - if (value == 0 || value < ta->value) - return; - if (value > ta->value) - cv_kill(&ta->fighters); - cv_pushback(&ta->fighters, fig); - cv_pushback(&fig->side->battle->leaders, fig); - ta->value = value; -} - -static double horsebonus(const unit * u) -{ - static const item_type * it_horse = 0; - static const item_type * it_elvenhorse = 0; - static const item_type * it_charger = 0; - region * r = u->region; - int n1 = 0, n2 = 0, n3 = 0; - item * itm = u->items; - int skl = eff_skill(u, SK_RIDING, r); - - if (skl<1) return 0.0; - - if (it_horse==0) { - it_horse = it_find("horse"); - it_elvenhorse = it_find("elvenhorse"); - it_charger = it_find("charger"); - } - - for (;itm;itm=itm->next) { - if (itm->type->flags&ITF_ANIMAL) { - if (itm->type==it_elvenhorse) n3 +=itm->number; - else if (itm->type==it_charger) n2 +=itm->number; - else if (itm->type==it_horse) n1 +=itm->number; - } - } - if (skl >= 5 && n3>=u->number) return 0.30; - if (skl >= 3 && n2+n3>=u->number) return 0.20; - if (skl >= 1 && n1+n2+n3>=u->number) return 0.10; - return 0.0F; -} - -double -fleechance(unit * u) -{ - double c = 0.20; /* Fluchtwahrscheinlichkeit in % */ - region * r = u->region; - attrib * a = a_find(u->attribs, &at_fleechance); - /* Einheit u versucht, dem Getümmel zu entkommen */ - - c += (eff_skill(u, SK_STEALTH, r) * 0.05); - c += horsebonus(u); - - if (u->race == new_race[RC_HALFLING]) { - c += 0.20; - c = MIN(c, 0.90); - } else { - c = MIN(c, 0.75); - } - - if (a!=NULL) c += a->data.flt; - - return c; -} - -/** add a new army to the conflict - * beware: armies need to be added _at the beginning_ of the list because - * otherwise join_allies() will get into trouble */ -static side * -make_side(battle * b, const faction * f, const group * g, unsigned int flags, const faction *stealthfaction) -{ - side *s1 = b->sides+b->nsides; - bfaction * bf; - -#ifdef SIMPLE_COMBAT - if (fval(b->region->terrain, SEA_REGION)) { - /* every fight in an ocean is short */ - flags |= SIDE_HASGUARDS; - } else { - unit * u; - for (u = b->region->units; u; u = u->next) { - if (is_guard(u, HELP_ALL)) { - if (alliedunit(u, f, HELP_GUARD)) { - flags |= SIDE_HASGUARDS; - break; - } - } - } - } -#endif - - s1->battle = b; - s1->group = g; - s1->flags = flags; - s1->stealthfaction = stealthfaction; - for (bf = b->factions;bf;bf=bf->next) { - faction * f2 = bf->faction; - - if (f2 == f) { - s1->bf = bf; - s1->faction = f2; - s1->index = b->nsides++; - s1->nextF = bf->sides; - bf->sides = s1; - assert(b->nsides<=MAXSIDES); - break; - } - } - assert(bf); - return s1; -} - -troop -select_ally(fighter * af, int minrow, int maxrow, int allytype) -{ - side *as = af->side; - battle *b = as->battle; - side * ds; - int allies = count_allies(as, minrow, maxrow, SELECT_ADVANCE, allytype); - - if (!allies) { - return no_troop; - } - allies = rng_int() % allies; - - for (ds=b->sides;ds!=b->sides+b->nsides;++ds) { - if ((allytype==ALLY_ANY && helping(as, ds)) || (allytype==ALLY_SELF && as->faction==ds->faction)) { - fighter * df; - for (df=ds->fighters; df; df=df->next) { - int dr = get_unitrow(df, NULL); - if (dr >= minrow && dr <= maxrow) { - if (df->alive - df->removed > allies) { - troop dt; - assert(allies>=0); - dt.index = allies; - dt.fighter = df; - return dt; - } - allies -= df->alive; - } - } - } - } - assert(!"we should never have gotten here"); - return no_troop; -} - - -static int loot_quota(const unit * src, const unit * dst, const item_type * type, int n) -{ - static float divisor = -1; - if (dst && src && src->faction!=dst->faction) { - if (divisor<0) { - divisor = get_param_flt(global.parameters, "rules.items.loot_divisor", 1); - assert(divisor==0 || divisor>=1); - } - if (divisor>=1) { - double r = n / divisor; - int x = (int)r; - - r = r - x; - if (chance(r)) ++x; - - return x; - } - } - return n; -} - -static void -loot_items(fighter * corpse) -{ - unit * u = corpse->unit; - item * itm = u->items; - battle * b = corpse->side->battle; - int dead = dead_fighters(corpse); - - if (dead<=0) return; - - while (itm) { - float lootfactor = dead/(float)u->number; /* only loot the dead! */ - int maxloot = (int)(itm->number*lootfactor); - if (maxloot>0) { - int i = MIN(10, maxloot); - for (; i != 0; --i) { - int loot = maxloot/i; - - if (loot>0) { - fighter *fig = NULL; - int looting = 0; - int maxrow = 0; - /* mustloot: we absolutely, positively must have somebody loot this thing */ - int mustloot = itm->type->flags & (ITF_CURSED|ITF_NOTLOST); - - itm->number -= loot; - maxloot -= loot; - - if (is_monsters(u->faction) && (loot_rules & LOOT_MONSTERS)) { - looting = 1; - } else if (loot_rules&LOOT_OTHERS) { - looting = 1; - } else if (loot_rules&LOOT_SELF) { - looting = 2; - } - if (looting) { - if (mustloot) { - maxrow = LAST_ROW; - } else if (loot_rules&LOOT_KEEPLOOT) { - int lootchance = 50 + b->keeploot; - if (rng_int() % 100 < lootchance) { - maxrow = BEHIND_ROW; - } - } else { - maxrow = LAST_ROW; - } - } - if (maxrow>0) { - if (looting==1) { - /* enemies get dibs */ - fig = select_enemy(corpse, FIGHT_ROW, maxrow, 0).fighter; - } - if (!fig) { - /* self and allies get second pick */ - fig = select_ally(corpse, FIGHT_ROW, LAST_ROW, ALLY_SELF).fighter; - } - } - - if (fig) { - int trueloot = mustloot?loot:loot_quota(corpse->unit, fig->unit, itm->type, loot); - if (trueloot>0) { - item * l = fig->loot; - while (l && l->type!=itm->type) l=l->next; - if (!l) { - l = calloc(sizeof(item), 1); - l->next = fig->loot; - fig->loot = l; - l->type = itm->type; - } - l->number += trueloot; - } - } - } - } - } - itm = itm->next; - } -} - -#ifndef SIMPLE_ESCAPE -static void -loot_fleeing(fighter* fig, unit* runner) -{ - /* TODO: Vernünftig fixen */ - runner->items = NULL; - assert(runner->items == NULL); - runner->items = fig->run.items; - fig->run.items = NULL; -} - -static void -merge_fleeloot(fighter* fig, unit* u) -{ - i_merge(&u->items, &fig->run.items); -} -#endif /* SIMPLE_ESCAPE */ - -static boolean -seematrix(const faction * f, const side * s) -{ - if (f==s->faction) return true; - if (s->flags & SIDE_STEALTH) return false; - return true; -} - -static double -PopulationDamage(void) -{ - static double value = -1.0; - if (value<0) { - int damage = get_param_int(global.parameters, "rules.combat.populationdamage", BATTLE_KILLS_PEASANTS); - value = damage/100.0; - } - return value; -} - - -static void -battle_effects(battle * b, int dead_players) -{ - region * r = b->region; - int dead_peasants = MIN(rpeasants(r), (int)(dead_players*PopulationDamage())); - if (dead_peasants) { - deathcounts(r, dead_peasants + dead_players); - chaoscounts(r, dead_peasants / 2); - rsetpeasants(r, rpeasants(r) - dead_peasants); - } -} - -static void -reorder_fleeing(region * r) -{ - unit **usrc = &r->units; - unit **udst = &r->units; - unit *ufirst = NULL; - unit *u; - - for (;*udst;udst=&u->next) { - u = *udst; - } - - for (u=*usrc;u!=ufirst;u=*usrc) { - if (u->next && fval(u, UFL_FLEEING)) { - *usrc = u->next; - *udst = u; - udst = &u->next; - if (!ufirst) ufirst = u; - } else { - usrc = &u->next; - } - } - *udst = NULL; -} - -static void -aftermath(battle * b) -{ - int i; - region *r = b->region; - ship *sh; - side *s; - int dead_players = 0; - bfaction * bf; - boolean ships_damaged = (boolean)(b->turn+(b->has_tactics_turn?1:0)>2); /* only used for ship damage! */ - -#ifdef TROLLSAVE - int *trollsave = calloc(2 * cv_size(&b->factions), sizeof(int)); -#endif - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter * df; - for (df = s->fighters; df; df=df->next) { - unit *du = df->unit; - int dead = dead_fighters(df); - int pr_mercy = 0; - -#ifdef TROLLSAVE - /* Trolle können regenerieren */ - if (df->alive > 0 && dead>0 && du->race == new_race[RC_TROLL]) { - for (i = 0; i != dead; ++i) { - if (chance(TROLL_REGENERATION)) { - ++df->alive; - ++s->alive; - ++s->battle->alive; - ++trollsave[s->index]; - /* do not change dead here, or loop will not terminate! recalculate later */ - } - } - dead = dead_fighters(df); - } -#endif - /* Regeneration durch PR_MERCY */ - if (dead>0 && pr_mercy) { - for (i = 0; i != dead; ++i) { - if (rng_int()%100 < pr_mercy) { - ++df->alive; - ++s->alive; - ++s->battle->alive; - /* do not change dead here, or loop will not terminate! recalculate later */ - } - } - dead = dead_fighters(df); - } - - /* tote insgesamt: */ - s->dead += dead; - /* Tote, die wiederbelebt werde können: */ - if (playerrace(df->unit->race)) { - s->casualties += dead; - } -#ifdef SHOW_KILLS - if (df->hits + df->kills) { - struct message * m = msg_message("killsandhits", "unit hits kills", du, df->hits, df->kills); - message_faction(b, du->faction, m); - msg_release(m); - } -#endif - } - } - - /* POSTCOMBAT */ - do_combatmagic(b, DO_POSTCOMBATSPELL); - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - int snumber = 0; - fighter *df; - boolean relevant = false; /* Kampf relevant für diese Partei? */ -#ifdef SIMPLE_COMBAT - if (fval(s, SIDE_HASGUARDS) == 0) relevant = true; -#else - if (s->bf->lastturn>1) { - relevant = true; - } else if (s->bf->lastturn==1 && b->has_tactics_turn) { - side * stac; - for (stac=b->sides; stac; stac=stac->next) { - if (stac->leader.value == b->max_tactics && helping(stac, s)) { - relevant = true; - break; - } - } - } -#endif - s->flee = 0; - - for (df=s->fighters;df;df=df->next) { - unit *du = df->unit; - int dead = dead_fighters(df); - int sum_hp = 0; - int n; - - for (n = 0; n != df->alive; ++n) { - if (df->person[n].hp > 0) { - sum_hp += df->person[n].hp; - } - } - snumber += du->number; -#ifdef SIMPLE_COMBAT - if (relevant) { - int flags = UFL_LONGACTION|UFL_NOTMOVING; -#ifdef SIMPLE_ESCAPE - if (du->status==ST_FLEE) flags -= UFL_NOTMOVING; -#endif /* SIMPLE_ESCAPE */ - fset(du, flags); - } - if (sum_hp+df->run.hphp) { - /* someone on the ship got damaged, damage the ship */ - ship * sh = du->ship?du->ship:leftship(du); - if (sh) fset(sh, SF_DAMAGED); - } -#else - if (relevant) { - fset(du, UFL_NOTMOVING); /* unit cannot move this round */ - if (df->action_counter >= du->number) { - ship * sh = du->ship?du->ship:leftship(du); - if (sh) fset(sh, SF_DAMAGED); - fset(du, UFL_LONGACTION); - } - } -#endif - - if (df->alive == du->number) { - du->hp = sum_hp; - continue; /* nichts passiert */ - } else if (df->run.hp) { - if (df->alive == 0) { - /* Report the casualties */ - reportcasualties(b, df, dead); - - /* Zuerst dürfen die Feinde plündern, die mitgenommenen Items - * stehen in fig->run.items. Dann werden die Fliehenden auf - * die leere (tote) alte Einheit gemapt */ -#ifdef SIMPLE_ESCAPE - if (!fval(df, FIG_NOLOOT)) { - loot_items(df); - } -#else - if (fval(df, FIG_NOLOOT)){ - merge_fleeloot(df, du); - } else { - loot_items(df); - loot_fleeing(df, du); - } -#endif /* SIMPLE_ESCAPE */ - scale_number(du, df->run.number); - du->hp = df->run.hp; - setguard(du, GUARD_NONE); - /* must leave ships or buildings, or a stealthy hobbit - * can hold castles indefinitely */ - if (!fval(r->terrain, SEA_REGION)) { - leave(du, true); /* even region owners have to flee */ - } -#ifndef SIMPLE_ESCAPE - if (df->run.region) { - run_to(du, df->run.region); - df->run.region = du->region; - } - fset(du, UFL_LONGACTION|UFL_NOTMOVING); -#endif /* SIMPLE_ESCAPE */ - fset(du, UFL_FLEEING); - } else { - /* nur teilweise geflohene Einheiten mergen sich wieder */ - df->alive += df->run.number; - s->size[0] += df->run.number; - s->size[statusrow(df->status)] += df->run.number; - s->alive += df->run.number; - sum_hp += df->run.hp; -#ifndef SIMPLE_ESCAPE - merge_fleeloot(df, du); -#endif /* SIMPLE_ESCAPE */ - df->run.number = 0; - df->run.hp = 0; - /* df->run.region = NULL;*/ - - reportcasualties(b, df, dead); - - scale_number(du, df->alive); - du->hp = sum_hp; - } - } else { - if (df->alive==0) { - /* alle sind tot, niemand geflohen. Einheit auflösen */ - df->run.number = 0; - df->run.hp = 0; -#ifndef SIMPLE_ESCAPE - df->run.region = NULL; -#endif /* SIMPLE_ESCAPE */ - - /* Report the casualties */ - reportcasualties(b, df, dead); - - /* Distribute Loot */ - loot_items(df); - - setguard(du, GUARD_NONE); - scale_number(du, 0); - } else { - df->run.number = 0; - df->run.hp = 0; - - reportcasualties(b, df, dead); - - scale_number(du, df->alive); - du->hp = sum_hp; - } - } - s->flee += df->run.number; - - if (playerrace(du->race)) { - /* tote im kampf werden zu regionsuntoten: - * for each of them, a peasant will die as well */ - dead_players += dead; - } - if (du->hp < du->number) { - log_error(("%s has less hitpoints (%u) than people (%u)\n", - itoa36(du->no), du->hp, du->number)); - du->hp = du->number; - } - } - s->alive+=s->healed; - assert(snumber==s->flee+s->alive+s->dead); - } - - battle_effects(b, dead_players); - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - message * seen = msg_message("battle::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", - "index abbrev dead fled survived", - army_index(s), "-?-", s->dead, s->flee, s->alive); - - for (bf=b->factions;bf;bf=bf->next) { - faction * f = bf->faction; - message * m = seematrix(f, s)?seen:unseen; - - message_faction(b, f, m); - } - - msg_release(seen); - msg_release(unseen); - } - - /* Wir benutzen drifted, um uns zu merken, ob ein Schiff - * schonmal Schaden genommen hat. (moved und drifted - * sollten in flags überführt werden */ - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter *df; - - for (df=s->fighters; df; df=df->next) { - unit *du = df->unit; - item * l; - - /* Beute verteilen */ - for (l=df->loot; l; l=l->next) { - const item_type * itype = l->type; - message * m = msg_message("battle_loot", "unit amount item", du, l->number, itype->rtype); - message_faction(b, du->faction, m); - msg_release(m); - i_change(&du->items, itype, l->number); - } - - /* Wenn sich die Einheit auf einem Schiff befindet, wird - * dieses Schiff beschädigt. Andernfalls ein Schiff, welches - * evt. zuvor verlassen wurde. */ - if (ships_damaged) { - if (du->ship) sh = du->ship; - else sh = leftship(du); - - if (sh && fval(sh, SF_DAMAGED)) { - int n = b->turn - 2; - if (n>0) { - damage_ship(sh, 0.05 * n); - freset(sh, SF_DAMAGED); - } - } - } - } - } - - if (ships_damaged) { - ship **sp = &r->ships; - - while (*sp) { - ship * sh = *sp; - freset(sh, SF_DAMAGED); - if (sh->damage >= sh->size * DAMAGE_SCALE) { - remove_ship(sp, sh); - } - if (*sp==sh) sp=&sh->next; - } - } -#ifdef TROLLSAVE - free(trollsave); -#endif - - reorder_fleeing(r); - - if (bdebug) { - fprintf(bdebug, "The battle lasted %d turns, %s and %s.\n", - b->turn, - b->has_tactics_turn?"had a tactic turn":"had no tactic turn", - ships_damaged?"was relevant":"was not relevant."); - } -} - -static void -battle_punit(unit * u, battle * b) -{ - bfaction * bf; - strlist *S, *x; - - for (bf = b->factions;bf;bf=bf->next) { - faction *f = bf->faction; - - S = 0; - spunit(&S, f, u, 4, see_battle); - for (x = S; x; x = x->next) { - fbattlerecord(b, f, x->s); - if (bdebug && u->faction == f) { - fputs(x->s, bdebug); - fputc('\n', bdebug); - } - } - if (S) - freestrlist(S); - } -} - -static void -print_fighters(battle * b, const side * s) -{ - fighter *df; - int row; - - for (row=1;row!=NUMROWS;++row) { - message * m = NULL; - - for (df=s->fighters; df; df=df->next) { - unit *du = df->unit; - int thisrow = statusrow(df->unit->status); - - if (row == thisrow) { - if (m==NULL) { - m = msg_message("battle::row_header", "row", row); - message_all(b, m); - } - battle_punit(du, b); - } - } - if (m!=NULL) msg_release(m); - } -} - -boolean -is_attacker(const fighter * fig) -{ - return fval(fig, FIG_ATTACKER)!=0; -} - -static void -set_attacker(fighter * fig) -{ - fset(fig, FIG_ATTACKER); -} - -static void -print_header(battle * b) -{ - bfaction * bf; - char zText[32*MAXSIDES]; - - for (bf=b->factions;bf;bf=bf->next) { - message * m; - faction * f = bf->faction; - const char * lastf = NULL; - boolean first = false; - side * s; - char * bufp = zText; - size_t size = sizeof(zText) - 1; - int bytes; - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter *df; - for (df=s->fighters;df;df=df->next) { - if (is_attacker(df)) { - if (first) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (lastf) { - bytes = (int)strlcpy(bufp, (const char *)lastf, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - first = true; - } - if (seematrix(f, s) == true) - lastf = sidename(s); - else - lastf = LOC(f->locale, "unknown_faction_dative"); - break; - } - } - } - if (first) { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, (const char *)LOC(f->locale, "and"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (lastf) { - bytes = (int)strlcpy(bufp, (const char *)lastf, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - - m = msg_message("battle::starters", "factions", zText); - message_faction(b, f, m); - msg_release(m); - } -} - -static void -print_stats(battle * b) -{ - side *s2; - side *s; - int i = 0; - for (s=b->sides;s!=b->sides+b->nsides;++s) { - bfaction *bf; - - ++i; - - for (bf=b->factions;bf;bf=bf->next) { - faction * f = bf->faction; - const char * loc_army = LOC(f->locale, "battle_army"); - char * bufp; - const char * header; - size_t rsize, size; - int komma; - const char * sname = seematrix(f, s) ? sidename(s) : LOC(f->locale, "unknown_faction"); - message * msg; - char buf[1024]; - - message_faction(b, f, msg_separator); - - msg = msg_message("battle_army", "index name", army_index(s), sname); - message_faction(b, f, msg); - msg_release(msg); - - bufp = buf; - size = sizeof(buf); - komma = 0; - header = LOC(f->locale, "battle_opponents"); - - for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { - if (enemy(s2, s)) { - const char * abbrev = seematrix(f, s2)?sideabkz(s2, false):"-?-"; - rsize = slprintf(bufp, size, "%s %s %d(%s)", - komma++ ? "," : (const char*)header, loc_army, army_index(s2), abbrev); - if (rsize>size) rsize = size-1; - size -= rsize; - bufp += rsize; - } - } - if (komma) fbattlerecord(b, f, buf); - - bufp = buf; - size = sizeof(buf); - komma = 0; - header = LOC(f->locale, "battle_helpers"); - - for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { - if (friendly(s2, s)) { - const char * abbrev = seematrix(f, s2)?sideabkz(s2, false):"-?-"; - rsize = slprintf(bufp, size, "%s %s %d(%s)", - komma++ ? "," : (const char*)header, loc_army, army_index(s2), abbrev); - if (rsize>size) rsize = size-1; - size -= rsize; - bufp += rsize; - } - } - if (komma) fbattlerecord(b, f, buf); - - bufp = buf; - size = sizeof(buf); - komma = 0; - header = LOC(f->locale, "battle_attack"); - - for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { - if (s->relations[s2->index] & E_ATTACKING) { - const char * abbrev = seematrix(f, s2)?sideabkz(s2, false):"-?-"; - rsize = slprintf(bufp, size, "%s %s %d(%s)", komma++ ? "," : (const char*)header, loc_army, - army_index(s2), abbrev); - if (rsize>size) rsize = size-1; - size -= rsize; - bufp += rsize; - } - } - if (komma) fbattlerecord(b, f, buf); - } - - if (bdebug && s->faction) { - if (f_get_alliance(s->faction)) { - fprintf(bdebug, "##### %s (%s/%d)\n", s->faction->name, itoa36(s->faction->no), - s->faction->alliance?s->faction->alliance->id:0); - } else { - fprintf(bdebug, "##### %s (%s)\n", s->faction->name, itoa36(s->faction->no)); - } - } - print_fighters(b, s); - } - - message_all(b, msg_separator); - - /* Besten Taktiker ermitteln */ - - b->max_tactics = 0; - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - if (cv_size(&s->leader.fighters)) { - b->max_tactics = MAX(b->max_tactics, s->leader.value); - } - } - - if (b->max_tactics > 0) { - for (s=b->sides;s!=b->sides+b->nsides;++s) { - if (s->leader.value == b->max_tactics) { - fighter *tf; - cv_foreach(tf, s->leader.fighters) { - unit *u = tf->unit; - message * m = NULL; - if (!is_attacker(tf)) { - m = msg_message("battle::tactics_lost", "unit", u); - } else { - m = msg_message("battle::tactics_won", "unit", u); - } - message_all(b, m); - msg_release(m); - } cv_next(tf); - } - } - } -} - -static int -weapon_weight(const weapon * w, boolean missile) -{ - if (missile == i2b(fval(w->type, WTF_MISSILE))) { - return w->attackskill + w->defenseskill; - } - return 0; -} - -fighter * -make_fighter(battle * b, unit * u, side * s1, boolean attack) -{ -#define WMAX 20 - weapon weapons[WMAX]; - int owp[WMAX]; - int dwp[WMAX]; - int w = 0; - region *r = b->region; - item * itm; - fighter *fig = NULL; - int i, tactics = eff_skill(u, SK_TACTICS, r); - side *s2; - int h; - int berserk; - int strongmen; - int speeded = 0, speed = 1; - boolean pr_aid = false; - int rest; - const group * g = NULL; - const attrib *a = a_find(u->attribs, &at_otherfaction); - const faction *stealthfaction = a?get_otherfaction(a):NULL; - unsigned int flags = 0; - - assert(u->number); - if (fval(u, UFL_ANON_FACTION)!=0) flags |= SIDE_STEALTH; - - if (!(AllianceAuto() & HELP_FIGHT) && fval(u, UFL_GROUP)) { - const attrib * agroup = a_find(u->attribs, &at_group); - if (agroup!=NULL) g = (const group*)agroup->data.v; - } - - /* Illusionen und Zauber kaempfen nicht */ - if (fval(u->race, RCF_ILLUSIONARY) || idle(u->faction) || u->number==0) - return NULL; - - if (s1==NULL) { - for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { - if (s2->faction == u->faction && s2->group==g) { -#ifdef SIMPLE_COMBAT - int s1flags = flags|SIDE_HASGUARDS; - int s2flags = s2->flags|SIDE_HASGUARDS; -#else - int s1flags = flags; - int s2flags = s2->flags; -#endif - if (s1flags==s2flags && s2->stealthfaction==stealthfaction) { - s1 = s2; - break; - } - } - } - - /* aliances are moved out of make_fighter and will be handled later */ - if (!s1) { - s1 = make_side(b, u->faction, g, flags, stealthfaction); - } - /* Zu diesem Zeitpunkt ist attacked noch 0, da die Einheit für noch - * keinen Kampf ausgewählt wurde (sonst würde ein fighter existieren) */ - } - fig = calloc(1, sizeof(struct fighter)); - - fig->next = s1->fighters; - s1->fighters = fig; - - fig->unit = u; - /* In einer Burg muß man a) nicht Angreifer sein, und b) drin sein, und - * c) noch Platz finden. d) menschanähnlich sein */ - if (attack) { - set_attacker(fig); - } else { - building * b = u->building; - if (b && b->sizeleft>=u->number && playerrace(u->race)) { - fig->building = b; - fig->building->sizeleft -= u->number; - } - } - fig->status = u->status; - fig->side = s1; - fig->alive = u->number; - fig->side->alive += u->number; - fig->side->battle->alive += u->number; - fig->catmsg = -1; - - /* Freigeben nicht vergessen! */ - fig->person = calloc(fig->alive, sizeof(struct person)); - - h = u->hp / u->number; - assert(h); - rest = u->hp % u->number; - - /* Effekte von Sprüchen */ - - { - static const curse_type * speed_ct; - speed_ct = ct_find("speed"); - if (speed_ct) { - curse *c = get_curse(u->attribs, speed_ct); - if (c) { - speeded = get_cursedmen(u, c); - speed = curse_geteffect_int(c); - } - } - } - - /* Effekte von Alchemie */ - berserk = get_effect(u, oldpotiontype[P_BERSERK]); - /* change_effect wird in ageing gemacht */ - - /* Effekte von Artefakten */ - strongmen = MIN(fig->unit->number, get_item(u, I_TROLLBELT)); - - /* Hitpoints, Attack- und Defence-Boni für alle Personen */ - for (i = 0; i < fig->alive; i++) { - assert(i < fig->unit->number); - fig->person[i].hp = h; - if (i < rest) - fig->person[i].hp++; - - if (i < speeded) - fig->person[i].speed = speed; - else - fig->person[i].speed = 1; - - if (i < berserk) { - fig->person[i].attack++; - } - /* Leute mit einem Aid-Prayer bekommen +1 auf fast alles. */ - if (pr_aid) { - fig->person[i].attack++; - fig->person[i].defence++; - fig->person[i].damage++; - fig->person[i].damage_rear++; - fig->person[i].flags |= FL_COURAGE; - } - /* Leute mit Kraftzauber machen +2 Schaden im Nahkampf. */ - if (i < strongmen) { - fig->person[i].damage += 2; - } - } - - /* Für alle Waffengattungne wird bestimmt, wie viele der Personen mit - * ihr kämpfen könnten, und was ihr Wert darin ist. */ - if (u->race->battle_flags & BF_EQUIPMENT) { - int oi=0, di=0; - for (itm=u->items;itm && w!=WMAX;itm=itm->next) { - const weapon_type * wtype = resource2weapon(itm->type->rtype); - if (wtype==NULL || itm->number==0) continue; - weapons[w].attackskill = weapon_skill(wtype, u, true); - weapons[w].defenseskill = weapon_skill(wtype, u, false); - if (weapons[w].attackskill>=0 || weapons[w].defenseskill>=0) { - weapons[w].type = wtype; - weapons[w].used = 0; - weapons[w].count = itm->number; - ++w; - } - assert(w!=WMAX); - } - fig->weapons = calloc(sizeof(weapon), w+1); - memcpy(fig->weapons, weapons, w*sizeof(weapon)); - - for (i=0; i!=w; ++i) { - int j, o=0, d=0; - for (j=0; j!=i; ++j) { - if (weapon_weight(fig->weapons+j, true)>=weapon_weight(fig->weapons+i, true)) ++d; - if (weapon_weight(fig->weapons+j, false)>=weapon_weight(fig->weapons+i, false)) ++o; - } - for (j=i+1; j!=w; ++j) { - if (weapon_weight(fig->weapons+j, true)>weapon_weight(fig->weapons+i, true)) ++d; - if (weapon_weight(fig->weapons+j, false)>weapon_weight(fig->weapons+i, false)) ++o; - } - owp[o] = i; - dwp[d] = i; - } - /* jetzt enthalten owp und dwp eine absteigend schlechter werdende Liste der Waffen - * oi and di are the current index to the sorted owp/dwp arrays - * owp, dwp contain indices to the figther::weapons array */ - - /* hand out melee weapons: */ - for (i=0; i!=fig->alive; ++i) { - int wpless = weapon_skill(NULL, u, true); - while (oi!=w && (fig->weapons[owp[oi]].used==fig->weapons[owp[oi]].count || fval(fig->weapons[owp[oi]].type, WTF_MISSILE))) { - ++oi; - } - if (oi==w) break; /* no more weapons available */ - if (weapon_weight(fig->weapons+owp[oi], false)<=wpless) { - continue; /* we fight better with bare hands */ - } - fig->person[i].melee = &fig->weapons[owp[oi]]; - ++fig->weapons[owp[oi]].used; - } - /* hand out missile weapons (from back to front, in case of mixed troops). */ - for (di=0, i=fig->alive; i--!=0;) { - while (di!=w && (fig->weapons[dwp[di]].used==fig->weapons[dwp[di]].count || !fval(fig->weapons[dwp[di]].type, WTF_MISSILE))) { - ++di; - } - if (di==w) break; /* no more weapons available */ - if (weapon_weight(fig->weapons+dwp[di], true)>0) { - fig->person[i].missile = &fig->weapons[dwp[di]]; - ++fig->weapons[dwp[di]].used; - } - } - } - - s1->size[statusrow(fig->status)] += u->number; - s1->size[SUM_ROW] += u->number; - if (u->race->battle_flags & BF_NOBLOCK) { - s1->nonblockers[statusrow(fig->status)] += u->number; - } - - if (fig->unit->race->flags & RCF_HORSE) { - fig->horses = fig->unit->number; - fig->elvenhorses = 0; - } else { - static const item_type * it_charger = 0; - if (it_charger==0) { - it_charger = it_find("charger"); - if (!it_charger) { - it_charger = it_find("horse"); - } - } - fig->horses = i_get(u->items, it_charger); - fig->elvenhorses = get_item(u, I_ELVENHORSE); - } - - if (u->race->battle_flags & BF_EQUIPMENT) { - for (itm=u->items; itm; itm=itm->next) { - if (itm->type->rtype->atype) { - if (i_canuse(u, itm->type)) { - struct armor * adata = malloc(sizeof(armor)), **aptr; - adata->atype = itm->type->rtype->atype; - adata->count = itm->number; - for (aptr=&fig->armors;*aptr;aptr=&(*aptr)->next) { - if (adata->atype->prot > (*aptr)->atype->prot) break; - } - adata->next = *aptr; - *aptr = adata; - } - } - } - } - - - /* Jetzt muß noch geschaut werden, wo die Einheit die jeweils besten - * Werte hat, das kommt aber erst irgendwo später. Ich entscheide - * wärend des Kampfes, welche ich nehme, je nach Gegner. Deswegen auch - * keine addierten boni. */ - - /* Zuerst mal die Spezialbehandlung gewisser Sonderfälle. */ - fig->magic = eff_skill(u, SK_MAGIC, r); - - if (fig->horses) { - if (!fval(r->terrain, CAVALRY_REGION) || r_isforest(r) - || eff_skill(u, SK_RIDING, r) < CavalrySkill() || u->race == new_race[RC_TROLL] || fval(u, UFL_WERE)) - fig->horses = 0; - } - - if (fig->elvenhorses) { - if (eff_skill(u, SK_RIDING, r) < 5 || u->race == new_race[RC_TROLL] || fval(u, UFL_WERE)) - fig->elvenhorses = 0; - } - - /* Schauen, wie gut wir in Taktik sind. */ - if (tactics > 0 && u->race == new_race[RC_INSECT]) - tactics -= 1 - (int) log10(fig->side->size[SUM_ROW]); -#ifdef TACTICS_MODIFIER - if (tactics > 0 && statusrow(fig->status) == FIGHT_ROW) - tactics += TACTICS_MODIFIER; - if (tactics > 0 && statusrow(fig->status) > BEHIND_ROW) { - tactics -= TACTICS_MODIFIER; - } -#endif - - if (tactics > 0) { - int bonus = 0; - - for (i = 0; i < fig->alive; i++) { - int p_bonus = 0; - int rnd; - - do { - rnd = rng_int()%100; - if (rnd >= 40 && rnd <= 69) - p_bonus += 1; - else if (rnd <= 89) - p_bonus += 2; - else - p_bonus += 3; - } while(rnd >= 97); - bonus = MAX(p_bonus, bonus); - } - tactics += bonus; - } - - add_tactics(&fig->side->leader, fig, tactics); - ++b->nfighters; - return fig; -} - - -static int -join_battle(battle * b, unit * u, boolean attack, fighter ** cp) -{ - side * s; - fighter *c = NULL; - - if (!attack) { - attrib * a = a_find(u->attribs, &at_fleechance); - if (a!=NULL) { - if (rng_double()<=a->data.flt) { - *cp = NULL; - return false; - } - } - } - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter *fig; - if (s->faction==u->faction) { - for (fig=s->fighters;fig;fig=fig->next) { - if (fig->unit == u) { - c = fig; - if (attack) { - set_attacker(fig); - } - break; - } - } - } - } - if (!c) { - *cp = make_fighter(b, u, NULL, attack); - return *cp!=NULL; - } - *cp = c; - return false; -} - -static const char * -simplename(region * r) -{ - int i; - static char name[17]; - const char * cp = rname(r, default_locale); - for (i=0;*cp && i!=16;++i, ++cp) { - int c = *(unsigned char *)cp; - while (c && !isalpha(c) && !isxspace(c)) { - ++cp; - c = *(unsigned char*)cp; - } - if (isxspace(c)) name[i] = '_'; - else name[i] = *cp; - if (c==0) break; - } - name[i]=0; - return name; -} - -static battle * -make_battle(region * r) -{ - battle *b = calloc(1, sizeof(struct battle)); - unit *u; - bfaction * bf; - static int max_fac_no = 0; /* need this only once */ - - if (battledebug) { - char zText[MAX_PATH]; - char zFilename[MAX_PATH]; - sprintf(zText, "%s/battles", basepath()); - makedir(zText, 0700); - sprintf(zFilename, "%s/battle-%d-%s.log", zText, obs_count, simplename(r)); - bdebug = fopen(zFilename, "w"); - if (!bdebug) log_error(("battles cannot be debugged\n")); - else { - const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; - fwrite(utf8_bom, 1, 3, bdebug); - fprintf(bdebug, "In %s findet ein Kampf stattactics:\n", rname(r, default_locale)); - } - obs_count++; - } - - b->region = r; - b->plane = getplane(r); - /* Finde alle Parteien, die den Kampf beobachten können: */ - for (u = r->units; u; u=u->next) { - if (u->number > 0) { - if (!fval(u->faction, FFL_MARK)) { - fset(u->faction, FFL_MARK); - for (bf=b->factions;bf;bf=bf->next) { - if (bf->faction==u->faction) break; - } - if (!bf) { - bf = calloc(sizeof(bfaction), 1); - ++b->nfactions; - bf->faction = u->faction; - bf->next = b->factions; - b->factions = bf; - } - } - } - } - - for (bf=b->factions;bf;bf=bf->next) { - faction * f = bf->faction; - max_fac_no = MAX(max_fac_no, f->no); - freset(f, FFL_MARK); - } - return b; -} - -static void -free_side(side * si) -{ - cv_kill(&si->leader.fighters); -} - -static void -free_fighter(fighter * fig) -{ - while (fig->loot) { - i_free(i_remove(&fig->loot, fig->loot)); - } - while (fig->armors) { - armor * a = fig->armors; - fig->armors = a->next; - free(a); - } - free(fig->person); - free(fig->weapons); - -} - -static void -free_battle(battle * b) -{ - side *s; - meffect *meffect; - int max_fac_no = 0; - - if (bdebug) { - fclose(bdebug); - } - - while (b->factions) { - bfaction * bf = b->factions; - faction * f = bf->faction; - b->factions = bf->next; - max_fac_no = MAX(max_fac_no, f->no); - free(bf); - } - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter *fnext = s->fighters; - while (fnext) { - fighter *fig = fnext; - fnext = fig->next; - free_fighter(fig); - free(fig); - } - free_side(s); - } - cv_kill(&b->leaders); - cv_foreach(meffect, b->meffects) { - free(meffect); - } - cv_next(meffect); - cv_kill(&b->meffects); -} - -static int * -get_alive(side * s) -{ -#if 0 - static int alive[NUMROWS]; - fighter *fig; - memset(alive, 0, NUMROWS * sizeof(int)); - for (fig=s->fighters;fig;fig=fig->next) { - if (fig->alive>0) { - int row = statusrow(fig); - alive[row] += fig->alive; - } - } - return alive; -#endif - return s->size; -} - -static int -battle_report(battle * b) -{ - side *s, *s2; - boolean cont = false; - boolean komma; - bfaction *bf; - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - if (s->alive-s->removed > 0) { - for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { - if (s2->alive-s2->removed > 0 && enemy(s, s2)) { - cont = true; - break; - } - } - if (cont) break; - } - } - - if (verbosity>0) log_stdio(stdout, " %d", b->turn); - fflush(stdout); - - for (bf=b->factions;bf;bf=bf->next) { - faction * fac = bf->faction; - char buf[32*MAXSIDES]; - char * bufp = buf; - int bytes; - size_t size = sizeof(buf) - 1; - message * m; - - message_faction(b, fac, msg_separator); - - if (cont) m = msg_message("battle::lineup", "turn", b->turn); - else m = msg_message("battle::after", ""); - message_faction(b, fac, m); - msg_release(m); - - komma = false; - for (s=b->sides;s!=b->sides+b->nsides;++s) { - if (s->alive) { - int r, k = 0, * alive = get_alive(s); - int l = FIGHT_ROW; - const char * abbrev = seematrix(fac, s)?sideabkz(s, false):"-?-"; - const char * loc_army = LOC(fac->locale, "battle_army"); - char buffer[32]; - - if (komma) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - snprintf(buffer, sizeof(buffer), "%s %2d(%s): ", - loc_army, army_index(s), abbrev); - buffer[sizeof(buffer)-1] = 0; - - bytes = (int)strlcpy(bufp, buffer, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - for (r=FIGHT_ROW;r!=NUMROWS;++r) { - if (alive[r]) { - if (l!=FIGHT_ROW) { - bytes = (int)strlcpy(bufp, "+", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - while (k--) { - bytes = (int)strlcpy(bufp, "0+", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - sprintf(buffer, "%d", alive[r]); - - bytes = (int)strlcpy(bufp, buffer, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - k = 0; - l = r+1; - } else ++k; - } - - komma = true; - } - } - *bufp = 0; - fbattlerecord(b, fac, buf); - } - return cont; -} - -static void -join_allies(battle * b) -{ - region *r = b->region; - unit *u; - side *s, *s_end = b->sides+b->nsides; - /* make_side might be adding a new faction, but it adds them to the end - * of the list, so we're safe in our iteration here if we remember the end - * up front. */ - for (u=r->units;u;u=u->next) { - /* Was ist mit Schiffen? */ - if (u->status != ST_FLEE && u->status != ST_AVOID && !fval(u, UFL_LONGACTION|UFL_ISNEW) && u->number > 0) { - faction * f = u->faction; - fighter * c = NULL; - - for (s=b->sides;s!=s_end;++s) { - side * se; - /* Wenn alle attackierten noch FFL_NOAID haben, dann kämpfe nicht mit. */ - if (fval(s->faction, FFL_NOAID)) continue; - if (s->faction!=f) { - /* Wenn wir attackiert haben, kommt niemand mehr hinzu: */ - if (s->bf->attacker) continue; - /* alliiert müssen wir schon sein, sonst ist's eh egal : */ - if (!alliedunit(u, s->faction, HELP_FIGHT)) continue; - /* wenn die partei verborgen ist, oder gar eine andere - * vorgespiegelt wird, und er sich uns gegenüber nicht zu - * erkennen gibt, helfen wir ihm nicht */ - if (s->stealthfaction){ - if(!allysfm(s, u->faction, HELP_FSTEALTH)) { - continue; - } - } - } - /* einen alliierten angreifen dürfen sie nicht, es sei denn, der - * ist mit einem alliierten verfeindet, der nicht attackiert - * hat: */ - for (se=b->sides;se!=s_end;++se) { - if (u->faction==se->faction) continue; - if (alliedunit(u, se->faction, HELP_FIGHT) && !se->bf->attacker) { - continue; - } - if (enemy(s, se)) break; - } - if (se==s_end) continue; - /* Wenn die Einheit belagert ist, muß auch einer der Alliierten belagert sein: */ - if (besieged(u)) { - fighter *ally; - for (ally = s->fighters; ally; ally=ally->next) { - if (besieged(ally->unit)) { - break; - } - } - if (ally==NULL) continue; - } - /* keine Einwände, also soll er mitmachen: */ - if (c==NULL) { - if (join_battle(b, u, false, &c)) { - if (battledebug) { - fprintf(bdebug, "%s joins to help %s against %s.\n", - unitname(u), factionname(s->faction), - factionname(se->faction)); - } - } else if (c==NULL) { - continue; - } - } - - /* the enemy of my friend is my enemy: */ - for (se=b->sides;se!=s_end;++se) { - if (se->faction!=u->faction && enemy(s, se)) { - if (set_enemy(se, c->side, false) && battledebug) { - fprintf(bdebug, "%u/%s hates %u/%s because they are enemies with %u/%s.\n", - c->side->index, sidename(c->side), - se->index, sidename(se), - s->index, sidename(s)); - } - } - } - } - } - } - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - int si; - side * sa; - faction * f = s->faction; - - /* Den Feinden meiner Feinde gebe ich Deckung (gegen gemeinsame Feinde): */ - for (si=0; s->enemies[si]; ++si) { - side * se = s->enemies[si]; - int ai; - for (ai=0; se->enemies[ai]; ++ai) { - side * as = se->enemies[ai]; - if (as==s || !enemy(as, s)) { - set_friendly(as, s); - } - } - } - - for (sa=s+1;sa!=b->sides+b->nsides;++sa) { - plane * pl = rplane(r); - if (enemy(s, sa)) continue; - if (friendly(s, sa)) continue; - if (!alliedgroup(pl, f, sa->faction, f->allies, HELP_FIGHT)) continue; - if (!alliedgroup(pl, sa->faction, f, sa->faction->allies, HELP_FIGHT)) continue; - - set_friendly(s, sa); - } - } -} - -static void -flee(const troop dt) -{ - fighter * fig = dt.fighter; - unit * u = fig->unit; - -#ifndef SIMPLE_ESCAPE - int carry = personcapacity(u) - u->race->weight; - int money; - - item ** ip = &u->items; - - while (*ip) { - item * itm = *ip; - const item_type * itype = itm->type; - int keep = 0; - - if (fval(itype, ITF_ANIMAL)) { - /* Regeländerung: Man muß das Tier nicht reiten können, - * um es vom Schlachtfeld mitzunehmen, ist ja nur - * eine Region weit. * */ - keep = MIN(1, itm->number); - /* da ist das weight des tiers mit drin */ - carry += itype->capacity - itype->weight; - } else if (itm->type->weight <= 0) { - /* if it doesn'tactics weigh anything, it won'tactics slow us down */ - keep = itm->number; - } - /* jeder troop nimmt seinen eigenen Teil der Sachen mit */ - if (keep>0){ - if (itm->number==keep) { - i_add(&fig->run.items, i_remove(ip, itm)); - } else { - item *run_itm = i_new(itype, keep); - i_add(&fig->run.items, run_itm); - i_change(ip, itype, -keep); - } - } - if (*ip==itm) ip = &itm->next; - } - - /* we will take money with us */ - money = get_money(u); - /* nur ganzgeflohene/resttote Einheiten verlassen die Region */ - if (money > carry) money = carry; - if (money > 0) { - i_change(&u->items, i_silver, -money); - i_change(&fig->run.items, i_silver, +money); - } -#endif /* SIMPLE_ESCAPE */ - - fig->run.hp += fig->person[dt.index].hp; - ++fig->run.number; - - setguard(u, GUARD_NONE); - - kill_troop(dt); -} - -static boolean -init_battle(region * r, battle **bp) -{ - battle * b = NULL; - unit * u; - boolean fighting = false; - - /* list_foreach geht nicht, wegen flucht */ - for (u = r->units; u != NULL; u = u->next) { - if (fval(u, UFL_LONGACTION)) continue; - if (u->number > 0) { - order * ord; - - for (ord=u->orders;ord;ord=ord->next) { - static boolean init = false; - static const curse_type * peace_ct, * slave_ct, * calm_ct; - - if (!init) { - init = true; - peace_ct = ct_find("peacezone"); - slave_ct = ct_find("slavery"); - calm_ct = ct_find("calmmonster"); - } - if (get_keyword(ord) == K_ATTACK) { - unit *u2; - fighter *c1, *c2; - ship * lsh = NULL; - plane * pl = rplane(r); - - if (pl && fval(pl, PFL_NOATTACK)) { - cmistake(u, ord, 271, MSG_BATTLE); - continue; - } - - if ((u->race->battle_flags&BF_CANATTACK) == 0) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_no_attack", "race", u->race)); - continue; - } - /** - ** Fehlerbehandlung Angreifer - **/ - if (LongHunger(u)) { - cmistake(u, ord, 225, MSG_BATTLE); - continue; - } - - if (u->status == ST_AVOID || u->status == ST_FLEE) { - cmistake(u, ord, 226, MSG_BATTLE); - continue; - } - - /* ist ein Flüchtling aus einem andern Kampf */ - if (fval(u, UFL_LONGACTION)) continue; - - if (peace_ct && curse_active(get_curse(r->attribs, peace_ct))) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "peace_active", "")); - continue; - } - - if (slave_ct && curse_active(get_curse(u->attribs, slave_ct))) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "slave_active", "")); - continue; - } - - if ((u->ship != NULL && !fval(r->terrain, SEA_REGION)) || (lsh = leftship(u))!=NULL) { - if (is_guarded(r, u, GUARD_TRAVELTHRU)) { - if (lsh) { - cmistake(u, ord, 234, MSG_BATTLE); - } else { - /* Fehler: "Das Schiff muß erst verlassen werden" */ - cmistake(u, ord, 19, MSG_BATTLE); - } - continue; - } - } - - /* Ende Fehlerbehandlung Angreifer */ - - init_tokens(ord); - skip_token(); - /* attackierte Einheit ermitteln */ - u2 = getunit(r, u->faction); - - /* Beginn Fehlerbehandlung */ - /* Fehler: "Die Einheit wurde nicht gefunden" */ - if (!u2 || u2->number == 0 || !cansee(u->faction, u->region, u2, 0)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - continue; - } - /* Fehler: "Die Einheit ist eine der unsrigen" */ - if (u2->faction == u->faction) { - cmistake(u, ord, 45, MSG_BATTLE); - continue; - } - /* Fehler: "Die Einheit ist mit uns alliert" */ - if (alliedunit(u, u2->faction, HELP_FIGHT)) { - cmistake(u, ord, 47, MSG_BATTLE); - continue; - } - if (IsImmune(u2->faction)) { - add_message(&u->faction->msgs, - msg_feedback(u, u->thisorder, "newbie_immunity_error", "turns", NewbieImmunity())); - continue; - } - /* Fehler: "Die Einheit ist mit uns alliert" */ - - if (calm_ct) { - attrib * a = a_find(u->attribs, &at_curse); - boolean calm = false; - while (a && a->type==&at_curse) { - curse * c = (curse *)a->data.v; - if (c->type==calm_ct && curse_geteffect(c)==u2->faction->subscription) { - if (curse_active(c)) { - calm = true; - break; - } - } - a = a->next; - } - if (calm) { - cmistake(u, ord, 47, MSG_BATTLE); - continue; - } - } - /* Ende Fehlerbehandlung */ - if (b==NULL) { - unit * utmp; - for (utmp=r->units; utmp!=NULL; utmp=utmp->next) { - fset(utmp->faction, FFL_NOAID); - } - b = make_battle(r); - } - if (join_battle(b, u, true, &c1)) { - if (battledebug) { - fprintf(bdebug, "%s joins by attacking %s.\n", - unitname(u), unitname(u2)); - } - } - if (join_battle(b, u2, false, &c2)) { - if (battledebug) { - fprintf(bdebug, "%s joins because of an attack from %s.\n", - unitname(u2), unitname(u)); - } - } - - /* Hat die attackierte Einheit keinen Noaid-Status, - * wird das Flag von der Faction genommen, andere - * Einheiten greifen ein. */ - if (!fval(u2, UFL_NOAID)) freset(u2->faction, FFL_NOAID); - - if (c1!=NULL && c2!=NULL) { - /* Merken, wer Angreifer ist, für die Rückzahlung der - * Präcombataura bei kurzem Kampf. */ - c1->side->bf->attacker = true; - - if (set_enemy(c1->side, c2->side, true) && battledebug) { - fprintf(bdebug, "%u/%s hates %u/%s because they attacked them.\n", - c2->side->index, sidename(c2->side), - c1->side->index, sidename(c1->side)); - } - fighting = true; - } - } - } - } - } - *bp = b; - return fighting; -} - -static void -battle_stats(FILE * F, battle * b) -{ - typedef struct stat_info { - struct stat_info * next; - const weapon_type * wtype; - int level; - int number; - } stat_info; - side * s; - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter * df; - stat_info * stats = NULL, * stat; - - for (df = s->fighters; df; df = df->next) { - unit *du = df->unit; - troop dt; - stat_info * slast = NULL; - - dt.fighter = df; - for (dt.index=0;dt.index!=du->number;++dt.index) { - weapon * wp = preferred_weapon(dt, true); - int level = wp?wp->attackskill:0; - const weapon_type * wtype = wp?wp->type:NULL; - stat_info ** slist = &stats; - - if (slast && slast->wtype==wtype && slast->level==level) { - ++slast->number; - continue; - } - while (*slist && (*slist)->wtype!=wtype) { - slist = &(*slist)->next; - } - while (*slist && (*slist)->wtype==wtype && (*slist)->level>level) { - slist = &(*slist)->next; - } - stat = *slist; - if (stat==NULL || stat->wtype!=wtype || stat->level!=level) { - stat = calloc(1, sizeof(stat_info)); - stat->wtype = wtype; - stat->level = level; - stat->next = *slist; - *slist = stat; - } - slast = stat; - ++slast->number; - } - } - - fprintf(F, "##STATS## Heer %u - %s:\n", army_index(s), factionname(s->faction)); - for (stat=stats;stat!=NULL;stat=stat->next) { - fprintf(F, "%s %u : %u\n", stat->wtype?stat->wtype->itype->rtype->_name[0]:"none", stat->level, stat->number); - } - freelist(stats); - } -} - -/** execute one round of attacks - * fig->fighting is used to determine who attacks, not fig->alive, since - * the latter may be influenced by attacks that already took place. - */ -static void -battle_attacks(battle * b) -{ - side * s; - - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter *fig; - - if (b->turn!=0 || (b->max_tactics > 0 && get_tactics(s, NULL) == b->max_tactics)) { - for (fig=s->fighters;fig;fig=fig->next) { - - /* ist in dieser Einheit noch jemand handlungsfähig? */ - if (fig->fighting <= 0) continue; - - /* Handle the unit's attack on someone */ - do_attack(fig); - } - } - } -} - -/** updates the number of attacking troops in each fighter struct. - * this has to be calculated _before_ the actual attacks take - * place because otherwise dead troops would not strike in the - * round they die. */ -static void -battle_update(battle * b) -{ - side * s; - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter *fig; - for (fig=s->fighters;fig;fig=fig->next) { - fig->fighting = fig->alive - fig->removed; - } - } -} - -/** attempt to flee from battle before the next round begins - * there's a double attempt before the first round, but only - * one attempt before round zero, the potential tactics round. */ -static void -battle_flee(battle * b) -{ - int attempt, flee_ops = 1; - - if (b->turn==1) - flee_ops = 2; - - for (attempt=1;attempt<=flee_ops;++attempt) { - side * s; - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter *fig; - for (fig=s->fighters;fig;fig=fig->next) { - unit *u = fig->unit; - troop dt; - int runners = 0; - /* Flucht nicht bei mehr als 600 HP. Damit Wyrme tötbar bleiben. */ - int runhp = MIN(600,(int)(0.9+unit_max_hp(u)*hpflee(u->status))); - - if (u->ship && fval(u->region->terrain, SEA_REGION)) { - /* keine Flucht von Schiffen auf hoher See */ - continue; - } - if (fval(u->race, RCF_UNDEAD) || u->race == new_race[RC_SHADOWKNIGHT]) { - /* Untote fliehen nicht. Warum eigentlich? */ - continue; - } - - dt.fighter = fig; -#ifndef SIMPLE_ESCAPE - if (!fig->run.region) fig->run.region = fleeregion(u); - if (!fig->run.region) continue; -#endif /* SIMPLE_ESCAPE */ - dt.index = fig->alive - fig->removed; - while (s->size[SUM_ROW] && dt.index != 0) { - double ispaniced = 0.0; - --dt.index; - assert(dt.index>=0 && dt.indexunit->number); - assert(fig->person[dt.index].hp > 0); - - /* Versuche zu fliehen, wenn - * - Kampfstatus fliehe - * - schwer verwundet und nicht erste kampfrunde - * - in panik (Zauber) - * aber nicht, wenn der Zaubereffekt Held auf dir liegt! - */ - switch (u->status) { - case ST_FLEE: - break; - default: - if ((fig->person[dt.index].flags & FL_HIT) == 0) continue; - if (b->turn<=1) continue; - if (fig->person[dt.index].hp <= runhp) break; - if (fig->person[dt.index].flags & FL_PANICED) { - if ((fig->person[dt.index].flags & FL_COURAGE)==0) break; - } - continue; - } - - if (fig->person[dt.index].flags & FL_PANICED) { - ispaniced = EFFECT_PANIC_SPELL; - } - if (chance(MIN(fleechance(u)+ispaniced, 0.90))) { - ++runners; - flee(dt); - } - } - if (bdebug && runners > 0) { - fprintf(bdebug, "Fleeing: %d from %s\n", runners, itoa36(fig->unit->no)); - } - } - } - } -} - -void -do_battle(region * r) -{ - battle *b = NULL; - boolean fighting = false; - ship * sh; - building *bu; - static int init_rules = 0; - - if (!init_rules) { - static_rules(); - init_rules = 1; - } - if (msg_separator==NULL) { - msg_separator = msg_message("battle::section", ""); - } - - fighting = init_battle(r, &b); - - if (b==NULL) return; - - /* Bevor wir die alliierten hineinziehen, sollten wir schauen, * - * Ob jemand fliehen kann. Dann erübrigt sich das ganze ja - * vielleicht schon. */ - print_header(b); - if (!fighting) { - /* Niemand mehr da, Kampf kann nicht stattfinden. */ - message * m = msg_message("battle::aborted", ""); - message_all(b, m); - msg_release(m); - free_battle(b); - free(b); - return; - } - join_allies(b); - make_heroes(b); - - /* Alle Mann raus aus der Burg! */ - for (bu=r->buildings; bu!=NULL; bu=bu->next) bu->sizeleft = bu->size; - - /* make sure no ships are damaged initially */ - for (sh=r->ships; sh; sh=sh->next) freset(sh, SF_DAMAGED); - - /* Gibt es eine Taktikrunde ? */ - if (cv_size(&b->leaders)) { - b->turn = 0; - b->has_tactics_turn = true; - } else { - b->turn = 1; - b->has_tactics_turn = false; - } - - if (b->region->flags & RF_COMBATDEBUG) battle_stats(bdebug, b); - - /* PRECOMBATSPELLS */ - do_combatmagic(b, DO_PRECOMBATSPELL); - - print_stats(b); /* gibt die Kampfaufstellung aus */ - if (verbosity>0) log_stdio(stdout, "%s (%d, %d) : ", rname(r, default_locale), r->x, r->y); - - for (;battle_report(b) && b->turn<=max_turns;++b->turn) { - if (bdebug) { - fprintf(bdebug, "*** Turn: %d\n", b->turn); - } - battle_flee(b); - battle_update(b); - battle_attacks(b); - - } - - if (verbosity>0) log_stdio(stdout, "\n"); - - /* Auswirkungen berechnen: */ - aftermath(b); - /* Hier ist das Gefecht beendet, und wir können die - * Hilfsstrukturen * wieder löschen: */ - - if (b) { - free_battle(b); - free(b); - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#pragma region includes + +#include +#include +#include "battle.h" + +#include "alchemy.h" +#include "alliance.h" +#include "build.h" +#include "building.h" +#include "curse.h" +#include "equipment.h" +#include "faction.h" +#include "group.h" +#include "item.h" +#include "magic.h" +#include "message.h" +#include "move.h" +#include "names.h" +#include "order.h" +#include "plane.h" +#include "race.h" +#include "region.h" +#include "reports.h" +#include "ship.h" +#include "skill.h" +#include "terrain.h" +#include "unit.h" + +/* attributes includes */ +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include + +#pragma endregion + +static FILE *bdebug; + +#define TACTICS_BONUS 1 /* when undefined, we have a tactics round. else this is the bonus tactics give */ +#define TACTICS_MODIFIER 1 /* modifier for generals in the fromt/rear */ + +#define CATAPULT_INITIAL_RELOAD 4 /* erster schuss in runde 1 + rng_int() % INITIAL */ +#define CATAPULT_STRUCTURAL_DAMAGE + +#define BASE_CHANCE 70 /* 70% Basis-Überlebenschance */ +#ifdef NEW_COMBATSKILLS_RULE +#define TDIFF_CHANGE 5 /* 5% höher pro Stufe */ +#define DAMAGE_QUOTIENT 2 /* damage += skilldiff/DAMAGE_QUOTIENT */ +#else +#define TDIFF_CHANGE 10 +# define DAMAGE_QUOTIENT 1 /* damage += skilldiff/DAMAGE_QUOTIENT */ +#endif + +#undef DEBUG_FAST /* should be disabled when b->fast and b->rowcache works */ +#define DEBUG_SELECT /* should be disabled if select_enemy works */ + +typedef enum combatmagic { + DO_PRECOMBATSPELL, + DO_POSTCOMBATSPELL +} combatmagic_t; + +/* globals */ +static int obs_count = 0; + +#define MINSPELLRANGE 1 +#define MAXSPELLRANGE 7 + +#ifndef ROW_FACTOR +# define ROW_FACTOR 10 +#endif +static const double EFFECT_PANIC_SPELL = 0.25; +static const double TROLL_REGENERATION = 0.10; + +/* Nach dem alten System: */ +static int missile_range[2] = {FIGHT_ROW, BEHIND_ROW}; +static int melee_range[2] = {FIGHT_ROW, FIGHT_ROW}; +static message * msg_separator; + +const troop no_troop = {0, 0}; + +static int max_turns = 0; +static int damage_rules = 0; +static int loot_rules = 0; +static int skill_formula = 0; + +#define FORMULA_ORIG 0 +#define FORMULA_NEW 1 + +#define LOOT_MONSTERS (1<<0) +#define LOOT_SELF (1<<1) /* code is mutually exclusive with LOOT_OTHERS */ +#define LOOT_OTHERS (1<<2) +#define LOOT_KEEPLOOT (1<<4) + +#define DAMAGE_CRITICAL (1<<0) +#define DAMAGE_MELEE_BONUS (1<<1) +#define DAMAGE_MISSILE_BONUS (1<<2) +#define DAMAGE_UNARMED_BONUS (1<<3) +#define DAMAGE_SKILL_BONUS (1<<4) +/** initialize rules from configuration. + */ +static void +static_rules(void) +{ + loot_rules = get_param_int(global.parameters, "rules.combat.loot", LOOT_MONSTERS|LOOT_OTHERS|LOOT_KEEPLOOT); + /* new formula to calculate to-hit-chance */ + skill_formula = get_param_int(global.parameters, "rules.combat.skill_formula", FORMULA_ORIG); + /* maximum number of combat turns */ + max_turns = get_param_int(global.parameters, "rules.combat.turns", COMBAT_TURNS); + /* damage calculation */ + if (get_param_int(global.parameters, "rules.combat.critical", 1)) { + damage_rules |= DAMAGE_CRITICAL; + } + if (get_param_int(global.parameters, "rules.combat.melee_bonus", 1)) { + damage_rules |= DAMAGE_MELEE_BONUS; + } + if (get_param_int(global.parameters, "rules.combat.missile_bonus", 1)) { + damage_rules |= DAMAGE_MISSILE_BONUS; + } + if (get_param_int(global.parameters, "rules.combat.unarmed_bonus", 1)) { + damage_rules |= DAMAGE_UNARMED_BONUS; + } + if (get_param_int(global.parameters, "rules.combat.skill_bonus", 1)) { + damage_rules |= DAMAGE_SKILL_BONUS; + } +} + +static int +army_index(side * s) +{ + return s->index; +} + +#ifndef SIMPLE_ESCAPE +region * +fleeregion(const unit * u) +{ + region *r = u->region; + region *neighbours[MAXDIRECTIONS]; + int c = 0; + direction_t i; + + if (u->ship && !fval(r->terrain, SEA_REGION)) + return NULL; + + if (u->ship && + !(u->race->flags & RCF_SWIM) && + !(u->race->flags & RCF_FLY)) { + return NULL; + } + + for (i = 0; i != MAXDIRECTIONS; ++i) { + region * r2 = rconnect(r, i); + if (r2) { + if (can_survive(u,r2) && !move_blocked(u, r, r2)) + neighbours[c++] = r2; + } + } + + if (!c) + return NULL; + return neighbours[rng_int() % c]; +} +#endif /* SIMPLE_ESCAPE */ + +static char * +sidename(side * s) +{ +#define SIDENAMEBUFLEN 256 + static int bufno; /* STATIC_XCALL: used across calls */ + static char sidename_buf[4][SIDENAMEBUFLEN]; /* STATIC_RESULT: used for return, not across calls */ + + bufno = bufno % 4; + if (s->stealthfaction) { + snprintf(sidename_buf[bufno], SIDENAMEBUFLEN, + "%s", factionname(s->stealthfaction)); + } else { + snprintf(sidename_buf[bufno], SIDENAMEBUFLEN, + "%s", factionname(s->faction)); + } + return sidename_buf[bufno++]; +} + +static const char * +sideabkz(side *s, boolean truename) +{ + static char sideabkz_buf[8]; /* STATIC_RESULT: used for return, not across calls */ + const faction * f = (s->stealthfaction && !truename)?s->stealthfaction:s->faction; + +#undef SIDE_ABKZ +#ifdef SIDE_ABKZ + abkz(f->name, sideabkz_buf, sizeof(sideabkz_buf), 3); +#else + strcpy(sideabkz_buf, itoa36(f->no)); +#endif + return sideabkz_buf; +} + +static void +message_faction(battle * b, faction * f, struct message * m) +{ + region * r = b->region; + + if (f->battles==NULL || f->battles->r!=r) { + struct bmsg * bm = calloc(1, sizeof(struct bmsg)); + bm->next = f->battles; + f->battles = bm; + bm->r = r; + } + add_message(&f->battles->msgs, m); +} + +int +armedmen(const unit * u, boolean siege_weapons) +{ + item * itm; + int n = 0; + if (!(urace(u)->flags & RCF_NOWEAPONS)) { + if (effskill(u, SK_WEAPONLESS)>=1) { + /* kann ohne waffen bewachen: fuer drachen */ + n = u->number; + } else { + /* alle Waffen werden gezaehlt, und dann wird auf die Anzahl + * Personen minimiert */ + for (itm=u->items;itm;itm=itm->next) { + const weapon_type * wtype = resource2weapon(itm->type->rtype); + if (wtype==NULL || (!siege_weapons && (wtype->flags & WTF_SIEGE))) continue; + if (effskill(u, wtype->skill) >= 1) n += itm->number; + /* if (effskill(u, wtype->skill) >= wtype->minskill) n += itm->number; */ + if (n>u->number) break; + } + n = MIN(n, u->number); + } + } + return n; +} + +void +message_all(battle * b, message * m) +{ + bfaction * bf; + plane * p = rplane(b->region); + watcher * w; + + for (bf = b->factions;bf;bf=bf->next) { + message_faction(b, bf->faction, m); + } + if (p) for (w=p->watchers;w;w=w->next) { + for (bf = b->factions;bf;bf=bf->next) if (bf->faction==w->faction) break; + if (bf==NULL) message_faction(b, w->faction, m); + } +} + +static void +fbattlerecord(battle * b, faction * f, const char *s) +{ + message * m = msg_message("battle_msg", "string", s); + message_faction(b, f, m); + msg_release(m); +} + +/* being an enemy or a friend is (and must always be!) symmetrical */ +#define enemy_i(as, di) (as->relations[di]&E_ENEMY) +#define friendly_i(as, di) (as->relations[di]&E_FRIEND) +#define enemy(as, ds) (as->relations[ds->index]&E_ENEMY) +#define friendly(as, ds) (as->relations[ds->index]&E_FRIEND) + +static boolean +set_enemy(side * as, side * ds, boolean attacking) +{ + int i; + for (i=0;i!=MAXSIDES;++i) { + if (ds->enemies[i]==NULL) ds->enemies[i]=as; + if (ds->enemies[i]==as) break; + } + for (i=0;i!=MAXSIDES;++i) { + if (as->enemies[i]==NULL) as->enemies[i]=ds; + if (as->enemies[i]==ds) break; + } + assert(i!=MAXSIDES); + if (attacking) as->relations[ds->index] |= E_ATTACKING; + if ((ds->relations[as->index] & E_ENEMY)==0) { + /* enemy-relation are always symmetrical */ + assert((as->relations[ds->index] & (E_ENEMY|E_FRIEND))==0); + ds->relations[as->index] |= E_ENEMY; + as->relations[ds->index] |= E_ENEMY; + return true; + } + return false; +} + +static void +set_friendly(side * as, side * ds) +{ + assert((as->relations[ds->index] & E_ENEMY)==0); + ds->relations[as->index] |= E_FRIEND; + as->relations[ds->index] |= E_FRIEND; +} + +static int +allysfm(const side * s, const faction * f, int mode) +{ + if (s->faction==f) return mode; + if (s->group) { + return alliedgroup(s->battle->plane, s->faction, f, s->group->allies, mode); + } + return alliedfaction(s->battle->plane, s->faction, f, mode); +} + +static int +allysf(const side * s, const faction * f) +{ + return allysfm(s, f, HELP_FIGHT); +} + +static int +dead_fighters(const fighter * df) +{ + return df->unit->number - df->alive - df->run.number; +} + +fighter * +select_corpse(battle * b, fighter * af) +/* Wählt eine Leiche aus, der af hilft. casualties ist die Anzahl der + * Toten auf allen Seiten (im Array). Wenn af == NULL, wird die + * Parteizugehörigkeit ignoriert, und irgendeine Leiche genommen. + * + * Untote werden nicht ausgewählt (casualties, not dead) */ +{ + int si, di, maxcasualties = 0; + fighter *df; + side *s; + + for (si=0;si!=b->nsides;++si) { + side * s = b->sides+si; + if (af==NULL || (!enemy_i(af->side, si) && allysf(af->side, s->faction))) { + maxcasualties += s->casualties; + } + } + di = rng_int() % maxcasualties; + for (s=b->sides;s!=b->sides+b->nsides;++s) { + for (df=s->fighters;df;df=df->next) { + /* Geflohene haben auch 0 hp, dürfen hier aber nicht ausgewählt + * werden! */ + int dead = dead_fighters(df); + if (!playerrace(df->unit->race)) continue; + + if (af && !helping(af->side, df->side)) + continue; + if (di < dead) { + return df; + } + di -= dead; + } + } + + return NULL; +} + +boolean +helping(const side * as, const side * ds) +{ + if (as->faction==ds->faction) return true; + return (boolean)(!enemy(as, ds) && allysf(as, ds->faction)); +} + +int +statusrow(int status) +{ + switch (status) { + case ST_AGGRO: + case ST_FIGHT: + return FIGHT_ROW; + case ST_BEHIND: + case ST_CHICKEN: + return BEHIND_ROW; + case ST_AVOID: + return AVOID_ROW; + case ST_FLEE: + return FLEE_ROW; + default: + assert(!"unknown combatrow"); + } + return FIGHT_ROW; +} + +static double +hpflee(int status) + /* if hp drop below this percentage, run away */ +{ + switch (status) { + case ST_AGGRO: + return 0.0; + case ST_FIGHT: + case ST_BEHIND: + return 0.2; + case ST_CHICKEN: + case ST_AVOID: + return 0.9; + case ST_FLEE: + return 1.0; + default: + assert(!"unknown combatrow"); + } + return 0.0; +} + +static int +get_row(const side * s, int row, const side * vs) +{ + boolean counted[MAXSIDES]; + int enemyfront = 0; + int line, result; + int retreat = 0; + int size[NUMROWS]; + int front = 0; + battle * b = s->battle; + + memset(counted, 0, sizeof(counted)); + memset(size, 0, sizeof(size)); + for (line=FIRST_ROW;line!=NUMROWS;++line) { + int si, sa_i; + /* how many enemies are there in the first row? */ + for (si=0;s->enemies[si];++si) { + side *se = s->enemies[si]; + if (se->size[line]>0) { + enemyfront += se->size[line]; + /* - s->nonblockers[line] (nicht, weil angreifer) */ + } + } + for (sa_i=0; sa_i!=b->nsides; ++sa_i) { + side * sa = b->sides+sa_i; + /* count people that like me, but don't like my enemy */ + if (friendly_i(s, sa_i) && enemy_i(vs, sa_i)) { + if (!counted[sa_i]) { + int i; + + for (i=0;i!=NUMROWS;++i) { + size[i] += sa->size[i] - sa->nonblockers[i]; + } + counted[sa_i] = true; + } + } + } + if (enemyfront) break; + } + if (enemyfront) { + for (line=FIRST_ROW;line!=NUMROWS;++line) { + front += size[line]; + if (!front || frontstatus); + if (vs==NULL) { + int i; + for (i=FIGHT_ROW;i!=row;++i) if (af->side->size[i]) break; + return FIGHT_ROW+(row-i); + } else { +#ifdef FASTROW + battle * b = vs->battle; + if (row!=b->rowcache.row || b->alive!=b->rowcache.alive || af->side!=b->rowcache.as || vs!=b->rowcache.vs) { + b->rowcache.alive = b->alive; + b->rowcache.as = af->side; + b->rowcache.vs = vs; + b->rowcache.row = row; + b->rowcache.result = get_row(af->side, row, vs); + return b->rowcache.result; + } +#ifdef DEBUG_FAST /* validation code */ + { + int i = get_row(af->side, row, vs); + assert(i==b->rowcache.result); + } +#endif + return b->rowcache.result; +#else + return get_row(af->side, row, vs); +#endif + } +} + +static void +reportcasualties(battle * b, fighter * fig, int dead) +{ + struct message * m; + region * r = NULL; + if (fig->alive == fig->unit->number) return; +#ifndef SIMPLE_ESCAPE + if (fig->run.region == NULL) { + fig->run.region = fleeregion(fig->unit); + if (fig->run.region == NULL) fig->run.region = b->region; + } + r = fig->run.region; +#endif /* SIMPLE_ESCAPE */ + m = msg_message("casualties", "unit runto run alive fallen", + fig->unit, r, fig->run.number, fig->alive, dead); + message_all(b, m); + msg_release(m); +} + +static int +contest_classic(int skilldiff, const armor_type * ar, const armor_type * sh) +{ + int p, vw = BASE_CHANCE - TDIFF_CHANGE * skilldiff; + double mod = 1.0; + + if (ar != NULL) + mod *= (1 + ar->penalty); + if (sh != NULL) + mod *= (1 + sh->penalty); + vw = (int)(100 - ((100 - vw) * mod)); + + do { + p = rng_int() % 100; + vw -= p; + } + while (vw >= 0 && p >= 90); + return (vw <= 0); +} + +/** new rule for Eressea 1.5 + * \param skilldiff - the attack skill with every modifier applied + */ +static int +contest_new(int skilldiff, const troop dt, const armor_type * ar, const armor_type * sh) +{ + double tohit = 0.5 + skilldiff * 0.1; + if (tohit<0.5) tohit = 0.5; + if (chance(tohit)) { + int defense = effskill(dt.fighter->unit, SK_STAMINA); + double tosave = defense * 0.05; + return !chance(tosave); + } + return 0; +} + +static int +contest(int skdiff, const troop dt, const armor_type * ar, const armor_type * sh) +{ + if (skill_formula==FORMULA_ORIG) { + return contest_classic(skdiff, ar, sh); + } else { + return contest_new(skdiff, dt, ar, sh); + } +} + +static boolean +is_riding(const troop t) { + if (t.fighter->building!=NULL) return false; + if (t.fighter->horses + t.fighter->elvenhorses > t.index) return true; + return false; +} + +static weapon * +preferred_weapon(const troop t, boolean attacking) +{ + weapon * missile = t.fighter->person[t.index].missile; + weapon * melee = t.fighter->person[t.index].melee; + if (attacking) { + if (melee==NULL || (missile && missile->attackskill>melee->attackskill)) { + return missile; + } + } else { + if (melee==NULL || (missile && missile->defenseskill>melee->defenseskill)) { + return missile; + } + } + return melee; +} + +static weapon * +select_weapon(const troop t, boolean attacking, boolean ismissile) + /* select the primary weapon for this trooper */ +{ + if (attacking) { + if (ismissile) { + /* from the back rows, have to use your missile weapon */ + return t.fighter->person[t.index].missile; + } + } else { + if (!ismissile) { + /* have to use your melee weapon if it's melee */ + return t.fighter->person[t.index].melee; + } + } + return preferred_weapon(t, attacking); +} + +static boolean +i_canuse(const unit * u, const item_type * itype) +{ + if (itype->canuse) { + return itype->canuse(u, itype); + } + return true; +} + +static int +weapon_skill(const weapon_type * wtype, const unit * u, boolean attacking) + /* the 'pure' skill when using this weapon to attack or defend. + * only undiscriminate modifiers (not affected by troops or enemies) + * are taken into account, e.g. no horses, magic, etc. */ +{ + int skill; + + if (wtype==NULL) { + skill = effskill(u, SK_WEAPONLESS); + if (skill<=0) { + /* wenn kein waffenloser kampf, dann den rassen-defaultwert */ + if (u->race == new_race[RC_ORC]) { + int sword = effskill(u, SK_MELEE); + int spear = effskill(u, SK_SPEAR); + skill = MAX(sword, spear) - 3; + if (attacking) { + skill = MAX(skill, u->race->at_default); + } else { + skill = MAX(skill, u->race->df_default); + } + } else { + if (attacking) { + skill = u->race->at_default; + } else { + skill = u->race->df_default; + } + } + } else { + /* der rassen-defaultwert kann höher sein als der Talentwert von + * waffenloser kampf */ + if (attacking) { + if (skill < u->race->at_default) skill = u->race->at_default; + } else { + if (skill < u->race->df_default) skill = u->race->df_default; + } + } + if (attacking) { + skill += u->race->at_bonus; + if (fval(u->region->terrain, SEA_REGION) && u->ship) skill += u->ship->type->at_bonus; + } else { + skill += u->race->df_bonus; + if (fval(u->region->terrain, SEA_REGION) && u->ship) skill += u->ship->type->df_bonus; + } + } else { + /* changed: if we own a weapon, we have at least a skill of 0 */ + if (!i_canuse(u, wtype->itype)) return -1; + skill = effskill(u, wtype->skill); + if (skill < wtype->minskill) skill = 0; + if (skill > 0) { + if (attacking) { + skill += u->race->at_bonus; + } else { + skill += u->race->df_bonus; + } + } + if (attacking) { + skill += wtype->offmod; + } else { + skill += wtype->defmod; + } + } + + return skill; +} + +static int CavalrySkill(void) +{ + static int skill = -1; + + if (skill<0) { + skill = get_param_int(global.parameters, "rules.cavalry.skill", 2); + } + return skill; +} + +#define BONUS_SKILL 1 +#define BONUS_DAMAGE 2 +static int +CavalryBonus(const unit * u, troop enemy, int type) +{ + static int mode = -1; + + if (mode<0) { + mode = get_param_int(global.parameters, "rules.cavalry.mode", 1); + } + if (mode==0) { + /* old rule, Eressea 1.0 compat */ + return (type==BONUS_SKILL)?2:0; + } else { + /* new rule, chargers in Eressea 1.1 */ + int skl = effskill(u, SK_RIDING); + /* only half against trolls */ + if (skl>0) { + if (type==BONUS_DAMAGE) { + int dmg = MIN(skl, 8); + if (enemy.fighter->unit->race==new_race[RC_TROLL]) { + dmg = dmg/4; + } else { + dmg = dmg/2; + } + return dmg; + } else { + skl = skl/2; + return MIN(skl, 4); + } + } + } + return 0; +} + +static int +weapon_effskill(troop t, troop enemy, const weapon * w, boolean attacking, boolean missile) + /* effektiver Waffenskill während des Kampfes */ +{ + /* In dieser Runde alle die Modifier berechnen, die fig durch die + * Waffen bekommt. */ + fighter * tf = t.fighter; + unit * tu = t.fighter->unit; + int skill; + const weapon_type * wtype = w?w->type:NULL; + + if (wtype==NULL) { + /* Ohne Waffe: Waffenlose Angriffe */ + skill = weapon_skill(NULL, tu, attacking); + } else { + if (attacking) { + skill = w->attackskill; + } else { + skill = w->defenseskill; + } + if (wtype->modifiers!=NULL) { + /* Pferdebonus, Lanzenbonus, usw. */ + int m; + unsigned int flags = WMF_SKILL|(attacking?WMF_OFFENSIVE:WMF_DEFENSIVE); + + if (is_riding(t)) flags |= WMF_RIDING; + else flags |= WMF_WALKING; + if (is_riding(enemy)) flags |= WMF_AGAINST_RIDING; + else flags |= WMF_AGAINST_WALKING; + + for (m=0;wtype->modifiers[m].value;++m) { + if ((wtype->modifiers[m].flags & flags) == flags) { + race_list * rlist = wtype->modifiers[m].races; + if (rlist!=NULL) { + while (rlist) { + if (rlist->data == tu->race) break; + rlist = rlist->next; + } + if (rlist==NULL) continue; + } + skill += wtype->modifiers[m].value; + } + } + } + } + + /* Burgenbonus, Pferdebonus */ + if (is_riding(t) && (wtype==NULL || (fval(wtype, WTF_HORSEBONUS) && !fval(wtype, WTF_MISSILE)))) { + skill += CavalryBonus(tu, enemy, BONUS_SKILL); + if (wtype) skill = skillmod(urace(tu)->attribs, tu, tu->region, wtype->skill, skill, SMF_RIDING); + } + + if (t.indexelvenhorses) { + /* Elfenpferde: Helfen dem Reiter, egal ob und welche Waffe. Das ist + * eleganter, und vor allem einfacher, sonst muß man noch ein + * WMF_ELVENHORSE einbauen. */ + skill += 2; + } + + if (skill>0 && !attacking && missile) { + /* + * Wenn ich verteidige, und nicht direkt meinem Feind gegenüberstehe, + * halbiert sich mein Skill: (z.B. gegen Fernkämpfer. Nahkämpfer + * können mich eh nicht treffen) + */ + skill /= 2; + } + return skill; +} + +static const armor_type * +select_armor(troop t, boolean shield) +{ + unsigned int type = shield?ATF_SHIELD:0; + unit * u = t.fighter->unit; + const armor * a = t.fighter->armors; + int geschuetzt = 0; + + /* some monsters should not use armor (dragons in chainmail? ha!) */ + if (!(u->race->battle_flags & BF_EQUIPMENT)) + return NULL; + + /* ... neither do werewolves */ + if (fval(u, UFL_WERE)) { + return NULL; + } + + for (;a;a=a->next) { + if ((a->atype->flags & ATF_SHIELD)==type) { + geschuetzt += a->count; + if (geschuetzt > t.index) { + /* unser Kandidat wird geschuetzt */ + return a->atype; + } + } + } + return NULL; +} + + +/* Hier ist zu beachten, ob und wie sich Zauber und Artefakte, die + * Rüstungschutz geben, addieren. + * - Artefakt I_TROLLBELT gibt Rüstung +1 + * - Zauber Rindenhaut gibt Rüstung +3 + */ +int +select_magicarmor(troop t) +{ + unit *u = t.fighter->unit; + int geschuetzt = 0; + int ma = 0; + + geschuetzt = MIN(get_item(u, I_TROLLBELT), u->number); + + if (geschuetzt > t.index) /* unser Kandidat wird geschuetzt */ + ma += 1; + + return ma; +} + +/* Sind side ds und Magier des meffect verbündet, dann return 1*/ +boolean +meffect_protection(battle * b, meffect * s, side * ds) +{ + if (!s->magician->alive) return false; + if (s->duration <= 0) return false; + if (enemy(s->magician->side, ds)) return false; + if (allysf(s->magician->side, ds->faction)) return true; + return false; +} + +/* Sind side as und Magier des meffect verfeindet, dann return 1*/ +boolean +meffect_blocked(battle *b, meffect *s, side *as) +{ + if (!s->magician->alive) return false; + if (s->duration <= 0) return false; + if (enemy(s->magician->side, as)) return true; + return false; +} + +/* rmfighter wird schon im PRAECOMBAT gebraucht, da gibt es noch keine + * troops */ +void +rmfighter(fighter *df, int i) +{ + side *ds = df->side; + + /* nicht mehr personen abziehen, als in der Einheit am Leben sind */ + assert(df->alive >= i); + assert(df->alive <= df->unit->number); + + /* erst ziehen wir die Anzahl der Personen von den Kämpfern in der + * Schlacht, dann von denen auf dieser Seite ab*/ + df->side->alive -= i; + df->side->battle->alive -= i; + + /* Dann die Kampfreihen aktualisieren */ + ds->size[SUM_ROW] -= i; + ds->size[statusrow(df->status)] -= i; + + /* Spezialwirkungen, z.B. Schattenritter */ + if (df->unit->race->battle_flags & BF_NOBLOCK) { + ds->nonblockers[SUM_ROW] -= i; + ds->nonblockers[statusrow(df->status)] -= i; + } + + /* und die Einheit selbst aktualisieren */ + df->alive -= i; +} + + +static void +rmtroop(troop dt) +{ + fighter *df = dt.fighter; + + /* troop ist immer eine einzele Person */ + rmfighter(df, 1); + + assert(dt.index >= 0 && dt.index < df->unit->number); + df->person[dt.index] = df->person[df->alive - df->removed]; + if (df->removed) { + df->person[df->alive - df->removed] = df->person[df->alive]; + } + df->person[df->alive].hp = 0; +} + +void +remove_troop(troop dt) +{ + fighter * df = dt.fighter; + struct person p = df->person[dt.index]; + battle * b = df->side->battle; +#ifdef FASTCOUNT + b->fast.alive = -1; /* invalidate cached value */ +#endif +#ifdef FASTROW + b->rowcache.alive = -1; /* invalidate cached value */ +#endif + ++df->removed; + ++df->side->removed; + df->person[dt.index] = df->person[df->alive-df->removed]; + df->person[df->alive - df->removed] = p; +} + +void +kill_troop(troop dt) +{ + fighter * df = dt.fighter; + unit * du = df->unit; + + rmtroop(dt); + if (!df->alive) { + char eqname[64]; + const struct equipment * eq; + if (du->race->itemdrop) { + item * drops = du->race->itemdrop(du->race, du->number-df->run.number); + + if (drops != NULL){ + i_merge(&du->items, &drops); + } + } + sprintf(eqname, "%s_spoils", du->race->_name[0]); + eq = get_equipment(eqname); + if (eq!=NULL) { + equip_items(&du->items, eq); + } + } +} + +/** reduces the target's exp by an equivalent of n points learning + * 30 points = 1 week + */ +void +drain_exp(struct unit *u, int n) +{ + skill_t sk = (skill_t)(rng_int() % MAXSKILLS); + skill_t ssk; + + ssk = sk; + + while (get_level(u, sk)==0) { + sk++; + if (sk == MAXSKILLS) + sk = 0; + if (sk == ssk) { + sk = NOSKILL; + break; + } + } + if (sk != NOSKILL) { + skill * sv = get_skill(u, sk); + while (n>0) { + if (n>=30*u->number) { + reduce_skill(u, sv, 1); + n-=30; + } else { + if (rng_int()%(30*u->number) 0.75) { + return "eine klaffende Wunde"; + } else if (q > 0.5) { + return "eine schwere Wunde"; + } else if (q > 0.25) { + return "eine Wunde"; + } + return "eine kleine Wunde"; +} + +static void vampirism(troop at, int damage) +{ + static int vampire = -1; + if (vampire<0) vampire = get_param_int(global.parameters, "rules.combat.demon_vampire", 0); + if (vampire>0) { + int gain = damage/vampire; + int chance = damage - vampire * gain; + if (chance>0 && (rng_int() % vampire < chance)) ++gain; + if (gain>0) { + int maxhp = unit_max_hp(at.fighter->unit); + at.fighter->person[at.index].hp = MIN(gain+at.fighter->person[at.index].hp, maxhp); + } + } +} + +static int +natural_armor(unit * du) +{ + static int * bonus = 0; + int an = du->race->armor; + if (bonus==0) { + bonus = calloc(sizeof(int), num_races); + } + if (bonus[du->race->index]==0) { + bonus[du->race->index] = get_param_int(du->race->parameters, "armor.stamina", -1); + if (bonus[du->race->index]==0) bonus[du->race->index] = -1; + } + if (bonus[du->race->index]>0) { + int sk = effskill(du, SK_STAMINA); + sk /= bonus[du->race->index]; + an += sk; + } + return an; +} + +boolean +terminate(troop dt, troop at, int type, const char *damage, boolean missile) +{ + item ** pitm; + fighter *df = dt.fighter; + fighter *af = at.fighter; + unit *au = af->unit; + unit *du = df->unit; + battle *b = df->side->battle; + int heiltrank = 0; + static int rule_armor = -1; + + /* Schild */ + void **si; + side *ds = df->side; + int hp; + + int ar = 0, an, am; + const armor_type * armor = select_armor(dt, true); + const armor_type * shield = select_armor(dt, false); + + const weapon_type *dwtype = NULL; + const weapon_type *awtype = NULL; + const weapon * weapon; + + int rda, sk = 0, sd; + boolean magic = false; + int da = dice_rand(damage); + + assert(du->number>0); +#ifdef SHOW_KILLS + ++at.fighter->hits; +#endif + + switch (type) { + case AT_STANDARD: + weapon = select_weapon(at, true, missile); + sk = weapon_effskill(at, dt, weapon, true, missile); + if (weapon) awtype = weapon->type; + if (awtype && fval(awtype, WTF_MAGICAL)) magic = true; + break; + case AT_NATURAL: + sk = weapon_effskill(at, dt, NULL, true, missile); + break; + case AT_SPELL: + case AT_COMBATSPELL: + magic = true; + break; + default: + break; + } + weapon = select_weapon(dt, false, true); /* missile=true to get the unmodified best weapon she has */ + sd = weapon_effskill(dt, at, weapon, false, false); + if (weapon!=NULL) dwtype=weapon->type; + + if (is_riding(at) && (awtype==NULL || (fval(awtype, WTF_HORSEBONUS) && !fval(awtype, WTF_MISSILE)))) { + da += CavalryBonus(au, dt, BONUS_DAMAGE); + } + + if (armor) { + ar += armor->prot; + if (armor->projectile>0 && chance(armor->projectile)) { + return false; + } + } + if (shield) { + ar += shield->prot; + if (shield->projectile>0 && chance(shield->projectile)) { + return false; + } + } + + /* natürliche Rüstung */ + an = natural_armor(du); + + /* magische Rüstung durch Artefakte oder Sprüche */ + /* Momentan nur Trollgürtel und Werwolf-Eigenschaft */ + am = select_magicarmor(dt); + +#if CHANGED_CROSSBOWS + if (awtype && fval(awtype, WTF_ARMORPIERCING)) { + /* crossbows */ + ar /= 2; + an /= 2; + } +#endif + + if (rule_armor<0) { + rule_armor = get_param_int(global.parameters, "rules.combat.nat_armor", 0); + } + if (rule_armor==0) { + /* natürliche Rüstung ist halbkumulativ */ + if (ar>0) { + ar += an/2; + } else { + ar = an; + } + } else { + /* use the higher value, add half the other value */ + ar = (ar>an)?(ar+an/2):(an+ar/2); + } + ar += am; + + if (type!=AT_COMBATSPELL && type!=AT_SPELL) { + if (damage_rules&DAMAGE_CRITICAL) { + double kritchance = (sk * 3 - sd) / 200.0; + + kritchance = MAX(kritchance, 0.005); + kritchance = MIN(0.9, kritchance); + + while (chance(kritchance)) { + if (bdebug) { + fprintf(bdebug, "%s/%d lands a critical hit\n", unitid(au), at.index); + } + da += dice_rand(damage); + } + } + + da += rc_specialdamage(au->race, du->race, awtype); + + if (awtype!=NULL && fval(awtype, WTF_MISSILE)) { + /* missile weapon bonus */ + if (damage_rules&DAMAGE_MISSILE_BONUS) { + da += af->person[at.index].damage_rear; + } + } else if (awtype==NULL) { + /* skill bonus for unarmed combat */ + if (damage_rules&DAMAGE_UNARMED_BONUS) { + da += effskill(au, SK_WEAPONLESS); + } + } else { + /* melee bonus */ + if (damage_rules&DAMAGE_MELEE_BONUS) { + da += af->person[at.index].damage; + } + } + + /* Skilldifferenzbonus */ + if (damage_rules&DAMAGE_SKILL_BONUS) { + da += MAX(0, (sk-sd)/DAMAGE_QUOTIENT); + } + } + + + if (magic) { + /* Magischer Schaden durch Spruch oder magische Waffe */ + double res = 1.0; + + /* magic_resistance gib x% Resistenzbonus zurück */ + res -= magic_resistance(du)*3.0; + + if (du->race->battle_flags & BF_EQUIPMENT) { +#ifdef TODO_RUNESWORD + /* Runenschwert gibt im Kampf 80% Resistenzbonus */ + if (dwp == WP_RUNESWORD) res -= 0.80; +#endif + /* der Effekt von Laen steigt nicht linear */ + if (armor && fval(armor, ATF_LAEN)) res *= (1-armor->magres); + if (shield && fval(shield, ATF_LAEN)) res *= (1-shield->magres); + if (dwtype) res *= (1-dwtype->magres); + } + + if (res > 0) { + da = (int) (MAX(da * res, 0)); + } + /* gegen Magie wirkt nur natürliche und magische Rüstung */ + ar = an+am; + } + + rda = MAX(da - ar,0); + + if ((du->race->battle_flags & BF_INV_NONMAGIC) && !magic) rda = 0; + else { + unsigned int i = 0; + if (du->race->battle_flags & BF_RES_PIERCE) i |= WTF_PIERCE; + if (du->race->battle_flags & BF_RES_CUT) i |= WTF_CUT; + if (du->race->battle_flags & BF_RES_BASH) i |= WTF_BLUNT; + + if (i && awtype && fval(awtype, i)) rda /= 2; + + /* Schilde */ + for (si = b->meffects.begin; si != b->meffects.end; ++si) { + meffect *meffect = *si; + if (meffect_protection(b, meffect, ds) != 0) { + assert(0 <= rda); /* rda sollte hier immer mindestens 0 sein */ + /* jeder Schaden wird um effect% reduziert bis der Schild duration + * Trefferpunkte aufgefangen hat */ + if (meffect->typ == SHIELD_REDUCE) { + hp = rda * (meffect->effect/100); + rda -= hp; + meffect->duration -= hp; + } + /* gibt Rüstung +effect für duration Treffer */ + if (meffect->typ == SHIELD_ARMOR) { + rda = MAX(rda - meffect->effect, 0); + meffect->duration--; + } + } + } + } + + assert(dt.indexnumber); + df->person[dt.index].hp -= rda; + if (au->race==new_race[RC_DAEMON]) { + vampirism(at, rda); + } + + if (df->person[dt.index].hp > 0) { /* Hat überlebt */ + if (bdebug) { + fprintf(bdebug, "Damage %d, armor %d: %d -> %d HP\n", + da, ar, df->person[dt.index].hp + rda, df->person[dt.index].hp); + } + if (au->race == new_race[RC_DAEMON]) { +#ifdef TODO_RUNESWORD + if (select_weapon(dt, 0, -1) == WP_RUNESWORD) continue; +#endif + if (!(df->person[dt.index].flags & (FL_COURAGE|FL_DAZZLED))) { + df->person[dt.index].flags |= FL_DAZZLED; + df->person[dt.index].defence--; + } + } + df->person[dt.index].flags = (df->person[dt.index].flags & ~FL_SLEEPING); + return false; + } + + /* Sieben Leben */ + if (du->race == new_race[RC_CAT] && (chance(1.0 / 7))) { + assert(dt.index>=0 && dt.indexnumber); + df->person[dt.index].hp = unit_max_hp(du); + return false; + } + + /* Heiltrank schluerfen und hoffen */ + if (oldpotiontype[P_HEAL]) { + if (get_effect(du, oldpotiontype[P_HEAL]) > 0) { + change_effect(du, oldpotiontype[P_HEAL], -1); + heiltrank = 1; + } else if (i_get(du->items, oldpotiontype[P_HEAL]->itype) > 0) { + i_change(&du->items, oldpotiontype[P_HEAL]->itype, -1); + change_effect(du, oldpotiontype[P_HEAL], 3); + heiltrank = 1; + } + if (heiltrank && (chance(0.50))) { + { + message * m = msg_message("battle::potionsave", "unit", du); + message_faction(b, du->faction, m); + msg_release(m); + } + assert(dt.index>=0 && dt.indexnumber); + df->person[dt.index].hp = du->race->hitpoints; + return false; + } + } +#ifdef SHOW_KILLS + ++at.fighter->kills; +#endif + + if (bdebug) { + fprintf(bdebug, "Damage %d, armor %d, type %d: %d -> %d HP, tot.\n", + da, ar, type, df->person[dt.index].hp + rda, df->person[dt.index].hp); + } + for (pitm=&du->items; *pitm; ) { + item * itm = *pitm; + const item_type * itype = itm->type; + if (!(itype->flags & ITF_CURSED) && dt.index < itm->number) { + /* 25% Grundchance, das ein Item kaputtgeht. */ + if (rng_int() % 4 < 1) { + i_change(pitm, itype, -1); + } + } + if (*pitm==itm) { + pitm = &itm->next; + } + } + kill_troop(dt); + + return true; +} + +static int +count_side(const side * s, const side * vs, int minrow, int maxrow, int select) +{ + fighter * fig; + int people = 0; + int unitrow[NUMROWS]; + + if (maxrowfighters; fig; fig = fig->next) { + if (fig->alive - fig->removed > 0) { + int row = statusrow(fig->status); + if (select&SELECT_ADVANCE) { + if (unitrow[row] == -1) { + unitrow[row] = get_unitrow(fig, vs); + } + row = unitrow[row]; + } + if (row >= minrow && row <= maxrow) { + people += fig->alive - fig->removed; + if (people>0 && (select&SELECT_FIND)) break; + } + } + } + return people; +} + +/* return the number of live allies warning: this function only considers +* troops that are still alive, not those that are still fighting although +* dead. */ +int +count_allies(const side * as, int minrow, int maxrow, int select, int allytype) +{ + battle *b = as->battle; + side *ds; + int count = 0; + + for (ds=b->sides;ds!=b->sides+b->nsides;++ds) { + if ((allytype==ALLY_ANY && helping(as, ds)) || (allytype==ALLY_SELF && as->faction==ds->faction)) { + count += count_side(ds, NULL, minrow, maxrow, select); + if (count>0 && (select&SELECT_FIND)) break; + } + } + return count; +} + +static int +count_enemies_i(battle * b, const fighter * af, int minrow, int maxrow, int select) +{ + side *es, *as = af->side; + int i = 0; + + for (es=b->sides;es!=b->sides+b->nsides;++es) { + if (as==NULL || enemy(es, as)) { + int offset = 0; + if (select&SELECT_DISTANCE) { + offset = get_unitrow(af, es) - FIGHT_ROW; + } + i += count_side(es, as, minrow-offset, maxrow-offset, select); + if (i>0 && (select&SELECT_FIND)) break; + } + } + return i; +} + +int +count_enemies(battle * b, const fighter * af, int minrow, int maxrow, int select) +{ +#ifdef FASTCOUNT + int sr = statusrow(af->status); + side *as = af->side; + + if (b->alive==b->fast.alive && as==b->fast.side && sr==b->fast.status && minrow==b->fast.minrow && maxrow==b->fast.maxrow) { + if (b->fast.enemies[select]>=0) { +#ifdef DEBUG_FAST + int i = count_enemies_i(b, af, minrow, maxrow, select); + assert(i==b->fast.enemies[select]); +#endif + return b->fast.enemies[select]; + } else if (select&SELECT_FIND) { + if (b->fast.enemies[select-SELECT_FIND]>=0) { +#ifdef DEBUG_FAST + int i = count_enemies_i(b, af, minrow, maxrow, select); + assert((i>0)==(b->fast.enemies[select-SELECT_FIND]>0)); +#endif + return b->fast.enemies[select-SELECT_FIND]; + } + } + } else if (select!=SELECT_FIND || b->alive!=b->fast.alive) { + b->fast.side = as; + b->fast.status = sr; + b->fast.minrow = minrow; + b->fast.alive=b->alive; + b->fast.maxrow = maxrow; + memset(b->fast.enemies, -1, sizeof(b->fast.enemies)); + } +#endif + if (maxrow>=FIRST_ROW) { + int i = count_enemies_i(b, af, minrow, maxrow, select); +#ifdef FASTCOUNT + b->fast.enemies[select] = i; +#endif + return i; + } + return 0; +} + +troop +select_enemy(fighter * af, int minrow, int maxrow, int select) +{ + side *as = af->side; + battle * b = as->battle; + int si, selected; + int enemies; +#ifdef DEBUG_SELECT + troop result = no_troop; +#endif + if (af->unit->race->flags & RCF_FLY) { + /* flying races ignore min- and maxrow and can attack anyone fighting + * them */ + minrow = FIGHT_ROW; + maxrow = BEHIND_ROW; + } + minrow = MAX(minrow, FIGHT_ROW); + + enemies = count_enemies(b, af, minrow, maxrow, select); + + /* Niemand ist in der angegebenen Entfernung? */ + if (enemies<=0) return no_troop; + + selected = rng_int() % enemies; + for (si=0;as->enemies[si];++si) { + side *ds = as->enemies[si]; + fighter * df; + int unitrow[NUMROWS]; + int offset = 0; + + if (select&SELECT_DISTANCE) offset = get_unitrow(af, ds) - FIGHT_ROW; + + if (select&SELECT_ADVANCE) { + int ui; + for (ui=0;ui!=NUMROWS;++ui) unitrow[ui] = -1; + } + + for (df=ds->fighters; df ; df = df->next) { + int dr; + + dr = statusrow(df->status); + if (select&SELECT_ADVANCE) { + if (unitrow[dr]<0) { + unitrow[dr] = get_unitrow(df, as); + } + dr = unitrow[dr]; + } + + if (select&SELECT_DISTANCE) dr += offset; + if (dr < minrow || dr > maxrow) continue; + if (df->alive - df->removed > selected) { +#ifdef DEBUG_SELECT + if (result.fighter==NULL) { + result.index = selected; + result.fighter = df; + } +#else + troop dt; + dt.index = selected; + dt.fighter = df; + return dt; +#endif + } + selected -= (df->alive - df->removed); + enemies -= (df->alive - df->removed); + } + } + if (enemies!=0) { + log_error(("select_enemies has a bug.\n")); + } +#ifdef DEBUG_SELECT + return result; +#else + assert(!selected); + return no_troop; +#endif +} + +static int +get_tactics(const side * as, const side * ds) +{ + battle * b = as->battle; + side *stac; + int result = 0; + int defense = 0; + + if (b->max_tactics > 0) { + for (stac=b->sides;stac!=b->sides+b->nsides;++stac) { + if (stac->leader.value > result && helping(stac, as)) { + assert(ds==NULL || !helping(stac, ds)); + result = stac->leader.value; + } + if (ds && stac->leader.value > defense && helping(stac, ds)) { + assert(!helping(stac, as)); + defense = stac->leader.value; + } + } + } + return result - defense; +} + +static troop +select_opponent(battle * b, troop at, int mindist, int maxdist) +{ + fighter * af = at.fighter; + troop dt; + + if (af->unit->race->flags & RCF_FLY) { + /* flying races ignore min- and maxrow and can attack anyone fighting + * them */ + dt = select_enemy(at.fighter, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); + } else { + mindist = MAX(mindist, FIGHT_ROW); + dt = select_enemy(at.fighter, mindist, maxdist, SELECT_ADVANCE); + } + + if (b->turn==0 && dt.fighter) { + int tactics_formula = -1; + + if (tactics_formula<0) { + tactics_formula = get_param_int(global.parameters, "rules.tactics.formula", 0); + } + if (tactics_formula==1) { + int tactics = get_tactics(at.fighter->side, dt.fighter->side); + + /* percentage chance to get this attack */ + if (tactics>0) { + double tacch = 0.1 * tactics; + if (fval(b->region->terrain, SEA_REGION)) { + ship * sh = at.fighter->unit->ship; + if (sh) tacch *= sh->type->tac_bonus; + } + if (!chance(tacch)) { + dt.fighter = NULL; + } + } else { + dt.fighter = NULL; + } + } + } + + return dt; +} + +/* + * Abfrage mit + * + * cvector *fgs=fighters(b,af,FIGHT_ROW,BEHIND_ROW, FS_HELP|FS_ENEMY); + * fighter *fig; + * + * Optional: Verwirbeln. Vorsicht: Aufwändig! + * v_scramble(fgs->begin, fgs->end); + * + * for (fig = fgs->begin; fig != fgs->end; ++fig) { + * fighter *df = *fig; + * + * } + * + * cv_kill(fgs); free(fgs); Nicht vergessen + */ + +cvector * +fighters(battle *b, const side * vs, int minrow, int maxrow, int mask) +{ + side * s; + cvector *fightervp = malloc(sizeof(cvector)); + + assert(vs!=NULL); + cv_init(fightervp); + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *fig; + + if (mask==FS_ENEMY) { + if (!enemy(s, vs)) continue; + } else if (mask==FS_HELP) { + if (enemy(s, vs) || !allysf(s, vs->faction)) { + continue; + } + } else { + assert(mask==(FS_HELP|FS_ENEMY) || !"invalid alliance state"); + } + for (fig = s->fighters; fig; fig = fig->next) { + int row = get_unitrow(fig, vs); + if (row >= minrow && row <= maxrow) { + cv_pushback(fightervp, fig); + } + } + } + + return fightervp; +} + +static void +report_failed_spell(battle * b, unit * mage, const spell * sp) +{ + message * m = msg_message("battle::spell_failed", "unit spell", mage, sp); + message_all(b, m); + msg_release(m); +} + +void +do_combatmagic(battle *b, combatmagic_t was) +{ + side * s; + region *r = b->region; + castorder *co; + int level, rank, sl; + spellrank spellranks[MAX_SPELLRANK]; + + memset(spellranks, 0, sizeof(spellranks)); + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter * fig; + for (fig = s->fighters; fig; fig = fig->next) { + unit * mage = fig->unit; + + if (fig->alive <= 0) continue; /* fighter kann im Kampf getötet worden sein */ + + level = eff_skill(mage, SK_MAGIC, r); + if (level > 0) { + double power; + const spell *sp; + const struct locale * lang = mage->faction->locale; + order * ord; + + switch(was) { + case DO_PRECOMBATSPELL: + sp = get_combatspell(mage, 0); + sl = get_combatspelllevel(mage, 0); + break; + case DO_POSTCOMBATSPELL: + sp = get_combatspell(mage, 2); + sl = get_combatspelllevel(mage, 2); + break; + default: + /* Fehler! */ + return; + } + if (sp == NULL) + continue; + + ord = create_order(K_CAST, lang, "'%s'", spell_name(sp, lang)); + if (cancast(mage, sp, 1, 1, ord) == false) { + free_order(ord); + continue; + } + + level = eff_spelllevel(mage, sp, level, 1); + if (sl > 0) level = MIN(sl, level); + if (level < 0) { + report_failed_spell(b, mage, sp); + free_order(ord); + continue; + } + + power = spellpower(r, mage, sp, level, ord); + free_order(ord); + if (power <= 0) { /* Effekt von Antimagie */ + report_failed_spell(b, mage, sp); + pay_spell(mage, sp, level, 1); + } else if (fumble(r, mage, sp, sp->level) == true) { + report_failed_spell(b, mage, sp); + pay_spell(mage, sp, level, 1); + } else { + co = new_castorder(fig, 0, sp, r, level, power, 0, 0, 0); + add_castorder(&spellranks[sp->rank], co); + } + } + } + } + for (rank = 0; rank < MAX_SPELLRANK; rank++) { + for (co = spellranks[rank].begin; co; co = co->next) { + fighter * fig = co->magician.fig; + const spell * sp = co->sp; + int level = co->level; + double power = co->force; + + if (sp->sp_function==NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + } else { + level = ((cspell_f)sp->sp_function)(fig, level, power, sp); + if (level > 0) { + pay_spell(fig->unit, sp, level, 1); + } + } + } + } + for (rank = 0; rank < MAX_SPELLRANK; rank++) { + free_castorders(spellranks[rank].begin); + } +} + +static void +combat_action(fighter * af, int turn) +{ +#ifndef SIMPLE_COMBAT + af->action_counter++; + af->side->bf->lastturn = turn; +#endif +} + + +static void +do_combatspell(troop at) +{ + const spell *sp; + fighter *fi = at.fighter; + unit *mage = fi->unit; + battle *b = fi->side->battle; + region *r = b->region; + int level; + double power; + int fumblechance = 0; + void **mg; + order * ord; + int sl; + const struct locale * lang = mage->faction->locale; + + sp = get_combatspell(mage, 1); + if (sp == NULL) { + fi->magic = 0; /* Hat keinen Kampfzauber, kämpft nichtmagisch weiter */ + return; + } + ord = create_order(K_CAST, lang, "'%s'", spell_name(sp, lang)); + if (cancast(mage, sp, 1, 1, ord) == false) { + fi->magic = 0; /* Kann nicht mehr Zaubern, kämpft nichtmagisch weiter */ + return; + } + + level = eff_spelllevel(mage, sp, fi->magic, 1); + if ((sl = get_combatspelllevel(mage, 1)) > 0) level = MIN(level, sl); + + if (fumble(r, mage, sp, sp->level) == true) { + report_failed_spell(b, mage, sp); + pay_spell(mage, sp, level, 1); + return; + } + + for (mg = b->meffects.begin; mg != b->meffects.end; ++mg) { + meffect *mblock = *mg; + if (mblock->typ == SHIELD_BLOCK) { + if (meffect_blocked(b, mblock, fi->side) != 0) { + fumblechance += mblock->duration; + mblock->duration -= mblock->effect; + } + } + } + + /* Antimagie die Fehlschlag erhöht */ + if (rng_int()%100 < fumblechance) { + report_failed_spell(b, mage, sp); + pay_spell(mage, sp, level, 1); + free_order(ord); + return; + } + power = spellpower(r, mage, sp, level, ord); + free_order(ord); + if (power <= 0) { /* Effekt von Antimagie */ + report_failed_spell(b, mage, sp); + pay_spell(mage, sp, level, 1); + return; + } + + if (sp->sp_function==NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + } else { + level = ((cspell_f)sp->sp_function)(fi, level, power, sp); + if (level > 0) { + pay_spell(mage, sp, level, 1); + combat_action(at.fighter, b->turn); + } + } +} + + +/* Sonderattacken: Monster patzern nicht und zahlen auch keine + * Spruchkosten. Da die Spruchstärke direkt durch den Level bestimmt + * wird, wirkt auch keine Antimagie (wird sonst in spellpower + * gemacht) */ + +static void +do_extra_spell(troop at, const att *a) +{ + const spell *sp = a->data.sp; + fighter *fi = at.fighter; + double power; + + power = sp->level * MagicPower(); + if (sp->sp_function==NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + } else { + ((cspell_f)sp->sp_function)(fi, sp->level, power, sp); + } +} + +static int +skilldiff(troop at, troop dt, int dist) +{ + fighter *af = at.fighter, *df = dt.fighter; + unit *au = af->unit, *du = df->unit; + int is_protected = 0, skdiff = 0; + weapon * awp = select_weapon(at, true, dist>1); + + skdiff += af->person[at.index].attack; + skdiff -= df->person[dt.index].defence; + + if (df->person[dt.index].flags & FL_SLEEPING) + skdiff += 2; + + /* Effekte durch Rassen */ + if (awp!=NULL && au->race == new_race[RC_HALFLING] && dragonrace(du->race)) { + skdiff += 5; + } + + if (au->race == new_race[RC_GOBLIN]) { + static int goblin_bonus = -1; + if (goblin_bonus<0) goblin_bonus = get_param_int(global.parameters, "rules.combat.goblinbonus", 10); + if (af->side->size[SUM_ROW] >= df->side->size[SUM_ROW] * goblin_bonus) { + skdiff += 1; + } + } + + if (df->building) { + boolean init = false; + static const curse_type * strongwall_ct, * magicwalls_ct; + if (!init) { + strongwall_ct = ct_find("strongwall"); + magicwalls_ct = ct_find("magicwalls"); + init=true; + } + if (df->building->type->protection) { + int beff = df->building->type->protection(df->building, du); + if (beff) { + skdiff -= beff; + is_protected = 2; + } + } + if (strongwall_ct) { + curse * c = get_curse(df->building->attribs, strongwall_ct); + if (curse_active(c)) { + /* wirkt auf alle Gebäude */ + skdiff -= curse_geteffect_int(c); + is_protected = 2; + } + } + if (magicwalls_ct && curse_active(get_curse(df->building->attribs, magicwalls_ct))) { + /* Verdoppelt Burgenbonus */ + skdiff -= buildingeffsize(df->building, false); + } + } + /* Goblin-Verteidigung + * ist direkt in der Rassentabelle als df_default + */ + + /* Effekte der Waffen */ + skdiff += weapon_effskill(at, dt, awp, true, dist>1); + if (awp && fval(awp->type, WTF_MISSILE)) { + skdiff -= is_protected; + if (awp->type->modifiers) { + int w; + for (w=0;awp->type->modifiers[w].value!=0;++w) { + if (awp->type->modifiers[w].flags & WMF_MISSILE_TARGET) { + /* skill decreases by targeting difficulty (bow -2, catapult -4) */ + skdiff -= awp->type->modifiers[w].value; + break; + } + } + } + } + if (skill_formula==FORMULA_ORIG) { + weapon * dwp = select_weapon(dt, false, dist>1); + skdiff -= weapon_effskill(dt, at, dwp, false, dist>1); + } + return skdiff; +} + +static int +setreload(troop at) +{ + fighter * af = at.fighter; + const weapon_type * wtype = af->person[at.index].missile->type; + if (wtype->reload == 0) return 0; + return af->person[at.index].reload = wtype->reload; +} + +int +getreload(troop at) +{ + return at.fighter->person[at.index].reload; +} + +static void +debug_hit(troop at, const weapon * awp, troop dt, const weapon * dwp, int skdiff, int dist, boolean success) +{ + fprintf(bdebug, "%.4s/%d [%6s/%d] %s %.4s/%d [%6s/%d] with %d, distance %d\n", + unitid(at.fighter->unit), at.index, + LOC(default_locale, awp ? resourcename(awp->type->itype->rtype, 0) : "unarmed"), + weapon_effskill(at, dt, awp, true, dist>1), + success?"hits":"misses", + unitid(dt.fighter->unit), dt.index, + LOC(default_locale, dwp ? resourcename(dwp->type->itype->rtype, 0) : "unarmed"), + weapon_effskill(dt, at, dwp, false, dist>1), + skdiff, dist); +} + +int +hits(troop at, troop dt, weapon * awp) +{ + fighter *af = at.fighter, *df = dt.fighter; + const armor_type * armor, * shield = 0; + int skdiff = 0; + int dist = get_unitrow(af, df->side) + get_unitrow(df, af->side) - 1; + weapon * dwp = select_weapon(dt, false, dist>1); + + if (!df->alive) return 0; + if (getreload(at)) return 0; + if (dist>1 && (awp == NULL || !fval(awp->type, WTF_MISSILE))) return 0; + + /* mark this person as hit. */ + df->person[dt.index].flags |= FL_HIT; + + if (af->person[at.index].flags & FL_STUNNED) { + af->person[at.index].flags &= ~FL_STUNNED; + return 0; + } + if ((af->person[at.index].flags & FL_TIRED && rng_int()%100 < 50) + || (af->person[at.index].flags & FL_SLEEPING)) + return 0; + + /* effect of sp_reeling_arrows combatspell */ + if (af->side->battle->reelarrow && awp && fval(awp->type, WTF_MISSILE) && rng_double() < 0.5) { + return 0; + } + + skdiff = skilldiff(at, dt, dist); + /* Verteidiger bekommt eine Rüstung */ + armor = select_armor(dt, true); + if (dwp==NULL || (dwp->type->flags & WTF_USESHIELD)) { + shield = select_armor(dt, false); + } + if (contest(skdiff, dt, armor, shield)) { + if (bdebug) { + debug_hit(at, awp, dt, dwp, skdiff, dist, true); + } + return 1; + } + if (bdebug) { + debug_hit(at, awp, dt, dwp, skdiff, dist, false); + } + return 0; +} + +void +dazzle(battle *b, troop *td) +{ + /* Nicht kumulativ ! */ + if(td->fighter->person[td->index].flags & FL_DAZZLED) return; + +#ifdef TODO_RUNESWORD + if (td->fighter->weapon[WP_RUNESWORD].count > td->index) { + return; + } +#endif + if (td->fighter->person[td->index].flags & FL_COURAGE) { + return; + } + + if (td->fighter->person[td->index].flags & FL_DAZZLED) { + return; + } + + td->fighter->person[td->index].flags |= FL_DAZZLED; + td->fighter->person[td->index].defence--; +} + +/* TODO: Gebäude/Schiffe sollten auch zerstörbar sein. Schwierig im Kampf, + * besonders bei Schiffen. */ + +void +damage_building(battle *b, building *bldg, int damage_abs) +{ + bldg->size = MAX(1, bldg->size-damage_abs); + + /* Wenn Burg, dann gucken, ob die Leute alle noch in das Gebäude passen. */ + + if (bldg->type->protection) { + side * s; + + bldg->sizeleft = bldg->size; + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter * fig; + for (fig=s->fighters;fig;fig=fig->next) { + if (fig->building == bldg) { + if (bldg->sizeleft >= fig->unit->number) { + fig->building = bldg; + bldg->sizeleft -= fig->unit->number; + } else { + fig->building = NULL; + } + } + } + } + } +} + +static int +attacks_per_round(troop t) +{ + return t.fighter->person[t.index].speed; +} + +static void +make_heroes(battle * b) +{ + side * s; + static int hero_speed = 0; + if (hero_speed==0) { + hero_speed = get_param_int(global.parameters, "rules.combat.herospeed", 10); + } + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter * fig; + for (fig=s->fighters;fig;fig=fig->next) { + unit * u = fig->unit; + if (fval(u, UFL_HERO)) { + int i; + assert(playerrace(u->race)); + for (i=0;i!=u->number;++i) { + fig->person[i].speed += (hero_speed-1); + } + } + } + } +} + +static void +attack(battle *b, troop ta, const att *a, int numattack) +{ + fighter *af = ta.fighter; + troop td; + unit *au = af->unit; + + switch(a->type) { + case AT_COMBATSPELL: + /* Magier versuchen immer erstmal zu zaubern, erst wenn das + * fehlschlägt, wird af->magic == 0 und der Magier kämpft + * konventionell weiter */ + if (numattack==0 && af->magic > 0) { + /* wenn der magier in die potenzielle Reichweite von Attacken des + * Feindes kommt, beginnt er auch bei einem Status von KAEMPFE NICHT, + * Kampfzauber zu schleudern: */ + if (count_enemies(b, af, melee_range[0], missile_range[1], SELECT_ADVANCE|SELECT_DISTANCE|SELECT_FIND)) { + do_combatspell(ta); + } + } + break; + case AT_STANDARD: /* Waffen, mag. Gegenstände, Kampfzauber */ + if (numattack > 0 || af->magic <= 0) { + weapon * wp = ta.fighter->person[ta.index].missile; + int melee = count_enemies(b, af, melee_range[0], melee_range[1], SELECT_ADVANCE|SELECT_DISTANCE|SELECT_FIND); + if (melee) wp = preferred_weapon(ta, true); + /* Sonderbehandlungen */ + + if (getreload(ta)) { + ta.fighter->person[ta.index].reload--; + } else { + boolean standard_attack = true; + boolean reload = false; + /* spezialattacken der waffe nur, wenn erste attacke in der runde. + * sonst helden mit feuerschwertern zu mächtig */ + if (numattack==0 && wp && wp->type->attack) { + int dead = 0; + standard_attack = wp->type->attack(&ta, wp->type, &dead); + if (!standard_attack) reload = true; + af->catmsg += dead; + if (!standard_attack && af->person[ta.index].last_action < b->turn) { + af->person[ta.index].last_action = b->turn; + combat_action(af, b->turn); + } + } + if (standard_attack) { + boolean missile = false; + if (wp && fval(wp->type, WTF_MISSILE)) missile = true; + if (missile) { + td = select_opponent(b, ta, missile_range[0], missile_range[1]); + } + else { + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + } + if (!td.fighter) return; + if (ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + reload = true; + if (hits(ta, td, wp)) { + const char * d; + if (wp == NULL) d = au->race->def_damage; + else if (is_riding(ta)) d = wp->type->damage[1]; + else d = wp->type->damage[0]; + terminate(td, ta, a->type, d, missile); + } + } + if (reload && wp && wp->type->reload && !getreload(ta)) { + int i = setreload(ta); + if (bdebug) { + fprintf(bdebug, "%s/%d reloading %d turns\n", unitid(au), ta.index, i); + } + } + } + } + break; + case AT_SPELL: /* Extra-Sprüche. Kampfzauber in AT_COMBATSPELL! */ + do_extra_spell(ta, a); + break; + case AT_NATURAL: + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + if (!td.fighter) return; + if(ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + if (hits(ta, td, NULL)) { + terminate(td, ta, a->type, a->data.dice, false); + } + break; + case AT_DRAIN_ST: + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + if (!td.fighter) return; + if(ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + if (hits(ta, td, NULL)) { + int c = dice_rand(a->data.dice); + while(c > 0) { + if (rng_int()%2) { + td.fighter->person[td.index].attack -= 1; + } else { + td.fighter->person[td.index].defence -= 1; + } + c--; + } + } + break; + case AT_DRAIN_EXP: + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + if (!td.fighter) return; + if(ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + if (hits(ta, td, NULL)) { + drain_exp(td.fighter->unit, dice_rand(a->data.dice)); + } + break; + case AT_DAZZLE: + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + if (!td.fighter) return; + if(ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + if (hits(ta, td, NULL)) { + dazzle(b, &td); + } + break; + case AT_STRUCTURAL: + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + if (!td.fighter) return; + if(ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + if (td.fighter->unit->ship) { + td.fighter->unit->ship->damage += DAMAGE_SCALE * dice_rand(a->data.dice); + } else if (td.fighter->unit->building) { + damage_building(b, td.fighter->unit->building, dice_rand(a->data.dice)); + } + } +} + +void +do_attack(fighter * af) +{ + troop ta; + unit *au = af->unit; + side *side = af->side; + battle *b = side->battle; + + ta.fighter = af; + + assert(au && au->number); + /* Da das Zuschlagen auf Einheiten und nicht auf den einzelnen + * Kämpfern beruht, darf die Reihenfolge und Größe der Einheit keine + * Rolle spielen, Das tut sie nur dann, wenn jeder, der am Anfang der + * Runde lebte, auch zuschlagen darf. Ansonsten ist der, der zufällig + * mit einer großen Einheit zuerst drankommt, extrem bevorteilt. */ + ta.index = af->fighting; + + while (ta.index--) { + /* Wir suchen eine beliebige Feind-Einheit aus. An der können + * wir feststellen, ob noch jemand da ist. */ + int apr, attacks = attacks_per_round(ta); + if (!count_enemies(b, af, FIGHT_ROW, LAST_ROW, SELECT_FIND)) break; + + for (apr=0;apr!=attacks;++apr) { + int a; + for (a=0; a!=10 && au->race->attack[a].type!=AT_NONE; ++a) { + if (apr>0) { + /* Wenn die Waffe nachladen muss, oder es sich nicht um einen + * Waffen-Angriff handelt, dann gilt der Speed nicht. */ + if (au->race->attack[a].type!=AT_STANDARD) continue; + else { + weapon * wp = preferred_weapon(ta, true); + if (wp!=NULL && wp->type->reload) continue; + } + } + attack(b, ta, &(au->race->attack[a]), apr); + } + } + } + /* Der letzte Katapultschütze setzt die + * Ladezeit neu und generiert die Meldung. */ + if (af->catmsg>=0) { + struct message * m = msg_message("battle::killed", "unit dead", au, af->catmsg); + message_all(b, m); + msg_release(m); + af->catmsg = -1; + } +} + +void +do_regenerate(fighter *af) +{ + troop ta; + unit *au = af->unit; + + ta.fighter = af; + ta.index = af->fighting; + + while(ta.index--) { + af->person[ta.index].hp += effskill(au, SK_STAMINA); + af->person[ta.index].hp = MIN(unit_max_hp(au), af->person[ta.index].hp); + } +} + +static void +add_tactics(tactics * ta, fighter * fig, int value) +{ + if (value == 0 || value < ta->value) + return; + if (value > ta->value) + cv_kill(&ta->fighters); + cv_pushback(&ta->fighters, fig); + cv_pushback(&fig->side->battle->leaders, fig); + ta->value = value; +} + +static double horsebonus(const unit * u) +{ + static const item_type * it_horse = 0; + static const item_type * it_elvenhorse = 0; + static const item_type * it_charger = 0; + region * r = u->region; + int n1 = 0, n2 = 0, n3 = 0; + item * itm = u->items; + int skl = eff_skill(u, SK_RIDING, r); + + if (skl<1) return 0.0; + + if (it_horse==0) { + it_horse = it_find("horse"); + it_elvenhorse = it_find("elvenhorse"); + it_charger = it_find("charger"); + } + + for (;itm;itm=itm->next) { + if (itm->type->flags&ITF_ANIMAL) { + if (itm->type==it_elvenhorse) n3 +=itm->number; + else if (itm->type==it_charger) n2 +=itm->number; + else if (itm->type==it_horse) n1 +=itm->number; + } + } + if (skl >= 5 && n3>=u->number) return 0.30; + if (skl >= 3 && n2+n3>=u->number) return 0.20; + if (skl >= 1 && n1+n2+n3>=u->number) return 0.10; + return 0.0F; +} + +double +fleechance(unit * u) +{ + double c = 0.20; /* Fluchtwahrscheinlichkeit in % */ + region * r = u->region; + attrib * a = a_find(u->attribs, &at_fleechance); + /* Einheit u versucht, dem Getümmel zu entkommen */ + + c += (eff_skill(u, SK_STEALTH, r) * 0.05); + c += horsebonus(u); + + if (u->race == new_race[RC_HALFLING]) { + c += 0.20; + c = MIN(c, 0.90); + } else { + c = MIN(c, 0.75); + } + + if (a!=NULL) c += a->data.flt; + + return c; +} + +/** add a new army to the conflict + * beware: armies need to be added _at the beginning_ of the list because + * otherwise join_allies() will get into trouble */ +static side * +make_side(battle * b, const faction * f, const group * g, unsigned int flags, const faction *stealthfaction) +{ + side *s1 = b->sides+b->nsides; + bfaction * bf; + +#ifdef SIMPLE_COMBAT + if (fval(b->region->terrain, SEA_REGION)) { + /* every fight in an ocean is short */ + flags |= SIDE_HASGUARDS; + } else { + unit * u; + for (u = b->region->units; u; u = u->next) { + if (is_guard(u, HELP_ALL)) { + if (alliedunit(u, f, HELP_GUARD)) { + flags |= SIDE_HASGUARDS; + break; + } + } + } + } +#endif + + s1->battle = b; + s1->group = g; + s1->flags = flags; + s1->stealthfaction = stealthfaction; + for (bf = b->factions;bf;bf=bf->next) { + faction * f2 = bf->faction; + + if (f2 == f) { + s1->bf = bf; + s1->faction = f2; + s1->index = b->nsides++; + s1->nextF = bf->sides; + bf->sides = s1; + assert(b->nsides<=MAXSIDES); + break; + } + } + assert(bf); + return s1; +} + +troop +select_ally(fighter * af, int minrow, int maxrow, int allytype) +{ + side *as = af->side; + battle *b = as->battle; + side * ds; + int allies = count_allies(as, minrow, maxrow, SELECT_ADVANCE, allytype); + + if (!allies) { + return no_troop; + } + allies = rng_int() % allies; + + for (ds=b->sides;ds!=b->sides+b->nsides;++ds) { + if ((allytype==ALLY_ANY && helping(as, ds)) || (allytype==ALLY_SELF && as->faction==ds->faction)) { + fighter * df; + for (df=ds->fighters; df; df=df->next) { + int dr = get_unitrow(df, NULL); + if (dr >= minrow && dr <= maxrow) { + if (df->alive - df->removed > allies) { + troop dt; + assert(allies>=0); + dt.index = allies; + dt.fighter = df; + return dt; + } + allies -= df->alive; + } + } + } + } + assert(!"we should never have gotten here"); + return no_troop; +} + + +static int loot_quota(const unit * src, const unit * dst, const item_type * type, int n) +{ + static float divisor = -1; + if (dst && src && src->faction!=dst->faction) { + if (divisor<0) { + divisor = get_param_flt(global.parameters, "rules.items.loot_divisor", 1); + assert(divisor==0 || divisor>=1); + } + if (divisor>=1) { + double r = n / divisor; + int x = (int)r; + + r = r - x; + if (chance(r)) ++x; + + return x; + } + } + return n; +} + +static void +loot_items(fighter * corpse) +{ + unit * u = corpse->unit; + item * itm = u->items; + battle * b = corpse->side->battle; + int dead = dead_fighters(corpse); + + if (dead<=0) return; + + while (itm) { + float lootfactor = dead/(float)u->number; /* only loot the dead! */ + int maxloot = (int)(itm->number*lootfactor); + if (maxloot>0) { + int i = MIN(10, maxloot); + for (; i != 0; --i) { + int loot = maxloot/i; + + if (loot>0) { + fighter *fig = NULL; + int looting = 0; + int maxrow = 0; + /* mustloot: we absolutely, positively must have somebody loot this thing */ + int mustloot = itm->type->flags & (ITF_CURSED|ITF_NOTLOST); + + itm->number -= loot; + maxloot -= loot; + + if (is_monsters(u->faction) && (loot_rules & LOOT_MONSTERS)) { + looting = 1; + } else if (loot_rules&LOOT_OTHERS) { + looting = 1; + } else if (loot_rules&LOOT_SELF) { + looting = 2; + } + if (looting) { + if (mustloot) { + maxrow = LAST_ROW; + } else if (loot_rules&LOOT_KEEPLOOT) { + int lootchance = 50 + b->keeploot; + if (rng_int() % 100 < lootchance) { + maxrow = BEHIND_ROW; + } + } else { + maxrow = LAST_ROW; + } + } + if (maxrow>0) { + if (looting==1) { + /* enemies get dibs */ + fig = select_enemy(corpse, FIGHT_ROW, maxrow, 0).fighter; + } + if (!fig) { + /* self and allies get second pick */ + fig = select_ally(corpse, FIGHT_ROW, LAST_ROW, ALLY_SELF).fighter; + } + } + + if (fig) { + int trueloot = mustloot?loot:loot_quota(corpse->unit, fig->unit, itm->type, loot); + if (trueloot>0) { + item * l = fig->loot; + while (l && l->type!=itm->type) l=l->next; + if (!l) { + l = calloc(sizeof(item), 1); + l->next = fig->loot; + fig->loot = l; + l->type = itm->type; + } + l->number += trueloot; + } + } + } + } + } + itm = itm->next; + } +} + +#ifndef SIMPLE_ESCAPE +static void +loot_fleeing(fighter* fig, unit* runner) +{ + /* TODO: Vernünftig fixen */ + runner->items = NULL; + assert(runner->items == NULL); + runner->items = fig->run.items; + fig->run.items = NULL; +} + +static void +merge_fleeloot(fighter* fig, unit* u) +{ + i_merge(&u->items, &fig->run.items); +} +#endif /* SIMPLE_ESCAPE */ + +static boolean +seematrix(const faction * f, const side * s) +{ + if (f==s->faction) return true; + if (s->flags & SIDE_STEALTH) return false; + return true; +} + +static double +PopulationDamage(void) +{ + static double value = -1.0; + if (value<0) { + int damage = get_param_int(global.parameters, "rules.combat.populationdamage", BATTLE_KILLS_PEASANTS); + value = damage/100.0; + } + return value; +} + + +static void +battle_effects(battle * b, int dead_players) +{ + region * r = b->region; + int dead_peasants = MIN(rpeasants(r), (int)(dead_players*PopulationDamage())); + if (dead_peasants) { + deathcounts(r, dead_peasants + dead_players); + chaoscounts(r, dead_peasants / 2); + rsetpeasants(r, rpeasants(r) - dead_peasants); + } +} + +static void +reorder_fleeing(region * r) +{ + unit **usrc = &r->units; + unit **udst = &r->units; + unit *ufirst = NULL; + unit *u; + + for (;*udst;udst=&u->next) { + u = *udst; + } + + for (u=*usrc;u!=ufirst;u=*usrc) { + if (u->next && fval(u, UFL_FLEEING)) { + *usrc = u->next; + *udst = u; + udst = &u->next; + if (!ufirst) ufirst = u; + } else { + usrc = &u->next; + } + } + *udst = NULL; +} + +static void +aftermath(battle * b) +{ + int i; + region *r = b->region; + ship *sh; + side *s; + int dead_players = 0; + bfaction * bf; + boolean ships_damaged = (boolean)(b->turn+(b->has_tactics_turn?1:0)>2); /* only used for ship damage! */ + +#ifdef TROLLSAVE + int *trollsave = calloc(2 * cv_size(&b->factions), sizeof(int)); +#endif + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter * df; + for (df = s->fighters; df; df=df->next) { + unit *du = df->unit; + int dead = dead_fighters(df); + int pr_mercy = 0; + +#ifdef TROLLSAVE + /* Trolle können regenerieren */ + if (df->alive > 0 && dead>0 && du->race == new_race[RC_TROLL]) { + for (i = 0; i != dead; ++i) { + if (chance(TROLL_REGENERATION)) { + ++df->alive; + ++s->alive; + ++s->battle->alive; + ++trollsave[s->index]; + /* do not change dead here, or loop will not terminate! recalculate later */ + } + } + dead = dead_fighters(df); + } +#endif + /* Regeneration durch PR_MERCY */ + if (dead>0 && pr_mercy) { + for (i = 0; i != dead; ++i) { + if (rng_int()%100 < pr_mercy) { + ++df->alive; + ++s->alive; + ++s->battle->alive; + /* do not change dead here, or loop will not terminate! recalculate later */ + } + } + dead = dead_fighters(df); + } + + /* tote insgesamt: */ + s->dead += dead; + /* Tote, die wiederbelebt werde können: */ + if (playerrace(df->unit->race)) { + s->casualties += dead; + } +#ifdef SHOW_KILLS + if (df->hits + df->kills) { + struct message * m = msg_message("killsandhits", "unit hits kills", du, df->hits, df->kills); + message_faction(b, du->faction, m); + msg_release(m); + } +#endif + } + } + + /* POSTCOMBAT */ + do_combatmagic(b, DO_POSTCOMBATSPELL); + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + int snumber = 0; + fighter *df; + boolean relevant = false; /* Kampf relevant für diese Partei? */ +#ifdef SIMPLE_COMBAT + if (fval(s, SIDE_HASGUARDS) == 0) relevant = true; +#else + if (s->bf->lastturn>1) { + relevant = true; + } else if (s->bf->lastturn==1 && b->has_tactics_turn) { + side * stac; + for (stac=b->sides; stac; stac=stac->next) { + if (stac->leader.value == b->max_tactics && helping(stac, s)) { + relevant = true; + break; + } + } + } +#endif + s->flee = 0; + + for (df=s->fighters;df;df=df->next) { + unit *du = df->unit; + int dead = dead_fighters(df); + int sum_hp = 0; + int n; + + for (n = 0; n != df->alive; ++n) { + if (df->person[n].hp > 0) { + sum_hp += df->person[n].hp; + } + } + snumber += du->number; +#ifdef SIMPLE_COMBAT + if (relevant) { + int flags = UFL_LONGACTION|UFL_NOTMOVING; +#ifdef SIMPLE_ESCAPE + if (du->status==ST_FLEE) flags -= UFL_NOTMOVING; +#endif /* SIMPLE_ESCAPE */ + fset(du, flags); + } + if (sum_hp+df->run.hphp) { + /* someone on the ship got damaged, damage the ship */ + ship * sh = du->ship?du->ship:leftship(du); + if (sh) fset(sh, SF_DAMAGED); + } +#else + if (relevant) { + fset(du, UFL_NOTMOVING); /* unit cannot move this round */ + if (df->action_counter >= du->number) { + ship * sh = du->ship?du->ship:leftship(du); + if (sh) fset(sh, SF_DAMAGED); + fset(du, UFL_LONGACTION); + } + } +#endif + + if (df->alive == du->number) { + du->hp = sum_hp; + continue; /* nichts passiert */ + } else if (df->run.hp) { + if (df->alive == 0) { + /* Report the casualties */ + reportcasualties(b, df, dead); + + /* Zuerst dürfen die Feinde plündern, die mitgenommenen Items + * stehen in fig->run.items. Dann werden die Fliehenden auf + * die leere (tote) alte Einheit gemapt */ +#ifdef SIMPLE_ESCAPE + if (!fval(df, FIG_NOLOOT)) { + loot_items(df); + } +#else + if (fval(df, FIG_NOLOOT)){ + merge_fleeloot(df, du); + } else { + loot_items(df); + loot_fleeing(df, du); + } +#endif /* SIMPLE_ESCAPE */ + scale_number(du, df->run.number); + du->hp = df->run.hp; + setguard(du, GUARD_NONE); + /* must leave ships or buildings, or a stealthy hobbit + * can hold castles indefinitely */ + if (!fval(r->terrain, SEA_REGION)) { + leave(du, true); /* even region owners have to flee */ + } +#ifndef SIMPLE_ESCAPE + if (df->run.region) { + run_to(du, df->run.region); + df->run.region = du->region; + } + fset(du, UFL_LONGACTION|UFL_NOTMOVING); +#endif /* SIMPLE_ESCAPE */ + fset(du, UFL_FLEEING); + } else { + /* nur teilweise geflohene Einheiten mergen sich wieder */ + df->alive += df->run.number; + s->size[0] += df->run.number; + s->size[statusrow(df->status)] += df->run.number; + s->alive += df->run.number; + sum_hp += df->run.hp; +#ifndef SIMPLE_ESCAPE + merge_fleeloot(df, du); +#endif /* SIMPLE_ESCAPE */ + df->run.number = 0; + df->run.hp = 0; + /* df->run.region = NULL;*/ + + reportcasualties(b, df, dead); + + scale_number(du, df->alive); + du->hp = sum_hp; + } + } else { + if (df->alive==0) { + /* alle sind tot, niemand geflohen. Einheit auflösen */ + df->run.number = 0; + df->run.hp = 0; +#ifndef SIMPLE_ESCAPE + df->run.region = NULL; +#endif /* SIMPLE_ESCAPE */ + + /* Report the casualties */ + reportcasualties(b, df, dead); + + /* Distribute Loot */ + loot_items(df); + + setguard(du, GUARD_NONE); + scale_number(du, 0); + } else { + df->run.number = 0; + df->run.hp = 0; + + reportcasualties(b, df, dead); + + scale_number(du, df->alive); + du->hp = sum_hp; + } + } + s->flee += df->run.number; + + if (playerrace(du->race)) { + /* tote im kampf werden zu regionsuntoten: + * for each of them, a peasant will die as well */ + dead_players += dead; + } + if (du->hp < du->number) { + log_error(("%s has less hitpoints (%u) than people (%u)\n", + itoa36(du->no), du->hp, du->number)); + du->hp = du->number; + } + } + s->alive+=s->healed; + assert(snumber==s->flee+s->alive+s->dead); + } + + battle_effects(b, dead_players); + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + message * seen = msg_message("battle::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", + "index abbrev dead fled survived", + army_index(s), "-?-", s->dead, s->flee, s->alive); + + for (bf=b->factions;bf;bf=bf->next) { + faction * f = bf->faction; + message * m = seematrix(f, s)?seen:unseen; + + message_faction(b, f, m); + } + + msg_release(seen); + msg_release(unseen); + } + + /* Wir benutzen drifted, um uns zu merken, ob ein Schiff + * schonmal Schaden genommen hat. (moved und drifted + * sollten in flags überführt werden */ + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *df; + + for (df=s->fighters; df; df=df->next) { + unit *du = df->unit; + item * l; + + /* Beute verteilen */ + for (l=df->loot; l; l=l->next) { + const item_type * itype = l->type; + message * m = msg_message("battle_loot", "unit amount item", du, l->number, itype->rtype); + message_faction(b, du->faction, m); + msg_release(m); + i_change(&du->items, itype, l->number); + } + + /* Wenn sich die Einheit auf einem Schiff befindet, wird + * dieses Schiff beschädigt. Andernfalls ein Schiff, welches + * evt. zuvor verlassen wurde. */ + if (ships_damaged) { + if (du->ship) sh = du->ship; + else sh = leftship(du); + + if (sh && fval(sh, SF_DAMAGED)) { + int n = b->turn - 2; + if (n>0) { + damage_ship(sh, 0.05 * n); + freset(sh, SF_DAMAGED); + } + } + } + } + } + + if (ships_damaged) { + ship **sp = &r->ships; + + while (*sp) { + ship * sh = *sp; + freset(sh, SF_DAMAGED); + if (sh->damage >= sh->size * DAMAGE_SCALE) { + remove_ship(sp, sh); + } + if (*sp==sh) sp=&sh->next; + } + } +#ifdef TROLLSAVE + free(trollsave); +#endif + + reorder_fleeing(r); + + if (bdebug) { + fprintf(bdebug, "The battle lasted %d turns, %s and %s.\n", + b->turn, + b->has_tactics_turn?"had a tactic turn":"had no tactic turn", + ships_damaged?"was relevant":"was not relevant."); + } +} + +static void +battle_punit(unit * u, battle * b) +{ + bfaction * bf; + strlist *S, *x; + + for (bf = b->factions;bf;bf=bf->next) { + faction *f = bf->faction; + + S = 0; + spunit(&S, f, u, 4, see_battle); + for (x = S; x; x = x->next) { + fbattlerecord(b, f, x->s); + if (bdebug && u->faction == f) { + fputs(x->s, bdebug); + fputc('\n', bdebug); + } + } + if (S) + freestrlist(S); + } +} + +static void +print_fighters(battle * b, const side * s) +{ + fighter *df; + int row; + + for (row=1;row!=NUMROWS;++row) { + message * m = NULL; + + for (df=s->fighters; df; df=df->next) { + unit *du = df->unit; + int thisrow = statusrow(df->unit->status); + + if (row == thisrow) { + if (m==NULL) { + m = msg_message("battle::row_header", "row", row); + message_all(b, m); + } + battle_punit(du, b); + } + } + if (m!=NULL) msg_release(m); + } +} + +boolean +is_attacker(const fighter * fig) +{ + return fval(fig, FIG_ATTACKER)!=0; +} + +static void +set_attacker(fighter * fig) +{ + fset(fig, FIG_ATTACKER); +} + +static void +print_header(battle * b) +{ + bfaction * bf; + char zText[32*MAXSIDES]; + + for (bf=b->factions;bf;bf=bf->next) { + message * m; + faction * f = bf->faction; + const char * lastf = NULL; + boolean first = false; + side * s; + char * bufp = zText; + size_t size = sizeof(zText) - 1; + int bytes; + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *df; + for (df=s->fighters;df;df=df->next) { + if (is_attacker(df)) { + if (first) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (lastf) { + bytes = (int)strlcpy(bufp, (const char *)lastf, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + first = true; + } + if (seematrix(f, s) == true) + lastf = sidename(s); + else + lastf = LOC(f->locale, "unknown_faction_dative"); + break; + } + } + } + if (first) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, (const char *)LOC(f->locale, "and"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (lastf) { + bytes = (int)strlcpy(bufp, (const char *)lastf, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + m = msg_message("battle::starters", "factions", zText); + message_faction(b, f, m); + msg_release(m); + } +} + +static void +print_stats(battle * b) +{ + side *s2; + side *s; + int i = 0; + for (s=b->sides;s!=b->sides+b->nsides;++s) { + bfaction *bf; + + ++i; + + for (bf=b->factions;bf;bf=bf->next) { + faction * f = bf->faction; + const char * loc_army = LOC(f->locale, "battle_army"); + char * bufp; + const char * header; + size_t rsize, size; + int komma; + const char * sname = seematrix(f, s) ? sidename(s) : LOC(f->locale, "unknown_faction"); + message * msg; + char buf[1024]; + + message_faction(b, f, msg_separator); + + msg = msg_message("battle_army", "index name", army_index(s), sname); + message_faction(b, f, msg); + msg_release(msg); + + bufp = buf; + size = sizeof(buf); + komma = 0; + header = LOC(f->locale, "battle_opponents"); + + for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { + if (enemy(s2, s)) { + const char * abbrev = seematrix(f, s2)?sideabkz(s2, false):"-?-"; + rsize = slprintf(bufp, size, "%s %s %d(%s)", + komma++ ? "," : (const char*)header, loc_army, army_index(s2), abbrev); + if (rsize>size) rsize = size-1; + size -= rsize; + bufp += rsize; + } + } + if (komma) fbattlerecord(b, f, buf); + + bufp = buf; + size = sizeof(buf); + komma = 0; + header = LOC(f->locale, "battle_helpers"); + + for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { + if (friendly(s2, s)) { + const char * abbrev = seematrix(f, s2)?sideabkz(s2, false):"-?-"; + rsize = slprintf(bufp, size, "%s %s %d(%s)", + komma++ ? "," : (const char*)header, loc_army, army_index(s2), abbrev); + if (rsize>size) rsize = size-1; + size -= rsize; + bufp += rsize; + } + } + if (komma) fbattlerecord(b, f, buf); + + bufp = buf; + size = sizeof(buf); + komma = 0; + header = LOC(f->locale, "battle_attack"); + + for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { + if (s->relations[s2->index] & E_ATTACKING) { + const char * abbrev = seematrix(f, s2)?sideabkz(s2, false):"-?-"; + rsize = slprintf(bufp, size, "%s %s %d(%s)", komma++ ? "," : (const char*)header, loc_army, + army_index(s2), abbrev); + if (rsize>size) rsize = size-1; + size -= rsize; + bufp += rsize; + } + } + if (komma) fbattlerecord(b, f, buf); + } + + if (bdebug && s->faction) { + if (f_get_alliance(s->faction)) { + fprintf(bdebug, "##### %s (%s/%d)\n", s->faction->name, itoa36(s->faction->no), + s->faction->alliance?s->faction->alliance->id:0); + } else { + fprintf(bdebug, "##### %s (%s)\n", s->faction->name, itoa36(s->faction->no)); + } + } + print_fighters(b, s); + } + + message_all(b, msg_separator); + + /* Besten Taktiker ermitteln */ + + b->max_tactics = 0; + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + if (cv_size(&s->leader.fighters)) { + b->max_tactics = MAX(b->max_tactics, s->leader.value); + } + } + + if (b->max_tactics > 0) { + for (s=b->sides;s!=b->sides+b->nsides;++s) { + if (s->leader.value == b->max_tactics) { + fighter *tf; + cv_foreach(tf, s->leader.fighters) { + unit *u = tf->unit; + message * m = NULL; + if (!is_attacker(tf)) { + m = msg_message("battle::tactics_lost", "unit", u); + } else { + m = msg_message("battle::tactics_won", "unit", u); + } + message_all(b, m); + msg_release(m); + } cv_next(tf); + } + } + } +} + +static int +weapon_weight(const weapon * w, boolean missile) +{ + if (missile == i2b(fval(w->type, WTF_MISSILE))) { + return w->attackskill + w->defenseskill; + } + return 0; +} + +fighter * +make_fighter(battle * b, unit * u, side * s1, boolean attack) +{ +#define WMAX 20 + weapon weapons[WMAX]; + int owp[WMAX]; + int dwp[WMAX]; + int w = 0; + region *r = b->region; + item * itm; + fighter *fig = NULL; + int i, tactics = eff_skill(u, SK_TACTICS, r); + side *s2; + int h; + int berserk; + int strongmen; + int speeded = 0, speed = 1; + boolean pr_aid = false; + int rest; + const group * g = NULL; + const attrib *a = a_find(u->attribs, &at_otherfaction); + const faction *stealthfaction = a?get_otherfaction(a):NULL; + unsigned int flags = 0; + + assert(u->number); + if (fval(u, UFL_ANON_FACTION)!=0) flags |= SIDE_STEALTH; + + if (!(AllianceAuto() & HELP_FIGHT) && fval(u, UFL_GROUP)) { + const attrib * agroup = a_find(u->attribs, &at_group); + if (agroup!=NULL) g = (const group*)agroup->data.v; + } + + /* Illusionen und Zauber kaempfen nicht */ + if (fval(u->race, RCF_ILLUSIONARY) || idle(u->faction) || u->number==0) + return NULL; + + if (s1==NULL) { + for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { + if (s2->faction == u->faction && s2->group==g) { +#ifdef SIMPLE_COMBAT + int s1flags = flags|SIDE_HASGUARDS; + int s2flags = s2->flags|SIDE_HASGUARDS; +#else + int s1flags = flags; + int s2flags = s2->flags; +#endif + if (s1flags==s2flags && s2->stealthfaction==stealthfaction) { + s1 = s2; + break; + } + } + } + + /* aliances are moved out of make_fighter and will be handled later */ + if (!s1) { + s1 = make_side(b, u->faction, g, flags, stealthfaction); + } + /* Zu diesem Zeitpunkt ist attacked noch 0, da die Einheit für noch + * keinen Kampf ausgewählt wurde (sonst würde ein fighter existieren) */ + } + fig = calloc(1, sizeof(struct fighter)); + + fig->next = s1->fighters; + s1->fighters = fig; + + fig->unit = u; + /* In einer Burg muß man a) nicht Angreifer sein, und b) drin sein, und + * c) noch Platz finden. d) menschanähnlich sein */ + if (attack) { + set_attacker(fig); + } else { + building * b = u->building; + if (b && b->sizeleft>=u->number && playerrace(u->race)) { + fig->building = b; + fig->building->sizeleft -= u->number; + } + } + fig->status = u->status; + fig->side = s1; + fig->alive = u->number; + fig->side->alive += u->number; + fig->side->battle->alive += u->number; + fig->catmsg = -1; + + /* Freigeben nicht vergessen! */ + fig->person = calloc(fig->alive, sizeof(struct person)); + + h = u->hp / u->number; + assert(h); + rest = u->hp % u->number; + + /* Effekte von Sprüchen */ + + { + static const curse_type * speed_ct; + speed_ct = ct_find("speed"); + if (speed_ct) { + curse *c = get_curse(u->attribs, speed_ct); + if (c) { + speeded = get_cursedmen(u, c); + speed = curse_geteffect_int(c); + } + } + } + + /* Effekte von Alchemie */ + berserk = get_effect(u, oldpotiontype[P_BERSERK]); + /* change_effect wird in ageing gemacht */ + + /* Effekte von Artefakten */ + strongmen = MIN(fig->unit->number, get_item(u, I_TROLLBELT)); + + /* Hitpoints, Attack- und Defence-Boni für alle Personen */ + for (i = 0; i < fig->alive; i++) { + assert(i < fig->unit->number); + fig->person[i].hp = h; + if (i < rest) + fig->person[i].hp++; + + if (i < speeded) + fig->person[i].speed = speed; + else + fig->person[i].speed = 1; + + if (i < berserk) { + fig->person[i].attack++; + } + /* Leute mit einem Aid-Prayer bekommen +1 auf fast alles. */ + if (pr_aid) { + fig->person[i].attack++; + fig->person[i].defence++; + fig->person[i].damage++; + fig->person[i].damage_rear++; + fig->person[i].flags |= FL_COURAGE; + } + /* Leute mit Kraftzauber machen +2 Schaden im Nahkampf. */ + if (i < strongmen) { + fig->person[i].damage += 2; + } + } + + /* Für alle Waffengattungne wird bestimmt, wie viele der Personen mit + * ihr kämpfen könnten, und was ihr Wert darin ist. */ + if (u->race->battle_flags & BF_EQUIPMENT) { + int oi=0, di=0; + for (itm=u->items;itm && w!=WMAX;itm=itm->next) { + const weapon_type * wtype = resource2weapon(itm->type->rtype); + if (wtype==NULL || itm->number==0) continue; + weapons[w].attackskill = weapon_skill(wtype, u, true); + weapons[w].defenseskill = weapon_skill(wtype, u, false); + if (weapons[w].attackskill>=0 || weapons[w].defenseskill>=0) { + weapons[w].type = wtype; + weapons[w].used = 0; + weapons[w].count = itm->number; + ++w; + } + assert(w!=WMAX); + } + fig->weapons = calloc(sizeof(weapon), w+1); + memcpy(fig->weapons, weapons, w*sizeof(weapon)); + + for (i=0; i!=w; ++i) { + int j, o=0, d=0; + for (j=0; j!=i; ++j) { + if (weapon_weight(fig->weapons+j, true)>=weapon_weight(fig->weapons+i, true)) ++d; + if (weapon_weight(fig->weapons+j, false)>=weapon_weight(fig->weapons+i, false)) ++o; + } + for (j=i+1; j!=w; ++j) { + if (weapon_weight(fig->weapons+j, true)>weapon_weight(fig->weapons+i, true)) ++d; + if (weapon_weight(fig->weapons+j, false)>weapon_weight(fig->weapons+i, false)) ++o; + } + owp[o] = i; + dwp[d] = i; + } + /* jetzt enthalten owp und dwp eine absteigend schlechter werdende Liste der Waffen + * oi and di are the current index to the sorted owp/dwp arrays + * owp, dwp contain indices to the figther::weapons array */ + + /* hand out melee weapons: */ + for (i=0; i!=fig->alive; ++i) { + int wpless = weapon_skill(NULL, u, true); + while (oi!=w && (fig->weapons[owp[oi]].used==fig->weapons[owp[oi]].count || fval(fig->weapons[owp[oi]].type, WTF_MISSILE))) { + ++oi; + } + if (oi==w) break; /* no more weapons available */ + if (weapon_weight(fig->weapons+owp[oi], false)<=wpless) { + continue; /* we fight better with bare hands */ + } + fig->person[i].melee = &fig->weapons[owp[oi]]; + ++fig->weapons[owp[oi]].used; + } + /* hand out missile weapons (from back to front, in case of mixed troops). */ + for (di=0, i=fig->alive; i--!=0;) { + while (di!=w && (fig->weapons[dwp[di]].used==fig->weapons[dwp[di]].count || !fval(fig->weapons[dwp[di]].type, WTF_MISSILE))) { + ++di; + } + if (di==w) break; /* no more weapons available */ + if (weapon_weight(fig->weapons+dwp[di], true)>0) { + fig->person[i].missile = &fig->weapons[dwp[di]]; + ++fig->weapons[dwp[di]].used; + } + } + } + + s1->size[statusrow(fig->status)] += u->number; + s1->size[SUM_ROW] += u->number; + if (u->race->battle_flags & BF_NOBLOCK) { + s1->nonblockers[statusrow(fig->status)] += u->number; + } + + if (fig->unit->race->flags & RCF_HORSE) { + fig->horses = fig->unit->number; + fig->elvenhorses = 0; + } else { + static const item_type * it_charger = 0; + if (it_charger==0) { + it_charger = it_find("charger"); + if (!it_charger) { + it_charger = it_find("horse"); + } + } + fig->horses = i_get(u->items, it_charger); + fig->elvenhorses = get_item(u, I_ELVENHORSE); + } + + if (u->race->battle_flags & BF_EQUIPMENT) { + for (itm=u->items; itm; itm=itm->next) { + if (itm->type->rtype->atype) { + if (i_canuse(u, itm->type)) { + struct armor * adata = malloc(sizeof(armor)), **aptr; + adata->atype = itm->type->rtype->atype; + adata->count = itm->number; + for (aptr=&fig->armors;*aptr;aptr=&(*aptr)->next) { + if (adata->atype->prot > (*aptr)->atype->prot) break; + } + adata->next = *aptr; + *aptr = adata; + } + } + } + } + + + /* Jetzt muß noch geschaut werden, wo die Einheit die jeweils besten + * Werte hat, das kommt aber erst irgendwo später. Ich entscheide + * wärend des Kampfes, welche ich nehme, je nach Gegner. Deswegen auch + * keine addierten boni. */ + + /* Zuerst mal die Spezialbehandlung gewisser Sonderfälle. */ + fig->magic = eff_skill(u, SK_MAGIC, r); + + if (fig->horses) { + if (!fval(r->terrain, CAVALRY_REGION) || r_isforest(r) + || eff_skill(u, SK_RIDING, r) < CavalrySkill() || u->race == new_race[RC_TROLL] || fval(u, UFL_WERE)) + fig->horses = 0; + } + + if (fig->elvenhorses) { + if (eff_skill(u, SK_RIDING, r) < 5 || u->race == new_race[RC_TROLL] || fval(u, UFL_WERE)) + fig->elvenhorses = 0; + } + + /* Schauen, wie gut wir in Taktik sind. */ + if (tactics > 0 && u->race == new_race[RC_INSECT]) + tactics -= 1 - (int) log10(fig->side->size[SUM_ROW]); +#ifdef TACTICS_MODIFIER + if (tactics > 0 && statusrow(fig->status) == FIGHT_ROW) + tactics += TACTICS_MODIFIER; + if (tactics > 0 && statusrow(fig->status) > BEHIND_ROW) { + tactics -= TACTICS_MODIFIER; + } +#endif + + if (tactics > 0) { + int bonus = 0; + + for (i = 0; i < fig->alive; i++) { + int p_bonus = 0; + int rnd; + + do { + rnd = rng_int()%100; + if (rnd >= 40 && rnd <= 69) + p_bonus += 1; + else if (rnd <= 89) + p_bonus += 2; + else + p_bonus += 3; + } while(rnd >= 97); + bonus = MAX(p_bonus, bonus); + } + tactics += bonus; + } + + add_tactics(&fig->side->leader, fig, tactics); + ++b->nfighters; + return fig; +} + + +static int +join_battle(battle * b, unit * u, boolean attack, fighter ** cp) +{ + side * s; + fighter *c = NULL; + + if (!attack) { + attrib * a = a_find(u->attribs, &at_fleechance); + if (a!=NULL) { + if (rng_double()<=a->data.flt) { + *cp = NULL; + return false; + } + } + } + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *fig; + if (s->faction==u->faction) { + for (fig=s->fighters;fig;fig=fig->next) { + if (fig->unit == u) { + c = fig; + if (attack) { + set_attacker(fig); + } + break; + } + } + } + } + if (!c) { + *cp = make_fighter(b, u, NULL, attack); + return *cp!=NULL; + } + *cp = c; + return false; +} + +static const char * +simplename(region * r) +{ + int i; + static char name[17]; + const char * cp = rname(r, default_locale); + for (i=0;*cp && i!=16;++i, ++cp) { + int c = *(unsigned char *)cp; + while (c && !isalpha(c) && !isxspace(c)) { + ++cp; + c = *(unsigned char*)cp; + } + if (isxspace(c)) name[i] = '_'; + else name[i] = *cp; + if (c==0) break; + } + name[i]=0; + return name; +} + +static battle * +make_battle(region * r) +{ + battle *b = calloc(1, sizeof(struct battle)); + unit *u; + bfaction * bf; + static int max_fac_no = 0; /* need this only once */ + + if (battledebug) { + char zText[MAX_PATH]; + char zFilename[MAX_PATH]; + sprintf(zText, "%s/battles", basepath()); + makedir(zText, 0700); + sprintf(zFilename, "%s/battle-%d-%s.log", zText, obs_count, simplename(r)); + bdebug = fopen(zFilename, "w"); + if (!bdebug) log_error(("battles cannot be debugged\n")); + else { + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + fwrite(utf8_bom, 1, 3, bdebug); + fprintf(bdebug, "In %s findet ein Kampf stattactics:\n", rname(r, default_locale)); + } + obs_count++; + } + + b->region = r; + b->plane = getplane(r); + /* Finde alle Parteien, die den Kampf beobachten können: */ + for (u = r->units; u; u=u->next) { + if (u->number > 0) { + if (!fval(u->faction, FFL_MARK)) { + fset(u->faction, FFL_MARK); + for (bf=b->factions;bf;bf=bf->next) { + if (bf->faction==u->faction) break; + } + if (!bf) { + bf = calloc(sizeof(bfaction), 1); + ++b->nfactions; + bf->faction = u->faction; + bf->next = b->factions; + b->factions = bf; + } + } + } + } + + for (bf=b->factions;bf;bf=bf->next) { + faction * f = bf->faction; + max_fac_no = MAX(max_fac_no, f->no); + freset(f, FFL_MARK); + } + return b; +} + +static void +free_side(side * si) +{ + cv_kill(&si->leader.fighters); +} + +static void +free_fighter(fighter * fig) +{ + while (fig->loot) { + i_free(i_remove(&fig->loot, fig->loot)); + } + while (fig->armors) { + armor * a = fig->armors; + fig->armors = a->next; + free(a); + } + free(fig->person); + free(fig->weapons); + +} + +static void +free_battle(battle * b) +{ + side *s; + meffect *meffect; + int max_fac_no = 0; + + if (bdebug) { + fclose(bdebug); + } + + while (b->factions) { + bfaction * bf = b->factions; + faction * f = bf->faction; + b->factions = bf->next; + max_fac_no = MAX(max_fac_no, f->no); + free(bf); + } + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *fnext = s->fighters; + while (fnext) { + fighter *fig = fnext; + fnext = fig->next; + free_fighter(fig); + free(fig); + } + free_side(s); + } + cv_kill(&b->leaders); + cv_foreach(meffect, b->meffects) { + free(meffect); + } + cv_next(meffect); + cv_kill(&b->meffects); +} + +static int * +get_alive(side * s) +{ +#if 0 + static int alive[NUMROWS]; + fighter *fig; + memset(alive, 0, NUMROWS * sizeof(int)); + for (fig=s->fighters;fig;fig=fig->next) { + if (fig->alive>0) { + int row = statusrow(fig); + alive[row] += fig->alive; + } + } + return alive; +#endif + return s->size; +} + +static int +battle_report(battle * b) +{ + side *s, *s2; + boolean cont = false; + boolean komma; + bfaction *bf; + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + if (s->alive-s->removed > 0) { + for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { + if (s2->alive-s2->removed > 0 && enemy(s, s2)) { + cont = true; + break; + } + } + if (cont) break; + } + } + + if (verbosity>0) log_stdio(stdout, " %d", b->turn); + fflush(stdout); + + for (bf=b->factions;bf;bf=bf->next) { + faction * fac = bf->faction; + char buf[32*MAXSIDES]; + char * bufp = buf; + int bytes; + size_t size = sizeof(buf) - 1; + message * m; + + message_faction(b, fac, msg_separator); + + if (cont) m = msg_message("battle::lineup", "turn", b->turn); + else m = msg_message("battle::after", ""); + message_faction(b, fac, m); + msg_release(m); + + komma = false; + for (s=b->sides;s!=b->sides+b->nsides;++s) { + if (s->alive) { + int r, k = 0, * alive = get_alive(s); + int l = FIGHT_ROW; + const char * abbrev = seematrix(fac, s)?sideabkz(s, false):"-?-"; + const char * loc_army = LOC(fac->locale, "battle_army"); + char buffer[32]; + + if (komma) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + snprintf(buffer, sizeof(buffer), "%s %2d(%s): ", + loc_army, army_index(s), abbrev); + buffer[sizeof(buffer)-1] = 0; + + bytes = (int)strlcpy(bufp, buffer, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + for (r=FIGHT_ROW;r!=NUMROWS;++r) { + if (alive[r]) { + if (l!=FIGHT_ROW) { + bytes = (int)strlcpy(bufp, "+", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + while (k--) { + bytes = (int)strlcpy(bufp, "0+", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + sprintf(buffer, "%d", alive[r]); + + bytes = (int)strlcpy(bufp, buffer, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + k = 0; + l = r+1; + } else ++k; + } + + komma = true; + } + } + *bufp = 0; + fbattlerecord(b, fac, buf); + } + return cont; +} + +static void +join_allies(battle * b) +{ + region *r = b->region; + unit *u; + side *s, *s_end = b->sides+b->nsides; + /* make_side might be adding a new faction, but it adds them to the end + * of the list, so we're safe in our iteration here if we remember the end + * up front. */ + for (u=r->units;u;u=u->next) { + /* Was ist mit Schiffen? */ + if (u->status != ST_FLEE && u->status != ST_AVOID && !fval(u, UFL_LONGACTION|UFL_ISNEW) && u->number > 0) { + faction * f = u->faction; + fighter * c = NULL; + + for (s=b->sides;s!=s_end;++s) { + side * se; + /* Wenn alle attackierten noch FFL_NOAID haben, dann kämpfe nicht mit. */ + if (fval(s->faction, FFL_NOAID)) continue; + if (s->faction!=f) { + /* Wenn wir attackiert haben, kommt niemand mehr hinzu: */ + if (s->bf->attacker) continue; + /* alliiert müssen wir schon sein, sonst ist's eh egal : */ + if (!alliedunit(u, s->faction, HELP_FIGHT)) continue; + /* wenn die partei verborgen ist, oder gar eine andere + * vorgespiegelt wird, und er sich uns gegenüber nicht zu + * erkennen gibt, helfen wir ihm nicht */ + if (s->stealthfaction){ + if(!allysfm(s, u->faction, HELP_FSTEALTH)) { + continue; + } + } + } + /* einen alliierten angreifen dürfen sie nicht, es sei denn, der + * ist mit einem alliierten verfeindet, der nicht attackiert + * hat: */ + for (se=b->sides;se!=s_end;++se) { + if (u->faction==se->faction) continue; + if (alliedunit(u, se->faction, HELP_FIGHT) && !se->bf->attacker) { + continue; + } + if (enemy(s, se)) break; + } + if (se==s_end) continue; + /* Wenn die Einheit belagert ist, muß auch einer der Alliierten belagert sein: */ + if (besieged(u)) { + fighter *ally; + for (ally = s->fighters; ally; ally=ally->next) { + if (besieged(ally->unit)) { + break; + } + } + if (ally==NULL) continue; + } + /* keine Einwände, also soll er mitmachen: */ + if (c==NULL) { + if (join_battle(b, u, false, &c)) { + if (battledebug) { + fprintf(bdebug, "%s joins to help %s against %s.\n", + unitname(u), factionname(s->faction), + factionname(se->faction)); + } + } else if (c==NULL) { + continue; + } + } + + /* the enemy of my friend is my enemy: */ + for (se=b->sides;se!=s_end;++se) { + if (se->faction!=u->faction && enemy(s, se)) { + if (set_enemy(se, c->side, false) && battledebug) { + fprintf(bdebug, "%u/%s hates %u/%s because they are enemies with %u/%s.\n", + c->side->index, sidename(c->side), + se->index, sidename(se), + s->index, sidename(s)); + } + } + } + } + } + } + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + int si; + side * sa; + faction * f = s->faction; + + /* Den Feinden meiner Feinde gebe ich Deckung (gegen gemeinsame Feinde): */ + for (si=0; s->enemies[si]; ++si) { + side * se = s->enemies[si]; + int ai; + for (ai=0; se->enemies[ai]; ++ai) { + side * as = se->enemies[ai]; + if (as==s || !enemy(as, s)) { + set_friendly(as, s); + } + } + } + + for (sa=s+1;sa!=b->sides+b->nsides;++sa) { + plane * pl = rplane(r); + if (enemy(s, sa)) continue; + if (friendly(s, sa)) continue; + if (!alliedgroup(pl, f, sa->faction, f->allies, HELP_FIGHT)) continue; + if (!alliedgroup(pl, sa->faction, f, sa->faction->allies, HELP_FIGHT)) continue; + + set_friendly(s, sa); + } + } +} + +static void +flee(const troop dt) +{ + fighter * fig = dt.fighter; + unit * u = fig->unit; + +#ifndef SIMPLE_ESCAPE + int carry = personcapacity(u) - u->race->weight; + int money; + + item ** ip = &u->items; + + while (*ip) { + item * itm = *ip; + const item_type * itype = itm->type; + int keep = 0; + + if (fval(itype, ITF_ANIMAL)) { + /* Regeländerung: Man muß das Tier nicht reiten können, + * um es vom Schlachtfeld mitzunehmen, ist ja nur + * eine Region weit. * */ + keep = MIN(1, itm->number); + /* da ist das weight des tiers mit drin */ + carry += itype->capacity - itype->weight; + } else if (itm->type->weight <= 0) { + /* if it doesn'tactics weigh anything, it won'tactics slow us down */ + keep = itm->number; + } + /* jeder troop nimmt seinen eigenen Teil der Sachen mit */ + if (keep>0){ + if (itm->number==keep) { + i_add(&fig->run.items, i_remove(ip, itm)); + } else { + item *run_itm = i_new(itype, keep); + i_add(&fig->run.items, run_itm); + i_change(ip, itype, -keep); + } + } + if (*ip==itm) ip = &itm->next; + } + + /* we will take money with us */ + money = get_money(u); + /* nur ganzgeflohene/resttote Einheiten verlassen die Region */ + if (money > carry) money = carry; + if (money > 0) { + i_change(&u->items, i_silver, -money); + i_change(&fig->run.items, i_silver, +money); + } +#endif /* SIMPLE_ESCAPE */ + + fig->run.hp += fig->person[dt.index].hp; + ++fig->run.number; + + setguard(u, GUARD_NONE); + + kill_troop(dt); +} + +static boolean +init_battle(region * r, battle **bp) +{ + battle * b = NULL; + unit * u; + boolean fighting = false; + + /* list_foreach geht nicht, wegen flucht */ + for (u = r->units; u != NULL; u = u->next) { + if (fval(u, UFL_LONGACTION)) continue; + if (u->number > 0) { + order * ord; + + for (ord=u->orders;ord;ord=ord->next) { + static boolean init = false; + static const curse_type * peace_ct, * slave_ct, * calm_ct; + + if (!init) { + init = true; + peace_ct = ct_find("peacezone"); + slave_ct = ct_find("slavery"); + calm_ct = ct_find("calmmonster"); + } + if (get_keyword(ord) == K_ATTACK) { + unit *u2; + fighter *c1, *c2; + ship * lsh = NULL; + plane * pl = rplane(r); + + if (pl && fval(pl, PFL_NOATTACK)) { + cmistake(u, ord, 271, MSG_BATTLE); + continue; + } + + if ((u->race->battle_flags&BF_CANATTACK) == 0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_no_attack", "race", u->race)); + continue; + } + /** + ** Fehlerbehandlung Angreifer + **/ + if (LongHunger(u)) { + cmistake(u, ord, 225, MSG_BATTLE); + continue; + } + + if (u->status == ST_AVOID || u->status == ST_FLEE) { + cmistake(u, ord, 226, MSG_BATTLE); + continue; + } + + /* ist ein Flüchtling aus einem andern Kampf */ + if (fval(u, UFL_LONGACTION)) continue; + + if (peace_ct && curse_active(get_curse(r->attribs, peace_ct))) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "peace_active", "")); + continue; + } + + if (slave_ct && curse_active(get_curse(u->attribs, slave_ct))) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "slave_active", "")); + continue; + } + + if ((u->ship != NULL && !fval(r->terrain, SEA_REGION)) || (lsh = leftship(u))!=NULL) { + if (is_guarded(r, u, GUARD_TRAVELTHRU)) { + if (lsh) { + cmistake(u, ord, 234, MSG_BATTLE); + } else { + /* Fehler: "Das Schiff muß erst verlassen werden" */ + cmistake(u, ord, 19, MSG_BATTLE); + } + continue; + } + } + + /* Ende Fehlerbehandlung Angreifer */ + + init_tokens(ord); + skip_token(); + /* attackierte Einheit ermitteln */ + u2 = getunit(r, u->faction); + + /* Beginn Fehlerbehandlung */ + /* Fehler: "Die Einheit wurde nicht gefunden" */ + if (!u2 || u2->number == 0 || !cansee(u->faction, u->region, u2, 0)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + continue; + } + /* Fehler: "Die Einheit ist eine der unsrigen" */ + if (u2->faction == u->faction) { + cmistake(u, ord, 45, MSG_BATTLE); + continue; + } + /* Fehler: "Die Einheit ist mit uns alliert" */ + if (alliedunit(u, u2->faction, HELP_FIGHT)) { + cmistake(u, ord, 47, MSG_BATTLE); + continue; + } + if (IsImmune(u2->faction)) { + add_message(&u->faction->msgs, + msg_feedback(u, u->thisorder, "newbie_immunity_error", "turns", NewbieImmunity())); + continue; + } + /* Fehler: "Die Einheit ist mit uns alliert" */ + + if (calm_ct) { + attrib * a = a_find(u->attribs, &at_curse); + boolean calm = false; + while (a && a->type==&at_curse) { + curse * c = (curse *)a->data.v; + if (c->type==calm_ct && curse_geteffect(c)==u2->faction->subscription) { + if (curse_active(c)) { + calm = true; + break; + } + } + a = a->next; + } + if (calm) { + cmistake(u, ord, 47, MSG_BATTLE); + continue; + } + } + /* Ende Fehlerbehandlung */ + if (b==NULL) { + unit * utmp; + for (utmp=r->units; utmp!=NULL; utmp=utmp->next) { + fset(utmp->faction, FFL_NOAID); + } + b = make_battle(r); + } + if (join_battle(b, u, true, &c1)) { + if (battledebug) { + fprintf(bdebug, "%s joins by attacking %s.\n", + unitname(u), unitname(u2)); + } + } + if (join_battle(b, u2, false, &c2)) { + if (battledebug) { + fprintf(bdebug, "%s joins because of an attack from %s.\n", + unitname(u2), unitname(u)); + } + } + + /* Hat die attackierte Einheit keinen Noaid-Status, + * wird das Flag von der Faction genommen, andere + * Einheiten greifen ein. */ + if (!fval(u2, UFL_NOAID)) freset(u2->faction, FFL_NOAID); + + if (c1!=NULL && c2!=NULL) { + /* Merken, wer Angreifer ist, für die Rückzahlung der + * Präcombataura bei kurzem Kampf. */ + c1->side->bf->attacker = true; + + if (set_enemy(c1->side, c2->side, true) && battledebug) { + fprintf(bdebug, "%u/%s hates %u/%s because they attacked them.\n", + c2->side->index, sidename(c2->side), + c1->side->index, sidename(c1->side)); + } + fighting = true; + } + } + } + } + } + *bp = b; + return fighting; +} + +static void +battle_stats(FILE * F, battle * b) +{ + typedef struct stat_info { + struct stat_info * next; + const weapon_type * wtype; + int level; + int number; + } stat_info; + side * s; + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter * df; + stat_info * stats = NULL, * stat; + + for (df = s->fighters; df; df = df->next) { + unit *du = df->unit; + troop dt; + stat_info * slast = NULL; + + dt.fighter = df; + for (dt.index=0;dt.index!=du->number;++dt.index) { + weapon * wp = preferred_weapon(dt, true); + int level = wp?wp->attackskill:0; + const weapon_type * wtype = wp?wp->type:NULL; + stat_info ** slist = &stats; + + if (slast && slast->wtype==wtype && slast->level==level) { + ++slast->number; + continue; + } + while (*slist && (*slist)->wtype!=wtype) { + slist = &(*slist)->next; + } + while (*slist && (*slist)->wtype==wtype && (*slist)->level>level) { + slist = &(*slist)->next; + } + stat = *slist; + if (stat==NULL || stat->wtype!=wtype || stat->level!=level) { + stat = calloc(1, sizeof(stat_info)); + stat->wtype = wtype; + stat->level = level; + stat->next = *slist; + *slist = stat; + } + slast = stat; + ++slast->number; + } + } + + fprintf(F, "##STATS## Heer %u - %s:\n", army_index(s), factionname(s->faction)); + for (stat=stats;stat!=NULL;stat=stat->next) { + fprintf(F, "%s %u : %u\n", stat->wtype?stat->wtype->itype->rtype->_name[0]:"none", stat->level, stat->number); + } + freelist(stats); + } +} + +/** execute one round of attacks + * fig->fighting is used to determine who attacks, not fig->alive, since + * the latter may be influenced by attacks that already took place. + */ +static void +battle_attacks(battle * b) +{ + side * s; + + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *fig; + + if (b->turn!=0 || (b->max_tactics > 0 && get_tactics(s, NULL) == b->max_tactics)) { + for (fig=s->fighters;fig;fig=fig->next) { + + /* ist in dieser Einheit noch jemand handlungsfähig? */ + if (fig->fighting <= 0) continue; + + /* Handle the unit's attack on someone */ + do_attack(fig); + } + } + } +} + +/** updates the number of attacking troops in each fighter struct. + * this has to be calculated _before_ the actual attacks take + * place because otherwise dead troops would not strike in the + * round they die. */ +static void +battle_update(battle * b) +{ + side * s; + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *fig; + for (fig=s->fighters;fig;fig=fig->next) { + fig->fighting = fig->alive - fig->removed; + } + } +} + +/** attempt to flee from battle before the next round begins + * there's a double attempt before the first round, but only + * one attempt before round zero, the potential tactics round. */ +static void +battle_flee(battle * b) +{ + int attempt, flee_ops = 1; + + if (b->turn==1) + flee_ops = 2; + + for (attempt=1;attempt<=flee_ops;++attempt) { + side * s; + for (s=b->sides;s!=b->sides+b->nsides;++s) { + fighter *fig; + for (fig=s->fighters;fig;fig=fig->next) { + unit *u = fig->unit; + troop dt; + int runners = 0; + /* Flucht nicht bei mehr als 600 HP. Damit Wyrme tötbar bleiben. */ + int runhp = MIN(600,(int)(0.9+unit_max_hp(u)*hpflee(u->status))); + + if (u->ship && fval(u->region->terrain, SEA_REGION)) { + /* keine Flucht von Schiffen auf hoher See */ + continue; + } + if (fval(u->race, RCF_UNDEAD) || u->race == new_race[RC_SHADOWKNIGHT]) { + /* Untote fliehen nicht. Warum eigentlich? */ + continue; + } + + dt.fighter = fig; +#ifndef SIMPLE_ESCAPE + if (!fig->run.region) fig->run.region = fleeregion(u); + if (!fig->run.region) continue; +#endif /* SIMPLE_ESCAPE */ + dt.index = fig->alive - fig->removed; + while (s->size[SUM_ROW] && dt.index != 0) { + double ispaniced = 0.0; + --dt.index; + assert(dt.index>=0 && dt.indexunit->number); + assert(fig->person[dt.index].hp > 0); + + /* Versuche zu fliehen, wenn + * - Kampfstatus fliehe + * - schwer verwundet und nicht erste kampfrunde + * - in panik (Zauber) + * aber nicht, wenn der Zaubereffekt Held auf dir liegt! + */ + switch (u->status) { + case ST_FLEE: + break; + default: + if ((fig->person[dt.index].flags & FL_HIT) == 0) continue; + if (b->turn<=1) continue; + if (fig->person[dt.index].hp <= runhp) break; + if (fig->person[dt.index].flags & FL_PANICED) { + if ((fig->person[dt.index].flags & FL_COURAGE)==0) break; + } + continue; + } + + if (fig->person[dt.index].flags & FL_PANICED) { + ispaniced = EFFECT_PANIC_SPELL; + } + if (chance(MIN(fleechance(u)+ispaniced, 0.90))) { + ++runners; + flee(dt); + } + } + if (bdebug && runners > 0) { + fprintf(bdebug, "Fleeing: %d from %s\n", runners, itoa36(fig->unit->no)); + } + } + } + } +} + +void +do_battle(region * r) +{ + battle *b = NULL; + boolean fighting = false; + ship * sh; + building *bu; + static int init_rules = 0; + + if (!init_rules) { + static_rules(); + init_rules = 1; + } + if (msg_separator==NULL) { + msg_separator = msg_message("battle::section", ""); + } + + fighting = init_battle(r, &b); + + if (b==NULL) return; + + /* Bevor wir die alliierten hineinziehen, sollten wir schauen, * + * Ob jemand fliehen kann. Dann erübrigt sich das ganze ja + * vielleicht schon. */ + print_header(b); + if (!fighting) { + /* Niemand mehr da, Kampf kann nicht stattfinden. */ + message * m = msg_message("battle::aborted", ""); + message_all(b, m); + msg_release(m); + free_battle(b); + free(b); + return; + } + join_allies(b); + make_heroes(b); + + /* Alle Mann raus aus der Burg! */ + for (bu=r->buildings; bu!=NULL; bu=bu->next) bu->sizeleft = bu->size; + + /* make sure no ships are damaged initially */ + for (sh=r->ships; sh; sh=sh->next) freset(sh, SF_DAMAGED); + + /* Gibt es eine Taktikrunde ? */ + if (cv_size(&b->leaders)) { + b->turn = 0; + b->has_tactics_turn = true; + } else { + b->turn = 1; + b->has_tactics_turn = false; + } + + if (b->region->flags & RF_COMBATDEBUG) battle_stats(bdebug, b); + + /* PRECOMBATSPELLS */ + do_combatmagic(b, DO_PRECOMBATSPELL); + + print_stats(b); /* gibt die Kampfaufstellung aus */ + if (verbosity>0) log_stdio(stdout, "%s (%d, %d) : ", rname(r, default_locale), r->x, r->y); + + for (;battle_report(b) && b->turn<=max_turns;++b->turn) { + if (bdebug) { + fprintf(bdebug, "*** Turn: %d\n", b->turn); + } + battle_flee(b); + battle_update(b); + battle_attacks(b); + + } + + if (verbosity>0) log_stdio(stdout, "\n"); + + /* Auswirkungen berechnen: */ + aftermath(b); + /* Hier ist das Gefecht beendet, und wir können die + * Hilfsstrukturen * wieder löschen: */ + + if (b) { + free_battle(b); + free(b); + } +} diff --git a/src/kernel/battle.h b/src/kernel/battle.h index da1930595..4bc054818 100644 --- a/src/kernel/battle.h +++ b/src/kernel/battle.h @@ -1,271 +1,271 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_BATTLE -#define H_KRNL_BATTLE -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#define SHOW_KILLS -#undef SMALL_BATTLE_MESSAGES - - /** more defines **/ -#define FS_ENEMY 1 -#define FS_HELP 2 - - /***** Verteidigungslinien. - * Eressea hat 4 Verteidigungslinien. 1 ist vorn, 5. enthält Summen - */ - -#define NUMROWS 5 -#define SUM_ROW 0 -#define FIGHT_ROW 1 -#define BEHIND_ROW 2 -#define AVOID_ROW 3 -#define FLEE_ROW 4 -#define LAST_ROW (NUMROWS-1) -#define FIRST_ROW FIGHT_ROW -#define MAXSIDES 192 /* if there are ever more than this, we're fucked. */ - - struct message; - - typedef struct bfaction { - struct bfaction * next; - struct side * sides; - struct faction *faction; -#ifndef SIMPLE_COMBAT - int lastturn; /* last time this struct faction was involved in combat */ -#endif - boolean attacker; - } bfaction; - - typedef struct tactics { - cvector fighters; - int value; - } tactics; - -#define SIDE_STEALTH 1<<0 -#ifdef SIMPLE_COMBAT -#define SIDE_HASGUARDS 1<<1 -#endif - typedef struct side { - struct side * nextF; /* next army of same faction */ - struct battle * battle; - struct bfaction * bf; /* battle info that goes with the faction */ - struct faction * faction; /* cache optimization for bf->faction */ - const struct group * group; - struct tactics leader; /* this army's best tactician */ -# define E_ENEMY 1 -# define E_FRIEND 2 -# define E_ATTACKING 4 - unsigned char relations[MAXSIDES]; - struct side * enemies[MAXSIDES]; - struct fighter * fighters; - int index; /* Eintrag der Fraktion in b->matrix/b->enemies */ - int size[NUMROWS]; /* Anzahl Personen in Reihe X. 0 = Summe */ - int nonblockers[NUMROWS]; /* Anzahl nichtblockierender Kämpfer, z.B. Schattenritter. */ - int alive; /* Die Partei hat den Kampf verlassen */ - int removed; /* stoned */ - int flee; - int dead; - int casualties; /* those dead that were real people, not undead! */ - int healed; - unsigned int flags; - const struct faction *stealthfaction; - } side; - - typedef struct battle { - cvector leaders; - struct region *region; - struct plane *plane; - bfaction * factions; - int nfactions; - int nfighters; - side sides[MAXSIDES]; - int nsides; - cvector meffects; - int max_tactics; - int turn; - boolean has_tactics_turn; - int keeploot; - boolean reelarrow; - int alive; -#ifdef SMALL_BATTLE_MESSAGES - boolean small; -#endif -#define FASTROW -#ifdef FASTROW - struct { - const struct side * as; - const struct side * vs; - int alive; - int row; - int result; - } rowcache; -#endif -#define FASTCOUNT -#ifdef FASTCOUNT - struct { - struct side * side; - int status; - int alive; - int minrow, maxrow; - int enemies[8]; - } fast; -#endif - } battle; - - typedef struct weapon { - int count, used; - const struct weapon_type * type; - int attackskill : 8; - int defenseskill : 8; - } weapon; - - /*** fighter::person::flags ***/ -#define FL_TIRED 1 -#define FL_DAZZLED 2 /* durch Untote oder Dämonen eingeschüchtert */ -#define FL_PANICED 4 -#define FL_COURAGE 8 /* Helden fliehen nie */ -#define FL_SLEEPING 16 -#define FL_STUNNED 32 /* eine Runde keinen Angriff */ -#define FL_HIT 64 /* the person at attacked */ - - typedef struct troop { - struct fighter *fighter; - int index; - } troop; - - typedef struct armor { - struct armor * next; - const struct armor_type * atype; - int count; - } armor; - - /*** fighter::flags ***/ -#define FIG_ATTACKER 1<<0 -#define FIG_NOLOOT 1<<1 - typedef struct fighter { - struct fighter * next; - struct side *side; - struct unit *unit; /* Die Einheit, die hier kämpft */ - struct building *building; /* Gebäude, in dem die Einheit evtl. steht */ - status_t status; /* Kampfstatus */ - struct weapon * weapons; - struct armor *armors; /* Anzahl Rüstungen jeden Typs */ - int alive; /* Anzahl der noch nicht Toten in der Einheit */ - int fighting; /* Anzahl der Kämpfer in der aktuellen Runde */ - int removed; /* Anzahl Kaempfer, die nicht tot sind, aber - aus dem Kampf raus sind (zB weil sie - versteinert wurden). Diese werden auch - in alive noch mitgezählt! */ - int magic; /* Magietalent der Einheit */ - int horses; /* Anzahl brauchbarer Pferde der Einheit */ - int elvenhorses; /* Anzahl brauchbarer Elfenpferde der Einheit */ - struct item * loot; - int catmsg; /* Merkt sich, ob Katapultmessage schon generiert. */ - struct person { - int hp; /* Trefferpunkte der Personen */ - int attack : 8; /* (Magie) Attackenbonus der Personen */ - int defence : 8; /* (Magie) Paradenbonus der Personen */ - int damage : 8; /* (Magie) Schadensbonus der Personen im Nahkampf */ - int damage_rear : 8; /* (Magie) Schadensbonus der Personen im Fernkampf */ - int flags : 8; /* (Magie) Diverse Flags auf Kämpfern */ - int speed : 8; /* (Magie) Geschwindigkeitsmultiplkator. */ - int reload : 4; /* Anzahl Runden, die die Waffe x noch laden muss. - * dahinter steckt ein array[RL_MAX] wenn er min. eine hat. */ - int last_action : 4; /* In welcher Runde haben wir zuletzt etwas getan */ - struct weapon * missile; /* missile weapon */ - struct weapon * melee; /* melee weapon */ - } * person; - unsigned int flags; - struct { - int number; /* number of people who fled */ - int hp; /* accumulated hp of fleeing people */ -#ifndef SIMPLE_ESCAPE - struct region *region; /* destination of fleeing people */ - struct item * items; /* items they take */ -#endif /* SIMPLE_ESCAPE */ - } run; -#ifndef SIMPLE_COMBAT - int action_counter; /* number of active actions the struct unit did in the fight */ -#endif /* SIMPLE_COMBAT */ -#ifdef SHOW_KILLS - int kills; - int hits; -#endif - } fighter; - - - /* schilde */ - - enum { - SHIELD_REDUCE, - SHIELD_ARMOR, - SHIELD_WIND, - SHIELD_BLOCK, - SHIELD_MAX - }; - - typedef struct meffect { - fighter *magician; /* Der Zauberer, der den Schild gezaubert hat */ - int typ; /* Wirkungsweise des Schilds */ - int effect; - int duration; - } meffect; - - extern const troop no_troop; - - extern void do_battle(struct region * r); - - /* for combat spells and special attacks */ - enum { SELECT_ADVANCE = 0x1, SELECT_DISTANCE = 0x2, SELECT_FIND = 0x4 }; - enum { ALLY_SELF, ALLY_ANY }; - - extern troop select_enemy(struct fighter * af, int minrow, int maxrow, int select); - extern troop select_ally(struct fighter * af, int minrow, int maxrow, int allytype); - - extern int count_enemies(struct battle * b, const struct fighter * af, int minrow, int maxrow, int select); - extern boolean terminate(troop dt, troop at, int type, const char *damage, boolean missile); - extern void message_all(battle * b, struct message * m); - extern int hits(troop at, troop dt, weapon * awp); - extern void damage_building(struct battle *b, struct building *bldg, int damage_abs); - extern struct cvector * fighters(struct battle *b, const struct side * vs, int minrow, int maxrow, int mask); - extern int count_allies(const struct side * as, int minrow, int maxrow, int select, int allytype); - extern int get_unitrow(const struct fighter * af, const struct side * vs); - extern boolean helping(const struct side * as, const struct side * ds); - extern void rmfighter(fighter *df, int i); -#ifndef SIMPLE_ESCAPE - extern struct region * fleeregion(const struct unit * u); -#endif - extern struct fighter * select_corpse(struct battle * b, struct fighter * af); - extern fighter * make_fighter(struct battle * b, struct unit * u, side * s, boolean attack); - extern int statusrow(int status); - extern void drain_exp(struct unit *u, int d); - extern void kill_troop(troop dt); - extern void remove_troop(troop dt); /* not the same as the badly named rmtroop */ - extern boolean is_attacker(const fighter * fig); - -#ifdef __cplusplus -} -#endif - -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_BATTLE +#define H_KRNL_BATTLE +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define SHOW_KILLS +#undef SMALL_BATTLE_MESSAGES + + /** more defines **/ +#define FS_ENEMY 1 +#define FS_HELP 2 + + /***** Verteidigungslinien. + * Eressea hat 4 Verteidigungslinien. 1 ist vorn, 5. enthält Summen + */ + +#define NUMROWS 5 +#define SUM_ROW 0 +#define FIGHT_ROW 1 +#define BEHIND_ROW 2 +#define AVOID_ROW 3 +#define FLEE_ROW 4 +#define LAST_ROW (NUMROWS-1) +#define FIRST_ROW FIGHT_ROW +#define MAXSIDES 192 /* if there are ever more than this, we're fucked. */ + + struct message; + + typedef struct bfaction { + struct bfaction * next; + struct side * sides; + struct faction *faction; +#ifndef SIMPLE_COMBAT + int lastturn; /* last time this struct faction was involved in combat */ +#endif + boolean attacker; + } bfaction; + + typedef struct tactics { + cvector fighters; + int value; + } tactics; + +#define SIDE_STEALTH 1<<0 +#ifdef SIMPLE_COMBAT +#define SIDE_HASGUARDS 1<<1 +#endif + typedef struct side { + struct side * nextF; /* next army of same faction */ + struct battle * battle; + struct bfaction * bf; /* battle info that goes with the faction */ + struct faction * faction; /* cache optimization for bf->faction */ + const struct group * group; + struct tactics leader; /* this army's best tactician */ +# define E_ENEMY 1 +# define E_FRIEND 2 +# define E_ATTACKING 4 + unsigned char relations[MAXSIDES]; + struct side * enemies[MAXSIDES]; + struct fighter * fighters; + int index; /* Eintrag der Fraktion in b->matrix/b->enemies */ + int size[NUMROWS]; /* Anzahl Personen in Reihe X. 0 = Summe */ + int nonblockers[NUMROWS]; /* Anzahl nichtblockierender Kämpfer, z.B. Schattenritter. */ + int alive; /* Die Partei hat den Kampf verlassen */ + int removed; /* stoned */ + int flee; + int dead; + int casualties; /* those dead that were real people, not undead! */ + int healed; + unsigned int flags; + const struct faction *stealthfaction; + } side; + + typedef struct battle { + cvector leaders; + struct region *region; + struct plane *plane; + bfaction * factions; + int nfactions; + int nfighters; + side sides[MAXSIDES]; + int nsides; + cvector meffects; + int max_tactics; + int turn; + boolean has_tactics_turn; + int keeploot; + boolean reelarrow; + int alive; +#ifdef SMALL_BATTLE_MESSAGES + boolean small; +#endif +#define FASTROW +#ifdef FASTROW + struct { + const struct side * as; + const struct side * vs; + int alive; + int row; + int result; + } rowcache; +#endif +#define FASTCOUNT +#ifdef FASTCOUNT + struct { + struct side * side; + int status; + int alive; + int minrow, maxrow; + int enemies[8]; + } fast; +#endif + } battle; + + typedef struct weapon { + int count, used; + const struct weapon_type * type; + int attackskill : 8; + int defenseskill : 8; + } weapon; + + /*** fighter::person::flags ***/ +#define FL_TIRED 1 +#define FL_DAZZLED 2 /* durch Untote oder Dämonen eingeschüchtert */ +#define FL_PANICED 4 +#define FL_COURAGE 8 /* Helden fliehen nie */ +#define FL_SLEEPING 16 +#define FL_STUNNED 32 /* eine Runde keinen Angriff */ +#define FL_HIT 64 /* the person at attacked */ + + typedef struct troop { + struct fighter *fighter; + int index; + } troop; + + typedef struct armor { + struct armor * next; + const struct armor_type * atype; + int count; + } armor; + + /*** fighter::flags ***/ +#define FIG_ATTACKER 1<<0 +#define FIG_NOLOOT 1<<1 + typedef struct fighter { + struct fighter * next; + struct side *side; + struct unit *unit; /* Die Einheit, die hier kämpft */ + struct building *building; /* Gebäude, in dem die Einheit evtl. steht */ + status_t status; /* Kampfstatus */ + struct weapon * weapons; + struct armor *armors; /* Anzahl Rüstungen jeden Typs */ + int alive; /* Anzahl der noch nicht Toten in der Einheit */ + int fighting; /* Anzahl der Kämpfer in der aktuellen Runde */ + int removed; /* Anzahl Kaempfer, die nicht tot sind, aber + aus dem Kampf raus sind (zB weil sie + versteinert wurden). Diese werden auch + in alive noch mitgezählt! */ + int magic; /* Magietalent der Einheit */ + int horses; /* Anzahl brauchbarer Pferde der Einheit */ + int elvenhorses; /* Anzahl brauchbarer Elfenpferde der Einheit */ + struct item * loot; + int catmsg; /* Merkt sich, ob Katapultmessage schon generiert. */ + struct person { + int hp; /* Trefferpunkte der Personen */ + int attack : 8; /* (Magie) Attackenbonus der Personen */ + int defence : 8; /* (Magie) Paradenbonus der Personen */ + int damage : 8; /* (Magie) Schadensbonus der Personen im Nahkampf */ + int damage_rear : 8; /* (Magie) Schadensbonus der Personen im Fernkampf */ + int flags : 8; /* (Magie) Diverse Flags auf Kämpfern */ + int speed : 8; /* (Magie) Geschwindigkeitsmultiplkator. */ + int reload : 4; /* Anzahl Runden, die die Waffe x noch laden muss. + * dahinter steckt ein array[RL_MAX] wenn er min. eine hat. */ + int last_action : 4; /* In welcher Runde haben wir zuletzt etwas getan */ + struct weapon * missile; /* missile weapon */ + struct weapon * melee; /* melee weapon */ + } * person; + unsigned int flags; + struct { + int number; /* number of people who fled */ + int hp; /* accumulated hp of fleeing people */ +#ifndef SIMPLE_ESCAPE + struct region *region; /* destination of fleeing people */ + struct item * items; /* items they take */ +#endif /* SIMPLE_ESCAPE */ + } run; +#ifndef SIMPLE_COMBAT + int action_counter; /* number of active actions the struct unit did in the fight */ +#endif /* SIMPLE_COMBAT */ +#ifdef SHOW_KILLS + int kills; + int hits; +#endif + } fighter; + + + /* schilde */ + + enum { + SHIELD_REDUCE, + SHIELD_ARMOR, + SHIELD_WIND, + SHIELD_BLOCK, + SHIELD_MAX + }; + + typedef struct meffect { + fighter *magician; /* Der Zauberer, der den Schild gezaubert hat */ + int typ; /* Wirkungsweise des Schilds */ + int effect; + int duration; + } meffect; + + extern const troop no_troop; + + extern void do_battle(struct region * r); + + /* for combat spells and special attacks */ + enum { SELECT_ADVANCE = 0x1, SELECT_DISTANCE = 0x2, SELECT_FIND = 0x4 }; + enum { ALLY_SELF, ALLY_ANY }; + + extern troop select_enemy(struct fighter * af, int minrow, int maxrow, int select); + extern troop select_ally(struct fighter * af, int minrow, int maxrow, int allytype); + + extern int count_enemies(struct battle * b, const struct fighter * af, int minrow, int maxrow, int select); + extern boolean terminate(troop dt, troop at, int type, const char *damage, boolean missile); + extern void message_all(battle * b, struct message * m); + extern int hits(troop at, troop dt, weapon * awp); + extern void damage_building(struct battle *b, struct building *bldg, int damage_abs); + extern struct cvector * fighters(struct battle *b, const struct side * vs, int minrow, int maxrow, int mask); + extern int count_allies(const struct side * as, int minrow, int maxrow, int select, int allytype); + extern int get_unitrow(const struct fighter * af, const struct side * vs); + extern boolean helping(const struct side * as, const struct side * ds); + extern void rmfighter(fighter *df, int i); +#ifndef SIMPLE_ESCAPE + extern struct region * fleeregion(const struct unit * u); +#endif + extern struct fighter * select_corpse(struct battle * b, struct fighter * af); + extern fighter * make_fighter(struct battle * b, struct unit * u, side * s, boolean attack); + extern int statusrow(int status); + extern void drain_exp(struct unit *u, int d); + extern void kill_troop(troop dt); + extern void remove_troop(troop dt); /* not the same as the badly named rmtroop */ + extern boolean is_attacker(const fighter * fig); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/kernel/binarystore.c b/src/kernel/binarystore.c index fdc02a09b..13780c981 100644 --- a/src/kernel/binarystore.c +++ b/src/kernel/binarystore.c @@ -1,294 +1,291 @@ -/* vi: set ts=2: -+-------------------+ Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -+-------------------+ -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ -#include -#include "config.h" -#include "textstore.h" - -#include "save.h" -#include "version.h" -#include -#include -#include - -#include -#include -#include -#ifdef HAVE_LIBXML -#include -#endif - -#define file(store) (FILE *)((store)->userdata) - -#define STREAM_VERSION 2 - -INLINE_FUNCTION size_t -pack_int(int v, char * buffer) -{ - int sign = (v<0); - - if (sign) { - v = ~v + 1; - sign = 0x40; - } - if (v<0x40) { - buffer[0] = (char)(v | sign); - return 1; - } else if (v<0x2000) { - buffer[0] = (char)((v>> 6) | 0x80); - buffer[1] = (char)((v & 0x3F) | sign); - return 2; - } else if (v<0x100000) { - buffer[0] = (char)(((v>>13) & 0x7f) | 0x80); - buffer[1] = (char)(((v>> 6) & 0x7f) | 0x80); - buffer[2] = (char)((v & 0x3F) | sign); - return 3; - } else if (v<0x8000000) { - buffer[0] = (char)(((v>>20) & 0x7f) | 0x80); - buffer[1] = (char)(((v>>13) & 0x7f) | 0x80); - buffer[2] = (char)(((v>> 6) & 0x7f) | 0x80); - buffer[3] = (char)((v & 0x3F) | sign); - return 4; - } - buffer[0] = (char)(((v>>27) & 0x7f) | 0x80); - buffer[1] = (char)(((v>>20) & 0x7f) | 0x80); - buffer[2] = (char)(((v>>13) & 0x7f) | 0x80); - buffer[3] = (char)(((v>> 6) & 0x7f) | 0x80); - buffer[4] = (char)((v & 0x3F) | sign); - return 5; -} - -INLINE_FUNCTION int -unpack_int(const char * buffer) -{ - int i = 0, v = 0; - - while (buffer[i] & 0x80) { - v = (v << 7) | (buffer[i++] & 0x7f); - } - v = (v << 6) | (buffer[i] & 0x3f); - - if (buffer[i] & 0x40) { - v = ~v + 1; - } - return v; -} - -static int -bin_w_brk(struct storage * store) -{ - return 0; -} - -static int -bin_w_int_pak(struct storage * store, int arg) -{ - char buffer[5]; - size_t size = pack_int(arg, buffer); - return (int)fwrite(buffer, sizeof(char), size, file(store)); -} - -static int -bin_r_int_pak(struct storage * store) -{ - int v = 0; - char ch; - - fread(&ch, sizeof(char), 1, file(store)); - while (ch & 0x80) { - v = (v << 7) | (ch & 0x7f); - fread(&ch, sizeof(char), 1, file(store)); - } - v = (v << 6) | (ch & 0x3f); - - if (ch & 0x40) { - v = ~v + 1; - } - return v; -} - -static int -bin_w_int(struct storage * store, int arg) -{ - return (int)fwrite(&arg, sizeof(arg), 1, file(store)); -} - -static int -bin_r_int(struct storage * store) -{ - int result; - fread(&result, sizeof(result), 1, file(store)); - return result; -} - -static int -bin_w_flt(struct storage * store, float arg) -{ - return (int)fwrite(&arg, sizeof(arg), 1, file(store)); -} - -static float -bin_r_flt(struct storage * store) -{ - float result; - fread(&result, sizeof(result), 1, file(store)); - return result; -} - -static int -bin_w_str(struct storage * store, const char * tok) -{ - int result; - if (tok==NULL || tok[0]==0) { - result = store->w_int(store, 0); - } else { - int size = (int)strlen(tok); - result = store->w_int(store, size); - result += (int)fwrite(tok, size, 1, file(store)); - } - return result; -} - -#define FIX_INVALID_CHARS /* required for data pre-574 */ -static char * -bin_r_str(struct storage * store) -{ - int len; - - len = store->r_int(store); - if (len>=0) { - char * result = malloc(len+1); - - fread(result, sizeof(char), len, file(store)); - result[len] = 0; -#ifdef FIX_INVALID_CHARS - { - char * p = strpbrk(result, "\n\r"); - while (p) { - log_error(("Invalid character %d in input string \"%s\".\n", *p, result)); - strcpy(p, p+1); - p = strpbrk(p, "\n\r"); - } - } -#endif - return result; - } else if (len<0) { - log_error(("invalid string-length %d in input.\n", len)); - } - return NULL; -} - -static void -bin_r_str_buf(struct storage * store, char * result, size_t size) -{ - int i; - size_t rd, len; - - i = store->r_int(store); - assert(i>=0); - if (i==0) { - result[0] = 0; - } else { - len = (size_t)i; - rd = MIN(len, size-1); - fread(result, sizeof(char), rd, file(store)); - if (rdw_int(store, len); - if (len>0) { - result += (int)fwrite(arg, len, 1, file(store)); - } - return result; -} - -static void -bin_r_bin(struct storage * store, void * result, size_t size) -{ - int len = store->r_int(store); - if (len>0) { - if ((size_t)len>size) { - log_error(("destination buffer too small %d %u.\n", len, size)); - fseek(file(store), len, SEEK_CUR); - } else { - fread(result, len, 1, file(store)); - } - } -} - - -static int -bin_open(struct storage * store, const char * filename, int mode) -{ - const char * modes[] = { 0, "rb", "wb", "ab" }; - FILE * F = fopen(filename, modes[mode]); - store->userdata = F; - store->encoding = ENCODING_UTF8; /* always utf8 it is */ - if (F) { - if (mode==IO_READ) { - int stream_version = 0; - store->version = bin_r_int(store); - if (store->version>=INTPAK_VERSION) { - stream_version = bin_r_int(store); - } - if (stream_version<=1) { - store->r_id = bin_r_int; - store->w_id = bin_w_int; - } - if (stream_version==0) { - store->r_int = bin_r_int; - store->w_int = bin_w_int; - } - } else if (store->encoding==ENCODING_UTF8) { - bin_w_int(store, RELEASE_VERSION); - bin_w_int(store, STREAM_VERSION); - } - } - return (F==NULL); -} - -static int -bin_close(struct storage * store) -{ - return fclose(file(store)); -} - -const storage binary_store = { - bin_w_brk, /* newline (ignore) */ - bin_w_int_pak, bin_r_int_pak, /* int storage */ - bin_w_flt, bin_r_flt, /* float storage */ - bin_w_int_pak, bin_r_int_pak, /* id storage */ - bin_w_str, bin_r_str, bin_r_str_buf, /* token storage */ - bin_w_str, bin_r_str, bin_r_str_buf, /* string storage */ - bin_w_bin, bin_r_bin, /* binary storage */ - bin_open, bin_close, - 0, 0, NULL -}; - +/* vi: set ts=2: ++-------------------+ Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel ++-------------------+ +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ +#include +#include "config.h" +#include "textstore.h" + +#include "save.h" +#include "version.h" +#include +#include + +#include +#include +#include +#include + +#define file(store) (FILE *)((store)->userdata) + +#define STREAM_VERSION 2 + +INLINE_FUNCTION size_t +pack_int(int v, char * buffer) +{ + int sign = (v<0); + + if (sign) { + v = ~v + 1; + sign = 0x40; + } + if (v<0x40) { + buffer[0] = (char)(v | sign); + return 1; + } else if (v<0x2000) { + buffer[0] = (char)((v>> 6) | 0x80); + buffer[1] = (char)((v & 0x3F) | sign); + return 2; + } else if (v<0x100000) { + buffer[0] = (char)(((v>>13) & 0x7f) | 0x80); + buffer[1] = (char)(((v>> 6) & 0x7f) | 0x80); + buffer[2] = (char)((v & 0x3F) | sign); + return 3; + } else if (v<0x8000000) { + buffer[0] = (char)(((v>>20) & 0x7f) | 0x80); + buffer[1] = (char)(((v>>13) & 0x7f) | 0x80); + buffer[2] = (char)(((v>> 6) & 0x7f) | 0x80); + buffer[3] = (char)((v & 0x3F) | sign); + return 4; + } + buffer[0] = (char)(((v>>27) & 0x7f) | 0x80); + buffer[1] = (char)(((v>>20) & 0x7f) | 0x80); + buffer[2] = (char)(((v>>13) & 0x7f) | 0x80); + buffer[3] = (char)(((v>> 6) & 0x7f) | 0x80); + buffer[4] = (char)((v & 0x3F) | sign); + return 5; +} + +INLINE_FUNCTION int +unpack_int(const char * buffer) +{ + int i = 0, v = 0; + + while (buffer[i] & 0x80) { + v = (v << 7) | (buffer[i++] & 0x7f); + } + v = (v << 6) | (buffer[i] & 0x3f); + + if (buffer[i] & 0x40) { + v = ~v + 1; + } + return v; +} + +static int +bin_w_brk(struct storage * store) +{ + return 0; +} + +static int +bin_w_int_pak(struct storage * store, int arg) +{ + char buffer[5]; + size_t size = pack_int(arg, buffer); + return (int)fwrite(buffer, sizeof(char), size, file(store)); +} + +static int +bin_r_int_pak(struct storage * store) +{ + int v = 0; + char ch; + + fread(&ch, sizeof(char), 1, file(store)); + while (ch & 0x80) { + v = (v << 7) | (ch & 0x7f); + fread(&ch, sizeof(char), 1, file(store)); + } + v = (v << 6) | (ch & 0x3f); + + if (ch & 0x40) { + v = ~v + 1; + } + return v; +} + +static int +bin_w_int(struct storage * store, int arg) +{ + return (int)fwrite(&arg, sizeof(arg), 1, file(store)); +} + +static int +bin_r_int(struct storage * store) +{ + int result; + fread(&result, sizeof(result), 1, file(store)); + return result; +} + +static int +bin_w_flt(struct storage * store, float arg) +{ + return (int)fwrite(&arg, sizeof(arg), 1, file(store)); +} + +static float +bin_r_flt(struct storage * store) +{ + float result; + fread(&result, sizeof(result), 1, file(store)); + return result; +} + +static int +bin_w_str(struct storage * store, const char * tok) +{ + int result; + if (tok==NULL || tok[0]==0) { + result = store->w_int(store, 0); + } else { + int size = (int)strlen(tok); + result = store->w_int(store, size); + result += (int)fwrite(tok, size, 1, file(store)); + } + return result; +} + +#define FIX_INVALID_CHARS /* required for data pre-574 */ +static char * +bin_r_str(struct storage * store) +{ + int len; + + len = store->r_int(store); + if (len>=0) { + char * result = malloc(len+1); + + fread(result, sizeof(char), len, file(store)); + result[len] = 0; +#ifdef FIX_INVALID_CHARS + { + char * p = strpbrk(result, "\n\r"); + while (p) { + log_error(("Invalid character %d in input string \"%s\".\n", *p, result)); + strcpy(p, p+1); + p = strpbrk(p, "\n\r"); + } + } +#endif + return result; + } else if (len<0) { + log_error(("invalid string-length %d in input.\n", len)); + } + return NULL; +} + +static void +bin_r_str_buf(struct storage * store, char * result, size_t size) +{ + int i; + size_t rd, len; + + i = store->r_int(store); + assert(i>=0); + if (i==0) { + result[0] = 0; + } else { + len = (size_t)i; + rd = MIN(len, size-1); + fread(result, sizeof(char), rd, file(store)); + if (rdw_int(store, len); + if (len>0) { + result += (int)fwrite(arg, len, 1, file(store)); + } + return result; +} + +static void +bin_r_bin(struct storage * store, void * result, size_t size) +{ + int len = store->r_int(store); + if (len>0) { + if ((size_t)len>size) { + log_error(("destination buffer too small %d %u.\n", len, size)); + fseek(file(store), len, SEEK_CUR); + } else { + fread(result, len, 1, file(store)); + } + } +} + + +static int +bin_open(struct storage * store, const char * filename, int mode) +{ + const char * modes[] = { 0, "rb", "wb", "ab" }; + FILE * F = fopen(filename, modes[mode]); + store->userdata = F; + store->encoding=XML_CHAR_ENCODING_UTF8; /* always utf8 it is */ + if (F) { + if (mode==IO_READ) { + int stream_version = 0; + store->version = bin_r_int(store); + if (store->version>=INTPAK_VERSION) { + stream_version = bin_r_int(store); + } + if (stream_version<=1) { + store->r_id = bin_r_int; + store->w_id = bin_w_int; + } + if (stream_version==0) { + store->r_int = bin_r_int; + store->w_int = bin_w_int; + } + } else if (store->encoding==XML_CHAR_ENCODING_UTF8) { + bin_w_int(store, RELEASE_VERSION); + bin_w_int(store, STREAM_VERSION); + } + } + return (F==NULL); +} + +static int +bin_close(struct storage * store) +{ + return fclose(file(store)); +} + +const storage binary_store = { + bin_w_brk, /* newline (ignore) */ + bin_w_int_pak, bin_r_int_pak, /* int storage */ + bin_w_flt, bin_r_flt, /* float storage */ + bin_w_int_pak, bin_r_int_pak, /* id storage */ + bin_w_str, bin_r_str, bin_r_str_buf, /* token storage */ + bin_w_str, bin_r_str, bin_r_str_buf, /* string storage */ + bin_w_bin, bin_r_bin, /* binary storage */ + bin_open, bin_close, + 0, 0, NULL +}; + diff --git a/src/kernel/binarystore.h b/src/kernel/binarystore.h index 6ab4c16fb..8ba979667 100644 --- a/src/kernel/binarystore.h +++ b/src/kernel/binarystore.h @@ -1,23 +1,23 @@ -/* vi: set ts=2: -+-------------------+ Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -+-------------------+ -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifndef H_KERNEL_BINSTORE -#define H_KERNEL_BINSTORE -#ifdef __cplusplus -extern "C" { -#endif - -#include - -extern const storage binary_store; - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: ++-------------------+ Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel ++-------------------+ +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifndef H_KERNEL_BINSTORE +#define H_KERNEL_BINSTORE +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern const storage binary_store; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/build.c b/src/kernel/build.c index 77adbcfca..50ab584c4 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -1,1349 +1,1350 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "build.h" - -/* kernel includes */ -#include "alchemy.h" -#include "alliance.h" -#include "connection.h" -#include "building.h" -#include "curse.h" -#include "faction.h" -#include "group.h" -#include "item.h" -#include "magic.h" -#include "message.h" -#include "move.h" -#include "order.h" -#include "pool.h" -#include "race.h" -#include "region.h" -#include "ship.h" -#include "skill.h" -#include "terrain.h" -#include "terrainid.h" -#include "unit.h" - -/* from libutil */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* from libc */ -#include -#include -#include -#include -#include -#include - -/* attributes inclues */ -#include -#include - -#define STONERECYCLE 50 -/* Name, MaxGroesse, MinBauTalent, Kapazitaet, {Eisen, Holz, Stein, BauSilber, - * Laen, Mallorn}, UnterSilber, UnterSpezialTyp, UnterSpezial */ - - -static boolean -CheckOverload(void) -{ - static int value = -1; - if (value<0) { - value = get_param_int(global.parameters, "rules.check_overload", 0); - } - return value; -} - -/* test if the unit can slip through a siege undetected. - * returns 0 if siege is successful, or 1 if the building is either - * not besieged or the unit can slip through the siege due to better stealth. - */ -static int -slipthru(const region * r, const unit * u, const building * b) -{ - unit *u2; - int n, o; - - /* b ist die burg, in die man hinein oder aus der man heraus will. */ - if (b==NULL || b->besieged < b->size * SIEGEFACTOR) { - return 1; - } - - /* u wird am hinein- oder herausschluepfen gehindert, wenn STEALTH <= - * OBSERVATION +2 der belagerer u2 ist */ - n = eff_skill(u, SK_STEALTH, r); - - for (u2 = r->units; u2; u2 = u2->next) { - if (usiege(u2) == b) { - - if (invisible(u, u2) >= u->number) continue; - - o = eff_skill(u2, SK_PERCEPTION, r); - - if (o + 2 >= n) { - return 0; /* entdeckt! */ - } - } - } - return 1; -} - -boolean -can_contact(const region * r, const unit * u, const unit * u2) -{ - - /* hier geht es nur um die belagerung von burgen */ - - if (u->building == u2->building) - return true; - - /* unit u is trying to contact u2 - unasked for contact. wenn u oder u2 - * nicht in einer burg ist, oder die burg nicht belagert ist, ist - * slipthru () == 1. ansonsten ist es nur 1, wenn man die belagerer */ - - if (slipthru(u->region, u, u->building) - && slipthru(u->region, u2, u2->building)) - return true; - - if (alliedunit(u, u2->faction, HELP_GIVE)) - return true; - - return false; -} - - -static void -contact_cmd(unit * u, order * ord, boolean tries) -{ - /* unit u kontaktiert unit u2. Dies setzt den contact einfach auf 1 - - * ein richtiger toggle ist (noch?) nicht noetig. die region als - * parameter ist nur deswegen wichtig, weil er an getunit () - * weitergegeben wird. dies wird fuer das auffinden von tempunits in - * getnewunit () verwendet! */ - unit *u2; - region * r = u->region; - - init_tokens(ord); - skip_token(); - u2 = getunitg(r, u->faction); - - if (u2!=NULL) { - if (!can_contact(r, u, u2)) { - if (tries) cmistake(u, u->thisorder, 23, MSG_EVENT); - return; - } - usetcontact(u, u2); - } -} -/* ------------------------------------------------------------- */ - -/* ------------------------------------------------------------- */ - - -/* ------------------------------------------------------------- */ - -struct building * -getbuilding(const struct region * r) -{ - building * b = findbuilding(getid()); - if (b==NULL || r!=b->region) return NULL; - return b; -} - -ship * -getship(const struct region * r) -{ - ship *sh, *sx = findship(getshipid()); - for (sh = r->ships; sh; sh = sh->next) { - if (sh == sx) return sh; - } - return NULL; -} - -/* ------------------------------------------------------------- */ - -static void -siege_cmd(unit * u, order * ord) -{ - region * r = u->region; - building *b; - int d, pooled; - int bewaffnete, katapultiere = 0; - static boolean init = false; - static const curse_type * magicwalls_ct; - static item_type * it_catapultammo = NULL; - static item_type * it_catapult = NULL; - if (!init) { - init = true; - magicwalls_ct = ct_find("magicwalls"); - it_catapultammo = it_find("catapultammo"); - it_catapult = it_find("catapult"); - } - /* gibt es ueberhaupt Burgen? */ - - init_tokens(ord); - skip_token(); - b = getbuilding(r); - - if (!b) { - cmistake(u, ord, 31, MSG_BATTLE); - return; - } - - if (!playerrace(u->race)) { - /* keine Drachen, Illusionen, Untote etc */ - cmistake(u, ord, 166, MSG_BATTLE); - return; - } - /* schaden durch katapulte */ - - d = i_get(u->items, it_catapult); - d = MIN(u->number, d); - pooled = get_pooled(u, it_catapultammo->rtype, GET_DEFAULT, d); - d = MIN(pooled, d); - if (eff_skill(u, SK_CATAPULT, r) >= 1) { - katapultiere = d; - d *= eff_skill(u, SK_CATAPULT, r); - } else { - d = 0; - } - - bewaffnete = armedmen(u, true); - if (d == 0 && bewaffnete == 0) { - /* abbruch, falls unbewaffnet oder unfaehig, katapulte zu benutzen */ - cmistake(u, ord, 80, MSG_EVENT); - return; - } - - if (!is_guard(u, GUARD_TRAVELTHRU)) { - /* abbruch, wenn die einheit nicht vorher die region bewacht - als - * warnung fuer alle anderen! */ - cmistake(u, ord, 81, MSG_EVENT); - return; - } - /* einheit und burg markieren - spart zeit beim behandeln der einheiten - * in der burg, falls die burg auch markiert ist und nicht alle - * einheiten wieder abgesucht werden muessen! */ - - usetsiege(u, b); - b->besieged += MAX(bewaffnete, katapultiere); - - /* definitiver schaden eingeschraenkt */ - - d = MIN(d, b->size - 1); - - /* meldung, schaden anrichten */ - if (d && !curse_active(get_curse(b->attribs, magicwalls_ct))) { - b->size -= d; - use_pooled(u, it_catapultammo->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, d); - /* send message to the entire region */ - ADDMSG(&r->msgs, msg_message("siege_catapults", - "unit building destruction", u, b, d)); - } else { - /* send message to the entire region */ - ADDMSG(&r->msgs, msg_message("siege", - "unit building", u, b)); - } -} - -void -do_siege(region *r) -{ - if (fval(r->terrain, LAND_REGION)) { - unit *u; - - for (u = r->units; u; u = u->next) { - if (get_keyword(u->thisorder) == K_BESIEGE) { - siege_cmd(u, u->thisorder); - } - } - } -} -/* ------------------------------------------------------------- */ - -static void -destroy_road(unit *u, int nmax, struct order * ord) -{ - direction_t d = getdirection(u->faction->locale); - unit *u2; - region *r = u->region; - short n = (short)nmax; - - if (nmax>SHRT_MAX) n = SHRT_MAX; - else if (nmax<0) n = 0; - - for (u2=r->units;u2;u2=u2->next) { - if (u2->faction!=u->faction && is_guard(u2, GUARD_TAX) - && cansee(u2->faction, u->region, u, 0) - && !alliedunit(u, u2->faction, HELP_GUARD)) { - cmistake(u, ord, 70, MSG_EVENT); - return; - } - } - - if (d==NODIRECTION) { - /* Die Richtung wurde nicht erkannt */ - cmistake(u, ord, 71, MSG_PRODUCE); - } else { - short road = rroad(r, d); - n = MIN(n, road); - if (n!=0) { - region * r2 = rconnect(r,d); - int willdo = eff_skill(u, SK_ROAD_BUILDING, r)*u->number; - willdo = MIN(willdo, n); - if (willdo==0) { - /* TODO: error message */ - } - if (willdo>SHRT_MAX) road = 0; - else road = road - (short)willdo; - rsetroad(r, d, road); - ADDMSG(&u->faction->msgs, msg_message("destroy_road", - "unit from to", u, r, r2)); - } - } -} - -int -destroy_cmd(unit * u, struct order * ord) -{ - ship *sh; - unit *u2; - region * r = u->region; - const construction * con = NULL; - int size = 0; - const char *s; - int n = INT_MAX; - - if (u->number < 1) - return 0; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - - if (findparam(s, u->faction->locale)==P_ROAD) { - destroy_road(u, INT_MAX, ord); - return 0; - } - - if (s && *s) { - n = atoi((const char *)s); - if (n <= 0) { - cmistake(u, ord, 288, MSG_PRODUCE); - return 0; - } - } - - if (getparam(u->faction->locale) == P_ROAD) { - destroy_road(u, n, ord); - return 0; - } - - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 138, MSG_PRODUCE); - return 0; - } - - if (u->building) { - building *b = u->building; - - if (n >= b->size) { - /* destroy completly */ - /* all units leave the building */ - for (u2 = r->units; u2; u2 = u2->next) { - if (u2->building == b) { - u2->building = 0; - freset(u2, UFL_OWNER); - } - } - ADDMSG(&u->faction->msgs, msg_message("destroy", - "building unit", b, u)); - con = b->type->construction; - remove_building(&r->buildings, b); - } else { - /* partial destroy */ - b->size -= n; - ADDMSG(&u->faction->msgs, msg_message("destroy_partial", - "building unit", b, u)); - } - } else if (u->ship) { - sh = u->ship; - - if (fval(r->terrain, SEA_REGION)) { - cmistake(u, ord, 14, MSG_EVENT); - return 0; - } - - if (n >= (sh->size*100)/sh->type->construction->maxsize) { - /* destroy completly */ - /* all units leave the ship */ - for (u2 = r->units; u2; u2 = u2->next) { - if (u2->ship == sh) { - u2->ship = 0; - freset(u2, UFL_OWNER); - } - } - ADDMSG(&u->faction->msgs, msg_message("shipdestroy", - "unit region ship", u, r, sh)); - con = sh->type->construction; - remove_ship(&sh->region->ships, sh); - } else { - /* partial destroy */ - sh->size -= (sh->type->construction->maxsize * n)/100; - ADDMSG(&u->faction->msgs, msg_message("shipdestroy_partial", - "unit region ship", u, r, sh)); - } - } else { - log_error(("Die Einheit %s von %s war owner eines objects, war aber weder in einer Burg noch in einem Schiff.\n", - unitname(u), u->faction->name, u->faction->email)); - } - - if (con) { - /* TODO: Nicht an ZERSTÖRE mit Punktangabe angepaßt! */ - int c; - for (c=0;con->materials[c].number;++c) { - const requirement * rq = con->materials+c; - int recycle = (int)(rq->recycle * rq->number * size/con->reqsize); - if (recycle) { - change_resource(u, rq->rtype, recycle); - } - } - } - return 0; -} -/* ------------------------------------------------------------- */ - -void -build_road(region * r, unit * u, int size, direction_t d) -{ - int n, left; - region * rn = rconnect(r,d); - - assert(u->number); - if (!eff_skill(u, SK_ROAD_BUILDING, r)) { - cmistake(u, u->thisorder, 103, MSG_PRODUCE); - return; - } - if (besieged(u)) { - cmistake(u, u->thisorder, 60, MSG_PRODUCE); - return; - } - - if (rn==NULL || rn->terrain->max_road < 0) { - cmistake(u, u->thisorder, 94, MSG_PRODUCE); - return; - } - - if (r->terrain->max_road < 0) { - cmistake(u, u->thisorder, 94, MSG_PRODUCE); - return; - } - - if (r->terrain == newterrain(T_SWAMP)) { - /* wenn kein Damm existiert */ - static const struct building_type * bt_dam; - if (!bt_dam) bt_dam = bt_find("dam"); - assert(bt_dam); - if (!buildingtype_exists(r, bt_dam, true)) { - cmistake(u, u->thisorder, 132, MSG_PRODUCE); - return; - } - } else if (r->terrain == newterrain(T_DESERT)) { - static const struct building_type * bt_caravan; - if (!bt_caravan) bt_caravan = bt_find("caravan"); - assert(bt_caravan); - /* wenn keine Karawanserei existiert */ - if (!buildingtype_exists(r, bt_caravan, true)) { - cmistake(u, u->thisorder, 133, MSG_PRODUCE); - return; - } - } else if (r->terrain == newterrain(T_GLACIER)) { - static const struct building_type * bt_tunnel; - if (!bt_tunnel) bt_tunnel = bt_find("tunnel"); - assert(bt_tunnel); - /* wenn kein Tunnel existiert */ - if (!buildingtype_exists(r, bt_tunnel, true)) { - cmistake(u, u->thisorder, 131, MSG_PRODUCE); - return; - } - } - - /* left kann man noch bauen */ - left = r->terrain->max_road - rroad(r, d); - - /* hoffentlich ist r->road <= r->terrain->max_road, n also >= 0 */ - if (left <= 0) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_roads_finished", "")); - return; - } - - if (size>0) left = MIN(size, left); - /* baumaximum anhand der rohstoffe */ - if (u->race == new_race[RC_STONEGOLEM]){ - n = u->number * GOLEM_STONE; - } else { - n = get_pooled(u, oldresourcetype[R_STONE], GET_DEFAULT, left); - if (n==0) { - cmistake(u, u->thisorder, 151, MSG_PRODUCE); - return; - } - } - left = MIN(n, left); - - /* n = maximum by skill. try to maximize it */ - n = u->number * eff_skill(u, SK_ROAD_BUILDING, r); - if (n < left) { - item * itm = *i_find(&u->items, olditemtype[I_RING_OF_NIMBLEFINGER]); - if (itm!=NULL && itm->number>0) { - int rings = MIN(u->number, itm->number); - n = n * ((roqf_factor()-1)*rings+u->number) / u->number; - } - } - if (n < left) { - int dm = get_effect(u, oldpotiontype[P_DOMORE]); - if (dm != 0) { - int sk = eff_skill(u, SK_ROAD_BUILDING, r); - int todo = (left - n + sk - 1) / sk; - todo = MIN(todo, u->number); - dm = MIN(dm, todo); - change_effect(u, oldpotiontype[P_DOMORE], -dm); - n += dm * sk; - } /* Auswirkung Schaffenstrunk */ - } - - /* make minimum of possible and available: */ - n = MIN(left, n); - - /* n is now modified by several special effects, so we have to - * minimize it again to make sure the road will not grow beyond - * maximum. */ - rsetroad(r, d, rroad(r, d) + (short)n); - - if (u->race == new_race[RC_STONEGOLEM]) { - int golemsused = n / GOLEM_STONE; - if (n%GOLEM_STONE != 0){ - ++golemsused; - } - scale_number(u, u->number - golemsused); - } else { - use_pooled(u, oldresourcetype[R_STONE], GET_DEFAULT, n); - /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ - produceexp(u, SK_ROAD_BUILDING, MIN(n, u->number)); - } - ADDMSG(&u->faction->msgs, msg_message("buildroad", - "region unit size", r, u, n)); -} -/* ------------------------------------------------------------- */ - -/* ** ** ** ** ** ** * - * new build rules * - * ** ** ** ** ** ** */ - -static int -required(int size, int msize, int maxneed) - /* um size von msize Punkten zu bauen, - * braucht man required von maxneed resourcen */ -{ - int used; - - used = size * maxneed / msize; - if (size * maxneed % msize) - ++used; - return used; -} - -static int -matmod(const attrib * a, const unit * u, const resource_type * material, int value) -{ - for (a=a_find((attrib*)a, &at_matmod);a && a->type==&at_matmod;a=a->next) { - mm_fun fun = (mm_fun)a->data.f; - value = fun(u, material, value); - if (value<0) return value; /* pass errors to caller */ - } - return value; -} - -int roqf_factor(void) -{ - int value = -1; - if (value<0) { - value = get_param_int(global.parameters, "rules.economy.roqf", 10); - } - return value; -} - -/** Use up resources for building an object. -* Build up to 'size' points of 'type', where 'completed' -* of the first object have already been finished. return the -* actual size that could be built. -*/ -int -build(unit * u, const construction * ctype, int completed, int want) -{ - const construction * type = ctype; - int skills = INT_MAX; /* number of skill points remainig */ - int basesk = 0; - int made = 0; - - if (want<=0) return 0; - if (type==NULL) return 0; - if (type->improvement==NULL && completed==type->maxsize) - return ECOMPLETE; - if (type->btype!=NULL) { - building * b; - if (!u->building || u->building->type!=type->btype) { - return EBUILDINGREQ; - } - b = inside_building(u); - if (b==NULL) return EBUILDINGREQ; - } - - if (type->skill!=NOSKILL) { - int effsk; - int dm = get_effect(u, oldpotiontype[P_DOMORE]); - - assert(u->number); - basesk = effskill(u, type->skill); - if (basesk==0) return ENEEDSKILL; - - effsk = basesk; - if (inside_building(u)) { - effsk = skillmod(u->building->type->attribs, u, u->region, type->skill, - effsk, SMF_PRODUCTION); - } - effsk = skillmod(type->attribs, u, u->region, type->skill, - effsk, SMF_PRODUCTION); - if (effsk<0) return effsk; /* pass errors to caller */ - if (effsk==0) return ENEEDSKILL; - - skills = effsk * u->number; - - /* technically, nimblefinge and domore should be in a global set of - * "game"-attributes, (as at_skillmod) but for a while, we're leaving - * them in here. */ - - if (dm != 0) { - /* Auswirkung Schaffenstrunk */ - dm = MIN(dm, u->number); - change_effect(u, oldpotiontype[P_DOMORE], -dm); - skills += dm * effsk; - } - } - for (;want>0 && skills>0;) { - int c, n; - - /* skip over everything that's already been done: - * type->improvement==NULL means no more improvements, but no size limits - * type->improvement==type means build another object of the same time - * while material lasts type->improvement==x means build x when type - * is finished */ - while (type->improvement!=NULL && - type->improvement!=type && - type->maxsize>0 && - type->maxsize<=completed) - { - completed -= type->maxsize; - type = type->improvement; - } - if (type==NULL) { - if (made==0) return ECOMPLETE; - break; /* completed */ - } - - /* Hier ist entweder maxsize == -1, oder completed < maxsize. - * Andernfalls ist das Datenfile oder sonstwas kaputt... - * (enno): Nein, das ist für Dinge, bei denen die nächste Ausbaustufe - * die gleiche wie die vorherige ist. z.b. gegenstände. - */ - if (type->maxsize>1) { - completed = completed % type->maxsize; - } - else { - completed = 0; assert(type->reqsize>=1); - } - - if (basesk < type->minskill) { - if (made==0) return ELOWSKILL; /* not good enough to go on */ - } - - /* n = maximum buildable size */ - if (type->minskill > 1) { - n = skills / type->minskill; - } else { - n = skills; - } - /* Flinkfingerring wirkt nicht auf Mengenbegrenzte (magische) - * Talente */ - if (skill_limit(u->faction, type->skill)==INT_MAX) { - int i = 0; - item * itm = *i_find(&u->items, olditemtype[I_RING_OF_NIMBLEFINGER]); - if (itm!=NULL) i = itm->number; - if (i>0) { - int rings = MIN(u->number, i); - n = n * ((roqf_factor()-1)*rings+u->number) / u->number; - } - } - - if (want>0) { - n = MIN(want, n); - } - - if (type->maxsize>0) { - n = MIN(type->maxsize-completed, n); - if (type->improvement==NULL) { - want = n; - } - } - - if (type->materials) for (c=0;n>0 && type->materials[c].number;c++) { - const struct resource_type * rtype = type->materials[c].rtype; - int need, prebuilt; - int canuse = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); - - if (inside_building(u)) { - canuse = matmod(u->building->type->attribs, u, rtype, canuse); - } - - if (canuse<0) return canuse; /* pass errors to caller */ - canuse = matmod(type->attribs, u, rtype, canuse); - if (type->reqsize>1) { - prebuilt = required(completed, type->reqsize, type->materials[c].number); - for (;n;) { - need = required(completed + n, type->reqsize, type->materials[c].number); - if (need-prebuilt<=canuse) break; - --n; /* TODO: optimieren? */ - } - } else { - int maxn = canuse / type->materials[c].number; - if (maxn < n) n = maxn; - } - } - if (n<=0) { - if (made==0) return ENOMATERIALS; - else break; - } - if (type->materials) for (c=0;type->materials[c].number;c++) { - const struct resource_type * rtype = type->materials[c].rtype; - int prebuilt = required(completed, type->reqsize, type->materials[c].number); - int need = required(completed + n, type->reqsize, type->materials[c].number); - int multi = 1; - int canuse = 100; /* normalization */ - if (inside_building(u)) canuse = matmod(u->building->type->attribs, u, rtype, canuse); - if (canuse<0) return canuse; /* pass errors to caller */ - canuse = matmod(type->attribs, u, rtype, canuse); - - assert(canuse % 100 == 0 || !"only constant multipliers are implemented in build()"); - multi = canuse/100; - if (canuse<0) return canuse; /* pass errors to caller */ - - use_pooled(u, rtype, GET_DEFAULT, (need-prebuilt+multi-1)/multi); - } - made += n; - skills -= n * type->minskill; - want -= n; - completed = completed + n; - } - /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ - produceexp(u, ctype->skill, MIN(made, u->number)); - - return made; -} - -message * -msg_materials_required(unit * u, order * ord, const construction * ctype, int multi) -{ - int c; - /* something missing from the list of materials */ - resource * reslist = NULL; - - if (multi<=0 || multi==INT_MAX) multi = 1; - for (c=0;ctype->materials[c].number; ++c) { - resource * res = malloc(sizeof(resource)); - res->number = multi * ctype->materials[c].number / ctype->reqsize; - res->type = ctype->materials[c].rtype; - res->next = reslist; - reslist = res; - } - return msg_feedback(u, ord, "build_required", "required", reslist); -} - -int -maxbuild(const unit * u, const construction * cons) - /* calculate maximum size that can be built from available material */ - /* !! ignores maximum objectsize and improvements...*/ -{ - int c; - int maximum = INT_MAX; - for (c=0;cons->materials[c].number;c++) { - const resource_type * rtype = cons->materials[c].rtype; - int have = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); - int need = required(1, cons->reqsize, cons->materials[c].number); - if (haveregion; - boolean newbuilding = false; - int n = want, built = 0, id; - building * b = NULL; - /* einmalige Korrektur */ - const char * btname; - order * new_order = NULL; - const struct locale * lang = u->faction->locale; - static int rule_other = -1; - - assert(u->number); - if (eff_skill(u, SK_BUILDING, r) == 0) { - cmistake(u, ord, 101, MSG_PRODUCE); - return; - } - - /* Falls eine Nummer angegeben worden ist, und ein Gebaeude mit der - * betreffenden Nummer existiert, ist b nun gueltig. Wenn keine Burg - * gefunden wurde, dann wird nicht einfach eine neue erbaut. Ansonsten - * baut man an der eigenen burg weiter. */ - - /* Wenn die angegebene Nummer falsch ist, KEINE Burg bauen! */ - id = getid(); - if (id>0) { /* eine Nummer angegeben, keine neue Burg bauen */ - b = findbuilding(id); - if (!b || b->region != u->region) { /* eine Burg mit dieser Nummer gibt es hier nicht */ - /* vieleicht Tippfehler und die eigene Burg ist gemeint? */ - if (u->building && u->building->type==btype) { - b = u->building; - } else { - /* keine neue Burg anfangen wenn eine Nummer angegeben war */ - cmistake(u, ord, 6, MSG_PRODUCE); - return; - } - } - } else if (u->building && u->building->type==btype) { - b = u->building; - } - - if (b) btype = b->type; - - if (b && fval(btype, BTF_UNIQUE) && buildingtype_exists(r, btype, false)) { - /* only one of these per region */ - cmistake(u, ord, 93, MSG_PRODUCE); - return; - } - if (besieged(u)) { - /* units under siege can not build */ - cmistake(u, ord, 60, MSG_PRODUCE); - return; - } - if (btype->flags & BTF_NOBUILD) { - /* special building, cannot be built */ - cmistake(u, ord, 221, MSG_PRODUCE); - return; - } - if (btype->flags & BTF_ONEPERTURN) { - if(b && fval(b, BLD_EXPANDED)) { - cmistake(u, ord, 318, MSG_PRODUCE); - return; - } - n = 1; - } - if (b) { - if (rule_other<0) { - rule_other = get_param_int(global.parameters, "rules.build.other_buildings", 1); - } - if (!rule_other) { - unit * owner = building_owner(b); - if (!owner || owner->faction!=u->faction) { - cmistake(u, ord, 1222, MSG_PRODUCE); - return; - } - } - } - - if (b) built = b->size; - if (n<=0 || n == INT_MAX) { - if(b == NULL) { - if(btype->maxsize > 0) { - n = btype->maxsize - built; - } else { - n = INT_MAX; - } - } else { - if (b->type->maxsize > 0) { - n = b->type->maxsize - built; - } else { - n = INT_MAX; - } - } - } - built = build(u, btype->construction, built, n); - - switch (built) { - case ECOMPLETE: - /* the building is already complete */ - cmistake(u, ord, 4, MSG_PRODUCE); - return; - case ENOMATERIALS: - ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, btype->construction, want)); - return; - case ELOWSKILL: - case ENEEDSKILL: - /* no skill, or not enough skill points to build */ - cmistake(u, ord, 50, MSG_PRODUCE); - return; - } - - - /* at this point, the building size is increased. */ - if (b==NULL) { - /* build a new building */ - b = new_building(btype, r, lang); - b->type = btype; - fset(b, BLD_MAINTAINED); - - /* Die Einheit befindet sich automatisch im Inneren der neuen Burg. */ - if (leave(u, false)) { - u->building = b; - fset(u, UFL_OWNER); - } - -#ifdef WDW_PYRAMID - if(b->type == bt_find("pyramid") && f_get_alliance(u->faction) != NULL) { - attrib * a = a_add(&b->attribs, a_new(&at_alliance)); - a->data.i = u->faction->alliance->id; - } -#endif - - newbuilding = true; - } - - btname = LOC(lang, btype->_name); - - if (want-built <= 0) { - /* gebäude fertig */ - new_order = default_order(lang); - } else if (want!=INT_MAX) { - /* reduzierte restgröße */ - const char * hasspace = strchr(btname, ' '); - if (hasspace) { - new_order = create_order(K_MAKE, lang, "%d \"%s\" %i", n-built, btname, b->no); - } else { - new_order = create_order(K_MAKE, lang, "%d %s %i", n-built, btname, b->no); - } - } else if (btname) { - /* Neues Haus, Befehl mit Gebäudename */ - const char * hasspace = strchr(btname, ' '); - if (hasspace) { - new_order = create_order(K_MAKE, lang, "\"%s\" %i", btname, b->no); - } else { - new_order = create_order(K_MAKE, lang, "%s %i", btname, b->no); - } - } - - if (new_order) { - replace_order(&u->orders, ord, new_order); - free_order(new_order); - } - - b->size += built; - fset(b, BLD_EXPANDED); - - update_lighthouse(b); - - - ADDMSG(&u->faction->msgs, msg_message("buildbuilding", - "building unit size", b, u, built)); -} - -static void -build_ship(unit * u, ship * sh, int want) -{ - const construction * construction = sh->type->construction; - int size = (sh->size * DAMAGE_SCALE - sh->damage) / DAMAGE_SCALE; - int n; - int can = build(u, construction, size, want); - - if ((n=construction->maxsize - sh->size)>0 && can>0) { - if (can>=n) { - sh->size += n; - can -= n; - } - else { - sh->size += can; - n=can; - can = 0; - } - } - - if (sh->damage && can) { - int repair = MIN(sh->damage, can * DAMAGE_SCALE); - n += repair / DAMAGE_SCALE; - if (repair % DAMAGE_SCALE) ++n; - sh->damage = sh->damage - repair; - } - - if (n) ADDMSG(&u->faction->msgs, - msg_message("buildship", "ship unit size", sh, u, n)); -} - -void -create_ship(region * r, unit * u, const struct ship_type * newtype, int want, order * ord) -{ - ship *sh; - int msize; - const construction * cons = newtype->construction; - order * new_order; - - if (!eff_skill(u, SK_SHIPBUILDING, r)) { - cmistake(u, ord, 100, MSG_PRODUCE); - return; - } - if (besieged(u)) { - cmistake(u, ord, 60, MSG_PRODUCE); - return; - } - - /* check if skill and material for 1 size is available */ - if (eff_skill(u, cons->skill, r) < cons->minskill) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_build_skill_low", "value name", - cons->minskill, newtype->name[1])); - return; - } - - msize = maxbuild(u, cons); - if (msize==0) { - cmistake(u, ord, 88, MSG_PRODUCE); - return; - } - if (want>0) want = MIN(want, msize); - else want = msize; - - sh = new_ship(newtype, u->faction->locale, r); - - if (leave(u, false)) { - if (fval(u->race, RCF_CANSAIL)) { - u->ship = sh; - fset(u, UFL_OWNER); - } - } - new_order = create_order(K_MAKE, u->faction->locale, "%s %i", LOC(u->faction->locale, parameters[P_SHIP]), sh->no); - replace_order(&u->orders, ord, new_order); - free_order(new_order); - - build_ship(u, sh, want); -} - -void -continue_ship(region * r, unit * u, int want) -{ - const construction * cons; - ship *sh; - int msize; - - if (!eff_skill(u, SK_SHIPBUILDING, r)) { - cmistake(u, u->thisorder, 100, MSG_PRODUCE); - return; - } - - /* Die Schiffsnummer bzw der Schiffstyp wird eingelesen */ - sh = getship(r); - - if (!sh) sh = u->ship; - - if (!sh) { - cmistake(u, u->thisorder, 20, MSG_PRODUCE); - return; - } - cons = sh->type->construction; - assert(cons->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */ - if (sh->size==cons->maxsize && !sh->damage) { - cmistake(u, u->thisorder, 16, MSG_PRODUCE); - return; - } - if (eff_skill(u, cons->skill, r) < cons->minskill) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_build_skill_low", "value name", - cons->minskill, sh->type->name[1])); - return; - } - msize = maxbuild(u, cons); - if (msize==0) { - cmistake(u, u->thisorder, 88, MSG_PRODUCE); - return; - } - if (want > 0) want = MIN(want, msize); - else want = msize; - - build_ship(u, sh, want); -} -/* ------------------------------------------------------------- */ - -static boolean -mayenter(region * r, unit * u, building * b) -{ - unit *u2; - if (fval(b, BLD_UNGUARDED)) return true; - u2 = building_owner(b); - - if (u2==NULL || ucontact(u2, u) - || alliedunit(u2, u->faction, HELP_GUARD)) return true; - - return false; -} - -static int -mayboard(const unit * u, const ship * sh) -{ - unit *u2 = shipowner(sh); - - return (!u2 || ucontact(u2, u) || alliedunit(u2, u->faction, HELP_GUARD)); -} - -int -leave_cmd(unit * u, struct order * ord) -{ - region * r = u->region; - - if (fval(u, UFL_ENTER)) { - /* if we just entered this round, then we don't leave again */ - return 0; - } - - if (fval(r->terrain, SEA_REGION) && u->ship) { - if(!fval(u->race, RCF_SWIM)) { - cmistake(u, ord, 11, MSG_MOVE); - return 0; - } - if (has_horses(u)) { - cmistake(u, ord, 231, MSG_MOVE); - return 0; - } - } - if (!slipthru(r, u, u->building)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "entrance_besieged", "building", u->building)); - } else { - leave(u, true); - } - return 0; -} - -static boolean -enter_ship(unit * u, struct order * ord, int id, boolean report) -{ - region * r = u->region; - ship * sh; - - /* Muß abgefangen werden, sonst könnten Schwimmer an - * Bord von Schiffen an Land gelangen. */ - if (!fval(u->race, RCF_CANSAIL) || (!fval(u->race, RCF_WALK) && !fval(u->race, RCF_FLY))) { - cmistake(u, ord, 233, MSG_MOVE); - return false; - } - - sh = findship(id); - if (sh == NULL || sh->region!=r) { - if (report) cmistake(u, ord, 20, MSG_MOVE); - return false; - } - if (sh==u->ship) return true; - if (!mayboard(u, sh)) { - if (report) cmistake(u, ord, 34, MSG_MOVE); - return false; - } - if (CheckOverload()) { - int sweight, scabins; - int mweight = shipcapacity(sh); - int mcabins = sh->type->cabins; - - if (mweight>0) { - getshipweight(sh, &sweight, &scabins); - sweight += weight(u); - if (mcabins) { - int pweight = u->number * u->race->weight; - /* weight goes into number of cabins, not cargo */ - scabins += pweight; - sweight -= pweight; - } - - if (sweight > mweight || (mcabins && (scabins > mcabins))) { - if (report) cmistake(u, ord, 34, MSG_MOVE); - return false; - } - } - } - - if (leave(u, false)) { - u->ship = sh; - - if (shipowner(sh) == NULL) { - fset(u, UFL_OWNER); - } - fset(u, UFL_ENTER); - } - return true; -} - -static boolean -enter_building(unit * u, order * ord, int id, boolean report) -{ - region * r = u->region; - building * b; - - /* Schwimmer können keine Gebäude betreten, außer diese sind - * auf dem Ozean */ - if (!fval(u->race, RCF_WALK) && !fval(u->race, RCF_FLY)) { - if (!fval(r->terrain, SEA_REGION)) { - if (report) { - cmistake(u, ord, 232, MSG_MOVE); - } - return false; - } - } - - b = findbuilding(id); - if (b==NULL || b->region!=r) { - if (report) { - cmistake(u, ord, 6, MSG_MOVE); - } - return false; - } - if (!mayenter(r, u, b)) { - if (report) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "entrance_denied", "building", b)); - } - return false; - } - if (!slipthru(r, u, b)) { - if (report) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "entrance_besieged", "building", b)); - } - return false; - } - - if (leave(u, false)) { - if (building_owner(b) == 0) { - fset(u, UFL_OWNER); - } - fset(u, UFL_ENTER); - u->building = b; - return true; - } - return false; -} - -void -do_misc(region * r, boolean lasttry) -{ - unit **uptr, *uc; - - for (uc = r->units; uc; uc = uc->next) { - order * ord; - for (ord = uc->orders; ord; ord = ord->next) { - switch (get_keyword(ord)) { - case K_CONTACT: - contact_cmd(uc, ord, lasttry); - break; - } - } - } - - for (uptr = &r->units; *uptr;) { - unit * u = *uptr; - order ** ordp = &u->orders; - - while (*ordp) { - order * ord = *ordp; - if (get_keyword(ord) == K_ENTER) { - param_t p; - int id; - unit * ulast = NULL; - - init_tokens(ord); - skip_token(); - p = getparam(u->faction->locale); - id = getid(); - - switch (p) { - case P_BUILDING: - case P_GEBAEUDE: - if (u->building && u->building->no==id) break; - if (enter_building(u, ord, id, lasttry)) { - unit *ub; - for (ub=u;ub;ub=ub->next) { - if (ub->building==u->building) { - ulast = ub; - } - } - } - break; - - case P_SHIP: - if (u->ship && u->ship->no==id) break; - if (enter_ship(u, ord, id, lasttry)) { - unit *ub; - ulast = u; - for (ub=u;ub;ub=ub->next) { - if (ub->ship==u->ship) { - ulast = ub; - } - } - } - break; - - default: - if (lasttry) cmistake(u, ord, 79, MSG_MOVE); - - } - if (ulast!=NULL) { - /* Wenn wir hier angekommen sind, war der Befehl - * erfolgreich und wir löschen ihn, damit er im - * zweiten Versuch nicht nochmal ausgeführt wird. */ - *ordp = ord->next; - ord->next = NULL; - free_order(ord); - - if (ulast!=u) { - /* put u behind ulast so it's the last unit in the building */ - *uptr = u->next; - u->next = ulast->next; - ulast->next = u; - } - break; - } - } - if (*ordp==ord) ordp = &ord->next; - } - if (*uptr==u) uptr = &u->next; - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "build.h" + +/* kernel includes */ +#include "alchemy.h" +#include "alliance.h" +#include "connection.h" +#include "building.h" +#include "curse.h" +#include "faction.h" +#include "group.h" +#include "item.h" +#include "magic.h" +#include "message.h" +#include "move.h" +#include "order.h" +#include "pool.h" +#include "race.h" +#include "region.h" +#include "ship.h" +#include "skill.h" +#include "terrain.h" +#include "terrainid.h" +#include "unit.h" + +/* from libutil */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* from libc */ +#include +#include +#include +#include +#include +#include + +/* attributes inclues */ +#include +#include + +#define STONERECYCLE 50 +/* Name, MaxGroesse, MinBauTalent, Kapazitaet, {Eisen, Holz, Stein, BauSilber, + * Laen, Mallorn}, UnterSilber, UnterSpezialTyp, UnterSpezial */ + + +static boolean +CheckOverload(void) +{ + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "rules.check_overload", 0); + } + return value; +} + +/* test if the unit can slip through a siege undetected. + * returns 0 if siege is successful, or 1 if the building is either + * not besieged or the unit can slip through the siege due to better stealth. + */ +static int +slipthru(const region * r, const unit * u, const building * b) +{ + unit *u2; + int n, o; + + /* b ist die burg, in die man hinein oder aus der man heraus will. */ + if (b==NULL || b->besieged < b->size * SIEGEFACTOR) { + return 1; + } + + /* u wird am hinein- oder herausschluepfen gehindert, wenn STEALTH <= + * OBSERVATION +2 der belagerer u2 ist */ + n = eff_skill(u, SK_STEALTH, r); + + for (u2 = r->units; u2; u2 = u2->next) { + if (usiege(u2) == b) { + + if (invisible(u, u2) >= u->number) continue; + + o = eff_skill(u2, SK_PERCEPTION, r); + + if (o + 2 >= n) { + return 0; /* entdeckt! */ + } + } + } + return 1; +} + +boolean +can_contact(const region * r, const unit * u, const unit * u2) +{ + + /* hier geht es nur um die belagerung von burgen */ + + if (u->building == u2->building) + return true; + + /* unit u is trying to contact u2 - unasked for contact. wenn u oder u2 + * nicht in einer burg ist, oder die burg nicht belagert ist, ist + * slipthru () == 1. ansonsten ist es nur 1, wenn man die belagerer */ + + if (slipthru(u->region, u, u->building) + && slipthru(u->region, u2, u2->building)) + return true; + + if (alliedunit(u, u2->faction, HELP_GIVE)) + return true; + + return false; +} + + +static void +contact_cmd(unit * u, order * ord, boolean tries) +{ + /* unit u kontaktiert unit u2. Dies setzt den contact einfach auf 1 - + * ein richtiger toggle ist (noch?) nicht noetig. die region als + * parameter ist nur deswegen wichtig, weil er an getunit () + * weitergegeben wird. dies wird fuer das auffinden von tempunits in + * getnewunit () verwendet! */ + unit *u2; + region * r = u->region; + + init_tokens(ord); + skip_token(); + u2 = getunitg(r, u->faction); + + if (u2!=NULL) { + if (!can_contact(r, u, u2)) { + if (tries) cmistake(u, u->thisorder, 23, MSG_EVENT); + return; + } + usetcontact(u, u2); + } +} +/* ------------------------------------------------------------- */ + +/* ------------------------------------------------------------- */ + + +/* ------------------------------------------------------------- */ + +struct building * +getbuilding(const struct region * r) +{ + building * b = findbuilding(getid()); + if (b==NULL || r!=b->region) return NULL; + return b; +} + +ship * +getship(const struct region * r) +{ + ship *sh, *sx = findship(getshipid()); + for (sh = r->ships; sh; sh = sh->next) { + if (sh == sx) return sh; + } + return NULL; +} + +/* ------------------------------------------------------------- */ + +static void +siege_cmd(unit * u, order * ord) +{ + region * r = u->region; + building *b; + int d, pooled; + int bewaffnete, katapultiere = 0; + static boolean init = false; + static const curse_type * magicwalls_ct; + static item_type * it_catapultammo = NULL; + static item_type * it_catapult = NULL; + if (!init) { + init = true; + magicwalls_ct = ct_find("magicwalls"); + it_catapultammo = it_find("catapultammo"); + it_catapult = it_find("catapult"); + } + /* gibt es ueberhaupt Burgen? */ + + init_tokens(ord); + skip_token(); + b = getbuilding(r); + + if (!b) { + cmistake(u, ord, 31, MSG_BATTLE); + return; + } + + if (!playerrace(u->race)) { + /* keine Drachen, Illusionen, Untote etc */ + cmistake(u, ord, 166, MSG_BATTLE); + return; + } + /* schaden durch katapulte */ + + d = i_get(u->items, it_catapult); + d = MIN(u->number, d); + pooled = get_pooled(u, it_catapultammo->rtype, GET_DEFAULT, d); + d = MIN(pooled, d); + if (eff_skill(u, SK_CATAPULT, r) >= 1) { + katapultiere = d; + d *= eff_skill(u, SK_CATAPULT, r); + } else { + d = 0; + } + + bewaffnete = armedmen(u, true); + if (d == 0 && bewaffnete == 0) { + /* abbruch, falls unbewaffnet oder unfaehig, katapulte zu benutzen */ + cmistake(u, ord, 80, MSG_EVENT); + return; + } + + if (!is_guard(u, GUARD_TRAVELTHRU)) { + /* abbruch, wenn die einheit nicht vorher die region bewacht - als + * warnung fuer alle anderen! */ + cmistake(u, ord, 81, MSG_EVENT); + return; + } + /* einheit und burg markieren - spart zeit beim behandeln der einheiten + * in der burg, falls die burg auch markiert ist und nicht alle + * einheiten wieder abgesucht werden muessen! */ + + usetsiege(u, b); + b->besieged += MAX(bewaffnete, katapultiere); + + /* definitiver schaden eingeschraenkt */ + + d = MIN(d, b->size - 1); + + /* meldung, schaden anrichten */ + if (d && !curse_active(get_curse(b->attribs, magicwalls_ct))) { + b->size -= d; + use_pooled(u, it_catapultammo->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, d); + /* send message to the entire region */ + ADDMSG(&r->msgs, msg_message("siege_catapults", + "unit building destruction", u, b, d)); + } else { + /* send message to the entire region */ + ADDMSG(&r->msgs, msg_message("siege", + "unit building", u, b)); + } +} + +void +do_siege(region *r) +{ + if (fval(r->terrain, LAND_REGION)) { + unit *u; + + for (u = r->units; u; u = u->next) { + if (get_keyword(u->thisorder) == K_BESIEGE) { + siege_cmd(u, u->thisorder); + } + } + } +} +/* ------------------------------------------------------------- */ + +static void +destroy_road(unit *u, int nmax, struct order * ord) +{ + direction_t d = getdirection(u->faction->locale); + unit *u2; + region *r = u->region; + short n = (short)nmax; + + if (nmax>SHRT_MAX) n = SHRT_MAX; + else if (nmax<0) n = 0; + + for (u2=r->units;u2;u2=u2->next) { + if (u2->faction!=u->faction && is_guard(u2, GUARD_TAX) + && cansee(u2->faction, u->region, u, 0) + && !alliedunit(u, u2->faction, HELP_GUARD)) { + cmistake(u, ord, 70, MSG_EVENT); + return; + } + } + + if (d==NODIRECTION) { + /* Die Richtung wurde nicht erkannt */ + cmistake(u, ord, 71, MSG_PRODUCE); + } else { + short road = rroad(r, d); + n = MIN(n, road); + if (n!=0) { + region * r2 = rconnect(r,d); + int willdo = eff_skill(u, SK_ROAD_BUILDING, r)*u->number; + willdo = MIN(willdo, n); + if (willdo==0) { + /* TODO: error message */ + } + if (willdo>SHRT_MAX) road = 0; + else road = road - (short)willdo; + rsetroad(r, d, road); + ADDMSG(&u->faction->msgs, msg_message("destroy_road", + "unit from to", u, r, r2)); + } + } +} + +int +destroy_cmd(unit * u, struct order * ord) +{ + ship *sh; + unit *u2; + region * r = u->region; + const construction * con = NULL; + int size = 0; + const char *s; + int n = INT_MAX; + + if (u->number < 1) + return 0; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + + if (findparam(s, u->faction->locale)==P_ROAD) { + destroy_road(u, INT_MAX, ord); + return 0; + } + + if (s && *s) { + n = atoi((const char *)s); + if (n <= 0) { + cmistake(u, ord, 288, MSG_PRODUCE); + return 0; + } + } + + if (getparam(u->faction->locale) == P_ROAD) { + destroy_road(u, n, ord); + return 0; + } + + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 138, MSG_PRODUCE); + return 0; + } + + if (u->building) { + building *b = u->building; + + if (n >= b->size) { + /* destroy completly */ + /* all units leave the building */ + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->building == b) { + u2->building = 0; + freset(u2, UFL_OWNER); + } + } + ADDMSG(&u->faction->msgs, msg_message("destroy", + "building unit", b, u)); + con = b->type->construction; + remove_building(&r->buildings, b); + } else { + /* partial destroy */ + b->size -= n; + ADDMSG(&u->faction->msgs, msg_message("destroy_partial", + "building unit", b, u)); + } + } else if (u->ship) { + sh = u->ship; + + if (fval(r->terrain, SEA_REGION)) { + cmistake(u, ord, 14, MSG_EVENT); + return 0; + } + + if (n >= (sh->size*100)/sh->type->construction->maxsize) { + /* destroy completly */ + /* all units leave the ship */ + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->ship == sh) { + u2->ship = 0; + freset(u2, UFL_OWNER); + } + } + ADDMSG(&u->faction->msgs, msg_message("shipdestroy", + "unit region ship", u, r, sh)); + con = sh->type->construction; + remove_ship(&sh->region->ships, sh); + } else { + /* partial destroy */ + sh->size -= (sh->type->construction->maxsize * n)/100; + ADDMSG(&u->faction->msgs, msg_message("shipdestroy_partial", + "unit region ship", u, r, sh)); + } + } else { + log_error(("Die Einheit %s von %s war owner eines objects, war aber weder in einer Burg noch in einem Schiff.\n", + unitname(u), u->faction->name, u->faction->email)); + } + + if (con) { + /* TODO: Nicht an ZERSTÖRE mit Punktangabe angepaßt! */ + int c; + for (c=0;con->materials[c].number;++c) { + const requirement * rq = con->materials+c; + int recycle = (int)(rq->recycle * rq->number * size/con->reqsize); + if (recycle) { + change_resource(u, rq->rtype, recycle); + } + } + } + return 0; +} +/* ------------------------------------------------------------- */ + +void +build_road(region * r, unit * u, int size, direction_t d) +{ + int n, left; + region * rn = rconnect(r,d); + + assert(u->number); + if (!eff_skill(u, SK_ROAD_BUILDING, r)) { + cmistake(u, u->thisorder, 103, MSG_PRODUCE); + return; + } + if (besieged(u)) { + cmistake(u, u->thisorder, 60, MSG_PRODUCE); + return; + } + + if (rn==NULL || rn->terrain->max_road < 0) { + cmistake(u, u->thisorder, 94, MSG_PRODUCE); + return; + } + + if (r->terrain->max_road < 0) { + cmistake(u, u->thisorder, 94, MSG_PRODUCE); + return; + } + + if (r->terrain == newterrain(T_SWAMP)) { + /* wenn kein Damm existiert */ + static const struct building_type * bt_dam; + if (!bt_dam) bt_dam = bt_find("dam"); + assert(bt_dam); + if (!buildingtype_exists(r, bt_dam, true)) { + cmistake(u, u->thisorder, 132, MSG_PRODUCE); + return; + } + } else if (r->terrain == newterrain(T_DESERT)) { + static const struct building_type * bt_caravan; + if (!bt_caravan) bt_caravan = bt_find("caravan"); + assert(bt_caravan); + /* wenn keine Karawanserei existiert */ + if (!buildingtype_exists(r, bt_caravan, true)) { + cmistake(u, u->thisorder, 133, MSG_PRODUCE); + return; + } + } else if (r->terrain == newterrain(T_GLACIER)) { + static const struct building_type * bt_tunnel; + if (!bt_tunnel) bt_tunnel = bt_find("tunnel"); + assert(bt_tunnel); + /* wenn kein Tunnel existiert */ + if (!buildingtype_exists(r, bt_tunnel, true)) { + cmistake(u, u->thisorder, 131, MSG_PRODUCE); + return; + } + } + + /* left kann man noch bauen */ + left = r->terrain->max_road - rroad(r, d); + + /* hoffentlich ist r->road <= r->terrain->max_road, n also >= 0 */ + if (left <= 0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_roads_finished", "")); + return; + } + + if (size>0) left = MIN(size, left); + /* baumaximum anhand der rohstoffe */ + if (u->race == new_race[RC_STONEGOLEM]){ + n = u->number * GOLEM_STONE; + } else { + n = get_pooled(u, oldresourcetype[R_STONE], GET_DEFAULT, left); + if (n==0) { + cmistake(u, u->thisorder, 151, MSG_PRODUCE); + return; + } + } + left = MIN(n, left); + + /* n = maximum by skill. try to maximize it */ + n = u->number * eff_skill(u, SK_ROAD_BUILDING, r); + if (n < left) { + item * itm = *i_find(&u->items, olditemtype[I_RING_OF_NIMBLEFINGER]); + if (itm!=NULL && itm->number>0) { + int rings = MIN(u->number, itm->number); + n = n * ((roqf_factor()-1)*rings+u->number) / u->number; + } + } + if (n < left) { + int dm = get_effect(u, oldpotiontype[P_DOMORE]); + if (dm != 0) { + int sk = eff_skill(u, SK_ROAD_BUILDING, r); + int todo = (left - n + sk - 1) / sk; + todo = MIN(todo, u->number); + dm = MIN(dm, todo); + change_effect(u, oldpotiontype[P_DOMORE], -dm); + n += dm * sk; + } /* Auswirkung Schaffenstrunk */ + } + + /* make minimum of possible and available: */ + n = MIN(left, n); + + /* n is now modified by several special effects, so we have to + * minimize it again to make sure the road will not grow beyond + * maximum. */ + rsetroad(r, d, rroad(r, d) + (short)n); + + if (u->race == new_race[RC_STONEGOLEM]) { + int golemsused = n / GOLEM_STONE; + if (n%GOLEM_STONE != 0){ + ++golemsused; + } + scale_number(u, u->number - golemsused); + } else { + use_pooled(u, oldresourcetype[R_STONE], GET_DEFAULT, n); + /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ + produceexp(u, SK_ROAD_BUILDING, MIN(n, u->number)); + } + ADDMSG(&u->faction->msgs, msg_message("buildroad", + "region unit size", r, u, n)); +} +/* ------------------------------------------------------------- */ + +/* ** ** ** ** ** ** * + * new build rules * + * ** ** ** ** ** ** */ + +static int +required(int size, int msize, int maxneed) + /* um size von msize Punkten zu bauen, + * braucht man required von maxneed resourcen */ +{ + int used; + + used = size * maxneed / msize; + if (size * maxneed % msize) + ++used; + return used; +} + +static int +matmod(const attrib * a, const unit * u, const resource_type * material, int value) +{ + for (a=a_find((attrib*)a, &at_matmod);a && a->type==&at_matmod;a=a->next) { + mm_fun fun = (mm_fun)a->data.f; + value = fun(u, material, value); + if (value<0) return value; /* pass errors to caller */ + } + return value; +} + +int roqf_factor(void) +{ + int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "rules.economy.roqf", 10); + } + return value; +} + +/** Use up resources for building an object. +* Build up to 'size' points of 'type', where 'completed' +* of the first object have already been finished. return the +* actual size that could be built. +*/ +int +build(unit * u, const construction * ctype, int completed, int want) +{ + const construction * type = ctype; + int skills = INT_MAX; /* number of skill points remainig */ + int basesk = 0; + int made = 0; + + if (want<=0) return 0; + if (type==NULL) return 0; + if (type->improvement==NULL && completed==type->maxsize) + return ECOMPLETE; + if (type->btype!=NULL) { + building * b; + if (!u->building || u->building->type!=type->btype) { + return EBUILDINGREQ; + } + b = inside_building(u); + if (b==NULL) return EBUILDINGREQ; + } + + if (type->skill!=NOSKILL) { + int effsk; + int dm = get_effect(u, oldpotiontype[P_DOMORE]); + + assert(u->number); + basesk = effskill(u, type->skill); + if (basesk==0) return ENEEDSKILL; + + effsk = basesk; + if (inside_building(u)) { + effsk = skillmod(u->building->type->attribs, u, u->region, type->skill, + effsk, SMF_PRODUCTION); + } + effsk = skillmod(type->attribs, u, u->region, type->skill, + effsk, SMF_PRODUCTION); + if (effsk<0) return effsk; /* pass errors to caller */ + if (effsk==0) return ENEEDSKILL; + + skills = effsk * u->number; + + /* technically, nimblefinge and domore should be in a global set of + * "game"-attributes, (as at_skillmod) but for a while, we're leaving + * them in here. */ + + if (dm != 0) { + /* Auswirkung Schaffenstrunk */ + dm = MIN(dm, u->number); + change_effect(u, oldpotiontype[P_DOMORE], -dm); + skills += dm * effsk; + } + } + for (;want>0 && skills>0;) { + int c, n; + + /* skip over everything that's already been done: + * type->improvement==NULL means no more improvements, but no size limits + * type->improvement==type means build another object of the same time + * while material lasts type->improvement==x means build x when type + * is finished */ + while (type->improvement!=NULL && + type->improvement!=type && + type->maxsize>0 && + type->maxsize<=completed) + { + completed -= type->maxsize; + type = type->improvement; + } + if (type==NULL) { + if (made==0) return ECOMPLETE; + break; /* completed */ + } + + /* Hier ist entweder maxsize == -1, oder completed < maxsize. + * Andernfalls ist das Datenfile oder sonstwas kaputt... + * (enno): Nein, das ist für Dinge, bei denen die nächste Ausbaustufe + * die gleiche wie die vorherige ist. z.b. gegenstände. + */ + if (type->maxsize>1) { + completed = completed % type->maxsize; + } + else { + completed = 0; assert(type->reqsize>=1); + } + + if (basesk < type->minskill) { + if (made==0) return ELOWSKILL; /* not good enough to go on */ + } + + /* n = maximum buildable size */ + if (type->minskill > 1) { + n = skills / type->minskill; + } else { + n = skills; + } + /* Flinkfingerring wirkt nicht auf Mengenbegrenzte (magische) + * Talente */ + if (skill_limit(u->faction, type->skill)==INT_MAX) { + int i = 0; + item * itm = *i_find(&u->items, olditemtype[I_RING_OF_NIMBLEFINGER]); + if (itm!=NULL) i = itm->number; + if (i>0) { + int rings = MIN(u->number, i); + n = n * ((roqf_factor()-1)*rings+u->number) / u->number; + } + } + + if (want>0) { + n = MIN(want, n); + } + + if (type->maxsize>0) { + n = MIN(type->maxsize-completed, n); + if (type->improvement==NULL) { + want = n; + } + } + + if (type->materials) for (c=0;n>0 && type->materials[c].number;c++) { + const struct resource_type * rtype = type->materials[c].rtype; + int need, prebuilt; + int canuse = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); + + if (inside_building(u)) { + canuse = matmod(u->building->type->attribs, u, rtype, canuse); + } + + if (canuse<0) return canuse; /* pass errors to caller */ + canuse = matmod(type->attribs, u, rtype, canuse); + if (type->reqsize>1) { + prebuilt = required(completed, type->reqsize, type->materials[c].number); + for (;n;) { + need = required(completed + n, type->reqsize, type->materials[c].number); + if (need-prebuilt<=canuse) break; + --n; /* TODO: optimieren? */ + } + } else { + int maxn = canuse / type->materials[c].number; + if (maxn < n) n = maxn; + } + } + if (n<=0) { + if (made==0) return ENOMATERIALS; + else break; + } + if (type->materials) for (c=0;type->materials[c].number;c++) { + const struct resource_type * rtype = type->materials[c].rtype; + int prebuilt = required(completed, type->reqsize, type->materials[c].number); + int need = required(completed + n, type->reqsize, type->materials[c].number); + int multi = 1; + int canuse = 100; /* normalization */ + if (inside_building(u)) canuse = matmod(u->building->type->attribs, u, rtype, canuse); + if (canuse<0) return canuse; /* pass errors to caller */ + canuse = matmod(type->attribs, u, rtype, canuse); + + assert(canuse % 100 == 0 || !"only constant multipliers are implemented in build()"); + multi = canuse/100; + if (canuse<0) return canuse; /* pass errors to caller */ + + use_pooled(u, rtype, GET_DEFAULT, (need-prebuilt+multi-1)/multi); + } + made += n; + skills -= n * type->minskill; + want -= n; + completed = completed + n; + } + /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ + produceexp(u, ctype->skill, MIN(made, u->number)); + + return made; +} + +message * +msg_materials_required(unit * u, order * ord, const construction * ctype, int multi) +{ + int c; + /* something missing from the list of materials */ + resource * reslist = NULL; + + if (multi<=0 || multi==INT_MAX) multi = 1; + for (c=0;ctype->materials[c].number; ++c) { + resource * res = malloc(sizeof(resource)); + res->number = multi * ctype->materials[c].number / ctype->reqsize; + res->type = ctype->materials[c].rtype; + res->next = reslist; + reslist = res; + } + return msg_feedback(u, ord, "build_required", "required", reslist); +} + +int +maxbuild(const unit * u, const construction * cons) + /* calculate maximum size that can be built from available material */ + /* !! ignores maximum objectsize and improvements...*/ +{ + int c; + int maximum = INT_MAX; + for (c=0;cons->materials[c].number;c++) { + const resource_type * rtype = cons->materials[c].rtype; + int have = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); + int need = required(1, cons->reqsize, cons->materials[c].number); + if (haveregion; + boolean newbuilding = false; + int n = want, built = 0, id; + building * b = NULL; + /* einmalige Korrektur */ + const char * btname; + order * new_order = NULL; + const struct locale * lang = u->faction->locale; + static int rule_other = -1; + + assert(u->number); + if (eff_skill(u, SK_BUILDING, r) == 0) { + cmistake(u, ord, 101, MSG_PRODUCE); + return; + } + + /* Falls eine Nummer angegeben worden ist, und ein Gebaeude mit der + * betreffenden Nummer existiert, ist b nun gueltig. Wenn keine Burg + * gefunden wurde, dann wird nicht einfach eine neue erbaut. Ansonsten + * baut man an der eigenen burg weiter. */ + + /* Wenn die angegebene Nummer falsch ist, KEINE Burg bauen! */ + id = getid(); + if (id>0) { /* eine Nummer angegeben, keine neue Burg bauen */ + b = findbuilding(id); + if (!b || b->region != u->region) { /* eine Burg mit dieser Nummer gibt es hier nicht */ + /* vieleicht Tippfehler und die eigene Burg ist gemeint? */ + if (u->building && u->building->type==btype) { + b = u->building; + } else { + /* keine neue Burg anfangen wenn eine Nummer angegeben war */ + cmistake(u, ord, 6, MSG_PRODUCE); + return; + } + } + } else if (u->building && u->building->type==btype) { + b = u->building; + } + + if (b) btype = b->type; + + if (b && fval(btype, BTF_UNIQUE) && buildingtype_exists(r, btype, false)) { + /* only one of these per region */ + cmistake(u, ord, 93, MSG_PRODUCE); + return; + } + if (besieged(u)) { + /* units under siege can not build */ + cmistake(u, ord, 60, MSG_PRODUCE); + return; + } + if (btype->flags & BTF_NOBUILD) { + /* special building, cannot be built */ + cmistake(u, ord, 221, MSG_PRODUCE); + return; + } + if (btype->flags & BTF_ONEPERTURN) { + if(b && fval(b, BLD_EXPANDED)) { + cmistake(u, ord, 318, MSG_PRODUCE); + return; + } + n = 1; + } + if (b) { + if (rule_other<0) { + rule_other = get_param_int(global.parameters, "rules.build.other_buildings", 1); + } + if (!rule_other) { + unit * owner = building_owner(b); + if (!owner || owner->faction!=u->faction) { + cmistake(u, ord, 1222, MSG_PRODUCE); + return; + } + } + } + + if (b) built = b->size; + if (n<=0 || n == INT_MAX) { + if(b == NULL) { + if(btype->maxsize > 0) { + n = btype->maxsize - built; + } else { + n = INT_MAX; + } + } else { + if (b->type->maxsize > 0) { + n = b->type->maxsize - built; + } else { + n = INT_MAX; + } + } + } + built = build(u, btype->construction, built, n); + + switch (built) { + case ECOMPLETE: + /* the building is already complete */ + cmistake(u, ord, 4, MSG_PRODUCE); + return; + case ENOMATERIALS: + ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, btype->construction, want)); + return; + case ELOWSKILL: + case ENEEDSKILL: + /* no skill, or not enough skill points to build */ + cmistake(u, ord, 50, MSG_PRODUCE); + return; + } + + + /* at this point, the building size is increased. */ + if (b==NULL) { + /* build a new building */ + b = new_building(btype, r, lang); + b->type = btype; + fset(b, BLD_MAINTAINED); + + /* Die Einheit befindet sich automatisch im Inneren der neuen Burg. */ + if (leave(u, false)) { + u->building = b; + fset(u, UFL_OWNER); + } + +#ifdef WDW_PYRAMID + if(b->type == bt_find("pyramid") && f_get_alliance(u->faction) != NULL) { + attrib * a = a_add(&b->attribs, a_new(&at_alliance)); + a->data.i = u->faction->alliance->id; + } +#endif + + newbuilding = true; + } + + btname = LOC(lang, btype->_name); + + if (want-built <= 0) { + /* gebäude fertig */ + new_order = default_order(lang); + } else if (want!=INT_MAX) { + /* reduzierte restgröße */ + const char * hasspace = strchr(btname, ' '); + if (hasspace) { + new_order = create_order(K_MAKE, lang, "%d \"%s\" %i", n-built, btname, b->no); + } else { + new_order = create_order(K_MAKE, lang, "%d %s %i", n-built, btname, b->no); + } + } else if (btname) { + /* Neues Haus, Befehl mit Gebäudename */ + const char * hasspace = strchr(btname, ' '); + if (hasspace) { + new_order = create_order(K_MAKE, lang, "\"%s\" %i", btname, b->no); + } else { + new_order = create_order(K_MAKE, lang, "%s %i", btname, b->no); + } + } + + if (new_order) { + replace_order(&u->orders, ord, new_order); + free_order(new_order); + } + + b->size += built; + fset(b, BLD_EXPANDED); + + update_lighthouse(b); + + + ADDMSG(&u->faction->msgs, msg_message("buildbuilding", + "building unit size", b, u, built)); +} + +static void +build_ship(unit * u, ship * sh, int want) +{ + const construction * construction = sh->type->construction; + int size = (sh->size * DAMAGE_SCALE - sh->damage) / DAMAGE_SCALE; + int n; + int can = build(u, construction, size, want); + + if ((n=construction->maxsize - sh->size)>0 && can>0) { + if (can>=n) { + sh->size += n; + can -= n; + } + else { + sh->size += can; + n=can; + can = 0; + } + } + + if (sh->damage && can) { + int repair = MIN(sh->damage, can * DAMAGE_SCALE); + n += repair / DAMAGE_SCALE; + if (repair % DAMAGE_SCALE) ++n; + sh->damage = sh->damage - repair; + } + + if (n) ADDMSG(&u->faction->msgs, + msg_message("buildship", "ship unit size", sh, u, n)); +} + +void +create_ship(region * r, unit * u, const struct ship_type * newtype, int want, order * ord) +{ + ship *sh; + int msize; + const construction * cons = newtype->construction; + order * new_order; + + if (!eff_skill(u, SK_SHIPBUILDING, r)) { + cmistake(u, ord, 100, MSG_PRODUCE); + return; + } + if (besieged(u)) { + cmistake(u, ord, 60, MSG_PRODUCE); + return; + } + + /* check if skill and material for 1 size is available */ + if (eff_skill(u, cons->skill, r) < cons->minskill) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_build_skill_low", "value name", + cons->minskill, newtype->name[1])); + return; + } + + msize = maxbuild(u, cons); + if (msize==0) { + cmistake(u, ord, 88, MSG_PRODUCE); + return; + } + if (want>0) want = MIN(want, msize); + else want = msize; + + sh = new_ship(newtype, u->faction->locale, r); + + if (leave(u, false)) { + if (fval(u->race, RCF_CANSAIL)) { + u->ship = sh; + fset(u, UFL_OWNER); + } + } + new_order = create_order(K_MAKE, u->faction->locale, "%s %i", LOC(u->faction->locale, parameters[P_SHIP]), sh->no); + replace_order(&u->orders, ord, new_order); + free_order(new_order); + + build_ship(u, sh, want); +} + +void +continue_ship(region * r, unit * u, int want) +{ + const construction * cons; + ship *sh; + int msize; + + if (!eff_skill(u, SK_SHIPBUILDING, r)) { + cmistake(u, u->thisorder, 100, MSG_PRODUCE); + return; + } + + /* Die Schiffsnummer bzw der Schiffstyp wird eingelesen */ + sh = getship(r); + + if (!sh) sh = u->ship; + + if (!sh) { + cmistake(u, u->thisorder, 20, MSG_PRODUCE); + return; + } + cons = sh->type->construction; + assert(cons->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (sh->size==cons->maxsize && !sh->damage) { + cmistake(u, u->thisorder, 16, MSG_PRODUCE); + return; + } + if (eff_skill(u, cons->skill, r) < cons->minskill) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_build_skill_low", "value name", + cons->minskill, sh->type->name[1])); + return; + } + msize = maxbuild(u, cons); + if (msize==0) { + cmistake(u, u->thisorder, 88, MSG_PRODUCE); + return; + } + if (want > 0) want = MIN(want, msize); + else want = msize; + + build_ship(u, sh, want); +} +/* ------------------------------------------------------------- */ + +static boolean +mayenter(region * r, unit * u, building * b) +{ + unit *u2; + if (fval(b, BLD_UNGUARDED)) return true; + u2 = building_owner(b); + + if (u2==NULL || ucontact(u2, u) + || alliedunit(u2, u->faction, HELP_GUARD)) return true; + + return false; +} + +static int +mayboard(const unit * u, const ship * sh) +{ + unit *u2 = shipowner(sh); + + return (!u2 || ucontact(u2, u) || alliedunit(u2, u->faction, HELP_GUARD)); +} + +int +leave_cmd(unit * u, struct order * ord) +{ + region * r = u->region; + + if (fval(u, UFL_ENTER)) { + /* if we just entered this round, then we don't leave again */ + return 0; + } + + if (fval(r->terrain, SEA_REGION) && u->ship) { + if(!fval(u->race, RCF_SWIM)) { + cmistake(u, ord, 11, MSG_MOVE); + return 0; + } + if (has_horses(u)) { + cmistake(u, ord, 231, MSG_MOVE); + return 0; + } + } + if (!slipthru(r, u, u->building)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "entrance_besieged", "building", u->building)); + } else { + leave(u, true); + } + return 0; +} + +static boolean +enter_ship(unit * u, struct order * ord, int id, boolean report) +{ + region * r = u->region; + ship * sh; + + /* Muß abgefangen werden, sonst könnten Schwimmer an + * Bord von Schiffen an Land gelangen. */ + if (!fval(u->race, RCF_CANSAIL) || (!fval(u->race, RCF_WALK) && !fval(u->race, RCF_FLY))) { + cmistake(u, ord, 233, MSG_MOVE); + return false; + } + + sh = findship(id); + if (sh == NULL || sh->region!=r) { + if (report) cmistake(u, ord, 20, MSG_MOVE); + return false; + } + if (sh==u->ship) return true; + if (!mayboard(u, sh)) { + if (report) cmistake(u, ord, 34, MSG_MOVE); + return false; + } + if (CheckOverload()) { + int sweight, scabins; + int mweight = shipcapacity(sh); + int mcabins = sh->type->cabins; + + if (mweight>0) { + getshipweight(sh, &sweight, &scabins); + sweight += weight(u); + if (mcabins) { + int pweight = u->number * u->race->weight; + /* weight goes into number of cabins, not cargo */ + scabins += pweight; + sweight -= pweight; + } + + if (sweight > mweight || (mcabins && (scabins > mcabins))) { + if (report) cmistake(u, ord, 34, MSG_MOVE); + return false; + } + } + } + + if (leave(u, false)) { + u->ship = sh; + + if (shipowner(sh) == NULL) { + fset(u, UFL_OWNER); + } + fset(u, UFL_ENTER); + } + return true; +} + +static boolean +enter_building(unit * u, order * ord, int id, boolean report) +{ + region * r = u->region; + building * b; + + /* Schwimmer können keine Gebäude betreten, außer diese sind + * auf dem Ozean */ + if (!fval(u->race, RCF_WALK) && !fval(u->race, RCF_FLY)) { + if (!fval(r->terrain, SEA_REGION)) { + if (report) { + cmistake(u, ord, 232, MSG_MOVE); + } + return false; + } + } + + b = findbuilding(id); + if (b==NULL || b->region!=r) { + if (report) { + cmistake(u, ord, 6, MSG_MOVE); + } + return false; + } + if (!mayenter(r, u, b)) { + if (report) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "entrance_denied", "building", b)); + } + return false; + } + if (!slipthru(r, u, b)) { + if (report) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "entrance_besieged", "building", b)); + } + return false; + } + + if (leave(u, false)) { + if (building_owner(b) == 0) { + fset(u, UFL_OWNER); + } + fset(u, UFL_ENTER); + u->building = b; + return true; + } + return false; +} + +void +do_misc(region * r, boolean lasttry) +{ + unit **uptr, *uc; + + for (uc = r->units; uc; uc = uc->next) { + order * ord; + for (ord = uc->orders; ord; ord = ord->next) { + switch (get_keyword(ord)) { + case K_CONTACT: + contact_cmd(uc, ord, lasttry); + break; + } + } + } + + for (uptr = &r->units; *uptr;) { + unit * u = *uptr; + order ** ordp = &u->orders; + + while (*ordp) { + order * ord = *ordp; + if (get_keyword(ord) == K_ENTER) { + param_t p; + int id; + unit * ulast = NULL; + + init_tokens(ord); + skip_token(); + p = getparam(u->faction->locale); + id = getid(); + + switch (p) { + case P_BUILDING: + case P_GEBAEUDE: + if (u->building && u->building->no==id) break; + if (enter_building(u, ord, id, lasttry)) { + unit *ub; + for (ub=u;ub;ub=ub->next) { + if (ub->building==u->building) { + ulast = ub; + } + } + } + break; + + case P_SHIP: + if (u->ship && u->ship->no==id) break; + if (enter_ship(u, ord, id, lasttry)) { + unit *ub; + ulast = u; + for (ub=u;ub;ub=ub->next) { + if (ub->ship==u->ship) { + ulast = ub; + } + } + } + break; + + default: + if (lasttry) cmistake(u, ord, 79, MSG_MOVE); + + } + if (ulast!=NULL) { + /* Wenn wir hier angekommen sind, war der Befehl + * erfolgreich und wir löschen ihn, damit er im + * zweiten Versuch nicht nochmal ausgeführt wird. */ + *ordp = ord->next; + ord->next = NULL; + free_order(ord); + + if (ulast!=u) { + /* put u behind ulast so it's the last unit in the building */ + *uptr = u->next; + u->next = ulast->next; + ulast->next = u; + } + break; + } + } + if (*ordp==ord) ordp = &ord->next; + } + if (*uptr==u) uptr = &u->next; + } +} diff --git a/src/kernel/build.h b/src/kernel/build.h index 35d8f44a3..012f06000 100644 --- a/src/kernel/build.h +++ b/src/kernel/build.h @@ -1,99 +1,99 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_BUILD -#define H_KRNL_BUILD - -#include "types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Die enums fuer Gebauede werden nie gebraucht, nur bei der Bestimmung - * des Schutzes durch eine Burg wird die Reihenfolge und MAXBUILDINGS - * wichtig - */ - -struct xml_tag; - -typedef struct requirement { - const struct resource_type * rtype; - int number; - double recycle; /* recycling quota */ -} requirement; - -typedef struct construction { - skill_t skill; /* skill req'd per point of size */ - int minskill; /* skill req'd per point of size */ - - int maxsize; /* maximum size of this type */ - int reqsize; /* size of object using up 1 set of requirement. */ - requirement * materials; /* material req'd to build one object */ - const struct building_type * btype; - /* building type required to make this thing */ - - struct construction * improvement; - /* next level, if upgradable. if more than one of these items - * can be built (weapons, armour) per turn, must not be NULL, - * but point to the same type again: - * const_sword.improvement = &const_sword - * last level of a building points to NULL, as do objects of - * an unlimited size. - */ - struct attrib * attribs; - /* stores skill modifiers and other attributes */ - -} construction; - -extern int destroy_cmd(struct unit * u, struct order * ord); -extern int leave_cmd(struct unit * u, struct order * ord); - -extern boolean can_contact(const struct region *r, const struct unit *u, const struct unit *u2); - -void do_siege(struct region *r); -void build_road(struct region * r, struct unit * u, int size, direction_t d); -void create_ship(struct region * r, struct unit * u, const struct ship_type * newtype, int size, struct order * ord); -void continue_ship(struct region * r, struct unit * u, int size); - -struct building * getbuilding(const struct region * r); -struct ship *getship(const struct region * r); - -void do_misc(struct region *r, boolean tries); - -void reportevent(struct region * r, char *s); - -void shash(struct ship * sh); -void sunhash(struct ship * sh); -extern int roqf_factor(void); - -extern int build(struct unit * u, const construction * ctype, int completed, int want); -extern int maxbuild(const struct unit *u, const construction *cons); -extern struct message * msg_materials_required(struct unit * u, struct order * ord, const struct construction * ctype, int multi); -/** error messages that build may return: */ -#define ELOWSKILL -1 -#define ENEEDSKILL -2 -#define ECOMPLETE -3 -#define ENOMATERIALS -4 -#define EBUILDINGREQ -5 - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_BUILD +#define H_KRNL_BUILD + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Die enums fuer Gebauede werden nie gebraucht, nur bei der Bestimmung + * des Schutzes durch eine Burg wird die Reihenfolge und MAXBUILDINGS + * wichtig + */ + +struct xml_tag; + +typedef struct requirement { + const struct resource_type * rtype; + int number; + double recycle; /* recycling quota */ +} requirement; + +typedef struct construction { + skill_t skill; /* skill req'd per point of size */ + int minskill; /* skill req'd per point of size */ + + int maxsize; /* maximum size of this type */ + int reqsize; /* size of object using up 1 set of requirement. */ + requirement * materials; /* material req'd to build one object */ + const struct building_type * btype; + /* building type required to make this thing */ + + struct construction * improvement; + /* next level, if upgradable. if more than one of these items + * can be built (weapons, armour) per turn, must not be NULL, + * but point to the same type again: + * const_sword.improvement = &const_sword + * last level of a building points to NULL, as do objects of + * an unlimited size. + */ + struct attrib * attribs; + /* stores skill modifiers and other attributes */ + +} construction; + +extern int destroy_cmd(struct unit * u, struct order * ord); +extern int leave_cmd(struct unit * u, struct order * ord); + +extern boolean can_contact(const struct region *r, const struct unit *u, const struct unit *u2); + +void do_siege(struct region *r); +void build_road(struct region * r, struct unit * u, int size, direction_t d); +void create_ship(struct region * r, struct unit * u, const struct ship_type * newtype, int size, struct order * ord); +void continue_ship(struct region * r, struct unit * u, int size); + +struct building * getbuilding(const struct region * r); +struct ship *getship(const struct region * r); + +void do_misc(struct region *r, boolean tries); + +void reportevent(struct region * r, char *s); + +void shash(struct ship * sh); +void sunhash(struct ship * sh); +extern int roqf_factor(void); + +extern int build(struct unit * u, const construction * ctype, int completed, int want); +extern int maxbuild(const struct unit *u, const construction *cons); +extern struct message * msg_materials_required(struct unit * u, struct order * ord, const struct construction * ctype, int multi); +/** error messages that build may return: */ +#define ELOWSKILL -1 +#define ENEEDSKILL -2 +#define ECOMPLETE -3 +#define ENOMATERIALS -4 +#define EBUILDINGREQ -5 + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/kernel/building.c b/src/kernel/building.c index c16efe8b9..3b2553812 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -1,695 +1,695 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include - -#include -#include "building.h" - -/* kernel includes */ -#include "item.h" -#include "curse.h" /* für C_NOCOST */ -#include "unit.h" -#include "faction.h" -#include "region.h" -#include "skill.h" -#include "magic.h" -#include "save.h" -#include "version.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -/* attributes includes */ -#include - -static const char * NULLSTRING = "(null)"; - -static void -lc_init(struct attrib *a) -{ - a->data.v = calloc(1, sizeof(building_action)); -} - -static void -lc_done(struct attrib *a) -{ - building_action * data = (building_action*)a->data.v; - if (data->fname) free(data->fname); - if (data->param) free(data->param); - free(data); -} - -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; - const char * fparam = data->param; - building * b = data->b; - - write_building_reference(b, store); - store->w_tok(store, fname); - store->w_tok(store, fparam?fparam:NULLSTRING); -} - -static int -lc_read(struct attrib * a, void * owner, struct storage * store) -{ - building_action * data = (building_action*)a->data.v; - int result = read_reference(&data->b, store, read_building_reference, resolve_building); - if (store->versionfname = store->r_str(store); - } else { - data->fname = store->r_tok(store); - } - if (store->version>=BACTION_VERSION) { - char lbuf[256]; - if (store->versionr_str_buf(store, lbuf, sizeof(lbuf)); - } else { - store->r_tok_buf(store, lbuf, sizeof(lbuf)); - } - if (strcmp(lbuf, NULLSTRING)==0) data->param = NULL; - else data->param = strdup(lbuf); - } else { - data->param = strdup(NULLSTRING); - } - if (result==0 && !data->b) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -attrib_type at_building_action = { - "lcbuilding", - lc_init, lc_done, - NULL, - lc_write, lc_read -}; - -typedef struct building_typelist { - struct building_typelist * next; - building_type * type; -} building_typelist; - -static building_typelist *buildingtypes; - -building_type * -bt_find(const char* name) -{ - const struct building_typelist * btl = buildingtypes; - assert(name); - while (btl && strcmp(btl->type->_name, name)) btl = btl->next; - if (btl==NULL) { - return NULL; - } - return btl->type; -} - -void -bt_register(building_type * type) -{ - struct building_typelist * btl = malloc(sizeof(building_type)); - if (type->init) type->init(type); - btl->type = type; - btl->next = buildingtypes; - buildingtypes = btl; -} - -int -buildingcapacity(const building * b) -{ - if (b->type->capacity>=0) { - if (b->type->maxcapacity>=0) { - return MIN(b->type->maxcapacity, b->size * b->type->capacity); - } - return b->size * b->type->capacity; - } - if (b->size>=b->type->maxsize) { - if (b->type->maxcapacity>=0) { - return b->type->maxcapacity; - } - } - return 0; -} - -attrib_type at_building_generic_type = { - "building_generic_type", NULL, NULL, NULL, a_writestring, a_readstring, ATF_UNIQUE -}; - -const char * -buildingtype(const building_type * btype, const building * b, int bsize) -{ - const char * s = NULL; - static boolean init_generic = false; - static const struct building_type * bt_generic; - - if (!init_generic) { - init_generic = true; - bt_generic = bt_find("generic"); - } - - if (btype == bt_generic) { - const attrib *a = a_find(b->attribs, &at_building_generic_type); - if (a) s = (const char*)a->data.v; - } - - if (btype->name) s = btype->name(btype, b, bsize); - if (s==NULL) s = btype->_name; - return s; -} - -#define BMAXHASH 7919 -static building *buildhash[BMAXHASH]; -void -bhash(building * b) -{ - building *old = buildhash[b->no % BMAXHASH]; - - buildhash[b->no % BMAXHASH] = b; - b->nexthash = old; -} - -void -bunhash(building * b) -{ - building **show; - - for (show = &buildhash[b->no % BMAXHASH]; *show; show = &(*show)->nexthash) { - if ((*show)->no == b->no) - break; - } - if (*show) { - assert(*show == b); - *show = (*show)->nexthash; - b->nexthash = 0; - } -} - -static building * -bfindhash(int i) -{ - building *old; - - for (old = buildhash[i % BMAXHASH]; old; old = old->nexthash) - if (old->no == i) - return old; - return 0; -} - -building * -findbuilding(int i) -{ - return bfindhash(i); -} -/* ** old building types ** */ - - -static int -sm_smithy(const unit * u, const region * r, skill_t sk, int value) /* skillmod */ -{ - if (sk==SK_WEAPONSMITH || sk==SK_ARMORER) { - if (u->region == r) return value + 1; - } - return value; -} -static int -mm_smithy(const unit * u, const resource_type * rtype, int value) /* material-mod */ -{ - if (rtype == oldresourcetype[R_IRON]) return value * 2; - return value; -} -static void -init_smithy(struct building_type * bt) -{ - a_add(&bt->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION, sm_smithy, 1.0, 0)); - a_add(&bt->attribs, make_matmod(mm_smithy)); -} - -static const char * -castle_name_i(const struct building_type* btype, const struct building * b, int bsize, const char * fname[]) -{ - int i = bt_effsize(btype, b, bsize); - - return fname[i]; -} - -static const char * -castle_name_2(const struct building_type* btype, const struct building * b, int bsize) -{ - const char * fname[] = { - "site", - "fortification", - "tower", - "castle", - "fortress", - "citadel" - }; - return castle_name_i(btype, b, bsize, fname); -} - -static const char * -castle_name(const struct building_type* btype, const struct building * b, int bsize) -{ - const char * fname[] = { - "site", - "tradepost", - "fortification", - "tower", - "castle", - "fortress", - "citadel" - }; - return castle_name_i(btype, b, bsize, fname); -} - -static const char * -fort_name(const struct building_type* btype, const struct building * b, int bsize) -{ - const char * fname[] = { - "scaffolding", - "guardhouse", - "guardtower", - }; - return castle_name_i(btype, b, bsize, fname); -} - -#ifdef WDW_PYRAMID - -static const char * -pyramid_name(const struct building_type* btype, int bsize) -{ - static char p_name_buf[32]; - int level=0; - const construction * ctype; - - ctype = btype->construction; - - while (ctype && ctype->maxsize != -1 && ctype->maxsize<=bsize) { - bsize-=ctype->maxsize; - ctype=ctype->improvement; - ++level; - } - - sprintf(p_name_buf, "pyramid%d", level); - - return p_name_buf; -} - -int -wdw_pyramid_level(const struct building *b) -{ - const construction *ctype = b->type->construction; - int completed = b->size; - int level = 0; - - while(ctype->improvement != NULL && - ctype->improvement != ctype && - ctype->maxsize > 0 && - ctype->maxsize <= completed) - { - ++level; - completed-=ctype->maxsize; - ctype = ctype->improvement; - } - - return level; -} -#endif - -/* for finding out what was meant by a particular building string */ - -static local_names * bnames; - -const building_type * -findbuildingtype(const char * name, const struct locale * lang) -{ - variant type; - local_names * bn = bnames; - - while (bn) { - if (bn->lang==lang) break; - bn=bn->next; - } - if (!bn) { - struct building_typelist * btl = buildingtypes; - bn = calloc(sizeof(local_names), 1); - bn->next = bnames; - bn->lang = lang; - while (btl) { - const char * n = locale_string(lang, btl->type->_name); - type.v = (void*)btl->type; - addtoken(&bn->names, n, type); - btl=btl->next; - } - bnames = bn; - } - if (findtoken(&bn->names, name, &type)==E_TOK_NOMATCH) return NULL; - return (const building_type*)type.v; -} - -static int eressea_building_protection(building * b, unit * u) -{ - int beff = buildingeffsize(b, false)-1; - /* -1 because the tradepost has no protection value */ - - return beff; -} - -void -register_buildings(void) -{ - register_function((pf_generic)&eressea_building_protection, "eressea_building_protection"); - register_function((pf_generic)&init_smithy, "init_smithy"); - register_function((pf_generic)&castle_name, "castle_name"); - register_function((pf_generic)&castle_name_2, "castle_name_2"); - register_function((pf_generic)&fort_name, "fort_name"); -#ifdef WDW_PYRAMID - register_function((pf_generic)&pyramid_name, "pyramid_name"); -#endif -} - -void -write_building_reference(const struct building * b, struct storage * store) -{ - store->w_id(store, (b && b->region)?b->no:0); -} - - -int -resolve_building(variant id, void * address) -{ - int result = 0; - building * b = NULL; - if (id.i!=0) { - b = findbuilding(id.i); - if (b==NULL) { - result = -1; - } - } - *(building**)address = b; - return result; -} - -variant -read_building_reference(struct storage * store) -{ - variant result; - result.i = store->r_id(store); - return result; -} - -void -free_buildinglist(building_list *blist) -{ - while (blist) { - building_list * rl2 = blist->next; - free(blist); - blist = rl2; - } -} - -void -add_buildinglist(building_list **blist, building *b) -{ - building_list *rl2 = (building_list*)malloc(sizeof(building_list)); - - rl2->data = b; - rl2->next = *blist; - - *blist = rl2; -} - -building * -new_building(const struct building_type * btype, region * r, const struct locale * lang) -{ - building *b = (building *) calloc(1, sizeof(building)); - static boolean init_lighthouse = false; - static const struct building_type * bt_lighthouse = 0; - - if (!init_lighthouse) { - bt_lighthouse = bt_find("lighthouse"); - init_lighthouse = true; - } - - b->flags = BLD_WORKING|BLD_MAINTAINED; - b->no = newcontainerid(); - bhash(b); - - b->type = btype; - b->region = r; - addlist(&r->buildings, b); - - if (b->type==bt_lighthouse) { - r->flags |= RF_LIGHTHOUSE; - } - { - const char * bname; - if (b->type->name==NULL) { - bname = LOC(lang, btype->_name); - } else { - bname = LOC(lang, buildingtype(btype, b, 0)); - } - b->name = strdup(bname); - } - return b; -} - -static building * deleted_buildings; - -/** remove a building from the region. - * remove_building lets units leave the building - */ -void -remove_building(building ** blist, building * b) -{ - unit *u; - direction_t d; - static const struct building_type * bt_caravan, * bt_dam, * bt_tunnel; - static boolean init = false; - - if (!init) { - init = true; - bt_caravan = bt_find("caravan"); - bt_dam = bt_find("dam"); - bt_tunnel = bt_find("tunnel"); - } - - assert(bfindhash(b->no)); - - handle_event(b->attribs, "destroy", b); - for (u=b->region->units; u; u=u->next) { - if (u->building == b) leave(u, true); - } - - b->size = 0; - update_lighthouse(b); - bunhash(b); - - /* Falls Karawanserei, Damm oder Tunnel einstürzen, wird die schon - * gebaute Straße zur Hälfte vernichtet */ - if (b->type == bt_caravan || b->type == bt_dam || b->type == bt_tunnel) { - region * r = b->region; - for (d=0;d!=MAXDIRECTIONS;++d) if (rroad(r, d) > 0) { - rsetroad(r, d, rroad(r, d) / 2); - } - } - - /* Stattdessen nur aus Liste entfernen, aber im Speicher halten. */ - while (*blist && *blist!=b) blist = &(*blist)->next; - *blist = b->next; - b->region = NULL; - b->next = deleted_buildings; - deleted_buildings = b; -} - -void -free_building(building * b) -{ - while (b->attribs) a_remove (&b->attribs, b->attribs); - free(b->name); - free(b->display); - free(b); -} - -void -free_buildings(void) -{ - while (deleted_buildings) { - building * b = deleted_buildings; - deleted_buildings = b->next; - } -} - -extern struct attrib_type at_icastle; - -/** returns the building's build stage (NOT size in people). - * only makes sense for castles or similar buildings with multiple - * stages */ -int -buildingeffsize(const building * b, boolean img) -{ - const struct building_type * btype = NULL; - - if (b==NULL) return 0; - - btype = b->type; - if (img) { - const attrib * a = a_find(b->attribs, &at_icastle); - if (a) { - btype = (const struct building_type *)a->data.v; - } - } - return bt_effsize(btype, b, b->size); -} - -int bt_effsize(const building_type * btype, const building * b, int bsize) -{ - int i = bsize, n = 0; - const construction * cons = btype->construction; - - /* TECH DEBT: simplest thing that works for E3 dwarf/halfling faction rules */ - if (b && get_param_int(global.parameters, "rules.dwarf_castles", 1) && strcmp(btype->_name, "castle")==0) { - unit * u = building_owner(b); - if (u && u->faction->race == new_race[RC_HALFLING]) { - i = bsize * 10 / 8; - } - } - - if (!cons || !cons->improvement) { - return 0; - } - - while (cons && cons->maxsize != -1 && i>=cons->maxsize) { - i -= cons->maxsize; - cons = cons->improvement; - ++n; - } - - return n; -} - -const char * -write_buildingname(const building * b, char * ibuf, size_t size) -{ - snprintf((char*)ibuf, size, "%s (%s)", b->name, itoa36(b->no)); - ibuf[size-1] = 0; - return ibuf; -} - -const char * -buildingname(const building * b) -{ - typedef char name[OBJECTIDSIZE + 1]; - static name idbuf[8]; - static int nextbuf = 0; - char *ibuf = idbuf[(++nextbuf) % 8]; - return write_buildingname(b, ibuf, sizeof(name)); -} - -unit * -building_owner(const building * b) -{ - unit *u = NULL; - unit *first = NULL; - region * r = b->region; - /* Prüfen ob Eigentümer am leben. */ - - for (u = r->units; u; u = u->next) { - if (u->building == b) { - if (!first && u->number > 0) - first = u; - if (fval(u, UFL_OWNER) && u->number > 0) - return u; - if (u->number == 0) - freset(u, UFL_OWNER); - } - } - - /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit - * nehmen. */ - - if (first) { - fset(first, UFL_OWNER); - } - return first; -} - -const char * building_getname(const building * self) -{ - return self->name; -} - -void building_setname(building * self, const char * name) -{ - free(self->name); - if (name) self->name = strdup(name); - else self->name = NULL; -} - -void -building_addaction(building * b, const char * fname, const char * param) -{ - attrib * a = a_add(&b->attribs, a_new(&at_building_action)); - building_action * data = (building_action*)a->data.v; - data->b = b; - data->fname = strdup(fname); - if (param) { - data->param = strdup(param); - } -} - -region * -building_getregion(const building * b) -{ - return b->region; -} - -void -building_setregion(building * b, region * r) -{ - building ** blist = &b->region->buildings; - while (*blist && *blist!=b) { - blist = &(*blist)->next; - } - *blist = b->next; - b->next = NULL; - - blist = &r->buildings; - while (*blist && *blist!=b) blist = &(*blist)->next; - *blist = b; - - b->region = r; -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include + +#include +#include "building.h" + +/* kernel includes */ +#include "item.h" +#include "curse.h" /* für C_NOCOST */ +#include "unit.h" +#include "faction.h" +#include "region.h" +#include "skill.h" +#include "magic.h" +#include "save.h" +#include "version.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +/* attributes includes */ +#include + +static const char * NULLSTRING = "(null)"; + +static void +lc_init(struct attrib *a) +{ + a->data.v = calloc(1, sizeof(building_action)); +} + +static void +lc_done(struct attrib *a) +{ + building_action * data = (building_action*)a->data.v; + if (data->fname) free(data->fname); + if (data->param) free(data->param); + free(data); +} + +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; + const char * fparam = data->param; + building * b = data->b; + + write_building_reference(b, store); + store->w_tok(store, fname); + store->w_tok(store, fparam?fparam:NULLSTRING); +} + +static int +lc_read(struct attrib * a, void * owner, struct storage * store) +{ + building_action * data = (building_action*)a->data.v; + int result = read_reference(&data->b, store, read_building_reference, resolve_building); + if (store->versionfname = store->r_str(store); + } else { + data->fname = store->r_tok(store); + } + if (store->version>=BACTION_VERSION) { + char lbuf[256]; + if (store->versionr_str_buf(store, lbuf, sizeof(lbuf)); + } else { + store->r_tok_buf(store, lbuf, sizeof(lbuf)); + } + if (strcmp(lbuf, NULLSTRING)==0) data->param = NULL; + else data->param = strdup(lbuf); + } else { + data->param = strdup(NULLSTRING); + } + if (result==0 && !data->b) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +attrib_type at_building_action = { + "lcbuilding", + lc_init, lc_done, + NULL, + lc_write, lc_read +}; + +typedef struct building_typelist { + struct building_typelist * next; + building_type * type; +} building_typelist; + +static building_typelist *buildingtypes; + +building_type * +bt_find(const char* name) +{ + const struct building_typelist * btl = buildingtypes; + assert(name); + while (btl && strcmp(btl->type->_name, name)) btl = btl->next; + if (btl==NULL) { + return NULL; + } + return btl->type; +} + +void +bt_register(building_type * type) +{ + struct building_typelist * btl = malloc(sizeof(building_type)); + if (type->init) type->init(type); + btl->type = type; + btl->next = buildingtypes; + buildingtypes = btl; +} + +int +buildingcapacity(const building * b) +{ + if (b->type->capacity>=0) { + if (b->type->maxcapacity>=0) { + return MIN(b->type->maxcapacity, b->size * b->type->capacity); + } + return b->size * b->type->capacity; + } + if (b->size>=b->type->maxsize) { + if (b->type->maxcapacity>=0) { + return b->type->maxcapacity; + } + } + return 0; +} + +attrib_type at_building_generic_type = { + "building_generic_type", NULL, NULL, NULL, a_writestring, a_readstring, ATF_UNIQUE +}; + +const char * +buildingtype(const building_type * btype, const building * b, int bsize) +{ + const char * s = NULL; + static boolean init_generic = false; + static const struct building_type * bt_generic; + + if (!init_generic) { + init_generic = true; + bt_generic = bt_find("generic"); + } + + if (btype == bt_generic) { + const attrib *a = a_find(b->attribs, &at_building_generic_type); + if (a) s = (const char*)a->data.v; + } + + if (btype->name) s = btype->name(btype, b, bsize); + if (s==NULL) s = btype->_name; + return s; +} + +#define BMAXHASH 7919 +static building *buildhash[BMAXHASH]; +void +bhash(building * b) +{ + building *old = buildhash[b->no % BMAXHASH]; + + buildhash[b->no % BMAXHASH] = b; + b->nexthash = old; +} + +void +bunhash(building * b) +{ + building **show; + + for (show = &buildhash[b->no % BMAXHASH]; *show; show = &(*show)->nexthash) { + if ((*show)->no == b->no) + break; + } + if (*show) { + assert(*show == b); + *show = (*show)->nexthash; + b->nexthash = 0; + } +} + +static building * +bfindhash(int i) +{ + building *old; + + for (old = buildhash[i % BMAXHASH]; old; old = old->nexthash) + if (old->no == i) + return old; + return 0; +} + +building * +findbuilding(int i) +{ + return bfindhash(i); +} +/* ** old building types ** */ + + +static int +sm_smithy(const unit * u, const region * r, skill_t sk, int value) /* skillmod */ +{ + if (sk==SK_WEAPONSMITH || sk==SK_ARMORER) { + if (u->region == r) return value + 1; + } + return value; +} +static int +mm_smithy(const unit * u, const resource_type * rtype, int value) /* material-mod */ +{ + if (rtype == oldresourcetype[R_IRON]) return value * 2; + return value; +} +static void +init_smithy(struct building_type * bt) +{ + a_add(&bt->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION, sm_smithy, 1.0, 0)); + a_add(&bt->attribs, make_matmod(mm_smithy)); +} + +static const char * +castle_name_i(const struct building_type* btype, const struct building * b, int bsize, const char * fname[]) +{ + int i = bt_effsize(btype, b, bsize); + + return fname[i]; +} + +static const char * +castle_name_2(const struct building_type* btype, const struct building * b, int bsize) +{ + const char * fname[] = { + "site", + "fortification", + "tower", + "castle", + "fortress", + "citadel" + }; + return castle_name_i(btype, b, bsize, fname); +} + +static const char * +castle_name(const struct building_type* btype, const struct building * b, int bsize) +{ + const char * fname[] = { + "site", + "tradepost", + "fortification", + "tower", + "castle", + "fortress", + "citadel" + }; + return castle_name_i(btype, b, bsize, fname); +} + +static const char * +fort_name(const struct building_type* btype, const struct building * b, int bsize) +{ + const char * fname[] = { + "scaffolding", + "guardhouse", + "guardtower", + }; + return castle_name_i(btype, b, bsize, fname); +} + +#ifdef WDW_PYRAMID + +static const char * +pyramid_name(const struct building_type* btype, int bsize) +{ + static char p_name_buf[32]; + int level=0; + const construction * ctype; + + ctype = btype->construction; + + while (ctype && ctype->maxsize != -1 && ctype->maxsize<=bsize) { + bsize-=ctype->maxsize; + ctype=ctype->improvement; + ++level; + } + + sprintf(p_name_buf, "pyramid%d", level); + + return p_name_buf; +} + +int +wdw_pyramid_level(const struct building *b) +{ + const construction *ctype = b->type->construction; + int completed = b->size; + int level = 0; + + while(ctype->improvement != NULL && + ctype->improvement != ctype && + ctype->maxsize > 0 && + ctype->maxsize <= completed) + { + ++level; + completed-=ctype->maxsize; + ctype = ctype->improvement; + } + + return level; +} +#endif + +/* for finding out what was meant by a particular building string */ + +static local_names * bnames; + +const building_type * +findbuildingtype(const char * name, const struct locale * lang) +{ + variant type; + local_names * bn = bnames; + + while (bn) { + if (bn->lang==lang) break; + bn=bn->next; + } + if (!bn) { + struct building_typelist * btl = buildingtypes; + bn = calloc(sizeof(local_names), 1); + bn->next = bnames; + bn->lang = lang; + while (btl) { + const char * n = locale_string(lang, btl->type->_name); + type.v = (void*)btl->type; + addtoken(&bn->names, n, type); + btl=btl->next; + } + bnames = bn; + } + if (findtoken(&bn->names, name, &type)==E_TOK_NOMATCH) return NULL; + return (const building_type*)type.v; +} + +static int eressea_building_protection(building * b, unit * u) +{ + int beff = buildingeffsize(b, false)-1; + /* -1 because the tradepost has no protection value */ + + return beff; +} + +void +register_buildings(void) +{ + register_function((pf_generic)&eressea_building_protection, "eressea_building_protection"); + register_function((pf_generic)&init_smithy, "init_smithy"); + register_function((pf_generic)&castle_name, "castle_name"); + register_function((pf_generic)&castle_name_2, "castle_name_2"); + register_function((pf_generic)&fort_name, "fort_name"); +#ifdef WDW_PYRAMID + register_function((pf_generic)&pyramid_name, "pyramid_name"); +#endif +} + +void +write_building_reference(const struct building * b, struct storage * store) +{ + store->w_id(store, (b && b->region)?b->no:0); +} + + +int +resolve_building(variant id, void * address) +{ + int result = 0; + building * b = NULL; + if (id.i!=0) { + b = findbuilding(id.i); + if (b==NULL) { + result = -1; + } + } + *(building**)address = b; + return result; +} + +variant +read_building_reference(struct storage * store) +{ + variant result; + result.i = store->r_id(store); + return result; +} + +void +free_buildinglist(building_list *blist) +{ + while (blist) { + building_list * rl2 = blist->next; + free(blist); + blist = rl2; + } +} + +void +add_buildinglist(building_list **blist, building *b) +{ + building_list *rl2 = (building_list*)malloc(sizeof(building_list)); + + rl2->data = b; + rl2->next = *blist; + + *blist = rl2; +} + +building * +new_building(const struct building_type * btype, region * r, const struct locale * lang) +{ + building *b = (building *) calloc(1, sizeof(building)); + static boolean init_lighthouse = false; + static const struct building_type * bt_lighthouse = 0; + + if (!init_lighthouse) { + bt_lighthouse = bt_find("lighthouse"); + init_lighthouse = true; + } + + b->flags = BLD_WORKING|BLD_MAINTAINED; + b->no = newcontainerid(); + bhash(b); + + b->type = btype; + b->region = r; + addlist(&r->buildings, b); + + if (b->type==bt_lighthouse) { + r->flags |= RF_LIGHTHOUSE; + } + { + const char * bname; + if (b->type->name==NULL) { + bname = LOC(lang, btype->_name); + } else { + bname = LOC(lang, buildingtype(btype, b, 0)); + } + b->name = strdup(bname); + } + return b; +} + +static building * deleted_buildings; + +/** remove a building from the region. + * remove_building lets units leave the building + */ +void +remove_building(building ** blist, building * b) +{ + unit *u; + direction_t d; + static const struct building_type * bt_caravan, * bt_dam, * bt_tunnel; + static boolean init = false; + + if (!init) { + init = true; + bt_caravan = bt_find("caravan"); + bt_dam = bt_find("dam"); + bt_tunnel = bt_find("tunnel"); + } + + assert(bfindhash(b->no)); + + handle_event(b->attribs, "destroy", b); + for (u=b->region->units; u; u=u->next) { + if (u->building == b) leave(u, true); + } + + b->size = 0; + update_lighthouse(b); + bunhash(b); + + /* Falls Karawanserei, Damm oder Tunnel einstürzen, wird die schon + * gebaute Straße zur Hälfte vernichtet */ + if (b->type == bt_caravan || b->type == bt_dam || b->type == bt_tunnel) { + region * r = b->region; + for (d=0;d!=MAXDIRECTIONS;++d) if (rroad(r, d) > 0) { + rsetroad(r, d, rroad(r, d) / 2); + } + } + + /* Stattdessen nur aus Liste entfernen, aber im Speicher halten. */ + while (*blist && *blist!=b) blist = &(*blist)->next; + *blist = b->next; + b->region = NULL; + b->next = deleted_buildings; + deleted_buildings = b; +} + +void +free_building(building * b) +{ + while (b->attribs) a_remove (&b->attribs, b->attribs); + free(b->name); + free(b->display); + free(b); +} + +void +free_buildings(void) +{ + while (deleted_buildings) { + building * b = deleted_buildings; + deleted_buildings = b->next; + } +} + +extern struct attrib_type at_icastle; + +/** returns the building's build stage (NOT size in people). + * only makes sense for castles or similar buildings with multiple + * stages */ +int +buildingeffsize(const building * b, boolean img) +{ + const struct building_type * btype = NULL; + + if (b==NULL) return 0; + + btype = b->type; + if (img) { + const attrib * a = a_find(b->attribs, &at_icastle); + if (a) { + btype = (const struct building_type *)a->data.v; + } + } + return bt_effsize(btype, b, b->size); +} + +int bt_effsize(const building_type * btype, const building * b, int bsize) +{ + int i = bsize, n = 0; + const construction * cons = btype->construction; + + /* TECH DEBT: simplest thing that works for E3 dwarf/halfling faction rules */ + if (b && get_param_int(global.parameters, "rules.dwarf_castles", 1) && strcmp(btype->_name, "castle")==0) { + unit * u = building_owner(b); + if (u && u->faction->race == new_race[RC_HALFLING]) { + i = bsize * 10 / 8; + } + } + + if (!cons || !cons->improvement) { + return 0; + } + + while (cons && cons->maxsize != -1 && i>=cons->maxsize) { + i -= cons->maxsize; + cons = cons->improvement; + ++n; + } + + return n; +} + +const char * +write_buildingname(const building * b, char * ibuf, size_t size) +{ + snprintf((char*)ibuf, size, "%s (%s)", b->name, itoa36(b->no)); + ibuf[size-1] = 0; + return ibuf; +} + +const char * +buildingname(const building * b) +{ + typedef char name[OBJECTIDSIZE + 1]; + static name idbuf[8]; + static int nextbuf = 0; + char *ibuf = idbuf[(++nextbuf) % 8]; + return write_buildingname(b, ibuf, sizeof(name)); +} + +unit * +building_owner(const building * b) +{ + unit *u = NULL; + unit *first = NULL; + region * r = b->region; + /* Prüfen ob Eigentümer am leben. */ + + for (u = r->units; u; u = u->next) { + if (u->building == b) { + if (!first && u->number > 0) + first = u; + if (fval(u, UFL_OWNER) && u->number > 0) + return u; + if (u->number == 0) + freset(u, UFL_OWNER); + } + } + + /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit + * nehmen. */ + + if (first) { + fset(first, UFL_OWNER); + } + return first; +} + +const char * building_getname(const building * self) +{ + return self->name; +} + +void building_setname(building * self, const char * name) +{ + free(self->name); + if (name) self->name = strdup(name); + else self->name = NULL; +} + +void +building_addaction(building * b, const char * fname, const char * param) +{ + attrib * a = a_add(&b->attribs, a_new(&at_building_action)); + building_action * data = (building_action*)a->data.v; + data->b = b; + data->fname = strdup(fname); + if (param) { + data->param = strdup(param); + } +} + +region * +building_getregion(const building * b) +{ + return b->region; +} + +void +building_setregion(building * b, region * r) +{ + building ** blist = &b->region->buildings; + while (*blist && *blist!=b) { + blist = &(*blist)->next; + } + *blist = b->next; + b->next = NULL; + + blist = &r->buildings; + while (*blist && *blist!=b) blist = &(*blist)->next; + *blist = b; + + b->region = r; +} + diff --git a/src/kernel/building.h b/src/kernel/building.h index 64b8941eb..7aea49bd1 100644 --- a/src/kernel/building.h +++ b/src/kernel/building.h @@ -1,177 +1,177 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_BUILDING -#define H_KRNL_BUILDING - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* maintenance::flags */ -#define MTF_NONE 0x00 -#define MTF_VARIABLE 0x01 /* resource usage scales with size */ -#define MTF_VITAL 0x02 /* if resource missing, building may crash */ - -typedef struct maintenance { - const struct resource_type * rtype; /* type of resource required */ - int number; /* amount of resources */ - unsigned int flags; /* misc. flags */ -} maintenance; - -/* building_type::flags */ -#define BTF_NONE 0x00 -#define BTF_INDESTRUCTIBLE 0x01 /* cannot be torm down */ -#define BTF_NOBUILD 0x02 /* special, can't be built */ -#define BTF_UNIQUE 0x04 /* only one per struct region (harbour) */ -#define BTF_DECAY 0x08 /* decays when not occupied */ -#define BTF_DYNAMIC 0x10 /* dynamic type, needs bt_write */ -#define BTF_MAGIC 0x40 /* magical effect */ -#define BTF_ONEPERTURN 0x80 /* one one sizepoint can be added per turn */ -#define BTF_NAMECHANGE 0x100 /* name and description can be changed more than once */ - -typedef struct building_type { - const char * _name; - - int flags; /* flags */ - int capacity; /* Kapazität pro Größenpunkt */ - int maxcapacity; /* Max. Kapazität */ - int maxsize; /* how big can it get, with all the extensions? */ - int magres; /* how well it resists against spells */ - int magresbonus; /* bonus it gives the target against spells */ - int fumblebonus; /* bonus that reduces fumbling */ - double auraregen; /* modifier for aura regeneration inside building */ - struct maintenance * maintenance; /* array of requirements */ - struct construction * construction; /* construction of 1 building-level */ - - const char * (*name)(const struct building_type*, const struct building * b, int size); - void (*init)(struct building_type*); - void (*age)(struct building *); - int (*protection)(struct building *, struct unit *); - double (*taxes)(const struct building *, int size); - struct attrib * attribs; -} building_type; - -extern building_type * bt_find(const char* name); -extern void register_buildings(void); -extern void bt_register(struct building_type * type); -extern int bt_effsize(const struct building_type * btype, const struct building * b, int bsize); - -/* buildingt => building_type - * Name => locale_string(name) - * MaxGroesse => levels - * MinBauTalent => construction->minskill - * Kapazitaet => capacity, maxcapacity - * Materialien => construction->materials - * UnterSilber, UnterSpezialTyp, UnterSpezial => maintenance - * per_size => !maintenance->fixed - */ -#define BFL_NONE 0x00 -#define BLD_MAINTAINED 0x01 /* vital maintenance paid for */ -#define BLD_WORKING 0x02 /* full maintenance paid, it works */ -#define BLD_UNGUARDED 0x04 /* you can enter this building anytime */ -#define BLD_EXPANDED 0x08 /* has been expanded this turn */ -#define BLD_SELECT 0x10 /* formerly FL_DH */ -#define BLD_DONTPAY 0x20 /* PAY NOT */ - -#define BLD_SAVEMASK 0x00 /* mask for persistent flags */ - -typedef struct building { - struct building *next; - struct building *nexthash; - - const struct building_type * type; - struct region *region; - char *name; - char *display; - struct attrib * attribs; - int no; - int size; - int sizeleft; /* is only used during battle. should be a temporary attribute */ - int besieged; /* should be an attribute */ - unsigned int flags; -} building; - -typedef struct building_list { - struct building_list * next; - building * data; -} building_list; - -extern void free_buildinglist(building_list *bl); -extern void add_buildinglist(building_list **bl, struct building *b); - -extern struct attrib_type at_building_generic_type; -extern const char * buildingtype(const building_type * btype, const struct building * b, int bsize); -extern const char * write_buildingname(const building * b, char * ibuf, size_t size); -extern int buildingcapacity(const struct building * b); -extern struct building *new_building(const struct building_type * typ, struct region * r, const struct locale * lang); -void build_building(struct unit * u, const struct building_type * typ, int size, struct order * ord); - -/* Alte Gebäudetypen: */ - -/* old functions, still in build.c: */ -int buildingeffsize(const building * b, boolean img); -void bhash(struct building * b); -void bunhash(struct building * b); -int buildingcapacity(const struct building * b); - -extern void remove_building(struct building * *blist, struct building * b); -extern void free_building(struct building * b); -extern void free_buildings(void); - -const struct building_type * findbuildingtype(const char * name, const struct locale * lang); - -#include "build.h" -#define NOBUILDING NULL - -extern int resolve_building(variant data, void * address); -extern void write_building_reference(const struct building * b, struct storage * store); -extern variant read_building_reference(struct storage * store); - -extern struct building *findbuilding(int n); - -extern struct unit * building_owner(const struct building * b); - -extern struct attrib_type at_building_action; -void building_addaction(struct building * b, const char * fname, const char * param); - -#ifdef WDW_PYRAMID -extern int wdw_pyramid_level(const struct building *b); -#endif - -typedef struct building_action { - building * b; - char * fname; - char * param; -} building_action; - -extern const char * buildingname(const struct building * b); - -extern const char * building_getname(const struct building * b); -extern void building_setname(struct building * self, const char * name); - -struct region * building_getregion(const struct building * b); -void building_setregion(struct building * bld, struct region * r); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_BUILDING +#define H_KRNL_BUILDING + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* maintenance::flags */ +#define MTF_NONE 0x00 +#define MTF_VARIABLE 0x01 /* resource usage scales with size */ +#define MTF_VITAL 0x02 /* if resource missing, building may crash */ + +typedef struct maintenance { + const struct resource_type * rtype; /* type of resource required */ + int number; /* amount of resources */ + unsigned int flags; /* misc. flags */ +} maintenance; + +/* building_type::flags */ +#define BTF_NONE 0x00 +#define BTF_INDESTRUCTIBLE 0x01 /* cannot be torm down */ +#define BTF_NOBUILD 0x02 /* special, can't be built */ +#define BTF_UNIQUE 0x04 /* only one per struct region (harbour) */ +#define BTF_DECAY 0x08 /* decays when not occupied */ +#define BTF_DYNAMIC 0x10 /* dynamic type, needs bt_write */ +#define BTF_MAGIC 0x40 /* magical effect */ +#define BTF_ONEPERTURN 0x80 /* one one sizepoint can be added per turn */ +#define BTF_NAMECHANGE 0x100 /* name and description can be changed more than once */ + +typedef struct building_type { + const char * _name; + + int flags; /* flags */ + int capacity; /* Kapazität pro Größenpunkt */ + int maxcapacity; /* Max. Kapazität */ + int maxsize; /* how big can it get, with all the extensions? */ + int magres; /* how well it resists against spells */ + int magresbonus; /* bonus it gives the target against spells */ + int fumblebonus; /* bonus that reduces fumbling */ + double auraregen; /* modifier for aura regeneration inside building */ + struct maintenance * maintenance; /* array of requirements */ + struct construction * construction; /* construction of 1 building-level */ + + const char * (*name)(const struct building_type*, const struct building * b, int size); + void (*init)(struct building_type*); + void (*age)(struct building *); + int (*protection)(struct building *, struct unit *); + double (*taxes)(const struct building *, int size); + struct attrib * attribs; +} building_type; + +extern building_type * bt_find(const char* name); +extern void register_buildings(void); +extern void bt_register(struct building_type * type); +extern int bt_effsize(const struct building_type * btype, const struct building * b, int bsize); + +/* buildingt => building_type + * Name => locale_string(name) + * MaxGroesse => levels + * MinBauTalent => construction->minskill + * Kapazitaet => capacity, maxcapacity + * Materialien => construction->materials + * UnterSilber, UnterSpezialTyp, UnterSpezial => maintenance + * per_size => !maintenance->fixed + */ +#define BFL_NONE 0x00 +#define BLD_MAINTAINED 0x01 /* vital maintenance paid for */ +#define BLD_WORKING 0x02 /* full maintenance paid, it works */ +#define BLD_UNGUARDED 0x04 /* you can enter this building anytime */ +#define BLD_EXPANDED 0x08 /* has been expanded this turn */ +#define BLD_SELECT 0x10 /* formerly FL_DH */ +#define BLD_DONTPAY 0x20 /* PAY NOT */ + +#define BLD_SAVEMASK 0x00 /* mask for persistent flags */ + +typedef struct building { + struct building *next; + struct building *nexthash; + + const struct building_type * type; + struct region *region; + char *name; + char *display; + struct attrib * attribs; + int no; + int size; + int sizeleft; /* is only used during battle. should be a temporary attribute */ + int besieged; /* should be an attribute */ + unsigned int flags; +} building; + +typedef struct building_list { + struct building_list * next; + building * data; +} building_list; + +extern void free_buildinglist(building_list *bl); +extern void add_buildinglist(building_list **bl, struct building *b); + +extern struct attrib_type at_building_generic_type; +extern const char * buildingtype(const building_type * btype, const struct building * b, int bsize); +extern const char * write_buildingname(const building * b, char * ibuf, size_t size); +extern int buildingcapacity(const struct building * b); +extern struct building *new_building(const struct building_type * typ, struct region * r, const struct locale * lang); +void build_building(struct unit * u, const struct building_type * typ, int size, struct order * ord); + +/* Alte Gebäudetypen: */ + +/* old functions, still in build.c: */ +int buildingeffsize(const building * b, boolean img); +void bhash(struct building * b); +void bunhash(struct building * b); +int buildingcapacity(const struct building * b); + +extern void remove_building(struct building * *blist, struct building * b); +extern void free_building(struct building * b); +extern void free_buildings(void); + +const struct building_type * findbuildingtype(const char * name, const struct locale * lang); + +#include "build.h" +#define NOBUILDING NULL + +extern int resolve_building(variant data, void * address); +extern void write_building_reference(const struct building * b, struct storage * store); +extern variant read_building_reference(struct storage * store); + +extern struct building *findbuilding(int n); + +extern struct unit * building_owner(const struct building * b); + +extern struct attrib_type at_building_action; +void building_addaction(struct building * b, const char * fname, const char * param); + +#ifdef WDW_PYRAMID +extern int wdw_pyramid_level(const struct building *b); +#endif + +typedef struct building_action { + building * b; + char * fname; + char * param; +} building_action; + +extern const char * buildingname(const struct building * b); + +extern const char * building_getname(const struct building * b); +extern void building_setname(struct building * self, const char * name); + +struct region * building_getregion(const struct building * b); +void building_setregion(struct building * bld, struct region * r); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/calendar.c b/src/kernel/calendar.c index 6a9e6b58f..8a4efccca 100644 --- a/src/kernel/calendar.c +++ b/src/kernel/calendar.c @@ -1,59 +1,59 @@ -#include -#include "calendar.h" - -#include - -int first_turn = 0; -int first_month = 0; -int weeks_per_month = 0; -int months_per_year = 0; -char **seasonnames = NULL; -char **weeknames = NULL; -char **weeknames2 = NULL; -char **monthnames = NULL; -int *month_season = NULL; -char *agename = NULL; -int seasons = 0; - -const gamedate * -get_gamedate(int turn, gamedate * gd) -{ - int weeks_per_year = months_per_year * weeks_per_month; - int t = turn - first_turn; - - assert(gd); - if (t<0) t = turn; - - gd->week = t%weeks_per_month; /* 0 - weeks_per_month-1 */ - gd->month = (t/weeks_per_month + first_month)%months_per_year; /* 0 - months_per_year-1 */ - gd->year = t/(weeks_per_year) + 1; - gd->season = month_season[gd->month]; - return gd; -} - -void -calendar_cleanup(void) -{ - int i; - - free(agename); - - for (i=0;i!=seasons;++i) { - free(seasonnames[i]); - } - free(seasonnames); - - for (i=0;i!=months_per_year;++i) { - free(monthnames[i]); - } - free(storms); - free(month_season); - free(monthnames); - - for (i=0;i!=weeks_per_month;++i) { - free(weeknames[i]); - free(weeknames2[i]); - } - free(weeknames); - free(weeknames2); -} +#include +#include "calendar.h" + +#include + +int first_turn = 0; +int first_month = 0; +int weeks_per_month = 0; +int months_per_year = 0; +char **seasonnames = NULL; +char **weeknames = NULL; +char **weeknames2 = NULL; +char **monthnames = NULL; +int *month_season = NULL; +char *agename = NULL; +int seasons = 0; + +const gamedate * +get_gamedate(int turn, gamedate * gd) +{ + int weeks_per_year = months_per_year * weeks_per_month; + int t = turn - first_turn; + + assert(gd); + if (t<0) t = turn; + + gd->week = t%weeks_per_month; /* 0 - weeks_per_month-1 */ + gd->month = (t/weeks_per_month + first_month)%months_per_year; /* 0 - months_per_year-1 */ + gd->year = t/(weeks_per_year) + 1; + gd->season = month_season[gd->month]; + return gd; +} + +void +calendar_cleanup(void) +{ + int i; + + free(agename); + + for (i=0;i!=seasons;++i) { + free(seasonnames[i]); + } + free(seasonnames); + + for (i=0;i!=months_per_year;++i) { + free(monthnames[i]); + } + free(storms); + free(month_season); + free(monthnames); + + for (i=0;i!=weeks_per_month;++i) { + free(weeknames[i]); + free(weeknames2[i]); + } + free(weeknames); + free(weeknames2); +} diff --git a/src/kernel/calendar.h b/src/kernel/calendar.h index fe7d0f930..ae4306d28 100644 --- a/src/kernel/calendar.h +++ b/src/kernel/calendar.h @@ -1,45 +1,45 @@ -#ifndef KRNL_CALENDAR_H -#define KRNL_CALENDAR_H - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - SEASON_WINTER, - SEASON_SPRING, - SEASON_SUMMER, - SEASON_AUTUMN -}; - - -extern char *agename; -extern int first_turn; -extern int first_month; - -extern int seasons; -extern char **seasonnames; - -extern int months_per_year; -extern char **monthnames; -extern int *month_season; -extern int *storms; /* in movement.c */ - -extern char **weeknames; -extern char **weeknames2; -extern int weeks_per_month; - -typedef struct gamedate { - int year; - int season; - int month; - int week; -} gamedate; - -extern const gamedate * get_gamedate(int turn, gamedate * gd); -extern void calendar_cleanup(void); - -#ifdef __cplusplus -} -#endif -#endif +#ifndef KRNL_CALENDAR_H +#define KRNL_CALENDAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + SEASON_WINTER, + SEASON_SPRING, + SEASON_SUMMER, + SEASON_AUTUMN +}; + + +extern char *agename; +extern int first_turn; +extern int first_month; + +extern int seasons; +extern char **seasonnames; + +extern int months_per_year; +extern char **monthnames; +extern int *month_season; +extern int *storms; /* in movement.c */ + +extern char **weeknames; +extern char **weeknames2; +extern int weeks_per_month; + +typedef struct gamedate { + int year; + int season; + int month; + int week; +} gamedate; + +extern const gamedate * get_gamedate(int turn, gamedate * gd); +extern void calendar_cleanup(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/command.c b/src/kernel/command.c index f2c6a1bea..93741e4c2 100644 --- a/src/kernel/command.c +++ b/src/kernel/command.c @@ -1,103 +1,103 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - - */ -#include -#include -#include "command.h" - -#include - -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -typedef struct command { - parser fun; - struct tnode * nodes; -} command; - -tnode * -stree_find(const syntaxtree * stree, const struct locale * lang) -{ - while (stree) { - if (stree->lang==lang) return stree->root; - stree = stree->next; - } - return NULL; -} - -syntaxtree * -stree_create(void) -{ - syntaxtree * sroot = NULL; - const struct locale * lang = locales; - while (lang) { - syntaxtree * stree = (syntaxtree *)malloc(sizeof(syntaxtree)); - stree->lang = lang; - stree->next = sroot; - sroot=stree; - lang=nextlocale(lang); - } - return sroot; -} - -void -add_command(struct tnode * keys, struct tnode * tnext, - const char * str, parser fun) -{ - command * cmd = (command *)malloc(sizeof(command)); - variant var; - - cmd->fun = fun; - cmd->nodes = tnext; - var.v = cmd; - addtoken(keys, str, var); -} - -static int -do_command_i(const struct tnode * keys, void * u, struct order * ord) -{ - const char * c; - variant var; - - c = getstrtoken(); - if (findtoken(keys, c, &var)==E_TOK_SUCCESS) { - command * cmd = (command *)var.v; - if (cmd->nodes && *c) { - assert(!cmd->fun); - return do_command_i(cmd->nodes, u, ord); - } else if (cmd->fun) { - cmd->fun(cmd->nodes, u, ord); - return E_TOK_SUCCESS; - } - } - return E_TOK_NOMATCH; -} - -void -do_command(const struct tnode * keys, void * u, struct order * ord) -{ - init_tokens(ord); - skip_token(); - if (do_command_i(keys, u, ord)!=E_TOK_SUCCESS) { - char * cmd = getcommand(ord); - log_warning(("%s failed command '%s'\n", unitname(u), cmd)); - free(cmd); - } -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ +#include +#include +#include "command.h" + +#include + +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +typedef struct command { + parser fun; + struct tnode * nodes; +} command; + +tnode * +stree_find(const syntaxtree * stree, const struct locale * lang) +{ + while (stree) { + if (stree->lang==lang) return stree->root; + stree = stree->next; + } + return NULL; +} + +syntaxtree * +stree_create(void) +{ + syntaxtree * sroot = NULL; + const struct locale * lang = locales; + while (lang) { + syntaxtree * stree = (syntaxtree *)malloc(sizeof(syntaxtree)); + stree->lang = lang; + stree->next = sroot; + sroot=stree; + lang=nextlocale(lang); + } + return sroot; +} + +void +add_command(struct tnode * keys, struct tnode * tnext, + const char * str, parser fun) +{ + command * cmd = (command *)malloc(sizeof(command)); + variant var; + + cmd->fun = fun; + cmd->nodes = tnext; + var.v = cmd; + addtoken(keys, str, var); +} + +static int +do_command_i(const struct tnode * keys, void * u, struct order * ord) +{ + const char * c; + variant var; + + c = getstrtoken(); + if (findtoken(keys, c, &var)==E_TOK_SUCCESS) { + command * cmd = (command *)var.v; + if (cmd->nodes && *c) { + assert(!cmd->fun); + return do_command_i(cmd->nodes, u, ord); + } else if (cmd->fun) { + cmd->fun(cmd->nodes, u, ord); + return E_TOK_SUCCESS; + } + } + return E_TOK_NOMATCH; +} + +void +do_command(const struct tnode * keys, void * u, struct order * ord) +{ + init_tokens(ord); + skip_token(); + if (do_command_i(keys, u, ord)!=E_TOK_SUCCESS) { + char * cmd = getcommand(ord); + log_warning(("%s failed command '%s'\n", unitname(u), cmd)); + free(cmd); + } +} diff --git a/src/kernel/command.h b/src/kernel/command.h index 56403db53..401b9e8bc 100644 --- a/src/kernel/command.h +++ b/src/kernel/command.h @@ -1,39 +1,39 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - - */ -#ifndef H_UTIL_COMMAND_H -#define H_UTIL_COMMAND_H -#ifdef __cplusplus -extern "C" { -#endif - -struct tnode; -struct locale; -struct order; - -typedef struct syntaxtree { - const struct locale * lang; - struct tnode * root; - struct syntaxtree * next; -} syntaxtree; - -typedef void (*parser)(const struct tnode *, void *, struct order*); -extern void add_command(struct tnode * troot, struct tnode * tnext, const char * str, parser fun); -extern void do_command(const struct tnode * troot, void * u, struct order *); - -extern struct syntaxtree * stree_create(void); -extern struct tnode * stree_find(const struct syntaxtree * stree, const struct locale * lang); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ +#ifndef H_UTIL_COMMAND_H +#define H_UTIL_COMMAND_H +#ifdef __cplusplus +extern "C" { +#endif + +struct tnode; +struct locale; +struct order; + +typedef struct syntaxtree { + const struct locale * lang; + struct tnode * root; + struct syntaxtree * next; +} syntaxtree; + +typedef void (*parser)(const struct tnode *, void *, struct order*); +extern void add_command(struct tnode * troot, struct tnode * tnext, const char * str, parser fun); +extern void do_command(const struct tnode * troot, void * u, struct order *); + +extern struct syntaxtree * stree_create(void); +extern struct tnode * stree_find(const struct syntaxtree * stree, const struct locale * lang); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/config.c b/src/kernel/config.c index b0c5ac4d4..814bc45d5 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -1,3271 +1,3275 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include - -/* attributes includes */ -#include -#include - -/* kernel includes */ -#include "alliance.h" -#include "alchemy.h" -#include "battle.h" -#include "connection.h" -#include "building.h" -#include "calendar.h" -#include "curse.h" -#include "faction.h" -#include "group.h" -#include "item.h" -#include "magic.h" -#include "message.h" -#include "move.h" -#include "names.h" -#include "objtypes.h" -#include "order.h" -#include "plane.h" -#include "pool.h" -#include "race.h" -#include "region.h" -#include "save.h" -#include "ship.h" -#include "skill.h" -#include "terrain.h" -#include "unit.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include -#include -#include - -#define PTRIES 0 /* it turns out they are slow :-( */ -#if PTRIES -#include -#endif - -struct settings global = { - "Eressea", /* gamename */ -}; -FILE *logfile; -FILE *updatelog; -const struct race * new_race[MAXRACES]; -boolean sqlpatch = false; -boolean battledebug = false; -int turn = 0; - -#if XECMD_MODULE -attrib_type at_xontormiaexpress = { - "xontormiaexpress", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - a_writeint, - a_readint, - ATF_UNIQUE -}; -#endif - -int -NewbieImmunity(void) { - static int value = -1; - if (value<0) { - value = get_param_int(global.parameters, "NewbieImmunity", 0); - } - return value; -} - -boolean -IsImmune(const faction * f) -{ - return !fval(f, FFL_NPC) && f->age < NewbieImmunity(); -} - -static int -MaxAge(void) { - static int value = -1; - if (value<0) { - value = get_param_int(global.parameters, "MaxAge", 0); - } - return value; -} - -static int -ally_flag(const char * s, int help_mask) -{ - if ((help_mask&HELP_MONEY) && strcmp(s, "money")==0) return HELP_MONEY; - if ((help_mask&HELP_FIGHT) && strcmp(s, "fight")==0) return HELP_FIGHT; - if ((help_mask&HELP_GIVE) && strcmp(s, "give")==0) return HELP_GIVE; - if ((help_mask&HELP_GUARD) && strcmp(s, "guard")==0) return HELP_GUARD; - if ((help_mask&HELP_FSTEALTH) && strcmp(s, "stealth")==0) return HELP_FSTEALTH; - if ((help_mask&HELP_TRAVEL) && strcmp(s, "travel")==0) return HELP_TRAVEL; - return 0; -} - -boolean -ExpensiveMigrants(void) -{ - int value = -1; - if (value<0) { - value = get_param_int(global.parameters, "study.expensivemigrants", 0); - } - return value; -} -/** Specifies automatic alliance modes. - * If this returns a value then the bits set are immutable between alliance - * partners (faction::alliance) and cannot be changed with the HELP command. - */ -int -AllianceAuto(void) -{ - static int value = -1; - if (value<0) { - const char * str = get_param(global.parameters, "alliance.auto"); - value = 0; - if (str!=NULL) { - char * sstr = strdup(str); - char * tok = strtok(sstr, " "); - while (tok) { - value |= ally_flag(tok, -1); - tok = strtok(NULL, " "); - } - free(sstr); - } - } - return value & HelpMask(); -} - -/** Limits the available help modes - * The bitfield returned by this function specifies the available help modes - * in this game (so you can, for example, disable HELP GIVE globally). - * Disabling a status will disable the command sequence entirely (order parsing - * uses this function). - */ -int -HelpMask(void) -{ - static int value = -1; - if (value<0) { - const char * str = get_param(global.parameters, "rules.help.mask"); - value = 0; - if (str!=NULL) { - char * sstr = strdup(str); - char * tok = strtok(sstr, " "); - while (tok) { - value |= ally_flag(tok, -1); - tok = strtok(NULL, " "); - } - free(sstr); - } else { - value = HELP_ALL; - } - } - return value; -} - -int -AllianceRestricted(void) -{ - static int value = -1; - if (value<0) { - const char * str = get_param(global.parameters, "alliance.restricted"); - value = 0; - if (str!=NULL) { - char * sstr = strdup(str); - char * tok = strtok(sstr, " "); - while (tok) { - value |= ally_flag(tok, -1); - tok = strtok(NULL, " "); - } - free(sstr); - } - value &= HelpMask(); - } - return value; -} - -int -LongHunger(const struct unit * u) { - static int value = -1; - if (u!=NULL) { - if (!fval(u, UFL_HUNGER)) return false; -#ifdef NEW_DAEMONHUNGER_RULE - if (u->race==new_race[RC_DAEMON]) return false; -#endif - } - if (value<0) { - value = get_param_int(global.parameters, "hunger.long", 0); - } - return value; -} - -int -SkillCap(skill_t sk) { - static int value = -1; - if (sk==SK_MAGIC) return 0; /* no caps on magic */ - if (value<0) { - value = get_param_int(global.parameters, "skill.maxlevel", 0); - } - return value; -} - -int -NMRTimeout(void) { - static int value = -1; - if (value<0) { - value = get_param_int(global.parameters, "nmr.timeout", 0); - } - return value; -} - -race_t -old_race(const struct race * rc) -{ - race_t i; - for (i=0;i!=MAXRACES;++i) { - if (new_race[i]==rc) return i; - } - return NORACE; -} - -helpmode helpmodes[] = { - { "all", HELP_ALL }, - { "money", HELP_MONEY }, - { "fight", HELP_FIGHT }, - { "observe", HELP_OBSERVE }, - { "give", HELP_GIVE }, - { "guard", HELP_GUARD }, - { "stealth", HELP_FSTEALTH }, - { "travel", HELP_TRAVEL }, - { NULL, 0 } -}; - -const char *directions[MAXDIRECTIONS+2] = -{ - "northwest", - "northeast", - "east", - "southeast", - "southwest", - "west", - "", - "pause" -}; - -/** Returns the English name of the race, which is what the database uses. - */ -const char * -dbrace(const struct race * rc) -{ - static char zText[32]; - char * zPtr = zText; - - /* the english names are all in ASCII, so we don't need to worry about UTF8 */ - strcpy(zText, (const char*)LOC(find_locale("en"), rc_name(rc, 0))); - while (*zPtr) { - *zPtr = (char)(toupper(*zPtr)); - ++zPtr; - } - return zText; -} - -const char *parameters[MAXPARAMS] = -{ - "LOCALE", - "ALLES", - "JEDEM", - "BAUERN", - "BURG", - "EINHEIT", - "PRIVAT", - "HINTEN", - "KOMMANDO", - "KRAEUTER", - "NICHT", - "NAECHSTER", - "PARTEI", - "ERESSEA", - "PERSONEN", - "REGION", - "SCHIFF", - "SILBER", - "STRASSEN", - "TEMPORAERE", - "FLIEHE", - "GEBAEUDE", - "GIB", /* Für HELFE */ - "KAEMPFE", - "DURCHREISE", - "BEWACHE", - "ZAUBER", - "PAUSE", - "VORNE", - "AGGRESSIV", - "DEFENSIV", - "STUFE", - "HELFE", - "FREMDES", - "AURA", - "UM", - "BEISTAND", - "GNADE", - "HINTER", - "VOR", - "ANZAHL", - "GEGENSTAENDE", - "TRAENKE", - "GRUPPE", - "PARTEITARNUNG", - "BAEUME", - "XEPOTION", - "XEBALLOON", - "XELAEN", - "ALLIANZ" -}; - - -const char *keywords[MAXKEYWORDS] = -{ - "//", - "BANNER", - "ARBEITEN", - "ATTACKIEREN", - "BEKLAUEN", - "BELAGERE", - "BENENNEN", - "BENUTZEN", - "BESCHREIBEN", - "BETRETEN", - "BEWACHEN", - "BOTSCHAFT", - "ENDE", - "FAHREN", - "NUMMER", - "KRIEG", - "FRIEDEN", - "FOLGEN", - "FORSCHEN", - "GIB", - "HELFEN", - "KAEMPFEN", - "KAMPFZAUBER", - "KAUFEN", - "KONTAKTIEREN", - "LEHREN", - "LERNEN", - "LIEFERE", - "MACHEN", - "NACH", - "PASSWORT", - "REKRUTIEREN", - "RESERVIEREN", - "ROUTE", - "SABOTIEREN", - "OPTION", - "SPIONIEREN", - "STIRB", - "TARNEN", - "TRANSPORTIEREN", - "TREIBEN", - "UNTERHALTEN", - "VERKAUFEN", - "VERLASSEN", - "VERGESSEN", - "ZAUBERE", - "ZEIGEN", - "ZERSTOEREN", - "ZUECHTEN", - "DEFAULT", - "URSPRUNG", - "EMAIL", - "PIRATERIE", - "NEUSTART", - "GRUPPE", - "OPFERE", - "BETEN", - "SORTIEREN", - "JIHAD", - "GM", - "INFO", - "PRAEFIX", - "PFLANZEN", - "WERWESEN", - "XONTORMIA", - "ALLIANZ", - "BEANSPRUCHEN", - "PROMOTION", - "BEZAHLEN", -}; - -const char *report_options[MAX_MSG] = -{ - "Kampf", - "Ereignisse", - "Bewegung", - "Einkommen", - "Handel", - "Produktion", - "Orkvermehrung", - "Zauber", - "", - "" -}; - -const char *message_levels[ML_MAX] = -{ - "Wichtig", - "Debug", - "Fehler", - "Warnungen", - "Infos" -}; - -const char *options[MAXOPTIONS] = -{ - "AUSWERTUNG", - "COMPUTER", - "ZUGVORLAGE", - NULL, - "STATISTIK", - "DEBUG", - "ZIPPED", - "ZEITUNG", /* Option hat Sonderbehandlung! */ - NULL, - "ADRESSEN", - "BZIP2", - "PUNKTE", - "SHOWSKCHANGE", - "XML" -}; - -static int -allied_skillcount(const faction * f, skill_t sk) -{ - int num = 0; - alliance * a = f_get_alliance(f); - faction_list * members = a->members; - while (members!=NULL) { - num += count_skill(members->data, sk); - members=members->next; - } - return num; -} - -static int -allied_skilllimit(const faction * f, skill_t sk) -{ - static int value = -1; - if (value<0) { - value = get_param_int(global.parameters, "alliance.skilllimit", 0); - } - return value; -} - -static void -init_maxmagicians(struct attrib *a) -{ - a->data.i = MAXMAGICIANS; -} - -static attrib_type at_maxmagicians = { - "maxmagicians", - init_maxmagicians, - NULL, - NULL, - a_writeint, - a_readint, - ATF_UNIQUE -}; - -static void -init_npcfaction(struct attrib *a) -{ - a->data.i = 1; -} - - -static attrib_type at_npcfaction = { - "npcfaction", - init_npcfaction, - NULL, - NULL, - a_writeint, - a_readint, - ATF_UNIQUE -}; - -int -max_magicians(const faction * f) -{ - int m = MAXMAGICIANS; - attrib * a; - - if ((a = a_find(f->attribs, &at_maxmagicians)) != NULL) { - m = a->data.i; - } - if (f->race == new_race[RC_ELF]) ++m; - return m; -} - -int -skill_limit(faction * f, skill_t sk) -{ - int m = INT_MAX; - int al = allied_skilllimit(f, sk); - if (al>0) { - if (sk!=SK_ALCHEMY && sk!=SK_MAGIC) return INT_MAX; - if (f_get_alliance(f)) { - int ac = listlen(f->alliance->members); /* number of factions */ - int fl = (al+ac-1)/ac; /* faction limit, rounded up */ - /* the faction limit may not be achievable because it would break the alliance-limit */ - int sc = al - allied_skillcount(f, sk); - if (sc<=0) return 0; - return fl; - } - } - switch (sk) { - case SK_MAGIC: - m = max_magicians(f); - break; - case SK_ALCHEMY: - m = MAXALCHEMISTS; - break; - } - return m; -} - -int -count_skill(faction * f, skill_t sk) -{ - int n = 0; - unit *u; - - for (u = f->units; u; u = u->nextF) { - if (has_skill(u, sk)) { - if (!is_familiar(u)) n += u->number; - } - } - return n; -} - -int verbosity = 0; - -FILE *debug; - -static int -ShipSpeedBonus(const unit * u) -{ - static int level = -1; - if (level==-1) { - level = get_param_int(global.parameters, "movement.shipspeed.skillbonus", 0); - } - if (level>0) { - ship * sh = u->ship; - int skl = effskill(u, SK_SAILING); - int minsk = (sh->type->cptskill+1)/2; - return (skl-minsk)/level; - } - return 0; -} - -int -shipspeed(const ship * sh, const unit * u) -{ - double k = sh->type->range; - static const curse_type * stormwind_ct, * nodrift_ct; - static boolean init; - attrib *a; - curse *c; - - if (!init) { - init = true; - stormwind_ct = ct_find("stormwind"); - nodrift_ct = ct_find("nodrift"); - } - - assert(u->ship==sh); - assert(sh->type->construction->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */ - if (sh->size!=sh->type->construction->maxsize) return 0; - - if( curse_active(get_curse(sh->attribs, stormwind_ct))) - k *= 2; - if( curse_active(get_curse(sh->attribs, nodrift_ct))) - k += 1; - - if (u->faction->race == u->race) { - /* race bonus for this faction? */ - if (fval(u->race, RCF_SHIPSPEED)) { - k += 1; - } - } - - k += ShipSpeedBonus(u); - - a = a_find(sh->attribs, &at_speedup); - while (a != NULL && a->type==&at_speedup) { - k += a->data.sa[0]; - a = a->next; - } - - c = get_curse(sh->attribs, ct_find("shipspeedup")); - while(c) { - k += curse_geteffect(c); - c = c->nexthash; - } - -#ifdef SHIPSPEED - k *= SHIPSPEED; -#endif - -#ifdef SHIPDAMAGE - if (sh->damage) k = (k * (sh->size * DAMAGE_SCALE - sh->damage) + sh->size * DAMAGE_SCALE- 1) / (sh->size*DAMAGE_SCALE); -#endif - - return (int)k; -} - -#define FMAXHASH 2039 -faction * factionhash[FMAXHASH]; - -void -fhash(faction * f) -{ - int index = f->no % FMAXHASH; - f->nexthash = factionhash[index]; - factionhash[index] = f; -} - -void -funhash(faction * f) -{ - int index = f->no % FMAXHASH; - faction ** fp = factionhash+index; - while (*fp && (*fp)!=f) fp = &(*fp)->nexthash; - *fp = f->nexthash; -} - -static faction * -ffindhash(int no) -{ - int index = no % FMAXHASH; - faction * f = factionhash[index]; - while (f && f->no!=no) f = f->nexthash; - return f; -} -/* ----------------------------------------------------------------------- */ - -void -verify_data(void) -{ -#ifndef NDEBUG - int lf = -1; - faction *f; - unit *u; - int mage, alchemist; - - if (verbosity>=1) puts(" - Überprüfe Daten auf Korrektheit..."); - - list_foreach(faction, factions, f) { - mage = 0; - alchemist = 0; - for (u=f->units;u;u=u->nextF) { - if (eff_skill(u, SK_MAGIC, u->region)) { - mage += u->number; - } - if (eff_skill(u, SK_ALCHEMY, u->region)) - alchemist += u->number; - if (u->number > UNIT_MAXSIZE) { - if (lf != f->no) { - lf = f->no; - log_stdio(stdout, "Partei %s:\n", factionid(f)); - } - log_warning(("Einheit %s hat %d Personen\n", unitid(u), u->number)); - } - } - if (f->no != 0 && ((mage > 3 && f->race != new_race[RC_ELF]) || mage > 4)) - log_error(("Partei %s hat %d Magier.\n", factionid(f), mage)); - if (alchemist > 3) - log_error(("Partei %s hat %d Alchemisten.\n", factionid(f), alchemist)); - } - list_next(f); -#endif -} - -int -distribute(int old, int new_value, int n) -{ - int i; - int t; - assert(new_value <= old); - - if (old == 0) - return 0; - - t = (n / old) * new_value; - for (i = (n % old); i; i--) - if (rng_int() % old < new_value) - t++; - - return t; -} - -int -change_hitpoints (unit * u, int value) -{ - int hp = u->hp; - - hp += value; - - /* Jede Person benötigt mindestens 1 HP */ - if (hp < u->number){ - if (hp < 0){ /* Einheit tot */ - hp = 0; - } - scale_number(u, hp); - } - u->hp = hp; - return hp; -} - -unsigned int -atoip(const char *s) -{ - int n; - - n = atoi (s); - - if (n < 0) - n = 0; - - return n; -} - -region * -findunitregion (const unit * su) -{ -#ifndef SLOW_REGION - return su->region; -#else - region *r; - const unit *u; - - for (r = regions; r; r = r->next) { - for (u = r->units; u; u = u->next) { - if (su == u) { - return r; - } - } - } - - /* This should never happen */ - assert (!"Die unit wurde nicht gefunden"); - - return (region *) NULL; -#endif -} - -int -effskill(const unit * u, skill_t sk) -{ - return eff_skill(u, sk, u->region); -} - -int -eff_stealth(const unit * u, const region * r) -{ - int e = 0; - - /* Auf Schiffen keine Tarnung! */ - if (!u->ship && skill_enabled[SK_STEALTH]) { - e = eff_skill (u, SK_STEALTH, r); - - if (fval(u, UFL_STEALTH)) { - int es = u_geteffstealth(u); - if (es >=0 && es < e) return es; - } - } - return e; -} - -boolean -unit_has_cursed_item(unit *u) -{ - item * itm = u->items; - while (itm) { - if (fval(itm->type, ITF_CURSED) && itm->number>0) return true; - itm=itm->next; - } - return false; -} - -static void -init_gms(void) -{ - faction * f; - - for (f=factions;f;f=f->next) { - const attrib * a = a_findc(f->attribs, &at_gm); - - if (a!=NULL) fset(f, FFL_GM); - } -} - -static int -autoalliance(const plane * pl, const faction * sf, const faction * f2) -{ - static boolean init = false; - if (!init) { - init_gms(); - init = true; - } - if (pl && (pl->flags & PFL_FRIENDLY)) return HELP_ALL; - /* if f2 is a gm in this plane, everyone has an auto-help to it */ - if (fval(f2, FFL_GM)) { - attrib * a = a_find(f2->attribs, &at_gm); - - while (a) { - const plane * p = (const plane*)a->data.v; - if (p==pl) return HELP_ALL; - a=a->next; - } - } - - if (f_get_alliance(sf)!=NULL && AllianceAuto()) { - if (sf->alliance==f2->alliance) return AllianceAuto(); - } - - return 0; -} - -static int -ally_mode(const ally * sf, int mode) -{ - if (sf==NULL) return 0; - return sf->status & mode; -} - -int -alliedgroup(const struct plane * pl, const struct faction * f, - const struct faction * f2, const struct ally * sf, int mode) -{ - while (sf && sf->faction!=f2) sf=sf->next; - if (sf==NULL) { - mode = mode & autoalliance(pl, f, f2); - } - mode = ally_mode(sf, mode) | (mode & autoalliance(pl, f, f2)); - if (AllianceRestricted()) { - if (a_findc(f->attribs, &at_npcfaction)) { - return mode; - } - if (a_findc(f2->attribs, &at_npcfaction)) { - return mode; - } - if (f->alliance!=f2->alliance) { - mode &= ~AllianceRestricted(); - } - } - return mode; -} - -int -alliedfaction(const struct plane * pl, const struct faction * f, - const struct faction * f2, int mode) -{ - return alliedgroup(pl, f, f2, f->allies, mode); -} - -/* Die Gruppe von Einheit u hat helfe zu f2 gesetzt. */ -int -alliedunit(const unit * u, const faction * f2, int mode) -{ - ally * sf; - int automode; - - assert(u->region); /* the unit should be in a region, but it's possible that u->number==0 (TEMP units) */ - if (u->faction == f2) return mode; - if (u->faction != NULL && f2!=NULL) { - plane * pl; - - if (mode&HELP_FIGHT) { - if ((u->flags&UFL_DEFENDER) || (u->faction->flags&FFL_DEFENDER)) { - faction * owner = region_get_owner(u->region); - /* helps the owner of the region */ - if (owner==f2) { - return HELP_FIGHT; - } - } - } - - pl = rplane(u->region); - automode = mode & autoalliance(pl, u->faction, f2); - - if (pl!=NULL && (pl->flags & PFL_NOALLIANCES)) - mode = (mode & automode) | (mode & HELP_GIVE); - - sf = u->faction->allies; - if (fval(u, UFL_GROUP)) { - const attrib * a = a_findc(u->attribs, &at_group); - if (a!=NULL) sf = ((group*)a->data.v)->allies; - } - return alliedgroup(pl, u->faction, f2, sf, mode); - } - return 0; -} - -boolean -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)) - return true; - return false; -} - -boolean -cansee(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 */ -{ - int stealth, rings; - unit *u2 = r->units; - static const item_type * itype_grail; - static boolean init; - - if (!init) { - init = true; - itype_grail = it_find("grail"); - } - - if (u->faction == f || omniscient(f)) { - return true; - } else if (fval(u->race, RCF_INVISIBLE)) { - return false; - } else if (u->number == 0) { - 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. */ - u = (unit *)a->data.v; - } else { - return false; - } - } - - if (leftship(u)) return true; - if (itype_grail!=NULL && i_get(u->items, itype_grail)) 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, GUARD_ALL)!=0 || usiege(u) || u->building || u->ship) { - return true; - } - - rings = invisible(u, NULL); - stealth = eff_stealth(u, r) - modifier; - - while (u2) { - if (ringsnumber || invisible(u, u2) < u->number) { - if (skill_enabled[SK_PERCEPTION]) { - int observation = eff_skill(u2, SK_PERCEPTION, r); - - if (observation >= stealth) { - return true; - } - } else { - return true; - } - } - - /* find next unit in our faction */ - do { - u2=u2->next; - } while (u2 && u2->faction != f); - } - return false; -} - -boolean -cansee_unit(const unit * u, const unit * target, int modifier) -/* target->region kann != u->region sein, wenn es um durchreisen geht */ -{ - if (fval(target->race, RCF_INVISIBLE) || target->number == 0) return false; - else if (target->faction == u->faction) return true; - else { - int n, rings, o; - - if (is_guard(target, GUARD_ALL)!=0 || usiege(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]) { - o = eff_skill(u, SK_PERCEPTION, target->region); - if (o >= n) { - return true; - } - } else { - return true; - } - } - return false; -} - -boolean -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 */ -{ - int n; - unit *u2; - - if (fval(u->race, RCF_INVISIBLE) || u->number == 0) return false; - else if (u->faction == f) return true; - else { - int rings; - - if (is_guard(u, GUARD_ALL)!=0 || usiege(u) || u->building || u->ship) { - return true; - } - - n = eff_stealth(u, r) - modifier; - rings = invisible(u, NULL); - if (rings==0 && n<=0) { - return true; - } - - for (u2 = r->units; u2; u2 = u2->next){ - if (u2->faction == f) { - int o; - - if (rings && invisible(u, u2) >= u->number) continue; - - o = eff_skill(u2, SK_PERCEPTION, r); - - if (o >= n) { - return true; - } - } - } - } - return false; -} - -#ifndef NDEBUG -const char * -strcheck (const char *s, size_t maxlen) -{ - static char buffer[16 * 1024]; - if (strlen(s) > maxlen) { - assert(maxlen < 16 * 1024); - log_warning(("[strcheck] String wurde auf %d Zeichen verkürzt:\n%s\n", - (int)maxlen, s)); - strlcpy(buffer, s, maxlen); - return buffer; - } - return s; -} -#endif - -static attrib_type at_lighthouse = { - "lighthouse" - /* Rest ist NULL; temporäres, nicht alterndes Attribut */ -}; - -/* update_lighthouse: call this function whenever the size of a lighthouse changes - * it adds temporary markers to the surrounding regions. - * The existence of markers says nothing about the quality of the observer in - * the lighthouse, for this may change more frequently. - */ -void -update_lighthouse(building * lh) -{ - static boolean init_lighthouse = false; - static const struct building_type * bt_lighthouse = 0; - - if (!init_lighthouse) { - bt_lighthouse = bt_find("lighthouse"); - if (bt_lighthouse==NULL) return; - init_lighthouse = true; - } - - if (lh->type==bt_lighthouse) { - region * r = lh->region; - int d = (int)log10(lh->size) + 1; - int x; - - if (lh->size>0) { - r->flags |= RF_LIGHTHOUSE; - } - - for (x=-d;x<=d;++x) { - int y; - for (y=-d;y<=d;++y) { - attrib * a; - region * r2; - int px = r->x+x, py = r->y+y; - pnormalize(&px, &py, rplane(r)); - r2 = findregion(px, py); - if (r2==NULL) continue; - if (!fval(r2->terrain, SEA_REGION)) continue; - if (distance(r, r2) > d) continue; - a = a_find(r2->attribs, &at_lighthouse); - while (a && a->type==&at_lighthouse) { - building * b = (building*)a->data.v; - if (b==lh) break; - a = a->next; - } - if (!a) { - a = a_add(&r2->attribs, a_new(&at_lighthouse)); - a->data.v = (void*)lh; - } - } - } - } -} - -int -count_all(const faction * f) -{ -#ifndef NDEBUG - int n = 0; - unit *u; - for (u=f->units;u;u=u->nextF) { - if (playerrace(u->race)) { - n += u->number; - assert(f==u->faction); - } - } - if (f->num_people != n) { - log_error(("# of people in %s is != num_people: %d should be %d.\n", - factionid(f), f->num_people, n)); - } -#endif - return f->num_people; -} - -int -count_migrants (const faction * f) -{ - unit *u = f->units; - int n = 0; - while (u) { - assert(u->faction == f); - if (u->race != f->race && u->race != new_race[RC_ILLUSION] && u->race != new_race[RC_SPELL] - && !!playerrace(u->race) && !(is_cursed(u->attribs, C_SLAVE, 0))) - { - n += u->number; - } - u = u->nextF; - } - return n; -} - -int -count_maxmigrants(const faction * f) -{ - static int migrants = -1; - - if (migrants<0) { - migrants = get_param_int(global.parameters, "rules.migrants", INT_MAX); - } - if (migrants==INT_MAX) { - int x = 0; - if (f->race == new_race[RC_HUMAN]) { - int nsize = count_all(f); - if (nsize>0) { - x = (int)(log10(nsize / 50.0) * 20); - if (x < 0) x = 0; - } - } - return x; - } - return migrants; -} - -void -init_tokens(const struct order * ord) -{ - char * cmd = getcommand(ord); - init_tokens_str(cmd, cmd); -} - -void -parse(keyword_t kword, int (*dofun)(unit *, struct order *), boolean thisorder) -{ - region *r; - - for (r = regions; r; r = r->next) { - unit **up = &r->units; - while (*up) { - unit * u = *up; - order ** ordp = &u->orders; - if (thisorder) ordp = &u->thisorder; - while (*ordp) { - order * ord = *ordp; - if (get_keyword(ord) == kword) { - if (dofun(u, ord)!=0) break; - if (u->orders==NULL) break; - } - if (thisorder) break; - if (*ordp==ord) ordp=&ord->next; - } - if (*up==u) up=&u->next; - } - } -} - -const char * -igetstrtoken(const char * initstr) -{ - if (initstr!=NULL) { - init_tokens_str(initstr, NULL); - } - - return getstrtoken(); -} - -unsigned int -getuint (void) -{ - return atoip((const char *)getstrtoken()); -} - -int -getint (void) -{ - return atoi((const char *)getstrtoken()); -} - -const struct race * -findrace(const char * s, const struct locale * lang) -{ - struct tnode * tokens = get_translations(lang, UT_RACES); - variant token; - - assert(lang); - if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { - return (const struct race *)token.v; - } - return NULL; -} - -int -findoption(const char *s, const struct locale * lang) -{ - struct tnode * tokens = get_translations(lang, UT_OPTIONS); - variant token; - - if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { - return (direction_t)token.i; - } - return NODIRECTION; -} - -#if PTRIES -static struct trie_node * ptries[UT_MAX][4]; - -static struct trie_node ** -get_ptrie(const struct locale * lang, int type) -{ - int index = (strcmp(locale_name(lang), "de")==0); - return &(ptries[type][index]); -} - -static int -umlaut_substitution(const char * ip, char * op, size_t outlen) -{ -#define UMAX 7 - static struct replace { - ucs4_t ucs; - const char str[3]; - } replace[UMAX] = { - /* match lower-case (!) umlauts and others to transcriptions */ - { 223, "ss"}, /* szlig */ - { 228, "ae"}, /* auml */ - { 229, "aa"}, /* norsk */ - { 230, "ae"}, /* norsk */ - { 246, "oe"}, /* ouml */ - { 248, "oe"}, /* norsk */ - { 252, "ue"}, /* uuml */ - }; - int subs = 0; - while (*ip) { - ucs4_t ucs = *ip; - size_t size = 1; - size_t cpsize = 1; - - if (ucs & 0x80) { - int ret = unicode_utf8_to_ucs4(&ucs, ip, &size); - if (ret!=0) { - return ret; - } - cpsize = size; - if (ucs >= replace[0].ucs && ucs <= replace[UMAX-1].ucs) { - int i; - for (i=0;i!=UMAX;++i) { - if (replace[i].ucs==ucs) { - cpsize = 0; - memcpy(op, replace[i].str, 2); - op+=2; - ++subs; - break; - } - } - } - } - if (cpsize) { - if (cpsize>outlen) { - return -1; - } - memcpy(op, ip, cpsize); - } - - ip += size; - op += cpsize; - outlen -= cpsize; - } - - if (outlen<=0) { - return -1; - } - *op = 0; - return subs; -} - -static int -ptrie_find(struct trie_node *ptrie, const char * key, void * data, size_t size) -{ - trie_node * node = trie_find_prefix(ptrie, key); - if (node) { - void * result = trie_getdata(node); - memcpy(data, result, size); - return 0; - } - return -1; -} - -static int -ptrie_insert(struct trie_node **ptrie, const char * name, void * data, size_t size) -{ - char converted[256]; - char simple[256]; - int ret = unicode_utf8_tolower(converted, 256, name); - if (ret==0) { - int subs = umlaut_substitution(converted, simple, sizeof(simple)); - if (subs>0) { - trie_insert(ptrie, simple, data, size); - } - trie_insert(ptrie, converted, data, size); - } - return ret; -} -#endif - -skill_t -findskill(const char *s, const struct locale * lang) -{ -#if PTRIES - char lowercase[256]; - int res = unicode_utf8_tolower(lowercase, sizeof(lowercase), s); - if (res==0) { - trie_node ** ptrie = get_ptrie(lang, UT_SKILLS); - skill_t sk; - int result = ptrie_find(*ptrie, lowercase, &sk, sizeof(sk)); - if (result==0) return sk; - } - return NOSKILL; -#else - struct tnode * tokens = get_translations(lang, UT_SKILLS); - variant token; - - if (findtoken(tokens, s, &token)==E_TOK_NOMATCH) return NOSKILL; - return (skill_t)token.i; -#endif -} - -keyword_t -findkeyword(const char *s, const struct locale * lang) -{ - struct tnode * tokens = get_translations(lang, UT_KEYWORDS); - variant token; - - if (*s == '@') s++; - if (findtoken(tokens, s, &token)==E_TOK_NOMATCH) return NOKEYWORD; - if (global.disabled[token.i]) return NOKEYWORD; - return (keyword_t) token.i; -} - -param_t -findparam(const char *s, const struct locale * lang) -{ - struct tnode * tokens = get_translations(lang, UT_PARAMS); - variant token; - - if (findtoken(tokens, s, &token)==E_TOK_NOMATCH) { - const building_type * btype = findbuildingtype(s, lang); - if (btype!=NULL) return (param_t) P_GEBAEUDE; - return NOPARAM; - } - if (token.i==P_BUILDING) return P_GEBAEUDE; - return (param_t)token.i; -} - -param_t -getparam (const struct locale * lang) -{ - return findparam (getstrtoken (), lang); -} - -faction * -findfaction (int n) -{ - faction * f = ffindhash(n); - return f; -} - -faction * -getfaction (void) -{ - return findfaction (getid()); -} - -unit * -findunitr (const region * r, int n) -{ - unit *u; - - /* findunit regional! */ - - for (u = r->units; u; u = u->next) - if (u->no == n) - return u; - - return 0; -} - -unit *findunit(int n) -{ - if (n <= 0) { - return NULL; - } - return ufindhash(n); -} - -unit * -findunitg (int n, const region * hint) -{ - - /* Abfangen von Syntaxfehlern. */ - if (n <= 0) - return NULL; - - /* findunit global! */ - hint = 0; - return ufindhash(n); -} - -unit * -getnewunit (const region * r, const faction * f) -{ - int n; - n = getid(); - - return findnewunit (r, f, n); -} - -static int -read_newunitid (const faction * f, const region * r) -{ - int n; - unit *u2; - n = getid(); - if (n == 0) - return -1; - - u2 = findnewunit(r, f, n); - if (u2) return u2->no; - - return -1; -} - -int -read_unitid (const faction * f, const region * r) -{ - const char * s = getstrtoken(); - - /* Da s nun nur einen string enthaelt, suchen wir ihn direkt in der - * paramliste. machen wir das nicht, dann wird getnewunit in s nach der - * nummer suchen, doch dort steht bei temp-units nur "temp" drinnen! */ - - switch (findparam(s, f->locale)) { - case P_TEMP: - return read_newunitid(f, r); - } - if (!s || *s == 0) - return -1; - return atoi36((const char *)s); -} - -/* exported symbol */ -boolean getunitpeasants; -unit * -getunitg(const region * r, const faction * f) -{ - int n = read_unitid(f, r); - - if (n == 0) { - getunitpeasants = 1; - return NULL; - } - getunitpeasants = 0; - if (n < 0) return 0; - - return findunit(n); -} - -unit * -getunit(const region * r, const faction * f) -{ - int n = read_unitid(f, r); - unit *u2; - - if (n == 0) { - getunitpeasants = 1; - return NULL; - } - getunitpeasants = 0; - if (n < 0) return 0; - - u2 = findunit(n); - if (u2!=NULL && u2->region==r) { - /* there used to be a 'u2->flags & UFL_ISNEW || u2->number>0' condition - * here, but it got removed because of a bug that made units disappear: - * http://eressea.upb.de/mantis/bug_view_page.php?bug_id=0000172 - */ - return u2; - } - - return NULL; -} - -/* - String Listen --------------------------------------------- */ -void -addstrlist (strlist ** SP, const char *s) -{ - strlist * slist = malloc(sizeof(strlist)); - slist->next = NULL; - slist->s = strdup(s); - addlist(SP, slist); -} - -void -freestrlist (strlist * s) -{ - strlist *q, *p = s; - while (p) { - q = p->next; - free(p->s); - free(p); - p = q; - } -} - -/* - Meldungen und Fehler ------------------------------------------------- */ - -boolean lomem = false; - -/* - Namen der Strukturen -------------------------------------- */ -typedef char name[OBJECTIDSIZE+1]; -static name idbuf[8]; -static int nextbuf = 0; - -char * -estring_i(char *ibuf) -{ - char *p = ibuf; - - while (*p) { - if (isxspace(*(unsigned*)p) == ' ') { - *p = '~'; - } - ++p; - } - return ibuf; -} - -char * -estring(const char *s) -{ - char *ibuf = idbuf[(++nextbuf) % 8]; - - strlcpy(ibuf, s, sizeof(name)); - return estring_i(ibuf); -} - -char * -cstring_i(char *ibuf) -{ - char *p = ibuf; - - while (*p) { - if (*p == '~') { - *p = ' '; - } - ++p; - } - return ibuf; -} - -char * -cstring(const char *s) -{ - char *ibuf = idbuf[(++nextbuf) % 8]; - - strlcpy(ibuf, s, sizeof(name)); - return cstring_i(ibuf); -} - -building * -largestbuilding(const region * r, cmp_building_cb cmp_gt, boolean imaginary) -{ - building *b, *best = NULL; - - for (b = rbuildings(r); b; b = b->next) { - if (cmp_gt(b, best)<=0) continue; - if (!imaginary) { - const attrib * a = a_find(b->attribs, &at_icastle); - if (a) continue; - } - best = b; - } - return best; -} - -char * -write_unitname(const unit * u, char * buffer, size_t size) -{ - snprintf((char*)buffer, size, "%s (%s)", (const char*)u->name, itoa36(u->no)); - buffer[size-1] = 0; - return buffer; -} - -const char * -unitname(const unit * u) -{ - char *ubuf = idbuf[(++nextbuf) % 8]; - return write_unitname(u, ubuf, sizeof(name)); -} - -/* -- Erschaffung neuer Einheiten ------------------------------ */ - -extern faction * dfindhash(int i); - -static const char* forbidden[] = { "t", "te", "tem", "temp", NULL }; - -int -forbiddenid(int id) -{ - static int * forbid = NULL; - static size_t len; - size_t i; - if (id<=0) return 1; - if (!forbid) { - while (forbidden[len]) ++len; - forbid = calloc(len, sizeof(int)); - for (i=0;i!=len;++i) { - forbid[i] = strtol(forbidden[i], NULL, 36); - } - } - for (i=0;i!=len;++i) if (id==forbid[i]) return 1; - return 0; -} - -/* ID's für Einheiten und Zauber */ -int -newunitid(void) -{ - int random_unit_no; - int start_random_no; - random_unit_no = 1 + (rng_int() % MAX_UNIT_NR); - start_random_no = random_unit_no; - - while (ufindhash(random_unit_no) || dfindhash(random_unit_no) - || cfindhash(random_unit_no) - || forbiddenid(random_unit_no)) - { - random_unit_no++; - if (random_unit_no == MAX_UNIT_NR + 1) { - random_unit_no = 1; - } - if (random_unit_no == start_random_no) { - random_unit_no = (int) MAX_UNIT_NR + 1; - } - } - return random_unit_no; -} - -int -newcontainerid(void) -{ - int random_no; - int start_random_no; - - random_no = 1 + (rng_int() % MAX_CONTAINER_NR); - start_random_no = random_no; - - while (findship(random_no) || findbuilding(random_no)) { - random_no++; - if (random_no == MAX_CONTAINER_NR + 1) { - random_no = 1; - } - if (random_no == start_random_no) { - random_no = (int) MAX_CONTAINER_NR + 1; - } - } - return random_no; -} - -unit * -createunit(region * r, faction * f, int number, const struct race * rc) -{ - assert(rc); - return create_unit(r, f, number, rc, 0, NULL, NULL); -} - -boolean -idle (faction * f) -{ - return (boolean) (f ? false : true); -} - - -int -maxworkingpeasants(const struct region * r) -{ - int i = production(r) * MAXPEASANTS_PER_AREA - - ((rtrees(r,2)+rtrees(r,1)/2) * TREESIZE); - return MAX(i, 0); -} - -int -lighthouse_range(const building * b, const faction * f) -{ - int d = 0; - if (fval(b, BLD_WORKING) && b->size >= 10) { - int maxd = (int)log10(b->size) + 1; - - if (skill_enabled[SK_PERCEPTION]) { - region * r = b->region; - int c = 0; - unit *u; - for (u = r->units; u; u = u->next) { - if (u->building == b) { - c += u->number; - if (c > buildingcapacity(b)) break; - if (f==NULL || u->faction == f) { - int sk = eff_skill(u, SK_PERCEPTION, r) / 3; - d = MAX(d, sk); - d = MIN(maxd, d); - if (d==maxd) break; - } - } else if (c) break; /* first unit that's no longer in the house ends the search */ - } - } else { - /* E3A rule: no perception req'd */ - return maxd; - } - } - return d; -} - -boolean -check_leuchtturm(region * r, faction * f) -{ - attrib * a; - - if (!fval(r->terrain, SEA_REGION)) return false; - - for (a = a_find(r->attribs, &at_lighthouse);a && a->type==&at_lighthouse;a=a->next) { - building *b = (building *)a->data.v; - - assert(b->type == bt_find("lighthouse")); - if (fval(b, BLD_WORKING) && b->size >= 10) { - int maxd = (int)log10(b->size) + 1; - - if (skill_enabled[SK_PERCEPTION]) { - region *r2 = b->region; - unit *u; - int c = 0; - int d = 0; - - for (u = r2->units; u; u = u->next) { - if (u->building == b) { - c += u->number; - if (c > buildingcapacity(b)) break; - if (f==NULL || u->faction == f) { - if (!d) d = distance(r, r2); - if (maxd < d) break; - if (eff_skill(u, SK_PERCEPTION, r) >= d * 3) return true; - } - } else if (c) break; /* first unit that's no longer in the house ends the search */ - } - } else { - /* E3A rule: no perception req'd */ - return maxd; - } - } - } - - return false; -} - -region * -lastregion (faction * f) -{ -#ifdef SMART_INTERVALS - unit * u = f->units; - region *r = f->last; - - if (u==NULL) return NULL; - if (r!=NULL) return r->next; - - /* it is safe to start in the region of the first unit. */ - f->last = u->region; - /* if regions have indices, we can skip ahead: */ - for (u=u->nextF; u!=NULL; u=u->nextF) { - r = u->region; - if (r->index > f->last->index) f->last = r; - } - - /* we continue from the best region and look for travelthru etc. */ - for (r = f->last->next; r; r = r->next) { - plane * p = rplane(r); - - /* search the region for travelthru-attributes: */ - if (fval(r, RF_TRAVELUNIT)) { - attrib * ru = a_find(r->attribs, &at_travelunit); - while (ru && ru->type==&at_travelunit) { - u = (unit*)ru->data.v; - if (u->faction == f) { - f->last = r; - break; - } - ru = ru->next; - } - } - if (f->last == r) continue; - if (check_leuchtturm(r, f)) - f->last = r; - if (p && is_watcher(p, f)) { - f->last = r; - } - } - return f->last->next; -#else - return NULL; -#endif -} - -region * -firstregion (faction * f) -{ -#ifdef SMART_INTERVALS - region *r = f->first; - - if (f->units==NULL) return NULL; - if (r!=NULL) return r; - - return f->first = regions; -#else - return regions; -#endif -} - -void ** blk_list[1024]; -int list_index; -int blk_index; - -static void -gc_done(void) -{ - int i, k; - for (i=0;i!=list_index;++i) - { - for (k=0;k!=1024;++k) free(blk_list[i][k]); - free(blk_list[i]); - } - for (k=0;k!=blk_index;++k) free(blk_list[list_index][k]); - free(blk_list[list_index]); - -} - -void * -gc_add(void * p) -{ - if (blk_index==0) { - blk_list[list_index] = (void**)malloc(1024 * sizeof(void*)); - } - blk_list[list_index][blk_index] = p; - blk_index = (blk_index+1) % 1024; - if (!blk_index) ++ list_index; - return p; -} - -static void -init_directions(tnode * root, const struct locale * lang) -{ - /* mit dieser routine kann man mehrere namen für eine direction geben, - * das ist für die hexes ideal. */ - const struct { - const char* name; - int direction; - } dirs [] = { - { "dir_ne", D_NORTHEAST}, - { "dir_nw", D_NORTHWEST}, - { "dir_se", D_SOUTHEAST}, - { "dir_sw", D_SOUTHWEST}, - { "dir_east", D_EAST}, - { "dir_west", D_WEST}, - { "northeast", D_NORTHEAST}, - { "northwest", D_NORTHWEST}, - { "southeast", D_SOUTHEAST}, - { "southwest", D_SOUTHWEST}, - { "east", D_EAST }, - { "west",D_WEST }, - { "PAUSE", D_PAUSE }, - { NULL, NODIRECTION} - }; - int i; - struct tnode * tokens = get_translations(lang, UT_DIRECTIONS); - - for (i=0; dirs[i].direction!=NODIRECTION;++i) { - variant token; - token.i = dirs[i].direction; - addtoken(tokens, LOC(lang, dirs[i].name), token); - } -} - -direction_t -finddirection(const char *s, const struct locale * lang) -{ - struct tnode * tokens = get_translations(lang, UT_DIRECTIONS); - variant token; - - if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { - return (direction_t)token.i; - } - return NODIRECTION; -} - -static void -init_locale(const struct locale * lang) -{ - variant var; - int i; - const struct race * rc; - struct tnode * tokens; - const terrain_type * terrain; -#if PTRIES - trie_node ** ptrie; -#endif - - tokens = get_translations(lang, UT_MAGIC); - if (tokens) { - const char * str = get_param(global.parameters, "rules.magic.playerschools"); - char * sstr, * tok; - if (str==NULL) { - str = "gwyrrd illaun draig cerddor tybied"; - } - - sstr = strdup(str); - tok = strtok(sstr, " "); - while (tok) { - for (i=0;i!=MAXMAGIETYP;++i) { - if (strcmp(tok, magic_school[i])==0) break; - } - assert(i!=MAXMAGIETYP); - var.i = i; - addtoken(tokens, LOC(lang, mkname("school", tok)), var); - tok = strtok(NULL, " "); - } - free(sstr); - } - - tokens = get_translations(lang, UT_DIRECTIONS); - init_directions(tokens, lang); - - tokens = get_translations(lang, UT_RACES); - for (rc=races;rc;rc=rc->next) { - var.v = (void*)rc; - addtoken(tokens, LOC(lang, rc_name(rc, 1)), var); - addtoken(tokens, LOC(lang, rc_name(rc, 0)), var); - } - - tokens = get_translations(lang, UT_PARAMS); - for (i=0;i!=MAXPARAMS;++i) { - var.i = i; - addtoken(tokens, LOC(lang, parameters[i]), var); - } -#if PTRIES - ptrie = get_ptrie(lang, UT_SKILLS); - for (i=0;i!=MAXSKILLS;++i) { - skill_t sk = (skill_t)i; - const char * skname = skillname(sk, lang); - if (skname!=NULL) { - ptrie_insert(ptrie, skname, &sk, sizeof(sk)); - } - } -#else - tokens = get_translations(lang, UT_SKILLS); - for (i=0;i!=MAXSKILLS;++i) { - const char * skname = skillname((skill_t)i, lang); - if (skname!=NULL) { - var.i = i; - addtoken(tokens, skname, var); - } - } -#endif - - tokens = get_translations(lang, UT_KEYWORDS); - for (i=0;i!=MAXKEYWORDS;++i) { - var.i = i; - if (keywords[i]) addtoken(tokens, LOC(lang, keywords[i]), var); - } - - tokens = get_translations(lang, UT_OPTIONS); - for (i=0;i!=MAXOPTIONS;++i) { - var.i = i; - if (options[i]) addtoken(tokens, LOC(lang, options[i]), var); - } - - tokens = get_translations(lang, UT_TERRAINS); - for (terrain=terrains();terrain!=NULL;terrain=terrain->next) { - var.v = (void*)terrain; - addtoken(tokens, LOC(lang, terrain->_name), var); - } -} - -typedef struct param { - struct param * next; - char * name; - char * data; -} param; - -int -getid(void) -{ - const char * str = (const char *)getstrtoken(); - int i = atoi36(str); - if (i<0) { - return -1; - } - return i; -} - -const char * -get_param(const struct param * p, const char * key) -{ - while (p!=NULL) { - if (strcmp(p->name, key)==0) return p->data; - p = p->next; - } - return NULL; -} - -int -get_param_int(const struct param * p, const char * key, int def) -{ - while (p!=NULL) { - if (strcmp(p->name, key)==0) return atoi(p->data); - p = p->next; - } - return def; -} - -static const char * g_datadir; -const char * -datapath(void) -{ - static char zText[MAX_PATH]; - if (g_datadir) return g_datadir; - return strcat(strcpy(zText, basepath()), "/data"); -} - -void -set_datapath(const char * path) -{ - g_datadir = path; -} - - -static const char * g_reportdir; -const char * -reportpath(void) -{ - static char zText[MAX_PATH]; - if (g_reportdir) return g_reportdir; - return strcat(strcpy(zText, basepath()), "/reports"); -} - -void -set_reportpath(const char * path) -{ - g_reportdir = path; -} - -static const char * g_basedir; -const char * -basepath(void) -{ - if (g_basedir) return g_basedir; - return "."; -} - - -void -set_basepath(const char * path) -{ - g_basedir = path; -} - -float -get_param_flt(const struct param * p, const char * key, float def) -{ - while (p!=NULL) { - if (strcmp(p->name, key)==0) return (float)atof(p->data); - p = p->next; - } - return def; -} - -void -set_param(struct param ** p, const char * key, const char * data) -{ - ++global.cookie; - while (*p!=NULL) { - if (strcmp((*p)->name, key)==0) { - free((*p)->data); - (*p)->data = strdup(data); - return; - } - p=&(*p)->next; - } - *p = malloc(sizeof(param)); - (*p)->name = strdup(key); - (*p)->data = strdup(data); - (*p)->next = NULL; -} - -void -kernel_done(void) -{ - /* calling this function releases memory assigned to static variables, etc. - * calling it is optional, e.g. a release server will most likely not do it. - */ - translation_done(); - gc_done(); - sql_done(); -} - -const char * localenames[] = { - "de", "en", - NULL -}; - -void -init_locales(void) -{ - int l; - for (l=0;localenames[l];++l) { - const struct locale * lang = find_locale(localenames[l]); - if (lang) init_locale(lang); - } -} - -/* TODO: soll hier weg */ -extern struct attrib_type at_shiptrail; - -attrib_type at_germs = { - "germs", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - a_writeshorts, - a_readshorts, - ATF_UNIQUE -}; - -/*********************/ -/* at_guard */ -/*********************/ -attrib_type at_guard = { - "guard", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - a_writeint, - a_readint, - ATF_UNIQUE -}; - -void -setstatus(struct unit * u, int status) -{ - assert(status>=ST_AGGRO && status<=ST_FLEE); - if (u->status!=status) { - u->status = (status_t)status; - } -} - -void -setguard(unit * u, unsigned int flags) -{ - /* setzt die guard-flags der Einheit */ - attrib * a = NULL; - assert(flags==0 || !fval(u, UFL_MOVED)); - assert(flags==0 || u->statusattribs, &at_guard); - } - if (flags == GUARD_NONE) { - freset(u, UFL_GUARD); - if (a) a_remove(&u->attribs, a); - return; - } - fset(u, UFL_GUARD); - fset(u->region, RF_GUARDED); - if ((int)flags==guard_flags(u)) { - if (a) a_remove(&u->attribs, a); - } else { - if (!a) a = a_add(&u->attribs, a_new(&at_guard)); - a->data.i = (int)flags; - } -} - -unsigned int -getguard(const unit * u) -{ - attrib * a; - - assert((u->building && fval(u, UFL_OWNER)) || fval(u, UFL_GUARD) || !"you're doing it wrong! check is_guard first"); - a = a_find(u->attribs, &at_guard); - if (a) { - return (unsigned int)a->data.i; - } - return guard_flags(u); -} - -#ifndef HAVE_STRDUP -char * -strdup(const char *s) -{ - return strcpy((char*)malloc(sizeof(char)*(strlen(s)+1)), s); -} -#endif - -void -remove_empty_factions(void) -{ - faction **fp, *f3; - - for (fp = &factions; *fp;) { - faction * f = *fp; - /* monster (0) werden nicht entfernt. alive kann beim readgame - * () auf 0 gesetzt werden, wenn monsters keine einheiten mehr - * haben. */ - if ((f->units==NULL || f->alive == 0) && !is_monsters(f)) { - ursprung * ur = f->ursprung; - while (ur && ur->id!=0) ur=ur->next; - if (verbosity>=2) log_stdio(stdout, "\t%s\n", factionname(f)); - - /* Einfach in eine Datei schreiben und später vermailen */ - - if (updatelog) fprintf(updatelog, "dropout %s\n", itoa36(f->no)); - - for (f3 = factions; f3; f3 = f3->next) { - ally * sf; - group * g; - ally ** sfp = &f3->allies; - while (*sfp) { - sf = *sfp; - if (sf->faction == f || sf->faction == NULL) { - *sfp = sf->next; - free(sf); - } - else sfp = &(*sfp)->next; - } - for (g = f3->groups; g; g=g->next) { - sfp = &g->allies; - while (*sfp) { - sf = *sfp; - if (sf->faction == f || sf->faction == NULL) { - *sfp = sf->next; - free(sf); - } - else sfp = &(*sfp)->next; - } - } - } - if (f->subscription) { - sql_print(("UPDATE subscriptions set status='DEAD' where id=%u;\n", - f->subscription)); - } - - *fp = f->next; - funhash(f); - free_faction(f); - free(f); - } - else fp = &(*fp)->next; - } -} - -void -remove_empty_units_in_region(region *r) -{ - unit **up = &r->units; - - while (*up) { - unit * u = *up; - - if (u->number) { - faction * f = u->faction; - if (f==NULL || !f->alive) { - set_number(u, 0); - } - if (MaxAge()>0) { - if ((!fval(f, FFL_NOTIMEOUT) && f->age > MaxAge())) { - set_number(u, 0); - } - } - } - if ((u->number == 0 && u->race != new_race[RC_SPELL]) || (u->age <= 0 && u->race == new_race[RC_SPELL])) { - remove_unit(up, u); - } - if (*up==u) up=&u->next; - } -} - -void -remove_empty_units(void) -{ - region *r; - - for (r = regions; r; r = r->next) { - remove_empty_units_in_region(r); - } -} - -boolean -faction_id_is_unused(int id) -{ - return findfaction(id)==NULL; -} - -int -weight(const unit * u) -{ - int w, n = 0, in_bag = 0; - - item * itm; - for (itm=u->items;itm;itm=itm->next) { - w = itm->type->weight * itm->number; - n += w; - if( !fval(itm->type, ITF_BIG)) - in_bag += w; - } - - n += u->number * u->race->weight; - - w = get_item(u, I_BAG_OF_HOLDING) * BAGCAPACITY; - if( w > in_bag ) - w = in_bag; - n -= w; - - return n; -} - -void -make_undead_unit(unit * u) -{ - free_orders(&u->orders); - name_unit(u); - fset(u, UFL_ISNEW); -} - -unsigned int guard_flags(const unit * u) -{ - unsigned int flags = GUARD_CREWS | GUARD_LANDING | GUARD_TRAVELTHRU | GUARD_TAX; -#if GUARD_DISABLES_PRODUCTION == 1 - flags |= GUARD_PRODUCE; -#endif -#if GUARD_DISABLES_RECRUIT == 1 - flags |= GUARD_RECRUIT; -#endif - switch (old_race(u->race)) { - case RC_ELF: - if (u->faction->race != u->race) break; - /* else fallthrough */ - case RC_TREEMAN: - flags |= GUARD_TREES; - break; - case RC_IRONKEEPER: - flags = GUARD_MINING; - break; - } - return flags; -} - -void -guard(unit * u, unsigned int mask) -{ - unsigned int flags = guard_flags(u); - setguard(u, flags & mask); -} - -int -besieged(const unit * u) -{ - /* belagert kann man in schiffen und burgen werden */ - return (u && !global.disabled[K_BESIEGE] - && u->building && u->building->besieged - && u->building->besieged >= u->building->size * SIEGEFACTOR); -} - -int -lifestyle(const unit * u) -{ - int need; - plane * pl; - static int gamecookie = -1; - if (gamecookie!=global.cookie) { - gamecookie = global.cookie; - } - - if (is_monsters(u->faction)) return 0; - - need = maintenance_cost(u); - - pl = rplane(u->region); - if (pl && fval(pl, PFL_NOFEED)) - return 0; - - return need; -} - -boolean has_horses(const struct unit * u) -{ - item * itm = u->items; - for (;itm;itm=itm->next) { - if (itm->type->flags&ITF_ANIMAL) return true; - } - return false; -} - -boolean -hunger(int number, unit * u) -{ - region * r = u->region; - int dead = 0, hpsub = 0; - int hp = u->hp / u->number; - static const char * damage = 0; - static const char * rcdamage = 0; - static const race * rc = 0; - - if (!damage) { - damage = get_param(global.parameters, "hunger.damage"); - if (damage==NULL) damage = "1d12+12"; - } - if (rc!=u->race) { - rcdamage = get_param(u->race->parameters, "hunger.damage"); - rc = u->race; - } - - while (number--) { - int dam = dice_rand(rcdamage?rcdamage:damage); - if (dam >= hp) { - ++dead; - } else { - hpsub += dam; - } - } - - if (dead) { - /* Gestorbene aus der Einheit nehmen, - * Sie bekommen keine Beerdingung. */ - ADDMSG(&u->faction->msgs, msg_message("starvation", - "unit region dead live", u, r, dead, u->number-dead)); - - scale_number(u, u->number - dead); - deathcounts(r, dead); - } - if (hpsub > 0) { - /* Jetzt die Schäden der nicht gestorbenen abziehen. */ - u->hp -= hpsub; - /* Meldung nur, wenn noch keine für Tote generiert. */ - if (dead == 0) { - /* Durch unzureichende Ernährung wird %s geschwächt */ - ADDMSG(&u->faction->msgs, msg_message("malnourish", - "unit region", u, r)); - } - } - return (dead || hpsub); -} - -void -plagues(region * r, boolean ismagic) -{ - int peasants; - int i; - int dead = 0; - - /* Seuchenwahrscheinlichkeit in % */ - - if (!ismagic) { - double mwp = MAX(maxworkingpeasants(r), 1); - double prob = pow(rpeasants(r) / (mwp * wage(r, NULL, NULL, turn) * 0.13), 4.0) - * PLAGUE_CHANCE; - - if (rng_double() >= prob) return; - } - - peasants = rpeasants(r); - dead = (int)(0.5F + PLAGUE_VICTIMS * peasants); - for (i = dead; i != 0; i--) { - if (rng_double() < PLAGUE_HEALCHANCE && rmoney(r) >= PLAGUE_HEALCOST) { - rsetmoney(r, rmoney(r) - PLAGUE_HEALCOST); - } else { - --dead; - } - } - - if (dead > 0) { - message * msg = add_message(&r->msgs, msg_message("pest", "dead", dead)); - msg_release(msg); - deathcounts(r, dead); - rsetpeasants(r, peasants - dead); - } -} - -/* Lohn bei den einzelnen Burgstufen für Normale Typen, Orks, Bauern, - * Modifikation für Städter. */ - -static const int wagetable[7][4] = { - {10, 10, 11, -7}, /* Baustelle */ - {10, 10, 11, -5}, /* Handelsposten */ - {11, 11, 12, -3}, /* Befestigung */ - {12, 11, 13, -1}, /* Turm */ - {13, 12, 14, 0}, /* Burg */ - {14, 12, 15, 1}, /* Festung */ - {15, 13, 16, 2} /* Zitadelle */ -}; - -int -cmp_wage(const struct building * b, const building * a) -{ - static const struct building_type * bt_castle; - if (!bt_castle) bt_castle = bt_find("castle"); - if (b->type==bt_castle) { - if (!a) return 1; - if (b->size>a->size) return 1; - if (b->size==a->size) return 0; - } - return -1; -} - -boolean is_owner_building(const struct building * b) -{ - region * r = b->region; - if (b->type->taxes && r->land && r->land->ownership) { - unit * u = building_owner(b); - return u && u->faction == r->land->ownership->owner; - } - return false; -} - -int -cmp_taxes(const building * b, const building * a) -{ - faction * f = region_get_owner(b->region); - if (b->type->taxes) { - unit * u = building_owner(b); - if (!u) { - return -1; - } else if (a) { - int newsize = buildingeffsize(b, false); - double newtaxes = b->type->taxes(b, newsize); - int oldsize = buildingeffsize(a, false); - double oldtaxes = a->type->taxes(a, oldsize); - - if (newtaxesoldtaxes) return 1; - else if (b->sizesize) return -1; - else if (b->size>a->size) return 1; - else { - if (u && u->faction==f) { - u = building_owner(a); - if (u && u->faction==f) return -1; - return 1; - } - } - } else { - return 1; - } - } - return -1; -} - -int -cmp_current_owner(const building * b, const building * a) -{ - faction * f = region_get_owner(b->region); - - assert(rule_region_owners()); - if (f && b->type->taxes) { - unit * u = building_owner(b); - if (!u || u->faction!=f) return -1; - if (a) { - int newsize = buildingeffsize(b, false); - double newtaxes = b->type->taxes(b, newsize); - int oldsize = buildingeffsize(a, false); - double oldtaxes = a->type->taxes(a, oldsize); - - if (newtaxes!=oldtaxes) return (newtaxes>oldtaxes)?1:-1; - if (newsize!=oldsize) return newsize-oldsize; - return (b->size-a->size); - } else { - return 1; - } - } - return -1; -} - -int rule_stealth_faction(void) -{ - static int gamecookie = -1; - static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { - rule = get_param_int(global.parameters, "rules.stealth.faction", 1); - gamecookie = global.cookie; - assert(rule>=0); - } - return rule; -} - -int rule_region_owners(void) -{ - static int gamecookie = -1; - static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { - rule = get_param_int(global.parameters, "rules.region_owners", 0); - gamecookie = global.cookie; - assert(rule>=0); - } - return rule; -} - -int rule_auto_taxation(void) -{ - static int gamecookie = -1; - static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { - rule = get_param_int(global.parameters, "rules.economy.taxation", TAX_ORDER); - gamecookie = global.cookie; - assert(rule>=0); - } - return rule; -} - -int rule_blessed_harvest(void) -{ - static int gamecookie = -1; - static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { - rule = get_param_int(global.parameters, "rules.magic.blessed_harvest", HARVEST_WORK); - gamecookie = global.cookie; - assert(rule>=0); - } - return rule; -} - -int rule_alliance_limit(void) -{ - static int gamecookie = -1; - static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { - rule = get_param_int(global.parameters, "rules.limit.alliance", 0); - gamecookie = global.cookie; - assert(rule>=0); - } - return rule; -} - -int rule_faction_limit(void) -{ - static int gamecookie = -1; - static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { - rule = get_param_int(global.parameters, "rules.limit.faction", 0); - gamecookie = global.cookie; - assert(rule>=0); - } - return rule; -} - -int rule_transfermen(void) -{ - static int gamecookie = -1; - static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { - rule = get_param_int(global.parameters, "rules.transfermen", 1); - gamecookie = global.cookie; - assert(rule>=0); - } - return rule; -} - -static int -default_wage(const region *r, const faction * f, const race * rc, int in_turn) -{ - building *b = largestbuilding(r, &cmp_wage, false); - int esize = 0; - curse * c; - double wage; - attrib *a; - const building_type *artsculpture_type = bt_find("artsculpture"); - static const curse_type * drought_ct, * blessedharvest_ct; - static boolean init; - - if (!init) { - init = true; - drought_ct = ct_find("drought"); - blessedharvest_ct = ct_find("blessedharvest"); - } - - if (b!=NULL) { - /* TODO: this reveals imaginary castles */ - esize = buildingeffsize(b, false); - } - - if (f!=NULL) { - int index = 0; - if (rc==new_race[RC_ORC] || rc==new_race[RC_SNOTLING]) { - index = 1; - } - wage = wagetable[esize][index]; - } else { - if (is_mourning(r, in_turn)) { - wage = 10; - } else if (fval(r->terrain, SEA_REGION)) { - wage = 11; - } else if (fval(r, RF_ORCIFIED)) { - wage = wagetable[esize][1]; - } else { - wage = wagetable[esize][2]; - } - if (rule_blessed_harvest()==HARVEST_WORK) { - /* E1 rules */ - wage += curse_geteffect(get_curse(r->attribs, blessedharvest_ct)); - } - } - - /* Artsculpture: Income +5 */ - for(b=r->buildings; b; b=b->next) { - if(b->type == artsculpture_type) { - wage += 5; - } - } - - /* Godcurse: Income -10 */ - if (curse_active(get_curse(r->attribs, ct_find("godcursezone")))) { - wage = MAX(0,wage-10); - } - - /* Bei einer Dürre verdient man nur noch ein Viertel */ - if (drought_ct) { - c = get_curse(r->attribs, drought_ct); - if (curse_active(c)) wage /= curse_geteffect(c); - } - - a = a_find(r->attribs, &at_reduceproduction); - if (a) wage = (wage * a->data.sa[0])/100; - - return (int)wage; -} - -static int -minimum_wage(const region *r, const faction * f, const race * rc, int in_turn) -{ - if (f && rc) { - return rc->maintenance; - } - return default_wage(r, f, rc, in_turn); -} - -/* Gibt Arbeitslohn für entsprechende Rasse zurück, oder für -* die Bauern wenn f == NULL. */ -int -wage(const region *r, const faction * f, const race * rc, int in_turn) -{ - if (global.functions.wage) { - return global.functions.wage(r, f, rc, in_turn); - } - return default_wage(r, f, rc, in_turn); -} - - -#define MAINTENANCE 10 -int -maintenance_cost(const struct unit * u) -{ - if (u==NULL) return MAINTENANCE; - if (global.functions.maintenance) { - int retval = global.functions.maintenance(u); - if (retval>=0) return retval; - } - return u->race->maintenance * u->number; -} - -message * -movement_error(unit * u, const char * token, order * ord, int error_code) -{ - direction_t d; - switch (error_code) { - case E_MOVE_BLOCKED: - d = finddirection(token, u->faction->locale); - return msg_message("moveblocked", "unit direction", u, d); - case E_MOVE_NOREGION: - return msg_feedback(u, ord, "unknowndirection", "dirname", token); - } - return NULL; -} - -int -movewhere(const unit *u, const char * token, region * r, region** resultp) -{ - region * r2; - direction_t d; - - if (*token == '\0') { - *resultp = NULL; - return E_MOVE_OK; - } - - d = finddirection(token, u->faction->locale); - switch (d) { - case D_PAUSE: - *resultp = r; - break; - - case NODIRECTION: - r2 = find_special_direction(r, token, u->faction->locale); - if (r2==NULL) { - return E_MOVE_NOREGION; - } - *resultp = r2; - break; - - default: - r2 = rconnect(r, d); - if (r2==NULL || move_blocked(u, r, r2)) { - return E_MOVE_BLOCKED; - } - *resultp = r2; - } - return E_MOVE_OK; -} - -boolean -move_blocked(const unit * u, const region *r, const region *r2) -{ - connection * b; - curse * c; - static const curse_type * fogtrap_ct = NULL; - - if (r2==NULL) return true; - b = get_borders(r, r2); - while (b) { - if (b->type->block && b->type->block(b, u, r)) return true; - b = b->next; - } - - if (fogtrap_ct==NULL) fogtrap_ct = ct_find("fogtrap"); - c = get_curse(r->attribs, fogtrap_ct); - if (curse_active(c)) return true; - return false; -} - -void -add_income(unit * u, int type, int want, int qty) -{ - if (want==INT_MAX) want = qty; - ADDMSG(&u->faction->msgs, msg_message("income", "unit region mode wanted amount", - u, u->region, type, want, qty)); -} - -void -reorder_units(region * r) -{ - unit ** unext = &r->units; - - if (r->buildings) { - building * b = r->buildings; - while (*unext && b) { - unit ** ufirst = unext; /* where the first unit in the building should go */ - unit ** umove = unext; /* a unit we consider moving */ - unit * owner = NULL; - while (*umove) { - unit * u = *umove; - if (u->number && u->building==b) { - unit ** uinsert = unext; - if (fval(u, UFL_OWNER)) { - uinsert = ufirst; - owner = u; - } - if (umove!=uinsert) { - *umove = u->next; - u->next = *uinsert; - *uinsert = u; - } else { - /* no need to move, skip ahead */ - umove = &u->next; - } - if (unext==uinsert) { - /* we have a new well-placed unit. jump over it */ - unext = &u->next; - } - } else { - umove = &u->next; - } - } - if (!owner && ufirst!=unext) { - owner = *ufirst; - fset(owner, UFL_OWNER); - } - b = b->next; - } - } - - if (r->ships) { - ship * sh = r->ships; - /* first, move all units up that are not on ships */ - unit ** umove = unext; /* a unit we consider moving */ - while (*umove) { - unit * u = *umove; - if (u->number && !u->ship) { - if (umove!=unext) { - *umove = u->next; - u->next = *unext; - *unext = u; - } else { - /* no need to move, skip ahead */ - umove = &u->next; - } - /* we have a new well-placed unit. jump over it */ - unext = &u->next; - } else { - umove = &u->next; - } - } - - while (*unext && sh) { - unit ** ufirst = unext; /* where the first unit in the building should go */ - unit ** umove = unext; /* a unit we consider moving */ - unit * owner = NULL; - while (*umove) { - unit * u = *umove; - if (u->number && u->ship==sh) { - unit ** uinsert = unext; - if (fval(u, UFL_OWNER)) { - uinsert = ufirst; - owner = u; - } - if (umove!=uinsert) { - *umove = u->next; - u->next = *uinsert; - *uinsert = u; - } else { - /* no need to move, skip ahead */ - umove = &u->next; - } - if (unext==uinsert) { - /* we have a new well-placed unit. jump over it */ - unext = &u->next; - } - } else { - umove = &u->next; - } - } - if (!owner && ufirst!=unext) { - owner = *ufirst; - fset(owner, UFL_OWNER); - } - sh = sh->next; - } - } -} - -int -produceexp(struct unit * u, skill_t sk, int n) -{ - if (global.producexpchance>0.0F) { - if (n==0 || !playerrace(u->race)) return 0; - learn_skill(u, sk, global.producexpchance); - } - return 0; -} - -int -lovar(double xpct_x2) -{ - int n = (int)(xpct_x2 * 500)+1; - if (n==0) return 0; - return (rng_int() % n + rng_int() % n)/1000; -} - -boolean -has_limited_skills (const struct unit * u) -{ - if (has_skill(u, SK_MAGIC) || has_skill(u, SK_ALCHEMY) || - has_skill(u, SK_TACTICS) || has_skill(u, SK_HERBALISM) || - has_skill(u, SK_SPY)) { - return true; - } else { - return false; - } -} - -void -attrib_init(void) -{ - /* Alle speicherbaren Attribute müssen hier registriert werden */ - at_register(&at_shiptrail); - at_register(&at_familiar); - at_register(&at_familiarmage); - at_register(&at_clone); - at_register(&at_clonemage); - at_register(&at_eventhandler); - at_register(&at_stealth); - at_register(&at_mage); - at_register(&at_countdown); - at_register(&at_curse); - - at_register(&at_seenspell); - - /* neue REGION-Attribute */ - at_register(&at_direction); - at_register(&at_moveblock); - at_register(&at_deathcount); - at_register(&at_chaoscount); - at_register(&at_woodcount); - - /* neue UNIT-Attribute */ - at_register(&at_siege); - at_register(&at_effect); - at_register(&at_private); - - at_register(&at_icastle); - at_register(&at_guard); - at_register(&at_group); - - at_register(&at_building_generic_type); - at_register(&at_maxmagicians); - at_register(&at_npcfaction); - - /* connection-typen */ - register_bordertype(&bt_noway); - register_bordertype(&bt_fogwall); - register_bordertype(&bt_wall); - register_bordertype(&bt_illusionwall); - register_bordertype(&bt_road); - register_bordertype(&bt_questportal); - - register_function((pf_generic)&minimum_wage, "minimum_wage"); - - at_register(&at_germs); -#if XECMD_MODULE - at_register(&at_xontormiaexpress); /* required for old datafiles */ -#endif - at_register(&at_speedup); - at_register(&at_building_action); -} - -void -kernel_init(void) -{ - char zBuffer[MAX_PATH]; - attrib_init(); - translation_init(); - - if (sqlpatch) { - sprintf(zBuffer, "%s/patch-%d.sql", datapath(), turn); - sql_init(zBuffer); - } -} - -order * -default_order(const struct locale * lang) -{ - return parse_order(locale_string(lang, "defaultorder"), lang); -} - -int -entertainmoney(const region *r) -{ - double n; - - if (is_cursed(r->attribs, C_DEPRESSION, 0)) { - return 0; - } - - n = rmoney(r) / ENTERTAINFRACTION; - - if (is_cursed(r->attribs, C_GENEROUS, 0)) { - n *= get_curseeffect(r->attribs, C_GENEROUS, 0); - } - - return (int)n; -} - -int rule_give(void) -{ - static int value = -1; - if (value<0) { - value = get_param_int(global.parameters, "rules.give", GIVE_DEFAULT); - } - return value; -} - -int markets_module(void) -{ - static int value = -1; - if (value<0) { - value = get_param_int(global.parameters, "modules.markets", 0); - } - return value; -} - -/** releases all memory associated with the game state. - * call this function before calling read_game() to load a new game - * if you have a previously loaded state in memory. - */ -void -free_gamedata(void) -{ - free_units(); - free_regions(); - free_borders(); - - while (alliances) { - alliance * al = alliances; - alliances = al->next; - free_alliance(al); - } - while (factions) { - faction * f = factions; - factions = f->next; - funhash(f); - free_faction(f); - free(f); - } - - while (planes) { - plane * pl = planes; - planes = planes->next; - free(pl->name); - free(pl); - } - - while (global.attribs) { - a_remove(&global.attribs, global.attribs); - } - ++global.cookie; /* readgame() already does this, but sjust in case */ -} - - -void -load_inifile(dictionary * d) -{ - const char * reportdir = reportpath(); - const char * datadir = datapath(); - const char * basedir = basepath(); - const char * str; - - assert(d); - - str = iniparser_getstring(d, "eressea:base", basedir); - if (str!=basedir) set_basepath(str); - str = iniparser_getstring(d, "eressea:report", reportdir); - if (str!=reportdir) set_reportpath(str); - str = iniparser_getstring(d, "eressea:data", datadir); - if (str!=datadir) set_datapath(str); - - lomem = iniparser_getint(d, "eressea:lomem", lomem)?1:0; - - str = iniparser_getstring(d, "eressea:encoding", NULL); - if (str) enc_gamedata = get_encoding_by_name(str); - - verbosity = iniparser_getint(d, "eressea:verbose", 2); - sqlpatch = iniparser_getint(d, "eressea:sqlpatch", false); - battledebug = iniparser_getint(d, "eressea:debug", battledebug)?1:0; - - str = iniparser_getstring(d, "eressea:locales", "de,en"); - make_locales(str); - - /* excerpt from [config] (the rest is used in bindings.c) */ - game_name = iniparser_getstring(d, "config:game", game_name); - - global.inifile = d; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include + +/* attributes includes */ +#include +#include + +/* kernel includes */ +#include "alliance.h" +#include "alchemy.h" +#include "battle.h" +#include "connection.h" +#include "building.h" +#include "calendar.h" +#include "curse.h" +#include "faction.h" +#include "group.h" +#include "item.h" +#include "magic.h" +#include "message.h" +#include "move.h" +#include "names.h" +#include "objtypes.h" +#include "order.h" +#include "plane.h" +#include "pool.h" +#include "race.h" +#include "region.h" +#include "save.h" +#include "ship.h" +#include "skill.h" +#include "terrain.h" +#include "unit.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libxml includes */ +#include +#include + +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define PTRIES 0 /* it turns out they are slow :-( */ +#if PTRIES +#include +#endif + +struct settings global = { + "Eressea", /* gamename */ +}; +FILE *logfile; +FILE *updatelog; +const struct race * new_race[MAXRACES]; +boolean sqlpatch = false; +boolean battledebug = false; +int turn = 0; + +#if XECMD_MODULE +attrib_type at_xontormiaexpress = { + "xontormiaexpress", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + a_writeint, + a_readint, + ATF_UNIQUE +}; +#endif + +int +NewbieImmunity(void) { + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "NewbieImmunity", 0); + } + return value; +} + +boolean +IsImmune(const faction * f) +{ + return !fval(f, FFL_NPC) && f->age < NewbieImmunity(); +} + +static int +MaxAge(void) { + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "MaxAge", 0); + } + return value; +} + +static int +ally_flag(const char * s, int help_mask) +{ + if ((help_mask&HELP_MONEY) && strcmp(s, "money")==0) return HELP_MONEY; + if ((help_mask&HELP_FIGHT) && strcmp(s, "fight")==0) return HELP_FIGHT; + if ((help_mask&HELP_GIVE) && strcmp(s, "give")==0) return HELP_GIVE; + if ((help_mask&HELP_GUARD) && strcmp(s, "guard")==0) return HELP_GUARD; + if ((help_mask&HELP_FSTEALTH) && strcmp(s, "stealth")==0) return HELP_FSTEALTH; + if ((help_mask&HELP_TRAVEL) && strcmp(s, "travel")==0) return HELP_TRAVEL; + return 0; +} + +boolean +ExpensiveMigrants(void) +{ + int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "study.expensivemigrants", 0); + } + return value; +} +/** Specifies automatic alliance modes. + * If this returns a value then the bits set are immutable between alliance + * partners (faction::alliance) and cannot be changed with the HELP command. + */ +int +AllianceAuto(void) +{ + static int value = -1; + if (value<0) { + const char * str = get_param(global.parameters, "alliance.auto"); + value = 0; + if (str!=NULL) { + char * sstr = strdup(str); + char * tok = strtok(sstr, " "); + while (tok) { + value |= ally_flag(tok, -1); + tok = strtok(NULL, " "); + } + free(sstr); + } + } + return value & HelpMask(); +} + +/** Limits the available help modes + * The bitfield returned by this function specifies the available help modes + * in this game (so you can, for example, disable HELP GIVE globally). + * Disabling a status will disable the command sequence entirely (order parsing + * uses this function). + */ +int +HelpMask(void) +{ + static int value = -1; + if (value<0) { + const char * str = get_param(global.parameters, "rules.help.mask"); + value = 0; + if (str!=NULL) { + char * sstr = strdup(str); + char * tok = strtok(sstr, " "); + while (tok) { + value |= ally_flag(tok, -1); + tok = strtok(NULL, " "); + } + free(sstr); + } else { + value = HELP_ALL; + } + } + return value; +} + +int +AllianceRestricted(void) +{ + static int value = -1; + if (value<0) { + const char * str = get_param(global.parameters, "alliance.restricted"); + value = 0; + if (str!=NULL) { + char * sstr = strdup(str); + char * tok = strtok(sstr, " "); + while (tok) { + value |= ally_flag(tok, -1); + tok = strtok(NULL, " "); + } + free(sstr); + } + value &= HelpMask(); + } + return value; +} + +int +LongHunger(const struct unit * u) { + static int value = -1; + if (u!=NULL) { + if (!fval(u, UFL_HUNGER)) return false; +#ifdef NEW_DAEMONHUNGER_RULE + if (u->race==new_race[RC_DAEMON]) return false; +#endif + } + if (value<0) { + value = get_param_int(global.parameters, "hunger.long", 0); + } + return value; +} + +int +SkillCap(skill_t sk) { + static int value = -1; + if (sk==SK_MAGIC) return 0; /* no caps on magic */ + if (value<0) { + value = get_param_int(global.parameters, "skill.maxlevel", 0); + } + return value; +} + +int +NMRTimeout(void) { + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "nmr.timeout", 0); + } + return value; +} + +race_t +old_race(const struct race * rc) +{ + race_t i; + for (i=0;i!=MAXRACES;++i) { + if (new_race[i]==rc) return i; + } + return NORACE; +} + +helpmode helpmodes[] = { + { "all", HELP_ALL }, + { "money", HELP_MONEY }, + { "fight", HELP_FIGHT }, + { "observe", HELP_OBSERVE }, + { "give", HELP_GIVE }, + { "guard", HELP_GUARD }, + { "stealth", HELP_FSTEALTH }, + { "travel", HELP_TRAVEL }, + { NULL, 0 } +}; + +const char *directions[MAXDIRECTIONS+2] = +{ + "northwest", + "northeast", + "east", + "southeast", + "southwest", + "west", + "", + "pause" +}; + +/** Returns the English name of the race, which is what the database uses. + */ +const char * +dbrace(const struct race * rc) +{ + static char zText[32]; + char * zPtr = zText; + + /* the english names are all in ASCII, so we don't need to worry about UTF8 */ + strcpy(zText, (const char*)LOC(find_locale("en"), rc_name(rc, 0))); + while (*zPtr) { + *zPtr = (char)(toupper(*zPtr)); + ++zPtr; + } + return zText; +} + +const char *parameters[MAXPARAMS] = +{ + "LOCALE", + "ALLES", + "JEDEM", + "BAUERN", + "BURG", + "EINHEIT", + "PRIVAT", + "HINTEN", + "KOMMANDO", + "KRAEUTER", + "NICHT", + "NAECHSTER", + "PARTEI", + "ERESSEA", + "PERSONEN", + "REGION", + "SCHIFF", + "SILBER", + "STRASSEN", + "TEMPORAERE", + "FLIEHE", + "GEBAEUDE", + "GIB", /* Für HELFE */ + "KAEMPFE", + "DURCHREISE", + "BEWACHE", + "ZAUBER", + "PAUSE", + "VORNE", + "AGGRESSIV", + "DEFENSIV", + "STUFE", + "HELFE", + "FREMDES", + "AURA", + "UM", + "BEISTAND", + "GNADE", + "HINTER", + "VOR", + "ANZAHL", + "GEGENSTAENDE", + "TRAENKE", + "GRUPPE", + "PARTEITARNUNG", + "BAEUME", + "XEPOTION", + "XEBALLOON", + "XELAEN", + "ALLIANZ" +}; + + +const char *keywords[MAXKEYWORDS] = +{ + "//", + "BANNER", + "ARBEITEN", + "ATTACKIEREN", + "BEKLAUEN", + "BELAGERE", + "BENENNEN", + "BENUTZEN", + "BESCHREIBEN", + "BETRETEN", + "BEWACHEN", + "BOTSCHAFT", + "ENDE", + "FAHREN", + "NUMMER", + "KRIEG", + "FRIEDEN", + "FOLGEN", + "FORSCHEN", + "GIB", + "HELFEN", + "KAEMPFEN", + "KAMPFZAUBER", + "KAUFEN", + "KONTAKTIEREN", + "LEHREN", + "LERNEN", + "LIEFERE", + "MACHEN", + "NACH", + "PASSWORT", + "REKRUTIEREN", + "RESERVIEREN", + "ROUTE", + "SABOTIEREN", + "OPTION", + "SPIONIEREN", + "STIRB", + "TARNEN", + "TRANSPORTIEREN", + "TREIBEN", + "UNTERHALTEN", + "VERKAUFEN", + "VERLASSEN", + "VERGESSEN", + "ZAUBERE", + "ZEIGEN", + "ZERSTOEREN", + "ZUECHTEN", + "DEFAULT", + "URSPRUNG", + "EMAIL", + "PIRATERIE", + "NEUSTART", + "GRUPPE", + "OPFERE", + "BETEN", + "SORTIEREN", + "JIHAD", + "GM", + "INFO", + "PRAEFIX", + "PFLANZEN", + "WERWESEN", + "XONTORMIA", + "ALLIANZ", + "BEANSPRUCHEN", + "PROMOTION", + "BEZAHLEN", +}; + +const char *report_options[MAX_MSG] = +{ + "Kampf", + "Ereignisse", + "Bewegung", + "Einkommen", + "Handel", + "Produktion", + "Orkvermehrung", + "Zauber", + "", + "" +}; + +const char *message_levels[ML_MAX] = +{ + "Wichtig", + "Debug", + "Fehler", + "Warnungen", + "Infos" +}; + +const char *options[MAXOPTIONS] = +{ + "AUSWERTUNG", + "COMPUTER", + "ZUGVORLAGE", + NULL, + "STATISTIK", + "DEBUG", + "ZIPPED", + "ZEITUNG", /* Option hat Sonderbehandlung! */ + NULL, + "ADRESSEN", + "BZIP2", + "PUNKTE", + "SHOWSKCHANGE", + "XML" +}; + +static int +allied_skillcount(const faction * f, skill_t sk) +{ + int num = 0; + alliance * a = f_get_alliance(f); + faction_list * members = a->members; + while (members!=NULL) { + num += count_skill(members->data, sk); + members=members->next; + } + return num; +} + +static int +allied_skilllimit(const faction * f, skill_t sk) +{ + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "alliance.skilllimit", 0); + } + return value; +} + +static void +init_maxmagicians(struct attrib *a) +{ + a->data.i = MAXMAGICIANS; +} + +static attrib_type at_maxmagicians = { + "maxmagicians", + init_maxmagicians, + NULL, + NULL, + a_writeint, + a_readint, + ATF_UNIQUE +}; + +static void +init_npcfaction(struct attrib *a) +{ + a->data.i = 1; +} + + +static attrib_type at_npcfaction = { + "npcfaction", + init_npcfaction, + NULL, + NULL, + a_writeint, + a_readint, + ATF_UNIQUE +}; + +int +max_magicians(const faction * f) +{ + int m = MAXMAGICIANS; + attrib * a; + + if ((a = a_find(f->attribs, &at_maxmagicians)) != NULL) { + m = a->data.i; + } + if (f->race == new_race[RC_ELF]) ++m; + return m; +} + +int +skill_limit(faction * f, skill_t sk) +{ + int m = INT_MAX; + int al = allied_skilllimit(f, sk); + if (al>0) { + if (sk!=SK_ALCHEMY && sk!=SK_MAGIC) return INT_MAX; + if (f_get_alliance(f)) { + int ac = listlen(f->alliance->members); /* number of factions */ + int fl = (al+ac-1)/ac; /* faction limit, rounded up */ + /* the faction limit may not be achievable because it would break the alliance-limit */ + int sc = al - allied_skillcount(f, sk); + if (sc<=0) return 0; + return fl; + } + } + switch (sk) { + case SK_MAGIC: + m = max_magicians(f); + break; + case SK_ALCHEMY: + m = MAXALCHEMISTS; + break; + } + return m; +} + +int +count_skill(faction * f, skill_t sk) +{ + int n = 0; + unit *u; + + for (u = f->units; u; u = u->nextF) { + if (has_skill(u, sk)) { + if (!is_familiar(u)) n += u->number; + } + } + return n; +} + +int verbosity = 0; + +FILE *debug; + +static int +ShipSpeedBonus(const unit * u) +{ + static int level = -1; + if (level==-1) { + level = get_param_int(global.parameters, "movement.shipspeed.skillbonus", 0); + } + if (level>0) { + ship * sh = u->ship; + int skl = effskill(u, SK_SAILING); + int minsk = (sh->type->cptskill+1)/2; + return (skl-minsk)/level; + } + return 0; +} + +int +shipspeed(const ship * sh, const unit * u) +{ + double k = sh->type->range; + static const curse_type * stormwind_ct, * nodrift_ct; + static boolean init; + attrib *a; + curse *c; + + if (!init) { + init = true; + stormwind_ct = ct_find("stormwind"); + nodrift_ct = ct_find("nodrift"); + } + + assert(u->ship==sh); + assert(sh->type->construction->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (sh->size!=sh->type->construction->maxsize) return 0; + + if( curse_active(get_curse(sh->attribs, stormwind_ct))) + k *= 2; + if( curse_active(get_curse(sh->attribs, nodrift_ct))) + k += 1; + + if (u->faction->race == u->race) { + /* race bonus for this faction? */ + if (fval(u->race, RCF_SHIPSPEED)) { + k += 1; + } + } + + k += ShipSpeedBonus(u); + + a = a_find(sh->attribs, &at_speedup); + while (a != NULL && a->type==&at_speedup) { + k += a->data.sa[0]; + a = a->next; + } + + c = get_curse(sh->attribs, ct_find("shipspeedup")); + while(c) { + k += curse_geteffect(c); + c = c->nexthash; + } + +#ifdef SHIPSPEED + k *= SHIPSPEED; +#endif + +#ifdef SHIPDAMAGE + if (sh->damage) k = (k * (sh->size * DAMAGE_SCALE - sh->damage) + sh->size * DAMAGE_SCALE- 1) / (sh->size*DAMAGE_SCALE); +#endif + + return (int)k; +} + +#define FMAXHASH 2039 +faction * factionhash[FMAXHASH]; + +void +fhash(faction * f) +{ + int index = f->no % FMAXHASH; + f->nexthash = factionhash[index]; + factionhash[index] = f; +} + +void +funhash(faction * f) +{ + int index = f->no % FMAXHASH; + faction ** fp = factionhash+index; + while (*fp && (*fp)!=f) fp = &(*fp)->nexthash; + *fp = f->nexthash; +} + +static faction * +ffindhash(int no) +{ + int index = no % FMAXHASH; + faction * f = factionhash[index]; + while (f && f->no!=no) f = f->nexthash; + return f; +} +/* ----------------------------------------------------------------------- */ + +void +verify_data(void) +{ +#ifndef NDEBUG + int lf = -1; + faction *f; + unit *u; + int mage, alchemist; + + if (verbosity>=1) puts(" - Überprüfe Daten auf Korrektheit..."); + + list_foreach(faction, factions, f) { + mage = 0; + alchemist = 0; + for (u=f->units;u;u=u->nextF) { + if (eff_skill(u, SK_MAGIC, u->region)) { + mage += u->number; + } + if (eff_skill(u, SK_ALCHEMY, u->region)) + alchemist += u->number; + if (u->number > UNIT_MAXSIZE) { + if (lf != f->no) { + lf = f->no; + log_stdio(stdout, "Partei %s:\n", factionid(f)); + } + log_warning(("Einheit %s hat %d Personen\n", unitid(u), u->number)); + } + } + if (f->no != 0 && ((mage > 3 && f->race != new_race[RC_ELF]) || mage > 4)) + log_error(("Partei %s hat %d Magier.\n", factionid(f), mage)); + if (alchemist > 3) + log_error(("Partei %s hat %d Alchemisten.\n", factionid(f), alchemist)); + } + list_next(f); +#endif +} + +int +distribute(int old, int new_value, int n) +{ + int i; + int t; + assert(new_value <= old); + + if (old == 0) + return 0; + + t = (n / old) * new_value; + for (i = (n % old); i; i--) + if (rng_int() % old < new_value) + t++; + + return t; +} + +int +change_hitpoints (unit * u, int value) +{ + int hp = u->hp; + + hp += value; + + /* Jede Person benötigt mindestens 1 HP */ + if (hp < u->number){ + if (hp < 0){ /* Einheit tot */ + hp = 0; + } + scale_number(u, hp); + } + u->hp = hp; + return hp; +} + +unsigned int +atoip(const char *s) +{ + int n; + + n = atoi (s); + + if (n < 0) + n = 0; + + return n; +} + +region * +findunitregion (const unit * su) +{ +#ifndef SLOW_REGION + return su->region; +#else + region *r; + const unit *u; + + for (r = regions; r; r = r->next) { + for (u = r->units; u; u = u->next) { + if (su == u) { + return r; + } + } + } + + /* This should never happen */ + assert (!"Die unit wurde nicht gefunden"); + + return (region *) NULL; +#endif +} + +int +effskill(const unit * u, skill_t sk) +{ + return eff_skill(u, sk, u->region); +} + +int +eff_stealth(const unit * u, const region * r) +{ + int e = 0; + + /* Auf Schiffen keine Tarnung! */ + if (!u->ship && skill_enabled[SK_STEALTH]) { + e = eff_skill (u, SK_STEALTH, r); + + if (fval(u, UFL_STEALTH)) { + int es = u_geteffstealth(u); + if (es >=0 && es < e) return es; + } + } + return e; +} + +boolean +unit_has_cursed_item(unit *u) +{ + item * itm = u->items; + while (itm) { + if (fval(itm->type, ITF_CURSED) && itm->number>0) return true; + itm=itm->next; + } + return false; +} + +static void +init_gms(void) +{ + faction * f; + + for (f=factions;f;f=f->next) { + const attrib * a = a_findc(f->attribs, &at_gm); + + if (a!=NULL) fset(f, FFL_GM); + } +} + +static int +autoalliance(const plane * pl, const faction * sf, const faction * f2) +{ + static boolean init = false; + if (!init) { + init_gms(); + init = true; + } + if (pl && (pl->flags & PFL_FRIENDLY)) return HELP_ALL; + /* if f2 is a gm in this plane, everyone has an auto-help to it */ + if (fval(f2, FFL_GM)) { + attrib * a = a_find(f2->attribs, &at_gm); + + while (a) { + const plane * p = (const plane*)a->data.v; + if (p==pl) return HELP_ALL; + a=a->next; + } + } + + if (f_get_alliance(sf)!=NULL && AllianceAuto()) { + if (sf->alliance==f2->alliance) return AllianceAuto(); + } + + return 0; +} + +static int +ally_mode(const ally * sf, int mode) +{ + if (sf==NULL) return 0; + return sf->status & mode; +} + +int +alliedgroup(const struct plane * pl, const struct faction * f, + const struct faction * f2, const struct ally * sf, int mode) +{ + while (sf && sf->faction!=f2) sf=sf->next; + if (sf==NULL) { + mode = mode & autoalliance(pl, f, f2); + } + mode = ally_mode(sf, mode) | (mode & autoalliance(pl, f, f2)); + if (AllianceRestricted()) { + if (a_findc(f->attribs, &at_npcfaction)) { + return mode; + } + if (a_findc(f2->attribs, &at_npcfaction)) { + return mode; + } + if (f->alliance!=f2->alliance) { + mode &= ~AllianceRestricted(); + } + } + return mode; +} + +int +alliedfaction(const struct plane * pl, const struct faction * f, + const struct faction * f2, int mode) +{ + return alliedgroup(pl, f, f2, f->allies, mode); +} + +/* Die Gruppe von Einheit u hat helfe zu f2 gesetzt. */ +int +alliedunit(const unit * u, const faction * f2, int mode) +{ + ally * sf; + int automode; + + assert(u->region); /* the unit should be in a region, but it's possible that u->number==0 (TEMP units) */ + if (u->faction == f2) return mode; + if (u->faction != NULL && f2!=NULL) { + plane * pl; + + if (mode&HELP_FIGHT) { + if ((u->flags&UFL_DEFENDER) || (u->faction->flags&FFL_DEFENDER)) { + faction * owner = region_get_owner(u->region); + /* helps the owner of the region */ + if (owner==f2) { + return HELP_FIGHT; + } + } + } + + pl = rplane(u->region); + automode = mode & autoalliance(pl, u->faction, f2); + + if (pl!=NULL && (pl->flags & PFL_NOALLIANCES)) + mode = (mode & automode) | (mode & HELP_GIVE); + + sf = u->faction->allies; + if (fval(u, UFL_GROUP)) { + const attrib * a = a_findc(u->attribs, &at_group); + if (a!=NULL) sf = ((group*)a->data.v)->allies; + } + return alliedgroup(pl, u->faction, f2, sf, mode); + } + return 0; +} + +boolean +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)) + return true; + return false; +} + +boolean +cansee(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 */ +{ + int stealth, rings; + unit *u2 = r->units; + static const item_type * itype_grail; + static boolean init; + + if (!init) { + init = true; + itype_grail = it_find("grail"); + } + + if (u->faction == f || omniscient(f)) { + return true; + } else if (fval(u->race, RCF_INVISIBLE)) { + return false; + } else if (u->number == 0) { + 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. */ + u = (unit *)a->data.v; + } else { + return false; + } + } + + if (leftship(u)) return true; + if (itype_grail!=NULL && i_get(u->items, itype_grail)) 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, GUARD_ALL)!=0 || usiege(u) || u->building || u->ship) { + return true; + } + + rings = invisible(u, NULL); + stealth = eff_stealth(u, r) - modifier; + + while (u2) { + if (ringsnumber || invisible(u, u2) < u->number) { + if (skill_enabled[SK_PERCEPTION]) { + int observation = eff_skill(u2, SK_PERCEPTION, r); + + if (observation >= stealth) { + return true; + } + } else { + return true; + } + } + + /* find next unit in our faction */ + do { + u2=u2->next; + } while (u2 && u2->faction != f); + } + return false; +} + +boolean +cansee_unit(const unit * u, const unit * target, int modifier) +/* target->region kann != u->region sein, wenn es um durchreisen geht */ +{ + if (fval(target->race, RCF_INVISIBLE) || target->number == 0) return false; + else if (target->faction == u->faction) return true; + else { + int n, rings, o; + + if (is_guard(target, GUARD_ALL)!=0 || usiege(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]) { + o = eff_skill(u, SK_PERCEPTION, target->region); + if (o >= n) { + return true; + } + } else { + return true; + } + } + return false; +} + +boolean +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 */ +{ + int n; + unit *u2; + + if (fval(u->race, RCF_INVISIBLE) || u->number == 0) return false; + else if (u->faction == f) return true; + else { + int rings; + + if (is_guard(u, GUARD_ALL)!=0 || usiege(u) || u->building || u->ship) { + return true; + } + + n = eff_stealth(u, r) - modifier; + rings = invisible(u, NULL); + if (rings==0 && n<=0) { + return true; + } + + for (u2 = r->units; u2; u2 = u2->next){ + if (u2->faction == f) { + int o; + + if (rings && invisible(u, u2) >= u->number) continue; + + o = eff_skill(u2, SK_PERCEPTION, r); + + if (o >= n) { + return true; + } + } + } + } + return false; +} + +#ifndef NDEBUG +const char * +strcheck (const char *s, size_t maxlen) +{ + static char buffer[16 * 1024]; + if (strlen(s) > maxlen) { + assert(maxlen < 16 * 1024); + log_warning(("[strcheck] String wurde auf %d Zeichen verkürzt:\n%s\n", + (int)maxlen, s)); + strlcpy(buffer, s, maxlen); + return buffer; + } + return s; +} +#endif + +static attrib_type at_lighthouse = { + "lighthouse" + /* Rest ist NULL; temporäres, nicht alterndes Attribut */ +}; + +/* update_lighthouse: call this function whenever the size of a lighthouse changes + * it adds temporary markers to the surrounding regions. + * The existence of markers says nothing about the quality of the observer in + * the lighthouse, for this may change more frequently. + */ +void +update_lighthouse(building * lh) +{ + static boolean init_lighthouse = false; + static const struct building_type * bt_lighthouse = 0; + + if (!init_lighthouse) { + bt_lighthouse = bt_find("lighthouse"); + if (bt_lighthouse==NULL) return; + init_lighthouse = true; + } + + if (lh->type==bt_lighthouse) { + region * r = lh->region; + int d = (int)log10(lh->size) + 1; + int x; + + if (lh->size>0) { + r->flags |= RF_LIGHTHOUSE; + } + + for (x=-d;x<=d;++x) { + int y; + for (y=-d;y<=d;++y) { + attrib * a; + region * r2; + int px = r->x+x, py = r->y+y; + pnormalize(&px, &py, rplane(r)); + r2 = findregion(px, py); + if (r2==NULL) continue; + if (!fval(r2->terrain, SEA_REGION)) continue; + if (distance(r, r2) > d) continue; + a = a_find(r2->attribs, &at_lighthouse); + while (a && a->type==&at_lighthouse) { + building * b = (building*)a->data.v; + if (b==lh) break; + a = a->next; + } + if (!a) { + a = a_add(&r2->attribs, a_new(&at_lighthouse)); + a->data.v = (void*)lh; + } + } + } + } +} + +int +count_all(const faction * f) +{ +#ifndef NDEBUG + int n = 0; + unit *u; + for (u=f->units;u;u=u->nextF) { + if (playerrace(u->race)) { + n += u->number; + assert(f==u->faction); + } + } + if (f->num_people != n) { + log_error(("# of people in %s is != num_people: %d should be %d.\n", + factionid(f), f->num_people, n)); + } +#endif + return f->num_people; +} + +int +count_migrants (const faction * f) +{ + unit *u = f->units; + int n = 0; + while (u) { + assert(u->faction == f); + if (u->race != f->race && u->race != new_race[RC_ILLUSION] && u->race != new_race[RC_SPELL] + && !!playerrace(u->race) && !(is_cursed(u->attribs, C_SLAVE, 0))) + { + n += u->number; + } + u = u->nextF; + } + return n; +} + +int +count_maxmigrants(const faction * f) +{ + static int migrants = -1; + + if (migrants<0) { + migrants = get_param_int(global.parameters, "rules.migrants", INT_MAX); + } + if (migrants==INT_MAX) { + int x = 0; + if (f->race == new_race[RC_HUMAN]) { + int nsize = count_all(f); + if (nsize>0) { + x = (int)(log10(nsize / 50.0) * 20); + if (x < 0) x = 0; + } + } + return x; + } + return migrants; +} + +void +init_tokens(const struct order * ord) +{ + char * cmd = getcommand(ord); + init_tokens_str(cmd, cmd); +} + +void +parse(keyword_t kword, int (*dofun)(unit *, struct order *), boolean thisorder) +{ + region *r; + + for (r = regions; r; r = r->next) { + unit **up = &r->units; + while (*up) { + unit * u = *up; + order ** ordp = &u->orders; + if (thisorder) ordp = &u->thisorder; + while (*ordp) { + order * ord = *ordp; + if (get_keyword(ord) == kword) { + if (dofun(u, ord)!=0) break; + if (u->orders==NULL) break; + } + if (thisorder) break; + if (*ordp==ord) ordp=&ord->next; + } + if (*up==u) up=&u->next; + } + } +} + +const char * +igetstrtoken(const char * initstr) +{ + if (initstr!=NULL) { + init_tokens_str(initstr, NULL); + } + + return getstrtoken(); +} + +unsigned int +getuint (void) +{ + return atoip((const char *)getstrtoken()); +} + +int +getint (void) +{ + return atoi((const char *)getstrtoken()); +} + +const struct race * +findrace(const char * s, const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_RACES); + variant token; + + assert(lang); + if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { + return (const struct race *)token.v; + } + return NULL; +} + +int +findoption(const char *s, const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_OPTIONS); + variant token; + + if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { + return (direction_t)token.i; + } + return NODIRECTION; +} + +#if PTRIES +static struct trie_node * ptries[UT_MAX][4]; + +static struct trie_node ** +get_ptrie(const struct locale * lang, int type) +{ + int index = (strcmp(locale_name(lang), "de")==0); + return &(ptries[type][index]); +} + +static int +umlaut_substitution(const char * ip, char * op, size_t outlen) +{ +#define UMAX 7 + static struct replace { + ucs4_t ucs; + const char str[3]; + } replace[UMAX] = { + /* match lower-case (!) umlauts and others to transcriptions */ + { 223, "ss"}, /* szlig */ + { 228, "ae"}, /* auml */ + { 229, "aa"}, /* norsk */ + { 230, "ae"}, /* norsk */ + { 246, "oe"}, /* ouml */ + { 248, "oe"}, /* norsk */ + { 252, "ue"}, /* uuml */ + }; + int subs = 0; + while (*ip) { + ucs4_t ucs = *ip; + size_t size = 1; + size_t cpsize = 1; + + if (ucs & 0x80) { + int ret = unicode_utf8_to_ucs4(&ucs, ip, &size); + if (ret!=0) { + return ret; + } + cpsize = size; + if (ucs >= replace[0].ucs && ucs <= replace[UMAX-1].ucs) { + int i; + for (i=0;i!=UMAX;++i) { + if (replace[i].ucs==ucs) { + cpsize = 0; + memcpy(op, replace[i].str, 2); + op+=2; + ++subs; + break; + } + } + } + } + if (cpsize) { + if (cpsize>outlen) { + return -1; + } + memcpy(op, ip, cpsize); + } + + ip += size; + op += cpsize; + outlen -= cpsize; + } + + if (outlen<=0) { + return -1; + } + *op = 0; + return subs; +} + +static int +ptrie_find(struct trie_node *ptrie, const char * key, void * data, size_t size) +{ + trie_node * node = trie_find_prefix(ptrie, key); + if (node) { + void * result = trie_getdata(node); + memcpy(data, result, size); + return 0; + } + return -1; +} + +static int +ptrie_insert(struct trie_node **ptrie, const char * name, void * data, size_t size) +{ + char converted[256]; + char simple[256]; + int ret = unicode_utf8_tolower(converted, 256, name); + if (ret==0) { + int subs = umlaut_substitution(converted, simple, sizeof(simple)); + if (subs>0) { + trie_insert(ptrie, simple, data, size); + } + trie_insert(ptrie, converted, data, size); + } + return ret; +} +#endif + +skill_t +findskill(const char *s, const struct locale * lang) +{ +#if PTRIES + char lowercase[256]; + int res = unicode_utf8_tolower(lowercase, sizeof(lowercase), s); + if (res==0) { + trie_node ** ptrie = get_ptrie(lang, UT_SKILLS); + skill_t sk; + int result = ptrie_find(*ptrie, lowercase, &sk, sizeof(sk)); + if (result==0) return sk; + } + return NOSKILL; +#else + struct tnode * tokens = get_translations(lang, UT_SKILLS); + variant token; + + if (findtoken(tokens, s, &token)==E_TOK_NOMATCH) return NOSKILL; + return (skill_t)token.i; +#endif +} + +keyword_t +findkeyword(const char *s, const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_KEYWORDS); + variant token; + + if (*s == '@') s++; + if (findtoken(tokens, s, &token)==E_TOK_NOMATCH) return NOKEYWORD; + if (global.disabled[token.i]) return NOKEYWORD; + return (keyword_t) token.i; +} + +param_t +findparam(const char *s, const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_PARAMS); + variant token; + + if (findtoken(tokens, s, &token)==E_TOK_NOMATCH) { + const building_type * btype = findbuildingtype(s, lang); + if (btype!=NULL) return (param_t) P_GEBAEUDE; + return NOPARAM; + } + if (token.i==P_BUILDING) return P_GEBAEUDE; + return (param_t)token.i; +} + +param_t +getparam (const struct locale * lang) +{ + return findparam (getstrtoken (), lang); +} + +faction * +findfaction (int n) +{ + faction * f = ffindhash(n); + return f; +} + +faction * +getfaction (void) +{ + return findfaction (getid()); +} + +unit * +findunitr (const region * r, int n) +{ + unit *u; + + /* findunit regional! */ + + for (u = r->units; u; u = u->next) + if (u->no == n) + return u; + + return 0; +} + +unit *findunit(int n) +{ + if (n <= 0) { + return NULL; + } + return ufindhash(n); +} + +unit * +findunitg (int n, const region * hint) +{ + + /* Abfangen von Syntaxfehlern. */ + if (n <= 0) + return NULL; + + /* findunit global! */ + hint = 0; + return ufindhash(n); +} + +unit * +getnewunit (const region * r, const faction * f) +{ + int n; + n = getid(); + + return findnewunit (r, f, n); +} + +static int +read_newunitid (const faction * f, const region * r) +{ + int n; + unit *u2; + n = getid(); + if (n == 0) + return -1; + + u2 = findnewunit(r, f, n); + if (u2) return u2->no; + + return -1; +} + +int +read_unitid (const faction * f, const region * r) +{ + const char * s = getstrtoken(); + + /* Da s nun nur einen string enthaelt, suchen wir ihn direkt in der + * paramliste. machen wir das nicht, dann wird getnewunit in s nach der + * nummer suchen, doch dort steht bei temp-units nur "temp" drinnen! */ + + switch (findparam(s, f->locale)) { + case P_TEMP: + return read_newunitid(f, r); + } + if (!s || *s == 0) + return -1; + return atoi36((const char *)s); +} + +/* exported symbol */ +boolean getunitpeasants; +unit * +getunitg(const region * r, const faction * f) +{ + int n = read_unitid(f, r); + + if (n == 0) { + getunitpeasants = 1; + return NULL; + } + getunitpeasants = 0; + if (n < 0) return 0; + + return findunit(n); +} + +unit * +getunit(const region * r, const faction * f) +{ + int n = read_unitid(f, r); + unit *u2; + + if (n == 0) { + getunitpeasants = 1; + return NULL; + } + getunitpeasants = 0; + if (n < 0) return 0; + + u2 = findunit(n); + if (u2!=NULL && u2->region==r) { + /* there used to be a 'u2->flags & UFL_ISNEW || u2->number>0' condition + * here, but it got removed because of a bug that made units disappear: + * http://eressea.upb.de/mantis/bug_view_page.php?bug_id=0000172 + */ + return u2; + } + + return NULL; +} + +/* - String Listen --------------------------------------------- */ +void +addstrlist (strlist ** SP, const char *s) +{ + strlist * slist = malloc(sizeof(strlist)); + slist->next = NULL; + slist->s = strdup(s); + addlist(SP, slist); +} + +void +freestrlist (strlist * s) +{ + strlist *q, *p = s; + while (p) { + q = p->next; + free(p->s); + free(p); + p = q; + } +} + +/* - Meldungen und Fehler ------------------------------------------------- */ + +boolean lomem = false; + +/* - Namen der Strukturen -------------------------------------- */ +typedef char name[OBJECTIDSIZE+1]; +static name idbuf[8]; +static int nextbuf = 0; + +char * +estring_i(char *ibuf) +{ + char *p = ibuf; + + while (*p) { + if (isxspace(*(unsigned*)p) == ' ') { + *p = '~'; + } + ++p; + } + return ibuf; +} + +char * +estring(const char *s) +{ + char *ibuf = idbuf[(++nextbuf) % 8]; + + strlcpy(ibuf, s, sizeof(name)); + return estring_i(ibuf); +} + +char * +cstring_i(char *ibuf) +{ + char *p = ibuf; + + while (*p) { + if (*p == '~') { + *p = ' '; + } + ++p; + } + return ibuf; +} + +char * +cstring(const char *s) +{ + char *ibuf = idbuf[(++nextbuf) % 8]; + + strlcpy(ibuf, s, sizeof(name)); + return cstring_i(ibuf); +} + +building * +largestbuilding(const region * r, cmp_building_cb cmp_gt, boolean imaginary) +{ + building *b, *best = NULL; + + for (b = rbuildings(r); b; b = b->next) { + if (cmp_gt(b, best)<=0) continue; + if (!imaginary) { + const attrib * a = a_find(b->attribs, &at_icastle); + if (a) continue; + } + best = b; + } + return best; +} + +char * +write_unitname(const unit * u, char * buffer, size_t size) +{ + snprintf((char*)buffer, size, "%s (%s)", (const char*)u->name, itoa36(u->no)); + buffer[size-1] = 0; + return buffer; +} + +const char * +unitname(const unit * u) +{ + char *ubuf = idbuf[(++nextbuf) % 8]; + return write_unitname(u, ubuf, sizeof(name)); +} + +/* -- Erschaffung neuer Einheiten ------------------------------ */ + +extern faction * dfindhash(int i); + +static const char* forbidden[] = { "t", "te", "tem", "temp", NULL }; + +int +forbiddenid(int id) +{ + static int * forbid = NULL; + static size_t len; + size_t i; + if (id<=0) return 1; + if (!forbid) { + while (forbidden[len]) ++len; + forbid = calloc(len, sizeof(int)); + for (i=0;i!=len;++i) { + forbid[i] = strtol(forbidden[i], NULL, 36); + } + } + for (i=0;i!=len;++i) if (id==forbid[i]) return 1; + return 0; +} + +/* ID's für Einheiten und Zauber */ +int +newunitid(void) +{ + int random_unit_no; + int start_random_no; + random_unit_no = 1 + (rng_int() % MAX_UNIT_NR); + start_random_no = random_unit_no; + + while (ufindhash(random_unit_no) || dfindhash(random_unit_no) + || cfindhash(random_unit_no) + || forbiddenid(random_unit_no)) + { + random_unit_no++; + if (random_unit_no == MAX_UNIT_NR + 1) { + random_unit_no = 1; + } + if (random_unit_no == start_random_no) { + random_unit_no = (int) MAX_UNIT_NR + 1; + } + } + return random_unit_no; +} + +int +newcontainerid(void) +{ + int random_no; + int start_random_no; + + random_no = 1 + (rng_int() % MAX_CONTAINER_NR); + start_random_no = random_no; + + while (findship(random_no) || findbuilding(random_no)) { + random_no++; + if (random_no == MAX_CONTAINER_NR + 1) { + random_no = 1; + } + if (random_no == start_random_no) { + random_no = (int) MAX_CONTAINER_NR + 1; + } + } + return random_no; +} + +unit * +createunit(region * r, faction * f, int number, const struct race * rc) +{ + assert(rc); + return create_unit(r, f, number, rc, 0, NULL, NULL); +} + +boolean +idle (faction * f) +{ + return (boolean) (f ? false : true); +} + + +int +maxworkingpeasants(const struct region * r) +{ + int i = production(r) * MAXPEASANTS_PER_AREA + - ((rtrees(r,2)+rtrees(r,1)/2) * TREESIZE); + return MAX(i, 0); +} + +int +lighthouse_range(const building * b, const faction * f) +{ + int d = 0; + if (fval(b, BLD_WORKING) && b->size >= 10) { + int maxd = (int)log10(b->size) + 1; + + if (skill_enabled[SK_PERCEPTION]) { + region * r = b->region; + int c = 0; + unit *u; + for (u = r->units; u; u = u->next) { + if (u->building == b) { + c += u->number; + if (c > buildingcapacity(b)) break; + if (f==NULL || u->faction == f) { + int sk = eff_skill(u, SK_PERCEPTION, r) / 3; + d = MAX(d, sk); + d = MIN(maxd, d); + if (d==maxd) break; + } + } else if (c) break; /* first unit that's no longer in the house ends the search */ + } + } else { + /* E3A rule: no perception req'd */ + return maxd; + } + } + return d; +} + +boolean +check_leuchtturm(region * r, faction * f) +{ + attrib * a; + + if (!fval(r->terrain, SEA_REGION)) return false; + + for (a = a_find(r->attribs, &at_lighthouse);a && a->type==&at_lighthouse;a=a->next) { + building *b = (building *)a->data.v; + + assert(b->type == bt_find("lighthouse")); + if (fval(b, BLD_WORKING) && b->size >= 10) { + int maxd = (int)log10(b->size) + 1; + + if (skill_enabled[SK_PERCEPTION]) { + region *r2 = b->region; + unit *u; + int c = 0; + int d = 0; + + for (u = r2->units; u; u = u->next) { + if (u->building == b) { + c += u->number; + if (c > buildingcapacity(b)) break; + if (f==NULL || u->faction == f) { + if (!d) d = distance(r, r2); + if (maxd < d) break; + if (eff_skill(u, SK_PERCEPTION, r) >= d * 3) return true; + } + } else if (c) break; /* first unit that's no longer in the house ends the search */ + } + } else { + /* E3A rule: no perception req'd */ + return maxd; + } + } + } + + return false; +} + +region * +lastregion (faction * f) +{ +#ifdef SMART_INTERVALS + unit * u = f->units; + region *r = f->last; + + if (u==NULL) return NULL; + if (r!=NULL) return r->next; + + /* it is safe to start in the region of the first unit. */ + f->last = u->region; + /* if regions have indices, we can skip ahead: */ + for (u=u->nextF; u!=NULL; u=u->nextF) { + r = u->region; + if (r->index > f->last->index) f->last = r; + } + + /* we continue from the best region and look for travelthru etc. */ + for (r = f->last->next; r; r = r->next) { + plane * p = rplane(r); + + /* search the region for travelthru-attributes: */ + if (fval(r, RF_TRAVELUNIT)) { + attrib * ru = a_find(r->attribs, &at_travelunit); + while (ru && ru->type==&at_travelunit) { + u = (unit*)ru->data.v; + if (u->faction == f) { + f->last = r; + break; + } + ru = ru->next; + } + } + if (f->last == r) continue; + if (check_leuchtturm(r, f)) + f->last = r; + if (p && is_watcher(p, f)) { + f->last = r; + } + } + return f->last->next; +#else + return NULL; +#endif +} + +region * +firstregion (faction * f) +{ +#ifdef SMART_INTERVALS + region *r = f->first; + + if (f->units==NULL) return NULL; + if (r!=NULL) return r; + + return f->first = regions; +#else + return regions; +#endif +} + +void ** blk_list[1024]; +int list_index; +int blk_index; + +static void +gc_done(void) +{ + int i, k; + for (i=0;i!=list_index;++i) + { + for (k=0;k!=1024;++k) free(blk_list[i][k]); + free(blk_list[i]); + } + for (k=0;k!=blk_index;++k) free(blk_list[list_index][k]); + free(blk_list[list_index]); + +} + +void * +gc_add(void * p) +{ + if (blk_index==0) { + blk_list[list_index] = (void**)malloc(1024 * sizeof(void*)); + } + blk_list[list_index][blk_index] = p; + blk_index = (blk_index+1) % 1024; + if (!blk_index) ++ list_index; + return p; +} + +static void +init_directions(tnode * root, const struct locale * lang) +{ + /* mit dieser routine kann man mehrere namen für eine direction geben, + * das ist für die hexes ideal. */ + const struct { + const char* name; + int direction; + } dirs [] = { + { "dir_ne", D_NORTHEAST}, + { "dir_nw", D_NORTHWEST}, + { "dir_se", D_SOUTHEAST}, + { "dir_sw", D_SOUTHWEST}, + { "dir_east", D_EAST}, + { "dir_west", D_WEST}, + { "northeast", D_NORTHEAST}, + { "northwest", D_NORTHWEST}, + { "southeast", D_SOUTHEAST}, + { "southwest", D_SOUTHWEST}, + { "east", D_EAST }, + { "west",D_WEST }, + { "PAUSE", D_PAUSE }, + { NULL, NODIRECTION} + }; + int i; + struct tnode * tokens = get_translations(lang, UT_DIRECTIONS); + + for (i=0; dirs[i].direction!=NODIRECTION;++i) { + variant token; + token.i = dirs[i].direction; + addtoken(tokens, LOC(lang, dirs[i].name), token); + } +} + +direction_t +finddirection(const char *s, const struct locale * lang) +{ + struct tnode * tokens = get_translations(lang, UT_DIRECTIONS); + variant token; + + if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { + return (direction_t)token.i; + } + return NODIRECTION; +} + +static void +init_locale(const struct locale * lang) +{ + variant var; + int i; + const struct race * rc; + struct tnode * tokens; + const terrain_type * terrain; +#if PTRIES + trie_node ** ptrie; +#endif + + tokens = get_translations(lang, UT_MAGIC); + if (tokens) { + const char * str = get_param(global.parameters, "rules.magic.playerschools"); + char * sstr, * tok; + if (str==NULL) { + str = "gwyrrd illaun draig cerddor tybied"; + } + + sstr = strdup(str); + tok = strtok(sstr, " "); + while (tok) { + for (i=0;i!=MAXMAGIETYP;++i) { + if (strcmp(tok, magic_school[i])==0) break; + } + assert(i!=MAXMAGIETYP); + var.i = i; + addtoken(tokens, LOC(lang, mkname("school", tok)), var); + tok = strtok(NULL, " "); + } + free(sstr); + } + + tokens = get_translations(lang, UT_DIRECTIONS); + init_directions(tokens, lang); + + tokens = get_translations(lang, UT_RACES); + for (rc=races;rc;rc=rc->next) { + var.v = (void*)rc; + addtoken(tokens, LOC(lang, rc_name(rc, 1)), var); + addtoken(tokens, LOC(lang, rc_name(rc, 0)), var); + } + + tokens = get_translations(lang, UT_PARAMS); + for (i=0;i!=MAXPARAMS;++i) { + var.i = i; + addtoken(tokens, LOC(lang, parameters[i]), var); + } +#if PTRIES + ptrie = get_ptrie(lang, UT_SKILLS); + for (i=0;i!=MAXSKILLS;++i) { + skill_t sk = (skill_t)i; + const char * skname = skillname(sk, lang); + if (skname!=NULL) { + ptrie_insert(ptrie, skname, &sk, sizeof(sk)); + } + } +#else + tokens = get_translations(lang, UT_SKILLS); + for (i=0;i!=MAXSKILLS;++i) { + const char * skname = skillname((skill_t)i, lang); + if (skname!=NULL) { + var.i = i; + addtoken(tokens, skname, var); + } + } +#endif + + tokens = get_translations(lang, UT_KEYWORDS); + for (i=0;i!=MAXKEYWORDS;++i) { + var.i = i; + if (keywords[i]) addtoken(tokens, LOC(lang, keywords[i]), var); + } + + tokens = get_translations(lang, UT_OPTIONS); + for (i=0;i!=MAXOPTIONS;++i) { + var.i = i; + if (options[i]) addtoken(tokens, LOC(lang, options[i]), var); + } + + tokens = get_translations(lang, UT_TERRAINS); + for (terrain=terrains();terrain!=NULL;terrain=terrain->next) { + var.v = (void*)terrain; + addtoken(tokens, LOC(lang, terrain->_name), var); + } +} + +typedef struct param { + struct param * next; + char * name; + char * data; +} param; + +int +getid(void) +{ + const char * str = (const char *)getstrtoken(); + int i = atoi36(str); + if (i<0) { + return -1; + } + return i; +} + +const char * +get_param(const struct param * p, const char * key) +{ + while (p!=NULL) { + if (strcmp(p->name, key)==0) return p->data; + p = p->next; + } + return NULL; +} + +int +get_param_int(const struct param * p, const char * key, int def) +{ + while (p!=NULL) { + if (strcmp(p->name, key)==0) return atoi(p->data); + p = p->next; + } + return def; +} + +static const char * g_datadir; +const char * +datapath(void) +{ + static char zText[MAX_PATH]; + if (g_datadir) return g_datadir; + return strcat(strcpy(zText, basepath()), "/data"); +} + +void +set_datapath(const char * path) +{ + g_datadir = path; +} + + +static const char * g_reportdir; +const char * +reportpath(void) +{ + static char zText[MAX_PATH]; + if (g_reportdir) return g_reportdir; + return strcat(strcpy(zText, basepath()), "/reports"); +} + +void +set_reportpath(const char * path) +{ + g_reportdir = path; +} + +static const char * g_basedir; +const char * +basepath(void) +{ + if (g_basedir) return g_basedir; + return "."; +} + + +void +set_basepath(const char * path) +{ + g_basedir = path; +} + +float +get_param_flt(const struct param * p, const char * key, float def) +{ + while (p!=NULL) { + if (strcmp(p->name, key)==0) return (float)atof(p->data); + p = p->next; + } + return def; +} + +void +set_param(struct param ** p, const char * key, const char * data) +{ + ++global.cookie; + while (*p!=NULL) { + if (strcmp((*p)->name, key)==0) { + free((*p)->data); + (*p)->data = strdup(data); + return; + } + p=&(*p)->next; + } + *p = malloc(sizeof(param)); + (*p)->name = strdup(key); + (*p)->data = strdup(data); + (*p)->next = NULL; +} + +void +kernel_done(void) +{ + /* calling this function releases memory assigned to static variables, etc. + * calling it is optional, e.g. a release server will most likely not do it. + */ + translation_done(); + gc_done(); + sql_done(); +} + +const char * localenames[] = { + "de", "en", + NULL +}; + +void +init_locales(void) +{ + int l; + for (l=0;localenames[l];++l) { + const struct locale * lang = find_locale(localenames[l]); + if (lang) init_locale(lang); + } +} + +/* TODO: soll hier weg */ +extern struct attrib_type at_shiptrail; + +attrib_type at_germs = { + "germs", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + a_writeshorts, + a_readshorts, + ATF_UNIQUE +}; + +/*********************/ +/* at_guard */ +/*********************/ +attrib_type at_guard = { + "guard", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + a_writeint, + a_readint, + ATF_UNIQUE +}; + +void +setstatus(struct unit * u, int status) +{ + assert(status>=ST_AGGRO && status<=ST_FLEE); + if (u->status!=status) { + u->status = (status_t)status; + } +} + +void +setguard(unit * u, unsigned int flags) +{ + /* setzt die guard-flags der Einheit */ + attrib * a = NULL; + assert(flags==0 || !fval(u, UFL_MOVED)); + assert(flags==0 || u->statusattribs, &at_guard); + } + if (flags == GUARD_NONE) { + freset(u, UFL_GUARD); + if (a) a_remove(&u->attribs, a); + return; + } + fset(u, UFL_GUARD); + fset(u->region, RF_GUARDED); + if ((int)flags==guard_flags(u)) { + if (a) a_remove(&u->attribs, a); + } else { + if (!a) a = a_add(&u->attribs, a_new(&at_guard)); + a->data.i = (int)flags; + } +} + +unsigned int +getguard(const unit * u) +{ + attrib * a; + + assert((u->building && fval(u, UFL_OWNER)) || fval(u, UFL_GUARD) || !"you're doing it wrong! check is_guard first"); + a = a_find(u->attribs, &at_guard); + if (a) { + return (unsigned int)a->data.i; + } + return guard_flags(u); +} + +#ifndef HAVE_STRDUP +char * +strdup(const char *s) +{ + return strcpy((char*)malloc(sizeof(char)*(strlen(s)+1)), s); +} +#endif + +void +remove_empty_factions(void) +{ + faction **fp, *f3; + + for (fp = &factions; *fp;) { + faction * f = *fp; + /* monster (0) werden nicht entfernt. alive kann beim readgame + * () auf 0 gesetzt werden, wenn monsters keine einheiten mehr + * haben. */ + if ((f->units==NULL || f->alive == 0) && !is_monsters(f)) { + ursprung * ur = f->ursprung; + while (ur && ur->id!=0) ur=ur->next; + if (verbosity>=2) log_stdio(stdout, "\t%s\n", factionname(f)); + + /* Einfach in eine Datei schreiben und später vermailen */ + + if (updatelog) fprintf(updatelog, "dropout %s\n", itoa36(f->no)); + + for (f3 = factions; f3; f3 = f3->next) { + ally * sf; + group * g; + ally ** sfp = &f3->allies; + while (*sfp) { + sf = *sfp; + if (sf->faction == f || sf->faction == NULL) { + *sfp = sf->next; + free(sf); + } + else sfp = &(*sfp)->next; + } + for (g = f3->groups; g; g=g->next) { + sfp = &g->allies; + while (*sfp) { + sf = *sfp; + if (sf->faction == f || sf->faction == NULL) { + *sfp = sf->next; + free(sf); + } + else sfp = &(*sfp)->next; + } + } + } + if (f->subscription) { + sql_print(("UPDATE subscriptions set status='DEAD' where id=%u;\n", + f->subscription)); + } + + *fp = f->next; + funhash(f); + free_faction(f); + free(f); + } + else fp = &(*fp)->next; + } +} + +void +remove_empty_units_in_region(region *r) +{ + unit **up = &r->units; + + while (*up) { + unit * u = *up; + + if (u->number) { + faction * f = u->faction; + if (f==NULL || !f->alive) { + set_number(u, 0); + } + if (MaxAge()>0) { + if ((!fval(f, FFL_NOTIMEOUT) && f->age > MaxAge())) { + set_number(u, 0); + } + } + } + if ((u->number == 0 && u->race != new_race[RC_SPELL]) || (u->age <= 0 && u->race == new_race[RC_SPELL])) { + remove_unit(up, u); + } + if (*up==u) up=&u->next; + } +} + +void +remove_empty_units(void) +{ + region *r; + + for (r = regions; r; r = r->next) { + remove_empty_units_in_region(r); + } +} + +boolean +faction_id_is_unused(int id) +{ + return findfaction(id)==NULL; +} + +int +weight(const unit * u) +{ + int w, n = 0, in_bag = 0; + + item * itm; + for (itm=u->items;itm;itm=itm->next) { + w = itm->type->weight * itm->number; + n += w; + if( !fval(itm->type, ITF_BIG)) + in_bag += w; + } + + n += u->number * u->race->weight; + + w = get_item(u, I_BAG_OF_HOLDING) * BAGCAPACITY; + if( w > in_bag ) + w = in_bag; + n -= w; + + return n; +} + +void +make_undead_unit(unit * u) +{ + free_orders(&u->orders); + name_unit(u); + fset(u, UFL_ISNEW); +} + +unsigned int guard_flags(const unit * u) +{ + unsigned int flags = GUARD_CREWS | GUARD_LANDING | GUARD_TRAVELTHRU | GUARD_TAX; +#if GUARD_DISABLES_PRODUCTION == 1 + flags |= GUARD_PRODUCE; +#endif +#if GUARD_DISABLES_RECRUIT == 1 + flags |= GUARD_RECRUIT; +#endif + switch (old_race(u->race)) { + case RC_ELF: + if (u->faction->race != u->race) break; + /* else fallthrough */ + case RC_TREEMAN: + flags |= GUARD_TREES; + break; + case RC_IRONKEEPER: + flags = GUARD_MINING; + break; + } + return flags; +} + +void +guard(unit * u, unsigned int mask) +{ + unsigned int flags = guard_flags(u); + setguard(u, flags & mask); +} + +int +besieged(const unit * u) +{ + /* belagert kann man in schiffen und burgen werden */ + return (u && !global.disabled[K_BESIEGE] + && u->building && u->building->besieged + && u->building->besieged >= u->building->size * SIEGEFACTOR); +} + +int +lifestyle(const unit * u) +{ + int need; + plane * pl; + static int gamecookie = -1; + if (gamecookie!=global.cookie) { + gamecookie = global.cookie; + } + + if (is_monsters(u->faction)) return 0; + + need = maintenance_cost(u); + + pl = rplane(u->region); + if (pl && fval(pl, PFL_NOFEED)) + return 0; + + return need; +} + +boolean has_horses(const struct unit * u) +{ + item * itm = u->items; + for (;itm;itm=itm->next) { + if (itm->type->flags&ITF_ANIMAL) return true; + } + return false; +} + +boolean +hunger(int number, unit * u) +{ + region * r = u->region; + int dead = 0, hpsub = 0; + int hp = u->hp / u->number; + static const char * damage = 0; + static const char * rcdamage = 0; + static const race * rc = 0; + + if (!damage) { + damage = get_param(global.parameters, "hunger.damage"); + if (damage==NULL) damage = "1d12+12"; + } + if (rc!=u->race) { + rcdamage = get_param(u->race->parameters, "hunger.damage"); + rc = u->race; + } + + while (number--) { + int dam = dice_rand(rcdamage?rcdamage:damage); + if (dam >= hp) { + ++dead; + } else { + hpsub += dam; + } + } + + if (dead) { + /* Gestorbene aus der Einheit nehmen, + * Sie bekommen keine Beerdingung. */ + ADDMSG(&u->faction->msgs, msg_message("starvation", + "unit region dead live", u, r, dead, u->number-dead)); + + scale_number(u, u->number - dead); + deathcounts(r, dead); + } + if (hpsub > 0) { + /* Jetzt die Schäden der nicht gestorbenen abziehen. */ + u->hp -= hpsub; + /* Meldung nur, wenn noch keine für Tote generiert. */ + if (dead == 0) { + /* Durch unzureichende Ernährung wird %s geschwächt */ + ADDMSG(&u->faction->msgs, msg_message("malnourish", + "unit region", u, r)); + } + } + return (dead || hpsub); +} + +void +plagues(region * r, boolean ismagic) +{ + int peasants; + int i; + int dead = 0; + + /* Seuchenwahrscheinlichkeit in % */ + + if (!ismagic) { + double mwp = MAX(maxworkingpeasants(r), 1); + double prob = pow(rpeasants(r) / (mwp * wage(r, NULL, NULL, turn) * 0.13), 4.0) + * PLAGUE_CHANCE; + + if (rng_double() >= prob) return; + } + + peasants = rpeasants(r); + dead = (int)(0.5F + PLAGUE_VICTIMS * peasants); + for (i = dead; i != 0; i--) { + if (rng_double() < PLAGUE_HEALCHANCE && rmoney(r) >= PLAGUE_HEALCOST) { + rsetmoney(r, rmoney(r) - PLAGUE_HEALCOST); + } else { + --dead; + } + } + + if (dead > 0) { + message * msg = add_message(&r->msgs, msg_message("pest", "dead", dead)); + msg_release(msg); + deathcounts(r, dead); + rsetpeasants(r, peasants - dead); + } +} + +/* Lohn bei den einzelnen Burgstufen für Normale Typen, Orks, Bauern, + * Modifikation für Städter. */ + +static const int wagetable[7][4] = { + {10, 10, 11, -7}, /* Baustelle */ + {10, 10, 11, -5}, /* Handelsposten */ + {11, 11, 12, -3}, /* Befestigung */ + {12, 11, 13, -1}, /* Turm */ + {13, 12, 14, 0}, /* Burg */ + {14, 12, 15, 1}, /* Festung */ + {15, 13, 16, 2} /* Zitadelle */ +}; + +int +cmp_wage(const struct building * b, const building * a) +{ + static const struct building_type * bt_castle; + if (!bt_castle) bt_castle = bt_find("castle"); + if (b->type==bt_castle) { + if (!a) return 1; + if (b->size>a->size) return 1; + if (b->size==a->size) return 0; + } + return -1; +} + +boolean is_owner_building(const struct building * b) +{ + region * r = b->region; + if (b->type->taxes && r->land && r->land->ownership) { + unit * u = building_owner(b); + return u && u->faction == r->land->ownership->owner; + } + return false; +} + +int +cmp_taxes(const building * b, const building * a) +{ + faction * f = region_get_owner(b->region); + if (b->type->taxes) { + unit * u = building_owner(b); + if (!u) { + return -1; + } else if (a) { + int newsize = buildingeffsize(b, false); + double newtaxes = b->type->taxes(b, newsize); + int oldsize = buildingeffsize(a, false); + double oldtaxes = a->type->taxes(a, oldsize); + + if (newtaxesoldtaxes) return 1; + else if (b->sizesize) return -1; + else if (b->size>a->size) return 1; + else { + if (u && u->faction==f) { + u = building_owner(a); + if (u && u->faction==f) return -1; + return 1; + } + } + } else { + return 1; + } + } + return -1; +} + +int +cmp_current_owner(const building * b, const building * a) +{ + faction * f = region_get_owner(b->region); + + assert(rule_region_owners()); + if (f && b->type->taxes) { + unit * u = building_owner(b); + if (!u || u->faction!=f) return -1; + if (a) { + int newsize = buildingeffsize(b, false); + double newtaxes = b->type->taxes(b, newsize); + int oldsize = buildingeffsize(a, false); + double oldtaxes = a->type->taxes(a, oldsize); + + if (newtaxes!=oldtaxes) return (newtaxes>oldtaxes)?1:-1; + if (newsize!=oldsize) return newsize-oldsize; + return (b->size-a->size); + } else { + return 1; + } + } + return -1; +} + +int rule_stealth_faction(void) +{ + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + rule = get_param_int(global.parameters, "rules.stealth.faction", 1); + gamecookie = global.cookie; + assert(rule>=0); + } + return rule; +} + +int rule_region_owners(void) +{ + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + rule = get_param_int(global.parameters, "rules.region_owners", 0); + gamecookie = global.cookie; + assert(rule>=0); + } + return rule; +} + +int rule_auto_taxation(void) +{ + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + rule = get_param_int(global.parameters, "rules.economy.taxation", TAX_ORDER); + gamecookie = global.cookie; + assert(rule>=0); + } + return rule; +} + +int rule_blessed_harvest(void) +{ + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + rule = get_param_int(global.parameters, "rules.magic.blessed_harvest", HARVEST_WORK); + gamecookie = global.cookie; + assert(rule>=0); + } + return rule; +} + +int rule_alliance_limit(void) +{ + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + rule = get_param_int(global.parameters, "rules.limit.alliance", 0); + gamecookie = global.cookie; + assert(rule>=0); + } + return rule; +} + +int rule_faction_limit(void) +{ + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + rule = get_param_int(global.parameters, "rules.limit.faction", 0); + gamecookie = global.cookie; + assert(rule>=0); + } + return rule; +} + +int rule_transfermen(void) +{ + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + rule = get_param_int(global.parameters, "rules.transfermen", 1); + gamecookie = global.cookie; + assert(rule>=0); + } + return rule; +} + +static int +default_wage(const region *r, const faction * f, const race * rc, int in_turn) +{ + building *b = largestbuilding(r, &cmp_wage, false); + int esize = 0; + curse * c; + double wage; + attrib *a; + const building_type *artsculpture_type = bt_find("artsculpture"); + static const curse_type * drought_ct, * blessedharvest_ct; + static boolean init; + + if (!init) { + init = true; + drought_ct = ct_find("drought"); + blessedharvest_ct = ct_find("blessedharvest"); + } + + if (b!=NULL) { + /* TODO: this reveals imaginary castles */ + esize = buildingeffsize(b, false); + } + + if (f!=NULL) { + int index = 0; + if (rc==new_race[RC_ORC] || rc==new_race[RC_SNOTLING]) { + index = 1; + } + wage = wagetable[esize][index]; + } else { + if (is_mourning(r, in_turn)) { + wage = 10; + } else if (fval(r->terrain, SEA_REGION)) { + wage = 11; + } else if (fval(r, RF_ORCIFIED)) { + wage = wagetable[esize][1]; + } else { + wage = wagetable[esize][2]; + } + if (rule_blessed_harvest()==HARVEST_WORK) { + /* E1 rules */ + wage += curse_geteffect(get_curse(r->attribs, blessedharvest_ct)); + } + } + + /* Artsculpture: Income +5 */ + for(b=r->buildings; b; b=b->next) { + if(b->type == artsculpture_type) { + wage += 5; + } + } + + /* Godcurse: Income -10 */ + if (curse_active(get_curse(r->attribs, ct_find("godcursezone")))) { + wage = MAX(0,wage-10); + } + + /* Bei einer Dürre verdient man nur noch ein Viertel */ + if (drought_ct) { + c = get_curse(r->attribs, drought_ct); + if (curse_active(c)) wage /= curse_geteffect(c); + } + + a = a_find(r->attribs, &at_reduceproduction); + if (a) wage = (wage * a->data.sa[0])/100; + + return (int)wage; +} + +static int +minimum_wage(const region *r, const faction * f, const race * rc, int in_turn) +{ + if (f && rc) { + return rc->maintenance; + } + return default_wage(r, f, rc, in_turn); +} + +/* Gibt Arbeitslohn für entsprechende Rasse zurück, oder für +* die Bauern wenn f == NULL. */ +int +wage(const region *r, const faction * f, const race * rc, int in_turn) +{ + if (global.functions.wage) { + return global.functions.wage(r, f, rc, in_turn); + } + return default_wage(r, f, rc, in_turn); +} + + +#define MAINTENANCE 10 +int +maintenance_cost(const struct unit * u) +{ + if (u==NULL) return MAINTENANCE; + if (global.functions.maintenance) { + int retval = global.functions.maintenance(u); + if (retval>=0) return retval; + } + return u->race->maintenance * u->number; +} + +message * +movement_error(unit * u, const char * token, order * ord, int error_code) +{ + direction_t d; + switch (error_code) { + case E_MOVE_BLOCKED: + d = finddirection(token, u->faction->locale); + return msg_message("moveblocked", "unit direction", u, d); + case E_MOVE_NOREGION: + return msg_feedback(u, ord, "unknowndirection", "dirname", token); + } + return NULL; +} + +int +movewhere(const unit *u, const char * token, region * r, region** resultp) +{ + region * r2; + direction_t d; + + if (*token == '\0') { + *resultp = NULL; + return E_MOVE_OK; + } + + d = finddirection(token, u->faction->locale); + switch (d) { + case D_PAUSE: + *resultp = r; + break; + + case NODIRECTION: + r2 = find_special_direction(r, token, u->faction->locale); + if (r2==NULL) { + return E_MOVE_NOREGION; + } + *resultp = r2; + break; + + default: + r2 = rconnect(r, d); + if (r2==NULL || move_blocked(u, r, r2)) { + return E_MOVE_BLOCKED; + } + *resultp = r2; + } + return E_MOVE_OK; +} + +boolean +move_blocked(const unit * u, const region *r, const region *r2) +{ + connection * b; + curse * c; + static const curse_type * fogtrap_ct = NULL; + + if (r2==NULL) return true; + b = get_borders(r, r2); + while (b) { + if (b->type->block && b->type->block(b, u, r)) return true; + b = b->next; + } + + if (fogtrap_ct==NULL) fogtrap_ct = ct_find("fogtrap"); + c = get_curse(r->attribs, fogtrap_ct); + if (curse_active(c)) return true; + return false; +} + +void +add_income(unit * u, int type, int want, int qty) +{ + if (want==INT_MAX) want = qty; + ADDMSG(&u->faction->msgs, msg_message("income", "unit region mode wanted amount", + u, u->region, type, want, qty)); +} + +void +reorder_units(region * r) +{ + unit ** unext = &r->units; + + if (r->buildings) { + building * b = r->buildings; + while (*unext && b) { + unit ** ufirst = unext; /* where the first unit in the building should go */ + unit ** umove = unext; /* a unit we consider moving */ + unit * owner = NULL; + while (*umove) { + unit * u = *umove; + if (u->number && u->building==b) { + unit ** uinsert = unext; + if (fval(u, UFL_OWNER)) { + uinsert = ufirst; + owner = u; + } + if (umove!=uinsert) { + *umove = u->next; + u->next = *uinsert; + *uinsert = u; + } else { + /* no need to move, skip ahead */ + umove = &u->next; + } + if (unext==uinsert) { + /* we have a new well-placed unit. jump over it */ + unext = &u->next; + } + } else { + umove = &u->next; + } + } + if (!owner && ufirst!=unext) { + owner = *ufirst; + fset(owner, UFL_OWNER); + } + b = b->next; + } + } + + if (r->ships) { + ship * sh = r->ships; + /* first, move all units up that are not on ships */ + unit ** umove = unext; /* a unit we consider moving */ + while (*umove) { + unit * u = *umove; + if (u->number && !u->ship) { + if (umove!=unext) { + *umove = u->next; + u->next = *unext; + *unext = u; + } else { + /* no need to move, skip ahead */ + umove = &u->next; + } + /* we have a new well-placed unit. jump over it */ + unext = &u->next; + } else { + umove = &u->next; + } + } + + while (*unext && sh) { + unit ** ufirst = unext; /* where the first unit in the building should go */ + unit ** umove = unext; /* a unit we consider moving */ + unit * owner = NULL; + while (*umove) { + unit * u = *umove; + if (u->number && u->ship==sh) { + unit ** uinsert = unext; + if (fval(u, UFL_OWNER)) { + uinsert = ufirst; + owner = u; + } + if (umove!=uinsert) { + *umove = u->next; + u->next = *uinsert; + *uinsert = u; + } else { + /* no need to move, skip ahead */ + umove = &u->next; + } + if (unext==uinsert) { + /* we have a new well-placed unit. jump over it */ + unext = &u->next; + } + } else { + umove = &u->next; + } + } + if (!owner && ufirst!=unext) { + owner = *ufirst; + fset(owner, UFL_OWNER); + } + sh = sh->next; + } + } +} + +int +produceexp(struct unit * u, skill_t sk, int n) +{ + if (global.producexpchance>0.0F) { + if (n==0 || !playerrace(u->race)) return 0; + learn_skill(u, sk, global.producexpchance); + } + return 0; +} + +int +lovar(double xpct_x2) +{ + int n = (int)(xpct_x2 * 500)+1; + if (n==0) return 0; + return (rng_int() % n + rng_int() % n)/1000; +} + +boolean +has_limited_skills (const struct unit * u) +{ + if (has_skill(u, SK_MAGIC) || has_skill(u, SK_ALCHEMY) || + has_skill(u, SK_TACTICS) || has_skill(u, SK_HERBALISM) || + has_skill(u, SK_SPY)) { + return true; + } else { + return false; + } +} + +void +attrib_init(void) +{ + /* Alle speicherbaren Attribute müssen hier registriert werden */ + at_register(&at_shiptrail); + at_register(&at_familiar); + at_register(&at_familiarmage); + at_register(&at_clone); + at_register(&at_clonemage); + at_register(&at_eventhandler); + at_register(&at_stealth); + at_register(&at_mage); + at_register(&at_countdown); + at_register(&at_curse); + + at_register(&at_seenspell); + + /* neue REGION-Attribute */ + at_register(&at_direction); + at_register(&at_moveblock); + at_register(&at_deathcount); + at_register(&at_chaoscount); + at_register(&at_woodcount); + + /* neue UNIT-Attribute */ + at_register(&at_siege); + at_register(&at_effect); + at_register(&at_private); + + at_register(&at_icastle); + at_register(&at_guard); + at_register(&at_group); + + at_register(&at_building_generic_type); + at_register(&at_maxmagicians); + at_register(&at_npcfaction); + + /* connection-typen */ + register_bordertype(&bt_noway); + register_bordertype(&bt_fogwall); + register_bordertype(&bt_wall); + register_bordertype(&bt_illusionwall); + register_bordertype(&bt_road); + register_bordertype(&bt_questportal); + + register_function((pf_generic)&minimum_wage, "minimum_wage"); + + at_register(&at_germs); +#if XECMD_MODULE + at_register(&at_xontormiaexpress); /* required for old datafiles */ +#endif + at_register(&at_speedup); + at_register(&at_building_action); +} + +void +kernel_init(void) +{ + char zBuffer[MAX_PATH]; + attrib_init(); + translation_init(); + + if (sqlpatch) { + sprintf(zBuffer, "%s/patch-%d.sql", datapath(), turn); + sql_init(zBuffer); + } +} + +order * +default_order(const struct locale * lang) +{ + return parse_order(locale_string(lang, "defaultorder"), lang); +} + +int +entertainmoney(const region *r) +{ + double n; + + if (is_cursed(r->attribs, C_DEPRESSION, 0)) { + return 0; + } + + n = rmoney(r) / ENTERTAINFRACTION; + + if (is_cursed(r->attribs, C_GENEROUS, 0)) { + n *= get_curseeffect(r->attribs, C_GENEROUS, 0); + } + + return (int)n; +} + +int rule_give(void) +{ + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "rules.give", GIVE_DEFAULT); + } + return value; +} + +int markets_module(void) +{ + static int value = -1; + if (value<0) { + value = get_param_int(global.parameters, "modules.markets", 0); + } + return value; +} + +/** releases all memory associated with the game state. + * call this function before calling read_game() to load a new game + * if you have a previously loaded state in memory. + */ +void +free_gamedata(void) +{ + free_units(); + free_regions(); + free_borders(); + + while (alliances) { + alliance * al = alliances; + alliances = al->next; + free_alliance(al); + } + while (factions) { + faction * f = factions; + factions = f->next; + funhash(f); + free_faction(f); + free(f); + } + + while (planes) { + plane * pl = planes; + planes = planes->next; + free(pl->name); + free(pl); + } + + while (global.attribs) { + a_remove(&global.attribs, global.attribs); + } + ++global.cookie; /* readgame() already does this, but sjust in case */ +} + + +void +load_inifile(dictionary * d) +{ + const char * reportdir = reportpath(); + const char * datadir = datapath(); + const char * basedir = basepath(); + const char * str; + + assert(d); + + str = iniparser_getstring(d, "eressea:base", basedir); + if (str!=basedir) set_basepath(str); + str = iniparser_getstring(d, "eressea:report", reportdir); + if (str!=reportdir) set_reportpath(str); + str = iniparser_getstring(d, "eressea:data", datadir); + if (str!=datadir) set_datapath(str); + + lomem = iniparser_getint(d, "eressea:lomem", lomem)?1:0; + + str = iniparser_getstring(d, "eressea:encoding", NULL); + if (str) enc_gamedata = xmlParseCharEncoding(str); + + verbosity = iniparser_getint(d, "eressea:verbose", 2); + sqlpatch = iniparser_getint(d, "eressea:sqlpatch", false); + battledebug = iniparser_getint(d, "eressea:debug", battledebug)?1:0; + + str = iniparser_getstring(d, "eressea:locales", "de,en"); + make_locales(str); + + /* excerpt from [config] (the rest is used in bindings.c) */ + game_name = iniparser_getstring(d, "config:game", game_name); + + global.inifile = d; +} diff --git a/src/kernel/config.h b/src/kernel/config.h index 89fb25f9a..22544a78b 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -1,460 +1,460 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef ERESSEA_H -#define ERESSEA_H - -#ifdef __cplusplus -extern "C" { -#endif - - /* this should always be the first thing included after platform.h */ -#include "types.h" - -struct _dictionary_; - - /* experimental gameplay features (that don't affect the savefile) */ - /* TODO: move these settings to settings.h or into configuration files */ -#define GOBLINKILL /* Goblin-Spezialklau kann tödlich enden */ -#define HERBS_ROT /* herbs owned by units have a chance to rot. */ -#define SHIPDAMAGE /* Schiffsbeschädigungen */ -#define INSECT_POTION /* Spezialtrank für Insekten */ -#define ORCIFICATION /* giving snotlings to the peasants gets counted */ -#undef TROLLSAVE /* saving throw for dead trolls */ - -#define ALLIED(f1, f2) (f1==f2 || (f1->alliance && f1->alliance==f2->alliance)) - -/* for some good prime numbers, check http://www.math.niu.edu/~rusin/known-math/98/pi_x */ -#ifndef MAXREGIONS -# define MAXREGIONS 524287 /* must be prime for hashing. 262139 was a little small */ -#endif -#ifndef MAXUNITS -# define MAXUNITS 1048573 /* must be prime for hashing. 524287 was >90% full */ -#endif - -#define MAXPEASANTS_PER_AREA 10 /* number of peasants per region-size */ -#define TREESIZE (MAXPEASANTS_PER_AREA-2) /* space used by trees (in #peasants) */ - -#define PEASANTFORCE 0.75 /* Chance einer Vermehrung trotz 90% Auslastung */ -#define HERBROTCHANCE 5 /* Verrottchance für Kräuter (ifdef HERBS_ROT) */ - -/* Gebäudegröße = Minimalbelagerer */ -#define SIEGEFACTOR 2 - -/** Magic */ -#define MAXMAGICIANS 3 -#define MAXALCHEMISTS 3 - -/** Plagues **/ -#define PLAGUE_CHANCE 0.1F /* Seuchenwahrscheinlichkeit (siehe plagues()) */ -#define PLAGUE_VICTIMS 0.2F /* % Betroffene */ -#define PLAGUE_HEALCHANCE 0.25F /* Wahrscheinlichkeit Heilung */ -#define PLAGUE_HEALCOST 30 /* Heilkosten */ - -/* Chance of a monster attack */ -#define MONSTERATTACK 0.4F - -/** Chance of an unmaintained building crashing */ -/* #define COLLAPSE_CHANCE 0.4F */ -#undef COLLAPSE_CHANCE -/** chance to survive the crash of a building */ -/* #define COLLAPSE_SURVIVAL 0.5F */ -#undef COLLAPSE_SURVIVAL - -/* 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 - -#define PERSON_WEIGHT 1000 /* weight of a "normal" human unit */ -#define STAMINA_AFFECTS_HP 1<<0 - -/** - * Hier endet der Teil von config.h, der die defines für die - * Spielwelt Eressea enthält, und beginnen die allgemeinen Routinen - */ - -#define ENCCHANCE 10 /* %-Chance für einmalige Zufallsbegegnung */ - -#define DISPLAYSIZE 8191 /* max. Länge einer Beschreibung, ohne trailing 0 */ -#define NAMESIZE 127 /* max. Länge eines Namens, ohne trailing 0 */ -#define IDSIZE 15 /* max. Länge einer no (als String), ohne trailing 0 */ -#define KEYWORDSIZE 15 /* max. Länge eines Keyword, ohne trailing 0 */ -#define OBJECTIDSIZE (NAMESIZE+5+IDSIZE) /* max. Länge der Strings, die - * von struct unitname, etc. zurückgegeben werden. ohne die 0 */ - -#define BAGCAPACITY 20000 /* soviel paßt in einen Bag of Holding */ -#define STRENGTHCAPACITY 50000 /* zusätzliche Tragkraft beim Kraftzauber (deprecated) */ -#define STRENGTHMULTIPLIER 50 /* multiplier for trollbelt */ - -/* ----------------- Befehle ----------------------------------- */ - -extern const char *keywords[MAXKEYWORDS]; -extern const char *parameters[MAXPARAMS]; - -/** report options **/ -#define want(option) (1<flags & (i)) -#define fset(u, i) ((u)->flags |= (i)) -#define freset(u, i) ((u)->flags &= ~(i)) - -extern int turn; -extern int verbosity; - -/* parteinummern */ -extern boolean faction_id_is_unused(int); - -/* leuchtturm */ -extern boolean check_leuchtturm(struct region * r, struct faction * f); -extern void update_lighthouse(struct building * lh); -extern int lighthouse_range(const struct building * b, const struct faction * f); - -/* skills */ -extern int skill_limit(struct faction * f, skill_t sk); -extern int count_skill(struct faction * f, skill_t sk); - -/* direction, geography */ -extern const char *directions[]; -extern direction_t finddirection(const char *s, const struct locale *); - -extern int findoption(const char *s, const struct locale * lang); - -/* special units */ -void make_undead_unit(struct unit *); - -void addstrlist(strlist ** SP, const char *s); - -int armedmen(const struct unit * u, boolean siege_weapons); - -unsigned int atoip(const char *s); -unsigned int getuint(void); -int getint(void); - -extern const char *igetstrtoken(const char *s); - -extern void init_tokens(const struct order * ord); /* initialize token parsing */ -extern skill_t findskill(const char *s, const struct locale * lang); - -extern keyword_t findkeyword(const char *s, const struct locale * lang); - -extern param_t findparam(const char *s, const struct locale * lang); -extern param_t getparam(const struct locale * lang); - -extern int getid(void); -#define unitid(x) itoa36((x)->no) - -#define getshipid() getid() -#define getfactionid() getid() - -#define buildingid(x) itoa36((x)->no) -#define shipid(x) itoa36((x)->no) -#define factionid(x) itoa36((x)->no) -#define curseid(x) itoa36((x)->no) - -extern boolean cansee(const struct faction * f, const struct region * r, const struct unit * u, int modifier); -boolean cansee_durchgezogen(const struct faction * f, const struct region * r, const struct unit * u, int modifier); -extern boolean cansee_unit(const struct unit * u, const struct unit * target, int modifier); -boolean seefaction(const struct faction * f, const struct region * r, const struct unit * u, int modifier); -extern int effskill(const struct unit * u, skill_t sk); - -extern int lovar(double xpct_x2); - /* returns a value between [0..xpct_2], generated with two dice */ - -int distribute(int old, int new_value, int n); - -int newunitid(void); -int forbiddenid(int id); -int newcontainerid(void); - -extern struct unit *createunit(struct region * r, struct faction * f, int number, const struct race * rc); -extern void create_unitid(struct unit *u, int id); -extern boolean getunitpeasants; -extern struct unit *getunitg(const struct region * r, const struct faction * f); -extern struct unit *getunit(const struct region * r, const struct faction * f); - -extern int read_unitid(const struct faction * f, const struct region * r); - -extern int alliedunit(const struct unit * u, const struct faction * f2, int mode); -extern int alliedfaction(const struct plane * pl, const struct faction * f, - const struct faction * f2, int mode); -extern int alliedgroup(const struct plane * pl, const struct faction * f, - const struct faction * f2, const struct ally * sf, - int mode); - -struct faction *findfaction(int n); -struct faction *getfaction(void); - -struct unit *findunitg(int n, const struct region * hint); -struct unit *findunit(int n); - -struct unit *findunitr(const struct region * r, int n); -struct region *findunitregion(const struct unit * su); - -extern char *estring(const char *s); -extern char *estring_i(char *s); -extern char *cstring(const char *s); -extern char *cstring_i(char *s); -extern const char *unitname(const struct unit * u); -extern char * write_unitname(const struct unit * u, char * buffer, size_t size); - -typedef int (*cmp_building_cb)(const struct building * b, const struct building * a); -struct building *largestbuilding(const struct region * r, cmp_building_cb, boolean imaginary); -int cmp_wage(const struct building * b, const struct building * bother); -int cmp_taxes(const struct building * b, const struct building * bother); -int cmp_current_owner(const struct building * b, const struct building * bother); - -#define TAX_ORDER 0x00 -#define TAX_OWNER 0x01 -int rule_auto_taxation(void); -int rule_transfermen(void); -int rule_region_owners(void); -int rule_stealth_faction(void); -#define HARVEST_WORK 0x00 -#define HARVEST_TAXES 0x01 -int rule_blessed_harvest(void); -extern int rule_give(void); -extern int rule_alliance_limit(void); -extern int rule_faction_limit(void); - -extern int count_all(const struct faction * f); -extern int count_migrants (const struct faction * f); -extern int count_maxmigrants(const struct faction * f); - -extern boolean has_limited_skills(const struct unit * u); -extern const struct race * findrace(const char *, const struct locale *); - -int eff_stealth(const struct unit * u, const struct region * r); -int ispresent(const struct faction * f, const struct region * r); - -int check_option(struct faction * f, int option); -extern void parse(keyword_t kword, int (*dofun)(struct unit *, struct order *), boolean thisorder); - -/* Anzahl Personen in einer Einheit festlegen. NUR (!) mit dieser Routine, - * sonst großes Unglück. Durch asserts an ein paar Stellen abgesichert. */ -void verify_data(void); - -void freestrlist(strlist * s); - -int change_hitpoints(struct unit *u, int value); - -int weight(const struct unit * u); -void changeblockchaos(void); - -/* intervall, in dem die regionen der partei zu finden sind */ -extern struct region *firstregion(struct faction * f); -extern struct region *lastregion(struct faction * f); - -void fhash(struct faction * f); -void funhash(struct faction * f); - -boolean idle(struct faction * f); -boolean unit_has_cursed_item(struct unit *u); - -/* simple garbage collection: */ -void * gc_add(void * p); - -/* grammatik-flags: */ -#define GF_NONE 0 - /* singular, ohne was dran */ -#define GF_PLURAL 1 - /* Angaben in Mehrzahl */ -#define GF_ARTICLE 8 - /* der, die, eine */ -#define GF_SPECIFIC 16 - /* der, die, das vs. ein, eine */ -#define GF_DETAILED 32 - /* mehr Informationen. z.b. straße zu 50% */ -#define GF_PURE 64 - /* untranslated */ - -#define GUARD_NONE 0 -#define GUARD_TAX 1 - /* Verhindert Steuereintreiben */ -#define GUARD_MINING 2 - /* Verhindert Bergbau */ -#define GUARD_TREES 4 - /* Verhindert Waldarbeiten */ -#define GUARD_TRAVELTHRU 8 - /* Blockiert Durchreisende */ -#define GUARD_LANDING 16 - /* Verhindert Ausstieg + Weiterreise */ -#define GUARD_CREWS 32 - /* Verhindert Unterhaltung auf Schiffen */ -#define GUARD_RECRUIT 64 - /* Verhindert Rekrutieren */ -#define GUARD_PRODUCE 128 - /* Verhindert Abbau von Resourcen mit RTF_LIMITED */ -#define GUARD_ALL 0xFFFF - -extern void setstatus(struct unit * u, int status); -/* !< sets combatstatus of a unit */ -extern void setguard(struct unit * u, unsigned int flags); -/* !< setzt die guard-flags der Einheit */ -extern unsigned int getguard(const struct unit * u); - /* liest die guard-flags der Einheit */ -extern void guard(struct unit * u, unsigned int mask); - /* Einheit setzt "BEWACHE", rassenspezifzisch. - * 'mask' kann einzelne flags zusätzlich und-maskieren. - */ -unsigned int guard_flags(const struct unit * u); - -extern boolean hunger(int number, struct unit * u); -extern int lifestyle(const struct unit*); -extern int besieged(const struct unit * u); -extern int maxworkingpeasants(const struct region * r); -extern boolean has_horses(const struct unit * u); -extern int markets_module(void); -extern int wage(const struct region *r, const struct faction *f, const struct race * rc, int in_turn); -extern int maintenance_cost(const struct unit * u); -extern struct message * movement_error(struct unit * u, const char * token, struct order * ord, int error_code); -extern boolean move_blocked(const struct unit * u, const struct region *src, const struct region *dest); -extern void add_income(struct unit * u, int type, int want, int qty); - -/* movewhere error codes */ -enum { - E_MOVE_OK = 0, /* possible to move */ - E_MOVE_NOREGION, /* no region exists in this direction */ - E_MOVE_BLOCKED /* cannot see this region, there is a blocking connection. */ -}; -extern int movewhere(const struct unit *u, const char * token, struct region * r, struct region** resultp); - -extern const char * datapath(void); -extern void set_datapath(const char * path); - -extern const char * basepath(void); -extern void set_basepath(const char *); -void load_inifile(struct _dictionary_ * d); - -extern const char * reportpath(void); -extern void set_reportpath(const char *); - -extern void kernel_init(void); -extern void kernel_done(void); - -extern void reorder_units(struct region * r); - -extern const char *localenames[]; - -/** compatibility: **/ -extern race_t old_race(const struct race *); -extern const struct race * new_race[]; - -/* globale settings des Spieles */ -typedef struct settings { - const char *gamename; - struct attrib *attribs; - unsigned int data_turn; - boolean disabled[MAXKEYWORDS]; - struct param * parameters; - void * vm_state; - float producexpchance; - int cookie; - struct _dictionary_ * inifile; - - struct global_functions { - int (*wage)(const struct region *r, const struct faction * f, const struct race * rc, int in_turn); - int (*maintenance)(const struct unit * u); - } functions; -} settings; -extern settings global; - -extern int produceexp(struct unit * u, skill_t sk, int n); - -extern boolean battledebug; -extern boolean sqlpatch; -extern boolean lomem; /* save memory */ - -extern const char * dbrace(const struct race * rc); - -extern void set_param(struct param ** p, const char * name, const char * data); -extern const char* get_param(const struct param * p, const char * name); -extern int get_param_int(const struct param * p, const char * name, int def); -extern float get_param_flt(const struct param * p, const char * name, float def); - -extern boolean ExpensiveMigrants(void); -extern int NMRTimeout(void); -extern int LongHunger(const struct unit * u); -extern int SkillCap(skill_t sk); -extern int NewbieImmunity(void); -extern boolean IsImmune(const struct faction * f); -extern int AllianceAuto(void); /* flags that allied factions get automatically */ -extern int AllianceRestricted(void); /* flags restricted to allied factions */ -extern int HelpMask(void); /* flags restricted to allied factions */ -extern struct order * default_order(const struct locale * lang); -extern int entertainmoney(const struct region * r); - -extern void plagues(struct region * r, boolean ismagic); -typedef struct helpmode { - const char * name; - int status; -} helpmode; - -extern struct helpmode helpmodes[]; - -#define GIVE_SELF 1 -#define GIVE_PEASANTS 2 -#define GIVE_LUXURIES 4 -#define GIVE_HERBS 8 -#define GIVE_GOODS 16 -#define GIVE_ONDEATH 32 -#define GIVE_ALLITEMS (GIVE_GOODS|GIVE_HERBS|GIVE_LUXURIES) -#define GIVE_DEFAULT (GIVE_SELF|GIVE_PEASANTS|GIVE_LUXURIES|GIVE_HERBS|GIVE_GOODS) - -extern struct attrib_type at_guard; -extern void free_gamedata(void); -#if 1 /* disable to count all units */ -# define count_unit(u) playerrace(u->race) -#else -# define count_unit(u) 1 -#endif - -#if XECMD_MODULE -extern struct attrib_type at_xontormiaexpress; -#endif - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef ERESSEA_H +#define ERESSEA_H + +#ifdef __cplusplus +extern "C" { +#endif + + /* this should always be the first thing included after platform.h */ +#include "types.h" + +struct _dictionary_; + + /* experimental gameplay features (that don't affect the savefile) */ + /* TODO: move these settings to settings.h or into configuration files */ +#define GOBLINKILL /* Goblin-Spezialklau kann tödlich enden */ +#define HERBS_ROT /* herbs owned by units have a chance to rot. */ +#define SHIPDAMAGE /* Schiffsbeschädigungen */ +#define INSECT_POTION /* Spezialtrank für Insekten */ +#define ORCIFICATION /* giving snotlings to the peasants gets counted */ +#undef TROLLSAVE /* saving throw for dead trolls */ + +#define ALLIED(f1, f2) (f1==f2 || (f1->alliance && f1->alliance==f2->alliance)) + +/* for some good prime numbers, check http://www.math.niu.edu/~rusin/known-math/98/pi_x */ +#ifndef MAXREGIONS +# define MAXREGIONS 524287 /* must be prime for hashing. 262139 was a little small */ +#endif +#ifndef MAXUNITS +# define MAXUNITS 1048573 /* must be prime for hashing. 524287 was >90% full */ +#endif + +#define MAXPEASANTS_PER_AREA 10 /* number of peasants per region-size */ +#define TREESIZE (MAXPEASANTS_PER_AREA-2) /* space used by trees (in #peasants) */ + +#define PEASANTFORCE 0.75 /* Chance einer Vermehrung trotz 90% Auslastung */ +#define HERBROTCHANCE 5 /* Verrottchance für Kräuter (ifdef HERBS_ROT) */ + +/* Gebäudegröße = Minimalbelagerer */ +#define SIEGEFACTOR 2 + +/** Magic */ +#define MAXMAGICIANS 3 +#define MAXALCHEMISTS 3 + +/** Plagues **/ +#define PLAGUE_CHANCE 0.1F /* Seuchenwahrscheinlichkeit (siehe plagues()) */ +#define PLAGUE_VICTIMS 0.2F /* % Betroffene */ +#define PLAGUE_HEALCHANCE 0.25F /* Wahrscheinlichkeit Heilung */ +#define PLAGUE_HEALCOST 30 /* Heilkosten */ + +/* Chance of a monster attack */ +#define MONSTERATTACK 0.4F + +/** Chance of an unmaintained building crashing */ +/* #define COLLAPSE_CHANCE 0.4F */ +#undef COLLAPSE_CHANCE +/** chance to survive the crash of a building */ +/* #define COLLAPSE_SURVIVAL 0.5F */ +#undef COLLAPSE_SURVIVAL + +/* 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 + +#define PERSON_WEIGHT 1000 /* weight of a "normal" human unit */ +#define STAMINA_AFFECTS_HP 1<<0 + +/** + * Hier endet der Teil von config.h, der die defines für die + * Spielwelt Eressea enthält, und beginnen die allgemeinen Routinen + */ + +#define ENCCHANCE 10 /* %-Chance für einmalige Zufallsbegegnung */ + +#define DISPLAYSIZE 8191 /* max. Länge einer Beschreibung, ohne trailing 0 */ +#define NAMESIZE 127 /* max. Länge eines Namens, ohne trailing 0 */ +#define IDSIZE 15 /* max. Länge einer no (als String), ohne trailing 0 */ +#define KEYWORDSIZE 15 /* max. Länge eines Keyword, ohne trailing 0 */ +#define OBJECTIDSIZE (NAMESIZE+5+IDSIZE) /* max. Länge der Strings, die + * von struct unitname, etc. zurückgegeben werden. ohne die 0 */ + +#define BAGCAPACITY 20000 /* soviel paßt in einen Bag of Holding */ +#define STRENGTHCAPACITY 50000 /* zusätzliche Tragkraft beim Kraftzauber (deprecated) */ +#define STRENGTHMULTIPLIER 50 /* multiplier for trollbelt */ + +/* ----------------- Befehle ----------------------------------- */ + +extern const char *keywords[MAXKEYWORDS]; +extern const char *parameters[MAXPARAMS]; + +/** report options **/ +#define want(option) (1<flags & (i)) +#define fset(u, i) ((u)->flags |= (i)) +#define freset(u, i) ((u)->flags &= ~(i)) + +extern int turn; +extern int verbosity; + +/* parteinummern */ +extern boolean faction_id_is_unused(int); + +/* leuchtturm */ +extern boolean check_leuchtturm(struct region * r, struct faction * f); +extern void update_lighthouse(struct building * lh); +extern int lighthouse_range(const struct building * b, const struct faction * f); + +/* skills */ +extern int skill_limit(struct faction * f, skill_t sk); +extern int count_skill(struct faction * f, skill_t sk); + +/* direction, geography */ +extern const char *directions[]; +extern direction_t finddirection(const char *s, const struct locale *); + +extern int findoption(const char *s, const struct locale * lang); + +/* special units */ +void make_undead_unit(struct unit *); + +void addstrlist(strlist ** SP, const char *s); + +int armedmen(const struct unit * u, boolean siege_weapons); + +unsigned int atoip(const char *s); +unsigned int getuint(void); +int getint(void); + +extern const char *igetstrtoken(const char *s); + +extern void init_tokens(const struct order * ord); /* initialize token parsing */ +extern skill_t findskill(const char *s, const struct locale * lang); + +extern keyword_t findkeyword(const char *s, const struct locale * lang); + +extern param_t findparam(const char *s, const struct locale * lang); +extern param_t getparam(const struct locale * lang); + +extern int getid(void); +#define unitid(x) itoa36((x)->no) + +#define getshipid() getid() +#define getfactionid() getid() + +#define buildingid(x) itoa36((x)->no) +#define shipid(x) itoa36((x)->no) +#define factionid(x) itoa36((x)->no) +#define curseid(x) itoa36((x)->no) + +extern boolean cansee(const struct faction * f, const struct region * r, const struct unit * u, int modifier); +boolean cansee_durchgezogen(const struct faction * f, const struct region * r, const struct unit * u, int modifier); +extern boolean cansee_unit(const struct unit * u, const struct unit * target, int modifier); +boolean seefaction(const struct faction * f, const struct region * r, const struct unit * u, int modifier); +extern int effskill(const struct unit * u, skill_t sk); + +extern int lovar(double xpct_x2); + /* returns a value between [0..xpct_2], generated with two dice */ + +int distribute(int old, int new_value, int n); + +int newunitid(void); +int forbiddenid(int id); +int newcontainerid(void); + +extern struct unit *createunit(struct region * r, struct faction * f, int number, const struct race * rc); +extern void create_unitid(struct unit *u, int id); +extern boolean getunitpeasants; +extern struct unit *getunitg(const struct region * r, const struct faction * f); +extern struct unit *getunit(const struct region * r, const struct faction * f); + +extern int read_unitid(const struct faction * f, const struct region * r); + +extern int alliedunit(const struct unit * u, const struct faction * f2, int mode); +extern int alliedfaction(const struct plane * pl, const struct faction * f, + const struct faction * f2, int mode); +extern int alliedgroup(const struct plane * pl, const struct faction * f, + const struct faction * f2, const struct ally * sf, + int mode); + +struct faction *findfaction(int n); +struct faction *getfaction(void); + +struct unit *findunitg(int n, const struct region * hint); +struct unit *findunit(int n); + +struct unit *findunitr(const struct region * r, int n); +struct region *findunitregion(const struct unit * su); + +extern char *estring(const char *s); +extern char *estring_i(char *s); +extern char *cstring(const char *s); +extern char *cstring_i(char *s); +extern const char *unitname(const struct unit * u); +extern char * write_unitname(const struct unit * u, char * buffer, size_t size); + +typedef int (*cmp_building_cb)(const struct building * b, const struct building * a); +struct building *largestbuilding(const struct region * r, cmp_building_cb, boolean imaginary); +int cmp_wage(const struct building * b, const struct building * bother); +int cmp_taxes(const struct building * b, const struct building * bother); +int cmp_current_owner(const struct building * b, const struct building * bother); + +#define TAX_ORDER 0x00 +#define TAX_OWNER 0x01 +int rule_auto_taxation(void); +int rule_transfermen(void); +int rule_region_owners(void); +int rule_stealth_faction(void); +#define HARVEST_WORK 0x00 +#define HARVEST_TAXES 0x01 +int rule_blessed_harvest(void); +extern int rule_give(void); +extern int rule_alliance_limit(void); +extern int rule_faction_limit(void); + +extern int count_all(const struct faction * f); +extern int count_migrants (const struct faction * f); +extern int count_maxmigrants(const struct faction * f); + +extern boolean has_limited_skills(const struct unit * u); +extern const struct race * findrace(const char *, const struct locale *); + +int eff_stealth(const struct unit * u, const struct region * r); +int ispresent(const struct faction * f, const struct region * r); + +int check_option(struct faction * f, int option); +extern void parse(keyword_t kword, int (*dofun)(struct unit *, struct order *), boolean thisorder); + +/* Anzahl Personen in einer Einheit festlegen. NUR (!) mit dieser Routine, + * sonst großes Unglück. Durch asserts an ein paar Stellen abgesichert. */ +void verify_data(void); + +void freestrlist(strlist * s); + +int change_hitpoints(struct unit *u, int value); + +int weight(const struct unit * u); +void changeblockchaos(void); + +/* intervall, in dem die regionen der partei zu finden sind */ +extern struct region *firstregion(struct faction * f); +extern struct region *lastregion(struct faction * f); + +void fhash(struct faction * f); +void funhash(struct faction * f); + +boolean idle(struct faction * f); +boolean unit_has_cursed_item(struct unit *u); + +/* simple garbage collection: */ +void * gc_add(void * p); + +/* grammatik-flags: */ +#define GF_NONE 0 + /* singular, ohne was dran */ +#define GF_PLURAL 1 + /* Angaben in Mehrzahl */ +#define GF_ARTICLE 8 + /* der, die, eine */ +#define GF_SPECIFIC 16 + /* der, die, das vs. ein, eine */ +#define GF_DETAILED 32 + /* mehr Informationen. z.b. straße zu 50% */ +#define GF_PURE 64 + /* untranslated */ + +#define GUARD_NONE 0 +#define GUARD_TAX 1 + /* Verhindert Steuereintreiben */ +#define GUARD_MINING 2 + /* Verhindert Bergbau */ +#define GUARD_TREES 4 + /* Verhindert Waldarbeiten */ +#define GUARD_TRAVELTHRU 8 + /* Blockiert Durchreisende */ +#define GUARD_LANDING 16 + /* Verhindert Ausstieg + Weiterreise */ +#define GUARD_CREWS 32 + /* Verhindert Unterhaltung auf Schiffen */ +#define GUARD_RECRUIT 64 + /* Verhindert Rekrutieren */ +#define GUARD_PRODUCE 128 + /* Verhindert Abbau von Resourcen mit RTF_LIMITED */ +#define GUARD_ALL 0xFFFF + +extern void setstatus(struct unit * u, int status); +/* !< sets combatstatus of a unit */ +extern void setguard(struct unit * u, unsigned int flags); +/* !< setzt die guard-flags der Einheit */ +extern unsigned int getguard(const struct unit * u); + /* liest die guard-flags der Einheit */ +extern void guard(struct unit * u, unsigned int mask); + /* Einheit setzt "BEWACHE", rassenspezifzisch. + * 'mask' kann einzelne flags zusätzlich und-maskieren. + */ +unsigned int guard_flags(const struct unit * u); + +extern boolean hunger(int number, struct unit * u); +extern int lifestyle(const struct unit*); +extern int besieged(const struct unit * u); +extern int maxworkingpeasants(const struct region * r); +extern boolean has_horses(const struct unit * u); +extern int markets_module(void); +extern int wage(const struct region *r, const struct faction *f, const struct race * rc, int in_turn); +extern int maintenance_cost(const struct unit * u); +extern struct message * movement_error(struct unit * u, const char * token, struct order * ord, int error_code); +extern boolean move_blocked(const struct unit * u, const struct region *src, const struct region *dest); +extern void add_income(struct unit * u, int type, int want, int qty); + +/* movewhere error codes */ +enum { + E_MOVE_OK = 0, /* possible to move */ + E_MOVE_NOREGION, /* no region exists in this direction */ + E_MOVE_BLOCKED /* cannot see this region, there is a blocking connection. */ +}; +extern int movewhere(const struct unit *u, const char * token, struct region * r, struct region** resultp); + +extern const char * datapath(void); +extern void set_datapath(const char * path); + +extern const char * basepath(void); +extern void set_basepath(const char *); +void load_inifile(struct _dictionary_ * d); + +extern const char * reportpath(void); +extern void set_reportpath(const char *); + +extern void kernel_init(void); +extern void kernel_done(void); + +extern void reorder_units(struct region * r); + +extern const char *localenames[]; + +/** compatibility: **/ +extern race_t old_race(const struct race *); +extern const struct race * new_race[]; + +/* globale settings des Spieles */ +typedef struct settings { + const char *gamename; + struct attrib *attribs; + unsigned int data_turn; + boolean disabled[MAXKEYWORDS]; + struct param * parameters; + void * vm_state; + float producexpchance; + int cookie; + struct _dictionary_ * inifile; + + struct global_functions { + int (*wage)(const struct region *r, const struct faction * f, const struct race * rc, int in_turn); + int (*maintenance)(const struct unit * u); + } functions; +} settings; +extern settings global; + +extern int produceexp(struct unit * u, skill_t sk, int n); + +extern boolean battledebug; +extern boolean sqlpatch; +extern boolean lomem; /* save memory */ + +extern const char * dbrace(const struct race * rc); + +extern void set_param(struct param ** p, const char * name, const char * data); +extern const char* get_param(const struct param * p, const char * name); +extern int get_param_int(const struct param * p, const char * name, int def); +extern float get_param_flt(const struct param * p, const char * name, float def); + +extern boolean ExpensiveMigrants(void); +extern int NMRTimeout(void); +extern int LongHunger(const struct unit * u); +extern int SkillCap(skill_t sk); +extern int NewbieImmunity(void); +extern boolean IsImmune(const struct faction * f); +extern int AllianceAuto(void); /* flags that allied factions get automatically */ +extern int AllianceRestricted(void); /* flags restricted to allied factions */ +extern int HelpMask(void); /* flags restricted to allied factions */ +extern struct order * default_order(const struct locale * lang); +extern int entertainmoney(const struct region * r); + +extern void plagues(struct region * r, boolean ismagic); +typedef struct helpmode { + const char * name; + int status; +} helpmode; + +extern struct helpmode helpmodes[]; + +#define GIVE_SELF 1 +#define GIVE_PEASANTS 2 +#define GIVE_LUXURIES 4 +#define GIVE_HERBS 8 +#define GIVE_GOODS 16 +#define GIVE_ONDEATH 32 +#define GIVE_ALLITEMS (GIVE_GOODS|GIVE_HERBS|GIVE_LUXURIES) +#define GIVE_DEFAULT (GIVE_SELF|GIVE_PEASANTS|GIVE_LUXURIES|GIVE_HERBS|GIVE_GOODS) + +extern struct attrib_type at_guard; +extern void free_gamedata(void); +#if 1 /* disable to count all units */ +# define count_unit(u) playerrace(u->race) +#else +# define count_unit(u) 1 +#endif + +#if XECMD_MODULE +extern struct attrib_type at_xontormiaexpress; +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/connection.c b/src/kernel/connection.c index 6ea99361d..0dc4a3753 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -1,613 +1,613 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "connection.h" - -#include "region.h" -#include "save.h" -#include "terrain.h" -#include "unit.h" -#include "version.h" - -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -unsigned int nextborder = 0; - -#define BORDER_MAXHASH 8191 -connection * borders[BORDER_MAXHASH]; -border_type * bordertypes; - -void (*border_convert_cb)(struct connection * con, struct attrib * attr) = 0; - -void -free_borders(void) -{ - int i; - for (i=0;i!=BORDER_MAXHASH;++i) { - while (borders[i]) { - connection * b = borders[i]; - borders[i] = b->nexthash; - while (b) { - connection * bf = b; - b = b->next; - assert(b==NULL || b->nexthash==NULL); - if (bf->type->destroy) { - bf->type->destroy(bf); - } - free(bf); - } - } - } -} - -connection * -find_border(unsigned int id) -{ - int key; - for (key=0;key!=BORDER_MAXHASH;key++) { - connection * bhash; - for (bhash=borders[key];bhash!=NULL;bhash=bhash->nexthash) { - connection * b; - for (b=bhash;b;b=b->next) { - if (b->id==id) return b; - } - } - } - return NULL; -} - -int -resolve_borderid(variant id, void * addr) -{ - int result = 0; - connection * b = NULL; - if (id.i!=0) { - b = find_border(id.i); - if (b==NULL) { - result = -1; - } - } - *(connection**)addr = b; - return result; -} - -static connection ** -get_borders_i(const region * r1, const region * r2) -{ - connection ** bp; - int key = reg_hashkey(r1); - int k2 = reg_hashkey(r2); - - key = MIN(k2, key) % BORDER_MAXHASH; - bp = &borders[key]; - while (*bp) { - connection * b = *bp; - if ((b->from==r1 && b->to==r2) || (b->from==r2 && b->to==r1)) break; - bp = &b->nexthash; - } - return bp; -} - -connection * -get_borders(const region * r1, const region * r2) -{ - connection ** bp = get_borders_i(r1, r2); - return *bp; -} - -connection * -new_border(border_type * type, region * from, region * to) -{ - connection * b = calloc(1, sizeof(struct connection)); - - if (from && to) { - connection ** bp = get_borders_i(from, to); - while (*bp) bp = &(*bp)->next; - *bp = b; - } - b->type = type; - b->from = from; - b->to = to; - b->id = ++nextborder; - - if (type->init) type->init(b); - return b; -} - -void -erase_border(connection * b) -{ - if (b->from && b->to) { - connection ** bp = get_borders_i(b->from, b->to); - assert(*bp!=NULL || !"error: connection is not registered"); - if (*bp==b) { - /* it is the first in the list, so it is in the nexthash list */ - if (b->next) { - *bp = b->next; - (*bp)->nexthash = b->nexthash; - } else { - *bp = b->nexthash; - } - } else { - while (*bp && *bp != b) { - bp = &(*bp)->next; - } - assert(*bp==b || !"error: connection is not registered"); - *bp = b->next; - } - } - if (b->type->destroy) { - b->type->destroy(b); - } - free(b); -} - -void -register_bordertype(border_type * type) -{ - border_type ** btp = &bordertypes; - - while (*btp && *btp!=type) btp = &(*btp)->next; - if (*btp) return; - *btp = type; -} - - -border_type * -find_bordertype(const char * name) -{ - border_type * bt = bordertypes; - - while (bt && strcmp(bt->__name, name)) bt = bt->next; - return bt; -} - -void -b_read(connection * b, storage * store) -{ - int result = 0; - switch (b->type->datatype) { - case VAR_NONE: - case VAR_INT: - b->data.i = store->r_int(store); - break; - case VAR_SHORTA: - b->data.sa[0] = (short)store->r_int(store); - b->data.sa[1] = (short)store->r_int(store); - break; - case VAR_VOIDPTR: - default: - assert(!"invalid variant type in connection"); - result = 0; - } - assert(result>=0 || "EOF encountered?"); -} - -void -b_write(const connection * b, storage * store) -{ - switch (b->type->datatype) { - case VAR_NONE: - case VAR_INT: - store->w_int(store, b->data.i); - break; - case VAR_SHORTA: - store->w_int(store, b->data.sa[0]); - store->w_int(store, b->data.sa[1]); - break; - case VAR_VOIDPTR: - default: - assert(!"invalid variant type in connection"); - } -} - -boolean b_transparent(const connection * b, const struct faction * f) { unused(b); unused(f); return true; } -boolean b_opaque(const connection * b, const struct faction * f) { unused(b); unused(f); return false; } -boolean b_blockall(const connection * b, const unit * u, const region * r) { unused(u); unused(r); unused(b); return true; } -boolean b_blocknone(const connection * b, const unit * u, const region * r) { unused(u); unused(r); unused(b); return false; } -boolean b_rvisible(const connection * b, const region * r) { return (boolean)(b->to==r || b->from==r); } -boolean b_fvisible(const connection * b, const struct faction * f, const region * r) { unused(r); unused(f); unused(b); return true; } -boolean b_uvisible(const connection * b, const unit * u) { unused(u); unused(b); return true; } -boolean b_rinvisible(const connection * b, const region * r) { unused(r); unused(b); return false; } -boolean b_finvisible(const connection * b, const struct faction * f, const region * r) { unused(r); unused(f); unused(b); return false; } -boolean b_uinvisible(const connection * b, const unit * u) { unused(u); unused(b); return false; } - -/**************************************/ -/* at_countdown - legacy, do not use */ -/**************************************/ - -attrib_type at_countdown = { - "countdown", - DEFAULT_INIT, - DEFAULT_FINALIZE, - NULL, - NULL, - a_readint -}; - -void -age_borders(void) -{ - border_list * deleted = NULL; - int i; - - for (i=0;i!=BORDER_MAXHASH;++i) { - connection * bhash = borders[i]; - for (;bhash;bhash=bhash->nexthash) { - connection * b = bhash; - for (;b;b=b->next) { - if (b->type->age) { - if (b->type->age(b)==AT_AGE_REMOVE) { - border_list * kill = malloc(sizeof(border_list)); - kill->data = b; - kill->next = deleted; - deleted = kill; - } - } - } - } - } - while (deleted) { - border_list * blist = deleted->next; - connection * b = deleted->data; - erase_border(b); - free(deleted); - deleted = blist; - } -} - -/******** - * implementation of a couple of borders. this shouldn't really be in here, so - * let's keep it separate from the more general stuff above - ********/ - -#include "faction.h" - -static const char * -b_namewall(const connection * b, const region * r, const struct faction * f, int gflags) -{ - const char * bname = "wall"; - - unused(f); - unused(r); - unused(b); - if (gflags & GF_ARTICLE) bname = "a_wall"; - if (gflags & GF_PURE) return bname; - return LOC(f->locale, mkname("border", bname)); -} - -border_type bt_wall = { - "wall", VAR_INT, - b_opaque, - NULL, /* init */ - NULL, /* destroy */ - b_read, /* read */ - b_write, /* write */ - b_blockall, /* block */ - b_namewall, /* name */ - b_rvisible, /* rvisible */ - b_fvisible, /* fvisible */ - b_uvisible, /* uvisible */ -}; - -border_type bt_noway = { - "noway", VAR_INT, - b_transparent, - NULL, /* init */ - NULL, /* destroy */ - b_read, /* read */ - b_write, /* write */ - b_blockall, /* block */ - NULL, /* name */ - b_rinvisible, /* rvisible */ - b_finvisible, /* fvisible */ - b_uinvisible, /* uvisible */ -}; - -static const char * -b_namefogwall(const connection * b, const region * r, const struct faction * f, int gflags) -{ - unused(f); - unused(b); - unused(r); - if (gflags & GF_PURE) return "fogwall"; - if (gflags & GF_ARTICLE) return LOC(f->locale, mkname("border", "a_fogwall")); - return LOC(f->locale, mkname("border", "fogwall")); -} - -static boolean -b_blockfogwall(const connection * b, const unit * u, const region * r) -{ - unused(b); - unused(r); - if (!u) return true; - return (boolean)(effskill(u, SK_PERCEPTION) > 4); /* Das ist die alte Nebelwand */ -} - -/** Legacy type used in old Eressea games, no longer in use. */ -border_type bt_fogwall = { - "fogwall", VAR_INT, - b_transparent, /* transparent */ - NULL, /* init */ - NULL, /* destroy */ - b_read, /* read */ - b_write, /* write */ - b_blockfogwall, /* block */ - b_namefogwall, /* name */ - b_rvisible, /* rvisible */ - b_fvisible, /* fvisible */ - b_uvisible, /* uvisible */ -}; - -static const char * -b_nameillusionwall(const connection * b, const region * r, const struct faction * f, int gflags) -{ - int fno = b->data.i; - unused(b); - unused(r); - if (gflags & GF_PURE) return (f && fno==f->no)?"illusionwall":"wall"; - if (gflags & GF_ARTICLE) { - return LOC(f->locale, mkname("border", (f && fno==f->subscription)?"an_illusionwall":"a_wall")); - } - return LOC(f->locale, mkname("border", (f && fno==f->no)?"illusionwall":"wall")); -} - -border_type bt_illusionwall = { - "illusionwall", VAR_INT, - b_opaque, - NULL, /* init */ - NULL, /* destroy */ - b_read, /* read */ - b_write, /* write */ - b_blocknone, /* block */ - b_nameillusionwall, /* name */ - b_rvisible, /* rvisible */ - b_fvisible, /* fvisible */ - b_uvisible, /* uvisible */ -}; - -/*** - * special quest door - ***/ - -boolean b_blockquestportal(const connection * b, const unit * u, const region * r) { - if(b->data.i > 0) return true; - return false; -} - -static const char * -b_namequestportal(const connection * b, const region * r, const struct faction * f, int gflags) -{ - const char * bname; - int lock = b->data.i; - unused(b); - unused(r); - - if (gflags & GF_ARTICLE) { - if (lock > 0) { - bname = "a_gate_locked"; - } else { - bname = "a_gate_open"; - } - } else { - if (lock > 0) { - bname = "gate_locked"; - } else { - bname = "gate_open"; - } - } - if (gflags & GF_PURE) return bname; - return LOC(f->locale, mkname("border", bname)); -} - -border_type bt_questportal = { - "questportal", VAR_INT, - b_opaque, - NULL, /* init */ - NULL, /* destroy */ - b_read, /* read */ - b_write, /* write */ - b_blockquestportal, /* block */ - b_namequestportal, /* name */ - b_rvisible, /* rvisible */ - b_fvisible, /* fvisible */ - b_uvisible, /* uvisible */ -}; - -/*** - * roads. meant to replace the old at_road or r->road attribute - ***/ - -static const char * -b_nameroad(const connection * b, const region * r, const struct faction * f, int gflags) -{ - region * r2 = (r==b->to)?b->from:b->to; - int local = (r==b->from)?b->data.sa[0]:b->data.sa[1]; - static char buffer[64]; - - unused(f); - if (gflags & GF_PURE) return "road"; - if (gflags & GF_ARTICLE) { - if (!(gflags & GF_DETAILED)) return LOC(f->locale, mkname("border", "a_road")); - else if (r->terrain->max_road<=local) { - int remote = (r2==b->from)?b->data.sa[0]:b->data.sa[1]; - if (r2->terrain->max_road<=remote) { - return LOC(f->locale, mkname("border", "a_road")); - } else { - return LOC(f->locale, mkname("border", "an_incomplete_road")); - } - } else { - int percent = MAX(1, 100*local/r->terrain->max_road); - if (local) { - snprintf(buffer, sizeof(buffer), LOC(f->locale, mkname("border", "a_road_percent")), percent); - } else { - return LOC(f->locale, mkname("border", "a_road_connection")); - } - } - } - else if (gflags & GF_PLURAL) return LOC(f->locale, mkname("border", "roads")); - else return LOC(f->locale, mkname("border", "road")); - return buffer; -} - -static void -b_readroad(connection * b, storage * store) -{ - b->data.sa[0] = (short)store->r_int(store); - b->data.sa[1] = (short)store->r_int(store); -} - -static void -b_writeroad(const connection * b, storage * store) -{ - store->w_int(store, b->data.sa[0]); - store->w_int(store, b->data.sa[1]); -} - -static boolean -b_validroad(const connection * b) -{ - if (b->data.sa[0]==SHRT_MAX) return false; - return true; -} - -static boolean -b_rvisibleroad(const connection * b, const region * r) -{ - int x = b->data.i; - x = (r==b->from)?b->data.sa[0]:b->data.sa[1]; - if (x==0) { - return false; - } - if (b->to!=r && b->from!=r) { - return false; - } - return true; -} - -border_type bt_road = { - "road", VAR_INT, - b_transparent, - NULL, /* init */ - NULL, /* destroy */ - b_readroad, /* read */ - b_writeroad, /* write */ - b_blocknone, /* block */ - b_nameroad, /* name */ - b_rvisibleroad, /* rvisible */ - b_finvisible, /* fvisible */ - b_uinvisible, /* uvisible */ - b_validroad /* valid */ -}; - -void -write_borders(struct storage * store) -{ - int i; - for (i=0;i!=BORDER_MAXHASH;++i) { - connection * bhash; - for (bhash=borders[i];bhash;bhash=bhash->nexthash) { - connection * b; - for (b=bhash;b!=NULL;b=b->next) { - if (b->type->valid && !b->type->valid(b)) continue; - store->w_tok(store, b->type->__name); - store->w_int(store, b->id); - store->w_int(store, b->from->uid); - store->w_int(store, b->to->uid); - - if (b->type->write) b->type->write(b, store); - store->w_brk(store); - } - } - } - store->w_tok(store, "end"); -} - -int -read_borders(struct storage * store) -{ - for (;;) { - unsigned int bid = 0; - char zText[32]; - connection * b; - region * from, * to; - border_type * type; - - store->r_tok_buf(store, zText, sizeof(zText)); - if (!strcmp(zText, "end")) break; - bid = store->r_int(store); - if (store->versionr_int(store); - fy = (short)store->r_int(store); - tx = (short)store->r_int(store); - ty = (short)store->r_int(store); - from = findregion(fx, fy); - to = findregion(tx, ty); - } else { - unsigned int fid = (unsigned int)store->r_int(store); - unsigned int tid = (unsigned int)store->r_int(store); - from = findregionbyid(fid); - to = findregionbyid(tid); - } - - type = find_bordertype(zText); - if (type==NULL) { - log_error(("[read_borders] unknown connection type %s in %s\n", zText, - regionname(from, NULL))); - assert(type || !"connection type not registered"); - } - - if (to==from && type && from) { - direction_t dir = (direction_t) (rng_int() % MAXDIRECTIONS); - region * r = rconnect(from, dir); - log_error(("[read_borders] invalid %s in %s\n", type->__name, - regionname(from, NULL))); - if (r!=NULL) to = r; - } - b = new_border(type, from, to); - nextborder--; /* new_border erhöht den Wert */ - b->id = bid; - assert(bid<=nextborder); - if (type->read) type->read(b, store); - if (store->version + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "connection.h" + +#include "region.h" +#include "save.h" +#include "terrain.h" +#include "unit.h" +#include "version.h" + +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +unsigned int nextborder = 0; + +#define BORDER_MAXHASH 8191 +connection * borders[BORDER_MAXHASH]; +border_type * bordertypes; + +void (*border_convert_cb)(struct connection * con, struct attrib * attr) = 0; + +void +free_borders(void) +{ + int i; + for (i=0;i!=BORDER_MAXHASH;++i) { + while (borders[i]) { + connection * b = borders[i]; + borders[i] = b->nexthash; + while (b) { + connection * bf = b; + b = b->next; + assert(b==NULL || b->nexthash==NULL); + if (bf->type->destroy) { + bf->type->destroy(bf); + } + free(bf); + } + } + } +} + +connection * +find_border(unsigned int id) +{ + int key; + for (key=0;key!=BORDER_MAXHASH;key++) { + connection * bhash; + for (bhash=borders[key];bhash!=NULL;bhash=bhash->nexthash) { + connection * b; + for (b=bhash;b;b=b->next) { + if (b->id==id) return b; + } + } + } + return NULL; +} + +int +resolve_borderid(variant id, void * addr) +{ + int result = 0; + connection * b = NULL; + if (id.i!=0) { + b = find_border(id.i); + if (b==NULL) { + result = -1; + } + } + *(connection**)addr = b; + return result; +} + +static connection ** +get_borders_i(const region * r1, const region * r2) +{ + connection ** bp; + int key = reg_hashkey(r1); + int k2 = reg_hashkey(r2); + + key = MIN(k2, key) % BORDER_MAXHASH; + bp = &borders[key]; + while (*bp) { + connection * b = *bp; + if ((b->from==r1 && b->to==r2) || (b->from==r2 && b->to==r1)) break; + bp = &b->nexthash; + } + return bp; +} + +connection * +get_borders(const region * r1, const region * r2) +{ + connection ** bp = get_borders_i(r1, r2); + return *bp; +} + +connection * +new_border(border_type * type, region * from, region * to) +{ + connection * b = calloc(1, sizeof(struct connection)); + + if (from && to) { + connection ** bp = get_borders_i(from, to); + while (*bp) bp = &(*bp)->next; + *bp = b; + } + b->type = type; + b->from = from; + b->to = to; + b->id = ++nextborder; + + if (type->init) type->init(b); + return b; +} + +void +erase_border(connection * b) +{ + if (b->from && b->to) { + connection ** bp = get_borders_i(b->from, b->to); + assert(*bp!=NULL || !"error: connection is not registered"); + if (*bp==b) { + /* it is the first in the list, so it is in the nexthash list */ + if (b->next) { + *bp = b->next; + (*bp)->nexthash = b->nexthash; + } else { + *bp = b->nexthash; + } + } else { + while (*bp && *bp != b) { + bp = &(*bp)->next; + } + assert(*bp==b || !"error: connection is not registered"); + *bp = b->next; + } + } + if (b->type->destroy) { + b->type->destroy(b); + } + free(b); +} + +void +register_bordertype(border_type * type) +{ + border_type ** btp = &bordertypes; + + while (*btp && *btp!=type) btp = &(*btp)->next; + if (*btp) return; + *btp = type; +} + + +border_type * +find_bordertype(const char * name) +{ + border_type * bt = bordertypes; + + while (bt && strcmp(bt->__name, name)) bt = bt->next; + return bt; +} + +void +b_read(connection * b, storage * store) +{ + int result = 0; + switch (b->type->datatype) { + case VAR_NONE: + case VAR_INT: + b->data.i = store->r_int(store); + break; + case VAR_SHORTA: + b->data.sa[0] = (short)store->r_int(store); + b->data.sa[1] = (short)store->r_int(store); + break; + case VAR_VOIDPTR: + default: + assert(!"invalid variant type in connection"); + result = 0; + } + assert(result>=0 || "EOF encountered?"); +} + +void +b_write(const connection * b, storage * store) +{ + switch (b->type->datatype) { + case VAR_NONE: + case VAR_INT: + store->w_int(store, b->data.i); + break; + case VAR_SHORTA: + store->w_int(store, b->data.sa[0]); + store->w_int(store, b->data.sa[1]); + break; + case VAR_VOIDPTR: + default: + assert(!"invalid variant type in connection"); + } +} + +boolean b_transparent(const connection * b, const struct faction * f) { unused(b); unused(f); return true; } +boolean b_opaque(const connection * b, const struct faction * f) { unused(b); unused(f); return false; } +boolean b_blockall(const connection * b, const unit * u, const region * r) { unused(u); unused(r); unused(b); return true; } +boolean b_blocknone(const connection * b, const unit * u, const region * r) { unused(u); unused(r); unused(b); return false; } +boolean b_rvisible(const connection * b, const region * r) { return (boolean)(b->to==r || b->from==r); } +boolean b_fvisible(const connection * b, const struct faction * f, const region * r) { unused(r); unused(f); unused(b); return true; } +boolean b_uvisible(const connection * b, const unit * u) { unused(u); unused(b); return true; } +boolean b_rinvisible(const connection * b, const region * r) { unused(r); unused(b); return false; } +boolean b_finvisible(const connection * b, const struct faction * f, const region * r) { unused(r); unused(f); unused(b); return false; } +boolean b_uinvisible(const connection * b, const unit * u) { unused(u); unused(b); return false; } + +/**************************************/ +/* at_countdown - legacy, do not use */ +/**************************************/ + +attrib_type at_countdown = { + "countdown", + DEFAULT_INIT, + DEFAULT_FINALIZE, + NULL, + NULL, + a_readint +}; + +void +age_borders(void) +{ + border_list * deleted = NULL; + int i; + + for (i=0;i!=BORDER_MAXHASH;++i) { + connection * bhash = borders[i]; + for (;bhash;bhash=bhash->nexthash) { + connection * b = bhash; + for (;b;b=b->next) { + if (b->type->age) { + if (b->type->age(b)==AT_AGE_REMOVE) { + border_list * kill = malloc(sizeof(border_list)); + kill->data = b; + kill->next = deleted; + deleted = kill; + } + } + } + } + } + while (deleted) { + border_list * blist = deleted->next; + connection * b = deleted->data; + erase_border(b); + free(deleted); + deleted = blist; + } +} + +/******** + * implementation of a couple of borders. this shouldn't really be in here, so + * let's keep it separate from the more general stuff above + ********/ + +#include "faction.h" + +static const char * +b_namewall(const connection * b, const region * r, const struct faction * f, int gflags) +{ + const char * bname = "wall"; + + unused(f); + unused(r); + unused(b); + if (gflags & GF_ARTICLE) bname = "a_wall"; + if (gflags & GF_PURE) return bname; + return LOC(f->locale, mkname("border", bname)); +} + +border_type bt_wall = { + "wall", VAR_INT, + b_opaque, + NULL, /* init */ + NULL, /* destroy */ + b_read, /* read */ + b_write, /* write */ + b_blockall, /* block */ + b_namewall, /* name */ + b_rvisible, /* rvisible */ + b_fvisible, /* fvisible */ + b_uvisible, /* uvisible */ +}; + +border_type bt_noway = { + "noway", VAR_INT, + b_transparent, + NULL, /* init */ + NULL, /* destroy */ + b_read, /* read */ + b_write, /* write */ + b_blockall, /* block */ + NULL, /* name */ + b_rinvisible, /* rvisible */ + b_finvisible, /* fvisible */ + b_uinvisible, /* uvisible */ +}; + +static const char * +b_namefogwall(const connection * b, const region * r, const struct faction * f, int gflags) +{ + unused(f); + unused(b); + unused(r); + if (gflags & GF_PURE) return "fogwall"; + if (gflags & GF_ARTICLE) return LOC(f->locale, mkname("border", "a_fogwall")); + return LOC(f->locale, mkname("border", "fogwall")); +} + +static boolean +b_blockfogwall(const connection * b, const unit * u, const region * r) +{ + unused(b); + unused(r); + if (!u) return true; + return (boolean)(effskill(u, SK_PERCEPTION) > 4); /* Das ist die alte Nebelwand */ +} + +/** Legacy type used in old Eressea games, no longer in use. */ +border_type bt_fogwall = { + "fogwall", VAR_INT, + b_transparent, /* transparent */ + NULL, /* init */ + NULL, /* destroy */ + b_read, /* read */ + b_write, /* write */ + b_blockfogwall, /* block */ + b_namefogwall, /* name */ + b_rvisible, /* rvisible */ + b_fvisible, /* fvisible */ + b_uvisible, /* uvisible */ +}; + +static const char * +b_nameillusionwall(const connection * b, const region * r, const struct faction * f, int gflags) +{ + int fno = b->data.i; + unused(b); + unused(r); + if (gflags & GF_PURE) return (f && fno==f->no)?"illusionwall":"wall"; + if (gflags & GF_ARTICLE) { + return LOC(f->locale, mkname("border", (f && fno==f->subscription)?"an_illusionwall":"a_wall")); + } + return LOC(f->locale, mkname("border", (f && fno==f->no)?"illusionwall":"wall")); +} + +border_type bt_illusionwall = { + "illusionwall", VAR_INT, + b_opaque, + NULL, /* init */ + NULL, /* destroy */ + b_read, /* read */ + b_write, /* write */ + b_blocknone, /* block */ + b_nameillusionwall, /* name */ + b_rvisible, /* rvisible */ + b_fvisible, /* fvisible */ + b_uvisible, /* uvisible */ +}; + +/*** + * special quest door + ***/ + +boolean b_blockquestportal(const connection * b, const unit * u, const region * r) { + if(b->data.i > 0) return true; + return false; +} + +static const char * +b_namequestportal(const connection * b, const region * r, const struct faction * f, int gflags) +{ + const char * bname; + int lock = b->data.i; + unused(b); + unused(r); + + if (gflags & GF_ARTICLE) { + if (lock > 0) { + bname = "a_gate_locked"; + } else { + bname = "a_gate_open"; + } + } else { + if (lock > 0) { + bname = "gate_locked"; + } else { + bname = "gate_open"; + } + } + if (gflags & GF_PURE) return bname; + return LOC(f->locale, mkname("border", bname)); +} + +border_type bt_questportal = { + "questportal", VAR_INT, + b_opaque, + NULL, /* init */ + NULL, /* destroy */ + b_read, /* read */ + b_write, /* write */ + b_blockquestportal, /* block */ + b_namequestportal, /* name */ + b_rvisible, /* rvisible */ + b_fvisible, /* fvisible */ + b_uvisible, /* uvisible */ +}; + +/*** + * roads. meant to replace the old at_road or r->road attribute + ***/ + +static const char * +b_nameroad(const connection * b, const region * r, const struct faction * f, int gflags) +{ + region * r2 = (r==b->to)?b->from:b->to; + int local = (r==b->from)?b->data.sa[0]:b->data.sa[1]; + static char buffer[64]; + + unused(f); + if (gflags & GF_PURE) return "road"; + if (gflags & GF_ARTICLE) { + if (!(gflags & GF_DETAILED)) return LOC(f->locale, mkname("border", "a_road")); + else if (r->terrain->max_road<=local) { + int remote = (r2==b->from)?b->data.sa[0]:b->data.sa[1]; + if (r2->terrain->max_road<=remote) { + return LOC(f->locale, mkname("border", "a_road")); + } else { + return LOC(f->locale, mkname("border", "an_incomplete_road")); + } + } else { + int percent = MAX(1, 100*local/r->terrain->max_road); + if (local) { + snprintf(buffer, sizeof(buffer), LOC(f->locale, mkname("border", "a_road_percent")), percent); + } else { + return LOC(f->locale, mkname("border", "a_road_connection")); + } + } + } + else if (gflags & GF_PLURAL) return LOC(f->locale, mkname("border", "roads")); + else return LOC(f->locale, mkname("border", "road")); + return buffer; +} + +static void +b_readroad(connection * b, storage * store) +{ + b->data.sa[0] = (short)store->r_int(store); + b->data.sa[1] = (short)store->r_int(store); +} + +static void +b_writeroad(const connection * b, storage * store) +{ + store->w_int(store, b->data.sa[0]); + store->w_int(store, b->data.sa[1]); +} + +static boolean +b_validroad(const connection * b) +{ + if (b->data.sa[0]==SHRT_MAX) return false; + return true; +} + +static boolean +b_rvisibleroad(const connection * b, const region * r) +{ + int x = b->data.i; + x = (r==b->from)?b->data.sa[0]:b->data.sa[1]; + if (x==0) { + return false; + } + if (b->to!=r && b->from!=r) { + return false; + } + return true; +} + +border_type bt_road = { + "road", VAR_INT, + b_transparent, + NULL, /* init */ + NULL, /* destroy */ + b_readroad, /* read */ + b_writeroad, /* write */ + b_blocknone, /* block */ + b_nameroad, /* name */ + b_rvisibleroad, /* rvisible */ + b_finvisible, /* fvisible */ + b_uinvisible, /* uvisible */ + b_validroad /* valid */ +}; + +void +write_borders(struct storage * store) +{ + int i; + for (i=0;i!=BORDER_MAXHASH;++i) { + connection * bhash; + for (bhash=borders[i];bhash;bhash=bhash->nexthash) { + connection * b; + for (b=bhash;b!=NULL;b=b->next) { + if (b->type->valid && !b->type->valid(b)) continue; + store->w_tok(store, b->type->__name); + store->w_int(store, b->id); + store->w_int(store, b->from->uid); + store->w_int(store, b->to->uid); + + if (b->type->write) b->type->write(b, store); + store->w_brk(store); + } + } + } + store->w_tok(store, "end"); +} + +int +read_borders(struct storage * store) +{ + for (;;) { + unsigned int bid = 0; + char zText[32]; + connection * b; + region * from, * to; + border_type * type; + + store->r_tok_buf(store, zText, sizeof(zText)); + if (!strcmp(zText, "end")) break; + bid = store->r_int(store); + if (store->versionr_int(store); + fy = (short)store->r_int(store); + tx = (short)store->r_int(store); + ty = (short)store->r_int(store); + from = findregion(fx, fy); + to = findregion(tx, ty); + } else { + unsigned int fid = (unsigned int)store->r_int(store); + unsigned int tid = (unsigned int)store->r_int(store); + from = findregionbyid(fid); + to = findregionbyid(tid); + } + + type = find_bordertype(zText); + if (type==NULL) { + log_error(("[read_borders] unknown connection type %s in %s\n", zText, + regionname(from, NULL))); + assert(type || !"connection type not registered"); + } + + if (to==from && type && from) { + direction_t dir = (direction_t) (rng_int() % MAXDIRECTIONS); + region * r = rconnect(from, dir); + log_error(("[read_borders] invalid %s in %s\n", type->__name, + regionname(from, NULL))); + if (r!=NULL) to = r; + } + b = new_border(type, from, to); + nextborder--; /* new_border erhöht den Wert */ + b->id = bid; + assert(bid<=nextborder); + if (type->read) type->read(b, store); + if (store->version - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_BORDER -#define H_KRNL_BORDER - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - extern unsigned int nextborder; - - typedef struct connection { - struct border_type * type; /* the type of this connection */ - struct connection * next; /* next connection between these regions */ - struct connection * nexthash; /* next connection between these regions */ - struct region * from, * to; /* borders can be directed edges */ - variant data; - unsigned int id; /* unique id */ - } connection; - - typedef struct border_list { - struct border_list * next; - struct connection * data; - } border_list; - - typedef struct border_type { - const char* __name; /* internal use only */ - variant_type datatype; - boolean (*transparent)(const connection *, const struct faction *); - /* is it possible to see through this? */ - void (*init)(connection *); - /* constructor: initialize the connection. allocate extra memory if needed */ - void (*destroy)(connection *); - /* destructor: remove all extra memory for destruction */ - void (*read)(connection *, struct storage *); - void (*write)(const connection *, struct storage *); - boolean (*block)(const connection *, const struct unit *, const struct region * r); - /* return true if it blocks movement of u from - * r to the opposite struct region. - * warning: struct unit may be NULL. - */ - const char *(*name)(const connection * b, const struct region * r, const struct faction * f, int gflags); - /* for example "a wall of fog" or "a doorway from r1 to r2" - * may depend on the struct faction, for example "a wall" may - * turn out to be "an illusionary wall" - */ - boolean (*rvisible)(const connection *, const struct region *); - /* is it visible to everyone in r ? - * if not, it may still be fvisible() for some f. - */ - boolean (*fvisible)(const connection *, const struct faction *, const struct region *); - /* is it visible to units of f in r? - * the function shall not check for - * existence of a struct unit in r. Example: a spell - * may be visible only to the struct faction that created it and thus - * appear in it's report (if there is a struct unit of f in r, which - * the reporting function will have to assure). - * if not true, it may still be uvisible() for some u. - */ - boolean (*uvisible)(const connection *, const struct unit *); - /* is it visible to u ? - * a doorway may only be visible to a struct unit with perception > 5 - */ - boolean (*valid)(const connection *); - /* is the connection in a valid state, - * or should it be erased at the end of this turn to save space? - */ - struct region * (*move)(const connection *, struct unit * u, struct region * from, struct region * to, boolean routing); - /* executed when the units traverses this connection */ - int (*age)(struct connection *); - /* return 0 if connection needs to be removed. >0 if still aging, <0 if not aging */ - struct border_type * next; /* for internal use only */ - } border_type; - - - extern connection * find_border(unsigned int id); - int resolve_borderid(variant data, void * addr); - extern void free_borders(void); - - extern connection * get_borders(const struct region * r1, const struct region * r2); - /* returns the list of borders between r1 and r2 or r2 and r1 */ - extern connection * new_border(border_type * type, struct region * from, struct region * to); - /* creates a connection of the specified type */ - extern void erase_border(connection * b); - /* remove the connection from memory */ - extern border_type * find_bordertype(const char * name); - extern void register_bordertype(border_type * type); - /* register a new bordertype */ - - extern int read_borders(struct storage * store); - extern void write_borders(struct storage * store); - extern void age_borders(void); - - /* provide default implementations for some member functions: */ - extern void b_read(connection * b, struct storage * store); - extern void b_write(const connection * b, struct storage * store); - extern boolean b_blockall(const connection *, const struct unit *, const struct region *); - extern boolean b_blocknone(const connection *, const struct unit *, const struct region *); - extern boolean b_rvisible(const connection *, const struct region * r); - extern boolean b_fvisible(const connection *, const struct faction * f, const struct region *); - extern boolean b_uvisible(const connection *, const struct unit * u); - extern boolean b_rinvisible(const connection *, const struct region * r); - extern boolean b_finvisible(const connection *, const struct faction * f, const struct region *); - extern boolean b_uinvisible(const connection *, const struct unit * u); - extern boolean b_transparent(const connection *, const struct faction *); - extern boolean b_opaque(const connection *, const struct faction *); /* !transparent */ - - extern border_type bt_fogwall; - extern border_type bt_noway; - extern border_type bt_wall; - extern border_type bt_illusionwall; - extern border_type bt_road; - extern border_type bt_questportal; - - extern struct attrib_type at_countdown; - - /* game-specific callbacks */ - extern void (*border_convert_cb)(struct connection * con, struct attrib * attr); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_BORDER +#define H_KRNL_BORDER + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + extern unsigned int nextborder; + + typedef struct connection { + struct border_type * type; /* the type of this connection */ + struct connection * next; /* next connection between these regions */ + struct connection * nexthash; /* next connection between these regions */ + struct region * from, * to; /* borders can be directed edges */ + variant data; + unsigned int id; /* unique id */ + } connection; + + typedef struct border_list { + struct border_list * next; + struct connection * data; + } border_list; + + typedef struct border_type { + const char* __name; /* internal use only */ + variant_type datatype; + boolean (*transparent)(const connection *, const struct faction *); + /* is it possible to see through this? */ + void (*init)(connection *); + /* constructor: initialize the connection. allocate extra memory if needed */ + void (*destroy)(connection *); + /* destructor: remove all extra memory for destruction */ + void (*read)(connection *, struct storage *); + void (*write)(const connection *, struct storage *); + boolean (*block)(const connection *, const struct unit *, const struct region * r); + /* return true if it blocks movement of u from + * r to the opposite struct region. + * warning: struct unit may be NULL. + */ + const char *(*name)(const connection * b, const struct region * r, const struct faction * f, int gflags); + /* for example "a wall of fog" or "a doorway from r1 to r2" + * may depend on the struct faction, for example "a wall" may + * turn out to be "an illusionary wall" + */ + boolean (*rvisible)(const connection *, const struct region *); + /* is it visible to everyone in r ? + * if not, it may still be fvisible() for some f. + */ + boolean (*fvisible)(const connection *, const struct faction *, const struct region *); + /* is it visible to units of f in r? + * the function shall not check for + * existence of a struct unit in r. Example: a spell + * may be visible only to the struct faction that created it and thus + * appear in it's report (if there is a struct unit of f in r, which + * the reporting function will have to assure). + * if not true, it may still be uvisible() for some u. + */ + boolean (*uvisible)(const connection *, const struct unit *); + /* is it visible to u ? + * a doorway may only be visible to a struct unit with perception > 5 + */ + boolean (*valid)(const connection *); + /* is the connection in a valid state, + * or should it be erased at the end of this turn to save space? + */ + struct region * (*move)(const connection *, struct unit * u, struct region * from, struct region * to, boolean routing); + /* executed when the units traverses this connection */ + int (*age)(struct connection *); + /* return 0 if connection needs to be removed. >0 if still aging, <0 if not aging */ + struct border_type * next; /* for internal use only */ + } border_type; + + + extern connection * find_border(unsigned int id); + int resolve_borderid(variant data, void * addr); + extern void free_borders(void); + + extern connection * get_borders(const struct region * r1, const struct region * r2); + /* returns the list of borders between r1 and r2 or r2 and r1 */ + extern connection * new_border(border_type * type, struct region * from, struct region * to); + /* creates a connection of the specified type */ + extern void erase_border(connection * b); + /* remove the connection from memory */ + extern border_type * find_bordertype(const char * name); + extern void register_bordertype(border_type * type); + /* register a new bordertype */ + + extern int read_borders(struct storage * store); + extern void write_borders(struct storage * store); + extern void age_borders(void); + + /* provide default implementations for some member functions: */ + extern void b_read(connection * b, struct storage * store); + extern void b_write(const connection * b, struct storage * store); + extern boolean b_blockall(const connection *, const struct unit *, const struct region *); + extern boolean b_blocknone(const connection *, const struct unit *, const struct region *); + extern boolean b_rvisible(const connection *, const struct region * r); + extern boolean b_fvisible(const connection *, const struct faction * f, const struct region *); + extern boolean b_uvisible(const connection *, const struct unit * u); + extern boolean b_rinvisible(const connection *, const struct region * r); + extern boolean b_finvisible(const connection *, const struct faction * f, const struct region *); + extern boolean b_uinvisible(const connection *, const struct unit * u); + extern boolean b_transparent(const connection *, const struct faction *); + extern boolean b_opaque(const connection *, const struct faction *); /* !transparent */ + + extern border_type bt_fogwall; + extern border_type bt_noway; + extern border_type bt_wall; + extern border_type bt_illusionwall; + extern border_type bt_road; + extern border_type bt_questportal; + + extern struct attrib_type at_countdown; + + /* game-specific callbacks */ + extern void (*border_convert_cb)(struct connection * con, struct attrib * attr); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/curse.c b/src/kernel/curse.c index f660b2597..415308d2c 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -1,821 +1,821 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "curse.h" - -/* kernel includes */ -#include "building.h" -#include "faction.h" -#include "magic.h" -#include "message.h" -#include "objtypes.h" -#include "race.h" -#include "region.h" -#include "ship.h" -#include "skill.h" -#include "unit.h" -#include "version.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include - -#include - -#define MAXENTITYHASH 7919 -curse *cursehash[MAXENTITYHASH]; - -void -c_setflag(curse *c, unsigned int flags) -{ - assert(c); - c->flags = (c->flags & ~flags) | (flags & (c->type->flags ^ flags)); -} -/* -------------------------------------------------------------------------- */ -void -c_clearflag(curse *c, unsigned int flags) -{ - assert(c); - c->flags = (c->flags & ~flags) | (c->type->flags & flags); -} - -void -chash(curse *c) -{ - curse *old = cursehash[c->no %MAXENTITYHASH]; - - cursehash[c->no %MAXENTITYHASH] = c; - c->nexthash = old; -} - -static void -cunhash(curse *c) -{ - curse **show; - - for (show = &cursehash[c->no % MAXENTITYHASH]; *show; show = &(*show)->nexthash) { - if ((*show)->no == c->no) - break; - } - if (*show) { - assert(*show == c); - *show = (*show)->nexthash; - c->nexthash = 0; - } -} - -curse * -cfindhash(int i) -{ - curse *old; - - for (old = cursehash[i % MAXENTITYHASH]; old; old = old->nexthash) - if (old->no == i) - return old; - return NULL; -} - -/* ------------------------------------------------------------- */ -/* at_curse */ -void -curse_init(attrib * a) { - a->data.v = calloc(1, sizeof(curse)); -} - -int -curse_age(attrib * a) -{ - curse * c = (curse*)a->data.v; - int result = 0; - - if (c_flags(c) & CURSE_NOAGE) { - c->duration = INT_MAX; - } - if (c->type->age) { - result = c->type->age(c); - } - if (result!=0) { - c->duration = 0; - } else if (c->duration!=INT_MAX) { - c->duration = MAX(0, c->duration-1); - } - return c->duration; -} - -void -destroy_curse(curse * c) -{ - cunhash(c); - free(c); -} - -void -curse_done(attrib * a) { - destroy_curse((curse *)a->data.v); -} - -/** reads curses that have been removed from the code */ -static int -read_ccompat(const char * cursename, struct storage * store) -{ - struct compat { - const char * name; - const char * tokens; - } * seek, old_curses[] = { {"disorientationzone", ""}, {"shipdisorientation", ""}, { NULL, NULL } } ; - for (seek=old_curses;seek->name;++seek) { - if (strcmp(seek->tokens, cursename)==0) { - const char * p; - for (p=seek->name;p;++p) { - switch (*p) { - case 'd': store->r_int(store); break; - case 's': store->r_str(store); break; - case 't': store->r_tok(store); break; - case 'i': store->r_id(store); break; - case 'f': store->r_flt(store); break; - } - } - return 0; - } - } - return -1; -} - -int -curse_read(attrib * a, void * owner, struct storage * store) -{ - curse * c = (curse*)a->data.v; - int ur; - char cursename[64]; - unsigned int flags; - - c->no = store->r_int(store); - chash(c); - store->r_tok_buf(store, cursename, sizeof(cursename)); - flags = store->r_int(store); - c->duration = store->r_int(store); - if (store->version >= CURSEVIGOURISFLOAT_VERSION) { - c->vigour = store->r_flt(store); - } else { - int vigour = store->r_int(store); - c->vigour = vigour; - } - if (store->versionmagician, store, read_int, resolve_unit); - } else { - ur = read_reference(&c->magician, store, read_unit_reference, resolve_unit); - } - if (store->versioneffect = (double)store->r_int(store); - } else { - c->effect = store->r_flt(store); - } - c->type = ct_find(cursename); - if (c->type==NULL) { - int result = read_ccompat(cursename, store); - if (result!=0) { - log_error(("missing curse %s, no compatibility code either.\n", cursename)); - } - assert(result==0); - return AT_READ_FAIL; - } - if (store->version < CURSEFLAGS_VERSION) { - c_setflag(c, flags); - } else { - c->flags = flags; - } - c_clearflag(c, CURSE_ISNEW); - - if (c->type->read) c->type->read(store, c, owner); - else if (c->type->typ==CURSETYP_UNIT) { - c->data.i = store->r_int(store); - } - if (c->type->typ == CURSETYP_REGION) { - int rr = read_reference(&c->data.v, store, read_region_reference, RESOLVE_REGION(store->version)); - if (ur==0 && rr==0 && !c->data.v) { - return AT_READ_FAIL; - } - } - - return AT_READ_OK; -} - -void -curse_write(const attrib * a, const void * owner, struct storage * store) -{ - unsigned int flags; - curse * c = (curse*)a->data.v; - const curse_type * ct = c->type; - unit * mage = (c->magician && c->magician->number)?c->magician:NULL; - - /* copied from c_clearflag */ - flags = (c->flags & ~CURSE_ISNEW) | (c->type->flags & CURSE_ISNEW); - - store->w_int(store, c->no); - store->w_tok(store, ct->cname); - store->w_int(store, flags); - store->w_int(store, c->duration); - store->w_flt(store, (float)c->vigour); - write_unit_reference(mage, store); - store->w_flt(store, (float)c->effect); - - if (c->type->write) c->type->write(store, c, owner); - else if (c->type->typ == CURSETYP_UNIT) { - store->w_int(store, c->data.i); - } - if (c->type->typ == CURSETYP_REGION) { - write_region_reference((region*)c->data.v, store); - } -} - -attrib_type at_curse = -{ - "curse", - curse_init, - curse_done, - curse_age, - curse_write, - curse_read, - ATF_CURSE -}; -/* ------------------------------------------------------------- */ -/* Spruch identifizieren */ - -#include - -typedef struct cursetype_list { - struct cursetype_list * next; - const curse_type * type; -} cursetype_list; - -cursetype_list * cursetypes[256]; - -void -ct_register(const curse_type * ct) -{ - unsigned int hash = tolower(ct->cname[0]); - cursetype_list ** ctlp = &cursetypes[hash]; - - while (*ctlp) { - cursetype_list * ctl = *ctlp; - if (ctl->type==ct) return; - ctlp=&ctl->next; - } - *ctlp = calloc(1, sizeof(cursetype_list)); - (*ctlp)->type = ct; -} - -const curse_type * -ct_find(const char *c) -{ - unsigned int hash = tolower(c[0]); - cursetype_list * ctl = cursetypes[hash]; - while (ctl) { - if (strcmp(c, ctl->type->cname)==0) { - return ctl->type; - } else { - size_t k = MIN(strlen(c), strlen(ctl->type->cname)); - if (!strncasecmp(c, ctl->type->cname, k)) { - return ctl->type; - } - } - ctl = ctl->next; - } - return NULL; -} - -/* ------------------------------------------------------------- */ -/* get_curse identifiziert eine Verzauberung über die ID und gibt - * einen pointer auf die struct zurück. - */ - -boolean -cmp_curse(const attrib * a, const void * data) { - const curse * c = (const curse*)data; - if (a->type->flags & ATF_CURSE) { - if (!data || c == (curse*)a->data.v) return true; - } - return false; -} - -boolean -cmp_cursetype(const attrib * a, const void * data) -{ - const curse_type * ct = (const curse_type *)data; - if (a->type->flags & ATF_CURSE) { - if (!data || ct == ((curse*)a->data.v)->type) return true; - } - return false; -} - -curse * -get_cursex(attrib *ap, const curse_type * ctype, variant data, boolean(*compare)(const curse *, variant)) -{ - attrib * a = a_select(ap, ctype, cmp_cursetype); - while (a) { - curse * c = (curse*)a->data.v; - if (compare(c, data)) return c; - a = a_select(a->next, ctype, cmp_cursetype); - } - return NULL; -} - -curse * -get_curse(attrib *ap, const curse_type * ctype) -{ - attrib * a = ap; - while (a) { - if (a->type->flags & ATF_CURSE) { - const attrib_type * at = a->type; - while (a && a->type==at) { - curse* c = (curse *)a->data.v; - if (c->type==ctype) return c; - a = a->next; - } - } else { - a = a->nexttype; - } - } - return NULL; -} - -/* ------------------------------------------------------------- */ -/* findet einen curse global anhand seiner 'curse-Einheitnummer' */ - -curse * -findcurse(int cid) -{ - return cfindhash(cid); -} - -/* ------------------------------------------------------------- */ -void -remove_curse(attrib **ap, const curse *c) -{ - attrib *a = a_select(*ap, c, cmp_curse); - if (a) a_remove(ap, a); -} - -/* gibt die allgemeine Stärke der Verzauberung zurück. id2 wird wie - * oben benutzt. Dies ist nicht die Wirkung, sondern die Kraft und - * damit der gegen Antimagie wirkende Widerstand einer Verzauberung */ -static double -get_cursevigour(const curse *c) -{ - if (c) return c->vigour; - return 0; -} - -/* setzt die Stärke der Verzauberung auf i */ -static void -set_cursevigour(curse *c, double vigour) -{ - assert(c && vigour > 0); - c->vigour = vigour; -} - -/* verändert die Stärke der Verzauberung um +i und gibt die neue - * Stärke zurück. Sollte die Zauberstärke unter Null sinken, löst er - * sich auf. - */ -double -curse_changevigour(attrib **ap, curse *c, double vigour) -{ - vigour += get_cursevigour(c); - - if (vigour <= 0) { - remove_curse(ap, c); - vigour = 0; - } else { - set_cursevigour(c, vigour); - } - return vigour; -} - -/* ------------------------------------------------------------- */ - -double -curse_geteffect(const curse *c) -{ - if (c==NULL) return 0; - if (c_flags(c) & CURSE_ISNEW) return 0; - return c->effect; -} - -int -curse_geteffect_int(const curse *c) -{ - double effect = curse_geteffect(c); - assert(effect-(int)effect == 0); - return (int)effect; -} - -/* ------------------------------------------------------------- */ -static void -set_curseingmagician(struct unit *magician, struct attrib *ap_target, const curse_type *ct) -{ - curse * c = get_curse(ap_target, ct); - if (c) { - c->magician = magician; - } -} - -/* ------------------------------------------------------------- */ -/* gibt bei Personenbeschränkten Verzauberungen die Anzahl der - * betroffenen Personen zurück. Ansonsten wird 0 zurückgegeben. */ -int -get_cursedmen(unit *u, const curse *c) -{ - int cursedmen = u->number; - - if (!c) return 0; - - /* je nach curse_type andere data struct */ - if (c->type->typ == CURSETYP_UNIT) { - cursedmen = c->data.i; - } - - return MIN(u->number, cursedmen); -} - -/* setzt die Anzahl der betroffenen Personen auf cursedmen */ -static void -set_cursedmen(curse *c, int cursedmen) -{ - if (!c) return; - - /* je nach curse_type andere data struct */ - if (c->type->typ == CURSETYP_UNIT) { - c->data.i = cursedmen; - } -} - -/* ------------------------------------------------------------- */ -/* Legt eine neue Verzauberung an. Sollte es schon einen Zauber - * dieses Typs geben, gibt es den bestehenden zurück. - */ -static curse * -make_curse(unit *mage, attrib **ap, const curse_type *ct, double vigour, - int duration, double effect, int men) -{ - curse *c; - attrib * a; - - a = a_new(&at_curse); - a_add(ap, a); - c = (curse*)a->data.v; - - c->type = ct; - c->flags = 0; - c->vigour = vigour; - c->duration = duration; - c->effect = effect; - c->magician = mage; - - c->no = newunitid(); - chash(c); - - switch (c->type->typ) { - case CURSETYP_NORM: - break; - - case CURSETYP_UNIT: - { - c->data.i = men; - break; - } - - } - return c; -} - - -/* Mapperfunktion für das Anlegen neuer curse. Automatisch wird zum - * passenden Typ verzweigt und die relevanten Variablen weitergegeben. - */ -curse * -create_curse(unit *magician, attrib **ap, const curse_type *ct, double vigour, - int duration, double effect, int men) -{ - curse *c; - - /* die Kraft eines Spruchs darf nicht 0 sein*/ - assert(vigour > 0); - - c = get_curse(*ap, ct); - - if (c && (c_flags(c) & CURSE_ONLYONE)){ - return NULL; - } - assert(c==NULL || ct==c->type); - - /* es gibt schon eins diese Typs */ - if (c && ct->mergeflags != NO_MERGE) { - if(ct->mergeflags & M_DURATION){ - c->duration = MAX(c->duration, duration); - } - if(ct->mergeflags & M_SUMDURATION){ - c->duration += duration; - } - if(ct->mergeflags & M_SUMEFFECT){ - c->effect += effect; - } - if(ct->mergeflags & M_MAXEFFECT){ - c->effect = MAX(c->effect, effect); - } - if(ct->mergeflags & M_VIGOUR){ - c->vigour = MAX(vigour, c->vigour); - } - if(ct->mergeflags & M_VIGOUR_ADD){ - c->vigour = vigour + c->vigour; - } - if(ct->mergeflags & M_MEN){ - switch (ct->typ) { - case CURSETYP_UNIT: - { - c->data.i += men; - } - } - } - set_curseingmagician(magician, *ap, ct); - } else { - c = make_curse(magician, ap, ct, vigour, duration, effect, men); - } - return c; -} - -/* ------------------------------------------------------------- */ -/* hier müssen alle c-typen, die auf Einheiten gezaubert werden können, - * berücksichtigt werden */ - -static void -do_transfer_curse(curse *c, unit * u, unit * u2, int n) -{ - int cursedmen = 0; - int men = get_cursedmen(u, c); - boolean dogive = false; - const curse_type *ct = c->type; - - switch ((ct->flags | c->flags) & CURSE_SPREADMASK) { - case CURSE_SPREADALWAYS: - dogive = true; - men = u2->number + n; - break; - - case CURSE_SPREADMODULO: - { - int i; - int u_number = u->number; - for (i=0;i0;i++){ - if (rng_int()%u_number < cursedmen){ - ++men; - --cursedmen; - dogive = true; - } - --u_number; - } - break; - } - case CURSE_SPREADCHANCE: - if (chance(u2->number/(double)(u2->number + n))) { - men = u2->number + n; - dogive = true; - } - break; - case CURSE_SPREADNEVER: - break; - } - - if (dogive == true) { - curse * cnew = make_curse(c->magician, &u2->attribs, c->type, c->vigour, - c->duration, c->effect, men); - cnew->flags = c->flags; - - if (ct->typ == CURSETYP_UNIT) set_cursedmen(cnew, men); - } -} - -void -transfer_curse(unit * u, unit * u2, int n) -{ - attrib * a; - - a = a_find(u->attribs, &at_curse); - while (a && a->type==&at_curse) { - curse *c = (curse*)a->data.v; - do_transfer_curse(c, u, u2, n); - a = a->next; - } -} - -/* ------------------------------------------------------------- */ - -boolean -curse_active(const curse *c) -{ - if (!c) return false; - if (c_flags(c) & CURSE_ISNEW) return false; - if (c->vigour <= 0) return false; - - return true; -} - -boolean -is_cursed_internal(attrib *ap, const curse_type *ct) -{ - curse *c = get_curse(ap, ct); - - if (!c) - return false; - - return true; -} - - -boolean -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)) { - return true; - } - a = a->next; - } - - return false; -} -/* ------------------------------------------------------------- */ -/* cursedata */ -/* ------------------------------------------------------------- */ -/* - * typedef struct curse_type { - * const char *cname; (Name der Zauberwirkung, Identifizierung des curse) - * int typ; - * spread_t spread; - * unsigned int mergeflags; - * int (*curseinfo)(const struct locale*, const void*, int, curse*, int); - * void (*change_vigour)(curse*, double); - * int (*read)(struct storage * store, curse * c); - * int (*write)(struct storage * store, const curse * c); - * } curse_type; - */ - -int -resolve_curse(variant id, void * address) -{ - int result = 0; - curse * c = NULL; - if (id.i!=0) { - c = cfindhash(id.i); - if (c==NULL) { - result = -1; - } - } - *(curse**)address = c; - return result; -} - -static const char * oldnames[MAXCURSE] = { - /* OBS: when removing curses, remember to update read_ccompat() */ - "fogtrap", - "antimagiczone", - "farvision", - "gbdream", - "auraboost", - "maelstrom", - "blessedharvest", - "drought", - "badlearn", - "stormwind", - "flyingship", - "nodrift", - "depression", - "magicwalls", - "strongwall", - "astralblock", - "generous", - "peacezone", - "magicstreet", - "magicrunes", - "badmagicresistancezone", - "goodmagicresistancezone", - "slavery", - "calmmonster", - "oldrace", - "fumble", - "riotzone", - "nocostbuilding", - "godcursezone", - "speed", - "orcish", - "magicboost", - "insectfur", - "strength", - "worse", - "magicresistance", - "itemcloak", - "sparkle", - "skillmod" -}; - -const char * -oldcursename(int id) -{ - return oldnames[id]; -} - -/* ------------------------------------------------------------- */ -message * -cinfo_simple(const void * obj, typ_t typ, const struct curse *c, int self) -{ - struct message * msg; - - unused(typ); - unused(self); - unused(obj); - - msg = msg_message(mkname("curseinfo", c->type->cname), "id", c->no); - if (msg==NULL) { - log_error(("There is no curseinfo for %s.\n", c->type->cname)); - } - return msg; -} - - -/* ------------------------------------------------------------- */ -/* Antimagie - curse auflösen */ -/* ------------------------------------------------------------- */ - -/* Wenn der Curse schwächer ist als der cast_level, dann wird er -* aufgelöst, bzw seine Kraft (vigour) auf 0 gesetzt. -* Ist der cast_level zu gering, hat die Antimagie nur mit einer Chance -* von 100-20*Stufenunterschied % eine Wirkung auf den Curse. Dann wird -* die Kraft des Curse um die halbe Stärke der Antimagie reduziert. -* Zurückgegeben wird der noch unverbrauchte Rest von force. -*/ -double -destr_curse(curse* c, int cast_level, double force) -{ - if (cast_level < c->vigour) { /* Zauber ist nicht stark genug */ - double probability = 0.1 + (cast_level - c->vigour)*0.2; - /* pro Stufe Unterschied -20% */ - if (chance(probability)) { - force -= c->vigour; - if (c->type->change_vigour) { - c->type->change_vigour(c, -(cast_level+1/2)); - } else { - c->vigour -= cast_level+1/2; - } - } - } else { /* Zauber ist stärker als curse */ - if (force >= c->vigour) { /* reicht die Kraft noch aus? */ - force -= c->vigour; - if (c->type->change_vigour) { - c->type->change_vigour(c, -c->vigour); - } else { - c->vigour = 0; - } - - } - } - return force; -} - -#ifndef DISABLE_TESTS -#include "curse_test.c" -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "curse.h" + +/* kernel includes */ +#include "building.h" +#include "faction.h" +#include "magic.h" +#include "message.h" +#include "objtypes.h" +#include "race.h" +#include "region.h" +#include "ship.h" +#include "skill.h" +#include "unit.h" +#include "version.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include + +#include + +#define MAXENTITYHASH 7919 +curse *cursehash[MAXENTITYHASH]; + +void +c_setflag(curse *c, unsigned int flags) +{ + assert(c); + c->flags = (c->flags & ~flags) | (flags & (c->type->flags ^ flags)); +} +/* -------------------------------------------------------------------------- */ +void +c_clearflag(curse *c, unsigned int flags) +{ + assert(c); + c->flags = (c->flags & ~flags) | (c->type->flags & flags); +} + +void +chash(curse *c) +{ + curse *old = cursehash[c->no %MAXENTITYHASH]; + + cursehash[c->no %MAXENTITYHASH] = c; + c->nexthash = old; +} + +static void +cunhash(curse *c) +{ + curse **show; + + for (show = &cursehash[c->no % MAXENTITYHASH]; *show; show = &(*show)->nexthash) { + if ((*show)->no == c->no) + break; + } + if (*show) { + assert(*show == c); + *show = (*show)->nexthash; + c->nexthash = 0; + } +} + +curse * +cfindhash(int i) +{ + curse *old; + + for (old = cursehash[i % MAXENTITYHASH]; old; old = old->nexthash) + if (old->no == i) + return old; + return NULL; +} + +/* ------------------------------------------------------------- */ +/* at_curse */ +void +curse_init(attrib * a) { + a->data.v = calloc(1, sizeof(curse)); +} + +int +curse_age(attrib * a) +{ + curse * c = (curse*)a->data.v; + int result = 0; + + if (c_flags(c) & CURSE_NOAGE) { + c->duration = INT_MAX; + } + if (c->type->age) { + result = c->type->age(c); + } + if (result!=0) { + c->duration = 0; + } else if (c->duration!=INT_MAX) { + c->duration = MAX(0, c->duration-1); + } + return c->duration; +} + +void +destroy_curse(curse * c) +{ + cunhash(c); + free(c); +} + +void +curse_done(attrib * a) { + destroy_curse((curse *)a->data.v); +} + +/** reads curses that have been removed from the code */ +static int +read_ccompat(const char * cursename, struct storage * store) +{ + struct compat { + const char * name; + const char * tokens; + } * seek, old_curses[] = { {"disorientationzone", ""}, {"shipdisorientation", ""}, { NULL, NULL } } ; + for (seek=old_curses;seek->name;++seek) { + if (strcmp(seek->tokens, cursename)==0) { + const char * p; + for (p=seek->name;p;++p) { + switch (*p) { + case 'd': store->r_int(store); break; + case 's': store->r_str(store); break; + case 't': store->r_tok(store); break; + case 'i': store->r_id(store); break; + case 'f': store->r_flt(store); break; + } + } + return 0; + } + } + return -1; +} + +int +curse_read(attrib * a, void * owner, struct storage * store) +{ + curse * c = (curse*)a->data.v; + int ur; + char cursename[64]; + unsigned int flags; + + c->no = store->r_int(store); + chash(c); + store->r_tok_buf(store, cursename, sizeof(cursename)); + flags = store->r_int(store); + c->duration = store->r_int(store); + if (store->version >= CURSEVIGOURISFLOAT_VERSION) { + c->vigour = store->r_flt(store); + } else { + int vigour = store->r_int(store); + c->vigour = vigour; + } + if (store->versionmagician, store, read_int, resolve_unit); + } else { + ur = read_reference(&c->magician, store, read_unit_reference, resolve_unit); + } + if (store->versioneffect = (double)store->r_int(store); + } else { + c->effect = store->r_flt(store); + } + c->type = ct_find(cursename); + if (c->type==NULL) { + int result = read_ccompat(cursename, store); + if (result!=0) { + log_error(("missing curse %s, no compatibility code either.\n", cursename)); + } + assert(result==0); + return AT_READ_FAIL; + } + if (store->version < CURSEFLAGS_VERSION) { + c_setflag(c, flags); + } else { + c->flags = flags; + } + c_clearflag(c, CURSE_ISNEW); + + if (c->type->read) c->type->read(store, c, owner); + else if (c->type->typ==CURSETYP_UNIT) { + c->data.i = store->r_int(store); + } + if (c->type->typ == CURSETYP_REGION) { + int rr = read_reference(&c->data.v, store, read_region_reference, RESOLVE_REGION(store->version)); + if (ur==0 && rr==0 && !c->data.v) { + return AT_READ_FAIL; + } + } + + return AT_READ_OK; +} + +void +curse_write(const attrib * a, const void * owner, struct storage * store) +{ + unsigned int flags; + curse * c = (curse*)a->data.v; + const curse_type * ct = c->type; + unit * mage = (c->magician && c->magician->number)?c->magician:NULL; + + /* copied from c_clearflag */ + flags = (c->flags & ~CURSE_ISNEW) | (c->type->flags & CURSE_ISNEW); + + store->w_int(store, c->no); + store->w_tok(store, ct->cname); + store->w_int(store, flags); + store->w_int(store, c->duration); + store->w_flt(store, (float)c->vigour); + write_unit_reference(mage, store); + store->w_flt(store, (float)c->effect); + + if (c->type->write) c->type->write(store, c, owner); + else if (c->type->typ == CURSETYP_UNIT) { + store->w_int(store, c->data.i); + } + if (c->type->typ == CURSETYP_REGION) { + write_region_reference((region*)c->data.v, store); + } +} + +attrib_type at_curse = +{ + "curse", + curse_init, + curse_done, + curse_age, + curse_write, + curse_read, + ATF_CURSE +}; +/* ------------------------------------------------------------- */ +/* Spruch identifizieren */ + +#include + +typedef struct cursetype_list { + struct cursetype_list * next; + const curse_type * type; +} cursetype_list; + +cursetype_list * cursetypes[256]; + +void +ct_register(const curse_type * ct) +{ + unsigned int hash = tolower(ct->cname[0]); + cursetype_list ** ctlp = &cursetypes[hash]; + + while (*ctlp) { + cursetype_list * ctl = *ctlp; + if (ctl->type==ct) return; + ctlp=&ctl->next; + } + *ctlp = calloc(1, sizeof(cursetype_list)); + (*ctlp)->type = ct; +} + +const curse_type * +ct_find(const char *c) +{ + unsigned int hash = tolower(c[0]); + cursetype_list * ctl = cursetypes[hash]; + while (ctl) { + if (strcmp(c, ctl->type->cname)==0) { + return ctl->type; + } else { + size_t k = MIN(strlen(c), strlen(ctl->type->cname)); + if (!strncasecmp(c, ctl->type->cname, k)) { + return ctl->type; + } + } + ctl = ctl->next; + } + return NULL; +} + +/* ------------------------------------------------------------- */ +/* get_curse identifiziert eine Verzauberung über die ID und gibt + * einen pointer auf die struct zurück. + */ + +boolean +cmp_curse(const attrib * a, const void * data) { + const curse * c = (const curse*)data; + if (a->type->flags & ATF_CURSE) { + if (!data || c == (curse*)a->data.v) return true; + } + return false; +} + +boolean +cmp_cursetype(const attrib * a, const void * data) +{ + const curse_type * ct = (const curse_type *)data; + if (a->type->flags & ATF_CURSE) { + if (!data || ct == ((curse*)a->data.v)->type) return true; + } + return false; +} + +curse * +get_cursex(attrib *ap, const curse_type * ctype, variant data, boolean(*compare)(const curse *, variant)) +{ + attrib * a = a_select(ap, ctype, cmp_cursetype); + while (a) { + curse * c = (curse*)a->data.v; + if (compare(c, data)) return c; + a = a_select(a->next, ctype, cmp_cursetype); + } + return NULL; +} + +curse * +get_curse(attrib *ap, const curse_type * ctype) +{ + attrib * a = ap; + while (a) { + if (a->type->flags & ATF_CURSE) { + const attrib_type * at = a->type; + while (a && a->type==at) { + curse* c = (curse *)a->data.v; + if (c->type==ctype) return c; + a = a->next; + } + } else { + a = a->nexttype; + } + } + return NULL; +} + +/* ------------------------------------------------------------- */ +/* findet einen curse global anhand seiner 'curse-Einheitnummer' */ + +curse * +findcurse(int cid) +{ + return cfindhash(cid); +} + +/* ------------------------------------------------------------- */ +void +remove_curse(attrib **ap, const curse *c) +{ + attrib *a = a_select(*ap, c, cmp_curse); + if (a) a_remove(ap, a); +} + +/* gibt die allgemeine Stärke der Verzauberung zurück. id2 wird wie + * oben benutzt. Dies ist nicht die Wirkung, sondern die Kraft und + * damit der gegen Antimagie wirkende Widerstand einer Verzauberung */ +static double +get_cursevigour(const curse *c) +{ + if (c) return c->vigour; + return 0; +} + +/* setzt die Stärke der Verzauberung auf i */ +static void +set_cursevigour(curse *c, double vigour) +{ + assert(c && vigour > 0); + c->vigour = vigour; +} + +/* verändert die Stärke der Verzauberung um +i und gibt die neue + * Stärke zurück. Sollte die Zauberstärke unter Null sinken, löst er + * sich auf. + */ +double +curse_changevigour(attrib **ap, curse *c, double vigour) +{ + vigour += get_cursevigour(c); + + if (vigour <= 0) { + remove_curse(ap, c); + vigour = 0; + } else { + set_cursevigour(c, vigour); + } + return vigour; +} + +/* ------------------------------------------------------------- */ + +double +curse_geteffect(const curse *c) +{ + if (c==NULL) return 0; + if (c_flags(c) & CURSE_ISNEW) return 0; + return c->effect; +} + +int +curse_geteffect_int(const curse *c) +{ + double effect = curse_geteffect(c); + assert(effect-(int)effect == 0); + return (int)effect; +} + +/* ------------------------------------------------------------- */ +static void +set_curseingmagician(struct unit *magician, struct attrib *ap_target, const curse_type *ct) +{ + curse * c = get_curse(ap_target, ct); + if (c) { + c->magician = magician; + } +} + +/* ------------------------------------------------------------- */ +/* gibt bei Personenbeschränkten Verzauberungen die Anzahl der + * betroffenen Personen zurück. Ansonsten wird 0 zurückgegeben. */ +int +get_cursedmen(unit *u, const curse *c) +{ + int cursedmen = u->number; + + if (!c) return 0; + + /* je nach curse_type andere data struct */ + if (c->type->typ == CURSETYP_UNIT) { + cursedmen = c->data.i; + } + + return MIN(u->number, cursedmen); +} + +/* setzt die Anzahl der betroffenen Personen auf cursedmen */ +static void +set_cursedmen(curse *c, int cursedmen) +{ + if (!c) return; + + /* je nach curse_type andere data struct */ + if (c->type->typ == CURSETYP_UNIT) { + c->data.i = cursedmen; + } +} + +/* ------------------------------------------------------------- */ +/* Legt eine neue Verzauberung an. Sollte es schon einen Zauber + * dieses Typs geben, gibt es den bestehenden zurück. + */ +static curse * +make_curse(unit *mage, attrib **ap, const curse_type *ct, double vigour, + int duration, double effect, int men) +{ + curse *c; + attrib * a; + + a = a_new(&at_curse); + a_add(ap, a); + c = (curse*)a->data.v; + + c->type = ct; + c->flags = 0; + c->vigour = vigour; + c->duration = duration; + c->effect = effect; + c->magician = mage; + + c->no = newunitid(); + chash(c); + + switch (c->type->typ) { + case CURSETYP_NORM: + break; + + case CURSETYP_UNIT: + { + c->data.i = men; + break; + } + + } + return c; +} + + +/* Mapperfunktion für das Anlegen neuer curse. Automatisch wird zum + * passenden Typ verzweigt und die relevanten Variablen weitergegeben. + */ +curse * +create_curse(unit *magician, attrib **ap, const curse_type *ct, double vigour, + int duration, double effect, int men) +{ + curse *c; + + /* die Kraft eines Spruchs darf nicht 0 sein*/ + assert(vigour > 0); + + c = get_curse(*ap, ct); + + if (c && (c_flags(c) & CURSE_ONLYONE)){ + return NULL; + } + assert(c==NULL || ct==c->type); + + /* es gibt schon eins diese Typs */ + if (c && ct->mergeflags != NO_MERGE) { + if(ct->mergeflags & M_DURATION){ + c->duration = MAX(c->duration, duration); + } + if(ct->mergeflags & M_SUMDURATION){ + c->duration += duration; + } + if(ct->mergeflags & M_SUMEFFECT){ + c->effect += effect; + } + if(ct->mergeflags & M_MAXEFFECT){ + c->effect = MAX(c->effect, effect); + } + if(ct->mergeflags & M_VIGOUR){ + c->vigour = MAX(vigour, c->vigour); + } + if(ct->mergeflags & M_VIGOUR_ADD){ + c->vigour = vigour + c->vigour; + } + if(ct->mergeflags & M_MEN){ + switch (ct->typ) { + case CURSETYP_UNIT: + { + c->data.i += men; + } + } + } + set_curseingmagician(magician, *ap, ct); + } else { + c = make_curse(magician, ap, ct, vigour, duration, effect, men); + } + return c; +} + +/* ------------------------------------------------------------- */ +/* hier müssen alle c-typen, die auf Einheiten gezaubert werden können, + * berücksichtigt werden */ + +static void +do_transfer_curse(curse *c, unit * u, unit * u2, int n) +{ + int cursedmen = 0; + int men = get_cursedmen(u, c); + boolean dogive = false; + const curse_type *ct = c->type; + + switch ((ct->flags | c->flags) & CURSE_SPREADMASK) { + case CURSE_SPREADALWAYS: + dogive = true; + men = u2->number + n; + break; + + case CURSE_SPREADMODULO: + { + int i; + int u_number = u->number; + for (i=0;i0;i++){ + if (rng_int()%u_number < cursedmen){ + ++men; + --cursedmen; + dogive = true; + } + --u_number; + } + break; + } + case CURSE_SPREADCHANCE: + if (chance(u2->number/(double)(u2->number + n))) { + men = u2->number + n; + dogive = true; + } + break; + case CURSE_SPREADNEVER: + break; + } + + if (dogive == true) { + curse * cnew = make_curse(c->magician, &u2->attribs, c->type, c->vigour, + c->duration, c->effect, men); + cnew->flags = c->flags; + + if (ct->typ == CURSETYP_UNIT) set_cursedmen(cnew, men); + } +} + +void +transfer_curse(unit * u, unit * u2, int n) +{ + attrib * a; + + a = a_find(u->attribs, &at_curse); + while (a && a->type==&at_curse) { + curse *c = (curse*)a->data.v; + do_transfer_curse(c, u, u2, n); + a = a->next; + } +} + +/* ------------------------------------------------------------- */ + +boolean +curse_active(const curse *c) +{ + if (!c) return false; + if (c_flags(c) & CURSE_ISNEW) return false; + if (c->vigour <= 0) return false; + + return true; +} + +boolean +is_cursed_internal(attrib *ap, const curse_type *ct) +{ + curse *c = get_curse(ap, ct); + + if (!c) + return false; + + return true; +} + + +boolean +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)) { + return true; + } + a = a->next; + } + + return false; +} +/* ------------------------------------------------------------- */ +/* cursedata */ +/* ------------------------------------------------------------- */ +/* + * typedef struct curse_type { + * const char *cname; (Name der Zauberwirkung, Identifizierung des curse) + * int typ; + * spread_t spread; + * unsigned int mergeflags; + * int (*curseinfo)(const struct locale*, const void*, int, curse*, int); + * void (*change_vigour)(curse*, double); + * int (*read)(struct storage * store, curse * c); + * int (*write)(struct storage * store, const curse * c); + * } curse_type; + */ + +int +resolve_curse(variant id, void * address) +{ + int result = 0; + curse * c = NULL; + if (id.i!=0) { + c = cfindhash(id.i); + if (c==NULL) { + result = -1; + } + } + *(curse**)address = c; + return result; +} + +static const char * oldnames[MAXCURSE] = { + /* OBS: when removing curses, remember to update read_ccompat() */ + "fogtrap", + "antimagiczone", + "farvision", + "gbdream", + "auraboost", + "maelstrom", + "blessedharvest", + "drought", + "badlearn", + "stormwind", + "flyingship", + "nodrift", + "depression", + "magicwalls", + "strongwall", + "astralblock", + "generous", + "peacezone", + "magicstreet", + "magicrunes", + "badmagicresistancezone", + "goodmagicresistancezone", + "slavery", + "calmmonster", + "oldrace", + "fumble", + "riotzone", + "nocostbuilding", + "godcursezone", + "speed", + "orcish", + "magicboost", + "insectfur", + "strength", + "worse", + "magicresistance", + "itemcloak", + "sparkle", + "skillmod" +}; + +const char * +oldcursename(int id) +{ + return oldnames[id]; +} + +/* ------------------------------------------------------------- */ +message * +cinfo_simple(const void * obj, typ_t typ, const struct curse *c, int self) +{ + struct message * msg; + + unused(typ); + unused(self); + unused(obj); + + msg = msg_message(mkname("curseinfo", c->type->cname), "id", c->no); + if (msg==NULL) { + log_error(("There is no curseinfo for %s.\n", c->type->cname)); + } + return msg; +} + + +/* ------------------------------------------------------------- */ +/* Antimagie - curse auflösen */ +/* ------------------------------------------------------------- */ + +/* Wenn der Curse schwächer ist als der cast_level, dann wird er +* aufgelöst, bzw seine Kraft (vigour) auf 0 gesetzt. +* Ist der cast_level zu gering, hat die Antimagie nur mit einer Chance +* von 100-20*Stufenunterschied % eine Wirkung auf den Curse. Dann wird +* die Kraft des Curse um die halbe Stärke der Antimagie reduziert. +* Zurückgegeben wird der noch unverbrauchte Rest von force. +*/ +double +destr_curse(curse* c, int cast_level, double force) +{ + if (cast_level < c->vigour) { /* Zauber ist nicht stark genug */ + double probability = 0.1 + (cast_level - c->vigour)*0.2; + /* pro Stufe Unterschied -20% */ + if (chance(probability)) { + force -= c->vigour; + if (c->type->change_vigour) { + c->type->change_vigour(c, -(cast_level+1/2)); + } else { + c->vigour -= cast_level+1/2; + } + } + } else { /* Zauber ist stärker als curse */ + if (force >= c->vigour) { /* reicht die Kraft noch aus? */ + force -= c->vigour; + if (c->type->change_vigour) { + c->type->change_vigour(c, -c->vigour); + } else { + c->vigour = 0; + } + + } + } + return force; +} + +#ifndef DISABLE_TESTS +#include "curse_test.c" +#endif diff --git a/src/kernel/curse.h b/src/kernel/curse.h index 6c6621b5c..7adb53477 100644 --- a/src/kernel/curse.h +++ b/src/kernel/curse.h @@ -1,330 +1,330 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef CURSE_H -#define CURSE_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* Sprueche in der struct region und auf Einheiten, Schiffen oder Burgen - * (struct attribute) - */ - -/* Brainstorming Überarbeitung curse - * - * Ziel: Keine Enum-Liste, flexible, leicht erweiterbare Curse-Objekte - * - * Was wird gebraucht? - * - Eindeutige Kennung für globale Suche - * - eine Wirkung, die sich einfach 'anwenden' läßt, dabei flexibel ist, - * Raum läßt für variable Boni, Anzahl betroffener Personen, - * spezielle Effekte oder anderes - * - einfacher Zugriff auf allgemeine Funktionen wie zb Alterung, aber - * auch Antimagieverhalten - * - Ausgabe von Beschreibungen in verschiedenen Sprachen - * - definiertes gekapseltes Verhalten zb bei Zusammenlegung von - * Einheiten, Übergabe von Personen, Mehrfachverzauberung - * - (Rück-)Referenzen auf Objekt, Verursacher (Magier), ? - * - * Vieleicht wäre ein Wirkungsklassensystem sinnvoll, so das im übrigen - * source einfach alle curse-attribs abgefragt werden können und bei - * gewünschter Wirkungsklasse angewendet, also nicht für jeden curse - * spezielle Änderungen im übrigen source notwendig sind. - * - * Die (Wirkungs-)Typen sollten die wichtigen Funktionen speziell - * belegen können, zb Alterung, Ausgabetexte, Merge-Verhalten - * - * Was sind wichtige individuelle Eigenschaften? - * - Referenzen auf Objekt und Verursacher - * - Referenzen für globale Liste - * > die Wirkung: - * - Dauer - * - Widerstandskraft, zb gegen Antimagie - * - Seiteneffekte zb Flag ONLYONE, Unverträglichkeiten - * - Alterungsverhalten zb Flag NOAGE - * - Effektverhalten, zb Bonus (variabel) - * - bei Einheitenzaubern die Zahl der betroffenen Personen - * - * Dabei sind nur die beiden letzten Punkte wirklich reine individuelle - * Wirkung, die anderen sind eher allgemeine Kennzeichen eines jeden - * Curse, die individuell belegt sind. - * ONLYONE und NOAGE könnten auch Eigenschaften des Typs sein, nicht des - * individuellen curse. Allgemein ist Alterung wohl eher eine - * Typeigenschaft als die eines individuellen curse. - * Dagegen ist der Widerstand gegen Antimagie sowohl abhängig von der - * Güte des Verursachers, also des Magiers zum Zeitpunkt des Zaubers, - * als auch vom Typ, der gegen bestimmte Arten des 'Fluchbrechens' immun - * sein könnte. - * - * Was sind wichtige Typeigenschaften? - * - Verhalten bei Personenübergaben - * - allgemeine Wirkung - * - Beschreibungstexte - * - Verhalten bei Antimagie - * - Alterung - * - Speicherung des C-Objekts - * - Laden des C-Objekts - * - Erzeugen des C-Objekts - * - Löschen und Aufräumen des C-Objekts - * - Funktionen zur Änderung der Werte - * - * */ - -#include - -/* ------------------------------------------------------------- */ -/* Zauberwirkungen */ -/* nicht vergessen curse_type zu aktualisieren und Reihenfolge beachten! - */ - -enum { -/* struct's vom typ curse: */ - C_FOGTRAP, - C_ANTIMAGICZONE, - C_FARVISION, - C_GBDREAM, - C_AURA, - C_MAELSTROM, - C_BLESSEDHARVEST, - C_DROUGHT, - C_BADLEARN, - C_SHIP_SPEEDUP, /* 9 - Sturmwind-Zauber */ - C_SHIP_FLYING, /* 10 - Luftschiff-Zauber */ - C_SHIP_NODRIFT, /* 11 - GünstigeWinde-Zauber */ - C_DEPRESSION, - C_MAGICWALLS, /* 13 - Heimstein */ - C_STRONGWALL, /* 14 - Feste Mauer - Precombat*/ - C_ASTRALBLOCK, /* 15 - Astralblock */ - C_GENEROUS, /* 16 - Unterhaltung vermehren */ - C_PEACE, /* 17 - Regionsweit Attacken verhindern */ - C_MAGICSTREET, /* 19 - magisches Straßennetz */ - C_RESIST_MAGIC, /* 20 - verändert Magieresistenz von Objekten */ - C_SONG_BADMR, /* 21 - verändert Magieresistenz */ - C_SONG_GOODMR, /* 22 - verändert Magieresistenz */ - C_SLAVE, /* 23 - dient fremder Partei */ - C_CALM, /* 25 - Beinflussung */ - C_OLDRACE, - C_FUMBLE, - C_RIOT, /*region in Aufruhr */ - C_NOCOST, - C_CURSED_BY_THE_GODS, -/* struct's vom untertyp curse_unit: */ - C_SPEED, /* Beschleunigt */ - C_ORC, - C_MBOOST, - C_KAELTESCHUTZ, - C_STRENGTH, - C_ALLSKILLS, - C_MAGICRESISTANCE, /* 44 - verändert Magieresistenz */ - C_ITEMCLOAK, - C_SPARKLE, -/* struct's vom untertyp curse_skill: */ - C_SKILL, - MAXCURSE /* OBS: when removing curses, remember to update read_ccompat() */ -}; - -/* ------------------------------------------------------------- */ -/* Flags */ - - -/* Verhalten von Zaubern auf Units beim Übergeben von Personen */ -typedef enum { - CURSE_ISNEW = 0x01, /* wirkt in der zauberrunde nicht (default)*/ - CURSE_NOAGE = 0x02, /* wirkt ewig */ - CURSE_IMMUNE = 0x04, /* ignoriert Antimagie */ - CURSE_ONLYONE = 0x08, /* Verhindert, das ein weiterer Zauber dieser Art auf das Objekt gezaubert wird */ - - /* the following are mutually exclusive */ - CURSE_SPREADNEVER = 0x00, /* wird nie mit übertragen */ - CURSE_SPREADALWAYS = 0x10, /* wird immer mit übertragen */ - CURSE_SPREADMODULO = 0x20, /* personenweise weitergabe */ - CURSE_SPREADCHANCE = 0x30 /* Ansteckungschance je nach Mengenverhältnis*/ -} curseflags; - -#define CURSE_FLAGSMASK 0x0F -#define CURSE_SPREADMASK 0x30 - -/* typ von struct */ -enum { - CURSETYP_NORM, - CURSETYP_UNIT, - CURSETYP_REGION, /* stores the region in c->data.v */ - MAXCURSETYP -}; - -/* Verhalten beim Zusammenfassen mit einem schon bestehenden Zauber - * gleichen Typs */ - -#define NO_MERGE 0 /* erzeugt jedesmal einen neuen Zauber */ -#define M_DURATION 1 /* Die Zauberdauer ist die maximale Dauer beider */ -#define M_SUMDURATION 2 /* die Dauer des Zaubers wird summiert */ -#define M_MAXEFFECT 4 /* der Effekt ist der maximale Effekt beider */ -#define M_SUMEFFECT 8 /* der Effekt summiert sich */ -#define M_MEN 16 /* die Anzahl der betroffenen Personen summiert - sich */ -#define M_VIGOUR 32 /* das Maximum der beiden Stärken wird die - Stärke des neuen Zaubers */ -#define M_VIGOUR_ADD 64 /* Vigour wird addiert */ - -/* ------------------------------------------------------------- */ -/* Allgemeine Zauberwirkungen */ - -typedef struct curse { - struct curse *nexthash; - int no; /* 'Einheitennummer' dieses Curse */ - const struct curse_type * type; /* Zeiger auf ein curse_type-struct */ - unsigned int flags; /* WARNING: these are XORed with type->flags! */ - int duration; /* Dauer der Verzauberung. Wird jede Runde vermindert */ - double vigour; /* Stärke der Verzauberung, Widerstand gegen Antimagie */ - struct unit *magician; /* Pointer auf den Magier, der den Spruch gewirkt hat */ - double effect; - variant data; /* pointer auf spezielle curse-unterstructs*/ -} curse; - -#define c_flags(c) ((c)->type->flags ^ (c)->flags) - -/* ------------------------------------------------------------- */ - -typedef struct curse_type { - const char *cname; /* Name der Zauberwirkung, Identifizierung des curse */ - int typ; - unsigned int flags; - unsigned int mergeflags; - struct message * (*curseinfo)(const void*, typ_t, const struct curse*, int); - void (*change_vigour)(curse*, double); - int (*read)(struct storage * store, curse * c, void * target); - int (*write)(struct storage * store, const struct curse * c, const void * target); - int (*cansee)(const struct faction*, const void*, typ_t, const struct curse *, int); - int (*age)(curse *); -} curse_type; - -extern struct attrib_type at_curse; -void curse_write(const struct attrib * a, const void * owner, struct storage * store); -int curse_read(struct attrib * a, void * owner, struct storage * store); - - -/* ------------------------------------------------------------- */ -/* Kommentare: - * Bei einigen Typen von Verzauberungen (z.B.Skillmodif.) muss neben - * der curse-id noch ein weiterer Identifizierer angegeben werden (id2). - * - * Wenn der Typ korrekt definiert wurde, erfolgt die Verzweigung zum - * korrekten Typus automatisch, und die unterschiedlichen struct-typen - * sind nach aussen unsichtbar. - * -* allgemeine Funktionen * -*/ - -curse * create_curse(struct unit *magician, struct attrib**ap, const curse_type * ctype, - double vigour, int duration, double ceffect, int men); - /* Verzweigt automatisch zum passenden struct-typ. Sollte es schon - * einen Zauber dieses Typs geben, so wird der neue dazuaddiert. Die - * Zahl der verzauberten Personen sollte beim Aufruf der Funktion - * nochmal gesondert auf min(get_cursedmen, u->number) gesetzt werden. - */ - -extern void destroy_curse(curse * c); - - -boolean is_cursed_internal(struct attrib *ap, const curse_type * ctype); - /* ignoriert CURSE_ISNEW */ - -extern void remove_curse(struct attrib **ap, const struct curse * c); - /* löscht einen konkreten Spruch auf einem Objekt. - */ - -extern int curse_geteffect_int(const struct curse * c); -extern double curse_geteffect(const struct curse * c); - /* gibt die Auswirkungen der Verzauberungen zurück. zB bei - * Skillmodifiziernden Verzauberungen ist hier der Modifizierer - * gespeichert. Wird automatisch beim Anlegen eines neuen curse - * gesetzt. Gibt immer den ersten Treffer von ap aus zurück. - */ - - -extern double curse_changevigour(struct attrib **ap, curse * c, double i); - /* verändert die Stärke der Verzauberung um i */ - -extern int get_cursedmen(struct unit *u, const struct curse *c); - /* gibt bei Personenbeschränkten Verzauberungen die Anzahl der - * betroffenen Personen zurück. Ansonsten wird 0 zurückgegeben. */ - -extern void c_setflag(curse * c, unsigned int flag); -extern void c_clearflag(curse *c, unsigned int flags); - /* setzt/loescht Spezialflag einer Verzauberung (zB 'dauert ewig') */ - -void transfer_curse(struct unit * u, struct unit * u2, int n); - /* sorgt dafür, das bei der Übergabe von Personen die curse-attribute - * korrekt gehandhabt werden. Je nach internen Flag kann dies - * unterschiedlich gewünscht sein - * */ - -extern struct curse * get_cursex(struct attrib *ap, const curse_type * ctype, variant data, - boolean(*compare)(const struct curse *, variant)); - /* gibt pointer auf die erste curse-struct zurück, deren Typ ctype ist, - * und für die compare() true liefert, oder einen NULL-pointer. - * */ -extern struct curse * get_curse(struct attrib *ap, const curse_type * ctype); - /* gibt pointer auf die erste curse-struct zurück, deren Typ ctype ist, - * oder einen NULL-pointer - * */ - -int find_cursebyname(const char *c); -const curse_type * ct_find(const char *c); -void ct_register(const curse_type *); -/* Regionszauber */ - -curse * cfindhash(int i); - -curse * findcurse(int curseid); - -extern void curse_init(struct attrib * a); -extern void curse_done(struct attrib * a); -extern int curse_age(struct attrib * a); - -extern boolean cmp_curse(const struct attrib * a, const void * data); -extern boolean cmp_cursetype(const struct attrib * a, const void * data); - -extern double destr_curse(struct curse* c, int cast_level, double force); - -extern int resolve_curse(variant data, void * address); -extern boolean is_cursed_with(const struct attrib *ap, const struct curse *c); - -extern boolean curse_active(const struct curse * c); - /* gibt true, wenn der Curse nicht NULL oder inaktiv ist */ - -/*** COMPATIBILITY MACROS. DO NOT USE FOR NEW CODE, REPLACE IN OLD CODE: */ -extern const char * oldcursename(int id); -extern struct message * cinfo_simple(const void * obj, typ_t typ, const struct curse *c, int self); - -#define is_cursed(a, id, id2) \ - curse_active(get_curse(a, ct_find(oldcursename(id)))) -#define get_curseeffect(a, id, id2) \ - curse_geteffect(get_curse(a, ct_find(oldcursename(id)))) - -/* eressea-defined attribute-type flags */ -#define ATF_CURSE ATF_USER_DEFINED - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CURSE_H +#define CURSE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Sprueche in der struct region und auf Einheiten, Schiffen oder Burgen + * (struct attribute) + */ + +/* Brainstorming Überarbeitung curse + * + * Ziel: Keine Enum-Liste, flexible, leicht erweiterbare Curse-Objekte + * + * Was wird gebraucht? + * - Eindeutige Kennung für globale Suche + * - eine Wirkung, die sich einfach 'anwenden' läßt, dabei flexibel ist, + * Raum läßt für variable Boni, Anzahl betroffener Personen, + * spezielle Effekte oder anderes + * - einfacher Zugriff auf allgemeine Funktionen wie zb Alterung, aber + * auch Antimagieverhalten + * - Ausgabe von Beschreibungen in verschiedenen Sprachen + * - definiertes gekapseltes Verhalten zb bei Zusammenlegung von + * Einheiten, Übergabe von Personen, Mehrfachverzauberung + * - (Rück-)Referenzen auf Objekt, Verursacher (Magier), ? + * + * Vieleicht wäre ein Wirkungsklassensystem sinnvoll, so das im übrigen + * source einfach alle curse-attribs abgefragt werden können und bei + * gewünschter Wirkungsklasse angewendet, also nicht für jeden curse + * spezielle Änderungen im übrigen source notwendig sind. + * + * Die (Wirkungs-)Typen sollten die wichtigen Funktionen speziell + * belegen können, zb Alterung, Ausgabetexte, Merge-Verhalten + * + * Was sind wichtige individuelle Eigenschaften? + * - Referenzen auf Objekt und Verursacher + * - Referenzen für globale Liste + * > die Wirkung: + * - Dauer + * - Widerstandskraft, zb gegen Antimagie + * - Seiteneffekte zb Flag ONLYONE, Unverträglichkeiten + * - Alterungsverhalten zb Flag NOAGE + * - Effektverhalten, zb Bonus (variabel) + * - bei Einheitenzaubern die Zahl der betroffenen Personen + * + * Dabei sind nur die beiden letzten Punkte wirklich reine individuelle + * Wirkung, die anderen sind eher allgemeine Kennzeichen eines jeden + * Curse, die individuell belegt sind. + * ONLYONE und NOAGE könnten auch Eigenschaften des Typs sein, nicht des + * individuellen curse. Allgemein ist Alterung wohl eher eine + * Typeigenschaft als die eines individuellen curse. + * Dagegen ist der Widerstand gegen Antimagie sowohl abhängig von der + * Güte des Verursachers, also des Magiers zum Zeitpunkt des Zaubers, + * als auch vom Typ, der gegen bestimmte Arten des 'Fluchbrechens' immun + * sein könnte. + * + * Was sind wichtige Typeigenschaften? + * - Verhalten bei Personenübergaben + * - allgemeine Wirkung + * - Beschreibungstexte + * - Verhalten bei Antimagie + * - Alterung + * - Speicherung des C-Objekts + * - Laden des C-Objekts + * - Erzeugen des C-Objekts + * - Löschen und Aufräumen des C-Objekts + * - Funktionen zur Änderung der Werte + * + * */ + +#include + +/* ------------------------------------------------------------- */ +/* Zauberwirkungen */ +/* nicht vergessen curse_type zu aktualisieren und Reihenfolge beachten! + */ + +enum { +/* struct's vom typ curse: */ + C_FOGTRAP, + C_ANTIMAGICZONE, + C_FARVISION, + C_GBDREAM, + C_AURA, + C_MAELSTROM, + C_BLESSEDHARVEST, + C_DROUGHT, + C_BADLEARN, + C_SHIP_SPEEDUP, /* 9 - Sturmwind-Zauber */ + C_SHIP_FLYING, /* 10 - Luftschiff-Zauber */ + C_SHIP_NODRIFT, /* 11 - GünstigeWinde-Zauber */ + C_DEPRESSION, + C_MAGICWALLS, /* 13 - Heimstein */ + C_STRONGWALL, /* 14 - Feste Mauer - Precombat*/ + C_ASTRALBLOCK, /* 15 - Astralblock */ + C_GENEROUS, /* 16 - Unterhaltung vermehren */ + C_PEACE, /* 17 - Regionsweit Attacken verhindern */ + C_MAGICSTREET, /* 19 - magisches Straßennetz */ + C_RESIST_MAGIC, /* 20 - verändert Magieresistenz von Objekten */ + C_SONG_BADMR, /* 21 - verändert Magieresistenz */ + C_SONG_GOODMR, /* 22 - verändert Magieresistenz */ + C_SLAVE, /* 23 - dient fremder Partei */ + C_CALM, /* 25 - Beinflussung */ + C_OLDRACE, + C_FUMBLE, + C_RIOT, /*region in Aufruhr */ + C_NOCOST, + C_CURSED_BY_THE_GODS, +/* struct's vom untertyp curse_unit: */ + C_SPEED, /* Beschleunigt */ + C_ORC, + C_MBOOST, + C_KAELTESCHUTZ, + C_STRENGTH, + C_ALLSKILLS, + C_MAGICRESISTANCE, /* 44 - verändert Magieresistenz */ + C_ITEMCLOAK, + C_SPARKLE, +/* struct's vom untertyp curse_skill: */ + C_SKILL, + MAXCURSE /* OBS: when removing curses, remember to update read_ccompat() */ +}; + +/* ------------------------------------------------------------- */ +/* Flags */ + + +/* Verhalten von Zaubern auf Units beim Übergeben von Personen */ +typedef enum { + CURSE_ISNEW = 0x01, /* wirkt in der zauberrunde nicht (default)*/ + CURSE_NOAGE = 0x02, /* wirkt ewig */ + CURSE_IMMUNE = 0x04, /* ignoriert Antimagie */ + CURSE_ONLYONE = 0x08, /* Verhindert, das ein weiterer Zauber dieser Art auf das Objekt gezaubert wird */ + + /* the following are mutually exclusive */ + CURSE_SPREADNEVER = 0x00, /* wird nie mit übertragen */ + CURSE_SPREADALWAYS = 0x10, /* wird immer mit übertragen */ + CURSE_SPREADMODULO = 0x20, /* personenweise weitergabe */ + CURSE_SPREADCHANCE = 0x30 /* Ansteckungschance je nach Mengenverhältnis*/ +} curseflags; + +#define CURSE_FLAGSMASK 0x0F +#define CURSE_SPREADMASK 0x30 + +/* typ von struct */ +enum { + CURSETYP_NORM, + CURSETYP_UNIT, + CURSETYP_REGION, /* stores the region in c->data.v */ + MAXCURSETYP +}; + +/* Verhalten beim Zusammenfassen mit einem schon bestehenden Zauber + * gleichen Typs */ + +#define NO_MERGE 0 /* erzeugt jedesmal einen neuen Zauber */ +#define M_DURATION 1 /* Die Zauberdauer ist die maximale Dauer beider */ +#define M_SUMDURATION 2 /* die Dauer des Zaubers wird summiert */ +#define M_MAXEFFECT 4 /* der Effekt ist der maximale Effekt beider */ +#define M_SUMEFFECT 8 /* der Effekt summiert sich */ +#define M_MEN 16 /* die Anzahl der betroffenen Personen summiert + sich */ +#define M_VIGOUR 32 /* das Maximum der beiden Stärken wird die + Stärke des neuen Zaubers */ +#define M_VIGOUR_ADD 64 /* Vigour wird addiert */ + +/* ------------------------------------------------------------- */ +/* Allgemeine Zauberwirkungen */ + +typedef struct curse { + struct curse *nexthash; + int no; /* 'Einheitennummer' dieses Curse */ + const struct curse_type * type; /* Zeiger auf ein curse_type-struct */ + unsigned int flags; /* WARNING: these are XORed with type->flags! */ + int duration; /* Dauer der Verzauberung. Wird jede Runde vermindert */ + double vigour; /* Stärke der Verzauberung, Widerstand gegen Antimagie */ + struct unit *magician; /* Pointer auf den Magier, der den Spruch gewirkt hat */ + double effect; + variant data; /* pointer auf spezielle curse-unterstructs*/ +} curse; + +#define c_flags(c) ((c)->type->flags ^ (c)->flags) + +/* ------------------------------------------------------------- */ + +typedef struct curse_type { + const char *cname; /* Name der Zauberwirkung, Identifizierung des curse */ + int typ; + unsigned int flags; + unsigned int mergeflags; + struct message * (*curseinfo)(const void*, typ_t, const struct curse*, int); + void (*change_vigour)(curse*, double); + int (*read)(struct storage * store, curse * c, void * target); + int (*write)(struct storage * store, const struct curse * c, const void * target); + int (*cansee)(const struct faction*, const void*, typ_t, const struct curse *, int); + int (*age)(curse *); +} curse_type; + +extern struct attrib_type at_curse; +void curse_write(const struct attrib * a, const void * owner, struct storage * store); +int curse_read(struct attrib * a, void * owner, struct storage * store); + + +/* ------------------------------------------------------------- */ +/* Kommentare: + * Bei einigen Typen von Verzauberungen (z.B.Skillmodif.) muss neben + * der curse-id noch ein weiterer Identifizierer angegeben werden (id2). + * + * Wenn der Typ korrekt definiert wurde, erfolgt die Verzweigung zum + * korrekten Typus automatisch, und die unterschiedlichen struct-typen + * sind nach aussen unsichtbar. + * +* allgemeine Funktionen * +*/ + +curse * create_curse(struct unit *magician, struct attrib**ap, const curse_type * ctype, + double vigour, int duration, double ceffect, int men); + /* Verzweigt automatisch zum passenden struct-typ. Sollte es schon + * einen Zauber dieses Typs geben, so wird der neue dazuaddiert. Die + * Zahl der verzauberten Personen sollte beim Aufruf der Funktion + * nochmal gesondert auf min(get_cursedmen, u->number) gesetzt werden. + */ + +extern void destroy_curse(curse * c); + + +boolean is_cursed_internal(struct attrib *ap, const curse_type * ctype); + /* ignoriert CURSE_ISNEW */ + +extern void remove_curse(struct attrib **ap, const struct curse * c); + /* löscht einen konkreten Spruch auf einem Objekt. + */ + +extern int curse_geteffect_int(const struct curse * c); +extern double curse_geteffect(const struct curse * c); + /* gibt die Auswirkungen der Verzauberungen zurück. zB bei + * Skillmodifiziernden Verzauberungen ist hier der Modifizierer + * gespeichert. Wird automatisch beim Anlegen eines neuen curse + * gesetzt. Gibt immer den ersten Treffer von ap aus zurück. + */ + + +extern double curse_changevigour(struct attrib **ap, curse * c, double i); + /* verändert die Stärke der Verzauberung um i */ + +extern int get_cursedmen(struct unit *u, const struct curse *c); + /* gibt bei Personenbeschränkten Verzauberungen die Anzahl der + * betroffenen Personen zurück. Ansonsten wird 0 zurückgegeben. */ + +extern void c_setflag(curse * c, unsigned int flag); +extern void c_clearflag(curse *c, unsigned int flags); + /* setzt/loescht Spezialflag einer Verzauberung (zB 'dauert ewig') */ + +void transfer_curse(struct unit * u, struct unit * u2, int n); + /* sorgt dafür, das bei der Übergabe von Personen die curse-attribute + * korrekt gehandhabt werden. Je nach internen Flag kann dies + * unterschiedlich gewünscht sein + * */ + +extern struct curse * get_cursex(struct attrib *ap, const curse_type * ctype, variant data, + boolean(*compare)(const struct curse *, variant)); + /* gibt pointer auf die erste curse-struct zurück, deren Typ ctype ist, + * und für die compare() true liefert, oder einen NULL-pointer. + * */ +extern struct curse * get_curse(struct attrib *ap, const curse_type * ctype); + /* gibt pointer auf die erste curse-struct zurück, deren Typ ctype ist, + * oder einen NULL-pointer + * */ + +int find_cursebyname(const char *c); +const curse_type * ct_find(const char *c); +void ct_register(const curse_type *); +/* Regionszauber */ + +curse * cfindhash(int i); + +curse * findcurse(int curseid); + +extern void curse_init(struct attrib * a); +extern void curse_done(struct attrib * a); +extern int curse_age(struct attrib * a); + +extern boolean cmp_curse(const struct attrib * a, const void * data); +extern boolean cmp_cursetype(const struct attrib * a, const void * data); + +extern double destr_curse(struct curse* c, int cast_level, double force); + +extern int resolve_curse(variant data, void * address); +extern boolean is_cursed_with(const struct attrib *ap, const struct curse *c); + +extern boolean curse_active(const struct curse * c); + /* gibt true, wenn der Curse nicht NULL oder inaktiv ist */ + +/*** COMPATIBILITY MACROS. DO NOT USE FOR NEW CODE, REPLACE IN OLD CODE: */ +extern const char * oldcursename(int id); +extern struct message * cinfo_simple(const void * obj, typ_t typ, const struct curse *c, int self); + +#define is_cursed(a, id, id2) \ + curse_active(get_curse(a, ct_find(oldcursename(id)))) +#define get_curseeffect(a, id, id2) \ + curse_geteffect(get_curse(a, ct_find(oldcursename(id)))) + +/* eressea-defined attribute-type flags */ +#define ATF_CURSE ATF_USER_DEFINED + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/curse_test.c b/src/kernel/curse_test.c index d0d11d2d8..0445995bc 100644 --- a/src/kernel/curse_test.c +++ b/src/kernel/curse_test.c @@ -1,23 +1,23 @@ -#include - -static void test_curse(CuTest * tc) { - attrib * attrs = NULL; - curse * c, * result; - int cid; - - curse_type ct_dummy = { "dummy", CURSETYP_NORM, 0, M_SUMEFFECT, NULL }; - c = create_curse(NULL, &attrs, &ct_dummy, 1.0, 1, 1, 1); - cid = c->no; - result = findcurse(cid); - CuAssertPtrEquals(tc, c, result); - destroy_curse(c); - result = findcurse(cid); - CuAssertPtrEquals(tc, NULL, result); -} - -CuSuite* get_curse_suite(void) -{ - CuSuite* suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, test_curse); - return suite; -} +#include + +static void test_curse(CuTest * tc) { + attrib * attrs = NULL; + curse * c, * result; + int cid; + + curse_type ct_dummy = { "dummy", CURSETYP_NORM, 0, M_SUMEFFECT, NULL }; + c = create_curse(NULL, &attrs, &ct_dummy, 1.0, 1, 1, 1); + cid = c->no; + result = findcurse(cid); + CuAssertPtrEquals(tc, c, result); + destroy_curse(c); + result = findcurse(cid); + CuAssertPtrEquals(tc, NULL, result); +} + +CuSuite* get_curse_suite(void) +{ + CuSuite* suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_curse); + return suite; +} diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index 17a44fc09..9b7e0393b 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -1,220 +1,220 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "equipment.h" - -/* kernel includes */ -#include "item.h" -#include "unit.h" -#include "race.h" - -/* util includes */ -#include -#include - -/* libc includes */ -#include -#include - -static equipment * equipment_sets; - -equipment * -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 = malloc(sizeof(equipment)); - eq->name = strdup(eqname); - eq->next = *eqp; - eq->items = NULL; - eq->spells = NULL; - eq->subsets = NULL; - eq->callback = NULL; - 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) { - if (value!=NULL) { - eq->skills[sk] = strdup(value); - } else if (eq->skills[sk]) { - free(eq->skills[sk]); - } - } -} - -void -equipment_addspell(equipment * eq, spell * sp) -{ - if (eq!=NULL) { - spelllist_add(&eq->spells, sp); - } -} - -void -equipment_setitem(equipment * eq, const item_type * itype, const char * value) -{ - if (eq!=NULL) { - if (itype!=NULL) { - itemdata * idata = eq->items; - while (idata &&idata->itype!=itype) { - idata = idata->next; - } - if (idata==NULL) { - idata = malloc(sizeof(itemdata)); - idata->itype = itype; - idata->value = strdup(value); - idata->next = eq->items; - eq->items = idata; - } - } - } -} - -void -equipment_setcallback(struct equipment * eq, void (*callback)(const struct equipment *, struct unit *)) -{ - eq->callback = callback; -} - -void -equip_unit(struct unit * u, const struct equipment * eq) -{ - equip_unit_mask(u, eq, EQUIP_ALL); -} - -void -equip_unit_mask(struct unit * u, const struct equipment * eq, int mask) -{ - if (eq) { - - if (mask&EQUIP_SKILLS) { - skill_t sk; - for (sk=0;sk!=MAXSKILLS;++sk) { - if (eq->skills[sk]!=NULL) { - int i = dice_rand(eq->skills[sk]); - if (i>0) set_level(u, sk, i); - } - } - } - - if (mask&EQUIP_SPELLS) { - spell_list * sp = eq->spells; - if (sp!=NULL) { - sc_mage * m = get_mage(u); - if (m==NULL) { - assert(!"trying to equip spells on a non-mage!"); - } else { - while (sp) { - add_spell(get_spelllist(m, u->faction), sp->data); - sp = sp->next; - } - } - } - } - - if (mask&EQUIP_ITEMS) { - itemdata * idata; - for (idata=eq->items;idata!=NULL;idata=idata->next) { - int i = u->number * dice_rand(idata->value); - if (i>0) { - i_add(&u->items, i_new(idata->itype, i)); - } - } - } - - if (eq->subsets) { - int i; - for (i=0;eq->subsets[i].sets;++i) { - if (chance(eq->subsets[i].chance)) { - float rnd = (1+rng_int() % 1000) / 1000.0f; - int k; - for (k=0;eq->subsets[i].sets[k].set;++k) { - if (rnd<=eq->subsets[i].sets[k].chance) { - equip_unit_mask(u, eq->subsets[i].sets[k].set, mask); - break; - } - rnd -= eq->subsets[i].sets[k].chance; - } - } - } - } - - if (mask&EQUIP_SPECIAL) { - if (eq->callback) eq->callback(eq, u); - } - } -} - -void -equip_items(struct item ** items, const struct equipment * eq) -{ - if (eq) { - itemdata * idata; - - for (idata=eq->items;idata!=NULL;idata=idata->next) { - int i = dice_rand(idata->value); - if (i>0) { - i_add(items, i_new(idata->itype, i)); - } - } - if (eq->subsets) { - int i; - for (i=0;eq->subsets[i].sets;++i) { - if (chance(eq->subsets[i].chance)) { - float rnd = (1+rng_int() % 1000) / 1000.0f; - int k; - for (k=0;eq->subsets[i].sets[k].set;++k) { - if (rnd<=eq->subsets[i].sets[k].chance) { - equip_items(items, eq->subsets[i].sets[k].set); - break; - } - rnd -= eq->subsets[i].sets[k].chance; - } - } - } - } - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "equipment.h" + +/* kernel includes */ +#include "item.h" +#include "unit.h" +#include "race.h" + +/* util includes */ +#include +#include + +/* libc includes */ +#include +#include + +static equipment * equipment_sets; + +equipment * +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 = malloc(sizeof(equipment)); + eq->name = strdup(eqname); + eq->next = *eqp; + eq->items = NULL; + eq->spells = NULL; + eq->subsets = NULL; + eq->callback = NULL; + 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) { + if (value!=NULL) { + eq->skills[sk] = strdup(value); + } else if (eq->skills[sk]) { + free(eq->skills[sk]); + } + } +} + +void +equipment_addspell(equipment * eq, spell * sp) +{ + if (eq!=NULL) { + spelllist_add(&eq->spells, sp); + } +} + +void +equipment_setitem(equipment * eq, const item_type * itype, const char * value) +{ + if (eq!=NULL) { + if (itype!=NULL) { + itemdata * idata = eq->items; + while (idata &&idata->itype!=itype) { + idata = idata->next; + } + if (idata==NULL) { + idata = malloc(sizeof(itemdata)); + idata->itype = itype; + idata->value = strdup(value); + idata->next = eq->items; + eq->items = idata; + } + } + } +} + +void +equipment_setcallback(struct equipment * eq, void (*callback)(const struct equipment *, struct unit *)) +{ + eq->callback = callback; +} + +void +equip_unit(struct unit * u, const struct equipment * eq) +{ + equip_unit_mask(u, eq, EQUIP_ALL); +} + +void +equip_unit_mask(struct unit * u, const struct equipment * eq, int mask) +{ + if (eq) { + + if (mask&EQUIP_SKILLS) { + skill_t sk; + for (sk=0;sk!=MAXSKILLS;++sk) { + if (eq->skills[sk]!=NULL) { + int i = dice_rand(eq->skills[sk]); + if (i>0) set_level(u, sk, i); + } + } + } + + if (mask&EQUIP_SPELLS) { + spell_list * sp = eq->spells; + if (sp!=NULL) { + sc_mage * m = get_mage(u); + if (m==NULL) { + assert(!"trying to equip spells on a non-mage!"); + } else { + while (sp) { + add_spell(get_spelllist(m, u->faction), sp->data); + sp = sp->next; + } + } + } + } + + if (mask&EQUIP_ITEMS) { + itemdata * idata; + for (idata=eq->items;idata!=NULL;idata=idata->next) { + int i = u->number * dice_rand(idata->value); + if (i>0) { + i_add(&u->items, i_new(idata->itype, i)); + } + } + } + + if (eq->subsets) { + int i; + for (i=0;eq->subsets[i].sets;++i) { + if (chance(eq->subsets[i].chance)) { + float rnd = (1+rng_int() % 1000) / 1000.0f; + int k; + for (k=0;eq->subsets[i].sets[k].set;++k) { + if (rnd<=eq->subsets[i].sets[k].chance) { + equip_unit_mask(u, eq->subsets[i].sets[k].set, mask); + break; + } + rnd -= eq->subsets[i].sets[k].chance; + } + } + } + } + + if (mask&EQUIP_SPECIAL) { + if (eq->callback) eq->callback(eq, u); + } + } +} + +void +equip_items(struct item ** items, const struct equipment * eq) +{ + if (eq) { + itemdata * idata; + + for (idata=eq->items;idata!=NULL;idata=idata->next) { + int i = dice_rand(idata->value); + if (i>0) { + i_add(items, i_new(idata->itype, i)); + } + } + if (eq->subsets) { + int i; + for (i=0;eq->subsets[i].sets;++i) { + if (chance(eq->subsets[i].chance)) { + float rnd = (1+rng_int() % 1000) / 1000.0f; + int k; + for (k=0;eq->subsets[i].sets[k].set;++k) { + if (rnd<=eq->subsets[i].sets[k].chance) { + equip_items(items, eq->subsets[i].sets[k].set); + break; + } + rnd -= eq->subsets[i].sets[k].chance; + } + } + } + } + } +} diff --git a/src/kernel/equipment.h b/src/kernel/equipment.h index 315854b42..174aad7f4 100644 --- a/src/kernel/equipment.h +++ b/src/kernel/equipment.h @@ -1,73 +1,73 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_EQUIPMENT_H -#define H_KRNL_EQUIPMENT_H -#ifdef __cplusplus -extern "C" { -#endif - struct spell; - - typedef struct itemdata { - const struct item_type * itype; - char * value; - struct itemdata * next; - } itemdata; - - typedef struct subsetitem { - struct equipment * set; - float chance; - } subsetitem; - - typedef struct subset { - float chance; - subsetitem * sets; - } subset; - - typedef struct equipment { - char * name; - struct itemdata * items; - char * skills[MAXSKILLS]; - struct spell_list * spells; - struct subset * subsets; - struct equipment * next; - void (*callback)(const struct equipment *, struct unit *); - } equipment; - - - extern struct equipment * create_equipment(const char * eqname); - extern struct equipment * get_equipment(const char * eqname); - - extern void equipment_setitem(struct equipment * eq, const struct item_type * itype, const char * value); - extern void equipment_setskill(struct equipment * eq, skill_t sk, const char * value); - extern void equipment_addspell(struct equipment * eq, struct spell * sp); - extern void equipment_setcallback(struct equipment * eq, void (*callback)(const struct equipment *, struct unit *)); - - extern void equip_unit(struct unit * u, const struct equipment * eq); -#define EQUIP_SKILLS (1<<1) -#define EQUIP_SPELLS (1<<2) -#define EQUIP_ITEMS (1<<3) -#define EQUIP_SPECIAL (1<<4) -#define EQUIP_ALL (0xFF) - extern void equip_unit_mask(struct unit * u, const struct equipment * eq, int mask); - extern void equip_items(struct item ** items, const struct equipment * eq); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_EQUIPMENT_H +#define H_KRNL_EQUIPMENT_H +#ifdef __cplusplus +extern "C" { +#endif + struct spell; + + typedef struct itemdata { + const struct item_type * itype; + char * value; + struct itemdata * next; + } itemdata; + + typedef struct subsetitem { + struct equipment * set; + float chance; + } subsetitem; + + typedef struct subset { + float chance; + subsetitem * sets; + } subset; + + typedef struct equipment { + char * name; + struct itemdata * items; + char * skills[MAXSKILLS]; + struct spell_list * spells; + struct subset * subsets; + struct equipment * next; + void (*callback)(const struct equipment *, struct unit *); + } equipment; + + + extern struct equipment * create_equipment(const char * eqname); + extern struct equipment * get_equipment(const char * eqname); + + extern void equipment_setitem(struct equipment * eq, const struct item_type * itype, const char * value); + extern void equipment_setskill(struct equipment * eq, skill_t sk, const char * value); + extern void equipment_addspell(struct equipment * eq, struct spell * sp); + extern void equipment_setcallback(struct equipment * eq, void (*callback)(const struct equipment *, struct unit *)); + + extern void equip_unit(struct unit * u, const struct equipment * eq); +#define EQUIP_SKILLS (1<<1) +#define EQUIP_SPELLS (1<<2) +#define EQUIP_ITEMS (1<<3) +#define EQUIP_SPECIAL (1<<4) +#define EQUIP_ALL (0xFF) + extern void equip_unit_mask(struct unit * u, const struct equipment * eq, int mask); + extern void equip_items(struct item ** items, const struct equipment * eq); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/faction.c b/src/kernel/faction.c index c7df564e8..f5ac32f3c 100644 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -1,507 +1,507 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "faction.h" - -#include "alliance.h" -#include "equipment.h" -#include "group.h" -#include "item.h" -#include "message.h" -#include "plane.h" -#include "race.h" -#include "region.h" -#include "terrain.h" -#include "unit.h" -#include "version.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -faction *factions; - -/** remove the faction from memory. - * this frees all memory that's only accessible through the faction, - * but you should still call funhash and remove the faction from the - * global list. - */ -void -free_faction (faction * f) -{ - if (f->msgs) free_messagelist(f->msgs); - while (f->battles) { - struct bmsg * bm = f->battles; - f->battles = bm->next; - if (bm->msgs) free_messagelist(bm->msgs); - free(bm); - } - - while (f->groups) { - group * g = f->groups; - f->groups = g->next; - free_group(g); - } - freelist(f->allies); - - free(f->email); - free(f->banner); - free(f->passw); - free(f->override); - free(f->name); - - while (f->attribs) { - a_remove (&f->attribs, f->attribs); - } - - i_freeall(&f->items); - - freelist(f->ursprung); -} - -faction * -get_monsters(void) -{ - static faction * monsters; - static int gamecookie = -1; - - if (gamecookie!=global.cookie) { - monsters = NULL; - gamecookie = global.cookie; - } - - if (!monsters) { - faction * f; - for (f=factions;f;f=f->next) { - if (f->flags&FFL_NPC) { - return monsters=f; - } - } - if (!monsters) { - /* shit! */ - monsters = findfaction(666); - } - if (monsters) { - fset(monsters, FFL_NPC|FFL_NOIDLEOUT); - } - } - return monsters; -} - -const unit * -random_unit_in_faction(const faction *f) -{ - unit *u; - int c = 0, u_nr; - - for(u = f->units; u; u=u->next) c++; - - u_nr = rng_int()%c; - c = 0; - - for(u = f->units; u; u=u->next) - if(u_nr == c) return u; - - /* Hier sollte er nie ankommen */ - return NULL; -} - -const char * -factionname(const faction * f) -{ - typedef char name[OBJECTIDSIZE+1]; - static name idbuf[8]; - static int nextbuf = 0; - - char *ibuf = idbuf[(++nextbuf) % 8]; - - if (f && f->name) { - snprintf(ibuf, sizeof(name), "%s (%s)", f->name, itoa36(f->no)); - ibuf[sizeof(name)-1] = 0; - } else { - strcpy(ibuf, "Unbekannte Partei (?)"); - } - 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; - } - } - *(faction**)address = f; - return result; -} - -#define MAX_FACTION_ID (36*36*36*36) - -static int -unused_faction_id(void) -{ - int id = rng_int()%MAX_FACTION_ID; - - while (!faction_id_is_unused(id)) { - id++; if(id == MAX_FACTION_ID) id = 0; - } - - return id; -} - -faction * -addfaction(const char *email, const char * password, - const struct race * frace, const struct locale *loc, - int subscription) -{ - faction * f = calloc(sizeof(faction), 1); - char buf[128]; - - assert(frace); - - if (set_email(&f->email, email)!=0) { - log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), email)); - } - - f->override = strdup(itoa36(rng_int())); - faction_setpassword(f, password); - - f->alliance_joindate = turn; - f->lastorders = turn; - f->alive = 1; - f->age = 0; - f->race = frace; - f->magiegebiet = 0; - f->locale = loc; - f->subscription = subscription; - - f->options = want(O_REPORT) | want(O_ZUGVORLAGE) | want(O_COMPUTER) | want(O_COMPRESS) | want(O_ADRESSEN) | want(O_STATISTICS); - - f->no = unused_faction_id(); - if (rule_region_owners()) { - alliance * al = makealliance(f->no, NULL); - setalliance(f, al); - } - addlist(&factions, f); - fhash(f); - - snprintf(buf, sizeof(buf), "%s %s", LOC(loc, "factiondefault"), factionid(f)); - f->name = strdup(buf); - - return f; -} - -unit * -addplayer(region *r, faction * f) -{ - unit *u; - char buffer[32]; - - assert(f->units==NULL); - set_ursprung(f, 0, r->x, r->y); - u = createunit(r, f, 1, f->race); - equip_items(&u->faction->items, get_equipment("new_faction")); - equip_unit(u, get_equipment("first_unit")); - sprintf(buffer, "first_%s", u->race->_name[0]); - equip_unit(u, get_equipment(buffer)); - u->hp = unit_max_hp(u) * u->number; - fset(u, UFL_ISNEW); - if (f->race == new_race[RC_DAEMON]) { - race_t urc; - do { - urc = (race_t)(rng_int() % MAXRACES); - } while (new_race[urc]==NULL || urc == RC_DAEMON || !playerrace(new_race[urc])); - u->irace = new_race[urc]; - } - - return u; -} - -boolean -checkpasswd(const faction * f, const char * passwd, boolean shortp) -{ - if (unicode_utf8_strcasecmp(f->passw, passwd)==0) return true; - if (unicode_utf8_strcasecmp(f->override, passwd)==0) return true; - return false; -} - - -variant -read_faction_reference(struct storage * store) -{ - variant id; - id.i = store->r_id(store); - return id; -} - -void -write_faction_reference(const faction * f, struct storage * store) -{ - store->w_id(store, f?f->no:0); -} - -void -destroyfaction(faction * f) -{ - unit *u = f->units; - faction *ff; - - if (!f->alive) return; - fset(f, FFL_QUIT); - - freelist(f->spellbook); - f->spellbook = NULL; - - while (f->battles) { - struct bmsg * bm = f->battles; - f->battles = bm->next; - if (bm->msgs) free_messagelist(bm->msgs); - free(bm); - } - - while (u) { - /* give away your stuff, make zombies if you cannot (quest items) */ - int result = gift_items(u, GIFT_FRIENDS|GIFT_PEASANTS); - if (result!=0) { - unit * zombie = u; - u = u->nextF; - make_zombie(zombie); - } else { - region * r = u->region; - - if (!fval(r->terrain, SEA_REGION) && !!playerrace(u->race)) { - const race * rc = u->race; - int m = rmoney(r); - - if ((rc->ec_flags & ECF_REC_ETHEREAL)==0) { - int p = rpeasants(u->region); - int h = rhorses(u->region); - item * itm; - - /* Personen gehen nur an die Bauern, wenn sie auch von dort - * stammen */ - if (rc->ec_flags & ECF_REC_HORSES) { /* Zentauren an die Pferde */ - h += u->number; - } else { /* Orks zählen nur zur Hälfte */ - p += (int)(u->number * rc->recruit_multi); - } - for (itm=u->items;itm;itm=itm->next) { - if (itm->type->flags&ITF_ANIMAL) { - h += itm->number; - } - } - rsetpeasants(r, p); - rsethorses(r, h); - } - m += get_money(u); - rsetmoney(r, m); - } - set_number(u, 0); - u=u->nextF; - } - } - f->alive = 0; -/* no way! f->units = NULL; */ - handle_event(f->attribs, "destroy", f); - for (ff = factions; ff; ff = ff->next) { - group *g; - ally *sf, *sfn; - - /* Alle HELFE für die Partei löschen */ - for (sf = ff->allies; sf; sf = sf->next) { - if (sf->faction == f) { - removelist(&ff->allies, sf); - break; - } - } - for(g=ff->groups; g; g=g->next) { - for (sf = g->allies; sf;) { - sfn = sf->next; - if (sf->faction == f) { - removelist(&g->allies, sf); - break; - } - sf = sfn; - } - } - } - - /* units of other factions that were disguised as this faction - * have their disguise replaced by ordinary faction hiding. */ - if (rule_stealth_faction()) { - region * rc; - for (rc=regions; rc; rc=rc->next) { - for(u=rc->units; u; u=u->next) { - attrib *a = a_find(u->attribs, &at_otherfaction); - if(!a) continue; - if (get_otherfaction(a) == f) { - a_removeall(&u->attribs, &at_otherfaction); - fset(u, UFL_ANON_FACTION); - } - } - } - } -} - -int -get_alliance(const faction * a, const faction * b) -{ - const ally * sf = a->allies; - for (;sf!=NULL;sf=sf->next) { - if (sf->faction==b) { - return sf->status; - } - } - return 0; -} - -void -set_alliance(faction * a, faction * b, int status) -{ - ally ** sfp; - sfp = &a->allies; - while (*sfp) { - ally * sf = *sfp; - if (sf->faction==b) break; - sfp = &sf->next; - } - if (*sfp==NULL) { - ally * sf = *sfp = malloc(sizeof(ally)); - sf->next = NULL; - sf->status = status; - sf->faction = b; - return; - } - (*sfp)->status |= status; -} - -void -renumber_faction(faction * f, int no) -{ - if (f->subscription) { - sql_print(("UPDATE subscriptions set faction='%s' where id=%u;\n", - itoa36(no), f->subscription)); - } - funhash(f); - f->no = no; - fhash(f); - fset(f, FFL_NEWID); -} - -#ifdef SMART_INTERVALS -void -update_interval(struct faction * f, struct region * r) -{ - if (r==NULL || f==NULL) return; - if (f->first==NULL || f->first->index>r->index) { - f->first = r; - } - if (f->last==NULL || f->last->index<=r->index) { - f->last = r; - } -} -#endif - -const char * faction_getname(const faction * self) -{ - return self->name?self->name:""; -} - -void faction_setname(faction * self, const char * name) -{ - free(self->name); - if (name) self->name = strdup(name); -} - -const char * faction_getemail(const faction * self) -{ - return self->email?self->email:""; -} - -void faction_setemail(faction * self, const char * email) -{ - free(self->email); - if (email) self->email = strdup(email); -} - -const char * faction_getbanner(const faction * self) -{ - return self->banner?self->banner:""; -} - -void faction_setbanner(faction * self, const char * banner) -{ - free(self->banner); - if (banner) self->banner = strdup(banner); -} - -void -faction_setpassword(faction * f, const char * passw) -{ - free(f->passw); - if (passw) f->passw = strdup(passw); - else f->passw = strdup(itoa36(rng_int())); -} - -boolean valid_race(const struct faction * f, const struct race * rc) -{ - if (f->race==rc) return true; - else { - const char * str = get_param(f->race->parameters, "other_race"); - if (str) return (boolean)(rc_find(str)==rc); - return false; - } -} - -const char * -faction_getpassword(const faction * f) -{ - return f->passw; -} - -struct alliance * -f_get_alliance(const struct faction * f) -{ - if (f->alliance && !(f->alliance->flags&ALF_NON_ALLIED)) { - return f->alliance; - } - return NULL; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "faction.h" + +#include "alliance.h" +#include "equipment.h" +#include "group.h" +#include "item.h" +#include "message.h" +#include "plane.h" +#include "race.h" +#include "region.h" +#include "terrain.h" +#include "unit.h" +#include "version.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +faction *factions; + +/** remove the faction from memory. + * this frees all memory that's only accessible through the faction, + * but you should still call funhash and remove the faction from the + * global list. + */ +void +free_faction (faction * f) +{ + if (f->msgs) free_messagelist(f->msgs); + while (f->battles) { + struct bmsg * bm = f->battles; + f->battles = bm->next; + if (bm->msgs) free_messagelist(bm->msgs); + free(bm); + } + + while (f->groups) { + group * g = f->groups; + f->groups = g->next; + free_group(g); + } + freelist(f->allies); + + free(f->email); + free(f->banner); + free(f->passw); + free(f->override); + free(f->name); + + while (f->attribs) { + a_remove (&f->attribs, f->attribs); + } + + i_freeall(&f->items); + + freelist(f->ursprung); +} + +faction * +get_monsters(void) +{ + static faction * monsters; + static int gamecookie = -1; + + if (gamecookie!=global.cookie) { + monsters = NULL; + gamecookie = global.cookie; + } + + if (!monsters) { + faction * f; + for (f=factions;f;f=f->next) { + if (f->flags&FFL_NPC) { + return monsters=f; + } + } + if (!monsters) { + /* shit! */ + monsters = findfaction(666); + } + if (monsters) { + fset(monsters, FFL_NPC|FFL_NOIDLEOUT); + } + } + return monsters; +} + +const unit * +random_unit_in_faction(const faction *f) +{ + unit *u; + int c = 0, u_nr; + + for(u = f->units; u; u=u->next) c++; + + u_nr = rng_int()%c; + c = 0; + + for(u = f->units; u; u=u->next) + if(u_nr == c) return u; + + /* Hier sollte er nie ankommen */ + return NULL; +} + +const char * +factionname(const faction * f) +{ + typedef char name[OBJECTIDSIZE+1]; + static name idbuf[8]; + static int nextbuf = 0; + + char *ibuf = idbuf[(++nextbuf) % 8]; + + if (f && f->name) { + snprintf(ibuf, sizeof(name), "%s (%s)", f->name, itoa36(f->no)); + ibuf[sizeof(name)-1] = 0; + } else { + strcpy(ibuf, "Unbekannte Partei (?)"); + } + 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; + } + } + *(faction**)address = f; + return result; +} + +#define MAX_FACTION_ID (36*36*36*36) + +static int +unused_faction_id(void) +{ + int id = rng_int()%MAX_FACTION_ID; + + while (!faction_id_is_unused(id)) { + id++; if(id == MAX_FACTION_ID) id = 0; + } + + return id; +} + +faction * +addfaction(const char *email, const char * password, + const struct race * frace, const struct locale *loc, + int subscription) +{ + faction * f = calloc(sizeof(faction), 1); + char buf[128]; + + assert(frace); + + if (set_email(&f->email, email)!=0) { + log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), email)); + } + + f->override = strdup(itoa36(rng_int())); + faction_setpassword(f, password); + + f->alliance_joindate = turn; + f->lastorders = turn; + f->alive = 1; + f->age = 0; + f->race = frace; + f->magiegebiet = 0; + f->locale = loc; + f->subscription = subscription; + + f->options = want(O_REPORT) | want(O_ZUGVORLAGE) | want(O_COMPUTER) | want(O_COMPRESS) | want(O_ADRESSEN) | want(O_STATISTICS); + + f->no = unused_faction_id(); + if (rule_region_owners()) { + alliance * al = makealliance(f->no, NULL); + setalliance(f, al); + } + addlist(&factions, f); + fhash(f); + + snprintf(buf, sizeof(buf), "%s %s", LOC(loc, "factiondefault"), factionid(f)); + f->name = strdup(buf); + + return f; +} + +unit * +addplayer(region *r, faction * f) +{ + unit *u; + char buffer[32]; + + assert(f->units==NULL); + set_ursprung(f, 0, r->x, r->y); + u = createunit(r, f, 1, f->race); + equip_items(&u->faction->items, get_equipment("new_faction")); + equip_unit(u, get_equipment("first_unit")); + sprintf(buffer, "first_%s", u->race->_name[0]); + equip_unit(u, get_equipment(buffer)); + u->hp = unit_max_hp(u) * u->number; + fset(u, UFL_ISNEW); + if (f->race == new_race[RC_DAEMON]) { + race_t urc; + do { + urc = (race_t)(rng_int() % MAXRACES); + } while (new_race[urc]==NULL || urc == RC_DAEMON || !playerrace(new_race[urc])); + u->irace = new_race[urc]; + } + + return u; +} + +boolean +checkpasswd(const faction * f, const char * passwd, boolean shortp) +{ + if (unicode_utf8_strcasecmp(f->passw, passwd)==0) return true; + if (unicode_utf8_strcasecmp(f->override, passwd)==0) return true; + return false; +} + + +variant +read_faction_reference(struct storage * store) +{ + variant id; + id.i = store->r_id(store); + return id; +} + +void +write_faction_reference(const faction * f, struct storage * store) +{ + store->w_id(store, f?f->no:0); +} + +void +destroyfaction(faction * f) +{ + unit *u = f->units; + faction *ff; + + if (!f->alive) return; + fset(f, FFL_QUIT); + + freelist(f->spellbook); + f->spellbook = NULL; + + while (f->battles) { + struct bmsg * bm = f->battles; + f->battles = bm->next; + if (bm->msgs) free_messagelist(bm->msgs); + free(bm); + } + + while (u) { + /* give away your stuff, make zombies if you cannot (quest items) */ + int result = gift_items(u, GIFT_FRIENDS|GIFT_PEASANTS); + if (result!=0) { + unit * zombie = u; + u = u->nextF; + make_zombie(zombie); + } else { + region * r = u->region; + + if (!fval(r->terrain, SEA_REGION) && !!playerrace(u->race)) { + const race * rc = u->race; + int m = rmoney(r); + + if ((rc->ec_flags & ECF_REC_ETHEREAL)==0) { + int p = rpeasants(u->region); + int h = rhorses(u->region); + item * itm; + + /* Personen gehen nur an die Bauern, wenn sie auch von dort + * stammen */ + if (rc->ec_flags & ECF_REC_HORSES) { /* Zentauren an die Pferde */ + h += u->number; + } else { /* Orks zählen nur zur Hälfte */ + p += (int)(u->number * rc->recruit_multi); + } + for (itm=u->items;itm;itm=itm->next) { + if (itm->type->flags&ITF_ANIMAL) { + h += itm->number; + } + } + rsetpeasants(r, p); + rsethorses(r, h); + } + m += get_money(u); + rsetmoney(r, m); + } + set_number(u, 0); + u=u->nextF; + } + } + f->alive = 0; +/* no way! f->units = NULL; */ + handle_event(f->attribs, "destroy", f); + for (ff = factions; ff; ff = ff->next) { + group *g; + ally *sf, *sfn; + + /* Alle HELFE für die Partei löschen */ + for (sf = ff->allies; sf; sf = sf->next) { + if (sf->faction == f) { + removelist(&ff->allies, sf); + break; + } + } + for(g=ff->groups; g; g=g->next) { + for (sf = g->allies; sf;) { + sfn = sf->next; + if (sf->faction == f) { + removelist(&g->allies, sf); + break; + } + sf = sfn; + } + } + } + + /* units of other factions that were disguised as this faction + * have their disguise replaced by ordinary faction hiding. */ + if (rule_stealth_faction()) { + region * rc; + for (rc=regions; rc; rc=rc->next) { + for(u=rc->units; u; u=u->next) { + attrib *a = a_find(u->attribs, &at_otherfaction); + if(!a) continue; + if (get_otherfaction(a) == f) { + a_removeall(&u->attribs, &at_otherfaction); + fset(u, UFL_ANON_FACTION); + } + } + } + } +} + +int +get_alliance(const faction * a, const faction * b) +{ + const ally * sf = a->allies; + for (;sf!=NULL;sf=sf->next) { + if (sf->faction==b) { + return sf->status; + } + } + return 0; +} + +void +set_alliance(faction * a, faction * b, int status) +{ + ally ** sfp; + sfp = &a->allies; + while (*sfp) { + ally * sf = *sfp; + if (sf->faction==b) break; + sfp = &sf->next; + } + if (*sfp==NULL) { + ally * sf = *sfp = malloc(sizeof(ally)); + sf->next = NULL; + sf->status = status; + sf->faction = b; + return; + } + (*sfp)->status |= status; +} + +void +renumber_faction(faction * f, int no) +{ + if (f->subscription) { + sql_print(("UPDATE subscriptions set faction='%s' where id=%u;\n", + itoa36(no), f->subscription)); + } + funhash(f); + f->no = no; + fhash(f); + fset(f, FFL_NEWID); +} + +#ifdef SMART_INTERVALS +void +update_interval(struct faction * f, struct region * r) +{ + if (r==NULL || f==NULL) return; + if (f->first==NULL || f->first->index>r->index) { + f->first = r; + } + if (f->last==NULL || f->last->index<=r->index) { + f->last = r; + } +} +#endif + +const char * faction_getname(const faction * self) +{ + return self->name?self->name:""; +} + +void faction_setname(faction * self, const char * name) +{ + free(self->name); + if (name) self->name = strdup(name); +} + +const char * faction_getemail(const faction * self) +{ + return self->email?self->email:""; +} + +void faction_setemail(faction * self, const char * email) +{ + free(self->email); + if (email) self->email = strdup(email); +} + +const char * faction_getbanner(const faction * self) +{ + return self->banner?self->banner:""; +} + +void faction_setbanner(faction * self, const char * banner) +{ + free(self->banner); + if (banner) self->banner = strdup(banner); +} + +void +faction_setpassword(faction * f, const char * passw) +{ + free(f->passw); + if (passw) f->passw = strdup(passw); + else f->passw = strdup(itoa36(rng_int())); +} + +boolean valid_race(const struct faction * f, const struct race * rc) +{ + if (f->race==rc) return true; + else { + const char * str = get_param(f->race->parameters, "other_race"); + if (str) return (boolean)(rc_find(str)==rc); + return false; + } +} + +const char * +faction_getpassword(const faction * f) +{ + return f->passw; +} + +struct alliance * +f_get_alliance(const struct faction * f) +{ + if (f->alliance && !(f->alliance->flags&ALF_NON_ALLIED)) { + return f->alliance; + } + return NULL; +} diff --git a/src/kernel/faction.h b/src/kernel/faction.h index c9049c52f..faa552581 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -1,161 +1,161 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_FACTION -#define H_KRNL_FACTION -#ifdef __cplusplus -extern "C" { -#endif - -struct player; -struct alliance; -struct item; -struct seen_region; - -/* SMART_INTERVALS: define to speed up finding the interval of regions that a - faction is in. defining this speeds up the turn by 30-40% */ -#define SMART_INTERVALS - -/* faction flags */ -#define FFL_NEWID (1<<0) /* Die Partei hat bereits einmal ihre no gewechselt */ -#define FFL_ISNEW (1<<1) -#define FFL_RESTART (1<<2) -#define FFL_QUIT (1<<3) -#define FFL_DEFENDER (1<<10) -#define FFL_SELECT (1<<18) /* ehemals f->dh, u->dh, r->dh, etc... */ -#define FFL_NOAID (1<<21) /* Hilfsflag Kampf */ -#define FFL_MARK (1<<23) /* für markierende algorithmen, die das - * hinterher auch wieder löschen müssen! - * (FFL_SELECT muss man vorher initialisieren, - * FL_MARK hinterher löschen) */ -#define FFL_NOIDLEOUT (1<<24) /* Partei stirbt nicht an NMRs */ -#define FFL_OVERRIDE (1<<27) /* Override-Passwort wurde benutzt */ -#define FFL_DBENTRY (1<<28) /* Partei ist in Datenbank eingetragen */ -#define FFL_NOTIMEOUT (1<<29) /* ignore MaxAge() */ -#define FFL_GM (1<<30) /* eine Partei mit Sonderrechten */ -#define FFL_NPC (1<<31) /* eine Partei mit Monstern */ - -#define FFL_SAVEMASK (FFL_DEFENDER|FFL_NEWID|FFL_GM|FFL_NPC|FFL_NOTIMEOUT|FFL_DBENTRY|FFL_NOTIMEOUT) - -struct faction * get_monsters(void); -#define is_monsters(f) ((f)->flags&FFL_NPC) - -typedef struct faction { - struct faction *next; - struct faction *nexthash; - - struct player *owner; -#ifdef SMART_INTERVALS - struct region *first; - struct region *last; -#endif - int no; - int subscription; - unsigned int flags; - char *name; - char *banner; - char *email; - char *passw; - char *override; - int max_spelllevel; - struct spell_list * spellbook; - const struct locale * locale; - int lastorders; /* enno: short? */ - int age; /* enno: short? */ - struct ursprung *ursprung; - const struct race * race; - magic_t magiegebiet; - int newbies; - int num_people; /* Anzahl Personen ohne Monster */ - int num_total; /* Anzahl Personen mit Monstern */ - int options; - int no_units; - struct ally *allies; - struct group *groups; - boolean alive; /* enno: sollte ein flag werden */ - int nregions; - int money; -#if SCORE_MODULE - int score; -#endif - struct alliance * alliance; - int alliance_joindate; /* the turn on which the faction joined its current alliance (or left the last one) */ -#ifdef VICTORY_DELAY - unsigned char victory_delay; -#endif - struct unit * units; - struct attrib *attribs; - struct message_list * msgs; - struct bmsg { - struct bmsg * next; - struct region * r; - struct message_list * msgs; - } * battles; - struct item * items; /* items this faction can claim */ - struct seen_region ** seen; -} faction; - -extern struct faction *factions; - -typedef struct faction_list { - struct faction_list * next; - struct faction * data; -} faction_list; - -extern const struct unit * random_unit_in_faction(const struct faction *f); -extern const char * factionname(const struct faction * f); -extern struct unit * addplayer(struct region *r, faction * f); -extern struct faction * addfaction(const char *email, const char* password, - const struct race * frace, - const struct locale *loc, int subscription); -extern boolean checkpasswd(const faction * f, const char * passwd, boolean shortp); -extern void destroyfaction(faction * f); - -extern void set_alliance(struct faction * a, struct faction * b, int status); -extern int get_alliance(const struct faction * a, const struct faction * b); - -extern struct alliance * f_get_alliance(const struct faction * a); - -extern void write_faction_reference(const struct faction * f, struct storage * store); -extern variant read_faction_reference(struct storage * store); -extern int resolve_faction(variant data, void * addr); - -extern void renumber_faction(faction * f, int no); -void free_faction(struct faction * f); - -#ifdef SMART_INTERVALS -extern void update_interval(struct faction * f, struct region * r); -#endif - -const char * faction_getbanner(const struct faction * self); -void faction_setbanner(struct faction * self, const char * name); - -const char * faction_getname(const struct faction * self); -void faction_setname(struct faction * self, const char * name); - -const char * faction_getemail(const struct faction * self); -void faction_setemail(struct faction * self, const char * email); - -const char * faction_getpassword(const struct faction * self); -void faction_setpassword(struct faction * self, const char * password); -boolean valid_race(const struct faction * f, const struct race * rc); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_FACTION +#define H_KRNL_FACTION +#ifdef __cplusplus +extern "C" { +#endif + +struct player; +struct alliance; +struct item; +struct seen_region; + +/* SMART_INTERVALS: define to speed up finding the interval of regions that a + faction is in. defining this speeds up the turn by 30-40% */ +#define SMART_INTERVALS + +/* faction flags */ +#define FFL_NEWID (1<<0) /* Die Partei hat bereits einmal ihre no gewechselt */ +#define FFL_ISNEW (1<<1) +#define FFL_RESTART (1<<2) +#define FFL_QUIT (1<<3) +#define FFL_DEFENDER (1<<10) +#define FFL_SELECT (1<<18) /* ehemals f->dh, u->dh, r->dh, etc... */ +#define FFL_NOAID (1<<21) /* Hilfsflag Kampf */ +#define FFL_MARK (1<<23) /* für markierende algorithmen, die das + * hinterher auch wieder löschen müssen! + * (FFL_SELECT muss man vorher initialisieren, + * FL_MARK hinterher löschen) */ +#define FFL_NOIDLEOUT (1<<24) /* Partei stirbt nicht an NMRs */ +#define FFL_OVERRIDE (1<<27) /* Override-Passwort wurde benutzt */ +#define FFL_DBENTRY (1<<28) /* Partei ist in Datenbank eingetragen */ +#define FFL_NOTIMEOUT (1<<29) /* ignore MaxAge() */ +#define FFL_GM (1<<30) /* eine Partei mit Sonderrechten */ +#define FFL_NPC (1<<31) /* eine Partei mit Monstern */ + +#define FFL_SAVEMASK (FFL_DEFENDER|FFL_NEWID|FFL_GM|FFL_NPC|FFL_NOTIMEOUT|FFL_DBENTRY|FFL_NOTIMEOUT) + +struct faction * get_monsters(void); +#define is_monsters(f) ((f)->flags&FFL_NPC) + +typedef struct faction { + struct faction *next; + struct faction *nexthash; + + struct player *owner; +#ifdef SMART_INTERVALS + struct region *first; + struct region *last; +#endif + int no; + int subscription; + unsigned int flags; + char *name; + char *banner; + char *email; + char *passw; + char *override; + int max_spelllevel; + struct spell_list * spellbook; + const struct locale * locale; + int lastorders; /* enno: short? */ + int age; /* enno: short? */ + struct ursprung *ursprung; + const struct race * race; + magic_t magiegebiet; + int newbies; + int num_people; /* Anzahl Personen ohne Monster */ + int num_total; /* Anzahl Personen mit Monstern */ + int options; + int no_units; + struct ally *allies; + struct group *groups; + boolean alive; /* enno: sollte ein flag werden */ + int nregions; + int money; +#if SCORE_MODULE + int score; +#endif + struct alliance * alliance; + int alliance_joindate; /* the turn on which the faction joined its current alliance (or left the last one) */ +#ifdef VICTORY_DELAY + unsigned char victory_delay; +#endif + struct unit * units; + struct attrib *attribs; + struct message_list * msgs; + struct bmsg { + struct bmsg * next; + struct region * r; + struct message_list * msgs; + } * battles; + struct item * items; /* items this faction can claim */ + struct seen_region ** seen; +} faction; + +extern struct faction *factions; + +typedef struct faction_list { + struct faction_list * next; + struct faction * data; +} faction_list; + +extern const struct unit * random_unit_in_faction(const struct faction *f); +extern const char * factionname(const struct faction * f); +extern struct unit * addplayer(struct region *r, faction * f); +extern struct faction * addfaction(const char *email, const char* password, + const struct race * frace, + const struct locale *loc, int subscription); +extern boolean checkpasswd(const faction * f, const char * passwd, boolean shortp); +extern void destroyfaction(faction * f); + +extern void set_alliance(struct faction * a, struct faction * b, int status); +extern int get_alliance(const struct faction * a, const struct faction * b); + +extern struct alliance * f_get_alliance(const struct faction * a); + +extern void write_faction_reference(const struct faction * f, struct storage * store); +extern variant read_faction_reference(struct storage * store); +extern int resolve_faction(variant data, void * addr); + +extern void renumber_faction(faction * f, int no); +void free_faction(struct faction * f); + +#ifdef SMART_INTERVALS +extern void update_interval(struct faction * f, struct region * r); +#endif + +const char * faction_getbanner(const struct faction * self); +void faction_setbanner(struct faction * self, const char * name); + +const char * faction_getname(const struct faction * self); +void faction_setname(struct faction * self, const char * name); + +const char * faction_getemail(const struct faction * self); +void faction_setemail(struct faction * self, const char * email); + +const char * faction_getpassword(const struct faction * self); +void faction_setpassword(struct faction * self, const char * password); +boolean valid_race(const struct faction * f, const struct race * rc); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/group.c b/src/kernel/group.c index 1c2c23bff..4838e26fc 100644 --- a/src/kernel/group.c +++ b/src/kernel/group.c @@ -1,243 +1,243 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "group.h" - -/* kernel includes */ -#include "unit.h" -#include "faction.h" -#include "save.h" -#include "version.h" - -/* attrib includes */ -#include - -/* util includes */ -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -#define GMAXHASH 2039 -static group * ghash[GMAXHASH]; -static int maxgid; - -static group * -new_group(faction * f, const char * name, int gid) -{ - group ** gp = &f->groups; - int index = gid % GMAXHASH; - group * g = calloc(sizeof(group), 1); - - while (*gp) gp = &(*gp)->next; - *gp = g; - - maxgid = MAX(gid, maxgid); - g->name = strdup(name); - g->gid = gid; - - g->nexthash = ghash[index]; - return ghash[index] = g; -} - -static void -init_group(faction * f, group * g) -{ - ally * a, ** an; - - an = &g->allies; - for (a=f->allies;a;a=a->next) if (a->faction) { - ally * ga = calloc(sizeof(ally), 1); - *ga = *a; - *an = ga; - an = &ga->next; - } -} - -static group * -find_groupbyname(group * g, const char * name) -{ - while (g && unicode_utf8_strcasecmp(name, g->name)!=0) g = g->next; - return g; -} - -static group * -find_group(int gid) -{ - int index = gid % GMAXHASH; - group * g = ghash[index]; - while (g && g->gid!=gid) g = g->nexthash; - return g; -} - -static int -read_group(attrib * a, void * owner, struct storage * store) -{ - group * g; - int gid = store->r_int(store); - a->data.v = g = find_group(gid); - if (g!=0) { - g->members++; - return AT_READ_OK; - } - return AT_READ_FAIL; -} - -static void -write_group(const attrib * a, const void * owner, struct storage * store) -{ - group * g = (group*)a->data.v; - store->w_int(store, g->gid); -} - -attrib_type -at_group = { /* attribute for units assigned to a group */ - "grp", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - write_group, - read_group, - ATF_UNIQUE -}; - -void -free_group(group * g) -{ - int index = g->gid % GMAXHASH; - group ** g_ptr = ghash+index; - while (*g_ptr && (*g_ptr)->gid!=g->gid) g_ptr = &(*g_ptr)->nexthash; - assert(*g_ptr==g); - *g_ptr = g->nexthash; - - while (g->allies) { - ally * a = g->allies; - g->allies = a->next; - free(a); - } - free(g->name); - free(g); -} - -void -set_group(struct unit * u, struct group * g) -{ - attrib * a = NULL; - - if (fval(u, UFL_GROUP)) { - a = a_find(u->attribs, &at_group); - } - - if (a) { - group * og = (group *)a->data.v; - if (og==g) return; - --og->members; - } - - if (g) { - if (!a) { - a = a_add(&u->attribs, a_new(&at_group)); - fset(u, UFL_GROUP); - } - a->data.v = g; - g->members++; - } else if (a) { - a_remove(&u->attribs, a); - freset(u, UFL_GROUP); - } -} - -boolean -join_group(unit * u, const char * name) -{ - group * g = NULL; - - if (name && name[0]) { - g = find_groupbyname(u->faction->groups, name); - if (g==NULL) { - g = new_group(u->faction, name, ++maxgid); - init_group(u->faction, g); - } - } - - set_group(u, g); - return true; -} - -void -write_groups(struct storage * store, group * g) -{ - while (g) { - ally * a; - store->w_int(store, g->gid); - store->w_str(store, g->name); - for (a=g->allies;a;a=a->next) { - if (a->faction) { - write_faction_reference(a->faction, store); - store->w_int(store, a->status); - } - } - store->w_id(store, 0); - a_write(store, g->attribs, g); - store->w_brk(store); - g=g->next; - } - store->w_int(store, 0); -} - -void -read_groups(struct storage * store, faction * f) -{ - for(;;) { - ally ** pa; - group * g; - int gid; - char buf[1024]; - - gid = store->r_int(store); - if (gid==0) break; - store->r_str_buf(store, buf, sizeof(buf)); - g = new_group(f, buf, gid); - pa = &g->allies; - for (;;) { - ally * a; - variant fid; - fid.i = store->r_id(store); - if (fid.i<=0) break; - if (store->versionnext; - a->status = store->r_int(store); - - a->faction = findfaction(fid.i); - if (!a->faction) ur_add(fid, &a->faction, resolve_faction); - } - *pa = 0; - a_read(store, &g->attribs, g); - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "group.h" + +/* kernel includes */ +#include "unit.h" +#include "faction.h" +#include "save.h" +#include "version.h" + +/* attrib includes */ +#include + +/* util includes */ +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +#define GMAXHASH 2039 +static group * ghash[GMAXHASH]; +static int maxgid; + +static group * +new_group(faction * f, const char * name, int gid) +{ + group ** gp = &f->groups; + int index = gid % GMAXHASH; + group * g = calloc(sizeof(group), 1); + + while (*gp) gp = &(*gp)->next; + *gp = g; + + maxgid = MAX(gid, maxgid); + g->name = strdup(name); + g->gid = gid; + + g->nexthash = ghash[index]; + return ghash[index] = g; +} + +static void +init_group(faction * f, group * g) +{ + ally * a, ** an; + + an = &g->allies; + for (a=f->allies;a;a=a->next) if (a->faction) { + ally * ga = calloc(sizeof(ally), 1); + *ga = *a; + *an = ga; + an = &ga->next; + } +} + +static group * +find_groupbyname(group * g, const char * name) +{ + while (g && unicode_utf8_strcasecmp(name, g->name)!=0) g = g->next; + return g; +} + +static group * +find_group(int gid) +{ + int index = gid % GMAXHASH; + group * g = ghash[index]; + while (g && g->gid!=gid) g = g->nexthash; + return g; +} + +static int +read_group(attrib * a, void * owner, struct storage * store) +{ + group * g; + int gid = store->r_int(store); + a->data.v = g = find_group(gid); + if (g!=0) { + g->members++; + return AT_READ_OK; + } + return AT_READ_FAIL; +} + +static void +write_group(const attrib * a, const void * owner, struct storage * store) +{ + group * g = (group*)a->data.v; + store->w_int(store, g->gid); +} + +attrib_type +at_group = { /* attribute for units assigned to a group */ + "grp", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + write_group, + read_group, + ATF_UNIQUE +}; + +void +free_group(group * g) +{ + int index = g->gid % GMAXHASH; + group ** g_ptr = ghash+index; + while (*g_ptr && (*g_ptr)->gid!=g->gid) g_ptr = &(*g_ptr)->nexthash; + assert(*g_ptr==g); + *g_ptr = g->nexthash; + + while (g->allies) { + ally * a = g->allies; + g->allies = a->next; + free(a); + } + free(g->name); + free(g); +} + +void +set_group(struct unit * u, struct group * g) +{ + attrib * a = NULL; + + if (fval(u, UFL_GROUP)) { + a = a_find(u->attribs, &at_group); + } + + if (a) { + group * og = (group *)a->data.v; + if (og==g) return; + --og->members; + } + + if (g) { + if (!a) { + a = a_add(&u->attribs, a_new(&at_group)); + fset(u, UFL_GROUP); + } + a->data.v = g; + g->members++; + } else if (a) { + a_remove(&u->attribs, a); + freset(u, UFL_GROUP); + } +} + +boolean +join_group(unit * u, const char * name) +{ + group * g = NULL; + + if (name && name[0]) { + g = find_groupbyname(u->faction->groups, name); + if (g==NULL) { + g = new_group(u->faction, name, ++maxgid); + init_group(u->faction, g); + } + } + + set_group(u, g); + return true; +} + +void +write_groups(struct storage * store, group * g) +{ + while (g) { + ally * a; + store->w_int(store, g->gid); + store->w_str(store, g->name); + for (a=g->allies;a;a=a->next) { + if (a->faction) { + write_faction_reference(a->faction, store); + store->w_int(store, a->status); + } + } + store->w_id(store, 0); + a_write(store, g->attribs, g); + store->w_brk(store); + g=g->next; + } + store->w_int(store, 0); +} + +void +read_groups(struct storage * store, faction * f) +{ + for(;;) { + ally ** pa; + group * g; + int gid; + char buf[1024]; + + gid = store->r_int(store); + if (gid==0) break; + store->r_str_buf(store, buf, sizeof(buf)); + g = new_group(f, buf, gid); + pa = &g->allies; + for (;;) { + ally * a; + variant fid; + fid.i = store->r_id(store); + if (fid.i<=0) break; + if (store->versionnext; + a->status = store->r_int(store); + + a->faction = findfaction(fid.i); + if (!a->faction) ur_add(fid, &a->faction, resolve_faction); + } + *pa = 0; + a_read(store, &g->attribs, g); + } +} diff --git a/src/kernel/group.h b/src/kernel/group.h index 0db22cd6d..63f8c0ba8 100644 --- a/src/kernel/group.h +++ b/src/kernel/group.h @@ -1,51 +1,51 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KERNEL_GROUP -#define H_KERNEL_GROUP -#ifdef __cplusplus -extern "C" { -#endif - -/* bitfield value for group::flags */ -#define GFL_ALIVE 0x01 /* There is at least one struct unit in the group */ - -typedef struct group { - struct group * next; - struct group * nexthash; - struct faction * f; - struct attrib *attribs; - char * name; - struct ally * allies; - int flags; - int gid; - int members; -} group; - -extern struct attrib_type at_group; /* attribute for units assigned to a group */ -extern boolean join_group(struct unit * u, const char * name); -extern void set_group(struct unit * u, struct group * g); -extern void free_group(struct group * g); - -extern void write_groups(struct storage * F, struct group * g); -extern void read_groups(struct storage * F, struct faction * f); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KERNEL_GROUP +#define H_KERNEL_GROUP +#ifdef __cplusplus +extern "C" { +#endif + +/* bitfield value for group::flags */ +#define GFL_ALIVE 0x01 /* There is at least one struct unit in the group */ + +typedef struct group { + struct group * next; + struct group * nexthash; + struct faction * f; + struct attrib *attribs; + char * name; + struct ally * allies; + int flags; + int gid; + int members; +} group; + +extern struct attrib_type at_group; /* attribute for units assigned to a group */ +extern boolean join_group(struct unit * u, const char * name); +extern void set_group(struct unit * u, struct group * g); +extern void free_group(struct group * g); + +extern void write_groups(struct storage * F, struct group * g); +extern void read_groups(struct storage * F, struct faction * f); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/item.c b/src/kernel/item.c index ce329460b..02e110f93 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -1,1186 +1,1185 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "item.h" - -#include - -#include "alchemy.h" -#include "build.h" -#include "faction.h" -#include "message.h" -#include "pool.h" -#include "race.h" -#include "region.h" -#include "save.h" -#include "skill.h" -#include "terrain.h" -#include "unit.h" - -/* triggers includes */ -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -resource_type * resourcetypes; -luxury_type * luxurytypes; -potion_type * potiontypes; - -#define IMAXHASH 127 -static item_type * itemtypes[IMAXHASH]; - -static int -res_changeaura(unit * u, const resource_type * rtype, int delta) -{ - assert(rtype!=NULL); - change_spellpoints(u, delta); - return 0; -} - -static int -res_changeperson(unit * u, const resource_type * rtype, int delta) -{ - assert(rtype!=NULL || !"not implemented"); - scale_number(u, u->number+delta); - return 0; -} - -static int -res_changepermaura(unit * u, const resource_type * rtype, int delta) -{ - assert(rtype!=NULL); - change_maxspellpoints(u, delta); - return 0; -} - -static int -res_changehp(unit * u, const resource_type * rtype, int delta) -{ - assert(rtype!=NULL); - u->hp+=delta; - return 0; -} - -static int -res_changepeasants(unit * u, const resource_type * rtype, int delta) -{ - assert(rtype!=NULL && u->region->land); - u->region->land->peasants+=delta; - return 0; -} - -int -res_changeitem(unit * u, const resource_type * rtype, int delta) -{ - int num; - if (rtype == oldresourcetype[R_STONE] && u->race==new_race[RC_STONEGOLEM] && delta<=0) { - int reduce = delta / GOLEM_STONE; - if (delta % GOLEM_STONE != 0) --reduce; - scale_number(u, u->number+reduce); - num = u->number; - } else if (rtype == oldresourcetype[R_IRON] && u->race==new_race[RC_IRONGOLEM] && delta<=0) { - int reduce = delta / GOLEM_IRON; - if (delta % GOLEM_IRON != 0) --reduce; - scale_number(u, u->number+reduce); - num = u->number; - } else { - const item_type * itype = resource2item(rtype); - item * i; - assert(itype!=NULL); - i = i_change(&u->items, itype, delta); - if (i==NULL) return 0; - num = i->number; - } - return num; -} - -const char * -resourcename(const resource_type * rtype, int flags) -{ - int i = 0; - - if (rtype) { - if (rtype->name) return rtype->name(rtype, flags); - - if (flags & NMF_PLURAL) i = 1; - if (flags & NMF_APPEARANCE && rtype->_appearance[i]) { - return rtype->_appearance[i]; - } - return rtype->_name[i]; - } - return "none"; -} - -resource_type * -new_resourcetype(const char ** names, const char ** appearances, int flags) -{ - resource_type * rtype = rt_find(names[0]); - - if (rtype==NULL) { - int i; - rtype = calloc(sizeof(resource_type), 1); - - for (i=0; i!=2; ++i) { - rtype->_name[i] = strdup(names[i]); - if (appearances) rtype->_appearance[i] = strdup(appearances[i]); - else rtype->_appearance[i] = NULL; - } - rt_register(rtype); - } -#ifndef NDEBUG - else { - /* TODO: check that this is the same type */ - } -#endif - rtype->flags |= flags; - return rtype; -} - -void -it_register(item_type * itype) -{ - int hash = hashstring(itype->rtype->_name[0]); - int key = hash % IMAXHASH; - item_type ** p_itype = &itemtypes[key]; - while (*p_itype && *p_itype != itype) p_itype = &(*p_itype)->next; - if (*p_itype==NULL) { - itype->rtype->itype = itype; - *p_itype = itype; - rt_register(itype->rtype); - } -} - -item_type * -new_itemtype(resource_type * rtype, - int iflags, int weight, int capacity) -{ - item_type * itype; - assert(resource2item(rtype) == NULL); - assert(rtype->flags & RTF_ITEM); - - itype = calloc(sizeof(item_type), 1); - - itype->rtype = rtype; - itype->weight = weight; - itype->capacity = capacity; - itype->flags |= iflags; - it_register(itype); - - rtype->uchange = res_changeitem; - - return itype; -} - -static void -lt_register(luxury_type * ltype) -{ - ltype->itype->rtype->ltype = ltype; - ltype->next = luxurytypes; - luxurytypes = ltype; -} - -luxury_type * -new_luxurytype(item_type * itype, int price) -{ - luxury_type * ltype; - - assert(resource2luxury(itype->rtype) == NULL); - - ltype = calloc(sizeof(luxury_type), 1); - ltype->itype = itype; - ltype->price = price; - lt_register(ltype); - - return ltype; -} - -weapon_type * -new_weapontype(item_type * itype, - int wflags, double magres, const char* damage[], int offmod, int defmod, int reload, skill_t sk, int minskill) -{ - weapon_type * wtype; - - assert(resource2weapon(itype->rtype)==NULL); - - wtype = calloc(sizeof(weapon_type), 1); - if (damage) { - wtype->damage[0] = strdup(damage[0]); - wtype->damage[1] = strdup(damage[1]); - } - wtype->defmod = defmod; - wtype->flags |= wflags; - wtype->itype = itype; - wtype->magres = magres; - wtype->minskill = minskill; - wtype->offmod = offmod; - wtype->reload = reload; - wtype->skill = sk; - itype->rtype->wtype = wtype; - - return wtype; -} - - -armor_type * -new_armortype(item_type * itype, double penalty, double magres, int prot, unsigned int flags) -{ - armor_type * atype; - - assert(itype->rtype->atype==NULL); - - atype = calloc(sizeof(armor_type), 1); - - atype->itype = itype; - atype->penalty = penalty; - atype->magres = magres; - atype->prot = prot; - atype->flags = flags; - itype->rtype->atype = atype; - - return atype; -} - -static void -pt_register(potion_type * ptype) -{ - ptype->itype->rtype->ptype = ptype; - ptype->next = potiontypes; - potiontypes = ptype; -} - -potion_type * -new_potiontype(item_type * itype, - int level) -{ - potion_type * ptype; - - assert(resource2potion(itype->rtype)==NULL); - - ptype = calloc(sizeof(potion_type), 1); - ptype->itype = itype; - ptype->level = level; - pt_register(ptype); - - return ptype; -} - - -void -rt_register(resource_type * rtype) -{ - resource_type ** prtype = &resourcetypes; - - if (!rtype->hashkey) { - rtype->hashkey = hashstring(rtype->_name[0]); - } - while (*prtype && *prtype!=rtype) prtype=&(*prtype)->next; - if (*prtype == NULL) { - *prtype = rtype; - } -} - -const resource_type * -item2resource(const item_type * itype) -{ - return itype?itype->rtype:NULL; -} - -const item_type * -resource2item(const resource_type * rtype) -{ - return rtype?rtype->itype:NULL; -} - -const weapon_type * -resource2weapon(const resource_type * rtype) { - return rtype->wtype; -} - -const luxury_type * -resource2luxury(const resource_type * rtype) -{ -#ifdef AT_LTYPE - attrib * a = a_find(rtype->attribs, &at_ltype); - if (a) return (const luxury_type *)a->data.v; - return NULL; -#else - return rtype->ltype; -#endif -} - -const potion_type * -resource2potion(const resource_type * rtype) -{ -#ifdef AT_PTYPE - attrib * a = a_find(rtype->attribs, &at_ptype); - if (a) return (const potion_type *)a->data.v; - return NULL; -#else - return rtype->ptype; -#endif -} - -resource_type * -rt_find(const char * name) -{ - unsigned int hash = hashstring(name); - resource_type * rtype; - - for (rtype=resourcetypes; rtype; rtype=rtype->next) { - if (rtype->hashkey==hash && !strcmp(rtype->_name[0], name)) break; - } - - return rtype; -} - -static const char * it_aliases[][2] = { - { "Runenschwert", "runesword" }, - { "p12", "truthpotion" }, - { "p1", "goliathwater" }, - { "p4", "ointment" }, - { "p5", "peasantblood" }, - { "p8", "nestwarmth" }, - { "diamond", "adamantium" }, - { "diamondaxe", "adamantiumaxe" }, - { "diamondplate", "adamantiumplate" }, - { "aoh", "ao_healing" }, - { NULL, NULL }, -}; - -static const char * -it_alias(const char * zname) -{ - int i; - for (i=0;it_aliases[i][0];++i) { - if (strcmp(it_aliases[i][0], zname)==0) return it_aliases[i][1]; - } - return zname; -} - -item_type * -it_find(const char * zname) -{ - const char * name = it_alias(zname); - unsigned int hash = hashstring(name); - item_type * itype; - unsigned int key = hash % IMAXHASH; - - for (itype=itemtypes[key]; itype; itype=itype->next) { - if (itype->rtype->hashkey==hash && strcmp(itype->rtype->_name[0], name) == 0) { - break; - } - } - if (itype==NULL) { - for (itype=itemtypes[key]; itype; itype=itype->next) { - if (strcmp(itype->rtype->_name[1], name) == 0) break; - } - } - return itype; -} - -item ** -i_find(item ** i, const item_type * it) -{ - while (*i && (*i)->type!=it) i = &(*i)->next; - return i; -} - -item * const * -i_findc(item * const * i, const item_type * it) -{ - while (*i && (*i)->type!=it) { - i = &(*i)->next; - } - return i; -} - -int -i_get(const item * i, const item_type * it) -{ - i = *i_find((item**)&i, it); - if (i) return i->number; - return 0; -} - -item * -i_add(item ** pi, item * i) -{ - assert(i && i->type && !i->next); - while (*pi) { - int d = strcmp((*pi)->type->rtype->_name[0], i->type->rtype->_name[0]); - if (d>=0) break; - pi = &(*pi)->next; - } - if (*pi && (*pi)->type==i->type) { - (*pi)->number += i->number; - assert((*pi)->number>=0); - i_free(i); - } else { - i->next = *pi; - *pi = i; - } - return *pi; -} - -void -i_merge(item ** pi, item ** si) -{ - item * i = *si; - while (i) { - item * itmp; - while (*pi) { - int d = strcmp((*pi)->type->rtype->_name[0], i->type->rtype->_name[0]); - if (d>=0) break; - pi=&(*pi)->next; - } - if (*pi && (*pi)->type==i->type) { - (*pi)->number += i->number; - assert((*pi)->number>=0); - i_free(i_remove(&i, i)); - } else { - itmp = i->next; - i->next=*pi; - *pi = i; - i = itmp; - } - } - *si=NULL; -} - -item * -i_change(item ** pi, const item_type * itype, int delta) -{ - assert(itype); - while (*pi) { - int d = strcmp((*pi)->type->rtype->_name[0], itype->rtype->_name[0]); - if (d>=0) break; - pi=&(*pi)->next; - } - if (!*pi || (*pi)->type!=itype) { - item * i; - if (delta==0) return NULL; - i = i_new(itype, delta); - i->next = *pi; - *pi = i; - } else { - item * i = *pi; - i->number+=delta; - if (i->number<0) { - log_error(("serious accounting error. number of items is %d.\n", i->number)); - assert(i>=0); - i->number = 0; - } - if (i->number==0) { - *pi = i->next; - i_free(i); - return NULL; - } - } - return *pi; -} - -item * -i_remove(item ** pi, item * i) -{ - assert(i); - while ((*pi)->type!=i->type) pi = &(*pi)->next; - assert(*pi); - *pi = i->next; - i->next = NULL; - return i; -} - -static item * icache; -static int icache_size; -#define ICACHE_MAX 100 - -void -i_free(item * i) -{ - if (icache_size>=ICACHE_MAX) { - free(i); - } else { - i->next = icache; - icache = i; - ++icache_size; - } -} - -void -i_freeall(item **i) { - item *in; - - while(*i) { - in = (*i)->next; - i_free(*i); - *i = in; - } -} - - -item * -i_new(const item_type * itype, int size) -{ - item * i; - if (icache_size>0) { - i = icache; - icache = i->next; - --icache_size; - } else { - i = malloc(sizeof(item)); - } - assert(itype); - i->next = NULL; - i->type = itype; - i->number = size; - assert(i->number>=0); - return i; -} - -#include "region.h" - -static int -give_horses(unit * s, unit * d, const item_type * itype, int n, struct order * ord) -{ - if (d==NULL) { - int use = use_pooled(s, item2resource(itype), GET_SLACK, n); - if (useregion, rhorses(s->region) + use); - return 0; - } - return -1; /* use the mechanism */ -} - -static int -give_money(unit * s, unit * d, const item_type * itype, int n, struct order * ord) -{ - if (d==NULL) { - int use = use_pooled(s, item2resource(itype), GET_SLACK, n); - if (useregion, rmoney(s->region) + use); - return 0; - } - return -1; /* use the mechanism */ -} - -#define R_MINOTHER R_SILVER -#define R_MINHERB R_PLAIN_1 -#define R_MINPOTION R_FAST -#define R_MINITEM R_IRON -#define MAXITEMS MAX_ITEMS -#define MAXRESOURCES MAX_RESOURCES -#define MAXHERBS MAX_HERBS -#define MAXPOTIONS MAX_POTIONS -#define MAXHERBSPERPOTION 6 -#define FIRSTLUXURY (I_BALM) -#define LASTLUXURY (I_INCENSE +1) -#define MAXLUXURIES (LASTLUXURY - FIRSTLUXURY) - -const item_type * olditemtype[MAXITEMS+1]; -const resource_type * oldresourcetype[MAXRESOURCES+1]; -const potion_type * oldpotiontype[MAXPOTIONS+1]; - -/*** alte items ***/ - -int -get_item(const unit * u, item_t it) -{ - const item_type * type = olditemtype[it]; - const item * i = *i_findc(&u->items, type); - if (i) assert(i->number>=0); - return i?i->number:0; -} - -int -set_item(unit * u, item_t it, int value) -{ - const item_type * type = olditemtype[it]; - item * i = *i_find(&u->items, type); - if (!i) { - i = i_add(&u->items, i_new(type, value)); - } else { - i->number = value; - assert(i->number>=0); - } - return value; -} - -static int -use_birthdayamulet(unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - direction_t d; - message * msg = msg_message("meow", ""); - - unused(ord); - unused(amount); - unused(itype); - - add_message(&u->region->msgs, msg); - for(d=0;dregion, d); - if (tr) add_message(&tr->msgs, msg); - } - msg_release(msg); - return 0; -} - - -/* t_item::flags */ -#define FL_ITEM_CURSED (1<<0) -#define FL_ITEM_NOTLOST (1<<1) -#define FL_ITEM_NOTINBAG (1<<2) /* nicht im Bag Of Holding */ -#define FL_ITEM_ANIMAL (1<<3) /* ist ein Tier */ -#define FL_ITEM_MOUNT ((1<<4) | FL_ITEM_ANIMAL) /* ist ein Reittier */ - -/* ------------------------------------------------------------- */ -/* Kann auch von Nichtmagier benutzt werden, modifiziert Taktik für diese - * Runde um -1 - 4 Punkte. */ -static int -use_tacticcrystal(unit * u, const struct item_type * itype, int amount, struct order * ord) -{ - int i; - for (i=0;i!=amount;++i) { - int duration = 1; /* wirkt nur eine Runde */ - float power = 5; /* Widerstand gegen Antimagiesprüche, ist in diesem - Fall egal, da der curse für den Kampf gelten soll, - der vor den Antimagiezaubern passiert */ - curse * c; - double effect; - - effect = rng_int()%6 - 1; - c = create_curse(u, &u->attribs, ct_find("skillmod"), power, - duration, effect, u->number); - c->data.i = SK_TACTICS; - unused(ord); - } - use_pooled(u, itype->rtype, GET_DEFAULT, amount); - ADDMSG(&u->faction->msgs, msg_message("use_tacticcrystal", - "unit region", u, u->region)); - return 0; -} - -typedef struct t_item { - const char *name; - /* [0]: Einzahl für eigene; [1]: Mehrzahl für eigene; - * [2]: Einzahl für Fremde; [3]: Mehrzahl für Fremde */ - boolean is_resource; - skill_t skill; - int minskill; - int gewicht; - int preis; - unsigned int flags; - void (*benutze_funktion) (struct region *, struct unit *, int amount, struct order *); -} t_item; - -const char * itemnames[MAXITEMS] = { - "iron", "stone", "horse", "ao_healing", - "aots", "roi", "rop", "ao_chastity", - "laen", "fairyboot", "aoc", "pegasus", - "elvenhorse", "dolphin", "roqf", "trollbelt", - "presspass", "aurafocus", "sphereofinv", "magicbag", - "magicherbbag", "dreameye" -}; - -#include "move.h" - -static int -mod_elves_only(const unit * u, const region * r, skill_t sk, int value) -{ - if (u->race == new_race[RC_ELF]) return value; - unused(r); - return -118; -} - -static int -mod_dwarves_only(const unit * u, const region * r, skill_t sk, int value) -{ - if (u->race == new_race[RC_DWARF]) return value; - unused(r); - return -118; -} - -static void -init_olditems(void) -{ - item_t i; -#if 0 - resource_type * rtype; - const struct locale * lang = find_locale("de"); - assert(lang); -#endif - - for (i=0; i!=MAXITEMS; ++i) { - /* item is defined in XML file, but IT_XYZ enum still in use */ - const item_type * itype = it_find(itemnames[i]); - - if (itype) { - olditemtype[i] = itype; - oldresourcetype[i] = itype->rtype; - } - } -} - -static int -heal(unit * user, int effect) -{ - int req = unit_max_hp(user) * user->number - user->hp; - if (req>0) { - req = MIN(req, effect); - effect -= req; - user->hp += req; - } - return effect; -} - -void -register_item_give(int (*foo) (struct unit *, struct unit *, const struct item_type *, int, struct order *), const char * name) -{ - register_function((pf_generic)foo, name); -} - -void -register_item_use(int (*foo) (struct unit *, const struct item_type *, int, struct order *), const char * name) -{ - register_function((pf_generic)foo, name); -} - -void -register_item_useonother(int (*foo) (struct unit *, int, const struct item_type *, int, struct order *), const char * name) -{ - register_function((pf_generic)foo, name); -} - -static int -use_healingpotion(struct unit *user, const struct item_type *itype, int amount, struct order * ord) -{ - int effect = amount * 400; - unit * u = user->region->units; - effect = heal(user, effect); - while (effect>0 && u!=NULL) { - if (u->faction==user->faction) { - effect = heal(u, effect); - } - u = u->next; - } - use_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); - usetpotionuse(user, itype->rtype->ptype); - - ADDMSG(&user->faction->msgs, msg_message("usepotion", - "unit potion", user, itype->rtype)); - return 0; -} - -static int -use_warmthpotion(struct unit *u, const struct item_type *itype, int amount, struct order * ord) -{ - if (u->faction->race == new_race[RC_INSECT]) { - fset(u, UFL_WARMTH); - } else { - /* nur für insekten: */ - cmistake(u, ord, 163, MSG_EVENT); - return ECUSTOM; - } - use_pooled(u, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); - usetpotionuse(u, itype->rtype->ptype); - - ADDMSG(&u->faction->msgs, msg_message("usepotion", - "unit potion", u, itype->rtype)); - return 0; -} - -static int -use_foolpotion(struct unit *u, int targetno, const struct item_type *itype, int amount, struct order * ord) -{ - unit * target = findunit(targetno); - if (target==NULL || u->region!=target->region) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return ECUSTOM; - } - if (effskill(u, SK_STEALTH)<=effskill(target, SK_PERCEPTION)) { - cmistake(u, ord, 64, MSG_EVENT); - return ECUSTOM; - } - ADDMSG(&u->faction->msgs, msg_message("givedumb", - "unit recipient amount", u, target, amount)); - - change_effect(target, itype->rtype->ptype, amount); - use_pooled(u, itype->rtype, GET_DEFAULT, amount); - return 0; -} - -static int -use_bloodpotion(struct unit *u, const struct item_type *itype, int amount, struct order * ord) -{ - if (u->race == new_race[RC_DAEMON]) { - change_effect(u, itype->rtype->ptype, 100*amount); - } else { - const race * irace = u_irace(u); - if (irace == u->race) { - static race * rcfailure; - if (!rcfailure) { - rcfailure = rc_find("smurf"); - if (!rcfailure) rcfailure = rc_find("toad"); - } - if (rcfailure) { - trigger * trestore = trigger_changerace(u, u->race, irace); - if (trestore) { - int duration = 2 + rng_int() % 8; - - add_trigger(&u->attribs, "timer", trigger_timeout(duration, trestore)); - u->irace = NULL; - u->race = rcfailure; - } - } - } - } - use_pooled(u, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); - usetpotionuse(u, itype->rtype->ptype); - - ADDMSG(&u->faction->msgs, msg_message("usepotion", - "unit potion", u, itype->rtype)); - return 0; -} - -#include -static int -use_mistletoe(struct unit * user, const struct item_type * itype, int amount, struct order * ord) -{ - int mtoes = get_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); - - if (user->number>mtoes) { - ADDMSG(&user->faction->msgs, msg_message("use_singleperson", - "unit item region command", user, itype->rtype, user->region, ord)); - return -1; - } - use_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); - a_add(&user->attribs, make_fleechance((float)1.0)); - ADDMSG(&user->faction->msgs, - msg_message("use_item", "unit item", user, itype->rtype)); - - return 0; -} - -static int -use_magicboost(struct unit * user, const struct item_type * itype, int amount, struct order * ord) -{ - int mtoes = get_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); - faction * f = user->faction; - if (user->number>mtoes) { - ADDMSG(&user->faction->msgs, msg_message("use_singleperson", - "unit item region command", user, itype->rtype, user->region, ord)); - return -1; - } - if (!is_mage(user) || find_key(f->attribs, atoi36("mbst"))!=NULL) { - cmistake(user, user->thisorder, 214, MSG_EVENT); - return -1; - } - use_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); - - a_add(&f->attribs, make_key(atoi36("mbst"))); - set_level(user, sk_find("magic"), 3); - - ADDMSG(&user->faction->msgs, msg_message("use_item", - "unit item", user, itype->rtype)); - - return 0; -} - -static int -use_snowball(struct unit * user, const struct item_type * itype, int amount, struct order * ord) -{ - return 0; -} - -static void -init_oldpotions(void) -{ - const char * potionnames[MAX_POTIONS] = { - "p0", "goliathwater", "p2", "p3", "ointment", "peasantblood", "p6", - "p7", "nestwarmth", "p9", "p10", "p11", "truthpotion", "p13", "p14" - }; - int p; - - for (p=0;p!=MAXPOTIONS;++p) { - item_type * itype = it_find(potionnames[p]); - if (itype!=NULL) { - oldpotiontype[p] = itype->rtype->ptype; - } - } -} - -resource_type * r_silver; -resource_type * r_aura; -resource_type * r_permaura; -resource_type * r_unit; -resource_type * r_hp; - -resource_type * r_silver; -item_type * i_silver; - -static const char * names[] = { - "money", "money_p", - "person", "person_p", - "permaura", "permaura_p", - "hp", "hp_p", - "peasant", "peasant_p", - "aura", "aura_p", - "unit", "unit_p" -}; - -void -init_resources(void) -{ - static boolean initialized = false; - if (initialized) return; - initialized = true; - - /* silver was never an item: */ - r_silver = new_resourcetype(&names[0], NULL, RTF_ITEM|RTF_POOLED); - i_silver = new_itemtype(r_silver, ITF_NONE, 1/*weight*/, 0); - r_silver->uchange = res_changeitem; - i_silver->give = give_money; - - r_permaura = new_resourcetype(&names[4], NULL, RTF_NONE); - r_permaura->uchange = res_changepermaura; - - r_hp = new_resourcetype(&names[6], NULL, RTF_NONE); - r_hp->uchange = res_changehp; - - r_aura = new_resourcetype(&names[10], NULL, RTF_NONE); - r_aura->uchange = res_changeaura; - - r_unit = new_resourcetype(&names[12], NULL, RTF_NONE); - r_unit->uchange = res_changeperson; - - oldresourcetype[R_SILVER] = r_silver; - oldresourcetype[R_AURA] = r_aura; - oldresourcetype[R_PERMAURA] = r_permaura; - - /* alte typen registrieren: */ - init_olditems(); - init_oldpotions(); -} - -int -get_money(const unit * u) -{ - const item * i = u->items; - while (i && i->type!=i_silver) i=i->next; - if (i==NULL) return 0; - return i->number; -} - -int -set_money(unit * u, int v) -{ - item ** ip = &u->items; - while (*ip && (*ip)->type!=i_silver) ip = &(*ip)->next; - if ((*ip)==NULL && v) { - i_add(&u->items, i_new(i_silver, v)); - return v; - } - if ((*ip)!=NULL) { - if (v) { - (*ip)->number = v; - assert((*ip)->number>=0); - } - else i_remove(ip, *ip); - } - return v; -} - -int -change_money(unit * u, int v) -{ - item ** ip = &u->items; - while (*ip && (*ip)->type!=i_silver) ip = &(*ip)->next; - if ((*ip)==NULL && v) { - i_add(&u->items, i_new(i_silver, v)); - return v; - } - if ((*ip)!=NULL) { - item * i = *ip; - if (i->number + v != 0) { - i->number += v; - assert(i->number>=0); - return i->number; - } - else i_free(i_remove(ip, *ip)); - } - return 0; -} - - -static local_names * rnames; - -const resource_type * -findresourcetype(const char * name, const struct locale * lang) -{ - local_names * rn = rnames; - variant token; - - while (rn) { - if (rn->lang==lang) break; - rn = rn->next; - } - if (!rn) { - const resource_type * rtl = resourcetypes; - rn = calloc(sizeof(local_names), 1); - rn->next = rnames; - rn->lang = lang; - while (rtl) { - token.v = (void*)rtl; - addtoken(&rn->names, locale_string(lang, rtl->_name[0]), token); - addtoken(&rn->names, locale_string(lang, rtl->_name[1]), token); - rtl=rtl->next; - } - rnames = rn; - } - - if (findtoken(&rn->names, name, &token)==E_TOK_NOMATCH) return NULL; - return (const resource_type*)token.v; -} - -attrib_type at_showitem = { - "showitem" -}; - -static local_names * inames; - -void -init_itemnames(void) -{ - int i; - for (i=0;localenames[i];++i) { - const struct locale * lang = find_locale(localenames[i]); - boolean exist = false; - local_names * in = inames; - - while (in!=NULL) { - if (in->lang==lang) { - exist = true; - break; - } - in = in->next; - } - if (in==NULL) in = calloc(sizeof(local_names), 1); - in->next = inames; - in->lang = lang; - - if (!exist) { - int key; - for (key=0;key!=IMAXHASH;++key) { - const item_type * itl; - for (itl=itemtypes[key];itl;itl=itl->next) { - variant var; - const char * iname = locale_string(lang, itl->rtype->_name[0]); - if (findtoken(&in->names, iname, &var)==E_TOK_NOMATCH || var.v!=itl) { - var.v = (void*)itl; - addtoken(&in->names, iname, var); - addtoken(&in->names, locale_string(lang, itl->rtype->_name[1]), var); - } - } - } - } - inames = in; - } -} - -const item_type * -finditemtype(const char * name, const struct locale * lang) -{ - local_names * in = inames; - variant var; - - while (in!=NULL) { - if (in->lang==lang) break; - in=in->next; - } - if (in==NULL) { - init_itemnames(); - for (in=inames;in->lang!=lang;in=in->next) ; - } - if (findtoken(&in->names, name, &var)==E_TOK_NOMATCH) return NULL; - return (const item_type*)var.v; -} - -static void -init_resourcelimit(attrib * a) -{ - a->data.v = calloc(sizeof(resource_limit), 1); -} - -static void -finalize_resourcelimit(attrib * a) -{ - free(a->data.v); -} - -attrib_type at_resourcelimit = { - "resourcelimit", - init_resourcelimit, - finalize_resourcelimit, -}; - -void -register_resources(void) -{ - register_function((pf_generic)mod_elves_only, "mod_elves_only"); - register_function((pf_generic)mod_dwarves_only, "mod_dwarves_only"); - register_function((pf_generic)res_changeitem, "changeitem"); - register_function((pf_generic)res_changeperson, "changeperson"); - register_function((pf_generic)res_changepeasants, "changepeasants"); - register_function((pf_generic)res_changepermaura, "changepermaura"); - register_function((pf_generic)res_changehp, "changehp"); - register_function((pf_generic)res_changeaura, "changeaura"); - - register_item_use(use_potion, "usepotion"); - register_item_use(use_potion_delayed, "usepotion_delayed"); - register_item_use(use_tacticcrystal, "use_tacticcrystal"); - register_item_use(use_birthdayamulet, "use_birthdayamulet"); - register_item_use(use_warmthpotion, "usewarmthpotion"); - register_item_use(use_bloodpotion, "usebloodpotion"); - register_item_use(use_healingpotion, "usehealingpotion"); - register_item_useonother(use_foolpotion, "usefoolpotion"); - register_item_use(use_mistletoe, "usemistletoe"); - register_item_use(use_magicboost, "usemagicboost"); - register_item_use(use_snowball, "usesnowball"); - - register_item_give(give_horses, "givehorses"); - - /* make sure noone has deleted an I_ tpe without deleting the R_ type that goes with it! */ - assert((int)I_TACTICCRYSTAL == (int)R_TACTICCRYSTAL); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "item.h" + +#include + +#include "alchemy.h" +#include "build.h" +#include "faction.h" +#include "message.h" +#include "pool.h" +#include "race.h" +#include "region.h" +#include "save.h" +#include "skill.h" +#include "terrain.h" +#include "unit.h" + +/* triggers includes */ +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +resource_type * resourcetypes; +luxury_type * luxurytypes; +potion_type * potiontypes; + +#define IMAXHASH 127 +static item_type * itemtypes[IMAXHASH]; + +static int +res_changeaura(unit * u, const resource_type * rtype, int delta) +{ + assert(rtype!=NULL); + change_spellpoints(u, delta); + return 0; +} + +static int +res_changeperson(unit * u, const resource_type * rtype, int delta) +{ + assert(rtype!=NULL || !"not implemented"); + scale_number(u, u->number+delta); + return 0; +} + +static int +res_changepermaura(unit * u, const resource_type * rtype, int delta) +{ + assert(rtype!=NULL); + change_maxspellpoints(u, delta); + return 0; +} + +static int +res_changehp(unit * u, const resource_type * rtype, int delta) +{ + assert(rtype!=NULL); + u->hp+=delta; + return 0; +} + +static int +res_changepeasants(unit * u, const resource_type * rtype, int delta) +{ + assert(rtype!=NULL && u->region->land); + u->region->land->peasants+=delta; + return 0; +} + +int +res_changeitem(unit * u, const resource_type * rtype, int delta) +{ + int num; + if (rtype == oldresourcetype[R_STONE] && u->race==new_race[RC_STONEGOLEM] && delta<=0) { + int reduce = delta / GOLEM_STONE; + if (delta % GOLEM_STONE != 0) --reduce; + scale_number(u, u->number+reduce); + num = u->number; + } else if (rtype == oldresourcetype[R_IRON] && u->race==new_race[RC_IRONGOLEM] && delta<=0) { + int reduce = delta / GOLEM_IRON; + if (delta % GOLEM_IRON != 0) --reduce; + scale_number(u, u->number+reduce); + num = u->number; + } else { + const item_type * itype = resource2item(rtype); + item * i; + assert(itype!=NULL); + i = i_change(&u->items, itype, delta); + if (i==NULL) return 0; + num = i->number; + } + return num; +} + +const char * +resourcename(const resource_type * rtype, int flags) +{ + int i = 0; + + if (rtype) { + if (rtype->name) return rtype->name(rtype, flags); + + if (flags & NMF_PLURAL) i = 1; + if (flags & NMF_APPEARANCE && rtype->_appearance[i]) { + return rtype->_appearance[i]; + } + return rtype->_name[i]; + } + return "none"; +} + +resource_type * +new_resourcetype(const char ** names, const char ** appearances, int flags) +{ + resource_type * rtype = rt_find(names[0]); + + if (rtype==NULL) { + int i; + rtype = calloc(sizeof(resource_type), 1); + + for (i=0; i!=2; ++i) { + rtype->_name[i] = strdup(names[i]); + if (appearances) rtype->_appearance[i] = strdup(appearances[i]); + else rtype->_appearance[i] = NULL; + } + rt_register(rtype); + } +#ifndef NDEBUG + else { + /* TODO: check that this is the same type */ + } +#endif + rtype->flags |= flags; + return rtype; +} + +void +it_register(item_type * itype) +{ + int hash = hashstring(itype->rtype->_name[0]); + int key = hash % IMAXHASH; + item_type ** p_itype = &itemtypes[key]; + while (*p_itype && *p_itype != itype) p_itype = &(*p_itype)->next; + if (*p_itype==NULL) { + itype->rtype->itype = itype; + *p_itype = itype; + rt_register(itype->rtype); + } +} + +item_type * +new_itemtype(resource_type * rtype, + int iflags, int weight, int capacity) +{ + item_type * itype; + assert(resource2item(rtype) == NULL); + assert(rtype->flags & RTF_ITEM); + + itype = calloc(sizeof(item_type), 1); + + itype->rtype = rtype; + itype->weight = weight; + itype->capacity = capacity; + itype->flags |= iflags; + it_register(itype); + + rtype->uchange = res_changeitem; + + return itype; +} + +static void +lt_register(luxury_type * ltype) +{ + ltype->itype->rtype->ltype = ltype; + ltype->next = luxurytypes; + luxurytypes = ltype; +} + +luxury_type * +new_luxurytype(item_type * itype, int price) +{ + luxury_type * ltype; + + assert(resource2luxury(itype->rtype) == NULL); + + ltype = calloc(sizeof(luxury_type), 1); + ltype->itype = itype; + ltype->price = price; + lt_register(ltype); + + return ltype; +} + +weapon_type * +new_weapontype(item_type * itype, + int wflags, double magres, const char* damage[], int offmod, int defmod, int reload, skill_t sk, int minskill) +{ + weapon_type * wtype; + + assert(resource2weapon(itype->rtype)==NULL); + + wtype = calloc(sizeof(weapon_type), 1); + if (damage) { + wtype->damage[0] = strdup(damage[0]); + wtype->damage[1] = strdup(damage[1]); + } + wtype->defmod = defmod; + wtype->flags |= wflags; + wtype->itype = itype; + wtype->magres = magres; + wtype->minskill = minskill; + wtype->offmod = offmod; + wtype->reload = reload; + wtype->skill = sk; + itype->rtype->wtype = wtype; + + return wtype; +} + + +armor_type * +new_armortype(item_type * itype, double penalty, double magres, int prot, unsigned int flags) +{ + armor_type * atype; + + assert(itype->rtype->atype==NULL); + + atype = calloc(sizeof(armor_type), 1); + + atype->itype = itype; + atype->penalty = penalty; + atype->magres = magres; + atype->prot = prot; + atype->flags = flags; + itype->rtype->atype = atype; + + return atype; +} + +static void +pt_register(potion_type * ptype) +{ + ptype->itype->rtype->ptype = ptype; + ptype->next = potiontypes; + potiontypes = ptype; +} + +potion_type * +new_potiontype(item_type * itype, + int level) +{ + potion_type * ptype; + + assert(resource2potion(itype->rtype)==NULL); + + ptype = calloc(sizeof(potion_type), 1); + ptype->itype = itype; + ptype->level = level; + pt_register(ptype); + + return ptype; +} + + +void +rt_register(resource_type * rtype) +{ + resource_type ** prtype = &resourcetypes; + + if (!rtype->hashkey) { + rtype->hashkey = hashstring(rtype->_name[0]); + } + while (*prtype && *prtype!=rtype) prtype=&(*prtype)->next; + if (*prtype == NULL) { + *prtype = rtype; + } +} + +const resource_type * +item2resource(const item_type * itype) +{ + return itype?itype->rtype:NULL; +} + +const item_type * +resource2item(const resource_type * rtype) +{ + return rtype?rtype->itype:NULL; +} + +const weapon_type * +resource2weapon(const resource_type * rtype) { + return rtype->wtype; +} + +const luxury_type * +resource2luxury(const resource_type * rtype) +{ +#ifdef AT_LTYPE + attrib * a = a_find(rtype->attribs, &at_ltype); + if (a) return (const luxury_type *)a->data.v; + return NULL; +#else + return rtype->ltype; +#endif +} + +const potion_type * +resource2potion(const resource_type * rtype) +{ +#ifdef AT_PTYPE + attrib * a = a_find(rtype->attribs, &at_ptype); + if (a) return (const potion_type *)a->data.v; + return NULL; +#else + return rtype->ptype; +#endif +} + +resource_type * +rt_find(const char * name) +{ + unsigned int hash = hashstring(name); + resource_type * rtype; + + for (rtype=resourcetypes; rtype; rtype=rtype->next) { + if (rtype->hashkey==hash && !strcmp(rtype->_name[0], name)) break; + } + + return rtype; +} + +static const char * it_aliases[][2] = { + { "Runenschwert", "runesword" }, + { "p12", "truthpotion" }, + { "p1", "goliathwater" }, + { "p4", "ointment" }, + { "p5", "peasantblood" }, + { "p8", "nestwarmth" }, + { "diamond", "adamantium" }, + { "diamondaxe", "adamantiumaxe" }, + { "diamondplate", "adamantiumplate" }, + { "aoh", "ao_healing" }, + { NULL, NULL }, +}; + +static const char * +it_alias(const char * zname) +{ + int i; + for (i=0;it_aliases[i][0];++i) { + if (strcmp(it_aliases[i][0], zname)==0) return it_aliases[i][1]; + } + return zname; +} + +item_type * +it_find(const char * zname) +{ + const char * name = it_alias(zname); + unsigned int hash = hashstring(name); + item_type * itype; + unsigned int key = hash % IMAXHASH; + + for (itype=itemtypes[key]; itype; itype=itype->next) { + if (itype->rtype->hashkey==hash && strcmp(itype->rtype->_name[0], name) == 0) { + break; + } + } + if (itype==NULL) { + for (itype=itemtypes[key]; itype; itype=itype->next) { + if (strcmp(itype->rtype->_name[1], name) == 0) break; + } + } + return itype; +} + +item ** +i_find(item ** i, const item_type * it) +{ + while (*i && (*i)->type!=it) i = &(*i)->next; + return i; +} + +item * const * +i_findc(item * const * i, const item_type * it) +{ + while (*i && (*i)->type!=it) { + i = &(*i)->next; + } + return i; +} + +int +i_get(const item * i, const item_type * it) +{ + i = *i_find((item**)&i, it); + if (i) return i->number; + return 0; +} + +item * +i_add(item ** pi, item * i) +{ + assert(i && i->type && !i->next); + while (*pi) { + int d = strcmp((*pi)->type->rtype->_name[0], i->type->rtype->_name[0]); + if (d>=0) break; + pi = &(*pi)->next; + } + if (*pi && (*pi)->type==i->type) { + (*pi)->number += i->number; + assert((*pi)->number>=0); + i_free(i); + } else { + i->next = *pi; + *pi = i; + } + return *pi; +} + +void +i_merge(item ** pi, item ** si) +{ + item * i = *si; + while (i) { + item * itmp; + while (*pi) { + int d = strcmp((*pi)->type->rtype->_name[0], i->type->rtype->_name[0]); + if (d>=0) break; + pi=&(*pi)->next; + } + if (*pi && (*pi)->type==i->type) { + (*pi)->number += i->number; + assert((*pi)->number>=0); + i_free(i_remove(&i, i)); + } else { + itmp = i->next; + i->next=*pi; + *pi = i; + i = itmp; + } + } + *si=NULL; +} + +item * +i_change(item ** pi, const item_type * itype, int delta) +{ + assert(itype); + while (*pi) { + int d = strcmp((*pi)->type->rtype->_name[0], itype->rtype->_name[0]); + if (d>=0) break; + pi=&(*pi)->next; + } + if (!*pi || (*pi)->type!=itype) { + item * i; + if (delta==0) return NULL; + i = i_new(itype, delta); + i->next = *pi; + *pi = i; + } else { + item * i = *pi; + i->number+=delta; + if (i->number<0) { + log_error(("serious accounting error. number of items is %d.\n", i->number)); + assert(i>=0); + i->number = 0; + } + if (i->number==0) { + *pi = i->next; + i_free(i); + return NULL; + } + } + return *pi; +} + +item * +i_remove(item ** pi, item * i) +{ + assert(i); + while ((*pi)->type!=i->type) pi = &(*pi)->next; + assert(*pi); + *pi = i->next; + i->next = NULL; + return i; +} + +static item * icache; +static int icache_size; +#define ICACHE_MAX 100 + +void +i_free(item * i) +{ + if (icache_size>=ICACHE_MAX) { + free(i); + } else { + i->next = icache; + icache = i; + ++icache_size; + } +} + +void +i_freeall(item **i) { + item *in; + + while(*i) { + in = (*i)->next; + i_free(*i); + *i = in; + } +} + + +item * +i_new(const item_type * itype, int size) +{ + item * i; + if (icache_size>0) { + i = icache; + icache = i->next; + --icache_size; + } else { + i = malloc(sizeof(item)); + } + assert(itype); + i->next = NULL; + i->type = itype; + i->number = size; + assert(i->number>=0); + return i; +} + +#include "region.h" + +static int +give_horses(unit * s, unit * d, const item_type * itype, int n, struct order * ord) +{ + if (d==NULL) { + int use = use_pooled(s, item2resource(itype), GET_SLACK, n); + if (useregion, rhorses(s->region) + use); + return 0; + } + return -1; /* use the mechanism */ +} + +static int +give_money(unit * s, unit * d, const item_type * itype, int n, struct order * ord) +{ + if (d==NULL) { + int use = use_pooled(s, item2resource(itype), GET_SLACK, n); + if (useregion, rmoney(s->region) + use); + return 0; + } + return -1; /* use the mechanism */ +} + +#define R_MINOTHER R_SILVER +#define R_MINHERB R_PLAIN_1 +#define R_MINPOTION R_FAST +#define R_MINITEM R_IRON +#define MAXITEMS MAX_ITEMS +#define MAXRESOURCES MAX_RESOURCES +#define MAXHERBS MAX_HERBS +#define MAXPOTIONS MAX_POTIONS +#define MAXHERBSPERPOTION 6 +#define FIRSTLUXURY (I_BALM) +#define LASTLUXURY (I_INCENSE +1) +#define MAXLUXURIES (LASTLUXURY - FIRSTLUXURY) + +const item_type * olditemtype[MAXITEMS+1]; +const resource_type * oldresourcetype[MAXRESOURCES+1]; +const potion_type * oldpotiontype[MAXPOTIONS+1]; + +/*** alte items ***/ + +int +get_item(const unit * u, item_t it) +{ + const item_type * type = olditemtype[it]; + const item * i = *i_findc(&u->items, type); + if (i) assert(i->number>=0); + return i?i->number:0; +} + +int +set_item(unit * u, item_t it, int value) +{ + const item_type * type = olditemtype[it]; + item * i = *i_find(&u->items, type); + if (!i) { + i = i_add(&u->items, i_new(type, value)); + } else { + i->number = value; + assert(i->number>=0); + } + return value; +} + +static int +use_birthdayamulet(unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + direction_t d; + message * msg = msg_message("meow", ""); + + unused(ord); + unused(amount); + unused(itype); + + add_message(&u->region->msgs, msg); + for(d=0;dregion, d); + if (tr) add_message(&tr->msgs, msg); + } + msg_release(msg); + return 0; +} + + +/* t_item::flags */ +#define FL_ITEM_CURSED (1<<0) +#define FL_ITEM_NOTLOST (1<<1) +#define FL_ITEM_NOTINBAG (1<<2) /* nicht im Bag Of Holding */ +#define FL_ITEM_ANIMAL (1<<3) /* ist ein Tier */ +#define FL_ITEM_MOUNT ((1<<4) | FL_ITEM_ANIMAL) /* ist ein Reittier */ + +/* ------------------------------------------------------------- */ +/* Kann auch von Nichtmagier benutzt werden, modifiziert Taktik für diese + * Runde um -1 - 4 Punkte. */ +static int +use_tacticcrystal(unit * u, const struct item_type * itype, int amount, struct order * ord) +{ + int i; + for (i=0;i!=amount;++i) { + int duration = 1; /* wirkt nur eine Runde */ + float power = 5; /* Widerstand gegen Antimagiesprüche, ist in diesem + Fall egal, da der curse für den Kampf gelten soll, + der vor den Antimagiezaubern passiert */ + curse * c; + double effect; + + effect = rng_int()%6 - 1; + c = create_curse(u, &u->attribs, ct_find("skillmod"), power, + duration, effect, u->number); + c->data.i = SK_TACTICS; + unused(ord); + } + use_pooled(u, itype->rtype, GET_DEFAULT, amount); + ADDMSG(&u->faction->msgs, msg_message("use_tacticcrystal", + "unit region", u, u->region)); + return 0; +} + +typedef struct t_item { + const char *name; + /* [0]: Einzahl für eigene; [1]: Mehrzahl für eigene; + * [2]: Einzahl für Fremde; [3]: Mehrzahl für Fremde */ + boolean is_resource; + skill_t skill; + int minskill; + int gewicht; + int preis; + unsigned int flags; + void (*benutze_funktion) (struct region *, struct unit *, int amount, struct order *); +} t_item; + +const char * itemnames[MAXITEMS] = { + "iron", "stone", "horse", "ao_healing", + "aots", "roi", "rop", "ao_chastity", + "laen", "fairyboot", "aoc", "pegasus", + "elvenhorse", "dolphin", "roqf", "trollbelt", + "presspass", "aurafocus", "sphereofinv", "magicbag", + "magicherbbag", "dreameye" +}; + +#include "move.h" + +static int +mod_elves_only(const unit * u, const region * r, skill_t sk, int value) +{ + if (u->race == new_race[RC_ELF]) return value; + unused(r); + return -118; +} + +static int +mod_dwarves_only(const unit * u, const region * r, skill_t sk, int value) +{ + if (u->race == new_race[RC_DWARF]) return value; + unused(r); + return -118; +} + +static void +init_olditems(void) +{ + item_t i; +#if 0 + resource_type * rtype; + const struct locale * lang = find_locale("de"); + assert(lang); +#endif + + for (i=0; i!=MAXITEMS; ++i) { + /* item is defined in XML file, but IT_XYZ enum still in use */ + const item_type * itype = it_find(itemnames[i]); + + if (itype) { + olditemtype[i] = itype; + oldresourcetype[i] = itype->rtype; + } + } +} + +static int +heal(unit * user, int effect) +{ + int req = unit_max_hp(user) * user->number - user->hp; + if (req>0) { + req = MIN(req, effect); + effect -= req; + user->hp += req; + } + return effect; +} + +void +register_item_give(int (*foo) (struct unit *, struct unit *, const struct item_type *, int, struct order *), const char * name) +{ + register_function((pf_generic)foo, name); +} + +void +register_item_use(int (*foo) (struct unit *, const struct item_type *, int, struct order *), const char * name) +{ + register_function((pf_generic)foo, name); +} + +void +register_item_useonother(int (*foo) (struct unit *, int, const struct item_type *, int, struct order *), const char * name) +{ + register_function((pf_generic)foo, name); +} + +static int +use_healingpotion(struct unit *user, const struct item_type *itype, int amount, struct order * ord) +{ + int effect = amount * 400; + unit * u = user->region->units; + effect = heal(user, effect); + while (effect>0 && u!=NULL) { + if (u->faction==user->faction) { + effect = heal(u, effect); + } + u = u->next; + } + use_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); + usetpotionuse(user, itype->rtype->ptype); + + ADDMSG(&user->faction->msgs, msg_message("usepotion", + "unit potion", user, itype->rtype)); + return 0; +} + +static int +use_warmthpotion(struct unit *u, const struct item_type *itype, int amount, struct order * ord) +{ + if (u->faction->race == new_race[RC_INSECT]) { + fset(u, UFL_WARMTH); + } else { + /* nur für insekten: */ + cmistake(u, ord, 163, MSG_EVENT); + return ECUSTOM; + } + use_pooled(u, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); + usetpotionuse(u, itype->rtype->ptype); + + ADDMSG(&u->faction->msgs, msg_message("usepotion", + "unit potion", u, itype->rtype)); + return 0; +} + +static int +use_foolpotion(struct unit *u, int targetno, const struct item_type *itype, int amount, struct order * ord) +{ + unit * target = findunit(targetno); + if (target==NULL || u->region!=target->region) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return ECUSTOM; + } + if (effskill(u, SK_STEALTH)<=effskill(target, SK_PERCEPTION)) { + cmistake(u, ord, 64, MSG_EVENT); + return ECUSTOM; + } + ADDMSG(&u->faction->msgs, msg_message("givedumb", + "unit recipient amount", u, target, amount)); + + change_effect(target, itype->rtype->ptype, amount); + use_pooled(u, itype->rtype, GET_DEFAULT, amount); + return 0; +} + +static int +use_bloodpotion(struct unit *u, const struct item_type *itype, int amount, struct order * ord) +{ + if (u->race == new_race[RC_DAEMON]) { + change_effect(u, itype->rtype->ptype, 100*amount); + } else { + const race * irace = u_irace(u); + if (irace == u->race) { + static race * rcfailure; + if (!rcfailure) { + rcfailure = rc_find("smurf"); + if (!rcfailure) rcfailure = rc_find("toad"); + } + if (rcfailure) { + trigger * trestore = trigger_changerace(u, u->race, irace); + if (trestore) { + int duration = 2 + rng_int() % 8; + + add_trigger(&u->attribs, "timer", trigger_timeout(duration, trestore)); + u->irace = NULL; + u->race = rcfailure; + } + } + } + } + use_pooled(u, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); + usetpotionuse(u, itype->rtype->ptype); + + ADDMSG(&u->faction->msgs, msg_message("usepotion", + "unit potion", u, itype->rtype)); + return 0; +} + +#include +static int +use_mistletoe(struct unit * user, const struct item_type * itype, int amount, struct order * ord) +{ + int mtoes = get_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); + + if (user->number>mtoes) { + ADDMSG(&user->faction->msgs, msg_message("use_singleperson", + "unit item region command", user, itype->rtype, user->region, ord)); + return -1; + } + use_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); + a_add(&user->attribs, make_fleechance((float)1.0)); + ADDMSG(&user->faction->msgs, + msg_message("use_item", "unit item", user, itype->rtype)); + + return 0; +} + +static int +use_magicboost(struct unit * user, const struct item_type * itype, int amount, struct order * ord) +{ + int mtoes = get_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); + faction * f = user->faction; + if (user->number>mtoes) { + ADDMSG(&user->faction->msgs, msg_message("use_singleperson", + "unit item region command", user, itype->rtype, user->region, ord)); + return -1; + } + if (!is_mage(user) || find_key(f->attribs, atoi36("mbst"))!=NULL) { + cmistake(user, user->thisorder, 214, MSG_EVENT); + return -1; + } + use_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); + + a_add(&f->attribs, make_key(atoi36("mbst"))); + set_level(user, sk_find("magic"), 3); + + ADDMSG(&user->faction->msgs, msg_message("use_item", + "unit item", user, itype->rtype)); + + return 0; +} + +static int +use_snowball(struct unit * user, const struct item_type * itype, int amount, struct order * ord) +{ + return 0; +} + +static void +init_oldpotions(void) +{ + const char * potionnames[MAX_POTIONS] = { + "p0", "goliathwater", "p2", "p3", "ointment", "peasantblood", "p6", + "p7", "nestwarmth", "p9", "p10", "p11", "truthpotion", "p13", "p14" + }; + int p; + + for (p=0;p!=MAXPOTIONS;++p) { + item_type * itype = it_find(potionnames[p]); + if (itype!=NULL) { + oldpotiontype[p] = itype->rtype->ptype; + } + } +} + +resource_type * r_silver; +resource_type * r_aura; +resource_type * r_permaura; +resource_type * r_unit; +resource_type * r_hp; + +resource_type * r_silver; +item_type * i_silver; + +static const char * names[] = { + "money", "money_p", + "person", "person_p", + "permaura", "permaura_p", + "hp", "hp_p", + "peasant", "peasant_p", + "aura", "aura_p", + "unit", "unit_p" +}; + +void +init_resources(void) +{ + static boolean initialized = false; + if (initialized) return; + initialized = true; + + /* silver was never an item: */ + r_silver = new_resourcetype(&names[0], NULL, RTF_ITEM|RTF_POOLED); + i_silver = new_itemtype(r_silver, ITF_NONE, 1/*weight*/, 0); + r_silver->uchange = res_changeitem; + i_silver->give = give_money; + + r_permaura = new_resourcetype(&names[4], NULL, RTF_NONE); + r_permaura->uchange = res_changepermaura; + + r_hp = new_resourcetype(&names[6], NULL, RTF_NONE); + r_hp->uchange = res_changehp; + + r_aura = new_resourcetype(&names[10], NULL, RTF_NONE); + r_aura->uchange = res_changeaura; + + r_unit = new_resourcetype(&names[12], NULL, RTF_NONE); + r_unit->uchange = res_changeperson; + + oldresourcetype[R_SILVER] = r_silver; + oldresourcetype[R_AURA] = r_aura; + oldresourcetype[R_PERMAURA] = r_permaura; + + /* alte typen registrieren: */ + init_olditems(); + init_oldpotions(); +} + +int +get_money(const unit * u) +{ + const item * i = u->items; + while (i && i->type!=i_silver) i=i->next; + if (i==NULL) return 0; + return i->number; +} + +int +set_money(unit * u, int v) +{ + item ** ip = &u->items; + while (*ip && (*ip)->type!=i_silver) ip = &(*ip)->next; + if ((*ip)==NULL && v) { + i_add(&u->items, i_new(i_silver, v)); + return v; + } + if ((*ip)!=NULL) { + if (v) { + (*ip)->number = v; + assert((*ip)->number>=0); + } + else i_remove(ip, *ip); + } + return v; +} + +int +change_money(unit * u, int v) +{ + item ** ip = &u->items; + while (*ip && (*ip)->type!=i_silver) ip = &(*ip)->next; + if ((*ip)==NULL && v) { + i_add(&u->items, i_new(i_silver, v)); + return v; + } + if ((*ip)!=NULL) { + item * i = *ip; + if (i->number + v != 0) { + i->number += v; + assert(i->number>=0); + return i->number; + } + else i_free(i_remove(ip, *ip)); + } + return 0; +} + + +static local_names * rnames; + +const resource_type * +findresourcetype(const char * name, const struct locale * lang) +{ + local_names * rn = rnames; + variant token; + + while (rn) { + if (rn->lang==lang) break; + rn = rn->next; + } + if (!rn) { + const resource_type * rtl = resourcetypes; + rn = calloc(sizeof(local_names), 1); + rn->next = rnames; + rn->lang = lang; + while (rtl) { + token.v = (void*)rtl; + addtoken(&rn->names, locale_string(lang, rtl->_name[0]), token); + addtoken(&rn->names, locale_string(lang, rtl->_name[1]), token); + rtl=rtl->next; + } + rnames = rn; + } + + if (findtoken(&rn->names, name, &token)==E_TOK_NOMATCH) return NULL; + return (const resource_type*)token.v; +} + +attrib_type at_showitem = { + "showitem" +}; + +static local_names * inames; + +void +init_itemnames(void) +{ + int i; + for (i=0;localenames[i];++i) { + const struct locale * lang = find_locale(localenames[i]); + boolean exist = false; + local_names * in = inames; + + while (in!=NULL) { + if (in->lang==lang) { + exist = true; + break; + } + in = in->next; + } + if (in==NULL) in = calloc(sizeof(local_names), 1); + in->next = inames; + in->lang = lang; + + if (!exist) { + int key; + for (key=0;key!=IMAXHASH;++key) { + const item_type * itl; + for (itl=itemtypes[key];itl;itl=itl->next) { + variant var; + const char * iname = locale_string(lang, itl->rtype->_name[0]); + if (findtoken(&in->names, iname, &var)==E_TOK_NOMATCH || var.v!=itl) { + var.v = (void*)itl; + addtoken(&in->names, iname, var); + addtoken(&in->names, locale_string(lang, itl->rtype->_name[1]), var); + } + } + } + } + inames = in; + } +} + +const item_type * +finditemtype(const char * name, const struct locale * lang) +{ + local_names * in = inames; + variant var; + + while (in!=NULL) { + if (in->lang==lang) break; + in=in->next; + } + if (in==NULL) { + init_itemnames(); + for (in=inames;in->lang!=lang;in=in->next) ; + } + if (findtoken(&in->names, name, &var)==E_TOK_NOMATCH) return NULL; + return (const item_type*)var.v; +} + +static void +init_resourcelimit(attrib * a) +{ + a->data.v = calloc(sizeof(resource_limit), 1); +} + +static void +finalize_resourcelimit(attrib * a) +{ + free(a->data.v); +} + +attrib_type at_resourcelimit = { + "resourcelimit", + init_resourcelimit, + finalize_resourcelimit, +}; + +void +register_resources(void) +{ + register_function((pf_generic)mod_elves_only, "mod_elves_only"); + register_function((pf_generic)mod_dwarves_only, "mod_dwarves_only"); + register_function((pf_generic)res_changeitem, "changeitem"); + register_function((pf_generic)res_changeperson, "changeperson"); + register_function((pf_generic)res_changepeasants, "changepeasants"); + register_function((pf_generic)res_changepermaura, "changepermaura"); + register_function((pf_generic)res_changehp, "changehp"); + register_function((pf_generic)res_changeaura, "changeaura"); + + register_item_use(use_potion, "usepotion"); + register_item_use(use_potion_delayed, "usepotion_delayed"); + register_item_use(use_tacticcrystal, "use_tacticcrystal"); + register_item_use(use_birthdayamulet, "use_birthdayamulet"); + register_item_use(use_warmthpotion, "usewarmthpotion"); + register_item_use(use_bloodpotion, "usebloodpotion"); + register_item_use(use_healingpotion, "usehealingpotion"); + register_item_useonother(use_foolpotion, "usefoolpotion"); + register_item_use(use_mistletoe, "usemistletoe"); + register_item_use(use_magicboost, "usemagicboost"); + register_item_use(use_snowball, "usesnowball"); + + register_item_give(give_horses, "givehorses"); + + /* make sure noone has deleted an I_ tpe without deleting the R_ type that goes with it! */ + assert((int)I_TACTICCRYSTAL == (int)R_TACTICCRYSTAL); +} diff --git a/src/kernel/item.h b/src/kernel/item.h index 7633790ed..516d0856d 100644 --- a/src/kernel/item.h +++ b/src/kernel/item.h @@ -1,357 +1,357 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_ITEM -#define H_KRNL_ITEM -#ifdef __cplusplus -extern "C" { -#endif - -struct unit; -struct attrib; -struct attrib_type; -struct region; -struct resource_type; -struct locale; -struct troop; - -typedef struct item { - struct item * next; - const struct item_type * type; - int number; -} item; - -typedef struct resource { - const struct resource_type * type; - int number; - struct resource * next; -} resource; - -/* bitfield values for resource_type::flags */ -#define RTF_NONE 0 -#define RTF_ITEM (1<<0) /* this resource is an item */ -#define RTF_LIMITED (1<<1) /* a resource that's freely available, but in - * limited supply */ -#define RTF_POOLED (1<<2) /* resource is available in pool */ - -/* flags for resource_type::name() */ -#define NMF_PLURAL 0x01 -#define NMF_APPEARANCE 0x02 - -typedef int (*rtype_uchange)(struct unit * user, const struct resource_type * rtype, int delta); -typedef int (*rtype_uget)(const struct unit * user, const struct resource_type * rtype); -typedef char * (*rtype_name)(const struct resource_type * rtype, int flags); -typedef struct resource_type { - /* --- constants --- */ - char * _name[2]; /* wie es heißt */ - char * _appearance[2]; /* wie es für andere aussieht */ - unsigned int flags; - /* --- functions --- */ - rtype_uchange uchange; - rtype_uget uget; - rtype_name name; - /* --- pointers --- */ - struct attrib * attribs; - struct resource_type * next; - unsigned int hashkey; - struct item_type * itype; - struct potion_type * ptype; - struct luxury_type * ltype; - struct weapon_type * wtype; - struct armor_type * atype; -} resource_type; -extern resource_type * resourcetypes; -extern const char* resourcename(const resource_type * rtype, int flags); -extern const resource_type * findresourcetype(const char * name, const struct locale * lang); - -/* resource-limits for regions */ -#define RMF_SKILL 0x01 /* int, bonus on resource production skill */ -#define RMF_SAVEMATERIAL 0x02 /* float, multiplier on resource usage */ -#define RMF_SAVERESOURCE 0x03 /* int, bonus on resource production skill */ -#define RMF_REQUIREDBUILDING 0x04 /* building, required to build */ - -typedef struct resource_mod { - variant value; - const struct building_type * btype; - const struct race * race; - unsigned int flags; -} resource_mod; - -extern struct attrib_type at_resourcelimit; -typedef int (*rlimit_limit)(const struct region * r, const struct resource_type * rtype); -typedef void (*rlimit_produce)(struct region * r, const struct resource_type * rtype, int n); -typedef struct resource_limit { - rlimit_limit limit; - rlimit_produce produce; - unsigned int guard; /* how to guard against theft */ - int value; - resource_mod * modifiers; -} resource_limit; - - -/* bitfield values for item_type::flags */ -#define ITF_NONE 0x0000 -#define ITF_HERB 0x0001 /* this item is a herb */ -#define ITF_CURSED 0x0010 /* cursed object, cannot be given away */ -#define ITF_NOTLOST 0x0020 /* special object (quests), cannot be lost through death etc. */ -#define ITF_BIG 0x0040 /* big item, e.g. does not fit in a bag of holding */ -#define ITF_ANIMAL 0x0080 /* an animal */ -#define ITF_VEHICLE 0x0100 /* a vehicle, drawn by two animals */ - -/* error codes for item_type::use */ -#define ECUSTOM -1; -#define ENOITEM -2; -#define ENOSKILL -3; -#define EUNUSABLE -4; - -typedef struct itemtype_list { - struct itemtype_list * next; - const struct item_type * type; -} itemtype_list; - -typedef struct item_type { - resource_type * rtype; - /* --- constants --- */ - unsigned int flags; - int weight; - int capacity; - struct construction * construction; - /* --- functions --- */ - boolean (*canuse)(const struct unit * user, const struct item_type * itype); - int (*use)(struct unit * user, const struct item_type * itype, int amount, struct order * ord); - int (*useonother)(struct unit * user, int targetno, const struct item_type * itype, int amount, struct order * ord); - int (*give)(struct unit * src, struct unit * dest, const struct item_type * itm, int number, struct order * ord); -#if SCORE_MODULE - int score; -#endif - struct item_type * next; -} item_type; - -extern const item_type * finditemtype(const char * name, const struct locale * lang); -extern void init_itemnames(void); - -typedef struct luxury_type { - struct luxury_type * next; - const item_type * itype; - int price; -} luxury_type; -extern luxury_type * luxurytypes; - -typedef struct potion_type { - struct potion_type * next; - const item_type * itype; - int level; -} potion_type; -extern potion_type * potiontypes; - -#define WMF_WALKING 0x0001 -#define WMF_RIDING 0x0002 -#define WMF_ANYONE 0x000F /* convenience */ - -#define WMF_AGAINST_RIDING 0x0010 -#define WMF_AGAINST_WALKING 0x0020 -#define WMF_AGAINST_ANYONE 0x00F0 /* convenience */ - -#define WMF_OFFENSIVE 0x0100 -#define WMF_DEFENSIVE 0x0200 -#define WMF_ANYTIME 0x0F00 /* convenience */ - -#define WMF_DAMAGE 0x1000 -#define WMF_SKILL 0x2000 -#define WMF_MISSILE_TARGET 0x4000 - -struct race_list; -typedef struct weapon_mod { - int value; - unsigned int flags; - struct race_list * races; -} weapon_mod; - -#define ATF_NONE 0x00 -#define ATF_SHIELD 0x01 -#define ATF_LAEN 0x02 - -typedef struct armor_type { - const item_type * itype; - double penalty; - double magres; - int prot; - float projectile; /* chance, dass ein projektil abprallt */ - unsigned int flags; -} armor_type; - -#define WTF_NONE 0x00 -#define WTF_MISSILE 0x01 -#define WTF_MAGICAL 0x02 -#define WTF_PIERCE 0x04 -#define WTF_CUT 0x08 -#define WTF_BLUNT 0x10 -#define WTF_SIEGE 0x20 -#define WTF_ARMORPIERCING 0x40 /* armor has only half value */ -#define WTF_HORSEBONUS 0x80 -#define WTF_USESHIELD 0x100 - -typedef struct weapon_type { - const item_type * itype; - const char * damage[2]; - unsigned int flags; - skill_t skill; - int minskill; - int offmod; - int defmod; - double magres; - int reload; /* time to reload this weapon */ - weapon_mod * modifiers; - /* --- functions --- */ - boolean (*attack)(const struct troop *, const struct weapon_type *, int *deaths); -} weapon_type; - -extern void rt_register(resource_type * it); -extern resource_type * rt_find(const char * name); -extern item_type * it_find(const char * name); - -extern void it_register(item_type * it); -extern void wt_register(weapon_type * wt); - -extern const item_type * resource2item(const resource_type * rtype); -extern const resource_type * item2resource(const item_type * i); - -extern const weapon_type * resource2weapon(const resource_type * i); -extern const potion_type * resource2potion(const resource_type * i); -extern const luxury_type * resource2luxury(const resource_type * i); - -extern item ** i_find(item ** pi, const item_type * it); -extern item * const * i_findc(item * const * pi, const item_type * it); -extern item * i_add(item ** pi, item * it); -extern void i_merge(item ** pi, item ** si); -extern item * i_remove(item ** pi, item * it); -extern void i_free(item * i); -extern void i_freeall(item ** i); -extern item * i_new(const item_type * it, int number); - -/* convenience: */ -extern item * i_change(item ** items, const item_type * it, int delta); -extern int i_get(const item * i, const item_type * it); - -/* creation */ -extern resource_type * new_resourcetype(const char ** names, const char ** appearances, int flags); -extern item_type * new_itemtype(resource_type * rtype, int iflags, int weight, int capacity); -extern luxury_type * new_luxurytype(item_type * itype, int price); -extern weapon_type * new_weapontype(item_type * itype, int wflags, double magres, const char* damage[], int offmod, int defmod, int reload, skill_t sk, int minskill); -extern armor_type * new_armortype(item_type * itype, double penalty, double magres, int prot, unsigned int flags); -extern potion_type * new_potiontype(item_type * itype, int level); - -/* for lack of another file: */ - -/* sonstige resourcen */ -extern resource_type * r_silver; -extern resource_type * r_aura; -extern resource_type * r_permaura; -extern resource_type * r_unit; -extern resource_type * r_hp; - -enum { - I_IRON, /* 0 */ - I_STONE, - I_HORSE, - /* alte Artefakte */ - I_AMULET_OF_HEALING, - I_AMULET_OF_TRUE_SEEING, - I_RING_OF_INVISIBILITY, - I_RING_OF_POWER, - I_CHASTITY_BELT, /* bleibt */ - I_LAEN, - I_FEENSTIEFEL, - I_BIRTHDAYAMULET, - I_PEGASUS, - I_ELVENHORSE, - I_DOLPHIN, - I_RING_OF_NIMBLEFINGER, - I_TROLLBELT, - I_PRESSCARD, - I_AURAKULUM, - I_SPHERE_OF_INVISIBILITY, - I_BAG_OF_HOLDING, - I_SACK_OF_CONSERVATION, - I_TACTICCRYSTAL, - MAX_ITEMS /* do not use outside item.c ! */ -}; - -enum { - /* ITEMS: */ - R_IRON, - R_STONE, - R_HORSE, - /**/ - R_AMULET_OF_HEALING, - R_AMULET_OF_TRUE_SEEING, - R_RING_OF_INVISIBILITY, - R_RING_OF_POWER, - R_CHASTITY_BELT, - R_EOG, - R_FEENSTIEFEL, - R_BIRTHDAYAMULET, - R_PEGASUS, - R_UNICORN, - R_DOLPHIN, - R_RING_OF_NIMBLEFINGER, - R_TROLLBELT, - R_PRESSCARD, - R_AURAKULUM, - R_SPHERE_OF_INVISIBILITY, - R_BAG_OF_HOLDING, - R_SACK_OF_CONSERVATION, - R_TACTICCRYSTAL, - - /* SONSTIGE */ - R_SILVER, - R_AURA, /* Aura */ - R_PERMAURA, /* Permanente Aura */ - - MAX_RESOURCES, /* do not use outside item.c ! */ - NORESOURCE = -1 -}; - -extern const struct potion_type * oldpotiontype[]; -extern const struct item_type * olditemtype[]; -extern const struct resource_type * oldresourcetype[]; - -int get_item(const struct unit *, item_t); -int set_item(struct unit *, item_t, int); - -int get_money(const struct unit *); -int set_money(struct unit *, int); -int change_money(struct unit *, int); -int res_changeitem(struct unit * u, const resource_type * rtype, int delta); - -extern struct attrib_type at_showitem; /* show this potion's description */ - -extern void register_resources(void); -extern void init_resources(void); -extern void init_itemtypes(void); - -extern void register_item_give(int (*foo) (struct unit *, struct unit *, const struct item_type *, int, struct order *), const char * name); -extern void register_item_use(int (*foo) (struct unit *, const struct item_type *, int, struct order *), const char * name); -extern void register_item_useonother(int (*foo) (struct unit *, int, const struct item_type *, int, struct order *), const char * name); - -extern struct item_type *i_silver; - -#ifdef __cplusplus -} -#endif -#endif /* _ITEM_H */ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_ITEM +#define H_KRNL_ITEM +#ifdef __cplusplus +extern "C" { +#endif + +struct unit; +struct attrib; +struct attrib_type; +struct region; +struct resource_type; +struct locale; +struct troop; + +typedef struct item { + struct item * next; + const struct item_type * type; + int number; +} item; + +typedef struct resource { + const struct resource_type * type; + int number; + struct resource * next; +} resource; + +/* bitfield values for resource_type::flags */ +#define RTF_NONE 0 +#define RTF_ITEM (1<<0) /* this resource is an item */ +#define RTF_LIMITED (1<<1) /* a resource that's freely available, but in + * limited supply */ +#define RTF_POOLED (1<<2) /* resource is available in pool */ + +/* flags for resource_type::name() */ +#define NMF_PLURAL 0x01 +#define NMF_APPEARANCE 0x02 + +typedef int (*rtype_uchange)(struct unit * user, const struct resource_type * rtype, int delta); +typedef int (*rtype_uget)(const struct unit * user, const struct resource_type * rtype); +typedef char * (*rtype_name)(const struct resource_type * rtype, int flags); +typedef struct resource_type { + /* --- constants --- */ + char * _name[2]; /* wie es heißt */ + char * _appearance[2]; /* wie es für andere aussieht */ + unsigned int flags; + /* --- functions --- */ + rtype_uchange uchange; + rtype_uget uget; + rtype_name name; + /* --- pointers --- */ + struct attrib * attribs; + struct resource_type * next; + unsigned int hashkey; + struct item_type * itype; + struct potion_type * ptype; + struct luxury_type * ltype; + struct weapon_type * wtype; + struct armor_type * atype; +} resource_type; +extern resource_type * resourcetypes; +extern const char* resourcename(const resource_type * rtype, int flags); +extern const resource_type * findresourcetype(const char * name, const struct locale * lang); + +/* resource-limits for regions */ +#define RMF_SKILL 0x01 /* int, bonus on resource production skill */ +#define RMF_SAVEMATERIAL 0x02 /* float, multiplier on resource usage */ +#define RMF_SAVERESOURCE 0x03 /* int, bonus on resource production skill */ +#define RMF_REQUIREDBUILDING 0x04 /* building, required to build */ + +typedef struct resource_mod { + variant value; + const struct building_type * btype; + const struct race * race; + unsigned int flags; +} resource_mod; + +extern struct attrib_type at_resourcelimit; +typedef int (*rlimit_limit)(const struct region * r, const struct resource_type * rtype); +typedef void (*rlimit_produce)(struct region * r, const struct resource_type * rtype, int n); +typedef struct resource_limit { + rlimit_limit limit; + rlimit_produce produce; + unsigned int guard; /* how to guard against theft */ + int value; + resource_mod * modifiers; +} resource_limit; + + +/* bitfield values for item_type::flags */ +#define ITF_NONE 0x0000 +#define ITF_HERB 0x0001 /* this item is a herb */ +#define ITF_CURSED 0x0010 /* cursed object, cannot be given away */ +#define ITF_NOTLOST 0x0020 /* special object (quests), cannot be lost through death etc. */ +#define ITF_BIG 0x0040 /* big item, e.g. does not fit in a bag of holding */ +#define ITF_ANIMAL 0x0080 /* an animal */ +#define ITF_VEHICLE 0x0100 /* a vehicle, drawn by two animals */ + +/* error codes for item_type::use */ +#define ECUSTOM -1; +#define ENOITEM -2; +#define ENOSKILL -3; +#define EUNUSABLE -4; + +typedef struct itemtype_list { + struct itemtype_list * next; + const struct item_type * type; +} itemtype_list; + +typedef struct item_type { + resource_type * rtype; + /* --- constants --- */ + unsigned int flags; + int weight; + int capacity; + struct construction * construction; + /* --- functions --- */ + boolean (*canuse)(const struct unit * user, const struct item_type * itype); + int (*use)(struct unit * user, const struct item_type * itype, int amount, struct order * ord); + int (*useonother)(struct unit * user, int targetno, const struct item_type * itype, int amount, struct order * ord); + int (*give)(struct unit * src, struct unit * dest, const struct item_type * itm, int number, struct order * ord); +#if SCORE_MODULE + int score; +#endif + struct item_type * next; +} item_type; + +extern const item_type * finditemtype(const char * name, const struct locale * lang); +extern void init_itemnames(void); + +typedef struct luxury_type { + struct luxury_type * next; + const item_type * itype; + int price; +} luxury_type; +extern luxury_type * luxurytypes; + +typedef struct potion_type { + struct potion_type * next; + const item_type * itype; + int level; +} potion_type; +extern potion_type * potiontypes; + +#define WMF_WALKING 0x0001 +#define WMF_RIDING 0x0002 +#define WMF_ANYONE 0x000F /* convenience */ + +#define WMF_AGAINST_RIDING 0x0010 +#define WMF_AGAINST_WALKING 0x0020 +#define WMF_AGAINST_ANYONE 0x00F0 /* convenience */ + +#define WMF_OFFENSIVE 0x0100 +#define WMF_DEFENSIVE 0x0200 +#define WMF_ANYTIME 0x0F00 /* convenience */ + +#define WMF_DAMAGE 0x1000 +#define WMF_SKILL 0x2000 +#define WMF_MISSILE_TARGET 0x4000 + +struct race_list; +typedef struct weapon_mod { + int value; + unsigned int flags; + struct race_list * races; +} weapon_mod; + +#define ATF_NONE 0x00 +#define ATF_SHIELD 0x01 +#define ATF_LAEN 0x02 + +typedef struct armor_type { + const item_type * itype; + double penalty; + double magres; + int prot; + float projectile; /* chance, dass ein projektil abprallt */ + unsigned int flags; +} armor_type; + +#define WTF_NONE 0x00 +#define WTF_MISSILE 0x01 +#define WTF_MAGICAL 0x02 +#define WTF_PIERCE 0x04 +#define WTF_CUT 0x08 +#define WTF_BLUNT 0x10 +#define WTF_SIEGE 0x20 +#define WTF_ARMORPIERCING 0x40 /* armor has only half value */ +#define WTF_HORSEBONUS 0x80 +#define WTF_USESHIELD 0x100 + +typedef struct weapon_type { + const item_type * itype; + const char * damage[2]; + unsigned int flags; + skill_t skill; + int minskill; + int offmod; + int defmod; + double magres; + int reload; /* time to reload this weapon */ + weapon_mod * modifiers; + /* --- functions --- */ + boolean (*attack)(const struct troop *, const struct weapon_type *, int *deaths); +} weapon_type; + +extern void rt_register(resource_type * it); +extern resource_type * rt_find(const char * name); +extern item_type * it_find(const char * name); + +extern void it_register(item_type * it); +extern void wt_register(weapon_type * wt); + +extern const item_type * resource2item(const resource_type * rtype); +extern const resource_type * item2resource(const item_type * i); + +extern const weapon_type * resource2weapon(const resource_type * i); +extern const potion_type * resource2potion(const resource_type * i); +extern const luxury_type * resource2luxury(const resource_type * i); + +extern item ** i_find(item ** pi, const item_type * it); +extern item * const * i_findc(item * const * pi, const item_type * it); +extern item * i_add(item ** pi, item * it); +extern void i_merge(item ** pi, item ** si); +extern item * i_remove(item ** pi, item * it); +extern void i_free(item * i); +extern void i_freeall(item ** i); +extern item * i_new(const item_type * it, int number); + +/* convenience: */ +extern item * i_change(item ** items, const item_type * it, int delta); +extern int i_get(const item * i, const item_type * it); + +/* creation */ +extern resource_type * new_resourcetype(const char ** names, const char ** appearances, int flags); +extern item_type * new_itemtype(resource_type * rtype, int iflags, int weight, int capacity); +extern luxury_type * new_luxurytype(item_type * itype, int price); +extern weapon_type * new_weapontype(item_type * itype, int wflags, double magres, const char* damage[], int offmod, int defmod, int reload, skill_t sk, int minskill); +extern armor_type * new_armortype(item_type * itype, double penalty, double magres, int prot, unsigned int flags); +extern potion_type * new_potiontype(item_type * itype, int level); + +/* for lack of another file: */ + +/* sonstige resourcen */ +extern resource_type * r_silver; +extern resource_type * r_aura; +extern resource_type * r_permaura; +extern resource_type * r_unit; +extern resource_type * r_hp; + +enum { + I_IRON, /* 0 */ + I_STONE, + I_HORSE, + /* alte Artefakte */ + I_AMULET_OF_HEALING, + I_AMULET_OF_TRUE_SEEING, + I_RING_OF_INVISIBILITY, + I_RING_OF_POWER, + I_CHASTITY_BELT, /* bleibt */ + I_LAEN, + I_FEENSTIEFEL, + I_BIRTHDAYAMULET, + I_PEGASUS, + I_ELVENHORSE, + I_DOLPHIN, + I_RING_OF_NIMBLEFINGER, + I_TROLLBELT, + I_PRESSCARD, + I_AURAKULUM, + I_SPHERE_OF_INVISIBILITY, + I_BAG_OF_HOLDING, + I_SACK_OF_CONSERVATION, + I_TACTICCRYSTAL, + MAX_ITEMS /* do not use outside item.c ! */ +}; + +enum { + /* ITEMS: */ + R_IRON, + R_STONE, + R_HORSE, + /**/ + R_AMULET_OF_HEALING, + R_AMULET_OF_TRUE_SEEING, + R_RING_OF_INVISIBILITY, + R_RING_OF_POWER, + R_CHASTITY_BELT, + R_EOG, + R_FEENSTIEFEL, + R_BIRTHDAYAMULET, + R_PEGASUS, + R_UNICORN, + R_DOLPHIN, + R_RING_OF_NIMBLEFINGER, + R_TROLLBELT, + R_PRESSCARD, + R_AURAKULUM, + R_SPHERE_OF_INVISIBILITY, + R_BAG_OF_HOLDING, + R_SACK_OF_CONSERVATION, + R_TACTICCRYSTAL, + + /* SONSTIGE */ + R_SILVER, + R_AURA, /* Aura */ + R_PERMAURA, /* Permanente Aura */ + + MAX_RESOURCES, /* do not use outside item.c ! */ + NORESOURCE = -1 +}; + +extern const struct potion_type * oldpotiontype[]; +extern const struct item_type * olditemtype[]; +extern const struct resource_type * oldresourcetype[]; + +int get_item(const struct unit *, item_t); +int set_item(struct unit *, item_t, int); + +int get_money(const struct unit *); +int set_money(struct unit *, int); +int change_money(struct unit *, int); +int res_changeitem(struct unit * u, const resource_type * rtype, int delta); + +extern struct attrib_type at_showitem; /* show this potion's description */ + +extern void register_resources(void); +extern void init_resources(void); +extern void init_itemtypes(void); + +extern void register_item_give(int (*foo) (struct unit *, struct unit *, const struct item_type *, int, struct order *), const char * name); +extern void register_item_use(int (*foo) (struct unit *, const struct item_type *, int, struct order *), const char * name); +extern void register_item_useonother(int (*foo) (struct unit *, int, const struct item_type *, int, struct order *), const char * name); + +extern struct item_type *i_silver; + +#ifdef __cplusplus +} +#endif +#endif /* _ITEM_H */ diff --git a/src/kernel/magic.c b/src/kernel/magic.c index d181b6328..a1e1251b6 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -1,2923 +1,2923 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "magic.h" - -#include "building.h" -#include "curse.h" -#include "faction.h" -#include "item.h" -#include "message.h" -#include "objtypes.h" -#include "order.h" -#include "pathfinder.h" -#include "plane.h" -#include "pool.h" -#include "race.h" -#include "region.h" -#include "ship.h" -#include "skill.h" -#include "spell.h" -#include "teleport.h" -#include "terrain.h" -#include "unit.h" -#include "version.h" - -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include -#include - -/* ------------------------------------------------------------- */ - -const char *magic_school[MAXMAGIETYP] = -{ - "gray", - "illaun", - "tybied", - "cerddor", - "gwyrrd", - "draig", - "common" -}; - -attrib_type at_reportspell = { - "reportspell", NULL, NULL, NULL, NO_WRITE, NO_READ -}; - -/** - ** at_icastle - ** TODO: separate castle-appearance from illusion-effects - **/ - -static double -MagicRegeneration(void) -{ - static double value = -1.0; - if (value<0) { - const char * str = get_param(global.parameters, "magic.regeneration"); - value = str?atof(str):1.0; - } - return value; -} - -double -MagicPower(void) -{ - static double value = -1.0; - if (value<0) { - const char * str = get_param(global.parameters, "magic.power"); - value = str?atof(str):1.0; - } - return value; -} - -static int -a_readicastle(attrib * a, void * owner, struct storage * store) -{ - icastle_data * data = (icastle_data*)a->data.v; - variant bno; - char token[32]; - store->r_tok_buf(store, token, sizeof(token)); - bno.i = store->r_int(store); - data->time = store->r_int(store); - data->building = findbuilding(bno.i); - if (!data->building) { - /* this shouldn't happen, but just in case it does: */ - ur_add(bno, &data->building, resolve_building); - } - data->type = bt_find(token); - return AT_READ_OK; -} - -static void -a_writeicastle(const attrib * a, const void * owner, struct storage * store) -{ - icastle_data * data = (icastle_data*)a->data.v; - store->w_tok(store, data->type->_name); - store->w_int(store, data->building->no); - store->w_int(store, data->time); -} - -static int -a_ageicastle(struct attrib * a) -{ - icastle_data * data = (icastle_data*)a->data.v; - if (data->time<=0) { - building * b = data->building; - region * r = b->region; - ADDMSG(&r->msgs, msg_message("icastle_dissolve", "building", b)); - /* remove_building lets units leave the building */ - remove_building(&r->buildings, b); - return AT_AGE_REMOVE; - } - else data->time--; - return AT_AGE_KEEP; -} - -static void -a_initicastle(struct attrib * a) -{ - a->data.v = calloc(sizeof(icastle_data), 1); -} - -static void -a_finalizeicastle(struct attrib * a) -{ - free(a->data.v); -} - -attrib_type at_icastle = { - "zauber_icastle", - a_initicastle, - a_finalizeicastle, - a_ageicastle, - a_writeicastle, - a_readicastle -}; - -/* ------------------------------------------------------------- */ - -extern int dice(int count, int value); - -/* ------------------------------------------------------------- */ -/* aus dem alten System übriggebliegene Funktionen, die bei der - * Umwandlung von alt nach neu gebraucht werden */ -/* ------------------------------------------------------------- */ - -static void -init_mage(attrib * a) { - a->data.v = calloc(sizeof(sc_mage), 1); -} - -static void -free_mage(attrib * a) -{ - sc_mage * mage = (sc_mage*)a->data.v; - freelist(mage->spells); - free(mage); -} - -int FactionSpells(void) -{ - static int rules_factionspells = -1; - if (rules_factionspells<0) { - rules_factionspells = get_param_int(global.parameters, "rules.magic.factionlist", 0); - } - return rules_factionspells; -} - -void read_spellist(struct spell_list ** slistp, magic_t mtype, struct storage * store) -{ - for (;;) { - spell * sp; - char spname[64]; - - if (store->versionr_int(store); - if (i < 0) break; - sp = find_spellbyid(M_NONE, (spellid_t)i); - } else { - store->r_tok_buf(store, spname, sizeof(spname)); - if (strcmp(spname, "end")==0) break; - sp = find_spell(mtype, spname); - } - if (sp!=NULL) { - add_spell(slistp, sp); - } - } -} - -static int -read_mage(attrib * a, void * owner, struct storage * store) -{ - int i, mtype; - sc_mage * mage = (sc_mage*)a->data.v; - char spname[64]; - - mtype = store->r_int(store); - mage->spellpoints = store->r_int(store); - mage->spchange = store->r_int(store); - mage->magietyp = (magic_t)mtype; - for (i=0;i!=MAXCOMBATSPELLS;++i) { - spell * sp = NULL; - int level = 0; - if (store->versionr_int(store); - level = store->r_int(store); - if (spid>=0) { - sp = find_spellbyid(mage->magietyp, (spellid_t)spid); - } - } else { - store->r_tok_buf(store, spname, sizeof(spname)); - level = store->r_int(store); - - if (strcmp("none", spname)!=0) { - sp = find_spell(mage->magietyp, spname); - } - } - if (sp && level>=0) { - int slot = -1; - if (sp->sptyp & PRECOMBATSPELL) slot = 0; - else if (sp->sptyp & COMBATSPELL) slot = 1; - else if (sp->sptyp & POSTCOMBATSPELL) slot = 2; - if (slot>=0) { - mage->combatspells[slot].level = level; - mage->combatspells[slot].sp = sp; - } - } - } - read_spellist(&mage->spells, mage->magietyp, store); - return AT_READ_OK; -} - -void write_spelllist(const spell_list * slist, struct storage * store) -{ - while (slist!=NULL) { - spell * sp = slist->data; - store->w_tok(store, sp->sname); - slist = slist->next; - } - store->w_tok(store, "end"); -} - -static void -write_mage(const attrib * a, const void * owner, struct storage * store) -{ - int i; - sc_mage *mage = (sc_mage*)a->data.v; - - store->w_int(store, mage->magietyp); - store->w_int(store, mage->spellpoints); - store->w_int(store, mage->spchange); - for (i=0;i!=MAXCOMBATSPELLS;++i) { - store->w_tok(store, mage->combatspells[i].sp?mage->combatspells[i].sp->sname:"none"); - store->w_int(store, mage->combatspells[i].level); - } - write_spelllist(mage->spells, store); -} - -attrib_type at_mage = { - "mage", - init_mage, - free_mage, - NULL, - write_mage, - read_mage, - ATF_UNIQUE -}; - -boolean -is_mage(const unit * u) -{ - return i2b(get_mage(u) != NULL); -} - -sc_mage * -get_mage(const unit * u) -{ - if (has_skill(u, SK_MAGIC)) { - attrib * a = a_find(u->attribs, &at_mage); - if (a) return a->data.v; - } - return (sc_mage *) NULL; -} - -/* ------------------------------------------------------------- */ -/* Ausgabe der Spruchbeschreibungen -* Anzeige des Spruchs nur, wenn die Stufe des besten Magiers vorher -* kleiner war (u->faction->seenspells). Ansonsten muss nur geprüft -* werden, ob dieser Magier den Spruch schon kennt, und andernfalls der -* Spruch zu seiner List-of-known-spells hinzugefügt werden. -*/ - - -static int -read_seenspell(attrib * a, void * owner, struct storage * store) -{ - int i; - spell * sp = NULL; - char token[32]; - - store->r_tok_buf(store, token, sizeof(token)); - i = atoi(token); - if (i!=0) { - sp = find_spellbyid(M_NONE, (spellid_t)i); - } else { - int mtype; - mtype = store->r_int(store); - sp = find_spell((magic_t)mtype, token); - } - if (sp==NULL) { - /* log_error(("could not find seenspell '%s'\n", buf)); */ - return AT_READ_FAIL; - } - a->data.v = sp; - return AT_READ_OK; -} - -static void -write_seenspell(const attrib * a, const void * owner, struct storage * store) -{ - const spell * sp = (const spell*)a->data.v; - store->w_tok(store, sp->sname); - store->w_int(store, sp->magietyp); -} - -attrib_type at_seenspell = { - "seenspell", NULL, NULL, NULL, write_seenspell, read_seenspell -}; - -static boolean -already_seen(const faction * f, const spell * sp) -{ - attrib *a; - - for (a = a_find(f->attribs, &at_seenspell); a && a->type==&at_seenspell; a=a->next) { - if (a->data.v==sp) return true; - } - return false; -} - -static boolean know_school(const faction * f, magic_t school) -{ - static int common = MAXMAGIETYP; - if (f->magiegebiet==school) return true; - if (common==MAXMAGIETYP) { - const char * common_school = get_param(global.parameters, "rules.magic.common"); - if (common_school) { - for (common=0;common!=MAXMAGIETYP;++common) { - if (strcmp(common_school, magic_school[common])==0) break; - } - if (common==MAXMAGIETYP) { - common = M_NONE; - } - } else { - return false; - } - } - return school==common; -} - -#define COMMONSPELLS 1 /* number of new common spells per level */ -#define MAXSPELLS 256 - -/** update the spellbook with a new level -* Written for Eressea 1.1 -*/ -void -update_spellbook(faction * f, int level) -{ - spell * commonspells[MAXSPELLS]; - int numspells = 0; - spell_list * slist; - - for (slist=spells;slist!=NULL;slist=slist->next) { - spell * sp = slist->data; - if (sp->magietyp == M_COMMON && level>f->max_spelllevel && sp->level<=level) { - commonspells[numspells++] = sp; - } else { - if (know_school(f, sp->magietyp) && sp->level <= level) { - if (!has_spell(f->spellbook, sp)) { - add_spell(&f->spellbook, sp); - } - } - } - } - while (numspells>0 && level>f->max_spelllevel) { - int i; - for (i=0;i!=COMMONSPELLS;++i) { - int maxspell = numspells; - int spellno = -1; - spell * sp; - do { - if (spellno==maxspell) { - --maxspell; - } - spellno = rng_int() % maxspell; - sp = commonspells[spellno]; - } - while (maxspell>0 && sp && sp->level<=f->max_spelllevel && !has_spell(f->spellbook, sp)); - - if (sp) { - add_spell(&f->spellbook, sp); - commonspells[spellno] = 0; - } - } - ++f->max_spelllevel; - } -} - -void -updatespelllist(unit * u) -{ - int sk = eff_skill(u, SK_MAGIC, u->region); - spell_list * slist = spells; - struct sc_mage * mage = get_mage(u); - boolean ismonster = is_monsters(u->faction); - - if (mage->magietyp==M_GRAY) { - /* Magier mit M_GRAY bekommen weder Sprüche angezeigt noch - * neue Sprüche in ihre List-of-known-spells. Das sind zb alle alten - * Drachen, die noch den Skill Magie haben, und alle familiars */ - return; - } - - if (FactionSpells()) { - slist = u->faction->spellbook; - } - - for (;slist!=NULL;slist=slist->next) { - spell * sp = slist->data; - if (sp->level<=sk) { - boolean know = u_hasspell(u, sp); - - if (know || sp->magietyp==M_COMMON || know_school(u->faction, sp->magietyp)) { - faction * f = u->faction; - - if (!know) add_spell(get_spelllist(mage, u->faction), sp); - if (!ismonster && !already_seen(u->faction, sp)) { - a_add(&f->attribs, a_new(&at_reportspell))->data.v = sp; - a_add(&f->attribs, a_new(&at_seenspell))->data.v = sp; - } - } - } - } - -} - -/* ------------------------------------------------------------- */ -/* Erzeugen eines neuen Magiers */ -sc_mage * -create_mage(unit * u, magic_t mtyp) -{ - sc_mage *mage; - attrib *a; - - a = a_find(u->attribs, &at_mage); - if (a!=NULL) { - a_remove(&u->attribs, a); - } - a = a_add(&u->attribs, a_new(&at_mage)); - mage = a->data.v; - - mage->magietyp = mtyp; - return mage; -} - -/* ------------------------------------------------------------- */ -/* Funktionen für die Bearbeitung der List-of-known-spells */ - -void -add_spell(spell_list ** slistp, spell * sp) -{ - if (slistp==NULL) { - log_error(("add_spell: unit is not a mage.\n")); - } else { - spell_list ** slist = spelllist_find(slistp, sp); - if (*slist) { - spell * psp = (*slist)->data; - if (psp==sp) { - log_error(("add_spell: unit already has spell '%s'.\n", sp->sname)); - return; - } - } - spelllist_add(slist, sp); - } -} - -boolean -has_spell(spell_list * slist, const spell * sp) -{ - if (slist!=NULL) { - spell_list * sfind = *spelllist_find(&slist, sp); - return sfind!=NULL && sfind->data==sp; - } - return false; -} - -boolean -u_hasspell(const struct unit *u, const struct spell * sp) -{ - sc_mage * mage = get_mage(u); - if (mage) return has_spell(mage->spells, sp); - return false; -} - -/* ------------------------------------------------------------- */ -/* Eingestellte Kampfzauberstufe ermitteln */ - -int -get_combatspelllevel(const unit *u, int nr) -{ - sc_mage *m = get_mage(u); - - assert(nr < MAXCOMBATSPELLS); - if (m) { - int level = eff_skill(u, SK_MAGIC, u->region); - return MIN(m->combatspells[nr].level, level); - } - return -1; -} - -/* ------------------------------------------------------------- */ -/* Kampfzauber ermitteln, setzen oder löschen */ - -const spell* -get_combatspell(const unit *u, int nr) -{ - sc_mage *m; - - assert(nr < MAXCOMBATSPELLS); - m = get_mage(u); - if (m) { - return m->combatspells[nr].sp; - } else if (u->race->precombatspell != NULL) { - return u->race->precombatspell; - } - - return NULL; -} - -void -set_combatspell(unit *u, spell *sp, struct order * ord, int level) -{ - sc_mage *m = get_mage(u); - int i = -1; - if (!m) return; - - /* knowsspell prüft auf ist_magier, ist_spruch, kennt_spruch */ - if (knowsspell(u->region, u, sp) == false){ - /* Fehler 'Spell not found' */ - cmistake(u, ord, 173, MSG_MAGIC); - return; - } - if (!u_hasspell(u, sp)) { - /* Diesen Zauber kennt die Einheit nicht */ - cmistake(u, ord, 169, MSG_MAGIC); - return; - } - if (!(sp->sptyp & ISCOMBATSPELL)) { - /* Diesen Kampfzauber gibt es nicht */ - cmistake(u, ord, 171, MSG_MAGIC); - return; - } - - if (sp->sptyp & PRECOMBATSPELL) i = 0; - else if (sp->sptyp & COMBATSPELL) i = 1; - else if (sp->sptyp & POSTCOMBATSPELL) i = 2; - assert(i>=0); - m->combatspells[i].sp = sp; - m->combatspells[i].level = level; - return; -} - -void -unset_combatspell(unit *u, spell *sp) -{ - sc_mage *m; - int nr = 0; - int i; - - m = get_mage(u); - if (!m) return; - - if (!sp) { - for (i=0;icombatspells[i].sp = NULL; - } - } - else if (sp->sptyp & PRECOMBATSPELL) { - if (sp != get_combatspell(u,0)) - return; - } else if (sp->sptyp & COMBATSPELL) { - if (sp != get_combatspell(u,1)) { - return; - } - nr = 1; - } else if (sp->sptyp & POSTCOMBATSPELL) { - if (sp != get_combatspell(u,2)) { - return; - } - nr = 2; - } - m->combatspells[nr].sp = NULL; - m->combatspells[nr].level = 0; - return; -} - -/* ------------------------------------------------------------- */ -/* Gibt die aktuelle Anzahl der Magiepunkte der Einheit zurück */ -int -get_spellpoints(const unit * u) -{ - sc_mage *m; - - m = get_mage(u); - if (!m) return 0; - - return m->spellpoints; -} - -void -set_spellpoints(unit * u, int sp) -{ - sc_mage *m; - - m = get_mage(u); - if (!m) return; - - m->spellpoints = sp; - - return; -} - -/* - * verändert die Anzahl der Magiepunkte der Einheit um +mp - */ -int -change_spellpoints(unit * u, int mp) -{ - sc_mage *m; - int sp; - - m = get_mage(u); - if (!m) return 0; - - /* verhindere negative Magiepunkte */ - sp = MAX(m->spellpoints + mp, 0); - m->spellpoints = sp; - - return sp; -} - -/* bietet die Möglichkeit, die maximale Anzahl der Magiepunkte mit - * Regionszaubern oder Attributen zu beinflussen - */ -static int -get_spchange(const unit * u) -{ - sc_mage *m; - - m = get_mage(u); - if (!m) return 0; - - return m->spchange; -} - -/* ein Magier kann normalerweise maximal Stufe^2.1/1.2+1 Magiepunkte - * haben. - * Manche Rassen haben einen zusätzlichen Multiplikator - * Durch Talentverlust (zB Insekten im Berg) können negative Werte - * entstehen - */ - -/* Artefakt der Stärke - * Ermöglicht dem Magier mehr Magiepunkte zu 'speichern' - */ -/** TODO: at_skillmod daraus machen */ -static int -use_item_aura(const region * r, const unit * u) -{ - int sk, n; - - sk = eff_skill(u, SK_MAGIC, r); - n = (int)(sk * sk * u->race->maxaura / 4); - - return n; -} - -int -max_spellpoints(const region * r, const unit * u) -{ - int sk; - double n, msp; - double potenz = 2.1; - double divisor = 1.2; - - sk = eff_skill(u, SK_MAGIC, r); - msp = u->race->maxaura*(pow(sk, potenz)/divisor+1) + get_spchange(u); - - if (get_item(u, I_AURAKULUM) > 0) { - msp += use_item_aura(r, u); - } - n = get_curseeffect(u->attribs, C_AURA, 0); - if (n>0) msp = (msp*n)/100; - - return MAX((int)msp, 0); -} - -int -change_maxspellpoints(unit * u, int csp) -{ - sc_mage *m; - - m = get_mage(u); - if (!m) return 0; - - m->spchange += csp; - return max_spellpoints(u->region, u); -} - -/* ------------------------------------------------------------- */ -/* Counter für die bereits gezauberte Anzahl Sprüche pro Runde. - * Um nur die Zahl der bereits gezauberten Sprüche zu ermitteln mit - * step = 0 aufrufen. - */ -int -countspells(unit *u, int step) -{ - sc_mage *m; - int count; - - m = get_mage(u); - if (!m) - return 0; - - if (step == 0) - return m->spellcount; - - count = m->spellcount + step; - - /* negative Werte abfangen. */ - m->spellcount = MAX(0,count); - - return m->spellcount; -} - -/* ------------------------------------------------------------- */ -/* Die für den Spruch benötigte Aura pro Stufe. - * Die Grundkosten pro Stufe werden hier um 2^count erhöht. Der - * Parameter count ist dabei die Anzahl der bereits gezauberten Sprüche - */ -int -spellcost(unit *u, const spell * sp) -{ - int k, aura = 0; - int count = countspells(u, 0); - - for (k = 0; sp->components[k].type; k++) { - if (sp->components[k].type == r_aura) { - aura = sp->components[k].amount; - } - } - aura *= (1<components[k].type; k++) { - if (costtyp == SPC_LINEAR) return SPC_LINEAR; - - if (sp->components[k].cost == SPC_LINEAR) { - return SPC_LINEAR; - } - - /* wenn keine Fixkosten, Typ übernehmen */ - if (sp->components[k].cost != SPC_FIX) { - costtyp = sp->components[k].cost; - } - } - return costtyp; -} - -/* ------------------------------------------------------------- */ -/* durch Komponenten und cast_level begrenzter maximal möglicher - * Level - * Da die Funktion nicht alle Komponenten durchprobiert sondern beim - * ersten Fehler abbricht, muss die Fehlermeldung später mit cancast() - * generiert werden. - * */ -int -eff_spelllevel(unit *u, const spell * sp, int cast_level, int range) -{ - int k, maxlevel, needplevel; - int costtyp = SPC_FIX; - - for (k = 0; sp->components[k].type; k++) { - if (cast_level == 0) - return 0; - - if (sp->components[k].amount > 0) { - /* Die Kosten für Aura sind auch von der Zahl der bereits - * gezauberten Sprüche abhängig */ - if (sp->components[k].type == r_aura) { - needplevel = spellcost(u, sp) * range; - } else { - needplevel = sp->components[k].amount * range; - } - maxlevel = get_pooled(u, sp->components[k].type, GET_DEFAULT, needplevel*cast_level)/needplevel; - - /* sind die Kosten fix, so muss die Komponente nur einmal vorhanden - * sein und der cast_level ändert sich nicht */ - if (sp->components[k].cost == SPC_FIX) { - if (maxlevel < 1) cast_level = 0; - /* ansonsten wird das Minimum aus maximal möglicher Stufe und der - * gewünschten gebildet */ - } else if (sp->components[k].cost == SPC_LEVEL) { - costtyp = SPC_LEVEL; - cast_level = MIN(cast_level, maxlevel); - /* bei Typ Linear müssen die Kosten in Höhe der Stufe vorhanden - * sein, ansonsten schlägt der Spruch fehl */ - } else if (sp->components[k].cost == SPC_LINEAR) { - costtyp = SPC_LINEAR; - if (maxlevel < cast_level) cast_level = 0; - } - } - } - /* Ein Spruch mit Fixkosten wird immer mit der Stufe des Spruchs und - * nicht auf der Stufe des Magiers gezaubert */ - if (costtyp == SPC_FIX) { - cast_level = MIN(cast_level, sp->level); - } - - return cast_level; -} - -/* ------------------------------------------------------------- */ -/* Die Spruchgrundkosten werden mit der Entfernung (Farcasting) - * multipliziert, wobei die Aurakosten ein Sonderfall sind, da sie sich - * auch durch die Menge der bereits gezauberten Sprüche erhöht. - * Je nach Kostenart werden dann die Komponenten noch mit cast_level - * multipliziert. - */ -void -pay_spell(unit * u, const spell * sp, int cast_level, int range) -{ - int k; - int resuse; - - for (k = 0; sp->components[k].type; k++) { - if (sp->components[k].type == r_aura) { - resuse = spellcost(u, sp) * range; - } else { - resuse = sp->components[k].amount * range; - } - - if (sp->components[k].cost == SPC_LINEAR - || sp->components[k].cost == SPC_LEVEL) - { - resuse *= cast_level; - } - - use_pooled(u, sp->components[k].type, GET_DEFAULT, resuse); - } -} - - -/* ------------------------------------------------------------- */ -/* Ein Magier kennt den Spruch und kann sich die Beschreibung anzeigen - * lassen, wenn diese in seiner Spruchliste steht. Zaubern muss er ihn - * aber dann immer noch nicht können, vieleicht ist seine Stufe derzeit - * nicht ausreichend oder die Komponenten fehlen. - */ -boolean -knowsspell(const region * r, const unit * u, const spell * sp) -{ - sc_mage * mage; - /* Ist überhaupt ein gültiger Spruch angegeben? */ - if (!sp || sp->id == 0) { - return false; - } - /* Magier? */ - mage = get_mage(u); - if (mage == NULL) { - log_warning(("%s ist kein Magier, versucht aber zu zaubern.\n", - unitname(u))); - return false; - } - /* steht der Spruch in der Spruchliste? */ - if (!u_hasspell(u, sp)) { - /* ist der Spruch aus einem anderen Magiegebiet? */ - if (know_school(u->faction, sp->magietyp)) { - return false; - } - if (eff_skill(u, SK_MAGIC, u->region) >= sp->level) { - log_warning(("%s ist hat die erforderliche Stufe, kennt aber %s nicht.\n", - unitname(u), spell_name(sp, default_locale))); - } - return false; - } - - /* hier sollten alle potentiellen Fehler abgefangen sein */ - return true; -} - -/* Um einen Spruch zu beherrschen, muss der Magier die Stufe des - * Spruchs besitzen, nicht nur wissen, das es ihn gibt (also den Spruch - * in seiner Spruchliste haben). - * Kosten für einen Spruch können Magiepunkte, Silber, Kraeuter - * und sonstige Gegenstaende sein. - */ - -boolean -cancast(unit * u, const spell * sp, int level, int range, struct order * ord) -{ - int k; - int itemanz; - resource * reslist = NULL; - - if (knowsspell(u->region, u, sp) == false) { - /* Diesen Zauber kennt die Einheit nicht */ - cmistake(u, ord, 173, MSG_MAGIC); - return false; - } - /* reicht die Stufe aus? */ - if (eff_skill(u, SK_MAGIC, u->region) < sp->level) { - /* die Einheit ist nicht erfahren genug für diesen Zauber */ - cmistake(u, ord, 169, MSG_MAGIC); - return false; - } - - for (k = 0; sp->components[k].type; ++k) { - if (sp->components[k].amount > 0) { - const resource_type * rtype = sp->components[k].type; - int itemhave; - - /* Die Kosten für Aura sind auch von der Zahl der bereits - * gezauberten Sprüche abhängig */ - if (rtype == r_aura) { - itemanz = spellcost(u, sp) * range; - } else { - itemanz = sp->components[k].amount * range; - } - - /* sind die Kosten stufenabhängig, so muss itemanz noch mit dem - * level multipliziert werden */ - switch(sp->components[k].cost) { - case SPC_LEVEL: - case SPC_LINEAR: - itemanz *= level; - break; - case SPC_FIX: - default: - break; - } - - itemhave = get_pooled(u, rtype, GET_DEFAULT, itemanz); - if (itemhave < itemanz) { - resource * res = malloc(sizeof(resource)); - res->number = itemanz-itemhave; - res->type = rtype; - res->next = reslist; - reslist = res; - } - } - } - if (reslist!=NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "missing_components_list", "list", reslist)); - return false; - } - return true; -} - -/* ------------------------------------------------------------- */ -/* generische Spruchstaerke, - * - * setzt sich derzeit aus der Stufe des Magiers, Magieturmeffekt, - * Spruchitems und Antimagiefeldern zusammen. Es koennen noch die - * Stufe des Spruchs und Magiekosten mit einfliessen. - * - * Die effektive Spruchstärke und ihre Auswirkungen werden in der - * Spruchfunktionsroutine ermittelt. - */ - -double -spellpower(region * r, unit * u, const spell * sp, int cast_level, struct order * ord) -{ - curse * c; - double force = cast_level; - int elf_power = -1; - - if (sp==NULL) { - return 0; - } else { - /* Bonus durch Magieturm und gesegneten Steinkreis */ - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - if (btype && btype->flags & BTF_MAGIC) ++force; - } - - if (get_item(u, I_RING_OF_POWER) > 0) ++force; - if (elf_power<0) { - elf_power = get_param_int(global.parameters, "rules.magic.elfpower", 0); - } - if (elf_power && u->race==new_race[RC_ELF] && r_isforest(r)) { - ++force; - } - - /* Antimagie in der Zielregion */ - c = get_curse(r->attribs, ct_find("antimagiczone")); - if (curse_active(c)) { - unit * mage = c->magician; - force -= curse_geteffect(c); - curse_changevigour(&r->attribs, c, (float)-cast_level); - cmistake(u, ord, 185, MSG_MAGIC); - if (mage!=NULL && mage->faction!=NULL) { - if (force>0) { - ADDMSG(&mage->faction->msgs, msg_message("reduce_spell", "self mage region", mage, u, r)); - } else { - ADDMSG(&mage->faction->msgs, msg_message("block_spell", "self mage region", mage, u, r)); - } - } - } - - /* Patzerfluch-Effekt: */ - c = get_curse(r->attribs, ct_find("fumble")); - if (curse_active(c)) { - unit * mage = c->magician; - force -= curse_geteffect(c); - curse_changevigour(&u->attribs, c, -1); - cmistake(u, ord, 185, MSG_MAGIC); - if (mage!=NULL && mage->faction!=NULL) { - if (force>0) { - ADDMSG(&mage->faction->msgs, msg_message("reduce_spell", "self mage region", mage, u, r)); - } else { - ADDMSG(&mage->faction->msgs, msg_message("block_spell", "self mage region", mage, u, r)); - } - } - } - - force = force * MagicPower(); - - return MAX(force, 0); -} - -/* ------------------------------------------------------------- */ -/* farcasting() == 1 -> gleiche Region, da man mit Null nicht vernünfigt - * rechnen kann */ -static int -farcasting(unit *magician, region *r) -{ - int dist; - int mult; - - if (!r) { - return INT_MAX; - } - - dist = koor_distance(r->x, r->y, magician->region->x, magician->region->y); - - if (dist > 24) return INT_MAX; - - mult = 1 << dist; - if (dist > 1) { - if (!path_exists(magician->region, r, dist*2, allowed_fly)) mult = INT_MAX; - } - - return mult; -} - - -/* ------------------------------------------------------------- */ -/* Antimagie - Magieresistenz */ -/* ------------------------------------------------------------- */ - -/* allgemeine Magieresistenz einer Einheit, - * reduziert magischen Schaden */ -double -magic_resistance(unit *target) -{ - attrib * a; - curse *c; - int n; - - /* Bonus durch Rassenmagieresistenz */ - double probability = target->race->magres; - assert(target->number>0); - - /* Magier haben einen Resistenzbonus vom Magietalent * 5%*/ - probability += effskill(target, SK_MAGIC)*0.05; - - /* Auswirkungen von Zaubern auf der Einheit */ - c = get_curse(target->attribs, ct_find("magicresistance")); - if (c) { - probability += 0.01 * curse_geteffect(c) * get_cursedmen(target, c); - } - - /* Unicorn +10 */ - n = get_item(target, I_ELVENHORSE); - if (n) probability += n*0.1/target->number; - - /* Auswirkungen von Zaubern auf der Region */ - a = a_find(target->region->attribs, &at_curse); - while (a && a->type==&at_curse) { - curse *c = (curse*)a->data.v; - unit *mage = c->magician; - - if (mage!=NULL) { - if (c->type == ct_find("goodmagicresistancezone")) { - if (alliedunit(mage, target->faction, HELP_GUARD)) { - probability += curse_geteffect(c)*0.01; - break; - } - } - else if (c->type == ct_find("badmagicresistancezone")) { - if (alliedunit(mage, target->faction, HELP_GUARD)) { - /* TODO: hier sollte doch sicher was passieren? */ - a = a->next; - continue; - } - } - } - a = a->next; - } - /* Bonus durch Artefakte */ - /* TODO (noch gibs keine)*/ - - /* Bonus durch Gebäude */ - { - struct building * b = inside_building(target); - const struct building_type * btype = b?b->type:NULL; - - /* gesegneter Steinkreis gibt 30% dazu */ - if (btype) probability += btype->magresbonus * 0.01; - } - return probability; -} - -/* ------------------------------------------------------------- */ -/* Prüft, ob das Objekt dem Zauber widerstehen kann. - * Objekte können Regionen, Units, Gebäude oder Schiffe sein. - * TYP_UNIT: - * Das höchste Talent des Ziels ist sein 'Magieresistenz-Talent', Magier - * bekommen einen Bonus. Grundchance ist 50%, für jede Stufe - * Unterschied gibt es 5%, minimalchance ist 5% für jeden (5-95%) - * Scheitert der Spruch an der Magieresistenz, so gibt die Funktion - * true zurück - */ - -boolean -target_resists_magic(unit *magician, void *obj, int objtyp, int t_bonus) -{ - double probability = 0.0; - - if (magician == NULL) return true; - if (obj == NULL) return true; - - switch(objtyp) { - case TYP_UNIT: - { - int at, pa = 0; - skill * sv; - unit * u = (unit*)obj; - - at = effskill(magician, SK_MAGIC); - - for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - int sk = effskill(u, sv->id); - if (pa < sk) pa = sk; - } - - /* Contest */ - probability = 0.05 * (10 + pa - at); - - probability += magic_resistance((unit *)obj); - break; - } - - case TYP_REGION: - /* Bonus durch Zauber */ - probability += 0.01 * get_curseeffect(((region *)obj)->attribs, C_RESIST_MAGIC, 0); - break; - - case TYP_BUILDING: - /* Bonus durch Zauber */ - probability += 0.01 * get_curseeffect(((building *)obj)->attribs, C_RESIST_MAGIC, 0); - - /* Bonus durch Typ */ - probability += 0.01 * ((building *)obj)->type->magres; - - break; - - case TYP_SHIP: - /* Bonus durch Zauber */ - probability += 0.01 * get_curseeffect(((ship *)obj)->attribs, C_RESIST_MAGIC, 0); - break; - } - - probability = MAX(0.02, probability + t_bonus*0.01); - probability = MIN(0.98, probability); - - /* gibt true, wenn die Zufallszahl kleiner als die chance ist und - * false, wenn sie gleich oder größer ist, dh je größer die - * Magieresistenz (chance) desto eher gibt die Funktion true zurück */ - return chance(probability); -} - -/* ------------------------------------------------------------- */ - -boolean -is_magic_resistant(unit *magician, unit *target, int resist_bonus) -{ - return (boolean)target_resists_magic(magician, target, TYP_UNIT, resist_bonus); -} - -/* ------------------------------------------------------------- */ -/* Patzer */ -/* ------------------------------------------------------------- */ -/* allgemeine Zauberpatzer: - * Treten auf, wenn die Stufe des Magieres zu niedrig ist. - * Abhaengig von Staerke des Spruchs. - * - * Die Warscheinlichkeit reicht von 20% (beherrscht den Spruch gerade - * eben) bis zu etwa 1% bei doppelt so gut wie notwendig - */ - -boolean -fumble(region * r, unit * u, const spell * sp, int cast_grade) -{ -/* X ergibt Zahl zwischen 1 und 0, je kleiner, desto besser der Magier. - * 0,5*40-20=0, dh wenn der Magier doppelt so gut ist, wie der Spruch - * benötigt, gelingt er immer, ist er gleich gut, gelingt der Spruch mit - * 20% Warscheinlichkeit nicht - * */ - - int rnd = 0; - double x = (double) cast_grade / (double) eff_skill(u, SK_MAGIC, r); - int patzer = (int) (((double) x * 40.0) - 20.0); - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - - if (btype) patzer -= btype->fumblebonus; - /* CHAOSPATZERCHANCE 10 : +10% Chance zu Patzern */ - if (sp->magietyp == M_DRAIG) { - patzer += CHAOSPATZERCHANCE; - } - if (is_cursed(u->attribs, C_MBOOST, 0) == true) { - patzer += CHAOSPATZERCHANCE; - } - if (is_cursed(u->attribs, C_FUMBLE, 0) == true) { - patzer += CHAOSPATZERCHANCE; - } - - /* wenn die Chance kleiner als 0 ist, können wir gleich false - * zurückgeben */ - if (patzer <= 0) { - return false; - } - rnd = rng_int()%100; - - if (rnd > patzer) { - /* Glück gehabt, kein Patzer */ - return false; - } - return true; -} - -/* ------------------------------------------------------------- */ -/* Dummy-Zauberpatzer, Platzhalter für speziel auf die Sprüche -* zugeschnittene Patzer */ -static void -patzer(castorder *co) -{ - unit *mage = co->magician.u; - - cmistake(mage, co->order, 180, MSG_MAGIC); - - return; -} -/* Die normalen Spruchkosten müssen immer bezahlt werden, hier noch - * alle weiteren Folgen eines Patzers - */ - -static void -do_fumble(castorder *co) -{ - curse * c; - region * r = co->rt; - unit * u = co->magician.u; - const spell *sp = co->sp; - int level = co->level; - int duration; - double effect; - - ADDMSG(&u->faction->msgs, msg_message("patzer", "unit region spell", - u, r, sp)); - switch (rng_int() % 10) { - case 0: - /* wenn vorhanden spezieller Patzer, ansonsten nix */ - if (sp->patzer) sp->patzer(co); - else patzer(co); - break; - - case 1: - /* Kröte */ - { - /* 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 triggerlit of the mage gone toad. - */ - trigger * trestore = trigger_changerace(u, u->race, u->irace); - - if (chance(0.7)) { - const item_type * it_toadslime = it_find("toadslime"); - if (it_toadslime!=NULL) { - t_add(&trestore, trigger_giveitem(u, it_toadslime, 1)); - } - } - - duration = rng_int()%level/2; - if (duration<2) duration = 2; - add_trigger(&u->attribs, "timer", trigger_timeout(duration, trestore)); - u->race = new_race[RC_TOAD]; - u->irace = NULL; - ADDMSG(&r->msgs, msg_message("patzer6", "unit region spell", - u, r, sp)); - break; - } - /* fall-through is intentional! */ - - case 2: - /* temporärer Stufenverlust */ - duration = MAX(rng_int()%level/2, 2); - effect = -0.5*level; - c = create_curse(u, &u->attribs, ct_find("skillmod"), (float)level, duration, - effect, 1); - c->data.i = SK_MAGIC; - ADDMSG(&u->faction->msgs, msg_message("patzer2", "unit region", u, r)); - break; - case 3: - case 4: - /* Spruch schlägt fehl, alle Magiepunkte weg */ - set_spellpoints(u, 0); - ADDMSG(&u->faction->msgs, msg_message("patzer3", "unit region spell", - u, r, sp)); - break; - - case 5: - case 6: - /* Spruch gelingt, aber alle Magiepunkte weg */ - if (sp->sp_function==NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); - } else { - ((nspell_f)sp->sp_function)(co); - } - set_spellpoints(u, 0); - ADDMSG(&u->faction->msgs, msg_message("patzer4", "unit region spell", - u, r, sp)); - break; - - case 7: - case 8: - case 9: - default: - /* Spruch gelingt, alle nachfolgenden Sprüche werden 2^4 so teuer */ - if (sp->sp_function==NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); - } else { - ((nspell_f)sp->sp_function)(co); - } - ADDMSG(&u->faction->msgs, msg_message("patzer5", "unit region spell", - u, r, sp)); - countspells(u, 3); - } - - return; -} - -/* ------------------------------------------------------------- */ -/* Regeneration von Aura */ -/* ------------------------------------------------------------- */ - -/* Ein Magier regeneriert pro Woche W(Stufe^1.5/2+1), mindestens 1 - * Zwerge nur die Hälfte - */ -static double -regeneration(unit * u) -{ - int sk; - double aura, d; - double potenz = 1.5; - double divisor = 2.0; - - sk = effskill(u, SK_MAGIC); - /* Rassenbonus/-malus */ - d = pow(sk, potenz) * u->race->regaura / divisor; - d++; - - /* Einfluss von Artefakten */ - /* TODO (noch gibs keine)*/ - - /* Würfeln */ - aura = (rng_double() * d + rng_double() * d)/2 + 1; - - aura *= MagicRegeneration(); - - return aura; -} - -void -regeneration_magiepunkte(void) -{ - region *r; - unit *u; - int aura, auramax; - double reg_aura; - int regen; - double mod; - - for (r = regions; r; r = r->next) { - for (u = r->units; u; u = u->next) { - if (u->number && is_mage(u)) { - aura = get_spellpoints(u); - auramax = max_spellpoints(r, u); - if (aura < auramax) { - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - reg_aura = regeneration(u); - - /* Magierturm erhöht die Regeneration um 75% */ - /* Steinkreis erhöht die Regeneration um 50% */ - if (btype) reg_aura *= btype->auraregen; - - /* Bonus/Malus durch Zauber */ - mod = get_curseeffect(u->attribs, C_AURA, 0); - if (mod>0) { - reg_aura = (reg_aura*mod)/100.0; - } - - /* Einfluss von Artefakten */ - /* TODO (noch gibs keine)*/ - - /* maximal Differenz bis Maximale-Aura regenerieren - * mindestens 1 Aura pro Monat */ - regen = (int)reg_aura; - reg_aura -= regen; - if (chance(reg_aura)) ++regen; - regen = MAX(1, regen); - regen = MIN((auramax - aura), regen); - - aura += regen; - ADDMSG(&u->faction->msgs, msg_message( - "regenaura", "unit region amount", - u, r, regen)); - } - set_spellpoints(u, MIN(aura, auramax)); - - /* Zum letzten Mal Spruchliste aktualisieren */ - /*updatespelllist(u);*/ - } - } - } -} - -static boolean -verify_ship(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) -{ - ship *sh = findship(spobj->data.i); - - if (sh!=NULL && sh->region!=r && (sp->sptyp & SEARCHLOCAL)) { - /* Burg muss in gleicher Region sein */ - sh = NULL; - } - - if (sh==NULL) { - /* Burg nicht gefunden */ - spobj->flag = TARGET_NOTFOUND; - ADDMSG(&mage->faction->msgs, msg_message("spellshipnotfound", - "unit region command id", mage, mage->region, ord, spobj->data.i)); - return false; - } - spobj->flag = 0; - spobj->data.sh = sh; - return true; -} - -static boolean -verify_building(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) -{ - building *b = findbuilding(spobj->data.i); - - if (b!=NULL && b->region!=r && (sp->sptyp & SEARCHLOCAL)) { - /* Burg muss in gleicher Region sein */ - b = NULL; - } - - if (b==NULL) { - /* Burg nicht gefunden */ - spobj->flag = TARGET_NOTFOUND; - ADDMSG(&mage->faction->msgs, msg_message("spellbuildingnotfound", - "unit region command id", mage, mage->region, ord, spobj->data.i)); - return false; - } - spobj->flag = 0; - spobj->data.b = b; - return true; -} - -message * -msg_unitnotfound(const struct unit * mage, struct order * ord, const struct spllprm * spobj) -{ - /* Einheit nicht gefunden */ - char tbuf[20]; - const char * uid; - - if (spobj->typ==SPP_UNIT) { - uid = itoa36(spobj->data.i); - } else { - sprintf(tbuf, "%s %s", LOC(mage->faction->locale, - parameters[P_TEMP]), itoa36(spobj->data.i)); - uid = tbuf; - } - return msg_message("unitnotfound_id", - "unit region command id", mage, mage->region, ord, uid); -} - -static boolean -verify_unit(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) -{ - unit *u = NULL; - switch (spobj->typ) { - case SPP_UNIT: - u = findunit(spobj->data.i); - break; - case SPP_TEMP: - u = findnewunit(r, mage->faction, spobj->data.i); - if (u==NULL) u = findnewunit(mage->region, mage->faction, spobj->data.i); - break; - default: - assert(!"shouldn't happen, this"); - } - if (u!=NULL && (sp->sptyp & SEARCHLOCAL)) { - if (u->region!=r) u = NULL; - else if (sp->sptyp & TESTCANSEE) { - if (!cansee(mage->faction, r, u, 0) && !ucontact(u, mage)) { - u = NULL; - } - } - } - - if (u==NULL) { - /* Einheit nicht gefunden */ - spobj->flag = TARGET_NOTFOUND; - ADDMSG(&mage->faction->msgs, msg_unitnotfound(mage, ord, spobj)); - return false; - } - /* Einheit wurde gefunden, pointer setzen */ - spobj->flag = 0; - spobj->data.u = u; - return true; -} - -/* ------------------------------------------------------------- */ -/* Zuerst wird versucht alle noch nicht gefundenen Objekte zu finden - * oder zu prüfen, ob das gefundene Objekt wirklich hätte gefunden - * werden dürfen (nicht alle Zauber wirken global). Dabei zählen wir die - * Misserfolge (failed). - * Dann folgen die Tests der gefundenen Objekte auf Magieresistenz und - * Sichtbarkeit. Dabei zählen wir die magieresistenten (resists) - * Objekte. Alle anderen werten wir als Erfolge (success) */ - -/* gibt bei Misserfolg 0 zurück, bei Magieresistenz zumindeste eines - * Objektes 1 und bei Erfolg auf ganzer Linie 2 */ -static void -verify_targets(castorder *co, int * invalid, int * resist, int * success) -{ - unit *mage = co->magician.u; - const spell *sp = co->sp; - region *target_r = co->rt; - spellparameter *sa = co->par; - int i; - - *invalid = 0; - *resist = 0; - *success = 0; - - if (sa && sa->length) { - /* zuerst versuchen wir vorher nicht gefundene Objekte zu finden. - * Wurde ein Objekt durch globalsuche gefunden, obwohl der Zauber - * gar nicht global hätte suchen dürften, setzen wir das Objekt - * zurück. */ - for (i=0;ilength;i++) { - spllprm * spobj = sa->param[i]; - - switch(spobj->typ) { - case SPP_TEMP: - case SPP_UNIT: - if (!verify_unit(target_r, mage, sp, spobj, co->order)) ++*invalid; - break; - case SPP_BUILDING: - if (!verify_building(target_r, mage, sp, spobj, co->order)) ++*invalid; - break; - case SPP_SHIP: - if (!verify_ship(target_r, mage, sp, spobj, co->order)) ++*invalid; - break; - default: - break; - } - } - - /* Nun folgen die Tests auf cansee und Magieresistenz */ - for (i=0;ilength;i++) { - spllprm * spobj = sa->param[i]; - unit * u; - building * b; - ship * sh; - region * tr; - - if (spobj->flag == TARGET_NOTFOUND) continue; - switch(spobj->typ) { - case SPP_TEMP: - case SPP_UNIT: - u = spobj->data.u; - - if ((sp->sptyp & TESTRESISTANCE) - && target_resists_magic(mage, u, TYP_UNIT, 0)) - { - /* Fehlermeldung */ - spobj->data.i = u->no; - spobj->flag = TARGET_RESISTS; - ++*resist; - ADDMSG(&mage->faction->msgs, msg_message("spellunitresists", - "unit region command target", - mage, mage->region, co->order, u)); - break; - } - - /* TODO: Test auf Parteieigenschaft Magieresistsenz */ - ++*success; - break; - case SPP_BUILDING: - b = spobj->data.b; - - if ((sp->sptyp & TESTRESISTANCE) - && target_resists_magic(mage, b, TYP_BUILDING, 0)) - { /* Fehlermeldung */ - spobj->data.i = b->no; - spobj->flag = TARGET_RESISTS; - ++*resist; - ADDMSG(&mage->faction->msgs, msg_message("spellbuildingresists", - "unit region command id", - mage, mage->region, co->order, spobj->data.i)); - break; - } - ++*success; - break; - case SPP_SHIP: - sh = spobj->data.sh; - - if ((sp->sptyp & TESTRESISTANCE) - && target_resists_magic(mage, sh, TYP_SHIP, 0)) - { /* Fehlermeldung */ - spobj->data.i = sh->no; - spobj->flag = TARGET_RESISTS; - ++*resist; - ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, - "spellshipresists", "ship", sh)); - break; - } - ++*success; - break; - - case SPP_REGION: - /* haben wir ein Regionsobjekt, dann wird auch dieses und - nicht target_r überprüft. */ - tr = spobj->data.r; - - if ((sp->sptyp & TESTRESISTANCE) - && target_resists_magic(mage, tr, TYP_REGION, 0)) - { /* Fehlermeldung */ - spobj->flag = TARGET_RESISTS; - ++*resist; - ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", - "unit region command", mage, mage->region, co->order)); - break; - } - ++*success; - break; - case SPP_INT: - case SPP_STRING: - ++*success; - break; - - default: - break; - } - } - } else { - /* der Zauber hat keine expliziten Parameter/Ziele, es kann sich - * aber um einen Regionszauber handeln. Wenn notwendig hier die - * Magieresistenz der Region prüfen. */ - if ((sp->sptyp & REGIONSPELL)) { - /* Zielobjekt Region anlegen */ - spllprm * spobj = malloc(sizeof(spllprm)); - spobj->flag = 0; - spobj->typ = SPP_REGION; - spobj->data.r = target_r; - - sa = calloc(1, sizeof(spellparameter)); - sa->length = 1; - sa->param = calloc(sa->length, sizeof(spllprm *)); - sa->param[0] = spobj; - co->par = sa; - - if ((sp->sptyp & TESTRESISTANCE)) { - if (target_resists_magic(mage, target_r, TYP_REGION, 0)) { - /* Fehlermeldung */ - ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", - "unit region command", mage, mage->region, co->order)); - spobj->flag = TARGET_RESISTS; - ++*resist; - } else { - ++*success; - } - } else { - ++*success; - } - } else { - ++*success; - } - } -} - -/* ------------------------------------------------------------- */ -/* Hilfsstrukturen für ZAUBERE */ -/* ------------------------------------------------------------- */ - -static void -free_spellparameter(spellparameter *pa) -{ - int i; - - /* Elemente free'en */ - for (i=0; i < pa->length; i++) { - - switch(pa->param[i]->typ) { - case SPP_STRING: - free(pa->param[i]->data.s); - break; - default: - break; - } - free(pa->param[i]); - } - - if (pa->param) free(pa->param); - /* struct free'en */ - free(pa); -} - -static int -addparam_string(const char * const param[], spllprm ** spobjp) -{ - spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); - assert(param[0]); - - spobj->flag = 0; - spobj->typ = SPP_STRING; - spobj->data.xs = strdup(param[0]); - return 1; -} - -static int -addparam_int(const char * const param[], spllprm ** spobjp) -{ - spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); - assert(param[0]); - - spobj->flag = 0; - spobj->typ = SPP_INT; - spobj->data.i = atoi((char*)param[0]); - return 1; -} - -static int -addparam_ship(const char * const param[], spllprm ** spobjp) -{ - spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); - int id = atoi36((const char *)param[0]); - - spobj->flag = 0; - spobj->typ = SPP_SHIP; - spobj->data.i = id; - return 1; -} - -static int -addparam_building(const char * const param[], spllprm ** spobjp) -{ - spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); - int id = atoi36((const char *)param[0]); - - spobj->flag = 0; - spobj->typ = SPP_BUILDING; - spobj->data.i = id; - return 1; -} - -static int -addparam_region(const char * const param[], spllprm ** spobjp, const unit * u, order * ord, plane * pl) -{ - assert(param[0]); - if (param[1]==0) { - /* Fehler: Zielregion vergessen */ - cmistake(u, ord, 194, MSG_MAGIC); - return -1; - } else { - int tx = atoi((const char*)param[0]), ty = atoi((const char*)param[1]); - int x = rel_to_abs(pl, u->faction, tx, 0); - int y = rel_to_abs(pl, u->faction, ty, 1); - region *rt; - - pnormalize(&x, &y, pl); - rt = findregion(x,y); - - if (rt!=NULL) { - spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); - - spobj->flag = 0; - spobj->typ = SPP_REGION; - spobj->data.r = rt; - } else { - /* Fehler: Zielregion vergessen */ - cmistake(u, ord, 194, MSG_MAGIC); - return -1; - } - return 2; - } -} - - -static int -addparam_unit(const char * const param[], spllprm ** spobjp, const unit * u, order * ord) -{ - spllprm *spobj; - int i = 0; - sppobj_t otype = SPP_UNIT; - - *spobjp = NULL; - if (findparam(param[0], u->faction->locale)==P_TEMP) { - if (param[1]==NULL) { - /* Fehler: Ziel vergessen */ - cmistake(u, ord, 203, MSG_MAGIC); - return -1; - } - ++i; - otype = SPP_TEMP; - } - - spobj = *spobjp = malloc(sizeof(spllprm)); - spobj->flag = 0; - spobj->typ = otype; - spobj->data.i = atoi36((const char*)param[i]); - - return i+1; -} - -static spellparameter * -add_spellparameter(region *target_r, unit *u, const char *syntax, const char * const param[], int size, struct order * ord) -{ - boolean fail = false; - int i = 0; - int p = 0; - const char * c; - spellparameter *par; - int minlen = 0; - - for (c=syntax;*c!=0;++c) { - /* this makes sure that: - * minlen("kc?") = 0 - * minlen("kc+") = 1 - * minlen("cccc+c?") = 4 - */ - if (*c=='?') --minlen; - else if (*c!='+' && *c!='k') ++minlen; - } - c = syntax; - - /* mindestens ein Ziel (Ziellose Zauber werden nicht - * geparst) */ - if (minlen && size==0) { - /* Fehler: Ziel vergessen */ - cmistake(u, ord, 203, MSG_MAGIC); - return 0; - } - - par = malloc(sizeof(spellparameter)); - par->length = size; - if (!size) { - par->param = NULL; - return par; - } - par->param = malloc(size * sizeof(spllprm *)); - - while (!fail && *c && ifaction->locale); - switch (pword) { - case P_REGION: - spobj = malloc(sizeof(spllprm)); - spobj->flag = 0; - spobj->typ = SPP_REGION; - spobj->data.r = u->region; - j = 0; - ++c; - break; - case P_UNIT: - if (iparam[p++] = spobj; - i += j; - } - } - - /* im Endeffekt waren es evtl. nur p parameter (wegen TEMP) */ - par->length = p; - if (fail || par->lengthmagician.u = u; - corder->familiar = u2; - corder->sp = sp; - corder->level = lev; - corder->force = force; - corder->rt = r; - corder->distance = range; - corder->order = copy_order(ord); - corder->par = p; - - return corder; -} - -/* Hänge c-order co an die letze c-order von cll an */ -void -add_castorder(spellrank *cll, castorder *co) -{ - if (cll->begin==NULL) { - cll->end = &cll->begin; - } - - *cll->end = co; - cll->end = &co->next; - - return; -} - -void -free_castorders(castorder *co) -{ - castorder *co2; - - while (co) { - co2 = co; - co = co->next; - if (co2->par) { - free_spellparameter(co2->par); - } - if (co2->order) free_order(co2->order); - free(co2); - } - return; -} - -/* ------------------------------------------------------------- */ -/*** - ** at_familiarmage - **/ - -typedef struct familiar_data { - unit * mage; - unit * familiar; -} famililar_data; - -boolean -is_familiar(const unit *u) -{ - attrib * a = a_find(u->attribs, &at_familiarmage); - return i2b(a!=NULL); -} - -static void -a_write_unit(const attrib * a, const void * owner, struct storage * store) -{ - unit * u = (unit*)a->data.v; - write_unit_reference(u, store); -} - -static int -sm_familiar(const unit * u, const region * r, skill_t sk, int value) /* skillmod */ -{ - if (sk==SK_MAGIC) return value; - else { - int mod; - unit * familiar = get_familiar(u); - if (familiar==NULL) { - /* the familiar is dead */ - return value; - } - mod = eff_skill(familiar, sk, r)/2; - if (r != familiar->region) { - mod /= distance(r, familiar->region); - } - return value + mod; - } -} - -static 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); - 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; - } - - a = a_find(mage->attribs, &at_familiar); - if (a==NULL) { - a = a_add(&mage->attribs, a_new(&at_familiar)); - a->data.v = familiar; - } else assert(!a->data.v || a->data.v == familiar); - /* 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 assert(!a->data.v || a->data.v == mage); -} - -void -remove_familiar(unit *mage) -{ - attrib *a = a_find(mage->attribs, &at_familiar); - attrib *an; - skillmod_data *smd; - - if (a!=NULL) { - a_remove(&mage->attribs, a); - } - a = a_find(mage->attribs, &at_skillmod); - while (a && a->type==&at_skillmod) { - an = a->next; - smd = (skillmod_data *)a->data.v; - if (smd->special==sm_familiar) a_remove(&mage->attribs, a); - a = an; - } -} - -boolean -create_newfamiliar(unit * mage, unit * familiar) -{ - /* 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); - - 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; - - /* TODO: Diese Attribute beim Tod des Familiars entfernen: */ - /* Wenn der Magier stirbt, dann auch der Vertraute */ - add_trigger(&mage->attribs, "destroy", trigger_killunit(familiar)); - /* 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; -} - -static int -resolve_familiar(variant data, void * addr) -{ - unit * familiar; - int result = resolve_unit(data, &familiar); - if (result==0 && familiar) { - 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; -} - -static int -read_familiar(attrib * a, void * owner, struct storage * store) -{ - int result = read_reference(&a->data.v, store, read_unit_reference, resolve_familiar); - if (result==0 && a->data.v==NULL) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -/* clones */ - -void -create_newclone(unit * mage, unit * clone) -{ - attrib *a; - - a = a_find(mage->attribs, &at_clone); - if (a == NULL) { - a = a_add(&mage->attribs, a_new(&at_clone)); - a->data.v = clone; - } else assert(!a->data.v || a->data.v == clone); - /* TODO: Diese Attribute beim Tod des Klons entfernen: */ - - a = a_find(clone->attribs, &at_clonemage); - if (a == NULL) { - a = a_add(&clone->attribs, a_new(&at_clonemage)); - a->data.v = mage; - } else assert(!a->data.v || a->data.v == mage); - - /* Wenn der Magier stirbt, wird das in destroy_unit abgefangen. - * Kein Trigger, zu kompliziert. */ - - /* Wenn der Klon stirbt, dann bekommt der Magier einen Schock */ - add_trigger(&clone->attribs, "destroy", trigger_clonedied(mage)); -} - -static void -set_clone(unit * mage, unit * clone) -{ - attrib *a; - - a = a_find(mage->attribs, &at_clone); - if (a==NULL) { - a = a_add(&mage->attribs, a_new(&at_clone)); - a->data.v = clone; - } else assert(!a->data.v || a->data.v == clone); - - a = a_find(clone->attribs, &at_clonemage); - if (a==NULL) { - a = a_add(&clone->attribs, a_new(&at_clonemage)); - a->data.v = mage; - } else assert(!a->data.v || a->data.v == mage); -} - -unit * -has_clone(unit *mage) -{ - attrib *a = a_find(mage->attribs, &at_clone); - if(a) return (unit *)a->data.v; - return NULL; -} - -static int -resolve_clone(variant data, void * addr) -{ - unit * clone; - int result = resolve_unit(data, &clone); - if (result==0 && clone) { - 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; -} - -static int -read_clone(attrib * a, void * owner, struct storage * store) -{ - int result = read_reference(&a->data.v, store, read_unit_reference, resolve_clone); - if (result==0 && a->data.v==NULL) { - 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) { - 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; -} - -static int -read_magician(attrib * a, void * owner, struct storage * store) -{ - int result = read_reference(&a->data.v, store, read_unit_reference, resolve_mage); - if (result==0 && a->data.v==NULL) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -static int -age_unit(attrib * a) -/* if unit is gone or dead, remove the attribute */ -{ - unit * u = (unit*)a->data.v; - return (u!=NULL && u->number>0)?AT_AGE_KEEP:AT_AGE_REMOVE; -} - -attrib_type at_familiarmage = { - "familiarmage", - NULL, - NULL, - age_unit, - a_write_unit, - read_magician, - ATF_UNIQUE -}; - -attrib_type at_familiar = { - "familiar", - NULL, - NULL, - age_unit, - a_write_unit, - read_familiar, - ATF_UNIQUE -}; - -attrib_type at_clonemage = { - "clonemage", - NULL, - NULL, - age_unit, - a_write_unit, - read_magician, - ATF_UNIQUE -}; - -attrib_type at_clone = { - "clone", - NULL, - NULL, - age_unit, - a_write_unit, - read_clone, - ATF_UNIQUE -}; - -unit * -get_familiar(const unit *u) -{ - attrib * a = a_find(u->attribs, &at_familiar); - if (a!=NULL) { - unit * u = (unit*)a->data.v; - if (u->number>0) return u; - } - return NULL; -} - -unit * -get_familiar_mage(const unit *u) -{ - attrib * a = a_find(u->attribs, &at_familiarmage); - if (a!=NULL) { - unit * u = (unit*)a->data.v; - if (u->number>0) return u; - } - return NULL; -} - -unit * -get_clone(const unit *u) -{ - attrib * a = a_find(u->attribs, &at_clone); - if (a!=NULL) { - unit * u = (unit*)a->data.v; - if (u->number>0) return u; - } - return NULL; -} - -unit * -get_clone_mage(const unit *u) -{ - attrib * a = a_find(u->attribs, &at_clonemage); - if (a!=NULL) { - unit * u = (unit*)a->data.v; - if (u->number>0) return u; - } - return NULL; -} - -static boolean -is_moving_ship(const region * r, const ship *sh) -{ - const unit *u = shipowner(sh); - - if (u) switch (get_keyword(u->thisorder)) { - case K_ROUTE: - case K_MOVE: - case K_FOLLOW: - return true; - } - return false; -} - -static castorder * -cast_cmd(unit * u, order * ord) -{ - region * r = u->region; - region * target_r = r; - int level, range; - unit *familiar = NULL, *mage = u; - const char * s; - spell * sp; - plane * pl; - spellparameter *args = NULL; - - if (LongHunger(u)) { - cmistake(u, ord, 224, MSG_MAGIC); - return 0; - } - pl = rplane(r); - if (pl && fval(pl, PFL_NOMAGIC)) { - cmistake(u, ord, 269, MSG_MAGIC); - return 0; - } - level = eff_skill(u, SK_MAGIC, r); - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - /* für Syntax ' STUFE x REGION y z ' */ - if (findparam(s, u->faction->locale) == P_LEVEL) { - int p = getint(); - level = MIN(p, level); - if (level < 1) { - /* Fehler "Das macht wenig Sinn" */ - cmistake(u, ord, 10, MSG_MAGIC); - return 0; - } - s = getstrtoken(); - } - if (findparam(s, u->faction->locale) == P_REGION) { - int t_x = getint(); - int t_y = getint(); - plane * pl = getplane(u->region); - t_x = rel_to_abs(pl, u->faction, t_x,0); - t_y = rel_to_abs(pl, u->faction, t_y,1); - pnormalize(&t_x, &t_y, pl); - target_r = findregion(t_x, t_y); - if (!target_r) { - /* Fehler "Die Region konnte nicht verzaubert werden" */ - ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", - "unit region command", mage, mage->region, ord)); - return 0; - } - s = getstrtoken(); - } - /* für Syntax ' REGION x y STUFE z ' - * hier nach REGION nochmal auf STUFE prüfen */ - if (findparam(s, u->faction->locale) == P_LEVEL) { - int p = getint(); - level = MIN(p, level); - if (level < 1) { - /* Fehler "Das macht wenig Sinn" */ - cmistake(u, ord, 10, MSG_MAGIC); - return 0; - } - s = getstrtoken(); - } - if (!s[0] || strlen(s) == 0) { - /* Fehler "Es wurde kein Zauber angegeben" */ - cmistake(u, ord, 172, MSG_MAGIC); - return 0; - } - sp = get_spellfromtoken(u, s, u->faction->locale); - - /* Vertraute können auch Zauber sprechen, die sie selbst nicht - * können. get_spellfromtoken findet aber nur jene Sprüche, die - * die Einheit beherrscht. */ - if (sp == NULL && is_familiar(u)) { - familiar = u; - mage = get_familiar_mage(u); - if (mage!=NULL) sp = get_spellfromtoken(mage, s, mage->faction->locale); - } - - if (sp == NULL) { - /* Fehler 'Spell not found' */ - cmistake(u, ord, 173, MSG_MAGIC); - return 0; - } - /* um testen auf spruchnamen zu unterbinden sollte vor allen - * fehlermeldungen die anzeigen das der magier diesen Spruch - * nur in diese Situation nicht anwenden kann, noch eine - * einfache Sicherheitsprüfung kommen */ - if (!knowsspell(r, u, sp)) { - /* vorsicht! u kann der familiar sein */ - if (!familiar) { - cmistake(u, ord, 173, MSG_MAGIC); - return 0; - } - } - if (sp->sptyp & ISCOMBATSPELL) { - /* Fehler: "Dieser Zauber ist nur im Kampf sinnvoll" */ - cmistake(u, ord, 174, MSG_MAGIC); - return 0; - } - /* Auf dem Ozean Zaubern als quasi-langer Befehl können - * normalerweise nur Meermenschen, ausgenommen explizit als - * OCEANCASTABLE deklarierte Sprüche */ - if (fval(r->terrain, SEA_REGION)) { - if (u->race != new_race[RC_AQUARIAN] - && !fval(u->race, RCF_SWIM) - && !(sp->sptyp & OCEANCASTABLE)) { - /* Fehlermeldung */ - ADDMSG(&u->faction->msgs, msg_message("spellfail_onocean", - "unit region command", u, u->region, ord)); - return 0; - } - /* Auf bewegenden Schiffen kann man nur explizit als - * ONSHIPCAST deklarierte Zauber sprechen */ - } else if (u->ship) { - if (is_moving_ship(r, u->ship)) { - if (!(sp->sptyp & ONSHIPCAST)) { - /* Fehler: "Diesen Spruch kann man nicht auf einem sich - * bewegenden Schiff stehend zaubern" */ - cmistake(u, ord, 175, MSG_MAGIC); - return 0; - } - } - } - /* Farcasting bei nicht farcastbaren Sprüchen abfangen */ - range = farcasting(u, target_r); - if (range > 1) { - if (!(sp->sptyp & FARCASTING)) { - /* Fehler "Diesen Spruch kann man nicht in die Ferne - * richten" */ - cmistake(u, ord, 176, MSG_MAGIC); - return 0; - } - if (range > 1024) { /* (2^10) weiter als 10 Regionen entfernt */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "spellfail::nocontact", - "target", target_r)); - return 0; - } - } - /* Stufenangabe bei nicht Stufenvariierbaren Sprüchen abfangen */ - if (!(sp->sptyp & SPELLLEVEL)) { - int ilevel = eff_skill(u, SK_MAGIC, u->region); - if (ilevel!=level) { - level = ilevel; - ADDMSG(&u->faction->msgs, msg_message("spellfail::nolevel", - "mage region command", u, u->region, ord)); - } - } - /* Vertrautenmagie */ - /* Kennt der Vertraute den Spruch, so zaubert er ganz normal. - * Ansonsten zaubert der Magier durch seinen Vertrauten, dh - * zahlt Komponenten und Aura. Dabei ist die maximale Stufe - * die des Vertrauten! - * Der Spruch wirkt dann auf die Region des Vertrauten und - * gilt nicht als Farcasting. */ - if (familiar || is_familiar(u)) { - if ((sp->sptyp & NOTFAMILIARCAST)) { - /* Fehler: "Diesen Spruch kann der Vertraute nicht zaubern" */ - cmistake(u, ord, 177, MSG_MAGIC); - return 0; - } - if (!knowsspell(r, u, sp)) { /* Magier zaubert durch Vertrauten */ - mage = get_familiar_mage(u); - if (range > 1) { /* Fehler! Versucht zu Farcasten */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_farcast", - "mage", mage)); - return 0; - } - if (distance(mage->region, r) > eff_skill(mage, SK_MAGIC, mage->region)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_toofar", - "mage", mage)); - return 0; - } - /* mage auf magier setzen, level anpassen, range für Erhöhung - * der Spruchkosten nutzen, langen Befehl des Magiers - * löschen, zaubern kann er noch */ - range *= 2; - set_order(&mage->thisorder, NULL); - level = MIN(level, eff_skill(mage, SK_MAGIC, mage->region)/2); - familiar = u; - } - } - /* Weitere Argumente zusammenbasteln */ - if (sp->parameter) { - char ** params = malloc(2*sizeof(char*)); - int p = 0, size = 2; - for (;;) { - s = getstrtoken(); - if (*s==0) break; - if (p+1>=size) { - size*=2; - params = realloc(params, sizeof(char*)*size); - } - params[p++] = strdup(s); - } - params[p] = 0; - args = add_spellparameter(target_r, mage, sp->parameter, (const char * const *)params, p, ord); - for (p=0;params[p];++p) free(params[p]); - free(params); - if (args==NULL) { - /* Syntax war falsch */ - return 0; - } - } - return new_castorder(mage, familiar, sp, target_r, level, 0, range, ord, args); -} - -/* ------------------------------------------------------------- */ -/* Damit man keine Rituale in fremden Gebiet machen kann, diese vor - * Bewegung zaubern. Magier sind also in einem fremden Gebiet eine Runde - * lang verletzlich, da sie es betreten, und angegriffen werden können, - * bevor sie ein Ritual machen können. - * - * Syntax: ZAUBER [REGION X Y] [STUFE ] "Spruchname" [Einheit-1 - * Einheit-2 ..] - * - * Nach Priorität geordnet die Zauber global auswerten. - * - * Die Kosten für Farcasting multiplizieren sich mit der Entfernung, - * cast_level gibt die virtuelle Stufe an, die den durch das Farcasten - * entstandenen Spruchkosten entspricht. Sind die Spruchkosten nicht - * levelabhängig, so sind die Kosten nur von der Entfernung bestimmt, - * die Stärke/Level durch den realen Skill des Magiers - */ - -void -magic(void) -{ - region *r; - int rank; - castorder *co; - spellrank spellranks[MAX_SPELLRANK]; - - memset(spellranks, 0, sizeof(spellranks)); - - for (r = regions; r; r = r->next) { - unit *u; - for (u = r->units; u; u = u->next) { - order * ord; - - if (u->number<=0 || u->race == new_race[RC_SPELL]) - continue; - - if (u->race == new_race[RC_INSECT] && r_insectstalled(r) && - !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) - continue; - - if (fval(u, UFL_WERE|UFL_LONGACTION)) { - continue; - } - - for (ord = u->orders; ord; ord = ord->next) { - if (get_keyword(ord) == K_CAST) { - castorder * co = cast_cmd(u, ord); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - if (co) { - const spell * sp = co->sp; - add_castorder(&spellranks[sp->rank], co); - } - } - } - } - } - - /* Da sich die Aura und Komponenten in der Zwischenzeit verändert - * haben können und sich durch vorherige Sprüche das Zaubern - * erschwert haben kann, muss beim zaubern erneut geprüft werden, ob der - * Spruch überhaupt gezaubert werden kann. - * (level) die effektive Stärke des Spruchs (= Stufe, auf der der - * Spruch gezaubert wird) */ - - for (rank = 0; rank < MAX_SPELLRANK; rank++) { - for (co = spellranks[rank].begin; co; co = co->next) { - order * ord = co->order; - int invalid, resist, success, cast_level = co->level; - boolean fumbled = false; - unit * u = co->magician.u; - const spell *sp = co->sp; - region * target_r = co->rt; - - /* reichen die Komponenten nicht, wird der Level reduziert. */ - co->level = eff_spelllevel(u, sp, cast_level, co->distance); - - if (co->level < 1) { - /* Fehlermeldung mit Komponenten generieren */ - cancast(u, sp, cast_level, co->distance, ord); - continue; - } - - if (cast_level > co->level) { - /* Sprüche mit Fixkosten werden immer auf Stufe des Spruchs - * gezaubert, co->level ist aber defaultmäßig Stufe des Magiers */ - if (spl_costtyp(sp) != SPC_FIX) { - ADDMSG(&u->faction->msgs, msg_message("missing_components", - "unit spell level", u, sp, cast_level)); - } - } - - /* Prüfen, ob die realen Kosten für die gewünschten Stufe bezahlt - * werden können */ - if (cancast(u, sp, co->level, co->distance, ord) == false) { - /* die Fehlermeldung wird in cancast generiert */ - continue; - } - - co->force = spellpower(target_r, u, sp, co->level, ord); - /* die Stärke kann durch Antimagie auf 0 sinken */ - if (co->force <= 0) { - co->force = 0; - ADDMSG(&u->faction->msgs, msg_message("missing_force", - "unit spell level", u, sp, co->level)); - } - - /* Ziele auf Existenz prüfen und Magieresistenz feststellen. Wurde - * kein Ziel gefunden, so ist verify_targets=0. Scheitert der - * Spruch an der Magieresistenz, so ist verify_targets = 1, bei - * Erfolg auf ganzer Linie ist verify_targets= 2 - */ - verify_targets(co, &invalid, &resist, &success); - if (success+resist==0) { - /* kein Ziel gefunden, Fehlermeldungen sind in verify_targets */ - /* keine kosten für den zauber */ - continue; /* äußere Schleife, nächster Zauberer */ - } else if (co->force>0 && resist>0) { - /* einige oder alle Ziele waren magieresistent */ - if (success==0) { - co->force = 0; - /* zwar wurde mindestens ein Ziel gefunden, das widerstand - * jedoch dem Zauber. Kosten abziehen und abbrechen. */ - ADDMSG(&u->faction->msgs, msg_message("spell_resist", "unit region spell", - u, r, sp)); - } - } - - /* Auch für Patzer gibt es Erfahrung, müssen die Spruchkosten - * bezahlt werden und die nachfolgenden Sprüche werden teurer */ - if (co->force>0) { - if (fumble(target_r, u, sp, co->level)) { - /* zuerst bezahlen, dann evt in do_fumble alle Aura verlieren */ - fumbled = true; - } else { - if (sp->sp_function==NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); - co->level = 0; - } else { - co->level = ((nspell_f)sp->sp_function)(co); - } - if (co->level <= 0) { - /* Kosten nur für real benötige Stufe berechnen */ - continue; - } - } - } - pay_spell(u, sp, co->level, co->distance); - /* erst bezahlen, dann Kostenzähler erhöhen */ - if (fumbled) do_fumble(co); - countspells(u, 1); - } - } - - /* Sind alle Zauber gesprochen gibts Erfahrung */ - for (r = regions; r; r = r->next) { - unit *u; - for (u = r->units; u; u = u->next) { - if (is_mage(u) && countspells(u, 0) > 0) { - produceexp(u, SK_MAGIC, u->number); - /* Spruchlistenaktualiesierung ist in Regeneration */ - } - } - } - for (rank = 0; rank < MAX_SPELLRANK; rank++) { - free_castorders(spellranks[rank].begin); - } - remove_empty_units(); -} - -const char * -spell_info(const spell * sp, const struct locale * lang) -{ - return LOC(lang, mkname("spellinfo", sp->sname)); -} - -const char * -spell_name(const spell * sp, const struct locale * lang) -{ - return LOC(lang, mkname("spell", sp->sname)); -} - -const char * -curse_name(const curse_type * ctype, const struct locale * lang) -{ - return LOC(lang, mkname("spell", ctype->cname)); -} - -void -spelllist_add(spell_list ** lspells, spell * sp) -{ - spell_list * entry; - - while (*lspells) { - spell_list * slist = *lspells; - if (slist->data->id==sp->id) { - if (slist->data==sp) { - log_error(("trying to add spell '%s' to a list twice.\n", sp->sname)); - return; - } - } - if (slist->data->id>sp->id) break; - lspells = &slist->next; - } - entry = malloc(sizeof(spell_list)); - entry->data = sp; - entry->next = *lspells; - *lspells = entry; -} - -spell_list ** -spelllist_find(spell_list ** lspells, const spell * sp) -{ - while (*lspells) { - spell_list * slist = *lspells; - if (slist->data->id>=sp->id) break; - lspells = &slist->next; - } - return lspells; -} - -extern struct spell_list ** get_spelllist(struct sc_mage * mage, struct faction * f) -{ - if (mage) { - return &mage->spells; - } - return NULL; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "magic.h" + +#include "building.h" +#include "curse.h" +#include "faction.h" +#include "item.h" +#include "message.h" +#include "objtypes.h" +#include "order.h" +#include "pathfinder.h" +#include "plane.h" +#include "pool.h" +#include "race.h" +#include "region.h" +#include "ship.h" +#include "skill.h" +#include "spell.h" +#include "teleport.h" +#include "terrain.h" +#include "unit.h" +#include "version.h" + +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include +#include + +/* ------------------------------------------------------------- */ + +const char *magic_school[MAXMAGIETYP] = +{ + "gray", + "illaun", + "tybied", + "cerddor", + "gwyrrd", + "draig", + "common" +}; + +attrib_type at_reportspell = { + "reportspell", NULL, NULL, NULL, NO_WRITE, NO_READ +}; + +/** + ** at_icastle + ** TODO: separate castle-appearance from illusion-effects + **/ + +static double +MagicRegeneration(void) +{ + static double value = -1.0; + if (value<0) { + const char * str = get_param(global.parameters, "magic.regeneration"); + value = str?atof(str):1.0; + } + return value; +} + +double +MagicPower(void) +{ + static double value = -1.0; + if (value<0) { + const char * str = get_param(global.parameters, "magic.power"); + value = str?atof(str):1.0; + } + return value; +} + +static int +a_readicastle(attrib * a, void * owner, struct storage * store) +{ + icastle_data * data = (icastle_data*)a->data.v; + variant bno; + char token[32]; + store->r_tok_buf(store, token, sizeof(token)); + bno.i = store->r_int(store); + data->time = store->r_int(store); + data->building = findbuilding(bno.i); + if (!data->building) { + /* this shouldn't happen, but just in case it does: */ + ur_add(bno, &data->building, resolve_building); + } + data->type = bt_find(token); + return AT_READ_OK; +} + +static void +a_writeicastle(const attrib * a, const void * owner, struct storage * store) +{ + icastle_data * data = (icastle_data*)a->data.v; + store->w_tok(store, data->type->_name); + store->w_int(store, data->building->no); + store->w_int(store, data->time); +} + +static int +a_ageicastle(struct attrib * a) +{ + icastle_data * data = (icastle_data*)a->data.v; + if (data->time<=0) { + building * b = data->building; + region * r = b->region; + ADDMSG(&r->msgs, msg_message("icastle_dissolve", "building", b)); + /* remove_building lets units leave the building */ + remove_building(&r->buildings, b); + return AT_AGE_REMOVE; + } + else data->time--; + return AT_AGE_KEEP; +} + +static void +a_initicastle(struct attrib * a) +{ + a->data.v = calloc(sizeof(icastle_data), 1); +} + +static void +a_finalizeicastle(struct attrib * a) +{ + free(a->data.v); +} + +attrib_type at_icastle = { + "zauber_icastle", + a_initicastle, + a_finalizeicastle, + a_ageicastle, + a_writeicastle, + a_readicastle +}; + +/* ------------------------------------------------------------- */ + +extern int dice(int count, int value); + +/* ------------------------------------------------------------- */ +/* aus dem alten System übriggebliegene Funktionen, die bei der + * Umwandlung von alt nach neu gebraucht werden */ +/* ------------------------------------------------------------- */ + +static void +init_mage(attrib * a) { + a->data.v = calloc(sizeof(sc_mage), 1); +} + +static void +free_mage(attrib * a) +{ + sc_mage * mage = (sc_mage*)a->data.v; + freelist(mage->spells); + free(mage); +} + +int FactionSpells(void) +{ + static int rules_factionspells = -1; + if (rules_factionspells<0) { + rules_factionspells = get_param_int(global.parameters, "rules.magic.factionlist", 0); + } + return rules_factionspells; +} + +void read_spellist(struct spell_list ** slistp, magic_t mtype, struct storage * store) +{ + for (;;) { + spell * sp; + char spname[64]; + + if (store->versionr_int(store); + if (i < 0) break; + sp = find_spellbyid(M_NONE, (spellid_t)i); + } else { + store->r_tok_buf(store, spname, sizeof(spname)); + if (strcmp(spname, "end")==0) break; + sp = find_spell(mtype, spname); + } + if (sp!=NULL) { + add_spell(slistp, sp); + } + } +} + +static int +read_mage(attrib * a, void * owner, struct storage * store) +{ + int i, mtype; + sc_mage * mage = (sc_mage*)a->data.v; + char spname[64]; + + mtype = store->r_int(store); + mage->spellpoints = store->r_int(store); + mage->spchange = store->r_int(store); + mage->magietyp = (magic_t)mtype; + for (i=0;i!=MAXCOMBATSPELLS;++i) { + spell * sp = NULL; + int level = 0; + if (store->versionr_int(store); + level = store->r_int(store); + if (spid>=0) { + sp = find_spellbyid(mage->magietyp, (spellid_t)spid); + } + } else { + store->r_tok_buf(store, spname, sizeof(spname)); + level = store->r_int(store); + + if (strcmp("none", spname)!=0) { + sp = find_spell(mage->magietyp, spname); + } + } + if (sp && level>=0) { + int slot = -1; + if (sp->sptyp & PRECOMBATSPELL) slot = 0; + else if (sp->sptyp & COMBATSPELL) slot = 1; + else if (sp->sptyp & POSTCOMBATSPELL) slot = 2; + if (slot>=0) { + mage->combatspells[slot].level = level; + mage->combatspells[slot].sp = sp; + } + } + } + read_spellist(&mage->spells, mage->magietyp, store); + return AT_READ_OK; +} + +void write_spelllist(const spell_list * slist, struct storage * store) +{ + while (slist!=NULL) { + spell * sp = slist->data; + store->w_tok(store, sp->sname); + slist = slist->next; + } + store->w_tok(store, "end"); +} + +static void +write_mage(const attrib * a, const void * owner, struct storage * store) +{ + int i; + sc_mage *mage = (sc_mage*)a->data.v; + + store->w_int(store, mage->magietyp); + store->w_int(store, mage->spellpoints); + store->w_int(store, mage->spchange); + for (i=0;i!=MAXCOMBATSPELLS;++i) { + store->w_tok(store, mage->combatspells[i].sp?mage->combatspells[i].sp->sname:"none"); + store->w_int(store, mage->combatspells[i].level); + } + write_spelllist(mage->spells, store); +} + +attrib_type at_mage = { + "mage", + init_mage, + free_mage, + NULL, + write_mage, + read_mage, + ATF_UNIQUE +}; + +boolean +is_mage(const unit * u) +{ + return i2b(get_mage(u) != NULL); +} + +sc_mage * +get_mage(const unit * u) +{ + if (has_skill(u, SK_MAGIC)) { + attrib * a = a_find(u->attribs, &at_mage); + if (a) return a->data.v; + } + return (sc_mage *) NULL; +} + +/* ------------------------------------------------------------- */ +/* Ausgabe der Spruchbeschreibungen +* Anzeige des Spruchs nur, wenn die Stufe des besten Magiers vorher +* kleiner war (u->faction->seenspells). Ansonsten muss nur geprüft +* werden, ob dieser Magier den Spruch schon kennt, und andernfalls der +* Spruch zu seiner List-of-known-spells hinzugefügt werden. +*/ + + +static int +read_seenspell(attrib * a, void * owner, struct storage * store) +{ + int i; + spell * sp = NULL; + char token[32]; + + store->r_tok_buf(store, token, sizeof(token)); + i = atoi(token); + if (i!=0) { + sp = find_spellbyid(M_NONE, (spellid_t)i); + } else { + int mtype; + mtype = store->r_int(store); + sp = find_spell((magic_t)mtype, token); + } + if (sp==NULL) { + /* log_error(("could not find seenspell '%s'\n", buf)); */ + return AT_READ_FAIL; + } + a->data.v = sp; + return AT_READ_OK; +} + +static void +write_seenspell(const attrib * a, const void * owner, struct storage * store) +{ + const spell * sp = (const spell*)a->data.v; + store->w_tok(store, sp->sname); + store->w_int(store, sp->magietyp); +} + +attrib_type at_seenspell = { + "seenspell", NULL, NULL, NULL, write_seenspell, read_seenspell +}; + +static boolean +already_seen(const faction * f, const spell * sp) +{ + attrib *a; + + for (a = a_find(f->attribs, &at_seenspell); a && a->type==&at_seenspell; a=a->next) { + if (a->data.v==sp) return true; + } + return false; +} + +static boolean know_school(const faction * f, magic_t school) +{ + static int common = MAXMAGIETYP; + if (f->magiegebiet==school) return true; + if (common==MAXMAGIETYP) { + const char * common_school = get_param(global.parameters, "rules.magic.common"); + if (common_school) { + for (common=0;common!=MAXMAGIETYP;++common) { + if (strcmp(common_school, magic_school[common])==0) break; + } + if (common==MAXMAGIETYP) { + common = M_NONE; + } + } else { + return false; + } + } + return school==common; +} + +#define COMMONSPELLS 1 /* number of new common spells per level */ +#define MAXSPELLS 256 + +/** update the spellbook with a new level +* Written for Eressea 1.1 +*/ +void +update_spellbook(faction * f, int level) +{ + spell * commonspells[MAXSPELLS]; + int numspells = 0; + spell_list * slist; + + for (slist=spells;slist!=NULL;slist=slist->next) { + spell * sp = slist->data; + if (sp->magietyp == M_COMMON && level>f->max_spelllevel && sp->level<=level) { + commonspells[numspells++] = sp; + } else { + if (know_school(f, sp->magietyp) && sp->level <= level) { + if (!has_spell(f->spellbook, sp)) { + add_spell(&f->spellbook, sp); + } + } + } + } + while (numspells>0 && level>f->max_spelllevel) { + int i; + for (i=0;i!=COMMONSPELLS;++i) { + int maxspell = numspells; + int spellno = -1; + spell * sp; + do { + if (spellno==maxspell) { + --maxspell; + } + spellno = rng_int() % maxspell; + sp = commonspells[spellno]; + } + while (maxspell>0 && sp && sp->level<=f->max_spelllevel && !has_spell(f->spellbook, sp)); + + if (sp) { + add_spell(&f->spellbook, sp); + commonspells[spellno] = 0; + } + } + ++f->max_spelllevel; + } +} + +void +updatespelllist(unit * u) +{ + int sk = eff_skill(u, SK_MAGIC, u->region); + spell_list * slist = spells; + struct sc_mage * mage = get_mage(u); + boolean ismonster = is_monsters(u->faction); + + if (mage->magietyp==M_GRAY) { + /* Magier mit M_GRAY bekommen weder Sprüche angezeigt noch + * neue Sprüche in ihre List-of-known-spells. Das sind zb alle alten + * Drachen, die noch den Skill Magie haben, und alle familiars */ + return; + } + + if (FactionSpells()) { + slist = u->faction->spellbook; + } + + for (;slist!=NULL;slist=slist->next) { + spell * sp = slist->data; + if (sp->level<=sk) { + boolean know = u_hasspell(u, sp); + + if (know || sp->magietyp==M_COMMON || know_school(u->faction, sp->magietyp)) { + faction * f = u->faction; + + if (!know) add_spell(get_spelllist(mage, u->faction), sp); + if (!ismonster && !already_seen(u->faction, sp)) { + a_add(&f->attribs, a_new(&at_reportspell))->data.v = sp; + a_add(&f->attribs, a_new(&at_seenspell))->data.v = sp; + } + } + } + } + +} + +/* ------------------------------------------------------------- */ +/* Erzeugen eines neuen Magiers */ +sc_mage * +create_mage(unit * u, magic_t mtyp) +{ + sc_mage *mage; + attrib *a; + + a = a_find(u->attribs, &at_mage); + if (a!=NULL) { + a_remove(&u->attribs, a); + } + a = a_add(&u->attribs, a_new(&at_mage)); + mage = a->data.v; + + mage->magietyp = mtyp; + return mage; +} + +/* ------------------------------------------------------------- */ +/* Funktionen für die Bearbeitung der List-of-known-spells */ + +void +add_spell(spell_list ** slistp, spell * sp) +{ + if (slistp==NULL) { + log_error(("add_spell: unit is not a mage.\n")); + } else { + spell_list ** slist = spelllist_find(slistp, sp); + if (*slist) { + spell * psp = (*slist)->data; + if (psp==sp) { + log_error(("add_spell: unit already has spell '%s'.\n", sp->sname)); + return; + } + } + spelllist_add(slist, sp); + } +} + +boolean +has_spell(spell_list * slist, const spell * sp) +{ + if (slist!=NULL) { + spell_list * sfind = *spelllist_find(&slist, sp); + return sfind!=NULL && sfind->data==sp; + } + return false; +} + +boolean +u_hasspell(const struct unit *u, const struct spell * sp) +{ + sc_mage * mage = get_mage(u); + if (mage) return has_spell(mage->spells, sp); + return false; +} + +/* ------------------------------------------------------------- */ +/* Eingestellte Kampfzauberstufe ermitteln */ + +int +get_combatspelllevel(const unit *u, int nr) +{ + sc_mage *m = get_mage(u); + + assert(nr < MAXCOMBATSPELLS); + if (m) { + int level = eff_skill(u, SK_MAGIC, u->region); + return MIN(m->combatspells[nr].level, level); + } + return -1; +} + +/* ------------------------------------------------------------- */ +/* Kampfzauber ermitteln, setzen oder löschen */ + +const spell* +get_combatspell(const unit *u, int nr) +{ + sc_mage *m; + + assert(nr < MAXCOMBATSPELLS); + m = get_mage(u); + if (m) { + return m->combatspells[nr].sp; + } else if (u->race->precombatspell != NULL) { + return u->race->precombatspell; + } + + return NULL; +} + +void +set_combatspell(unit *u, spell *sp, struct order * ord, int level) +{ + sc_mage *m = get_mage(u); + int i = -1; + if (!m) return; + + /* knowsspell prüft auf ist_magier, ist_spruch, kennt_spruch */ + if (knowsspell(u->region, u, sp) == false){ + /* Fehler 'Spell not found' */ + cmistake(u, ord, 173, MSG_MAGIC); + return; + } + if (!u_hasspell(u, sp)) { + /* Diesen Zauber kennt die Einheit nicht */ + cmistake(u, ord, 169, MSG_MAGIC); + return; + } + if (!(sp->sptyp & ISCOMBATSPELL)) { + /* Diesen Kampfzauber gibt es nicht */ + cmistake(u, ord, 171, MSG_MAGIC); + return; + } + + if (sp->sptyp & PRECOMBATSPELL) i = 0; + else if (sp->sptyp & COMBATSPELL) i = 1; + else if (sp->sptyp & POSTCOMBATSPELL) i = 2; + assert(i>=0); + m->combatspells[i].sp = sp; + m->combatspells[i].level = level; + return; +} + +void +unset_combatspell(unit *u, spell *sp) +{ + sc_mage *m; + int nr = 0; + int i; + + m = get_mage(u); + if (!m) return; + + if (!sp) { + for (i=0;icombatspells[i].sp = NULL; + } + } + else if (sp->sptyp & PRECOMBATSPELL) { + if (sp != get_combatspell(u,0)) + return; + } else if (sp->sptyp & COMBATSPELL) { + if (sp != get_combatspell(u,1)) { + return; + } + nr = 1; + } else if (sp->sptyp & POSTCOMBATSPELL) { + if (sp != get_combatspell(u,2)) { + return; + } + nr = 2; + } + m->combatspells[nr].sp = NULL; + m->combatspells[nr].level = 0; + return; +} + +/* ------------------------------------------------------------- */ +/* Gibt die aktuelle Anzahl der Magiepunkte der Einheit zurück */ +int +get_spellpoints(const unit * u) +{ + sc_mage *m; + + m = get_mage(u); + if (!m) return 0; + + return m->spellpoints; +} + +void +set_spellpoints(unit * u, int sp) +{ + sc_mage *m; + + m = get_mage(u); + if (!m) return; + + m->spellpoints = sp; + + return; +} + +/* + * verändert die Anzahl der Magiepunkte der Einheit um +mp + */ +int +change_spellpoints(unit * u, int mp) +{ + sc_mage *m; + int sp; + + m = get_mage(u); + if (!m) return 0; + + /* verhindere negative Magiepunkte */ + sp = MAX(m->spellpoints + mp, 0); + m->spellpoints = sp; + + return sp; +} + +/* bietet die Möglichkeit, die maximale Anzahl der Magiepunkte mit + * Regionszaubern oder Attributen zu beinflussen + */ +static int +get_spchange(const unit * u) +{ + sc_mage *m; + + m = get_mage(u); + if (!m) return 0; + + return m->spchange; +} + +/* ein Magier kann normalerweise maximal Stufe^2.1/1.2+1 Magiepunkte + * haben. + * Manche Rassen haben einen zusätzlichen Multiplikator + * Durch Talentverlust (zB Insekten im Berg) können negative Werte + * entstehen + */ + +/* Artefakt der Stärke + * Ermöglicht dem Magier mehr Magiepunkte zu 'speichern' + */ +/** TODO: at_skillmod daraus machen */ +static int +use_item_aura(const region * r, const unit * u) +{ + int sk, n; + + sk = eff_skill(u, SK_MAGIC, r); + n = (int)(sk * sk * u->race->maxaura / 4); + + return n; +} + +int +max_spellpoints(const region * r, const unit * u) +{ + int sk; + double n, msp; + double potenz = 2.1; + double divisor = 1.2; + + sk = eff_skill(u, SK_MAGIC, r); + msp = u->race->maxaura*(pow(sk, potenz)/divisor+1) + get_spchange(u); + + if (get_item(u, I_AURAKULUM) > 0) { + msp += use_item_aura(r, u); + } + n = get_curseeffect(u->attribs, C_AURA, 0); + if (n>0) msp = (msp*n)/100; + + return MAX((int)msp, 0); +} + +int +change_maxspellpoints(unit * u, int csp) +{ + sc_mage *m; + + m = get_mage(u); + if (!m) return 0; + + m->spchange += csp; + return max_spellpoints(u->region, u); +} + +/* ------------------------------------------------------------- */ +/* Counter für die bereits gezauberte Anzahl Sprüche pro Runde. + * Um nur die Zahl der bereits gezauberten Sprüche zu ermitteln mit + * step = 0 aufrufen. + */ +int +countspells(unit *u, int step) +{ + sc_mage *m; + int count; + + m = get_mage(u); + if (!m) + return 0; + + if (step == 0) + return m->spellcount; + + count = m->spellcount + step; + + /* negative Werte abfangen. */ + m->spellcount = MAX(0,count); + + return m->spellcount; +} + +/* ------------------------------------------------------------- */ +/* Die für den Spruch benötigte Aura pro Stufe. + * Die Grundkosten pro Stufe werden hier um 2^count erhöht. Der + * Parameter count ist dabei die Anzahl der bereits gezauberten Sprüche + */ +int +spellcost(unit *u, const spell * sp) +{ + int k, aura = 0; + int count = countspells(u, 0); + + for (k = 0; sp->components[k].type; k++) { + if (sp->components[k].type == r_aura) { + aura = sp->components[k].amount; + } + } + aura *= (1<components[k].type; k++) { + if (costtyp == SPC_LINEAR) return SPC_LINEAR; + + if (sp->components[k].cost == SPC_LINEAR) { + return SPC_LINEAR; + } + + /* wenn keine Fixkosten, Typ übernehmen */ + if (sp->components[k].cost != SPC_FIX) { + costtyp = sp->components[k].cost; + } + } + return costtyp; +} + +/* ------------------------------------------------------------- */ +/* durch Komponenten und cast_level begrenzter maximal möglicher + * Level + * Da die Funktion nicht alle Komponenten durchprobiert sondern beim + * ersten Fehler abbricht, muss die Fehlermeldung später mit cancast() + * generiert werden. + * */ +int +eff_spelllevel(unit *u, const spell * sp, int cast_level, int range) +{ + int k, maxlevel, needplevel; + int costtyp = SPC_FIX; + + for (k = 0; sp->components[k].type; k++) { + if (cast_level == 0) + return 0; + + if (sp->components[k].amount > 0) { + /* Die Kosten für Aura sind auch von der Zahl der bereits + * gezauberten Sprüche abhängig */ + if (sp->components[k].type == r_aura) { + needplevel = spellcost(u, sp) * range; + } else { + needplevel = sp->components[k].amount * range; + } + maxlevel = get_pooled(u, sp->components[k].type, GET_DEFAULT, needplevel*cast_level)/needplevel; + + /* sind die Kosten fix, so muss die Komponente nur einmal vorhanden + * sein und der cast_level ändert sich nicht */ + if (sp->components[k].cost == SPC_FIX) { + if (maxlevel < 1) cast_level = 0; + /* ansonsten wird das Minimum aus maximal möglicher Stufe und der + * gewünschten gebildet */ + } else if (sp->components[k].cost == SPC_LEVEL) { + costtyp = SPC_LEVEL; + cast_level = MIN(cast_level, maxlevel); + /* bei Typ Linear müssen die Kosten in Höhe der Stufe vorhanden + * sein, ansonsten schlägt der Spruch fehl */ + } else if (sp->components[k].cost == SPC_LINEAR) { + costtyp = SPC_LINEAR; + if (maxlevel < cast_level) cast_level = 0; + } + } + } + /* Ein Spruch mit Fixkosten wird immer mit der Stufe des Spruchs und + * nicht auf der Stufe des Magiers gezaubert */ + if (costtyp == SPC_FIX) { + cast_level = MIN(cast_level, sp->level); + } + + return cast_level; +} + +/* ------------------------------------------------------------- */ +/* Die Spruchgrundkosten werden mit der Entfernung (Farcasting) + * multipliziert, wobei die Aurakosten ein Sonderfall sind, da sie sich + * auch durch die Menge der bereits gezauberten Sprüche erhöht. + * Je nach Kostenart werden dann die Komponenten noch mit cast_level + * multipliziert. + */ +void +pay_spell(unit * u, const spell * sp, int cast_level, int range) +{ + int k; + int resuse; + + for (k = 0; sp->components[k].type; k++) { + if (sp->components[k].type == r_aura) { + resuse = spellcost(u, sp) * range; + } else { + resuse = sp->components[k].amount * range; + } + + if (sp->components[k].cost == SPC_LINEAR + || sp->components[k].cost == SPC_LEVEL) + { + resuse *= cast_level; + } + + use_pooled(u, sp->components[k].type, GET_DEFAULT, resuse); + } +} + + +/* ------------------------------------------------------------- */ +/* Ein Magier kennt den Spruch und kann sich die Beschreibung anzeigen + * lassen, wenn diese in seiner Spruchliste steht. Zaubern muss er ihn + * aber dann immer noch nicht können, vieleicht ist seine Stufe derzeit + * nicht ausreichend oder die Komponenten fehlen. + */ +boolean +knowsspell(const region * r, const unit * u, const spell * sp) +{ + sc_mage * mage; + /* Ist überhaupt ein gültiger Spruch angegeben? */ + if (!sp || sp->id == 0) { + return false; + } + /* Magier? */ + mage = get_mage(u); + if (mage == NULL) { + log_warning(("%s ist kein Magier, versucht aber zu zaubern.\n", + unitname(u))); + return false; + } + /* steht der Spruch in der Spruchliste? */ + if (!u_hasspell(u, sp)) { + /* ist der Spruch aus einem anderen Magiegebiet? */ + if (know_school(u->faction, sp->magietyp)) { + return false; + } + if (eff_skill(u, SK_MAGIC, u->region) >= sp->level) { + log_warning(("%s ist hat die erforderliche Stufe, kennt aber %s nicht.\n", + unitname(u), spell_name(sp, default_locale))); + } + return false; + } + + /* hier sollten alle potentiellen Fehler abgefangen sein */ + return true; +} + +/* Um einen Spruch zu beherrschen, muss der Magier die Stufe des + * Spruchs besitzen, nicht nur wissen, das es ihn gibt (also den Spruch + * in seiner Spruchliste haben). + * Kosten für einen Spruch können Magiepunkte, Silber, Kraeuter + * und sonstige Gegenstaende sein. + */ + +boolean +cancast(unit * u, const spell * sp, int level, int range, struct order * ord) +{ + int k; + int itemanz; + resource * reslist = NULL; + + if (knowsspell(u->region, u, sp) == false) { + /* Diesen Zauber kennt die Einheit nicht */ + cmistake(u, ord, 173, MSG_MAGIC); + return false; + } + /* reicht die Stufe aus? */ + if (eff_skill(u, SK_MAGIC, u->region) < sp->level) { + /* die Einheit ist nicht erfahren genug für diesen Zauber */ + cmistake(u, ord, 169, MSG_MAGIC); + return false; + } + + for (k = 0; sp->components[k].type; ++k) { + if (sp->components[k].amount > 0) { + const resource_type * rtype = sp->components[k].type; + int itemhave; + + /* Die Kosten für Aura sind auch von der Zahl der bereits + * gezauberten Sprüche abhängig */ + if (rtype == r_aura) { + itemanz = spellcost(u, sp) * range; + } else { + itemanz = sp->components[k].amount * range; + } + + /* sind die Kosten stufenabhängig, so muss itemanz noch mit dem + * level multipliziert werden */ + switch(sp->components[k].cost) { + case SPC_LEVEL: + case SPC_LINEAR: + itemanz *= level; + break; + case SPC_FIX: + default: + break; + } + + itemhave = get_pooled(u, rtype, GET_DEFAULT, itemanz); + if (itemhave < itemanz) { + resource * res = malloc(sizeof(resource)); + res->number = itemanz-itemhave; + res->type = rtype; + res->next = reslist; + reslist = res; + } + } + } + if (reslist!=NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "missing_components_list", "list", reslist)); + return false; + } + return true; +} + +/* ------------------------------------------------------------- */ +/* generische Spruchstaerke, + * + * setzt sich derzeit aus der Stufe des Magiers, Magieturmeffekt, + * Spruchitems und Antimagiefeldern zusammen. Es koennen noch die + * Stufe des Spruchs und Magiekosten mit einfliessen. + * + * Die effektive Spruchstärke und ihre Auswirkungen werden in der + * Spruchfunktionsroutine ermittelt. + */ + +double +spellpower(region * r, unit * u, const spell * sp, int cast_level, struct order * ord) +{ + curse * c; + double force = cast_level; + int elf_power = -1; + + if (sp==NULL) { + return 0; + } else { + /* Bonus durch Magieturm und gesegneten Steinkreis */ + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + if (btype && btype->flags & BTF_MAGIC) ++force; + } + + if (get_item(u, I_RING_OF_POWER) > 0) ++force; + if (elf_power<0) { + elf_power = get_param_int(global.parameters, "rules.magic.elfpower", 0); + } + if (elf_power && u->race==new_race[RC_ELF] && r_isforest(r)) { + ++force; + } + + /* Antimagie in der Zielregion */ + c = get_curse(r->attribs, ct_find("antimagiczone")); + if (curse_active(c)) { + unit * mage = c->magician; + force -= curse_geteffect(c); + curse_changevigour(&r->attribs, c, (float)-cast_level); + cmistake(u, ord, 185, MSG_MAGIC); + if (mage!=NULL && mage->faction!=NULL) { + if (force>0) { + ADDMSG(&mage->faction->msgs, msg_message("reduce_spell", "self mage region", mage, u, r)); + } else { + ADDMSG(&mage->faction->msgs, msg_message("block_spell", "self mage region", mage, u, r)); + } + } + } + + /* Patzerfluch-Effekt: */ + c = get_curse(r->attribs, ct_find("fumble")); + if (curse_active(c)) { + unit * mage = c->magician; + force -= curse_geteffect(c); + curse_changevigour(&u->attribs, c, -1); + cmistake(u, ord, 185, MSG_MAGIC); + if (mage!=NULL && mage->faction!=NULL) { + if (force>0) { + ADDMSG(&mage->faction->msgs, msg_message("reduce_spell", "self mage region", mage, u, r)); + } else { + ADDMSG(&mage->faction->msgs, msg_message("block_spell", "self mage region", mage, u, r)); + } + } + } + + force = force * MagicPower(); + + return MAX(force, 0); +} + +/* ------------------------------------------------------------- */ +/* farcasting() == 1 -> gleiche Region, da man mit Null nicht vernünfigt + * rechnen kann */ +static int +farcasting(unit *magician, region *r) +{ + int dist; + int mult; + + if (!r) { + return INT_MAX; + } + + dist = koor_distance(r->x, r->y, magician->region->x, magician->region->y); + + if (dist > 24) return INT_MAX; + + mult = 1 << dist; + if (dist > 1) { + if (!path_exists(magician->region, r, dist*2, allowed_fly)) mult = INT_MAX; + } + + return mult; +} + + +/* ------------------------------------------------------------- */ +/* Antimagie - Magieresistenz */ +/* ------------------------------------------------------------- */ + +/* allgemeine Magieresistenz einer Einheit, + * reduziert magischen Schaden */ +double +magic_resistance(unit *target) +{ + attrib * a; + curse *c; + int n; + + /* Bonus durch Rassenmagieresistenz */ + double probability = target->race->magres; + assert(target->number>0); + + /* Magier haben einen Resistenzbonus vom Magietalent * 5%*/ + probability += effskill(target, SK_MAGIC)*0.05; + + /* Auswirkungen von Zaubern auf der Einheit */ + c = get_curse(target->attribs, ct_find("magicresistance")); + if (c) { + probability += 0.01 * curse_geteffect(c) * get_cursedmen(target, c); + } + + /* Unicorn +10 */ + n = get_item(target, I_ELVENHORSE); + if (n) probability += n*0.1/target->number; + + /* Auswirkungen von Zaubern auf der Region */ + a = a_find(target->region->attribs, &at_curse); + while (a && a->type==&at_curse) { + curse *c = (curse*)a->data.v; + unit *mage = c->magician; + + if (mage!=NULL) { + if (c->type == ct_find("goodmagicresistancezone")) { + if (alliedunit(mage, target->faction, HELP_GUARD)) { + probability += curse_geteffect(c)*0.01; + break; + } + } + else if (c->type == ct_find("badmagicresistancezone")) { + if (alliedunit(mage, target->faction, HELP_GUARD)) { + /* TODO: hier sollte doch sicher was passieren? */ + a = a->next; + continue; + } + } + } + a = a->next; + } + /* Bonus durch Artefakte */ + /* TODO (noch gibs keine)*/ + + /* Bonus durch Gebäude */ + { + struct building * b = inside_building(target); + const struct building_type * btype = b?b->type:NULL; + + /* gesegneter Steinkreis gibt 30% dazu */ + if (btype) probability += btype->magresbonus * 0.01; + } + return probability; +} + +/* ------------------------------------------------------------- */ +/* Prüft, ob das Objekt dem Zauber widerstehen kann. + * Objekte können Regionen, Units, Gebäude oder Schiffe sein. + * TYP_UNIT: + * Das höchste Talent des Ziels ist sein 'Magieresistenz-Talent', Magier + * bekommen einen Bonus. Grundchance ist 50%, für jede Stufe + * Unterschied gibt es 5%, minimalchance ist 5% für jeden (5-95%) + * Scheitert der Spruch an der Magieresistenz, so gibt die Funktion + * true zurück + */ + +boolean +target_resists_magic(unit *magician, void *obj, int objtyp, int t_bonus) +{ + double probability = 0.0; + + if (magician == NULL) return true; + if (obj == NULL) return true; + + switch(objtyp) { + case TYP_UNIT: + { + int at, pa = 0; + skill * sv; + unit * u = (unit*)obj; + + at = effskill(magician, SK_MAGIC); + + for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { + int sk = effskill(u, sv->id); + if (pa < sk) pa = sk; + } + + /* Contest */ + probability = 0.05 * (10 + pa - at); + + probability += magic_resistance((unit *)obj); + break; + } + + case TYP_REGION: + /* Bonus durch Zauber */ + probability += 0.01 * get_curseeffect(((region *)obj)->attribs, C_RESIST_MAGIC, 0); + break; + + case TYP_BUILDING: + /* Bonus durch Zauber */ + probability += 0.01 * get_curseeffect(((building *)obj)->attribs, C_RESIST_MAGIC, 0); + + /* Bonus durch Typ */ + probability += 0.01 * ((building *)obj)->type->magres; + + break; + + case TYP_SHIP: + /* Bonus durch Zauber */ + probability += 0.01 * get_curseeffect(((ship *)obj)->attribs, C_RESIST_MAGIC, 0); + break; + } + + probability = MAX(0.02, probability + t_bonus*0.01); + probability = MIN(0.98, probability); + + /* gibt true, wenn die Zufallszahl kleiner als die chance ist und + * false, wenn sie gleich oder größer ist, dh je größer die + * Magieresistenz (chance) desto eher gibt die Funktion true zurück */ + return chance(probability); +} + +/* ------------------------------------------------------------- */ + +boolean +is_magic_resistant(unit *magician, unit *target, int resist_bonus) +{ + return (boolean)target_resists_magic(magician, target, TYP_UNIT, resist_bonus); +} + +/* ------------------------------------------------------------- */ +/* Patzer */ +/* ------------------------------------------------------------- */ +/* allgemeine Zauberpatzer: + * Treten auf, wenn die Stufe des Magieres zu niedrig ist. + * Abhaengig von Staerke des Spruchs. + * + * Die Warscheinlichkeit reicht von 20% (beherrscht den Spruch gerade + * eben) bis zu etwa 1% bei doppelt so gut wie notwendig + */ + +boolean +fumble(region * r, unit * u, const spell * sp, int cast_grade) +{ +/* X ergibt Zahl zwischen 1 und 0, je kleiner, desto besser der Magier. + * 0,5*40-20=0, dh wenn der Magier doppelt so gut ist, wie der Spruch + * benötigt, gelingt er immer, ist er gleich gut, gelingt der Spruch mit + * 20% Warscheinlichkeit nicht + * */ + + int rnd = 0; + double x = (double) cast_grade / (double) eff_skill(u, SK_MAGIC, r); + int patzer = (int) (((double) x * 40.0) - 20.0); + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + + if (btype) patzer -= btype->fumblebonus; + /* CHAOSPATZERCHANCE 10 : +10% Chance zu Patzern */ + if (sp->magietyp == M_DRAIG) { + patzer += CHAOSPATZERCHANCE; + } + if (is_cursed(u->attribs, C_MBOOST, 0) == true) { + patzer += CHAOSPATZERCHANCE; + } + if (is_cursed(u->attribs, C_FUMBLE, 0) == true) { + patzer += CHAOSPATZERCHANCE; + } + + /* wenn die Chance kleiner als 0 ist, können wir gleich false + * zurückgeben */ + if (patzer <= 0) { + return false; + } + rnd = rng_int()%100; + + if (rnd > patzer) { + /* Glück gehabt, kein Patzer */ + return false; + } + return true; +} + +/* ------------------------------------------------------------- */ +/* Dummy-Zauberpatzer, Platzhalter für speziel auf die Sprüche +* zugeschnittene Patzer */ +static void +patzer(castorder *co) +{ + unit *mage = co->magician.u; + + cmistake(mage, co->order, 180, MSG_MAGIC); + + return; +} +/* Die normalen Spruchkosten müssen immer bezahlt werden, hier noch + * alle weiteren Folgen eines Patzers + */ + +static void +do_fumble(castorder *co) +{ + curse * c; + region * r = co->rt; + unit * u = co->magician.u; + const spell *sp = co->sp; + int level = co->level; + int duration; + double effect; + + ADDMSG(&u->faction->msgs, msg_message("patzer", "unit region spell", + u, r, sp)); + switch (rng_int() % 10) { + case 0: + /* wenn vorhanden spezieller Patzer, ansonsten nix */ + if (sp->patzer) sp->patzer(co); + else patzer(co); + break; + + case 1: + /* Kröte */ + { + /* 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 triggerlit of the mage gone toad. + */ + trigger * trestore = trigger_changerace(u, u->race, u->irace); + + if (chance(0.7)) { + const item_type * it_toadslime = it_find("toadslime"); + if (it_toadslime!=NULL) { + t_add(&trestore, trigger_giveitem(u, it_toadslime, 1)); + } + } + + duration = rng_int()%level/2; + if (duration<2) duration = 2; + add_trigger(&u->attribs, "timer", trigger_timeout(duration, trestore)); + u->race = new_race[RC_TOAD]; + u->irace = NULL; + ADDMSG(&r->msgs, msg_message("patzer6", "unit region spell", + u, r, sp)); + break; + } + /* fall-through is intentional! */ + + case 2: + /* temporärer Stufenverlust */ + duration = MAX(rng_int()%level/2, 2); + effect = -0.5*level; + c = create_curse(u, &u->attribs, ct_find("skillmod"), (float)level, duration, + effect, 1); + c->data.i = SK_MAGIC; + ADDMSG(&u->faction->msgs, msg_message("patzer2", "unit region", u, r)); + break; + case 3: + case 4: + /* Spruch schlägt fehl, alle Magiepunkte weg */ + set_spellpoints(u, 0); + ADDMSG(&u->faction->msgs, msg_message("patzer3", "unit region spell", + u, r, sp)); + break; + + case 5: + case 6: + /* Spruch gelingt, aber alle Magiepunkte weg */ + if (sp->sp_function==NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + } else { + ((nspell_f)sp->sp_function)(co); + } + set_spellpoints(u, 0); + ADDMSG(&u->faction->msgs, msg_message("patzer4", "unit region spell", + u, r, sp)); + break; + + case 7: + case 8: + case 9: + default: + /* Spruch gelingt, alle nachfolgenden Sprüche werden 2^4 so teuer */ + if (sp->sp_function==NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + } else { + ((nspell_f)sp->sp_function)(co); + } + ADDMSG(&u->faction->msgs, msg_message("patzer5", "unit region spell", + u, r, sp)); + countspells(u, 3); + } + + return; +} + +/* ------------------------------------------------------------- */ +/* Regeneration von Aura */ +/* ------------------------------------------------------------- */ + +/* Ein Magier regeneriert pro Woche W(Stufe^1.5/2+1), mindestens 1 + * Zwerge nur die Hälfte + */ +static double +regeneration(unit * u) +{ + int sk; + double aura, d; + double potenz = 1.5; + double divisor = 2.0; + + sk = effskill(u, SK_MAGIC); + /* Rassenbonus/-malus */ + d = pow(sk, potenz) * u->race->regaura / divisor; + d++; + + /* Einfluss von Artefakten */ + /* TODO (noch gibs keine)*/ + + /* Würfeln */ + aura = (rng_double() * d + rng_double() * d)/2 + 1; + + aura *= MagicRegeneration(); + + return aura; +} + +void +regeneration_magiepunkte(void) +{ + region *r; + unit *u; + int aura, auramax; + double reg_aura; + int regen; + double mod; + + for (r = regions; r; r = r->next) { + for (u = r->units; u; u = u->next) { + if (u->number && is_mage(u)) { + aura = get_spellpoints(u); + auramax = max_spellpoints(r, u); + if (aura < auramax) { + struct building * b = inside_building(u); + const struct building_type * btype = b?b->type:NULL; + reg_aura = regeneration(u); + + /* Magierturm erhöht die Regeneration um 75% */ + /* Steinkreis erhöht die Regeneration um 50% */ + if (btype) reg_aura *= btype->auraregen; + + /* Bonus/Malus durch Zauber */ + mod = get_curseeffect(u->attribs, C_AURA, 0); + if (mod>0) { + reg_aura = (reg_aura*mod)/100.0; + } + + /* Einfluss von Artefakten */ + /* TODO (noch gibs keine)*/ + + /* maximal Differenz bis Maximale-Aura regenerieren + * mindestens 1 Aura pro Monat */ + regen = (int)reg_aura; + reg_aura -= regen; + if (chance(reg_aura)) ++regen; + regen = MAX(1, regen); + regen = MIN((auramax - aura), regen); + + aura += regen; + ADDMSG(&u->faction->msgs, msg_message( + "regenaura", "unit region amount", + u, r, regen)); + } + set_spellpoints(u, MIN(aura, auramax)); + + /* Zum letzten Mal Spruchliste aktualisieren */ + /*updatespelllist(u);*/ + } + } + } +} + +static boolean +verify_ship(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) +{ + ship *sh = findship(spobj->data.i); + + if (sh!=NULL && sh->region!=r && (sp->sptyp & SEARCHLOCAL)) { + /* Burg muss in gleicher Region sein */ + sh = NULL; + } + + if (sh==NULL) { + /* Burg nicht gefunden */ + spobj->flag = TARGET_NOTFOUND; + ADDMSG(&mage->faction->msgs, msg_message("spellshipnotfound", + "unit region command id", mage, mage->region, ord, spobj->data.i)); + return false; + } + spobj->flag = 0; + spobj->data.sh = sh; + return true; +} + +static boolean +verify_building(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) +{ + building *b = findbuilding(spobj->data.i); + + if (b!=NULL && b->region!=r && (sp->sptyp & SEARCHLOCAL)) { + /* Burg muss in gleicher Region sein */ + b = NULL; + } + + if (b==NULL) { + /* Burg nicht gefunden */ + spobj->flag = TARGET_NOTFOUND; + ADDMSG(&mage->faction->msgs, msg_message("spellbuildingnotfound", + "unit region command id", mage, mage->region, ord, spobj->data.i)); + return false; + } + spobj->flag = 0; + spobj->data.b = b; + return true; +} + +message * +msg_unitnotfound(const struct unit * mage, struct order * ord, const struct spllprm * spobj) +{ + /* Einheit nicht gefunden */ + char tbuf[20]; + const char * uid; + + if (spobj->typ==SPP_UNIT) { + uid = itoa36(spobj->data.i); + } else { + sprintf(tbuf, "%s %s", LOC(mage->faction->locale, + parameters[P_TEMP]), itoa36(spobj->data.i)); + uid = tbuf; + } + return msg_message("unitnotfound_id", + "unit region command id", mage, mage->region, ord, uid); +} + +static boolean +verify_unit(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) +{ + unit *u = NULL; + switch (spobj->typ) { + case SPP_UNIT: + u = findunit(spobj->data.i); + break; + case SPP_TEMP: + u = findnewunit(r, mage->faction, spobj->data.i); + if (u==NULL) u = findnewunit(mage->region, mage->faction, spobj->data.i); + break; + default: + assert(!"shouldn't happen, this"); + } + if (u!=NULL && (sp->sptyp & SEARCHLOCAL)) { + if (u->region!=r) u = NULL; + else if (sp->sptyp & TESTCANSEE) { + if (!cansee(mage->faction, r, u, 0) && !ucontact(u, mage)) { + u = NULL; + } + } + } + + if (u==NULL) { + /* Einheit nicht gefunden */ + spobj->flag = TARGET_NOTFOUND; + ADDMSG(&mage->faction->msgs, msg_unitnotfound(mage, ord, spobj)); + return false; + } + /* Einheit wurde gefunden, pointer setzen */ + spobj->flag = 0; + spobj->data.u = u; + return true; +} + +/* ------------------------------------------------------------- */ +/* Zuerst wird versucht alle noch nicht gefundenen Objekte zu finden + * oder zu prüfen, ob das gefundene Objekt wirklich hätte gefunden + * werden dürfen (nicht alle Zauber wirken global). Dabei zählen wir die + * Misserfolge (failed). + * Dann folgen die Tests der gefundenen Objekte auf Magieresistenz und + * Sichtbarkeit. Dabei zählen wir die magieresistenten (resists) + * Objekte. Alle anderen werten wir als Erfolge (success) */ + +/* gibt bei Misserfolg 0 zurück, bei Magieresistenz zumindeste eines + * Objektes 1 und bei Erfolg auf ganzer Linie 2 */ +static void +verify_targets(castorder *co, int * invalid, int * resist, int * success) +{ + unit *mage = co->magician.u; + const spell *sp = co->sp; + region *target_r = co->rt; + spellparameter *sa = co->par; + int i; + + *invalid = 0; + *resist = 0; + *success = 0; + + if (sa && sa->length) { + /* zuerst versuchen wir vorher nicht gefundene Objekte zu finden. + * Wurde ein Objekt durch globalsuche gefunden, obwohl der Zauber + * gar nicht global hätte suchen dürften, setzen wir das Objekt + * zurück. */ + for (i=0;ilength;i++) { + spllprm * spobj = sa->param[i]; + + switch(spobj->typ) { + case SPP_TEMP: + case SPP_UNIT: + if (!verify_unit(target_r, mage, sp, spobj, co->order)) ++*invalid; + break; + case SPP_BUILDING: + if (!verify_building(target_r, mage, sp, spobj, co->order)) ++*invalid; + break; + case SPP_SHIP: + if (!verify_ship(target_r, mage, sp, spobj, co->order)) ++*invalid; + break; + default: + break; + } + } + + /* Nun folgen die Tests auf cansee und Magieresistenz */ + for (i=0;ilength;i++) { + spllprm * spobj = sa->param[i]; + unit * u; + building * b; + ship * sh; + region * tr; + + if (spobj->flag == TARGET_NOTFOUND) continue; + switch(spobj->typ) { + case SPP_TEMP: + case SPP_UNIT: + u = spobj->data.u; + + if ((sp->sptyp & TESTRESISTANCE) + && target_resists_magic(mage, u, TYP_UNIT, 0)) + { + /* Fehlermeldung */ + spobj->data.i = u->no; + spobj->flag = TARGET_RESISTS; + ++*resist; + ADDMSG(&mage->faction->msgs, msg_message("spellunitresists", + "unit region command target", + mage, mage->region, co->order, u)); + break; + } + + /* TODO: Test auf Parteieigenschaft Magieresistsenz */ + ++*success; + break; + case SPP_BUILDING: + b = spobj->data.b; + + if ((sp->sptyp & TESTRESISTANCE) + && target_resists_magic(mage, b, TYP_BUILDING, 0)) + { /* Fehlermeldung */ + spobj->data.i = b->no; + spobj->flag = TARGET_RESISTS; + ++*resist; + ADDMSG(&mage->faction->msgs, msg_message("spellbuildingresists", + "unit region command id", + mage, mage->region, co->order, spobj->data.i)); + break; + } + ++*success; + break; + case SPP_SHIP: + sh = spobj->data.sh; + + if ((sp->sptyp & TESTRESISTANCE) + && target_resists_magic(mage, sh, TYP_SHIP, 0)) + { /* Fehlermeldung */ + spobj->data.i = sh->no; + spobj->flag = TARGET_RESISTS; + ++*resist; + ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + "spellshipresists", "ship", sh)); + break; + } + ++*success; + break; + + case SPP_REGION: + /* haben wir ein Regionsobjekt, dann wird auch dieses und + nicht target_r überprüft. */ + tr = spobj->data.r; + + if ((sp->sptyp & TESTRESISTANCE) + && target_resists_magic(mage, tr, TYP_REGION, 0)) + { /* Fehlermeldung */ + spobj->flag = TARGET_RESISTS; + ++*resist; + ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", + "unit region command", mage, mage->region, co->order)); + break; + } + ++*success; + break; + case SPP_INT: + case SPP_STRING: + ++*success; + break; + + default: + break; + } + } + } else { + /* der Zauber hat keine expliziten Parameter/Ziele, es kann sich + * aber um einen Regionszauber handeln. Wenn notwendig hier die + * Magieresistenz der Region prüfen. */ + if ((sp->sptyp & REGIONSPELL)) { + /* Zielobjekt Region anlegen */ + spllprm * spobj = malloc(sizeof(spllprm)); + spobj->flag = 0; + spobj->typ = SPP_REGION; + spobj->data.r = target_r; + + sa = calloc(1, sizeof(spellparameter)); + sa->length = 1; + sa->param = calloc(sa->length, sizeof(spllprm *)); + sa->param[0] = spobj; + co->par = sa; + + if ((sp->sptyp & TESTRESISTANCE)) { + if (target_resists_magic(mage, target_r, TYP_REGION, 0)) { + /* Fehlermeldung */ + ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", + "unit region command", mage, mage->region, co->order)); + spobj->flag = TARGET_RESISTS; + ++*resist; + } else { + ++*success; + } + } else { + ++*success; + } + } else { + ++*success; + } + } +} + +/* ------------------------------------------------------------- */ +/* Hilfsstrukturen für ZAUBERE */ +/* ------------------------------------------------------------- */ + +static void +free_spellparameter(spellparameter *pa) +{ + int i; + + /* Elemente free'en */ + for (i=0; i < pa->length; i++) { + + switch(pa->param[i]->typ) { + case SPP_STRING: + free(pa->param[i]->data.s); + break; + default: + break; + } + free(pa->param[i]); + } + + if (pa->param) free(pa->param); + /* struct free'en */ + free(pa); +} + +static int +addparam_string(const char * const param[], spllprm ** spobjp) +{ + spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); + assert(param[0]); + + spobj->flag = 0; + spobj->typ = SPP_STRING; + spobj->data.xs = strdup(param[0]); + return 1; +} + +static int +addparam_int(const char * const param[], spllprm ** spobjp) +{ + spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); + assert(param[0]); + + spobj->flag = 0; + spobj->typ = SPP_INT; + spobj->data.i = atoi((char*)param[0]); + return 1; +} + +static int +addparam_ship(const char * const param[], spllprm ** spobjp) +{ + spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); + int id = atoi36((const char *)param[0]); + + spobj->flag = 0; + spobj->typ = SPP_SHIP; + spobj->data.i = id; + return 1; +} + +static int +addparam_building(const char * const param[], spllprm ** spobjp) +{ + spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); + int id = atoi36((const char *)param[0]); + + spobj->flag = 0; + spobj->typ = SPP_BUILDING; + spobj->data.i = id; + return 1; +} + +static int +addparam_region(const char * const param[], spllprm ** spobjp, const unit * u, order * ord, plane * pl) +{ + assert(param[0]); + if (param[1]==0) { + /* Fehler: Zielregion vergessen */ + cmistake(u, ord, 194, MSG_MAGIC); + return -1; + } else { + int tx = atoi((const char*)param[0]), ty = atoi((const char*)param[1]); + int x = rel_to_abs(pl, u->faction, tx, 0); + int y = rel_to_abs(pl, u->faction, ty, 1); + region *rt; + + pnormalize(&x, &y, pl); + rt = findregion(x,y); + + if (rt!=NULL) { + spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); + + spobj->flag = 0; + spobj->typ = SPP_REGION; + spobj->data.r = rt; + } else { + /* Fehler: Zielregion vergessen */ + cmistake(u, ord, 194, MSG_MAGIC); + return -1; + } + return 2; + } +} + + +static int +addparam_unit(const char * const param[], spllprm ** spobjp, const unit * u, order * ord) +{ + spllprm *spobj; + int i = 0; + sppobj_t otype = SPP_UNIT; + + *spobjp = NULL; + if (findparam(param[0], u->faction->locale)==P_TEMP) { + if (param[1]==NULL) { + /* Fehler: Ziel vergessen */ + cmistake(u, ord, 203, MSG_MAGIC); + return -1; + } + ++i; + otype = SPP_TEMP; + } + + spobj = *spobjp = malloc(sizeof(spllprm)); + spobj->flag = 0; + spobj->typ = otype; + spobj->data.i = atoi36((const char*)param[i]); + + return i+1; +} + +static spellparameter * +add_spellparameter(region *target_r, unit *u, const char *syntax, const char * const param[], int size, struct order * ord) +{ + boolean fail = false; + int i = 0; + int p = 0; + const char * c; + spellparameter *par; + int minlen = 0; + + for (c=syntax;*c!=0;++c) { + /* this makes sure that: + * minlen("kc?") = 0 + * minlen("kc+") = 1 + * minlen("cccc+c?") = 4 + */ + if (*c=='?') --minlen; + else if (*c!='+' && *c!='k') ++minlen; + } + c = syntax; + + /* mindestens ein Ziel (Ziellose Zauber werden nicht + * geparst) */ + if (minlen && size==0) { + /* Fehler: Ziel vergessen */ + cmistake(u, ord, 203, MSG_MAGIC); + return 0; + } + + par = malloc(sizeof(spellparameter)); + par->length = size; + if (!size) { + par->param = NULL; + return par; + } + par->param = malloc(size * sizeof(spllprm *)); + + while (!fail && *c && ifaction->locale); + switch (pword) { + case P_REGION: + spobj = malloc(sizeof(spllprm)); + spobj->flag = 0; + spobj->typ = SPP_REGION; + spobj->data.r = u->region; + j = 0; + ++c; + break; + case P_UNIT: + if (iparam[p++] = spobj; + i += j; + } + } + + /* im Endeffekt waren es evtl. nur p parameter (wegen TEMP) */ + par->length = p; + if (fail || par->lengthmagician.u = u; + corder->familiar = u2; + corder->sp = sp; + corder->level = lev; + corder->force = force; + corder->rt = r; + corder->distance = range; + corder->order = copy_order(ord); + corder->par = p; + + return corder; +} + +/* Hänge c-order co an die letze c-order von cll an */ +void +add_castorder(spellrank *cll, castorder *co) +{ + if (cll->begin==NULL) { + cll->end = &cll->begin; + } + + *cll->end = co; + cll->end = &co->next; + + return; +} + +void +free_castorders(castorder *co) +{ + castorder *co2; + + while (co) { + co2 = co; + co = co->next; + if (co2->par) { + free_spellparameter(co2->par); + } + if (co2->order) free_order(co2->order); + free(co2); + } + return; +} + +/* ------------------------------------------------------------- */ +/*** + ** at_familiarmage + **/ + +typedef struct familiar_data { + unit * mage; + unit * familiar; +} famililar_data; + +boolean +is_familiar(const unit *u) +{ + attrib * a = a_find(u->attribs, &at_familiarmage); + return i2b(a!=NULL); +} + +static void +a_write_unit(const attrib * a, const void * owner, struct storage * store) +{ + unit * u = (unit*)a->data.v; + write_unit_reference(u, store); +} + +static int +sm_familiar(const unit * u, const region * r, skill_t sk, int value) /* skillmod */ +{ + if (sk==SK_MAGIC) return value; + else { + int mod; + unit * familiar = get_familiar(u); + if (familiar==NULL) { + /* the familiar is dead */ + return value; + } + mod = eff_skill(familiar, sk, r)/2; + if (r != familiar->region) { + mod /= distance(r, familiar->region); + } + return value + mod; + } +} + +static 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); + 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; + } + + a = a_find(mage->attribs, &at_familiar); + if (a==NULL) { + a = a_add(&mage->attribs, a_new(&at_familiar)); + a->data.v = familiar; + } else assert(!a->data.v || a->data.v == familiar); + /* 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 assert(!a->data.v || a->data.v == mage); +} + +void +remove_familiar(unit *mage) +{ + attrib *a = a_find(mage->attribs, &at_familiar); + attrib *an; + skillmod_data *smd; + + if (a!=NULL) { + a_remove(&mage->attribs, a); + } + a = a_find(mage->attribs, &at_skillmod); + while (a && a->type==&at_skillmod) { + an = a->next; + smd = (skillmod_data *)a->data.v; + if (smd->special==sm_familiar) a_remove(&mage->attribs, a); + a = an; + } +} + +boolean +create_newfamiliar(unit * mage, unit * familiar) +{ + /* 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); + + 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; + + /* TODO: Diese Attribute beim Tod des Familiars entfernen: */ + /* Wenn der Magier stirbt, dann auch der Vertraute */ + add_trigger(&mage->attribs, "destroy", trigger_killunit(familiar)); + /* 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; +} + +static int +resolve_familiar(variant data, void * addr) +{ + unit * familiar; + int result = resolve_unit(data, &familiar); + if (result==0 && familiar) { + 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; +} + +static int +read_familiar(attrib * a, void * owner, struct storage * store) +{ + int result = read_reference(&a->data.v, store, read_unit_reference, resolve_familiar); + if (result==0 && a->data.v==NULL) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +/* clones */ + +void +create_newclone(unit * mage, unit * clone) +{ + attrib *a; + + a = a_find(mage->attribs, &at_clone); + if (a == NULL) { + a = a_add(&mage->attribs, a_new(&at_clone)); + a->data.v = clone; + } else assert(!a->data.v || a->data.v == clone); + /* TODO: Diese Attribute beim Tod des Klons entfernen: */ + + a = a_find(clone->attribs, &at_clonemage); + if (a == NULL) { + a = a_add(&clone->attribs, a_new(&at_clonemage)); + a->data.v = mage; + } else assert(!a->data.v || a->data.v == mage); + + /* Wenn der Magier stirbt, wird das in destroy_unit abgefangen. + * Kein Trigger, zu kompliziert. */ + + /* Wenn der Klon stirbt, dann bekommt der Magier einen Schock */ + add_trigger(&clone->attribs, "destroy", trigger_clonedied(mage)); +} + +static void +set_clone(unit * mage, unit * clone) +{ + attrib *a; + + a = a_find(mage->attribs, &at_clone); + if (a==NULL) { + a = a_add(&mage->attribs, a_new(&at_clone)); + a->data.v = clone; + } else assert(!a->data.v || a->data.v == clone); + + a = a_find(clone->attribs, &at_clonemage); + if (a==NULL) { + a = a_add(&clone->attribs, a_new(&at_clonemage)); + a->data.v = mage; + } else assert(!a->data.v || a->data.v == mage); +} + +unit * +has_clone(unit *mage) +{ + attrib *a = a_find(mage->attribs, &at_clone); + if(a) return (unit *)a->data.v; + return NULL; +} + +static int +resolve_clone(variant data, void * addr) +{ + unit * clone; + int result = resolve_unit(data, &clone); + if (result==0 && clone) { + 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; +} + +static int +read_clone(attrib * a, void * owner, struct storage * store) +{ + int result = read_reference(&a->data.v, store, read_unit_reference, resolve_clone); + if (result==0 && a->data.v==NULL) { + 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) { + 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; +} + +static int +read_magician(attrib * a, void * owner, struct storage * store) +{ + int result = read_reference(&a->data.v, store, read_unit_reference, resolve_mage); + if (result==0 && a->data.v==NULL) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +static int +age_unit(attrib * a) +/* if unit is gone or dead, remove the attribute */ +{ + unit * u = (unit*)a->data.v; + return (u!=NULL && u->number>0)?AT_AGE_KEEP:AT_AGE_REMOVE; +} + +attrib_type at_familiarmage = { + "familiarmage", + NULL, + NULL, + age_unit, + a_write_unit, + read_magician, + ATF_UNIQUE +}; + +attrib_type at_familiar = { + "familiar", + NULL, + NULL, + age_unit, + a_write_unit, + read_familiar, + ATF_UNIQUE +}; + +attrib_type at_clonemage = { + "clonemage", + NULL, + NULL, + age_unit, + a_write_unit, + read_magician, + ATF_UNIQUE +}; + +attrib_type at_clone = { + "clone", + NULL, + NULL, + age_unit, + a_write_unit, + read_clone, + ATF_UNIQUE +}; + +unit * +get_familiar(const unit *u) +{ + attrib * a = a_find(u->attribs, &at_familiar); + if (a!=NULL) { + unit * u = (unit*)a->data.v; + if (u->number>0) return u; + } + return NULL; +} + +unit * +get_familiar_mage(const unit *u) +{ + attrib * a = a_find(u->attribs, &at_familiarmage); + if (a!=NULL) { + unit * u = (unit*)a->data.v; + if (u->number>0) return u; + } + return NULL; +} + +unit * +get_clone(const unit *u) +{ + attrib * a = a_find(u->attribs, &at_clone); + if (a!=NULL) { + unit * u = (unit*)a->data.v; + if (u->number>0) return u; + } + return NULL; +} + +unit * +get_clone_mage(const unit *u) +{ + attrib * a = a_find(u->attribs, &at_clonemage); + if (a!=NULL) { + unit * u = (unit*)a->data.v; + if (u->number>0) return u; + } + return NULL; +} + +static boolean +is_moving_ship(const region * r, const ship *sh) +{ + const unit *u = shipowner(sh); + + if (u) switch (get_keyword(u->thisorder)) { + case K_ROUTE: + case K_MOVE: + case K_FOLLOW: + return true; + } + return false; +} + +static castorder * +cast_cmd(unit * u, order * ord) +{ + region * r = u->region; + region * target_r = r; + int level, range; + unit *familiar = NULL, *mage = u; + const char * s; + spell * sp; + plane * pl; + spellparameter *args = NULL; + + if (LongHunger(u)) { + cmistake(u, ord, 224, MSG_MAGIC); + return 0; + } + pl = rplane(r); + if (pl && fval(pl, PFL_NOMAGIC)) { + cmistake(u, ord, 269, MSG_MAGIC); + return 0; + } + level = eff_skill(u, SK_MAGIC, r); + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + /* für Syntax ' STUFE x REGION y z ' */ + if (findparam(s, u->faction->locale) == P_LEVEL) { + int p = getint(); + level = MIN(p, level); + if (level < 1) { + /* Fehler "Das macht wenig Sinn" */ + cmistake(u, ord, 10, MSG_MAGIC); + return 0; + } + s = getstrtoken(); + } + if (findparam(s, u->faction->locale) == P_REGION) { + int t_x = getint(); + int t_y = getint(); + plane * pl = getplane(u->region); + t_x = rel_to_abs(pl, u->faction, t_x,0); + t_y = rel_to_abs(pl, u->faction, t_y,1); + pnormalize(&t_x, &t_y, pl); + target_r = findregion(t_x, t_y); + if (!target_r) { + /* Fehler "Die Region konnte nicht verzaubert werden" */ + ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", + "unit region command", mage, mage->region, ord)); + return 0; + } + s = getstrtoken(); + } + /* für Syntax ' REGION x y STUFE z ' + * hier nach REGION nochmal auf STUFE prüfen */ + if (findparam(s, u->faction->locale) == P_LEVEL) { + int p = getint(); + level = MIN(p, level); + if (level < 1) { + /* Fehler "Das macht wenig Sinn" */ + cmistake(u, ord, 10, MSG_MAGIC); + return 0; + } + s = getstrtoken(); + } + if (!s[0] || strlen(s) == 0) { + /* Fehler "Es wurde kein Zauber angegeben" */ + cmistake(u, ord, 172, MSG_MAGIC); + return 0; + } + sp = get_spellfromtoken(u, s, u->faction->locale); + + /* Vertraute können auch Zauber sprechen, die sie selbst nicht + * können. get_spellfromtoken findet aber nur jene Sprüche, die + * die Einheit beherrscht. */ + if (sp == NULL && is_familiar(u)) { + familiar = u; + mage = get_familiar_mage(u); + if (mage!=NULL) sp = get_spellfromtoken(mage, s, mage->faction->locale); + } + + if (sp == NULL) { + /* Fehler 'Spell not found' */ + cmistake(u, ord, 173, MSG_MAGIC); + return 0; + } + /* um testen auf spruchnamen zu unterbinden sollte vor allen + * fehlermeldungen die anzeigen das der magier diesen Spruch + * nur in diese Situation nicht anwenden kann, noch eine + * einfache Sicherheitsprüfung kommen */ + if (!knowsspell(r, u, sp)) { + /* vorsicht! u kann der familiar sein */ + if (!familiar) { + cmistake(u, ord, 173, MSG_MAGIC); + return 0; + } + } + if (sp->sptyp & ISCOMBATSPELL) { + /* Fehler: "Dieser Zauber ist nur im Kampf sinnvoll" */ + cmistake(u, ord, 174, MSG_MAGIC); + return 0; + } + /* Auf dem Ozean Zaubern als quasi-langer Befehl können + * normalerweise nur Meermenschen, ausgenommen explizit als + * OCEANCASTABLE deklarierte Sprüche */ + if (fval(r->terrain, SEA_REGION)) { + if (u->race != new_race[RC_AQUARIAN] + && !fval(u->race, RCF_SWIM) + && !(sp->sptyp & OCEANCASTABLE)) { + /* Fehlermeldung */ + ADDMSG(&u->faction->msgs, msg_message("spellfail_onocean", + "unit region command", u, u->region, ord)); + return 0; + } + /* Auf bewegenden Schiffen kann man nur explizit als + * ONSHIPCAST deklarierte Zauber sprechen */ + } else if (u->ship) { + if (is_moving_ship(r, u->ship)) { + if (!(sp->sptyp & ONSHIPCAST)) { + /* Fehler: "Diesen Spruch kann man nicht auf einem sich + * bewegenden Schiff stehend zaubern" */ + cmistake(u, ord, 175, MSG_MAGIC); + return 0; + } + } + } + /* Farcasting bei nicht farcastbaren Sprüchen abfangen */ + range = farcasting(u, target_r); + if (range > 1) { + if (!(sp->sptyp & FARCASTING)) { + /* Fehler "Diesen Spruch kann man nicht in die Ferne + * richten" */ + cmistake(u, ord, 176, MSG_MAGIC); + return 0; + } + if (range > 1024) { /* (2^10) weiter als 10 Regionen entfernt */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "spellfail::nocontact", + "target", target_r)); + return 0; + } + } + /* Stufenangabe bei nicht Stufenvariierbaren Sprüchen abfangen */ + if (!(sp->sptyp & SPELLLEVEL)) { + int ilevel = eff_skill(u, SK_MAGIC, u->region); + if (ilevel!=level) { + level = ilevel; + ADDMSG(&u->faction->msgs, msg_message("spellfail::nolevel", + "mage region command", u, u->region, ord)); + } + } + /* Vertrautenmagie */ + /* Kennt der Vertraute den Spruch, so zaubert er ganz normal. + * Ansonsten zaubert der Magier durch seinen Vertrauten, dh + * zahlt Komponenten und Aura. Dabei ist die maximale Stufe + * die des Vertrauten! + * Der Spruch wirkt dann auf die Region des Vertrauten und + * gilt nicht als Farcasting. */ + if (familiar || is_familiar(u)) { + if ((sp->sptyp & NOTFAMILIARCAST)) { + /* Fehler: "Diesen Spruch kann der Vertraute nicht zaubern" */ + cmistake(u, ord, 177, MSG_MAGIC); + return 0; + } + if (!knowsspell(r, u, sp)) { /* Magier zaubert durch Vertrauten */ + mage = get_familiar_mage(u); + if (range > 1) { /* Fehler! Versucht zu Farcasten */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_farcast", + "mage", mage)); + return 0; + } + if (distance(mage->region, r) > eff_skill(mage, SK_MAGIC, mage->region)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_toofar", + "mage", mage)); + return 0; + } + /* mage auf magier setzen, level anpassen, range für Erhöhung + * der Spruchkosten nutzen, langen Befehl des Magiers + * löschen, zaubern kann er noch */ + range *= 2; + set_order(&mage->thisorder, NULL); + level = MIN(level, eff_skill(mage, SK_MAGIC, mage->region)/2); + familiar = u; + } + } + /* Weitere Argumente zusammenbasteln */ + if (sp->parameter) { + char ** params = malloc(2*sizeof(char*)); + int p = 0, size = 2; + for (;;) { + s = getstrtoken(); + if (*s==0) break; + if (p+1>=size) { + size*=2; + params = realloc(params, sizeof(char*)*size); + } + params[p++] = strdup(s); + } + params[p] = 0; + args = add_spellparameter(target_r, mage, sp->parameter, (const char * const *)params, p, ord); + for (p=0;params[p];++p) free(params[p]); + free(params); + if (args==NULL) { + /* Syntax war falsch */ + return 0; + } + } + return new_castorder(mage, familiar, sp, target_r, level, 0, range, ord, args); +} + +/* ------------------------------------------------------------- */ +/* Damit man keine Rituale in fremden Gebiet machen kann, diese vor + * Bewegung zaubern. Magier sind also in einem fremden Gebiet eine Runde + * lang verletzlich, da sie es betreten, und angegriffen werden können, + * bevor sie ein Ritual machen können. + * + * Syntax: ZAUBER [REGION X Y] [STUFE ] "Spruchname" [Einheit-1 + * Einheit-2 ..] + * + * Nach Priorität geordnet die Zauber global auswerten. + * + * Die Kosten für Farcasting multiplizieren sich mit der Entfernung, + * cast_level gibt die virtuelle Stufe an, die den durch das Farcasten + * entstandenen Spruchkosten entspricht. Sind die Spruchkosten nicht + * levelabhängig, so sind die Kosten nur von der Entfernung bestimmt, + * die Stärke/Level durch den realen Skill des Magiers + */ + +void +magic(void) +{ + region *r; + int rank; + castorder *co; + spellrank spellranks[MAX_SPELLRANK]; + + memset(spellranks, 0, sizeof(spellranks)); + + for (r = regions; r; r = r->next) { + unit *u; + for (u = r->units; u; u = u->next) { + order * ord; + + if (u->number<=0 || u->race == new_race[RC_SPELL]) + continue; + + if (u->race == new_race[RC_INSECT] && r_insectstalled(r) && + !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) + continue; + + if (fval(u, UFL_WERE|UFL_LONGACTION)) { + continue; + } + + for (ord = u->orders; ord; ord = ord->next) { + if (get_keyword(ord) == K_CAST) { + castorder * co = cast_cmd(u, ord); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + if (co) { + const spell * sp = co->sp; + add_castorder(&spellranks[sp->rank], co); + } + } + } + } + } + + /* Da sich die Aura und Komponenten in der Zwischenzeit verändert + * haben können und sich durch vorherige Sprüche das Zaubern + * erschwert haben kann, muss beim zaubern erneut geprüft werden, ob der + * Spruch überhaupt gezaubert werden kann. + * (level) die effektive Stärke des Spruchs (= Stufe, auf der der + * Spruch gezaubert wird) */ + + for (rank = 0; rank < MAX_SPELLRANK; rank++) { + for (co = spellranks[rank].begin; co; co = co->next) { + order * ord = co->order; + int invalid, resist, success, cast_level = co->level; + boolean fumbled = false; + unit * u = co->magician.u; + const spell *sp = co->sp; + region * target_r = co->rt; + + /* reichen die Komponenten nicht, wird der Level reduziert. */ + co->level = eff_spelllevel(u, sp, cast_level, co->distance); + + if (co->level < 1) { + /* Fehlermeldung mit Komponenten generieren */ + cancast(u, sp, cast_level, co->distance, ord); + continue; + } + + if (cast_level > co->level) { + /* Sprüche mit Fixkosten werden immer auf Stufe des Spruchs + * gezaubert, co->level ist aber defaultmäßig Stufe des Magiers */ + if (spl_costtyp(sp) != SPC_FIX) { + ADDMSG(&u->faction->msgs, msg_message("missing_components", + "unit spell level", u, sp, cast_level)); + } + } + + /* Prüfen, ob die realen Kosten für die gewünschten Stufe bezahlt + * werden können */ + if (cancast(u, sp, co->level, co->distance, ord) == false) { + /* die Fehlermeldung wird in cancast generiert */ + continue; + } + + co->force = spellpower(target_r, u, sp, co->level, ord); + /* die Stärke kann durch Antimagie auf 0 sinken */ + if (co->force <= 0) { + co->force = 0; + ADDMSG(&u->faction->msgs, msg_message("missing_force", + "unit spell level", u, sp, co->level)); + } + + /* Ziele auf Existenz prüfen und Magieresistenz feststellen. Wurde + * kein Ziel gefunden, so ist verify_targets=0. Scheitert der + * Spruch an der Magieresistenz, so ist verify_targets = 1, bei + * Erfolg auf ganzer Linie ist verify_targets= 2 + */ + verify_targets(co, &invalid, &resist, &success); + if (success+resist==0) { + /* kein Ziel gefunden, Fehlermeldungen sind in verify_targets */ + /* keine kosten für den zauber */ + continue; /* äußere Schleife, nächster Zauberer */ + } else if (co->force>0 && resist>0) { + /* einige oder alle Ziele waren magieresistent */ + if (success==0) { + co->force = 0; + /* zwar wurde mindestens ein Ziel gefunden, das widerstand + * jedoch dem Zauber. Kosten abziehen und abbrechen. */ + ADDMSG(&u->faction->msgs, msg_message("spell_resist", "unit region spell", + u, r, sp)); + } + } + + /* Auch für Patzer gibt es Erfahrung, müssen die Spruchkosten + * bezahlt werden und die nachfolgenden Sprüche werden teurer */ + if (co->force>0) { + if (fumble(target_r, u, sp, co->level)) { + /* zuerst bezahlen, dann evt in do_fumble alle Aura verlieren */ + fumbled = true; + } else { + if (sp->sp_function==NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + co->level = 0; + } else { + co->level = ((nspell_f)sp->sp_function)(co); + } + if (co->level <= 0) { + /* Kosten nur für real benötige Stufe berechnen */ + continue; + } + } + } + pay_spell(u, sp, co->level, co->distance); + /* erst bezahlen, dann Kostenzähler erhöhen */ + if (fumbled) do_fumble(co); + countspells(u, 1); + } + } + + /* Sind alle Zauber gesprochen gibts Erfahrung */ + for (r = regions; r; r = r->next) { + unit *u; + for (u = r->units; u; u = u->next) { + if (is_mage(u) && countspells(u, 0) > 0) { + produceexp(u, SK_MAGIC, u->number); + /* Spruchlistenaktualiesierung ist in Regeneration */ + } + } + } + for (rank = 0; rank < MAX_SPELLRANK; rank++) { + free_castorders(spellranks[rank].begin); + } + remove_empty_units(); +} + +const char * +spell_info(const spell * sp, const struct locale * lang) +{ + return LOC(lang, mkname("spellinfo", sp->sname)); +} + +const char * +spell_name(const spell * sp, const struct locale * lang) +{ + return LOC(lang, mkname("spell", sp->sname)); +} + +const char * +curse_name(const curse_type * ctype, const struct locale * lang) +{ + return LOC(lang, mkname("spell", ctype->cname)); +} + +void +spelllist_add(spell_list ** lspells, spell * sp) +{ + spell_list * entry; + + while (*lspells) { + spell_list * slist = *lspells; + if (slist->data->id==sp->id) { + if (slist->data==sp) { + log_error(("trying to add spell '%s' to a list twice.\n", sp->sname)); + return; + } + } + if (slist->data->id>sp->id) break; + lspells = &slist->next; + } + entry = malloc(sizeof(spell_list)); + entry->data = sp; + entry->next = *lspells; + *lspells = entry; +} + +spell_list ** +spelllist_find(spell_list ** lspells, const spell * sp) +{ + while (*lspells) { + spell_list * slist = *lspells; + if (slist->data->id>=sp->id) break; + lspells = &slist->next; + } + return lspells; +} + +extern struct spell_list ** get_spelllist(struct sc_mage * mage, struct faction * f) +{ + if (mage) { + return &mage->spells; + } + return NULL; +} diff --git a/src/kernel/magic.h b/src/kernel/magic.h index ff91341af..623c5f516 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -1,395 +1,395 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_MAGIC -#define H_KRNL_MAGIC -#ifdef __cplusplus -extern "C" { -#endif - -#include "curse.h" -struct fighter; -struct building; - -/* ------------------------------------------------------------- */ - -#define MAXCOMBATSPELLS 3 /* PRECOMBAT COMBAT POSTCOMBAT */ -#define MAX_SPELLRANK 9 /* Standard-Rank 5 */ -#define MAXINGREDIENT 5 /* bis zu 5 Komponenten pro Zauber */ -#define CHAOSPATZERCHANCE 10 /* +10% Chance zu Patzern */ - -/* ------------------------------------------------------------- */ - -#define IRONGOLEM_CRUMBLE 15 /* monatlich Chance zu zerfallen */ -#define STONEGOLEM_CRUMBLE 10 /* monatlich Chance zu zerfallen */ - -/* ------------------------------------------------------------- */ -/* Spruchparameter - * Wir suchen beim Parsen des Befehls erstmal nach lokalen Objekten, - * erst in verify_targets wird dann global gesucht, da in den meisten - * Fällen das Zielobjekt lokal sein dürfte */ - -/* siehe auch typ_t in objtypes.h */ -typedef enum { - SPP_REGION, /* "r" : findregion(x,y) -> *region */ - SPP_UNIT, /* - : atoi36() -> int */ - SPP_TEMP, /* - : temp einheit */ - SPP_BUILDING, /* - : atoi() -> int */ - SPP_SHIP, /* - : atoi() -> int */ - SPP_STRING, /* "c" */ - SPP_INT, /* "i" : atoi() -> int */ -} sppobj_t; - -typedef struct spllprm{ - sppobj_t typ; - int flag; - union { - struct region *r; - struct unit *u; - struct building *b; - struct ship *sh; - char *s; - char * xs; - int i; - } data; -} spllprm; - -typedef struct spellparameter{ - int length; /* Anzahl der Elemente */ - struct spllprm **param; -} spellparameter; - -typedef struct strarray { - int length; /* Anzahl der Elemente */ - char **strings; -} strarray; - -#define TARGET_RESISTS (1<<0) -#define TARGET_NOTFOUND (1<<1) - -/* ------------------------------------------------------------- */ -/* Magierichtungen */ - -/* typedef unsigned char magic_t; */ -enum { - M_GRAY = 0, /* Gray */ - M_ILLAUN = 1, /* Illaun */ - M_TYBIED = 2, /* Tybied */ - M_CERDDOR = 3, /* Cerddor */ - M_GWYRRD = 4, /* Gwyrrd */ - M_DRAIG = 5, /* Draig */ - M_COMMON = 6, /* common spells */ - MAXMAGIETYP, - /* this enum is stored in the datafile, so do not change the numbers around */ - M_NONE = (magic_t) -1 -}; -extern const char *magic_school[MAXMAGIETYP]; - -/* ------------------------------------------------------------- */ -/* Magier: - * - Magierichtung - * - Magiepunkte derzeit - * - Malus (neg. Wert)/ Bonus (pos. Wert) auf maximale Magiepunkte - * (können sich durch Questen absolut verändern und durch Gegenstände - * temporär). Auch für Artefakt benötigt man permanente MP - * - Anzahl bereits gezauberte Sprüche diese Runde - * - Kampfzauber (3) (vor/während/nach) - * - Spruchliste - */ - -typedef struct combatspell { - int level; - const struct spell * sp; -} combatspell; - -typedef struct sc_mage { - magic_t magietyp; - int spellpoints; - int spchange; - int spellcount; - combatspell combatspells[MAXCOMBATSPELLS]; - struct spell_list * spells; -} sc_mage; - -/* ------------------------------------------------------------- */ -/* Zauberliste */ - -typedef struct castorder { - struct castorder *next; - union { - struct unit * u; - struct fighter * fig; - } magician; /* Magier (kann vom Typ struct unit oder fighter sein) */ - struct unit *familiar; /* Vertrauter, gesetzt, wenn der Spruch durch - den Vertrauten gezaubert wird */ - const struct spell *sp; /* Spruch */ - int level; /* gewünschte Stufe oder Stufe des Magiers */ - double force; /* Stärke des Zaubers */ - struct region *rt; /* Zielregion des Spruchs */ - int distance; /* Entfernung zur Zielregion */ - struct order * order; /* Befehl */ - struct spellparameter *par; /* für weitere Parameter */ -} castorder; - -/* irgendwelche zauber: */ -typedef void (*spell_f) (void*); -/* normale zauber: */ -typedef int (*nspell_f)(castorder*); -/* kampfzauber: */ -typedef int (*cspell_f) (struct fighter*, int, double, const struct spell * sp); -/* zauber-patzer: */ -typedef void (*pspell_f) (castorder *); - -typedef struct spell_component { - const struct resource_type * type; - int amount; - int cost; -} spell_component; - -typedef struct spell { - spellid_t id; - char *sname; - char *syntax; - char *parameter; - magic_t magietyp; - int sptyp; - int rank; /* Reihenfolge der Zauber */ - int level; /* Stufe des Zaubers */ - struct spell_component * components; - spell_f sp_function; - void (*patzer) (castorder*); -} spell; - -typedef struct spell_list { - struct spell_list * next; - spell * data; /* TODO: should be const */ -} spell_list; - -extern void spelllist_add(spell_list ** lspells, struct spell * sp); -extern spell_list ** spelllist_find(spell_list ** lspells, const struct spell * sp); -/* ------------------------------------------------------------- */ - -/* besondere Spruchtypen */ -#define FARCASTING (1<<0) /* ZAUBER [struct region x y] */ -#define SPELLLEVEL (1<<1) /* ZAUBER [STUFE x] */ - -/* ID's können zu drei unterschiedlichen Entitäten gehören: Einheiten, - * Gebäuden und Schiffen. */ -#define UNITSPELL (1<<2) /* ZAUBER .. [ ..] */ -#define SHIPSPELL (1<<3) /* ZAUBER .. [ ..] */ -#define BUILDINGSPELL (1<<4) /* ZAUBER .. [ ..] */ -#define REGIONSPELL (1<<5) /* wirkt auf struct region */ - -#define PRECOMBATSPELL (1<<7) /* PRÄKAMPFZAUBER .. */ -#define COMBATSPELL (1<<8) /* KAMPFZAUBER .. */ -#define POSTCOMBATSPELL (1<<9) /* POSTKAMPFZAUBER .. */ -#define ISCOMBATSPELL (PRECOMBATSPELL|COMBATSPELL|POSTCOMBATSPELL) - -#define OCEANCASTABLE (1<<10) /* Können auch nicht-Meermenschen auf - hoher See zaubern */ -#define ONSHIPCAST (1<<11) /* kann auch auf von Land ablegenden - Schiffen stehend gezaubert werden */ -/* */ -#define NOTFAMILIARCAST (1<<12) -#define TESTRESISTANCE (1<<13) /* alle Zielobjekte (u, s, b, r) auf - Magieresistenz prüfen */ -#define SEARCHLOCAL (1<<14) /* Ziel muss in der target_region sein */ -#define TESTCANSEE (1<<15) /* alle Zielunits auf cansee prüfen */ -#define ANYTARGET (UNITSPELL|REGIONSPELL|BUILDINGSPELL|SHIPSPELL) /* wirkt auf alle objekttypen (unit, ship, building, region) */ - -/* Flag Spruchkostenberechnung: */ -enum{ - SPC_FIX, /* Fixkosten */ - SPC_LEVEL, /* Komponenten pro Level */ - SPC_LINEAR /* Komponenten pro Level und müssen vorhanden sein */ -}; - -enum { - RS_DUMMY, - RS_FARVISION, - MAX_REGIONSPELLS -}; - -/* ------------------------------------------------------------- */ -/* Prototypen */ - -void magic(void); - -void regeneration_magiepunkte(void); - -extern struct attrib_type at_seenspell; -extern struct attrib_type at_mage; -extern struct attrib_type at_familiarmage; -extern struct attrib_type at_familiar; -extern struct attrib_type at_clonemage; -extern struct attrib_type at_clone; -extern struct attrib_type at_reportspell; -extern struct attrib_type at_icastle; - -typedef struct icastle_data { - const struct building_type * type; - struct building * building; /* reverse pointer to dissolve the object */ - int time; -} icastle_data; - - -/* ------------------------------------------------------------- */ -/* Kommentare: - * - * Spruchzauberrei und Gegenstandszauberrei werden getrennt behandelt. - * Das macht u.a. bestimmte Fehlermeldungen einfacher, das - * identifizieren der Komponennten über den Missversuch ist nicht - * möglich - * Spruchzauberrei: 'ZAUBER [struct region x y] [STUFE a] "Spruchname" [Ziel]' - * Gegenstandszauberrei: 'BENUTZE "Gegenstand" [Ziel]' - * - * Die Funktionen: - */ - -/* Magier */ -sc_mage * create_mage(struct unit *u, magic_t mtyp); - /* macht die struct unit zu einem neuen Magier: legt die struct u->mage an - * und initialisiert den Magiertypus mit mtyp. */ -sc_mage * get_mage(const struct unit *u); - /* gibt u->mage zurück, bei nicht-Magiern *NULL */ -boolean is_mage(const struct unit *u); - /* gibt true, wenn u->mage gesetzt. */ -boolean is_familiar(const struct unit *u); - /* gibt true, wenn eine Familiar-Relation besteht. */ - -/* Sprüche */ -int get_combatspelllevel(const struct unit *u, int nr); - /* versucht, eine eingestellte maximale Kampfzauberstufe - * zurückzugeben. 0 = Maximum, -1 u ist kein Magier. */ -const spell *get_combatspell(const struct unit *u, int nr); - /* gibt den Kampfzauber nr [pre/kampf/post] oder NULL zurück */ -void set_combatspell(struct unit *u, spell *sp, struct order * ord, int level); - /* setzt Kampfzauber */ -void unset_combatspell(struct unit *u, spell *sp); - /* löscht Kampfzauber */ -void add_spell(spell_list ** slistp, spell *sp); - /* fügt den Spruch mit der Id spellid der Spruchliste der Einheit hinzu. */ -boolean has_spell(struct spell_list *slist, const struct spell * sp); - /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ -boolean u_hasspell(const struct unit * u, const struct spell * sp); - /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ -void update_spellbook(struct faction * f, int level); -void updatespelllist(struct unit *u); - /* fügt alle Zauber des Magiegebietes der Einheit, deren Stufe kleiner - * als das aktuelle Magietalent ist, in die Spruchliste der Einheit - * ein */ -boolean knowsspell(const struct region * r, const struct unit * u, const spell * sp); - /* prüft, ob die Einheit diesen Spruch gerade beherrscht, dh - * mindestens die erforderliche Stufe hat. Hier können auch Abfragen - * auf spezielle Antimagiezauber auf Regionen oder Einheiten eingefügt - * werden - */ - - -/* Magiepunkte */ -int get_spellpoints(const struct unit *u); - /* Gibt die aktuelle Anzahl der Magiepunkte der Einheit zurück */ -void set_spellpoints(struct unit * u, int sp); - /* setzt die Magiepunkte auf sp */ -int change_spellpoints(struct unit *u, int mp); - /* verändert die Anzahl der Magiepunkte der Einheit um +mp */ -int max_spellpoints(const struct region *r, const struct unit *u); - /* gibt die aktuell maximal möglichen Magiepunkte der Einheit zurück */ -int change_maxspellpoints(struct unit * u, int csp); - /* verändert die maximalen Magiepunkte einer Einheit */ - -/* Zaubern */ -extern double spellpower(struct region *r, struct unit *u, const spell *sp, int cast_level, struct order * ord); - /* ermittelt die Stärke eines Spruchs */ -boolean fumble (struct region *r, struct unit *u, const spell *sp, int cast_level); - /* true, wenn der Zauber misslingt, bei false gelingt der Zauber */ - - -typedef struct spellrank { - struct castorder * begin; - struct castorder ** end; -} spellrank; - -castorder *new_castorder(void *u, struct unit *familiar, const spell *sp, struct region *r, - int lev, double force, int distance, struct order * ord, spellparameter *p); - /* Zwischenspreicher für Zauberbefehle, notwendig für Prioritäten */ -void add_castorder(struct spellrank *cll, struct castorder *co); - /* Hänge c-order co an die letze c-order von cll an */ -void free_castorders(struct castorder *co); - /* Speicher wieder freigeben */ - -/* Prüfroutinen für Zaubern */ -int countspells(struct unit *u, int step); - /* erhöht den Counter für Zaubersprüche um 'step' und gibt die neue - * Anzahl der gezauberten Sprüche zurück. */ -int spellcost(struct unit *u, const spell *sp); - /* gibt die für diesen Spruch derzeit notwendigen Magiepunkte auf der - * geringstmöglichen Stufe zurück, schon um den Faktor der bereits - * zuvor gezauberten Sprüche erhöht */ -boolean cancast (struct unit *u, const spell *spruch, int eff_stufe, int distance, struct order * ord); - /* true, wenn Einheit alle Komponenten des Zaubers (incl. MP) für die - * geringstmögliche Stufe hat und den Spruch beherrscht */ -void pay_spell(struct unit *u, const spell *sp, int eff_stufe, int distance); - /* zieht die Komponenten des Zaubers aus dem Inventory der Einheit - * ab. Die effektive Stufe des gezauberten Spruchs ist wichtig für - * die korrekte Bestimmung der Magiepunktkosten */ -int eff_spelllevel(struct unit *u, const spell * sp, int cast_level, int distance); - /* ermittelt die effektive Stufe des Zaubers. Dabei ist cast_level - * die gewünschte maximale Stufe (im Normalfall Stufe des Magiers, - * bei Farcasting Stufe*2^Entfernung) */ -boolean is_magic_resistant(struct unit *magician, struct unit *target, int - resist_bonus); - /* Mapperfunktion für target_resists_magic() vom Typ struct unit. */ -extern double magic_resistance(struct unit *target); - /* gibt die Chance an, mit der einem Zauber widerstanden wird. Je - * größer, desto resistenter ist da Opfer */ -boolean target_resists_magic(struct unit *magician, void *obj, int objtyp, - int resist_bonus); - /* gibt false zurück, wenn der Zauber gelingt, true, wenn das Ziel - * widersteht */ - - -/* 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 boolean 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); - -extern const char * spell_info(const struct spell * sp, const struct locale * lang); -extern const char * spell_name(const struct spell * sp, const struct locale * lang); -extern const char * curse_name(const struct curse_type * ctype, const struct locale * lang); - -extern struct message * msg_unitnotfound(const struct unit * mage, struct order * ord, const struct spllprm * spobj); -extern int FactionSpells(void); -extern struct spell_list ** get_spelllist(struct sc_mage * mage, struct faction * f); - -extern void write_spelllist(const struct spell_list * slist, struct storage * store); -extern void read_spellist(struct spell_list ** slistp, magic_t mtype, struct storage * store); -extern double MagicPower(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_MAGIC +#define H_KRNL_MAGIC +#ifdef __cplusplus +extern "C" { +#endif + +#include "curse.h" +struct fighter; +struct building; + +/* ------------------------------------------------------------- */ + +#define MAXCOMBATSPELLS 3 /* PRECOMBAT COMBAT POSTCOMBAT */ +#define MAX_SPELLRANK 9 /* Standard-Rank 5 */ +#define MAXINGREDIENT 5 /* bis zu 5 Komponenten pro Zauber */ +#define CHAOSPATZERCHANCE 10 /* +10% Chance zu Patzern */ + +/* ------------------------------------------------------------- */ + +#define IRONGOLEM_CRUMBLE 15 /* monatlich Chance zu zerfallen */ +#define STONEGOLEM_CRUMBLE 10 /* monatlich Chance zu zerfallen */ + +/* ------------------------------------------------------------- */ +/* Spruchparameter + * Wir suchen beim Parsen des Befehls erstmal nach lokalen Objekten, + * erst in verify_targets wird dann global gesucht, da in den meisten + * Fällen das Zielobjekt lokal sein dürfte */ + +/* siehe auch typ_t in objtypes.h */ +typedef enum { + SPP_REGION, /* "r" : findregion(x,y) -> *region */ + SPP_UNIT, /* - : atoi36() -> int */ + SPP_TEMP, /* - : temp einheit */ + SPP_BUILDING, /* - : atoi() -> int */ + SPP_SHIP, /* - : atoi() -> int */ + SPP_STRING, /* "c" */ + SPP_INT, /* "i" : atoi() -> int */ +} sppobj_t; + +typedef struct spllprm{ + sppobj_t typ; + int flag; + union { + struct region *r; + struct unit *u; + struct building *b; + struct ship *sh; + char *s; + char * xs; + int i; + } data; +} spllprm; + +typedef struct spellparameter{ + int length; /* Anzahl der Elemente */ + struct spllprm **param; +} spellparameter; + +typedef struct strarray { + int length; /* Anzahl der Elemente */ + char **strings; +} strarray; + +#define TARGET_RESISTS (1<<0) +#define TARGET_NOTFOUND (1<<1) + +/* ------------------------------------------------------------- */ +/* Magierichtungen */ + +/* typedef unsigned char magic_t; */ +enum { + M_GRAY = 0, /* Gray */ + M_ILLAUN = 1, /* Illaun */ + M_TYBIED = 2, /* Tybied */ + M_CERDDOR = 3, /* Cerddor */ + M_GWYRRD = 4, /* Gwyrrd */ + M_DRAIG = 5, /* Draig */ + M_COMMON = 6, /* common spells */ + MAXMAGIETYP, + /* this enum is stored in the datafile, so do not change the numbers around */ + M_NONE = (magic_t) -1 +}; +extern const char *magic_school[MAXMAGIETYP]; + +/* ------------------------------------------------------------- */ +/* Magier: + * - Magierichtung + * - Magiepunkte derzeit + * - Malus (neg. Wert)/ Bonus (pos. Wert) auf maximale Magiepunkte + * (können sich durch Questen absolut verändern und durch Gegenstände + * temporär). Auch für Artefakt benötigt man permanente MP + * - Anzahl bereits gezauberte Sprüche diese Runde + * - Kampfzauber (3) (vor/während/nach) + * - Spruchliste + */ + +typedef struct combatspell { + int level; + const struct spell * sp; +} combatspell; + +typedef struct sc_mage { + magic_t magietyp; + int spellpoints; + int spchange; + int spellcount; + combatspell combatspells[MAXCOMBATSPELLS]; + struct spell_list * spells; +} sc_mage; + +/* ------------------------------------------------------------- */ +/* Zauberliste */ + +typedef struct castorder { + struct castorder *next; + union { + struct unit * u; + struct fighter * fig; + } magician; /* Magier (kann vom Typ struct unit oder fighter sein) */ + struct unit *familiar; /* Vertrauter, gesetzt, wenn der Spruch durch + den Vertrauten gezaubert wird */ + const struct spell *sp; /* Spruch */ + int level; /* gewünschte Stufe oder Stufe des Magiers */ + double force; /* Stärke des Zaubers */ + struct region *rt; /* Zielregion des Spruchs */ + int distance; /* Entfernung zur Zielregion */ + struct order * order; /* Befehl */ + struct spellparameter *par; /* für weitere Parameter */ +} castorder; + +/* irgendwelche zauber: */ +typedef void (*spell_f) (void*); +/* normale zauber: */ +typedef int (*nspell_f)(castorder*); +/* kampfzauber: */ +typedef int (*cspell_f) (struct fighter*, int, double, const struct spell * sp); +/* zauber-patzer: */ +typedef void (*pspell_f) (castorder *); + +typedef struct spell_component { + const struct resource_type * type; + int amount; + int cost; +} spell_component; + +typedef struct spell { + spellid_t id; + char *sname; + char *syntax; + char *parameter; + magic_t magietyp; + int sptyp; + int rank; /* Reihenfolge der Zauber */ + int level; /* Stufe des Zaubers */ + struct spell_component * components; + spell_f sp_function; + void (*patzer) (castorder*); +} spell; + +typedef struct spell_list { + struct spell_list * next; + spell * data; /* TODO: should be const */ +} spell_list; + +extern void spelllist_add(spell_list ** lspells, struct spell * sp); +extern spell_list ** spelllist_find(spell_list ** lspells, const struct spell * sp); +/* ------------------------------------------------------------- */ + +/* besondere Spruchtypen */ +#define FARCASTING (1<<0) /* ZAUBER [struct region x y] */ +#define SPELLLEVEL (1<<1) /* ZAUBER [STUFE x] */ + +/* ID's können zu drei unterschiedlichen Entitäten gehören: Einheiten, + * Gebäuden und Schiffen. */ +#define UNITSPELL (1<<2) /* ZAUBER .. [ ..] */ +#define SHIPSPELL (1<<3) /* ZAUBER .. [ ..] */ +#define BUILDINGSPELL (1<<4) /* ZAUBER .. [ ..] */ +#define REGIONSPELL (1<<5) /* wirkt auf struct region */ + +#define PRECOMBATSPELL (1<<7) /* PRÄKAMPFZAUBER .. */ +#define COMBATSPELL (1<<8) /* KAMPFZAUBER .. */ +#define POSTCOMBATSPELL (1<<9) /* POSTKAMPFZAUBER .. */ +#define ISCOMBATSPELL (PRECOMBATSPELL|COMBATSPELL|POSTCOMBATSPELL) + +#define OCEANCASTABLE (1<<10) /* Können auch nicht-Meermenschen auf + hoher See zaubern */ +#define ONSHIPCAST (1<<11) /* kann auch auf von Land ablegenden + Schiffen stehend gezaubert werden */ +/* */ +#define NOTFAMILIARCAST (1<<12) +#define TESTRESISTANCE (1<<13) /* alle Zielobjekte (u, s, b, r) auf + Magieresistenz prüfen */ +#define SEARCHLOCAL (1<<14) /* Ziel muss in der target_region sein */ +#define TESTCANSEE (1<<15) /* alle Zielunits auf cansee prüfen */ +#define ANYTARGET (UNITSPELL|REGIONSPELL|BUILDINGSPELL|SHIPSPELL) /* wirkt auf alle objekttypen (unit, ship, building, region) */ + +/* Flag Spruchkostenberechnung: */ +enum{ + SPC_FIX, /* Fixkosten */ + SPC_LEVEL, /* Komponenten pro Level */ + SPC_LINEAR /* Komponenten pro Level und müssen vorhanden sein */ +}; + +enum { + RS_DUMMY, + RS_FARVISION, + MAX_REGIONSPELLS +}; + +/* ------------------------------------------------------------- */ +/* Prototypen */ + +void magic(void); + +void regeneration_magiepunkte(void); + +extern struct attrib_type at_seenspell; +extern struct attrib_type at_mage; +extern struct attrib_type at_familiarmage; +extern struct attrib_type at_familiar; +extern struct attrib_type at_clonemage; +extern struct attrib_type at_clone; +extern struct attrib_type at_reportspell; +extern struct attrib_type at_icastle; + +typedef struct icastle_data { + const struct building_type * type; + struct building * building; /* reverse pointer to dissolve the object */ + int time; +} icastle_data; + + +/* ------------------------------------------------------------- */ +/* Kommentare: + * + * Spruchzauberrei und Gegenstandszauberrei werden getrennt behandelt. + * Das macht u.a. bestimmte Fehlermeldungen einfacher, das + * identifizieren der Komponennten über den Missversuch ist nicht + * möglich + * Spruchzauberrei: 'ZAUBER [struct region x y] [STUFE a] "Spruchname" [Ziel]' + * Gegenstandszauberrei: 'BENUTZE "Gegenstand" [Ziel]' + * + * Die Funktionen: + */ + +/* Magier */ +sc_mage * create_mage(struct unit *u, magic_t mtyp); + /* macht die struct unit zu einem neuen Magier: legt die struct u->mage an + * und initialisiert den Magiertypus mit mtyp. */ +sc_mage * get_mage(const struct unit *u); + /* gibt u->mage zurück, bei nicht-Magiern *NULL */ +boolean is_mage(const struct unit *u); + /* gibt true, wenn u->mage gesetzt. */ +boolean is_familiar(const struct unit *u); + /* gibt true, wenn eine Familiar-Relation besteht. */ + +/* Sprüche */ +int get_combatspelllevel(const struct unit *u, int nr); + /* versucht, eine eingestellte maximale Kampfzauberstufe + * zurückzugeben. 0 = Maximum, -1 u ist kein Magier. */ +const spell *get_combatspell(const struct unit *u, int nr); + /* gibt den Kampfzauber nr [pre/kampf/post] oder NULL zurück */ +void set_combatspell(struct unit *u, spell *sp, struct order * ord, int level); + /* setzt Kampfzauber */ +void unset_combatspell(struct unit *u, spell *sp); + /* löscht Kampfzauber */ +void add_spell(spell_list ** slistp, spell *sp); + /* fügt den Spruch mit der Id spellid der Spruchliste der Einheit hinzu. */ +boolean has_spell(struct spell_list *slist, const struct spell * sp); + /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ +boolean u_hasspell(const struct unit * u, const struct spell * sp); + /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ +void update_spellbook(struct faction * f, int level); +void updatespelllist(struct unit *u); + /* fügt alle Zauber des Magiegebietes der Einheit, deren Stufe kleiner + * als das aktuelle Magietalent ist, in die Spruchliste der Einheit + * ein */ +boolean knowsspell(const struct region * r, const struct unit * u, const spell * sp); + /* prüft, ob die Einheit diesen Spruch gerade beherrscht, dh + * mindestens die erforderliche Stufe hat. Hier können auch Abfragen + * auf spezielle Antimagiezauber auf Regionen oder Einheiten eingefügt + * werden + */ + + +/* Magiepunkte */ +int get_spellpoints(const struct unit *u); + /* Gibt die aktuelle Anzahl der Magiepunkte der Einheit zurück */ +void set_spellpoints(struct unit * u, int sp); + /* setzt die Magiepunkte auf sp */ +int change_spellpoints(struct unit *u, int mp); + /* verändert die Anzahl der Magiepunkte der Einheit um +mp */ +int max_spellpoints(const struct region *r, const struct unit *u); + /* gibt die aktuell maximal möglichen Magiepunkte der Einheit zurück */ +int change_maxspellpoints(struct unit * u, int csp); + /* verändert die maximalen Magiepunkte einer Einheit */ + +/* Zaubern */ +extern double spellpower(struct region *r, struct unit *u, const spell *sp, int cast_level, struct order * ord); + /* ermittelt die Stärke eines Spruchs */ +boolean fumble (struct region *r, struct unit *u, const spell *sp, int cast_level); + /* true, wenn der Zauber misslingt, bei false gelingt der Zauber */ + + +typedef struct spellrank { + struct castorder * begin; + struct castorder ** end; +} spellrank; + +castorder *new_castorder(void *u, struct unit *familiar, const spell *sp, struct region *r, + int lev, double force, int distance, struct order * ord, spellparameter *p); + /* Zwischenspreicher für Zauberbefehle, notwendig für Prioritäten */ +void add_castorder(struct spellrank *cll, struct castorder *co); + /* Hänge c-order co an die letze c-order von cll an */ +void free_castorders(struct castorder *co); + /* Speicher wieder freigeben */ + +/* Prüfroutinen für Zaubern */ +int countspells(struct unit *u, int step); + /* erhöht den Counter für Zaubersprüche um 'step' und gibt die neue + * Anzahl der gezauberten Sprüche zurück. */ +int spellcost(struct unit *u, const spell *sp); + /* gibt die für diesen Spruch derzeit notwendigen Magiepunkte auf der + * geringstmöglichen Stufe zurück, schon um den Faktor der bereits + * zuvor gezauberten Sprüche erhöht */ +boolean cancast (struct unit *u, const spell *spruch, int eff_stufe, int distance, struct order * ord); + /* true, wenn Einheit alle Komponenten des Zaubers (incl. MP) für die + * geringstmögliche Stufe hat und den Spruch beherrscht */ +void pay_spell(struct unit *u, const spell *sp, int eff_stufe, int distance); + /* zieht die Komponenten des Zaubers aus dem Inventory der Einheit + * ab. Die effektive Stufe des gezauberten Spruchs ist wichtig für + * die korrekte Bestimmung der Magiepunktkosten */ +int eff_spelllevel(struct unit *u, const spell * sp, int cast_level, int distance); + /* ermittelt die effektive Stufe des Zaubers. Dabei ist cast_level + * die gewünschte maximale Stufe (im Normalfall Stufe des Magiers, + * bei Farcasting Stufe*2^Entfernung) */ +boolean is_magic_resistant(struct unit *magician, struct unit *target, int + resist_bonus); + /* Mapperfunktion für target_resists_magic() vom Typ struct unit. */ +extern double magic_resistance(struct unit *target); + /* gibt die Chance an, mit der einem Zauber widerstanden wird. Je + * größer, desto resistenter ist da Opfer */ +boolean target_resists_magic(struct unit *magician, void *obj, int objtyp, + int resist_bonus); + /* gibt false zurück, wenn der Zauber gelingt, true, wenn das Ziel + * widersteht */ + + +/* 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 boolean 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); + +extern const char * spell_info(const struct spell * sp, const struct locale * lang); +extern const char * spell_name(const struct spell * sp, const struct locale * lang); +extern const char * curse_name(const struct curse_type * ctype, const struct locale * lang); + +extern struct message * msg_unitnotfound(const struct unit * mage, struct order * ord, const struct spllprm * spobj); +extern int FactionSpells(void); +extern struct spell_list ** get_spelllist(struct sc_mage * mage, struct faction * f); + +extern void write_spelllist(const struct spell_list * slist, struct storage * store); +extern void read_spellist(struct spell_list ** slistp, magic_t mtype, struct storage * store); +extern double MagicPower(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/message.c b/src/kernel/message.c index 77a892b72..67ccadfa3 100644 --- a/src/kernel/message.c +++ b/src/kernel/message.c @@ -1,283 +1,283 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "message.h" - -/* kernel includes */ -#include "building.h" -#include "faction.h" -#include "item.h" -#include "order.h" -#include "plane.h" -#include "region.h" -#include "unit.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include - -typedef struct msg_setting { - struct msg_setting *next; - const struct message_type *type; - int level; -} msg_setting; - -/************ Compatibility function *************/ -#define MAXSTRLEN (4*DISPLAYSIZE+3) -#include "region.h" -#include - -static void -arg_set(variant args[], const message_type * mtype, const char * buffer, variant v) -{ - int i; - for (i=0;i!=mtype->nparameters;++i) { - if (!strcmp(buffer, mtype->pnames[i])) break; - } - if (i!=mtype->nparameters) { - args[i] = v; - } else { - fprintf(stderr, "invalid parameter %s for message type %s\n", buffer, mtype->name); - assert(!"program aborted."); - } -} - -struct message * -msg_feedback(const struct unit * u, struct order * ord, const char * name, const char* sig, ...) -{ - va_list marker; - const message_type * mtype = mt_find(name); - char paramname[64]; - const char *ic = sig; - variant args[16]; - variant var; - memset(args, 0, sizeof(args)); - - if (ord==NULL) ord = u->thisorder; - - if (!mtype) { - log_error(("trying to create message of unknown type \"%s\"\n", name)); - return msg_message("missing_feedback", "unit region command name", u, u->region, ord, name); - } - - var.v = (void*)u; - arg_set(args, mtype, "unit", var); - var.v = (void*)u->region; - arg_set(args, mtype, "region", var); - var.v = (void*)ord; - arg_set(args, mtype, "command", var); - - va_start(marker, sig); - while (*ic && !isalnum(*ic)) ic++; - while (*ic) { - char * oc = paramname; - int i; - - while (isalnum(*ic)) *oc++ = *ic++; - *oc = '\0'; - - for (i=0;i!=mtype->nparameters;++i) { - if (!strcmp(paramname, mtype->pnames[i])) break; - } - if (i!=mtype->nparameters) { - if (mtype->types[i]->vtype==VAR_VOIDPTR) { - args[i].v = va_arg(marker, void*); - } else if (mtype->types[i]->vtype==VAR_INT) { - args[i].i = va_arg(marker, int); - } else { - assert(!"unknown variant type"); - } - } else { - log_error(("invalid parameter %s for message type %s\n", paramname, mtype->name)); - assert(!"program aborted."); - } - while (*ic && !isalnum(*ic)) ic++; - } - va_end(marker); - - return msg_create(mtype, args); -} - -message * -msg_message(const char * name, const char* sig, ...) - /* msg_message("oops_error", "unit region command", u, r, cmd) */ -{ - va_list marker; - const message_type * mtype = mt_find(name); - char paramname[64]; - const char *ic = sig; - variant args[16]; - memset(args, 0, sizeof(args)); - - if (!mtype) { - log_error(("trying to create message of unknown type \"%s\"\n", name)); - if (strcmp(name, "missing_message")!=0) { - return msg_message("missing_message", "name", name); - } - return NULL; - } - - va_start(marker, sig); - while (*ic && !isalnum(*ic)) ic++; - while (*ic) { - char * oc = paramname; - int i; - - while (isalnum(*ic)) *oc++ = *ic++; - *oc = '\0'; - - for (i=0;i!=mtype->nparameters;++i) { - if (!strcmp(paramname, mtype->pnames[i])) break; - } - if (i!=mtype->nparameters) { - if (mtype->types[i]->vtype==VAR_VOIDPTR) { - args[i].v = va_arg(marker, void*); - } else if (mtype->types[i]->vtype==VAR_INT) { - args[i].i = va_arg(marker, int); - } else { - assert(!"unknown variant type"); - } - } else { - log_error(("invalid parameter %s for message type %s\n", paramname, mtype->name)); - assert(!"program aborted."); - } - while (*ic && !isalnum(*ic)) ic++; - } - va_end(marker); - - return msg_create(mtype, args); -} - -static void -caddmessage(region * r, faction * f, const char *s, msg_t mtype, int level) -{ - message * m = NULL; - -#define LOG_ENGLISH -#ifdef LOG_ENGLISH - if (f && f->locale!=default_locale) { - log_warning(("message for locale \"%s\": %s\n", locale_name(f->locale), s)); - } -#endif - unused(level); - switch (mtype) { - case MSG_INCOME: - assert(f); - m = add_message(&f->msgs, msg_message("msg_economy", "string", s)); - break; - case MSG_BATTLE: - assert(0 || !"battle-meldungen nicht über addmessage machen"); - break; - case MSG_MOVE: - assert(f); - m = add_message(&f->msgs, msg_message("msg_movement", "string", s)); - break; - case MSG_COMMERCE: - assert(f); - m = add_message(&f->msgs, msg_message("msg_economy", "string", s)); - break; - case MSG_PRODUCE: - assert(f); - m = add_message(&f->msgs, msg_message("msg_production", "string", s)); - break; - case MSG_MAGIC: - case MSG_COMMENT: - case MSG_MESSAGE: - case MSG_ORCVERMEHRUNG: - case MSG_EVENT: - /* Botschaften an REGION oder einzelne PARTEI */ - m = msg_message("msg_event", "string", s); - if (!r) { - assert(f); - m = add_message(&f->msgs, m); - } else { - if (f==NULL) add_message(&r->msgs, m); - else r_addmessage(r, f, m); - } - break; - default: - assert(!"Ungültige Msg-Klasse!"); - } - if (m) msg_release(m); -} - -void -addmessage(region * r, faction * f, const char *s, msg_t mtype, int level) -{ - caddmessage(r, f, s, mtype, level); -} - -void -cmistake(const unit * u, struct order *ord, int mno, int mtype) -{ - static char msgname[20]; - unused(mtype); - - if (is_monsters(u->faction)) return; - sprintf(msgname, "error%d", mno); - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, msgname, "")); -} - -extern unsigned int new_hashstring(const char* s); - -void -free_messagelist(message_list * msgs) -{ - struct mlist ** mlistptr = &msgs->begin; - while (*mlistptr) { - struct mlist * ml = *mlistptr; - *mlistptr = ml->next; - msg_release(ml->msg); - free(ml); - } - free(msgs); -} - -message * -add_message(message_list** pm, message * m) -{ - if (!lomem && m!=NULL) { - struct mlist * mnew = malloc(sizeof(struct mlist)); - if (*pm==NULL) { - *pm = malloc(sizeof(message_list)); - (*pm)->end=&(*pm)->begin; - } - mnew->msg = msg_addref(m); - mnew->next = NULL; - *((*pm)->end) = mnew; - (*pm)->end=&mnew->next; - } - return m; -} - - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "message.h" + +/* kernel includes */ +#include "building.h" +#include "faction.h" +#include "item.h" +#include "order.h" +#include "plane.h" +#include "region.h" +#include "unit.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include + +typedef struct msg_setting { + struct msg_setting *next; + const struct message_type *type; + int level; +} msg_setting; + +/************ Compatibility function *************/ +#define MAXSTRLEN (4*DISPLAYSIZE+3) +#include "region.h" +#include + +static void +arg_set(variant args[], const message_type * mtype, const char * buffer, variant v) +{ + int i; + for (i=0;i!=mtype->nparameters;++i) { + if (!strcmp(buffer, mtype->pnames[i])) break; + } + if (i!=mtype->nparameters) { + args[i] = v; + } else { + fprintf(stderr, "invalid parameter %s for message type %s\n", buffer, mtype->name); + assert(!"program aborted."); + } +} + +struct message * +msg_feedback(const struct unit * u, struct order * ord, const char * name, const char* sig, ...) +{ + va_list marker; + const message_type * mtype = mt_find(name); + char paramname[64]; + const char *ic = sig; + variant args[16]; + variant var; + memset(args, 0, sizeof(args)); + + if (ord==NULL) ord = u->thisorder; + + if (!mtype) { + log_error(("trying to create message of unknown type \"%s\"\n", name)); + return msg_message("missing_feedback", "unit region command name", u, u->region, ord, name); + } + + var.v = (void*)u; + arg_set(args, mtype, "unit", var); + var.v = (void*)u->region; + arg_set(args, mtype, "region", var); + var.v = (void*)ord; + arg_set(args, mtype, "command", var); + + va_start(marker, sig); + while (*ic && !isalnum(*ic)) ic++; + while (*ic) { + char * oc = paramname; + int i; + + while (isalnum(*ic)) *oc++ = *ic++; + *oc = '\0'; + + for (i=0;i!=mtype->nparameters;++i) { + if (!strcmp(paramname, mtype->pnames[i])) break; + } + if (i!=mtype->nparameters) { + if (mtype->types[i]->vtype==VAR_VOIDPTR) { + args[i].v = va_arg(marker, void*); + } else if (mtype->types[i]->vtype==VAR_INT) { + args[i].i = va_arg(marker, int); + } else { + assert(!"unknown variant type"); + } + } else { + log_error(("invalid parameter %s for message type %s\n", paramname, mtype->name)); + assert(!"program aborted."); + } + while (*ic && !isalnum(*ic)) ic++; + } + va_end(marker); + + return msg_create(mtype, args); +} + +message * +msg_message(const char * name, const char* sig, ...) + /* msg_message("oops_error", "unit region command", u, r, cmd) */ +{ + va_list marker; + const message_type * mtype = mt_find(name); + char paramname[64]; + const char *ic = sig; + variant args[16]; + memset(args, 0, sizeof(args)); + + if (!mtype) { + log_error(("trying to create message of unknown type \"%s\"\n", name)); + if (strcmp(name, "missing_message")!=0) { + return msg_message("missing_message", "name", name); + } + return NULL; + } + + va_start(marker, sig); + while (*ic && !isalnum(*ic)) ic++; + while (*ic) { + char * oc = paramname; + int i; + + while (isalnum(*ic)) *oc++ = *ic++; + *oc = '\0'; + + for (i=0;i!=mtype->nparameters;++i) { + if (!strcmp(paramname, mtype->pnames[i])) break; + } + if (i!=mtype->nparameters) { + if (mtype->types[i]->vtype==VAR_VOIDPTR) { + args[i].v = va_arg(marker, void*); + } else if (mtype->types[i]->vtype==VAR_INT) { + args[i].i = va_arg(marker, int); + } else { + assert(!"unknown variant type"); + } + } else { + log_error(("invalid parameter %s for message type %s\n", paramname, mtype->name)); + assert(!"program aborted."); + } + while (*ic && !isalnum(*ic)) ic++; + } + va_end(marker); + + return msg_create(mtype, args); +} + +static void +caddmessage(region * r, faction * f, const char *s, msg_t mtype, int level) +{ + message * m = NULL; + +#define LOG_ENGLISH +#ifdef LOG_ENGLISH + if (f && f->locale!=default_locale) { + log_warning(("message for locale \"%s\": %s\n", locale_name(f->locale), s)); + } +#endif + unused(level); + switch (mtype) { + case MSG_INCOME: + assert(f); + m = add_message(&f->msgs, msg_message("msg_economy", "string", s)); + break; + case MSG_BATTLE: + assert(0 || !"battle-meldungen nicht über addmessage machen"); + break; + case MSG_MOVE: + assert(f); + m = add_message(&f->msgs, msg_message("msg_movement", "string", s)); + break; + case MSG_COMMERCE: + assert(f); + m = add_message(&f->msgs, msg_message("msg_economy", "string", s)); + break; + case MSG_PRODUCE: + assert(f); + m = add_message(&f->msgs, msg_message("msg_production", "string", s)); + break; + case MSG_MAGIC: + case MSG_COMMENT: + case MSG_MESSAGE: + case MSG_ORCVERMEHRUNG: + case MSG_EVENT: + /* Botschaften an REGION oder einzelne PARTEI */ + m = msg_message("msg_event", "string", s); + if (!r) { + assert(f); + m = add_message(&f->msgs, m); + } else { + if (f==NULL) add_message(&r->msgs, m); + else r_addmessage(r, f, m); + } + break; + default: + assert(!"Ungültige Msg-Klasse!"); + } + if (m) msg_release(m); +} + +void +addmessage(region * r, faction * f, const char *s, msg_t mtype, int level) +{ + caddmessage(r, f, s, mtype, level); +} + +void +cmistake(const unit * u, struct order *ord, int mno, int mtype) +{ + static char msgname[20]; + unused(mtype); + + if (is_monsters(u->faction)) return; + sprintf(msgname, "error%d", mno); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, msgname, "")); +} + +extern unsigned int new_hashstring(const char* s); + +void +free_messagelist(message_list * msgs) +{ + struct mlist ** mlistptr = &msgs->begin; + while (*mlistptr) { + struct mlist * ml = *mlistptr; + *mlistptr = ml->next; + msg_release(ml->msg); + free(ml); + } + free(msgs); +} + +message * +add_message(message_list** pm, message * m) +{ + if (!lomem && m!=NULL) { + struct mlist * mnew = malloc(sizeof(struct mlist)); + if (*pm==NULL) { + *pm = malloc(sizeof(message_list)); + (*pm)->end=&(*pm)->begin; + } + mnew->msg = msg_addref(m); + mnew->next = NULL; + *((*pm)->end) = mnew; + (*pm)->end=&mnew->next; + } + return m; +} + + diff --git a/src/kernel/message.h b/src/kernel/message.h index 709def1b0..c3e6e3fbe 100644 --- a/src/kernel/message.h +++ b/src/kernel/message.h @@ -1,61 +1,61 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_MESSAGE -#define H_KRNL_MESSAGE -#ifdef __cplusplus -extern "C" { -#endif - -#include - -struct message; -struct faction; -struct msglevel; - -struct message_type; - -typedef struct message_list { - struct mlist { - struct mlist * next; - struct message *msg; - } * begin, **end; -} message_list; - -extern void free_messagelist(message_list * msgs); - -typedef struct msglevel { - /* used to set specialized msg-levels */ - struct msglevel *next; - const struct message_type *type; - 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, - const char * name, const char* sig, ...); -extern 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); - -#define ADDMSG(msgs, mcreate) { message * m = mcreate; if (m) { assert(m->refcount>=1); add_message(msgs, m); msg_release(m); } } - -extern void cmistake(const struct unit * u, struct order *ord, int mno, int mtype); -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_MESSAGE +#define H_KRNL_MESSAGE +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct message; +struct faction; +struct msglevel; + +struct message_type; + +typedef struct message_list { + struct mlist { + struct mlist * next; + struct message *msg; + } * begin, **end; +} message_list; + +extern void free_messagelist(message_list * msgs); + +typedef struct msglevel { + /* used to set specialized msg-levels */ + struct msglevel *next; + const struct message_type *type; + 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, + const char * name, const char* sig, ...); +extern 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); + +#define ADDMSG(msgs, mcreate) { message * m = mcreate; if (m) { assert(m->refcount>=1); add_message(msgs, m); msg_release(m); } } + +extern void cmistake(const struct unit * u, struct order *ord, int mno, int mtype); +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/move.c b/src/kernel/move.c index 0924775ad..137d3c35d 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -1,2648 +1,2648 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "move.h" - -#include "alchemy.h" -#include "connection.h" -#include "build.h" -#include "building.h" -#include "calendar.h" -#include "curse.h" -#include "faction.h" -#include "item.h" -#include "magic.h" -#include "message.h" -#include "order.h" -#include "plane.h" -#include "race.h" -#include "region.h" -#include "render.h" -#include "reports.h" -#include "save.h" -#include "ship.h" -#include "skill.h" -#include "terrain.h" -#include "teleport.h" -#include "unit.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* attributes includes */ -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -int * storms; - -typedef struct traveldir { - int no; - direction_t dir; - int age; -} traveldir; - -static attrib_type at_traveldir = { - "traveldir", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, /* Weil normales Aging an ungünstiger Stelle */ - a_writechars, - a_readchars -}; - -typedef struct follower { - struct follower * next; - unit * uf; - unit * ut; - const region_list * route_end; -} follower; - -static void -get_followers(unit * target, region * r, const region_list * route_end, follower ** followers) -{ - unit * uf; - for (uf=r->units;uf;uf=uf->next) { - if (fval(uf, UFL_FOLLOWING) && !fval(uf, UFL_NOTMOVING)) { - const attrib * a = a_findc(uf->attribs, &at_follow); - if (a && a->data.v == target) { - follower * fnew = malloc(sizeof(follower)); - fnew->uf = uf; - fnew->ut = target; - fnew->route_end = route_end; - fnew->next = *followers; - *followers = fnew; - } - } - } -} - -static void -shiptrail_init(attrib *a) -{ - a->data.v = calloc(1, sizeof(traveldir)); -} - -static void -shiptrail_finalize(attrib *a) -{ - free(a->data.v); -} - -static int -shiptrail_age(attrib *a) -{ - traveldir *t = (traveldir *)(a->data.v); - - t->age--; - return (t->age>0)?AT_AGE_KEEP:AT_AGE_REMOVE; -} - -static int -shiptrail_read(attrib *a, void * owner, struct storage * store) -{ - traveldir *t = (traveldir *)(a->data.v); - - t->no = store->r_int(store); - t->dir = (direction_t)store->r_int(store); - t->age = store->r_int(store); - return AT_READ_OK; -} - -static void -shiptrail_write(const attrib * a, const void * owner, struct storage * store) -{ - traveldir *t = (traveldir *)(a->data.v); - store->w_int(store, t->no); - store->w_int(store, t->dir); - store->w_int(store, t->age); -} - -attrib_type at_shiptrail = { - "traveldir_new", - shiptrail_init, - shiptrail_finalize, - shiptrail_age, - shiptrail_write, - shiptrail_read -}; - -static int -age_speedup(attrib *a) -{ - if (a->data.sa[0] > 0) { - a->data.sa[0] = a->data.sa[0] - a->data.sa[1]; - } - return (a->data.sa[0]>0)?AT_AGE_KEEP:AT_AGE_REMOVE; -} - -attrib_type at_speedup = { - "speedup", - NULL, NULL, - age_speedup, - a_writeint, - a_readint -}; - -/* ------------------------------------------------------------- */ - -direction_t -getdirection(const struct locale * lang) -{ - return finddirection(getstrtoken(), lang); -} -/* ------------------------------------------------------------- */ - -static attrib_type at_driveweight = { - "driveweight", NULL, NULL, NULL, NULL, NULL -}; - -static boolean -entrance_allowed(const struct unit * u, const struct region * r) -{ -#ifdef REGIONOWNERS - faction * owner = region_get_owner(r); - if (owner == NULL || u->faction == owner) return true; - if (alliedfaction(rplane(r), owner, u->faction, HELP_TRAVEL)) return true; - return false; -#else - return true; -#endif -} - -int -personcapacity(const unit *u) -{ - int cap = u->race->weight+u->race->capacity; - return cap; -} - -static int -eff_weight(const unit *u) -{ - attrib *a = a_find(u->attribs, &at_driveweight); - - if (a) return weight(u) + a->data.i; - - return weight(u); -} - -static void -get_transporters(const item * itm, int * p_animals, int *p_acap, int * p_vehicles, int * p_vcap) -{ - int vehicles = 0, vcap = 0; - int animals = 0, acap = 0; - - for (;itm!=NULL;itm=itm->next) { - const item_type * itype = itm->type; - if (itype->capacity>0) { - if (itype->flags & ITF_ANIMAL) { - animals += itm->number; - if (acap==0) acap = itype->capacity; - assert(acap==itype->capacity || !"animals with different capacity not supported"); - } - if (itype->flags & ITF_VEHICLE) { - vehicles += itm->number; - if (vcap==0) vcap = itype->capacity; - assert(vcap==itype->capacity || !"vehicles with different capacity not supported"); - } - } - } - *p_vehicles = vehicles; - *p_animals = animals; - *p_vcap = vcap; - *p_acap = acap; -} - -static int -ridingcapacity(unit * u) -{ - int vehicles = 0, vcap = 0; - int animals = 0, acap = 0; - - get_transporters(u->items, &animals, &acap, &vehicles, &vcap); - - /* Man trägt sein eigenes Gewicht plus seine Kapazität! Die Menschen - ** tragen nichts (siehe walkingcapacity). Ein Wagen zählt nur, wenn er - ** von zwei Pferden gezogen wird */ - - animals = MIN(animals, effskill(u, SK_RIDING) * u->number * 2); - if (fval(u->race, RCF_HORSE)) animals += u->number; - - /* maximal diese Pferde können zum Ziehen benutzt werden */ - vehicles = MIN(animals / HORSESNEEDED, vehicles); - - return vehicles * vcap + animals * acap; -} - -int -walkingcapacity(const struct unit * u) -{ - int n, tmp, people, pferde_fuer_wagen; - int wagen_ohne_pferde, wagen_mit_pferden, wagen_mit_trollen; - int vehicles = 0, vcap = 0; - int animals = 0, acap = 0; - - get_transporters(u->items, &animals, &acap, &vehicles, &vcap); - - /* Das Gewicht, welches die Pferde tragen, plus das Gewicht, welches - * die Leute tragen */ - - pferde_fuer_wagen = MIN(animals, effskill(u, SK_RIDING) * u->number * 4); - if (fval(u->race, RCF_HORSE)) { - animals += u->number; - people = 0; - } else { - people = u->number; - } - - /* maximal diese Pferde können zum Ziehen benutzt werden */ - wagen_mit_pferden = MIN(vehicles, pferde_fuer_wagen / HORSESNEEDED); - - n = wagen_mit_pferden * vcap; - - if (u->race == new_race[RC_TROLL]) { - /* 4 Trolle ziehen einen Wagen. */ - /* Unbesetzte Wagen feststellen */ - wagen_ohne_pferde = vehicles - wagen_mit_pferden; - - /* Genug Trolle, um die Restwagen zu ziehen? */ - wagen_mit_trollen = MIN(u->number / 4, wagen_ohne_pferde); - - /* Wagenkapazität hinzuzählen */ - n += wagen_mit_trollen * vcap; - wagen_ohne_pferde -= wagen_mit_trollen; - } - - n += animals * acap; - n += people * personcapacity(u); - /* Goliathwasser */ - tmp = get_effect(u, oldpotiontype[P_STRONG]); - if (tmp>0) { - int horsecap = olditemtype[I_HORSE]->capacity; - if (tmp>people) tmp = people; - n += tmp * (horsecap - personcapacity(u)); - } - /* change_effect wird in ageing gemacht */ - tmp = get_item(u, I_TROLLBELT); - n += MIN(people, tmp) * (STRENGTHMULTIPLIER-1) * personcapacity(u); - - return n; -} - -enum { - E_CANWALK_OK = 0, - E_CANWALK_TOOMANYHORSES, - E_CANWALK_TOOMANYCARTS, - E_CANWALK_TOOHEAVY -}; - -static int -canwalk(unit * u) -{ - int maxwagen, maxpferde; - int vehicles = 0, vcap = 0; - int animals = 0, acap = 0; - - /* workaround: monsters are too stupid to drop items, therefore they have - * infinite carrying capacity */ - - if (is_monsters(u->faction)) return E_CANWALK_OK; - - get_transporters(u->items, &animals, &acap, &vehicles, &vcap); - - maxwagen = effskill(u, SK_RIDING) * u->number * 2; - if (u->race == new_race[RC_TROLL]) { - maxwagen = MAX(maxwagen, u->number / 4); - } - maxpferde = effskill(u, SK_RIDING) * u->number * 4 + u->number; - - if (animals > maxpferde) - return E_CANWALK_TOOMANYHORSES; - - if (walkingcapacity(u) - eff_weight(u) >= 0) - return E_CANWALK_OK; - - /* Stimmt das Gewicht, impliziert dies hier, daß alle Wagen ohne - * Zugpferde/-trolle als Fracht aufgeladen wurden: zu viele Pferde hat - * die Einheit nicht zum Ziehen benutzt, also nicht mehr Wagen gezogen - * als erlaubt. */ - - if (vehicles > maxwagen) - return E_CANWALK_TOOMANYCARTS; - /* Es muß nicht zwingend an den Wagen liegen, aber egal... (man - * könnte z.B. auch 8 Eisen abladen, damit ein weiterer Wagen als - * Fracht draufpaßt) */ - - return E_CANWALK_TOOHEAVY; -} - -boolean -canfly(unit *u) -{ - if (get_item(u, I_PEGASUS) >= u->number && effskill(u, SK_RIDING) >= 4) - return true; - - if (fval(u->race, RCF_FLY)) return true; - - if (get_movement(&u->attribs, MV_FLY)) return true; - - return false; -} - -boolean -canswim(unit *u) -{ - if (get_item(u, I_DOLPHIN) >= u->number && effskill(u, SK_RIDING) >= 4) - return true; - - if (u->race->flags & RCF_FLY) return true; - - if (u->race->flags & RCF_SWIM) return true; - - if (get_movement(&u->attribs, MV_FLY)) return true; - - if (get_movement(&u->attribs, MV_SWIM)) return true; - - return false; -} - -static int -canride(unit * u) -{ - int horses = 0, maxhorses, unicorns = 0, maxunicorns; - int skill = effskill(u, SK_RIDING); - item * itm; - static const item_type * it_horse = 0; - static const item_type * it_elvenhorse = 0; - static const item_type * it_charger = 0; - - if (it_horse==0) { - it_horse = it_find("horse"); - it_elvenhorse = it_find("elvenhorse"); - it_charger = it_find("charger"); - } - - for (itm=u->items;itm;itm=itm->next) { - if (itm->type==it_horse || itm->type==it_charger) { - horses += itm->number; - } else if (itm->type==it_elvenhorse) { - unicorns += itm->number; - } - } - - maxunicorns = (skill/5) * u->number; - maxhorses = skill * u->number * 2; - - if(!(u->race->flags & RCF_HORSE) - && ((horses == 0 && unicorns == 0) - || horses > maxhorses || unicorns > maxunicorns)) { - return 0; - } - - if (ridingcapacity(u) - eff_weight(u) >= 0) { - if (horses == 0 && unicorns >= u->number && !(u->race->flags & RCF_HORSE)) { - return 2; - } - return 1; - } - - return 0; -} - -static boolean -cansail(const region * r, ship * sh) -{ - /* sonst ist construction:: size nicht ship_type::maxsize */ - assert(!sh->type->construction || sh->type->construction->improvement == NULL); - - if (sh->type->construction && sh->size!=sh->type->construction->maxsize) { - return false; - } else { - int n = 0, p = 0; - int mweight = shipcapacity(sh); - int mcabins = sh->type->cabins; - - getshipweight(sh, &n, &p); - - if (n > mweight) return false; - if (mcabins && p > mcabins) return false; - } - return true; -} - -int -enoughsailors(const ship * sh, const region * r) -{ - int n; - unit *u; - - n = 0; - - for (u = r->units; u; u = u->next) { - if (u->ship == sh) - n += eff_skill(u, SK_SAILING, r) * u->number; - } - return n >= sh->type->sumskill; -} -/* ------------------------------------------------------------- */ - -static ship * -do_maelstrom(region *r, unit *u) -{ - int damage; - ship * sh = u->ship; - - damage = rng_int()%75 + rng_int()%75 - eff_skill(u, SK_SAILING, r)*4; - - if (damage <= 0) { - return sh; - } - - damage_ship(u->ship, 0.01*damage); - - if (sh->damage >= sh->size * DAMAGE_SCALE) { - ADDMSG(&u->faction->msgs, msg_message("entermaelstrom", - "region ship damage sink", r, sh, damage, 1)); - remove_ship(&sh->region->ships, sh); - return NULL; - } - ADDMSG(&u->faction->msgs, msg_message("entermaelstrom", - "region ship damage sink", r, sh, damage, 0)); - return u->ship; -} - -/** sets a marker in the region telling that the unit has travelled through it - * this is used for two distinctly different purposes: - * - to report that a unit has travelled through. the report function - * makes sure to only report the ships of travellers, not the travellers - * themselves - * - to report the region to the traveller - */ -void -travelthru(const unit * u, region * r) -{ - attrib *ru = a_add(&r->attribs, a_new(&at_travelunit)); - - fset(r, RF_TRAVELUNIT); - - ru->data.v = (void*)u; - - /* the first and last region of the faction gets reset, because travelthrough - * could be in regions that are located before the [first, last] interval, - * and recalculation is needed */ -#ifdef SMART_INTERVALS - update_interval(u->faction, r); -#endif -} - -static void -leave_trail(ship * sh, region * from, region_list *route) -{ - region * r = from; - - while (route!=NULL) { - region * rn = route->data; - direction_t dir = reldirection(r, rn); - - /* TODO: we cannot leave a trail into special directions - * if we use this kind of direction-attribute */ - if (dir=0) { - traveldir * td = NULL; - attrib * a = a_find(r->attribs, &at_shiptrail); - - while (a!=NULL && a->type==&at_shiptrail) { - td = (traveldir *)a->data.v; - if (td->no == sh->no) break; - a = a->next; - } - - if (a == NULL || a->type!=&at_shiptrail) { - a = a_add(&(r->attribs), a_new(&at_shiptrail)); - td = (traveldir *)a->data.v; - td->no = sh->no; - } - td->dir = dir; - td->age = 2; - } - route = route->next; - r = rn; - } -} - -static void -mark_travelthru(const unit * u, region * r, const region_list * route, const region_list * route_end) -{ - /* kein travelthru in der letzten region! */ - while (route!=route_end) { - travelthru(u, r); - r = route->data; - route = route->next; - } -} - -ship * -move_ship(ship * sh, region * from, region * to, region_list * route) -{ - unit **iunit = &from->units; - unit **ulist = &to->units; - boolean trail = (route == NULL); - - if (from!=to) { - translist(&from->ships, &to->ships, sh); - sh->region = to; - } - if (!trail) { - leave_trail(sh, from, route); - trail = true; - } - - while (*iunit!=NULL) { - unit *u = *iunit; - assert(u->region == from); - - if (u->ship == sh) { - if (route!=NULL) mark_travelthru(u, from, route, NULL); - if (from!=to) { - u->ship = NULL; /* damit move_unit() kein leave() macht */ - move_unit(u, to, ulist); - ulist = &u->next; - u->ship = sh; - } - if (route && eff_skill(u, SK_SAILING, from) >= 1) { - produceexp(u, SK_SAILING, u->number); - } - } - if (*iunit == u) iunit=&u->next; - } - - return sh; -} - -static boolean -is_freezing(const unit * u) -{ - if (u->race!=new_race[RC_INSECT]) return false; - if (is_cursed(u->attribs, C_KAELTESCHUTZ, 0)) return false; - return true; -} - -static boolean -ship_allowed(const struct ship * sh, const region * r) -{ - int c = 0; - static const building_type * bt_harbour=NULL; - - if (bt_harbour == NULL) bt_harbour=bt_find("harbour"); - - if (r_insectstalled(r)) { - /* insekten dürfen nicht hier rein. haben wir welche? */ - unit * u; - - for (u=sh->region->units;u!=NULL;u=u->next) { - if (u->ship!=sh) continue; - - if (is_freezing(u)) { - unit * captain = shipowner(sh); - if (captain) { - ADDMSG(&captain->faction->msgs, msg_message("detectforbidden", - "unit region", u, r)); - } - - return false; - } - } - } - - if (buildingtype_exists(r, bt_harbour, true)) return true; - for (c=0;sh->type->coasts[c]!=NULL;++c) { - if (sh->type->coasts[c] == r->terrain) return true; - } - - return false; -} - -static boolean -flying_ship(const ship * sh) -{ - if (sh->type->flags & SFL_FLY) return true; - if (sh->flags & SF_FLYING) return true; - return false; -} - -static void -set_coast(ship * sh, region * r, region * rnext) -{ - if (sh->type->flags & SFL_NOCOAST) { - sh->coast = NODIRECTION; - } else if (!fval(rnext->terrain, SEA_REGION) && !flying_ship(sh)) { - sh->coast = reldirection(rnext, r); - assert(fval(r->terrain, SEA_REGION)); - } else { - sh->coast = NODIRECTION; - } -} - -static float -damage_drift(void) -{ - static float value = -1.0F; - if (value<0) { - value = get_param_flt(global.parameters, "rules.ship.damage_drift", 0.02F); - } - return value; -} - -static void -drifting_ships(region * r) -{ - direction_t d; - - if (fval(r->terrain, SEA_REGION)) { - ship** shp = &r->ships; - while (*shp) { - ship * sh = *shp; - region * rnext = NULL; - region_list * route = NULL; - unit *firstu = NULL, *captain; - int d_offset; - direction_t dir = 0; - - if (sh->type->fishing>0) { - sh->flags |= SF_FISHING; - } - - /* Schiff schon abgetrieben oder durch Zauber geschützt? */ - if (fval(sh, SF_DRIFTED) || is_cursed(sh->attribs, C_SHIP_NODRIFT, 0)) { - shp = &sh->next; - continue; - } - - /* Kapitän bestimmen */ - for (captain = r->units; captain; captain = captain->next) { - if (captain->ship != sh) continue; - if (firstu==NULL) firstu = captain; - if (eff_skill(captain, SK_SAILING, r) >= sh->type->cptskill) { - break; - } - } - /* Kapitän da? Beschädigt? Genügend Matrosen? - * Genügend leicht? Dann ist alles OK. */ - - assert(sh->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ - if (captain && sh->size == sh->type->construction->maxsize && enoughsailors(sh, r) && cansail(r, sh)) { - shp = &sh->next; - continue; - } - - /* Auswahl einer Richtung: Zuerst auf Land, dann - * zufällig. Falls unmögliches Resultat: vergiß es. */ - d_offset = rng_int() % MAXDIRECTIONS; - for (d = 0; d != MAXDIRECTIONS; ++d) { - region * rn; - dir = (direction_t)((d + d_offset) % MAXDIRECTIONS); - rn = rconnect(r, dir); - if (rn!=NULL && fval(rn->terrain, SAIL_INTO) && ship_allowed(sh, rn)) { - rnext = rn; - if (!fval(rnext->terrain, SEA_REGION)) break; - } - } - - if (rnext == NULL) { - shp = &sh->next; - continue; - } - - /* Das Schiff und alle Einheiten darin werden nun von r - * nach rnext verschoben. Danach eine Meldung. */ - add_regionlist(&route, rnext); - - set_coast(sh, r, rnext); - sh = move_ship(sh, r, rnext, route); - free_regionlist(route); - - if (firstu!=NULL) { - unit *u, *lastu = NULL; - message * msg = msg_message("ship_drift", "ship dir", sh, dir); - for (u=firstu;u;u=u->next) { - if (u->ship==sh && !fval(u->faction, FFL_MARK)) { - fset(u->faction, FFL_MARK); - add_message(&u->faction->msgs, msg); - lastu = u->next; - } - } - for (u=firstu;u!=lastu;u=u->next) { - freset(u->faction, FFL_MARK); - } - msg_release(msg); - } - - if (sh!=NULL) { - fset(sh, SF_DRIFTED); - - damage_ship(sh, damage_drift()); - if (sh->damage>=sh->size * DAMAGE_SCALE) { - remove_ship(&sh->region->ships, sh); - } - } - - if (*shp == sh) shp = &sh->next; - } - } -} - -static boolean -present(region * r, unit * u) -{ - return (boolean) (u && u->region == r); -} - -static void -caught_target(region * r, unit * u) -{ - attrib * a = a_find(u->attribs, &at_follow); - - /* Verfolgungen melden */ - /* Misserfolgsmeldung, oder bei erfolgreichem Verfolgen unter - * Umstaenden eine Warnung. */ - - if (a) { - unit * target = (unit*)a->data.v; - - if (!present(r, target)) { - ADDMSG(&u->faction->msgs, msg_message("followfail", "unit follower", - target, u)); - } else if (!alliedunit(target, u->faction, HELP_ALL) - && cansee(target->faction, r, u, 0)) - { - ADDMSG(&target->faction->msgs, msg_message("followdetect", - "unit follower", target, u)); - } - } -} - -/* TODO: Unsichtbarkeit bedenken ! */ - -static unit * -bewegung_blockiert_von(unit * reisender, region * r) -{ - unit *u; - int perception = 0; - boolean contact = false; - unit * guard = NULL; - - if (fval(reisender->race, RCF_ILLUSIONARY)) return NULL; - for (u=r->units;u && !contact;u=u->next) { - if (is_guard(u, GUARD_TRAVELTHRU)) { - int sk = eff_skill(u, SK_PERCEPTION, r); - if (invisible(reisender, u) >= reisender->number) continue; - if (u->faction == reisender->faction) contact = true; - else if (ucontact(u, reisender)) contact = true; - else if (alliedunit(u, reisender->faction, HELP_GUARD)) contact = true; - else if (sk>=perception) { - perception = sk; - guard = u; - } - } - } - if (!contact && guard) { - double prob = 0.3; /* 30% base chance */ - prob += 0.1 * (perception - eff_stealth(reisender, r)); - prob += 0.1 * MIN(guard->number, get_item(guard, I_AMULET_OF_TRUE_SEEING)); - - if (chance(prob)) { - return guard; - } - } - return NULL; -} - -static boolean -is_guardian_u(const unit * guard, unit *u, unsigned int mask) -{ - if (guard->faction == u->faction) return false; - if (is_guard(guard, mask) == 0) return false; - if (alliedunit(guard, u->faction, HELP_GUARD)) return false; - if (ucontact(guard, u)) return false; - if (!cansee(guard->faction, u->region, u, 0)) return false; - - return true; -} - -static boolean -is_guardian_r(const unit * guard) -{ - if (guard->number == 0) return false; - if (besieged(guard)) return false; - - /* if region_owners exist then they may be guardians: */ - if (guard->building && rule_region_owners() && fval(guard, UFL_OWNER)) { - faction * owner = region_get_owner(guard->region); - if (owner==guard->faction) { - building * bowner = largestbuilding(guard->region, &cmp_taxes, false); - if (bowner==guard->building) { - return true; - } - } - } - - if ((guard->flags&UFL_GUARD)==0) return false; - if (!armedmen(guard, true) && !fval(guard->race, RCF_UNARMEDGUARD)) return false; - return true; -} - -boolean is_guard(const struct unit * u, int mask) -{ - return is_guardian_r(u) && (getguard(u) & mask)!=0; -} - -#define MAXGUARDCACHE 16 -/** returns the guard which prevents 'u' from doing 'mask' actions in 'r'. -*/ -unit * -is_guarded(region * r, unit * u, unsigned int mask) -{ - unit *u2 = NULL; - int i, noguards = 1; - static unit * guardcache[MAXGUARDCACHE], * lastguard; /* STATIC_XCALL: used across calls */ - static int gamecookie = -1; - - if (!fval(r, RF_GUARDED)) { - return NULL; - } - - if (gamecookie!=global.cookie) { - if (gamecookie>=0) { - /* clear the previous turn's cache */ - memset(guardcache, 0, sizeof(guardcache)); - lastguard = NULL; - } - gamecookie = global.cookie; - } - - if (lastguard && lastguard->region==r) { - if (is_guardian_u(lastguard, u, mask)) { - return lastguard; - } - } - - for (i=0;i!=MAXGUARDCACHE;++i) { - unit * guard = guardcache[i]; - if (guard && guard!=lastguard && guard->region==r) { - noguards = 0; - if (is_guardian_u(guard, u, mask)) { - lastguard = guard; - return guard; - } - if (u2==guard) { - /* same guard twice signals we've tested everyone */ - return NULL; - } - u2 = guard; - } else { - /* exhausted all the guards in the cache, but maybe we'll find one later? */ - break; - } - } - - /* at this point, u2 is the last unit we tested to - * be a guard (and failed), or NULL - * i is the position of the first free slot in the cache */ - - for (u2 = (u2?u2->next:r->units); u2; u2=u2->next) { - if (is_guardian_r(u2)) { - noguards = 0; - /* u2 is a guard, so worth remembering */ - if (i0 && ifaction->locale; - pause = false; - token = getstrtoken(); - d = finddirection(token, lang); - if(d == D_PAUSE) { - pause = true; - } else if (d == NODIRECTION) { - break; - } - if (cmsizeof(neworder)/2) break; - else if (cm == gereist && !paused && pause) { - const char * loc = LOC(lang, parameters[P_PAUSE]); - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, loc, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - paused = true; - } - else if (pause) { - /* da PAUSE nicht in ein shortdirections[d] umgesetzt wird (ist - * hier keine normale direction), muss jede PAUSE einzeln - * herausgefiltert und explizit gesetzt werden */ - if (neworder[0]) strcat(neworder, " "); - strcat(neworder, LOC(lang, parameters[P_PAUSE])); - } else { - if (neworder[0]) strcat(neworder, " "); - strcat(neworder, LOC(lang, shortdirections[d])); - } - } - - if (neworder[0]) { - norder = create_order(K_ROUTE, u->faction->locale, "%s %s", neworder, tail); - } else { - norder = create_order(K_ROUTE, u->faction->locale, "%s", tail); - } - replace_order(&u->orders, ord, norder); - free_order(norder); -} - -static boolean -transport(unit * ut, unit * u) -{ - order * ord; - - if (LongHunger(u) || fval(ut->region->terrain, SEA_REGION)) { - return false; - } - - for (ord = ut->orders; ord; ord = ord->next) { - if (get_keyword(ord) == K_TRANSPORT) { - init_tokens(ord); - skip_token(); - if (getunit(ut->region, ut->faction) == u) { - return true; - } - } - } - return false; -} - -static boolean -can_move(const unit * u) -{ - if (u->race->flags & RCF_CANNOTMOVE) return false; - if (get_movement(&u->attribs, MV_CANNOTMOVE)) return false; - return true; -} - -static void -init_transportation(void) -{ - region *r; - - for (r=regions; r; r=r->next) { - unit *u; - - /* This is just a simple check for non-corresponding K_TRANSPORT/ - * K_DRIVE. This is time consuming for an error check, but there - * doesn't seem to be an easy way to speed this up. */ - for (u=r->units; u; u=u->next) { - if (get_keyword(u->thisorder) == K_DRIVE && can_move(u) && !fval(u, UFL_NOTMOVING) && !LongHunger(u)) { - unit * ut; - - init_tokens(u->thisorder); - skip_token(); - ut = getunit(r, u->faction); - if (ut == NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); - continue; - } - if (!transport(ut, u)) { - if (cansee(u->faction, r, ut, 0)) { - cmistake(u, u->thisorder, 286, MSG_MOVE); - } else { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); - } - } - } - } - - /* This calculates the weights of all transported units and - * adds them to an internal counter which is used by travel () to - * calculate effective weight and movement. */ - - if (!fval(r->terrain, SEA_REGION)) { - for (u=r->units; u; u=u->next) { - order * ord; - int w = 0; - - for (ord = u->orders; ord; ord = ord->next) { - if (get_keyword(ord) == K_TRANSPORT) { - init_tokens(ord); - skip_token(); - for (;;) { - unit * ut = getunit(r, u->faction); - - if (ut == NULL) break; - if (get_keyword(ut->thisorder) == K_DRIVE && can_move(ut) && !fval(ut, UFL_NOTMOVING) && !LongHunger(ut)) { - init_tokens(ut->thisorder); - skip_token(); - if (getunit(r, ut->faction) == u) { - w += weight(ut); - } - } - } - } - } - if (w > 0) a_add(&u->attribs, a_new(&at_driveweight))->data.i = w; - } - } - } -} - -static boolean -roadto(const region * r, direction_t dir) -{ - /* wenn es hier genug strassen gibt, und verbunden ist, und es dort - * genug strassen gibt, dann existiert eine strasse in diese richtung */ - region * r2; - static const curse_type * roads_ct = NULL; - - if (dir>=MAXDIRECTIONS || dir<0) return false; - r2 = rconnect(r, dir); - if (r == NULL || r2 == NULL) return false; - - if (roads_ct == NULL) roads_ct = ct_find("magicstreet"); - if (roads_ct!=NULL) { - if (get_curse(r->attribs, roads_ct)!=NULL) return true; - if (get_curse(r2->attribs, roads_ct)!=NULL) return true; - } - - if (r->terrain->max_road <= 0) return false; - if (r2->terrain->max_road <= 0) return false; - if (rroad(r, dir) < r->terrain->max_road) return false; - if (rroad(r2, dir_invert(dir)) < r2->terrain->max_road) return false; - return true; -} - -static const region_list * -cap_route(region * r, const region_list * route, const region_list * route_end, int speed) -{ - region * current = r; - int moves = speed; - const region_list * iroute = route; - while (iroute!=route_end) { - region * next = iroute->data; - direction_t reldir = reldirection(current, next); - - /* adjust the range of the unit */ - if (roadto(current, reldir)) moves -= BP_ROAD; - else moves -= BP_NORMAL; - if (moves<0) break; - iroute = iroute->next; - current = next; - } - return iroute; -} - -static region * -next_region(unit * u, region * current, region * next) -{ - connection * b; - - b = get_borders(current, next); - while (b!=NULL) { - if (b->type->move) { - region * rto = b->type->move(b, u, current, next, true); - if (rto!=next) { - /* the target region was changed (wisps, for example). check the - * new target region for borders */ - next = rto; - b = get_borders(current, next); - continue; - } - } - b = b->next; - } - return next; -} - -static const region_list * -reroute(unit * u, const region_list * route, const region_list * route_end) -{ - region * current = u->region; - while (route!=route_end) { - region * next = next_region(u, current, route->data); - if (next!=route->data) break; - route = route->next; - } - return route; -} - -static void -make_route(unit * u, order * ord, region_list ** routep) -{ - region_list **iroute = routep; - region * current = u->region; - region * next = NULL; - const char * token = getstrtoken(); - int error = movewhere(u, token, current, &next); - - if (error!=E_MOVE_OK) { - message * msg = movement_error(u, token, ord, error); - if (msg!=NULL) { - add_message(&u->faction->msgs, msg); - msg_release(msg); - } - next = NULL; - } - - while (next!=NULL) { - direction_t reldir; - - if (current == next) { - /* PAUSE */ - break; - } - next = next_region(u, current, next); - reldir = reldirection(current, next); - - add_regionlist(iroute, next); - iroute = &(*iroute)->next; - - current = next; - token = getstrtoken(); - error = movewhere(u, token, current, &next); - if (error) { - message * msg = movement_error(u, token, ord, error); - if (msg!=NULL) { - add_message(&u->faction->msgs, msg); - msg_release(msg); - } - next = NULL; - } - } -} - -/** calculate the speed of a unit - * - * zu Fuß reist man 1 Region, zu Pferd 2 Regionen. Mit Straßen reist - * man zu Fuß 2, mit Pferden 3 weit. - * - * Berechnet wird das mit BPs. Zu Fuß hat man 4 BPs, zu Pferd 6. - * 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 mp; - static const curse_type * speed_ct; - static boolean init = false; - double dk = u->race->speed; - - assert(u->number); - /* dragons have a fixed speed, and no other effects work on them: */ - switch (old_race(u->race)) { - case RC_DRAGON: - case RC_WYRM: - case RC_FIREDRAGON: - case RC_BIRTHDAYDRAGON: - case RC_SONGDRAGON: - return BP_DRAGON; - } - - if (!init) { - init = true; - speed_ct = ct_find("speed"); - } - if (speed_ct) { - curse *c = get_curse(u->attribs, speed_ct); - if (c!=NULL) { - int men = get_cursedmen(u, c); - dk *= 1.0 + (double)men/(double)u->number; - } - } - - switch (canride(u)) { - - case 1: /* Pferd */ - mp = BP_RIDING; - break; - - case 2: /* Einhorn */ - mp = BP_UNICORN; - break; - - default: - mp = BP_WALKING; - - /* 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 <= get_item(u, I_FEENSTIEFEL)) { - mp *= 2; - } - - /* Im Astralraum sind Tyb und Ill-Magier doppelt so schnell. - * Nicht kumulativ mit anderen Beschleunigungen! */ - if (mp*dk <= BP_WALKING*u->race->speed && is_astral(u->region) && is_mage(u)) { - sc_mage * mage = get_mage(u); - if (mage->magietyp == M_TYBIED || mage->magietyp == M_ILLAUN) { - mp *= 2; - } - } - break; - } - return (int)(dk*mp); -} - -enum { - TRAVEL_NORMAL, - TRAVEL_FOLLOWING, - TRAVEL_TRANSPORTED, - TRAVEL_RUNNING -}; - -static arg_regions * -var_copy_regions(const region_list * begin, int size) -{ - const region_list * rsrc; - - if (size>0) { - int i = 0; - arg_regions * dst = (arg_regions *)malloc(sizeof(arg_regions) + sizeof(region*) * size); - dst->nregions = size; - dst->regions = (region**)(dst+1); - for (rsrc = begin; i!=size; rsrc=rsrc->next) { - dst->regions[i++] = rsrc->data; - } - return dst; - } - return NULL; -} - - -static const region_list * -travel_route(unit * u, const region_list * route_begin, const region_list * route_end, order * ord, int mode) -{ - region * r = u->region; - region * current = u->region; - const region_list * iroute = route_begin; - int steps = 0; - boolean landing = false; /* aquarians have landed */ - - while (iroute && iroute!=route_end) { - region * next = iroute->data; - direction_t reldir = reldirection(current, next); - connection * b = get_borders(current, next); - - /* check if we are caught by guarding units */ - if (iroute!=route_begin && mode!=TRAVEL_RUNNING && mode!=TRAVEL_TRANSPORTED) { - unit * wache = bewegung_blockiert_von(u, current); - if (wache!=NULL) { - ADDMSG(&u->faction->msgs, msg_message("moveblockedbyguard", - "unit region guard", u, current, wache)); - break; - } - } - - /* check movement from/to oceans. - * aquarian special, flying units, horses, the works */ - if ((u->race->flags & RCF_FLY) == 0) { - if (!fval(next->terrain, SEA_REGION)) { - /* next region is land */ - if (fval(current->terrain, SEA_REGION)) { - int moving = u->race->flags & (RCF_SWIM|RCF_WALK|RCF_COASTAL); - /* Die Einheit kann nicht fliegen, ist im Ozean, und will an Land */ - if (moving != (RCF_SWIM|RCF_WALK) && (moving&RCF_COASTAL) == 0) { - /* can't swim+walk and isn't allowed to enter coast from sea */ - if (ord!=NULL) cmistake(u, ord, 44, MSG_MOVE); - break; - } - landing = true; - } else if ((u->race->flags & RCF_WALK) == 0) { - /* Spezialeinheiten, die nicht laufen können. */ - ADDMSG(&u->faction->msgs, msg_message("detectocean", - "unit region", u, next)); - break; - } else if (landing) { - /* wir sind diese woche angelandet */ - ADDMSG(&u->faction->msgs, msg_message("detectocean", - "unit region", u, next)); - break; - } - } else { - /* Ozeanfelder können nur von Einheiten mit Schwimmen und ohne - * Pferde betreten werden. */ - if (!(canswim(u) || canfly(u))) { - ADDMSG(&u->faction->msgs, msg_message("detectocean", - "unit region", u, next)); - break; - } - } - - if (fval(current->terrain, SEA_REGION) || fval(next->terrain, SEA_REGION)) { - /* trying to enter or exit ocean with horses, are we? */ - if (has_horses(u)) { - /* tries to do it with horses */ - if (ord!=NULL) cmistake(u, ord, 67, MSG_MOVE); - break; - } - } - - } - - /* movement blocked by a wall */ - if (reldir>=0 && move_blocked(u, current, next)) { - ADDMSG(&u->faction->msgs, msg_message("leavefail", - "unit region", u, next)); - break; - } - - /* region ownership only: region owned by enemies */ - if (!entrance_allowed(u, next)) { - ADDMSG(&u->faction->msgs, msg_message("regionowned", - "unit region target", u, current, next)); - break; - } - - /* illusionary units disappear in antimagic zones */ - if (fval(u->race, RCF_ILLUSIONARY)) { - curse * c = get_curse(next->attribs, ct_find("antimagiczone")); - if (curse_active(c)) { - curse_changevigour(&next->attribs, c, (float)-u->number); - ADDMSG(&u->faction->msgs, msg_message("illusionantimagic", "unit", u)); - set_number(u, 0); - break; - } - } - - /* terrain is marked as forbidden (curse, etc) */ - if (fval(next, RF_BLOCKED) || fval(next->terrain, FORBIDDEN_REGION)) { - ADDMSG(&u->faction->msgs, msg_message("detectforbidden", - "unit region", u, next)); - break; - } - - /* unit is an insect and cannot move into a glacier */ - if (u->race == new_race[RC_INSECT]) { - if (r_insectstalled(next) && is_freezing(u)) { - ADDMSG(&u->faction->msgs, msg_message("detectforbidden", - "unit region", u, next)); - break; - } - } - - /* effect of borders */ - while (b!=NULL) { - if (b->type->move) { - b->type->move(b, u, current, next, false); - } - b = b->next; - } - - current = next; - iroute = iroute->next; - ++steps; - if (u->number == 0) break; - } - - if (iroute!=route_begin) { - /* the unit has moved at least one region */ - int walkmode; - - setguard(u, GUARD_NONE); - cycle_route(ord, u, steps); - - if (mode == TRAVEL_RUNNING) { - walkmode = 0; - } if (canride(u)) { - walkmode = 1; - produceexp(u, SK_RIDING, u->number); - } else { - walkmode = 2; - } - - /* Berichte über Durchreiseregionen */ - - if (mode!=TRAVEL_TRANSPORTED) { - arg_regions * ar = var_copy_regions(route_begin, steps-1); - ADDMSG(&u->faction->msgs, msg_message("travel", - "unit mode start end regions", u, walkmode, r, current, ar)); - } - - mark_travelthru(u, r, route_begin, iroute); - move_unit(u, current, NULL); - - /* make orders for the followers */ - } - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - setguard(u, GUARD_NONE); - assert(u->region == current); - return iroute; -} - -static boolean -ship_ready(const region * r, unit * u) -{ - if (!fval(u, UFL_OWNER)) { - cmistake(u, u->thisorder, 146, MSG_MOVE); - return false; - } - if (eff_skill(u, SK_SAILING, r) < u->ship->type->cptskill) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_captain_skill_low", - "value ship", u->ship->type->cptskill, u->ship)); - return false; - } - assert(u->ship->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ - if (u->ship->size!=u->ship->type->construction->maxsize) { - cmistake(u, u->thisorder, 15, MSG_MOVE); - return false; - } - if (!enoughsailors(u->ship, r)) { - cmistake(u, u->thisorder, 1, MSG_MOVE); -/* mistake(u, u->thisorder, - "Auf dem Schiff befinden sich zuwenig erfahrene Seeleute.", MSG_MOVE); */ - return false; - } - if (!cansail(r, u->ship)) { - cmistake(u, u->thisorder, 18, MSG_MOVE); - return false; - } - return true; -} - -unit * -owner_buildingtyp(const region * r, const building_type * bt) -{ - building *b; - unit *owner; - - for (b = rbuildings(r); b; b = b->next) { - owner = building_owner(b); - if (b->type == bt && owner != NULL) { - if (b->size >= bt->maxsize) { - return owner; - } - } - } - - return NULL; -} - -boolean -buildingtype_exists(const region * r, const building_type * bt, boolean working) -{ - building *b; - - for (b = rbuildings(r); b; b = b->next) { - if (b->type == bt) { - if (b->size >= bt->maxsize) { - return true; - } - } - } - - return false; -} - -/* Prüft, ob Ablegen von einer Küste in eine der erlaubten Richtungen erfolgt. */ - -static boolean -check_takeoff(ship *sh, region *from, region *to) -{ - if (!fval(from->terrain, SEA_REGION) && sh->coast != NODIRECTION) { - direction_t coast = sh->coast; - direction_t dir = reldirection(from, to); - direction_t coastr = (direction_t)((coast+1) % MAXDIRECTIONS); - direction_t coastl = (direction_t)((coast+MAXDIRECTIONS-1) % MAXDIRECTIONS); - - if (dir!=coast && dir!=coastl && dir!=coastr - && !buildingtype_exists(from, bt_find("harbour"), true)) - { - return false; - } - } - - return true; -} - -static void -sail(unit * u, order * ord, boolean move_on_land, region_list **routep) -{ - region *starting_point = u->region; - region *current_point, *last_point; - int k, step = 0; - region_list **iroute = routep; - ship * sh = u->ship; - faction * f = u->faction; - region * next_point = NULL; - int error; - const char * token = getstrtoken(); - - if (routep) *routep = NULL; - - error = movewhere(u, token, starting_point, &next_point); - if (error) { - message * msg = movement_error(u, token, ord, error); - if (msg!=NULL) { - add_message(&u->faction->msgs, msg); - msg_release(msg); - } - return; - } - - if (!ship_ready(starting_point, u)) return; - - /* Wir suchen so lange nach neuen Richtungen, wie es geht. Diese werden - * dann nacheinander ausgeführt. */ - - k = shipspeed(sh, u); - - last_point = starting_point; - current_point = starting_point; - - /* die nächste Region, in die man segelt, wird durch movewhere () aus der - * letzten Region bestimmt. - * - * Anfangen tun wir bei starting_point. next_point ist beim ersten - * Durchlauf schon gesetzt (Parameter!). current_point ist die letzte gültige, - * befahrene Region. */ - - while (next_point && current_point!=next_point && step < k) { - const char * token; - int error; - const terrain_type * tthis = current_point->terrain; - /* these values need to be updated if next_point changes (due to storms): */ - const terrain_type * tnext = next_point->terrain; - direction_t dir = reldirection(current_point, next_point); - - assert(sh == u->ship || !"ship has sunk, but we didn't notice it"); - - if (fval(next_point->terrain, FORBIDDEN_REGION)) { - ADDMSG(&f->msgs, msg_message("sailforbidden", - "ship region", sh, next_point)); - break; - } - - if (!flying_ship(sh)) { - int stormchance; - static int stormyness; - static int gamecookie = -1; - - if (gamecookie != global.cookie) { - gamedate date; - get_gamedate(turn, &date); - stormyness = storms[date.month] * 5; - gamecookie = global.cookie; - } - - /* storms should be the first thing we do. */ - stormchance = stormyness / shipspeed(sh, u); - if (check_leuchtturm(next_point, NULL)) stormchance /= 3; - - if (rng_int()%10000 < stormchance*sh->type->storm && fval(current_point->terrain, SEA_REGION)) { - if (!is_cursed(sh->attribs, C_SHIP_NODRIFT, 0)) { - region * rnext = NULL; - boolean storm = true; - int d_offset = rng_int() % MAXDIRECTIONS; - direction_t d; - /* Sturm nur, wenn nächste Region Hochsee ist. */ - for (d=0;d!=MAXDIRECTIONS;++d) { - direction_t dnext = (direction_t)((d + d_offset) % MAXDIRECTIONS); - region * rn = rconnect(current_point, dnext); - - if (rn!=NULL) { - if (fval(rn->terrain, FORBIDDEN_REGION)) continue; - if (!fval(rn->terrain, SEA_REGION)) { - storm = false; - break; - } - if (rn!=next_point) rnext = rn; - } - } - if (storm && rnext!=NULL) { - ADDMSG(&f->msgs, msg_message("storm", "ship region sink", - sh, current_point, sh->damage>=sh->size * DAMAGE_SCALE)); - - /* damage the ship. we handle destruction in the end */ - damage_ship(sh, damage_drift()); - if (sh->damage>=sh->size * DAMAGE_SCALE) break; - - next_point = rnext; - /* these values need to be updated if next_point changes (due to storms): */ - tnext = next_point->terrain; - dir = reldirection(current_point, next_point); - } - } - } - - if (!fval(tthis, SEA_REGION)) { - if (!fval(tnext, SEA_REGION)) { - if (!move_on_land) { - /* check that you're not traveling from one land region to another. */ - ADDMSG(&u->faction->msgs, msg_message("shipnoshore", - "ship region", sh, next_point)); - break; - } - } else { - if (check_takeoff(sh, current_point, next_point) == false) { - /* Schiff kann nicht ablegen */ - cmistake(u, ord, 182, MSG_MOVE); - break; - } - } - } else if (fval(tnext, SEA_REGION)) { - /* target region is an ocean, and we're not leaving a shore */ - if (!(sh->type->flags & SFL_OPENSEA)) { - /* ship can only stay close to shore */ - direction_t d; - - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rc = rconnect(next_point, d); - if (rc==NULL || !fval(rc->terrain, SEA_REGION)) break; - } - if (d == MAXDIRECTIONS) { - /* Schiff kann nicht aufs offene Meer */ - cmistake(u, ord, 249, MSG_MOVE); - break; - } - } - } - - if (!ship_allowed(sh, next_point)) { - /* for some reason or another, we aren't allowed in there.. */ - if (check_leuchtturm(current_point, NULL)) { - ADDMSG(&f->msgs, msg_message("sailnolandingstorm", "ship", sh)); - } else { - ADDMSG(&f->msgs, msg_message("sailnolanding", "ship region", sh, next_point)); - damage_ship(sh, 0.10); - /* we handle destruction at the end */ - } - break; - } - - - if (curse_active(get_curse(next_point->attribs, ct_find("maelstrom")))) { - if (do_maelstrom(next_point, u) == NULL) break; - } - - } /* !flying_ship */ - - /* Falls Blockade, endet die Seglerei hier */ - if (move_blocked(u, current_point, next_point)) { - ADDMSG(&u->faction->msgs, msg_message("sailfail", "ship region", sh, current_point)); - break; - } - - /* Falls kein Problem, eines weiter ziehen */ - fset(sh, SF_MOVED); - if (iroute) { - add_regionlist(iroute, next_point); - iroute = &(*iroute)->next; - } - step++; - - last_point = current_point; - current_point = next_point; - - if (!fval(current_point->terrain, SEA_REGION) && !is_cursed(sh->attribs, C_SHIP_FLYING, 0)) break; - token = getstrtoken(); - error = movewhere(u, token, current_point, &next_point); - if (error || next_point == NULL) { - message * msg = movement_error(u, token, ord, error); - if (msg!=NULL) { - add_message(&u->faction->msgs, msg); - msg_release(msg); - } - next_point = current_point; - break; - } - } - - if (sh->damage>=sh->size * DAMAGE_SCALE) { - if (sh->region) { - ADDMSG(&f->msgs, msg_message("shipsink", "ship", sh)); - remove_ship(&sh->region->ships, sh); - } - sh = NULL; - } - - /* Nun enthält current_point die Region, in der das Schiff seine Runde - * beendet hat. Wir generieren hier ein Ereignis für den Spieler, das - * ihm sagt, bis wohin er gesegelt ist, falls er überhaupt vom Fleck - * gekommen ist. Das ist nicht der Fall, wenn er von der Küste ins - * Inland zu segeln versuchte */ - - if (sh!=NULL && fval(sh, SF_MOVED)) { - unit * hafenmeister; - /* nachdem alle Richtungen abgearbeitet wurden, und alle Einheiten - * transferiert wurden, kann der aktuelle Befehl gelöscht werden. */ - cycle_route(ord, u, step); - set_order(&u->thisorder, NULL); - set_coast(sh, last_point, current_point); - - if( is_cursed(sh->attribs, C_SHIP_FLYING, 0) ) { - ADDMSG(&f->msgs, msg_message("shipfly", "ship from to", sh, starting_point, current_point)); - } else { - ADDMSG(&f->msgs, msg_message("shipsail", "ship from to", sh, starting_point, current_point)); - } - - /* Das Schiff und alle Einheiten darin werden nun von - * starting_point nach current_point verschoben */ - - /* Verfolgungen melden */ - if (fval(u, UFL_FOLLOWING)) caught_target(current_point, u); - - sh = move_ship(sh, starting_point, current_point, *routep); - - /* Hafengebühren ? */ - - hafenmeister = owner_buildingtyp(current_point, bt_find("harbour")); - if (sh && hafenmeister != NULL) { - item * itm; - unit * u2; - item * trans = NULL; - - for (u2 = current_point->units; u2; u2 = u2->next) { - if (u2->ship == sh && - !alliedunit(hafenmeister, u->faction, HELP_GUARD)) { - - - if (effskill(hafenmeister, SK_PERCEPTION) > effskill(u2, SK_STEALTH)) { - for (itm=u2->items; itm; itm=itm->next) { - const luxury_type * ltype = resource2luxury(itm->type->rtype); - if (ltype!=NULL && itm->number>0) { - int st = itm->number * effskill(hafenmeister, SK_TRADE) / 50; - st = MIN(itm->number, st); - - if (st > 0) { - i_change(&u2->items, itm->type, -st); - i_change(&hafenmeister->items, itm->type, st); - i_add(&trans, i_new(itm->type, st)); - } - } - } - } - } - } - if (trans) { - message * msg = msg_message("harbor_trade", "unit items ship", hafenmeister, trans, u->ship); - add_message(&u->faction->msgs, msg); - add_message(&hafenmeister->faction->msgs, msg); - msg_release(msg); - while (trans) i_remove(&trans, trans); - } - } - } -} - -unit * -get_captain(const ship * sh) -{ - const region * r = sh->region; - unit *u; - - for (u = r->units; u; u = u->next) { - if (u->ship == sh && eff_skill(u, SK_SAILING, r) >= sh->type->cptskill) - return u; - } - - return NULL; -} - -/* Segeln, Wandern, Reiten -* when this routine returns a non-zero value, movement for the region needs -* to be done again because of followers that got new MOVE orders. -* Setting FL_LONGACTION will prevent a unit from being handled more than once -* by this routine -* -* the token parser needs to be initialized before calling this function! -*/ - -/** fleeing units use this function -*/ -void -run_to(unit * u, region * to) -{ - region_list * route = NULL; - add_regionlist(&route, to); - travel_route(u, route, NULL, NULL, TRAVEL_RUNNING); - free_regionlist(route); - /* weder transport noch follow */ -} - -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; - - if (u->building && !can_leave(u)) { - cmistake(u, u->thisorder, 150, MSG_MOVE); - return route_begin; - } - switch (canwalk(u)) { - case E_CANWALK_TOOHEAVY: - cmistake(u, ord, 57, MSG_MOVE); - return route_begin; - case E_CANWALK_TOOMANYHORSES: - cmistake(u, ord, 56, MSG_MOVE); - return route_begin; - case E_CANWALK_TOOMANYCARTS: - cmistake(u, ord, 42, MSG_MOVE); - return route_begin; - } - route_end = cap_route(r, route_begin, route_end, movement_speed(u)); - - route_end = travel_route(u, route_begin, route_end, ord, mode); - get_followers(u, r, route_end, followers); - - /* transportation */ - for (ord = u->orders; ord; ord = ord->next) { - unit * ut; - - if (get_keyword(ord) != K_TRANSPORT) continue; - - init_tokens(ord); - skip_token(); - ut = getunit(r, u->faction); - if (ut!=NULL) { - if (get_keyword(ut->thisorder) == K_DRIVE) { - if (ut->building && !can_leave(ut)) { - cmistake(ut, ut->thisorder, 150, MSG_MOVE); - cmistake(u, ord, 99, MSG_MOVE); - } else if (!can_move(ut)) { - cmistake(u, ord, 99, MSG_MOVE); - } else { - boolean found = false; - - if (!fval(ut, UFL_NOTMOVING) && !LongHunger(ut)) { - init_tokens(ut->thisorder); - skip_token(); - if (getunit(u->region, ut->faction) == u) { - const region_list * route_to = travel_route(ut, route_begin, route_end, ord, TRAVEL_TRANSPORTED); - - if (route_to!=route_begin) { - get_followers(ut, r, route_to, followers); - } - ADDMSG(&ut->faction->msgs, msg_message("transport", - "unit target start end", u, ut, r, ut->region)); - found = true; - } - } - if (!found) { - if (cansee(u->faction, u->region, ut, 0)) { - cmistake(u, ord, 90, MSG_MOVE); - } else { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } - } - } - } - } else { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } - } - return route_end; -} - -/** traveling without ships - * walking, flying or riding units use this function - */ -static void -travel(unit * u, region_list ** routep) -{ - region * r = u->region; - region_list * route_begin = NULL; - follower * followers = NULL; - - if (routep) *routep = NULL; - - /* a few pre-checks that need not be done for each step: */ - if (!fval(r->terrain, SEA_REGION)) { - ship * sh = u->ship; - - if (!can_leave(u)) { - cmistake(u, u->thisorder, 150, MSG_MOVE); - return; - } - - /* An Land kein NACH wenn in dieser Runde Schiff VERLASSEN! */ - if (sh == NULL) { - sh = leftship(u); - if (sh && sh->region!=u->region) sh = NULL; - } - if (sh) { - unit * guard = is_guarded(r, u, GUARD_LANDING); - if (guard) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "region_guarded", "guard", guard)); - return; - } - } - if (u->ship && u->race->flags & RCF_SWIM) { - cmistake(u, u->thisorder, 143, MSG_MOVE); - return; - } - } - else if (u->ship && fval(u->ship, SF_MOVED)) { - /* die Einheit ist auf einem Schiff, das sich bereits bewegt hat */ - cmistake(u, u->thisorder, 13, MSG_MOVE); - return; - } - - make_route(u, u->thisorder, routep); - route_begin = *routep; - - /* und ab die post: */ - travel_i(u, route_begin, NULL, u->thisorder, TRAVEL_NORMAL, &followers); - - /* followers */ - while (followers!=NULL) { - follower * fnext = followers->next; - unit * uf = followers->uf; - unit * ut = followers->ut; - const region_list * route_end = followers->route_end; - - free(followers); - followers = fnext; - - if (uf->region == r) { - order * follow_order; - const struct locale * lang = u->faction->locale; - - /* construct an order */ - follow_order = create_order(K_FOLLOW, lang, "%s %i", - LOC(uf->faction->locale, parameters[P_UNIT]), ut->no); - - route_end = reroute(uf, route_begin, route_end); - travel_i(uf, route_begin, route_end, follow_order, TRAVEL_FOLLOWING, &followers); - caught_target(uf->region, uf); - free_order(follow_order); - } - } - -} - -static void -move(unit * u, boolean move_on_land) -{ - region_list * route = NULL; - - assert(u->number); - if (u->ship && fval(u, UFL_OWNER)) { - sail(u, u->thisorder, move_on_land, &route); - } else { - travel(u, &route); - } - - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - set_order(&u->thisorder, NULL); - - if (route!=NULL) free_regionlist(route); -} - -typedef struct piracy_data { - const struct faction * pirate; - const struct faction * target; - direction_t dir; -} piracy_data; - -static void -piracy_init(struct attrib * a) -{ - a->data.v = calloc(1, sizeof(piracy_data)); -} - -static void -piracy_done(struct attrib * a) -{ - free(a->data.v); -} - -static attrib_type at_piracy_direction = { - "piracy_direction", - piracy_init, - piracy_done, - DEFAULT_AGE, - NO_WRITE, - NO_READ -}; - -static attrib * -mk_piracy(const faction * pirate, const faction * target, direction_t target_dir) -{ - attrib * a = a_new(&at_piracy_direction); - piracy_data * data = a->data.v; - data->pirate = pirate; - data->target = target; - data->dir = target_dir; - return a; -} - -static void -piracy_cmd(unit *u, struct order * ord) -{ - region *r = u->region; - ship *sh = u->ship, *sh2; - direction_t dir, target_dir = NODIRECTION; - struct { - const faction * target; - int value; - } aff[MAXDIRECTIONS]; - int saff = 0; - int *il = NULL; - const char *s; - attrib *a; - - if (!sh) { - cmistake(u, ord, 144, MSG_MOVE); - return; - } - - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 146, MSG_MOVE); - return; - } - - /* Feststellen, ob schon ein anderer alliierter Pirat ein - * Ziel gefunden hat. */ - - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - if (s!=NULL && *s) { - il = intlist_init(); - while (s && *s) { - il = intlist_add(il, atoi36(s)); - s = getstrtoken(); - } - } - - for (a = a_find(r->attribs, &at_piracy_direction); a && a->type==&at_piracy_direction; a=a->next) { - piracy_data * data = a->data.v; - const faction * p = data->pirate; - const faction * t = data->target; - - if (alliedunit(u, p, HELP_FIGHT)) { - if (il == 0 || (t && intlist_find(il, t->no))) { - target_dir = data->dir; - break; - } - } - } - - /* Wenn nicht, sehen wir, ob wir ein Ziel finden. */ - - if (target_dir == NODIRECTION) { - /* Einheit ist also Kapitän. Jetzt gucken, in wievielen - * Nachbarregionen potentielle Opfer sind. */ - - for(dir = 0; dir < MAXDIRECTIONS; dir++) { - region *rc = rconnect(r, dir); - aff[dir].value = 0; - aff[dir].target = 0; - if (rc && fval(rc->terrain, SWIM_INTO) - && check_takeoff(sh, r, rc) == true) { - - for (sh2 = rc->ships; sh2; sh2 = sh2->next) { - unit * cap = shipowner(sh2); - if (cap) { - faction * f = visible_faction(cap->faction, cap); - if (alliedunit(u, f, HELP_FIGHT)) continue; - if (il == 0 || intlist_find(il, cap->faction->no)) { - ++aff[dir].value; - if (rng_int() % aff[dir].value == 0) { - aff[dir].target = f; - } - } - } - } - - /* Und aufaddieren. */ - saff += aff[dir].value; - } - } - - if (saff != 0) { - saff = rng_int() % saff; - for (dir=0; dir!=MAXDIRECTIONS; ++dir) { - if (saff!=aff[dir].value) break; - saff -= aff[dir].value; - } - target_dir = dir; - a = a_add(&r->attribs, mk_piracy(u->faction, aff[dir].target, target_dir)); - } - } - - free(il); - - /* Wenn kein Ziel gefunden, entsprechende Meldung generieren */ - if (target_dir == NODIRECTION) { - ADDMSG(&u->faction->msgs, msg_message("piratenovictim", - "ship region", sh, r)); - return; - } - - /* Meldung generieren */ - ADDMSG(&u->faction->msgs, msg_message("piratesawvictim", - "ship region dir", sh, r, target_dir)); - - /* Befehl konstruieren */ - set_order(&u->thisorder, create_order(K_MOVE, u->faction->locale, "%s", - LOC(u->faction->locale, directions[target_dir]))); - - /* Bewegung ausführen */ - init_tokens(u->thisorder); - skip_token(); - move(u, true); -} - -static void -age_traveldir(region *r) -{ - attrib *a = a_find(r->attribs, &at_traveldir); - - while(a && a->type==&at_traveldir) { - attrib *an = a->next; - a->data.ca[3]--; - if(a->data.ca[3] <= 0) { - a_remove(&r->attribs, a); - } - a = an; - } -} - -static direction_t -hunted_dir(attrib *at, int id) -{ - attrib *a = a_find(at, &at_shiptrail); - direction_t d = NODIRECTION; - - while (a!=NULL && a->type==&at_shiptrail) { - traveldir *t = (traveldir *)(a->data.v); - if (t->no == id) { - d = t->dir; - /* do not break, because we want the last one for this ship */ - } - a = a->next; - } - - return d; -} - -static int -hunt(unit *u, order * ord) -{ - region *rc = u->region; - int bytes, moves, id, speed; - char command[256], * bufp = command; - size_t size = sizeof(command); - direction_t dir; - - if (fval(u, UFL_NOTMOVING)) { - return 0; - } else if (u->ship == NULL) { - cmistake(u, ord, 144, MSG_MOVE); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ - return 0; - } else if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 146, MSG_MOVE); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ - return 0; - } else if (!can_move(u)) { - cmistake(u, ord, 55, MSG_MOVE); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ - return 0; - } - - id = getshipid(); - - if (id <= 0) { - cmistake(u, ord, 20, MSG_MOVE); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ - return 0; - } - - dir = hunted_dir(rc->attribs, id); - - if (dir == NODIRECTION) { - ship * sh = findship(id); - if (sh == NULL || sh->region!=rc) { - cmistake(u, ord, 20, MSG_MOVE); - } - fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ - return 0; - } - - bufp = command; - bytes = snprintf(bufp, size, "%s %s", LOC(u->faction->locale, keywords[K_MOVE]), - LOC(u->faction->locale, directions[dir])); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - moves = 1; - - speed = getuint(); - if (speed==0) { - speed = shipspeed(u->ship, u); - } else { - int maxspeed = shipspeed(u->ship, u); - if (maxspeedattribs, id)) != NODIRECTION) - { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(u->faction->locale, directions[dir]), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - moves++; - rc = rconnect(rc, dir); - } - - /* In command steht jetzt das NACH-Kommando. */ - - /* NACH ignorieren und Parsing initialisieren. */ - igetstrtoken(command); - /* NACH ausführen */ - move(u, false); - return 1; /* true -> Einheitenliste von vorne durchgehen */ -} - -void -destroy_damaged_ships(void) -{ - region *r; - ship *sh,*shn; - - for(r=regions;r;r=r->next) { - for(sh=r->ships;sh;) { - shn = sh->next; - if (sh->damage>=sh->size * DAMAGE_SCALE) { - remove_ship(&sh->region->ships, sh); - } - sh = shn; - } - } -} - -/* Bewegung, Verfolgung, Piraterie */ - -/** ships that folow other ships - * Dann generieren die jagenden Einheiten ihre Befehle und - * bewegen sich. - * Following the trails of other ships. - */ -static void -move_hunters(void) -{ - region *r; - - for (r = regions; r; r = r->next) { - unit ** up = &r->units; - - while (*up!=NULL) { - unit * u = *up; - - if (!fval(u, UFL_MOVED|UFL_NOTMOVING)) { - order * ord; - - for (ord=u->orders;ord;ord=ord->next) { - if (get_keyword(ord) == K_FOLLOW) { - param_t p; - - init_tokens(ord); - skip_token(); - p = getparam(u->faction->locale); - if (p != P_SHIP) { - if (p != P_UNIT) { - cmistake(u, ord, 240, MSG_MOVE); - } - break; - } - - /* wir folgen definitiv einem Schiff. */ - - if (fval(u, UFL_NOTMOVING)) { - cmistake(u, ord, 52, MSG_MOVE); - break; - } else if (!can_move(u)) { - cmistake(u, ord, 55, MSG_MOVE); - break; - } - - if (!fval(u, UFL_NOTMOVING) && !LongHunger(u) && hunt(u, ord)) { - up = &r->units; - break; - } - } - } - } - if (*up == u) up=&u->next; - } - } -} - -/** Piraten and Drift - * - */ -static void -move_pirates(void) -{ - region * r; - - for (r = regions; r; r = r->next) { - unit ** up = &r->units; - - while (*up) { - unit *u = *up; - - if (!fval(u, UFL_NOTMOVING) && get_keyword(u->thisorder) == K_PIRACY) { - piracy_cmd(u, u->thisorder); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - } - - if (*up == u) { - /* not moved, use next unit */ - up = &u->next; - } else if (*up && (*up)->region!=r) { - /* moved the previous unit along with u (units on same ship) - * must start from the beginning again */ - up = &r->units; - } - /* else *up is already the next unit */ - } - - a_removeall(&r->attribs, &at_piracy_direction); - age_traveldir(r); - } -} - -void -movement(void) -{ - int ships; - - /* Initialize the additional encumbrance by transported units */ - init_transportation(); - - /* Move ships in last phase, others first - * This is to make sure you can't land someplace and then get off the ship - * in the same turn. - */ - for (ships=0;ships<=1;++ships) { - region * r = regions; - while (r!=NULL) { - unit ** up = &r->units; - boolean repeat = false; - - while (*up) { - unit *u = *up; - keyword_t kword; - - if (u->ship && fval(u->ship, SF_DRIFTED)) { - up = &u->next; - continue; - } - kword = get_keyword(u->thisorder); - - switch (kword) { - case K_ROUTE: - case K_MOVE: - /* after moving, the unit has no thisorder. this prevents - * it from moving twice (or getting error messages twice). - * UFL_NOTMOVING is set in combat if the unit is not allowed - * to move because it was involved in a battle. - */ - if (fval(u, UFL_NOTMOVING)) { - if (fval(u, UFL_LONGACTION)) { - cmistake(u, u->thisorder, 52, MSG_MOVE); - set_order(&u->thisorder, NULL); - } else { - cmistake(u, u->thisorder, 319, MSG_MOVE); - set_order(&u->thisorder, NULL); - } - } else if (fval(u, UFL_MOVED)) { - cmistake(u, u->thisorder, 187, MSG_MOVE); - set_order(&u->thisorder, NULL); - } else if (!can_move(u)) { - cmistake(u, u->thisorder, 55, MSG_MOVE); - set_order(&u->thisorder, NULL); - } else { - if (ships) { - if (u->ship && fval(u, UFL_OWNER)) { - init_tokens(u->thisorder); - skip_token(); - move(u, false); - } - } else { - if (u->ship == NULL || !fval(u, UFL_OWNER)) { - init_tokens(u->thisorder); - skip_token(); - move(u, false); - } - } - } - break; - } - if (u->region == r) { - /* not moved, use next unit */ - up = &u->next; - } else { - if (*up && (*up)->region!=r) { - /* moved the upcoming unit along with u (units on ships or followers, - * for example). must start from the beginning again immediately */ - up = &r->units; - repeat = false; - } else { - repeat = true; - } - } - /* else *up is already the next unit */ - } - if (repeat) continue; - if (ships == 0) { - /* Abtreiben von beschädigten, unterbemannten, überladenen Schiffen */ - drifting_ships(r); - } - r = r->next; - } - } - - move_hunters(); - move_pirates(); -} - -/** Overrides long orders with a FOLLOW order if the target is moving. - * FOLLOW SHIP is a long order, and doesn't need to be treated in here. - * BUGS: http://bugs.eressea.de/view.php?id=1444 (A folgt B folgt C) - */ -void -follow_unit(unit * u) -{ - region * r = u->region; - attrib * a = NULL; - order * ord; - - if (fval(u, UFL_NOTMOVING) || LongHunger(u)) return; - - for (ord=u->orders;ord;ord=ord->next) { - const struct locale * lang = u->faction->locale; - - if (get_keyword(ord) == K_FOLLOW) { - init_tokens(ord); - skip_token(); - if (getparam(lang) == P_UNIT) { - int id = read_unitid(u->faction, r); - - if (a!=NULL) { - a = a_find(u->attribs, &at_follow); - } - - if (id>0) { - unit * uf = findunit(id); - if (!a) { - a = a_add(&u->attribs, make_follow(uf)); - } else { - a->data.v = uf; - } - } else if (a) { - a_remove(&u->attribs, a); - a = NULL; - } - } - } - } - - if (a && !fval(u, UFL_MOVED|UFL_NOTMOVING)) { - unit * u2 = a->data.v; - boolean follow = false; - - if (!u2 || u2->region!=r || !cansee(u->faction, r, u2, 0)) { - return; - } - - switch (get_keyword(u2->thisorder)) { - case K_MOVE: - case K_ROUTE: - case K_DRIVE: - follow = true; - break; - default: - for (ord=u2->orders;ord;ord=ord->next) { - switch (get_keyword(ord)) { - case K_FOLLOW: - case K_PIRACY: - follow = true; - break; - default: - continue; - } - break; - } - break; - } - if (!follow) { - attrib * a2 = a_find(u2->attribs, &at_follow); - if (a2!=NULL) { - unit * u3 = a2->data.v; - follow = (u3 && u2->region == u2->region); - } - } - if (follow) { - fset(u, UFL_FOLLOWING); - fset(u2, UFL_FOLLOWED); - set_order(&u->thisorder, NULL); - } - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "move.h" + +#include "alchemy.h" +#include "connection.h" +#include "build.h" +#include "building.h" +#include "calendar.h" +#include "curse.h" +#include "faction.h" +#include "item.h" +#include "magic.h" +#include "message.h" +#include "order.h" +#include "plane.h" +#include "race.h" +#include "region.h" +#include "render.h" +#include "reports.h" +#include "save.h" +#include "ship.h" +#include "skill.h" +#include "terrain.h" +#include "teleport.h" +#include "unit.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* attributes includes */ +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +int * storms; + +typedef struct traveldir { + int no; + direction_t dir; + int age; +} traveldir; + +static attrib_type at_traveldir = { + "traveldir", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, /* Weil normales Aging an ungünstiger Stelle */ + a_writechars, + a_readchars +}; + +typedef struct follower { + struct follower * next; + unit * uf; + unit * ut; + const region_list * route_end; +} follower; + +static void +get_followers(unit * target, region * r, const region_list * route_end, follower ** followers) +{ + unit * uf; + for (uf=r->units;uf;uf=uf->next) { + if (fval(uf, UFL_FOLLOWING) && !fval(uf, UFL_NOTMOVING)) { + const attrib * a = a_findc(uf->attribs, &at_follow); + if (a && a->data.v == target) { + follower * fnew = malloc(sizeof(follower)); + fnew->uf = uf; + fnew->ut = target; + fnew->route_end = route_end; + fnew->next = *followers; + *followers = fnew; + } + } + } +} + +static void +shiptrail_init(attrib *a) +{ + a->data.v = calloc(1, sizeof(traveldir)); +} + +static void +shiptrail_finalize(attrib *a) +{ + free(a->data.v); +} + +static int +shiptrail_age(attrib *a) +{ + traveldir *t = (traveldir *)(a->data.v); + + t->age--; + return (t->age>0)?AT_AGE_KEEP:AT_AGE_REMOVE; +} + +static int +shiptrail_read(attrib *a, void * owner, struct storage * store) +{ + traveldir *t = (traveldir *)(a->data.v); + + t->no = store->r_int(store); + t->dir = (direction_t)store->r_int(store); + t->age = store->r_int(store); + return AT_READ_OK; +} + +static void +shiptrail_write(const attrib * a, const void * owner, struct storage * store) +{ + traveldir *t = (traveldir *)(a->data.v); + store->w_int(store, t->no); + store->w_int(store, t->dir); + store->w_int(store, t->age); +} + +attrib_type at_shiptrail = { + "traveldir_new", + shiptrail_init, + shiptrail_finalize, + shiptrail_age, + shiptrail_write, + shiptrail_read +}; + +static int +age_speedup(attrib *a) +{ + if (a->data.sa[0] > 0) { + a->data.sa[0] = a->data.sa[0] - a->data.sa[1]; + } + return (a->data.sa[0]>0)?AT_AGE_KEEP:AT_AGE_REMOVE; +} + +attrib_type at_speedup = { + "speedup", + NULL, NULL, + age_speedup, + a_writeint, + a_readint +}; + +/* ------------------------------------------------------------- */ + +direction_t +getdirection(const struct locale * lang) +{ + return finddirection(getstrtoken(), lang); +} +/* ------------------------------------------------------------- */ + +static attrib_type at_driveweight = { + "driveweight", NULL, NULL, NULL, NULL, NULL +}; + +static boolean +entrance_allowed(const struct unit * u, const struct region * r) +{ +#ifdef REGIONOWNERS + faction * owner = region_get_owner(r); + if (owner == NULL || u->faction == owner) return true; + if (alliedfaction(rplane(r), owner, u->faction, HELP_TRAVEL)) return true; + return false; +#else + return true; +#endif +} + +int +personcapacity(const unit *u) +{ + int cap = u->race->weight+u->race->capacity; + return cap; +} + +static int +eff_weight(const unit *u) +{ + attrib *a = a_find(u->attribs, &at_driveweight); + + if (a) return weight(u) + a->data.i; + + return weight(u); +} + +static void +get_transporters(const item * itm, int * p_animals, int *p_acap, int * p_vehicles, int * p_vcap) +{ + int vehicles = 0, vcap = 0; + int animals = 0, acap = 0; + + for (;itm!=NULL;itm=itm->next) { + const item_type * itype = itm->type; + if (itype->capacity>0) { + if (itype->flags & ITF_ANIMAL) { + animals += itm->number; + if (acap==0) acap = itype->capacity; + assert(acap==itype->capacity || !"animals with different capacity not supported"); + } + if (itype->flags & ITF_VEHICLE) { + vehicles += itm->number; + if (vcap==0) vcap = itype->capacity; + assert(vcap==itype->capacity || !"vehicles with different capacity not supported"); + } + } + } + *p_vehicles = vehicles; + *p_animals = animals; + *p_vcap = vcap; + *p_acap = acap; +} + +static int +ridingcapacity(unit * u) +{ + int vehicles = 0, vcap = 0; + int animals = 0, acap = 0; + + get_transporters(u->items, &animals, &acap, &vehicles, &vcap); + + /* Man trägt sein eigenes Gewicht plus seine Kapazität! Die Menschen + ** tragen nichts (siehe walkingcapacity). Ein Wagen zählt nur, wenn er + ** von zwei Pferden gezogen wird */ + + animals = MIN(animals, effskill(u, SK_RIDING) * u->number * 2); + if (fval(u->race, RCF_HORSE)) animals += u->number; + + /* maximal diese Pferde können zum Ziehen benutzt werden */ + vehicles = MIN(animals / HORSESNEEDED, vehicles); + + return vehicles * vcap + animals * acap; +} + +int +walkingcapacity(const struct unit * u) +{ + int n, tmp, people, pferde_fuer_wagen; + int wagen_ohne_pferde, wagen_mit_pferden, wagen_mit_trollen; + int vehicles = 0, vcap = 0; + int animals = 0, acap = 0; + + get_transporters(u->items, &animals, &acap, &vehicles, &vcap); + + /* Das Gewicht, welches die Pferde tragen, plus das Gewicht, welches + * die Leute tragen */ + + pferde_fuer_wagen = MIN(animals, effskill(u, SK_RIDING) * u->number * 4); + if (fval(u->race, RCF_HORSE)) { + animals += u->number; + people = 0; + } else { + people = u->number; + } + + /* maximal diese Pferde können zum Ziehen benutzt werden */ + wagen_mit_pferden = MIN(vehicles, pferde_fuer_wagen / HORSESNEEDED); + + n = wagen_mit_pferden * vcap; + + if (u->race == new_race[RC_TROLL]) { + /* 4 Trolle ziehen einen Wagen. */ + /* Unbesetzte Wagen feststellen */ + wagen_ohne_pferde = vehicles - wagen_mit_pferden; + + /* Genug Trolle, um die Restwagen zu ziehen? */ + wagen_mit_trollen = MIN(u->number / 4, wagen_ohne_pferde); + + /* Wagenkapazität hinzuzählen */ + n += wagen_mit_trollen * vcap; + wagen_ohne_pferde -= wagen_mit_trollen; + } + + n += animals * acap; + n += people * personcapacity(u); + /* Goliathwasser */ + tmp = get_effect(u, oldpotiontype[P_STRONG]); + if (tmp>0) { + int horsecap = olditemtype[I_HORSE]->capacity; + if (tmp>people) tmp = people; + n += tmp * (horsecap - personcapacity(u)); + } + /* change_effect wird in ageing gemacht */ + tmp = get_item(u, I_TROLLBELT); + n += MIN(people, tmp) * (STRENGTHMULTIPLIER-1) * personcapacity(u); + + return n; +} + +enum { + E_CANWALK_OK = 0, + E_CANWALK_TOOMANYHORSES, + E_CANWALK_TOOMANYCARTS, + E_CANWALK_TOOHEAVY +}; + +static int +canwalk(unit * u) +{ + int maxwagen, maxpferde; + int vehicles = 0, vcap = 0; + int animals = 0, acap = 0; + + /* workaround: monsters are too stupid to drop items, therefore they have + * infinite carrying capacity */ + + if (is_monsters(u->faction)) return E_CANWALK_OK; + + get_transporters(u->items, &animals, &acap, &vehicles, &vcap); + + maxwagen = effskill(u, SK_RIDING) * u->number * 2; + if (u->race == new_race[RC_TROLL]) { + maxwagen = MAX(maxwagen, u->number / 4); + } + maxpferde = effskill(u, SK_RIDING) * u->number * 4 + u->number; + + if (animals > maxpferde) + return E_CANWALK_TOOMANYHORSES; + + if (walkingcapacity(u) - eff_weight(u) >= 0) + return E_CANWALK_OK; + + /* Stimmt das Gewicht, impliziert dies hier, daß alle Wagen ohne + * Zugpferde/-trolle als Fracht aufgeladen wurden: zu viele Pferde hat + * die Einheit nicht zum Ziehen benutzt, also nicht mehr Wagen gezogen + * als erlaubt. */ + + if (vehicles > maxwagen) + return E_CANWALK_TOOMANYCARTS; + /* Es muß nicht zwingend an den Wagen liegen, aber egal... (man + * könnte z.B. auch 8 Eisen abladen, damit ein weiterer Wagen als + * Fracht draufpaßt) */ + + return E_CANWALK_TOOHEAVY; +} + +boolean +canfly(unit *u) +{ + if (get_item(u, I_PEGASUS) >= u->number && effskill(u, SK_RIDING) >= 4) + return true; + + if (fval(u->race, RCF_FLY)) return true; + + if (get_movement(&u->attribs, MV_FLY)) return true; + + return false; +} + +boolean +canswim(unit *u) +{ + if (get_item(u, I_DOLPHIN) >= u->number && effskill(u, SK_RIDING) >= 4) + return true; + + if (u->race->flags & RCF_FLY) return true; + + if (u->race->flags & RCF_SWIM) return true; + + if (get_movement(&u->attribs, MV_FLY)) return true; + + if (get_movement(&u->attribs, MV_SWIM)) return true; + + return false; +} + +static int +canride(unit * u) +{ + int horses = 0, maxhorses, unicorns = 0, maxunicorns; + int skill = effskill(u, SK_RIDING); + item * itm; + static const item_type * it_horse = 0; + static const item_type * it_elvenhorse = 0; + static const item_type * it_charger = 0; + + if (it_horse==0) { + it_horse = it_find("horse"); + it_elvenhorse = it_find("elvenhorse"); + it_charger = it_find("charger"); + } + + for (itm=u->items;itm;itm=itm->next) { + if (itm->type==it_horse || itm->type==it_charger) { + horses += itm->number; + } else if (itm->type==it_elvenhorse) { + unicorns += itm->number; + } + } + + maxunicorns = (skill/5) * u->number; + maxhorses = skill * u->number * 2; + + if(!(u->race->flags & RCF_HORSE) + && ((horses == 0 && unicorns == 0) + || horses > maxhorses || unicorns > maxunicorns)) { + return 0; + } + + if (ridingcapacity(u) - eff_weight(u) >= 0) { + if (horses == 0 && unicorns >= u->number && !(u->race->flags & RCF_HORSE)) { + return 2; + } + return 1; + } + + return 0; +} + +static boolean +cansail(const region * r, ship * sh) +{ + /* sonst ist construction:: size nicht ship_type::maxsize */ + assert(!sh->type->construction || sh->type->construction->improvement == NULL); + + if (sh->type->construction && sh->size!=sh->type->construction->maxsize) { + return false; + } else { + int n = 0, p = 0; + int mweight = shipcapacity(sh); + int mcabins = sh->type->cabins; + + getshipweight(sh, &n, &p); + + if (n > mweight) return false; + if (mcabins && p > mcabins) return false; + } + return true; +} + +int +enoughsailors(const ship * sh, const region * r) +{ + int n; + unit *u; + + n = 0; + + for (u = r->units; u; u = u->next) { + if (u->ship == sh) + n += eff_skill(u, SK_SAILING, r) * u->number; + } + return n >= sh->type->sumskill; +} +/* ------------------------------------------------------------- */ + +static ship * +do_maelstrom(region *r, unit *u) +{ + int damage; + ship * sh = u->ship; + + damage = rng_int()%75 + rng_int()%75 - eff_skill(u, SK_SAILING, r)*4; + + if (damage <= 0) { + return sh; + } + + damage_ship(u->ship, 0.01*damage); + + if (sh->damage >= sh->size * DAMAGE_SCALE) { + ADDMSG(&u->faction->msgs, msg_message("entermaelstrom", + "region ship damage sink", r, sh, damage, 1)); + remove_ship(&sh->region->ships, sh); + return NULL; + } + ADDMSG(&u->faction->msgs, msg_message("entermaelstrom", + "region ship damage sink", r, sh, damage, 0)); + return u->ship; +} + +/** sets a marker in the region telling that the unit has travelled through it + * this is used for two distinctly different purposes: + * - to report that a unit has travelled through. the report function + * makes sure to only report the ships of travellers, not the travellers + * themselves + * - to report the region to the traveller + */ +void +travelthru(const unit * u, region * r) +{ + attrib *ru = a_add(&r->attribs, a_new(&at_travelunit)); + + fset(r, RF_TRAVELUNIT); + + ru->data.v = (void*)u; + + /* the first and last region of the faction gets reset, because travelthrough + * could be in regions that are located before the [first, last] interval, + * and recalculation is needed */ +#ifdef SMART_INTERVALS + update_interval(u->faction, r); +#endif +} + +static void +leave_trail(ship * sh, region * from, region_list *route) +{ + region * r = from; + + while (route!=NULL) { + region * rn = route->data; + direction_t dir = reldirection(r, rn); + + /* TODO: we cannot leave a trail into special directions + * if we use this kind of direction-attribute */ + if (dir=0) { + traveldir * td = NULL; + attrib * a = a_find(r->attribs, &at_shiptrail); + + while (a!=NULL && a->type==&at_shiptrail) { + td = (traveldir *)a->data.v; + if (td->no == sh->no) break; + a = a->next; + } + + if (a == NULL || a->type!=&at_shiptrail) { + a = a_add(&(r->attribs), a_new(&at_shiptrail)); + td = (traveldir *)a->data.v; + td->no = sh->no; + } + td->dir = dir; + td->age = 2; + } + route = route->next; + r = rn; + } +} + +static void +mark_travelthru(const unit * u, region * r, const region_list * route, const region_list * route_end) +{ + /* kein travelthru in der letzten region! */ + while (route!=route_end) { + travelthru(u, r); + r = route->data; + route = route->next; + } +} + +ship * +move_ship(ship * sh, region * from, region * to, region_list * route) +{ + unit **iunit = &from->units; + unit **ulist = &to->units; + boolean trail = (route == NULL); + + if (from!=to) { + translist(&from->ships, &to->ships, sh); + sh->region = to; + } + if (!trail) { + leave_trail(sh, from, route); + trail = true; + } + + while (*iunit!=NULL) { + unit *u = *iunit; + assert(u->region == from); + + if (u->ship == sh) { + if (route!=NULL) mark_travelthru(u, from, route, NULL); + if (from!=to) { + u->ship = NULL; /* damit move_unit() kein leave() macht */ + move_unit(u, to, ulist); + ulist = &u->next; + u->ship = sh; + } + if (route && eff_skill(u, SK_SAILING, from) >= 1) { + produceexp(u, SK_SAILING, u->number); + } + } + if (*iunit == u) iunit=&u->next; + } + + return sh; +} + +static boolean +is_freezing(const unit * u) +{ + if (u->race!=new_race[RC_INSECT]) return false; + if (is_cursed(u->attribs, C_KAELTESCHUTZ, 0)) return false; + return true; +} + +static boolean +ship_allowed(const struct ship * sh, const region * r) +{ + int c = 0; + static const building_type * bt_harbour=NULL; + + if (bt_harbour == NULL) bt_harbour=bt_find("harbour"); + + if (r_insectstalled(r)) { + /* insekten dürfen nicht hier rein. haben wir welche? */ + unit * u; + + for (u=sh->region->units;u!=NULL;u=u->next) { + if (u->ship!=sh) continue; + + if (is_freezing(u)) { + unit * captain = shipowner(sh); + if (captain) { + ADDMSG(&captain->faction->msgs, msg_message("detectforbidden", + "unit region", u, r)); + } + + return false; + } + } + } + + if (buildingtype_exists(r, bt_harbour, true)) return true; + for (c=0;sh->type->coasts[c]!=NULL;++c) { + if (sh->type->coasts[c] == r->terrain) return true; + } + + return false; +} + +static boolean +flying_ship(const ship * sh) +{ + if (sh->type->flags & SFL_FLY) return true; + if (sh->flags & SF_FLYING) return true; + return false; +} + +static void +set_coast(ship * sh, region * r, region * rnext) +{ + if (sh->type->flags & SFL_NOCOAST) { + sh->coast = NODIRECTION; + } else if (!fval(rnext->terrain, SEA_REGION) && !flying_ship(sh)) { + sh->coast = reldirection(rnext, r); + assert(fval(r->terrain, SEA_REGION)); + } else { + sh->coast = NODIRECTION; + } +} + +static float +damage_drift(void) +{ + static float value = -1.0F; + if (value<0) { + value = get_param_flt(global.parameters, "rules.ship.damage_drift", 0.02F); + } + return value; +} + +static void +drifting_ships(region * r) +{ + direction_t d; + + if (fval(r->terrain, SEA_REGION)) { + ship** shp = &r->ships; + while (*shp) { + ship * sh = *shp; + region * rnext = NULL; + region_list * route = NULL; + unit *firstu = NULL, *captain; + int d_offset; + direction_t dir = 0; + + if (sh->type->fishing>0) { + sh->flags |= SF_FISHING; + } + + /* Schiff schon abgetrieben oder durch Zauber geschützt? */ + if (fval(sh, SF_DRIFTED) || is_cursed(sh->attribs, C_SHIP_NODRIFT, 0)) { + shp = &sh->next; + continue; + } + + /* Kapitän bestimmen */ + for (captain = r->units; captain; captain = captain->next) { + if (captain->ship != sh) continue; + if (firstu==NULL) firstu = captain; + if (eff_skill(captain, SK_SAILING, r) >= sh->type->cptskill) { + break; + } + } + /* Kapitän da? Beschädigt? Genügend Matrosen? + * Genügend leicht? Dann ist alles OK. */ + + assert(sh->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (captain && sh->size == sh->type->construction->maxsize && enoughsailors(sh, r) && cansail(r, sh)) { + shp = &sh->next; + continue; + } + + /* Auswahl einer Richtung: Zuerst auf Land, dann + * zufällig. Falls unmögliches Resultat: vergiß es. */ + d_offset = rng_int() % MAXDIRECTIONS; + for (d = 0; d != MAXDIRECTIONS; ++d) { + region * rn; + dir = (direction_t)((d + d_offset) % MAXDIRECTIONS); + rn = rconnect(r, dir); + if (rn!=NULL && fval(rn->terrain, SAIL_INTO) && ship_allowed(sh, rn)) { + rnext = rn; + if (!fval(rnext->terrain, SEA_REGION)) break; + } + } + + if (rnext == NULL) { + shp = &sh->next; + continue; + } + + /* Das Schiff und alle Einheiten darin werden nun von r + * nach rnext verschoben. Danach eine Meldung. */ + add_regionlist(&route, rnext); + + set_coast(sh, r, rnext); + sh = move_ship(sh, r, rnext, route); + free_regionlist(route); + + if (firstu!=NULL) { + unit *u, *lastu = NULL; + message * msg = msg_message("ship_drift", "ship dir", sh, dir); + for (u=firstu;u;u=u->next) { + if (u->ship==sh && !fval(u->faction, FFL_MARK)) { + fset(u->faction, FFL_MARK); + add_message(&u->faction->msgs, msg); + lastu = u->next; + } + } + for (u=firstu;u!=lastu;u=u->next) { + freset(u->faction, FFL_MARK); + } + msg_release(msg); + } + + if (sh!=NULL) { + fset(sh, SF_DRIFTED); + + damage_ship(sh, damage_drift()); + if (sh->damage>=sh->size * DAMAGE_SCALE) { + remove_ship(&sh->region->ships, sh); + } + } + + if (*shp == sh) shp = &sh->next; + } + } +} + +static boolean +present(region * r, unit * u) +{ + return (boolean) (u && u->region == r); +} + +static void +caught_target(region * r, unit * u) +{ + attrib * a = a_find(u->attribs, &at_follow); + + /* Verfolgungen melden */ + /* Misserfolgsmeldung, oder bei erfolgreichem Verfolgen unter + * Umstaenden eine Warnung. */ + + if (a) { + unit * target = (unit*)a->data.v; + + if (!present(r, target)) { + ADDMSG(&u->faction->msgs, msg_message("followfail", "unit follower", + target, u)); + } else if (!alliedunit(target, u->faction, HELP_ALL) + && cansee(target->faction, r, u, 0)) + { + ADDMSG(&target->faction->msgs, msg_message("followdetect", + "unit follower", target, u)); + } + } +} + +/* TODO: Unsichtbarkeit bedenken ! */ + +static unit * +bewegung_blockiert_von(unit * reisender, region * r) +{ + unit *u; + int perception = 0; + boolean contact = false; + unit * guard = NULL; + + if (fval(reisender->race, RCF_ILLUSIONARY)) return NULL; + for (u=r->units;u && !contact;u=u->next) { + if (is_guard(u, GUARD_TRAVELTHRU)) { + int sk = eff_skill(u, SK_PERCEPTION, r); + if (invisible(reisender, u) >= reisender->number) continue; + if (u->faction == reisender->faction) contact = true; + else if (ucontact(u, reisender)) contact = true; + else if (alliedunit(u, reisender->faction, HELP_GUARD)) contact = true; + else if (sk>=perception) { + perception = sk; + guard = u; + } + } + } + if (!contact && guard) { + double prob = 0.3; /* 30% base chance */ + prob += 0.1 * (perception - eff_stealth(reisender, r)); + prob += 0.1 * MIN(guard->number, get_item(guard, I_AMULET_OF_TRUE_SEEING)); + + if (chance(prob)) { + return guard; + } + } + return NULL; +} + +static boolean +is_guardian_u(const unit * guard, unit *u, unsigned int mask) +{ + if (guard->faction == u->faction) return false; + if (is_guard(guard, mask) == 0) return false; + if (alliedunit(guard, u->faction, HELP_GUARD)) return false; + if (ucontact(guard, u)) return false; + if (!cansee(guard->faction, u->region, u, 0)) return false; + + return true; +} + +static boolean +is_guardian_r(const unit * guard) +{ + if (guard->number == 0) return false; + if (besieged(guard)) return false; + + /* if region_owners exist then they may be guardians: */ + if (guard->building && rule_region_owners() && fval(guard, UFL_OWNER)) { + faction * owner = region_get_owner(guard->region); + if (owner==guard->faction) { + building * bowner = largestbuilding(guard->region, &cmp_taxes, false); + if (bowner==guard->building) { + return true; + } + } + } + + if ((guard->flags&UFL_GUARD)==0) return false; + if (!armedmen(guard, true) && !fval(guard->race, RCF_UNARMEDGUARD)) return false; + return true; +} + +boolean is_guard(const struct unit * u, int mask) +{ + return is_guardian_r(u) && (getguard(u) & mask)!=0; +} + +#define MAXGUARDCACHE 16 +/** returns the guard which prevents 'u' from doing 'mask' actions in 'r'. +*/ +unit * +is_guarded(region * r, unit * u, unsigned int mask) +{ + unit *u2 = NULL; + int i, noguards = 1; + static unit * guardcache[MAXGUARDCACHE], * lastguard; /* STATIC_XCALL: used across calls */ + static int gamecookie = -1; + + if (!fval(r, RF_GUARDED)) { + return NULL; + } + + if (gamecookie!=global.cookie) { + if (gamecookie>=0) { + /* clear the previous turn's cache */ + memset(guardcache, 0, sizeof(guardcache)); + lastguard = NULL; + } + gamecookie = global.cookie; + } + + if (lastguard && lastguard->region==r) { + if (is_guardian_u(lastguard, u, mask)) { + return lastguard; + } + } + + for (i=0;i!=MAXGUARDCACHE;++i) { + unit * guard = guardcache[i]; + if (guard && guard!=lastguard && guard->region==r) { + noguards = 0; + if (is_guardian_u(guard, u, mask)) { + lastguard = guard; + return guard; + } + if (u2==guard) { + /* same guard twice signals we've tested everyone */ + return NULL; + } + u2 = guard; + } else { + /* exhausted all the guards in the cache, but maybe we'll find one later? */ + break; + } + } + + /* at this point, u2 is the last unit we tested to + * be a guard (and failed), or NULL + * i is the position of the first free slot in the cache */ + + for (u2 = (u2?u2->next:r->units); u2; u2=u2->next) { + if (is_guardian_r(u2)) { + noguards = 0; + /* u2 is a guard, so worth remembering */ + if (i0 && ifaction->locale; + pause = false; + token = getstrtoken(); + d = finddirection(token, lang); + if(d == D_PAUSE) { + pause = true; + } else if (d == NODIRECTION) { + break; + } + if (cmsizeof(neworder)/2) break; + else if (cm == gereist && !paused && pause) { + const char * loc = LOC(lang, parameters[P_PAUSE]); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, loc, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + paused = true; + } + else if (pause) { + /* da PAUSE nicht in ein shortdirections[d] umgesetzt wird (ist + * hier keine normale direction), muss jede PAUSE einzeln + * herausgefiltert und explizit gesetzt werden */ + if (neworder[0]) strcat(neworder, " "); + strcat(neworder, LOC(lang, parameters[P_PAUSE])); + } else { + if (neworder[0]) strcat(neworder, " "); + strcat(neworder, LOC(lang, shortdirections[d])); + } + } + + if (neworder[0]) { + norder = create_order(K_ROUTE, u->faction->locale, "%s %s", neworder, tail); + } else { + norder = create_order(K_ROUTE, u->faction->locale, "%s", tail); + } + replace_order(&u->orders, ord, norder); + free_order(norder); +} + +static boolean +transport(unit * ut, unit * u) +{ + order * ord; + + if (LongHunger(u) || fval(ut->region->terrain, SEA_REGION)) { + return false; + } + + for (ord = ut->orders; ord; ord = ord->next) { + if (get_keyword(ord) == K_TRANSPORT) { + init_tokens(ord); + skip_token(); + if (getunit(ut->region, ut->faction) == u) { + return true; + } + } + } + return false; +} + +static boolean +can_move(const unit * u) +{ + if (u->race->flags & RCF_CANNOTMOVE) return false; + if (get_movement(&u->attribs, MV_CANNOTMOVE)) return false; + return true; +} + +static void +init_transportation(void) +{ + region *r; + + for (r=regions; r; r=r->next) { + unit *u; + + /* This is just a simple check for non-corresponding K_TRANSPORT/ + * K_DRIVE. This is time consuming for an error check, but there + * doesn't seem to be an easy way to speed this up. */ + for (u=r->units; u; u=u->next) { + if (get_keyword(u->thisorder) == K_DRIVE && can_move(u) && !fval(u, UFL_NOTMOVING) && !LongHunger(u)) { + unit * ut; + + init_tokens(u->thisorder); + skip_token(); + ut = getunit(r, u->faction); + if (ut == NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); + continue; + } + if (!transport(ut, u)) { + if (cansee(u->faction, r, ut, 0)) { + cmistake(u, u->thisorder, 286, MSG_MOVE); + } else { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); + } + } + } + } + + /* This calculates the weights of all transported units and + * adds them to an internal counter which is used by travel () to + * calculate effective weight and movement. */ + + if (!fval(r->terrain, SEA_REGION)) { + for (u=r->units; u; u=u->next) { + order * ord; + int w = 0; + + for (ord = u->orders; ord; ord = ord->next) { + if (get_keyword(ord) == K_TRANSPORT) { + init_tokens(ord); + skip_token(); + for (;;) { + unit * ut = getunit(r, u->faction); + + if (ut == NULL) break; + if (get_keyword(ut->thisorder) == K_DRIVE && can_move(ut) && !fval(ut, UFL_NOTMOVING) && !LongHunger(ut)) { + init_tokens(ut->thisorder); + skip_token(); + if (getunit(r, ut->faction) == u) { + w += weight(ut); + } + } + } + } + } + if (w > 0) a_add(&u->attribs, a_new(&at_driveweight))->data.i = w; + } + } + } +} + +static boolean +roadto(const region * r, direction_t dir) +{ + /* wenn es hier genug strassen gibt, und verbunden ist, und es dort + * genug strassen gibt, dann existiert eine strasse in diese richtung */ + region * r2; + static const curse_type * roads_ct = NULL; + + if (dir>=MAXDIRECTIONS || dir<0) return false; + r2 = rconnect(r, dir); + if (r == NULL || r2 == NULL) return false; + + if (roads_ct == NULL) roads_ct = ct_find("magicstreet"); + if (roads_ct!=NULL) { + if (get_curse(r->attribs, roads_ct)!=NULL) return true; + if (get_curse(r2->attribs, roads_ct)!=NULL) return true; + } + + if (r->terrain->max_road <= 0) return false; + if (r2->terrain->max_road <= 0) return false; + if (rroad(r, dir) < r->terrain->max_road) return false; + if (rroad(r2, dir_invert(dir)) < r2->terrain->max_road) return false; + return true; +} + +static const region_list * +cap_route(region * r, const region_list * route, const region_list * route_end, int speed) +{ + region * current = r; + int moves = speed; + const region_list * iroute = route; + while (iroute!=route_end) { + region * next = iroute->data; + direction_t reldir = reldirection(current, next); + + /* adjust the range of the unit */ + if (roadto(current, reldir)) moves -= BP_ROAD; + else moves -= BP_NORMAL; + if (moves<0) break; + iroute = iroute->next; + current = next; + } + return iroute; +} + +static region * +next_region(unit * u, region * current, region * next) +{ + connection * b; + + b = get_borders(current, next); + while (b!=NULL) { + if (b->type->move) { + region * rto = b->type->move(b, u, current, next, true); + if (rto!=next) { + /* the target region was changed (wisps, for example). check the + * new target region for borders */ + next = rto; + b = get_borders(current, next); + continue; + } + } + b = b->next; + } + return next; +} + +static const region_list * +reroute(unit * u, const region_list * route, const region_list * route_end) +{ + region * current = u->region; + while (route!=route_end) { + region * next = next_region(u, current, route->data); + if (next!=route->data) break; + route = route->next; + } + return route; +} + +static void +make_route(unit * u, order * ord, region_list ** routep) +{ + region_list **iroute = routep; + region * current = u->region; + region * next = NULL; + const char * token = getstrtoken(); + int error = movewhere(u, token, current, &next); + + if (error!=E_MOVE_OK) { + message * msg = movement_error(u, token, ord, error); + if (msg!=NULL) { + add_message(&u->faction->msgs, msg); + msg_release(msg); + } + next = NULL; + } + + while (next!=NULL) { + direction_t reldir; + + if (current == next) { + /* PAUSE */ + break; + } + next = next_region(u, current, next); + reldir = reldirection(current, next); + + add_regionlist(iroute, next); + iroute = &(*iroute)->next; + + current = next; + token = getstrtoken(); + error = movewhere(u, token, current, &next); + if (error) { + message * msg = movement_error(u, token, ord, error); + if (msg!=NULL) { + add_message(&u->faction->msgs, msg); + msg_release(msg); + } + next = NULL; + } + } +} + +/** calculate the speed of a unit + * + * zu Fuß reist man 1 Region, zu Pferd 2 Regionen. Mit Straßen reist + * man zu Fuß 2, mit Pferden 3 weit. + * + * Berechnet wird das mit BPs. Zu Fuß hat man 4 BPs, zu Pferd 6. + * 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 mp; + static const curse_type * speed_ct; + static boolean init = false; + double dk = u->race->speed; + + assert(u->number); + /* dragons have a fixed speed, and no other effects work on them: */ + switch (old_race(u->race)) { + case RC_DRAGON: + case RC_WYRM: + case RC_FIREDRAGON: + case RC_BIRTHDAYDRAGON: + case RC_SONGDRAGON: + return BP_DRAGON; + } + + if (!init) { + init = true; + speed_ct = ct_find("speed"); + } + if (speed_ct) { + curse *c = get_curse(u->attribs, speed_ct); + if (c!=NULL) { + int men = get_cursedmen(u, c); + dk *= 1.0 + (double)men/(double)u->number; + } + } + + switch (canride(u)) { + + case 1: /* Pferd */ + mp = BP_RIDING; + break; + + case 2: /* Einhorn */ + mp = BP_UNICORN; + break; + + default: + mp = BP_WALKING; + + /* 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 <= get_item(u, I_FEENSTIEFEL)) { + mp *= 2; + } + + /* Im Astralraum sind Tyb und Ill-Magier doppelt so schnell. + * Nicht kumulativ mit anderen Beschleunigungen! */ + if (mp*dk <= BP_WALKING*u->race->speed && is_astral(u->region) && is_mage(u)) { + sc_mage * mage = get_mage(u); + if (mage->magietyp == M_TYBIED || mage->magietyp == M_ILLAUN) { + mp *= 2; + } + } + break; + } + return (int)(dk*mp); +} + +enum { + TRAVEL_NORMAL, + TRAVEL_FOLLOWING, + TRAVEL_TRANSPORTED, + TRAVEL_RUNNING +}; + +static arg_regions * +var_copy_regions(const region_list * begin, int size) +{ + const region_list * rsrc; + + if (size>0) { + int i = 0; + arg_regions * dst = (arg_regions *)malloc(sizeof(arg_regions) + sizeof(region*) * size); + dst->nregions = size; + dst->regions = (region**)(dst+1); + for (rsrc = begin; i!=size; rsrc=rsrc->next) { + dst->regions[i++] = rsrc->data; + } + return dst; + } + return NULL; +} + + +static const region_list * +travel_route(unit * u, const region_list * route_begin, const region_list * route_end, order * ord, int mode) +{ + region * r = u->region; + region * current = u->region; + const region_list * iroute = route_begin; + int steps = 0; + boolean landing = false; /* aquarians have landed */ + + while (iroute && iroute!=route_end) { + region * next = iroute->data; + direction_t reldir = reldirection(current, next); + connection * b = get_borders(current, next); + + /* check if we are caught by guarding units */ + if (iroute!=route_begin && mode!=TRAVEL_RUNNING && mode!=TRAVEL_TRANSPORTED) { + unit * wache = bewegung_blockiert_von(u, current); + if (wache!=NULL) { + ADDMSG(&u->faction->msgs, msg_message("moveblockedbyguard", + "unit region guard", u, current, wache)); + break; + } + } + + /* check movement from/to oceans. + * aquarian special, flying units, horses, the works */ + if ((u->race->flags & RCF_FLY) == 0) { + if (!fval(next->terrain, SEA_REGION)) { + /* next region is land */ + if (fval(current->terrain, SEA_REGION)) { + int moving = u->race->flags & (RCF_SWIM|RCF_WALK|RCF_COASTAL); + /* Die Einheit kann nicht fliegen, ist im Ozean, und will an Land */ + if (moving != (RCF_SWIM|RCF_WALK) && (moving&RCF_COASTAL) == 0) { + /* can't swim+walk and isn't allowed to enter coast from sea */ + if (ord!=NULL) cmistake(u, ord, 44, MSG_MOVE); + break; + } + landing = true; + } else if ((u->race->flags & RCF_WALK) == 0) { + /* Spezialeinheiten, die nicht laufen können. */ + ADDMSG(&u->faction->msgs, msg_message("detectocean", + "unit region", u, next)); + break; + } else if (landing) { + /* wir sind diese woche angelandet */ + ADDMSG(&u->faction->msgs, msg_message("detectocean", + "unit region", u, next)); + break; + } + } else { + /* Ozeanfelder können nur von Einheiten mit Schwimmen und ohne + * Pferde betreten werden. */ + if (!(canswim(u) || canfly(u))) { + ADDMSG(&u->faction->msgs, msg_message("detectocean", + "unit region", u, next)); + break; + } + } + + if (fval(current->terrain, SEA_REGION) || fval(next->terrain, SEA_REGION)) { + /* trying to enter or exit ocean with horses, are we? */ + if (has_horses(u)) { + /* tries to do it with horses */ + if (ord!=NULL) cmistake(u, ord, 67, MSG_MOVE); + break; + } + } + + } + + /* movement blocked by a wall */ + if (reldir>=0 && move_blocked(u, current, next)) { + ADDMSG(&u->faction->msgs, msg_message("leavefail", + "unit region", u, next)); + break; + } + + /* region ownership only: region owned by enemies */ + if (!entrance_allowed(u, next)) { + ADDMSG(&u->faction->msgs, msg_message("regionowned", + "unit region target", u, current, next)); + break; + } + + /* illusionary units disappear in antimagic zones */ + if (fval(u->race, RCF_ILLUSIONARY)) { + curse * c = get_curse(next->attribs, ct_find("antimagiczone")); + if (curse_active(c)) { + curse_changevigour(&next->attribs, c, (float)-u->number); + ADDMSG(&u->faction->msgs, msg_message("illusionantimagic", "unit", u)); + set_number(u, 0); + break; + } + } + + /* terrain is marked as forbidden (curse, etc) */ + if (fval(next, RF_BLOCKED) || fval(next->terrain, FORBIDDEN_REGION)) { + ADDMSG(&u->faction->msgs, msg_message("detectforbidden", + "unit region", u, next)); + break; + } + + /* unit is an insect and cannot move into a glacier */ + if (u->race == new_race[RC_INSECT]) { + if (r_insectstalled(next) && is_freezing(u)) { + ADDMSG(&u->faction->msgs, msg_message("detectforbidden", + "unit region", u, next)); + break; + } + } + + /* effect of borders */ + while (b!=NULL) { + if (b->type->move) { + b->type->move(b, u, current, next, false); + } + b = b->next; + } + + current = next; + iroute = iroute->next; + ++steps; + if (u->number == 0) break; + } + + if (iroute!=route_begin) { + /* the unit has moved at least one region */ + int walkmode; + + setguard(u, GUARD_NONE); + cycle_route(ord, u, steps); + + if (mode == TRAVEL_RUNNING) { + walkmode = 0; + } if (canride(u)) { + walkmode = 1; + produceexp(u, SK_RIDING, u->number); + } else { + walkmode = 2; + } + + /* Berichte über Durchreiseregionen */ + + if (mode!=TRAVEL_TRANSPORTED) { + arg_regions * ar = var_copy_regions(route_begin, steps-1); + ADDMSG(&u->faction->msgs, msg_message("travel", + "unit mode start end regions", u, walkmode, r, current, ar)); + } + + mark_travelthru(u, r, route_begin, iroute); + move_unit(u, current, NULL); + + /* make orders for the followers */ + } + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + setguard(u, GUARD_NONE); + assert(u->region == current); + return iroute; +} + +static boolean +ship_ready(const region * r, unit * u) +{ + if (!fval(u, UFL_OWNER)) { + cmistake(u, u->thisorder, 146, MSG_MOVE); + return false; + } + if (eff_skill(u, SK_SAILING, r) < u->ship->type->cptskill) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_captain_skill_low", + "value ship", u->ship->type->cptskill, u->ship)); + return false; + } + assert(u->ship->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (u->ship->size!=u->ship->type->construction->maxsize) { + cmistake(u, u->thisorder, 15, MSG_MOVE); + return false; + } + if (!enoughsailors(u->ship, r)) { + cmistake(u, u->thisorder, 1, MSG_MOVE); +/* mistake(u, u->thisorder, + "Auf dem Schiff befinden sich zuwenig erfahrene Seeleute.", MSG_MOVE); */ + return false; + } + if (!cansail(r, u->ship)) { + cmistake(u, u->thisorder, 18, MSG_MOVE); + return false; + } + return true; +} + +unit * +owner_buildingtyp(const region * r, const building_type * bt) +{ + building *b; + unit *owner; + + for (b = rbuildings(r); b; b = b->next) { + owner = building_owner(b); + if (b->type == bt && owner != NULL) { + if (b->size >= bt->maxsize) { + return owner; + } + } + } + + return NULL; +} + +boolean +buildingtype_exists(const region * r, const building_type * bt, boolean working) +{ + building *b; + + for (b = rbuildings(r); b; b = b->next) { + if (b->type == bt) { + if (b->size >= bt->maxsize) { + return true; + } + } + } + + return false; +} + +/* Prüft, ob Ablegen von einer Küste in eine der erlaubten Richtungen erfolgt. */ + +static boolean +check_takeoff(ship *sh, region *from, region *to) +{ + if (!fval(from->terrain, SEA_REGION) && sh->coast != NODIRECTION) { + direction_t coast = sh->coast; + direction_t dir = reldirection(from, to); + direction_t coastr = (direction_t)((coast+1) % MAXDIRECTIONS); + direction_t coastl = (direction_t)((coast+MAXDIRECTIONS-1) % MAXDIRECTIONS); + + if (dir!=coast && dir!=coastl && dir!=coastr + && !buildingtype_exists(from, bt_find("harbour"), true)) + { + return false; + } + } + + return true; +} + +static void +sail(unit * u, order * ord, boolean move_on_land, region_list **routep) +{ + region *starting_point = u->region; + region *current_point, *last_point; + int k, step = 0; + region_list **iroute = routep; + ship * sh = u->ship; + faction * f = u->faction; + region * next_point = NULL; + int error; + const char * token = getstrtoken(); + + if (routep) *routep = NULL; + + error = movewhere(u, token, starting_point, &next_point); + if (error) { + message * msg = movement_error(u, token, ord, error); + if (msg!=NULL) { + add_message(&u->faction->msgs, msg); + msg_release(msg); + } + return; + } + + if (!ship_ready(starting_point, u)) return; + + /* Wir suchen so lange nach neuen Richtungen, wie es geht. Diese werden + * dann nacheinander ausgeführt. */ + + k = shipspeed(sh, u); + + last_point = starting_point; + current_point = starting_point; + + /* die nächste Region, in die man segelt, wird durch movewhere () aus der + * letzten Region bestimmt. + * + * Anfangen tun wir bei starting_point. next_point ist beim ersten + * Durchlauf schon gesetzt (Parameter!). current_point ist die letzte gültige, + * befahrene Region. */ + + while (next_point && current_point!=next_point && step < k) { + const char * token; + int error; + const terrain_type * tthis = current_point->terrain; + /* these values need to be updated if next_point changes (due to storms): */ + const terrain_type * tnext = next_point->terrain; + direction_t dir = reldirection(current_point, next_point); + + assert(sh == u->ship || !"ship has sunk, but we didn't notice it"); + + if (fval(next_point->terrain, FORBIDDEN_REGION)) { + ADDMSG(&f->msgs, msg_message("sailforbidden", + "ship region", sh, next_point)); + break; + } + + if (!flying_ship(sh)) { + int stormchance; + static int stormyness; + static int gamecookie = -1; + + if (gamecookie != global.cookie) { + gamedate date; + get_gamedate(turn, &date); + stormyness = storms[date.month] * 5; + gamecookie = global.cookie; + } + + /* storms should be the first thing we do. */ + stormchance = stormyness / shipspeed(sh, u); + if (check_leuchtturm(next_point, NULL)) stormchance /= 3; + + if (rng_int()%10000 < stormchance*sh->type->storm && fval(current_point->terrain, SEA_REGION)) { + if (!is_cursed(sh->attribs, C_SHIP_NODRIFT, 0)) { + region * rnext = NULL; + boolean storm = true; + int d_offset = rng_int() % MAXDIRECTIONS; + direction_t d; + /* Sturm nur, wenn nächste Region Hochsee ist. */ + for (d=0;d!=MAXDIRECTIONS;++d) { + direction_t dnext = (direction_t)((d + d_offset) % MAXDIRECTIONS); + region * rn = rconnect(current_point, dnext); + + if (rn!=NULL) { + if (fval(rn->terrain, FORBIDDEN_REGION)) continue; + if (!fval(rn->terrain, SEA_REGION)) { + storm = false; + break; + } + if (rn!=next_point) rnext = rn; + } + } + if (storm && rnext!=NULL) { + ADDMSG(&f->msgs, msg_message("storm", "ship region sink", + sh, current_point, sh->damage>=sh->size * DAMAGE_SCALE)); + + /* damage the ship. we handle destruction in the end */ + damage_ship(sh, damage_drift()); + if (sh->damage>=sh->size * DAMAGE_SCALE) break; + + next_point = rnext; + /* these values need to be updated if next_point changes (due to storms): */ + tnext = next_point->terrain; + dir = reldirection(current_point, next_point); + } + } + } + + if (!fval(tthis, SEA_REGION)) { + if (!fval(tnext, SEA_REGION)) { + if (!move_on_land) { + /* check that you're not traveling from one land region to another. */ + ADDMSG(&u->faction->msgs, msg_message("shipnoshore", + "ship region", sh, next_point)); + break; + } + } else { + if (check_takeoff(sh, current_point, next_point) == false) { + /* Schiff kann nicht ablegen */ + cmistake(u, ord, 182, MSG_MOVE); + break; + } + } + } else if (fval(tnext, SEA_REGION)) { + /* target region is an ocean, and we're not leaving a shore */ + if (!(sh->type->flags & SFL_OPENSEA)) { + /* ship can only stay close to shore */ + direction_t d; + + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rc = rconnect(next_point, d); + if (rc==NULL || !fval(rc->terrain, SEA_REGION)) break; + } + if (d == MAXDIRECTIONS) { + /* Schiff kann nicht aufs offene Meer */ + cmistake(u, ord, 249, MSG_MOVE); + break; + } + } + } + + if (!ship_allowed(sh, next_point)) { + /* for some reason or another, we aren't allowed in there.. */ + if (check_leuchtturm(current_point, NULL)) { + ADDMSG(&f->msgs, msg_message("sailnolandingstorm", "ship", sh)); + } else { + ADDMSG(&f->msgs, msg_message("sailnolanding", "ship region", sh, next_point)); + damage_ship(sh, 0.10); + /* we handle destruction at the end */ + } + break; + } + + + if (curse_active(get_curse(next_point->attribs, ct_find("maelstrom")))) { + if (do_maelstrom(next_point, u) == NULL) break; + } + + } /* !flying_ship */ + + /* Falls Blockade, endet die Seglerei hier */ + if (move_blocked(u, current_point, next_point)) { + ADDMSG(&u->faction->msgs, msg_message("sailfail", "ship region", sh, current_point)); + break; + } + + /* Falls kein Problem, eines weiter ziehen */ + fset(sh, SF_MOVED); + if (iroute) { + add_regionlist(iroute, next_point); + iroute = &(*iroute)->next; + } + step++; + + last_point = current_point; + current_point = next_point; + + if (!fval(current_point->terrain, SEA_REGION) && !is_cursed(sh->attribs, C_SHIP_FLYING, 0)) break; + token = getstrtoken(); + error = movewhere(u, token, current_point, &next_point); + if (error || next_point == NULL) { + message * msg = movement_error(u, token, ord, error); + if (msg!=NULL) { + add_message(&u->faction->msgs, msg); + msg_release(msg); + } + next_point = current_point; + break; + } + } + + if (sh->damage>=sh->size * DAMAGE_SCALE) { + if (sh->region) { + ADDMSG(&f->msgs, msg_message("shipsink", "ship", sh)); + remove_ship(&sh->region->ships, sh); + } + sh = NULL; + } + + /* Nun enthält current_point die Region, in der das Schiff seine Runde + * beendet hat. Wir generieren hier ein Ereignis für den Spieler, das + * ihm sagt, bis wohin er gesegelt ist, falls er überhaupt vom Fleck + * gekommen ist. Das ist nicht der Fall, wenn er von der Küste ins + * Inland zu segeln versuchte */ + + if (sh!=NULL && fval(sh, SF_MOVED)) { + unit * hafenmeister; + /* nachdem alle Richtungen abgearbeitet wurden, und alle Einheiten + * transferiert wurden, kann der aktuelle Befehl gelöscht werden. */ + cycle_route(ord, u, step); + set_order(&u->thisorder, NULL); + set_coast(sh, last_point, current_point); + + if( is_cursed(sh->attribs, C_SHIP_FLYING, 0) ) { + ADDMSG(&f->msgs, msg_message("shipfly", "ship from to", sh, starting_point, current_point)); + } else { + ADDMSG(&f->msgs, msg_message("shipsail", "ship from to", sh, starting_point, current_point)); + } + + /* Das Schiff und alle Einheiten darin werden nun von + * starting_point nach current_point verschoben */ + + /* Verfolgungen melden */ + if (fval(u, UFL_FOLLOWING)) caught_target(current_point, u); + + sh = move_ship(sh, starting_point, current_point, *routep); + + /* Hafengebühren ? */ + + hafenmeister = owner_buildingtyp(current_point, bt_find("harbour")); + if (sh && hafenmeister != NULL) { + item * itm; + unit * u2; + item * trans = NULL; + + for (u2 = current_point->units; u2; u2 = u2->next) { + if (u2->ship == sh && + !alliedunit(hafenmeister, u->faction, HELP_GUARD)) { + + + if (effskill(hafenmeister, SK_PERCEPTION) > effskill(u2, SK_STEALTH)) { + for (itm=u2->items; itm; itm=itm->next) { + const luxury_type * ltype = resource2luxury(itm->type->rtype); + if (ltype!=NULL && itm->number>0) { + int st = itm->number * effskill(hafenmeister, SK_TRADE) / 50; + st = MIN(itm->number, st); + + if (st > 0) { + i_change(&u2->items, itm->type, -st); + i_change(&hafenmeister->items, itm->type, st); + i_add(&trans, i_new(itm->type, st)); + } + } + } + } + } + } + if (trans) { + message * msg = msg_message("harbor_trade", "unit items ship", hafenmeister, trans, u->ship); + add_message(&u->faction->msgs, msg); + add_message(&hafenmeister->faction->msgs, msg); + msg_release(msg); + while (trans) i_remove(&trans, trans); + } + } + } +} + +unit * +get_captain(const ship * sh) +{ + const region * r = sh->region; + unit *u; + + for (u = r->units; u; u = u->next) { + if (u->ship == sh && eff_skill(u, SK_SAILING, r) >= sh->type->cptskill) + return u; + } + + return NULL; +} + +/* Segeln, Wandern, Reiten +* when this routine returns a non-zero value, movement for the region needs +* to be done again because of followers that got new MOVE orders. +* Setting FL_LONGACTION will prevent a unit from being handled more than once +* by this routine +* +* the token parser needs to be initialized before calling this function! +*/ + +/** fleeing units use this function +*/ +void +run_to(unit * u, region * to) +{ + region_list * route = NULL; + add_regionlist(&route, to); + travel_route(u, route, NULL, NULL, TRAVEL_RUNNING); + free_regionlist(route); + /* weder transport noch follow */ +} + +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; + + if (u->building && !can_leave(u)) { + cmistake(u, u->thisorder, 150, MSG_MOVE); + return route_begin; + } + switch (canwalk(u)) { + case E_CANWALK_TOOHEAVY: + cmistake(u, ord, 57, MSG_MOVE); + return route_begin; + case E_CANWALK_TOOMANYHORSES: + cmistake(u, ord, 56, MSG_MOVE); + return route_begin; + case E_CANWALK_TOOMANYCARTS: + cmistake(u, ord, 42, MSG_MOVE); + return route_begin; + } + route_end = cap_route(r, route_begin, route_end, movement_speed(u)); + + route_end = travel_route(u, route_begin, route_end, ord, mode); + get_followers(u, r, route_end, followers); + + /* transportation */ + for (ord = u->orders; ord; ord = ord->next) { + unit * ut; + + if (get_keyword(ord) != K_TRANSPORT) continue; + + init_tokens(ord); + skip_token(); + ut = getunit(r, u->faction); + if (ut!=NULL) { + if (get_keyword(ut->thisorder) == K_DRIVE) { + if (ut->building && !can_leave(ut)) { + cmistake(ut, ut->thisorder, 150, MSG_MOVE); + cmistake(u, ord, 99, MSG_MOVE); + } else if (!can_move(ut)) { + cmistake(u, ord, 99, MSG_MOVE); + } else { + boolean found = false; + + if (!fval(ut, UFL_NOTMOVING) && !LongHunger(ut)) { + init_tokens(ut->thisorder); + skip_token(); + if (getunit(u->region, ut->faction) == u) { + const region_list * route_to = travel_route(ut, route_begin, route_end, ord, TRAVEL_TRANSPORTED); + + if (route_to!=route_begin) { + get_followers(ut, r, route_to, followers); + } + ADDMSG(&ut->faction->msgs, msg_message("transport", + "unit target start end", u, ut, r, ut->region)); + found = true; + } + } + if (!found) { + if (cansee(u->faction, u->region, ut, 0)) { + cmistake(u, ord, 90, MSG_MOVE); + } else { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } + } + } + } + } else { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } + } + return route_end; +} + +/** traveling without ships + * walking, flying or riding units use this function + */ +static void +travel(unit * u, region_list ** routep) +{ + region * r = u->region; + region_list * route_begin = NULL; + follower * followers = NULL; + + if (routep) *routep = NULL; + + /* a few pre-checks that need not be done for each step: */ + if (!fval(r->terrain, SEA_REGION)) { + ship * sh = u->ship; + + if (!can_leave(u)) { + cmistake(u, u->thisorder, 150, MSG_MOVE); + return; + } + + /* An Land kein NACH wenn in dieser Runde Schiff VERLASSEN! */ + if (sh == NULL) { + sh = leftship(u); + if (sh && sh->region!=u->region) sh = NULL; + } + if (sh) { + unit * guard = is_guarded(r, u, GUARD_LANDING); + if (guard) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "region_guarded", "guard", guard)); + return; + } + } + if (u->ship && u->race->flags & RCF_SWIM) { + cmistake(u, u->thisorder, 143, MSG_MOVE); + return; + } + } + else if (u->ship && fval(u->ship, SF_MOVED)) { + /* die Einheit ist auf einem Schiff, das sich bereits bewegt hat */ + cmistake(u, u->thisorder, 13, MSG_MOVE); + return; + } + + make_route(u, u->thisorder, routep); + route_begin = *routep; + + /* und ab die post: */ + travel_i(u, route_begin, NULL, u->thisorder, TRAVEL_NORMAL, &followers); + + /* followers */ + while (followers!=NULL) { + follower * fnext = followers->next; + unit * uf = followers->uf; + unit * ut = followers->ut; + const region_list * route_end = followers->route_end; + + free(followers); + followers = fnext; + + if (uf->region == r) { + order * follow_order; + const struct locale * lang = u->faction->locale; + + /* construct an order */ + follow_order = create_order(K_FOLLOW, lang, "%s %i", + LOC(uf->faction->locale, parameters[P_UNIT]), ut->no); + + route_end = reroute(uf, route_begin, route_end); + travel_i(uf, route_begin, route_end, follow_order, TRAVEL_FOLLOWING, &followers); + caught_target(uf->region, uf); + free_order(follow_order); + } + } + +} + +static void +move(unit * u, boolean move_on_land) +{ + region_list * route = NULL; + + assert(u->number); + if (u->ship && fval(u, UFL_OWNER)) { + sail(u, u->thisorder, move_on_land, &route); + } else { + travel(u, &route); + } + + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + set_order(&u->thisorder, NULL); + + if (route!=NULL) free_regionlist(route); +} + +typedef struct piracy_data { + const struct faction * pirate; + const struct faction * target; + direction_t dir; +} piracy_data; + +static void +piracy_init(struct attrib * a) +{ + a->data.v = calloc(1, sizeof(piracy_data)); +} + +static void +piracy_done(struct attrib * a) +{ + free(a->data.v); +} + +static attrib_type at_piracy_direction = { + "piracy_direction", + piracy_init, + piracy_done, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +static attrib * +mk_piracy(const faction * pirate, const faction * target, direction_t target_dir) +{ + attrib * a = a_new(&at_piracy_direction); + piracy_data * data = a->data.v; + data->pirate = pirate; + data->target = target; + data->dir = target_dir; + return a; +} + +static void +piracy_cmd(unit *u, struct order * ord) +{ + region *r = u->region; + ship *sh = u->ship, *sh2; + direction_t dir, target_dir = NODIRECTION; + struct { + const faction * target; + int value; + } aff[MAXDIRECTIONS]; + int saff = 0; + int *il = NULL; + const char *s; + attrib *a; + + if (!sh) { + cmistake(u, ord, 144, MSG_MOVE); + return; + } + + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 146, MSG_MOVE); + return; + } + + /* Feststellen, ob schon ein anderer alliierter Pirat ein + * Ziel gefunden hat. */ + + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + if (s!=NULL && *s) { + il = intlist_init(); + while (s && *s) { + il = intlist_add(il, atoi36(s)); + s = getstrtoken(); + } + } + + for (a = a_find(r->attribs, &at_piracy_direction); a && a->type==&at_piracy_direction; a=a->next) { + piracy_data * data = a->data.v; + const faction * p = data->pirate; + const faction * t = data->target; + + if (alliedunit(u, p, HELP_FIGHT)) { + if (il == 0 || (t && intlist_find(il, t->no))) { + target_dir = data->dir; + break; + } + } + } + + /* Wenn nicht, sehen wir, ob wir ein Ziel finden. */ + + if (target_dir == NODIRECTION) { + /* Einheit ist also Kapitän. Jetzt gucken, in wievielen + * Nachbarregionen potentielle Opfer sind. */ + + for(dir = 0; dir < MAXDIRECTIONS; dir++) { + region *rc = rconnect(r, dir); + aff[dir].value = 0; + aff[dir].target = 0; + if (rc && fval(rc->terrain, SWIM_INTO) + && check_takeoff(sh, r, rc) == true) { + + for (sh2 = rc->ships; sh2; sh2 = sh2->next) { + unit * cap = shipowner(sh2); + if (cap) { + faction * f = visible_faction(cap->faction, cap); + if (alliedunit(u, f, HELP_FIGHT)) continue; + if (il == 0 || intlist_find(il, cap->faction->no)) { + ++aff[dir].value; + if (rng_int() % aff[dir].value == 0) { + aff[dir].target = f; + } + } + } + } + + /* Und aufaddieren. */ + saff += aff[dir].value; + } + } + + if (saff != 0) { + saff = rng_int() % saff; + for (dir=0; dir!=MAXDIRECTIONS; ++dir) { + if (saff!=aff[dir].value) break; + saff -= aff[dir].value; + } + target_dir = dir; + a = a_add(&r->attribs, mk_piracy(u->faction, aff[dir].target, target_dir)); + } + } + + free(il); + + /* Wenn kein Ziel gefunden, entsprechende Meldung generieren */ + if (target_dir == NODIRECTION) { + ADDMSG(&u->faction->msgs, msg_message("piratenovictim", + "ship region", sh, r)); + return; + } + + /* Meldung generieren */ + ADDMSG(&u->faction->msgs, msg_message("piratesawvictim", + "ship region dir", sh, r, target_dir)); + + /* Befehl konstruieren */ + set_order(&u->thisorder, create_order(K_MOVE, u->faction->locale, "%s", + LOC(u->faction->locale, directions[target_dir]))); + + /* Bewegung ausführen */ + init_tokens(u->thisorder); + skip_token(); + move(u, true); +} + +static void +age_traveldir(region *r) +{ + attrib *a = a_find(r->attribs, &at_traveldir); + + while(a && a->type==&at_traveldir) { + attrib *an = a->next; + a->data.ca[3]--; + if(a->data.ca[3] <= 0) { + a_remove(&r->attribs, a); + } + a = an; + } +} + +static direction_t +hunted_dir(attrib *at, int id) +{ + attrib *a = a_find(at, &at_shiptrail); + direction_t d = NODIRECTION; + + while (a!=NULL && a->type==&at_shiptrail) { + traveldir *t = (traveldir *)(a->data.v); + if (t->no == id) { + d = t->dir; + /* do not break, because we want the last one for this ship */ + } + a = a->next; + } + + return d; +} + +static int +hunt(unit *u, order * ord) +{ + region *rc = u->region; + int bytes, moves, id, speed; + char command[256], * bufp = command; + size_t size = sizeof(command); + direction_t dir; + + if (fval(u, UFL_NOTMOVING)) { + return 0; + } else if (u->ship == NULL) { + cmistake(u, ord, 144, MSG_MOVE); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ + return 0; + } else if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 146, MSG_MOVE); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ + return 0; + } else if (!can_move(u)) { + cmistake(u, ord, 55, MSG_MOVE); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ + return 0; + } + + id = getshipid(); + + if (id <= 0) { + cmistake(u, ord, 20, MSG_MOVE); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ + return 0; + } + + dir = hunted_dir(rc->attribs, id); + + if (dir == NODIRECTION) { + ship * sh = findship(id); + if (sh == NULL || sh->region!=rc) { + cmistake(u, ord, 20, MSG_MOVE); + } + fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ + return 0; + } + + bufp = command; + bytes = snprintf(bufp, size, "%s %s", LOC(u->faction->locale, keywords[K_MOVE]), + LOC(u->faction->locale, directions[dir])); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + moves = 1; + + speed = getuint(); + if (speed==0) { + speed = shipspeed(u->ship, u); + } else { + int maxspeed = shipspeed(u->ship, u); + if (maxspeedattribs, id)) != NODIRECTION) + { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(u->faction->locale, directions[dir]), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + moves++; + rc = rconnect(rc, dir); + } + + /* In command steht jetzt das NACH-Kommando. */ + + /* NACH ignorieren und Parsing initialisieren. */ + igetstrtoken(command); + /* NACH ausführen */ + move(u, false); + return 1; /* true -> Einheitenliste von vorne durchgehen */ +} + +void +destroy_damaged_ships(void) +{ + region *r; + ship *sh,*shn; + + for(r=regions;r;r=r->next) { + for(sh=r->ships;sh;) { + shn = sh->next; + if (sh->damage>=sh->size * DAMAGE_SCALE) { + remove_ship(&sh->region->ships, sh); + } + sh = shn; + } + } +} + +/* Bewegung, Verfolgung, Piraterie */ + +/** ships that folow other ships + * Dann generieren die jagenden Einheiten ihre Befehle und + * bewegen sich. + * Following the trails of other ships. + */ +static void +move_hunters(void) +{ + region *r; + + for (r = regions; r; r = r->next) { + unit ** up = &r->units; + + while (*up!=NULL) { + unit * u = *up; + + if (!fval(u, UFL_MOVED|UFL_NOTMOVING)) { + order * ord; + + for (ord=u->orders;ord;ord=ord->next) { + if (get_keyword(ord) == K_FOLLOW) { + param_t p; + + init_tokens(ord); + skip_token(); + p = getparam(u->faction->locale); + if (p != P_SHIP) { + if (p != P_UNIT) { + cmistake(u, ord, 240, MSG_MOVE); + } + break; + } + + /* wir folgen definitiv einem Schiff. */ + + if (fval(u, UFL_NOTMOVING)) { + cmistake(u, ord, 52, MSG_MOVE); + break; + } else if (!can_move(u)) { + cmistake(u, ord, 55, MSG_MOVE); + break; + } + + if (!fval(u, UFL_NOTMOVING) && !LongHunger(u) && hunt(u, ord)) { + up = &r->units; + break; + } + } + } + } + if (*up == u) up=&u->next; + } + } +} + +/** Piraten and Drift + * + */ +static void +move_pirates(void) +{ + region * r; + + for (r = regions; r; r = r->next) { + unit ** up = &r->units; + + while (*up) { + unit *u = *up; + + if (!fval(u, UFL_NOTMOVING) && get_keyword(u->thisorder) == K_PIRACY) { + piracy_cmd(u, u->thisorder); + fset(u, UFL_LONGACTION|UFL_NOTMOVING); + } + + if (*up == u) { + /* not moved, use next unit */ + up = &u->next; + } else if (*up && (*up)->region!=r) { + /* moved the previous unit along with u (units on same ship) + * must start from the beginning again */ + up = &r->units; + } + /* else *up is already the next unit */ + } + + a_removeall(&r->attribs, &at_piracy_direction); + age_traveldir(r); + } +} + +void +movement(void) +{ + int ships; + + /* Initialize the additional encumbrance by transported units */ + init_transportation(); + + /* Move ships in last phase, others first + * This is to make sure you can't land someplace and then get off the ship + * in the same turn. + */ + for (ships=0;ships<=1;++ships) { + region * r = regions; + while (r!=NULL) { + unit ** up = &r->units; + boolean repeat = false; + + while (*up) { + unit *u = *up; + keyword_t kword; + + if (u->ship && fval(u->ship, SF_DRIFTED)) { + up = &u->next; + continue; + } + kword = get_keyword(u->thisorder); + + switch (kword) { + case K_ROUTE: + case K_MOVE: + /* after moving, the unit has no thisorder. this prevents + * it from moving twice (or getting error messages twice). + * UFL_NOTMOVING is set in combat if the unit is not allowed + * to move because it was involved in a battle. + */ + if (fval(u, UFL_NOTMOVING)) { + if (fval(u, UFL_LONGACTION)) { + cmistake(u, u->thisorder, 52, MSG_MOVE); + set_order(&u->thisorder, NULL); + } else { + cmistake(u, u->thisorder, 319, MSG_MOVE); + set_order(&u->thisorder, NULL); + } + } else if (fval(u, UFL_MOVED)) { + cmistake(u, u->thisorder, 187, MSG_MOVE); + set_order(&u->thisorder, NULL); + } else if (!can_move(u)) { + cmistake(u, u->thisorder, 55, MSG_MOVE); + set_order(&u->thisorder, NULL); + } else { + if (ships) { + if (u->ship && fval(u, UFL_OWNER)) { + init_tokens(u->thisorder); + skip_token(); + move(u, false); + } + } else { + if (u->ship == NULL || !fval(u, UFL_OWNER)) { + init_tokens(u->thisorder); + skip_token(); + move(u, false); + } + } + } + break; + } + if (u->region == r) { + /* not moved, use next unit */ + up = &u->next; + } else { + if (*up && (*up)->region!=r) { + /* moved the upcoming unit along with u (units on ships or followers, + * for example). must start from the beginning again immediately */ + up = &r->units; + repeat = false; + } else { + repeat = true; + } + } + /* else *up is already the next unit */ + } + if (repeat) continue; + if (ships == 0) { + /* Abtreiben von beschädigten, unterbemannten, überladenen Schiffen */ + drifting_ships(r); + } + r = r->next; + } + } + + move_hunters(); + move_pirates(); +} + +/** Overrides long orders with a FOLLOW order if the target is moving. + * FOLLOW SHIP is a long order, and doesn't need to be treated in here. + * BUGS: http://bugs.eressea.de/view.php?id=1444 (A folgt B folgt C) + */ +void +follow_unit(unit * u) +{ + region * r = u->region; + attrib * a = NULL; + order * ord; + + if (fval(u, UFL_NOTMOVING) || LongHunger(u)) return; + + for (ord=u->orders;ord;ord=ord->next) { + const struct locale * lang = u->faction->locale; + + if (get_keyword(ord) == K_FOLLOW) { + init_tokens(ord); + skip_token(); + if (getparam(lang) == P_UNIT) { + int id = read_unitid(u->faction, r); + + if (a!=NULL) { + a = a_find(u->attribs, &at_follow); + } + + if (id>0) { + unit * uf = findunit(id); + if (!a) { + a = a_add(&u->attribs, make_follow(uf)); + } else { + a->data.v = uf; + } + } else if (a) { + a_remove(&u->attribs, a); + a = NULL; + } + } + } + } + + if (a && !fval(u, UFL_MOVED|UFL_NOTMOVING)) { + unit * u2 = a->data.v; + boolean follow = false; + + if (!u2 || u2->region!=r || !cansee(u->faction, r, u2, 0)) { + return; + } + + switch (get_keyword(u2->thisorder)) { + case K_MOVE: + case K_ROUTE: + case K_DRIVE: + follow = true; + break; + default: + for (ord=u2->orders;ord;ord=ord->next) { + switch (get_keyword(ord)) { + case K_FOLLOW: + case K_PIRACY: + follow = true; + break; + default: + continue; + } + break; + } + break; + } + if (!follow) { + attrib * a2 = a_find(u2->attribs, &at_follow); + if (a2!=NULL) { + unit * u3 = a2->data.v; + follow = (u3 && u2->region == u2->region); + } + } + if (follow) { + fset(u, UFL_FOLLOWING); + fset(u2, UFL_FOLLOWED); + set_order(&u->thisorder, NULL); + } + } +} diff --git a/src/kernel/move.h b/src/kernel/move.h index 96c04a117..2b5b7bdd1 100644 --- a/src/kernel/move.h +++ b/src/kernel/move.h @@ -1,71 +1,71 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_MOVEMENT -#define H_KRNL_MOVEMENT -#ifdef __cplusplus -extern "C" { -#endif - -struct unit; -struct ship; -struct building_type; - -/* die Zahlen sind genau äquivalent zu den race Flags */ -#define MV_CANNOTMOVE (1<<5) -#define MV_FLY (1<<7) /* kann fliegen */ -#define MV_SWIM (1<<8) /* kann schwimmen */ -#define MV_WALK (1<<9) /* kann über Land gehen */ - -/* Die tragekapaz. ist hardcodiert mit defines, da es bis jetzt sowieso nur 2 -** objekte gibt, die etwas tragen. */ -#define SILVERWEIGHT 1 -#define SCALEWEIGHT 100 /* Faktor, um den die Anzeige von gewichten - * * skaliert wird */ -#define HORSECAPACITY 7000 -#define WAGONCAPACITY 14000 - -#define HORSESNEEDED 2 - -/* ein mensch wiegt 10, traegt also 5, ein pferd wiegt 50, traegt also 20. ein -** wagen wird von zwei pferden gezogen und traegt total 140, davon 40 die -** pferde, macht nur noch 100, aber samt eigenem gewicht (40) macht also 140. */ - -int personcapacity(const struct unit *u); -direction_t getdirection(const struct locale *); -void movement(void); -void run_to(struct unit * u, struct region * to); -struct unit *is_guarded(struct region * r, struct unit * u, unsigned int mask); -boolean is_guard(const struct unit * u, int mask); -int enoughsailors(const struct ship * sh, const struct region * r); -boolean canswim(struct unit *u); -boolean canfly(struct unit *u); -struct unit *get_captain(const struct ship * sh); -void travelthru(const struct unit * u, struct region * r); -struct ship * move_ship(struct ship * sh, struct region * from, struct region * to, struct region_list * route); -int walkingcapacity(const struct unit * u); -void follow_unit(struct unit * u); -boolean buildingtype_exists(const struct region * r, const struct building_type * bt, boolean working); -struct unit* owner_buildingtyp(const struct region * r, const struct building_type * bt); - -extern struct attrib_type at_speedup; - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_MOVEMENT +#define H_KRNL_MOVEMENT +#ifdef __cplusplus +extern "C" { +#endif + +struct unit; +struct ship; +struct building_type; + +/* die Zahlen sind genau äquivalent zu den race Flags */ +#define MV_CANNOTMOVE (1<<5) +#define MV_FLY (1<<7) /* kann fliegen */ +#define MV_SWIM (1<<8) /* kann schwimmen */ +#define MV_WALK (1<<9) /* kann über Land gehen */ + +/* Die tragekapaz. ist hardcodiert mit defines, da es bis jetzt sowieso nur 2 +** objekte gibt, die etwas tragen. */ +#define SILVERWEIGHT 1 +#define SCALEWEIGHT 100 /* Faktor, um den die Anzeige von gewichten + * * skaliert wird */ +#define HORSECAPACITY 7000 +#define WAGONCAPACITY 14000 + +#define HORSESNEEDED 2 + +/* ein mensch wiegt 10, traegt also 5, ein pferd wiegt 50, traegt also 20. ein +** wagen wird von zwei pferden gezogen und traegt total 140, davon 40 die +** pferde, macht nur noch 100, aber samt eigenem gewicht (40) macht also 140. */ + +int personcapacity(const struct unit *u); +direction_t getdirection(const struct locale *); +void movement(void); +void run_to(struct unit * u, struct region * to); +struct unit *is_guarded(struct region * r, struct unit * u, unsigned int mask); +boolean is_guard(const struct unit * u, int mask); +int enoughsailors(const struct ship * sh, const struct region * r); +boolean canswim(struct unit *u); +boolean canfly(struct unit *u); +struct unit *get_captain(const struct ship * sh); +void travelthru(const struct unit * u, struct region * r); +struct ship * move_ship(struct ship * sh, struct region * from, struct region * to, struct region_list * route); +int walkingcapacity(const struct unit * u); +void follow_unit(struct unit * u); +boolean buildingtype_exists(const struct region * r, const struct building_type * bt, boolean working); +struct unit* owner_buildingtyp(const struct region * r, const struct building_type * bt); + +extern struct attrib_type at_speedup; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/names.c b/src/kernel/names.c index 7875983c6..9d617cc0b 100644 --- a/src/kernel/names.c +++ b/src/kernel/names.c @@ -1,483 +1,483 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "names.h" - -/* kernel includes */ -#include "unit.h" -#include "region.h" -#include "faction.h" -#include "magic.h" -#include "race.h" -#include "terrain.h" -#include "terrainid.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -const char * -describe_braineater(unit * u, const struct locale * lang) -{ - return LOC(lang, "describe_braineater"); -} - -static const char * -make_names(const char * monster, int * num_postfix, int pprefix, int * num_name, int * num_prefix, int ppostfix) -{ - int uv, uu, un; - static char name[NAMESIZE + 1]; - char zText[32]; - const char * str; - - if (*num_prefix==0) { - - for (*num_prefix=0;;++*num_prefix) { - sprintf(zText, "%s_prefix_%d", monster, *num_prefix); - str = locale_getstring(default_locale, zText); - if (str==NULL) break; - } - - for (*num_name=0;;++*num_name) { - sprintf(zText, "%s_name_%d", monster, *num_name); - str = locale_getstring(default_locale, zText); - if (str==NULL) break; - } - - for (*num_postfix=0;;++*num_postfix) { - sprintf(zText, "%s_postfix_%d", monster, *num_postfix); - str = locale_getstring(default_locale, zText); - if (str==NULL) break; - } - } - - if (*num_name==0) { - return NULL; - } - - /* nur 50% aller Namen haben "Vor-Teil" */ - uv = rng_int() % (*num_prefix * pprefix); - - uu = rng_int() % *num_name; - - /* nur 50% aller Namen haben "Nach-Teil", wenn kein Vor-Teil */ - if (uv>=*num_prefix) { - un = rng_int() % *num_postfix; - } else { - un = rng_int() % (*num_postfix * ppostfix); - } - - name[0] = 0; - if (uv < *num_prefix) { - sprintf(zText, "%s_prefix_%d", monster, uv); - str = locale_getstring(default_locale, zText); - if (str) { - strcat(name, (const char *)str); - strcat(name, " "); - } - } - - sprintf(zText, "%s_name_%d", monster, uu); - str = locale_getstring(default_locale, zText); - if (str) strcat(name, (const char *)str); - - if (un < *num_postfix) { - sprintf(zText, "%s_postfix_%d", monster, un); - str = locale_getstring(default_locale, zText); - if (str) { - strcat(name, " "); - strcat(name, (const char *)str); - } - } - return name; -} - -const char * -undead_name(const unit * u) -{ - static int num_postfix, num_name, num_prefix; - return make_names("undead", &num_postfix, 2, &num_name, &num_prefix, 2); -} - -const char * -skeleton_name(const unit * u) -{ - static int num_postfix, num_name, num_prefix; - return make_names("skeleton", &num_postfix, 5, &num_name, &num_prefix, 2); -} - -const char * -zombie_name(const unit * u) -{ - static int num_postfix, num_name, num_prefix; - return make_names("zombie", &num_postfix, 5, &num_name, &num_prefix, 2); -} - -const char * -ghoul_name(const unit * u) -{ - static int num_postfix, num_name, num_prefix; - return make_names("ghoul", &num_postfix, 5, &num_name, &num_prefix, 4); -} - - -/* Drachen */ - -#define SIL1 15 - -const char *silbe1[SIL1] = { - "Tar", - "Ter", - "Tor", - "Pan", - "Par", - "Per", - "Nim", - "Nan", - "Nun", - "Gor", - "For", - "Fer", - "Kar", - "Kur", - "Pen", -}; - -#define SIL2 19 - -const char *silbe2[SIL2] = { - "da", - "do", - "dil", - "di", - "dor", - "dar", - "ra", - "ran", - "ras", - "ro", - "rum", - "rin", - "ten", - "tan", - "ta", - "tor", - "gur", - "ga", - "gas", -}; - -#define SIL3 14 - -const char *silbe3[SIL3] = { - "gul", - "gol", - "dol", - "tan", - "tar", - "tur", - "sur", - "sin", - "kur", - "kor", - "kar", - "dul", - "dol", - "bus", -}; - -const char * -generic_name(const unit *u) -{ - if (u->no == 1) { - return LOC(u->faction->locale, mkname("race", u->race->_name[0])); - } - return LOC(u->faction->locale, mkname("race", u->race->_name[1])); -} - -const char * -dragon_name(const unit *u) -{ - static char name[NAMESIZE + 1]; - int rnd, ter = 0; - int anzahl = 1; - static int num_postfix; - char zText[32]; - const char * str; - - if (num_postfix==0) { - for (num_postfix=0;;++num_postfix) { - sprintf(zText, "dragon_postfix_%d", num_postfix); - str = locale_getstring(default_locale, zText); - if (str==NULL) break; - } - if (num_postfix==0) num_postfix = -1; - } - if (num_postfix<=0) { - return NULL; - } - - if (u) { - region *r = u->region; - anzahl = u->number; - switch (rterrain(r)) { - case T_PLAIN: - ter = 1; - break; - case T_MOUNTAIN: - ter = 2; - break; - case T_DESERT: - ter = 3; - break; - case T_SWAMP: - ter = 4; - break; - case T_GLACIER: - ter = 5; - break; - } - } - - rnd = num_postfix / 6; - rnd = (rng_int() % rnd) + ter * rnd; - - sprintf(zText, "dragon_postfix_%d", rnd); - - str = locale_getstring(default_locale, zText); - assert(str!=NULL); - - if (anzahl > 1) { - const char * no_article = strchr((const char *)str, ' '); - assert(no_article); - /* TODO: GERMAN */ - sprintf(name, "Die %sn von %s", no_article, rname(u->region, default_locale)); - } else { - char n[32]; - - strcpy(n, silbe1[rng_int() % SIL1]); - strcat(n, silbe2[rng_int() % SIL2]); - strcat(n, silbe3[rng_int() % SIL3]); - if (rng_int() % 5 > 2) { - sprintf(name, "%s, %s", n, str); /* "Name, der Titel" */ - } else { - strcpy(name, (const char *)str); /* "Der Titel Name" */ - name[0] = (char)toupper(name[0]); /* TODO: UNICODE - should use towupper() */ - strcat(name, " "); - strcat(name, n); - } - if (u && (rng_int() % 3 == 0)) { - strcat(name, " von "); - strcat(name, (const char *)rname(u->region, default_locale)); - } - } - - return name; -} - -/* Dracoide */ - -#define DRAC_PRE 13 -static const char *drac_pre[DRAC_PRE] = { - "Siss", - "Xxaa", - "Shht", - "X'xixi", - "Xar", - "X'zish", - "X", - "Sh", - "R", - "Z", - "Y", - "L", - "Ck", -}; - -#define DRAC_MID 12 -static const char *drac_mid[DRAC_MID] = { - "siss", - "xxaa", - "shht", - "xxi", - "xar", - "x'zish", - "x", - "sh", - "r", - "z'ck", - "y", - "rl" -}; - -#define DRAC_SUF 10 -static const char *drac_suf[DRAC_SUF] = { - "xil", - "shh", - "s", - "x", - "arr", - "lll", - "lll", - "shack", - "ck", - "k" -}; - -const char * -dracoid_name(const unit *u) -{ - static char name[NAMESIZE + 1]; - int mid_syllabels; - - u=u; - /* Wieviele Mittelteile? */ - - mid_syllabels = rng_int()%4; - - strcpy(name, drac_pre[rng_int()%DRAC_PRE]); - while(mid_syllabels > 0) { - mid_syllabels--; - if(rng_int()%10 < 4) strcat(name,"'"); - strcat(name, drac_mid[rng_int()%DRAC_MID]); - } - strcat(name, drac_suf[rng_int()%DRAC_SUF]); - return name; -} - -/** returns an abbreviation of a string. - * TODO: buflen is being ignored */ - -const char * -abkz(const char *s, char * buf, size_t buflen, size_t maxchars) -{ - const char *p = s; - char * bufp; - unsigned int c = 0; - size_t bpt, i; - ucs4_t ucs; - size_t size; - int result; - - /* Prüfen, ob Kurz genug */ - - if (strlen(s) <= maxchars) { - return s; - } - /* Anzahl der Wörter feststellen */ - - while (*p != 0) { - - result = unicode_utf8_to_ucs4(&ucs, p, &size); - assert(result==0 || "damnit, we're not handling invalid input here!"); - - /* Leerzeichen überspringen */ - while (*p != 0 && !iswalnum((wint_t)ucs)) { - p += size; - result = unicode_utf8_to_ucs4(&ucs, p, &size); - assert(result==0 || "damnit, we're not handling invalid input here!"); - } - - /* Counter erhöhen */ - if (*p != 0) ++c; - - /* alnums überspringen */ - while (*p != 0 && iswalnum((wint_t)ucs)) { - p+=size; - result = unicode_utf8_to_ucs4(&ucs, p, &size); - assert(result==0 || "damnit, we're not handling invalid input here!"); - } - } - - /* Buchstaben pro Teilkürzel = MAX(1,max/AnzWort) */ - - bpt = MAX(1, maxchars / c); - - /* Einzelne Wörter anspringen und jeweils die ersten BpT kopieren */ - - p = s; - c = 0; - bufp = buf; - - result = unicode_utf8_to_ucs4(&ucs, p, &size); - assert(result==0 || "damnit, we're not handling invalid input here!"); - - while (*p != 0 && c < maxchars) { - /* Leerzeichen überspringen */ - - while (*p != 0 && !iswalnum((wint_t)ucs)) { - p+=size; - result = unicode_utf8_to_ucs4(&ucs, p, &size); - assert(result==0 || "damnit, we're not handling invalid input here!"); - } - - /* alnums übertragen */ - - for (i = 0; i < bpt && *p != 0 && iswalnum((wint_t)ucs); ++i) { - memcpy(bufp, p, size); - p += size; - bufp += size; - ++c; - - result = unicode_utf8_to_ucs4(&ucs, p, &size); - assert(result==0 || "damnit, we're not handling invalid input here!"); - } - - /* Bis zum nächsten Leerzeichen */ - - while (c < maxchars && *p != 0 && iswalnum((wint_t)ucs)) { - p+=size; - result = unicode_utf8_to_ucs4(&ucs, p, &size); - assert(result==0 || "damnit, we're not handling invalid input here!"); - } - } - - *bufp = 0; - - return buf; -} - -void -register_names(void) -{ - register_function((pf_generic)describe_braineater, "describe_braineater"); - /* function name - * generate a name for a nonplayerunit - * race->generate_name() */ - register_function((pf_generic)undead_name, "nameundead"); - register_function((pf_generic)skeleton_name, "nameskeleton"); - register_function((pf_generic)zombie_name, "namezombie"); - register_function((pf_generic)ghoul_name, "nameghoul"); - register_function((pf_generic)dragon_name, "namedragon"); - register_function((pf_generic)dracoid_name, "namedracoid"); - register_function((pf_generic)generic_name, "namegeneric"); -} - - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "names.h" + +/* kernel includes */ +#include "unit.h" +#include "region.h" +#include "faction.h" +#include "magic.h" +#include "race.h" +#include "terrain.h" +#include "terrainid.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +const char * +describe_braineater(unit * u, const struct locale * lang) +{ + return LOC(lang, "describe_braineater"); +} + +static const char * +make_names(const char * monster, int * num_postfix, int pprefix, int * num_name, int * num_prefix, int ppostfix) +{ + int uv, uu, un; + static char name[NAMESIZE + 1]; + char zText[32]; + const char * str; + + if (*num_prefix==0) { + + for (*num_prefix=0;;++*num_prefix) { + sprintf(zText, "%s_prefix_%d", monster, *num_prefix); + str = locale_getstring(default_locale, zText); + if (str==NULL) break; + } + + for (*num_name=0;;++*num_name) { + sprintf(zText, "%s_name_%d", monster, *num_name); + str = locale_getstring(default_locale, zText); + if (str==NULL) break; + } + + for (*num_postfix=0;;++*num_postfix) { + sprintf(zText, "%s_postfix_%d", monster, *num_postfix); + str = locale_getstring(default_locale, zText); + if (str==NULL) break; + } + } + + if (*num_name==0) { + return NULL; + } + + /* nur 50% aller Namen haben "Vor-Teil" */ + uv = rng_int() % (*num_prefix * pprefix); + + uu = rng_int() % *num_name; + + /* nur 50% aller Namen haben "Nach-Teil", wenn kein Vor-Teil */ + if (uv>=*num_prefix) { + un = rng_int() % *num_postfix; + } else { + un = rng_int() % (*num_postfix * ppostfix); + } + + name[0] = 0; + if (uv < *num_prefix) { + sprintf(zText, "%s_prefix_%d", monster, uv); + str = locale_getstring(default_locale, zText); + if (str) { + strcat(name, (const char *)str); + strcat(name, " "); + } + } + + sprintf(zText, "%s_name_%d", monster, uu); + str = locale_getstring(default_locale, zText); + if (str) strcat(name, (const char *)str); + + if (un < *num_postfix) { + sprintf(zText, "%s_postfix_%d", monster, un); + str = locale_getstring(default_locale, zText); + if (str) { + strcat(name, " "); + strcat(name, (const char *)str); + } + } + return name; +} + +const char * +undead_name(const unit * u) +{ + static int num_postfix, num_name, num_prefix; + return make_names("undead", &num_postfix, 2, &num_name, &num_prefix, 2); +} + +const char * +skeleton_name(const unit * u) +{ + static int num_postfix, num_name, num_prefix; + return make_names("skeleton", &num_postfix, 5, &num_name, &num_prefix, 2); +} + +const char * +zombie_name(const unit * u) +{ + static int num_postfix, num_name, num_prefix; + return make_names("zombie", &num_postfix, 5, &num_name, &num_prefix, 2); +} + +const char * +ghoul_name(const unit * u) +{ + static int num_postfix, num_name, num_prefix; + return make_names("ghoul", &num_postfix, 5, &num_name, &num_prefix, 4); +} + + +/* Drachen */ + +#define SIL1 15 + +const char *silbe1[SIL1] = { + "Tar", + "Ter", + "Tor", + "Pan", + "Par", + "Per", + "Nim", + "Nan", + "Nun", + "Gor", + "For", + "Fer", + "Kar", + "Kur", + "Pen", +}; + +#define SIL2 19 + +const char *silbe2[SIL2] = { + "da", + "do", + "dil", + "di", + "dor", + "dar", + "ra", + "ran", + "ras", + "ro", + "rum", + "rin", + "ten", + "tan", + "ta", + "tor", + "gur", + "ga", + "gas", +}; + +#define SIL3 14 + +const char *silbe3[SIL3] = { + "gul", + "gol", + "dol", + "tan", + "tar", + "tur", + "sur", + "sin", + "kur", + "kor", + "kar", + "dul", + "dol", + "bus", +}; + +const char * +generic_name(const unit *u) +{ + if (u->no == 1) { + return LOC(u->faction->locale, mkname("race", u->race->_name[0])); + } + return LOC(u->faction->locale, mkname("race", u->race->_name[1])); +} + +const char * +dragon_name(const unit *u) +{ + static char name[NAMESIZE + 1]; + int rnd, ter = 0; + int anzahl = 1; + static int num_postfix; + char zText[32]; + const char * str; + + if (num_postfix==0) { + for (num_postfix=0;;++num_postfix) { + sprintf(zText, "dragon_postfix_%d", num_postfix); + str = locale_getstring(default_locale, zText); + if (str==NULL) break; + } + if (num_postfix==0) num_postfix = -1; + } + if (num_postfix<=0) { + return NULL; + } + + if (u) { + region *r = u->region; + anzahl = u->number; + switch (rterrain(r)) { + case T_PLAIN: + ter = 1; + break; + case T_MOUNTAIN: + ter = 2; + break; + case T_DESERT: + ter = 3; + break; + case T_SWAMP: + ter = 4; + break; + case T_GLACIER: + ter = 5; + break; + } + } + + rnd = num_postfix / 6; + rnd = (rng_int() % rnd) + ter * rnd; + + sprintf(zText, "dragon_postfix_%d", rnd); + + str = locale_getstring(default_locale, zText); + assert(str!=NULL); + + if (anzahl > 1) { + const char * no_article = strchr((const char *)str, ' '); + assert(no_article); + /* TODO: GERMAN */ + sprintf(name, "Die %sn von %s", no_article, rname(u->region, default_locale)); + } else { + char n[32]; + + strcpy(n, silbe1[rng_int() % SIL1]); + strcat(n, silbe2[rng_int() % SIL2]); + strcat(n, silbe3[rng_int() % SIL3]); + if (rng_int() % 5 > 2) { + sprintf(name, "%s, %s", n, str); /* "Name, der Titel" */ + } else { + strcpy(name, (const char *)str); /* "Der Titel Name" */ + name[0] = (char)toupper(name[0]); /* TODO: UNICODE - should use towupper() */ + strcat(name, " "); + strcat(name, n); + } + if (u && (rng_int() % 3 == 0)) { + strcat(name, " von "); + strcat(name, (const char *)rname(u->region, default_locale)); + } + } + + return name; +} + +/* Dracoide */ + +#define DRAC_PRE 13 +static const char *drac_pre[DRAC_PRE] = { + "Siss", + "Xxaa", + "Shht", + "X'xixi", + "Xar", + "X'zish", + "X", + "Sh", + "R", + "Z", + "Y", + "L", + "Ck", +}; + +#define DRAC_MID 12 +static const char *drac_mid[DRAC_MID] = { + "siss", + "xxaa", + "shht", + "xxi", + "xar", + "x'zish", + "x", + "sh", + "r", + "z'ck", + "y", + "rl" +}; + +#define DRAC_SUF 10 +static const char *drac_suf[DRAC_SUF] = { + "xil", + "shh", + "s", + "x", + "arr", + "lll", + "lll", + "shack", + "ck", + "k" +}; + +const char * +dracoid_name(const unit *u) +{ + static char name[NAMESIZE + 1]; + int mid_syllabels; + + u=u; + /* Wieviele Mittelteile? */ + + mid_syllabels = rng_int()%4; + + strcpy(name, drac_pre[rng_int()%DRAC_PRE]); + while(mid_syllabels > 0) { + mid_syllabels--; + if(rng_int()%10 < 4) strcat(name,"'"); + strcat(name, drac_mid[rng_int()%DRAC_MID]); + } + strcat(name, drac_suf[rng_int()%DRAC_SUF]); + return name; +} + +/** returns an abbreviation of a string. + * TODO: buflen is being ignored */ + +const char * +abkz(const char *s, char * buf, size_t buflen, size_t maxchars) +{ + const char *p = s; + char * bufp; + unsigned int c = 0; + size_t bpt, i; + ucs4_t ucs; + size_t size; + int result; + + /* Prüfen, ob Kurz genug */ + + if (strlen(s) <= maxchars) { + return s; + } + /* Anzahl der Wörter feststellen */ + + while (*p != 0) { + + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result==0 || "damnit, we're not handling invalid input here!"); + + /* Leerzeichen überspringen */ + while (*p != 0 && !iswalnum((wint_t)ucs)) { + p += size; + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result==0 || "damnit, we're not handling invalid input here!"); + } + + /* Counter erhöhen */ + if (*p != 0) ++c; + + /* alnums überspringen */ + while (*p != 0 && iswalnum((wint_t)ucs)) { + p+=size; + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result==0 || "damnit, we're not handling invalid input here!"); + } + } + + /* Buchstaben pro Teilkürzel = MAX(1,max/AnzWort) */ + + bpt = MAX(1, maxchars / c); + + /* Einzelne Wörter anspringen und jeweils die ersten BpT kopieren */ + + p = s; + c = 0; + bufp = buf; + + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result==0 || "damnit, we're not handling invalid input here!"); + + while (*p != 0 && c < maxchars) { + /* Leerzeichen überspringen */ + + while (*p != 0 && !iswalnum((wint_t)ucs)) { + p+=size; + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result==0 || "damnit, we're not handling invalid input here!"); + } + + /* alnums übertragen */ + + for (i = 0; i < bpt && *p != 0 && iswalnum((wint_t)ucs); ++i) { + memcpy(bufp, p, size); + p += size; + bufp += size; + ++c; + + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result==0 || "damnit, we're not handling invalid input here!"); + } + + /* Bis zum nächsten Leerzeichen */ + + while (c < maxchars && *p != 0 && iswalnum((wint_t)ucs)) { + p+=size; + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result==0 || "damnit, we're not handling invalid input here!"); + } + } + + *bufp = 0; + + return buf; +} + +void +register_names(void) +{ + register_function((pf_generic)describe_braineater, "describe_braineater"); + /* function name + * generate a name for a nonplayerunit + * race->generate_name() */ + register_function((pf_generic)undead_name, "nameundead"); + register_function((pf_generic)skeleton_name, "nameskeleton"); + register_function((pf_generic)zombie_name, "namezombie"); + register_function((pf_generic)ghoul_name, "nameghoul"); + register_function((pf_generic)dragon_name, "namedragon"); + register_function((pf_generic)dracoid_name, "namedracoid"); + register_function((pf_generic)generic_name, "namegeneric"); +} + + diff --git a/src/kernel/names.h b/src/kernel/names.h index 0cde3a55d..d689197d2 100644 --- a/src/kernel/names.h +++ b/src/kernel/names.h @@ -1,37 +1,37 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_NAMES -#define H_KRNL_NAMES -#ifdef __cplusplus -extern "C" { -#endif -extern void register_names(void); -const char *undead_name(const struct unit * u); -const char *skeleton_name(const struct unit * u); -const char *zombie_name(const struct unit * u); -const char *ghoul_name(const struct unit * u); -const char *dragon_name(const struct unit *u); -const char *dracoid_name(const struct unit *u); -const char *generic_name(const struct unit *u); -const char *abkz(const char *s, char * buf, size_t size, size_t maxchars); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_NAMES +#define H_KRNL_NAMES +#ifdef __cplusplus +extern "C" { +#endif +extern void register_names(void); +const char *undead_name(const struct unit * u); +const char *skeleton_name(const struct unit * u); +const char *zombie_name(const struct unit * u); +const char *ghoul_name(const struct unit * u); +const char *dragon_name(const struct unit *u); +const char *dracoid_name(const struct unit *u); +const char *generic_name(const struct unit *u); +const char *abkz(const char *s, char * buf, size_t size, size_t maxchars); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/objtypes.h b/src/kernel/objtypes.h index 6ba12e034..789ef0c5d 100644 --- a/src/kernel/objtypes.h +++ b/src/kernel/objtypes.h @@ -1,40 +1,40 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_OBJTYPES -#define H_KRNL_OBJTYPES -#ifdef __cplusplus -extern "C" { -#endif - -enum { - TYP_UNIT, - TYP_REGION, - TYP_BUILDING, - TYP_SHIP, - TYP_FACTION, - TYP_ACTION, - TYP_TRIGGER, - TYP_TIMEOUT -}; - -#ifdef __cplusplus -} -#endif -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_OBJTYPES +#define H_KRNL_OBJTYPES +#ifdef __cplusplus +extern "C" { +#endif + +enum { + TYP_UNIT, + TYP_REGION, + TYP_BUILDING, + TYP_SHIP, + TYP_FACTION, + TYP_ACTION, + TYP_TRIGGER, + TYP_TIMEOUT +}; + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/kernel/order.c b/src/kernel/order.c index 2ecf5162e..690cd0181 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -1,517 +1,517 @@ -/* vi: set ts=2: - +-------------------+ - | | Christian Schlittchen - | Eressea PBEM host | Enno Rehling - | (c) 1998 - 2004 | Katja Zedel - | | - +-------------------+ - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "order.h" - -#include "skill.h" - -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include - -# define ORD_KEYWORD(ord) (ord)->data->_keyword -# 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 * study_orders[MAXSKILLS]; - const struct locale * lang; -} locale_data; - -static struct locale_data * locale_array[16]; -static int nlocales = 0; - -typedef struct order_data { - char * _str; - int _refcount : 20; - int _lindex : 4; - keyword_t _keyword; -} order_data; - -static void -release_data(order_data * data) -{ - if (data) { - if (--data->_refcount == 0) { - if (data->_str) free(data->_str); - free(data); - } - } -} - -void -replace_order(order ** dlist, order * orig, const order * src) -{ - while (*dlist!=NULL) { - order * dst = *dlist; - if (dst->data==orig->data) { - order * cpy = copy_order(src); - *dlist = cpy; - cpy->next = dst->next; - dst->next = 0; - free_order(dst); - } - dlist = &(*dlist)->next; - } -} - -keyword_t -get_keyword(const order * ord) -{ - if (ord==NULL) { - return NOKEYWORD; - } - return ORD_KEYWORD(ord); -} - -/** returns a plain-text representation of the order. - * This is the inverse function to the parse_order command. Note that - * keywords are expanded to their full length. - */ -static char * -get_command(const order * ord, char * sbuffer, size_t size) -{ - char * bufp = sbuffer; - const char * text = ORD_STRING(ord); - keyword_t kwd = ORD_KEYWORD(ord); - int bytes; - - if (ord->_persistent) { - if (size>0) { - *bufp++ = '@'; - --size; - } else { - WARN_STATIC_BUFFER(); - } - } - if (kwd!=NOKEYWORD) { - const struct locale * lang = ORD_LOCALE(ord); - if (size>0) { - if (text) --size; - bytes = (int)strlcpy(bufp, (const char*)LOC(lang, keywords[kwd]), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (text) *bufp++ = ' '; - } else WARN_STATIC_BUFFER(); - } - if (text) { - bytes = (int)strlcpy(bufp, (const char *)text, size); - if (wrptr(&bufp, &size, bytes)!=0) { - WARN_STATIC_BUFFER(); - if (bufp-sbuffer>=6) { - bufp -= 6; - while (bufp>sbuffer&& (*bufp&0x80)!=0) { - ++size; - --bufp; - } - memcpy(bufp+1, "[...]", 6); /* TODO: make sure this only happens in eval_command */ - bufp += 6; - } - } - } - if (size>0) *bufp = 0; - return sbuffer; -} - -char * -getcommand(const order * ord) -{ - char sbuffer[DISPLAYSIZE*2]; - return strdup(get_command(ord, sbuffer, sizeof(sbuffer))); -} - -void -free_order(order * ord) -{ - if (ord!=NULL) { - assert(ord->next==0); - - release_data(ord->data); - free(ord); - } -} - -order * -copy_order(const order * src) -{ - if (src!=NULL) { - order * ord = (order*)malloc(sizeof(order)); - ord->next = NULL; - ord->_persistent = src->_persistent; - ord->data = src->data; - ++ord->data->_refcount; - return ord; - } - return NULL; -} - -void -set_order(struct order ** destp, struct order * src) -{ - if (*destp==src) return; - free_order(*destp); - *destp = src; -} - -void -free_orders(order ** olist) -{ - while (*olist) { - order * ord = *olist; - *olist = ord->next; - ord->next = NULL; - free_order(ord); - } -} - -static order_data * -create_data(keyword_t kwd, const char * sptr, int lindex) -{ - const char * s = sptr; - order_data * data; - const struct locale * lang = locale_array[lindex]->lang; - - if (kwd!=NOKEYWORD) s = (*sptr)?sptr:NULL; - - /* learning, only one order_data per skill required */ - if (kwd==K_STUDY) { - skill_t sk = findskill(parse_token(&sptr), lang); - switch (sk) { - case NOSKILL: /* fehler */ - break; - case SK_MAGIC: /* kann parameter haben */ - if (*sptr != 0) break; - default: /* nur skill als Parameter, keine extras */ - data = locale_array[lindex]->study_orders[sk]; - if (data==NULL) { - const char * skname = skillname(sk, lang); - data = (order_data*)malloc(sizeof(order_data)); - locale_array[lindex]->study_orders[sk] = data; - data->_keyword = kwd; - data->_lindex = lindex; - if (strchr(skname, ' ')!=NULL) { - size_t len = strlen(skname); - data->_str = malloc(len+3); - data->_str[0]='\"'; - memcpy(data->_str+1, skname, len); - data->_str[len+1]='\"'; - data->_str[len+2]='\0'; - } else { - data->_str = strdup(skname); - } - data->_refcount = 1; - } - ++data->_refcount; - return data; - } - } - - /* orders with no parameter, only one order_data per order required */ - else if (kwd!=NOKEYWORD && *sptr == 0) { - data = locale_array[lindex]->short_orders[kwd]; - if (data == NULL) { - data = (order_data*)malloc(sizeof(order_data)); - locale_array[lindex]->short_orders[kwd] = data; - data->_keyword = kwd; - data->_lindex = lindex; - data->_str = NULL; - data->_refcount = 1; - } - ++data->_refcount; - return data; - } - data = (order_data*)malloc(sizeof(order_data)); - data->_keyword = kwd; - data->_lindex = lindex; - data->_str = s?strdup(s):NULL; - data->_refcount = 1; - return data; -} - -static order * -create_order_i(keyword_t kwd, const char * sptr, int persistent, const struct locale * lang) -{ - order * ord = NULL; - int lindex; - - /* if this is just nonsense, then we skip it. */ - if (lomem) { - switch (kwd) { - case K_KOMMENTAR: - case NOKEYWORD: - return NULL; - case K_LIEFERE: - kwd = K_GIVE; - persistent = 1; - break; - default: - break; - } - } - - for (lindex=0;lindex!=nlocales;++lindex) { - if (locale_array[lindex]->lang==lang) break; - } - if (lindex==nlocales) { - locale_array[nlocales] = (locale_data*)calloc(1, sizeof(locale_data)); - locale_array[nlocales]->lang = lang; - ++nlocales; - } - - ord = (order*)malloc(sizeof(order)); - ord->_persistent = persistent; - ord->next = NULL; - - ord->data = create_data(kwd, sptr, lindex); - - return ord; -} - -order * -create_order(keyword_t kwd, const struct locale * lang, const char * params, ...) -{ - char zBuffer[DISPLAYSIZE]; - if (params) { - char * bufp = zBuffer; - int bytes; - size_t size = sizeof(zBuffer) - 1; - va_list marker; - - va_start(marker, params); - while (*params) { - if (*params=='%') { - int i; - const char * s; - ++params; - switch (*params) { - case 's': - s = va_arg(marker, const char *); - bytes = (int)strlcpy(bufp, s, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - break; - case 'd': - i = va_arg(marker, int); - bytes = (int)strlcpy(bufp, itoa10(i), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - break; - case 'i': - i = va_arg(marker, int); - bytes = (int)strlcpy(bufp, itoa36(i), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - break; - default: - assert(!"unknown format-character in create_order"); - } - } else if (size>0) { - *bufp++ = *params; - --size; - } - ++params; - } - va_end(marker); - *bufp = 0; - } else { - zBuffer[0] = 0; - } - return create_order_i(kwd, zBuffer, 0, lang); -} - -order * -parse_order(const char * s, const struct locale * lang) -{ - while (*s && !isalnum(*(unsigned char*)s) && !ispunct(*(unsigned char*)s)) ++s; - if (*s!=0) { - keyword_t kwd; - const char * sptr; - int persistent = 0; - - while (*s=='@') { - persistent = 1; - ++s; - } - sptr = s; - kwd = findkeyword(parse_token(&sptr), lang); - if (kwd!=NOKEYWORD) { - while (isxspace(*(unsigned char*)sptr)) ++sptr; - s = sptr; - } - return create_order_i(kwd, s, persistent, lang); - } - return NULL; -} - -boolean -is_repeated(const order * ord) -{ - keyword_t kwd = ORD_KEYWORD(ord); - const struct locale * lang = ORD_LOCALE(ord); - param_t param; - - switch (kwd) { - case K_CAST: - case K_BUY: - case K_SELL: - case K_ROUTE: - case K_DRIVE: - case K_WORK: - case K_BESIEGE: - case K_ENTERTAIN: - case K_TAX: - case K_RESEARCH: - case K_SPY: - case K_STEAL: - case K_SABOTAGE: - case K_STUDY: - case K_TEACH: - case K_BREED: - case K_PIRACY: - return true; - - case K_PLANT: - return true; - - case K_FOLLOW: - /* FOLLOW is only a long order if we are following a ship. */ - parser_pushstate(); - init_tokens(ord); - skip_token(); - param = getparam(lang); - parser_popstate(); - - if (param == P_SHIP) return true; - break; - - case K_MAKE: - /* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen - * Arten von MACHE zaehlen aber als neue defaults und werden - * behandelt wie die anderen (deswegen kein break nach case - * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) - * abgespeichert). */ - parser_pushstate(); - init_tokens(ord); /* initialize token-parser */ - skip_token(); - param = getparam(lang); - parser_popstate(); - - if (param != P_TEMP) return true; - break; - } - return false; -} - -boolean -is_exclusive(const order * ord) -{ - keyword_t kwd = ORD_KEYWORD(ord); - const struct locale * lang = ORD_LOCALE(ord); - param_t param; - - switch (kwd) { - case K_MOVE: - case K_WEREWOLF: - /* these should not become persistent */ - case K_ROUTE: - case K_DRIVE: - case K_WORK: - case K_BESIEGE: - case K_ENTERTAIN: - case K_TAX: - case K_RESEARCH: - case K_SPY: - case K_STEAL: - case K_SABOTAGE: - case K_STUDY: - case K_TEACH: - case K_BREED: - case K_PIRACY: - return true; - - case K_PLANT: - return true; - - case K_FOLLOW: - /* FOLLOW is only a long order if we are following a ship. */ - parser_pushstate(); - init_tokens(ord); - skip_token(); - param = getparam(lang); - parser_popstate(); - - if (param == P_SHIP) return true; - break; - - case K_MAKE: - /* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen - * Arten von MACHE zaehlen aber als neue defaults und werden - * behandelt wie die anderen (deswegen kein break nach case - * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) - * abgespeichert). */ - parser_pushstate(); - init_tokens(ord); /* initialize token-parser */ - skip_token(); - param = getparam(lang); - parser_popstate(); - - if (param != P_TEMP) return true; - break; - } - return false; -} - -boolean -is_persistent(const order * ord) -{ - keyword_t kwd = ORD_KEYWORD(ord); - boolean persist = ord->_persistent!=0; - switch (kwd) { - case K_MOVE: - case K_WEREWOLF: - case NOKEYWORD: - /* lang, aber niemals persistent! */ - return false; - - case K_KOMMENTAR: - case K_LIEFERE: - return true; - } - - return persist || is_repeated(ord); -} - -char * -write_order(const order * ord, char * buffer, size_t size) -{ - if (ord==0) { - buffer[0]=0; - } else { - keyword_t kwd = ORD_KEYWORD(ord); - if (kwd==NOKEYWORD) { - const char * text = ORD_STRING(ord); - strlcpy(buffer, (const char *)text, size); - } else { - get_command(ord, buffer, size); - } - } - return buffer; -} +/* vi: set ts=2: + +-------------------+ + | | Christian Schlittchen + | Eressea PBEM host | Enno Rehling + | (c) 1998 - 2004 | Katja Zedel + | | + +-------------------+ + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "order.h" + +#include "skill.h" + +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +# define ORD_KEYWORD(ord) (ord)->data->_keyword +# 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 * study_orders[MAXSKILLS]; + const struct locale * lang; +} locale_data; + +static struct locale_data * locale_array[16]; +static int nlocales = 0; + +typedef struct order_data { + char * _str; + int _refcount : 20; + int _lindex : 4; + keyword_t _keyword; +} order_data; + +static void +release_data(order_data * data) +{ + if (data) { + if (--data->_refcount == 0) { + if (data->_str) free(data->_str); + free(data); + } + } +} + +void +replace_order(order ** dlist, order * orig, const order * src) +{ + while (*dlist!=NULL) { + order * dst = *dlist; + if (dst->data==orig->data) { + order * cpy = copy_order(src); + *dlist = cpy; + cpy->next = dst->next; + dst->next = 0; + free_order(dst); + } + dlist = &(*dlist)->next; + } +} + +keyword_t +get_keyword(const order * ord) +{ + if (ord==NULL) { + return NOKEYWORD; + } + return ORD_KEYWORD(ord); +} + +/** returns a plain-text representation of the order. + * This is the inverse function to the parse_order command. Note that + * keywords are expanded to their full length. + */ +static char * +get_command(const order * ord, char * sbuffer, size_t size) +{ + char * bufp = sbuffer; + const char * text = ORD_STRING(ord); + keyword_t kwd = ORD_KEYWORD(ord); + int bytes; + + if (ord->_persistent) { + if (size>0) { + *bufp++ = '@'; + --size; + } else { + WARN_STATIC_BUFFER(); + } + } + if (kwd!=NOKEYWORD) { + const struct locale * lang = ORD_LOCALE(ord); + if (size>0) { + if (text) --size; + bytes = (int)strlcpy(bufp, (const char*)LOC(lang, keywords[kwd]), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (text) *bufp++ = ' '; + } else WARN_STATIC_BUFFER(); + } + if (text) { + bytes = (int)strlcpy(bufp, (const char *)text, size); + if (wrptr(&bufp, &size, bytes)!=0) { + WARN_STATIC_BUFFER(); + if (bufp-sbuffer>=6) { + bufp -= 6; + while (bufp>sbuffer&& (*bufp&0x80)!=0) { + ++size; + --bufp; + } + memcpy(bufp+1, "[...]", 6); /* TODO: make sure this only happens in eval_command */ + bufp += 6; + } + } + } + if (size>0) *bufp = 0; + return sbuffer; +} + +char * +getcommand(const order * ord) +{ + char sbuffer[DISPLAYSIZE*2]; + return strdup(get_command(ord, sbuffer, sizeof(sbuffer))); +} + +void +free_order(order * ord) +{ + if (ord!=NULL) { + assert(ord->next==0); + + release_data(ord->data); + free(ord); + } +} + +order * +copy_order(const order * src) +{ + if (src!=NULL) { + order * ord = (order*)malloc(sizeof(order)); + ord->next = NULL; + ord->_persistent = src->_persistent; + ord->data = src->data; + ++ord->data->_refcount; + return ord; + } + return NULL; +} + +void +set_order(struct order ** destp, struct order * src) +{ + if (*destp==src) return; + free_order(*destp); + *destp = src; +} + +void +free_orders(order ** olist) +{ + while (*olist) { + order * ord = *olist; + *olist = ord->next; + ord->next = NULL; + free_order(ord); + } +} + +static order_data * +create_data(keyword_t kwd, const char * sptr, int lindex) +{ + const char * s = sptr; + order_data * data; + const struct locale * lang = locale_array[lindex]->lang; + + if (kwd!=NOKEYWORD) s = (*sptr)?sptr:NULL; + + /* learning, only one order_data per skill required */ + if (kwd==K_STUDY) { + skill_t sk = findskill(parse_token(&sptr), lang); + switch (sk) { + case NOSKILL: /* fehler */ + break; + case SK_MAGIC: /* kann parameter haben */ + if (*sptr != 0) break; + default: /* nur skill als Parameter, keine extras */ + data = locale_array[lindex]->study_orders[sk]; + if (data==NULL) { + const char * skname = skillname(sk, lang); + data = (order_data*)malloc(sizeof(order_data)); + locale_array[lindex]->study_orders[sk] = data; + data->_keyword = kwd; + data->_lindex = lindex; + if (strchr(skname, ' ')!=NULL) { + size_t len = strlen(skname); + data->_str = malloc(len+3); + data->_str[0]='\"'; + memcpy(data->_str+1, skname, len); + data->_str[len+1]='\"'; + data->_str[len+2]='\0'; + } else { + data->_str = strdup(skname); + } + data->_refcount = 1; + } + ++data->_refcount; + return data; + } + } + + /* orders with no parameter, only one order_data per order required */ + else if (kwd!=NOKEYWORD && *sptr == 0) { + data = locale_array[lindex]->short_orders[kwd]; + if (data == NULL) { + data = (order_data*)malloc(sizeof(order_data)); + locale_array[lindex]->short_orders[kwd] = data; + data->_keyword = kwd; + data->_lindex = lindex; + data->_str = NULL; + data->_refcount = 1; + } + ++data->_refcount; + return data; + } + data = (order_data*)malloc(sizeof(order_data)); + data->_keyword = kwd; + data->_lindex = lindex; + data->_str = s?strdup(s):NULL; + data->_refcount = 1; + return data; +} + +static order * +create_order_i(keyword_t kwd, const char * sptr, int persistent, const struct locale * lang) +{ + order * ord = NULL; + int lindex; + + /* if this is just nonsense, then we skip it. */ + if (lomem) { + switch (kwd) { + case K_KOMMENTAR: + case NOKEYWORD: + return NULL; + case K_LIEFERE: + kwd = K_GIVE; + persistent = 1; + break; + default: + break; + } + } + + for (lindex=0;lindex!=nlocales;++lindex) { + if (locale_array[lindex]->lang==lang) break; + } + if (lindex==nlocales) { + locale_array[nlocales] = (locale_data*)calloc(1, sizeof(locale_data)); + locale_array[nlocales]->lang = lang; + ++nlocales; + } + + ord = (order*)malloc(sizeof(order)); + ord->_persistent = persistent; + ord->next = NULL; + + ord->data = create_data(kwd, sptr, lindex); + + return ord; +} + +order * +create_order(keyword_t kwd, const struct locale * lang, const char * params, ...) +{ + char zBuffer[DISPLAYSIZE]; + if (params) { + char * bufp = zBuffer; + int bytes; + size_t size = sizeof(zBuffer) - 1; + va_list marker; + + va_start(marker, params); + while (*params) { + if (*params=='%') { + int i; + const char * s; + ++params; + switch (*params) { + case 's': + s = va_arg(marker, const char *); + bytes = (int)strlcpy(bufp, s, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + break; + case 'd': + i = va_arg(marker, int); + bytes = (int)strlcpy(bufp, itoa10(i), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + break; + case 'i': + i = va_arg(marker, int); + bytes = (int)strlcpy(bufp, itoa36(i), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + break; + default: + assert(!"unknown format-character in create_order"); + } + } else if (size>0) { + *bufp++ = *params; + --size; + } + ++params; + } + va_end(marker); + *bufp = 0; + } else { + zBuffer[0] = 0; + } + return create_order_i(kwd, zBuffer, 0, lang); +} + +order * +parse_order(const char * s, const struct locale * lang) +{ + while (*s && !isalnum(*(unsigned char*)s) && !ispunct(*(unsigned char*)s)) ++s; + if (*s!=0) { + keyword_t kwd; + const char * sptr; + int persistent = 0; + + while (*s=='@') { + persistent = 1; + ++s; + } + sptr = s; + kwd = findkeyword(parse_token(&sptr), lang); + if (kwd!=NOKEYWORD) { + while (isxspace(*(unsigned char*)sptr)) ++sptr; + s = sptr; + } + return create_order_i(kwd, s, persistent, lang); + } + return NULL; +} + +boolean +is_repeated(const order * ord) +{ + keyword_t kwd = ORD_KEYWORD(ord); + const struct locale * lang = ORD_LOCALE(ord); + param_t param; + + switch (kwd) { + case K_CAST: + case K_BUY: + case K_SELL: + case K_ROUTE: + case K_DRIVE: + case K_WORK: + case K_BESIEGE: + case K_ENTERTAIN: + case K_TAX: + case K_RESEARCH: + case K_SPY: + case K_STEAL: + case K_SABOTAGE: + case K_STUDY: + case K_TEACH: + case K_BREED: + case K_PIRACY: + return true; + + case K_PLANT: + return true; + + case K_FOLLOW: + /* FOLLOW is only a long order if we are following a ship. */ + parser_pushstate(); + init_tokens(ord); + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param == P_SHIP) return true; + break; + + case K_MAKE: + /* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen + * Arten von MACHE zaehlen aber als neue defaults und werden + * behandelt wie die anderen (deswegen kein break nach case + * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) + * abgespeichert). */ + parser_pushstate(); + init_tokens(ord); /* initialize token-parser */ + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param != P_TEMP) return true; + break; + } + return false; +} + +boolean +is_exclusive(const order * ord) +{ + keyword_t kwd = ORD_KEYWORD(ord); + const struct locale * lang = ORD_LOCALE(ord); + param_t param; + + switch (kwd) { + case K_MOVE: + case K_WEREWOLF: + /* these should not become persistent */ + case K_ROUTE: + case K_DRIVE: + case K_WORK: + case K_BESIEGE: + case K_ENTERTAIN: + case K_TAX: + case K_RESEARCH: + case K_SPY: + case K_STEAL: + case K_SABOTAGE: + case K_STUDY: + case K_TEACH: + case K_BREED: + case K_PIRACY: + return true; + + case K_PLANT: + return true; + + case K_FOLLOW: + /* FOLLOW is only a long order if we are following a ship. */ + parser_pushstate(); + init_tokens(ord); + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param == P_SHIP) return true; + break; + + case K_MAKE: + /* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen + * Arten von MACHE zaehlen aber als neue defaults und werden + * behandelt wie die anderen (deswegen kein break nach case + * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) + * abgespeichert). */ + parser_pushstate(); + init_tokens(ord); /* initialize token-parser */ + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param != P_TEMP) return true; + break; + } + return false; +} + +boolean +is_persistent(const order * ord) +{ + keyword_t kwd = ORD_KEYWORD(ord); + boolean persist = ord->_persistent!=0; + switch (kwd) { + case K_MOVE: + case K_WEREWOLF: + case NOKEYWORD: + /* lang, aber niemals persistent! */ + return false; + + case K_KOMMENTAR: + case K_LIEFERE: + return true; + } + + return persist || is_repeated(ord); +} + +char * +write_order(const order * ord, char * buffer, size_t size) +{ + if (ord==0) { + buffer[0]=0; + } else { + keyword_t kwd = ORD_KEYWORD(ord); + if (kwd==NOKEYWORD) { + const char * text = ORD_STRING(ord); + strlcpy(buffer, (const char *)text, size); + } else { + get_command(ord, buffer, size); + } + } + return buffer; +} diff --git a/src/kernel/order.h b/src/kernel/order.h index 5d87fe045..29f273863 100644 --- a/src/kernel/order.h +++ b/src/kernel/order.h @@ -1,61 +1,61 @@ -/* vi: set ts=2: - +-------------------+ - | | Christian Schlittchen - | Eressea PBEM host | Enno Rehling - | (c) 1998 - 2004 | Katja Zedel - | | - +-------------------+ - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef KRNL_ORDER_H -#define KRNL_ORDER_H -#ifdef __cplusplus -extern "C" { -#endif - -/* Encapsulation of an order - * - * This structure contains one order given by a unit. These used to be - * stored in string lists, but by storing them in order-structures, - * it is possible to use reference-counting on them, reduce string copies, - * and reduce overall memory usage by sharing strings between orders (not - * implemented yet) saving approx. 50% of all string-related memory. - */ - -struct order_data; - -typedef struct order { - struct order * next; - /* do not access this data: */ - struct order_data * data; - int _persistent : 1; -} order; - -/* constructor */ -extern 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); - -/* reference counted copies of orders: */ -extern order * copy_order(const order * ord); -extern void free_order(order * ord); -extern void free_orders(order ** olist); - -/* access functions for orders */ -extern keyword_t get_keyword(const order * ord); -extern void set_order(order ** destp, order * src); -extern char * getcommand(const order * ord); -extern boolean is_persistent(const order *ord); -extern boolean is_exclusive(const order *ord); -extern boolean is_repeated(const order * ord); - -extern char * write_order(const order * ord, char * buffer, size_t size); - - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ + | | Christian Schlittchen + | Eressea PBEM host | Enno Rehling + | (c) 1998 - 2004 | Katja Zedel + | | + +-------------------+ + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef KRNL_ORDER_H +#define KRNL_ORDER_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Encapsulation of an order + * + * This structure contains one order given by a unit. These used to be + * stored in string lists, but by storing them in order-structures, + * it is possible to use reference-counting on them, reduce string copies, + * and reduce overall memory usage by sharing strings between orders (not + * implemented yet) saving approx. 50% of all string-related memory. + */ + +struct order_data; + +typedef struct order { + struct order * next; + /* do not access this data: */ + struct order_data * data; + int _persistent : 1; +} order; + +/* constructor */ +extern 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); + +/* reference counted copies of orders: */ +extern order * copy_order(const order * ord); +extern void free_order(order * ord); +extern void free_orders(order ** olist); + +/* access functions for orders */ +extern keyword_t get_keyword(const order * ord); +extern void set_order(order ** destp, order * src); +extern char * getcommand(const order * ord); +extern boolean is_persistent(const order *ord); +extern boolean is_exclusive(const order *ord); +extern boolean is_repeated(const order * ord); + +extern char * write_order(const order * ord, char * buffer, size_t size); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/pathfinder.c b/src/kernel/pathfinder.c index 5c2ebb9a7..29c52ed8b 100644 --- a/src/kernel/pathfinder.c +++ b/src/kernel/pathfinder.c @@ -1,200 +1,200 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "pathfinder.h" - -#include "region.h" -#include "terrain.h" - -#include -#include -#include - -boolean -allowed_swim(const region * src, const region * r) -{ - if (fval(r->terrain, SWIM_INTO)) return true; - return false; -} - -boolean -allowed_walk(const region * src, const region * r) -{ - if (fval(r->terrain, WALK_INTO)) return true; - return false; -} - -boolean -allowed_fly(const region * src, const region * r) -{ - if (fval(r->terrain, FLY_INTO)) return true; - return false; -} - -typedef struct node { - struct node * next; - region * r; - struct node * prev; - int distance; -} node; - -static node * node_garbage; - -void -pathfinder_cleanup(void) -{ - while (node_garbage) { - node * n = node_garbage; - node_garbage = n->next; - free(n); - } -} - -static node * -new_node(region * r, int distance, node * prev) -{ - node * n; - if (node_garbage!=NULL) { - n = node_garbage; - node_garbage = n->next; - } - else n = malloc(sizeof(node)); - n->next = NULL; - n->prev = prev; - n->r= r; - n->distance= distance; - return n; -} - -static node * -free_node(node * n) -{ - node * s = n->next; - n->next = node_garbage; - node_garbage = n; - return s; -} - -static void -free_nodes(node * root) -{ - while (root!=NULL) { - region * r = root->r; - freset(r, RF_MARK); - root = free_node(root); - } -} - -struct region_list * -regions_in_range(struct region * start, int maxdist, boolean (*allowed)(const struct region*, const struct region*)) -{ - region_list * rlist = NULL; - node * root = new_node(start, 0, NULL); - node ** end = &root->next; - node * n = root; - - while (n!=NULL) { - region * r = n->r; - int depth = n->distance+1; - direction_t d; - - if (n->distance >= maxdist) break; - for (d=0;d!=MAXDIRECTIONS; ++d) { - region * rn = rconnect(r, d); - if (rn==NULL) continue; - if (fval(rn, RF_MARK)) continue; /* already been there */ - if (allowed && !allowed(r, rn)) continue; /* can't go there */ - - /* add the region to the list of available ones. */ - add_regionlist(&rlist, rn); - - /* make sure we don't go here again, and put the region into the set for - further BFS'ing */ - fset(rn, RF_MARK); - *end = new_node(rn, depth, n); - end = &(*end)->next; - } - n = n->next; - } - free_nodes(root); - - return rlist; -} - -static region ** -internal_path_find(region *start, const region *target, int maxlen, boolean (*allowed)(const region*, const region*)) -{ - static region * path[MAXDEPTH+2]; /* STATIC_RETURN: used for return, not across calls */ - direction_t d; - node * root = new_node(start, 0, NULL); - node ** end = &root->next; - node * n = root; - boolean found = false; - assert(maxlen<=MAXDEPTH); - fset(start, RF_MARK); - - while (n!=NULL) { - region * r = n->r; - int depth = n->distance+1; - if (n->distance >= maxlen) break; - for (d=0;d!=MAXDIRECTIONS; ++d) { - region * rn = rconnect(r, d); - if (rn==NULL) continue; - if (fval(rn, RF_MARK)) continue; /* already been there */ - if (!allowed(r, rn)) continue; /* can't go there */ - if (rn==target) { - int i = depth; - path[i+1] = NULL; - path[i] = rn; - while (n) { - path[--i] = n->r; - n = n->prev; - } - found = true; - break; - } else { - fset(rn, RF_MARK); - *end = new_node(rn, depth, n); - end = &(*end)->next; - } - } - if (found) break; - n = n->next; - } - free_nodes(root); - if (found) return path; - return NULL; -} - -boolean -path_exists(region *start, const region *target, int maxlen, boolean (*allowed)(const region*, const region*)) -{ - assert((!fval(start, RF_MARK) && !fval(target, RF_MARK)) || !"Some Algorithm did not clear its RF_MARKs!"); - if (start==target) return true; - if (internal_path_find(start, target, maxlen, allowed)!=NULL) return true; - return false; -} - -region ** -path_find(region *start, const region *target, int maxlen, boolean (*allowed)(const region*, const region*)) -{ - assert((!fval(start, RF_MARK) && !fval(target, RF_MARK)) || !"Did you call path_init()?"); - return internal_path_find(start, target, maxlen, allowed); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "pathfinder.h" + +#include "region.h" +#include "terrain.h" + +#include +#include +#include + +boolean +allowed_swim(const region * src, const region * r) +{ + if (fval(r->terrain, SWIM_INTO)) return true; + return false; +} + +boolean +allowed_walk(const region * src, const region * r) +{ + if (fval(r->terrain, WALK_INTO)) return true; + return false; +} + +boolean +allowed_fly(const region * src, const region * r) +{ + if (fval(r->terrain, FLY_INTO)) return true; + return false; +} + +typedef struct node { + struct node * next; + region * r; + struct node * prev; + int distance; +} node; + +static node * node_garbage; + +void +pathfinder_cleanup(void) +{ + while (node_garbage) { + node * n = node_garbage; + node_garbage = n->next; + free(n); + } +} + +static node * +new_node(region * r, int distance, node * prev) +{ + node * n; + if (node_garbage!=NULL) { + n = node_garbage; + node_garbage = n->next; + } + else n = malloc(sizeof(node)); + n->next = NULL; + n->prev = prev; + n->r= r; + n->distance= distance; + return n; +} + +static node * +free_node(node * n) +{ + node * s = n->next; + n->next = node_garbage; + node_garbage = n; + return s; +} + +static void +free_nodes(node * root) +{ + while (root!=NULL) { + region * r = root->r; + freset(r, RF_MARK); + root = free_node(root); + } +} + +struct region_list * +regions_in_range(struct region * start, int maxdist, boolean (*allowed)(const struct region*, const struct region*)) +{ + region_list * rlist = NULL; + node * root = new_node(start, 0, NULL); + node ** end = &root->next; + node * n = root; + + while (n!=NULL) { + region * r = n->r; + int depth = n->distance+1; + direction_t d; + + if (n->distance >= maxdist) break; + for (d=0;d!=MAXDIRECTIONS; ++d) { + region * rn = rconnect(r, d); + if (rn==NULL) continue; + if (fval(rn, RF_MARK)) continue; /* already been there */ + if (allowed && !allowed(r, rn)) continue; /* can't go there */ + + /* add the region to the list of available ones. */ + add_regionlist(&rlist, rn); + + /* make sure we don't go here again, and put the region into the set for + further BFS'ing */ + fset(rn, RF_MARK); + *end = new_node(rn, depth, n); + end = &(*end)->next; + } + n = n->next; + } + free_nodes(root); + + return rlist; +} + +static region ** +internal_path_find(region *start, const region *target, int maxlen, boolean (*allowed)(const region*, const region*)) +{ + static region * path[MAXDEPTH+2]; /* STATIC_RETURN: used for return, not across calls */ + direction_t d; + node * root = new_node(start, 0, NULL); + node ** end = &root->next; + node * n = root; + boolean found = false; + assert(maxlen<=MAXDEPTH); + fset(start, RF_MARK); + + while (n!=NULL) { + region * r = n->r; + int depth = n->distance+1; + if (n->distance >= maxlen) break; + for (d=0;d!=MAXDIRECTIONS; ++d) { + region * rn = rconnect(r, d); + if (rn==NULL) continue; + if (fval(rn, RF_MARK)) continue; /* already been there */ + if (!allowed(r, rn)) continue; /* can't go there */ + if (rn==target) { + int i = depth; + path[i+1] = NULL; + path[i] = rn; + while (n) { + path[--i] = n->r; + n = n->prev; + } + found = true; + break; + } else { + fset(rn, RF_MARK); + *end = new_node(rn, depth, n); + end = &(*end)->next; + } + } + if (found) break; + n = n->next; + } + free_nodes(root); + if (found) return path; + return NULL; +} + +boolean +path_exists(region *start, const region *target, int maxlen, boolean (*allowed)(const region*, const region*)) +{ + assert((!fval(start, RF_MARK) && !fval(target, RF_MARK)) || !"Some Algorithm did not clear its RF_MARKs!"); + if (start==target) return true; + if (internal_path_find(start, target, maxlen, allowed)!=NULL) return true; + return false; +} + +region ** +path_find(region *start, const region *target, int maxlen, boolean (*allowed)(const region*, const region*)) +{ + assert((!fval(start, RF_MARK) && !fval(target, RF_MARK)) || !"Did you call path_init()?"); + return internal_path_find(start, target, maxlen, allowed); +} diff --git a/src/kernel/pathfinder.h b/src/kernel/pathfinder.h index 42785f25e..5ae704509 100644 --- a/src/kernel/pathfinder.h +++ b/src/kernel/pathfinder.h @@ -1,42 +1,42 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_PATHFINDER -#define H_KRNL_PATHFINDER -#ifdef __cplusplus -extern "C" { -#endif - -#define MAXDEPTH 1024 - -extern int search[MAXDEPTH][2]; -extern int search_len; - -extern struct region ** path_find(struct region *start, const struct region *target, int maxlen, boolean (*allowed)(const struct region*, const struct region*)); -extern boolean path_exists(struct region *start, const struct region *target, int maxlen, boolean (*allowed)(const struct region*, const struct region*)); -extern boolean allowed_swim(const struct region * src, const struct region * target); -extern boolean allowed_fly(const struct region * src, const struct region * target); -extern boolean allowed_walk(const struct region * src, const struct region * target); -extern struct region_list * regions_in_range(struct region * src, int maxdist, boolean (*allowed)(const struct region*, const struct region*)); - -extern void pathfinder_cleanup(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_PATHFINDER +#define H_KRNL_PATHFINDER +#ifdef __cplusplus +extern "C" { +#endif + +#define MAXDEPTH 1024 + +extern int search[MAXDEPTH][2]; +extern int search_len; + +extern struct region ** path_find(struct region *start, const struct region *target, int maxlen, boolean (*allowed)(const struct region*, const struct region*)); +extern boolean path_exists(struct region *start, const struct region *target, int maxlen, boolean (*allowed)(const struct region*, const struct region*)); +extern boolean allowed_swim(const struct region * src, const struct region * target); +extern boolean allowed_fly(const struct region * src, const struct region * target); +extern boolean allowed_walk(const struct region * src, const struct region * target); +extern struct region_list * regions_in_range(struct region * src, int maxdist, boolean (*allowed)(const struct region*, const struct region*)); + +extern void pathfinder_cleanup(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/plane.c b/src/kernel/plane.c index 929230285..8ab941838 100644 --- a/src/kernel/plane.c +++ b/src/kernel/plane.c @@ -1,326 +1,326 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "plane.h" - -/* kernel includes */ -#include "region.h" -#include "faction.h" - -/* util includes */ -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -struct plane *planes; - -int plane_width(const plane * pl) -{ - if (pl) { - return pl->maxx-pl->minx+1; - } - return 0; -} - -int plane_height(const plane * pl) -{ - if (pl) { - return pl->maxy-pl->miny+1; - } - return 0; -} - -static plane * home_plane = NULL; - -plane * -get_homeplane(void) -{ - return getplanebyid(0); -} - - -plane * -getplane(const region *r) -{ - if (r) { - return r->_plane; - } - return get_homeplane(); -} - -plane * -getplanebyid(int id) -{ - plane *p; - - for (p=planes; p; p=p->next) { - if (p->id == id) { - return p; - } - } - return NULL; -} - -plane * -getplanebyname(const char * name) -{ - plane *p; - - for (p=planes; p; p=p->next) - if (p->name && !strcmp(p->name, name)) - return p; - return NULL; -} - -plane * -findplane(int x, int y) -{ - plane *pl; - - for(pl=planes;pl;pl=pl->next) { - if(x >= pl->minx && x <= pl->maxx - && y >= pl->miny && y <= pl->maxy) { - return pl; - } - } - return NULL; -} - -int -getplaneid(const region *r) - -{ - if(r) { - plane * pl = getplane(r); - if (pl) return pl->id; - - for(pl=planes;pl;pl=pl->next) { - if(r->x >= pl->minx && r->x <= pl->maxx - && r->y >= pl->miny && r->y <= pl->maxy) { - return pl->id; - } - } - } - return 0; -} - -static int -ursprung_x(const faction *f, const plane *pl, const region * rdefault) -{ - ursprung *ur; - int id = 0; - - if(!f) - return 0; - - if(pl) - id = pl->id; - - for(ur = f->ursprung; ur; ur = ur->next) { - if(ur->id == id) - return ur->x; - } - if (!rdefault) return 0; - set_ursprung((faction*)f, id, rdefault->x - plane_center_x(pl), rdefault->y - plane_center_y(pl)); - return rdefault->x - plane_center_x(pl); -} - -static int -ursprung_y(const faction *f, const plane *pl, const region * rdefault) -{ - ursprung *ur; - int id = 0; - - if(!f) - return 0; - - if(pl) - id = pl->id; - - for(ur = f->ursprung; ur; ur = ur->next) { - if(ur->id == id) - return ur->y; - } - if (!rdefault) return 0; - set_ursprung((faction*)f, id, rdefault->x - plane_center_x(pl), rdefault->y - plane_center_y(pl)); - return rdefault->y - plane_center_y(pl); -} - -int -plane_center_x(const plane *pl) -{ - if(pl == NULL) - return 0; - - return(pl->minx + pl->maxx)/2; -} - -int -plane_center_y(const plane *pl) -{ - if(pl == NULL) - return 0; - - return(pl->miny + pl->maxy)/2; -} - -void -adjust_coordinates(const faction *f, int *x, int *y, const plane * pl, const region * r) -{ - int nx = *x; - int ny = *y; - if (f) { - nx -= ursprung_x(f, pl, r); - ny -= ursprung_y(f, pl, r); - } - if (pl) { - nx -= plane_center_x(pl); - ny -= plane_center_y(pl); - } - - if (pl) { - int width = plane_width(pl); - int height = plane_height(pl); - int width_2 = width/2; - int height_2 = height/2; - - if (nx<0) nx = (width-(-nx)%width); - if (nx>width_2) nx -= width; - if (ny<0) ny = (height-(-ny)%height); - if (ny>height_2) ny -= height; - } - - assert(!pl || nx<=pl->maxx - plane_center_x(pl)); - assert(!pl || nx>=pl->minx - plane_center_x(pl)); - assert(!pl || ny<=pl->maxy - plane_center_y(pl)); - assert(!pl || ny>=pl->miny - plane_center_y(pl)); - - *x = nx; - *y = ny; -} - -void -set_ursprung(faction *f, int id, int x, int y) -{ - ursprung *ur; - assert(f!=NULL); - for(ur=f->ursprung;ur;ur=ur->next) { - if (ur->id == id) { - ur->x = ur->x + x; - ur->y = ur->y + y; - return; - } - } - - ur = calloc(1, sizeof(ursprung)); - ur->id = id; - ur->x = x; - ur->y = y; - - addlist(&f->ursprung, ur); -} - -plane * -create_new_plane(int id, const char *name, int minx, int maxx, int miny, int maxy, int flags) -{ - plane *pl = getplanebyid(id); - - if (pl) return pl; - pl = calloc(1, sizeof(plane)); - - pl->next = NULL; - pl->id = id; - if (name) pl->name = strdup(name); - pl->minx = minx; - pl->maxx = maxx; - pl->miny = miny; - pl->maxy = maxy; - pl->flags = flags; - - addlist(&planes, pl); - if (id==0) { - home_plane = pl; - } - return pl; -} - -/* Umrechnung Relative-Absolute-Koordinaten */ -int -rel_to_abs(const struct plane *pl, const struct faction * f, int rel, unsigned char index) -{ - assert(index == 0 || index == 1); - - if(index == 0) - return (rel + ursprung_x(f, pl, NULL) + plane_center_x(pl)); - - return (rel + ursprung_y(f, pl, NULL) + plane_center_y(pl)); -} - - -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) -{ - store->w_int(store, u?(u->id):0); -} - -int -read_plane_reference(plane ** pp, struct storage * store) -{ - variant id; - id.i = store->r_int(store); - 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; -} - -boolean -is_watcher(const struct plane * p, const struct faction * f) -{ - struct watcher * w; - if (!p) return false; - w = p->watchers; - while (w && w->faction!=f) w=w->next; - return (w!=NULL); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "plane.h" + +/* kernel includes */ +#include "region.h" +#include "faction.h" + +/* util includes */ +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +struct plane *planes; + +int plane_width(const plane * pl) +{ + if (pl) { + return pl->maxx-pl->minx+1; + } + return 0; +} + +int plane_height(const plane * pl) +{ + if (pl) { + return pl->maxy-pl->miny+1; + } + return 0; +} + +static plane * home_plane = NULL; + +plane * +get_homeplane(void) +{ + return getplanebyid(0); +} + + +plane * +getplane(const region *r) +{ + if (r) { + return r->_plane; + } + return get_homeplane(); +} + +plane * +getplanebyid(int id) +{ + plane *p; + + for (p=planes; p; p=p->next) { + if (p->id == id) { + return p; + } + } + return NULL; +} + +plane * +getplanebyname(const char * name) +{ + plane *p; + + for (p=planes; p; p=p->next) + if (p->name && !strcmp(p->name, name)) + return p; + return NULL; +} + +plane * +findplane(int x, int y) +{ + plane *pl; + + for(pl=planes;pl;pl=pl->next) { + if(x >= pl->minx && x <= pl->maxx + && y >= pl->miny && y <= pl->maxy) { + return pl; + } + } + return NULL; +} + +int +getplaneid(const region *r) + +{ + if(r) { + plane * pl = getplane(r); + if (pl) return pl->id; + + for(pl=planes;pl;pl=pl->next) { + if(r->x >= pl->minx && r->x <= pl->maxx + && r->y >= pl->miny && r->y <= pl->maxy) { + return pl->id; + } + } + } + return 0; +} + +static int +ursprung_x(const faction *f, const plane *pl, const region * rdefault) +{ + ursprung *ur; + int id = 0; + + if(!f) + return 0; + + if(pl) + id = pl->id; + + for(ur = f->ursprung; ur; ur = ur->next) { + if(ur->id == id) + return ur->x; + } + if (!rdefault) return 0; + set_ursprung((faction*)f, id, rdefault->x - plane_center_x(pl), rdefault->y - plane_center_y(pl)); + return rdefault->x - plane_center_x(pl); +} + +static int +ursprung_y(const faction *f, const plane *pl, const region * rdefault) +{ + ursprung *ur; + int id = 0; + + if(!f) + return 0; + + if(pl) + id = pl->id; + + for(ur = f->ursprung; ur; ur = ur->next) { + if(ur->id == id) + return ur->y; + } + if (!rdefault) return 0; + set_ursprung((faction*)f, id, rdefault->x - plane_center_x(pl), rdefault->y - plane_center_y(pl)); + return rdefault->y - plane_center_y(pl); +} + +int +plane_center_x(const plane *pl) +{ + if(pl == NULL) + return 0; + + return(pl->minx + pl->maxx)/2; +} + +int +plane_center_y(const plane *pl) +{ + if(pl == NULL) + return 0; + + return(pl->miny + pl->maxy)/2; +} + +void +adjust_coordinates(const faction *f, int *x, int *y, const plane * pl, const region * r) +{ + int nx = *x; + int ny = *y; + if (f) { + nx -= ursprung_x(f, pl, r); + ny -= ursprung_y(f, pl, r); + } + if (pl) { + nx -= plane_center_x(pl); + ny -= plane_center_y(pl); + } + + if (pl) { + int width = plane_width(pl); + int height = plane_height(pl); + int width_2 = width/2; + int height_2 = height/2; + + if (nx<0) nx = (width-(-nx)%width); + if (nx>width_2) nx -= width; + if (ny<0) ny = (height-(-ny)%height); + if (ny>height_2) ny -= height; + } + + assert(!pl || nx<=pl->maxx - plane_center_x(pl)); + assert(!pl || nx>=pl->minx - plane_center_x(pl)); + assert(!pl || ny<=pl->maxy - plane_center_y(pl)); + assert(!pl || ny>=pl->miny - plane_center_y(pl)); + + *x = nx; + *y = ny; +} + +void +set_ursprung(faction *f, int id, int x, int y) +{ + ursprung *ur; + assert(f!=NULL); + for(ur=f->ursprung;ur;ur=ur->next) { + if (ur->id == id) { + ur->x = ur->x + x; + ur->y = ur->y + y; + return; + } + } + + ur = calloc(1, sizeof(ursprung)); + ur->id = id; + ur->x = x; + ur->y = y; + + addlist(&f->ursprung, ur); +} + +plane * +create_new_plane(int id, const char *name, int minx, int maxx, int miny, int maxy, int flags) +{ + plane *pl = getplanebyid(id); + + if (pl) return pl; + pl = calloc(1, sizeof(plane)); + + pl->next = NULL; + pl->id = id; + if (name) pl->name = strdup(name); + pl->minx = minx; + pl->maxx = maxx; + pl->miny = miny; + pl->maxy = maxy; + pl->flags = flags; + + addlist(&planes, pl); + if (id==0) { + home_plane = pl; + } + return pl; +} + +/* Umrechnung Relative-Absolute-Koordinaten */ +int +rel_to_abs(const struct plane *pl, const struct faction * f, int rel, unsigned char index) +{ + assert(index == 0 || index == 1); + + if(index == 0) + return (rel + ursprung_x(f, pl, NULL) + plane_center_x(pl)); + + return (rel + ursprung_y(f, pl, NULL) + plane_center_y(pl)); +} + + +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) +{ + store->w_int(store, u?(u->id):0); +} + +int +read_plane_reference(plane ** pp, struct storage * store) +{ + variant id; + id.i = store->r_int(store); + 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; +} + +boolean +is_watcher(const struct plane * p, const struct faction * f) +{ + struct watcher * w; + if (!p) return false; + w = p->watchers; + while (w && w->faction!=f) w=w->next; + return (w!=NULL); +} diff --git a/src/kernel/plane.h b/src/kernel/plane.h index d5536b86e..f7827679f 100644 --- a/src/kernel/plane.h +++ b/src/kernel/plane.h @@ -1,84 +1,84 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_PLANES -#define H_KRNL_PLANES -#ifdef __cplusplus -extern "C" { -#endif - -#define PFL_NOCOORDS 1 /* not in use */ -#define PFL_NORECRUITS 2 -#define PFL_NOALLIANCES 4 -#define PFL_LOWSTEALING 8 -#define PFL_NOGIVE 16 /* Übergaben sind unmöglich */ -#define PFL_NOATTACK 32 /* Angriffe und Diebstähle sind unmöglich */ -#define PFL_NOTERRAIN 64 /* Terraintyp wird nicht angezeigt TODO? */ -#define PFL_NOMAGIC 128 /* Zaubern ist unmöglich */ -#define PFL_NOSTEALTH 256 /* Tarnung außer Betrieb */ -#define PFL_NOTEACH 512 /* Lehre außer Betrieb */ -#define PFL_NOBUILD 1024 /* Bauen außer Betrieb */ -#define PFL_NOFEED 2048 /* Kein Unterhalt nötig */ -#define PFL_FRIENDLY 4096 /* everyone is your ally */ -#define PFL_NOORCGROWTH 8192 /* orcs don't grow */ -#define PFL_NOMONSTERS 16384 /* no monster randenc */ -#define PFL_SEESPECIAL 32768 /* far seeing */ - -typedef struct watcher { - struct watcher * next; - struct faction * faction; - unsigned char mode; -} watcher; - -typedef struct plane { - struct plane *next; - struct watcher * watchers; - int id; - char *name; - int minx, maxx, miny, maxy; - unsigned int flags; - struct attrib *attribs; -} plane; - -#define plane_id(pl) ( (pl) ? (pl)->id : 0 ) - -extern struct plane *planes; - -struct plane *getplane(const struct region *r); -struct plane *findplane(int x, int y); -void init_planes(void); -int getplaneid(const struct region *r); -struct plane * getplanebyid(int id); -int plane_center_x(const struct plane *pl); -int plane_center_y(const struct plane *pl); -void set_ursprung(struct faction *f, int id, int x, int y); -struct plane * create_new_plane(int id, const char *name, int minx, int maxx, int miny, int maxy, int flags); -struct plane * getplanebyname(const char *); -struct plane * get_homeplane(void); -extern int rel_to_abs(const struct plane *pl, const struct faction * f, int rel, unsigned char index); -extern boolean is_watcher(const struct plane * p, const struct faction * f); -extern int resolve_plane(variant data, void * addr); -extern void write_plane_reference(const plane * p, struct storage * store); -extern int read_plane_reference(plane ** pp, struct storage * store); -extern int plane_width(const plane * pl); -extern int plane_height(const plane * pl); -void adjust_coordinates(const struct faction *f, int *x, int *y, const struct plane * pl, const struct region * r); -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_PLANES +#define H_KRNL_PLANES +#ifdef __cplusplus +extern "C" { +#endif + +#define PFL_NOCOORDS 1 /* not in use */ +#define PFL_NORECRUITS 2 +#define PFL_NOALLIANCES 4 +#define PFL_LOWSTEALING 8 +#define PFL_NOGIVE 16 /* Übergaben sind unmöglich */ +#define PFL_NOATTACK 32 /* Angriffe und Diebstähle sind unmöglich */ +#define PFL_NOTERRAIN 64 /* Terraintyp wird nicht angezeigt TODO? */ +#define PFL_NOMAGIC 128 /* Zaubern ist unmöglich */ +#define PFL_NOSTEALTH 256 /* Tarnung außer Betrieb */ +#define PFL_NOTEACH 512 /* Lehre außer Betrieb */ +#define PFL_NOBUILD 1024 /* Bauen außer Betrieb */ +#define PFL_NOFEED 2048 /* Kein Unterhalt nötig */ +#define PFL_FRIENDLY 4096 /* everyone is your ally */ +#define PFL_NOORCGROWTH 8192 /* orcs don't grow */ +#define PFL_NOMONSTERS 16384 /* no monster randenc */ +#define PFL_SEESPECIAL 32768 /* far seeing */ + +typedef struct watcher { + struct watcher * next; + struct faction * faction; + unsigned char mode; +} watcher; + +typedef struct plane { + struct plane *next; + struct watcher * watchers; + int id; + char *name; + int minx, maxx, miny, maxy; + unsigned int flags; + struct attrib *attribs; +} plane; + +#define plane_id(pl) ( (pl) ? (pl)->id : 0 ) + +extern struct plane *planes; + +struct plane *getplane(const struct region *r); +struct plane *findplane(int x, int y); +void init_planes(void); +int getplaneid(const struct region *r); +struct plane * getplanebyid(int id); +int plane_center_x(const struct plane *pl); +int plane_center_y(const struct plane *pl); +void set_ursprung(struct faction *f, int id, int x, int y); +struct plane * create_new_plane(int id, const char *name, int minx, int maxx, int miny, int maxy, int flags); +struct plane * getplanebyname(const char *); +struct plane * get_homeplane(void); +extern int rel_to_abs(const struct plane *pl, const struct faction * f, int rel, unsigned char index); +extern boolean is_watcher(const struct plane * p, const struct faction * f); +extern int resolve_plane(variant data, void * addr); +extern void write_plane_reference(const plane * p, struct storage * store); +extern int read_plane_reference(plane ** pp, struct storage * store); +extern int plane_width(const plane * pl); +extern int plane_height(const plane * pl); +void adjust_coordinates(const struct faction *f, int *x, int *y, const struct plane * pl, const struct region * r); +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/player.c b/src/kernel/player.c index 5ac1dd457..c8076f640 100644 --- a/src/kernel/player.c +++ b/src/kernel/player.c @@ -1,101 +1,101 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - - */ -#include -#include "player.h" - -#include -#include - -#include -#include - -#define PMAXHASH 1021 - -typedef struct player_hash { - struct player * entries; -} player_hash; - -static player_hash * players[PMAXHASH]; - -player * -make_player(const struct faction * f) -{ - player * p = calloc(sizeof(player), 1); - unsigned int hash; - - for (p->id = rng_int();;p->id++) { - /* if there is a hashing conflict, resolve it */ - player * pi = get_player(p->id); - if (pi) p->id++; - else break; - } - hash = p->id % PMAXHASH; - p->faction = f; - p->nexthash = players[hash]->entries; - players[hash]->entries = p; - - return p; -} - -player * -next_player(player * p) -{ - if (p->nexthash) return p->nexthash; - else { - unsigned int hash = p->id % PMAXHASH; - p = NULL; - while (++hash!=PMAXHASH) { - if (players[hash]->entries!=NULL) { - p = players[hash]->entries; - break; - } - } - return p; - } -} - -player * -get_player(unsigned int id) -{ - unsigned int hash = id % PMAXHASH; - struct player * p = players[hash]->entries; - - while (p && p->id!=id) p = p->nexthash; - return p; -} - -player * -get_players(void) -{ - struct player * p = NULL; - unsigned int hash = 0; - - while (p!=NULL && hash!=PMAXHASH) { - p = players[hash++]->entries; - } - return p; -} - -void -players_done(void) -{ - int i; - for (i=0;i!=PMAXHASH;++i) { - player * p = players[i]->entries; - players[i]->entries = p->nexthash; - free(p->name); - if (p->email) free(p->email); - if (p->name) free(p->name); - free(p); - } -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ +#include +#include "player.h" + +#include +#include + +#include +#include + +#define PMAXHASH 1021 + +typedef struct player_hash { + struct player * entries; +} player_hash; + +static player_hash * players[PMAXHASH]; + +player * +make_player(const struct faction * f) +{ + player * p = calloc(sizeof(player), 1); + unsigned int hash; + + for (p->id = rng_int();;p->id++) { + /* if there is a hashing conflict, resolve it */ + player * pi = get_player(p->id); + if (pi) p->id++; + else break; + } + hash = p->id % PMAXHASH; + p->faction = f; + p->nexthash = players[hash]->entries; + players[hash]->entries = p; + + return p; +} + +player * +next_player(player * p) +{ + if (p->nexthash) return p->nexthash; + else { + unsigned int hash = p->id % PMAXHASH; + p = NULL; + while (++hash!=PMAXHASH) { + if (players[hash]->entries!=NULL) { + p = players[hash]->entries; + break; + } + } + return p; + } +} + +player * +get_player(unsigned int id) +{ + unsigned int hash = id % PMAXHASH; + struct player * p = players[hash]->entries; + + while (p && p->id!=id) p = p->nexthash; + return p; +} + +player * +get_players(void) +{ + struct player * p = NULL; + unsigned int hash = 0; + + while (p!=NULL && hash!=PMAXHASH) { + p = players[hash++]->entries; + } + return p; +} + +void +players_done(void) +{ + int i; + for (i=0;i!=PMAXHASH;++i) { + player * p = players[i]->entries; + players[i]->entries = p->nexthash; + free(p->name); + if (p->email) free(p->email); + if (p->name) free(p->name); + free(p); + } +} diff --git a/src/kernel/player.h b/src/kernel/player.h index d70fa4ad2..74fb8c4a5 100644 --- a/src/kernel/player.h +++ b/src/kernel/player.h @@ -1,43 +1,43 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - - */ -#ifndef H_KRNL_PLAYER -#define H_KRNL_PLAYER -#ifdef __cplusplus -extern "C" { -#endif - -struct faction; - -typedef struct player { - unsigned int id; - char * name; - char * email; - char * address; - struct vacation { - int weeks; - char * email; - } * vacation; - const struct faction * faction; - - struct player * nexthash; /* don't use! */ -} player; - -extern struct player * get_players(void); -extern struct player * get_player(unsigned int id); -extern struct player * make_player(const struct faction * f); -extern struct player * next_player(struct player * p); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ +#ifndef H_KRNL_PLAYER +#define H_KRNL_PLAYER +#ifdef __cplusplus +extern "C" { +#endif + +struct faction; + +typedef struct player { + unsigned int id; + char * name; + char * email; + char * address; + struct vacation { + int weeks; + char * email; + } * vacation; + const struct faction * faction; + + struct player * nexthash; /* don't use! */ +} player; + +extern struct player * get_players(void); +extern struct player * get_player(unsigned int id); +extern struct player * make_player(const struct faction * f); +extern struct player * next_player(struct player * p); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/pool.c b/src/kernel/pool.c index 042cc7db3..a7a1e6b02 100644 --- a/src/kernel/pool.c +++ b/src/kernel/pool.c @@ -1,262 +1,262 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "pool.h" - -#include "faction.h" -#include "item.h" -#include "magic.h" -#include "order.h" -#include "region.h" -#include "race.h" -#include "unit.h" - -#include -#include - -#include -#include - -#define TODO_POOL -#undef TODO_RESOURCES - -int -get_resource(const unit * u, const resource_type * rtype) -{ - const item_type * itype = resource2item(rtype); - - if (rtype->uget) { - /* this resource is probably special */ - int i = rtype->uget(u, rtype); - if (i>=0) return i; - } - if (itype!=NULL) { - if (itype == olditemtype[R_STONE] && (u->race->flags&RCF_STONEGOLEM)) { - return u->number*GOLEM_STONE; - } else if (itype==olditemtype[R_IRON] && (u->race->flags&RCF_IRONGOLEM)) { - return u->number*GOLEM_IRON; - } else { - const item * i = *i_findc(&u->items, itype); - if (i) return i->number; - return 0; - } - } - if (rtype == oldresourcetype[R_AURA]) - return get_spellpoints(u); - if (rtype == oldresourcetype[R_PERMAURA]) - return max_spellpoints(u->region, u); - log_error(("trying to get unknown resource '%s'.\n", rtype->_name[0])); - return 0; -} - -int -change_resource(unit * u, const resource_type * rtype, int change) -{ - int i = 0; - - if (rtype->uchange) - i = rtype->uchange(u, rtype, change); - else if (rtype == oldresourcetype[R_AURA]) - i = change_spellpoints(u, change); - else if (rtype == oldresourcetype[R_PERMAURA]) - i = change_maxspellpoints(u, change); - else - assert(!"undefined resource detected. rtype->uchange not initialized."); - assert(i >= 0 && (i < 100000000)); /* soft test to catch mischief */ - return i; -} - -int -get_reservation(const unit * u, const resource_type * rtype) -{ - struct reservation * res = u->reservations; - - if (rtype==oldresourcetype[R_STONE] && (u->race->flags&RCF_STONEGOLEM)) - return (u->number * GOLEM_STONE); - if (rtype==oldresourcetype[R_IRON] && (u->race->flags&RCF_IRONGOLEM)) - return (u->number * GOLEM_IRON); - while (res && res->type!=rtype) res=res->next; - if (res) return res->value; - return 0; -} - -int -change_reservation(unit * u, const resource_type * rtype, int value) -{ - struct reservation *res, ** rp = &u->reservations; - - if (!value) return 0; - - while (*rp && (*rp)->type!=rtype) rp=&(*rp)->next; - res = *rp; - if (!res) { - *rp = res = calloc(sizeof(struct reservation), 1); - res->type = rtype; - res->value = value; - } else if (res && res->value+value<=0) { - *rp = res->next; - free(res); - return 0; - } else { - res->value += value; - } - return res->value; -} - -static int -new_set_resvalue(unit * u, const resource_type * rtype, int value) -{ - struct reservation *res, ** rp = &u->reservations; - - while (*rp && (*rp)->type!=rtype) rp=&(*rp)->next; - res = *rp; - if (!res) { - if (!value) return 0; - *rp = res = calloc(sizeof(struct reservation), 1); - res->type = rtype; - res->value = value; - } else if (res && value<=0) { - *rp = res->next; - free(res); - return 0; - } else { - res->value = value; - } - return res->value; -} - -int -get_pooled(const unit * u, const resource_type * rtype, unsigned int mode, int count) -{ - const faction * f = u->faction; - unit *v; - int use = 0; - region * r = u->region; - int have = get_resource(u, rtype); - - if ((u->race->ec_flags & GETITEM) == 0) { - mode &= (GET_SLACK|GET_RESERVE); - } - - if ((mode & GET_SLACK) && (mode & GET_RESERVE)) use = have; - else { - int reserve = get_reservation(u, rtype); - int slack = MAX(0, have-reserve); - if (mode & GET_RESERVE) use = have-slack; - else if (mode & GET_SLACK) use = slack; - } - if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK|GET_RESERVE)) { - for (v = r->units; v && usenext) if (u!=v) { - int mask; - - if (v->items==NULL && rtype->uget==NULL) continue; - if ((urace(v)->ec_flags & GIVEITEM) == 0) continue; - - if (v->faction == f) { - mask = (mode >> 3) & (GET_SLACK|GET_RESERVE); - } - else if (alliedunit(v, f, HELP_MONEY)) mask = (mode >> 6) & (GET_SLACK|GET_RESERVE); - else continue; - use += get_pooled(v, rtype, mask, count-use); - } - } - return use; -} - -int -use_pooled(unit * u, const resource_type * rtype, unsigned int mode, int count) -{ - const faction *f = u->faction; - unit *v; - int use = count; - region * r = u->region; - int n = 0, have = get_resource(u, rtype); - - if ((u->race->ec_flags & GETITEM) == 0) { - mode &= (GET_SLACK|GET_RESERVE); - } - - if ((mode & GET_SLACK) && (mode & GET_RESERVE)) { - n = MIN(use, have); - } else { - int reserve = get_reservation(u, rtype); - int slack = MAX(0, have-reserve); - if (mode & GET_RESERVE) { - n = have-slack; - n = MIN(use, n); - change_reservation(u, rtype, -n); - } - else if (mode & GET_SLACK) { - n = MIN(use, slack); - } - } - if (n>0) { - change_resource(u, rtype, -n); - use -= n; - } - - if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK|GET_RESERVE)) { - for (v = r->units; use>0 && v!=NULL; v = v->next) if (u!=v) { - int mask; - if ((urace(v)->ec_flags & GIVEITEM) == 0) continue; - if (v->items==NULL && rtype->uget==NULL) continue; - - if (v->faction == f) { - mask = (mode >> 3) & (GET_SLACK|GET_RESERVE); - } - else if (alliedunit(v, f, HELP_MONEY)) mask = (mode >> 6) & (GET_SLACK|GET_RESERVE); - else continue; - use -= use_pooled(v, rtype, mask, use); - } - } - return count-use; -} - - -int -reserve_cmd(unit * u, struct order *ord) -{ - if (u->number > 0 && (urace(u)->ec_flags & GETITEM)) { - int use, count; - const resource_type * rtype; - const char * s; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - count = atoip((const char *)s); - - if (count == 0 && findparam(s, u->faction->locale)==P_EACH) { - count = getint() * u->number; - } - - rtype = findresourcetype(getstrtoken(), u->faction->locale); - if (rtype == NULL) return 0; - - new_set_resvalue(u, rtype, 0); /* make sure the pool is empty */ - use = use_pooled(u, rtype, GET_DEFAULT, count); - if (use) { - new_set_resvalue(u, rtype, use); - change_resource(u, rtype, use); - } - } - return 0; -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "pool.h" + +#include "faction.h" +#include "item.h" +#include "magic.h" +#include "order.h" +#include "region.h" +#include "race.h" +#include "unit.h" + +#include +#include + +#include +#include + +#define TODO_POOL +#undef TODO_RESOURCES + +int +get_resource(const unit * u, const resource_type * rtype) +{ + const item_type * itype = resource2item(rtype); + + if (rtype->uget) { + /* this resource is probably special */ + int i = rtype->uget(u, rtype); + if (i>=0) return i; + } + if (itype!=NULL) { + if (itype == olditemtype[R_STONE] && (u->race->flags&RCF_STONEGOLEM)) { + return u->number*GOLEM_STONE; + } else if (itype==olditemtype[R_IRON] && (u->race->flags&RCF_IRONGOLEM)) { + return u->number*GOLEM_IRON; + } else { + const item * i = *i_findc(&u->items, itype); + if (i) return i->number; + return 0; + } + } + if (rtype == oldresourcetype[R_AURA]) + return get_spellpoints(u); + if (rtype == oldresourcetype[R_PERMAURA]) + return max_spellpoints(u->region, u); + log_error(("trying to get unknown resource '%s'.\n", rtype->_name[0])); + return 0; +} + +int +change_resource(unit * u, const resource_type * rtype, int change) +{ + int i = 0; + + if (rtype->uchange) + i = rtype->uchange(u, rtype, change); + else if (rtype == oldresourcetype[R_AURA]) + i = change_spellpoints(u, change); + else if (rtype == oldresourcetype[R_PERMAURA]) + i = change_maxspellpoints(u, change); + else + assert(!"undefined resource detected. rtype->uchange not initialized."); + assert(i >= 0 && (i < 100000000)); /* soft test to catch mischief */ + return i; +} + +int +get_reservation(const unit * u, const resource_type * rtype) +{ + struct reservation * res = u->reservations; + + if (rtype==oldresourcetype[R_STONE] && (u->race->flags&RCF_STONEGOLEM)) + return (u->number * GOLEM_STONE); + if (rtype==oldresourcetype[R_IRON] && (u->race->flags&RCF_IRONGOLEM)) + return (u->number * GOLEM_IRON); + while (res && res->type!=rtype) res=res->next; + if (res) return res->value; + return 0; +} + +int +change_reservation(unit * u, const resource_type * rtype, int value) +{ + struct reservation *res, ** rp = &u->reservations; + + if (!value) return 0; + + while (*rp && (*rp)->type!=rtype) rp=&(*rp)->next; + res = *rp; + if (!res) { + *rp = res = calloc(sizeof(struct reservation), 1); + res->type = rtype; + res->value = value; + } else if (res && res->value+value<=0) { + *rp = res->next; + free(res); + return 0; + } else { + res->value += value; + } + return res->value; +} + +static int +new_set_resvalue(unit * u, const resource_type * rtype, int value) +{ + struct reservation *res, ** rp = &u->reservations; + + while (*rp && (*rp)->type!=rtype) rp=&(*rp)->next; + res = *rp; + if (!res) { + if (!value) return 0; + *rp = res = calloc(sizeof(struct reservation), 1); + res->type = rtype; + res->value = value; + } else if (res && value<=0) { + *rp = res->next; + free(res); + return 0; + } else { + res->value = value; + } + return res->value; +} + +int +get_pooled(const unit * u, const resource_type * rtype, unsigned int mode, int count) +{ + const faction * f = u->faction; + unit *v; + int use = 0; + region * r = u->region; + int have = get_resource(u, rtype); + + if ((u->race->ec_flags & GETITEM) == 0) { + mode &= (GET_SLACK|GET_RESERVE); + } + + if ((mode & GET_SLACK) && (mode & GET_RESERVE)) use = have; + else { + int reserve = get_reservation(u, rtype); + int slack = MAX(0, have-reserve); + if (mode & GET_RESERVE) use = have-slack; + else if (mode & GET_SLACK) use = slack; + } + if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK|GET_RESERVE)) { + for (v = r->units; v && usenext) if (u!=v) { + int mask; + + if (v->items==NULL && rtype->uget==NULL) continue; + if ((urace(v)->ec_flags & GIVEITEM) == 0) continue; + + if (v->faction == f) { + mask = (mode >> 3) & (GET_SLACK|GET_RESERVE); + } + else if (alliedunit(v, f, HELP_MONEY)) mask = (mode >> 6) & (GET_SLACK|GET_RESERVE); + else continue; + use += get_pooled(v, rtype, mask, count-use); + } + } + return use; +} + +int +use_pooled(unit * u, const resource_type * rtype, unsigned int mode, int count) +{ + const faction *f = u->faction; + unit *v; + int use = count; + region * r = u->region; + int n = 0, have = get_resource(u, rtype); + + if ((u->race->ec_flags & GETITEM) == 0) { + mode &= (GET_SLACK|GET_RESERVE); + } + + if ((mode & GET_SLACK) && (mode & GET_RESERVE)) { + n = MIN(use, have); + } else { + int reserve = get_reservation(u, rtype); + int slack = MAX(0, have-reserve); + if (mode & GET_RESERVE) { + n = have-slack; + n = MIN(use, n); + change_reservation(u, rtype, -n); + } + else if (mode & GET_SLACK) { + n = MIN(use, slack); + } + } + if (n>0) { + change_resource(u, rtype, -n); + use -= n; + } + + if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK|GET_RESERVE)) { + for (v = r->units; use>0 && v!=NULL; v = v->next) if (u!=v) { + int mask; + if ((urace(v)->ec_flags & GIVEITEM) == 0) continue; + if (v->items==NULL && rtype->uget==NULL) continue; + + if (v->faction == f) { + mask = (mode >> 3) & (GET_SLACK|GET_RESERVE); + } + else if (alliedunit(v, f, HELP_MONEY)) mask = (mode >> 6) & (GET_SLACK|GET_RESERVE); + else continue; + use -= use_pooled(v, rtype, mask, use); + } + } + return count-use; +} + + +int +reserve_cmd(unit * u, struct order *ord) +{ + if (u->number > 0 && (urace(u)->ec_flags & GETITEM)) { + int use, count; + const resource_type * rtype; + const char * s; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + count = atoip((const char *)s); + + if (count == 0 && findparam(s, u->faction->locale)==P_EACH) { + count = getint() * u->number; + } + + rtype = findresourcetype(getstrtoken(), u->faction->locale); + if (rtype == NULL) return 0; + + new_set_resvalue(u, rtype, 0); /* make sure the pool is empty */ + use = use_pooled(u, rtype, GET_DEFAULT, count); + if (use) { + new_set_resvalue(u, rtype, use); + change_resource(u, rtype, use); + } + } + return 0; +} + diff --git a/src/kernel/pool.h b/src/kernel/pool.h index 80239c8d7..124bcb432 100644 --- a/src/kernel/pool.h +++ b/src/kernel/pool.h @@ -1,62 +1,62 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_POOL_H -#define H_KRNL_POOL_H -#ifdef __cplusplus -extern "C" { -#endif - -/* bitfield values for get/use/change operations */ -#define GET_SLACK 0x01 -#define GET_RESERVE 0x02 - -#define GET_POOLED_SLACK 0x08 -#define GET_POOLED_RESERVE 0x10 -#define GET_POOLED_FORCE 0x20 /* ignore f->options pools */ -#define GET_ALLIED_SLACK 0x30 -#define GET_ALLIED_RESERVE 0x40 - -/* for convenience: */ -#define GET_DEFAULT (GET_RESERVE|GET_SLACK|GET_POOLED_SLACK) -#define GET_ALL (GET_SLACK|GET_RESERVE|GET_POOLED_SLACK|GET_POOLED_RESERVE|GET_POOLED_FORCE) - -int get_pooled(const struct unit * u, const struct resource_type * res, unsigned int mode, int count); -int use_pooled(struct unit * u, const struct resource_type * res, unsigned int mode, int count); - /** use_pooled - * verbraucht 'count' Objekte der resource 'itm' - * unter zuhilfenahme des Pools der struct region und Aufbrauch des - * von der Einheit reservierten Resourcen - */ - -int get_resource(const struct unit * u, const struct resource_type * res); -int change_resource(struct unit * u, const struct resource_type * res, int change); - -int get_reservation(const struct unit * u, const struct resource_type * res); -int change_reservation(struct unit * u, const struct resource_type * res, int value); - -int reserve_cmd(struct unit *u, struct order *ord); - -/** init_pool - * initialisiert den regionalen Pool. - */ - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_POOL_H +#define H_KRNL_POOL_H +#ifdef __cplusplus +extern "C" { +#endif + +/* bitfield values for get/use/change operations */ +#define GET_SLACK 0x01 +#define GET_RESERVE 0x02 + +#define GET_POOLED_SLACK 0x08 +#define GET_POOLED_RESERVE 0x10 +#define GET_POOLED_FORCE 0x20 /* ignore f->options pools */ +#define GET_ALLIED_SLACK 0x30 +#define GET_ALLIED_RESERVE 0x40 + +/* for convenience: */ +#define GET_DEFAULT (GET_RESERVE|GET_SLACK|GET_POOLED_SLACK) +#define GET_ALL (GET_SLACK|GET_RESERVE|GET_POOLED_SLACK|GET_POOLED_RESERVE|GET_POOLED_FORCE) + +int get_pooled(const struct unit * u, const struct resource_type * res, unsigned int mode, int count); +int use_pooled(struct unit * u, const struct resource_type * res, unsigned int mode, int count); + /** use_pooled + * verbraucht 'count' Objekte der resource 'itm' + * unter zuhilfenahme des Pools der struct region und Aufbrauch des + * von der Einheit reservierten Resourcen + */ + +int get_resource(const struct unit * u, const struct resource_type * res); +int change_resource(struct unit * u, const struct resource_type * res, int change); + +int get_reservation(const struct unit * u, const struct resource_type * res); +int change_reservation(struct unit * u, const struct resource_type * res, int value); + +int reserve_cmd(struct unit *u, struct order *ord); + +/** init_pool + * initialisiert den regionalen Pool. + */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/race.c b/src/kernel/race.c index ffb9bf8a5..bc2977b0a 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -1,296 +1,296 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "race.h" - -#include "alchemy.h" -#include "build.h" -#include "building.h" -#include "equipment.h" -#include "faction.h" -#include "group.h" -#include "item.h" -#include "magic.h" -#include "names.h" -#include "pathfinder.h" -#include "region.h" -#include "ship.h" -#include "skill.h" -#include "terrain.h" -#include "unit.h" -#include "version.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include - -/* attrib includes */ -#include - -/* libc includes */ -#include -#include -#include -#include -#include - -/** external variables **/ -race * races; -int num_races = 0; - -race_list * -get_familiarraces(void) -{ - static int init = 0; - static race_list * familiarraces; - - if (!init) { - race * rc = races; - for (;rc!=NULL;rc=rc->next) { - if (rc->init_familiar!=NULL) { - racelist_insert(&familiarraces, rc); - } - } - init = false; - } - return familiarraces; -} - -void -racelist_clear(struct race_list **rl) -{ - while (*rl) { - race_list * rl2 = (*rl)->next; - free(*rl); - *rl = rl2; - } -} - -void -racelist_insert(struct race_list **rl, const struct race *r) -{ - race_list *rl2 = (race_list*)malloc(sizeof(race_list)); - - rl2->data = r; - rl2->next = *rl; - - *rl = rl2; -} - -race * -rc_new(const char * zName) -{ - char zBuffer[80]; - race * rc = calloc(sizeof(race), 1); - if (strchr(zName, ' ')!=NULL) { - log_error(("race '%s' has an invalid name. remove spaces\n", zName)); - assert(strchr(zName, ' ')==NULL); - } - strcpy(zBuffer, zName); - rc->_name[0] = strdup(zBuffer); - sprintf(zBuffer, "%s_p", zName); - rc->_name[1] = strdup(zBuffer); - sprintf(zBuffer, "%s_d", zName); - rc->_name[2] = strdup(zBuffer); - sprintf(zBuffer, "%s_x", zName); - rc->_name[3] = strdup(zBuffer); - rc->precombatspell = NULL; - - rc->attack[0].type = AT_COMBATSPELL; - rc->attack[1].type = AT_NONE; - return rc; -} - -race * -rc_add(race * rc) -{ - rc->index = num_races++; - rc->next = races; - return races = rc; -} - -static const char * racealias[][2] = { - { "uruk", "orc" }, /* there was a time when the orc race was called uruk (and there were other orcs). That was really confusing */ - { "skeletton lord", "skeleton lord" }, /* we once had a typo here. it is fixed */ - { NULL, NULL } -}; - -race * -rc_find(const char * name) -{ - const char * rname = name; - race * rc = races; - int i; - - for (i=0;racealias[i][0];++i) { - if (strcmp(racealias[i][0], name)==0) { - rname = racealias[i][1]; - break; - } - } - while (rc && !strcmp(rname, rc->_name[0])==0) rc = rc->next; - return rc; -} - -/** dragon movement **/ -boolean -allowed_dragon(const region * src, const region * target) -{ - if (fval(src->terrain, ARCTIC_REGION) && fval(target->terrain, SEA_REGION)) return false; - return allowed_fly(src, target); -} - -char ** race_prefixes = NULL; - -extern void -add_raceprefix(const char * prefix) -{ - static size_t size = 4; - static unsigned int next = 0; - if (race_prefixes==NULL) race_prefixes = malloc(size * sizeof(char*)); - if (next+1==size) { - size *= 2; - race_prefixes = realloc(race_prefixes, size * sizeof(char*)); - } - race_prefixes[next++] = strdup(prefix); - race_prefixes[next] = NULL; -} - -/* Die Bezeichnungen dürfen wegen der Art des Speicherns keine - * Leerzeichen enthalten! */ - -/* "den Zwergen", "Halblingsparteien" */ - -void -set_show_item(faction *f, item_t i) -{ - attrib *a = a_add(&f->attribs, a_new(&at_showitem)); - a->data.v = (void*)olditemtype[i]; -} - -boolean -r_insectstalled(const region * r) -{ - return fval(r->terrain, ARCTIC_REGION); -} - -const char * -rc_name(const race * rc, int n) -{ - return rc?mkname("race", rc->_name[n]):NULL; -} - -const char * -raceprefix(const unit *u) -{ - const attrib * asource = u->faction->attribs; - - if (fval(u, UFL_GROUP)) { - const attrib * agroup = agroup = a_findc(u->attribs, &at_group); - if (agroup!=NULL) asource = ((const group *)(agroup->data.v))->attribs; - } - return get_prefix(asource); -} - -const char * -racename(const struct locale *loc, const unit *u, const race * rc) -{ - const char * prefix = raceprefix(u); - - if (prefix!=NULL) { - static char lbuf[80]; - char * bufp = lbuf; - size_t size = sizeof(lbuf) - 1; - int ch, bytes; - - bytes = (int)strlcpy(bufp, LOC(loc, mkname("prefix", prefix)), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - bytes = (int)strlcpy(bufp, LOC(loc, rc_name(rc, u->number != 1)), size); - assert(~bufp[0] & 0x80|| !"unicode/not implemented"); - ch = tolower(*(unsigned char *)bufp); - bufp[0] = (char)ch; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - *bufp = 0; - - return lbuf; - } - return LOC(loc, rc_name(rc, u->number != 1)); -} - -int -rc_specialdamage(const race * ar, const race * dr, const struct weapon_type * wtype) -{ - race_t art = old_race(ar); - int m, modifier = 0; - - if (wtype!=NULL && wtype->modifiers!=NULL) for (m=0;wtype->modifiers[m].value;++m) { - /* weapon damage for this weapon, possibly by race */ - if (wtype->modifiers[m].flags & WMF_DAMAGE) { - race_list * rlist = wtype->modifiers[m].races; - if (rlist!=NULL) { - while (rlist) { - if (rlist->data == ar) break; - rlist = rlist->next; - } - if (rlist==NULL) continue; - } - modifier += wtype->modifiers[m].value; - } - } - switch (art) { - case RC_HALFLING: - if (wtype!=NULL && dragonrace(dr)) { - modifier += 5; - } - break; - default: - break; - } - return modifier; -} - -void -write_race_reference(const race * rc, struct storage * store) -{ - store->w_tok(store, rc?rc->_name[0]:"none"); -} - -variant -read_race_reference(struct storage * store) -{ - variant result; - char zName[20]; - store->r_tok_buf(store, zName, sizeof(zName)); - - if (strcmp(zName, "none")==0) { - result.v = NULL; - return result; - } else { - result.v = rc_find(zName); - } - assert(result.v!=NULL); - return result; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "race.h" + +#include "alchemy.h" +#include "build.h" +#include "building.h" +#include "equipment.h" +#include "faction.h" +#include "group.h" +#include "item.h" +#include "magic.h" +#include "names.h" +#include "pathfinder.h" +#include "region.h" +#include "ship.h" +#include "skill.h" +#include "terrain.h" +#include "unit.h" +#include "version.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include + +/* attrib includes */ +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +/** external variables **/ +race * races; +int num_races = 0; + +race_list * +get_familiarraces(void) +{ + static int init = 0; + static race_list * familiarraces; + + if (!init) { + race * rc = races; + for (;rc!=NULL;rc=rc->next) { + if (rc->init_familiar!=NULL) { + racelist_insert(&familiarraces, rc); + } + } + init = false; + } + return familiarraces; +} + +void +racelist_clear(struct race_list **rl) +{ + while (*rl) { + race_list * rl2 = (*rl)->next; + free(*rl); + *rl = rl2; + } +} + +void +racelist_insert(struct race_list **rl, const struct race *r) +{ + race_list *rl2 = (race_list*)malloc(sizeof(race_list)); + + rl2->data = r; + rl2->next = *rl; + + *rl = rl2; +} + +race * +rc_new(const char * zName) +{ + char zBuffer[80]; + race * rc = calloc(sizeof(race), 1); + if (strchr(zName, ' ')!=NULL) { + log_error(("race '%s' has an invalid name. remove spaces\n", zName)); + assert(strchr(zName, ' ')==NULL); + } + strcpy(zBuffer, zName); + rc->_name[0] = strdup(zBuffer); + sprintf(zBuffer, "%s_p", zName); + rc->_name[1] = strdup(zBuffer); + sprintf(zBuffer, "%s_d", zName); + rc->_name[2] = strdup(zBuffer); + sprintf(zBuffer, "%s_x", zName); + rc->_name[3] = strdup(zBuffer); + rc->precombatspell = NULL; + + rc->attack[0].type = AT_COMBATSPELL; + rc->attack[1].type = AT_NONE; + return rc; +} + +race * +rc_add(race * rc) +{ + rc->index = num_races++; + rc->next = races; + return races = rc; +} + +static const char * racealias[][2] = { + { "uruk", "orc" }, /* there was a time when the orc race was called uruk (and there were other orcs). That was really confusing */ + { "skeletton lord", "skeleton lord" }, /* we once had a typo here. it is fixed */ + { NULL, NULL } +}; + +race * +rc_find(const char * name) +{ + const char * rname = name; + race * rc = races; + int i; + + for (i=0;racealias[i][0];++i) { + if (strcmp(racealias[i][0], name)==0) { + rname = racealias[i][1]; + break; + } + } + while (rc && !strcmp(rname, rc->_name[0])==0) rc = rc->next; + return rc; +} + +/** dragon movement **/ +boolean +allowed_dragon(const region * src, const region * target) +{ + if (fval(src->terrain, ARCTIC_REGION) && fval(target->terrain, SEA_REGION)) return false; + return allowed_fly(src, target); +} + +char ** race_prefixes = NULL; + +extern void +add_raceprefix(const char * prefix) +{ + static size_t size = 4; + static unsigned int next = 0; + if (race_prefixes==NULL) race_prefixes = malloc(size * sizeof(char*)); + if (next+1==size) { + size *= 2; + race_prefixes = realloc(race_prefixes, size * sizeof(char*)); + } + race_prefixes[next++] = strdup(prefix); + race_prefixes[next] = NULL; +} + +/* Die Bezeichnungen dürfen wegen der Art des Speicherns keine + * Leerzeichen enthalten! */ + +/* "den Zwergen", "Halblingsparteien" */ + +void +set_show_item(faction *f, item_t i) +{ + attrib *a = a_add(&f->attribs, a_new(&at_showitem)); + a->data.v = (void*)olditemtype[i]; +} + +boolean +r_insectstalled(const region * r) +{ + return fval(r->terrain, ARCTIC_REGION); +} + +const char * +rc_name(const race * rc, int n) +{ + return rc?mkname("race", rc->_name[n]):NULL; +} + +const char * +raceprefix(const unit *u) +{ + const attrib * asource = u->faction->attribs; + + if (fval(u, UFL_GROUP)) { + const attrib * agroup = agroup = a_findc(u->attribs, &at_group); + if (agroup!=NULL) asource = ((const group *)(agroup->data.v))->attribs; + } + return get_prefix(asource); +} + +const char * +racename(const struct locale *loc, const unit *u, const race * rc) +{ + const char * prefix = raceprefix(u); + + if (prefix!=NULL) { + static char lbuf[80]; + char * bufp = lbuf; + size_t size = sizeof(lbuf) - 1; + int ch, bytes; + + bytes = (int)strlcpy(bufp, LOC(loc, mkname("prefix", prefix)), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + bytes = (int)strlcpy(bufp, LOC(loc, rc_name(rc, u->number != 1)), size); + assert(~bufp[0] & 0x80|| !"unicode/not implemented"); + ch = tolower(*(unsigned char *)bufp); + bufp[0] = (char)ch; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + *bufp = 0; + + return lbuf; + } + return LOC(loc, rc_name(rc, u->number != 1)); +} + +int +rc_specialdamage(const race * ar, const race * dr, const struct weapon_type * wtype) +{ + race_t art = old_race(ar); + int m, modifier = 0; + + if (wtype!=NULL && wtype->modifiers!=NULL) for (m=0;wtype->modifiers[m].value;++m) { + /* weapon damage for this weapon, possibly by race */ + if (wtype->modifiers[m].flags & WMF_DAMAGE) { + race_list * rlist = wtype->modifiers[m].races; + if (rlist!=NULL) { + while (rlist) { + if (rlist->data == ar) break; + rlist = rlist->next; + } + if (rlist==NULL) continue; + } + modifier += wtype->modifiers[m].value; + } + } + switch (art) { + case RC_HALFLING: + if (wtype!=NULL && dragonrace(dr)) { + modifier += 5; + } + break; + default: + break; + } + return modifier; +} + +void +write_race_reference(const race * rc, struct storage * store) +{ + store->w_tok(store, rc?rc->_name[0]:"none"); +} + +variant +read_race_reference(struct storage * store) +{ + variant result; + char zName[20]; + store->r_tok_buf(store, zName, sizeof(zName)); + + if (strcmp(zName, "none")==0) { + result.v = NULL; + return result; + } else { + result.v = rc_find(zName); + } + assert(result.v!=NULL); + return result; +} diff --git a/src/kernel/race.h b/src/kernel/race.h index e1f7e5439..321eb4826 100644 --- a/src/kernel/race.h +++ b/src/kernel/race.h @@ -1,192 +1,192 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_RACE_H -#define H_KRNL_RACE_H -#ifdef __cplusplus -extern "C" { -#endif - -#include "magic.h" /* wegen MAXMAGIETYP */ - -#define AT_NONE 0 -#define AT_STANDARD 1 -#define AT_DRAIN_EXP 2 -#define AT_DRAIN_ST 3 -#define AT_NATURAL 4 -#define AT_DAZZLE 5 -#define AT_SPELL 6 -#define AT_COMBATSPELL 7 -#define AT_STRUCTURAL 8 - -#define GOLEM_IRON 4 /* Anzahl Eisen in einem Eisengolem */ -#define GOLEM_STONE 4 /* Anzahl Steine in einem Steingolem */ - -#define RACESPOILCHANCE 5 /* Chance auf rassentypische Beute */ - -typedef struct att { - int type; - union { - const char * dice; - const struct spell * sp; - } data; - int flags; -} att; - -struct param; - -extern int num_races; - -typedef struct race { - struct param * parameters; - const char *_name[4]; /* neu: name[4]völker */ - float magres; - float maxaura; /* Faktor auf Maximale Aura */ - float regaura; /* Faktor auf Regeneration */ - float recruit_multi; /* Faktor für Bauernverbrauch */ - int index; - int recruitcost; - int maintenance; - int splitsize; - int weight; - int capacity; - float speed; - float aggression; /* chance that a monster will attack */ - int hitpoints; - const char *def_damage; - char armor; - int at_default; /* Angriffsskill Unbewaffnet (default: -2)*/ - int df_default; /* Verteidigungsskill Unbewaffnet (default: -2)*/ - int at_bonus; /* Verändert den Angriffsskill (default: 0)*/ - int df_bonus; /* Verändert den Verteidigungskill (default: 0)*/ - const spell * precombatspell; - struct att attack[10]; - char bonus[MAXSKILLS]; - signed char * study_speed; /* study-speed-bonus in points/turn (0=30 Tage) */ - boolean __remove_me_nonplayer; - int flags; - int battle_flags; - int ec_flags; - race_t oldfamiliars[MAXMAGIETYP]; - - const char *(*generate_name) (const struct unit *); - const char *(*describe) (const struct unit *, const struct locale *); - void (*age)(struct unit *u); - boolean (*move_allowed)(const struct region *, const struct region *); - struct item * (*itemdrop)(const struct race *, int size); - void (*init_familiar)(struct unit *); - - const struct race * familiars[MAXMAGIETYP]; - struct attrib * attribs; - struct race * next; -} race; - -typedef struct race_list { - struct race_list * next; - const struct race * data; -} race_list; - -extern void racelist_clear(struct race_list **rl); -extern void racelist_insert(struct race_list **rl, const struct race *r); - -extern struct race_list * get_familiarraces(void); -extern struct race * races; - -extern struct race * rc_find(const char *); -extern const char * rc_name(const struct race *, int); -extern struct race * rc_add(struct race *); -extern struct race * rc_new(const char * zName); -extern int rc_specialdamage(const race *, const race *, const struct weapon_type *); - -/* Flags */ -#define RCF_PLAYERRACE (1<<0) /* can be played by a player. */ -#define RCF_KILLPEASANTS (1<<1) /* Töten Bauern. Dämonen werden nicht über dieses Flag, sondern in randenc() behandelt. */ -#define RCF_SCAREPEASANTS (1<<2) -#define RCF_CANSTEAL (1<<3) -#define RCF_MOVERANDOM (1<<4) -#define RCF_CANNOTMOVE (1<<5) -#define RCF_LEARN (1<<6) /* Lernt automatisch wenn struct faction == 0 */ -#define RCF_FLY (1<<7) /* kann fliegen */ -#define RCF_SWIM (1<<8) /* kann schwimmen */ -#define RCF_WALK (1<<9) /* kann über Land gehen */ -#define RCF_NOLEARN (1<<10) /* kann nicht normal lernen */ -#define RCF_NOTEACH (1<<11) /* kann nicht lehren */ -#define RCF_HORSE (1<<12) /* Einheit ist Pferd, sozusagen */ -#define RCF_DESERT (1<<13) /* 5% Chance, das Einheit desertiert */ -#define RCF_ILLUSIONARY (1<<14) /* (Illusion & Spell) Does not drop items. */ -#define RCF_ABSORBPEASANTS (1<<15) /* Tötet und absorbiert Bauern */ -#define RCF_NOHEAL (1<<16) /* Einheit kann nicht geheilt werden */ -#define RCF_NOWEAPONS (1<<17) /* Einheit kann keine Waffen benutzen */ -#define RCF_SHAPESHIFT (1<<18) /* Kann TARNE RASSE benutzen. */ -#define RCF_SHAPESHIFTANY (1<<19) /* Kann TARNE RASSE "string" benutzen. */ -#define RCF_UNDEAD (1<<20) /* Undead. */ -#define RCF_DRAGON (1<<21) /* Drachenart (für Zauber)*/ -#define RCF_COASTAL (1<<22) /* kann in Landregionen an der Küste sein */ -#define RCF_UNARMEDGUARD (1<<23) /* kann ohne Waffen bewachen */ -#define RCF_CANSAIL (1<<24) /* Einheit darf Schiffe betreten */ -#define RCF_INVISIBLE (1<<25) /* not visible in any report */ -#define RCF_SHIPSPEED (1<<26) /* race gets +1 on shipspeed */ -#define RCF_STONEGOLEM (1<<27) /* race gets stonegolem properties */ -#define RCF_IRONGOLEM (1<<28) /* race gets irongolem properties */ - -/* Economic flags */ -#define GIVEITEM (1<<1) /* gibt Gegenstände weg */ -#define GIVEPERSON (1<<2) /* übergibt Personen */ -#define GIVEUNIT (1<<3) /* Einheiten an andere Partei übergeben */ -#define GETITEM (1<<4) /* nimmt Gegenstände an */ -#define ECF_REC_HORSES (1<<6) /* Rekrutiert aus Pferden */ -#define ECF_REC_ETHEREAL (1<<7) /* Rekrutiert aus dem Nichts */ -#define ECF_REC_UNLIMITED (1<<8) /* Rekrutiert ohne Limit */ - -/* Battle-Flags */ -#define BF_EQUIPMENT (1<<0) /* Kann Ausrüstung benutzen */ -#define BF_NOBLOCK (1<<1) /* Wird in die Rückzugsberechnung nicht einbezogen */ -#define BF_RES_PIERCE (1<<2) /* Halber Schaden durch PIERCE */ -#define BF_RES_CUT (1<<3) /* Halber Schaden durch CUT */ -#define BF_RES_BASH (1<<4) /* Halber Schaden durch BASH */ -#define BF_INV_NONMAGIC (1<<5) /* Immun gegen nichtmagischen Schaden */ -#define BF_CANATTACK (1<<6) /* Kann keine ATTACKIERE Befehle ausfuehren */ - -extern int unit_old_max_hp(struct unit * u); -extern const char * racename(const struct locale *lang, const struct unit *u, const race * rc); - -#define omniscient(f) (((f)->race)==new_race[RC_ILLUSION] || ((f)->race)==new_race[RC_TEMPLATE]) - -#define playerrace(rc) (fval((rc), RCF_PLAYERRACE)) -#define dragonrace(rc) ((rc) == new_race[RC_FIREDRAGON] || (rc) == new_race[RC_DRAGON] || (rc) == new_race[RC_WYRM] || (rc) == new_race[RC_BIRTHDAYDRAGON]) -#define humanoidrace(rc) (fval((rc), RCF_UNDEAD) || (rc)==new_race[RC_DRACOID] || playerrace(rc)) -#define illusionaryrace(rc) (fval(rc, RCF_ILLUSIONARY)) - -extern boolean allowed_dragon(const struct region * src, const struct region * target); - -extern boolean r_insectstalled(const struct region *r); - -extern void add_raceprefix(const char *); -extern char ** race_prefixes; - -extern void write_race_reference(const struct race * rc, struct storage * store); -extern variant read_race_reference(struct storage * store); - -extern const char * raceprefix(const struct unit *u); - -extern void give_starting_equipment(const struct equipment * eq, struct unit *u); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_RACE_H +#define H_KRNL_RACE_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "magic.h" /* wegen MAXMAGIETYP */ + +#define AT_NONE 0 +#define AT_STANDARD 1 +#define AT_DRAIN_EXP 2 +#define AT_DRAIN_ST 3 +#define AT_NATURAL 4 +#define AT_DAZZLE 5 +#define AT_SPELL 6 +#define AT_COMBATSPELL 7 +#define AT_STRUCTURAL 8 + +#define GOLEM_IRON 4 /* Anzahl Eisen in einem Eisengolem */ +#define GOLEM_STONE 4 /* Anzahl Steine in einem Steingolem */ + +#define RACESPOILCHANCE 5 /* Chance auf rassentypische Beute */ + +typedef struct att { + int type; + union { + const char * dice; + const struct spell * sp; + } data; + int flags; +} att; + +struct param; + +extern int num_races; + +typedef struct race { + struct param * parameters; + const char *_name[4]; /* neu: name[4]völker */ + float magres; + float maxaura; /* Faktor auf Maximale Aura */ + float regaura; /* Faktor auf Regeneration */ + float recruit_multi; /* Faktor für Bauernverbrauch */ + int index; + int recruitcost; + int maintenance; + int splitsize; + int weight; + int capacity; + float speed; + float aggression; /* chance that a monster will attack */ + int hitpoints; + const char *def_damage; + char armor; + int at_default; /* Angriffsskill Unbewaffnet (default: -2)*/ + int df_default; /* Verteidigungsskill Unbewaffnet (default: -2)*/ + int at_bonus; /* Verändert den Angriffsskill (default: 0)*/ + int df_bonus; /* Verändert den Verteidigungskill (default: 0)*/ + const spell * precombatspell; + struct att attack[10]; + char bonus[MAXSKILLS]; + signed char * study_speed; /* study-speed-bonus in points/turn (0=30 Tage) */ + boolean __remove_me_nonplayer; + int flags; + int battle_flags; + int ec_flags; + race_t oldfamiliars[MAXMAGIETYP]; + + const char *(*generate_name) (const struct unit *); + const char *(*describe) (const struct unit *, const struct locale *); + void (*age)(struct unit *u); + boolean (*move_allowed)(const struct region *, const struct region *); + struct item * (*itemdrop)(const struct race *, int size); + void (*init_familiar)(struct unit *); + + const struct race * familiars[MAXMAGIETYP]; + struct attrib * attribs; + struct race * next; +} race; + +typedef struct race_list { + struct race_list * next; + const struct race * data; +} race_list; + +extern void racelist_clear(struct race_list **rl); +extern void racelist_insert(struct race_list **rl, const struct race *r); + +extern struct race_list * get_familiarraces(void); +extern struct race * races; + +extern struct race * rc_find(const char *); +extern const char * rc_name(const struct race *, int); +extern struct race * rc_add(struct race *); +extern struct race * rc_new(const char * zName); +extern int rc_specialdamage(const race *, const race *, const struct weapon_type *); + +/* Flags */ +#define RCF_PLAYERRACE (1<<0) /* can be played by a player. */ +#define RCF_KILLPEASANTS (1<<1) /* Töten Bauern. Dämonen werden nicht über dieses Flag, sondern in randenc() behandelt. */ +#define RCF_SCAREPEASANTS (1<<2) +#define RCF_CANSTEAL (1<<3) +#define RCF_MOVERANDOM (1<<4) +#define RCF_CANNOTMOVE (1<<5) +#define RCF_LEARN (1<<6) /* Lernt automatisch wenn struct faction == 0 */ +#define RCF_FLY (1<<7) /* kann fliegen */ +#define RCF_SWIM (1<<8) /* kann schwimmen */ +#define RCF_WALK (1<<9) /* kann über Land gehen */ +#define RCF_NOLEARN (1<<10) /* kann nicht normal lernen */ +#define RCF_NOTEACH (1<<11) /* kann nicht lehren */ +#define RCF_HORSE (1<<12) /* Einheit ist Pferd, sozusagen */ +#define RCF_DESERT (1<<13) /* 5% Chance, das Einheit desertiert */ +#define RCF_ILLUSIONARY (1<<14) /* (Illusion & Spell) Does not drop items. */ +#define RCF_ABSORBPEASANTS (1<<15) /* Tötet und absorbiert Bauern */ +#define RCF_NOHEAL (1<<16) /* Einheit kann nicht geheilt werden */ +#define RCF_NOWEAPONS (1<<17) /* Einheit kann keine Waffen benutzen */ +#define RCF_SHAPESHIFT (1<<18) /* Kann TARNE RASSE benutzen. */ +#define RCF_SHAPESHIFTANY (1<<19) /* Kann TARNE RASSE "string" benutzen. */ +#define RCF_UNDEAD (1<<20) /* Undead. */ +#define RCF_DRAGON (1<<21) /* Drachenart (für Zauber)*/ +#define RCF_COASTAL (1<<22) /* kann in Landregionen an der Küste sein */ +#define RCF_UNARMEDGUARD (1<<23) /* kann ohne Waffen bewachen */ +#define RCF_CANSAIL (1<<24) /* Einheit darf Schiffe betreten */ +#define RCF_INVISIBLE (1<<25) /* not visible in any report */ +#define RCF_SHIPSPEED (1<<26) /* race gets +1 on shipspeed */ +#define RCF_STONEGOLEM (1<<27) /* race gets stonegolem properties */ +#define RCF_IRONGOLEM (1<<28) /* race gets irongolem properties */ + +/* Economic flags */ +#define GIVEITEM (1<<1) /* gibt Gegenstände weg */ +#define GIVEPERSON (1<<2) /* übergibt Personen */ +#define GIVEUNIT (1<<3) /* Einheiten an andere Partei übergeben */ +#define GETITEM (1<<4) /* nimmt Gegenstände an */ +#define ECF_REC_HORSES (1<<6) /* Rekrutiert aus Pferden */ +#define ECF_REC_ETHEREAL (1<<7) /* Rekrutiert aus dem Nichts */ +#define ECF_REC_UNLIMITED (1<<8) /* Rekrutiert ohne Limit */ + +/* Battle-Flags */ +#define BF_EQUIPMENT (1<<0) /* Kann Ausrüstung benutzen */ +#define BF_NOBLOCK (1<<1) /* Wird in die Rückzugsberechnung nicht einbezogen */ +#define BF_RES_PIERCE (1<<2) /* Halber Schaden durch PIERCE */ +#define BF_RES_CUT (1<<3) /* Halber Schaden durch CUT */ +#define BF_RES_BASH (1<<4) /* Halber Schaden durch BASH */ +#define BF_INV_NONMAGIC (1<<5) /* Immun gegen nichtmagischen Schaden */ +#define BF_CANATTACK (1<<6) /* Kann keine ATTACKIERE Befehle ausfuehren */ + +extern int unit_old_max_hp(struct unit * u); +extern const char * racename(const struct locale *lang, const struct unit *u, const race * rc); + +#define omniscient(f) (((f)->race)==new_race[RC_ILLUSION] || ((f)->race)==new_race[RC_TEMPLATE]) + +#define playerrace(rc) (fval((rc), RCF_PLAYERRACE)) +#define dragonrace(rc) ((rc) == new_race[RC_FIREDRAGON] || (rc) == new_race[RC_DRAGON] || (rc) == new_race[RC_WYRM] || (rc) == new_race[RC_BIRTHDAYDRAGON]) +#define humanoidrace(rc) (fval((rc), RCF_UNDEAD) || (rc)==new_race[RC_DRACOID] || playerrace(rc)) +#define illusionaryrace(rc) (fval(rc, RCF_ILLUSIONARY)) + +extern boolean allowed_dragon(const struct region * src, const struct region * target); + +extern boolean r_insectstalled(const struct region *r); + +extern void add_raceprefix(const char *); +extern char ** race_prefixes; + +extern void write_race_reference(const struct race * rc, struct storage * store); +extern variant read_race_reference(struct storage * store); + +extern const char * raceprefix(const struct unit *u); + +extern void give_starting_equipment(const struct equipment * eq, struct unit *u); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/region.c b/src/kernel/region.c index a74dc6898..7935691f5 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -1,1608 +1,1608 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "region.h" - -/* kernel includes */ -#include "alliance.h" -#include "building.h" -#include "connection.h" -#include "curse.h" -#include "equipment.h" -#include "faction.h" -#include "item.h" -#include "message.h" -#include "plane.h" -#include "region.h" -#include "resources.h" -#include "save.h" -#include "ship.h" -#include "terrain.h" -#include "terrainid.h" -#include "unit.h" -#include "version.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* libc includes */ -#include -#include -#include -#include -#include - -extern int dice_rand(const char *s); - -region *regions; - -int -get_maxluxuries() -{ - static int maxluxuries = -1; - if (maxluxuries==-1) { - const luxury_type * ltype; - maxluxuries = 0; - for (ltype = luxurytypes;ltype;ltype=ltype->next) ++maxluxuries; - } - return maxluxuries; -} -const int delta_x[MAXDIRECTIONS] = -{ - -1, 0, 1, 1, 0, -1 -}; - -const int delta_y[MAXDIRECTIONS] = -{ - 1, 1, 0, -1, -1, 0 -}; - -static const direction_t back[MAXDIRECTIONS] = -{ - D_SOUTHEAST, - D_SOUTHWEST, - D_WEST, - D_NORTHWEST, - D_NORTHEAST, - D_EAST, -}; - -direction_t -dir_invert(direction_t dir) -{ - switch (dir) { - case D_PAUSE: - case D_SPECIAL: - return dir; - break; - default: - if (dir>=0 && dirlocale : 0; - if (r==NULL) { - strcpy(buf, "(null)"); - } else { - plane * pl = rplane(r); - int nx = r->x, ny = r->y; - pnormalize(&nx, &ny, pl); - adjust_coordinates(f, &nx, &ny, pl, r); - snprintf(buf, size, "%s (%d,%d)", rname(r, lang), nx, ny); - } - buf[size-1] = 0; - return buffer; -} - -const char * -regionname(const region * r, const faction * f) -{ - static char buf[NAMESIZE]; - return write_regionname(r, f, buf, sizeof(buf)); -} - -int -deathcount(const region * r) -{ - attrib * a = a_find(r->attribs, &at_deathcount); - if (!a) return 0; - return a->data.i; -} - -int -chaoscount(const region * r) -{ - attrib * a = a_find(r->attribs, &at_chaoscount); - if (!a) return 0; - return a->data.i; -} - -void -deathcounts (region * r, int fallen) -{ - attrib * a; - static const curse_type * ctype = NULL; - - if (fallen==0) return; - if (!ctype) ctype = ct_find("holyground"); - if (ctype && curse_active(get_curse(r->attribs, ctype))) return; - - a = a_find(r->attribs, &at_deathcount); - if (!a) a = a_add(&r->attribs, a_new(&at_deathcount)); - a->data.i += fallen; - - if (a->data.i<=0) a_remove(&r->attribs, a); -} - -void -chaoscounts(region * r, int fallen) -{ - attrib * a; - - if (fallen==0) return; - - a = a_find(r->attribs, &at_chaoscount); - if (!a) a = a_add(&r->attribs, a_new(&at_chaoscount)); - a->data.i += fallen; - - if (a->data.i<=0) a_remove(&r->attribs, a); -} - - - -/********************/ -/* at_direction */ -/********************/ -static void -a_initdirection(attrib *a) -{ - a->data.v = calloc(1, sizeof(spec_direction)); -} - -static void -a_freedirection(attrib *a) -{ - free(a->data.v); -} - -static int -a_agedirection(attrib *a) -{ - spec_direction *d = (spec_direction *)(a->data.v); - --d->duration; - return (d->duration>0)?AT_AGE_KEEP:AT_AGE_REMOVE; -} - -typedef struct dir_lookup { - char * name; - const char * oldname; - struct dir_lookup * next; -} dir_lookup; - -static dir_lookup * dir_name_lookup; - -void -register_special_direction(const char * name) -{ - struct locale * lang; - char * str = strdup(name); - - for (lang=locales;lang;lang=nextlocale(lang)) { - tnode * tokens = get_translations(lang, UT_SPECDIR); - const char * token = LOC(lang, name); - - if (token) { - variant var; - - var.v = str; - addtoken(tokens, token, var); - - if (lang==default_locale) { - dir_lookup * dl = malloc(sizeof(dir_lookup)); - dl->name = str; - dl->oldname = token; - dl->next = dir_name_lookup; - dir_name_lookup = dl; - } - } else { - log_error(("no translation for spec_direction '%s' in locale '%s'\n", - name, locale_name(lang))); - } - } -} - -static int -a_readdirection(attrib *a, void * owner, struct storage * store) -{ - spec_direction *d = (spec_direction *)(a->data.v); - - d->x = (short)store->r_int(store); - d->y = (short)store->r_int(store); - d->duration = store->r_int(store); - if (store->versionr_tok_buf(store, NULL, 0); - store->r_tok_buf(store, lbuf, sizeof(lbuf)); - - cstring_i(lbuf); - for (;dl;dl=dl->next) { - if (strcmp(lbuf, dl->oldname)==0) { - d->keyword=strdup(dl->name); - sprintf(lbuf, "%s_desc", d->keyword); - d->desc=strdup(dl->name); - break; - } - } - if (dl==NULL) { - log_error(("unknown spec_direction '%s'\n", lbuf)); - assert(!"not implemented"); - } - } - else { - d->desc = store->r_tok(store); - d->keyword = store->r_tok(store); - } - d->active = true; - return AT_READ_OK; -} - -static void -a_writedirection(const attrib * a, const void * owner, struct storage * store) -{ - spec_direction *d = (spec_direction *)(a->data.v); - - store->w_int(store, d->x); - store->w_int(store, d->y); - store->w_int(store, d->duration); - store->w_tok(store, d->desc); - store->w_tok(store, d->keyword); -} - -attrib_type at_direction = { - "direction", - a_initdirection, - a_freedirection, - a_agedirection, - a_writedirection, - a_readdirection -}; - -region * -find_special_direction(const region *r, const char *token, const struct locale * lang) -{ - attrib *a; - spec_direction *d; - - if (strlen(token)==0) return NULL; - for (a = a_find(r->attribs, &at_direction);a && a->type==&at_direction;a=a->next) { - d = (spec_direction *)(a->data.v); - - if (d->active) { - tnode * tokens = get_translations(lang, UT_SPECDIR); - variant var; - if (findtoken(tokens, token, &var)==E_TOK_SUCCESS) { - if (strcmp((const char *)var.v, d->keyword)==0) { - return findregion(d->x, d->y); - } - } - } - } - - return NULL; -} - -attrib * -create_special_direction(region *r, region * rt, int duration, - const char *desc, const char *keyword) - -{ - attrib *a = a_add(&r->attribs, a_new(&at_direction)); - spec_direction *d = (spec_direction *)(a->data.v); - - d->active = false; - d->x = rt->x; - d->y = rt->y; - d->duration = duration; - d->desc = strdup(desc); - d->keyword = strdup(keyword); - - return a; -} - -/* Moveblock wird zur Zeit nicht über Attribute, sondern ein Bitfeld - r->moveblock gemacht. Sollte umgestellt werden, wenn kompliziertere - Dinge gefragt werden. */ - -/********************/ -/* at_moveblock */ -/********************/ -void -a_initmoveblock(attrib *a) -{ - a->data.v = calloc(1, sizeof(moveblock)); -} - -int -a_readmoveblock(attrib *a, void * owner, struct storage * store) -{ - moveblock *m = (moveblock *)(a->data.v); - int i; - - i = store->r_int(store); - m->dir = (direction_t)i; - return AT_READ_OK; -} - -void -a_writemoveblock(const attrib * a, const void * owner, struct storage * store) -{ - moveblock *m = (moveblock *)(a->data.v); - store->w_int(store, (int)m->dir); -} - -attrib_type at_moveblock = { - "moveblock", a_initmoveblock, NULL, NULL, a_writemoveblock, a_readmoveblock -}; - -#define coor_hashkey(x, y) (unsigned int)((x<<16) + y) -#define RMAXHASH MAXREGIONS -static region * regionhash[RMAXHASH]; -static int dummy_data; -static region * dummy_ptr = (region*)&dummy_data; /* a funny hack */ - -typedef struct uidhashentry { - unsigned int uid; - region * r; -} uidhashentry; -static uidhashentry uidhash[MAXREGIONS]; - -struct region * -findregionbyid(unsigned int uid) -{ - int key = uid % MAXREGIONS; - while (uidhash[key].uid!=0 && uidhash[key].uid!=uid) ++key; - return uidhash[key].r; -} - -#define DELMARKER dummy_ptr - -static void -unhash_uid(region * r) -{ - int key = r->uid % MAXREGIONS; - assert(r->uid); - while (uidhash[key].uid!=0 && uidhash[key].uid!=r->uid) ++key; - assert(uidhash[key].r==r); - uidhash[key].r = NULL; -} - -static void -hash_uid(region * r) -{ - unsigned int uid = r->uid; - for (;;) { - if (uid!=0) { - int key = uid % MAXREGIONS; - while (uidhash[key].uid!=0 && uidhash[key].uid!=uid) ++key; - if (uidhash[key].uid==0) { - uidhash[key].uid = uid; - uidhash[key].r = r; - break; - } - assert(uidhash[key].r!=r || !"duplicate registration"); - } - r->uid = uid = rng_int(); - } -} - -#define HASH_STATISTICS 1 -#if HASH_STATISTICS -static int hash_requests; -static int hash_misses; -#endif - -boolean pnormalize(int * x, int * y, const plane * pl) -{ - if (pl) { - if (x) { - int width = pl->maxx - pl->minx + 1; - int nx = *x - pl->minx; - nx = (nx>0)?nx:(width-(-nx)%width); - *x = nx % width+ pl->minx; - } - if (y) { - int height = pl->maxy - pl->miny + 1; - int ny = *y - pl->miny; - ny = (ny>0)?ny:(height-(-ny)%height); - *y = ny % height + pl->miny; - } - } - return false; /* TBD */ -} - -static region * -rfindhash(int x, int y) -{ - unsigned int rid; - - rid = coor_hashkey(x, y); -#if HASH_STATISTICS - ++hash_requests; -#endif - if (rid>=0) { - int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); - while (regionhash[key]!=NULL && (regionhash[key]==DELMARKER || regionhash[key]->x!=x || regionhash[key]->y!=y)) { - key = (key + gk) % RMAXHASH; -#if HASH_STATISTICS - ++hash_misses; -#endif - } - return regionhash[key]; - } - return NULL; -} - -void -rhash(region * r) -{ - unsigned int rid = coor_hashkey(r->x, r->y); - int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); - while (regionhash[key]!=NULL && regionhash[key]!=DELMARKER && regionhash[key]!=r) { - key = (key + gk) % RMAXHASH; - } - assert(regionhash[key]!=r || !"trying to add the same region twice"); - regionhash[key] = r; -} - -void -runhash(region * r) -{ - unsigned int rid = coor_hashkey(r->x, r->y); - int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); - -#ifdef FAST_CONNECT - int d, di; - for (d=0,di=MAXDIRECTIONS/2;d!=MAXDIRECTIONS;++d,++di) { - region * rc = r->connect[d]; - if (rc!=NULL) { - if (di>=MAXDIRECTIONS) di-=MAXDIRECTIONS; - rc->connect[di] = NULL; - r->connect[d] = NULL; - } - } -#endif - while (regionhash[key]!=NULL && regionhash[key]!=r) { - key = (key + gk) % RMAXHASH; - } - assert(regionhash[key]==r || !"trying to remove a unit that is not hashed"); - regionhash[key] = DELMARKER; -} - -region * -r_connect(const region * r, direction_t dir) -{ - region * result; - int x, y; -#ifdef FAST_CONNECT - region * rmodify = (region*)r; - assert (dir>=0 && dirconnect[dir]) return r->connect[dir]; -#endif - assert(dirx + delta_x[dir]; - y = r->y + delta_y[dir]; - pnormalize(&x, &y, rplane(r)); - result = rfindhash(x, y); -#ifdef FAST_CONNECT - if (result) { - rmodify->connect[dir] = result; - result->connect[back[dir]] = rmodify; - } -#endif - return result; -} - -region * -findregion(int x, int y) -{ - return rfindhash(x, y); -} - -/* Contributed by Hubert Mackenberg. Thanks. - * x und y Abstand zwischen x1 und x2 berechnen - */ -static int -koor_distance_orig(int x1, int y1, int x2, int y2) -{ - int dx = x1 - x2; - int dy = y1 - y2; - - /* Bei negativem dy am Ursprung spiegeln, das veraendert - * den Abstand nicht - */ - if ( dy < 0 ) { - dy = -dy; - dx = -dx; - } - - /* - * dy ist jetzt >=0, fuer dx sind 3 Faelle zu untescheiden - */ - if ( dx >= 0 ) { - int result = dx + dy; - return result; - } - else if (-dx >= dy) { - int result = -dx; - return result; - } - else { - return dy; - } -} - -static int -koor_distance_wrap_xy(int x1, int y1, int x2, int y2, int width, int height) -{ - int dx = x1 - x2; - int dy = y1 - y2; - int result, dist; - int mindist = MIN(width, height) >> 1; - - /* Bei negativem dy am Ursprung spiegeln, das veraendert - * den Abstand nicht - */ - if ( dy < 0 ) { - dy = -dy; - dx = -dx; - } - if (dx<0) { - dx = width + dx; - } - /* dx,dy is now pointing northeast */ - result = dx + dy; - if (result<=mindist) return result; - - dist = (width-dx) + (height-dy); /* southwest */ - if (dist>=0 && dist=0 && dist=0 && distx, r1->y, r2->x, r2->y); -} - -static direction_t -koor_reldirection(int ax, int ay, int bx, int by, const struct plane * pl) -{ - direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - int x = ax + delta_x[dir]; - int y = ay + delta_y[dir]; - pnormalize(&x, &y, pl); - if (bx == x && by == y) return dir; - } - return NODIRECTION; -} - -spec_direction * -special_direction(const region * from, const region * to) -{ - const attrib *a = a_findc(from->attribs, &at_direction); - - while (a!=NULL && a->type==&at_direction) { - spec_direction * sd = (spec_direction *)a->data.v; - if (sd->x==to->x && sd->y==to->y) return sd; - a = a->next; - } - return NULL; -} - -direction_t -reldirection(const region * from, const region * to) -{ - plane * pl = rplane(from); - if (pl == rplane(to)) { - direction_t dir = koor_reldirection(from->x, from->y, to->x, to->y, pl); - - if (dir==NODIRECTION) { - spec_direction *sd = special_direction(from, to); - if (sd!=NULL && sd->active) return D_SPECIAL; - } - return dir; - } - return NODIRECTION; -} - -void -free_regionlist(region_list *rl) -{ - while (rl) { - region_list * rl2 = rl->next; - free(rl); - rl = rl2; - } -} - -void -add_regionlist(region_list **rl, region *r) -{ - region_list *rl2 = (region_list*)malloc(sizeof(region_list)); - - rl2->data = r; - rl2->next = *rl; - - *rl = rl2; -} - -/********************/ -/* at_horseluck */ -/********************/ -attrib_type at_horseluck = { - "horseluck", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - NO_WRITE, - NO_READ, - ATF_UNIQUE -}; - - -/**********************/ -/* at_peasantluck */ -/**********************/ -attrib_type at_peasantluck = { - "peasantluck", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - NO_WRITE, - NO_READ, - ATF_UNIQUE -}; - -/*********************/ -/* at_chaoscount */ -/*********************/ -attrib_type at_chaoscount = { - "chaoscount", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - a_writeint, - a_readint, - ATF_UNIQUE -}; - -/*********************/ -/* at_deathcount */ -/*********************/ -attrib_type at_deathcount = { - "deathcount", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - a_writeint, - a_readint, - ATF_UNIQUE -}; - -/*********************/ -/* at_woodcount */ -/*********************/ -attrib_type at_woodcount = { - "woodcount", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - NO_WRITE, - a_readint, - ATF_UNIQUE -}; - -/*********************/ -/* at_travelunit */ -/*********************/ -attrib_type at_travelunit = { - "travelunit", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - NO_WRITE, - NO_READ -}; - -void -rsetroad(region * r, direction_t d, short val) -{ - connection * b; - region * r2 = rconnect(r, d); - - if (!r2) return; - b = get_borders(r, r2); - while (b && b->type!=&bt_road) b = b->next; - if (!b) b = new_border(&bt_road, r, r2); - if (r==b->from) b->data.sa[0] = val; - else b->data.sa[1] = val; -} - -short -rroad(const region * r, direction_t d) -{ - int rval; - connection * b; - region * r2 = rconnect(r, d); - - if (!r2) return 0; - b = get_borders(r, r2); - while (b && b->type!=&bt_road) b = b->next; - if (!b) return 0; - rval = b->data.i; - if (r==b->from) return b->data.sa[0]; - return b->data.sa[1]; -} - -boolean -r_isforest(const region * r) -{ - if (fval(r->terrain, FOREST_REGION)) { - /* needs to be covered with at leas 48% trees */ - int mincover = (int)(r->terrain->size * 0.48); - int trees = rtrees(r, 2) + rtrees(r, 1); - return (trees*TREESIZE >= mincover); - } - return false; -} - -int -is_coastregion(region *r) -{ - direction_t i; - int res = 0; - - for(i=0;iterrain, SEA_REGION)) res++; - } - return res; -} - -int -rpeasants(const region * r) -{ - return ((r)->land?(r)->land->peasants:0); -} - -void -rsetpeasants(region * r, int value) -{ - ((r)->land?((r)->land->peasants=(value)):(assert((value)>=0), (value)),0); -} - -int -rmoney(const region * r) -{ - return ((r)->land?(r)->land->money:0); -} - -void -rsethorses(const region *r, int value) -{ - assert(value >= 0); - if(r->land) - r->land->horses = value; -} - -int -rhorses(const region *r) -{ - return r->land?r->land->horses:0; -} - -void -rsetmoney(region * r, int value) -{ - ((r)->land?((r)->land->money=(value)):(assert((value)>=0), (value)),0); -} - -void -r_setdemand(region * r, const luxury_type * ltype, int value) -{ - struct demand * d, ** dp = &r->land->demands; - - if (ltype==NULL) return; - - while (*dp && (*dp)->type != ltype) dp = &(*dp)->next; - d = *dp; - if (!d) { - d = *dp = malloc(sizeof(struct demand)); - d->next = NULL; - d->type = ltype; - } - d->value = value; -} - -const item_type * -r_luxury(region * r) -{ - struct demand * dmd; - if (r->land) { - if (!r->land->demands) { - fix_demand(r); - } - for (dmd=r->land->demands;dmd;dmd=dmd->next) { - if (dmd->value==0) return dmd->type->itype; - } - } - return NULL; -} - -int -r_demand(const region * r, const luxury_type * ltype) -{ - struct demand * d = r->land->demands; - while (d && d->type != ltype) d = d->next; - if (!d) return -1; - return d->value; -} - -const char * -rname(const region * r, const struct locale * lang) -{ - if (r->land) { - return r->land->name; - } - return LOC(lang, terrain_name(r)); -} - -int -rtrees(const region *r, int ageclass) -{ - return ((r)->land?(r)->land->trees[ageclass]:0); -} - -int -rsettrees(const region *r, int ageclass, int value) -{ - if (!r->land) assert(value==0); - else { - assert(value>=0); - return r->land->trees[ageclass]=value; - } - return 0; -} - -static region *last; - -static unsigned int max_index = 0; - -region * -new_region(int x, int y, struct plane * pl, unsigned int uid) -{ - region *r; - - pnormalize(&x, &y, pl); - r = rfindhash(x, y); - - if (r) { - log_error(("duplicate region discovered: %s(%d,%d)\n", regionname(r, NULL), x, y)); - if (r->units) - log_error(("duplicate region contains units\n")); - return r; - } - r = calloc(1, sizeof(region)); - r->x = x; - r->y = y; - r->uid = uid; - r->age = 1; - r->_plane = pl; - rhash(r); - hash_uid(r); - if (last) - addlist(&last, r); - else - addlist(®ions, r); - last = r; - assert(r->next==NULL); - r->index = ++max_index; - return r; -} - -static region * deleted_regions; - -void -remove_region(region ** rlist, region * r) -{ - - while (r->units) { - unit * u = r->units; - i_freeall(&u->items); - remove_unit(&r->units, u); - } - - runhash(r); - unhash_uid(r); - while (*rlist && *rlist!=r) rlist=&(*rlist)->next; - assert(*rlist==r); - *rlist = r->next; - r->next = deleted_regions; - deleted_regions = r; -} - -static void -freeland(land_region * lr) -{ - while (lr->demands) { - struct demand * d = lr->demands; - lr->demands = d->next; - free(d); - } - if (lr->name) free(lr->name); - free(lr); -} - -void -region_setresource(region * r, const resource_type * rtype, int value) -{ - rawmaterial * rm = r->resources; - while (rm) { - if (rm->type->rtype==rtype) { - rm->amount = value; - break; - } - rm=rm->next; - } - if (!rm) { - if (rtype==rt_find("money")) rsetmoney(r, value); - else if (rtype==rt_find("peasant")) rsetpeasants(r, value); - else if (rtype==rt_find("horse")) rsethorses(r, value); - } -} - -int -region_getresource(const region * r, const resource_type * rtype) -{ - const rawmaterial * rm; - for (rm=r->resources;rm;rm=rm->next) { - if (rm->type->rtype==rtype) { - return rm->amount; - } - } - if (rtype==rt_find("money")) return rmoney(r); - if (rtype==rt_find("horse")) return rhorses(r); - if (rtype==rt_find("peasant")) return rpeasants(r); - return 0; -} - -void -free_region(region * r) -{ - if (last == r) last = NULL; - free(r->display); - if (r->land) freeland(r->land); - - if (r->msgs) { - free_messagelist(r->msgs); - r->msgs = 0; - } - - while (r->individual_messages) { - struct individual_message * msg = r->individual_messages; - r->individual_messages = msg->next; - if (msg->msgs) free_messagelist(msg->msgs); - free(msg); - } - - while (r->attribs) a_remove (&r->attribs, r->attribs); - while (r->resources) { - rawmaterial * res = r->resources; - r->resources = res->next; - free(res); - } - - while (r->donations) { - donation * don = r->donations; - r->donations = don->next; - free(don); - } - - while (r->units) { - unit * u = r->units; - r->units = u->next; - uunhash(u); - free_unit(u); - free(u); - } - - while (r->buildings) { - building * b = r->buildings; - assert(b->region==r); - r->buildings = b->next; - bunhash(b); /* must be done here, because remove_building does it, and wasn't called */ - free_building(b); - } - - while (r->ships) { - ship * s = r->ships; - assert(s->region==r); - r->ships = s->next; - sunhash(s); - free_ship(s); - } - - free(r); -} - -void -free_regions(void) -{ - memset(uidhash, 0, sizeof(uidhash)); - while (deleted_regions) { - region * r = deleted_regions; - deleted_regions = r->next; - free_region(r); - } - while (regions) { - region * r = regions; - regions = r->next; - runhash(r); - free_region(r); - } - max_index = 0; - last = NULL; -} - -/** creates a name for a region - * TODO: Make vowels XML-configurable and allow non-ascii characters again. - * - that will probably require a wchar_t * string to pick from. - */ -static char * -makename(void) -{ - int s, v, k, e, p = 0, x = 0; - size_t nk, ne, nv, ns; - static char name[16]; - const char *kons = "bcdfghklmnprstvwz", - *start = "bcdgtskpvfr", - *end = "nlrdst", - *vowels = "aaaaaaaaaaaeeeeeeeeeeeeiiiiiiiiiiioooooooooooouuuuuuuuuuyy"; - - /* const char * vowels_latin1 = "aaaaaaaaaàâeeeeeeeeeéèêiiiiiiiiiíîoooooooooóòôuuuuuuuuuúyy"; */ - - nk = strlen(kons); - ne = strlen(end); - nv = strlen(vowels); - ns = strlen(start); - - for (s = rng_int() % 3 + 2; s > 0; s--) { - if (x > 0) { - k = rng_int() % (int)nk; - name[p] = kons[k]; - p++; - } else { - k = rng_int() % (int)ns; - name[p] = start[k]; - p++; - } - v = rng_int() % (int)nv; - name[p] = vowels[v]; - p++; - if (rng_int() % 3 == 2 || s == 1) { - e = rng_int() % (int)ne; - name[p] = end[e]; - p++; - x = 1; - } else - x = 0; - } - name[p] = '\0'; - name[0] = (char) toupper(name[0]); - return name; -} - -void -setluxuries(region * r, const luxury_type * sale) -{ - const luxury_type * ltype; - - assert(r->land); - - if(r->land->demands) freelist(r->land->demands); - - for (ltype=luxurytypes; ltype; ltype=ltype->next) { - struct demand * dmd = malloc(sizeof(struct demand)); - dmd->type = ltype; - if (ltype!=sale) dmd->value = 1 + rng_int() % 5; - else dmd->value = 0; - dmd->next = r->land->demands; - r->land->demands = dmd; - } -} - -void -terraform_region(region * r, const terrain_type * terrain) -{ - /* Resourcen, die nicht mehr vorkommen können, löschen */ - const terrain_type * oldterrain = r->terrain; - rawmaterial **lrm = &r->resources; - - assert(terrain); - - while (*lrm) { - rawmaterial *rm = *lrm; - const resource_type * rtype = NULL; - - if (terrain->production!=NULL) { - int i; - for (i=0;terrain->production[i].type;++i) { - if (rm->type->rtype == terrain->production[i].type) { - rtype = rm->type->rtype; - break; - } - } - } - if (rtype==NULL) { - *lrm = rm->next; - free(rm); - } else { - lrm = &rm->next; - } - } - - r->terrain = terrain; - terraform_resources(r); - - if (!fval(terrain, LAND_REGION)) { - region_setinfo(r, NULL); - if (r->land!=NULL) { - i_freeall(&r->land->items); - freeland(r->land); - r->land = NULL; - } - rsettrees(r, 0, 0); - rsettrees(r, 1, 0); - rsettrees(r, 2, 0); - rsethorses(r, 0); - rsetpeasants(r, 0); - rsetmoney(r, 0); - freset(r, RF_ENCOUNTER); - freset(r, RF_MALLORN); - /* Beschreibung und Namen löschen */ - return; - } - - if (r->land) { - i_freeall(&r->land->items); - } else { - static struct surround { - struct surround * next; - const luxury_type * type; - int value; - } *trash =NULL, *nb = NULL; - const luxury_type * ltype = NULL; - direction_t d; - int mnr = 0; - - r->land = calloc(1, sizeof(land_region)); - r->land->ownership = NULL; - region_set_morale(r, MORALE_DEFAULT, -1); - region_setname(r, makename()); - for (d=0;d!=MAXDIRECTIONS;++d) { - region * nr = rconnect(r, d); - if (nr && nr->land) { - struct demand * sale = r->land->demands; - while (sale && sale->value!=0) sale=sale->next; - if (sale) { - struct surround * sr = nb; - while (sr && sr->type!=sale->type) sr=sr->next; - if (!sr) { - if (trash) { - sr = trash; - trash = trash->next; - } else { - sr = calloc(1, sizeof(struct surround)); - } - sr->next = nb; - sr->type = sale->type; - sr->value = 1; - nb = sr; - } else sr->value++; - ++mnr; - } - } - } - if (!nb) { - int i = get_maxluxuries(); - if (i>0) { - i = rng_int() % i; - ltype = luxurytypes; - while (i--) ltype=ltype->next; - } - } else { - int i = rng_int() % mnr; - struct surround * srd = nb; - while (i>srd->value) { - i-=srd->value; - srd=srd->next; - } - if (srd->type) setluxuries(r, srd->type); - while (srd->next!=NULL) srd=srd->next; - srd->next=trash; - trash = nb; - nb = NULL; - } - } - - if (fval(terrain, LAND_REGION)) { - const item_type * itype = NULL; - char equip_hash[64]; - - /* TODO: put the equipment in struct terrain, faster */ - sprintf(equip_hash, "terrain_%s", terrain->_name); - equip_items(&r->land->items, get_equipment(equip_hash)); - - if (r->terrain->herbs) { - int len=0; - while (r->terrain->herbs[len]) ++len; - if (len) itype = r->terrain->herbs[rng_int()%len]; - } - if (itype!=NULL) { - rsetherbtype(r, itype); - rsetherbs(r, (short)(50+rng_int()%31)); - } - else { - rsetherbtype(r, NULL); - } - if (oldterrain==NULL || !fval(oldterrain, LAND_REGION)) { - if (rng_int() % 100 < 3) fset(r, RF_MALLORN); - else freset(r, RF_MALLORN); - if (rng_int() % 100 < ENCCHANCE) { - fset(r, RF_ENCOUNTER); - } - } - } - - if (oldterrain==NULL || terrain->size!=oldterrain->size) { - if (terrain==newterrain(T_PLAIN)) { - rsethorses(r, rng_int() % (terrain->size / 50)); - if(rng_int()%100 < 40) { - rsettrees(r, 2, terrain->size * (30+rng_int()%40)/1000); - } - } else if (chance(0.2)) { - rsettrees(r, 2, terrain->size * (30 + rng_int() % 40) / 1000); - } else { - rsettrees(r, 2, 0); - } - rsettrees(r, 1, rtrees(r, 2)/4); - rsettrees(r, 0, rtrees(r, 2)/8); - - if (!fval(r, RF_CHAOTIC)) { - int peasants; - peasants = (maxworkingpeasants(r) * (20+dice_rand("6d10")))/100; - rsetpeasants(r, MAX(100, peasants)); - rsetmoney(r, rpeasants(r) * ((wage(r, NULL, NULL, INT_MAX)+1) + rng_int() % 5)); - } - } -} - -/** ENNO: - * ich denke, das das hier nicht sein sollte. - * statt dessen sollte ein attribut an der region sein, das das erledigt, - * egal ob durch den spell oder anderes angelegt. - **/ -#include "curse.h" -int -production(const region *r) -{ - /* muß rterrain(r) sein, nicht rterrain() wegen rekursion */ - int p = r->terrain->size / MAXPEASANTS_PER_AREA; - if (curse_active(get_curse(r->attribs, ct_find("drought")))) p /= 2; - - return p; -} - -int -resolve_region_coor(variant id, void * address) { - region * r = findregion(id.sa[0], id.sa[1]); - if (r) { - *(region**)address = r; - return 0; - } - *(region**)address = NULL; - return -1; -} - -int -resolve_region_id(variant id, void * address) -{ - region * r = NULL; - if (id.i!=0) { - r = findregionbyid((unsigned int)id.i); - if (r==NULL) { - *(region**)address = NULL; - return -1; - } - } - *(region**)address = r; - return 0; -} - -variant -read_region_reference(struct storage * store) -{ - variant result; - if (store->versionr_int(store); - result.sa[1] = (short)store->r_int(store); - } else { - result.i = store->r_int(store); - } - return result; -} - -void -write_region_reference(const region * r, struct storage * store) -{ - if (r) { - store->w_int(store, r->uid); - } else { - store->w_int(store, 0); - } -} - -struct message_list * -r_getmessages(const struct region * r, const struct faction * viewer) -{ - struct individual_message * imsg = r->individual_messages; - while (imsg && (imsg)->viewer!=viewer) imsg = imsg->next; - if (imsg) return imsg->msgs; - return NULL; -} - -struct message * -r_addmessage(struct region * r, const struct faction * viewer, struct message * msg) -{ - assert(r); - if (viewer) { - struct individual_message * imsg; - imsg = r->individual_messages; - while (imsg && imsg->viewer!=viewer) imsg = imsg->next; - if (imsg==NULL) { - imsg = malloc(sizeof(struct individual_message)); - imsg->next = r->individual_messages; - imsg->msgs = NULL; - r->individual_messages = imsg; - imsg->viewer = viewer; - } - return add_message(&imsg->msgs, msg); - } - return add_message(&r->msgs, msg); -} - -struct faction * -region_get_owner(const struct region * r) -{ - assert(rule_region_owners()); - if (r->land && r->land->ownership) { - return r->land->ownership->owner; - } - return NULL; -} - -struct alliance * -region_get_alliance(const struct region * r) -{ - assert(rule_region_owners()); - if (r->land && r->land->ownership) { - region_owner * own = r->land->ownership; - return own->owner?own->owner->alliance:own->alliance; - } - return NULL; -} - -void -region_set_owner(struct region * r, struct faction * owner, int turn) -{ - assert(rule_region_owners()); - if (r->land) { - if (!r->land->ownership) { - r->land->ownership = malloc(sizeof(region_owner)); - assert(region_get_morale(r)==MORALE_DEFAULT); - r->land->ownership->owner = NULL; - r->land->ownership->alliance = NULL; - r->land->ownership->flags = 0; - } - r->land->ownership->since_turn = turn; - r->land->ownership->morale_turn = turn; - assert(r->land->ownership->owner != owner); - r->land->ownership->owner = owner; - if (owner) { - r->land->ownership->alliance = owner->alliance; - } - } -} - - -faction * update_owners(region * r) -{ - faction * f = NULL; - assert(rule_region_owners()); - if (r->land) { - building * bowner = largestbuilding(r, &cmp_current_owner, false); - building * blargest = largestbuilding(r, &cmp_taxes, false); - if (blargest) { - if (!bowner || bowner->sizesize) { - /* region owners update? */ - unit * u = building_owner(blargest); - f = region_get_owner(r); - if (u==NULL) { - if (f) { - region_set_owner(r, NULL, turn); - r->land->ownership->flags |= OWNER_MOURNING; - f = NULL; - } - } else if (u->faction!=f) { - if (!r->land->ownership) { - /* there has never been a prior owner */ - region_set_morale(r, MORALE_DEFAULT, turn); - } else { - alliance * al = region_get_alliance(r); - if (al && u->faction->alliance==al) { - int morale = MAX(0, r->land->morale-MORALE_TRANSFER); - region_set_morale(r, morale, turn); - } else { - region_set_morale(r, MORALE_TAKEOVER, turn); - if (f) { - r->land->ownership->flags |= OWNER_MOURNING; - } - } - } - region_set_owner(r, u->faction, turn); - f = u->faction; - } - } - } else if (r->land->ownership && r->land->ownership->owner) { - r->land->ownership->flags |= OWNER_MOURNING; - region_set_owner(r, NULL, turn); - f = NULL; - } - } - return f; -} - -void -region_setinfo(struct region * r, const char * info) -{ - free(r->display); - r->display = info?strdup(info):0; -} - -const char * -region_getinfo(const region * r) { - return r->display?r->display:""; -} - -void -region_setname(struct region * r, const char * name) -{ - if (r->land) { - free(r->land->name); - r->land->name = name?strdup(name):0; - } -} - -const char * -region_getname(const region * r) { - if (r->land && r->land->name) { - return r->land->name; - } - return ""; -} - -int region_get_morale(const region * r) -{ - if (r->land) { - assert(r->land->morale>=0 && r->land->morale<=MORALE_MAX); - return r->land->morale; - } - return -1; -} - -void region_set_morale(region * r, int morale, int turn) -{ - if (r->land) { - r->land->morale = (short)morale; - if (turn>=0 && r->land->ownership) { - r->land->ownership->morale_turn = turn; - } - assert(r->land->morale>=0 && r->land->morale<=MORALE_MAX); - } -} - -void get_neighbours(const region * r, region ** list) -{ - direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - list[dir] = rconnect(r, dir); - } -} - -int owner_change(const region * r) -{ - if (r->land && r->land->ownership) { - return r->land->ownership->since_turn; - } - return -1; -} - -boolean is_mourning(const region * r, int in_turn) -{ - int change = owner_change(r); - return (change==in_turn-1 && (r->land->ownership->flags&OWNER_MOURNING)); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "region.h" + +/* kernel includes */ +#include "alliance.h" +#include "building.h" +#include "connection.h" +#include "curse.h" +#include "equipment.h" +#include "faction.h" +#include "item.h" +#include "message.h" +#include "plane.h" +#include "region.h" +#include "resources.h" +#include "save.h" +#include "ship.h" +#include "terrain.h" +#include "terrainid.h" +#include "unit.h" +#include "version.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +extern int dice_rand(const char *s); + +region *regions; + +int +get_maxluxuries() +{ + static int maxluxuries = -1; + if (maxluxuries==-1) { + const luxury_type * ltype; + maxluxuries = 0; + for (ltype = luxurytypes;ltype;ltype=ltype->next) ++maxluxuries; + } + return maxluxuries; +} +const int delta_x[MAXDIRECTIONS] = +{ + -1, 0, 1, 1, 0, -1 +}; + +const int delta_y[MAXDIRECTIONS] = +{ + 1, 1, 0, -1, -1, 0 +}; + +static const direction_t back[MAXDIRECTIONS] = +{ + D_SOUTHEAST, + D_SOUTHWEST, + D_WEST, + D_NORTHWEST, + D_NORTHEAST, + D_EAST, +}; + +direction_t +dir_invert(direction_t dir) +{ + switch (dir) { + case D_PAUSE: + case D_SPECIAL: + return dir; + break; + default: + if (dir>=0 && dirlocale : 0; + if (r==NULL) { + strcpy(buf, "(null)"); + } else { + plane * pl = rplane(r); + int nx = r->x, ny = r->y; + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl, r); + snprintf(buf, size, "%s (%d,%d)", rname(r, lang), nx, ny); + } + buf[size-1] = 0; + return buffer; +} + +const char * +regionname(const region * r, const faction * f) +{ + static char buf[NAMESIZE]; + return write_regionname(r, f, buf, sizeof(buf)); +} + +int +deathcount(const region * r) +{ + attrib * a = a_find(r->attribs, &at_deathcount); + if (!a) return 0; + return a->data.i; +} + +int +chaoscount(const region * r) +{ + attrib * a = a_find(r->attribs, &at_chaoscount); + if (!a) return 0; + return a->data.i; +} + +void +deathcounts (region * r, int fallen) +{ + attrib * a; + static const curse_type * ctype = NULL; + + if (fallen==0) return; + if (!ctype) ctype = ct_find("holyground"); + if (ctype && curse_active(get_curse(r->attribs, ctype))) return; + + a = a_find(r->attribs, &at_deathcount); + if (!a) a = a_add(&r->attribs, a_new(&at_deathcount)); + a->data.i += fallen; + + if (a->data.i<=0) a_remove(&r->attribs, a); +} + +void +chaoscounts(region * r, int fallen) +{ + attrib * a; + + if (fallen==0) return; + + a = a_find(r->attribs, &at_chaoscount); + if (!a) a = a_add(&r->attribs, a_new(&at_chaoscount)); + a->data.i += fallen; + + if (a->data.i<=0) a_remove(&r->attribs, a); +} + + + +/********************/ +/* at_direction */ +/********************/ +static void +a_initdirection(attrib *a) +{ + a->data.v = calloc(1, sizeof(spec_direction)); +} + +static void +a_freedirection(attrib *a) +{ + free(a->data.v); +} + +static int +a_agedirection(attrib *a) +{ + spec_direction *d = (spec_direction *)(a->data.v); + --d->duration; + return (d->duration>0)?AT_AGE_KEEP:AT_AGE_REMOVE; +} + +typedef struct dir_lookup { + char * name; + const char * oldname; + struct dir_lookup * next; +} dir_lookup; + +static dir_lookup * dir_name_lookup; + +void +register_special_direction(const char * name) +{ + struct locale * lang; + char * str = strdup(name); + + for (lang=locales;lang;lang=nextlocale(lang)) { + tnode * tokens = get_translations(lang, UT_SPECDIR); + const char * token = LOC(lang, name); + + if (token) { + variant var; + + var.v = str; + addtoken(tokens, token, var); + + if (lang==default_locale) { + dir_lookup * dl = malloc(sizeof(dir_lookup)); + dl->name = str; + dl->oldname = token; + dl->next = dir_name_lookup; + dir_name_lookup = dl; + } + } else { + log_error(("no translation for spec_direction '%s' in locale '%s'\n", + name, locale_name(lang))); + } + } +} + +static int +a_readdirection(attrib *a, void * owner, struct storage * store) +{ + spec_direction *d = (spec_direction *)(a->data.v); + + d->x = (short)store->r_int(store); + d->y = (short)store->r_int(store); + d->duration = store->r_int(store); + if (store->versionr_tok_buf(store, NULL, 0); + store->r_tok_buf(store, lbuf, sizeof(lbuf)); + + cstring_i(lbuf); + for (;dl;dl=dl->next) { + if (strcmp(lbuf, dl->oldname)==0) { + d->keyword=strdup(dl->name); + sprintf(lbuf, "%s_desc", d->keyword); + d->desc=strdup(dl->name); + break; + } + } + if (dl==NULL) { + log_error(("unknown spec_direction '%s'\n", lbuf)); + assert(!"not implemented"); + } + } + else { + d->desc = store->r_tok(store); + d->keyword = store->r_tok(store); + } + d->active = true; + return AT_READ_OK; +} + +static void +a_writedirection(const attrib * a, const void * owner, struct storage * store) +{ + spec_direction *d = (spec_direction *)(a->data.v); + + store->w_int(store, d->x); + store->w_int(store, d->y); + store->w_int(store, d->duration); + store->w_tok(store, d->desc); + store->w_tok(store, d->keyword); +} + +attrib_type at_direction = { + "direction", + a_initdirection, + a_freedirection, + a_agedirection, + a_writedirection, + a_readdirection +}; + +region * +find_special_direction(const region *r, const char *token, const struct locale * lang) +{ + attrib *a; + spec_direction *d; + + if (strlen(token)==0) return NULL; + for (a = a_find(r->attribs, &at_direction);a && a->type==&at_direction;a=a->next) { + d = (spec_direction *)(a->data.v); + + if (d->active) { + tnode * tokens = get_translations(lang, UT_SPECDIR); + variant var; + if (findtoken(tokens, token, &var)==E_TOK_SUCCESS) { + if (strcmp((const char *)var.v, d->keyword)==0) { + return findregion(d->x, d->y); + } + } + } + } + + return NULL; +} + +attrib * +create_special_direction(region *r, region * rt, int duration, + const char *desc, const char *keyword) + +{ + attrib *a = a_add(&r->attribs, a_new(&at_direction)); + spec_direction *d = (spec_direction *)(a->data.v); + + d->active = false; + d->x = rt->x; + d->y = rt->y; + d->duration = duration; + d->desc = strdup(desc); + d->keyword = strdup(keyword); + + return a; +} + +/* Moveblock wird zur Zeit nicht über Attribute, sondern ein Bitfeld + r->moveblock gemacht. Sollte umgestellt werden, wenn kompliziertere + Dinge gefragt werden. */ + +/********************/ +/* at_moveblock */ +/********************/ +void +a_initmoveblock(attrib *a) +{ + a->data.v = calloc(1, sizeof(moveblock)); +} + +int +a_readmoveblock(attrib *a, void * owner, struct storage * store) +{ + moveblock *m = (moveblock *)(a->data.v); + int i; + + i = store->r_int(store); + m->dir = (direction_t)i; + return AT_READ_OK; +} + +void +a_writemoveblock(const attrib * a, const void * owner, struct storage * store) +{ + moveblock *m = (moveblock *)(a->data.v); + store->w_int(store, (int)m->dir); +} + +attrib_type at_moveblock = { + "moveblock", a_initmoveblock, NULL, NULL, a_writemoveblock, a_readmoveblock +}; + +#define coor_hashkey(x, y) (unsigned int)((x<<16) + y) +#define RMAXHASH MAXREGIONS +static region * regionhash[RMAXHASH]; +static int dummy_data; +static region * dummy_ptr = (region*)&dummy_data; /* a funny hack */ + +typedef struct uidhashentry { + unsigned int uid; + region * r; +} uidhashentry; +static uidhashentry uidhash[MAXREGIONS]; + +struct region * +findregionbyid(unsigned int uid) +{ + int key = uid % MAXREGIONS; + while (uidhash[key].uid!=0 && uidhash[key].uid!=uid) ++key; + return uidhash[key].r; +} + +#define DELMARKER dummy_ptr + +static void +unhash_uid(region * r) +{ + int key = r->uid % MAXREGIONS; + assert(r->uid); + while (uidhash[key].uid!=0 && uidhash[key].uid!=r->uid) ++key; + assert(uidhash[key].r==r); + uidhash[key].r = NULL; +} + +static void +hash_uid(region * r) +{ + unsigned int uid = r->uid; + for (;;) { + if (uid!=0) { + int key = uid % MAXREGIONS; + while (uidhash[key].uid!=0 && uidhash[key].uid!=uid) ++key; + if (uidhash[key].uid==0) { + uidhash[key].uid = uid; + uidhash[key].r = r; + break; + } + assert(uidhash[key].r!=r || !"duplicate registration"); + } + r->uid = uid = rng_int(); + } +} + +#define HASH_STATISTICS 1 +#if HASH_STATISTICS +static int hash_requests; +static int hash_misses; +#endif + +boolean pnormalize(int * x, int * y, const plane * pl) +{ + if (pl) { + if (x) { + int width = pl->maxx - pl->minx + 1; + int nx = *x - pl->minx; + nx = (nx>0)?nx:(width-(-nx)%width); + *x = nx % width+ pl->minx; + } + if (y) { + int height = pl->maxy - pl->miny + 1; + int ny = *y - pl->miny; + ny = (ny>0)?ny:(height-(-ny)%height); + *y = ny % height + pl->miny; + } + } + return false; /* TBD */ +} + +static region * +rfindhash(int x, int y) +{ + unsigned int rid; + + rid = coor_hashkey(x, y); +#if HASH_STATISTICS + ++hash_requests; +#endif + if (rid>=0) { + int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); + while (regionhash[key]!=NULL && (regionhash[key]==DELMARKER || regionhash[key]->x!=x || regionhash[key]->y!=y)) { + key = (key + gk) % RMAXHASH; +#if HASH_STATISTICS + ++hash_misses; +#endif + } + return regionhash[key]; + } + return NULL; +} + +void +rhash(region * r) +{ + unsigned int rid = coor_hashkey(r->x, r->y); + int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); + while (regionhash[key]!=NULL && regionhash[key]!=DELMARKER && regionhash[key]!=r) { + key = (key + gk) % RMAXHASH; + } + assert(regionhash[key]!=r || !"trying to add the same region twice"); + regionhash[key] = r; +} + +void +runhash(region * r) +{ + unsigned int rid = coor_hashkey(r->x, r->y); + int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); + +#ifdef FAST_CONNECT + int d, di; + for (d=0,di=MAXDIRECTIONS/2;d!=MAXDIRECTIONS;++d,++di) { + region * rc = r->connect[d]; + if (rc!=NULL) { + if (di>=MAXDIRECTIONS) di-=MAXDIRECTIONS; + rc->connect[di] = NULL; + r->connect[d] = NULL; + } + } +#endif + while (regionhash[key]!=NULL && regionhash[key]!=r) { + key = (key + gk) % RMAXHASH; + } + assert(regionhash[key]==r || !"trying to remove a unit that is not hashed"); + regionhash[key] = DELMARKER; +} + +region * +r_connect(const region * r, direction_t dir) +{ + region * result; + int x, y; +#ifdef FAST_CONNECT + region * rmodify = (region*)r; + assert (dir>=0 && dirconnect[dir]) return r->connect[dir]; +#endif + assert(dirx + delta_x[dir]; + y = r->y + delta_y[dir]; + pnormalize(&x, &y, rplane(r)); + result = rfindhash(x, y); +#ifdef FAST_CONNECT + if (result) { + rmodify->connect[dir] = result; + result->connect[back[dir]] = rmodify; + } +#endif + return result; +} + +region * +findregion(int x, int y) +{ + return rfindhash(x, y); +} + +/* Contributed by Hubert Mackenberg. Thanks. + * x und y Abstand zwischen x1 und x2 berechnen + */ +static int +koor_distance_orig(int x1, int y1, int x2, int y2) +{ + int dx = x1 - x2; + int dy = y1 - y2; + + /* Bei negativem dy am Ursprung spiegeln, das veraendert + * den Abstand nicht + */ + if ( dy < 0 ) { + dy = -dy; + dx = -dx; + } + + /* + * dy ist jetzt >=0, fuer dx sind 3 Faelle zu untescheiden + */ + if ( dx >= 0 ) { + int result = dx + dy; + return result; + } + else if (-dx >= dy) { + int result = -dx; + return result; + } + else { + return dy; + } +} + +static int +koor_distance_wrap_xy(int x1, int y1, int x2, int y2, int width, int height) +{ + int dx = x1 - x2; + int dy = y1 - y2; + int result, dist; + int mindist = MIN(width, height) >> 1; + + /* Bei negativem dy am Ursprung spiegeln, das veraendert + * den Abstand nicht + */ + if ( dy < 0 ) { + dy = -dy; + dx = -dx; + } + if (dx<0) { + dx = width + dx; + } + /* dx,dy is now pointing northeast */ + result = dx + dy; + if (result<=mindist) return result; + + dist = (width-dx) + (height-dy); /* southwest */ + if (dist>=0 && dist=0 && dist=0 && distx, r1->y, r2->x, r2->y); +} + +static direction_t +koor_reldirection(int ax, int ay, int bx, int by, const struct plane * pl) +{ + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + int x = ax + delta_x[dir]; + int y = ay + delta_y[dir]; + pnormalize(&x, &y, pl); + if (bx == x && by == y) return dir; + } + return NODIRECTION; +} + +spec_direction * +special_direction(const region * from, const region * to) +{ + const attrib *a = a_findc(from->attribs, &at_direction); + + while (a!=NULL && a->type==&at_direction) { + spec_direction * sd = (spec_direction *)a->data.v; + if (sd->x==to->x && sd->y==to->y) return sd; + a = a->next; + } + return NULL; +} + +direction_t +reldirection(const region * from, const region * to) +{ + plane * pl = rplane(from); + if (pl == rplane(to)) { + direction_t dir = koor_reldirection(from->x, from->y, to->x, to->y, pl); + + if (dir==NODIRECTION) { + spec_direction *sd = special_direction(from, to); + if (sd!=NULL && sd->active) return D_SPECIAL; + } + return dir; + } + return NODIRECTION; +} + +void +free_regionlist(region_list *rl) +{ + while (rl) { + region_list * rl2 = rl->next; + free(rl); + rl = rl2; + } +} + +void +add_regionlist(region_list **rl, region *r) +{ + region_list *rl2 = (region_list*)malloc(sizeof(region_list)); + + rl2->data = r; + rl2->next = *rl; + + *rl = rl2; +} + +/********************/ +/* at_horseluck */ +/********************/ +attrib_type at_horseluck = { + "horseluck", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ, + ATF_UNIQUE +}; + + +/**********************/ +/* at_peasantluck */ +/**********************/ +attrib_type at_peasantluck = { + "peasantluck", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ, + ATF_UNIQUE +}; + +/*********************/ +/* at_chaoscount */ +/*********************/ +attrib_type at_chaoscount = { + "chaoscount", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + a_writeint, + a_readint, + ATF_UNIQUE +}; + +/*********************/ +/* at_deathcount */ +/*********************/ +attrib_type at_deathcount = { + "deathcount", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + a_writeint, + a_readint, + ATF_UNIQUE +}; + +/*********************/ +/* at_woodcount */ +/*********************/ +attrib_type at_woodcount = { + "woodcount", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + a_readint, + ATF_UNIQUE +}; + +/*********************/ +/* at_travelunit */ +/*********************/ +attrib_type at_travelunit = { + "travelunit", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +void +rsetroad(region * r, direction_t d, short val) +{ + connection * b; + region * r2 = rconnect(r, d); + + if (!r2) return; + b = get_borders(r, r2); + while (b && b->type!=&bt_road) b = b->next; + if (!b) b = new_border(&bt_road, r, r2); + if (r==b->from) b->data.sa[0] = val; + else b->data.sa[1] = val; +} + +short +rroad(const region * r, direction_t d) +{ + int rval; + connection * b; + region * r2 = rconnect(r, d); + + if (!r2) return 0; + b = get_borders(r, r2); + while (b && b->type!=&bt_road) b = b->next; + if (!b) return 0; + rval = b->data.i; + if (r==b->from) return b->data.sa[0]; + return b->data.sa[1]; +} + +boolean +r_isforest(const region * r) +{ + if (fval(r->terrain, FOREST_REGION)) { + /* needs to be covered with at leas 48% trees */ + int mincover = (int)(r->terrain->size * 0.48); + int trees = rtrees(r, 2) + rtrees(r, 1); + return (trees*TREESIZE >= mincover); + } + return false; +} + +int +is_coastregion(region *r) +{ + direction_t i; + int res = 0; + + for(i=0;iterrain, SEA_REGION)) res++; + } + return res; +} + +int +rpeasants(const region * r) +{ + return ((r)->land?(r)->land->peasants:0); +} + +void +rsetpeasants(region * r, int value) +{ + ((r)->land?((r)->land->peasants=(value)):(assert((value)>=0), (value)),0); +} + +int +rmoney(const region * r) +{ + return ((r)->land?(r)->land->money:0); +} + +void +rsethorses(const region *r, int value) +{ + assert(value >= 0); + if(r->land) + r->land->horses = value; +} + +int +rhorses(const region *r) +{ + return r->land?r->land->horses:0; +} + +void +rsetmoney(region * r, int value) +{ + ((r)->land?((r)->land->money=(value)):(assert((value)>=0), (value)),0); +} + +void +r_setdemand(region * r, const luxury_type * ltype, int value) +{ + struct demand * d, ** dp = &r->land->demands; + + if (ltype==NULL) return; + + while (*dp && (*dp)->type != ltype) dp = &(*dp)->next; + d = *dp; + if (!d) { + d = *dp = malloc(sizeof(struct demand)); + d->next = NULL; + d->type = ltype; + } + d->value = value; +} + +const item_type * +r_luxury(region * r) +{ + struct demand * dmd; + if (r->land) { + if (!r->land->demands) { + fix_demand(r); + } + for (dmd=r->land->demands;dmd;dmd=dmd->next) { + if (dmd->value==0) return dmd->type->itype; + } + } + return NULL; +} + +int +r_demand(const region * r, const luxury_type * ltype) +{ + struct demand * d = r->land->demands; + while (d && d->type != ltype) d = d->next; + if (!d) return -1; + return d->value; +} + +const char * +rname(const region * r, const struct locale * lang) +{ + if (r->land) { + return r->land->name; + } + return LOC(lang, terrain_name(r)); +} + +int +rtrees(const region *r, int ageclass) +{ + return ((r)->land?(r)->land->trees[ageclass]:0); +} + +int +rsettrees(const region *r, int ageclass, int value) +{ + if (!r->land) assert(value==0); + else { + assert(value>=0); + return r->land->trees[ageclass]=value; + } + return 0; +} + +static region *last; + +static unsigned int max_index = 0; + +region * +new_region(int x, int y, struct plane * pl, unsigned int uid) +{ + region *r; + + pnormalize(&x, &y, pl); + r = rfindhash(x, y); + + if (r) { + log_error(("duplicate region discovered: %s(%d,%d)\n", regionname(r, NULL), x, y)); + if (r->units) + log_error(("duplicate region contains units\n")); + return r; + } + r = calloc(1, sizeof(region)); + r->x = x; + r->y = y; + r->uid = uid; + r->age = 1; + r->_plane = pl; + rhash(r); + hash_uid(r); + if (last) + addlist(&last, r); + else + addlist(®ions, r); + last = r; + assert(r->next==NULL); + r->index = ++max_index; + return r; +} + +static region * deleted_regions; + +void +remove_region(region ** rlist, region * r) +{ + + while (r->units) { + unit * u = r->units; + i_freeall(&u->items); + remove_unit(&r->units, u); + } + + runhash(r); + unhash_uid(r); + while (*rlist && *rlist!=r) rlist=&(*rlist)->next; + assert(*rlist==r); + *rlist = r->next; + r->next = deleted_regions; + deleted_regions = r; +} + +static void +freeland(land_region * lr) +{ + while (lr->demands) { + struct demand * d = lr->demands; + lr->demands = d->next; + free(d); + } + if (lr->name) free(lr->name); + free(lr); +} + +void +region_setresource(region * r, const resource_type * rtype, int value) +{ + rawmaterial * rm = r->resources; + while (rm) { + if (rm->type->rtype==rtype) { + rm->amount = value; + break; + } + rm=rm->next; + } + if (!rm) { + if (rtype==rt_find("money")) rsetmoney(r, value); + else if (rtype==rt_find("peasant")) rsetpeasants(r, value); + else if (rtype==rt_find("horse")) rsethorses(r, value); + } +} + +int +region_getresource(const region * r, const resource_type * rtype) +{ + const rawmaterial * rm; + for (rm=r->resources;rm;rm=rm->next) { + if (rm->type->rtype==rtype) { + return rm->amount; + } + } + if (rtype==rt_find("money")) return rmoney(r); + if (rtype==rt_find("horse")) return rhorses(r); + if (rtype==rt_find("peasant")) return rpeasants(r); + return 0; +} + +void +free_region(region * r) +{ + if (last == r) last = NULL; + free(r->display); + if (r->land) freeland(r->land); + + if (r->msgs) { + free_messagelist(r->msgs); + r->msgs = 0; + } + + while (r->individual_messages) { + struct individual_message * msg = r->individual_messages; + r->individual_messages = msg->next; + if (msg->msgs) free_messagelist(msg->msgs); + free(msg); + } + + while (r->attribs) a_remove (&r->attribs, r->attribs); + while (r->resources) { + rawmaterial * res = r->resources; + r->resources = res->next; + free(res); + } + + while (r->donations) { + donation * don = r->donations; + r->donations = don->next; + free(don); + } + + while (r->units) { + unit * u = r->units; + r->units = u->next; + uunhash(u); + free_unit(u); + free(u); + } + + while (r->buildings) { + building * b = r->buildings; + assert(b->region==r); + r->buildings = b->next; + bunhash(b); /* must be done here, because remove_building does it, and wasn't called */ + free_building(b); + } + + while (r->ships) { + ship * s = r->ships; + assert(s->region==r); + r->ships = s->next; + sunhash(s); + free_ship(s); + } + + free(r); +} + +void +free_regions(void) +{ + memset(uidhash, 0, sizeof(uidhash)); + while (deleted_regions) { + region * r = deleted_regions; + deleted_regions = r->next; + free_region(r); + } + while (regions) { + region * r = regions; + regions = r->next; + runhash(r); + free_region(r); + } + max_index = 0; + last = NULL; +} + +/** creates a name for a region + * TODO: Make vowels XML-configurable and allow non-ascii characters again. + * - that will probably require a wchar_t * string to pick from. + */ +static char * +makename(void) +{ + int s, v, k, e, p = 0, x = 0; + size_t nk, ne, nv, ns; + static char name[16]; + const char *kons = "bcdfghklmnprstvwz", + *start = "bcdgtskpvfr", + *end = "nlrdst", + *vowels = "aaaaaaaaaaaeeeeeeeeeeeeiiiiiiiiiiioooooooooooouuuuuuuuuuyy"; + + /* const char * vowels_latin1 = "aaaaaaaaaàâeeeeeeeeeéèêiiiiiiiiiíîoooooooooóòôuuuuuuuuuúyy"; */ + + nk = strlen(kons); + ne = strlen(end); + nv = strlen(vowels); + ns = strlen(start); + + for (s = rng_int() % 3 + 2; s > 0; s--) { + if (x > 0) { + k = rng_int() % (int)nk; + name[p] = kons[k]; + p++; + } else { + k = rng_int() % (int)ns; + name[p] = start[k]; + p++; + } + v = rng_int() % (int)nv; + name[p] = vowels[v]; + p++; + if (rng_int() % 3 == 2 || s == 1) { + e = rng_int() % (int)ne; + name[p] = end[e]; + p++; + x = 1; + } else + x = 0; + } + name[p] = '\0'; + name[0] = (char) toupper(name[0]); + return name; +} + +void +setluxuries(region * r, const luxury_type * sale) +{ + const luxury_type * ltype; + + assert(r->land); + + if(r->land->demands) freelist(r->land->demands); + + for (ltype=luxurytypes; ltype; ltype=ltype->next) { + struct demand * dmd = malloc(sizeof(struct demand)); + dmd->type = ltype; + if (ltype!=sale) dmd->value = 1 + rng_int() % 5; + else dmd->value = 0; + dmd->next = r->land->demands; + r->land->demands = dmd; + } +} + +void +terraform_region(region * r, const terrain_type * terrain) +{ + /* Resourcen, die nicht mehr vorkommen können, löschen */ + const terrain_type * oldterrain = r->terrain; + rawmaterial **lrm = &r->resources; + + assert(terrain); + + while (*lrm) { + rawmaterial *rm = *lrm; + const resource_type * rtype = NULL; + + if (terrain->production!=NULL) { + int i; + for (i=0;terrain->production[i].type;++i) { + if (rm->type->rtype == terrain->production[i].type) { + rtype = rm->type->rtype; + break; + } + } + } + if (rtype==NULL) { + *lrm = rm->next; + free(rm); + } else { + lrm = &rm->next; + } + } + + r->terrain = terrain; + terraform_resources(r); + + if (!fval(terrain, LAND_REGION)) { + region_setinfo(r, NULL); + if (r->land!=NULL) { + i_freeall(&r->land->items); + freeland(r->land); + r->land = NULL; + } + rsettrees(r, 0, 0); + rsettrees(r, 1, 0); + rsettrees(r, 2, 0); + rsethorses(r, 0); + rsetpeasants(r, 0); + rsetmoney(r, 0); + freset(r, RF_ENCOUNTER); + freset(r, RF_MALLORN); + /* Beschreibung und Namen löschen */ + return; + } + + if (r->land) { + i_freeall(&r->land->items); + } else { + static struct surround { + struct surround * next; + const luxury_type * type; + int value; + } *trash =NULL, *nb = NULL; + const luxury_type * ltype = NULL; + direction_t d; + int mnr = 0; + + r->land = calloc(1, sizeof(land_region)); + r->land->ownership = NULL; + region_set_morale(r, MORALE_DEFAULT, -1); + region_setname(r, makename()); + for (d=0;d!=MAXDIRECTIONS;++d) { + region * nr = rconnect(r, d); + if (nr && nr->land) { + struct demand * sale = r->land->demands; + while (sale && sale->value!=0) sale=sale->next; + if (sale) { + struct surround * sr = nb; + while (sr && sr->type!=sale->type) sr=sr->next; + if (!sr) { + if (trash) { + sr = trash; + trash = trash->next; + } else { + sr = calloc(1, sizeof(struct surround)); + } + sr->next = nb; + sr->type = sale->type; + sr->value = 1; + nb = sr; + } else sr->value++; + ++mnr; + } + } + } + if (!nb) { + int i = get_maxluxuries(); + if (i>0) { + i = rng_int() % i; + ltype = luxurytypes; + while (i--) ltype=ltype->next; + } + } else { + int i = rng_int() % mnr; + struct surround * srd = nb; + while (i>srd->value) { + i-=srd->value; + srd=srd->next; + } + if (srd->type) setluxuries(r, srd->type); + while (srd->next!=NULL) srd=srd->next; + srd->next=trash; + trash = nb; + nb = NULL; + } + } + + if (fval(terrain, LAND_REGION)) { + const item_type * itype = NULL; + char equip_hash[64]; + + /* TODO: put the equipment in struct terrain, faster */ + sprintf(equip_hash, "terrain_%s", terrain->_name); + equip_items(&r->land->items, get_equipment(equip_hash)); + + if (r->terrain->herbs) { + int len=0; + while (r->terrain->herbs[len]) ++len; + if (len) itype = r->terrain->herbs[rng_int()%len]; + } + if (itype!=NULL) { + rsetherbtype(r, itype); + rsetherbs(r, (short)(50+rng_int()%31)); + } + else { + rsetherbtype(r, NULL); + } + if (oldterrain==NULL || !fval(oldterrain, LAND_REGION)) { + if (rng_int() % 100 < 3) fset(r, RF_MALLORN); + else freset(r, RF_MALLORN); + if (rng_int() % 100 < ENCCHANCE) { + fset(r, RF_ENCOUNTER); + } + } + } + + if (oldterrain==NULL || terrain->size!=oldterrain->size) { + if (terrain==newterrain(T_PLAIN)) { + rsethorses(r, rng_int() % (terrain->size / 50)); + if(rng_int()%100 < 40) { + rsettrees(r, 2, terrain->size * (30+rng_int()%40)/1000); + } + } else if (chance(0.2)) { + rsettrees(r, 2, terrain->size * (30 + rng_int() % 40) / 1000); + } else { + rsettrees(r, 2, 0); + } + rsettrees(r, 1, rtrees(r, 2)/4); + rsettrees(r, 0, rtrees(r, 2)/8); + + if (!fval(r, RF_CHAOTIC)) { + int peasants; + peasants = (maxworkingpeasants(r) * (20+dice_rand("6d10")))/100; + rsetpeasants(r, MAX(100, peasants)); + rsetmoney(r, rpeasants(r) * ((wage(r, NULL, NULL, INT_MAX)+1) + rng_int() % 5)); + } + } +} + +/** ENNO: + * ich denke, das das hier nicht sein sollte. + * statt dessen sollte ein attribut an der region sein, das das erledigt, + * egal ob durch den spell oder anderes angelegt. + **/ +#include "curse.h" +int +production(const region *r) +{ + /* muß rterrain(r) sein, nicht rterrain() wegen rekursion */ + int p = r->terrain->size / MAXPEASANTS_PER_AREA; + if (curse_active(get_curse(r->attribs, ct_find("drought")))) p /= 2; + + return p; +} + +int +resolve_region_coor(variant id, void * address) { + region * r = findregion(id.sa[0], id.sa[1]); + if (r) { + *(region**)address = r; + return 0; + } + *(region**)address = NULL; + return -1; +} + +int +resolve_region_id(variant id, void * address) +{ + region * r = NULL; + if (id.i!=0) { + r = findregionbyid((unsigned int)id.i); + if (r==NULL) { + *(region**)address = NULL; + return -1; + } + } + *(region**)address = r; + return 0; +} + +variant +read_region_reference(struct storage * store) +{ + variant result; + if (store->versionr_int(store); + result.sa[1] = (short)store->r_int(store); + } else { + result.i = store->r_int(store); + } + return result; +} + +void +write_region_reference(const region * r, struct storage * store) +{ + if (r) { + store->w_int(store, r->uid); + } else { + store->w_int(store, 0); + } +} + +struct message_list * +r_getmessages(const struct region * r, const struct faction * viewer) +{ + struct individual_message * imsg = r->individual_messages; + while (imsg && (imsg)->viewer!=viewer) imsg = imsg->next; + if (imsg) return imsg->msgs; + return NULL; +} + +struct message * +r_addmessage(struct region * r, const struct faction * viewer, struct message * msg) +{ + assert(r); + if (viewer) { + struct individual_message * imsg; + imsg = r->individual_messages; + while (imsg && imsg->viewer!=viewer) imsg = imsg->next; + if (imsg==NULL) { + imsg = malloc(sizeof(struct individual_message)); + imsg->next = r->individual_messages; + imsg->msgs = NULL; + r->individual_messages = imsg; + imsg->viewer = viewer; + } + return add_message(&imsg->msgs, msg); + } + return add_message(&r->msgs, msg); +} + +struct faction * +region_get_owner(const struct region * r) +{ + assert(rule_region_owners()); + if (r->land && r->land->ownership) { + return r->land->ownership->owner; + } + return NULL; +} + +struct alliance * +region_get_alliance(const struct region * r) +{ + assert(rule_region_owners()); + if (r->land && r->land->ownership) { + region_owner * own = r->land->ownership; + return own->owner?own->owner->alliance:own->alliance; + } + return NULL; +} + +void +region_set_owner(struct region * r, struct faction * owner, int turn) +{ + assert(rule_region_owners()); + if (r->land) { + if (!r->land->ownership) { + r->land->ownership = malloc(sizeof(region_owner)); + assert(region_get_morale(r)==MORALE_DEFAULT); + r->land->ownership->owner = NULL; + r->land->ownership->alliance = NULL; + r->land->ownership->flags = 0; + } + r->land->ownership->since_turn = turn; + r->land->ownership->morale_turn = turn; + assert(r->land->ownership->owner != owner); + r->land->ownership->owner = owner; + if (owner) { + r->land->ownership->alliance = owner->alliance; + } + } +} + + +faction * update_owners(region * r) +{ + faction * f = NULL; + assert(rule_region_owners()); + if (r->land) { + building * bowner = largestbuilding(r, &cmp_current_owner, false); + building * blargest = largestbuilding(r, &cmp_taxes, false); + if (blargest) { + if (!bowner || bowner->sizesize) { + /* region owners update? */ + unit * u = building_owner(blargest); + f = region_get_owner(r); + if (u==NULL) { + if (f) { + region_set_owner(r, NULL, turn); + r->land->ownership->flags |= OWNER_MOURNING; + f = NULL; + } + } else if (u->faction!=f) { + if (!r->land->ownership) { + /* there has never been a prior owner */ + region_set_morale(r, MORALE_DEFAULT, turn); + } else { + alliance * al = region_get_alliance(r); + if (al && u->faction->alliance==al) { + int morale = MAX(0, r->land->morale-MORALE_TRANSFER); + region_set_morale(r, morale, turn); + } else { + region_set_morale(r, MORALE_TAKEOVER, turn); + if (f) { + r->land->ownership->flags |= OWNER_MOURNING; + } + } + } + region_set_owner(r, u->faction, turn); + f = u->faction; + } + } + } else if (r->land->ownership && r->land->ownership->owner) { + r->land->ownership->flags |= OWNER_MOURNING; + region_set_owner(r, NULL, turn); + f = NULL; + } + } + return f; +} + +void +region_setinfo(struct region * r, const char * info) +{ + free(r->display); + r->display = info?strdup(info):0; +} + +const char * +region_getinfo(const region * r) { + return r->display?r->display:""; +} + +void +region_setname(struct region * r, const char * name) +{ + if (r->land) { + free(r->land->name); + r->land->name = name?strdup(name):0; + } +} + +const char * +region_getname(const region * r) { + if (r->land && r->land->name) { + return r->land->name; + } + return ""; +} + +int region_get_morale(const region * r) +{ + if (r->land) { + assert(r->land->morale>=0 && r->land->morale<=MORALE_MAX); + return r->land->morale; + } + return -1; +} + +void region_set_morale(region * r, int morale, int turn) +{ + if (r->land) { + r->land->morale = (short)morale; + if (turn>=0 && r->land->ownership) { + r->land->ownership->morale_turn = turn; + } + assert(r->land->morale>=0 && r->land->morale<=MORALE_MAX); + } +} + +void get_neighbours(const region * r, region ** list) +{ + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + list[dir] = rconnect(r, dir); + } +} + +int owner_change(const region * r) +{ + if (r->land && r->land->ownership) { + return r->land->ownership->since_turn; + } + return -1; +} + +boolean is_mourning(const region * r, int in_turn) +{ + int change = owner_change(r); + return (change==in_turn-1 && (r->land->ownership->flags&OWNER_MOURNING)); +} diff --git a/src/kernel/region.h b/src/kernel/region.h index b5a955eac..5c226fd2a 100644 --- a/src/kernel/region.h +++ b/src/kernel/region.h @@ -1,300 +1,300 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_REGION -#define H_KRNL_REGION -#ifdef __cplusplus -extern "C" { -#endif - -#include "types.h" - -/* FAST_CONNECT: regions are directly connected to neighbours, saves doing - a hash-access each time a neighbour is needed */ -#define FAST_CONNECT - -#define RF_CHAOTIC (1<<0) -#define RF_MALLORN (1<<1) -#define RF_BLOCKED (1<<2) - -#define RF_BLOCK_NORTHWEST (1<<3) -#define RF_BLOCK_NORTHEAST (1<<4) -#define RF_BLOCK_EAST (1<<5) -#define RF_BLOCK_SOUTHEAST (1<<6) -#define RF_BLOCK_SOUTHWEST (1<<7) -#define RF_BLOCK_WEST (1<<8) - -#define RF_ENCOUNTER (1<<9) -#define RF_MIGRATION (1<<10) -#define RF_UNUSED_1 (1<<11) -#define RF_ORCIFIED (1<<12) -#define RF_CURSED (1<<13) - - /* debug flags */ -#define RF_COMBATDEBUG (1<<14) -#define RF_MAPPER_HIGHLIGHT (1<<14) /* only used by mapper, not stored */ -#define RF_LIGHTHOUSE (1<<15) /* this region may contain a lighthouse */ - -#define RF_SELECT (1<<17) -#define RF_MARK (1<<18) - -/* flags that speed up attribute access: */ -#define RF_TRAVELUNIT (1<<19) -#define RF_GUARDED (1<<20) - -#define RF_ALL 0xFFFFFF - -#define RF_SAVEMASK (RF_GUARDED|RF_CHAOTIC|RF_MALLORN|RF_BLOCKED|RF_BLOCK_NORTHWEST|RF_BLOCK_NORTHEAST|RF_BLOCK_EAST|RF_BLOCK_SOUTHEAST|RF_BLOCK_SOUTHWEST|RF_BLOCK_WEST|RF_ENCOUNTER|RF_ORCIFIED) -struct message; -struct message_list; -struct rawmaterial; -struct donation; -struct item; - -#define MORALE_TAX_FACTOR 0.005 /* 0.5% tax per point of morale */ -#define MORALE_MAX 10 /* Maximum morale allowed */ -#define MORALE_DEFAULT 1 /* Morale of peasants when they are conquered for the first time */ -#define MORALE_TAKEOVER 0 /* Morale of peasants after they lose their lord */ -#define MORALE_COOLDOWN 2 /* minimum cooldown before a morale change occurs */ -#define MORALE_AVERAGE 6 /* default average time for morale to change */ -#define MORALE_TRANSFER 2 /* points of morale lost when GIVE COMMAND */ - -#define OWNER_MOURNING 0x01 -typedef struct region_owner { - struct faction * owner; - struct alliance * alliance; - int since_turn; /* turn the region changed owners */ - int morale_turn; /* turn when morale has changed most recently */ - unsigned int flags; -} region_owner; - -typedef struct demand { - struct demand * next; - const struct luxury_type * type; - int value; -} demand; - -typedef struct land_region { - char *name; - /* TODO: demand kann nach Konvertierung entfernt werden. */ - demand * demands; - const struct item_type * herbtype; - short herbs; - short morale; - int trees[3]; /* 0 -> seeds, 1 -> shoots, 2 -> trees */ - int horses; - int peasants; - int newpeasants; - int money; - struct item * items; /* items that can be claimed */ - struct region_owner * ownership; -} land_region; - -typedef struct donation { - struct donation *next; - struct faction *f1, *f2; - int amount; -} donation; - -typedef struct region { - struct region *next; - struct land_region *land; - struct unit *units; - struct ship *ships; - struct building *buildings; - unsigned int index; - /* an ascending number, to improve the speed of determining the interval in - which a faction has its units. See the implementations of firstregion - and lastregion */ - unsigned int uid; /* a unique id */ - int x, y; - struct plane * _plane; /* to access, use rplane(r) */ - char *display; - unsigned int flags; - unsigned short age; - struct message_list *msgs; - struct individual_message { - struct individual_message * next; - const struct faction * viewer; - struct message_list *msgs; - } * individual_messages; - struct attrib *attribs; - struct donation * donations; - const struct terrain_type * terrain; - struct rawmaterial * resources; -#ifdef FAST_CONNECT - struct region * connect[MAXDIRECTIONS]; /* use rconnect(r, dir) to access */ -#endif -} region; - -extern struct region *regions; - -typedef struct region_list { - struct region_list * next; - struct region * data; -} region_list; - -struct message_list * r_getmessages(const struct region * r, const struct faction * viewer); -struct message * r_addmessage(struct region * r, const struct faction * viewer, struct message * msg); - -typedef struct spec_direction { - int x, y; - int duration; - boolean active; - char *desc; - char *keyword; -} spec_direction; - -typedef struct { - direction_t dir; -} moveblock; - -#define reg_hashkey(r) (r->index) - -int distance(const struct region*, const struct region*); -int koor_distance(int ax, int ay, int bx, int by) ; -direction_t reldirection(const struct region * from, const struct region * to); -struct region * findregion(int x, int y); -struct region * findregionbyid(unsigned int uid); - -extern struct attrib_type at_direction; -extern struct attrib_type at_moveblock; -extern struct attrib_type at_peasantluck; -extern struct attrib_type at_horseluck; -extern struct attrib_type at_chaoscount; -extern struct attrib_type at_woodcount; -extern struct attrib_type at_deathcount; -extern struct attrib_type at_travelunit; - -void initrhash(void); -void rhash(struct region * r); -void runhash(struct region * r); - -void free_regionlist(region_list *rl); -void add_regionlist(region_list **rl, struct region *r); - -struct region * find_special_direction(const struct region *r, const char *token, const struct locale * lang); -void register_special_direction(const char * name); -struct spec_direction * special_direction(const region * from, const region * to); -struct attrib *create_special_direction(struct region *r, struct region *rt, - int duration, const char *desc, - const char *keyword); - -int deathcount(const struct region * r); -int chaoscount(const struct region * r); - -void deathcounts(struct region * r, int delta); -void chaoscounts(struct region * r, int delta); - -void setluxuries(struct region * r, const struct luxury_type * sale); -int get_maxluxuries(void); - -short rroad(const struct region * r, direction_t d); -void rsetroad(struct region * r, direction_t d, short value); - -int is_coastregion(struct region *r); - -int rtrees(const struct region * r, int ageclass); -enum { - TREE_SEED = 0, - TREE_SAPLING = 1, - TREE_TREE = 2 -}; - -int rsettrees(const struct region *r, int ageclass, int value); - -int rpeasants(const struct region * r); -void rsetpeasants(struct region * r, int value); -int rmoney(const struct region * r); -void rsetmoney(struct region * r, int value); -int rhorses(const struct region * r); -void rsethorses(const struct region * r, int value); - -#define rbuildings(r) ((r)->buildings) - -#define rherbtype(r) ((r)->land?(r)->land->herbtype:0) -#define rsetherbtype(r, value) if ((r)->land) (r)->land->herbtype=(value) - -#define rherbs(r) ((r)->land?(r)->land->herbs:0) -#define rsetherbs(r, value) if ((r)->land) ((r)->land->herbs=(short)(value)) - -boolean r_isforest(const struct region * r); - -#define rterrain(r) (oldterrain((r)->terrain)) -#define rsetterrain(r, t) ((r)->terrain = newterrain(t)) - -const char * rname(const struct region * r, const struct locale * lang); - -#define rplane(r) getplane(r) - -void r_setdemand(struct region * r, const struct luxury_type * ltype, int value); -int r_demand(const struct region * r, const struct luxury_type * ltype); - -const char * write_regionname(const struct region * r, const struct faction * f, char * buffer, size_t size); - -struct region * new_region(int x, int y, struct plane * pl, unsigned int uid); -void remove_region(region ** rlist, region * r); -void terraform_region(struct region * r, const struct terrain_type * terrain); -boolean pnormalize(int * x, int * y, const struct plane * pl); - -extern const int delta_x[MAXDIRECTIONS]; -extern const int delta_y[MAXDIRECTIONS]; -direction_t dir_invert(direction_t dir); -int production(const struct region *r); - -void region_set_owner(struct region * r, struct faction * owner, int turn); -struct faction * region_get_owner(const struct region * r); -struct alliance * region_get_alliance(const struct region * r); - -struct region * r_connect(const struct region *, direction_t dir); -#ifdef FAST_CONNECT -# define rconnect(r, dir) ((r)->connect[dir]?(r)->connect[dir]:r_connect(r, (direction_t)dir)) -#else -# define rconnect(r, dir) r_connect(r, (direction_t)dir) -#endif - -void free_regions(void); - -int region_get_morale(const region * r); -void region_set_morale(region * r, int morale, int turn); - -void write_region_reference(const struct region * r, struct storage * store); -variant read_region_reference(struct storage * store); -int resolve_region_coor(variant id, void * address); -int resolve_region_id(variant id, void * address); -#define RESOLVE_REGION(version) ((version + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_REGION +#define H_KRNL_REGION +#ifdef __cplusplus +extern "C" { +#endif + +#include "types.h" + +/* FAST_CONNECT: regions are directly connected to neighbours, saves doing + a hash-access each time a neighbour is needed */ +#define FAST_CONNECT + +#define RF_CHAOTIC (1<<0) +#define RF_MALLORN (1<<1) +#define RF_BLOCKED (1<<2) + +#define RF_BLOCK_NORTHWEST (1<<3) +#define RF_BLOCK_NORTHEAST (1<<4) +#define RF_BLOCK_EAST (1<<5) +#define RF_BLOCK_SOUTHEAST (1<<6) +#define RF_BLOCK_SOUTHWEST (1<<7) +#define RF_BLOCK_WEST (1<<8) + +#define RF_ENCOUNTER (1<<9) +#define RF_MIGRATION (1<<10) +#define RF_UNUSED_1 (1<<11) +#define RF_ORCIFIED (1<<12) +#define RF_CURSED (1<<13) + + /* debug flags */ +#define RF_COMBATDEBUG (1<<14) +#define RF_MAPPER_HIGHLIGHT (1<<14) /* only used by mapper, not stored */ +#define RF_LIGHTHOUSE (1<<15) /* this region may contain a lighthouse */ + +#define RF_SELECT (1<<17) +#define RF_MARK (1<<18) + +/* flags that speed up attribute access: */ +#define RF_TRAVELUNIT (1<<19) +#define RF_GUARDED (1<<20) + +#define RF_ALL 0xFFFFFF + +#define RF_SAVEMASK (RF_GUARDED|RF_CHAOTIC|RF_MALLORN|RF_BLOCKED|RF_BLOCK_NORTHWEST|RF_BLOCK_NORTHEAST|RF_BLOCK_EAST|RF_BLOCK_SOUTHEAST|RF_BLOCK_SOUTHWEST|RF_BLOCK_WEST|RF_ENCOUNTER|RF_ORCIFIED) +struct message; +struct message_list; +struct rawmaterial; +struct donation; +struct item; + +#define MORALE_TAX_FACTOR 0.005 /* 0.5% tax per point of morale */ +#define MORALE_MAX 10 /* Maximum morale allowed */ +#define MORALE_DEFAULT 1 /* Morale of peasants when they are conquered for the first time */ +#define MORALE_TAKEOVER 0 /* Morale of peasants after they lose their lord */ +#define MORALE_COOLDOWN 2 /* minimum cooldown before a morale change occurs */ +#define MORALE_AVERAGE 6 /* default average time for morale to change */ +#define MORALE_TRANSFER 2 /* points of morale lost when GIVE COMMAND */ + +#define OWNER_MOURNING 0x01 +typedef struct region_owner { + struct faction * owner; + struct alliance * alliance; + int since_turn; /* turn the region changed owners */ + int morale_turn; /* turn when morale has changed most recently */ + unsigned int flags; +} region_owner; + +typedef struct demand { + struct demand * next; + const struct luxury_type * type; + int value; +} demand; + +typedef struct land_region { + char *name; + /* TODO: demand kann nach Konvertierung entfernt werden. */ + demand * demands; + const struct item_type * herbtype; + short herbs; + short morale; + int trees[3]; /* 0 -> seeds, 1 -> shoots, 2 -> trees */ + int horses; + int peasants; + int newpeasants; + int money; + struct item * items; /* items that can be claimed */ + struct region_owner * ownership; +} land_region; + +typedef struct donation { + struct donation *next; + struct faction *f1, *f2; + int amount; +} donation; + +typedef struct region { + struct region *next; + struct land_region *land; + struct unit *units; + struct ship *ships; + struct building *buildings; + unsigned int index; + /* an ascending number, to improve the speed of determining the interval in + which a faction has its units. See the implementations of firstregion + and lastregion */ + unsigned int uid; /* a unique id */ + int x, y; + struct plane * _plane; /* to access, use rplane(r) */ + char *display; + unsigned int flags; + unsigned short age; + struct message_list *msgs; + struct individual_message { + struct individual_message * next; + const struct faction * viewer; + struct message_list *msgs; + } * individual_messages; + struct attrib *attribs; + struct donation * donations; + const struct terrain_type * terrain; + struct rawmaterial * resources; +#ifdef FAST_CONNECT + struct region * connect[MAXDIRECTIONS]; /* use rconnect(r, dir) to access */ +#endif +} region; + +extern struct region *regions; + +typedef struct region_list { + struct region_list * next; + struct region * data; +} region_list; + +struct message_list * r_getmessages(const struct region * r, const struct faction * viewer); +struct message * r_addmessage(struct region * r, const struct faction * viewer, struct message * msg); + +typedef struct spec_direction { + int x, y; + int duration; + boolean active; + char *desc; + char *keyword; +} spec_direction; + +typedef struct { + direction_t dir; +} moveblock; + +#define reg_hashkey(r) (r->index) + +int distance(const struct region*, const struct region*); +int koor_distance(int ax, int ay, int bx, int by) ; +direction_t reldirection(const struct region * from, const struct region * to); +struct region * findregion(int x, int y); +struct region * findregionbyid(unsigned int uid); + +extern struct attrib_type at_direction; +extern struct attrib_type at_moveblock; +extern struct attrib_type at_peasantluck; +extern struct attrib_type at_horseluck; +extern struct attrib_type at_chaoscount; +extern struct attrib_type at_woodcount; +extern struct attrib_type at_deathcount; +extern struct attrib_type at_travelunit; + +void initrhash(void); +void rhash(struct region * r); +void runhash(struct region * r); + +void free_regionlist(region_list *rl); +void add_regionlist(region_list **rl, struct region *r); + +struct region * find_special_direction(const struct region *r, const char *token, const struct locale * lang); +void register_special_direction(const char * name); +struct spec_direction * special_direction(const region * from, const region * to); +struct attrib *create_special_direction(struct region *r, struct region *rt, + int duration, const char *desc, + const char *keyword); + +int deathcount(const struct region * r); +int chaoscount(const struct region * r); + +void deathcounts(struct region * r, int delta); +void chaoscounts(struct region * r, int delta); + +void setluxuries(struct region * r, const struct luxury_type * sale); +int get_maxluxuries(void); + +short rroad(const struct region * r, direction_t d); +void rsetroad(struct region * r, direction_t d, short value); + +int is_coastregion(struct region *r); + +int rtrees(const struct region * r, int ageclass); +enum { + TREE_SEED = 0, + TREE_SAPLING = 1, + TREE_TREE = 2 +}; + +int rsettrees(const struct region *r, int ageclass, int value); + +int rpeasants(const struct region * r); +void rsetpeasants(struct region * r, int value); +int rmoney(const struct region * r); +void rsetmoney(struct region * r, int value); +int rhorses(const struct region * r); +void rsethorses(const struct region * r, int value); + +#define rbuildings(r) ((r)->buildings) + +#define rherbtype(r) ((r)->land?(r)->land->herbtype:0) +#define rsetherbtype(r, value) if ((r)->land) (r)->land->herbtype=(value) + +#define rherbs(r) ((r)->land?(r)->land->herbs:0) +#define rsetherbs(r, value) if ((r)->land) ((r)->land->herbs=(short)(value)) + +boolean r_isforest(const struct region * r); + +#define rterrain(r) (oldterrain((r)->terrain)) +#define rsetterrain(r, t) ((r)->terrain = newterrain(t)) + +const char * rname(const struct region * r, const struct locale * lang); + +#define rplane(r) getplane(r) + +void r_setdemand(struct region * r, const struct luxury_type * ltype, int value); +int r_demand(const struct region * r, const struct luxury_type * ltype); + +const char * write_regionname(const struct region * r, const struct faction * f, char * buffer, size_t size); + +struct region * new_region(int x, int y, struct plane * pl, unsigned int uid); +void remove_region(region ** rlist, region * r); +void terraform_region(struct region * r, const struct terrain_type * terrain); +boolean pnormalize(int * x, int * y, const struct plane * pl); + +extern const int delta_x[MAXDIRECTIONS]; +extern const int delta_y[MAXDIRECTIONS]; +direction_t dir_invert(direction_t dir); +int production(const struct region *r); + +void region_set_owner(struct region * r, struct faction * owner, int turn); +struct faction * region_get_owner(const struct region * r); +struct alliance * region_get_alliance(const struct region * r); + +struct region * r_connect(const struct region *, direction_t dir); +#ifdef FAST_CONNECT +# define rconnect(r, dir) ((r)->connect[dir]?(r)->connect[dir]:r_connect(r, (direction_t)dir)) +#else +# define rconnect(r, dir) r_connect(r, (direction_t)dir) +#endif + +void free_regions(void); + +int region_get_morale(const region * r); +void region_set_morale(region * r, int morale, int turn); + +void write_region_reference(const struct region * r, struct storage * store); +variant read_region_reference(struct storage * store); +int resolve_region_coor(variant id, void * address); +int resolve_region_id(variant id, void * address); +#define RESOLVE_REGION(version) ((version - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include - -struct message; - -/* TODO: this could be nicer and faster - * call with MSG(("msg_name", "param", p), buf, faction). */ -#define MSG(makemsg, buf, size, loc, ud) { struct message * m = msg_message makemsg; nr_render(m, loc, buf, size, ud); msg_release(m); } -#define RENDER(f, buf, size, mcreate) { struct message * m = msg_message mcreate; nr_render(m, f->locale, buf, size, f); msg_release(m); } +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include + +struct message; + +/* TODO: this could be nicer and faster + * call with MSG(("msg_name", "param", p), buf, faction). */ +#define MSG(makemsg, buf, size, loc, ud) { struct message * m = msg_message makemsg; nr_render(m, loc, buf, size, ud); msg_release(m); } +#define RENDER(f, buf, size, mcreate) { struct message * m = msg_message mcreate; nr_render(m, f->locale, buf, size, f); msg_release(m); } diff --git a/src/kernel/reports.c b/src/kernel/reports.c index b373e73ba..dadad6481 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -1,2186 +1,2186 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "reports.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include -#include -#include - -/* attributes includes */ -#include -#include -#include -#include - -boolean nocr = false; -boolean nonr = false; -boolean noreports = false; - -const char * visibility[] = { - "none", - "neighbour", - "lighthouse", - "travel", - "far", - "unit", - "battle" -}; - -const char *coasts[MAXDIRECTIONS] = -{ - "coast::nw", - "coast::ne", - "coast::e", - "coast::se", - "coast::sw", - "coast::w" -}; - -static char * -groupid(const struct group * g, const struct faction * f) -{ - typedef char name[OBJECTIDSIZE + 1]; - static name idbuf[8]; - static int nextbuf = 0; - char *buf = idbuf[(++nextbuf) % 8]; - sprintf(buf, "%s (%s)", g->name, factionid(f)); - return buf; -} - -const char * combatstatus[] = { - "status_aggressive", "status_front", - "status_rear", "status_defensive", - "status_avoid", "status_flee" -}; - -const char * -report_kampfstatus(const unit * u, const struct locale * lang) -{ - static char fsbuf[64]; - - strlcpy(fsbuf, LOC(lang, combatstatus[u->status]), sizeof(fsbuf)); - if (fval(u, UFL_NOAID)) { - strcat(fsbuf, ", "); - strcat(fsbuf, LOC(lang, "status_noaid")); - } - - return fsbuf; -} - -const char * -hp_status(const unit * u) -{ - double p = (double) ((double) u->hp / (double) (u->number * unit_max_hp(u))); - - if (p > 2.00) return mkname("damage", "critical"); - if (p > 1.50) return mkname("damage", "heavily"); - if (p < 0.50) return mkname("damage", "badly"); - if (p < 0.75) return mkname("damage", "wounded"); - if (p < 0.99) return mkname("damage", "exhausted"); - - return NULL; -} - -void -report_item(const unit * owner, const item * i, const faction * viewer, const char ** name, const char ** basename, int * number, boolean singular) -{ - assert(!owner || owner->number); - if (owner && owner->faction == viewer) { - if (name) *name = locale_string(viewer->locale, resourcename(i->type->rtype, ((i->number!=1 && !singular)?GR_PLURAL:0))); - if (basename) *basename = resourcename(i->type->rtype, 0); - if (number) *number = i->number; - } else if (owner && i->type->rtype==r_silver) { - int pp = i->number/owner->number; - if (number) *number = 1; - if (pp > 50000 && dragonrace(owner->race)) { - if (name) *name = locale_string(viewer->locale, "dragonhoard"); - if (basename) *basename = "dragonhoard"; - } else if (pp > 5000) { - if (name) *name = locale_string(viewer->locale, "moneychest"); - if (basename) *basename = "moneychest"; - } else if (pp > 500) { - if (name) *name = locale_string(viewer->locale, "moneybag"); - if (basename) *basename = "moneybag"; - } else { - if (number) *number = 0; - if (name) *name = NULL; - if (basename) *basename = NULL; - } - } else { - if (name) *name = locale_string(viewer->locale, resourcename(i->type->rtype, NMF_APPEARANCE|((i->number!=1 && !singular)?GR_PLURAL:0))); - if (basename) *basename = resourcename(i->type->rtype, NMF_APPEARANCE); - if (number) { - if (fval(i->type, ITF_HERB)) *number = 1; - else *number = i->number; - } - } -} - - -int * nmrs = NULL; - -int -update_nmrs(void) -{ - int i, newplayers =0; - faction *f; - int turn = global.data_turn; - - if (nmrs==NULL) nmrs = malloc(sizeof(int)*(NMRTimeout()+1)); - for (i = 0; i <= NMRTimeout(); ++i) { - nmrs[i] = 0; - } - - for (f = factions; f; f = f->next) { - if (fval(f, FFL_ISNEW)) { - ++newplayers; - } else if (!is_monsters(f) && f->alive) { - int nmr = turn-f->lastorders+1; - if (nmr<0 || nmr>NMRTimeout()) { - log_error(("faction %s has %d NMRS\n", factionid(f), nmr)); - nmr = MAX(0, nmr); - nmr = MIN(nmr, NMRTimeout()); - } - ++nmrs[nmr]; - } - } - return newplayers; -} - -#define ORDERS_IN_NR 1 -static size_t -buforder(char * bufp, size_t size, const order * ord, int mode) -{ - size_t tsize = 0; - int bytes; - - bytes = (int)strlcpy(bufp, ", \"", size); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (mode1) { - *bufp++ ='\"'; - --size; - } else { - WARN_STATIC_BUFFER(); - } - ++tsize; - - return tsize; -} - -/** create a report of a list of items to a non-owner. - * \param result: an array of size items. - * \param size: maximum number of items to return - * \param owner: the owner of the items, or NULL for faction::items etc. - * \param viewer: the faction looking at the items - */ -int -report_items(const item * items, item * result, int size, const unit * owner, const faction * viewer) -{ - const item * itm; - int n = 0; /* number of results */ - - assert(owner==NULL || viewer!=owner->faction || !"not required for owner=viewer!"); - assert(size); - - for (itm=items;itm;itm=itm->next) { - item * ishow; - const char * ic; - - report_item(owner, itm, viewer, NULL, &ic, NULL, false); - if (ic && *ic) { - for (ishow = result; ishow!=result+n; ++ishow) { - const char * sc; - - if (ishow->type==itm->type) sc = ic; - else report_item(owner, ishow, viewer, NULL, &sc, NULL, false); - if (sc==ic || strcmp(sc, ic)==0) { - ishow->number+=itm->number; - break; - } - } - if (ishow==result+n) { - if (n==size) { - log_error(("too many items to report, increase buffer size.\n")); - return -1; - } - result[n].number = itm->number; - result[n].type = itm->type; - result[n].next = (n+1==size)?NULL:result+n+1; - ++n; - } - } - } - if (n>0) result[n-1].next = NULL; - return n; -} - -static void -report_resource(resource_report * result, const char * name, int number, int level) -{ - result->name = name; - result->number = number; - result->level = level; -} - -void -report_race(const struct unit * u, const char ** name, const char ** illusion) -{ - if (illusion) { - const race * irace = u_irace(u); - if (irace && irace!=u->race) { - *illusion = irace->_name[0]; - } - else { - *illusion = NULL; - } - } - if (name) { - *name = u->race->_name[0]; - if (fval(u->race, RCF_SHAPESHIFTANY)) { - const char * str = get_racename(u->attribs); - if (str) *name = str; - } - } -} - -void -report_building(const struct building * b, const char ** name, const char ** illusion) -{ - static int init; - static const struct building_type * bt_illusion; - - if (name) { - *name = buildingtype(b->type, b, b->size); - } - if (illusion) { - *illusion = NULL; - - if (!init) { - bt_illusion = bt_find("illusioncastle"); - init = 1; - } - if (bt_illusion && b->type==bt_illusion) { - const attrib * a = a_findc(b->attribs, &at_icastle); - if (a!=NULL) { - icastle_data * icastle = (icastle_data*)a->data.v; - *illusion = buildingtype(icastle->type, b, b->size); - } - } - } -} - -int -report_resources(const seen_region * sr, resource_report * result, int size, const faction * viewer) -{ - const region * r = sr->r; - int n = 0; - - if (r->land) { - int peasants = rpeasants(r); - int money = rmoney(r); - int horses = rhorses(r); - int trees = rtrees(r, 2); - int saplings = rtrees(r, 1); - boolean mallorn = fval(r, RF_MALLORN)!=0; - - if (money) { - if (n>=size) return -1; - report_resource(result+n, "rm_money", money, -1); - ++n; - } - if (peasants) { - if (n>=size) return -1; - report_resource(result+n, "rm_peasant", peasants, -1); - ++n; - } - if (horses) { - if (n>=size) return -1; - report_resource(result+n, "rm_horse", horses, -1); - ++n; - } - if (saplings) { - if (n>=size) return -1; - report_resource(result+n, mallorn?"rm_mallornsapling":"rm_sapling", saplings, -1); - ++n; - } - if (trees) { - if (n>=size) return -1; - report_resource(result+n, mallorn?"rm_mallorn":"rm_tree", trees, -1); - ++n; - } - } - - if (sr->mode>=see_unit) { - rawmaterial * res = r->resources; - while (res) { - int maxskill = 0; - const item_type * itype = resource2item(res->type->rtype); - int level = res->level + itype->construction->minskill - 1; - int visible = -1; - if (res->type->visible==NULL) { - visible = res->amount; - level = res->level + itype->construction->minskill - 1; - } else { - const unit * u; - for (u=r->units; visible!=res->amount && u!=NULL; u=u->next) { - if (u->faction == viewer) { - int s = eff_skill(u, itype->construction->skill, r); - if (s>maxskill) { - maxskill = s; - visible = res->type->visible(res, maxskill); - } - } - } - } - if (level>=0 && visible>=0) { - if (n>=size) return -1; - report_resource(result+n, res->type->name, visible, level); - n++; - } - res = res->next; - } - } - return n; -} - -int -bufunit(const faction * f, const unit * u, int indent, int mode, char * buf, size_t size) -{ - int i, dh; - int getarnt = fval(u, UFL_ANON_FACTION); - const char *pzTmp, *str; - building * b; - boolean isbattle = (boolean)(mode == see_battle); - int telepath_see = 0; - attrib *a_fshidden = NULL; - item * itm; - item * show; - faction *fv = visible_faction(f, u); - char * bufp = buf; - boolean itemcloak = false; - static const curse_type * itemcloak_ct = 0; - static boolean init = false; - int bytes; - item result[MAX_INVENTORY]; - - if (!init) { - init = true; - itemcloak_ct = ct_find("itemcloak"); - } - if (itemcloak_ct!=NULL) { - itemcloak = curse_active(get_curse(u->attribs, itemcloak_ct)); - } - - bytes = (int)strlcpy(bufp, unitname(u), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (!isbattle) { - attrib *a_otherfaction = a_find(u->attribs, &at_otherfaction); - if (u->faction == f) { - if (fval(u, UFL_GROUP)) { - attrib *a = a_find(u->attribs, &at_group); - if (a) { - group * g = (group*)a->data.v; - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, groupid(g, f), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - if (getarnt) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, "anonymous"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else if (a_otherfaction) { - faction * otherfaction = get_otherfaction(a_otherfaction); - if (otherfaction) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, factionname(otherfaction), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - } else { - if (getarnt) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, "anonymous"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else { - if (a_otherfaction && alliedunit(u, f, HELP_FSTEALTH)) { - faction * f = get_otherfaction(a_otherfaction); - bytes = snprintf(bufp, size, ", %s (%s)", factionname(f), factionname(u->faction)); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, factionname(fv), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - } - } - - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (u->faction != f && a_fshidden && a_fshidden->data.ca[0] == 1 && effskill(u, SK_STEALTH) >= 6) { - bytes = (int)strlcpy(bufp, "? ", size); - } else { - bytes = snprintf(bufp, size, "%d ", u->number); - } - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - pzTmp = get_racename(u->attribs); - if (pzTmp) { - bytes = (int)strlcpy(bufp, pzTmp, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (u->faction==f && fval(u->race, RCF_SHAPESHIFTANY)) { - bytes = (int)strlcpy(bufp, " (", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, racename(f->locale, u, u->race), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (size>1) { - strcpy(bufp++, ")"); - --size; - } - } - } else { - const race * irace = u_irace(u); - bytes = (int)strlcpy(bufp, racename(f->locale, u, irace), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (u->faction==f && irace!=u->race) { - bytes = (int)strlcpy(bufp, " (", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, racename(f->locale, u, u->race), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (size>1) { - strcpy(bufp++, ")"); - --size; - } - } - } - - if (fval(u, UFL_HERO) && (u->faction == f || omniscient(f))) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, "hero"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - /* status */ - - if (u->number && (u->faction == f || telepath_see || isbattle)) { - const char * c = locale_string(f->locale, hp_status(u)); - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, report_kampfstatus(u, f->locale), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (c || fval(u, UFL_HUNGER)) { - bytes = (int)strlcpy(bufp, " (", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (c) { - bytes = (int)strlcpy(bufp, c, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (fval(u, UFL_HUNGER)) { - if (c) bytes = (int)strlcpy(bufp, ", hungert", size); - else bytes = (int)strlcpy(bufp, "hungert", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - if (size>1) { - strcpy(bufp++, ")"); - --size; - } - } - } - if (is_guard(u, GUARD_ALL)!=0) { - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, "unit_guards"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - - if ((b = usiege(u))!=NULL) { - bytes = (int)strlcpy(bufp, ", belagert ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, buildingname(b), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - - dh = 0; - if (u->faction == f || telepath_see) { - skill * sv; - for (sv = u->skills;sv!=u->skills+u->skill_size;++sv) { - bytes = (int)spskill(bufp, size, f->locale, u, sv, &dh, 1); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - - dh = 0; - if (f == u->faction || telepath_see || omniscient(f)) { - show = u->items; - } else if (!itemcloak && mode >= see_unit && !(a_fshidden - && a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) - { - int n = report_items(u->items, result, MAX_INVENTORY, u, f); - assert(n>=0); - if (n>0) show = result; - else show = NULL; - } else { - show = NULL; - } - for (itm=show; itm; itm=itm->next) { - const char * ic; - int in, bytes; - report_item(u, itm, f, &ic, NULL, &in, false); - if (in==0 || ic==NULL) continue; - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (!dh) { - bytes = snprintf(bufp, size, "%s: ", LOC(f->locale, "nr_inventory")); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - dh = 1; - } - if (in == 1) { - bytes = (int)strlcpy(bufp, ic, size); - } else { - bytes = snprintf(bufp, size, "%d %s", in, ic); - } - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - - if (u->faction == f || telepath_see) { - sc_mage * m = get_mage(u); - - if (m!=NULL) { - spell_list *slist = m->spells; - int t = effskill(u, SK_MAGIC); - int bytes = snprintf(bufp, size, ". Aura %d/%d", get_spellpoints(u), max_spellpoints(u->region,u)); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - for (dh=0; slist; slist=slist->next) { - spell * sp = slist->data; - if (sp->level > t) continue; - if (!dh) { - bytes = snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_spells")); - dh = 1; - } else { - bytes = (int)strlcpy(bufp, ", ", size); - } - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, spell_name(sp, f->locale), size); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - - for (i=0; i!=MAXCOMBATSPELLS; ++i) { - if (get_combatspell(u, i)) break; - } - if (i!=MAXCOMBATSPELLS) { - bytes = snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_combatspells")); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - dh = 0; - for (i = 0; i < MAXCOMBATSPELLS; i++){ - const spell *sp; - if (!dh){ - dh = 1; - } else { - bytes = (int)strlcpy(bufp, ", ", size); - if (bytes && wrptr(&bufp, &size, bytes)!=0) { - WARN_STATIC_BUFFER(); - } - } - sp = get_combatspell(u,i); - if (sp) { - int sl = get_combatspelllevel(u, i); - bytes = (int)strlcpy(bufp, spell_name(sp, u->faction->locale), size); - if (bytes && wrptr(&bufp, &size, bytes)!=0) { - WARN_STATIC_BUFFER(); - } - - if (sl > 0) { - bytes = snprintf(bufp, size, " (%d)", sl); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } else { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nospells"), size); - if (bytes && wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - } - } - if (!isbattle) { - boolean printed = 0; - order * ord;; - for (ord=u->old_orders;ord;ord=ord->next) { - if (is_repeated(ord)) { - if (printedorders;ord;ord=ord->next) { - if (is_repeated(ord)) { - if (printedlocale); - if (str) { - bytes = (int)strlcpy(bufp, "; ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - bytes = (int)strlcpy(bufp, str, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - i = str[strlen(str) - 1]; - } - if (i != '!' && i != '?' && i != '.') { - if (size>1) { - strcpy(bufp++, "."); - --size; - } - } - pzTmp = uprivate(u); - if (u->faction == f && pzTmp) { - bytes = (int)strlcpy(bufp, " (Bem: ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, pzTmp, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, ")", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - - dh=0; - if (!getarnt && f) { - if (alliedfaction(rplane(u->region), f, fv, HELP_ALL)) { - dh = 1; - } - } - if (size<=1) { - log_warning(("bufunit ran out of space after writing %u bytes.\n", (bufp-buf))); - } - return dh; -} - -/* TODO: telepath_see wird nicht berücksichtigt: Parteien mit - * telepath_see sollten immer einzelne Einheiten zu sehen - * bekommen, alles andere ist darstellungsteschnisch kompliziert. - */ - -size_t -spskill(char * buffer, size_t size, const struct locale * lang, const struct unit * u, struct skill * sv, int *dh, int days) -{ - char * bufp = buffer; - int i, effsk; - int bytes; - size_t tsize = 0; - - if (!u->number) return 0; - if (sv->level<=0) { - if (sv->old<=0 || (u->faction->options & want(O_SHOWSKCHANGE))==0) { - return 0; - } - } - - bytes = (int)strlcpy(bufp, ", ", size); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (!*dh) { - bytes = (int)strlcpy(bufp, LOC(lang, "nr_skills"), size); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - bytes = (int)strlcpy(bufp, ": ", size); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - *dh = 1; - } - bytes = (int)strlcpy(bufp, skillname(sv->id, lang), size); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - bytes = (int)strlcpy(bufp, " ", size); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (sv->id == SK_MAGIC){ - sc_mage * mage = get_mage(u); - if (mage && mage->magietyp != M_GRAY) { - bytes = (int)strlcpy(bufp, LOC(lang, mkname("school", magic_school[mage->magietyp])), size); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - bytes = (int)strlcpy(bufp, " ", size); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - - if (sv->id == SK_STEALTH && fval(u, UFL_STEALTH)) { - i = u_geteffstealth(u); - if (i>=0) { - bytes = slprintf(bufp, size, "%d/", i); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - - effsk = effskill(u, sv->id); - bytes = slprintf(bufp, size, "%d", effsk); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (u->faction->options & want(O_SHOWSKCHANGE)) { - int oldeff = 0; - int diff; - - if (sv->old > 0) { - oldeff = sv->old + get_modifier(u, sv->id, sv->old, u->region, false); - } - - oldeff = MAX(0, oldeff); - diff = effsk - oldeff; - - if (diff != 0) { - bytes = slprintf(bufp, size, " (%s%d)", (diff>0)?"+":"", diff); - tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } - return tsize; -} - -void -lparagraph(struct strlist ** SP, char *s, int indent, char mark) -{ - - /* Die Liste SP wird mit dem String s aufgefuellt, mit indent und einer - * mark, falls angegeben. SP wurde also auf 0 gesetzt vor dem Aufruf. - * Vgl. spunit (). */ - - char *buflocal = calloc(strlen(s) + indent + 1, sizeof(char)); - - if (indent) { - memset(buflocal, ' ', indent); - if (mark) - buflocal[indent - 2] = mark; - } - strcpy(buflocal + indent, s); - addstrlist(SP, buflocal); - free(buflocal); -} - -void -spunit(struct strlist ** SP, const struct faction * f, const unit * u, int indent, - int mode) -{ - char buf[DISPLAYSIZE]; - int dh = bufunit(f, u, indent, mode, buf, sizeof(buf)); - lparagraph(SP, buf, indent, (char) ((u->faction == f) ? '*' : (dh ? '+' : '-'))); -} - -struct message * -msg_curse(const struct curse * c, const void * obj, typ_t typ, int self) -{ - if (c->type->curseinfo) { - /* if curseinfo returns NULL, then we don't want to tell the viewer anything. */ - return c->type->curseinfo(obj, typ, c, self); - } else { - message * msg = cinfo_simple(obj, typ, c, self); - if (msg==NULL) { - const char * unknown[] = { "unit_unknown", "region_unknown", "building_unknown", "ship_unknown" }; - msg = msg_message(mkname("curseinfo", unknown[typ]), "id", c->no); - log_error(("no curseinfo function for %s and no fallback either.\n", c->type->cname)); - } else { - log_error(("no curseinfo function for %s, using cinfo_simple fallback.\n", c->type->cname)); - } - return msg; - } -} - -const struct unit * -ucansee(const struct faction *f, const struct unit *u, const struct unit *x) -{ - if (cansee(f, u->region, u, 0)) return u; - return x; -} - -static void -add_faction(faction_list ** flist, faction * sf) -{ - faction_list ** fnew = flist; - while (*fnew && (*fnew)->data->no < sf->no) { - fnew =&(*fnew)->next; - } - if ((*fnew==NULL) || (*fnew)->data!=sf) { - faction_list * finsert = malloc(sizeof(faction_list)); - finsert->next = *fnew; - *fnew = finsert; - finsert->data = sf; - } -} - -int -stealth_modifier(int seen_mode) -{ - switch (seen_mode) { - case see_unit: - return 0; - case see_far: - case see_lighthouse: - return -2; - case see_travel: - return -1; - default: - return INT_MIN; - } -} - -static void -get_addresses(report_context * ctx) -{ -/* "TODO: travelthru" */ - seen_region * sr = NULL; - region *r; - const faction * lastf = NULL; - faction_list * flist = calloc(1, sizeof(faction_list)); - - flist->data = ctx->f; - - if (f_get_alliance(ctx->f)) { - faction_list * member = ctx->f->alliance->members; - for (;member;member=member->next) { - add_faction(&flist, member->data); - } - } - - for (r=ctx->first;sr==NULL && r!=ctx->last;r=r->next) { - sr = find_seen(ctx->seen, r); - } - - for (;sr!=NULL;sr=sr->next) { - int stealthmod = stealth_modifier(sr->mode); - r = sr->r; - if (sr->mode==see_lighthouse) { - unit * u = r->units; - for (;u;u=u->next) { - faction * sf = visible_faction(ctx->f, u); - if (lastf!=sf) { - if (u->building || u->ship || (stealthmod>INT_MIN && cansee(ctx->f, r, u, stealthmod))) { - add_faction(&flist, sf); - lastf = sf; - } - } - } - } else if (sr->mode==see_travel) { - unit * u = r->units; - while (u) { - faction * sf = visible_faction(ctx->f, u); - assert(u->faction!=ctx->f); /* if this is see_travel only, then I shouldn't be here. */ - if (lastf!=sf) { - attrib * a = a_find(r->attribs, &at_travelunit); - while (a && a->type==&at_travelunit) { - unit * u2 = (unit*)a->data.v; - if (u2->faction==ctx->f) { - if (cansee_unit(u2, u, stealthmod)) { - add_faction(&flist, sf); - lastf = sf; - break; - } - } - a = a->next; - } - } - u = u->next; - } - } else if (sr->mode>see_travel) { - const unit * u = r->units; - while (u!=NULL) { - if (u->faction!=ctx->f) { - faction * sf = visible_faction(ctx->f, u); - boolean ballied = sf && sf!=ctx->f && sf!=lastf - && !fval(u, UFL_ANON_FACTION) && cansee(ctx->f, r, u, stealthmod); - if (ballied || ALLIED(ctx->f, sf)) { - add_faction(&flist, sf); - lastf = sf; - } - } - u = u->next; - } - } - } - - if (f_get_alliance(ctx->f)) { - faction *f2; - for (f2 = factions; f2; f2 = f2->next) { - if (f2->alliance == ctx->f->alliance) { - add_faction(&flist, f2); - } - } - } - ctx->addresses = flist; -} - -#define MAXSEEHASH 0x1000 -seen_region * reuse; - -seen_region ** -seen_init(void) -{ - return (seen_region **)calloc(MAXSEEHASH, sizeof(seen_region*)); -} - -void -seen_done(seen_region * seehash[]) -{ - int i; - for (i=0;i!=MAXSEEHASH;++i) { - seen_region * sd = seehash[i]; - if (sd==NULL) continue; - while (sd->nextHash!=NULL) sd = sd->nextHash; - sd->nextHash = reuse; - reuse = seehash[i]; - seehash[i] = NULL; - } - // free(seehash); -} - -void -free_seen(void) -{ - while (reuse) { - seen_region * r = reuse; - reuse = reuse->nextHash; - free(r); - } -} - -void -link_seen(seen_region * seehash[], const region * first, const region * last) -{ - const region * r = first; - seen_region * sr = NULL; - - if (first==last) return; - - do { - sr = find_seen(seehash, r); - r = r->next; - } while (sr==NULL && r!=last); - - while (r!=last) { - seen_region * sn = find_seen(seehash, r); - if (sn!=NULL) { - sr->next = sn; - sr = sn; - } - r = r->next; - } - sr->next = 0; -} - -seen_region * -find_seen(struct seen_region * seehash[], const region * r) -{ - unsigned int index = reg_hashkey(r) & (MAXSEEHASH-1); - seen_region * find = seehash[index]; - while (find) { - if (find->r==r) return find; - find=find->nextHash; - } - return NULL; -} - -static void -get_seen_interval(report_context * ctx) -{ - /* this is required to find the neighbour regions of the ones we are in, - * which may well be outside of [firstregion, lastregion) */ - int i; - for (i=0;i!=MAXSEEHASH;++i) { - seen_region * sr = ctx->seen[i]; - while (sr!=NULL) { - if (ctx->first==NULL || sr->r->indexfirst->index) { - ctx->first = sr->r; - } - if (ctx->last!=NULL && sr->r->index>=ctx->last->index) { - ctx->last = sr->r->next; - } - sr = sr->nextHash; - } - } - link_seen(ctx->seen, ctx->first, ctx->last); -} - -boolean -add_seen(struct seen_region * seehash[], struct region * r, unsigned char mode, boolean dis) -{ - seen_region * find = find_seen(seehash, r); - if (find==NULL) { - unsigned int index = reg_hashkey(r) & (MAXSEEHASH-1); - if (!reuse) reuse = (seen_region*)calloc(1, sizeof(struct seen_region)); - find = reuse; - reuse = reuse->nextHash; - find->nextHash = seehash[index]; - seehash[index] = find; - find->r = r; - } else if (find->mode >= mode) { - return false; - } - find->mode = mode; - find->disbelieves |= dis; - return true; -} - -typedef struct report_type { - struct report_type * next; - report_fun write; - const char * extension; - int flag; -} report_type; - -static report_type * report_types; - -void -register_reporttype(const char * extension, report_fun write, int flag) -{ - report_type * type = malloc(sizeof(report_type)); - type->extension = extension; - type->write = write; - type->flag = flag; - type->next = report_types; - report_types = type; -} - -static region_list * -get_regions_distance(region * root, int radius) -{ - region_list * rptr, * rlist = NULL; - region_list ** rp = &rlist; - add_regionlist(rp, root); - fset(root, RF_MARK); - while (*rp) { - region_list * r = *rp; - direction_t d; - rp = &r->next; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(r->data, d); - if (rn!=NULL && !fval(rn, RF_MARK) && distance(rn, root)<=radius) { - add_regionlist(rp, rn); - fset(rn, RF_MARK); - } - } - } - for (rptr=rlist;rptr;rptr=rptr->next) { - freset(rptr->data, RF_MARK); - } - return rlist; -} - -static void -view_default(struct seen_region ** seen, region *r, faction *f) -{ - direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * r2 = rconnect(r, dir); - if (r2) { - connection * b = get_borders(r, r2); - while (b) { - if (!b->type->transparent(b, f)) break; - b = b->next; - } - if (!b) add_seen(seen, r2, see_neighbour, false); - } - } -} - -static void -view_neighbours(struct seen_region ** seen, region * r, faction * f) -{ - direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * r2 = rconnect(r, dir); - if (r2) { - connection * b = get_borders(r, r2); - while (b) { - if (!b->type->transparent(b, f)) break; - b = b->next; - } - if (!b) { - if (add_seen(seen, r2, see_far, false)) { - if (!(fval(r2->terrain, FORBIDDEN_REGION))) { - direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * r3 = rconnect(r2, dir); - if (r3) { - connection * b = get_borders(r2, r3); - while (b) { - if (!b->type->transparent(b, f)) break; - b = b->next; - } - if (!b) add_seen(seen, r3, see_neighbour, false); - } - } - } - } - } - } - } -} - -static void -recurse_regatta(struct seen_region ** seen, region *center, region *r, faction *f, int maxdist) -{ - direction_t dir; - int dist = distance(center, r); - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * r2 = rconnect(r, dir); - if (r2) { - int ndist = distance(center, r2); - if (ndist>dist && fval(r2->terrain, SEA_REGION)) { - connection * b = get_borders(r, r2); - while (b) { - if (!b->type->transparent(b, f)) break; - b = b->next; - } - if (!b) { - if (ndistunits; u; u=u->next) { - if (u->faction==f) { - int es = effskill(u, SK_PERCEPTION); - if (es>skill) skill=es; - } - } - recurse_regatta(seen, r, r, f, skill/2); -} - -static void -prepare_reports(void) -{ - region * r; - faction * f; - static const struct building_type * bt_lighthouse = NULL; - if (bt_lighthouse==NULL) bt_lighthouse = bt_find("lighthouse"); - - for (f = factions; f ; f = f->next) { - if (f->seen) seen_done(f->seen); - f->seen = seen_init(); - } - - for (r = regions; r ; r = r->next) { - attrib *ru; - unit * u; - plane * p = rplane(r); - - reorder_units(r); - - if (p) { - watcher * w = p->watchers; - for (;w;w=w->next) { - add_seen(w->faction->seen, r, w->mode, false); -#ifdef SMART_INTERVALS - update_interval(w->faction, r); -#endif - } - } - - for (u = r->units; u; u = u->next) { - if (u->building && u->building->type==bt_lighthouse) { - /* we are in a lighthouse. add the regions we can see from here! */ - int range = lighthouse_range(u->building, u->faction); - region_list * rlist = get_regions_distance(r, range); - region_list * rp = rlist; - - while (rp) { - region * rl = rp->data; - if (fval(rl->terrain, SEA_REGION)) { - direction_t d; - add_seen(u->faction->seen, rl, see_lighthouse, false); - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(rl, d); - if (rn!=NULL) { - add_seen(u->faction->seen, rn, see_neighbour, false); - } - } - } - rp = rp->next; - } - free_regionlist(rlist); - } - - if (u->race != new_race[RC_SPELL] || u->number == RS_FARVISION) { - if (fval(u, UFL_DISBELIEVES)) { - add_seen(u->faction->seen, r, see_unit, true); - } else { - add_seen(u->faction->seen, r, see_unit, false); - } - } - } - - if (fval(r, RF_TRAVELUNIT)) { - for (ru = a_find(r->attribs, &at_travelunit); ru && ru->type==&at_travelunit; ru = ru->next) { - unit * u = (unit*)ru->data.v; - - /* make sure the faction has not been removed this turn: */ - if (u->faction) { - add_seen(u->faction->seen, r, see_travel, false); - } - } - } - } -} - -static seen_region ** -prepare_report(faction * f) -{ - struct seen_region * sr; - region * r = firstregion(f); - region * last = lastregion(f); - - link_seen(f->seen, r, last); - - for (sr=NULL; sr==NULL && r!=last; r=r->next) { - sr = find_seen(f->seen, r); - } - - for (;sr!=NULL;sr=sr->next) { - if (sr->mode>see_neighbour) { - region * r = sr->r; - plane * p = rplane(r); - - void (*view)(struct seen_region **, region *, faction *) = view_default; - if (p && fval(p, PFL_SEESPECIAL)) { - attrib * a = a_find(p->attribs, &at_viewrange); - if (a) view = (void (*)(struct seen_region **, region *, faction *))a->data.f; - } - view(f->seen, r, f); - } - } - return f->seen; -} - -int -write_reports(faction * f, time_t ltime) -{ - int backup = 1, maxbackup = 128; - boolean gotit = false; - struct report_context ctx; - const char * encoding = "UTF-8"; - - if (noreports) { - return false; - } - ctx.f = f; - ctx.report_time = time(NULL); - ctx.seen = prepare_report(f); - ctx.first = firstregion(f); - ctx.last = lastregion(f); - ctx.addresses = NULL; - ctx.userdata = NULL; - get_seen_interval(&ctx); - get_addresses(&ctx); - - do { - report_type * rtype = report_types; - - errno = 0; - if (verbosity>=2) { - log_stdio(stdout, "Reports for %s:", factionname(f)); - } - for (;rtype!=NULL;rtype=rtype->next) { - if (f->options & rtype->flag) { - char filename[MAX_PATH]; - sprintf(filename, "%s/%d-%s.%s", reportpath(), turn, factionid(f), rtype->extension); - if (rtype->write(filename, &ctx, encoding)==0) { - gotit = true; - } - } - } - - if (errno) { - char zText[64]; - puts(" ERROR"); - sprintf(zText, "Waiting %u seconds before retry", backup); - perror(zText); - sleep(backup); - if (backup=2) { - puts(" DONE"); - } - } while (errno); - if (!gotit) { - log_warning(("No report for faction %s!\n", factionid(f))); - } - freelist(ctx.addresses); - seen_done(ctx.seen); - return 0; -} - -static void -nmr_warnings(void) -{ - faction *f,*fa; -#define FRIEND (HELP_GUARD|HELP_MONEY) - for (f=factions;f;f=f->next) { - if (!is_monsters(f) && (turn-f->lastorders) >= 2) { - message * msg = NULL; - for (fa=factions;fa;fa=fa->next) { - int warn = 0; - if (get_param_int(global.parameters, "rules.alliances", 0)!=0) { - if (f->alliance && f->alliance==fa->alliance) { - warn = 1; - } - } else if (alliedfaction(NULL, f, fa, FRIEND) && alliedfaction(NULL, fa, f, FRIEND)) { - warn = 1; - } - if (warn) { - if (msg==NULL) { - msg = msg_message("warn_dropout", "faction turns", f, turn - f->lastorders); - } - add_message(&fa->msgs, msg); - } - } - if (msg!=NULL) msg_release(msg); - } - } -} - -static void -report_donations(void) -{ - region * r; - for (r=regions;r;r=r->next) { - while (r->donations) { - donation * sp = r->donations; - if (sp->amount > 0) { - struct message * msg = msg_message("donation", - "from to amount", sp->f1, sp->f2, sp->amount); - r_addmessage(r, sp->f1, msg); - r_addmessage(r, sp->f2, msg); - msg_release(msg); - } - r->donations = sp->next; - free(sp); - } - } -} - -static void -write_script(FILE * F, const faction * f) -{ - report_type * rtype; - char buf[1024]; - - fprintf(F, "faction=%s:email=%s:lang=%s", factionid(f), f->email, locale_name(f->locale)); - if (f->options & (1<extension); - } - } - fputs(buf, F); - fputc('\n', F); -} - -int -init_reports(void) -{ - prepare_reports(); -#ifdef HAVE_STAT - { - stat_type st; - if (stat(reportpath(), &st)==0) return 0; - } -#endif - if (makedir(reportpath(), 0700)!=0) { - if (errno!=EEXIST) { - perror("could not create reportpath"); - return -1; - } - } - return 0; -} - -int -reports(void) -{ - faction *f; - FILE *mailit; - time_t ltime = time(NULL); - const char * str; - int retval = 0; - char path[MAX_PATH]; - - if (verbosity>=1) { - log_stdio(stdout, "Writing reports for turn %d:", turn); - } - nmr_warnings(); - report_donations(); - remove_empty_units(); - - sprintf(path, "%s/reports.txt", reportpath()); - mailit = fopen(path, "w"); - if (mailit == NULL) { - log_error(("%s could not be opened!\n", path)); - } - - for (f = factions; f; f = f->next) { - int error = write_reports(f, ltime); - if (error) retval = error; - if (mailit) write_script(mailit, f); - } - if (mailit) fclose(mailit); - free_seen(); - str = get_param(global.parameters, "globalreport"); -#ifdef GLOBAL_REPORT - if (str!=NULL) { - sprintf(path, "%s/%s.%u.cr", reportpath(), str, turn); - global_report(path); - } -#endif - return retval; -} - -static variant -var_copy_string(variant x) -{ - x.v = strdup((const char*)x.v); - return x; -} - -static void -var_free_string(variant x) -{ - free(x.v); -} - -static variant -var_copy_order(variant x) -{ - x.v = copy_order((order*)x.v); - return x; -} - -static void -var_free_order(variant x) -{ - free_order(x.v); -} - -static variant -var_copy_items(variant x) -{ - item * isrc; - resource * rdst = NULL, ** rptr = &rdst; - - for (isrc = (item*)x.v; isrc!=NULL; isrc=isrc->next) { - resource * res = malloc(sizeof(resource)); - res->number = isrc->number; - res->type = isrc->type->rtype; - *rptr = res; - rptr = &res->next; - } - *rptr = NULL; - x.v = rdst; - return x; -} - -static void -var_free_resources(variant x) -{ - resource * rsrc = (resource*)x.v; - while (rsrc) { - resource * res = rsrc->next; - free(rsrc); - rsrc = res; - } - x.v = 0; -} - -static void -var_free_regions(variant x) -{ - free(x.v); -} - -const char * -trailinto(const region * r, const struct locale * lang) -{ - char ref[32]; - const char * s; - if (r) { - const char * tname = terrain_name(r); - strcat(strcpy(ref, tname), "_trail"); - s = locale_string(lang, ref); - if (s && *s) { - if (strstr(s, "%s")) return s; - } - } - return "%s"; -} - -size_t -f_regionid(const region * r, const faction * f, char * buffer, size_t size) -{ - if (!r) { - strncpy(buffer, "(Chaos)", size); - } else { - plane * pl = rplane(r); - const char * name = pl?pl->name:0; - int nx = r->x, ny = r->y; - pnormalize(&nx, &ny, pl); - adjust_coordinates(f, &nx, &ny, pl, r); - strncpy(buffer, rname(r, f->locale), size); - buffer[size-1]=0; - sprintf(buffer+strlen(buffer), " (%d,%d%s%s)", nx, ny, name?",":"", (name)?name:""); - } - return strlen(buffer); -} - -static char * -f_regionid_s(const region * r, const faction * f) -{ - static int i = 0; - static char bufs[4][NAMESIZE + 20]; - char * buf = bufs[(++i)%4]; - - f_regionid(r, f, buf, NAMESIZE + 20); - return buf; -} - -/*** BEGIN MESSAGE RENDERING ***/ -static void -eval_localize(struct opstack ** stack, const void * userdata) /* (string, locale) -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct locale * lang = f?f->locale:default_locale; - const char *c = (const char *)opop_v(stack); - c = locale_string(lang, c); - opush_v(stack, strcpy(balloc(strlen(c)+1), c)); -} - -static void -eval_trailto(struct opstack ** stack, const void * userdata) /* (int, int) -> int */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct locale * lang = f?f->locale:default_locale; - const struct region * r = (const struct region*)opop(stack).v; - const char * trail = trailinto(r, lang); - const char * rn = f_regionid_s(r, f); - variant var; - char * x = var.v = balloc(strlen(trail)+strlen(rn)); - sprintf(x, trail, rn); - opush(stack, var); -} - -static void -eval_unit(struct opstack ** stack, const void * userdata) /* unit -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct unit * u = (const struct unit *)opop(stack).v; - const char * c = u?unitname(u):LOC(f->locale, "an_unknown_unit"); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_unit_dative(struct opstack ** stack, const void * userdata) /* unit -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct unit * u = (const struct unit *)opop(stack).v; - const char * c = u?unitname(u):LOC(f->locale, "unknown_unit_dative"); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_spell(struct opstack ** stack, const void * userdata) /* unit -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct spell * sp = (const struct spell *)opop(stack).v; - const char * c = sp?spell_name(sp, f->locale):LOC(f->locale, "an_unknown_spell"); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_curse(struct opstack ** stack, const void * userdata) /* unit -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct curse_type * sp = (const struct curse_type *)opop(stack).v; - const char * c = sp?curse_name(sp, f->locale):LOC(f->locale, "an_unknown_curse"); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_unitname(struct opstack ** stack, const void * userdata) /* unit -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct unit * u = (const struct unit *)opop(stack).v; - const char * c = u?u->name:LOC(f->locale, "an_unknown_unit"); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - - -static void -eval_unitid(struct opstack ** stack, const void * userdata) /* unit -> int */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct unit * u = (const struct unit *)opop(stack).v; - const char * c = u?u->name:LOC(f->locale, "an_unknown_unit"); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_unitsize(struct opstack ** stack, const void * userdata) /* unit -> int */ -{ - const struct unit * u = (const struct unit *)opop(stack).v; - variant var; - - var.i = u->number; - opush(stack, var); -} - -static void -eval_faction(struct opstack ** stack, const void * userdata) /* faction -> string */ -{ - const struct faction * f = (const struct faction *)opop(stack).v; - const char * c = factionname(f); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_alliance(struct opstack ** stack, const void * userdata) /* faction -> string */ -{ - const struct alliance * al = (const struct alliance *)opop(stack).v; - const char * c = alliancename(al); - variant var; - if (c!=NULL) { - size_t len = strlen(c); - var.v = strcpy(balloc(len+1), c); - } - else var.v = NULL; - opush(stack, var); -} - -static void -eval_region(struct opstack ** stack, const void * userdata) /* region -> string */ -{ - char name[NAMESIZE+32]; - const struct faction * f = (const struct faction *)userdata; - const struct region * r = (const struct region *)opop(stack).v; - const char * c = write_regionname(r, f, name, sizeof(name)); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_terrain(struct opstack ** stack, const void * userdata) /* region -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct region * r = (const struct region *)opop(stack).v; - const char * c = LOC(f->locale, terrain_name(r)); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_ship(struct opstack ** stack, const void * userdata) /* ship -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct ship * u = (const struct ship *)opop(stack).v; - const char * c = u?shipname(u):LOC(f->locale, "an_unknown_ship"); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_building(struct opstack ** stack, const void * userdata) /* building -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct building * u = (const struct building *)opop(stack).v; - const char * c = u?buildingname(u):LOC(f->locale, "an_unknown_building"); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_weight(struct opstack ** stack, const void * userdata) /* region -> string */ -{ - char buffer[32]; - const struct faction * f = (const struct faction *)userdata; - const struct locale * lang = f->locale; - int weight = opop_i(stack); - variant var; - - if (weight % SCALEWEIGHT == 0) { - if (weight==SCALEWEIGHT) { - sprintf(buffer, "1 %s", LOC(lang, "weight_unit")); - } else { - sprintf(buffer, "%u %s", weight/SCALEWEIGHT, LOC(lang, "weight_unit_p")); - } - } else { - if (weight==1) { - sprintf(buffer, "1 %s %u", LOC(lang, "weight_per"), SCALEWEIGHT); - } else { - sprintf(buffer, "%u %s %u", weight, LOC(lang, "weight_per_p"), SCALEWEIGHT); - } - } - - var.v = strcpy(balloc(strlen(buffer)+1), buffer); - opush(stack, var); -} - -static void -eval_resource(struct opstack ** stack, const void * userdata) -{ - const faction * report = (const faction*)userdata; - const struct locale * lang = report?report->locale:default_locale; - int j = opop(stack).i; - const struct resource_type * res = (const struct resource_type *)opop(stack).v; - const char * c = LOC(lang, resourcename(res, j!=1)); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_race(struct opstack ** stack, const void * userdata) -{ - const faction * report = (const faction*)userdata; - const struct locale * lang = report?report->locale:default_locale; - int j = opop(stack).i; - const race * r = (const race *)opop(stack).v; - const char * c = LOC(lang, rc_name(r, j!=1)); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_order(struct opstack ** stack, const void * userdata) /* order -> string */ -{ - const struct order * ord = (const struct order *)opop(stack).v; - static char buf[256]; - size_t len; - variant var; - - unused(userdata); - write_order(ord, buf, sizeof(buf)); - len = strlen(buf); - var.v = strcpy(balloc(len+1), buf); - opush(stack, var); -} - -static void -eval_resources(struct opstack ** stack, const void * userdata) /* order -> string */ -{ - const faction * report = (const faction*)userdata; - const struct locale * lang = report?report->locale:default_locale; - const struct resource * res = (const struct resource *)opop(stack).v; - static char buf[1024]; /* but we only use about half of this */ - size_t size = sizeof(buf) - 1; - variant var; - - char * bufp = buf; - while (res!=NULL && size > 4) { - const char * rname = resourcename(res->type, (res->number!=1)?NMF_PLURAL:0); - int bytes = snprintf(bufp, size, "%d %s", res->number, LOC(lang, rname)); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0 || sizenext; - if (res!=NULL && size>2) { - strcat(bufp, ", "); - bufp += 2; - size -= 2; - } - } - *bufp = 0; - var.v = strcpy(balloc(bufp-buf+1), buf); - opush(stack, var); -} - -static void -eval_regions(struct opstack ** stack, const void * userdata) /* order -> string */ -{ - const faction * report = (const faction*)userdata; - int i = opop(stack).i; - int end, begin = opop(stack).i; - const arg_regions * regions = (const arg_regions *)opop(stack).v; - static char buf[256]; - size_t size = sizeof(buf) - 1; - variant var; - char * bufp = buf; - - if (regions==NULL) { - end = begin; - } else { - if (i>=0) end = begin+i; - else end = regions->nregions+i; - } - for (i=begin;iregions[i], report); - int bytes = (int)strlcpy(bufp, rname, size); - if (bytes && wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (i+12) { - strcat(bufp, ", "); - bufp += 2; - size -= 2; - } - } - *bufp = 0; - var.v = strcpy(balloc(bufp-buf+1), buf); - opush(stack, var); -} - -static void -eval_trail(struct opstack ** stack, const void * userdata) /* order -> string */ -{ - const faction * report = (const faction*)userdata; - const struct locale * lang = report?report->locale:default_locale; - int i, end = 0, begin = 0; - const arg_regions * regions = (const arg_regions *)opop(stack).v; - static char buf[512]; - size_t size = sizeof(buf) - 1; - variant var; - char * bufp = buf; -#ifdef _SECURECRT_ERRCODE_VALUES_DEFINED - /* stupid MS broke snprintf */ - int eold = errno; -#endif - - if (regions!=NULL) { - end = regions->nregions; - for (i=begin;iregions[i]; - const char * trail = trailinto(r, lang); - const char * rn = f_regionid_s(r, report); - int bytes = snprintf(bufp, size, trail, rn); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (i+2locale:default_locale; - int i = opop(stack).i; - const char * c = LOC(lang, (i>=0)?directions[i]:"unknown_direction"); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_skill(struct opstack ** stack, const void * userdata) -{ - const faction * report = (const faction*)userdata; - const struct locale * lang = report?report->locale:default_locale; - skill_t sk = (skill_t)opop(stack).i; - const char * c = skillname(sk, lang); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -static void -eval_int36(struct opstack ** stack, const void * userdata) -{ - int i = opop(stack).i; - const char * c = itoa36(i); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); - unused(userdata); -} -/*** END MESSAGE RENDERING ***/ - -#include - -static void log_orders(const struct message * msg) -{ - faction * f = get_monsters(); - char buffer[4096]; - int i; - - for (i=0;i!=msg->type->nparameters;++i) { - if (msg->type->types[i]->copy==&var_copy_order) { - const char * section = nr_section(msg); - nr_render(msg, f?f->locale:default_locale, buffer, sizeof(buffer), f); - log_printf("MESSAGE [%s]: %s\n", section, buffer); - break; - } - } -} - -int -report_action(region * r, unit * actor, message * msg, int flags) -{ - int result = 0; - unit * u; - int view = flags&(ACTION_CANSEE|ACTION_CANNOTSEE); - - /* melden, 1x pro Partei */ - if (flags&ACTION_RESET) { - freset(actor->faction, FFL_SELECT); - for (u = r->units; u; u = u->next ) freset(u->faction, FFL_SELECT); - } - if (view) { - for (u = r->units; u; u = u->next ) { - if (!fval(u->faction, FFL_SELECT) ) { - boolean show = u->faction == actor->faction; - fset(u->faction, FFL_SELECT); - if (view==ACTION_CANSEE) { - /* Bei Fernzaubern sieht nur die eigene Partei den Magier */ - show = show || (r==actor->region && cansee(u->faction, r, actor, 0)); - } else if (view==ACTION_CANNOTSEE) { - show = !show && !(r==actor->region && cansee(u->faction, r, actor, 0)); - } else { - /* the unliely (or lazy) case */ - show = true; - } - - if (show) { - r_addmessage(r, u->faction, msg); - } else { /* Partei des Magiers, sieht diesen immer */ - result = 1; - } - } - } - /* Ist niemand von der Partei des Magiers in der Region, dem Magier - * nochmal gesondert melden */ - if ((flags&ACTION_CANSEE) && !fval(actor->faction, FFL_SELECT)) { - add_message(&actor->faction->msgs, msg); - } - } - return result; -} - - -void -register_reports(void) -{ - /* register datatypes for the different message objects */ - register_argtype("alliance", NULL, NULL, VAR_VOIDPTR); - register_argtype("building", NULL, NULL, VAR_VOIDPTR); - register_argtype("direction", NULL, NULL, VAR_INT); - register_argtype("faction", NULL, NULL, VAR_VOIDPTR); - register_argtype("race", NULL, NULL, VAR_VOIDPTR); - register_argtype("region", NULL, NULL, VAR_VOIDPTR); - register_argtype("resource", NULL, NULL, VAR_VOIDPTR); - register_argtype("ship", NULL, NULL, VAR_VOIDPTR); - register_argtype("skill", NULL, NULL, VAR_VOIDPTR); - register_argtype("spell", NULL, NULL, VAR_VOIDPTR); - register_argtype("curse", NULL, NULL, VAR_VOIDPTR); - register_argtype("unit", NULL, NULL, VAR_VOIDPTR); - register_argtype("int", NULL, NULL, VAR_INT); - register_argtype("string", var_free_string, var_copy_string, VAR_VOIDPTR); - register_argtype("order", var_free_order, var_copy_order, VAR_VOIDPTR); - register_argtype("resources", var_free_resources, NULL, VAR_VOIDPTR); - register_argtype("items", var_free_resources, var_copy_items, VAR_VOIDPTR); - register_argtype("regions", var_free_regions, NULL, VAR_VOIDPTR); - - - msg_log_create = &log_orders; - - /* register functions that turn message contents to readable strings */ - add_function("alliance", &eval_alliance); - add_function("region", &eval_region); - add_function("terrain", &eval_terrain); - add_function("weight", &eval_weight); - add_function("resource", &eval_resource); - add_function("race", &eval_race); - add_function("faction", &eval_faction); - add_function("ship", &eval_ship); - add_function("unit", &eval_unit); - add_function("unit.dative", &eval_unit_dative); - add_function("unit.name", &eval_unitname); - add_function("unit.id", &eval_unitid); - add_function("unit.size", &eval_unitsize); - add_function("building", &eval_building); - add_function("skill", &eval_skill); - add_function("order", &eval_order); - add_function("direction", &eval_direction); - add_function("int36", &eval_int36); - add_function("trailto", &eval_trailto); - add_function("localize", &eval_localize); - add_function("spell", &eval_spell); - add_function("curse", &eval_curse); - add_function("resources", &eval_resources); - add_function("regions", &eval_regions); - add_function("trail", &eval_trail); - - /* register alternative visibility functions */ - register_function((pf_generic)view_neighbours, "view_neighbours"); - register_function((pf_generic)view_regatta, "view_regatta"); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "reports.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include +#include +#include + +/* attributes includes */ +#include +#include +#include +#include + +boolean nocr = false; +boolean nonr = false; +boolean noreports = false; + +const char * visibility[] = { + "none", + "neighbour", + "lighthouse", + "travel", + "far", + "unit", + "battle" +}; + +const char *coasts[MAXDIRECTIONS] = +{ + "coast::nw", + "coast::ne", + "coast::e", + "coast::se", + "coast::sw", + "coast::w" +}; + +static char * +groupid(const struct group * g, const struct faction * f) +{ + typedef char name[OBJECTIDSIZE + 1]; + static name idbuf[8]; + static int nextbuf = 0; + char *buf = idbuf[(++nextbuf) % 8]; + sprintf(buf, "%s (%s)", g->name, factionid(f)); + return buf; +} + +const char * combatstatus[] = { + "status_aggressive", "status_front", + "status_rear", "status_defensive", + "status_avoid", "status_flee" +}; + +const char * +report_kampfstatus(const unit * u, const struct locale * lang) +{ + static char fsbuf[64]; + + strlcpy(fsbuf, LOC(lang, combatstatus[u->status]), sizeof(fsbuf)); + if (fval(u, UFL_NOAID)) { + strcat(fsbuf, ", "); + strcat(fsbuf, LOC(lang, "status_noaid")); + } + + return fsbuf; +} + +const char * +hp_status(const unit * u) +{ + double p = (double) ((double) u->hp / (double) (u->number * unit_max_hp(u))); + + if (p > 2.00) return mkname("damage", "critical"); + if (p > 1.50) return mkname("damage", "heavily"); + if (p < 0.50) return mkname("damage", "badly"); + if (p < 0.75) return mkname("damage", "wounded"); + if (p < 0.99) return mkname("damage", "exhausted"); + + return NULL; +} + +void +report_item(const unit * owner, const item * i, const faction * viewer, const char ** name, const char ** basename, int * number, boolean singular) +{ + assert(!owner || owner->number); + if (owner && owner->faction == viewer) { + if (name) *name = locale_string(viewer->locale, resourcename(i->type->rtype, ((i->number!=1 && !singular)?GR_PLURAL:0))); + if (basename) *basename = resourcename(i->type->rtype, 0); + if (number) *number = i->number; + } else if (owner && i->type->rtype==r_silver) { + int pp = i->number/owner->number; + if (number) *number = 1; + if (pp > 50000 && dragonrace(owner->race)) { + if (name) *name = locale_string(viewer->locale, "dragonhoard"); + if (basename) *basename = "dragonhoard"; + } else if (pp > 5000) { + if (name) *name = locale_string(viewer->locale, "moneychest"); + if (basename) *basename = "moneychest"; + } else if (pp > 500) { + if (name) *name = locale_string(viewer->locale, "moneybag"); + if (basename) *basename = "moneybag"; + } else { + if (number) *number = 0; + if (name) *name = NULL; + if (basename) *basename = NULL; + } + } else { + if (name) *name = locale_string(viewer->locale, resourcename(i->type->rtype, NMF_APPEARANCE|((i->number!=1 && !singular)?GR_PLURAL:0))); + if (basename) *basename = resourcename(i->type->rtype, NMF_APPEARANCE); + if (number) { + if (fval(i->type, ITF_HERB)) *number = 1; + else *number = i->number; + } + } +} + + +int * nmrs = NULL; + +int +update_nmrs(void) +{ + int i, newplayers =0; + faction *f; + int turn = global.data_turn; + + if (nmrs==NULL) nmrs = malloc(sizeof(int)*(NMRTimeout()+1)); + for (i = 0; i <= NMRTimeout(); ++i) { + nmrs[i] = 0; + } + + for (f = factions; f; f = f->next) { + if (fval(f, FFL_ISNEW)) { + ++newplayers; + } else if (!is_monsters(f) && f->alive) { + int nmr = turn-f->lastorders+1; + if (nmr<0 || nmr>NMRTimeout()) { + log_error(("faction %s has %d NMRS\n", factionid(f), nmr)); + nmr = MAX(0, nmr); + nmr = MIN(nmr, NMRTimeout()); + } + ++nmrs[nmr]; + } + } + return newplayers; +} + +#define ORDERS_IN_NR 1 +static size_t +buforder(char * bufp, size_t size, const order * ord, int mode) +{ + size_t tsize = 0; + int bytes; + + bytes = (int)strlcpy(bufp, ", \"", size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (mode1) { + *bufp++ ='\"'; + --size; + } else { + WARN_STATIC_BUFFER(); + } + ++tsize; + + return tsize; +} + +/** create a report of a list of items to a non-owner. + * \param result: an array of size items. + * \param size: maximum number of items to return + * \param owner: the owner of the items, or NULL for faction::items etc. + * \param viewer: the faction looking at the items + */ +int +report_items(const item * items, item * result, int size, const unit * owner, const faction * viewer) +{ + const item * itm; + int n = 0; /* number of results */ + + assert(owner==NULL || viewer!=owner->faction || !"not required for owner=viewer!"); + assert(size); + + for (itm=items;itm;itm=itm->next) { + item * ishow; + const char * ic; + + report_item(owner, itm, viewer, NULL, &ic, NULL, false); + if (ic && *ic) { + for (ishow = result; ishow!=result+n; ++ishow) { + const char * sc; + + if (ishow->type==itm->type) sc = ic; + else report_item(owner, ishow, viewer, NULL, &sc, NULL, false); + if (sc==ic || strcmp(sc, ic)==0) { + ishow->number+=itm->number; + break; + } + } + if (ishow==result+n) { + if (n==size) { + log_error(("too many items to report, increase buffer size.\n")); + return -1; + } + result[n].number = itm->number; + result[n].type = itm->type; + result[n].next = (n+1==size)?NULL:result+n+1; + ++n; + } + } + } + if (n>0) result[n-1].next = NULL; + return n; +} + +static void +report_resource(resource_report * result, const char * name, int number, int level) +{ + result->name = name; + result->number = number; + result->level = level; +} + +void +report_race(const struct unit * u, const char ** name, const char ** illusion) +{ + if (illusion) { + const race * irace = u_irace(u); + if (irace && irace!=u->race) { + *illusion = irace->_name[0]; + } + else { + *illusion = NULL; + } + } + if (name) { + *name = u->race->_name[0]; + if (fval(u->race, RCF_SHAPESHIFTANY)) { + const char * str = get_racename(u->attribs); + if (str) *name = str; + } + } +} + +void +report_building(const struct building * b, const char ** name, const char ** illusion) +{ + static int init; + static const struct building_type * bt_illusion; + + if (name) { + *name = buildingtype(b->type, b, b->size); + } + if (illusion) { + *illusion = NULL; + + if (!init) { + bt_illusion = bt_find("illusioncastle"); + init = 1; + } + if (bt_illusion && b->type==bt_illusion) { + const attrib * a = a_findc(b->attribs, &at_icastle); + if (a!=NULL) { + icastle_data * icastle = (icastle_data*)a->data.v; + *illusion = buildingtype(icastle->type, b, b->size); + } + } + } +} + +int +report_resources(const seen_region * sr, resource_report * result, int size, const faction * viewer) +{ + const region * r = sr->r; + int n = 0; + + if (r->land) { + int peasants = rpeasants(r); + int money = rmoney(r); + int horses = rhorses(r); + int trees = rtrees(r, 2); + int saplings = rtrees(r, 1); + boolean mallorn = fval(r, RF_MALLORN)!=0; + + if (money) { + if (n>=size) return -1; + report_resource(result+n, "rm_money", money, -1); + ++n; + } + if (peasants) { + if (n>=size) return -1; + report_resource(result+n, "rm_peasant", peasants, -1); + ++n; + } + if (horses) { + if (n>=size) return -1; + report_resource(result+n, "rm_horse", horses, -1); + ++n; + } + if (saplings) { + if (n>=size) return -1; + report_resource(result+n, mallorn?"rm_mallornsapling":"rm_sapling", saplings, -1); + ++n; + } + if (trees) { + if (n>=size) return -1; + report_resource(result+n, mallorn?"rm_mallorn":"rm_tree", trees, -1); + ++n; + } + } + + if (sr->mode>=see_unit) { + rawmaterial * res = r->resources; + while (res) { + int maxskill = 0; + const item_type * itype = resource2item(res->type->rtype); + int level = res->level + itype->construction->minskill - 1; + int visible = -1; + if (res->type->visible==NULL) { + visible = res->amount; + level = res->level + itype->construction->minskill - 1; + } else { + const unit * u; + for (u=r->units; visible!=res->amount && u!=NULL; u=u->next) { + if (u->faction == viewer) { + int s = eff_skill(u, itype->construction->skill, r); + if (s>maxskill) { + maxskill = s; + visible = res->type->visible(res, maxskill); + } + } + } + } + if (level>=0 && visible>=0) { + if (n>=size) return -1; + report_resource(result+n, res->type->name, visible, level); + n++; + } + res = res->next; + } + } + return n; +} + +int +bufunit(const faction * f, const unit * u, int indent, int mode, char * buf, size_t size) +{ + int i, dh; + int getarnt = fval(u, UFL_ANON_FACTION); + const char *pzTmp, *str; + building * b; + boolean isbattle = (boolean)(mode == see_battle); + int telepath_see = 0; + attrib *a_fshidden = NULL; + item * itm; + item * show; + faction *fv = visible_faction(f, u); + char * bufp = buf; + boolean itemcloak = false; + static const curse_type * itemcloak_ct = 0; + static boolean init = false; + int bytes; + item result[MAX_INVENTORY]; + + if (!init) { + init = true; + itemcloak_ct = ct_find("itemcloak"); + } + if (itemcloak_ct!=NULL) { + itemcloak = curse_active(get_curse(u->attribs, itemcloak_ct)); + } + + bytes = (int)strlcpy(bufp, unitname(u), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (!isbattle) { + attrib *a_otherfaction = a_find(u->attribs, &at_otherfaction); + if (u->faction == f) { + if (fval(u, UFL_GROUP)) { + attrib *a = a_find(u->attribs, &at_group); + if (a) { + group * g = (group*)a->data.v; + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, groupid(g, f), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + if (getarnt) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "anonymous"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else if (a_otherfaction) { + faction * otherfaction = get_otherfaction(a_otherfaction); + if (otherfaction) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, factionname(otherfaction), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + } else { + if (getarnt) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "anonymous"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else { + if (a_otherfaction && alliedunit(u, f, HELP_FSTEALTH)) { + faction * f = get_otherfaction(a_otherfaction); + bytes = snprintf(bufp, size, ", %s (%s)", factionname(f), factionname(u->faction)); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } else { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, factionname(fv), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + } + } + + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (u->faction != f && a_fshidden && a_fshidden->data.ca[0] == 1 && effskill(u, SK_STEALTH) >= 6) { + bytes = (int)strlcpy(bufp, "? ", size); + } else { + bytes = snprintf(bufp, size, "%d ", u->number); + } + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + pzTmp = get_racename(u->attribs); + if (pzTmp) { + bytes = (int)strlcpy(bufp, pzTmp, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (u->faction==f && fval(u->race, RCF_SHAPESHIFTANY)) { + bytes = (int)strlcpy(bufp, " (", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, racename(f->locale, u, u->race), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (size>1) { + strcpy(bufp++, ")"); + --size; + } + } + } else { + const race * irace = u_irace(u); + bytes = (int)strlcpy(bufp, racename(f->locale, u, irace), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (u->faction==f && irace!=u->race) { + bytes = (int)strlcpy(bufp, " (", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, racename(f->locale, u, u->race), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (size>1) { + strcpy(bufp++, ")"); + --size; + } + } + } + + if (fval(u, UFL_HERO) && (u->faction == f || omniscient(f))) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "hero"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + /* status */ + + if (u->number && (u->faction == f || telepath_see || isbattle)) { + const char * c = locale_string(f->locale, hp_status(u)); + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, report_kampfstatus(u, f->locale), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (c || fval(u, UFL_HUNGER)) { + bytes = (int)strlcpy(bufp, " (", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (c) { + bytes = (int)strlcpy(bufp, c, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (fval(u, UFL_HUNGER)) { + if (c) bytes = (int)strlcpy(bufp, ", hungert", size); + else bytes = (int)strlcpy(bufp, "hungert", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + if (size>1) { + strcpy(bufp++, ")"); + --size; + } + } + } + if (is_guard(u, GUARD_ALL)!=0) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "unit_guards"), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + if ((b = usiege(u))!=NULL) { + bytes = (int)strlcpy(bufp, ", belagert ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, buildingname(b), size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + dh = 0; + if (u->faction == f || telepath_see) { + skill * sv; + for (sv = u->skills;sv!=u->skills+u->skill_size;++sv) { + bytes = (int)spskill(bufp, size, f->locale, u, sv, &dh, 1); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + + dh = 0; + if (f == u->faction || telepath_see || omniscient(f)) { + show = u->items; + } else if (!itemcloak && mode >= see_unit && !(a_fshidden + && a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) + { + int n = report_items(u->items, result, MAX_INVENTORY, u, f); + assert(n>=0); + if (n>0) show = result; + else show = NULL; + } else { + show = NULL; + } + for (itm=show; itm; itm=itm->next) { + const char * ic; + int in, bytes; + report_item(u, itm, f, &ic, NULL, &in, false); + if (in==0 || ic==NULL) continue; + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (!dh) { + bytes = snprintf(bufp, size, "%s: ", LOC(f->locale, "nr_inventory")); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + dh = 1; + } + if (in == 1) { + bytes = (int)strlcpy(bufp, ic, size); + } else { + bytes = snprintf(bufp, size, "%d %s", in, ic); + } + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + if (u->faction == f || telepath_see) { + sc_mage * m = get_mage(u); + + if (m!=NULL) { + spell_list *slist = m->spells; + int t = effskill(u, SK_MAGIC); + int bytes = snprintf(bufp, size, ". Aura %d/%d", get_spellpoints(u), max_spellpoints(u->region,u)); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + for (dh=0; slist; slist=slist->next) { + spell * sp = slist->data; + if (sp->level > t) continue; + if (!dh) { + bytes = snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_spells")); + dh = 1; + } else { + bytes = (int)strlcpy(bufp, ", ", size); + } + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, spell_name(sp, f->locale), size); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + for (i=0; i!=MAXCOMBATSPELLS; ++i) { + if (get_combatspell(u, i)) break; + } + if (i!=MAXCOMBATSPELLS) { + bytes = snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_combatspells")); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + dh = 0; + for (i = 0; i < MAXCOMBATSPELLS; i++){ + const spell *sp; + if (!dh){ + dh = 1; + } else { + bytes = (int)strlcpy(bufp, ", ", size); + if (bytes && wrptr(&bufp, &size, bytes)!=0) { + WARN_STATIC_BUFFER(); + } + } + sp = get_combatspell(u,i); + if (sp) { + int sl = get_combatspelllevel(u, i); + bytes = (int)strlcpy(bufp, spell_name(sp, u->faction->locale), size); + if (bytes && wrptr(&bufp, &size, bytes)!=0) { + WARN_STATIC_BUFFER(); + } + + if (sl > 0) { + bytes = snprintf(bufp, size, " (%d)", sl); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } else { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nospells"), size); + if (bytes && wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + } + } + if (!isbattle) { + boolean printed = 0; + order * ord;; + for (ord=u->old_orders;ord;ord=ord->next) { + if (is_repeated(ord)) { + if (printedorders;ord;ord=ord->next) { + if (is_repeated(ord)) { + if (printedlocale); + if (str) { + bytes = (int)strlcpy(bufp, "; ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + bytes = (int)strlcpy(bufp, str, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + i = str[strlen(str) - 1]; + } + if (i != '!' && i != '?' && i != '.') { + if (size>1) { + strcpy(bufp++, "."); + --size; + } + } + pzTmp = uprivate(u); + if (u->faction == f && pzTmp) { + bytes = (int)strlcpy(bufp, " (Bem: ", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, pzTmp, size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, ")", size); + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + + dh=0; + if (!getarnt && f) { + if (alliedfaction(rplane(u->region), f, fv, HELP_ALL)) { + dh = 1; + } + } + if (size<=1) { + log_warning(("bufunit ran out of space after writing %u bytes.\n", (bufp-buf))); + } + return dh; +} + +/* TODO: telepath_see wird nicht berücksichtigt: Parteien mit + * telepath_see sollten immer einzelne Einheiten zu sehen + * bekommen, alles andere ist darstellungsteschnisch kompliziert. + */ + +size_t +spskill(char * buffer, size_t size, const struct locale * lang, const struct unit * u, struct skill * sv, int *dh, int days) +{ + char * bufp = buffer; + int i, effsk; + int bytes; + size_t tsize = 0; + + if (!u->number) return 0; + if (sv->level<=0) { + if (sv->old<=0 || (u->faction->options & want(O_SHOWSKCHANGE))==0) { + return 0; + } + } + + bytes = (int)strlcpy(bufp, ", ", size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (!*dh) { + bytes = (int)strlcpy(bufp, LOC(lang, "nr_skills"), size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + bytes = (int)strlcpy(bufp, ": ", size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + *dh = 1; + } + bytes = (int)strlcpy(bufp, skillname(sv->id, lang), size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + bytes = (int)strlcpy(bufp, " ", size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (sv->id == SK_MAGIC){ + sc_mage * mage = get_mage(u); + if (mage && mage->magietyp != M_GRAY) { + bytes = (int)strlcpy(bufp, LOC(lang, mkname("school", magic_school[mage->magietyp])), size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + bytes = (int)strlcpy(bufp, " ", size); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + + if (sv->id == SK_STEALTH && fval(u, UFL_STEALTH)) { + i = u_geteffstealth(u); + if (i>=0) { + bytes = slprintf(bufp, size, "%d/", i); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + + effsk = effskill(u, sv->id); + bytes = slprintf(bufp, size, "%d", effsk); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (u->faction->options & want(O_SHOWSKCHANGE)) { + int oldeff = 0; + int diff; + + if (sv->old > 0) { + oldeff = sv->old + get_modifier(u, sv->id, sv->old, u->region, false); + } + + oldeff = MAX(0, oldeff); + diff = effsk - oldeff; + + if (diff != 0) { + bytes = slprintf(bufp, size, " (%s%d)", (diff>0)?"+":"", diff); + tsize += bytes; + if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + } + } + return tsize; +} + +void +lparagraph(struct strlist ** SP, char *s, int indent, char mark) +{ + + /* Die Liste SP wird mit dem String s aufgefuellt, mit indent und einer + * mark, falls angegeben. SP wurde also auf 0 gesetzt vor dem Aufruf. + * Vgl. spunit (). */ + + char *buflocal = calloc(strlen(s) + indent + 1, sizeof(char)); + + if (indent) { + memset(buflocal, ' ', indent); + if (mark) + buflocal[indent - 2] = mark; + } + strcpy(buflocal + indent, s); + addstrlist(SP, buflocal); + free(buflocal); +} + +void +spunit(struct strlist ** SP, const struct faction * f, const unit * u, int indent, + int mode) +{ + char buf[DISPLAYSIZE]; + int dh = bufunit(f, u, indent, mode, buf, sizeof(buf)); + lparagraph(SP, buf, indent, (char) ((u->faction == f) ? '*' : (dh ? '+' : '-'))); +} + +struct message * +msg_curse(const struct curse * c, const void * obj, typ_t typ, int self) +{ + if (c->type->curseinfo) { + /* if curseinfo returns NULL, then we don't want to tell the viewer anything. */ + return c->type->curseinfo(obj, typ, c, self); + } else { + message * msg = cinfo_simple(obj, typ, c, self); + if (msg==NULL) { + const char * unknown[] = { "unit_unknown", "region_unknown", "building_unknown", "ship_unknown" }; + msg = msg_message(mkname("curseinfo", unknown[typ]), "id", c->no); + log_error(("no curseinfo function for %s and no fallback either.\n", c->type->cname)); + } else { + log_error(("no curseinfo function for %s, using cinfo_simple fallback.\n", c->type->cname)); + } + return msg; + } +} + +const struct unit * +ucansee(const struct faction *f, const struct unit *u, const struct unit *x) +{ + if (cansee(f, u->region, u, 0)) return u; + return x; +} + +static void +add_faction(faction_list ** flist, faction * sf) +{ + faction_list ** fnew = flist; + while (*fnew && (*fnew)->data->no < sf->no) { + fnew =&(*fnew)->next; + } + if ((*fnew==NULL) || (*fnew)->data!=sf) { + faction_list * finsert = malloc(sizeof(faction_list)); + finsert->next = *fnew; + *fnew = finsert; + finsert->data = sf; + } +} + +int +stealth_modifier(int seen_mode) +{ + switch (seen_mode) { + case see_unit: + return 0; + case see_far: + case see_lighthouse: + return -2; + case see_travel: + return -1; + default: + return INT_MIN; + } +} + +static void +get_addresses(report_context * ctx) +{ +/* "TODO: travelthru" */ + seen_region * sr = NULL; + region *r; + const faction * lastf = NULL; + faction_list * flist = calloc(1, sizeof(faction_list)); + + flist->data = ctx->f; + + if (f_get_alliance(ctx->f)) { + faction_list * member = ctx->f->alliance->members; + for (;member;member=member->next) { + add_faction(&flist, member->data); + } + } + + for (r=ctx->first;sr==NULL && r!=ctx->last;r=r->next) { + sr = find_seen(ctx->seen, r); + } + + for (;sr!=NULL;sr=sr->next) { + int stealthmod = stealth_modifier(sr->mode); + r = sr->r; + if (sr->mode==see_lighthouse) { + unit * u = r->units; + for (;u;u=u->next) { + faction * sf = visible_faction(ctx->f, u); + if (lastf!=sf) { + if (u->building || u->ship || (stealthmod>INT_MIN && cansee(ctx->f, r, u, stealthmod))) { + add_faction(&flist, sf); + lastf = sf; + } + } + } + } else if (sr->mode==see_travel) { + unit * u = r->units; + while (u) { + faction * sf = visible_faction(ctx->f, u); + assert(u->faction!=ctx->f); /* if this is see_travel only, then I shouldn't be here. */ + if (lastf!=sf) { + attrib * a = a_find(r->attribs, &at_travelunit); + while (a && a->type==&at_travelunit) { + unit * u2 = (unit*)a->data.v; + if (u2->faction==ctx->f) { + if (cansee_unit(u2, u, stealthmod)) { + add_faction(&flist, sf); + lastf = sf; + break; + } + } + a = a->next; + } + } + u = u->next; + } + } else if (sr->mode>see_travel) { + const unit * u = r->units; + while (u!=NULL) { + if (u->faction!=ctx->f) { + faction * sf = visible_faction(ctx->f, u); + boolean ballied = sf && sf!=ctx->f && sf!=lastf + && !fval(u, UFL_ANON_FACTION) && cansee(ctx->f, r, u, stealthmod); + if (ballied || ALLIED(ctx->f, sf)) { + add_faction(&flist, sf); + lastf = sf; + } + } + u = u->next; + } + } + } + + if (f_get_alliance(ctx->f)) { + faction *f2; + for (f2 = factions; f2; f2 = f2->next) { + if (f2->alliance == ctx->f->alliance) { + add_faction(&flist, f2); + } + } + } + ctx->addresses = flist; +} + +#define MAXSEEHASH 0x1000 +seen_region * reuse; + +seen_region ** +seen_init(void) +{ + return (seen_region **)calloc(MAXSEEHASH, sizeof(seen_region*)); +} + +void +seen_done(seen_region * seehash[]) +{ + int i; + for (i=0;i!=MAXSEEHASH;++i) { + seen_region * sd = seehash[i]; + if (sd==NULL) continue; + while (sd->nextHash!=NULL) sd = sd->nextHash; + sd->nextHash = reuse; + reuse = seehash[i]; + seehash[i] = NULL; + } + // free(seehash); +} + +void +free_seen(void) +{ + while (reuse) { + seen_region * r = reuse; + reuse = reuse->nextHash; + free(r); + } +} + +void +link_seen(seen_region * seehash[], const region * first, const region * last) +{ + const region * r = first; + seen_region * sr = NULL; + + if (first==last) return; + + do { + sr = find_seen(seehash, r); + r = r->next; + } while (sr==NULL && r!=last); + + while (r!=last) { + seen_region * sn = find_seen(seehash, r); + if (sn!=NULL) { + sr->next = sn; + sr = sn; + } + r = r->next; + } + sr->next = 0; +} + +seen_region * +find_seen(struct seen_region * seehash[], const region * r) +{ + unsigned int index = reg_hashkey(r) & (MAXSEEHASH-1); + seen_region * find = seehash[index]; + while (find) { + if (find->r==r) return find; + find=find->nextHash; + } + return NULL; +} + +static void +get_seen_interval(report_context * ctx) +{ + /* this is required to find the neighbour regions of the ones we are in, + * which may well be outside of [firstregion, lastregion) */ + int i; + for (i=0;i!=MAXSEEHASH;++i) { + seen_region * sr = ctx->seen[i]; + while (sr!=NULL) { + if (ctx->first==NULL || sr->r->indexfirst->index) { + ctx->first = sr->r; + } + if (ctx->last!=NULL && sr->r->index>=ctx->last->index) { + ctx->last = sr->r->next; + } + sr = sr->nextHash; + } + } + link_seen(ctx->seen, ctx->first, ctx->last); +} + +boolean +add_seen(struct seen_region * seehash[], struct region * r, unsigned char mode, boolean dis) +{ + seen_region * find = find_seen(seehash, r); + if (find==NULL) { + unsigned int index = reg_hashkey(r) & (MAXSEEHASH-1); + if (!reuse) reuse = (seen_region*)calloc(1, sizeof(struct seen_region)); + find = reuse; + reuse = reuse->nextHash; + find->nextHash = seehash[index]; + seehash[index] = find; + find->r = r; + } else if (find->mode >= mode) { + return false; + } + find->mode = mode; + find->disbelieves |= dis; + return true; +} + +typedef struct report_type { + struct report_type * next; + report_fun write; + const char * extension; + int flag; +} report_type; + +static report_type * report_types; + +void +register_reporttype(const char * extension, report_fun write, int flag) +{ + report_type * type = malloc(sizeof(report_type)); + type->extension = extension; + type->write = write; + type->flag = flag; + type->next = report_types; + report_types = type; +} + +static region_list * +get_regions_distance(region * root, int radius) +{ + region_list * rptr, * rlist = NULL; + region_list ** rp = &rlist; + add_regionlist(rp, root); + fset(root, RF_MARK); + while (*rp) { + region_list * r = *rp; + direction_t d; + rp = &r->next; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(r->data, d); + if (rn!=NULL && !fval(rn, RF_MARK) && distance(rn, root)<=radius) { + add_regionlist(rp, rn); + fset(rn, RF_MARK); + } + } + } + for (rptr=rlist;rptr;rptr=rptr->next) { + freset(rptr->data, RF_MARK); + } + return rlist; +} + +static void +view_default(struct seen_region ** seen, region *r, faction *f) +{ + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * r2 = rconnect(r, dir); + if (r2) { + connection * b = get_borders(r, r2); + while (b) { + if (!b->type->transparent(b, f)) break; + b = b->next; + } + if (!b) add_seen(seen, r2, see_neighbour, false); + } + } +} + +static void +view_neighbours(struct seen_region ** seen, region * r, faction * f) +{ + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * r2 = rconnect(r, dir); + if (r2) { + connection * b = get_borders(r, r2); + while (b) { + if (!b->type->transparent(b, f)) break; + b = b->next; + } + if (!b) { + if (add_seen(seen, r2, see_far, false)) { + if (!(fval(r2->terrain, FORBIDDEN_REGION))) { + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * r3 = rconnect(r2, dir); + if (r3) { + connection * b = get_borders(r2, r3); + while (b) { + if (!b->type->transparent(b, f)) break; + b = b->next; + } + if (!b) add_seen(seen, r3, see_neighbour, false); + } + } + } + } + } + } + } +} + +static void +recurse_regatta(struct seen_region ** seen, region *center, region *r, faction *f, int maxdist) +{ + direction_t dir; + int dist = distance(center, r); + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * r2 = rconnect(r, dir); + if (r2) { + int ndist = distance(center, r2); + if (ndist>dist && fval(r2->terrain, SEA_REGION)) { + connection * b = get_borders(r, r2); + while (b) { + if (!b->type->transparent(b, f)) break; + b = b->next; + } + if (!b) { + if (ndistunits; u; u=u->next) { + if (u->faction==f) { + int es = effskill(u, SK_PERCEPTION); + if (es>skill) skill=es; + } + } + recurse_regatta(seen, r, r, f, skill/2); +} + +static void +prepare_reports(void) +{ + region * r; + faction * f; + static const struct building_type * bt_lighthouse = NULL; + if (bt_lighthouse==NULL) bt_lighthouse = bt_find("lighthouse"); + + for (f = factions; f ; f = f->next) { + if (f->seen) seen_done(f->seen); + f->seen = seen_init(); + } + + for (r = regions; r ; r = r->next) { + attrib *ru; + unit * u; + plane * p = rplane(r); + + reorder_units(r); + + if (p) { + watcher * w = p->watchers; + for (;w;w=w->next) { + add_seen(w->faction->seen, r, w->mode, false); +#ifdef SMART_INTERVALS + update_interval(w->faction, r); +#endif + } + } + + for (u = r->units; u; u = u->next) { + if (u->building && u->building->type==bt_lighthouse) { + /* we are in a lighthouse. add the regions we can see from here! */ + int range = lighthouse_range(u->building, u->faction); + region_list * rlist = get_regions_distance(r, range); + region_list * rp = rlist; + + while (rp) { + region * rl = rp->data; + if (fval(rl->terrain, SEA_REGION)) { + direction_t d; + add_seen(u->faction->seen, rl, see_lighthouse, false); + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(rl, d); + if (rn!=NULL) { + add_seen(u->faction->seen, rn, see_neighbour, false); + } + } + } + rp = rp->next; + } + free_regionlist(rlist); + } + + if (u->race != new_race[RC_SPELL] || u->number == RS_FARVISION) { + if (fval(u, UFL_DISBELIEVES)) { + add_seen(u->faction->seen, r, see_unit, true); + } else { + add_seen(u->faction->seen, r, see_unit, false); + } + } + } + + if (fval(r, RF_TRAVELUNIT)) { + for (ru = a_find(r->attribs, &at_travelunit); ru && ru->type==&at_travelunit; ru = ru->next) { + unit * u = (unit*)ru->data.v; + + /* make sure the faction has not been removed this turn: */ + if (u->faction) { + add_seen(u->faction->seen, r, see_travel, false); + } + } + } + } +} + +static seen_region ** +prepare_report(faction * f) +{ + struct seen_region * sr; + region * r = firstregion(f); + region * last = lastregion(f); + + link_seen(f->seen, r, last); + + for (sr=NULL; sr==NULL && r!=last; r=r->next) { + sr = find_seen(f->seen, r); + } + + for (;sr!=NULL;sr=sr->next) { + if (sr->mode>see_neighbour) { + region * r = sr->r; + plane * p = rplane(r); + + void (*view)(struct seen_region **, region *, faction *) = view_default; + if (p && fval(p, PFL_SEESPECIAL)) { + attrib * a = a_find(p->attribs, &at_viewrange); + if (a) view = (void (*)(struct seen_region **, region *, faction *))a->data.f; + } + view(f->seen, r, f); + } + } + return f->seen; +} + +int +write_reports(faction * f, time_t ltime) +{ + int backup = 1, maxbackup = 128; + boolean gotit = false; + struct report_context ctx; + const char * encoding = "UTF-8"; + + if (noreports) { + return false; + } + ctx.f = f; + ctx.report_time = time(NULL); + ctx.seen = prepare_report(f); + ctx.first = firstregion(f); + ctx.last = lastregion(f); + ctx.addresses = NULL; + ctx.userdata = NULL; + get_seen_interval(&ctx); + get_addresses(&ctx); + + do { + report_type * rtype = report_types; + + errno = 0; + if (verbosity>=2) { + log_stdio(stdout, "Reports for %s:", factionname(f)); + } + for (;rtype!=NULL;rtype=rtype->next) { + if (f->options & rtype->flag) { + char filename[MAX_PATH]; + sprintf(filename, "%s/%d-%s.%s", reportpath(), turn, factionid(f), rtype->extension); + if (rtype->write(filename, &ctx, encoding)==0) { + gotit = true; + } + } + } + + if (errno) { + char zText[64]; + puts(" ERROR"); + sprintf(zText, "Waiting %u seconds before retry", backup); + perror(zText); + sleep(backup); + if (backup=2) { + puts(" DONE"); + } + } while (errno); + if (!gotit) { + log_warning(("No report for faction %s!\n", factionid(f))); + } + freelist(ctx.addresses); + seen_done(ctx.seen); + return 0; +} + +static void +nmr_warnings(void) +{ + faction *f,*fa; +#define FRIEND (HELP_GUARD|HELP_MONEY) + for (f=factions;f;f=f->next) { + if (!is_monsters(f) && (turn-f->lastorders) >= 2) { + message * msg = NULL; + for (fa=factions;fa;fa=fa->next) { + int warn = 0; + if (get_param_int(global.parameters, "rules.alliances", 0)!=0) { + if (f->alliance && f->alliance==fa->alliance) { + warn = 1; + } + } else if (alliedfaction(NULL, f, fa, FRIEND) && alliedfaction(NULL, fa, f, FRIEND)) { + warn = 1; + } + if (warn) { + if (msg==NULL) { + msg = msg_message("warn_dropout", "faction turns", f, turn - f->lastorders); + } + add_message(&fa->msgs, msg); + } + } + if (msg!=NULL) msg_release(msg); + } + } +} + +static void +report_donations(void) +{ + region * r; + for (r=regions;r;r=r->next) { + while (r->donations) { + donation * sp = r->donations; + if (sp->amount > 0) { + struct message * msg = msg_message("donation", + "from to amount", sp->f1, sp->f2, sp->amount); + r_addmessage(r, sp->f1, msg); + r_addmessage(r, sp->f2, msg); + msg_release(msg); + } + r->donations = sp->next; + free(sp); + } + } +} + +static void +write_script(FILE * F, const faction * f) +{ + report_type * rtype; + char buf[1024]; + + fprintf(F, "faction=%s:email=%s:lang=%s", factionid(f), f->email, locale_name(f->locale)); + if (f->options & (1<extension); + } + } + fputs(buf, F); + fputc('\n', F); +} + +int +init_reports(void) +{ + prepare_reports(); +#ifdef HAVE_STAT + { + stat_type st; + if (stat(reportpath(), &st)==0) return 0; + } +#endif + if (makedir(reportpath(), 0700)!=0) { + if (errno!=EEXIST) { + perror("could not create reportpath"); + return -1; + } + } + return 0; +} + +int +reports(void) +{ + faction *f; + FILE *mailit; + time_t ltime = time(NULL); + const char * str; + int retval = 0; + char path[MAX_PATH]; + + if (verbosity>=1) { + log_stdio(stdout, "Writing reports for turn %d:", turn); + } + nmr_warnings(); + report_donations(); + remove_empty_units(); + + sprintf(path, "%s/reports.txt", reportpath()); + mailit = fopen(path, "w"); + if (mailit == NULL) { + log_error(("%s could not be opened!\n", path)); + } + + for (f = factions; f; f = f->next) { + int error = write_reports(f, ltime); + if (error) retval = error; + if (mailit) write_script(mailit, f); + } + if (mailit) fclose(mailit); + free_seen(); + str = get_param(global.parameters, "globalreport"); +#ifdef GLOBAL_REPORT + if (str!=NULL) { + sprintf(path, "%s/%s.%u.cr", reportpath(), str, turn); + global_report(path); + } +#endif + return retval; +} + +static variant +var_copy_string(variant x) +{ + x.v = strdup((const char*)x.v); + return x; +} + +static void +var_free_string(variant x) +{ + free(x.v); +} + +static variant +var_copy_order(variant x) +{ + x.v = copy_order((order*)x.v); + return x; +} + +static void +var_free_order(variant x) +{ + free_order(x.v); +} + +static variant +var_copy_items(variant x) +{ + item * isrc; + resource * rdst = NULL, ** rptr = &rdst; + + for (isrc = (item*)x.v; isrc!=NULL; isrc=isrc->next) { + resource * res = malloc(sizeof(resource)); + res->number = isrc->number; + res->type = isrc->type->rtype; + *rptr = res; + rptr = &res->next; + } + *rptr = NULL; + x.v = rdst; + return x; +} + +static void +var_free_resources(variant x) +{ + resource * rsrc = (resource*)x.v; + while (rsrc) { + resource * res = rsrc->next; + free(rsrc); + rsrc = res; + } + x.v = 0; +} + +static void +var_free_regions(variant x) +{ + free(x.v); +} + +const char * +trailinto(const region * r, const struct locale * lang) +{ + char ref[32]; + const char * s; + if (r) { + const char * tname = terrain_name(r); + strcat(strcpy(ref, tname), "_trail"); + s = locale_string(lang, ref); + if (s && *s) { + if (strstr(s, "%s")) return s; + } + } + return "%s"; +} + +size_t +f_regionid(const region * r, const faction * f, char * buffer, size_t size) +{ + if (!r) { + strncpy(buffer, "(Chaos)", size); + } else { + plane * pl = rplane(r); + const char * name = pl?pl->name:0; + int nx = r->x, ny = r->y; + pnormalize(&nx, &ny, pl); + adjust_coordinates(f, &nx, &ny, pl, r); + strncpy(buffer, rname(r, f->locale), size); + buffer[size-1]=0; + sprintf(buffer+strlen(buffer), " (%d,%d%s%s)", nx, ny, name?",":"", (name)?name:""); + } + return strlen(buffer); +} + +static char * +f_regionid_s(const region * r, const faction * f) +{ + static int i = 0; + static char bufs[4][NAMESIZE + 20]; + char * buf = bufs[(++i)%4]; + + f_regionid(r, f, buf, NAMESIZE + 20); + return buf; +} + +/*** BEGIN MESSAGE RENDERING ***/ +static void +eval_localize(struct opstack ** stack, const void * userdata) /* (string, locale) -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct locale * lang = f?f->locale:default_locale; + const char *c = (const char *)opop_v(stack); + c = locale_string(lang, c); + opush_v(stack, strcpy(balloc(strlen(c)+1), c)); +} + +static void +eval_trailto(struct opstack ** stack, const void * userdata) /* (int, int) -> int */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct locale * lang = f?f->locale:default_locale; + const struct region * r = (const struct region*)opop(stack).v; + const char * trail = trailinto(r, lang); + const char * rn = f_regionid_s(r, f); + variant var; + char * x = var.v = balloc(strlen(trail)+strlen(rn)); + sprintf(x, trail, rn); + opush(stack, var); +} + +static void +eval_unit(struct opstack ** stack, const void * userdata) /* unit -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct unit * u = (const struct unit *)opop(stack).v; + const char * c = u?unitname(u):LOC(f->locale, "an_unknown_unit"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_unit_dative(struct opstack ** stack, const void * userdata) /* unit -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct unit * u = (const struct unit *)opop(stack).v; + const char * c = u?unitname(u):LOC(f->locale, "unknown_unit_dative"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_spell(struct opstack ** stack, const void * userdata) /* unit -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct spell * sp = (const struct spell *)opop(stack).v; + const char * c = sp?spell_name(sp, f->locale):LOC(f->locale, "an_unknown_spell"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_curse(struct opstack ** stack, const void * userdata) /* unit -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct curse_type * sp = (const struct curse_type *)opop(stack).v; + const char * c = sp?curse_name(sp, f->locale):LOC(f->locale, "an_unknown_curse"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_unitname(struct opstack ** stack, const void * userdata) /* unit -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct unit * u = (const struct unit *)opop(stack).v; + const char * c = u?u->name:LOC(f->locale, "an_unknown_unit"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + + +static void +eval_unitid(struct opstack ** stack, const void * userdata) /* unit -> int */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct unit * u = (const struct unit *)opop(stack).v; + const char * c = u?u->name:LOC(f->locale, "an_unknown_unit"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_unitsize(struct opstack ** stack, const void * userdata) /* unit -> int */ +{ + const struct unit * u = (const struct unit *)opop(stack).v; + variant var; + + var.i = u->number; + opush(stack, var); +} + +static void +eval_faction(struct opstack ** stack, const void * userdata) /* faction -> string */ +{ + const struct faction * f = (const struct faction *)opop(stack).v; + const char * c = factionname(f); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_alliance(struct opstack ** stack, const void * userdata) /* faction -> string */ +{ + const struct alliance * al = (const struct alliance *)opop(stack).v; + const char * c = alliancename(al); + variant var; + if (c!=NULL) { + size_t len = strlen(c); + var.v = strcpy(balloc(len+1), c); + } + else var.v = NULL; + opush(stack, var); +} + +static void +eval_region(struct opstack ** stack, const void * userdata) /* region -> string */ +{ + char name[NAMESIZE+32]; + const struct faction * f = (const struct faction *)userdata; + const struct region * r = (const struct region *)opop(stack).v; + const char * c = write_regionname(r, f, name, sizeof(name)); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_terrain(struct opstack ** stack, const void * userdata) /* region -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct region * r = (const struct region *)opop(stack).v; + const char * c = LOC(f->locale, terrain_name(r)); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_ship(struct opstack ** stack, const void * userdata) /* ship -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct ship * u = (const struct ship *)opop(stack).v; + const char * c = u?shipname(u):LOC(f->locale, "an_unknown_ship"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_building(struct opstack ** stack, const void * userdata) /* building -> string */ +{ + const struct faction * f = (const struct faction *)userdata; + const struct building * u = (const struct building *)opop(stack).v; + const char * c = u?buildingname(u):LOC(f->locale, "an_unknown_building"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_weight(struct opstack ** stack, const void * userdata) /* region -> string */ +{ + char buffer[32]; + const struct faction * f = (const struct faction *)userdata; + const struct locale * lang = f->locale; + int weight = opop_i(stack); + variant var; + + if (weight % SCALEWEIGHT == 0) { + if (weight==SCALEWEIGHT) { + sprintf(buffer, "1 %s", LOC(lang, "weight_unit")); + } else { + sprintf(buffer, "%u %s", weight/SCALEWEIGHT, LOC(lang, "weight_unit_p")); + } + } else { + if (weight==1) { + sprintf(buffer, "1 %s %u", LOC(lang, "weight_per"), SCALEWEIGHT); + } else { + sprintf(buffer, "%u %s %u", weight, LOC(lang, "weight_per_p"), SCALEWEIGHT); + } + } + + var.v = strcpy(balloc(strlen(buffer)+1), buffer); + opush(stack, var); +} + +static void +eval_resource(struct opstack ** stack, const void * userdata) +{ + const faction * report = (const faction*)userdata; + const struct locale * lang = report?report->locale:default_locale; + int j = opop(stack).i; + const struct resource_type * res = (const struct resource_type *)opop(stack).v; + const char * c = LOC(lang, resourcename(res, j!=1)); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_race(struct opstack ** stack, const void * userdata) +{ + const faction * report = (const faction*)userdata; + const struct locale * lang = report?report->locale:default_locale; + int j = opop(stack).i; + const race * r = (const race *)opop(stack).v; + const char * c = LOC(lang, rc_name(r, j!=1)); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_order(struct opstack ** stack, const void * userdata) /* order -> string */ +{ + const struct order * ord = (const struct order *)opop(stack).v; + static char buf[256]; + size_t len; + variant var; + + unused(userdata); + write_order(ord, buf, sizeof(buf)); + len = strlen(buf); + var.v = strcpy(balloc(len+1), buf); + opush(stack, var); +} + +static void +eval_resources(struct opstack ** stack, const void * userdata) /* order -> string */ +{ + const faction * report = (const faction*)userdata; + const struct locale * lang = report?report->locale:default_locale; + const struct resource * res = (const struct resource *)opop(stack).v; + static char buf[1024]; /* but we only use about half of this */ + size_t size = sizeof(buf) - 1; + variant var; + + char * bufp = buf; + while (res!=NULL && size > 4) { + const char * rname = resourcename(res->type, (res->number!=1)?NMF_PLURAL:0); + int bytes = snprintf(bufp, size, "%d %s", res->number, LOC(lang, rname)); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0 || sizenext; + if (res!=NULL && size>2) { + strcat(bufp, ", "); + bufp += 2; + size -= 2; + } + } + *bufp = 0; + var.v = strcpy(balloc(bufp-buf+1), buf); + opush(stack, var); +} + +static void +eval_regions(struct opstack ** stack, const void * userdata) /* order -> string */ +{ + const faction * report = (const faction*)userdata; + int i = opop(stack).i; + int end, begin = opop(stack).i; + const arg_regions * regions = (const arg_regions *)opop(stack).v; + static char buf[256]; + size_t size = sizeof(buf) - 1; + variant var; + char * bufp = buf; + + if (regions==NULL) { + end = begin; + } else { + if (i>=0) end = begin+i; + else end = regions->nregions+i; + } + for (i=begin;iregions[i], report); + int bytes = (int)strlcpy(bufp, rname, size); + if (bytes && wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (i+12) { + strcat(bufp, ", "); + bufp += 2; + size -= 2; + } + } + *bufp = 0; + var.v = strcpy(balloc(bufp-buf+1), buf); + opush(stack, var); +} + +static void +eval_trail(struct opstack ** stack, const void * userdata) /* order -> string */ +{ + const faction * report = (const faction*)userdata; + const struct locale * lang = report?report->locale:default_locale; + int i, end = 0, begin = 0; + const arg_regions * regions = (const arg_regions *)opop(stack).v; + static char buf[512]; + size_t size = sizeof(buf) - 1; + variant var; + char * bufp = buf; +#ifdef _SECURECRT_ERRCODE_VALUES_DEFINED + /* stupid MS broke snprintf */ + int eold = errno; +#endif + + if (regions!=NULL) { + end = regions->nregions; + for (i=begin;iregions[i]; + const char * trail = trailinto(r, lang); + const char * rn = f_regionid_s(r, report); + int bytes = snprintf(bufp, size, trail, rn); + if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + + if (i+2locale:default_locale; + int i = opop(stack).i; + const char * c = LOC(lang, (i>=0)?directions[i]:"unknown_direction"); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_skill(struct opstack ** stack, const void * userdata) +{ + const faction * report = (const faction*)userdata; + const struct locale * lang = report?report->locale:default_locale; + skill_t sk = (skill_t)opop(stack).i; + const char * c = skillname(sk, lang); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +static void +eval_int36(struct opstack ** stack, const void * userdata) +{ + int i = opop(stack).i; + const char * c = itoa36(i); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); + unused(userdata); +} +/*** END MESSAGE RENDERING ***/ + +#include + +static void log_orders(const struct message * msg) +{ + faction * f = get_monsters(); + char buffer[4096]; + int i; + + for (i=0;i!=msg->type->nparameters;++i) { + if (msg->type->types[i]->copy==&var_copy_order) { + const char * section = nr_section(msg); + nr_render(msg, f?f->locale:default_locale, buffer, sizeof(buffer), f); + log_printf("MESSAGE [%s]: %s\n", section, buffer); + break; + } + } +} + +int +report_action(region * r, unit * actor, message * msg, int flags) +{ + int result = 0; + unit * u; + int view = flags&(ACTION_CANSEE|ACTION_CANNOTSEE); + + /* melden, 1x pro Partei */ + if (flags&ACTION_RESET) { + freset(actor->faction, FFL_SELECT); + for (u = r->units; u; u = u->next ) freset(u->faction, FFL_SELECT); + } + if (view) { + for (u = r->units; u; u = u->next ) { + if (!fval(u->faction, FFL_SELECT) ) { + boolean show = u->faction == actor->faction; + fset(u->faction, FFL_SELECT); + if (view==ACTION_CANSEE) { + /* Bei Fernzaubern sieht nur die eigene Partei den Magier */ + show = show || (r==actor->region && cansee(u->faction, r, actor, 0)); + } else if (view==ACTION_CANNOTSEE) { + show = !show && !(r==actor->region && cansee(u->faction, r, actor, 0)); + } else { + /* the unliely (or lazy) case */ + show = true; + } + + if (show) { + r_addmessage(r, u->faction, msg); + } else { /* Partei des Magiers, sieht diesen immer */ + result = 1; + } + } + } + /* Ist niemand von der Partei des Magiers in der Region, dem Magier + * nochmal gesondert melden */ + if ((flags&ACTION_CANSEE) && !fval(actor->faction, FFL_SELECT)) { + add_message(&actor->faction->msgs, msg); + } + } + return result; +} + + +void +register_reports(void) +{ + /* register datatypes for the different message objects */ + register_argtype("alliance", NULL, NULL, VAR_VOIDPTR); + register_argtype("building", NULL, NULL, VAR_VOIDPTR); + register_argtype("direction", NULL, NULL, VAR_INT); + register_argtype("faction", NULL, NULL, VAR_VOIDPTR); + register_argtype("race", NULL, NULL, VAR_VOIDPTR); + register_argtype("region", NULL, NULL, VAR_VOIDPTR); + register_argtype("resource", NULL, NULL, VAR_VOIDPTR); + register_argtype("ship", NULL, NULL, VAR_VOIDPTR); + register_argtype("skill", NULL, NULL, VAR_VOIDPTR); + register_argtype("spell", NULL, NULL, VAR_VOIDPTR); + register_argtype("curse", NULL, NULL, VAR_VOIDPTR); + register_argtype("unit", NULL, NULL, VAR_VOIDPTR); + register_argtype("int", NULL, NULL, VAR_INT); + register_argtype("string", var_free_string, var_copy_string, VAR_VOIDPTR); + register_argtype("order", var_free_order, var_copy_order, VAR_VOIDPTR); + register_argtype("resources", var_free_resources, NULL, VAR_VOIDPTR); + register_argtype("items", var_free_resources, var_copy_items, VAR_VOIDPTR); + register_argtype("regions", var_free_regions, NULL, VAR_VOIDPTR); + + + msg_log_create = &log_orders; + + /* register functions that turn message contents to readable strings */ + add_function("alliance", &eval_alliance); + add_function("region", &eval_region); + add_function("terrain", &eval_terrain); + add_function("weight", &eval_weight); + add_function("resource", &eval_resource); + add_function("race", &eval_race); + add_function("faction", &eval_faction); + add_function("ship", &eval_ship); + add_function("unit", &eval_unit); + add_function("unit.dative", &eval_unit_dative); + add_function("unit.name", &eval_unitname); + add_function("unit.id", &eval_unitid); + add_function("unit.size", &eval_unitsize); + add_function("building", &eval_building); + add_function("skill", &eval_skill); + add_function("order", &eval_order); + add_function("direction", &eval_direction); + add_function("int36", &eval_int36); + add_function("trailto", &eval_trailto); + add_function("localize", &eval_localize); + add_function("spell", &eval_spell); + add_function("curse", &eval_curse); + add_function("resources", &eval_resources); + add_function("regions", &eval_regions); + add_function("trail", &eval_trail); + + /* register alternative visibility functions */ + register_function((pf_generic)view_neighbours, "view_neighbours"); + register_function((pf_generic)view_regatta, "view_regatta"); +} diff --git a/src/kernel/reports.h b/src/kernel/reports.h index cd22bf13e..f4082f91c 100644 --- a/src/kernel/reports.h +++ b/src/kernel/reports.h @@ -1,140 +1,140 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_REPORTS -#define H_KRNL_REPORTS -#ifdef __cplusplus -extern "C" { -#endif - -/* Alter, ab dem der Score angezeigt werden soll: */ -#define DISPLAYSCORE 12 -/* Breite einer Reportzeile: */ -#define REPORTWIDTH 78 - -extern const char *directions[]; -extern const char *coasts[]; -extern boolean nonr; -extern boolean nocr; -extern boolean noreports; - -/* kann_finden speedups */ -extern boolean kann_finden(struct faction * f1, struct faction * f2); -extern struct unit * can_find(struct faction *, struct faction *); - -/* funktionen zum schreiben eines reports */ -void sparagraph(struct strlist ** SP, const char *s, int indent, char mark); -void lparagraph(struct strlist ** SP, char *s, int indent, char mark); -const char *hp_status(const struct unit * u); -extern size_t spskill(char * pbuf, size_t siz, const struct locale * lang, const struct unit * u, struct skill * sv, int *dh, int days); /* mapper */ -extern void spunit(struct strlist ** SP, const struct faction * f, const struct unit * u, int indent, int mode); - -extern int reports(void); -extern int write_reports(struct faction * f, time_t ltime); -extern int init_reports(void); - -extern const struct unit *ucansee(const struct faction *f, const struct unit *u, const struct unit *x); - -int hat_in_region(item_t itm, struct region * r, struct faction * f); - -/* für fast_region und neuen CR: */ - -enum { - see_none, - see_neighbour, - see_lighthouse, - see_travel, - see_far, - see_unit, - see_battle -}; -extern int stealth_modifier(int seen_mode); - -typedef struct seen_region { - struct seen_region * nextHash; - struct seen_region * next; - struct region *r; - unsigned char mode; - boolean disbelieves; -} seen_region; - -extern struct seen_region * find_seen(struct seen_region * seehash[], const struct region * r); -extern boolean add_seen(struct seen_region * seehash[], struct region * r, unsigned char mode, boolean dis); -extern struct seen_region ** seen_init(void); -extern void seen_done(struct seen_region * seehash[]); -extern void free_seen(void); -extern void link_seen(seen_region * seehash[], const struct region * first, const struct region * last); -extern const char * visibility[]; - -typedef struct report_context { - struct faction * f; - struct faction_list * addresses; - struct seen_region ** seen; - struct region * first, * last; - void * userdata; - time_t report_time; -} report_context; - -typedef int (*report_fun)(const char * filename, report_context * ctx, const char * charset); -extern void register_reporttype(const char * extension, report_fun write, int flag); - - -extern int bufunit(const struct faction * f, const struct unit * u, int indent, int mode, char * buf, size_t size); - -extern const char * trailinto(const struct region * r, const struct locale * lang); -extern const char * report_kampfstatus(const struct unit * u, const struct locale * lang); - - extern void register_reports(void); - - extern int update_nmrs(void); - extern int * nmrs; - - extern struct message * msg_curse(const struct curse * c, const void * obj, typ_t typ, int slef); - - typedef struct arg_regions { - int nregions; - struct region ** regions; - } arg_regions; - - typedef struct resource_report { - const char * name; - int number; - int level; - } resource_report; - int report_resources(const struct seen_region * sr, struct resource_report * result, int size, const struct faction * viewer); - int report_items(const struct item * items, struct item * result, int size, const struct unit * owner, const struct faction * viewer); - void report_item(const struct unit * owner, const struct item * i, const struct faction * viewer, const char ** name, const char ** basename, int * number, boolean singular); - void report_building(const struct building * b, const char ** btype, const char ** billusion); - void report_race(const struct unit * u, const char ** rcname, const char ** rcillusion); - -#define ACTION_RESET 0x01 /* reset the one-time-flag FFL_SELECT (on first pass) */ -#define ACTION_CANSEE 0x02 /* to people who can see the actor */ -#define ACTION_CANNOTSEE 0x04 /* to people who can not see the actor */ -extern int report_action(struct region * r, struct unit * actor, struct message * msg, int flags); - - extern size_t f_regionid(const struct region * r, const struct faction * f, char * buffer, size_t size); - - extern const char * combatstatus[]; -#define GR_PLURAL 0x01 /* grammar: plural */ -#define MAX_INVENTORY 128 /* maimum number of different items in an inventory */ -#define MAX_RAWMATERIALS 8 /* maximum kinds of raw materials in a regions */ - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_REPORTS +#define H_KRNL_REPORTS +#ifdef __cplusplus +extern "C" { +#endif + +/* Alter, ab dem der Score angezeigt werden soll: */ +#define DISPLAYSCORE 12 +/* Breite einer Reportzeile: */ +#define REPORTWIDTH 78 + +extern const char *directions[]; +extern const char *coasts[]; +extern boolean nonr; +extern boolean nocr; +extern boolean noreports; + +/* kann_finden speedups */ +extern boolean kann_finden(struct faction * f1, struct faction * f2); +extern struct unit * can_find(struct faction *, struct faction *); + +/* funktionen zum schreiben eines reports */ +void sparagraph(struct strlist ** SP, const char *s, int indent, char mark); +void lparagraph(struct strlist ** SP, char *s, int indent, char mark); +const char *hp_status(const struct unit * u); +extern size_t spskill(char * pbuf, size_t siz, const struct locale * lang, const struct unit * u, struct skill * sv, int *dh, int days); /* mapper */ +extern void spunit(struct strlist ** SP, const struct faction * f, const struct unit * u, int indent, int mode); + +extern int reports(void); +extern int write_reports(struct faction * f, time_t ltime); +extern int init_reports(void); + +extern const struct unit *ucansee(const struct faction *f, const struct unit *u, const struct unit *x); + +int hat_in_region(item_t itm, struct region * r, struct faction * f); + +/* für fast_region und neuen CR: */ + +enum { + see_none, + see_neighbour, + see_lighthouse, + see_travel, + see_far, + see_unit, + see_battle +}; +extern int stealth_modifier(int seen_mode); + +typedef struct seen_region { + struct seen_region * nextHash; + struct seen_region * next; + struct region *r; + unsigned char mode; + boolean disbelieves; +} seen_region; + +extern struct seen_region * find_seen(struct seen_region * seehash[], const struct region * r); +extern boolean add_seen(struct seen_region * seehash[], struct region * r, unsigned char mode, boolean dis); +extern struct seen_region ** seen_init(void); +extern void seen_done(struct seen_region * seehash[]); +extern void free_seen(void); +extern void link_seen(seen_region * seehash[], const struct region * first, const struct region * last); +extern const char * visibility[]; + +typedef struct report_context { + struct faction * f; + struct faction_list * addresses; + struct seen_region ** seen; + struct region * first, * last; + void * userdata; + time_t report_time; +} report_context; + +typedef int (*report_fun)(const char * filename, report_context * ctx, const char * charset); +extern void register_reporttype(const char * extension, report_fun write, int flag); + + +extern int bufunit(const struct faction * f, const struct unit * u, int indent, int mode, char * buf, size_t size); + +extern const char * trailinto(const struct region * r, const struct locale * lang); +extern const char * report_kampfstatus(const struct unit * u, const struct locale * lang); + + extern void register_reports(void); + + extern int update_nmrs(void); + extern int * nmrs; + + extern struct message * msg_curse(const struct curse * c, const void * obj, typ_t typ, int slef); + + typedef struct arg_regions { + int nregions; + struct region ** regions; + } arg_regions; + + typedef struct resource_report { + const char * name; + int number; + int level; + } resource_report; + int report_resources(const struct seen_region * sr, struct resource_report * result, int size, const struct faction * viewer); + int report_items(const struct item * items, struct item * result, int size, const struct unit * owner, const struct faction * viewer); + void report_item(const struct unit * owner, const struct item * i, const struct faction * viewer, const char ** name, const char ** basename, int * number, boolean singular); + void report_building(const struct building * b, const char ** btype, const char ** billusion); + void report_race(const struct unit * u, const char ** rcname, const char ** rcillusion); + +#define ACTION_RESET 0x01 /* reset the one-time-flag FFL_SELECT (on first pass) */ +#define ACTION_CANSEE 0x02 /* to people who can see the actor */ +#define ACTION_CANNOTSEE 0x04 /* to people who can not see the actor */ +extern int report_action(struct region * r, struct unit * actor, struct message * msg, int flags); + + extern size_t f_regionid(const struct region * r, const struct faction * f, char * buffer, size_t size); + + extern const char * combatstatus[]; +#define GR_PLURAL 0x01 /* grammar: plural */ +#define MAX_INVENTORY 128 /* maimum number of different items in an inventory */ +#define MAX_RAWMATERIALS 8 /* maximum kinds of raw materials in a regions */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/resources.c b/src/kernel/resources.c index 81620ba46..999ff1671 100644 --- a/src/kernel/resources.c +++ b/src/kernel/resources.c @@ -1,208 +1,208 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "resources.h" - -/* kernel includes */ -#include "build.h" -#include "item.h" -#include "region.h" -#include "terrain.h" - -#include -#include - -#include -#include -#include - -static double -ResourceFactor(void) -{ - static double value = -1.0; - if (value<0) { - const char * str = get_param(global.parameters, "resource.factor"); - value = str?atof(str):1.0; - } - return value; -} - -void -update_resources(region * r) -{ - struct rawmaterial * res = r->resources; - while (res) { - if (res->type->update) res->type->update(res, r); - res = res->next; - } -} - -extern int dice_rand(const char *s); - -static void -update_resource(struct rawmaterial * res, double modifier) -{ - double amount = 1 + (res->level-res->startlevel) * res->divisor/100.0; - amount = ResourceFactor() * res->base * amount * modifier; - if (amount<1.0) res->amount = 1; - else res->amount = (int)amount; - assert(res->amount>0); -} - -void -add_resource(region * r, int level, int base, int divisor, const resource_type * rtype) -{ - struct rawmaterial * rm = calloc(sizeof(struct rawmaterial), 1); - - rm->next = r->resources; - r->resources = rm; - rm->level = level; - rm->startlevel = level; - rm->base = base; - rm->divisor = divisor; - rm->flags = 0; - rm->type = rmt_get(rtype); - update_resource(rm, 1.0); - rm->type->terraform(rm, r); -} - -void -terraform_resources(region * r) -{ - int i; - const terrain_type * terrain = r->terrain; - - if (terrain->production==NULL) return; - for (i=0;terrain->production[i].type; ++i) { - rawmaterial *rm; - const terrain_production * production = terrain->production+i; - const resource_type * rtype = production->type; - - for (rm=r->resources; rm; rm=rm->next) { - if (rm->type->rtype == rtype) break; - } - if (rm) continue; - - if (chance(production->chance)) { - add_resource(r, dice_rand(production->startlevel), dice_rand(production->base), dice_rand(production->divisor), production->type); - } - } -} - -static void -terraform_default(struct rawmaterial * res, const region * r) -{ -#define SHIFT 70 - double modifier = 1.0 + ((rng_int() % (SHIFT*2+1)) - SHIFT) * ((rng_int() % (SHIFT*2+1)) - SHIFT) / 10000.0; - res->amount = (int)(res->amount*modifier); /* random adjustment, +/- 91% */ - if (res->amount<1) res->amount=1; - unused(r); -} - -#ifdef RANDOM_CHANGE -static void -resource_random_change(int *pvalue, boolean used) -{ - int split = 5; - int rnd = rng_int()%100; - - if (pvalue==0 || rnd %10 >= 10) return; - if (used) split = 4; - /* if a resource was mined this round, there is a 6% probability - * of a decline and a 4% probability of a raise. */ - /* if it wasn't mined this round, there is an equal probability - * of 5% for a decline or a raise. */ - if(rnd < split) { - (*pvalue)++; - } else { - (*pvalue)--; - } - if ((*pvalue) < 0) (*pvalue) = 0; -} -#endif - -static int -visible_default(const rawmaterial *res, int skilllevel) -/* resources are visible, if skill equals minimum skill to mine them - * plus current level of difficulty */ -{ - const struct item_type * itype = res->type->rtype->itype; - if (res->level<=1 && res->level + itype->construction->minskill <= skilllevel+1) { - assert (res->amount>0); - return res->amount; - } else if (res->level + itype->construction->minskill <= skilllevel+2) { - assert (res->amount>0); - return res->amount; - } - return -1; -} - -static void -use_default(rawmaterial *res, const region * r, int amount) -{ - assert(res->amount>0 && amount>=0 && amount <= res->amount); - res->amount-=amount; - while (res->amount==0) { - double modifier = 1.0 + ((rng_int() % (SHIFT*2+1)) - SHIFT) * ((rng_int() % (SHIFT*2+1)) - SHIFT) / 10000.0; - int i; - - for (i=0;r->terrain->production[i].type;++i) { - if (res->type->rtype == r->terrain->production[i].type) break; - } - - ++res->level; - update_resource(res, modifier); - } -} - -struct rawmaterial * -rm_get(region * r, const struct resource_type * rtype) -{ - struct rawmaterial * rm = r->resources; - while (rm && rm->type->rtype!=rtype) rm = rm->next; - return rm; -} - -struct rawmaterial_type * rawmaterialtypes = 0; - -struct rawmaterial_type * -rmt_find(const char * str) -{ - rawmaterial_type * rmt = rawmaterialtypes; - while (rmt && strcmp(rmt->name, str)!=0) rmt = rmt->next; - return rmt; -} - -struct rawmaterial_type * -rmt_get(const struct resource_type * rtype) -{ - rawmaterial_type * rmt = rawmaterialtypes; - while (rmt && rmt->rtype!=rtype) rmt = rmt->next; - return rmt; -} - -struct rawmaterial_type * -rmt_create(const struct resource_type * rtype, const char * name) -{ - rawmaterial_type * rmtype = malloc(sizeof(rawmaterial_type)); - rmtype->name = strdup(name); - rmtype->rtype = rtype; - rmtype->terraform = terraform_default; - rmtype->update = NULL; - rmtype->use = use_default; - rmtype->visible = visible_default; - rmtype->next = rawmaterialtypes; - rawmaterialtypes = rmtype; - return rmtype; -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "resources.h" + +/* kernel includes */ +#include "build.h" +#include "item.h" +#include "region.h" +#include "terrain.h" + +#include +#include + +#include +#include +#include + +static double +ResourceFactor(void) +{ + static double value = -1.0; + if (value<0) { + const char * str = get_param(global.parameters, "resource.factor"); + value = str?atof(str):1.0; + } + return value; +} + +void +update_resources(region * r) +{ + struct rawmaterial * res = r->resources; + while (res) { + if (res->type->update) res->type->update(res, r); + res = res->next; + } +} + +extern int dice_rand(const char *s); + +static void +update_resource(struct rawmaterial * res, double modifier) +{ + double amount = 1 + (res->level-res->startlevel) * res->divisor/100.0; + amount = ResourceFactor() * res->base * amount * modifier; + if (amount<1.0) res->amount = 1; + else res->amount = (int)amount; + assert(res->amount>0); +} + +void +add_resource(region * r, int level, int base, int divisor, const resource_type * rtype) +{ + struct rawmaterial * rm = calloc(sizeof(struct rawmaterial), 1); + + rm->next = r->resources; + r->resources = rm; + rm->level = level; + rm->startlevel = level; + rm->base = base; + rm->divisor = divisor; + rm->flags = 0; + rm->type = rmt_get(rtype); + update_resource(rm, 1.0); + rm->type->terraform(rm, r); +} + +void +terraform_resources(region * r) +{ + int i; + const terrain_type * terrain = r->terrain; + + if (terrain->production==NULL) return; + for (i=0;terrain->production[i].type; ++i) { + rawmaterial *rm; + const terrain_production * production = terrain->production+i; + const resource_type * rtype = production->type; + + for (rm=r->resources; rm; rm=rm->next) { + if (rm->type->rtype == rtype) break; + } + if (rm) continue; + + if (chance(production->chance)) { + add_resource(r, dice_rand(production->startlevel), dice_rand(production->base), dice_rand(production->divisor), production->type); + } + } +} + +static void +terraform_default(struct rawmaterial * res, const region * r) +{ +#define SHIFT 70 + double modifier = 1.0 + ((rng_int() % (SHIFT*2+1)) - SHIFT) * ((rng_int() % (SHIFT*2+1)) - SHIFT) / 10000.0; + res->amount = (int)(res->amount*modifier); /* random adjustment, +/- 91% */ + if (res->amount<1) res->amount=1; + unused(r); +} + +#ifdef RANDOM_CHANGE +static void +resource_random_change(int *pvalue, boolean used) +{ + int split = 5; + int rnd = rng_int()%100; + + if (pvalue==0 || rnd %10 >= 10) return; + if (used) split = 4; + /* if a resource was mined this round, there is a 6% probability + * of a decline and a 4% probability of a raise. */ + /* if it wasn't mined this round, there is an equal probability + * of 5% for a decline or a raise. */ + if(rnd < split) { + (*pvalue)++; + } else { + (*pvalue)--; + } + if ((*pvalue) < 0) (*pvalue) = 0; +} +#endif + +static int +visible_default(const rawmaterial *res, int skilllevel) +/* resources are visible, if skill equals minimum skill to mine them + * plus current level of difficulty */ +{ + const struct item_type * itype = res->type->rtype->itype; + if (res->level<=1 && res->level + itype->construction->minskill <= skilllevel+1) { + assert (res->amount>0); + return res->amount; + } else if (res->level + itype->construction->minskill <= skilllevel+2) { + assert (res->amount>0); + return res->amount; + } + return -1; +} + +static void +use_default(rawmaterial *res, const region * r, int amount) +{ + assert(res->amount>0 && amount>=0 && amount <= res->amount); + res->amount-=amount; + while (res->amount==0) { + double modifier = 1.0 + ((rng_int() % (SHIFT*2+1)) - SHIFT) * ((rng_int() % (SHIFT*2+1)) - SHIFT) / 10000.0; + int i; + + for (i=0;r->terrain->production[i].type;++i) { + if (res->type->rtype == r->terrain->production[i].type) break; + } + + ++res->level; + update_resource(res, modifier); + } +} + +struct rawmaterial * +rm_get(region * r, const struct resource_type * rtype) +{ + struct rawmaterial * rm = r->resources; + while (rm && rm->type->rtype!=rtype) rm = rm->next; + return rm; +} + +struct rawmaterial_type * rawmaterialtypes = 0; + +struct rawmaterial_type * +rmt_find(const char * str) +{ + rawmaterial_type * rmt = rawmaterialtypes; + while (rmt && strcmp(rmt->name, str)!=0) rmt = rmt->next; + return rmt; +} + +struct rawmaterial_type * +rmt_get(const struct resource_type * rtype) +{ + rawmaterial_type * rmt = rawmaterialtypes; + while (rmt && rmt->rtype!=rtype) rmt = rmt->next; + return rmt; +} + +struct rawmaterial_type * +rmt_create(const struct resource_type * rtype, const char * name) +{ + rawmaterial_type * rmtype = malloc(sizeof(rawmaterial_type)); + rmtype->name = strdup(name); + rmtype->rtype = rtype; + rmtype->terraform = terraform_default; + rmtype->update = NULL; + rmtype->use = use_default; + rmtype->visible = visible_default; + rmtype->next = rawmaterialtypes; + rawmaterialtypes = rmtype; + return rmtype; +} diff --git a/src/kernel/resources.h b/src/kernel/resources.h index 5e1333c78..9c99ad6f8 100644 --- a/src/kernel/resources.h +++ b/src/kernel/resources.h @@ -1,63 +1,63 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ -#ifndef H_KRNL_RESOURCES -#define H_KRNL_RESOURCES -#ifdef __cplusplus -extern "C" { -#endif - -enum { - RM_USED = 1<<0, /* resource has been used */ - RM_MALLORN = 1<<1 /* this is not wood. it's mallorn */ -}; - -typedef struct rawmaterial { - const struct rawmaterial_type * type; - int amount : 16; - int level : 8; - int flags : 8; - int base : 8; - int divisor : 8; - int startlevel : 8; - struct rawmaterial * next; -} rawmaterial; - -typedef struct rawmaterial_type { - char * name; - const struct resource_type * rtype; - - void (*terraform) (struct rawmaterial *, const struct region *); - void (*update) (struct rawmaterial *, const struct region *); - void (*use) (struct rawmaterial *, const struct region *, int amount); - int (*visible) (const struct rawmaterial *, int skilllevel); - - /* no initialization required */ - struct rawmaterial_type * next; -} rawmaterial_type; - -extern struct rawmaterial_type * rawmaterialtypes; - -extern void update_resources(struct region * r); -extern void terraform_resources(struct region * r); -extern void read_resources(struct region * r); -extern void write_resources(struct region * r); -extern struct rawmaterial * rm_get(struct region *, const struct resource_type *); -extern struct rawmaterial_type * rmt_find(const char * str); -extern struct rawmaterial_type * rmt_get(const struct resource_type *); - -extern void add_resource(struct region * r, int level, int base, int divisor, const struct resource_type * rtype); -extern struct rawmaterial_type * rmt_create(const struct resource_type * rtype, const char * name); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#ifndef H_KRNL_RESOURCES +#define H_KRNL_RESOURCES +#ifdef __cplusplus +extern "C" { +#endif + +enum { + RM_USED = 1<<0, /* resource has been used */ + RM_MALLORN = 1<<1 /* this is not wood. it's mallorn */ +}; + +typedef struct rawmaterial { + const struct rawmaterial_type * type; + int amount : 16; + int level : 8; + int flags : 8; + int base : 8; + int divisor : 8; + int startlevel : 8; + struct rawmaterial * next; +} rawmaterial; + +typedef struct rawmaterial_type { + char * name; + const struct resource_type * rtype; + + void (*terraform) (struct rawmaterial *, const struct region *); + void (*update) (struct rawmaterial *, const struct region *); + void (*use) (struct rawmaterial *, const struct region *, int amount); + int (*visible) (const struct rawmaterial *, int skilllevel); + + /* no initialization required */ + struct rawmaterial_type * next; +} rawmaterial_type; + +extern struct rawmaterial_type * rawmaterialtypes; + +extern void update_resources(struct region * r); +extern void terraform_resources(struct region * r); +extern void read_resources(struct region * r); +extern void write_resources(struct region * r); +extern struct rawmaterial * rm_get(struct region *, const struct resource_type *); +extern struct rawmaterial_type * rmt_find(const char * str); +extern struct rawmaterial_type * rmt_get(const struct resource_type *); + +extern void add_resource(struct region * r, int level, int base, int divisor, const struct resource_type * rtype); +extern struct rawmaterial_type * rmt_create(const struct resource_type * rtype, const char * name); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/save.c b/src/kernel/save.c index b303acb16..67c268d45 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1,1889 +1,1890 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "save.h" - -#include "alchemy.h" -#include "alliance.h" -#include "connection.h" -#include "building.h" -#include "faction.h" -#include "group.h" -#include "item.h" -#include "magic.h" -#include "message.h" -#include "move.h" -#include "objtypes.h" -#include "order.h" -#include "pathfinder.h" -#include "plane.h" -#include "race.h" -#include "region.h" -#include "resources.h" -#include "ship.h" -#include "skill.h" -#include "spell.h" -#include "terrain.h" -#include "terrainid.h" /* only for conversion code */ -#include "unit.h" -#include "version.h" - -#include "textstore.h" -#include "binarystore.h" - -/* attributes includes */ -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include - -#define xisdigit(c) (((c) >= '0' && (c) <= '9') || (c) == '-') - -#define ESCAPE_FIX -#define MAXORDERS 256 -#define MAXPERSISTENT 128 - -/* exported symbols symbols */ -const char * game_name = "eressea"; -int firstx = 0, firsty = 0; -int enc_gamedata = 0; - -/* local symbols */ -static region * current_region; - -char * -rns(FILE * f, char *c, size_t size) -{ - char * s = c; - do { - *s = (char) getc(f); - } while (*s!='"'); - - for (;;) { - *s = (char) getc(f); - if (*s=='"') break; - if (s0) str+=ret; - else { - log_error(("input data was not iso-8859-1! assuming utf-8\n")); - encoding = ENCODING_ERROR; - *str++ = (char)c; - } - } else { - *str++ = (char)c; - } - } - } - break; - default: - if ((size_t)(str-start+1)0) str+=ret; - else { - log_error(("input data was not iso-8859-1! assuming utf-8\n")); - encoding = ENCODING_ERROR; - *str++ = (char)c; - } - } else { - *str++ = (char)c; - } - } - } - } -} - - -/** writes a quoted string to the file -* no trailing space, since this is used to make the creport. -*/ -int -fwritestr(FILE * F, const char * str) -{ - int nwrite = 0; - fputc('\"', F); - if (str) while (*str) { - int c = (int)(unsigned char)*str++; - switch (c) { - case '"': - case '\\': - fputc('\\', F); - fputc(c, F); - nwrite+=2; - break; - case '\n': - fputc('\\', F); - fputc('n', F); - nwrite+=2; - break; - default: - fputc(c, F); - ++nwrite; - } - } - fputc('\"', F); - return nwrite + 2; -} - -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->race == new_race[RC_SPELL]) return 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; - if (!is_repeated(ord)) { - *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]) { - const char * stok = s; - stok = parse_token(&stok); - - if (stok) { - boolean 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; - } - } - if (quit) break; - } - /* Nun wird der Befehl erzeut und eingehängt */ - *ordp = parse_order(s, u->faction->locale); - if (*ordp) ordp = &(*ordp)->next; - } - } - - } else { - /* cmistake(?, buf, 160, MSG_EVENT); */ - return NULL; - } - return u; -} - -static faction * -factionorders(void) -{ - faction * f = NULL; - int fid = getid(); - - f = findfaction(fid); - - if (f!=NULL && !is_monsters(f)) { - const char * pass = getstrtoken(); - - if (!checkpasswd(f, (const char *)pass, true)) { - log_warning(("Invalid password for faction %s\n", itoa36(fid))); - ADDMSG(&f->msgs, msg_message("wrongpasswd", "faction password", - f->no, pass)); - return 0; - } - /* Die Partei hat sich zumindest gemeldet, so daß sie noch - * nicht als untätig gilt */ - - /* TODO: +1 ist ein Workaround, weil cturn erst in process_orders - * incrementiert wird. */ - f->lastorders = global.data_turn+1; - - } else { - log_warning(("orders for invalid faction %s\n", itoa36(fid))); - } - return f; -} - -double -version(void) -{ - return RELEASE_VERSION * 0.1; -} -/* ------------------------------------------------------------- */ - -static param_t -igetparam (const char *s, const struct locale *lang) -{ - return findparam (igetstrtoken (s), lang); -} - -int -readorders(const char *filename) -{ - FILE * F = NULL; - const char *b; - int nfactions=0; - struct faction *f = NULL; - - if (filename) F = cfopen(filename, "rb"); - if (F==NULL) return 0; - - if (verbosity>=1) puts(" - lese Befehlsdatei...\n"); - - /* TODO: recognize UTF8 BOM */ - b = getbuf(F, enc_gamedata); - - /* Auffinden der ersten Partei, und danach abarbeiten bis zur letzten - * Partei */ - - while (b) { - const struct locale * lang = f?f->locale:default_locale; - int p; - const char * s; - - switch (igetparam(b, lang)) { - case P_LOCALE: - s = getstrtoken(); -#undef LOCALE_CHANGE -#ifdef LOCALE_CHANGE - if (f && find_locale(s)) { - f->locale = find_locale(s); - } -#endif - - b = getbuf(F, enc_gamedata); - break; - 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; - p = igetparam(b, lang); - } 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 - * muß buf erneut gefüllt werden, da die betreffende Information in nur - * einer Zeile steht, und nun die nächste gelesen werden muß. */ - - case P_NEXT: - f = NULL; - b = getbuf(F, enc_gamedata); - break; - - default: - b = getbuf(F, enc_gamedata); - break; - } - } - - fclose(F); - puts("\n"); - log_printf(" %d Befehlsdateien gelesen\n", nfactions); - return 0; -} -/* ------------------------------------------------------------- */ - -/* #define INNER_WORLD */ -/* fürs debuggen nur den inneren Teil der Welt laden */ -/* -9;-27;-1;-19;Sumpfloch */ -int -inner_world(region * r) -{ - static int xy[2] = - {18, -45}; - static int size[2] = - {27, 27}; - - if (r->x >= xy[0] && r->x < xy[0] + size[0] && r->y >= xy[1] && r->y < xy[1] + size[1]) - return 2; - if (r->x >= xy[0] - 9 && r->x < xy[0] + size[0] + 9 && r->y >= xy[1] - 9 && r->y < xy[1] + size[1] + 9) - return 1; - return 0; -} - -int maxregions = -1; -int loadplane = 0; - -enum { - U_MAN, - U_UNDEAD, - U_ILLUSION, - U_FIREDRAGON, - U_DRAGON, - U_WYRM, - U_SPELL, - U_TAVERNE, - U_MONSTER, - U_BIRTHDAYDRAGON, - U_TREEMAN, - MAXTYPES -}; - -race_t -typus2race(unsigned char typus) -{ - if (typus>0 && typus <=11) return (race_t)(typus-1); - return NORACE; -} - -void -create_backup(char *file) -{ -#ifdef HAVE_LINK - char bfile[MAX_PATH]; - int c = 1; - - if (access(file, R_OK) == 0) return; - do { - sprintf(bfile, "%s.backup%d", file, c); - c++; - } while(access(bfile, R_OK) == 0); - link(file, bfile); -#endif -} - -void -read_items(struct storage * store, item **ilist) -{ - for (;;) { - char ibuf[32]; - const item_type * itype; - int i; - store->r_str_buf(store, ibuf, sizeof(ibuf)); - if (!strcmp("end", ibuf)) break; - itype = it_find(ibuf); - i = store->r_int(store); - if (i<=0) { - log_error(("data contains an entry with %d %s\n", i, itype->rtype->_name[1])); - } else { - assert(itype!=NULL); - if (itype!=NULL) { - i_change(ilist, itype, i); - } - } - } -} - -static void -read_alliances(struct storage * store) -{ - char pbuf[8]; - int id, terminator = 0; - if (store->versionversionr_str_buf(store, pbuf, sizeof(pbuf)); - id = atoi36(pbuf); - } else { - id = store->r_id(store); - } - while (id!=terminator) { - char aname[128]; - alliance * al; - store->r_str_buf(store, aname, sizeof(aname)); - al = makealliance(id, aname); - if (store->version>=OWNER_2_VERSION) { - al->flags = store->r_int(store); - } - if (store->version>=ALLIANCELEADER_VERSION) { - read_reference(&al->_leader, store, read_faction_reference, resolve_faction); - id = store->r_id(store); - } else{ - store->r_str_buf(store, pbuf, sizeof(pbuf)); - id = atoi36(pbuf); - } - } -} - -void -write_alliances(struct storage * store) -{ - alliance * al = alliances; - while (al) { - if (al->_leader) { - store->w_id(store, al->id); - store->w_str(store, al->name); - store->w_int(store, (int)al->flags); - write_faction_reference(al->_leader, store); - store->w_brk(store); - } - al = al->next; - } - store->w_id(store, 0); - store->w_brk(store); -} - -void -write_items(struct storage * store, item *ilist) -{ - item * itm; - for (itm=ilist;itm;itm=itm->next) { - assert(itm->number>=0); - if (itm->number) { - store->w_tok(store, resourcename(itm->type->rtype, 0)); - store->w_int(store, itm->number); - } - } - store->w_tok(store, "end"); -} - -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)\n", itoa36(id.i))); - f = get_monsters(); - } - } - owner->owner = f; - if (f) { - owner->alliance = f->alliance; - } - return result; -} - -static void -read_owner(struct storage * store, region_owner **powner) -{ - int since_turn = store->r_int(store); - if (since_turn>=0) { - region_owner * owner = malloc(sizeof(region_owner)); - owner->since_turn = since_turn; - owner->morale_turn = store->r_int(store); - if (store->version>=MOURNING_VERSION) { - owner->flags = store->r_int(store); - } else { - owner->flags = 0; - } - if (store->version>=OWNER_2_VERSION) { - int id = store->r_int(store); - owner->alliance = id?findalliance(id):NULL; - } else { - owner->alliance = NULL; - } - read_reference(owner, store, &read_faction_reference, &resolve_owner); - *powner = owner; - } else { - *powner = 0; - } -} - -static void -write_owner(struct storage * store, region_owner *owner) -{ - if (owner) { - store->w_int(store, owner->since_turn); - store->w_int(store, owner->morale_turn); - store->w_int(store, owner->flags); - store->w_id(store, owner->alliance?owner->alliance->id:0); - write_faction_reference(owner->owner, store); - } else { - store->w_int(store, -1); - } -} - -int -current_turn(void) -{ - char zText[MAX_PATH]; - int cturn = 0; - FILE * f; - - sprintf(zText, "%s/turn", basepath()); - f = cfopen(zText, "r"); - if (f) { - fscanf(f, "%d\n", &cturn); - fclose(f); - } - return cturn; -} - -static void -writeorder(struct storage * store, const struct order * ord, const struct locale * lang) -{ - char obuf[1024]; - write_order(ord, obuf, sizeof(obuf)); - if (obuf[0]) store->w_str(store, obuf); -} - -unit * -read_unit(struct storage * store) -{ - skill_t sk; - unit * u; - int number, n, p; - order ** orderp; - char obuf[1024]; - faction * f; - char rname[32]; - - n = store->r_id(store); - if (n<=0) return NULL; - u = findunit(n); - if (u==NULL) { - u = calloc(sizeof(unit), 1); - u->no = n; - uhash(u); - } else { - while (u->attribs) a_remove(&u->attribs, u->attribs); - while (u->items) i_free(i_remove(&u->items, u->items)); - free(u->skills); - u->skills = 0; - u->skill_size = 0; - u_setfaction(u, NULL); - } - - n = store->r_id(store); - f = findfaction(n); - if (f!=u->faction) u_setfaction(u, f); - - u->name = store->r_str(store); - if (lomem) { - store->r_str_buf(store, NULL, 0); - } else { - u->display = store->r_str(store); - } - number = store->r_int(store); - u->age = (short)store->r_int(store); - - if (store->versionr_str_buf(store, rname, sizeof(rname)); - space = strchr(rname, ' '); - if (space!=NULL) { - char * inc = space+1; - char * outc = space; - do { - while (*inc==' ') ++inc; - while (*inc) { - *outc++ = *inc++; - if (*inc==' ') break; - } - } while (*inc); - *outc = 0; - } - } else { - store->r_tok_buf(store, rname, sizeof(rname)); - } - u->race = rc_find(rname); - assert(u->race); - if (store->versionr_str_buf(store, rname, sizeof(rname)); - } else { - store->r_tok_buf(store, rname, sizeof(rname)); - } - if (rname[0] && skill_enabled[SK_STEALTH]) u->irace = rc_find(rname); - else u->irace = NULL; - - if (u->race->describe) { - const char * rcdisp = u->race->describe(u, u->faction->locale); - if (u->display && rcdisp) { - /* see if the data file contains old descriptions */ - if (strcmp(rcdisp, u->display)==0) { - free(u->display); - u->display = NULL; - } - } - } - if (u->faction == NULL) { - log_error(("unit %s has faction == NULL\n", unitname(u))); - u_setfaction(u, get_monsters()); - set_number(u, 0); - } - - if (count_unit(u) && u->faction) u->faction->no_units++; - - set_number(u, number); - - n = store->r_id(store); - if (n>0) u->building = findbuilding(n); - - n = store->r_id(store); - if (n>0) u->ship = findship(n); - - setstatus(u, store->r_int(store)); - u->flags = store->r_int(store); - u->flags &= UFL_SAVEMASK; - if ((u->flags&UFL_ANON_FACTION) && !rule_stealth_faction()) { - /* if this rule is broken, then fix broken units */ - u->flags -= UFL_ANON_FACTION; - log_warning(("%s was anonymous.\n", unitname(u))); - } - /* Persistente Befehle einlesen */ - free_orders(&u->orders); - store->r_str_buf(store, obuf, sizeof(obuf)); - p = n = 0; - orderp = &u->orders; - while (obuf[0]) { - if (!lomem) { - order * ord = parse_order(obuf, u->faction->locale); - if (ord!=NULL) { - if (++nnext; - ord = NULL; - } else if (p==MAXPERSISTENT) { - log_warning(("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT)); - } - } else if (n==MAXORDERS) { - log_warning(("%s had %d or more orders\n", unitname(u), MAXORDERS)); - } - if (ord!=NULL) free_order(ord); - } - } - store->r_str_buf(store, obuf, sizeof(obuf)); - } - if (store->versionr_str_buf(store, obuf, sizeof(obuf)); - ord = parse_order(obuf, u->faction->locale); - if (ord!=NULL) { - addlist(&u->orders, ord); - } - } - set_order(&u->thisorder, NULL); - - assert(u->race); - while ((sk = (skill_t) store->r_int(store)) != NOSKILL) { - int level = store->r_int(store); - int weeks = store->r_int(store); - if (level) { - skill * sv = add_skill(u, sk); - sv->level = sv->old = (unsigned char)level; - sv->weeks = (unsigned char)weeks; - } - } - read_items(store, &u->items); - u->hp = store->r_int(store); - if (u->hp < u->number) { - log_error(("Einheit %s hat %u Personen, und %u Trefferpunkte\n", itoa36(u->no), - u->number, u->hp)); - u->hp=u->number; - } - - a_read(store, &u->attribs, u); - return u; -} - -void -write_unit(struct storage * store, const unit * u) -{ - order * ord; - int i, p = 0; - const race * irace = u_irace(u); - write_unit_reference(u, store); - write_faction_reference(u->faction, store); - store->w_str(store, (const char *)u->name); - store->w_str(store, u->display?(const char *)u->display:""); - store->w_int(store, u->number); - store->w_int(store, u->age); - store->w_tok(store, u->race->_name[0]); - store->w_tok(store, (irace && irace!=u->race)?irace->_name[0]:""); - write_building_reference(u->building, store); - write_ship_reference(u->ship, store); - store->w_int(store, u->status); - store->w_int(store, u->flags & UFL_SAVEMASK); - store->w_brk(store); - for (ord = u->old_orders; ord; ord=ord->next) { - if (++pfaction->locale); - } else { - log_error(("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT)); - break; - } - } - for (ord = u->orders; ord; ord=ord->next) { - if (u->old_orders && is_repeated(ord)) continue; /* has new defaults */ - if (is_persistent(ord)) { - if (++pfaction->locale); - } else { - log_error(("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT)); - break; - } - } - } - /* write an empty string to terminate the list */ - store->w_str(store, ""); - store->w_brk(store); - - assert(u->race); - - for (i=0;i!=u->skill_size;++i) { - skill * sv = u->skills+i; - assert(sv->weeks<=sv->level*2+1); - if (sv->level>0) { - store->w_int(store, sv->id); - store->w_int(store, sv->level); - store->w_int(store, sv->weeks); - } - } - store->w_int(store, -1); - store->w_brk(store); - write_items(store, u->items); - store->w_brk(store); - if (u->hp == 0) { - log_error(("unit %s has 0 hitpoints, adjusting.\n", itoa36(u->no))); - ((unit*)u)->hp = u->number; - } - store->w_int(store, u->hp); - store->w_brk(store); - a_write(store, u->attribs, u); - store->w_brk(store); -} - -static region * -readregion(struct storage * store, int x, int y) -{ - region * r = findregion(x, y); - const terrain_type * terrain; - char token[32]; - unsigned int uid = 0; - - if (store->version>=UID_VERSION) { - uid = store->r_int(store); - } - - if (r==NULL) { - plane * pl = findplane(x, y); - r = new_region(x, y, pl, uid); - } else { - assert(uid==0 || r->uid==uid); - current_region = r; - while (r->attribs) a_remove(&r->attribs, r->attribs); - if (r->land) { - free(r->land); /* mem leak */ - r->land->demands = 0; /* mem leak */ - } - while (r->resources) { - rawmaterial * rm = r->resources; - r->resources = rm->next; - free(rm); - } - r->land = 0; - } - if (lomem) { - store->r_str_buf(store, NULL, 0); - } else { - char info[DISPLAYSIZE]; - store->r_str_buf(store, info, sizeof(info)); - region_setinfo(r, info); - } - - if (store->version < TERRAIN_VERSION) { - int ter = store->r_int(store); - terrain = newterrain((terrain_t)ter); - if (terrain==NULL) { - log_error(("while reading datafile from pre-TERRAIN_VERSION, could not find terrain #%d.\n", ter)); - terrain = newterrain(T_PLAIN); - } - } else { - char name[64]; - store->r_str_buf(store, name, sizeof(name)); - terrain = get_terrain(name); - if (terrain==NULL) { - log_error(("Unknown terrain '%s'\n", name)); - assert(!"unknown terrain"); - } - } - r->terrain = terrain; - r->flags = (char) store->r_int(store); - - r->age = (unsigned short) store->r_int(store); - - if (fval(r->terrain, LAND_REGION)) { - r->land = calloc(1, sizeof(land_region)); - r->land->name = store->r_str(store); - } - if (r->land) { - int i; - rawmaterial ** pres = &r->resources; - - i = store->r_int(store); - if (i<0) { - log_error(("number of trees in %s is %d.\n", - regionname(r, NULL), i)); - i=0; - } - rsettrees(r, 0, i); - i = store->r_int(store); - if (i<0) { - log_error(("number of young trees in %s is %d.\n", - regionname(r, NULL), i)); - i=0; - } - rsettrees(r, 1, i); - i = store->r_int(store); - if (i<0) { - log_error(("number of seeds in %s is %d.\n", - regionname(r, NULL), i)); - i=0; - } - rsettrees(r, 2, i); - - i = store->r_int(store); rsethorses(r, i); - assert(*pres==NULL); - for (;;) { - rawmaterial * res; - store->r_str_buf(store, token, sizeof(token)); - if (strcmp(token, "end")==0) break; - res = malloc(sizeof(rawmaterial)); - res->type = rmt_find(token); - if (res->type==NULL) { - log_error(("invalid resourcetype %s in data.\n", token)); - } - assert(res->type!=NULL); - res->level = store->r_int(store); - res->amount = store->r_int(store); - res->flags = 0; - - res->startlevel = store->r_int(store); - res->base = store->r_int(store); - res->divisor = store->r_int(store); - - *pres = res; - pres=&res->next; - } - *pres = NULL; - - store->r_str_buf(store, token, sizeof(token)); - if (strcmp(token, "noherb") != 0) { - const resource_type * rtype = rt_find(token); - assert(rtype && rtype->itype && fval(rtype->itype, ITF_HERB)); - rsetherbtype(r, rtype->itype); - } else { - rsetherbtype(r, NULL); - } - rsetherbs(r, (short)store->r_int(store)); - rsetpeasants(r, store->r_int(store)); - rsetmoney(r, store->r_int(store)); - } - - assert(r->terrain!=NULL); - assert(rhorses(r) >= 0); - assert(rpeasants(r) >= 0); - assert(rmoney(r) >= 0); - - if (r->land) { - for (;;) { - const struct item_type * itype; - store->r_str_buf(store, token, sizeof(token)); - if (!strcmp(token, "end")) break; - itype = it_find(token); - assert(itype->rtype->ltype); - r_setdemand(r, itype->rtype->ltype, store->r_int(store)); - } - if (store->version>=REGIONITEMS_VERSION) { - read_items(store, &r->land->items); - } - if (store->version>=REGIONOWNER_VERSION) { - r->land->morale = (short)store->r_int(store); - if (r->land->morale<0) r->land->morale = 0; - read_owner(store, &r->land->ownership); - } - } - a_read(store, &r->attribs, r); - - return r; -} - -void -writeregion(struct storage * store, const region * r) -{ - store->w_int(store, r->uid); - store->w_str(store, region_getinfo(r)); - store->w_tok(store, r->terrain->_name); - store->w_int(store, r->flags & RF_SAVEMASK); - store->w_int(store, r->age); - store->w_brk(store); - if (fval(r->terrain, LAND_REGION)) { - const item_type *rht; - struct demand * demand; - rawmaterial * res = r->resources; - store->w_str(store, (const char *)r->land->name); - assert(rtrees(r,0)>=0); - assert(rtrees(r,1)>=0); - assert(rtrees(r,2)>=0); - store->w_int(store, rtrees(r,0)); - store->w_int(store, rtrees(r,1)); - store->w_int(store, rtrees(r,2)); - store->w_int(store, rhorses(r)); - - while (res) { - store->w_tok(store, res->type->name); - store->w_int(store, res->level); - store->w_int(store, res->amount); - store->w_int(store, res->startlevel); - store->w_int(store, res->base); - store->w_int(store, res->divisor); - res = res->next; - } - store->w_tok(store, "end"); - - rht = rherbtype(r); - if (rht) { - store->w_tok(store, resourcename(rht->rtype, 0)); - } else { - store->w_tok(store, "noherb"); - } - store->w_int(store, rherbs(r)); - store->w_int(store, rpeasants(r)); - store->w_int(store, rmoney(r)); - if (r->land) for (demand=r->land->demands; demand; demand=demand->next) { - store->w_tok(store, resourcename(demand->type->itype->rtype, 0)); - store->w_int(store, demand->value); - } - store->w_tok(store, "end"); -#if RELEASE_VERSION>=REGIONITEMS_VERSION - write_items(store, r->land->items); - store->w_brk(store); -#endif -#if RELEASE_VERSION>=REGIONOWNER_VERSION - store->w_int(store, r->land->morale); - write_owner(store, r->land->ownership); - store->w_brk(store); -#endif - } - a_write(store, r->attribs, r); - store->w_brk(store); -} - -static ally ** -addally(const faction * f, ally ** sfp, int aid, int state) -{ - struct faction * af = findfaction(aid); - ally * sf; - - state &= ~HELP_OBSERVE; -#ifndef REGIONOWNERS - state &= ~HELP_TRAVEL; -#endif - state &= HelpMask(); - - if (state==0) return sfp; - - sf = calloc(1, sizeof(ally)); - sf->faction = af; - if (!sf->faction) { - variant id; - id.i = aid; - ur_add(id, &sf->faction, resolve_faction); - } - sf->status = state & HELP_ALL; - - while (*sfp) sfp=&(*sfp)->next; - *sfp = sf; - return &sf->next; -} - -/** Reads a faction from a file. - * This function requires no context, can be called in any state. The - * faction may not already exist, however. - */ -faction * -readfaction(struct storage * store) -{ - ally **sfp; - int planes; - int i = store->r_id(store); - faction * f = findfaction(i); - char email[128]; - char token[32]; - - if (f==NULL) { - f = (faction *) calloc(1, sizeof(faction)); - f->no = i; - } else { - f->allies = NULL; /* mem leak */ - while (f->attribs) a_remove(&f->attribs, f->attribs); - } - f->subscription = store->r_int(store); - - if (alliances || store->version>=OWNER_2_VERSION) { - int allianceid = store->r_id(store); - if (allianceid>0) f->alliance = findalliance(allianceid); - if (f->alliance) { - alliance * al = f->alliance; - faction_list * flist = malloc(sizeof(faction_list)); - if (al->flags&ALF_NON_ALLIED) { - assert(!al->members || !"non-allied dummy-alliance has more than one member"); - } - flist->data = f; - flist->next = al->members; - al->members = flist; - } else if (rule_region_owners()){ - /* compat fix for non-allied factions */ - alliance * al = makealliance(0, NULL); - setalliance(f, al); - } - if (store->version>=OWNER_2_VERSION) { - f->alliance_joindate = store->r_int(store); - } else { - f->alliance_joindate = turn - 10; /* we're guessing something safe here */ - } - } - - f->name = store->r_str(store); - f->banner = store->r_str(store); - - log_info((3, " - Lese Partei %s (%s)\n", f->name, factionid(f))); - - store->r_str_buf(store, email, sizeof(email)); - if (set_email(&f->email, email)!=0) { - log_warning(("Invalid email address for faction %s: %s\n", itoa36(f->no), email)); - set_email(&f->email, ""); - } - - f->passw = store->r_str(store); - if (store->version >= OVERRIDE_VERSION) { - f->override = store->r_str(store); - } else { - f->override = strdup(itoa36(rng_int())); - } - - store->r_str_buf(store, token, sizeof(token)); - f->locale = find_locale(token); - f->lastorders = store->r_int(store); - f->age = store->r_int(store); - store->r_str_buf(store, token, sizeof(token)); - f->race = rc_find(token); - assert(f->race); - f->magiegebiet = (magic_t)store->r_int(store); - - if (store->versionr_int(store); - } - - f->flags = store->r_int(store); - if (f->no==0) { - f->flags |= FFL_NPC; - } - - a_read(store, &f->attribs, f); - if (store->version>=CLAIM_VERSION) { - read_items(store, &f->items); - } - for (;;) { - int level; - store->r_tok_buf(store, token, sizeof(token)); - if (strcmp("end", token)==0) break; - level = store->r_int(store); - } - planes = store->r_int(store); - while(--planes >= 0) { - int id = store->r_int(store); - int ux = store->r_int(store); - int uy = store->r_int(store); - set_ursprung(f, id, ux, uy); - } - f->newbies = 0; - - i = f->options = store->r_int(store); - - if ((i & (want(O_REPORT)|want(O_COMPUTER)))==0 && !is_monsters(f)) { - /* Kein Report eingestellt, Fehler */ - f->options = f->options | want(O_REPORT) | want(O_ZUGVORLAGE); - } - - sfp = &f->allies; - if (store->versionr_int(store); - while (--p >= 0) { - int aid = store->r_id(store); - int state = store->r_int(store); - sfp = addally(f, sfp, aid, state); - } - } else { - for (;;) { - int aid = 0; - if (store->versionr_tok_buf(store, token, sizeof(token)); - if (strcmp(token, "end")!=0) { - aid = atoi36(token); - } - } else { - aid = store->r_id(store); - } - if (aid>0) { - int state = store->r_int(store); - sfp = addally(f, sfp, aid, state); - } else { - break; - } - } - } - read_groups(store, f); - f->spellbook = NULL; - if (store->version>=REGIONOWNER_VERSION) { - read_spellist(&f->spellbook, f->magiegebiet, store); - } - return f; -} - -void -writefaction(struct storage * store, const faction * f) -{ - ally *sf; - ursprung *ur; - - write_faction_reference(f, store); - store->w_int(store, f->subscription); - if (f->alliance) { - store->w_id(store, f->alliance->id); - if (f->alliance->flags&ALF_NON_ALLIED) { - assert(f==f->alliance->_leader || !"non-allied faction is not leader of its own dummy-alliance."); - } - } - else { - store->w_id(store, 0); - } - store->w_int(store, f->alliance_joindate); - - store->w_str(store, (const char *)f->name); - store->w_str(store, (const char *)f->banner); - store->w_str(store, f->email); - store->w_tok(store, (const char *)f->passw); - store->w_tok(store, (const char *)f->override); - store->w_tok(store, locale_name(f->locale)); - store->w_int(store, f->lastorders); - store->w_int(store, f->age); - store->w_tok(store, f->race->_name[0]); - store->w_brk(store); - store->w_int(store, f->magiegebiet); - - store->w_int(store, f->flags&FFL_SAVEMASK); - a_write(store, f->attribs, f); - store->w_brk(store); - write_items(store, f->items); - store->w_brk(store); - store->w_tok(store, "end"); - store->w_brk(store); - store->w_int(store, listlen(f->ursprung)); - for (ur = f->ursprung;ur;ur=ur->next) { - store->w_int(store, ur->id); - store->w_int(store, ur->x); - store->w_int(store, ur->y); - } - store->w_brk(store); - store->w_int(store, f->options & ~want(O_DEBUG)); - store->w_brk(store); - - for (sf = f->allies; sf; sf = sf->next) { - int no = (sf->faction!=NULL)?sf->faction->no:0; - int status = alliedfaction(NULL, f, sf->faction, HELP_ALL); - if (status!=0) { - store->w_id(store, no); - store->w_int(store, sf->status); - } - } - store->w_id(store, 0); - store->w_brk(store); - write_groups(store, f->groups); - write_spelllist(f->spellbook, store); -} - -int -readgame(const char * filename, int mode, int backup) -{ - int i, n, p; - faction *f, **fp; - region *r; - building *b, **bp; - ship **shp; - unit *u; - int rmax = maxregions; - char path[MAX_PATH]; - char token[32]; - const struct building_type * bt_lighthouse = bt_find("lighthouse"); - storage my_store = (mode==IO_BINARY)?binary_store:text_store; - storage * store = &my_store; - - sprintf(path, "%s/%s", datapath(), filename); - log_printf("- reading game data from %s\n", filename); - if (backup) create_backup(path); - - store->encoding = enc_gamedata; - if (store->open(store, path, IO_READ)!=0) { - return -1; - } - enc_gamedata = store->encoding; - - assert(store->version>=MIN_VERSION || !"unsupported data format"); - assert(store->version<=RELEASE_VERSION || !"unsupported data format"); - - if (store->version >= SAVEXMLNAME_VERSION) { - char basefile[1024]; - - store->r_str_buf(store, basefile, sizeof(basefile)); - if (strcmp(game_name, basefile)!=0) { - char buffer[64]; - snprintf(buffer, sizeof(buffer), "%s.xml", game_name); - if (strcmp(basefile, buffer)!=0) { - log_warning(("game mismatch: datafile contains %s, game is %s\n", basefile, game_name)); - printf("WARNING: any key to continue, Ctrl-C to stop\n"); - getchar(); - } - } - } - a_read(store, &global.attribs, NULL); - global.data_turn = turn = store->r_int(store); - log_info((1, " - reading turn %d\n", turn)); - rng_init(turn); - ++global.cookie; - store->r_int(store); /* max_unique_id = */ - nextborder = store->r_int(store); - - /* Planes */ - planes = NULL; - n = store->r_int(store); - while(--n >= 0) { - int id = store->r_int(store); - plane *pl = getplanebyid(id); - if (pl==NULL) { - pl = calloc(1, sizeof(plane)); - } else { - log_warning(("the plane with id=%d already exists.\n", id)); - } - pl->id = id; - pl->name = store->r_str(store); - pl->minx = store->r_int(store); - pl->maxx = store->r_int(store); - pl->miny = store->r_int(store); - pl->maxy = store->r_int(store); - pl->flags = store->r_int(store); - - /* read watchers */ - store->r_str_buf(store, token, sizeof(token)); - while (strcmp(token, "end")!=0) { - watcher * w = calloc(sizeof(watcher),1); - variant fno; - fno.i = atoi36(token); - w->mode = (unsigned char)store->r_int(store); - w->next = pl->watchers; - pl->watchers = w; - ur_add(fno, &w->faction, resolve_faction); - store->r_str_buf(store, token, sizeof(token)); - } - - a_read(store, &pl->attribs, pl); - addlist(&planes, pl); - } - - /* Read factions */ - if (store->version>=ALLIANCES_VERSION) { - read_alliances(store); - } - n = store->r_int(store); - log_info((1, " - Einzulesende Parteien: %d\n", n)); - fp = &factions; - while (*fp) fp=&(*fp)->next; - - while (--n >= 0) { - faction * f = readfaction(store); - - *fp = f; - fp = &f->next; - fhash(f); - } - *fp = 0; - - /* Benutzte Faction-Ids */ - if (store->versionr_int(store); - while (i--) { - store->r_int(store); /* used faction ids. ignore. */ - } - } - - /* Regionen */ - - n = store->r_int(store); - assert(n= 0) { - unit **up; - int x = store->r_int(store); - int y = store->r_int(store); - - if ((n & 0x3FF) == 0) { /* das spart extrem Zeit */ - log_info((2, " - Einzulesende Regionen: %d/%d * %d,%d \r", rmax, n, x, y)); - } - --rmax; - - r = readregion(store, x, y); - - /* Burgen */ - p = store->r_int(store); - bp = &r->buildings; - - while (--p >= 0) { - - b = (building *) calloc(1, sizeof(building)); - b->no = store->r_id(store); - *bp = b; - bp = &b->next; - bhash(b); - b->name = store->r_str(store); - if (lomem) { - store->r_str_buf(store, NULL, 0); - } - else { - b->display = store->r_str(store); - } - b->size = store->r_int(store); - store->r_str_buf(store, token, sizeof(token)); - b->type = bt_find(token); - b->region = r; - a_read(store, &b->attribs, b); - if (b->type==bt_lighthouse) { - r->flags |= RF_LIGHTHOUSE; - } - } - /* Schiffe */ - - p = store->r_int(store); - shp = &r->ships; - - while (--p >= 0) { - ship * sh = (ship *) calloc(1, sizeof(ship)); - sh->region = r; - sh->no = store->r_id(store); - *shp = sh; - shp = &sh->next; - shash(sh); - sh->name = store->r_str(store); - if (lomem) { - store->r_str_buf(store, NULL, 0); - } - else { - sh->display = store->r_str(store); - } - store->r_str_buf(store, token, sizeof(token)); - sh->type = st_find(token); - if (sh->type==NULL) { - /* old datafiles */ - sh->type = st_find((const char *)locale_string(default_locale, token)); - } - assert(sh->type || !"ship_type not registered!"); - sh->size = store->r_int(store); - sh->damage = store->r_int(store); - if (store->version>=FOSS_VERSION) { - sh->flags = store->r_int(store); - } - - /* Attribute rekursiv einlesen */ - - sh->coast = (direction_t)store->r_int(store); - if (sh->type->flags & SFL_NOCOAST) { - sh->coast = NODIRECTION; - } - a_read(store, &sh->attribs, sh); - } - - *shp = 0; - - /* Einheiten */ - - p = store->r_int(store); - up = &r->units; - - while (--p >= 0) { - unit * u = read_unit(store); - sc_mage * mage; - - assert(u->region==NULL); - u->region = r; - *up = u; - up = &u->next; - - update_interval(u->faction, u->region); - mage = get_mage(u); - if (mage) { - faction * f = u->faction; - int skl = effskill(u, SK_MAGIC); - if (!is_monsters(f) && f->magiegebiet==M_GRAY) { - log_error(("faction %s had magic=gray, fixing (%s)\n", - factionname(f), magic_school[mage->magietyp])); - f->magiegebiet = mage->magietyp; - } - if (f->max_spelllevelmax_spelllevel = skl; - } - if (mage->spellcount<0) { - mage->spellcount = 0; - updatespelllist(u); - } - } - } - } - log_info((1, "\n")); - read_borders(store); - - store->close(store); - - /* Unaufgeloeste Zeiger initialisieren */ - log_info((1, "fixing unresolved references.\n")); - resolve(); - - log_info((1, "updating area information for lighthouses.\n")); - for (r=regions;r;r=r->next) { - if (r->flags & RF_LIGHTHOUSE) { - building * b; - for (b=r->buildings;b;b=b->next) update_lighthouse(b); - } - } - log_info((1, "marking factions as alive.\n")); - for (f = factions; f; f = f->next) { - if (f->flags & FFL_NPC) { - f->alive = 1; - if (f->no==0) { - int no=666; - while (findfaction(no)) ++no; - log_warning(("renum(monsters, %d)\n", no)); - renumber_faction(f, no); - } - } else { - for (u = f->units; u; u = u->nextF) { - if (u->number>0) { - f->alive = 1; - break; - } - } - } - } - if (loadplane || maxregions>=0) { - remove_empty_factions(); - } - log_info((1, "Done loading turn %d.\n", turn)); - return 0; -} - -static void -clear_monster_orders(void) -{ - faction * f = get_monsters(); - if (f) { - unit * u; - for (u=f->units;u;u=u->nextF) { - free_orders(&u->orders); - } - } -} - -int -writegame(const char *filename, int mode) -{ - char *base; - int n; - faction *f; - region *r; - building *b; - ship *sh; - unit *u; - plane *pl; - char path[MAX_PATH]; - storage my_store = (mode==IO_BINARY)?binary_store:text_store; - storage * store = &my_store; - store->version = RELEASE_VERSION; - - clear_monster_orders(); - sprintf(path, "%s/%s", datapath(), filename); -#ifdef HAVE_UNISTD_H - if (access(path, R_OK) == 0) { - /* make sure we don't overwrite some hardlinkedfile */ - unlink(path); - } -#endif - - store->encoding = enc_gamedata; - if (store->open(store, path, IO_WRITE)!=0) { - return -1; - } - - /* globale Variablen */ - - base = strrchr(game_name, '/'); - if (base) { - store->w_str(store, base+1); - } else { - store->w_str(store, game_name); - } - store->w_brk(store); - - a_write(store, global.attribs, NULL); - store->w_brk(store); - - store->w_int(store, turn); - store->w_int(store, 0/*max_unique_id*/); - store->w_int(store, nextborder); - - /* Write planes */ - store->w_brk(store); - store->w_int(store, listlen(planes)); - store->w_brk(store); - - for(pl = planes; pl; pl=pl->next) { - watcher * w; - store->w_int(store, pl->id); - store->w_str(store, pl->name); - store->w_int(store, pl->minx); - store->w_int(store, pl->maxx); - store->w_int(store, pl->miny); - store->w_int(store, pl->maxy); - store->w_int(store, pl->flags); - w = pl->watchers; - while (w) { - if (w->faction) { - write_faction_reference(w->faction, store); - store->w_int(store, w->mode); - } - w = w->next; - } - store->w_tok(store, "end"); - a_write(store, pl->attribs, pl); - store->w_brk(store); - } - - - /* Write factions */ -#if RELEASE_VERSION>=ALLIANCES_VERSION - write_alliances(store); -#endif - n = listlen(factions); - store->w_int(store, n); - store->w_brk(store); - - log_info((1, " - Schreibe %d Parteien...\n", n)); - for (f = factions; f; f = f->next) { - writefaction(store, f); - store->w_brk(store); - } - - /* Write regions */ - - n=listlen(regions); - store->w_int(store, n); - store->w_brk(store); - log_info((1, " - Schreibe Regionen: %d \r", n)); - - for (r = regions; r; r = r->next, --n) { - /* plus leerzeile */ - if ((n%1024)==0) { /* das spart extrem Zeit */ - log_info((2, " - Schreibe Regionen: %d \r", n)); - fflush(stdout); - } - store->w_brk(store); - store->w_int(store, r->x); - store->w_int(store, r->y); - writeregion(store, r); - - store->w_int(store, listlen(r->buildings)); - store->w_brk(store); - for (b = r->buildings; b; b = b->next) { - write_building_reference(b, store); - store->w_str(store, b->name); - store->w_str(store, b->display?b->display:""); - store->w_int(store, b->size); - store->w_tok(store, b->type->_name); - store->w_brk(store); - a_write(store, b->attribs, b); - store->w_brk(store); - } - - store->w_int(store, listlen(r->ships)); - store->w_brk(store); - for (sh = r->ships; sh; sh = sh->next) { - assert(sh->region == r); - write_ship_reference(sh, store); - store->w_str(store, (const char *)sh->name); - store->w_str(store, sh->display?(const char *)sh->display:""); - store->w_tok(store, sh->type->name[0]); - store->w_int(store, sh->size); - store->w_int(store, sh->damage); - store->w_int(store, sh->flags & SFL_SAVEMASK); - assert((sh->type->flags & SFL_NOCOAST)==0 || sh->coast == NODIRECTION); - store->w_int(store, sh->coast); - store->w_brk(store); - a_write(store, sh->attribs, sh); - store->w_brk(store); - } - - store->w_int(store, listlen(r->units)); - store->w_brk(store); - for (u = r->units; u; u = u->next) { - write_unit(store, u); - } - } - store->w_brk(store); - write_borders(store); - store->w_brk(store); - - store->close(store); - - log_info((1, "\nOk.\n")); - return 0; -} - -int -a_readint(attrib * a, void * owner, struct storage * store) -{ - /* assert(sizeof(int)==sizeof(a->data)); */ - a->data.i = store->r_int(store); - return AT_READ_OK; -} - -void -a_writeint(const attrib * a, const void * owner, struct storage * store) -{ - store->w_int(store, a->data.i); -} - -int -a_readshorts(attrib * a, void * owner, struct storage * store) -{ - if (store->versiondata.sa[0] = (short)store->r_int(store); - a->data.sa[1] = (short)store->r_int(store); - return AT_READ_OK; -} - -void -a_writeshorts(const attrib * a, const void * owner, struct storage * store) -{ - store->w_int(store, a->data.sa[0]); - store->w_int(store, a->data.sa[1]); -} - -int -a_readchars(attrib * a, void * owner, struct storage * store) -{ - int i; - if (store->versiondata.ca[i] = (char)store->r_int(store); - } - return AT_READ_OK; -} - -void -a_writechars(const attrib * a, const void * owner, struct storage * store) -{ - int i; - - for (i=0;i!=4;++i) { - store->w_int(store, a->data.ca[i]); - } -} - -int -a_readvoid(attrib * a, void * owner, struct storage * store) -{ - if (store->versiondata.v = store->r_str(store); - return AT_READ_OK; -} - -void -a_writestring(const attrib * a, const void * owner, struct storage * store) -{ - assert(a->data.v); - store->w_str(store, (const char *)a->data.v); -} - -void -a_finalizestring(attrib * a) -{ - free(a->data.v); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "save.h" + +#include "alchemy.h" +#include "alliance.h" +#include "connection.h" +#include "building.h" +#include "faction.h" +#include "group.h" +#include "item.h" +#include "magic.h" +#include "message.h" +#include "move.h" +#include "objtypes.h" +#include "order.h" +#include "pathfinder.h" +#include "plane.h" +#include "race.h" +#include "region.h" +#include "resources.h" +#include "ship.h" +#include "skill.h" +#include "spell.h" +#include "terrain.h" +#include "terrainid.h" /* only for conversion code */ +#include "unit.h" +#include "version.h" + +#include "textstore.h" +#include "binarystore.h" + +/* attributes includes */ +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +#define xisdigit(c) (((c) >= '0' && (c) <= '9') || (c) == '-') + +#define ESCAPE_FIX +#define MAXORDERS 256 +#define MAXPERSISTENT 128 + +/* exported symbols symbols */ +const char * game_name = "eressea"; +int firstx = 0, firsty = 0; +int enc_gamedata = 0; + +/* local symbols */ +static region * current_region; + +char * +rns(FILE * f, char *c, size_t size) +{ + char * s = c; + do { + *s = (char) getc(f); + } while (*s!='"'); + + for (;;) { + *s = (char) getc(f); + if (*s=='"') break; + if (s0) str+=ret; + else { + log_error(("input data was not iso-8859-1! assuming utf-8\n")); + encoding = XML_CHAR_ENCODING_ERROR; + *str++ = (char)c; + } + } else { + *str++ = (char)c; + } + } + } + break; + default: + if ((size_t)(str-start+1)0) str+=ret; + else { + log_error(("input data was not iso-8859-1! assuming utf-8\n")); + encoding = XML_CHAR_ENCODING_ERROR; + *str++ = (char)c; + } + } else { + *str++ = (char)c; + } + } + } + } +} + + +/** writes a quoted string to the file +* no trailing space, since this is used to make the creport. +*/ +int +fwritestr(FILE * F, const char * str) +{ + int nwrite = 0; + fputc('\"', F); + if (str) while (*str) { + int c = (int)(unsigned char)*str++; + switch (c) { + case '"': + case '\\': + fputc('\\', F); + fputc(c, F); + nwrite+=2; + break; + case '\n': + fputc('\\', F); + fputc('n', F); + nwrite+=2; + break; + default: + fputc(c, F); + ++nwrite; + } + } + fputc('\"', F); + return nwrite + 2; +} + +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->race == new_race[RC_SPELL]) return 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; + if (!is_repeated(ord)) { + *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]) { + const char * stok = s; + stok = parse_token(&stok); + + if (stok) { + boolean 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; + } + } + if (quit) break; + } + /* Nun wird der Befehl erzeut und eingehängt */ + *ordp = parse_order(s, u->faction->locale); + if (*ordp) ordp = &(*ordp)->next; + } + } + + } else { + /* cmistake(?, buf, 160, MSG_EVENT); */ + return NULL; + } + return u; +} + +static faction * +factionorders(void) +{ + faction * f = NULL; + int fid = getid(); + + f = findfaction(fid); + + if (f!=NULL && !is_monsters(f)) { + const char * pass = getstrtoken(); + + if (!checkpasswd(f, (const char *)pass, true)) { + log_warning(("Invalid password for faction %s\n", itoa36(fid))); + ADDMSG(&f->msgs, msg_message("wrongpasswd", "faction password", + f->no, pass)); + return 0; + } + /* Die Partei hat sich zumindest gemeldet, so daß sie noch + * nicht als untätig gilt */ + + /* TODO: +1 ist ein Workaround, weil cturn erst in process_orders + * incrementiert wird. */ + f->lastorders = global.data_turn+1; + + } else { + log_warning(("orders for invalid faction %s\n", itoa36(fid))); + } + return f; +} + +double +version(void) +{ + return RELEASE_VERSION * 0.1; +} +/* ------------------------------------------------------------- */ + +static param_t +igetparam (const char *s, const struct locale *lang) +{ + return findparam (igetstrtoken (s), lang); +} + +int +readorders(const char *filename) +{ + FILE * F = NULL; + const char *b; + int nfactions=0; + struct faction *f = NULL; + + if (filename) F = cfopen(filename, "rb"); + if (F==NULL) return 0; + + if (verbosity>=1) puts(" - lese Befehlsdatei...\n"); + + /* TODO: recognize UTF8 BOM */ + b = getbuf(F, enc_gamedata); + + /* Auffinden der ersten Partei, und danach abarbeiten bis zur letzten + * Partei */ + + while (b) { + const struct locale * lang = f?f->locale:default_locale; + int p; + const char * s; + + switch (igetparam(b, lang)) { + case P_LOCALE: + s = getstrtoken(); +#undef LOCALE_CHANGE +#ifdef LOCALE_CHANGE + if (f && find_locale(s)) { + f->locale = find_locale(s); + } +#endif + + b = getbuf(F, enc_gamedata); + break; + 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; + p = igetparam(b, lang); + } 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 + * muß buf erneut gefüllt werden, da die betreffende Information in nur + * einer Zeile steht, und nun die nächste gelesen werden muß. */ + + case P_NEXT: + f = NULL; + b = getbuf(F, enc_gamedata); + break; + + default: + b = getbuf(F, enc_gamedata); + break; + } + } + + fclose(F); + puts("\n"); + log_printf(" %d Befehlsdateien gelesen\n", nfactions); + return 0; +} +/* ------------------------------------------------------------- */ + +/* #define INNER_WORLD */ +/* fürs debuggen nur den inneren Teil der Welt laden */ +/* -9;-27;-1;-19;Sumpfloch */ +int +inner_world(region * r) +{ + static int xy[2] = + {18, -45}; + static int size[2] = + {27, 27}; + + if (r->x >= xy[0] && r->x < xy[0] + size[0] && r->y >= xy[1] && r->y < xy[1] + size[1]) + return 2; + if (r->x >= xy[0] - 9 && r->x < xy[0] + size[0] + 9 && r->y >= xy[1] - 9 && r->y < xy[1] + size[1] + 9) + return 1; + return 0; +} + +int maxregions = -1; +int loadplane = 0; + +enum { + U_MAN, + U_UNDEAD, + U_ILLUSION, + U_FIREDRAGON, + U_DRAGON, + U_WYRM, + U_SPELL, + U_TAVERNE, + U_MONSTER, + U_BIRTHDAYDRAGON, + U_TREEMAN, + MAXTYPES +}; + +race_t +typus2race(unsigned char typus) +{ + if (typus>0 && typus <=11) return (race_t)(typus-1); + return NORACE; +} + +void +create_backup(char *file) +{ +#ifdef HAVE_LINK + char bfile[MAX_PATH]; + int c = 1; + + if (access(file, R_OK) == 0) return; + do { + sprintf(bfile, "%s.backup%d", file, c); + c++; + } while(access(bfile, R_OK) == 0); + link(file, bfile); +#endif +} + +void +read_items(struct storage * store, item **ilist) +{ + for (;;) { + char ibuf[32]; + const item_type * itype; + int i; + store->r_str_buf(store, ibuf, sizeof(ibuf)); + if (!strcmp("end", ibuf)) break; + itype = it_find(ibuf); + i = store->r_int(store); + if (i<=0) { + log_error(("data contains an entry with %d %s\n", i, itype->rtype->_name[1])); + } else { + assert(itype!=NULL); + if (itype!=NULL) { + i_change(ilist, itype, i); + } + } + } +} + +static void +read_alliances(struct storage * store) +{ + char pbuf[8]; + int id, terminator = 0; + if (store->versionversionr_str_buf(store, pbuf, sizeof(pbuf)); + id = atoi36(pbuf); + } else { + id = store->r_id(store); + } + while (id!=terminator) { + char aname[128]; + alliance * al; + store->r_str_buf(store, aname, sizeof(aname)); + al = makealliance(id, aname); + if (store->version>=OWNER_2_VERSION) { + al->flags = store->r_int(store); + } + if (store->version>=ALLIANCELEADER_VERSION) { + read_reference(&al->_leader, store, read_faction_reference, resolve_faction); + id = store->r_id(store); + } else{ + store->r_str_buf(store, pbuf, sizeof(pbuf)); + id = atoi36(pbuf); + } + } +} + +void +write_alliances(struct storage * store) +{ + alliance * al = alliances; + while (al) { + if (al->_leader) { + store->w_id(store, al->id); + store->w_str(store, al->name); + store->w_int(store, (int)al->flags); + write_faction_reference(al->_leader, store); + store->w_brk(store); + } + al = al->next; + } + store->w_id(store, 0); + store->w_brk(store); +} + +void +write_items(struct storage * store, item *ilist) +{ + item * itm; + for (itm=ilist;itm;itm=itm->next) { + assert(itm->number>=0); + if (itm->number) { + store->w_tok(store, resourcename(itm->type->rtype, 0)); + store->w_int(store, itm->number); + } + } + store->w_tok(store, "end"); +} + +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)\n", itoa36(id.i))); + f = get_monsters(); + } + } + owner->owner = f; + if (f) { + owner->alliance = f->alliance; + } + return result; +} + +static void +read_owner(struct storage * store, region_owner **powner) +{ + int since_turn = store->r_int(store); + if (since_turn>=0) { + region_owner * owner = malloc(sizeof(region_owner)); + owner->since_turn = since_turn; + owner->morale_turn = store->r_int(store); + if (store->version>=MOURNING_VERSION) { + owner->flags = store->r_int(store); + } else { + owner->flags = 0; + } + if (store->version>=OWNER_2_VERSION) { + int id = store->r_int(store); + owner->alliance = id?findalliance(id):NULL; + } else { + owner->alliance = NULL; + } + read_reference(owner, store, &read_faction_reference, &resolve_owner); + *powner = owner; + } else { + *powner = 0; + } +} + +static void +write_owner(struct storage * store, region_owner *owner) +{ + if (owner) { + store->w_int(store, owner->since_turn); + store->w_int(store, owner->morale_turn); + store->w_int(store, owner->flags); + store->w_id(store, owner->alliance?owner->alliance->id:0); + write_faction_reference(owner->owner, store); + } else { + store->w_int(store, -1); + } +} + +int +current_turn(void) +{ + char zText[MAX_PATH]; + int cturn = 0; + FILE * f; + + sprintf(zText, "%s/turn", basepath()); + f = cfopen(zText, "r"); + if (f) { + fscanf(f, "%d\n", &cturn); + fclose(f); + } + return cturn; +} + +static void +writeorder(struct storage * store, const struct order * ord, const struct locale * lang) +{ + char obuf[1024]; + write_order(ord, obuf, sizeof(obuf)); + if (obuf[0]) store->w_str(store, obuf); +} + +unit * +read_unit(struct storage * store) +{ + skill_t sk; + unit * u; + int number, n, p; + order ** orderp; + char obuf[1024]; + faction * f; + char rname[32]; + + n = store->r_id(store); + if (n<=0) return NULL; + u = findunit(n); + if (u==NULL) { + u = calloc(sizeof(unit), 1); + u->no = n; + uhash(u); + } else { + while (u->attribs) a_remove(&u->attribs, u->attribs); + while (u->items) i_free(i_remove(&u->items, u->items)); + free(u->skills); + u->skills = 0; + u->skill_size = 0; + u_setfaction(u, NULL); + } + + n = store->r_id(store); + f = findfaction(n); + if (f!=u->faction) u_setfaction(u, f); + + u->name = store->r_str(store); + if (lomem) { + store->r_str_buf(store, NULL, 0); + } else { + u->display = store->r_str(store); + } + number = store->r_int(store); + u->age = (short)store->r_int(store); + + if (store->versionr_str_buf(store, rname, sizeof(rname)); + space = strchr(rname, ' '); + if (space!=NULL) { + char * inc = space+1; + char * outc = space; + do { + while (*inc==' ') ++inc; + while (*inc) { + *outc++ = *inc++; + if (*inc==' ') break; + } + } while (*inc); + *outc = 0; + } + } else { + store->r_tok_buf(store, rname, sizeof(rname)); + } + u->race = rc_find(rname); + assert(u->race); + if (store->versionr_str_buf(store, rname, sizeof(rname)); + } else { + store->r_tok_buf(store, rname, sizeof(rname)); + } + if (rname[0] && skill_enabled[SK_STEALTH]) u->irace = rc_find(rname); + else u->irace = NULL; + + if (u->race->describe) { + const char * rcdisp = u->race->describe(u, u->faction->locale); + if (u->display && rcdisp) { + /* see if the data file contains old descriptions */ + if (strcmp(rcdisp, u->display)==0) { + free(u->display); + u->display = NULL; + } + } + } + if (u->faction == NULL) { + log_error(("unit %s has faction == NULL\n", unitname(u))); + u_setfaction(u, get_monsters()); + set_number(u, 0); + } + + if (count_unit(u) && u->faction) u->faction->no_units++; + + set_number(u, number); + + n = store->r_id(store); + if (n>0) u->building = findbuilding(n); + + n = store->r_id(store); + if (n>0) u->ship = findship(n); + + setstatus(u, store->r_int(store)); + u->flags = store->r_int(store); + u->flags &= UFL_SAVEMASK; + if ((u->flags&UFL_ANON_FACTION) && !rule_stealth_faction()) { + /* if this rule is broken, then fix broken units */ + u->flags -= UFL_ANON_FACTION; + log_warning(("%s was anonymous.\n", unitname(u))); + } + /* Persistente Befehle einlesen */ + free_orders(&u->orders); + store->r_str_buf(store, obuf, sizeof(obuf)); + p = n = 0; + orderp = &u->orders; + while (obuf[0]) { + if (!lomem) { + order * ord = parse_order(obuf, u->faction->locale); + if (ord!=NULL) { + if (++nnext; + ord = NULL; + } else if (p==MAXPERSISTENT) { + log_warning(("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT)); + } + } else if (n==MAXORDERS) { + log_warning(("%s had %d or more orders\n", unitname(u), MAXORDERS)); + } + if (ord!=NULL) free_order(ord); + } + } + store->r_str_buf(store, obuf, sizeof(obuf)); + } + if (store->versionr_str_buf(store, obuf, sizeof(obuf)); + ord = parse_order(obuf, u->faction->locale); + if (ord!=NULL) { + addlist(&u->orders, ord); + } + } + set_order(&u->thisorder, NULL); + + assert(u->race); + while ((sk = (skill_t) store->r_int(store)) != NOSKILL) { + int level = store->r_int(store); + int weeks = store->r_int(store); + if (level) { + skill * sv = add_skill(u, sk); + sv->level = sv->old = (unsigned char)level; + sv->weeks = (unsigned char)weeks; + } + } + read_items(store, &u->items); + u->hp = store->r_int(store); + if (u->hp < u->number) { + log_error(("Einheit %s hat %u Personen, und %u Trefferpunkte\n", itoa36(u->no), + u->number, u->hp)); + u->hp=u->number; + } + + a_read(store, &u->attribs, u); + return u; +} + +void +write_unit(struct storage * store, const unit * u) +{ + order * ord; + int i, p = 0; + const race * irace = u_irace(u); + write_unit_reference(u, store); + write_faction_reference(u->faction, store); + store->w_str(store, (const char *)u->name); + store->w_str(store, u->display?(const char *)u->display:""); + store->w_int(store, u->number); + store->w_int(store, u->age); + store->w_tok(store, u->race->_name[0]); + store->w_tok(store, (irace && irace!=u->race)?irace->_name[0]:""); + write_building_reference(u->building, store); + write_ship_reference(u->ship, store); + store->w_int(store, u->status); + store->w_int(store, u->flags & UFL_SAVEMASK); + store->w_brk(store); + for (ord = u->old_orders; ord; ord=ord->next) { + if (++pfaction->locale); + } else { + log_error(("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT)); + break; + } + } + for (ord = u->orders; ord; ord=ord->next) { + if (u->old_orders && is_repeated(ord)) continue; /* has new defaults */ + if (is_persistent(ord)) { + if (++pfaction->locale); + } else { + log_error(("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT)); + break; + } + } + } + /* write an empty string to terminate the list */ + store->w_str(store, ""); + store->w_brk(store); + + assert(u->race); + + for (i=0;i!=u->skill_size;++i) { + skill * sv = u->skills+i; + assert(sv->weeks<=sv->level*2+1); + if (sv->level>0) { + store->w_int(store, sv->id); + store->w_int(store, sv->level); + store->w_int(store, sv->weeks); + } + } + store->w_int(store, -1); + store->w_brk(store); + write_items(store, u->items); + store->w_brk(store); + if (u->hp == 0) { + log_error(("unit %s has 0 hitpoints, adjusting.\n", itoa36(u->no))); + ((unit*)u)->hp = u->number; + } + store->w_int(store, u->hp); + store->w_brk(store); + a_write(store, u->attribs, u); + store->w_brk(store); +} + +static region * +readregion(struct storage * store, int x, int y) +{ + region * r = findregion(x, y); + const terrain_type * terrain; + char token[32]; + unsigned int uid = 0; + + if (store->version>=UID_VERSION) { + uid = store->r_int(store); + } + + if (r==NULL) { + plane * pl = findplane(x, y); + r = new_region(x, y, pl, uid); + } else { + assert(uid==0 || r->uid==uid); + current_region = r; + while (r->attribs) a_remove(&r->attribs, r->attribs); + if (r->land) { + free(r->land); /* mem leak */ + r->land->demands = 0; /* mem leak */ + } + while (r->resources) { + rawmaterial * rm = r->resources; + r->resources = rm->next; + free(rm); + } + r->land = 0; + } + if (lomem) { + store->r_str_buf(store, NULL, 0); + } else { + char info[DISPLAYSIZE]; + store->r_str_buf(store, info, sizeof(info)); + region_setinfo(r, info); + } + + if (store->version < TERRAIN_VERSION) { + int ter = store->r_int(store); + terrain = newterrain((terrain_t)ter); + if (terrain==NULL) { + log_error(("while reading datafile from pre-TERRAIN_VERSION, could not find terrain #%d.\n", ter)); + terrain = newterrain(T_PLAIN); + } + } else { + char name[64]; + store->r_str_buf(store, name, sizeof(name)); + terrain = get_terrain(name); + if (terrain==NULL) { + log_error(("Unknown terrain '%s'\n", name)); + assert(!"unknown terrain"); + } + } + r->terrain = terrain; + r->flags = (char) store->r_int(store); + + r->age = (unsigned short) store->r_int(store); + + if (fval(r->terrain, LAND_REGION)) { + r->land = calloc(1, sizeof(land_region)); + r->land->name = store->r_str(store); + } + if (r->land) { + int i; + rawmaterial ** pres = &r->resources; + + i = store->r_int(store); + if (i<0) { + log_error(("number of trees in %s is %d.\n", + regionname(r, NULL), i)); + i=0; + } + rsettrees(r, 0, i); + i = store->r_int(store); + if (i<0) { + log_error(("number of young trees in %s is %d.\n", + regionname(r, NULL), i)); + i=0; + } + rsettrees(r, 1, i); + i = store->r_int(store); + if (i<0) { + log_error(("number of seeds in %s is %d.\n", + regionname(r, NULL), i)); + i=0; + } + rsettrees(r, 2, i); + + i = store->r_int(store); rsethorses(r, i); + assert(*pres==NULL); + for (;;) { + rawmaterial * res; + store->r_str_buf(store, token, sizeof(token)); + if (strcmp(token, "end")==0) break; + res = malloc(sizeof(rawmaterial)); + res->type = rmt_find(token); + if (res->type==NULL) { + log_error(("invalid resourcetype %s in data.\n", token)); + } + assert(res->type!=NULL); + res->level = store->r_int(store); + res->amount = store->r_int(store); + res->flags = 0; + + res->startlevel = store->r_int(store); + res->base = store->r_int(store); + res->divisor = store->r_int(store); + + *pres = res; + pres=&res->next; + } + *pres = NULL; + + store->r_str_buf(store, token, sizeof(token)); + if (strcmp(token, "noherb") != 0) { + const resource_type * rtype = rt_find(token); + assert(rtype && rtype->itype && fval(rtype->itype, ITF_HERB)); + rsetherbtype(r, rtype->itype); + } else { + rsetherbtype(r, NULL); + } + rsetherbs(r, (short)store->r_int(store)); + rsetpeasants(r, store->r_int(store)); + rsetmoney(r, store->r_int(store)); + } + + assert(r->terrain!=NULL); + assert(rhorses(r) >= 0); + assert(rpeasants(r) >= 0); + assert(rmoney(r) >= 0); + + if (r->land) { + for (;;) { + const struct item_type * itype; + store->r_str_buf(store, token, sizeof(token)); + if (!strcmp(token, "end")) break; + itype = it_find(token); + assert(itype->rtype->ltype); + r_setdemand(r, itype->rtype->ltype, store->r_int(store)); + } + if (store->version>=REGIONITEMS_VERSION) { + read_items(store, &r->land->items); + } + if (store->version>=REGIONOWNER_VERSION) { + r->land->morale = (short)store->r_int(store); + if (r->land->morale<0) r->land->morale = 0; + read_owner(store, &r->land->ownership); + } + } + a_read(store, &r->attribs, r); + + return r; +} + +void +writeregion(struct storage * store, const region * r) +{ + store->w_int(store, r->uid); + store->w_str(store, region_getinfo(r)); + store->w_tok(store, r->terrain->_name); + store->w_int(store, r->flags & RF_SAVEMASK); + store->w_int(store, r->age); + store->w_brk(store); + if (fval(r->terrain, LAND_REGION)) { + const item_type *rht; + struct demand * demand; + rawmaterial * res = r->resources; + store->w_str(store, (const char *)r->land->name); + assert(rtrees(r,0)>=0); + assert(rtrees(r,1)>=0); + assert(rtrees(r,2)>=0); + store->w_int(store, rtrees(r,0)); + store->w_int(store, rtrees(r,1)); + store->w_int(store, rtrees(r,2)); + store->w_int(store, rhorses(r)); + + while (res) { + store->w_tok(store, res->type->name); + store->w_int(store, res->level); + store->w_int(store, res->amount); + store->w_int(store, res->startlevel); + store->w_int(store, res->base); + store->w_int(store, res->divisor); + res = res->next; + } + store->w_tok(store, "end"); + + rht = rherbtype(r); + if (rht) { + store->w_tok(store, resourcename(rht->rtype, 0)); + } else { + store->w_tok(store, "noherb"); + } + store->w_int(store, rherbs(r)); + store->w_int(store, rpeasants(r)); + store->w_int(store, rmoney(r)); + if (r->land) for (demand=r->land->demands; demand; demand=demand->next) { + store->w_tok(store, resourcename(demand->type->itype->rtype, 0)); + store->w_int(store, demand->value); + } + store->w_tok(store, "end"); +#if RELEASE_VERSION>=REGIONITEMS_VERSION + write_items(store, r->land->items); + store->w_brk(store); +#endif +#if RELEASE_VERSION>=REGIONOWNER_VERSION + store->w_int(store, r->land->morale); + write_owner(store, r->land->ownership); + store->w_brk(store); +#endif + } + a_write(store, r->attribs, r); + store->w_brk(store); +} + +static ally ** +addally(const faction * f, ally ** sfp, int aid, int state) +{ + struct faction * af = findfaction(aid); + ally * sf; + + state &= ~HELP_OBSERVE; +#ifndef REGIONOWNERS + state &= ~HELP_TRAVEL; +#endif + state &= HelpMask(); + + if (state==0) return sfp; + + sf = calloc(1, sizeof(ally)); + sf->faction = af; + if (!sf->faction) { + variant id; + id.i = aid; + ur_add(id, &sf->faction, resolve_faction); + } + sf->status = state & HELP_ALL; + + while (*sfp) sfp=&(*sfp)->next; + *sfp = sf; + return &sf->next; +} + +/** Reads a faction from a file. + * This function requires no context, can be called in any state. The + * faction may not already exist, however. + */ +faction * +readfaction(struct storage * store) +{ + ally **sfp; + int planes; + int i = store->r_id(store); + faction * f = findfaction(i); + char email[128]; + char token[32]; + + if (f==NULL) { + f = (faction *) calloc(1, sizeof(faction)); + f->no = i; + } else { + f->allies = NULL; /* mem leak */ + while (f->attribs) a_remove(&f->attribs, f->attribs); + } + f->subscription = store->r_int(store); + + if (alliances || store->version>=OWNER_2_VERSION) { + int allianceid = store->r_id(store); + if (allianceid>0) f->alliance = findalliance(allianceid); + if (f->alliance) { + alliance * al = f->alliance; + faction_list * flist = malloc(sizeof(faction_list)); + if (al->flags&ALF_NON_ALLIED) { + assert(!al->members || !"non-allied dummy-alliance has more than one member"); + } + flist->data = f; + flist->next = al->members; + al->members = flist; + } else if (rule_region_owners()){ + /* compat fix for non-allied factions */ + alliance * al = makealliance(0, NULL); + setalliance(f, al); + } + if (store->version>=OWNER_2_VERSION) { + f->alliance_joindate = store->r_int(store); + } else { + f->alliance_joindate = turn - 10; /* we're guessing something safe here */ + } + } + + f->name = store->r_str(store); + f->banner = store->r_str(store); + + log_info((3, " - Lese Partei %s (%s)\n", f->name, factionid(f))); + + store->r_str_buf(store, email, sizeof(email)); + if (set_email(&f->email, email)!=0) { + log_warning(("Invalid email address for faction %s: %s\n", itoa36(f->no), email)); + set_email(&f->email, ""); + } + + f->passw = store->r_str(store); + if (store->version >= OVERRIDE_VERSION) { + f->override = store->r_str(store); + } else { + f->override = strdup(itoa36(rng_int())); + } + + store->r_str_buf(store, token, sizeof(token)); + f->locale = find_locale(token); + f->lastorders = store->r_int(store); + f->age = store->r_int(store); + store->r_str_buf(store, token, sizeof(token)); + f->race = rc_find(token); + assert(f->race); + f->magiegebiet = (magic_t)store->r_int(store); + + if (store->versionr_int(store); + } + + f->flags = store->r_int(store); + if (f->no==0) { + f->flags |= FFL_NPC; + } + + a_read(store, &f->attribs, f); + if (store->version>=CLAIM_VERSION) { + read_items(store, &f->items); + } + for (;;) { + int level; + store->r_tok_buf(store, token, sizeof(token)); + if (strcmp("end", token)==0) break; + level = store->r_int(store); + } + planes = store->r_int(store); + while(--planes >= 0) { + int id = store->r_int(store); + int ux = store->r_int(store); + int uy = store->r_int(store); + set_ursprung(f, id, ux, uy); + } + f->newbies = 0; + + i = f->options = store->r_int(store); + + if ((i & (want(O_REPORT)|want(O_COMPUTER)))==0 && !is_monsters(f)) { + /* Kein Report eingestellt, Fehler */ + f->options = f->options | want(O_REPORT) | want(O_ZUGVORLAGE); + } + + sfp = &f->allies; + if (store->versionr_int(store); + while (--p >= 0) { + int aid = store->r_id(store); + int state = store->r_int(store); + sfp = addally(f, sfp, aid, state); + } + } else { + for (;;) { + int aid = 0; + if (store->versionr_tok_buf(store, token, sizeof(token)); + if (strcmp(token, "end")!=0) { + aid = atoi36(token); + } + } else { + aid = store->r_id(store); + } + if (aid>0) { + int state = store->r_int(store); + sfp = addally(f, sfp, aid, state); + } else { + break; + } + } + } + read_groups(store, f); + f->spellbook = NULL; + if (store->version>=REGIONOWNER_VERSION) { + read_spellist(&f->spellbook, f->magiegebiet, store); + } + return f; +} + +void +writefaction(struct storage * store, const faction * f) +{ + ally *sf; + ursprung *ur; + + write_faction_reference(f, store); + store->w_int(store, f->subscription); + if (f->alliance) { + store->w_id(store, f->alliance->id); + if (f->alliance->flags&ALF_NON_ALLIED) { + assert(f==f->alliance->_leader || !"non-allied faction is not leader of its own dummy-alliance."); + } + } + else { + store->w_id(store, 0); + } + store->w_int(store, f->alliance_joindate); + + store->w_str(store, (const char *)f->name); + store->w_str(store, (const char *)f->banner); + store->w_str(store, f->email); + store->w_tok(store, (const char *)f->passw); + store->w_tok(store, (const char *)f->override); + store->w_tok(store, locale_name(f->locale)); + store->w_int(store, f->lastorders); + store->w_int(store, f->age); + store->w_tok(store, f->race->_name[0]); + store->w_brk(store); + store->w_int(store, f->magiegebiet); + + store->w_int(store, f->flags&FFL_SAVEMASK); + a_write(store, f->attribs, f); + store->w_brk(store); + write_items(store, f->items); + store->w_brk(store); + store->w_tok(store, "end"); + store->w_brk(store); + store->w_int(store, listlen(f->ursprung)); + for (ur = f->ursprung;ur;ur=ur->next) { + store->w_int(store, ur->id); + store->w_int(store, ur->x); + store->w_int(store, ur->y); + } + store->w_brk(store); + store->w_int(store, f->options & ~want(O_DEBUG)); + store->w_brk(store); + + for (sf = f->allies; sf; sf = sf->next) { + int no = (sf->faction!=NULL)?sf->faction->no:0; + int status = alliedfaction(NULL, f, sf->faction, HELP_ALL); + if (status!=0) { + store->w_id(store, no); + store->w_int(store, sf->status); + } + } + store->w_id(store, 0); + store->w_brk(store); + write_groups(store, f->groups); + write_spelllist(f->spellbook, store); +} + +int +readgame(const char * filename, int mode, int backup) +{ + int i, n, p; + faction *f, **fp; + region *r; + building *b, **bp; + ship **shp; + unit *u; + int rmax = maxregions; + char path[MAX_PATH]; + char token[32]; + const struct building_type * bt_lighthouse = bt_find("lighthouse"); + storage my_store = (mode==IO_BINARY)?binary_store:text_store; + storage * store = &my_store; + + sprintf(path, "%s/%s", datapath(), filename); + log_printf("- reading game data from %s\n", filename); + if (backup) create_backup(path); + + store->encoding = enc_gamedata; + if (store->open(store, path, IO_READ)!=0) { + return -1; + } + enc_gamedata = store->encoding; + + assert(store->version>=MIN_VERSION || !"unsupported data format"); + assert(store->version<=RELEASE_VERSION || !"unsupported data format"); + + if (store->version >= SAVEXMLNAME_VERSION) { + char basefile[1024]; + + store->r_str_buf(store, basefile, sizeof(basefile)); + if (strcmp(game_name, basefile)!=0) { + char buffer[64]; + snprintf(buffer, sizeof(buffer), "%s.xml", game_name); + if (strcmp(basefile, buffer)!=0) { + log_warning(("game mismatch: datafile contains %s, game is %s\n", basefile, game_name)); + printf("WARNING: any key to continue, Ctrl-C to stop\n"); + getchar(); + } + } + } + a_read(store, &global.attribs, NULL); + global.data_turn = turn = store->r_int(store); + log_info((1, " - reading turn %d\n", turn)); + rng_init(turn); + ++global.cookie; + store->r_int(store); /* max_unique_id = */ + nextborder = store->r_int(store); + + /* Planes */ + planes = NULL; + n = store->r_int(store); + while(--n >= 0) { + int id = store->r_int(store); + plane *pl = getplanebyid(id); + if (pl==NULL) { + pl = calloc(1, sizeof(plane)); + } else { + log_warning(("the plane with id=%d already exists.\n", id)); + } + pl->id = id; + pl->name = store->r_str(store); + pl->minx = store->r_int(store); + pl->maxx = store->r_int(store); + pl->miny = store->r_int(store); + pl->maxy = store->r_int(store); + pl->flags = store->r_int(store); + + /* read watchers */ + store->r_str_buf(store, token, sizeof(token)); + while (strcmp(token, "end")!=0) { + watcher * w = calloc(sizeof(watcher),1); + variant fno; + fno.i = atoi36(token); + w->mode = (unsigned char)store->r_int(store); + w->next = pl->watchers; + pl->watchers = w; + ur_add(fno, &w->faction, resolve_faction); + store->r_str_buf(store, token, sizeof(token)); + } + + a_read(store, &pl->attribs, pl); + addlist(&planes, pl); + } + + /* Read factions */ + if (store->version>=ALLIANCES_VERSION) { + read_alliances(store); + } + n = store->r_int(store); + log_info((1, " - Einzulesende Parteien: %d\n", n)); + fp = &factions; + while (*fp) fp=&(*fp)->next; + + while (--n >= 0) { + faction * f = readfaction(store); + + *fp = f; + fp = &f->next; + fhash(f); + } + *fp = 0; + + /* Benutzte Faction-Ids */ + if (store->versionr_int(store); + while (i--) { + store->r_int(store); /* used faction ids. ignore. */ + } + } + + /* Regionen */ + + n = store->r_int(store); + assert(n= 0) { + unit **up; + int x = store->r_int(store); + int y = store->r_int(store); + + if ((n & 0x3FF) == 0) { /* das spart extrem Zeit */ + log_info((2, " - Einzulesende Regionen: %d/%d * %d,%d \r", rmax, n, x, y)); + } + --rmax; + + r = readregion(store, x, y); + + /* Burgen */ + p = store->r_int(store); + bp = &r->buildings; + + while (--p >= 0) { + + b = (building *) calloc(1, sizeof(building)); + b->no = store->r_id(store); + *bp = b; + bp = &b->next; + bhash(b); + b->name = store->r_str(store); + if (lomem) { + store->r_str_buf(store, NULL, 0); + } + else { + b->display = store->r_str(store); + } + b->size = store->r_int(store); + store->r_str_buf(store, token, sizeof(token)); + b->type = bt_find(token); + b->region = r; + a_read(store, &b->attribs, b); + if (b->type==bt_lighthouse) { + r->flags |= RF_LIGHTHOUSE; + } + } + /* Schiffe */ + + p = store->r_int(store); + shp = &r->ships; + + while (--p >= 0) { + ship * sh = (ship *) calloc(1, sizeof(ship)); + sh->region = r; + sh->no = store->r_id(store); + *shp = sh; + shp = &sh->next; + shash(sh); + sh->name = store->r_str(store); + if (lomem) { + store->r_str_buf(store, NULL, 0); + } + else { + sh->display = store->r_str(store); + } + store->r_str_buf(store, token, sizeof(token)); + sh->type = st_find(token); + if (sh->type==NULL) { + /* old datafiles */ + sh->type = st_find((const char *)locale_string(default_locale, token)); + } + assert(sh->type || !"ship_type not registered!"); + sh->size = store->r_int(store); + sh->damage = store->r_int(store); + if (store->version>=FOSS_VERSION) { + sh->flags = store->r_int(store); + } + + /* Attribute rekursiv einlesen */ + + sh->coast = (direction_t)store->r_int(store); + if (sh->type->flags & SFL_NOCOAST) { + sh->coast = NODIRECTION; + } + a_read(store, &sh->attribs, sh); + } + + *shp = 0; + + /* Einheiten */ + + p = store->r_int(store); + up = &r->units; + + while (--p >= 0) { + unit * u = read_unit(store); + sc_mage * mage; + + assert(u->region==NULL); + u->region = r; + *up = u; + up = &u->next; + + update_interval(u->faction, u->region); + mage = get_mage(u); + if (mage) { + faction * f = u->faction; + int skl = effskill(u, SK_MAGIC); + if (!is_monsters(f) && f->magiegebiet==M_GRAY) { + log_error(("faction %s had magic=gray, fixing (%s)\n", + factionname(f), magic_school[mage->magietyp])); + f->magiegebiet = mage->magietyp; + } + if (f->max_spelllevelmax_spelllevel = skl; + } + if (mage->spellcount<0) { + mage->spellcount = 0; + updatespelllist(u); + } + } + } + } + log_info((1, "\n")); + read_borders(store); + + store->close(store); + + /* Unaufgeloeste Zeiger initialisieren */ + log_info((1, "fixing unresolved references.\n")); + resolve(); + + log_info((1, "updating area information for lighthouses.\n")); + for (r=regions;r;r=r->next) { + if (r->flags & RF_LIGHTHOUSE) { + building * b; + for (b=r->buildings;b;b=b->next) update_lighthouse(b); + } + } + log_info((1, "marking factions as alive.\n")); + for (f = factions; f; f = f->next) { + if (f->flags & FFL_NPC) { + f->alive = 1; + if (f->no==0) { + int no=666; + while (findfaction(no)) ++no; + log_warning(("renum(monsters, %d)\n", no)); + renumber_faction(f, no); + } + } else { + for (u = f->units; u; u = u->nextF) { + if (u->number>0) { + f->alive = 1; + break; + } + } + } + } + if (loadplane || maxregions>=0) { + remove_empty_factions(); + } + log_info((1, "Done loading turn %d.\n", turn)); + return 0; +} + +static void +clear_monster_orders(void) +{ + faction * f = get_monsters(); + if (f) { + unit * u; + for (u=f->units;u;u=u->nextF) { + free_orders(&u->orders); + } + } +} + +int +writegame(const char *filename, int mode) +{ + char *base; + int n; + faction *f; + region *r; + building *b; + ship *sh; + unit *u; + plane *pl; + char path[MAX_PATH]; + storage my_store = (mode==IO_BINARY)?binary_store:text_store; + storage * store = &my_store; + store->version = RELEASE_VERSION; + + clear_monster_orders(); + sprintf(path, "%s/%s", datapath(), filename); +#ifdef HAVE_UNISTD_H + if (access(path, R_OK) == 0) { + /* make sure we don't overwrite some hardlinkedfile */ + unlink(path); + } +#endif + + store->encoding = enc_gamedata; + if (store->open(store, path, IO_WRITE)!=0) { + return -1; + } + + /* globale Variablen */ + + base = strrchr(game_name, '/'); + if (base) { + store->w_str(store, base+1); + } else { + store->w_str(store, game_name); + } + store->w_brk(store); + + a_write(store, global.attribs, NULL); + store->w_brk(store); + + store->w_int(store, turn); + store->w_int(store, 0/*max_unique_id*/); + store->w_int(store, nextborder); + + /* Write planes */ + store->w_brk(store); + store->w_int(store, listlen(planes)); + store->w_brk(store); + + for(pl = planes; pl; pl=pl->next) { + watcher * w; + store->w_int(store, pl->id); + store->w_str(store, pl->name); + store->w_int(store, pl->minx); + store->w_int(store, pl->maxx); + store->w_int(store, pl->miny); + store->w_int(store, pl->maxy); + store->w_int(store, pl->flags); + w = pl->watchers; + while (w) { + if (w->faction) { + write_faction_reference(w->faction, store); + store->w_int(store, w->mode); + } + w = w->next; + } + store->w_tok(store, "end"); + a_write(store, pl->attribs, pl); + store->w_brk(store); + } + + + /* Write factions */ +#if RELEASE_VERSION>=ALLIANCES_VERSION + write_alliances(store); +#endif + n = listlen(factions); + store->w_int(store, n); + store->w_brk(store); + + log_info((1, " - Schreibe %d Parteien...\n", n)); + for (f = factions; f; f = f->next) { + writefaction(store, f); + store->w_brk(store); + } + + /* Write regions */ + + n=listlen(regions); + store->w_int(store, n); + store->w_brk(store); + log_info((1, " - Schreibe Regionen: %d \r", n)); + + for (r = regions; r; r = r->next, --n) { + /* plus leerzeile */ + if ((n%1024)==0) { /* das spart extrem Zeit */ + log_info((2, " - Schreibe Regionen: %d \r", n)); + fflush(stdout); + } + store->w_brk(store); + store->w_int(store, r->x); + store->w_int(store, r->y); + writeregion(store, r); + + store->w_int(store, listlen(r->buildings)); + store->w_brk(store); + for (b = r->buildings; b; b = b->next) { + write_building_reference(b, store); + store->w_str(store, b->name); + store->w_str(store, b->display?b->display:""); + store->w_int(store, b->size); + store->w_tok(store, b->type->_name); + store->w_brk(store); + a_write(store, b->attribs, b); + store->w_brk(store); + } + + store->w_int(store, listlen(r->ships)); + store->w_brk(store); + for (sh = r->ships; sh; sh = sh->next) { + assert(sh->region == r); + write_ship_reference(sh, store); + store->w_str(store, (const char *)sh->name); + store->w_str(store, sh->display?(const char *)sh->display:""); + store->w_tok(store, sh->type->name[0]); + store->w_int(store, sh->size); + store->w_int(store, sh->damage); + store->w_int(store, sh->flags & SFL_SAVEMASK); + assert((sh->type->flags & SFL_NOCOAST)==0 || sh->coast == NODIRECTION); + store->w_int(store, sh->coast); + store->w_brk(store); + a_write(store, sh->attribs, sh); + store->w_brk(store); + } + + store->w_int(store, listlen(r->units)); + store->w_brk(store); + for (u = r->units; u; u = u->next) { + write_unit(store, u); + } + } + store->w_brk(store); + write_borders(store); + store->w_brk(store); + + store->close(store); + + log_info((1, "\nOk.\n")); + return 0; +} + +int +a_readint(attrib * a, void * owner, struct storage * store) +{ + /* assert(sizeof(int)==sizeof(a->data)); */ + a->data.i = store->r_int(store); + return AT_READ_OK; +} + +void +a_writeint(const attrib * a, const void * owner, struct storage * store) +{ + store->w_int(store, a->data.i); +} + +int +a_readshorts(attrib * a, void * owner, struct storage * store) +{ + if (store->versiondata.sa[0] = (short)store->r_int(store); + a->data.sa[1] = (short)store->r_int(store); + return AT_READ_OK; +} + +void +a_writeshorts(const attrib * a, const void * owner, struct storage * store) +{ + store->w_int(store, a->data.sa[0]); + store->w_int(store, a->data.sa[1]); +} + +int +a_readchars(attrib * a, void * owner, struct storage * store) +{ + int i; + if (store->versiondata.ca[i] = (char)store->r_int(store); + } + return AT_READ_OK; +} + +void +a_writechars(const attrib * a, const void * owner, struct storage * store) +{ + int i; + + for (i=0;i!=4;++i) { + store->w_int(store, a->data.ca[i]); + } +} + +int +a_readvoid(attrib * a, void * owner, struct storage * store) +{ + if (store->versiondata.v = store->r_str(store); + return AT_READ_OK; +} + +void +a_writestring(const attrib * a, const void * owner, struct storage * store) +{ + assert(a->data.v); + store->w_str(store, (const char *)a->data.v); +} + +void +a_finalizestring(attrib * a) +{ + free(a->data.v); +} diff --git a/src/kernel/save.h b/src/kernel/save.h index 4d11347b7..4f10e7090 100644 --- a/src/kernel/save.h +++ b/src/kernel/save.h @@ -1,73 +1,73 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_SAVE -#define H_KRNL_SAVE -#ifdef __cplusplus -extern "C" { -#endif - -double version(void); - -#define MAX_INPUT_SIZE DISPLAYSIZE*2 -/* Nach MAX_INPUT_SIZE brechen wir das Einlesen der Zeile ab und nehmen an, - * dass hier ein Fehler (fehlende ") vorliegt */ - -FILE * cfopen(const char *filename, const char *mode); -int readorders(const char *filename); -int creategame(void); -extern int readgame(const char * filename, int mode, int backup); -int writegame(const char *filename, int mode); - -extern void rsf(FILE * F, char *s, size_t len); - -/* Versionsänderungen: */ -extern int data_version; -extern const char *game_name; -extern int enc_gamedata; - -extern void init_locales(void); -extern int current_turn(void); - -extern void read_items(struct storage * store, struct item **it); -extern void write_items(struct storage * store, struct item *it); - -extern void write_unit(struct storage * store, const struct unit * u); -extern struct unit * read_unit(struct storage * store); - -extern int a_readint(struct attrib * a, void * owner, struct storage * store); -extern void a_writeint(const struct attrib * a, const void * owner, struct storage * store); -extern int a_readshorts(struct attrib * a, void * owner, struct storage * store); -extern void a_writeshorts(const struct attrib * a, const void * owner, struct storage * store); -extern int a_readchars(struct attrib * a, void * owner, struct storage * store); -extern void a_writechars(const struct attrib * a, const void * owner, struct storage * store); -extern int a_readvoid(struct attrib * a, void * owner, struct storage * store); -extern void a_writevoid(const struct attrib * a, const void * owner, struct storage * store); -extern int a_readstring(struct attrib * a, void * owner, struct storage * store); -extern void a_writestring(const struct attrib * a, const void * owner, struct storage * store); -extern void a_finalizestring(struct attrib * a); - -extern int freadstr(FILE * F, int encoding, char * str, size_t size); -extern int fwritestr(FILE * F, const char * str); - -extern void create_backup(char *file); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_SAVE +#define H_KRNL_SAVE +#ifdef __cplusplus +extern "C" { +#endif + +double version(void); + +#define MAX_INPUT_SIZE DISPLAYSIZE*2 +/* Nach MAX_INPUT_SIZE brechen wir das Einlesen der Zeile ab und nehmen an, + * dass hier ein Fehler (fehlende ") vorliegt */ + +FILE * cfopen(const char *filename, const char *mode); +int readorders(const char *filename); +int creategame(void); +extern int readgame(const char * filename, int mode, int backup); +int writegame(const char *filename, int mode); + +extern void rsf(FILE * F, char *s, size_t len); + +/* Versionsänderungen: */ +extern int data_version; +extern const char *game_name; +extern int enc_gamedata; + +extern void init_locales(void); +extern int current_turn(void); + +extern void read_items(struct storage * store, struct item **it); +extern void write_items(struct storage * store, struct item *it); + +extern void write_unit(struct storage * store, const struct unit * u); +extern struct unit * read_unit(struct storage * store); + +extern int a_readint(struct attrib * a, void * owner, struct storage * store); +extern void a_writeint(const struct attrib * a, const void * owner, struct storage * store); +extern int a_readshorts(struct attrib * a, void * owner, struct storage * store); +extern void a_writeshorts(const struct attrib * a, const void * owner, struct storage * store); +extern int a_readchars(struct attrib * a, void * owner, struct storage * store); +extern void a_writechars(const struct attrib * a, const void * owner, struct storage * store); +extern int a_readvoid(struct attrib * a, void * owner, struct storage * store); +extern void a_writevoid(const struct attrib * a, const void * owner, struct storage * store); +extern int a_readstring(struct attrib * a, void * owner, struct storage * store); +extern void a_writestring(const struct attrib * a, const void * owner, struct storage * store); +extern void a_finalizestring(struct attrib * a); + +extern int freadstr(FILE * F, int encoding, char * str, size_t size); +extern int fwritestr(FILE * F, const char * str); + +extern void create_backup(char *file); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 4a7764f82..5cf96aa3c 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -1,337 +1,338 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "ship.h" - -/* kernel includes */ -#include "build.h" -#include "unit.h" -#include "item.h" -#include "race.h" -#include "region.h" -#include "skill.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - - -ship_typelist *shiptypes = NULL; - -static local_names * snames; - -const ship_type * -findshiptype(const char * name, const struct locale * lang) -{ - local_names * sn = snames; - variant var; - - while (sn) { - if (sn->lang==lang) break; - sn=sn->next; - } - if (!sn) { - struct ship_typelist * stl = shiptypes; - sn = calloc(sizeof(local_names), 1); - sn->next = snames; - sn->lang = lang; - while (stl) { - variant var; - const char * n = locale_string(lang, stl->type->name[0]); - var.v = (void*)stl->type; - addtoken(&sn->names, n, var); - stl = stl->next; - } - snames = sn; - } - if (findtoken(&sn->names, name, &var)==E_TOK_NOMATCH) return NULL; - return (const ship_type*)var.v; -} - -const ship_type * -st_find(const char* name) -{ - const struct ship_typelist * stl = shiptypes; - while (stl && strcmp(stl->type->name[0], name)) stl = stl->next; - return stl?stl->type:NULL; -} - -void -st_register(const ship_type * type) { - struct ship_typelist * stl = malloc(sizeof(ship_type)); - stl->type = type; - stl->next = shiptypes; - shiptypes = stl; -} - -#define SMAXHASH 7919 -ship *shiphash[SMAXHASH]; -void -shash(ship * s) -{ - ship *old = shiphash[s->no % SMAXHASH]; - - shiphash[s->no % SMAXHASH] = s; - s->nexthash = old; -} - -void -sunhash(ship * s) -{ - ship **show; - - for (show = &shiphash[s->no % SMAXHASH]; *show; show = &(*show)->nexthash) { - if ((*show)->no == s->no) - break; - } - if (*show) { - assert(*show == s); - *show = (*show)->nexthash; - s->nexthash = 0; - } -} - -static ship * -sfindhash(int i) -{ - ship *old; - - for (old = shiphash[i % SMAXHASH]; old; old = old->nexthash) - if (old->no == i) - return old; - return 0; -} - -struct ship * -findship(int i) -{ - return sfindhash(i); -} - -struct ship * -findshipr(const region *r, int n) -{ - ship * sh; - - for (sh = r->ships; sh; sh = sh->next) { - if (sh->no == n) { - assert(sh->region == r); - return sh; - } - } - return 0; -} - -void -damage_ship(ship * sh, double percent) -{ - double damage = DAMAGE_SCALE * sh->type->damage * percent * sh->size + sh->damage; - sh->damage = (int)damage; -} - -unit * -captain(ship *sh) -{ - unit *u; - - for(u = sh->region->units; u; u = u->next) - if(u->ship == sh && fval(u, UFL_OWNER)) return u; - - return NULL; -} - -/* Alte Schiffstypen: */ -static ship * deleted_ships; - -ship * -new_ship(const ship_type * stype, const struct locale * lang, region * r) -{ - static char buffer[7 + IDSIZE + 1]; - ship *sh = (ship *) calloc(1, sizeof(ship)); - - assert(stype); - sh->no = newcontainerid(); - sh->coast = NODIRECTION; - sh->type = stype; - sh->region = r; - - sprintf(buffer, "%s %s", LOC(lang, stype->name[0]), shipid(sh)); - sh->name = strdup(buffer); - shash(sh); - addlist(&r->ships, sh); - return sh; -} - -void -remove_ship(ship ** slist, ship * sh) -{ - region * r = sh->region; - unit * u = r->units; - - handle_event(sh->attribs, "destroy", sh); - while (u) { - if (u->ship == sh) { - leave_ship(u); - } - u = u->next; - } - sunhash(sh); - while (*slist && *slist!=sh) slist = &(*slist)->next; - assert(*slist); - *slist = sh->next; - sh->next = deleted_ships; - deleted_ships = sh; - sh->region = NULL; -} - -void -free_ship(ship * s) -{ - while (s->attribs) a_remove(&s->attribs, s->attribs); - free(s->name); - free(s->display); - free(s); -} - -void -free_ships(void) -{ - while (deleted_ships) { - ship * s = deleted_ships; - deleted_ships = s->next; - } -} - -const char * -write_shipname(const ship * sh, char * ibuf, size_t size) -{ - snprintf(ibuf, size, "%s (%s)", sh->name, itoa36(sh->no)); - ibuf[size-1] = 0; - return ibuf; -} - -const char * -shipname(const ship * sh) -{ - typedef char name[OBJECTIDSIZE + 1]; - static name idbuf[8]; - static int nextbuf = 0; - char *ibuf = idbuf[(++nextbuf) % 8]; - return write_shipname(sh, ibuf, sizeof(name)); -} - -int -shipcapacity (const ship * sh) -{ - int i = sh->type->cargo; - - /* sonst ist construction:: size nicht ship_type::maxsize */ - assert(!sh->type->construction || sh->type->construction->improvement==NULL); - - if (sh->type->construction && sh->size!=sh->type->construction->maxsize) - return 0; - -#ifdef SHIPDAMAGE - if (sh->damage) { - i = (int)ceil(i * (1.0 - sh->damage / sh->size / (double)DAMAGE_SCALE)); - } -#endif - return i; -} - -void -getshipweight(const ship * sh, int *sweight, int *scabins) -{ - unit * u; - - *sweight = 0; - *scabins = 0; - - for (u = sh->region->units; u; u = u->next) { - if (u->ship == sh) { - *sweight += weight(u); - if (sh->type->cabins) { - int pweight = u->number * u->race->weight; - /* weight goes into number of cabins, not cargo */ - *scabins += pweight; - *sweight -= pweight; - } - } - } -} - -unit * -shipowner(const ship * sh) -{ - unit *u; - unit *first = NULL; - - const region * r = sh->region; - - /* Prüfen ob Eigentümer am leben. */ - for (u = r->units; u; u = u->next) { - if (u->ship == sh) { - if (!first && u->number > 0) - first = u; - if (fval(u, UFL_OWNER) && u->number > 0) - return u; - if (u->number == 0) - freset(u, UFL_OWNER); - } - } - - /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit - * nehmen. */ - - if (first) - fset(first, UFL_OWNER); - return first; -} - -void -write_ship_reference(const struct ship * sh, struct storage * store) -{ - store->w_id(store, (sh && sh->region)?sh->no:0); -} - -void -ship_setname(ship * self, const char * name) -{ - free(self->name); - if (name) self->name = strdup(name); - else self->name = NULL; -} - -const char * -ship_getname(const ship * self) -{ - return self->name; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "ship.h" + +/* kernel includes */ +#include "build.h" +#include "unit.h" +#include "item.h" +#include "race.h" +#include "region.h" +#include "skill.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + + +ship_typelist *shiptypes = NULL; + +static local_names * snames; + +const ship_type * +findshiptype(const char * name, const struct locale * lang) +{ + local_names * sn = snames; + variant var; + + while (sn) { + if (sn->lang==lang) break; + sn=sn->next; + } + if (!sn) { + struct ship_typelist * stl = shiptypes; + sn = calloc(sizeof(local_names), 1); + sn->next = snames; + sn->lang = lang; + while (stl) { + variant var; + const char * n = locale_string(lang, stl->type->name[0]); + var.v = (void*)stl->type; + addtoken(&sn->names, n, var); + stl = stl->next; + } + snames = sn; + } + if (findtoken(&sn->names, name, &var)==E_TOK_NOMATCH) return NULL; + return (const ship_type*)var.v; +} + +const ship_type * +st_find(const char* name) +{ + const struct ship_typelist * stl = shiptypes; + while (stl && strcmp(stl->type->name[0], name)) stl = stl->next; + return stl?stl->type:NULL; +} + +void +st_register(const ship_type * type) { + struct ship_typelist * stl = malloc(sizeof(ship_type)); + stl->type = type; + stl->next = shiptypes; + shiptypes = stl; +} + +#define SMAXHASH 7919 +ship *shiphash[SMAXHASH]; +void +shash(ship * s) +{ + ship *old = shiphash[s->no % SMAXHASH]; + + shiphash[s->no % SMAXHASH] = s; + s->nexthash = old; +} + +void +sunhash(ship * s) +{ + ship **show; + + for (show = &shiphash[s->no % SMAXHASH]; *show; show = &(*show)->nexthash) { + if ((*show)->no == s->no) + break; + } + if (*show) { + assert(*show == s); + *show = (*show)->nexthash; + s->nexthash = 0; + } +} + +static ship * +sfindhash(int i) +{ + ship *old; + + for (old = shiphash[i % SMAXHASH]; old; old = old->nexthash) + if (old->no == i) + return old; + return 0; +} + +struct ship * +findship(int i) +{ + return sfindhash(i); +} + +struct ship * +findshipr(const region *r, int n) +{ + ship * sh; + + for (sh = r->ships; sh; sh = sh->next) { + if (sh->no == n) { + assert(sh->region == r); + return sh; + } + } + return 0; +} + +void +damage_ship(ship * sh, double percent) +{ + double damage = DAMAGE_SCALE * sh->type->damage * percent * sh->size + sh->damage; + sh->damage = (int)damage; +} + +unit * +captain(ship *sh) +{ + unit *u; + + for(u = sh->region->units; u; u = u->next) + if(u->ship == sh && fval(u, UFL_OWNER)) return u; + + return NULL; +} + +/* Alte Schiffstypen: */ +static ship * deleted_ships; + +ship * +new_ship(const ship_type * stype, const struct locale * lang, region * r) +{ + static char buffer[7 + IDSIZE + 1]; + ship *sh = (ship *) calloc(1, sizeof(ship)); + + assert(stype); + sh->no = newcontainerid(); + sh->coast = NODIRECTION; + sh->type = stype; + sh->region = r; + + sprintf(buffer, "%s %s", LOC(lang, stype->name[0]), shipid(sh)); + sh->name = strdup(buffer); + shash(sh); + addlist(&r->ships, sh); + return sh; +} + +void +remove_ship(ship ** slist, ship * sh) +{ + region * r = sh->region; + unit * u = r->units; + + handle_event(sh->attribs, "destroy", sh); + while (u) { + if (u->ship == sh) { + leave_ship(u); + } + u = u->next; + } + sunhash(sh); + while (*slist && *slist!=sh) slist = &(*slist)->next; + assert(*slist); + *slist = sh->next; + sh->next = deleted_ships; + deleted_ships = sh; + sh->region = NULL; +} + +void +free_ship(ship * s) +{ + while (s->attribs) a_remove(&s->attribs, s->attribs); + free(s->name); + free(s->display); + free(s); +} + +void +free_ships(void) +{ + while (deleted_ships) { + ship * s = deleted_ships; + deleted_ships = s->next; + } +} + +const char * +write_shipname(const ship * sh, char * ibuf, size_t size) +{ + snprintf(ibuf, size, "%s (%s)", sh->name, itoa36(sh->no)); + ibuf[size-1] = 0; + return ibuf; +} + +const char * +shipname(const ship * sh) +{ + typedef char name[OBJECTIDSIZE + 1]; + static name idbuf[8]; + static int nextbuf = 0; + char *ibuf = idbuf[(++nextbuf) % 8]; + return write_shipname(sh, ibuf, sizeof(name)); +} + +int +shipcapacity (const ship * sh) +{ + int i = sh->type->cargo; + + /* sonst ist construction:: size nicht ship_type::maxsize */ + assert(!sh->type->construction || sh->type->construction->improvement==NULL); + + if (sh->type->construction && sh->size!=sh->type->construction->maxsize) + return 0; + +#ifdef SHIPDAMAGE + if (sh->damage) { + i = (int)ceil(i * (1.0 - sh->damage / sh->size / (double)DAMAGE_SCALE)); + } +#endif + return i; +} + +void +getshipweight(const ship * sh, int *sweight, int *scabins) +{ + unit * u; + + *sweight = 0; + *scabins = 0; + + for (u = sh->region->units; u; u = u->next) { + if (u->ship == sh) { + *sweight += weight(u); + if (sh->type->cabins) { + int pweight = u->number * u->race->weight; + /* weight goes into number of cabins, not cargo */ + *scabins += pweight; + *sweight -= pweight; + } + } + } +} + +unit * +shipowner(const ship * sh) +{ + unit *u; + unit *first = NULL; + + const region * r = sh->region; + + /* Prüfen ob Eigentümer am leben. */ + for (u = r->units; u; u = u->next) { + if (u->ship == sh) { + if (!first && u->number > 0) + first = u; + if (fval(u, UFL_OWNER) && u->number > 0) + return u; + if (u->number == 0) + freset(u, UFL_OWNER); + } + } + + /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit + * nehmen. */ + + if (first) + fset(first, UFL_OWNER); + return first; +} + +void +write_ship_reference(const struct ship * sh, struct storage * store) +{ + store->w_id(store, (sh && sh->region)?sh->no:0); +} + +void +ship_setname(ship * self, const char * name) +{ + free(self->name); + if (name) self->name = strdup(name); + else self->name = NULL; +} + +const char * +ship_getname(const ship * self) +{ + return self->name; +} diff --git a/src/kernel/ship.h b/src/kernel/ship.h index c850b480e..0bc8ee9d4 100644 --- a/src/kernel/ship.h +++ b/src/kernel/ship.h @@ -1,127 +1,127 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_SHIP -#define H_KRNL_SHIP -#ifdef __cplusplus -extern "C" { -#endif - -#include "types.h" - -#define DAMAGE_SCALE 100 /* multiplier for sh->damage */ - -/* ship_type::flags */ -#define SFL_OPENSEA 0x01 -#define SFL_FLY 0x02 -#define SFL_NOCOAST 0x04 - -typedef struct ship_type { - const char * name[2]; - - int range; /* range in regions */ - int flags; /* flags */ - int combat; /* modifier for combat */ - - double storm; /* multiplier for chance to drift in storm */ - double damage; /* multiplier for damage taken by the ship */ - - int cabins; /* max. cabins (weight) */ - int cargo; /* max. cargo (weight) */ - - int cptskill; /* min. skill of captain */ - int minskill; /* min. skill to sail this (crew) */ - int sumskill; /* min. sum of crew+captain */ - - int fishing; /* weekly income from fishing */ - - int at_bonus; /* Verändert den Angriffsskill (default: 0)*/ - int df_bonus; /* Verändert den Verteidigungskill (default: 0)*/ - float tac_bonus; - - const struct terrain_type ** coasts; /* coast that this ship can land on */ - - struct construction * construction; /* how to build a ship */ -} ship_type; - -typedef struct ship_typelist { - struct ship_typelist * next; - const ship_type * type; -} ship_typelist; - -extern ship_typelist *shiptypes; - -/* Alte Schiffstypen: */ - -extern const ship_type * st_find(const char* name); -extern void st_register(const ship_type * type); - -#define NOSHIP NULL - -#define SF_DRIFTED 1<<0 -#define SF_MOVED 1<<1 -#define SF_DAMAGED 1<<2 /* for use in combat */ -#define SF_SELECT 1<<3 /* previously FL_DH */ -#define SF_FISHING 1<<4 /* was on an ocean, can fish */ -#define SF_FLYING 1<<5 /* the ship can fly */ - -#define SFL_SAVEMASK (SF_FLYING) -#define INCOME_FISHING 10 - -typedef struct ship { - struct ship *next; - struct ship *nexthash; - int no; - struct region *region; - char *name; - char *display; - struct attrib * attribs; - int size; - int damage; /* damage in 100th of a point of size */ - unsigned int flags; - const struct ship_type * type; - direction_t coast; -} ship; - -extern void damage_ship(ship *sh, double percent); -extern struct unit *captain(ship *sh); -extern struct unit *shipowner(const struct ship * sh); -extern const char * shipname(const struct ship * self); -extern int shipcapacity(const struct ship * sh); -extern void getshipweight(const struct ship * sh, int *weight, int *cabins); - -extern ship *new_ship(const struct ship_type * stype, const struct locale * lang, struct region * r); -extern const char *write_shipname(const struct ship * sh, char * buffer, size_t size); -extern struct ship *findship(int n); -extern struct ship *findshipr(const struct region *r, int n); - -extern const struct ship_type * findshiptype(const char *s, const struct locale * lang); - -extern void write_ship_reference(const struct ship * sh, struct storage * store); - -extern void remove_ship(struct ship ** slist, struct ship * s); -extern void free_ship(struct ship * s); -extern void free_ships(void); - -extern const char * ship_getname(const struct ship * self); -extern void ship_setname(struct ship * self, const char * name); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_SHIP +#define H_KRNL_SHIP +#ifdef __cplusplus +extern "C" { +#endif + +#include "types.h" + +#define DAMAGE_SCALE 100 /* multiplier for sh->damage */ + +/* ship_type::flags */ +#define SFL_OPENSEA 0x01 +#define SFL_FLY 0x02 +#define SFL_NOCOAST 0x04 + +typedef struct ship_type { + const char * name[2]; + + int range; /* range in regions */ + int flags; /* flags */ + int combat; /* modifier for combat */ + + double storm; /* multiplier for chance to drift in storm */ + double damage; /* multiplier for damage taken by the ship */ + + int cabins; /* max. cabins (weight) */ + int cargo; /* max. cargo (weight) */ + + int cptskill; /* min. skill of captain */ + int minskill; /* min. skill to sail this (crew) */ + int sumskill; /* min. sum of crew+captain */ + + int fishing; /* weekly income from fishing */ + + int at_bonus; /* Verändert den Angriffsskill (default: 0)*/ + int df_bonus; /* Verändert den Verteidigungskill (default: 0)*/ + float tac_bonus; + + const struct terrain_type ** coasts; /* coast that this ship can land on */ + + struct construction * construction; /* how to build a ship */ +} ship_type; + +typedef struct ship_typelist { + struct ship_typelist * next; + const ship_type * type; +} ship_typelist; + +extern ship_typelist *shiptypes; + +/* Alte Schiffstypen: */ + +extern const ship_type * st_find(const char* name); +extern void st_register(const ship_type * type); + +#define NOSHIP NULL + +#define SF_DRIFTED 1<<0 +#define SF_MOVED 1<<1 +#define SF_DAMAGED 1<<2 /* for use in combat */ +#define SF_SELECT 1<<3 /* previously FL_DH */ +#define SF_FISHING 1<<4 /* was on an ocean, can fish */ +#define SF_FLYING 1<<5 /* the ship can fly */ + +#define SFL_SAVEMASK (SF_FLYING) +#define INCOME_FISHING 10 + +typedef struct ship { + struct ship *next; + struct ship *nexthash; + int no; + struct region *region; + char *name; + char *display; + struct attrib * attribs; + int size; + int damage; /* damage in 100th of a point of size */ + unsigned int flags; + const struct ship_type * type; + direction_t coast; +} ship; + +extern void damage_ship(ship *sh, double percent); +extern struct unit *captain(ship *sh); +extern struct unit *shipowner(const struct ship * sh); +extern const char * shipname(const struct ship * self); +extern int shipcapacity(const struct ship * sh); +extern void getshipweight(const struct ship * sh, int *weight, int *cabins); + +extern ship *new_ship(const struct ship_type * stype, const struct locale * lang, struct region * r); +extern const char *write_shipname(const struct ship * sh, char * buffer, size_t size); +extern struct ship *findship(int n); +extern struct ship *findshipr(const struct region *r, int n); + +extern const struct ship_type * findshiptype(const char *s, const struct locale * lang); + +extern void write_ship_reference(const struct ship * sh, struct storage * store); + +extern void remove_ship(struct ship ** slist, struct ship * s); +extern void free_ship(struct ship * s); +extern void free_ships(void); + +extern const char * ship_getname(const struct ship * self); +extern void ship_setname(struct ship * self, const char * name); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/skill.c b/src/kernel/skill.c index 645b8cffa..5f8d053d4 100644 --- a/src/kernel/skill.c +++ b/src/kernel/skill.c @@ -1,315 +1,315 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "skill.h" - -#include "curse.h" -#include "item.h" -#include "magic.h" -#include "race.h" -#include "region.h" -#include "terrain.h" -#include "terrainid.h" -#include "unit.h" - -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -const char *skillnames[MAXSKILLS] = -{ - "alchemy", - "crossbow", - "mining", - "bow", - "building", - "trade", - "forestry", - "catapult", - "herbalism", - "magic", - "training", - "riding", - "armorer", - "shipcraft", - "melee", - "sailing", - "polearm", - "espionage", - "quarrying", - "roadwork", - "tactics", - "stealth", - "entertainment", - "weaponsmithing", - "cartmaking", - "perception", - "taxation", - "stamina", - "unarmed" -}; - -boolean skill_enabled[MAXSKILLS]; - -const char * -skillname(skill_t sk, const struct locale * lang) -{ - if (skill_enabled[sk]) { - return locale_string(lang, mkname("skill", skillnames[sk])); - } - return NULL; -} - -void -enable_skill(const char * skname, boolean value) -{ - skill_t sk; - for (sk=0;sk!=MAXSKILLS;++sk) { - if (strcmp(skillnames[sk], skname)==0) { - skill_enabled[sk] = value; - return; - } - } - log_error(("Trying to set unknown skill %s to %u", skname, value)); -} - -skill_t -sk_find(const char * name) -{ - skill_t i; - if (name==NULL) return NOSKILL; - if (strncmp(name, "sk_", 3)==0) name+=3; - for (i=0;i!=MAXSKILLS;++i) { - if (skill_enabled[i]) { - if (strcmp(name, skillnames[i])==0) return i; - } - } - return NOSKILL; -} - -/** skillmod attribut **/ -static void -init_skillmod(attrib * a) { - a->data.v = calloc(sizeof(skillmod_data), 1); -} - -static void -finalize_skillmod(attrib * a) -{ - free(a->data.v); -} - -/** temporary skill modification (NOT SAVED!). */ -attrib_type at_skillmod = { - "skillmod", - init_skillmod, - finalize_skillmod, - NULL, - NULL, /* can't write function pointers */ - NULL, /* can't read function pointers */ - ATF_PRESERVE -}; - -attrib * -make_skillmod(skill_t sk, unsigned int flags, skillmod_fun special, double multiplier, int bonus) -{ - attrib * a = a_new(&at_skillmod); - skillmod_data * smd = (skillmod_data*)a->data.v; - - smd->skill=sk; - smd->special=special; - smd->bonus=bonus; - smd->multiplier=multiplier; - smd->flags=flags; - - return a; -} - -int -skillmod(const attrib * a, const unit * u, const region * r, skill_t sk, int value, int flags) -{ - for (a = a_find((attrib*)a, &at_skillmod); a && a->type==&at_skillmod; a=a->next) { - skillmod_data * smd = (skillmod_data *)a->data.v; - if (smd->skill!=NOSKILL && smd->skill!=sk) continue; - if (flags!=SMF_ALWAYS && (smd->flags & flags) == 0) continue; - if (smd->special) { - value = smd->special(u, r, sk, value); - if (value<0) return value; /* pass errors back to caller */ - } - if (smd->multiplier) value = (int)(value*smd->multiplier); - value += smd->bonus; - } - return value; -} - -int -skill_mod(const race * rc, skill_t sk, const struct terrain_type * terrain) -{ - int result = 0; - - result = rc->bonus[sk]; - - if (rc == new_race[RC_DWARF]) { - if (sk==SK_TACTICS) { - if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION)) - ++result; - } - } - else if (rc == new_race[RC_INSECT]) { - if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION)) - --result; - else if (terrain == newterrain(T_DESERT) || terrain == newterrain(T_SWAMP)) - ++result; - } - - return result; -} - -#define RCMODMAXHASH 31 -#ifdef FASTER_SKILLMOD -static struct skillmods { - struct skillmods * next; - const struct race * race; - struct modifiers { - int value[MAXSKILLS]; - } mod[MAXTERRAINS]; -} * modhash[RCMODMAXHASH]; - -static struct skillmods * -init_skills(const race * rc) -{ - terrain_t t; - struct skillmods *mods = (struct skillmods*)calloc(1, sizeof(struct skillmods)); - mods->race = rc; - - for (t=0;t!=MAXTERRAINS;++t) { - skill_t sk; - for (sk=0;sk!=MAXSKILLS;++sk) { - mods->mod[t].value[sk] = skill_mod(rc, sk, newterrain(t)); - } - } - return mods; -} -#endif - -int -rc_skillmod(const struct race * rc, const region *r, skill_t sk) -{ - int mods; - - if (!skill_enabled[sk]) return 0; -#ifdef FASTER_SKILLMOD - unsigned int index = hashstring(rc->_name[0]) % RCMODMAXHASH; - struct skillmods **imods = &modhash[index]; - while (*imods && (*imods)->race!=rc) imods = &(*imods)->next; - if (*imods==NULL) { - *imods = init_skills(rc); - } - mods = (*imods)->mod[rterrain(r)].value[sk]; -#else - mods = skill_mod(rc, sk, r->terrain); -#endif - if (rc == new_race[RC_ELF] && r_isforest(r)) switch (sk) { - case SK_PERCEPTION: - ++mods; - break; - case SK_STEALTH: - if (r_isforest(r)) ++mods; - break; - case SK_TACTICS: - if (r_isforest(r)) mods += 2; - break; - } - - return mods; -} - -int -level_days(int level) -{ - return 30 * ((level+1) * level / 2); -} - -int -level(int days) -{ - int i; - static int ldays[64]; - static boolean init = false; - if (!init) { - init = true; - for (i=0;i!=64;++i) ldays[i] = level_days(i+1); - } - for (i=0;i!=64;++i) if (ldays[i]>days) return i; - return i; -} - -void -sk_set(skill * sv, int level) -{ - assert(level!=0); - sv->weeks = (unsigned char)skill_weeks(level); - sv->level = (unsigned char)level; -} - -int -skill_weeks(int level) -/* how many weeks must i study to get from level to level+1 */ -{ - int coins = 2*level; - int heads = 1; - while (coins--) { - heads += rng_int() % 2; - } - return heads; -} - -void -reduce_skill(unit * u, skill * sv, unsigned int weeks) -{ - sv->weeks+=weeks; - while (sv->level>0 && sv->level*2+1weeks) { - sv->weeks -= sv->level; - --sv->level; - } - if (sv->level==0) { - /* reroll */ - sv->weeks = (unsigned char)skill_weeks(sv->level); - } -} - - -int -skill_compare(const skill * sk, const skill * sc) -{ - if (sk->level > sc->level) return 1; - if (sk->level < sc->level) return -1; - if (sk->weeks < sc->weeks) return 1; - if (sk->weeks > sc->weeks) return -1; - return 0; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "skill.h" + +#include "curse.h" +#include "item.h" +#include "magic.h" +#include "race.h" +#include "region.h" +#include "terrain.h" +#include "terrainid.h" +#include "unit.h" + +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +const char *skillnames[MAXSKILLS] = +{ + "alchemy", + "crossbow", + "mining", + "bow", + "building", + "trade", + "forestry", + "catapult", + "herbalism", + "magic", + "training", + "riding", + "armorer", + "shipcraft", + "melee", + "sailing", + "polearm", + "espionage", + "quarrying", + "roadwork", + "tactics", + "stealth", + "entertainment", + "weaponsmithing", + "cartmaking", + "perception", + "taxation", + "stamina", + "unarmed" +}; + +boolean skill_enabled[MAXSKILLS]; + +const char * +skillname(skill_t sk, const struct locale * lang) +{ + if (skill_enabled[sk]) { + return locale_string(lang, mkname("skill", skillnames[sk])); + } + return NULL; +} + +void +enable_skill(const char * skname, boolean value) +{ + skill_t sk; + for (sk=0;sk!=MAXSKILLS;++sk) { + if (strcmp(skillnames[sk], skname)==0) { + skill_enabled[sk] = value; + return; + } + } + log_error(("Trying to set unknown skill %s to %u", skname, value)); +} + +skill_t +sk_find(const char * name) +{ + skill_t i; + if (name==NULL) return NOSKILL; + if (strncmp(name, "sk_", 3)==0) name+=3; + for (i=0;i!=MAXSKILLS;++i) { + if (skill_enabled[i]) { + if (strcmp(name, skillnames[i])==0) return i; + } + } + return NOSKILL; +} + +/** skillmod attribut **/ +static void +init_skillmod(attrib * a) { + a->data.v = calloc(sizeof(skillmod_data), 1); +} + +static void +finalize_skillmod(attrib * a) +{ + free(a->data.v); +} + +/** temporary skill modification (NOT SAVED!). */ +attrib_type at_skillmod = { + "skillmod", + init_skillmod, + finalize_skillmod, + NULL, + NULL, /* can't write function pointers */ + NULL, /* can't read function pointers */ + ATF_PRESERVE +}; + +attrib * +make_skillmod(skill_t sk, unsigned int flags, skillmod_fun special, double multiplier, int bonus) +{ + attrib * a = a_new(&at_skillmod); + skillmod_data * smd = (skillmod_data*)a->data.v; + + smd->skill=sk; + smd->special=special; + smd->bonus=bonus; + smd->multiplier=multiplier; + smd->flags=flags; + + return a; +} + +int +skillmod(const attrib * a, const unit * u, const region * r, skill_t sk, int value, int flags) +{ + for (a = a_find((attrib*)a, &at_skillmod); a && a->type==&at_skillmod; a=a->next) { + skillmod_data * smd = (skillmod_data *)a->data.v; + if (smd->skill!=NOSKILL && smd->skill!=sk) continue; + if (flags!=SMF_ALWAYS && (smd->flags & flags) == 0) continue; + if (smd->special) { + value = smd->special(u, r, sk, value); + if (value<0) return value; /* pass errors back to caller */ + } + if (smd->multiplier) value = (int)(value*smd->multiplier); + value += smd->bonus; + } + return value; +} + +int +skill_mod(const race * rc, skill_t sk, const struct terrain_type * terrain) +{ + int result = 0; + + result = rc->bonus[sk]; + + if (rc == new_race[RC_DWARF]) { + if (sk==SK_TACTICS) { + if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION)) + ++result; + } + } + else if (rc == new_race[RC_INSECT]) { + if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION)) + --result; + else if (terrain == newterrain(T_DESERT) || terrain == newterrain(T_SWAMP)) + ++result; + } + + return result; +} + +#define RCMODMAXHASH 31 +#ifdef FASTER_SKILLMOD +static struct skillmods { + struct skillmods * next; + const struct race * race; + struct modifiers { + int value[MAXSKILLS]; + } mod[MAXTERRAINS]; +} * modhash[RCMODMAXHASH]; + +static struct skillmods * +init_skills(const race * rc) +{ + terrain_t t; + struct skillmods *mods = (struct skillmods*)calloc(1, sizeof(struct skillmods)); + mods->race = rc; + + for (t=0;t!=MAXTERRAINS;++t) { + skill_t sk; + for (sk=0;sk!=MAXSKILLS;++sk) { + mods->mod[t].value[sk] = skill_mod(rc, sk, newterrain(t)); + } + } + return mods; +} +#endif + +int +rc_skillmod(const struct race * rc, const region *r, skill_t sk) +{ + int mods; + + if (!skill_enabled[sk]) return 0; +#ifdef FASTER_SKILLMOD + unsigned int index = hashstring(rc->_name[0]) % RCMODMAXHASH; + struct skillmods **imods = &modhash[index]; + while (*imods && (*imods)->race!=rc) imods = &(*imods)->next; + if (*imods==NULL) { + *imods = init_skills(rc); + } + mods = (*imods)->mod[rterrain(r)].value[sk]; +#else + mods = skill_mod(rc, sk, r->terrain); +#endif + if (rc == new_race[RC_ELF] && r_isforest(r)) switch (sk) { + case SK_PERCEPTION: + ++mods; + break; + case SK_STEALTH: + if (r_isforest(r)) ++mods; + break; + case SK_TACTICS: + if (r_isforest(r)) mods += 2; + break; + } + + return mods; +} + +int +level_days(int level) +{ + return 30 * ((level+1) * level / 2); +} + +int +level(int days) +{ + int i; + static int ldays[64]; + static boolean init = false; + if (!init) { + init = true; + for (i=0;i!=64;++i) ldays[i] = level_days(i+1); + } + for (i=0;i!=64;++i) if (ldays[i]>days) return i; + return i; +} + +void +sk_set(skill * sv, int level) +{ + assert(level!=0); + sv->weeks = (unsigned char)skill_weeks(level); + sv->level = (unsigned char)level; +} + +int +skill_weeks(int level) +/* how many weeks must i study to get from level to level+1 */ +{ + int coins = 2*level; + int heads = 1; + while (coins--) { + heads += rng_int() % 2; + } + return heads; +} + +void +reduce_skill(unit * u, skill * sv, unsigned int weeks) +{ + sv->weeks+=weeks; + while (sv->level>0 && sv->level*2+1weeks) { + sv->weeks -= sv->level; + --sv->level; + } + if (sv->level==0) { + /* reroll */ + sv->weeks = (unsigned char)skill_weeks(sv->level); + } +} + + +int +skill_compare(const skill * sk, const skill * sc) +{ + if (sk->level > sc->level) return 1; + if (sk->level < sc->level) return -1; + if (sk->weeks < sc->weeks) return 1; + if (sk->weeks > sc->weeks) return -1; + return 0; +} diff --git a/src/kernel/skill.h b/src/kernel/skill.h index 6e7173eca..1ed5c6ad6 100644 --- a/src/kernel/skill.h +++ b/src/kernel/skill.h @@ -1,66 +1,66 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - */ - -#ifndef H_KRNL_SKILL -#define H_KRNL_SKILL -#ifdef __cplusplus -extern "C" { -#endif - -extern signed char skill_bonus(struct unit * u, struct region * r); - -/* skillmod_data::flags -- wann gilt der modifier? */ -#define SMF_ALWAYS (1<<0) /* immer */ -#define SMF_PRODUCTION (1<<1) /* für Produktion - am gebäude, an der einheit */ -#define SMF_RIDING (1<<2) /* Bonus für berittene - an der rasse*/ - -typedef struct skill { - unsigned char id; - unsigned int level : 8; - unsigned int weeks : 8; - unsigned int old : 8; -} skill; - -typedef int (*skillmod_fun)(const struct unit*, const struct region*, skill_t, int); -typedef struct skillmod_data { - skill_t skill; - skillmod_fun special; - double multiplier; - int number; - int bonus; - int flags; -} skillmod_data; -extern struct attrib_type at_skillmod; -extern int rc_skillmod(const struct race * rc, const struct region *r, skill_t sk); -extern int skillmod(const struct attrib * a, const struct unit * u, const struct region * r, skill_t sk, int value, int flags); -extern struct attrib * make_skillmod(skill_t sk, unsigned int flags, skillmod_fun special, double multiplier, int bonus); - -extern const char * skillname(skill_t, const struct locale *); -extern skill_t sk_find(const char * name); -extern void enable_skill(const char * name, boolean value); -extern int level_days(int level); -extern int level(int days); - -#define skill_level(level) (level) -extern void reduce_skill(struct unit *u, skill * sv, unsigned int change); -extern int skill_weeks(int level); -extern int skill_compare(const skill * sk, const skill * sc); - -extern void sk_set(skill * sv, int level); - -extern const char *skillnames[]; -extern boolean skill_enabled[]; - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + */ + +#ifndef H_KRNL_SKILL +#define H_KRNL_SKILL +#ifdef __cplusplus +extern "C" { +#endif + +extern signed char skill_bonus(struct unit * u, struct region * r); + +/* skillmod_data::flags -- wann gilt der modifier? */ +#define SMF_ALWAYS (1<<0) /* immer */ +#define SMF_PRODUCTION (1<<1) /* für Produktion - am gebäude, an der einheit */ +#define SMF_RIDING (1<<2) /* Bonus für berittene - an der rasse*/ + +typedef struct skill { + unsigned char id; + unsigned int level : 8; + unsigned int weeks : 8; + unsigned int old : 8; +} skill; + +typedef int (*skillmod_fun)(const struct unit*, const struct region*, skill_t, int); +typedef struct skillmod_data { + skill_t skill; + skillmod_fun special; + double multiplier; + int number; + int bonus; + int flags; +} skillmod_data; +extern struct attrib_type at_skillmod; +extern int rc_skillmod(const struct race * rc, const struct region *r, skill_t sk); +extern int skillmod(const struct attrib * a, const struct unit * u, const struct region * r, skill_t sk, int value, int flags); +extern struct attrib * make_skillmod(skill_t sk, unsigned int flags, skillmod_fun special, double multiplier, int bonus); + +extern const char * skillname(skill_t, const struct locale *); +extern skill_t sk_find(const char * name); +extern void enable_skill(const char * name, boolean value); +extern int level_days(int level); +extern int level(int days); + +#define skill_level(level) (level) +extern void reduce_skill(struct unit *u, skill * sv, unsigned int change); +extern int skill_weeks(int level); +extern int skill_compare(const skill * sk, const skill * sc); + +extern void sk_set(skill * sv, int level); + +extern const char *skillnames[]; +extern boolean skill_enabled[]; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/spell.c b/src/kernel/spell.c index c9c8edfc9..7bd05cf15 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -1,184 +1,184 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "spell.h" - -/* kernel includes */ -#include "magic.h" -#include "unit.h" - -/* libc includes */ -#include -#include - -/* util includes */ -#include -#include -#include -#include - - /* Bitte die Sprüche nach Gebieten und Stufe ordnen, denn in derselben - * Reihenfolge wie in Spelldaten tauchen sie auch im Report auf - */ - -spell_list * spells = NULL; - -void -register_spell(spell * sp) -{ - if (sp->id==0) { - sp->id = hashstring(sp->sname); - } - spelllist_add(&spells, sp); -} - -/** versucht einen Spruch über gebiet + name zu identifizieren. - * gibt ansonsten NULL zurück */ -spell * -find_spell(magic_t mtype, const char * name) -{ - spell_list * slist = spells; - spell * spx = NULL; - while (slist) { - spell * sp = slist->data; - if (strcmp(name, sp->sname)==0) { - if (mtype==M_NONE || sp->magietyp==mtype) return sp; - spx = sp; - } - slist = slist->next; - } - if (spx==NULL) { - log_error(("cannot find spell by name: %s\n", name)); - } - return spx; -} - - -/* ------------------------------------------------------------- */ -/* Spruch identifizieren */ - -typedef struct spell_names { - struct spell_names * next; - const struct locale * lang; - magic_t mtype; - struct tnode names; -} spell_names; - -static spell_names * spellnames; - -static spell_names * -init_spellnames(const struct locale * lang, magic_t mtype) -{ - spell_list * slist; - spell_names * sn = calloc(sizeof(spell_names), 1); - sn->next = spellnames; - sn->lang = lang; - sn->mtype = mtype; - for (slist=spells;slist!=NULL;slist=slist->next) { - spell * sp = slist->data; - if (sp->magietyp==mtype) { - const char * n = spell_name(sp, lang); - variant token; - token.v = sp; - addtoken(&sn->names, n, token); - } - } - return spellnames = sn; -} - -static spell_names * -get_spellnames(const struct locale * lang, magic_t mtype) -{ - spell_names * sn = spellnames; - while (sn) { - if (sn->mtype==mtype && sn->lang==lang) break; - sn=sn->next; - } - if (!sn) return init_spellnames(lang, mtype); - return sn; -} - -static spell * -get_spellfromtoken_i(const char *name, const struct locale * lang, magic_t mtype) -{ - variant token = { 0 }; - spell_names * sn; - - sn = get_spellnames(lang, mtype); - if (findtoken(&sn->names, name, &token)==E_TOK_NOMATCH) { - magic_t mt; - /* if we could not find it in the main magic type, we look through all the others */ - for (mt=0;mt!=MAXMAGIETYP;++mt) { - if (mt!=mtype) { - sn = get_spellnames(lang, mt); - if (findtoken(&sn->names, name, &token)!=E_TOK_NOMATCH) break; - } - } - } - - if (token.v!=NULL) return (spell*)token.v; - if (lang==default_locale) return NULL; - return get_spellfromtoken_i(name, default_locale, mtype); -} - -spell * -get_spellfromtoken(unit *u, const char *name, const struct locale * lang) -{ - sc_mage * m = get_mage(u); - spell * sp; - - if (m==NULL) return NULL; - sp = get_spellfromtoken_i(name, lang, m->magietyp); - if (sp!=NULL) { - spell_list * slist = m->spells; - - while (slist && slist->data->id<=sp->id) { - if (sp==slist->data) return sp; - slist = slist->next; - } - } - return NULL; -} - -spell * -find_spellbyid(magic_t mtype, spellid_t id) -{ - spell_list * slist; - - assert(id>=0); - if (id==0) return NULL; - for (slist=spells;slist!=NULL;slist=slist->next) { - spell* sp = slist->data; - if (sp->id == id) return sp; - } - for (slist=spells;slist!=NULL;slist=slist->next) { - spell* sp = slist->data; - unsigned int hashid = hashstring(sp->sname); - if (hashid==id) { - if (sp->magietyp==mtype || mtype==M_NONE) { - return sp; - } - } - } - - log_warning(("cannot find spell by id: %u\n", id)); - return NULL; -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "spell.h" + +/* kernel includes */ +#include "magic.h" +#include "unit.h" + +/* libc includes */ +#include +#include + +/* util includes */ +#include +#include +#include +#include + + /* Bitte die Sprüche nach Gebieten und Stufe ordnen, denn in derselben + * Reihenfolge wie in Spelldaten tauchen sie auch im Report auf + */ + +spell_list * spells = NULL; + +void +register_spell(spell * sp) +{ + if (sp->id==0) { + sp->id = hashstring(sp->sname); + } + spelllist_add(&spells, sp); +} + +/** versucht einen Spruch über gebiet + name zu identifizieren. + * gibt ansonsten NULL zurück */ +spell * +find_spell(magic_t mtype, const char * name) +{ + spell_list * slist = spells; + spell * spx = NULL; + while (slist) { + spell * sp = slist->data; + if (strcmp(name, sp->sname)==0) { + if (mtype==M_NONE || sp->magietyp==mtype) return sp; + spx = sp; + } + slist = slist->next; + } + if (spx==NULL) { + log_error(("cannot find spell by name: %s\n", name)); + } + return spx; +} + + +/* ------------------------------------------------------------- */ +/* Spruch identifizieren */ + +typedef struct spell_names { + struct spell_names * next; + const struct locale * lang; + magic_t mtype; + struct tnode names; +} spell_names; + +static spell_names * spellnames; + +static spell_names * +init_spellnames(const struct locale * lang, magic_t mtype) +{ + spell_list * slist; + spell_names * sn = calloc(sizeof(spell_names), 1); + sn->next = spellnames; + sn->lang = lang; + sn->mtype = mtype; + for (slist=spells;slist!=NULL;slist=slist->next) { + spell * sp = slist->data; + if (sp->magietyp==mtype) { + const char * n = spell_name(sp, lang); + variant token; + token.v = sp; + addtoken(&sn->names, n, token); + } + } + return spellnames = sn; +} + +static spell_names * +get_spellnames(const struct locale * lang, magic_t mtype) +{ + spell_names * sn = spellnames; + while (sn) { + if (sn->mtype==mtype && sn->lang==lang) break; + sn=sn->next; + } + if (!sn) return init_spellnames(lang, mtype); + return sn; +} + +static spell * +get_spellfromtoken_i(const char *name, const struct locale * lang, magic_t mtype) +{ + variant token = { 0 }; + spell_names * sn; + + sn = get_spellnames(lang, mtype); + if (findtoken(&sn->names, name, &token)==E_TOK_NOMATCH) { + magic_t mt; + /* if we could not find it in the main magic type, we look through all the others */ + for (mt=0;mt!=MAXMAGIETYP;++mt) { + if (mt!=mtype) { + sn = get_spellnames(lang, mt); + if (findtoken(&sn->names, name, &token)!=E_TOK_NOMATCH) break; + } + } + } + + if (token.v!=NULL) return (spell*)token.v; + if (lang==default_locale) return NULL; + return get_spellfromtoken_i(name, default_locale, mtype); +} + +spell * +get_spellfromtoken(unit *u, const char *name, const struct locale * lang) +{ + sc_mage * m = get_mage(u); + spell * sp; + + if (m==NULL) return NULL; + sp = get_spellfromtoken_i(name, lang, m->magietyp); + if (sp!=NULL) { + spell_list * slist = m->spells; + + while (slist && slist->data->id<=sp->id) { + if (sp==slist->data) return sp; + slist = slist->next; + } + } + return NULL; +} + +spell * +find_spellbyid(magic_t mtype, spellid_t id) +{ + spell_list * slist; + + assert(id>=0); + if (id==0) return NULL; + for (slist=spells;slist!=NULL;slist=slist->next) { + spell* sp = slist->data; + if (sp->id == id) return sp; + } + for (slist=spells;slist!=NULL;slist=slist->next) { + spell* sp = slist->data; + unsigned int hashid = hashstring(sp->sname); + if (hashid==id) { + if (sp->magietyp==mtype || mtype==M_NONE) { + return sp; + } + } + } + + log_warning(("cannot find spell by id: %u\n", id)); + return NULL; +} + diff --git a/src/kernel/spell.h b/src/kernel/spell.h index ddf903c24..9a250deb0 100644 --- a/src/kernel/spell.h +++ b/src/kernel/spell.h @@ -1,159 +1,159 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_SPELL -#define H_KRNL_SPELL -#ifdef __cplusplus -extern "C" { -#endif - - struct fighter; - struct spell; - struct border_type; - struct attrib_type; - struct curse_type; - struct castorder; - struct curse; - - /* Prototypen */ - - int use_item_power(struct region * r, struct unit * u); - int use_item_regeneration(struct region * r, struct unit * u); - void showspells(struct region *r, struct unit *u); - int sp_antimagiczone(struct castorder *co); - - /* ------------------------------------------------------------- */ - - extern struct attrib_type at_unitdissolve; - extern struct attrib_type at_wdwpyramid; - - extern struct spell_list * spells; - extern void register_spell(struct spell * sp); - extern struct spell * find_spell(magic_t mtype, const char * name); - extern struct spell * find_spellbyid(magic_t mtype, spellid_t i); - extern struct spell *get_spellfromtoken(struct unit *u, const char *s, const struct locale * lang); - -#ifdef __cplusplus -} -#endif -#endif - -/* ------------------------------------------------------------- */ -/* Erläuterungen zu den Spruchdefinitionen - * - * Spruchstukturdefinition: - * spell{ - * id, name, - * beschreibung, - * syntax, - * parameter, - * magietyp, - * sptyp, - * rank,level, - * costtyp, aura, - * komponenten[5][2][faktorart], - * &funktion, patzer} - * - * id: - * SPL_NOSPELL muss der letzte Spruch in der Liste spelldaten sein, - * denn nicht auf die Reihenfolge in der Liste sondern auf die id wird - * geprüft - * - * sptyp: - * besondere Spruchtypen und Flags - * (Regionszauber, Kampfzauber, Farcastbar, Stufe variable, ..) - * - * rank: - * gibt die Priorität und damit die Reihenfolge an, in der der Spruch - * gezaubert wird. - * 1: Aura übertragen - * 2: Antimagie - * 3: Magierverändernde Sprüche (Magic Boost, ..) - * 4: Monster erschaffen - * 5: Standartlevel - * 7: Teleport - * - * Komponenten[Anzahl mögl. Items][Art:Anzahl:Kostentyp] - * - * R_AURA: - * Grundkosten für einen Zauber. Soviel Mp müssen mindestens investiert - * werden, um den Spruch zu wirken. Zusätzliche Mp können unterschiedliche - * Auswirkungen haben, die in der Spruchfunktionsroutine definiert werden. - * - * R_PERMAURA: - * Kosten an permantenter Aura - * - * Komponenten Kostentyp: - * SPC_LEVEL == Spruch mit Levelabhängigen Magiekosten. Die angegeben - * Kosten müssen für Stufe 1 berechnet sein. - * SPC_FIX == Feste Kosten - * - * Wenn keine spezielle Syntax angegeben ist, wird die - * Syntaxbeschreibung aus sptyp generiert: - * FARCASTING: ZAUBER [REGION x y] - * SPELLLEVEL: ZAUBER [STUFE n] - * UNITSPELL : ZAUBER [ ..] - * SHIPSPELL : ZAUBER [ ..] - * BUILDINGSPELL: ZAUBER [ ..] - * PRECOMBATSPELL : KAMPFZAUBER [STUFE n] - * COMBATSPELL : KAMPFZAUBER [STUFE n] - * POSTCOMBATSPELL: KAMPFZAUBER [STUFE n] - * - * Das Parsing - * - * Der String spell->parameter gibt die Syntax an, nach der die - * Parameter des Spruches in add_spellparameter() geparst werden sollen. - * - * u : eine Einheitennummer - * r : hier kommen zwei Regionskoordinaten x y - * b : Gebäude- oder Burgnummer - * s : Schiffsnummer - * c : String, wird ohne Weiterverarbeitung übergeben - * i : Zahl (int), wird ohne Weiterverarbeitung übergeben - * k : Keywort - dieser String gibt den Paramter an, der folgt. Der - * Parameter wird mit findparam() identifiziert. - * k muss immer von einem c als Platzhalter für das Objekt gefolgt - * werden. - * Ein gutes Beispiel sind hierfür die Sprüche zur Magieanalyse. - * + : gibt an, das der vorherige Parameter mehrfach vorkommen kann. Da - * ein Ende nicht definiert werden kann, muss dies immer am Schluss - * kommen. - * - * Flags für das Parsing: - * TESTRESISTANCE : alle Zielobjekte, also alle Parameter vom Typ Unit, - * Burg, Schiff oder Region, werden auf ihre - * Magieresistenz überprüft - * TESTCANSEE : jedes Objekt vom Typ Einheit wird auf seine - * Sichtbarkeit überprüft - * SEARCHLOCAL : die Zielobjekte werden nur regional gesucht - * REGIONSPELL : Ziel ist die Region, auch wenn kein Zielobjekt - * angegeben wird. Ist TESTRESISTANCE gesetzt, so wird - * die Magieresistenz der Region überprüft - * - * Bei fehlendem Ziel oder wenn dieses dem Zauber widersteht, wird die - * Spruchfunktion nicht aufgerufen. - * Sind zu wenig Parameter vorhanden, wird der Zauber ebenfalls nicht - * ausgeführt. - * Ist eins von mehreren Zielobjekten resistent, so wird das Flag - * pa->param[n]->flag == TARGET_RESISTS - * Ist eins von mehreren Zielobjekten nicht gefunden worden, so ist - * pa->param[n]->flag == TARGET_NOTFOUND - * - */ -/* ------------------------------------------------------------- */ - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_SPELL +#define H_KRNL_SPELL +#ifdef __cplusplus +extern "C" { +#endif + + struct fighter; + struct spell; + struct border_type; + struct attrib_type; + struct curse_type; + struct castorder; + struct curse; + + /* Prototypen */ + + int use_item_power(struct region * r, struct unit * u); + int use_item_regeneration(struct region * r, struct unit * u); + void showspells(struct region *r, struct unit *u); + int sp_antimagiczone(struct castorder *co); + + /* ------------------------------------------------------------- */ + + extern struct attrib_type at_unitdissolve; + extern struct attrib_type at_wdwpyramid; + + extern struct spell_list * spells; + extern void register_spell(struct spell * sp); + extern struct spell * find_spell(magic_t mtype, const char * name); + extern struct spell * find_spellbyid(magic_t mtype, spellid_t i); + extern struct spell *get_spellfromtoken(struct unit *u, const char *s, const struct locale * lang); + +#ifdef __cplusplus +} +#endif +#endif + +/* ------------------------------------------------------------- */ +/* Erläuterungen zu den Spruchdefinitionen + * + * Spruchstukturdefinition: + * spell{ + * id, name, + * beschreibung, + * syntax, + * parameter, + * magietyp, + * sptyp, + * rank,level, + * costtyp, aura, + * komponenten[5][2][faktorart], + * &funktion, patzer} + * + * id: + * SPL_NOSPELL muss der letzte Spruch in der Liste spelldaten sein, + * denn nicht auf die Reihenfolge in der Liste sondern auf die id wird + * geprüft + * + * sptyp: + * besondere Spruchtypen und Flags + * (Regionszauber, Kampfzauber, Farcastbar, Stufe variable, ..) + * + * rank: + * gibt die Priorität und damit die Reihenfolge an, in der der Spruch + * gezaubert wird. + * 1: Aura übertragen + * 2: Antimagie + * 3: Magierverändernde Sprüche (Magic Boost, ..) + * 4: Monster erschaffen + * 5: Standartlevel + * 7: Teleport + * + * Komponenten[Anzahl mögl. Items][Art:Anzahl:Kostentyp] + * + * R_AURA: + * Grundkosten für einen Zauber. Soviel Mp müssen mindestens investiert + * werden, um den Spruch zu wirken. Zusätzliche Mp können unterschiedliche + * Auswirkungen haben, die in der Spruchfunktionsroutine definiert werden. + * + * R_PERMAURA: + * Kosten an permantenter Aura + * + * Komponenten Kostentyp: + * SPC_LEVEL == Spruch mit Levelabhängigen Magiekosten. Die angegeben + * Kosten müssen für Stufe 1 berechnet sein. + * SPC_FIX == Feste Kosten + * + * Wenn keine spezielle Syntax angegeben ist, wird die + * Syntaxbeschreibung aus sptyp generiert: + * FARCASTING: ZAUBER [REGION x y] + * SPELLLEVEL: ZAUBER [STUFE n] + * UNITSPELL : ZAUBER [ ..] + * SHIPSPELL : ZAUBER [ ..] + * BUILDINGSPELL: ZAUBER [ ..] + * PRECOMBATSPELL : KAMPFZAUBER [STUFE n] + * COMBATSPELL : KAMPFZAUBER [STUFE n] + * POSTCOMBATSPELL: KAMPFZAUBER [STUFE n] + * + * Das Parsing + * + * Der String spell->parameter gibt die Syntax an, nach der die + * Parameter des Spruches in add_spellparameter() geparst werden sollen. + * + * u : eine Einheitennummer + * r : hier kommen zwei Regionskoordinaten x y + * b : Gebäude- oder Burgnummer + * s : Schiffsnummer + * c : String, wird ohne Weiterverarbeitung übergeben + * i : Zahl (int), wird ohne Weiterverarbeitung übergeben + * k : Keywort - dieser String gibt den Paramter an, der folgt. Der + * Parameter wird mit findparam() identifiziert. + * k muss immer von einem c als Platzhalter für das Objekt gefolgt + * werden. + * Ein gutes Beispiel sind hierfür die Sprüche zur Magieanalyse. + * + : gibt an, das der vorherige Parameter mehrfach vorkommen kann. Da + * ein Ende nicht definiert werden kann, muss dies immer am Schluss + * kommen. + * + * Flags für das Parsing: + * TESTRESISTANCE : alle Zielobjekte, also alle Parameter vom Typ Unit, + * Burg, Schiff oder Region, werden auf ihre + * Magieresistenz überprüft + * TESTCANSEE : jedes Objekt vom Typ Einheit wird auf seine + * Sichtbarkeit überprüft + * SEARCHLOCAL : die Zielobjekte werden nur regional gesucht + * REGIONSPELL : Ziel ist die Region, auch wenn kein Zielobjekt + * angegeben wird. Ist TESTRESISTANCE gesetzt, so wird + * die Magieresistenz der Region überprüft + * + * Bei fehlendem Ziel oder wenn dieses dem Zauber widersteht, wird die + * Spruchfunktion nicht aufgerufen. + * Sind zu wenig Parameter vorhanden, wird der Zauber ebenfalls nicht + * ausgeführt. + * Ist eins von mehreren Zielobjekten resistent, so wird das Flag + * pa->param[n]->flag == TARGET_RESISTS + * Ist eins von mehreren Zielobjekten nicht gefunden worden, so ist + * pa->param[n]->flag == TARGET_NOTFOUND + * + */ +/* ------------------------------------------------------------- */ + diff --git a/src/kernel/spellid.h b/src/kernel/spellid.h index 351e0b24a..ffdc411f0 100644 --- a/src/kernel/spellid.h +++ b/src/kernel/spellid.h @@ -1,176 +1,176 @@ -/* vi: set ts=2: -* +-------------------+ Christian Schlittchen -* | | Enno Rehling -* | Eressea PBEM host | Katja Zedel -* | (c) 1998 - 2005 | -* | | This program may not be used, modified or distributed -* +-------------------+ without prior permission by the authors of Eressea. -* -*/ - -#ifndef H_KRNL_SPELLID -#define H_KRNL_SPELLID - -/* Sprüche. Neue NUR hinten anfügen, oder das Datenfile geht kaputt */ -enum { - SPL_NOSPELL = 0, - SPL_FIREBALL = 4, - SPL_HAGEL, - SPL_RUSTWEAPON, - SPL_COMBATRUST, - SPL_TREEGROW, - SPL_HEALING, - SPL_HEALINGSONG, - SPL_BADDREAMS, - SPL_GOODDREAMS, - SPL_DREAMREADING, - SPL_SWEETDREAMS, - SPL_TIREDSOLDIERS, - SPL_PLAGUE, - SPL_MAGICBOOST, - SPL_CHAOSROW, - SPL_SONG_OF_CONFUSION, - SPL_FLEE, - SPL_SONG_OF_FEAR, - SPL_BERSERK, - SPL_BLOODTHIRST, - SPL_MAELSTROM, - SPL_TRANSFERAURA_DRUIDE = 27, - SPL_TRANSFERAURA_BARDE, - SPL_TRANSFERAURA_CHAOS, - SPL_TRANSFERAURA_TRAUM, - SPL_TRANSFERAURA_ASTRAL, - SPL_STONEGOLEM, - SPL_IRONGOLEM, - SPL_SUMMONSHADOW, - SPL_SUMMONSHADOWLORDS, - SPL_REELING_ARROWS, - SPL_ANTIMAGICZONE = 37, - SPL_KAELTESCHUTZ = 39, - SPL_STEALAURA, - SPL_SUMMONUNDEAD, - SPL_AURALEAK, - SPL_GREAT_DROUGHT, - SPL_STRONG_WALL, - SPL_HOMESTONE, - SPL_DROUGHT, - SPL_FOREST_FIRE = 47, - SPL_SUMMONENT = 49, - SPL_DISTURBINGDREAMS, - SPL_DENYATTACK, - SPL_SLEEP, - SPL_EARTHQUAKE, - SPL_IRONKEEPER, - SPL_STORMWINDS, - SPL_GOODWINDS, - SPL_FLYING_SHIP, - SPL_SUMMON_ALP, - SPL_WINDSHIELD, - SPL_RAISEPEASANTS, - SPL_DEPRESSION, - SPL_HEADACHE = 62, - SPL_ENTERASTRAL = 64, - SPL_LEAVEASTRAL, - SPL_SHOWASTRAL, - SPL_VERSTEINERN, - SPL_TREEWALKENTER, - SPL_TREEWALKEXIT, - SPL_CHAOSSUCTION, - SPL_VIEWREALITY, - SPL_DISRUPTASTRAL, - SPL_SEDUCE, - SPL_PUMP, - SPL_CALM_MONSTER, - SPL_HERO, - SPL_FRIGHTEN, - SPL_MINDBLAST, - SPL_SPEED, - SPL_SPEED2, - SPL_FIREDRAGONODEM, - SPL_DRAGONODEM, - SPL_WYRMODEM, /* 83 */ - SPL_MAGICSTREET, - SPL_REANIMATE, - SPL_RECRUIT, - SPL_GENEROUS, - SPL_PERMTRANSFER, - SPL_SONG_OF_PEACE, - SPL_MIGRANT, - SPL_RALLYPEASANTMOB, - SPL_RAISEPEASANTMOB, - SPL_ILL_SHAPESHIFT, - SPL_WOLFHOWL, - SPL_FOG_OF_CONFUSION, - SPL_DREAM_OF_CONFUSION, - SPL_RESISTMAGICBONUS, - SPL_KEEPLOOT, - SPL_SCHILDRUNEN, - SPL_SONG_RESISTMAGIC, - SPL_SONG_SUSCEPTMAGIC, - SPL_ANALYSEMAGIC, - SPL_ANALYSEDREAM, - SPL_UNIT_ANALYSESONG, - SPL_OBJ_ANALYSESONG, - SPL_TYBIED_DESTROY_MAGIC, - SPL_DESTROY_MAGIC, - SPL_METEORRAIN, - SPL_REDUCESHIELD, - SPL_ARMORSHIELD, - SPL_DEATHCLOUD, - SPL_ORKDREAM, - SPL_SUMMONDRAGON = 113, - SPL_MOVECASTLE = 116, - SPL_BLESSSTONECIRCLE, - SPL_ILLAUN_FAMILIAR, - SPL_GWYRRD_FAMILIAR, - SPL_DRAIG_FAMILIAR, - SPL_CERDDOR_FAMILIAR, - SPL_TYBIED_FAMILIAR, - SPL_SONG_OF_ENSLAVE = 123, - SPL_FUMBLECURSE = 136, - SPL_ICASTLE, - SPL_GWYRRD_DESTROY_MAGIC, - SPL_DRAIG_DESTROY_MAGIC, - SPL_ILLAUN_DESTROY_MAGIC, - SPL_CERDDOR_DESTROY_MAGIC, - SPL_GWYRRD_ARMORSHIELD, - SPL_DRAIG_FUMBLESHIELD, - SPL_GWYRRD_FUMBLESHIELD, - SPL_CERRDOR_FUMBLESHIELD, - SPL_TYBIED_FUMBLESHIELD, - SPL_SHADOWKNIGHTS = 147, - SPL_ITEMCLOAK = 150, - SPL_FIREWALL, - SPL_WISPS, - SPL_SPARKLE_CHAOS, - SPL_SPARKLE_DREAM = 154, - SPL_PULLASTRAL = 156, - SPL_FETCHASTRAL = 157, - SPL_SHOCKWAVE = 163, - SPL_UNDEADHERO = 164, - SPL_BECOMEWYRM = 166, - SPL_ETERNIZEWALL, - SPL_PUTTOREST, - SPL_UNHOLYPOWER, - SPL_HOLYGROUND, - SPL_BLOODSACRIFICE, - SPL_MALLORN, - SPL_CLONECOPY, - SPL_DRAINODEM, - SPL_AURA_OF_FEAR, - SPL_SHADOWCALL, - SPL_MALLORNTREEGROW = 177, - SPL_BIGRECRUIT = 179, - SPL_IMMOLATION, - SPL_FIREODEM, /* 181 */ - SPL_ICEODEM, - SPL_ACIDODEM, - /* no longer used, but kept for reference: */ - XMLSPL_WDWPYRAMID_TRAUM = 184, - XMLSPL_WDWPYRAMID_ASTRAL = 185, - XMLSPL_WDWPYRAMID_DRUIDE = 186, - XMLSPL_WDWPYRAMID_BARDE = 187, - XMLSPL_WDWPYRAMID_CHAOS = 188, -}; - -#endif +/* vi: set ts=2: +* +-------------------+ Christian Schlittchen +* | | Enno Rehling +* | Eressea PBEM host | Katja Zedel +* | (c) 1998 - 2005 | +* | | This program may not be used, modified or distributed +* +-------------------+ without prior permission by the authors of Eressea. +* +*/ + +#ifndef H_KRNL_SPELLID +#define H_KRNL_SPELLID + +/* Sprüche. Neue NUR hinten anfügen, oder das Datenfile geht kaputt */ +enum { + SPL_NOSPELL = 0, + SPL_FIREBALL = 4, + SPL_HAGEL, + SPL_RUSTWEAPON, + SPL_COMBATRUST, + SPL_TREEGROW, + SPL_HEALING, + SPL_HEALINGSONG, + SPL_BADDREAMS, + SPL_GOODDREAMS, + SPL_DREAMREADING, + SPL_SWEETDREAMS, + SPL_TIREDSOLDIERS, + SPL_PLAGUE, + SPL_MAGICBOOST, + SPL_CHAOSROW, + SPL_SONG_OF_CONFUSION, + SPL_FLEE, + SPL_SONG_OF_FEAR, + SPL_BERSERK, + SPL_BLOODTHIRST, + SPL_MAELSTROM, + SPL_TRANSFERAURA_DRUIDE = 27, + SPL_TRANSFERAURA_BARDE, + SPL_TRANSFERAURA_CHAOS, + SPL_TRANSFERAURA_TRAUM, + SPL_TRANSFERAURA_ASTRAL, + SPL_STONEGOLEM, + SPL_IRONGOLEM, + SPL_SUMMONSHADOW, + SPL_SUMMONSHADOWLORDS, + SPL_REELING_ARROWS, + SPL_ANTIMAGICZONE = 37, + SPL_KAELTESCHUTZ = 39, + SPL_STEALAURA, + SPL_SUMMONUNDEAD, + SPL_AURALEAK, + SPL_GREAT_DROUGHT, + SPL_STRONG_WALL, + SPL_HOMESTONE, + SPL_DROUGHT, + SPL_FOREST_FIRE = 47, + SPL_SUMMONENT = 49, + SPL_DISTURBINGDREAMS, + SPL_DENYATTACK, + SPL_SLEEP, + SPL_EARTHQUAKE, + SPL_IRONKEEPER, + SPL_STORMWINDS, + SPL_GOODWINDS, + SPL_FLYING_SHIP, + SPL_SUMMON_ALP, + SPL_WINDSHIELD, + SPL_RAISEPEASANTS, + SPL_DEPRESSION, + SPL_HEADACHE = 62, + SPL_ENTERASTRAL = 64, + SPL_LEAVEASTRAL, + SPL_SHOWASTRAL, + SPL_VERSTEINERN, + SPL_TREEWALKENTER, + SPL_TREEWALKEXIT, + SPL_CHAOSSUCTION, + SPL_VIEWREALITY, + SPL_DISRUPTASTRAL, + SPL_SEDUCE, + SPL_PUMP, + SPL_CALM_MONSTER, + SPL_HERO, + SPL_FRIGHTEN, + SPL_MINDBLAST, + SPL_SPEED, + SPL_SPEED2, + SPL_FIREDRAGONODEM, + SPL_DRAGONODEM, + SPL_WYRMODEM, /* 83 */ + SPL_MAGICSTREET, + SPL_REANIMATE, + SPL_RECRUIT, + SPL_GENEROUS, + SPL_PERMTRANSFER, + SPL_SONG_OF_PEACE, + SPL_MIGRANT, + SPL_RALLYPEASANTMOB, + SPL_RAISEPEASANTMOB, + SPL_ILL_SHAPESHIFT, + SPL_WOLFHOWL, + SPL_FOG_OF_CONFUSION, + SPL_DREAM_OF_CONFUSION, + SPL_RESISTMAGICBONUS, + SPL_KEEPLOOT, + SPL_SCHILDRUNEN, + SPL_SONG_RESISTMAGIC, + SPL_SONG_SUSCEPTMAGIC, + SPL_ANALYSEMAGIC, + SPL_ANALYSEDREAM, + SPL_UNIT_ANALYSESONG, + SPL_OBJ_ANALYSESONG, + SPL_TYBIED_DESTROY_MAGIC, + SPL_DESTROY_MAGIC, + SPL_METEORRAIN, + SPL_REDUCESHIELD, + SPL_ARMORSHIELD, + SPL_DEATHCLOUD, + SPL_ORKDREAM, + SPL_SUMMONDRAGON = 113, + SPL_MOVECASTLE = 116, + SPL_BLESSSTONECIRCLE, + SPL_ILLAUN_FAMILIAR, + SPL_GWYRRD_FAMILIAR, + SPL_DRAIG_FAMILIAR, + SPL_CERDDOR_FAMILIAR, + SPL_TYBIED_FAMILIAR, + SPL_SONG_OF_ENSLAVE = 123, + SPL_FUMBLECURSE = 136, + SPL_ICASTLE, + SPL_GWYRRD_DESTROY_MAGIC, + SPL_DRAIG_DESTROY_MAGIC, + SPL_ILLAUN_DESTROY_MAGIC, + SPL_CERDDOR_DESTROY_MAGIC, + SPL_GWYRRD_ARMORSHIELD, + SPL_DRAIG_FUMBLESHIELD, + SPL_GWYRRD_FUMBLESHIELD, + SPL_CERRDOR_FUMBLESHIELD, + SPL_TYBIED_FUMBLESHIELD, + SPL_SHADOWKNIGHTS = 147, + SPL_ITEMCLOAK = 150, + SPL_FIREWALL, + SPL_WISPS, + SPL_SPARKLE_CHAOS, + SPL_SPARKLE_DREAM = 154, + SPL_PULLASTRAL = 156, + SPL_FETCHASTRAL = 157, + SPL_SHOCKWAVE = 163, + SPL_UNDEADHERO = 164, + SPL_BECOMEWYRM = 166, + SPL_ETERNIZEWALL, + SPL_PUTTOREST, + SPL_UNHOLYPOWER, + SPL_HOLYGROUND, + SPL_BLOODSACRIFICE, + SPL_MALLORN, + SPL_CLONECOPY, + SPL_DRAINODEM, + SPL_AURA_OF_FEAR, + SPL_SHADOWCALL, + SPL_MALLORNTREEGROW = 177, + SPL_BIGRECRUIT = 179, + SPL_IMMOLATION, + SPL_FIREODEM, /* 181 */ + SPL_ICEODEM, + SPL_ACIDODEM, + /* no longer used, but kept for reference: */ + XMLSPL_WDWPYRAMID_TRAUM = 184, + XMLSPL_WDWPYRAMID_ASTRAL = 185, + XMLSPL_WDWPYRAMID_DRUIDE = 186, + XMLSPL_WDWPYRAMID_BARDE = 187, + XMLSPL_WDWPYRAMID_CHAOS = 188, +}; + +#endif diff --git a/src/kernel/sqlite.c b/src/kernel/sqlite.c index 2a428a614..eba6f3b3e 100644 --- a/src/kernel/sqlite.c +++ b/src/kernel/sqlite.c @@ -1,257 +1,257 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -faction * get_faction_by_id(int uid) -{ - faction * f; - for (f=factions;f;f=f->next) { - if (f->subscription==uid) { - return f; - } - } - return NULL; -} - -#define SQL_EXPECT(res, val) if (res!=val) { return val; } -#define MAX_EMAIL_LENGTH 64 -#define MD5_LENGTH 32 -#define MD5_LENGTH_0 (MD5_LENGTH+1) /* MD5 + zero-terminator */ -#define MAX_FACTION_NAME 64 -#define MAX_FACTION_NAME_0 (MAX_FACTION_NAME+1) -typedef struct stmt_cache { - sqlite3 * db; - sqlite3_stmt * stmt; - const char * sql; - int inuse; -} stmt_cache; - -#define MAX_STMT_CACHE 64 -static stmt_cache cache[MAX_STMT_CACHE]; -static int cache_insert; - -static sqlite3_stmt * -stmt_cache_get(sqlite3 * db, const char * sql) -{ - int i, res; - - for (i=0;i!=MAX_STMT_CACHE && cache[i].db;++i) { - if (cache[i].sql==sql && cache[i].db==db) { - cache[i].inuse = 1; - res = sqlite3_reset(cache[i].stmt); - return cache[i].stmt; - } - } - if (i==MAX_STMT_CACHE) { - while (cache[cache_insert].inuse) { - cache[cache_insert].inuse = 0; - cache_insert = (cache_insert+1)&(MAX_STMT_CACHE-1); - } - i = cache_insert; - res = sqlite3_finalize(cache[i].stmt); - } - cache[i].inuse = 1; - cache[i].db = db; - cache[i].sql = sql; - res = sqlite3_prepare_v2(db, sql, -1, &cache[i].stmt, NULL); - return cache[i].stmt; -} - - -typedef struct db_faction { - sqlite3_uint64 id_faction; - sqlite3_uint64 id_email; - int no; - const char * email; - const char * passwd_md5; - const char * name; -} db_faction; - -static int -db_update_email(sqlite3 * db, const faction * f, const db_faction * dbstate, boolean force, /* [OUT] */ sqlite3_uint64 * id_email) -{ - boolean update = force; - int res = SQLITE_OK; - char email_lc[MAX_EMAIL_LENGTH]; - - if (update) { - unicode_utf8_tolower(email_lc, sizeof(email_lc), f->email); - } else { - if (strcmp(dbstate->email, f->email)!=0) { - unicode_utf8_tolower(email_lc, sizeof(email_lc), f->email); - if (strcmp(dbstate->email, email_lc)!=0) { - update = true; - } - } - } - - if (update) { - char email_md5[MD5_LENGTH_0]; - int i; - md5_state_t ms; - md5_byte_t digest[16]; - const char sql_insert_email[] = - "INSERT OR FAIL INTO email (email,md5) VALUES (?,?)"; - const char sql_select_email[] = - "SELECT id FROM email WHERE md5=?"; - sqlite3_stmt *stmt_insert_email = stmt_cache_get(db, sql_insert_email); - sqlite3_stmt *stmt_select_email = stmt_cache_get(db, sql_select_email); - - md5_init(&ms); - md5_append(&ms, (md5_byte_t*)email_lc, (int)strlen(email_lc)); - md5_finish(&ms, digest); - for (i=0;i!=16;++i) sprintf(email_md5+2*i, "%.02x", digest[i]); - - res = sqlite3_bind_text(stmt_insert_email, 1, email_lc, -1, SQLITE_TRANSIENT); - res = sqlite3_bind_text(stmt_insert_email, 2, email_md5, MD5_LENGTH, SQLITE_TRANSIENT); - res = sqlite3_step(stmt_insert_email); - - if (res==SQLITE_DONE) { - *id_email = sqlite3_last_insert_rowid(db); - } else { - res = sqlite3_bind_text(stmt_select_email, 1, email_md5, MD5_LENGTH, SQLITE_TRANSIENT); - res = sqlite3_step(stmt_select_email); - SQL_EXPECT(res, SQLITE_ROW); - *id_email = sqlite3_column_int64(stmt_select_email, 0); - } - } - - return SQLITE_OK; -} - -int -db_update_factions(sqlite3 * db, boolean force) -{ - int game_id = 6; - const char sql_select[] = - "SELECT faction.id, faction.email_id, faction.code, email.email, faction.password_md5, faction.name, faction.lastturn FROM email, faction" - " WHERE email.id=faction.email_id AND faction.game_id=? AND (lastturn IS NULL OR lastturn>?)"; - sqlite3_stmt *stmt_select = stmt_cache_get(db, sql_select); - faction * f; - int res; - - res = sqlite3_bind_int(stmt_select, 1, game_id); - SQL_EXPECT(res, SQLITE_OK); - res = sqlite3_bind_int(stmt_select, 2, turn-2); - SQL_EXPECT(res, SQLITE_OK); - for (;;) { - sqlite3_uint64 id_faction; - int lastturn; - - res = sqlite3_step(stmt_select); - if (res!=SQLITE_ROW) break; - - id_faction = sqlite3_column_int64(stmt_select, 0); - lastturn = sqlite3_column_int(stmt_select, 6); - f = get_faction_by_id((int)id_faction); - - if (f==NULL || !f->alive) { - if (lastturn==0) { - const char sql_update[] = "UPDATE faction SET lastturn=? WHERE id=?"; - sqlite3_stmt *stmt = stmt_cache_get(db, sql_update); - - lastturn = f?f->lastorders:turn-1; - sqlite3_bind_int(stmt, 1, lastturn); - sqlite3_bind_int64(stmt, 2, id_faction); - res = sqlite3_step(stmt); - SQL_EXPECT(res, SQLITE_DONE); - } - } else { - md5_state_t ms; - md5_byte_t digest[16]; - int i; - char passwd_md5[MD5_LENGTH_0]; - sqlite3_uint64 id_email; - boolean update = force; - db_faction dbstate; - const char * no_b36; - - fset(f, FFL_MARK); - dbstate.id_faction = id_faction; - dbstate.id_email = sqlite3_column_int64(stmt_select, 1); - no_b36 = (const char *)sqlite3_column_text(stmt_select, 2); - dbstate.no = no_b36?atoi36(no_b36):-1; - dbstate.email = (const char *)sqlite3_column_text(stmt_select, 3); - dbstate.passwd_md5 = (const char *)sqlite3_column_text(stmt_select, 4); - dbstate.name = (const char *)sqlite3_column_text(stmt_select, 5); - - id_email = dbstate.id_email; - res = db_update_email(db, f, &dbstate, force, &id_email); - SQL_EXPECT(res, SQLITE_OK); - - md5_init(&ms); - md5_append(&ms, (md5_byte_t*)f->passw, (int)strlen(f->passw)); - md5_finish(&ms, digest); - for (i=0;i!=16;++i) sprintf(passwd_md5+2*i, "%.02x", digest[i]); - - if (!update) { - update = ((id_email!=0 && dbstate.id_email!=id_email) || dbstate.no!=f->no - || dbstate.passwd_md5==NULL || strcmp(passwd_md5, dbstate.passwd_md5)!=0 - || dbstate.name==NULL || strncmp(f->name, dbstate.name, MAX_FACTION_NAME)!=0); - } - if (update) { - const char sql_update_faction[] = - "UPDATE faction SET email_id=?, password_md5=?, code=?, name=?, firstturn=? WHERE id=?"; - sqlite3_stmt *stmt_update_faction = stmt_cache_get(db, sql_update_faction); - - res = sqlite3_bind_int64(stmt_update_faction, 1, id_email); - SQL_EXPECT(res, SQLITE_OK); - res = sqlite3_bind_text(stmt_update_faction, 2, passwd_md5, MD5_LENGTH, SQLITE_TRANSIENT); - SQL_EXPECT(res, SQLITE_OK); - res = sqlite3_bind_text(stmt_update_faction, 3, no_b36, -1, SQLITE_TRANSIENT); - SQL_EXPECT(res, SQLITE_OK); - res = sqlite3_bind_text(stmt_update_faction, 4, f->name, -1, SQLITE_TRANSIENT); - SQL_EXPECT(res, SQLITE_OK); - res = sqlite3_bind_int(stmt_update_faction, 5, turn-f->age); - SQL_EXPECT(res, SQLITE_OK); - res = sqlite3_bind_int64(stmt_update_faction, 6, f->subscription); - SQL_EXPECT(res, SQLITE_OK); - res = sqlite3_step(stmt_update_faction); - SQL_EXPECT(res, SQLITE_DONE); - } - } - } - - for (f=factions;f;f=f->next) { - if (!fval(f, FFL_MARK)) { - log_error(("%s (sub=%d, email=%s) has no entry in the database\n", factionname(f), f->subscription, f->email)); - } else { - freset(f, FFL_MARK); - } - } - return SQLITE_OK; -} - -int -db_update_scores(sqlite3 * db, boolean force) -{ - const char * sql_ins = "INSERT OR FAIL INTO score (value,faction_id,turn) VALUES (?,?,?)"; - sqlite3_stmt * stmt_ins = stmt_cache_get(db, sql_ins); - const char * sql_upd = "UPDATE score set value=? WHERE faction_id=? AND turn=?"; - sqlite3_stmt * stmt_upd = stmt_cache_get(db, sql_upd); - faction * f; - sqlite3_exec(db, "BEGIN", 0, 0, 0); - for (f=factions;f;f=f->next) { - int res; - sqlite3_bind_int(stmt_ins, 1, f->score); - sqlite3_bind_int64(stmt_ins, 2, f->subscription); - sqlite3_bind_int(stmt_ins, 3, turn); - res = sqlite3_step(stmt_ins); - if (res==SQLITE_CONSTRAINT) { - sqlite3_bind_int(stmt_upd, 1, f->score); - sqlite3_bind_int64(stmt_upd, 2, f->subscription); - sqlite3_bind_int(stmt_upd, 3, turn); - res = sqlite3_step(stmt_upd); - sqlite3_reset(stmt_upd); - } - sqlite3_reset(stmt_ins); - } - sqlite3_exec(db, "COMMIT", 0, 0, 0); - return SQLITE_OK; -} +#include +#include +#include +#include +#include +#include +#include +#include +#include + +faction * get_faction_by_id(int uid) +{ + faction * f; + for (f=factions;f;f=f->next) { + if (f->subscription==uid) { + return f; + } + } + return NULL; +} + +#define SQL_EXPECT(res, val) if (res!=val) { return val; } +#define MAX_EMAIL_LENGTH 64 +#define MD5_LENGTH 32 +#define MD5_LENGTH_0 (MD5_LENGTH+1) /* MD5 + zero-terminator */ +#define MAX_FACTION_NAME 64 +#define MAX_FACTION_NAME_0 (MAX_FACTION_NAME+1) +typedef struct stmt_cache { + sqlite3 * db; + sqlite3_stmt * stmt; + const char * sql; + int inuse; +} stmt_cache; + +#define MAX_STMT_CACHE 64 +static stmt_cache cache[MAX_STMT_CACHE]; +static int cache_insert; + +static sqlite3_stmt * +stmt_cache_get(sqlite3 * db, const char * sql) +{ + int i, res; + + for (i=0;i!=MAX_STMT_CACHE && cache[i].db;++i) { + if (cache[i].sql==sql && cache[i].db==db) { + cache[i].inuse = 1; + res = sqlite3_reset(cache[i].stmt); + return cache[i].stmt; + } + } + if (i==MAX_STMT_CACHE) { + while (cache[cache_insert].inuse) { + cache[cache_insert].inuse = 0; + cache_insert = (cache_insert+1)&(MAX_STMT_CACHE-1); + } + i = cache_insert; + res = sqlite3_finalize(cache[i].stmt); + } + cache[i].inuse = 1; + cache[i].db = db; + cache[i].sql = sql; + res = sqlite3_prepare_v2(db, sql, -1, &cache[i].stmt, NULL); + return cache[i].stmt; +} + + +typedef struct db_faction { + sqlite3_uint64 id_faction; + sqlite3_uint64 id_email; + int no; + const char * email; + const char * passwd_md5; + const char * name; +} db_faction; + +static int +db_update_email(sqlite3 * db, const faction * f, const db_faction * dbstate, boolean force, /* [OUT] */ sqlite3_uint64 * id_email) +{ + boolean update = force; + int res = SQLITE_OK; + char email_lc[MAX_EMAIL_LENGTH]; + + if (update) { + unicode_utf8_tolower(email_lc, sizeof(email_lc), f->email); + } else { + if (strcmp(dbstate->email, f->email)!=0) { + unicode_utf8_tolower(email_lc, sizeof(email_lc), f->email); + if (strcmp(dbstate->email, email_lc)!=0) { + update = true; + } + } + } + + if (update) { + char email_md5[MD5_LENGTH_0]; + int i; + md5_state_t ms; + md5_byte_t digest[16]; + const char sql_insert_email[] = + "INSERT OR FAIL INTO email (email,md5) VALUES (?,?)"; + const char sql_select_email[] = + "SELECT id FROM email WHERE md5=?"; + sqlite3_stmt *stmt_insert_email = stmt_cache_get(db, sql_insert_email); + sqlite3_stmt *stmt_select_email = stmt_cache_get(db, sql_select_email); + + md5_init(&ms); + md5_append(&ms, (md5_byte_t*)email_lc, (int)strlen(email_lc)); + md5_finish(&ms, digest); + for (i=0;i!=16;++i) sprintf(email_md5+2*i, "%.02x", digest[i]); + + res = sqlite3_bind_text(stmt_insert_email, 1, email_lc, -1, SQLITE_TRANSIENT); + res = sqlite3_bind_text(stmt_insert_email, 2, email_md5, MD5_LENGTH, SQLITE_TRANSIENT); + res = sqlite3_step(stmt_insert_email); + + if (res==SQLITE_DONE) { + *id_email = sqlite3_last_insert_rowid(db); + } else { + res = sqlite3_bind_text(stmt_select_email, 1, email_md5, MD5_LENGTH, SQLITE_TRANSIENT); + res = sqlite3_step(stmt_select_email); + SQL_EXPECT(res, SQLITE_ROW); + *id_email = sqlite3_column_int64(stmt_select_email, 0); + } + } + + return SQLITE_OK; +} + +int +db_update_factions(sqlite3 * db, boolean force) +{ + int game_id = 6; + const char sql_select[] = + "SELECT faction.id, faction.email_id, faction.code, email.email, faction.password_md5, faction.name, faction.lastturn FROM email, faction" + " WHERE email.id=faction.email_id AND faction.game_id=? AND (lastturn IS NULL OR lastturn>?)"; + sqlite3_stmt *stmt_select = stmt_cache_get(db, sql_select); + faction * f; + int res; + + res = sqlite3_bind_int(stmt_select, 1, game_id); + SQL_EXPECT(res, SQLITE_OK); + res = sqlite3_bind_int(stmt_select, 2, turn-2); + SQL_EXPECT(res, SQLITE_OK); + for (;;) { + sqlite3_uint64 id_faction; + int lastturn; + + res = sqlite3_step(stmt_select); + if (res!=SQLITE_ROW) break; + + id_faction = sqlite3_column_int64(stmt_select, 0); + lastturn = sqlite3_column_int(stmt_select, 6); + f = get_faction_by_id((int)id_faction); + + if (f==NULL || !f->alive) { + if (lastturn==0) { + const char sql_update[] = "UPDATE faction SET lastturn=? WHERE id=?"; + sqlite3_stmt *stmt = stmt_cache_get(db, sql_update); + + lastturn = f?f->lastorders:turn-1; + sqlite3_bind_int(stmt, 1, lastturn); + sqlite3_bind_int64(stmt, 2, id_faction); + res = sqlite3_step(stmt); + SQL_EXPECT(res, SQLITE_DONE); + } + } else { + md5_state_t ms; + md5_byte_t digest[16]; + int i; + char passwd_md5[MD5_LENGTH_0]; + sqlite3_uint64 id_email; + boolean update = force; + db_faction dbstate; + const char * no_b36; + + fset(f, FFL_MARK); + dbstate.id_faction = id_faction; + dbstate.id_email = sqlite3_column_int64(stmt_select, 1); + no_b36 = (const char *)sqlite3_column_text(stmt_select, 2); + dbstate.no = no_b36?atoi36(no_b36):-1; + dbstate.email = (const char *)sqlite3_column_text(stmt_select, 3); + dbstate.passwd_md5 = (const char *)sqlite3_column_text(stmt_select, 4); + dbstate.name = (const char *)sqlite3_column_text(stmt_select, 5); + + id_email = dbstate.id_email; + res = db_update_email(db, f, &dbstate, force, &id_email); + SQL_EXPECT(res, SQLITE_OK); + + md5_init(&ms); + md5_append(&ms, (md5_byte_t*)f->passw, (int)strlen(f->passw)); + md5_finish(&ms, digest); + for (i=0;i!=16;++i) sprintf(passwd_md5+2*i, "%.02x", digest[i]); + + if (!update) { + update = ((id_email!=0 && dbstate.id_email!=id_email) || dbstate.no!=f->no + || dbstate.passwd_md5==NULL || strcmp(passwd_md5, dbstate.passwd_md5)!=0 + || dbstate.name==NULL || strncmp(f->name, dbstate.name, MAX_FACTION_NAME)!=0); + } + if (update) { + const char sql_update_faction[] = + "UPDATE faction SET email_id=?, password_md5=?, code=?, name=?, firstturn=? WHERE id=?"; + sqlite3_stmt *stmt_update_faction = stmt_cache_get(db, sql_update_faction); + + res = sqlite3_bind_int64(stmt_update_faction, 1, id_email); + SQL_EXPECT(res, SQLITE_OK); + res = sqlite3_bind_text(stmt_update_faction, 2, passwd_md5, MD5_LENGTH, SQLITE_TRANSIENT); + SQL_EXPECT(res, SQLITE_OK); + res = sqlite3_bind_text(stmt_update_faction, 3, no_b36, -1, SQLITE_TRANSIENT); + SQL_EXPECT(res, SQLITE_OK); + res = sqlite3_bind_text(stmt_update_faction, 4, f->name, -1, SQLITE_TRANSIENT); + SQL_EXPECT(res, SQLITE_OK); + res = sqlite3_bind_int(stmt_update_faction, 5, turn-f->age); + SQL_EXPECT(res, SQLITE_OK); + res = sqlite3_bind_int64(stmt_update_faction, 6, f->subscription); + SQL_EXPECT(res, SQLITE_OK); + res = sqlite3_step(stmt_update_faction); + SQL_EXPECT(res, SQLITE_DONE); + } + } + } + + for (f=factions;f;f=f->next) { + if (!fval(f, FFL_MARK)) { + log_error(("%s (sub=%d, email=%s) has no entry in the database\n", factionname(f), f->subscription, f->email)); + } else { + freset(f, FFL_MARK); + } + } + return SQLITE_OK; +} + +int +db_update_scores(sqlite3 * db, boolean force) +{ + const char * sql_ins = "INSERT OR FAIL INTO score (value,faction_id,turn) VALUES (?,?,?)"; + sqlite3_stmt * stmt_ins = stmt_cache_get(db, sql_ins); + const char * sql_upd = "UPDATE score set value=? WHERE faction_id=? AND turn=?"; + sqlite3_stmt * stmt_upd = stmt_cache_get(db, sql_upd); + faction * f; + sqlite3_exec(db, "BEGIN", 0, 0, 0); + for (f=factions;f;f=f->next) { + int res; + sqlite3_bind_int(stmt_ins, 1, f->score); + sqlite3_bind_int64(stmt_ins, 2, f->subscription); + sqlite3_bind_int(stmt_ins, 3, turn); + res = sqlite3_step(stmt_ins); + if (res==SQLITE_CONSTRAINT) { + sqlite3_bind_int(stmt_upd, 1, f->score); + sqlite3_bind_int64(stmt_upd, 2, f->subscription); + sqlite3_bind_int(stmt_upd, 3, turn); + res = sqlite3_step(stmt_upd); + sqlite3_reset(stmt_upd); + } + sqlite3_reset(stmt_ins); + } + sqlite3_exec(db, "COMMIT", 0, 0, 0); + return SQLITE_OK; +} diff --git a/src/kernel/teleport.c b/src/kernel/teleport.c index 7098f9353..40fc7b8ae 100644 --- a/src/kernel/teleport.c +++ b/src/kernel/teleport.c @@ -1,228 +1,228 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "teleport.h" - -/* kernel includes */ -#include "equipment.h" -#include "unit.h" -#include "region.h" -#include "race.h" -#include "skill.h" -#include "terrain.h" -#include "faction.h" -#include "plane.h" - -/* util includes */ -#include -#include - -/* libc includes */ -#include - -#define TE_CENTER_X 1000 -#define TE_CENTER_Y 1000 -#define TP_RADIUS 2 -#define TP_DISTANCE 4 - -static int -real2tp(int rk) { - /* in C: - * -4 / 5 = 0; - * +4 / 5 = 0; - * !!!!!!!!!!; - */ - return (rk + (TP_DISTANCE*5000)) / TP_DISTANCE - 5000; -} - -static region * -tpregion(const region *r) { - region * rt = findregion(TE_CENTER_X+real2tp(r->x), TE_CENTER_Y+real2tp(r->y)); - if (!is_astral(rt)) return NULL; - return rt; -} - -region_list * -astralregions(const region * r, boolean (*valid)(const region *)) -{ - region_list * rlist = NULL; - int x, y; - - assert(is_astral(r)); - if (!is_astral(r)) { - log_error(("astralregions was called with a non-astral region.\n")); - return NULL; - } - r = r_astral_to_standard(r); - if (r==NULL) return NULL; - - for (x=-TP_RADIUS;x<=+TP_RADIUS;++x) { - for (y=-TP_RADIUS;y<=+TP_RADIUS;++y) { - region * rn; - int dist = koor_distance(0, 0, x, y); - int nx = r->x+x, ny = r->y+y; - - if (dist > TP_RADIUS) continue; - pnormalize(&nx, &ny, rplane(r)); - rn = findregion(nx, ny); - if (rn!=NULL && (valid==NULL || valid(rn))) add_regionlist(&rlist, rn); - } - } - return rlist; -} - -region * -r_standard_to_astral(const region *r) -{ - if (rplane(r) != get_normalplane()) return NULL; - return tpregion(r); -} - -region * -r_astral_to_standard(const region *r) -{ - int x, y; - region *r2; - - assert(is_astral(r)); - x = (r->x-TE_CENTER_X)*TP_DISTANCE; - y = (r->y-TE_CENTER_Y)*TP_DISTANCE; - pnormalize(&x, &y, get_normalplane()); - r2 = findregion(x, y); - if (r2==NULL || rplane(r2)!=get_normalplane()) return NULL; - - return r2; -} - -region_list * -all_in_range(const region *r, int n, boolean (*valid)(const region *)) -{ - int x, y; - region_list *rlist = NULL; - plane * pl = rplane(r); - - if (r == NULL) return NULL; - - for (x = r->x-n; x <= r->x+n; x++) { - for (y = r->y-n; y <= r->y+n; y++) { - if (koor_distance(r->x, r->y, x, y) <= n) { - region * r2; - int nx = x, ny = y; - pnormalize(&nx, &ny, pl); - r2 = findregion(nx, ny); - if (r2!=NULL && (valid==NULL || valid(r2))) add_regionlist(&rlist, r2); - } - } - } - - return rlist; -} - -void -spawn_braineaters(float chance) -{ - region *r; - faction *f0 = get_monsters(); - int next = rng_int() % (int)(chance*100); - - if (f0==NULL) return; - - for (r = regions; r; r = r->next) { - if (!is_astral(r) || fval(r->terrain, FORBIDDEN_REGION)) continue; - - /* Neues Monster ? */ - if (next-- == 0) { - unit *u = createunit(r, f0, 1+rng_int()%10+rng_int()%10, new_race[RC_HIRNTOETER]); - equip_unit(u, get_equipment("monster_braineater")); - - next = rng_int() % (int)(chance*100); - } - } -} - -plane * -get_normalplane(void) -{ - return NULL; -} - -boolean -is_astral(const region * r) -{ - plane * pl = get_astralplane(); - return (pl && rplane(r) == pl); -} - -plane * -get_astralplane(void) -{ - static plane * astralspace; - static int rule_astralplane = -1; - static int gamecookie = -1; - if (rule_astralplane<0) { - rule_astralplane = get_param_int(global.parameters, "modules.astralspace", 1); - } - if (!rule_astralplane) { - return NULL; - } - if (gamecookie!=global.cookie) { - astralspace = getplanebyname("Astralraum"); - gamecookie = global.cookie; - } - - if (astralspace==NULL) { - astralspace = create_new_plane(1, "Astralraum", - TE_CENTER_X-500, TE_CENTER_X+500, - TE_CENTER_Y-500, TE_CENTER_Y+500, 0); - } - return astralspace; -} - -void -create_teleport_plane(void) -{ - region *r; - plane * hplane = get_homeplane(); - plane * aplane = get_astralplane(); - - const terrain_type * fog = get_terrain("fog"); - - for (r=regions;r;r=r->next) { - plane * pl = rplane(r); - if (pl == hplane) { - region *ra = tpregion(r); - - if (ra==NULL) { - int x = TE_CENTER_X+real2tp(r->x); - int y = TE_CENTER_Y+real2tp(r->y); - pnormalize(&x, &y, aplane); - - ra = new_region(x, y, aplane, 0); - terraform_region(ra, fog); - } - } - } -} - -boolean -inhabitable(const region * r) -{ - return fval(r->terrain, LAND_REGION); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "teleport.h" + +/* kernel includes */ +#include "equipment.h" +#include "unit.h" +#include "region.h" +#include "race.h" +#include "skill.h" +#include "terrain.h" +#include "faction.h" +#include "plane.h" + +/* util includes */ +#include +#include + +/* libc includes */ +#include + +#define TE_CENTER_X 1000 +#define TE_CENTER_Y 1000 +#define TP_RADIUS 2 +#define TP_DISTANCE 4 + +static int +real2tp(int rk) { + /* in C: + * -4 / 5 = 0; + * +4 / 5 = 0; + * !!!!!!!!!!; + */ + return (rk + (TP_DISTANCE*5000)) / TP_DISTANCE - 5000; +} + +static region * +tpregion(const region *r) { + region * rt = findregion(TE_CENTER_X+real2tp(r->x), TE_CENTER_Y+real2tp(r->y)); + if (!is_astral(rt)) return NULL; + return rt; +} + +region_list * +astralregions(const region * r, boolean (*valid)(const region *)) +{ + region_list * rlist = NULL; + int x, y; + + assert(is_astral(r)); + if (!is_astral(r)) { + log_error(("astralregions was called with a non-astral region.\n")); + return NULL; + } + r = r_astral_to_standard(r); + if (r==NULL) return NULL; + + for (x=-TP_RADIUS;x<=+TP_RADIUS;++x) { + for (y=-TP_RADIUS;y<=+TP_RADIUS;++y) { + region * rn; + int dist = koor_distance(0, 0, x, y); + int nx = r->x+x, ny = r->y+y; + + if (dist > TP_RADIUS) continue; + pnormalize(&nx, &ny, rplane(r)); + rn = findregion(nx, ny); + if (rn!=NULL && (valid==NULL || valid(rn))) add_regionlist(&rlist, rn); + } + } + return rlist; +} + +region * +r_standard_to_astral(const region *r) +{ + if (rplane(r) != get_normalplane()) return NULL; + return tpregion(r); +} + +region * +r_astral_to_standard(const region *r) +{ + int x, y; + region *r2; + + assert(is_astral(r)); + x = (r->x-TE_CENTER_X)*TP_DISTANCE; + y = (r->y-TE_CENTER_Y)*TP_DISTANCE; + pnormalize(&x, &y, get_normalplane()); + r2 = findregion(x, y); + if (r2==NULL || rplane(r2)!=get_normalplane()) return NULL; + + return r2; +} + +region_list * +all_in_range(const region *r, int n, boolean (*valid)(const region *)) +{ + int x, y; + region_list *rlist = NULL; + plane * pl = rplane(r); + + if (r == NULL) return NULL; + + for (x = r->x-n; x <= r->x+n; x++) { + for (y = r->y-n; y <= r->y+n; y++) { + if (koor_distance(r->x, r->y, x, y) <= n) { + region * r2; + int nx = x, ny = y; + pnormalize(&nx, &ny, pl); + r2 = findregion(nx, ny); + if (r2!=NULL && (valid==NULL || valid(r2))) add_regionlist(&rlist, r2); + } + } + } + + return rlist; +} + +void +spawn_braineaters(float chance) +{ + region *r; + faction *f0 = get_monsters(); + int next = rng_int() % (int)(chance*100); + + if (f0==NULL) return; + + for (r = regions; r; r = r->next) { + if (!is_astral(r) || fval(r->terrain, FORBIDDEN_REGION)) continue; + + /* Neues Monster ? */ + if (next-- == 0) { + unit *u = createunit(r, f0, 1+rng_int()%10+rng_int()%10, new_race[RC_HIRNTOETER]); + equip_unit(u, get_equipment("monster_braineater")); + + next = rng_int() % (int)(chance*100); + } + } +} + +plane * +get_normalplane(void) +{ + return NULL; +} + +boolean +is_astral(const region * r) +{ + plane * pl = get_astralplane(); + return (pl && rplane(r) == pl); +} + +plane * +get_astralplane(void) +{ + static plane * astralspace; + static int rule_astralplane = -1; + static int gamecookie = -1; + if (rule_astralplane<0) { + rule_astralplane = get_param_int(global.parameters, "modules.astralspace", 1); + } + if (!rule_astralplane) { + return NULL; + } + if (gamecookie!=global.cookie) { + astralspace = getplanebyname("Astralraum"); + gamecookie = global.cookie; + } + + if (astralspace==NULL) { + astralspace = create_new_plane(1, "Astralraum", + TE_CENTER_X-500, TE_CENTER_X+500, + TE_CENTER_Y-500, TE_CENTER_Y+500, 0); + } + return astralspace; +} + +void +create_teleport_plane(void) +{ + region *r; + plane * hplane = get_homeplane(); + plane * aplane = get_astralplane(); + + const terrain_type * fog = get_terrain("fog"); + + for (r=regions;r;r=r->next) { + plane * pl = rplane(r); + if (pl == hplane) { + region *ra = tpregion(r); + + if (ra==NULL) { + int x = TE_CENTER_X+real2tp(r->x); + int y = TE_CENTER_Y+real2tp(r->y); + pnormalize(&x, &y, aplane); + + ra = new_region(x, y, aplane, 0); + terraform_region(ra, fog); + } + } + } +} + +boolean +inhabitable(const region * r) +{ + return fval(r->terrain, LAND_REGION); +} diff --git a/src/kernel/teleport.h b/src/kernel/teleport.h index 552a69736..83f777899 100644 --- a/src/kernel/teleport.h +++ b/src/kernel/teleport.h @@ -1,41 +1,41 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef TELEPORT_H -#define TELEPORT_H -#ifdef __cplusplus -extern "C" { -#endif - - struct region *r_standard_to_astral(const struct region *r); - struct region *r_astral_to_standard(const struct region *); - extern struct region_list *astralregions(const struct region * rastral, boolean (*valid)(const struct region *)); - extern struct region_list *all_in_range(const struct region *r, int n, boolean (*valid)(const struct region *)); - extern boolean inhabitable(const struct region * r); - extern boolean is_astral(const struct region * r); - extern struct plane * get_astralplane(void); - extern struct plane * get_normalplane(void); - - void create_teleport_plane(void); - void set_teleport_plane_regiontypes(void); - void spawn_braineaters(float chance); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef TELEPORT_H +#define TELEPORT_H +#ifdef __cplusplus +extern "C" { +#endif + + struct region *r_standard_to_astral(const struct region *r); + struct region *r_astral_to_standard(const struct region *); + extern struct region_list *astralregions(const struct region * rastral, boolean (*valid)(const struct region *)); + extern struct region_list *all_in_range(const struct region *r, int n, boolean (*valid)(const struct region *)); + extern boolean inhabitable(const struct region * r); + extern boolean is_astral(const struct region * r); + extern struct plane * get_astralplane(void); + extern struct plane * get_normalplane(void); + + void create_teleport_plane(void); + void set_teleport_plane_regiontypes(void); + void spawn_braineaters(float chance); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/terrain.c b/src/kernel/terrain.c index 8605246fe..15ef6b58f 100644 --- a/src/kernel/terrain.c +++ b/src/kernel/terrain.c @@ -1,158 +1,158 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include -#include "terrain.h" -#include "terrainid.h" - -/* kernel includes */ -#include "curse.h" -#include "region.h" -#include "resources.h" - -#include -#include - -/* libc includes */ -#include -#include -#include - -#define MAXTERRAINS 20 - -const char * terraindata[MAXTERRAINS] = { - "ocean", - "plain", - "swamp", - "desert", - "highland", - "mountain", - "glacier", - "firewall", - NULL, /* dungeon module */ - NULL, /* former grassland */ - "fog", - "thickfog", - "volcano", - "activevolcano", - "iceberg_sleep", - "iceberg", - - NULL, /* museum module */ - NULL, /* museum module */ - NULL, /* former magicstorm */ - NULL /* museum module */ -}; - -static terrain_type * registered_terrains; - -const terrain_type * -terrains(void) -{ - return registered_terrains; -} - -static const char * -plain_name(const struct region * r) -{ - /* TODO: xml defined */ - if (r_isforest(r)) return "forest"; - return r->terrain->_name; -} - -void -register_terrain(struct terrain_type * terrain) -{ - assert(terrain->next==NULL), - terrain->next = registered_terrains; - registered_terrains = terrain; - if (strcmp("plain", terrain->_name)==0) - terrain->name = &plain_name; -} - -const struct terrain_type * -get_terrain(const char * name) -{ - const struct terrain_type * terrain; - for (terrain=registered_terrains;terrain;terrain=terrain->next) { - if (strcmp(terrain->_name, name)==0) break; - } - return terrain; -} - -static const terrain_type * newterrains[MAXTERRAINS]; - -const struct terrain_type * -newterrain(terrain_t t) -{ - if (t==NOTERRAIN) return NULL; - assert(t>=0); - assert(t_name)); - return NOTERRAIN; -} - -const char * -terrain_name(const struct region * r) -{ - if (r->attribs) { - attrib * a = a_find(r->attribs, &at_racename); - if (a) { - const char * str = get_racename(a); - if (str) return str; - } - } - - if (r->terrain->name!=NULL) { - return r->terrain->name(r); - } else if (fval(r->terrain, SEA_REGION)) { - if (curse_active(get_curse(r->attribs, ct_find("maelstrom")))) { - return "maelstrom"; - } - } - return r->terrain->_name; -} - -void -init_terrains(void) -{ - terrain_t t; - for (t=0;t!=MAXTERRAINS;++t) { - const terrain_type * newterrain = newterrains[t]; - if (newterrain!=NULL) continue; - if (terraindata[t]!=NULL) { - newterrain = get_terrain(terraindata[t]); - if (newterrain!=NULL) { - newterrains[t] = newterrain; - } - } - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include +#include "terrain.h" +#include "terrainid.h" + +/* kernel includes */ +#include "curse.h" +#include "region.h" +#include "resources.h" + +#include +#include + +/* libc includes */ +#include +#include +#include + +#define MAXTERRAINS 20 + +const char * terraindata[MAXTERRAINS] = { + "ocean", + "plain", + "swamp", + "desert", + "highland", + "mountain", + "glacier", + "firewall", + NULL, /* dungeon module */ + NULL, /* former grassland */ + "fog", + "thickfog", + "volcano", + "activevolcano", + "iceberg_sleep", + "iceberg", + + NULL, /* museum module */ + NULL, /* museum module */ + NULL, /* former magicstorm */ + NULL /* museum module */ +}; + +static terrain_type * registered_terrains; + +const terrain_type * +terrains(void) +{ + return registered_terrains; +} + +static const char * +plain_name(const struct region * r) +{ + /* TODO: xml defined */ + if (r_isforest(r)) return "forest"; + return r->terrain->_name; +} + +void +register_terrain(struct terrain_type * terrain) +{ + assert(terrain->next==NULL), + terrain->next = registered_terrains; + registered_terrains = terrain; + if (strcmp("plain", terrain->_name)==0) + terrain->name = &plain_name; +} + +const struct terrain_type * +get_terrain(const char * name) +{ + const struct terrain_type * terrain; + for (terrain=registered_terrains;terrain;terrain=terrain->next) { + if (strcmp(terrain->_name, name)==0) break; + } + return terrain; +} + +static const terrain_type * newterrains[MAXTERRAINS]; + +const struct terrain_type * +newterrain(terrain_t t) +{ + if (t==NOTERRAIN) return NULL; + assert(t>=0); + assert(t_name)); + return NOTERRAIN; +} + +const char * +terrain_name(const struct region * r) +{ + if (r->attribs) { + attrib * a = a_find(r->attribs, &at_racename); + if (a) { + const char * str = get_racename(a); + if (str) return str; + } + } + + if (r->terrain->name!=NULL) { + return r->terrain->name(r); + } else if (fval(r->terrain, SEA_REGION)) { + if (curse_active(get_curse(r->attribs, ct_find("maelstrom")))) { + return "maelstrom"; + } + } + return r->terrain->_name; +} + +void +init_terrains(void) +{ + terrain_t t; + for (t=0;t!=MAXTERRAINS;++t) { + const terrain_type * newterrain = newterrains[t]; + if (newterrain!=NULL) continue; + if (terraindata[t]!=NULL) { + newterrain = get_terrain(terraindata[t]); + if (newterrain!=NULL) { + newterrains[t] = newterrain; + } + } + } +} diff --git a/src/kernel/terrain.h b/src/kernel/terrain.h index 499a2acc8..644a0e329 100644 --- a/src/kernel/terrain.h +++ b/src/kernel/terrain.h @@ -1,83 +1,83 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef TERRAIN_H -#define TERRAIN_H -#ifdef __cplusplus -extern "C" { -#endif - -/* diverse Flags */ -/* Strassen können gebaut werden, wenn max_road > 0 */ -#define LAND_REGION (1<<0) /* Standard-Land-struct region */ -#define SEA_REGION (1<<1) /* hier braucht man ein Boot */ -#define FOREST_REGION (1<<2) /* Elfen- und Kampfvorteil durch Bäume */ -#define ARCTIC_REGION (1<<3) /* Gletscher & co = Keine Insekten! */ -#define CAVALRY_REGION (1<<4) /* Gletscher & co = Keine Insekten! */ -/* Achtung: SEA_REGION ist nicht das Gegenteil von LAND_REGION. Die zwei schliessen sich nichtmal aus! */ -#define FORBIDDEN_REGION (1<<5) /* unpassierbare Blockade-struct region */ -#define SAIL_INTO (1<<6) /* man darf hierhin segeln */ -#define FLY_INTO (1<<7) /* man darf hierhin fliegen */ -#define SWIM_INTO (1<<8) /* man darf hierhin schwimmen */ -#define WALK_INTO (1<<9) /* man darf hierhin laufen */ -#define LARGE_SHIPS (1<<10) /* grosse Schiffe dürfen hinfahren */ - -typedef struct production_rule { - char * name; - const struct resource_type * rtype; - - void (*terraform) (struct production_rule *, const struct region *); - void (*update) (struct production_rule *, const struct region *); - void (*use) (struct production_rule *, const struct region *, int amount); - int (*visible) (const struct production_rule *, int skilllevel); - - /* no initialization required */ - struct production_rule * next; -} production_rule; - -typedef struct terrain_production { - const struct resource_type * type; - const char *startlevel; - const char *base; - const char *divisor; - float chance; -} terrain_production; - -typedef struct terrain_type { - char * _name; - int size; /* how many peasants can work? */ - unsigned int flags; - short max_road; /* this many stones make a full road */ - short distribution; /* multiplier used for seeding */ - struct terrain_production * production; - const struct item_type ** herbs; /* zero-terminated array of herbs */ - const char * (*name)(const struct region * r); - const struct terrain_type * next; -} terrain_type; - -extern const terrain_type * terrains(void); -extern void register_terrain(struct terrain_type * terrain); -extern const struct terrain_type * get_terrain(const char * name); -extern const char * terrain_name(const struct region * r); - -extern void init_terrains(void); - -#ifdef __cplusplus -} -#endif -#endif /* TERRAIN_H */ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef TERRAIN_H +#define TERRAIN_H +#ifdef __cplusplus +extern "C" { +#endif + +/* diverse Flags */ +/* Strassen können gebaut werden, wenn max_road > 0 */ +#define LAND_REGION (1<<0) /* Standard-Land-struct region */ +#define SEA_REGION (1<<1) /* hier braucht man ein Boot */ +#define FOREST_REGION (1<<2) /* Elfen- und Kampfvorteil durch Bäume */ +#define ARCTIC_REGION (1<<3) /* Gletscher & co = Keine Insekten! */ +#define CAVALRY_REGION (1<<4) /* Gletscher & co = Keine Insekten! */ +/* Achtung: SEA_REGION ist nicht das Gegenteil von LAND_REGION. Die zwei schliessen sich nichtmal aus! */ +#define FORBIDDEN_REGION (1<<5) /* unpassierbare Blockade-struct region */ +#define SAIL_INTO (1<<6) /* man darf hierhin segeln */ +#define FLY_INTO (1<<7) /* man darf hierhin fliegen */ +#define SWIM_INTO (1<<8) /* man darf hierhin schwimmen */ +#define WALK_INTO (1<<9) /* man darf hierhin laufen */ +#define LARGE_SHIPS (1<<10) /* grosse Schiffe dürfen hinfahren */ + +typedef struct production_rule { + char * name; + const struct resource_type * rtype; + + void (*terraform) (struct production_rule *, const struct region *); + void (*update) (struct production_rule *, const struct region *); + void (*use) (struct production_rule *, const struct region *, int amount); + int (*visible) (const struct production_rule *, int skilllevel); + + /* no initialization required */ + struct production_rule * next; +} production_rule; + +typedef struct terrain_production { + const struct resource_type * type; + const char *startlevel; + const char *base; + const char *divisor; + float chance; +} terrain_production; + +typedef struct terrain_type { + char * _name; + int size; /* how many peasants can work? */ + unsigned int flags; + short max_road; /* this many stones make a full road */ + short distribution; /* multiplier used for seeding */ + struct terrain_production * production; + const struct item_type ** herbs; /* zero-terminated array of herbs */ + const char * (*name)(const struct region * r); + const struct terrain_type * next; +} terrain_type; + +extern const terrain_type * terrains(void); +extern void register_terrain(struct terrain_type * terrain); +extern const struct terrain_type * get_terrain(const char * name); +extern const char * terrain_name(const struct region * r); + +extern void init_terrains(void); + +#ifdef __cplusplus +} +#endif +#endif /* TERRAIN_H */ diff --git a/src/kernel/terrainid.h b/src/kernel/terrainid.h index ee0947ec5..fb2e40dd0 100644 --- a/src/kernel/terrainid.h +++ b/src/kernel/terrainid.h @@ -1,48 +1,48 @@ -/* vi: set ts=2: - * +-------------------+ Christian Schlittchen - * | | Enno Rehling - * | Eressea PBEM host | Katja Zedel - * | (c) 1998 - 2005 | - * | | This program may not be used, modified or distributed - * +-------------------+ without prior permission by the authors of Eressea. - */ - -#ifndef H_KRNL_TERRAINID_H -#define H_KRNL_TERRAINID_H - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - T_OCEAN = 0, - T_PLAIN = 1, - T_SWAMP = 2, - T_DESERT = 3, /* kann aus T_PLAIN entstehen */ - T_HIGHLAND = 4, - T_MOUNTAIN = 5, - T_GLACIER = 6, /* kann aus T_MOUNTAIN entstehen */ - T_FIREWALL = 7, /* Unpassierbar */ - /* T_HELL = 8, Hölle */ - /* T_GRASSLAND = 9, */ - T_ASTRAL = 10, - T_ASTRALB = 11, - T_VOLCANO = 12, - T_VOLCANO_SMOKING = 13, - T_ICEBERG_SLEEP = 14, - T_ICEBERG = 15, - /* T_HALL1 = 16, */ - /* T_CORRIDOR1 = 17, */ - /* T_MAGICSTORM = 18, */ - /* T_WALL1 = 19, */ - NOTERRAIN = (terrain_t) - 1 -}; - -extern const struct terrain_type * newterrain(terrain_t t); -extern terrain_t oldterrain(const struct terrain_type * terrain); - -#ifdef __cplusplus -} -#endif - -#endif +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2005 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + */ + +#ifndef H_KRNL_TERRAINID_H +#define H_KRNL_TERRAINID_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + T_OCEAN = 0, + T_PLAIN = 1, + T_SWAMP = 2, + T_DESERT = 3, /* kann aus T_PLAIN entstehen */ + T_HIGHLAND = 4, + T_MOUNTAIN = 5, + T_GLACIER = 6, /* kann aus T_MOUNTAIN entstehen */ + T_FIREWALL = 7, /* Unpassierbar */ + /* T_HELL = 8, Hölle */ + /* T_GRASSLAND = 9, */ + T_ASTRAL = 10, + T_ASTRALB = 11, + T_VOLCANO = 12, + T_VOLCANO_SMOKING = 13, + T_ICEBERG_SLEEP = 14, + T_ICEBERG = 15, + /* T_HALL1 = 16, */ + /* T_CORRIDOR1 = 17, */ + /* T_MAGICSTORM = 18, */ + /* T_WALL1 = 19, */ + NOTERRAIN = (terrain_t) - 1 +}; + +extern const struct terrain_type * newterrain(terrain_t t); +extern terrain_t oldterrain(const struct terrain_type * terrain); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/kernel/textstore.c b/src/kernel/textstore.c index d3ffca98e..391038f0f 100644 --- a/src/kernel/textstore.c +++ b/src/kernel/textstore.c @@ -1,208 +1,205 @@ -/* vi: set ts=2: -+-------------------+ Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -+-------------------+ -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ -#include -#include "config.h" -#include "textstore.h" - -#include "save.h" -#include "version.h" -#include -#include -#include - -#include -#include -#include -#ifdef HAVE_LIBXML -#include -#endif - -#define NULL_TOKEN '@' - -static int -txt_w_brk(struct storage * store) -{ - putc('\n', (FILE *)store->userdata); - return 1; -} - -static int -txt_w_id(struct storage * store, int arg) -{ - return fprintf((FILE *)store->userdata, "%s ", itoa36(arg)); -} - -static int -txt_r_id(struct storage * store) -{ - char id[8]; - fscanf((FILE *)store->userdata, "%7s", id); - return atoi36(id); -} - -static int -txt_w_int(struct storage * store, int arg) -{ - return fprintf((FILE *)store->userdata, "%d ", arg); -} - -static int -txt_r_int(struct storage * store) -{ - int result; - fscanf((FILE *)store->userdata, "%d", &result); - return result; -} - -static int -txt_w_flt(struct storage * store, float arg) -{ - return fprintf((FILE *)store->userdata, "%f ", arg); -} - -static float -txt_r_flt(struct storage * store) -{ - double result; - fscanf((FILE *)store->userdata, "%lf", &result); - return (float)result; -} - -static int -txt_w_tok(struct storage * store, const char * tok) -{ - int result; - if (tok==NULL || tok[0]==0) { - result = fputc(NULL_TOKEN, (FILE *)store->userdata); - } else { -#ifndef NDEBUG - const char * find = strchr(tok, ' '); - if (!find) find = strchr(tok, NULL_TOKEN); - assert(!find || !"reserved character in token"); -#endif - assert(tok[0]!=' '); - result = fputs(tok, (FILE *)store->userdata); - } - fputc(' ', (FILE *)store->userdata); - return result; -} -static char * -txt_r_tok(struct storage * store) -{ - char result[256]; - fscanf((FILE *)store->userdata, "%256s", result); - if (result[0]==NULL_TOKEN || result[0]==0) { - return NULL; - } - return strdup(result); -} -static void -txt_r_tok_buf(struct storage * store, char * result, size_t size) -{ - char format[16]; - if (result && size>0) { - format[0]='%'; - sprintf(format+1, "%us", size); - fscanf((FILE *)store->userdata, format, result); - if (result[0]==NULL_TOKEN) { - result[0] = 0; - } - } else { - /* trick to skip when no result expected */ - fscanf((FILE *)store->userdata, "%*s"); - } -} - -static int -txt_w_str(struct storage * store, const char * str) -{ - int result = fwritestr((FILE *)store->userdata, str); - fputc(' ', (FILE *)store->userdata); - return result+1; -} - -static char * -txt_r_str(struct storage * store) -{ - char buffer[DISPLAYSIZE]; - /* you should not use this */ - freadstr((FILE *)store->userdata, store->encoding, buffer, sizeof(buffer)); - return strdup(buffer); -} - -static void -txt_r_str_buf(struct storage * store, char * result, size_t size) -{ - freadstr((FILE *)store->userdata, store->encoding, result, size); -} - -static int -txt_open(struct storage * store, const char * filename, int mode) -{ - const char * modes[] = { 0, "rt", "wt", "at" }; - FILE * F = fopen(filename, modes[mode]); - store->userdata = F; - if (F) { - const char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; - if (mode==IO_READ) { - char token[8]; - /* recognize UTF8 BOM */ - store->r_tok_buf(store, token, sizeof(token)); - if (memcmp(token, utf8_bom, 3)==0) { - if (enc_gamedata!=ENCODING_UTF8) { - log_warning(("Found UTF-8 BOM, assuming unicode game data.\n")); - store->encoding = ENCODING_UTF8; - } - store->version = atoi(token+3); - } else { - if (store->encoding==ENCODING_NONE) { - store->encoding = ENCODING_8859_1; - log_warning(("No BOM, assuming 8859-1 game data.\n")); - } - store->version = atoi(token); - } - } else if (store->encoding==ENCODING_UTF8) { - fputs(utf8_bom, F); - fprintf(F, "%d\n", RELEASE_VERSION); - } - } - return (F==NULL); -} - -static int -txt_w_bin(struct storage * store, void * arg, size_t size) -{ - assert(!"not implemented!"); - return 0; -} - -static void -txt_r_bin(struct storage * store, void * result, size_t size) -{ - assert(!"not implemented!"); -} - -static int -txt_close(struct storage * store) -{ - return fclose((FILE *)store->userdata); -} - -const storage text_store = { - txt_w_brk, - txt_w_int, txt_r_int, - txt_w_flt, txt_r_flt, - txt_w_id, txt_r_id, - txt_w_tok, txt_r_tok, txt_r_tok_buf, - txt_w_str, txt_r_str, txt_r_str_buf, - txt_w_bin, txt_r_bin, - txt_open, txt_close, - 0, 0, NULL -}; - +/* vi: set ts=2: ++-------------------+ Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel ++-------------------+ +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ +#include +#include "config.h" +#include "textstore.h" + +#include "save.h" +#include "version.h" +#include +#include + +#include +#include +#include +#include + +#define NULL_TOKEN '@' + +static int +txt_w_brk(struct storage * store) +{ + putc('\n', (FILE *)store->userdata); + return 1; +} + +static int +txt_w_id(struct storage * store, int arg) +{ + return fprintf((FILE *)store->userdata, "%s ", itoa36(arg)); +} + +static int +txt_r_id(struct storage * store) +{ + char id[8]; + fscanf((FILE *)store->userdata, "%7s", id); + return atoi36(id); +} + +static int +txt_w_int(struct storage * store, int arg) +{ + return fprintf((FILE *)store->userdata, "%d ", arg); +} + +static int +txt_r_int(struct storage * store) +{ + int result; + fscanf((FILE *)store->userdata, "%d", &result); + return result; +} + +static int +txt_w_flt(struct storage * store, float arg) +{ + return fprintf((FILE *)store->userdata, "%f ", arg); +} + +static float +txt_r_flt(struct storage * store) +{ + double result; + fscanf((FILE *)store->userdata, "%lf", &result); + return (float)result; +} + +static int +txt_w_tok(struct storage * store, const char * tok) +{ + int result; + if (tok==NULL || tok[0]==0) { + result = fputc(NULL_TOKEN, (FILE *)store->userdata); + } else { +#ifndef NDEBUG + const char * find = strchr(tok, ' '); + if (!find) find = strchr(tok, NULL_TOKEN); + assert(!find || !"reserved character in token"); +#endif + assert(tok[0]!=' '); + result = fputs(tok, (FILE *)store->userdata); + } + fputc(' ', (FILE *)store->userdata); + return result; +} +static char * +txt_r_tok(struct storage * store) +{ + char result[256]; + fscanf((FILE *)store->userdata, "%256s", result); + if (result[0]==NULL_TOKEN || result[0]==0) { + return NULL; + } + return strdup(result); +} +static void +txt_r_tok_buf(struct storage * store, char * result, size_t size) +{ + char format[16]; + if (result && size>0) { + format[0]='%'; + sprintf(format+1, "%us", size); + fscanf((FILE *)store->userdata, format, result); + if (result[0]==NULL_TOKEN) { + result[0] = 0; + } + } else { + /* trick to skip when no result expected */ + fscanf((FILE *)store->userdata, "%*s"); + } +} + +static int +txt_w_str(struct storage * store, const char * str) +{ + int result = fwritestr((FILE *)store->userdata, str); + fputc(' ', (FILE *)store->userdata); + return result+1; +} + +static char * +txt_r_str(struct storage * store) +{ + char buffer[DISPLAYSIZE]; + /* you should not use this */ + freadstr((FILE *)store->userdata, store->encoding, buffer, sizeof(buffer)); + return strdup(buffer); +} + +static void +txt_r_str_buf(struct storage * store, char * result, size_t size) +{ + freadstr((FILE *)store->userdata, store->encoding, result, size); +} + +static int +txt_open(struct storage * store, const char * filename, int mode) +{ + const char * modes[] = { 0, "rt", "wt", "at" }; + FILE * F = fopen(filename, modes[mode]); + store->userdata = F; + if (F) { + const char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + if (mode==IO_READ) { + char token[8]; + /* recognize UTF8 BOM */ + store->r_tok_buf(store, token, sizeof(token)); + if (memcmp(token, utf8_bom, 3)==0) { + if (enc_gamedata!=XML_CHAR_ENCODING_UTF8) { + log_warning(("Found UTF-8 BOM, assuming unicode game data.\n")); + store->encoding = XML_CHAR_ENCODING_UTF8; + } + store->version = atoi(token+3); + } else { + if (store->encoding==XML_CHAR_ENCODING_NONE) { + store->encoding = XML_CHAR_ENCODING_8859_1; + log_warning(("No BOM, assuming 8859-1 game data.\n")); + } + store->version = atoi(token); + } + } else if (store->encoding==XML_CHAR_ENCODING_UTF8) { + fputs(utf8_bom, F); + fprintf(F, "%d\n", RELEASE_VERSION); + } + } + return (F==NULL); +} + +static int +txt_w_bin(struct storage * store, void * arg, size_t size) +{ + assert(!"not implemented!"); + return 0; +} + +static void +txt_r_bin(struct storage * store, void * result, size_t size) +{ + assert(!"not implemented!"); +} + +static int +txt_close(struct storage * store) +{ + return fclose((FILE *)store->userdata); +} + +const storage text_store = { + txt_w_brk, + txt_w_int, txt_r_int, + txt_w_flt, txt_r_flt, + txt_w_id, txt_r_id, + txt_w_tok, txt_r_tok, txt_r_tok_buf, + txt_w_str, txt_r_str, txt_r_str_buf, + txt_w_bin, txt_r_bin, + txt_open, txt_close, + 0, 0, NULL +}; + diff --git a/src/kernel/textstore.h b/src/kernel/textstore.h index d6f60f776..134a8da7e 100644 --- a/src/kernel/textstore.h +++ b/src/kernel/textstore.h @@ -1,23 +1,23 @@ -/* vi: set ts=2: -+-------------------+ Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -+-------------------+ -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifndef H_KERNEL_TEXTSTORE -#define H_KERNEL_TEXTSTORE -#ifdef __cplusplus -extern "C" { -#endif - -#include - -extern const storage text_store; - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: ++-------------------+ Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel ++-------------------+ +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifndef H_KERNEL_TEXTSTORE +#define H_KERNEL_TEXTSTORE +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern const storage text_store; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/types.h b/src/kernel/types.h index af54b1d92..9c16e63ac 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -1,407 +1,407 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef ERESSEA_TYPES_H -#define ERESSEA_TYPES_H - -/* - * Features enabled: - * If you are lacking the settings.h, create a new file common/settings.h, - * and write #include (or whatever settings you want - * your game to use) in there. - * !!! DO NOT COMMIT THE SETTINGS.H FILE TO CVS !!! - * settings.h should always be the first thing you include (after platform.h). - */ -#include -#include - -typedef short terrain_t; -typedef short direction_t; -typedef short race_t; -typedef short magic_t; -typedef short skill_t; -typedef short typ_t; -typedef short item_t; -typedef unsigned int spellid_t; - -struct attrib; -struct attrib_type; -struct building; -struct building_type; -struct curse; -struct equipment; -struct faction; -struct fighter; -struct item; -struct item_type; -struct locale; -struct luxury_type; -struct order; -struct plane; -struct potion_type; -struct race; -struct region; -struct region_list; -struct resource_type; -struct ship; -struct ship_type; -struct skill; -struct spell; -struct storage; -struct strlist; -struct terrain_type; -struct unit; -struct unit_list; -struct weapon_type; - -typedef struct ursprung { - struct ursprung *next; - int id; - int x, y; -} ursprung; - -/* ----------------- Befehle ----------------------------------- */ - -typedef unsigned char keyword_t; -enum { - K_KOMMENTAR, - K_BANNER, - K_WORK, - K_ATTACK, - K_STEAL, - K_BESIEGE, - K_NAME, - K_USE, - K_DISPLAY, - K_ENTER, - K_GUARD, - K_MAIL, - K_END, - K_DRIVE, - K_NUMBER, - K_WAR, - K_PEACE, - K_FOLLOW, - K_RESEARCH, - K_GIVE, - K_ALLY, - K_STATUS, - K_COMBATSPELL, - K_BUY, - K_CONTACT, - K_TEACH, - K_STUDY, - K_LIEFERE, - K_MAKE, - K_MOVE, - K_PASSWORD, - K_RECRUIT, - K_RESERVE, - K_ROUTE, - K_SABOTAGE, - K_SEND, - K_SPY, - K_QUIT, - K_SETSTEALTH, - K_TRANSPORT, - K_TAX, - K_ENTERTAIN, - K_SELL, - K_LEAVE, - K_FORGET, - K_CAST, - K_RESHOW, - K_DESTROY, - K_BREED, - K_DEFAULT, - K_URSPRUNG, - K_EMAIL, - K_PIRACY, - K_RESTART, - K_GROUP, - K_SACRIFICE, - K_PRAY, - K_SORT, - K_SETJIHAD, - K_GM, /* perform GM commands */ - K_INFO, /* set player-info */ - K_PREFIX, - K_PLANT, - K_WEREWOLF, - K_XE, - K_ALLIANCE, - K_CLAIM, - K_PROMOTION, - K_PAY, - MAXKEYWORDS, - NOKEYWORD = (keyword_t) - 1 -}; - -/* ------------------ Status von Einheiten --------------------- */ - -typedef unsigned char status_t; -enum { - ST_AGGRO, - ST_FIGHT, - ST_BEHIND, - ST_CHICKEN, - ST_AVOID, - ST_FLEE -}; - -/* ----------------- Parameter --------------------------------- */ - -typedef unsigned char param_t; -enum { - P_LOCALE, - P_ANY, - P_EACH, - P_PEASANT, - P_BUILDING, - P_UNIT, - P_PRIVAT, - P_BEHIND, - P_CONTROL, - P_HERBS, - P_NOT, - P_NEXT, - P_FACTION, - P_GAMENAME, - P_PERSON, - P_REGION, - P_SHIP, - P_MONEY, - P_ROAD, - P_TEMP, - P_FLEE, - P_GEBAEUDE, - P_GIVE, - P_FIGHT, - P_TRAVEL, - P_GUARD, - P_ZAUBER, - P_PAUSE, - P_VORNE, - P_AGGRO, - P_CHICKEN, - P_LEVEL, - P_HELP, - P_FOREIGN, - P_AURA, - P_FOR, - P_AID, - P_MERCY, - P_AFTER, - P_BEFORE, - P_NUMBER, - P_ITEMS, - P_POTIONS, - P_GROUP, - P_FACTIONSTEALTH, - P_TREES, - P_XEPOTION, - P_XEBALLOON, - P_XELAEN, - P_ALLIANCE, - MAXPARAMS, - NOPARAM = (param_t) - 1 -}; - -typedef enum { /* Fehler und Meldungen im Report */ - MSG_BATTLE, - MSG_EVENT, - MSG_MOVE, - MSG_INCOME, - MSG_COMMERCE, - MSG_PRODUCE, - MSG_ORCVERMEHRUNG, - MSG_MESSAGE, - MSG_COMMENT, - MSG_MAGIC, - MAX_MSG -} msg_t; - -enum { /* Message-Level */ - ML_IMPORTANT, /* Sachen, die IMO erscheinen _muessen_ */ - ML_DEBUG, - ML_MISTAKE, - ML_WARN, - ML_INFO, - ML_MAX -}; - -extern const char *parameters[MAXPARAMS]; - -/* --------------- Reports Typen ------------------------------- */ - -enum { - O_REPORT, /* 1 */ - O_COMPUTER, /* 2 */ - O_ZUGVORLAGE, /* 4 */ - O_UNUSED_3, - O_STATISTICS, /* 16 */ - O_DEBUG, /* 32 */ - O_COMPRESS, /* 64 */ - O_NEWS, /* 128 */ - O_UNUSED_8, - O_ADRESSEN, /* 512 */ - O_BZIP2, /* 1024 - compress as bzip2 */ - O_SCORE, /* 2048 - punkte anzeigen? */ - O_SHOWSKCHANGE, /* 4096 - Skillveränderungen anzeigen? */ - O_XML, /* 8192 - XML report versenden */ - MAXOPTIONS -}; - -/* ------------------ Talente ---------------------------------- */ - -enum { - SK_ALCHEMY, - SK_CROSSBOW, - SK_MINING, - SK_LONGBOW, - SK_BUILDING, - SK_TRADE, - SK_LUMBERJACK, - SK_CATAPULT, - SK_HERBALISM, - SK_MAGIC, - SK_HORSE_TRAINING, /* 10 */ - SK_RIDING, - SK_ARMORER, - SK_SHIPBUILDING, - SK_MELEE, - SK_SAILING, - SK_SPEAR, - SK_SPY, - SK_QUARRYING, - SK_ROAD_BUILDING, - SK_TACTICS, /* 20 */ - SK_STEALTH, - SK_ENTERTAINMENT, - SK_WEAPONSMITH, - SK_CARTMAKER, - SK_PERCEPTION, - SK_TAXING, - SK_STAMINA, - SK_WEAPONLESS, - MAXSKILLS, - NOSKILL = (skill_t) -1 -}; - -/* ------------- Typ von Einheiten ----------------------------- */ - -enum { - RC_DWARF, /* 0 - Zwerg */ - RC_ELF, - RC_GOBLIN = 3, - RC_HUMAN, - - RC_TROLL, - RC_DAEMON, - RC_INSECT, - RC_HALFLING, - RC_CAT, - - RC_AQUARIAN, - RC_ORC, - RC_SNOTLING, - RC_UNDEAD, - RC_ILLUSION, - - RC_FIREDRAGON, - RC_DRAGON, - RC_WYRM, - RC_TREEMAN, - RC_BIRTHDAYDRAGON, - - RC_DRACOID, - RC_SPECIAL, - RC_SPELL, - RC_IRONGOLEM, - RC_STONEGOLEM, - - RC_SHADOW, - RC_SHADOWLORD, - RC_IRONKEEPER, - RC_ALP, - RC_TOAD, - - RC_HIRNTOETER, - RC_PEASANT, - RC_WOLF = 32, - - RC_SONGDRAGON = 37, - - RC_SEASERPENT = 51, - RC_SHADOWKNIGHT, - RC_CENTAUR, - RC_SKELETON, - - RC_SKELETON_LORD, - RC_ZOMBIE, - RC_ZOMBIE_LORD, - RC_GHOUL, - RC_GHOUL_LORD, - - RC_MUS_SPIRIT, - RC_GNOME, - RC_TEMPLATE, - RC_CLONE, - - MAXRACES, - NORACE = (race_t) - 1 -}; - -/* Richtungen */ -enum { - D_NORTHWEST, - D_NORTHEAST, - D_EAST, - D_SOUTHEAST, - D_SOUTHWEST, - D_WEST, - MAXDIRECTIONS, - D_PAUSE, - D_SPECIAL, - NODIRECTION = (direction_t) - 1 -}; - -#define DONT_HELP 0 -#define HELP_MONEY 1 /* Mitversorgen von Einheiten */ -#define HELP_FIGHT 2 /* Bei Verteidigung mithelfen */ -#define HELP_OBSERVE 4 /* Bei Wahrnehmung mithelfen */ -#define HELP_GIVE 8 /* Dinge annehmen ohne KONTAKTIERE */ -#define HELP_GUARD 16 /* Laesst Steuern eintreiben etc. */ -#define HELP_FSTEALTH 32 /* Parteitarnung anzeigen. */ -#define HELP_TRAVEL 64 /* Laesst Regionen betreten. */ -#define HELP_ALL (127-HELP_TRAVEL-HELP_OBSERVE) /* Alle "positiven" HELPs zusammen */ -/* HELP_OBSERVE deaktiviert */ -/* ------------------------------------------------------------- */ -/* Prototypen */ - - -#define ALLIED_TAX 1 -#define ALLIED_NOBLOCK 2 -#define ALLIED_HELP 4 - -/* alle vierstelligen zahlen: */ -#define MAX_UNIT_NR (36*36*36*36-1) -#define MAX_CONTAINER_NR (36*36*36*36-1) - - -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef ERESSEA_TYPES_H +#define ERESSEA_TYPES_H + +/* + * Features enabled: + * If you are lacking the settings.h, create a new file common/settings.h, + * and write #include (or whatever settings you want + * your game to use) in there. + * !!! DO NOT COMMIT THE SETTINGS.H FILE TO CVS !!! + * settings.h should always be the first thing you include (after platform.h). + */ +#include +#include + +typedef short terrain_t; +typedef short direction_t; +typedef short race_t; +typedef short magic_t; +typedef short skill_t; +typedef short typ_t; +typedef short item_t; +typedef unsigned int spellid_t; + +struct attrib; +struct attrib_type; +struct building; +struct building_type; +struct curse; +struct equipment; +struct faction; +struct fighter; +struct item; +struct item_type; +struct locale; +struct luxury_type; +struct order; +struct plane; +struct potion_type; +struct race; +struct region; +struct region_list; +struct resource_type; +struct ship; +struct ship_type; +struct skill; +struct spell; +struct storage; +struct strlist; +struct terrain_type; +struct unit; +struct unit_list; +struct weapon_type; + +typedef struct ursprung { + struct ursprung *next; + int id; + int x, y; +} ursprung; + +/* ----------------- Befehle ----------------------------------- */ + +typedef unsigned char keyword_t; +enum { + K_KOMMENTAR, + K_BANNER, + K_WORK, + K_ATTACK, + K_STEAL, + K_BESIEGE, + K_NAME, + K_USE, + K_DISPLAY, + K_ENTER, + K_GUARD, + K_MAIL, + K_END, + K_DRIVE, + K_NUMBER, + K_WAR, + K_PEACE, + K_FOLLOW, + K_RESEARCH, + K_GIVE, + K_ALLY, + K_STATUS, + K_COMBATSPELL, + K_BUY, + K_CONTACT, + K_TEACH, + K_STUDY, + K_LIEFERE, + K_MAKE, + K_MOVE, + K_PASSWORD, + K_RECRUIT, + K_RESERVE, + K_ROUTE, + K_SABOTAGE, + K_SEND, + K_SPY, + K_QUIT, + K_SETSTEALTH, + K_TRANSPORT, + K_TAX, + K_ENTERTAIN, + K_SELL, + K_LEAVE, + K_FORGET, + K_CAST, + K_RESHOW, + K_DESTROY, + K_BREED, + K_DEFAULT, + K_URSPRUNG, + K_EMAIL, + K_PIRACY, + K_RESTART, + K_GROUP, + K_SACRIFICE, + K_PRAY, + K_SORT, + K_SETJIHAD, + K_GM, /* perform GM commands */ + K_INFO, /* set player-info */ + K_PREFIX, + K_PLANT, + K_WEREWOLF, + K_XE, + K_ALLIANCE, + K_CLAIM, + K_PROMOTION, + K_PAY, + MAXKEYWORDS, + NOKEYWORD = (keyword_t) - 1 +}; + +/* ------------------ Status von Einheiten --------------------- */ + +typedef unsigned char status_t; +enum { + ST_AGGRO, + ST_FIGHT, + ST_BEHIND, + ST_CHICKEN, + ST_AVOID, + ST_FLEE +}; + +/* ----------------- Parameter --------------------------------- */ + +typedef unsigned char param_t; +enum { + P_LOCALE, + P_ANY, + P_EACH, + P_PEASANT, + P_BUILDING, + P_UNIT, + P_PRIVAT, + P_BEHIND, + P_CONTROL, + P_HERBS, + P_NOT, + P_NEXT, + P_FACTION, + P_GAMENAME, + P_PERSON, + P_REGION, + P_SHIP, + P_MONEY, + P_ROAD, + P_TEMP, + P_FLEE, + P_GEBAEUDE, + P_GIVE, + P_FIGHT, + P_TRAVEL, + P_GUARD, + P_ZAUBER, + P_PAUSE, + P_VORNE, + P_AGGRO, + P_CHICKEN, + P_LEVEL, + P_HELP, + P_FOREIGN, + P_AURA, + P_FOR, + P_AID, + P_MERCY, + P_AFTER, + P_BEFORE, + P_NUMBER, + P_ITEMS, + P_POTIONS, + P_GROUP, + P_FACTIONSTEALTH, + P_TREES, + P_XEPOTION, + P_XEBALLOON, + P_XELAEN, + P_ALLIANCE, + MAXPARAMS, + NOPARAM = (param_t) - 1 +}; + +typedef enum { /* Fehler und Meldungen im Report */ + MSG_BATTLE, + MSG_EVENT, + MSG_MOVE, + MSG_INCOME, + MSG_COMMERCE, + MSG_PRODUCE, + MSG_ORCVERMEHRUNG, + MSG_MESSAGE, + MSG_COMMENT, + MSG_MAGIC, + MAX_MSG +} msg_t; + +enum { /* Message-Level */ + ML_IMPORTANT, /* Sachen, die IMO erscheinen _muessen_ */ + ML_DEBUG, + ML_MISTAKE, + ML_WARN, + ML_INFO, + ML_MAX +}; + +extern const char *parameters[MAXPARAMS]; + +/* --------------- Reports Typen ------------------------------- */ + +enum { + O_REPORT, /* 1 */ + O_COMPUTER, /* 2 */ + O_ZUGVORLAGE, /* 4 */ + O_UNUSED_3, + O_STATISTICS, /* 16 */ + O_DEBUG, /* 32 */ + O_COMPRESS, /* 64 */ + O_NEWS, /* 128 */ + O_UNUSED_8, + O_ADRESSEN, /* 512 */ + O_BZIP2, /* 1024 - compress as bzip2 */ + O_SCORE, /* 2048 - punkte anzeigen? */ + O_SHOWSKCHANGE, /* 4096 - Skillveränderungen anzeigen? */ + O_XML, /* 8192 - XML report versenden */ + MAXOPTIONS +}; + +/* ------------------ Talente ---------------------------------- */ + +enum { + SK_ALCHEMY, + SK_CROSSBOW, + SK_MINING, + SK_LONGBOW, + SK_BUILDING, + SK_TRADE, + SK_LUMBERJACK, + SK_CATAPULT, + SK_HERBALISM, + SK_MAGIC, + SK_HORSE_TRAINING, /* 10 */ + SK_RIDING, + SK_ARMORER, + SK_SHIPBUILDING, + SK_MELEE, + SK_SAILING, + SK_SPEAR, + SK_SPY, + SK_QUARRYING, + SK_ROAD_BUILDING, + SK_TACTICS, /* 20 */ + SK_STEALTH, + SK_ENTERTAINMENT, + SK_WEAPONSMITH, + SK_CARTMAKER, + SK_PERCEPTION, + SK_TAXING, + SK_STAMINA, + SK_WEAPONLESS, + MAXSKILLS, + NOSKILL = (skill_t) -1 +}; + +/* ------------- Typ von Einheiten ----------------------------- */ + +enum { + RC_DWARF, /* 0 - Zwerg */ + RC_ELF, + RC_GOBLIN = 3, + RC_HUMAN, + + RC_TROLL, + RC_DAEMON, + RC_INSECT, + RC_HALFLING, + RC_CAT, + + RC_AQUARIAN, + RC_ORC, + RC_SNOTLING, + RC_UNDEAD, + RC_ILLUSION, + + RC_FIREDRAGON, + RC_DRAGON, + RC_WYRM, + RC_TREEMAN, + RC_BIRTHDAYDRAGON, + + RC_DRACOID, + RC_SPECIAL, + RC_SPELL, + RC_IRONGOLEM, + RC_STONEGOLEM, + + RC_SHADOW, + RC_SHADOWLORD, + RC_IRONKEEPER, + RC_ALP, + RC_TOAD, + + RC_HIRNTOETER, + RC_PEASANT, + RC_WOLF = 32, + + RC_SONGDRAGON = 37, + + RC_SEASERPENT = 51, + RC_SHADOWKNIGHT, + RC_CENTAUR, + RC_SKELETON, + + RC_SKELETON_LORD, + RC_ZOMBIE, + RC_ZOMBIE_LORD, + RC_GHOUL, + RC_GHOUL_LORD, + + RC_MUS_SPIRIT, + RC_GNOME, + RC_TEMPLATE, + RC_CLONE, + + MAXRACES, + NORACE = (race_t) - 1 +}; + +/* Richtungen */ +enum { + D_NORTHWEST, + D_NORTHEAST, + D_EAST, + D_SOUTHEAST, + D_SOUTHWEST, + D_WEST, + MAXDIRECTIONS, + D_PAUSE, + D_SPECIAL, + NODIRECTION = (direction_t) - 1 +}; + +#define DONT_HELP 0 +#define HELP_MONEY 1 /* Mitversorgen von Einheiten */ +#define HELP_FIGHT 2 /* Bei Verteidigung mithelfen */ +#define HELP_OBSERVE 4 /* Bei Wahrnehmung mithelfen */ +#define HELP_GIVE 8 /* Dinge annehmen ohne KONTAKTIERE */ +#define HELP_GUARD 16 /* Laesst Steuern eintreiben etc. */ +#define HELP_FSTEALTH 32 /* Parteitarnung anzeigen. */ +#define HELP_TRAVEL 64 /* Laesst Regionen betreten. */ +#define HELP_ALL (127-HELP_TRAVEL-HELP_OBSERVE) /* Alle "positiven" HELPs zusammen */ +/* HELP_OBSERVE deaktiviert */ +/* ------------------------------------------------------------- */ +/* Prototypen */ + + +#define ALLIED_TAX 1 +#define ALLIED_NOBLOCK 2 +#define ALLIED_HELP 4 + +/* alle vierstelligen zahlen: */ +#define MAX_UNIT_NR (36*36*36*36-1) +#define MAX_CONTAINER_NR (36*36*36*36-1) + + +#endif diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 0dd720bd0..e8ab947f7 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1,1743 +1,1743 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "unit.h" - -#include "building.h" -#include "faction.h" -#include "group.h" -#include "connection.h" -#include "item.h" -#include "move.h" -#include "order.h" -#include "plane.h" -#include "race.h" -#include "region.h" -#include "save.h" -#include "ship.h" -#include "skill.h" -#include "terrain.h" - -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -#define FIND_FOREIGN_TEMP - -attrib_type at_creator = { - "creator" - /* Rest ist NULL; temporäres, nicht alterndes Attribut */ -}; - -#define UMAXHASH MAXUNITS -static unit * unithash[UMAXHASH]; -static unit * delmarker = (unit*)unithash; /* a funny hack */ - -#define HASH_STATISTICS 1 -#if HASH_STATISTICS -static int hash_requests; -static int hash_misses; -#endif - -void -uhash(unit * u) -{ - int key = HASH1(u->no, UMAXHASH), gk = HASH2(u->no, UMAXHASH); - while (unithash[key]!=NULL && unithash[key]!=delmarker && unithash[key]!=u) { - key = (key + gk) % UMAXHASH; - } - assert(unithash[key]!=u || !"trying to add the same unit twice"); - unithash[key] = u; -} - -void -uunhash(unit * u) -{ - int key = HASH1(u->no, UMAXHASH), gk = HASH2(u->no, UMAXHASH); - while (unithash[key]!=NULL && unithash[key]!=u) { - key = (key + gk) % UMAXHASH; - } - assert(unithash[key]==u || !"trying to remove a unit that is not hashed"); - unithash[key] = delmarker; -} - -unit * -ufindhash(int uid) -{ - assert(uid>=0); -#if HASH_STATISTICS - ++hash_requests; -#endif - if (uid>=0) { - int key = HASH1(uid, UMAXHASH), gk = HASH2(uid, UMAXHASH); - while (unithash[key]!=NULL && (unithash[key]==delmarker || unithash[key]->no!=uid)) { - key = (key + gk) % UMAXHASH; -#if HASH_STATISTICS - ++hash_misses; -#endif - } - return unithash[key]; - } - return NULL; -} - -#define DMAXHASH 7919 -typedef struct dead { - struct dead * nexthash; - faction * f; - int no; -} dead; - -static dead* deadhash[DMAXHASH]; - -static void -dhash(int no, faction * f) -{ - dead * hash = (dead*)calloc(1, sizeof(dead)); - dead * old = deadhash[no % DMAXHASH]; - hash->no = no; - hash->f = f; - deadhash[no % DMAXHASH] = hash; - hash->nexthash = old; -} - -faction * -dfindhash(int no) -{ - dead * old; - - if(no < 0) return 0; - - for (old = deadhash[no % DMAXHASH]; old; old = old->nexthash) { - if (old->no == no) { - return old->f; - } - } - return 0; -} - -typedef struct friend { - struct friend * next; - int number; - faction * faction; - unit * unit; -} friend; - -static friend * -get_friends(const unit * u, int * numfriends) -{ - friend * friends = 0; - faction * f = u->faction; - region * r = u->region; - int number = 0; - unit * u2; - - for (u2=r->units;u2;u2=u2->next) { - if (u2->faction!=f && u2->number>0) { - int allied = 0; - if (get_param_int(global.parameters, "rules.alliances", 0)!=0) { - allied = (f->alliance && f->alliance==u2->faction->alliance); - } - else if (alliedunit(u, u2->faction, HELP_MONEY) && alliedunit(u2, f, HELP_GIVE)) { - allied = 1; - } - if (allied) { - friend * nf, ** fr = &friends; - - /* some units won't take stuff: */ - if (u2->race->ec_flags & GETITEM) { - while (*fr && (*fr)->faction->nofaction->no) fr = &(*fr)->next; - nf = *fr; - if (nf==NULL || nf->faction!=u2->faction) { - nf = malloc(sizeof(friend)); - nf->next = *fr; - nf->faction = u2->faction; - nf->unit = u2; - nf->number = 0; - *fr = nf; - } else if (nf->faction==u2->faction && (u2->race->ec_flags & GIVEITEM)) { - /* we don't like to gift it to units that won't give it back */ - if ((nf->unit->race->ec_flags & GIVEITEM) == 0) { - nf->unit = u2; - } - } - nf->number += u2->number; - number += u2->number; - } - } - } - } - if (numfriends) *numfriends = number; - return friends; -} - -/** give all items to friends or peasants. - * this function returns 0 on success, or 1 if there are items that - * could not be destroyed. - */ -int -gift_items(unit * u, int flags) -{ - region * r = u->region; - item ** itm_p = &u->items; - int retval = 0; - int rule = rule_give(); - - if ((u->faction->flags&FFL_QUIT)==0 || (rule&GIVE_ONDEATH)==0) { - if ((rule&GIVE_ALLITEMS)==0 && (flags&GIFT_FRIENDS)) flags-=GIFT_FRIENDS; - if ((rule&GIVE_PEASANTS)==0 && (flags&GIFT_PEASANTS)) flags-=GIFT_PEASANTS; - if ((rule&GIVE_SELF)==0 && (flags&GIFT_SELF)) flags-=GIFT_SELF; - } - - if (u->items==NULL || fval(u->race, RCF_ILLUSIONARY)) return 0; - if ((u->race->ec_flags & GIVEITEM) == 0) return 0; - - /* at first, I should try giving my crap to my own units in this region */ - if (u->faction && (u->faction->flags&FFL_QUIT)==0 && (flags & GIFT_SELF)) { - unit * u2, * u3 = NULL; - for (u2 = r->units; u2; u2 = u2->next) { - if (u2 != u && u2->faction == u->faction && u2->number>0) { - /* some units won't take stuff: */ - if (u2->race->ec_flags & GETITEM) { - /* we don't like to gift it to units that won't give it back */ - if (u2->race->ec_flags & GIVEITEM) { - i_merge(&u2->items, &u->items); - u->items = NULL; - break; - } else { - u3 = u2; - } - } - } - } - if (u->items && u3) { - /* if nobody else takes it, we give it to a unit that has issues */ - i_merge(&u3->items, &u->items); - u->items = NULL; - } - if (u->items==NULL) return 0; - } - - /* if I have friends, I'll try to give my stuff to them */ - if (u->faction && (flags & GIFT_FRIENDS)) { - int number = 0; - friend * friends = get_friends(u, &number); - - while (friends) { - struct friend * nf = friends; - unit * u2 = nf->unit; - item * itm = u->items; - while (itm!=NULL) { - const item_type * itype = itm->type; - item * itn = itm->next; - int n = itm->number; - n = n * nf->number / number; - if (n>0) { - i_change(&u->items, itype, -n); - i_change(&u2->items, itype, n); - } - itm = itn; - } - number -= nf->number; - friends = nf->next; - free(nf); - } - if (u->items==NULL) return 0; - } - - /* last, but not least, give money and horses to peasants */ - while (*itm_p) { - item * itm = *itm_p; - - if (flags & GIFT_PEASANTS) { - if (!fval(u->region->terrain, SEA_REGION)) { - if (itm->type==olditemtype[I_HORSE]) { - rsethorses(r, rhorses(r) + itm->number); - itm->number = 0; - } else if (itm->type==i_silver) { - rsetmoney(r, rmoney(r) + itm->number); - itm->number = 0; - } - } - } - if (itm->number>0 && (itm->type->flags & ITF_NOTLOST)) { - itm_p = &itm->next; - retval = -1; - } else { - i_remove(itm_p, itm); - i_free(itm); - } - } - return retval; -} - -void -make_zombie(unit * u) -{ - u_setfaction(u, get_monsters()); - scale_number(u, 1); - u->race = new_race[RC_ZOMBIE]; - u->irace = NULL; -} - -/** remove the unit from the list of active units. - * the unit is not actually freed, because there may still be references - * dangling to it (from messages, for example). To free all removed units, - * call free_units(). - * returns 0 on success, or -1 if unit could not be removed. - */ - -static unit * deleted_units = NULL; - -int -remove_unit(unit ** ulist, unit * u) -{ - int result; - - assert(ufindhash(u->no)); - handle_event(u->attribs, "destroy", u); - - result = gift_items(u, GIFT_SELF|GIFT_FRIENDS|GIFT_PEASANTS); - if (result!=0) { - make_zombie(u); - return -1; - } - - if (u->number) set_number(u, 0); - leave(u, true); - u->region = NULL; - - uunhash(u); - if (ulist) { - while (*ulist!=u) { - ulist = &(*ulist)->next; - } - assert(*ulist==u); - *ulist = u->next; - } - - u->next = deleted_units; - deleted_units = u; - dhash(u->no, u->faction); - - u_setfaction(u, NULL); - u->region = NULL; - - return 0; -} - -unit * -findnewunit (const region * r, const faction *f, int n) -{ - unit *u2; - - if (n == 0) - return 0; - - for (u2 = r->units; u2; u2 = u2->next) - if (u2->faction == f && ualias(u2) == n) - return u2; -#ifdef FIND_FOREIGN_TEMP - for (u2 = r->units; u2; u2 = u2->next) - if (ualias(u2) == n) - return u2; -#endif - return 0; -} - -/* ------------------------------------------------------------- */ - - -/*********************/ -/* at_alias */ -/*********************/ -attrib_type at_alias = { - "alias", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - NO_WRITE, - NO_READ -}; - -int -ualias(const unit * u) -{ - attrib * a = a_find(u->attribs, &at_alias); - if (!a) return 0; - return a->data.i; -} - -int -a_readprivate(attrib * a, void * owner, struct storage * store) -{ - a->data.v = store->r_str(store); - if (a->data.v) return AT_READ_OK; - return AT_READ_FAIL; -} - -/*********************/ -/* at_private */ -/*********************/ -attrib_type at_private = { - "private", - DEFAULT_INIT, - a_finalizestring, - DEFAULT_AGE, - a_writestring, - a_readprivate -}; - -const char * -u_description(const unit * u, const struct locale * lang) -{ - if (u->display && u->display[0]) { - return u->display; - } else if (u->race->describe) { - return u->race->describe(u, lang); - } - return NULL; -} - -const char * -uprivate(const unit * u) -{ - attrib * a = a_find(u->attribs, &at_private); - if (!a) return NULL; - return a->data.v; -} - -void -usetprivate(unit * u, const char * str) -{ - attrib * a = a_find(u->attribs, &at_private); - - if (str == NULL) { - if (a) a_remove(&u->attribs, a); - return; - } - if (!a) a = a_add(&u->attribs, a_new(&at_private)); - if (a->data.v) free(a->data.v); - a->data.v = strdup((const char*)str); -} - -/*********************/ -/* at_potionuser */ -/*********************/ -/* Einheit BENUTZT einen Trank */ -attrib_type at_potionuser = { - "potionuser", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - NO_WRITE, - NO_READ -}; - -void -usetpotionuse(unit * u, const potion_type * ptype) -{ - attrib * a = a_find(u->attribs, &at_potionuser); - if (!a) a = a_add(&u->attribs, a_new(&at_potionuser)); - a->data.v = (void*)ptype; -} - -const potion_type * -ugetpotionuse(const unit * u) { - attrib * a = a_find(u->attribs, &at_potionuser); - if (!a) return NULL; - return (const potion_type *)a->data.v; -} - -/*********************/ -/* at_target */ -/*********************/ -attrib_type at_target = { - "target", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - NO_WRITE, - NO_READ -}; - -unit * -utarget(const unit * u) { - attrib * a; - if (!fval(u, UFL_TARGET)) return NULL; - a = a_find(u->attribs, &at_target); - assert (a || !"flag set, but no target found"); - return (unit*)a->data.v; -} - -void -usettarget(unit * u, const unit * t) -{ - attrib * a = a_find(u->attribs, &at_target); - if (!a && t) a = a_add(&u->attribs, a_new(&at_target)); - if (a) { - if (!t) { - a_remove(&u->attribs, a); - freset(u, UFL_TARGET); - } - else { - a->data.v = (void*)t; - fset(u, UFL_TARGET); - } - } -} - -/*********************/ -/* at_siege */ -/*********************/ - -void -a_writesiege(const attrib * a, const void * owner, struct storage * store) -{ - struct building * b = (struct building*)a->data.v; - write_building_reference(b, store); -} - -int -a_readsiege(attrib * a, void * owner, struct storage * store) -{ - int result = read_reference(&a->data.v, store, read_building_reference, resolve_building); - if (result==0 && !a->data.v) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -attrib_type at_siege = { - "siege", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - a_writesiege, - a_readsiege -}; - -struct building * - usiege(const unit * u) { - attrib * a; - if (!fval(u, UFL_SIEGE)) return NULL; - a = a_find(u->attribs, &at_siege); - assert (a || !"flag set, but no siege found"); - return (struct building *)a->data.v; -} - -void -usetsiege(unit * u, const struct building * t) -{ - attrib * a = a_find(u->attribs, &at_siege); - if (!a && t) a = a_add(&u->attribs, a_new(&at_siege)); - if (a) { - if (!t) { - a_remove(&u->attribs, a); - freset(u, UFL_SIEGE); - } - else { - a->data.v = (void*)t; - fset(u, UFL_SIEGE); - } - } -} - -/*********************/ -/* at_contact */ -/*********************/ -attrib_type at_contact = { - "contact", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - NO_WRITE, - NO_READ -}; - -void -usetcontact(unit * u, const unit * u2) -{ - attrib * a = a_find(u->attribs, &at_contact); - while (a && a->type==&at_contact && a->data.v!=u2) a = a->next; - if (a && a->type==&at_contact) return; - a_add(&u->attribs, a_new(&at_contact))->data.v = (void*)u2; -} - -boolean -ucontact(const unit * u, const unit * u2) -/* Prüft, ob u den Kontaktiere-Befehl zu u2 gesetzt hat. */ -{ - attrib *ru; - if (u->faction==u2->faction) return true; - - /* Explizites KONTAKTIERE */ - for (ru = a_find(u->attribs, &at_contact); ru && ru->type==&at_contact; ru = ru->next) { - if (((unit*)ru->data.v) == u2) { - return true; - } - } - - return false; -} - -/*** -** init & cleanup module -**/ - -void -free_units(void) -{ - while (deleted_units) { - unit * u = deleted_units; - deleted_units = deleted_units->next; - free_unit(u); - free(u); - } -} - - -void -write_unit_reference(const unit * u, struct storage * store) -{ - store->w_id(store, (u && u->region)?u->no:0); -} - -int -resolve_unit(variant id, void * address) -{ - unit * u = NULL; - if (id.i!=0) { - u = findunit(id.i); - if (u==NULL) { - *(unit**)address = NULL; - return -1; - } - } - *(unit**)address = u; - return 0; -} - -variant -read_unit_reference(struct storage * store) -{ - variant var; - var.i = store->r_id(store); - return var; -} - -attrib_type at_stealth = { - "stealth", NULL, NULL, NULL, a_writeint, a_readint -}; - -void -u_seteffstealth(unit * u, int value) -{ - if (skill_enabled[SK_STEALTH]) { - attrib * a = NULL; - if (fval(u, UFL_STEALTH)) { - a = a_find(u->attribs, &at_stealth); - } - if (value<0) { - if (a!=NULL) { - freset(u, UFL_STEALTH); - a_remove(&u->attribs, a); - } - return; - } - if (a==NULL) { - a = a_add(&u->attribs, a_new(&at_stealth)); - fset(u, UFL_STEALTH); - } - a->data.i = value; - } -} - -int -u_geteffstealth(const struct unit * u) -{ - if (skill_enabled[SK_STEALTH]) { - if (fval(u, UFL_STEALTH)) { - attrib * a = a_find(u->attribs, &at_stealth); - if (a!=NULL) return a->data.i; - } - } - return -1; -} - -int -get_level(const unit * u, skill_t id) -{ - if (skill_enabled[id]) { - skill * sv = u->skills; - while (sv != u->skills + u->skill_size) { - if (sv->id == id) { - return sv->level; - } - ++sv; - } - } - return 0; -} - -void -set_level(unit * u, skill_t sk, int value) -{ - skill * sv = u->skills; - - if (!skill_enabled[sk]) return; - - if (value==0) { - remove_skill(u, sk); - return; - } - while (sv != u->skills + u->skill_size) { - if (sv->id == sk) { - sk_set(sv, value); - return; - } - ++sv; - } - sk_set(add_skill(u, sk), value); -} - -static int -leftship_age(struct attrib * a) -{ - /* must be aged, so it doesn't affect report generation (cansee) */ - unused(a); - return AT_AGE_REMOVE; /* remove me */ -} - -static attrib_type at_leftship = { - "leftship", NULL, NULL, leftship_age -}; - -static attrib * -make_leftship(struct ship * leftship) -{ - attrib * a = a_new(&at_leftship); - a->data.v = leftship; - return a; -} - -void -set_leftship(unit *u, ship *sh) -{ - a_add(&u->attribs, make_leftship(sh)); -} - -ship * -leftship(const unit *u) -{ - attrib * a = a_find(u->attribs, &at_leftship); - - /* Achtung: Es ist nicht garantiert, daß der Rückgabewert zu jedem - * Zeitpunkt noch auf ein existierendes Schiff zeigt! */ - - if (a) return (ship *)(a->data.v); - - return NULL; -} - -void -leave_ship(unit * u) -{ - struct ship * sh = u->ship; - if (sh==NULL) return; - u->ship = NULL; - set_leftship(u, sh); - - if (fval(u, UFL_OWNER)) { - unit *u2, *owner = NULL; - freset(u, UFL_OWNER); - - for (u2 = u->region->units; u2; u2 = u2->next) { - if (u2->ship == sh) { - if (u2->faction == u->faction) { - owner = u2; - break; - } - else if (owner==NULL) owner = u2; - } - } - if (owner!=NULL) fset(owner, UFL_OWNER); - } -} - -void -leave_building(unit * u) -{ - struct building * b = u->building; - if (!b) return; - u->building = NULL; - - if (fval(u, UFL_OWNER)) { - unit *u2, *owner = NULL; - freset(u, UFL_OWNER); - - for (u2 = u->region->units; u2; u2 = u2->next) { - if (u2->building == b) { - if (u2->faction == u->faction) { - owner = u2; - break; - } - else if (owner==NULL) owner = u2; - } - } - if (owner!=NULL) { - fset(owner, UFL_OWNER); - } - } -} - -boolean -can_leave(unit * u) -{ - static int rule_leave = -1; - - if (!u->building) { - return true; - } - if (rule_leave<0) { - rule_leave = get_param_int(global.parameters, "rules.move.owner_leave", 0); - } - if (rule_leave && u->building && u==building_owner(u->building)) { - return false; - } - return true; -} - -boolean -leave(unit * u, boolean force) -{ - if (!force) { - if (!can_leave(u)) { - return false; - } - } - if (u->building) leave_building(u); - else if (u->ship) leave_ship(u); - return true; -} - -const struct race * -urace(const struct unit * u) -{ - return u->race; -} - -boolean -can_survive(const unit *u, const region *r) -{ - if ((fval(r->terrain, WALK_INTO) && (u->race->flags & RCF_WALK)) - || (fval(r->terrain, SWIM_INTO) && (u->race->flags & RCF_SWIM)) - || (fval(r->terrain, FLY_INTO) && (u->race->flags & RCF_FLY))) - { - static const curse_type * ctype = NULL; - - if (has_horses(u) && !fval(r->terrain, WALK_INTO)) - return false; - - if (!ctype) ctype = ct_find("holyground"); - if (fval(u->race, RCF_UNDEAD) && curse_active(get_curse(r->attribs, ctype))) - return false; - - return true; - } - return false; -} - -void -move_unit(unit * u, region * r, unit ** ulist) -{ - int maxhp = 0; - assert(u && r); - - assert(u->faction || !"this unit is dead"); - if (u->region == r) return; - if (u->region!=NULL) maxhp = unit_max_hp(u); - if (!ulist) ulist = (&r->units); - if (u->region) { - setguard(u, GUARD_NONE); - fset(u, UFL_MOVED); - if (u->ship || u->building) { - /* can_leave must be checked in travel_i */ -#ifndef NDEBUG - boolean result = leave(u, false); - assert(result); -#else - leave(u, false); -#endif - } - translist(&u->region->units, ulist, u); - } else { - addlist(ulist, u); - } - -#ifdef SMART_INTERVALS - update_interval(u->faction, r); -#endif - u->region = r; - /* keine automatische hp reduzierung bei bewegung */ - /* if (maxhp>0) u->hp = u->hp * unit_max_hp(u) / maxhp; */ -} - -/* ist mist, aber wegen nicht skalierender attribute notwendig: */ -#include "alchemy.h" - -void -transfermen(unit * u, unit * u2, int n) -{ - const attrib * a; - int hp = u->hp; - region * r = u->region; - - if (n==0) return; - assert(n > 0); - /* "hat attackiert"-status wird übergeben */ - - if (u2) { - skill *sv, *sn; - skill_t sk; - ship * sh; - - assert(u2->number+n>0); - - for (sk=0; sk!=MAXSKILLS; ++sk) { - int weeks, level = 0; - - sv = get_skill(u, sk); - sn = get_skill(u2, sk); - - if (sv==NULL && sn==NULL) continue; - if (sn==NULL && u2->number==0) { - /* new unit, easy to solve */ - level = sv->level; - weeks = sv->weeks; - } else { - double dlevel = 0.0; - - if (sv && sv->level) { - dlevel += (sv->level + 1 - sv->weeks/(sv->level+1.0)) * n; - level += sv->level * n; - } - if (sn && sn->level) { - dlevel += (sn->level + 1 - sn->weeks/(sn->level+1.0)) * u2->number; - level += sn->level * u2->number; - } - - dlevel = dlevel / (n + u2->number); - level = level / (n + u2->number); - if (level<=dlevel) { - /* apply the remaining fraction to the number of weeks to go. - * subtract the according number of weeks, getting closer to the - * next level */ - level = (int)dlevel; - weeks = (level+1) - (int)((dlevel - level) * (level+1)); - } else { - /* make it harder to reach the next level. - * weeks+level is the max difficulty, 1 - the fraction between - * level and dlevel applied to the number of weeks between this - * and the previous level is the added difficutly */ - level = (int)dlevel+1; - weeks = 1 + 2 * level - (int)((1 + dlevel - level) * level); - } - } - if (level) { - if (sn==NULL) sn = add_skill(u2, sk); - sn->level = (unsigned char)level; - sn->weeks = (unsigned char)weeks; - assert(sn->weeks>0 && sn->weeks<=sn->level*2+1); - assert(u2->number!=0 || (sn->level==sv->level && sn->weeks==sv->weeks)); - } else if (sn) { - remove_skill(u2, sk); - sn = NULL; - } - } - a = a_find(u->attribs, &at_effect); - while (a && a->type==&at_effect) { - effect_data * olde = (effect_data*)a->data.v; - if (olde->value) change_effect(u2, olde->type, olde->value); - a = a->next; - } - sh = leftship(u); - if (sh!=NULL) set_leftship(u2, sh); - u2->flags |= u->flags&(UFL_LONGACTION|UFL_NOTMOVING|UFL_HUNGER|UFL_MOVED|UFL_ENTER); - if (u->attribs) { - transfer_curse(u, u2, n); - } - } - scale_number(u, u->number - n); - if (u2) { - set_number(u2, u2->number + n); - hp -= u->hp; - u2->hp += hp; - /* TODO: Das ist schnarchlahm! und gehört nicht hierhin */ - a = a_find(u2->attribs, &at_effect); - while (a && a->type==&at_effect) { - attrib * an = a->next; - effect_data * olde = (effect_data*)a->data.v; - int e = get_effect(u, olde->type); - if (e!=0) change_effect(u2, olde->type, -e); - a = an; - } - } - else if (r->land) { - if ((u->race->ec_flags & ECF_REC_ETHEREAL)==0) { - const race * rc = u->race; - if (rc->ec_flags & ECF_REC_HORSES) { /* Zentauren an die Pferde */ - int h = rhorses(r) + n; - rsethorses(r, h); - } else { - int p = rpeasants(r); - p += (int)(n * rc->recruit_multi); - rsetpeasants(r, p); - } - } - } -} - -struct building * - inside_building(const struct unit * u) -{ - if (u->building==NULL) return NULL; - - if (!fval(u->building, BLD_WORKING)) { - /* Unterhalt nicht bezahlt */ - return NULL; - } else if (u->building->size < u->building->type->maxsize) { - /* Gebäude noch nicht fertig */ - return NULL; - } else { - int p = 0, cap = buildingcapacity(u->building); - const unit * u2; - for (u2 = u->region->units; u2; u2 = u2->next) { - if (u2->building == u->building) { - p += u2->number; - if (u2 == u) { - if (p <= cap) return u->building; - return NULL; - } - if (p > cap) return NULL; - } - } - } - return NULL; -} - -void -u_setfaction(unit * u, faction * f) -{ - int cnt = u->number; - - if (u->faction==f) return; - if (u->faction) { - set_number(u, 0); - if (count_unit(u)) --u->faction->no_units; - join_group(u, NULL); - free_orders(&u->orders); - set_order(&u->thisorder, NULL); - - if (u->nextF) u->nextF->prevF = u->prevF; - if (u->prevF) u->prevF->nextF = u->nextF; - else u->faction->units = u->nextF; - } - - if (f!=NULL) { - if (f->units) f->units->prevF=u; - u->prevF = NULL; - u->nextF = f->units; - f->units = u; - } - else u->nextF = NULL; - - u->faction = f; - if (u->region) update_interval(f, u->region); - if (cnt && f) { - set_number(u, cnt); - if (count_unit(u)) ++f->no_units; - } -} - -/* vorsicht Sprüche können u->number == RS_FARVISION haben! */ -void -set_number(unit * u, int count) -{ - assert (count >= 0); - assert (count <= UNIT_MAXSIZE); - -#ifndef NDEBUG - assert(u->faction || count==0); -#endif - - if (count == 0) { - u->flags &= ~(UFL_HERO); - } - if (u->faction) { - if (playerrace(u->race)) { - u->faction->num_people += count - u->number; - } - u->number = (unsigned short)count; - } else if (u->number>0) { - assert(!"why doesn't this unit have a faction? this will fuck up num_people"); - } -} - -boolean -learn_skill(unit * u, skill_t sk, double chance) -{ - skill * sv = u->skills; - if (chance < 1.0 && rng_int()%10000>=chance*10000) return false; - while (sv != u->skills + u->skill_size) { - assert (sv->weeks>0); - if (sv->id == sk) { - if (sv->weeks<=1) { - sk_set(sv, sv->level+1); - } else { - sv->weeks--; - } - return true; - } - ++sv; - } - sv = add_skill(u, sk); - sk_set(sv, 1); - return true; -} - -void -remove_skill(unit *u, skill_t sk) -{ - skill * sv = u->skills; - for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - if (sv->id==sk) { - skill * sl = u->skills + u->skill_size - 1; - if (sl!=sv) { - *sv = *sl; - } - --u->skill_size; - return; - } - } -} - -skill * -add_skill(unit * u, skill_t id) -{ - skill * sv = u->skills; -#ifndef NDEBUG - for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - assert(sv->id != id); - } -#endif - ++u->skill_size; - u->skills = realloc(u->skills, u->skill_size * sizeof(skill)); - sv = (u->skills + u->skill_size - 1); - sv->level = (unsigned char)0; - sv->weeks = (unsigned char)1; - sv->old = (unsigned char)0; - sv->id = (unsigned char)id; - return sv; -} - -skill * -get_skill(const unit * u, skill_t sk) -{ - skill * sv = u->skills; - while (sv!=u->skills+u->skill_size) { - if (sv->id==sk) return sv; - ++sv; - } - return NULL; -} - -boolean -has_skill(const unit * u, skill_t sk) -{ - skill * sv = u->skills; - while (sv!=u->skills+u->skill_size) { - if (sv->id==sk) { - return (sv->level>0); - } - ++sv; - } - return false; -} - -static int -item_modification(const unit *u, skill_t sk, int val) -{ - /* Presseausweis: *2 Spionage, 0 Tarnung */ - if(sk == SK_SPY && get_item(u, I_PRESSCARD) >= u->number) { - val = val * 2; - } else if(sk == SK_STEALTH) { -#if NEWATSROI == 1 - if (get_item(u, I_RING_OF_INVISIBILITY) - + 100 * get_item(u, I_SPHERE_OF_INVISIBILITY) >= u->number) { - val += ROIBONUS; - } -#endif - if(get_item(u, I_PRESSCARD) >= u->number) { - val = 0; - } - } -#if NEWATSROI == 1 - if(sk == SK_PERCEPTION) { - if(get_item(u, I_AMULET_OF_TRUE_SEEING) >= u->number) { - val += ATSBONUS; - } - } -#endif - return val; -} - -static int -att_modification(const unit *u, skill_t sk) -{ - double bonus = 0, malus = 0; - attrib * a; - double result = 0; - static boolean init = false; - static const curse_type * skillmod_ct, * gbdream_ct, * worse_ct; - curse * c; - - if (!init) { - init = true; - skillmod_ct = ct_find("skillmod"); - gbdream_ct = ct_find("gbdream"); - worse_ct = ct_find("worse"); - } - - c = get_curse(u->attribs, worse_ct); - if (c!=NULL) result += curse_geteffect(c); - if (skillmod_ct) { - attrib * a = a_find(u->attribs, &at_curse); - while (a && a->type==&at_curse) { - curse * c = (curse *)a->data.v; - if (c->type==skillmod_ct && c->data.i==sk) { - result += curse_geteffect(c); - break; - } - a = a->next; - } - } - - /* TODO hier kann nicht mit get/iscursed gearbeitet werden, da nur der - * jeweils erste vom Typ C_GBDREAM zurückgegen wird, wir aber alle - * durchsuchen und aufaddieren müssen */ - a = a_find(u->region->attribs, &at_curse); - while (a && a->type==&at_curse) { - curse * c = (curse*)a->data.v; - if (curse_active(c) && c->type==gbdream_ct) { - double mod = curse_geteffect(c); - unit * mage = c->magician; - /* wir suchen jeweils den größten Bonus und den größten Malus */ - if (mod>bonus) { - if (mage==NULL || mage->number==0 || alliedunit(mage, u->faction, HELP_GUARD)) { - bonus = mod; - } - } else if (mod < malus) { - if (mage == NULL || !alliedunit(mage, u->faction, HELP_GUARD)) { - malus = mod; - } - } - } - a = a->next; - } - result = result + bonus + malus; - - return (int)result; -} - -int -get_modifier(const unit *u, skill_t sk, int level, const region *r, boolean noitem) -{ - int bskill = level; - int skill = bskill; - - assert(r); - if (sk == SK_STEALTH) { - plane * pl = rplane(r); - if (pl &&fval(pl, PFL_NOSTEALTH)) return 0; - } - - skill += rc_skillmod(u->race, r, sk); - skill += att_modification(u, sk); - - if (noitem == false) { - skill = item_modification(u, sk, skill); - } - skill = skillmod(u->attribs, u, r, sk, skill, SMF_ALWAYS); - -#ifdef HUNGER_REDUCES_SKILL - if (fval(u, UFL_HUNGER)) { - skill = skill/2; - } -#endif - return skill - bskill; -} - -int -eff_skill(const unit * u, skill_t sk, const region * r) -{ - if (skill_enabled[sk]) { - int level = get_level(u, sk); - if (level>0) { - int mlevel = level + get_modifier(u, sk, level, r, false); - - if (mlevel>0) { - int skillcap = SkillCap(sk); - if (skillcap && mlevel>skillcap) { - return skillcap; - } - return mlevel; - } - } - } - return 0; -} - -int -eff_skill_study(const unit * u, skill_t sk, const region * r) -{ - int level = get_level(u, sk); - if (level>0) { - int mlevel = level + get_modifier(u, sk, level, r, true); - - if (mlevel>0) return mlevel; - } - return 0; -} - -int -invisible(const unit *target, const unit * viewer) -{ -#if NEWATSROI == 1 - return 0; -#else - if (viewer && viewer->faction==target->faction) return 0; - else { - int hidden = get_item(target, I_RING_OF_INVISIBILITY) + 100 * get_item(target, I_SPHERE_OF_INVISIBILITY); - if (hidden) { - hidden = MIN(hidden, target->number); - if (viewer) hidden -= get_item(viewer, I_AMULET_OF_TRUE_SEEING); - } - return hidden; - } -#endif -} - -/** remove the unit from memory. - * this frees all memory that's only accessible through the unit, - * and you should already have called uunhash and removed the unit from the - * region. - */ -void -free_unit(unit * u) -{ - free(u->name); - free(u->display); - free_order(u->thisorder); - free_orders(&u->orders); - if (u->skills) free(u->skills); - while (u->items) { - item * it = u->items->next; - u->items->next = NULL; - i_free(u->items); - u->items = it; - } - while (u->attribs) a_remove (&u->attribs, u->attribs); - while (u->reservations) { - struct reservation *res = u->reservations; - u->reservations = res->next; - free(res); - } -} - - -void -unitlist_clear(struct unit_list **ul) -{ - while (*ul) { - unit_list * rl2 = (*ul)->next; - free(*ul); - *ul = rl2; - } -} - -void -unitlist_insert(struct unit_list **ul, struct unit *u) -{ - unit_list *rl2 = (unit_list*)malloc(sizeof(unit_list)); - - rl2->data = u; - rl2->next = *ul; - - *ul = rl2; -} - - -static void -createunitid(unit *u, int id) -{ - if (id<=0 || id > MAX_UNIT_NR || ufindhash(id) || dfindhash(id) || forbiddenid(id)) - u->no = newunitid(); - else - u->no = id; - uhash(u); -} - -void -name_unit(unit *u) -{ - if (u->race->generate_name) { - const char * gen_name = u->race->generate_name(u); - if (gen_name) { - unit_setname(u, gen_name); - } else { - unit_setname(u, racename(u->faction->locale, u, u->race)); - } - } else { - char name[32]; - snprintf(name, sizeof(name), "%s %s", LOC(u->faction->locale, "unitdefault"), itoa36(u->no)); - unit_setname(u, name); - } -} - -/** creates a new unit. -* -* @param dname: name, set to NULL to get a default. -* @param creator: unit to inherit stealth, group, building, ship, etc. from -*/ -unit * -create_unit(region * r, faction * f, int number, const struct race *urace, int id, const char * dname, unit *creator) -{ - unit * u = calloc(1, sizeof(unit)); - - assert(urace); - assert(f->alive); - u_setfaction(u, f); - - if (f->locale) { - order * deford = default_order(f->locale); - if (deford) { - set_order(&u->thisorder, NULL); - addlist(&u->orders, deford); - } - } - u_seteffstealth(u, -1); - u->race = urace; - u->irace = NULL; - - set_number(u, number); - - /* die nummer der neuen einheit muss vor name_unit generiert werden, - * da der default name immer noch 'Nummer u->no' ist */ - createunitid(u, id); - - /* zuerst in die Region setzen, da zb Drachennamen den Regionsnamen - * enthalten */ - if (r) move_unit(u, r, NULL); - - /* u->race muss bereits gesetzt sein, wird für default-hp gebraucht */ - /* u->region auch */ - u->hp = unit_max_hp(u) * number; - - if (!dname) { - name_unit(u); - } else { - u->name = strdup(dname); - } - if (count_unit(u)) f->no_units++; - - if (creator) { - attrib * a; - - /* erbt Kampfstatus */ - setstatus(u, creator->status); - - /* erbt Gebäude/Schiff*/ - if (creator->region==r) { - u->building = creator->building; - if (creator->ship!=NULL && fval(u->race, RCF_CANSAIL)) { - u->ship = creator->ship; - } - } - - /* Tarnlimit wird vererbt */ - if (fval(creator, UFL_STEALTH)) { - attrib * a = a_find(creator->attribs, &at_stealth); - if (a) { - int stealth = a->data.i; - a = a_add(&u->attribs, a_new(&at_stealth)); - a->data.i = stealth; - } - } - - /* Temps von parteigetarnten Einheiten sind wieder parteigetarnt */ - if (fval(creator, UFL_ANON_FACTION)) { - fset(u, UFL_ANON_FACTION); - } - /* Daemonentarnung */ - set_racename(&u->attribs, get_racename(creator->attribs)); - if (fval(u->race, RCF_SHAPESHIFT) && fval(creator->race, RCF_SHAPESHIFT)) { - u->irace = creator->irace; - } - - /* Gruppen */ - if (creator->faction==f && fval(creator, UFL_GROUP)) { - a = a_find(creator->attribs, &at_group); - if (a) { - group * g = (group*)a->data.v; - set_group(u, g); - } - } - a = a_find(creator->attribs, &at_otherfaction); - if (a) { - a_add(&u->attribs, make_otherfaction(get_otherfaction(a))); - } - - a = a_add(&u->attribs, a_new(&at_creator)); - a->data.v = creator; - } - - return u; -} - -int -maxheroes(const struct faction * f) -{ - int nsize = count_all(f); - if (nsize==0) return 0; - else { - int nmax = (int)(log10(nsize / 50.0) * 20); - return (nmax<0)?0:nmax; - } -} - -int -countheroes(const struct faction * f) -{ - const unit * u = f->units; - int n = 0; - - while (u) { - if (fval(u, UFL_HERO)) n+= u->number; - u = u->nextF; - } -#ifdef DEBUG_MAXHEROES - int m = maxheroes(f); - if (n>m) { - log_warning(("%s has %d of %d heroes\n", factionname(f), n, m)); - } -#endif - return n; -} - -const char * -unit_getname(const unit * u) -{ - return (const char *)u->name; -} - -void -unit_setname(unit * u, const char * name) -{ - free(u->name); - if (name) u->name = strdup(name); - else u->name = NULL; -} - -const char * -unit_getinfo(const unit * u) -{ - return (const char *)u->display; -} - -void -unit_setinfo(unit * u, const char * info) -{ - free(u->display); - if (info) u->display = strdup(info); - else u->display = NULL; -} - -int -unit_getid(const unit * u) -{ - return u->no; -} - -void -unit_setid(unit * u, int id) -{ - unit * nu = findunit(id); - if (nu==NULL) { - uunhash(u); - u->no = id; - uhash(u); - } -} - -int -unit_gethp(const unit * u) -{ - return u->hp; -} - -void -unit_sethp(unit * u, int hp) -{ - u->hp = hp; -} - -status_t -unit_getstatus(const unit * u) -{ - return u->status; -} - -void -unit_setstatus(unit * u, status_t status) -{ - u->status = status; -} - -int -unit_getweight(const unit * u) -{ - return weight(u); -} - -int -unit_getcapacity(const unit * u) -{ - return walkingcapacity(u); -} - -void -unit_addorder(unit * u, order * ord) -{ - order ** ordp = &u->orders; - while (*ordp) ordp = &(*ordp)->next; - *ordp = ord; - u->faction->lastorders = turn; -} - -int -unit_max_hp(const unit * u) -{ - static int rules_stamina = -1; - int h; - double p; - static const curse_type * heal_ct = NULL; - - if (rules_stamina<0) { - rules_stamina = get_param_int(global.parameters, "rules.stamina", STAMINA_AFFECTS_HP); - } - h = u->race->hitpoints; - if (heal_ct==NULL) heal_ct = ct_find("healingzone"); - - if (rules_stamina & 1) { - p = pow(effskill(u, SK_STAMINA) / 2.0, 1.5) * 0.2; - h += (int) (h * p + 0.5); - } - /* der healing curse verändert die maximalen hp */ - if (heal_ct) { - curse *c = get_curse(u->region->attribs, heal_ct); - if (c) { - h = (int) (h * (1.0+(curse_geteffect(c)/100))); - } - } - - return h; -} - -void -scale_number (unit * u, int n) -{ - skill_t sk; - const attrib * a; - int remain; - - if (n == u->number) return; - if (n && u->number>0) { - int full; - remain = ((u->hp%u->number) * (n % u->number)) % u->number; - - full = u->hp/u->number; /* wieviel kriegt jede person mindestens */ - u->hp = full * n + (u->hp-full*u->number) * n / u->number; - assert(u->hp>=0); - if ((rng_int() % u->number) < remain) - ++u->hp; /* Nachkommastellen */ - } else { - remain = 0; - u->hp = 0; - } - if (u->number>0) { - for (a = a_find(u->attribs, &at_effect);a && a->type==&at_effect;a=a->next) { - effect_data * data = (effect_data *)a->data.v; - int snew = data->value / u->number * n; - if (n) { - remain = data->value - snew / n * u->number; - snew += remain * n / u->number; - remain = (remain * n) % u->number; - if ((rng_int() % u->number) < remain) - ++snew; /* Nachkommastellen */ - } - data->value = snew; - } - } - if (u->number==0 || n==0) { - for (sk = 0; sk < MAXSKILLS; sk++) { - remove_skill(u, sk); - } - } - - set_number(u, n); -} - -const struct race * u_irace(const struct unit * u) -{ - if (u->irace && skill_enabled[SK_STEALTH]) { - return u->irace; - } - return u->race; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "unit.h" + +#include "building.h" +#include "faction.h" +#include "group.h" +#include "connection.h" +#include "item.h" +#include "move.h" +#include "order.h" +#include "plane.h" +#include "race.h" +#include "region.h" +#include "save.h" +#include "ship.h" +#include "skill.h" +#include "terrain.h" + +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +#define FIND_FOREIGN_TEMP + +attrib_type at_creator = { + "creator" + /* Rest ist NULL; temporäres, nicht alterndes Attribut */ +}; + +#define UMAXHASH MAXUNITS +static unit * unithash[UMAXHASH]; +static unit * delmarker = (unit*)unithash; /* a funny hack */ + +#define HASH_STATISTICS 1 +#if HASH_STATISTICS +static int hash_requests; +static int hash_misses; +#endif + +void +uhash(unit * u) +{ + int key = HASH1(u->no, UMAXHASH), gk = HASH2(u->no, UMAXHASH); + while (unithash[key]!=NULL && unithash[key]!=delmarker && unithash[key]!=u) { + key = (key + gk) % UMAXHASH; + } + assert(unithash[key]!=u || !"trying to add the same unit twice"); + unithash[key] = u; +} + +void +uunhash(unit * u) +{ + int key = HASH1(u->no, UMAXHASH), gk = HASH2(u->no, UMAXHASH); + while (unithash[key]!=NULL && unithash[key]!=u) { + key = (key + gk) % UMAXHASH; + } + assert(unithash[key]==u || !"trying to remove a unit that is not hashed"); + unithash[key] = delmarker; +} + +unit * +ufindhash(int uid) +{ + assert(uid>=0); +#if HASH_STATISTICS + ++hash_requests; +#endif + if (uid>=0) { + int key = HASH1(uid, UMAXHASH), gk = HASH2(uid, UMAXHASH); + while (unithash[key]!=NULL && (unithash[key]==delmarker || unithash[key]->no!=uid)) { + key = (key + gk) % UMAXHASH; +#if HASH_STATISTICS + ++hash_misses; +#endif + } + return unithash[key]; + } + return NULL; +} + +#define DMAXHASH 7919 +typedef struct dead { + struct dead * nexthash; + faction * f; + int no; +} dead; + +static dead* deadhash[DMAXHASH]; + +static void +dhash(int no, faction * f) +{ + dead * hash = (dead*)calloc(1, sizeof(dead)); + dead * old = deadhash[no % DMAXHASH]; + hash->no = no; + hash->f = f; + deadhash[no % DMAXHASH] = hash; + hash->nexthash = old; +} + +faction * +dfindhash(int no) +{ + dead * old; + + if(no < 0) return 0; + + for (old = deadhash[no % DMAXHASH]; old; old = old->nexthash) { + if (old->no == no) { + return old->f; + } + } + return 0; +} + +typedef struct friend { + struct friend * next; + int number; + faction * faction; + unit * unit; +} friend; + +static friend * +get_friends(const unit * u, int * numfriends) +{ + friend * friends = 0; + faction * f = u->faction; + region * r = u->region; + int number = 0; + unit * u2; + + for (u2=r->units;u2;u2=u2->next) { + if (u2->faction!=f && u2->number>0) { + int allied = 0; + if (get_param_int(global.parameters, "rules.alliances", 0)!=0) { + allied = (f->alliance && f->alliance==u2->faction->alliance); + } + else if (alliedunit(u, u2->faction, HELP_MONEY) && alliedunit(u2, f, HELP_GIVE)) { + allied = 1; + } + if (allied) { + friend * nf, ** fr = &friends; + + /* some units won't take stuff: */ + if (u2->race->ec_flags & GETITEM) { + while (*fr && (*fr)->faction->nofaction->no) fr = &(*fr)->next; + nf = *fr; + if (nf==NULL || nf->faction!=u2->faction) { + nf = malloc(sizeof(friend)); + nf->next = *fr; + nf->faction = u2->faction; + nf->unit = u2; + nf->number = 0; + *fr = nf; + } else if (nf->faction==u2->faction && (u2->race->ec_flags & GIVEITEM)) { + /* we don't like to gift it to units that won't give it back */ + if ((nf->unit->race->ec_flags & GIVEITEM) == 0) { + nf->unit = u2; + } + } + nf->number += u2->number; + number += u2->number; + } + } + } + } + if (numfriends) *numfriends = number; + return friends; +} + +/** give all items to friends or peasants. + * this function returns 0 on success, or 1 if there are items that + * could not be destroyed. + */ +int +gift_items(unit * u, int flags) +{ + region * r = u->region; + item ** itm_p = &u->items; + int retval = 0; + int rule = rule_give(); + + if ((u->faction->flags&FFL_QUIT)==0 || (rule&GIVE_ONDEATH)==0) { + if ((rule&GIVE_ALLITEMS)==0 && (flags&GIFT_FRIENDS)) flags-=GIFT_FRIENDS; + if ((rule&GIVE_PEASANTS)==0 && (flags&GIFT_PEASANTS)) flags-=GIFT_PEASANTS; + if ((rule&GIVE_SELF)==0 && (flags&GIFT_SELF)) flags-=GIFT_SELF; + } + + if (u->items==NULL || fval(u->race, RCF_ILLUSIONARY)) return 0; + if ((u->race->ec_flags & GIVEITEM) == 0) return 0; + + /* at first, I should try giving my crap to my own units in this region */ + if (u->faction && (u->faction->flags&FFL_QUIT)==0 && (flags & GIFT_SELF)) { + unit * u2, * u3 = NULL; + for (u2 = r->units; u2; u2 = u2->next) { + if (u2 != u && u2->faction == u->faction && u2->number>0) { + /* some units won't take stuff: */ + if (u2->race->ec_flags & GETITEM) { + /* we don't like to gift it to units that won't give it back */ + if (u2->race->ec_flags & GIVEITEM) { + i_merge(&u2->items, &u->items); + u->items = NULL; + break; + } else { + u3 = u2; + } + } + } + } + if (u->items && u3) { + /* if nobody else takes it, we give it to a unit that has issues */ + i_merge(&u3->items, &u->items); + u->items = NULL; + } + if (u->items==NULL) return 0; + } + + /* if I have friends, I'll try to give my stuff to them */ + if (u->faction && (flags & GIFT_FRIENDS)) { + int number = 0; + friend * friends = get_friends(u, &number); + + while (friends) { + struct friend * nf = friends; + unit * u2 = nf->unit; + item * itm = u->items; + while (itm!=NULL) { + const item_type * itype = itm->type; + item * itn = itm->next; + int n = itm->number; + n = n * nf->number / number; + if (n>0) { + i_change(&u->items, itype, -n); + i_change(&u2->items, itype, n); + } + itm = itn; + } + number -= nf->number; + friends = nf->next; + free(nf); + } + if (u->items==NULL) return 0; + } + + /* last, but not least, give money and horses to peasants */ + while (*itm_p) { + item * itm = *itm_p; + + if (flags & GIFT_PEASANTS) { + if (!fval(u->region->terrain, SEA_REGION)) { + if (itm->type==olditemtype[I_HORSE]) { + rsethorses(r, rhorses(r) + itm->number); + itm->number = 0; + } else if (itm->type==i_silver) { + rsetmoney(r, rmoney(r) + itm->number); + itm->number = 0; + } + } + } + if (itm->number>0 && (itm->type->flags & ITF_NOTLOST)) { + itm_p = &itm->next; + retval = -1; + } else { + i_remove(itm_p, itm); + i_free(itm); + } + } + return retval; +} + +void +make_zombie(unit * u) +{ + u_setfaction(u, get_monsters()); + scale_number(u, 1); + u->race = new_race[RC_ZOMBIE]; + u->irace = NULL; +} + +/** remove the unit from the list of active units. + * the unit is not actually freed, because there may still be references + * dangling to it (from messages, for example). To free all removed units, + * call free_units(). + * returns 0 on success, or -1 if unit could not be removed. + */ + +static unit * deleted_units = NULL; + +int +remove_unit(unit ** ulist, unit * u) +{ + int result; + + assert(ufindhash(u->no)); + handle_event(u->attribs, "destroy", u); + + result = gift_items(u, GIFT_SELF|GIFT_FRIENDS|GIFT_PEASANTS); + if (result!=0) { + make_zombie(u); + return -1; + } + + if (u->number) set_number(u, 0); + leave(u, true); + u->region = NULL; + + uunhash(u); + if (ulist) { + while (*ulist!=u) { + ulist = &(*ulist)->next; + } + assert(*ulist==u); + *ulist = u->next; + } + + u->next = deleted_units; + deleted_units = u; + dhash(u->no, u->faction); + + u_setfaction(u, NULL); + u->region = NULL; + + return 0; +} + +unit * +findnewunit (const region * r, const faction *f, int n) +{ + unit *u2; + + if (n == 0) + return 0; + + for (u2 = r->units; u2; u2 = u2->next) + if (u2->faction == f && ualias(u2) == n) + return u2; +#ifdef FIND_FOREIGN_TEMP + for (u2 = r->units; u2; u2 = u2->next) + if (ualias(u2) == n) + return u2; +#endif + return 0; +} + +/* ------------------------------------------------------------- */ + + +/*********************/ +/* at_alias */ +/*********************/ +attrib_type at_alias = { + "alias", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +int +ualias(const unit * u) +{ + attrib * a = a_find(u->attribs, &at_alias); + if (!a) return 0; + return a->data.i; +} + +int +a_readprivate(attrib * a, void * owner, struct storage * store) +{ + a->data.v = store->r_str(store); + if (a->data.v) return AT_READ_OK; + return AT_READ_FAIL; +} + +/*********************/ +/* at_private */ +/*********************/ +attrib_type at_private = { + "private", + DEFAULT_INIT, + a_finalizestring, + DEFAULT_AGE, + a_writestring, + a_readprivate +}; + +const char * +u_description(const unit * u, const struct locale * lang) +{ + if (u->display && u->display[0]) { + return u->display; + } else if (u->race->describe) { + return u->race->describe(u, lang); + } + return NULL; +} + +const char * +uprivate(const unit * u) +{ + attrib * a = a_find(u->attribs, &at_private); + if (!a) return NULL; + return a->data.v; +} + +void +usetprivate(unit * u, const char * str) +{ + attrib * a = a_find(u->attribs, &at_private); + + if (str == NULL) { + if (a) a_remove(&u->attribs, a); + return; + } + if (!a) a = a_add(&u->attribs, a_new(&at_private)); + if (a->data.v) free(a->data.v); + a->data.v = strdup((const char*)str); +} + +/*********************/ +/* at_potionuser */ +/*********************/ +/* Einheit BENUTZT einen Trank */ +attrib_type at_potionuser = { + "potionuser", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +void +usetpotionuse(unit * u, const potion_type * ptype) +{ + attrib * a = a_find(u->attribs, &at_potionuser); + if (!a) a = a_add(&u->attribs, a_new(&at_potionuser)); + a->data.v = (void*)ptype; +} + +const potion_type * +ugetpotionuse(const unit * u) { + attrib * a = a_find(u->attribs, &at_potionuser); + if (!a) return NULL; + return (const potion_type *)a->data.v; +} + +/*********************/ +/* at_target */ +/*********************/ +attrib_type at_target = { + "target", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +unit * +utarget(const unit * u) { + attrib * a; + if (!fval(u, UFL_TARGET)) return NULL; + a = a_find(u->attribs, &at_target); + assert (a || !"flag set, but no target found"); + return (unit*)a->data.v; +} + +void +usettarget(unit * u, const unit * t) +{ + attrib * a = a_find(u->attribs, &at_target); + if (!a && t) a = a_add(&u->attribs, a_new(&at_target)); + if (a) { + if (!t) { + a_remove(&u->attribs, a); + freset(u, UFL_TARGET); + } + else { + a->data.v = (void*)t; + fset(u, UFL_TARGET); + } + } +} + +/*********************/ +/* at_siege */ +/*********************/ + +void +a_writesiege(const attrib * a, const void * owner, struct storage * store) +{ + struct building * b = (struct building*)a->data.v; + write_building_reference(b, store); +} + +int +a_readsiege(attrib * a, void * owner, struct storage * store) +{ + int result = read_reference(&a->data.v, store, read_building_reference, resolve_building); + if (result==0 && !a->data.v) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +attrib_type at_siege = { + "siege", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + a_writesiege, + a_readsiege +}; + +struct building * + usiege(const unit * u) { + attrib * a; + if (!fval(u, UFL_SIEGE)) return NULL; + a = a_find(u->attribs, &at_siege); + assert (a || !"flag set, but no siege found"); + return (struct building *)a->data.v; +} + +void +usetsiege(unit * u, const struct building * t) +{ + attrib * a = a_find(u->attribs, &at_siege); + if (!a && t) a = a_add(&u->attribs, a_new(&at_siege)); + if (a) { + if (!t) { + a_remove(&u->attribs, a); + freset(u, UFL_SIEGE); + } + else { + a->data.v = (void*)t; + fset(u, UFL_SIEGE); + } + } +} + +/*********************/ +/* at_contact */ +/*********************/ +attrib_type at_contact = { + "contact", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ +}; + +void +usetcontact(unit * u, const unit * u2) +{ + attrib * a = a_find(u->attribs, &at_contact); + while (a && a->type==&at_contact && a->data.v!=u2) a = a->next; + if (a && a->type==&at_contact) return; + a_add(&u->attribs, a_new(&at_contact))->data.v = (void*)u2; +} + +boolean +ucontact(const unit * u, const unit * u2) +/* Prüft, ob u den Kontaktiere-Befehl zu u2 gesetzt hat. */ +{ + attrib *ru; + if (u->faction==u2->faction) return true; + + /* Explizites KONTAKTIERE */ + for (ru = a_find(u->attribs, &at_contact); ru && ru->type==&at_contact; ru = ru->next) { + if (((unit*)ru->data.v) == u2) { + return true; + } + } + + return false; +} + +/*** +** init & cleanup module +**/ + +void +free_units(void) +{ + while (deleted_units) { + unit * u = deleted_units; + deleted_units = deleted_units->next; + free_unit(u); + free(u); + } +} + + +void +write_unit_reference(const unit * u, struct storage * store) +{ + store->w_id(store, (u && u->region)?u->no:0); +} + +int +resolve_unit(variant id, void * address) +{ + unit * u = NULL; + if (id.i!=0) { + u = findunit(id.i); + if (u==NULL) { + *(unit**)address = NULL; + return -1; + } + } + *(unit**)address = u; + return 0; +} + +variant +read_unit_reference(struct storage * store) +{ + variant var; + var.i = store->r_id(store); + return var; +} + +attrib_type at_stealth = { + "stealth", NULL, NULL, NULL, a_writeint, a_readint +}; + +void +u_seteffstealth(unit * u, int value) +{ + if (skill_enabled[SK_STEALTH]) { + attrib * a = NULL; + if (fval(u, UFL_STEALTH)) { + a = a_find(u->attribs, &at_stealth); + } + if (value<0) { + if (a!=NULL) { + freset(u, UFL_STEALTH); + a_remove(&u->attribs, a); + } + return; + } + if (a==NULL) { + a = a_add(&u->attribs, a_new(&at_stealth)); + fset(u, UFL_STEALTH); + } + a->data.i = value; + } +} + +int +u_geteffstealth(const struct unit * u) +{ + if (skill_enabled[SK_STEALTH]) { + if (fval(u, UFL_STEALTH)) { + attrib * a = a_find(u->attribs, &at_stealth); + if (a!=NULL) return a->data.i; + } + } + return -1; +} + +int +get_level(const unit * u, skill_t id) +{ + if (skill_enabled[id]) { + skill * sv = u->skills; + while (sv != u->skills + u->skill_size) { + if (sv->id == id) { + return sv->level; + } + ++sv; + } + } + return 0; +} + +void +set_level(unit * u, skill_t sk, int value) +{ + skill * sv = u->skills; + + if (!skill_enabled[sk]) return; + + if (value==0) { + remove_skill(u, sk); + return; + } + while (sv != u->skills + u->skill_size) { + if (sv->id == sk) { + sk_set(sv, value); + return; + } + ++sv; + } + sk_set(add_skill(u, sk), value); +} + +static int +leftship_age(struct attrib * a) +{ + /* must be aged, so it doesn't affect report generation (cansee) */ + unused(a); + return AT_AGE_REMOVE; /* remove me */ +} + +static attrib_type at_leftship = { + "leftship", NULL, NULL, leftship_age +}; + +static attrib * +make_leftship(struct ship * leftship) +{ + attrib * a = a_new(&at_leftship); + a->data.v = leftship; + return a; +} + +void +set_leftship(unit *u, ship *sh) +{ + a_add(&u->attribs, make_leftship(sh)); +} + +ship * +leftship(const unit *u) +{ + attrib * a = a_find(u->attribs, &at_leftship); + + /* Achtung: Es ist nicht garantiert, daß der Rückgabewert zu jedem + * Zeitpunkt noch auf ein existierendes Schiff zeigt! */ + + if (a) return (ship *)(a->data.v); + + return NULL; +} + +void +leave_ship(unit * u) +{ + struct ship * sh = u->ship; + if (sh==NULL) return; + u->ship = NULL; + set_leftship(u, sh); + + if (fval(u, UFL_OWNER)) { + unit *u2, *owner = NULL; + freset(u, UFL_OWNER); + + for (u2 = u->region->units; u2; u2 = u2->next) { + if (u2->ship == sh) { + if (u2->faction == u->faction) { + owner = u2; + break; + } + else if (owner==NULL) owner = u2; + } + } + if (owner!=NULL) fset(owner, UFL_OWNER); + } +} + +void +leave_building(unit * u) +{ + struct building * b = u->building; + if (!b) return; + u->building = NULL; + + if (fval(u, UFL_OWNER)) { + unit *u2, *owner = NULL; + freset(u, UFL_OWNER); + + for (u2 = u->region->units; u2; u2 = u2->next) { + if (u2->building == b) { + if (u2->faction == u->faction) { + owner = u2; + break; + } + else if (owner==NULL) owner = u2; + } + } + if (owner!=NULL) { + fset(owner, UFL_OWNER); + } + } +} + +boolean +can_leave(unit * u) +{ + static int rule_leave = -1; + + if (!u->building) { + return true; + } + if (rule_leave<0) { + rule_leave = get_param_int(global.parameters, "rules.move.owner_leave", 0); + } + if (rule_leave && u->building && u==building_owner(u->building)) { + return false; + } + return true; +} + +boolean +leave(unit * u, boolean force) +{ + if (!force) { + if (!can_leave(u)) { + return false; + } + } + if (u->building) leave_building(u); + else if (u->ship) leave_ship(u); + return true; +} + +const struct race * +urace(const struct unit * u) +{ + return u->race; +} + +boolean +can_survive(const unit *u, const region *r) +{ + if ((fval(r->terrain, WALK_INTO) && (u->race->flags & RCF_WALK)) + || (fval(r->terrain, SWIM_INTO) && (u->race->flags & RCF_SWIM)) + || (fval(r->terrain, FLY_INTO) && (u->race->flags & RCF_FLY))) + { + static const curse_type * ctype = NULL; + + if (has_horses(u) && !fval(r->terrain, WALK_INTO)) + return false; + + if (!ctype) ctype = ct_find("holyground"); + if (fval(u->race, RCF_UNDEAD) && curse_active(get_curse(r->attribs, ctype))) + return false; + + return true; + } + return false; +} + +void +move_unit(unit * u, region * r, unit ** ulist) +{ + int maxhp = 0; + assert(u && r); + + assert(u->faction || !"this unit is dead"); + if (u->region == r) return; + if (u->region!=NULL) maxhp = unit_max_hp(u); + if (!ulist) ulist = (&r->units); + if (u->region) { + setguard(u, GUARD_NONE); + fset(u, UFL_MOVED); + if (u->ship || u->building) { + /* can_leave must be checked in travel_i */ +#ifndef NDEBUG + boolean result = leave(u, false); + assert(result); +#else + leave(u, false); +#endif + } + translist(&u->region->units, ulist, u); + } else { + addlist(ulist, u); + } + +#ifdef SMART_INTERVALS + update_interval(u->faction, r); +#endif + u->region = r; + /* keine automatische hp reduzierung bei bewegung */ + /* if (maxhp>0) u->hp = u->hp * unit_max_hp(u) / maxhp; */ +} + +/* ist mist, aber wegen nicht skalierender attribute notwendig: */ +#include "alchemy.h" + +void +transfermen(unit * u, unit * u2, int n) +{ + const attrib * a; + int hp = u->hp; + region * r = u->region; + + if (n==0) return; + assert(n > 0); + /* "hat attackiert"-status wird übergeben */ + + if (u2) { + skill *sv, *sn; + skill_t sk; + ship * sh; + + assert(u2->number+n>0); + + for (sk=0; sk!=MAXSKILLS; ++sk) { + int weeks, level = 0; + + sv = get_skill(u, sk); + sn = get_skill(u2, sk); + + if (sv==NULL && sn==NULL) continue; + if (sn==NULL && u2->number==0) { + /* new unit, easy to solve */ + level = sv->level; + weeks = sv->weeks; + } else { + double dlevel = 0.0; + + if (sv && sv->level) { + dlevel += (sv->level + 1 - sv->weeks/(sv->level+1.0)) * n; + level += sv->level * n; + } + if (sn && sn->level) { + dlevel += (sn->level + 1 - sn->weeks/(sn->level+1.0)) * u2->number; + level += sn->level * u2->number; + } + + dlevel = dlevel / (n + u2->number); + level = level / (n + u2->number); + if (level<=dlevel) { + /* apply the remaining fraction to the number of weeks to go. + * subtract the according number of weeks, getting closer to the + * next level */ + level = (int)dlevel; + weeks = (level+1) - (int)((dlevel - level) * (level+1)); + } else { + /* make it harder to reach the next level. + * weeks+level is the max difficulty, 1 - the fraction between + * level and dlevel applied to the number of weeks between this + * and the previous level is the added difficutly */ + level = (int)dlevel+1; + weeks = 1 + 2 * level - (int)((1 + dlevel - level) * level); + } + } + if (level) { + if (sn==NULL) sn = add_skill(u2, sk); + sn->level = (unsigned char)level; + sn->weeks = (unsigned char)weeks; + assert(sn->weeks>0 && sn->weeks<=sn->level*2+1); + assert(u2->number!=0 || (sn->level==sv->level && sn->weeks==sv->weeks)); + } else if (sn) { + remove_skill(u2, sk); + sn = NULL; + } + } + a = a_find(u->attribs, &at_effect); + while (a && a->type==&at_effect) { + effect_data * olde = (effect_data*)a->data.v; + if (olde->value) change_effect(u2, olde->type, olde->value); + a = a->next; + } + sh = leftship(u); + if (sh!=NULL) set_leftship(u2, sh); + u2->flags |= u->flags&(UFL_LONGACTION|UFL_NOTMOVING|UFL_HUNGER|UFL_MOVED|UFL_ENTER); + if (u->attribs) { + transfer_curse(u, u2, n); + } + } + scale_number(u, u->number - n); + if (u2) { + set_number(u2, u2->number + n); + hp -= u->hp; + u2->hp += hp; + /* TODO: Das ist schnarchlahm! und gehört nicht hierhin */ + a = a_find(u2->attribs, &at_effect); + while (a && a->type==&at_effect) { + attrib * an = a->next; + effect_data * olde = (effect_data*)a->data.v; + int e = get_effect(u, olde->type); + if (e!=0) change_effect(u2, olde->type, -e); + a = an; + } + } + else if (r->land) { + if ((u->race->ec_flags & ECF_REC_ETHEREAL)==0) { + const race * rc = u->race; + if (rc->ec_flags & ECF_REC_HORSES) { /* Zentauren an die Pferde */ + int h = rhorses(r) + n; + rsethorses(r, h); + } else { + int p = rpeasants(r); + p += (int)(n * rc->recruit_multi); + rsetpeasants(r, p); + } + } + } +} + +struct building * + inside_building(const struct unit * u) +{ + if (u->building==NULL) return NULL; + + if (!fval(u->building, BLD_WORKING)) { + /* Unterhalt nicht bezahlt */ + return NULL; + } else if (u->building->size < u->building->type->maxsize) { + /* Gebäude noch nicht fertig */ + return NULL; + } else { + int p = 0, cap = buildingcapacity(u->building); + const unit * u2; + for (u2 = u->region->units; u2; u2 = u2->next) { + if (u2->building == u->building) { + p += u2->number; + if (u2 == u) { + if (p <= cap) return u->building; + return NULL; + } + if (p > cap) return NULL; + } + } + } + return NULL; +} + +void +u_setfaction(unit * u, faction * f) +{ + int cnt = u->number; + + if (u->faction==f) return; + if (u->faction) { + set_number(u, 0); + if (count_unit(u)) --u->faction->no_units; + join_group(u, NULL); + free_orders(&u->orders); + set_order(&u->thisorder, NULL); + + if (u->nextF) u->nextF->prevF = u->prevF; + if (u->prevF) u->prevF->nextF = u->nextF; + else u->faction->units = u->nextF; + } + + if (f!=NULL) { + if (f->units) f->units->prevF=u; + u->prevF = NULL; + u->nextF = f->units; + f->units = u; + } + else u->nextF = NULL; + + u->faction = f; + if (u->region) update_interval(f, u->region); + if (cnt && f) { + set_number(u, cnt); + if (count_unit(u)) ++f->no_units; + } +} + +/* vorsicht Sprüche können u->number == RS_FARVISION haben! */ +void +set_number(unit * u, int count) +{ + assert (count >= 0); + assert (count <= UNIT_MAXSIZE); + +#ifndef NDEBUG + assert(u->faction || count==0); +#endif + + if (count == 0) { + u->flags &= ~(UFL_HERO); + } + if (u->faction) { + if (playerrace(u->race)) { + u->faction->num_people += count - u->number; + } + u->number = (unsigned short)count; + } else if (u->number>0) { + assert(!"why doesn't this unit have a faction? this will fuck up num_people"); + } +} + +boolean +learn_skill(unit * u, skill_t sk, double chance) +{ + skill * sv = u->skills; + if (chance < 1.0 && rng_int()%10000>=chance*10000) return false; + while (sv != u->skills + u->skill_size) { + assert (sv->weeks>0); + if (sv->id == sk) { + if (sv->weeks<=1) { + sk_set(sv, sv->level+1); + } else { + sv->weeks--; + } + return true; + } + ++sv; + } + sv = add_skill(u, sk); + sk_set(sv, 1); + return true; +} + +void +remove_skill(unit *u, skill_t sk) +{ + skill * sv = u->skills; + for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { + if (sv->id==sk) { + skill * sl = u->skills + u->skill_size - 1; + if (sl!=sv) { + *sv = *sl; + } + --u->skill_size; + return; + } + } +} + +skill * +add_skill(unit * u, skill_t id) +{ + skill * sv = u->skills; +#ifndef NDEBUG + for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { + assert(sv->id != id); + } +#endif + ++u->skill_size; + u->skills = realloc(u->skills, u->skill_size * sizeof(skill)); + sv = (u->skills + u->skill_size - 1); + sv->level = (unsigned char)0; + sv->weeks = (unsigned char)1; + sv->old = (unsigned char)0; + sv->id = (unsigned char)id; + return sv; +} + +skill * +get_skill(const unit * u, skill_t sk) +{ + skill * sv = u->skills; + while (sv!=u->skills+u->skill_size) { + if (sv->id==sk) return sv; + ++sv; + } + return NULL; +} + +boolean +has_skill(const unit * u, skill_t sk) +{ + skill * sv = u->skills; + while (sv!=u->skills+u->skill_size) { + if (sv->id==sk) { + return (sv->level>0); + } + ++sv; + } + return false; +} + +static int +item_modification(const unit *u, skill_t sk, int val) +{ + /* Presseausweis: *2 Spionage, 0 Tarnung */ + if(sk == SK_SPY && get_item(u, I_PRESSCARD) >= u->number) { + val = val * 2; + } else if(sk == SK_STEALTH) { +#if NEWATSROI == 1 + if (get_item(u, I_RING_OF_INVISIBILITY) + + 100 * get_item(u, I_SPHERE_OF_INVISIBILITY) >= u->number) { + val += ROIBONUS; + } +#endif + if(get_item(u, I_PRESSCARD) >= u->number) { + val = 0; + } + } +#if NEWATSROI == 1 + if(sk == SK_PERCEPTION) { + if(get_item(u, I_AMULET_OF_TRUE_SEEING) >= u->number) { + val += ATSBONUS; + } + } +#endif + return val; +} + +static int +att_modification(const unit *u, skill_t sk) +{ + double bonus = 0, malus = 0; + attrib * a; + double result = 0; + static boolean init = false; + static const curse_type * skillmod_ct, * gbdream_ct, * worse_ct; + curse * c; + + if (!init) { + init = true; + skillmod_ct = ct_find("skillmod"); + gbdream_ct = ct_find("gbdream"); + worse_ct = ct_find("worse"); + } + + c = get_curse(u->attribs, worse_ct); + if (c!=NULL) result += curse_geteffect(c); + if (skillmod_ct) { + attrib * a = a_find(u->attribs, &at_curse); + while (a && a->type==&at_curse) { + curse * c = (curse *)a->data.v; + if (c->type==skillmod_ct && c->data.i==sk) { + result += curse_geteffect(c); + break; + } + a = a->next; + } + } + + /* TODO hier kann nicht mit get/iscursed gearbeitet werden, da nur der + * jeweils erste vom Typ C_GBDREAM zurückgegen wird, wir aber alle + * durchsuchen und aufaddieren müssen */ + a = a_find(u->region->attribs, &at_curse); + while (a && a->type==&at_curse) { + curse * c = (curse*)a->data.v; + if (curse_active(c) && c->type==gbdream_ct) { + double mod = curse_geteffect(c); + unit * mage = c->magician; + /* wir suchen jeweils den größten Bonus und den größten Malus */ + if (mod>bonus) { + if (mage==NULL || mage->number==0 || alliedunit(mage, u->faction, HELP_GUARD)) { + bonus = mod; + } + } else if (mod < malus) { + if (mage == NULL || !alliedunit(mage, u->faction, HELP_GUARD)) { + malus = mod; + } + } + } + a = a->next; + } + result = result + bonus + malus; + + return (int)result; +} + +int +get_modifier(const unit *u, skill_t sk, int level, const region *r, boolean noitem) +{ + int bskill = level; + int skill = bskill; + + assert(r); + if (sk == SK_STEALTH) { + plane * pl = rplane(r); + if (pl &&fval(pl, PFL_NOSTEALTH)) return 0; + } + + skill += rc_skillmod(u->race, r, sk); + skill += att_modification(u, sk); + + if (noitem == false) { + skill = item_modification(u, sk, skill); + } + skill = skillmod(u->attribs, u, r, sk, skill, SMF_ALWAYS); + +#ifdef HUNGER_REDUCES_SKILL + if (fval(u, UFL_HUNGER)) { + skill = skill/2; + } +#endif + return skill - bskill; +} + +int +eff_skill(const unit * u, skill_t sk, const region * r) +{ + if (skill_enabled[sk]) { + int level = get_level(u, sk); + if (level>0) { + int mlevel = level + get_modifier(u, sk, level, r, false); + + if (mlevel>0) { + int skillcap = SkillCap(sk); + if (skillcap && mlevel>skillcap) { + return skillcap; + } + return mlevel; + } + } + } + return 0; +} + +int +eff_skill_study(const unit * u, skill_t sk, const region * r) +{ + int level = get_level(u, sk); + if (level>0) { + int mlevel = level + get_modifier(u, sk, level, r, true); + + if (mlevel>0) return mlevel; + } + return 0; +} + +int +invisible(const unit *target, const unit * viewer) +{ +#if NEWATSROI == 1 + return 0; +#else + if (viewer && viewer->faction==target->faction) return 0; + else { + int hidden = get_item(target, I_RING_OF_INVISIBILITY) + 100 * get_item(target, I_SPHERE_OF_INVISIBILITY); + if (hidden) { + hidden = MIN(hidden, target->number); + if (viewer) hidden -= get_item(viewer, I_AMULET_OF_TRUE_SEEING); + } + return hidden; + } +#endif +} + +/** remove the unit from memory. + * this frees all memory that's only accessible through the unit, + * and you should already have called uunhash and removed the unit from the + * region. + */ +void +free_unit(unit * u) +{ + free(u->name); + free(u->display); + free_order(u->thisorder); + free_orders(&u->orders); + if (u->skills) free(u->skills); + while (u->items) { + item * it = u->items->next; + u->items->next = NULL; + i_free(u->items); + u->items = it; + } + while (u->attribs) a_remove (&u->attribs, u->attribs); + while (u->reservations) { + struct reservation *res = u->reservations; + u->reservations = res->next; + free(res); + } +} + + +void +unitlist_clear(struct unit_list **ul) +{ + while (*ul) { + unit_list * rl2 = (*ul)->next; + free(*ul); + *ul = rl2; + } +} + +void +unitlist_insert(struct unit_list **ul, struct unit *u) +{ + unit_list *rl2 = (unit_list*)malloc(sizeof(unit_list)); + + rl2->data = u; + rl2->next = *ul; + + *ul = rl2; +} + + +static void +createunitid(unit *u, int id) +{ + if (id<=0 || id > MAX_UNIT_NR || ufindhash(id) || dfindhash(id) || forbiddenid(id)) + u->no = newunitid(); + else + u->no = id; + uhash(u); +} + +void +name_unit(unit *u) +{ + if (u->race->generate_name) { + const char * gen_name = u->race->generate_name(u); + if (gen_name) { + unit_setname(u, gen_name); + } else { + unit_setname(u, racename(u->faction->locale, u, u->race)); + } + } else { + char name[32]; + snprintf(name, sizeof(name), "%s %s", LOC(u->faction->locale, "unitdefault"), itoa36(u->no)); + unit_setname(u, name); + } +} + +/** creates a new unit. +* +* @param dname: name, set to NULL to get a default. +* @param creator: unit to inherit stealth, group, building, ship, etc. from +*/ +unit * +create_unit(region * r, faction * f, int number, const struct race *urace, int id, const char * dname, unit *creator) +{ + unit * u = calloc(1, sizeof(unit)); + + assert(urace); + assert(f->alive); + u_setfaction(u, f); + + if (f->locale) { + order * deford = default_order(f->locale); + if (deford) { + set_order(&u->thisorder, NULL); + addlist(&u->orders, deford); + } + } + u_seteffstealth(u, -1); + u->race = urace; + u->irace = NULL; + + set_number(u, number); + + /* die nummer der neuen einheit muss vor name_unit generiert werden, + * da der default name immer noch 'Nummer u->no' ist */ + createunitid(u, id); + + /* zuerst in die Region setzen, da zb Drachennamen den Regionsnamen + * enthalten */ + if (r) move_unit(u, r, NULL); + + /* u->race muss bereits gesetzt sein, wird für default-hp gebraucht */ + /* u->region auch */ + u->hp = unit_max_hp(u) * number; + + if (!dname) { + name_unit(u); + } else { + u->name = strdup(dname); + } + if (count_unit(u)) f->no_units++; + + if (creator) { + attrib * a; + + /* erbt Kampfstatus */ + setstatus(u, creator->status); + + /* erbt Gebäude/Schiff*/ + if (creator->region==r) { + u->building = creator->building; + if (creator->ship!=NULL && fval(u->race, RCF_CANSAIL)) { + u->ship = creator->ship; + } + } + + /* Tarnlimit wird vererbt */ + if (fval(creator, UFL_STEALTH)) { + attrib * a = a_find(creator->attribs, &at_stealth); + if (a) { + int stealth = a->data.i; + a = a_add(&u->attribs, a_new(&at_stealth)); + a->data.i = stealth; + } + } + + /* Temps von parteigetarnten Einheiten sind wieder parteigetarnt */ + if (fval(creator, UFL_ANON_FACTION)) { + fset(u, UFL_ANON_FACTION); + } + /* Daemonentarnung */ + set_racename(&u->attribs, get_racename(creator->attribs)); + if (fval(u->race, RCF_SHAPESHIFT) && fval(creator->race, RCF_SHAPESHIFT)) { + u->irace = creator->irace; + } + + /* Gruppen */ + if (creator->faction==f && fval(creator, UFL_GROUP)) { + a = a_find(creator->attribs, &at_group); + if (a) { + group * g = (group*)a->data.v; + set_group(u, g); + } + } + a = a_find(creator->attribs, &at_otherfaction); + if (a) { + a_add(&u->attribs, make_otherfaction(get_otherfaction(a))); + } + + a = a_add(&u->attribs, a_new(&at_creator)); + a->data.v = creator; + } + + return u; +} + +int +maxheroes(const struct faction * f) +{ + int nsize = count_all(f); + if (nsize==0) return 0; + else { + int nmax = (int)(log10(nsize / 50.0) * 20); + return (nmax<0)?0:nmax; + } +} + +int +countheroes(const struct faction * f) +{ + const unit * u = f->units; + int n = 0; + + while (u) { + if (fval(u, UFL_HERO)) n+= u->number; + u = u->nextF; + } +#ifdef DEBUG_MAXHEROES + int m = maxheroes(f); + if (n>m) { + log_warning(("%s has %d of %d heroes\n", factionname(f), n, m)); + } +#endif + return n; +} + +const char * +unit_getname(const unit * u) +{ + return (const char *)u->name; +} + +void +unit_setname(unit * u, const char * name) +{ + free(u->name); + if (name) u->name = strdup(name); + else u->name = NULL; +} + +const char * +unit_getinfo(const unit * u) +{ + return (const char *)u->display; +} + +void +unit_setinfo(unit * u, const char * info) +{ + free(u->display); + if (info) u->display = strdup(info); + else u->display = NULL; +} + +int +unit_getid(const unit * u) +{ + return u->no; +} + +void +unit_setid(unit * u, int id) +{ + unit * nu = findunit(id); + if (nu==NULL) { + uunhash(u); + u->no = id; + uhash(u); + } +} + +int +unit_gethp(const unit * u) +{ + return u->hp; +} + +void +unit_sethp(unit * u, int hp) +{ + u->hp = hp; +} + +status_t +unit_getstatus(const unit * u) +{ + return u->status; +} + +void +unit_setstatus(unit * u, status_t status) +{ + u->status = status; +} + +int +unit_getweight(const unit * u) +{ + return weight(u); +} + +int +unit_getcapacity(const unit * u) +{ + return walkingcapacity(u); +} + +void +unit_addorder(unit * u, order * ord) +{ + order ** ordp = &u->orders; + while (*ordp) ordp = &(*ordp)->next; + *ordp = ord; + u->faction->lastorders = turn; +} + +int +unit_max_hp(const unit * u) +{ + static int rules_stamina = -1; + int h; + double p; + static const curse_type * heal_ct = NULL; + + if (rules_stamina<0) { + rules_stamina = get_param_int(global.parameters, "rules.stamina", STAMINA_AFFECTS_HP); + } + h = u->race->hitpoints; + if (heal_ct==NULL) heal_ct = ct_find("healingzone"); + + if (rules_stamina & 1) { + p = pow(effskill(u, SK_STAMINA) / 2.0, 1.5) * 0.2; + h += (int) (h * p + 0.5); + } + /* der healing curse verändert die maximalen hp */ + if (heal_ct) { + curse *c = get_curse(u->region->attribs, heal_ct); + if (c) { + h = (int) (h * (1.0+(curse_geteffect(c)/100))); + } + } + + return h; +} + +void +scale_number (unit * u, int n) +{ + skill_t sk; + const attrib * a; + int remain; + + if (n == u->number) return; + if (n && u->number>0) { + int full; + remain = ((u->hp%u->number) * (n % u->number)) % u->number; + + full = u->hp/u->number; /* wieviel kriegt jede person mindestens */ + u->hp = full * n + (u->hp-full*u->number) * n / u->number; + assert(u->hp>=0); + if ((rng_int() % u->number) < remain) + ++u->hp; /* Nachkommastellen */ + } else { + remain = 0; + u->hp = 0; + } + if (u->number>0) { + for (a = a_find(u->attribs, &at_effect);a && a->type==&at_effect;a=a->next) { + effect_data * data = (effect_data *)a->data.v; + int snew = data->value / u->number * n; + if (n) { + remain = data->value - snew / n * u->number; + snew += remain * n / u->number; + remain = (remain * n) % u->number; + if ((rng_int() % u->number) < remain) + ++snew; /* Nachkommastellen */ + } + data->value = snew; + } + } + if (u->number==0 || n==0) { + for (sk = 0; sk < MAXSKILLS; sk++) { + remove_skill(u, sk); + } + } + + set_number(u, n); +} + +const struct race * u_irace(const struct unit * u) +{ + if (u->irace && skill_enabled[SK_STEALTH]) { + return u->irace; + } + return u->race; +} diff --git a/src/kernel/unit.h b/src/kernel/unit.h index c6068bb3b..86af46741 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -1,237 +1,237 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_KRNL_UNIT_H -#define H_KRNL_UNIT_H - -#include -#include "types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct skill; -struct item; -#define UFL_DEBUG (1<<0) -#define UFL_ISNEW (1<<1) /* 2 */ -#define UFL_LONGACTION (1<<2) /* 4 */ -#define UFL_OWNER (1<<3) /* 8 */ -#define UFL_ANON_FACTION (1<<4) /* 16 */ -#define UFL_DISBELIEVES (1<<5) /* 32 */ -#define UFL_WARMTH (1<<6) /* 64 */ -#define UFL_HERO (1<<7) -#define UFL_MOVED (1<<8) -#define UFL_NOTMOVING (1<<9) /* Die Einheit kann sich wg. langen Kampfes nicht bewegen */ -#define UFL_DEFENDER (1<<10) -#define UFL_HUNGER (1<<11) /* kann im Folgemonat keinen langen Befehl außer ARBEITE ausführen */ -#define UFL_SIEGE (1<<12) /* speedup: belagert eine burg, siehe attribut */ -#define UFL_TARGET (1<<13) /* speedup: hat ein target, siehe attribut */ -#define UFL_WERE (1<<14) -#define UFL_ENTER (1<<15) /* unit has entered a ship/building and will not leave it */ - -/* warning: von 512/1024 gewechslet, wegen konflikt mit NEW_FOLLOW */ -#define UFL_LOCKED (1<<16) /* Einheit kann keine Personen aufnehmen oder weggeben, nicht rekrutieren. */ -#define UFL_FLEEING (1<<17) /* unit was in a battle, fleeing. */ -#define UFL_STORM (1<<19) /* Kapitän war in einem Sturm */ -#define UFL_FOLLOWING (1<<20) -#define UFL_FOLLOWED (1<<21) - -#define UFL_NOAID (1<<22) /* Einheit hat Noaid-Status */ -#define UFL_MARK (1<<23) /* same as FL_MARK */ -#define UFL_ORDERS (1<<24) /* Einheit hat Befehle erhalten */ -#define UFL_TAKEALL (1<<25) /* Einheit nimmt alle Gegenstände an */ - -/* flags that speed up attribute access: */ -#define UFL_STEALTH (1<<26) -#define UFL_GUARD (1<<27) -#define UFL_GROUP (1<<28) - -/* Flags, die gespeichert werden sollen: */ -#define UFL_SAVEMASK (UFL_DEFENDER|UFL_MOVED|UFL_NOAID|UFL_OWNER|UFL_ANON_FACTION|UFL_LOCKED|UFL_HUNGER|UFL_TAKEALL|UFL_GUARD|UFL_STEALTH|UFL_GROUP|UFL_HERO) - -#define UNIT_MAXSIZE 50000 -extern int maxheroes(const struct faction * f); -extern int countheroes(const struct faction * f); - -typedef struct unit { - struct unit *next; /* needs to be first entry, for region's unitlist */ - struct unit *nextF; /* nächste Einheit der Partei */ - struct unit *prevF; /* vorherige Einheit der Partei */ - struct region *region; - int no; - int hp; - char *name; - char *display; - struct faction *faction; - struct building *building; - struct ship *ship; - unsigned short number; - short age; - - /* skill data */ - short skill_size; - struct skill *skills; - struct item * items; - struct reservation { - struct reservation * next; - const struct resource_type * type; - int value; - } * reservations; - - /* orders */ - struct order * orders; - struct order * thisorder; - struct order * old_orders; - - /* race and illusionary race */ - const struct race * race; - const struct race * irace; - - unsigned int flags; - struct attrib * attribs; - status_t status; - int n; /* enno: attribut? */ - int wants; /* enno: attribut? */ -} unit; - -typedef struct unit_list { - struct unit_list * next; - struct unit * data; -} unit_list; - -extern void unitlist_clear(struct unit_list **ul); -extern void unitlist_insert(struct unit_list **ul, struct unit *u); - -extern struct attrib_type at_alias; -extern struct attrib_type at_siege; -extern struct attrib_type at_target; -extern struct attrib_type at_potionuser; -extern struct attrib_type at_contact; -extern struct attrib_type at_effect; -extern struct attrib_type at_private; -extern struct attrib_type at_showskchange; - -int ualias(const struct unit * u); - -extern struct attrib_type at_stealth; - -void u_seteffstealth(struct unit * u, int value); -int u_geteffstealth(const struct unit * u); -const struct race * u_irace(const struct unit * u); -struct building * usiege(const struct unit * u); -void usetsiege(struct unit * u, const struct building * b); - -struct unit * utarget(const struct unit * u); -void usettarget(struct unit * u, const struct unit * b); - -struct unit * utarget(const struct unit * u); -void usettarget(struct unit * u, const struct unit * b); - -extern const struct race * urace(const struct unit * u); - -const char * uprivate(const struct unit * u); -void usetprivate(struct unit * u, const char * c); - -const struct potion_type * ugetpotionuse(const struct unit * u); /* benutzt u einein trank? */ -void usetpotionuse(struct unit * u, const struct potion_type * p); /* u benutzt trank p (es darf halt nur einer pro runde) */ - -boolean ucontact(const struct unit * u, const struct unit * u2); -void usetcontact(struct unit * u, const struct unit * c); - -struct unit * findnewunit (const struct region * r, const struct faction *f, int alias); - -extern const char * u_description(const unit * u, const struct locale * lang); -extern struct skill * add_skill(struct unit * u, skill_t id); -extern void remove_skill(struct unit *u, skill_t sk); -extern struct skill * get_skill(const struct unit * u, skill_t id); -extern boolean has_skill(const unit* u, skill_t sk); - -extern void set_level(struct unit * u, skill_t id, int level); -extern int get_level(const struct unit * u, skill_t id); -extern void transfermen(struct unit * u, struct unit * u2, int n); - -extern int eff_skill(const struct unit * u, skill_t sk, const struct region * r); -extern int eff_skill_study(const struct unit * u, skill_t sk, const struct region * r); - -extern int get_modifier(const struct unit * u, skill_t sk, int lvl, const struct region * r, boolean noitem); -extern int remove_unit(struct unit ** ulist, struct unit * u); - -#define GIFT_SELF 1<<0 -#define GIFT_FRIENDS 1<<1 -#define GIFT_PEASANTS 1<<2 -int gift_items(struct unit * u, int flags); -void make_zombie(unit * u); - -/* see resolve.h */ -extern int resolve_unit(variant data, void * address); -extern void write_unit_reference(const struct unit * u, struct storage * store); -extern variant read_unit_reference(struct storage * store); - -extern boolean leave(struct unit * u, boolean force); -extern boolean can_leave(struct unit * u); - -extern void leave_ship(unit * u); -extern void leave_building(unit * u); - -extern void set_leftship(struct unit *u, struct ship *sh); -extern struct ship * leftship(const struct unit *); -extern boolean can_survive(const struct unit *u, const struct region *r); -extern void move_unit(struct unit * u, struct region * target, struct unit ** ulist); - -extern struct building * inside_building(const struct unit * u); - -/* cleanup code for this module */ -extern void free_units(void); -extern struct faction * dfindhash(int no); -extern void u_setfaction(struct unit * u, struct faction * f); -extern void set_number(struct unit * u, int count); - -extern boolean learn_skill(struct unit * u, skill_t sk, double chance); - -extern int invisible(const struct unit *target, const struct unit * viewer); -extern void free_unit(struct unit * u); - -extern void name_unit(struct unit *u); -extern struct unit * create_unit(struct region * r1, struct faction * f, int number, const struct race * rc, int id, const char * dname, struct unit *creator); - -extern void uhash(struct unit * u); -extern void uunhash(struct unit * u); -extern struct unit *ufindhash(int i); - -const char * unit_getname(const struct unit * u); -void unit_setname(struct unit * u, const char * name); -const char * unit_getinfo(const struct unit * u); -void unit_setinfo(struct unit * u, const char * name); -int unit_getid(const unit * u); -void unit_setid(unit * u, int id); -int unit_gethp(const unit * u); -void unit_sethp(unit * u, int id); -status_t unit_getstatus(const unit * u); -void unit_setstatus(unit * u, status_t status); -int unit_getweight(const unit * u); -int unit_getcapacity(const unit * u); -void unit_addorder(unit * u, struct order * ord); -int unit_max_hp(const struct unit * u); -void scale_number(struct unit * u, int n); - -extern struct attrib_type at_creator; -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_UNIT_H +#define H_KRNL_UNIT_H + +#include +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct skill; +struct item; +#define UFL_DEBUG (1<<0) +#define UFL_ISNEW (1<<1) /* 2 */ +#define UFL_LONGACTION (1<<2) /* 4 */ +#define UFL_OWNER (1<<3) /* 8 */ +#define UFL_ANON_FACTION (1<<4) /* 16 */ +#define UFL_DISBELIEVES (1<<5) /* 32 */ +#define UFL_WARMTH (1<<6) /* 64 */ +#define UFL_HERO (1<<7) +#define UFL_MOVED (1<<8) +#define UFL_NOTMOVING (1<<9) /* Die Einheit kann sich wg. langen Kampfes nicht bewegen */ +#define UFL_DEFENDER (1<<10) +#define UFL_HUNGER (1<<11) /* kann im Folgemonat keinen langen Befehl außer ARBEITE ausführen */ +#define UFL_SIEGE (1<<12) /* speedup: belagert eine burg, siehe attribut */ +#define UFL_TARGET (1<<13) /* speedup: hat ein target, siehe attribut */ +#define UFL_WERE (1<<14) +#define UFL_ENTER (1<<15) /* unit has entered a ship/building and will not leave it */ + +/* warning: von 512/1024 gewechslet, wegen konflikt mit NEW_FOLLOW */ +#define UFL_LOCKED (1<<16) /* Einheit kann keine Personen aufnehmen oder weggeben, nicht rekrutieren. */ +#define UFL_FLEEING (1<<17) /* unit was in a battle, fleeing. */ +#define UFL_STORM (1<<19) /* Kapitän war in einem Sturm */ +#define UFL_FOLLOWING (1<<20) +#define UFL_FOLLOWED (1<<21) + +#define UFL_NOAID (1<<22) /* Einheit hat Noaid-Status */ +#define UFL_MARK (1<<23) /* same as FL_MARK */ +#define UFL_ORDERS (1<<24) /* Einheit hat Befehle erhalten */ +#define UFL_TAKEALL (1<<25) /* Einheit nimmt alle Gegenstände an */ + +/* flags that speed up attribute access: */ +#define UFL_STEALTH (1<<26) +#define UFL_GUARD (1<<27) +#define UFL_GROUP (1<<28) + +/* Flags, die gespeichert werden sollen: */ +#define UFL_SAVEMASK (UFL_DEFENDER|UFL_MOVED|UFL_NOAID|UFL_OWNER|UFL_ANON_FACTION|UFL_LOCKED|UFL_HUNGER|UFL_TAKEALL|UFL_GUARD|UFL_STEALTH|UFL_GROUP|UFL_HERO) + +#define UNIT_MAXSIZE 50000 +extern int maxheroes(const struct faction * f); +extern int countheroes(const struct faction * f); + +typedef struct unit { + struct unit *next; /* needs to be first entry, for region's unitlist */ + struct unit *nextF; /* nächste Einheit der Partei */ + struct unit *prevF; /* vorherige Einheit der Partei */ + struct region *region; + int no; + int hp; + char *name; + char *display; + struct faction *faction; + struct building *building; + struct ship *ship; + unsigned short number; + short age; + + /* skill data */ + short skill_size; + struct skill *skills; + struct item * items; + struct reservation { + struct reservation * next; + const struct resource_type * type; + int value; + } * reservations; + + /* orders */ + struct order * orders; + struct order * thisorder; + struct order * old_orders; + + /* race and illusionary race */ + const struct race * race; + const struct race * irace; + + unsigned int flags; + struct attrib * attribs; + status_t status; + int n; /* enno: attribut? */ + int wants; /* enno: attribut? */ +} unit; + +typedef struct unit_list { + struct unit_list * next; + struct unit * data; +} unit_list; + +extern void unitlist_clear(struct unit_list **ul); +extern void unitlist_insert(struct unit_list **ul, struct unit *u); + +extern struct attrib_type at_alias; +extern struct attrib_type at_siege; +extern struct attrib_type at_target; +extern struct attrib_type at_potionuser; +extern struct attrib_type at_contact; +extern struct attrib_type at_effect; +extern struct attrib_type at_private; +extern struct attrib_type at_showskchange; + +int ualias(const struct unit * u); + +extern struct attrib_type at_stealth; + +void u_seteffstealth(struct unit * u, int value); +int u_geteffstealth(const struct unit * u); +const struct race * u_irace(const struct unit * u); +struct building * usiege(const struct unit * u); +void usetsiege(struct unit * u, const struct building * b); + +struct unit * utarget(const struct unit * u); +void usettarget(struct unit * u, const struct unit * b); + +struct unit * utarget(const struct unit * u); +void usettarget(struct unit * u, const struct unit * b); + +extern const struct race * urace(const struct unit * u); + +const char * uprivate(const struct unit * u); +void usetprivate(struct unit * u, const char * c); + +const struct potion_type * ugetpotionuse(const struct unit * u); /* benutzt u einein trank? */ +void usetpotionuse(struct unit * u, const struct potion_type * p); /* u benutzt trank p (es darf halt nur einer pro runde) */ + +boolean ucontact(const struct unit * u, const struct unit * u2); +void usetcontact(struct unit * u, const struct unit * c); + +struct unit * findnewunit (const struct region * r, const struct faction *f, int alias); + +extern const char * u_description(const unit * u, const struct locale * lang); +extern struct skill * add_skill(struct unit * u, skill_t id); +extern void remove_skill(struct unit *u, skill_t sk); +extern struct skill * get_skill(const struct unit * u, skill_t id); +extern boolean has_skill(const unit* u, skill_t sk); + +extern void set_level(struct unit * u, skill_t id, int level); +extern int get_level(const struct unit * u, skill_t id); +extern void transfermen(struct unit * u, struct unit * u2, int n); + +extern int eff_skill(const struct unit * u, skill_t sk, const struct region * r); +extern int eff_skill_study(const struct unit * u, skill_t sk, const struct region * r); + +extern int get_modifier(const struct unit * u, skill_t sk, int lvl, const struct region * r, boolean noitem); +extern int remove_unit(struct unit ** ulist, struct unit * u); + +#define GIFT_SELF 1<<0 +#define GIFT_FRIENDS 1<<1 +#define GIFT_PEASANTS 1<<2 +int gift_items(struct unit * u, int flags); +void make_zombie(unit * u); + +/* see resolve.h */ +extern int resolve_unit(variant data, void * address); +extern void write_unit_reference(const struct unit * u, struct storage * store); +extern variant read_unit_reference(struct storage * store); + +extern boolean leave(struct unit * u, boolean force); +extern boolean can_leave(struct unit * u); + +extern void leave_ship(unit * u); +extern void leave_building(unit * u); + +extern void set_leftship(struct unit *u, struct ship *sh); +extern struct ship * leftship(const struct unit *); +extern boolean can_survive(const struct unit *u, const struct region *r); +extern void move_unit(struct unit * u, struct region * target, struct unit ** ulist); + +extern struct building * inside_building(const struct unit * u); + +/* cleanup code for this module */ +extern void free_units(void); +extern struct faction * dfindhash(int no); +extern void u_setfaction(struct unit * u, struct faction * f); +extern void set_number(struct unit * u, int count); + +extern boolean learn_skill(struct unit * u, skill_t sk, double chance); + +extern int invisible(const struct unit *target, const struct unit * viewer); +extern void free_unit(struct unit * u); + +extern void name_unit(struct unit *u); +extern struct unit * create_unit(struct region * r1, struct faction * f, int number, const struct race * rc, int id, const char * dname, struct unit *creator); + +extern void uhash(struct unit * u); +extern void uunhash(struct unit * u); +extern struct unit *ufindhash(int i); + +const char * unit_getname(const struct unit * u); +void unit_setname(struct unit * u, const char * name); +const char * unit_getinfo(const struct unit * u); +void unit_setinfo(struct unit * u, const char * name); +int unit_getid(const unit * u); +void unit_setid(unit * u, int id); +int unit_gethp(const unit * u); +void unit_sethp(unit * u, int id); +status_t unit_getstatus(const unit * u); +void unit_setstatus(unit * u, status_t status); +int unit_getweight(const unit * u); +int unit_getcapacity(const unit * u); +void unit_addorder(unit * u, struct order * ord); +int unit_max_hp(const struct unit * u); +void scale_number(struct unit * u, int n); + +extern struct attrib_type at_creator; +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/version.h b/src/kernel/version.h index 745a30a5e..a07ea3e52 100644 --- a/src/kernel/version.h +++ b/src/kernel/version.h @@ -1,71 +1,71 @@ -/* vi: set ts=2: - +-------------------+ - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2007 | Christian Schlittchen - | | - +-------------------+ - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - - */ - -/* changes from->to: 72->73: struct unit::lock entfernt. - * 73->74: struct unit::flags eingeführt. - * 74->75: parteitarnung als flag. - * 75->76: #ifdef NEW_HP: hp - * 76->77: ship->damage - * 77->78: neue Message-Option "Orkvermehrung" (MAX_MSG +1) - * 78->79: showdata nicht mehr speichern - * 79->HEX_VERSION: hex - * 80->82: ATTRIB_VERSION - * 90: Ebenen - * 92: Magiegebiet-Auswahl f->magiegebiet - * 94: f->attribs wird gespeichert - * 100: NEWMAGIC, neue Message-Option "Zauber" (MAX_MSG +1) - * 108: Speichern von Timeouts - * 193: curse bekommen id aus struct unit-nummernraum - */ - -/* -#define HEX_VERSION 81 -#define GROWTREE_VERSION 305 -#define RANDOMIZED_RESOURCES_VERSION 306 -#define NEWRACE_VERSION 307 -#define INTERIM_VERSION 309 -#define NEWSKILL_VERSION 309 -#define WATCHERS_VERSION 310 -*/ -#define OVERRIDE_VERSION 311 -#define CURSETYPE_VERSION 312 /* turn 287 */ -#define ALLIANCES_VERSION 313 -#define DBLINK_VERSION 314 -#define CURSEVIGOURISFLOAT_VERSION 315 -#define SAVEXMLNAME_VERSION 316 -#define SAVEALLIANCE_VERSION 317 -#define CLAIM_VERSION 318 -/* 319 is the HSE4 data version */ -#define BACTION_VERSION 319 /* building action gets a param string */ -#define NOLASTORDER_VERSION 320 /* do not use lastorder */ -#define SPELLNAME_VERSION 321 /* reference spells by name */ -#define TERRAIN_VERSION 322 /* terrains are a full type and saved by name */ -#define REGIONITEMS_VERSION 323 /* regions have items */ -#define ATTRIBREAD_VERSION 324 /* remove a_readint */ -#define CURSEFLAGS_VERSION 325 /* remove a_readint */ -#define UNICODE_VERSION 326 /* 2007-06-27 everything is stored as UTF8 */ -#define UID_VERSION 327 /* regions have a unique id */ -#define STORAGE_VERSION 328 /* with storage.h, some things are stored smarter (ids as base36, fractions as float) */ -#define INTPAK_VERSION 329 /* in binary, ints can get packed */ -#define NOZEROIDS_VERSION 330 /* 2008-05-16 zero is not a valid ID for anything (including factions) */ -#define NOBORDERATTRIBS_VERSION 331 /* 2008-05-17 connection::attribs has been moved to userdata */ -#define UIDHASH_VERSION 332 /* 2008-05-22 borders use the region.uid to store */ -#define REGIONOWNER_VERSION 333 /* 2009-05-14 regions have owners and morale */ -#define ALLIANCELEADER_VERSION 333 /* alliances have a leader */ -#define CURSEFLOAT_VERSION 334 /* all curse-effects are float */ -#define MOURNING_VERSION 335 /* mourning peasants */ -#define FOSS_VERSION 336 /* the open source release */ -#define OWNER_2_VERSION 337 /* region owners contain an alliance */ - -#define MIN_VERSION CURSETYPE_VERSION /* minimal datafile we support */ -#define RELEASE_VERSION OWNER_2_VERSION /* current datafile */ +/* vi: set ts=2: + +-------------------+ + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2007 | Christian Schlittchen + | | + +-------------------+ + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ + +/* changes from->to: 72->73: struct unit::lock entfernt. + * 73->74: struct unit::flags eingeführt. + * 74->75: parteitarnung als flag. + * 75->76: #ifdef NEW_HP: hp + * 76->77: ship->damage + * 77->78: neue Message-Option "Orkvermehrung" (MAX_MSG +1) + * 78->79: showdata nicht mehr speichern + * 79->HEX_VERSION: hex + * 80->82: ATTRIB_VERSION + * 90: Ebenen + * 92: Magiegebiet-Auswahl f->magiegebiet + * 94: f->attribs wird gespeichert + * 100: NEWMAGIC, neue Message-Option "Zauber" (MAX_MSG +1) + * 108: Speichern von Timeouts + * 193: curse bekommen id aus struct unit-nummernraum + */ + +/* +#define HEX_VERSION 81 +#define GROWTREE_VERSION 305 +#define RANDOMIZED_RESOURCES_VERSION 306 +#define NEWRACE_VERSION 307 +#define INTERIM_VERSION 309 +#define NEWSKILL_VERSION 309 +#define WATCHERS_VERSION 310 +*/ +#define OVERRIDE_VERSION 311 +#define CURSETYPE_VERSION 312 /* turn 287 */ +#define ALLIANCES_VERSION 313 +#define DBLINK_VERSION 314 +#define CURSEVIGOURISFLOAT_VERSION 315 +#define SAVEXMLNAME_VERSION 316 +#define SAVEALLIANCE_VERSION 317 +#define CLAIM_VERSION 318 +/* 319 is the HSE4 data version */ +#define BACTION_VERSION 319 /* building action gets a param string */ +#define NOLASTORDER_VERSION 320 /* do not use lastorder */ +#define SPELLNAME_VERSION 321 /* reference spells by name */ +#define TERRAIN_VERSION 322 /* terrains are a full type and saved by name */ +#define REGIONITEMS_VERSION 323 /* regions have items */ +#define ATTRIBREAD_VERSION 324 /* remove a_readint */ +#define CURSEFLAGS_VERSION 325 /* remove a_readint */ +#define UNICODE_VERSION 326 /* 2007-06-27 everything is stored as UTF8 */ +#define UID_VERSION 327 /* regions have a unique id */ +#define STORAGE_VERSION 328 /* with storage.h, some things are stored smarter (ids as base36, fractions as float) */ +#define INTPAK_VERSION 329 /* in binary, ints can get packed */ +#define NOZEROIDS_VERSION 330 /* 2008-05-16 zero is not a valid ID for anything (including factions) */ +#define NOBORDERATTRIBS_VERSION 331 /* 2008-05-17 connection::attribs has been moved to userdata */ +#define UIDHASH_VERSION 332 /* 2008-05-22 borders use the region.uid to store */ +#define REGIONOWNER_VERSION 333 /* 2009-05-14 regions have owners and morale */ +#define ALLIANCELEADER_VERSION 333 /* alliances have a leader */ +#define CURSEFLOAT_VERSION 334 /* all curse-effects are float */ +#define MOURNING_VERSION 335 /* mourning peasants */ +#define FOSS_VERSION 336 /* the open source release */ +#define OWNER_2_VERSION 337 /* region owners contain an alliance */ + +#define MIN_VERSION CURSETYPE_VERSION /* minimal datafile we support */ +#define RELEASE_VERSION OWNER_2_VERSION /* current datafile */ diff --git a/src/kernel/xmlkernel.h b/src/kernel/xmlkernel.h index 9b3832b77..b2cb331c4 100644 --- a/src/kernel/xmlkernel.h +++ b/src/kernel/xmlkernel.h @@ -1,30 +1,28 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2007 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifndef H_KRNL_XML -#define H_KRNL_XML - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef HAVE_LIBXML -#include - -extern void xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, struct construction ** consPtr); -#endif - -#ifdef __cplusplus -} -#endif - -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2007 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifndef H_KRNL_XML +#define H_KRNL_XML + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern void xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, struct construction ** consPtr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index a66ad5d86..829f3736d 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1,2180 +1,2180 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2004 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "xmlreader.h" - -/* kernel includes */ -#include "building.h" -#include "equipment.h" -#include "item.h" -#include "message.h" -#include "race.h" -#include "region.h" -#include "resources.h" -#include "ship.h" -#include "terrain.h" -#include "skill.h" -#include "spell.h" -#include "calendar.h" - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include - - -/* libxml includes */ -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -static boolean gamecode_enabled = false; - -void (*set_spelldata_cb)(struct spell * sp) = 0; -static building_type * bt_get_or_create(const char * name) -{ - if (name!=NULL) { - building_type * btype = bt_find(name); - if (btype==NULL) { - btype = calloc(sizeof(building_type), 1); - btype->_name = strdup(name); - bt_register(btype); - } - return btype; - } - return NULL; -} - -void -enable_xml_gamecode(void) -{ - gamecode_enabled = true; -} - -static void -xml_readtext(xmlNodePtr node, struct locale ** lang, xmlChar **text) -{ - xmlChar * propValue = xmlGetProp(node, BAD_CAST "locale"); - assert(propValue!=NULL); - *lang = find_locale((const char*)propValue); -#ifdef MAKE_LOCALES - if (*lang==NULL) *lang = make_locale((const char*)propValue); -#endif - xmlFree(propValue); - - *text = xmlNodeListGetString(node->doc, node->children, 1); -} - -static const spell * -xml_spell(xmlNode * node, const char * name) -{ - const spell * sp = NULL; - xmlChar * propValue = xmlGetProp(node, BAD_CAST name); - if (propValue!=NULL) { - sp = find_spell(M_NONE, (const char *)propValue); - assert(sp); - xmlFree(propValue); - } - return sp; -} - -static xmlChar * -xml_cleanup_string(xmlChar * str) -{ - xmlChar * read = str; - xmlChar * write = str; - - while (*read) { - /* eat leading whitespace */ - if (*read && isxspace(*read)) { - while (*read && isxspace(*read)) { - ++read; - } - *write++ = ' '; - } - while (*read) { - if (*read== '\n') break; - if (*read== '\r') break; - *write++ = *read++; - } - } - *write = 0; - return str; -} - -static const resource_type * -rt_findorcreate(const char * name) -{ - resource_type * rtype = rt_find(name); - if (rtype==NULL) { - const char * names[2]; - char * namep = strcat(strcpy((char*)malloc(strlen(name)+3), name), "_p"); - /* we'll make a placeholder */ - names[0] = name; - names[1] = namep; - rtype = new_resourcetype(names, NULL, RTF_NONE); - free(namep); - } - return rtype; -} - -static void -xml_readrequirements(xmlNodePtr * nodeTab, int nodeNr, requirement ** reqArray) -{ - int req; - requirement * radd = *reqArray; - - assert (radd==NULL); - if (nodeNr==0) return; - - radd = *reqArray = calloc(sizeof(requirement), nodeNr+1); - - for (req=0;req!=nodeNr;++req) { - xmlNodePtr node = nodeTab[req]; - xmlChar * propValue; - - radd->number = xml_ivalue(node, "quantity", 1); - radd->recycle = xml_fvalue(node, "recycle", 0.5); - - propValue = xmlGetProp(node, BAD_CAST "type"); - radd->rtype = rt_findorcreate((const char*)propValue); - xmlFree(propValue); - - ++radd; - } -} - -void -xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, construction ** consPtr) -{ - xmlNodePtr pushNode = xpath->node; - int k; - for (k=0;k!=nodeSet->nodeNr;++k) { - xmlNodePtr node = nodeSet->nodeTab[k]; - xmlChar * propValue; - construction * con; - xmlXPathObjectPtr req; - int m; - skill_t sk = NOSKILL; - - propValue = xmlGetProp(node, BAD_CAST "skill"); - if (propValue!=NULL) { - sk = sk_find((const char*)propValue); - if (sk==NOSKILL) { - log_error(("construction requires skill '%s' that does not exist.\n", (const char *)propValue)); - xmlFree(propValue); - continue; - } - xmlFree(propValue); - } - - assert(*consPtr==NULL); - - *consPtr = con = calloc(sizeof(construction), 1); - consPtr = &con->improvement; - - con->skill = sk; - con->maxsize = xml_ivalue(node, "maxsize", -1); - con->minskill = xml_ivalue(node, "minskill", -1); - con->reqsize = xml_ivalue(node, "reqsize", -1); - - propValue = xmlGetProp(node, BAD_CAST "building"); - if (propValue!=NULL) { - con->btype = bt_get_or_create((const char*)propValue); - xmlFree(propValue); - } - - /* read construction/requirement */ - xpath->node = node; - req = xmlXPathEvalExpression(BAD_CAST "requirement", xpath); - xml_readrequirements(req->nodesetval->nodeTab, - req->nodesetval->nodeNr, &con->materials); - xmlXPathFreeObject(req); - - /* read construction/modifier */ - xpath->node = node; - req = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); - for (m=0;m!=req->nodesetval->nodeNr;++m) { - xmlNodePtr node = req->nodesetval->nodeTab[m]; - - propValue = xmlGetProp(node, BAD_CAST "function"); - if (propValue!=NULL) { - pf_generic foo = get_function((const char*)propValue); - a_add(&con->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION, (skillmod_fun)foo, 1.0, 0)); - xmlFree(propValue); - } - - } - xmlXPathFreeObject(req); - } - xpath->node = pushNode; -} - -static int -parse_function(xmlNodePtr node, pf_generic * funPtr, xmlChar ** namePtr) -{ - pf_generic fun; - xmlChar * propValue = xmlGetProp(node, BAD_CAST "value"); - assert(propValue!=NULL); - fun = get_function((const char*)propValue); - if (fun!=NULL) { - xmlFree(propValue); - - propValue = xmlGetProp(node, BAD_CAST "name"); - } - *namePtr = propValue; - *funPtr = fun; - return 0; -} - -static int -parse_buildings(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr buildings; - int i; - - /* reading eressea/buildings/building */ - buildings = xmlXPathEvalExpression(BAD_CAST "/eressea/buildings/building", xpath); - if (buildings->nodesetval!=NULL) { - xmlNodeSetPtr nodes = buildings->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr node = nodes->nodeTab[i]; - xmlChar * propValue; - building_type * btype; - xmlXPathObjectPtr result; - int k; - - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - btype = bt_get_or_create((const char*)propValue); - xmlFree(propValue); - - btype->capacity = xml_ivalue(node, "capacity", -1); - btype->maxcapacity = xml_ivalue(node, "maxcapacity", -1); - btype->maxsize = xml_ivalue(node, "maxsize", -1); - - btype->magres = xml_ivalue(node, "magres", 0); - btype->magresbonus = xml_ivalue(node, "magresbonus", 0); - btype->fumblebonus = xml_ivalue(node, "fumblebonus", 0); - btype->auraregen = xml_fvalue(node, "auraregen", 1.0); - - if (xml_bvalue(node, "nodestroy", false)) btype->flags |= BTF_INDESTRUCTIBLE; - if (xml_bvalue(node, "oneperturn", false)) btype->flags |= BTF_ONEPERTURN; - if (xml_bvalue(node, "nobuild", false)) btype->flags |= BTF_NOBUILD; - if (xml_bvalue(node, "namechange", true)) btype->flags |= BTF_NAMECHANGE; - if (xml_bvalue(node, "unique", false)) btype->flags |= BTF_UNIQUE; - if (xml_bvalue(node, "decay", false)) btype->flags |= BTF_DECAY; - if (xml_bvalue(node, "magic", false)) btype->flags |= BTF_MAGIC; - - /* reading eressea/buildings/building/construction */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); - xml_readconstruction(xpath, result->nodesetval, &btype->construction); - xmlXPathFreeObject(result); - - if (gamecode_enabled) { - /* reading eressea/buildings/building/function */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - pf_generic fun; - parse_function(node, &fun, &propValue); - - if (fun==NULL) { - log_error(("unknown function name '%s' for building %s\n", - (const char*)propValue, btype->_name)); - xmlFree(propValue); - continue; - } - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "name")==0) { - btype->name = (const char * (*)(const struct building_type*, const struct building *, int))fun; - } else if (strcmp((const char*)propValue, "init")==0) { - btype->init = (void (*)(struct building_type*))fun; - } else if (strcmp((const char*)propValue, "age")==0) { - btype->age = (void (*)(struct building*))fun; - } else if (strcmp((const char*)propValue, "protection")==0) { - btype->protection = (int (*)(struct building*, struct unit *))fun; - } else if (strcmp((const char*)propValue, "taxes")==0) { - btype->taxes = (double (*)(const struct building*, int))fun; - } else if (strcmp((const char*)propValue, "age")==0) { - btype->age = (void (*)(struct building*))fun; - } else { - log_error(("unknown function type '%s' for building %s\n", - (const char*)propValue, btype->_name)); - } - xmlFree(propValue); - } - xmlXPathFreeObject(result); - } - - /* reading eressea/buildings/building/maintenance */ - result = xmlXPathEvalExpression(BAD_CAST "maintenance", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - maintenance * mt; - - if (btype->maintenance==NULL) { - btype->maintenance = calloc(sizeof(struct maintenance), result->nodesetval->nodeNr+1); - } - mt = btype->maintenance + k; - mt->number = xml_ivalue(node, "amount", 0); - - propValue = xmlGetProp(node, BAD_CAST "type"); - assert(propValue!=NULL); - mt->rtype = rt_find((const char*)propValue); - assert(mt->rtype!=NULL); - xmlFree(propValue); - - if (xml_bvalue(node, "variable", false)) mt->flags |= MTF_VARIABLE; - if (xml_bvalue(node, "vital", false)) mt->flags |= MTF_VITAL; - - } - xmlXPathFreeObject(result); - - /* finally, initialize the new building type */ - if (btype->init) btype->init(btype); - } - } - xmlXPathFreeObject(buildings); - - xmlXPathFreeContext(xpath); - return 0; -} - -static int -parse_calendar(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr xpathCalendars; - xmlNodeSetPtr nsetCalendars; - int c, rv = 0; - - /* reading eressea/buildings/building */ - xpathCalendars = xmlXPathEvalExpression(BAD_CAST "/eressea/calendar", xpath); - nsetCalendars = xpathCalendars->nodesetval; - months_per_year = 0; - if (nsetCalendars==NULL || nsetCalendars->nodeNr==0) { - rv = -1; - } else for (c=0;c!=nsetCalendars->nodeNr;++c) { - xmlNodePtr calendar = nsetCalendars->nodeTab[c]; - xmlXPathObjectPtr xpathWeeks, xpathMonths, xpathSeasons; - xmlNodeSetPtr nsetWeeks, nsetMonths, nsetSeasons; - xmlChar * propValue = xmlGetProp(calendar, BAD_CAST "name"); - xmlChar * newyear = xmlGetProp(calendar, BAD_CAST "newyear"); - - first_turn = xml_ivalue(calendar, "start", first_turn); - if (propValue) { - free(agename); - agename = strdup(mkname("calendar", (const char*)propValue)); - xmlFree(propValue); - } - - xpath->node = calendar; - xpathWeeks = xmlXPathEvalExpression(BAD_CAST "week", xpath); - nsetWeeks = xpathWeeks->nodesetval; - if (nsetWeeks!=NULL && nsetWeeks->nodeNr) { - int i; - - weeks_per_month = nsetWeeks->nodeNr; - assert(!weeknames); - weeknames = malloc(sizeof(char *) * weeks_per_month); - weeknames2 = malloc(sizeof(char *) * weeks_per_month); - for (i=0;i!=nsetWeeks->nodeNr;++i) { - xmlNodePtr week = nsetWeeks->nodeTab[i]; - xmlChar * propValue = xmlGetProp(week, BAD_CAST "name"); - if (propValue) { - weeknames[i] = strdup(mkname("calendar", (const char*)propValue)); - weeknames2[i] = malloc(strlen(weeknames[i])+3); - sprintf(weeknames2[i], "%s_d", weeknames[i]); - xmlFree(propValue); - } - } - } - xmlXPathFreeObject(xpathWeeks); - - xpathSeasons = xmlXPathEvalExpression(BAD_CAST "season", xpath); - nsetSeasons = xpathSeasons->nodesetval; - if (nsetSeasons!=NULL && nsetSeasons->nodeNr) { - int i; - - seasons = nsetSeasons->nodeNr; - assert(!seasonnames); - seasonnames = malloc(sizeof(char *) * seasons); - - for (i=0;i!=nsetSeasons->nodeNr;++i) { - xmlNodePtr season = nsetSeasons->nodeTab[i]; - xmlChar * propValue = xmlGetProp(season, BAD_CAST "name"); - if (propValue) { - seasonnames[i] = strdup(mkname("calendar", (const char*)propValue)); - xmlFree(propValue); - } - } - } - - xpathMonths = xmlXPathEvalExpression(BAD_CAST "season/month", xpath); - nsetMonths = xpathMonths->nodesetval; - if (nsetMonths!=NULL && nsetMonths->nodeNr) { - int i; - - months_per_year = nsetMonths->nodeNr; - assert(!monthnames); - monthnames = malloc(sizeof(char *) * months_per_year); - month_season = malloc(sizeof(int) * months_per_year); - storms = malloc(sizeof(int) * months_per_year); - - for (i=0;i!=nsetMonths->nodeNr;++i) { - xmlNodePtr month = nsetMonths->nodeTab[i]; - xmlChar * propValue = xmlGetProp(month, BAD_CAST "name"); - int j; - - if (propValue) { - if (newyear && strcmp((const char*)newyear, (const char*)propValue)==0) { - first_month = i; - xmlFree(newyear); - newyear = NULL; - } - monthnames[i] = strdup(mkname("calendar", (const char*)propValue)); - xmlFree(propValue); - } - for (j=0;j!=seasons;++j) { - xmlNodePtr season = month->parent; - if (season==nsetSeasons->nodeTab[j]) { - month_season[i] = j; - break; - } - } - assert(j!=seasons); - storms[i] = xml_ivalue(nsetMonths->nodeTab[i], "storm", 0); - } - } - xmlXPathFreeObject(xpathMonths); - xmlXPathFreeObject(xpathSeasons); - } - xmlXPathFreeObject(xpathCalendars); - xmlXPathFreeContext(xpath); - - return rv; -} - -static int -parse_directions(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr xpathDirections; - xmlNodeSetPtr nsetDirections; - int rv = 0; - - /* reading eressea/directions/dir */ - xpathDirections = xmlXPathEvalExpression(BAD_CAST "/eressea/directions/dir", xpath); - nsetDirections = xpathDirections->nodesetval; - if (nsetDirections!=NULL) { - int k; - for (k=0;k!=nsetDirections->nodeNr;++k) { - xmlNodePtr dir = nsetDirections->nodeTab[k]; - xmlChar * propValue = xmlGetProp(dir, BAD_CAST "name"); - - register_special_direction((const char *)propValue); - xmlFree(propValue); - } - } - xmlXPathFreeObject(xpathDirections); - xmlXPathFreeContext(xpath); - - return rv; -} - -static int -parse_ships(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr ships; - int i; - - /* reading eressea/ships/ship */ - ships = xmlXPathEvalExpression(BAD_CAST "/eressea/ships/ship", xpath); - if (ships->nodesetval!=NULL) { - xmlNodeSetPtr nodes = ships->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr child, node = nodes->nodeTab[i]; - xmlChar * propValue; - ship_type * st = calloc(sizeof(ship_type), 1); - xmlXPathObjectPtr result; - int k, c; - - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - st->name[0] = strdup((const char *)propValue); - st->name[1] = strcat(strcpy(malloc(strlen(st->name[0])+3), st->name[0]),"_a"); - xmlFree(propValue); - - st->cabins = xml_ivalue(node, "cabins", 0) * PERSON_WEIGHT; - st->cargo = xml_ivalue(node, "cargo", 0); - st->combat = xml_ivalue(node, "combat", 0); - st->cptskill = xml_ivalue(node, "cptskill", 0); - st->damage = xml_fvalue(node, "damage", 0.0); - if (xml_bvalue(node, "nocoast", false)) st->flags |= SFL_NOCOAST; - if (xml_bvalue(node, "fly", false)) st->flags |= SFL_FLY; - if (xml_bvalue(node, "opensea", false)) st->flags |= SFL_OPENSEA; - st->fishing = xml_ivalue(node, "fishing", 0); - st->minskill = xml_ivalue(node, "minskill", 0); - st->range = xml_ivalue(node, "range", 0); - st->storm = xml_fvalue(node, "storm", 1.0); - st->sumskill = xml_ivalue(node, "sumskill", 0); - - /* reading eressea/ships/ship/construction */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); - xml_readconstruction(xpath, result->nodesetval, &st->construction); - xmlXPathFreeObject(result); - - for (child=node->children;child;child=child->next) { - if (strcmp((const char *)child->name, "modifier")==0) { - double value = xml_fvalue(child, "value", 0.0); - propValue = xmlGetProp(child, BAD_CAST "type"); - if (strcmp((const char *)propValue, "tactics")==0) st->tac_bonus = (float)value; - else if (strcmp((const char *)propValue, "attack")==0) st->at_bonus = (int)value; - else if (strcmp((const char *)propValue, "defense")==0) st->df_bonus = (int)value; - xmlFree(propValue); - } - } - /* reading eressea/ships/ship/coast */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "coast", xpath); - for (c=0,k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - - if (k==0) { - assert(st->coasts==NULL); - st->coasts = (const terrain_type**)malloc(sizeof(const terrain_type*) * (result->nodesetval->nodeNr+1)); - st->coasts[result->nodesetval->nodeNr] = NULL; - } - - propValue = xmlGetProp(node, BAD_CAST "terrain"); - assert(propValue!=NULL); - st->coasts[c] = get_terrain((const char*)propValue); - if (st->coasts[c]!=NULL) ++c; - else { - log_warning(("ship %s mentions a non-existing terrain %s.\n", st->name[0], propValue)); - } - xmlFree(propValue); - } - xmlXPathFreeObject(result); - - /* finally, register the new building type */ - st_register(st); - } - } - xmlXPathFreeObject(ships); - - xmlXPathFreeContext(xpath); - return 0; -} - -static void -race_compat(void) -{ - /* required for old_race, do not change order! */ - const char * oldracenames[MAXRACES] = { - "dwarf", "elf", NULL, "goblin", "human", "troll", "demon", "insect", - "halfling", "cat", "aquarian", "orc", "snotling", "undead", "illusion", - "youngdragon", "dragon", "wyrm", "ent", "catdragon", "dracoid", - "special", "spell", "irongolem", "stonegolem", "shadowdemon", - "shadowmaster", "mountainguard", "alp", "toad", "braineater", "peasant", - "wolf", NULL, NULL, NULL, NULL, "songdragon", NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, "seaserpent", - "shadowknight", "centaur", "skeleton", "skeletonlord", "zombie", - "juju-zombie", "ghoul", "ghast", "museumghost", "gnome", "template", - "clone" - }; - int i; - - for (i=0;i!=MAXRACES;++i) { - const char * rcname = oldracenames[i]; - if (rcname==NULL) { - new_race[i] = NULL; - } else { - race * rc = rc_find(oldracenames[i]); - if (rc) { - new_race[i] = rc; - if (rc == new_race[RC_TROLL]) { - a_add(&rc->attribs, make_skillmod(NOSKILL, SMF_RIDING, NULL, 0.0, -1)); - } - } - } - } -} - -static potion_type * -xml_readpotion(xmlXPathContextPtr xpath, item_type * itype) -{ - int level = xml_ivalue(xpath->node, "level", 0); - - assert(level>0); - return new_potiontype(itype, level); -} - -static luxury_type * -xml_readluxury(xmlXPathContextPtr xpath, item_type * itype) -{ - int price = xml_ivalue(xpath->node, "price", 0); - return new_luxurytype(itype, price); -} - - -static armor_type * -xml_readarmor(xmlXPathContextPtr xpath, item_type * itype) -{ - xmlNodePtr node = xpath->node; - armor_type * atype = NULL; - unsigned int flags = ATF_NONE; - int ac = xml_ivalue(node, "ac", 0); - double penalty = xml_fvalue(node, "penalty", 0.0); - double magres = xml_fvalue(node, "magres", 0.0); - - if (xml_bvalue(node, "laen", false)) flags |= ATF_LAEN; - if (xml_bvalue(node, "shield", false)) flags |= ATF_SHIELD; - - atype = new_armortype(itype, penalty, magres, ac, flags); - atype->projectile = (float)xml_fvalue(node, "projectile", 0.0); - return atype; -} - -static weapon_type * -xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) -{ - xmlNodePtr node = xpath->node; - weapon_type * wtype = NULL; - unsigned int flags = WTF_NONE; - xmlXPathObjectPtr result; - xmlChar * propValue; - int k; - skill_t sk; - int minskill = xml_ivalue(node, "minskill", 0); - int offmod = xml_ivalue(node, "offmod", 0); - int defmod = xml_ivalue(node, "defmod", 0); - int reload = xml_ivalue(node, "reload", 0); - double magres = xml_fvalue(node, "magres", 0.0); - - if (xml_bvalue(node, "armorpiercing", false)) flags |= WTF_ARMORPIERCING; - if (xml_bvalue(node, "magical", false)) flags |= WTF_MAGICAL; - if (xml_bvalue(node, "missile", false)) flags |= WTF_MISSILE; - if (xml_bvalue(node, "pierce", false)) flags |= WTF_PIERCE; - if (xml_bvalue(node, "cut", false)) flags |= WTF_CUT; - if (xml_bvalue(node, "blunt", false)) flags |= WTF_BLUNT; - if (xml_bvalue(node, "siege", false)) flags |= WTF_SIEGE; - if (xml_bvalue(node, "horse", (flags&WTF_MISSILE)==0)) flags |= WTF_HORSEBONUS; - if (xml_bvalue(node, "useshield", true)) flags |= WTF_USESHIELD; - - propValue = xmlGetProp(node, BAD_CAST "skill"); - assert(propValue!=NULL); - sk = sk_find((const char*)propValue); - assert(sk!=NOSKILL); - xmlFree(propValue); - - wtype = new_weapontype(itype, flags, magres, NULL, offmod, defmod, reload, sk, minskill); - - /* reading weapon/damage */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "damage", xpath); - assert(result->nodesetval->nodeNr<=2); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - int pos = 0; - - propValue = xmlGetProp(node, BAD_CAST "type"); - if (strcmp((const char *)propValue, "footman")!=0) { - pos = 1; - } - xmlFree(propValue); - - propValue = xmlGetProp(node, BAD_CAST "value"); - wtype->damage[pos] = gc_add(strdup((const char*)propValue)); - if (k==0) wtype->damage[1-pos] = wtype->damage[pos]; - xmlFree(propValue); - } - xmlXPathFreeObject(result); - - /* reading weapon/modifier */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); - assert(wtype->modifiers==NULL); - wtype->modifiers = calloc(result->nodesetval->nodeNr+1, sizeof(weapon_mod)); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - xmlXPathObjectPtr races; - int r, flags = 0; - - if (xml_bvalue(node, "walking", false)) flags|=WMF_WALKING; - if (xml_bvalue(node, "riding", false)) flags|=WMF_RIDING; - if (xml_bvalue(node, "against_walking", false)) flags|=WMF_AGAINST_WALKING; - if (xml_bvalue(node, "against_riding", false)) flags|=WMF_AGAINST_RIDING; - if (xml_bvalue(node, "offensive", false)) flags|=WMF_OFFENSIVE; - if (xml_bvalue(node, "defensive", false)) flags|=WMF_DEFENSIVE; - - propValue = xmlGetProp(node, BAD_CAST "type"); - if (strcmp((const char*)propValue, "damage")==0) flags|=WMF_DAMAGE; - else if (strcmp((const char*)propValue, "skill")==0) flags|=WMF_SKILL; - else if (strcmp((const char*)propValue, "missile_target")==0) flags|=WMF_MISSILE_TARGET; - xmlFree(propValue); - - wtype->modifiers[k].flags = flags; - wtype->modifiers[k].value = xml_ivalue(node, "value", 0); - - xpath->node = node; - races = xmlXPathEvalExpression(BAD_CAST "race", xpath); - for (r=0;r!=races->nodesetval->nodeNr;++r) { - xmlNodePtr node = races->nodesetval->nodeTab[r]; - - propValue = xmlGetProp(node, BAD_CAST "name"); - if (propValue!=NULL) { - const race * rc = rc_find((const char*)propValue); - if (rc==NULL) rc = rc_add(rc_new((const char*)propValue)); - racelist_insert(&wtype->modifiers[k].races, rc); - xmlFree(propValue); - } - } - xmlXPathFreeObject(races); - } - xmlXPathFreeObject(result); - - if (gamecode_enabled) { - /* reading weapon/function */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - xmlChar * propValue; - pf_generic fun; - - parse_function(node, &fun, &propValue); - if (fun==NULL) { - log_error(("unknown function name '%s' for item '%s'\n", - (const char*)propValue, itype->rtype->_name[0])); - xmlFree(propValue); - continue; - } - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "attack")==0) { - wtype->attack = (boolean (*)(const struct troop*, const struct weapon_type *, int*))fun; - } else { - log_error(("unknown function type '%s' for item '%s'\n", - (const char*)propValue, itype->rtype->_name[0])); - } - xmlFree(propValue); - } - xmlXPathFreeObject(result); - } - - xpath->node = node; - return wtype; -} - -static item_type * -xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) -{ - xmlNodePtr node = xpath->node; - item_type * itype = NULL; - unsigned int flags = ITF_NONE; - xmlXPathObjectPtr result; - int k; - - int weight = xml_ivalue(node, "weight", 0); - int capacity = xml_ivalue(node, "capacity", 0); - - if (xml_bvalue(node, "cursed", false)) flags |= ITF_CURSED; - if (xml_bvalue(node, "notlost", false)) flags |= ITF_NOTLOST; - if (xml_bvalue(node, "herb", false)) flags |= ITF_HERB; - if (xml_bvalue(node, "big", false)) flags |= ITF_BIG; - if (xml_bvalue(node, "animal", false)) flags |= ITF_ANIMAL; - if (xml_bvalue(node, "vehicle", false)) flags |= ITF_VEHICLE; - itype = new_itemtype(rtype, flags, weight, capacity); -#if SCORE_MODULE - itype->score = xml_ivalue(node, "score", 0); -#endif - - /* reading item/construction */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); - xml_readconstruction(xpath, result->nodesetval, &itype->construction); - xmlXPathFreeObject(result); - - /* reading item/weapon */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "weapon", xpath); - assert(result->nodesetval->nodeNr<=1); - if (result->nodesetval->nodeNr!=0) { - xpath->node = result->nodesetval->nodeTab[0]; - rtype->wtype = xml_readweapon(xpath, itype); - } - xmlXPathFreeObject(result); - - /* reading item/potion */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "potion", xpath); - assert(result->nodesetval->nodeNr<=1); - if (result->nodesetval->nodeNr!=0) { - xpath->node = result->nodesetval->nodeTab[0]; - rtype->ptype = xml_readpotion(xpath, itype); - } - xmlXPathFreeObject(result); - - /* reading item/luxury */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "luxury", xpath); - assert(result->nodesetval->nodeNr<=1); - if (result->nodesetval->nodeNr!=0) { - xpath->node = result->nodesetval->nodeTab[0]; - rtype->ltype = xml_readluxury(xpath, itype); - } - xmlXPathFreeObject(result); - - /* reading item/armor */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "armor", xpath); - assert(result->nodesetval->nodeNr<=1); - if (result->nodesetval->nodeNr!=0) { - xpath->node = result->nodesetval->nodeTab[0]; - rtype->atype = xml_readarmor(xpath, itype); - } - xmlXPathFreeObject(result); - - if (gamecode_enabled) { - /* reading item/function */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - xmlChar * propValue; - pf_generic fun; - - parse_function(node, &fun, &propValue); - if (fun==NULL) { - log_error(("unknown function name '%s' for item '%s'\n", - (const char*)propValue, rtype->_name[0])); - xmlFree(propValue); - continue; - } - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "give")==0) { - itype->give = (int (*)(struct unit*, struct unit*, const struct item_type *, int, struct order *))fun; - } else if (strcmp((const char*)propValue, "use")==0) { - itype->use = (int (*)(struct unit *, const struct item_type *, int, struct order *))fun; - } else if (strcmp((const char*)propValue, "canuse")==0) { - itype->canuse = (boolean (*)(const struct unit *, const struct item_type *))fun; - } else if (strcmp((const char*)propValue, "useonother")==0) { - itype->useonother = (int (*)(struct unit *, int, const struct item_type *, int, struct order *))fun; - } else { - log_error(("unknown function type '%s' for item '%s'\n", - (const char*)propValue, rtype->_name[0])); - } - xmlFree(propValue); - } - xmlXPathFreeObject(result); - } - - return itype; -} - -static int -parse_rules(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr functions; - xmlNodeSetPtr nodes; - int i; - - /* reading eressea/resources/resource */ - functions = xmlXPathEvalExpression(BAD_CAST "/eressea/rules/function", xpath); - nodes = functions->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr node = nodes->nodeTab[i]; - xmlChar *propValue; - pf_generic fun; - - parse_function(node, &fun, &propValue); - - if (fun==NULL) { - log_error(("unknown function for rule '%s' %s\n", (const char*)propValue)); - xmlFree(propValue); - continue; - } - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "wage")==0) { - global.functions.wage = (int (*)(const struct region*, const struct faction*, const struct race*, int))fun; - } else if (strcmp((const char*)propValue, "maintenance")==0) { - global.functions.maintenance = (int (*)(const struct unit*))fun; - } else { - log_error(("unknown function for rule '%s'\n", - (const char*)propValue)); - } - xmlFree(propValue); - } - xmlXPathFreeObject(functions); - xmlXPathFreeContext(xpath); - return 0; -} - -static int -parse_resources(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr resources; - xmlNodeSetPtr nodes; - int i; - - /* reading eressea/resources/resource */ - resources = xmlXPathEvalExpression(BAD_CAST "/eressea/resources/resource", xpath); - nodes = resources->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr node = nodes->nodeTab[i]; - xmlChar *propValue, *name, *appearance; - const char *names[2], *appearances[2]; - char * namep = NULL, * appearancep = NULL; - resource_type * rtype; - unsigned int flags = RTF_NONE; - xmlXPathObjectPtr result; - int k; - - if (xml_bvalue(node, "pooled", true)) flags |= RTF_POOLED; - if (xml_bvalue(node, "limited", false)) flags |= RTF_LIMITED; - - name = xmlGetProp(node, BAD_CAST "name"); - appearance = xmlGetProp(node, BAD_CAST "appearance"); - assert(name!=NULL); - - if (appearance!=NULL) { - appearancep = strcat(strcpy((char*)malloc(strlen((char*)appearance)+3), (char*)appearance), "_p"); - } - - rtype = rt_find((const char *)name); - if (rtype!=NULL) { - /* dependency from another item, was created earlier */ - rtype->flags |= flags; - if (appearance) { - rtype->_appearance[0] = strdup((const char*)appearance); - rtype->_appearance[1] = appearancep; - free(appearancep); - } - } else { - namep = strcat(strcpy((char*)malloc(strlen((char*)name)+3), (char*)name), "_p"); - names[0] = (const char*)name; - names[1] = namep; - if (appearance) { - appearances[0] = (const char*)appearance; - appearances[1] = appearancep; - rtype = new_resourcetype((const char**)names, (const char**)appearances, flags); - free(appearancep); - } else { - rtype = new_resourcetype(names, NULL, flags); - } - free(namep); - } - - if (name) xmlFree(name); - if (appearance) xmlFree(appearance); - - name = xmlGetProp(node, BAD_CAST "material"); - if (name) { - rmt_create(rtype, (const char *)name); - xmlFree(name); - } - - - if (gamecode_enabled) { - /* reading eressea/resources/resource/function */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - if (result->nodesetval!=NULL) for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - pf_generic fun; - - parse_function(node, &fun, &propValue); - if (fun==NULL) { - log_error(("unknown function name '%s' for resource %s\n", - (const char*)propValue, rtype->_name[0])); - xmlFree(propValue); - continue; - } - - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "change")==0) { - rtype->uchange = (rtype_uchange)fun; - } else if (strcmp((const char*)propValue, "get")==0) { - rtype->uget = (rtype_uget)fun; - } else if (strcmp((const char*)propValue, "name")==0) { - rtype->name = (rtype_name)fun; - } else { - log_error(("unknown function type '%s' for resource %s\n", - (const char*)propValue, rtype->_name[0])); - } - xmlFree(propValue); - } - xmlXPathFreeObject(result); - } - - /* reading eressea/resources/resource/resourcelimit */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "resourcelimit", xpath); - assert(result->nodesetval->nodeNr<=1); - if (result->nodesetval->nodeNr!=0) { - resource_limit * rdata; - attrib * a = a_find(rtype->attribs, &at_resourcelimit); - xmlNodePtr limit = result->nodesetval->nodeTab[0]; - - if (a==NULL) a = a_add(&rtype->attribs, a_new(&at_resourcelimit)); - rdata = (resource_limit*)a->data.v; - rtype->flags |= RTF_LIMITED; - xpath->node = limit; - xmlXPathFreeObject(result); - - result = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); - if (result->nodesetval!=NULL) { - rdata->modifiers = calloc(result->nodesetval->nodeNr+1, sizeof(resource_mod)); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - building_type * btype = NULL; - const race * rc = NULL; - - propValue = xmlGetProp(node, BAD_CAST "race"); - if (propValue!=NULL) { - rc = rc_find((const char*)propValue); - if (rc==NULL) rc = rc_add(rc_new((const char*)propValue)); - xmlFree(propValue); - } - rdata->modifiers[k].race = rc; - - propValue = xmlGetProp(node, BAD_CAST "building"); - if (propValue!=NULL) { - btype = bt_get_or_create((const char*)propValue); - xmlFree(propValue); - } - rdata->modifiers[k].btype = btype; - - propValue = xmlGetProp(node, BAD_CAST "type"); - assert(propValue!=NULL); - if (strcmp((const char *)propValue, "skill")==0) { - rdata->modifiers[k].value.i = xml_ivalue(node, "value", 0); - rdata->modifiers[k].flags = RMF_SKILL; - } else if (strcmp((const char *)propValue, "material")==0) { - rdata->modifiers[k].value.f = (float)xml_fvalue(node, "value", 0); - rdata->modifiers[k].flags = RMF_SAVEMATERIAL; - } else if (strcmp((const char *)propValue, "resource")==0) { - rdata->modifiers[k].value.f = (float)xml_fvalue(node, "value", 0); - rdata->modifiers[k].flags = RMF_SAVERESOURCE; - } else if (strcmp((const char *)propValue, "require")==0) { - xmlChar * propBldg = xmlGetProp(node, BAD_CAST "building"); - if (propBldg!=NULL) { - btype = bt_get_or_create((const char*)propBldg); - rdata->modifiers[k].btype = btype; - rdata->modifiers[k].flags = RMF_REQUIREDBUILDING; - xmlFree(propBldg); - } - } else { - log_error(("unknown type '%s' for resourcelimit-modifier '%s'\n", - (const char*)propValue, rtype->_name[0])); - } - xmlFree(propValue); - } - } - xmlXPathFreeObject(result); - - result = xmlXPathEvalExpression(BAD_CAST "guard", xpath); - if (result->nodesetval!=NULL) for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - xmlChar * propFlag = xmlGetProp(node, BAD_CAST "flag"); - - if (propFlag!=NULL) { - if (strcmp((const char *)propFlag, "logging")==0) { - rdata->guard |= GUARD_TREES; - } else if (strcmp((const char *)propFlag, "mining")==0) { - rdata->guard |= GUARD_MINING; - } - xmlFree(propFlag); - } - } - xmlXPathFreeObject(result); - - /* reading eressea/resources/resource/resourcelimit/function */ - result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - if (result->nodesetval!=NULL) for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - pf_generic fun; - - propValue = xmlGetProp(node, BAD_CAST "value"); - assert(propValue!=NULL); - fun = get_function((const char*)propValue); - if (fun==NULL) { - log_error(("unknown limit '%s' for resource %s\n", - (const char*)propValue, rtype->_name[0])); - xmlFree(propValue); - continue; - } - xmlFree(propValue); - - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "produce")==0) { - rdata->produce = (rlimit_produce)fun; - } else if (strcmp((const char*)propValue, "limit")==0) { - rdata->limit = (rlimit_limit)fun; - } else { - log_error(("unknown limit '%s' for resource %s\n", - (const char*)propValue, rtype->_name[0])); - } - xmlFree(propValue); - } - } - xmlXPathFreeObject(result); - - /* reading eressea/resources/resource/resourcelimit/function */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "resourcelimit/function", xpath); - xmlXPathFreeObject(result); - - /* reading eressea/resources/resource/item */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "item", xpath); - assert(result->nodesetval->nodeNr<=1); - if (result->nodesetval->nodeNr!=0) { - rtype->flags |= RTF_ITEM; - xpath->node = result->nodesetval->nodeTab[0]; - rtype->itype = xml_readitem(xpath, rtype); - } - xmlXPathFreeObject(result); - } - xmlXPathFreeObject(resources); - - xmlXPathFreeContext(xpath); - - /* make sure old items (used in requirements) are available */ - init_resources(); - init_itemtypes(); - - return 0; -} - -static void -add_items(equipment * eq, xmlNodeSetPtr nsetItems) -{ - if (nsetItems!=NULL && nsetItems->nodeNr>0) { - int i; - for (i=0;i!=nsetItems->nodeNr;++i) { - xmlNodePtr node = nsetItems->nodeTab[i]; - xmlChar * propValue; - const struct item_type * itype; - - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - itype = it_find((const char*)propValue); - xmlFree(propValue); - if (itype!=NULL) { - propValue = xmlGetProp(node, BAD_CAST "amount"); - if (propValue!=NULL) { - equipment_setitem(eq, itype, (const char*)propValue); - xmlFree(propValue); - } - } - } - } -} - -static void -add_callbacks(equipment * eq, xmlNodeSetPtr nsetItems) -{ - if (nsetItems!=NULL && nsetItems->nodeNr>0) { - int i; - for (i=0;i!=nsetItems->nodeNr;++i) { - xmlNodePtr node = nsetItems->nodeTab[i]; - xmlChar * propValue; - pf_generic fun; - - propValue = xmlGetProp(node, BAD_CAST "name"); - if (propValue!=NULL) { - fun = get_function((const char*)propValue); - if (fun) { - equipment_setcallback(eq, (void (*)(const struct equipment *, struct unit *))fun); - } - xmlFree(propValue); - } - } - } -} - -static void -add_spells(equipment * eq, xmlNodeSetPtr nsetItems) -{ - if (nsetItems!=NULL && nsetItems->nodeNr>0) { - int i; - for (i=0;i!=nsetItems->nodeNr;++i) { - xmlNodePtr node = nsetItems->nodeTab[i]; - xmlChar * propValue; - magic_t mtype = M_NONE; - struct spell * sp; - - propValue = xmlGetProp(node, BAD_CAST "school"); - if (propValue!=NULL) { - for (mtype=0;mtype!=MAXMAGIETYP;++mtype) { - if (strcmp((const char*)propValue, magic_school[mtype])==0) break; - } - assert(mtype!=MAXMAGIETYP); - xmlFree(propValue); - } - - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - sp = find_spell(mtype, (const char*)propValue); - assert(sp); - xmlFree(propValue); - if (sp!=NULL) { - equipment_addspell(eq, sp); - } - } - } -} - -static void -add_skills(equipment * eq, xmlNodeSetPtr nsetSkills) -{ - if (nsetSkills!=NULL && nsetSkills->nodeNr>0) { - int i; - for (i=0;i!=nsetSkills->nodeNr;++i) { - xmlNodePtr node = nsetSkills->nodeTab[i]; - xmlChar * propValue; - skill_t sk; - - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - sk = sk_find((const char*)propValue); - xmlFree(propValue); - if (sk!=NOSKILL) { - propValue = xmlGetProp(node, BAD_CAST "level"); - if (propValue!=NULL) { - equipment_setskill(eq, sk, (const char*)propValue); - xmlFree(propValue); - } - } - } - } -} - -static void -add_subsets(xmlDocPtr doc, equipment * eq, xmlNodeSetPtr nsetSubsets) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - if (nsetSubsets!=NULL && nsetSubsets->nodeNr>0) { - int i; - - eq->subsets = calloc(nsetSubsets->nodeNr+1, sizeof(subset)); - for (i=0;i!=nsetSubsets->nodeNr;++i) { - xmlXPathObjectPtr xpathResult; - xmlNodePtr node = nsetSubsets->nodeTab[i]; - xmlChar * propValue; - - eq->subsets[i].chance = 1.0f; - propValue = xmlGetProp(node, BAD_CAST "chance"); - if (propValue!=NULL) { - eq->subsets[i].chance = (float)atof((const char *)propValue); - xmlFree(propValue); - } - xpath->node = node; - xpathResult = xmlXPathEvalExpression(BAD_CAST "set", xpath); - if (xpathResult->nodesetval) { - xmlNodeSetPtr nsetSets = xpathResult->nodesetval; - float totalChance = 0.0f; - - if (nsetSets->nodeNr>0) { - int set; - eq->subsets[i].sets = calloc(nsetSets->nodeNr+1, sizeof(subsetitem)); - for (set=0;set!=nsetSets->nodeNr;++set) { - xmlNodePtr nodeSet = nsetSets->nodeTab[set]; - float chance = 1.0f; - - propValue = xmlGetProp(nodeSet, BAD_CAST "chance"); - if (propValue!=NULL) { - chance = (float)atof((const char *)propValue); - xmlFree(propValue); - } - totalChance += chance; - - propValue = xmlGetProp(nodeSet, BAD_CAST "name"); - assert(propValue!=NULL); - eq->subsets[i].sets[set].chance = chance; - eq->subsets[i].sets[set].set = create_equipment((const char*)propValue); - xmlFree(propValue); - } - } - if (totalChance>1.0f) { - log_error(("total chance exceeds 1.0: %f in equipment set %s.\n", - totalChance, eq->name)); - } - } - xmlXPathFreeObject(xpathResult); - } - } - xmlXPathFreeContext(xpath); -} - -static int -parse_equipment(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr xpathRaces; - - /* reading eressea/equipment/set */ - xpathRaces = xmlXPathEvalExpression(BAD_CAST "/eressea/equipment/set", xpath); - if (xpathRaces->nodesetval) { - xmlNodeSetPtr nsetRaces = xpathRaces->nodesetval; - int i; - - for (i=0;i!=nsetRaces->nodeNr;++i) { - xmlNodePtr node = nsetRaces->nodeTab[i]; - xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); - - if (propName!=NULL) { - equipment * eq = create_equipment((const char*)propName); - xmlXPathObjectPtr xpathResult; - - xpath->node = node; - - xpathResult = xmlXPathEvalExpression(BAD_CAST "callback", xpath); - assert(!eq->callback); - add_callbacks(eq, xpathResult->nodesetval); - xmlXPathFreeObject(xpathResult); - - xpathResult = xmlXPathEvalExpression(BAD_CAST "item", xpath); - assert(!eq->items); - add_items(eq, xpathResult->nodesetval); - xmlXPathFreeObject(xpathResult); - - xpathResult = xmlXPathEvalExpression(BAD_CAST "spell", xpath); - assert(!eq->spells); - add_spells(eq, xpathResult->nodesetval); - xmlXPathFreeObject(xpathResult); - - xpathResult = xmlXPathEvalExpression(BAD_CAST "skill", xpath); - add_skills(eq, xpathResult->nodesetval); - xmlXPathFreeObject(xpathResult); - - xpathResult = xmlXPathEvalExpression(BAD_CAST "subset", xpath); - assert(!eq->subsets); - add_subsets(doc, eq, xpathResult->nodesetval); - xmlXPathFreeObject(xpathResult); - - xmlFree(propName); - } - } - } - - xmlXPathFreeObject(xpathRaces); - xmlXPathFreeContext(xpath); - - return 0; -} - -static int -parse_spells(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr spells; - - /* reading eressea/spells/spell */ - spells = xmlXPathEvalExpression(BAD_CAST "/eressea/spells/spell", xpath); - if (spells->nodesetval!=NULL) { - xmlNodeSetPtr nodes = spells->nodesetval; - int i; - - for (i=0;i!=nodes->nodeNr;++i) { - xmlXPathObjectPtr result; - xmlNodePtr node = nodes->nodeTab[i]; - xmlChar * propValue; - int k; - spell * sp = calloc(1, sizeof(spell)); - static int modes[] = { 0, PRECOMBATSPELL, COMBATSPELL, POSTCOMBATSPELL }; - - /* spellname */ - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - sp->sname = strdup((const char*)propValue); - xmlFree(propValue); - - propValue = xmlGetProp(node, BAD_CAST "parameters"); - if (propValue) { - sp->parameter=strdup((const char *)propValue); - xmlFree(propValue); - } - - propValue = xmlGetProp(node, BAD_CAST "syntax"); - if (propValue) { - sp->syntax=strdup((const char *)propValue); - xmlFree(propValue); - } - - /* magic type */ - propValue = xmlGetProp(node, BAD_CAST "type"); - assert(propValue!=NULL); - for (sp->magietyp=0;sp->magietyp!=MAXMAGIETYP;++sp->magietyp) { - if (strcmp(magic_school[sp->magietyp], (const char *)propValue)==0) break; - } - assert(sp->magietyp!=MAXMAGIETYP); - xmlFree(propValue); - - /* level, rank and flags */ - sp->id = xml_ivalue(node, "index", 0); - sp->level = xml_ivalue(node, "level", -1); - sp->rank = (char)xml_ivalue(node, "rank", -1); - if (xml_bvalue(node, "los", false)) sp->sptyp |= TESTCANSEE; /* must see or have contact */ - if (!xml_bvalue(node, "target_global", false)) sp->sptyp |= SEARCHLOCAL; /* must be in same region */ - if (xml_bvalue(node, "ship", false)) sp->sptyp |= ONSHIPCAST; - if (xml_bvalue(node, "ocean", false)) sp->sptyp |= OCEANCASTABLE; - if (xml_bvalue(node, "far", false)) sp->sptyp |= FARCASTING; - if (xml_bvalue(node, "variable", false)) sp->sptyp |= SPELLLEVEL; - k = xml_ivalue(node, "combat", 0); - if (k>=0 && k<=3) sp->sptyp |= modes[k]; - - if (gamecode_enabled) { - /* reading eressea/spells/spell/function */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - - if (result->nodesetval->nodeNr==0) { - /* deprecated style: this spell gets its' function from a callback */ - if (set_spelldata_cb) set_spelldata_cb(sp); - } else { - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - pf_generic fun; - - parse_function(node, &fun, &propValue); - if (fun==NULL) { - log_error(("unknown function name '%s' for spell '%s'\n", - (const char*)propValue, sp->sname)); - xmlFree(propValue); - continue; - } - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "cast")==0) { - sp->sp_function = (spell_f)fun; - } else if (strcmp((const char*)propValue, "fumble")==0) { - sp->patzer = (pspell_f)fun; - } else { - log_error(("unknown function type '%s' for spell %s\n", - (const char*)propValue, sp->sname)); - } - xmlFree(propValue); - } - } - xmlXPathFreeObject(result); - } - - /* reading eressea/spells/spell/resource */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "resource", xpath); - if (result->nodesetval->nodeNr) { - sp->components = malloc(sizeof(spell_component)*(result->nodesetval->nodeNr+1)); - sp->components[result->nodesetval->nodeNr].type = 0; - } - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue); - sp->components[k].type = rt_find((const char *)propValue); - assert(sp->components[k].type); - xmlFree(propValue); - sp->components[k].amount = xml_ivalue(node, "amount", 1); - sp->components[k].cost = SPC_FIX; - propValue = xmlGetProp(node, BAD_CAST "cost"); - if (propValue!=NULL) { - if (strcmp((const char *)propValue, "linear")==0) { - sp->components[k].cost = SPC_LINEAR; - } else if (strcmp((const char *)propValue, "level")==0) { - sp->components[k].cost = SPC_LEVEL; - } - xmlFree(propValue); - } - } - xmlXPathFreeObject(result); - register_spell(sp); - } - } - - xmlXPathFreeObject(spells); - - xmlXPathFreeContext(xpath); - - return 0; -} - -static void -parse_param(struct param ** params, xmlNodePtr node) -{ - xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); - xmlChar * propValue = xmlGetProp(node, BAD_CAST "value"); - - set_param(params, (const char*)propName, (const char*)propValue); - - xmlFree(propName); - xmlFree(propValue); -} - -static void -parse_ai(race * rc, xmlNodePtr node) -{ - rc->splitsize = xml_ivalue(node, "splitsize", 0); - rc->aggression = (float)xml_fvalue(node, "aggression", 0.04); - if (xml_bvalue(node, "killpeasants", false)) rc->flags |= RCF_KILLPEASANTS; - if (xml_bvalue(node, "moverandom", false)) rc->flags |= RCF_MOVERANDOM; - if (xml_bvalue(node, "learn", false)) rc->flags |= RCF_LEARN; -} - -static int -parse_races(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr races; - xmlNodeSetPtr nodes; - int i; - - /* reading eressea/races/race */ - races = xmlXPathEvalExpression(BAD_CAST "/eressea/races/race", xpath); - nodes = races->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr node = nodes->nodeTab[i]; - xmlNodePtr child; - xmlChar * propValue; - race * rc; - xmlXPathObjectPtr result; - int k, study_speed_base; - struct att * attack; - - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - rc = rc_find((const char*)propValue); - if (rc==NULL) rc = rc_add(rc_new((const char*)propValue)); - xmlFree(propValue); - - propValue = xmlGetProp(node, BAD_CAST "damage"); - assert(propValue!=NULL); - rc->def_damage = strdup((const char*)propValue); - xmlFree(propValue); - - rc->magres = (float)xml_fvalue(node, "magres", 0.0); - rc->maxaura = (float)xml_fvalue(node, "maxaura", 0.0); - rc->regaura = (float)xml_fvalue(node, "regaura", 1.0); - rc->recruitcost = xml_ivalue(node, "recruitcost", 0); - rc->maintenance = xml_ivalue(node, "maintenance", 0); - rc->weight = xml_ivalue(node, "weight", PERSON_WEIGHT); - rc->capacity = xml_ivalue(node, "capacity", 540); - rc->speed = (float)xml_fvalue(node, "speed", 1.0F); - rc->hitpoints = xml_ivalue(node, "hp", 0); - rc->armor = (char)xml_ivalue(node, "ac", 0); - study_speed_base = xml_ivalue(node, "studyspeed", 0); - - rc->at_default = (char)xml_ivalue(node, "unarmedattack", -2); - rc->df_default = (char)xml_ivalue(node, "unarmeddefense", -2); - rc->at_bonus = (char)xml_ivalue(node, "attackmodifier", 0); - rc->df_bonus = (char)xml_ivalue(node, "defensemodifier", 0); - - if (xml_bvalue(node, "playerrace", false)) rc->flags |= RCF_PLAYERRACE; - if (xml_bvalue(node, "scarepeasants", false)) rc->flags |= RCF_SCAREPEASANTS; - if (xml_bvalue(node, "cansteal", true)) rc->flags |= RCF_CANSTEAL; - if (xml_bvalue(node, "cansail", true)) rc->flags |= RCF_CANSAIL; - if (xml_bvalue(node, "cannotmove", false)) rc->flags |= RCF_CANNOTMOVE; - if (xml_bvalue(node, "fly", false)) rc->flags |= RCF_FLY; - if (xml_bvalue(node, "invisible", false)) rc->flags |= RCF_INVISIBLE; - if (xml_bvalue(node, "coastal", false)) rc->flags |= RCF_COASTAL; - if (xml_bvalue(node, "unarmedguard", false)) rc->flags |= RCF_UNARMEDGUARD; - if (xml_bvalue(node, "swim", false)) rc->flags |= RCF_SWIM; - if (xml_bvalue(node, "walk", false)) rc->flags |= RCF_WALK; - if (!xml_bvalue(node, "canlearn", true)) rc->flags |= RCF_NOLEARN; - if (!xml_bvalue(node, "canteach", true)) rc->flags |= RCF_NOTEACH; - if (xml_bvalue(node, "horse", false)) rc->flags |= RCF_HORSE; - if (xml_bvalue(node, "desert", false)) rc->flags |= RCF_DESERT; - if (xml_bvalue(node, "absorbpeasants", false)) rc->flags |= RCF_ABSORBPEASANTS; - if (xml_bvalue(node, "noheal", false)) rc->flags |= RCF_NOHEAL; - if (xml_bvalue(node, "noweapons", false)) rc->flags |= RCF_NOWEAPONS; - if (xml_bvalue(node, "shapeshift", false)) rc->flags |= RCF_SHAPESHIFT; - if (xml_bvalue(node, "shapeshiftany", false)) rc->flags |= RCF_SHAPESHIFTANY; - if (xml_bvalue(node, "illusionary", false)) rc->flags |= RCF_ILLUSIONARY; - if (xml_bvalue(node, "undead", false)) rc->flags |= RCF_UNDEAD; - if (xml_bvalue(node, "dragon", false)) rc->flags |= RCF_DRAGON; - if (xml_bvalue(node, "shipspeed", false)) rc->flags |= RCF_SHIPSPEED; - if (xml_bvalue(node, "stonegolem", false)) rc->flags |= RCF_STONEGOLEM; - if (xml_bvalue(node, "irongolem", false)) rc->flags |= RCF_IRONGOLEM; - - if (xml_bvalue(node, "giveitem", false)) rc->ec_flags |= GIVEITEM; - if (xml_bvalue(node, "giveperson", false)) rc->ec_flags |= GIVEPERSON; - if (xml_bvalue(node, "giveunit", false)) rc->ec_flags |= GIVEUNIT; - if (xml_bvalue(node, "getitem", false)) rc->ec_flags |= GETITEM; - if (xml_bvalue(node, "recruithorses", false)) rc->ec_flags |= ECF_REC_HORSES; - if (xml_bvalue(node, "recruitethereal", false)) rc->ec_flags |= ECF_REC_ETHEREAL; - if (xml_bvalue(node, "recruitunlimited", false)) rc->ec_flags |= ECF_REC_UNLIMITED; - - if (xml_bvalue(node, "equipment", false)) rc->battle_flags |= BF_EQUIPMENT; - if (xml_bvalue(node, "noblock", false)) rc->battle_flags |= BF_NOBLOCK; - if (xml_bvalue(node, "invinciblenonmagic", false)) rc->battle_flags |= BF_INV_NONMAGIC; - if (xml_bvalue(node, "resistbash", false)) rc->battle_flags |= BF_RES_BASH; - if (xml_bvalue(node, "resistcut", false)) rc->battle_flags |= BF_RES_CUT; - if (xml_bvalue(node, "resistpierce", false)) rc->battle_flags |= BF_RES_PIERCE; - if (xml_bvalue(node, "canattack", true)) rc->battle_flags |= BF_CANATTACK; - - for (child=node->children;child;child=child->next) { - if (strcmp((const char *)child->name, "ai")==0) { - parse_ai(rc, child); - } else if (strcmp((const char *)child->name, "param")==0) { - parse_param(&rc->parameters, child); - } - } - rc->recruit_multi = get_param_flt(rc->parameters, "recruit_multi", 1.0); - - /* reading eressea/races/race/skill */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "skill", xpath); - memset(rc->bonus, 0, sizeof(rc->bonus)); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - int mod = xml_ivalue(node, "modifier", 0); - int speed = xml_ivalue(node, "speed", study_speed_base); - skill_t sk; - - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - sk = sk_find((const char*)propValue); - if (sk!=NOSKILL) { - rc->bonus[sk] = (char)mod; - if (speed) { - if (!rc->study_speed) rc->study_speed = calloc(1, MAXSKILLS); - rc->study_speed[sk] = (char)speed; - } - } else { - log_error(("unknown skill '%s' in race '%s'\n", - (const char*)propValue, rc->_name[0])); - } - xmlFree(propValue); - } - xmlXPathFreeObject(result); - - if (gamecode_enabled) { - /* reading eressea/races/race/function */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - pf_generic fun; - - parse_function(node, &fun, &propValue); - if (fun==NULL) { - log_error(("unknown function name '%s' for race %s\n", - (const char*)propValue, rc->_name[0])); - xmlFree(propValue); - continue; - } - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "name")==0) { - rc->generate_name = (const char * (*)(const struct unit*))fun; - } else if (strcmp((const char*)propValue, "describe")==0) { - rc->describe = (const char * (*)(const struct unit*, const struct locale *))fun; - } else if (strcmp((const char*)propValue, "age")==0) { - rc->age = (void(*)(struct unit*))fun; - } else if (strcmp((const char*)propValue, "move")==0) { - rc->move_allowed = (boolean(*)(const struct region *, const struct region *))fun; - } else if (strcmp((const char*)propValue, "itemdrop")==0) { - rc->itemdrop = (struct item *(*)(const struct race *, int))fun; - } else if (strcmp((const char*)propValue, "initfamiliar")==0) { - rc->init_familiar = (void(*)(struct unit *))fun; - } else { - log_error(("unknown function type '%s' for race %s\n", - (const char*)propValue, rc->_name[0])); - } - xmlFree(propValue); - } - xmlXPathFreeObject(result); - } - - /* reading eressea/races/race/familiar */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "familiar", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - race * frc; - - propValue = xmlGetProp(node, BAD_CAST "race"); - assert(propValue!=NULL); - frc = rc_find((const char *)propValue); - if (frc == NULL) { -// log_error(("%s not registered, is familiar for %s\n", -// (const char*)propValue, rc->_name[0])); -// assert(frc!=NULL); - frc = rc_add(rc_new((const char*)propValue)); - } - if (xml_bvalue(node, "default", false)) { - rc->familiars[k] = rc->familiars[0]; - rc->familiars[0] = frc; - } else { - rc->familiars[k] = frc; - } - xmlFree(propValue); - } - xmlXPathFreeObject(result); - - /* reading eressea/races/race/precombatspell */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "precombatspell", xpath); - assert(rc->precombatspell==NULL || !"precombatspell is already initialized"); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - rc->precombatspell = xml_spell(node, "spell"); - } - xmlXPathFreeObject(result); - - /* reading eressea/races/race/attack */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "attack", xpath); - attack = rc->attack; - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - while (attack->type!=AT_NONE) ++attack; - - propValue = xmlGetProp(node, BAD_CAST "damage"); - if (propValue!=NULL) { - attack->data.dice = strdup((const char*)propValue); - xmlFree(propValue); - } else { - attack->data.sp = xml_spell(node, "spell"); - } - attack->type = xml_ivalue(node, "type", 0); - attack->flags = xml_ivalue(node, "flags", 0); - } - xmlXPathFreeObject(result); - } - xmlXPathFreeObject(races); - - xmlXPathFreeContext(xpath); - - race_compat(); - return 0; -} - -static int -parse_terrains(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath; - xmlXPathObjectPtr terrains; - xmlNodeSetPtr nodes; - int i; - - xpath = xmlXPathNewContext(doc); - - /* reading eressea/terrains/terrain */ - terrains = xmlXPathEvalExpression(BAD_CAST "/eressea/terrains/terrain", xpath); - nodes = terrains->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr node = nodes->nodeTab[i]; - terrain_type * terrain = calloc(1, sizeof(terrain_type)); - xmlChar * propValue; - xmlXPathObjectPtr xpathChildren; - xmlNodeSetPtr children; - - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - terrain->_name = strdup((const char *)propValue); - xmlFree(propValue); - - terrain->max_road = (short)xml_ivalue(node, "road", 0); - assert(terrain->max_road>=0); - terrain->size = xml_ivalue(node, "size", 0); - - if (xml_bvalue(node, "forbidden", false)) terrain->flags |= FORBIDDEN_REGION; - else { - if (xml_bvalue(node, "fly", true)) terrain->flags |= FLY_INTO; - if (xml_bvalue(node, "sail", true)) terrain->flags |= SAIL_INTO; - if (xml_bvalue(node, "walk", true)) terrain->flags |= WALK_INTO; - if (xml_bvalue(node, "swim", false)) terrain->flags |= SWIM_INTO; - if (xml_bvalue(node, "shallow", true)) terrain->flags |= LARGE_SHIPS; - if (xml_bvalue(node, "cavalry", false)) terrain->flags |= CAVALRY_REGION; - } - if (xml_bvalue(node, "sea", false)) terrain->flags |= SEA_REGION; - if (xml_bvalue(node, "arctic", false)) terrain->flags |= ARCTIC_REGION; - if (xml_bvalue(node, "land", true)) terrain->flags |= LAND_REGION; - if (xml_bvalue(node, "forest", false)) terrain->flags |= FOREST_REGION; - - terrain->distribution = (short)xml_ivalue(node, "seed", 0); - - xpath->node = node; - xpathChildren = xmlXPathEvalExpression(BAD_CAST "herb", xpath); - children = xpathChildren->nodesetval; - if (children->nodeNr>0) { - int k; - - terrain->herbs = malloc((children->nodeNr+1) * sizeof(item_type*)); - terrain->herbs[children->nodeNr] = NULL; - for (k=0;k!=children->nodeNr;++k) { - xmlNodePtr nodeHerb = children->nodeTab[k]; - const struct resource_type * rtype; - - propValue = xmlGetProp(nodeHerb, BAD_CAST "name"); - assert(propValue!=NULL); - rtype = rt_find((const char*)propValue); - assert(rtype!=NULL && rtype->itype!=NULL && fval(rtype->itype, ITF_HERB)); - terrain->herbs[k] = rtype->itype; - xmlFree(propValue); - } - } - xmlXPathFreeObject(xpathChildren); - - xpath->node = node; - xpathChildren = xmlXPathEvalExpression(BAD_CAST "resource", xpath); - children = xpathChildren->nodesetval; - if (children->nodeNr>0) { - int k; - - terrain->production = malloc((children->nodeNr+1) * sizeof(terrain_production)); - terrain->production[children->nodeNr].type = NULL; - for (k=0;k!=children->nodeNr;++k) { - xmlNodePtr nodeProd = children->nodeTab[k]; - - propValue = xmlGetProp(nodeProd, BAD_CAST "name"); - assert(propValue!=NULL); - terrain->production[k].type = rt_find((const char*)propValue); - assert(terrain->production[k].type); - xmlFree(propValue); - - propValue = xmlGetProp(nodeProd, BAD_CAST "level"); - assert(propValue); - terrain->production[k].startlevel = strdup((const char *)propValue); - xmlFree(propValue); - - propValue = xmlGetProp(nodeProd, BAD_CAST "base"); - assert(propValue); - terrain->production[k].base = strdup((const char *)propValue); - xmlFree(propValue); - - propValue = xmlGetProp(nodeProd, BAD_CAST "div"); - assert(propValue); - terrain->production[k].divisor = strdup((const char *)propValue); - xmlFree(propValue); - - terrain->production[k].chance = (float)xml_fvalue(nodeProd, "chance", 1.0); - } - } - xmlXPathFreeObject(xpathChildren); - - register_terrain(terrain); - } - xmlXPathFreeObject(terrains); - - xmlXPathFreeContext(xpath); - - init_terrains(); - return 0; -} - -static int -parse_messages(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath; - xmlXPathObjectPtr messages; - xmlNodeSetPtr nodes; - int i; - - if (!gamecode_enabled) return 0; - - xpath = xmlXPathNewContext(doc); - - /* reading eressea/messages/message */ - messages = xmlXPathEvalExpression(BAD_CAST "/eressea/messages/message", xpath); - nodes = messages->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr node = nodes->nodeTab[i]; - const char * default_section = "events"; - xmlChar * propSection; - xmlChar * propValue; - xmlXPathObjectPtr result; - int k; - char ** argv = NULL; - const message_type * mtype; - - /* arguments */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "type/arg", xpath); - if (result->nodesetval && result->nodesetval->nodeNr>0) { - argv = malloc(sizeof(char*)*(result->nodesetval->nodeNr+1)); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - char zBuffer[128]; - xmlChar * propName, * propType; - - propName = xmlGetProp(node, BAD_CAST "name"); - propType = xmlGetProp(node, BAD_CAST "type"); - sprintf(zBuffer, "%s:%s", (const char*)propName, (const char*)propType); - xmlFree(propName); - xmlFree(propType); - argv[k] = strdup(zBuffer); - } - argv[result->nodesetval->nodeNr] = NULL; - } - xmlXPathFreeObject(result); - - /* add the messagetype */ - propValue = xmlGetProp(node, BAD_CAST "name"); - mtype = mt_find((const char *)propValue); - if (mtype==NULL) { - mtype = mt_register(mt_new((const char *)propValue, (const char**)argv)); - } else { - assert(argv!=NULL || !"cannot redefine arguments of message now"); - } - xmlFree(propValue); - - /* register the type for the CR */ - crt_register(mtype); - - /* let's clean up the mess */ - if (argv!=NULL) { - for (k=0;argv[k]!=NULL;++k) free(argv[k]); - free(argv); - } - - propSection = xmlGetProp(node, BAD_CAST "section"); - if (propSection==NULL) propSection = BAD_CAST default_section; - - /* strings */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "text", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - struct locale * lang; - xmlChar * propText; - - xml_readtext(node, &lang, &propText); - if (lang) { - xml_cleanup_string(propText); - nrt_register(mtype, lang, (const char *)propText, 0, (const char*)propSection); - } - xmlFree(propText); - - } - xmlXPathFreeObject(result); - - if (propSection != BAD_CAST default_section) xmlFree(propSection); - } - - xmlXPathFreeObject(messages); - - xmlXPathFreeContext(xpath); - return 0; -} - -static void -xml_readstrings(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, boolean names) -{ - int i; - - for (i=0;i!=nodeNr;++i) { - xmlNodePtr stringNode = nodeTab[i]; - xmlChar * propName = xmlGetProp(stringNode, BAD_CAST "name"); - xmlChar * propNamespace = NULL; - xmlXPathObjectPtr result; - int k; - char zName[128]; - - assert(propName!=NULL); - if (names) propNamespace = xmlGetProp(stringNode->parent, BAD_CAST "name"); - mkname_buf((const char*)propNamespace, (const char*)propName, zName); - if (propNamespace!=NULL) xmlFree(propNamespace); - xmlFree(propName); - - /* strings */ - xpath->node = stringNode; - result = xmlXPathEvalExpression(BAD_CAST "text", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr textNode = result->nodesetval->nodeTab[k]; - struct locale * lang; - xmlChar * propText; - - xml_readtext(textNode, &lang, &propText); - if (propText!=NULL) { - assert(strcmp(zName, (const char*)xml_cleanup_string(BAD_CAST zName))==0); - if (lang) { - xml_cleanup_string(propText); - locale_setstring(lang, zName, (const char *)propText); - } - xmlFree(propText); - } else { - log_warning(("string %s has no text in locale %s\n", - zName, locale_name(lang))); - } - } - xmlXPathFreeObject(result); - } -} - -static int -parse_strings(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr strings; - - /* reading eressea/strings/string */ - strings = xmlXPathEvalExpression(BAD_CAST "/eressea/strings/string", xpath); - xml_readstrings(xpath, strings->nodesetval->nodeTab, strings->nodesetval->nodeNr, false); - xmlXPathFreeObject(strings); - - strings = xmlXPathEvalExpression(BAD_CAST "/eressea/strings/namespace/string", xpath); - xml_readstrings(xpath, strings->nodesetval->nodeTab, strings->nodesetval->nodeNr, true); - xmlXPathFreeObject(strings); - - xmlXPathFreeContext(xpath); - return 0; -} - -static void -xml_readprefixes(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, boolean names) -{ - int i; - - for (i=0;i!=nodeNr;++i) { - xmlNodePtr node = nodeTab[i]; - xmlChar * propText = xmlNodeListGetString(node->doc, node->children, 1); - - if (propText!=NULL) { - add_raceprefix((const char*)propText); - xmlFree(propText); - } - } -} - -static int -parse_prefixes(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr strings; - - /* reading eressea/strings/string */ - strings = xmlXPathEvalExpression(BAD_CAST "/eressea/prefixes/prefix", xpath); - xml_readprefixes(xpath, strings->nodesetval->nodeTab, strings->nodesetval->nodeNr, false); - xmlXPathFreeObject(strings); - - xmlXPathFreeContext(xpath); - return 0; -} - -static int -parse_main(xmlDocPtr doc) -{ - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr result = xmlXPathEvalExpression(BAD_CAST "/eressea/game", xpath); - xmlNodeSetPtr nodes = result->nodesetval; - int i; - - xmlChar * propValue; - if (nodes->nodeNr>0) { - xmlNodePtr node = nodes->nodeTab[0]; - - global.producexpchance = (float)xml_fvalue(node, "learningbydoing", 1.0/3); - - propValue = xmlGetProp(node, BAD_CAST "name"); - if (propValue!=NULL) { - global.gamename = strdup((const char*)propValue); - xmlFree(propValue); - } - - xmlXPathFreeObject(result); - - /* reading eressea/game/param */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "param", xpath); - nodes = result->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr node = nodes->nodeTab[i]; - parse_param(&global.parameters, node); - } - - xmlXPathFreeObject(result); - - /* reading eressea/game/order */ - result = xmlXPathEvalExpression(BAD_CAST "order", xpath); - nodes = result->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr node = nodes->nodeTab[i]; - xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); - boolean disable = xml_bvalue(node, "disable", false); - - if (disable) { - int k; - for (k=0;k!=MAXKEYWORDS;++k) { - if (strcmp(keywords[k], (const char*)propName)==0) { - global.disabled[k]=1; - break; - } - } - if (k==MAXKEYWORDS) { - log_error(("trying to disable unknown comand %s\n", (const char*)propName)); - } - } - xmlFree(propName); - } - - xmlXPathFreeObject(result); - - /* reading eressea/game/skill */ - result = xmlXPathEvalExpression(BAD_CAST "skill", xpath); - nodes = result->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { - xmlNodePtr node = nodes->nodeTab[i]; - xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); - boolean enable = xml_bvalue(node, "enable", true); - enable_skill((const char*)propName, enable); - xmlFree(propName); - } - } - xmlXPathFreeObject(result); - - xmlXPathFreeContext(xpath); - return 0; -} - -void -register_xmlreader(void) -{ - xml_register_callback(parse_main); - - xml_register_callback(parse_strings); - xml_register_callback(parse_prefixes); - xml_register_callback(parse_messages); - xml_register_callback(parse_resources); - xml_register_callback(parse_rules); - - xml_register_callback(parse_terrains); /* requires resources */ - xml_register_callback(parse_buildings); /* requires resources */ - xml_register_callback(parse_ships); /* requires terrains */ - xml_register_callback(parse_spells); /* requires resources */ - xml_register_callback(parse_equipment); /* requires spells */ - xml_register_callback(parse_races); /* requires spells */ - xml_register_callback(parse_calendar); - xml_register_callback(parse_directions); -} +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2004 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "xmlreader.h" + +/* kernel includes */ +#include "building.h" +#include "equipment.h" +#include "item.h" +#include "message.h" +#include "race.h" +#include "region.h" +#include "resources.h" +#include "ship.h" +#include "terrain.h" +#include "skill.h" +#include "spell.h" +#include "calendar.h" + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include + + +/* libxml includes */ +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +static boolean gamecode_enabled = false; + +void (*set_spelldata_cb)(struct spell * sp) = 0; +static building_type * bt_get_or_create(const char * name) +{ + if (name!=NULL) { + building_type * btype = bt_find(name); + if (btype==NULL) { + btype = calloc(sizeof(building_type), 1); + btype->_name = strdup(name); + bt_register(btype); + } + return btype; + } + return NULL; +} + +void +enable_xml_gamecode(void) +{ + gamecode_enabled = true; +} + +static void +xml_readtext(xmlNodePtr node, struct locale ** lang, xmlChar **text) +{ + xmlChar * propValue = xmlGetProp(node, BAD_CAST "locale"); + assert(propValue!=NULL); + *lang = find_locale((const char*)propValue); +#ifdef MAKE_LOCALES + if (*lang==NULL) *lang = make_locale((const char*)propValue); +#endif + xmlFree(propValue); + + *text = xmlNodeListGetString(node->doc, node->children, 1); +} + +static const spell * +xml_spell(xmlNode * node, const char * name) +{ + const spell * sp = NULL; + xmlChar * propValue = xmlGetProp(node, BAD_CAST name); + if (propValue!=NULL) { + sp = find_spell(M_NONE, (const char *)propValue); + assert(sp); + xmlFree(propValue); + } + return sp; +} + +static xmlChar * +xml_cleanup_string(xmlChar * str) +{ + xmlChar * read = str; + xmlChar * write = str; + + while (*read) { + /* eat leading whitespace */ + if (*read && isxspace(*read)) { + while (*read && isxspace(*read)) { + ++read; + } + *write++ = ' '; + } + while (*read) { + if (*read== '\n') break; + if (*read== '\r') break; + *write++ = *read++; + } + } + *write = 0; + return str; +} + +static const resource_type * +rt_findorcreate(const char * name) +{ + resource_type * rtype = rt_find(name); + if (rtype==NULL) { + const char * names[2]; + char * namep = strcat(strcpy((char*)malloc(strlen(name)+3), name), "_p"); + /* we'll make a placeholder */ + names[0] = name; + names[1] = namep; + rtype = new_resourcetype(names, NULL, RTF_NONE); + free(namep); + } + return rtype; +} + +static void +xml_readrequirements(xmlNodePtr * nodeTab, int nodeNr, requirement ** reqArray) +{ + int req; + requirement * radd = *reqArray; + + assert (radd==NULL); + if (nodeNr==0) return; + + radd = *reqArray = calloc(sizeof(requirement), nodeNr+1); + + for (req=0;req!=nodeNr;++req) { + xmlNodePtr node = nodeTab[req]; + xmlChar * propValue; + + radd->number = xml_ivalue(node, "quantity", 1); + radd->recycle = xml_fvalue(node, "recycle", 0.5); + + propValue = xmlGetProp(node, BAD_CAST "type"); + radd->rtype = rt_findorcreate((const char*)propValue); + xmlFree(propValue); + + ++radd; + } +} + +void +xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, construction ** consPtr) +{ + xmlNodePtr pushNode = xpath->node; + int k; + for (k=0;k!=nodeSet->nodeNr;++k) { + xmlNodePtr node = nodeSet->nodeTab[k]; + xmlChar * propValue; + construction * con; + xmlXPathObjectPtr req; + int m; + skill_t sk = NOSKILL; + + propValue = xmlGetProp(node, BAD_CAST "skill"); + if (propValue!=NULL) { + sk = sk_find((const char*)propValue); + if (sk==NOSKILL) { + log_error(("construction requires skill '%s' that does not exist.\n", (const char *)propValue)); + xmlFree(propValue); + continue; + } + xmlFree(propValue); + } + + assert(*consPtr==NULL); + + *consPtr = con = calloc(sizeof(construction), 1); + consPtr = &con->improvement; + + con->skill = sk; + con->maxsize = xml_ivalue(node, "maxsize", -1); + con->minskill = xml_ivalue(node, "minskill", -1); + con->reqsize = xml_ivalue(node, "reqsize", -1); + + propValue = xmlGetProp(node, BAD_CAST "building"); + if (propValue!=NULL) { + con->btype = bt_get_or_create((const char*)propValue); + xmlFree(propValue); + } + + /* read construction/requirement */ + xpath->node = node; + req = xmlXPathEvalExpression(BAD_CAST "requirement", xpath); + xml_readrequirements(req->nodesetval->nodeTab, + req->nodesetval->nodeNr, &con->materials); + xmlXPathFreeObject(req); + + /* read construction/modifier */ + xpath->node = node; + req = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); + for (m=0;m!=req->nodesetval->nodeNr;++m) { + xmlNodePtr node = req->nodesetval->nodeTab[m]; + + propValue = xmlGetProp(node, BAD_CAST "function"); + if (propValue!=NULL) { + pf_generic foo = get_function((const char*)propValue); + a_add(&con->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION, (skillmod_fun)foo, 1.0, 0)); + xmlFree(propValue); + } + + } + xmlXPathFreeObject(req); + } + xpath->node = pushNode; +} + +static int +parse_function(xmlNodePtr node, pf_generic * funPtr, xmlChar ** namePtr) +{ + pf_generic fun; + xmlChar * propValue = xmlGetProp(node, BAD_CAST "value"); + assert(propValue!=NULL); + fun = get_function((const char*)propValue); + if (fun!=NULL) { + xmlFree(propValue); + + propValue = xmlGetProp(node, BAD_CAST "name"); + } + *namePtr = propValue; + *funPtr = fun; + return 0; +} + +static int +parse_buildings(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr buildings; + int i; + + /* reading eressea/buildings/building */ + buildings = xmlXPathEvalExpression(BAD_CAST "/eressea/buildings/building", xpath); + if (buildings->nodesetval!=NULL) { + xmlNodeSetPtr nodes = buildings->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + xmlChar * propValue; + building_type * btype; + xmlXPathObjectPtr result; + int k; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + btype = bt_get_or_create((const char*)propValue); + xmlFree(propValue); + + btype->capacity = xml_ivalue(node, "capacity", -1); + btype->maxcapacity = xml_ivalue(node, "maxcapacity", -1); + btype->maxsize = xml_ivalue(node, "maxsize", -1); + + btype->magres = xml_ivalue(node, "magres", 0); + btype->magresbonus = xml_ivalue(node, "magresbonus", 0); + btype->fumblebonus = xml_ivalue(node, "fumblebonus", 0); + btype->auraregen = xml_fvalue(node, "auraregen", 1.0); + + if (xml_bvalue(node, "nodestroy", false)) btype->flags |= BTF_INDESTRUCTIBLE; + if (xml_bvalue(node, "oneperturn", false)) btype->flags |= BTF_ONEPERTURN; + if (xml_bvalue(node, "nobuild", false)) btype->flags |= BTF_NOBUILD; + if (xml_bvalue(node, "namechange", true)) btype->flags |= BTF_NAMECHANGE; + if (xml_bvalue(node, "unique", false)) btype->flags |= BTF_UNIQUE; + if (xml_bvalue(node, "decay", false)) btype->flags |= BTF_DECAY; + if (xml_bvalue(node, "magic", false)) btype->flags |= BTF_MAGIC; + + /* reading eressea/buildings/building/construction */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); + xml_readconstruction(xpath, result->nodesetval, &btype->construction); + xmlXPathFreeObject(result); + + if (gamecode_enabled) { + /* reading eressea/buildings/building/function */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "function", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + pf_generic fun; + parse_function(node, &fun, &propValue); + + if (fun==NULL) { + log_error(("unknown function name '%s' for building %s\n", + (const char*)propValue, btype->_name)); + xmlFree(propValue); + continue; + } + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "name")==0) { + btype->name = (const char * (*)(const struct building_type*, const struct building *, int))fun; + } else if (strcmp((const char*)propValue, "init")==0) { + btype->init = (void (*)(struct building_type*))fun; + } else if (strcmp((const char*)propValue, "age")==0) { + btype->age = (void (*)(struct building*))fun; + } else if (strcmp((const char*)propValue, "protection")==0) { + btype->protection = (int (*)(struct building*, struct unit *))fun; + } else if (strcmp((const char*)propValue, "taxes")==0) { + btype->taxes = (double (*)(const struct building*, int))fun; + } else if (strcmp((const char*)propValue, "age")==0) { + btype->age = (void (*)(struct building*))fun; + } else { + log_error(("unknown function type '%s' for building %s\n", + (const char*)propValue, btype->_name)); + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + } + + /* reading eressea/buildings/building/maintenance */ + result = xmlXPathEvalExpression(BAD_CAST "maintenance", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + maintenance * mt; + + if (btype->maintenance==NULL) { + btype->maintenance = calloc(sizeof(struct maintenance), result->nodesetval->nodeNr+1); + } + mt = btype->maintenance + k; + mt->number = xml_ivalue(node, "amount", 0); + + propValue = xmlGetProp(node, BAD_CAST "type"); + assert(propValue!=NULL); + mt->rtype = rt_find((const char*)propValue); + assert(mt->rtype!=NULL); + xmlFree(propValue); + + if (xml_bvalue(node, "variable", false)) mt->flags |= MTF_VARIABLE; + if (xml_bvalue(node, "vital", false)) mt->flags |= MTF_VITAL; + + } + xmlXPathFreeObject(result); + + /* finally, initialize the new building type */ + if (btype->init) btype->init(btype); + } + } + xmlXPathFreeObject(buildings); + + xmlXPathFreeContext(xpath); + return 0; +} + +static int +parse_calendar(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr xpathCalendars; + xmlNodeSetPtr nsetCalendars; + int c, rv = 0; + + /* reading eressea/buildings/building */ + xpathCalendars = xmlXPathEvalExpression(BAD_CAST "/eressea/calendar", xpath); + nsetCalendars = xpathCalendars->nodesetval; + months_per_year = 0; + if (nsetCalendars==NULL || nsetCalendars->nodeNr==0) { + rv = -1; + } else for (c=0;c!=nsetCalendars->nodeNr;++c) { + xmlNodePtr calendar = nsetCalendars->nodeTab[c]; + xmlXPathObjectPtr xpathWeeks, xpathMonths, xpathSeasons; + xmlNodeSetPtr nsetWeeks, nsetMonths, nsetSeasons; + xmlChar * propValue = xmlGetProp(calendar, BAD_CAST "name"); + xmlChar * newyear = xmlGetProp(calendar, BAD_CAST "newyear"); + + first_turn = xml_ivalue(calendar, "start", first_turn); + if (propValue) { + free(agename); + agename = strdup(mkname("calendar", (const char*)propValue)); + xmlFree(propValue); + } + + xpath->node = calendar; + xpathWeeks = xmlXPathEvalExpression(BAD_CAST "week", xpath); + nsetWeeks = xpathWeeks->nodesetval; + if (nsetWeeks!=NULL && nsetWeeks->nodeNr) { + int i; + + weeks_per_month = nsetWeeks->nodeNr; + assert(!weeknames); + weeknames = malloc(sizeof(char *) * weeks_per_month); + weeknames2 = malloc(sizeof(char *) * weeks_per_month); + for (i=0;i!=nsetWeeks->nodeNr;++i) { + xmlNodePtr week = nsetWeeks->nodeTab[i]; + xmlChar * propValue = xmlGetProp(week, BAD_CAST "name"); + if (propValue) { + weeknames[i] = strdup(mkname("calendar", (const char*)propValue)); + weeknames2[i] = malloc(strlen(weeknames[i])+3); + sprintf(weeknames2[i], "%s_d", weeknames[i]); + xmlFree(propValue); + } + } + } + xmlXPathFreeObject(xpathWeeks); + + xpathSeasons = xmlXPathEvalExpression(BAD_CAST "season", xpath); + nsetSeasons = xpathSeasons->nodesetval; + if (nsetSeasons!=NULL && nsetSeasons->nodeNr) { + int i; + + seasons = nsetSeasons->nodeNr; + assert(!seasonnames); + seasonnames = malloc(sizeof(char *) * seasons); + + for (i=0;i!=nsetSeasons->nodeNr;++i) { + xmlNodePtr season = nsetSeasons->nodeTab[i]; + xmlChar * propValue = xmlGetProp(season, BAD_CAST "name"); + if (propValue) { + seasonnames[i] = strdup(mkname("calendar", (const char*)propValue)); + xmlFree(propValue); + } + } + } + + xpathMonths = xmlXPathEvalExpression(BAD_CAST "season/month", xpath); + nsetMonths = xpathMonths->nodesetval; + if (nsetMonths!=NULL && nsetMonths->nodeNr) { + int i; + + months_per_year = nsetMonths->nodeNr; + assert(!monthnames); + monthnames = malloc(sizeof(char *) * months_per_year); + month_season = malloc(sizeof(int) * months_per_year); + storms = malloc(sizeof(int) * months_per_year); + + for (i=0;i!=nsetMonths->nodeNr;++i) { + xmlNodePtr month = nsetMonths->nodeTab[i]; + xmlChar * propValue = xmlGetProp(month, BAD_CAST "name"); + int j; + + if (propValue) { + if (newyear && strcmp((const char*)newyear, (const char*)propValue)==0) { + first_month = i; + xmlFree(newyear); + newyear = NULL; + } + monthnames[i] = strdup(mkname("calendar", (const char*)propValue)); + xmlFree(propValue); + } + for (j=0;j!=seasons;++j) { + xmlNodePtr season = month->parent; + if (season==nsetSeasons->nodeTab[j]) { + month_season[i] = j; + break; + } + } + assert(j!=seasons); + storms[i] = xml_ivalue(nsetMonths->nodeTab[i], "storm", 0); + } + } + xmlXPathFreeObject(xpathMonths); + xmlXPathFreeObject(xpathSeasons); + } + xmlXPathFreeObject(xpathCalendars); + xmlXPathFreeContext(xpath); + + return rv; +} + +static int +parse_directions(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr xpathDirections; + xmlNodeSetPtr nsetDirections; + int rv = 0; + + /* reading eressea/directions/dir */ + xpathDirections = xmlXPathEvalExpression(BAD_CAST "/eressea/directions/dir", xpath); + nsetDirections = xpathDirections->nodesetval; + if (nsetDirections!=NULL) { + int k; + for (k=0;k!=nsetDirections->nodeNr;++k) { + xmlNodePtr dir = nsetDirections->nodeTab[k]; + xmlChar * propValue = xmlGetProp(dir, BAD_CAST "name"); + + register_special_direction((const char *)propValue); + xmlFree(propValue); + } + } + xmlXPathFreeObject(xpathDirections); + xmlXPathFreeContext(xpath); + + return rv; +} + +static int +parse_ships(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr ships; + int i; + + /* reading eressea/ships/ship */ + ships = xmlXPathEvalExpression(BAD_CAST "/eressea/ships/ship", xpath); + if (ships->nodesetval!=NULL) { + xmlNodeSetPtr nodes = ships->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr child, node = nodes->nodeTab[i]; + xmlChar * propValue; + ship_type * st = calloc(sizeof(ship_type), 1); + xmlXPathObjectPtr result; + int k, c; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + st->name[0] = strdup((const char *)propValue); + st->name[1] = strcat(strcpy(malloc(strlen(st->name[0])+3), st->name[0]),"_a"); + xmlFree(propValue); + + st->cabins = xml_ivalue(node, "cabins", 0) * PERSON_WEIGHT; + st->cargo = xml_ivalue(node, "cargo", 0); + st->combat = xml_ivalue(node, "combat", 0); + st->cptskill = xml_ivalue(node, "cptskill", 0); + st->damage = xml_fvalue(node, "damage", 0.0); + if (xml_bvalue(node, "nocoast", false)) st->flags |= SFL_NOCOAST; + if (xml_bvalue(node, "fly", false)) st->flags |= SFL_FLY; + if (xml_bvalue(node, "opensea", false)) st->flags |= SFL_OPENSEA; + st->fishing = xml_ivalue(node, "fishing", 0); + st->minskill = xml_ivalue(node, "minskill", 0); + st->range = xml_ivalue(node, "range", 0); + st->storm = xml_fvalue(node, "storm", 1.0); + st->sumskill = xml_ivalue(node, "sumskill", 0); + + /* reading eressea/ships/ship/construction */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); + xml_readconstruction(xpath, result->nodesetval, &st->construction); + xmlXPathFreeObject(result); + + for (child=node->children;child;child=child->next) { + if (strcmp((const char *)child->name, "modifier")==0) { + double value = xml_fvalue(child, "value", 0.0); + propValue = xmlGetProp(child, BAD_CAST "type"); + if (strcmp((const char *)propValue, "tactics")==0) st->tac_bonus = (float)value; + else if (strcmp((const char *)propValue, "attack")==0) st->at_bonus = (int)value; + else if (strcmp((const char *)propValue, "defense")==0) st->df_bonus = (int)value; + xmlFree(propValue); + } + } + /* reading eressea/ships/ship/coast */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "coast", xpath); + for (c=0,k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + + if (k==0) { + assert(st->coasts==NULL); + st->coasts = (const terrain_type**)malloc(sizeof(const terrain_type*) * (result->nodesetval->nodeNr+1)); + st->coasts[result->nodesetval->nodeNr] = NULL; + } + + propValue = xmlGetProp(node, BAD_CAST "terrain"); + assert(propValue!=NULL); + st->coasts[c] = get_terrain((const char*)propValue); + if (st->coasts[c]!=NULL) ++c; + else { + log_warning(("ship %s mentions a non-existing terrain %s.\n", st->name[0], propValue)); + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + + /* finally, register the new building type */ + st_register(st); + } + } + xmlXPathFreeObject(ships); + + xmlXPathFreeContext(xpath); + return 0; +} + +static void +race_compat(void) +{ + /* required for old_race, do not change order! */ + const char * oldracenames[MAXRACES] = { + "dwarf", "elf", NULL, "goblin", "human", "troll", "demon", "insect", + "halfling", "cat", "aquarian", "orc", "snotling", "undead", "illusion", + "youngdragon", "dragon", "wyrm", "ent", "catdragon", "dracoid", + "special", "spell", "irongolem", "stonegolem", "shadowdemon", + "shadowmaster", "mountainguard", "alp", "toad", "braineater", "peasant", + "wolf", NULL, NULL, NULL, NULL, "songdragon", NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, "seaserpent", + "shadowknight", "centaur", "skeleton", "skeletonlord", "zombie", + "juju-zombie", "ghoul", "ghast", "museumghost", "gnome", "template", + "clone" + }; + int i; + + for (i=0;i!=MAXRACES;++i) { + const char * rcname = oldracenames[i]; + if (rcname==NULL) { + new_race[i] = NULL; + } else { + race * rc = rc_find(oldracenames[i]); + if (rc) { + new_race[i] = rc; + if (rc == new_race[RC_TROLL]) { + a_add(&rc->attribs, make_skillmod(NOSKILL, SMF_RIDING, NULL, 0.0, -1)); + } + } + } + } +} + +static potion_type * +xml_readpotion(xmlXPathContextPtr xpath, item_type * itype) +{ + int level = xml_ivalue(xpath->node, "level", 0); + + assert(level>0); + return new_potiontype(itype, level); +} + +static luxury_type * +xml_readluxury(xmlXPathContextPtr xpath, item_type * itype) +{ + int price = xml_ivalue(xpath->node, "price", 0); + return new_luxurytype(itype, price); +} + + +static armor_type * +xml_readarmor(xmlXPathContextPtr xpath, item_type * itype) +{ + xmlNodePtr node = xpath->node; + armor_type * atype = NULL; + unsigned int flags = ATF_NONE; + int ac = xml_ivalue(node, "ac", 0); + double penalty = xml_fvalue(node, "penalty", 0.0); + double magres = xml_fvalue(node, "magres", 0.0); + + if (xml_bvalue(node, "laen", false)) flags |= ATF_LAEN; + if (xml_bvalue(node, "shield", false)) flags |= ATF_SHIELD; + + atype = new_armortype(itype, penalty, magres, ac, flags); + atype->projectile = (float)xml_fvalue(node, "projectile", 0.0); + return atype; +} + +static weapon_type * +xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) +{ + xmlNodePtr node = xpath->node; + weapon_type * wtype = NULL; + unsigned int flags = WTF_NONE; + xmlXPathObjectPtr result; + xmlChar * propValue; + int k; + skill_t sk; + int minskill = xml_ivalue(node, "minskill", 0); + int offmod = xml_ivalue(node, "offmod", 0); + int defmod = xml_ivalue(node, "defmod", 0); + int reload = xml_ivalue(node, "reload", 0); + double magres = xml_fvalue(node, "magres", 0.0); + + if (xml_bvalue(node, "armorpiercing", false)) flags |= WTF_ARMORPIERCING; + if (xml_bvalue(node, "magical", false)) flags |= WTF_MAGICAL; + if (xml_bvalue(node, "missile", false)) flags |= WTF_MISSILE; + if (xml_bvalue(node, "pierce", false)) flags |= WTF_PIERCE; + if (xml_bvalue(node, "cut", false)) flags |= WTF_CUT; + if (xml_bvalue(node, "blunt", false)) flags |= WTF_BLUNT; + if (xml_bvalue(node, "siege", false)) flags |= WTF_SIEGE; + if (xml_bvalue(node, "horse", (flags&WTF_MISSILE)==0)) flags |= WTF_HORSEBONUS; + if (xml_bvalue(node, "useshield", true)) flags |= WTF_USESHIELD; + + propValue = xmlGetProp(node, BAD_CAST "skill"); + assert(propValue!=NULL); + sk = sk_find((const char*)propValue); + assert(sk!=NOSKILL); + xmlFree(propValue); + + wtype = new_weapontype(itype, flags, magres, NULL, offmod, defmod, reload, sk, minskill); + + /* reading weapon/damage */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "damage", xpath); + assert(result->nodesetval->nodeNr<=2); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + int pos = 0; + + propValue = xmlGetProp(node, BAD_CAST "type"); + if (strcmp((const char *)propValue, "footman")!=0) { + pos = 1; + } + xmlFree(propValue); + + propValue = xmlGetProp(node, BAD_CAST "value"); + wtype->damage[pos] = gc_add(strdup((const char*)propValue)); + if (k==0) wtype->damage[1-pos] = wtype->damage[pos]; + xmlFree(propValue); + } + xmlXPathFreeObject(result); + + /* reading weapon/modifier */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); + assert(wtype->modifiers==NULL); + wtype->modifiers = calloc(result->nodesetval->nodeNr+1, sizeof(weapon_mod)); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + xmlXPathObjectPtr races; + int r, flags = 0; + + if (xml_bvalue(node, "walking", false)) flags|=WMF_WALKING; + if (xml_bvalue(node, "riding", false)) flags|=WMF_RIDING; + if (xml_bvalue(node, "against_walking", false)) flags|=WMF_AGAINST_WALKING; + if (xml_bvalue(node, "against_riding", false)) flags|=WMF_AGAINST_RIDING; + if (xml_bvalue(node, "offensive", false)) flags|=WMF_OFFENSIVE; + if (xml_bvalue(node, "defensive", false)) flags|=WMF_DEFENSIVE; + + propValue = xmlGetProp(node, BAD_CAST "type"); + if (strcmp((const char*)propValue, "damage")==0) flags|=WMF_DAMAGE; + else if (strcmp((const char*)propValue, "skill")==0) flags|=WMF_SKILL; + else if (strcmp((const char*)propValue, "missile_target")==0) flags|=WMF_MISSILE_TARGET; + xmlFree(propValue); + + wtype->modifiers[k].flags = flags; + wtype->modifiers[k].value = xml_ivalue(node, "value", 0); + + xpath->node = node; + races = xmlXPathEvalExpression(BAD_CAST "race", xpath); + for (r=0;r!=races->nodesetval->nodeNr;++r) { + xmlNodePtr node = races->nodesetval->nodeTab[r]; + + propValue = xmlGetProp(node, BAD_CAST "name"); + if (propValue!=NULL) { + const race * rc = rc_find((const char*)propValue); + if (rc==NULL) rc = rc_add(rc_new((const char*)propValue)); + racelist_insert(&wtype->modifiers[k].races, rc); + xmlFree(propValue); + } + } + xmlXPathFreeObject(races); + } + xmlXPathFreeObject(result); + + if (gamecode_enabled) { + /* reading weapon/function */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "function", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + xmlChar * propValue; + pf_generic fun; + + parse_function(node, &fun, &propValue); + if (fun==NULL) { + log_error(("unknown function name '%s' for item '%s'\n", + (const char*)propValue, itype->rtype->_name[0])); + xmlFree(propValue); + continue; + } + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "attack")==0) { + wtype->attack = (boolean (*)(const struct troop*, const struct weapon_type *, int*))fun; + } else { + log_error(("unknown function type '%s' for item '%s'\n", + (const char*)propValue, itype->rtype->_name[0])); + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + } + + xpath->node = node; + return wtype; +} + +static item_type * +xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) +{ + xmlNodePtr node = xpath->node; + item_type * itype = NULL; + unsigned int flags = ITF_NONE; + xmlXPathObjectPtr result; + int k; + + int weight = xml_ivalue(node, "weight", 0); + int capacity = xml_ivalue(node, "capacity", 0); + + if (xml_bvalue(node, "cursed", false)) flags |= ITF_CURSED; + if (xml_bvalue(node, "notlost", false)) flags |= ITF_NOTLOST; + if (xml_bvalue(node, "herb", false)) flags |= ITF_HERB; + if (xml_bvalue(node, "big", false)) flags |= ITF_BIG; + if (xml_bvalue(node, "animal", false)) flags |= ITF_ANIMAL; + if (xml_bvalue(node, "vehicle", false)) flags |= ITF_VEHICLE; + itype = new_itemtype(rtype, flags, weight, capacity); +#if SCORE_MODULE + itype->score = xml_ivalue(node, "score", 0); +#endif + + /* reading item/construction */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "construction", xpath); + xml_readconstruction(xpath, result->nodesetval, &itype->construction); + xmlXPathFreeObject(result); + + /* reading item/weapon */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "weapon", xpath); + assert(result->nodesetval->nodeNr<=1); + if (result->nodesetval->nodeNr!=0) { + xpath->node = result->nodesetval->nodeTab[0]; + rtype->wtype = xml_readweapon(xpath, itype); + } + xmlXPathFreeObject(result); + + /* reading item/potion */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "potion", xpath); + assert(result->nodesetval->nodeNr<=1); + if (result->nodesetval->nodeNr!=0) { + xpath->node = result->nodesetval->nodeTab[0]; + rtype->ptype = xml_readpotion(xpath, itype); + } + xmlXPathFreeObject(result); + + /* reading item/luxury */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "luxury", xpath); + assert(result->nodesetval->nodeNr<=1); + if (result->nodesetval->nodeNr!=0) { + xpath->node = result->nodesetval->nodeTab[0]; + rtype->ltype = xml_readluxury(xpath, itype); + } + xmlXPathFreeObject(result); + + /* reading item/armor */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "armor", xpath); + assert(result->nodesetval->nodeNr<=1); + if (result->nodesetval->nodeNr!=0) { + xpath->node = result->nodesetval->nodeTab[0]; + rtype->atype = xml_readarmor(xpath, itype); + } + xmlXPathFreeObject(result); + + if (gamecode_enabled) { + /* reading item/function */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "function", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + xmlChar * propValue; + pf_generic fun; + + parse_function(node, &fun, &propValue); + if (fun==NULL) { + log_error(("unknown function name '%s' for item '%s'\n", + (const char*)propValue, rtype->_name[0])); + xmlFree(propValue); + continue; + } + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "give")==0) { + itype->give = (int (*)(struct unit*, struct unit*, const struct item_type *, int, struct order *))fun; + } else if (strcmp((const char*)propValue, "use")==0) { + itype->use = (int (*)(struct unit *, const struct item_type *, int, struct order *))fun; + } else if (strcmp((const char*)propValue, "canuse")==0) { + itype->canuse = (boolean (*)(const struct unit *, const struct item_type *))fun; + } else if (strcmp((const char*)propValue, "useonother")==0) { + itype->useonother = (int (*)(struct unit *, int, const struct item_type *, int, struct order *))fun; + } else { + log_error(("unknown function type '%s' for item '%s'\n", + (const char*)propValue, rtype->_name[0])); + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + } + + return itype; +} + +static int +parse_rules(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr functions; + xmlNodeSetPtr nodes; + int i; + + /* reading eressea/resources/resource */ + functions = xmlXPathEvalExpression(BAD_CAST "/eressea/rules/function", xpath); + nodes = functions->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + xmlChar *propValue; + pf_generic fun; + + parse_function(node, &fun, &propValue); + + if (fun==NULL) { + log_error(("unknown function for rule '%s' %s\n", (const char*)propValue)); + xmlFree(propValue); + continue; + } + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "wage")==0) { + global.functions.wage = (int (*)(const struct region*, const struct faction*, const struct race*, int))fun; + } else if (strcmp((const char*)propValue, "maintenance")==0) { + global.functions.maintenance = (int (*)(const struct unit*))fun; + } else { + log_error(("unknown function for rule '%s'\n", + (const char*)propValue)); + } + xmlFree(propValue); + } + xmlXPathFreeObject(functions); + xmlXPathFreeContext(xpath); + return 0; +} + +static int +parse_resources(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr resources; + xmlNodeSetPtr nodes; + int i; + + /* reading eressea/resources/resource */ + resources = xmlXPathEvalExpression(BAD_CAST "/eressea/resources/resource", xpath); + nodes = resources->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + xmlChar *propValue, *name, *appearance; + const char *names[2], *appearances[2]; + char * namep = NULL, * appearancep = NULL; + resource_type * rtype; + unsigned int flags = RTF_NONE; + xmlXPathObjectPtr result; + int k; + + if (xml_bvalue(node, "pooled", true)) flags |= RTF_POOLED; + if (xml_bvalue(node, "limited", false)) flags |= RTF_LIMITED; + + name = xmlGetProp(node, BAD_CAST "name"); + appearance = xmlGetProp(node, BAD_CAST "appearance"); + assert(name!=NULL); + + if (appearance!=NULL) { + appearancep = strcat(strcpy((char*)malloc(strlen((char*)appearance)+3), (char*)appearance), "_p"); + } + + rtype = rt_find((const char *)name); + if (rtype!=NULL) { + /* dependency from another item, was created earlier */ + rtype->flags |= flags; + if (appearance) { + rtype->_appearance[0] = strdup((const char*)appearance); + rtype->_appearance[1] = appearancep; + free(appearancep); + } + } else { + namep = strcat(strcpy((char*)malloc(strlen((char*)name)+3), (char*)name), "_p"); + names[0] = (const char*)name; + names[1] = namep; + if (appearance) { + appearances[0] = (const char*)appearance; + appearances[1] = appearancep; + rtype = new_resourcetype((const char**)names, (const char**)appearances, flags); + free(appearancep); + } else { + rtype = new_resourcetype(names, NULL, flags); + } + free(namep); + } + + if (name) xmlFree(name); + if (appearance) xmlFree(appearance); + + name = xmlGetProp(node, BAD_CAST "material"); + if (name) { + rmt_create(rtype, (const char *)name); + xmlFree(name); + } + + + if (gamecode_enabled) { + /* reading eressea/resources/resource/function */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "function", xpath); + if (result->nodesetval!=NULL) for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + pf_generic fun; + + parse_function(node, &fun, &propValue); + if (fun==NULL) { + log_error(("unknown function name '%s' for resource %s\n", + (const char*)propValue, rtype->_name[0])); + xmlFree(propValue); + continue; + } + + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "change")==0) { + rtype->uchange = (rtype_uchange)fun; + } else if (strcmp((const char*)propValue, "get")==0) { + rtype->uget = (rtype_uget)fun; + } else if (strcmp((const char*)propValue, "name")==0) { + rtype->name = (rtype_name)fun; + } else { + log_error(("unknown function type '%s' for resource %s\n", + (const char*)propValue, rtype->_name[0])); + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + } + + /* reading eressea/resources/resource/resourcelimit */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "resourcelimit", xpath); + assert(result->nodesetval->nodeNr<=1); + if (result->nodesetval->nodeNr!=0) { + resource_limit * rdata; + attrib * a = a_find(rtype->attribs, &at_resourcelimit); + xmlNodePtr limit = result->nodesetval->nodeTab[0]; + + if (a==NULL) a = a_add(&rtype->attribs, a_new(&at_resourcelimit)); + rdata = (resource_limit*)a->data.v; + rtype->flags |= RTF_LIMITED; + xpath->node = limit; + xmlXPathFreeObject(result); + + result = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); + if (result->nodesetval!=NULL) { + rdata->modifiers = calloc(result->nodesetval->nodeNr+1, sizeof(resource_mod)); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + building_type * btype = NULL; + const race * rc = NULL; + + propValue = xmlGetProp(node, BAD_CAST "race"); + if (propValue!=NULL) { + rc = rc_find((const char*)propValue); + if (rc==NULL) rc = rc_add(rc_new((const char*)propValue)); + xmlFree(propValue); + } + rdata->modifiers[k].race = rc; + + propValue = xmlGetProp(node, BAD_CAST "building"); + if (propValue!=NULL) { + btype = bt_get_or_create((const char*)propValue); + xmlFree(propValue); + } + rdata->modifiers[k].btype = btype; + + propValue = xmlGetProp(node, BAD_CAST "type"); + assert(propValue!=NULL); + if (strcmp((const char *)propValue, "skill")==0) { + rdata->modifiers[k].value.i = xml_ivalue(node, "value", 0); + rdata->modifiers[k].flags = RMF_SKILL; + } else if (strcmp((const char *)propValue, "material")==0) { + rdata->modifiers[k].value.f = (float)xml_fvalue(node, "value", 0); + rdata->modifiers[k].flags = RMF_SAVEMATERIAL; + } else if (strcmp((const char *)propValue, "resource")==0) { + rdata->modifiers[k].value.f = (float)xml_fvalue(node, "value", 0); + rdata->modifiers[k].flags = RMF_SAVERESOURCE; + } else if (strcmp((const char *)propValue, "require")==0) { + xmlChar * propBldg = xmlGetProp(node, BAD_CAST "building"); + if (propBldg!=NULL) { + btype = bt_get_or_create((const char*)propBldg); + rdata->modifiers[k].btype = btype; + rdata->modifiers[k].flags = RMF_REQUIREDBUILDING; + xmlFree(propBldg); + } + } else { + log_error(("unknown type '%s' for resourcelimit-modifier '%s'\n", + (const char*)propValue, rtype->_name[0])); + } + xmlFree(propValue); + } + } + xmlXPathFreeObject(result); + + result = xmlXPathEvalExpression(BAD_CAST "guard", xpath); + if (result->nodesetval!=NULL) for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + xmlChar * propFlag = xmlGetProp(node, BAD_CAST "flag"); + + if (propFlag!=NULL) { + if (strcmp((const char *)propFlag, "logging")==0) { + rdata->guard |= GUARD_TREES; + } else if (strcmp((const char *)propFlag, "mining")==0) { + rdata->guard |= GUARD_MINING; + } + xmlFree(propFlag); + } + } + xmlXPathFreeObject(result); + + /* reading eressea/resources/resource/resourcelimit/function */ + result = xmlXPathEvalExpression(BAD_CAST "function", xpath); + if (result->nodesetval!=NULL) for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + pf_generic fun; + + propValue = xmlGetProp(node, BAD_CAST "value"); + assert(propValue!=NULL); + fun = get_function((const char*)propValue); + if (fun==NULL) { + log_error(("unknown limit '%s' for resource %s\n", + (const char*)propValue, rtype->_name[0])); + xmlFree(propValue); + continue; + } + xmlFree(propValue); + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "produce")==0) { + rdata->produce = (rlimit_produce)fun; + } else if (strcmp((const char*)propValue, "limit")==0) { + rdata->limit = (rlimit_limit)fun; + } else { + log_error(("unknown limit '%s' for resource %s\n", + (const char*)propValue, rtype->_name[0])); + } + xmlFree(propValue); + } + } + xmlXPathFreeObject(result); + + /* reading eressea/resources/resource/resourcelimit/function */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "resourcelimit/function", xpath); + xmlXPathFreeObject(result); + + /* reading eressea/resources/resource/item */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "item", xpath); + assert(result->nodesetval->nodeNr<=1); + if (result->nodesetval->nodeNr!=0) { + rtype->flags |= RTF_ITEM; + xpath->node = result->nodesetval->nodeTab[0]; + rtype->itype = xml_readitem(xpath, rtype); + } + xmlXPathFreeObject(result); + } + xmlXPathFreeObject(resources); + + xmlXPathFreeContext(xpath); + + /* make sure old items (used in requirements) are available */ + init_resources(); + init_itemtypes(); + + return 0; +} + +static void +add_items(equipment * eq, xmlNodeSetPtr nsetItems) +{ + if (nsetItems!=NULL && nsetItems->nodeNr>0) { + int i; + for (i=0;i!=nsetItems->nodeNr;++i) { + xmlNodePtr node = nsetItems->nodeTab[i]; + xmlChar * propValue; + const struct item_type * itype; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + itype = it_find((const char*)propValue); + xmlFree(propValue); + if (itype!=NULL) { + propValue = xmlGetProp(node, BAD_CAST "amount"); + if (propValue!=NULL) { + equipment_setitem(eq, itype, (const char*)propValue); + xmlFree(propValue); + } + } + } + } +} + +static void +add_callbacks(equipment * eq, xmlNodeSetPtr nsetItems) +{ + if (nsetItems!=NULL && nsetItems->nodeNr>0) { + int i; + for (i=0;i!=nsetItems->nodeNr;++i) { + xmlNodePtr node = nsetItems->nodeTab[i]; + xmlChar * propValue; + pf_generic fun; + + propValue = xmlGetProp(node, BAD_CAST "name"); + if (propValue!=NULL) { + fun = get_function((const char*)propValue); + if (fun) { + equipment_setcallback(eq, (void (*)(const struct equipment *, struct unit *))fun); + } + xmlFree(propValue); + } + } + } +} + +static void +add_spells(equipment * eq, xmlNodeSetPtr nsetItems) +{ + if (nsetItems!=NULL && nsetItems->nodeNr>0) { + int i; + for (i=0;i!=nsetItems->nodeNr;++i) { + xmlNodePtr node = nsetItems->nodeTab[i]; + xmlChar * propValue; + magic_t mtype = M_NONE; + struct spell * sp; + + propValue = xmlGetProp(node, BAD_CAST "school"); + if (propValue!=NULL) { + for (mtype=0;mtype!=MAXMAGIETYP;++mtype) { + if (strcmp((const char*)propValue, magic_school[mtype])==0) break; + } + assert(mtype!=MAXMAGIETYP); + xmlFree(propValue); + } + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + sp = find_spell(mtype, (const char*)propValue); + assert(sp); + xmlFree(propValue); + if (sp!=NULL) { + equipment_addspell(eq, sp); + } + } + } +} + +static void +add_skills(equipment * eq, xmlNodeSetPtr nsetSkills) +{ + if (nsetSkills!=NULL && nsetSkills->nodeNr>0) { + int i; + for (i=0;i!=nsetSkills->nodeNr;++i) { + xmlNodePtr node = nsetSkills->nodeTab[i]; + xmlChar * propValue; + skill_t sk; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + sk = sk_find((const char*)propValue); + xmlFree(propValue); + if (sk!=NOSKILL) { + propValue = xmlGetProp(node, BAD_CAST "level"); + if (propValue!=NULL) { + equipment_setskill(eq, sk, (const char*)propValue); + xmlFree(propValue); + } + } + } + } +} + +static void +add_subsets(xmlDocPtr doc, equipment * eq, xmlNodeSetPtr nsetSubsets) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + if (nsetSubsets!=NULL && nsetSubsets->nodeNr>0) { + int i; + + eq->subsets = calloc(nsetSubsets->nodeNr+1, sizeof(subset)); + for (i=0;i!=nsetSubsets->nodeNr;++i) { + xmlXPathObjectPtr xpathResult; + xmlNodePtr node = nsetSubsets->nodeTab[i]; + xmlChar * propValue; + + eq->subsets[i].chance = 1.0f; + propValue = xmlGetProp(node, BAD_CAST "chance"); + if (propValue!=NULL) { + eq->subsets[i].chance = (float)atof((const char *)propValue); + xmlFree(propValue); + } + xpath->node = node; + xpathResult = xmlXPathEvalExpression(BAD_CAST "set", xpath); + if (xpathResult->nodesetval) { + xmlNodeSetPtr nsetSets = xpathResult->nodesetval; + float totalChance = 0.0f; + + if (nsetSets->nodeNr>0) { + int set; + eq->subsets[i].sets = calloc(nsetSets->nodeNr+1, sizeof(subsetitem)); + for (set=0;set!=nsetSets->nodeNr;++set) { + xmlNodePtr nodeSet = nsetSets->nodeTab[set]; + float chance = 1.0f; + + propValue = xmlGetProp(nodeSet, BAD_CAST "chance"); + if (propValue!=NULL) { + chance = (float)atof((const char *)propValue); + xmlFree(propValue); + } + totalChance += chance; + + propValue = xmlGetProp(nodeSet, BAD_CAST "name"); + assert(propValue!=NULL); + eq->subsets[i].sets[set].chance = chance; + eq->subsets[i].sets[set].set = create_equipment((const char*)propValue); + xmlFree(propValue); + } + } + if (totalChance>1.0f) { + log_error(("total chance exceeds 1.0: %f in equipment set %s.\n", + totalChance, eq->name)); + } + } + xmlXPathFreeObject(xpathResult); + } + } + xmlXPathFreeContext(xpath); +} + +static int +parse_equipment(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr xpathRaces; + + /* reading eressea/equipment/set */ + xpathRaces = xmlXPathEvalExpression(BAD_CAST "/eressea/equipment/set", xpath); + if (xpathRaces->nodesetval) { + xmlNodeSetPtr nsetRaces = xpathRaces->nodesetval; + int i; + + for (i=0;i!=nsetRaces->nodeNr;++i) { + xmlNodePtr node = nsetRaces->nodeTab[i]; + xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); + + if (propName!=NULL) { + equipment * eq = create_equipment((const char*)propName); + xmlXPathObjectPtr xpathResult; + + xpath->node = node; + + xpathResult = xmlXPathEvalExpression(BAD_CAST "callback", xpath); + assert(!eq->callback); + add_callbacks(eq, xpathResult->nodesetval); + xmlXPathFreeObject(xpathResult); + + xpathResult = xmlXPathEvalExpression(BAD_CAST "item", xpath); + assert(!eq->items); + add_items(eq, xpathResult->nodesetval); + xmlXPathFreeObject(xpathResult); + + xpathResult = xmlXPathEvalExpression(BAD_CAST "spell", xpath); + assert(!eq->spells); + add_spells(eq, xpathResult->nodesetval); + xmlXPathFreeObject(xpathResult); + + xpathResult = xmlXPathEvalExpression(BAD_CAST "skill", xpath); + add_skills(eq, xpathResult->nodesetval); + xmlXPathFreeObject(xpathResult); + + xpathResult = xmlXPathEvalExpression(BAD_CAST "subset", xpath); + assert(!eq->subsets); + add_subsets(doc, eq, xpathResult->nodesetval); + xmlXPathFreeObject(xpathResult); + + xmlFree(propName); + } + } + } + + xmlXPathFreeObject(xpathRaces); + xmlXPathFreeContext(xpath); + + return 0; +} + +static int +parse_spells(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr spells; + + /* reading eressea/spells/spell */ + spells = xmlXPathEvalExpression(BAD_CAST "/eressea/spells/spell", xpath); + if (spells->nodesetval!=NULL) { + xmlNodeSetPtr nodes = spells->nodesetval; + int i; + + for (i=0;i!=nodes->nodeNr;++i) { + xmlXPathObjectPtr result; + xmlNodePtr node = nodes->nodeTab[i]; + xmlChar * propValue; + int k; + spell * sp = calloc(1, sizeof(spell)); + static int modes[] = { 0, PRECOMBATSPELL, COMBATSPELL, POSTCOMBATSPELL }; + + /* spellname */ + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + sp->sname = strdup((const char*)propValue); + xmlFree(propValue); + + propValue = xmlGetProp(node, BAD_CAST "parameters"); + if (propValue) { + sp->parameter=strdup((const char *)propValue); + xmlFree(propValue); + } + + propValue = xmlGetProp(node, BAD_CAST "syntax"); + if (propValue) { + sp->syntax=strdup((const char *)propValue); + xmlFree(propValue); + } + + /* magic type */ + propValue = xmlGetProp(node, BAD_CAST "type"); + assert(propValue!=NULL); + for (sp->magietyp=0;sp->magietyp!=MAXMAGIETYP;++sp->magietyp) { + if (strcmp(magic_school[sp->magietyp], (const char *)propValue)==0) break; + } + assert(sp->magietyp!=MAXMAGIETYP); + xmlFree(propValue); + + /* level, rank and flags */ + sp->id = xml_ivalue(node, "index", 0); + sp->level = xml_ivalue(node, "level", -1); + sp->rank = (char)xml_ivalue(node, "rank", -1); + if (xml_bvalue(node, "los", false)) sp->sptyp |= TESTCANSEE; /* must see or have contact */ + if (!xml_bvalue(node, "target_global", false)) sp->sptyp |= SEARCHLOCAL; /* must be in same region */ + if (xml_bvalue(node, "ship", false)) sp->sptyp |= ONSHIPCAST; + if (xml_bvalue(node, "ocean", false)) sp->sptyp |= OCEANCASTABLE; + if (xml_bvalue(node, "far", false)) sp->sptyp |= FARCASTING; + if (xml_bvalue(node, "variable", false)) sp->sptyp |= SPELLLEVEL; + k = xml_ivalue(node, "combat", 0); + if (k>=0 && k<=3) sp->sptyp |= modes[k]; + + if (gamecode_enabled) { + /* reading eressea/spells/spell/function */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "function", xpath); + + if (result->nodesetval->nodeNr==0) { + /* deprecated style: this spell gets its' function from a callback */ + if (set_spelldata_cb) set_spelldata_cb(sp); + } else { + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + pf_generic fun; + + parse_function(node, &fun, &propValue); + if (fun==NULL) { + log_error(("unknown function name '%s' for spell '%s'\n", + (const char*)propValue, sp->sname)); + xmlFree(propValue); + continue; + } + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "cast")==0) { + sp->sp_function = (spell_f)fun; + } else if (strcmp((const char*)propValue, "fumble")==0) { + sp->patzer = (pspell_f)fun; + } else { + log_error(("unknown function type '%s' for spell %s\n", + (const char*)propValue, sp->sname)); + } + xmlFree(propValue); + } + } + xmlXPathFreeObject(result); + } + + /* reading eressea/spells/spell/resource */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "resource", xpath); + if (result->nodesetval->nodeNr) { + sp->components = malloc(sizeof(spell_component)*(result->nodesetval->nodeNr+1)); + sp->components[result->nodesetval->nodeNr].type = 0; + } + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue); + sp->components[k].type = rt_find((const char *)propValue); + assert(sp->components[k].type); + xmlFree(propValue); + sp->components[k].amount = xml_ivalue(node, "amount", 1); + sp->components[k].cost = SPC_FIX; + propValue = xmlGetProp(node, BAD_CAST "cost"); + if (propValue!=NULL) { + if (strcmp((const char *)propValue, "linear")==0) { + sp->components[k].cost = SPC_LINEAR; + } else if (strcmp((const char *)propValue, "level")==0) { + sp->components[k].cost = SPC_LEVEL; + } + xmlFree(propValue); + } + } + xmlXPathFreeObject(result); + register_spell(sp); + } + } + + xmlXPathFreeObject(spells); + + xmlXPathFreeContext(xpath); + + return 0; +} + +static void +parse_param(struct param ** params, xmlNodePtr node) +{ + xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); + xmlChar * propValue = xmlGetProp(node, BAD_CAST "value"); + + set_param(params, (const char*)propName, (const char*)propValue); + + xmlFree(propName); + xmlFree(propValue); +} + +static void +parse_ai(race * rc, xmlNodePtr node) +{ + rc->splitsize = xml_ivalue(node, "splitsize", 0); + rc->aggression = (float)xml_fvalue(node, "aggression", 0.04); + if (xml_bvalue(node, "killpeasants", false)) rc->flags |= RCF_KILLPEASANTS; + if (xml_bvalue(node, "moverandom", false)) rc->flags |= RCF_MOVERANDOM; + if (xml_bvalue(node, "learn", false)) rc->flags |= RCF_LEARN; +} + +static int +parse_races(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr races; + xmlNodeSetPtr nodes; + int i; + + /* reading eressea/races/race */ + races = xmlXPathEvalExpression(BAD_CAST "/eressea/races/race", xpath); + nodes = races->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + xmlNodePtr child; + xmlChar * propValue; + race * rc; + xmlXPathObjectPtr result; + int k, study_speed_base; + struct att * attack; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + rc = rc_find((const char*)propValue); + if (rc==NULL) rc = rc_add(rc_new((const char*)propValue)); + xmlFree(propValue); + + propValue = xmlGetProp(node, BAD_CAST "damage"); + assert(propValue!=NULL); + rc->def_damage = strdup((const char*)propValue); + xmlFree(propValue); + + rc->magres = (float)xml_fvalue(node, "magres", 0.0); + rc->maxaura = (float)xml_fvalue(node, "maxaura", 0.0); + rc->regaura = (float)xml_fvalue(node, "regaura", 1.0); + rc->recruitcost = xml_ivalue(node, "recruitcost", 0); + rc->maintenance = xml_ivalue(node, "maintenance", 0); + rc->weight = xml_ivalue(node, "weight", PERSON_WEIGHT); + rc->capacity = xml_ivalue(node, "capacity", 540); + rc->speed = (float)xml_fvalue(node, "speed", 1.0F); + rc->hitpoints = xml_ivalue(node, "hp", 0); + rc->armor = (char)xml_ivalue(node, "ac", 0); + study_speed_base = xml_ivalue(node, "studyspeed", 0); + + rc->at_default = (char)xml_ivalue(node, "unarmedattack", -2); + rc->df_default = (char)xml_ivalue(node, "unarmeddefense", -2); + rc->at_bonus = (char)xml_ivalue(node, "attackmodifier", 0); + rc->df_bonus = (char)xml_ivalue(node, "defensemodifier", 0); + + if (xml_bvalue(node, "playerrace", false)) rc->flags |= RCF_PLAYERRACE; + if (xml_bvalue(node, "scarepeasants", false)) rc->flags |= RCF_SCAREPEASANTS; + if (xml_bvalue(node, "cansteal", true)) rc->flags |= RCF_CANSTEAL; + if (xml_bvalue(node, "cansail", true)) rc->flags |= RCF_CANSAIL; + if (xml_bvalue(node, "cannotmove", false)) rc->flags |= RCF_CANNOTMOVE; + if (xml_bvalue(node, "fly", false)) rc->flags |= RCF_FLY; + if (xml_bvalue(node, "invisible", false)) rc->flags |= RCF_INVISIBLE; + if (xml_bvalue(node, "coastal", false)) rc->flags |= RCF_COASTAL; + if (xml_bvalue(node, "unarmedguard", false)) rc->flags |= RCF_UNARMEDGUARD; + if (xml_bvalue(node, "swim", false)) rc->flags |= RCF_SWIM; + if (xml_bvalue(node, "walk", false)) rc->flags |= RCF_WALK; + if (!xml_bvalue(node, "canlearn", true)) rc->flags |= RCF_NOLEARN; + if (!xml_bvalue(node, "canteach", true)) rc->flags |= RCF_NOTEACH; + if (xml_bvalue(node, "horse", false)) rc->flags |= RCF_HORSE; + if (xml_bvalue(node, "desert", false)) rc->flags |= RCF_DESERT; + if (xml_bvalue(node, "absorbpeasants", false)) rc->flags |= RCF_ABSORBPEASANTS; + if (xml_bvalue(node, "noheal", false)) rc->flags |= RCF_NOHEAL; + if (xml_bvalue(node, "noweapons", false)) rc->flags |= RCF_NOWEAPONS; + if (xml_bvalue(node, "shapeshift", false)) rc->flags |= RCF_SHAPESHIFT; + if (xml_bvalue(node, "shapeshiftany", false)) rc->flags |= RCF_SHAPESHIFTANY; + if (xml_bvalue(node, "illusionary", false)) rc->flags |= RCF_ILLUSIONARY; + if (xml_bvalue(node, "undead", false)) rc->flags |= RCF_UNDEAD; + if (xml_bvalue(node, "dragon", false)) rc->flags |= RCF_DRAGON; + if (xml_bvalue(node, "shipspeed", false)) rc->flags |= RCF_SHIPSPEED; + if (xml_bvalue(node, "stonegolem", false)) rc->flags |= RCF_STONEGOLEM; + if (xml_bvalue(node, "irongolem", false)) rc->flags |= RCF_IRONGOLEM; + + if (xml_bvalue(node, "giveitem", false)) rc->ec_flags |= GIVEITEM; + if (xml_bvalue(node, "giveperson", false)) rc->ec_flags |= GIVEPERSON; + if (xml_bvalue(node, "giveunit", false)) rc->ec_flags |= GIVEUNIT; + if (xml_bvalue(node, "getitem", false)) rc->ec_flags |= GETITEM; + if (xml_bvalue(node, "recruithorses", false)) rc->ec_flags |= ECF_REC_HORSES; + if (xml_bvalue(node, "recruitethereal", false)) rc->ec_flags |= ECF_REC_ETHEREAL; + if (xml_bvalue(node, "recruitunlimited", false)) rc->ec_flags |= ECF_REC_UNLIMITED; + + if (xml_bvalue(node, "equipment", false)) rc->battle_flags |= BF_EQUIPMENT; + if (xml_bvalue(node, "noblock", false)) rc->battle_flags |= BF_NOBLOCK; + if (xml_bvalue(node, "invinciblenonmagic", false)) rc->battle_flags |= BF_INV_NONMAGIC; + if (xml_bvalue(node, "resistbash", false)) rc->battle_flags |= BF_RES_BASH; + if (xml_bvalue(node, "resistcut", false)) rc->battle_flags |= BF_RES_CUT; + if (xml_bvalue(node, "resistpierce", false)) rc->battle_flags |= BF_RES_PIERCE; + if (xml_bvalue(node, "canattack", true)) rc->battle_flags |= BF_CANATTACK; + + for (child=node->children;child;child=child->next) { + if (strcmp((const char *)child->name, "ai")==0) { + parse_ai(rc, child); + } else if (strcmp((const char *)child->name, "param")==0) { + parse_param(&rc->parameters, child); + } + } + rc->recruit_multi = get_param_flt(rc->parameters, "recruit_multi", 1.0); + + /* reading eressea/races/race/skill */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "skill", xpath); + memset(rc->bonus, 0, sizeof(rc->bonus)); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + int mod = xml_ivalue(node, "modifier", 0); + int speed = xml_ivalue(node, "speed", study_speed_base); + skill_t sk; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + sk = sk_find((const char*)propValue); + if (sk!=NOSKILL) { + rc->bonus[sk] = (char)mod; + if (speed) { + if (!rc->study_speed) rc->study_speed = calloc(1, MAXSKILLS); + rc->study_speed[sk] = (char)speed; + } + } else { + log_error(("unknown skill '%s' in race '%s'\n", + (const char*)propValue, rc->_name[0])); + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + + if (gamecode_enabled) { + /* reading eressea/races/race/function */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "function", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + pf_generic fun; + + parse_function(node, &fun, &propValue); + if (fun==NULL) { + log_error(("unknown function name '%s' for race %s\n", + (const char*)propValue, rc->_name[0])); + xmlFree(propValue); + continue; + } + assert(propValue!=NULL); + if (strcmp((const char*)propValue, "name")==0) { + rc->generate_name = (const char * (*)(const struct unit*))fun; + } else if (strcmp((const char*)propValue, "describe")==0) { + rc->describe = (const char * (*)(const struct unit*, const struct locale *))fun; + } else if (strcmp((const char*)propValue, "age")==0) { + rc->age = (void(*)(struct unit*))fun; + } else if (strcmp((const char*)propValue, "move")==0) { + rc->move_allowed = (boolean(*)(const struct region *, const struct region *))fun; + } else if (strcmp((const char*)propValue, "itemdrop")==0) { + rc->itemdrop = (struct item *(*)(const struct race *, int))fun; + } else if (strcmp((const char*)propValue, "initfamiliar")==0) { + rc->init_familiar = (void(*)(struct unit *))fun; + } else { + log_error(("unknown function type '%s' for race %s\n", + (const char*)propValue, rc->_name[0])); + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + } + + /* reading eressea/races/race/familiar */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "familiar", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + race * frc; + + propValue = xmlGetProp(node, BAD_CAST "race"); + assert(propValue!=NULL); + frc = rc_find((const char *)propValue); + if (frc == NULL) { +// log_error(("%s not registered, is familiar for %s\n", +// (const char*)propValue, rc->_name[0])); +// assert(frc!=NULL); + frc = rc_add(rc_new((const char*)propValue)); + } + if (xml_bvalue(node, "default", false)) { + rc->familiars[k] = rc->familiars[0]; + rc->familiars[0] = frc; + } else { + rc->familiars[k] = frc; + } + xmlFree(propValue); + } + xmlXPathFreeObject(result); + + /* reading eressea/races/race/precombatspell */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "precombatspell", xpath); + assert(rc->precombatspell==NULL || !"precombatspell is already initialized"); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + rc->precombatspell = xml_spell(node, "spell"); + } + xmlXPathFreeObject(result); + + /* reading eressea/races/race/attack */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "attack", xpath); + attack = rc->attack; + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + while (attack->type!=AT_NONE) ++attack; + + propValue = xmlGetProp(node, BAD_CAST "damage"); + if (propValue!=NULL) { + attack->data.dice = strdup((const char*)propValue); + xmlFree(propValue); + } else { + attack->data.sp = xml_spell(node, "spell"); + } + attack->type = xml_ivalue(node, "type", 0); + attack->flags = xml_ivalue(node, "flags", 0); + } + xmlXPathFreeObject(result); + } + xmlXPathFreeObject(races); + + xmlXPathFreeContext(xpath); + + race_compat(); + return 0; +} + +static int +parse_terrains(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath; + xmlXPathObjectPtr terrains; + xmlNodeSetPtr nodes; + int i; + + xpath = xmlXPathNewContext(doc); + + /* reading eressea/terrains/terrain */ + terrains = xmlXPathEvalExpression(BAD_CAST "/eressea/terrains/terrain", xpath); + nodes = terrains->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + terrain_type * terrain = calloc(1, sizeof(terrain_type)); + xmlChar * propValue; + xmlXPathObjectPtr xpathChildren; + xmlNodeSetPtr children; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue!=NULL); + terrain->_name = strdup((const char *)propValue); + xmlFree(propValue); + + terrain->max_road = (short)xml_ivalue(node, "road", 0); + assert(terrain->max_road>=0); + terrain->size = xml_ivalue(node, "size", 0); + + if (xml_bvalue(node, "forbidden", false)) terrain->flags |= FORBIDDEN_REGION; + else { + if (xml_bvalue(node, "fly", true)) terrain->flags |= FLY_INTO; + if (xml_bvalue(node, "sail", true)) terrain->flags |= SAIL_INTO; + if (xml_bvalue(node, "walk", true)) terrain->flags |= WALK_INTO; + if (xml_bvalue(node, "swim", false)) terrain->flags |= SWIM_INTO; + if (xml_bvalue(node, "shallow", true)) terrain->flags |= LARGE_SHIPS; + if (xml_bvalue(node, "cavalry", false)) terrain->flags |= CAVALRY_REGION; + } + if (xml_bvalue(node, "sea", false)) terrain->flags |= SEA_REGION; + if (xml_bvalue(node, "arctic", false)) terrain->flags |= ARCTIC_REGION; + if (xml_bvalue(node, "land", true)) terrain->flags |= LAND_REGION; + if (xml_bvalue(node, "forest", false)) terrain->flags |= FOREST_REGION; + + terrain->distribution = (short)xml_ivalue(node, "seed", 0); + + xpath->node = node; + xpathChildren = xmlXPathEvalExpression(BAD_CAST "herb", xpath); + children = xpathChildren->nodesetval; + if (children->nodeNr>0) { + int k; + + terrain->herbs = malloc((children->nodeNr+1) * sizeof(item_type*)); + terrain->herbs[children->nodeNr] = NULL; + for (k=0;k!=children->nodeNr;++k) { + xmlNodePtr nodeHerb = children->nodeTab[k]; + const struct resource_type * rtype; + + propValue = xmlGetProp(nodeHerb, BAD_CAST "name"); + assert(propValue!=NULL); + rtype = rt_find((const char*)propValue); + assert(rtype!=NULL && rtype->itype!=NULL && fval(rtype->itype, ITF_HERB)); + terrain->herbs[k] = rtype->itype; + xmlFree(propValue); + } + } + xmlXPathFreeObject(xpathChildren); + + xpath->node = node; + xpathChildren = xmlXPathEvalExpression(BAD_CAST "resource", xpath); + children = xpathChildren->nodesetval; + if (children->nodeNr>0) { + int k; + + terrain->production = malloc((children->nodeNr+1) * sizeof(terrain_production)); + terrain->production[children->nodeNr].type = NULL; + for (k=0;k!=children->nodeNr;++k) { + xmlNodePtr nodeProd = children->nodeTab[k]; + + propValue = xmlGetProp(nodeProd, BAD_CAST "name"); + assert(propValue!=NULL); + terrain->production[k].type = rt_find((const char*)propValue); + assert(terrain->production[k].type); + xmlFree(propValue); + + propValue = xmlGetProp(nodeProd, BAD_CAST "level"); + assert(propValue); + terrain->production[k].startlevel = strdup((const char *)propValue); + xmlFree(propValue); + + propValue = xmlGetProp(nodeProd, BAD_CAST "base"); + assert(propValue); + terrain->production[k].base = strdup((const char *)propValue); + xmlFree(propValue); + + propValue = xmlGetProp(nodeProd, BAD_CAST "div"); + assert(propValue); + terrain->production[k].divisor = strdup((const char *)propValue); + xmlFree(propValue); + + terrain->production[k].chance = (float)xml_fvalue(nodeProd, "chance", 1.0); + } + } + xmlXPathFreeObject(xpathChildren); + + register_terrain(terrain); + } + xmlXPathFreeObject(terrains); + + xmlXPathFreeContext(xpath); + + init_terrains(); + return 0; +} + +static int +parse_messages(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath; + xmlXPathObjectPtr messages; + xmlNodeSetPtr nodes; + int i; + + if (!gamecode_enabled) return 0; + + xpath = xmlXPathNewContext(doc); + + /* reading eressea/messages/message */ + messages = xmlXPathEvalExpression(BAD_CAST "/eressea/messages/message", xpath); + nodes = messages->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + const char * default_section = "events"; + xmlChar * propSection; + xmlChar * propValue; + xmlXPathObjectPtr result; + int k; + char ** argv = NULL; + const message_type * mtype; + + /* arguments */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "type/arg", xpath); + if (result->nodesetval && result->nodesetval->nodeNr>0) { + argv = malloc(sizeof(char*)*(result->nodesetval->nodeNr+1)); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + char zBuffer[128]; + xmlChar * propName, * propType; + + propName = xmlGetProp(node, BAD_CAST "name"); + propType = xmlGetProp(node, BAD_CAST "type"); + sprintf(zBuffer, "%s:%s", (const char*)propName, (const char*)propType); + xmlFree(propName); + xmlFree(propType); + argv[k] = strdup(zBuffer); + } + argv[result->nodesetval->nodeNr] = NULL; + } + xmlXPathFreeObject(result); + + /* add the messagetype */ + propValue = xmlGetProp(node, BAD_CAST "name"); + mtype = mt_find((const char *)propValue); + if (mtype==NULL) { + mtype = mt_register(mt_new((const char *)propValue, (const char**)argv)); + } else { + assert(argv!=NULL || !"cannot redefine arguments of message now"); + } + xmlFree(propValue); + + /* register the type for the CR */ + crt_register(mtype); + + /* let's clean up the mess */ + if (argv!=NULL) { + for (k=0;argv[k]!=NULL;++k) free(argv[k]); + free(argv); + } + + propSection = xmlGetProp(node, BAD_CAST "section"); + if (propSection==NULL) propSection = BAD_CAST default_section; + + /* strings */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "text", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + struct locale * lang; + xmlChar * propText; + + xml_readtext(node, &lang, &propText); + if (lang) { + xml_cleanup_string(propText); + nrt_register(mtype, lang, (const char *)propText, 0, (const char*)propSection); + } + xmlFree(propText); + + } + xmlXPathFreeObject(result); + + if (propSection != BAD_CAST default_section) xmlFree(propSection); + } + + xmlXPathFreeObject(messages); + + xmlXPathFreeContext(xpath); + return 0; +} + +static void +xml_readstrings(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, boolean names) +{ + int i; + + for (i=0;i!=nodeNr;++i) { + xmlNodePtr stringNode = nodeTab[i]; + xmlChar * propName = xmlGetProp(stringNode, BAD_CAST "name"); + xmlChar * propNamespace = NULL; + xmlXPathObjectPtr result; + int k; + char zName[128]; + + assert(propName!=NULL); + if (names) propNamespace = xmlGetProp(stringNode->parent, BAD_CAST "name"); + mkname_buf((const char*)propNamespace, (const char*)propName, zName); + if (propNamespace!=NULL) xmlFree(propNamespace); + xmlFree(propName); + + /* strings */ + xpath->node = stringNode; + result = xmlXPathEvalExpression(BAD_CAST "text", xpath); + for (k=0;k!=result->nodesetval->nodeNr;++k) { + xmlNodePtr textNode = result->nodesetval->nodeTab[k]; + struct locale * lang; + xmlChar * propText; + + xml_readtext(textNode, &lang, &propText); + if (propText!=NULL) { + assert(strcmp(zName, (const char*)xml_cleanup_string(BAD_CAST zName))==0); + if (lang) { + xml_cleanup_string(propText); + locale_setstring(lang, zName, (const char *)propText); + } + xmlFree(propText); + } else { + log_warning(("string %s has no text in locale %s\n", + zName, locale_name(lang))); + } + } + xmlXPathFreeObject(result); + } +} + +static int +parse_strings(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr strings; + + /* reading eressea/strings/string */ + strings = xmlXPathEvalExpression(BAD_CAST "/eressea/strings/string", xpath); + xml_readstrings(xpath, strings->nodesetval->nodeTab, strings->nodesetval->nodeNr, false); + xmlXPathFreeObject(strings); + + strings = xmlXPathEvalExpression(BAD_CAST "/eressea/strings/namespace/string", xpath); + xml_readstrings(xpath, strings->nodesetval->nodeTab, strings->nodesetval->nodeNr, true); + xmlXPathFreeObject(strings); + + xmlXPathFreeContext(xpath); + return 0; +} + +static void +xml_readprefixes(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, boolean names) +{ + int i; + + for (i=0;i!=nodeNr;++i) { + xmlNodePtr node = nodeTab[i]; + xmlChar * propText = xmlNodeListGetString(node->doc, node->children, 1); + + if (propText!=NULL) { + add_raceprefix((const char*)propText); + xmlFree(propText); + } + } +} + +static int +parse_prefixes(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr strings; + + /* reading eressea/strings/string */ + strings = xmlXPathEvalExpression(BAD_CAST "/eressea/prefixes/prefix", xpath); + xml_readprefixes(xpath, strings->nodesetval->nodeTab, strings->nodesetval->nodeNr, false); + xmlXPathFreeObject(strings); + + xmlXPathFreeContext(xpath); + return 0; +} + +static int +parse_main(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr result = xmlXPathEvalExpression(BAD_CAST "/eressea/game", xpath); + xmlNodeSetPtr nodes = result->nodesetval; + int i; + + xmlChar * propValue; + if (nodes->nodeNr>0) { + xmlNodePtr node = nodes->nodeTab[0]; + + global.producexpchance = (float)xml_fvalue(node, "learningbydoing", 1.0/3); + + propValue = xmlGetProp(node, BAD_CAST "name"); + if (propValue!=NULL) { + global.gamename = strdup((const char*)propValue); + xmlFree(propValue); + } + + xmlXPathFreeObject(result); + + /* reading eressea/game/param */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "param", xpath); + nodes = result->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + parse_param(&global.parameters, node); + } + + xmlXPathFreeObject(result); + + /* reading eressea/game/order */ + result = xmlXPathEvalExpression(BAD_CAST "order", xpath); + nodes = result->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); + boolean disable = xml_bvalue(node, "disable", false); + + if (disable) { + int k; + for (k=0;k!=MAXKEYWORDS;++k) { + if (strcmp(keywords[k], (const char*)propName)==0) { + global.disabled[k]=1; + break; + } + } + if (k==MAXKEYWORDS) { + log_error(("trying to disable unknown comand %s\n", (const char*)propName)); + } + } + xmlFree(propName); + } + + xmlXPathFreeObject(result); + + /* reading eressea/game/skill */ + result = xmlXPathEvalExpression(BAD_CAST "skill", xpath); + nodes = result->nodesetval; + for (i=0;i!=nodes->nodeNr;++i) { + xmlNodePtr node = nodes->nodeTab[i]; + xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); + boolean enable = xml_bvalue(node, "enable", true); + enable_skill((const char*)propName, enable); + xmlFree(propName); + } + } + xmlXPathFreeObject(result); + + xmlXPathFreeContext(xpath); + return 0; +} + +void +register_xmlreader(void) +{ + xml_register_callback(parse_main); + + xml_register_callback(parse_strings); + xml_register_callback(parse_prefixes); + xml_register_callback(parse_messages); + xml_register_callback(parse_resources); + xml_register_callback(parse_rules); + + xml_register_callback(parse_terrains); /* requires resources */ + xml_register_callback(parse_buildings); /* requires resources */ + xml_register_callback(parse_ships); /* requires terrains */ + xml_register_callback(parse_spells); /* requires resources */ + xml_register_callback(parse_equipment); /* requires spells */ + xml_register_callback(parse_races); /* requires spells */ + xml_register_callback(parse_calendar); + xml_register_callback(parse_directions); +} diff --git a/src/kernel/xmlreader.h b/src/kernel/xmlreader.h index 8dfb85dfe..4c4457da1 100644 --- a/src/kernel/xmlreader.h +++ b/src/kernel/xmlreader.h @@ -1,28 +1,27 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2007 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#ifndef H_KRNL_XMLREADER_H -#define H_KRNL_XMLREADER_H - -#ifdef __cplusplus -extern "C" { -#endif - extern void register_xmlreader(void); - extern void enable_xml_gamecode(void); - - /* game-specific callbacks */ - extern void (*set_spelldata_cb)(struct spell * sp); -#ifdef __cplusplus -} -#endif - -#endif +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2007 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#ifndef H_KRNL_XMLREADER_H +#define H_KRNL_XMLREADER_H +#ifdef __cplusplus +extern "C" { +#endif + extern void register_xmlreader(void); + extern void enable_xml_gamecode(void); + + /* game-specific callbacks */ + extern void (*set_spelldata_cb)(struct spell * sp); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/modules/arena.c b/src/modules/arena.c index d7f817fab..84081797e 100644 --- a/src/modules/arena.c +++ b/src/modules/arena.c @@ -1,527 +1,527 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include - -#if ARENA_MODULE -#include "arena.h" - -/* modules include */ -#include "score.h" - -/* attributes include */ -#include - -/* items include */ -#include - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util include */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc include */ -#include -#include -#include - - -/* exports: */ -plane * arena = NULL; - - -/* local vars */ -#define CENTRAL_VOLCANO 1 - -#ifdef ARENA_CREATION -static unsigned int arena_id = 0; -static region * arena_center = NULL; -static int newarena = 0; -#endif -static region * tower_region[6]; -static region * start_region[6]; - -static region * -arena_region(int school) -{ - return tower_region[school]; -} - -static building * -arena_tower(int school) -{ - return arena_region(school)->buildings; -} - -static int -leave_fail(unit * u) -{ - ADDMSG(&u->faction->msgs, msg_message("arena_leave_fail", "unit", u)); - return 1; -} - -static int -leave_arena(struct unit * u, const struct item_type * itype, int amount, order * ord) -{ - if (!u->building && leave_fail(u)) return -1; - if (u->building!=arena_tower(u->faction->magiegebiet) && leave_fail(u)) return -1; - unused(amount); - unused(ord); - unused(itype); - assert(!"not implemented"); - return 0; -} - -static int -enter_fail(unit * u) -{ - ADDMSG(&u->faction->msgs, msg_message("arena_enter_fail", "region unit", u->region, u)); - return 1; -} - -static int -enter_arena(unit * u, const item_type * itype, int amount, order * ord) -{ - skill_t sk; - region * r = u->region; - unit * u2; - int fee = u->faction->score / 5; - unused(ord); - unused(amount); - unused(itype); - if (fee>2000) fee = 2000; - if (getplane(r)==arena) return -1; - if (u->number!=1 && enter_fail(u)) return -1; - if (get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, fee) < fee && enter_fail(u)) return -1; - for (sk=0;sk!=MAXSKILLS;++sk) { - if (get_level(u, sk)>1 && enter_fail(u)) return -1; - } - for (u2=r->units;u2;u2=u2->next) if (u2->faction==u->faction) break; - - assert(!"not implemented"); -/* - for (res=0;res!=MAXRESOURCES;++res) if (res!=R_SILVER && res!=R_ARENA_GATE && (is_item(res) || is_herb(res) || is_potion(res))) { - int x = get_resource(u, res); - if (x) { - if (u2) { - change_resource(u2, res, x); - change_resource(u, res, -x); - } - else if (enter_fail(u)) return -1; - } - } -*/ - if (get_money(u) > fee) { - if (u2) change_money(u2, get_money(u) - fee); - else if (enter_fail(u)) return -1; - } - ADDMSG(&u->faction->msgs, msg_message("arena_enter_fail", "region unit", u->region, u)); - use_pooled(u, itype->rtype, GET_SLACK|GET_RESERVE, 1); - use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, fee); - set_money(u, 109); - fset(u, UFL_ANON_FACTION); - move_unit(u, start_region[rng_int() % 6], NULL); - return 0; -} - -/*** - ** Szepter der Tränen, Demo-Item - ***/ - -static int -use_wand_of_tears(unit * user, const struct item_type * itype, int amount, order * ord) -{ - int n; - unused(ord); - for (n=0;n!=amount;++n) { - unit * u; - for (u=user->region->units;u;u=u->next) { - if (u->faction != user->faction) { - int i; - - for (i=0;i!=u->skill_size;++i) { - if (rng_int()%3) reduce_skill(u, u->skills+i, 1); - } - ADDMSG(&u->faction->msgs, msg_message("wand_of_tears_effect", - "unit", u)); - } - } - } - ADDMSG(&user->region->msgs, msg_message("wand_of_tears_usage", - "unit", user)); - return 0; -} - -/** - * Tempel der Schreie, Demo-Gebäude **/ - -static int -age_hurting(attrib * a) { - building * b = (building *)a->data.v; - unit * u; - int active = 0; - if (b==NULL) return AT_AGE_REMOVE; - for (u=b->region->units;u;u=u->next) { - if (u->building==b) { - if (u->faction->magiegebiet==M_DRAIG) { - active ++; - ADDMSG(&b->region->msgs, msg_message("praytoigjarjuk", "unit", u)); - } - } - } - if (active) for (u=b->region->units;u;u=u->next) if (playerrace(u->faction->race)) { - int i; - if (u->faction->magiegebiet!=M_DRAIG) { - for (i=0;i!=active;++i) u->hp = (u->hp+1) / 2; /* make them suffer, but not die */ - ADDMSG(&b->region->msgs, msg_message("cryinpain", "unit", u)); - } - } - return AT_AGE_KEEP; -} - -static void -write_hurting(const attrib * a, const void * owner, struct storage * store) { - building * b = a->data.v; - store->w_int(store, b->no); -} - -static int -read_hurting(attrib * a, void * owner, struct storage * store) { - int i; - i = store->r_int(store); - a->data.v = (void*)findbuilding(i); - if (a->data.v==NULL) { - log_error(("temple of pain is broken\n")); - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -static attrib_type at_hurting = { - "hurting", NULL, NULL, age_hurting, write_hurting, read_hurting -}; - -#ifdef ARENA_CREATION -static void -make_temple(region * r) -{ - const building_type * btype = bt_find("temple"); - building * b; - if (btype==NULL) { - log_error(("could not find buildingtype 'temple'\n")); - return; - } - - b = r->buildings; - while (b!=NULL && b->type!=btype) b = b->next; - if (b!=NULL) return; /* gibt schon einen */ - - b = new_building(btype, r, NULL); - b->size = btype->maxsize; - b->name = strdup("Igjarjuk's Tempel der Schreie"); - b->display = strdup("Ein Schrein aus spitzen Knochen und lodernden Flammen, gewidmet dem Wyrm der Wyrme"); - a_add(&b->attribs, a_new(&at_hurting))->data.v=b; -} -#endif - -/** - * Initialisierung Türme */ - -#ifdef ARENA_CREATION -static void -tower_init(void) -{ - int i, first = newarena; - item_type * it_demonseye = it_find("demonseye"); - item_type * it_griphonwing = it_find("griphonwing"); - assert(it_griphonwing && it_demonseye); - for (i=0;i!=6;++i) { - region * r = tower_region[i] = findregion(arena_center->x+delta_x[i]*3, arena_center->y+delta_y[i]*3); - if (r) { - start_region[i] = findregion(arena_center->x+delta_x[i]*2, arena_center->y+delta_y[i]*2); - if (rterrain(r)!=T_DESERT) terraform(r, T_DESERT); - if (!r->buildings) { - building * b = new_building(bt_find("castle"), r, NULL); - b->size = 10; - if (i!=0) { - sprintf(buf, "Turm des %s", - LOC(default_locale, mkname("school", magic_school[i]))); - } - else sprintf(buf, "Turm der Ahnungslosen"); - set_string(&b->name, buf); - } - } - } - if (first && !arena_center->buildings) { - building * b = new_building(bt_find("castle"), arena_center, NULL); - attrib * a; - item * items; - - i_add(&items, i_new(it_griphonwing, 1)); - i_add(&items, i_new(it_demonseye, 1)); - a = a_add(&b->attribs, make_giveitem(b, items)); - - b->size = 10; - set_string(&b->name, "Höhle des Greifen"); - } -} -#endif - -#ifdef ARENA_CREATION -static void -guardian_faction(plane * pl, int id) -{ - region * r; - faction * f = findfaction(id); - - if (!f) { - f = calloc(1, sizeof(faction)); - f->banner = strdup("Sie dienen dem großen Wyrm"); - f->passw = strdup(itoa36(rng_int())); - f->override = strdup(itoa36(rng_int())); - set_email(&f->email, "igjarjuk@eressea.de"); - f->name = strdup("Igjarjuks Kundschafter"); - f->race = new_race[RC_ILLUSION]; - f->age = turn; - f->locale = find_locale("de"); - f->options = want(O_COMPRESS) | want(O_REPORT) | want(O_COMPUTER) | want(O_ADRESSEN) | want(O_DEBUG); - - f->no = id; - addlist(&factions, f); - fhash(f); - } - if (f->race != new_race[RC_ILLUSION]) { - assert(!"guardian id vergeben"); - exit(0); - } - f->lastorders = turn; - f->alive = true; - for (r=regions;r;r=r->next) if (getplane(r)==pl && rterrain(r)!=T_FIREWALL) - { - unit * u; - freset(r, RF_ENCOUNTER); - for (u=r->units;u;u=u->next) { - if (u->faction==f) break; - } - if (u) continue; - u = createunit(r, f, 1, new_race[RC_GOBLIN]); - set_string(&u->name, "Igjarjuks Auge"); - set_item(u, I_RING_OF_INVISIBILITY, 1); - set_order(&u->thisorder, NULL); - fset(u, UFL_ANON_FACTION); - set_money(u, 1000); - } -} -#endif - -#define BLOCKSIZE 9 - -#ifdef ARENA_CREATION -static void -block_create(int x1, int y1, char terrain) -{ - int x, y; - for (x=0;x!=BLOCKSIZE;++x) { - for (y=0;y!=BLOCKSIZE;++y) { - region * r = new_region(x1 + x, y1 + y, 0); - terraform(r, terrain); - } - } -} -#endif - -#ifdef CENTRAL_VOLCANO - -static int -caldera_handle(trigger * t, void * data) -{ - /* call an event handler on caldera. - * data.v -> ( variant event, int timer ) - */ - building *b = (building *)t->data.v; - if (b!=NULL) { - unit ** up = &b->region->units; - while (*up) { - unit * u = *up; - if (u->building==b) { - message * msg; - if (u->items) { - item ** ip = &u->items; - msg = msg_message("caldera_handle_1", "unit items", u, u->items); - while (*ip) { - item * i = *ip; - i_remove(ip, i); - if (*ip==i) ip=&i->next; - } - } else { - msg = msg_message("caldera_handle_0", "unit", u); - } - add_message(&u->region->msgs, msg); - set_number(u, 0); - } - if (*up==u) up = &u->next; - } - } else { - log_error(("could not perform caldera::handle()\n")); - } - unused(data); - return 0; -} - -static void -caldera_write(const trigger * t, struct storage * store) -{ - building *b = (building *)t->data.v; - write_building_reference(b, store); -} - -static int -caldera_read(trigger * t, struct storage * store) -{ - int rb = read_reference(&t->data.v, store, read_building_reference, resolve_building); - if (rb==0 && !t->data.v) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -struct trigger_type tt_caldera = { - "caldera", - NULL, - NULL, - caldera_handle, - caldera_write, - caldera_read -}; - -#ifdef ARENA_CREATION -static trigger * -trigger_caldera(building * b) -{ - trigger * t = t_new(&tt_caldera); - t->data.v = b; - return t; -} -#endif - -#ifdef ARENA_CREATION -static void -init_volcano(void) -{ - building * b; - region * r = arena_center; - assert(arena_center); - if (rterrain(r)!=T_DESERT) return; /* been done before */ - terraform(arena_center, T_VOLCANO_SMOKING); - b = new_building(bt_find("caldera"), r, NULL); - b->size = 1; - b->name = strdup("Igjarjuk's Schlund"); - b->display = strdup("Feurige Lava fließt aus dem Krater des großen Vulkans. Alles wird von ihr verschlungen."); - add_trigger(&b->attribs, "timer", trigger_caldera(b)); - tt_register(&tt_caldera); -} -#endif -#endif - -#ifdef ARENA_CREATION -void -create_arena(void) -{ - int x; - arena_id = hashstring("arena"); - arena = getplanebyid(arena_id); - if (arena!=NULL) return; - score(); /* ist wichtig, damit alle Parteien einen score haben, wenn sie durchs Tor wollen. */ - guardian_faction(arena, 999); - if (arena) arena_center = findregion(plane_center_x(arena), plane_center_y(arena)); - if (!arena_center) { - newarena = 1; - arena = create_new_plane(arena_id, "Arena", -10000, -10000, 0, BLOCKSIZE-1, PFL_LOWSTEALING | PFL_NORECRUITS | PFL_NOALLIANCES); - block_create(arena->minx, arena->miny, T_OCEAN); - arena_center = findregion(plane_center_x(arena), plane_center_y(arena)); - for (x=0;x!=BLOCKSIZE;++x) { - int y; - for (y=0;y!=BLOCKSIZE;++y) { - region * r = findregion(arena->minx+x, arena->miny+y); - freset(r, RF_ENCOUNTER); - r->planep = arena; - switch (distance(r, arena_center)) { - case 4: - terraform(r, T_FIREWALL); - break; - case 0: - terraform(r, T_GLACIER); - break; - case 1: - terraform(r, T_SWAMP); - break; - case 2: - terraform(r, T_MOUNTAIN); - break; - } - } - } - } - make_temple(arena_center); -#ifdef CENTRAL_VOLCANO - init_volcano(); -#else - if (arena_center->terrain!=T_DESERT) terraform(arena_center, T_DESERT); -#endif - rsetmoney(arena_center, 0); - rsetpeasants(arena_center, 0); - tower_init(); -} -#endif -void -register_arena(void) -{ - at_register(&at_hurting); - register_item_use(use_wand_of_tears, "use_wand_of_tears"); - register_function((pf_generic)enter_arena, "enter_arena"); - register_function((pf_generic)leave_arena, "leave_arena"); - tt_register(&tt_caldera); -} - -#endif /* def ARENA_MODULE */ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include + +#if ARENA_MODULE +#include "arena.h" + +/* modules include */ +#include "score.h" + +/* attributes include */ +#include + +/* items include */ +#include + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util include */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc include */ +#include +#include +#include + + +/* exports: */ +plane * arena = NULL; + + +/* local vars */ +#define CENTRAL_VOLCANO 1 + +#ifdef ARENA_CREATION +static unsigned int arena_id = 0; +static region * arena_center = NULL; +static int newarena = 0; +#endif +static region * tower_region[6]; +static region * start_region[6]; + +static region * +arena_region(int school) +{ + return tower_region[school]; +} + +static building * +arena_tower(int school) +{ + return arena_region(school)->buildings; +} + +static int +leave_fail(unit * u) +{ + ADDMSG(&u->faction->msgs, msg_message("arena_leave_fail", "unit", u)); + return 1; +} + +static int +leave_arena(struct unit * u, const struct item_type * itype, int amount, order * ord) +{ + if (!u->building && leave_fail(u)) return -1; + if (u->building!=arena_tower(u->faction->magiegebiet) && leave_fail(u)) return -1; + unused(amount); + unused(ord); + unused(itype); + assert(!"not implemented"); + return 0; +} + +static int +enter_fail(unit * u) +{ + ADDMSG(&u->faction->msgs, msg_message("arena_enter_fail", "region unit", u->region, u)); + return 1; +} + +static int +enter_arena(unit * u, const item_type * itype, int amount, order * ord) +{ + skill_t sk; + region * r = u->region; + unit * u2; + int fee = u->faction->score / 5; + unused(ord); + unused(amount); + unused(itype); + if (fee>2000) fee = 2000; + if (getplane(r)==arena) return -1; + if (u->number!=1 && enter_fail(u)) return -1; + if (get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, fee) < fee && enter_fail(u)) return -1; + for (sk=0;sk!=MAXSKILLS;++sk) { + if (get_level(u, sk)>1 && enter_fail(u)) return -1; + } + for (u2=r->units;u2;u2=u2->next) if (u2->faction==u->faction) break; + + assert(!"not implemented"); +/* + for (res=0;res!=MAXRESOURCES;++res) if (res!=R_SILVER && res!=R_ARENA_GATE && (is_item(res) || is_herb(res) || is_potion(res))) { + int x = get_resource(u, res); + if (x) { + if (u2) { + change_resource(u2, res, x); + change_resource(u, res, -x); + } + else if (enter_fail(u)) return -1; + } + } +*/ + if (get_money(u) > fee) { + if (u2) change_money(u2, get_money(u) - fee); + else if (enter_fail(u)) return -1; + } + ADDMSG(&u->faction->msgs, msg_message("arena_enter_fail", "region unit", u->region, u)); + use_pooled(u, itype->rtype, GET_SLACK|GET_RESERVE, 1); + use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, fee); + set_money(u, 109); + fset(u, UFL_ANON_FACTION); + move_unit(u, start_region[rng_int() % 6], NULL); + return 0; +} + +/*** + ** Szepter der Tränen, Demo-Item + ***/ + +static int +use_wand_of_tears(unit * user, const struct item_type * itype, int amount, order * ord) +{ + int n; + unused(ord); + for (n=0;n!=amount;++n) { + unit * u; + for (u=user->region->units;u;u=u->next) { + if (u->faction != user->faction) { + int i; + + for (i=0;i!=u->skill_size;++i) { + if (rng_int()%3) reduce_skill(u, u->skills+i, 1); + } + ADDMSG(&u->faction->msgs, msg_message("wand_of_tears_effect", + "unit", u)); + } + } + } + ADDMSG(&user->region->msgs, msg_message("wand_of_tears_usage", + "unit", user)); + return 0; +} + +/** + * Tempel der Schreie, Demo-Gebäude **/ + +static int +age_hurting(attrib * a) { + building * b = (building *)a->data.v; + unit * u; + int active = 0; + if (b==NULL) return AT_AGE_REMOVE; + for (u=b->region->units;u;u=u->next) { + if (u->building==b) { + if (u->faction->magiegebiet==M_DRAIG) { + active ++; + ADDMSG(&b->region->msgs, msg_message("praytoigjarjuk", "unit", u)); + } + } + } + if (active) for (u=b->region->units;u;u=u->next) if (playerrace(u->faction->race)) { + int i; + if (u->faction->magiegebiet!=M_DRAIG) { + for (i=0;i!=active;++i) u->hp = (u->hp+1) / 2; /* make them suffer, but not die */ + ADDMSG(&b->region->msgs, msg_message("cryinpain", "unit", u)); + } + } + return AT_AGE_KEEP; +} + +static void +write_hurting(const attrib * a, const void * owner, struct storage * store) { + building * b = a->data.v; + store->w_int(store, b->no); +} + +static int +read_hurting(attrib * a, void * owner, struct storage * store) { + int i; + i = store->r_int(store); + a->data.v = (void*)findbuilding(i); + if (a->data.v==NULL) { + log_error(("temple of pain is broken\n")); + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +static attrib_type at_hurting = { + "hurting", NULL, NULL, age_hurting, write_hurting, read_hurting +}; + +#ifdef ARENA_CREATION +static void +make_temple(region * r) +{ + const building_type * btype = bt_find("temple"); + building * b; + if (btype==NULL) { + log_error(("could not find buildingtype 'temple'\n")); + return; + } + + b = r->buildings; + while (b!=NULL && b->type!=btype) b = b->next; + if (b!=NULL) return; /* gibt schon einen */ + + b = new_building(btype, r, NULL); + b->size = btype->maxsize; + b->name = strdup("Igjarjuk's Tempel der Schreie"); + b->display = strdup("Ein Schrein aus spitzen Knochen und lodernden Flammen, gewidmet dem Wyrm der Wyrme"); + a_add(&b->attribs, a_new(&at_hurting))->data.v=b; +} +#endif + +/** + * Initialisierung Türme */ + +#ifdef ARENA_CREATION +static void +tower_init(void) +{ + int i, first = newarena; + item_type * it_demonseye = it_find("demonseye"); + item_type * it_griphonwing = it_find("griphonwing"); + assert(it_griphonwing && it_demonseye); + for (i=0;i!=6;++i) { + region * r = tower_region[i] = findregion(arena_center->x+delta_x[i]*3, arena_center->y+delta_y[i]*3); + if (r) { + start_region[i] = findregion(arena_center->x+delta_x[i]*2, arena_center->y+delta_y[i]*2); + if (rterrain(r)!=T_DESERT) terraform(r, T_DESERT); + if (!r->buildings) { + building * b = new_building(bt_find("castle"), r, NULL); + b->size = 10; + if (i!=0) { + sprintf(buf, "Turm des %s", + LOC(default_locale, mkname("school", magic_school[i]))); + } + else sprintf(buf, "Turm der Ahnungslosen"); + set_string(&b->name, buf); + } + } + } + if (first && !arena_center->buildings) { + building * b = new_building(bt_find("castle"), arena_center, NULL); + attrib * a; + item * items; + + i_add(&items, i_new(it_griphonwing, 1)); + i_add(&items, i_new(it_demonseye, 1)); + a = a_add(&b->attribs, make_giveitem(b, items)); + + b->size = 10; + set_string(&b->name, "Höhle des Greifen"); + } +} +#endif + +#ifdef ARENA_CREATION +static void +guardian_faction(plane * pl, int id) +{ + region * r; + faction * f = findfaction(id); + + if (!f) { + f = calloc(1, sizeof(faction)); + f->banner = strdup("Sie dienen dem großen Wyrm"); + f->passw = strdup(itoa36(rng_int())); + f->override = strdup(itoa36(rng_int())); + set_email(&f->email, "igjarjuk@eressea.de"); + f->name = strdup("Igjarjuks Kundschafter"); + f->race = new_race[RC_ILLUSION]; + f->age = turn; + f->locale = find_locale("de"); + f->options = want(O_COMPRESS) | want(O_REPORT) | want(O_COMPUTER) | want(O_ADRESSEN) | want(O_DEBUG); + + f->no = id; + addlist(&factions, f); + fhash(f); + } + if (f->race != new_race[RC_ILLUSION]) { + assert(!"guardian id vergeben"); + exit(0); + } + f->lastorders = turn; + f->alive = true; + for (r=regions;r;r=r->next) if (getplane(r)==pl && rterrain(r)!=T_FIREWALL) + { + unit * u; + freset(r, RF_ENCOUNTER); + for (u=r->units;u;u=u->next) { + if (u->faction==f) break; + } + if (u) continue; + u = createunit(r, f, 1, new_race[RC_GOBLIN]); + set_string(&u->name, "Igjarjuks Auge"); + set_item(u, I_RING_OF_INVISIBILITY, 1); + set_order(&u->thisorder, NULL); + fset(u, UFL_ANON_FACTION); + set_money(u, 1000); + } +} +#endif + +#define BLOCKSIZE 9 + +#ifdef ARENA_CREATION +static void +block_create(int x1, int y1, char terrain) +{ + int x, y; + for (x=0;x!=BLOCKSIZE;++x) { + for (y=0;y!=BLOCKSIZE;++y) { + region * r = new_region(x1 + x, y1 + y, 0); + terraform(r, terrain); + } + } +} +#endif + +#ifdef CENTRAL_VOLCANO + +static int +caldera_handle(trigger * t, void * data) +{ + /* call an event handler on caldera. + * data.v -> ( variant event, int timer ) + */ + building *b = (building *)t->data.v; + if (b!=NULL) { + unit ** up = &b->region->units; + while (*up) { + unit * u = *up; + if (u->building==b) { + message * msg; + if (u->items) { + item ** ip = &u->items; + msg = msg_message("caldera_handle_1", "unit items", u, u->items); + while (*ip) { + item * i = *ip; + i_remove(ip, i); + if (*ip==i) ip=&i->next; + } + } else { + msg = msg_message("caldera_handle_0", "unit", u); + } + add_message(&u->region->msgs, msg); + set_number(u, 0); + } + if (*up==u) up = &u->next; + } + } else { + log_error(("could not perform caldera::handle()\n")); + } + unused(data); + return 0; +} + +static void +caldera_write(const trigger * t, struct storage * store) +{ + building *b = (building *)t->data.v; + write_building_reference(b, store); +} + +static int +caldera_read(trigger * t, struct storage * store) +{ + int rb = read_reference(&t->data.v, store, read_building_reference, resolve_building); + if (rb==0 && !t->data.v) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +struct trigger_type tt_caldera = { + "caldera", + NULL, + NULL, + caldera_handle, + caldera_write, + caldera_read +}; + +#ifdef ARENA_CREATION +static trigger * +trigger_caldera(building * b) +{ + trigger * t = t_new(&tt_caldera); + t->data.v = b; + return t; +} +#endif + +#ifdef ARENA_CREATION +static void +init_volcano(void) +{ + building * b; + region * r = arena_center; + assert(arena_center); + if (rterrain(r)!=T_DESERT) return; /* been done before */ + terraform(arena_center, T_VOLCANO_SMOKING); + b = new_building(bt_find("caldera"), r, NULL); + b->size = 1; + b->name = strdup("Igjarjuk's Schlund"); + b->display = strdup("Feurige Lava fließt aus dem Krater des großen Vulkans. Alles wird von ihr verschlungen."); + add_trigger(&b->attribs, "timer", trigger_caldera(b)); + tt_register(&tt_caldera); +} +#endif +#endif + +#ifdef ARENA_CREATION +void +create_arena(void) +{ + int x; + arena_id = hashstring("arena"); + arena = getplanebyid(arena_id); + if (arena!=NULL) return; + score(); /* ist wichtig, damit alle Parteien einen score haben, wenn sie durchs Tor wollen. */ + guardian_faction(arena, 999); + if (arena) arena_center = findregion(plane_center_x(arena), plane_center_y(arena)); + if (!arena_center) { + newarena = 1; + arena = create_new_plane(arena_id, "Arena", -10000, -10000, 0, BLOCKSIZE-1, PFL_LOWSTEALING | PFL_NORECRUITS | PFL_NOALLIANCES); + block_create(arena->minx, arena->miny, T_OCEAN); + arena_center = findregion(plane_center_x(arena), plane_center_y(arena)); + for (x=0;x!=BLOCKSIZE;++x) { + int y; + for (y=0;y!=BLOCKSIZE;++y) { + region * r = findregion(arena->minx+x, arena->miny+y); + freset(r, RF_ENCOUNTER); + r->planep = arena; + switch (distance(r, arena_center)) { + case 4: + terraform(r, T_FIREWALL); + break; + case 0: + terraform(r, T_GLACIER); + break; + case 1: + terraform(r, T_SWAMP); + break; + case 2: + terraform(r, T_MOUNTAIN); + break; + } + } + } + } + make_temple(arena_center); +#ifdef CENTRAL_VOLCANO + init_volcano(); +#else + if (arena_center->terrain!=T_DESERT) terraform(arena_center, T_DESERT); +#endif + rsetmoney(arena_center, 0); + rsetpeasants(arena_center, 0); + tower_init(); +} +#endif +void +register_arena(void) +{ + at_register(&at_hurting); + register_item_use(use_wand_of_tears, "use_wand_of_tears"); + register_function((pf_generic)enter_arena, "enter_arena"); + register_function((pf_generic)leave_arena, "leave_arena"); + tt_register(&tt_caldera); +} + +#endif /* def ARENA_MODULE */ diff --git a/src/modules/arena.h b/src/modules/arena.h index 78872e9fc..6dbec6e93 100644 --- a/src/modules/arena.h +++ b/src/modules/arena.h @@ -1,39 +1,39 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef ARENA_H -#define ARENA_H -#ifdef __cplusplus -extern "C" { -#endif - -#if ARENA_MODULE == 0 -#error "must define ARENA_MODULE to use this module" -#endif -/* exports: */ -extern struct plane * arena; - -extern void register_arena(void); -#ifdef ARENA_CREATION -extern void create_arena(void); -#endif - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef ARENA_H +#define ARENA_H +#ifdef __cplusplus +extern "C" { +#endif + +#if ARENA_MODULE == 0 +#error "must define ARENA_MODULE to use this module" +#endif +/* exports: */ +extern struct plane * arena; + +extern void register_arena(void); +#ifdef ARENA_CREATION +extern void create_arena(void); +#endif + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c index a7ad73e3f..c28a3f1bd 100644 --- a/src/modules/autoseed.c +++ b/src/modules/autoseed.c @@ -1,1022 +1,1024 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "autoseed.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include - -const terrain_type * -random_terrain(const terrain_type * terrains[], int distribution[], int size) -{ - int ndistribution = size; - const terrain_type * terrain; - int n; - - if (distribution) { - ndistribution = 0; - for (n=0;n!=size;++n) { - ndistribution += distribution[n]; - } - } - - n = rng_int() % ndistribution; - if (distribution) { - int i; - for (i=0;i!=size;++i) { - n -= distribution[i]; - if (n<0) break; - } - assert(iresources;rm;rm=rm->next) { - if (rm->type->rtype==rtype) break; - } - if (!rm) { - add_resource(r, 1, base, 150, rtype); - } - return 0; -} - - -static int -count_demand(const region *r) -{ - struct demand *dmd; - int c = 0; - if (r->land) { - for (dmd=r->land->demands;dmd;dmd=dmd->next) c++; - } - return c; -} - -static int -recurse_regions(region *r, region_list **rlist, boolean(*fun)(const region *r)) -{ - if (!fun(r)) return 0; - else { - int len = 0; - direction_t d; - region_list * rl = calloc(sizeof(region_list), 1); - rl->next = *rlist; - rl->data = r; - (*rlist) = rl; - fset(r, RF_MARK); - for (d=0;d!=MAXDIRECTIONS;++d) { - region * nr = rconnect(r, d); - if (nr && !fval(nr, RF_MARK)) len += recurse_regions(nr, rlist, fun); - } - return len+1; - } -} - -static boolean -f_nolux(const region * r) -{ - if (r->land && count_demand(r) != get_maxluxuries()) return true; - return false; -} - -int -fix_demand(region *rd) -{ - region_list *rl, *rlist = NULL; - static const struct luxury_type **mlux = 0, ** ltypes; - const luxury_type *sale = NULL; - int maxlux = 0; - int maxluxuries = get_maxluxuries(); - - if (maxluxuries==0) return 0; - recurse_regions(rd, &rlist, f_nolux); - if (mlux==0) { - int i = 0; - mlux = (const luxury_type **)gc_add(calloc(maxluxuries, sizeof(const luxury_type *))); - ltypes = (const luxury_type **)gc_add(calloc(maxluxuries, sizeof(const luxury_type *))); - for (sale=luxurytypes;sale;sale=sale->next) { - ltypes[i++] = sale; - } - } - else { - int i; - for (i=0;i!=maxluxuries;++i) mlux[i] = 0; - } - for (rl=rlist;rl;rl=rl->next) { - region * r = rl->data; - direction_t d; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * nr = rconnect(r, d); - if (nr && nr->land && nr->land->demands) { - struct demand * dmd; - for (dmd = nr->land->demands;dmd;dmd=dmd->next) { - if (dmd->value == 0) { - int i; - for (i=0;i!=maxluxuries;++i) { - if (mlux[i]==NULL) { - maxlux = i; - mlux[i] = dmd->type; - break; - } else if (mlux[i]==dmd->type) { - break; - } - } - break; - } - } - } - } - freset(r, RF_MARK); /* undo recursive marker */ - } - if (maxlux<2) { - int i; - for (i=maxlux;i!=2;++i) { - int j; - do { - int k = rng_int() % maxluxuries; - mlux[i] = ltypes[k]; - for (j=0;j!=i;++j) { - if (mlux[j]==mlux[i]) break; - } - } while (j!=i); - } - maxlux = 2; - } - for (rl=rlist;rl;rl=rl->next) { - region * r = rl->data; - if (!fval(r, RF_CHAOTIC)) { - log_info((LOG_INFO1, "fixing demand in %s\n", regionname(r, NULL))); - } - sale = mlux[rng_int() % maxlux]; - if (sale) setluxuries(r, sale); - } - while (rlist) { - rl = rlist->next; - free(rlist); - rlist = rl; - } - return 0; -} - -/* nach 150 Runden ist Neustart erlaubt */ -#define MINAGE_MULTI 150 -newfaction * -read_newfactions(const char * filename) -{ - newfaction * newfactions = NULL; - FILE * F = fopen(filename, "r"); - char buf[1024]; - - if (F==NULL) return NULL; - for (;;) { - faction * f; - char race[20], email[64], lang[8], password[16]; - newfaction *nf, **nfi; - int bonus = 0, subscription = 0; - int alliance = 0; - - if (fgets(buf, sizeof(buf), F)==NULL) break; - - email[0] = '\0'; - password[0] = '\0'; - - if (sscanf(buf, "%54s %20s %8s %d %d %16s %d", email, race, lang, &bonus, &subscription, password, &alliance)<6) break; - if (email[0]=='\0') break; - if (password[0]=='\0') { - strcpy(password, itoa36(rng_int())); - strcat(password, itoa36(rng_int())); - } - for (f=factions;f;f=f->next) { - if (strcmp(f->email, email)==0 && f->subscription && f->ageunits) continue; /* skip the ones we've already got */ - for (nf=newfactions;nf;nf=nf->next) { - if (strcmp(nf->email, email)==0) break; - } - if (nf) continue; - nf = calloc(sizeof(newfaction), 1); - if (set_email(&nf->email, email)!=0) { - log_error(("Invalid email address for subscription %s: %s\n", - itoa36(subscription), email)); - continue; - } - nf->password = strdup(password); - nf->race = rc_find(race); - nf->subscription = subscription; - if (alliances!=NULL) { - struct alliance * al = findalliance(alliance); - if (al==NULL) { - char zText[64]; - sprintf(zText, "Allianz %d", alliance); - al = makealliance(alliance, zText); - } - nf->allies = al; - } else { - nf->allies = NULL; - } - if (nf->race==NULL) { - /* if the script didn't supply the race as a token, then it gives us a - * race in the default locale (which means that itis a UTF8 string) */ - nf->race = findrace(race, default_locale); - if (nf->race==NULL) { - char buffer[32]; - size_t outbytes = sizeof(buffer) - 1; - size_t inbytes = strlen(race); - unicode_latin1_to_utf8(buffer, &outbytes, race, &inbytes); - buffer[outbytes] = 0; - nf->race = findrace(buffer, default_locale); - if (nf->race==NULL) { - log_error(("new faction has unknown race '%s'.\n", race)); - free(nf); - continue; - } - } - } - nf->lang = find_locale(lang); - nf->bonus = bonus; - assert(nf->race && nf->email && nf->lang); - nfi = &newfactions; - while (*nfi) { - if ((*nfi)->race==nf->race) break; - nfi=&(*nfi)->next; - } - nf->next = *nfi; - *nfi = nf; - } - fclose(F); - return newfactions; -} - -extern int numnewbies; - -static const terrain_type * -preferred_terrain(const struct race * rc) -{ - terrain_t t = T_PLAIN; - if (rc==rc_find("dwarf")) t = T_MOUNTAIN; - if (rc==rc_find("insect")) t = T_DESERT; - if (rc==rc_find("halfling")) t = T_SWAMP; - if (rc==rc_find("troll")) t = T_MOUNTAIN; - return newterrain(t); -} - -#define REGIONS_PER_FACTION 2 -#define PLAYERS_PER_ISLAND 20 -#define MAXISLANDSIZE 50 -#define MINFACTIONS 1 -#define VOLCANO_CHANCE 100 - -static boolean -virgin_region(const region * r) -{ - direction_t d; - if (r==NULL) return true; - if (fval(r->terrain, FORBIDDEN_REGION)) return false; - if (r->units) return false; - for (d=0;d!=MAXDIRECTIONS;++d) { - const region * rn = rconnect(r, d); - if (rn) { - if (rn->age>r->age+1) return false; - if (rn->units) return false; - if (fval(rn->terrain, FORBIDDEN_REGION)) { - /* because it kinda sucks to have islands that are adjacent to a firewall */ - return false; - } - } - } - return true; -} - -void -get_island(region * root, region_list ** rlist) -{ - region_list ** rnext = rlist; - while (*rnext) rnext=&(*rnext)->next; - - fset(root, RF_MARK); - add_regionlist(rnext, root); - - while (*rnext) { - direction_t dir; - - region * rcurrent = (*rnext)->data; - rnext = &(*rnext)->next; - - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * r = rconnect(rcurrent, dir); - if (r!=NULL && r->land && !fval(r, RF_MARK)) { - fset(r, RF_MARK); - add_regionlist(rnext, r); - } - } - } - rnext=rlist; - while (*rnext) { - region_list * rptr = *rnext; - freset(rptr->data, RF_MARK); - rnext = &rptr->next; - } -} - -static void -get_island_info(region * root, int * size_p, int * inhabited_p, int * maxage_p) -{ - int size = 0, maxage = 0, inhabited = 0; - region_list * rlist = NULL; - region_list * island = NULL; - add_regionlist(&rlist, root); - island = rlist; - fset(root, RF_MARK); - while (rlist) { - direction_t d; - region * r = rlist->data; - if (r->units) { - unit * u; - for (u=r->units; u; u=u->next) { - if (!is_monsters(u->faction) && u->faction->age > maxage) { - maxage = u->faction->age; - } - } - ++inhabited; - } - ++size; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(r, d); - if (rn && !fval(rn, RF_MARK) && rn->land) { - region_list * rnew = malloc(sizeof(region_list)); - rnew->data = rn; - rnew->next = rlist->next; - rlist->next = rnew; - fset(rn, RF_MARK); - } - } - rlist = rlist->next; - } - for (rlist=island;rlist;rlist=rlist->next) { - freset(rlist->data, RF_MARK); - } - free_regionlist(island); - if (size_p) *size_p = size; - if (inhabited_p) *inhabited_p = inhabited; - if (maxage_p) *maxage_p = maxage; -} - -void -free_newfaction(newfaction * nf) -{ - free(nf->email); - free(nf->password); - free(nf); -} - -static void -frame_regions(int age, const terrain_type * terrain) -{ - plane * hplane = get_homeplane(); - region * r = regions; - for (r=regions;r;r=r->next) { - plane * pl = rplane(r); - direction_t d; - if (r->ageterrain == terrain) continue; - - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(r, d); - if (rn==NULL) { - int x = r->x + delta_x[d]; - int y = r->y + delta_y[d]; - pnormalize(&x, &y, pl); - rn = new_region(x, y, pl, 0); - terraform_region(rn, terrain); - rn->age=r->age; - } - } - } -} - -static void -prepare_starting_region(region * r) -{ - int n, t; - double p; - - assert(r->land); - - /* population between 30% and 60% of max */ - p = rng_double(); - n = (int)(r->terrain->size * (0.3 + p*0.3)); - rsetpeasants(r, n); - - /* trees: don't squash the peasants, and at least 5% should be forrest */ - t = (rtrees(r, 2) + rtrees(r, 1)/2) * TREESIZE; - if (t < r->terrain->size/20 || t+n > r->terrain->size) { - double p2 = 0.05 + rng_double()*(1.0-p-0.05); - int maxtrees = (int)(r->terrain->size/1.25/TREESIZE); /* 1.25 = each young tree will take 1/2 the space of old trees */ - int trees = (int)(p2 * maxtrees); - - rsettrees(r, 2, trees); - rsettrees(r, 1, trees/2); - rsettrees(r, 0, trees/4); - } - - /* horses: between 1% and 2% */ - p = rng_double(); - rsethorses(r, (int)(r->terrain->size * (0.01 + p*0.01))); - - if (!markets_module()) { - fix_demand(r); - } -} - -/** create new island with up to nsize players - * returns the number of players placed on the new island. - */ -int -autoseed(newfaction ** players, int nsize, int max_agediff) -{ - region * r = NULL; - region_list * rlist = NULL; - int rsize = 0, tsize = 0; - int isize = REGIONS_PER_FACTION; /* target size for the island */ - int psize = 0; /* players on this island */ - const terrain_type * volcano_terrain = get_terrain("volcano"); - static int nterrains = -1; - static const terrain_type ** terrainarr = 0; - static int * distribution; - - if (nterrains<0) { - int n = 0; - const terrain_type * terrain = terrains(); - for (nterrains=0;terrain;terrain=terrain->next) { - if (terrain->distribution) { - ++nterrains; - } - } - terrainarr = malloc(sizeof(terrain_type *) * nterrains); - distribution = malloc(sizeof(int) * nterrains); - for (terrain = terrains();terrain;terrain = terrain->next) { - if (terrain->distribution) { - terrainarr[n] = terrain; - distribution[n++] = terrain->distribution; - } - } - } - frame_regions(16, newterrain(T_FIREWALL)); - - if (listlen(*players)0) { - region * rmin = NULL; - plane * hplane = get_homeplane(); - /* find a spot that's adjacent to the previous island, but virgin. - * like the last land virgin ocean region adjacent to land. - */ - for (r=regions;r;r=r->next) { - struct plane * pl = rplane(r); - if (r->age<=max_agediff && r->terrain == newterrain(T_OCEAN) && pl==hplane && virgin_region(r)) { - direction_t d; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(r, d); - if (rn && rn->land && rn->age<=max_agediff && virgin_region(rn)) { - /* only expand islands that aren't single-islands and not too big already */ - int size, inhabitants, maxage; - get_island_info(rn, &size, &inhabitants, &maxage); - if (maxage<=max_agediff && size>=2 && sizenext) { - region * r = rlist->data; - unit * u; - for (u=r->units;u;u=u->next) { - f = u->faction; - if (!fval(f, FFL_MARK)) { - ++psize; - fset(f, FFL_MARK); - } - } - } - free_regionlist(rlist); - if (psize>0) for (f=factions;f;f=f->next) freset(f, FFL_MARK); - if (psizenext) { - struct plane * pl = rplane(r); - if (r->terrain == newterrain(T_OCEAN) && pl==hplane && (rmin==NULL || r->age<=max_agediff)) { - direction_t d; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(r, d); - if (rn==NULL) break; - } - if (d!=MAXDIRECTIONS) { - rmin=r; - dmin=d; - } - } - } - - /* create a new region where we found the empty spot, and make it the first - * in our island. island regions are kept in rlist, so only new regions can - * get populated, and old regions are not overwritten */ - if (rmin!=NULL) { - plane * pl = rplane(rmin); - int x = rmin->x + delta_x[dmin]; - int y = rmin->y + delta_y[dmin]; - pnormalize(&x, &y, pl); - assert(virgin_region(rconnect(rmin, dmin))); - r = new_region(x, y, pl, 0); - terraform_region(r, newterrain(T_OCEAN)); - } - } - if (r!=NULL) { - add_regionlist(&rlist, r); - fset(r, RF_MARK); - rsize = 1; - } - - while (rsize && (nsize || isize>=REGIONS_PER_FACTION)) { - int i = rng_int() % rsize; - region_list ** rnext = &rlist; - region_list * rfind; - direction_t d; - while (i--) rnext=&(*rnext)->next; - rfind = *rnext; - r = rfind->data; - freset(r, RF_MARK); - *rnext = rfind->next; - free(rfind); - --rsize; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(r, d); - if (rn && fval(rn, RF_MARK)) continue; - if (rn==NULL) { - plane * pl = rplane(r); - int x = r->x + delta_x[d]; - int y = r->y + delta_y[d]; - pnormalize(&x, &y, pl); - rn = new_region(x, y, pl, 0); - terraform_region(rn, newterrain(T_OCEAN)); - } - if (virgin_region(rn)) { - add_regionlist(&rlist, rn); - fset(rn, RF_MARK); - ++rsize; - } - } - if (volcano_terrain!=NULL && (rng_int() % VOLCANO_CHANCE == 0)) { - terraform_region(r, volcano_terrain); - } else if (nsize && (rng_int() % isize == 0 || rsize==0)) { - newfaction ** nfp, * nextf = *players; - faction * f; - unit * u; - - isize += REGIONS_PER_FACTION; - terraform_region(r, preferred_terrain(nextf->race)); - prepare_starting_region(r); - ++tsize; - assert(r->land && r->units==0); - u = addplayer(r, addfaction(nextf->email, nextf->password, nextf->race, - nextf->lang, nextf->subscription)); - f = u->faction; - fset(f, FFL_ISNEW); - f->alliance = nextf->allies; - log_printf("New faction (%s), %s at %s\n", itoa36(f->no), - f->email, regionname(r, NULL)); - if (f->subscription) { - sql_print(("UPDATE subscriptions SET status='ACTIVE', faction='%s', firstturn=%d, lastturn=%d, password='%s' WHERE id=%u;\n", - factionid(f), f->lastorders, f->lastorders, f->override, f->subscription)); - } - - /* remove duplicate email addresses */ - nfp = &nextf->next; - while (*nfp) { - newfaction * nf = *nfp; - if (strcmp(nextf->email, nf->email)==0) { - *nfp = nf->next; - free_newfaction(nf); - } - else nfp = &nf->next; - } - *players = nextf->next; - free_newfaction(nextf); - - ++psize; - --nsize; - --isize; - if (psize>=PLAYERS_PER_ISLAND) break; - } else { - terraform_region(r, random_terrain(terrainarr, distribution, nterrains)); - --isize; - } - } - - if (nsize!=0) { - log_error(("Could not place all factions on the same island as requested\n")); - } - - - if (rlist) { -#define MINOCEANDIST 3 -#define MAXOCEANDIST 6 -#define MAXFILLDIST 10 -#define SPECIALCHANCE 80 - region_list ** rbegin = &rlist; - int special = 1; - int oceandist = MINOCEANDIST + (rng_int() % (MAXOCEANDIST-MINOCEANDIST)); - while (oceandist--) { - region_list ** rend = rbegin; - while (*rend) rend=&(*rend)->next; - while (rbegin!=rend) { - direction_t d; - region * r = (*rbegin)->data; - rbegin=&(*rbegin)->next; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(r, d); - if (rn==NULL) { - const struct terrain_type * terrain = newterrain(T_OCEAN); - plane * pl = rplane(r); - int x = r->x + delta_x[d]; - int y = r->y + delta_y[d]; - pnormalize(&x, &y, pl); - rn = new_region(x, y, pl, 0); - if (rng_int() % SPECIALCHANCE < special) { - terrain = random_terrain(terrainarr, distribution, nterrains); - special = SPECIALCHANCE / 3; /* 33% chance auf noch eines */ - } else { - special = 1; - } - terraform_region(rn, terrain); - /* the new region has an extra 20% chance to have mallorn */ - if (rng_int() % 100 < 20) fset(r, RF_MALLORN); - add_regionlist(rend, rn); - } - } - } - - } - while (*rbegin) { - region * r = (*rbegin)->data; - plane * pl = rplane(r); - direction_t d; - rbegin=&(*rbegin)->next; - for (d=0;d!=MAXDIRECTIONS;++d) if (rconnect(r, d)==NULL) { - int i; - for (i=1;i!=MAXFILLDIST;++i) { - int x = r->x + delta_x[d]*i; - int y = r->y + delta_y[d]*i; - pnormalize(&x, &y, pl); - if (findregion(x, y)) { - break; - } - } - if (i!=MAXFILLDIST) { - while (--i) { - region * rn; - int x = r->x + delta_x[d]*i; - int y = r->y + delta_y[d]*i; - pnormalize(&x, &y, pl); - rn = new_region(x, y, pl, 0); - terraform_region(rn, newterrain(T_OCEAN)); - } - } - } - } - while (rlist) { - region_list * self = rlist; - rlist = rlist->next; - freset(self->data, RF_MARK); - free(self); - } - } - return tsize; -} - -region_list * regionqueue_push(region_list ** rlist, region * r) -{ - region_list * rnew = malloc(sizeof(region_list)); - rnew->data = r; - rnew->next = 0; - while (*rlist) { rlist = &(*rlist)->next; } - *rlist = rnew; - return rnew; -} - -region * regionqueue_pop(region_list ** rlist) -{ - if (*rlist) { - region * r = (*rlist)->data; - region_list * rpop = *rlist; - *rlist = rpop->next; - free(rpop); - return r; - } - return 0; -} - -#define GEOMAX 8 -static struct geo { - int distribution; - terrain_t type; -} geography_e3[GEOMAX] = { - { 8, T_OCEAN }, - { 3, T_SWAMP }, - { 1, T_VOLCANO }, - { 3, T_DESERT }, - { 4, T_HIGHLAND }, - { 3, T_MOUNTAIN }, - { 2, T_GLACIER }, - { 1, T_PLAIN } -}; - -const terrain_type * random_terrain_e3(direction_t dir) -{ - static const terrain_type ** terrainarr = 0; - static int * distribution = 0; - - if (!distribution) { - int n = 0; - - terrainarr = malloc(GEOMAX * sizeof(const terrain_type *)); - distribution = malloc(GEOMAX * sizeof(int)); - for (n=0;n!=GEOMAX;++n) { - terrainarr[n] = newterrain(geography_e3[n].type); - distribution[n] = geography_e3[n].distribution; - } - } - return random_terrain(terrainarr, distribution, GEOMAX); -} - -int -random_neighbours(region * r, region_list ** rlist, const terrain_type *(*terraformer)(direction_t)) -{ - int nsize = 0; - direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * rn = rconnect(r, dir); - if (rn==NULL) { - const terrain_type * terrain = terraformer(dir); - plane * pl = rplane(r); - int x = r->x + delta_x[dir]; - int y = r->y + delta_y[dir]; - pnormalize(&x, &y, pl); - rn = new_region(x, y, pl, 0); - terraform_region(rn, terrain); - regionqueue_push(rlist, rn); - if (rn->land) { - ++nsize; - } - } - } - return nsize; -} - -const terrain_type * get_ocean(direction_t dir) -{ - return newterrain(T_OCEAN); -} - -int region_quality(const region * r, region * rn[]) -{ - int n, result = 0; - - for (n=0;n!=MAXDIRECTIONS;++n) { - if (rn[n] && rn[n]->land) { - if (rn[n]->terrain==newterrain(T_VOLCANO)) { - /* nobody likes volcanoes */ - result -= 2000; - } - result += rn[n]->land->peasants; - } - } - return result; -} - -static void -oceans_around(region * r, region * rn[]) -{ - int n; - for (n=0;n!=MAXDIRECTIONS;++n) { - region * rx = rn[n]; - if (rx==NULL) { - plane * pl = rplane(r); - int x = r->x + delta_x[n]; - int y = r->y + delta_y[n]; - pnormalize(&x, &y, pl); - rx = new_region(x, y, pl, 0); - terraform_region(rx, newterrain(T_OCEAN)); - rn[n] = rx; - } - } -} - -static void -smooth_island(region_list * island) -{ - region * rn[MAXDIRECTIONS]; - region_list * rlist = NULL; - for (rlist=island;rlist;rlist=rlist->next) { - region * r = rlist->data; - int n, nland = 0; - - if (r->land) { - get_neighbours(r, rn); - for (n=0;n!=MAXDIRECTIONS && nland<=1;++n) { - if (rn[n]->land) { - ++nland; - r = rn[n]; - } - } - - if (nland==1) { - get_neighbours(r, rn); - oceans_around(r, rn); - for (n=0;n!=MAXDIRECTIONS;++n) { - int n1 = (n+1)%MAXDIRECTIONS; - int n2 = (n+1+MAXDIRECTIONS)%MAXDIRECTIONS; - if (!rn[n]->land && rn[n1]!=r && rn[n2]!=r) { - r = rlist->data; - runhash(r); - runhash(rn[n]); - SWAP_VARS(int, r->x, rn[n]->x); - SWAP_VARS(int, r->y, rn[n]->y); - rhash(r); - rhash(rn[n]); - rlist->data = r; - oceans_around(r, rn); - break; - } - } - } - } - } -} - -static void -starting_region(region * r, region * rn[]) -{ - unit * u; - int n; - - oceans_around(r, rn); - freset(r, RF_MARK); - for (n=0;n!=MAXDIRECTIONS;++n) { - freset(rn[n], RF_MARK); - } - terraform_region(r, newterrain(T_PLAIN)); - prepare_starting_region(r); - u = addplayer(r, addfaction("enno@eressea.de", itoa36(rng_int()), races, - default_locale, 0)); -} -/* E3A island generation */ -int -build_island_e3(int x, int y, int numfactions, int minsize) -{ -#define MIN_QUALITY 1000 - int nfactions = 0; - region_list * rlist = NULL; - region_list * island = NULL; - plane * pl = findplane(x, y); - region * r = findregion(x, y); - int nsize = 1; - int q, maxq = INT_MIN, minq = INT_MAX; - - if (!r) r = new_region(x, y, pl, 0); - assert(!r->units); - do { - terraform_region(r, random_terrain_e3(NODIRECTION)); - } while (!r->land); - - while (r) { - fset(r, RF_MARK); - if (r->land) { - if (nsizeminsize/2) { - for (rlist=island;rlist;rlist=rlist->next) { - r = rlist->data; - if (r->land && fval(r, RF_MARK)) { - region *rn[MAXDIRECTIONS]; - - get_neighbours(r, rn); - q = region_quality(r,rn); - if (q>=MIN_QUALITY && nfactionsnext) { - r = rlist->data; - if (!r->land && fval(r, RF_MARK)) { - region *rn[MAXDIRECTIONS]; - get_neighbours(r, rn); - q = region_quality(r, rn); - if (q>=MIN_QUALITY*4/3 && nfactionsnext) { - r = rlist->data; - if (r->units) { - region *rn[MAXDIRECTIONS]; - get_neighbours(r, rn); - q = region_quality(r, rn); - if (q-minq > (maxq-minq)*2/3) { - terraform_region(r, newterrain(T_HIGHLAND)); - prepare_starting_region(r); - } - r->land->money = 50000; /* 2% = 1000 silver */ - } else if (r->land) { - r->land->money *= 4; - } - } - return nfactions; -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "autoseed.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +const terrain_type * +random_terrain(const terrain_type * terrains[], int distribution[], int size) +{ + int ndistribution = size; + const terrain_type * terrain; + int n; + + if (distribution) { + ndistribution = 0; + for (n=0;n!=size;++n) { + ndistribution += distribution[n]; + } + } + + n = rng_int() % ndistribution; + if (distribution) { + int i; + for (i=0;i!=size;++i) { + n -= distribution[i]; + if (n<0) break; + } + assert(iresources;rm;rm=rm->next) { + if (rm->type->rtype==rtype) break; + } + if (!rm) { + add_resource(r, 1, base, 150, rtype); + } + return 0; +} + + +static int +count_demand(const region *r) +{ + struct demand *dmd; + int c = 0; + if (r->land) { + for (dmd=r->land->demands;dmd;dmd=dmd->next) c++; + } + return c; +} + +static int +recurse_regions(region *r, region_list **rlist, boolean(*fun)(const region *r)) +{ + if (!fun(r)) return 0; + else { + int len = 0; + direction_t d; + region_list * rl = calloc(sizeof(region_list), 1); + rl->next = *rlist; + rl->data = r; + (*rlist) = rl; + fset(r, RF_MARK); + for (d=0;d!=MAXDIRECTIONS;++d) { + region * nr = rconnect(r, d); + if (nr && !fval(nr, RF_MARK)) len += recurse_regions(nr, rlist, fun); + } + return len+1; + } +} + +static boolean +f_nolux(const region * r) +{ + if (r->land && count_demand(r) != get_maxluxuries()) return true; + return false; +} + +int +fix_demand(region *rd) +{ + region_list *rl, *rlist = NULL; + static const struct luxury_type **mlux = 0, ** ltypes; + const luxury_type *sale = NULL; + int maxlux = 0; + int maxluxuries = get_maxluxuries(); + + if (maxluxuries==0) return 0; + recurse_regions(rd, &rlist, f_nolux); + if (mlux==0) { + int i = 0; + mlux = (const luxury_type **)gc_add(calloc(maxluxuries, sizeof(const luxury_type *))); + ltypes = (const luxury_type **)gc_add(calloc(maxluxuries, sizeof(const luxury_type *))); + for (sale=luxurytypes;sale;sale=sale->next) { + ltypes[i++] = sale; + } + } + else { + int i; + for (i=0;i!=maxluxuries;++i) mlux[i] = 0; + } + for (rl=rlist;rl;rl=rl->next) { + region * r = rl->data; + direction_t d; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * nr = rconnect(r, d); + if (nr && nr->land && nr->land->demands) { + struct demand * dmd; + for (dmd = nr->land->demands;dmd;dmd=dmd->next) { + if (dmd->value == 0) { + int i; + for (i=0;i!=maxluxuries;++i) { + if (mlux[i]==NULL) { + maxlux = i; + mlux[i] = dmd->type; + break; + } else if (mlux[i]==dmd->type) { + break; + } + } + break; + } + } + } + } + freset(r, RF_MARK); /* undo recursive marker */ + } + if (maxlux<2) { + int i; + for (i=maxlux;i!=2;++i) { + int j; + do { + int k = rng_int() % maxluxuries; + mlux[i] = ltypes[k]; + for (j=0;j!=i;++j) { + if (mlux[j]==mlux[i]) break; + } + } while (j!=i); + } + maxlux = 2; + } + for (rl=rlist;rl;rl=rl->next) { + region * r = rl->data; + if (!fval(r, RF_CHAOTIC)) { + log_info((LOG_INFO1, "fixing demand in %s\n", regionname(r, NULL))); + } + sale = mlux[rng_int() % maxlux]; + if (sale) setluxuries(r, sale); + } + while (rlist) { + rl = rlist->next; + free(rlist); + rlist = rl; + } + return 0; +} + +/* nach 150 Runden ist Neustart erlaubt */ +#define MINAGE_MULTI 150 +newfaction * +read_newfactions(const char * filename) +{ + newfaction * newfactions = NULL; + FILE * F = fopen(filename, "r"); + char buf[1024]; + + if (F==NULL) return NULL; + for (;;) { + faction * f; + char race[20], email[64], lang[8], password[16]; + newfaction *nf, **nfi; + int bonus = 0, subscription = 0; + int alliance = 0; + + if (fgets(buf, sizeof(buf), F)==NULL) break; + + email[0] = '\0'; + password[0] = '\0'; + + if (sscanf(buf, "%54s %20s %8s %d %d %16s %d", email, race, lang, &bonus, &subscription, password, &alliance)<6) break; + if (email[0]=='\0') break; + if (password[0]=='\0') { + strcpy(password, itoa36(rng_int())); + strcat(password, itoa36(rng_int())); + } + for (f=factions;f;f=f->next) { + if (strcmp(f->email, email)==0 && f->subscription && f->ageunits) continue; /* skip the ones we've already got */ + for (nf=newfactions;nf;nf=nf->next) { + if (strcmp(nf->email, email)==0) break; + } + if (nf) continue; + nf = calloc(sizeof(newfaction), 1); + if (set_email(&nf->email, email)!=0) { + log_error(("Invalid email address for subscription %s: %s\n", + itoa36(subscription), email)); + continue; + } + nf->password = strdup(password); + nf->race = rc_find(race); + nf->subscription = subscription; + if (alliances!=NULL) { + struct alliance * al = findalliance(alliance); + if (al==NULL) { + char zText[64]; + sprintf(zText, "Allianz %d", alliance); + al = makealliance(alliance, zText); + } + nf->allies = al; + } else { + nf->allies = NULL; + } + if (nf->race==NULL) { + /* if the script didn't supply the race as a token, then it gives us a + * race in the default locale (which means that itis a UTF8 string) */ + nf->race = findrace(race, default_locale); + if (nf->race==NULL) { + char buffer[32]; + size_t outbytes = sizeof(buffer) - 1; + size_t inbytes = strlen(race); + unicode_latin1_to_utf8(buffer, &outbytes, race, &inbytes); + buffer[outbytes] = 0; + nf->race = findrace(buffer, default_locale); + if (nf->race==NULL) { + log_error(("new faction has unknown race '%s'.\n", race)); + free(nf); + continue; + } + } + } + nf->lang = find_locale(lang); + nf->bonus = bonus; + assert(nf->race && nf->email && nf->lang); + nfi = &newfactions; + while (*nfi) { + if ((*nfi)->race==nf->race) break; + nfi=&(*nfi)->next; + } + nf->next = *nfi; + *nfi = nf; + } + fclose(F); + return newfactions; +} + +extern int numnewbies; + +static const terrain_type * +preferred_terrain(const struct race * rc) +{ + terrain_t t = T_PLAIN; + if (rc==rc_find("dwarf")) t = T_MOUNTAIN; + if (rc==rc_find("insect")) t = T_DESERT; + if (rc==rc_find("halfling")) t = T_SWAMP; + if (rc==rc_find("troll")) t = T_MOUNTAIN; + return newterrain(t); +} + +#define REGIONS_PER_FACTION 2 +#define PLAYERS_PER_ISLAND 20 +#define MAXISLANDSIZE 50 +#define MINFACTIONS 1 +#define VOLCANO_CHANCE 100 + +static boolean +virgin_region(const region * r) +{ + direction_t d; + if (r==NULL) return true; + if (fval(r->terrain, FORBIDDEN_REGION)) return false; + if (r->units) return false; + for (d=0;d!=MAXDIRECTIONS;++d) { + const region * rn = rconnect(r, d); + if (rn) { + if (rn->age>r->age+1) return false; + if (rn->units) return false; + if (fval(rn->terrain, FORBIDDEN_REGION)) { + /* because it kinda sucks to have islands that are adjacent to a firewall */ + return false; + } + } + } + return true; +} + +void +get_island(region * root, region_list ** rlist) +{ + region_list ** rnext = rlist; + while (*rnext) rnext=&(*rnext)->next; + + fset(root, RF_MARK); + add_regionlist(rnext, root); + + while (*rnext) { + direction_t dir; + + region * rcurrent = (*rnext)->data; + rnext = &(*rnext)->next; + + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * r = rconnect(rcurrent, dir); + if (r!=NULL && r->land && !fval(r, RF_MARK)) { + fset(r, RF_MARK); + add_regionlist(rnext, r); + } + } + } + rnext=rlist; + while (*rnext) { + region_list * rptr = *rnext; + freset(rptr->data, RF_MARK); + rnext = &rptr->next; + } +} + +static void +get_island_info(region * root, int * size_p, int * inhabited_p, int * maxage_p) +{ + int size = 0, maxage = 0, inhabited = 0; + region_list * rlist = NULL; + region_list * island = NULL; + add_regionlist(&rlist, root); + island = rlist; + fset(root, RF_MARK); + while (rlist) { + direction_t d; + region * r = rlist->data; + if (r->units) { + unit * u; + for (u=r->units; u; u=u->next) { + if (!is_monsters(u->faction) && u->faction->age > maxage) { + maxage = u->faction->age; + } + } + ++inhabited; + } + ++size; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(r, d); + if (rn && !fval(rn, RF_MARK) && rn->land) { + region_list * rnew = malloc(sizeof(region_list)); + rnew->data = rn; + rnew->next = rlist->next; + rlist->next = rnew; + fset(rn, RF_MARK); + } + } + rlist = rlist->next; + } + for (rlist=island;rlist;rlist=rlist->next) { + freset(rlist->data, RF_MARK); + } + free_regionlist(island); + if (size_p) *size_p = size; + if (inhabited_p) *inhabited_p = inhabited; + if (maxage_p) *maxage_p = maxage; +} + +void +free_newfaction(newfaction * nf) +{ + free(nf->email); + free(nf->password); + free(nf); +} + +static void +frame_regions(int age, const terrain_type * terrain) +{ + plane * hplane = get_homeplane(); + region * r = regions; + for (r=regions;r;r=r->next) { + plane * pl = rplane(r); + direction_t d; + if (r->ageterrain == terrain) continue; + + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(r, d); + if (rn==NULL) { + int x = r->x + delta_x[d]; + int y = r->y + delta_y[d]; + pnormalize(&x, &y, pl); + rn = new_region(x, y, pl, 0); + terraform_region(rn, terrain); + rn->age=r->age; + } + } + } +} + +static void +prepare_starting_region(region * r) +{ + int n, t; + double p; + + assert(r->land); + + /* population between 30% and 60% of max */ + p = rng_double(); + n = (int)(r->terrain->size * (0.3 + p*0.3)); + rsetpeasants(r, n); + + /* trees: don't squash the peasants, and at least 5% should be forrest */ + t = (rtrees(r, 2) + rtrees(r, 1)/2) * TREESIZE; + if (t < r->terrain->size/20 || t+n > r->terrain->size) { + double p2 = 0.05 + rng_double()*(1.0-p-0.05); + int maxtrees = (int)(r->terrain->size/1.25/TREESIZE); /* 1.25 = each young tree will take 1/2 the space of old trees */ + int trees = (int)(p2 * maxtrees); + + rsettrees(r, 2, trees); + rsettrees(r, 1, trees/2); + rsettrees(r, 0, trees/4); + } + + /* horses: between 1% and 2% */ + p = rng_double(); + rsethorses(r, (int)(r->terrain->size * (0.01 + p*0.01))); + + if (!markets_module()) { + fix_demand(r); + } +} + +/** create new island with up to nsize players + * returns the number of players placed on the new island. + */ +int +autoseed(newfaction ** players, int nsize, int max_agediff) +{ + region * r = NULL; + region_list * rlist = NULL; + int rsize = 0, tsize = 0; + int isize = REGIONS_PER_FACTION; /* target size for the island */ + int psize = 0; /* players on this island */ + const terrain_type * volcano_terrain = get_terrain("volcano"); + static int nterrains = -1; + static const terrain_type ** terrainarr = 0; + static int * distribution; + + if (nterrains<0) { + int n = 0; + const terrain_type * terrain = terrains(); + for (nterrains=0;terrain;terrain=terrain->next) { + if (terrain->distribution) { + ++nterrains; + } + } + terrainarr = malloc(sizeof(terrain_type *) * nterrains); + distribution = malloc(sizeof(int) * nterrains); + for (terrain = terrains();terrain;terrain = terrain->next) { + if (terrain->distribution) { + terrainarr[n] = terrain; + distribution[n++] = terrain->distribution; + } + } + } + frame_regions(16, newterrain(T_FIREWALL)); + + if (listlen(*players)0) { + region * rmin = NULL; + plane * hplane = get_homeplane(); + /* find a spot that's adjacent to the previous island, but virgin. + * like the last land virgin ocean region adjacent to land. + */ + for (r=regions;r;r=r->next) { + struct plane * pl = rplane(r); + if (r->age<=max_agediff && r->terrain == newterrain(T_OCEAN) && pl==hplane && virgin_region(r)) { + direction_t d; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(r, d); + if (rn && rn->land && rn->age<=max_agediff && virgin_region(rn)) { + /* only expand islands that aren't single-islands and not too big already */ + int size, inhabitants, maxage; + get_island_info(rn, &size, &inhabitants, &maxage); + if (maxage<=max_agediff && size>=2 && sizenext) { + region * r = rlist->data; + unit * u; + for (u=r->units;u;u=u->next) { + f = u->faction; + if (!fval(f, FFL_MARK)) { + ++psize; + fset(f, FFL_MARK); + } + } + } + free_regionlist(rlist); + if (psize>0) for (f=factions;f;f=f->next) freset(f, FFL_MARK); + if (psizenext) { + struct plane * pl = rplane(r); + if (r->terrain == newterrain(T_OCEAN) && pl==hplane && (rmin==NULL || r->age<=max_agediff)) { + direction_t d; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(r, d); + if (rn==NULL) break; + } + if (d!=MAXDIRECTIONS) { + rmin=r; + dmin=d; + } + } + } + + /* create a new region where we found the empty spot, and make it the first + * in our island. island regions are kept in rlist, so only new regions can + * get populated, and old regions are not overwritten */ + if (rmin!=NULL) { + plane * pl = rplane(rmin); + int x = rmin->x + delta_x[dmin]; + int y = rmin->y + delta_y[dmin]; + pnormalize(&x, &y, pl); + assert(virgin_region(rconnect(rmin, dmin))); + r = new_region(x, y, pl, 0); + terraform_region(r, newterrain(T_OCEAN)); + } + } + if (r!=NULL) { + add_regionlist(&rlist, r); + fset(r, RF_MARK); + rsize = 1; + } + + while (rsize && (nsize || isize>=REGIONS_PER_FACTION)) { + int i = rng_int() % rsize; + region_list ** rnext = &rlist; + region_list * rfind; + direction_t d; + while (i--) rnext=&(*rnext)->next; + rfind = *rnext; + r = rfind->data; + freset(r, RF_MARK); + *rnext = rfind->next; + free(rfind); + --rsize; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(r, d); + if (rn && fval(rn, RF_MARK)) continue; + if (rn==NULL) { + plane * pl = rplane(r); + int x = r->x + delta_x[d]; + int y = r->y + delta_y[d]; + pnormalize(&x, &y, pl); + rn = new_region(x, y, pl, 0); + terraform_region(rn, newterrain(T_OCEAN)); + } + if (virgin_region(rn)) { + add_regionlist(&rlist, rn); + fset(rn, RF_MARK); + ++rsize; + } + } + if (volcano_terrain!=NULL && (rng_int() % VOLCANO_CHANCE == 0)) { + terraform_region(r, volcano_terrain); + } else if (nsize && (rng_int() % isize == 0 || rsize==0)) { + newfaction ** nfp, * nextf = *players; + faction * f; + unit * u; + + isize += REGIONS_PER_FACTION; + terraform_region(r, preferred_terrain(nextf->race)); + prepare_starting_region(r); + ++tsize; + assert(r->land && r->units==0); + u = addplayer(r, addfaction(nextf->email, nextf->password, nextf->race, + nextf->lang, nextf->subscription)); + f = u->faction; + fset(f, FFL_ISNEW); + f->alliance = nextf->allies; + log_printf("New faction (%s), %s at %s\n", itoa36(f->no), + f->email, regionname(r, NULL)); + if (f->subscription) { + sql_print(("UPDATE subscriptions SET status='ACTIVE', faction='%s', firstturn=%d, lastturn=%d, password='%s' WHERE id=%u;\n", + factionid(f), f->lastorders, f->lastorders, f->override, f->subscription)); + } + + /* remove duplicate email addresses */ + nfp = &nextf->next; + while (*nfp) { + newfaction * nf = *nfp; + if (strcmp(nextf->email, nf->email)==0) { + *nfp = nf->next; + free_newfaction(nf); + } + else nfp = &nf->next; + } + *players = nextf->next; + free_newfaction(nextf); + + ++psize; + --nsize; + --isize; + if (psize>=PLAYERS_PER_ISLAND) break; + } else { + terraform_region(r, random_terrain(terrainarr, distribution, nterrains)); + --isize; + } + } + + if (nsize!=0) { + log_error(("Could not place all factions on the same island as requested\n")); + } + + + if (rlist) { +#define MINOCEANDIST 3 +#define MAXOCEANDIST 6 +#define MAXFILLDIST 10 +#define SPECIALCHANCE 80 + region_list ** rbegin = &rlist; + int special = 1; + int oceandist = MINOCEANDIST + (rng_int() % (MAXOCEANDIST-MINOCEANDIST)); + while (oceandist--) { + region_list ** rend = rbegin; + while (*rend) rend=&(*rend)->next; + while (rbegin!=rend) { + direction_t d; + region * r = (*rbegin)->data; + rbegin=&(*rbegin)->next; + for (d=0;d!=MAXDIRECTIONS;++d) { + region * rn = rconnect(r, d); + if (rn==NULL) { + const struct terrain_type * terrain = newterrain(T_OCEAN); + plane * pl = rplane(r); + int x = r->x + delta_x[d]; + int y = r->y + delta_y[d]; + pnormalize(&x, &y, pl); + rn = new_region(x, y, pl, 0); + if (rng_int() % SPECIALCHANCE < special) { + terrain = random_terrain(terrainarr, distribution, nterrains); + special = SPECIALCHANCE / 3; /* 33% chance auf noch eines */ + } else { + special = 1; + } + terraform_region(rn, terrain); + /* the new region has an extra 20% chance to have mallorn */ + if (rng_int() % 100 < 20) fset(r, RF_MALLORN); + add_regionlist(rend, rn); + } + } + } + + } + while (*rbegin) { + region * r = (*rbegin)->data; + plane * pl = rplane(r); + direction_t d; + rbegin=&(*rbegin)->next; + for (d=0;d!=MAXDIRECTIONS;++d) if (rconnect(r, d)==NULL) { + int i; + for (i=1;i!=MAXFILLDIST;++i) { + int x = r->x + delta_x[d]*i; + int y = r->y + delta_y[d]*i; + pnormalize(&x, &y, pl); + if (findregion(x, y)) { + break; + } + } + if (i!=MAXFILLDIST) { + while (--i) { + region * rn; + int x = r->x + delta_x[d]*i; + int y = r->y + delta_y[d]*i; + pnormalize(&x, &y, pl); + rn = new_region(x, y, pl, 0); + terraform_region(rn, newterrain(T_OCEAN)); + } + } + } + } + while (rlist) { + region_list * self = rlist; + rlist = rlist->next; + freset(self->data, RF_MARK); + free(self); + } + } + return tsize; +} + +region_list * regionqueue_push(region_list ** rlist, region * r) +{ + region_list * rnew = malloc(sizeof(region_list)); + rnew->data = r; + rnew->next = 0; + while (*rlist) { rlist = &(*rlist)->next; } + *rlist = rnew; + return rnew; +} + +region * regionqueue_pop(region_list ** rlist) +{ + if (*rlist) { + region * r = (*rlist)->data; + region_list * rpop = *rlist; + *rlist = rpop->next; + free(rpop); + return r; + } + return 0; +} + +#define GEOMAX 8 +static struct geo { + int distribution; + terrain_t type; +} geography_e3[GEOMAX] = { + { 8, T_OCEAN }, + { 3, T_SWAMP }, + { 1, T_VOLCANO }, + { 3, T_DESERT }, + { 4, T_HIGHLAND }, + { 3, T_MOUNTAIN }, + { 2, T_GLACIER }, + { 1, T_PLAIN } +}; + +const terrain_type * random_terrain_e3(direction_t dir) +{ + static const terrain_type ** terrainarr = 0; + static int * distribution = 0; + + if (!distribution) { + int n = 0; + + terrainarr = malloc(GEOMAX * sizeof(const terrain_type *)); + distribution = malloc(GEOMAX * sizeof(int)); + for (n=0;n!=GEOMAX;++n) { + terrainarr[n] = newterrain(geography_e3[n].type); + distribution[n] = geography_e3[n].distribution; + } + } + return random_terrain(terrainarr, distribution, GEOMAX); +} + +int +random_neighbours(region * r, region_list ** rlist, const terrain_type *(*terraformer)(direction_t)) +{ + int nsize = 0; + direction_t dir; + for (dir=0;dir!=MAXDIRECTIONS;++dir) { + region * rn = rconnect(r, dir); + if (rn==NULL) { + const terrain_type * terrain = terraformer(dir); + plane * pl = rplane(r); + int x = r->x + delta_x[dir]; + int y = r->y + delta_y[dir]; + pnormalize(&x, &y, pl); + rn = new_region(x, y, pl, 0); + terraform_region(rn, terrain); + regionqueue_push(rlist, rn); + if (rn->land) { + ++nsize; + } + } + } + return nsize; +} + +const terrain_type * get_ocean(direction_t dir) +{ + return newterrain(T_OCEAN); +} + +int region_quality(const region * r, region * rn[]) +{ + int n, result = 0; + + for (n=0;n!=MAXDIRECTIONS;++n) { + if (rn[n] && rn[n]->land) { + if (rn[n]->terrain==newterrain(T_VOLCANO)) { + /* nobody likes volcanoes */ + result -= 2000; + } + result += rn[n]->land->peasants; + } + } + return result; +} + +static void +oceans_around(region * r, region * rn[]) +{ + int n; + for (n=0;n!=MAXDIRECTIONS;++n) { + region * rx = rn[n]; + if (rx==NULL) { + plane * pl = rplane(r); + int x = r->x + delta_x[n]; + int y = r->y + delta_y[n]; + pnormalize(&x, &y, pl); + rx = new_region(x, y, pl, 0); + terraform_region(rx, newterrain(T_OCEAN)); + rn[n] = rx; + } + } +} + +static void +smooth_island(region_list * island) +{ + region * rn[MAXDIRECTIONS]; + region_list * rlist = NULL; + for (rlist=island;rlist;rlist=rlist->next) { + region * r = rlist->data; + int n, nland = 0; + + if (r->land) { + get_neighbours(r, rn); + for (n=0;n!=MAXDIRECTIONS && nland<=1;++n) { + if (rn[n]->land) { + ++nland; + r = rn[n]; + } + } + + if (nland==1) { + get_neighbours(r, rn); + oceans_around(r, rn); + for (n=0;n!=MAXDIRECTIONS;++n) { + int n1 = (n+1)%MAXDIRECTIONS; + int n2 = (n+1+MAXDIRECTIONS)%MAXDIRECTIONS; + if (!rn[n]->land && rn[n1]!=r && rn[n2]!=r) { + r = rlist->data; + runhash(r); + runhash(rn[n]); + SWAP_VARS(int, r->x, rn[n]->x); + SWAP_VARS(int, r->y, rn[n]->y); + rhash(r); + rhash(rn[n]); + rlist->data = r; + oceans_around(r, rn); + break; + } + } + } + } + } +} + +static void +starting_region(region * r, region * rn[]) +{ + unit * u; + int n; + + oceans_around(r, rn); + freset(r, RF_MARK); + for (n=0;n!=MAXDIRECTIONS;++n) { + freset(rn[n], RF_MARK); + } + terraform_region(r, newterrain(T_PLAIN)); + prepare_starting_region(r); + u = addplayer(r, addfaction("enno@eressea.de", itoa36(rng_int()), races, + default_locale, 0)); +} +/* E3A island generation */ +int +build_island_e3(int x, int y, int numfactions, int minsize) +{ +#define MIN_QUALITY 1000 + int nfactions = 0; + region_list * rlist = NULL; + region_list * island = NULL; + plane * pl = findplane(x, y); + region * r = findregion(x, y); + int nsize = 1; + int q, maxq = INT_MIN, minq = INT_MAX; + + if (!r) r = new_region(x, y, pl, 0); + assert(!r->units); + do { + terraform_region(r, random_terrain_e3(NODIRECTION)); + } while (!r->land); + + while (r) { + fset(r, RF_MARK); + if (r->land) { + if (nsizeminsize/2) { + for (rlist=island;rlist;rlist=rlist->next) { + r = rlist->data; + if (r->land && fval(r, RF_MARK)) { + region *rn[MAXDIRECTIONS]; + + get_neighbours(r, rn); + q = region_quality(r,rn); + if (q>=MIN_QUALITY && nfactionsnext) { + r = rlist->data; + if (!r->land && fval(r, RF_MARK)) { + region *rn[MAXDIRECTIONS]; + get_neighbours(r, rn); + q = region_quality(r, rn); + if (q>=MIN_QUALITY*4/3 && nfactionsnext) { + r = rlist->data; + if (r->units) { + region *rn[MAXDIRECTIONS]; + get_neighbours(r, rn); + q = region_quality(r, rn); + if (q-minq > (maxq-minq)*2/3) { + terraform_region(r, newterrain(T_HIGHLAND)); + prepare_starting_region(r); + } + r->land->money = 50000; /* 2% = 1000 silver */ + } else if (r->land) { + r->land->money *= 4; + } + } + return nfactions; +} diff --git a/src/modules/autoseed.h b/src/modules/autoseed.h index 2c023f3f4..0fcb75da5 100644 --- a/src/modules/autoseed.h +++ b/src/modules/autoseed.h @@ -1,50 +1,50 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef _REGIONLIST_H -#define _REGIONLIST_H -#ifdef __cplusplus -extern "C" { -#endif - - -struct region_list; -struct newfaction; - -typedef struct newfaction { - struct newfaction * next; - char * email; - char * password; - const struct locale * lang; - const struct race * race; - int bonus; - int subscription; - boolean oldregions; - struct alliance * allies; -} newfaction; - -#define ISLANDSIZE 20 -#define TURNS_PER_ISLAND 5 - -extern int autoseed(newfaction ** players, int nsize, int max_agediff); -extern newfaction * read_newfactions(const char * filename); -extern void get_island(struct region * root, struct region_list ** rlist); -extern int fix_demand(struct region *r); -extern const struct terrain_type * random_terrain(const struct terrain_type * terrains[], int distribution[], int size); - -extern int seed_adamantium(struct region * r, int base); -extern int build_island_e3(int x, int y, int numfactions, int minsize); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef _REGIONLIST_H +#define _REGIONLIST_H +#ifdef __cplusplus +extern "C" { +#endif + + +struct region_list; +struct newfaction; + +typedef struct newfaction { + struct newfaction * next; + char * email; + char * password; + const struct locale * lang; + const struct race * race; + int bonus; + int subscription; + boolean oldregions; + struct alliance * allies; +} newfaction; + +#define ISLANDSIZE 20 +#define TURNS_PER_ISLAND 5 + +extern int autoseed(newfaction ** players, int nsize, int max_agediff); +extern newfaction * read_newfactions(const char * filename); +extern void get_island(struct region * root, struct region_list ** rlist); +extern int fix_demand(struct region *r); +extern const struct terrain_type * random_terrain(const struct terrain_type * terrains[], int distribution[], int size); + +extern int seed_adamantium(struct region * r, int base); +extern int build_island_e3(int x, int y, int numfactions, int minsize); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/dungeon.c b/src/modules/dungeon.c index c8a5fb6a9..a8275bbda 100644 --- a/src/modules/dungeon.c +++ b/src/modules/dungeon.c @@ -1,268 +1,268 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include - -#if DUNGEON_MODULE -#include "dungeon.h" -#include "gmcmd.h" - -#include -#include - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include - -/* libc includes */ -#include -#include -#include - -typedef struct treasure { - const struct item_type * itype; - int amount; - struct treasure * next; -} treasure; - -typedef struct monster { - const struct race * race; - double chance; - int maxunits; - int avgsize; - struct treasure * treasures; - struct monster * next; - struct itemtype_list * weapons; -} monster; - -typedef struct skilllimit { - skill_t skill; - int minskill; - int maxskill; - struct skilllimit * next; -} skilllimit; - -typedef struct dungeon { - int level; - int radius; - int size; - int maxpeople; - struct skilllimit * limits; - double connect; - struct monster * boss; - struct monster * monsters; - struct dungeon * next; -} dungeon; - -dungeon * dungeonstyles; - -region * -make_dungeon(const dungeon * data) -{ - int nb[2][3][2] = { - { { -1, 0 }, { 0, 1 }, { 1, -1 } }, - { { 1, 0 }, { -1, 1 }, { 0, -1 } } - }; - const struct race * bossrace = data->boss->race; - char name[128]; - int size = data->size; - int iterations = size * size; - unsigned int flags = PFL_NORECRUITS; - int n = 0; - struct faction * fmonsters = get_monsters(); - plane * p; - region *r, *center; - region * rnext; - region_list * iregion, * rlist = NULL; - const terrain_type * terrain_hell = get_terrain("hell"); - - assert(terrain_hell!=NULL); - sprintf(name, "Die Höhlen von %s", bossrace->generate_name(NULL)); - p = gm_addplane(data->radius, flags, name); - - center = findregion(p->minx+(p->maxx-p->minx)/2, p->miny+(p->maxy-p->miny)/2); - assert(center); - terraform_region(center, terrain_hell); - add_regionlist(&rlist, center); - rnext = r = center; - while (size>0 && iterations--) { - int d, o = rng_int() % 3; - for (d=0;d!=3;++d) { - int index = (d+o) % 3; - region * rn = findregion(r->x+nb[n][index][0], r->y+nb[n][index][1]); - assert(r->terrain==terrain_hell); - if (rn) { - if (rn->terrain==terrain_hell) { - rnext = rn; - } else if (fval(rn->terrain, SEA_REGION)) { - if (rng_int() % 100 < data->connect*100) { - terraform_region(rn, terrain_hell); - --size; - rnext = rn; - add_regionlist(&rlist, rn); - } - else terraform(rn, T_FIREWALL); - } - if (size == 0) break; - } - rn = findregion(r->x+nb[(n+1)%2][index][0], r->y+nb[(n+1)%2][index][1]); - if (rn && fval(rn->terrain, SEA_REGION)) { - terraform(rn, T_FIREWALL); - } - } - if (size==0) break; - if (r==rnext) { - /* error */ - break; - } - r = rnext; - n = (n+1) % 2; - } - - for (iregion=rlist;iregion;iregion=iregion->next) { - monster * m = data->monsters; - region * r = iregion->data; - while (m) { - if ((rng_int() % 100) < (m->chance * 100)) { - /* TODO: check maxunits. */ - treasure * loot = m->treasures; - struct itemtype_list * weapon = m->weapons; - int size = 1 + (rng_int() % m->avgsize) + (rng_int() % m->avgsize); - unit * u = createunit(r, fmonsters, size, m->race); - while (weapon) { - i_change(&u->items, weapon->type, size); - weapon = weapon->next; - } - while (loot) { - i_change(&u->items, loot->itype, loot->amount*size); - loot = loot->next; - } - } - m = m->next; - } - } - return center; -} - -void -make_dungeongate(region * source, region * target, const struct dungeon * d) -{ - building *bsource, *btarget; - - if (source==NULL || target==NULL || d==NULL) return; - bsource = new_building(bt_find("castle"), source, default_locale); - set_string(&bsource->name, "Pforte zur Hölle"); - bsource->size = 50; - add_trigger(&bsource->attribs, "timer", trigger_gate(bsource, target)); - add_trigger(&bsource->attribs, "create", trigger_unguard(bsource)); - fset(bsource, BLD_UNGUARDED); - - btarget = new_building(bt_find("castle"), target, default_locale); - set_string(&btarget->name, "Pforte zur Außenwelt"); - btarget->size = 50; - add_trigger(&btarget->attribs, "timer", trigger_gate(btarget, source)); - add_trigger(&btarget->attribs, "create", trigger_unguard(btarget)); - fset(btarget, BLD_UNGUARDED); -} - -static int -tagbegin(xml_stack *stack) -{ - xml_tag * tag = stack->tag; - if (strcmp(tag->name, "dungeon")==0) { - dungeon * d = (dungeon*)calloc(sizeof(dungeon), 1); - d->maxpeople = xml_ivalue(tag, "maxpeople"); - if (d->maxpeople==0) d->maxpeople = INT_MAX; - d->level = xml_ivalue(tag, "level"); - d->radius = xml_ivalue(tag, "radius"); - d->connect = xml_fvalue(tag, "connect"); - d->size = xml_ivalue(tag, "size"); - stack->state = d; - } else { - dungeon * d = (dungeon*)stack->state; - if (strcmp(tag->name, "skilllimit")==0) { - skill_t sk = sk_find(xml_value(tag, "name")); - if (sk!=NOSKILL) { - skilllimit * skl = calloc(sizeof(skilllimit), 1); - skl->skill = sk; - if (xml_value(tag, "max")!=NULL) { - skl->maxskill = xml_ivalue(tag, "max"); - } else skl->maxskill = INT_MAX; - if (xml_value(tag, "min")!=NULL) { - skl->minskill = xml_ivalue(tag, "min"); - } else skl->maxskill = INT_MIN; - skl->next = d->limits; - d->limits = skl; - } - } else if (strcmp(tag->name, "monster")==0) { - monster * m = calloc(sizeof(monster), 1); - m->race = rc_find(xml_value(tag, "race")); - m->chance = xml_fvalue(tag, "chance"); - m->avgsize = MAX(1, xml_ivalue(tag, "size")); - m->maxunits = MIN(1, xml_ivalue(tag, "maxunits")); - - if (m->race) { - if (xml_bvalue(tag, "boss")) { - d->boss = m; - } else { - m->next = d->monsters; - d->monsters = m; - } - } - } else if (strcmp(tag->name, "weapon")==0) { - monster * m = d->monsters; - itemtype_list * w = calloc(sizeof(itemtype_list), 1); - w->type = it_find(xml_value(tag, "type")); - if (w->type) { - w->next = m->weapons; - m->weapons = w; - } - } - } - return XML_OK; -} - -static int -tagend(xml_stack * stack) -{ - xml_tag * tag = stack->tag; - if (strcmp(tag->name, "dungeon")) { - dungeon * d = (dungeon*)stack->state; - stack->state = NULL; - d->next = dungeonstyles; - dungeonstyles = d; - } - return XML_OK; -} - -xml_callbacks xml_dungeon = { - tagbegin, tagend, NULL -}; - -void -register_dungeon(void) -{ - xml_register(&xml_dungeon, "eressea dungeon", 0); -} - -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include + +#if DUNGEON_MODULE +#include "dungeon.h" +#include "gmcmd.h" + +#include +#include + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include + +/* libc includes */ +#include +#include +#include + +typedef struct treasure { + const struct item_type * itype; + int amount; + struct treasure * next; +} treasure; + +typedef struct monster { + const struct race * race; + double chance; + int maxunits; + int avgsize; + struct treasure * treasures; + struct monster * next; + struct itemtype_list * weapons; +} monster; + +typedef struct skilllimit { + skill_t skill; + int minskill; + int maxskill; + struct skilllimit * next; +} skilllimit; + +typedef struct dungeon { + int level; + int radius; + int size; + int maxpeople; + struct skilllimit * limits; + double connect; + struct monster * boss; + struct monster * monsters; + struct dungeon * next; +} dungeon; + +dungeon * dungeonstyles; + +region * +make_dungeon(const dungeon * data) +{ + int nb[2][3][2] = { + { { -1, 0 }, { 0, 1 }, { 1, -1 } }, + { { 1, 0 }, { -1, 1 }, { 0, -1 } } + }; + const struct race * bossrace = data->boss->race; + char name[128]; + int size = data->size; + int iterations = size * size; + unsigned int flags = PFL_NORECRUITS; + int n = 0; + struct faction * fmonsters = get_monsters(); + plane * p; + region *r, *center; + region * rnext; + region_list * iregion, * rlist = NULL; + const terrain_type * terrain_hell = get_terrain("hell"); + + assert(terrain_hell!=NULL); + sprintf(name, "Die Höhlen von %s", bossrace->generate_name(NULL)); + p = gm_addplane(data->radius, flags, name); + + center = findregion(p->minx+(p->maxx-p->minx)/2, p->miny+(p->maxy-p->miny)/2); + assert(center); + terraform_region(center, terrain_hell); + add_regionlist(&rlist, center); + rnext = r = center; + while (size>0 && iterations--) { + int d, o = rng_int() % 3; + for (d=0;d!=3;++d) { + int index = (d+o) % 3; + region * rn = findregion(r->x+nb[n][index][0], r->y+nb[n][index][1]); + assert(r->terrain==terrain_hell); + if (rn) { + if (rn->terrain==terrain_hell) { + rnext = rn; + } else if (fval(rn->terrain, SEA_REGION)) { + if (rng_int() % 100 < data->connect*100) { + terraform_region(rn, terrain_hell); + --size; + rnext = rn; + add_regionlist(&rlist, rn); + } + else terraform(rn, T_FIREWALL); + } + if (size == 0) break; + } + rn = findregion(r->x+nb[(n+1)%2][index][0], r->y+nb[(n+1)%2][index][1]); + if (rn && fval(rn->terrain, SEA_REGION)) { + terraform(rn, T_FIREWALL); + } + } + if (size==0) break; + if (r==rnext) { + /* error */ + break; + } + r = rnext; + n = (n+1) % 2; + } + + for (iregion=rlist;iregion;iregion=iregion->next) { + monster * m = data->monsters; + region * r = iregion->data; + while (m) { + if ((rng_int() % 100) < (m->chance * 100)) { + /* TODO: check maxunits. */ + treasure * loot = m->treasures; + struct itemtype_list * weapon = m->weapons; + int size = 1 + (rng_int() % m->avgsize) + (rng_int() % m->avgsize); + unit * u = createunit(r, fmonsters, size, m->race); + while (weapon) { + i_change(&u->items, weapon->type, size); + weapon = weapon->next; + } + while (loot) { + i_change(&u->items, loot->itype, loot->amount*size); + loot = loot->next; + } + } + m = m->next; + } + } + return center; +} + +void +make_dungeongate(region * source, region * target, const struct dungeon * d) +{ + building *bsource, *btarget; + + if (source==NULL || target==NULL || d==NULL) return; + bsource = new_building(bt_find("castle"), source, default_locale); + set_string(&bsource->name, "Pforte zur Hölle"); + bsource->size = 50; + add_trigger(&bsource->attribs, "timer", trigger_gate(bsource, target)); + add_trigger(&bsource->attribs, "create", trigger_unguard(bsource)); + fset(bsource, BLD_UNGUARDED); + + btarget = new_building(bt_find("castle"), target, default_locale); + set_string(&btarget->name, "Pforte zur Außenwelt"); + btarget->size = 50; + add_trigger(&btarget->attribs, "timer", trigger_gate(btarget, source)); + add_trigger(&btarget->attribs, "create", trigger_unguard(btarget)); + fset(btarget, BLD_UNGUARDED); +} + +static int +tagbegin(xml_stack *stack) +{ + xml_tag * tag = stack->tag; + if (strcmp(tag->name, "dungeon")==0) { + dungeon * d = (dungeon*)calloc(sizeof(dungeon), 1); + d->maxpeople = xml_ivalue(tag, "maxpeople"); + if (d->maxpeople==0) d->maxpeople = INT_MAX; + d->level = xml_ivalue(tag, "level"); + d->radius = xml_ivalue(tag, "radius"); + d->connect = xml_fvalue(tag, "connect"); + d->size = xml_ivalue(tag, "size"); + stack->state = d; + } else { + dungeon * d = (dungeon*)stack->state; + if (strcmp(tag->name, "skilllimit")==0) { + skill_t sk = sk_find(xml_value(tag, "name")); + if (sk!=NOSKILL) { + skilllimit * skl = calloc(sizeof(skilllimit), 1); + skl->skill = sk; + if (xml_value(tag, "max")!=NULL) { + skl->maxskill = xml_ivalue(tag, "max"); + } else skl->maxskill = INT_MAX; + if (xml_value(tag, "min")!=NULL) { + skl->minskill = xml_ivalue(tag, "min"); + } else skl->maxskill = INT_MIN; + skl->next = d->limits; + d->limits = skl; + } + } else if (strcmp(tag->name, "monster")==0) { + monster * m = calloc(sizeof(monster), 1); + m->race = rc_find(xml_value(tag, "race")); + m->chance = xml_fvalue(tag, "chance"); + m->avgsize = MAX(1, xml_ivalue(tag, "size")); + m->maxunits = MIN(1, xml_ivalue(tag, "maxunits")); + + if (m->race) { + if (xml_bvalue(tag, "boss")) { + d->boss = m; + } else { + m->next = d->monsters; + d->monsters = m; + } + } + } else if (strcmp(tag->name, "weapon")==0) { + monster * m = d->monsters; + itemtype_list * w = calloc(sizeof(itemtype_list), 1); + w->type = it_find(xml_value(tag, "type")); + if (w->type) { + w->next = m->weapons; + m->weapons = w; + } + } + } + return XML_OK; +} + +static int +tagend(xml_stack * stack) +{ + xml_tag * tag = stack->tag; + if (strcmp(tag->name, "dungeon")) { + dungeon * d = (dungeon*)stack->state; + stack->state = NULL; + d->next = dungeonstyles; + dungeonstyles = d; + } + return XML_OK; +} + +xml_callbacks xml_dungeon = { + tagbegin, tagend, NULL +}; + +void +register_dungeon(void) +{ + xml_register(&xml_dungeon, "eressea dungeon", 0); +} + +#endif diff --git a/src/modules/dungeon.h b/src/modules/dungeon.h index 12960cbdb..b0526e5a9 100644 --- a/src/modules/dungeon.h +++ b/src/modules/dungeon.h @@ -1,36 +1,36 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_MOD_DUNGEON -#define H_MOD_DUNGEON -#ifdef __cplusplus -extern "C" { -#endif - -#if DUNGEON_MODULE == 0 -#error "must define DUNGEON_MODULE to use this module" -#endif - -struct region; -struct plane; -struct building; -struct dungeon; - -extern struct dungeon * dungeonstyles; -extern struct region * make_dungeon(const struct dungeon*); -extern void make_dungeongate(struct region * source, struct region * target, const struct dungeon *); -extern void register_dungeon(void); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_MOD_DUNGEON +#define H_MOD_DUNGEON +#ifdef __cplusplus +extern "C" { +#endif + +#if DUNGEON_MODULE == 0 +#error "must define DUNGEON_MODULE to use this module" +#endif + +struct region; +struct plane; +struct building; +struct dungeon; + +extern struct dungeon * dungeonstyles; +extern struct region * make_dungeon(const struct dungeon*); +extern void make_dungeongate(struct region * source, struct region * target, const struct dungeon *); +extern void register_dungeon(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/gmcmd.c b/src/modules/gmcmd.c index ced1d27f9..61b216e4e 100644 --- a/src/modules/gmcmd.c +++ b/src/modules/gmcmd.c @@ -1,772 +1,772 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "gmcmd.h" -#include - -/* misc includes */ -#include -#include -#include -#include - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include - -/** - ** at_permissions - **/ - -static void -mistake(const unit * u, struct order * ord, const char *comment) -{ - if (!is_monsters(u->faction)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "mistake", - "error", comment)); - } -} - -static void -write_permissions(const attrib * a, const void * owner, struct storage * store) -{ - a_write(store, (attrib*)a->data.v, owner); -} - -static int -read_permissions(attrib * a, void * owner, struct storage * store) -{ - attrib * attr = NULL; - a_read(store, &attr, NULL); - a->data.v = attr; - return AT_READ_OK; -} - -struct attrib_type at_permissions = { - "GM:permissions", - NULL, NULL, NULL, - write_permissions, read_permissions, - ATF_UNIQUE -}; - -attrib * -make_atpermissions(void) -{ - return a_new(&at_permissions); -} - -/** - ** GM: CREATE - **/ - -static void -write_gmcreate(const attrib * a, const void * owner, struct storage * store) -{ - const item_type * itype = (const item_type *)a->data.v; - assert(itype); - store->w_tok(store, resourcename(itype->rtype, 0)); -} - -static int -read_gmcreate(attrib * a, void * owner, struct storage * store) -{ - char zText[32]; - store->r_tok_buf(store, zText, sizeof(zText)); - a->data.v = it_find(zText); - if (a->data.v == NULL) { - log_error(("unknown itemtype %s in gmcreate attribute\n", zText)); - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -/* at_gmcreate specifies that the owner can create items of a particular type */ -attrib_type at_gmcreate = { - "GM:create", - NULL, NULL, NULL, - write_gmcreate, read_gmcreate -}; - -attrib * -make_atgmcreate(const struct item_type * itype) -{ - attrib * a = a_new(&at_gmcreate); - a->data.v = (void*)itype; - return a; -} - -static void -gm_create(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - int i; - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (permissions) permissions = (attrib*)permissions->data.v; - if (!permissions) return; - i = getint(); - - if (i>0) { - const char * iname = getstrtoken(); - const item_type * itype = finditemtype(iname, u->faction->locale); - if (itype==NULL) { - mistake(u, ord, "unknown item."); - } else { - attrib * a = a_find(permissions, &at_gmcreate); - - while (a && a->type==&at_gmcreate && a->data.v!=(void*)itype) a=a->next; - if (a) i_change(&u->items, itype, i); - else mistake(u, ord, "your faction cannot create this item."); - } - } -} - -static boolean -has_permission(const attrib * permissions, unsigned int key) -{ - return (find_key((attrib*)permissions->data.v, key) || - find_key((attrib*)permissions->data.v, atoi36("master"))); -} - -/** - ** GM: GATE - ** requires: permission-key "gmgate" - **/ -static void -gm_gate(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - const struct plane * pl = rplane(u->region); - int id = getid(); - int x = rel_to_abs(pl, u->faction, getint(), 0); - int y = rel_to_abs(pl, u->faction, getint(), 1); - building * b = findbuilding(id); - region * r; - - pnormalize(&x, &y, pl); - r = findregion(x, y); - if (b==NULL || r==NULL || pl!=rplane(b->region) || pl!=rplane(r)) { - mistake(u, ord, "the unit cannot transform this building."); - return; - } else { - /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (permissions && has_permission(permissions, atoi36("gmgate"))) { - remove_triggers(&b->attribs, "timer", &tt_gate); - remove_triggers(&b->attribs, "create", &tt_unguard); - if (r!=b->region) { - add_trigger(&b->attribs, "timer", trigger_gate(b, r)); - add_trigger(&b->attribs, "create", trigger_unguard(b)); - fset(b, BLD_UNGUARDED); - } - } - } -} - - -/** - ** GM: TERRAFORM - ** requires: permission-key "gmterf" - **/ -static void -gm_terraform(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - const struct plane * p = rplane(u->region); - int x = rel_to_abs(p, u->faction, getint(), 0); - int y = rel_to_abs(p, u->faction, getint(), 1); - const char * c = getstrtoken(); - variant token; - tnode * tokens = get_translations(u->faction->locale, UT_TERRAINS); - region * r; - pnormalize(&x, &y, p); - r = findregion(x, y); - - if (r==NULL || p!=rplane(r)) { - mistake(u, ord, "region is in another plane."); - return; - } else { - /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmterf"))) return; - } - - if (findtoken(tokens, c, &token)!=E_TOK_NOMATCH) { - const terrain_type * terrain = (const terrain_type *)token.v; - terraform_region(r, terrain); - } -} - -/** - ** GM: TELEPORT - ** requires: permission-key "gmtele" - **/ -static void -gm_teleport(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - const struct plane * p = rplane(u->region); - unit * to = findunit(getid()); - int x = rel_to_abs(p, u->faction, getint(), 0); - int y = rel_to_abs(p, u->faction, getint(), 1); - region * r = findregion(x, y); - - if (r==NULL || p!=rplane(r)) { - mistake(u, ord, "region is in another plane."); - } else if (to==NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } else if (rplane(to->region)!=rplane(r) && !ucontact(to, u)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", "target", to)); - } else { - /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmtele"))) { - mistake(u, ord, "permission denied."); - } - else move_unit(to, r, NULL); - } -} - -/** - ** GM: TELL PLANE - ** requires: permission-key "gmmsgr" - **/ -static void -gm_messageplane(const tnode * tnext, void * data, struct order * ord) -{ - unit * gm = (unit*)data; - const struct plane * p = rplane(gm->region); - const char * zmsg = getstrtoken(); - if (p==NULL) { - mistake(gm, ord, "In diese Ebene kann keine Nachricht gesandt werden."); - } else { - /* checking permissions */ - attrib * permissions = a_find(gm->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { - mistake(gm, ord, "permission denied."); - } - else { - message * msg = msg_message("msg_event", "string", zmsg); - faction * f; - region * r; - for (f=factions;f;f=f->next) { - freset(f, FFL_SELECT); - } - for (r=regions;r;r=r->next) { - unit * u; - if (rplane(r)!=p) continue; - for (u=r->units;u;u=u->next) if (!fval(u->faction, FFL_SELECT)) { - f = u->faction; - fset(f, FFL_SELECT); - add_message(&f->msgs, msg); - } - } - msg_release(msg); - } - } -} - -static void -gm_messagefaction(const tnode * tnext, void * data, struct order * ord) -{ - unit * gm = (unit*)data; - int n = getid(); - faction * f = findfaction(n); - const char * msg = getstrtoken(); - plane * p = rplane(gm->region); - attrib * permissions = a_find(gm->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { - mistake(gm, ord, "permission denied."); - return; - } - if (f!=NULL) { - region * r; - for (r=regions;r;r=r->next) if (rplane(r)==p) { - unit * u; - for (u=r->units;u;u=u->next) if (u->faction==f) { - add_message(&f->msgs, msg_message("msg_event", "string", msg)); - return; - } - } - } - mistake(gm, ord, "cannot send messages to this faction."); -} - -/** - ** GM: TELL REGION - ** requires: permission-key "gmmsgr" - **/ -static void -gm_messageregion(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - const struct plane * p = rplane(u->region); - int x = rel_to_abs(p, u->faction, getint(), 0); - int y = rel_to_abs(p, u->faction, getint(), 1); - const char * msg = getstrtoken(); - region * r = findregion(x, y); - - if (r==NULL || p!=rplane(r)) { - mistake(u, ord, "region is in another plane."); - } else { - /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { - mistake(u, ord, "permission denied."); - } - else { - add_message(&r->msgs, msg_message("msg_event", "string", msg)); - } - } -} - -/** - ** GM: KILL UNIT - ** requires: permission-key "gmkill" - **/ -static void -gm_killunit(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - const struct plane * p = rplane(u->region); - unit * target = findunit(getid()); - const char * msg = getstrtoken(); - region * r = target->region; - - if (r==NULL || p!=rplane(r)) { - mistake(u, ord, "region is in another plane."); - } else { - /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmkill"))) { - mistake(u, ord, "permission denied."); - } - else { - scale_number(target, 0); - ADDMSG(&target->faction->msgs, msg_message("killedbygm", - "region unit string", r, target, msg)); - } - } -} - - -/** - ** GM: KILL FACTION - ** requires: permission-key "gmmsgr" - **/ -static void -gm_killfaction(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - int n = getid(); - faction * f = findfaction(n); - const char * msg = getstrtoken(); - plane * p = rplane(u->region); - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmkill"))) { - mistake(u, ord, "permission denied."); - return; - } - if (f!=NULL) { - region * r; - for (r=regions;r;r=r->next) if (rplane(r)==p) { - unit * target; - for (target=r->units;target;target=target->next) { - if (target->faction==f) { - scale_number(target, 0); - ADDMSG(&target->faction->msgs, msg_message("killedbygm", - "region unit string", r, target, msg)); - return; - } - } - } - } - mistake(u, ord, "cannot remove a unit from this faction."); -} - -/** - ** GM: TELL - ** requires: permission-key "gmmsgr" - **/ -static void -gm_messageunit(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - const struct plane * p = rplane(u->region); - unit * target = findunit(getid()); - const char * msg = getstrtoken(); - region * r; - - if (target == NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return; - } - - r = target->region; - - if (r==NULL || p!=rplane(r)) { - mistake(u, ord, "region is in another plane."); - } else { - /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmmsgu"))) { - mistake(u, ord, "permission denied."); - } - else { - add_message(&target->faction->msgs, - msg_message("regionmessage", "region sender string", r, u, msg)); - } - } -} - -/** - ** GM: GIVE - ** requires: permission-key "gmgive" - **/ -static void -gm_give(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - unit * to = findunit(getid()); - int num = getint(); - const item_type * itype = finditemtype(getstrtoken(), u->faction->locale); - - if (to==NULL || rplane(to->region) != rplane(u->region)) { - /* unknown or in another plane */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } else if (itype==NULL || i_get(u->items, itype)==0) { - /* unknown or not enough */ - mistake(u, ord, "invalid item or item not found."); - } else { - /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmgive"))) { - mistake(u, ord, "permission denied."); - } - else { - int i = i_get(u->items, itype); - if (iitems, itype, -num); - i_change(&to->items, itype, num); - } - } - } -} - -/** - ** GM: TAKE - ** requires: permission-key "gmtake" - **/ -static void -gm_take(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - unit * to = findunit(getid()); - int num = getint(); - const item_type * itype = finditemtype(getstrtoken(), u->faction->locale); - - if (to==NULL || rplane(to->region) != rplane(u->region)) { - /* unknown or in another plane */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } else if (itype==NULL || i_get(to->items, itype)==0) { - /* unknown or not enough */ - mistake(u, ord, "invalid item or item not found."); - } else { - /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmtake"))) { - mistake(u, ord, "permission denied."); - } - else { - int i = i_get(to->items, itype); - if (iitems, itype, -num); - i_change(&u->items, itype, num); - } - } - } -} - -/** - ** GM: SKILL - ** requires: permission-key "gmskil" - **/ -static void -gm_skill(const tnode * tnext, void * data, struct order * ord) -{ - unit * u = (unit*)data; - unit * to = findunit(getid()); - skill_t skill = findskill(getstrtoken(), u->faction->locale); - int num = getint(); - - if (to==NULL || rplane(to->region) != rplane(u->region)) { - /* unknown or in another plane */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } else if (skill==NOSKILL || skill==SK_MAGIC || skill==SK_ALCHEMY) { - /* unknown or not enough */ - mistake(u, ord, "unknown skill, or skill cannot be raised."); - } else if (num<0 || num>30) { - /* sanity check failed */ - mistake(u, ord, "invalid value."); - } else { - /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmskil"))) { - mistake(u, ord, "permission denied."); - } - else { - set_level(to, skill, num); - } - } -} - -static tnode g_keys; -static tnode g_root; -static tnode g_tell; -static tnode g_kill; - -void -register_gmcmd(void) -{ - at_register(&at_gmcreate); - at_register(&at_permissions); - add_command(&g_root, &g_keys, "gm", NULL); - add_command(&g_keys, NULL, "terraform", &gm_terraform); - add_command(&g_keys, NULL, "create", &gm_create); - add_command(&g_keys, NULL, "gate", &gm_gate); - add_command(&g_keys, NULL, "give", &gm_give); - add_command(&g_keys, NULL, "take", &gm_take); - add_command(&g_keys, NULL, "teleport", &gm_teleport); - add_command(&g_keys, NULL, "skill", &gm_skill); - add_command(&g_keys, &g_tell, "tell", NULL); - add_command(&g_tell, NULL, "region", &gm_messageregion); - add_command(&g_tell, NULL, "unit", &gm_messageunit); - add_command(&g_tell, NULL, "plane", &gm_messageplane); - add_command(&g_tell, NULL, "faction", &gm_messagefaction); - add_command(&g_keys, &g_kill, "kill", NULL); - add_command(&g_kill, NULL, "unit", &gm_killunit); - add_command(&g_kill, NULL, "faction", &gm_killfaction); -} - -/* - * execute gm-commands for all units in the game - */ - -void -gmcommands(void) -{ - region ** rp = ®ions; - while (*rp) { - region * r = *rp; - unit **up = &r->units; - while (*up) { - unit * u = *up; - struct order * ord; - for (ord = u->orders; ord; ord = ord->next) { - if (get_keyword(ord) == K_GM) { - do_command(&g_root, u, ord); - } - } - if (u==*up) up = &u->next; - } - if (*rp==r) rp = &r->next; - } -} - -#define EXTENSION 10000 - -faction * -gm_addquest(const char * email, const char * name, int radius, unsigned int flags) -{ - plane * pl; - watcher * w = calloc(sizeof(watcher), 1); - region * center; - boolean invalid = false; - int minx, miny, maxx, maxy, cx, cy; - int x; - faction * f; - - /* GM playfield */ - do { - minx = ((rng_int() % (2*EXTENSION)) - EXTENSION); - miny = ((rng_int() % (2*EXTENSION)) - EXTENSION); - for (x=0;!invalid && x<=radius*2;++x) { - int y; - for (y=0;!invalid && y<=radius*2;++y) { - region * r = findregion(minx+x, miny+y); - if (r) invalid = true; - } - } - } while (invalid); - maxx = minx+2*radius; cx = minx+radius; - maxy = miny+2*radius; cy = miny+radius; - pl = create_new_plane(rng_int(), name, minx, maxx, miny, maxy, flags); - center = new_region(cx, cy, pl, 0); - for (x=0;x<=2*radius;++x) { - int y; - for (y=0;y<=2*radius;++y) { - region * r = findregion(minx+x, miny+y); - if (!r) { - r = new_region(minx+x, miny+y, pl, 0); - } - freset(r, RF_ENCOUNTER); - if (distance(r, center)==radius) { - terraform_region(r, newterrain(T_FIREWALL)); - } else if (r==center) { - terraform_region(r, newterrain(T_PLAIN)); - } else { - terraform_region(r, newterrain(T_OCEAN)); - } - } - } - - /* watcher: */ - f = gm_addfaction(email, pl, center); - w->faction = f; - w->mode = see_unit; - w->next = pl->watchers; - pl->watchers = w; - - return f; -} - -faction * -gm_addfaction(const char * email, plane * p, region * r) -{ - attrib * a; - unit * u; - faction * f = calloc(1, sizeof(faction)); - - assert(p!=NULL); - - /* GM faction */ - a_add(&f->attribs, make_key(atoi36("quest"))); - f->banner = strdup("quest faction"); - f->name = strdup("quest faction"); - f->passw = strdup(itoa36(rng_int())); - f->override = strdup(itoa36(rng_int())); - if (set_email(&f->email, email)!=0) { - log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), email)); - } - f->race = new_race[RC_TEMPLATE]; - f->age = 0; - f->lastorders = turn; - f->alive = true; - f->locale = default_locale; - f->options = want(O_COMPRESS) | want(O_REPORT) | want(O_COMPUTER) | want(O_ADRESSEN); - { - faction * xist; - int id = atoi36("gm00")-1; - do { - xist = findfaction(++id); - } while (xist); - - f->no = id; - addlist(&factions, f); - fhash(f); - } - - /* generic permissions */ - a = a_add(&f->attribs, a_new(&at_permissions)); - if (a) { - attrib * ap = (attrib*)a->data.v; - const char* keys[] = { "gmterf", "gmtele", "gmgive", "gmskil", "gmtake", "gmmsgr", "gmmsgu", "gmgate", 0 }; - const char ** key_p = keys; - while (*key_p) { - add_key(&ap, atoi36(*key_p)); - ++key_p; - } - a_add(&ap, make_atgmcreate(resource2item(r_silver))); - - a->data.v = ap; - } - - /* one initial unit */ - u = create_unit(r, f, 1, new_race[RC_TEMPLATE], 1, "quest master", NULL); - u->irace = new_race[RC_GNOME]; - - return f; -} - -plane * -gm_addplane(int radius, unsigned int flags, const char * name) -{ - region * center; - plane * pl; - boolean invalid = false; - int minx, miny, maxx, maxy, cx, cy; - int x; - - /* GM playfield */ - do { - minx = (rng_int() % (2*EXTENSION)) - EXTENSION; - miny = (rng_int() % (2*EXTENSION)) - EXTENSION; - for (x=0;!invalid && x<=radius*2;++x) { - int y; - for (y=0;!invalid && y<=radius*2;++y) { - region * r = findregion(minx+x, miny+y); - if (r) invalid = true; - } - } - } while (invalid); - maxx = minx+2*radius; cx = minx+radius; - maxy = miny+2*radius; cy = miny+radius; - pl = create_new_plane(rng_int(), name, minx, maxx, miny, maxy, flags); - center = new_region(cx, cy, pl, 0); - for (x=0;x<=2*radius;++x) { - int y; - for (y=0;y<=2*radius;++y) { - region * r = findregion(minx+x, miny+y); - if (!r) r = new_region(minx+x, miny+y, pl, 0); - freset(r, RF_ENCOUNTER); - if (distance(r, center)==radius) { - terraform_region(r, newterrain(T_FIREWALL)); - } else if (r==center) { - terraform_region(r, newterrain(T_PLAIN)); - } else { - terraform_region(r, newterrain(T_OCEAN)); - } - } - } - return pl; -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "gmcmd.h" +#include + +/* misc includes */ +#include +#include +#include +#include + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +/** + ** at_permissions + **/ + +static void +mistake(const unit * u, struct order * ord, const char *comment) +{ + if (!is_monsters(u->faction)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "mistake", + "error", comment)); + } +} + +static void +write_permissions(const attrib * a, const void * owner, struct storage * store) +{ + a_write(store, (attrib*)a->data.v, owner); +} + +static int +read_permissions(attrib * a, void * owner, struct storage * store) +{ + attrib * attr = NULL; + a_read(store, &attr, NULL); + a->data.v = attr; + return AT_READ_OK; +} + +struct attrib_type at_permissions = { + "GM:permissions", + NULL, NULL, NULL, + write_permissions, read_permissions, + ATF_UNIQUE +}; + +attrib * +make_atpermissions(void) +{ + return a_new(&at_permissions); +} + +/** + ** GM: CREATE + **/ + +static void +write_gmcreate(const attrib * a, const void * owner, struct storage * store) +{ + const item_type * itype = (const item_type *)a->data.v; + assert(itype); + store->w_tok(store, resourcename(itype->rtype, 0)); +} + +static int +read_gmcreate(attrib * a, void * owner, struct storage * store) +{ + char zText[32]; + store->r_tok_buf(store, zText, sizeof(zText)); + a->data.v = it_find(zText); + if (a->data.v == NULL) { + log_error(("unknown itemtype %s in gmcreate attribute\n", zText)); + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +/* at_gmcreate specifies that the owner can create items of a particular type */ +attrib_type at_gmcreate = { + "GM:create", + NULL, NULL, NULL, + write_gmcreate, read_gmcreate +}; + +attrib * +make_atgmcreate(const struct item_type * itype) +{ + attrib * a = a_new(&at_gmcreate); + a->data.v = (void*)itype; + return a; +} + +static void +gm_create(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + int i; + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (permissions) permissions = (attrib*)permissions->data.v; + if (!permissions) return; + i = getint(); + + if (i>0) { + const char * iname = getstrtoken(); + const item_type * itype = finditemtype(iname, u->faction->locale); + if (itype==NULL) { + mistake(u, ord, "unknown item."); + } else { + attrib * a = a_find(permissions, &at_gmcreate); + + while (a && a->type==&at_gmcreate && a->data.v!=(void*)itype) a=a->next; + if (a) i_change(&u->items, itype, i); + else mistake(u, ord, "your faction cannot create this item."); + } + } +} + +static boolean +has_permission(const attrib * permissions, unsigned int key) +{ + return (find_key((attrib*)permissions->data.v, key) || + find_key((attrib*)permissions->data.v, atoi36("master"))); +} + +/** + ** GM: GATE + ** requires: permission-key "gmgate" + **/ +static void +gm_gate(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + const struct plane * pl = rplane(u->region); + int id = getid(); + int x = rel_to_abs(pl, u->faction, getint(), 0); + int y = rel_to_abs(pl, u->faction, getint(), 1); + building * b = findbuilding(id); + region * r; + + pnormalize(&x, &y, pl); + r = findregion(x, y); + if (b==NULL || r==NULL || pl!=rplane(b->region) || pl!=rplane(r)) { + mistake(u, ord, "the unit cannot transform this building."); + return; + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (permissions && has_permission(permissions, atoi36("gmgate"))) { + remove_triggers(&b->attribs, "timer", &tt_gate); + remove_triggers(&b->attribs, "create", &tt_unguard); + if (r!=b->region) { + add_trigger(&b->attribs, "timer", trigger_gate(b, r)); + add_trigger(&b->attribs, "create", trigger_unguard(b)); + fset(b, BLD_UNGUARDED); + } + } + } +} + + +/** + ** GM: TERRAFORM + ** requires: permission-key "gmterf" + **/ +static void +gm_terraform(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + const struct plane * p = rplane(u->region); + int x = rel_to_abs(p, u->faction, getint(), 0); + int y = rel_to_abs(p, u->faction, getint(), 1); + const char * c = getstrtoken(); + variant token; + tnode * tokens = get_translations(u->faction->locale, UT_TERRAINS); + region * r; + pnormalize(&x, &y, p); + r = findregion(x, y); + + if (r==NULL || p!=rplane(r)) { + mistake(u, ord, "region is in another plane."); + return; + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmterf"))) return; + } + + if (findtoken(tokens, c, &token)!=E_TOK_NOMATCH) { + const terrain_type * terrain = (const terrain_type *)token.v; + terraform_region(r, terrain); + } +} + +/** + ** GM: TELEPORT + ** requires: permission-key "gmtele" + **/ +static void +gm_teleport(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + const struct plane * p = rplane(u->region); + unit * to = findunit(getid()); + int x = rel_to_abs(p, u->faction, getint(), 0); + int y = rel_to_abs(p, u->faction, getint(), 1); + region * r = findregion(x, y); + + if (r==NULL || p!=rplane(r)) { + mistake(u, ord, "region is in another plane."); + } else if (to==NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } else if (rplane(to->region)!=rplane(r) && !ucontact(to, u)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", "target", to)); + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmtele"))) { + mistake(u, ord, "permission denied."); + } + else move_unit(to, r, NULL); + } +} + +/** + ** GM: TELL PLANE + ** requires: permission-key "gmmsgr" + **/ +static void +gm_messageplane(const tnode * tnext, void * data, struct order * ord) +{ + unit * gm = (unit*)data; + const struct plane * p = rplane(gm->region); + const char * zmsg = getstrtoken(); + if (p==NULL) { + mistake(gm, ord, "In diese Ebene kann keine Nachricht gesandt werden."); + } else { + /* checking permissions */ + attrib * permissions = a_find(gm->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { + mistake(gm, ord, "permission denied."); + } + else { + message * msg = msg_message("msg_event", "string", zmsg); + faction * f; + region * r; + for (f=factions;f;f=f->next) { + freset(f, FFL_SELECT); + } + for (r=regions;r;r=r->next) { + unit * u; + if (rplane(r)!=p) continue; + for (u=r->units;u;u=u->next) if (!fval(u->faction, FFL_SELECT)) { + f = u->faction; + fset(f, FFL_SELECT); + add_message(&f->msgs, msg); + } + } + msg_release(msg); + } + } +} + +static void +gm_messagefaction(const tnode * tnext, void * data, struct order * ord) +{ + unit * gm = (unit*)data; + int n = getid(); + faction * f = findfaction(n); + const char * msg = getstrtoken(); + plane * p = rplane(gm->region); + attrib * permissions = a_find(gm->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { + mistake(gm, ord, "permission denied."); + return; + } + if (f!=NULL) { + region * r; + for (r=regions;r;r=r->next) if (rplane(r)==p) { + unit * u; + for (u=r->units;u;u=u->next) if (u->faction==f) { + add_message(&f->msgs, msg_message("msg_event", "string", msg)); + return; + } + } + } + mistake(gm, ord, "cannot send messages to this faction."); +} + +/** + ** GM: TELL REGION + ** requires: permission-key "gmmsgr" + **/ +static void +gm_messageregion(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + const struct plane * p = rplane(u->region); + int x = rel_to_abs(p, u->faction, getint(), 0); + int y = rel_to_abs(p, u->faction, getint(), 1); + const char * msg = getstrtoken(); + region * r = findregion(x, y); + + if (r==NULL || p!=rplane(r)) { + mistake(u, ord, "region is in another plane."); + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { + mistake(u, ord, "permission denied."); + } + else { + add_message(&r->msgs, msg_message("msg_event", "string", msg)); + } + } +} + +/** + ** GM: KILL UNIT + ** requires: permission-key "gmkill" + **/ +static void +gm_killunit(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + const struct plane * p = rplane(u->region); + unit * target = findunit(getid()); + const char * msg = getstrtoken(); + region * r = target->region; + + if (r==NULL || p!=rplane(r)) { + mistake(u, ord, "region is in another plane."); + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmkill"))) { + mistake(u, ord, "permission denied."); + } + else { + scale_number(target, 0); + ADDMSG(&target->faction->msgs, msg_message("killedbygm", + "region unit string", r, target, msg)); + } + } +} + + +/** + ** GM: KILL FACTION + ** requires: permission-key "gmmsgr" + **/ +static void +gm_killfaction(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + int n = getid(); + faction * f = findfaction(n); + const char * msg = getstrtoken(); + plane * p = rplane(u->region); + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmkill"))) { + mistake(u, ord, "permission denied."); + return; + } + if (f!=NULL) { + region * r; + for (r=regions;r;r=r->next) if (rplane(r)==p) { + unit * target; + for (target=r->units;target;target=target->next) { + if (target->faction==f) { + scale_number(target, 0); + ADDMSG(&target->faction->msgs, msg_message("killedbygm", + "region unit string", r, target, msg)); + return; + } + } + } + } + mistake(u, ord, "cannot remove a unit from this faction."); +} + +/** + ** GM: TELL + ** requires: permission-key "gmmsgr" + **/ +static void +gm_messageunit(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + const struct plane * p = rplane(u->region); + unit * target = findunit(getid()); + const char * msg = getstrtoken(); + region * r; + + if (target == NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + + r = target->region; + + if (r==NULL || p!=rplane(r)) { + mistake(u, ord, "region is in another plane."); + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmmsgu"))) { + mistake(u, ord, "permission denied."); + } + else { + add_message(&target->faction->msgs, + msg_message("regionmessage", "region sender string", r, u, msg)); + } + } +} + +/** + ** GM: GIVE + ** requires: permission-key "gmgive" + **/ +static void +gm_give(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + unit * to = findunit(getid()); + int num = getint(); + const item_type * itype = finditemtype(getstrtoken(), u->faction->locale); + + if (to==NULL || rplane(to->region) != rplane(u->region)) { + /* unknown or in another plane */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } else if (itype==NULL || i_get(u->items, itype)==0) { + /* unknown or not enough */ + mistake(u, ord, "invalid item or item not found."); + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmgive"))) { + mistake(u, ord, "permission denied."); + } + else { + int i = i_get(u->items, itype); + if (iitems, itype, -num); + i_change(&to->items, itype, num); + } + } + } +} + +/** + ** GM: TAKE + ** requires: permission-key "gmtake" + **/ +static void +gm_take(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + unit * to = findunit(getid()); + int num = getint(); + const item_type * itype = finditemtype(getstrtoken(), u->faction->locale); + + if (to==NULL || rplane(to->region) != rplane(u->region)) { + /* unknown or in another plane */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } else if (itype==NULL || i_get(to->items, itype)==0) { + /* unknown or not enough */ + mistake(u, ord, "invalid item or item not found."); + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmtake"))) { + mistake(u, ord, "permission denied."); + } + else { + int i = i_get(to->items, itype); + if (iitems, itype, -num); + i_change(&u->items, itype, num); + } + } + } +} + +/** + ** GM: SKILL + ** requires: permission-key "gmskil" + **/ +static void +gm_skill(const tnode * tnext, void * data, struct order * ord) +{ + unit * u = (unit*)data; + unit * to = findunit(getid()); + skill_t skill = findskill(getstrtoken(), u->faction->locale); + int num = getint(); + + if (to==NULL || rplane(to->region) != rplane(u->region)) { + /* unknown or in another plane */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + } else if (skill==NOSKILL || skill==SK_MAGIC || skill==SK_ALCHEMY) { + /* unknown or not enough */ + mistake(u, ord, "unknown skill, or skill cannot be raised."); + } else if (num<0 || num>30) { + /* sanity check failed */ + mistake(u, ord, "invalid value."); + } else { + /* checking permissions */ + attrib * permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmskil"))) { + mistake(u, ord, "permission denied."); + } + else { + set_level(to, skill, num); + } + } +} + +static tnode g_keys; +static tnode g_root; +static tnode g_tell; +static tnode g_kill; + +void +register_gmcmd(void) +{ + at_register(&at_gmcreate); + at_register(&at_permissions); + add_command(&g_root, &g_keys, "gm", NULL); + add_command(&g_keys, NULL, "terraform", &gm_terraform); + add_command(&g_keys, NULL, "create", &gm_create); + add_command(&g_keys, NULL, "gate", &gm_gate); + add_command(&g_keys, NULL, "give", &gm_give); + add_command(&g_keys, NULL, "take", &gm_take); + add_command(&g_keys, NULL, "teleport", &gm_teleport); + add_command(&g_keys, NULL, "skill", &gm_skill); + add_command(&g_keys, &g_tell, "tell", NULL); + add_command(&g_tell, NULL, "region", &gm_messageregion); + add_command(&g_tell, NULL, "unit", &gm_messageunit); + add_command(&g_tell, NULL, "plane", &gm_messageplane); + add_command(&g_tell, NULL, "faction", &gm_messagefaction); + add_command(&g_keys, &g_kill, "kill", NULL); + add_command(&g_kill, NULL, "unit", &gm_killunit); + add_command(&g_kill, NULL, "faction", &gm_killfaction); +} + +/* + * execute gm-commands for all units in the game + */ + +void +gmcommands(void) +{ + region ** rp = ®ions; + while (*rp) { + region * r = *rp; + unit **up = &r->units; + while (*up) { + unit * u = *up; + struct order * ord; + for (ord = u->orders; ord; ord = ord->next) { + if (get_keyword(ord) == K_GM) { + do_command(&g_root, u, ord); + } + } + if (u==*up) up = &u->next; + } + if (*rp==r) rp = &r->next; + } +} + +#define EXTENSION 10000 + +faction * +gm_addquest(const char * email, const char * name, int radius, unsigned int flags) +{ + plane * pl; + watcher * w = calloc(sizeof(watcher), 1); + region * center; + boolean invalid = false; + int minx, miny, maxx, maxy, cx, cy; + int x; + faction * f; + + /* GM playfield */ + do { + minx = ((rng_int() % (2*EXTENSION)) - EXTENSION); + miny = ((rng_int() % (2*EXTENSION)) - EXTENSION); + for (x=0;!invalid && x<=radius*2;++x) { + int y; + for (y=0;!invalid && y<=radius*2;++y) { + region * r = findregion(minx+x, miny+y); + if (r) invalid = true; + } + } + } while (invalid); + maxx = minx+2*radius; cx = minx+radius; + maxy = miny+2*radius; cy = miny+radius; + pl = create_new_plane(rng_int(), name, minx, maxx, miny, maxy, flags); + center = new_region(cx, cy, pl, 0); + for (x=0;x<=2*radius;++x) { + int y; + for (y=0;y<=2*radius;++y) { + region * r = findregion(minx+x, miny+y); + if (!r) { + r = new_region(minx+x, miny+y, pl, 0); + } + freset(r, RF_ENCOUNTER); + if (distance(r, center)==radius) { + terraform_region(r, newterrain(T_FIREWALL)); + } else if (r==center) { + terraform_region(r, newterrain(T_PLAIN)); + } else { + terraform_region(r, newterrain(T_OCEAN)); + } + } + } + + /* watcher: */ + f = gm_addfaction(email, pl, center); + w->faction = f; + w->mode = see_unit; + w->next = pl->watchers; + pl->watchers = w; + + return f; +} + +faction * +gm_addfaction(const char * email, plane * p, region * r) +{ + attrib * a; + unit * u; + faction * f = calloc(1, sizeof(faction)); + + assert(p!=NULL); + + /* GM faction */ + a_add(&f->attribs, make_key(atoi36("quest"))); + f->banner = strdup("quest faction"); + f->name = strdup("quest faction"); + f->passw = strdup(itoa36(rng_int())); + f->override = strdup(itoa36(rng_int())); + if (set_email(&f->email, email)!=0) { + log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), email)); + } + f->race = new_race[RC_TEMPLATE]; + f->age = 0; + f->lastorders = turn; + f->alive = true; + f->locale = default_locale; + f->options = want(O_COMPRESS) | want(O_REPORT) | want(O_COMPUTER) | want(O_ADRESSEN); + { + faction * xist; + int id = atoi36("gm00")-1; + do { + xist = findfaction(++id); + } while (xist); + + f->no = id; + addlist(&factions, f); + fhash(f); + } + + /* generic permissions */ + a = a_add(&f->attribs, a_new(&at_permissions)); + if (a) { + attrib * ap = (attrib*)a->data.v; + const char* keys[] = { "gmterf", "gmtele", "gmgive", "gmskil", "gmtake", "gmmsgr", "gmmsgu", "gmgate", 0 }; + const char ** key_p = keys; + while (*key_p) { + add_key(&ap, atoi36(*key_p)); + ++key_p; + } + a_add(&ap, make_atgmcreate(resource2item(r_silver))); + + a->data.v = ap; + } + + /* one initial unit */ + u = create_unit(r, f, 1, new_race[RC_TEMPLATE], 1, "quest master", NULL); + u->irace = new_race[RC_GNOME]; + + return f; +} + +plane * +gm_addplane(int radius, unsigned int flags, const char * name) +{ + region * center; + plane * pl; + boolean invalid = false; + int minx, miny, maxx, maxy, cx, cy; + int x; + + /* GM playfield */ + do { + minx = (rng_int() % (2*EXTENSION)) - EXTENSION; + miny = (rng_int() % (2*EXTENSION)) - EXTENSION; + for (x=0;!invalid && x<=radius*2;++x) { + int y; + for (y=0;!invalid && y<=radius*2;++y) { + region * r = findregion(minx+x, miny+y); + if (r) invalid = true; + } + } + } while (invalid); + maxx = minx+2*radius; cx = minx+radius; + maxy = miny+2*radius; cy = miny+radius; + pl = create_new_plane(rng_int(), name, minx, maxx, miny, maxy, flags); + center = new_region(cx, cy, pl, 0); + for (x=0;x<=2*radius;++x) { + int y; + for (y=0;y<=2*radius;++y) { + region * r = findregion(minx+x, miny+y); + if (!r) r = new_region(minx+x, miny+y, pl, 0); + freset(r, RF_ENCOUNTER); + if (distance(r, center)==radius) { + terraform_region(r, newterrain(T_FIREWALL)); + } else if (r==center) { + terraform_region(r, newterrain(T_PLAIN)); + } else { + terraform_region(r, newterrain(T_OCEAN)); + } + } + } + return pl; +} diff --git a/src/modules/gmcmd.h b/src/modules/gmcmd.h index 143e126f4..2e830b51c 100644 --- a/src/modules/gmcmd.h +++ b/src/modules/gmcmd.h @@ -1,48 +1,48 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_MOD_GMCMD -#define H_MOD_GMCMD -#ifdef __cplusplus -extern "C" { -#endif - -struct plane; -struct attrib; -struct unit; -struct faction; -struct region; - -extern void register_gmcmd(void); -/* initialize this module */ - -extern void gmcommands(void); -/* execute commands */ - -extern struct faction * gm_addfaction(const char * email, struct plane * p, struct region * r); -extern struct plane * gm_addplane(int radius, unsigned int flags, const char * name); - -/* - * doesn't belong in here: - */ -struct attrib * find_key(struct attrib * attribs, int key); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_MOD_GMCMD +#define H_MOD_GMCMD +#ifdef __cplusplus +extern "C" { +#endif + +struct plane; +struct attrib; +struct unit; +struct faction; +struct region; + +extern void register_gmcmd(void); +/* initialize this module */ + +extern void gmcommands(void); +/* execute commands */ + +extern struct faction * gm_addfaction(const char * email, struct plane * p, struct region * r); +extern struct plane * gm_addplane(int radius, unsigned int flags, const char * name); + +/* + * doesn't belong in here: + */ +struct attrib * find_key(struct attrib * attribs, int key); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/museum.c b/src/modules/museum.c index c89a51d6b..7186f177d 100644 --- a/src/modules/museum.c +++ b/src/modules/museum.c @@ -1,396 +1,396 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include - -#include - -#if MUSEUM_MODULE -#include "museum.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -#define PFL_MUSEUM PFL_NOMONSTERS | PFL_NORECRUITS | PFL_NOGIVE | PFL_NOATTACK | PFL_NOTERRAIN | PFL_NOMAGIC | PFL_NOSTEALTH | PFL_NOTEACH | PFL_NOBUILD | PFL_NOFEED - -attrib_type at_museumexit = { - "museumexit", NULL, NULL, NULL, a_writeshorts, a_readshorts -}; - -static void -a_initmuseumgivebackcookie(attrib *a) -{ - a->data.v = calloc(1,sizeof(museumgivebackcookie)); -} - -static void -a_finalizemuseumgivebackcookie(attrib *a) -{ - free(a->data.v); -} - -static void -a_writemuseumgivebackcookie(const attrib * a, const void * owner, struct storage * store) -{ - museumgivebackcookie *gbc = (museumgivebackcookie *)a->data.v; - store->w_int(store, gbc->warden_no); - store->w_int(store, gbc->cookie); -} - -static int -a_readmuseumgivebackcookie(attrib *a, void * owner, struct storage * store) -{ - museumgivebackcookie *gbc = (museumgivebackcookie *)a->data.v; - gbc->warden_no = store->r_int(store); - gbc->cookie = store->r_int(store); - return AT_READ_OK; -} - -attrib_type at_museumgivebackcookie = { - "museumgivebackcookie", - a_initmuseumgivebackcookie, - a_finalizemuseumgivebackcookie, - NULL, - a_writemuseumgivebackcookie, - a_readmuseumgivebackcookie -}; - -attrib_type at_warden = { - "itemwarden", NULL, NULL, NULL, a_writeint, a_readint -}; - -static void -a_initmuseumgiveback(attrib *a) -{ - a->data.v = calloc(1, sizeof(museumgiveback)); -} - -static void -a_finalizemuseumgiveback(attrib *a) -{ - museumgiveback *gb = (museumgiveback *)a->data.v; - i_freeall(&gb->items); - free(a->data.v); -} - -static void -a_writemuseumgiveback(const attrib * a, const void * owner, struct storage * store) -{ - museumgiveback *gb = (museumgiveback *)a->data.v; - store->w_int(store, gb->cookie); - write_items(store, gb->items); -} - -static int -a_readmuseumgiveback(attrib *a, void * owner, struct storage * store) -{ - museumgiveback *gb = (museumgiveback *)a->data.v; - gb->cookie = store->r_int(store); - read_items(store, &gb->items); - return AT_READ_OK; -} - -attrib_type at_museumgiveback = { - "museumgiveback", - a_initmuseumgiveback, - a_finalizemuseumgiveback, - NULL, - a_writemuseumgiveback, - a_readmuseumgiveback -}; - -void -warden_add_give(unit *src, unit *u, const item_type *itype, int n) -{ - attrib *aw = a_find(u->attribs, &at_warden); - museumgiveback *gb = NULL; - museumgivebackcookie *gbc; - attrib *a; - - /* has the giver a cookie corresponding to the warden */ - for(a = a_find(src->attribs, &at_museumgivebackcookie); a && a->type==&at_museumgivebackcookie; a=a->next) { - if(((museumgivebackcookie *)(a->data.v))->warden_no == u->no) break; - } - - /* if not give it one */ - if (a==NULL || a->type!=&at_museumgivebackcookie) { - a = a_add(&src->attribs, a_new(&at_museumgivebackcookie)); - gbc = (museumgivebackcookie *)a->data.v; - gbc->warden_no = u->no; - gbc->cookie = aw->data.i; - assert(aw->data.i < INT_MAX); - aw->data.i++; - } else { - gbc = (museumgivebackcookie *)(a->data.v); - } - - /* now we search for the warden's corresponding item list */ - for (a = a_find(u->attribs, &at_museumgiveback); a && a->type==&at_museumgiveback; a=a->next) { - gb = (museumgiveback *)a->data.v; - if (gb->cookie == gbc->cookie) { - break; - } - } - - /* if there's none, give it one */ - if (!gb) { - a = a_add(&u->attribs, a_new(&at_museumgiveback)); - gb = (museumgiveback *)a->data.v; - gb->cookie = gbc->cookie; - } - - /* now register the items */ - i_change(&gb->items, itype, n); - - /* done */ - - /* this has a caveat: If the src-unit is destroyed while inside - * the museum, the corresponding itemlist of the warden will never - * be removed. to circumvent that in a generic way will be extremly - * difficult. */ -} - -void -create_museum(void) -{ -#if 0 /* TODO: move this to LUA. It should be possible. */ - unsigned int museum_id = hashstring("museum"); - plane *museum = getplanebyid(museum_id); - region *r; - building *b; - const terrain_type * terrain_hall = get_terrain("hall1"); - const terrain_type * terrain_corridor = get_terrain("corridor1"); - - assert(terrain_corridor && terrain_hall); - - if (!museum) { - museum = create_new_plane(museum_id, "Museum", 9500, 9550, - 9500, 9550, PFL_MUSEUM); - } - - if (findregion(9525, 9525) == NULL) { - /* Eingangshalle */ - r = new_region(9525, 9525, 0); - terraform_region(r, terrain_hall); - r->planep = museum; - rsetname(r, "Eingangshalle"); - rsethorses(r, 0); - rsetmoney(r, 0); - rsetpeasants(r, 0); - set_string(&r->display, "Die Eingangshalle des Großen Museum der 1. Welt ist bereits jetzt ein beeindruckender Anblick. Obwohl das Museum noch nicht eröffnet ist, vermittelt sie bereits einen Flair exotischer Welten. In den Boden ist ein großer Kompass eingelassen, der den Besuchern bei Orientierung helfen soll."); - } - - r = findregion(9526, 9525); - if(!r) { - /* Lounge */ - r = new_region(9526, 9525, 0); - terraform_region(r, terrain_hall); - r->planep = museum; - rsetname(r, "Lounge"); - rsethorses(r, 0); - rsetmoney(r, 0); - rsetpeasants(r, 0); - set_string(&r->display, "Die Lounge des großen Museums ist ein Platz, in dem sich die Besucher treffen, um die Eindrücke, die sie gewonnen haben, zu verarbeiten. Gemütliche Sitzgruppen laden zum Verweilen ein."); - } - - r = findregion(9526, 9525); - if(!r->buildings) { - const building_type * bt_generic = bt_find("generic"); - b = new_building(bt_generic, r, NULL); - set_string(&b->name, "Séparée im dämonischen Stil"); - set_string(&b->display, "Diese ganz im dämonischen Stil gehaltene Sitzgruppe ist ganz in dunklen Schwarztönen gehalten. Muster fremdartiger Runen bedecken das merkwürdig geformte Mobiliar, das unangenehm lebendig wirkt."); - - b = new_building(bt_generic, r, NULL); - set_string(&b->name, "Séparée im elfischen Stil"); - set_string(&b->display, "Ganz in Grün- und Brauntönen gehalten wirkt die Sitzgruppe fast lebendig. Bei näherer Betrachtung erschließt sich dem Betrachter, daß sie tatsächlich aus lebenden Pflanzen erstellt ist. So ist der Tisch aus einem eizigen Baum gewachsen, und die Polster bestehen aus weichen Grassoden. Ein wunderschön gemusterter Webteppich mit tausenden naturgetreu eingestickter Blumensarten bedeckt den Boden."); - - b = new_building(bt_generic, r, NULL); - set_string(&b->name, "Séparée im halblingschen Stil"); - set_string(&b->display, "Dieses rustikale Mobiliar ist aus einem einzigen, gewaltigen Baum hergestellt worden. Den Stamm haben fleißige Halblinge der Länge nach gevierteilt und aus den vier langen Viertelstämmen die Sitzbänke geschnitzt, während der verbleibende Stumpf als Tisch dient. Schon von weitem steigen dem Besucher die Gerüche der Köstlichkeiten entgegen, die auf dem Tisch stapeln."); - - b = new_building(bt_generic, r, NULL); - set_string(&b->name, "Séparée im orkischen Stil"); - set_string(&b->display, "Grobgeschreinerte, elfenhautbespannte Stühle und ein Tisch aus Knochen, über deren Herkunft man sich lieber keine Gedanken macht, bilden die Sitzgruppe im orkischen Stil. Überall haben Orks ihre Namen, und anderes wenig zitierenswertes in das Holz und Gebein geritzt."); - - b = new_building(bt_generic, r, NULL); - set_string(&b->name, "Séparée im Meermenschenstil"); - set_string(&b->display, "Ganz in Blau- und Grüntönen gehalten, mit Algen und Muscheln verziert wirken die aus altem Meerholz geschnitzten Stühle immer ein wenig feucht. Seltsammerweise hat der schwere aus alten Planken gezimmerte Tisch einen Mast mit kompletten Segel in der Mitte."); - - b = new_building(bt_generic, r, NULL); - set_string(&b->name, "Séparée im Katzenstil"); - set_string(&b->display, "Die Wände dieses Séparée sind aus dunklem Holz. Was aus der Ferne wie ein chaotisch durchbrochenes Flechtwerk wirkt, entpuppt sich bei näherer Betrachtung als eine bis in winzige Details gestaltete dschungelartige Landschaft, in die eine Vielzahl von kleinen Bildergeschichten eingewoben sind. Wie es scheint hat sich der Künstler Mühe gegeben wirklich jedes Katzenvolk Eresseas zu porträtieren. Das schummrige Innere wird von einem Kamin dominiert, vor dem einige Sessel und weiche Kissen zu einem gemütlichen Nickerchen einladen. Feiner Anduner Sisal bezieht die Lehnen der Sessel und verlockt dazu, seine Krallen hinein zu versenken. Auf einem kleinen Ecktisch steht ein großer Korb mit roten Wollknäulen und grauen und braunen Spielmäusen."); - } else { - for(b=r->buildings; b; b=b->next) { - b->size = b->type->maxsize; - } - } - - r = findregion(9524, 9526); - if(!r) { - r = new_region(9524, 9526, 0); - terraform_region(r, terrain_corridor); - r->planep = museum; - rsetname(r, "Nördliche Promenade"); - rsethorses(r, 0); - rsetmoney(r, 0); - rsetpeasants(r, 0); - set_string(&r->display, "Die Nördliche Promenade führt direkt in den naturgeschichtlichen Teil des Museums."); - } - r = findregion(9525, 9524); - if(!r) { - r = new_region(9525, 9524, 0); - terraform_region(r, terrain_corridor); - r->planep = museum; - rsetname(r, "Südliche Promenade"); - rsethorses(r, 0); - rsetmoney(r, 0); - rsetpeasants(r, 0); - set_string(&r->display, "Die Südliche Promenade führt den Besucher in den kulturgeschichtlichen Teil des Museums."); - } -#endif -} - -static int -use_museumexitticket(unit *u, const struct item_type *itype, int amount, order * ord) -{ - attrib *a; - region *r; - unit *warden = findunit(atoi36("mwar")); - int unit_cookie; - - unused(amount); - - /* Prüfen ob in Eingangshalle */ - if(u->region->x != 9525 || u->region->y != 9525) { - cmistake(u, ord, 266, MSG_MAGIC); - return 0; - } - - a = a_find(u->attribs, &at_museumexit); assert(a); - r = findregion(a->data.sa[0], a->data.sa[1]); assert(r); - a_remove(&u->attribs, a); - - /* Übergebene Gegenstände zurückgeben */ - - a = a_find(u->attribs, &at_museumgivebackcookie); - unit_cookie = a->data.i; - a_remove(&u->attribs, a); - - if (a) { - for(a = a_find(warden->attribs, &at_museumgiveback); a && a->type==&at_museumgiveback; a = a->next) { - if(((museumgiveback *)(a->data.v))->cookie == unit_cookie) break; - } - if (a && a->type==&at_museumgiveback) { - museumgiveback *gb = (museumgiveback *)(a->data.v); - item *it; - - for (it = gb->items; it; it = it->next) { - i_change(&u->items, it->type, it->number); - } - ADDMSG(&u->faction->msgs, msg_message("museumgiveback", "region unit sender items", r, u, warden, gb->items)); - a_remove(&warden->attribs, a); - } - } - - /* Benutzer zurück teleportieren */ - move_unit(u, r, NULL); - - /* Exitticket abziehen */ - i_change(&u->items, itype, -1); - - return 0; -} - -static int -use_museumticket(unit *u, const struct item_type *itype, int amount, order * ord) -{ - attrib *a; - region *r = u->region; - plane * pl = rplane(r); - - unused(amount); - - /* Prüfen ob in normaler Plane und nur eine Person */ - if (pl != get_homeplane()) { - cmistake(u, ord, 265, MSG_MAGIC); - return 0; - } - if(u->number != 1) { - cmistake(u, ord, 267, MSG_MAGIC); - return 0; - } - if (has_horses(u)) { - cmistake(u, ord, 272, MSG_MAGIC); - return 0; - } - - /* In diesem Attribut merken wir uns, wohin die Einheit zurückgesetzt - * wird, wenn sie das Museum verläßt. */ - - a = a_add(&u->attribs, a_new(&at_museumexit)); - a->data.sa[0] = (short)r->x; - a->data.sa[1] = (short)r->y; - - /* Benutzer in die Halle teleportieren */ - move_unit(u, findregion(9525, 9525), NULL); - - /* Ticket abziehen */ - i_change(&u->items, itype, -1); - - /* Benutzer ein Exitticket geben */ - i_change(&u->items, itype, 1); - - return 0; -} - -void -register_museum(void) -{ - at_register(&at_warden); - at_register(&at_museumexit); - at_register(&at_museumgivebackcookie); - at_register(&at_museumgiveback); - - register_item_use(use_museumticket, "use_museumticket"); - register_item_use(use_museumexitticket, "use_museumexitticket"); -} - -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include + +#include + +#if MUSEUM_MODULE +#include "museum.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +#define PFL_MUSEUM PFL_NOMONSTERS | PFL_NORECRUITS | PFL_NOGIVE | PFL_NOATTACK | PFL_NOTERRAIN | PFL_NOMAGIC | PFL_NOSTEALTH | PFL_NOTEACH | PFL_NOBUILD | PFL_NOFEED + +attrib_type at_museumexit = { + "museumexit", NULL, NULL, NULL, a_writeshorts, a_readshorts +}; + +static void +a_initmuseumgivebackcookie(attrib *a) +{ + a->data.v = calloc(1,sizeof(museumgivebackcookie)); +} + +static void +a_finalizemuseumgivebackcookie(attrib *a) +{ + free(a->data.v); +} + +static void +a_writemuseumgivebackcookie(const attrib * a, const void * owner, struct storage * store) +{ + museumgivebackcookie *gbc = (museumgivebackcookie *)a->data.v; + store->w_int(store, gbc->warden_no); + store->w_int(store, gbc->cookie); +} + +static int +a_readmuseumgivebackcookie(attrib *a, void * owner, struct storage * store) +{ + museumgivebackcookie *gbc = (museumgivebackcookie *)a->data.v; + gbc->warden_no = store->r_int(store); + gbc->cookie = store->r_int(store); + return AT_READ_OK; +} + +attrib_type at_museumgivebackcookie = { + "museumgivebackcookie", + a_initmuseumgivebackcookie, + a_finalizemuseumgivebackcookie, + NULL, + a_writemuseumgivebackcookie, + a_readmuseumgivebackcookie +}; + +attrib_type at_warden = { + "itemwarden", NULL, NULL, NULL, a_writeint, a_readint +}; + +static void +a_initmuseumgiveback(attrib *a) +{ + a->data.v = calloc(1, sizeof(museumgiveback)); +} + +static void +a_finalizemuseumgiveback(attrib *a) +{ + museumgiveback *gb = (museumgiveback *)a->data.v; + i_freeall(&gb->items); + free(a->data.v); +} + +static void +a_writemuseumgiveback(const attrib * a, const void * owner, struct storage * store) +{ + museumgiveback *gb = (museumgiveback *)a->data.v; + store->w_int(store, gb->cookie); + write_items(store, gb->items); +} + +static int +a_readmuseumgiveback(attrib *a, void * owner, struct storage * store) +{ + museumgiveback *gb = (museumgiveback *)a->data.v; + gb->cookie = store->r_int(store); + read_items(store, &gb->items); + return AT_READ_OK; +} + +attrib_type at_museumgiveback = { + "museumgiveback", + a_initmuseumgiveback, + a_finalizemuseumgiveback, + NULL, + a_writemuseumgiveback, + a_readmuseumgiveback +}; + +void +warden_add_give(unit *src, unit *u, const item_type *itype, int n) +{ + attrib *aw = a_find(u->attribs, &at_warden); + museumgiveback *gb = NULL; + museumgivebackcookie *gbc; + attrib *a; + + /* has the giver a cookie corresponding to the warden */ + for(a = a_find(src->attribs, &at_museumgivebackcookie); a && a->type==&at_museumgivebackcookie; a=a->next) { + if(((museumgivebackcookie *)(a->data.v))->warden_no == u->no) break; + } + + /* if not give it one */ + if (a==NULL || a->type!=&at_museumgivebackcookie) { + a = a_add(&src->attribs, a_new(&at_museumgivebackcookie)); + gbc = (museumgivebackcookie *)a->data.v; + gbc->warden_no = u->no; + gbc->cookie = aw->data.i; + assert(aw->data.i < INT_MAX); + aw->data.i++; + } else { + gbc = (museumgivebackcookie *)(a->data.v); + } + + /* now we search for the warden's corresponding item list */ + for (a = a_find(u->attribs, &at_museumgiveback); a && a->type==&at_museumgiveback; a=a->next) { + gb = (museumgiveback *)a->data.v; + if (gb->cookie == gbc->cookie) { + break; + } + } + + /* if there's none, give it one */ + if (!gb) { + a = a_add(&u->attribs, a_new(&at_museumgiveback)); + gb = (museumgiveback *)a->data.v; + gb->cookie = gbc->cookie; + } + + /* now register the items */ + i_change(&gb->items, itype, n); + + /* done */ + + /* this has a caveat: If the src-unit is destroyed while inside + * the museum, the corresponding itemlist of the warden will never + * be removed. to circumvent that in a generic way will be extremly + * difficult. */ +} + +void +create_museum(void) +{ +#if 0 /* TODO: move this to LUA. It should be possible. */ + unsigned int museum_id = hashstring("museum"); + plane *museum = getplanebyid(museum_id); + region *r; + building *b; + const terrain_type * terrain_hall = get_terrain("hall1"); + const terrain_type * terrain_corridor = get_terrain("corridor1"); + + assert(terrain_corridor && terrain_hall); + + if (!museum) { + museum = create_new_plane(museum_id, "Museum", 9500, 9550, + 9500, 9550, PFL_MUSEUM); + } + + if (findregion(9525, 9525) == NULL) { + /* Eingangshalle */ + r = new_region(9525, 9525, 0); + terraform_region(r, terrain_hall); + r->planep = museum; + rsetname(r, "Eingangshalle"); + rsethorses(r, 0); + rsetmoney(r, 0); + rsetpeasants(r, 0); + set_string(&r->display, "Die Eingangshalle des Großen Museum der 1. Welt ist bereits jetzt ein beeindruckender Anblick. Obwohl das Museum noch nicht eröffnet ist, vermittelt sie bereits einen Flair exotischer Welten. In den Boden ist ein großer Kompass eingelassen, der den Besuchern bei Orientierung helfen soll."); + } + + r = findregion(9526, 9525); + if(!r) { + /* Lounge */ + r = new_region(9526, 9525, 0); + terraform_region(r, terrain_hall); + r->planep = museum; + rsetname(r, "Lounge"); + rsethorses(r, 0); + rsetmoney(r, 0); + rsetpeasants(r, 0); + set_string(&r->display, "Die Lounge des großen Museums ist ein Platz, in dem sich die Besucher treffen, um die Eindrücke, die sie gewonnen haben, zu verarbeiten. Gemütliche Sitzgruppen laden zum Verweilen ein."); + } + + r = findregion(9526, 9525); + if(!r->buildings) { + const building_type * bt_generic = bt_find("generic"); + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im dämonischen Stil"); + set_string(&b->display, "Diese ganz im dämonischen Stil gehaltene Sitzgruppe ist ganz in dunklen Schwarztönen gehalten. Muster fremdartiger Runen bedecken das merkwürdig geformte Mobiliar, das unangenehm lebendig wirkt."); + + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im elfischen Stil"); + set_string(&b->display, "Ganz in Grün- und Brauntönen gehalten wirkt die Sitzgruppe fast lebendig. Bei näherer Betrachtung erschließt sich dem Betrachter, daß sie tatsächlich aus lebenden Pflanzen erstellt ist. So ist der Tisch aus einem eizigen Baum gewachsen, und die Polster bestehen aus weichen Grassoden. Ein wunderschön gemusterter Webteppich mit tausenden naturgetreu eingestickter Blumensarten bedeckt den Boden."); + + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im halblingschen Stil"); + set_string(&b->display, "Dieses rustikale Mobiliar ist aus einem einzigen, gewaltigen Baum hergestellt worden. Den Stamm haben fleißige Halblinge der Länge nach gevierteilt und aus den vier langen Viertelstämmen die Sitzbänke geschnitzt, während der verbleibende Stumpf als Tisch dient. Schon von weitem steigen dem Besucher die Gerüche der Köstlichkeiten entgegen, die auf dem Tisch stapeln."); + + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im orkischen Stil"); + set_string(&b->display, "Grobgeschreinerte, elfenhautbespannte Stühle und ein Tisch aus Knochen, über deren Herkunft man sich lieber keine Gedanken macht, bilden die Sitzgruppe im orkischen Stil. Überall haben Orks ihre Namen, und anderes wenig zitierenswertes in das Holz und Gebein geritzt."); + + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im Meermenschenstil"); + set_string(&b->display, "Ganz in Blau- und Grüntönen gehalten, mit Algen und Muscheln verziert wirken die aus altem Meerholz geschnitzten Stühle immer ein wenig feucht. Seltsammerweise hat der schwere aus alten Planken gezimmerte Tisch einen Mast mit kompletten Segel in der Mitte."); + + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im Katzenstil"); + set_string(&b->display, "Die Wände dieses Séparée sind aus dunklem Holz. Was aus der Ferne wie ein chaotisch durchbrochenes Flechtwerk wirkt, entpuppt sich bei näherer Betrachtung als eine bis in winzige Details gestaltete dschungelartige Landschaft, in die eine Vielzahl von kleinen Bildergeschichten eingewoben sind. Wie es scheint hat sich der Künstler Mühe gegeben wirklich jedes Katzenvolk Eresseas zu porträtieren. Das schummrige Innere wird von einem Kamin dominiert, vor dem einige Sessel und weiche Kissen zu einem gemütlichen Nickerchen einladen. Feiner Anduner Sisal bezieht die Lehnen der Sessel und verlockt dazu, seine Krallen hinein zu versenken. Auf einem kleinen Ecktisch steht ein großer Korb mit roten Wollknäulen und grauen und braunen Spielmäusen."); + } else { + for(b=r->buildings; b; b=b->next) { + b->size = b->type->maxsize; + } + } + + r = findregion(9524, 9526); + if(!r) { + r = new_region(9524, 9526, 0); + terraform_region(r, terrain_corridor); + r->planep = museum; + rsetname(r, "Nördliche Promenade"); + rsethorses(r, 0); + rsetmoney(r, 0); + rsetpeasants(r, 0); + set_string(&r->display, "Die Nördliche Promenade führt direkt in den naturgeschichtlichen Teil des Museums."); + } + r = findregion(9525, 9524); + if(!r) { + r = new_region(9525, 9524, 0); + terraform_region(r, terrain_corridor); + r->planep = museum; + rsetname(r, "Südliche Promenade"); + rsethorses(r, 0); + rsetmoney(r, 0); + rsetpeasants(r, 0); + set_string(&r->display, "Die Südliche Promenade führt den Besucher in den kulturgeschichtlichen Teil des Museums."); + } +#endif +} + +static int +use_museumexitticket(unit *u, const struct item_type *itype, int amount, order * ord) +{ + attrib *a; + region *r; + unit *warden = findunit(atoi36("mwar")); + int unit_cookie; + + unused(amount); + + /* Prüfen ob in Eingangshalle */ + if(u->region->x != 9525 || u->region->y != 9525) { + cmistake(u, ord, 266, MSG_MAGIC); + return 0; + } + + a = a_find(u->attribs, &at_museumexit); assert(a); + r = findregion(a->data.sa[0], a->data.sa[1]); assert(r); + a_remove(&u->attribs, a); + + /* Übergebene Gegenstände zurückgeben */ + + a = a_find(u->attribs, &at_museumgivebackcookie); + unit_cookie = a->data.i; + a_remove(&u->attribs, a); + + if (a) { + for(a = a_find(warden->attribs, &at_museumgiveback); a && a->type==&at_museumgiveback; a = a->next) { + if(((museumgiveback *)(a->data.v))->cookie == unit_cookie) break; + } + if (a && a->type==&at_museumgiveback) { + museumgiveback *gb = (museumgiveback *)(a->data.v); + item *it; + + for (it = gb->items; it; it = it->next) { + i_change(&u->items, it->type, it->number); + } + ADDMSG(&u->faction->msgs, msg_message("museumgiveback", "region unit sender items", r, u, warden, gb->items)); + a_remove(&warden->attribs, a); + } + } + + /* Benutzer zurück teleportieren */ + move_unit(u, r, NULL); + + /* Exitticket abziehen */ + i_change(&u->items, itype, -1); + + return 0; +} + +static int +use_museumticket(unit *u, const struct item_type *itype, int amount, order * ord) +{ + attrib *a; + region *r = u->region; + plane * pl = rplane(r); + + unused(amount); + + /* Prüfen ob in normaler Plane und nur eine Person */ + if (pl != get_homeplane()) { + cmistake(u, ord, 265, MSG_MAGIC); + return 0; + } + if(u->number != 1) { + cmistake(u, ord, 267, MSG_MAGIC); + return 0; + } + if (has_horses(u)) { + cmistake(u, ord, 272, MSG_MAGIC); + return 0; + } + + /* In diesem Attribut merken wir uns, wohin die Einheit zurückgesetzt + * wird, wenn sie das Museum verläßt. */ + + a = a_add(&u->attribs, a_new(&at_museumexit)); + a->data.sa[0] = (short)r->x; + a->data.sa[1] = (short)r->y; + + /* Benutzer in die Halle teleportieren */ + move_unit(u, findregion(9525, 9525), NULL); + + /* Ticket abziehen */ + i_change(&u->items, itype, -1); + + /* Benutzer ein Exitticket geben */ + i_change(&u->items, itype, 1); + + return 0; +} + +void +register_museum(void) +{ + at_register(&at_warden); + at_register(&at_museumexit); + at_register(&at_museumgivebackcookie); + at_register(&at_museumgiveback); + + register_item_use(use_museumticket, "use_museumticket"); + register_item_use(use_museumexitticket, "use_museumexitticket"); +} + +#endif diff --git a/src/modules/museum.h b/src/modules/museum.h index 940327042..bcf8457ef 100644 --- a/src/modules/museum.h +++ b/src/modules/museum.h @@ -1,53 +1,53 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef HEADER_MUSEUM_H -#define HEADER_MUSEUM_H -#ifdef __cplusplus -extern "C" { -#endif - -#if MUSEUM_MODULE == 0 -#error "must define MUSEUM_MODULE to use this module" -#endif - -extern struct attrib_type at_warden; -extern struct attrib_type at_museumexit; -extern struct attrib_type at_museumgivebackcookie; -extern struct attrib_type at_museumgiveback; - -typedef struct { - int warden_no; - int cookie; -} museumgivebackcookie; - -typedef struct { - int cookie; - struct item *items; -} museumgiveback; - -extern void register_museum(void); -extern void create_museum(void); -extern void warden_add_give(struct unit *src, struct unit *u, const struct item_type *itype, int n); - -#ifdef __cplusplus -} -#endif - - -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef HEADER_MUSEUM_H +#define HEADER_MUSEUM_H +#ifdef __cplusplus +extern "C" { +#endif + +#if MUSEUM_MODULE == 0 +#error "must define MUSEUM_MODULE to use this module" +#endif + +extern struct attrib_type at_warden; +extern struct attrib_type at_museumexit; +extern struct attrib_type at_museumgivebackcookie; +extern struct attrib_type at_museumgiveback; + +typedef struct { + int warden_no; + int cookie; +} museumgivebackcookie; + +typedef struct { + int cookie; + struct item *items; +} museumgiveback; + +extern void register_museum(void); +extern void create_museum(void); +extern void warden_add_give(struct unit *src, struct unit *u, const struct item_type *itype, int n); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/src/modules/oceannames.c b/src/modules/oceannames.c index c39c21516..b52eddec3 100644 --- a/src/modules/oceannames.c +++ b/src/modules/oceannames.c @@ -1,126 +1,126 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "oceannames.h" - -/* kernel includes */ -#include -#include - -/* util includes */ -#include - -/* libc includes */ -#include -#include - -typedef struct namehash { - struct namehash * next; - const char * name; -} namehash; - -#define NMAXHASH 1023 -namehash names[NMAXHASH]; - -void nhash(const char * name); - -typedef struct oceanname { - struct oceanname * next; - struct faction_list * factions; - const char * name; -} oceanname; - -static void -free_names(attrib * a) -{ - oceanname * data = (oceanname*)a->data.v; - while (a->data.v) { - a->data.v = data->next; - free(data); - } -} - -struct attrib_type at_oceanname = { "names", NULL, free_names, NULL/*, write_names, read_names, ATF_UNIQUE */}; - -const char * -get_oceanname(const struct region * r, const struct faction * f) -{ - attrib * a = a_find(r->attribs, &at_oceanname); - if (a) { - oceanname * names = (oceanname*)a->data.v; - while (names) { - faction_list * fl = names->factions; - while (fl) { - if (fl->data==f) return names->name; - fl=fl->next; - } - names = names->next; - } - } - return NULL; -} - -void -nameocean(struct region *r, struct faction * f, const char * newname) -{ - attrib * a = a_find(r->attribs, &at_oceanname); - if (!a && newname) a = a_add(&r->attribs, a_new(&at_oceanname)); - if (a) { - faction_list **oldf = NULL, **newf = NULL; - faction_list * fl = NULL; - oceanname * names = (oceanname*)a->data.v; - while ((names && (!newf && newname)) || !oldf) { - faction_list ** fli = &names->factions; - if (oldf==NULL) while (*fli) { - if ((*fli)->data==f) { - oldf = fli; - break; - } - fli=&(*fli)->next; - } - if (newname && !newf && !strcmp(names->name, newname)) { - newf = fli; - } - names = names->next; - } - - if (oldf) { - fl = *oldf; - *oldf = fl->next; - } else if (newname) { - fl = calloc(1, sizeof(faction_list)); - } - - if (newf) { - fl->data = f; - fl->next = *newf; - *newf = fl; - } else if (newname) { - oceanname * nm = calloc(1, sizeof(oceanname)); - nm->factions = fl; - fl->data = f; - fl->next = NULL; - nm->next = (oceanname*)a->data.v; - a->data.v = nm; - } else if (fl) { - free(fl); - } - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "oceannames.h" + +/* kernel includes */ +#include +#include + +/* util includes */ +#include + +/* libc includes */ +#include +#include + +typedef struct namehash { + struct namehash * next; + const char * name; +} namehash; + +#define NMAXHASH 1023 +namehash names[NMAXHASH]; + +void nhash(const char * name); + +typedef struct oceanname { + struct oceanname * next; + struct faction_list * factions; + const char * name; +} oceanname; + +static void +free_names(attrib * a) +{ + oceanname * data = (oceanname*)a->data.v; + while (a->data.v) { + a->data.v = data->next; + free(data); + } +} + +struct attrib_type at_oceanname = { "names", NULL, free_names, NULL/*, write_names, read_names, ATF_UNIQUE */}; + +const char * +get_oceanname(const struct region * r, const struct faction * f) +{ + attrib * a = a_find(r->attribs, &at_oceanname); + if (a) { + oceanname * names = (oceanname*)a->data.v; + while (names) { + faction_list * fl = names->factions; + while (fl) { + if (fl->data==f) return names->name; + fl=fl->next; + } + names = names->next; + } + } + return NULL; +} + +void +nameocean(struct region *r, struct faction * f, const char * newname) +{ + attrib * a = a_find(r->attribs, &at_oceanname); + if (!a && newname) a = a_add(&r->attribs, a_new(&at_oceanname)); + if (a) { + faction_list **oldf = NULL, **newf = NULL; + faction_list * fl = NULL; + oceanname * names = (oceanname*)a->data.v; + while ((names && (!newf && newname)) || !oldf) { + faction_list ** fli = &names->factions; + if (oldf==NULL) while (*fli) { + if ((*fli)->data==f) { + oldf = fli; + break; + } + fli=&(*fli)->next; + } + if (newname && !newf && !strcmp(names->name, newname)) { + newf = fli; + } + names = names->next; + } + + if (oldf) { + fl = *oldf; + *oldf = fl->next; + } else if (newname) { + fl = calloc(1, sizeof(faction_list)); + } + + if (newf) { + fl->data = f; + fl->next = *newf; + *newf = fl; + } else if (newname) { + oceanname * nm = calloc(1, sizeof(oceanname)); + nm->factions = fl; + fl->data = f; + fl->next = NULL; + nm->next = (oceanname*)a->data.v; + a->data.v = nm; + } else if (fl) { + free(fl); + } + } +} diff --git a/src/modules/oceannames.h b/src/modules/oceannames.h index 625979f56..ed5e4b5cc 100644 --- a/src/modules/oceannames.h +++ b/src/modules/oceannames.h @@ -1,32 +1,32 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_MOD_OCEANNAMES -#define H_MOD_OCEANNAMES -#ifdef __cplusplus -extern "C" { -#endif - -struct faction; -struct region; -extern const char * get_oceanname(const struct region * r, const struct faction * f); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_MOD_OCEANNAMES +#define H_MOD_OCEANNAMES +#ifdef __cplusplus +extern "C" { +#endif + +struct faction; +struct region; +extern const char * get_oceanname(const struct region * r, const struct faction * f); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/score.c b/src/modules/score.c index a58bc6c89..46b61f418 100644 --- a/src/modules/score.c +++ b/src/modules/score.c @@ -1,212 +1,212 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#if SCORE_MODULE -#include "score.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include - -/* libc includes */ -#include - -int -average_score_of_age(int age, int a) -{ - faction *f; - int sum = 0, count = 0; - - for (f = factions; f; f = f->next) { - if (!is_monsters(f) && f->race != new_race[RC_TEMPLATE] && f->age <= age + a && f->age >= age - a) { - sum += f->score; - count++; - } - } - - if (count == 0) { - return 0; - } - return sum / count; -} - -void -score(void) -{ - FILE *scoreFP; - region *r; - faction *fc; - int allscores = 0; - char path[MAX_PATH]; - - for (fc = factions; fc; fc = fc->next) fc->score = 0; - - for (r = regions; r; r = r->next) { - unit * u; - building * b; - ship * s; - - if (rule_region_owners()) { - fc = region_get_owner(r); - if (fc) fc->score += 10; - } - - for (b = r->buildings; b; b = b->next) { - u = building_owner(b); - if (u!=NULL) { - faction * fbo = u->faction; - - if (fbo) { - fbo->score += b->size * 5; - } - } - } - - for (s = r->ships; s; s = s->next) { - unit * cap = shipowner(s); - if (cap && cap->faction) { - cap->faction->score += s->size * 2; - } - } - - for (u = r->units; u; u = u->next) { - item * itm; - int itemscore = 0; - int i; - faction * f = u->faction; - - if (f==NULL || u->race == new_race[RC_SPELL] || u->race == new_race[RC_BIRTHDAYDRAGON]) { - continue; - } - - if (old_race(u->race) <= RC_AQUARIAN) { - f->score += (u->race->recruitcost * u->number) / 50; - } - f->score += get_money(u) / 50; - for (itm=u->items; itm; itm=itm->next) { - itemscore += itm->number * itm->type->score; - } - f->score += itemscore / 10; - - for (i=0;i!=u->skill_size;++i) { - skill * sv = u->skills+i; - switch (sv->id) { - case SK_MAGIC: - f->score += (int)(u->number * pow(sv->level, 4)); - break; - case SK_TACTICS: - f->score += (int)(u->number * pow(sv->level, 3)); - break; - case SK_SPY: - case SK_ALCHEMY: - case SK_HERBALISM: - f->score += (int)(u->number * pow(sv->level, 2.5)); - break; - default: - f->score += (int)(u->number * pow(sv->level, 2.5) / 10); - break; - } - } - } - } - - for (fc = factions; fc; fc = fc->next) { - fc->score = fc->score / 5; - if (!is_monsters(fc) && fc->race != new_race[RC_TEMPLATE]) { - allscores += fc->score; - } - } - if (allscores == 0) { - allscores = 1; - } - - sprintf(path, "%s/score", basepath()); - scoreFP = fopen(path, "w"); - if (scoreFP) { - const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; - faction * f; - fwrite(utf8_bom, 1, 3, scoreFP); - for (f = factions; f; f = f->next) if (f->num_total != 0) { - fprintf(scoreFP, "%8d (%8d/%4.2f%%/%5.2f) %30.30s (%3.3s) %5s (%3d)\n", - f->score, f->score - average_score_of_age(f->age, f->age / 24 + 1), - ((float) f->score / (float) allscores) * 100.0, - (float) f->score / f->num_total, - f->name, LOC(default_locale, rc_name(f->race, 0)), factionid(f), f->age); - } - fclose(scoreFP); - } - if (alliances!=NULL) { - alliance *a; - const item_type * token = it_find("conquesttoken"); - - sprintf(path, "%s/score.alliances", basepath()); - scoreFP = fopen(path, "w"); - if (scoreFP) { - const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; - fwrite(utf8_bom, 1, 3, scoreFP); - - fprintf(scoreFP, "# alliance:factions:persons:score\n"); - - for (a = alliances; a; a = a->next) { - int alliance_score = 0, alliance_number = 0, alliance_factions = 0; - int grails = 0; - faction * f; - - for (f = factions; f; f = f->next) { - if (f->alliance && f->alliance == a) { - alliance_factions++; - alliance_score += f->score; - alliance_number += f->num_total; - if (token!=NULL) { - unit * u = f->units; - while (u!=NULL) { - item ** iitem = i_find(&u->items, token); - if (iitem!=NULL && *iitem!=NULL) { - grails += (*iitem)->number; - } - u=u->nextF; - } - } - } - } - - fprintf(scoreFP, "%d:%d:%d:%d", a->id, alliance_factions, alliance_number, alliance_score); - if (token!=NULL) fprintf(scoreFP, ":%d", grails); - fputc('\n', scoreFP); - } - fclose(scoreFP); - } - } -} - -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#if SCORE_MODULE +#include "score.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include + +/* libc includes */ +#include + +int +average_score_of_age(int age, int a) +{ + faction *f; + int sum = 0, count = 0; + + for (f = factions; f; f = f->next) { + if (!is_monsters(f) && f->race != new_race[RC_TEMPLATE] && f->age <= age + a && f->age >= age - a) { + sum += f->score; + count++; + } + } + + if (count == 0) { + return 0; + } + return sum / count; +} + +void +score(void) +{ + FILE *scoreFP; + region *r; + faction *fc; + int allscores = 0; + char path[MAX_PATH]; + + for (fc = factions; fc; fc = fc->next) fc->score = 0; + + for (r = regions; r; r = r->next) { + unit * u; + building * b; + ship * s; + + if (rule_region_owners()) { + fc = region_get_owner(r); + if (fc) fc->score += 10; + } + + for (b = r->buildings; b; b = b->next) { + u = building_owner(b); + if (u!=NULL) { + faction * fbo = u->faction; + + if (fbo) { + fbo->score += b->size * 5; + } + } + } + + for (s = r->ships; s; s = s->next) { + unit * cap = shipowner(s); + if (cap && cap->faction) { + cap->faction->score += s->size * 2; + } + } + + for (u = r->units; u; u = u->next) { + item * itm; + int itemscore = 0; + int i; + faction * f = u->faction; + + if (f==NULL || u->race == new_race[RC_SPELL] || u->race == new_race[RC_BIRTHDAYDRAGON]) { + continue; + } + + if (old_race(u->race) <= RC_AQUARIAN) { + f->score += (u->race->recruitcost * u->number) / 50; + } + f->score += get_money(u) / 50; + for (itm=u->items; itm; itm=itm->next) { + itemscore += itm->number * itm->type->score; + } + f->score += itemscore / 10; + + for (i=0;i!=u->skill_size;++i) { + skill * sv = u->skills+i; + switch (sv->id) { + case SK_MAGIC: + f->score += (int)(u->number * pow(sv->level, 4)); + break; + case SK_TACTICS: + f->score += (int)(u->number * pow(sv->level, 3)); + break; + case SK_SPY: + case SK_ALCHEMY: + case SK_HERBALISM: + f->score += (int)(u->number * pow(sv->level, 2.5)); + break; + default: + f->score += (int)(u->number * pow(sv->level, 2.5) / 10); + break; + } + } + } + } + + for (fc = factions; fc; fc = fc->next) { + fc->score = fc->score / 5; + if (!is_monsters(fc) && fc->race != new_race[RC_TEMPLATE]) { + allscores += fc->score; + } + } + if (allscores == 0) { + allscores = 1; + } + + sprintf(path, "%s/score", basepath()); + scoreFP = fopen(path, "w"); + if (scoreFP) { + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + faction * f; + fwrite(utf8_bom, 1, 3, scoreFP); + for (f = factions; f; f = f->next) if (f->num_total != 0) { + fprintf(scoreFP, "%8d (%8d/%4.2f%%/%5.2f) %30.30s (%3.3s) %5s (%3d)\n", + f->score, f->score - average_score_of_age(f->age, f->age / 24 + 1), + ((float) f->score / (float) allscores) * 100.0, + (float) f->score / f->num_total, + f->name, LOC(default_locale, rc_name(f->race, 0)), factionid(f), f->age); + } + fclose(scoreFP); + } + if (alliances!=NULL) { + alliance *a; + const item_type * token = it_find("conquesttoken"); + + sprintf(path, "%s/score.alliances", basepath()); + scoreFP = fopen(path, "w"); + if (scoreFP) { + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + fwrite(utf8_bom, 1, 3, scoreFP); + + fprintf(scoreFP, "# alliance:factions:persons:score\n"); + + for (a = alliances; a; a = a->next) { + int alliance_score = 0, alliance_number = 0, alliance_factions = 0; + int grails = 0; + faction * f; + + for (f = factions; f; f = f->next) { + if (f->alliance && f->alliance == a) { + alliance_factions++; + alliance_score += f->score; + alliance_number += f->num_total; + if (token!=NULL) { + unit * u = f->units; + while (u!=NULL) { + item ** iitem = i_find(&u->items, token); + if (iitem!=NULL && *iitem!=NULL) { + grails += (*iitem)->number; + } + u=u->nextF; + } + } + } + } + + fprintf(scoreFP, "%d:%d:%d:%d", a->id, alliance_factions, alliance_number, alliance_score); + if (token!=NULL) fprintf(scoreFP, ":%d", grails); + fputc('\n', scoreFP); + } + fclose(scoreFP); + } + } +} + +#endif diff --git a/src/modules/score.h b/src/modules/score.h index b9c502c8d..335afc23d 100644 --- a/src/modules/score.h +++ b/src/modules/score.h @@ -1,36 +1,36 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef SCORE_H -#define SCORE_H -#ifdef __cplusplus -extern "C" { -#endif - -#if SCORE_MODULE == 0 -#error "must define SCORE_MODULE to use this module" -#endif - - -extern void score(void); -extern int average_score_of_age(int age, int a); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef SCORE_H +#define SCORE_H +#ifdef __cplusplus +extern "C" { +#endif + +#if SCORE_MODULE == 0 +#error "must define SCORE_MODULE to use this module" +#endif + + +extern void score(void); +extern int average_score_of_age(int age, int a); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/weather.c b/src/modules/weather.c index 98bab62d0..03b5b035c 100644 --- a/src/modules/weather.c +++ b/src/modules/weather.c @@ -1,141 +1,141 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifdef WEATHER - -#include -#include -#include "weather.h" - -/* libc includes */ -#include - -weather * -create_weather(region *r, weather_t type) - -{ - weather *w; - - w = calloc(1, sizeof(weather)); - w->center[0] = r->x; - w->center[1] = r->y; - w->type = type; - w->move[0] = (rng_int()%3) - 1; - w->move[1] = (rng_int()%3) - 1; - - switch(type) { - case WEATHER_STORM: - w->radius = rng_int()%2+1; - break; - case WEATHER_HURRICANE: - w->radius = 1; - break; - default: - w->radius = 0; - } - - addlist(&weathers, w); - - return w; -} - -double -distance(int x1, int y1, int x2, int y2) - -{ - return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); -} - -/* Diese Funktion ermittelt für jede Region, welches Wetter in ihr - herrscht. Die Wettertypen sind dabei nach ihrer Reihenfolge in der - enumeration priorisiert. - - - Einladen - set_weather(); - - Eigentliche Auswertung - - Veränderungen des Wetters - set_weather(); - - Report generieren - - Abspeichern - - Diese Routine ist sehr rechenaufwendig! -*/ - -void -set_weather(void) - -{ - weather_t i; - weather *w; - short x, y; - int d; - region *r; - - for(r=regions;r;r=r->next) { - r->weathertype = WEATHER_NONE; - } - - for(i = 0; i < MAXWEATHERS; i++) { - for(w = weathers; w; w = w->next) { - if(w->type == i) { - for(x=w->center[0]-w->radius; x<=w->center[0]+w->radius; x++) { - for(y=w->center[1]-w->radius; y<=w->center[1]+w->radius; y++) { - d = distance(w->center[0], w->center[1], x, y); - if(floor(d+0.5) <= w->radius) { - r = findregion(x,y); - if(r) { - r->weathertype = w->type; - } - } - } - } - } - } - } -} - -void -move_weather(void) - -{ - weather *w, *wnext; - region *r; - - for(w = weathers; w;) { - wnext = w->next; - w->center[0] = w->center[0] + w->move[0]; - w->center[1] = w->center[1] + w->move[1]; - r = findregion(w->center[0], w->center[1]); - if(!r || rng_int()%100 < 5) { - removelist(&weathers, w); - } - w = wnext; - } -} - -#else -#include -static const char* copyright = "(c) Eressea PBEM 2000"; - -void -init_weather(void) -{ - fputs(copyright, stderr); - /* TODO: Initialization */ -} -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifdef WEATHER + +#include +#include +#include "weather.h" + +/* libc includes */ +#include + +weather * +create_weather(region *r, weather_t type) + +{ + weather *w; + + w = calloc(1, sizeof(weather)); + w->center[0] = r->x; + w->center[1] = r->y; + w->type = type; + w->move[0] = (rng_int()%3) - 1; + w->move[1] = (rng_int()%3) - 1; + + switch(type) { + case WEATHER_STORM: + w->radius = rng_int()%2+1; + break; + case WEATHER_HURRICANE: + w->radius = 1; + break; + default: + w->radius = 0; + } + + addlist(&weathers, w); + + return w; +} + +double +distance(int x1, int y1, int x2, int y2) + +{ + return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); +} + +/* Diese Funktion ermittelt für jede Region, welches Wetter in ihr + herrscht. Die Wettertypen sind dabei nach ihrer Reihenfolge in der + enumeration priorisiert. + + - Einladen + set_weather(); + - Eigentliche Auswertung + - Veränderungen des Wetters + set_weather(); + - Report generieren + - Abspeichern + + Diese Routine ist sehr rechenaufwendig! +*/ + +void +set_weather(void) + +{ + weather_t i; + weather *w; + short x, y; + int d; + region *r; + + for(r=regions;r;r=r->next) { + r->weathertype = WEATHER_NONE; + } + + for(i = 0; i < MAXWEATHERS; i++) { + for(w = weathers; w; w = w->next) { + if(w->type == i) { + for(x=w->center[0]-w->radius; x<=w->center[0]+w->radius; x++) { + for(y=w->center[1]-w->radius; y<=w->center[1]+w->radius; y++) { + d = distance(w->center[0], w->center[1], x, y); + if(floor(d+0.5) <= w->radius) { + r = findregion(x,y); + if(r) { + r->weathertype = w->type; + } + } + } + } + } + } + } +} + +void +move_weather(void) + +{ + weather *w, *wnext; + region *r; + + for(w = weathers; w;) { + wnext = w->next; + w->center[0] = w->center[0] + w->move[0]; + w->center[1] = w->center[1] + w->move[1]; + r = findregion(w->center[0], w->center[1]); + if(!r || rng_int()%100 < 5) { + removelist(&weathers, w); + } + w = wnext; + } +} + +#else +#include +static const char* copyright = "(c) Eressea PBEM 2000"; + +void +init_weather(void) +{ + fputs(copyright, stderr); + /* TODO: Initialization */ +} +#endif diff --git a/src/modules/weather.h b/src/modules/weather.h index 60800c7e9..6ec87dd14 100644 --- a/src/modules/weather.h +++ b/src/modules/weather.h @@ -1,54 +1,54 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_MOD_WEATHER_H -#define H_MOD_WEATHER_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WEATHER -# error "the weather system is disabled" -#endif - -enum { - WEATHER_NONE, - WEATHER_STORM, - WEATHER_HURRICANE, - MAXWEATHERS -}; - -typedef unsigned char weather_t; - -typedef struct weather { - struct weather *next; - weather_t type; /* Typ der Wetterzone */ - int center[2]; /* Koordinaten des Zentrums */ - int radius; - int move[2]; -} weather; - -weather *weathers; - -void set_weather(void); -void move_weather(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_MOD_WEATHER_H +#define H_MOD_WEATHER_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WEATHER +# error "the weather system is disabled" +#endif + +enum { + WEATHER_NONE, + WEATHER_STORM, + WEATHER_HURRICANE, + MAXWEATHERS +}; + +typedef unsigned char weather_t; + +typedef struct weather { + struct weather *next; + weather_t type; /* Typ der Wetterzone */ + int center[2]; /* Koordinaten des Zentrums */ + int radius; + int move[2]; +} weather; + +weather *weathers; + +void set_weather(void); +void move_weather(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/wormhole.c b/src/modules/wormhole.c index 144c0656a..1ad7c93bf 100644 --- a/src/modules/wormhole.c +++ b/src/modules/wormhole.c @@ -1,222 +1,221 @@ -/* vi: set ts=2: - +-------------------+ - | | Christian Schlittchen - | Eressea PBEM host | Enno Rehling - | (c) 1998 - 2004 | Katja Zedel - | | - +-------------------+ - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "settings.h" - -#include "wormhole.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include - -static boolean -good_region(const region * r) -{ - return (!fval(r, RF_CHAOTIC) && r->age>30 && rplane(r)==NULL && r->units!=NULL && r->land!=NULL); -} - -static int -cmp_age(const void * v1, const void *v2) -{ - const region * r1 = (const region*)v1; - const region * r2 = (const region*)v2; - if (r1->ageage) return -1; - if (r1->age>r2->age) return 1; - return 0; -} - -typedef struct wormhole_data { - building * entry; - region * exit; -} wormhole_data; - -static void -wormhole_init(struct attrib *a) -{ - a->data.v = calloc(1, sizeof(wormhole_data)); -} - -static void -wormhole_done(struct attrib * a) -{ - free(a->data.v); -} - -static int -wormhole_age(struct attrib * a) -{ - wormhole_data * data = (wormhole_data*)a->data.v; - int maxtransport = data->entry->size; - region * r = data->entry->region; - unit * u = r->units; - - for (;u!=NULL && maxtransport!=0;u=u->next) { - if (u->building==data->entry) { - message * m = NULL; - if (u->number>maxtransport || has_limited_skills(u)) { - m = msg_message("wormhole_requirements", "unit region", u, u->region); - } else if (data->exit!=NULL) { - move_unit(u, data->exit, NULL); - maxtransport -= u->number; - m = msg_message("wormhole_exit", "unit region", u, data->exit); - add_message(&data->exit->msgs, m); - } - if (m!=NULL) { - add_message(&u->faction->msgs, m); - msg_release(m); - } - } - } - - remove_building(&r->buildings, data->entry); - ADDMSG(&r->msgs, msg_message("wormhole_dissolve", "region", r)); - - /* age returns 0 if the attribute needs to be removed, !=0 otherwise */ - return AT_AGE_KEEP; -} - -static void -wormhole_write(const struct attrib * a, const void * owner, struct storage * store) -{ - wormhole_data * data = (wormhole_data*)a->data.v; - write_building_reference(data->entry, store); - write_region_reference(data->exit, store); -} - -/** conversion code, turn 573, 2008-05-23 */ -static int -resolve_exit(variant id, void * address) -{ - building * b = findbuilding(id.i); - region ** rp = address; - if (b) { - *rp = b->region; - return 0; - } - *rp = NULL; - return -1; -} - -static int -wormhole_read(struct attrib * a, void * owner, struct storage * store) -{ - wormhole_data * data = (wormhole_data*)a->data.v; - resolve_fun resolver = (store->versionversionentry, store, read_building_reference, resolve_building); - int rr = read_reference(&data->exit, store, reader, resolver); - if (rb==0 && rr==0) { - if (!data->exit || !data->entry) { - return AT_READ_FAIL; - } - } - return AT_READ_OK; -} - -static attrib_type at_wormhole = { - "wormhole", - wormhole_init, - wormhole_done, - wormhole_age, - wormhole_write, - wormhole_read, - ATF_UNIQUE -}; - -static void -make_wormhole(const building_type * bt_wormhole, region * r1, region * r2) -{ - building * b1 = new_building(bt_wormhole, r1, default_locale); - building * b2 = new_building(bt_wormhole, r2, default_locale); - attrib * a1 = a_add(&b1->attribs, a_new(&at_wormhole)); - attrib * a2 = a_add(&b2->attribs, a_new(&at_wormhole)); - wormhole_data * d1 = (wormhole_data*)a1->data.v; - wormhole_data * d2 = (wormhole_data*)a2->data.v; - d1->entry = b1; - d2->entry = b2; - d1->exit = b2->region; - d2->exit = b1->region; - b1->size = bt_wormhole->maxsize; - b2->size = bt_wormhole->maxsize; - ADDMSG(&r1->msgs, msg_message("wormhole_appear", "region", r1)); - ADDMSG(&r2->msgs, msg_message("wormhole_appear", "region", r2)); -} - -void -create_wormholes(void) -{ -#define WORMHOLE_CHANCE 10000 - const building_type * bt_wormhole = bt_find("wormhole"); - region_list *rptr, * rlist = NULL; - region * r = regions; - int i = 0, count = 0; - region ** match; - - if (bt_wormhole==NULL) return; - /* - * select a list of regions. we'll sort them by age later. - */ - while (r!=NULL) { - int next = rng_int() % (2*WORMHOLE_CHANCE); - while (r!=NULL && (next!=0 || !good_region(r))) { - if (good_region(r)) { - --next; - } - r=r->next; - } - if (r==NULL) break; - add_regionlist(&rlist, r); - ++count; - r=r->next; - } - - if (count<2) return; - - match = (region**)malloc(sizeof(region*) * count); - rptr = rlist; - while (i!=count) { - match[i++] = rptr->data; - rptr = rptr->next; - } - qsort(match, count, sizeof(region *), cmp_age); - free_regionlist(rlist); - - count /= 2; - for (i=0;i!=count;++i) { - make_wormhole(bt_wormhole, match[i], match[i+count]); - } -} - -void -register_wormholes(void) -{ - at_register(&at_wormhole); -} +/* vi: set ts=2: + +-------------------+ + | | Christian Schlittchen + | Eressea PBEM host | Enno Rehling + | (c) 1998 - 2004 | Katja Zedel + | | + +-------------------+ + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "settings.h" + +#include "wormhole.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include + +/* libc includes */ +#include +#include + +static boolean +good_region(const region * r) +{ + return (!fval(r, RF_CHAOTIC) && r->age>30 && rplane(r)==NULL && r->units!=NULL && r->land!=NULL); +} + +static int +cmp_age(const void * v1, const void *v2) +{ + const region * r1 = (const region*)v1; + const region * r2 = (const region*)v2; + if (r1->ageage) return -1; + if (r1->age>r2->age) return 1; + return 0; +} + +typedef struct wormhole_data { + building * entry; + region * exit; +} wormhole_data; + +static void +wormhole_init(struct attrib *a) +{ + a->data.v = calloc(1, sizeof(wormhole_data)); +} + +static void +wormhole_done(struct attrib * a) +{ + free(a->data.v); +} + +static int +wormhole_age(struct attrib * a) +{ + wormhole_data * data = (wormhole_data*)a->data.v; + int maxtransport = data->entry->size; + region * r = data->entry->region; + unit * u = r->units; + + for (;u!=NULL && maxtransport!=0;u=u->next) { + if (u->building==data->entry) { + message * m = NULL; + if (u->number>maxtransport || has_limited_skills(u)) { + m = msg_message("wormhole_requirements", "unit region", u, u->region); + } else if (data->exit!=NULL) { + move_unit(u, data->exit, NULL); + maxtransport -= u->number; + m = msg_message("wormhole_exit", "unit region", u, data->exit); + add_message(&data->exit->msgs, m); + } + if (m!=NULL) { + add_message(&u->faction->msgs, m); + msg_release(m); + } + } + } + + remove_building(&r->buildings, data->entry); + ADDMSG(&r->msgs, msg_message("wormhole_dissolve", "region", r)); + + /* age returns 0 if the attribute needs to be removed, !=0 otherwise */ + return AT_AGE_KEEP; +} + +static void +wormhole_write(const struct attrib * a, const void * owner, struct storage * store) +{ + wormhole_data * data = (wormhole_data*)a->data.v; + write_building_reference(data->entry, store); + write_region_reference(data->exit, store); +} + +/** conversion code, turn 573, 2008-05-23 */ +static int +resolve_exit(variant id, void * address) +{ + building * b = findbuilding(id.i); + region ** rp = address; + if (b) { + *rp = b->region; + return 0; + } + *rp = NULL; + return -1; +} + +static int +wormhole_read(struct attrib * a, void * owner, struct storage * store) +{ + wormhole_data * data = (wormhole_data*)a->data.v; + resolve_fun resolver = (store->versionversionentry, store, read_building_reference, resolve_building); + int rr = read_reference(&data->exit, store, reader, resolver); + if (rb==0 && rr==0) { + if (!data->exit || !data->entry) { + return AT_READ_FAIL; + } + } + return AT_READ_OK; +} + +static attrib_type at_wormhole = { + "wormhole", + wormhole_init, + wormhole_done, + wormhole_age, + wormhole_write, + wormhole_read, + ATF_UNIQUE +}; + +static void +make_wormhole(const building_type * bt_wormhole, region * r1, region * r2) +{ + building * b1 = new_building(bt_wormhole, r1, default_locale); + building * b2 = new_building(bt_wormhole, r2, default_locale); + attrib * a1 = a_add(&b1->attribs, a_new(&at_wormhole)); + attrib * a2 = a_add(&b2->attribs, a_new(&at_wormhole)); + wormhole_data * d1 = (wormhole_data*)a1->data.v; + wormhole_data * d2 = (wormhole_data*)a2->data.v; + d1->entry = b1; + d2->entry = b2; + d1->exit = b2->region; + d2->exit = b1->region; + b1->size = bt_wormhole->maxsize; + b2->size = bt_wormhole->maxsize; + ADDMSG(&r1->msgs, msg_message("wormhole_appear", "region", r1)); + ADDMSG(&r2->msgs, msg_message("wormhole_appear", "region", r2)); +} + +void +create_wormholes(void) +{ +#define WORMHOLE_CHANCE 10000 + const building_type * bt_wormhole = bt_find("wormhole"); + region_list *rptr, * rlist = NULL; + region * r = regions; + int i = 0, count = 0; + region ** match; + + if (bt_wormhole==NULL) return; + /* + * select a list of regions. we'll sort them by age later. + */ + while (r!=NULL) { + int next = rng_int() % (2*WORMHOLE_CHANCE); + while (r!=NULL && (next!=0 || !good_region(r))) { + if (good_region(r)) { + --next; + } + r=r->next; + } + if (r==NULL) break; + add_regionlist(&rlist, r); + ++count; + r=r->next; + } + + if (count<2) return; + + match = (region**)malloc(sizeof(region*) * count); + rptr = rlist; + while (i!=count) { + match[i++] = rptr->data; + rptr = rptr->next; + } + qsort(match, count, sizeof(region *), cmp_age); + free_regionlist(rlist); + + count /= 2; + for (i=0;i!=count;++i) { + make_wormhole(bt_wormhole, match[i], match[i+count]); + } +} + +void +register_wormholes(void) +{ + at_register(&at_wormhole); +} diff --git a/src/modules/wormhole.h b/src/modules/wormhole.h index 9bb5507f1..dea7a6aab 100644 --- a/src/modules/wormhole.h +++ b/src/modules/wormhole.h @@ -1,31 +1,31 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_MOD_WORMHOLE -#define H_MOD_WORMHOLE -#ifdef __cplusplus -extern "C" { -#endif - - extern void create_wormholes(void); - extern void register_wormholes(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_MOD_WORMHOLE +#define H_MOD_WORMHOLE +#ifdef __cplusplus +extern "C" { +#endif + + extern void create_wormholes(void); + extern void register_wormholes(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/modules/xecmd.c b/src/modules/xecmd.c index 9a1f7765f..b181766b2 100644 --- a/src/modules/xecmd.c +++ b/src/modules/xecmd.c @@ -1,111 +1,111 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include - -#if XECMD_MODULE -#include "xecmd.h" - -#include - -#include "xecmd.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -static void -xe_givelaen(unit *u, struct order * ord) -{ - unit *u2 =getunitg(u->region, u->faction); - - if(!u2) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return; - } - i_change(&u2->items, olditemtype[I_LAEN], 5); -} - -static void -xe_givepotion(unit *u, struct order *ord) -{ - unit *u2 =getunitg(u->region, u->faction); - - if(!u2) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return; - } - i_change(&u2->items, it_find("skillpotion"), 1); -} - -static void -xe_giveballon(unit *u, struct order *ord) -{ - unit *u2 = getunitg(u->region, u->faction); - ship *sh; - - if (!u2) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return; - } - - sh = new_ship(st_find("balloon"), u2->faction->locale, u2->region); - sh->size = 5; - ship_setname(sh, "Xontormia-Ballon"); - leave(u2, false); - u2->ship = sh; - fset(u2, UFL_OWNER); -} - -int -xecmd(unit * u, order * ord) -{ - faction *f = u->faction; - - if (a_find(f->attribs, &at_xontormiaexpress)) { - if (get_keyword(ord) == K_XE) { - init_tokens(ord); - skip_token(); - switch(findparam(getstrtoken(),f->locale)) { - case P_XEPOTION: - xe_givepotion(u, ord); - break; - case P_XEBALLOON: - xe_giveballon(u, ord); - break; - case P_XELAEN: - xe_givelaen(u, ord); - break; - } - } - } - return 0; -} - -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include + +#if XECMD_MODULE +#include "xecmd.h" + +#include + +#include "xecmd.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +static void +xe_givelaen(unit *u, struct order * ord) +{ + unit *u2 =getunitg(u->region, u->faction); + + if(!u2) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + i_change(&u2->items, olditemtype[I_LAEN], 5); +} + +static void +xe_givepotion(unit *u, struct order *ord) +{ + unit *u2 =getunitg(u->region, u->faction); + + if(!u2) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + i_change(&u2->items, it_find("skillpotion"), 1); +} + +static void +xe_giveballon(unit *u, struct order *ord) +{ + unit *u2 = getunitg(u->region, u->faction); + ship *sh; + + if (!u2) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + return; + } + + sh = new_ship(st_find("balloon"), u2->faction->locale, u2->region); + sh->size = 5; + ship_setname(sh, "Xontormia-Ballon"); + leave(u2, false); + u2->ship = sh; + fset(u2, UFL_OWNER); +} + +int +xecmd(unit * u, order * ord) +{ + faction *f = u->faction; + + if (a_find(f->attribs, &at_xontormiaexpress)) { + if (get_keyword(ord) == K_XE) { + init_tokens(ord); + skip_token(); + switch(findparam(getstrtoken(),f->locale)) { + case P_XEPOTION: + xe_givepotion(u, ord); + break; + case P_XEBALLOON: + xe_giveballon(u, ord); + break; + case P_XELAEN: + xe_givelaen(u, ord); + break; + } + } + } + return 0; +} + +#endif diff --git a/src/modules/xecmd.h b/src/modules/xecmd.h index 65712f877..a964d38da 100644 --- a/src/modules/xecmd.h +++ b/src/modules/xecmd.h @@ -1,27 +1,27 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_MOD_XECMD_H -#define H_MOD_XECMD_H -#ifdef __cplusplus -extern "C" { -#endif - -#if XECMD_MODULE -int xecmd(struct unit * u, struct order * ord); -#endif - -#ifdef __cplusplus -} -#endif -#endif - +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_MOD_XECMD_H +#define H_MOD_XECMD_H +#ifdef __cplusplus +extern "C" { +#endif + +#if XECMD_MODULE +int xecmd(struct unit * u, struct order * ord); +#endif + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/modules/xmas.c b/src/modules/xmas.c index 3fa8796c8..01f0b4297 100644 --- a/src/modules/xmas.c +++ b/src/modules/xmas.c @@ -1,82 +1,82 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "xmas.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include - -static int -xmasgate_handle(trigger * t, void * data) -{ - return -1; -} - -static void -xmasgate_write(const trigger * t, struct storage * store) -{ - building *b = (building *)t->data.v; - store->w_tok(store, itoa36(b->no)); -} - -static int -xmasgate_read(trigger * t, struct storage * store) -{ - int bc = read_reference(&t->data.v, store, read_building_reference, resolve_building); - if (bc==0 && !t->data.v) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -struct trigger_type tt_xmasgate = { - "xmasgate", - NULL, - NULL, - xmasgate_handle, - xmasgate_write, - xmasgate_read -}; - -trigger * -trigger_xmasgate(building * b) -{ - trigger * t = t_new(&tt_xmasgate); - t->data.v = b; - return t; -} - -void -register_xmas(void) -{ - tt_register(&tt_xmasgate); -} - +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "xmas.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include + +static int +xmasgate_handle(trigger * t, void * data) +{ + return -1; +} + +static void +xmasgate_write(const trigger * t, struct storage * store) +{ + building *b = (building *)t->data.v; + store->w_tok(store, itoa36(b->no)); +} + +static int +xmasgate_read(trigger * t, struct storage * store) +{ + int bc = read_reference(&t->data.v, store, read_building_reference, resolve_building); + if (bc==0 && !t->data.v) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +struct trigger_type tt_xmasgate = { + "xmasgate", + NULL, + NULL, + xmasgate_handle, + xmasgate_write, + xmasgate_read +}; + +trigger * +trigger_xmasgate(building * b) +{ + trigger * t = t_new(&tt_xmasgate); + t->data.v = b; + return t; +} + +void +register_xmas(void) +{ + tt_register(&tt_xmasgate); +} + diff --git a/src/modules/xmas.h b/src/modules/xmas.h index 7201aee6c..334ab8b38 100644 --- a/src/modules/xmas.h +++ b/src/modules/xmas.h @@ -1,29 +1,29 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_MOD_XMAS -#define H_MOD_XMAS -#ifdef __cplusplus -extern "C" { -#endif - -struct region; -struct unit; - -extern struct trigger *trigger_xmasgate(struct building * b); - -extern void register_xmas(void); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_MOD_XMAS +#define H_MOD_XMAS +#ifdef __cplusplus +extern "C" { +#endif + +struct region; +struct unit; + +extern struct trigger *trigger_xmasgate(struct building * b); + +extern void register_xmas(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/platform.h b/src/platform.h index 8596a9ab0..721006b7b 100644 --- a/src/platform.h +++ b/src/platform.h @@ -1,286 +1,282 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef CONFIG_H -#define CONFIG_H - -#define HAVE_LIBXML -#undef HAVE_TINYXML -#define HAVE_CURSES - -#ifdef _MSC_VER -# define VC_EXTRALEAN -# define WIN32_LEAN_AND_MEAN -# include -# undef MOUSE_MOVED -# define STDIO_CP 1252 /* log.c, convert to console character set */ -# pragma warning (disable: 4201 4214 4514 4115 4711) -# pragma warning(disable: 4056) -/* warning C4056: overflow in floating point constant arithmetic */ -# pragma warning(disable: 4201) -/* warning C4201: nonstandard extension used : nameless struct/union */ -# pragma warning(disable: 4214) -/* warning C4214: nonstandard extension used : bit field types other than int */ -# pragma warning(disable: 4100) -/* warning C4100: : unreferenced formal parameter */ -# pragma warning(disable: 4996) - -/* warning C4100: was declared deprecated */ -#ifndef _CRT_SECURE_NO_DEPRECATE -# define _CRT_SECURE_NO_DEPRECATE -#endif - -/* http://msdn2.microsoft.com/en-us/library/ms235505(VS.80).aspx */ -#ifndef _CRT_DISABLE_PERFCRIT_LOCKS -# define _CRT_DISABLE_PERFCRIT_LOCKS -#endif - -#endif /* _MSC_VER_ */ - - -#ifdef __cplusplus -# include -# include -extern "C" { -#else -# include -# include -#endif - -/**** **** - ** Debugging Libraries ** - **** ****/ -#if defined __GNUC__ -# define HAVE_INLINE -# define INLINE_FUNCTION static __inline -#endif - -/* define USE_DMALLOC to enable use of the dmalloc library */ -#ifdef USE_DMALLOC -# include -# include -# include -#endif - -/* define CRTDBG to enable MSVC CRT Debug library functions */ -#if defined(_DEBUG) && defined(_MSC_VER) && defined(CRTDBG) -# include -# define _CRTDBG_MAP_ALLOC -#endif - -/**** **** - ** Architecture Dependent ** - **** ****/ - -/* für solaris: */ -#ifdef SOLARIS -# define _SYS_PROCSET_H -# define _XOPEN_SOURCE -#endif - -#ifdef __GNUC__ -# ifndef _BSD_SOURCE -# define _BSD_SOURCE -# define __USE_BSD -# endif -/* # include */ -# include /* strncasecmp-Prototyp */ -#endif - -#ifdef _BSD_SOURCE -# define __EXTENSIONS__ -#endif - -#ifdef WIN32 -# define HAVE__MKDIR_WITHOUT_PERMISSION -# define HAVE__SLEEP_MSEC -#endif - -#if defined(__USE_SVID) || defined(_BSD_SOURCE) || defined(__USE_XOPEN_EXTENDED) || defined(_BE_SETUP_H) || defined(CYGWIN) -# include -# define HAVE_UNISTD_H -# define HAVE_STRCASECMP -# define HAVE_STRNCASECMP -# define HAVE_ACCESS -# define HAVE_STAT -typedef struct stat stat_type; -# include -# define HAVE_STRDUP -# define HAVE_SNPRINTF -#ifdef _POSIX_SOURCE /* MINGW doesn't seem to have these */ -# define HAVE_EXECINFO -# define HAVE_MKDIR_WITH_PERMISSION -# define HAVE_SIGACTION -# define HAVE_LINK -# define HAVE_SLEEP -#endif -#endif - -/* egcpp 4 dos */ -#ifdef MSDOS -# include -# define HAVE_MKDIR_WITH_PERMISSION -#endif - -/* lcc-win32 */ -#ifdef __LCC__ -# include -# include -# include -# define HAVE_ACCESS -# define HAVE_STAT -typedef struct stat stat_type; -# define HAVE_STRICMP -# define HAVE_STRNICMP -# define HAVE_STRDUP -# define HAVE_SLEEP -# define snprintf _snprintf -# define HAVE_SNPRINTF -# undef HAVE_STRCASECMP -# undef HAVE_STRNCASECMP -# define R_OK 4 -#endif - -/* Microsoft Visual C */ -#ifdef _MSC_VER -# include /* must be included here so strdup is not redefined */ -# define R_OK 4 -# define HAVE_INLINE -# define INLINE_FUNCTION __inline - -# define snprintf _snprintf -# define HAVE_SNPRINTF - -/* MSVC has _access, not access */ -#ifndef access -# define access(f, m) _access(f, m) -#endif -#define HAVE_ACCESS - -/* MSVC has _stat, not stat */ -# define HAVE_STAT -#include -# define stat(a, b) _stat(a, b) -typedef struct _stat stat_type; - -/* MSVC has _strdup */ -# define strdup _strdup -# define HAVE_STRDUP - -# define stricmp(a, b) _stricmp(a, b) -# define HAVE_STRICMP - -# define strnicmp(a, b, c) _strnicmp(a, b, c) -# define HAVE_STRNICMP -# undef HAVE_STRCASECMP -# undef HAVE_STRNCASECMP -#endif - -/* replacements for missing functions: */ - -#ifndef HAVE_STRCASECMP -# if defined(HAVE_STRICMP) -# define strcasecmp stricmp -# elif defined(HAVE__STRICMP) -# define strcasecmp _stricmp -# endif -#endif - -#ifndef HAVE_STRNCASECMP -# if defined(HAVE_STRNICMP) -# define strncasecmp strnicmp -# elif defined(HAVE__STRNICMP) -# define strncasecmp _strnicmp -# endif -#endif - -#ifdef HAVE_MKDIR_WITH_PERMISSION -# define makedir(d, p) mkdir(d, p) -#elif defined(HAVE_MKDIR_WITHOUT_PERMISSION) -# define makedir(d, p) mkdir(d) -#elif defined(HAVE__MKDIR_WITHOUT_PERMISSION) -_CRTIMP int __cdecl _mkdir(const char *); -# define makedir(d, p) _mkdir(d) -#endif - -#ifndef HAVE_STRDUP -extern char * strdup(const char *s); -#endif - -#ifndef HAVE_SLEEP -#ifdef HAVE__SLEEP_MSEC -# define sleep(sec) _sleep(1000*sec) -#elif defined(HAVE__SLEEP) -# define sleep(sec) _sleep(sec) -#endif -#endif - -#if !defined(MAX_PATH) -# if defined(PATH_MAX) -# define MAX_PATH PATH_MAX -# else -# define MAX_PATH 1024 -# endif -#endif - -/**** **** - ** min/max macros ** - **** ****/ -#ifndef NOMINMAX -#ifndef MIN -# define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif -#ifndef MAX -# define MAX(a,b) ((a) > (b) ? (a) : (b)) -#endif -#endif - -#if defined (__GNUC__) -# define unused(a) /* unused: a */ -#elif defined (ghs) || defined (__hpux) || defined (__sgi) || defined (__DECCXX) || defined (__KCC) || defined (__rational__) || defined (__USLC__) || defined (ACE_RM544) -# define unused(a) do {/* null */} while (&a == 0) -#else /* ghs || __GNUC__ || ..... */ -# define unused(a) (a) -#endif /* ghs || __GNUC__ || ..... */ - -/**** **** - ** The Eressea boolean type ** - **** ****/ -#if defined(BOOLEAN) -# define boolean BOOLEAN -#else - typedef int boolean; /* not bool! wrong size. */ -#endif -#ifndef __cplusplus -# define false ((boolean)0) -# define true ((boolean)!false) -#endif -#ifdef __cplusplus -} -#endif - -#ifndef INLINE_FUNCTION -# define INLINE_FUNCTION -#endif - -#define iswxspace(c) (c==160 || iswspace(c)) -#define isxspace(c) (c==160 || isspace(c)) - -#define TOLUA_CAST (char*) -#endif - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CONFIG_H +#define CONFIG_H + +#ifdef _MSC_VER +# define VC_EXTRALEAN +# define WIN32_LEAN_AND_MEAN +# include +# undef MOUSE_MOVED +# define STDIO_CP 1252 /* log.c, convert to console character set */ +# pragma warning (disable: 4201 4214 4514 4115 4711) +# pragma warning(disable: 4056) +/* warning C4056: overflow in floating point constant arithmetic */ +# pragma warning(disable: 4201) +/* warning C4201: nonstandard extension used : nameless struct/union */ +# pragma warning(disable: 4214) +/* warning C4214: nonstandard extension used : bit field types other than int */ +# pragma warning(disable: 4100) +/* warning C4100: : unreferenced formal parameter */ +# pragma warning(disable: 4996) + +/* warning C4100: was declared deprecated */ +#ifndef _CRT_SECURE_NO_DEPRECATE +# define _CRT_SECURE_NO_DEPRECATE +#endif + +/* http://msdn2.microsoft.com/en-us/library/ms235505(VS.80).aspx */ +#ifndef _CRT_DISABLE_PERFCRIT_LOCKS +# define _CRT_DISABLE_PERFCRIT_LOCKS +#endif + +#endif /* _MSC_VER_ */ + + +#ifdef __cplusplus +# include +# include +extern "C" { +#else +# include +# include +#endif + +/**** **** + ** Debugging Libraries ** + **** ****/ +#if defined __GNUC__ +# define HAVE_INLINE +# define INLINE_FUNCTION static __inline +#endif + +/* define USE_DMALLOC to enable use of the dmalloc library */ +#ifdef USE_DMALLOC +# include +# include +# include +#endif + +/* define CRTDBG to enable MSVC CRT Debug library functions */ +#if defined(_DEBUG) && defined(_MSC_VER) && defined(CRTDBG) +# include +# define _CRTDBG_MAP_ALLOC +#endif + +/**** **** + ** Architecture Dependent ** + **** ****/ + +/* für solaris: */ +#ifdef SOLARIS +# define _SYS_PROCSET_H +# define _XOPEN_SOURCE +#endif + +#ifdef __GNUC__ +# ifndef _BSD_SOURCE +# define _BSD_SOURCE +# define __USE_BSD +# endif +/* # include */ +# include /* strncasecmp-Prototyp */ +#endif + +#ifdef _BSD_SOURCE +# define __EXTENSIONS__ +#endif + +#ifdef WIN32 +# define HAVE__MKDIR_WITHOUT_PERMISSION +# define HAVE__SLEEP_MSEC +#endif + +#if defined(__USE_SVID) || defined(_BSD_SOURCE) || defined(__USE_XOPEN_EXTENDED) || defined(_BE_SETUP_H) || defined(CYGWIN) +# include +# define HAVE_UNISTD_H +# define HAVE_STRCASECMP +# define HAVE_STRNCASECMP +# define HAVE_ACCESS +# define HAVE_STAT +typedef struct stat stat_type; +# include +# define HAVE_STRDUP +# define HAVE_SNPRINTF +#ifdef _POSIX_SOURCE /* MINGW doesn't seem to have these */ +# define HAVE_EXECINFO +# define HAVE_MKDIR_WITH_PERMISSION +# define HAVE_SIGACTION +# define HAVE_LINK +# define HAVE_SLEEP +#endif +#endif + +/* egcpp 4 dos */ +#ifdef MSDOS +# include +# define HAVE_MKDIR_WITH_PERMISSION +#endif + +/* lcc-win32 */ +#ifdef __LCC__ +# include +# include +# include +# define HAVE_ACCESS +# define HAVE_STAT +typedef struct stat stat_type; +# define HAVE_STRICMP +# define HAVE_STRNICMP +# define HAVE_STRDUP +# define HAVE_SLEEP +# define snprintf _snprintf +# define HAVE_SNPRINTF +# undef HAVE_STRCASECMP +# undef HAVE_STRNCASECMP +# define R_OK 4 +#endif + +/* Microsoft Visual C */ +#ifdef _MSC_VER +# include /* must be included here so strdup is not redefined */ +# define R_OK 4 +# define HAVE_INLINE +# define INLINE_FUNCTION __inline + +# define snprintf _snprintf +# define HAVE_SNPRINTF + +/* MSVC has _access, not access */ +#ifndef access +# define access(f, m) _access(f, m) +#endif +#define HAVE_ACCESS + +/* MSVC has _stat, not stat */ +# define HAVE_STAT +#include +# define stat(a, b) _stat(a, b) +typedef struct _stat stat_type; + +/* MSVC has _strdup */ +# define strdup _strdup +# define HAVE_STRDUP + +# define stricmp(a, b) _stricmp(a, b) +# define HAVE_STRICMP + +# define strnicmp(a, b, c) _strnicmp(a, b, c) +# define HAVE_STRNICMP +# undef HAVE_STRCASECMP +# undef HAVE_STRNCASECMP +#endif + +/* replacements for missing functions: */ + +#ifndef HAVE_STRCASECMP +# if defined(HAVE_STRICMP) +# define strcasecmp stricmp +# elif defined(HAVE__STRICMP) +# define strcasecmp _stricmp +# endif +#endif + +#ifndef HAVE_STRNCASECMP +# if defined(HAVE_STRNICMP) +# define strncasecmp strnicmp +# elif defined(HAVE__STRNICMP) +# define strncasecmp _strnicmp +# endif +#endif + +#ifdef HAVE_MKDIR_WITH_PERMISSION +# define makedir(d, p) mkdir(d, p) +#elif defined(HAVE_MKDIR_WITHOUT_PERMISSION) +# define makedir(d, p) mkdir(d) +#elif defined(HAVE__MKDIR_WITHOUT_PERMISSION) +_CRTIMP int __cdecl _mkdir(const char *); +# define makedir(d, p) _mkdir(d) +#endif + +#ifndef HAVE_STRDUP +extern char * strdup(const char *s); +#endif + +#ifndef HAVE_SLEEP +#ifdef HAVE__SLEEP_MSEC +# define sleep(sec) _sleep(1000*sec) +#elif defined(HAVE__SLEEP) +# define sleep(sec) _sleep(sec) +#endif +#endif + +#if !defined(MAX_PATH) +# if defined(PATH_MAX) +# define MAX_PATH PATH_MAX +# else +# define MAX_PATH 1024 +# endif +#endif + +/**** **** + ** min/max macros ** + **** ****/ +#ifndef NOMINMAX +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef MAX +# define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif +#endif + +#if defined (__GNUC__) +# define unused(a) /* unused: a */ +#elif defined (ghs) || defined (__hpux) || defined (__sgi) || defined (__DECCXX) || defined (__KCC) || defined (__rational__) || defined (__USLC__) || defined (ACE_RM544) +# define unused(a) do {/* null */} while (&a == 0) +#else /* ghs || __GNUC__ || ..... */ +# define unused(a) (a) +#endif /* ghs || __GNUC__ || ..... */ + +/**** **** + ** The Eressea boolean type ** + **** ****/ +#if defined(BOOLEAN) +# define boolean BOOLEAN +#else + typedef int boolean; /* not bool! wrong size. */ +#endif +#ifndef __cplusplus +# define false ((boolean)0) +# define true ((boolean)!false) +#endif +#ifdef __cplusplus +} +#endif + +#ifndef INLINE_FUNCTION +# define INLINE_FUNCTION +#endif + +#define iswxspace(c) (c==160 || iswspace(c)) +#define isxspace(c) (c==160 || isspace(c)) + +#define TOLUA_CAST (char*) +#endif + diff --git a/src/settings.h b/src/settings.h index b791c45e2..c866d648e 100644 --- a/src/settings.h +++ b/src/settings.h @@ -1,55 +1,63 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -/* - * Contains defines for the "free" game (Eressea) . - * Include this file from settings.h to make eressea work. - */ -#define ENTERTAINFRACTION 20 -#define TEACHDIFFERENCE 2 -#define GUARD_DISABLES_RECRUIT 1 -#define GUARD_DISABLES_PRODUCTION 1 -#define RESOURCE_QUANTITY 0.5 -#define RECRUITFRACTION 40 /* 100/RECRUITFRACTION% */ -#define COMBAT_TURNS 5 -#define NEWATSROI 0 - -/* Vermehrungsrate Bauern in 1/10000. -* Evt. Berechnungsfehler, reale Vermehrungsraten scheinen höher. */ -#define PEASANTGROWTH 10 -#define BATTLE_KILLS_PEASANTS 20 -#define PEASANTLUCK 10 - -#define HUNGER_REDUCES_SKILL /* Hunger reduziert den Talentwert - auf die Hälfte */ - -#define ASTRAL_ITEM_RESTRICTIONS /* keine grossen dinge im astralraum */ -#define NEW_DAEMONHUNGER_RULE -#define NEW_COMBATSKILLS_RULE -#define ROW_FACTOR 3 /* factor for combat row advancement rule */ - -/* optional game components. TODO: These should either be - * configuration variables (XML), script extensions (lua), - * or both. We don't want separate binaries for different games - */ -#define SCORE_MODULE 1 -#define MUSEUM_MODULE 1 -#define ARENA_MODULE 1 -#define XECMD_MODULE 1 -#define DUNGEON_MODULE 0 -#define CHANGED_CROSSBOWS 0 /* use the WTF_ARMORPIERCING flag */ -#undef GLOBAL_WARMING /* number of turns before global warming sets in */ - -#define SIMPLE_COMBAT -#define SIMPLE_ESCAPE - -#undef REGIONOWNERS /* (WIP) region-owner uses HELP_TRAVEL to control entry to region */ +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +/* + * Contains defines for the "free" game (Eressea) . + * Include this file from settings.h to make eressea work. + */ +#define ENTERTAINFRACTION 20 +#define TEACHDIFFERENCE 2 +#define GUARD_DISABLES_RECRUIT 1 +#define GUARD_DISABLES_PRODUCTION 1 +#define RESOURCE_QUANTITY 0.5 +#define RECRUITFRACTION 40 /* 100/RECRUITFRACTION% */ +#define COMBAT_TURNS 5 +#define NEWATSROI 0 + +/* Vermehrungsrate Bauern in 1/10000. +* Evt. Berechnungsfehler, reale Vermehrungsraten scheinen höher. */ +#define PEASANTGROWTH 10 +#define BATTLE_KILLS_PEASANTS 20 +#define PEASANTLUCK 10 + +#define HUNGER_REDUCES_SKILL /* Hunger reduziert den Talentwert + auf die Hälfte */ + +#define ASTRAL_ITEM_RESTRICTIONS /* keine grossen dinge im astralraum */ +#define NEW_DAEMONHUNGER_RULE +#define NEW_COMBATSKILLS_RULE +#define ROW_FACTOR 3 /* factor for combat row advancement rule */ + +/* optional game components. TODO: These should either be + * configuration variables (XML), script extensions (lua), + * or both. We don't want separate binaries for different games + */ +#define SCORE_MODULE 1 +#define MUSEUM_MODULE 1 +#define ARENA_MODULE 1 +#define XECMD_MODULE 1 +#define DUNGEON_MODULE 0 +#define CHANGED_CROSSBOWS 0 /* use the WTF_ARMORPIERCING flag */ +#undef GLOBAL_WARMING /* number of turns before global warming sets in */ + +#define SIMPLE_COMBAT +#define SIMPLE_ESCAPE + +#if defined(BINDINGS_LUABIND) +# undef BINDINGS_TOLUA +#elif defined(BINDINGS_TOLUA) +# undef BINDINGS_LUABIND +#else +# define BINDINGS_TOLUA /* new default */ +#endif + +#undef REGIONOWNERS /* (WIP) region-owner uses HELP_TRAVEL to control entry to region */ diff --git a/src/stdafx.h b/src/stdafx.h index 0fd846fd4..f6db3cac1 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -1 +1 @@ -/* empty, only used in non-msvc builds */ +/* empty, only used in non-msvc builds */ diff --git a/src/tests.c b/src/tests.c index 3fc765b9d..27f28b791 100644 --- a/src/tests.c +++ b/src/tests.c @@ -1,127 +1,127 @@ -#include -#include - -#include -#include "tests.h" - -CuSuite* get_base36_suite(void); -CuSuite* get_curse_suite(void); -CuSuite* get_market_suite(void); -CuSuite* get_laws_suite(void); - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int RunAllTests(void) { - CuString *output = CuStringNew(); - CuSuite* suite = CuSuiteNew(); - - init_resources(); - - CuSuiteAddSuite(suite, get_base36_suite()); - CuSuiteAddSuite(suite, get_curse_suite()); - CuSuiteAddSuite(suite, get_market_suite()); - CuSuiteAddSuite(suite, get_laws_suite()); - - CuSuiteRun(suite); - CuSuiteSummary(suite, output); - CuSuiteDetails(suite, output); - printf("%s\n", output->buffer); - return suite->failCount; -} - -struct race * test_create_race(const char * name) -{ - race * rc = rc_add(rc_new("human")); - return rc; -} - -struct region * test_create_region(int x, int y, const struct terrain_type * terrain) -{ - region * r = new_region(x, y, NULL, 0); - terraform_region(r, terrain); - rsettrees(r, 0, 0); - rsettrees(r, 1, 0); - rsettrees(r, 2, 0); - rsethorses(r, 0); - rsetpeasants(r, terrain->size); - return r; -} - -struct faction * test_create_faction(const struct race * rc) -{ - faction * f = addfaction("nobody@eressea.de", NULL, rc, default_locale, 0); - return f; -} - -struct unit * test_create_unit(struct faction * f, struct region * r) -{ - unit * u = create_unit(r, f, 1, f->race, 0, 0, 0); - return u; -} - -void test_cleanup(void) { - global.functions.maintenance = NULL; - global.functions.wage = NULL; - free_gamedata(); -} - -/** creates a small world and some stuff in it. - * two terrains: 'plain' and 'ocean' - * one race: 'human' - * one ship_type: 'boat' - * one building_type: 'castle' - * in 0.0 and 1.0 is an island of two plains, around it is ocean. - */ -void test_create_world(void) -{ - terrain_type * t_plain, * t_ocean; - region * island[2]; - race * rc_human; - int i; - building_type * btype; - ship_type * stype; - - t_plain = calloc(1, sizeof(terrain_type)); - t_plain->_name = strdup("plain"); - t_plain->flags = LAND_REGION|FOREST_REGION|WALK_INTO; - register_terrain(t_plain); - - t_ocean = calloc(1, sizeof(terrain_type)); - t_ocean->_name = strdup("ocean"); - t_ocean->flags = SEA_REGION|SAIL_INTO|SWIM_INTO; - register_terrain(t_ocean); - - island[0] = test_create_region(0, 0, t_plain); - island[1] = test_create_region(1, 0, t_plain); - for (i=0;i!=2;++i) { - direction_t j; - region * r = island[i]; - for (j=0;j!=MAXDIRECTIONS;++j) { - region * rn = r_connect(r, j); - if (!rn) { - rn = test_create_region(r->x+delta_x[j], r->y+delta_y[j], t_ocean); - } - } - } - - rc_human = rc_add(rc_new("human")); - rc_human->maintenance = 10; - - btype = calloc(sizeof(building_type), 1); - btype->_name = strdup("castle"); - bt_register(btype); - - stype = calloc(sizeof(ship_type), 1); - stype->name[0] = strdup("boat"); - stype->name[1] = strdup("boat_p"); - st_register(stype); - -} +#include +#include + +#include +#include "tests.h" + +CuSuite* get_base36_suite(void); +CuSuite* get_curse_suite(void); +CuSuite* get_market_suite(void); +CuSuite* get_laws_suite(void); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int RunAllTests(void) { + CuString *output = CuStringNew(); + CuSuite* suite = CuSuiteNew(); + + init_resources(); + + CuSuiteAddSuite(suite, get_base36_suite()); + CuSuiteAddSuite(suite, get_curse_suite()); + CuSuiteAddSuite(suite, get_market_suite()); + CuSuiteAddSuite(suite, get_laws_suite()); + + CuSuiteRun(suite); + CuSuiteSummary(suite, output); + CuSuiteDetails(suite, output); + printf("%s\n", output->buffer); + return suite->failCount; +} + +struct race * test_create_race(const char * name) +{ + race * rc = rc_add(rc_new("human")); + return rc; +} + +struct region * test_create_region(int x, int y, const struct terrain_type * terrain) +{ + region * r = new_region(x, y, NULL, 0); + terraform_region(r, terrain); + rsettrees(r, 0, 0); + rsettrees(r, 1, 0); + rsettrees(r, 2, 0); + rsethorses(r, 0); + rsetpeasants(r, terrain->size); + return r; +} + +struct faction * test_create_faction(const struct race * rc) +{ + faction * f = addfaction("nobody@eressea.de", NULL, rc, default_locale, 0); + return f; +} + +struct unit * test_create_unit(struct faction * f, struct region * r) +{ + unit * u = create_unit(r, f, 1, f->race, 0, 0, 0); + return u; +} + +void test_cleanup(void) { + global.functions.maintenance = NULL; + global.functions.wage = NULL; + free_gamedata(); +} + +/** creates a small world and some stuff in it. + * two terrains: 'plain' and 'ocean' + * one race: 'human' + * one ship_type: 'boat' + * one building_type: 'castle' + * in 0.0 and 1.0 is an island of two plains, around it is ocean. + */ +void test_create_world(void) +{ + terrain_type * t_plain, * t_ocean; + region * island[2]; + race * rc_human; + int i; + building_type * btype; + ship_type * stype; + + t_plain = calloc(1, sizeof(terrain_type)); + t_plain->_name = strdup("plain"); + t_plain->flags = LAND_REGION|FOREST_REGION|WALK_INTO; + register_terrain(t_plain); + + t_ocean = calloc(1, sizeof(terrain_type)); + t_ocean->_name = strdup("ocean"); + t_ocean->flags = SEA_REGION|SAIL_INTO|SWIM_INTO; + register_terrain(t_ocean); + + island[0] = test_create_region(0, 0, t_plain); + island[1] = test_create_region(1, 0, t_plain); + for (i=0;i!=2;++i) { + direction_t j; + region * r = island[i]; + for (j=0;j!=MAXDIRECTIONS;++j) { + region * rn = r_connect(r, j); + if (!rn) { + rn = test_create_region(r->x+delta_x[j], r->y+delta_y[j], t_ocean); + } + } + } + + rc_human = rc_add(rc_new("human")); + rc_human->maintenance = 10; + + btype = calloc(sizeof(building_type), 1); + btype->_name = strdup("castle"); + bt_register(btype); + + stype = calloc(sizeof(ship_type), 1); + stype->name[0] = strdup("boat"); + stype->name[1] = strdup("boat_p"); + st_register(stype); + +} diff --git a/src/tests.h b/src/tests.h index a7510d75c..1bf6a1304 100644 --- a/src/tests.h +++ b/src/tests.h @@ -1,21 +1,21 @@ -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef DISABLE_TESTS -void test_cleanup(void); - -struct race * test_create_race(const char * name); -struct region * test_create_region(int x, int y, const struct terrain_type * terrain); -struct faction * test_create_faction(const struct race * rc); -struct unit * test_create_unit(struct faction * f, struct region * r); -void test_create_world(void); - -int RunAllTests(void); -#else -#define RunAllTests() 0 -#endif - -#ifdef __cplusplus -} -#endif +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DISABLE_TESTS +void test_cleanup(void); + +struct race * test_create_race(const char * name); +struct region * test_create_region(int x, int y, const struct terrain_type * terrain); +struct faction * test_create_faction(const struct race * rc); +struct unit * test_create_unit(struct faction * f, struct region * r); +void test_create_world(void); + +int RunAllTests(void); +#else +#define RunAllTests() 0 +#endif + +#ifdef __cplusplus +} +#endif diff --git a/src/triggers/changefaction.c b/src/triggers/changefaction.c index b3df84b58..e704dd241 100644 --- a/src/triggers/changefaction.c +++ b/src/triggers/changefaction.c @@ -1,114 +1,114 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "changefaction.h" - -/* kernel includes */ -#include -#include -#include /* FIXME: resolve_faction */ - -/* util includes */ -#include -#include -#include -#include -#include -#include - -/* ansi includes */ -#include -#include -#include - - -#include -/*** - ** restore a mage that was turned into a toad - **/ - -typedef struct changefaction_data { - struct unit * unit; - struct faction * faction; -} changefaction_data; - -static void -changefaction_init(trigger * t) -{ - t->data.v = calloc(sizeof(changefaction_data), 1); -} - -static void -changefaction_free(trigger * t) -{ - free(t->data.v); -} - -static int -changefaction_handle(trigger * t, void * data) -{ - /* call an event handler on changefaction. - * data.v -> ( variant event, int timer ) - */ - changefaction_data * td = (changefaction_data*)t->data.v; - if (td->unit && td->faction) { - u_setfaction(td->unit, td->faction); - } else { - log_error(("could not perform changefaction::handle()\n")); - } - unused(data); - return 0; -} - -static void -changefaction_write(const trigger * t, struct storage * store) -{ - changefaction_data * td = (changefaction_data*)t->data.v; - write_unit_reference(td->unit, store); - write_faction_reference(td->faction, store); -} - -static int -changefaction_read(trigger * t, struct storage * store) -{ - changefaction_data * td = (changefaction_data*)t->data.v; - read_reference(&td->unit, store, read_unit_reference, resolve_unit); - read_reference(&td->faction, store, read_faction_reference, resolve_faction); - return AT_READ_OK; -} - -trigger_type tt_changefaction = { - "changefaction", - changefaction_init, - changefaction_free, - changefaction_handle, - changefaction_write, - changefaction_read -}; - -trigger * -trigger_changefaction(unit * u, struct faction * f) -{ - trigger * t = t_new(&tt_changefaction); - changefaction_data * td = (changefaction_data*)t->data.v; - td->unit = u; - td->faction = f; - return t; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "changefaction.h" + +/* kernel includes */ +#include +#include +#include /* FIXME: resolve_faction */ + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* ansi includes */ +#include +#include +#include + + +#include +/*** + ** restore a mage that was turned into a toad + **/ + +typedef struct changefaction_data { + struct unit * unit; + struct faction * faction; +} changefaction_data; + +static void +changefaction_init(trigger * t) +{ + t->data.v = calloc(sizeof(changefaction_data), 1); +} + +static void +changefaction_free(trigger * t) +{ + free(t->data.v); +} + +static int +changefaction_handle(trigger * t, void * data) +{ + /* call an event handler on changefaction. + * data.v -> ( variant event, int timer ) + */ + changefaction_data * td = (changefaction_data*)t->data.v; + if (td->unit && td->faction) { + u_setfaction(td->unit, td->faction); + } else { + log_error(("could not perform changefaction::handle()\n")); + } + unused(data); + return 0; +} + +static void +changefaction_write(const trigger * t, struct storage * store) +{ + changefaction_data * td = (changefaction_data*)t->data.v; + write_unit_reference(td->unit, store); + write_faction_reference(td->faction, store); +} + +static int +changefaction_read(trigger * t, struct storage * store) +{ + changefaction_data * td = (changefaction_data*)t->data.v; + read_reference(&td->unit, store, read_unit_reference, resolve_unit); + read_reference(&td->faction, store, read_faction_reference, resolve_faction); + return AT_READ_OK; +} + +trigger_type tt_changefaction = { + "changefaction", + changefaction_init, + changefaction_free, + changefaction_handle, + changefaction_write, + changefaction_read +}; + +trigger * +trigger_changefaction(unit * u, struct faction * f) +{ + trigger * t = t_new(&tt_changefaction); + changefaction_data * td = (changefaction_data*)t->data.v; + td->unit = u; + td->faction = f; + return t; +} diff --git a/src/triggers/changefaction.h b/src/triggers/changefaction.h index c46deea55..dd2a302c5 100644 --- a/src/triggers/changefaction.h +++ b/src/triggers/changefaction.h @@ -1,39 +1,39 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef CHANGEFACTION_H -#define CHANGEFACTION_H -#ifdef __cplusplus -extern "C" { -#endif - -/* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; - -struct unit; -struct faction; - -extern struct trigger_type tt_changefaction; - -extern struct trigger * trigger_changefaction(struct unit * u, struct faction * f); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CHANGEFACTION_H +#define CHANGEFACTION_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; + +struct unit; +struct faction; + +extern struct trigger_type tt_changefaction; + +extern struct trigger * trigger_changefaction(struct unit * u, struct faction * f); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/changerace.c b/src/triggers/changerace.c index 35effa513..db5904d23 100644 --- a/src/triggers/changerace.c +++ b/src/triggers/changerace.c @@ -1,120 +1,120 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "changerace.h" - -/* kernel includes */ -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include - -/* ansi includes */ -#include -#include -#include - - -#include -/*** - ** 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(sizeof(changerace_data), 1); -} - -static void -changerace_free(trigger * t) -{ - free(t->data.v); -} - -static int -changerace_handle(trigger * t, void * data) -{ - /* call an event handler on changerace. - * data.v -> ( variant event, int timer ) - */ - changerace_data * td = (changerace_data*)t->data.v; - if (td->u) { - if (td->race!=NULL) td->u->race = td->race; - if (td->irace!=NULL) td->u->irace = td->irace; - } else { - log_error(("could not perform changerace::handle()\n")); - } - unused(data); - return 0; -} - -static void -changerace_write(const trigger * t, struct storage * store) -{ - changerace_data * td = (changerace_data*)t->data.v; - write_unit_reference(td->u, store); - write_race_reference(td->race, store); - write_race_reference(td->irace, store); -} - -static int -changerace_read(trigger * t, struct storage * store) -{ - changerace_data * td = (changerace_data*)t->data.v; - read_reference(&td->u, store, read_unit_reference, resolve_unit); - td->race = (const struct race*)read_race_reference(store).v; - td->irace = (const struct race*)read_race_reference(store).v; - return AT_READ_OK; -} - -trigger_type tt_changerace = { - "changerace", - changerace_init, - changerace_free, - changerace_handle, - changerace_write, - changerace_read -}; - -trigger * -trigger_changerace(struct unit * u, const struct race * prace, const struct race * irace) -{ - trigger * t = t_new(&tt_changerace); - changerace_data * td = (changerace_data*)t->data.v; - - assert(u->race==u_irace(u) || "!changerace-triggers cannot stack!"); - td->u = u; - td->race = prace; - td->irace = irace; - return t; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "changerace.h" + +/* kernel includes */ +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* ansi includes */ +#include +#include +#include + + +#include +/*** + ** 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(sizeof(changerace_data), 1); +} + +static void +changerace_free(trigger * t) +{ + free(t->data.v); +} + +static int +changerace_handle(trigger * t, void * data) +{ + /* call an event handler on changerace. + * data.v -> ( variant event, int timer ) + */ + changerace_data * td = (changerace_data*)t->data.v; + if (td->u) { + if (td->race!=NULL) td->u->race = td->race; + if (td->irace!=NULL) td->u->irace = td->irace; + } else { + log_error(("could not perform changerace::handle()\n")); + } + unused(data); + return 0; +} + +static void +changerace_write(const trigger * t, struct storage * store) +{ + changerace_data * td = (changerace_data*)t->data.v; + write_unit_reference(td->u, store); + write_race_reference(td->race, store); + write_race_reference(td->irace, store); +} + +static int +changerace_read(trigger * t, struct storage * store) +{ + changerace_data * td = (changerace_data*)t->data.v; + read_reference(&td->u, store, read_unit_reference, resolve_unit); + td->race = (const struct race*)read_race_reference(store).v; + td->irace = (const struct race*)read_race_reference(store).v; + return AT_READ_OK; +} + +trigger_type tt_changerace = { + "changerace", + changerace_init, + changerace_free, + changerace_handle, + changerace_write, + changerace_read +}; + +trigger * +trigger_changerace(struct unit * u, const struct race * prace, const struct race * irace) +{ + trigger * t = t_new(&tt_changerace); + changerace_data * td = (changerace_data*)t->data.v; + + assert(u->race==u_irace(u) || "!changerace-triggers cannot stack!"); + td->u = u; + td->race = prace; + td->irace = irace; + return t; +} diff --git a/src/triggers/changerace.h b/src/triggers/changerace.h index 91ff8c975..dc2c55111 100644 --- a/src/triggers/changerace.h +++ b/src/triggers/changerace.h @@ -1,37 +1,37 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef CHANGERACE_H -#define CHANGERACE_H -#ifdef __cplusplus -extern "C" { -#endif - -/* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; -struct unit; - -extern struct trigger_type tt_changerace; - -extern struct trigger * trigger_changerace(struct unit * u, const struct race *urace, const struct race *irace); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CHANGERACE_H +#define CHANGERACE_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; +struct unit; + +extern struct trigger_type tt_changerace; + +extern struct trigger * trigger_changerace(struct unit * u, const struct race *urace, const struct race *irace); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/clonedied.c b/src/triggers/clonedied.c index 9463bd7ac..98f156afd 100644 --- a/src/triggers/clonedied.c +++ b/src/triggers/clonedied.c @@ -1,95 +1,95 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "clonedied.h" - -/* kernel includes */ -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -/** - clonedied. - - This trigger ist called when a clone of a mage dies. - It simply removes the clone-attribute from the mage. - */ - -static int -clonedied_handle(trigger * t, void * data) -{ - /* destroy the unit */ - unit * u = (unit*)t->data.v; - if (u) { - attrib *a = a_find(u->attribs, &at_clone); - if(a) a_remove(&u->attribs, a); - } else - log_error(("could not perform clonedied::handle()\n")); - unused(data); - return 0; -} - -static void -clonedied_write(const trigger * t, struct storage * store) -{ - unit * u = (unit*)t->data.v; - write_unit_reference(u, store); -} - -static int -clonedied_read(trigger * t, struct storage * store) -{ - int result = read_reference(&t->data.v, store, read_unit_reference, resolve_unit); - if (result==0 && t->data.v==NULL) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -trigger_type tt_clonedied = { - "clonedied", - NULL, - NULL, - clonedied_handle, - clonedied_write, - clonedied_read -}; - -trigger * -trigger_clonedied(unit * u) -{ - trigger * t = t_new(&tt_clonedied); - t->data.v = (void*)u; - return t; -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "clonedied.h" + +/* kernel includes */ +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include + +/** + clonedied. + + This trigger ist called when a clone of a mage dies. + It simply removes the clone-attribute from the mage. + */ + +static int +clonedied_handle(trigger * t, void * data) +{ + /* destroy the unit */ + unit * u = (unit*)t->data.v; + if (u) { + attrib *a = a_find(u->attribs, &at_clone); + if(a) a_remove(&u->attribs, a); + } else + log_error(("could not perform clonedied::handle()\n")); + unused(data); + return 0; +} + +static void +clonedied_write(const trigger * t, struct storage * store) +{ + unit * u = (unit*)t->data.v; + write_unit_reference(u, store); +} + +static int +clonedied_read(trigger * t, struct storage * store) +{ + int result = read_reference(&t->data.v, store, read_unit_reference, resolve_unit); + if (result==0 && t->data.v==NULL) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +trigger_type tt_clonedied = { + "clonedied", + NULL, + NULL, + clonedied_handle, + clonedied_write, + clonedied_read +}; + +trigger * +trigger_clonedied(unit * u) +{ + trigger * t = t_new(&tt_clonedied); + t->data.v = (void*)u; + return t; +} + diff --git a/src/triggers/clonedied.h b/src/triggers/clonedied.h index 36dbf718f..607a1c415 100644 --- a/src/triggers/clonedied.h +++ b/src/triggers/clonedied.h @@ -1,36 +1,36 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef CLONEDIED_H -#define CLONEDIED_H -#ifdef __cplusplus -extern "C" { -#endif - -struct trigger_type; -struct trigger; - -struct unit; - -extern struct trigger_type tt_clonedied; -extern struct trigger * trigger_clonedied(struct unit * u); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CLONEDIED_H +#define CLONEDIED_H +#ifdef __cplusplus +extern "C" { +#endif + +struct trigger_type; +struct trigger; + +struct unit; + +extern struct trigger_type tt_clonedied; +extern struct trigger * trigger_clonedied(struct unit * u); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/createcurse.c b/src/triggers/createcurse.c index 8d0b9a593..085b08317 100644 --- a/src/triggers/createcurse.c +++ b/src/triggers/createcurse.c @@ -1,157 +1,157 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "createcurse.h" - -/* kernel includes */ -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include - -/* ansi includes */ -#include -#include -#include - - -#include -/*** - ** restore a mage that was turned into a toad - **/ - -typedef struct createcurse_data { - struct unit * mage; - struct unit * target; - const curse_type * type; - double vigour; - int duration; - double effect; - int men; -} createcurse_data; - -static void -createcurse_init(trigger * t) -{ - t->data.v = calloc(sizeof(createcurse_data), 1); -} - -static void -createcurse_free(trigger * t) -{ - free(t->data.v); -} - -static int -createcurse_handle(trigger * t, void * data) -{ - /* call an event handler on createcurse. - * data.v -> ( variant event, int timer ) - */ - createcurse_data * td = (createcurse_data*)t->data.v; - if (td->mage && td->target && td->mage->number && td->target->number) { - create_curse(td->mage, &td->target->attribs, - td->type, td->vigour, td->duration, td->effect, td->men); - } else { - log_error(("could not perform createcurse::handle()\n")); - } - unused(data); - return 0; -} - -static void -createcurse_write(const trigger * t, struct storage * store) -{ - createcurse_data * td = (createcurse_data*)t->data.v; - write_unit_reference(td->mage, store); - write_unit_reference(td->target, store); - store->w_tok(store, td->type->cname); - store->w_flt(store, (float)td->vigour); - store->w_int(store, td->duration); - store->w_flt(store, (float)td->effect); - store->w_int(store, td->men); -} - -static int -createcurse_read(trigger * t, struct storage * store) -{ - createcurse_data * td = (createcurse_data*)t->data.v; - char zText[128]; - - read_reference(&td->mage, store, read_unit_reference, resolve_unit); - read_reference(&td->target, store, read_unit_reference, resolve_unit); - - if (store->versionr_int(store); - id2 = store->r_int(store); - assert(id2==0); - td->vigour = store->r_flt(store); - td->duration = store->r_int(store); - td->effect = store->r_int(store); - td->men = store->r_int(store); - td->type = ct_find(oldcursename(id1)); - } else { - store->r_tok_buf(store, zText, sizeof(zText)); - td->type = ct_find(zText); - td->vigour = store->r_flt(store); - td->duration = store->r_int(store); - if (store->versioneffect = (double)store->r_int(store); - } else { - td->effect = store->r_flt(store); - } - td->men = store->r_int(store); - } - return AT_READ_OK; -} - -trigger_type tt_createcurse = { - "createcurse", - createcurse_init, - createcurse_free, - createcurse_handle, - createcurse_write, - createcurse_read -}; - -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); - createcurse_data * td = (createcurse_data*)t->data.v; - td->mage = mage; - td->target = target; - td->type = ct; - td->vigour = vigour; - td->duration = duration; - td->effect = effect; - td->men = men; - return t; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "createcurse.h" + +/* kernel includes */ +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* ansi includes */ +#include +#include +#include + + +#include +/*** + ** restore a mage that was turned into a toad + **/ + +typedef struct createcurse_data { + struct unit * mage; + struct unit * target; + const curse_type * type; + double vigour; + int duration; + double effect; + int men; +} createcurse_data; + +static void +createcurse_init(trigger * t) +{ + t->data.v = calloc(sizeof(createcurse_data), 1); +} + +static void +createcurse_free(trigger * t) +{ + free(t->data.v); +} + +static int +createcurse_handle(trigger * t, void * data) +{ + /* call an event handler on createcurse. + * data.v -> ( variant event, int timer ) + */ + createcurse_data * td = (createcurse_data*)t->data.v; + if (td->mage && td->target && td->mage->number && td->target->number) { + create_curse(td->mage, &td->target->attribs, + td->type, td->vigour, td->duration, td->effect, td->men); + } else { + log_error(("could not perform createcurse::handle()\n")); + } + unused(data); + return 0; +} + +static void +createcurse_write(const trigger * t, struct storage * store) +{ + createcurse_data * td = (createcurse_data*)t->data.v; + write_unit_reference(td->mage, store); + write_unit_reference(td->target, store); + store->w_tok(store, td->type->cname); + store->w_flt(store, (float)td->vigour); + store->w_int(store, td->duration); + store->w_flt(store, (float)td->effect); + store->w_int(store, td->men); +} + +static int +createcurse_read(trigger * t, struct storage * store) +{ + createcurse_data * td = (createcurse_data*)t->data.v; + char zText[128]; + + read_reference(&td->mage, store, read_unit_reference, resolve_unit); + read_reference(&td->target, store, read_unit_reference, resolve_unit); + + if (store->versionr_int(store); + id2 = store->r_int(store); + assert(id2==0); + td->vigour = store->r_flt(store); + td->duration = store->r_int(store); + td->effect = store->r_int(store); + td->men = store->r_int(store); + td->type = ct_find(oldcursename(id1)); + } else { + store->r_tok_buf(store, zText, sizeof(zText)); + td->type = ct_find(zText); + td->vigour = store->r_flt(store); + td->duration = store->r_int(store); + if (store->versioneffect = (double)store->r_int(store); + } else { + td->effect = store->r_flt(store); + } + td->men = store->r_int(store); + } + return AT_READ_OK; +} + +trigger_type tt_createcurse = { + "createcurse", + createcurse_init, + createcurse_free, + createcurse_handle, + createcurse_write, + createcurse_read +}; + +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); + createcurse_data * td = (createcurse_data*)t->data.v; + td->mage = mage; + td->target = target; + td->type = ct; + td->vigour = vigour; + td->duration = duration; + td->effect = effect; + td->men = men; + return t; +} diff --git a/src/triggers/createcurse.h b/src/triggers/createcurse.h index 47cc07203..bc3d2e797 100644 --- a/src/triggers/createcurse.h +++ b/src/triggers/createcurse.h @@ -1,40 +1,40 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef CREATECURSE_H -#define CREATECURSE_H -#ifdef __cplusplus -extern "C" { -#endif - -/* all types we use are defined here to reduce dependencies */ -struct curse_type; -struct trigger_type; -struct trigger; -struct region; -struct faction; -struct unit; - -extern struct trigger_type tt_createcurse; - -extern struct trigger * trigger_createcurse(struct unit * mage, struct unit * target, const struct curse_type * ct, double vigour, int duration, double effect, int men); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CREATECURSE_H +#define CREATECURSE_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct curse_type; +struct trigger_type; +struct trigger; +struct region; +struct faction; +struct unit; + +extern struct trigger_type tt_createcurse; + +extern struct trigger * trigger_createcurse(struct unit * mage, struct unit * target, const struct curse_type * ct, double vigour, int duration, double effect, int men); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/createunit.c b/src/triggers/createunit.c index 0aacf0da3..48610c9d1 100644 --- a/src/triggers/createunit.c +++ b/src/triggers/createunit.c @@ -1,130 +1,130 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "createunit.h" - -/* kernel includes */ -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include - -/* ansi includes */ -#include -#include -#include - - -#include -/*** - ** restore a mage that was turned into a toad - **/ - -typedef struct createunit_data { - struct region * r; - struct faction * f; - const struct race * race; - int number; -} createunit_data; - -static void -createunit_init(trigger * t) -{ - t->data.v = calloc(sizeof(createunit_data), 1); -} - -static void -createunit_free(trigger * t) -{ - free(t->data.v); -} - -static int -createunit_handle(trigger * t, void * data) -{ - /* call an event handler on createunit. - * data.v -> ( variant event, int timer ) - */ - createunit_data * td = (createunit_data*)t->data.v; - if (td->r!=NULL && td->f!=NULL) { - create_unit(td->r, td->f, td->number, td->race, 0, NULL, NULL); - } else { - log_error(("could not perform createunit::handle()\n")); - } - unused(data); - return 0; -} - -static void -createunit_write(const trigger * t, struct storage * store) -{ - createunit_data * td = (createunit_data*)t->data.v; - write_faction_reference(td->f, store); - write_region_reference(td->r, store); - write_race_reference(td->race, store); - store->w_int(store, td->number); -} - -static int -createunit_read(trigger * t, struct storage * store) -{ - createunit_data * td = (createunit_data*)t->data.v; - - int uc = read_reference(&td->f, store, read_faction_reference, resolve_faction); - int rc = read_reference(&td->r, store, read_region_reference, RESOLVE_REGION(store->version)); - td->race = (const struct race*)read_race_reference(store).v; - - if (uc==0 && rc==0) { - if (!td->f || !td->r) return AT_READ_FAIL; - } - td->number = store->r_int(store); - - return AT_READ_OK; -} - -trigger_type tt_createunit = { - "createunit", - createunit_init, - createunit_free, - createunit_handle, - createunit_write, - createunit_read -}; - -trigger * -trigger_createunit(region * r, struct faction * f, const struct race * rc, int number) -{ - trigger * t = t_new(&tt_createunit); - createunit_data * td = (createunit_data*)t->data.v; - td->r = r; - td->f = f; - td->race = rc; - td->number = number; - return t; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "createunit.h" + +/* kernel includes */ +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* ansi includes */ +#include +#include +#include + + +#include +/*** + ** restore a mage that was turned into a toad + **/ + +typedef struct createunit_data { + struct region * r; + struct faction * f; + const struct race * race; + int number; +} createunit_data; + +static void +createunit_init(trigger * t) +{ + t->data.v = calloc(sizeof(createunit_data), 1); +} + +static void +createunit_free(trigger * t) +{ + free(t->data.v); +} + +static int +createunit_handle(trigger * t, void * data) +{ + /* call an event handler on createunit. + * data.v -> ( variant event, int timer ) + */ + createunit_data * td = (createunit_data*)t->data.v; + if (td->r!=NULL && td->f!=NULL) { + create_unit(td->r, td->f, td->number, td->race, 0, NULL, NULL); + } else { + log_error(("could not perform createunit::handle()\n")); + } + unused(data); + return 0; +} + +static void +createunit_write(const trigger * t, struct storage * store) +{ + createunit_data * td = (createunit_data*)t->data.v; + write_faction_reference(td->f, store); + write_region_reference(td->r, store); + write_race_reference(td->race, store); + store->w_int(store, td->number); +} + +static int +createunit_read(trigger * t, struct storage * store) +{ + createunit_data * td = (createunit_data*)t->data.v; + + int uc = read_reference(&td->f, store, read_faction_reference, resolve_faction); + int rc = read_reference(&td->r, store, read_region_reference, RESOLVE_REGION(store->version)); + td->race = (const struct race*)read_race_reference(store).v; + + if (uc==0 && rc==0) { + if (!td->f || !td->r) return AT_READ_FAIL; + } + td->number = store->r_int(store); + + return AT_READ_OK; +} + +trigger_type tt_createunit = { + "createunit", + createunit_init, + createunit_free, + createunit_handle, + createunit_write, + createunit_read +}; + +trigger * +trigger_createunit(region * r, struct faction * f, const struct race * rc, int number) +{ + trigger * t = t_new(&tt_createunit); + createunit_data * td = (createunit_data*)t->data.v; + td->r = r; + td->f = f; + td->race = rc; + td->number = number; + return t; +} diff --git a/src/triggers/createunit.h b/src/triggers/createunit.h index c26a7be6b..7dd6894f2 100644 --- a/src/triggers/createunit.h +++ b/src/triggers/createunit.h @@ -1,39 +1,39 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef CREATEUNIT_H -#define CREATEUNIT_H -#ifdef __cplusplus -extern "C" { -#endif - -/* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; -struct region; -struct faction; -struct unit; - -extern struct trigger_type tt_createunit; - -extern struct trigger * trigger_createunit(struct region * r, struct faction * f, const struct race * rc, int number); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CREATEUNIT_H +#define CREATEUNIT_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; +struct region; +struct faction; +struct unit; + +extern struct trigger_type tt_createunit; + +extern struct trigger * trigger_createunit(struct region * r, struct faction * f, const struct race * rc, int number); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/gate.c b/src/triggers/gate.c index 2de707ad8..ef1344495 100644 --- a/src/triggers/gate.c +++ b/src/triggers/gate.c @@ -1,117 +1,117 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ -#include -#include -#include "gate.h" - -/* kernel includes */ -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include - -/* libc includes */ -#include - -typedef struct gate_data { - struct building * gate; - struct region * target; -} gate_data; - -static int -gate_handle(trigger * t, void * data) -{ - /* call an event handler on gate. - * data.v -> ( variant event, int timer ) - */ - gate_data * gd = (gate_data*)t->data.v; - struct building * b = gd->gate; - struct region * r = gd->target; - - if (b && b->region && r) { - unit ** up = &b->region->units; - while (*up) { - unit * u = *up; - if (u->building==b) move_unit(u, r, NULL); - if (*up==u) up = &u->next; - } - } else { - log_error(("could not perform gate::handle()\n")); - return -1; - } - unused(data); - return 0; -} - -static void -gate_write(const trigger * t, struct storage * store) -{ - gate_data * gd = (gate_data*)t->data.v; - building * b = gd->gate; - region * r = gd->target; - - write_building_reference(b, store); - write_region_reference(r, store); -} - -static int -gate_read(trigger * t, struct storage * store) -{ - gate_data * gd = (gate_data*)t->data.v; - - int bc = read_reference(&gd->gate, store, read_building_reference, resolve_building); - int rc = read_reference(&gd->target, store, read_region_reference, RESOLVE_REGION(store->version)); - - if (bc==0 && rc==0) { - if (!gd->gate || !gd->target) return AT_READ_FAIL; - } - return AT_READ_OK; -} - -static void -gate_init(trigger * t) -{ - t->data.v = calloc(sizeof(gate_data), 1); -} - -static void -gate_done(trigger * t) -{ - free(t->data.v); -} - - -struct trigger_type tt_gate = { - "gate", - gate_init, - gate_done, - gate_handle, - gate_write, - gate_read -}; - -trigger * -trigger_gate(building * b, region * target) -{ - trigger * t = t_new(&tt_gate); - gate_data * td = (gate_data*)t->data.v; - td->gate = b; - td->target = target; - return t; -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#include +#include +#include "gate.h" + +/* kernel includes */ +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include + +/* libc includes */ +#include + +typedef struct gate_data { + struct building * gate; + struct region * target; +} gate_data; + +static int +gate_handle(trigger * t, void * data) +{ + /* call an event handler on gate. + * data.v -> ( variant event, int timer ) + */ + gate_data * gd = (gate_data*)t->data.v; + struct building * b = gd->gate; + struct region * r = gd->target; + + if (b && b->region && r) { + unit ** up = &b->region->units; + while (*up) { + unit * u = *up; + if (u->building==b) move_unit(u, r, NULL); + if (*up==u) up = &u->next; + } + } else { + log_error(("could not perform gate::handle()\n")); + return -1; + } + unused(data); + return 0; +} + +static void +gate_write(const trigger * t, struct storage * store) +{ + gate_data * gd = (gate_data*)t->data.v; + building * b = gd->gate; + region * r = gd->target; + + write_building_reference(b, store); + write_region_reference(r, store); +} + +static int +gate_read(trigger * t, struct storage * store) +{ + gate_data * gd = (gate_data*)t->data.v; + + int bc = read_reference(&gd->gate, store, read_building_reference, resolve_building); + int rc = read_reference(&gd->target, store, read_region_reference, RESOLVE_REGION(store->version)); + + if (bc==0 && rc==0) { + if (!gd->gate || !gd->target) return AT_READ_FAIL; + } + return AT_READ_OK; +} + +static void +gate_init(trigger * t) +{ + t->data.v = calloc(sizeof(gate_data), 1); +} + +static void +gate_done(trigger * t) +{ + free(t->data.v); +} + + +struct trigger_type tt_gate = { + "gate", + gate_init, + gate_done, + gate_handle, + gate_write, + gate_read +}; + +trigger * +trigger_gate(building * b, region * target) +{ + trigger * t = t_new(&tt_gate); + gate_data * td = (gate_data*)t->data.v; + td->gate = b; + td->target = target; + return t; +} diff --git a/src/triggers/gate.h b/src/triggers/gate.h index 5ed82d778..677118330 100644 --- a/src/triggers/gate.h +++ b/src/triggers/gate.h @@ -1,32 +1,32 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef GATE_H -#define GATE_H -#ifdef __cplusplus -extern "C" { -#endif - -/* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; -struct region; -struct building; - -extern struct trigger_type tt_gate; - -extern struct trigger * trigger_gate(struct building * b, struct region * r); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef GATE_H +#define GATE_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; +struct region; +struct building; + +extern struct trigger_type tt_gate; + +extern struct trigger * trigger_gate(struct building * b, struct region * r); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/giveitem.c b/src/triggers/giveitem.c index e5709f16a..53a06f24b 100644 --- a/src/triggers/giveitem.c +++ b/src/triggers/giveitem.c @@ -1,124 +1,124 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "giveitem.h" - -/* kernel includes */ -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include - -/* ansi includes */ -#include -#include -#include - -/*** - ** give an item to someone - **/ - -typedef struct giveitem_data { - struct unit * u; - const struct item_type * itype; - int number; -} giveitem_data; - -static void -giveitem_init(trigger * t) -{ - t->data.v = calloc(sizeof(giveitem_data), 1); -} - -static void -giveitem_free(trigger * t) -{ - free(t->data.v); -} - -static int -giveitem_handle(trigger * t, void * data) -{ - /* call an event handler on giveitem. - * data.v -> ( variant event, int timer ) - */ - giveitem_data * td = (giveitem_data*)t->data.v; - if (td->u && td->u->number) { - i_change(&td->u->items, td->itype, td->number); - } else { - log_error(("could not perform giveitem::handle()\n")); - } - unused(data); - return 0; -} - -static void -giveitem_write(const trigger * t, struct storage * store) -{ - giveitem_data * td = (giveitem_data*)t->data.v; - write_unit_reference(td->u, store); - store->w_int(store, td->number); - store->w_tok(store, td->itype->rtype->_name[0]); -} - -static int -giveitem_read(trigger * t, struct storage * store) -{ - giveitem_data * td = (giveitem_data*)t->data.v; - char zText[128]; - - int result = read_reference(&td->u, store, read_unit_reference, resolve_unit); - - td->number = store->r_int(store); - store->r_tok_buf(store, zText, sizeof(zText)); - td->itype = it_find(zText); - assert(td->itype); - - if (result==0 && td->u==NULL) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -trigger_type tt_giveitem = { - "giveitem", - giveitem_init, - giveitem_free, - giveitem_handle, - giveitem_write, - giveitem_read -}; - -trigger * -trigger_giveitem(unit * u, const item_type * itype, int number) -{ - trigger * t = t_new(&tt_giveitem); - giveitem_data * td = (giveitem_data*)t->data.v; - td->number = number; - td->u = u; - td->itype = itype; - return t; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "giveitem.h" + +/* kernel includes */ +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* ansi includes */ +#include +#include +#include + +/*** + ** give an item to someone + **/ + +typedef struct giveitem_data { + struct unit * u; + const struct item_type * itype; + int number; +} giveitem_data; + +static void +giveitem_init(trigger * t) +{ + t->data.v = calloc(sizeof(giveitem_data), 1); +} + +static void +giveitem_free(trigger * t) +{ + free(t->data.v); +} + +static int +giveitem_handle(trigger * t, void * data) +{ + /* call an event handler on giveitem. + * data.v -> ( variant event, int timer ) + */ + giveitem_data * td = (giveitem_data*)t->data.v; + if (td->u && td->u->number) { + i_change(&td->u->items, td->itype, td->number); + } else { + log_error(("could not perform giveitem::handle()\n")); + } + unused(data); + return 0; +} + +static void +giveitem_write(const trigger * t, struct storage * store) +{ + giveitem_data * td = (giveitem_data*)t->data.v; + write_unit_reference(td->u, store); + store->w_int(store, td->number); + store->w_tok(store, td->itype->rtype->_name[0]); +} + +static int +giveitem_read(trigger * t, struct storage * store) +{ + giveitem_data * td = (giveitem_data*)t->data.v; + char zText[128]; + + int result = read_reference(&td->u, store, read_unit_reference, resolve_unit); + + td->number = store->r_int(store); + store->r_tok_buf(store, zText, sizeof(zText)); + td->itype = it_find(zText); + assert(td->itype); + + if (result==0 && td->u==NULL) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +trigger_type tt_giveitem = { + "giveitem", + giveitem_init, + giveitem_free, + giveitem_handle, + giveitem_write, + giveitem_read +}; + +trigger * +trigger_giveitem(unit * u, const item_type * itype, int number) +{ + trigger * t = t_new(&tt_giveitem); + giveitem_data * td = (giveitem_data*)t->data.v; + td->number = number; + td->u = u; + td->itype = itype; + return t; +} diff --git a/src/triggers/giveitem.h b/src/triggers/giveitem.h index a9c021a86..048b4a5cd 100644 --- a/src/triggers/giveitem.h +++ b/src/triggers/giveitem.h @@ -1,38 +1,38 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef GIVEITEM_H -#define GIVEITEM_H -#ifdef __cplusplus -extern "C" { -#endif - -/* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; -struct unit; -struct item_type; - -extern struct trigger_type tt_giveitem; - -extern struct trigger * trigger_giveitem(struct unit * mage, const struct item_type * itype, int number); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef GIVEITEM_H +#define GIVEITEM_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; +struct unit; +struct item_type; + +extern struct trigger_type tt_giveitem; + +extern struct trigger * trigger_giveitem(struct unit * mage, const struct item_type * itype, int number); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/killunit.c b/src/triggers/killunit.c index 9ac360bdf..b1d5a4064 100644 --- a/src/triggers/killunit.c +++ b/src/triggers/killunit.c @@ -1,87 +1,87 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "killunit.h" - -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include - -#include -#include -/*** - ** killunit - **/ - -static int -killunit_handle(trigger * t, void * data) -{ - /* call an event handler on killunit. - * data.v -> ( variant event, int timer ) - */ - unit * u = (unit*)t->data.v; - if (u) { - /* we can't remove_unit() here, because that's what's calling us. */ - set_number(u, 0); - } - unused(data); - return 0; -} - -static void -killunit_write(const trigger * t, struct storage * store) -{ - unit * u = (unit*)t->data.v; - write_unit_reference(u, store); -} - -static int -killunit_read(trigger * t, struct storage * store) -{ - int result = read_reference(&t->data.v, store, read_unit_reference, resolve_unit); - if (result==0 && t->data.v==NULL) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -trigger_type tt_killunit = { - "killunit", - NULL, - NULL, - killunit_handle, - killunit_write, - killunit_read -}; - -trigger * -trigger_killunit(unit * u) -{ - trigger * t = t_new(&tt_killunit); - t->data.v = (void*)u; - return t; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "killunit.h" + +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +#include +#include +/*** + ** killunit + **/ + +static int +killunit_handle(trigger * t, void * data) +{ + /* call an event handler on killunit. + * data.v -> ( variant event, int timer ) + */ + unit * u = (unit*)t->data.v; + if (u) { + /* we can't remove_unit() here, because that's what's calling us. */ + set_number(u, 0); + } + unused(data); + return 0; +} + +static void +killunit_write(const trigger * t, struct storage * store) +{ + unit * u = (unit*)t->data.v; + write_unit_reference(u, store); +} + +static int +killunit_read(trigger * t, struct storage * store) +{ + int result = read_reference(&t->data.v, store, read_unit_reference, resolve_unit); + if (result==0 && t->data.v==NULL) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +trigger_type tt_killunit = { + "killunit", + NULL, + NULL, + killunit_handle, + killunit_write, + killunit_read +}; + +trigger * +trigger_killunit(unit * u) +{ + trigger * t = t_new(&tt_killunit); + t->data.v = (void*)u; + return t; +} diff --git a/src/triggers/killunit.h b/src/triggers/killunit.h index 9f42fd4cf..f9aa652fa 100644 --- a/src/triggers/killunit.h +++ b/src/triggers/killunit.h @@ -1,36 +1,36 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef KILLUNIT_H -#define KILLUNIT_H -#ifdef __cplusplus -extern "C" { -#endif - -struct trigger_type; -struct trigger; - -struct unit; - -extern struct trigger_type tt_killunit; -extern struct trigger * trigger_killunit(struct unit * u); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef KILLUNIT_H +#define KILLUNIT_H +#ifdef __cplusplus +extern "C" { +#endif + +struct trigger_type; +struct trigger; + +struct unit; + +extern struct trigger_type tt_killunit; +extern struct trigger * trigger_killunit(struct unit * u); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/removecurse.c b/src/triggers/removecurse.c index 994aa2cdd..0377974cf 100644 --- a/src/triggers/removecurse.c +++ b/src/triggers/removecurse.c @@ -1,114 +1,114 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "removecurse.h" - -/* kernel includes */ -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include - -/* ansi includes */ -#include -#include -#include - - -#include - -typedef struct removecurse_data { - curse * curse; - unit * target; -} removecurse_data; - -static void -removecurse_init(trigger * t) -{ - t->data.v = calloc(sizeof(removecurse_data), 1); -} - -static void -removecurse_free(trigger * t) -{ - free(t->data.v); -} - -static int -removecurse_handle(trigger * t, void * data) -{ - /* call an event handler on removecurse. - * data.v -> ( variant event, int timer ) - */ - removecurse_data * td = (removecurse_data*)t->data.v; - if (td->curse && td->target) { - attrib * a = a_select(td->target->attribs, td->curse, cmp_curse); - if (a) { - a_remove(&td->target->attribs, a); - } - else log_error(("could not perform removecurse::handle()\n")); - } - unused(data); - return 0; -} - -static void -removecurse_write(const trigger * t, struct storage * store) -{ - removecurse_data * td = (removecurse_data*)t->data.v; - store->w_tok(store, td->target?itoa36(td->target->no):0); - store->w_int(store, td->curse?td->curse->no:0); -} - -static int -removecurse_read(trigger * t, struct storage * store) -{ - removecurse_data * td = (removecurse_data*)t->data.v; - - read_reference(&td->target, store, read_unit_reference, resolve_unit); - read_reference(&td->curse, store, read_int, resolve_curse); - - return AT_READ_OK; -} - -trigger_type tt_removecurse = { - "removecurse", - removecurse_init, - removecurse_free, - removecurse_handle, - removecurse_write, - removecurse_read -}; - -trigger * -trigger_removecurse(curse * c, unit * target) -{ - trigger * t = t_new(&tt_removecurse); - removecurse_data * td = (removecurse_data*)t->data.v; - td->curse = c; - td->target = target; - return t; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "removecurse.h" + +/* kernel includes */ +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include + +/* ansi includes */ +#include +#include +#include + + +#include + +typedef struct removecurse_data { + curse * curse; + unit * target; +} removecurse_data; + +static void +removecurse_init(trigger * t) +{ + t->data.v = calloc(sizeof(removecurse_data), 1); +} + +static void +removecurse_free(trigger * t) +{ + free(t->data.v); +} + +static int +removecurse_handle(trigger * t, void * data) +{ + /* call an event handler on removecurse. + * data.v -> ( variant event, int timer ) + */ + removecurse_data * td = (removecurse_data*)t->data.v; + if (td->curse && td->target) { + attrib * a = a_select(td->target->attribs, td->curse, cmp_curse); + if (a) { + a_remove(&td->target->attribs, a); + } + else log_error(("could not perform removecurse::handle()\n")); + } + unused(data); + return 0; +} + +static void +removecurse_write(const trigger * t, struct storage * store) +{ + removecurse_data * td = (removecurse_data*)t->data.v; + store->w_tok(store, td->target?itoa36(td->target->no):0); + store->w_int(store, td->curse?td->curse->no:0); +} + +static int +removecurse_read(trigger * t, struct storage * store) +{ + removecurse_data * td = (removecurse_data*)t->data.v; + + read_reference(&td->target, store, read_unit_reference, resolve_unit); + read_reference(&td->curse, store, read_int, resolve_curse); + + return AT_READ_OK; +} + +trigger_type tt_removecurse = { + "removecurse", + removecurse_init, + removecurse_free, + removecurse_handle, + removecurse_write, + removecurse_read +}; + +trigger * +trigger_removecurse(curse * c, unit * target) +{ + trigger * t = t_new(&tt_removecurse); + removecurse_data * td = (removecurse_data*)t->data.v; + td->curse = c; + td->target = target; + return t; +} diff --git a/src/triggers/removecurse.h b/src/triggers/removecurse.h index 7615b87eb..0a89a5e97 100644 --- a/src/triggers/removecurse.h +++ b/src/triggers/removecurse.h @@ -1,39 +1,39 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef REMOVECURSE_H -#define REMOVECURSE_H -#ifdef __cplusplus -extern "C" { -#endif - -/* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; - -struct unit; -struct curse; - -extern struct trigger_type tt_removecurse; - -extern struct trigger * trigger_removecurse(struct curse * c, struct unit * target); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef REMOVECURSE_H +#define REMOVECURSE_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; + +struct unit; +struct curse; + +extern struct trigger_type tt_removecurse; + +extern struct trigger * trigger_removecurse(struct curse * c, struct unit * target); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/shock.c b/src/triggers/shock.c index 06f15f47d..4cb361478 100644 --- a/src/triggers/shock.c +++ b/src/triggers/shock.c @@ -1,148 +1,148 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "shock.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -/*** - ** shock - **/ - -/* ------------------------------------------------------------- */ -/* do_shock - Schockt die Einheit, z.B. bei Verlust eines */ -/* Vertrauten. */ -/* ------------------------------------------------------------- */ - -static void -do_shock(unit *u, const char *reason) -{ - int i; - - if (u->number > 0) { - /* HP - Verlust */ - u->hp = (unit_max_hp(u) * u->number)/10; - u->hp = MAX(1, u->hp); - } - - /* Aura - Verlust */ - if (is_mage(u)) { - set_spellpoints(u, max_spellpoints(u->region,u)/10); - } - - /* Evt. Talenttageverlust */ - for (i=0;i!=u->skill_size;++i) if (rng_int()%5==0) { - skill * sv = u->skills+i; - int weeks = (sv->level * sv->level - sv->level) / 2; - int change = (weeks+9) / 10; - reduce_skill(u, sv, change); - } - - /* Dies ist ein Hack, um das skillmod und familiar-Attribut beim Mage - * zu löschen wenn der Familiar getötet wird. Da sollten wir über eine - * saubere Implementation nachdenken. */ - - if (strcmp(reason, "trigger")==0) { - remove_familiar(u); - } - if (u->faction!=NULL) { - ADDMSG(&u->faction->msgs, msg_message("shock", - "mage reason", u, strdup(reason))); - } -} - -static int -shock_handle(trigger * t, void * data) -{ - /* destroy the unit */ - unit * u = (unit*)t->data.v; - if (u && u->number) { - do_shock(u, "trigger"); - } - unused(data); - return 0; -} - -static void -shock_write(const trigger * t, struct storage * store) -{ - unit * u = (unit*)t->data.v; - trigger * next = t->next; - while (next) { - /* make sure it is unique! */ - if (next->type==t->type && next->data.v==t->data.v) break; - next=next->next; - } - if (next && u) { - log_error(("more than one shock-attribut for %s on a unit. FIXED.\n", - unitid(u))); - write_unit_reference(NULL, store); - } else { - write_unit_reference(u, store); - } -} - -static int -shock_read(trigger * t, struct storage * store) -{ - int result = read_reference(&t->data.v, store, read_unit_reference, resolve_unit); - if (result==0 && t->data.v==NULL) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -trigger_type tt_shock = { - "shock", - NULL, - NULL, - shock_handle, - shock_write, - shock_read -}; - -trigger * -trigger_shock(unit * u) -{ - trigger * t = t_new(&tt_shock); - t->data.v = (void*)u; - return t; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "shock.h" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +/*** + ** shock + **/ + +/* ------------------------------------------------------------- */ +/* do_shock - Schockt die Einheit, z.B. bei Verlust eines */ +/* Vertrauten. */ +/* ------------------------------------------------------------- */ + +static void +do_shock(unit *u, const char *reason) +{ + int i; + + if (u->number > 0) { + /* HP - Verlust */ + u->hp = (unit_max_hp(u) * u->number)/10; + u->hp = MAX(1, u->hp); + } + + /* Aura - Verlust */ + if (is_mage(u)) { + set_spellpoints(u, max_spellpoints(u->region,u)/10); + } + + /* Evt. Talenttageverlust */ + for (i=0;i!=u->skill_size;++i) if (rng_int()%5==0) { + skill * sv = u->skills+i; + int weeks = (sv->level * sv->level - sv->level) / 2; + int change = (weeks+9) / 10; + reduce_skill(u, sv, change); + } + + /* Dies ist ein Hack, um das skillmod und familiar-Attribut beim Mage + * zu löschen wenn der Familiar getötet wird. Da sollten wir über eine + * saubere Implementation nachdenken. */ + + if (strcmp(reason, "trigger")==0) { + remove_familiar(u); + } + if (u->faction!=NULL) { + ADDMSG(&u->faction->msgs, msg_message("shock", + "mage reason", u, strdup(reason))); + } +} + +static int +shock_handle(trigger * t, void * data) +{ + /* destroy the unit */ + unit * u = (unit*)t->data.v; + if (u && u->number) { + do_shock(u, "trigger"); + } + unused(data); + return 0; +} + +static void +shock_write(const trigger * t, struct storage * store) +{ + unit * u = (unit*)t->data.v; + trigger * next = t->next; + while (next) { + /* make sure it is unique! */ + if (next->type==t->type && next->data.v==t->data.v) break; + next=next->next; + } + if (next && u) { + log_error(("more than one shock-attribut for %s on a unit. FIXED.\n", + unitid(u))); + write_unit_reference(NULL, store); + } else { + write_unit_reference(u, store); + } +} + +static int +shock_read(trigger * t, struct storage * store) +{ + int result = read_reference(&t->data.v, store, read_unit_reference, resolve_unit); + if (result==0 && t->data.v==NULL) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +trigger_type tt_shock = { + "shock", + NULL, + NULL, + shock_handle, + shock_write, + shock_read +}; + +trigger * +trigger_shock(unit * u) +{ + trigger * t = t_new(&tt_shock); + t->data.v = (void*)u; + return t; +} diff --git a/src/triggers/shock.h b/src/triggers/shock.h index 382b65eb9..07e59cb30 100644 --- a/src/triggers/shock.h +++ b/src/triggers/shock.h @@ -1,36 +1,36 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_TRG_SHOCK_H -#define H_TRG_SHOCK_H -#ifdef __cplusplus -extern "C" { -#endif - -struct trigger_type; -struct trigger; - -struct unit; - -extern struct trigger_type tt_shock; -extern struct trigger * trigger_shock(struct unit * u); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_TRG_SHOCK_H +#define H_TRG_SHOCK_H +#ifdef __cplusplus +extern "C" { +#endif + +struct trigger_type; +struct trigger; + +struct unit; + +extern struct trigger_type tt_shock; +extern struct trigger * trigger_shock(struct unit * u); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/timeout.c b/src/triggers/timeout.c index 2e0157508..e0770ed39 100644 --- a/src/triggers/timeout.c +++ b/src/triggers/timeout.c @@ -1,113 +1,113 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "timeout.h" - -/* util includes */ -#include -#include -#include -#include - -#include -#include -/*** - ** timeout - **/ - -typedef struct timeout_data { - trigger * triggers; - int timer; - variant trigger_data; -} timeout_data; - -static void -timeout_init(trigger * t) -{ - t->data.v = calloc(sizeof(timeout_data), 1); -} - -static void -timeout_free(trigger * t) -{ - timeout_data * td = (timeout_data*)t->data.v; - free_triggers(td->triggers); - free(t->data.v); -} - -static int -timeout_handle(trigger * t, void * data) -{ - /* call an event handler on timeout. - * data.v -> ( variant event, int timer ) - */ - timeout_data * td = (timeout_data*)t->data.v; - if (--td->timer==0) { - handle_triggers(&td->triggers, NULL); - return -1; - } - unused(data); - return 0; -} - -static void -timeout_write(const trigger * t, struct storage * store) -{ - timeout_data * td = (timeout_data*)t->data.v; - store->w_int(store, td->timer); - write_triggers(store, td->triggers); -} - -static int -timeout_read(trigger * t, struct storage * store) -{ - timeout_data * td = (timeout_data*)t->data.v; - td->timer = store->r_int(store); - read_triggers(store, &td->triggers); - if (td->timer>20) { - trigger * tr = td->triggers; - log_warning(("there is a timeout lasting for another %d turns\n", td->timer)); - while (tr) { - log_warning((" timeout triggers: %s\n", tr->type->name)); - tr = tr->next; - } - } - if (td->triggers!=NULL && td->timer>0) return AT_READ_OK; - return AT_READ_FAIL; -} - -trigger_type tt_timeout = { - "timeout", - timeout_init, - timeout_free, - timeout_handle, - timeout_write, - timeout_read -}; - -trigger * -trigger_timeout(int time, trigger * callbacks) -{ - trigger * t = t_new(&tt_timeout); - timeout_data * td = (timeout_data*)t->data.v; - td->triggers = callbacks; - td->timer = time; - return t; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "timeout.h" + +/* util includes */ +#include +#include +#include +#include + +#include +#include +/*** + ** timeout + **/ + +typedef struct timeout_data { + trigger * triggers; + int timer; + variant trigger_data; +} timeout_data; + +static void +timeout_init(trigger * t) +{ + t->data.v = calloc(sizeof(timeout_data), 1); +} + +static void +timeout_free(trigger * t) +{ + timeout_data * td = (timeout_data*)t->data.v; + free_triggers(td->triggers); + free(t->data.v); +} + +static int +timeout_handle(trigger * t, void * data) +{ + /* call an event handler on timeout. + * data.v -> ( variant event, int timer ) + */ + timeout_data * td = (timeout_data*)t->data.v; + if (--td->timer==0) { + handle_triggers(&td->triggers, NULL); + return -1; + } + unused(data); + return 0; +} + +static void +timeout_write(const trigger * t, struct storage * store) +{ + timeout_data * td = (timeout_data*)t->data.v; + store->w_int(store, td->timer); + write_triggers(store, td->triggers); +} + +static int +timeout_read(trigger * t, struct storage * store) +{ + timeout_data * td = (timeout_data*)t->data.v; + td->timer = store->r_int(store); + read_triggers(store, &td->triggers); + if (td->timer>20) { + trigger * tr = td->triggers; + log_warning(("there is a timeout lasting for another %d turns\n", td->timer)); + while (tr) { + log_warning((" timeout triggers: %s\n", tr->type->name)); + tr = tr->next; + } + } + if (td->triggers!=NULL && td->timer>0) return AT_READ_OK; + return AT_READ_FAIL; +} + +trigger_type tt_timeout = { + "timeout", + timeout_init, + timeout_free, + timeout_handle, + timeout_write, + timeout_read +}; + +trigger * +trigger_timeout(int time, trigger * callbacks) +{ + trigger * t = t_new(&tt_timeout); + timeout_data * td = (timeout_data*)t->data.v; + td->triggers = callbacks; + td->timer = time; + return t; +} diff --git a/src/triggers/timeout.h b/src/triggers/timeout.h index e62bef26e..3f9f122ef 100644 --- a/src/triggers/timeout.h +++ b/src/triggers/timeout.h @@ -1,35 +1,35 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_TRG_TIMEOUT_H -#define H_TRG_TIMEOUT_H -#ifdef __cplusplus -extern "C" { -#endif - -struct trigger_type; -struct trigger; - -extern struct trigger_type tt_timeout; - -extern struct trigger * trigger_timeout(int time, struct trigger * callbacks); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_TRG_TIMEOUT_H +#define H_TRG_TIMEOUT_H +#ifdef __cplusplus +extern "C" { +#endif + +struct trigger_type; +struct trigger; + +extern struct trigger_type tt_timeout; + +extern struct trigger * trigger_timeout(int time, struct trigger * callbacks); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/triggers.c b/src/triggers/triggers.c index 4d974f975..7df6cffc1 100644 --- a/src/triggers/triggers.c +++ b/src/triggers/triggers.c @@ -1,60 +1,60 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include - -/* triggers includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include - -/* libc includes */ -#include - -void -register_triggers(void) -{ - if (verbosity>=2) printf("- registering triggers\n"); - tt_register(&tt_changefaction); - tt_register(&tt_changerace); - tt_register(&tt_createcurse); - tt_register(&tt_createunit); - tt_register(&tt_gate); - tt_register(&tt_unguard); - tt_register(&tt_giveitem); - tt_register(&tt_killunit); - tt_register(&tt_removecurse); - tt_register(&tt_shock); - tt_register(&tt_unitmessage); - tt_register(&tt_timeout); - tt_register(&tt_clonedied); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include + +/* triggers includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* util includes */ +#include + +/* libc includes */ +#include + +void +register_triggers(void) +{ + if (verbosity>=2) printf("- registering triggers\n"); + tt_register(&tt_changefaction); + tt_register(&tt_changerace); + tt_register(&tt_createcurse); + tt_register(&tt_createunit); + tt_register(&tt_gate); + tt_register(&tt_unguard); + tt_register(&tt_giveitem); + tt_register(&tt_killunit); + tt_register(&tt_removecurse); + tt_register(&tt_shock); + tt_register(&tt_unitmessage); + tt_register(&tt_timeout); + tt_register(&tt_clonedied); +} diff --git a/src/triggers/triggers.h b/src/triggers/triggers.h index bb6f81d30..def5f4072 100644 --- a/src/triggers/triggers.h +++ b/src/triggers/triggers.h @@ -1,30 +1,30 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_TRG_TRIGGERS -#define H_TRG_TRIGGERS -#ifdef __cplusplus -extern "C" { -#endif - -void register_triggers(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_TRG_TRIGGERS +#define H_TRG_TRIGGERS +#ifdef __cplusplus +extern "C" { +#endif + +void register_triggers(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/unguard.c b/src/triggers/unguard.c index 079d93218..1c4cb42ea 100644 --- a/src/triggers/unguard.c +++ b/src/triggers/unguard.c @@ -1,77 +1,77 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ -#include -#include -#include "unguard.h" - -/* kernel includes */ -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include - -/* libc includes */ -#include - -static int -unguard_handle(trigger * t, void * data) -{ - building * b = (building*)t->data.v; - - if (b) { - fset(b, BLD_UNGUARDED); - } else { - log_error(("could not perform unguard::handle()\n")); - return -1; - } - unused(data); - return 0; -} - -static void -unguard_write(const trigger * t, struct storage * store) -{ - write_building_reference((building*)t->data.v, store); -} - -static int -unguard_read(trigger * t, struct storage * store) -{ - int rb = read_reference(&t->data.v, store, read_building_reference, resolve_building); - if (rb==0 && !t->data.v) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -struct trigger_type tt_unguard = { - "building", - NULL, - NULL, - unguard_handle, - unguard_write, - unguard_read -}; - -trigger * -trigger_unguard(building * b) -{ - trigger * t = t_new(&tt_unguard); - t->data.v = (void*)b; - return t; -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#include +#include +#include "unguard.h" + +/* kernel includes */ +#include +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include + +/* libc includes */ +#include + +static int +unguard_handle(trigger * t, void * data) +{ + building * b = (building*)t->data.v; + + if (b) { + fset(b, BLD_UNGUARDED); + } else { + log_error(("could not perform unguard::handle()\n")); + return -1; + } + unused(data); + return 0; +} + +static void +unguard_write(const trigger * t, struct storage * store) +{ + write_building_reference((building*)t->data.v, store); +} + +static int +unguard_read(trigger * t, struct storage * store) +{ + int rb = read_reference(&t->data.v, store, read_building_reference, resolve_building); + if (rb==0 && !t->data.v) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +struct trigger_type tt_unguard = { + "building", + NULL, + NULL, + unguard_handle, + unguard_write, + unguard_read +}; + +trigger * +trigger_unguard(building * b) +{ + trigger * t = t_new(&tt_unguard); + t->data.v = (void*)b; + return t; +} diff --git a/src/triggers/unguard.h b/src/triggers/unguard.h index a5ad8c3d7..7748e5a92 100644 --- a/src/triggers/unguard.h +++ b/src/triggers/unguard.h @@ -1,32 +1,32 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef UNGUARD_H -#define UNGUARD_H -#ifdef __cplusplus -extern "C" { -#endif - -/* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; -struct region; -struct building; - -extern struct trigger_type tt_unguard; - -extern struct trigger * trigger_unguard(struct building * b); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef UNGUARD_H +#define UNGUARD_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; +struct region; +struct building; + +extern struct trigger_type tt_unguard; + +extern struct trigger * trigger_unguard(struct building * b); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/triggers/unitmessage.c b/src/triggers/unitmessage.c index ca7b0d7c2..f1d7d7dbf 100644 --- a/src/triggers/unitmessage.c +++ b/src/triggers/unitmessage.c @@ -1,123 +1,123 @@ -/* vi: set ts=2: -+-------------------+ Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -+-------------------+ -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include -#include "unitmessage.h" - -/* kernel includes */ -#include -#include -#include - -/* util includes */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* ansi includes */ -#include -#include -#include -#include - -/*** -** give an item to someone -**/ - -typedef struct unitmessage_data { - struct unit * target; - char * string; - int type; - int level; -} unitmessage_data; - -static void -unitmessage_init(trigger * t) -{ - t->data.v = calloc(sizeof(unitmessage_data), 1); -} - -static void -unitmessage_free(trigger * t) -{ - unitmessage_data * sd = (unitmessage_data*)t->data.v; - free(sd->string); - free(t->data.v); -} - -static int -unitmessage_handle(trigger * t, void * data) -{ - /* call an event handler on unitmessage. - * data.v -> ( variant event, int timer ) - */ - unitmessage_data * td = (unitmessage_data*)t->data.v; - if (td->target && td->target->no) { - struct faction * f = td->target->faction; - addmessage(td->target->region, f, LOC(f->locale, td->string), td->type, td->level); - } - unused(data); - return 0; -} - -static void -unitmessage_write(const trigger * t, struct storage * store) -{ - unitmessage_data * td = (unitmessage_data*)t->data.v; - write_unit_reference(td->target, store); - store->w_tok(store, td->string); - store->w_int(store, td->type); - store->w_int(store, td->level); -} - -static int -unitmessage_read(trigger * t, struct storage * store) -{ - unitmessage_data * td = (unitmessage_data*)t->data.v; - char zText[256]; - - int result = read_reference(&td->target, store, read_unit_reference, resolve_unit); - - td->string = store->r_tok(store); - td->type = store->r_int(store); - td->level = store->r_int(store); - td->string = strdup(zText); - - if (result==0 && td->target==NULL) { - return AT_READ_FAIL; - } - return AT_READ_OK; -} - -trigger_type tt_unitmessage = { - "unitmessage", - unitmessage_init, - unitmessage_free, - unitmessage_handle, - unitmessage_write, - unitmessage_read -}; - -trigger * -trigger_unitmessage(unit * target, const char * string, int type, int level) -{ - trigger * t = t_new(&tt_unitmessage); - unitmessage_data * td = (unitmessage_data*)t->data.v; - td->target = target; - td->string = strdup(string); - td->type = type; - td->level = level; - return t; -} +/* vi: set ts=2: ++-------------------+ Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel ++-------------------+ +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include +#include "unitmessage.h" + +/* kernel includes */ +#include +#include +#include + +/* util includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* ansi includes */ +#include +#include +#include +#include + +/*** +** give an item to someone +**/ + +typedef struct unitmessage_data { + struct unit * target; + char * string; + int type; + int level; +} unitmessage_data; + +static void +unitmessage_init(trigger * t) +{ + t->data.v = calloc(sizeof(unitmessage_data), 1); +} + +static void +unitmessage_free(trigger * t) +{ + unitmessage_data * sd = (unitmessage_data*)t->data.v; + free(sd->string); + free(t->data.v); +} + +static int +unitmessage_handle(trigger * t, void * data) +{ + /* call an event handler on unitmessage. + * data.v -> ( variant event, int timer ) + */ + unitmessage_data * td = (unitmessage_data*)t->data.v; + if (td->target && td->target->no) { + struct faction * f = td->target->faction; + addmessage(td->target->region, f, LOC(f->locale, td->string), td->type, td->level); + } + unused(data); + return 0; +} + +static void +unitmessage_write(const trigger * t, struct storage * store) +{ + unitmessage_data * td = (unitmessage_data*)t->data.v; + write_unit_reference(td->target, store); + store->w_tok(store, td->string); + store->w_int(store, td->type); + store->w_int(store, td->level); +} + +static int +unitmessage_read(trigger * t, struct storage * store) +{ + unitmessage_data * td = (unitmessage_data*)t->data.v; + char zText[256]; + + int result = read_reference(&td->target, store, read_unit_reference, resolve_unit); + + td->string = store->r_tok(store); + td->type = store->r_int(store); + td->level = store->r_int(store); + td->string = strdup(zText); + + if (result==0 && td->target==NULL) { + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +trigger_type tt_unitmessage = { + "unitmessage", + unitmessage_init, + unitmessage_free, + unitmessage_handle, + unitmessage_write, + unitmessage_read +}; + +trigger * +trigger_unitmessage(unit * target, const char * string, int type, int level) +{ + trigger * t = t_new(&tt_unitmessage); + unitmessage_data * td = (unitmessage_data*)t->data.v; + td->target = target; + td->string = strdup(string); + td->type = type; + td->level = level; + return t; +} diff --git a/src/triggers/unitmessage.h b/src/triggers/unitmessage.h index 5833e4645..dcc8df47d 100644 --- a/src/triggers/unitmessage.h +++ b/src/triggers/unitmessage.h @@ -1,36 +1,36 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef UNITMESSAGE_H -#define UNITMESSAGE_H -#ifdef __cplusplus -extern "C" { -#endif - -/* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; -struct unit; - -extern struct trigger_type tt_unitmessage; -extern struct trigger * trigger_unitmessage(struct unit * target, const char * string, int type, int level); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef UNITMESSAGE_H +#define UNITMESSAGE_H +#ifdef __cplusplus +extern "C" { +#endif + +/* all types we use are defined here to reduce dependencies */ +struct trigger_type; +struct trigger; +struct unit; + +extern struct trigger_type tt_unitmessage; +extern struct trigger * trigger_unitmessage(struct unit * target, const char * string, int type, int level); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/argstack.c b/src/util/argstack.c index a938d77ec..614a18def 100644 --- a/src/util/argstack.c +++ b/src/util/argstack.c @@ -1,66 +1,66 @@ -#include "argstack.h" -#include - -#define ARGSTKSIZE 16 -typedef struct arguments { - int n; - struct value { - int type; - union { - double number; - const char * str; - void * data; - } value; - } stack[ARGSTKSIZE]; -} arguments; - -void arg_init(struct arguments * arg) { - arg->n = 0; -} - -void arg_done(struct arguments * arg) { - arg = arg; -} - -void arg_pushuserdata(struct arguments * arg, int type, void * data) { - assert(arg->nstack[arg->n].type = type; - arg->stack[arg->n].value.data = data; - ++arg->n; -} - -void arg_pushstring(struct arguments * arg, const char * str) { - assert(arg->nstack[arg->n].type = ARG_TSTRING; - arg->stack[arg->n].value.str = str; - ++arg->n; -} - -void arg_pushnumber(struct arguments * arg, double number) { - assert(arg->nstack[arg->n].type = ARG_TSTRING; - arg->stack[arg->n].value.number = number; - ++arg->n; -} - -int arg_size(struct arguments * arg) { - return arg->n; -} - -void * arg_touserdata(struct arguments * arg, int idx, int type) { - assert(arg->n>idx && idx>=0); - assert(arg->stack[arg->n].type==type); - return arg->stack[arg->n].value.data; -} - -double arg_tonumber(struct arguments * arg, int idx) { - assert(arg->n>idx && idx>=0); - assert(arg->stack[arg->n].type==ARG_TNUMBER); - return arg->stack[arg->n].value.number; -} - -const char * arg_tostring(struct arguments * arg, int idx) { - assert(arg->n>idx && idx>=0); - assert(arg->stack[arg->n].type==ARG_TSTRING); - return arg->stack[arg->n].value.str; -} +#include "argstack.h" +#include + +#define ARGSTKSIZE 16 +typedef struct arguments { + int n; + struct value { + int type; + union { + double number; + const char * str; + void * data; + } value; + } stack[ARGSTKSIZE]; +} arguments; + +void arg_init(struct arguments * arg) { + arg->n = 0; +} + +void arg_done(struct arguments * arg) { + arg = arg; +} + +void arg_pushuserdata(struct arguments * arg, int type, void * data) { + assert(arg->nstack[arg->n].type = type; + arg->stack[arg->n].value.data = data; + ++arg->n; +} + +void arg_pushstring(struct arguments * arg, const char * str) { + assert(arg->nstack[arg->n].type = ARG_TSTRING; + arg->stack[arg->n].value.str = str; + ++arg->n; +} + +void arg_pushnumber(struct arguments * arg, double number) { + assert(arg->nstack[arg->n].type = ARG_TSTRING; + arg->stack[arg->n].value.number = number; + ++arg->n; +} + +int arg_size(struct arguments * arg) { + return arg->n; +} + +void * arg_touserdata(struct arguments * arg, int idx, int type) { + assert(arg->n>idx && idx>=0); + assert(arg->stack[arg->n].type==type); + return arg->stack[arg->n].value.data; +} + +double arg_tonumber(struct arguments * arg, int idx) { + assert(arg->n>idx && idx>=0); + assert(arg->stack[arg->n].type==ARG_TNUMBER); + return arg->stack[arg->n].value.number; +} + +const char * arg_tostring(struct arguments * arg, int idx) { + assert(arg->n>idx && idx>=0); + assert(arg->stack[arg->n].type==ARG_TSTRING); + return arg->stack[arg->n].value.str; +} diff --git a/src/util/argstack.h b/src/util/argstack.h index 4ce6738ec..b4a0dc420 100644 --- a/src/util/argstack.h +++ b/src/util/argstack.h @@ -1,27 +1,27 @@ -#ifndef UTIL_ARG_H -#define UTIL_ARG_H -#ifdef __cplusplus -extern "C" { -#endif - -struct arguments; - -#define ARG_TNUMBER -1 -#define ARG_TSTRING -2 - -void arg_init(struct arguments * arg); -void arg_done(struct arguments * arg); - -void arg_push(struct arguments * arg, int type, void * data); -void arg_pushstring(struct arguments * arg, const char * str); -void arg_pushnumber(struct arguments * arg, double number); - -int arg_size(struct arguments * arg); -void * arg_touserdata(struct arguments * arg, int idx, int type); -double arg_tonumber(struct arguments * arg, int idx); -const char * arg_tostring(struct arguments * arg, int idx); - -#ifdef __cplusplus -} -#endif -#endif +#ifndef UTIL_ARG_H +#define UTIL_ARG_H +#ifdef __cplusplus +extern "C" { +#endif + +struct arguments; + +#define ARG_TNUMBER -1 +#define ARG_TSTRING -2 + +void arg_init(struct arguments * arg); +void arg_done(struct arguments * arg); + +void arg_push(struct arguments * arg, int type, void * data); +void arg_pushstring(struct arguments * arg, const char * str); +void arg_pushnumber(struct arguments * arg, double number); + +int arg_size(struct arguments * arg); +void * arg_touserdata(struct arguments * arg, int idx, int type); +double arg_tonumber(struct arguments * arg, int idx); +const char * arg_tostring(struct arguments * arg, int idx); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/attrib.c b/src/util/attrib.c index 18c4937af..97d3a0d97 100644 --- a/src/util/attrib.c +++ b/src/util/attrib.c @@ -1,322 +1,322 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "attrib.h" - -#include "log.h" -#include "storage.h" - -#include -#include -#include - -#define MAXATHASH 61 -attrib_type * at_hash[MAXATHASH]; - -static unsigned int -__at_hashkey(const char* s) -{ - int key = 0; - size_t i = strlen(s); - - while (i>0) { - key = (s[--i] + key*37); - } - return key & 0x7fffffff; -} - -void -at_register(attrib_type * at) -{ - attrib_type * find; - - if (at->read==NULL) { - log_warning(("registering non-persistent attribute %s.\n", at->name)); - } - at->hashkey = __at_hashkey(at->name); - find = at_hash[at->hashkey % MAXATHASH]; - while (find && at->hashkey!=find->hashkey) find = find->nexthash; - if (find && find==at) { - log_warning(("attribute '%s' was registered more than once\n", at->name)); - return; - } else { - assert(!find || !"hashkey is already in use"); - } - at->nexthash = at_hash[at->hashkey % MAXATHASH]; - at_hash[at->hashkey % MAXATHASH] = at; -} - -static attrib_type * -at_find(unsigned int hk) -{ - const char* translate[3][2] = { - { "zielregion", "targetregion" }, /* remapping: from 'zielregion, heute targetregion */ - { "verzaubert", "curse" }, /* remapping: früher verzaubert, jetzt curse */ - { NULL, NULL } - }; - attrib_type * find = at_hash[hk % MAXATHASH]; - while (find && hk!=find->hashkey) find = find->nexthash; - if (!find) { - int i = 0; - while (translate[i][0]) { - if (__at_hashkey(translate[i][0])==hk) - return at_find(__at_hashkey(translate[i][1])); - ++i; - } - } - return find; -} - -attrib * -a_select(attrib * a, const void * data, boolean(*compare)(const attrib *, const void *)) -{ - while (a && !compare(a, data)) a = a->next; - return a; -} - -attrib * -a_find(attrib * a, const attrib_type * at) -{ - while (a && a->type!=at) a = a->nexttype; - return a; -} - -const attrib * -a_findc(const attrib * a, const attrib_type * at) -{ - while (a && a->type!=at) a = a->nexttype; - return a; -} - -static attrib * -a_insert(attrib * head, attrib * a) -{ - attrib ** pa=&head->next; - - assert(!(a->type->flags & ATF_UNIQUE)); - assert(head && head->type==a->type); - - while (*pa && (*pa)->type==a->type) { - pa = &(*pa)->next; - } - a->next = *pa; - return *pa = a; -} - -attrib * -a_add(attrib ** pa, attrib * a) -{ - attrib * first = *pa; - assert(a->next==NULL && a->nexttype==NULL); - - if (first==NULL) return *pa = a; - if (first->type==a->type) { - return a_insert(first, a); - } - for (;;) { - attrib * next = first->nexttype; - if (next==NULL) { - /* the type is not in the list, append it behind the last type */ - attrib ** insert = &first->next; - first->nexttype = a; - while (*insert) insert = &(*insert)->next; - *insert = a; - break; - } - if (next->type==a->type) { - return a_insert(next, a); - } - first = next; - } - return a; -} - -void -a_free(attrib * a) -{ - const attrib_type * at = a->type; - if (at->finalize) at->finalize(a); - free(a); -} - -static int -a_unlink(attrib ** pa, attrib * a) -{ - attrib ** pnexttype = pa; - attrib ** pnext = NULL; - - assert(a!=NULL); - while (*pnexttype) { - attrib * next = *pnexttype; - if (next->type==a->type) break; - pnexttype = &next->nexttype; - pnext = &next->next; - } - if (*pnexttype && (*pnexttype)->type==a->type) { - if (*pnexttype==a) { - *pnexttype = a->next; - if (a->next!=a->nexttype) { - a->next->nexttype = a->nexttype; - } - if (pnext==NULL) return 1; - while (*pnext && (*pnext)->type!=a->type) pnext = &(*pnext)->next; - } else { - pnext = &(*pnexttype)->next; - } - while (*pnext && (*pnext)->type==a->type) { - if (*pnext==a) { - *pnext = a->next; - return 1; - } - pnext = &(*pnext)->next; - } - } - return 0; -} - -int -a_remove(attrib ** pa, attrib * a) -{ - int ok; - assert(a!=NULL); - ok = a_unlink(pa, a); - if (ok) a_free(a); - return ok; -} - -void -a_removeall(attrib **pa, const attrib_type * at) -{ - attrib ** pnexttype = pa; - attrib ** pnext = NULL; - - while (*pnexttype) { - attrib * next = *pnexttype; - if (next->type==at) break; - pnexttype = &next->nexttype; - pnext = &next->next; - } - if (*pnexttype && (*pnexttype)->type==at) { - attrib * a = *pnexttype; - - *pnexttype = a->nexttype; - if (pnext) { - while (*pnext && (*pnext)->type!=at) pnext = &(*pnext)->next; - *pnext = a->nexttype; - } - while (a && a->type==at) { - attrib * ra = a; - a = a->next; - a_free(ra); - } - } -} - -attrib * -a_new(const attrib_type * at) -{ - attrib * a = (attrib*)calloc(1, sizeof(attrib)); - assert(at!=NULL); - a->type = at; - if (at->initialize) at->initialize(a); - return a; -} - -int -a_age(attrib ** p) -{ - attrib ** ap = p; - /* Attribute altern, und die Entfernung (age()==0) eines Attributs - * hat Einfluß auf den Besitzer */ - while(*ap) { - attrib * a = *ap; - if (a->type->age) { - int result = a->type->age(a); - assert(result>=0 || !"age() returned a negative value"); - if (result==0) { - a_remove(p, a); - continue; - } - } - ap = &a->next; - } - return (*p!=NULL); -} - -int -a_read(struct storage * store, attrib ** attribs, void * owner) -{ - int key, retval = AT_READ_OK; - char zText[128]; - strcpy(zText, "unknown"); - - key = -1; - store->r_tok_buf(store, zText, sizeof(zText)); - if (strcmp(zText, "end")==0) return retval; - else key = __at_hashkey(zText); - - while(key!=-1) { - attrib_type * at = at_find(key); - if (!at) { - fprintf(stderr, "attribute hash: %d (%s)\n", key, zText); - assert(at || !"attribute not registered"); - } - if (at->read) { - attrib * na = a_new(at); - int i = at->read(na, owner, store); - switch (i) { - case AT_READ_OK: - a_add(attribs, na); - break; - case AT_READ_FAIL: - retval = AT_READ_FAIL; - a_free(na); - break; - default: - assert(!"invalid return value"); - break; - } - } else { - assert(!"fehler: keine laderoutine für attribut"); - } - - store->r_tok_buf(store, zText, sizeof(zText)); - if (!strcmp(zText, "end")) break; - key = __at_hashkey(zText); - } - return retval; -} - -void -a_write(struct storage * store, const attrib * attribs, const void * owner) -{ - const attrib * na = attribs; - - while(na) { - if (na->type->write) { - assert(na->type->hashkey || !"attribute not registered"); - store->w_tok(store, na->type->name); - na->type->write(na, owner, store); - na = na->next; - } else { - na = na->nexttype; - } - } - store->w_tok(store, "end"); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "attrib.h" + +#include "log.h" +#include "storage.h" + +#include +#include +#include + +#define MAXATHASH 61 +attrib_type * at_hash[MAXATHASH]; + +static unsigned int +__at_hashkey(const char* s) +{ + int key = 0; + size_t i = strlen(s); + + while (i>0) { + key = (s[--i] + key*37); + } + return key & 0x7fffffff; +} + +void +at_register(attrib_type * at) +{ + attrib_type * find; + + if (at->read==NULL) { + log_warning(("registering non-persistent attribute %s.\n", at->name)); + } + at->hashkey = __at_hashkey(at->name); + find = at_hash[at->hashkey % MAXATHASH]; + while (find && at->hashkey!=find->hashkey) find = find->nexthash; + if (find && find==at) { + log_warning(("attribute '%s' was registered more than once\n", at->name)); + return; + } else { + assert(!find || !"hashkey is already in use"); + } + at->nexthash = at_hash[at->hashkey % MAXATHASH]; + at_hash[at->hashkey % MAXATHASH] = at; +} + +static attrib_type * +at_find(unsigned int hk) +{ + const char* translate[3][2] = { + { "zielregion", "targetregion" }, /* remapping: from 'zielregion, heute targetregion */ + { "verzaubert", "curse" }, /* remapping: früher verzaubert, jetzt curse */ + { NULL, NULL } + }; + attrib_type * find = at_hash[hk % MAXATHASH]; + while (find && hk!=find->hashkey) find = find->nexthash; + if (!find) { + int i = 0; + while (translate[i][0]) { + if (__at_hashkey(translate[i][0])==hk) + return at_find(__at_hashkey(translate[i][1])); + ++i; + } + } + return find; +} + +attrib * +a_select(attrib * a, const void * data, boolean(*compare)(const attrib *, const void *)) +{ + while (a && !compare(a, data)) a = a->next; + return a; +} + +attrib * +a_find(attrib * a, const attrib_type * at) +{ + while (a && a->type!=at) a = a->nexttype; + return a; +} + +const attrib * +a_findc(const attrib * a, const attrib_type * at) +{ + while (a && a->type!=at) a = a->nexttype; + return a; +} + +static attrib * +a_insert(attrib * head, attrib * a) +{ + attrib ** pa=&head->next; + + assert(!(a->type->flags & ATF_UNIQUE)); + assert(head && head->type==a->type); + + while (*pa && (*pa)->type==a->type) { + pa = &(*pa)->next; + } + a->next = *pa; + return *pa = a; +} + +attrib * +a_add(attrib ** pa, attrib * a) +{ + attrib * first = *pa; + assert(a->next==NULL && a->nexttype==NULL); + + if (first==NULL) return *pa = a; + if (first->type==a->type) { + return a_insert(first, a); + } + for (;;) { + attrib * next = first->nexttype; + if (next==NULL) { + /* the type is not in the list, append it behind the last type */ + attrib ** insert = &first->next; + first->nexttype = a; + while (*insert) insert = &(*insert)->next; + *insert = a; + break; + } + if (next->type==a->type) { + return a_insert(next, a); + } + first = next; + } + return a; +} + +void +a_free(attrib * a) +{ + const attrib_type * at = a->type; + if (at->finalize) at->finalize(a); + free(a); +} + +static int +a_unlink(attrib ** pa, attrib * a) +{ + attrib ** pnexttype = pa; + attrib ** pnext = NULL; + + assert(a!=NULL); + while (*pnexttype) { + attrib * next = *pnexttype; + if (next->type==a->type) break; + pnexttype = &next->nexttype; + pnext = &next->next; + } + if (*pnexttype && (*pnexttype)->type==a->type) { + if (*pnexttype==a) { + *pnexttype = a->next; + if (a->next!=a->nexttype) { + a->next->nexttype = a->nexttype; + } + if (pnext==NULL) return 1; + while (*pnext && (*pnext)->type!=a->type) pnext = &(*pnext)->next; + } else { + pnext = &(*pnexttype)->next; + } + while (*pnext && (*pnext)->type==a->type) { + if (*pnext==a) { + *pnext = a->next; + return 1; + } + pnext = &(*pnext)->next; + } + } + return 0; +} + +int +a_remove(attrib ** pa, attrib * a) +{ + int ok; + assert(a!=NULL); + ok = a_unlink(pa, a); + if (ok) a_free(a); + return ok; +} + +void +a_removeall(attrib **pa, const attrib_type * at) +{ + attrib ** pnexttype = pa; + attrib ** pnext = NULL; + + while (*pnexttype) { + attrib * next = *pnexttype; + if (next->type==at) break; + pnexttype = &next->nexttype; + pnext = &next->next; + } + if (*pnexttype && (*pnexttype)->type==at) { + attrib * a = *pnexttype; + + *pnexttype = a->nexttype; + if (pnext) { + while (*pnext && (*pnext)->type!=at) pnext = &(*pnext)->next; + *pnext = a->nexttype; + } + while (a && a->type==at) { + attrib * ra = a; + a = a->next; + a_free(ra); + } + } +} + +attrib * +a_new(const attrib_type * at) +{ + attrib * a = (attrib*)calloc(1, sizeof(attrib)); + assert(at!=NULL); + a->type = at; + if (at->initialize) at->initialize(a); + return a; +} + +int +a_age(attrib ** p) +{ + attrib ** ap = p; + /* Attribute altern, und die Entfernung (age()==0) eines Attributs + * hat Einfluß auf den Besitzer */ + while(*ap) { + attrib * a = *ap; + if (a->type->age) { + int result = a->type->age(a); + assert(result>=0 || !"age() returned a negative value"); + if (result==0) { + a_remove(p, a); + continue; + } + } + ap = &a->next; + } + return (*p!=NULL); +} + +int +a_read(struct storage * store, attrib ** attribs, void * owner) +{ + int key, retval = AT_READ_OK; + char zText[128]; + strcpy(zText, "unknown"); + + key = -1; + store->r_tok_buf(store, zText, sizeof(zText)); + if (strcmp(zText, "end")==0) return retval; + else key = __at_hashkey(zText); + + while(key!=-1) { + attrib_type * at = at_find(key); + if (!at) { + fprintf(stderr, "attribute hash: %d (%s)\n", key, zText); + assert(at || !"attribute not registered"); + } + if (at->read) { + attrib * na = a_new(at); + int i = at->read(na, owner, store); + switch (i) { + case AT_READ_OK: + a_add(attribs, na); + break; + case AT_READ_FAIL: + retval = AT_READ_FAIL; + a_free(na); + break; + default: + assert(!"invalid return value"); + break; + } + } else { + assert(!"fehler: keine laderoutine für attribut"); + } + + store->r_tok_buf(store, zText, sizeof(zText)); + if (!strcmp(zText, "end")) break; + key = __at_hashkey(zText); + } + return retval; +} + +void +a_write(struct storage * store, const attrib * attribs, const void * owner) +{ + const attrib * na = attribs; + + while(na) { + if (na->type->write) { + assert(na->type->hashkey || !"attribute not registered"); + store->w_tok(store, na->type->name); + na->type->write(na, owner, store); + na = na->next; + } else { + na = na->nexttype; + } + } + store->w_tok(store, "end"); +} diff --git a/src/util/attrib.h b/src/util/attrib.h index 638505a67..f5c6648fb 100644 --- a/src/util/attrib.h +++ b/src/util/attrib.h @@ -1,93 +1,93 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef ATTRIB_H -#define ATTRIB_H -#ifdef __cplusplus -extern "C" { -#endif - -struct storage; -typedef void (*afun)(void); - -typedef struct attrib { - const struct attrib_type * type; - union { - afun f; - void * v; - int i; - float flt; - char c; - short s; - short sa[2]; - char ca[4]; - } data; - /* internal data, do not modify: */ - struct attrib * next; /* next attribute in the list */ - struct attrib * nexttype; /* skip to attribute of a different type */ -} attrib; - -#define ATF_UNIQUE (1<<0) /* only one per attribute-list */ -#define ATF_PRESERVE (1<<1) /* preserve order in list. append to back */ -#define ATF_USER_DEFINED (1<<2) /* use this to make udf */ - -typedef struct attrib_type { - const char* name; - void (*initialize)(struct attrib *); - void (*finalize)(struct attrib *); - int (*age)(struct attrib *); - /* age returns 0 if the attribute needs to be removed, !=0 otherwise */ - void (*write)(const struct attrib *, const void * owner, struct storage *); - int (*read)(struct attrib *, void * owner, struct storage *); /* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */ - unsigned int flags; - /* ---- internal data, do not modify: ---- */ - struct attrib_type * nexthash; - unsigned int hashkey; -} attrib_type; - -extern void at_register(attrib_type * at); - -extern attrib * a_select(attrib * a, const void * data, boolean(*compare)(const attrib *, const void *)); -extern attrib * a_find(attrib * a, const attrib_type * at); -extern const attrib * a_findc(const attrib * a, const attrib_type * at); -extern attrib * a_add(attrib ** pa, attrib * at); -extern int a_remove(attrib ** pa, attrib * at); -extern void a_removeall(attrib ** a, const attrib_type * at); -extern attrib * a_new(const attrib_type * at); -extern void a_free(attrib * a); - -extern int a_age(attrib ** attribs); -extern int a_read(struct storage * store, attrib ** attribs, void * owner); -extern void a_write(struct storage * store, const attrib * attribs, const void * owner); - -#define DEFAULT_AGE NULL -#define DEFAULT_INIT NULL -#define DEFAULT_FINALIZE NULL -#define NO_WRITE NULL -#define NO_READ NULL - -#define AT_READ_OK 0 -#define AT_READ_FAIL -1 - -#define AT_AGE_REMOVE 0 /* remove the attribute after calling age() */ -#define AT_AGE_KEEP 1 /* keep the attribute for another turn */ - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef ATTRIB_H +#define ATTRIB_H +#ifdef __cplusplus +extern "C" { +#endif + +struct storage; +typedef void (*afun)(void); + +typedef struct attrib { + const struct attrib_type * type; + union { + afun f; + void * v; + int i; + float flt; + char c; + short s; + short sa[2]; + char ca[4]; + } data; + /* internal data, do not modify: */ + struct attrib * next; /* next attribute in the list */ + struct attrib * nexttype; /* skip to attribute of a different type */ +} attrib; + +#define ATF_UNIQUE (1<<0) /* only one per attribute-list */ +#define ATF_PRESERVE (1<<1) /* preserve order in list. append to back */ +#define ATF_USER_DEFINED (1<<2) /* use this to make udf */ + +typedef struct attrib_type { + const char* name; + void (*initialize)(struct attrib *); + void (*finalize)(struct attrib *); + int (*age)(struct attrib *); + /* age returns 0 if the attribute needs to be removed, !=0 otherwise */ + void (*write)(const struct attrib *, const void * owner, struct storage *); + int (*read)(struct attrib *, void * owner, struct storage *); /* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */ + unsigned int flags; + /* ---- internal data, do not modify: ---- */ + struct attrib_type * nexthash; + unsigned int hashkey; +} attrib_type; + +extern void at_register(attrib_type * at); + +extern attrib * a_select(attrib * a, const void * data, boolean(*compare)(const attrib *, const void *)); +extern attrib * a_find(attrib * a, const attrib_type * at); +extern const attrib * a_findc(const attrib * a, const attrib_type * at); +extern attrib * a_add(attrib ** pa, attrib * at); +extern int a_remove(attrib ** pa, attrib * at); +extern void a_removeall(attrib ** a, const attrib_type * at); +extern attrib * a_new(const attrib_type * at); +extern void a_free(attrib * a); + +extern int a_age(attrib ** attribs); +extern int a_read(struct storage * store, attrib ** attribs, void * owner); +extern void a_write(struct storage * store, const attrib * attribs, const void * owner); + +#define DEFAULT_AGE NULL +#define DEFAULT_INIT NULL +#define DEFAULT_FINALIZE NULL +#define NO_WRITE NULL +#define NO_READ NULL + +#define AT_READ_OK 0 +#define AT_READ_FAIL -1 + +#define AT_AGE_REMOVE 0 /* remove the attribute after calling age() */ +#define AT_AGE_KEEP 1 /* keep the attribute for another turn */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/base36.c b/src/util/base36.c index a1477e34c..3c795077a 100644 --- a/src/util/base36.c +++ b/src/util/base36.c @@ -1,115 +1,115 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "base36.h" - -#include -#include -#include - -int -atoi36(const char * str) -{ - /* cannot use strtol, because invalid strings will cause crash */ - const unsigned char * s = (const unsigned char *)str; - int i = 0, sign = 1; - assert(s); - if(!(*s)) return 0; - - while(isxspace(*(unsigned char*)s)) ++s; - if (*s == '-') { - sign = -1; - ++s; - } - while(isalnum(*(unsigned char*)s)) { - if (isupper(*(unsigned char*)s)) i = i*36 + (*s)-'A' + 10; - else if (islower(*(unsigned char*)s)) i=i*36 + (*s)-'a' + 10; - else if (isdigit(*(unsigned char*)s)) i=i*36 + (*s)-'0'; - else - break; - ++s; - } - if (i<0) return 0; - return i * sign; -} - -const char* -itoab(int i, int base) -{ - static char **as = NULL; /* STATIC_RETURN: used for return, not across calls */ - char * s, * dst; - static int index = 0; /* STATIC_XCALL: used across calls */ - int neg = 0; - - if (!as) { - int j; - char * x = (char*)calloc(sizeof(char), 8*4); /* STATIC_LEAK: malloc in static variable */ - as = (char **)calloc(sizeof(char*), 4); - for (j=0;j!=4;++j) as[j] = x+j*8; - } - s = as[index]; - index = (index+1) & 3; /* quick for % 4 */ - dst = s+7; - (*dst--)=0; - if (i!=0) { - if (i<0) { - i=-i; - neg = 1; - } - while (i) { - int x = i % base; - i = i / base; - if (x<10) *(dst--) = (char)('0' + x); - else if ('a' + x - 10 == 'l') *(dst--) = 'L'; - else *(dst--) = (char)('a' + (x-10)); - } - if (neg) *(dst) = '-'; - else ++dst; - } - else *dst = '0'; - - return dst; -} - -const char* -itoa36(int i) -{ - return itoab(i, 36); -} - -const char* -itoa10(int i) -{ - return itoab(i, 10); -} - -int -i10toi36(int i) -{ - int r = 0; - while(i) { - r = r*36 + i % 10; - i = i / 10; - } - return r; -} - -#ifndef DISABLE_TESTS -#include "base36_test.c" -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "base36.h" + +#include +#include +#include + +int +atoi36(const char * str) +{ + /* cannot use strtol, because invalid strings will cause crash */ + const unsigned char * s = (const unsigned char *)str; + int i = 0, sign = 1; + assert(s); + if(!(*s)) return 0; + + while(isxspace(*(unsigned char*)s)) ++s; + if (*s == '-') { + sign = -1; + ++s; + } + while(isalnum(*(unsigned char*)s)) { + if (isupper(*(unsigned char*)s)) i = i*36 + (*s)-'A' + 10; + else if (islower(*(unsigned char*)s)) i=i*36 + (*s)-'a' + 10; + else if (isdigit(*(unsigned char*)s)) i=i*36 + (*s)-'0'; + else + break; + ++s; + } + if (i<0) return 0; + return i * sign; +} + +const char* +itoab(int i, int base) +{ + static char **as = NULL; /* STATIC_RETURN: used for return, not across calls */ + char * s, * dst; + static int index = 0; /* STATIC_XCALL: used across calls */ + int neg = 0; + + if (!as) { + int j; + char * x = (char*)calloc(sizeof(char), 8*4); /* STATIC_LEAK: malloc in static variable */ + as = (char **)calloc(sizeof(char*), 4); + for (j=0;j!=4;++j) as[j] = x+j*8; + } + s = as[index]; + index = (index+1) & 3; /* quick for % 4 */ + dst = s+7; + (*dst--)=0; + if (i!=0) { + if (i<0) { + i=-i; + neg = 1; + } + while (i) { + int x = i % base; + i = i / base; + if (x<10) *(dst--) = (char)('0' + x); + else if ('a' + x - 10 == 'l') *(dst--) = 'L'; + else *(dst--) = (char)('a' + (x-10)); + } + if (neg) *(dst) = '-'; + else ++dst; + } + else *dst = '0'; + + return dst; +} + +const char* +itoa36(int i) +{ + return itoab(i, 36); +} + +const char* +itoa10(int i) +{ + return itoab(i, 10); +} + +int +i10toi36(int i) +{ + int r = 0; + while(i) { + r = r*36 + i % 10; + i = i / 10; + } + return r; +} + +#ifndef DISABLE_TESTS +#include "base36_test.c" +#endif diff --git a/src/util/base36.h b/src/util/base36.h index 5018a0028..e11be7ec2 100644 --- a/src/util/base36.h +++ b/src/util/base36.h @@ -1,34 +1,34 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_UTIL_BASE36 -#define H_UTIL_BASE36 -#ifdef __cplusplus -extern "C" { -#endif - -extern int atoi36(const char * s); -extern const char* itoab(int i, int base); -extern const char* itoa36(int i); -extern const char* itoa10(int i); -extern int i10toi36(int i); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_UTIL_BASE36 +#define H_UTIL_BASE36 +#ifdef __cplusplus +extern "C" { +#endif + +extern int atoi36(const char * s); +extern const char* itoab(int i, int base); +extern const char* itoa36(int i); +extern const char* itoa10(int i); +extern int i10toi36(int i); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/base36_test.c b/src/util/base36_test.c index 74a43685b..c11847ad7 100644 --- a/src/util/base36_test.c +++ b/src/util/base36_test.c @@ -1,27 +1,27 @@ -#include - -static void test_atoi36(CuTest * tc) { - CuAssertIntEquals(tc, 0, atoi36("0")); - CuAssertIntEquals(tc, 666, atoi36("ii")); - CuAssertIntEquals(tc, -10, atoi36("-a")); - CuAssertIntEquals(tc, -1, atoi36("-1")); - CuAssertIntEquals(tc, -10, atoi("-10")); - CuAssertIntEquals(tc, -10, atoi("-10")); -} - -static void test_itoa36(CuTest * tc) { - CuAssertStrEquals(tc, itoa36(0), "0"); - CuAssertStrEquals(tc, itoa10(INT_MAX), "2147483647"); - CuAssertStrEquals(tc, itoab(-1, 5), "-1"); - CuAssertStrEquals(tc, itoa36(-1), "-1"); - CuAssertStrEquals(tc, itoa36(-10), "-a"); - CuAssertStrEquals(tc, itoa36(666), "ii"); -} - -CuSuite* get_base36_suite(void) -{ - CuSuite* suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, test_itoa36); - SUITE_ADD_TEST(suite, test_atoi36); - return suite; -} +#include + +static void test_atoi36(CuTest * tc) { + CuAssertIntEquals(tc, 0, atoi36("0")); + CuAssertIntEquals(tc, 666, atoi36("ii")); + CuAssertIntEquals(tc, -10, atoi36("-a")); + CuAssertIntEquals(tc, -1, atoi36("-1")); + CuAssertIntEquals(tc, -10, atoi("-10")); + CuAssertIntEquals(tc, -10, atoi("-10")); +} + +static void test_itoa36(CuTest * tc) { + CuAssertStrEquals(tc, itoa36(0), "0"); + CuAssertStrEquals(tc, itoa10(INT_MAX), "2147483647"); + CuAssertStrEquals(tc, itoab(-1, 5), "-1"); + CuAssertStrEquals(tc, itoa36(-1), "-1"); + CuAssertStrEquals(tc, itoa36(-10), "-a"); + CuAssertStrEquals(tc, itoa36(666), "ii"); +} + +CuSuite* get_base36_suite(void) +{ + CuSuite* suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_itoa36); + SUITE_ADD_TEST(suite, test_atoi36); + return suite; +} diff --git a/src/util/bsdstring.c b/src/util/bsdstring.c index 548961db2..84802c70e 100644 --- a/src/util/bsdstring.c +++ b/src/util/bsdstring.c @@ -1,88 +1,88 @@ -#include -#include -#include -#include - -#ifndef HAVE_INLINE -#include "bsdstring.h" -#endif - -INLINE_FUNCTION int -wrptr(char ** ptr, size_t * size, int bytes) -{ - assert(bytes>=0 || !"you're not using snprintf right, maybe?"); - - if (bytes==0) { - return 0; - } - if (bytes<0) { - *size = 0; - return EINVAL; - } - if (bytes<=*(int*)size) { - *ptr += bytes; - *size -= bytes; - return 0; - } - - *ptr += *size; - *size = 0; - return ENAMETOOLONG; -} - -#if !defined(HAVE_STRLCPY) -INLINE_FUNCTION size_t -strlcpy(char *dst, const char *src, size_t siz) /* copied from OpenBSD source code */ -{ - register char *d = dst; - register const char *s = src; - register size_t n = siz; - - /* Copy as many bytes as will fit */ - if (n != 0 && --n != 0) { - do { - if ((*d++ = *s++) == 0) - break; - } while (--n != 0); - } - - /* Not enough room in dst, add NUL and traverse rest of src */ - if (n == 0) { - if (siz != 0) - *d = '\0'; /* NUL-terminate dst */ - while (*s++) - ; - } - - return(s - src - 1); /* count does not include NUL */ -} - - -INLINE_FUNCTION size_t -strlcat(char * dst, const char * src, size_t siz) -{ - register char *d = dst; - register const char *s = src; - register size_t n = siz; - size_t dlen; - - /* Find the end of dst and adjust bytes left but don't go past end */ - while (*d != '\0' && n-- != 0) - d++; - dlen = d - dst; - n = siz - dlen; - - if (n == 0) - return(dlen + strlen(s)); - while (*s != '\0') { - if (n != 1) { - *d++ = *s; - n--; - } - s++; - } - *d = '\0'; - - return(dlen + (s - src)); /* count does not include NUL */ -} -#endif +#include +#include +#include +#include + +#ifndef HAVE_INLINE +#include "bsdstring.h" +#endif + +INLINE_FUNCTION int +wrptr(char ** ptr, size_t * size, int bytes) +{ + assert(bytes>=0 || !"you're not using snprintf right, maybe?"); + + if (bytes==0) { + return 0; + } + if (bytes<0) { + *size = 0; + return EINVAL; + } + if (bytes<=*(int*)size) { + *ptr += bytes; + *size -= bytes; + return 0; + } + + *ptr += *size; + *size = 0; + return ENAMETOOLONG; +} + +#if !defined(HAVE_STRLCPY) +INLINE_FUNCTION size_t +strlcpy(char *dst, const char *src, size_t siz) /* copied from OpenBSD source code */ +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} + + +INLINE_FUNCTION size_t +strlcat(char * dst, const char * src, size_t siz) +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (*d != '\0' && n-- != 0) + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} +#endif diff --git a/src/util/bsdstring.h b/src/util/bsdstring.h index e6858b9d4..ca0e94188 100644 --- a/src/util/bsdstring.h +++ b/src/util/bsdstring.h @@ -1,23 +1,23 @@ -#ifndef UTIL_BSDSTRING_H -#define UTIL_BSDSTRING_H - -#ifdef HAVE_INLINE -# include "bsdstring.c" -#else - extern size_t strlcpy(char *dst, const char *src, size_t siz); - extern size_t strlcat(char * dst, const char * src, size_t siz); - extern int wrptr(char ** ptr, size_t * size, int bytes); -#endif - -#if !defined(HAVE_STRLCPY) -# define HAVE_STRLCPY -#endif - -#define WARN_STATIC_BUFFER() log_warning(("static buffer too small in %s:%d\n", __FILE__, __LINE__)) - -#if !defined(HAVE_STRLPRINTF) -# define HAVE_STRLPRINTF -# define slprintf snprintf -#endif - -#endif +#ifndef UTIL_BSDSTRING_H +#define UTIL_BSDSTRING_H + +#ifdef HAVE_INLINE +# include "bsdstring.c" +#else + extern size_t strlcpy(char *dst, const char *src, size_t siz); + extern size_t strlcat(char * dst, const char * src, size_t siz); + extern int wrptr(char ** ptr, size_t * size, int bytes); +#endif + +#if !defined(HAVE_STRLCPY) +# define HAVE_STRLCPY +#endif + +#define WARN_STATIC_BUFFER() log_warning(("static buffer too small in %s:%d\n", __FILE__, __LINE__)) + +#if !defined(HAVE_STRLPRINTF) +# define HAVE_STRLPRINTF +# define slprintf snprintf +#endif + +#endif diff --git a/src/util/console.c b/src/util/console.c index b5237d786..62353604a 100644 --- a/src/util/console.c +++ b/src/util/console.c @@ -1,247 +1,247 @@ -#include -#include "console.h" - -/* lua includes */ -#include -#include -#include - -/* libc includes */ -#include -#include -#include -#include -#include - -/*** Lua Console ***/ -/* -** this macro defines a function to show the prompt and reads the -** next line for manual input -*/ -/* maximum length of an input line */ -#ifndef LUA_MAXINPUT -#define LUA_MAXINPUT 512 -#endif - -#if defined(LUA_USE_READLINE) -#include -#include -#include -#define default_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) -#define lua_saveline(L,idx) \ - if (lua_strlen(L,idx) > 0) /* non-empty line? */ \ - add_history(lua_tostring(L, idx)); /* add it to history */ -#define lua_freeline(L,b) ((void)L, free(b)) -#else -#define default_readline(L,b,p) \ - ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ - fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ -#define lua_saveline(L,idx) { (void)L; (void)idx; } -#define lua_freeline(L,b) { (void)L; (void)b; } -#endif - -static int (*my_readline)(lua_State *l, char *, size_t, const char *prompt) = NULL; -static int lua_readline(lua_State *l, char *b, const char *prompt) -{ - if (my_readline) { - return my_readline(l, b, LUA_MAXINPUT, prompt); - } else { - return default_readline(l, b, prompt); - } -} - -void set_readline(readline foo) { - my_readline = foo; -} - -#ifndef PROMPT -#define PROMPT "E> " -#endif - -#ifndef PROMPT2 -#define PROMPT2 ".. " -#endif - -/* BAD hack, all this action stuff. */ -#define STATESTACK_MAX 16 -static lua_State * state_stack[STATESTACK_MAX]; -int state_stack_top = -1; - -static const char *progname = "eressea"; - -static void -lstop(lua_State *l, lua_Debug *ar) -{ - (void)ar; /* unused arg. */ - lua_sethook(l, NULL, 0, 0); - luaL_error(l, "interrupted!"); -} - -static void -laction(int i) -{ - signal(i, SIG_DFL); /* if another SIGINT happens before lstop, - terminate process (default action) */ - assert(state_stack_top>=0 && state_stack_top'") == NULL) return 0; - - lua_pop(L, 1); - return 1; -} - - -static int pushline (lua_State *L, int firstline) { - char buffer[LUA_MAXINPUT]; - char *b = buffer; - size_t l; - const char *prmt = get_prompt(L, firstline); - if (lua_readline(L, b, prmt) == 0) - return 0; /* no input */ - l = strlen(b); - if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ - b[l-1] = '\0'; /* remove it */ - if (firstline && b[0] == '=') /* first line starts with `=' ? */ - lua_pushfstring(L, "return %s", b+1); /* change it to `return' */ - else - lua_pushstring(L, b); - lua_freeline(L, b); - return 1; -} - - -static int loadline (lua_State *L) { - int status; - lua_settop(L, 0); - if (!pushline(L, 1)) - return -1; /* no input */ - for (;;) { /* repeat until gets a complete line */ - status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); - if (!incomplete(L, status)) break; /* cannot try to add lines? */ - if (!pushline(L, 0)) /* no more input? */ - return -1; - lua_pushliteral(L, "\n"); /* add a new line... */ - lua_insert(L, -2); /* ...between the two lines */ - lua_concat(L, 3); /* join them */ - } - lua_saveline(L, 1); - lua_remove(L, 1); /* remove line */ - return status; -} - -static void dotty (lua_State *L) { - int status; - const char *oldprogname = progname; - progname = NULL; - while ((status = loadline(L)) != -1) { - if (status == 0) status = docall(L, 0, 0); - report(L, status); - if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ - lua_getglobal(L, "print"); - lua_insert(L, 1); - if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) - l_message(progname, lua_pushfstring(L, - "error calling " LUA_QL("print") " (%s)", - lua_tostring(L, -1))); - } - } - lua_settop(L, 0); /* clear stack */ - fputs("\n", stdout); - fflush(stdout); - progname = oldprogname; -} - -int -lua_console(lua_State * L) -{ - dotty(L); - return 0; -} - -int -lua_do(lua_State * L) -{ - int status = loadline(L); - if (status != -1) { - if (status == 0) status = docall(L, 0, 0); - report(L, status); - if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ - lua_getglobal(L, "print"); - lua_insert(L, 1); - if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) - l_message(NULL, lua_pushfstring(L, "error calling `print' (%s)", - lua_tostring(L, -1))); - } - } - lua_settop(L, 0); /* clear stack */ - return 0; -} +#include +#include "console.h" + +/* lua includes */ +#include +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +/*** Lua Console ***/ +/* +** this macro defines a function to show the prompt and reads the +** next line for manual input +*/ +/* maximum length of an input line */ +#ifndef LUA_MAXINPUT +#define LUA_MAXINPUT 512 +#endif + +#if defined(LUA_USE_READLINE) +#include +#include +#include +#define default_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) +#define lua_saveline(L,idx) \ + if (lua_strlen(L,idx) > 0) /* non-empty line? */ \ + add_history(lua_tostring(L, idx)); /* add it to history */ +#define lua_freeline(L,b) ((void)L, free(b)) +#else +#define default_readline(L,b,p) \ + ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ + fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ +#define lua_saveline(L,idx) { (void)L; (void)idx; } +#define lua_freeline(L,b) { (void)L; (void)b; } +#endif + +static int (*my_readline)(lua_State *l, char *, size_t, const char *prompt) = NULL; +static int lua_readline(lua_State *l, char *b, const char *prompt) +{ + if (my_readline) { + return my_readline(l, b, LUA_MAXINPUT, prompt); + } else { + return default_readline(l, b, prompt); + } +} + +void set_readline(readline foo) { + my_readline = foo; +} + +#ifndef PROMPT +#define PROMPT "E> " +#endif + +#ifndef PROMPT2 +#define PROMPT2 ".. " +#endif + +/* BAD hack, all this action stuff. */ +#define STATESTACK_MAX 16 +static lua_State * state_stack[STATESTACK_MAX]; +int state_stack_top = -1; + +static const char *progname = "eressea"; + +static void +lstop(lua_State *l, lua_Debug *ar) +{ + (void)ar; /* unused arg. */ + lua_sethook(l, NULL, 0, 0); + luaL_error(l, "interrupted!"); +} + +static void +laction(int i) +{ + signal(i, SIG_DFL); /* if another SIGINT happens before lstop, + terminate process (default action) */ + assert(state_stack_top>=0 && state_stack_top'") == NULL) return 0; + + lua_pop(L, 1); + return 1; +} + + +static int pushline (lua_State *L, int firstline) { + char buffer[LUA_MAXINPUT]; + char *b = buffer; + size_t l; + const char *prmt = get_prompt(L, firstline); + if (lua_readline(L, b, prmt) == 0) + return 0; /* no input */ + l = strlen(b); + if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ + b[l-1] = '\0'; /* remove it */ + if (firstline && b[0] == '=') /* first line starts with `=' ? */ + lua_pushfstring(L, "return %s", b+1); /* change it to `return' */ + else + lua_pushstring(L, b); + lua_freeline(L, b); + return 1; +} + + +static int loadline (lua_State *L) { + int status; + lua_settop(L, 0); + if (!pushline(L, 1)) + return -1; /* no input */ + for (;;) { /* repeat until gets a complete line */ + status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); + if (!incomplete(L, status)) break; /* cannot try to add lines? */ + if (!pushline(L, 0)) /* no more input? */ + return -1; + lua_pushliteral(L, "\n"); /* add a new line... */ + lua_insert(L, -2); /* ...between the two lines */ + lua_concat(L, 3); /* join them */ + } + lua_saveline(L, 1); + lua_remove(L, 1); /* remove line */ + return status; +} + +static void dotty (lua_State *L) { + int status; + const char *oldprogname = progname; + progname = NULL; + while ((status = loadline(L)) != -1) { + if (status == 0) status = docall(L, 0, 0); + report(L, status); + if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ + lua_getglobal(L, "print"); + lua_insert(L, 1); + if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) + l_message(progname, lua_pushfstring(L, + "error calling " LUA_QL("print") " (%s)", + lua_tostring(L, -1))); + } + } + lua_settop(L, 0); /* clear stack */ + fputs("\n", stdout); + fflush(stdout); + progname = oldprogname; +} + +int +lua_console(lua_State * L) +{ + dotty(L); + return 0; +} + +int +lua_do(lua_State * L) +{ + int status = loadline(L); + if (status != -1) { + if (status == 0) status = docall(L, 0, 0); + report(L, status); + if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ + lua_getglobal(L, "print"); + lua_insert(L, 1); + if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) + l_message(NULL, lua_pushfstring(L, "error calling `print' (%s)", + lua_tostring(L, -1))); + } + } + lua_settop(L, 0); /* clear stack */ + return 0; +} diff --git a/src/util/console.h b/src/util/console.h index 2249927dd..d5821135b 100644 --- a/src/util/console.h +++ b/src/util/console.h @@ -1,37 +1,37 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_LUA_CONSOLE -#define H_LUA_CONSOLE -#ifdef __cplusplus -extern "C" { -#endif - - struct lua_State; - - extern int lua_console(struct lua_State * L); - extern int lua_do(struct lua_State * L); - - typedef int (*readline)(struct lua_State *, char *, size_t, const char *); - extern void set_readline(readline foo); - -#ifdef __cplusplus -} -#endif - -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_LUA_CONSOLE +#define H_LUA_CONSOLE +#ifdef __cplusplus +extern "C" { +#endif + + struct lua_State; + + extern int lua_console(struct lua_State * L); + extern int lua_do(struct lua_State * L); + + typedef int (*readline)(struct lua_State *, char *, size_t, const char *); + extern void set_readline(readline foo); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/util/crmessage.c b/src/util/crmessage.c index 6d10406fb..6cb1ba349 100644 --- a/src/util/crmessage.c +++ b/src/util/crmessage.c @@ -1,159 +1,159 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - -*/ - -#include -#include "crmessage.h" - -#include "message.h" -#include "goodies.h" -#include "log.h" - -#include -#include -#include -#include - -/** type to string conversion **/ -typedef struct tsf_list { - struct tsf_list * next; - const char * name; - tostring_f fun; -} tsf_list; - -static tsf_list * tostringfs; - -static tostring_f -tsf_find(const char * name) -{ - if (name!=NULL) { - tsf_list * tsf; - for (tsf=tostringfs;tsf;tsf=tsf->next) { - if (!strcmp(tsf->name, name)) return tsf->fun; - } - } - return NULL; -} - -void -tsf_register(const char * name, tostring_f fun) -{ - tsf_list * tsf; - for (tsf=tostringfs;tsf;tsf=tsf->next) { - if (!strcmp(tsf->name, name)) break; - } - if (tsf==NULL) { - tsf = malloc(sizeof(tsf_list)); - tsf->fun = fun; - tsf->name = name; - tsf->next = tostringfs; - tostringfs = tsf; - } -} - -/** crmesssage **/ -typedef struct crmessage_type { - const struct message_type * mtype; - tostring_f * renderers; - struct crmessage_type * next; -} crmessage_type; - -#define CRMAXHASH 63 -static crmessage_type * crtypes[CRMAXHASH]; - -static crmessage_type * -crt_find(const struct message_type * mtype) -{ - unsigned int hash = hashstring(mtype->name) % CRMAXHASH; - crmessage_type * found = NULL; - crmessage_type * type = crtypes[hash]; - while (type) { - if (type->mtype==mtype) found = type; - type = type->next; - } - return found; -} - -void -crt_register(const struct message_type * mtype) -{ - unsigned int hash = hashstring(mtype->name) % CRMAXHASH; - crmessage_type * crt = crtypes[hash]; - while (crt && crt->mtype!=mtype) { - crt = crt->next; - } - if (!crt) { - int i; - crt = malloc(sizeof(crmessage_type)); - crt->mtype = mtype; - crt->next = crtypes[hash]; - crtypes[hash] = crt; - if(mtype->nparameters > 0) { - crt->renderers = malloc(sizeof(tostring_f)*mtype->nparameters); - } else { - crt->renderers = NULL; - } - - /* can be scrapped for memory vs. speed */ - for (i=0;i!=mtype->nparameters;++i) { - crt->renderers[i] = tsf_find(mtype->types[i]->name); - } - } -} - -int -cr_render(const message * msg, char * buffer, const void * userdata) -{ - int i; - char * c = buffer; - struct crmessage_type * crt = crt_find(msg->type); - - if (crt==NULL) return -1; - for (i=0;i!=msg->type->nparameters;++i) { - if (crt->renderers[i]==NULL) { - log_error(("No renderer for argument %s:%s of \"%s\"\n", - msg->type->pnames[i], msg->type->types[i]->name, msg->type->name)); - continue; /* strcpy(c, (const char*)msg->locale_string(u->faction->locale, parameters[i])); */ - } else { - if (crt->renderers[i](msg->parameters[i], c, userdata)!=0) continue; - } - c += strlen(c); - sprintf(c, ";%s\n", msg->type->pnames[i]); - c += strlen(c); - } - return 0; -} - -int -cr_string(variant var, char * buffer, const void * userdata) -{ - sprintf(buffer, "\"%s\"", (const char *)var.v); - unused(userdata); - return 0; -} - -int -cr_int(variant var, char * buffer, const void * userdata) -{ - sprintf(buffer, "%d", var.i); - unused(userdata); - return 0; -} - -int -cr_ignore(variant var, char * buffer, const void * userdata) -{ - unused(var); - unused(buffer); - unused(userdata); - return -1; -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + +*/ + +#include +#include "crmessage.h" + +#include "message.h" +#include "goodies.h" +#include "log.h" + +#include +#include +#include +#include + +/** type to string conversion **/ +typedef struct tsf_list { + struct tsf_list * next; + const char * name; + tostring_f fun; +} tsf_list; + +static tsf_list * tostringfs; + +static tostring_f +tsf_find(const char * name) +{ + if (name!=NULL) { + tsf_list * tsf; + for (tsf=tostringfs;tsf;tsf=tsf->next) { + if (!strcmp(tsf->name, name)) return tsf->fun; + } + } + return NULL; +} + +void +tsf_register(const char * name, tostring_f fun) +{ + tsf_list * tsf; + for (tsf=tostringfs;tsf;tsf=tsf->next) { + if (!strcmp(tsf->name, name)) break; + } + if (tsf==NULL) { + tsf = malloc(sizeof(tsf_list)); + tsf->fun = fun; + tsf->name = name; + tsf->next = tostringfs; + tostringfs = tsf; + } +} + +/** crmesssage **/ +typedef struct crmessage_type { + const struct message_type * mtype; + tostring_f * renderers; + struct crmessage_type * next; +} crmessage_type; + +#define CRMAXHASH 63 +static crmessage_type * crtypes[CRMAXHASH]; + +static crmessage_type * +crt_find(const struct message_type * mtype) +{ + unsigned int hash = hashstring(mtype->name) % CRMAXHASH; + crmessage_type * found = NULL; + crmessage_type * type = crtypes[hash]; + while (type) { + if (type->mtype==mtype) found = type; + type = type->next; + } + return found; +} + +void +crt_register(const struct message_type * mtype) +{ + unsigned int hash = hashstring(mtype->name) % CRMAXHASH; + crmessage_type * crt = crtypes[hash]; + while (crt && crt->mtype!=mtype) { + crt = crt->next; + } + if (!crt) { + int i; + crt = malloc(sizeof(crmessage_type)); + crt->mtype = mtype; + crt->next = crtypes[hash]; + crtypes[hash] = crt; + if(mtype->nparameters > 0) { + crt->renderers = malloc(sizeof(tostring_f)*mtype->nparameters); + } else { + crt->renderers = NULL; + } + + /* can be scrapped for memory vs. speed */ + for (i=0;i!=mtype->nparameters;++i) { + crt->renderers[i] = tsf_find(mtype->types[i]->name); + } + } +} + +int +cr_render(const message * msg, char * buffer, const void * userdata) +{ + int i; + char * c = buffer; + struct crmessage_type * crt = crt_find(msg->type); + + if (crt==NULL) return -1; + for (i=0;i!=msg->type->nparameters;++i) { + if (crt->renderers[i]==NULL) { + log_error(("No renderer for argument %s:%s of \"%s\"\n", + msg->type->pnames[i], msg->type->types[i]->name, msg->type->name)); + continue; /* strcpy(c, (const char*)msg->locale_string(u->faction->locale, parameters[i])); */ + } else { + if (crt->renderers[i](msg->parameters[i], c, userdata)!=0) continue; + } + c += strlen(c); + sprintf(c, ";%s\n", msg->type->pnames[i]); + c += strlen(c); + } + return 0; +} + +int +cr_string(variant var, char * buffer, const void * userdata) +{ + sprintf(buffer, "\"%s\"", (const char *)var.v); + unused(userdata); + return 0; +} + +int +cr_int(variant var, char * buffer, const void * userdata) +{ + sprintf(buffer, "%d", var.i); + unused(userdata); + return 0; +} + +int +cr_ignore(variant var, char * buffer, const void * userdata) +{ + unused(var); + unused(buffer); + unused(userdata); + return -1; +} diff --git a/src/util/crmessage.h b/src/util/crmessage.h index 6b0583d18..7861aaffe 100644 --- a/src/util/crmessage.h +++ b/src/util/crmessage.h @@ -1,39 +1,39 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_UTIL_CRMESSAGE -#define H_UTIL_CRMESSAGE - -#include "variant.h" -#ifdef __cplusplus -extern "C" { -#endif - -struct locale; -struct message; -struct message_type; - -typedef int (*tostring_f)(variant data, char * buffer, const void * userdata); -extern void tsf_register(const char * name, tostring_f fun); - /* registers a new type->string-function */ - -extern int cr_string(variant v, char * buffer, const void * userdata); -extern int cr_int(variant v, char * buffer, const void * userdata); -extern int cr_ignore(variant v, char * buffer, const void * userdata); - -extern void crt_register(const struct message_type * mtype); -extern int cr_render(const struct message * msg, char * buffer, const void * userdata); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_UTIL_CRMESSAGE +#define H_UTIL_CRMESSAGE + +#include "variant.h" +#ifdef __cplusplus +extern "C" { +#endif + +struct locale; +struct message; +struct message_type; + +typedef int (*tostring_f)(variant data, char * buffer, const void * userdata); +extern void tsf_register(const char * name, tostring_f fun); + /* registers a new type->string-function */ + +extern int cr_string(variant v, char * buffer, const void * userdata); +extern int cr_int(variant v, char * buffer, const void * userdata); +extern int cr_ignore(variant v, char * buffer, const void * userdata); + +extern void crt_register(const struct message_type * mtype); +extern int cr_render(const struct message * msg, char * buffer, const void * userdata); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/cvector.c b/src/util/cvector.c index fbbd10f8c..27c395908 100644 --- a/src/util/cvector.c +++ b/src/util/cvector.c @@ -1,97 +1,97 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "cvector.h" -#include "rng.h" - -#include -#include -#include -#include - -void -cv_init(cvector * cv) -{ - cv->begin = 0; - cv->end = 0; - cv->space = 0; -} - -cvector * -cv_kill(cvector * cv) -{ - if (cv->begin) free(cv->begin); - cv_init(cv); - return cv; -} - -size_t -cv_size(cvector * cv) -{ - return cv->end - cv->begin; -} - -void -cv_reserve(cvector * cv, size_t size) -{ - size_t count = cv->end - cv->begin; - cv->begin = realloc(cv->begin, size * sizeof(void *)); - - cv->space = size; - cv->end = cv->begin + count; -} - -void -cv_pushback(cvector * cv, void *u) -{ - if (cv->space == cv_size(cv)) - cv_reserve(cv, cv->space ? cv->space * 2 : 2); - *(cv->end++) = u; -} - -int -__cv_scramblecmp(const void *p1, const void *p2) -{ - return *((long *) p1) - *((long *) p2); -} - -#define addptr(p,i) ((void *)(((char *)p) + i)) - -/** randomly shuffle an array - * for correctness, see Donald E. Knuth, The Art of Computer Programming - */ -static void -__cv_scramble(void *v1, size_t n, size_t width) -{ - size_t i; - void * temp = malloc(width); - for (i=0;i!=n;++i) { - size_t j = i + (rng_int() % (n-i)); - memcpy(temp, addptr(v1, i*width), width); - memcpy(addptr(v1, i*width), addptr(v1, j*width), width); - memcpy(addptr(v1, j*width), temp, width); - } - free(temp); -} - -void -v_scramble(void **begin, void **end) -{ - __cv_scramble(begin, end - begin, sizeof(void *)); -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "cvector.h" +#include "rng.h" + +#include +#include +#include +#include + +void +cv_init(cvector * cv) +{ + cv->begin = 0; + cv->end = 0; + cv->space = 0; +} + +cvector * +cv_kill(cvector * cv) +{ + if (cv->begin) free(cv->begin); + cv_init(cv); + return cv; +} + +size_t +cv_size(cvector * cv) +{ + return cv->end - cv->begin; +} + +void +cv_reserve(cvector * cv, size_t size) +{ + size_t count = cv->end - cv->begin; + cv->begin = realloc(cv->begin, size * sizeof(void *)); + + cv->space = size; + cv->end = cv->begin + count; +} + +void +cv_pushback(cvector * cv, void *u) +{ + if (cv->space == cv_size(cv)) + cv_reserve(cv, cv->space ? cv->space * 2 : 2); + *(cv->end++) = u; +} + +int +__cv_scramblecmp(const void *p1, const void *p2) +{ + return *((long *) p1) - *((long *) p2); +} + +#define addptr(p,i) ((void *)(((char *)p) + i)) + +/** randomly shuffle an array + * for correctness, see Donald E. Knuth, The Art of Computer Programming + */ +static void +__cv_scramble(void *v1, size_t n, size_t width) +{ + size_t i; + void * temp = malloc(width); + for (i=0;i!=n;++i) { + size_t j = i + (rng_int() % (n-i)); + memcpy(temp, addptr(v1, i*width), width); + memcpy(addptr(v1, i*width), addptr(v1, j*width), width); + memcpy(addptr(v1, j*width), temp, width); + } + free(temp); +} + +void +v_scramble(void **begin, void **end) +{ + __cv_scramble(begin, end - begin, sizeof(void *)); +} diff --git a/src/util/cvector.h b/src/util/cvector.h index 6b647e580..c0e50944d 100644 --- a/src/util/cvector.h +++ b/src/util/cvector.h @@ -1,61 +1,61 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef CVECTOR_H -#define CVECTOR_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WIN32 -#ifndef __cdecl -#define __cdecl -#endif -#endif - -#include -typedef struct cvector cvector; - -struct cvector { - void **begin; - void **end; - size_t space; -}; - -typedef int (__cdecl * v_sort_fun) (const void *, const void *); - -void cv_init(cvector * cv); -cvector *cv_kill(cvector * cv); -size_t cv_size(cvector * cv); -void cv_reserve(cvector * cv, size_t size); -void cv_pushback(cvector * cv, void *u); -void v_scramble(void **begin, void **end); - -#define cv_remove(c, i) { void** x = v_find((c)->begin, (c)->end, (i)); if (x) { *x = *(c)->end; (c)->end--; } } -#define cv_foreach(item, vector) \ -{ \ - void **iterator; \ - for (iterator = (vector).begin; iterator<(vector).end; ++iterator) \ - { \ - (item) = *iterator; -#define cv_next(item) } } - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef CVECTOR_H +#define CVECTOR_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WIN32 +#ifndef __cdecl +#define __cdecl +#endif +#endif + +#include +typedef struct cvector cvector; + +struct cvector { + void **begin; + void **end; + size_t space; +}; + +typedef int (__cdecl * v_sort_fun) (const void *, const void *); + +void cv_init(cvector * cv); +cvector *cv_kill(cvector * cv); +size_t cv_size(cvector * cv); +void cv_reserve(cvector * cv, size_t size); +void cv_pushback(cvector * cv, void *u); +void v_scramble(void **begin, void **end); + +#define cv_remove(c, i) { void** x = v_find((c)->begin, (c)->end, (i)); if (x) { *x = *(c)->end; (c)->end--; } } +#define cv_foreach(item, vector) \ +{ \ + void **iterator; \ + for (iterator = (vector).begin; iterator<(vector).end; ++iterator) \ + { \ + (item) = *iterator; +#define cv_next(item) } } + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/dice.c b/src/util/dice.c index 8e9fc5df5..bf8593d0c 100644 --- a/src/util/dice.c +++ b/src/util/dice.c @@ -1,97 +1,97 @@ -/* vi: set ts=2: - * - * - * Eressea PB(E)M host Copyright (C) 1998 - * Enno Rehling (rehling@usa.net) - * Christian Schlittchen (corwin@amber.kn-bremen.de) - * Katja Zedel (katze@felidae.kn-bremen.de) - * Henning Peters (faroul@beyond.kn-bremen.de) - * - * based on: - * - * Atlantis v1.0 13 September 1993 Copyright 1993 by Russell Wallace - * Atlantis v1.7 Copyright 1996 by Alex Schröder - * - * This program may not be used, modified or distributed. It may not be - * sold or used commercially without prior written permission from the - * authors. - */ - -#include -#include "rng.h" - -#include -#include -#include - -/** rolls a number of n-sided dice. - * Usage: 3d6-3d4+5 = dice(3,6)-dice(3,4)+5 */ -int -dice(int count, int value) -{ - int d = 0, c; - - if (value<=0) return 0; /* (enno) %0 geht nicht. echt wahr. */ - if (count >= 0) - for (c = count; c > 0; c--) - d += rng_int() % value + 1; - else - for (c = count; c < 0; c++) - d -= rng_int() % value + 1; - - return d; -} - -static int -term_eval(const char **sptr) -{ - const char *c = *sptr; - int m = 0, d = 0, k = 0, term = 1, multi = 1; - int state = 1; - - for (;;) { - if (isdigit(*(unsigned char*)c)) { - k = k*10+(*c-'0'); - } - else if (*c=='+' || *c=='-' || *c==0 || *c=='*' || *c==')' || *c=='(') { - if (state==1) /* konstante k addieren */ - m+=k*multi; - else if (state==2) { /* dDk */ - int i; - if (k == 0) k = 6; /* 3d == 3d6 */ - for (i=0;i!=d;++i) m += (1 + rng_int() % k)*multi; - } - else assert(!"dice_rand: illegal token"); - if (*c=='*') { - term *= m; - m = 0; - } - k = d = 0; - state = 1; - multi = (*c=='-')?-1:1; - - if (*c=='(') { - ++c; - k = term_eval(&c); - } - else if (*c==0 || *c==')') { - break; - } - } else if (*c=='d' || *c=='D') { - if (k==0) k = 1; /* d9 == 1d9 */ - assert(state==1 || !"dice_rand: illegal token"); - d = k; - k = 0; - state=2; - } - c++; - } - *sptr = c; - return m*term; -} - -int -dice_rand(const char *s) -{ - return term_eval(&s); -} +/* vi: set ts=2: + * + * + * Eressea PB(E)M host Copyright (C) 1998 + * Enno Rehling (rehling@usa.net) + * Christian Schlittchen (corwin@amber.kn-bremen.de) + * Katja Zedel (katze@felidae.kn-bremen.de) + * Henning Peters (faroul@beyond.kn-bremen.de) + * + * based on: + * + * Atlantis v1.0 13 September 1993 Copyright 1993 by Russell Wallace + * Atlantis v1.7 Copyright 1996 by Alex Schröder + * + * This program may not be used, modified or distributed. It may not be + * sold or used commercially without prior written permission from the + * authors. + */ + +#include +#include "rng.h" + +#include +#include +#include + +/** rolls a number of n-sided dice. + * Usage: 3d6-3d4+5 = dice(3,6)-dice(3,4)+5 */ +int +dice(int count, int value) +{ + int d = 0, c; + + if (value<=0) return 0; /* (enno) %0 geht nicht. echt wahr. */ + if (count >= 0) + for (c = count; c > 0; c--) + d += rng_int() % value + 1; + else + for (c = count; c < 0; c++) + d -= rng_int() % value + 1; + + return d; +} + +static int +term_eval(const char **sptr) +{ + const char *c = *sptr; + int m = 0, d = 0, k = 0, term = 1, multi = 1; + int state = 1; + + for (;;) { + if (isdigit(*(unsigned char*)c)) { + k = k*10+(*c-'0'); + } + else if (*c=='+' || *c=='-' || *c==0 || *c=='*' || *c==')' || *c=='(') { + if (state==1) /* konstante k addieren */ + m+=k*multi; + else if (state==2) { /* dDk */ + int i; + if (k == 0) k = 6; /* 3d == 3d6 */ + for (i=0;i!=d;++i) m += (1 + rng_int() % k)*multi; + } + else assert(!"dice_rand: illegal token"); + if (*c=='*') { + term *= m; + m = 0; + } + k = d = 0; + state = 1; + multi = (*c=='-')?-1:1; + + if (*c=='(') { + ++c; + k = term_eval(&c); + } + else if (*c==0 || *c==')') { + break; + } + } else if (*c=='d' || *c=='D') { + if (k==0) k = 1; /* d9 == 1d9 */ + assert(state==1 || !"dice_rand: illegal token"); + d = k; + k = 0; + state=2; + } + c++; + } + *sptr = c; + return m*term; +} + +int +dice_rand(const char *s) +{ + return term_eval(&s); +} diff --git a/src/util/encoding.h b/src/util/encoding.h index f2cc22d5f..0fe33d4ef 100644 --- a/src/util/encoding.h +++ b/src/util/encoding.h @@ -1,19 +1,19 @@ -#ifndef ENCODING_H -#define ENCODING_H -#ifdef __cplusplus -extern "C" { -#endif - -enum { - ENCODING_ERROR = -1, - ENCODING_NONE = 0, - ENCODING_8859_1 = 1, - ENCODING_UTF8 = 10 -}; - -int get_encoding_by_name(const char * name); - -#ifdef __cplusplus -} -#endif -#endif +#ifndef ENCODING_H +#define ENCODING_H +#ifdef __cplusplus +extern "C" { +#endif + +enum { + ENCODING_ERROR = -1, + ENCODING_NONE = 0, + ENCODING_8859_1 = 1, + ENCODING_UTF8 = 10 +}; + +int get_encoding_by_name(const char * name); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/event.c b/src/util/event.c index 977af7ffe..50f652ec2 100644 --- a/src/util/event.c +++ b/src/util/event.c @@ -1,270 +1,270 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "event.h" - -/* util includes */ -#include "attrib.h" -#include "log.h" -#include "storage.h" - -/* libc includes */ -#include -#include -#include -#include - -void -write_triggers(struct storage * store, const trigger * t) -{ - while (t) { - if (t->type->write) { - store->w_tok(store, t->type->name); - t->type->write(t, store); - } - t = t->next; - } - store->w_tok(store, "end"); -} - -int -read_triggers(struct storage * store, trigger ** tp) -{ - for (;;) { - trigger_type * ttype; - char zText[128]; - - store->r_tok_buf(store, zText, sizeof(zText)); - if (!strcmp(zText, "end")) break; - ttype = tt_find(zText); - assert(ttype || !"unknown trigger-type"); - *tp = t_new(ttype); - if (ttype->read) { - int i = ttype->read(*tp, store); - switch (i) { - case AT_READ_OK: - tp = &(*tp)->next; - break; - case AT_READ_FAIL: - t_free(*tp); - *tp = NULL; - break; - default: - assert(!"invalid return value"); - break; - } - } - } - return 0; -} - -trigger * -t_new(trigger_type * ttype) -{ - trigger * t = calloc(sizeof(trigger), 1); - t->type=ttype; - if (ttype->initialize) ttype->initialize(t); - return t; -} - -void -t_free(trigger * t) -{ - if (t->type->finalize) t->type->finalize(t); -} - -void -free_triggers(trigger * triggers) -{ - while (triggers) { - trigger * t = triggers; - triggers = t->next; - t_free(t); - } -} - -int -handle_triggers(trigger ** triggers, void * param) -{ - trigger ** tp = triggers; - while (*tp) { - trigger * t = *tp; - if (t->type->handle(t, param)!=0) { - *tp=t->next; - t_free(t); - } - else tp=&t->next; - } - return (*triggers!=NULL); -} - -/*** - ** at_eventhandler - **/ - -typedef struct handler_info { - char * event; - trigger * triggers; -} handler_info; - -static void -init_handler(attrib * a) { - a->data.v = calloc(sizeof(handler_info), 1); -} - -static void -free_handler(attrib * a) { - handler_info *hi = (handler_info*)a->data.v; - free_triggers(hi->triggers); - free(hi->event); - free(hi); -} - -static void -write_handler(const attrib * a, const void * owner, struct storage * store) -{ - handler_info *hi = (handler_info*)a->data.v; - store->w_tok(store, hi->event); - write_triggers(store, hi->triggers); -} - -static int -read_handler(attrib * a, void * owner, struct storage * store) -{ - char zText[128]; - handler_info *hi = (handler_info*)a->data.v; - - store->r_tok_buf(store, zText, sizeof(zText)); - hi->event = strdup(zText); - read_triggers(store, &hi->triggers); - if (hi->triggers!=NULL) { - return AT_READ_OK; - } - return AT_READ_FAIL; -} - -attrib_type at_eventhandler = { - "eventhandler", - init_handler, - free_handler, - NULL, - write_handler, - read_handler -}; - -struct trigger ** -get_triggers(struct attrib * ap, const char * eventname) -{ - handler_info * td = NULL; - attrib * a = a_find(ap, &at_eventhandler); - while (a!=NULL && a->type==&at_eventhandler) { - td = (handler_info *)a->data.v; - if (strcmp(td->event, eventname)==0) { - return &td->triggers; - } - a = a->next; - } - return NULL; -} - -void -add_trigger(struct attrib ** ap, const char * eventname, struct trigger * t) -{ - trigger ** tp; - handler_info * td = NULL; - attrib * a = a_find(*ap, &at_eventhandler); - assert(t->next==NULL); - while (a!=NULL && a->type==&at_eventhandler) { - td = (handler_info *)a->data.v; - if (!strcmp(td->event, eventname)) { - break; - } - a = a->next; - } - if (a==NULL || a->type!=&at_eventhandler) { - a = a_add(ap, a_new(&at_eventhandler)); - td = (handler_info *)a->data.v; - td->event = strdup(eventname); - } - tp = &td->triggers; - while (*tp) tp=&(*tp)->next; - *tp = t; -} - -void -handle_event(attrib * attribs, const char * eventname, void * data) -{ - while (attribs) { - if (attribs->type==&at_eventhandler) break; - attribs = attribs->nexttype; - } - while (attribs && attribs->type==&at_eventhandler) { - handler_info * tl = (handler_info*)attribs->data.v; - if (!strcmp(tl->event, eventname)) { - handler_info * tl = (handler_info*)attribs->data.v; - handle_triggers(&tl->triggers, data); - break; - } - attribs = attribs->next; - } -} - -void -t_add(struct trigger ** tlist, struct trigger * t) -{ - while (*tlist) tlist = &(*tlist)->next; - *tlist = t; -} - -static trigger_type * triggertypes; - -void -tt_register(trigger_type * tt) -{ - tt->next = triggertypes; - triggertypes = tt; -} - -trigger_type * -tt_find(const char * name) -{ - trigger_type * tt = triggertypes; - while (tt && strcmp(tt->name, name)) tt = tt->next; - return tt; -} - -void -remove_triggers(struct attrib ** ap, const char * eventname, const trigger_type * tt) -{ - trigger ** tp = get_triggers(*ap, eventname); - if(tp == NULL) return; - while (*tp) { - /* first, remove all gate-triggers */ - trigger * t = *tp; - if (t->type == tt) { - *tp = t->next; - t_free(t); - } else tp = &t->next; - } -} - -/*** - ** default events - **/ - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "event.h" + +/* util includes */ +#include "attrib.h" +#include "log.h" +#include "storage.h" + +/* libc includes */ +#include +#include +#include +#include + +void +write_triggers(struct storage * store, const trigger * t) +{ + while (t) { + if (t->type->write) { + store->w_tok(store, t->type->name); + t->type->write(t, store); + } + t = t->next; + } + store->w_tok(store, "end"); +} + +int +read_triggers(struct storage * store, trigger ** tp) +{ + for (;;) { + trigger_type * ttype; + char zText[128]; + + store->r_tok_buf(store, zText, sizeof(zText)); + if (!strcmp(zText, "end")) break; + ttype = tt_find(zText); + assert(ttype || !"unknown trigger-type"); + *tp = t_new(ttype); + if (ttype->read) { + int i = ttype->read(*tp, store); + switch (i) { + case AT_READ_OK: + tp = &(*tp)->next; + break; + case AT_READ_FAIL: + t_free(*tp); + *tp = NULL; + break; + default: + assert(!"invalid return value"); + break; + } + } + } + return 0; +} + +trigger * +t_new(trigger_type * ttype) +{ + trigger * t = calloc(sizeof(trigger), 1); + t->type=ttype; + if (ttype->initialize) ttype->initialize(t); + return t; +} + +void +t_free(trigger * t) +{ + if (t->type->finalize) t->type->finalize(t); +} + +void +free_triggers(trigger * triggers) +{ + while (triggers) { + trigger * t = triggers; + triggers = t->next; + t_free(t); + } +} + +int +handle_triggers(trigger ** triggers, void * param) +{ + trigger ** tp = triggers; + while (*tp) { + trigger * t = *tp; + if (t->type->handle(t, param)!=0) { + *tp=t->next; + t_free(t); + } + else tp=&t->next; + } + return (*triggers!=NULL); +} + +/*** + ** at_eventhandler + **/ + +typedef struct handler_info { + char * event; + trigger * triggers; +} handler_info; + +static void +init_handler(attrib * a) { + a->data.v = calloc(sizeof(handler_info), 1); +} + +static void +free_handler(attrib * a) { + handler_info *hi = (handler_info*)a->data.v; + free_triggers(hi->triggers); + free(hi->event); + free(hi); +} + +static void +write_handler(const attrib * a, const void * owner, struct storage * store) +{ + handler_info *hi = (handler_info*)a->data.v; + store->w_tok(store, hi->event); + write_triggers(store, hi->triggers); +} + +static int +read_handler(attrib * a, void * owner, struct storage * store) +{ + char zText[128]; + handler_info *hi = (handler_info*)a->data.v; + + store->r_tok_buf(store, zText, sizeof(zText)); + hi->event = strdup(zText); + read_triggers(store, &hi->triggers); + if (hi->triggers!=NULL) { + return AT_READ_OK; + } + return AT_READ_FAIL; +} + +attrib_type at_eventhandler = { + "eventhandler", + init_handler, + free_handler, + NULL, + write_handler, + read_handler +}; + +struct trigger ** +get_triggers(struct attrib * ap, const char * eventname) +{ + handler_info * td = NULL; + attrib * a = a_find(ap, &at_eventhandler); + while (a!=NULL && a->type==&at_eventhandler) { + td = (handler_info *)a->data.v; + if (strcmp(td->event, eventname)==0) { + return &td->triggers; + } + a = a->next; + } + return NULL; +} + +void +add_trigger(struct attrib ** ap, const char * eventname, struct trigger * t) +{ + trigger ** tp; + handler_info * td = NULL; + attrib * a = a_find(*ap, &at_eventhandler); + assert(t->next==NULL); + while (a!=NULL && a->type==&at_eventhandler) { + td = (handler_info *)a->data.v; + if (!strcmp(td->event, eventname)) { + break; + } + a = a->next; + } + if (a==NULL || a->type!=&at_eventhandler) { + a = a_add(ap, a_new(&at_eventhandler)); + td = (handler_info *)a->data.v; + td->event = strdup(eventname); + } + tp = &td->triggers; + while (*tp) tp=&(*tp)->next; + *tp = t; +} + +void +handle_event(attrib * attribs, const char * eventname, void * data) +{ + while (attribs) { + if (attribs->type==&at_eventhandler) break; + attribs = attribs->nexttype; + } + while (attribs && attribs->type==&at_eventhandler) { + handler_info * tl = (handler_info*)attribs->data.v; + if (!strcmp(tl->event, eventname)) { + handler_info * tl = (handler_info*)attribs->data.v; + handle_triggers(&tl->triggers, data); + break; + } + attribs = attribs->next; + } +} + +void +t_add(struct trigger ** tlist, struct trigger * t) +{ + while (*tlist) tlist = &(*tlist)->next; + *tlist = t; +} + +static trigger_type * triggertypes; + +void +tt_register(trigger_type * tt) +{ + tt->next = triggertypes; + triggertypes = tt; +} + +trigger_type * +tt_find(const char * name) +{ + trigger_type * tt = triggertypes; + while (tt && strcmp(tt->name, name)) tt = tt->next; + return tt; +} + +void +remove_triggers(struct attrib ** ap, const char * eventname, const trigger_type * tt) +{ + trigger ** tp = get_triggers(*ap, eventname); + if(tp == NULL) return; + while (*tp) { + /* first, remove all gate-triggers */ + trigger * t = *tp; + if (t->type == tt) { + *tp = t->next; + t_free(t); + } else tp = &t->next; + } +} + +/*** + ** default events + **/ + diff --git a/src/util/event.h b/src/util/event.h index 6c5566c34..23f272952 100644 --- a/src/util/event.h +++ b/src/util/event.h @@ -1,80 +1,80 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef EVENT_H -#define EVENT_H -#ifdef __cplusplus -extern "C" { -#endif - -#include "variant.h" - -struct attrib; -struct trigger; -struct storage; - -typedef struct trigger_type { - const char * name; - void (*initialize)(struct trigger *); - void (*finalize)(struct trigger *); - int (*handle)(struct trigger *, void *); - void (*write)(const struct trigger *, struct storage * store); - int (*read)(struct trigger *, struct storage * store); - - struct trigger_type * next; -} trigger_type; - -extern trigger_type * tt_find(const char * name); -extern void tt_register(trigger_type * ttype); - -typedef struct trigger { - struct trigger_type * type; - struct trigger * next; - - variant data; -} trigger; - -typedef struct event_arg { - const char * type; - variant data; -} event_arg; - -extern trigger * t_new(trigger_type * ttype); -extern void t_free(trigger * t); -extern void t_add(trigger ** tlist, trigger * t); -/** add and handle triggers **/ - -/* add a trigger to a list of attributes */ -extern void add_trigger(struct attrib ** ap, const char * eventname, struct trigger * t); -extern void remove_triggers(struct attrib ** ap, const char * eventname, const trigger_type * tt); -extern struct trigger ** get_triggers(struct attrib * ap, const char * eventname); -/* calls handle() for each of these. e.g. used in timeout */ -extern void handle_event(struct attrib * attribs, const char * eventname, void * data); - -/* functions for making complex triggers: */ -extern void free_triggers(trigger * triggers); /* release all these triggers */ -extern void write_triggers(struct storage * store, const trigger * t); -extern int read_triggers(struct storage * store, trigger ** tp); -extern int handle_triggers(trigger ** triggers, void * data); - -extern struct attrib_type at_eventhandler; - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef EVENT_H +#define EVENT_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "variant.h" + +struct attrib; +struct trigger; +struct storage; + +typedef struct trigger_type { + const char * name; + void (*initialize)(struct trigger *); + void (*finalize)(struct trigger *); + int (*handle)(struct trigger *, void *); + void (*write)(const struct trigger *, struct storage * store); + int (*read)(struct trigger *, struct storage * store); + + struct trigger_type * next; +} trigger_type; + +extern trigger_type * tt_find(const char * name); +extern void tt_register(trigger_type * ttype); + +typedef struct trigger { + struct trigger_type * type; + struct trigger * next; + + variant data; +} trigger; + +typedef struct event_arg { + const char * type; + variant data; +} event_arg; + +extern trigger * t_new(trigger_type * ttype); +extern void t_free(trigger * t); +extern void t_add(trigger ** tlist, trigger * t); +/** add and handle triggers **/ + +/* add a trigger to a list of attributes */ +extern void add_trigger(struct attrib ** ap, const char * eventname, struct trigger * t); +extern void remove_triggers(struct attrib ** ap, const char * eventname, const trigger_type * tt); +extern struct trigger ** get_triggers(struct attrib * ap, const char * eventname); +/* calls handle() for each of these. e.g. used in timeout */ +extern void handle_event(struct attrib * attribs, const char * eventname, void * data); + +/* functions for making complex triggers: */ +extern void free_triggers(trigger * triggers); /* release all these triggers */ +extern void write_triggers(struct storage * store, const trigger * t); +extern int read_triggers(struct storage * store, trigger ** tp); +extern int handle_triggers(trigger ** triggers, void * data); + +extern struct attrib_type at_eventhandler; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/eventbus.c b/src/util/eventbus.c index e9cdebbee..77e81b578 100644 --- a/src/util/eventbus.c +++ b/src/util/eventbus.c @@ -1,56 +1,56 @@ -#include -#include "eventbus.h" - -/* -** first iteration. it is slow, and a proof of the concept - the simplest -** thing that would work, a.k.a. should be refectored when required. -*/ - -typedef struct listener { - struct listener * next; - event_handler callback; - event_arg_free destroy; - void * sender; - char * event; - void * arguments; -} listener; - -static listener * listeners; - -void -eventbus_fire(void * sender, const char * event, void * args) -{ - listener * lst = listeners; - while (lst) { - int i = strcmp(lst->event, event); - if (i>0) break; - if (i==0) { - if (!lst->sender || lst->sender==sender) { - lst->callback(sender, event, args); - } - } - lst = lst->next; - } -} - -void -eventbus_register(void * sender, const char * event, event_handler cb, event_arg_free arg_free, void * args) -{ - listener * lst; - listener ** lstp = &listeners; - while (*lstp) { - lst = *lstp; - if (strcmp(lst->event, event)>=0) { - break; - } - lstp=&lst->next; - } - lst = malloc(sizeof(listener)); - lst->sender = sender; - lst->arguments = args; - lst->callback = cb; - lst->destroy = arg_free; - lst->event = strdup(event); - lst->next = *lstp; - *lstp = lst; -} +#include +#include "eventbus.h" + +/* +** first iteration. it is slow, and a proof of the concept - the simplest +** thing that would work, a.k.a. should be refectored when required. +*/ + +typedef struct listener { + struct listener * next; + event_handler callback; + event_arg_free destroy; + void * sender; + char * event; + void * arguments; +} listener; + +static listener * listeners; + +void +eventbus_fire(void * sender, const char * event, void * args) +{ + listener * lst = listeners; + while (lst) { + int i = strcmp(lst->event, event); + if (i>0) break; + if (i==0) { + if (!lst->sender || lst->sender==sender) { + lst->callback(sender, event, args); + } + } + lst = lst->next; + } +} + +void +eventbus_register(void * sender, const char * event, event_handler cb, event_arg_free arg_free, void * args) +{ + listener * lst; + listener ** lstp = &listeners; + while (*lstp) { + lst = *lstp; + if (strcmp(lst->event, event)>=0) { + break; + } + lstp=&lst->next; + } + lst = malloc(sizeof(listener)); + lst->sender = sender; + lst->arguments = args; + lst->callback = cb; + lst->destroy = arg_free; + lst->event = strdup(event); + lst->next = *lstp; + *lstp = lst; +} diff --git a/src/util/eventbus.h b/src/util/eventbus.h index d7352cb51..b217c686c 100644 --- a/src/util/eventbus.h +++ b/src/util/eventbus.h @@ -1,29 +1,29 @@ -/* vi: set ts=2: - +-------------------+ - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2010 | Christian Schlittchen - | | - +-------------------+ - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_UTIL_EVTBUS -#define H_UTIL_EVTBUS - - -#ifdef __cplusplus -extern "C" { -#endif - - typedef void (*event_handler)(void *, const char *, void *); - typedef void (*event_arg_free)(void *); - void eventbus_fire(void * sender, const char * event, void * args); - void eventbus_register(void * sender, const char * event, event_handler callback, event_arg_free arg_free, void * args); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2010 | Christian Schlittchen + | | + +-------------------+ + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_UTIL_EVTBUS +#define H_UTIL_EVTBUS + + +#ifdef __cplusplus +extern "C" { +#endif + + typedef void (*event_handler)(void *, const char *, void *); + typedef void (*event_arg_free)(void *); + void eventbus_fire(void * sender, const char * event, void * args); + void eventbus_register(void * sender, const char * event, event_handler callback, event_arg_free arg_free, void * args); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/filereader.c b/src/util/filereader.c index 0b309959a..26c745851 100644 --- a/src/util/filereader.c +++ b/src/util/filereader.c @@ -1,314 +1,314 @@ -#include -#include "filereader.h" - -#include -#include - -#include - -#include -#include - -#define COMMENT_CHAR ';' -#define CONTINUE_CHAR '\\' -#define MAXLINE 4096*16 -static char lbuf[MAXLINE]; -static char fbuf[MAXLINE]; - -static void -unicode_warning(const char * bp) -{ - log_warning(("invalid sequence in UTF-8 string: %s\n", bp)); -} - -INLINE_FUNCTION int -eatwhite(const char * ptr, size_t * total_size) -{ - int ret = 0; - - *total_size = 0; - - while (*ptr) { - ucs4_t ucs; - size_t size = 0; - ret = unicode_utf8_to_ucs4(&ucs, ptr, &size); - if (ret!=0) break; - if (!iswxspace((wint_t)ucs)) break; - *total_size += size; - ptr += size; - } - return ret; -} - -static const char * -getbuf_latin1(FILE * F) -{ - boolean cont = false; - char quote = 0; - boolean comment = false; - char * cp = fbuf; - char * tail = lbuf+MAXLINE-2; - - tail[1] = '@'; /* if this gets overwritten by fgets then the line was very long. */ - do { - const char * bp = fgets(lbuf, MAXLINE, F); - - if (bp==NULL) return NULL; - while (*bp && isxspace(*(unsigned char*)bp)) ++bp; /* eatwhite */ - - comment = (boolean)(comment && cont); - - if (tail[1]==0) { - /* we read he maximum number of bytes! */ - if (tail[0]!='\n') { - /* it wasn't enough space to finish the line, eat the rest */ - for (;;) { - tail[1] = '@'; - bp = fgets(lbuf, MAXLINE, F); - if (bp==NULL) return NULL; - if (tail[1]) { - /* read enough this time to end the line */ - break; - } - } - comment = false; - cont = false; - bp = NULL; - continue; - } else { - tail[1] = '@'; - } - } - cont = false; - while (*bp && cp0) cp+=ret; - else { - log_error(("input data was not iso-8859-1! assuming utf-8\n")); - return NULL; - } - - ++bp; - continue; - } - } - if (cp==fbuf+MAXLINE) { - --cp; - } - *cp=0; - } while (cont || cp==fbuf); - return fbuf; -} - -static const char * -getbuf_utf8(FILE * F) -{ - boolean cont = false; - char quote = 0; - boolean comment = false; - char * cp = fbuf; - char * tail = lbuf+MAXLINE-2; - - tail[1] = '@'; /* if this gets overwritten by fgets then the line was very long. */ - do { - const char * bp = fgets(lbuf, MAXLINE, F); - size_t white; - if (bp==NULL) { - return NULL; - } - - eatwhite(bp, &white); /* decoding errors will get caught later on, don't have to check */ - bp += white; - - comment = (boolean)(comment && cont); - - if (tail[1]==0) { - /* we read he maximum number of bytes! */ - if (tail[0]!='\n') { - /* it wasn't enough space to finish the line, eat the rest */ - for (;;) { - tail[1] = '@'; - bp = fgets(lbuf, MAXLINE, F); - if (bp==NULL) return NULL; - if (tail[1]) { - /* read enough this time to end the line */ - break; - } - } - comment = false; - cont = false; - bp = NULL; - continue; - } else { - tail[1] = '@'; - } - } - cont = false; - while (*bp && cp +#include "filereader.h" + +#include +#include + +#include + +#include +#include + +#define COMMENT_CHAR ';' +#define CONTINUE_CHAR '\\' +#define MAXLINE 4096*16 +static char lbuf[MAXLINE]; +static char fbuf[MAXLINE]; + +static void +unicode_warning(const char * bp) +{ + log_warning(("invalid sequence in UTF-8 string: %s\n", bp)); +} + +INLINE_FUNCTION int +eatwhite(const char * ptr, size_t * total_size) +{ + int ret = 0; + + *total_size = 0; + + while (*ptr) { + ucs4_t ucs; + size_t size = 0; + ret = unicode_utf8_to_ucs4(&ucs, ptr, &size); + if (ret!=0) break; + if (!iswxspace((wint_t)ucs)) break; + *total_size += size; + ptr += size; + } + return ret; +} + +static const char * +getbuf_latin1(FILE * F) +{ + boolean cont = false; + char quote = 0; + boolean comment = false; + char * cp = fbuf; + char * tail = lbuf+MAXLINE-2; + + tail[1] = '@'; /* if this gets overwritten by fgets then the line was very long. */ + do { + const char * bp = fgets(lbuf, MAXLINE, F); + + if (bp==NULL) return NULL; + while (*bp && isxspace(*(unsigned char*)bp)) ++bp; /* eatwhite */ + + comment = (boolean)(comment && cont); + + if (tail[1]==0) { + /* we read he maximum number of bytes! */ + if (tail[0]!='\n') { + /* it wasn't enough space to finish the line, eat the rest */ + for (;;) { + tail[1] = '@'; + bp = fgets(lbuf, MAXLINE, F); + if (bp==NULL) return NULL; + if (tail[1]) { + /* read enough this time to end the line */ + break; + } + } + comment = false; + cont = false; + bp = NULL; + continue; + } else { + tail[1] = '@'; + } + } + cont = false; + while (*bp && cp0) cp+=ret; + else { + log_error(("input data was not iso-8859-1! assuming utf-8\n")); + return NULL; + } + + ++bp; + continue; + } + } + if (cp==fbuf+MAXLINE) { + --cp; + } + *cp=0; + } while (cont || cp==fbuf); + return fbuf; +} + +static const char * +getbuf_utf8(FILE * F) +{ + boolean cont = false; + char quote = 0; + boolean comment = false; + char * cp = fbuf; + char * tail = lbuf+MAXLINE-2; + + tail[1] = '@'; /* if this gets overwritten by fgets then the line was very long. */ + do { + const char * bp = fgets(lbuf, MAXLINE, F); + size_t white; + if (bp==NULL) { + return NULL; + } + + eatwhite(bp, &white); /* decoding errors will get caught later on, don't have to check */ + bp += white; + + comment = (boolean)(comment && cont); + + if (tail[1]==0) { + /* we read he maximum number of bytes! */ + if (tail[0]!='\n') { + /* it wasn't enough space to finish the line, eat the rest */ + for (;;) { + tail[1] = '@'; + bp = fgets(lbuf, MAXLINE, F); + if (bp==NULL) return NULL; + if (tail[1]) { + /* read enough this time to end the line */ + break; + } + } + comment = false; + cont = false; + bp = NULL; + continue; + } else { + tail[1] = '@'; + } + } + cont = false; + while (*bp && cp -* | | Enno Rehling -* | Eressea PBEM host | Katja Zedel -* | (c) 1998 - 2005 | -* | | This program may not be used, modified or distributed -* +-------------------+ without prior permission by the authors of Eressea. -* -*/ -#ifndef UTIL_FILEREADER_H -#define UTIL_FILEREADER_H -#ifdef __cplusplus -extern "C" { -#endif - -const char * getbuf(FILE *, int encoding); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: +* +-------------------+ Christian Schlittchen +* | | Enno Rehling +* | Eressea PBEM host | Katja Zedel +* | (c) 1998 - 2005 | +* | | This program may not be used, modified or distributed +* +-------------------+ without prior permission by the authors of Eressea. +* +*/ +#ifndef UTIL_FILEREADER_H +#define UTIL_FILEREADER_H +#ifdef __cplusplus +extern "C" { +#endif + +const char * getbuf(FILE *, int encoding); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/functions.c b/src/util/functions.c index e8f488333..81b9face6 100644 --- a/src/util/functions.c +++ b/src/util/functions.c @@ -1,74 +1,74 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "functions.h" - -/* libc includes */ -#include -#include - - - -typedef struct function_list { - struct function_list * next; - pf_generic fun; - const char * name; -} function_list; - -static function_list * functionlist; - -pf_generic -get_function(const char * name) -{ - function_list * fl = functionlist; - if (name==NULL) return NULL; - while (fl && strcmp(fl->name, name)!=0) fl=fl->next; - if (fl) return fl->fun; - return NULL; -} - -const char * -get_functionname(pf_generic fun) -{ - function_list * fl = functionlist; - while (fl && fl->fun!=fun) fl=fl->next; - if (fl) return fl->name; - return NULL; -} - -void -register_function(pf_generic fun, const char * name) -{ - function_list * fl = calloc(sizeof(function_list), 1); - fl->next = functionlist; - fl->fun = fun; - fl->name = strdup(name); - functionlist = fl; -} - -void -list_registered_functions(void) -{ - function_list * fl = functionlist; - - while(fl) { - printf("%s\n", fl->name); - fl = fl->next; - } -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "functions.h" + +/* libc includes */ +#include +#include + + + +typedef struct function_list { + struct function_list * next; + pf_generic fun; + const char * name; +} function_list; + +static function_list * functionlist; + +pf_generic +get_function(const char * name) +{ + function_list * fl = functionlist; + if (name==NULL) return NULL; + while (fl && strcmp(fl->name, name)!=0) fl=fl->next; + if (fl) return fl->fun; + return NULL; +} + +const char * +get_functionname(pf_generic fun) +{ + function_list * fl = functionlist; + while (fl && fl->fun!=fun) fl=fl->next; + if (fl) return fl->name; + return NULL; +} + +void +register_function(pf_generic fun, const char * name) +{ + function_list * fl = calloc(sizeof(function_list), 1); + fl->next = functionlist; + fl->fun = fun; + fl->name = strdup(name); + functionlist = fl; +} + +void +list_registered_functions(void) +{ + function_list * fl = functionlist; + + while(fl) { + printf("%s\n", fl->name); + fl = fl->next; + } +} diff --git a/src/util/functions.h b/src/util/functions.h index da80ddeba..f8fd090a6 100644 --- a/src/util/functions.h +++ b/src/util/functions.h @@ -1,35 +1,35 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef FUNCTIONS_H -#define FUNCTIONS_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*pf_generic)(void); - -extern const char *get_functionname(pf_generic fun); -extern pf_generic get_function(const char * name); -extern void register_function(pf_generic fun, const char * name); -extern void list_registered_functions(void); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef FUNCTIONS_H +#define FUNCTIONS_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*pf_generic)(void); + +extern const char *get_functionname(pf_generic fun); +extern pf_generic get_function(const char * name); +extern void register_function(pf_generic fun, const char * name); +extern void list_registered_functions(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/goodies.c b/src/util/goodies.c index c49d02772..231bbd9e9 100644 --- a/src/util/goodies.c +++ b/src/util/goodies.c @@ -1,154 +1,128 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "goodies.h" - -#include "unicode.h" - -/* libc includes */ -#include -#include -#include - -/* Simple Integer-Liste */ - -int * -intlist_init(void) -{ - return (calloc(1, sizeof(int))); -} - -int * -intlist_add(int *i_p, int i) -{ - i_p[0]++; - i_p = realloc(i_p, (i_p[0]+1) * sizeof(int)); - - i_p[i_p[0]] = i; - return (i_p); -} - -int * -intlist_find(int *i_p, int fi) -{ - int i; - - for(i=1; i <= i_p[0]; i++) { - if(i_p[i] == fi) return (&i_p[i]); - } - return NULL; -} - -char * -set_string (char **s, const char *neu) -{ - if (neu==NULL) { - free(*s); - *s = NULL; - } else if (*s == NULL) { - *s = malloc(strlen(neu)+1); - strcpy(*s, neu); - } else { - *s = realloc(*s, strlen(neu) + 1); - strcpy(*s, neu); - } - return *s; -} - - -static int -spc_email_isvalid(const char *address) -{ - int count = 0; - const char *c, *domain; - static const char *rfc822_specials = "()<>@,;:\\\"[]"; /* STATIC_CONST: contains a constant value */ - - /* first we validate the name portion (name@domain) */ - for (c = address; *c; c++) { - if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == - '\"')) { - while (*++c) { - if (*c == '\"') break; - if (*c == '\\' && (*++c == ' ')) continue; - if (*c <= ' ' || *c >= 127) return 0; - } - if (!*c++) return 0; - if (*c == '@') break; - if (*c != '.') return 0; - continue; - } - if (*c == '@') break; - if (*c <= ' ' || *c >= 127) return 0; - if (strchr(rfc822_specials, *c)) return 0; - } - if (c == address || *(c - 1) == '.') return 0; - - /* next we validate the domain portion (name@domain) */ - if (!*(domain = ++c)) return 0; - do { - if (*c == '.') { - if (c == domain || *(c - 1) == '.') return 0; - count++; - } - if (*c <= ' ' || *c >= 127) return 0; - if (strchr(rfc822_specials, *c)) return 0; - } while (*++c); - - return (count >= 1); -} - -int -set_email(char** pemail, const char *newmail) -{ - if (newmail && *newmail) { - if (spc_email_isvalid(newmail)<=0) return -1; - } - if (*pemail) free(*pemail); - *pemail = 0; - if (newmail) { - *pemail = strdup(newmail); - } - return 0; -} - -#include "encoding.h" -#include - -static struct { - int encoding; - const char * names; -} encodings[] = { - { ENCODING_UTF8, " utf8 utf-8 UTF8 UTF-8 "}, - { ENCODING_8859_1, " iso8859-1 latin1 latin-1 iso-8859-1 ISO8859-1 LATIN1 LATIN-1 ISO-8859-1 "}, - { ENCODING_NONE, 0 } -}; - -int -get_encoding_by_name(const char * name) -{ - char str[32]; - int i; - snprintf(str, 32, " %s ", name); - for (i=0;encodings[i].encoding!=ENCODING_NONE;++i) { - if (strstr(encodings[i].names, str)) { - return encodings[i].encoding; - } - } - return ENCODING_NONE; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "goodies.h" + +#include "unicode.h" + +/* libc includes */ +#include +#include +#include + +/* Simple Integer-Liste */ + +int * +intlist_init(void) +{ + return (calloc(1, sizeof(int))); +} + +int * +intlist_add(int *i_p, int i) +{ + i_p[0]++; + i_p = realloc(i_p, (i_p[0]+1) * sizeof(int)); + + i_p[i_p[0]] = i; + return (i_p); +} + +int * +intlist_find(int *i_p, int fi) +{ + int i; + + for(i=1; i <= i_p[0]; i++) { + if(i_p[i] == fi) return (&i_p[i]); + } + return NULL; +} + +char * +set_string (char **s, const char *neu) +{ + if (neu==NULL) { + free(*s); + *s = NULL; + } else if (*s == NULL) { + *s = malloc(strlen(neu)+1); + strcpy(*s, neu); + } else { + *s = realloc(*s, strlen(neu) + 1); + strcpy(*s, neu); + } + return *s; +} + + +static int +spc_email_isvalid(const char *address) +{ + int count = 0; + const char *c, *domain; + static const char *rfc822_specials = "()<>@,;:\\\"[]"; /* STATIC_CONST: contains a constant value */ + + /* first we validate the name portion (name@domain) */ + for (c = address; *c; c++) { + if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == + '\"')) { + while (*++c) { + if (*c == '\"') break; + if (*c == '\\' && (*++c == ' ')) continue; + if (*c <= ' ' || *c >= 127) return 0; + } + if (!*c++) return 0; + if (*c == '@') break; + if (*c != '.') return 0; + continue; + } + if (*c == '@') break; + if (*c <= ' ' || *c >= 127) return 0; + if (strchr(rfc822_specials, *c)) return 0; + } + if (c == address || *(c - 1) == '.') return 0; + + /* next we validate the domain portion (name@domain) */ + if (!*(domain = ++c)) return 0; + do { + if (*c == '.') { + if (c == domain || *(c - 1) == '.') return 0; + count++; + } + if (*c <= ' ' || *c >= 127) return 0; + if (strchr(rfc822_specials, *c)) return 0; + } while (*++c); + + return (count >= 1); +} + +int +set_email(char** pemail, const char *newmail) +{ + if (newmail && *newmail) { + if (spc_email_isvalid(newmail)<=0) return -1; + } + if (*pemail) free(*pemail); + *pemail = 0; + if (newmail) { + *pemail = strdup(newmail); + } + return 0; +} diff --git a/src/util/goodies.h b/src/util/goodies.h index 50dc7cb40..aabf0cb4b 100644 --- a/src/util/goodies.h +++ b/src/util/goodies.h @@ -1,63 +1,63 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef GOODIES_H -#define GOODIES_H -#ifdef __cplusplus -extern "C" { -#endif - -extern char * set_string(char **s, const char *neu); -extern int set_email(char** pemail, const char *newmail); - -extern int *intlist_init(void); -extern int *intlist_add(int *i_p, int i); -extern int *intlist_find(int *i_p, int i); - -#ifdef HAVE_INLINE -# include "strings.c" -#else -extern unsigned int hashstring(const char* s); -extern const char *escape_string(const char * str, char * buffer, unsigned int len); -extern unsigned int jenkins_hash(unsigned int a); -extern unsigned int wang_hash(unsigned int a); -#endif - -/* benchmark for units: - * JENKINS_HASH: 5.25 misses/hit (with good cache behavior) - * WANG_HASH: 5.33 misses/hit (with good cache behavior) - * KNUTH_HASH: 1.93 misses/hit (with bad cache behavior) - * CF_HASH: fucking awful! - */ -#define KNUTH_HASH1(a, m) ((a) % m) -#define KNUTH_HASH2(a, m) (m - 2 - a % (m-2)) -#define CF_HASH1(a, m) ((a) % m) -#define CF_HASH2(a, m) (8 - ((a) & 7)) -#define JENKINS_HASH1(a, m) (jenkins_hash(a) % m) -#define JENKINS_HASH2(a, m) 1 -#define WANG_HASH1(a, m) (wang_hash(a) % m) -#define WANG_HASH2(a, m) 1 - -#define HASH1 JENKINS_HASH1 -#define HASH2 JENKINS_HASH2 - -#define SWAP_VARS(T, a, b) { T x = a; a = b; b = x; } -#ifdef __cplusplus -} -#endif -#endif /* GOODIES_H */ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef GOODIES_H +#define GOODIES_H +#ifdef __cplusplus +extern "C" { +#endif + +extern char * set_string(char **s, const char *neu); +extern int set_email(char** pemail, const char *newmail); + +extern int *intlist_init(void); +extern int *intlist_add(int *i_p, int i); +extern int *intlist_find(int *i_p, int i); + +#ifdef HAVE_INLINE +# include "strings.c" +#else +extern unsigned int hashstring(const char* s); +extern const char *escape_string(const char * str, char * buffer, unsigned int len); +extern unsigned int jenkins_hash(unsigned int a); +extern unsigned int wang_hash(unsigned int a); +#endif + +/* benchmark for units: + * JENKINS_HASH: 5.25 misses/hit (with good cache behavior) + * WANG_HASH: 5.33 misses/hit (with good cache behavior) + * KNUTH_HASH: 1.93 misses/hit (with bad cache behavior) + * CF_HASH: fucking awful! + */ +#define KNUTH_HASH1(a, m) ((a) % m) +#define KNUTH_HASH2(a, m) (m - 2 - a % (m-2)) +#define CF_HASH1(a, m) ((a) % m) +#define CF_HASH2(a, m) (8 - ((a) & 7)) +#define JENKINS_HASH1(a, m) (jenkins_hash(a) % m) +#define JENKINS_HASH2(a, m) 1 +#define WANG_HASH1(a, m) (wang_hash(a) % m) +#define WANG_HASH2(a, m) 1 + +#define HASH1 JENKINS_HASH1 +#define HASH2 JENKINS_HASH2 + +#define SWAP_VARS(T, a, b) { T x = a; a = b; b = x; } +#ifdef __cplusplus +} +#endif +#endif /* GOODIES_H */ diff --git a/src/util/graph.c b/src/util/graph.c index 3e6f7aec1..9ea181466 100644 --- a/src/util/graph.c +++ b/src/util/graph.c @@ -1,203 +1,203 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - */ - -/* This is a very simple graph library. It is not optimized in any - way, and relies heavily on the vset and stack routines. */ - -#include -#include "vset.h" -#include "graph.h" - -void -graph_init(graph *g) -{ - vset_init(&g->nodes); - vset_init(&g->edges); -} - -void -graph_free(graph *g) -{ - vset_destroy(&g->nodes); - vset_destroy(&g->edges); -} - -void -graph_add_node(graph *g, node *n) -{ - vset_add(&g->nodes, n); -} - -void -graph_add_edge(graph *g, edge *v) -{ - vset_add(&g->nodes, v); -} - -void -graph_remove_node(graph *g, node *n) -{ - unsigned int i; - - for(i=0; i != g->edges.size; ++i) { - edge *v = g->edges.data[i]; - if(v->node1 == n || v->node2 == n) { - vset_erase(&g->nodes, v); - i--; - } - } - vset_erase(&g->nodes, n); -} - -node * -graph_find_node(graph *g, void *object) -{ - unsigned int i; - - for(i=0; i != g->nodes.size; ++i) { - node *node = g->nodes.data[i]; - if(node->object == object) { - return g->nodes.data[i]; - } - } - return NULL; -} - -/* The vset returned has to freed externally, else this will be a - memory leak. */ - -vset * -graph_neighbours(graph *g, node *n) -{ - unsigned int i; - vset * vs = malloc(sizeof(vs)); - vset_init(vs); - for(i=0; i != g->edges.size; ++i) { - edge *v = g->edges.data[i]; - if(v->node1 == n && vset_count(vs, v->node2) == 0) { - vset_add(vs, v->node2); - } else if(v->node2 == n && vset_count(vs, v->node1) == 0) { - vset_add(vs, v->node1); - } - } - - return vs; -} - -void -graph_resetmarkers(graph *g) -{ - unsigned int i; - - for(i=0; i != g->nodes.size; ++i) { - node *node = g->nodes.data[i]; - node->marker = 0; - } - for(i=0; i != g->edges.size; ++i) { - edge *edge = g->edges.data[i]; - edge->marker = 0; - } -} - -/* The vset returned has to freed externally, else this will be a - memory leak. */ - -vset * -graph_connected_nodes(graph *g, node *n) -{ - vset * vs = malloc(sizeof(vset)); - vset s; - - vset_init(vs); - vset_init(&s); - graph_resetmarkers(g); - vset_add(vs, n); - n->marker = 1; - vset_add(&s, n); - while(s.size > 0) { - node *n = vset_pop(&s); - vset *vs_nb = graph_neighbours(g, n); - unsigned int i; - for(i=0; i != vs_nb->size; ++i) { - node *nb = vs_nb->data[i]; - if(nb->marker == 0) { - nb->marker = 1; - vset_add(vs, nb); - vset_add(&s, nb); - } - } - vset_destroy(vs_nb); - free(vs_nb); - } - - vset_destroy(&s); - - return vs; -} - -/* The vset returned has to freed externally, else this will be a - memory leak. */ - -vset * -graph_disjunct_graphs(graph *g) -{ - vset * dg = malloc(sizeof(vset)); - vset nodes; - - vset_init(dg); - vset_init(&nodes); - vset_concat(&nodes, &g->nodes); - - while(nodes.size > 0) { - graph *gt = malloc(sizeof(graph)); - vset s; - unsigned int i; - node *start; - - graph_init(gt); - start = vset_pop(&nodes); - graph_resetmarkers(g); - graph_add_node(gt, start); - start->marker = 1; - vset_init(&s); - vset_add(&s,start); - while(s.size > 0) { - vset * nbs = graph_neighbours(g,vset_pop(&s)); - for(i=0; i != nbs->size; ++i) { - node *nb = nbs->data[i]; - if(nb->marker == 0) { - nb->marker = 1; - graph_add_node(gt,nb); - vset_erase(&nodes,nb); - vset_add(&s,nb); - } - } - vset_destroy(nbs); free(nbs); - } - - vset_destroy(&s); - - for(i=0;i != g->edges.size; ++i) { - edge *v = g->edges.data[i]; - if(vset_count(&g->nodes, v->node1)) { - graph_add_edge(gt, v); - } - } - - vset_add(dg, gt); - } - - vset_destroy(&nodes); - - return dg; -} - +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + */ + +/* This is a very simple graph library. It is not optimized in any + way, and relies heavily on the vset and stack routines. */ + +#include +#include "vset.h" +#include "graph.h" + +void +graph_init(graph *g) +{ + vset_init(&g->nodes); + vset_init(&g->edges); +} + +void +graph_free(graph *g) +{ + vset_destroy(&g->nodes); + vset_destroy(&g->edges); +} + +void +graph_add_node(graph *g, node *n) +{ + vset_add(&g->nodes, n); +} + +void +graph_add_edge(graph *g, edge *v) +{ + vset_add(&g->nodes, v); +} + +void +graph_remove_node(graph *g, node *n) +{ + unsigned int i; + + for(i=0; i != g->edges.size; ++i) { + edge *v = g->edges.data[i]; + if(v->node1 == n || v->node2 == n) { + vset_erase(&g->nodes, v); + i--; + } + } + vset_erase(&g->nodes, n); +} + +node * +graph_find_node(graph *g, void *object) +{ + unsigned int i; + + for(i=0; i != g->nodes.size; ++i) { + node *node = g->nodes.data[i]; + if(node->object == object) { + return g->nodes.data[i]; + } + } + return NULL; +} + +/* The vset returned has to freed externally, else this will be a + memory leak. */ + +vset * +graph_neighbours(graph *g, node *n) +{ + unsigned int i; + vset * vs = malloc(sizeof(vs)); + vset_init(vs); + for(i=0; i != g->edges.size; ++i) { + edge *v = g->edges.data[i]; + if(v->node1 == n && vset_count(vs, v->node2) == 0) { + vset_add(vs, v->node2); + } else if(v->node2 == n && vset_count(vs, v->node1) == 0) { + vset_add(vs, v->node1); + } + } + + return vs; +} + +void +graph_resetmarkers(graph *g) +{ + unsigned int i; + + for(i=0; i != g->nodes.size; ++i) { + node *node = g->nodes.data[i]; + node->marker = 0; + } + for(i=0; i != g->edges.size; ++i) { + edge *edge = g->edges.data[i]; + edge->marker = 0; + } +} + +/* The vset returned has to freed externally, else this will be a + memory leak. */ + +vset * +graph_connected_nodes(graph *g, node *n) +{ + vset * vs = malloc(sizeof(vset)); + vset s; + + vset_init(vs); + vset_init(&s); + graph_resetmarkers(g); + vset_add(vs, n); + n->marker = 1; + vset_add(&s, n); + while(s.size > 0) { + node *n = vset_pop(&s); + vset *vs_nb = graph_neighbours(g, n); + unsigned int i; + for(i=0; i != vs_nb->size; ++i) { + node *nb = vs_nb->data[i]; + if(nb->marker == 0) { + nb->marker = 1; + vset_add(vs, nb); + vset_add(&s, nb); + } + } + vset_destroy(vs_nb); + free(vs_nb); + } + + vset_destroy(&s); + + return vs; +} + +/* The vset returned has to freed externally, else this will be a + memory leak. */ + +vset * +graph_disjunct_graphs(graph *g) +{ + vset * dg = malloc(sizeof(vset)); + vset nodes; + + vset_init(dg); + vset_init(&nodes); + vset_concat(&nodes, &g->nodes); + + while(nodes.size > 0) { + graph *gt = malloc(sizeof(graph)); + vset s; + unsigned int i; + node *start; + + graph_init(gt); + start = vset_pop(&nodes); + graph_resetmarkers(g); + graph_add_node(gt, start); + start->marker = 1; + vset_init(&s); + vset_add(&s,start); + while(s.size > 0) { + vset * nbs = graph_neighbours(g,vset_pop(&s)); + for(i=0; i != nbs->size; ++i) { + node *nb = nbs->data[i]; + if(nb->marker == 0) { + nb->marker = 1; + graph_add_node(gt,nb); + vset_erase(&nodes,nb); + vset_add(&s,nb); + } + } + vset_destroy(nbs); free(nbs); + } + + vset_destroy(&s); + + for(i=0;i != g->edges.size; ++i) { + edge *v = g->edges.data[i]; + if(vset_count(&g->nodes, v->node1)) { + graph_add_edge(gt, v); + } + } + + vset_add(dg, gt); + } + + vset_destroy(&nodes); + + return dg; +} + diff --git a/src/util/graph.h b/src/util/graph.h index e5398b3a0..e5480d1ab 100644 --- a/src/util/graph.h +++ b/src/util/graph.h @@ -1,38 +1,38 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - */ - -#ifndef GRAPH_H -#define GRAPH_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct node { - int marker; - void *object; -} node; - -typedef struct edge { - int marker; - node *node1; - node *node2; -} edge; - -typedef struct graph { - vset nodes; - vset edges; -} graph; - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + */ + +#ifndef GRAPH_H +#define GRAPH_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct node { + int marker; + void *object; +} node; + +typedef struct edge { + int marker; + node *node1; + node *node2; +} edge; + +typedef struct graph { + vset nodes; + vset edges; +} graph; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/language.c b/src/util/language.c index d5842142b..298cf92b0 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -1,252 +1,252 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "language.h" -#include "language_struct.h" - -#include "log.h" -#include "goodies.h" -#include "umlaut.h" - -#include -#include -#include -#include - -/** importing **/ - -locale * default_locale; -locale * locales; - -unsigned int -locale_hashkey(const locale * lang) -{ - assert(lang); - return lang->hashkey; -} - -locale * -find_locale(const char * name) -{ - unsigned int hkey = hashstring(name); - locale * l = locales; - while (l && l->hashkey!=hkey) l=l->next; - return l; -} - -static int nextlocaleindex = 0; - -locale * -make_locale(const char * name) -{ - unsigned int hkey = hashstring(name); - locale * l = (locale *)calloc(sizeof(locale), 1); - locale ** lp = &locales; - - while (*lp && (*lp)->hashkey!=hkey) lp=&(*lp)->next; - if (*lp) { - return *lp; - } - - l->hashkey = hkey; - l->name = strdup(name); - l->next = NULL; - l->index = nextlocaleindex++; - assert(nextlocaleindex<=MAXLOCALES); - *lp = l; - if (default_locale==NULL) default_locale = l; - return l; -} - -/** creates a list of locales - * This function takes a comma-delimited list of locale-names and creates - * the locales using the make_locale function (useful for ini-files). - * For maximum performance, locales should be created in order of popularity. - */ -void -make_locales(const char * str) -{ - const char * tok = str; - while (*tok) { - char zText[32]; - while (*tok && *tok !=',') ++tok; - strncpy(zText, str, tok-str); - zText[tok-str] = 0; - make_locale(zText); - if (*tok) { - str = ++tok; - } - } -} - -static FILE * s_debug = NULL; -static char * s_logfile = NULL; - -void -debug_language(const char * log) -{ - s_logfile = strdup(log); -} - -const char * -locale_getstring(const locale * lang, const char * key) -{ - unsigned int hkey = hashstring(key); - unsigned int id = hkey & (SMAXHASH-1); - const struct locale_str * find; - - assert(lang); - if (key==NULL || *key==0) return NULL; - find = lang->strings[id]; - while (find) { - if (find->hashkey == hkey) { - if (find->nexthash==NULL) { - /* if this is the only entry with this hash, fine. */ - assert(strcmp(key, find->key)==0); - return find->str; - } - if (strcmp(key, find->key)==0) { - return find->str; - } - } - find = find->nexthash; - } - return NULL; -} - -const char * -locale_string(const locale * lang, const char * key) -{ - assert(lang!=0); - - if (key!=NULL) { - unsigned int hkey = hashstring(key); - unsigned int id = hkey & (SMAXHASH-1); - struct locale_str * find; - - if (*key==0) return NULL; - if (lang == NULL) return key; - find = lang->strings[id]; - while (find) { - if (find->hashkey == hkey) { - if (find->nexthash==NULL) { - /* if this is the only entry with this hash, fine. */ - assert(strcmp(key, find->key)==0); - break; - } - if (strcmp(key, find->key)==0) break; - } - find = find->nexthash; - } - if (!find) { - const char * s = key; - log_warning(("missing translation for \"%s\" in locale %s\n", key, lang->name)); - if (lang!=default_locale) { - s = locale_string(default_locale, key); - } - if (s_logfile) { - s_debug = s_debug?s_debug:fopen(s_logfile, "w"); - if (s_debug) { - fprintf(s_debug, "%s;%s;%s\n", key, lang->name, s); - fflush(s_debug); - locale_setstring((struct locale*)lang, key, s); - } - } - return s; - } - return find->str; - } - return NULL; -} - -void -locale_setstring(locale * lang, const char * key, const char * value) -{ - unsigned int hkey = hashstring(key); - unsigned int id = hkey & (SMAXHASH-1); - struct locale_str * find; - if (lang==NULL) lang=default_locale; - find = lang->strings[id]; - while (find) { - if (find->hashkey==hkey && strcmp(key, find->key)==0) break; - find = find->nexthash; - } - if (!find) { - find = calloc(1, sizeof(struct locale_str)); - find->nexthash = lang->strings[id]; - lang->strings[id] = find; - find->hashkey = hkey; - find->key = strdup(key); - find->str = strdup(value); - } - else { - if (strcmp(find->str, value)!=0) { - log_error(("Duplicate key %s for '%s' and '%s'\n", key, value, find->str)); - } - assert(!strcmp(find->str, value) || !"duplicate string for key"); - } -} - -const char * -locale_name(const locale * lang) -{ - assert(lang); - return lang->name; -} - -char * -mkname_buf(const char * space, const char * name, char * buffer) -{ - if (space && *space) { - sprintf(buffer, "%s::%s", space, name); - } else { - strcpy(buffer, name); - } - return buffer; -} - -const char * -mkname(const char * space, const char * name) -{ - static char zBuffer[128]; /* STATIC_RESULT: used for return, not across calls */ - return mkname_buf(space, name, zBuffer); -} - -locale * -nextlocale(const struct locale * lang) -{ - return lang->next; -} - -typedef struct lstr { - tnode tokens[UT_MAX]; -} lstr; - -static lstr lstrs[MAXLOCALES]; - -struct tnode * -get_translations(const struct locale * lang, int index) -{ - assert(lang); - assert(lang->indexindexindex].tokens+index; - } - return lstrs[0].tokens+index; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "language.h" +#include "language_struct.h" + +#include "log.h" +#include "goodies.h" +#include "umlaut.h" + +#include +#include +#include +#include + +/** importing **/ + +locale * default_locale; +locale * locales; + +unsigned int +locale_hashkey(const locale * lang) +{ + assert(lang); + return lang->hashkey; +} + +locale * +find_locale(const char * name) +{ + unsigned int hkey = hashstring(name); + locale * l = locales; + while (l && l->hashkey!=hkey) l=l->next; + return l; +} + +static int nextlocaleindex = 0; + +locale * +make_locale(const char * name) +{ + unsigned int hkey = hashstring(name); + locale * l = (locale *)calloc(sizeof(locale), 1); + locale ** lp = &locales; + + while (*lp && (*lp)->hashkey!=hkey) lp=&(*lp)->next; + if (*lp) { + return *lp; + } + + l->hashkey = hkey; + l->name = strdup(name); + l->next = NULL; + l->index = nextlocaleindex++; + assert(nextlocaleindex<=MAXLOCALES); + *lp = l; + if (default_locale==NULL) default_locale = l; + return l; +} + +/** creates a list of locales + * This function takes a comma-delimited list of locale-names and creates + * the locales using the make_locale function (useful for ini-files). + * For maximum performance, locales should be created in order of popularity. + */ +void +make_locales(const char * str) +{ + const char * tok = str; + while (*tok) { + char zText[32]; + while (*tok && *tok !=',') ++tok; + strncpy(zText, str, tok-str); + zText[tok-str] = 0; + make_locale(zText); + if (*tok) { + str = ++tok; + } + } +} + +static FILE * s_debug = NULL; +static char * s_logfile = NULL; + +void +debug_language(const char * log) +{ + s_logfile = strdup(log); +} + +const char * +locale_getstring(const locale * lang, const char * key) +{ + unsigned int hkey = hashstring(key); + unsigned int id = hkey & (SMAXHASH-1); + const struct locale_str * find; + + assert(lang); + if (key==NULL || *key==0) return NULL; + find = lang->strings[id]; + while (find) { + if (find->hashkey == hkey) { + if (find->nexthash==NULL) { + /* if this is the only entry with this hash, fine. */ + assert(strcmp(key, find->key)==0); + return find->str; + } + if (strcmp(key, find->key)==0) { + return find->str; + } + } + find = find->nexthash; + } + return NULL; +} + +const char * +locale_string(const locale * lang, const char * key) +{ + assert(lang!=0); + + if (key!=NULL) { + unsigned int hkey = hashstring(key); + unsigned int id = hkey & (SMAXHASH-1); + struct locale_str * find; + + if (*key==0) return NULL; + if (lang == NULL) return key; + find = lang->strings[id]; + while (find) { + if (find->hashkey == hkey) { + if (find->nexthash==NULL) { + /* if this is the only entry with this hash, fine. */ + assert(strcmp(key, find->key)==0); + break; + } + if (strcmp(key, find->key)==0) break; + } + find = find->nexthash; + } + if (!find) { + const char * s = key; + log_warning(("missing translation for \"%s\" in locale %s\n", key, lang->name)); + if (lang!=default_locale) { + s = locale_string(default_locale, key); + } + if (s_logfile) { + s_debug = s_debug?s_debug:fopen(s_logfile, "w"); + if (s_debug) { + fprintf(s_debug, "%s;%s;%s\n", key, lang->name, s); + fflush(s_debug); + locale_setstring((struct locale*)lang, key, s); + } + } + return s; + } + return find->str; + } + return NULL; +} + +void +locale_setstring(locale * lang, const char * key, const char * value) +{ + unsigned int hkey = hashstring(key); + unsigned int id = hkey & (SMAXHASH-1); + struct locale_str * find; + if (lang==NULL) lang=default_locale; + find = lang->strings[id]; + while (find) { + if (find->hashkey==hkey && strcmp(key, find->key)==0) break; + find = find->nexthash; + } + if (!find) { + find = calloc(1, sizeof(struct locale_str)); + find->nexthash = lang->strings[id]; + lang->strings[id] = find; + find->hashkey = hkey; + find->key = strdup(key); + find->str = strdup(value); + } + else { + if (strcmp(find->str, value)!=0) { + log_error(("Duplicate key %s for '%s' and '%s'\n", key, value, find->str)); + } + assert(!strcmp(find->str, value) || !"duplicate string for key"); + } +} + +const char * +locale_name(const locale * lang) +{ + assert(lang); + return lang->name; +} + +char * +mkname_buf(const char * space, const char * name, char * buffer) +{ + if (space && *space) { + sprintf(buffer, "%s::%s", space, name); + } else { + strcpy(buffer, name); + } + return buffer; +} + +const char * +mkname(const char * space, const char * name) +{ + static char zBuffer[128]; /* STATIC_RESULT: used for return, not across calls */ + return mkname_buf(space, name, zBuffer); +} + +locale * +nextlocale(const struct locale * lang) +{ + return lang->next; +} + +typedef struct lstr { + tnode tokens[UT_MAX]; +} lstr; + +static lstr lstrs[MAXLOCALES]; + +struct tnode * +get_translations(const struct locale * lang, int index) +{ + assert(lang); + assert(lang->indexindexindex].tokens+index; + } + return lstrs[0].tokens+index; +} diff --git a/src/util/language.h b/src/util/language.h index b1ad422bf..a051bc6f0 100644 --- a/src/util/language.h +++ b/src/util/language.h @@ -1,69 +1,69 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef MY_LOCALE_H -#define MY_LOCALE_H -#ifdef __cplusplus -extern "C" { -#endif - -struct locale; - -/** managing multiple locales: **/ -extern struct locale * find_locale(const char * name); -extern struct locale * make_locale(const char * key); - -/** operations on locales: **/ -extern void locale_setstring(struct locale * lang, const char * key, const char * value); -extern const char * locale_getstring(const struct locale * lang, const char * key); -extern const char * locale_string(const struct locale * lang, const char * key); /* does fallback */ -extern unsigned int locale_hashkey(const struct locale * lang); -extern const char * locale_name(const struct locale * lang); - -extern const char * mkname(const char * namespc, const char * key); -extern char * mkname_buf(const char * namespc, const char * key, char * buffer); - -extern void debug_language(const char * log); -extern void make_locales(const char * str); - -#define LOC(lang, s) (lang?locale_string(lang, s):s) - -extern struct locale * default_locale; -extern struct locale * locales; -extern struct locale * nextlocale(const struct locale * lang); - -enum { - UT_PARAMS, - UT_KEYWORDS, - UT_SKILLS, - UT_RACES, - UT_OPTIONS, - UT_DIRECTIONS, - UT_ARCHETYPES, - UT_MAGIC, - UT_TERRAINS, - UT_SPECDIR, - UT_MAX -}; - -struct tnode * get_translations(const struct locale * lang, int index); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef MY_LOCALE_H +#define MY_LOCALE_H +#ifdef __cplusplus +extern "C" { +#endif + +struct locale; + +/** managing multiple locales: **/ +extern struct locale * find_locale(const char * name); +extern struct locale * make_locale(const char * key); + +/** operations on locales: **/ +extern void locale_setstring(struct locale * lang, const char * key, const char * value); +extern const char * locale_getstring(const struct locale * lang, const char * key); +extern const char * locale_string(const struct locale * lang, const char * key); /* does fallback */ +extern unsigned int locale_hashkey(const struct locale * lang); +extern const char * locale_name(const struct locale * lang); + +extern const char * mkname(const char * namespc, const char * key); +extern char * mkname_buf(const char * namespc, const char * key, char * buffer); + +extern void debug_language(const char * log); +extern void make_locales(const char * str); + +#define LOC(lang, s) (lang?locale_string(lang, s):s) + +extern struct locale * default_locale; +extern struct locale * locales; +extern struct locale * nextlocale(const struct locale * lang); + +enum { + UT_PARAMS, + UT_KEYWORDS, + UT_SKILLS, + UT_RACES, + UT_OPTIONS, + UT_DIRECTIONS, + UT_ARCHETYPES, + UT_MAGIC, + UT_TERRAINS, + UT_SPECDIR, + UT_MAX +}; + +struct tnode * get_translations(const struct locale * lang, int index); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/language_struct.h b/src/util/language_struct.h index 700464eb8..1f09a071b 100644 --- a/src/util/language_struct.h +++ b/src/util/language_struct.h @@ -1,28 +1,28 @@ -#ifndef CLASS_LANGUAGE_STRUCT -#define CLASS_LANGUAGE_STRUCT - -/* This file should not be included by anything in the server. If you - * feel that you need to include it, it's a sure sign that you're trying to - * do something BAD. */ - -#define MAXLOCALES 3 -#define SMAXHASH 2048 -typedef struct locale_str { - unsigned int hashkey; - struct locale_str * nexthash; - char * str; - char * key; -} locale_str; - -typedef struct locale { - int index; - struct locale * next; - unsigned int hashkey; - const char * name; - struct locale_str * strings[SMAXHASH]; -} locale; - -extern locale * default_locale; -extern locale * locales; - -#endif +#ifndef CLASS_LANGUAGE_STRUCT +#define CLASS_LANGUAGE_STRUCT + +/* This file should not be included by anything in the server. If you + * feel that you need to include it, it's a sure sign that you're trying to + * do something BAD. */ + +#define MAXLOCALES 3 +#define SMAXHASH 2048 +typedef struct locale_str { + unsigned int hashkey; + struct locale_str * nexthash; + char * str; + char * key; +} locale_str; + +typedef struct locale { + int index; + struct locale * next; + unsigned int hashkey; + const char * name; + struct locale_str * strings[SMAXHASH]; +} locale; + +extern locale * default_locale; +extern locale * locales; + +#endif diff --git a/src/util/listbox.c b/src/util/listbox.c index 330b877c8..508d5bd3c 100644 --- a/src/util/listbox.c +++ b/src/util/listbox.c @@ -1,191 +1,191 @@ -/* vi: set ts=2: -* +-------------------+ Christian Schlittchen -* | | Enno Rehling -* | Eressea PBEM host | Katja Zedel -* | (c) 1998 - 2006 | -* | | This program may not be used, modified or distributed -* +-------------------+ without prior permission by the authors of Eressea. -* -*/ - -/* wenn platform.h nicht vor curses included wird, kompiliert es unter windows nicht */ -#include -#include - -#include "listbox.h" - -#include -#include - -void -insert_selection(list_selection ** p_sel, list_selection * prev, const char * str, void * payload) -{ - list_selection * sel = calloc(sizeof(list_selection), 1); - sel->str = strdup(str); - sel->data = payload; - if (*p_sel) { - list_selection * s; - sel->next = *p_sel; - sel->prev = sel->next->prev; - sel->next->prev=sel; - if (sel->prev) { - sel->prev->next = sel; - sel->index=sel->prev->index+1; - } - for (s=sel->next;s;s=s->next) { - s->index = s->prev->index+1; - } - *p_sel = sel; - } else { - *p_sel = sel; - sel->prev = prev; - if (prev) sel->index=prev->index+1; - } -} - -list_selection ** -push_selection(list_selection ** p_sel, char * str, void * payload) -{ - list_selection * sel = calloc(sizeof(list_selection), 1); - list_selection * prev = NULL; - sel->str = str; - sel->data = payload; - while (*p_sel) { - prev = *p_sel; - p_sel=&prev->next; - } - *p_sel = sel; - if (prev) { - sel->prev = prev; - sel->index = prev->index+1; - } - return p_sel; -} - -#define SX (stdscr->_maxx) -#define SY (stdscr->_maxy) - -list_selection * -do_selection(list_selection * sel, const char * title, void (*perform)(list_selection *, void *), void * data) -{ - WINDOW * wn; - boolean update = true; - list_selection *s; - list_selection *top = sel; - list_selection *current = top; - int i; - int height = 0, width = (int)strlen(title)+8; - for (s=sel;s;s=s->next) { - if ((int)strlen(s->str)>width) width = (int)strlen(s->str); - ++height; - } - if (height==0 || width==0) return NULL; - if (width+3>SX) width=SX-4; - if (height+2>SY) height=SY-2; - - wn = newwin(height+2, width+4, (SY - height - 2) / 2, (SX - width - 4) / 2); - - for (;;) { - int input; - if (update) { - for (s=top;s!=NULL && top->index+height!=s->index;s=s->next) { - i = s->index-top->index; - wmove(wn, i + 1, 4); - waddnstr(wn, s->str, -1); - wclrtoeol(wn); - } - wborder(wn, 0, 0, 0, 0, 0, 0, 0, 0); - mvwprintw(wn, 0, 2, "[ %s ]", title); - update = false; - } - i = current->index-top->index; - wattron(wn, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - wmove(wn, i + 1, 2); - waddstr(wn, "->"); - wmove(wn, i + 1, 4); - waddnstr(wn, current->str, -1); - wattroff(wn, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - - wrefresh(wn); - - input = getch(); - - wmove(wn, i + 1, 2); - waddstr(wn, " "); - wmove(wn, i + 1, 4); - waddnstr(wn, current->str, width); - - switch (input) { - case KEY_NPAGE: - for (i=0;i!=height/2;++i) { - if (current->next) { - current = current->next; - if (current->index-height>=top->index) { - top=current; - update = true; - } - } - } - break; - case KEY_PPAGE: - for (i=0;i!=height/2;++i) { - if (current->prev) { - if (current==top) { - top = sel; - while (top->index+heightindex) top=top->next; - update = true; - } - current = current->prev; - } - } - break; - case KEY_DOWN: - if (current->next) { - current = current->next; - if (current->index-height>=top->index) { - top=current; - update = true; - } - } - break; - case KEY_UP: - if (current->prev) { - if (current==top) { - top = sel; - while (top->index+heightindex) top=top->next; - update = true; - } - current = current->prev; - } - break; - case 27: - case 'q': - delwin(wn); - return NULL; - case 10: - case 13: - if (perform) perform(current, data); - else { - delwin(wn); - return current; - } - break; - default: - s = current->next; - if (s==NULL) s = top; - while (s!=current) { - if (tolower(s->str[0])==tolower(input)) { - current = s; - update = true; - } else { - s = s->next; - if (s==NULL) s = top; - } - } - if (current->index-height>=top->index) { - top=current; - update = true; - } - } - } -} +/* vi: set ts=2: +* +-------------------+ Christian Schlittchen +* | | Enno Rehling +* | Eressea PBEM host | Katja Zedel +* | (c) 1998 - 2006 | +* | | This program may not be used, modified or distributed +* +-------------------+ without prior permission by the authors of Eressea. +* +*/ + +/* wenn platform.h nicht vor curses included wird, kompiliert es unter windows nicht */ +#include +#include + +#include "listbox.h" + +#include +#include + +void +insert_selection(list_selection ** p_sel, list_selection * prev, const char * str, void * payload) +{ + list_selection * sel = calloc(sizeof(list_selection), 1); + sel->str = strdup(str); + sel->data = payload; + if (*p_sel) { + list_selection * s; + sel->next = *p_sel; + sel->prev = sel->next->prev; + sel->next->prev=sel; + if (sel->prev) { + sel->prev->next = sel; + sel->index=sel->prev->index+1; + } + for (s=sel->next;s;s=s->next) { + s->index = s->prev->index+1; + } + *p_sel = sel; + } else { + *p_sel = sel; + sel->prev = prev; + if (prev) sel->index=prev->index+1; + } +} + +list_selection ** +push_selection(list_selection ** p_sel, char * str, void * payload) +{ + list_selection * sel = calloc(sizeof(list_selection), 1); + list_selection * prev = NULL; + sel->str = str; + sel->data = payload; + while (*p_sel) { + prev = *p_sel; + p_sel=&prev->next; + } + *p_sel = sel; + if (prev) { + sel->prev = prev; + sel->index = prev->index+1; + } + return p_sel; +} + +#define SX (stdscr->_maxx) +#define SY (stdscr->_maxy) + +list_selection * +do_selection(list_selection * sel, const char * title, void (*perform)(list_selection *, void *), void * data) +{ + WINDOW * wn; + boolean update = true; + list_selection *s; + list_selection *top = sel; + list_selection *current = top; + int i; + int height = 0, width = (int)strlen(title)+8; + for (s=sel;s;s=s->next) { + if ((int)strlen(s->str)>width) width = (int)strlen(s->str); + ++height; + } + if (height==0 || width==0) return NULL; + if (width+3>SX) width=SX-4; + if (height+2>SY) height=SY-2; + + wn = newwin(height+2, width+4, (SY - height - 2) / 2, (SX - width - 4) / 2); + + for (;;) { + int input; + if (update) { + for (s=top;s!=NULL && top->index+height!=s->index;s=s->next) { + i = s->index-top->index; + wmove(wn, i + 1, 4); + waddnstr(wn, s->str, -1); + wclrtoeol(wn); + } + wborder(wn, 0, 0, 0, 0, 0, 0, 0, 0); + mvwprintw(wn, 0, 2, "[ %s ]", title); + update = false; + } + i = current->index-top->index; + wattron(wn, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + wmove(wn, i + 1, 2); + waddstr(wn, "->"); + wmove(wn, i + 1, 4); + waddnstr(wn, current->str, -1); + wattroff(wn, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); + + wrefresh(wn); + + input = getch(); + + wmove(wn, i + 1, 2); + waddstr(wn, " "); + wmove(wn, i + 1, 4); + waddnstr(wn, current->str, width); + + switch (input) { + case KEY_NPAGE: + for (i=0;i!=height/2;++i) { + if (current->next) { + current = current->next; + if (current->index-height>=top->index) { + top=current; + update = true; + } + } + } + break; + case KEY_PPAGE: + for (i=0;i!=height/2;++i) { + if (current->prev) { + if (current==top) { + top = sel; + while (top->index+heightindex) top=top->next; + update = true; + } + current = current->prev; + } + } + break; + case KEY_DOWN: + if (current->next) { + current = current->next; + if (current->index-height>=top->index) { + top=current; + update = true; + } + } + break; + case KEY_UP: + if (current->prev) { + if (current==top) { + top = sel; + while (top->index+heightindex) top=top->next; + update = true; + } + current = current->prev; + } + break; + case 27: + case 'q': + delwin(wn); + return NULL; + case 10: + case 13: + if (perform) perform(current, data); + else { + delwin(wn); + return current; + } + break; + default: + s = current->next; + if (s==NULL) s = top; + while (s!=current) { + if (tolower(s->str[0])==tolower(input)) { + current = s; + update = true; + } else { + s = s->next; + if (s==NULL) s = top; + } + } + if (current->index-height>=top->index) { + top=current; + update = true; + } + } + } +} diff --git a/src/util/listbox.h b/src/util/listbox.h index 5ff85f1b1..ab2c7f9bc 100644 --- a/src/util/listbox.h +++ b/src/util/listbox.h @@ -1,16 +1,16 @@ -#ifndef CURSES_LISTBOX -#define CURSES_LISTBOX - -typedef struct list_selection { - struct list_selection * next; - struct list_selection * prev; - int index; - char * str; - void * data; -} list_selection; - -extern struct list_selection * do_selection(struct list_selection * sel, const char * title, void (*perform)(struct list_selection *, void *), void * data); -extern struct list_selection ** push_selection(struct list_selection ** p_sel, char * str, void * payload); -extern void insert_selection(struct list_selection ** p_sel, struct list_selection * prev, const char * str, void * payload); - -#endif /* CURSES_LISTBOX */ +#ifndef CURSES_LISTBOX +#define CURSES_LISTBOX + +typedef struct list_selection { + struct list_selection * next; + struct list_selection * prev; + int index; + char * str; + void * data; +} list_selection; + +extern struct list_selection * do_selection(struct list_selection * sel, const char * title, void (*perform)(struct list_selection *, void *), void * data); +extern struct list_selection ** push_selection(struct list_selection ** p_sel, char * str, void * payload); +extern void insert_selection(struct list_selection ** p_sel, struct list_selection * prev, const char * str, void * payload); + +#endif /* CURSES_LISTBOX */ diff --git a/src/util/lists.c b/src/util/lists.c index 7411406b2..cff4b287c 100644 --- a/src/util/lists.c +++ b/src/util/lists.c @@ -1,143 +1,143 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include - -#include -#include "lists.h" - -void -addlist(void *l1, void *p1) -{ - - /* add entry p to the end of list l */ - - void_list **l; - void_list *p, *q; - - l = (void_list **)l1; - p = (void_list *)p1; - assert(p->next == 0); - - if (*l) { - for (q = *l; q->next; q = q->next) - assert(q); - q->next = p; - } else - *l = p; -} - -void -choplist(void * a, void * b) -{ - void_list **l = (void_list**)a, *p = (void_list*)b; - /* remove entry p from list l - when called, a pointer to p must be - * kept in order to use (and free) p; if omitted, this will be a - * memory leak */ - - void_list **q; - - for (q = l; *q; q = &((*q)->next)) { - if (*q == p) { - *q = p->next; - p->next = 0; - break; - } - } -} - -void -translist(void *l1, void *l2, void *p) -{ - - /* remove entry p from list l1 and add it at the end of list l2 */ - - choplist(l1, p); - addlist(l2, p); -} - -void -insertlist(void_list ** l, void_list * p) -{ - - /* insert entry p at the beginning of list l */ - - p->next = *l; - *l = p; - -} - -void -removelist(void *l, void *p) -{ - - /* remove entry p from list l; free p */ - - choplist(l, p); - free(p); -} - -void -freelist(void *p1) -{ - - /* remove all entries following and including entry p from a listlist */ - - void_list *p, *p2; - - p = (void_list *)p1; - - while (p) { - p2 = p->next; - free(p); - p = p2; - } -} - -unsigned int -listlen(void *l) -{ - - /* count entries p in list l */ - - unsigned int i; - void_list *p; - - for (p = (void_list *)l, i = 0; p; p = p->next, i++); - return i; -} - -/* Hilfsfunktion, um das Debugging zu erleichtern. Statt print - * (cast)foo->next->next->next->next nur noch - * print (cast)listelem(foo, 3) */ - -void * -listelem(void *l, int n) -{ - int i=0; - - while(i < n && l != NULL) { - l = ((void_list *)l)->next; - i++; - } - - return l; -} - - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include + +#include +#include "lists.h" + +void +addlist(void *l1, void *p1) +{ + + /* add entry p to the end of list l */ + + void_list **l; + void_list *p, *q; + + l = (void_list **)l1; + p = (void_list *)p1; + assert(p->next == 0); + + if (*l) { + for (q = *l; q->next; q = q->next) + assert(q); + q->next = p; + } else + *l = p; +} + +void +choplist(void * a, void * b) +{ + void_list **l = (void_list**)a, *p = (void_list*)b; + /* remove entry p from list l - when called, a pointer to p must be + * kept in order to use (and free) p; if omitted, this will be a + * memory leak */ + + void_list **q; + + for (q = l; *q; q = &((*q)->next)) { + if (*q == p) { + *q = p->next; + p->next = 0; + break; + } + } +} + +void +translist(void *l1, void *l2, void *p) +{ + + /* remove entry p from list l1 and add it at the end of list l2 */ + + choplist(l1, p); + addlist(l2, p); +} + +void +insertlist(void_list ** l, void_list * p) +{ + + /* insert entry p at the beginning of list l */ + + p->next = *l; + *l = p; + +} + +void +removelist(void *l, void *p) +{ + + /* remove entry p from list l; free p */ + + choplist(l, p); + free(p); +} + +void +freelist(void *p1) +{ + + /* remove all entries following and including entry p from a listlist */ + + void_list *p, *p2; + + p = (void_list *)p1; + + while (p) { + p2 = p->next; + free(p); + p = p2; + } +} + +unsigned int +listlen(void *l) +{ + + /* count entries p in list l */ + + unsigned int i; + void_list *p; + + for (p = (void_list *)l, i = 0; p; p = p->next, i++); + return i; +} + +/* Hilfsfunktion, um das Debugging zu erleichtern. Statt print + * (cast)foo->next->next->next->next nur noch + * print (cast)listelem(foo, 3) */ + +void * +listelem(void *l, int n) +{ + int i=0; + + while(i < n && l != NULL) { + l = ((void_list *)l)->next; + i++; + } + + return l; +} + + diff --git a/src/util/lists.h b/src/util/lists.h index 1fe3638d6..588cc4878 100644 --- a/src/util/lists.h +++ b/src/util/lists.h @@ -1,55 +1,55 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef LISTS_H -#define LISTS_H -#ifdef __cplusplus -extern "C" { -#endif - -#include - -typedef struct void_list { - struct void_list * next; - void * data; -} void_list; - -#define list_foreach(type, list, item) item=list; while (item!=NULL) { type* __next__=item->next; -#define list_continue(item) { item=__next__; continue; } -#define list_next(item) item=__next__; } - -void addlist(void *l1, void *p1); -void choplist(void * l, void * p); -void translist(void *l1, void *l2, void *p); -#ifndef MALLOCDBG -void freelist(void *p1); -void removelist(void *l, void *p); -#else -#define freelist(p) { while (p) { void * p2 = p->next; free(p); p = p2; } } -#define removelist(l,p) { choplist(l, p); free(p); } -#endif - -unsigned int listlen(void *l); -#define addlist2(l, p) (*l = p, l = &p->next) - -void *listelem(void *l, int n); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef LISTS_H +#define LISTS_H +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef struct void_list { + struct void_list * next; + void * data; +} void_list; + +#define list_foreach(type, list, item) item=list; while (item!=NULL) { type* __next__=item->next; +#define list_continue(item) { item=__next__; continue; } +#define list_next(item) item=__next__; } + +void addlist(void *l1, void *p1); +void choplist(void * l, void * p); +void translist(void *l1, void *l2, void *p); +#ifndef MALLOCDBG +void freelist(void *p1); +void removelist(void *l, void *p); +#else +#define freelist(p) { while (p) { void * p2 = p->next; free(p); p = p2; } } +#define removelist(l,p) { choplist(l, p); free(p); } +#endif + +unsigned int listlen(void *l); +#define addlist2(l, p) (*l = p, l = &p->next) + +void *listelem(void *l, int n); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/log.c b/src/util/log.c index 92c4c3ef8..7b5b22ff6 100644 --- a/src/util/log.c +++ b/src/util/log.c @@ -1,288 +1,288 @@ -/* vi: set ts=2: -+-------------------+ Christian Schlittchen -| | Enno Rehling -| Eressea PBEM host | Katja Zedel -| (c) 1998 - 2003 | Henning Peters -| | Ingo Wilken -+-------------------+ Stefan Reich - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ -#include -#include "log.h" -#include "unicode.h" - -#include -#include -#include -#include -#include - -/* TODO: set from external function */ -int log_flags = LOG_FLUSH|LOG_CPERROR|LOG_CPWARNING; -#ifdef STDIO_CP -static int stdio_codepage = STDIO_CP; -#else -static int stdio_codepage = 0; -#endif -static FILE * logfile; - -#define MAXLENGTH 4096 /* because I am lazy, CP437 output is limited to this many chars */ -void -log_flush(void) -{ - fflush(logfile); -} - -void -log_puts(const char * str) -{ - fflush(stdout); - if (!logfile) logfile = stderr; - fputs(str, logfile); -} - -static int -cp_convert(const char * format, char * buffer, size_t length, int codepage) -{ - /* when console output on MSDOS, convert to codepage */ - const char * input = format; - char * pos = buffer; - - while (pos+1=level) { - fprintf(logfile, "INFO[%u]: ", level); - va_start(marker, format); - vfprintf(logfile, format, marker); - va_end(marker); - if (logfile!=stderr) { - if (stderr_level>=level) { - fprintf(stderr, "INFO[%u]: ", level); - va_start(marker, format); - if (stdio_codepage) { - char buffer[MAXLENGTH]; - char converted[MAXLENGTH]; - - vsnprintf(buffer, sizeof(buffer), format, marker); - if (cp_convert(buffer, converted, MAXLENGTH, stdio_codepage)==0) { - fputs(converted, stderr); - } else { - /* fall back to non-converted output */ - va_end(marker); - va_start(marker, format); - vfprintf(stderr, format, marker); - } - } else { - vfprintf(stderr, format, marker); - } - va_end(marker); - } - if (log_flags & LOG_FLUSH) { - log_flush(); - } - } - } -} +/* vi: set ts=2: ++-------------------+ Christian Schlittchen +| | Enno Rehling +| Eressea PBEM host | Katja Zedel +| (c) 1998 - 2003 | Henning Peters +| | Ingo Wilken ++-------------------+ Stefan Reich + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ +#include +#include "log.h" +#include "unicode.h" + +#include +#include +#include +#include +#include + +/* TODO: set from external function */ +int log_flags = LOG_FLUSH|LOG_CPERROR|LOG_CPWARNING; +#ifdef STDIO_CP +static int stdio_codepage = STDIO_CP; +#else +static int stdio_codepage = 0; +#endif +static FILE * logfile; + +#define MAXLENGTH 4096 /* because I am lazy, CP437 output is limited to this many chars */ +void +log_flush(void) +{ + fflush(logfile); +} + +void +log_puts(const char * str) +{ + fflush(stdout); + if (!logfile) logfile = stderr; + fputs(str, logfile); +} + +static int +cp_convert(const char * format, char * buffer, size_t length, int codepage) +{ + /* when console output on MSDOS, convert to codepage */ + const char * input = format; + char * pos = buffer; + + while (pos+1=level) { + fprintf(logfile, "INFO[%u]: ", level); + va_start(marker, format); + vfprintf(logfile, format, marker); + va_end(marker); + if (logfile!=stderr) { + if (stderr_level>=level) { + fprintf(stderr, "INFO[%u]: ", level); + va_start(marker, format); + if (stdio_codepage) { + char buffer[MAXLENGTH]; + char converted[MAXLENGTH]; + + vsnprintf(buffer, sizeof(buffer), format, marker); + if (cp_convert(buffer, converted, MAXLENGTH, stdio_codepage)==0) { + fputs(converted, stderr); + } else { + /* fall back to non-converted output */ + va_end(marker); + va_start(marker, format); + vfprintf(stderr, format, marker); + } + } else { + vfprintf(stderr, format, marker); + } + va_end(marker); + } + if (log_flags & LOG_FLUSH) { + log_flush(); + } + } + } +} diff --git a/src/util/log.h b/src/util/log.h index 0fc454610..87a35dfee 100644 --- a/src/util/log.h +++ b/src/util/log.h @@ -1,45 +1,45 @@ -/* vi: set ts=2: -+-------------------+ Christian Schlittchen -| | Enno Rehling -| Eressea PBEM host | Katja Zedel -| (c) 1998 - 2003 | Henning Peters -| | Ingo Wilken -+-------------------+ Stefan Reich - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ -#ifndef H_UTIL_LOG -#define H_UTIL_LOG -#ifdef __cplusplus -extern "C" { -#endif - - extern void log_open(const char * filename); - extern void log_printf(const char * str, ...); - extern void log_puts(const char * str); - extern void log_close(void); - extern void log_flush(void); - extern void log_stdio(FILE * io, const char * format, ...); - -#define log_warning(x) _log_warn x -#define log_error(x) _log_error x -#define log_info(x) _log_info x - - /* use macros above instead of these: */ - extern void _log_warn(const char * format, ...); - extern void _log_error(const char * format, ...); - extern void _log_info(unsigned int flag, const char * format, ...); - -#define LOG_FLUSH 0x01 -#define LOG_CPWARNING 0x02 -#define LOG_CPERROR 0x04 -#define LOG_INFO1 0x08 -#define LOG_INFO2 0x10 -#define LOG_INFO3 0x20 - - extern int log_flags; -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: ++-------------------+ Christian Schlittchen +| | Enno Rehling +| Eressea PBEM host | Katja Zedel +| (c) 1998 - 2003 | Henning Peters +| | Ingo Wilken ++-------------------+ Stefan Reich + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ +#ifndef H_UTIL_LOG +#define H_UTIL_LOG +#ifdef __cplusplus +extern "C" { +#endif + + extern void log_open(const char * filename); + extern void log_printf(const char * str, ...); + extern void log_puts(const char * str); + extern void log_close(void); + extern void log_flush(void); + extern void log_stdio(FILE * io, const char * format, ...); + +#define log_warning(x) _log_warn x +#define log_error(x) _log_error x +#define log_info(x) _log_info x + + /* use macros above instead of these: */ + extern void _log_warn(const char * format, ...); + extern void _log_error(const char * format, ...); + extern void _log_info(unsigned int flag, const char * format, ...); + +#define LOG_FLUSH 0x01 +#define LOG_CPWARNING 0x02 +#define LOG_CPERROR 0x04 +#define LOG_INFO1 0x08 +#define LOG_INFO2 0x10 +#define LOG_INFO3 0x20 + + extern int log_flags; +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/message.c b/src/util/message.c index cf3048512..243b6ba40 100644 --- a/src/util/message.c +++ b/src/util/message.c @@ -1,237 +1,237 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - -*/ - -#include -#include "message.h" - -#include "goodies.h" -#include "log.h" - -/* libc includes */ -#include -#include -#include -#include -#include - -void (*msg_log_create)(const struct message * msg) = 0; - -const char * -mt_name(const message_type* mtype) -{ - return mtype->name; -} - -message_type * -mt_new(const char * name, const char * args[]) -{ - int i, nparameters = 0; - message_type * mtype = (message_type *)malloc(sizeof(message_type)); - - assert(name!=NULL); - if (name==NULL) { - log_error(("Trying to create message_type with name=0x0\n")); - return NULL; - } - if (args!=NULL) for (nparameters=0;args[nparameters];++nparameters); - - mtype->name = strdup(name); - mtype->nparameters = nparameters; - if (nparameters > 0) { - mtype->pnames = (const char**)malloc(sizeof(char*) * nparameters); - mtype->types = (const arg_type**)malloc(sizeof(arg_type*) * nparameters); - } else { - mtype->pnames = NULL; - mtype->types = NULL; - } - if (args!=NULL) for (i=0;args[i];++i) { - const char * x = args[i]; - const char * spos = strchr(x, ':'); - if (spos==NULL) { - mtype->pnames[i] = strdup(x); - mtype->types[i] = NULL; - } else { - char * cp = strncpy((char*)malloc(spos-x+1), x, spos-x); - cp[spos-x] = '\0'; - mtype->pnames[i] = cp; - mtype->types[i] = find_argtype(spos+1); - if (mtype->types[i]==NULL) { - log_error(("unknown argument type %s for message type %s\n", - spos+1, mtype->name)); - } - assert(mtype->types[i]); - } - } - return mtype; -} - -message_type * -mt_new_va(const char * name, ...) -{ - const char * args[16]; - int i = 0; - va_list marker; - - va_start(marker, name); - for (;;) { - const char * c = va_arg(marker, const char*); - args[i++] = c; - if (c==NULL) break; - } - va_end(marker); - return mt_new(name, args); -} - -arg_type * argtypes = NULL; - -void -register_argtype(const char * name, void(*free_arg)(variant), variant (*copy_arg)(variant), variant_type type) -{ - arg_type * atype = (arg_type *)malloc(sizeof(arg_type)); - atype->name = name; - atype->next = argtypes; - atype->release = free_arg; - atype->copy = copy_arg; - atype->vtype = type; - argtypes = atype; -} - -const arg_type * -find_argtype(const char * name) -{ - arg_type * atype = argtypes; - while (atype!=NULL) { - if (strcmp(atype->name, name)==0) return atype; - atype = atype->next; - } - return NULL; -} - -static variant -copy_arg(const arg_type * atype, variant data) -{ - assert(atype!=NULL); - if (atype->copy==NULL) return data; - return atype->copy(data); -} - -static void -free_arg(const arg_type * atype, variant data) -{ - assert(atype!=NULL); - if (atype->release) atype->release(data); -} - -message * -msg_create(const struct message_type * mtype, variant args[]) -{ - int i; - message * msg = (message *)malloc(sizeof(message)); - - assert(mtype!=NULL); - if (mtype==NULL) { - log_error(("Trying to create message with type=0x0\n")); - return NULL; - } - msg->type = mtype; - msg->parameters = (variant*)calloc(mtype->nparameters, sizeof(variant)); - msg->refcount=1; - for (i=0;i!=mtype->nparameters;++i) { - msg->parameters[i] = copy_arg(mtype->types[i], args[i]); - } - if (msg_log_create) msg_log_create(msg); - return msg; -} - -typedef struct messagetype_list { - struct messagetype_list * next; - const struct message_type * data; -} messagetype_list; - -#define MT_MAXHASH 1021 -static messagetype_list * messagetypes[MT_MAXHASH]; - -const message_type * -mt_find(const char * name) -{ - const struct message_type * found = NULL; - unsigned int hash = hashstring(name) % MT_MAXHASH; - messagetype_list * type = messagetypes[hash]; - while (type) { - if (strcmp(type->data->name, name)==0) { - if (found==NULL) found = type->data; - break; - } - type = type->next; - } - return found; -} - -static unsigned int -mt_id(const message_type * mtype) -{ - unsigned int key = 0; - size_t i = strlen(mtype->name); - - while (i>0) { - key = (mtype->name[--i] + key*37); - } - return key % 0x7FFFFFFF; -} - - -const message_type * -mt_register(message_type * type) -{ - unsigned int hash = hashstring(type->name) % MT_MAXHASH; - messagetype_list * mtl = messagetypes[hash]; - - while (mtl && mtl->data!=type) mtl=mtl->next; - if (mtl==NULL) { - mtl = (messagetype_list*)malloc(sizeof(messagetype_list)); - mtl->data = type; - mtl->next = messagetypes[hash]; - messagetypes[hash] = mtl; - type->key = mt_id(type); - } - return type; -} - -void -msg_free(message *msg) -{ - int i; - assert(msg->refcount==0); - for (i=0;i!=msg->type->nparameters;++i) { - free_arg(msg->type->types[i], msg->parameters[i]); - } - free((void*)msg->parameters); - free(msg); -} - -void -msg_release(struct message * msg) -{ - assert(msg->refcount>0); - if (--msg->refcount>0) return; - msg_free(msg); -} - -struct message * -msg_addref(struct message * msg) -{ - assert(msg->refcount>0); - ++msg->refcount; - return msg; -} - +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + +*/ + +#include +#include "message.h" + +#include "goodies.h" +#include "log.h" + +/* libc includes */ +#include +#include +#include +#include +#include + +void (*msg_log_create)(const struct message * msg) = 0; + +const char * +mt_name(const message_type* mtype) +{ + return mtype->name; +} + +message_type * +mt_new(const char * name, const char * args[]) +{ + int i, nparameters = 0; + message_type * mtype = (message_type *)malloc(sizeof(message_type)); + + assert(name!=NULL); + if (name==NULL) { + log_error(("Trying to create message_type with name=0x0\n")); + return NULL; + } + if (args!=NULL) for (nparameters=0;args[nparameters];++nparameters); + + mtype->name = strdup(name); + mtype->nparameters = nparameters; + if (nparameters > 0) { + mtype->pnames = (const char**)malloc(sizeof(char*) * nparameters); + mtype->types = (const arg_type**)malloc(sizeof(arg_type*) * nparameters); + } else { + mtype->pnames = NULL; + mtype->types = NULL; + } + if (args!=NULL) for (i=0;args[i];++i) { + const char * x = args[i]; + const char * spos = strchr(x, ':'); + if (spos==NULL) { + mtype->pnames[i] = strdup(x); + mtype->types[i] = NULL; + } else { + char * cp = strncpy((char*)malloc(spos-x+1), x, spos-x); + cp[spos-x] = '\0'; + mtype->pnames[i] = cp; + mtype->types[i] = find_argtype(spos+1); + if (mtype->types[i]==NULL) { + log_error(("unknown argument type %s for message type %s\n", + spos+1, mtype->name)); + } + assert(mtype->types[i]); + } + } + return mtype; +} + +message_type * +mt_new_va(const char * name, ...) +{ + const char * args[16]; + int i = 0; + va_list marker; + + va_start(marker, name); + for (;;) { + const char * c = va_arg(marker, const char*); + args[i++] = c; + if (c==NULL) break; + } + va_end(marker); + return mt_new(name, args); +} + +arg_type * argtypes = NULL; + +void +register_argtype(const char * name, void(*free_arg)(variant), variant (*copy_arg)(variant), variant_type type) +{ + arg_type * atype = (arg_type *)malloc(sizeof(arg_type)); + atype->name = name; + atype->next = argtypes; + atype->release = free_arg; + atype->copy = copy_arg; + atype->vtype = type; + argtypes = atype; +} + +const arg_type * +find_argtype(const char * name) +{ + arg_type * atype = argtypes; + while (atype!=NULL) { + if (strcmp(atype->name, name)==0) return atype; + atype = atype->next; + } + return NULL; +} + +static variant +copy_arg(const arg_type * atype, variant data) +{ + assert(atype!=NULL); + if (atype->copy==NULL) return data; + return atype->copy(data); +} + +static void +free_arg(const arg_type * atype, variant data) +{ + assert(atype!=NULL); + if (atype->release) atype->release(data); +} + +message * +msg_create(const struct message_type * mtype, variant args[]) +{ + int i; + message * msg = (message *)malloc(sizeof(message)); + + assert(mtype!=NULL); + if (mtype==NULL) { + log_error(("Trying to create message with type=0x0\n")); + return NULL; + } + msg->type = mtype; + msg->parameters = (variant*)calloc(mtype->nparameters, sizeof(variant)); + msg->refcount=1; + for (i=0;i!=mtype->nparameters;++i) { + msg->parameters[i] = copy_arg(mtype->types[i], args[i]); + } + if (msg_log_create) msg_log_create(msg); + return msg; +} + +typedef struct messagetype_list { + struct messagetype_list * next; + const struct message_type * data; +} messagetype_list; + +#define MT_MAXHASH 1021 +static messagetype_list * messagetypes[MT_MAXHASH]; + +const message_type * +mt_find(const char * name) +{ + const struct message_type * found = NULL; + unsigned int hash = hashstring(name) % MT_MAXHASH; + messagetype_list * type = messagetypes[hash]; + while (type) { + if (strcmp(type->data->name, name)==0) { + if (found==NULL) found = type->data; + break; + } + type = type->next; + } + return found; +} + +static unsigned int +mt_id(const message_type * mtype) +{ + unsigned int key = 0; + size_t i = strlen(mtype->name); + + while (i>0) { + key = (mtype->name[--i] + key*37); + } + return key % 0x7FFFFFFF; +} + + +const message_type * +mt_register(message_type * type) +{ + unsigned int hash = hashstring(type->name) % MT_MAXHASH; + messagetype_list * mtl = messagetypes[hash]; + + while (mtl && mtl->data!=type) mtl=mtl->next; + if (mtl==NULL) { + mtl = (messagetype_list*)malloc(sizeof(messagetype_list)); + mtl->data = type; + mtl->next = messagetypes[hash]; + messagetypes[hash] = mtl; + type->key = mt_id(type); + } + return type; +} + +void +msg_free(message *msg) +{ + int i; + assert(msg->refcount==0); + for (i=0;i!=msg->type->nparameters;++i) { + free_arg(msg->type->types[i], msg->parameters[i]); + } + free((void*)msg->parameters); + free(msg); +} + +void +msg_release(struct message * msg) +{ + assert(msg->refcount>0); + if (--msg->refcount>0) return; + msg_free(msg); +} + +struct message * +msg_addref(struct message * msg) +{ + assert(msg->refcount>0); + ++msg->refcount; + return msg; +} + diff --git a/src/util/message.h b/src/util/message.h index 060d71301..021283903 100644 --- a/src/util/message.h +++ b/src/util/message.h @@ -1,71 +1,71 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ -#ifndef UTIL_MESSAGE_H -#define UTIL_MESSAGE_H - -#include "variant.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct locale; - -typedef struct arg_type { - struct arg_type * next; - variant_type vtype; - const char * name; - void (*release)(variant); - variant (*copy)(variant); -} arg_type; - -typedef struct message_type { - unsigned int key; - const char * name; - int nparameters; - const char ** pnames; - const struct arg_type ** types; -} message_type; - -typedef struct message { - const struct message_type * type; - variant * parameters; - int refcount; -} message; - -extern struct message_type * mt_new(const char * name, const char ** args); -extern struct message_type * mt_new_va(const char * name, ...); - /* mt_new("simple_sentence", "subject:string", "predicate:string", - * "object:string", "lang:locale", NULL); */ - -extern struct message * msg_create(const struct message_type * type, variant args[]); - /* msg_create(&mt_simplesentence, "enno", "eats", "chocolate", &locale_de); - * parameters must be in the same order as they were for mt_new! */ - -extern void msg_release(struct message * msg); -extern struct message * msg_addref(struct message * msg); - -extern const char * mt_name(const struct message_type* mtype); - -/** message_type registry (optional): **/ -extern const struct message_type * mt_register(struct message_type *); -extern const struct message_type * mt_find(const char *); - -extern void register_argtype(const char * name, void(*free_arg)(variant), variant (*copy_arg)(variant), variant_type); -extern const struct arg_type * find_argtype(const char * name); - -extern void (*msg_log_create)(const struct message * msg); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#ifndef UTIL_MESSAGE_H +#define UTIL_MESSAGE_H + +#include "variant.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct locale; + +typedef struct arg_type { + struct arg_type * next; + variant_type vtype; + const char * name; + void (*release)(variant); + variant (*copy)(variant); +} arg_type; + +typedef struct message_type { + unsigned int key; + const char * name; + int nparameters; + const char ** pnames; + const struct arg_type ** types; +} message_type; + +typedef struct message { + const struct message_type * type; + variant * parameters; + int refcount; +} message; + +extern struct message_type * mt_new(const char * name, const char ** args); +extern struct message_type * mt_new_va(const char * name, ...); + /* mt_new("simple_sentence", "subject:string", "predicate:string", + * "object:string", "lang:locale", NULL); */ + +extern struct message * msg_create(const struct message_type * type, variant args[]); + /* msg_create(&mt_simplesentence, "enno", "eats", "chocolate", &locale_de); + * parameters must be in the same order as they were for mt_new! */ + +extern void msg_release(struct message * msg); +extern struct message * msg_addref(struct message * msg); + +extern const char * mt_name(const struct message_type* mtype); + +/** message_type registry (optional): **/ +extern const struct message_type * mt_register(struct message_type *); +extern const struct message_type * mt_find(const char *); + +extern void register_argtype(const char * name, void(*free_arg)(variant), variant (*copy_arg)(variant), variant_type); +extern const struct arg_type * find_argtype(const char * name); + +extern void (*msg_log_create)(const struct message * msg); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/nrmessage.c b/src/util/nrmessage.c index 50587deb8..0086159d5 100644 --- a/src/util/nrmessage.c +++ b/src/util/nrmessage.c @@ -1,174 +1,174 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - -*/ - -#include -#include "nrmessage.h" -#include "nrmessage_struct.h" - -/* util includes */ -#include "bsdstring.h" -#include "log.h" -#include "message.h" -#include "language.h" -#include "translation.h" -#include "goodies.h" - -/* libc includes */ -#include -#include -#include - -#define NRT_MAXHASH 1021 -static nrmessage_type * nrtypes[NRT_MAXHASH]; - -const char * -nrt_string(const struct nrmessage_type *type) -{ - return type->string; -} - -nrmessage_type * -nrt_find(const struct locale * lang, const struct message_type * mtype) -{ - nrmessage_type * found = NULL; - unsigned int hash = hashstring(mtype->name) % NRT_MAXHASH; - nrmessage_type * type = nrtypes[hash]; - while (type) { - if (type->mtype==mtype) { - if (found==NULL) found = type; - else if (type->lang==NULL) found = type; - if (lang==type->lang) { - found = type; - break; - } - } - type = type->next; - } - if (!found) { - log_warning(("could not find nr-type %s for locale %s\n", - mtype->name, locale_name(lang))); - } - if (lang && found && found->lang!=lang) { - log_warning(("could not find nr-type %s for locale %s, using %s\n", - mtype->name, locale_name(lang), locale_name(found->lang))); - } - return found; -} - -nrsection * sections; - -const nrsection * -section_find(const char * name) -{ - nrsection ** mcp = §ions; - if (name==NULL) return NULL; - for (;*mcp;mcp=&(*mcp)->next) { - nrsection * mc = *mcp; - if (!strcmp(mc->name, name)) break; - } - return *mcp; -} - -const nrsection * -section_add(const char * name) -{ - nrsection ** mcp = §ions; - if (name==NULL) return NULL; - for (;*mcp;mcp=&(*mcp)->next) { - nrsection * mc = *mcp; - if (!strcmp(mc->name, name)) break; - } - if (!*mcp) { - nrsection * mc = calloc(sizeof(nrsection), 1); - mc->name = strdup(name); - *mcp = mc; - } - return *mcp; -} - -void -nrt_register(const struct message_type * mtype, const struct locale * lang, const char * string, int level, const char * section) -{ - unsigned int hash = hashstring(mtype->name) % NRT_MAXHASH; - nrmessage_type * nrt = nrtypes[hash]; - while (nrt && (nrt->lang!=lang || nrt->mtype!=mtype)) { - nrt = nrt->next; - } - if (nrt) { - log_error(("duplicate message-type %s\n", mtype->name)); - assert(!nrt || !"trying to register same nr-type twice"); - } else { - int i; - char zNames[256]; - char * c = zNames; - nrt = malloc(sizeof(nrmessage_type)); - nrt->lang = lang; - nrt->mtype = mtype; - nrt->next = nrtypes[hash]; - nrt->level=level; - if (section) { - const nrsection * s = section_find(section); - if (s==NULL) { - s = section_add(section); - } - nrt->section = s->name; - } - else nrt->section = NULL; - nrtypes[hash] = nrt; - assert(string && *string); - nrt->string = strdup(string); - *c = '\0'; - for (i=0;i!=mtype->nparameters;++i) { - if (i!=0) *c++ = ' '; - c+= strlen(strcpy(c, mtype->pnames[i])); - } - nrt->vars = strdup(zNames); - } -} - -size_t -nr_render(const struct message * msg, const struct locale * lang, char * buffer, size_t size, const void * userdata) -{ - struct nrmessage_type * nrt = nrt_find(lang, msg->type); - - if (nrt) { - const char * m = translate(nrt->string, userdata, nrt->vars, msg->parameters); - if (m) { - return strlcpy((char*)buffer, m, size); - } else { - log_error(("Couldn't render message %s\n", nrt->mtype->name)); - } - } - if (size>0 && buffer) buffer[0] = 0; - return 0; -} - -int -nr_level(const struct message *msg) -{ - nrmessage_type * nrt = nrt_find(NULL, msg->type); - return nrt?nrt->level:0; -} - -const char * -nr_section(const struct message *msg) -{ - nrmessage_type * nrt = nrt_find(default_locale, msg->type); - return nrt?nrt->section:NULL; -} - -const char * -nrt_section(const nrmessage_type * nrt) -{ - return nrt?nrt->section:NULL; -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + +*/ + +#include +#include "nrmessage.h" +#include "nrmessage_struct.h" + +/* util includes */ +#include "bsdstring.h" +#include "log.h" +#include "message.h" +#include "language.h" +#include "translation.h" +#include "goodies.h" + +/* libc includes */ +#include +#include +#include + +#define NRT_MAXHASH 1021 +static nrmessage_type * nrtypes[NRT_MAXHASH]; + +const char * +nrt_string(const struct nrmessage_type *type) +{ + return type->string; +} + +nrmessage_type * +nrt_find(const struct locale * lang, const struct message_type * mtype) +{ + nrmessage_type * found = NULL; + unsigned int hash = hashstring(mtype->name) % NRT_MAXHASH; + nrmessage_type * type = nrtypes[hash]; + while (type) { + if (type->mtype==mtype) { + if (found==NULL) found = type; + else if (type->lang==NULL) found = type; + if (lang==type->lang) { + found = type; + break; + } + } + type = type->next; + } + if (!found) { + log_warning(("could not find nr-type %s for locale %s\n", + mtype->name, locale_name(lang))); + } + if (lang && found && found->lang!=lang) { + log_warning(("could not find nr-type %s for locale %s, using %s\n", + mtype->name, locale_name(lang), locale_name(found->lang))); + } + return found; +} + +nrsection * sections; + +const nrsection * +section_find(const char * name) +{ + nrsection ** mcp = §ions; + if (name==NULL) return NULL; + for (;*mcp;mcp=&(*mcp)->next) { + nrsection * mc = *mcp; + if (!strcmp(mc->name, name)) break; + } + return *mcp; +} + +const nrsection * +section_add(const char * name) +{ + nrsection ** mcp = §ions; + if (name==NULL) return NULL; + for (;*mcp;mcp=&(*mcp)->next) { + nrsection * mc = *mcp; + if (!strcmp(mc->name, name)) break; + } + if (!*mcp) { + nrsection * mc = calloc(sizeof(nrsection), 1); + mc->name = strdup(name); + *mcp = mc; + } + return *mcp; +} + +void +nrt_register(const struct message_type * mtype, const struct locale * lang, const char * string, int level, const char * section) +{ + unsigned int hash = hashstring(mtype->name) % NRT_MAXHASH; + nrmessage_type * nrt = nrtypes[hash]; + while (nrt && (nrt->lang!=lang || nrt->mtype!=mtype)) { + nrt = nrt->next; + } + if (nrt) { + log_error(("duplicate message-type %s\n", mtype->name)); + assert(!nrt || !"trying to register same nr-type twice"); + } else { + int i; + char zNames[256]; + char * c = zNames; + nrt = malloc(sizeof(nrmessage_type)); + nrt->lang = lang; + nrt->mtype = mtype; + nrt->next = nrtypes[hash]; + nrt->level=level; + if (section) { + const nrsection * s = section_find(section); + if (s==NULL) { + s = section_add(section); + } + nrt->section = s->name; + } + else nrt->section = NULL; + nrtypes[hash] = nrt; + assert(string && *string); + nrt->string = strdup(string); + *c = '\0'; + for (i=0;i!=mtype->nparameters;++i) { + if (i!=0) *c++ = ' '; + c+= strlen(strcpy(c, mtype->pnames[i])); + } + nrt->vars = strdup(zNames); + } +} + +size_t +nr_render(const struct message * msg, const struct locale * lang, char * buffer, size_t size, const void * userdata) +{ + struct nrmessage_type * nrt = nrt_find(lang, msg->type); + + if (nrt) { + const char * m = translate(nrt->string, userdata, nrt->vars, msg->parameters); + if (m) { + return strlcpy((char*)buffer, m, size); + } else { + log_error(("Couldn't render message %s\n", nrt->mtype->name)); + } + } + if (size>0 && buffer) buffer[0] = 0; + return 0; +} + +int +nr_level(const struct message *msg) +{ + nrmessage_type * nrt = nrt_find(NULL, msg->type); + return nrt?nrt->level:0; +} + +const char * +nr_section(const struct message *msg) +{ + nrmessage_type * nrt = nrt_find(default_locale, msg->type); + return nrt?nrt->section:NULL; +} + +const char * +nrt_section(const nrmessage_type * nrt) +{ + return nrt?nrt->section:NULL; +} diff --git a/src/util/nrmessage.h b/src/util/nrmessage.h index 53a1fdc78..f36d8e79f 100644 --- a/src/util/nrmessage.h +++ b/src/util/nrmessage.h @@ -1,56 +1,56 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_UTIL_NRMESSAGE -#define H_UTIL_NRMESSAGE -#ifdef __cplusplus -extern "C" { -#endif - -struct locale; -struct message; -struct message_type; -struct nrmessage_type; - -typedef struct nrsection { - char * name; - struct nrsection * next; -} nrsection; - -extern nrsection * sections; - -extern void nrt_register(const struct message_type * mtype, - const struct locale * lang, const char * script, - int level, const char * section); -extern struct nrmessage_type * nrt_find(const struct locale *, - const struct message_type *); -extern const char * nrt_string(const struct nrmessage_type *type); -extern const char * nrt_section(const struct nrmessage_type * mt); - -extern size_t nr_render(const struct message * msg, const struct locale * lang, - char * buffer, size_t size, const void * userdata); -extern int nr_level(const struct message *msg); -extern const char * nr_section(const struct message *msg); - - -/* before: - * fogblock;movement:0;de;{unit} konnte von {region} nicht nach {$dir direction} ausreisen, der Nebel war zu dicht. - * after: - * fogblock:movement:0 - * $unit($unit) konnte von $region($region) nicht nach $direction($direction) ausreisen, der Nebel war zu dicht. - * unit:unit region:region direction:int - */ - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_UTIL_NRMESSAGE +#define H_UTIL_NRMESSAGE +#ifdef __cplusplus +extern "C" { +#endif + +struct locale; +struct message; +struct message_type; +struct nrmessage_type; + +typedef struct nrsection { + char * name; + struct nrsection * next; +} nrsection; + +extern nrsection * sections; + +extern void nrt_register(const struct message_type * mtype, + const struct locale * lang, const char * script, + int level, const char * section); +extern struct nrmessage_type * nrt_find(const struct locale *, + const struct message_type *); +extern const char * nrt_string(const struct nrmessage_type *type); +extern const char * nrt_section(const struct nrmessage_type * mt); + +extern size_t nr_render(const struct message * msg, const struct locale * lang, + char * buffer, size_t size, const void * userdata); +extern int nr_level(const struct message *msg); +extern const char * nr_section(const struct message *msg); + + +/* before: + * fogblock;movement:0;de;{unit} konnte von {region} nicht nach {$dir direction} ausreisen, der Nebel war zu dicht. + * after: + * fogblock:movement:0 + * $unit($unit) konnte von $region($region) nicht nach $direction($direction) ausreisen, der Nebel war zu dicht. + * unit:unit region:region direction:int + */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/nrmessage_struct.h b/src/util/nrmessage_struct.h index 3d36249df..ac14bef82 100644 --- a/src/util/nrmessage_struct.h +++ b/src/util/nrmessage_struct.h @@ -1,20 +1,20 @@ -#ifndef CLASS_NRMESSAGE_STRUCT -#define CLASS_NRMESSAGE_STRUCT - -/* This file should not be included by anything in the server. If you - * feel that you need to include it, it's a sure sign that you're trying to - * do something BAD. */ - -typedef struct nrmessage_type { - const struct message_type * mtype; - const struct locale * lang; - const char * string; - const char * vars; - struct nrmessage_type * next; - int level; - const char * section; -} nrmessage_type; - -extern nrmessage_type * get_nrmessagetypes(void); - -#endif +#ifndef CLASS_NRMESSAGE_STRUCT +#define CLASS_NRMESSAGE_STRUCT + +/* This file should not be included by anything in the server. If you + * feel that you need to include it, it's a sure sign that you're trying to + * do something BAD. */ + +typedef struct nrmessage_type { + const struct message_type * mtype; + const struct locale * lang; + const char * string; + const char * vars; + struct nrmessage_type * next; + int level; + const char * section; +} nrmessage_type; + +extern nrmessage_type * get_nrmessagetypes(void); + +#endif diff --git a/src/util/parser.c b/src/util/parser.c index f9944b9a6..1dfff3798 100644 --- a/src/util/parser.c +++ b/src/util/parser.c @@ -1,195 +1,195 @@ -#include -#include "parser.h" -#include "unicode.h" -#include "log.h" - -#include -#include -#include - -#define SPACE_REPLACEMENT '~' -#define ESCAPE_CHAR '\\' -#define MAXTOKENSIZE 8192 - -typedef struct parser_state { - const char *current_token; - char * current_cmd; - struct parser_state * next; -} parser_state; - -static parser_state * state; - -static int -eatwhitespace_c(const char ** str_p) -{ - int ret = 0; - ucs4_t ucs; - size_t len; - const char * str = *str_p; - - /* skip over potential whitespace */ - for (;;) { - unsigned char utf8_character = (unsigned char)*str; - if (~utf8_character & 0x80) { - if (!iswxspace(utf8_character)) break; - ++str; - } else { - ret = unicode_utf8_to_ucs4(&ucs, str, &len); - if (ret!=0) { - log_warning(("illegal character sequence in UTF8 string: %s\n", str)); - break; - } - if (!iswxspace((wint_t)ucs)) break; - str+=len; - } - } - *str_p = str; - return ret; -} - -void -init_tokens_str(const char * initstr, char * cmd) -{ - if (state==NULL) { - state = malloc(sizeof(parser_state)); - } - else if (state->current_cmd) free(state->current_cmd); - state->current_cmd = cmd; - state->current_token = initstr; -} - -void -parser_pushstate(void) -{ - parser_state * new_state = malloc(sizeof(parser_state)); - new_state->current_cmd = NULL; - new_state->current_token = NULL; - new_state->next = state; - state = new_state; -} - -void -parser_popstate(void) -{ - parser_state * new_state = state->next; - if (state->current_cmd!=NULL) free(state->current_cmd); - free(state); - state = new_state; -} - -boolean -parser_end(void) -{ - eatwhitespace_c(&state->current_token); - return *state->current_token == 0; -} - -void -skip_token(void) -{ - char quotechar = 0; - eatwhitespace_c(&state->current_token); - - while (*state->current_token) { - ucs4_t ucs; - size_t len; - - unsigned char utf8_character = (unsigned char)state->current_token[0]; - if (~utf8_character & 0x80) { - ucs = utf8_character; - ++state->current_token; - } else { - int ret = unicode_utf8_to_ucs4(&ucs, state->current_token, &len); - if (ret==0) { - state->current_token+=len; - } else { - log_warning(("illegal character sequence in UTF8 string: %s\n", state->current_token)); - } - } - if (iswxspace((wint_t)ucs) && quotechar==0) { - return; - } else { - switch(utf8_character) { - case '"': - case '\'': - if (utf8_character==quotechar) return; - quotechar = utf8_character; - break; - case ESCAPE_CHAR: - ++state->current_token; - break; - } - } - } -} - -const char * -parse_token(const char ** str) -{ - static char lbuf[MAXTOKENSIZE]; /* STATIC_RESULT: used for return, not across calls */ - char * cursor = lbuf; - char quotechar = 0; - boolean escape = false; - const char * ctoken = *str; - - assert(ctoken); - - eatwhitespace_c(&ctoken); - while (*ctoken && cursor-lbuf < MAXTOKENSIZE-1) { - ucs4_t ucs; - size_t len; - boolean copy = false; - - unsigned char utf8_character = *(unsigned char *)ctoken; - if (~utf8_character & 0x80) { - ucs = utf8_character; - len = 1; - } else { - int ret = unicode_utf8_to_ucs4(&ucs, ctoken, &len); - if (ret!=0) { - log_warning(("illegal character sequence in UTF8 string: %s\n", ctoken)); - break; - } - } - if (escape) { - copy = true; - escape = false; - } else if (iswxspace((wint_t)ucs)) { - if (quotechar==0) break; - copy = true; - } else if (utf8_character=='"' || utf8_character=='\'') { - if (utf8_character==quotechar) { - ++ctoken; - break; - } else if (quotechar==0) { - quotechar = utf8_character; - ++ctoken; - } else { - *cursor++ = *ctoken++; - } - } else if (utf8_character==SPACE_REPLACEMENT) { - *cursor++ = ' '; - ++ctoken; - } else if (utf8_character==ESCAPE_CHAR) { - escape = true; - ++ctoken; - } else { - copy = true; - } - if (copy) { - memcpy(cursor, ctoken, len); - cursor+=len; - ctoken+=len; - } - } - - *cursor = '\0'; - *str = ctoken; - return lbuf; -} - -const char * -getstrtoken(void) -{ - return parse_token((const char **)&state->current_token); -} +#include +#include "parser.h" +#include "unicode.h" +#include "log.h" + +#include +#include +#include + +#define SPACE_REPLACEMENT '~' +#define ESCAPE_CHAR '\\' +#define MAXTOKENSIZE 8192 + +typedef struct parser_state { + const char *current_token; + char * current_cmd; + struct parser_state * next; +} parser_state; + +static parser_state * state; + +static int +eatwhitespace_c(const char ** str_p) +{ + int ret = 0; + ucs4_t ucs; + size_t len; + const char * str = *str_p; + + /* skip over potential whitespace */ + for (;;) { + unsigned char utf8_character = (unsigned char)*str; + if (~utf8_character & 0x80) { + if (!iswxspace(utf8_character)) break; + ++str; + } else { + ret = unicode_utf8_to_ucs4(&ucs, str, &len); + if (ret!=0) { + log_warning(("illegal character sequence in UTF8 string: %s\n", str)); + break; + } + if (!iswxspace((wint_t)ucs)) break; + str+=len; + } + } + *str_p = str; + return ret; +} + +void +init_tokens_str(const char * initstr, char * cmd) +{ + if (state==NULL) { + state = malloc(sizeof(parser_state)); + } + else if (state->current_cmd) free(state->current_cmd); + state->current_cmd = cmd; + state->current_token = initstr; +} + +void +parser_pushstate(void) +{ + parser_state * new_state = malloc(sizeof(parser_state)); + new_state->current_cmd = NULL; + new_state->current_token = NULL; + new_state->next = state; + state = new_state; +} + +void +parser_popstate(void) +{ + parser_state * new_state = state->next; + if (state->current_cmd!=NULL) free(state->current_cmd); + free(state); + state = new_state; +} + +boolean +parser_end(void) +{ + eatwhitespace_c(&state->current_token); + return *state->current_token == 0; +} + +void +skip_token(void) +{ + char quotechar = 0; + eatwhitespace_c(&state->current_token); + + while (*state->current_token) { + ucs4_t ucs; + size_t len; + + unsigned char utf8_character = (unsigned char)state->current_token[0]; + if (~utf8_character & 0x80) { + ucs = utf8_character; + ++state->current_token; + } else { + int ret = unicode_utf8_to_ucs4(&ucs, state->current_token, &len); + if (ret==0) { + state->current_token+=len; + } else { + log_warning(("illegal character sequence in UTF8 string: %s\n", state->current_token)); + } + } + if (iswxspace((wint_t)ucs) && quotechar==0) { + return; + } else { + switch(utf8_character) { + case '"': + case '\'': + if (utf8_character==quotechar) return; + quotechar = utf8_character; + break; + case ESCAPE_CHAR: + ++state->current_token; + break; + } + } + } +} + +const char * +parse_token(const char ** str) +{ + static char lbuf[MAXTOKENSIZE]; /* STATIC_RESULT: used for return, not across calls */ + char * cursor = lbuf; + char quotechar = 0; + boolean escape = false; + const char * ctoken = *str; + + assert(ctoken); + + eatwhitespace_c(&ctoken); + while (*ctoken && cursor-lbuf < MAXTOKENSIZE-1) { + ucs4_t ucs; + size_t len; + boolean copy = false; + + unsigned char utf8_character = *(unsigned char *)ctoken; + if (~utf8_character & 0x80) { + ucs = utf8_character; + len = 1; + } else { + int ret = unicode_utf8_to_ucs4(&ucs, ctoken, &len); + if (ret!=0) { + log_warning(("illegal character sequence in UTF8 string: %s\n", ctoken)); + break; + } + } + if (escape) { + copy = true; + escape = false; + } else if (iswxspace((wint_t)ucs)) { + if (quotechar==0) break; + copy = true; + } else if (utf8_character=='"' || utf8_character=='\'') { + if (utf8_character==quotechar) { + ++ctoken; + break; + } else if (quotechar==0) { + quotechar = utf8_character; + ++ctoken; + } else { + *cursor++ = *ctoken++; + } + } else if (utf8_character==SPACE_REPLACEMENT) { + *cursor++ = ' '; + ++ctoken; + } else if (utf8_character==ESCAPE_CHAR) { + escape = true; + ++ctoken; + } else { + copy = true; + } + if (copy) { + memcpy(cursor, ctoken, len); + cursor+=len; + ctoken+=len; + } + } + + *cursor = '\0'; + *str = ctoken; + return lbuf; +} + +const char * +getstrtoken(void) +{ + return parse_token((const char **)&state->current_token); +} diff --git a/src/util/parser.h b/src/util/parser.h index d856ef9cb..fecb5ff9f 100644 --- a/src/util/parser.h +++ b/src/util/parser.h @@ -1,29 +1,29 @@ -/* vi: set ts=2: - * +-------------------+ Christian Schlittchen - * | | Enno Rehling - * | Eressea PBEM host | Katja Zedel - * | (c) 1998 - 2007 | - * | | This program may not be used, modified or distributed - * +-------------------+ without prior permission by the authors of Eressea. - * - */ - -#ifndef UTIL_PARSER_H -#define UTIL_PARSER_H -#ifdef __cplusplus -extern "C" { -#endif - -extern void init_tokens_str(const char * initstr, char * cmd); /* initialize token parsing, take ownership of cmd */ -extern void skip_token(void); -extern const char * parse_token(const char ** str); -extern void parser_pushstate(void); -extern void parser_popstate(void); -extern boolean parser_end(void); -extern const char *getstrtoken(void); - -#ifdef __cplusplus -} -#endif - -#endif +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2007 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +#ifndef UTIL_PARSER_H +#define UTIL_PARSER_H +#ifdef __cplusplus +extern "C" { +#endif + +extern void init_tokens_str(const char * initstr, char * cmd); /* initialize token parsing, take ownership of cmd */ +extern void skip_token(void); +extern const char * parse_token(const char ** str); +extern void parser_pushstate(void); +extern void parser_popstate(void); +extern boolean parser_end(void); +extern const char *getstrtoken(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/util/patricia.c b/src/util/patricia.c index cafd71e3a..4189f146b 100644 --- a/src/util/patricia.c +++ b/src/util/patricia.c @@ -1,236 +1,236 @@ -#include - -#include -#include -#include - -#include "patricia.h" - -#define MAXKEYLEN 128 - -/* TODO: custom memory management to optimize cache layout, or use arrays. */ - -/* NOTE: The structure saves an extra 0 delimiter for the key. Technically - * this wouldn't be necessary (because we know its' length from data[0]), - * but it makes it possible for trie_getkey to return a key without making - * a copy or have a cumbersome (const char**, size_t*) interface. - * +-----------+-------------+------+------------+ - * data: | keylen(1) | key(keylen) | 0(1) | data(size) | - * +-----------+-------------+------+------------+ - */ - -struct trie_node { - struct trie_node *l, *r; - char * data; - unsigned int bitpos; -}; - -#if 1 -#define get_bit(c, s, p) (unsigned int)((((p)>>3)>(unsigned int)(s))?0:((c)[(p)>>3]>>((p)&7)&1)) -#else -unsigned int get_bit(const char * c, size_t s, unsigned int p) -{ - if ((p>>3)>=(unsigned int)s) return 0; - return ((c)[p>>3]>>(p&7)&1); -} -#endif -#define node_bit(n, p) get_bit((n)->data+1, (n)->data[0], (p)) - -trie_node * trie_insert(trie_node **root_p, const char * key, const void * data, size_t size) -{ - trie_node * new_node; - size_t keylen = strlen(key); - trie_node ** insert_p = root_p, *node = *insert_p; - unsigned int p, bit=0; - - assert(keylenbitpos) { - insert_p = bit?&node->r:&node->l; - node = *insert_p; - if (node==NULL) { - continue; - } - } - - /* if we are looking at a back-node, we need to add our node before it. */ - if (p>=node->bitpos) { - /* find the point p where both differ. */ - if (keylen==(unsigned int)node->data[0] && strncmp(key, node->data+1, keylen)==0) { - /* we are trying to insert the same key again */ - - return node; - } - do { - ++p; - bit = get_bit(key, keylen, p); - } while (node_bit(node, p)==bit); - break; - } - - /* if instead we differ before reaching the end of the current prefix, we must split. - * we insert our node before the current one and re-attach it. */ - if (node_bit(node, p)!=bit) { - break; - } - } - - new_node = (trie_node *)malloc(sizeof(trie_node)); - new_node->bitpos = p; - new_node->data = malloc(keylen+2+size); - new_node->data[0] = (char)keylen; - memcpy(new_node->data+1, key, keylen+1); - if (data!=NULL && size>0) { - /* if data is NULL then the user only wanted some space that they're going to write to later */ - /* if size is 0 then the user is using the trie as a set, not a map */ - memcpy(new_node->data+2+keylen, data, size); - } - if (bit) { - new_node->l = node; - new_node->r = new_node; /* loop the 1-bit to ourselves, search will end */ - } else { - new_node->l = new_node; /* loop the 0-bit to ourselves, search will end */ - new_node->r = node; - } - *insert_p = new_node; - return new_node; -} - -void trie_remove(trie_node **root_p, trie_node *pos) -{ - if (pos!=NULL) { - const char * key = trie_getkey(pos); - size_t keylen = pos->data[0]; - trie_node ** node_p = root_p; - trie_node * node = *root_p; - - while (node) { - int bit; - trie_node ** next_p; - trie_node * next; - - if (node == pos) { - if (node->l==node) { - *node_p = node->r; - break; - } else if (node->r==node) { - *node_p = node->l; - break; - } - } - - bit = get_bit(key, keylen, node->bitpos); - next_p = bit?&node->r:&node->l; - next = *next_p; - if (next == pos && next->bitpos<=node->bitpos) { - /* the element that has a back-pointer to pos gets swapped with pos */ - char * data = pos->data; - pos->data = node->data; - node->data = data; - - /* finally, find the back-pointer to node and set it to pos */ - next_p = bit?&node->l:&node->r; /* NB: this is the OTHER child of node */ - next = *next_p; - key = trie_getkey(node); - keylen = (unsigned int)node->data[0]; - while (next) { - int new_bit; - if (next==node) { - *next_p = pos; - break; - } - new_bit = get_bit(key, keylen, next->bitpos); - next_p = new_bit?&next->r:&next->l; - next = *next_p; - } - *node_p = bit?node->l:node->r; - break; - } - node = *next_p; - node_p = next_p; - } - free(node->data); - free(node); - } -} - -void trie_debug(trie_node * root) -{ - const char * l = root->l?trie_getkey(root->l):"?"; - const char * r = root->r?trie_getkey(root->r):"?"; - printf("%s %d | %s | %s\n", trie_getkey(root), root->bitpos, l, r); - if (root->l && root->l->bitpos > root->bitpos) trie_debug(root->l); - if (root->r && root->r->bitpos > root->bitpos) trie_debug(root->r); -} - -trie_node * trie_find(trie_node *root, const char *key) -{ - trie_node * node = root; - size_t keylen = strlen(key); - - while (node) { - int bit = get_bit(key, keylen, node->bitpos); - trie_node * next = bit?node->r:node->l; - - if (next!=NULL) { - if (node->bitpos>=next->bitpos) { - if (keylen==(unsigned int)next->data[0] && strncmp(key, next->data+1, keylen)==0) { - return next; - } - next = NULL; - } - } - node = next; - } - return NULL; -} - -trie_node * trie_find_prefix(trie_node *root, const char *key) -{ - trie_node * node = root; - size_t keylen = strlen(key); - - while (node) { - int bit = get_bit(key, keylen, node->bitpos); - trie_node * next = bit?node->r:node->l; - - if (next!=NULL) { - if (node->bitpos>=next->bitpos) { - if (keylen<=(unsigned int)next->data[0] && strncmp(key, next->data+1, keylen)==0) { - return next; - } - next = NULL; - } - } - node = next; - } - return NULL; -} - -void * trie_getdata(trie_node * node) -{ - return node->data+2+node->data[0]; -} - -const char * trie_getkey(trie_node * node) -{ - return node->data+1; -} - -void trie_free(trie_node * root) -{ - if (root) { - if (root->l && root->l->bitpos>root->bitpos) trie_free(root->l); - if (root->r && root->r->bitpos>root->bitpos) trie_free(root->r); - free(root); - } -} +#include + +#include +#include +#include + +#include "patricia.h" + +#define MAXKEYLEN 128 + +/* TODO: custom memory management to optimize cache layout, or use arrays. */ + +/* NOTE: The structure saves an extra 0 delimiter for the key. Technically + * this wouldn't be necessary (because we know its' length from data[0]), + * but it makes it possible for trie_getkey to return a key without making + * a copy or have a cumbersome (const char**, size_t*) interface. + * +-----------+-------------+------+------------+ + * data: | keylen(1) | key(keylen) | 0(1) | data(size) | + * +-----------+-------------+------+------------+ + */ + +struct trie_node { + struct trie_node *l, *r; + char * data; + unsigned int bitpos; +}; + +#if 1 +#define get_bit(c, s, p) (unsigned int)((((p)>>3)>(unsigned int)(s))?0:((c)[(p)>>3]>>((p)&7)&1)) +#else +unsigned int get_bit(const char * c, size_t s, unsigned int p) +{ + if ((p>>3)>=(unsigned int)s) return 0; + return ((c)[p>>3]>>(p&7)&1); +} +#endif +#define node_bit(n, p) get_bit((n)->data+1, (n)->data[0], (p)) + +trie_node * trie_insert(trie_node **root_p, const char * key, const void * data, size_t size) +{ + trie_node * new_node; + size_t keylen = strlen(key); + trie_node ** insert_p = root_p, *node = *insert_p; + unsigned int p, bit=0; + + assert(keylenbitpos) { + insert_p = bit?&node->r:&node->l; + node = *insert_p; + if (node==NULL) { + continue; + } + } + + /* if we are looking at a back-node, we need to add our node before it. */ + if (p>=node->bitpos) { + /* find the point p where both differ. */ + if (keylen==(unsigned int)node->data[0] && strncmp(key, node->data+1, keylen)==0) { + /* we are trying to insert the same key again */ + + return node; + } + do { + ++p; + bit = get_bit(key, keylen, p); + } while (node_bit(node, p)==bit); + break; + } + + /* if instead we differ before reaching the end of the current prefix, we must split. + * we insert our node before the current one and re-attach it. */ + if (node_bit(node, p)!=bit) { + break; + } + } + + new_node = (trie_node *)malloc(sizeof(trie_node)); + new_node->bitpos = p; + new_node->data = malloc(keylen+2+size); + new_node->data[0] = (char)keylen; + memcpy(new_node->data+1, key, keylen+1); + if (data!=NULL && size>0) { + /* if data is NULL then the user only wanted some space that they're going to write to later */ + /* if size is 0 then the user is using the trie as a set, not a map */ + memcpy(new_node->data+2+keylen, data, size); + } + if (bit) { + new_node->l = node; + new_node->r = new_node; /* loop the 1-bit to ourselves, search will end */ + } else { + new_node->l = new_node; /* loop the 0-bit to ourselves, search will end */ + new_node->r = node; + } + *insert_p = new_node; + return new_node; +} + +void trie_remove(trie_node **root_p, trie_node *pos) +{ + if (pos!=NULL) { + const char * key = trie_getkey(pos); + size_t keylen = pos->data[0]; + trie_node ** node_p = root_p; + trie_node * node = *root_p; + + while (node) { + int bit; + trie_node ** next_p; + trie_node * next; + + if (node == pos) { + if (node->l==node) { + *node_p = node->r; + break; + } else if (node->r==node) { + *node_p = node->l; + break; + } + } + + bit = get_bit(key, keylen, node->bitpos); + next_p = bit?&node->r:&node->l; + next = *next_p; + if (next == pos && next->bitpos<=node->bitpos) { + /* the element that has a back-pointer to pos gets swapped with pos */ + char * data = pos->data; + pos->data = node->data; + node->data = data; + + /* finally, find the back-pointer to node and set it to pos */ + next_p = bit?&node->l:&node->r; /* NB: this is the OTHER child of node */ + next = *next_p; + key = trie_getkey(node); + keylen = (unsigned int)node->data[0]; + while (next) { + int new_bit; + if (next==node) { + *next_p = pos; + break; + } + new_bit = get_bit(key, keylen, next->bitpos); + next_p = new_bit?&next->r:&next->l; + next = *next_p; + } + *node_p = bit?node->l:node->r; + break; + } + node = *next_p; + node_p = next_p; + } + free(node->data); + free(node); + } +} + +void trie_debug(trie_node * root) +{ + const char * l = root->l?trie_getkey(root->l):"?"; + const char * r = root->r?trie_getkey(root->r):"?"; + printf("%s %d | %s | %s\n", trie_getkey(root), root->bitpos, l, r); + if (root->l && root->l->bitpos > root->bitpos) trie_debug(root->l); + if (root->r && root->r->bitpos > root->bitpos) trie_debug(root->r); +} + +trie_node * trie_find(trie_node *root, const char *key) +{ + trie_node * node = root; + size_t keylen = strlen(key); + + while (node) { + int bit = get_bit(key, keylen, node->bitpos); + trie_node * next = bit?node->r:node->l; + + if (next!=NULL) { + if (node->bitpos>=next->bitpos) { + if (keylen==(unsigned int)next->data[0] && strncmp(key, next->data+1, keylen)==0) { + return next; + } + next = NULL; + } + } + node = next; + } + return NULL; +} + +trie_node * trie_find_prefix(trie_node *root, const char *key) +{ + trie_node * node = root; + size_t keylen = strlen(key); + + while (node) { + int bit = get_bit(key, keylen, node->bitpos); + trie_node * next = bit?node->r:node->l; + + if (next!=NULL) { + if (node->bitpos>=next->bitpos) { + if (keylen<=(unsigned int)next->data[0] && strncmp(key, next->data+1, keylen)==0) { + return next; + } + next = NULL; + } + } + node = next; + } + return NULL; +} + +void * trie_getdata(trie_node * node) +{ + return node->data+2+node->data[0]; +} + +const char * trie_getkey(trie_node * node) +{ + return node->data+1; +} + +void trie_free(trie_node * root) +{ + if (root) { + if (root->l && root->l->bitpos>root->bitpos) trie_free(root->l); + if (root->r && root->r->bitpos>root->bitpos) trie_free(root->r); + free(root); + } +} diff --git a/src/util/patricia.h b/src/util/patricia.h index 42efa89fc..f01be96be 100644 --- a/src/util/patricia.h +++ b/src/util/patricia.h @@ -1,21 +1,21 @@ -#ifndef H_PATRICIA -#define H_PATRICIA -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct trie_node trie_node; - -trie_node * trie_insert(trie_node **root, const char *key, const void *data, size_t size); -trie_node * trie_find(trie_node *root, const char *key); -void * trie_getdata(trie_node *node); -const char * trie_getkey(trie_node *node); -void trie_free(trie_node * root); -void trie_remove(trie_node **root_p, trie_node *pos); -void trie_debug(trie_node * root); -trie_node * trie_find_prefix(trie_node *root, const char *key); - -#ifdef __cplusplus -} -#endif -#endif +#ifndef H_PATRICIA +#define H_PATRICIA +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct trie_node trie_node; + +trie_node * trie_insert(trie_node **root, const char *key, const void *data, size_t size); +trie_node * trie_find(trie_node *root, const char *key); +void * trie_getdata(trie_node *node); +const char * trie_getkey(trie_node *node); +void trie_free(trie_node * root); +void trie_remove(trie_node **root_p, trie_node *pos); +void trie_debug(trie_node * root); +trie_node * trie_find_prefix(trie_node *root, const char *key); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/rand.c b/src/util/rand.c index 92f2b927a..9694c182c 100644 --- a/src/util/rand.c +++ b/src/util/rand.c @@ -1,72 +1,72 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "rand.h" -#include "rng.h" - -#include -#include -#include -#include -#include - -#define M_PIl 3.1415926535897932384626433832795029L /* pi */ - -/* NormalRand aus python, random.py geklaut, dort ist Referenz auf -* den Algorithmus. mu = Mittelwert, sigma = Standardabweichung. -* http://de.wikipedia.org/wiki/Standardabweichung#Diskrete_Gleichverteilung.2C_W.C3.BCrfel -*/ -double -normalvariate(double mu, double sigma) -{ - static const double NV_MAGICCONST = 1.7155277699214135; /* STATIC_CONST: a constant */ - double z; - for (;;) { - double u1 = rng_double(); - double u2 = 1.0 - rng_double(); - z = NV_MAGICCONST*(u1-0.5)/u2; - if (z*z/4.0 <= -log(u2)) { - break; - } - } - return mu+z*sigma; -} - -int -ntimespprob(int n, double p, double mod) -{ - int count = 0; - int i; - - for(i=0; i0; i++) { - if(rng_double() < p) { - count++; - p += mod; - } - } - return count; -} - -boolean -chance(double x) -{ - if (x>=1.0) return true; - return rng_double() < x; -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "rand.h" +#include "rng.h" + +#include +#include +#include +#include +#include + +#define M_PIl 3.1415926535897932384626433832795029L /* pi */ + +/* NormalRand aus python, random.py geklaut, dort ist Referenz auf +* den Algorithmus. mu = Mittelwert, sigma = Standardabweichung. +* http://de.wikipedia.org/wiki/Standardabweichung#Diskrete_Gleichverteilung.2C_W.C3.BCrfel +*/ +double +normalvariate(double mu, double sigma) +{ + static const double NV_MAGICCONST = 1.7155277699214135; /* STATIC_CONST: a constant */ + double z; + for (;;) { + double u1 = rng_double(); + double u2 = 1.0 - rng_double(); + z = NV_MAGICCONST*(u1-0.5)/u2; + if (z*z/4.0 <= -log(u2)) { + break; + } + } + return mu+z*sigma; +} + +int +ntimespprob(int n, double p, double mod) +{ + int count = 0; + int i; + + for(i=0; i0; i++) { + if(rng_double() < p) { + count++; + p += mod; + } + } + return count; +} + +boolean +chance(double x) +{ + if (x>=1.0) return true; + return rng_double() < x; +} + diff --git a/src/util/rand.h b/src/util/rand.h index 8e6999619..2c9d6e96b 100644 --- a/src/util/rand.h +++ b/src/util/rand.h @@ -1,37 +1,37 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef RAND_H -#define RAND_H -#ifdef __cplusplus -extern "C" { -#endif - - /* in dice.c: */ - extern int dice_rand(const char *str); - extern int dice(int count, int value); - - /* in rand.c: */ - extern double normalvariate(double mu, double sigma); - extern int ntimespprob(int n, double p, double mod); - extern boolean chance(double x); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef RAND_H +#define RAND_H +#ifdef __cplusplus +extern "C" { +#endif + + /* in dice.c: */ + extern int dice_rand(const char *str); + extern int dice(int count, int value); + + /* in rand.c: */ + extern double normalvariate(double mu, double sigma); + extern int ntimespprob(int n, double p, double mod); + extern boolean chance(double x); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/resolve.c b/src/util/resolve.c index 0166da066..224fbff52 100644 --- a/src/util/resolve.c +++ b/src/util/resolve.c @@ -1,96 +1,96 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include -#include "resolve.h" -#include "storage.h" -#include "variant.h" - -typedef struct unresolved { - void * ptrptr; - /* address to pass to the resolve-function */ - variant data; - /* information on how to resolve the missing object */ - resolve_fun resolve; - /* function to resolve the unknown object */ -} unresolved; - -#define BLOCKSIZE 1024 -static unresolved * ur_list; -static unresolved * ur_begin; -static unresolved * ur_current; - -variant -read_int(struct storage * store) -{ - variant var; - var.i = store->r_int(store); - return var; -} - -int -read_reference(void * address, storage * store, read_fun reader, resolve_fun resolver) -{ - variant var = reader(store); - int result = resolver(var, address); - if (result!=0) { - ur_add(var, address, resolver); - } - return result; -} - -void -ur_add(variant data, void * ptrptr, resolve_fun fun) -{ - if (ur_list==NULL) { - ur_list = malloc(BLOCKSIZE*sizeof(unresolved)); - ur_begin = ur_current = ur_list; - } - else if (ur_current-ur_begin==BLOCKSIZE-1) { - ur_begin = malloc(BLOCKSIZE*sizeof(unresolved)); - ur_current->data.v = ur_begin; - ur_current = ur_begin; - } - ur_current->data = data; - ur_current->resolve = fun; - ur_current->ptrptr = ptrptr; - - ++ur_current; - ur_current->resolve = NULL; - ur_current->data.v = NULL; -} - -void -resolve(void) -{ - unresolved * ur = ur_list; - while (ur) { - if (ur->resolve==NULL) { - ur = ur->data.v; - free(ur_list); - ur_list = ur; - continue; - } - ur->resolve(ur->data, ur->ptrptr); - ++ur; - } - free(ur_list); - ur_list = NULL; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include +#include "resolve.h" +#include "storage.h" +#include "variant.h" + +typedef struct unresolved { + void * ptrptr; + /* address to pass to the resolve-function */ + variant data; + /* information on how to resolve the missing object */ + resolve_fun resolve; + /* function to resolve the unknown object */ +} unresolved; + +#define BLOCKSIZE 1024 +static unresolved * ur_list; +static unresolved * ur_begin; +static unresolved * ur_current; + +variant +read_int(struct storage * store) +{ + variant var; + var.i = store->r_int(store); + return var; +} + +int +read_reference(void * address, storage * store, read_fun reader, resolve_fun resolver) +{ + variant var = reader(store); + int result = resolver(var, address); + if (result!=0) { + ur_add(var, address, resolver); + } + return result; +} + +void +ur_add(variant data, void * ptrptr, resolve_fun fun) +{ + if (ur_list==NULL) { + ur_list = malloc(BLOCKSIZE*sizeof(unresolved)); + ur_begin = ur_current = ur_list; + } + else if (ur_current-ur_begin==BLOCKSIZE-1) { + ur_begin = malloc(BLOCKSIZE*sizeof(unresolved)); + ur_current->data.v = ur_begin; + ur_current = ur_begin; + } + ur_current->data = data; + ur_current->resolve = fun; + ur_current->ptrptr = ptrptr; + + ++ur_current; + ur_current->resolve = NULL; + ur_current->data.v = NULL; +} + +void +resolve(void) +{ + unresolved * ur = ur_list; + while (ur) { + if (ur->resolve==NULL) { + ur = ur->data.v; + free(ur_list); + ur_list = ur; + continue; + } + ur->resolve(ur->data, ur->ptrptr); + ++ur; + } + free(ur_list); + ur_list = NULL; +} diff --git a/src/util/resolve.h b/src/util/resolve.h index f52345e68..c6deb4f77 100644 --- a/src/util/resolve.h +++ b/src/util/resolve.h @@ -1,41 +1,41 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef RESOLVE_H -#define RESOLVE_H - -#include "variant.h" -struct storage; - -#ifdef __cplusplus -extern "C" { -#endif - - typedef int (*resolve_fun)(variant data, void * address); - typedef variant (*read_fun)(struct storage* store); - extern int read_reference(void * address, struct storage * store, read_fun reader, resolve_fun resolver); - - extern void ur_add(variant data, void * address, resolve_fun fun); - extern void resolve(void); - - extern variant read_int(struct storage * store); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef RESOLVE_H +#define RESOLVE_H + +#include "variant.h" +struct storage; + +#ifdef __cplusplus +extern "C" { +#endif + + typedef int (*resolve_fun)(variant data, void * address); + typedef variant (*read_fun)(struct storage* store); + extern int read_reference(void * address, struct storage * store, read_fun reader, resolve_fun resolver); + + extern void ur_add(variant data, void * address, resolve_fun fun); + extern void resolve(void); + + extern variant read_int(struct storage * store); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/rng.h b/src/util/rng.h index 5092a32d4..3ef39d49e 100644 --- a/src/util/rng.h +++ b/src/util/rng.h @@ -1,45 +1,45 @@ -/* vi: set ts=2: - * +-------------------+ Christian Schlittchen - * | | Enno Rehling - * | Eressea PBEM host | Katja Zedel - * | (c) 1998 - 2005 | - * | | This program may not be used, modified or distributed - * +-------------------+ without prior permission by the authors of Eressea. - * - */ -#ifndef UTIL_RNG_H -#define UTIL_RNG_H -#ifdef __cplusplus -extern "C" { -#endif - -#define RNG_MT - -#ifdef RNG_MT - /* initializes mt[N] with a seed */ - extern void init_genrand(unsigned long s); - - /* generates a random number on [0,0xffffffff]-interval */ - extern unsigned long genrand_int32(void); - - /* generates a random number on [0,1)-real-interval */ - extern double genrand_real2(void); - - /* generates a random number on [0,0x7fffffff]-interval */ - long genrand_int31(void); - -# define rng_init(seed) init_genrand(seed) -# define rng_int genrand_int31 -# define rng_double genrand_real2 -# define RNG_RAND_MAX 0x7fffffff -#else -# include -# define rng_init(seed) srand(seed) -# define rng_int rand() -# define rng_double ((rand()%RAND_MAX)/(double)RAND_MAX) -# define RNG_RAND_MAX RAND_MAX -#endif -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + * +-------------------+ Christian Schlittchen + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2005 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ +#ifndef UTIL_RNG_H +#define UTIL_RNG_H +#ifdef __cplusplus +extern "C" { +#endif + +#define RNG_MT + +#ifdef RNG_MT + /* initializes mt[N] with a seed */ + extern void init_genrand(unsigned long s); + + /* generates a random number on [0,0xffffffff]-interval */ + extern unsigned long genrand_int32(void); + + /* generates a random number on [0,1)-real-interval */ + extern double genrand_real2(void); + + /* generates a random number on [0,0x7fffffff]-interval */ + long genrand_int31(void); + +# define rng_init(seed) init_genrand(seed) +# define rng_int genrand_int31 +# define rng_double genrand_real2 +# define RNG_RAND_MAX 0x7fffffff +#else +# include +# define rng_init(seed) srand(seed) +# define rng_int rand() +# define rng_double ((rand()%RAND_MAX)/(double)RAND_MAX) +# define RNG_RAND_MAX RAND_MAX +#endif +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/sql.c b/src/util/sql.c index 42018f50b..9f653e8af 100644 --- a/src/util/sql.c +++ b/src/util/sql.c @@ -1,82 +1,82 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "sql.h" - -#include "log.h" - -#include -#include -#include - -static FILE * sqlstream = NULL; -static char * sqlfilename = NULL; - -void -sql_init(const char * filename) -{ - if (sqlfilename!=NULL) free(sqlfilename); - sqlfilename = strdup(filename); -} - -void -_sql_print(const char * format, ...) -{ - if (!sqlstream && sqlfilename) { - sqlstream=fopen(sqlfilename, "wt+"); - free(sqlfilename); - sqlfilename=NULL; - } - if (sqlstream!=NULL) { - va_list marker; - va_start(marker, format); - vfprintf(sqlstream, format, marker); - va_end(marker); - } -} - -void -sql_done(void) -{ - if (sqlstream) fclose(sqlstream); - if (sqlfilename) free(sqlfilename); - sqlstream=NULL; - sqlfilename=NULL; -} - -const char * -sqlquote(const char * str) -{ -#define BUFFERS 4 -#define BUFSIZE 1024 - static char sqlstring[BUFSIZE*BUFFERS]; /* STATIC_RESULT: used for return, not across calls */ - static int index = 0; /* STATIC_XCALL: used across calls */ - char * start = sqlstring+index*BUFSIZE; - char * o = start; - const char * i = str; - while (*i && o-start < BUFSIZE-1) { - if (*i!='\'' && *i!='\"') { - *o++ = *i++; - } else ++i; - } - *o = '\0'; - index = (index+1) % BUFFERS; - return start; -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "sql.h" + +#include "log.h" + +#include +#include +#include + +static FILE * sqlstream = NULL; +static char * sqlfilename = NULL; + +void +sql_init(const char * filename) +{ + if (sqlfilename!=NULL) free(sqlfilename); + sqlfilename = strdup(filename); +} + +void +_sql_print(const char * format, ...) +{ + if (!sqlstream && sqlfilename) { + sqlstream=fopen(sqlfilename, "wt+"); + free(sqlfilename); + sqlfilename=NULL; + } + if (sqlstream!=NULL) { + va_list marker; + va_start(marker, format); + vfprintf(sqlstream, format, marker); + va_end(marker); + } +} + +void +sql_done(void) +{ + if (sqlstream) fclose(sqlstream); + if (sqlfilename) free(sqlfilename); + sqlstream=NULL; + sqlfilename=NULL; +} + +const char * +sqlquote(const char * str) +{ +#define BUFFERS 4 +#define BUFSIZE 1024 + static char sqlstring[BUFSIZE*BUFFERS]; /* STATIC_RESULT: used for return, not across calls */ + static int index = 0; /* STATIC_XCALL: used across calls */ + char * start = sqlstring+index*BUFSIZE; + char * o = start; + const char * i = str; + while (*i && o-start < BUFSIZE-1) { + if (*i!='\'' && *i!='\"') { + *o++ = *i++; + } else ++i; + } + *o = '\0'; + index = (index+1) % BUFFERS; + return start; +} + diff --git a/src/util/sql.h b/src/util/sql.h index d0e9f813a..b16fa7930 100644 --- a/src/util/sql.h +++ b/src/util/sql.h @@ -1,35 +1,35 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_UTIL_SQL -#define H_UTIL_SQL -#ifdef __cplusplus -extern "C" { -#endif - - extern void sql_init(const char * filename); - extern void sql_done(void); - extern const char * sqlquote(const char * str); - extern void _sql_print(const char * format, ...); - -#define sql_print(x) _sql_print x - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_UTIL_SQL +#define H_UTIL_SQL +#ifdef __cplusplus +extern "C" { +#endif + + extern void sql_init(const char * filename); + extern void sql_done(void); + extern const char * sqlquote(const char * str); + extern void _sql_print(const char * format, ...); + +#define sql_print(x) _sql_print x + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/storage.h b/src/util/storage.h index 678d377e8..96b62216b 100644 --- a/src/util/storage.h +++ b/src/util/storage.h @@ -1,48 +1,48 @@ -#ifndef STORAGE_H -#define STORAGE_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct storage { - /* separator for readable files: */ - int (*w_brk)(struct storage *); - /* integer values: */ - int (*w_int)(struct storage *, int arg); - int (*r_int)(struct storage *); - /* float values: */ - int (*w_flt)(struct storage *, float arg); - float (*r_flt)(struct storage *); - /* id values: */ - int (*w_id)(struct storage *, int arg); - int (*r_id)(struct storage *); - /* tokens that contain no whitespace: */ - int (*w_tok)(struct storage *, const char * tok); - char *(*r_tok)(struct storage *); - void (*r_tok_buf)(struct storage *, char * result, size_t size); - /* strings that need to be quoted: */ - int (*w_str)(struct storage *, const char * tok); - char * (*r_str)(struct storage *); - void (*r_str_buf)(struct storage *, char * result, size_t size); - /* binary data: */ - int (*w_bin)(struct storage *, void * arg, size_t size); - void (*r_bin)(struct storage *, void * result, size_t size); - - int (*open)(struct storage *, const char * filename, int mode); - int (*close)(struct storage *); - - int encoding; - int version; - void * userdata; -} storage; - -#define IO_READ 0x01 -#define IO_WRITE 0x02 -#define IO_BINARY 0x04 -#define IO_TEXT 0x08 -#define IO_DEFAULT IO_BINARY - -#ifdef __cplusplus -} -#endif -#endif +#ifndef STORAGE_H +#define STORAGE_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct storage { + /* separator for readable files: */ + int (*w_brk)(struct storage *); + /* integer values: */ + int (*w_int)(struct storage *, int arg); + int (*r_int)(struct storage *); + /* float values: */ + int (*w_flt)(struct storage *, float arg); + float (*r_flt)(struct storage *); + /* id values: */ + int (*w_id)(struct storage *, int arg); + int (*r_id)(struct storage *); + /* tokens that contain no whitespace: */ + int (*w_tok)(struct storage *, const char * tok); + char *(*r_tok)(struct storage *); + void (*r_tok_buf)(struct storage *, char * result, size_t size); + /* strings that need to be quoted: */ + int (*w_str)(struct storage *, const char * tok); + char * (*r_str)(struct storage *); + void (*r_str_buf)(struct storage *, char * result, size_t size); + /* binary data: */ + int (*w_bin)(struct storage *, void * arg, size_t size); + void (*r_bin)(struct storage *, void * result, size_t size); + + int (*open)(struct storage *, const char * filename, int mode); + int (*close)(struct storage *); + + int encoding; + int version; + void * userdata; +} storage; + +#define IO_READ 0x01 +#define IO_WRITE 0x02 +#define IO_BINARY 0x04 +#define IO_TEXT 0x08 +#define IO_DEFAULT IO_BINARY + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/strings.c b/src/util/strings.c index fca7308e9..390bc5462 100644 --- a/src/util/strings.c +++ b/src/util/strings.c @@ -1,132 +1,132 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include - -/* libc includes */ -#include - -INLINE_FUNCTION unsigned int -hashstring(const char* s) -{ - unsigned int key = 0; - while (*s) { - key = key*37 + *s++; - } - return key & 0x7FFFFFFF; -} - -/* -static const char * -escape_string_inplace(char * buffer, unsigned int len, unsigned int offset) -{ -#define MAXQUOTES 32 - char * o; - char * d[MAXQUOTES+1]; - int i = 0; - - o = strchr(buffer, '"'); - if (!o) { - return buffer; - } - - while (*o && i0) { - const char * src = d[i]; - char * dst = d[i] + i + offset; - size_t mlen = d[i+1] - d[i]; - memmove(dst--, src, mlen); - *dst = '\\'; - } - return buffer; -} -*/ - -INLINE_FUNCTION const char * -escape_string(const char * str, char * buffer, unsigned int len) -{ - const char * start = strchr(str, '\"'); - if (start) { - static char s_buffer[4096]; /* STATIC_RESULT: used for return, not across calls */ - const char * p; - char * o; - size_t skip = start-str; - - if (buffer==NULL) { - buffer = s_buffer; - len = sizeof(s_buffer); - } - memcpy(buffer, str, skip); - o = buffer + skip; - p = str + skip; - do { - if (*p == '\"' || *p=='\\') { - if (len<2) { - *o = '\0'; - break; - } - (*o++) = '\\'; - len -= 2; - } else { - if (len<1) { - *o = '\0'; - break; - } - --len; - } - (*o++) = (*p); - } while (*p++); - return buffer; - } - return str; -} - -INLINE_FUNCTION unsigned int jenkins_hash(unsigned int a) -{ - a = (a+0x7ed55d16) + (a<<12); - a = (a^0xc761c23c) ^ (a>>19); - a = (a+0x165667b1) + (a<<5); - a = (a+0xd3a2646c) ^ (a<<9); - a = (a+0xfd7046c5) + (a<<3); - a = (a^0xb55a4f09) ^ (a>>16); - return a; -} - -INLINE_FUNCTION unsigned int wang_hash(unsigned int a) -{ - a = ~a + (a << 15); // a = (a << 15) - a - 1; - a = a ^ (a >> 12); - a = a + (a << 2); - a = a ^ (a >> 4); - a = a * 2057; // a = (a + (a << 3)) + (a << 11); - a = a ^ (a >> 16); - return a; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include + +/* libc includes */ +#include + +INLINE_FUNCTION unsigned int +hashstring(const char* s) +{ + unsigned int key = 0; + while (*s) { + key = key*37 + *s++; + } + return key & 0x7FFFFFFF; +} + +/* +static const char * +escape_string_inplace(char * buffer, unsigned int len, unsigned int offset) +{ +#define MAXQUOTES 32 + char * o; + char * d[MAXQUOTES+1]; + int i = 0; + + o = strchr(buffer, '"'); + if (!o) { + return buffer; + } + + while (*o && i0) { + const char * src = d[i]; + char * dst = d[i] + i + offset; + size_t mlen = d[i+1] - d[i]; + memmove(dst--, src, mlen); + *dst = '\\'; + } + return buffer; +} +*/ + +INLINE_FUNCTION const char * +escape_string(const char * str, char * buffer, unsigned int len) +{ + const char * start = strchr(str, '\"'); + if (start) { + static char s_buffer[4096]; /* STATIC_RESULT: used for return, not across calls */ + const char * p; + char * o; + size_t skip = start-str; + + if (buffer==NULL) { + buffer = s_buffer; + len = sizeof(s_buffer); + } + memcpy(buffer, str, skip); + o = buffer + skip; + p = str + skip; + do { + if (*p == '\"' || *p=='\\') { + if (len<2) { + *o = '\0'; + break; + } + (*o++) = '\\'; + len -= 2; + } else { + if (len<1) { + *o = '\0'; + break; + } + --len; + } + (*o++) = (*p); + } while (*p++); + return buffer; + } + return str; +} + +INLINE_FUNCTION unsigned int jenkins_hash(unsigned int a) +{ + a = (a+0x7ed55d16) + (a<<12); + a = (a^0xc761c23c) ^ (a>>19); + a = (a+0x165667b1) + (a<<5); + a = (a+0xd3a2646c) ^ (a<<9); + a = (a+0xfd7046c5) + (a<<3); + a = (a^0xb55a4f09) ^ (a>>16); + return a; +} + +INLINE_FUNCTION unsigned int wang_hash(unsigned int a) +{ + a = ~a + (a << 15); // a = (a << 15) - a - 1; + a = a ^ (a >> 12); + a = a + (a << 2); + a = a ^ (a >> 4); + a = a * 2057; // a = (a + (a << 3)) + (a << 11); + a = a ^ (a >> 16); + return a; +} diff --git a/src/util/strncpy.c b/src/util/strncpy.c index 4c8d22099..8da32d488 100644 --- a/src/util/strncpy.c +++ b/src/util/strncpy.c @@ -1,22 +1,22 @@ - -/* - * Faster replacement for ISO-C strncpy, does not pad with zeros - */ - -#include - -char * -strncpy(char *to, const char *from, size_t size) -{ - char *t = to, *f = (char *)from; - int copied = 0; - - while(copied < size) { - *t = *f; - if(*f == '\0') break; - t++; f++; copied++; - } - - return to; -} - + +/* + * Faster replacement for ISO-C strncpy, does not pad with zeros + */ + +#include + +char * +strncpy(char *to, const char *from, size_t size) +{ + char *t = to, *f = (char *)from; + int copied = 0; + + while(copied < size) { + *t = *f; + if(*f == '\0') break; + t++; f++; copied++; + } + + return to; +} + diff --git a/src/util/translation.c b/src/util/translation.c index 7385893fb..b92246a19 100644 --- a/src/util/translation.c +++ b/src/util/translation.c @@ -1,488 +1,488 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ -#include - -#include "translation.h" -#include "log.h" -#include "bsdstring.h" - -/* libc includes */ -#include -#include -#include -#include -#include - -/** - ** simple operand stack - **/ - -typedef struct opstack { - variant * begin; - variant * top; - int size; -} opstack; - -variant -opstack_pop(opstack ** stackp) -{ - opstack * stack = *stackp; - - assert(stack); - assert(stack->top>stack->begin); - return *(--stack->top); -} - -void -opstack_push(opstack ** stackp, variant data) -{ - opstack * stack = *stackp; - if (stack==NULL) { - stack = (opstack*)malloc(sizeof(opstack)); - stack->size = 1; - stack->begin = malloc(sizeof(variant) * stack->size); - stack->top = stack->begin; - *stackp = stack; - } - if (stack->top - stack->begin == stack->size) { - size_t pos = stack->top - stack->begin; - stack->size += stack->size; - stack->begin = realloc(stack->begin, sizeof(variant) * stack->size); - stack->top = stack->begin + pos; - } - *stack->top++ = data; -} - -/** - ** static buffer malloc - **/ - -#define BBUFSIZE 128*1024 -static struct { - char * begin; - char * end; - char * last; - char * current; -} buffer; - -char * -balloc(size_t size) -{ - static int init = 0; /* STATIC_XCALL: used across calls */ - if (!init) { - init = 1; - buffer.current = buffer.begin = malloc(BBUFSIZE); - buffer.end = buffer.begin + BBUFSIZE; - } - if (buffer.current + size > buffer.end) { - /* out of memory! */ - return NULL; - } - buffer.last = buffer.current; - buffer.current +=size; - return buffer.last; -} - -void -bfree(char * c) -/* only release this memory if it was part of the last allocation - * that's a joke, but who cares. - */ -{ - if (c>=buffer.last && cvalue = value; - var->symbol = symbol; - - var->next = variables; - variables = var; -} - -static variable * -find_variable(const char * symbol) -{ - variable * var = variables; - while (var) { - if (!strcmp(var->symbol, symbol)) break; - var = var->next; - } - return var; -} - -/** - ** constant values - **/ - -typedef struct function { - struct function * next; - const char * symbol; - evalfun parse; -} function; - -static function * functions; - -static void -free_functions(void) -{ - while (functions) { - function * fun = functions; - functions = fun->next; - free(fun); - } -} - -void -add_function(const char * symbol, evalfun parse) -{ - function * fun = (function*)malloc(sizeof(function)); - - fun->parse = parse; - fun->symbol = symbol; - - fun->next = functions; - functions = fun; -} - -static function * -find_function(const char * symbol) -{ - function * fun = functions; - while (fun) { - if (!strcmp(fun->symbol, symbol)) break; - fun = fun->next; - } - return fun; -} - -static const char * parse(opstack **, const char* in, const void *); -/* static const char * sample = "\"enno and $bool($if($eq($i,0),\"noone else\",\"$i other people\"))\""; */ - -static const char * -parse_symbol(opstack ** stack, const char* in, const void * userdata) -/* in is the symbol name and following text, starting after the $ - * result goes on the stack - */ -{ - boolean braces = false; - char symbol[32]; - char *cp = symbol; /* current position */ - - if (*in=='{') { - braces = true; - ++in; - } - while (isalnum(*in) || *in=='.') *cp++ = *in++; - *cp = '\0'; - /* symbol will now contain the symbol name */ - if (*in=='(') { - /* it's a function we need to parse, start by reading the parameters */ - function * foo; - while (*in != ')') { - in = parse(stack, ++in, userdata); /* will push the result on the stack */ - if (in==NULL) return NULL; - } - ++in; - foo = find_function(symbol); - if (foo==NULL) { - log_error(("parser does not know about \"%s\" function.\n", symbol)); - return NULL; - } - foo->parse(stack, userdata); /* will pop parameters from stack (reverse order!) and push the result */ - } else { - variable * var = find_variable(symbol); - if (braces && *in=='}') { - ++in; - } - /* it's a constant (variable is a misnomer, but heck, const was taken;)) */ - if (var==NULL) { - log_error(("parser does not know about \"%s\" variable.\n", symbol)); - return NULL; - } - opush(stack, var->value); - } - return in; -} - -#define TOKENSIZE 4096 -static const char * -parse_string(opstack ** stack, const char* in, const void * userdata) /* (char*) -> char* */ -{ - char * c; - char * buffer = balloc(TOKENSIZE); - size_t size = TOKENSIZE - 1; - const char * ic = in; - char * oc = buffer; - /* mode flags */ - boolean f_escape = false; - boolean bDone = false; - variant var; - - while (*ic && !bDone) { - if (f_escape) { - f_escape = false; - switch (*ic) { - case 'n': - if (size>0) { *oc++='\n'; --size; } - break; - case 't': - if (size>0) { *oc++='\t'; --size; } - break; - default: - if (size>0) { *oc++=*ic++; --size; } - } - } else { - int ch = (unsigned char)(*ic); - int bytes; - - switch (ch) { - case '\\': - f_escape = true; - ++ic; - break; - case '"': - bDone = true; - ++ic; - break; - case '$': - ic = parse_symbol(stack, ++ic, userdata); - if (ic==NULL) return NULL; - c = (char*)opop_v(stack); - bytes = (int)strlcpy(oc, c, size); - if (bytes<(int)size) oc += bytes; - else oc += size; - bfree(c); - break; - default: - if (size>0) { *oc++=*ic++; --size; } - else ++ic; - } - } - } - *oc++ = '\0'; - bfree(oc); - var.v = buffer; - opush(stack, var); - return ic; -} - -static const char * -parse_int(opstack ** stack, const char * in) -{ - int k = 0; - int vz = 1; - boolean ok = false; - variant var; - do { - switch (*in) { - case '+': - ++in; - break; - case '-': - ++in; - vz=vz*-1; - break; - default: - ok = true; - } - } while (!ok); - while (isdigit(*(unsigned char*)in)) { - k = k * 10 + (*in++)-'0'; - } - var.i = k*vz; - opush(stack, var); - return in; -} - - -static const char * -parse(opstack ** stack, const char* inn, const void * userdata) -{ - const char * b = inn; - while (*b) { - switch (*b) { - case '"': - return parse_string(stack, ++b, userdata); - break; - case '$': - return parse_symbol(stack, ++b, userdata); - break; - default: - if (isdigit(*(unsigned char*)b) || *b=='-' || *b=='+') { - return parse_int(stack, b); - } - else ++b; - } - } - log_error(("could not parse \"%s\". Probably invalid message syntax.", inn)); - return NULL; -} - -const char * -translate(const char* format, const void * userdata, const char* vars, variant args[]) -{ - int i = 0; - const char *ic = vars; - char symbol[32]; - char *oc = symbol; - opstack * stack = NULL; - const char * rv; - - brelease(); - free_variables(); - - assert(format); - assert(*ic == 0 || isalnum(*ic)); - while (*ic) { - *oc++ = *ic++; - if (!isalnum(*ic)) { - variant x = args[i++]; - *oc = '\0'; - oc = symbol; - add_variable(strcpy(balloc(strlen(symbol)+1), symbol), x); - while (*ic && !isalnum(*ic)) ++ic; - } - } - - if (format[0]=='"') { - rv = parse(&stack, format, userdata); - } - else { - rv = parse_string(&stack, format, userdata); - } - if (rv!=NULL) { - if (rv[0]) { - log_error(("residual data after parsing: %s\n", rv)); - } - rv = (const char*)opop(&stack).v; - free(stack->begin); - free(stack); - } - return rv; -} - -static void -eval_lt(opstack ** stack, const void * userdata) /* (int, int) -> int */ -{ - int a = opop_i(stack); - int b = opop_i(stack); - int rval = (b int */ -{ - int a = opop_i(stack); - int b = opop_i(stack); - int rval = (a==b)?1:0; - opush_i(stack, rval); - unused(userdata); -} - -static void -eval_add(opstack ** stack, const void * userdata) /* (int, int) -> int */ -{ - int a = opop_i(stack); - int b = opop_i(stack); - opush_i(stack, a+b); - unused(userdata); -} - -static void -eval_isnull(opstack ** stack, const void * userdata) /* (int, int) -> int */ -{ - void * a = opop_v(stack); - opush_i(stack, (a==NULL)?1:0); - unused(userdata); -} - -static void -eval_if(opstack ** stack, const void * userdata) /* (int, int) -> int */ -{ - void * a = opop_v(stack); - void * b = opop_v(stack); - int cond = opop_i(stack); - opush_v(stack, cond?b:a); - unused(userdata); -} - -static void -eval_strlen(opstack ** stack, const void * userdata) /* string -> int */ -{ - const char * c = (const char *)opop_v(stack); - opush_i(stack, c?(int)strlen(c):0); - unused(userdata); -} - -#include "base36.h" -static void -eval_int(opstack ** stack, const void * userdata) -{ - int i = opop_i(stack); - const char * c = itoa10(i); - size_t len = strlen(c); - variant var; - - var.v = strcpy(balloc(len+1), c); - opush(stack, var); -} - -void -translation_init(void) -{ - add_function("lt", &eval_lt); - add_function("eq", &eval_eq); - add_function("int", &eval_int); - add_function("add", &eval_add); - add_function("strlen", &eval_strlen); - add_function("if", &eval_if); - add_function("isnull", &eval_isnull); -} - -void -translation_done(void) -{ - free_functions(); - free(buffer.begin); -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#include + +#include "translation.h" +#include "log.h" +#include "bsdstring.h" + +/* libc includes */ +#include +#include +#include +#include +#include + +/** + ** simple operand stack + **/ + +typedef struct opstack { + variant * begin; + variant * top; + int size; +} opstack; + +variant +opstack_pop(opstack ** stackp) +{ + opstack * stack = *stackp; + + assert(stack); + assert(stack->top>stack->begin); + return *(--stack->top); +} + +void +opstack_push(opstack ** stackp, variant data) +{ + opstack * stack = *stackp; + if (stack==NULL) { + stack = (opstack*)malloc(sizeof(opstack)); + stack->size = 1; + stack->begin = malloc(sizeof(variant) * stack->size); + stack->top = stack->begin; + *stackp = stack; + } + if (stack->top - stack->begin == stack->size) { + size_t pos = stack->top - stack->begin; + stack->size += stack->size; + stack->begin = realloc(stack->begin, sizeof(variant) * stack->size); + stack->top = stack->begin + pos; + } + *stack->top++ = data; +} + +/** + ** static buffer malloc + **/ + +#define BBUFSIZE 128*1024 +static struct { + char * begin; + char * end; + char * last; + char * current; +} buffer; + +char * +balloc(size_t size) +{ + static int init = 0; /* STATIC_XCALL: used across calls */ + if (!init) { + init = 1; + buffer.current = buffer.begin = malloc(BBUFSIZE); + buffer.end = buffer.begin + BBUFSIZE; + } + if (buffer.current + size > buffer.end) { + /* out of memory! */ + return NULL; + } + buffer.last = buffer.current; + buffer.current +=size; + return buffer.last; +} + +void +bfree(char * c) +/* only release this memory if it was part of the last allocation + * that's a joke, but who cares. + */ +{ + if (c>=buffer.last && cvalue = value; + var->symbol = symbol; + + var->next = variables; + variables = var; +} + +static variable * +find_variable(const char * symbol) +{ + variable * var = variables; + while (var) { + if (!strcmp(var->symbol, symbol)) break; + var = var->next; + } + return var; +} + +/** + ** constant values + **/ + +typedef struct function { + struct function * next; + const char * symbol; + evalfun parse; +} function; + +static function * functions; + +static void +free_functions(void) +{ + while (functions) { + function * fun = functions; + functions = fun->next; + free(fun); + } +} + +void +add_function(const char * symbol, evalfun parse) +{ + function * fun = (function*)malloc(sizeof(function)); + + fun->parse = parse; + fun->symbol = symbol; + + fun->next = functions; + functions = fun; +} + +static function * +find_function(const char * symbol) +{ + function * fun = functions; + while (fun) { + if (!strcmp(fun->symbol, symbol)) break; + fun = fun->next; + } + return fun; +} + +static const char * parse(opstack **, const char* in, const void *); +/* static const char * sample = "\"enno and $bool($if($eq($i,0),\"noone else\",\"$i other people\"))\""; */ + +static const char * +parse_symbol(opstack ** stack, const char* in, const void * userdata) +/* in is the symbol name and following text, starting after the $ + * result goes on the stack + */ +{ + boolean braces = false; + char symbol[32]; + char *cp = symbol; /* current position */ + + if (*in=='{') { + braces = true; + ++in; + } + while (isalnum(*in) || *in=='.') *cp++ = *in++; + *cp = '\0'; + /* symbol will now contain the symbol name */ + if (*in=='(') { + /* it's a function we need to parse, start by reading the parameters */ + function * foo; + while (*in != ')') { + in = parse(stack, ++in, userdata); /* will push the result on the stack */ + if (in==NULL) return NULL; + } + ++in; + foo = find_function(symbol); + if (foo==NULL) { + log_error(("parser does not know about \"%s\" function.\n", symbol)); + return NULL; + } + foo->parse(stack, userdata); /* will pop parameters from stack (reverse order!) and push the result */ + } else { + variable * var = find_variable(symbol); + if (braces && *in=='}') { + ++in; + } + /* it's a constant (variable is a misnomer, but heck, const was taken;)) */ + if (var==NULL) { + log_error(("parser does not know about \"%s\" variable.\n", symbol)); + return NULL; + } + opush(stack, var->value); + } + return in; +} + +#define TOKENSIZE 4096 +static const char * +parse_string(opstack ** stack, const char* in, const void * userdata) /* (char*) -> char* */ +{ + char * c; + char * buffer = balloc(TOKENSIZE); + size_t size = TOKENSIZE - 1; + const char * ic = in; + char * oc = buffer; + /* mode flags */ + boolean f_escape = false; + boolean bDone = false; + variant var; + + while (*ic && !bDone) { + if (f_escape) { + f_escape = false; + switch (*ic) { + case 'n': + if (size>0) { *oc++='\n'; --size; } + break; + case 't': + if (size>0) { *oc++='\t'; --size; } + break; + default: + if (size>0) { *oc++=*ic++; --size; } + } + } else { + int ch = (unsigned char)(*ic); + int bytes; + + switch (ch) { + case '\\': + f_escape = true; + ++ic; + break; + case '"': + bDone = true; + ++ic; + break; + case '$': + ic = parse_symbol(stack, ++ic, userdata); + if (ic==NULL) return NULL; + c = (char*)opop_v(stack); + bytes = (int)strlcpy(oc, c, size); + if (bytes<(int)size) oc += bytes; + else oc += size; + bfree(c); + break; + default: + if (size>0) { *oc++=*ic++; --size; } + else ++ic; + } + } + } + *oc++ = '\0'; + bfree(oc); + var.v = buffer; + opush(stack, var); + return ic; +} + +static const char * +parse_int(opstack ** stack, const char * in) +{ + int k = 0; + int vz = 1; + boolean ok = false; + variant var; + do { + switch (*in) { + case '+': + ++in; + break; + case '-': + ++in; + vz=vz*-1; + break; + default: + ok = true; + } + } while (!ok); + while (isdigit(*(unsigned char*)in)) { + k = k * 10 + (*in++)-'0'; + } + var.i = k*vz; + opush(stack, var); + return in; +} + + +static const char * +parse(opstack ** stack, const char* inn, const void * userdata) +{ + const char * b = inn; + while (*b) { + switch (*b) { + case '"': + return parse_string(stack, ++b, userdata); + break; + case '$': + return parse_symbol(stack, ++b, userdata); + break; + default: + if (isdigit(*(unsigned char*)b) || *b=='-' || *b=='+') { + return parse_int(stack, b); + } + else ++b; + } + } + log_error(("could not parse \"%s\". Probably invalid message syntax.", inn)); + return NULL; +} + +const char * +translate(const char* format, const void * userdata, const char* vars, variant args[]) +{ + int i = 0; + const char *ic = vars; + char symbol[32]; + char *oc = symbol; + opstack * stack = NULL; + const char * rv; + + brelease(); + free_variables(); + + assert(format); + assert(*ic == 0 || isalnum(*ic)); + while (*ic) { + *oc++ = *ic++; + if (!isalnum(*ic)) { + variant x = args[i++]; + *oc = '\0'; + oc = symbol; + add_variable(strcpy(balloc(strlen(symbol)+1), symbol), x); + while (*ic && !isalnum(*ic)) ++ic; + } + } + + if (format[0]=='"') { + rv = parse(&stack, format, userdata); + } + else { + rv = parse_string(&stack, format, userdata); + } + if (rv!=NULL) { + if (rv[0]) { + log_error(("residual data after parsing: %s\n", rv)); + } + rv = (const char*)opop(&stack).v; + free(stack->begin); + free(stack); + } + return rv; +} + +static void +eval_lt(opstack ** stack, const void * userdata) /* (int, int) -> int */ +{ + int a = opop_i(stack); + int b = opop_i(stack); + int rval = (b int */ +{ + int a = opop_i(stack); + int b = opop_i(stack); + int rval = (a==b)?1:0; + opush_i(stack, rval); + unused(userdata); +} + +static void +eval_add(opstack ** stack, const void * userdata) /* (int, int) -> int */ +{ + int a = opop_i(stack); + int b = opop_i(stack); + opush_i(stack, a+b); + unused(userdata); +} + +static void +eval_isnull(opstack ** stack, const void * userdata) /* (int, int) -> int */ +{ + void * a = opop_v(stack); + opush_i(stack, (a==NULL)?1:0); + unused(userdata); +} + +static void +eval_if(opstack ** stack, const void * userdata) /* (int, int) -> int */ +{ + void * a = opop_v(stack); + void * b = opop_v(stack); + int cond = opop_i(stack); + opush_v(stack, cond?b:a); + unused(userdata); +} + +static void +eval_strlen(opstack ** stack, const void * userdata) /* string -> int */ +{ + const char * c = (const char *)opop_v(stack); + opush_i(stack, c?(int)strlen(c):0); + unused(userdata); +} + +#include "base36.h" +static void +eval_int(opstack ** stack, const void * userdata) +{ + int i = opop_i(stack); + const char * c = itoa10(i); + size_t len = strlen(c); + variant var; + + var.v = strcpy(balloc(len+1), c); + opush(stack, var); +} + +void +translation_init(void) +{ + add_function("lt", &eval_lt); + add_function("eq", &eval_eq); + add_function("int", &eval_int); + add_function("add", &eval_add); + add_function("strlen", &eval_strlen); + add_function("if", &eval_if); + add_function("isnull", &eval_isnull); +} + +void +translation_done(void) +{ + free_functions(); + free(buffer.begin); +} diff --git a/src/util/translation.h b/src/util/translation.h index 572d5b7b7..6aa6dd28d 100644 --- a/src/util/translation.h +++ b/src/util/translation.h @@ -1,45 +1,45 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_UTIL_TRANSLATION -#define H_UTIL_TRANSLATION -#ifdef __cplusplus -extern "C" { -#endif - -#include "variant.h" -struct opstack; -extern void opstack_push(struct opstack ** stack, variant data); -#define opush_i(stack, x) { variant localvar; localvar.i = x; opstack_push(stack, localvar); } -#define opush_v(stack, x) { variant localvar; localvar.v = x; opstack_push(stack, localvar); } -#define opush(stack, i) opstack_push(stack, i) - -extern variant opstack_pop(struct opstack ** stack); -#define opop_v(stack) opstack_pop(stack).v -#define opop_i(stack) opstack_pop(stack).i -#define opop(stack) opstack_pop(stack) - -extern void translation_init(void); -extern void translation_done(void); -extern const char * translate(const char* format, const void * userdata, const char* vars, variant args[]); - -/* eval_x functions */ -typedef void (*evalfun)(struct opstack ** stack, const void *); -extern void add_function(const char * symbol, evalfun parse); - -/* transient memory blocks */ -extern char * balloc(size_t size); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_UTIL_TRANSLATION +#define H_UTIL_TRANSLATION +#ifdef __cplusplus +extern "C" { +#endif + +#include "variant.h" +struct opstack; +extern void opstack_push(struct opstack ** stack, variant data); +#define opush_i(stack, x) { variant localvar; localvar.i = x; opstack_push(stack, localvar); } +#define opush_v(stack, x) { variant localvar; localvar.v = x; opstack_push(stack, localvar); } +#define opush(stack, i) opstack_push(stack, i) + +extern variant opstack_pop(struct opstack ** stack); +#define opop_v(stack) opstack_pop(stack).v +#define opop_i(stack) opstack_pop(stack).i +#define opop(stack) opstack_pop(stack) + +extern void translation_init(void); +extern void translation_done(void); +extern const char * translate(const char* format, const void * userdata, const char* vars, variant args[]); + +/* eval_x functions */ +typedef void (*evalfun)(struct opstack ** stack, const void *); +extern void add_function(const char * symbol, evalfun parse); + +/* transient memory blocks */ +extern char * balloc(size_t size); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/umlaut.c b/src/util/umlaut.c index a29b16635..67bd03964 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -1,160 +1,160 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "umlaut.h" - -#include "log.h" -#include "unicode.h" - -#include -#include -#include -#include - -typedef struct tref { - struct tref * nexthash; - ucs4_t ucs; - struct tnode * node; -} tref; - -#define LEAF 1 /* leaf node for a word. always matches */ -#define SHARED 2 /* at least two words share the node */ - -void -addtoken(tnode * root, const char * str, variant id) -{ - static const struct replace { /* STATIC_CONST: constant value */ - ucs4_t ucs; - const char str[3]; - } replace[] = { - /* match lower-case (!) umlauts and others to transcriptions */ - { 228, "AE"}, /* auml */ - { 246, "OE"}, /* ouml */ - { 252, "UE"}, /* uuml */ - { 223, "SS"}, /* szlig */ - { 230, "AE"}, /* norsk */ - { 248, "OE"}, /* norsk */ - { 229, "AA"}, /* norsk */ - { 0, "" } - }; - - if (!*str) { - root->id = id; - root->flags |= LEAF; - } else { - tref * next; - int ret, index, i = 0; - ucs4_t ucs, lcs; - size_t len; - - ret = unicode_utf8_to_ucs4(&ucs, str, &len); - assert(ret==0 || !"invalid utf8 string"); - lcs = ucs; - -#if NODEHASHSIZE == 8 - index = ucs & 7; -#else - index = ucs % NODEHASHSIZE; -#endif - assert(index>=0); - next = root->next[index]; - if (!(root->flags & LEAF)) root->id = id; - while (next && next->ucs != ucs) next = next->nexthash; - if (!next) { - tref * ref; - tnode * node = calloc(1, sizeof(tnode)); - - if (ucs<'a' || ucs>'z') { - lcs = towlower((wint_t)ucs); - } - if (ucs==lcs) { - ucs = towupper((wint_t)ucs); - } - - ref = malloc(sizeof(tref)); - ref->ucs = ucs; - ref->node = node; - ref->nexthash=root->next[index]; - root->next[index] = ref; - - /* try lower/upper casing the character, and try again */ - if (ucs!=lcs) { -#if NODEHASHSIZE == 8 - index = lcs & 7; -#else - index = lcs % NODEHASHSIZE; -#endif - ref = malloc(sizeof(tref)); - ref->ucs = lcs; - ref->node = node; - ref->nexthash = root->next[index]; - root->next[index] = ref; - } - next=ref; - } else { - next->node->flags |= SHARED; - if ((next->node->flags & LEAF) == 0) next->node->id.v = NULL; /* why?*/ - } - addtoken(next->node, str+len, id); - while (replace[i].str[0]) { - if (lcs==replace[i].ucs) { - char zText[1024]; - memcpy(zText, replace[i].str, 3); - strcpy(zText+2, (const char*)str+len); - addtoken(root, zText, id); - break; - } - ++i; - } - } -} - -int -findtoken(const tnode * tk, const char * str, variant* result) -{ - if (!str || *str==0) return E_TOK_NOMATCH; - - do { - int index; - const tref * ref; - ucs4_t ucs; - size_t len; - int ret = unicode_utf8_to_ucs4(&ucs, str, &len); - - if (ret!=0) { - /* encoding is broken. youch */ - return E_TOK_NOMATCH; - } -#if NODEHASHSIZE == 8 - index = ucs & 7; -#else - index = ucs % NODEHASHSIZE; -#endif - ref = tk->next[index]; - while (ref && ref->ucs!=ucs) ref = ref->nexthash; - str+=len; - if (!ref) return E_TOK_NOMATCH; - tk = ref->node; - } while (*str); - if (tk) { - *result = tk->id; - return E_TOK_SUCCESS; - } - return E_TOK_NOMATCH; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include "umlaut.h" + +#include "log.h" +#include "unicode.h" + +#include +#include +#include +#include + +typedef struct tref { + struct tref * nexthash; + ucs4_t ucs; + struct tnode * node; +} tref; + +#define LEAF 1 /* leaf node for a word. always matches */ +#define SHARED 2 /* at least two words share the node */ + +void +addtoken(tnode * root, const char * str, variant id) +{ + static const struct replace { /* STATIC_CONST: constant value */ + ucs4_t ucs; + const char str[3]; + } replace[] = { + /* match lower-case (!) umlauts and others to transcriptions */ + { 228, "AE"}, /* auml */ + { 246, "OE"}, /* ouml */ + { 252, "UE"}, /* uuml */ + { 223, "SS"}, /* szlig */ + { 230, "AE"}, /* norsk */ + { 248, "OE"}, /* norsk */ + { 229, "AA"}, /* norsk */ + { 0, "" } + }; + + if (!*str) { + root->id = id; + root->flags |= LEAF; + } else { + tref * next; + int ret, index, i = 0; + ucs4_t ucs, lcs; + size_t len; + + ret = unicode_utf8_to_ucs4(&ucs, str, &len); + assert(ret==0 || !"invalid utf8 string"); + lcs = ucs; + +#if NODEHASHSIZE == 8 + index = ucs & 7; +#else + index = ucs % NODEHASHSIZE; +#endif + assert(index>=0); + next = root->next[index]; + if (!(root->flags & LEAF)) root->id = id; + while (next && next->ucs != ucs) next = next->nexthash; + if (!next) { + tref * ref; + tnode * node = calloc(1, sizeof(tnode)); + + if (ucs<'a' || ucs>'z') { + lcs = towlower((wint_t)ucs); + } + if (ucs==lcs) { + ucs = towupper((wint_t)ucs); + } + + ref = malloc(sizeof(tref)); + ref->ucs = ucs; + ref->node = node; + ref->nexthash=root->next[index]; + root->next[index] = ref; + + /* try lower/upper casing the character, and try again */ + if (ucs!=lcs) { +#if NODEHASHSIZE == 8 + index = lcs & 7; +#else + index = lcs % NODEHASHSIZE; +#endif + ref = malloc(sizeof(tref)); + ref->ucs = lcs; + ref->node = node; + ref->nexthash = root->next[index]; + root->next[index] = ref; + } + next=ref; + } else { + next->node->flags |= SHARED; + if ((next->node->flags & LEAF) == 0) next->node->id.v = NULL; /* why?*/ + } + addtoken(next->node, str+len, id); + while (replace[i].str[0]) { + if (lcs==replace[i].ucs) { + char zText[1024]; + memcpy(zText, replace[i].str, 3); + strcpy(zText+2, (const char*)str+len); + addtoken(root, zText, id); + break; + } + ++i; + } + } +} + +int +findtoken(const tnode * tk, const char * str, variant* result) +{ + if (!str || *str==0) return E_TOK_NOMATCH; + + do { + int index; + const tref * ref; + ucs4_t ucs; + size_t len; + int ret = unicode_utf8_to_ucs4(&ucs, str, &len); + + if (ret!=0) { + /* encoding is broken. youch */ + return E_TOK_NOMATCH; + } +#if NODEHASHSIZE == 8 + index = ucs & 7; +#else + index = ucs % NODEHASHSIZE; +#endif + ref = tk->next[index]; + while (ref && ref->ucs!=ucs) ref = ref->nexthash; + str+=len; + if (!ref) return E_TOK_NOMATCH; + tk = ref->node; + } while (*str); + if (tk) { + *result = tk->id; + return E_TOK_SUCCESS; + } + return E_TOK_NOMATCH; +} diff --git a/src/util/umlaut.h b/src/util/umlaut.h index e1085eb1a..a89f3df77 100644 --- a/src/util/umlaut.h +++ b/src/util/umlaut.h @@ -1,51 +1,51 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef _UMLAUT_H -#define _UMLAUT_H - -#include "variant.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define E_TOK_NOMATCH (-1) -#define E_TOK_SUCCESS 0 -#define NODEHASHSIZE 8 -struct tref; - -typedef struct tnode { - struct tref * next[NODEHASHSIZE]; - unsigned char flags; - variant id; -} tnode; - -int findtoken(const struct tnode * tk, const char * str, variant* result); -void addtoken(struct tnode * root, const char * str, variant id); - -typedef struct local_names { - struct local_names * next; - const struct locale * lang; - struct tnode names; -} local_names; - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef _UMLAUT_H +#define _UMLAUT_H + +#include "variant.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define E_TOK_NOMATCH (-1) +#define E_TOK_SUCCESS 0 +#define NODEHASHSIZE 8 +struct tref; + +typedef struct tnode { + struct tref * next[NODEHASHSIZE]; + unsigned char flags; + variant id; +} tnode; + +int findtoken(const struct tnode * tk, const char * str, variant* result); +void addtoken(struct tnode * root, const char * str, variant id); + +typedef struct local_names { + struct local_names * next; + const struct locale * lang; + struct tnode names; +} local_names; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/unicode.c b/src/util/unicode.c index d23b3b8f8..adda90870 100644 --- a/src/util/unicode.c +++ b/src/util/unicode.c @@ -1,436 +1,436 @@ -/* vi: set ts=2: - * +-------------------+ Christian Schlittchen - * | | Enno Rehling - * | Eressea PBEM host | Katja Zedel - * | (c) 1998 - 2007 | - * | | This program may not be used, modified or distributed - * +-------------------+ without prior permission by the authors of Eressea. - * - */ - -#include -#include "unicode.h" - -#include -#include - -#define B00000000 0x00 -#define B10000000 0x80 -#define B11000000 0xC0 -#define B11100000 0xE0 -#define B11110000 0xF0 -#define B11111000 0xF8 -#define B11111100 0xFC -#define B11111110 0xFE - -#define B00111111 0x3F -#define B00011111 0x1F -#define B00001111 0x0F -#define B00000111 0x07 -#define B00000011 0x03 -#define B00000001 0x01 - -int -unicode_utf8_tolower(utf8_t *op, size_t outlen, const utf8_t *ip) -{ - while (*ip) { - ucs4_t ucs = *ip; - ucs4_t low; - size_t size = 1; - - if (ucs & 0x80) { - int ret = unicode_utf8_to_ucs4(&ucs, ip, &size); - if (ret!=0) { - return ret; - } - } - if (size>outlen) { - return ENOMEM; - } - low = towlower((wint_t)ucs); - if (low==ucs) { - memcpy(op, ip, size); - ip += size; - op += size; - outlen -=size; - } else { - ip += size; - unicode_ucs4_to_utf8(op, &size, low); - op += size; - outlen -=size; - } - } - - if (outlen<=0) { - return ENOMEM; - } - *op = 0; - return 0; -} - -int -unicode_latin1_to_utf8(utf8_t *out, size_t *outlen, const char *in, size_t *inlen) -{ - int is = (int)*inlen; - int os = (int)*outlen; - const char * ip = in; - utf8_t * op = out; - - while (ip-in 0xBF) { - if (op-out>=os-1) break; - *op++ = 0xC3; - *op++ = c-64; - } else if (c>0x7F) { - if (op-out>=os-1) break; - *op++ = 0xC2; - *op++ = c; - } else { - if (op-out>=os) break; - *op++ = c; - } - ++ip; - } - *outlen = op-out; - *inlen = ip-in; - return (int)*outlen; -} - -int -unicode_utf8_strcasecmp(const utf8_t * a, const char * b) -{ - while (*a && *b) { - int ret; - size_t size; - ucs4_t ucsa = *a, ucsb = *b; - - if (ucsa & 0x80) { - ret = unicode_utf8_to_ucs4(&ucsa, a, &size); - if (ret!=0) return -1; - a += size; - } else ++a; - if (ucsb & 0x80) { - ret = unicode_utf8_to_ucs4(&ucsb, b, &size); - if (ret!=0) return -1; - b += size; - } else ++b; - - if (ucsb!=ucsa) { - ucsb = towlower((wint_t)ucsb); - ucsa = towlower((wint_t)ucsa); - if (ucsbucsa) return -1; - } - } - if (*b) return -1; - if (*a) return 1; - return 0; -} - -/* Convert a UCS-4 character to UTF-8. */ -int -unicode_ucs4_to_utf8 (utf8_t *utf8_character, size_t *size, ucs4_t ucs4_character) -{ - int utf8_bytes; - - if (ucs4_character <= 0x0000007F) { - /* 0xxxxxxx */ - utf8_bytes = 1; - utf8_character[0] = (char) ucs4_character; - } - else if (ucs4_character <= 0x000007FF) { - /* 110xxxxx 10xxxxxx */ - utf8_bytes = 2; - utf8_character[0] = (char) ((ucs4_character >> 6) | B11000000); - utf8_character[1] = (char) ((ucs4_character & B00111111) | B10000000); - } - else if (ucs4_character <= 0x0000FFFF) { - /* 1110xxxx 10xxxxxx 10xxxxxx */ - utf8_bytes = 3; - utf8_character[0] = (char) ((ucs4_character >> 12) | B11100000); - utf8_character[1] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); - utf8_character[2] = (char) ((ucs4_character & B00111111) | B10000000); - } - else if (ucs4_character <= 0x001FFFFF) { - /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ - utf8_bytes = 4; - utf8_character[0] = (char) ((ucs4_character >> 18) | B11110000); - utf8_character[1] = (char) (((ucs4_character >> 12) & B00111111) | B10000000); - utf8_character[2] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); - utf8_character[3] = (char) ((ucs4_character & B00111111) | B10000000); - } - else if (ucs4_character <= 0x03FFFFFF) { - /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ - utf8_bytes = 5; - utf8_character[0] = (char) ((ucs4_character >> 24) | B11111000); - utf8_character[1] = (char) (((ucs4_character >> 18) & B00111111) | B10000000); - utf8_character[2] = (char) (((ucs4_character >> 12) & B00111111) | B10000000); - utf8_character[3] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); - utf8_character[4] = (char) ((ucs4_character & B00111111) | B10000000); - } - else if (ucs4_character <= 0x7FFFFFFF) { - /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ - utf8_bytes = 6; - utf8_character[0] = (char) ((ucs4_character >> 30) | B11111100); - utf8_character[1] = (char) (((ucs4_character >> 24) & B00111111) | B10000000); - utf8_character[2] = (char) (((ucs4_character >> 18) & B00111111) | B10000000); - utf8_character[3] = (char) (((ucs4_character >> 12) & B00111111) | B10000000); - utf8_character[4] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); - utf8_character[5] = (char) ((ucs4_character & B00111111) | B10000000); - } - else { - return EILSEQ; - } - - *size = utf8_bytes; - - return 0; -} - - -/* Convert a UTF-8 encoded character to UCS-4. */ -int -unicode_utf8_to_ucs4(ucs4_t *ucs4_character, const utf8_t *utf8_string, - size_t *length) -{ - utf8_t utf8_character = utf8_string[0]; - - /* Is the character in the ASCII range? If so, just copy it to the - output. */ - if (~utf8_character & 0x80) - { - *ucs4_character = utf8_character; - *length = 1; - } - else if ((utf8_character & 0xE0) == 0xC0) - { - /* A two-byte UTF-8 sequence. Make sure the other byte is good. */ - if (utf8_string[1] != '\0' && - (utf8_string[1] & 0xC0) != 0x80) - { - return EILSEQ; - } - - *ucs4_character = - ((utf8_string[1] & 0x3F) << 0) + - ((utf8_character & 0x1F) << 6); - *length = 2; - } - else if ((utf8_character & 0xF0) == 0xE0) - { - /* A three-byte UTF-8 sequence. Make sure the other bytes are - good. */ - if ((utf8_string[1] != '\0') && - (utf8_string[1] & 0xC0) != 0x80 && - (utf8_string[2] != '\0') && - (utf8_string[2] & 0xC0) != 0x80) - { - return EILSEQ; - } - - *ucs4_character = - ((utf8_string[2] & 0x3F) << 0) + - ((utf8_string[1] & 0x3F) << 6) + - ((utf8_character & 0x0F) << 12); - *length = 3; - } - else if ((utf8_character & 0xF8) == 0xF0) - { - /* A four-byte UTF-8 sequence. Make sure the other bytes are - good. */ - if ((utf8_string[1] != '\0') && - (utf8_string[1] & 0xC0) != 0x80 && - (utf8_string[2] != '\0') && - (utf8_string[2] & 0xC0) != 0x80 && - (utf8_string[3] != '\0') && - (utf8_string[3] & 0xC0) != 0x80) - { - return EILSEQ; - } - - *ucs4_character = - ((utf8_string[3] & 0x3F) << 0) + - ((utf8_string[2] & 0x3F) << 6) + - ((utf8_string[1] & 0x3F) << 12) + - ((utf8_character & 0x07) << 18); - *length = 4; - } - else if ((utf8_character & 0xFC) == 0xF8) - { - /* A five-byte UTF-8 sequence. Make sure the other bytes are - good. */ - if ((utf8_string[1] != '\0') && - (utf8_string[1] & 0xC0) != 0x80 && - (utf8_string[2] != '\0') && - (utf8_string[2] & 0xC0) != 0x80 && - (utf8_string[3] != '\0') && - (utf8_string[3] & 0xC0) != 0x80 && - (utf8_string[4] != '\0') && - (utf8_string[4] & 0xC0) != 0x80) - { - return EILSEQ; - } - - *ucs4_character = - ((utf8_string[4] & 0x3F) << 0) + - ((utf8_string[3] & 0x3F) << 6) + - ((utf8_string[2] & 0x3F) << 12) + - ((utf8_string[1] & 0x3F) << 18) + - ((utf8_character & 0x03) << 24); - *length = 5; - } - else if ((utf8_character & 0xFE) == 0xFC) - { - /* A six-byte UTF-8 sequence. Make sure the other bytes are - good. */ - if ((utf8_string[1] != '\0') && - (utf8_string[1] & 0xC0) != 0x80 && - (utf8_string[2] != '\0') && - (utf8_string[2] & 0xC0) != 0x80 && - (utf8_string[3] != '\0') && - (utf8_string[3] & 0xC0) != 0x80 && - (utf8_string[4] != '\0') && - (utf8_string[4] & 0xC0) != 0x80 && - (utf8_string[5] != '\0') && - (utf8_string[5] & 0xC0) != 0x80) - { - return EILSEQ; - } - - *ucs4_character = - ((utf8_string[5] & 0x3F) << 0) + - ((utf8_string[4] & 0x3F) << 6) + - ((utf8_string[3] & 0x3F) << 12) + - ((utf8_string[2] & 0x3F) << 18) + - ((utf8_string[1] & 0x3F) << 24) + - ((utf8_character & 0x01) << 30); - *length = 6; - } - else - { - return EILSEQ; - } - - return 0; -} - -/** Convert a UTF-8 encoded character to CP437. */ -int -unicode_utf8_to_cp437(char *cp_character, const utf8_t *utf8_string, - size_t *length) -{ - ucs4_t ucs4_character; - int result; - - result = unicode_utf8_to_ucs4(&ucs4_character, utf8_string, length); - if (result!=0) { - /* pass decoding characters upstream */ - return result; - } - - if (ucs4_character<0x7F) { - *cp_character = (char)ucs4_character; - } else { - struct { ucs4_t ucs4; unsigned char cp437; } xref[160] = { - {0x00A0, 255}, {0x00A1, 173}, {0x00A2, 155}, {0x00A3, 156}, - {0x00A5, 157}, {0x00A7, 21}, {0x00AA, 166}, {0x00AB, 174}, - {0x00AC, 170}, {0x00B0, 248}, {0x00B1, 241}, {0x00B2, 253}, - {0x00B5, 230}, {0x00B6, 20}, {0x00B7, 250}, {0x00BA, 167}, - {0x00BB, 175}, {0x00BC, 172}, {0x00BD, 171}, {0x00BF, 168}, - {0x00C4, 142}, {0x00C5, 143}, {0x00C6, 146}, {0x00C7, 128}, - {0x00C9, 144}, {0x00D1, 165}, {0x00D6, 153}, {0x00DC, 154}, - {0x00DF, 225}, {0x00E0, 133}, {0x00E1, 160}, {0x00E2, 131}, - {0x00E4, 132}, {0x00E5, 134}, {0x00E6, 145}, {0x00E7, 135}, - {0x00E8, 138}, {0x00E9, 130}, {0x00EA, 136}, {0x00EB, 137}, - {0x00EC, 141}, {0x00ED, 161}, {0x00EE, 140}, {0x00EF, 139}, - {0x00F1, 164}, {0x00F2, 149}, {0x00F3, 162}, {0x00F4, 147}, - {0x00F6, 148}, {0x00F7, 246}, {0x00F9, 151}, {0x00FA, 163}, - {0x00FB, 150}, {0x00FC, 129}, {0x00FF, 152}, {0x0192, 159}, - {0x0393, 226}, {0x0398, 233}, {0x03A3, 228}, {0x03A6, 232}, - {0x03A9, 234}, {0x03B1, 224}, {0x03B4, 235}, {0x03B5, 238}, - {0x03C0, 227}, {0x03C3, 229}, {0x03C4, 231}, {0x03C6, 237}, - {0x2022, 7}, {0x203C, 19}, {0x207F, 252}, {0x20A7, 158}, - {0x2190, 27}, {0x2191, 24}, {0x2192, 26}, {0x2193, 25}, - {0x2194, 29}, {0x2195, 18}, {0x21A8, 23}, {0x2219, 249}, - {0x221A, 251}, {0x221E, 236}, {0x221F, 28}, {0x2229, 239}, - {0x2248, 247}, {0x2261, 240}, {0x2264, 243}, {0x2265, 242}, - {0x2302, 127}, {0x2310, 169}, {0x2320, 244}, {0x2321, 245}, - {0x2500, 196}, {0x2502, 179}, {0x250C, 218}, {0x2510, 191}, - {0x2514, 192}, {0x2518, 217}, {0x251C, 195}, {0x2524, 180}, - {0x252C, 194}, {0x2534, 193}, {0x253C, 197}, {0x2550, 205}, - {0x2551, 186}, {0x2552, 213}, {0x2553, 214}, {0x2554, 201}, - {0x2555, 184}, {0x2556, 183}, {0x2557, 187}, {0x2558, 212}, - {0x2559, 211}, {0x255A, 200}, {0x255B, 190}, {0x255C, 189}, - {0x255D, 188}, {0x255E, 198}, {0x255F, 199}, {0x2560, 204}, - {0x2561, 181}, {0x2562, 182}, {0x2563, 185}, {0x2564, 209}, - {0x2565, 210}, {0x2566, 203}, {0x2567, 207}, {0x2568, 208}, - {0x2569, 202}, {0x256A, 216}, {0x256B, 215}, {0x256C, 206}, - {0x2580, 223}, {0x2584, 220}, {0x2588, 219}, {0x258C, 221}, - {0x2590, 222}, {0x2591, 176}, {0x2592, 177}, {0x2593, 178}, - {0x25A0, 254}, {0x25AC, 22}, {0x25B2, 30}, {0x25BA, 16}, - {0x25BC, 31}, {0x25C4, 17}, {0x25CB, 9}, {0x25D8, 8}, - {0x25D9, 10}, {0x263A, 1}, {0x263B, 2}, {0x263C, 15}, - {0x2640, 12}, {0x2642, 11}, {0x2660, 6}, {0x2663, 5}, - {0x2665, 3}, {0x2666, 4}, {0x266A, 13}, {0x266B, 14} - }; - int l=0, r=160; - while (l!=r) { - int m = (l+r)/2; - if (xref[m].ucs4==ucs4_character) { - *cp_character = (char)xref[m].cp437; - break; - } - else if (xref[m].ucs4=0xA0) { - *cp_character = (char)ucs4_character; - } else { - struct { ucs4_t ucs4; unsigned char cp; } xref[] = { - {0x20ac, 0x80}, {0x0081, 0x81}, {0x201a, 0x82}, {0x0192, 0x83}, - {0x201e, 0x84}, {0x2026, 0x85}, {0x2020, 0x86}, {0x2021, 0x87}, - {0x02c6, 0x88}, {0x2030, 0x89}, {0x0160, 0x8a}, {0x2039, 0x8b}, - {0x0152, 0x8c}, {0x008d, 0x8d}, {0x017d, 0x8e}, {0x008f, 0x8f}, - {0x0090, 0x90}, {0x2018, 0x91}, {0x2019, 0x92}, {0x201c, 0x93}, - {0x201d, 0x94}, {0x2022, 0x95}, {0x2013, 0x96}, {0x2014, 0x97}, - {0x02dc, 0x98}, {0x2122, 0x99}, {0x0161, 0x9a}, {0x203a, 0x9b}, - {0x0153, 0x9c}, {0x009d, 0x9d}, {0x017e, 0x9e}, {0x0178, 0x9f} - }; - int l=0, r=sizeof(xref)/sizeof(xref[0]); - while (l!=r) { - int m = (l+r)/2; - if (xref[m].ucs4==ucs4_character) { - *cp_character = (char)xref[m].cp; - break; - } - else if (xref[m].ucs4 + * | | Enno Rehling + * | Eressea PBEM host | Katja Zedel + * | (c) 1998 - 2007 | + * | | This program may not be used, modified or distributed + * +-------------------+ without prior permission by the authors of Eressea. + * + */ + +#include +#include "unicode.h" + +#include +#include + +#define B00000000 0x00 +#define B10000000 0x80 +#define B11000000 0xC0 +#define B11100000 0xE0 +#define B11110000 0xF0 +#define B11111000 0xF8 +#define B11111100 0xFC +#define B11111110 0xFE + +#define B00111111 0x3F +#define B00011111 0x1F +#define B00001111 0x0F +#define B00000111 0x07 +#define B00000011 0x03 +#define B00000001 0x01 + +int +unicode_utf8_tolower(utf8_t *op, size_t outlen, const utf8_t *ip) +{ + while (*ip) { + ucs4_t ucs = *ip; + ucs4_t low; + size_t size = 1; + + if (ucs & 0x80) { + int ret = unicode_utf8_to_ucs4(&ucs, ip, &size); + if (ret!=0) { + return ret; + } + } + if (size>outlen) { + return ENOMEM; + } + low = towlower((wint_t)ucs); + if (low==ucs) { + memcpy(op, ip, size); + ip += size; + op += size; + outlen -=size; + } else { + ip += size; + unicode_ucs4_to_utf8(op, &size, low); + op += size; + outlen -=size; + } + } + + if (outlen<=0) { + return ENOMEM; + } + *op = 0; + return 0; +} + +int +unicode_latin1_to_utf8(utf8_t *out, size_t *outlen, const char *in, size_t *inlen) +{ + int is = (int)*inlen; + int os = (int)*outlen; + const char * ip = in; + utf8_t * op = out; + + while (ip-in 0xBF) { + if (op-out>=os-1) break; + *op++ = 0xC3; + *op++ = c-64; + } else if (c>0x7F) { + if (op-out>=os-1) break; + *op++ = 0xC2; + *op++ = c; + } else { + if (op-out>=os) break; + *op++ = c; + } + ++ip; + } + *outlen = op-out; + *inlen = ip-in; + return (int)*outlen; +} + +int +unicode_utf8_strcasecmp(const utf8_t * a, const char * b) +{ + while (*a && *b) { + int ret; + size_t size; + ucs4_t ucsa = *a, ucsb = *b; + + if (ucsa & 0x80) { + ret = unicode_utf8_to_ucs4(&ucsa, a, &size); + if (ret!=0) return -1; + a += size; + } else ++a; + if (ucsb & 0x80) { + ret = unicode_utf8_to_ucs4(&ucsb, b, &size); + if (ret!=0) return -1; + b += size; + } else ++b; + + if (ucsb!=ucsa) { + ucsb = towlower((wint_t)ucsb); + ucsa = towlower((wint_t)ucsa); + if (ucsbucsa) return -1; + } + } + if (*b) return -1; + if (*a) return 1; + return 0; +} + +/* Convert a UCS-4 character to UTF-8. */ +int +unicode_ucs4_to_utf8 (utf8_t *utf8_character, size_t *size, ucs4_t ucs4_character) +{ + int utf8_bytes; + + if (ucs4_character <= 0x0000007F) { + /* 0xxxxxxx */ + utf8_bytes = 1; + utf8_character[0] = (char) ucs4_character; + } + else if (ucs4_character <= 0x000007FF) { + /* 110xxxxx 10xxxxxx */ + utf8_bytes = 2; + utf8_character[0] = (char) ((ucs4_character >> 6) | B11000000); + utf8_character[1] = (char) ((ucs4_character & B00111111) | B10000000); + } + else if (ucs4_character <= 0x0000FFFF) { + /* 1110xxxx 10xxxxxx 10xxxxxx */ + utf8_bytes = 3; + utf8_character[0] = (char) ((ucs4_character >> 12) | B11100000); + utf8_character[1] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); + utf8_character[2] = (char) ((ucs4_character & B00111111) | B10000000); + } + else if (ucs4_character <= 0x001FFFFF) { + /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_bytes = 4; + utf8_character[0] = (char) ((ucs4_character >> 18) | B11110000); + utf8_character[1] = (char) (((ucs4_character >> 12) & B00111111) | B10000000); + utf8_character[2] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); + utf8_character[3] = (char) ((ucs4_character & B00111111) | B10000000); + } + else if (ucs4_character <= 0x03FFFFFF) { + /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_bytes = 5; + utf8_character[0] = (char) ((ucs4_character >> 24) | B11111000); + utf8_character[1] = (char) (((ucs4_character >> 18) & B00111111) | B10000000); + utf8_character[2] = (char) (((ucs4_character >> 12) & B00111111) | B10000000); + utf8_character[3] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); + utf8_character[4] = (char) ((ucs4_character & B00111111) | B10000000); + } + else if (ucs4_character <= 0x7FFFFFFF) { + /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_bytes = 6; + utf8_character[0] = (char) ((ucs4_character >> 30) | B11111100); + utf8_character[1] = (char) (((ucs4_character >> 24) & B00111111) | B10000000); + utf8_character[2] = (char) (((ucs4_character >> 18) & B00111111) | B10000000); + utf8_character[3] = (char) (((ucs4_character >> 12) & B00111111) | B10000000); + utf8_character[4] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); + utf8_character[5] = (char) ((ucs4_character & B00111111) | B10000000); + } + else { + return EILSEQ; + } + + *size = utf8_bytes; + + return 0; +} + + +/* Convert a UTF-8 encoded character to UCS-4. */ +int +unicode_utf8_to_ucs4(ucs4_t *ucs4_character, const utf8_t *utf8_string, + size_t *length) +{ + utf8_t utf8_character = utf8_string[0]; + + /* Is the character in the ASCII range? If so, just copy it to the + output. */ + if (~utf8_character & 0x80) + { + *ucs4_character = utf8_character; + *length = 1; + } + else if ((utf8_character & 0xE0) == 0xC0) + { + /* A two-byte UTF-8 sequence. Make sure the other byte is good. */ + if (utf8_string[1] != '\0' && + (utf8_string[1] & 0xC0) != 0x80) + { + return EILSEQ; + } + + *ucs4_character = + ((utf8_string[1] & 0x3F) << 0) + + ((utf8_character & 0x1F) << 6); + *length = 2; + } + else if ((utf8_character & 0xF0) == 0xE0) + { + /* A three-byte UTF-8 sequence. Make sure the other bytes are + good. */ + if ((utf8_string[1] != '\0') && + (utf8_string[1] & 0xC0) != 0x80 && + (utf8_string[2] != '\0') && + (utf8_string[2] & 0xC0) != 0x80) + { + return EILSEQ; + } + + *ucs4_character = + ((utf8_string[2] & 0x3F) << 0) + + ((utf8_string[1] & 0x3F) << 6) + + ((utf8_character & 0x0F) << 12); + *length = 3; + } + else if ((utf8_character & 0xF8) == 0xF0) + { + /* A four-byte UTF-8 sequence. Make sure the other bytes are + good. */ + if ((utf8_string[1] != '\0') && + (utf8_string[1] & 0xC0) != 0x80 && + (utf8_string[2] != '\0') && + (utf8_string[2] & 0xC0) != 0x80 && + (utf8_string[3] != '\0') && + (utf8_string[3] & 0xC0) != 0x80) + { + return EILSEQ; + } + + *ucs4_character = + ((utf8_string[3] & 0x3F) << 0) + + ((utf8_string[2] & 0x3F) << 6) + + ((utf8_string[1] & 0x3F) << 12) + + ((utf8_character & 0x07) << 18); + *length = 4; + } + else if ((utf8_character & 0xFC) == 0xF8) + { + /* A five-byte UTF-8 sequence. Make sure the other bytes are + good. */ + if ((utf8_string[1] != '\0') && + (utf8_string[1] & 0xC0) != 0x80 && + (utf8_string[2] != '\0') && + (utf8_string[2] & 0xC0) != 0x80 && + (utf8_string[3] != '\0') && + (utf8_string[3] & 0xC0) != 0x80 && + (utf8_string[4] != '\0') && + (utf8_string[4] & 0xC0) != 0x80) + { + return EILSEQ; + } + + *ucs4_character = + ((utf8_string[4] & 0x3F) << 0) + + ((utf8_string[3] & 0x3F) << 6) + + ((utf8_string[2] & 0x3F) << 12) + + ((utf8_string[1] & 0x3F) << 18) + + ((utf8_character & 0x03) << 24); + *length = 5; + } + else if ((utf8_character & 0xFE) == 0xFC) + { + /* A six-byte UTF-8 sequence. Make sure the other bytes are + good. */ + if ((utf8_string[1] != '\0') && + (utf8_string[1] & 0xC0) != 0x80 && + (utf8_string[2] != '\0') && + (utf8_string[2] & 0xC0) != 0x80 && + (utf8_string[3] != '\0') && + (utf8_string[3] & 0xC0) != 0x80 && + (utf8_string[4] != '\0') && + (utf8_string[4] & 0xC0) != 0x80 && + (utf8_string[5] != '\0') && + (utf8_string[5] & 0xC0) != 0x80) + { + return EILSEQ; + } + + *ucs4_character = + ((utf8_string[5] & 0x3F) << 0) + + ((utf8_string[4] & 0x3F) << 6) + + ((utf8_string[3] & 0x3F) << 12) + + ((utf8_string[2] & 0x3F) << 18) + + ((utf8_string[1] & 0x3F) << 24) + + ((utf8_character & 0x01) << 30); + *length = 6; + } + else + { + return EILSEQ; + } + + return 0; +} + +/** Convert a UTF-8 encoded character to CP437. */ +int +unicode_utf8_to_cp437(char *cp_character, const utf8_t *utf8_string, + size_t *length) +{ + ucs4_t ucs4_character; + int result; + + result = unicode_utf8_to_ucs4(&ucs4_character, utf8_string, length); + if (result!=0) { + /* pass decoding characters upstream */ + return result; + } + + if (ucs4_character<0x7F) { + *cp_character = (char)ucs4_character; + } else { + struct { ucs4_t ucs4; unsigned char cp437; } xref[160] = { + {0x00A0, 255}, {0x00A1, 173}, {0x00A2, 155}, {0x00A3, 156}, + {0x00A5, 157}, {0x00A7, 21}, {0x00AA, 166}, {0x00AB, 174}, + {0x00AC, 170}, {0x00B0, 248}, {0x00B1, 241}, {0x00B2, 253}, + {0x00B5, 230}, {0x00B6, 20}, {0x00B7, 250}, {0x00BA, 167}, + {0x00BB, 175}, {0x00BC, 172}, {0x00BD, 171}, {0x00BF, 168}, + {0x00C4, 142}, {0x00C5, 143}, {0x00C6, 146}, {0x00C7, 128}, + {0x00C9, 144}, {0x00D1, 165}, {0x00D6, 153}, {0x00DC, 154}, + {0x00DF, 225}, {0x00E0, 133}, {0x00E1, 160}, {0x00E2, 131}, + {0x00E4, 132}, {0x00E5, 134}, {0x00E6, 145}, {0x00E7, 135}, + {0x00E8, 138}, {0x00E9, 130}, {0x00EA, 136}, {0x00EB, 137}, + {0x00EC, 141}, {0x00ED, 161}, {0x00EE, 140}, {0x00EF, 139}, + {0x00F1, 164}, {0x00F2, 149}, {0x00F3, 162}, {0x00F4, 147}, + {0x00F6, 148}, {0x00F7, 246}, {0x00F9, 151}, {0x00FA, 163}, + {0x00FB, 150}, {0x00FC, 129}, {0x00FF, 152}, {0x0192, 159}, + {0x0393, 226}, {0x0398, 233}, {0x03A3, 228}, {0x03A6, 232}, + {0x03A9, 234}, {0x03B1, 224}, {0x03B4, 235}, {0x03B5, 238}, + {0x03C0, 227}, {0x03C3, 229}, {0x03C4, 231}, {0x03C6, 237}, + {0x2022, 7}, {0x203C, 19}, {0x207F, 252}, {0x20A7, 158}, + {0x2190, 27}, {0x2191, 24}, {0x2192, 26}, {0x2193, 25}, + {0x2194, 29}, {0x2195, 18}, {0x21A8, 23}, {0x2219, 249}, + {0x221A, 251}, {0x221E, 236}, {0x221F, 28}, {0x2229, 239}, + {0x2248, 247}, {0x2261, 240}, {0x2264, 243}, {0x2265, 242}, + {0x2302, 127}, {0x2310, 169}, {0x2320, 244}, {0x2321, 245}, + {0x2500, 196}, {0x2502, 179}, {0x250C, 218}, {0x2510, 191}, + {0x2514, 192}, {0x2518, 217}, {0x251C, 195}, {0x2524, 180}, + {0x252C, 194}, {0x2534, 193}, {0x253C, 197}, {0x2550, 205}, + {0x2551, 186}, {0x2552, 213}, {0x2553, 214}, {0x2554, 201}, + {0x2555, 184}, {0x2556, 183}, {0x2557, 187}, {0x2558, 212}, + {0x2559, 211}, {0x255A, 200}, {0x255B, 190}, {0x255C, 189}, + {0x255D, 188}, {0x255E, 198}, {0x255F, 199}, {0x2560, 204}, + {0x2561, 181}, {0x2562, 182}, {0x2563, 185}, {0x2564, 209}, + {0x2565, 210}, {0x2566, 203}, {0x2567, 207}, {0x2568, 208}, + {0x2569, 202}, {0x256A, 216}, {0x256B, 215}, {0x256C, 206}, + {0x2580, 223}, {0x2584, 220}, {0x2588, 219}, {0x258C, 221}, + {0x2590, 222}, {0x2591, 176}, {0x2592, 177}, {0x2593, 178}, + {0x25A0, 254}, {0x25AC, 22}, {0x25B2, 30}, {0x25BA, 16}, + {0x25BC, 31}, {0x25C4, 17}, {0x25CB, 9}, {0x25D8, 8}, + {0x25D9, 10}, {0x263A, 1}, {0x263B, 2}, {0x263C, 15}, + {0x2640, 12}, {0x2642, 11}, {0x2660, 6}, {0x2663, 5}, + {0x2665, 3}, {0x2666, 4}, {0x266A, 13}, {0x266B, 14} + }; + int l=0, r=160; + while (l!=r) { + int m = (l+r)/2; + if (xref[m].ucs4==ucs4_character) { + *cp_character = (char)xref[m].cp437; + break; + } + else if (xref[m].ucs4=0xA0) { + *cp_character = (char)ucs4_character; + } else { + struct { ucs4_t ucs4; unsigned char cp; } xref[] = { + {0x20ac, 0x80}, {0x0081, 0x81}, {0x201a, 0x82}, {0x0192, 0x83}, + {0x201e, 0x84}, {0x2026, 0x85}, {0x2020, 0x86}, {0x2021, 0x87}, + {0x02c6, 0x88}, {0x2030, 0x89}, {0x0160, 0x8a}, {0x2039, 0x8b}, + {0x0152, 0x8c}, {0x008d, 0x8d}, {0x017d, 0x8e}, {0x008f, 0x8f}, + {0x0090, 0x90}, {0x2018, 0x91}, {0x2019, 0x92}, {0x201c, 0x93}, + {0x201d, 0x94}, {0x2022, 0x95}, {0x2013, 0x96}, {0x2014, 0x97}, + {0x02dc, 0x98}, {0x2122, 0x99}, {0x0161, 0x9a}, {0x203a, 0x9b}, + {0x0153, 0x9c}, {0x009d, 0x9d}, {0x017e, 0x9e}, {0x0178, 0x9f} + }; + int l=0, r=sizeof(xref)/sizeof(xref[0]); + while (l!=r) { + int m = (l+r)/2; + if (xref[m].ucs4==ucs4_character) { + *cp_character = (char)xref[m].cp; + break; + } + else if (xref[m].ucs4 - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef _UNICODE_H -#define _UNICODE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#define USE_UNICODE - typedef unsigned long ucs4_t; - typedef char utf8_t; - - extern int unicode_utf8_to_cp437(char *result, const utf8_t *utf8_string, size_t *length); - extern int unicode_utf8_to_cp1252(char *result, const utf8_t *utf8_string, size_t *length); - extern int unicode_utf8_to_ucs4(ucs4_t *result, const utf8_t *utf8_string, size_t *length); - extern int unicode_ucs4_to_utf8 (utf8_t *result, size_t *size, ucs4_t ucs4_character); - extern int unicode_utf8_strcasecmp(const utf8_t * a, const utf8_t * b); - extern int unicode_latin1_to_utf8(utf8_t *out, size_t *outlen, const char *in, size_t *inlen); - extern int unicode_utf8_tolower(utf8_t *out, size_t outlen, const utf8_t *in); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef _UNICODE_H +#define _UNICODE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#define USE_UNICODE + typedef unsigned long ucs4_t; + typedef char utf8_t; + + extern int unicode_utf8_to_cp437(char *result, const utf8_t *utf8_string, size_t *length); + extern int unicode_utf8_to_cp1252(char *result, const utf8_t *utf8_string, size_t *length); + extern int unicode_utf8_to_ucs4(ucs4_t *result, const utf8_t *utf8_string, size_t *length); + extern int unicode_ucs4_to_utf8 (utf8_t *result, size_t *size, ucs4_t ucs4_character); + extern int unicode_utf8_strcasecmp(const utf8_t * a, const utf8_t * b); + extern int unicode_latin1_to_utf8(utf8_t *out, size_t *outlen, const char *in, size_t *inlen); + extern int unicode_utf8_tolower(utf8_t *out, size_t outlen, const utf8_t *in); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/variant.h b/src/util/variant.h index 7caa3e94a..62fe323c6 100644 --- a/src/util/variant.h +++ b/src/util/variant.h @@ -1,24 +1,24 @@ -#ifndef STRUCT_VARIANT_H -#define STRUCT_VARIANT_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef union variant { - void *v; - int i; - char c; - short s; - short sa[2]; - char ca[4]; - float f; -} variant; - -typedef enum variant_type { - VAR_NONE, VAR_INT, VAR_VOIDPTR, VAR_CHAR, VAR_SHORT, VAR_SHORTA, VAR_CHARA, VAR_FLOAT -} variant_type; - -#ifdef __cplusplus -} -#endif -#endif +#ifndef STRUCT_VARIANT_H +#define STRUCT_VARIANT_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef union variant { + void *v; + int i; + char c; + short s; + short sa[2]; + char ca[4]; + float f; +} variant; + +typedef enum variant_type { + VAR_NONE, VAR_INT, VAR_VOIDPTR, VAR_CHAR, VAR_SHORT, VAR_SHORTA, VAR_CHARA, VAR_FLOAT +} variant_type; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/vmap.c b/src/util/vmap.c index b24355844..6ca8f473d 100644 --- a/src/util/vmap.c +++ b/src/util/vmap.c @@ -1,146 +1,146 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifdef _MSC_VER -#pragma warning (disable: 4711) -#endif - -#include -#include -#include -#include -#include "vmap.h" - -size_t -vmap_lowerbound(const vmap * vm, const int key) -/* returns the index of the entry which has the greatest key that is less or - * equal to 'key' */ -{ - vmapentry *first = vm->data, *middle; - unsigned int half, len = vm->size; - while (len > 0) { - half = len / 2; - middle = first; - middle += half; - if (middle->key < key) { - first = middle + 1; - len = len - half - 1; - } else - len = half; - } - return first - vm->data; -} - -void -vmap_init(vmap * map) -{ - map->size = 0; /* !! */ - map->maxsize = 4; - map->data = calloc(4, sizeof(vmapentry)); -} - -size_t -vmap_upperbound(const vmap * vm, const int key) -/* returns the index of the entry which has the smallest key that is greater - * or equal to 'key' */ -{ - unsigned int half, len = vm->size; - vmapentry *first = vm->data, *middle; - while (len > 0) { - half = len / 2; - middle = first; - middle += half; - if (key < middle->key) - len = half; - else { - first = middle + 1; - len = len - half - 1; - } - } - return first - vm->data; -} - -size_t -vmap_get(vmap * vm, const int key) -{ - size_t insert = vmap_lowerbound(vm, key); - vmapentry *at; - - /* make sure it's a unique key: */ - if (insert != vm->size && vm->data[insert].key == key) - return insert; - /* insert at this position: */ - if (vm->size == vm->maxsize) { - /* need more space */ - vm->maxsize *= 2; - vm->data = realloc(vm->data, vm->maxsize * sizeof(vmapentry)); - } - at = vm->data + insert; - memmove(at + 1, at, (vm->size - insert) * sizeof(vmapentry)); /* !1.3! */ - at->key = key; - at->value = 0; - ++vm->size; - return insert; -} - -size_t -vmap_insert(vmap * vm, const int key, void *data) -/* inserts an object into the vmap, identifies it with the 'key' which must be - * unique, and returns the vmapentry it created. */ -{ - size_t insert = vmap_lowerbound(vm, key); - vmapentry *at; - - /* make sure it's a unique key: */ - assert(insert == vm->size || vm->data[insert].key != key); - /* insert at this position: */ - if (vm->size == vm->maxsize) { - /* need more space */ - vm->maxsize = vm->maxsize ? (vm->maxsize * 2) : 4; - vm->data = realloc(vm->data, vm->maxsize * sizeof(vmapentry)); - } - at = vm->data + insert; - memmove(at + 1, at, (vm->size - insert) * sizeof(vmapentry)); - at->key = key; - at->value = data; - ++vm->size; - return insert; -} - -size_t -vmap_find(const vmap * vm, const int key) -/* returns the index of the vmapentry that's identified by the key or size (a - * past-the-end value) if it is not found. */ -{ - vmapentry *first = vm->data, *middle; - unsigned int half, len = vm->size; - while (len > 0) { - half = len / 2; - middle = first; - middle += half; - if (middle->key < key) { - first = middle + 1; - len = len - half - 1; - } else - len = half; - } - if (first != vm->data + vm->size && first->key == key) - return first - vm->data; - else - return vm->size; -} +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifdef _MSC_VER +#pragma warning (disable: 4711) +#endif + +#include +#include +#include +#include +#include "vmap.h" + +size_t +vmap_lowerbound(const vmap * vm, const int key) +/* returns the index of the entry which has the greatest key that is less or + * equal to 'key' */ +{ + vmapentry *first = vm->data, *middle; + unsigned int half, len = vm->size; + while (len > 0) { + half = len / 2; + middle = first; + middle += half; + if (middle->key < key) { + first = middle + 1; + len = len - half - 1; + } else + len = half; + } + return first - vm->data; +} + +void +vmap_init(vmap * map) +{ + map->size = 0; /* !! */ + map->maxsize = 4; + map->data = calloc(4, sizeof(vmapentry)); +} + +size_t +vmap_upperbound(const vmap * vm, const int key) +/* returns the index of the entry which has the smallest key that is greater + * or equal to 'key' */ +{ + unsigned int half, len = vm->size; + vmapentry *first = vm->data, *middle; + while (len > 0) { + half = len / 2; + middle = first; + middle += half; + if (key < middle->key) + len = half; + else { + first = middle + 1; + len = len - half - 1; + } + } + return first - vm->data; +} + +size_t +vmap_get(vmap * vm, const int key) +{ + size_t insert = vmap_lowerbound(vm, key); + vmapentry *at; + + /* make sure it's a unique key: */ + if (insert != vm->size && vm->data[insert].key == key) + return insert; + /* insert at this position: */ + if (vm->size == vm->maxsize) { + /* need more space */ + vm->maxsize *= 2; + vm->data = realloc(vm->data, vm->maxsize * sizeof(vmapentry)); + } + at = vm->data + insert; + memmove(at + 1, at, (vm->size - insert) * sizeof(vmapentry)); /* !1.3! */ + at->key = key; + at->value = 0; + ++vm->size; + return insert; +} + +size_t +vmap_insert(vmap * vm, const int key, void *data) +/* inserts an object into the vmap, identifies it with the 'key' which must be + * unique, and returns the vmapentry it created. */ +{ + size_t insert = vmap_lowerbound(vm, key); + vmapentry *at; + + /* make sure it's a unique key: */ + assert(insert == vm->size || vm->data[insert].key != key); + /* insert at this position: */ + if (vm->size == vm->maxsize) { + /* need more space */ + vm->maxsize = vm->maxsize ? (vm->maxsize * 2) : 4; + vm->data = realloc(vm->data, vm->maxsize * sizeof(vmapentry)); + } + at = vm->data + insert; + memmove(at + 1, at, (vm->size - insert) * sizeof(vmapentry)); + at->key = key; + at->value = data; + ++vm->size; + return insert; +} + +size_t +vmap_find(const vmap * vm, const int key) +/* returns the index of the vmapentry that's identified by the key or size (a + * past-the-end value) if it is not found. */ +{ + vmapentry *first = vm->data, *middle; + unsigned int half, len = vm->size; + while (len > 0) { + half = len / 2; + middle = first; + middle += half; + if (middle->key < key) { + first = middle + 1; + len = len - half - 1; + } else + len = half; + } + if (first != vm->data + vm->size && first->key == key) + return first - vm->data; + else + return vm->size; +} diff --git a/src/util/vmap.h b/src/util/vmap.h index e38b5c52f..872d4db35 100644 --- a/src/util/vmap.h +++ b/src/util/vmap.h @@ -1,47 +1,47 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef VMAP_H -#define VMAP_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct vmapentry vmapentry; -struct vmapentry { - int key; - void *value; -}; -typedef struct vmap vmap; -struct vmap { - vmapentry *data; - unsigned int size; - unsigned int maxsize; -}; - -size_t vmap_lowerbound(const vmap * vm, const int key); -size_t vmap_upperbound(const vmap * vm, const int key); -size_t vmap_insert(vmap * vm, const int key, void *data); -size_t vmap_find(const vmap * vm, const int key); -size_t vmap_get(vmap * vm, const int key); -void vmap_init(vmap * vm); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef VMAP_H +#define VMAP_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct vmapentry vmapentry; +struct vmapentry { + int key; + void *value; +}; +typedef struct vmap vmap; +struct vmap { + vmapentry *data; + unsigned int size; + unsigned int maxsize; +}; + +size_t vmap_lowerbound(const vmap * vm, const int key); +size_t vmap_upperbound(const vmap * vm, const int key); +size_t vmap_insert(vmap * vm, const int key, void *data); +size_t vmap_find(const vmap * vm, const int key); +size_t vmap_get(vmap * vm, const int key); +void vmap_init(vmap * vm); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/vset.c b/src/util/vset.c index 693490392..f4bac1bb0 100644 --- a/src/util/vset.c +++ b/src/util/vset.c @@ -1,104 +1,104 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "vset.h" - -void -vset_init(vset * s) -{ - s->data = 0; - s->size = 0; - s->maxsize = 0; -} - -void -vset_destroy(vset * s) -{ - if (s->data) - free(s->data); -} - -int -vset_erase(vset * s, void *item) -{ - size_t i; - - for (i = 0; i != s->size; ++i) - if (s->data[i] == item) { - s->size--; - s->data[i] = s->data[s->size]; - return 1; - } - return 0; -} - -size_t -vset_add(vset * s, void *item) -{ - size_t i; - - if (!s->data) { - s->size = 0; - s->maxsize = 4; - s->data = calloc(4, sizeof(void *)); - } - for (i = 0; i != s->size; ++i) - if (s->data[i] == item) - return i; - if (s->size == s->maxsize) { - s->maxsize *= 2; - s->data = realloc(s->data, s->maxsize * sizeof(void *)); - } - s->data[s->size] = item; - ++s->size; - return s->size - 1; -} - -void * -vset_pop(vset *s) -{ - if(s->size == 0) return NULL; - s->size--; - return s->data[s->size+1]; -} - -int -vset_count(vset *s, void *item) -{ - size_t i; - int c = 0; - - for(i = 0; i != s->size; ++i) { - if(s->data[i] == item) c++; - } - - return c; -} - -void -vset_concat(vset *to, vset *from) -{ - size_t i; - - for(i=0; i != from->size; ++i) { - vset_add(to, from->data[i]); - } -} - +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include +#include +#include "vset.h" + +void +vset_init(vset * s) +{ + s->data = 0; + s->size = 0; + s->maxsize = 0; +} + +void +vset_destroy(vset * s) +{ + if (s->data) + free(s->data); +} + +int +vset_erase(vset * s, void *item) +{ + size_t i; + + for (i = 0; i != s->size; ++i) + if (s->data[i] == item) { + s->size--; + s->data[i] = s->data[s->size]; + return 1; + } + return 0; +} + +size_t +vset_add(vset * s, void *item) +{ + size_t i; + + if (!s->data) { + s->size = 0; + s->maxsize = 4; + s->data = calloc(4, sizeof(void *)); + } + for (i = 0; i != s->size; ++i) + if (s->data[i] == item) + return i; + if (s->size == s->maxsize) { + s->maxsize *= 2; + s->data = realloc(s->data, s->maxsize * sizeof(void *)); + } + s->data[s->size] = item; + ++s->size; + return s->size - 1; +} + +void * +vset_pop(vset *s) +{ + if(s->size == 0) return NULL; + s->size--; + return s->data[s->size+1]; +} + +int +vset_count(vset *s, void *item) +{ + size_t i; + int c = 0; + + for(i = 0; i != s->size; ++i) { + if(s->data[i] == item) c++; + } + + return c; +} + +void +vset_concat(vset *to, vset *from) +{ + size_t i; + + for(i=0; i != from->size; ++i) { + vset_add(to, from->data[i]); + } +} + diff --git a/src/util/vset.h b/src/util/vset.h index 917180d4b..30a045ceb 100644 --- a/src/util/vset.h +++ b/src/util/vset.h @@ -1,43 +1,43 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef VOIDPTR_SETS -#define VOIDPTR_SETS -#ifdef __cplusplus -extern "C" { -#endif - -#include -typedef struct vset vset; -struct vset { - void **data; - size_t size; - size_t maxsize; -}; -extern void vset_init(vset * s); -extern void vset_destroy(vset * s); -extern size_t vset_add(vset * s, void *); -extern int vset_erase(vset * s, void *); -extern int vset_count(vset *s, void * i); -extern void *vset_pop(vset *s); -extern void vset_concat(vset *to, vset *from); - -#ifdef __cplusplus -} -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef VOIDPTR_SETS +#define VOIDPTR_SETS +#ifdef __cplusplus +extern "C" { +#endif + +#include +typedef struct vset vset; +struct vset { + void **data; + size_t size; + size_t maxsize; +}; +extern void vset_init(vset * s); +extern void vset_destroy(vset * s); +extern size_t vset_add(vset * s, void *); +extern int vset_erase(vset * s, void *); +extern int vset_count(vset *s, void * i); +extern void *vset_pop(vset *s); +extern void vset_concat(vset *to, vset *from); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/util/windir.c b/src/util/windir.c index 4bdaadaf5..9d62f8360 100644 --- a/src/util/windir.c +++ b/src/util/windir.c @@ -1,56 +1,56 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifdef _MSC_VER -#include - -#include -#include -#include "windir.h" - -DIR * -opendir(const char *name) -{ - static DIR direct; /* STATIC_RESULT: used for return, not across calls */ - - direct.first = 1; - _searchenv(name, "ERESSEA_PATH", direct.name); - if (*direct.name != '\0') - return &direct; - return NULL; -} - -struct dirent * -readdir(DIR * thedir) -{ - static struct _finddata_t ft; /* STATIC_RESULT: used for return, not across calls */ - static struct dirent de; /* STATIC_RESULT: used for return, not across calls */ - char where[_MAX_PATH]; - - strcat(strcpy(where, thedir->name), "/*"); - if (thedir->first) { - thedir->first = 0; - de.hnd = _findfirst(where, &ft); - } else { - if (_findnext(de.hnd, &ft) != 0) - return NULL; - } - _splitpath(ft.name, de.d_drive, de.d_dir, de.d_name, de.d_ext); - return &de; -} -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifdef _MSC_VER +#include + +#include +#include +#include "windir.h" + +DIR * +opendir(const char *name) +{ + static DIR direct; /* STATIC_RESULT: used for return, not across calls */ + + direct.first = 1; + _searchenv(name, "ERESSEA_PATH", direct.name); + if (*direct.name != '\0') + return &direct; + return NULL; +} + +struct dirent * +readdir(DIR * thedir) +{ + static struct _finddata_t ft; /* STATIC_RESULT: used for return, not across calls */ + static struct dirent de; /* STATIC_RESULT: used for return, not across calls */ + char where[_MAX_PATH]; + + strcat(strcpy(where, thedir->name), "/*"); + if (thedir->first) { + thedir->first = 0; + de.hnd = _findfirst(where, &ft); + } else { + if (_findnext(de.hnd, &ft) != 0) + return NULL; + } + _splitpath(ft.name, de.d_drive, de.d_dir, de.d_name, de.d_ext); + return &de; +} +#endif diff --git a/src/util/windir.h b/src/util/windir.h index 77aed13c1..de9851aa9 100644 --- a/src/util/windir.h +++ b/src/util/windir.h @@ -1,50 +1,50 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef WINDIR_H -#define WINDIR_H - -#ifdef _MSC_VER -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -typedef struct DIR { - char name[_MAX_PATH]; - int first; -} DIR; - -typedef struct dirent { - char d_path[_MAX_PATH]; - char d_name[_MAX_FNAME]; - char d_drive[_MAX_DRIVE]; - char d_dir[_MAX_DIR]; - char d_ext[_MAX_EXT]; - intptr_t hnd; -} dirent; - -DIR *opendir(const char *name); -struct dirent *readdir(DIR * thedir); - -#ifdef __cplusplus -} -#endif -#endif -#endif +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef WINDIR_H +#define WINDIR_H + +#ifdef _MSC_VER +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +typedef struct DIR { + char name[_MAX_PATH]; + int first; +} DIR; + +typedef struct dirent { + char d_path[_MAX_PATH]; + char d_name[_MAX_FNAME]; + char d_drive[_MAX_DRIVE]; + char d_dir[_MAX_DIR]; + char d_ext[_MAX_EXT]; + intptr_t hnd; +} dirent; + +DIR *opendir(const char *name); +struct dirent *readdir(DIR * thedir); + +#ifdef __cplusplus +} +#endif +#endif +#endif diff --git a/src/util/xml.c b/src/util/xml.c index 32792baf6..e05019d7e 100644 --- a/src/util/xml.c +++ b/src/util/xml.c @@ -1,145 +1,139 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ -#include -#include "xml.h" - -/* util includes */ -#include "log.h" - -#ifdef HAVE_LIBXML -#include -#include -#endif - -/* libc includes */ -#include -#include -#include -#include -#include - -#ifdef HAVE_LIBXML -const xmlChar * -xml_i(double number) -{ - static char buffer[128]; - snprintf(buffer, sizeof(buffer), "%.0lf", number); - return (const xmlChar *)buffer; -} - -int -xml_ivalue(xmlNodePtr node, const char * name, int dflt) -{ - int i = dflt; - xmlChar * propValue = xmlGetProp(node, BAD_CAST name); - if (propValue!=NULL) { - i = atoi((const char*)propValue); - xmlFree(propValue); - } - return i; -} - -boolean -xml_bvalue(xmlNodePtr node, const char * name, boolean dflt) -{ - boolean result = dflt; - xmlChar * propValue = xmlGetProp(node, BAD_CAST name); - if (propValue!=NULL) { - if (strcmp((const char*)propValue, "no")==0) result = false; - else if (strcmp((const char*)propValue, "yes")==0) result = true; - else if (strcmp((const char*)propValue, "false")==0) result = false; - else if (strcmp((const char*)propValue, "true")==0) result = true; - else if (strcmp((const char*)propValue, "1")==0) { - log_warning(("boolean value is '1': %s::%s\n", node->name, name)); - result = true; - } - else if (strcmp((const char*)propValue, "0")==0) { - log_warning(("boolean value is '0': %s::%s\n", node->name, name)); - result = false; - } - xmlFree(propValue); - } - return result; -} - -double -xml_fvalue(xmlNodePtr node, const char * name, double dflt) -{ - double result = dflt; - xmlChar * propValue = xmlGetProp(node, BAD_CAST name); - if (propValue!=NULL) { - result = atof((const char*)propValue); - xmlFree(propValue); - } - return result; -} - -/* new xml functions */ -/* libxml includes */ -#include -#include -#include - -typedef struct xml_reader { - struct xml_reader * next; - xml_callback callback; -} xml_reader; - -static xml_reader * xmlReaders; - -void -xml_register_callback(xml_callback callback) -{ - xml_reader * reader = (xml_reader *)malloc(sizeof(xml_reader)); - xml_reader ** insert = &xmlReaders; - reader->callback = callback; - reader->next = NULL; - - while (*insert) insert = &(*insert)->next; - *insert = reader; -} -#endif - -int -read_xml(const char * filename, const char * catalog) -{ -#ifdef HAVE_LIBXML - xml_reader * reader = xmlReaders; - xmlDocPtr doc; - - if (catalog) { - xmlLoadCatalog(catalog); - } -#ifdef XML_PARSE_XINCLUDE - doc = xmlReadFile(filename, NULL, XML_PARSE_XINCLUDE); -#else - doc = xmlParseFile(filename); -#endif - if (doc==NULL) { - log_error(("could not open %s\n", filename)); - return -1; - } - - xmlXIncludeProcess(doc); - - while (reader!=NULL) { - int i = reader->callback(doc); - if (i!=0) { - return i; - } - reader = reader->next; - } - xmlFreeDoc(doc); -#endif - return 0; -} - +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ +#include +#include "xml.h" + +/* util includes */ +#include "log.h" + +#include +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +const xmlChar * +xml_i(double number) +{ + static char buffer[128]; + snprintf(buffer, sizeof(buffer), "%.0lf", number); + return (const xmlChar *)buffer; +} + +int +xml_ivalue(xmlNodePtr node, const char * name, int dflt) +{ + int i = dflt; + xmlChar * propValue = xmlGetProp(node, BAD_CAST name); + if (propValue!=NULL) { + i = atoi((const char*)propValue); + xmlFree(propValue); + } + return i; +} + +boolean +xml_bvalue(xmlNodePtr node, const char * name, boolean dflt) +{ + boolean result = dflt; + xmlChar * propValue = xmlGetProp(node, BAD_CAST name); + if (propValue!=NULL) { + if (strcmp((const char*)propValue, "no")==0) result = false; + else if (strcmp((const char*)propValue, "yes")==0) result = true; + else if (strcmp((const char*)propValue, "false")==0) result = false; + else if (strcmp((const char*)propValue, "true")==0) result = true; + else if (strcmp((const char*)propValue, "1")==0) { + log_warning(("boolean value is '1': %s::%s\n", node->name, name)); + result = true; + } + else if (strcmp((const char*)propValue, "0")==0) { + log_warning(("boolean value is '0': %s::%s\n", node->name, name)); + result = false; + } + xmlFree(propValue); + } + return result; +} + +double +xml_fvalue(xmlNodePtr node, const char * name, double dflt) +{ + double result = dflt; + xmlChar * propValue = xmlGetProp(node, BAD_CAST name); + if (propValue!=NULL) { + result = atof((const char*)propValue); + xmlFree(propValue); + } + return result; +} + +/* new xml functions */ +/* libxml includes */ +#include +#include +#include + +typedef struct xml_reader { + struct xml_reader * next; + xml_callback callback; +} xml_reader; + +static xml_reader * xmlReaders; + +void +xml_register_callback(xml_callback callback) +{ + xml_reader * reader = (xml_reader *)malloc(sizeof(xml_reader)); + xml_reader ** insert = &xmlReaders; + reader->callback = callback; + reader->next = NULL; + + while (*insert) insert = &(*insert)->next; + *insert = reader; +} + +int +read_xml(const char * filename, const char * catalog) +{ + xml_reader * reader = xmlReaders; + xmlDocPtr doc; + + if (catalog) { + xmlLoadCatalog(catalog); + } +#ifdef XML_PARSE_XINCLUDE + doc = xmlReadFile(filename, NULL, XML_PARSE_XINCLUDE); +#else + doc = xmlParseFile(filename); +#endif + if (doc==NULL) { + log_error(("could not open %s\n", filename)); + return -1; + } + + xmlXIncludeProcess(doc); + + while (reader!=NULL) { + int i = reader->callback(doc); + if (i!=0) { + return i; + } + reader = reader->next; + } + xmlFreeDoc(doc); + return 0; +} + diff --git a/src/util/xml.h b/src/util/xml.h index 1feb3dcfa..540b886e9 100644 --- a/src/util/xml.h +++ b/src/util/xml.h @@ -1,36 +1,36 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_UTIL_XML -#define H_UTIL_XML - - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef HAVE_LIBXML -#include - typedef int (*xml_callback)(xmlDocPtr); - extern void xml_register_callback(xml_callback callback); - extern double xml_fvalue(xmlNodePtr node, const char * name, double dflt); - extern int xml_ivalue(xmlNodePtr node, const char * name, int dflt); - extern boolean xml_bvalue(xmlNodePtr node, const char * name, boolean dflt); - const xmlChar * xml_i(double number); -#endif - - extern int read_xml(const char * filename, const char * catalog); - -#ifdef __cplusplus -} -#endif -#endif +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2003 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#ifndef H_UTIL_XML +#define H_UTIL_XML + + +#ifdef __cplusplus +extern "C" { +#endif + + /* new xml functions: */ +#include + + typedef int (*xml_callback)(xmlDocPtr); + extern void xml_register_callback(xml_callback callback); + extern int read_xml(const char * filename, const char * catalog); + extern double xml_fvalue(xmlNodePtr node, const char * name, double dflt); + extern int xml_ivalue(xmlNodePtr node, const char * name, int dflt); + extern boolean xml_bvalue(xmlNodePtr node, const char * name, boolean dflt); + + const xmlChar * xml_i(double number); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tools/atoi36.c b/tools/atoi36.c index 6b11ded07..a935e7650 100644 --- a/tools/atoi36.c +++ b/tools/atoi36.c @@ -1,35 +1,35 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2001 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include -#include -#include - -int main(int argc, char**argv) -{ - int i=1, reverse = 0; - if (strstr(argv[0], "itoa36")) reverse=1; - if (argc>1) { - if (strcmp(argv[1], "-r")==0) { - i=2; - reverse=1; - } - } - for (;i!=argc;++i) { - if (reverse) { - printf("%s -> %s\n", argv[i], itoa36(atoi(argv[i]))); - } - else printf("%s -> %d\n", argv[i], atoi36(argv[i])); - } - return 0; -} +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2001 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. +*/ + +#include +#include +#include +#include + +int main(int argc, char**argv) +{ + int i=1, reverse = 0; + if (strstr(argv[0], "itoa36")) reverse=1; + if (argc>1) { + if (strcmp(argv[1], "-r")==0) { + i=2; + reverse=1; + } + } + for (;i!=argc;++i) { + if (reverse) { + printf("%s -> %s\n", argv[i], itoa36(atoi(argv[i]))); + } + else printf("%s -> %d\n", argv[i], atoi36(argv[i])); + } + return 0; +} diff --git a/tools/gethash.c b/tools/gethash.c index 63f04713f..65fc1ef76 100644 --- a/tools/gethash.c +++ b/tools/gethash.c @@ -1,23 +1,23 @@ -#include -#include -#include - -int main(int argc, char ** argv) -{ - char key[4]; - char code[4]; - char result[4]; - int a, i, rot; - for (a=1;a +#include +#include + +int main(int argc, char ** argv) +{ + char key[4]; + char code[4]; + char result[4]; + int a, i, rot; + for (a=1;a - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2001 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - - */ - -#include -#include -#include - -static char *dwarf_syllable1[] = -{ - "B", "D", "F", "G", "Gl", "H", "K", "L", "M", "N", "R", "S", "T", "Th", "V", -}; - -static char *dwarf_syllable2[] = -{ - "a", "e", "i", "o", "oi", "u", -}; - -static char *dwarf_syllable3[] = -{ - "bur", "fur", "gan", "gnus", "gnar", "li", "lin", "lir", "mli", "nar", "nus", "rin", "ran", "sin", "sil", "sur", -}; - -static char *elf_syllable1[] = -{ - "Al", "An", "Bal", "Bel", "Cal", "Cel", "El", "Elr", "Elv", "Eow", "Ear", "F", "Fal", "Fel", "Fin", "G", "Gal", "Gel", "Gl", "Is", "Lan", "Leg", "Lom", "N", "Nal", "Nel", "S", "Sal", "Sel", "T", "Tal", "Tel", "Thr", "Tin", -}; - -static char *elf_syllable2[] = -{ - "a", "adrie", "ara", "e", "ebri", "ele", "ere", "i", "io", "ithra", "ilma", "il-Ga", "ili", "o", "orfi", "u", "y", -}; - -static char *elf_syllable3[] = -{ - "l", "las", "lad", "ldor", "ldur", "linde", "lith", "mir", "n", "nd", "ndel", "ndil", "ndir", "nduil", "ng", "mbor", "r", "rith", "ril", "riand", "rion", "s", "thien", "viel", "wen", "wyn", -}; - -static char *gnome_syllable1[] = -{ - "Aar", "An", "Ar", "As", "C", "H", "Han", "Har", "Hel", "Iir", "J", "Jan", "Jar", "K", "L", "M", "Mar", "N", "Nik", "Os", "Ol", "P", "R", "S", "Sam", "San", "T", "Ter", "Tom", "Ul", "V", "W", "Y", -}; - -static char *gnome_syllable2[] = -{ - "a", "aa", "ai", "e", "ei", "i", "o", "uo", "u", "uu", -}; - -static char *gnome_syllable3[] = -{ - "ron", "re", "la", "ki", "kseli", "ksi", "ku", "ja", "ta", "na", "namari", "neli", "nika", "nikki", "nu", "nukka", "ka", "ko", "li", "kki", "rik", "po", "to", "pekka", "rjaana", "rjatta", "rjukka", "la", "lla", "lli", "mo", "nni", -}; - -static char *hobbit_syllable1[] = -{ - "B", "Ber", "Br", "D", "Der", "Dr", "F", "Fr", "G", "H", "L", "Ler", "M", "Mer", "N", "P", "Pr", "Per", "R", "S", "T", "W", -}; - -static char *hobbit_syllable2[] = -{ - "a", "e", "i", "ia", "o", "oi", "u", -}; - -static char *hobbit_syllable3[] = -{ - "bo", "ck", "decan", "degar", "do", "doc", "go", "grin", "lba", "lbo", "lda", "ldo", "lla", "ll", "lo", "m", "mwise", "nac", "noc", "nwise", "p", "ppin", "pper", "tho", "to", -}; - -static char *human_syllable1[] = -{ - "Ab", "Ac", "Ad", "Af", "Agr", "Ast", "As", "Al", "Adw", "Adr", "Ar", "B", "Br", "C", "Cr", "Ch", "Cad", "D", "Dr", "Dw", "Ed", "Eth", "Et", "Er", "El", "Eow", "F", "Fr", "G", "Gr", "Gw", "Gal", "Gl", "H", "Ha", "Ib", "Jer", "K", "Ka", "Ked", "L", "Loth", "Lar", "Leg", "M", "Mir", "N", "Nyd", "Ol", "Oc", "On", "P", "Pr", "R", "Rh", "S", "Sev", "T", "Tr", "Th", "V", "Y", "Z", "W", "Wic", -}; - -static char *human_syllable2[] = -{ - "a", "ae", "au", "ao", "are", "ale", "ali", "ay", "ardo", "e", "ei", "ea", "eri", "era", "ela", "eli", "enda", "erra", "i", "ia", "ie", "ire", "ira", "ila", "ili", "ira", "igo", "o", "oa", "oi", "oe", "ore", "u", "y", -}; - -static char *human_syllable3[] = -{ - "a", "and", "b", "bwyn", "baen", "bard", "c", "ctred", "cred", "ch", "can", "d", "dan", "don", "der", "dric", "dfrid", "dus", "f", "g", "gord", "gan", "l", "li", "lgrin", "lin", "lith", "lath", "loth", "ld", "ldric", "ldan", "m", "mas", "mos", "mar", "mond", "n", "nydd", "nidd", "nnon", "nwan", "nyth", "nad", "nn", "nnor", "nd", "p", "r", "ron", "rd", "s", "sh", "seth", "sean", "t", "th", "tha", "tlan", "trem", "tram", "v", "vudd", "w", "wan", "win", "wyn", "wyr", "wyr", "wyth", -}; - -static char *orc_syllable1[] = -{ - "B", "Er", "G", "Gr", "H", "P", "Pr", "R", "V", "Vr", "T", "Tr", "M", "Dr", -}; - -static char *orc_syllable2[] = -{ - "a", "i", "o", "oo", "u", "ui", -}; - -static char *orc_syllable3[] = -{ - "dash", "dish", "dush", "gar", "gor", "gdush", "lo", "gdish", "k", "lg", "nak", "rag", "rbag", "rg", "rk", "ng", "nk", "rt", "ol", "urk", "shnak", "mog", "mak", "rak", -}; - -static char *entish_syllable1[] = -{ - "Baum","Wurzel","Rinden","Ast","Blatt", -}; - -static char *entish_syllable2[] = -{ - "-", -}; - -static char *entish_syllable3[] = -{ - "Hüter","Pflanzer","Hirte","Wächter","Wachser","Beschützer", -}; - -static char *cthuloid_syllable1[] = -{ - "Cth","Az","Fth","Ts","Xo","Q'N","R'L","Ghata","L","Zz","Fl","Cl","S","Y", -}; - -static char *cthuloid_syllable2[] = -{ - "nar","loi","ul","lu","noth","thon","ath","'N","rhy","oth","aza","agn","oa","og", -}; - -static char *cthuloid_syllable3[] = -{ - "l","a","u","oa","oggua","oth","ath","aggua","lu","lo","loth","lotha","agn","axl", -}; - -static char * -create_random_name(race_t race) -{ - static char name[64]; - - switch (race) - { - case RC_DWARF: - strcpy(name, dwarf_syllable1[rng_int()%(sizeof(dwarf_syllable1) / sizeof(char*))]); - strcat(name, dwarf_syllable2[rand()%(sizeof(dwarf_syllable2) / sizeof(char*))]); - strcat(name, dwarf_syllable3[rand()%(sizeof(dwarf_syllable3) / sizeof(char*))]); - break; - case RC_ELF: - strcpy(name, elf_syllable1[rand()%(sizeof(elf_syllable1) / sizeof(char*))]); - strcat(name, elf_syllable2[rand()%(sizeof(elf_syllable2) / sizeof(char*))]); - strcat(name, elf_syllable3[rand()%(sizeof(elf_syllable3) / sizeof(char*))]); - break; -/* - case RACE_GNOME: - strcpy(name, gnome_syllable1[rand()%(sizeof(gnome_syllable1) / sizeof(char*))]); - strcat(name, gnome_syllable2[rand()%(sizeof(gnome_syllable2) / sizeof(char*))]); - strcat(name, gnome_syllable3[rand()%(sizeof(gnome_syllable3) / sizeof(char*))]); - break; -*/ - case RC_HALFLING: - strcpy(name, hobbit_syllable1[rand()%(sizeof(hobbit_syllable1) / sizeof(char*))]); - strcat(name, hobbit_syllable2[rand()%(sizeof(hobbit_syllable2) / sizeof(char*))]); - strcat(name, hobbit_syllable3[rand()%(sizeof(hobbit_syllable3) / sizeof(char*))]); - break; - case RC_HUMAN: - case RC_AQUARIAN: - case RC_CAT: - strcpy(name, human_syllable1[rand()%(sizeof(human_syllable1) / sizeof(char*))]); - strcat(name, human_syllable2[rand()%(sizeof(human_syllable2) / sizeof(char*))]); - strcat(name, human_syllable3[rand()%(sizeof(human_syllable3) / sizeof(char*))]); - break; - case RC_ORC: - case RC_TROLL: - case RC_GOBLIN: - strcpy(name, orc_syllable1[rand()%(sizeof(orc_syllable1) / sizeof(char*))]); - strcat(name, orc_syllable2[rand()%(sizeof(orc_syllable2) / sizeof(char*))]); - strcat(name, orc_syllable3[rand()%(sizeof(orc_syllable3) / sizeof(char*))]); - break; -/* - case RC_TREEMAN: - strcpy(name, entish_syllable1[rand()%(sizeof(entish_syllable1) / sizeof(char*))]); - strcat(name, entish_syllable2[rand()%(sizeof(entish_syllable2) / sizeof(char*))]); - strcat(name, entish_syllable3[rand()%(sizeof(entish_syllable3) / sizeof(char*))]); - break; -*/ - case RC_DAEMON: - case RC_INSECT: - strcpy(name, cthuloid_syllable1[rand()%(sizeof(cthuloid_syllable1) / sizeof(char*))]); - strcat(name, cthuloid_syllable2[rand()%(sizeof(cthuloid_syllable2) / sizeof(char*))]); - strcat(name, cthuloid_syllable3[rand()%(sizeof(cthuloid_syllable3) / sizeof(char*))]); - break; - default: - name[0] = 0; - break; - } - - return name; -} - -int -main(void) -{ - race_t race; - - for(race=0; race<11; race++) { - int i; - printf("%d:", (int)race); - for(i=0;i<20;i++) { - printf(" %s", create_random_name(race)); - } - printf("\n"); - } - - return 0; -} - +/* vi: set ts=2: + +-------------------+ Christian Schlittchen + | | Enno Rehling + | Eressea PBEM host | Katja Zedel + | (c) 1998 - 2001 | Henning Peters + | | Ingo Wilken + +-------------------+ Stefan Reich + + This program may not be used, modified or distributed + without prior permission by the authors of Eressea. + + */ + +#include +#include +#include + +static char *dwarf_syllable1[] = +{ + "B", "D", "F", "G", "Gl", "H", "K", "L", "M", "N", "R", "S", "T", "Th", "V", +}; + +static char *dwarf_syllable2[] = +{ + "a", "e", "i", "o", "oi", "u", +}; + +static char *dwarf_syllable3[] = +{ + "bur", "fur", "gan", "gnus", "gnar", "li", "lin", "lir", "mli", "nar", "nus", "rin", "ran", "sin", "sil", "sur", +}; + +static char *elf_syllable1[] = +{ + "Al", "An", "Bal", "Bel", "Cal", "Cel", "El", "Elr", "Elv", "Eow", "Ear", "F", "Fal", "Fel", "Fin", "G", "Gal", "Gel", "Gl", "Is", "Lan", "Leg", "Lom", "N", "Nal", "Nel", "S", "Sal", "Sel", "T", "Tal", "Tel", "Thr", "Tin", +}; + +static char *elf_syllable2[] = +{ + "a", "adrie", "ara", "e", "ebri", "ele", "ere", "i", "io", "ithra", "ilma", "il-Ga", "ili", "o", "orfi", "u", "y", +}; + +static char *elf_syllable3[] = +{ + "l", "las", "lad", "ldor", "ldur", "linde", "lith", "mir", "n", "nd", "ndel", "ndil", "ndir", "nduil", "ng", "mbor", "r", "rith", "ril", "riand", "rion", "s", "thien", "viel", "wen", "wyn", +}; + +static char *gnome_syllable1[] = +{ + "Aar", "An", "Ar", "As", "C", "H", "Han", "Har", "Hel", "Iir", "J", "Jan", "Jar", "K", "L", "M", "Mar", "N", "Nik", "Os", "Ol", "P", "R", "S", "Sam", "San", "T", "Ter", "Tom", "Ul", "V", "W", "Y", +}; + +static char *gnome_syllable2[] = +{ + "a", "aa", "ai", "e", "ei", "i", "o", "uo", "u", "uu", +}; + +static char *gnome_syllable3[] = +{ + "ron", "re", "la", "ki", "kseli", "ksi", "ku", "ja", "ta", "na", "namari", "neli", "nika", "nikki", "nu", "nukka", "ka", "ko", "li", "kki", "rik", "po", "to", "pekka", "rjaana", "rjatta", "rjukka", "la", "lla", "lli", "mo", "nni", +}; + +static char *hobbit_syllable1[] = +{ + "B", "Ber", "Br", "D", "Der", "Dr", "F", "Fr", "G", "H", "L", "Ler", "M", "Mer", "N", "P", "Pr", "Per", "R", "S", "T", "W", +}; + +static char *hobbit_syllable2[] = +{ + "a", "e", "i", "ia", "o", "oi", "u", +}; + +static char *hobbit_syllable3[] = +{ + "bo", "ck", "decan", "degar", "do", "doc", "go", "grin", "lba", "lbo", "lda", "ldo", "lla", "ll", "lo", "m", "mwise", "nac", "noc", "nwise", "p", "ppin", "pper", "tho", "to", +}; + +static char *human_syllable1[] = +{ + "Ab", "Ac", "Ad", "Af", "Agr", "Ast", "As", "Al", "Adw", "Adr", "Ar", "B", "Br", "C", "Cr", "Ch", "Cad", "D", "Dr", "Dw", "Ed", "Eth", "Et", "Er", "El", "Eow", "F", "Fr", "G", "Gr", "Gw", "Gal", "Gl", "H", "Ha", "Ib", "Jer", "K", "Ka", "Ked", "L", "Loth", "Lar", "Leg", "M", "Mir", "N", "Nyd", "Ol", "Oc", "On", "P", "Pr", "R", "Rh", "S", "Sev", "T", "Tr", "Th", "V", "Y", "Z", "W", "Wic", +}; + +static char *human_syllable2[] = +{ + "a", "ae", "au", "ao", "are", "ale", "ali", "ay", "ardo", "e", "ei", "ea", "eri", "era", "ela", "eli", "enda", "erra", "i", "ia", "ie", "ire", "ira", "ila", "ili", "ira", "igo", "o", "oa", "oi", "oe", "ore", "u", "y", +}; + +static char *human_syllable3[] = +{ + "a", "and", "b", "bwyn", "baen", "bard", "c", "ctred", "cred", "ch", "can", "d", "dan", "don", "der", "dric", "dfrid", "dus", "f", "g", "gord", "gan", "l", "li", "lgrin", "lin", "lith", "lath", "loth", "ld", "ldric", "ldan", "m", "mas", "mos", "mar", "mond", "n", "nydd", "nidd", "nnon", "nwan", "nyth", "nad", "nn", "nnor", "nd", "p", "r", "ron", "rd", "s", "sh", "seth", "sean", "t", "th", "tha", "tlan", "trem", "tram", "v", "vudd", "w", "wan", "win", "wyn", "wyr", "wyr", "wyth", +}; + +static char *orc_syllable1[] = +{ + "B", "Er", "G", "Gr", "H", "P", "Pr", "R", "V", "Vr", "T", "Tr", "M", "Dr", +}; + +static char *orc_syllable2[] = +{ + "a", "i", "o", "oo", "u", "ui", +}; + +static char *orc_syllable3[] = +{ + "dash", "dish", "dush", "gar", "gor", "gdush", "lo", "gdish", "k", "lg", "nak", "rag", "rbag", "rg", "rk", "ng", "nk", "rt", "ol", "urk", "shnak", "mog", "mak", "rak", +}; + +static char *entish_syllable1[] = +{ + "Baum","Wurzel","Rinden","Ast","Blatt", +}; + +static char *entish_syllable2[] = +{ + "-", +}; + +static char *entish_syllable3[] = +{ + "Hüter","Pflanzer","Hirte","Wächter","Wachser","Beschützer", +}; + +static char *cthuloid_syllable1[] = +{ + "Cth","Az","Fth","Ts","Xo","Q'N","R'L","Ghata","L","Zz","Fl","Cl","S","Y", +}; + +static char *cthuloid_syllable2[] = +{ + "nar","loi","ul","lu","noth","thon","ath","'N","rhy","oth","aza","agn","oa","og", +}; + +static char *cthuloid_syllable3[] = +{ + "l","a","u","oa","oggua","oth","ath","aggua","lu","lo","loth","lotha","agn","axl", +}; + +static char * +create_random_name(race_t race) +{ + static char name[64]; + + switch (race) + { + case RC_DWARF: + strcpy(name, dwarf_syllable1[rng_int()%(sizeof(dwarf_syllable1) / sizeof(char*))]); + strcat(name, dwarf_syllable2[rand()%(sizeof(dwarf_syllable2) / sizeof(char*))]); + strcat(name, dwarf_syllable3[rand()%(sizeof(dwarf_syllable3) / sizeof(char*))]); + break; + case RC_ELF: + strcpy(name, elf_syllable1[rand()%(sizeof(elf_syllable1) / sizeof(char*))]); + strcat(name, elf_syllable2[rand()%(sizeof(elf_syllable2) / sizeof(char*))]); + strcat(name, elf_syllable3[rand()%(sizeof(elf_syllable3) / sizeof(char*))]); + break; +/* + case RACE_GNOME: + strcpy(name, gnome_syllable1[rand()%(sizeof(gnome_syllable1) / sizeof(char*))]); + strcat(name, gnome_syllable2[rand()%(sizeof(gnome_syllable2) / sizeof(char*))]); + strcat(name, gnome_syllable3[rand()%(sizeof(gnome_syllable3) / sizeof(char*))]); + break; +*/ + case RC_HALFLING: + strcpy(name, hobbit_syllable1[rand()%(sizeof(hobbit_syllable1) / sizeof(char*))]); + strcat(name, hobbit_syllable2[rand()%(sizeof(hobbit_syllable2) / sizeof(char*))]); + strcat(name, hobbit_syllable3[rand()%(sizeof(hobbit_syllable3) / sizeof(char*))]); + break; + case RC_HUMAN: + case RC_AQUARIAN: + case RC_CAT: + strcpy(name, human_syllable1[rand()%(sizeof(human_syllable1) / sizeof(char*))]); + strcat(name, human_syllable2[rand()%(sizeof(human_syllable2) / sizeof(char*))]); + strcat(name, human_syllable3[rand()%(sizeof(human_syllable3) / sizeof(char*))]); + break; + case RC_ORC: + case RC_TROLL: + case RC_GOBLIN: + strcpy(name, orc_syllable1[rand()%(sizeof(orc_syllable1) / sizeof(char*))]); + strcat(name, orc_syllable2[rand()%(sizeof(orc_syllable2) / sizeof(char*))]); + strcat(name, orc_syllable3[rand()%(sizeof(orc_syllable3) / sizeof(char*))]); + break; +/* + case RC_TREEMAN: + strcpy(name, entish_syllable1[rand()%(sizeof(entish_syllable1) / sizeof(char*))]); + strcat(name, entish_syllable2[rand()%(sizeof(entish_syllable2) / sizeof(char*))]); + strcat(name, entish_syllable3[rand()%(sizeof(entish_syllable3) / sizeof(char*))]); + break; +*/ + case RC_DAEMON: + case RC_INSECT: + strcpy(name, cthuloid_syllable1[rand()%(sizeof(cthuloid_syllable1) / sizeof(char*))]); + strcat(name, cthuloid_syllable2[rand()%(sizeof(cthuloid_syllable2) / sizeof(char*))]); + strcat(name, cthuloid_syllable3[rand()%(sizeof(cthuloid_syllable3) / sizeof(char*))]); + break; + default: + name[0] = 0; + break; + } + + return name; +} + +int +main(void) +{ + race_t race; + + for(race=0; race<11; race++) { + int i; + printf("%d:", (int)race); + for(i=0;i<20;i++) { + printf(" %s", create_random_name(race)); + } + printf("\n"); + } + + return 0; +} + From 240aae8c587236ba848e6e701b984d9800f4e70c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 8 Aug 2010 12:04:08 +0200 Subject: [PATCH 004/400] bugfix, test crash --- src/gamecode/laws_test.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gamecode/laws_test.c b/src/gamecode/laws_test.c index 2bc958813..0bf75911f 100644 --- a/src/gamecode/laws_test.c +++ b/src/gamecode/laws_test.c @@ -6,10 +6,12 @@ static void test_new_building_can_be_renamed(CuTest * tc) { region * r; building * b; - building_type * btype = bt_find("castle"); + building_type * btype; test_cleanup(); test_create_world(); + + btype = bt_find("castle"); r = findregion(-1, 0); b = new_building(btype, r, default_locale); From beec74e0c6e71c39fb1e30f0d228ef4372918c73 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 8 Aug 2010 23:39:21 -0700 Subject: [PATCH 005/400] Clearing every mage's spell-list before each turn is counter-productive. It destroys tests, and it doesn't let us have special spells added per-unit. --- src/bindings/bind_unit.c | 4 +++- src/gamecode/laws.c | 8 -------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 9de137d90..7084571d8 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -522,7 +522,9 @@ unit_addspell(unit * u, const char * name) slist=slist->next; } if (!spadd) log_error(("spell %s could not be found\n", name)); - else add_spell(starget, spadd); + else { + add_spell(starget, spadd); + } } static int diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index c5cb1173e..dc638e047 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -3596,14 +3596,6 @@ update_spells(void) if (FactionSpells() && maxlevel>f->max_spelllevel) { update_spellbook(f, maxlevel); - for (i=0;i!=n;++i) { - sc_mage *mage = get_mage(mages[i]); - while (mage->spells) { - spell_list * slist = mage->spells; - mage->spells = slist->next; - free(slist); - } - } } for (i=0;i!=n;++i) { updatespelllist(mages[i]); From 3d5f7a92b80b78ce498522d74a0ee4e513dee453 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 10 Aug 2010 23:33:38 -0700 Subject: [PATCH 006/400] http://bugs.eressea.de/view.php?id=1788 renaming buildings should finally work again. --- src/gamecode/laws.c | 13 +++++-------- src/gamecode/laws_test.c | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index dc638e047..4c755a544 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -1627,20 +1627,17 @@ rename_building(unit * u, order * ord, building * b, const char * name) { } if (foreign) { - unit *uo; - if (renamed_building(b)) { cmistake(u, ord, 246, MSG_EVENT); return -1; } - uo = building_owner(b); - if (uo) { - if (cansee(uo->faction, u->region, u, 0)) { - ADDMSG(&uo->faction->msgs, msg_message("renamed_building_seen", + if (owner) { + if (cansee(owner->faction, u->region, u, 0)) { + ADDMSG(&owner->faction->msgs, msg_message("renamed_building_seen", "building renamer region", b, u, u->region)); } else { - ADDMSG(&uo->faction->msgs, msg_message("renamed_building_notseen", + ADDMSG(&owner->faction->msgs, msg_message("renamed_building_notseen", "building region", b, u->region)); } } @@ -1651,7 +1648,7 @@ rename_building(unit * u, order * ord, building * b, const char * name) { } } - return rename_cmd(u, ord, &b->name, getstrtoken()); + return rename_cmd(u, ord, &b->name, name); } static int diff --git a/src/gamecode/laws_test.c b/src/gamecode/laws_test.c index 0bf75911f..281245153 100644 --- a/src/gamecode/laws_test.c +++ b/src/gamecode/laws_test.c @@ -18,6 +18,29 @@ static void test_new_building_can_be_renamed(CuTest * tc) { CuAssertTrue(tc, !renamed_building(b)); } +static void test_rename_building(CuTest * tc) { + region * r; + building * b; + unit * u; + faction * f; + building_type * btype; + + test_cleanup(); + test_create_world(); + + btype = bt_find("castle"); + + r = findregion(-1, 0); + b = new_building(btype, r, default_locale); + f = test_create_faction(rc_find("human")); + u = test_create_unit(f, r); + u->building = b; + fset(u, UFL_OWNER); + + rename_building(u, NULL, b, "Villa Nagel"); + CuAssertStrEquals(tc, "Villa Nagel", b->name); +} + static void test_fishing_feeds_2_people(CuTest * tc) { region * r; faction * f; @@ -141,6 +164,7 @@ CuSuite* get_laws_suite(void) { CuSuite* suite = CuSuiteNew(); SUITE_ADD_TEST(suite, &test_new_building_can_be_renamed); + SUITE_ADD_TEST(suite, &test_rename_building); SUITE_ADD_TEST(suite, &test_fishing_feeds_2_people); SUITE_ADD_TEST(suite, &test_fishing_does_not_give_goblins_money); SUITE_ADD_TEST(suite, &test_fishing_gets_reset); From 8554cbf48b2816130b3480a947dab986ca0bc49c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 14 Aug 2010 16:49:13 -0700 Subject: [PATCH 007/400] VC 2008 project files for building on my netbook --- src/gamecode.vcproj | 3 ++- src/kernel.vcproj | 3 ++- src/lua-bindings.vcproj | 7 ++++--- src/util.vcproj | 23 ++++++++++++++++++++--- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/gamecode.vcproj b/src/gamecode.vcproj index 6cdabb3e8..a1f0dfc6e 100644 --- a/src/gamecode.vcproj +++ b/src/gamecode.vcproj @@ -1,11 +1,12 @@ + + + + + + Date: Sat, 14 Aug 2010 19:41:18 -0700 Subject: [PATCH 008/400] VS 2008 fixes fixed to build Release --- src/bindings/bind_building.c | 3 +++ src/gamecode.vcproj | 11 ++++------- src/kernel.vcproj | 23 ++++++++++++++++++----- src/kernel/item.c | 1 + src/lua-bindings.vcproj | 7 ++----- src/modules/wormhole.c | 1 + src/util.vcproj | 7 ++----- 7 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/bindings/bind_building.c b/src/bindings/bind_building.c index e5c9efde3..a177b1975 100644 --- a/src/bindings/bind_building.c +++ b/src/bindings/bind_building.c @@ -14,10 +14,13 @@ without prior permission by the authors of Eressea. #include "bind_building.h" #include "bind_unit.h" +#include #include #include #include +#include + #include #include diff --git a/src/gamecode.vcproj b/src/gamecode.vcproj index a1f0dfc6e..d852037e7 100644 --- a/src/gamecode.vcproj +++ b/src/gamecode.vcproj @@ -42,16 +42,14 @@ Name="VCCLCompilerTool" AdditionalOptions="/MP" Optimization="0" - AdditionalIncludeDirectories=".;../../external" - PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_DEPRECATE" - MinimalRebuild="true" + AdditionalIncludeDirectories=".;..\..\external;..\..\external\libxml2\include;..\..\external\pdcurses;..\..\external\lua\src" + PreprocessorDefinitions="LIBXML_STATIC;WIN32;_CRT_SECURE_NO_DEPRECATE" BasicRuntimeChecks="3" RuntimeLibrary="3" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" WarningLevel="4" WarnAsError="true" - Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> + + + + + + diff --git a/src/kernel/item.c b/src/kernel/item.c index 02e110f93..d68808d8f 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -44,6 +44,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include diff --git a/src/lua-bindings.vcproj b/src/lua-bindings.vcproj index c53e667dd..a43b73683 100644 --- a/src/lua-bindings.vcproj +++ b/src/lua-bindings.vcproj @@ -42,16 +42,14 @@ Name="VCCLCompilerTool" AdditionalOptions="/MP" Optimization="0" - AdditionalIncludeDirectories=".;..\..\external;..\..\external\lua\src;..\..\external\tolua\include;..\..\external\libxml2\include" + AdditionalIncludeDirectories=".;..\..\external;..\..\external\lua\src;..\..\external\tolua\include;..\..\external\libxml2\include;..\..\external\pdcurses" PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_DEPRECATE" - MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" WarningLevel="4" WarnAsError="true" - Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> #include #include +#include #include /* libc includes */ diff --git a/src/util.vcproj b/src/util.vcproj index 5b112e0a6..6a4e95ef9 100644 --- a/src/util.vcproj +++ b/src/util.vcproj @@ -42,16 +42,14 @@ Name="VCCLCompilerTool" AdditionalOptions="/MP" Optimization="0" - AdditionalIncludeDirectories=".;..\..\external;..\..\external\pdcurses" + AdditionalIncludeDirectories=".;..\..\external;..\..\external\pdcurses;..\..\external\libxml2\include;..\..\external\lua\src" PreprocessorDefinitions="WIN32;_CRT_SECURE_NO_DEPRECATE" - MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" EnableFunctionLevelLinking="true" UsePrecompiledHeader="0" WarningLevel="4" WarnAsError="true" - Detect64BitPortabilityProblems="true" DebugInformationFormat="4" /> Date: Mon, 16 Aug 2010 23:08:42 -0700 Subject: [PATCH 009/400] log an error instead of asserting on spell components --- src/kernel/xmlreader.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 829f3736d..3ee54780d 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1414,7 +1414,8 @@ parse_spells(xmlDocPtr doc) xmlNodePtr node = nodes->nodeTab[i]; xmlChar * propValue; int k; - spell * sp = calloc(1, sizeof(spell)); + spell_component * component; + spell * sp = (spell *)calloc(1, sizeof(spell)); static int modes[] = { 0, PRECOMBATSPELL, COMBATSPELL, POSTCOMBATSPELL }; /* spellname */ @@ -1496,27 +1497,34 @@ parse_spells(xmlDocPtr doc) xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "resource", xpath); if (result->nodesetval->nodeNr) { - sp->components = malloc(sizeof(spell_component)*(result->nodesetval->nodeNr+1)); + sp->components = (spell_component *)malloc(sizeof(spell_component)*(result->nodesetval->nodeNr+1)); sp->components[result->nodesetval->nodeNr].type = 0; } - for (k=0;k!=result->nodesetval->nodeNr;++k) { + for (component=sp->components,k=0;k!=result->nodesetval->nodeNr;++k) { + const resource_type * rtype; xmlNodePtr node = result->nodesetval->nodeTab[k]; propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue); - sp->components[k].type = rt_find((const char *)propValue); - assert(sp->components[k].type); + rtype = rt_find((const char *)propValue); + if (!rtype) { + log_error(("spell %s uses unknown component %s.\n", sp->sname, (const char*)propValue)); + xmlFree(propValue); + continue; + } + component->type = rtype; xmlFree(propValue); - sp->components[k].amount = xml_ivalue(node, "amount", 1); - sp->components[k].cost = SPC_FIX; + component->amount = xml_ivalue(node, "amount", 1); + component->cost = SPC_FIX; propValue = xmlGetProp(node, BAD_CAST "cost"); if (propValue!=NULL) { if (strcmp((const char *)propValue, "linear")==0) { - sp->components[k].cost = SPC_LINEAR; + component->cost = SPC_LINEAR; } else if (strcmp((const char *)propValue, "level")==0) { - sp->components[k].cost = SPC_LEVEL; + component->cost = SPC_LEVEL; } xmlFree(propValue); } + component++; } xmlXPathFreeObject(result); register_spell(sp); From 592d0c377b5cef90eba6e586391e5c4541b691e2 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 16 Aug 2010 23:55:53 -0700 Subject: [PATCH 010/400] Add a test that verifies learning magic costs money. --- scripts/tests/common.lua | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 9e0ff43db..e54736e74 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -641,3 +641,15 @@ function test_hero_normal_transfer() assert_true(is_flag_set(u1.flags, 128), "unit is not a hero?") assert_false(is_flag_set(u2.flags, 128), "unit turned into a hero") end + +function test_expensive_skills_cost_money() + local r = region.create(0,0, "mountain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u:add_item("money", 10000) + u:clear_orders() + u:add_order("LERNEN MAGIE Gwyrrd") + process_orders() + assert_equal(9890, u:get_item("money")) + assert_equal(1, u:get_skill("magic")) +end From 366035510c0912ea2911accabab97b122667ed51 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 17 Aug 2010 22:32:36 -0700 Subject: [PATCH 011/400] fixing building renaming http://bugs.eressea.de/view.php?id=1798 foreign/owned was swapped --- src/gamecode/laws.c | 2 +- src/gamecode/laws_test.c | 27 +++++++++++++++++++++++++++ src/tests.c | 1 + 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 4c755a544..515da34d3 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -1614,7 +1614,7 @@ rename_cmd(unit * u, order * ord, char **s, const char * s2) static int rename_building(unit * u, order * ord, building * b, const char * name) { unit * owner = b?building_owner(b):0; - boolean foreign = owner && owner->faction==u->faction; + boolean foreign = !(owner && owner->faction==u->faction); if (!b) { cmistake(u, ord, u->building?6:145, MSG_EVENT); diff --git a/src/gamecode/laws_test.c b/src/gamecode/laws_test.c index 281245153..c45719ec5 100644 --- a/src/gamecode/laws_test.c +++ b/src/gamecode/laws_test.c @@ -41,6 +41,32 @@ static void test_rename_building(CuTest * tc) { CuAssertStrEquals(tc, "Villa Nagel", b->name); } +static void test_rename_building_twice(CuTest * tc) { + region * r; + building * b; + unit * u; + faction * f; + building_type * btype; + + test_cleanup(); + test_create_world(); + + btype = bt_find("castle"); + + r = findregion(-1, 0); + b = new_building(btype, r, default_locale); + f = test_create_faction(rc_find("human")); + u = test_create_unit(f, r); + u->building = b; + fset(u, UFL_OWNER); + + rename_building(u, NULL, b, "Villa Nagel"); + CuAssertStrEquals(tc, "Villa Nagel", b->name); + + rename_building(u, NULL, b, "Villa Kunterbunt"); + CuAssertStrEquals(tc, "Villa Kunterbunt", b->name); +} + static void test_fishing_feeds_2_people(CuTest * tc) { region * r; faction * f; @@ -165,6 +191,7 @@ CuSuite* get_laws_suite(void) CuSuite* suite = CuSuiteNew(); SUITE_ADD_TEST(suite, &test_new_building_can_be_renamed); SUITE_ADD_TEST(suite, &test_rename_building); + SUITE_ADD_TEST(suite, &test_rename_building_twice); SUITE_ADD_TEST(suite, &test_fishing_feeds_2_people); SUITE_ADD_TEST(suite, &test_fishing_does_not_give_goblins_money); SUITE_ADD_TEST(suite, &test_fishing_gets_reset); diff --git a/src/tests.c b/src/tests.c index 27f28b791..e47442a22 100644 --- a/src/tests.c +++ b/src/tests.c @@ -116,6 +116,7 @@ void test_create_world(void) rc_human->maintenance = 10; btype = calloc(sizeof(building_type), 1); + btype->flags = BTF_NAMECHANGE; btype->_name = strdup("castle"); bt_register(btype); From e3c2ac1ec687c658776f69b5079a732f46631ad1 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 17 Aug 2010 23:24:51 -0700 Subject: [PATCH 012/400] http://bugs.eressea.de/view.php?id=1796 great bows should be allowed for all, not just elves --- src/kernel/battle.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kernel/battle.c b/src/kernel/battle.c index a4eadfcda..74b60bc4f 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -3336,7 +3336,7 @@ make_fighter(battle * b, unit * u, side * s1, boolean attack) } } - /* Für alle Waffengattungne wird bestimmt, wie viele der Personen mit + /* Für alle Waffengattungen wird bestimmt, wie viele der Personen mit * ihr kämpfen könnten, und was ihr Wert darin ist. */ if (u->race->battle_flags & BF_EQUIPMENT) { int oi=0, di=0; @@ -3353,7 +3353,7 @@ make_fighter(battle * b, unit * u, side * s1, boolean attack) } assert(w!=WMAX); } - fig->weapons = calloc(sizeof(weapon), w+1); + fig->weapons = (weapon *)calloc(sizeof(weapon), w+1); memcpy(fig->weapons, weapons, w*sizeof(weapon)); for (i=0; i!=w; ++i) { From 1f489bafeea59df6a2067f25b0a226182e390760 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 28 Aug 2010 13:41:02 -0700 Subject: [PATCH 013/400] broken test of magic skill cost (magician must not be human in e3) --- scripts/tests/common.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index e54736e74..76bc5a763 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -644,7 +644,7 @@ end function test_expensive_skills_cost_money() local r = region.create(0,0, "mountain") - local f = faction.create("noreply@eressea.de", "human", "de") + local f = faction.create("noreply@eressea.de", "elf", "de") local u = unit.create(f, r, 1) u:add_item("money", 10000) u:clear_orders() From e53c1dc07bd1620ce92281c8051047a5ca3b78f5 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 28 Aug 2010 17:52:33 -0700 Subject: [PATCH 014/400] bind settings and unit-reporting --- src/bindings/bindings.c | 43 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index fa1947c54..09f863ccd 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -985,6 +985,34 @@ tolua_eventbus_fire(lua_State * L) return 0; } +static int +tolua_report_unit(lua_State* L) +{ + char buffer[512]; + unit * u = (unit *)tolua_tousertype(L, 1, 0); + faction * f = (faction *)tolua_tousertype(L, 2, 0); + bufunit(f, u, 0, see_unit, buffer, sizeof(buffer)); + tolua_pushstring(L, buffer); + return 1; +} + +static int +tolua_settings_get(lua_State* L) +{ + const char * name = tolua_tostring(L, 1, 0); + tolua_pushstring(L, get_param(global.parameters, name)); + return 1; +} + +static int +tolua_settings_set(lua_State* L) +{ + const char * name = tolua_tostring(L, 1, 0); + const char * value = tolua_tostring(L, 2, 0); + set_param(&global.parameters, name, value); + return 0; +} + static void parse_inifile(lua_State* L, dictionary * d, const char * section) { @@ -1065,6 +1093,21 @@ tolua_eressea_open(lua_State* L) } tolua_endmodule(L); + tolua_module(L, TOLUA_CAST "settings", 1); + tolua_beginmodule(L, TOLUA_CAST "settings"); + { + tolua_function(L, TOLUA_CAST "set", &tolua_settings_set); + tolua_function(L, TOLUA_CAST "get", &tolua_settings_get); + } + tolua_endmodule(L); + + tolua_module(L, TOLUA_CAST "report", 1); + tolua_beginmodule(L, TOLUA_CAST "report"); + { + tolua_function(L, TOLUA_CAST "report_unit", &tolua_report_unit); + } + tolua_endmodule(L); + tolua_module(L, TOLUA_CAST "config", 1); tolua_beginmodule(L, TOLUA_CAST "config"); { From bf5bccc133f711c06a218c7ae2ae56f589b5f91e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 28 Aug 2010 23:05:45 -0700 Subject: [PATCH 015/400] add an option to disable anonymous armies in combat --- src/kernel/battle.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/kernel/battle.c b/src/kernel/battle.c index 74b60bc4f..e3e84441e 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -3218,10 +3218,16 @@ make_fighter(battle * b, unit * u, side * s1, boolean attack) const attrib *a = a_find(u->attribs, &at_otherfaction); const faction *stealthfaction = a?get_otherfaction(a):NULL; unsigned int flags = 0; + static int rule_anon_battle = -1; assert(u->number); - if (fval(u, UFL_ANON_FACTION)!=0) flags |= SIDE_STEALTH; + if (rule_anon_battle<0) { + rule_anon_battle = get_param_int(global.parameters, "rules.stealth.anon_battle", 1); + } + if (rule_anon_battle) { + if (fval(u, UFL_ANON_FACTION)!=0) flags |= SIDE_STEALTH; + } if (!(AllianceAuto() & HELP_FIGHT) && fval(u, UFL_GROUP)) { const attrib * agroup = a_find(u->attribs, &at_group); if (agroup!=NULL) g = (const group*)agroup->data.v; From db8f2f7d0cdcad0235db16e524b3adabcaccb11d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 2 Sep 2010 23:25:25 -0700 Subject: [PATCH 016/400] do not damage ships with no owner while still in production --- src/gamecode/laws.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 515da34d3..232637508 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -2659,12 +2659,15 @@ sinkships(region * r) while (*shp) { ship * sh = *shp; - if (fval(r->terrain, SEA_REGION) && (!enoughsailors(sh, r) || get_captain(sh)==NULL)) { - /* Schiff nicht seetüchtig */ - damage_ship(sh, 0.30); - } - if (shipowner(sh)==NULL) { - damage_ship(sh, 0.05); + + if (!sh->type->construction || sh->size>=sh->type->construction->maxsize) { + if (fval(r->terrain, SEA_REGION) && (!enoughsailors(sh, r) || get_captain(sh)==NULL)) { + /* Schiff nicht seetüchtig */ + damage_ship(sh, 0.30); + } + if (shipowner(sh)==NULL) { + damage_ship(sh, 0.05); + } } if (sh->damage >= sh->size * DAMAGE_SCALE) { remove_ship(shp, sh); From f934772a66d1165481a557e8bdbdc8198ccc2c4b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 2 Sep 2010 23:29:33 -0700 Subject: [PATCH 017/400] cleaning up a little, no change to logic --- src/gamecode/spy.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/gamecode/spy.c b/src/gamecode/spy.c index fe665bda8..f42caecc5 100644 --- a/src/gamecode/spy.c +++ b/src/gamecode/spy.c @@ -37,6 +37,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* attributes includes */ #include +#include /* util includes */ #include @@ -52,8 +53,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -#include - /* in spy steht der Unterschied zwischen Wahrnehmung des Opfers und * Spionage des Spions */ void @@ -202,7 +201,7 @@ int setstealth_cmd(unit * u, struct order * ord) { const char *s; - int level; + int level, rule; const race * trace; init_tokens(ord); @@ -257,7 +256,8 @@ setstealth_cmd(unit * u, struct order * ord) switch(findparam(s, u->faction->locale)) { case P_FACTION: /* TARNE PARTEI [NICHT|NUMMER abcd] */ - if (!rule_stealth_faction()) break; + rule = rule_stealth_faction(); + if (!rule) break; s = getstrtoken(); if(!s || *s == 0) { fset(u, UFL_ANON_FACTION); @@ -283,10 +283,8 @@ setstealth_cmd(unit * u, struct order * ord) } break; case P_ANY: - /* TARNE ALLES (was nicht so alles geht?) */ - u_seteffstealth(u, -1); - break; case P_NOT: + /* TARNE ALLES (was nicht so alles geht?) */ u_seteffstealth(u, -1); break; default: @@ -479,4 +477,3 @@ sabotage_cmd(unit * u, struct order * ord) return 0; } - From 482a39db6d56fa703991fa3dcba040c614bb2061 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 11 Sep 2010 19:30:00 -0700 Subject: [PATCH 018/400] prevent buildings in regions that should not have any (simple hack) --- res/messages.xml | 6 +++--- src/kernel/build.c | 5 +++++ src/kernel/terrain.h | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/res/messages.xml b/res/messages.xml index 533ec1418..443f98785 100644 --- a/res/messages.xml +++ b/res/messages.xml @@ -4759,8 +4759,8 @@ - "$unit($unit) in $region($region): '$order($command)' - So etwas kann man nicht bauen." - "$unit($unit) in $region($region): '$order($command)' - You cannot build such a thing." + "$unit($unit) in $region($region): '$order($command)' - So etwas kann man hier nicht bauen." + "$unit($unit) in $region($region): '$order($command)' - You cannot build this here." @@ -4769,7 +4769,7 @@ "$unit($unit) in $region($region): '$order($command)' - Im astralen Nebel konnte niemand entdeckt werden." - "$unit($unit) in $region($region): '$order($command)' - Noone could be seen in th astral fog." + "$unit($unit) in $region($region): '$order($command)' - Noone could be seen in the astral fog." diff --git a/src/kernel/build.c b/src/kernel/build.c index 50ab584c4..cd70206ff 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -873,6 +873,11 @@ build_building(unit * u, const building_type * btype, int want, order * ord) cmistake(u, ord, 221, MSG_PRODUCE); return; } + if (r->terrain->max_road<=0) { + /* special terrain, cannot build */ + cmistake(u, ord, 221, MSG_PRODUCE); + return; + } if (btype->flags & BTF_ONEPERTURN) { if(b && fval(b, BLD_EXPANDED)) { cmistake(u, ord, 318, MSG_PRODUCE); diff --git a/src/kernel/terrain.h b/src/kernel/terrain.h index 644a0e329..b8be715f4 100644 --- a/src/kernel/terrain.h +++ b/src/kernel/terrain.h @@ -23,7 +23,7 @@ extern "C" { #endif /* diverse Flags */ -/* Strassen können gebaut werden, wenn max_road > 0 */ +/* Strassen und Gebäude können gebaut werden, wenn max_road > 0 */ #define LAND_REGION (1<<0) /* Standard-Land-struct region */ #define SEA_REGION (1<<1) /* hier braucht man ein Boot */ #define FOREST_REGION (1<<2) /* Elfen- und Kampfvorteil durch Bäume */ From 45f451f17dc2336da60c3e764f6313144250a497 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 11 Sep 2010 19:37:11 -0700 Subject: [PATCH 019/400] there are regions with no name, maybe? --- src/kernel/region.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/region.c b/src/kernel/region.c index 7935691f5..3eb0354c9 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -915,7 +915,7 @@ r_demand(const region * r, const luxury_type * ltype) const char * rname(const region * r, const struct locale * lang) { - if (r->land) { + if (r->land && r->land->name) { return r->land->name; } return LOC(lang, terrain_name(r)); From 163f6f13cff8424d71254050c4bf2dc224f8b6e5 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 11 Sep 2010 20:11:15 -0700 Subject: [PATCH 020/400] add support for a new terrain type --- src/gmtool.c | 10 ++++++++-- src/util/listbox.c | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/gmtool.c b/src/gmtool.c index 5d1ce1227..c20de22bf 100644 --- a/src/gmtool.c +++ b/src/gmtool.c @@ -223,13 +223,19 @@ mr_tile(const map_region * mr, int highlight) } else if (r->terrain->_name[1]=='i') { /* firewall */ return '%' | COLOR_PAIR(hl + COLOR_RED) | A_BOLD; } + break; case 'h' : return 'H' | COLOR_PAIR(hl + COLOR_YELLOW) | A_NORMAL; case 'm' : return '^' | COLOR_PAIR(hl + COLOR_WHITE) | A_NORMAL; case 'p' : - if (r_isforest(r)) return '#' | COLOR_PAIR(hl + COLOR_GREEN) | A_NORMAL; - return '+' | COLOR_PAIR(hl + COLOR_GREEN) | A_BOLD; + if (r->terrain->_name[1]=='l') { /* plain */ + if (r_isforest(r)) return '#' | COLOR_PAIR(hl + COLOR_GREEN) | A_NORMAL; + return '+' | COLOR_PAIR(hl + COLOR_GREEN) | A_BOLD; + } else if (r->terrain->_name[1]=='l') { /* packice */ + return ':' | COLOR_PAIR(hl + COLOR_WHITE) | A_BOLD; + } + break; case 'g' : return '*' | COLOR_PAIR(hl + COLOR_WHITE) | A_BOLD; case 's' : diff --git a/src/util/listbox.c b/src/util/listbox.c index 508d5bd3c..b04840a3c 100644 --- a/src/util/listbox.c +++ b/src/util/listbox.c @@ -13,6 +13,7 @@ #include #include "listbox.h" +#include "gmtool_structs.h" #include #include @@ -94,7 +95,7 @@ do_selection(list_selection * sel, const char * title, void (*perform)(list_sele waddnstr(wn, s->str, -1); wclrtoeol(wn); } - wborder(wn, 0, 0, 0, 0, 0, 0, 0, 0); + wxborder(wn); mvwprintw(wn, 0, 2, "[ %s ]", title); update = false; } From fd05fe95e7a6ae2234b8135bf880b9799ffe67f7 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 12 Sep 2010 05:20:32 +0200 Subject: [PATCH 021/400] woops. wrong character --- src/gmtool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gmtool.c b/src/gmtool.c index c20de22bf..537766e4b 100644 --- a/src/gmtool.c +++ b/src/gmtool.c @@ -232,7 +232,7 @@ mr_tile(const map_region * mr, int highlight) if (r->terrain->_name[1]=='l') { /* plain */ if (r_isforest(r)) return '#' | COLOR_PAIR(hl + COLOR_GREEN) | A_NORMAL; return '+' | COLOR_PAIR(hl + COLOR_GREEN) | A_BOLD; - } else if (r->terrain->_name[1]=='l') { /* packice */ + } else if (r->terrain->_name[1]=='a') { /* packice */ return ':' | COLOR_PAIR(hl + COLOR_WHITE) | A_BOLD; } break; From fbb3234beeb5a2c04f0b47e939cb451cd6b987bf Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 23 Sep 2010 23:32:15 -0700 Subject: [PATCH 022/400] stealth for totally anonymous armies should work in E3 --- src/kernel/battle.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/kernel/battle.c b/src/kernel/battle.c index e3e84441e..bae395979 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -3225,18 +3225,16 @@ make_fighter(battle * b, unit * u, side * s1, boolean attack) if (rule_anon_battle<0) { rule_anon_battle = get_param_int(global.parameters, "rules.stealth.anon_battle", 1); } - if (rule_anon_battle) { - if (fval(u, UFL_ANON_FACTION)!=0) flags |= SIDE_STEALTH; - } + if (fval(u, UFL_ANON_FACTION)!=0) flags |= SIDE_STEALTH; if (!(AllianceAuto() & HELP_FIGHT) && fval(u, UFL_GROUP)) { const attrib * agroup = a_find(u->attribs, &at_group); if (agroup!=NULL) g = (const group*)agroup->data.v; } /* Illusionen und Zauber kaempfen nicht */ - if (fval(u->race, RCF_ILLUSIONARY) || idle(u->faction) || u->number==0) + if (fval(u->race, RCF_ILLUSIONARY) || idle(u->faction) || u->number==0) { return NULL; - + } if (s1==NULL) { for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { if (s2->faction == u->faction && s2->group==g) { @@ -3247,7 +3245,10 @@ make_fighter(battle * b, unit * u, side * s1, boolean attack) int s1flags = flags; int s2flags = s2->flags; #endif - if (s1flags==s2flags && s2->stealthfaction==stealthfaction) { + if (rule_anon_battle && s2->stealthfaction!=stealthfaction) { + continue; + } + if (s1flags==s2flags) { s1 = s2; break; } @@ -3257,6 +3258,8 @@ make_fighter(battle * b, unit * u, side * s1, boolean attack) /* aliances are moved out of make_fighter and will be handled later */ if (!s1) { s1 = make_side(b, u->faction, g, flags, stealthfaction); + } else if (!stealthfaction) { + s1->stealthfaction = NULL; } /* Zu diesem Zeitpunkt ist attacked noch 0, da die Einheit für noch * keinen Kampf ausgewählt wurde (sonst würde ein fighter existieren) */ From 0d653ec2bf6a2ac2eb3e619736bd8b15c2faae54 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 26 Sep 2010 01:06:46 +0200 Subject: [PATCH 023/400] sometimes monsters have heroes, too --- src/kernel/battle.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/kernel/battle.c b/src/kernel/battle.c index bae395979..db0284ec6 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -2089,7 +2089,9 @@ make_heroes(battle * b) unit * u = fig->unit; if (fval(u, UFL_HERO)) { int i; - assert(playerrace(u->race)); + if (!playerrace(u->race)) { + log_error(("Hero %s is a %s.\n", unitname(u), u->race->_name[0])); + } for (i=0;i!=u->number;++i) { fig->person[i].speed += (hero_speed-1); } From bfbe9b373b9d58c07cb91d578b6f6639416b0363 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 2 Oct 2010 15:37:48 -0700 Subject: [PATCH 024/400] increase skill-limitations by config --- src/kernel/config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kernel/config.c b/src/kernel/config.c index 814bc45d5..2591ce7ec 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -543,7 +543,7 @@ static attrib_type at_npcfaction = { int max_magicians(const faction * f) { - int m = MAXMAGICIANS; + int m = get_param_int(global.parameters, "rules.maxskills.magic", MAXMAGICIANS); attrib * a; if ((a = a_find(f->attribs, &at_maxmagicians)) != NULL) { @@ -574,7 +574,7 @@ skill_limit(faction * f, skill_t sk) m = max_magicians(f); break; case SK_ALCHEMY: - m = MAXALCHEMISTS; + m = get_param_int(global.parameters, "rules.maxskills.alchemy", MAXALCHEMISTS); break; } return m; From 6ce601828b53df34c51103f7d43907f7f5817aff Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 5 Oct 2010 22:10:44 -0700 Subject: [PATCH 025/400] this is probably correct with respect to http://bugs.eressea.de/view.php?id=1808 --- src/gamecode/study.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gamecode/study.c b/src/gamecode/study.c index 32911c286..36fda0217 100644 --- a/src/gamecode/study.c +++ b/src/gamecode/study.c @@ -197,7 +197,7 @@ teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, return 0; } - n = 30; + n = 30 * student->number; a = a_find(student->attribs, &at_learning); if (a!=NULL) { teach = (teaching_info*)a->data.v; From f1f46782f774ffb3dcb3b21ec85ad382069ae720 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 8 Oct 2010 23:39:16 -0700 Subject: [PATCH 026/400] * fix some rules to not use static variables across multiple runs * add tests for upkeep * add a config setting to disable upkeep in tests * add a config setting to disable random factor in studying --- scripts/tests/common.lua | 27 +++++++++++++- src/gamecode/laws.c | 17 +++++++-- src/kernel/config.c | 76 +++++++++++++++++++++++++--------------- src/kernel/skill.c | 20 +++++++---- 4 files changed, 101 insertions(+), 39 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 76bc5a763..d83a5314e 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -2,6 +2,7 @@ require "lunit" function setup() free_game() + settings.set("rules.economy.food", "4") end function one_unit(r, f) @@ -650,6 +651,30 @@ function test_expensive_skills_cost_money() u:clear_orders() u:add_order("LERNEN MAGIE Gwyrrd") process_orders() - assert_equal(9890, u:get_item("money")) + assert_equal(9900, u:get_item("money")) assert_equal(1, u:get_skill("magic")) end + +function test_food_is_consumed() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u:add_item("money", 100) + u:clear_orders() + u:add_order("LERNEN Reiten") -- don't work + settings.set("rules.economy.food", "4") + process_orders() + assert_equal(100, u:get_item("money")) +end + +function test_food_can_override() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u:add_item("money", 100) + u:clear_orders() + u:add_order("LERNEN Reiten") -- don't work + settings.set("rules.economy.food", "0") + process_orders() + assert_equal(90, u:get_item("money")) +end diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 232637508..5986ff315 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -196,6 +196,12 @@ help_feed(unit * donor, unit * u, int * need_p) *need_p = need; } +enum { + FOOD_FROM_PEASANTS = 1, + FOOD_FROM_OWNER = 2, + FOOD_IS_FREE = 4 +}; + static void get_food(region *r) { @@ -203,11 +209,16 @@ get_food(region *r) unit *u; int peasantfood = rpeasants(r)*10; static int food_rules = -1; + static int gamecookie = -1; - if (food_rules<0) { + if (food_rules<0 || gamecookie!=global.cookie) { + gamecookie = global.cookie; food_rules = get_param_int(global.parameters, "rules.economy.food", 0); } + if (food_rules&FOOD_IS_FREE) { + return; + } /* 1. Versorgung von eigenen Einheiten. Das vorhandene Silber * wird zunächst so auf die Einheiten aufgeteilt, dass idealerweise * jede Einheit genug Silber für ihren Unterhalt hat. */ @@ -238,7 +249,7 @@ get_food(region *r) u->ship->flags -= SF_FISHING; } - if (food_rules&1) { + if (food_rules&FOOD_FROM_PEASANTS) { faction * owner = region_get_owner(r); /* if the region is owned, and the owner is nice, then we'll get * food from the peasants - should not be used with WORK */ @@ -279,7 +290,7 @@ get_food(region *r) if (need > 0) { unit *v; - if (food_rules&2) { + if (food_rules&FOOD_FROM_OWNER) { /* the owner of the region is the first faction to help out when you're hungry */ faction * owner = region_get_owner(r); if (owner && owner!=u->faction) { diff --git a/src/kernel/config.c b/src/kernel/config.c index 2591ce7ec..294827f51 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -115,7 +115,9 @@ attrib_type at_xontormiaexpress = { int NewbieImmunity(void) { static int value = -1; - if (value<0) { + static int gamecookie = -1; + if (value<0 || gamecookie!=global.cookie) { + gamecookie = global.cookie; value = get_param_int(global.parameters, "NewbieImmunity", 0); } return value; @@ -130,7 +132,9 @@ IsImmune(const faction * f) static int MaxAge(void) { static int value = -1; - if (value<0) { + static int gamecookie = -1; + if (value<0 || gamecookie!=global.cookie) { + gamecookie = global.cookie; value = get_param_int(global.parameters, "MaxAge", 0); } return value; @@ -151,8 +155,10 @@ ally_flag(const char * s, int help_mask) boolean ExpensiveMigrants(void) { - int value = -1; - if (value<0) { + static int value = -1; + static int gamecookie = -1; + if (value<0 || gamecookie!=global.cookie) { + gamecookie = global.cookie; value = get_param_int(global.parameters, "study.expensivemigrants", 0); } return value; @@ -165,8 +171,10 @@ int AllianceAuto(void) { static int value = -1; - if (value<0) { + static int gamecookie = -1; + if (value<0 || gamecookie!=global.cookie) { const char * str = get_param(global.parameters, "alliance.auto"); + gamecookie = global.cookie; value = 0; if (str!=NULL) { char * sstr = strdup(str); @@ -190,78 +198,88 @@ AllianceAuto(void) int HelpMask(void) { - static int value = -1; - if (value<0) { + static int rule = -1; + static int gamecookie = -1; + if (rule<0 || gamecookie!=global.cookie) { const char * str = get_param(global.parameters, "rules.help.mask"); - value = 0; + gamecookie = global.cookie; + rule = 0; if (str!=NULL) { char * sstr = strdup(str); char * tok = strtok(sstr, " "); while (tok) { - value |= ally_flag(tok, -1); + rule |= ally_flag(tok, -1); tok = strtok(NULL, " "); } free(sstr); } else { - value = HELP_ALL; + rule = HELP_ALL; } } - return value; + return rule; } int AllianceRestricted(void) { - static int value = -1; - if (value<0) { + static int rule = -1; + static int gamecookie = -1; + if (rule<0 || gamecookie!=global.cookie) { const char * str = get_param(global.parameters, "alliance.restricted"); - value = 0; + gamecookie = global.cookie; + rule = 0; if (str!=NULL) { char * sstr = strdup(str); char * tok = strtok(sstr, " "); while (tok) { - value |= ally_flag(tok, -1); + rule |= ally_flag(tok, -1); tok = strtok(NULL, " "); } free(sstr); } - value &= HelpMask(); + rule &= HelpMask(); } - return value; + return rule; } int LongHunger(const struct unit * u) { - static int value = -1; + static int gamecookie = -1; + static int rule = -1; if (u!=NULL) { if (!fval(u, UFL_HUNGER)) return false; #ifdef NEW_DAEMONHUNGER_RULE if (u->race==new_race[RC_DAEMON]) return false; #endif } - if (value<0) { - value = get_param_int(global.parameters, "hunger.long", 0); + if (rule<0 || gamecookie!=global.cookie) { + gamecookie = global.cookie; + rule = get_param_int(global.parameters, "hunger.long", 0); } - return value; + return rule; } int SkillCap(skill_t sk) { - static int value = -1; + static int gamecookie = -1; + static int rule = -1; if (sk==SK_MAGIC) return 0; /* no caps on magic */ - if (value<0) { - value = get_param_int(global.parameters, "skill.maxlevel", 0); + if (rule<0 || gamecookie!=global.cookie) { + gamecookie = global.cookie; + rule = get_param_int(global.parameters, "skill.maxlevel", 0); } - return value; + return rule; } int NMRTimeout(void) { - static int value = -1; - if (value<0) { - value = get_param_int(global.parameters, "nmr.timeout", 0); + static int gamecookie = -1; + static int rule = -1; + if (rule<0 || gamecookie!=global.cookie) { + gamecookie = global.cookie; + rule = get_param_int(global.parameters, "nmr.timeout", 0); } - return value; + return rule; } race_t diff --git a/src/kernel/skill.c b/src/kernel/skill.c index 5f8d053d4..ebc225d27 100644 --- a/src/kernel/skill.c +++ b/src/kernel/skill.c @@ -277,16 +277,24 @@ sk_set(skill * sv, int level) sv->level = (unsigned char)level; } +static int +rule_random_progress(void) { + return get_param_int(global.parameters, "study.random_progress", 1); +} + int skill_weeks(int level) /* how many weeks must i study to get from level to level+1 */ { - int coins = 2*level; - int heads = 1; - while (coins--) { - heads += rng_int() % 2; - } - return heads; + if (rule_random_progress()) { + int coins = 2*level; + int heads = 1; + while (coins--) { + heads += rng_int() % 2; + } + return heads; + } + return level+1; } void From ed77af52619bf353b4d94fc4e0c46ad3cd9440ae Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 12 Oct 2010 23:17:35 -0700 Subject: [PATCH 027/400] http://bugs.eressea.de/view.php?id=1784 espionage should show the faction of the spied unit in the report. --- src/gamecode/spy.c | 1 + src/kernel/faction.c | 16 ++++++++++++++++ src/kernel/faction.h | 2 ++ src/kernel/reports.c | 32 +++++++++----------------------- 4 files changed, 28 insertions(+), 23 deletions(-) diff --git a/src/gamecode/spy.c b/src/gamecode/spy.c index f42caecc5..164c3b2b1 100644 --- a/src/gamecode/spy.c +++ b/src/gamecode/spy.c @@ -73,6 +73,7 @@ spy_message(int spy, const unit *u, const unit *target) if (fv && fv!=target->faction) { /* wahre Partei */ ADDMSG(&u->faction->msgs, msg_message("spyreport_faction", "target faction", target, target->faction)); + flist_add(&u->faction->seen_factions, target->faction); } } if (spy > 0) { diff --git a/src/kernel/faction.c b/src/kernel/faction.c index f5ac32f3c..44873ac24 100644 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -505,3 +505,19 @@ f_get_alliance(const struct faction * f) } return NULL; } + +void +flist_add(faction_list ** flist, faction * sf) +{ + faction_list ** fnew = flist; + while (*fnew && (*fnew)->data->no < sf->no) { + fnew =&(*fnew)->next; + } + if ((*fnew==NULL) || (*fnew)->data!=sf) { + faction_list * finsert = malloc(sizeof(faction_list)); + finsert->next = *fnew; + *fnew = finsert; + finsert->data = sf; + } +} + diff --git a/src/kernel/faction.h b/src/kernel/faction.h index faa552581..910929937 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -108,6 +108,7 @@ typedef struct faction { } * battles; struct item * items; /* items this faction can claim */ struct seen_region ** seen; + struct faction_list * seen_factions; } faction; extern struct faction *factions; @@ -117,6 +118,7 @@ typedef struct faction_list { struct faction * data; } faction_list; +void flist_add(struct faction_list ** flist, struct faction * sf); extern const struct unit * random_unit_in_faction(const struct faction *f); extern const char * factionname(const struct faction * f); extern struct unit * addplayer(struct region *r, faction * f); diff --git a/src/kernel/reports.c b/src/kernel/reports.c index dadad6481..b04cb9b0c 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -883,21 +883,6 @@ ucansee(const struct faction *f, const struct unit *u, const struct unit *x) return x; } -static void -add_faction(faction_list ** flist, faction * sf) -{ - faction_list ** fnew = flist; - while (*fnew && (*fnew)->data->no < sf->no) { - fnew =&(*fnew)->next; - } - if ((*fnew==NULL) || (*fnew)->data!=sf) { - faction_list * finsert = malloc(sizeof(faction_list)); - finsert->next = *fnew; - *fnew = finsert; - finsert->data = sf; - } -} - int stealth_modifier(int seen_mode) { @@ -921,14 +906,15 @@ get_addresses(report_context * ctx) seen_region * sr = NULL; region *r; const faction * lastf = NULL; - faction_list * flist = calloc(1, sizeof(faction_list)); - - flist->data = ctx->f; + faction_list * flist = ctx->f->seen_factions; + + ctx->f->seen_factions = NULL; /* do not delete it twice */ + flist_add(&flist, ctx->f); if (f_get_alliance(ctx->f)) { faction_list * member = ctx->f->alliance->members; for (;member;member=member->next) { - add_faction(&flist, member->data); + flist_add(&flist, member->data); } } @@ -945,7 +931,7 @@ get_addresses(report_context * ctx) faction * sf = visible_faction(ctx->f, u); if (lastf!=sf) { if (u->building || u->ship || (stealthmod>INT_MIN && cansee(ctx->f, r, u, stealthmod))) { - add_faction(&flist, sf); + flist_add(&flist, sf); lastf = sf; } } @@ -961,7 +947,7 @@ get_addresses(report_context * ctx) unit * u2 = (unit*)a->data.v; if (u2->faction==ctx->f) { if (cansee_unit(u2, u, stealthmod)) { - add_faction(&flist, sf); + flist_add(&flist, sf); lastf = sf; break; } @@ -979,7 +965,7 @@ get_addresses(report_context * ctx) boolean ballied = sf && sf!=ctx->f && sf!=lastf && !fval(u, UFL_ANON_FACTION) && cansee(ctx->f, r, u, stealthmod); if (ballied || ALLIED(ctx->f, sf)) { - add_faction(&flist, sf); + flist_add(&flist, sf); lastf = sf; } } @@ -992,7 +978,7 @@ get_addresses(report_context * ctx) faction *f2; for (f2 = factions; f2; f2 = f2->next) { if (f2->alliance == ctx->f->alliance) { - add_faction(&flist, f2); + flist_add(&flist, f2); } } } From 357de0f249d9b9526cb83255bb9258bfc69075c1 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 16 Oct 2010 22:18:30 +0200 Subject: [PATCH 028/400] fix a crash where flying ships try to anchor --- src/kernel/move.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/kernel/move.c b/src/kernel/move.c index 137d3c35d..95bead255 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -1830,7 +1830,9 @@ sail(unit * u, order * ord, boolean move_on_land, region_list **routep) * transferiert wurden, kann der aktuelle Befehl gelöscht werden. */ cycle_route(ord, u, step); set_order(&u->thisorder, NULL); - set_coast(sh, last_point, current_point); + if (!move_on_land) { + set_coast(sh, last_point, current_point); + } if( is_cursed(sh->attribs, C_SHIP_FLYING, 0) ) { ADDMSG(&f->msgs, msg_message("shipfly", "ship from to", sh, starting_point, current_point)); From 49a9992896a8d8bdcc8e4916cd8eaf23bf115fd5 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 16 Oct 2010 21:10:46 -0700 Subject: [PATCH 029/400] bindings for ship.coast --- src/bindings/bind_ship.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/bindings/bind_ship.c b/src/bindings/bind_ship.c index b5a0e90a3..2162b9933 100644 --- a/src/bindings/bind_ship.c +++ b/src/bindings/bind_ship.c @@ -144,6 +144,27 @@ static int tolua_ship_set_flags(lua_State* L) return 0; } +static int tolua_ship_set_coast(lua_State* L) +{ + ship* self = (ship*)tolua_tousertype(L, 1, 0); + if (lua_isnil(L, 2)) { + self->coast = NODIRECTION; + } else if (lua_isnumber(L, 2)) { + self->coast = (direction_t)tolua_tonumber(L, 2, 0); + } + return 0; +} + +static int tolua_ship_get_coast(lua_State* L) +{ + ship* self = (ship*)tolua_tousertype(L, 1, 0); + if (self->coast) { + tolua_pushnumber(L, self->coast); + return 1; + } + return 0; +} + void tolua_ship_open(lua_State* L) @@ -163,6 +184,7 @@ tolua_ship_open(lua_State* L) tolua_variable(L, TOLUA_CAST "units", tolua_ship_get_units, NULL); tolua_variable(L, TOLUA_CAST "flags", &tolua_ship_get_flags, tolua_ship_set_flags); tolua_variable(L, TOLUA_CAST "region", tolua_ship_get_region, tolua_ship_set_region); + tolua_variable(L, TOLUA_CAST "coast", tolua_ship_get_coast, tolua_ship_set_coast); #ifdef TODO .property("type", &ship_gettype) .property("weight", &ship_getweight) From fa6ea0a626aa1b3b703f060f1917e3c783a649a7 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 17 Oct 2010 17:24:10 -0700 Subject: [PATCH 030/400] http://bugs.eressea.de/view.php?id=1811 BTF_INDESTRUCTIBLE buildings were not indestructible --- src/kernel/build.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/kernel/build.c b/src/kernel/build.c index cd70206ff..12979a85d 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -373,7 +373,10 @@ destroy_cmd(unit * u, struct order * ord) if (u->building) { building *b = u->building; - if (n >= b->size) { + if (fval(b->type, BTF_INDESTRUCTIBLE)) { + cmistake(u, ord, 138, MSG_PRODUCE); + return 0; + } if (n >= b->size) { /* destroy completly */ /* all units leave the building */ for (u2 = r->units; u2; u2 = u2->next) { From 03fd39ac63f836a9cab55be0c2a390982954189d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 31 Oct 2010 19:31:45 -0700 Subject: [PATCH 031/400] Idiotic Visual Studio has no separate C and C++ modes, and puts curly lines under the word "friend". So they can't be called that. --- src/kernel/unit.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/kernel/unit.c b/src/kernel/unit.c index e8ab947f7..102f84656 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -152,17 +152,17 @@ dfindhash(int no) return 0; } -typedef struct friend { - struct friend * next; +typedef struct buddy { + struct buddy * next; int number; faction * faction; unit * unit; -} friend; +} buddy; -static friend * +static buddy * get_friends(const unit * u, int * numfriends) { - friend * friends = 0; + buddy * friends = 0; faction * f = u->faction; region * r = u->region; int number = 0; @@ -178,14 +178,14 @@ get_friends(const unit * u, int * numfriends) allied = 1; } if (allied) { - friend * nf, ** fr = &friends; + buddy * nf, ** fr = &friends; /* some units won't take stuff: */ if (u2->race->ec_flags & GETITEM) { while (*fr && (*fr)->faction->nofaction->no) fr = &(*fr)->next; nf = *fr; if (nf==NULL || nf->faction!=u2->faction) { - nf = malloc(sizeof(friend)); + nf = malloc(sizeof(buddy)); nf->next = *fr; nf->faction = u2->faction; nf->unit = u2; @@ -219,6 +219,8 @@ gift_items(unit * u, int flags) int retval = 0; int rule = rule_give(); + assert(u->region); + if ((u->faction->flags&FFL_QUIT)==0 || (rule&GIVE_ONDEATH)==0) { if ((rule&GIVE_ALLITEMS)==0 && (flags&GIFT_FRIENDS)) flags-=GIFT_FRIENDS; if ((rule&GIVE_PEASANTS)==0 && (flags&GIFT_PEASANTS)) flags-=GIFT_PEASANTS; @@ -257,10 +259,10 @@ gift_items(unit * u, int flags) /* if I have friends, I'll try to give my stuff to them */ if (u->faction && (flags & GIFT_FRIENDS)) { int number = 0; - friend * friends = get_friends(u, &number); + buddy * friends = get_friends(u, &number); while (friends) { - struct friend * nf = friends; + struct buddy * nf = friends; unit * u2 = nf->unit; item * itm = u->items; while (itm!=NULL) { From 279fa623d94ac3db03378e9b02ac1f66f8c4be19 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 31 Oct 2010 19:32:24 -0700 Subject: [PATCH 032/400] Make sure static data expires. --- src/gamecode/laws.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 5986ff315..154ce3b4b 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -124,8 +124,11 @@ boolean nomonsters = false; static int RemoveNMRNewbie(void) { static int value = -1; - if (value<0) { + static int gamecookie = -1; + + if (value<0 || gamecookie!=global.cookie) { value = get_param_int(global.parameters, "nmr.removenewbie", 0); + gamecookie = global.cookie; } return value; } From 321c0816f6fcf9ac6e4f449891d218a5e9c56e5a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 31 Oct 2010 19:33:18 -0700 Subject: [PATCH 033/400] harmless code beautification --- src/bindings/bind_region.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/bindings/bind_region.c b/src/bindings/bind_region.c index 19ec1dedb..022f65d24 100644 --- a/src/bindings/bind_region.c +++ b/src/bindings/bind_region.c @@ -199,15 +199,6 @@ static int tolua_region_set_morale(lua_State* L) return 0; } -static int tolua_region_get_flag(lua_State* L) -{ - region* self = (region*)tolua_tousertype(L, 1, 0); - int bit = (int)tolua_tonumber(L, 2, 0); - - lua_pushboolean(L, (self->flags & (1<flags & (1< Date: Sun, 31 Oct 2010 19:34:55 -0700 Subject: [PATCH 034/400] new test: verify that units swim after terraforming, and can get picked up by boats in the turn thereafter. --- scripts/tests/common.lua | 43 ++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index d83a5314e..8d52e6c87 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -2,6 +2,8 @@ require "lunit" function setup() free_game() + settings.set("nmr.removenewbie", "0") + settings.set("nmr.timeout", "0") settings.set("rules.economy.food", "4") end @@ -18,9 +20,7 @@ end function two_factions() local f1 = faction.create("noreply@eressea.de", "human", "de") - f1.id = 1 local f2 = faction.create("noreply@eressea.de", "orc", "de") - f2.id = 2 return f1, f2 end @@ -371,7 +371,6 @@ function test_work() free_game() local r = region.create(0, 0, "plain") local f = faction.create("noreply@eressea.de", "human", "de") - f.id = 42 local u = unit.create(f, r, 1) u:add_item("money", u.number * 10) -- humans cost 10 u:set_skill("herbalism", 5) @@ -385,7 +384,6 @@ function test_upkeep() free_game() local r = region.create(0, 0, "plain") local f = faction.create("noreply@eressea.de", "human", "de") - f.id = 42 local u = unit.create(f, r, 5) u:add_item("money", u.number * 11) u:clear_orders() @@ -430,7 +428,6 @@ function test_herbalism() free_game() local r = region.create(0, 0, "plain") local f = faction.create("noreply@eressea.de", "human", "de") - f.id = 42 local u = unit.create(f, r, 1) u:add_item("money", u.number * 100) u:set_skill("herbalism", 5) @@ -524,12 +521,12 @@ function test_control() assert_equal(u2, b.owner) end -function test_storage() +function test_store_unit() free_game() local r = region.create(0, 0, "plain") local f = faction.create("noreply@eressea.de", "human", "de") - f.id = 42 local u = unit.create(f, r, 1) + local fid = f.id u:add_item("money", u.number * 100) store = storage.create("test.unit.dat", "wb") assert_not_equal(store, nil) @@ -539,7 +536,7 @@ function test_storage() -- recreate world: r = region.create(0, 0, "plain") f = faction.create("noreply@eressea.de", "human", "de") - f.id = 42 + f.id = fid store = storage.create("test.unit.dat", "rb") assert(store) u = store:read_unit() @@ -678,3 +675,33 @@ function test_food_can_override() process_orders() assert_equal(90, u:get_item("money")) end + +function test_swim_and_survive() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + f.nam = "chaos" + local u = unit.create(f, r, 1) + f.age = 20 + u:add_item("money", 100) + process_orders() + r.terrain = "ocean" + local s = ship.create(r, "boat") + u:clear_orders() + u:add_order("BETRETE SCHIFF " .. itoa36(s.id)) + process_orders() + assert_equal(u.number, 1) +end + +function test_swim_and_die() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + local uid = u.id + u:add_item("money", 100) + process_orders() + r.terrain = "ocean" + u = get_unit(uid) + assert_not_equal(get_unit(uid), nil) + process_orders() + assert_equal(get_unit(uid), nil) +end From c5418fc28b9d34e2f88626f9c9821e6d5085746f Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 31 Oct 2010 19:46:08 -0700 Subject: [PATCH 035/400] E3 does not have a boat, so tests needs to create a canoe sometimes --- scripts/tests/common.lua | 15 ++++++++++----- src/kernel/ship.c | 1 + 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 8d52e6c87..0596a08d2 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -1,5 +1,13 @@ require "lunit" +local function _test_create_ship(r) + local s = ship.create(r, "canoe") + if (s==nil) then + s = ship.create(r, "boat") + end + return s +end + function setup() free_game() settings.set("nmr.removenewbie", "0") @@ -414,10 +422,7 @@ function test_id() assert(get_building(fortytwo)==b) assert(get_building(atoi36(fortytwo))==b) - local s = ship.create(r, "canoe") - if (s==nil) then - s = ship.create(r, "boat") - end + local s = _test_create_ship(r) -- s.id = atoi36("42") local fortytwo = itoa36(s.id) assert(get_ship(fortytwo)==s) @@ -685,7 +690,7 @@ function test_swim_and_survive() u:add_item("money", 100) process_orders() r.terrain = "ocean" - local s = ship.create(r, "boat") + local s = _test_create_ship(r) u:clear_orders() u:add_order("BETRETE SCHIFF " .. itoa36(s.id)) process_orders() diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 5cf96aa3c..4f9364fa7 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -179,6 +179,7 @@ new_ship(const ship_type * stype, const struct locale * lang, region * r) ship *sh = (ship *) calloc(1, sizeof(ship)); assert(stype); + assert(r); sh->no = newcontainerid(); sh->coast = NODIRECTION; sh->type = stype; From 0472c35647808a4a93e25afbe0e5fcbdcd696b63 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 31 Oct 2010 23:31:56 -0700 Subject: [PATCH 036/400] * clean up the test setup * test horses, carts and their capacities --- scripts/tests/common.lua | 133 ++++++++++++++++++++++++++------------- 1 file changed, 91 insertions(+), 42 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 0596a08d2..1582a179b 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -8,25 +8,18 @@ local function _test_create_ship(r) return s end -function setup() - free_game() - settings.set("nmr.removenewbie", "0") - settings.set("nmr.timeout", "0") - settings.set("rules.economy.food", "4") -end - -function one_unit(r, f) +local function one_unit(r, f) local u = unit.create(f, r, 1) u:add_item("money", u.number * 100) u:clear_orders() return u end -function two_units(r, f1, f2) +local function two_units(r, f1, f2) return one_unit(r, f1), one_unit(r, f2) end -function two_factions() +local function two_factions() local f1 = faction.create("noreply@eressea.de", "human", "de") local f2 = faction.create("noreply@eressea.de", "orc", "de") return f1, f2 @@ -34,6 +27,13 @@ end module( "common", package.seeall, lunit.testcase ) +function setup() + free_game() + settings.set("nmr.removenewbie", "0") + settings.set("nmr.timeout", "0") + settings.set("rules.economy.food", "4") +end + function DISABLE_test_eventbus_fire() local r = region.create(0, 0, "plain") local f = faction.create("noreply@eressea.de", "human", "de") @@ -85,14 +85,12 @@ function test_plane() end function test_pure() - free_game() local r = region.create(0, 0, "plain") assert_not_equal(nil, r) assert_equal(r, get_region(0, 0)) end function test_read_write() - free_game() local r = region.create(0, 0, "plain") local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r) @@ -118,11 +116,9 @@ function test_read_write() assert_not_equal(nil, get_region(0, 0)) assert_not_equal(nil, get_faction(fno)) assert_not_equal(nil, get_unit(uno)) - free_game() end function test_gmtool() - free_game() local r1 = region.create(1, 0, "plain") local r2 = region.create(1, 1, "plain") local r3 = region.create(1, 2, "plain") @@ -147,7 +143,6 @@ function test_gmtool() end function test_faction() - free_game() local r = region.create(0, 0, "plain") local f = faction.create("noreply@eressea.de", "human", "de") assert(f) @@ -171,7 +166,6 @@ function test_faction() end function test_unit() - free_game() local r = region.create(0, 0, "plain") local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r) @@ -188,7 +182,6 @@ function test_unit() end function test_region() - free_game() local r = region.create(0, 0, "plain") r:set_resource("horse", 42) r:set_resource("money", 45) @@ -206,7 +199,6 @@ function test_region() end function test_building() - free_game() local u local f = faction.create("noreply@eressea.de", "human", "de") local r = region.create(0, 0, "plain") @@ -233,7 +225,6 @@ function test_building() end function test_message() - free_game() local r = region.create(0, 0, "plain") local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r) @@ -248,7 +239,6 @@ function test_message() end function test_hashtable() - free_game() local f = faction.create("noreply@eressea.de", "human", "de") f.objects:set("enno", "smart guy") f.objects:set("age", 10) @@ -299,7 +289,6 @@ function test_events() end function test_recruit2() - free_game() local r = region.create(0, 0, "plain") local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r) @@ -314,7 +303,6 @@ function test_recruit2() end function test_guard() - free_game() region.create(1, 0, "plain") local r = region.create(0, 0, "plain") local f1 = faction.create("noreply@eressea.de", "human", "de") @@ -343,7 +331,6 @@ function test_guard() end function test_recruit() - free_game() local r = region.create(0, 0, "plain") local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r) @@ -361,7 +348,6 @@ function test_recruit() end function test_produce() - free_game() local r = region.create(0, 0, "plain") local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r, 1) @@ -376,7 +362,6 @@ function test_produce() end function test_work() - free_game() local r = region.create(0, 0, "plain") local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r, 1) @@ -389,19 +374,18 @@ function test_work() end function test_upkeep() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - local u = unit.create(f, r, 5) - u:add_item("money", u.number * 11) - u:clear_orders() - u:add_order("LERNE Waffenbau") - process_orders() - assert(u:get_item("money")==u.number) + settings.set("rules.economy.food", "0") + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 5) + u:add_item("money", u.number * 11) + u:clear_orders() + u:add_order("LERNE Waffenbau") + process_orders() + assert(u:get_item("money")==u.number) end function test_id() - free_game() local r = region.create(0, 0, "plain") local f = faction.create("noreply@eressea.de", "human", "de") @@ -430,7 +414,6 @@ function test_id() end function test_herbalism() - free_game() local r = region.create(0, 0, "plain") local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r, 1) @@ -442,7 +425,6 @@ function test_herbalism() end function test_mallorn() - free_game() local r = region.create(0, 0, "plain") r:set_flag(1, false) -- not mallorn r:set_resource("tree", 100) @@ -512,7 +494,6 @@ function test_coordinate_translation() end function test_control() - free_game() local u1, u2 = two_units(region.create(0, 0, "plain"), two_factions()) local r = u1.region local b = building.create(r, "castle") @@ -527,7 +508,6 @@ function test_control() end function test_store_unit() - free_game() local r = region.create(0, 0, "plain") local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r, 1) @@ -686,8 +666,6 @@ function test_swim_and_survive() local f = faction.create("noreply@eressea.de", "human", "de") f.nam = "chaos" local u = unit.create(f, r, 1) - f.age = 20 - u:add_item("money", 100) process_orders() r.terrain = "ocean" local s = _test_create_ship(r) @@ -702,7 +680,6 @@ function test_swim_and_die() local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r, 1) local uid = u.id - u:add_item("money", 100) process_orders() r.terrain = "ocean" u = get_unit(uid) @@ -710,3 +687,75 @@ function test_swim_and_die() process_orders() assert_equal(get_unit(uid), nil) end + +function test_ride_with_horse() + region.create(1, 0, "plain") + region.create(2, 0, "plain") + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u:add_item("horse", 1) + u:add_item("sword", 10) + u:set_skill("riding", 2) + + u:clear_orders() + u:add_order("NACH O O") + process_orders() + assert_equal(u.region.x, 2) + + u:add_item("sword", 1) + u:clear_orders() + u:add_order("NACH W W") + process_orders() + assert_equal(u.region.x, 1) +end + +function test_ride_with_horses_and_cart() + region.create(1, 0, "plain") + region.create(2, 0, "plain") + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u:add_item("cart", 1) + u:add_item("horse", 2) + u:add_item("sword", 120) + u:set_skill("riding", 3) + + -- ride + u:clear_orders() + u:add_order("NACH O O") + process_orders() + assert_equal(2, u.region.x) + + -- walk + u:add_item("sword", 20) + r:get_key("eviL") + u:clear_orders() + u:add_order("NACH W W") + process_orders() + assert_equal(1, u.region.x) + + -- too heavy + + u:add_item("sword", 10) + r:get_key("eviL") + u:clear_orders() + u:add_order("NACH W W") + process_orders() + assert_equal(1, u.region.x) +end + +function test_walk_and_carry_the_cart() + region.create(1, 0, "plain") + local r = region.create(2, 0, "plain") + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 10) + u:add_item("cart", 1) + + -- walk + u:clear_orders() + u:add_order("NACH O O") + process_orders() + assert_equal(1, u.region.x) +end From 33100abebb846ab1858e2061231edf0f77af034f Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 2 Nov 2010 22:23:04 -0700 Subject: [PATCH 037/400] http://bugs.eressea.de/view.php?id=1585 prevent prospecting-exploit --- src/gamecode/economy.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index 53000af93..7d19c80a7 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -1752,15 +1752,9 @@ split_allocations(region * r) fset(r, RF_SELECT); } if (al->want==INT_MAX) al->want = al->get; - if (fval(al, AFL_LOWSKILL)) { - ADDMSG(&al->unit->faction->msgs, - msg_message("produce_lowskill", "unit region resource", - al->unit, al->unit->region, rtype)); - } else { - ADDMSG(&al->unit->faction->msgs, msg_message("produce", - "unit region amount wanted resource", - al->unit, al->unit->region, al->get, al->want, rtype)); - } + ADDMSG(&al->unit->faction->msgs, msg_message("produce", + "unit region amount wanted resource", + al->unit, al->unit->region, al->get, al->want, rtype)); *p_al=al->next; free_allocation(al); } From 12828f0edde6b2f2e02e593720bbf2a0ed0cfcb7 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 5 Nov 2010 21:21:49 -0700 Subject: [PATCH 038/400] for planes that have no name, do not print a comma after the coordinates (this has irritated me in E3). also: add tests for this, and add a way to assert on content in reports. --- scripts/tests/common.lua | 57 ++++++++++++++++++++++++++++++++++++++++ src/kernel/plane.c | 5 ---- src/kernel/reports.c | 3 ++- 3 files changed, 59 insertions(+), 6 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 1582a179b..c4e2ea88a 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -759,3 +759,60 @@ function test_walk_and_carry_the_cart() process_orders() assert_equal(1, u.region.x) end + +module( "report", package.seeall, lunit.testcase ) + +function setup() + free_game() + settings.set("nmr.removenewbie", "0") + settings.set("nmr.timeout", "0") + settings.set("rules.economy.food", "4") +end + +local function assert_in_report(f, pattern) + write_report(f) + local filename = config.basepath .. "/reports/" .. get_turn() .. "-" .. itoa36(f.id) .. ".nr" + local report = io.open(filename, 'rt'); + t = report:read("*all") + if string.find(t, pattern) == nil then + print(t, pattern) + end + assert_not_equal(nil, string.find(t, pattern)) + report:close() +-- posix.unlink(filename) +end + +function test_coordinates_no_plane() + local r = region.create(0, 0, "mountain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + init_reports() + assert_in_report(f, r.name .. " %(0,0%), Berg") +end + +function test_coordinates_named_plane() + local p = plane.create(0, -3, -3, 7, 7, "Hell") + local r = region.create(0, 0, "mountain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + init_reports() + assert_in_report(f, r.name .. " %(0,0,Hell%), Berg") +end + +function test_coordinates_unnamed_plane() + local p = plane.create(0, -3, -3, 7, 7) + local r = region.create(0, 0, "mountain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + init_reports() + assert_in_report(f, r.name .. " %(0,0%), Berg") +end + +function test_coordinates_noname_plane() + local p = plane.create(0, -3, -3, 7, 7, "") + local r = region.create(0, 0, "mountain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + init_reports() + assert_in_report(f, r.name .. " %(0,0%), Berg") +end diff --git a/src/kernel/plane.c b/src/kernel/plane.c index 8ab941838..f2c544ff3 100644 --- a/src/kernel/plane.c +++ b/src/kernel/plane.c @@ -53,8 +53,6 @@ int plane_height(const plane * pl) return 0; } -static plane * home_plane = NULL; - plane * get_homeplane(void) { @@ -261,9 +259,6 @@ create_new_plane(int id, const char *name, int minx, int maxx, int miny, int max pl->flags = flags; addlist(&planes, pl); - if (id==0) { - home_plane = pl; - } return pl; } diff --git a/src/kernel/reports.c b/src/kernel/reports.c index b04cb9b0c..27f14128a 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -1615,11 +1615,12 @@ f_regionid(const region * r, const faction * f, char * buffer, size_t size) plane * pl = rplane(r); const char * name = pl?pl->name:0; int nx = r->x, ny = r->y; + int named = (name && name[0]); pnormalize(&nx, &ny, pl); adjust_coordinates(f, &nx, &ny, pl, r); strncpy(buffer, rname(r, f->locale), size); buffer[size-1]=0; - sprintf(buffer+strlen(buffer), " (%d,%d%s%s)", nx, ny, name?",":"", (name)?name:""); + sprintf(buffer+strlen(buffer), " (%d,%d%s%s)", nx, ny, named?",":"", (named)?name:""); } return strlen(buffer); } From e7ce28a258d5f57f0479f3c986dc8cbb05e9c706 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 5 Nov 2010 22:54:29 -0700 Subject: [PATCH 039/400] http://bugs.eressea.de/view.php?id=1814 fix a quoting bug in the order parser, add a very basic test to make sure order parsing works. --- scripts/tests/common.lua | 62 ++++++++++++++++++++++++++++++++++++---- src/kernel/save.c | 2 +- src/util/filereader.c | 4 ++- 3 files changed, 60 insertions(+), 8 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index c4e2ea88a..86f625123 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -769,17 +769,24 @@ function setup() settings.set("rules.economy.food", "4") end -local function assert_in_report(f, pattern) +local function find_in_report(f, pattern, extension) + extension = extension or "nr" write_report(f) - local filename = config.basepath .. "/reports/" .. get_turn() .. "-" .. itoa36(f.id) .. ".nr" + local filename = config.basepath .. "/reports/" .. get_turn() .. "-" .. itoa36(f.id) .. "." .. extension local report = io.open(filename, 'rt'); t = report:read("*all") - if string.find(t, pattern) == nil then - print(t, pattern) - end - assert_not_equal(nil, string.find(t, pattern)) report:close() + + local start, _ = string.find(t, pattern) -- posix.unlink(filename) + return start~=nil +end + +local function assert_in_report(f, pattern, extension) + assert_not_equal(nil, find_in_report(f, pattern, extension)) +end +local function assert_not_in_report(f, pattern, extension) + assert_equal(nil, find_in_report(f, pattern, extension)) end function test_coordinates_no_plane() @@ -816,3 +823,46 @@ function test_coordinates_noname_plane() init_reports() assert_in_report(f, r.name .. " %(0,0%), Berg") end + +module( "parser", package.seeall, lunit.testcase ) + +function setup() + free_game() +end + +function test_parser() + local r = region.create(0, 0, "mountain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + local filename = "1814.txt" + + local file = io.open(filename, "w+") + file:write('ERESSEA ' .. itoa36(f.id) .. ' "' .. f.password .. '"\n') + file:write('EINHEIT ' .. itoa36(u.id) .. "\n") + file:write("LERNEN Hiebwaffen\n") + file:close() + + read_orders(filename) + process_orders() + assert_not_equal(0, u:get_skill("melee")) +end + +function test_bug_1814() + -- see http://bugs.eressea.de/view.php?id=1814 + local r = region.create(0, 0, "mountain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + local filename = "1814.txt" + + local file = io.open(filename, "w+") + file:write('ERESSEA ' .. itoa36(f.id) .. ' "' .. f.password .. '"\n') + file:write('EINHEIT ' .. itoa36(u.id) .. "\n") + file:write("; parse error follows: '\n") + file:write("; ARBEITE\n") + file:close() + + read_orders(filename) + process_orders() + init_reports() + assert_false(find_in_report(f, "Der Befehl wurde nicht erkannt", "cr")) +end diff --git a/src/kernel/save.c b/src/kernel/save.c index 67c268d45..5d43bf6c5 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -443,7 +443,7 @@ readorders(const char *filename) } fclose(F); - puts("\n"); + if (verbosity>=1) puts("\n"); log_printf(" %d Befehlsdateien gelesen\n", nfactions); return 0; } diff --git a/src/util/filereader.c b/src/util/filereader.c index 26c745851..a87427a54 100644 --- a/src/util/filereader.c +++ b/src/util/filereader.c @@ -57,6 +57,7 @@ getbuf_latin1(FILE * F) while (*bp && isxspace(*(unsigned char*)bp)) ++bp; /* eatwhite */ comment = (boolean)(comment && cont); + quote = (boolean)(quote && cont); if (tail[1]==0) { /* we read he maximum number of bytes! */ @@ -189,9 +190,10 @@ getbuf_utf8(FILE * F) bp += white; comment = (boolean)(comment && cont); + quote = (boolean)(quote && cont); if (tail[1]==0) { - /* we read he maximum number of bytes! */ + /* we read the maximum number of bytes! */ if (tail[0]!='\n') { /* it wasn't enough space to finish the line, eat the rest */ for (;;) { From d3a7d222537cfa1ce9a25ad4efe733420cae4a80 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 11 Nov 2010 20:11:19 -0800 Subject: [PATCH 040/400] http://bugs.eressea.de/view.php?id=1679 Applying a patch provided by Solthar: Server will give error when unit is given more than one long order. I just added a test to this. --- res/messages.xml | 4 +- scripts/tests/common.lua | 43 +++++++++++++----- src/gamecode/economy.c | 2 + src/gamecode/laws.c | 55 +++++++++++++++++++++-- src/kernel/order.c | 94 ++++++++++++++++++++++++++++++++++++++++ src/kernel/order.h | 1 + 6 files changed, 181 insertions(+), 18 deletions(-) diff --git a/res/messages.xml b/res/messages.xml index 443f98785..6d14bfd30 100644 --- a/res/messages.xml +++ b/res/messages.xml @@ -3800,7 +3800,7 @@ "$unit($unit) in $region($region): '$order($command)' - Das Gebäude kann nur einmal pro Runde erweitert werden." - "$unit($unit) in $region($region): '$order($command)' - Thhe building can be expanded only once per turn." + "$unit($unit) in $region($region): '$order($command)' - The building can be expanded only once per turn." @@ -6460,7 +6460,7 @@ "$unit($unit) in $region($region): '$order($command)' - Die Einheit kann keine weiteren langen Befehle ausführen." - "$unit($unit) in $region($region): '$order($command)' - The unit is exhausted from battle." + "$unit($unit) in $region($region): '$order($command)' - The unit cannot execute more long orders." diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 86f625123..f0d987ada 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -771,7 +771,6 @@ end local function find_in_report(f, pattern, extension) extension = extension or "nr" - write_report(f) local filename = config.basepath .. "/reports/" .. get_turn() .. "-" .. itoa36(f.id) .. "." .. extension local report = io.open(filename, 'rt'); t = report:read("*all") @@ -782,19 +781,13 @@ local function find_in_report(f, pattern, extension) return start~=nil end -local function assert_in_report(f, pattern, extension) - assert_not_equal(nil, find_in_report(f, pattern, extension)) -end -local function assert_not_in_report(f, pattern, extension) - assert_equal(nil, find_in_report(f, pattern, extension)) -end - function test_coordinates_no_plane() local r = region.create(0, 0, "mountain") local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r, 1) init_reports() - assert_in_report(f, r.name .. " %(0,0%), Berg") + write_report(f) + assert_true(find_in_report(f, r.name .. " %(0,0%), Berg")) end function test_coordinates_named_plane() @@ -803,7 +796,8 @@ function test_coordinates_named_plane() local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r, 1) init_reports() - assert_in_report(f, r.name .. " %(0,0,Hell%), Berg") + write_report(f) + assert_true(find_in_report(f, r.name .. " %(0,0,Hell%), Berg")) end function test_coordinates_unnamed_plane() @@ -812,7 +806,8 @@ function test_coordinates_unnamed_plane() local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r, 1) init_reports() - assert_in_report(f, r.name .. " %(0,0%), Berg") + write_report(f) + assert_true(find_in_report(f, r.name .. " %(0,0%), Berg")) end function test_coordinates_noname_plane() @@ -821,7 +816,8 @@ function test_coordinates_noname_plane() local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r, 1) init_reports() - assert_in_report(f, r.name .. " %(0,0%), Berg") + write_report(f) + assert_true(find_in_report(f, r.name .. " %(0,0%), Berg")) end module( "parser", package.seeall, lunit.testcase ) @@ -864,5 +860,28 @@ function test_bug_1814() read_orders(filename) process_orders() init_reports() + write_report(f) assert_false(find_in_report(f, "Der Befehl wurde nicht erkannt", "cr")) end + +function test_bug_1679() + -- see http://bugs.eressea.de/view.php?id=1679 + local r = region.create(0, 0, "mountain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + local filename = "1814.txt" + + local file = io.open(filename, "w+") + file:write('ERESSEA ' .. itoa36(f.id) .. ' "' .. f.password .. '"\n') + file:write('EINHEIT ' .. itoa36(u.id) .. "\n") + file:write("NACH W\n") + file:write("ARBEITEN\n") + file:close() + + read_orders(filename) + process_orders() + init_reports() + write_report(f) + assert_true(find_in_report(f, "Die Einheit kann keine weiteren langen Befehle", "cr")) + assert_true(find_in_report(f, "entdeckt, dass es keinen Weg nach Westen gibt")) +end diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index 7d19c80a7..0c4110401 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -3349,7 +3349,9 @@ produce(struct region *r) continue; if (fval(u, UFL_LONGACTION) && u->thisorder==NULL) { + /* this message was already given in laws.setdefaults cmistake(u, u->thisorder, 52, MSG_PRODUCE); + */ continue; } diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 154ce3b4b..762b4c0ae 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -3335,6 +3335,48 @@ new_units(void) } } +/** Checks for two long orders and issues a warning if necessary. + */ +void check_long_orders(unit *u) { + order *ord; + keyword_t otherorder = MAXKEYWORDS; + + for (ord = u->orders; ord; ord = ord->next) { + if (get_keyword(ord) == NOKEYWORD) { + cmistake(u, ord, 22, MSG_EVENT); + } else if (is_long(ord)) { + keyword_t longorder = get_keyword(ord); + if (otherorder != MAXKEYWORDS) { + switch (longorder) { + case K_CAST: + if (otherorder!=longorder) { + cmistake(u, ord, 52, MSG_EVENT); + } + break; + case K_BUY: + if (otherorder==K_SELL) { + otherorder=K_BUY; + } else { + cmistake(u, ord, 52, MSG_EVENT); + } + break; + case K_SELL: + if (otherorder!=K_SELL && otherorder!=K_BUY) { + cmistake(u, ord, 52, MSG_EVENT); + } + break; + case K_WEREWOLF: + /* don't know what WEREWOLF does... */ + default: + cmistake(u, ord, 52, MSG_EVENT); + } + } else { + otherorder = longorder; + } + } + } +} + static void setdefaults(unit *u) { @@ -3346,9 +3388,14 @@ setdefaults(unit *u) if (hunger) { /* Hungernde Einheiten führen NUR den default-Befehl aus */ set_order(&u->thisorder, default_order(u->faction->locale)); + } else { + check_long_orders(u); } /* check all orders for a potential new long order this round: */ for (ord = u->orders; ord; ord = ord->next) { + if (get_keyword(ord) == NOKEYWORD) + continue; + if (u->old_orders && is_repeated(ord)) { /* this new order will replace the old defaults */ free_orders(&u->old_orders); @@ -3371,9 +3418,6 @@ setdefaults(unit *u) * werden. Da Handel erst nach anderen langen Befehlen kommt, * muß das vorher abgefangen werden. Wir merken uns also * hier, ob die Einheit handelt. */ - case NOKEYWORD: - cmistake(u, ord, 22, MSG_EVENT); - break; case K_BUY: case K_SELL: /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht @@ -3872,7 +3916,8 @@ process(void) porder = punit; while (porder && porder->priority==prio && porder->type==PR_ORDER) { order ** ordp = &u->orders; - if (porder->flags & PROC_THISORDER) ordp = &u->thisorder; + if (porder->flags & PROC_THISORDER) + ordp = &u->thisorder; while (*ordp) { order * ord = *ordp; if (get_keyword(ord) == porder->data.per_order.kword) { @@ -3885,7 +3930,9 @@ process(void) cmistake(u, ord, 224, MSG_MAGIC); ord = NULL; } else if (fval(u, UFL_LONGACTION)) { + /* this message was already given in laws.setdefaults cmistake(u, ord, 52, MSG_PRODUCE); + */ ord = NULL; } else if (fval(r->terrain, SEA_REGION) && u->race != new_race[RC_AQUARIAN] && !(u->race->flags & RCF_SWIM)) { /* error message disabled by popular demand */ diff --git a/src/kernel/order.c b/src/kernel/order.c index 690cd0181..e1513a01f 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -361,6 +361,14 @@ parse_order(const char * s, const struct locale * lang) return NULL; } +/** + * Returns true if the order qualifies as "repeated". An order is repeated if it will overwrite the + * old default order. K_BUY is in this category, but not K_MOVE. + * + * \param ord An order. + * \return true if the order is long + * \sa is_exclusive(), is_repeated(), is_persistent() + */ boolean is_repeated(const order * ord) { @@ -420,6 +428,14 @@ is_repeated(const order * ord) return false; } +/** + * Returns true if the order qualifies as "exclusive". An order is exclusive if it makes all other + * long orders illegal. K_MOVE is in this category, but not K_BUY. + * + * \param ord An order. + * \return true if the order is long + * \sa is_exclusive(), is_repeated(), is_persistent() + */ boolean is_exclusive(const order * ord) { @@ -479,6 +495,84 @@ is_exclusive(const order * ord) return false; } +/** + * Returns true if the order qualifies as "long". An order is long if it excludes most other long + * orders. + * + * \param ord An order. + * \return true if the order is long + * \sa is_exclusive(), is_repeated(), is_persistent() + */ +boolean +is_long(const order * ord) +{ + keyword_t kwd = ORD_KEYWORD(ord); + const struct locale * lang = ORD_LOCALE(ord); + param_t param; + + switch (kwd) { + case K_CAST: + case K_BUY: + case K_SELL: + case K_MOVE: + case K_WEREWOLF: + case K_ROUTE: + case K_DRIVE: + case K_WORK: + case K_BESIEGE: + case K_ENTERTAIN: + case K_TAX: + case K_RESEARCH: + case K_SPY: + case K_STEAL: + case K_SABOTAGE: + case K_STUDY: + case K_TEACH: + case K_BREED: + case K_PIRACY: + return true; + + case K_PLANT: + return true; + + case K_FOLLOW: + /* FOLLOW is only a long order if we are following a ship. */ + parser_pushstate(); + init_tokens(ord); + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param == P_SHIP) return true; + break; + + case K_MAKE: + /* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen + * Arten von MACHE zaehlen aber als neue defaults und werden + * behandelt wie die anderen (deswegen kein break nach case + * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) + * abgespeichert). */ + parser_pushstate(); + init_tokens(ord); /* initialize token-parser */ + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param != P_TEMP) return true; + break; + } + return false; +} + +/** + * Returns true if the order qualifies as "persistent". An order is persistent if it will be + * included in the template orders. @-orders, comments and most long orders are in this category, + * but not K_MOVE. + * + * \param ord An order. + * \return true if the order is persistent + * \sa is_exclusive(), is_repeated(), is_persistent() + */ boolean is_persistent(const order * ord) { diff --git a/src/kernel/order.h b/src/kernel/order.h index 29f273863..f840ad7fc 100644 --- a/src/kernel/order.h +++ b/src/kernel/order.h @@ -51,6 +51,7 @@ extern char * getcommand(const order * ord); extern boolean is_persistent(const order *ord); extern boolean is_exclusive(const order *ord); extern boolean is_repeated(const order * ord); +extern boolean is_long(const order *ord); extern char * write_order(const order * ord, char * buffer, size_t size); From c421cf06773a0e148c74d2c244f21caa5a4e1a62 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 13 Nov 2010 13:09:59 -0800 Subject: [PATCH 041/400] move some messages to a different section in the report, because they are important. --- res/messages.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/res/messages.xml b/res/messages.xml index 6d14bfd30..d0c2fcbe7 100644 --- a/res/messages.xml +++ b/res/messages.xml @@ -7151,7 +7151,7 @@ "$unit($unit) pays the maintenance for $building($building)." "$unit($unit) pays the maintenance for $building($building)." - + @@ -7160,7 +7160,7 @@ "$unit($unit) fehlen $resource($item,0) für den Betrieb von $building($building)." "$unit($unit) lacks $resource($item,0) to operate $building($building)." - + @@ -7169,7 +7169,7 @@ "$unit($unit) cannot pay the maintenance for $building($building)." "$unit($unit) cannot pay the maintenance for $building($building)." - + From e0d70b096ac42928bca871c7507f948f1a8602b8 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 4 Dec 2010 17:35:49 -0800 Subject: [PATCH 042/400] http://bugs.eressea.de/view.php?id=1825 giving command to empty units is a mistake. --- src/gamecode/economy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index 0c4110401..84bd59144 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -654,7 +654,7 @@ give_control_cmd(unit * u, order * ord) if (p == P_CONTROL) { message * msg; - if (!u2) { + if (!u2 || u2->number==0) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); } else if (!u->building && !u->ship) { From dec5bb883443cff75f7d2645d736ed0c91ebea34 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 5 Feb 2011 23:01:51 -0800 Subject: [PATCH 043/400] code cleanup --- src/bindings/bind_attrib.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/bindings/bind_attrib.c b/src/bindings/bind_attrib.c index f92bcb99e..dd1544fbc 100644 --- a/src/bindings/bind_attrib.c +++ b/src/bindings/bind_attrib.c @@ -293,16 +293,33 @@ attrib_type at_lua_ext = { "lua", init_ext, free_ext, age_ext, write_ext, read_ext }; -static int -tolua_attrib_create(lua_State* L) -{ +static attrib ** +get_attribs(lua_State * L, int idx) { attrib ** ap = NULL; tolua_Error tolua_err; - if (tolua_isusertype(L, 1, TOLUA_CAST "unit", 0, &tolua_err)) { - unit * u = (unit *)tolua_tousertype(L, 1, 0); + if (tolua_isusertype(L, idx, TOLUA_CAST "unit", 0, &tolua_err)) { + unit * u = (unit *)tolua_tousertype(L, idx, 0); ap = &u->attribs; + } else if (tolua_isusertype(L, idx, TOLUA_CAST "region", 0, &tolua_err)) { + region * r = (region *)tolua_tousertype(L, idx, 0); + ap = &r->attribs; + } else if (tolua_isusertype(L, idx, TOLUA_CAST "faction", 0, &tolua_err)) { + faction * f = (faction *)tolua_tousertype(L, idx, 0); + ap = &f->attribs; + } else if (lua_isstring(L, idx)) { + const char * str = tolua_tostring(L, idx, NULL); + if (str && strcmp(str, "global")==0) { + ap = &global.attribs; + } } + return ap; +} + +static int +tolua_attrib_create(lua_State* L) +{ + attrib ** ap = get_attribs(L, 1); if (ap) { attrib * a = a_new(&at_lua_ext); int handle; From ad4f4f59f00372e6db52f6617b9a9d3e6f3e57e1 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 6 Feb 2011 08:11:40 +0100 Subject: [PATCH 044/400] bson attributes can be on anything now --- src/bindings/bind_attrib.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/bindings/bind_attrib.c b/src/bindings/bind_attrib.c index dd1544fbc..3c8ac1487 100644 --- a/src/bindings/bind_attrib.c +++ b/src/bindings/bind_attrib.c @@ -366,6 +366,20 @@ tolua_attriblist_next(lua_State *L) else return 0; /* no more values to return */ } +int +tolua_attrib_get(lua_State * L) { + attrib ** ap = get_attribs(L, 1); + if (ap) { + attrib * a = tolua_get_lua_ext(*ap); + attrib ** attrib_ptr = (attrib**)lua_newuserdata(L, sizeof(attrib *)); + luaL_getmetatable(L, "attrib"); + lua_setmetatable(L, -2); + *attrib_ptr = a; + lua_pushcclosure(L, tolua_attriblist_next, 1); + return 1; + } + else return 0; +} void tolua_attrib_open(lua_State* L) @@ -381,6 +395,7 @@ tolua_attrib_open(lua_State* L) tolua_beginmodule(L, TOLUA_CAST "attrib"); { tolua_function(L, TOLUA_CAST "create", &tolua_attrib_create); + tolua_function(L, TOLUA_CAST "get", &tolua_attrib_get); tolua_variable(L, TOLUA_CAST "data", &tolua_attrib_data, NULL); } tolua_endmodule(L); From b07f40c02ec9ee55c69725585011290da66d57ed Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 6 Feb 2011 08:41:14 +0100 Subject: [PATCH 045/400] test the bson functionality, and provide examples for using it --- scripts/tests/common.lua | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index f0d987ada..467dfeb5a 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -885,3 +885,26 @@ function test_bug_1679() assert_true(find_in_report(f, "Die Einheit kann keine weiteren langen Befehle", "cr")) assert_true(find_in_report(f, "entdeckt, dass es keinen Weg nach Westen gibt")) end + +function test_bson() + local r = region.create(0, 0, "mountain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + attrib.create(r, 1) + assert_equal(attrib.get(r)().data, 1) + attrib.create(u, 3) + assert_equal(attrib.get(u)().data, 3) + attrib.create(f, 5) + assert_equal(attrib.get(f)().data, 5) +end + +function test_bson_with_multiple_attribs() + local r = region.create(0, 0, "mountain") + attrib.create(r, { a=1}) + attrib.create(r, { a=5}) + local total = 0 + for a in attrib.get(r) do + total = total + a.data.a; + end + assert_equal(6, total) +end From f5b4b1ff994fef0beb9895048079c18c40c84efe Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 15 Feb 2011 23:06:26 -0800 Subject: [PATCH 046/400] Merged a bugfix for omniscient factions from stm. --- src/gamecode/creport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index edef15247..065fd78de 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -885,7 +885,7 @@ cr_output_unit(FILE * F, const region * r, } /* items */ pr = 0; - if (f == u->faction || omniscient(u->faction)) { + if (f == u->faction || omniscient(f)) { show = u->items; } else if (itemcloak==false && mode>=see_unit && !(a_fshidden && a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) From 42c5331f1bf5cbc9a9fc7f34968c867ecbda3d79 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 15 Feb 2011 23:28:09 -0800 Subject: [PATCH 047/400] http://bugs.eressea.de/view.php?id=1833 There's a pretty bad problem with watchers in older datafiles. --- src/kernel/save.c | 36 ++++++++++++++++++++++++------------ src/kernel/version.h | 3 ++- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/kernel/save.c b/src/kernel/save.c index 5d43bf6c5..4d0a450a0 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1413,7 +1413,9 @@ readgame(const char * filename, int mode, int backup) n = store->r_int(store); while(--n >= 0) { int id = store->r_int(store); + variant fno; plane *pl = getplanebyid(id); + if (pl==NULL) { pl = calloc(1, sizeof(plane)); } else { @@ -1428,18 +1430,28 @@ readgame(const char * filename, int mode, int backup) pl->flags = store->r_int(store); /* read watchers */ - store->r_str_buf(store, token, sizeof(token)); - while (strcmp(token, "end")!=0) { - watcher * w = calloc(sizeof(watcher),1); - variant fno; - fno.i = atoi36(token); - w->mode = (unsigned char)store->r_int(store); - w->next = pl->watchers; - pl->watchers = w; - ur_add(fno, &w->faction, resolve_faction); - store->r_str_buf(store, token, sizeof(token)); + if (store->versionr_tok_buf(store, rname, sizeof(rname)); + if (strcmp(rname, "end")==0) { + break; /* this is most likely the end of the list */ + } else { + log_error(("This datafile contains watchers, but we are unable to read them\n")); + } + } + } else { + fno = read_faction_reference(store); + while (fno.i) { + watcher * w = (watcher *)malloc(sizeof(watcher)); + ur_add(fno, &w->faction, resolve_faction); + w->mode = (unsigned char)store->r_int(store); + w->next = pl->watchers; + pl->watchers = w; + fno = read_faction_reference(store); + } } - a_read(store, &pl->attribs, pl); addlist(&planes, pl); } @@ -1715,7 +1727,7 @@ writegame(const char *filename, int mode) } w = w->next; } - store->w_tok(store, "end"); + write_faction_reference(NULL, store); /* mark the end of the list */ a_write(store, pl->attribs, pl); store->w_brk(store); } diff --git a/src/kernel/version.h b/src/kernel/version.h index a07ea3e52..e1a792b7d 100644 --- a/src/kernel/version.h +++ b/src/kernel/version.h @@ -66,6 +66,7 @@ #define MOURNING_VERSION 335 /* mourning peasants */ #define FOSS_VERSION 336 /* the open source release */ #define OWNER_2_VERSION 337 /* region owners contain an alliance */ +#define FIX_WATCHERS_VERSION 338 /* fixed storage of watchers */ #define MIN_VERSION CURSETYPE_VERSION /* minimal datafile we support */ -#define RELEASE_VERSION OWNER_2_VERSION /* current datafile */ +#define RELEASE_VERSION FIX_WATCHERS_VERSION /* current datafile */ From 8f327f716567d5dc3839907162a1ae00b68e5ed6 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 15 Feb 2011 23:31:22 -0800 Subject: [PATCH 048/400] array-indexing error in error message discovered by stm. --- src/bindings/bind_attrib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bindings/bind_attrib.c b/src/bindings/bind_attrib.c index 3c8ac1487..f1688750d 100644 --- a/src/bindings/bind_attrib.c +++ b/src/bindings/bind_attrib.c @@ -244,7 +244,7 @@ read_ext_i(lua_State * L, bson_iterator * it, bson_type type) else lua_pushnil(L); } else { - log_error(("unknown oid %d %d %d\n", oid->ints[0], oid->ints[3], oid->ints[2])); + log_error(("unknown oid %d %d %d\n", oid->ints[0], oid->ints[1], oid->ints[2])); lua_pushnil(L); } } From 204924c35a67a79ed5c9d7b0f105a4ab8d569281 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 15 Feb 2011 23:34:00 -0800 Subject: [PATCH 049/400] http://bugs.eressea.de/view.php?id=1810 Only rich peasants were dying during the plague (and paying for it) --- src/kernel/config.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/kernel/config.c b/src/kernel/config.c index 294827f51..62c2de98a 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -2608,7 +2608,6 @@ plagues(region * r, boolean ismagic) for (i = dead; i != 0; i--) { if (rng_double() < PLAGUE_HEALCHANCE && rmoney(r) >= PLAGUE_HEALCOST) { rsetmoney(r, rmoney(r) - PLAGUE_HEALCOST); - } else { --dead; } } From d033e7156c6e859b7009818916da6ab3e66eda7d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 19 Feb 2011 06:13:24 -0800 Subject: [PATCH 050/400] Simple tests for persistent attributes and a fix. --- scripts/tests/bson.lua | 30 ++++++++++++++++++++++++++++++ scripts/tests/common.lua | 9 ++++++--- scripts/tests/spells.lua | 2 +- src/bindings/bind_attrib.c | 6 +++--- 4 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 scripts/tests/bson.lua diff --git a/scripts/tests/bson.lua b/scripts/tests/bson.lua new file mode 100644 index 000000000..d655c4b55 --- /dev/null +++ b/scripts/tests/bson.lua @@ -0,0 +1,30 @@ +require "lunit" + +module("tests.bson", package.seeall, lunit.testcase) + +function setup() + free_game() +end + +function test_bson_create() + local a = attrib.create("global", 12) + assert_not_equal(nil, a) + for a in attrib.get("global") do + assert_equal(a.data, 12) + end +end + +function test_bson_readwrite() + local r = region.create(0, 0, "mountain") + attrib.create(r, 42) + write_game("test_read_write.dat") + free_game() + r = get_region(0, 0) + assert_equal(nil, r) + read_game("test_read_write.dat") + r = get_region(0, 0) + assert_not_equal(nil, r) + for a in attrib.get(r) do + assert_equal(a.data, 42) + end +end diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 467dfeb5a..f15eb8164 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -25,7 +25,7 @@ local function two_factions() return f1, f2 end -module( "common", package.seeall, lunit.testcase ) +module("tests.common", package.seeall, lunit.testcase) function setup() free_game() @@ -760,7 +760,7 @@ function test_walk_and_carry_the_cart() assert_equal(1, u.region.x) end -module( "report", package.seeall, lunit.testcase ) +module("tests.report", package.seeall, lunit.testcase) function setup() free_game() @@ -820,7 +820,7 @@ function test_coordinates_noname_plane() assert_true(find_in_report(f, r.name .. " %(0,0%), Berg")) end -module( "parser", package.seeall, lunit.testcase ) +module("tests.parser", package.seeall, lunit.testcase) function setup() free_game() @@ -890,6 +890,9 @@ function test_bson() local r = region.create(0, 0, "mountain") local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r, 1) + assert_not_equal(nil, u) + assert_not_equal(nil, r) + assert_not_equal(nil, f) attrib.create(r, 1) assert_equal(attrib.get(r)().data, 1) attrib.create(u, 3) diff --git a/scripts/tests/spells.lua b/scripts/tests/spells.lua index e71935aa8..141a6d8bd 100644 --- a/scripts/tests/spells.lua +++ b/scripts/tests/spells.lua @@ -1,6 +1,6 @@ require "lunit" -module( "spells", package.seeall, lunit.testcase ) +module("tests.spells", package.seeall, lunit.testcase) function setup() free_game() diff --git a/src/bindings/bind_attrib.c b/src/bindings/bind_attrib.c index f1688750d..54821bfe9 100644 --- a/src/bindings/bind_attrib.c +++ b/src/bindings/bind_attrib.c @@ -300,13 +300,13 @@ get_attribs(lua_State * L, int idx) { if (tolua_isusertype(L, idx, TOLUA_CAST "unit", 0, &tolua_err)) { unit * u = (unit *)tolua_tousertype(L, idx, 0); - ap = &u->attribs; + if (u) ap = &u->attribs; } else if (tolua_isusertype(L, idx, TOLUA_CAST "region", 0, &tolua_err)) { region * r = (region *)tolua_tousertype(L, idx, 0); - ap = &r->attribs; + if (r) ap = &r->attribs; } else if (tolua_isusertype(L, idx, TOLUA_CAST "faction", 0, &tolua_err)) { faction * f = (faction *)tolua_tousertype(L, idx, 0); - ap = &f->attribs; + if (f) ap = &f->attribs; } else if (lua_isstring(L, idx)) { const char * str = tolua_tostring(L, idx, NULL); if (str && strcmp(str, "global")==0) { From e8d00d874427d6c35513e473df3c001b9a128fd0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 19 Feb 2011 06:15:15 -0800 Subject: [PATCH 051/400] test error conditions fixed by the last commit. --- scripts/tests/bson.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/tests/bson.lua b/scripts/tests/bson.lua index d655c4b55..35b08051c 100644 --- a/scripts/tests/bson.lua +++ b/scripts/tests/bson.lua @@ -14,6 +14,13 @@ function test_bson_create() end end +function test_illegal_arg() + local a = attrib.create(nil, 42) + assert_equal(nil, a) + a = attrib.create("fred", 42) + assert_equal(nil, a) +end + function test_bson_readwrite() local r = region.create(0, 0, "mountain") attrib.create(r, 42) From 0adf7899ddf51c781a6287298d6b84e028e63c39 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 21 Feb 2011 22:00:03 -0800 Subject: [PATCH 052/400] cleaning up the lists functionality a bit. I have plans. --- src/kernel/alliance.c | 1 - src/kernel/battle.c | 7 ++- src/kernel/building.c | 5 +- src/kernel/config.c | 3 +- src/kernel/faction.h | 10 ++-- src/kernel/order.c | 5 ++ src/kernel/order.h | 2 + src/util/lists.c | 118 +++++++++++++++++++----------------------- src/util/lists.h | 13 ----- 9 files changed, 73 insertions(+), 91 deletions(-) diff --git a/src/kernel/alliance.c b/src/kernel/alliance.c index cec763793..cfacb00c2 100644 --- a/src/kernel/alliance.c +++ b/src/kernel/alliance.c @@ -31,7 +31,6 @@ without prior permission by the authors of Eressea. /* util includes */ #include #include -#include #include #include #include diff --git a/src/kernel/battle.c b/src/kernel/battle.c index db0284ec6..0aaa0e840 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -58,7 +58,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include #include #include #include @@ -4175,7 +4174,11 @@ battle_stats(FILE * F, battle * b) for (stat=stats;stat!=NULL;stat=stat->next) { fprintf(F, "%s %u : %u\n", stat->wtype?stat->wtype->itype->rtype->_name[0]:"none", stat->level, stat->number); } - freelist(stats); + while(stats) { + stat_info * stat = stats; + stats = stat->next; + free(stat); + } } } diff --git a/src/kernel/building.c b/src/kernel/building.c index 3b2553812..0ab58de70 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -38,7 +38,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include #include #include #include @@ -454,6 +453,7 @@ add_buildinglist(building_list **blist, building *b) building * new_building(const struct building_type * btype, region * r, const struct locale * lang) { + building ** bptr = &r->buildings; building *b = (building *) calloc(1, sizeof(building)); static boolean init_lighthouse = false; static const struct building_type * bt_lighthouse = 0; @@ -469,7 +469,8 @@ new_building(const struct building_type * btype, region * r, const struct locale b->type = btype; b->region = r; - addlist(&r->buildings, b); + while (*bptr) bptr=&(*bptr)->next; + *bptr = b; if (b->type==bt_lighthouse) { r->flags |= RF_LIGHTHOUSE; diff --git a/src/kernel/config.c b/src/kernel/config.c index 62c2de98a..d0885efd2 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -729,7 +729,7 @@ verify_data(void) if (verbosity>=1) puts(" - Überprüfe Daten auf Korrektheit..."); - list_foreach(faction, factions, f) { + for (f=factions; f; f=f->next) { mage = 0; alchemist = 0; for (u=f->units;u;u=u->nextF) { @@ -751,7 +751,6 @@ verify_data(void) if (alchemist > 3) log_error(("Partei %s hat %d Alchemisten.\n", factionid(f), alchemist)); } - list_next(f); #endif } diff --git a/src/kernel/faction.h b/src/kernel/faction.h index 910929937..198af7d88 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -75,13 +75,13 @@ typedef struct faction { int max_spelllevel; struct spell_list * spellbook; const struct locale * locale; - int lastorders; /* enno: short? */ - int age; /* enno: short? */ + int lastorders; + int age; struct ursprung *ursprung; const struct race * race; magic_t magiegebiet; int newbies; - int num_people; /* Anzahl Personen ohne Monster */ + int num_people; /* Anzahl Personen ohne Monster */ int num_total; /* Anzahl Personen mit Monstern */ int options; int no_units; @@ -114,8 +114,8 @@ typedef struct faction { extern struct faction *factions; typedef struct faction_list { - struct faction_list * next; - struct faction * data; + struct faction_list * next; + struct faction * data; } faction_list; void flist_add(struct faction_list ** flist, struct faction * sf); diff --git a/src/kernel/order.c b/src/kernel/order.c index e1513a01f..ad05af80a 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -609,3 +609,8 @@ write_order(const order * ord, char * buffer, size_t size) } return buffer; } + +void push_order(order ** ordp, order * ord) { + while (*ordp) ordp=&(*ordp)->next; + *ordp = ord; +} \ No newline at end of file diff --git a/src/kernel/order.h b/src/kernel/order.h index f840ad7fc..7b229644d 100644 --- a/src/kernel/order.h +++ b/src/kernel/order.h @@ -44,6 +44,8 @@ extern order * copy_order(const order * ord); extern void free_order(order * ord); extern void free_orders(order ** olist); +extern void push_order(struct order ** olist, struct order * ord); + /* access functions for orders */ extern keyword_t get_keyword(const order * ord); extern void set_order(order ** destp, order * src); diff --git a/src/util/lists.c b/src/util/lists.c index cff4b287c..4c4173cb5 100644 --- a/src/util/lists.c +++ b/src/util/lists.c @@ -22,64 +22,69 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include "lists.h" +typedef struct void_list { + struct void_list * next; + void * data; +} void_list; + void addlist(void *l1, void *p1) { - /* add entry p to the end of list l */ + /* add entry p to the end of list l */ - void_list **l; - void_list *p, *q; + void_list **l; + void_list *p, *q; - l = (void_list **)l1; - p = (void_list *)p1; - assert(p->next == 0); + l = (void_list **)l1; + p = (void_list *)p1; + assert(p->next == 0); - if (*l) { - for (q = *l; q->next; q = q->next) - assert(q); - q->next = p; - } else - *l = p; + if (*l) { + for (q = *l; q->next; q = q->next) + assert(q); + q->next = p; + } else + *l = p; } -void +static void choplist(void * a, void * b) { - void_list **l = (void_list**)a, *p = (void_list*)b; - /* remove entry p from list l - when called, a pointer to p must be - * kept in order to use (and free) p; if omitted, this will be a - * memory leak */ + void_list **l = (void_list**)a, *p = (void_list*)b; + /* remove entry p from list l - when called, a pointer to p must be + * kept in order to use (and free) p; if omitted, this will be a + * memory leak */ - void_list **q; + void_list **q; - for (q = l; *q; q = &((*q)->next)) { - if (*q == p) { - *q = p->next; - p->next = 0; - break; - } - } + for (q = l; *q; q = &((*q)->next)) { + if (*q == p) { + *q = p->next; + p->next = 0; + break; + } + } } void translist(void *l1, void *l2, void *p) { - /* remove entry p from list l1 and add it at the end of list l2 */ + /* remove entry p from list l1 and add it at the end of list l2 */ - choplist(l1, p); - addlist(l2, p); + choplist(l1, p); + addlist(l2, p); } void insertlist(void_list ** l, void_list * p) { - /* insert entry p at the beginning of list l */ + /* insert entry p at the beginning of list l */ - p->next = *l; - *l = p; + p->next = *l; + *l = p; } @@ -87,57 +92,38 @@ void removelist(void *l, void *p) { - /* remove entry p from list l; free p */ + /* remove entry p from list l; free p */ - choplist(l, p); - free(p); + choplist(l, p); + free(p); } void freelist(void *p1) { - /* remove all entries following and including entry p from a listlist */ + /* remove all entries following and including entry p from a listlist */ - void_list *p, *p2; + void_list *p, *p2; - p = (void_list *)p1; + p = (void_list *)p1; - while (p) { - p2 = p->next; - free(p); - p = p2; - } + while (p) { + p2 = p->next; + free(p); + p = p2; + } } unsigned int listlen(void *l) { - /* count entries p in list l */ + /* count entries p in list l */ - unsigned int i; - void_list *p; + unsigned int i; + void_list *p; - for (p = (void_list *)l, i = 0; p; p = p->next, i++); - return i; + for (p = (void_list *)l, i = 0; p; p = p->next, i++); + return i; } - -/* Hilfsfunktion, um das Debugging zu erleichtern. Statt print - * (cast)foo->next->next->next->next nur noch - * print (cast)listelem(foo, 3) */ - -void * -listelem(void *l, int n) -{ - int i=0; - - while(i < n && l != NULL) { - l = ((void_list *)l)->next; - i++; - } - - return l; -} - - diff --git a/src/util/lists.h b/src/util/lists.h index 588cc4878..848831817 100644 --- a/src/util/lists.h +++ b/src/util/lists.h @@ -24,17 +24,7 @@ extern "C" { #include -typedef struct void_list { - struct void_list * next; - void * data; -} void_list; - -#define list_foreach(type, list, item) item=list; while (item!=NULL) { type* __next__=item->next; -#define list_continue(item) { item=__next__; continue; } -#define list_next(item) item=__next__; } - void addlist(void *l1, void *p1); -void choplist(void * l, void * p); void translist(void *l1, void *l2, void *p); #ifndef MALLOCDBG void freelist(void *p1); @@ -45,9 +35,6 @@ void removelist(void *l, void *p); #endif unsigned int listlen(void *l); -#define addlist2(l, p) (*l = p, l = &p->next) - -void *listelem(void *l, int n); #ifdef __cplusplus } From 1cae5e22834e299b993e902320012703c9315070 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 23 Feb 2011 22:18:58 -0800 Subject: [PATCH 053/400] Added quicklist, a linked list with better cache characteristics. --- src/build/util.c | 1 + src/util.vcxproj | 2 + src/util.vcxproj.filters | 6 ++ src/util/quicklist.c | 115 +++++++++++++++++++++++++++++++++++++++ src/util/quicklist.h | 35 ++++++++++++ 5 files changed, 159 insertions(+) create mode 100644 src/util/quicklist.c create mode 100644 src/util/quicklist.h diff --git a/src/build/util.c b/src/build/util.c index dfae8d012..c9a6897aa 100644 --- a/src/build/util.c +++ b/src/build/util.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include diff --git a/src/util.vcxproj b/src/util.vcxproj index 6c774d665..b744abb18 100644 --- a/src/util.vcxproj +++ b/src/util.vcxproj @@ -109,6 +109,7 @@ + @@ -145,6 +146,7 @@ + diff --git a/src/util.vcxproj.filters b/src/util.vcxproj.filters index 237444227..6d6e644bf 100644 --- a/src/util.vcxproj.filters +++ b/src/util.vcxproj.filters @@ -107,6 +107,9 @@ Header Files + + Header Files + @@ -199,5 +202,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/src/util/quicklist.c b/src/util/quicklist.c new file mode 100644 index 000000000..729d2ec37 --- /dev/null +++ b/src/util/quicklist.c @@ -0,0 +1,115 @@ +/* +Copyright (c) 2010-2011, Enno Rehling + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include "quicklist.h" +#include +#include +#include + +#define QL_MAXSIZE 14 /* total struct is 64 bytes */ +#define QL_LIMIT 8 + +typedef struct quicklist { + struct quicklist * next; + int num_elements; + void * elements[QL_MAXSIZE]; +} quicklist; + + +void * ql_get(quicklist * ql, int index) { + return (ql && indexnum_elements)?ql->elements[index]:ql_get(ql->next, index-ql->num_elements); +} + +int ql_length(const quicklist * ql) { + return ql?ql->num_elements+ql_length(ql->next):0; +} + +void ql_push(quicklist ** qlp, void * data) { + quicklist * ql = 0; + while(*qlp && ((*qlp)->next || (*qlp)->num_elements==QL_MAXSIZE)) { + qlp = &(*qlp)->next; + } + if (!*qlp) { + ql = malloc(sizeof(quicklist)); + ql->num_elements = 0; + ql->next = 0; + *qlp = ql; + } else { + ql = *qlp; + } + ql->elements[ql->num_elements++] = data; +} + +int ql_delete(quicklist ** qlp, int index) { + quicklist * ql = *qlp; + if (index<0) return EINVAL; + if (ql && index>=ql->num_elements) { + return ql_delete(&ql->next, index-ql->num_elements); + } else if (ql) { + if (index+1num_elements) { + memmove(ql->elements+index, ql->elements+index+1, (ql->num_elements-index-1)*sizeof(void*)); + } + --ql->num_elements; + if (ql->num_elements==0) { + *qlp = ql->next; + free(ql); + } else if (ql->next && ql->num_elementsnext; + if (ql->num_elements+qn->num_elements>QL_MAXSIZE) { + memcpy(ql->elements+ql->num_elements, qn->elements, sizeof(void*)); + --qn->num_elements; + ++ql->num_elements; + memmove(qn->elements, qn->elements+1, qn->num_elements*sizeof(void*)); + } else { + memcpy(ql->elements+ql->num_elements, qn->elements, qn->num_elements*sizeof(void*)); + ql->num_elements += qn->num_elements; + ql->next = qn->next; + free(qn); + } + } + } + return 0; +} + +int ql_insert(quicklist ** qlp, int index, void * data) { + quicklist * ql = *qlp; + if (ql) { + if (index>=QL_MAXSIZE) { + return ql_insert(&ql->next, index-ql->num_elements, data); + } else if (ql->num_elementselements+index+1, ql->elements+index, (ql->num_elements-index)*sizeof(void*)); + ql->elements[index]=data; + ++ql->num_elements; + } else { + quicklist * qn = malloc(sizeof(quicklist)); + qn->next = ql->next; + ql->next = qn; + qn->num_elements = QL_LIMIT; + ql->num_elements -= QL_LIMIT; + memcpy(qn->elements, ql->elements+ql->num_elements-QL_LIMIT, QL_LIMIT*sizeof(void*)); + if (index<=ql->num_elements) { + return ql_insert(qlp, index, data); + } else { + return ql_insert(&ql->next, index-ql->num_elements, data); + } + } + } else if (index==0) { + ql_push(qlp, data); + } else { + return EINVAL; + } + return 0; +} diff --git a/src/util/quicklist.h b/src/util/quicklist.h new file mode 100644 index 000000000..d77ebcf94 --- /dev/null +++ b/src/util/quicklist.h @@ -0,0 +1,35 @@ +/* +Copyright (c) 2010-2011, Enno Rehling + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef _QUICKLIST_H +#define _QUICKLIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* see http://en.wikipedia.org/wiki/Unrolled_linked_list */ +struct quicklist; +void * ql_get(struct quicklist * ql, int index); +int ql_length(const struct quicklist * ql); +void ql_push(struct quicklist ** qlp, void * data); +int ql_delete(struct quicklist ** qlp, int index); +int ql_insert(struct quicklist ** qlp, int index, void * data); + +#ifdef __cplusplus +} +#endif +#endif From 16d86413d52ee3dd0455fb90d83126ef8db7d594 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 23 Feb 2011 23:22:31 -0800 Subject: [PATCH 054/400] add tests for quicklist. Fix the inevitable bug. --- src/util/quicklist.c | 34 ++++++++++++++- src/util/quicklist.h | 6 ++- src/util/quicklist_test.c | 91 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 3 deletions(-) create mode 100644 src/util/quicklist_test.c diff --git a/src/util/quicklist.c b/src/util/quicklist.c index 729d2ec37..11f446ba2 100644 --- a/src/util/quicklist.c +++ b/src/util/quicklist.c @@ -99,7 +99,7 @@ int ql_insert(quicklist ** qlp, int index, void * data) { ql->next = qn; qn->num_elements = QL_LIMIT; ql->num_elements -= QL_LIMIT; - memcpy(qn->elements, ql->elements+ql->num_elements-QL_LIMIT, QL_LIMIT*sizeof(void*)); + memcpy(qn->elements, ql->elements+ql->num_elements, QL_LIMIT*sizeof(void*)); if (index<=ql->num_elements) { return ql_insert(qlp, index, data); } else { @@ -113,3 +113,35 @@ int ql_insert(quicklist ** qlp, int index, void * data) { } return 0; } + +void ql_foreach(struct quicklist * ql, void (*cb)(void *)) +{ + for (;ql;ql=ql->next) { + int i; + for (i=0;i!=ql->num_elements;++i) { + cb(ql->elements[i]); + } + } +} + +int ql_advance(struct quicklist ** iterator, int * index, int stride) +{ + quicklist * ql = *iterator; + int i = *index; + if (!ql || i<0 || stride<0) { + return ERANGE; + } else if (i + stridenum_elements) { + *index = i + stride; + return 0; + } else { + *index = i - ql->num_elements + stride; + *iterator = ql->next; + return ql_advance(iterator, index, 0); + } +} + +void ql_free(struct quicklist * ql) +{ + if (ql->next) ql_free(ql->next); + free(ql); +} diff --git a/src/util/quicklist.h b/src/util/quicklist.h index d77ebcf94..89fc95cf7 100644 --- a/src/util/quicklist.h +++ b/src/util/quicklist.h @@ -22,13 +22,15 @@ extern "C" { #endif /* see http://en.wikipedia.org/wiki/Unrolled_linked_list */ -struct quicklist; +typedef struct quicklist quicklist; void * ql_get(struct quicklist * ql, int index); int ql_length(const struct quicklist * ql); void ql_push(struct quicklist ** qlp, void * data); int ql_delete(struct quicklist ** qlp, int index); int ql_insert(struct quicklist ** qlp, int index, void * data); - +void ql_foreach(struct quicklist * ql, void (*cb)(void *)); +int ql_advance(struct quicklist ** iterator, int * index, int stride); +void ql_free(struct quicklist * ql); #ifdef __cplusplus } #endif diff --git a/src/util/quicklist_test.c b/src/util/quicklist_test.c new file mode 100644 index 000000000..5125a9b37 --- /dev/null +++ b/src/util/quicklist_test.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include "quicklist.h" + +static const char * hello = "Hello World"; + +static void test_insert(CuTest * tc) { + struct quicklist * ql = NULL; + int i; + for (i=0;i!=32;++i) { + CuAssertIntEquals(tc, i, ql_length(ql)); + ql_insert(&ql, 0, (void*)i); + } + for (i=0;i!=32;++i) { + CuAssertIntEquals(tc, 31-i, (int)ql_get(ql, i)); + } +} + +static void test_advance(CuTest * tc) { + struct quicklist * ql = NULL, *qli; + int i, n = 31; + for (i=0;i!=32;++i) { + ql_insert(&ql, 0, (void*)i); + } + for (i=0,qli=ql;qli;ql_advance(&qli, &i, 1),n--) { + int g = (int)ql_get(qli, i); + CuAssertIntEquals(tc, n, g); + } +} + +static void test_push(CuTest * tc) { + struct quicklist * ql = NULL; + CuAssertIntEquals(tc, 0, ql_length(ql)); + ql_push(&ql, (void*)hello); + CuAssertIntEquals(tc, 1, ql_length(ql)); + CuAssertStrEquals(tc, "Hello World", (const char *)ql_get(ql, 0)); + ql_delete(&ql, 0); + CuAssertPtrEquals(tc, 0, ql); +} + +static void test_delete_edgecases(CuTest * tc) { + struct quicklist * ql = NULL; + ql_delete(&ql, 0); + CuAssertPtrEquals(tc, 0, ql); + ql_push(&ql, (void*)hello); + ql_delete(&ql, -1); + ql_delete(&ql, 32); + CuAssertIntEquals(tc, 1, ql_length(ql)); +} + +static void test_insert_many(CuTest * tc) { + struct quicklist * ql = NULL; + int i; + for (i=0;i!=32;++i) { + ql_push(&ql, (void*)i); + } + for (i=0;i!=32;++i) { + CuAssertIntEquals(tc, 32-i, ql_length(ql)); + CuAssertIntEquals(tc, i, (int)ql_get(ql, 0)); + CuAssertIntEquals(tc, 31, (int)ql_get(ql, ql_length(ql)-1)); + ql_delete(&ql, 0); + } + CuAssertPtrEquals(tc, 0, ql); +} + +static void test_delete_rand(CuTest * tc) { + struct quicklist * ql = NULL; + int i; + for (i=0;i!=32;++i) { + ql_push(&ql, (void*)i); + } + CuAssertIntEquals(tc, 32, ql_length(ql)); + ql_delete(&ql, 0); + CuAssertIntEquals(tc, 1, (int)ql_get(ql, 0)); + CuAssertIntEquals(tc, 31, ql_length(ql)); + ql_delete(&ql, 30); + CuAssertIntEquals(tc, 30, ql_length(ql)); +} + +CuSuite* get_quicklist_suite(void) +{ + CuSuite* suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_advance); + SUITE_ADD_TEST(suite, test_push); + SUITE_ADD_TEST(suite, test_insert); + SUITE_ADD_TEST(suite, test_insert_many); + SUITE_ADD_TEST(suite, test_delete_rand); + SUITE_ADD_TEST(suite, test_delete_edgecases); + return suite; +} From d479075c531d25ae4c10c521cfe320fed6cee0c3 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 23 Feb 2011 23:23:32 -0800 Subject: [PATCH 055/400] Testing util is no longer such an include-weirdness. --- src/gamecode/market.c | 57 +++++++++++++++++++--------------------- src/tests.c | 5 +++- src/util.vcxproj | 5 ++-- src/util.vcxproj.filters | 3 +++ src/util/base36.c | 4 --- src/util/base36_test.c | 3 +++ 6 files changed, 39 insertions(+), 38 deletions(-) diff --git a/src/gamecode/market.c b/src/gamecode/market.c index 34d13172e..2f0f3ba2c 100644 --- a/src/gamecode/market.c +++ b/src/gamecode/market.c @@ -17,6 +17,7 @@ without prior permission by the authors of Eressea. #include #include +#include #include #include @@ -89,7 +90,7 @@ static int rc_herb_trade(const struct race * rc) void do_markets(void) { - unit_list * traders = 0; + quicklist * traders = 0; unit * markets[MAX_MARKETS]; region * r; for (r=regions;r;r=r->next) { @@ -119,11 +120,8 @@ void do_markets(void) item * items; attrib * a = a_find(u->attribs, &at_market); if (a==NULL) { - unit_list * ulist = malloc(sizeof(unit_list)); a = a_add(&u->attribs, a_new(&at_market)); - ulist->next = traders; - ulist->data = u; - traders = ulist; + ql_push(&traders, u); } items = (item *)a->data.v; i_change(&items, lux, 1); @@ -136,11 +134,8 @@ void do_markets(void) item * items; attrib * a = a_find(u->attribs, &at_market); if (a==NULL) { - unit_list * ulist = malloc(sizeof(unit_list)); a = a_add(&u->attribs, a_new(&at_market)); - ulist->next = traders; - ulist->data = u; - traders = ulist; + ql_push(&traders, u); } items = (item *)a->data.v; i_change(&items, herb, 1); @@ -152,33 +147,35 @@ void do_markets(void) } } - while (traders) { - unit_list * trade = traders; - unit * u = trade->data; - attrib * a = a_find(u->attribs, &at_market); - item * items = a->data.v; + if (traders) { + quicklist * qliter = traders; + int qli = 0; + for (qli=0;qliter;ql_advance(&qliter, &qli, 1)) { + unit * u = (unit *)ql_get(qliter, qli); + attrib * a = a_find(u->attribs, &at_market); + item * items = (item *)a->data.v; - a->data.v = NULL; - while (items) { - item * itm = items; - items = itm->next; + a->data.v = NULL; + while (items) { + item * itm = items; + items = itm->next; - if (itm->number) { - ADDMSG(&u->faction->msgs, msg_message("buyamount", - "unit amount resource", u, itm->number, itm->type->rtype)); - itm->next = NULL; - i_add(&u->items, itm); - } else { - i_free(itm); + if (itm->number) { + ADDMSG(&u->faction->msgs, msg_message("buyamount", + "unit amount resource", u, itm->number, itm->type->rtype)); + itm->next = NULL; + i_add(&u->items, itm); + } else { + i_free(itm); + } } + + a_remove(&u->attribs, a); } - - traders = trade->next; - - a_remove(&u->attribs, a); - free(trade); + ql_free(traders); } } + #ifndef DISABLE_TESTS #include "market_test.c" #endif diff --git a/src/tests.c b/src/tests.c index e47442a22..5a7695c97 100644 --- a/src/tests.c +++ b/src/tests.c @@ -4,7 +4,9 @@ #include #include "tests.h" -CuSuite* get_base36_suite(void); +#include +#include + CuSuite* get_curse_suite(void); CuSuite* get_market_suite(void); CuSuite* get_laws_suite(void); @@ -26,6 +28,7 @@ int RunAllTests(void) { init_resources(); CuSuiteAddSuite(suite, get_base36_suite()); + CuSuiteAddSuite(suite, get_quicklist_suite()); CuSuiteAddSuite(suite, get_curse_suite()); CuSuiteAddSuite(suite, get_market_suite()); CuSuiteAddSuite(suite, get_laws_suite()); diff --git a/src/util.vcxproj b/src/util.vcxproj index b744abb18..02c556a66 100644 --- a/src/util.vcxproj +++ b/src/util.vcxproj @@ -125,9 +125,7 @@ - - true - + @@ -147,6 +145,7 @@ + diff --git a/src/util.vcxproj.filters b/src/util.vcxproj.filters index 6d6e644bf..726f4856e 100644 --- a/src/util.vcxproj.filters +++ b/src/util.vcxproj.filters @@ -205,5 +205,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/src/util/base36.c b/src/util/base36.c index 3c795077a..149d42e24 100644 --- a/src/util/base36.c +++ b/src/util/base36.c @@ -109,7 +109,3 @@ i10toi36(int i) } return r; } - -#ifndef DISABLE_TESTS -#include "base36_test.c" -#endif diff --git a/src/util/base36_test.c b/src/util/base36_test.c index c11847ad7..2658becc1 100644 --- a/src/util/base36_test.c +++ b/src/util/base36_test.c @@ -1,4 +1,7 @@ #include +#include "base36.h" +#include +#include static void test_atoi36(CuTest * tc) { CuAssertIntEquals(tc, 0, atoi36("0")); From 0c2ccf2d209ed1ef726d91b25661540f087771a3 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 23 Feb 2011 23:26:15 -0800 Subject: [PATCH 056/400] We do not require unit_list, quicklists are the future. --- src/bindings/bind_unit.c | 1 - src/kernel/types.h | 1 - src/kernel/unit.c | 23 ----------------------- src/kernel/unit.h | 8 -------- 4 files changed, 33 deletions(-) diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 7084571d8..c7ff2a345 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -946,7 +946,6 @@ tolua_unit_open(lua_State * L) { /* register user types */ tolua_usertype(L, TOLUA_CAST "unit"); - tolua_usertype(L, TOLUA_CAST "unit_list"); tolua_module(L, NULL, 0); tolua_beginmodule(L, NULL); diff --git a/src/kernel/types.h b/src/kernel/types.h index 9c16e63ac..0f558386e 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -66,7 +66,6 @@ struct storage; struct strlist; struct terrain_type; struct unit; -struct unit_list; struct weapon_type; typedef struct ursprung { diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 102f84656..92ab35e3b 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1393,29 +1393,6 @@ free_unit(unit * u) } } - -void -unitlist_clear(struct unit_list **ul) -{ - while (*ul) { - unit_list * rl2 = (*ul)->next; - free(*ul); - *ul = rl2; - } -} - -void -unitlist_insert(struct unit_list **ul, struct unit *u) -{ - unit_list *rl2 = (unit_list*)malloc(sizeof(unit_list)); - - rl2->data = u; - rl2->next = *ul; - - *ul = rl2; -} - - static void createunitid(unit *u, int id) { diff --git a/src/kernel/unit.h b/src/kernel/unit.h index 86af46741..3eb2de3d9 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -110,14 +110,6 @@ typedef struct unit { int wants; /* enno: attribut? */ } unit; -typedef struct unit_list { - struct unit_list * next; - struct unit * data; -} unit_list; - -extern void unitlist_clear(struct unit_list **ul); -extern void unitlist_insert(struct unit_list **ul, struct unit *u); - extern struct attrib_type at_alias; extern struct attrib_type at_siege; extern struct attrib_type at_target; From 372908a9af818bb2618415b9395a819cc3d7fdb1 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 24 Feb 2011 08:29:48 +0100 Subject: [PATCH 057/400] gcc complains about typedefs for the same struct twice --- src/util/quicklist.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/quicklist.c b/src/util/quicklist.c index 11f446ba2..db06108c0 100644 --- a/src/util/quicklist.c +++ b/src/util/quicklist.c @@ -22,11 +22,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define QL_MAXSIZE 14 /* total struct is 64 bytes */ #define QL_LIMIT 8 -typedef struct quicklist { +struct quicklist { struct quicklist * next; int num_elements; void * elements[QL_MAXSIZE]; -} quicklist; +}; void * ql_get(quicklist * ql, int index) { From a538c52bc4f12a9719915856d838f71631d7cac3 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 24 Feb 2011 22:27:04 -0800 Subject: [PATCH 058/400] quicklists can be used as a set of pointers (this will be useful). --- src/util/quicklist.c | 35 ++++++++++++++++++++++++++++++++--- src/util/quicklist.h | 5 ++++- src/util/quicklist_test.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/util/quicklist.c b/src/util/quicklist.c index db06108c0..f5b0bc8bd 100644 --- a/src/util/quicklist.c +++ b/src/util/quicklist.c @@ -29,7 +29,7 @@ struct quicklist { }; -void * ql_get(quicklist * ql, int index) { +void * ql_get(const quicklist * ql, int index) { return (ql && indexnum_elements)?ql->elements[index]:ql_get(ql->next, index-ql->num_elements); } @@ -43,7 +43,7 @@ void ql_push(quicklist ** qlp, void * data) { qlp = &(*qlp)->next; } if (!*qlp) { - ql = malloc(sizeof(quicklist)); + ql = (quicklist *)malloc(sizeof(quicklist)); ql->num_elements = 0; ql->next = 0; *qlp = ql; @@ -94,7 +94,7 @@ int ql_insert(quicklist ** qlp, int index, void * data) { ql->elements[index]=data; ++ql->num_elements; } else { - quicklist * qn = malloc(sizeof(quicklist)); + quicklist * qn = (quicklist *)malloc(sizeof(quicklist)); qn->next = ql->next; ql->next = qn; qn->num_elements = QL_LIMIT; @@ -145,3 +145,32 @@ void ql_free(struct quicklist * ql) if (ql->next) ql_free(ql->next); free(ql); } + +int ql_set_insert(struct quicklist ** qlp, void * data) +{ + if (*qlp) { + quicklist * ql = *qlp; + if (ql->num_elements>0 && ql->elements[ql->num_elements-1] < data) { + if (ql->num_elements==QL_MAXSIZE || (ql->next && ql->next->elements[0]<=data)) { + return ql_set_insert(&ql->next, data); + } else { + ql->elements[ql->num_elements++] = data; + } + return 0; + } else { + int i; + /* TODO: OPT | binary search */ + for (i=0;i!=ql->num_elements;++i) { + if (data < ql->elements[i]) { + ql_insert(qlp, i, data); + return 0; + } + if (data == ql->elements[i]) { + return 1; + } + } + } + } + ql_push(qlp, data); + return 0; +} \ No newline at end of file diff --git a/src/util/quicklist.h b/src/util/quicklist.h index 89fc95cf7..cc7186a31 100644 --- a/src/util/quicklist.h +++ b/src/util/quicklist.h @@ -23,7 +23,7 @@ extern "C" { /* see http://en.wikipedia.org/wiki/Unrolled_linked_list */ typedef struct quicklist quicklist; -void * ql_get(struct quicklist * ql, int index); +void * ql_get(const struct quicklist * ql, int index); int ql_length(const struct quicklist * ql); void ql_push(struct quicklist ** qlp, void * data); int ql_delete(struct quicklist ** qlp, int index); @@ -31,6 +31,9 @@ int ql_insert(struct quicklist ** qlp, int index, void * data); void ql_foreach(struct quicklist * ql, void (*cb)(void *)); int ql_advance(struct quicklist ** iterator, int * index, int stride); void ql_free(struct quicklist * ql); + +/* you can use it as a set (sorted pointers)*/ +int ql_set_insert(struct quicklist ** qlp, void * data); #ifdef __cplusplus } #endif diff --git a/src/util/quicklist_test.c b/src/util/quicklist_test.c index 5125a9b37..bb82afa12 100644 --- a/src/util/quicklist_test.c +++ b/src/util/quicklist_test.c @@ -17,6 +17,33 @@ static void test_insert(CuTest * tc) { } } +static void test_insert_delete_gives_null(CuTest * tc) { + struct quicklist * ql = NULL; + ql_push(&ql, (void*)42); + ql_delete(&ql, 0); + CuAssertPtrEquals(tc, 0, ql); +} + +static void test_set_insert(CuTest * tc) { + struct quicklist * ql = NULL; + int a; + a = ql_set_insert(&ql, (void*)42); + CuAssertIntEquals(tc, 1, ql_length(ql)); + CuAssertIntEquals(tc, 0, a); + a = ql_set_insert(&ql, (void*)43); + CuAssertIntEquals(tc, 2, ql_length(ql)); + CuAssertIntEquals(tc, 0, a); + a = ql_set_insert(&ql, (void*)42); + CuAssertIntEquals(tc, 2, ql_length(ql)); + CuAssertIntEquals(tc, 1, a); + a = ql_set_insert(&ql, (void*)41); + CuAssertIntEquals(tc, 0, a); + CuAssertIntEquals(tc, 3, ql_length(ql)); + CuAssertIntEquals(tc, 41, (int)ql_get(ql, 0)); + CuAssertIntEquals(tc, 42, (int)ql_get(ql, 1)); + CuAssertIntEquals(tc, 43, (int)ql_get(ql, 2)); +} + static void test_advance(CuTest * tc) { struct quicklist * ql = NULL, *qli; int i, n = 31; @@ -84,8 +111,10 @@ CuSuite* get_quicklist_suite(void) SUITE_ADD_TEST(suite, test_advance); SUITE_ADD_TEST(suite, test_push); SUITE_ADD_TEST(suite, test_insert); + SUITE_ADD_TEST(suite, test_insert_delete_gives_null); SUITE_ADD_TEST(suite, test_insert_many); SUITE_ADD_TEST(suite, test_delete_rand); SUITE_ADD_TEST(suite, test_delete_edgecases); + SUITE_ADD_TEST(suite, test_set_insert); return suite; } From 831de3dd559064bb628a553fcd499c8fab5995af Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 24 Feb 2011 22:29:21 -0800 Subject: [PATCH 059/400] the report's address list is now a quicklist. A bit faster perhaps, and less memory? One less reason to have the faction_list struct, at least. --- src/gamecode/creport.c | 12 +++++++----- src/gamecode/report.c | 10 ++++++---- src/gamecode/xmlreport.c | 9 +++++---- src/kernel/reports.c | 29 +++++++++++++++++++++-------- src/kernel/reports.h | 2 +- 5 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index 065fd78de..fbf0af602 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -63,6 +63,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include #include @@ -959,11 +960,12 @@ show_active_spells(const region * r) /* this is a copy of laws.c->find_address output changed. */ static void -cr_find_address(FILE * F, const faction * uf, const faction_list * addresses) +cr_find_address(FILE * F, const faction * uf, quicklist * addresses) { - const faction_list * flist = addresses; - while (flist!=NULL) { - const faction * f = flist->data; + int i = 0; + quicklist * flist = addresses; + while (flist) { + const faction * f = (const faction *)ql_get(flist, i); if (uf!=f) { fprintf(F, "PARTEI %d\n", f->no); fprintf(F, "\"%s\";Parteiname\n", f->name); @@ -974,7 +976,7 @@ cr_find_address(FILE * F, const faction * uf, const faction_list * addresses) fprintf(F, "%d;alliance\n", f->alliance->id); } } - flist = flist->next; + ql_advance(&flist, &i, 1); } } /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ diff --git a/src/gamecode/report.c b/src/gamecode/report.c index 4d9308a41..b32c252b0 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -76,6 +76,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include @@ -1700,15 +1701,16 @@ rpline(FILE * F) } static void -list_address(FILE * F, const faction * uf, const faction_list * seenfactions) +list_address(FILE * F, const faction * uf, quicklist * seenfactions) { - const faction_list *flist = seenfactions; + int qi = 0; + quicklist * flist = seenfactions; centre(F, LOC(uf->locale, "nr_addresses"), false); rnl(F); while (flist!=NULL) { - const faction * f = flist->data; + const faction * f = (const faction *)ql_get(flist, qi); if (!is_monsters(f)) { char buf[8192]; char label = '-'; @@ -1720,7 +1722,7 @@ list_address(FILE * F, const faction * uf, const faction_list * seenfactions) rparagraph(F, buf, 4, 0, label); } - flist = flist->next; + ql_advance(&flist, &qi, 1); } rnl(F); rpline(F); diff --git a/src/gamecode/xmlreport.c b/src/gamecode/xmlreport.c index f428f9417..2c7646895 100644 --- a/src/gamecode/xmlreport.c +++ b/src/gamecode/xmlreport.c @@ -672,7 +672,8 @@ xml_region(report_context * ctx, seen_region * sr) static xmlNodePtr report_root(report_context * ctx) { - const faction_list * address; + int qi; + quicklist * address; region * r = ctx->first, * rend = ctx->last; xml_context* xct = (xml_context*)ctx->userdata; xmlNodePtr node, child, xmlReport = xmlNewNode(NULL, BAD_CAST "atlantis"); @@ -697,9 +698,9 @@ report_root(report_context * ctx) xmlNewTextChild(node, xct->ns_atl, BAD_CAST "time", (xmlChar *)zText); xmlNewTextChild(node, xct->ns_atl, BAD_CAST "turn", (xmlChar *)itoab(turn, 10)); - - for (address=ctx->addresses;address;address=address->next) { - xmlAddChild(xmlReport, xml_faction(ctx, address->data)); + for (qi=0,address=ctx->addresses;address;ql_advance(&address, &qi, 1)) { + faction * f = (faction *)ql_get(address, qi); + xmlAddChild(xmlReport, xml_faction(ctx, f)); } for (;r!=rend;r=r->next) { diff --git a/src/kernel/reports.c b/src/kernel/reports.c index 27f14128a..7cd973a6c 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -51,6 +51,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include /* libc includes */ #include @@ -899,6 +900,15 @@ stealth_modifier(int seen_mode) } } +void transfer_seen(quicklist ** dst, faction_list ** src) { + while (*src) { + faction_list * flist = *src; + ql_set_insert(dst, flist->data); + free(flist); + *src = flist->next; + } +} + static void get_addresses(report_context * ctx) { @@ -906,18 +916,21 @@ get_addresses(report_context * ctx) seen_region * sr = NULL; region *r; const faction * lastf = NULL; - faction_list * flist = ctx->f->seen_factions; + quicklist * flist = 0; + + transfer_seen(&flist, &ctx->f->seen_factions); ctx->f->seen_factions = NULL; /* do not delete it twice */ - flist_add(&flist, ctx->f); + ql_push(&flist, ctx->f); if (f_get_alliance(ctx->f)) { faction_list * member = ctx->f->alliance->members; for (;member;member=member->next) { - flist_add(&flist, member->data); + ql_set_insert(&flist, member->data); } } + /* find the first region that this faction can see */ for (r=ctx->first;sr==NULL && r!=ctx->last;r=r->next) { sr = find_seen(ctx->seen, r); } @@ -931,7 +944,7 @@ get_addresses(report_context * ctx) faction * sf = visible_faction(ctx->f, u); if (lastf!=sf) { if (u->building || u->ship || (stealthmod>INT_MIN && cansee(ctx->f, r, u, stealthmod))) { - flist_add(&flist, sf); + ql_set_insert(&flist, sf); lastf = sf; } } @@ -947,7 +960,7 @@ get_addresses(report_context * ctx) unit * u2 = (unit*)a->data.v; if (u2->faction==ctx->f) { if (cansee_unit(u2, u, stealthmod)) { - flist_add(&flist, sf); + ql_set_insert(&flist, sf); lastf = sf; break; } @@ -965,7 +978,7 @@ get_addresses(report_context * ctx) boolean ballied = sf && sf!=ctx->f && sf!=lastf && !fval(u, UFL_ANON_FACTION) && cansee(ctx->f, r, u, stealthmod); if (ballied || ALLIED(ctx->f, sf)) { - flist_add(&flist, sf); + ql_set_insert(&flist, sf); lastf = sf; } } @@ -978,7 +991,7 @@ get_addresses(report_context * ctx) faction *f2; for (f2 = factions; f2; f2 = f2->next) { if (f2->alliance == ctx->f->alliance) { - flist_add(&flist, f2); + ql_set_insert(&flist, f2); } } } @@ -1393,7 +1406,7 @@ write_reports(faction * f, time_t ltime) if (!gotit) { log_warning(("No report for faction %s!\n", factionid(f))); } - freelist(ctx.addresses); + ql_free(ctx.addresses); seen_done(ctx.seen); return 0; } diff --git a/src/kernel/reports.h b/src/kernel/reports.h index f4082f91c..d97e204df 100644 --- a/src/kernel/reports.h +++ b/src/kernel/reports.h @@ -83,7 +83,7 @@ extern const char * visibility[]; typedef struct report_context { struct faction * f; - struct faction_list * addresses; + struct quicklist * addresses; struct seen_region ** seen; struct region * first, * last; void * userdata; From d2994d816a44e6b4d818bd55da84be7662ba93df Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 24 Feb 2011 23:25:54 -0800 Subject: [PATCH 060/400] the oceannames has never been used. git history does not forget, so deleting is fine. --- src/kernel.vcproj | 8 --- src/kernel.vcxproj | 2 - src/kernel.vcxproj.filters | 6 -- src/kernel/save.c | 2 +- src/modules/oceannames.c | 126 ------------------------------------- src/modules/oceannames.h | 32 ---------- 6 files changed, 1 insertion(+), 175 deletions(-) delete mode 100644 src/modules/oceannames.c delete mode 100644 src/modules/oceannames.h diff --git a/src/kernel.vcproj b/src/kernel.vcproj index 1ee01709a..faa1240f4 100644 --- a/src/kernel.vcproj +++ b/src/kernel.vcproj @@ -711,14 +711,6 @@ RelativePath=".\modules\museum.h" > - - - - diff --git a/src/kernel.vcxproj b/src/kernel.vcxproj index cc64219c6..b6beb08b2 100644 --- a/src/kernel.vcxproj +++ b/src/kernel.vcxproj @@ -152,7 +152,6 @@ - @@ -256,7 +255,6 @@ - diff --git a/src/kernel.vcxproj.filters b/src/kernel.vcxproj.filters index 38fd989f5..1eba9e2a2 100644 --- a/src/kernel.vcxproj.filters +++ b/src/kernel.vcxproj.filters @@ -213,9 +213,6 @@ modules - - modules - modules @@ -510,9 +507,6 @@ modules - - modules - modules diff --git a/src/kernel/save.c b/src/kernel/save.c index 4d0a450a0..ca140d313 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1178,7 +1178,7 @@ readfaction(struct storage * store) if (allianceid>0) f->alliance = findalliance(allianceid); if (f->alliance) { alliance * al = f->alliance; - faction_list * flist = malloc(sizeof(faction_list)); + faction_list * flist = (faction_list *)malloc(sizeof(faction_list)); if (al->flags&ALF_NON_ALLIED) { assert(!al->members || !"non-allied dummy-alliance has more than one member"); } diff --git a/src/modules/oceannames.c b/src/modules/oceannames.c deleted file mode 100644 index b52eddec3..000000000 --- a/src/modules/oceannames.c +++ /dev/null @@ -1,126 +0,0 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "oceannames.h" - -/* kernel includes */ -#include -#include - -/* util includes */ -#include - -/* libc includes */ -#include -#include - -typedef struct namehash { - struct namehash * next; - const char * name; -} namehash; - -#define NMAXHASH 1023 -namehash names[NMAXHASH]; - -void nhash(const char * name); - -typedef struct oceanname { - struct oceanname * next; - struct faction_list * factions; - const char * name; -} oceanname; - -static void -free_names(attrib * a) -{ - oceanname * data = (oceanname*)a->data.v; - while (a->data.v) { - a->data.v = data->next; - free(data); - } -} - -struct attrib_type at_oceanname = { "names", NULL, free_names, NULL/*, write_names, read_names, ATF_UNIQUE */}; - -const char * -get_oceanname(const struct region * r, const struct faction * f) -{ - attrib * a = a_find(r->attribs, &at_oceanname); - if (a) { - oceanname * names = (oceanname*)a->data.v; - while (names) { - faction_list * fl = names->factions; - while (fl) { - if (fl->data==f) return names->name; - fl=fl->next; - } - names = names->next; - } - } - return NULL; -} - -void -nameocean(struct region *r, struct faction * f, const char * newname) -{ - attrib * a = a_find(r->attribs, &at_oceanname); - if (!a && newname) a = a_add(&r->attribs, a_new(&at_oceanname)); - if (a) { - faction_list **oldf = NULL, **newf = NULL; - faction_list * fl = NULL; - oceanname * names = (oceanname*)a->data.v; - while ((names && (!newf && newname)) || !oldf) { - faction_list ** fli = &names->factions; - if (oldf==NULL) while (*fli) { - if ((*fli)->data==f) { - oldf = fli; - break; - } - fli=&(*fli)->next; - } - if (newname && !newf && !strcmp(names->name, newname)) { - newf = fli; - } - names = names->next; - } - - if (oldf) { - fl = *oldf; - *oldf = fl->next; - } else if (newname) { - fl = calloc(1, sizeof(faction_list)); - } - - if (newf) { - fl->data = f; - fl->next = *newf; - *newf = fl; - } else if (newname) { - oceanname * nm = calloc(1, sizeof(oceanname)); - nm->factions = fl; - fl->data = f; - fl->next = NULL; - nm->next = (oceanname*)a->data.v; - a->data.v = nm; - } else if (fl) { - free(fl); - } - } -} diff --git a/src/modules/oceannames.h b/src/modules/oceannames.h deleted file mode 100644 index ed5e4b5cc..000000000 --- a/src/modules/oceannames.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_MOD_OCEANNAMES -#define H_MOD_OCEANNAMES -#ifdef __cplusplus -extern "C" { -#endif - -struct faction; -struct region; -extern const char * get_oceanname(const struct region * r, const struct faction * f); - -#ifdef __cplusplus -} -#endif -#endif From efca8cee43f5968401304db80b255cf7dfce9190 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 Feb 2011 07:23:02 -0800 Subject: [PATCH 061/400] The list of alliance members is now also a quicklist, and the lua binding for faction_list iteration can disappear. --- src/bindings/bind_faction.c | 13 +----- src/bindings/bind_faction.h | 1 - src/bindings/bindings.c | 27 ++++++++++++- src/kernel/alliance.c | 80 +++++++++++++++++-------------------- src/kernel/alliance.h | 2 +- src/kernel/config.c | 15 ++++--- src/kernel/reports.c | 7 ++-- src/kernel/save.c | 6 +-- src/util/quicklist.c | 1 + 9 files changed, 79 insertions(+), 73 deletions(-) diff --git a/src/bindings/bind_faction.c b/src/bindings/bind_faction.c index 44caf3618..045aeea05 100644 --- a/src/bindings/bind_faction.c +++ b/src/bindings/bind_faction.c @@ -26,6 +26,7 @@ without prior permission by the authors of Eressea. #include #include +#include #include #include @@ -43,18 +44,6 @@ int tolua_factionlist_next(lua_State *L) else return 0; /* no more values to return */ } -int tolua_factionlist_iter(lua_State *L) -{ - faction_list** faction_ptr = (faction_list **)lua_touserdata(L, lua_upvalueindex(1)); - faction_list* flist = *faction_ptr; - if (flist != NULL) { - tolua_pushusertype(L, (void*)flist->data, TOLUA_CAST "faction"); - *faction_ptr = flist->next; - return 1; - } - else return 0; /* no more values to return */ -} - static int tolua_faction_get_units(lua_State* L) { faction * self = (faction *)tolua_tousertype(L, 1, 0); diff --git a/src/bindings/bind_faction.h b/src/bindings/bind_faction.h index c89750062..c390c5606 100644 --- a/src/bindings/bind_faction.h +++ b/src/bindings/bind_faction.h @@ -16,7 +16,6 @@ extern "C" { struct lua_State; int tolua_factionlist_next(struct lua_State *L); - int tolua_factionlist_iter(struct lua_State *L); void tolua_faction_open(struct lua_State *L); #ifdef __cplusplus diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index 09f863ccd..400df4a5c 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -55,6 +55,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include #include #include #include @@ -91,6 +92,24 @@ int tolua_orderlist_next(lua_State *L) else return 0; /* no more values to return */ } +int tolua_quicklist_iter(lua_State *L) +{ + quicklist** qlp = (quicklist **)lua_touserdata(L, lua_upvalueindex(1)); + quicklist* ql = *qlp; + if (ql != NULL) { + int index = lua_tointeger(L, lua_upvalueindex(2)); + const char * type = lua_tostring(L, lua_upvalueindex(3)); + void * data = ql_get(ql, index); + tolua_pushusertype(L, data, TOLUA_CAST type); + ql_advance(qlp, &index, 1); + + tolua_pushnumber(L, index); + lua_replace(L, lua_upvalueindex(2)); + return 1; + } + else return 0; /* no more values to return */ +} + int tolua_spelllist_next(lua_State *L) { spell_list** spell_ptr = (spell_list **)lua_touserdata(L, lua_upvalueindex(1)); @@ -728,14 +747,17 @@ static int tolua_get_alliance_factions(lua_State* L) { alliance * self = (alliance *)tolua_tousertype(L, 1, 0); - faction_list ** faction_ptr = (faction_list**)lua_newuserdata(L, sizeof(faction_list *)); + quicklist ** faction_ptr = (quicklist**)lua_newuserdata(L, sizeof(quicklist *)); luaL_getmetatable(L, "faction_list"); lua_setmetatable(L, -2); + lua_pushnumber(L, 0); + *faction_ptr = self->members; - lua_pushcclosure(L, tolua_factionlist_iter, 1); + lua_pushstring(L, "faction"); + lua_pushcclosure(L, tolua_quicklist_iter, 3); /* OBS: this closure has multiple upvalues (list, index, type_name) */ return 1; } @@ -1052,6 +1074,7 @@ tolua_eressea_open(lua_State* L) tolua_usertype(L, TOLUA_CAST "item"); tolua_usertype(L, TOLUA_CAST "alliance"); tolua_usertype(L, TOLUA_CAST "event"); + tolua_usertype(L, TOLUA_CAST "faction_list"); tolua_module(L, NULL, 0); tolua_beginmodule(L, NULL); diff --git a/src/kernel/alliance.c b/src/kernel/alliance.c index cfacb00c2..fc8cbb452 100644 --- a/src/kernel/alliance.c +++ b/src/kernel/alliance.c @@ -33,6 +33,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include #include #include @@ -49,11 +50,7 @@ void free_alliance(alliance * al) { free(al->name); - while (al->members) { - faction_list * m = al->members; - al->members = m->next; - free(m); - } + if (al->members) ql_free(al->members); free(al); } @@ -111,7 +108,7 @@ alliance_get_leader(alliance * al) { if (!al->_leader) { if (al->members) { - al->_leader = al->members->data; + al->_leader = (faction *)ql_get(al->members, 0); } } return al->_leader; @@ -120,7 +117,7 @@ alliance_get_leader(alliance * al) static void create_transaction(int type, unit * u, order * ord) { - alliance_transaction * tr = calloc(1, sizeof(alliance_transaction)); + alliance_transaction * tr = (alliance_transaction *)calloc(1, sizeof(alliance_transaction)); tr->ord = ord; tr->u = u; tr->next = transactions[type]; @@ -372,24 +369,24 @@ alliancejoin(void) } void -setalliance(struct faction * f, alliance * al) +setalliance(faction * f, alliance * al) { - faction_list * flist = NULL; if (f->alliance==al) return; if (f->alliance!=NULL) { - faction_list ** flistp = &f->alliance->members; - while (*flistp) { - faction_list * flist = *flistp; - if ((*flistp)->data==f) { - *flistp = flist->next; + int qi; + quicklist ** flistp = &f->alliance->members; + + for (qi=0;*flistp;ql_advance(flistp, &qi, 1)) { + faction * data = (faction *)ql_get(*flistp, qi); + if (data==f) { + ql_delete(flistp, qi); break; } - flistp = &flist->next; } if (f->alliance->_leader==f) { if (f->alliance->members) { - f->alliance->_leader = f->alliance->members->data; + f->alliance->_leader = (faction *)ql_get(f->alliance->members, 0); } else { f->alliance->_leader = NULL; } @@ -398,22 +395,11 @@ setalliance(struct faction * f, alliance * al) f->alliance = al; f->alliance_joindate = turn; if (al!=NULL) { - faction_list ** flistp = &al->members; - while (*flistp) { - flistp = &(*flistp)->next; - } - if (flist==NULL) { - flist = malloc(sizeof(faction_list)); - flist->data = f; - } - *flistp = flist; - flist->next = NULL; + ql_push(&al->members, f); if (al->_leader==NULL) { al->_leader = f; } - flist = NULL; } - free(flist); } const char * @@ -456,15 +442,15 @@ alliancevictory(void) } while (al!=NULL) { if (!fval(al, FFL_MARK)) { - faction_list * flist = al->members; - while (flist!=0) { - faction * f = flist->data; + int qi; + quicklist * flist = al->members; + for (qi=0;flist;ql_advance(&flist, &qi, 1)) { + faction * f = (faction *)ql_get(flist, qi); if (f->alliance==al) { ADDMSG(&f->msgs, msg_message("alliance::lost", "alliance", al)); destroyfaction(f); } - flist = flist->next; } } else { freset(al, FFL_MARK); @@ -478,18 +464,20 @@ victorycondition(const alliance * al, const char * name) { const char * gems[] = { "opal", "diamond", "zaphire", "topaz", "beryl", "agate", "garnet", "emerald", NULL }; if (strcmp(name, "gems")==0) { - const char ** igem = gems; + const char ** igem; - for (;*igem;++igem) { + for (igem=gems;*igem;++igem) { const struct item_type * itype = it_find(*igem); - faction_list * flist = al->members; + quicklist * flist = al->members; + int qi; boolean found = false; assert(itype!=NULL); - for (;flist && !found;flist=flist->next) { - unit * u = flist->data->units; + for (qi=0;flist && !found;ql_advance(&flist, &qi, 1)) { + faction * f = (faction *)ql_get(flist, 0); + unit * u; - for (;u;u=u->nextF) { + for (u=f->units;u;u=u->nextF) { if (i_get(u->items, itype)>0) { found = true; break; @@ -501,9 +489,11 @@ victorycondition(const alliance * al, const char * name) return 1; } else if (strcmp(name, "phoenix")==0) { - faction_list * flist = al->members; - for (;flist;flist=flist->next) { - faction * f = flist->data; + quicklist * flist = al->members; + int qi; + + for (qi=0;flist;ql_advance(&flist, &qi, 1)) { + faction * f = (faction *)ql_get(flist, qi); if (find_key(f->attribs, atoi36("phnx"))) { return 1; } @@ -527,9 +517,11 @@ victorycondition(const alliance * al, const char * name) * } */ - faction_list * flist = al->members; - for (;flist;flist=flist->next) { - faction * f = flist->data; + quicklist * flist = al->members; + int qi; + + for (qi=0;flist;ql_advance(&flist, &qi, 1)) { + faction * f = (faction *)ql_get(flist, qi); if (find_key(f->attribs, atoi36("pyra"))) { return 1; } diff --git a/src/kernel/alliance.h b/src/kernel/alliance.h index e9cab8b66..e384b0f8f 100644 --- a/src/kernel/alliance.h +++ b/src/kernel/alliance.h @@ -44,7 +44,7 @@ enum { typedef struct alliance { struct alliance * next; struct faction * _leader; - struct faction_list * members; + struct quicklist * members; unsigned int flags; int id; char * name; diff --git a/src/kernel/config.c b/src/kernel/config.c index d0885efd2..4423ad467 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -53,6 +53,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include #include +#include #include #include #include @@ -60,14 +61,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include #include +#include #include #include -#include -#include /* libxml includes */ #include @@ -507,10 +508,12 @@ allied_skillcount(const faction * f, skill_t sk) { int num = 0; alliance * a = f_get_alliance(f); - faction_list * members = a->members; - while (members!=NULL) { - num += count_skill(members->data, sk); - members=members->next; + quicklist * members = a->members; + int qi; + + for (qi=0;members;ql_advance(&members, &qi, 1)) { + faction * m = (faction *)ql_get(members, qi); + num += count_skill(m, sk); } return num; } diff --git a/src/kernel/reports.c b/src/kernel/reports.c index 7cd973a6c..616c69d1e 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -924,9 +924,10 @@ get_addresses(report_context * ctx) ql_push(&flist, ctx->f); if (f_get_alliance(ctx->f)) { - faction_list * member = ctx->f->alliance->members; - for (;member;member=member->next) { - ql_set_insert(&flist, member->data); + quicklist * ql = ctx->f->alliance->members; + int qi; + for (qi=0;ql;ql_advance(&ql, &qi, 1)) { + ql_set_insert(&flist, ql_get(ql, qi)); } } diff --git a/src/kernel/save.c b/src/kernel/save.c index ca140d313..19db607ce 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -62,6 +62,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include @@ -1178,13 +1179,10 @@ readfaction(struct storage * store) if (allianceid>0) f->alliance = findalliance(allianceid); if (f->alliance) { alliance * al = f->alliance; - faction_list * flist = (faction_list *)malloc(sizeof(faction_list)); if (al->flags&ALF_NON_ALLIED) { assert(!al->members || !"non-allied dummy-alliance has more than one member"); } - flist->data = f; - flist->next = al->members; - al->members = flist; + ql_push(&al->members, f); } else if (rule_region_owners()){ /* compat fix for non-allied factions */ alliance * al = makealliance(0, NULL); diff --git a/src/util/quicklist.c b/src/util/quicklist.c index f5b0bc8bd..e3986eb75 100644 --- a/src/util/quicklist.c +++ b/src/util/quicklist.c @@ -142,6 +142,7 @@ int ql_advance(struct quicklist ** iterator, int * index, int stride) void ql_free(struct quicklist * ql) { + if (!ql) return; if (ql->next) ql_free(ql->next); free(ql); } From 14dff6cdfa3ae8e881cf1baa781a0abab42a855c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 Feb 2011 07:27:44 -0800 Subject: [PATCH 062/400] seen_factions is a quicklist, and the faction_list struct is a thing of the past. --- src/gamecode/spy.c | 3 ++- src/kernel/alliance.h | 1 - src/kernel/faction.c | 16 ---------------- src/kernel/faction.h | 8 +------- src/kernel/reports.c | 12 +++++------- 5 files changed, 8 insertions(+), 32 deletions(-) diff --git a/src/gamecode/spy.c b/src/gamecode/spy.c index 164c3b2b1..42747dfba 100644 --- a/src/gamecode/spy.c +++ b/src/gamecode/spy.c @@ -43,6 +43,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include @@ -73,7 +74,7 @@ spy_message(int spy, const unit *u, const unit *target) if (fv && fv!=target->faction) { /* wahre Partei */ ADDMSG(&u->faction->msgs, msg_message("spyreport_faction", "target faction", target, target->faction)); - flist_add(&u->faction->seen_factions, target->faction); + ql_set_insert(&u->faction->seen_factions, target->faction); } } if (spy > 0) { diff --git a/src/kernel/alliance.h b/src/kernel/alliance.h index e384b0f8f..026bd0c11 100644 --- a/src/kernel/alliance.h +++ b/src/kernel/alliance.h @@ -27,7 +27,6 @@ struct attrib; struct unit; struct faction; struct region; -struct faction_list; enum { ALLIANCE_KICK, diff --git a/src/kernel/faction.c b/src/kernel/faction.c index 44873ac24..f5ac32f3c 100644 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -505,19 +505,3 @@ f_get_alliance(const struct faction * f) } return NULL; } - -void -flist_add(faction_list ** flist, faction * sf) -{ - faction_list ** fnew = flist; - while (*fnew && (*fnew)->data->no < sf->no) { - fnew =&(*fnew)->next; - } - if ((*fnew==NULL) || (*fnew)->data!=sf) { - faction_list * finsert = malloc(sizeof(faction_list)); - finsert->next = *fnew; - *fnew = finsert; - finsert->data = sf; - } -} - diff --git a/src/kernel/faction.h b/src/kernel/faction.h index 198af7d88..0e3617e34 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -108,17 +108,11 @@ typedef struct faction { } * battles; struct item * items; /* items this faction can claim */ struct seen_region ** seen; - struct faction_list * seen_factions; + struct quicklist * seen_factions; } faction; extern struct faction *factions; -typedef struct faction_list { - struct faction_list * next; - struct faction * data; -} faction_list; - -void flist_add(struct faction_list ** flist, struct faction * sf); extern const struct unit * random_unit_in_faction(const struct faction *f); extern const char * factionname(const struct faction * f); extern struct unit * addplayer(struct region *r, faction * f); diff --git a/src/kernel/reports.c b/src/kernel/reports.c index 616c69d1e..8ba41875b 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -900,13 +900,11 @@ stealth_modifier(int seen_mode) } } -void transfer_seen(quicklist ** dst, faction_list ** src) { - while (*src) { - faction_list * flist = *src; - ql_set_insert(dst, flist->data); - free(flist); - *src = flist->next; - } +void transfer_seen(quicklist ** dst, quicklist ** src) +{ + assert(!*dst); + *dst = *src; + *src = NULL; } static void From 5497875c93dabe703e609e1b8267982dc94befae Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 Feb 2011 07:41:51 -0800 Subject: [PATCH 063/400] Funny. It turns out that building_list is totally not a thing and never was. --- src/bindings/bind_building.c | 1 - src/kernel/building.c | 21 --------------------- src/kernel/building.h | 8 -------- 3 files changed, 30 deletions(-) diff --git a/src/bindings/bind_building.c b/src/bindings/bind_building.c index a177b1975..eecde8fbb 100644 --- a/src/bindings/bind_building.c +++ b/src/bindings/bind_building.c @@ -223,7 +223,6 @@ tolua_building_open(lua_State* L) { /* register user types */ tolua_usertype(L, TOLUA_CAST "building"); - tolua_usertype(L, TOLUA_CAST "building_list"); tolua_module(L, NULL, 0); tolua_beginmodule(L, NULL); diff --git a/src/kernel/building.c b/src/kernel/building.c index 0ab58de70..509cb6d1a 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -429,27 +429,6 @@ read_building_reference(struct storage * store) return result; } -void -free_buildinglist(building_list *blist) -{ - while (blist) { - building_list * rl2 = blist->next; - free(blist); - blist = rl2; - } -} - -void -add_buildinglist(building_list **blist, building *b) -{ - building_list *rl2 = (building_list*)malloc(sizeof(building_list)); - - rl2->data = b; - rl2->next = *blist; - - *blist = rl2; -} - building * new_building(const struct building_type * btype, region * r, const struct locale * lang) { diff --git a/src/kernel/building.h b/src/kernel/building.h index 7aea49bd1..08ede08bb 100644 --- a/src/kernel/building.h +++ b/src/kernel/building.h @@ -110,14 +110,6 @@ typedef struct building { unsigned int flags; } building; -typedef struct building_list { - struct building_list * next; - building * data; -} building_list; - -extern void free_buildinglist(building_list *bl); -extern void add_buildinglist(building_list **bl, struct building *b); - extern struct attrib_type at_building_generic_type; extern const char * buildingtype(const building_type * btype, const struct building * b, int bsize); extern const char * write_buildingname(const building * b, char * ibuf, size_t size); From 5e21579036142d5984902ea8aadb9b7d656eb1ea Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 Feb 2011 07:47:35 -0800 Subject: [PATCH 064/400] another special-cased list type bites the dust and is replaced by the quicklist. --- src/kernel/connection.c | 16 ++++++---------- src/kernel/connection.h | 5 ----- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/kernel/connection.c b/src/kernel/connection.c index 0dc4a3753..fd8d3d3c9 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -29,6 +29,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include @@ -254,7 +255,7 @@ attrib_type at_countdown = { void age_borders(void) { - border_list * deleted = NULL; + quicklist * deleted = NULL, *ql; int i; for (i=0;i!=BORDER_MAXHASH;++i) { @@ -264,22 +265,17 @@ age_borders(void) for (;b;b=b->next) { if (b->type->age) { if (b->type->age(b)==AT_AGE_REMOVE) { - border_list * kill = malloc(sizeof(border_list)); - kill->data = b; - kill->next = deleted; - deleted = kill; + ql_push(&deleted, b); } } } } } - while (deleted) { - border_list * blist = deleted->next; - connection * b = deleted->data; + for (ql=deleted,i=0;ql;ql_advance(&ql, &i, 1)) { + connection * b = (connection *)ql_get(ql, i); erase_border(b); - free(deleted); - deleted = blist; } + ql_free(deleted); } /******** diff --git a/src/kernel/connection.h b/src/kernel/connection.h index ae5160459..9a7091132 100644 --- a/src/kernel/connection.h +++ b/src/kernel/connection.h @@ -36,11 +36,6 @@ extern "C" { unsigned int id; /* unique id */ } connection; - typedef struct border_list { - struct border_list * next; - struct connection * data; - } border_list; - typedef struct border_type { const char* __name; /* internal use only */ variant_type datatype; From c278a3b71f9fa8bdaa674ddcdac40b83b24a8df6 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 Feb 2011 07:56:00 -0800 Subject: [PATCH 065/400] cursetype_list, another special-cased list type, bites the dust and is replaced by the quicklist. --- src/kernel/curse.c | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 415308d2c..024066b54 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -275,44 +275,37 @@ attrib_type at_curse = /* Spruch identifizieren */ #include +#include -typedef struct cursetype_list { - struct cursetype_list * next; - const curse_type * type; -} cursetype_list; - -cursetype_list * cursetypes[256]; +static quicklist * cursetypes[256]; void ct_register(const curse_type * ct) { unsigned int hash = tolower(ct->cname[0]); - cursetype_list ** ctlp = &cursetypes[hash]; + quicklist ** ctlp = &cursetypes[hash]; - while (*ctlp) { - cursetype_list * ctl = *ctlp; - if (ctl->type==ct) return; - ctlp=&ctl->next; - } - *ctlp = calloc(1, sizeof(cursetype_list)); - (*ctlp)->type = ct; + ql_set_insert(ctlp, (void *)ct); } const curse_type * ct_find(const char *c) { unsigned int hash = tolower(c[0]); - cursetype_list * ctl = cursetypes[hash]; - while (ctl) { - if (strcmp(c, ctl->type->cname)==0) { - return ctl->type; + quicklist * ctl = cursetypes[hash]; + int qi; + + for (qi=0;ctl;ql_advance(&ctl, &qi, 1)) { + curse_type * type = (curse_type*)ql_get(ctl, qi); + + if (strcmp(c, type->cname)==0) { + return type; } else { - size_t k = MIN(strlen(c), strlen(ctl->type->cname)); - if (!strncasecmp(c, ctl->type->cname, k)) { - return ctl->type; + size_t k = MIN(strlen(c), strlen(type->cname)); + if (!strncasecmp(c, type->cname, k)) { + return type; } } - ctl = ctl->next; } return NULL; } From fd2b30a0ff82e3e6b683cc9a24797332485db139 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 Feb 2011 08:04:25 -0800 Subject: [PATCH 066/400] messagetype_list, another special-cased list type, bites the dust and is replaced by the quicklist. --- src/kernel/curse.c | 2 +- src/util/message.c | 57 +++++++++++++++++++--------------------------- 2 files changed, 25 insertions(+), 34 deletions(-) diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 024066b54..0747d9443 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -283,7 +283,7 @@ void ct_register(const curse_type * ct) { unsigned int hash = tolower(ct->cname[0]); - quicklist ** ctlp = &cursetypes[hash]; + quicklist ** ctlp = cursetypes+hash; ql_set_insert(ctlp, (void *)ct); } diff --git a/src/util/message.c b/src/util/message.c index 243b6ba40..2fdeb14ba 100644 --- a/src/util/message.c +++ b/src/util/message.c @@ -16,6 +16,7 @@ #include "goodies.h" #include "log.h" +#include "quicklist.h" /* libc includes */ #include @@ -29,7 +30,7 @@ void (*msg_log_create)(const struct message * msg) = 0; const char * mt_name(const message_type* mtype) { - return mtype->name; + return mtype->name; } message_type * @@ -78,18 +79,18 @@ mt_new(const char * name, const char * args[]) message_type * mt_new_va(const char * name, ...) { - const char * args[16]; - int i = 0; - va_list marker; + const char * args[16]; + int i = 0; + va_list marker; - va_start(marker, name); - for (;;) { - const char * c = va_arg(marker, const char*); - args[i++] = c; - if (c==NULL) break; - } - va_end(marker); - return mt_new(name, args); + va_start(marker, name); + for (;;) { + const char * c = va_arg(marker, const char*); + args[i++] = c; + if (c==NULL) break; + } + va_end(marker); + return mt_new(name, args); } arg_type * argtypes = NULL; @@ -153,28 +154,23 @@ msg_create(const struct message_type * mtype, variant args[]) return msg; } -typedef struct messagetype_list { - struct messagetype_list * next; - const struct message_type * data; -} messagetype_list; - #define MT_MAXHASH 1021 -static messagetype_list * messagetypes[MT_MAXHASH]; +static quicklist * messagetypes[MT_MAXHASH]; const message_type * mt_find(const char * name) { - const struct message_type * found = NULL; unsigned int hash = hashstring(name) % MT_MAXHASH; - messagetype_list * type = messagetypes[hash]; - while (type) { - if (strcmp(type->data->name, name)==0) { - if (found==NULL) found = type->data; - break; + quicklist * ql = messagetypes[hash]; + int qi; + + for (qi=0;ql;ql_advance(&ql, &qi, 1)) { + message_type * data = (message_type *)ql_get(ql, qi); + if (strcmp(data->name, name)==0) { + return data; } - type = type->next; } - return found; + return 0; } static unsigned int @@ -194,14 +190,9 @@ const message_type * mt_register(message_type * type) { unsigned int hash = hashstring(type->name) % MT_MAXHASH; - messagetype_list * mtl = messagetypes[hash]; + quicklist ** qlp = messagetypes+hash; - while (mtl && mtl->data!=type) mtl=mtl->next; - if (mtl==NULL) { - mtl = (messagetype_list*)malloc(sizeof(messagetype_list)); - mtl->data = type; - mtl->next = messagetypes[hash]; - messagetypes[hash] = mtl; + if (ql_set_insert(qlp, type)==0) { type->key = mt_id(type); } return type; From b28fa19d01dbeb52c52de1a7223072736c4c5cc5 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 Feb 2011 18:16:14 -0800 Subject: [PATCH 067/400] Even if equipment is not very frequently used, there's no need for it to use spell_list structs. --- src/kernel/equipment.c | 16 +++++++++------- src/kernel/equipment.h | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index 9b7e0393b..34e80a33a 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -26,6 +26,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "race.h" /* util includes */ +#include #include #include @@ -89,7 +90,7 @@ void equipment_addspell(equipment * eq, spell * sp) { if (eq!=NULL) { - spelllist_add(&eq->spells, sp); + ql_set_insert(&eq->spells, sp); } } @@ -103,7 +104,7 @@ equipment_setitem(equipment * eq, const item_type * itype, const char * value) idata = idata->next; } if (idata==NULL) { - idata = malloc(sizeof(itemdata)); + idata = (itemdata *)malloc(sizeof(itemdata)); idata->itype = itype; idata->value = strdup(value); idata->next = eq->items; @@ -141,15 +142,16 @@ equip_unit_mask(struct unit * u, const struct equipment * eq, int mask) } if (mask&EQUIP_SPELLS) { - spell_list * sp = eq->spells; - if (sp!=NULL) { + quicklist * ql = eq->spells; + if (ql) { sc_mage * m = get_mage(u); if (m==NULL) { assert(!"trying to equip spells on a non-mage!"); } else { - while (sp) { - add_spell(get_spelllist(m, u->faction), sp->data); - sp = sp->next; + int qi; + for (qi=0;ql;ql_advance(&ql, &qi, 1)) { + spell * sp = (spell *)ql_get(ql, qi); + add_spell(get_spelllist(m, u->faction), sp); } } } diff --git a/src/kernel/equipment.h b/src/kernel/equipment.h index 174aad7f4..a0989c7eb 100644 --- a/src/kernel/equipment.h +++ b/src/kernel/equipment.h @@ -43,7 +43,7 @@ extern "C" { char * name; struct itemdata * items; char * skills[MAXSKILLS]; - struct spell_list * spells; + struct quicklist * spells; struct subset * subsets; struct equipment * next; void (*callback)(const struct equipment *, struct unit *); From b2d6203cece53d9c89f6dad4359650dec9d50366 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 Feb 2011 00:26:14 -0800 Subject: [PATCH 068/400] 1. spell_list was pretty much used everywhere in the code, and is now also a quicklist. 2. Cleaned up the bindings for quicklist to Lua. --- src/bindings/bind_attrib.c | 1 + src/bindings/bind_faction.c | 14 +---- src/bindings/bind_unit.c | 59 ++++++----------- src/bindings/bindings.c | 57 ++++++----------- src/bindings/bindings.h | 1 + src/gamecode.vcxproj | 2 + src/gamecode.vcxproj.filters | 6 ++ src/gamecode/creport.c | 11 ++-- src/gamecode/xmlreport.c | 11 ++-- src/kernel/faction.c | 3 +- src/kernel/faction.h | 2 +- src/kernel/magic.c | 119 ++++++++++++----------------------- src/kernel/magic.h | 20 ++---- src/kernel/reports.c | 8 +-- src/kernel/save.c | 4 +- src/kernel/spell.c | 46 ++++++++------ src/kernel/spell.h | 2 +- src/util/quicklist.c | 45 ++++++++++++- src/util/quicklist.h | 3 + src/util/quicklist_test.c | 62 +++++++++++++++++- 20 files changed, 254 insertions(+), 222 deletions(-) diff --git a/src/bindings/bind_attrib.c b/src/bindings/bind_attrib.c index 54821bfe9..04c02f305 100644 --- a/src/bindings/bind_attrib.c +++ b/src/bindings/bind_attrib.c @@ -15,6 +15,7 @@ without prior permission by the authors of Eressea. #include #include +#include #include #include #include diff --git a/src/bindings/bind_faction.c b/src/bindings/bind_faction.c index 045aeea05..75bafa275 100644 --- a/src/bindings/bind_faction.c +++ b/src/bindings/bind_faction.c @@ -471,19 +471,7 @@ tolua_faction_tostring(lua_State *L) static int tolua_faction_get_spells(lua_State* L) { faction* self = (faction*)tolua_tousertype(L, 1, 0); - spell_list * slist = self->spellbook; - if (slist) { - spell_list ** spell_ptr = (spell_list **)lua_newuserdata(L, sizeof(spell_list *)); - luaL_getmetatable(L, TOLUA_CAST "spell_list"); - lua_setmetatable(L, -2); - - *spell_ptr = slist; - lua_pushcclosure(L, tolua_spelllist_next, 1); - return 1; - } - - lua_pushnil(L); - return 1; + return tolua_quicklist_push(L, "spell_list", "spell", self->spellbook); } void diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index c7ff2a345..186950b9c 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -43,6 +43,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include #include #include @@ -468,9 +469,11 @@ tolua_unit_addnotice(lua_State* L) static void unit_castspell(unit * u, const char * name) { - spell_list * slist = spells; - while (slist!=NULL) { - spell * sp = slist->data; + quicklist * ql = spells; + int qi; + + for (ql=spells,qi=0;ql;ql_advance(&ql, &qi, 1)) { + spell * sp = (spell *)ql_get(ql, qi); if (strcmp(name, sp->sname)==0) { castorder * co = (castorder*)malloc(sizeof(castorder)); co->distance = 0; @@ -490,7 +493,6 @@ unit_castspell(unit * u, const char * name) } free(co); } - slist=slist->next; } } @@ -506,23 +508,12 @@ tolua_unit_castspell(lua_State* L) static void unit_addspell(unit * u, const char * name) { - int add = 0; sc_mage * m = get_mage(u); - spell_list * slist = spells; - spell_list ** starget = NULL; - spell * spadd = NULL; - while (slist!=NULL) { - spell * sp = slist->data; - if (strcmp(name, sp->sname)==0) { - starget = get_spelllist(m, u->faction); - if (m->magietyp==sp->magietyp) spadd = sp; - else if (!spadd) spadd = sp; - add = 1; - } - slist=slist->next; - } + spell * spadd = find_spell(M_NONE, name); + if (!spadd) log_error(("spell %s could not be found\n", name)); else { + quicklist ** starget = get_spelllist(m, u->faction); add_spell(starget, spadd); } } @@ -537,19 +528,12 @@ tolua_unit_addspell(lua_State* L) } static void -unit_removespell(unit * u, const spell * sp) +unit_removespell(unit * u, spell * sp) { - spell_list ** isptr; - isptr = get_spelllist(get_mage(u), u->faction); + quicklist ** isptr; - while (*isptr && (*isptr)->data != sp) { - isptr = &(*isptr)->next; - } - if (*isptr) { - spell_list * sptr = *isptr; - *isptr = sptr->next; - free(sptr); - } + isptr = get_spelllist(get_mage(u), u->faction); + ql_set_remove(isptr, sp); } static int @@ -760,23 +744,16 @@ static int tolua_unit_get_spells(lua_State* L) { unit* self = (unit*)tolua_tousertype(L, 1, 0); sc_mage * mage = get_mage(self); + quicklist * slist = 0; if (mage) { - spell_list ** slist = get_spelllist(mage, self->faction); - assert(slist); - if (slist) { - spell_list ** spell_ptr = (spell_list **)lua_newuserdata(L, sizeof(spell_list *)); - luaL_getmetatable(L, TOLUA_CAST "spell_list"); - lua_setmetatable(L, -2); - - *spell_ptr = *slist; - lua_pushcclosure(L, tolua_spelllist_next, 1); - return 1; + quicklist ** slist_ptr = get_spelllist(mage, self->faction); + if (slist_ptr) { + slist = *slist_ptr; } } - lua_pushnil(L); - return 1; + return tolua_quicklist_push(L, "spell_list", "spell", slist); } static int tolua_unit_get_orders(lua_State* L) diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index 400df4a5c..f987c0173 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -92,7 +92,7 @@ int tolua_orderlist_next(lua_State *L) else return 0; /* no more values to return */ } -int tolua_quicklist_iter(lua_State *L) +static int tolua_quicklist_iter(lua_State *L) { quicklist** qlp = (quicklist **)lua_touserdata(L, lua_upvalueindex(1)); quicklist* ql = *qlp; @@ -110,16 +110,21 @@ int tolua_quicklist_iter(lua_State *L) else return 0; /* no more values to return */ } -int tolua_spelllist_next(lua_State *L) +int tolua_quicklist_push(struct lua_State *L, const char * list_type, const char * elem_type, struct quicklist * list) { - spell_list** spell_ptr = (spell_list **)lua_touserdata(L, lua_upvalueindex(1)); - spell_list* slist = *spell_ptr; - if (slist != NULL) { - tolua_pushusertype(L, slist->data, TOLUA_CAST "spell"); - *spell_ptr = slist->next; - return 1; + if (list) { + quicklist ** qlist_ptr = (quicklist**)lua_newuserdata(L, sizeof(quicklist *)); + *qlist_ptr = list; + + luaL_getmetatable(L, list_type); + lua_setmetatable(L, -2); + lua_pushnumber(L, 0); + lua_pushstring(L, elem_type); + lua_pushcclosure(L, tolua_quicklist_iter, 3); /* OBS: this closure has multiple upvalues (list, index, type_name) */ + } else { + lua_pushnil(L); } - else return 0; /* no more values to return */ + return 1; } int tolua_itemlist_next(lua_State *L) @@ -747,18 +752,7 @@ static int tolua_get_alliance_factions(lua_State* L) { alliance * self = (alliance *)tolua_tousertype(L, 1, 0); - quicklist ** faction_ptr = (quicklist**)lua_newuserdata(L, sizeof(quicklist *)); - - luaL_getmetatable(L, "faction_list"); - lua_setmetatable(L, -2); - - lua_pushnumber(L, 0); - - *faction_ptr = self->members; - - lua_pushstring(L, "faction"); - lua_pushcclosure(L, tolua_quicklist_iter, 3); /* OBS: this closure has multiple upvalues (list, index, type_name) */ - return 1; + return tolua_quicklist_push(L, "faction_list", "faction", self->members); } static int tolua_get_alliance_id(lua_State* L) @@ -794,10 +788,11 @@ tolua_write_spells(lua_State* L) const char * filename = "magic.xml"; xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); xmlNodePtr root = xmlNewNode(NULL, BAD_CAST "spells"); - spell_list * splist; + quicklist * ql; + int qi; - for (splist=spells; splist; splist=splist->next) { - spell * sp = splist->data; + for (ql=spells,qi=0;ql;ql_advance(&ql, &qi, 1)) { + spell * sp = (spell *)ql_get(ql, qi); if (sp->sp_function!=fun) { int combat = 0; xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "spell"); @@ -904,19 +899,7 @@ tolua_get_spell_name(lua_State *L) static int tolua_get_spells(lua_State* L) { - spell_list * slist = spells; - if (slist) { - spell_list ** spell_ptr = (spell_list **)lua_newuserdata(L, sizeof(spell_list *)); - luaL_getmetatable(L, "spell_list"); - lua_setmetatable(L, -2); - - *spell_ptr = slist; - lua_pushcclosure(L, tolua_spelllist_next, 1); - return 1; - } - - lua_pushnil(L); - return 1; + return tolua_quicklist_push(L, "spell_list", "spell", spells); } int diff --git a/src/bindings/bindings.h b/src/bindings/bindings.h index 5ed8d6232..4cca8fee4 100644 --- a/src/bindings/bindings.h +++ b/src/bindings/bindings.h @@ -20,6 +20,7 @@ extern "C" { int tolua_spelllist_next(struct lua_State *L); int tolua_itemlist_next(struct lua_State *L); int tolua_orderlist_next(struct lua_State *L); + int tolua_quicklist_push(struct lua_State *L, const char * list_type, const char * elem_type, struct quicklist * list); int log_lua_error(struct lua_State * L); #ifdef __cplusplus diff --git a/src/gamecode.vcxproj b/src/gamecode.vcxproj index 8cfd4712a..78f231ff1 100644 --- a/src/gamecode.vcxproj +++ b/src/gamecode.vcxproj @@ -93,6 +93,7 @@ + @@ -119,6 +120,7 @@ + diff --git a/src/gamecode.vcxproj.filters b/src/gamecode.vcxproj.filters index 8cd90a6f3..9105225f2 100644 --- a/src/gamecode.vcxproj.filters +++ b/src/gamecode.vcxproj.filters @@ -65,6 +65,9 @@ Source Files + + Source Files + @@ -121,5 +124,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index fbf0af602..a216b37e0 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -641,12 +641,15 @@ fwriteorder(FILE * F, const struct order * ord, const struct locale * lang, bool fputc('"', F); } -static void cr_output_spells(FILE * F, spell_list * slist, const faction * f, int maxlevel) +static void cr_output_spells(FILE * F, quicklist * slist, const faction * f, int maxlevel) { if (slist) { + quicklist * ql; + int qi; fprintf(F, "SPRUECHE\n"); - for (;slist; slist = slist->next) { - spell * sp = slist->data; + + for (ql=slist,qi=0;ql;ql_advance(&ql, &qi, 1)) { + spell * sp = (spell *)ql_get(ql, qi); if (sp->level <= maxlevel) { const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, f->locale)); fprintf(F, "\"%s\"\n", name); @@ -868,7 +871,7 @@ cr_output_unit(FILE * F, const region * r, /* spells */ if (is_mage(u)) { sc_mage * mage = get_mage(u); - spell_list ** slistp = get_spelllist(mage, u->faction); + quicklist ** slistp = get_spelllist(mage, u->faction); int i, maxlevel = effskill(u, SK_MAGIC); cr_output_spells(F, *slistp, f, maxlevel); diff --git a/src/gamecode/xmlreport.c b/src/gamecode/xmlreport.c index 2c7646895..eaa4873a5 100644 --- a/src/gamecode/xmlreport.c +++ b/src/gamecode/xmlreport.c @@ -58,6 +58,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include #include #include @@ -173,13 +174,15 @@ xml_inventory(report_context * ctx, item * items, unit * u) } static xmlNodePtr -xml_spells(report_context * ctx, spell_list * slist, int maxlevel) +xml_spells(report_context * ctx, quicklist * slist, int maxlevel) { xml_context* xct = (xml_context*)ctx->userdata; xmlNodePtr child, node = xmlNewNode(xct->ns_atl, BAD_CAST "spells"); + quicklist * ql; + int qi; - for (;slist; slist = slist->next) { - spell * sp = slist->data; + for (ql=slist,qi=0;ql;ql_advance(&ql, &qi, 1)) { + spell * sp = (spell *)ql_get(ql, qi); if (sp->level <= maxlevel) { child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "spell")); @@ -338,7 +341,7 @@ xml_unit(report_context * ctx, unit * u, int mode) /* spells */ if (is_mage(u)) { sc_mage * mage = get_mage(u); - spell_list * slist = mage->spells; + quicklist * slist = mage->spells; if (slist) { xmlAddChild(node, xml_spells(ctx, slist, effskill(u, SK_MAGIC))); } diff --git a/src/kernel/faction.c b/src/kernel/faction.c index f5ac32f3c..7216e9338 100644 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -40,6 +40,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include @@ -287,7 +288,7 @@ destroyfaction(faction * f) if (!f->alive) return; fset(f, FFL_QUIT); - freelist(f->spellbook); + ql_free(f->spellbook); f->spellbook = NULL; while (f->battles) { diff --git a/src/kernel/faction.h b/src/kernel/faction.h index 0e3617e34..fc0b71107 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -73,7 +73,7 @@ typedef struct faction { char *passw; char *override; int max_spelllevel; - struct spell_list * spellbook; + struct quicklist * spellbook; const struct locale * locale; int lastorders; int age; diff --git a/src/kernel/magic.c b/src/kernel/magic.c index a1e1251b6..db73632d6 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -53,6 +53,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include @@ -208,7 +209,7 @@ int FactionSpells(void) return rules_factionspells; } -void read_spellist(struct spell_list ** slistp, magic_t mtype, struct storage * store) +void read_spells(struct quicklist ** slistp, magic_t mtype, struct storage * store) { for (;;) { spell * sp; @@ -269,16 +270,18 @@ read_mage(attrib * a, void * owner, struct storage * store) } } } - read_spellist(&mage->spells, mage->magietyp, store); + read_spells(&mage->spells, mage->magietyp, store); return AT_READ_OK; } -void write_spelllist(const spell_list * slist, struct storage * store) +void write_spells(struct quicklist * slist, struct storage * store) { - while (slist!=NULL) { - spell * sp = slist->data; + quicklist * ql; + int qi; + + for (ql=slist,qi=0;ql;ql_advance(&ql, &qi, 1)) { + spell * sp = (spell *)ql_get(ql, qi); store->w_tok(store, sp->sname); - slist = slist->next; } store->w_tok(store, "end"); } @@ -296,7 +299,7 @@ write_mage(const attrib * a, const void * owner, struct storage * store) store->w_tok(store, mage->combatspells[i].sp?mage->combatspells[i].sp->sname:"none"); store->w_int(store, mage->combatspells[i].level); } - write_spelllist(mage->spells, store); + write_spells(mage->spells, store); } attrib_type at_mage = { @@ -404,6 +407,13 @@ static boolean know_school(const faction * f, magic_t school) #define COMMONSPELLS 1 /* number of new common spells per level */ #define MAXSPELLS 256 +static boolean +has_spell(quicklist * ql, const spell * sp) +{ + int qi; + return ql_set_find(&ql, &qi, sp)!=0; +} + /** update the spellbook with a new level * Written for Eressea 1.1 */ @@ -411,18 +421,16 @@ void update_spellbook(faction * f, int level) { spell * commonspells[MAXSPELLS]; - int numspells = 0; - spell_list * slist; + int qi, numspells = 0; + quicklist * ql; - for (slist=spells;slist!=NULL;slist=slist->next) { - spell * sp = slist->data; + for (qi=0,ql=spells;ql;ql_advance(&ql, &qi, 1)) { + spell * sp = (spell *)ql_get(ql, qi); if (sp->magietyp == M_COMMON && level>f->max_spelllevel && sp->level<=level) { commonspells[numspells++] = sp; } else { if (know_school(f, sp->magietyp) && sp->level <= level) { - if (!has_spell(f->spellbook, sp)) { - add_spell(&f->spellbook, sp); - } + add_spell(&f->spellbook, sp); } } } @@ -442,7 +450,7 @@ update_spellbook(faction * f, int level) while (maxspell>0 && sp && sp->level<=f->max_spelllevel && !has_spell(f->spellbook, sp)); if (sp) { - add_spell(&f->spellbook, sp); + ql_set_insert(&f->spellbook, sp); commonspells[spellno] = 0; } } @@ -454,9 +462,11 @@ void updatespelllist(unit * u) { int sk = eff_skill(u, SK_MAGIC, u->region); - spell_list * slist = spells; + quicklist * ql = spells; + int qi; struct sc_mage * mage = get_mage(u); boolean ismonster = is_monsters(u->faction); + quicklist ** dst; if (mage->magietyp==M_GRAY) { /* Magier mit M_GRAY bekommen weder Sprüche angezeigt noch @@ -466,18 +476,19 @@ updatespelllist(unit * u) } if (FactionSpells()) { - slist = u->faction->spellbook; + ql = u->faction->spellbook; } + dst = get_spelllist(mage, u->faction); - for (;slist!=NULL;slist=slist->next) { - spell * sp = slist->data; + for (qi=0;ql;ql_advance(&ql, &qi, 1)) { + spell * sp = (spell *)ql_get(ql, qi); if (sp->level<=sk) { boolean know = u_hasspell(u, sp); if (know || sp->magietyp==M_COMMON || know_school(u->faction, sp->magietyp)) { faction * f = u->faction; - if (!know) add_spell(get_spelllist(mage, u->faction), sp); + if (!know) add_spell(dst, sp); if (!ismonster && !already_seen(u->faction, sp)) { a_add(&f->attribs, a_new(&at_reportspell))->data.v = sp; a_add(&f->attribs, a_new(&at_seenspell))->data.v = sp; @@ -511,39 +522,24 @@ create_mage(unit * u, magic_t mtyp) /* Funktionen für die Bearbeitung der List-of-known-spells */ void -add_spell(spell_list ** slistp, spell * sp) +add_spell(struct quicklist ** slistp, spell * sp) { - if (slistp==NULL) { - log_error(("add_spell: unit is not a mage.\n")); - } else { - spell_list ** slist = spelllist_find(slistp, sp); - if (*slist) { - spell * psp = (*slist)->data; - if (psp==sp) { - log_error(("add_spell: unit already has spell '%s'.\n", sp->sname)); - return; - } - } - spelllist_add(slist, sp); - } -} + quicklist * ql = *slistp; + int qi; -boolean -has_spell(spell_list * slist, const spell * sp) -{ - if (slist!=NULL) { - spell_list * sfind = *spelllist_find(&slist, sp); - return sfind!=NULL && sfind->data==sp; + if (ql_set_find(&ql, &qi, sp)) { + log_error(("add_spell: the list already contains the spell '%s'.\n", sp->sname)); + } else { + ql_set_insert(slistp, sp); } - return false; } boolean u_hasspell(const struct unit *u, const struct spell * sp) { sc_mage * mage = get_mage(u); - if (mage) return has_spell(mage->spells, sp); - return false; + + return (mage)?has_spell(mage->spells, sp):false; } /* ------------------------------------------------------------- */ @@ -2881,40 +2877,7 @@ curse_name(const curse_type * ctype, const struct locale * lang) return LOC(lang, mkname("spell", ctype->cname)); } -void -spelllist_add(spell_list ** lspells, spell * sp) -{ - spell_list * entry; - - while (*lspells) { - spell_list * slist = *lspells; - if (slist->data->id==sp->id) { - if (slist->data==sp) { - log_error(("trying to add spell '%s' to a list twice.\n", sp->sname)); - return; - } - } - if (slist->data->id>sp->id) break; - lspells = &slist->next; - } - entry = malloc(sizeof(spell_list)); - entry->data = sp; - entry->next = *lspells; - *lspells = entry; -} - -spell_list ** -spelllist_find(spell_list ** lspells, const spell * sp) -{ - while (*lspells) { - spell_list * slist = *lspells; - if (slist->data->id>=sp->id) break; - lspells = &slist->next; - } - return lspells; -} - -extern struct spell_list ** get_spelllist(struct sc_mage * mage, struct faction * f) +struct quicklist ** get_spelllist(struct sc_mage * mage, struct faction * f) { if (mage) { return &mage->spells; diff --git a/src/kernel/magic.h b/src/kernel/magic.h index 623c5f516..c3b65a038 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -25,6 +25,7 @@ extern "C" { #include "curse.h" struct fighter; struct building; +struct quicklist; /* ------------------------------------------------------------- */ @@ -123,7 +124,7 @@ typedef struct sc_mage { int spchange; int spellcount; combatspell combatspells[MAXCOMBATSPELLS]; - struct spell_list * spells; + struct quicklist * spells; } sc_mage; /* ------------------------------------------------------------- */ @@ -175,13 +176,6 @@ typedef struct spell { void (*patzer) (castorder*); } spell; -typedef struct spell_list { - struct spell_list * next; - spell * data; /* TODO: should be const */ -} spell_list; - -extern void spelllist_add(spell_list ** lspells, struct spell * sp); -extern spell_list ** spelllist_find(spell_list ** lspells, const struct spell * sp); /* ------------------------------------------------------------- */ /* besondere Spruchtypen */ @@ -282,10 +276,8 @@ void set_combatspell(struct unit *u, spell *sp, struct order * ord, int level); /* setzt Kampfzauber */ void unset_combatspell(struct unit *u, spell *sp); /* löscht Kampfzauber */ -void add_spell(spell_list ** slistp, spell *sp); +void add_spell(struct quicklist ** slistp, spell *sp); /* fügt den Spruch mit der Id spellid der Spruchliste der Einheit hinzu. */ -boolean has_spell(struct spell_list *slist, const struct spell * sp); - /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ boolean u_hasspell(const struct unit * u, const struct spell * sp); /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ void update_spellbook(struct faction * f, int level); @@ -383,10 +375,10 @@ extern const char * curse_name(const struct curse_type * ctype, const struct loc extern struct message * msg_unitnotfound(const struct unit * mage, struct order * ord, const struct spllprm * spobj); extern int FactionSpells(void); -extern struct spell_list ** get_spelllist(struct sc_mage * mage, struct faction * f); +extern struct quicklist ** get_spelllist(struct sc_mage * mage, struct faction * f); -extern void write_spelllist(const struct spell_list * slist, struct storage * store); -extern void read_spellist(struct spell_list ** slistp, magic_t mtype, struct storage * store); +extern void write_spells(struct quicklist * slist, struct storage * store); +extern void read_spells(struct quicklist ** slistp, magic_t mtype, struct storage * store); extern double MagicPower(void); #ifdef __cplusplus diff --git a/src/kernel/reports.c b/src/kernel/reports.c index 8ba41875b..c22c5f392 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -622,13 +622,13 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char * buf, siz sc_mage * m = get_mage(u); if (m!=NULL) { - spell_list *slist = m->spells; - int t = effskill(u, SK_MAGIC); + quicklist * ql = m->spells; + int qi, t = effskill(u, SK_MAGIC); int bytes = snprintf(bufp, size, ". Aura %d/%d", get_spellpoints(u), max_spellpoints(u->region,u)); if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - for (dh=0; slist; slist=slist->next) { - spell * sp = slist->data; + for (dh=0,qi=0; ql; ql_advance(&ql, &qi, 1)) { + spell * sp = (spell *)ql_get(ql, qi); if (sp->level > t) continue; if (!dh) { bytes = snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_spells")); diff --git a/src/kernel/save.c b/src/kernel/save.c index 19db607ce..17a17b685 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1288,7 +1288,7 @@ readfaction(struct storage * store) read_groups(store, f); f->spellbook = NULL; if (store->version>=REGIONOWNER_VERSION) { - read_spellist(&f->spellbook, f->magiegebiet, store); + read_spells(&f->spellbook, f->magiegebiet, store); } return f; } @@ -1352,7 +1352,7 @@ writefaction(struct storage * store, const faction * f) store->w_id(store, 0); store->w_brk(store); write_groups(store, f->groups); - write_spelllist(f->spellbook, store); + write_spells(f->spellbook, store); } int diff --git a/src/kernel/spell.c b/src/kernel/spell.c index 7bd05cf15..f48fdd0d5 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -33,12 +33,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include /* Bitte die Sprüche nach Gebieten und Stufe ordnen, denn in derselben * Reihenfolge wie in Spelldaten tauchen sie auch im Report auf */ -spell_list * spells = NULL; +quicklist * spells = NULL; void register_spell(spell * sp) @@ -46,7 +47,7 @@ register_spell(spell * sp) if (sp->id==0) { sp->id = hashstring(sp->sname); } - spelllist_add(&spells, sp); + add_spell(&spells, sp); } /** versucht einen Spruch über gebiet + name zu identifizieren. @@ -54,15 +55,16 @@ register_spell(spell * sp) spell * find_spell(magic_t mtype, const char * name) { - spell_list * slist = spells; + quicklist * ql = spells; + int qi; spell * spx = NULL; - while (slist) { - spell * sp = slist->data; + + for (qi=0;ql;ql_advance(&ql, &qi, 1)) { + spell * sp = (spell *)ql_get(ql, qi); if (strcmp(name, sp->sname)==0) { if (mtype==M_NONE || sp->magietyp==mtype) return sp; spx = sp; } - slist = slist->next; } if (spx==NULL) { log_error(("cannot find spell by name: %s\n", name)); @@ -86,13 +88,14 @@ static spell_names * spellnames; static spell_names * init_spellnames(const struct locale * lang, magic_t mtype) { - spell_list * slist; - spell_names * sn = calloc(sizeof(spell_names), 1); + quicklist * ql; + int qi; + spell_names * sn = (spell_names *)calloc(sizeof(spell_names), 1); sn->next = spellnames; sn->lang = lang; sn->mtype = mtype; - for (slist=spells;slist!=NULL;slist=slist->next) { - spell * sp = slist->data; + for (qi=0,ql=spells;ql;ql_advance(&ql, &qi, 1)) { + spell * sp = (spell *)ql_get(ql, qi); if (sp->magietyp==mtype) { const char * n = spell_name(sp, lang); variant token; @@ -147,11 +150,11 @@ get_spellfromtoken(unit *u, const char *name, const struct locale * lang) if (m==NULL) return NULL; sp = get_spellfromtoken_i(name, lang, m->magietyp); if (sp!=NULL) { - spell_list * slist = m->spells; + quicklist * ql = m->spells; + int qi; - while (slist && slist->data->id<=sp->id) { - if (sp==slist->data) return sp; - slist = slist->next; + if (ql_set_find(&ql, &qi, sp)) { + return sp; } } return NULL; @@ -160,16 +163,19 @@ get_spellfromtoken(unit *u, const char *name, const struct locale * lang) spell * find_spellbyid(magic_t mtype, spellid_t id) { - spell_list * slist; + quicklist * ql; + int qi; assert(id>=0); if (id==0) return NULL; - for (slist=spells;slist!=NULL;slist=slist->next) { - spell* sp = slist->data; - if (sp->id == id) return sp; + for (qi=0, ql=spells; ql; ql_advance(&ql, &qi, 1)) { + spell * sp = (spell *)ql_get(ql, qi); + if (sp->id == id) { + return sp; + } } - for (slist=spells;slist!=NULL;slist=slist->next) { - spell* sp = slist->data; + for (qi=0, ql=spells; ql; ql_advance(&ql, &qi, 1)) { + spell * sp = (spell *)ql_get(ql, qi); unsigned int hashid = hashstring(sp->sname); if (hashid==id) { if (sp->magietyp==mtype || mtype==M_NONE) { diff --git a/src/kernel/spell.h b/src/kernel/spell.h index 9a250deb0..4565d2053 100644 --- a/src/kernel/spell.h +++ b/src/kernel/spell.h @@ -42,7 +42,7 @@ extern "C" { extern struct attrib_type at_unitdissolve; extern struct attrib_type at_wdwpyramid; - extern struct spell_list * spells; + extern struct quicklist * spells; extern void register_spell(struct spell * sp); extern struct spell * find_spell(magic_t mtype, const char * name); extern struct spell * find_spellbyid(magic_t mtype, spellid_t i); diff --git a/src/util/quicklist.c b/src/util/quicklist.c index e3986eb75..215bb0065 100644 --- a/src/util/quicklist.c +++ b/src/util/quicklist.c @@ -147,6 +147,22 @@ void ql_free(struct quicklist * ql) free(ql); } +int ql_set_remove(struct quicklist ** qlp, void * data) +{ + int qi; + quicklist * ql = *qlp; + + if (!ql) return 0; + + for (qi=0;qi!=ql->num_elements;++qi) { + void * qd = ql_get(ql, qi); + if (qd==data) { + return ql_delete(qlp, qi)==0; + } + } + return ql_set_remove(&ql->next, data); +} + int ql_set_insert(struct quicklist ** qlp, void * data) { if (*qlp) { @@ -174,4 +190,31 @@ int ql_set_insert(struct quicklist ** qlp, void * data) } ql_push(qlp, data); return 0; -} \ No newline at end of file +} + +int ql_set_find(struct quicklist ** qlp, int * qip, const void * data) +{ + quicklist * ql = *qlp; + int qi; + + while (ql && ql->elements[ql->num_elements-1]next; + } + + if (!ql) return 0; + + /* TODO: OPT | binary search */ + for (qi=0;qi!=ql->num_elements;++qi) { + if (ql->elements[qi]>data) { + return 0; + } + if (ql->elements[qi]==data) { + if (qip) { + *qip = qi; + *qlp = ql; + } + return 1; + } + } + return 0; +} diff --git a/src/util/quicklist.h b/src/util/quicklist.h index cc7186a31..f3068de48 100644 --- a/src/util/quicklist.h +++ b/src/util/quicklist.h @@ -34,6 +34,9 @@ void ql_free(struct quicklist * ql); /* you can use it as a set (sorted pointers)*/ int ql_set_insert(struct quicklist ** qlp, void * data); +int ql_set_find(struct quicklist ** qlp, int * qip, const void * data); +int ql_set_remove(struct quicklist ** qlp, void * data); + #ifdef __cplusplus } #endif diff --git a/src/util/quicklist_test.c b/src/util/quicklist_test.c index bb82afa12..8dd677405 100644 --- a/src/util/quicklist_test.c +++ b/src/util/quicklist_test.c @@ -26,7 +26,7 @@ static void test_insert_delete_gives_null(CuTest * tc) { static void test_set_insert(CuTest * tc) { struct quicklist * ql = NULL; - int a; + int a, qi; a = ql_set_insert(&ql, (void*)42); CuAssertIntEquals(tc, 1, ql_length(ql)); CuAssertIntEquals(tc, 0, a); @@ -42,6 +42,64 @@ static void test_set_insert(CuTest * tc) { CuAssertIntEquals(tc, 41, (int)ql_get(ql, 0)); CuAssertIntEquals(tc, 42, (int)ql_get(ql, 1)); CuAssertIntEquals(tc, 43, (int)ql_get(ql, 2)); + + a = ql_set_find(&ql, &qi, (void *)49); + CuAssertIntEquals(tc, 0, a); + a = ql_set_find(&ql, &qi, (void *)42); + CuAssertIntEquals(tc, 1, a); + CuAssertIntEquals(tc, 42, (int)ql_get(ql, qi)); +} + +static void test_set_remove(CuTest * tc) { + struct quicklist * ql = NULL, * q2; + int a; + + ql_set_insert(&ql, (void*)41); + ql_set_insert(&ql, (void*)42); + ql_set_insert(&ql, (void*)43); + + q2 = ql; + + a = ql_set_remove(&ql, (void*)42); + CuAssertPtrEquals(tc, q2, ql); + CuAssertIntEquals(tc, 1, a); + CuAssertIntEquals(tc, 41, (int)ql_get(ql, 0)); + CuAssertIntEquals(tc, 43, (int)ql_get(ql, 1)); + CuAssertIntEquals(tc, 2, ql_length(ql)); + + a = ql_set_remove(&ql, (void*)42); + CuAssertPtrEquals(tc, q2, ql); + CuAssertIntEquals(tc, 0, a); + + ql_set_remove(&ql, (void*)41); + ql_set_remove(&ql, (void*)43); + CuAssertPtrEquals(tc, 0, ql); +} + +static void test_set_find(CuTest * tc) { + struct quicklist * ql = NULL, * q2; + int a, qi; + + for (a=0;a!=32;++a) { + ql_set_insert(&ql, (void *)a); + } + + q2 = ql; + a = ql_set_find(&q2, 0, (void *)31); + CuAssertIntEquals(tc, 1, a); + CuAssertPtrEquals(tc, ql, q2); + + q2 = ql; + a = ql_set_find(&ql, &qi, (void *)0); + CuAssertIntEquals(tc, 1, a); + CuAssertIntEquals(tc, 0, qi); + CuAssertPtrEquals(tc, ql, q2); + + q2 = ql; + a = ql_set_find(&ql, &qi, (void *)31); + CuAssertIntEquals(tc, 1, a); + CuAssertIntEquals(tc, 31, (int)ql_get(ql, qi)); + CuAssertTrue(tc, ql!=q2); } static void test_advance(CuTest * tc) { @@ -111,6 +169,8 @@ CuSuite* get_quicklist_suite(void) SUITE_ADD_TEST(suite, test_advance); SUITE_ADD_TEST(suite, test_push); SUITE_ADD_TEST(suite, test_insert); + SUITE_ADD_TEST(suite, test_set_remove); + SUITE_ADD_TEST(suite, test_set_find); SUITE_ADD_TEST(suite, test_insert_delete_gives_null); SUITE_ADD_TEST(suite, test_insert_many); SUITE_ADD_TEST(suite, test_delete_rand); From 2e67e9c290822ec0615bf4207654e9a56d3218e1 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 Feb 2011 09:33:20 +0100 Subject: [PATCH 069/400] gcc wants us to define this struct, and that's correct --- src/bindings/bindings.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bindings/bindings.h b/src/bindings/bindings.h index 4cca8fee4..a289a9d90 100644 --- a/src/bindings/bindings.h +++ b/src/bindings/bindings.h @@ -15,6 +15,8 @@ extern "C" { #endif struct lua_State; + struct quicklist; + int tolua_sqlite_open(struct lua_State * L); int tolua_eressea_open(struct lua_State* L); int tolua_spelllist_next(struct lua_State *L); From 4fa45d64499e9f975ffb8920a53183693356fbb1 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 Feb 2011 10:21:10 +0100 Subject: [PATCH 070/400] tcc support added --- src/build/util.c | 1 + src/gmtool.h | 2 +- src/platform.h | 6 ++++++ src/util/bsdstring.h | 4 ---- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/build/util.c b/src/build/util.c index c9a6897aa..aacf33927 100644 --- a/src/build/util.c +++ b/src/build/util.c @@ -34,6 +34,7 @@ #ifndef HAVE_INLINE #include +#include #endif #ifdef __GNUC__ diff --git a/src/gmtool.h b/src/gmtool.h index 1912e03ee..f0bbd6d86 100644 --- a/src/gmtool.h +++ b/src/gmtool.h @@ -26,7 +26,7 @@ extern "C" { void select_coordinate(struct selection * selected, int x, int y, int on); void run_mapper(void); - int force_color; + extern int force_color; struct state * state_open(void); void state_close(struct state * ); diff --git a/src/platform.h b/src/platform.h index 721006b7b..e8b988885 100644 --- a/src/platform.h +++ b/src/platform.h @@ -133,6 +133,12 @@ typedef struct stat stat_type; # define HAVE_MKDIR_WITH_PERMISSION #endif +/* TinyCC */ +#ifdef TINYCC +# undef HAVE_INLINE +# define INLINE_FUNCTION +#endif + /* lcc-win32 */ #ifdef __LCC__ # include diff --git a/src/util/bsdstring.h b/src/util/bsdstring.h index ca0e94188..90feb2165 100644 --- a/src/util/bsdstring.h +++ b/src/util/bsdstring.h @@ -9,10 +9,6 @@ extern int wrptr(char ** ptr, size_t * size, int bytes); #endif -#if !defined(HAVE_STRLCPY) -# define HAVE_STRLCPY -#endif - #define WARN_STATIC_BUFFER() log_warning(("static buffer too small in %s:%d\n", __FILE__, __LINE__)) #if !defined(HAVE_STRLPRINTF) From 665d4aec4d46ad43c11880eda893b18e408553b5 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 Feb 2011 10:07:49 -0800 Subject: [PATCH 071/400] Test framework broken, we were adding the wrong spell with the right name. --- src/bindings/bind_unit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 186950b9c..1a7289326 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -509,7 +509,7 @@ static void unit_addspell(unit * u, const char * name) { sc_mage * m = get_mage(u); - spell * spadd = find_spell(M_NONE, name); + spell * spadd = find_spell(m->magietyp, name); if (!spadd) log_error(("spell %s could not be found\n", name)); else { From 611fe8e2a10578c046b67b998debae50bb527b80 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 Feb 2011 22:55:27 -0800 Subject: [PATCH 072/400] adding a os module for os-specific functions (mkdir in this case). --- src/build/util.c | 3 ++- src/gamecode/study.c | 2 +- src/kernel/battle.c | 3 ++- src/kernel/reports.c | 3 ++- src/kernel/save.c | 7 ++++++- src/platform.h | 16 ---------------- src/util.vcxproj | 2 ++ src/util.vcxproj.filters | 6 ++++++ src/util/os.c | 17 +++++++++++++++++ src/util/os.h | 29 +++++++++++++++++++++++++++++ 10 files changed, 67 insertions(+), 21 deletions(-) create mode 100644 src/util/os.c create mode 100644 src/util/os.h diff --git a/src/build/util.c b/src/build/util.c index aacf33927..012c557da 100644 --- a/src/build/util.c +++ b/src/build/util.c @@ -19,11 +19,12 @@ #include #include #include -#include #include #include #include +#include #include +#include #include #include #include diff --git a/src/gamecode/study.c b/src/gamecode/study.c index 36fda0217..2fbcb270e 100644 --- a/src/gamecode/study.c +++ b/src/gamecode/study.c @@ -589,7 +589,7 @@ learn_cmd(unit * u, order * ord) struct building * b = inside_building(u); const struct building_type * btype = b?b->type:NULL; - if (btype == bt_find("academy")) { + if (btype && btype == bt_find("academy")) { studycost = MAX(50, studycost * 2); } } diff --git a/src/kernel/battle.c b/src/kernel/battle.c index 0aaa0e840..3d8747c61 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -59,6 +59,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include @@ -3575,7 +3576,7 @@ make_battle(region * r) char zText[MAX_PATH]; char zFilename[MAX_PATH]; sprintf(zText, "%s/battles", basepath()); - makedir(zText, 0700); + os_mkdir(zText, 0700); sprintf(zFilename, "%s/battle-%d-%s.log", zText, obs_count, simplename(r)); bdebug = fopen(zFilename, "w"); if (!bdebug) log_error(("battles cannot be debugged\n")); diff --git a/src/kernel/reports.c b/src/kernel/reports.c index c22c5f392..0cca313b4 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -51,6 +51,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include /* libc includes */ @@ -1491,7 +1492,7 @@ init_reports(void) if (stat(reportpath(), &st)==0) return 0; } #endif - if (makedir(reportpath(), 0700)!=0) { + if (os_mkdir(reportpath(), 0700)!=0) { if (errno!=EEXIST) { perror("could not create reportpath"); return -1; diff --git a/src/kernel/save.c b/src/kernel/save.c index 17a17b685..7dedc93b1 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -61,6 +61,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include @@ -1683,7 +1684,11 @@ writegame(const char *filename, int mode) store->encoding = enc_gamedata; if (store->open(store, path, IO_WRITE)!=0) { - return -1; + int err = os_mkdir(datapath(), 0700); + if (err) return err; + if (store->open(store, path, IO_WRITE)!=0) { + return -1; + } } /* globale Variablen */ diff --git a/src/platform.h b/src/platform.h index e8b988885..96903dde7 100644 --- a/src/platform.h +++ b/src/platform.h @@ -120,19 +120,12 @@ typedef struct stat stat_type; # define HAVE_SNPRINTF #ifdef _POSIX_SOURCE /* MINGW doesn't seem to have these */ # define HAVE_EXECINFO -# define HAVE_MKDIR_WITH_PERMISSION # define HAVE_SIGACTION # define HAVE_LINK # define HAVE_SLEEP #endif #endif -/* egcpp 4 dos */ -#ifdef MSDOS -# include -# define HAVE_MKDIR_WITH_PERMISSION -#endif - /* TinyCC */ #ifdef TINYCC # undef HAVE_INLINE @@ -211,15 +204,6 @@ typedef struct _stat stat_type; # endif #endif -#ifdef HAVE_MKDIR_WITH_PERMISSION -# define makedir(d, p) mkdir(d, p) -#elif defined(HAVE_MKDIR_WITHOUT_PERMISSION) -# define makedir(d, p) mkdir(d) -#elif defined(HAVE__MKDIR_WITHOUT_PERMISSION) -_CRTIMP int __cdecl _mkdir(const char *); -# define makedir(d, p) _mkdir(d) -#endif - #ifndef HAVE_STRDUP extern char * strdup(const char *s); #endif diff --git a/src/util.vcxproj b/src/util.vcxproj index 02c556a66..027e10ae6 100644 --- a/src/util.vcxproj +++ b/src/util.vcxproj @@ -107,6 +107,7 @@ + @@ -142,6 +143,7 @@ + diff --git a/src/util.vcxproj.filters b/src/util.vcxproj.filters index 726f4856e..f1e5a7d17 100644 --- a/src/util.vcxproj.filters +++ b/src/util.vcxproj.filters @@ -110,6 +110,9 @@ Header Files + + Source Files + @@ -208,5 +211,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/src/util/os.c b/src/util/os.c new file mode 100644 index 000000000..6360869d0 --- /dev/null +++ b/src/util/os.c @@ -0,0 +1,17 @@ +#include "os.h" + +#if defined(WIN32) +#include +#elif defined(__GCC__) +#include +#endif + +int os_mkdir(const char * path, int mode) +{ +#ifdef WIN32 + mode = mode; + return _mkdir(path); +#else /* POSIX is our last hope */ + return mkdir(path, (mode_t)mode); +#endif +} \ No newline at end of file diff --git a/src/util/os.h b/src/util/os.h new file mode 100644 index 000000000..64e17e5e9 --- /dev/null +++ b/src/util/os.h @@ -0,0 +1,29 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef _OS_H +#define _OS_H +#ifdef __cplusplus +extern "C" { +#endif + + extern int os_mkdir(const char * path, int mode); +#ifdef __cplusplus +} +#endif +#endif From c810b7284562bd86c502017384e7bda30c179c85 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 Feb 2011 22:57:42 -0800 Subject: [PATCH 073/400] Some test requires that a cart exists. Meropis gets its own list of items. --- res/common/items.xml | 8 -------- res/common/resources.xml | 6 +++++- res/resources/cart.xml | 8 ++++++++ scripts/tests/bson.lua | 8 +++++--- scripts/tests/common.lua | 4 ++++ 5 files changed, 22 insertions(+), 12 deletions(-) create mode 100644 res/resources/cart.xml diff --git a/res/common/items.xml b/res/common/items.xml index 7c57a8184..2a96de46d 100644 --- a/res/common/items.xml +++ b/res/common/items.xml @@ -121,14 +121,6 @@ - - - - - - - - diff --git a/res/common/resources.xml b/res/common/resources.xml index bc39933e6..91d0e8afc 100644 --- a/res/common/resources.xml +++ b/res/common/resources.xml @@ -1,7 +1,11 @@ - + + diff --git a/res/resources/cart.xml b/res/resources/cart.xml new file mode 100644 index 000000000..a72b222d3 --- /dev/null +++ b/res/resources/cart.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/scripts/tests/bson.lua b/scripts/tests/bson.lua index 35b08051c..a7c12d75c 100644 --- a/scripts/tests/bson.lua +++ b/scripts/tests/bson.lua @@ -22,13 +22,15 @@ function test_illegal_arg() end function test_bson_readwrite() - local r = region.create(0, 0, "mountain") + local i, r = region.create(0, 0, "mountain") attrib.create(r, 42) - write_game("test_read_write.dat") + i = write_game("test_read_write.dat") + assert_equal(0, i) free_game() r = get_region(0, 0) assert_equal(nil, r) - read_game("test_read_write.dat") + i = read_game("test_read_write.dat") + assert_equal(0, i) r = get_region(0, 0) assert_not_equal(nil, r) for a in attrib.get(r) do diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index f15eb8164..c2cfabe8c 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -717,8 +717,11 @@ function test_ride_with_horses_and_cart() local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r, 1) u:add_item("cart", 1) + assert_equal(1, u:get_item("cart")) -- every game has a cart, right? right? u:add_item("horse", 2) + assert_equal(2, u:get_item("horse")) -- every game has a horse, right? right? u:add_item("sword", 120) + assert_equal(120, u:get_item("sword")) -- every game has a sword, right? and it weighs 1 unit? u:set_skill("riding", 3) -- ride @@ -824,6 +827,7 @@ module("tests.parser", package.seeall, lunit.testcase) function setup() free_game() + settings.set("rules.economy.food", "4") -- FOOD_IS_FREE end function test_parser() From 916e5389c74042d8fd9744981245152a46780ee4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 27 Feb 2011 08:01:23 +0100 Subject: [PATCH 074/400] include the correct header on linux --- src/util/os.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/os.c b/src/util/os.c index 6360869d0..263b44e42 100644 --- a/src/util/os.c +++ b/src/util/os.c @@ -2,7 +2,7 @@ #if defined(WIN32) #include -#elif defined(__GCC__) +#else #include #endif @@ -14,4 +14,4 @@ int os_mkdir(const char * path, int mode) #else /* POSIX is our last hope */ return mkdir(path, (mode_t)mode); #endif -} \ No newline at end of file +} From cc9e95a2abd3f140f4ad13be4a8b23d02caa87a5 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 Feb 2011 23:21:12 -0800 Subject: [PATCH 075/400] spells.lua is a bad file for example and meropis, it tests things that not every game has. lua_pushinteger() must be new, I've never used it before. all tests in meropis and example pass. --- scripts/tests/spells.lua | 79 +++++++++++++++++++++------------------- src/bindings/bind_unit.c | 55 +++++++++++++++------------- 2 files changed, 72 insertions(+), 62 deletions(-) diff --git a/scripts/tests/spells.lua b/scripts/tests/spells.lua index 141a6d8bd..bad60c192 100644 --- a/scripts/tests/spells.lua +++ b/scripts/tests/spells.lua @@ -13,52 +13,57 @@ function test_roi() u.race = "elf" u:set_skill("magic", 10) u:add_item("money", 3010) + u:add_item("roi", 1) + assert_equal(1, u:get_item("roi")) u.magic = "tybied" u.aura = 200 u.ship = s1 - u:add_spell("create_roi") + local err = u:add_spell("create_roi") + assert_equal(0, err) u:clear_orders() u:add_order("ZAUBERE 'Erschaffe einen Ring der Unsichtbarkeit' ") process_orders() write_reports() - assert_equal(1, u:get_item("roi")) + assert_equal(2, u:get_item("roi")) end function test_blessedharvest_lasts_n_turn() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "halfling", "de") - local u = unit.create(f, r) - r:set_resource("peasant", 100) - r:set_resource("money", 0) - u:add_item("money", 1000) - u.magic = "gwyrrd" - u.race = "dwarf" - u:set_skill("magic", 20) - u.aura = 200 - u:add_spell("raindance") - u:add_spell("blessedharvest") - u:clear_orders() - local level = 5 - u:add_order("ZAUBERE STUFE " .. level .. " Regentanz") - assert_equal(0, r:get_resource("money"), 0) - - local m = 0 - local p = 100 - for i=1,level+2 do - process_orders() - local income = p * 12 - p = r:get_resource("peasant") - income = income - p * 10 - m = m + income - -- print(i, m, p, r:get_resource("money")) - if (i>level+1) then - assert_not_equal(m, r:get_resource("money")) - else - assert_equal(m, r:get_resource("money")) - end + free_game() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "halfling", "de") + local u = unit.create(f, r) + local err = 0 + r:set_resource("peasant", 100) + r:set_resource("money", 0) + u:add_item("money", 1000) + u.magic = "gwyrrd" + u.race = "dwarf" + u:set_skill("magic", 20) + u.aura = 200 + err = err + u:add_spell("raindance") + err = err + u:add_spell("blessedharvest") + assert_equal(0, err) + u:clear_orders() - u:add_order("ARBEITEN") --- u:add_spell("raindance") - end + local level = 5 + u:add_order("ZAUBERE STUFE " .. level .. " Regentanz") + assert_equal(0, r:get_resource("money"), 0) + + local m = 0 + local p = 100 + for i=1,level+2 do + process_orders() + local income = p * 12 + p = r:get_resource("peasant") + income = income - p * 10 + m = m + income + -- print(i, m, p, r:get_resource("money")) + if (i>level+1) then + assert_not_equal(m, r:get_resource("money")) + else + assert_equal(m, r:get_resource("money")) + end + u:clear_orders() + u:add_order("ARBEITEN") + end end diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 1a7289326..80a264fca 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -48,8 +48,9 @@ without prior permission by the authors of Eressea. #include #include -#include #include +#include +#include static int tolua_unit_get_objects(lua_State* L) @@ -168,7 +169,7 @@ static int tolua_unit_set_info(lua_State* L) static int tolua_unit_get_id(lua_State* L) { unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)unit_getid(self)); + lua_pushinteger(L, unit_getid(self)); return 1; } @@ -182,14 +183,14 @@ static int tolua_unit_set_id(lua_State* L) static int tolua_unit_get_hpmax(lua_State* L) { unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)unit_max_hp(self)); + lua_pushinteger(L, unit_max_hp(self)); return 1; } static int tolua_unit_get_hp(lua_State* L) { unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)unit_gethp(self)); + lua_pushinteger(L, unit_gethp(self)); return 1; } @@ -203,7 +204,7 @@ static int tolua_unit_set_hp(lua_State* L) static int tolua_unit_get_number(lua_State* L) { unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->number); + lua_pushinteger(L, self->number); return 1; } @@ -223,7 +224,7 @@ static int tolua_unit_set_number(lua_State* L) static int tolua_unit_get_flags(lua_State* L) { unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->flags); + lua_pushinteger(L, self->flags); return 1; } @@ -273,7 +274,7 @@ static int tolua_unit_set_magic(lua_State* L) static int tolua_unit_get_aura(lua_State* L) { unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)get_spellpoints(self)); + lua_pushinteger(L, get_spellpoints(self)); return 1; } @@ -287,7 +288,7 @@ static int tolua_unit_set_aura(lua_State* L) static int tolua_unit_get_age(lua_State* L) { unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->age); + lua_pushinteger(L, self->age); return 1; } @@ -301,7 +302,7 @@ static int tolua_unit_set_age(lua_State* L) static int tolua_unit_get_status(lua_State* L) { unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)unit_getstatus(self)); + lua_pushinteger(L, unit_getstatus(self)); return 1; } @@ -325,7 +326,7 @@ tolua_unit_get_item(lua_State* L) result = i_get(self->items, itype); } } - tolua_pushnumber(L, (lua_Number)result); + lua_pushinteger(L, result); return 1; } @@ -344,7 +345,7 @@ tolua_unit_add_item(lua_State* L) result = i?i->number:0; } } - lua_pushnumber(L, (lua_Number)result); + lua_pushinteger(L, result); return 1; } @@ -362,7 +363,7 @@ tolua_unit_getskill(lua_State* L) } else value = 0; } - lua_pushnumber(L, (lua_Number)value); + lua_pushinteger(L, value); return 1; } @@ -373,7 +374,7 @@ tolua_unit_effskill(lua_State* L) const char * skname = tolua_tostring(L, 2, 0); skill_t sk = sk_find(skname); int value = (sk==NOSKILL)?-1:eff_skill(self, sk, self->region); - lua_pushnumber(L, (lua_Number)value); + lua_pushinteger(L, value); return 1; } @@ -505,17 +506,20 @@ tolua_unit_castspell(lua_State* L) return 0; } -static void +static int unit_addspell(unit * u, const char * name) { sc_mage * m = get_mage(u); spell * spadd = find_spell(m->magietyp, name); - if (!spadd) log_error(("spell %s could not be found\n", name)); - else { + if (!spadd) { + log_error(("spell %s could not be found\n", name)); + return EINVAL; + } else { quicklist ** starget = get_spelllist(m, u->faction); add_spell(starget, spadd); } + return 0; } static int @@ -523,8 +527,9 @@ tolua_unit_addspell(lua_State* L) { unit* self = (unit*)tolua_tousertype(L, 1, 0); const char * str = tolua_tostring(L, 2, 0); - unit_addspell(self, str); - return 0; + int err = unit_addspell(self, str); + lua_pushinteger(L, err); + return 1; } static void @@ -579,7 +584,7 @@ tolua_unit_setskill(lua_State* L) } else { level = -1; } - lua_pushnumber(L, (lua_Number)level); + lua_pushinteger(L, level); return 1; } @@ -594,7 +599,7 @@ tolua_unit_use_pooled(lua_State* L) if (rtype!=NULL) { result = use_pooled(self, rtype, GET_DEFAULT, number); } - lua_pushnumber(L, (lua_Number)result); + lua_pushinteger(L, result); return 1; } @@ -608,7 +613,7 @@ tolua_unit_get_pooled(lua_State* L) if (rtype!=NULL) { result = get_pooled(self, rtype, GET_DEFAULT, INT_MAX); } - lua_pushnumber(L, (lua_Number)result); + lua_pushinteger(L, result); return 1; } @@ -800,14 +805,14 @@ static int tolua_unit_set_flag(lua_State* L) static int tolua_unit_get_weight(lua_State* L) { unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)unit_getweight(self)); + lua_pushinteger(L, unit_getweight(self)); return 1; } static int tolua_unit_get_capacity(lua_State* L) { unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)unit_getcapacity(self)); + lua_pushinteger(L, unit_getcapacity(self)); return 1; } @@ -905,9 +910,9 @@ tolua_event_get(lua_State *L) if (strcmp(arg->type, "string")==0) { tolua_pushstring(L, (const char *)arg->data.v); } else if (strcmp(arg->type, "int")==0) { - tolua_pushnumber(L, (lua_Number)arg->data.i); + lua_pushinteger(L, arg->data.i); } else if (strcmp(arg->type, "float")==0) { - tolua_pushnumber(L, (lua_Number)arg->data.f); + lua_pushnumber(L, (lua_Number)arg->data.f); } else { /* this is pretty lazy */ tolua_pushusertype(L, (void*)arg->data.v, TOLUA_CAST arg->type); From 59f3ebef68540188c6198c0d8e2d016cfe73bec4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 27 Feb 2011 08:51:17 +0100 Subject: [PATCH 076/400] fix some tests --- scripts/tests/common.lua | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index c2cfabe8c..09081d42a 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -29,6 +29,7 @@ module("tests.common", package.seeall, lunit.testcase) function setup() free_game() + write_game("free.dat") settings.set("nmr.removenewbie", "0") settings.set("nmr.timeout", "0") settings.set("rules.economy.food", "4") @@ -513,7 +514,8 @@ function test_store_unit() local u = unit.create(f, r, 1) local fid = f.id u:add_item("money", u.number * 100) - store = storage.create("test.unit.dat", "wb") + local filename = config.basepath .. "/data/test.unit.dat" + store = storage.create(filename, "wb") assert_not_equal(store, nil) store:write_unit(u) store:close() @@ -522,8 +524,8 @@ function test_store_unit() r = region.create(0, 0, "plain") f = faction.create("noreply@eressea.de", "human", "de") f.id = fid - store = storage.create("test.unit.dat", "rb") - assert(store) + store = storage.create(filename, "rb") + assert_not_nil(store) u = store:read_unit() store:close() assert(u) @@ -776,6 +778,7 @@ local function find_in_report(f, pattern, extension) extension = extension or "nr" local filename = config.basepath .. "/reports/" .. get_turn() .. "-" .. itoa36(f.id) .. "." .. extension local report = io.open(filename, 'rt'); + assert_not_nil(report) t = report:read("*all") report:close() @@ -827,6 +830,7 @@ module("tests.parser", package.seeall, lunit.testcase) function setup() free_game() + write_game("free.dat") settings.set("rules.economy.food", "4") -- FOOD_IS_FREE end @@ -834,9 +838,10 @@ function test_parser() local r = region.create(0, 0, "mountain") local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r, 1) - local filename = "1814.txt" + local filename = config.basepath .. "/data/orders.txt" local file = io.open(filename, "w+") + assert_not_nil(file) file:write('ERESSEA ' .. itoa36(f.id) .. ' "' .. f.password .. '"\n') file:write('EINHEIT ' .. itoa36(u.id) .. "\n") file:write("LERNEN Hiebwaffen\n") @@ -852,7 +857,7 @@ function test_bug_1814() local r = region.create(0, 0, "mountain") local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r, 1) - local filename = "1814.txt" + local filename = config.basepath .. "/data/1814.txt" local file = io.open(filename, "w+") file:write('ERESSEA ' .. itoa36(f.id) .. ' "' .. f.password .. '"\n') @@ -873,7 +878,7 @@ function test_bug_1679() local r = region.create(0, 0, "mountain") local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r, 1) - local filename = "1814.txt" + local filename = config.basepath .. "/data/1679.txt" local file = io.open(filename, "w+") file:write('ERESSEA ' .. itoa36(f.id) .. ' "' .. f.password .. '"\n') From ca2556c618edd30d95540ce4009a37ee97406495 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 Feb 2011 23:52:28 -0800 Subject: [PATCH 077/400] fix a segmentation fault when file cannot be opened --- src/bindings/bind_storage.c | 8 +++++--- src/kernel/binarystore.c | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/bindings/bind_storage.c b/src/bindings/bind_storage.c index 23b9a0a5a..a8914a5cb 100644 --- a/src/bindings/bind_storage.c +++ b/src/bindings/bind_storage.c @@ -58,9 +58,11 @@ tolua_storage_read_unit(lua_State *L) static int tolua_storage_write_unit(lua_State *L) { - storage * self = (storage *)tolua_tousertype(L, 1, 0); + storage * store = (storage *)tolua_tousertype(L, 1, 0); struct unit * u = (struct unit *)tolua_tousertype(L, 2, 0); - write_unit(self, u); + if (store->version) { + write_unit(store, u); + } return 0; } @@ -87,7 +89,7 @@ static int tolua_storage_write(lua_State *L) { storage * self = (storage *)tolua_tousertype(L, 1, 0); - if (tolua_isnumber(L, 2, 0, 0)) { + if (self->version && tolua_isnumber(L, 2, 0, 0)) { lua_Number num = tolua_tonumber(L, 2, 0); double n; if (modf(num, &n)==0.0) { diff --git a/src/kernel/binarystore.c b/src/kernel/binarystore.c index 13780c981..3c35183bc 100644 --- a/src/kernel/binarystore.c +++ b/src/kernel/binarystore.c @@ -264,6 +264,7 @@ bin_open(struct storage * store, const char * filename, int mode) store->w_int = bin_w_int; } } else if (store->encoding==XML_CHAR_ENCODING_UTF8) { + store->version = RELEASE_VERSION; bin_w_int(store, RELEASE_VERSION); bin_w_int(store, STREAM_VERSION); } From 12c3324850de242cf5add5d9fcd4b76fd4c5cf58 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 27 Feb 2011 00:11:34 -0800 Subject: [PATCH 078/400] When running --tests, messages cannot be created (externally defined), so that isn't an error we are interested in. --- src/kernel/message.c | 2 +- src/tests.c | 4 ++++ src/util/log.c | 24 ++++++++++++------------ 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/kernel/message.c b/src/kernel/message.c index 67ccadfa3..3bcf10e64 100644 --- a/src/kernel/message.c +++ b/src/kernel/message.c @@ -140,7 +140,7 @@ msg_message(const char * name, const char* sig, ...) memset(args, 0, sizeof(args)); if (!mtype) { - log_error(("trying to create message of unknown type \"%s\"\n", name)); + log_warning(("trying to create message of unknown type \"%s\"\n", name)); if (strcmp(name, "missing_message")!=0) { return msg_message("missing_message", "name", name); } diff --git a/src/tests.c b/src/tests.c index 5a7695c97..ca5497d25 100644 --- a/src/tests.c +++ b/src/tests.c @@ -24,7 +24,9 @@ CuSuite* get_laws_suite(void); int RunAllTests(void) { CuString *output = CuStringNew(); CuSuite* suite = CuSuiteNew(); + int flags = log_flags; + log_flags = LOG_FLUSH|LOG_CPERROR; init_resources(); CuSuiteAddSuite(suite, get_base36_suite()); @@ -37,6 +39,8 @@ int RunAllTests(void) { CuSuiteSummary(suite, output); CuSuiteDetails(suite, output); printf("%s\n", output->buffer); + + log_flags = flags; return suite->failCount; } diff --git a/src/util/log.c b/src/util/log.c index 7b5b22ff6..93203d54a 100644 --- a/src/util/log.c +++ b/src/util/log.c @@ -161,19 +161,19 @@ check_dupe(const char * format, const char * type) void _log_warn(const char * format, ...) { - int dupe = check_dupe(format, "WARNING"); + if (log_flags & LOG_CPWARNING) { + int dupe = check_dupe(format, "WARNING"); - fflush(stdout); - if (!logfile) logfile = stderr; - if (logfile!=stderr) { - va_list marker; - fputs("WARNING: ", logfile); - va_start(marker, format); - vfprintf(logfile, format, marker); - va_end(marker); - } - if (!dupe) { - if (log_flags & LOG_CPWARNING) { + fflush(stdout); + if (!logfile) logfile = stderr; + if (logfile!=stderr) { + va_list marker; + fputs("WARNING: ", logfile); + va_start(marker, format); + vfprintf(logfile, format, marker); + va_end(marker); + } + if (!dupe) { va_list marker; fputs("WARNING: ", stderr); va_start(marker, format); From 2e547d6ae8c59e5861c7109b1e4753ce9c1bb3e8 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 27 Feb 2011 00:36:38 -0800 Subject: [PATCH 079/400] put spoils code into the open source parts of the code. reduce number of races in Meropis --- scripts/tests/common.lua | 4 ++-- src/kernel/item.c | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 09081d42a..a33f47dbf 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -21,7 +21,7 @@ end local function two_factions() local f1 = faction.create("noreply@eressea.de", "human", "de") - local f2 = faction.create("noreply@eressea.de", "orc", "de") + local f2 = faction.create("noreply@eressea.de", "elf", "de") return f1, f2 end @@ -266,7 +266,7 @@ function test_events() plain = region.create(0, 0, "plain") skill = 8 - f = faction.create("noreply@eressea.de", "orc", "de") + f = faction.create("noreply@eressea.de", "elf", "de") f.age = 20 u = unit.create(f, plain) diff --git a/src/kernel/item.c b/src/kernel/item.c index d68808d8f..7886d88c8 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -1155,6 +1155,24 @@ attrib_type at_resourcelimit = { finalize_resourcelimit, }; +static item * +default_spoil(const struct race * rc, int size) +{ + item * itm = NULL; + + if (rng_int()%100 < RACESPOILCHANCE) { + char spoilname[32]; + const item_type * itype; + + sprintf(spoilname, "%sspoil", rc->_name[0]); + itype = it_find(spoilname); + if (itype!=NULL) { + i_add(&itm, i_new(itype, size)); + } + } + return itm; +} + void register_resources(void) { @@ -1166,6 +1184,7 @@ register_resources(void) register_function((pf_generic)res_changepermaura, "changepermaura"); register_function((pf_generic)res_changehp, "changehp"); register_function((pf_generic)res_changeaura, "changeaura"); + register_function((pf_generic)default_spoil, "defaultdrops"); register_item_use(use_potion, "usepotion"); register_item_use(use_potion_delayed, "usepotion_delayed"); From 10e64c59e1af203cab71c5428a8bc93e2555d267 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 27 Feb 2011 02:57:28 -0800 Subject: [PATCH 080/400] Some old files that weren't in use. Goodbye. --- src/build/util.c | 1 - src/kernel/config.c | 5 - src/util.vcxproj | 4 - src/util.vcxproj.filters | 12 -- src/util/argstack.c | 66 ----------- src/util/argstack.h | 27 ----- src/util/patricia.c | 236 --------------------------------------- src/util/patricia.h | 21 ---- src/util/vmap.c | 146 ------------------------ src/util/vmap.h | 47 -------- src/util/vset.c | 104 ----------------- src/util/vset.h | 43 ------- src/util/windir.c | 56 ---------- src/util/windir.h | 50 --------- 14 files changed, 818 deletions(-) delete mode 100644 src/util/argstack.c delete mode 100644 src/util/argstack.h delete mode 100644 src/util/patricia.c delete mode 100644 src/util/patricia.h delete mode 100644 src/util/vmap.c delete mode 100644 src/util/vmap.h delete mode 100644 src/util/vset.c delete mode 100644 src/util/vset.h delete mode 100644 src/util/windir.c delete mode 100644 src/util/windir.h diff --git a/src/build/util.c b/src/build/util.c index 012c557da..5a37a6463 100644 --- a/src/build/util.c +++ b/src/build/util.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff --git a/src/kernel/config.c b/src/kernel/config.c index 4423ad467..c310d9703 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -86,11 +86,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -#define PTRIES 0 /* it turns out they are slow :-( */ -#if PTRIES -#include -#endif - struct settings global = { "Eressea", /* gamename */ }; diff --git a/src/util.vcxproj b/src/util.vcxproj index 027e10ae6..d21e79368 100644 --- a/src/util.vcxproj +++ b/src/util.vcxproj @@ -87,7 +87,6 @@ - @@ -109,7 +108,6 @@ - @@ -123,7 +121,6 @@ - @@ -145,7 +142,6 @@ - diff --git a/src/util.vcxproj.filters b/src/util.vcxproj.filters index f1e5a7d17..7ef937c10 100644 --- a/src/util.vcxproj.filters +++ b/src/util.vcxproj.filters @@ -11,9 +11,6 @@ - - Header Files - Header Files @@ -74,9 +71,6 @@ Header Files - - Header Files - Header Files @@ -115,9 +109,6 @@ - - Source Files - Source Files @@ -178,9 +169,6 @@ Source Files - - Source Files - Source Files diff --git a/src/util/argstack.c b/src/util/argstack.c deleted file mode 100644 index 614a18def..000000000 --- a/src/util/argstack.c +++ /dev/null @@ -1,66 +0,0 @@ -#include "argstack.h" -#include - -#define ARGSTKSIZE 16 -typedef struct arguments { - int n; - struct value { - int type; - union { - double number; - const char * str; - void * data; - } value; - } stack[ARGSTKSIZE]; -} arguments; - -void arg_init(struct arguments * arg) { - arg->n = 0; -} - -void arg_done(struct arguments * arg) { - arg = arg; -} - -void arg_pushuserdata(struct arguments * arg, int type, void * data) { - assert(arg->nstack[arg->n].type = type; - arg->stack[arg->n].value.data = data; - ++arg->n; -} - -void arg_pushstring(struct arguments * arg, const char * str) { - assert(arg->nstack[arg->n].type = ARG_TSTRING; - arg->stack[arg->n].value.str = str; - ++arg->n; -} - -void arg_pushnumber(struct arguments * arg, double number) { - assert(arg->nstack[arg->n].type = ARG_TSTRING; - arg->stack[arg->n].value.number = number; - ++arg->n; -} - -int arg_size(struct arguments * arg) { - return arg->n; -} - -void * arg_touserdata(struct arguments * arg, int idx, int type) { - assert(arg->n>idx && idx>=0); - assert(arg->stack[arg->n].type==type); - return arg->stack[arg->n].value.data; -} - -double arg_tonumber(struct arguments * arg, int idx) { - assert(arg->n>idx && idx>=0); - assert(arg->stack[arg->n].type==ARG_TNUMBER); - return arg->stack[arg->n].value.number; -} - -const char * arg_tostring(struct arguments * arg, int idx) { - assert(arg->n>idx && idx>=0); - assert(arg->stack[arg->n].type==ARG_TSTRING); - return arg->stack[arg->n].value.str; -} diff --git a/src/util/argstack.h b/src/util/argstack.h deleted file mode 100644 index b4a0dc420..000000000 --- a/src/util/argstack.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef UTIL_ARG_H -#define UTIL_ARG_H -#ifdef __cplusplus -extern "C" { -#endif - -struct arguments; - -#define ARG_TNUMBER -1 -#define ARG_TSTRING -2 - -void arg_init(struct arguments * arg); -void arg_done(struct arguments * arg); - -void arg_push(struct arguments * arg, int type, void * data); -void arg_pushstring(struct arguments * arg, const char * str); -void arg_pushnumber(struct arguments * arg, double number); - -int arg_size(struct arguments * arg); -void * arg_touserdata(struct arguments * arg, int idx, int type); -double arg_tonumber(struct arguments * arg, int idx); -const char * arg_tostring(struct arguments * arg, int idx); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/util/patricia.c b/src/util/patricia.c deleted file mode 100644 index 4189f146b..000000000 --- a/src/util/patricia.c +++ /dev/null @@ -1,236 +0,0 @@ -#include - -#include -#include -#include - -#include "patricia.h" - -#define MAXKEYLEN 128 - -/* TODO: custom memory management to optimize cache layout, or use arrays. */ - -/* NOTE: The structure saves an extra 0 delimiter for the key. Technically - * this wouldn't be necessary (because we know its' length from data[0]), - * but it makes it possible for trie_getkey to return a key without making - * a copy or have a cumbersome (const char**, size_t*) interface. - * +-----------+-------------+------+------------+ - * data: | keylen(1) | key(keylen) | 0(1) | data(size) | - * +-----------+-------------+------+------------+ - */ - -struct trie_node { - struct trie_node *l, *r; - char * data; - unsigned int bitpos; -}; - -#if 1 -#define get_bit(c, s, p) (unsigned int)((((p)>>3)>(unsigned int)(s))?0:((c)[(p)>>3]>>((p)&7)&1)) -#else -unsigned int get_bit(const char * c, size_t s, unsigned int p) -{ - if ((p>>3)>=(unsigned int)s) return 0; - return ((c)[p>>3]>>(p&7)&1); -} -#endif -#define node_bit(n, p) get_bit((n)->data+1, (n)->data[0], (p)) - -trie_node * trie_insert(trie_node **root_p, const char * key, const void * data, size_t size) -{ - trie_node * new_node; - size_t keylen = strlen(key); - trie_node ** insert_p = root_p, *node = *insert_p; - unsigned int p, bit=0; - - assert(keylenbitpos) { - insert_p = bit?&node->r:&node->l; - node = *insert_p; - if (node==NULL) { - continue; - } - } - - /* if we are looking at a back-node, we need to add our node before it. */ - if (p>=node->bitpos) { - /* find the point p where both differ. */ - if (keylen==(unsigned int)node->data[0] && strncmp(key, node->data+1, keylen)==0) { - /* we are trying to insert the same key again */ - - return node; - } - do { - ++p; - bit = get_bit(key, keylen, p); - } while (node_bit(node, p)==bit); - break; - } - - /* if instead we differ before reaching the end of the current prefix, we must split. - * we insert our node before the current one and re-attach it. */ - if (node_bit(node, p)!=bit) { - break; - } - } - - new_node = (trie_node *)malloc(sizeof(trie_node)); - new_node->bitpos = p; - new_node->data = malloc(keylen+2+size); - new_node->data[0] = (char)keylen; - memcpy(new_node->data+1, key, keylen+1); - if (data!=NULL && size>0) { - /* if data is NULL then the user only wanted some space that they're going to write to later */ - /* if size is 0 then the user is using the trie as a set, not a map */ - memcpy(new_node->data+2+keylen, data, size); - } - if (bit) { - new_node->l = node; - new_node->r = new_node; /* loop the 1-bit to ourselves, search will end */ - } else { - new_node->l = new_node; /* loop the 0-bit to ourselves, search will end */ - new_node->r = node; - } - *insert_p = new_node; - return new_node; -} - -void trie_remove(trie_node **root_p, trie_node *pos) -{ - if (pos!=NULL) { - const char * key = trie_getkey(pos); - size_t keylen = pos->data[0]; - trie_node ** node_p = root_p; - trie_node * node = *root_p; - - while (node) { - int bit; - trie_node ** next_p; - trie_node * next; - - if (node == pos) { - if (node->l==node) { - *node_p = node->r; - break; - } else if (node->r==node) { - *node_p = node->l; - break; - } - } - - bit = get_bit(key, keylen, node->bitpos); - next_p = bit?&node->r:&node->l; - next = *next_p; - if (next == pos && next->bitpos<=node->bitpos) { - /* the element that has a back-pointer to pos gets swapped with pos */ - char * data = pos->data; - pos->data = node->data; - node->data = data; - - /* finally, find the back-pointer to node and set it to pos */ - next_p = bit?&node->l:&node->r; /* NB: this is the OTHER child of node */ - next = *next_p; - key = trie_getkey(node); - keylen = (unsigned int)node->data[0]; - while (next) { - int new_bit; - if (next==node) { - *next_p = pos; - break; - } - new_bit = get_bit(key, keylen, next->bitpos); - next_p = new_bit?&next->r:&next->l; - next = *next_p; - } - *node_p = bit?node->l:node->r; - break; - } - node = *next_p; - node_p = next_p; - } - free(node->data); - free(node); - } -} - -void trie_debug(trie_node * root) -{ - const char * l = root->l?trie_getkey(root->l):"?"; - const char * r = root->r?trie_getkey(root->r):"?"; - printf("%s %d | %s | %s\n", trie_getkey(root), root->bitpos, l, r); - if (root->l && root->l->bitpos > root->bitpos) trie_debug(root->l); - if (root->r && root->r->bitpos > root->bitpos) trie_debug(root->r); -} - -trie_node * trie_find(trie_node *root, const char *key) -{ - trie_node * node = root; - size_t keylen = strlen(key); - - while (node) { - int bit = get_bit(key, keylen, node->bitpos); - trie_node * next = bit?node->r:node->l; - - if (next!=NULL) { - if (node->bitpos>=next->bitpos) { - if (keylen==(unsigned int)next->data[0] && strncmp(key, next->data+1, keylen)==0) { - return next; - } - next = NULL; - } - } - node = next; - } - return NULL; -} - -trie_node * trie_find_prefix(trie_node *root, const char *key) -{ - trie_node * node = root; - size_t keylen = strlen(key); - - while (node) { - int bit = get_bit(key, keylen, node->bitpos); - trie_node * next = bit?node->r:node->l; - - if (next!=NULL) { - if (node->bitpos>=next->bitpos) { - if (keylen<=(unsigned int)next->data[0] && strncmp(key, next->data+1, keylen)==0) { - return next; - } - next = NULL; - } - } - node = next; - } - return NULL; -} - -void * trie_getdata(trie_node * node) -{ - return node->data+2+node->data[0]; -} - -const char * trie_getkey(trie_node * node) -{ - return node->data+1; -} - -void trie_free(trie_node * root) -{ - if (root) { - if (root->l && root->l->bitpos>root->bitpos) trie_free(root->l); - if (root->r && root->r->bitpos>root->bitpos) trie_free(root->r); - free(root); - } -} diff --git a/src/util/patricia.h b/src/util/patricia.h deleted file mode 100644 index f01be96be..000000000 --- a/src/util/patricia.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef H_PATRICIA -#define H_PATRICIA -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct trie_node trie_node; - -trie_node * trie_insert(trie_node **root, const char *key, const void *data, size_t size); -trie_node * trie_find(trie_node *root, const char *key); -void * trie_getdata(trie_node *node); -const char * trie_getkey(trie_node *node); -void trie_free(trie_node * root); -void trie_remove(trie_node **root_p, trie_node *pos); -void trie_debug(trie_node * root); -trie_node * trie_find_prefix(trie_node *root, const char *key); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/util/vmap.c b/src/util/vmap.c deleted file mode 100644 index 6ca8f473d..000000000 --- a/src/util/vmap.c +++ /dev/null @@ -1,146 +0,0 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifdef _MSC_VER -#pragma warning (disable: 4711) -#endif - -#include -#include -#include -#include -#include "vmap.h" - -size_t -vmap_lowerbound(const vmap * vm, const int key) -/* returns the index of the entry which has the greatest key that is less or - * equal to 'key' */ -{ - vmapentry *first = vm->data, *middle; - unsigned int half, len = vm->size; - while (len > 0) { - half = len / 2; - middle = first; - middle += half; - if (middle->key < key) { - first = middle + 1; - len = len - half - 1; - } else - len = half; - } - return first - vm->data; -} - -void -vmap_init(vmap * map) -{ - map->size = 0; /* !! */ - map->maxsize = 4; - map->data = calloc(4, sizeof(vmapentry)); -} - -size_t -vmap_upperbound(const vmap * vm, const int key) -/* returns the index of the entry which has the smallest key that is greater - * or equal to 'key' */ -{ - unsigned int half, len = vm->size; - vmapentry *first = vm->data, *middle; - while (len > 0) { - half = len / 2; - middle = first; - middle += half; - if (key < middle->key) - len = half; - else { - first = middle + 1; - len = len - half - 1; - } - } - return first - vm->data; -} - -size_t -vmap_get(vmap * vm, const int key) -{ - size_t insert = vmap_lowerbound(vm, key); - vmapentry *at; - - /* make sure it's a unique key: */ - if (insert != vm->size && vm->data[insert].key == key) - return insert; - /* insert at this position: */ - if (vm->size == vm->maxsize) { - /* need more space */ - vm->maxsize *= 2; - vm->data = realloc(vm->data, vm->maxsize * sizeof(vmapentry)); - } - at = vm->data + insert; - memmove(at + 1, at, (vm->size - insert) * sizeof(vmapentry)); /* !1.3! */ - at->key = key; - at->value = 0; - ++vm->size; - return insert; -} - -size_t -vmap_insert(vmap * vm, const int key, void *data) -/* inserts an object into the vmap, identifies it with the 'key' which must be - * unique, and returns the vmapentry it created. */ -{ - size_t insert = vmap_lowerbound(vm, key); - vmapentry *at; - - /* make sure it's a unique key: */ - assert(insert == vm->size || vm->data[insert].key != key); - /* insert at this position: */ - if (vm->size == vm->maxsize) { - /* need more space */ - vm->maxsize = vm->maxsize ? (vm->maxsize * 2) : 4; - vm->data = realloc(vm->data, vm->maxsize * sizeof(vmapentry)); - } - at = vm->data + insert; - memmove(at + 1, at, (vm->size - insert) * sizeof(vmapentry)); - at->key = key; - at->value = data; - ++vm->size; - return insert; -} - -size_t -vmap_find(const vmap * vm, const int key) -/* returns the index of the vmapentry that's identified by the key or size (a - * past-the-end value) if it is not found. */ -{ - vmapentry *first = vm->data, *middle; - unsigned int half, len = vm->size; - while (len > 0) { - half = len / 2; - middle = first; - middle += half; - if (middle->key < key) { - first = middle + 1; - len = len - half - 1; - } else - len = half; - } - if (first != vm->data + vm->size && first->key == key) - return first - vm->data; - else - return vm->size; -} diff --git a/src/util/vmap.h b/src/util/vmap.h deleted file mode 100644 index 872d4db35..000000000 --- a/src/util/vmap.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef VMAP_H -#define VMAP_H -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct vmapentry vmapentry; -struct vmapentry { - int key; - void *value; -}; -typedef struct vmap vmap; -struct vmap { - vmapentry *data; - unsigned int size; - unsigned int maxsize; -}; - -size_t vmap_lowerbound(const vmap * vm, const int key); -size_t vmap_upperbound(const vmap * vm, const int key); -size_t vmap_insert(vmap * vm, const int key, void *data); -size_t vmap_find(const vmap * vm, const int key); -size_t vmap_get(vmap * vm, const int key); -void vmap_init(vmap * vm); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/util/vset.c b/src/util/vset.c deleted file mode 100644 index f4bac1bb0..000000000 --- a/src/util/vset.c +++ /dev/null @@ -1,104 +0,0 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include -#include "vset.h" - -void -vset_init(vset * s) -{ - s->data = 0; - s->size = 0; - s->maxsize = 0; -} - -void -vset_destroy(vset * s) -{ - if (s->data) - free(s->data); -} - -int -vset_erase(vset * s, void *item) -{ - size_t i; - - for (i = 0; i != s->size; ++i) - if (s->data[i] == item) { - s->size--; - s->data[i] = s->data[s->size]; - return 1; - } - return 0; -} - -size_t -vset_add(vset * s, void *item) -{ - size_t i; - - if (!s->data) { - s->size = 0; - s->maxsize = 4; - s->data = calloc(4, sizeof(void *)); - } - for (i = 0; i != s->size; ++i) - if (s->data[i] == item) - return i; - if (s->size == s->maxsize) { - s->maxsize *= 2; - s->data = realloc(s->data, s->maxsize * sizeof(void *)); - } - s->data[s->size] = item; - ++s->size; - return s->size - 1; -} - -void * -vset_pop(vset *s) -{ - if(s->size == 0) return NULL; - s->size--; - return s->data[s->size+1]; -} - -int -vset_count(vset *s, void *item) -{ - size_t i; - int c = 0; - - for(i = 0; i != s->size; ++i) { - if(s->data[i] == item) c++; - } - - return c; -} - -void -vset_concat(vset *to, vset *from) -{ - size_t i; - - for(i=0; i != from->size; ++i) { - vset_add(to, from->data[i]); - } -} - diff --git a/src/util/vset.h b/src/util/vset.h deleted file mode 100644 index 30a045ceb..000000000 --- a/src/util/vset.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef VOIDPTR_SETS -#define VOIDPTR_SETS -#ifdef __cplusplus -extern "C" { -#endif - -#include -typedef struct vset vset; -struct vset { - void **data; - size_t size; - size_t maxsize; -}; -extern void vset_init(vset * s); -extern void vset_destroy(vset * s); -extern size_t vset_add(vset * s, void *); -extern int vset_erase(vset * s, void *); -extern int vset_count(vset *s, void * i); -extern void *vset_pop(vset *s); -extern void vset_concat(vset *to, vset *from); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/util/windir.c b/src/util/windir.c deleted file mode 100644 index 9d62f8360..000000000 --- a/src/util/windir.c +++ /dev/null @@ -1,56 +0,0 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifdef _MSC_VER -#include - -#include -#include -#include "windir.h" - -DIR * -opendir(const char *name) -{ - static DIR direct; /* STATIC_RESULT: used for return, not across calls */ - - direct.first = 1; - _searchenv(name, "ERESSEA_PATH", direct.name); - if (*direct.name != '\0') - return &direct; - return NULL; -} - -struct dirent * -readdir(DIR * thedir) -{ - static struct _finddata_t ft; /* STATIC_RESULT: used for return, not across calls */ - static struct dirent de; /* STATIC_RESULT: used for return, not across calls */ - char where[_MAX_PATH]; - - strcat(strcpy(where, thedir->name), "/*"); - if (thedir->first) { - thedir->first = 0; - de.hnd = _findfirst(where, &ft); - } else { - if (_findnext(de.hnd, &ft) != 0) - return NULL; - } - _splitpath(ft.name, de.d_drive, de.d_dir, de.d_name, de.d_ext); - return &de; -} -#endif diff --git a/src/util/windir.h b/src/util/windir.h deleted file mode 100644 index de9851aa9..000000000 --- a/src/util/windir.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef WINDIR_H -#define WINDIR_H - -#ifdef _MSC_VER -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -typedef struct DIR { - char name[_MAX_PATH]; - int first; -} DIR; - -typedef struct dirent { - char d_path[_MAX_PATH]; - char d_name[_MAX_FNAME]; - char d_drive[_MAX_DRIVE]; - char d_dir[_MAX_DIR]; - char d_ext[_MAX_EXT]; - intptr_t hnd; -} dirent; - -DIR *opendir(const char *name); -struct dirent *readdir(DIR * thedir); - -#ifdef __cplusplus -} -#endif -#endif -#endif From 37326e4f34dcb8bcdffdcc43c4fd15fdda27244c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 27 Feb 2011 03:18:02 -0800 Subject: [PATCH 081/400] move file --- src/util.vcxproj.filters | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util.vcxproj.filters b/src/util.vcxproj.filters index 7ef937c10..1530a0454 100644 --- a/src/util.vcxproj.filters +++ b/src/util.vcxproj.filters @@ -105,7 +105,7 @@ Header Files - Source Files + Header Files From 09f2286b826e13419d887c278432de796fe267c5 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 27 Feb 2011 11:24:51 -0800 Subject: [PATCH 082/400] use malloc. change indentation. --- src/util/functions.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/util/functions.c b/src/util/functions.c index 81b9face6..4ec89e347 100644 --- a/src/util/functions.c +++ b/src/util/functions.c @@ -55,11 +55,11 @@ get_functionname(pf_generic fun) void register_function(pf_generic fun, const char * name) { - function_list * fl = calloc(sizeof(function_list), 1); - fl->next = functionlist; - fl->fun = fun; - fl->name = strdup(name); - functionlist = fl; + function_list * fl = (function_list *)malloc(sizeof(function_list)); + fl->next = functionlist; + fl->fun = fun; + fl->name = strdup(name); + functionlist = fl; } void From e6f60618198ce0cf9cc17a2b3064eef25d28936d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 27 Feb 2011 11:49:01 -0800 Subject: [PATCH 083/400] quicklist.replace makes changes to the content --- src/util/quicklist.c | 10 ++++++++++ src/util/quicklist.h | 1 + src/util/quicklist_test.c | 10 ++++++++++ 3 files changed, 21 insertions(+) diff --git a/src/util/quicklist.c b/src/util/quicklist.c index 215bb0065..92eb38c08 100644 --- a/src/util/quicklist.c +++ b/src/util/quicklist.c @@ -33,6 +33,16 @@ void * ql_get(const quicklist * ql, int index) { return (ql && indexnum_elements)?ql->elements[index]:ql_get(ql->next, index-ql->num_elements); } +void * ql_replace(quicklist * ql, int index, void * data) { + if (ql && indexnum_elements) { + void * orig = ql->elements[index]; + ql->elements[index] = data; + return orig; + } else { + return ql_replace(ql->next, index-ql->num_elements, data); + } +} + int ql_length(const quicklist * ql) { return ql?ql->num_elements+ql_length(ql->next):0; } diff --git a/src/util/quicklist.h b/src/util/quicklist.h index f3068de48..91eb55468 100644 --- a/src/util/quicklist.h +++ b/src/util/quicklist.h @@ -31,6 +31,7 @@ int ql_insert(struct quicklist ** qlp, int index, void * data); void ql_foreach(struct quicklist * ql, void (*cb)(void *)); int ql_advance(struct quicklist ** iterator, int * index, int stride); void ql_free(struct quicklist * ql); +void * ql_replace(struct quicklist * ql, int index, void * data); /* you can use it as a set (sorted pointers)*/ int ql_set_insert(struct quicklist ** qlp, void * data); diff --git a/src/util/quicklist_test.c b/src/util/quicklist_test.c index 8dd677405..5592599f8 100644 --- a/src/util/quicklist_test.c +++ b/src/util/quicklist_test.c @@ -24,6 +24,15 @@ static void test_insert_delete_gives_null(CuTest * tc) { CuAssertPtrEquals(tc, 0, ql); } +static void test_replace(CuTest * tc) { + struct quicklist * ql = NULL; + int a; + ql_push(&ql, (void*)42); + a = (int)ql_replace(ql, 0, (void *)43); + CuAssertIntEquals(tc, 42, a); + CuAssertIntEquals(tc, 43, (int)ql_get(ql, 0)); +} + static void test_set_insert(CuTest * tc) { struct quicklist * ql = NULL; int a, qi; @@ -167,6 +176,7 @@ CuSuite* get_quicklist_suite(void) { CuSuite* suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_advance); + SUITE_ADD_TEST(suite, test_replace); SUITE_ADD_TEST(suite, test_push); SUITE_ADD_TEST(suite, test_insert); SUITE_ADD_TEST(suite, test_set_remove); From b40f3d19b00f212d93d870cf4628743531fff3f3 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 27 Feb 2011 12:04:49 -0800 Subject: [PATCH 084/400] Store fighters in a quicklist, not a cvector. --- src/kernel/battle.c | 25 ++++--------------------- src/kernel/battle.h | 2 +- src/kernel/item.h | 5 ----- 3 files changed, 5 insertions(+), 27 deletions(-) diff --git a/src/kernel/battle.c b/src/kernel/battle.c index 3d8747c61..cbcccca5f 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -61,6 +61,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include @@ -1606,31 +1607,13 @@ select_opponent(battle * b, troop at, int mindist, int maxdist) return dt; } -/* - * Abfrage mit - * - * cvector *fgs=fighters(b,af,FIGHT_ROW,BEHIND_ROW, FS_HELP|FS_ENEMY); - * fighter *fig; - * - * Optional: Verwirbeln. Vorsicht: Aufwändig! - * v_scramble(fgs->begin, fgs->end); - * - * for (fig = fgs->begin; fig != fgs->end; ++fig) { - * fighter *df = *fig; - * - * } - * - * cv_kill(fgs); free(fgs); Nicht vergessen - */ - -cvector * +quicklist * fighters(battle *b, const side * vs, int minrow, int maxrow, int mask) { side * s; - cvector *fightervp = malloc(sizeof(cvector)); + quicklist *fightervp = 0; assert(vs!=NULL); - cv_init(fightervp); for (s=b->sides;s!=b->sides+b->nsides;++s) { fighter *fig; @@ -1647,7 +1630,7 @@ fighters(battle *b, const side * vs, int minrow, int maxrow, int mask) for (fig = s->fighters; fig; fig = fig->next) { int row = get_unitrow(fig, vs); if (row >= minrow && row <= maxrow) { - cv_pushback(fightervp, fig); + ql_push(&fightervp, fig); } } } diff --git a/src/kernel/battle.h b/src/kernel/battle.h index 4bc054818..602121346 100644 --- a/src/kernel/battle.h +++ b/src/kernel/battle.h @@ -248,7 +248,7 @@ extern "C" { extern void message_all(battle * b, struct message * m); extern int hits(troop at, troop dt, weapon * awp); extern void damage_building(struct battle *b, struct building *bldg, int damage_abs); - extern struct cvector * fighters(struct battle *b, const struct side * vs, int minrow, int maxrow, int mask); + extern struct quicklist * fighters(struct battle *b, const struct side * vs, int minrow, int maxrow, int mask); extern int count_allies(const struct side * as, int minrow, int maxrow, int select, int allytype); extern int get_unitrow(const struct fighter * af, const struct side * vs); extern boolean helping(const struct side * as, const struct side * ds); diff --git a/src/kernel/item.h b/src/kernel/item.h index 516d0856d..4898f7603 100644 --- a/src/kernel/item.h +++ b/src/kernel/item.h @@ -119,11 +119,6 @@ typedef struct resource_limit { #define ENOSKILL -3; #define EUNUSABLE -4; -typedef struct itemtype_list { - struct itemtype_list * next; - const struct item_type * type; -} itemtype_list; - typedef struct item_type { resource_type * rtype; /* --- constants --- */ From 1fbe46ddfe40c3c9a50070506b0873a989dd8659 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 27 Feb 2011 12:14:16 -0800 Subject: [PATCH 085/400] test for emptiness of a list (it's super-simple) --- src/util/quicklist.c | 4 ++++ src/util/quicklist.h | 1 + src/util/quicklist_test.c | 2 ++ 3 files changed, 7 insertions(+) diff --git a/src/util/quicklist.c b/src/util/quicklist.c index 92eb38c08..8356106ca 100644 --- a/src/util/quicklist.c +++ b/src/util/quicklist.c @@ -47,6 +47,10 @@ int ql_length(const quicklist * ql) { return ql?ql->num_elements+ql_length(ql->next):0; } +int ql_empty(const quicklist * ql) { + return !ql; +} + void ql_push(quicklist ** qlp, void * data) { quicklist * ql = 0; while(*qlp && ((*qlp)->next || (*qlp)->num_elements==QL_MAXSIZE)) { diff --git a/src/util/quicklist.h b/src/util/quicklist.h index 91eb55468..d70fa648c 100644 --- a/src/util/quicklist.h +++ b/src/util/quicklist.h @@ -25,6 +25,7 @@ extern "C" { typedef struct quicklist quicklist; void * ql_get(const struct quicklist * ql, int index); int ql_length(const struct quicklist * ql); +int ql_empty(const struct quicklist * ql); void ql_push(struct quicklist ** qlp, void * data); int ql_delete(struct quicklist ** qlp, int index); int ql_insert(struct quicklist ** qlp, int index, void * data); diff --git a/src/util/quicklist_test.c b/src/util/quicklist_test.c index 5592599f8..ead3d2c78 100644 --- a/src/util/quicklist_test.c +++ b/src/util/quicklist_test.c @@ -19,7 +19,9 @@ static void test_insert(CuTest * tc) { static void test_insert_delete_gives_null(CuTest * tc) { struct quicklist * ql = NULL; + CuAssertIntEquals(tc, 1, ql_empty(ql)); ql_push(&ql, (void*)42); + CuAssertIntEquals(tc, 0, ql_empty(ql)); ql_delete(&ql, 0); CuAssertPtrEquals(tc, 0, ql); } From 342e7ee2499133af664213cfb017e7b87026f27d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 27 Feb 2011 12:14:33 -0800 Subject: [PATCH 086/400] remove TROLLSAVE code remove more cvector usage --- src/kernel/battle.c | 45 +++++++++++++-------------------------------- src/kernel/battle.h | 4 ++-- src/kernel/config.h | 1 - 3 files changed, 15 insertions(+), 35 deletions(-) diff --git a/src/kernel/battle.c b/src/kernel/battle.c index cbcccca5f..04b6fb1fb 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -2301,9 +2301,9 @@ add_tactics(tactics * ta, fighter * fig, int value) if (value == 0 || value < ta->value) return; if (value > ta->value) - cv_kill(&ta->fighters); - cv_pushback(&ta->fighters, fig); - cv_pushback(&fig->side->battle->leaders, fig); + ql_free(ta->fighters); + ql_push(&ta->fighters, fig); + ql_push(&fig->side->battle->leaders, fig); ta->value = value; } @@ -2630,10 +2630,6 @@ aftermath(battle * b) bfaction * bf; boolean ships_damaged = (boolean)(b->turn+(b->has_tactics_turn?1:0)>2); /* only used for ship damage! */ -#ifdef TROLLSAVE - int *trollsave = calloc(2 * cv_size(&b->factions), sizeof(int)); -#endif - for (s=b->sides;s!=b->sides+b->nsides;++s) { fighter * df; for (df = s->fighters; df; df=df->next) { @@ -2641,21 +2637,6 @@ aftermath(battle * b) int dead = dead_fighters(df); int pr_mercy = 0; -#ifdef TROLLSAVE - /* Trolle können regenerieren */ - if (df->alive > 0 && dead>0 && du->race == new_race[RC_TROLL]) { - for (i = 0; i != dead; ++i) { - if (chance(TROLL_REGENERATION)) { - ++df->alive; - ++s->alive; - ++s->battle->alive; - ++trollsave[s->index]; - /* do not change dead here, or loop will not terminate! recalculate later */ - } - } - dead = dead_fighters(df); - } -#endif /* Regeneration durch PR_MERCY */ if (dead>0 && pr_mercy) { for (i = 0; i != dead; ++i) { @@ -2918,9 +2899,6 @@ aftermath(battle * b) if (*sp==sh) sp=&sh->next; } } -#ifdef TROLLSAVE - free(trollsave); -#endif reorder_fleeing(r); @@ -3146,7 +3124,7 @@ print_stats(battle * b) b->max_tactics = 0; for (s=b->sides;s!=b->sides+b->nsides;++s) { - if (cv_size(&s->leader.fighters)) { + if (!ql_empty(s->leader.fighters)) { b->max_tactics = MAX(b->max_tactics, s->leader.value); } } @@ -3154,8 +3132,11 @@ print_stats(battle * b) if (b->max_tactics > 0) { for (s=b->sides;s!=b->sides+b->nsides;++s) { if (s->leader.value == b->max_tactics) { - fighter *tf; - cv_foreach(tf, s->leader.fighters) { + quicklist *ql; + int qi; + + for (qi=0,ql=s->leader.fighters;ql;ql_advance(&ql, &qi, 1)) { + fighter *tf = (fighter *)ql_get(ql, qi); unit *u = tf->unit; message * m = NULL; if (!is_attacker(tf)) { @@ -3165,7 +3146,7 @@ print_stats(battle * b) } message_all(b, m); msg_release(m); - } cv_next(tf); + } } } } @@ -3603,7 +3584,7 @@ make_battle(region * r) static void free_side(side * si) { - cv_kill(&si->leader.fighters); + ql_free(si->leader.fighters); } static void @@ -3651,7 +3632,7 @@ free_battle(battle * b) } free_side(s); } - cv_kill(&b->leaders); + ql_free(b->leaders); cv_foreach(meffect, b->meffects) { free(meffect); } @@ -4329,7 +4310,7 @@ do_battle(region * r) for (sh=r->ships; sh; sh=sh->next) freset(sh, SF_DAMAGED); /* Gibt es eine Taktikrunde ? */ - if (cv_size(&b->leaders)) { + if (!ql_empty(b->leaders)) { b->turn = 0; b->has_tactics_turn = true; } else { diff --git a/src/kernel/battle.h b/src/kernel/battle.h index 602121346..dde95838b 100644 --- a/src/kernel/battle.h +++ b/src/kernel/battle.h @@ -58,7 +58,7 @@ extern "C" { } bfaction; typedef struct tactics { - cvector fighters; + struct quicklist * fighters; int value; } tactics; @@ -93,7 +93,7 @@ extern "C" { } side; typedef struct battle { - cvector leaders; + struct quicklist * leaders; struct region *region; struct plane *plane; bfaction * factions; diff --git a/src/kernel/config.h b/src/kernel/config.h index 22544a78b..513d2d859 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -35,7 +35,6 @@ struct _dictionary_; #define SHIPDAMAGE /* Schiffsbeschädigungen */ #define INSECT_POTION /* Spezialtrank für Insekten */ #define ORCIFICATION /* giving snotlings to the peasants gets counted */ -#undef TROLLSAVE /* saving throw for dead trolls */ #define ALLIED(f1, f2) (f1==f2 || (f1->alliance && f1->alliance==f2->alliance)) From de13d0d412e6853d6bdcd9c7591405f1712c87b6 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 27 Feb 2011 12:22:34 -0800 Subject: [PATCH 087/400] remove more cvector usage --- src/kernel/battle.c | 38 ++++++++++++++++++-------------------- src/kernel/battle.h | 6 +++--- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/kernel/battle.c b/src/kernel/battle.c index 04b6fb1fb..b445b4518 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -1087,7 +1087,6 @@ terminate(troop dt, troop at, int type, const char *damage, boolean missile) static int rule_armor = -1; /* Schild */ - void **si; side *ds = df->side; int hp; @@ -1247,7 +1246,10 @@ terminate(troop dt, troop at, int type, const char *damage, boolean missile) if ((du->race->battle_flags & BF_INV_NONMAGIC) && !magic) rda = 0; else { + int qi; + quicklist * ql; unsigned int i = 0; + if (du->race->battle_flags & BF_RES_PIERCE) i |= WTF_PIERCE; if (du->race->battle_flags & BF_RES_CUT) i |= WTF_CUT; if (du->race->battle_flags & BF_RES_BASH) i |= WTF_BLUNT; @@ -1255,21 +1257,21 @@ terminate(troop dt, troop at, int type, const char *damage, boolean missile) if (i && awtype && fval(awtype, i)) rda /= 2; /* Schilde */ - for (si = b->meffects.begin; si != b->meffects.end; ++si) { - meffect *meffect = *si; - if (meffect_protection(b, meffect, ds) != 0) { + for (qi=0,ql=b->meffects;ql;ql_advance(&ql, &qi, 1)) { + meffect *me = (meffect *)ql_get(ql, qi); + if (meffect_protection(b, me, ds) != 0) { assert(0 <= rda); /* rda sollte hier immer mindestens 0 sein */ /* jeder Schaden wird um effect% reduziert bis der Schild duration * Trefferpunkte aufgefangen hat */ - if (meffect->typ == SHIELD_REDUCE) { - hp = rda * (meffect->effect/100); + if (me->typ == SHIELD_REDUCE) { + hp = rda * (me->effect/100); rda -= hp; - meffect->duration -= hp; + me->duration -= hp; } /* gibt Rüstung +effect für duration Treffer */ - if (meffect->typ == SHIELD_ARMOR) { - rda = MAX(rda - meffect->effect, 0); - meffect->duration--; + if (me->typ == SHIELD_ARMOR) { + rda = MAX(rda - me->effect, 0); + me->duration--; } } } @@ -1756,10 +1758,10 @@ do_combatspell(troop at) unit *mage = fi->unit; battle *b = fi->side->battle; region *r = b->region; - int level; + quicklist * ql; + int level, qi; double power; int fumblechance = 0; - void **mg; order * ord; int sl; const struct locale * lang = mage->faction->locale; @@ -1784,8 +1786,8 @@ do_combatspell(troop at) return; } - for (mg = b->meffects.begin; mg != b->meffects.end; ++mg) { - meffect *mblock = *mg; + for (qi=0,ql=b->meffects;ql;ql_advance(&ql, &qi, 1)) { + meffect *mblock = (meffect *)ql_get(ql, qi); if (mblock->typ == SHIELD_BLOCK) { if (meffect_blocked(b, mblock, fi->side) != 0) { fumblechance += mblock->duration; @@ -3607,7 +3609,6 @@ static void free_battle(battle * b) { side *s; - meffect *meffect; int max_fac_no = 0; if (bdebug) { @@ -3633,11 +3634,8 @@ free_battle(battle * b) free_side(s); } ql_free(b->leaders); - cv_foreach(meffect, b->meffects) { - free(meffect); - } - cv_next(meffect); - cv_kill(&b->meffects); + ql_foreach(b->meffects, free); + ql_free(b->meffects); } static int * diff --git a/src/kernel/battle.h b/src/kernel/battle.h index dde95838b..e6b263d0f 100644 --- a/src/kernel/battle.h +++ b/src/kernel/battle.h @@ -101,9 +101,9 @@ extern "C" { int nfighters; side sides[MAXSIDES]; int nsides; - cvector meffects; - int max_tactics; - int turn; + struct quicklist *meffects; + int max_tactics; + int turn; boolean has_tactics_turn; int keeploot; boolean reelarrow; From 42eb0ef0edc917787c937bfee3c29606e27da77d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 27 Feb 2011 20:49:38 -0800 Subject: [PATCH 088/400] remove cvector.[hc] completely --- src/build/util.c | 1 - src/kernel/battle.c | 1 - src/kernel/battle.h | 2 - src/util.vcxproj | 2 - src/util.vcxproj.filters | 6 --- src/util/cvector.c | 97 ---------------------------------------- src/util/cvector.h | 61 ------------------------- 7 files changed, 170 deletions(-) delete mode 100644 src/util/cvector.c delete mode 100644 src/util/cvector.h diff --git a/src/build/util.c b/src/build/util.c index 5a37a6463..8882b9dbc 100644 --- a/src/build/util.c +++ b/src/build/util.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/src/kernel/battle.c b/src/kernel/battle.c index b445b4518..1f6910213 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -56,7 +56,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include #include #include #include diff --git a/src/kernel/battle.h b/src/kernel/battle.h index e6b263d0f..77a3917f2 100644 --- a/src/kernel/battle.h +++ b/src/kernel/battle.h @@ -22,8 +22,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -#include - #define SHOW_KILLS #undef SMALL_BATTLE_MESSAGES diff --git a/src/util.vcxproj b/src/util.vcxproj index d21e79368..db7f763dc 100644 --- a/src/util.vcxproj +++ b/src/util.vcxproj @@ -92,7 +92,6 @@ - @@ -127,7 +126,6 @@ - diff --git a/src/util.vcxproj.filters b/src/util.vcxproj.filters index 1530a0454..685e18404 100644 --- a/src/util.vcxproj.filters +++ b/src/util.vcxproj.filters @@ -26,9 +26,6 @@ Header Files - - Header Files - Header Files @@ -127,9 +124,6 @@ Source Files - - Source Files - Source Files diff --git a/src/util/cvector.c b/src/util/cvector.c deleted file mode 100644 index 27c395908..000000000 --- a/src/util/cvector.c +++ /dev/null @@ -1,97 +0,0 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "cvector.h" -#include "rng.h" - -#include -#include -#include -#include - -void -cv_init(cvector * cv) -{ - cv->begin = 0; - cv->end = 0; - cv->space = 0; -} - -cvector * -cv_kill(cvector * cv) -{ - if (cv->begin) free(cv->begin); - cv_init(cv); - return cv; -} - -size_t -cv_size(cvector * cv) -{ - return cv->end - cv->begin; -} - -void -cv_reserve(cvector * cv, size_t size) -{ - size_t count = cv->end - cv->begin; - cv->begin = realloc(cv->begin, size * sizeof(void *)); - - cv->space = size; - cv->end = cv->begin + count; -} - -void -cv_pushback(cvector * cv, void *u) -{ - if (cv->space == cv_size(cv)) - cv_reserve(cv, cv->space ? cv->space * 2 : 2); - *(cv->end++) = u; -} - -int -__cv_scramblecmp(const void *p1, const void *p2) -{ - return *((long *) p1) - *((long *) p2); -} - -#define addptr(p,i) ((void *)(((char *)p) + i)) - -/** randomly shuffle an array - * for correctness, see Donald E. Knuth, The Art of Computer Programming - */ -static void -__cv_scramble(void *v1, size_t n, size_t width) -{ - size_t i; - void * temp = malloc(width); - for (i=0;i!=n;++i) { - size_t j = i + (rng_int() % (n-i)); - memcpy(temp, addptr(v1, i*width), width); - memcpy(addptr(v1, i*width), addptr(v1, j*width), width); - memcpy(addptr(v1, j*width), temp, width); - } - free(temp); -} - -void -v_scramble(void **begin, void **end) -{ - __cv_scramble(begin, end - begin, sizeof(void *)); -} diff --git a/src/util/cvector.h b/src/util/cvector.h deleted file mode 100644 index c0e50944d..000000000 --- a/src/util/cvector.h +++ /dev/null @@ -1,61 +0,0 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef CVECTOR_H -#define CVECTOR_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WIN32 -#ifndef __cdecl -#define __cdecl -#endif -#endif - -#include -typedef struct cvector cvector; - -struct cvector { - void **begin; - void **end; - size_t space; -}; - -typedef int (__cdecl * v_sort_fun) (const void *, const void *); - -void cv_init(cvector * cv); -cvector *cv_kill(cvector * cv); -size_t cv_size(cvector * cv); -void cv_reserve(cvector * cv, size_t size); -void cv_pushback(cvector * cv, void *u); -void v_scramble(void **begin, void **end); - -#define cv_remove(c, i) { void** x = v_find((c)->begin, (c)->end, (i)); if (x) { *x = *(c)->end; (c)->end--; } } -#define cv_foreach(item, vector) \ -{ \ - void **iterator; \ - for (iterator = (vector).begin; iterator<(vector).end; ++iterator) \ - { \ - (item) = *iterator; -#define cv_next(item) } } - -#ifdef __cplusplus -} -#endif -#endif From 2af300431d16ddac2a6048b8ed752c03de2b8a13 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 1 Mar 2011 04:55:58 +0100 Subject: [PATCH 089/400] fix a crash in battles caused by quicklist changes --- src/kernel/battle.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/kernel/battle.c b/src/kernel/battle.c index 1f6910213..35c48dfb6 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -2301,8 +2301,10 @@ add_tactics(tactics * ta, fighter * fig, int value) { if (value == 0 || value < ta->value) return; - if (value > ta->value) + if (value > ta->value) { ql_free(ta->fighters); + ta->fighters = 0; + } ql_push(&ta->fighters, fig); ql_push(&fig->side->battle->leaders, fig); ta->value = value; From 168e1d08d4b24c7c4954a92b9111a07edb78ddfe Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 28 Feb 2011 21:28:26 -0800 Subject: [PATCH 090/400] stop warning about duplicate spells. --- src/kernel/magic.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/kernel/magic.c b/src/kernel/magic.c index db73632d6..fc200c3f3 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -430,7 +430,7 @@ update_spellbook(faction * f, int level) commonspells[numspells++] = sp; } else { if (know_school(f, sp->magietyp) && sp->level <= level) { - add_spell(&f->spellbook, sp); + ql_set_insert(&f->spellbook, sp); } } } @@ -524,13 +524,8 @@ create_mage(unit * u, magic_t mtyp) void add_spell(struct quicklist ** slistp, spell * sp) { - quicklist * ql = *slistp; - int qi; - - if (ql_set_find(&ql, &qi, sp)) { + if (ql_set_insert(slistp, sp)!=0) { log_error(("add_spell: the list already contains the spell '%s'.\n", sp->sname)); - } else { - ql_set_insert(slistp, sp); } } From 7fd2852f3be684b77b0eabb630e5803cea5f14f7 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 15 Feb 2011 16:36:26 +0100 Subject: [PATCH 091/400] fixed error with option window dimensions in gmtool --- src/util/listbox.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/util/listbox.c b/src/util/listbox.c index b04840a3c..0dfefe4b2 100644 --- a/src/util/listbox.c +++ b/src/util/listbox.c @@ -11,10 +11,13 @@ /* wenn platform.h nicht vor curses included wird, kompiliert es unter windows nicht */ #include #include +#include #include "listbox.h" #include "gmtool_structs.h" +#include + #include #include @@ -63,8 +66,8 @@ push_selection(list_selection ** p_sel, char * str, void * payload) return p_sel; } -#define SX (stdscr->_maxx) -#define SY (stdscr->_maxy) +#define SX (getmaxx(stdscr)) +#define SY (getmaxy(stdscr)) list_selection * do_selection(list_selection * sel, const char * title, void (*perform)(list_selection *, void *), void * data) @@ -79,11 +82,16 @@ do_selection(list_selection * sel, const char * title, void (*perform)(list_sele for (s=sel;s;s=s->next) { if ((int)strlen(s->str)>width) width = (int)strlen(s->str); ++height; + if (verbosity>=5) + log_info((1, "s %s w %d h %d\n", s->str, width, height)); } if (height==0 || width==0) return NULL; if (width+3>SX) width=SX-4; if (height+2>SY) height=SY-2; + if (verbosity>=5) + log_info((1, "w %d h %d\n", width, height)); + wn = newwin(height+2, width+4, (SY - height - 2) / 2, (SX - width - 4) / 2); for (;;) { @@ -95,6 +103,7 @@ do_selection(list_selection * sel, const char * title, void (*perform)(list_sele waddnstr(wn, s->str, -1); wclrtoeol(wn); } + wclrtobot(wn); wxborder(wn); mvwprintw(wn, 0, 2, "[ %s ]", title); update = false; @@ -104,7 +113,7 @@ do_selection(list_selection * sel, const char * title, void (*perform)(list_sele wmove(wn, i + 1, 2); waddstr(wn, "->"); wmove(wn, i + 1, 4); - waddnstr(wn, current->str, -1); + waddnstr(wn, current->str, width-2); wattroff(wn, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); wrefresh(wn); From 258b33e63921577ff7345601b0adb8bd192f2880 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 17 Feb 2011 01:40:45 +0100 Subject: [PATCH 092/400] updates windows after search --- src/gmtool.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gmtool.c b/src/gmtool.c index 537766e4b..35c79a139 100644 --- a/src/gmtool.c +++ b/src/gmtool.c @@ -1074,6 +1074,8 @@ handlekey(state * st, int c) } if (r!=NULL) { region2coord(r, &st->cursor); + st->wnd_info->update |=1; + st->wnd_status->update |=1; } break; case 'Q': From a11d49b4061da3760e6f0de81c46125c5219579a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 3 Mar 2011 15:46:55 +0100 Subject: [PATCH 093/400] added a parenthesis to remove a warning --- src/gmtool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gmtool.c b/src/gmtool.c index 35c79a139..801b68d76 100644 --- a/src/gmtool.c +++ b/src/gmtool.c @@ -271,7 +271,7 @@ paint_map(window * wnd, const state * st) attr |= A_REVERSE; } } - if (mr->r && mr->r->flags & RF_MAPPER_HIGHLIGHT) hl = 1; + if (mr->r && (mr->r->flags & RF_MAPPER_HIGHLIGHT)) hl = 1; mvwaddch(win, yp, xp, mr_tile(mr, hl) | attr); } } From b0f1445d68af11fff7d9fc84fc71230b139bc4cb Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 4 Mar 2011 20:38:36 +0100 Subject: [PATCH 094/400] removed all unused items --- scripts/tests/common.lua | 57 +++++++++++++++++++++++++++++++--------- src/bindings/bindings.c | 19 ++++++++++++++ 2 files changed, 63 insertions(+), 13 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index a33f47dbf..253f09c99 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -354,12 +354,12 @@ function test_produce() local u = unit.create(f, r, 1) u:clear_orders() u:set_skill("weaponsmithing", 3) - u:add_item("iron", 2) + u:add_item("iron", 10) u:add_item("money", u.number * 10) u:add_order("MACHE Schwert") process_orders() - assert(u:get_item("iron")==1) - assert(u:get_item("sword")==1) + assert_equal(10-3/test.swordmakeskill*test.swordiron, u:get_item("iron")) + assert_equal(3/test.swordmakeskill, u:get_item("sword")) end function test_work() @@ -431,7 +431,7 @@ function test_mallorn() r:set_resource("tree", 100) assert(r:get_resource("tree")==100) local m = region.create(0, 0, "plain") - m:set_flag(1, true) -- not mallorn + m:set_flag(1, true) -- mallorn m:set_resource("tree", 100) assert(m:get_resource("tree")==100) @@ -454,10 +454,17 @@ function test_mallorn() u3:set_skill("forestry", 2) u3:clear_orders() u3:add_order("MACHE Mallorn") + process_orders() + assert(u1:get_item("log")==2) assert(u2:get_item("log")==2) - assert(u3:get_item("mallorn")==1) + if (has_item("mallorn")) then + assert(u3:get_item("mallorn")==1) + else + assert_equal(-1, u3:get_item("mallorn")) + assert_equal(0, u3:get_item("log")) + end end function test_coordinate_translation() @@ -696,8 +703,9 @@ function test_ride_with_horse() local r = region.create(0, 0, "plain") local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r, 1) + local pweight = u.weight u:add_item("horse", 1) - u:add_item("sword", 10) + u:add_item("sword", (test.horsecapacity - pweight)/100) u:set_skill("riding", 2) u:clear_orders() @@ -718,14 +726,37 @@ function test_ride_with_horses_and_cart() local r = region.create(0, 0, "plain") local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r, 1) - u:add_item("cart", 1) - assert_equal(1, u:get_item("cart")) -- every game has a cart, right? right? - u:add_item("horse", 2) - assert_equal(2, u:get_item("horse")) -- every game has a horse, right? right? - u:add_item("sword", 120) - assert_equal(120, u:get_item("sword")) -- every game has a sword, right? and it weighs 1 unit? + local carts = 0 + local horses = 0 + local pweight = u.weight + if (has_item("cart")) then + u:add_item("cart", 1) + assert_equal(1, u:get_item("cart")) -- every game has a cart, right? right? no! atlantis hasn't! + carts = u:get_item("cart") + end + u:add_item("horse", 1) + assert_equal(1, u:get_item("horse")) -- every game has a horse, right? right? + local horses = u:get_item("horse") + assert(horses+carts>0) + local capacity = test.horsecapacity*(horses+1) + test.cartcapacity*carts - pweight + capacity = capacity / 100 + u:add_item("sword", capacity) + assert_equal(capacity, u:get_item("sword")) -- every game has a sword, right? and it weighs 1 unit? + u:set_skill("riding", 3) + if (has_item("cart")) then + -- need 2 horses for a cart + u:clear_orders() + u:add_order("NACH O O") + process_orders() + assert_equal(0, u.region.x) + end + + u:add_item("horse", 1) + assert_equal(2, u:get_item("horse")) + horses = u:get_item("horse") + -- ride u:clear_orders() u:add_order("NACH O O") @@ -733,7 +764,7 @@ function test_ride_with_horses_and_cart() assert_equal(2, u.region.x) -- walk - u:add_item("sword", 20) + u:add_item("sword", 10) r:get_key("eviL") u:clear_orders() u:add_order("NACH W W") diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index f987c0173..68ed85a61 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -1018,6 +1018,22 @@ tolua_settings_set(lua_State* L) return 0; } +/* + * Paramter: item name + * Returns true if the item type is known in the game + */ +static int +tolua_has_item(lua_State* L) +{ + const char * iname = tolua_tostring(L, 1, 0); + const item_type * itype = NULL; + if (iname!=NULL) { + itype = it_find(iname); + } + lua_pushboolean(L, itype!=NULL); + return 1; +} + static void parse_inifile(lua_State* L, dictionary * d, const char * section) { @@ -1202,6 +1218,9 @@ tolua_eressea_open(lua_State* L) tolua_function(L, TOLUA_CAST "read_xml", tolua_read_xml); + /* test helpers */ + tolua_function(L, TOLUA_CAST "has_item", tolua_has_item); + } tolua_endmodule(L); return 1; From 53aec0d4386ef092ae719b342c92c2234ef2d808 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 5 Mar 2011 19:34:51 +0100 Subject: [PATCH 095/400] do not silently fail on unknown skill --- src/kernel/xmlreader.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 3ee54780d..887d04337 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1271,13 +1271,12 @@ add_skills(equipment * eq, xmlNodeSetPtr nsetSkills) propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue!=NULL); sk = sk_find((const char*)propValue); + assert(sk!=NOSKILL); xmlFree(propValue); - if (sk!=NOSKILL) { - propValue = xmlGetProp(node, BAD_CAST "level"); - if (propValue!=NULL) { - equipment_setskill(eq, sk, (const char*)propValue); - xmlFree(propValue); - } + propValue = xmlGetProp(node, BAD_CAST "level"); + if (propValue!=NULL) { + equipment_setskill(eq, sk, (const char*)propValue); + xmlFree(propValue); } } } From 8c129f157657ecfaa77568adb6d4f30df11b1ee3 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 5 Mar 2011 19:36:05 +0100 Subject: [PATCH 096/400] skill.id had wrong type --- src/kernel/skill.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/kernel/skill.h b/src/kernel/skill.h index 1ed5c6ad6..3f8ec53ce 100644 --- a/src/kernel/skill.h +++ b/src/kernel/skill.h @@ -16,6 +16,7 @@ extern "C" { #endif +/* FIXME where is this defined?? */ extern signed char skill_bonus(struct unit * u, struct region * r); /* skillmod_data::flags -- wann gilt der modifier? */ @@ -24,7 +25,7 @@ extern signed char skill_bonus(struct unit * u, struct region * r); #define SMF_RIDING (1<<2) /* Bonus für berittene - an der rasse*/ typedef struct skill { - unsigned char id; + skill_t id; unsigned int level : 8; unsigned int weeks : 8; unsigned int old : 8; From 8c42643528a53a8f4a3d9369180431ebd856e177 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 6 Mar 2011 11:27:37 +0100 Subject: [PATCH 097/400] added Atlantis ship types --- scripts/tests/common.lua | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 253f09c99..c836e4272 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -1,10 +1,7 @@ require "lunit" local function _test_create_ship(r) - local s = ship.create(r, "canoe") - if (s==nil) then - s = ship.create(r, "boat") - end + local s = ship.create(r, test.shipname) return s end @@ -408,6 +405,7 @@ function test_id() assert(get_building(atoi36(fortytwo))==b) local s = _test_create_ship(r) + assert_not_nil(s) -- s.id = atoi36("42") local fortytwo = itoa36(s.id) assert(get_ship(fortytwo)==s) From cb4f7a03c662b4c913e269b96a5d63af8ed76d43 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 6 Mar 2011 12:11:57 +0100 Subject: [PATCH 098/400] configurable ship damage --- src/gamecode/laws.c | 6 ++++-- src/gamecode/randenc.c | 12 ++++++++---- src/items/weapons.c | 6 ++++-- src/kernel/battle.c | 4 +++- src/kernel/move.c | 5 +++-- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 762b4c0ae..e0bc75e9a 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -2677,10 +2677,12 @@ sinkships(region * r) if (!sh->type->construction || sh->size>=sh->type->construction->maxsize) { if (fval(r->terrain, SEA_REGION) && (!enoughsailors(sh, r) || get_captain(sh)==NULL)) { /* Schiff nicht seetüchtig */ - damage_ship(sh, 0.30); + float dmg = get_param_flt(global.parameters, "rules.ship.damage.nocrewocean", 0.30); + damage_ship(sh, dmg); } if (shipowner(sh)==NULL) { - damage_ship(sh, 0.05); + float dmg = get_param_flt(global.parameters, "rules.ship.damage.nocrew", 0.05); + damage_ship(sh, dmg); } } if (sh->damage >= sh->size * DAMAGE_SCALE) { diff --git a/src/gamecode/randenc.c b/src/gamecode/randenc.c index a80eddea0..3b7cb3a03 100644 --- a/src/gamecode/randenc.c +++ b/src/gamecode/randenc.c @@ -503,7 +503,8 @@ chaos(region * r) while (sh) { ship * nsh = sh->next; - damage_ship(sh, 0.50); + float dmg = get_param_flt(global.parameters, "rules.ship.damage.atlantis", 0.50); + damage_ship(sh, dmg); if (sh->damage >= sh->size * DAMAGE_SCALE) { remove_ship(&sh->region->ships, sh); } @@ -854,7 +855,8 @@ move_iceberg(region *r) for (sh = r->ships; sh; sh = sh->next) { /* Meldung an Kapitän */ - damage_ship(sh, 0.10); + float dmg = get_param_flt(global.parameters, "rules.ship.damage.intoiceberg", 0.10); + damage_ship(sh, dmg); fset(sh, SF_SELECT); } @@ -865,7 +867,8 @@ move_iceberg(region *r) } while (rc->ships) { fset(rc->ships, SF_SELECT); - damage_ship(rc->ships, 0.10); + float dmg = get_param_flt(global.parameters, "rules.ship.damage.withiceberg", 0.10); + damage_ship(rc->ships, dmg); move_ship(rc->ships, rc, r, NULL); } while (rc->units) { @@ -991,7 +994,8 @@ godcurse(void) ship *sh; for (sh = r->ships; sh;) { ship *shn = sh->next; - damage_ship(sh, 0.10); + float dmg = get_param_flt(global.parameters, "rules.ship.damage.godcurse", 0.10); + damage_ship(sh, dmg); if (sh->damage>=sh->size * DAMAGE_SCALE) { unit * u = shipowner(sh); if (u) ADDMSG(&u->faction->msgs, diff --git a/src/items/weapons.c b/src/items/weapons.c index 11c0379c8..77a62ce59 100644 --- a/src/items/weapons.c +++ b/src/items/weapons.c @@ -136,9 +136,11 @@ attack_catapult(const troop * at, const struct weapon_type * wtype, int * casual d += terminate(dt, *at, AT_STANDARD, wp->type->damage[0], true); #ifdef CATAPULT_STRUCTURAL_DAMAGE if (dt.fighter->unit->building && rng_int()%100 < 5) { - damage_building(b, dt.fighter->unit->building, 1); + float dmg = get_param_flt(global.parameters, "rules.building.damage.catapult", 1); + damage_building(b, dt.fighter->unit->building, dmg); } else if (dt.fighter->unit->ship && rng_int()%100 < 5) { - dt.fighter->unit->ship->damage+=DAMAGE_SCALE; + float dmg = get_param_flt(global.parameters, "rules.ship.damage.catapult", 0.01); + damage_ship(dt.fighter->unit->ship, dmg) } #endif } diff --git a/src/kernel/battle.c b/src/kernel/battle.c index 35c48dfb6..579838ed1 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -2634,6 +2634,7 @@ aftermath(battle * b) boolean ships_damaged = (boolean)(b->turn+(b->has_tactics_turn?1:0)>2); /* only used for ship damage! */ for (s=b->sides;s!=b->sides+b->nsides;++s) { + s->dead=0; fighter * df; for (df = s->fighters; df; df=df->next) { unit *du = df->unit; @@ -2882,7 +2883,8 @@ aftermath(battle * b) if (sh && fval(sh, SF_DAMAGED)) { int n = b->turn - 2; if (n>0) { - damage_ship(sh, 0.05 * n); + float dmg = get_param_flt(global.parameters, "rules.ship.damage.battleround", 0.05); + damage_ship(sh, dmg * n); freset(sh, SF_DAMAGED); } } diff --git a/src/kernel/move.c b/src/kernel/move.c index 95bead255..e34411cba 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -1276,7 +1276,7 @@ make_route(unit * u, order * ord, region_list ** routep) * * Berechnet wird das mit BPs. Zu Fuß hat man 4 BPs, zu Pferd 6. * Normalerweise verliert man 3 BP pro Region, bei Straßen nur 2 BP. - * Außerdem: Wenn Einheit transportiert, nur halbe BP + * Außerdem: Wenn Einheit transportiert, nur halbe BP */ static int movement_speed(unit * u) @@ -1766,7 +1766,8 @@ sail(unit * u, order * ord, boolean move_on_land, region_list **routep) ADDMSG(&f->msgs, msg_message("sailnolandingstorm", "ship", sh)); } else { ADDMSG(&f->msgs, msg_message("sailnolanding", "ship region", sh, next_point)); - damage_ship(sh, 0.10); + float dmg = get_param_flt(global.parameters, "rules.ship.damage.nolanding", 0.10); + damage_ship(sh, dmg); /* we handle destruction at the end */ } break; From 623c0dce840ad9cc59f18d30a63071e0ad3ab088 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 6 Mar 2011 12:38:49 +0100 Subject: [PATCH 099/400] empty ships sink --- src/kernel/move.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/move.c b/src/kernel/move.c index e34411cba..6756739a0 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -1897,7 +1897,7 @@ get_captain(const ship * sh) unit *u; for (u = r->units; u; u = u->next) { - if (u->ship == sh && eff_skill(u, SK_SAILING, r) >= sh->type->cptskill) + if (u->ship == sh && u->number && eff_skill(u, SK_SAILING, r) >= sh->type->cptskill) return u; } From d672510f06e7d17c357381746d2bcb753f900aad Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 6 Mar 2011 11:31:12 +0100 Subject: [PATCH 100/400] two little remarks --- src/kernel/battle.c | 1 + src/util/language.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/kernel/battle.c b/src/kernel/battle.c index 579838ed1..a6fa318de 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -2224,6 +2224,7 @@ attack(battle *b, troop ta, const att *a, int numattack) combat_action(ta.fighter, b->turn); } if (td.fighter->unit->ship) { + /* FIXME should use damage_ship here? */ td.fighter->unit->ship->damage += DAMAGE_SCALE * dice_rand(a->data.dice); } else if (td.fighter->unit->building) { damage_building(b, td.fighter->unit->building, dice_rand(a->data.dice)); diff --git a/src/util/language.c b/src/util/language.c index 298cf92b0..707928677 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -197,7 +197,7 @@ locale_setstring(locale * lang, const char * key, const char * value) } else { if (strcmp(find->str, value)!=0) { - log_error(("Duplicate key %s for '%s' and '%s'\n", key, value, find->str)); + log_error(("Duplicate values '%s' and '%s' for %s\n", value, find->str, key)); } assert(!strcmp(find->str, value) || !"duplicate string for key"); } From d75ee1a057656be870861b828c060dd7ce56abee Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 6 Mar 2011 17:00:39 -0800 Subject: [PATCH 101/400] Make the code compile on Visual Studio again, fixing type conversion warnings and C99-isms. Signed-off-by: Enno Rehling --- src/gamecode/laws.c | 4 ++-- src/gamecode/randenc.c | 6 +++--- src/kernel/battle.c | 5 +++-- src/kernel/move.c | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index e0bc75e9a..94144b370 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -2677,11 +2677,11 @@ sinkships(region * r) if (!sh->type->construction || sh->size>=sh->type->construction->maxsize) { if (fval(r->terrain, SEA_REGION) && (!enoughsailors(sh, r) || get_captain(sh)==NULL)) { /* Schiff nicht seetüchtig */ - float dmg = get_param_flt(global.parameters, "rules.ship.damage.nocrewocean", 0.30); + float dmg = get_param_flt(global.parameters, "rules.ship.damage.nocrewocean", 0.30F); damage_ship(sh, dmg); } if (shipowner(sh)==NULL) { - float dmg = get_param_flt(global.parameters, "rules.ship.damage.nocrew", 0.05); + float dmg = get_param_flt(global.parameters, "rules.ship.damage.nocrew", 0.05F); damage_ship(sh, dmg); } } diff --git a/src/gamecode/randenc.c b/src/gamecode/randenc.c index 3b7cb3a03..7d6a0d58d 100644 --- a/src/gamecode/randenc.c +++ b/src/gamecode/randenc.c @@ -855,7 +855,7 @@ move_iceberg(region *r) for (sh = r->ships; sh; sh = sh->next) { /* Meldung an Kapitän */ - float dmg = get_param_flt(global.parameters, "rules.ship.damage.intoiceberg", 0.10); + float dmg = get_param_flt(global.parameters, "rules.ship.damage.intoiceberg", 0.10F); damage_ship(sh, dmg); fset(sh, SF_SELECT); } @@ -866,8 +866,8 @@ move_iceberg(region *r) translist(&rc->buildings, &r->buildings, rc->buildings); } while (rc->ships) { + float dmg = get_param_flt(global.parameters, "rules.ship.damage.withiceberg", 0.10F); fset(rc->ships, SF_SELECT); - float dmg = get_param_flt(global.parameters, "rules.ship.damage.withiceberg", 0.10); damage_ship(rc->ships, dmg); move_ship(rc->ships, rc, r, NULL); } @@ -994,7 +994,7 @@ godcurse(void) ship *sh; for (sh = r->ships; sh;) { ship *shn = sh->next; - float dmg = get_param_flt(global.parameters, "rules.ship.damage.godcurse", 0.10); + float dmg = get_param_flt(global.parameters, "rules.ship.damage.godcurse", 0.10F); damage_ship(sh, dmg); if (sh->damage>=sh->size * DAMAGE_SCALE) { unit * u = shipowner(sh); diff --git a/src/kernel/battle.c b/src/kernel/battle.c index a6fa318de..fee9a4055 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -2635,8 +2635,9 @@ aftermath(battle * b) boolean ships_damaged = (boolean)(b->turn+(b->has_tactics_turn?1:0)>2); /* only used for ship damage! */ for (s=b->sides;s!=b->sides+b->nsides;++s) { - s->dead=0; fighter * df; + s->dead=0; + for (df = s->fighters; df; df=df->next) { unit *du = df->unit; int dead = dead_fighters(df); @@ -2884,7 +2885,7 @@ aftermath(battle * b) if (sh && fval(sh, SF_DAMAGED)) { int n = b->turn - 2; if (n>0) { - float dmg = get_param_flt(global.parameters, "rules.ship.damage.battleround", 0.05); + float dmg = get_param_flt(global.parameters, "rules.ship.damage.battleround", 0.05F); damage_ship(sh, dmg * n); freset(sh, SF_DAMAGED); } diff --git a/src/kernel/move.c b/src/kernel/move.c index 6756739a0..dbcedd03d 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -1765,8 +1765,8 @@ sail(unit * u, order * ord, boolean move_on_land, region_list **routep) if (check_leuchtturm(current_point, NULL)) { ADDMSG(&f->msgs, msg_message("sailnolandingstorm", "ship", sh)); } else { + float dmg = get_param_flt(global.parameters, "rules.ship.damage.nolanding", 0.10F); ADDMSG(&f->msgs, msg_message("sailnolanding", "ship region", sh, next_point)); - float dmg = get_param_flt(global.parameters, "rules.ship.damage.nolanding", 0.10); damage_ship(sh, dmg); /* we handle destruction at the end */ } From 3677e899af3a7bc3e570ea41f468f57f91ed20d2 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 6 Mar 2011 19:56:20 -0800 Subject: [PATCH 102/400] Do not assert on unknown skills, but log them as an error. --- src/kernel/xmlreader.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 887d04337..6ead426d1 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1271,12 +1271,16 @@ add_skills(equipment * eq, xmlNodeSetPtr nsetSkills) propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue!=NULL); sk = sk_find((const char*)propValue); - assert(sk!=NOSKILL); - xmlFree(propValue); - propValue = xmlGetProp(node, BAD_CAST "level"); - if (propValue!=NULL) { - equipment_setskill(eq, sk, (const char*)propValue); + if (sk==NOSKILL) { + log_error(("unknown skill '%s' in equipment-set %s\n", (const char*)propValue, eq->name)); xmlFree(propValue); + } else { + xmlFree(propValue); + propValue = xmlGetProp(node, BAD_CAST "level"); + if (propValue!=NULL) { + equipment_setskill(eq, sk, (const char*)propValue); + xmlFree(propValue); + } } } } From 36e53069e08ff4b2f3f4fa845c33834532640baa Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 6 Mar 2011 21:11:17 -0800 Subject: [PATCH 103/400] use quicklist to store ship types. --- src/kernel/ship.c | 150 ++++++++++++++++++++++++---------------------- src/kernel/ship.h | 7 +-- 2 files changed, 80 insertions(+), 77 deletions(-) diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 4f9364fa7..cbb755d3a 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -35,6 +35,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include @@ -45,52 +46,59 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include -ship_typelist *shiptypes = NULL; +quicklist *shiptypes = NULL; static local_names * snames; const ship_type * findshiptype(const char * name, const struct locale * lang) { - local_names * sn = snames; - variant var; + local_names * sn = snames; + variant var; - while (sn) { - if (sn->lang==lang) break; - sn=sn->next; - } - if (!sn) { - struct ship_typelist * stl = shiptypes; - sn = calloc(sizeof(local_names), 1); - sn->next = snames; - sn->lang = lang; - while (stl) { + while (sn) { + if (sn->lang==lang) break; + sn=sn->next; + } + if (!sn) { + quicklist * ql; + int qi; + + sn = (local_names *)calloc(sizeof(local_names), 1); + sn->next = snames; + sn->lang = lang; + + for (qi=0,ql=shiptypes;ql;ql_advance(&ql, &qi, 1)) { + ship_type * stype = (ship_type *)ql_get(ql, qi); variant var; - const char * n = locale_string(lang, stl->type->name[0]); - var.v = (void*)stl->type; - addtoken(&sn->names, n, var); - stl = stl->next; - } - snames = sn; - } - if (findtoken(&sn->names, name, &var)==E_TOK_NOMATCH) return NULL; - return (const ship_type*)var.v; + const char * n = locale_string(lang, stype->name[0]); + var.v = (void*)stype; + addtoken(&sn->names, n, var); + } + snames = sn; + } + if (findtoken(&sn->names, name, &var)==E_TOK_NOMATCH) return NULL; + return (const ship_type*)var.v; } const ship_type * st_find(const char* name) { - const struct ship_typelist * stl = shiptypes; - while (stl && strcmp(stl->type->name[0], name)) stl = stl->next; - return stl?stl->type:NULL; + quicklist * ql; + int qi; + + for (qi=0,ql=shiptypes;ql;ql_advance(&ql, &qi, 1)) { + ship_type * stype = (ship_type *)ql_get(ql, qi); + if (strcmp(stype->name[0], name)==0) { + return stype; + } + } + return NULL; } void st_register(const ship_type * type) { - struct ship_typelist * stl = malloc(sizeof(ship_type)); - stl->type = type; - stl->next = shiptypes; - shiptypes = stl; + ql_push(&shiptypes, (void *)type); } #define SMAXHASH 7919 @@ -98,43 +106,43 @@ ship *shiphash[SMAXHASH]; void shash(ship * s) { - ship *old = shiphash[s->no % SMAXHASH]; + ship *old = shiphash[s->no % SMAXHASH]; - shiphash[s->no % SMAXHASH] = s; - s->nexthash = old; + shiphash[s->no % SMAXHASH] = s; + s->nexthash = old; } void sunhash(ship * s) { - ship **show; + ship **show; - for (show = &shiphash[s->no % SMAXHASH]; *show; show = &(*show)->nexthash) { - if ((*show)->no == s->no) - break; - } - if (*show) { - assert(*show == s); - *show = (*show)->nexthash; - s->nexthash = 0; - } + for (show = &shiphash[s->no % SMAXHASH]; *show; show = &(*show)->nexthash) { + if ((*show)->no == s->no) + break; + } + if (*show) { + assert(*show == s); + *show = (*show)->nexthash; + s->nexthash = 0; + } } static ship * sfindhash(int i) { - ship *old; + ship *old; - for (old = shiphash[i % SMAXHASH]; old; old = old->nexthash) - if (old->no == i) - return old; - return 0; + for (old = shiphash[i % SMAXHASH]; old; old = old->nexthash) + if (old->no == i) + return old; + return 0; } struct ship * findship(int i) { - return sfindhash(i); + return sfindhash(i); } struct ship * @@ -154,19 +162,19 @@ findshipr(const region *r, int n) void damage_ship(ship * sh, double percent) { - double damage = DAMAGE_SCALE * sh->type->damage * percent * sh->size + sh->damage; - sh->damage = (int)damage; + double damage = DAMAGE_SCALE * sh->type->damage * percent * sh->size + sh->damage; + sh->damage = (int)damage; } unit * captain(ship *sh) { - unit *u; + unit *u; - for(u = sh->region->units; u; u = u->next) - if(u->ship == sh && fval(u, UFL_OWNER)) return u; + for(u = sh->region->units; u; u = u->next) + if(u->ship == sh && fval(u, UFL_OWNER)) return u; - return NULL; + return NULL; } /* Alte Schiffstypen: */ @@ -293,29 +301,29 @@ getshipweight(const ship * sh, int *sweight, int *scabins) unit * shipowner(const ship * sh) { - unit *u; - unit *first = NULL; + unit *u; + unit *first = NULL; const region * r = sh->region; /* Prüfen ob Eigentümer am leben. */ - for (u = r->units; u; u = u->next) { - if (u->ship == sh) { - if (!first && u->number > 0) - first = u; - if (fval(u, UFL_OWNER) && u->number > 0) - return u; - if (u->number == 0) - freset(u, UFL_OWNER); - } - } + for (u = r->units; u; u = u->next) { + if (u->ship == sh) { + if (!first && u->number > 0) + first = u; + if (fval(u, UFL_OWNER) && u->number > 0) + return u; + if (u->number == 0) + freset(u, UFL_OWNER); + } + } - /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit - * nehmen. */ + /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit + * nehmen. */ - if (first) - fset(first, UFL_OWNER); - return first; + if (first) + fset(first, UFL_OWNER); + return first; } void diff --git a/src/kernel/ship.h b/src/kernel/ship.h index 0bc8ee9d4..411225bf8 100644 --- a/src/kernel/ship.h +++ b/src/kernel/ship.h @@ -59,12 +59,7 @@ typedef struct ship_type { struct construction * construction; /* how to build a ship */ } ship_type; -typedef struct ship_typelist { - struct ship_typelist * next; - const ship_type * type; -} ship_typelist; - -extern ship_typelist *shiptypes; +extern struct quicklist *shiptypes; /* Alte Schiffstypen: */ From fb94908014edcba5b14bfd384b84e22842bd7427 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 6 Mar 2011 21:12:55 -0800 Subject: [PATCH 104/400] export resources and shiptypes as part of configuration. --- src/bindings/bindings.c | 64 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index 68ed85a61..a700a9186 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -848,7 +848,23 @@ tolua_write_spells(lua_State* L) } static int -tolua_get_locales(lua_State *L) +config_get_ships(lua_State *L) +{ + quicklist * ql; + int qi, i=0; + + lua_createtable(L, ql_length(shiptypes), 0); + + for (qi=0,ql=shiptypes;ql;ql_advance(&ql, &qi, 1)) { + ship_type * stype = (ship_type *)ql_get(ql, qi); + tolua_pushstring(L, TOLUA_CAST stype->name); + lua_rawseti(L, -2, ++i); + } + return 1; +} + +static int +config_get_locales(lua_State *L) { const struct locale * lang; int i = 0, n = 0; @@ -863,6 +879,48 @@ tolua_get_locales(lua_State *L) return 1; } +static int +config_get_resource(lua_State *L) +{ + const char * name = tolua_tostring(L, 1, 0); + if (name) { + const struct item_type * itype = it_find(name); + if (itype) { + lua_newtable(L); + lua_pushstring(L, "weight"); + lua_pushinteger(L, itype->weight); + lua_settable(L, -3); + if (itype->capacity>0) { + lua_pushstring(L, "capacity"); + lua_pushinteger(L, itype->capacity); + lua_settable(L, -3); + } + if (itype->construction) { + int i; + lua_pushstring(L, "build_skill_min"); + lua_pushinteger(L, itype->construction->minskill); + lua_settable(L, -3); + lua_pushstring(L, "build_skill_name"); + lua_pushstring(L, skillnames[itype->construction->skill]); + lua_settable(L, -3); + + if (itype->construction->materials) { + lua_pushstring(L, "materials"); + lua_newtable(L); + for (i=0;itype->construction->materials[i].number;++i) { + lua_pushstring(L, itype->construction->materials[i].rtype->_name[0]); + lua_pushinteger(L, itype->construction->materials[i].number); + lua_settable(L, -3); + } + lua_settable(L, -3); + } + } + return 1; + } + } + return 0; +} + static int tolua_get_spell_text(lua_State *L) { @@ -1134,7 +1192,9 @@ tolua_eressea_open(lua_State* L) tolua_beginmodule(L, TOLUA_CAST "config"); { parse_inifile(L, global.inifile, "config"); - tolua_variable(L, TOLUA_CAST "locales", &tolua_get_locales, 0); + tolua_variable(L, TOLUA_CAST "locales", &config_get_locales, 0); + tolua_function(L, TOLUA_CAST "get_resource", &config_get_resource); + tolua_variable(L, TOLUA_CAST "ships", &config_get_ships, 0); } tolua_endmodule(L); From 1be42e9d505b07ec65a9410db03cd411edbfdff1 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 6 Mar 2011 21:49:01 -0800 Subject: [PATCH 105/400] Make all tests for Eressea pass again, using the config module. --- scripts/tests/common.lua | 90 +++++++++++++++++++--------------------- src/bindings/bindings.c | 21 +--------- 2 files changed, 43 insertions(+), 68 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index c836e4272..808d68ff4 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -1,7 +1,7 @@ require "lunit" local function _test_create_ship(r) - local s = ship.create(r, test.shipname) + local s = ship.create(r, config.ships[1]) return s end @@ -287,17 +287,17 @@ function test_events() end function test_recruit2() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - local u = unit.create(f, r) - u.number = 1 - u:add_item("money", 2000) - u:clear_orders() - u:add_order("MACHE TEMP 1") - u:add_order("REKRUTIERE 1 Elf") - u:add_order("REKRUTIERE 1 mensch") - u:add_order("REKRUTIERE 1") - process_orders() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r) + u.number = 1 + u:add_item("money", 2000) + u:clear_orders() + u:add_order("MACHE TEMP 1") + u:add_order("REKRUTIERE 1 Elf") + u:add_order("REKRUTIERE 1 Mensch") + u:add_order("REKRUTIERE 1") + process_orders() end function test_guard() @@ -350,13 +350,14 @@ function test_produce() local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r, 1) u:clear_orders() - u:set_skill("weaponsmithing", 3) + local sword = config.get_resource('sword') + u:set_skill(sword.build_skill_name, 3) u:add_item("iron", 10) u:add_item("money", u.number * 10) u:add_order("MACHE Schwert") process_orders() - assert_equal(10-3/test.swordmakeskill*test.swordiron, u:get_item("iron")) - assert_equal(3/test.swordmakeskill, u:get_item("sword")) + assert_equal(10-3/sword.build_skill_min*sword.materials['iron'], u:get_item("iron")) + assert_equal(3/sword.build_skill_min, u:get_item("sword")) end function test_work() @@ -457,7 +458,8 @@ function test_mallorn() assert(u1:get_item("log")==2) assert(u2:get_item("log")==2) - if (has_item("mallorn")) then + local mallorn_cfg = config.get_resource("mallorn") + if mallorn_cfg then assert(u3:get_item("mallorn")==1) else assert_equal(-1, u3:get_item("mallorn")) @@ -701,9 +703,9 @@ function test_ride_with_horse() local r = region.create(0, 0, "plain") local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r, 1) - local pweight = u.weight u:add_item("horse", 1) - u:add_item("sword", (test.horsecapacity - pweight)/100) + local horse_cfg = config.get_resource("horse") + u:add_item("sword", (horse_cfg.capacity - u.weight)/100) u:set_skill("riding", 2) u:clear_orders() @@ -724,36 +726,31 @@ function test_ride_with_horses_and_cart() local r = region.create(0, 0, "plain") local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r, 1) - local carts = 0 - local horses = 0 - local pweight = u.weight - if (has_item("cart")) then - u:add_item("cart", 1) - assert_equal(1, u:get_item("cart")) -- every game has a cart, right? right? no! atlantis hasn't! - carts = u:get_item("cart") - end - u:add_item("horse", 1) - assert_equal(1, u:get_item("horse")) -- every game has a horse, right? right? - local horses = u:get_item("horse") - assert(horses+carts>0) - local capacity = test.horsecapacity*(horses+1) + test.cartcapacity*carts - pweight - capacity = capacity / 100 - u:add_item("sword", capacity) - assert_equal(capacity, u:get_item("sword")) -- every game has a sword, right? and it weighs 1 unit? - + local horse_cfg = config.get_resource("horse") + local cart_cfg = config.get_resource("cart") + local sword_cfg = config.get_resource("sword") + u:set_skill("riding", 3) - if (has_item("cart")) then - -- need 2 horses for a cart - u:clear_orders() - u:add_order("NACH O O") - process_orders() - assert_equal(0, u.region.x) + local capacity = (horse_cfg.capacity-horse_cfg.weight)*2 - u.weight + if cart_cfg~=nil then + capacity = capacity + cart_cfg.capacity-cart_cfg.weight end + u:add_item("sword", capacity / sword_cfg.weight) + u:add_item("horse", 1) + if (cart_cfg~=nil) then + -- we need 2 horses for a cart, so this should fail: + u:add_item("cart", 1) + u:clear_orders() + u:add_order("NACH O O") + process_orders() + assert_equal(0, u.region.x) + end + + -- here is your second horse, milord: u:add_item("horse", 1) assert_equal(2, u:get_item("horse")) - horses = u:get_item("horse") -- ride u:clear_orders() @@ -762,17 +759,14 @@ function test_ride_with_horses_and_cart() assert_equal(2, u.region.x) -- walk - u:add_item("sword", 10) - r:get_key("eviL") + u:add_item("sword", 1000/sword_cfg.weight) u:clear_orders() u:add_order("NACH W W") process_orders() assert_equal(1, u.region.x) - -- too heavy - - u:add_item("sword", 10) - r:get_key("eviL") + -- make this fellow too heavy + u:add_item("sword", 1000/sword_cfg.weight) u:clear_orders() u:add_order("NACH W W") process_orders() diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index a700a9186..8cef22507 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -857,7 +857,7 @@ config_get_ships(lua_State *L) for (qi=0,ql=shiptypes;ql;ql_advance(&ql, &qi, 1)) { ship_type * stype = (ship_type *)ql_get(ql, qi); - tolua_pushstring(L, TOLUA_CAST stype->name); + tolua_pushstring(L, TOLUA_CAST stype->name[0]); lua_rawseti(L, -2, ++i); } return 1; @@ -1076,22 +1076,6 @@ tolua_settings_set(lua_State* L) return 0; } -/* - * Paramter: item name - * Returns true if the item type is known in the game - */ -static int -tolua_has_item(lua_State* L) -{ - const char * iname = tolua_tostring(L, 1, 0); - const item_type * itype = NULL; - if (iname!=NULL) { - itype = it_find(iname); - } - lua_pushboolean(L, itype!=NULL); - return 1; -} - static void parse_inifile(lua_State* L, dictionary * d, const char * section) { @@ -1278,9 +1262,6 @@ tolua_eressea_open(lua_State* L) tolua_function(L, TOLUA_CAST "read_xml", tolua_read_xml); - /* test helpers */ - tolua_function(L, TOLUA_CAST "has_item", tolua_has_item); - } tolua_endmodule(L); return 1; From 7a983c80cf10c470024aafc0b77d5794a7c0b02e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 6 Mar 2011 22:06:30 -0800 Subject: [PATCH 106/400] * there are no boats * skill should only use 4 bytes --- src/kernel/skill.h | 23 ++++++++++------------- src/util/language.c | 2 +- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/kernel/skill.h b/src/kernel/skill.h index 3f8ec53ce..32185ab19 100644 --- a/src/kernel/skill.h +++ b/src/kernel/skill.h @@ -16,29 +16,26 @@ extern "C" { #endif -/* FIXME where is this defined?? */ -extern signed char skill_bonus(struct unit * u, struct region * r); - /* skillmod_data::flags -- wann gilt der modifier? */ #define SMF_ALWAYS (1<<0) /* immer */ #define SMF_PRODUCTION (1<<1) /* für Produktion - am gebäude, an der einheit */ #define SMF_RIDING (1<<2) /* Bonus für berittene - an der rasse*/ typedef struct skill { - skill_t id; - unsigned int level : 8; - unsigned int weeks : 8; - unsigned int old : 8; + skill_t id : 8; + unsigned int level : 8; + unsigned int weeks : 8; + unsigned int old : 8; } skill; typedef int (*skillmod_fun)(const struct unit*, const struct region*, skill_t, int); typedef struct skillmod_data { - skill_t skill; - skillmod_fun special; - double multiplier; - int number; - int bonus; - int flags; + skill_t skill; + skillmod_fun special; + double multiplier; + int number; + int bonus; + int flags; } skillmod_data; extern struct attrib_type at_skillmod; extern int rc_skillmod(const struct race * rc, const struct region *r, skill_t sk); diff --git a/src/util/language.c b/src/util/language.c index 707928677..00e1adff8 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -197,7 +197,7 @@ locale_setstring(locale * lang, const char * key, const char * value) } else { if (strcmp(find->str, value)!=0) { - log_error(("Duplicate values '%s' and '%s' for %s\n", value, find->str, key)); + log_error(("duplicate translation '%s' for key %s\n", value, key)); } assert(!strcmp(find->str, value) || !"duplicate string for key"); } From fb7a642d47c30b7875b21940b34f7f0b936d9784 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 7 Mar 2011 08:02:35 +0100 Subject: [PATCH 107/400] indentation rules, strictly applied --- src/attributes/aggressive.h | 7 +- src/attributes/alliance.c | 14 +- src/attributes/alliance.h | 3 +- src/attributes/attributes.c | 3 +- src/attributes/attributes.h | 3 +- src/attributes/fleechance.c | 27 +- src/attributes/fleechance.h | 6 +- src/attributes/follow.c | 11 +- src/attributes/follow.h | 7 +- src/attributes/giveitem.c | 117 +- src/attributes/giveitem.h | 10 +- src/attributes/gm.c | 34 +- src/attributes/gm.h | 7 +- src/attributes/hate.c | 45 +- src/attributes/hate.h | 7 +- src/attributes/iceberg.c | 24 +- src/attributes/iceberg.h | 5 +- src/attributes/key.c | 43 +- src/attributes/key.h | 9 +- src/attributes/matmod.c | 24 +- src/attributes/matmod.h | 12 +- src/attributes/moved.c | 40 +- src/attributes/moved.h | 11 +- src/attributes/movement.c | 40 +- src/attributes/movement.h | 6 +- src/attributes/object.c | 111 +- src/attributes/object.h | 21 +- src/attributes/orcification.c | 12 +- src/attributes/orcification.h | 4 +- src/attributes/otherfaction.c | 37 +- src/attributes/otherfaction.h | 15 +- src/attributes/overrideroads.c | 3 +- src/attributes/overrideroads.h | 3 +- src/attributes/racename.c | 17 +- src/attributes/racename.h | 11 +- src/attributes/raceprefix.c | 28 +- src/attributes/raceprefix.h | 7 +- src/attributes/reduceproduction.c | 33 +- src/attributes/reduceproduction.h | 5 +- src/attributes/targetregion.c | 38 +- src/attributes/targetregion.h | 7 +- src/attributes/viewrange.c | 60 +- src/attributes/viewrange.h | 10 +- src/bindings/bind_attrib.c | 449 +++-- src/bindings/bind_attrib.h | 2 +- src/bindings/bind_building.c | 196 +- src/bindings/bind_faction.c | 448 +++-- src/bindings/bind_gmtool.c | 138 +- src/bindings/bind_hashtable.c | 68 +- src/bindings/bind_hashtable.h | 2 +- src/bindings/bind_message.c | 216 +- src/bindings/bind_region.c | 560 +++--- src/bindings/bind_ship.c | 143 +- src/bindings/bind_sqlite.c | 60 +- src/bindings/bind_storage.c | 91 +- src/bindings/bind_unit.c | 792 ++++---- src/bindings/bindings.c | 897 +++++---- src/bindings/bindings.h | 11 +- src/bindings/helpers.c | 434 ++-- src/bindings/helpers.h | 4 +- src/eressea.c | 60 +- src/eressea.h | 7 +- src/gamecode/archetype.c | 86 +- src/gamecode/archetype.h | 25 +- src/gamecode/creation.c | 7 +- src/gamecode/creation.h | 2 +- src/gamecode/creport.c | 1136 ++++++----- src/gamecode/creport.h | 7 +- src/gamecode/economy.c | 2771 +++++++++++++++----------- src/gamecode/economy.h | 24 +- src/gamecode/give.c | 222 ++- src/gamecode/give.h | 8 +- src/gamecode/items.c | 134 +- src/gamecode/laws.c | 3065 ++++++++++++++++------------- src/gamecode/laws.h | 30 +- src/gamecode/laws_test.c | 117 +- src/gamecode/market.c | 138 +- src/gamecode/market_test.c | 54 +- src/gamecode/monster.c | 79 +- src/gamecode/monster.h | 4 +- src/gamecode/randenc.c | 1331 +++++++------ src/gamecode/randenc.h | 4 +- src/gamecode/report.c | 1765 ++++++++++------- src/gamecode/report.h | 1 - src/gamecode/spy.c | 336 ++-- src/gamecode/spy.h | 15 +- src/gamecode/study.c | 541 ++--- src/gamecode/study.h | 21 +- src/gamecode/summary.c | 169 +- src/gamecode/summary.h | 5 +- src/gamecode/xmlreport.c | 460 +++-- src/gamecode/xmlreport.h | 7 +- src/gmtool.c | 1382 +++++++------ src/gmtool.h | 14 +- src/gmtool_structs.h | 116 +- src/items/artrewards.c | 70 +- src/items/artrewards.h | 2 +- src/items/demonseye.c | 30 +- src/items/demonseye.h | 2 +- src/items/itemtypes.c | 6 +- src/items/itemtypes.h | 4 +- src/items/phoenixcompass.c | 77 +- src/items/phoenixcompass.h | 2 +- src/items/seed.c | 57 +- src/items/seed.h | 8 +- src/items/speedsail.c | 20 +- src/items/speedsail.h | 2 +- src/items/studypotion.c | 26 +- src/items/weapons.c | 140 +- src/items/weapons.h | 2 +- src/items/xerewards.c | 44 +- src/items/xerewards.h | 2 +- src/kernel/alchemy.c | 246 ++- src/kernel/alchemy.h | 73 +- src/kernel/alliance.c | 410 ++-- src/kernel/alliance.h | 64 +- src/kernel/battle.c | 3012 ++++++++++++++++------------ src/kernel/battle.h | 195 +- src/kernel/binarystore.c | 165 +- src/kernel/binarystore.h | 2 +- src/kernel/build.c | 823 ++++---- src/kernel/build.h | 89 +- src/kernel/building.c | 495 ++--- src/kernel/building.h | 161 +- src/kernel/calendar.c | 52 +- src/kernel/calendar.h | 52 +- src/kernel/command.c | 50 +- src/kernel/command.h | 28 +- src/kernel/config.c | 2074 ++++++++++--------- src/kernel/config.h | 478 ++--- src/kernel/connection.c | 544 +++-- src/kernel/connection.h | 127 +- src/kernel/curse.c | 396 ++-- src/kernel/curse.h | 258 +-- src/kernel/curse_test.c | 14 +- src/kernel/equipment.c | 145 +- src/kernel/equipment.h | 46 +- src/kernel/faction.c | 286 +-- src/kernel/faction.h | 187 +- src/kernel/group.c | 171 +- src/kernel/group.h | 36 +- src/kernel/item.c | 859 ++++---- src/kernel/item.h | 498 ++--- src/kernel/magic.c | 1815 +++++++++-------- src/kernel/magic.h | 500 ++--- src/kernel/message.c | 194 +- src/kernel/message.h | 49 +- src/kernel/move.c | 2012 ++++++++++--------- src/kernel/move.h | 53 +- src/kernel/names.c | 452 +++-- src/kernel/names.h | 18 +- src/kernel/objtypes.h | 21 +- src/kernel/order.c | 350 ++-- src/kernel/order.h | 45 +- src/kernel/pathfinder.c | 239 ++- src/kernel/pathfinder.h | 26 +- src/kernel/plane.c | 206 +- src/kernel/plane.h | 97 +- src/kernel/player.c | 122 +- src/kernel/player.h | 34 +- src/kernel/pool.c | 188 +- src/kernel/pool.h | 22 +- src/kernel/race.c | 180 +- src/kernel/race.h | 231 +-- src/kernel/region.c | 1007 +++++----- src/kernel/region.h | 351 ++-- src/kernel/reports.c | 1947 ++++++++++-------- src/kernel/reports.h | 163 +- src/kernel/resources.c | 214 +- src/kernel/resources.h | 71 +- src/kernel/save.c | 1152 ++++++----- src/kernel/save.h | 65 +- src/kernel/ship.c | 165 +- src/kernel/ship.h | 120 +- src/kernel/skill.c | 358 ++-- src/kernel/skill.h | 70 +- src/kernel/spell.c | 139 +- src/kernel/spell.h | 23 +- src/kernel/spellid.h | 4 +- src/kernel/sqlite.c | 176 +- src/kernel/teleport.c | 168 +- src/kernel/teleport.h | 14 +- src/kernel/terrain.c | 98 +- src/kernel/terrain.h | 90 +- src/kernel/terrainid.h | 51 +- src/kernel/textstore.c | 142 +- src/kernel/textstore.h | 2 +- src/kernel/types.h | 101 +- src/kernel/unit.c | 1088 +++++----- src/kernel/unit.h | 285 +-- src/kernel/version.h | 42 +- src/kernel/xmlkernel.h | 4 +- src/kernel/xmlreader.c | 1851 ++++++++++------- src/kernel/xmlreader.h | 3 +- src/modules/arena.c | 609 +++--- src/modules/arena.h | 6 +- src/modules/autoseed.c | 877 +++++---- src/modules/autoseed.h | 41 +- src/modules/dungeon.c | 403 ++-- src/modules/dungeon.h | 17 +- src/modules/gmcmd.c | 644 +++--- src/modules/gmcmd.h | 22 +- src/modules/museum.c | 474 ++--- src/modules/museum.h | 33 +- src/modules/score.c | 138 +- src/modules/score.h | 4 +- src/modules/weather.c | 144 +- src/modules/weather.h | 34 +- src/modules/wormhole.c | 158 +- src/modules/xecmd.c | 60 +- src/modules/xecmd.h | 3 +- src/modules/xmas.c | 48 +- src/modules/xmas.h | 8 +- src/platform.h | 23 +- src/settings.h | 18 +- src/tests.c | 75 +- src/tests.h | 15 +- src/triggers/changefaction.c | 85 +- src/triggers/changefaction.h | 13 +- src/triggers/changerace.c | 91 +- src/triggers/changerace.h | 11 +- src/triggers/clonedied.c | 61 +- src/triggers/clonedied.h | 10 +- src/triggers/createcurse.c | 93 +- src/triggers/createcurse.h | 18 +- src/triggers/createunit.c | 109 +- src/triggers/createunit.h | 15 +- src/triggers/gate.c | 132 +- src/triggers/gate.h | 12 +- src/triggers/giveitem.c | 75 +- src/triggers/giveitem.h | 13 +- src/triggers/killunit.c | 46 +- src/triggers/killunit.h | 10 +- src/triggers/removecurse.c | 75 +- src/triggers/removecurse.h | 13 +- src/triggers/shock.c | 85 +- src/triggers/shock.h | 10 +- src/triggers/timeout.c | 51 +- src/triggers/timeout.h | 8 +- src/triggers/triggers.c | 32 +- src/triggers/triggers.h | 2 +- src/triggers/unguard.c | 57 +- src/triggers/unguard.h | 12 +- src/triggers/unitmessage.c | 56 +- src/triggers/unitmessage.h | 11 +- src/util/attrib.c | 289 +-- src/util/attrib.h | 96 +- src/util/base36.c | 98 +- src/util/base36.h | 10 +- src/util/base36_test.c | 11 +- src/util/bsdstring.c | 35 +- src/util/bsdstring.h | 8 +- src/util/console.c | 166 +- src/util/console.h | 7 +- src/util/crmessage.c | 163 +- src/util/crmessage.h | 23 +- src/util/dice.c | 59 +- src/util/encoding.h | 14 +- src/util/event.c | 307 +-- src/util/event.h | 76 +- src/util/eventbus.c | 39 +- src/util/eventbus.h | 9 +- src/util/filereader.c | 223 ++- src/util/filereader.h | 2 +- src/util/functions.c | 52 +- src/util/functions.h | 10 +- src/util/goodies.c | 100 +- src/util/goodies.h | 21 +- src/util/graph.c | 273 +-- src/util/graph.h | 26 +- src/util/language.c | 177 +- src/util/language.h | 60 +- src/util/language_struct.h | 19 +- src/util/listbox.c | 198 +- src/util/listbox.h | 18 +- src/util/lists.c | 38 +- src/util/lists.h | 10 +- src/util/log.c | 181 +- src/util/log.h | 14 +- src/util/message.c | 181 +- src/util/message.h | 72 +- src/util/nrmessage.c | 137 +- src/util/nrmessage.h | 40 +- src/util/nrmessage_struct.h | 16 +- src/util/os.c | 26 +- src/util/os.h | 2 +- src/util/parser.c | 119 +- src/util/parser.h | 15 +- src/util/quicklist.c | 180 +- src/util/quicklist.h | 28 +- src/util/quicklist_test.c | 142 +- src/util/rand.c | 32 +- src/util/resolve.c | 51 +- src/util/resolve.h | 11 +- src/util/rng.h | 4 +- src/util/sql.c | 70 +- src/util/sql.h | 6 +- src/util/storage.h | 58 +- src/util/strings.c | 46 +- src/util/strncpy.c | 14 +- src/util/translation.c | 419 ++-- src/util/translation.h | 19 +- src/util/umlaut.c | 101 +- src/util/umlaut.h | 26 +- src/util/unicode.c | 550 ++++-- src/util/unicode.h | 18 +- src/util/variant.h | 25 +- src/util/xml.c | 82 +- src/util/xml.h | 14 +- tools/atoi36.c | 22 +- tools/gethash.c | 21 +- tools/namegen.c | 271 +-- 312 files changed, 33689 insertions(+), 25960 deletions(-) diff --git a/src/attributes/aggressive.h b/src/attributes/aggressive.h index dd6060637..c653b12bd 100644 --- a/src/attributes/aggressive.h +++ b/src/attributes/aggressive.h @@ -22,12 +22,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern struct attrib_type at_aggressive; -extern struct attrib * make_aggressive(double probability); -extern void init_aggressive(void); + extern struct attrib_type at_aggressive; + extern struct attrib *make_aggressive(double probability); + extern void init_aggressive(void); #ifdef __cplusplus } #endif #endif - diff --git a/src/attributes/alliance.c b/src/attributes/alliance.c index 526ec18db..c774ef26b 100644 --- a/src/attributes/alliance.c +++ b/src/attributes/alliance.c @@ -24,11 +24,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include attrib_type at_alliance = { - "alliance", - NULL, - NULL, - NULL, - a_writeint, - a_readint, - ATF_UNIQUE + "alliance", + NULL, + NULL, + NULL, + a_writeint, + a_readint, + ATF_UNIQUE }; diff --git a/src/attributes/alliance.h b/src/attributes/alliance.h index 42336c47b..ca90da4ac 100644 --- a/src/attributes/alliance.h +++ b/src/attributes/alliance.h @@ -22,10 +22,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern struct attrib_type at_alliance; + extern struct attrib_type at_alliance; #ifdef __cplusplus } #endif #endif - diff --git a/src/attributes/attributes.c b/src/attributes/attributes.c index 8e9d4a0cd..139c63f8c 100644 --- a/src/attributes/attributes.c +++ b/src/attributes/attributes.c @@ -55,8 +55,7 @@ attrib_type at_unitdissolve = { "unitdissolve", NULL, NULL, NULL, a_writechars, a_readchars }; -void -register_attributes(void) +void register_attributes(void) { at_register(&at_object); at_register(&at_unitdissolve); diff --git a/src/attributes/attributes.h b/src/attributes/attributes.h index 594ecf3f3..284c43f88 100644 --- a/src/attributes/attributes.h +++ b/src/attributes/attributes.h @@ -22,10 +22,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern void register_attributes(void); + extern void register_attributes(void); #ifdef __cplusplus } #endif #endif - diff --git a/src/attributes/fleechance.c b/src/attributes/fleechance.c index 24062bd55..505158dab 100644 --- a/src/attributes/fleechance.c +++ b/src/attributes/fleechance.c @@ -22,24 +22,23 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include attrib_type at_fleechance = { - "fleechance", - NULL, - NULL, - NULL, - NULL, - NULL, + "fleechance", + NULL, + NULL, + NULL, + NULL, + NULL, }; -attrib * -make_fleechance(float fleechance) +attrib *make_fleechance(float fleechance) { - attrib * a = a_new(&at_fleechance); - a->data.flt = fleechance; - return a; + attrib *a = a_new(&at_fleechance); + + a->data.flt = fleechance; + return a; } -void -init_fleechance(void) +void init_fleechance(void) { - at_register(&at_fleechance); + at_register(&at_fleechance); } diff --git a/src/attributes/fleechance.h b/src/attributes/fleechance.h index 482b1ad64..98f5811ff 100644 --- a/src/attributes/fleechance.h +++ b/src/attributes/fleechance.h @@ -22,10 +22,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern struct attrib_type at_fleechance; + extern struct attrib_type at_fleechance; -extern struct attrib * make_fleechance(float fleechance); -extern void init_fleechance(void); + extern struct attrib *make_fleechance(float fleechance); + extern void init_fleechance(void); #ifdef __cplusplus } diff --git a/src/attributes/follow.c b/src/attributes/follow.c index d080a0d49..66c7c7eb2 100644 --- a/src/attributes/follow.c +++ b/src/attributes/follow.c @@ -26,10 +26,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -static int -read_follow(attrib * a, void * owner, struct storage * store) +static int read_follow(attrib * a, void *owner, struct storage *store) { - read_unit_reference(store); /* skip it */ + read_unit_reference(store); /* skip it */ return AT_READ_FAIL; } @@ -37,10 +36,10 @@ attrib_type at_follow = { "follow", NULL, NULL, NULL, NULL, read_follow }; -attrib * -make_follow(struct unit * u) +attrib *make_follow(struct unit * u) { - attrib * a = a_new(&at_follow); + attrib *a = a_new(&at_follow); + a->data.v = u; return a; } diff --git a/src/attributes/follow.h b/src/attributes/follow.h index 0328949cc..3604971c3 100644 --- a/src/attributes/follow.h +++ b/src/attributes/follow.h @@ -22,14 +22,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern struct attrib_type at_follow; + extern struct attrib_type at_follow; -struct unit; + struct unit; -extern struct attrib * make_follow(struct unit * u); + extern struct attrib *make_follow(struct unit *u); #ifdef __cplusplus } #endif #endif - diff --git a/src/attributes/giveitem.c b/src/attributes/giveitem.c index db0b136eb..b248428d5 100644 --- a/src/attributes/giveitem.c +++ b/src/attributes/giveitem.c @@ -38,98 +38,107 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include typedef struct give_data { - struct building * building; - struct item * items; + struct building *building; + struct item *items; } give_data; static void -a_writegive(const attrib * a, const void * owner, struct storage * store) +a_writegive(const attrib * a, const void *owner, struct storage *store) { - give_data * gdata = (give_data*)a->data.v; - item * itm; - write_building_reference(gdata->building, store); - for (itm=gdata->items;itm;itm=itm->next) { - store->w_tok(store, resourcename(itm->type->rtype, 0)); - store->w_int(store, itm->number); - } - store->w_tok(store, "end"); + give_data *gdata = (give_data *) a->data.v; + + item *itm; + + write_building_reference(gdata->building, store); + for (itm = gdata->items; itm; itm = itm->next) { + store->w_tok(store, resourcename(itm->type->rtype, 0)); + store->w_int(store, itm->number); + } + store->w_tok(store, "end"); } -static int -a_readgive(attrib * a, void * owner, struct storage * store) +static int a_readgive(attrib * a, void *owner, struct storage *store) { - give_data * gdata = (give_data*)a->data.v; + give_data *gdata = (give_data *) a->data.v; + variant var; + char zText[32]; var.i = store->r_id(store); - if (var.i>0) { + if (var.i > 0) { gdata->building = findbuilding(var.i); - if (gdata->building==NULL) { + if (gdata->building == NULL) { ur_add(var, &gdata->building, resolve_building); } } else { - gdata->building=NULL; + gdata->building = NULL; } for (;;) { int i; + store->r_tok_buf(store, zText, sizeof(zText)); - if (!strcmp("end", zText)) break; + if (!strcmp("end", zText)) + break; i = store->r_int(store); - if (i==0) i_add(&gdata->items, i_new(it_find(zText), i)); + if (i == 0) + i_add(&gdata->items, i_new(it_find(zText), i)); } return AT_READ_OK; } -static void -a_initgive(struct attrib * a) +static void a_initgive(struct attrib *a) { - a->data.v = calloc(sizeof(give_data), 1); + a->data.v = calloc(sizeof(give_data), 1); } -static void -a_finalizegive(struct attrib * a) +static void a_finalizegive(struct attrib *a) { - free(a->data.v); + free(a->data.v); } -static int -a_giveitem(attrib * a) +static int a_giveitem(attrib * a) { - give_data * gdata = (give_data*)a->data.v; - region * r; - unit * u; - if (gdata->building==NULL || gdata->items==NULL) return 0; - r = gdata->building->region; - u = building_owner(gdata->building); - if (u==NULL) return 1; - while (gdata->items) { - item * itm = gdata->items; - i_change(&u->items, itm->type, itm->number); - i_free(i_remove(&gdata->items, itm)); - } - return 0; + give_data *gdata = (give_data *) a->data.v; + + region *r; + + unit *u; + + if (gdata->building == NULL || gdata->items == NULL) + return 0; + r = gdata->building->region; + u = building_owner(gdata->building); + if (u == NULL) + return 1; + while (gdata->items) { + item *itm = gdata->items; + + i_change(&u->items, itm->type, itm->number); + i_free(i_remove(&gdata->items, itm)); + } + return 0; } attrib_type at_giveitem = { - "giveitem", - a_initgive, a_finalizegive, - a_giveitem, - a_writegive, a_readgive + "giveitem", + a_initgive, a_finalizegive, + a_giveitem, + a_writegive, a_readgive }; -attrib * -make_giveitem(struct building * b, struct item * ip) +attrib *make_giveitem(struct building * b, struct item * ip) { - attrib * a = a_new(&at_giveitem); - give_data * gd = (give_data*)a->data.v; - gd->building = b; - gd->items = ip; - return a; + attrib *a = a_new(&at_giveitem); + + give_data *gd = (give_data *) a->data.v; + + gd->building = b; + gd->items = ip; + return a; } -void -init_giveitem(void) +void init_giveitem(void) { - at_register(&at_giveitem); + at_register(&at_giveitem); } diff --git a/src/attributes/giveitem.h b/src/attributes/giveitem.h index e45d3df56..952ca4fb7 100644 --- a/src/attributes/giveitem.h +++ b/src/attributes/giveitem.h @@ -22,13 +22,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -struct building; -struct item; + struct building; + struct item; -extern struct attrib_type at_giveitem; + extern struct attrib_type at_giveitem; -extern struct attrib * make_giveitem(struct building * b, struct item * items); -extern void init_giveitem(void); + extern struct attrib *make_giveitem(struct building *b, struct item *items); + extern void init_giveitem(void); #ifdef __cplusplus } diff --git a/src/attributes/gm.c b/src/attributes/gm.c index bf062722a..b320ee477 100644 --- a/src/attributes/gm.c +++ b/src/attributes/gm.c @@ -27,35 +27,35 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -static void -write_gm(const attrib * a, const void * owner, struct storage * store) +static void write_gm(const attrib * a, const void *owner, struct storage *store) { - write_plane_reference((plane*)a->data.v, store); + write_plane_reference((plane *) a->data.v, store); } -static int -read_gm(attrib * a, void * owner, struct storage * store) +static int read_gm(attrib * a, void *owner, struct storage *store) { - plane * pl; + plane *pl; + int result = read_plane_reference(&pl, store); + a->data.v = pl; return result; } attrib_type at_gm = { - "gm", - NULL, - NULL, - NULL, - write_gm, - read_gm, + "gm", + NULL, + NULL, + NULL, + write_gm, + read_gm, }; -attrib * -make_gm(const struct plane * pl) +attrib *make_gm(const struct plane * pl) { - attrib * a = a_new(&at_gm); - a->data.v = (void*)pl; - return a; + attrib *a = a_new(&at_gm); + + a->data.v = (void *)pl; + return a; } diff --git a/src/attributes/gm.h b/src/attributes/gm.h index 341b4d76a..e1a17bef6 100644 --- a/src/attributes/gm.h +++ b/src/attributes/gm.h @@ -24,13 +24,12 @@ extern "C" { /* this is an attribute used by the kernel (isallied) */ -struct plane; -extern struct attrib_type at_gm; + struct plane; + extern struct attrib_type at_gm; -extern struct attrib * make_gm(const struct plane *pl); + extern struct attrib *make_gm(const struct plane *pl); #ifdef __cplusplus } #endif #endif - diff --git a/src/attributes/hate.c b/src/attributes/hate.c index 545eec8e1..e2531e921 100644 --- a/src/attributes/hate.c +++ b/src/attributes/hate.c @@ -27,44 +27,43 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -static int -verify_hate(attrib * a) +static int verify_hate(attrib * a) { - if (a->data.v==NULL) { - return 0; - } - return 1; + if (a->data.v == NULL) { + return 0; + } + return 1; } static void -write_hate(const attrib * a, const void * owner, struct storage * store) +write_hate(const attrib * a, const void *owner, struct storage *store) { - write_unit_reference((unit*)a->data.v, store); + write_unit_reference((unit *) a->data.v, store); } -static int -read_hate(attrib * a, void * owner, struct storage * store) +static int read_hate(attrib * a, void *owner, struct storage *store) { - int result = read_reference(&a->data.v, store, read_unit_reference, resolve_unit); - if (result==0 && !a->data.v) { + int result = + read_reference(&a->data.v, store, read_unit_reference, resolve_unit); + if (result == 0 && !a->data.v) { return AT_READ_FAIL; } return AT_READ_OK; } attrib_type at_hate = { - "hates", - NULL, - NULL, - verify_hate, - write_hate, - read_hate, + "hates", + NULL, + NULL, + verify_hate, + write_hate, + read_hate, }; -attrib * -make_hate(struct unit * u) +attrib *make_hate(struct unit * u) { - attrib * a = a_new(&at_hate); - a->data.v = u; - return a; + attrib *a = a_new(&at_hate); + + a->data.v = u; + return a; } diff --git a/src/attributes/hate.h b/src/attributes/hate.h index e58c6205b..14b4a5189 100644 --- a/src/attributes/hate.h +++ b/src/attributes/hate.h @@ -22,14 +22,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern struct attrib_type at_hate; + extern struct attrib_type at_hate; -struct unit; + struct unit; -extern struct attrib * make_hate(struct unit * u); + extern struct attrib *make_hate(struct unit *u); #ifdef __cplusplus } #endif #endif - diff --git a/src/attributes/iceberg.c b/src/attributes/iceberg.c index cb0efc7f3..5c51f02fb 100644 --- a/src/attributes/iceberg.c +++ b/src/attributes/iceberg.c @@ -24,19 +24,19 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include attrib_type at_iceberg = { - "iceberg_drift", - NULL, - NULL, - NULL, - a_writeint, - a_readint, - ATF_UNIQUE + "iceberg_drift", + NULL, + NULL, + NULL, + a_writeint, + a_readint, + ATF_UNIQUE }; -attrib * -make_iceberg(direction_t dir) +attrib *make_iceberg(direction_t dir) { - attrib * a = a_new(&at_iceberg); - a->data.i = (int)dir; - return a; + attrib *a = a_new(&at_iceberg); + + a->data.i = (int)dir; + return a; } diff --git a/src/attributes/iceberg.h b/src/attributes/iceberg.h index 2f99d60dd..b9c423d85 100644 --- a/src/attributes/iceberg.h +++ b/src/attributes/iceberg.h @@ -22,12 +22,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern struct attrib_type at_iceberg; + extern struct attrib_type at_iceberg; -extern struct attrib * make_iceberg(direction_t dir); + extern struct attrib *make_iceberg(direction_t dir); #ifdef __cplusplus } #endif #endif - diff --git a/src/attributes/key.c b/src/attributes/key.c index ea612b01a..5d3147a45 100644 --- a/src/attributes/key.c +++ b/src/attributes/key.c @@ -24,36 +24,37 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include attrib_type at_key = { - "key", - NULL, - NULL, - NULL, - a_writeint, - a_readint, + "key", + NULL, + NULL, + NULL, + a_writeint, + a_readint, }; -attrib * -add_key(attrib ** alist, int key) +attrib *add_key(attrib ** alist, int key) { - attrib * a = find_key(*alist, key); - if (a==NULL) a = a_add(alist, make_key(key)); - return a; + attrib *a = find_key(*alist, key); + + if (a == NULL) + a = a_add(alist, make_key(key)); + return a; } -attrib * -make_key(int key) +attrib *make_key(int key) { - attrib * a = a_new(&at_key); - a->data.i = key; - return a; + attrib *a = a_new(&at_key); + + a->data.i = key; + return a; } -attrib * -find_key(attrib * alist, int key) +attrib *find_key(attrib * alist, int key) { - attrib * a = a_find(alist, &at_key); - while (a && a->type==&at_key && a->data.i != key) { + attrib *a = a_find(alist, &at_key); + + while (a && a->type == &at_key && a->data.i != key) { a = a->next; } - return (a && a->type==&at_key)?a:NULL; + return (a && a->type == &at_key) ? a : NULL; } diff --git a/src/attributes/key.h b/src/attributes/key.h index 112bbe581..2aa9fee99 100644 --- a/src/attributes/key.h +++ b/src/attributes/key.h @@ -22,14 +22,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern struct attrib_type at_key; + extern struct attrib_type at_key; -extern struct attrib * make_key(int key); -extern struct attrib * find_key(struct attrib * alist, int key); -extern struct attrib * add_key(struct attrib ** alist, int key); + extern struct attrib *make_key(int key); + extern struct attrib *find_key(struct attrib *alist, int key); + extern struct attrib *add_key(struct attrib **alist, int key); #ifdef __cplusplus } #endif #endif - diff --git a/src/attributes/matmod.c b/src/attributes/matmod.c index 8f8f6bec8..6a520ce43 100644 --- a/src/attributes/matmod.c +++ b/src/attributes/matmod.c @@ -22,19 +22,19 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include attrib_type at_matmod = { - "matmod", - NULL, - NULL, - NULL, - NULL, - NULL, - ATF_PRESERVE + "matmod", + NULL, + NULL, + NULL, + NULL, + NULL, + ATF_PRESERVE }; -attrib * -make_matmod(mm_fun function) +attrib *make_matmod(mm_fun function) { - attrib * a = a_new(&at_matmod); - a->data.f = (void(*)(void))function; - return a; + attrib *a = a_new(&at_matmod); + + a->data.f = (void (*)(void))function; + return a; } diff --git a/src/attributes/matmod.h b/src/attributes/matmod.h index e32b6a94c..fc4570c0f 100644 --- a/src/attributes/matmod.h +++ b/src/attributes/matmod.h @@ -23,15 +23,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -struct resource_type; -struct unit; -typedef int (*mm_fun)(const struct unit * u, const struct resource_type * rtype, int value); + struct resource_type; + struct unit; + typedef int (*mm_fun) (const struct unit * u, + const struct resource_type * rtype, int value); -extern struct attrib_type at_matmod; -extern struct attrib * make_matmod(mm_fun function); + extern struct attrib_type at_matmod; + extern struct attrib *make_matmod(mm_fun function); #ifdef __cplusplus } #endif - #endif diff --git a/src/attributes/moved.c b/src/attributes/moved.c index 08c11ac1e..16d2e0de4 100644 --- a/src/attributes/moved.c +++ b/src/attributes/moved.c @@ -23,41 +23,41 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -static int -age_moved(attrib * a) +static int age_moved(attrib * a) { - --a->data.i; - return a->data.i > 0; + --a->data.i; + return a->data.i > 0; } static void -write_moved(const attrib * a, const void * owner, struct storage * store) +write_moved(const attrib * a, const void *owner, struct storage *store) { - store->w_int(store, a->data.i); + store->w_int(store, a->data.i); } -static int -read_moved(attrib * a, void * owner, struct storage * store) +static int read_moved(attrib * a, void *owner, struct storage *store) { - a->data.i = store->r_int(store); - if (a->data.i !=0 ) return AT_READ_OK; - else return AT_READ_FAIL; + a->data.i = store->r_int(store); + if (a->data.i != 0) + return AT_READ_OK; + else + return AT_READ_FAIL; } attrib_type at_moved = { - "moved", NULL, NULL, age_moved, write_moved, read_moved + "moved", NULL, NULL, age_moved, write_moved, read_moved }; -boolean -get_moved(attrib ** alist) +boolean get_moved(attrib ** alist) { - return a_find(*alist, &at_moved) ? true : false; + return a_find(*alist, &at_moved) ? true : false; } -void -set_moved(attrib ** alist) +void set_moved(attrib ** alist) { - attrib * a = a_find(*alist, &at_moved); - if (a==NULL) a = a_add(alist, a_new(&at_moved)); - a->data.i = 2; + attrib *a = a_find(*alist, &at_moved); + + if (a == NULL) + a = a_add(alist, a_new(&at_moved)); + a->data.i = 2; } diff --git a/src/attributes/moved.h b/src/attributes/moved.h index af84797ea..cce9fe941 100644 --- a/src/attributes/moved.h +++ b/src/attributes/moved.h @@ -22,16 +22,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -struct attrib; -struct attrib_type; + struct attrib; + struct attrib_type; -extern boolean get_moved(struct attrib ** alist); -extern void set_moved(struct attrib ** alist); + extern boolean get_moved(struct attrib **alist); + extern void set_moved(struct attrib **alist); -extern struct attrib_type at_moved; + extern struct attrib_type at_moved; #ifdef __cplusplus } #endif #endif - diff --git a/src/attributes/movement.c b/src/attributes/movement.c index 125fbf779..f46d839b9 100644 --- a/src/attributes/movement.c +++ b/src/attributes/movement.c @@ -24,36 +24,40 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include static void -write_movement(const attrib * a, const void * owner, struct storage * store) +write_movement(const attrib * a, const void *owner, struct storage *store) { - store->w_int(store, a->data.i); + store->w_int(store, a->data.i); } -static int -read_movement(attrib * a, void * owner, struct storage * store) +static int read_movement(attrib * a, void *owner, struct storage *store) { a->data.i = store->r_int(store); - if (a->data.i !=0 ) return AT_READ_OK; - else return AT_READ_FAIL; + if (a->data.i != 0) + return AT_READ_OK; + else + return AT_READ_FAIL; } attrib_type at_movement = { - "movement", NULL, NULL, NULL, write_movement, read_movement + "movement", NULL, NULL, NULL, write_movement, read_movement }; -boolean -get_movement(attrib * const * alist, int type) +boolean get_movement(attrib * const *alist, int type) { - const attrib * a = a_findc(*alist, &at_movement); - if (a==NULL) return false; - if (a->data.i & type) return true; - return false; + const attrib *a = a_findc(*alist, &at_movement); + + if (a == NULL) + return false; + if (a->data.i & type) + return true; + return false; } -void -set_movement(attrib ** alist, int type) +void set_movement(attrib ** alist, int type) { - attrib * a = a_find(*alist, &at_movement); - if (a==NULL) a = a_add(alist, a_new(&at_movement)); - a->data.i |= type; + attrib *a = a_find(*alist, &at_movement); + + if (a == NULL) + a = a_add(alist, a_new(&at_movement)); + a->data.i |= type; } diff --git a/src/attributes/movement.h b/src/attributes/movement.h index 53ae8f923..b976a67ec 100644 --- a/src/attributes/movement.h +++ b/src/attributes/movement.h @@ -22,10 +22,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern boolean get_movement(struct attrib * const * alist, int type); -extern void set_movement(struct attrib ** alist, int type); + extern boolean get_movement(struct attrib *const *alist, int type); + extern void set_movement(struct attrib **alist, int type); -extern struct attrib_type at_movement; + extern struct attrib_type at_movement; #ifdef __cplusplus } diff --git a/src/attributes/object.c b/src/attributes/object.c index 033fd8b32..ab8de87d5 100644 --- a/src/attributes/object.c +++ b/src/attributes/object.c @@ -40,24 +40,26 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. typedef struct object_data { object_type type; - char * name; + char *name; union { int i; - char * str; + char *str; double real; - struct unit * u; - struct region * r; - struct building * b; - struct ship * sh; - struct faction * f; + struct unit *u; + struct region *r; + struct building *b; + struct ship *sh; + struct faction *f; } data; } object_data; static void -object_write(const attrib * a, const void * owner, struct storage * store) +object_write(const attrib * a, const void *owner, struct storage *store) { - const object_data * data = (object_data *)a->data.v; + const object_data *data = (object_data *) a->data.v; + int type = (int)data->type; + store->w_tok(store, data->name); store->w_int(store, type); switch (data->type) { @@ -71,7 +73,7 @@ object_write(const attrib * a, const void * owner, struct storage * store) store->w_str(store, data->data.str); break; case TUNIT: - write_unit_reference(data->data.u, store ); + write_unit_reference(data->data.u, store); break; case TFACTION: write_faction_reference(data->data.f, store); @@ -93,14 +95,14 @@ object_write(const attrib * a, const void * owner, struct storage * store) } } -static int -object_read(attrib *a, void * owner, struct storage * store) +static int object_read(attrib * a, void *owner, struct storage *store) { - object_data * data = (object_data *)a->data.v; + object_data *data = (object_data *) a->data.v; + int result; data->name = store->r_str(store); - data->type = (object_type)store->r_int(store); + data->type = (object_type) store->r_int(store); switch (data->type) { case TINTEGER: data->data.i = store->r_int(store); @@ -112,26 +114,33 @@ object_read(attrib *a, void * owner, struct storage * store) data->data.str = store->r_str(store); break; case TBUILDING: - result = read_reference(&data->data.b, store, read_building_reference, resolve_building); - if (result==0 && !data->data.b) { + result = + read_reference(&data->data.b, store, read_building_reference, + resolve_building); + if (result == 0 && !data->data.b) { return AT_READ_FAIL; } break; case TUNIT: - result = read_reference(&data->data.u, store, read_unit_reference, resolve_unit); - if (result==0 && !data->data.u) { + result = + read_reference(&data->data.u, store, read_unit_reference, resolve_unit); + if (result == 0 && !data->data.u) { return AT_READ_FAIL; } break; case TFACTION: - result = read_reference(&data->data.f, store, read_faction_reference, resolve_faction); - if (result==0 && !data->data.f) { + result = + read_reference(&data->data.f, store, read_faction_reference, + resolve_faction); + if (result == 0 && !data->data.f) { return AT_READ_FAIL; } break; case TREGION: - result = read_reference(&data->data.r, store, read_region_reference, RESOLVE_REGION(store->version)); - if (result==0 && !data->data.r) { + result = + read_reference(&data->data.r, store, read_region_reference, + RESOLVE_REGION(store->version)); + if (result == 0 && !data->data.r) { return AT_READ_FAIL; } break; @@ -147,20 +156,21 @@ object_read(attrib *a, void * owner, struct storage * store) return AT_READ_OK; } -static void -object_init(attrib * a) +static void object_init(attrib * a) { - object_data * data; + object_data *data; + a->data.v = malloc(sizeof(object_data)); - data = (object_data *)a->data.v; + data = (object_data *) a->data.v; data->type = TNONE; } -static void -object_done(attrib * a) +static void object_done(attrib * a) { - object_data * data = (object_data *)a->data.v; - if (data->type == TSTRING) free(data->data.str); + object_data *data = (object_data *) a->data.v; + + if (data->type == TSTRING) + free(data->data.str); free(data->name); free(a->data.v); } @@ -170,34 +180,35 @@ attrib_type at_object = { object_write, object_read }; -const char * -object_name(const attrib * a) +const char *object_name(const attrib * a) { - object_data * data = (object_data *)a->data.v; + object_data *data = (object_data *) a->data.v; + return data->name; } -struct attrib * -object_create(const char * name, object_type type, variant value) +struct attrib *object_create(const char *name, object_type type, variant value) { - attrib * a = a_new(&at_object); - object_data * data = (object_data *)a->data.v; + attrib *a = a_new(&at_object); + + object_data *data = (object_data *) a->data.v; + data->name = strdup(name); object_set(a, type, value); return a; } -void -object_set(attrib * a, object_type type, variant value) +void object_set(attrib * a, object_type type, variant value) { - object_data * data = (object_data *)a->data.v; + object_data *data = (object_data *) a->data.v; - if (data->type==TSTRING) free(data->data.str); + if (data->type == TSTRING) + free(data->data.str); data->type = type; switch (type) { case TSTRING: - data->data.str = value.v?strdup(value.v):NULL; + data->data.str = value.v ? strdup(value.v) : NULL; break; case TINTEGER: data->data.i = value.i; @@ -206,19 +217,19 @@ object_set(attrib * a, object_type type, variant value) data->data.real = value.f; break; case TREGION: - data->data.r = (region*)value.v; + data->data.r = (region *) value.v; break; case TBUILDING: - data->data.b = (building*)value.v; + data->data.b = (building *) value.v; break; case TFACTION: - data->data.f = (faction*)value.v; + data->data.f = (faction *) value.v; break; case TUNIT: - data->data.u = (unit*)value.v; + data->data.u = (unit *) value.v; break; case TSHIP: - data->data.sh = (ship*)value.v; + data->data.sh = (ship *) value.v; break; case TNONE: break; @@ -228,10 +239,10 @@ object_set(attrib * a, object_type type, variant value) } } -void -object_get(const struct attrib * a, object_type * type, variant * value) +void object_get(const struct attrib *a, object_type * type, variant * value) { - object_data * data = (object_data *)a->data.v; + object_data *data = (object_data *) a->data.v; + *type = data->type; switch (data->type) { case TSTRING: diff --git a/src/attributes/object.h b/src/attributes/object.h index c0ebcab7e..44bec8b56 100644 --- a/src/attributes/object.h +++ b/src/attributes/object.h @@ -19,20 +19,21 @@ extern "C" { #endif -typedef enum { - TNONE = 0, TINTEGER = 1, TREAL = 2, TSTRING = 3, - TUNIT = 10, TFACTION = 11, TREGION = 12, TBUILDING = 13, TSHIP = 14, -} object_type; + typedef enum { + TNONE = 0, TINTEGER = 1, TREAL = 2, TSTRING = 3, + TUNIT = 10, TFACTION = 11, TREGION = 12, TBUILDING = 13, TSHIP = 14, + } object_type; -extern struct attrib_type at_object; + extern struct attrib_type at_object; -extern struct attrib * object_create(const char * name, object_type type, variant value); -extern void object_get(const struct attrib * a, object_type * type, variant * value); -extern void object_set(struct attrib * a, object_type type, variant value); -extern const char * object_name(const struct attrib * a); + extern struct attrib *object_create(const char *name, object_type type, + variant value); + extern void object_get(const struct attrib *a, object_type * type, + variant * value); + extern void object_set(struct attrib *a, object_type type, variant value); + extern const char *object_name(const struct attrib *a); #ifdef __cplusplus } #endif #endif - diff --git a/src/attributes/orcification.c b/src/attributes/orcification.c index 745d13e24..2cd820dea 100644 --- a/src/attributes/orcification.c +++ b/src/attributes/orcification.c @@ -28,13 +28,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ attrib_type at_orcification = { - "orcification", NULL, NULL, NULL, a_writeint, a_readint, ATF_UNIQUE + "orcification", NULL, NULL, NULL, a_writeint, a_readint, ATF_UNIQUE }; -attrib * -make_orcification(int orcification) +attrib *make_orcification(int orcification) { - attrib * a = a_new(&at_orcification); - a->data.i = orcification; - return a; + attrib *a = a_new(&at_orcification); + + a->data.i = orcification; + return a; } diff --git a/src/attributes/orcification.h b/src/attributes/orcification.h index 285e9414e..cbd21a8ec 100644 --- a/src/attributes/orcification.h +++ b/src/attributes/orcification.h @@ -19,9 +19,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifdef __cplusplus extern "C" { #endif -extern struct attrib_type at_orcification; + extern struct attrib_type at_orcification; -extern struct attrib * make_orcification(int orcification); + extern struct attrib *make_orcification(int orcification); #ifdef __cplusplus } diff --git a/src/attributes/otherfaction.c b/src/attributes/otherfaction.c index 14c4a3d03..697a203d2 100644 --- a/src/attributes/otherfaction.c +++ b/src/attributes/otherfaction.c @@ -31,19 +31,20 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -void -write_of(const struct attrib * a, const void * owner, struct storage * store) +void write_of(const struct attrib *a, const void *owner, struct storage *store) { - const faction * f = (faction*)a->data.v; + const faction *f = (faction *) a->data.v; + store->w_int(store, f->no); } -int -read_of(struct attrib * a, void * owner, struct storage * store) /* return 1 on success, 0 if attrib needs removal */ -{ +int read_of(struct attrib *a, void *owner, struct storage *store) +{ /* return 1 on success, 0 if attrib needs removal */ int of = store->r_int(store); + a->data.v = findfaction(of); - if (a->data.v) return AT_READ_OK; + if (a->data.v) + return AT_READ_OK; return AT_READ_FAIL; } @@ -51,28 +52,28 @@ attrib_type at_otherfaction = { "otherfaction", NULL, NULL, NULL, write_of, read_of, ATF_UNIQUE }; -struct faction * - get_otherfaction(const struct attrib * a) +struct faction *get_otherfaction(const struct attrib *a) { - return (faction*)(a->data.v); + return (faction *) (a->data.v); } -struct attrib * - make_otherfaction(struct faction * f) +struct attrib *make_otherfaction(struct faction *f) { - attrib * a = a_new(&at_otherfaction); - a->data.v = (void*)f; + attrib *a = a_new(&at_otherfaction); + + a->data.v = (void *)f; return a; } -faction * -visible_faction(const faction *f, const unit * u) +faction *visible_faction(const faction * f, const unit * u) { - if (f==NULL || !alliedunit(u, f, HELP_FSTEALTH)) { + if (f == NULL || !alliedunit(u, f, HELP_FSTEALTH)) { attrib *a = a_find(u->attribs, &at_otherfaction); + if (a) { faction *fv = get_otherfaction(a); - assert (fv != NULL); /* fv should never be NULL! */ + + assert(fv != NULL); /* fv should never be NULL! */ return fv; } } diff --git a/src/attributes/otherfaction.h b/src/attributes/otherfaction.h index 4fe99f295..4bb2608d0 100644 --- a/src/attributes/otherfaction.h +++ b/src/attributes/otherfaction.h @@ -20,14 +20,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -struct faction; -struct attrib; -extern struct attrib_type at_otherfaction; + struct faction; + struct attrib; + extern struct attrib_type at_otherfaction; -extern struct faction * get_otherfaction(const struct attrib * a); -extern struct attrib * make_otherfaction(struct faction * f); -extern struct faction * visible_faction(const struct faction *f, const struct unit * u); + extern struct faction *get_otherfaction(const struct attrib *a); + extern struct attrib *make_otherfaction(struct faction *f); + extern struct faction *visible_faction(const struct faction *f, + const struct unit *u); #ifdef __cplusplus -extern "C" { +} #endif diff --git a/src/attributes/overrideroads.c b/src/attributes/overrideroads.c index 96803a2a9..9476b609f 100644 --- a/src/attributes/overrideroads.c +++ b/src/attributes/overrideroads.c @@ -23,7 +23,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -attrib_type at_overrideroads = { +attrib_type at_overrideroads = { "roads_override", NULL, NULL, NULL, &a_writestring, &a_readstring }; - diff --git a/src/attributes/overrideroads.h b/src/attributes/overrideroads.h index a9322c598..9fcfc6610 100644 --- a/src/attributes/overrideroads.h +++ b/src/attributes/overrideroads.h @@ -22,10 +22,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern struct attrib_type at_overrideroads; + extern struct attrib_type at_overrideroads; #ifdef __cplusplus } #endif #endif - diff --git a/src/attributes/racename.c b/src/attributes/racename.c index 39ba6b4fa..7bc19f259 100644 --- a/src/attributes/racename.c +++ b/src/attributes/racename.c @@ -31,25 +31,26 @@ attrib_type at_racename = { "racename", NULL, a_finalizestring, NULL, a_writestring, a_readstring }; -const char * -get_racename(attrib * alist) +const char *get_racename(attrib * alist) { - attrib * a = a_find(alist, &at_racename); - if (a) return (const char *)a->data.v; + attrib *a = a_find(alist, &at_racename); + + if (a) + return (const char *)a->data.v; return NULL; } -void -set_racename(attrib ** palist, const char * name) +void set_racename(attrib ** palist, const char *name) { - attrib * a = a_find(*palist, &at_racename); + attrib *a = a_find(*palist, &at_racename); + if (!a && name) { a = a_add(palist, a_new(&at_racename)); a->data.v = strdup(name); } else if (a && !name) { a_remove(palist, a); } else if (a) { - if (strcmp(a->data.v, name)!=0) { + if (strcmp(a->data.v, name) != 0) { free(a->data.v); a->data.v = strdup(name); } diff --git a/src/attributes/racename.h b/src/attributes/racename.h index 04b271e35..f4327b20c 100644 --- a/src/attributes/racename.h +++ b/src/attributes/racename.h @@ -22,16 +22,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -struct attrib_type; -struct attrib; + struct attrib_type; + struct attrib; -extern void set_racename(struct attrib ** palist, const char * name); -extern const char * get_racename(struct attrib * alist); + extern void set_racename(struct attrib **palist, const char *name); + extern const char *get_racename(struct attrib *alist); -extern struct attrib_type at_racename; + extern struct attrib_type at_racename; #ifdef __cplusplus } #endif #endif - diff --git a/src/attributes/raceprefix.c b/src/attributes/raceprefix.c index 3c15a93a0..4163c8523 100644 --- a/src/attributes/raceprefix.c +++ b/src/attributes/raceprefix.c @@ -26,33 +26,35 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -attrib_type at_raceprefix = { - "raceprefix", NULL, a_finalizestring, NULL, a_writestring, a_readstring, ATF_UNIQUE +attrib_type at_raceprefix = { + "raceprefix", NULL, a_finalizestring, NULL, a_writestring, a_readstring, + ATF_UNIQUE }; -void -set_prefix(attrib ** ap, const char * str) +void set_prefix(attrib ** ap, const char *str) { - attrib * a = a_find(*ap, &at_raceprefix); - if (a==NULL) { + attrib *a = a_find(*ap, &at_raceprefix); + + if (a == NULL) { a = a_add(ap, a_new(&at_raceprefix)); } else { free(a->data.v); } - assert(a->type==&at_raceprefix); + assert(a->type == &at_raceprefix); a->data.v = strdup(str); } -const char * -get_prefix(const attrib * a) +const char *get_prefix(const attrib * a) { - char * str; + char *str; + a = a_findc(a, &at_raceprefix); - if (a==NULL) return NULL; + if (a == NULL) + return NULL; str = (char *)a->data.v; /* conversion of old prefixes */ - if (strncmp(str, "prefix_", 7)==0) { - ((attrib*)a)->data.v = strdup(str+7); + if (strncmp(str, "prefix_", 7) == 0) { + ((attrib *) a)->data.v = strdup(str + 7); free(str); str = (char *)a->data.v; } diff --git a/src/attributes/raceprefix.h b/src/attributes/raceprefix.h index f3fb85e7d..312b497a8 100644 --- a/src/attributes/raceprefix.h +++ b/src/attributes/raceprefix.h @@ -22,12 +22,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern struct attrib_type at_raceprefix; -extern void set_prefix(struct attrib ** ap, const char * str); -extern const char * get_prefix(const struct attrib * a); + extern struct attrib_type at_raceprefix; + extern void set_prefix(struct attrib **ap, const char *str); + extern const char *get_prefix(const struct attrib *a); #ifdef __cplusplus } #endif #endif - diff --git a/src/attributes/reduceproduction.c b/src/attributes/reduceproduction.c index 3f1ef5ac9..d69633b16 100644 --- a/src/attributes/reduceproduction.c +++ b/src/attributes/reduceproduction.c @@ -22,29 +22,30 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -static int -age_reduceproduction(attrib *a) +static int age_reduceproduction(attrib * a) { - int reduce = 100 - (5 * --a->data.sa[1]); - if (reduce < 10) reduce = 10; - a->data.sa[0] = (short)reduce; - return (a->data.sa[1]>0)?AT_AGE_KEEP:AT_AGE_REMOVE; + int reduce = 100 - (5 * --a->data.sa[1]); + + if (reduce < 10) + reduce = 10; + a->data.sa[0] = (short)reduce; + return (a->data.sa[1] > 0) ? AT_AGE_KEEP : AT_AGE_REMOVE; } attrib_type at_reduceproduction = { - "reduceproduction", - NULL, - NULL, - age_reduceproduction, - a_writeshorts, - a_readshorts, - ATF_UNIQUE + "reduceproduction", + NULL, + NULL, + age_reduceproduction, + a_writeshorts, + a_readshorts, + ATF_UNIQUE }; -attrib * -make_reduceproduction(int percent, int time) +attrib *make_reduceproduction(int percent, int time) { - attrib * a = a_new(&at_reduceproduction); + attrib *a = a_new(&at_reduceproduction); + a->data.sa[0] = (short)percent; a->data.sa[1] = (short)time; return a; diff --git a/src/attributes/reduceproduction.h b/src/attributes/reduceproduction.h index 4bee20399..c94f6fb01 100644 --- a/src/attributes/reduceproduction.h +++ b/src/attributes/reduceproduction.h @@ -22,11 +22,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern struct attrib * make_reduceproduction(int percent, int time); -extern struct attrib_type at_reduceproduction; + extern struct attrib *make_reduceproduction(int percent, int time); + extern struct attrib_type at_reduceproduction; #ifdef __cplusplus } #endif #endif - diff --git a/src/attributes/targetregion.c b/src/attributes/targetregion.c index d182e7fff..275705d01 100644 --- a/src/attributes/targetregion.c +++ b/src/attributes/targetregion.c @@ -29,33 +29,35 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include static void -write_targetregion(const attrib * a, const void * owner, struct storage * store) +write_targetregion(const attrib * a, const void *owner, struct storage *store) { - write_region_reference((region*)a->data.v, store); + write_region_reference((region *) a->data.v, store); } -static int -read_targetregion(attrib * a, void * owner, struct storage * store) +static int read_targetregion(attrib * a, void *owner, struct storage *store) { - int result = read_reference(&a->data.v, store, read_region_reference, RESOLVE_REGION(store->version)); - if (result==0 && !a->data.v) return AT_READ_FAIL; + int result = + read_reference(&a->data.v, store, read_region_reference, + RESOLVE_REGION(store->version)); + if (result == 0 && !a->data.v) + return AT_READ_FAIL; return AT_READ_OK; } attrib_type at_targetregion = { - "targetregion", - NULL, - NULL, - NULL, - write_targetregion, - read_targetregion, - ATF_UNIQUE + "targetregion", + NULL, + NULL, + NULL, + write_targetregion, + read_targetregion, + ATF_UNIQUE }; -attrib * -make_targetregion(struct region * r) +attrib *make_targetregion(struct region * r) { - attrib * a = a_new(&at_targetregion); - a->data.v = r; - return a; + attrib *a = a_new(&at_targetregion); + + a->data.v = r; + return a; } diff --git a/src/attributes/targetregion.h b/src/attributes/targetregion.h index d35aeba06..950e1634a 100644 --- a/src/attributes/targetregion.h +++ b/src/attributes/targetregion.h @@ -22,13 +22,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern struct attrib_type at_targetregion; + extern struct attrib_type at_targetregion; -struct region; -extern struct attrib * make_targetregion(struct region *); + struct region; + extern struct attrib *make_targetregion(struct region *); #ifdef __cplusplus } #endif #endif - diff --git a/src/attributes/viewrange.c b/src/attributes/viewrange.c index e44f2ca00..c2f31d047 100644 --- a/src/attributes/viewrange.c +++ b/src/attributes/viewrange.c @@ -27,51 +27,53 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* libc includes */ #include -static void -a_writefunction(const struct attrib * a, const void * owner, struct storage * store) +static void +a_writefunction(const struct attrib *a, const void *owner, + struct storage *store) { - const char * str = get_functionname((pf_generic)a->data.f); + const char *str = get_functionname((pf_generic) a->data.f); + store->w_tok(store, str); } -static int -a_readfunction(struct attrib *a, void * owner, struct storage * store) +static int a_readfunction(struct attrib *a, void *owner, struct storage *store) /* return 1 on success, 0 if attrib needs removal */ { - char buf[64]; - store->r_tok_buf(store, buf, sizeof(buf)); - a->data.f = get_function(buf); - return AT_READ_OK; + char buf[64]; + + store->r_tok_buf(store, buf, sizeof(buf)); + a->data.f = get_function(buf); + return AT_READ_OK; } attrib_type at_viewrange = { - "viewrange", - NULL, - NULL, - NULL, - a_writefunction, - a_readfunction, + "viewrange", + NULL, + NULL, + NULL, + a_writefunction, + a_readfunction, }; -attrib * -add_viewrange(attrib ** alist, const char *function) +attrib *add_viewrange(attrib ** alist, const char *function) { - attrib * a = a_find(*alist, &at_viewrange); - if (a==NULL) a = a_add(alist, make_viewrange(function)); - return a; + attrib *a = a_find(*alist, &at_viewrange); + + if (a == NULL) + a = a_add(alist, make_viewrange(function)); + return a; } -attrib * -make_viewrange(const char *function) +attrib *make_viewrange(const char *function) { - attrib * a = a_new(&at_viewrange); - a->data.f = get_function(function); - assert(a->data.f); - return a; + attrib *a = a_new(&at_viewrange); + + a->data.f = get_function(function); + assert(a->data.f); + return a; } -void -init_viewrange(void) +void init_viewrange(void) { - at_register(&at_viewrange); + at_register(&at_viewrange); } diff --git a/src/attributes/viewrange.h b/src/attributes/viewrange.h index 8f8ec1c55..d5e8d57d4 100644 --- a/src/attributes/viewrange.h +++ b/src/attributes/viewrange.h @@ -22,14 +22,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern struct attrib_type at_viewrange; + extern struct attrib_type at_viewrange; -extern struct attrib * make_viewrange(const char *function); -extern struct attrib * add_viewrange(struct attrib ** alist, const char *function); -extern void init_viewrange(void); + extern struct attrib *make_viewrange(const char *function); + extern struct attrib *add_viewrange(struct attrib **alist, + const char *function); + extern void init_viewrange(void); #ifdef __cplusplus } #endif #endif - diff --git a/src/bindings/bind_attrib.c b/src/bindings/bind_attrib.c index 04c02f305..65295af79 100644 --- a/src/bindings/bind_attrib.c +++ b/src/bindings/bind_attrib.c @@ -31,9 +31,9 @@ without prior permission by the authors of Eressea. #include #include -static void -init_ext(attrib * a) { - lua_State * L = (lua_State *)global.vm_state; +static void init_ext(attrib * a) +{ + lua_State *L = (lua_State *) global.vm_state; lua_pushstring(L, "callbacks"); lua_rawget(L, LUA_GLOBALSINDEX); @@ -42,109 +42,128 @@ init_ext(attrib * a) { lua_rawget(L, LUA_GLOBALSINDEX); if (lua_isfunction(L, -1)) { lua_rawgeti(L, LUA_REGISTRYINDEX, a->data.i); - if (lua_pcall(L, 1, 0, 0)!=0) { - const char* error = lua_tostring(L, -1); + if (lua_pcall(L, 1, 0, 0) != 0) { + const char *error = lua_tostring(L, -1); + log_error(("attrib_init '%d': %s.\n", a->data.i, error)); } } } } -static void -free_ext(attrib * a) { - lua_State * L = (lua_State *)global.vm_state; - if (a->data.i>0) { +static void free_ext(attrib * a) +{ + lua_State *L = (lua_State *) global.vm_state; + + if (a->data.i > 0) { luaL_unref(L, LUA_REGISTRYINDEX, a->data.i); } } -static int -age_ext(attrib * a) { +static int age_ext(attrib * a) +{ return AT_AGE_KEEP; } -static void -write_ext_i(lua_State * L, const char * name, bson_buffer * bb) +static void write_ext_i(lua_State * L, const char *name, bson_buffer * bb) { int type = lua_type(L, -1); + switch (type) { case LUA_TNUMBER: - { - double value = tolua_tonumber(L, -1, 0); - bson_append_double(bb, name, value); - } + { + double value = tolua_tonumber(L, -1, 0); + + bson_append_double(bb, name, value); + } break; case LUA_TSTRING: - { - const char * value = tolua_tostring(L, -1, 0); - bson_append_string(bb, name, value); - } + { + const char *value = tolua_tostring(L, -1, 0); + + bson_append_string(bb, name, value); + } break; case LUA_TTABLE: - { - int n = luaL_getn(L, -1); - if (n) { - bson_buffer * arr = bson_append_start_array(bb, name); - int i; - for (i=0;i!=n;++i) { - char num[12]; - bson_numstr(num, i); - lua_rawgeti(L, -1, i+1); - write_ext_i(L, num, arr); - lua_pop(L, 1); - } - bson_append_finish_object(arr); - } else { - bson_buffer * sub = bson_append_start_object(bb, name); - lua_pushnil(L); /* first key */ - while (lua_next(L, -2) != 0) { - const char * key; - /* uses 'key' (at index -2) and 'value' (at index -1) */ - lua_pushvalue(L, -2); - key = lua_tolstring(L, -1, 0); - lua_pushvalue(L, -2); - if (key) { - write_ext_i(L, key, sub); - } - /* removes 'value'; keeps 'key' for next iteration */ - lua_pop(L, 3); - } - bson_append_finish_object(sub); + { + int n = luaL_getn(L, -1); + + if (n) { + bson_buffer *arr = bson_append_start_array(bb, name); + + int i; + + for (i = 0; i != n; ++i) { + char num[12]; + + bson_numstr(num, i); + lua_rawgeti(L, -1, i + 1); + write_ext_i(L, num, arr); + lua_pop(L, 1); } + bson_append_finish_object(arr); + } else { + bson_buffer *sub = bson_append_start_object(bb, name); + + lua_pushnil(L); /* first key */ + while (lua_next(L, -2) != 0) { + const char *key; + + /* uses 'key' (at index -2) and 'value' (at index -1) */ + lua_pushvalue(L, -2); + key = lua_tolstring(L, -1, 0); + lua_pushvalue(L, -2); + if (key) { + write_ext_i(L, key, sub); + } + /* removes 'value'; keeps 'key' for next iteration */ + lua_pop(L, 3); + } + bson_append_finish_object(sub); } + } break; case LUA_TUSERDATA: - { - tolua_Error tolua_err; - if (tolua_isusertype(L, -1, "unit", 0, &tolua_err)) { - unit * u = (unit *)tolua_tousertype(L, -1, 0); - bson_oid_t oid; - oid.ints[0] = TYP_UNIT; - oid.ints[1] = u->no; - bson_append_oid(bb, name, &oid); - } else if (tolua_isusertype(L, -1, "region", 0, &tolua_err)) { - region * r = (region *)tolua_tousertype(L, -1, 0); - bson_oid_t oid; - oid.ints[0] = TYP_REGION; - oid.ints[1] = r->uid; - bson_append_oid(bb, name, &oid); - } else if (tolua_isusertype(L, -1, "ship", 0, &tolua_err)) { - ship * sh = (ship *)tolua_tousertype(L, -1, 0); - bson_oid_t oid; - oid.ints[0] = TYP_SHIP; - oid.ints[1] = sh->no; - bson_append_oid(bb, name, &oid); - } else if (tolua_isusertype(L, -1, "building", 0, &tolua_err)) { - building * b = (building *)tolua_tousertype(L, -1, 0); - bson_oid_t oid; - oid.ints[0] = TYP_BUILDING; - oid.ints[1] = b->no; - bson_append_oid(bb, name, &oid); - } else { - log_error(("unsuported type.\n")); - bson_append_null(bb, name); - } + { + tolua_Error tolua_err; + + if (tolua_isusertype(L, -1, "unit", 0, &tolua_err)) { + unit *u = (unit *) tolua_tousertype(L, -1, 0); + + bson_oid_t oid; + + oid.ints[0] = TYP_UNIT; + oid.ints[1] = u->no; + bson_append_oid(bb, name, &oid); + } else if (tolua_isusertype(L, -1, "region", 0, &tolua_err)) { + region *r = (region *) tolua_tousertype(L, -1, 0); + + bson_oid_t oid; + + oid.ints[0] = TYP_REGION; + oid.ints[1] = r->uid; + bson_append_oid(bb, name, &oid); + } else if (tolua_isusertype(L, -1, "ship", 0, &tolua_err)) { + ship *sh = (ship *) tolua_tousertype(L, -1, 0); + + bson_oid_t oid; + + oid.ints[0] = TYP_SHIP; + oid.ints[1] = sh->no; + bson_append_oid(bb, name, &oid); + } else if (tolua_isusertype(L, -1, "building", 0, &tolua_err)) { + building *b = (building *) tolua_tousertype(L, -1, 0); + + bson_oid_t oid; + + oid.ints[0] = TYP_BUILDING; + oid.ints[1] = b->no; + bson_append_oid(bb, name, &oid); + } else { + log_error(("unsuported type.\n")); + bson_append_null(bb, name); } + } break; default: bson_append_null(bb, name); @@ -153,14 +172,18 @@ write_ext_i(lua_State * L, const char * name, bson_buffer * bb) } static void -write_ext(const attrib * a, const void * owner, struct storage * store) { - lua_State * L = (lua_State *)global.vm_state; - if (a->data.i>0) { +write_ext(const attrib * a, const void *owner, struct storage *store) +{ + lua_State *L = (lua_State *) global.vm_state; + + if (a->data.i > 0) { int handle = a->data.i; + bson_buffer bb; + bson b; - - bson_buffer_init( & bb ); + + bson_buffer_init(&bb); lua_rawgeti(L, LUA_REGISTRYINDEX, handle); write_ext_i(L, "_data", &bb); bson_from_buffer(&b, &bb); @@ -170,85 +193,106 @@ write_ext(const attrib * a, const void * owner, struct storage * store) { } } -static int -read_ext_i(lua_State * L, bson_iterator * it, bson_type type) +static int read_ext_i(lua_State * L, bson_iterator * it, bson_type type) { switch (type) { case bson_double: - { - lua_pushnumber(L, bson_iterator_double(it)); - } + { + lua_pushnumber(L, bson_iterator_double(it)); + } break; case bson_string: - { - lua_pushstring(L, bson_iterator_string(it)); - } + { + lua_pushstring(L, bson_iterator_string(it)); + } break; case bson_array: - { - bson_iterator sub; - int err; - bson_iterator_subiterator(it, &sub); - lua_newtable(L); - if (bson_iterator_more(&sub)) { - bson_type ctype; - for (ctype = bson_iterator_next(&sub); bson_iterator_more(&sub); ctype = bson_iterator_next(&sub)) { - int i = atoi(bson_iterator_key(&sub)); - err = read_ext_i(L, &sub, ctype); - if (err) { - lua_pop(L, 1); - return err; - } - lua_rawseti(L, -2, i+1); + { + bson_iterator sub; + + int err; + + bson_iterator_subiterator(it, &sub); + lua_newtable(L); + if (bson_iterator_more(&sub)) { + bson_type ctype; + + for (ctype = bson_iterator_next(&sub); bson_iterator_more(&sub); + ctype = bson_iterator_next(&sub)) { + int i = atoi(bson_iterator_key(&sub)); + + err = read_ext_i(L, &sub, ctype); + if (err) { + lua_pop(L, 1); + return err; } + lua_rawseti(L, -2, i + 1); } } + } break; case bson_object: - { - bson_iterator sub; - int err; - bson_iterator_subiterator(it, &sub); - lua_newtable(L); - if (bson_iterator_more(&sub)) { - bson_type ctype; - for (ctype = bson_iterator_next(&sub); bson_iterator_more(&sub); ctype = bson_iterator_next(&sub)) { - lua_pushstring(L, bson_iterator_key(&sub)); - err = read_ext_i(L, &sub, ctype); - if (err) { - lua_pop(L, 1); - return err; - } - lua_rawset(L, -3); + { + bson_iterator sub; + + int err; + + bson_iterator_subiterator(it, &sub); + lua_newtable(L); + if (bson_iterator_more(&sub)) { + bson_type ctype; + + for (ctype = bson_iterator_next(&sub); bson_iterator_more(&sub); + ctype = bson_iterator_next(&sub)) { + lua_pushstring(L, bson_iterator_key(&sub)); + err = read_ext_i(L, &sub, ctype); + if (err) { + lua_pop(L, 1); + return err; } + lua_rawset(L, -3); } } + } break; case bson_oid: - { - bson_oid_t * oid = bson_iterator_oid(it); - if (oid->ints[0]==TYP_UNIT) { - unit * u = findunit(oid->ints[1]); - if (u) tolua_pushusertype(L, u, "unit"); - else lua_pushnil(L); - } else if (oid->ints[0]==TYP_REGION) { - region * r = findregionbyid(oid->ints[1]); - if (r) tolua_pushusertype(L, r, "region"); - else lua_pushnil(L); - } else if (oid->ints[0]==TYP_SHIP) { - ship * sh = findship(oid->ints[1]); - if (sh) tolua_pushusertype(L, sh, "ship"); - else lua_pushnil(L); - } else if (oid->ints[0]==TYP_BUILDING) { - building * b = findbuilding(oid->ints[1]); - if (b) tolua_pushusertype(L, b, "building"); - else lua_pushnil(L); - } - else { - log_error(("unknown oid %d %d %d\n", oid->ints[0], oid->ints[1], oid->ints[2])); + { + bson_oid_t *oid = bson_iterator_oid(it); + + if (oid->ints[0] == TYP_UNIT) { + unit *u = findunit(oid->ints[1]); + + if (u) + tolua_pushusertype(L, u, "unit"); + else lua_pushnil(L); - } + } else if (oid->ints[0] == TYP_REGION) { + region *r = findregionbyid(oid->ints[1]); + + if (r) + tolua_pushusertype(L, r, "region"); + else + lua_pushnil(L); + } else if (oid->ints[0] == TYP_SHIP) { + ship *sh = findship(oid->ints[1]); + + if (sh) + tolua_pushusertype(L, sh, "ship"); + else + lua_pushnil(L); + } else if (oid->ints[0] == TYP_BUILDING) { + building *b = findbuilding(oid->ints[1]); + + if (b) + tolua_pushusertype(L, b, "building"); + else + lua_pushnil(L); + } else { + log_error(("unknown oid %d %d %d\n", oid->ints[0], oid->ints[1], + oid->ints[2])); + lua_pushnil(L); } + } break; case bson_null: lua_pushnil(L); @@ -261,30 +305,36 @@ read_ext_i(lua_State * L, bson_iterator * it, bson_type type) return 0; } -static int -resolve_bson(variant data, void * address) +static int resolve_bson(variant data, void *address) { - lua_State * L = (lua_State *)global.vm_state; + lua_State *L = (lua_State *) global.vm_state; + bson b; + int err; + bson_iterator it; - attrib * a = (attrib*)address; - char * buffer = data.v; + + attrib *a = (attrib *) address; + + char *buffer = data.v; bson_init(&b, buffer, 1); bson_iterator_init(&it, b.data); err = read_ext_i(L, &it, bson_iterator_next(&it)); a->data.i = luaL_ref(L, LUA_REGISTRYINDEX); bson_destroy(&b); - return err?AT_READ_FAIL:AT_READ_OK; + return err ? AT_READ_FAIL : AT_READ_OK; } -static int -read_ext(attrib * a, void * owner, struct storage * store) { +static int read_ext(attrib * a, void *owner, struct storage *store) +{ variant data; + int len = store->r_int(store); + data.v = bson_malloc(len); - store->r_bin(store, data.v, (size_t)len); + store->r_bin(store, data.v, (size_t) len); a->data.v = 0; ur_add(data, a, resolve_bson); return AT_READ_OK; @@ -294,35 +344,44 @@ attrib_type at_lua_ext = { "lua", init_ext, free_ext, age_ext, write_ext, read_ext }; -static attrib ** -get_attribs(lua_State * L, int idx) { - attrib ** ap = NULL; +static attrib **get_attribs(lua_State * L, int idx) +{ + attrib **ap = NULL; + tolua_Error tolua_err; if (tolua_isusertype(L, idx, TOLUA_CAST "unit", 0, &tolua_err)) { - unit * u = (unit *)tolua_tousertype(L, idx, 0); - if (u) ap = &u->attribs; + unit *u = (unit *) tolua_tousertype(L, idx, 0); + + if (u) + ap = &u->attribs; } else if (tolua_isusertype(L, idx, TOLUA_CAST "region", 0, &tolua_err)) { - region * r = (region *)tolua_tousertype(L, idx, 0); - if (r) ap = &r->attribs; + region *r = (region *) tolua_tousertype(L, idx, 0); + + if (r) + ap = &r->attribs; } else if (tolua_isusertype(L, idx, TOLUA_CAST "faction", 0, &tolua_err)) { - faction * f = (faction *)tolua_tousertype(L, idx, 0); - if (f) ap = &f->attribs; + faction *f = (faction *) tolua_tousertype(L, idx, 0); + + if (f) + ap = &f->attribs; } else if (lua_isstring(L, idx)) { - const char * str = tolua_tostring(L, idx, NULL); - if (str && strcmp(str, "global")==0) { + const char *str = tolua_tostring(L, idx, NULL); + + if (str && strcmp(str, "global") == 0) { ap = &global.attribs; } } return ap; } -static int -tolua_attrib_create(lua_State* L) +static int tolua_attrib_create(lua_State * L) { - attrib ** ap = get_attribs(L, 1); + attrib **ap = get_attribs(L, 1); + if (ap) { - attrib * a = a_new(&at_lua_ext); + attrib *a = a_new(&at_lua_ext); + int handle; lua_pushvalue(L, 2); @@ -330,16 +389,16 @@ tolua_attrib_create(lua_State* L) a->data.i = handle; a_add(ap, a); - tolua_pushusertype(L, (void*)a, TOLUA_CAST "attrib"); + tolua_pushusertype(L, (void *)a, TOLUA_CAST "attrib"); return 1; } return 0; } -int -tolua_attrib_data(lua_State * L) +int tolua_attrib_data(lua_State * L) { - attrib * a = (attrib *)tolua_tousertype(L, 1, 0); + attrib *a = (attrib *) tolua_tousertype(L, 1, 0); + if (a && a->data.i) { lua_rawgeti(L, LUA_REGISTRYINDEX, a->data.i); return 1; @@ -347,43 +406,46 @@ tolua_attrib_data(lua_State * L) return 0; } -attrib * -tolua_get_lua_ext(struct attrib * alist) +attrib *tolua_get_lua_ext(struct attrib * alist) { - while (alist && alist->type!=&at_lua_ext) alist = alist->next; + while (alist && alist->type != &at_lua_ext) + alist = alist->next; return alist; } -int -tolua_attriblist_next(lua_State *L) +int tolua_attriblist_next(lua_State * L) { - attrib** attrib_ptr = (attrib **)lua_touserdata(L, lua_upvalueindex(1)); - attrib * a = *attrib_ptr; + attrib **attrib_ptr = (attrib **) lua_touserdata(L, lua_upvalueindex(1)); + + attrib *a = *attrib_ptr; + if (a != NULL) { - tolua_pushusertype(L, (void*)a, TOLUA_CAST "attrib"); + tolua_pushusertype(L, (void *)a, TOLUA_CAST "attrib"); *attrib_ptr = tolua_get_lua_ext(a->next); return 1; - } - else return 0; /* no more values to return */ + } else + return 0; /* no more values to return */ } -int -tolua_attrib_get(lua_State * L) { - attrib ** ap = get_attribs(L, 1); +int tolua_attrib_get(lua_State * L) +{ + attrib **ap = get_attribs(L, 1); + if (ap) { - attrib * a = tolua_get_lua_ext(*ap); - attrib ** attrib_ptr = (attrib**)lua_newuserdata(L, sizeof(attrib *)); + attrib *a = tolua_get_lua_ext(*ap); + + attrib **attrib_ptr = (attrib **) lua_newuserdata(L, sizeof(attrib *)); + luaL_getmetatable(L, "attrib"); lua_setmetatable(L, -2); *attrib_ptr = a; lua_pushcclosure(L, tolua_attriblist_next, 1); return 1; - } - else return 0; + } else + return 0; } -void -tolua_attrib_open(lua_State* L) +void tolua_attrib_open(lua_State * L) { at_register(&at_lua_ext); @@ -392,7 +454,8 @@ tolua_attrib_open(lua_State* L) tolua_module(L, NULL, 0); tolua_beginmodule(L, NULL); { - tolua_cclass(L, TOLUA_CAST "attrib", TOLUA_CAST "attrib", TOLUA_CAST "", NULL); + tolua_cclass(L, TOLUA_CAST "attrib", TOLUA_CAST "attrib", TOLUA_CAST "", + NULL); tolua_beginmodule(L, TOLUA_CAST "attrib"); { tolua_function(L, TOLUA_CAST "create", &tolua_attrib_create); diff --git a/src/bindings/bind_attrib.h b/src/bindings/bind_attrib.h index d4ce7bf95..5ab8daad5 100644 --- a/src/bindings/bind_attrib.h +++ b/src/bindings/bind_attrib.h @@ -16,7 +16,7 @@ extern "C" { struct attrib; void tolua_attrib_open(struct lua_State *L); - struct attrib * tolua_get_lua_ext(struct attrib * alist); + struct attrib *tolua_get_lua_ext(struct attrib *alist); int tolua_attriblist_next(struct lua_State *L); #ifdef __cplusplus diff --git a/src/bindings/bind_building.c b/src/bindings/bind_building.c index eecde8fbb..3f5f53bd0 100644 --- a/src/bindings/bind_building.c +++ b/src/bindings/bind_building.c @@ -24,107 +24,123 @@ without prior permission by the authors of Eressea. #include #include -int tolua_buildinglist_next(lua_State *L) +int tolua_buildinglist_next(lua_State * L) { - building** building_ptr = (building **)lua_touserdata(L, lua_upvalueindex(1)); - building * u = *building_ptr; + building **building_ptr = + (building **) lua_touserdata(L, lua_upvalueindex(1)); + building *u = *building_ptr; + if (u != NULL) { - tolua_pushusertype(L, (void*)u, TOLUA_CAST "building"); + tolua_pushusertype(L, (void *)u, TOLUA_CAST "building"); *building_ptr = u->next; return 1; - } - else return 0; /* no more values to return */ + } else + return 0; /* no more values to return */ } -static int -tolua_building_addaction(lua_State* L) +static int tolua_building_addaction(lua_State * L) { - building* self = (building*)tolua_tousertype(L, 1, 0); - const char * fname = tolua_tostring(L, 2, 0); - const char * param = tolua_tostring(L, 3, 0); + building *self = (building *) tolua_tousertype(L, 1, 0); + + const char *fname = tolua_tostring(L, 2, 0); + + const char *param = tolua_tostring(L, 3, 0); building_addaction(self, fname, param); return 0; } -static int -tolua_building_get_objects(lua_State* L) +static int tolua_building_get_objects(lua_State * L) { - building * self = (building *)tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); + building *self = (building *) tolua_tousertype(L, 1, 0); + + tolua_pushusertype(L, (void *)&self->attribs, TOLUA_CAST "hashtable"); return 1; } -static int tolua_building_get_region(lua_State* L) +static int tolua_building_get_region(lua_State * L) { - building* self = (building*) tolua_tousertype(L, 1, 0); + building *self = (building *) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, building_getregion(self), TOLUA_CAST "region"); return 1; } -static int tolua_building_set_region(lua_State* L) +static int tolua_building_set_region(lua_State * L) { - building* self = (building*)tolua_tousertype(L, 1, 0); - building_setregion(self, (region*)tolua_tousertype(L, 2, 0)); + building *self = (building *) tolua_tousertype(L, 1, 0); + + building_setregion(self, (region *) tolua_tousertype(L, 2, 0)); return 0; } -static int tolua_building_get_info(lua_State* L) +static int tolua_building_get_info(lua_State * L) { - building* self = (building*) tolua_tousertype(L, 1, 0); + building *self = (building *) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->display); return 1; } -static int tolua_building_set_info(lua_State* L) +static int tolua_building_set_info(lua_State * L) { - building* self = (building*)tolua_tousertype(L, 1, 0); - const char * info = tolua_tostring(L, 2, 0); + building *self = (building *) tolua_tousertype(L, 1, 0); + + const char *info = tolua_tostring(L, 2, 0); + free(self->display); - if (info) self->display = strdup(info); - else self->display = NULL; + if (info) + self->display = strdup(info); + else + self->display = NULL; return 0; } -static int tolua_building_get_name(lua_State* L) +static int tolua_building_get_name(lua_State * L) { - building* self = (building*) tolua_tousertype(L, 1, 0); + building *self = (building *) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, building_getname(self)); return 1; } -static int tolua_building_set_name(lua_State* L) +static int tolua_building_set_name(lua_State * L) { - building* self = (building*)tolua_tousertype(L, 1, 0); + building *self = (building *) tolua_tousertype(L, 1, 0); + building_setname(self, tolua_tostring(L, 2, 0)); return 0; } -static int tolua_building_get_size(lua_State* L) +static int tolua_building_get_size(lua_State * L) { - building* self = (building*) tolua_tousertype(L, 1, 0); + building *self = (building *) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, self->size); return 1; } -static int tolua_building_set_size(lua_State* L) +static int tolua_building_set_size(lua_State * L) { - building* self = (building*)tolua_tousertype(L, 1, 0); + building *self = (building *) tolua_tousertype(L, 1, 0); + self->size = (int)tolua_tonumber(L, 2, 0); return 0; } -static int -tolua_building_get_units(lua_State* L) +static int tolua_building_get_units(lua_State * L) { - building * self = (building *)tolua_tousertype(L, 1, 0); - unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); - unit * u = self->region->units; + building *self = (building *) tolua_tousertype(L, 1, 0); - while (u && u->building!=self) u = u->next; + unit **unit_ptr = (unit **) lua_newuserdata(L, sizeof(unit *)); + + unit *u = self->region->units; + + while (u && u->building != self) + u = u->next; luaL_getmetatable(L, "unit"); lua_setmetatable(L, -2); @@ -134,50 +150,54 @@ tolua_building_get_units(lua_State* L) return 1; } -static int -tolua_building_get_id(lua_State* L) +static int tolua_building_get_id(lua_State * L) { - building * self = (building *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->no); + building *self = (building *) tolua_tousertype(L, 1, 0); + + tolua_pushnumber(L, (lua_Number) self->no); return 1; } -static int -tolua_building_get_type(lua_State* L) +static int tolua_building_get_type(lua_State * L) { - building * self = (building *)tolua_tousertype(L, 1, 0); + building *self = (building *) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->type->_name); return 1; } -static int -tolua_building_get_typename(lua_State* L) +static int tolua_building_get_typename(lua_State * L) { - building * b = (building *)tolua_tousertype(L, 1, 0); + building *b = (building *) tolua_tousertype(L, 1, 0); + if (b) { int size = (int)tolua_tonumber(L, 2, b->size); + tolua_pushstring(L, buildingtype(b->type, b, size)); return 1; } return 0; } -static int -tolua_building_get_owner(lua_State* L) +static int tolua_building_get_owner(lua_State * L) { - building* b = (building*) tolua_tousertype(L, 1, 0); - unit * u = b?building_owner(b):NULL; + building *b = (building *) tolua_tousertype(L, 1, 0); + + unit *u = b ? building_owner(b) : NULL; + tolua_pushusertype(L, u, TOLUA_CAST "unit"); return 1; } -static int -tolua_building_set_owner(lua_State* L) +static int tolua_building_set_owner(lua_State * L) { - building* b = (building*) tolua_tousertype(L, 1, 0); - unit * u = (unit *)tolua_tousertype(L, 2, 0); - unit * o = b?building_owner(b):NULL; - if (o && o!=u) { + building *b = (building *) tolua_tousertype(L, 1, 0); + + unit *u = (unit *) tolua_tousertype(L, 2, 0); + + unit *o = b ? building_owner(b) : NULL; + + if (o && o != u) { freset(o, UFL_OWNER); } if (u) { @@ -186,40 +206,42 @@ tolua_building_set_owner(lua_State* L) return 0; } -static int -tolua_building_create(lua_State* L) +static int tolua_building_create(lua_State * L) { - region * r = (region *)tolua_tousertype(L, 1, 0); - const char * bname = tolua_tostring(L, 2, 0); + region *r = (region *) tolua_tousertype(L, 1, 0); + + const char *bname = tolua_tostring(L, 2, 0); + if (bname) { - const building_type * btype = bt_find(bname); + const building_type *btype = bt_find(bname); + if (btype) { - building * b = new_building(btype, r, default_locale); - tolua_pushusertype(L, (void*)b, TOLUA_CAST "building"); + building *b = new_building(btype, r, default_locale); + + tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); return 1; } } return 0; } -static int -tolua_building_tostring(lua_State *L) +static int tolua_building_tostring(lua_State * L) { - building * self = (building *)tolua_tousertype(L, 1, 0); + building *self = (building *) tolua_tousertype(L, 1, 0); + lua_pushstring(L, buildingname(self)); return 1; } -static int -tolua_building_destroy(lua_State *L) +static int tolua_building_destroy(lua_State * L) { - building * self = (building *)tolua_tousertype(L, 1, 0); + building *self = (building *) tolua_tousertype(L, 1, 0); + remove_building(&self->region->buildings, self); return 0; } -void -tolua_building_open(lua_State* L) +void tolua_building_open(lua_State * L) { /* register user types */ tolua_usertype(L, TOLUA_CAST "building"); @@ -227,7 +249,8 @@ tolua_building_open(lua_State* L) tolua_module(L, NULL, 0); tolua_beginmodule(L, NULL); { - tolua_cclass(L, TOLUA_CAST "building", TOLUA_CAST "building", TOLUA_CAST "", NULL); + tolua_cclass(L, TOLUA_CAST "building", TOLUA_CAST "building", TOLUA_CAST "", + NULL); tolua_beginmodule(L, TOLUA_CAST "building"); { tolua_function(L, TOLUA_CAST "create", tolua_building_create); @@ -235,20 +258,25 @@ tolua_building_open(lua_State* L) tolua_function(L, TOLUA_CAST "__tostring", tolua_building_tostring); tolua_variable(L, TOLUA_CAST "id", tolua_building_get_id, NULL); - tolua_variable(L, TOLUA_CAST "owner", tolua_building_get_owner, tolua_building_set_owner); + tolua_variable(L, TOLUA_CAST "owner", tolua_building_get_owner, + tolua_building_set_owner); tolua_variable(L, TOLUA_CAST "type", tolua_building_get_type, NULL); - tolua_variable(L, TOLUA_CAST "name", tolua_building_get_name, tolua_building_set_name); - tolua_variable(L, TOLUA_CAST "info", tolua_building_get_info, tolua_building_set_info); + tolua_variable(L, TOLUA_CAST "name", tolua_building_get_name, + tolua_building_set_name); + tolua_variable(L, TOLUA_CAST "info", tolua_building_get_info, + tolua_building_set_info); tolua_variable(L, TOLUA_CAST "units", tolua_building_get_units, NULL); - tolua_variable(L, TOLUA_CAST "region", tolua_building_get_region, tolua_building_set_region); - tolua_variable(L, TOLUA_CAST "size", tolua_building_get_size, tolua_building_set_size); + tolua_variable(L, TOLUA_CAST "region", tolua_building_get_region, + tolua_building_set_region); + tolua_variable(L, TOLUA_CAST "size", tolua_building_get_size, + tolua_building_set_size); tolua_function(L, TOLUA_CAST "add_action", tolua_building_addaction); tolua_function(L, TOLUA_CAST "get_typename", tolua_building_get_typename); #ifdef TODO .property("type", &building_gettype) - .def_readwrite("size", &building::size) + .def_readwrite("size", &building::size) #endif - tolua_variable(L, TOLUA_CAST "objects", tolua_building_get_objects, 0); + tolua_variable(L, TOLUA_CAST "objects", tolua_building_get_objects, 0); } tolua_endmodule(L); diff --git a/src/bindings/bind_faction.c b/src/bindings/bind_faction.c index 75bafa275..abfff18e0 100644 --- a/src/bindings/bind_faction.c +++ b/src/bindings/bind_faction.c @@ -32,22 +32,25 @@ without prior permission by the authors of Eressea. #include -int tolua_factionlist_next(lua_State *L) +int tolua_factionlist_next(lua_State * L) { - faction** faction_ptr = (faction **)lua_touserdata(L, lua_upvalueindex(1)); - faction * f = *faction_ptr; + faction **faction_ptr = (faction **) lua_touserdata(L, lua_upvalueindex(1)); + + faction *f = *faction_ptr; + if (f != NULL) { - tolua_pushusertype(L, (void*)f, TOLUA_CAST "faction"); + tolua_pushusertype(L, (void *)f, TOLUA_CAST "faction"); *faction_ptr = f->next; return 1; - } - else return 0; /* no more values to return */ + } else + return 0; /* no more values to return */ } -static int tolua_faction_get_units(lua_State* L) +static int tolua_faction_get_units(lua_State * L) { - faction * self = (faction *)tolua_tousertype(L, 1, 0); - unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + + unit **unit_ptr = (unit **) lua_newuserdata(L, sizeof(unit *)); luaL_getmetatable(L, TOLUA_CAST "unit"); lua_setmetatable(L, -2); @@ -58,62 +61,68 @@ static int tolua_faction_get_units(lua_State* L) return 1; } -int tolua_faction_add_item(lua_State *L) +int tolua_faction_add_item(lua_State * L) { - faction * self = (faction *)tolua_tousertype(L, 1, 0); - const char * iname = tolua_tostring(L, 2, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + + const char *iname = tolua_tostring(L, 2, 0); + int number = (int)tolua_tonumber(L, 3, 0); + int result = -1; - if (iname!=NULL) { - const item_type * itype = it_find(iname); - if (itype!=NULL) { - item * i = i_change(&self->items, itype, number); - result = i?i->number:0; - } // if (itype!=NULL) + if (iname != NULL) { + const item_type *itype = it_find(iname); + + if (itype != NULL) { + item *i = i_change(&self->items, itype, number); + + result = i ? i->number : 0; + } // if (itype!=NULL) } lua_pushnumber(L, result); return 1; } -static int -tolua_faction_get_maxheroes(lua_State* L) +static int tolua_faction_get_maxheroes(lua_State * L) { - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)maxheroes(self)); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + + tolua_pushnumber(L, (lua_Number) maxheroes(self)); return 1; } -static int -tolua_faction_get_heroes(lua_State* L) +static int tolua_faction_get_heroes(lua_State * L) { - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)countheroes(self)); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + + tolua_pushnumber(L, (lua_Number) countheroes(self)); return 1; } -static int -tolua_faction_get_score(lua_State* L) +static int tolua_faction_get_score(lua_State * L) { - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->score); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + + tolua_pushnumber(L, (lua_Number) self->score); return 1; } -static int -tolua_faction_get_id(lua_State* L) +static int tolua_faction_get_id(lua_State * L) { - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->no); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + + tolua_pushnumber(L, (lua_Number) self->no); return 1; } -static int -tolua_faction_set_id(lua_State* L) +static int tolua_faction_set_id(lua_State * L) { - faction * self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + int id = (int)tolua_tonumber(L, 2, 0); - if (findfaction(id)==NULL) { + + if (findfaction(id) == NULL) { renumber_faction(self, id); lua_pushboolean(L, 1); } else { @@ -122,119 +131,128 @@ tolua_faction_set_id(lua_State* L) return 1; } -static int -tolua_faction_get_age(lua_State* L) +static int tolua_faction_get_age(lua_State * L) { - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->age); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + + tolua_pushnumber(L, (lua_Number) self->age); return 1; } -static int -tolua_faction_set_age(lua_State* L) +static int tolua_faction_set_age(lua_State * L) { - faction * self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + int age = (int)tolua_tonumber(L, 2, 0); + self->age = age; return 0; } -static int -tolua_faction_get_flags(lua_State* L) +static int tolua_faction_get_flags(lua_State * L) { - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->flags); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + + tolua_pushnumber(L, (lua_Number) self->flags); return 1; } -static int -tolua_faction_get_options(lua_State* L) +static int tolua_faction_get_options(lua_State * L) { - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->options); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + + tolua_pushnumber(L, (lua_Number) self->options); return 1; } -static int -tolua_faction_set_options(lua_State* L) +static int tolua_faction_set_options(lua_State * L) { - faction * self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + int options = (int)tolua_tonumber(L, 2, self->options); + self->options = options; return 1; } -static int -tolua_faction_get_lastturn(lua_State* L) +static int tolua_faction_get_lastturn(lua_State * L) { - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->lastorders); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + + tolua_pushnumber(L, (lua_Number) self->lastorders); return 1; } -static int -tolua_faction_set_lastturn(lua_State* L) +static int tolua_faction_set_lastturn(lua_State * L) { - faction * self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + if (self) { self->lastorders = (int)tolua_tonumber(L, 2, self->lastorders); } return 0; } -static int -tolua_faction_renumber(lua_State* L) +static int tolua_faction_renumber(lua_State * L) { - faction * self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + int no = (int)tolua_tonumber(L, 2, 0); renumber_faction(self, no); return 0; } -static int -tolua_faction_get_objects(lua_State* L) +static int tolua_faction_get_objects(lua_State * L) { - faction * self = (faction *)tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + + tolua_pushusertype(L, (void *)&self->attribs, TOLUA_CAST "hashtable"); return 1; } -static int -tolua_faction_get_policy(lua_State* L) +static int tolua_faction_get_policy(lua_State * L) { - faction * self = (faction *)tolua_tousertype(L, 1, 0); - faction * other = (faction *)tolua_tousertype(L, 2, 0); - const char * policy = tolua_tostring(L, 3, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + + faction *other = (faction *) tolua_tousertype(L, 2, 0); + + const char *policy = tolua_tostring(L, 3, 0); int result = 0, mode; - for (mode=0;helpmodes[mode].name!=NULL;++mode) { - if (strcmp(policy, helpmodes[mode].name)==0) { + + for (mode = 0; helpmodes[mode].name != NULL; ++mode) { + if (strcmp(policy, helpmodes[mode].name) == 0) { result = get_alliance(self, other) & mode; break; } } - tolua_pushnumber(L, (lua_Number)result); + tolua_pushnumber(L, (lua_Number) result); return 1; } -static int -tolua_faction_set_policy(lua_State* L) +static int tolua_faction_set_policy(lua_State * L) { - faction * self = (faction *)tolua_tousertype(L, 1, 0); - faction * other = (faction *)tolua_tousertype(L, 2, 0); - const char * policy = tolua_tostring(L, 3, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + + faction *other = (faction *) tolua_tousertype(L, 2, 0); + + const char *policy = tolua_tostring(L, 3, 0); + int value = tolua_toboolean(L, 4, 0); int mode; - for (mode=0;helpmodes[mode].name!=NULL;++mode) { - if (strcmp(policy, helpmodes[mode].name)==0) { + + for (mode = 0; helpmodes[mode].name != NULL; ++mode) { + if (strcmp(policy, helpmodes[mode].name) == 0) { if (value) { - set_alliance(self, other, get_alliance(self, other) | helpmodes[mode].status); + set_alliance(self, other, get_alliance(self, + other) | helpmodes[mode].status); } else { - set_alliance(self, other, get_alliance(self, other) & ~helpmodes[mode].status); + set_alliance(self, other, get_alliance(self, + other) & ~helpmodes[mode].status); } break; } @@ -243,43 +261,49 @@ tolua_faction_set_policy(lua_State* L) return 0; } -static int -tolua_faction_normalize(lua_State* L) +static int tolua_faction_normalize(lua_State * L) { - faction * f = (faction *)tolua_tousertype(L, 1, 0); - region * r = (region * )tolua_tousertype(L, 2, 0); + faction *f = (faction *) tolua_tousertype(L, 1, 0); + + region *r = (region *) tolua_tousertype(L, 2, 0); + if (r) { - plane * pl = rplane(r); + plane *pl = rplane(r); + int nx = r->x, ny = r->y; + pnormalize(&nx, &ny, pl); adjust_coordinates(f, &nx, &ny, pl, r); - tolua_pushnumber(L, (lua_Number)nx); - tolua_pushnumber(L, (lua_Number)ny); + tolua_pushnumber(L, (lua_Number) nx); + tolua_pushnumber(L, (lua_Number) ny); return 2; } return 0; } -static int -tolua_faction_set_origin(lua_State* L) +static int tolua_faction_set_origin(lua_State * L) { - faction * f = (faction *)tolua_tousertype(L, 1, 0); - region * r = (region *)tolua_tousertype(L, 2, 0); - plane * pl = rplane(r); - int id = pl?pl->id:0; - + faction *f = (faction *) tolua_tousertype(L, 1, 0); + + region *r = (region *) tolua_tousertype(L, 2, 0); + + plane *pl = rplane(r); + + int id = pl ? pl->id : 0; + set_ursprung(f, id, r->x - plane_center_x(pl), r->y - plane_center_y(pl)); return 0; } -static int -tolua_faction_get_origin(lua_State* L) +static int tolua_faction_get_origin(lua_State * L) { - faction * self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + + ursprung *origin = self->ursprung; - ursprung * origin = self->ursprung; int x, y; - while (origin!=NULL && origin->id!=0) { + + while (origin != NULL && origin->id != 0) { origin = origin->next; } if (origin) { @@ -290,31 +314,38 @@ tolua_faction_get_origin(lua_State* L) y = 0; } - tolua_pushnumber(L, (lua_Number)x); - tolua_pushnumber(L, (lua_Number)y); + tolua_pushnumber(L, (lua_Number) x); + tolua_pushnumber(L, (lua_Number) y); return 2; } -static int -tolua_faction_destroy(lua_State* L) +static int tolua_faction_destroy(lua_State * L) { - faction* f = (faction*) tolua_tousertype(L, 1, 0); + faction *f = (faction *) tolua_tousertype(L, 1, 0); + destroyfaction(f); return 0; } -static int -tolua_faction_create(lua_State* L) +static int tolua_faction_create(lua_State * L) { - const char * email = tolua_tostring(L, 1, 0); - const char * racename = tolua_tostring(L, 2, 0); - const char * lang = tolua_tostring(L, 3, 0); - struct locale * loc = find_locale(lang); - faction * f = NULL; - const struct race * frace = rc_find(racename); - if (frace==NULL) frace = findrace(racename, find_locale("de")); - if (frace==NULL) frace = findrace(racename, find_locale("en")); - if (frace!=NULL) { + const char *email = tolua_tostring(L, 1, 0); + + const char *racename = tolua_tostring(L, 2, 0); + + const char *lang = tolua_tostring(L, 3, 0); + + struct locale *loc = find_locale(lang); + + faction *f = NULL; + + const struct race *frace = rc_find(racename); + + if (frace == NULL) + frace = findrace(racename, find_locale("de")); + if (frace == NULL) + frace = findrace(racename, find_locale("en")); + if (frace != NULL) { f = addfaction(email, NULL, frace, loc, 0); } if (!f) { @@ -324,131 +355,151 @@ tolua_faction_create(lua_State* L) return 1; } -static int tolua_faction_get_password(lua_State* L) +static int tolua_faction_get_password(lua_State * L) { - faction* self = (faction*) tolua_tousertype(L, 1, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, faction_getpassword(self)); return 1; } -static int tolua_faction_set_password(lua_State* L) +static int tolua_faction_set_password(lua_State * L) { - faction* self = (faction*)tolua_tousertype(L, 1, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + faction_setpassword(self, tolua_tostring(L, 2, 0)); return 0; } -static int tolua_faction_get_email(lua_State* L) +static int tolua_faction_get_email(lua_State * L) { - faction* self = (faction*) tolua_tousertype(L, 1, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, faction_getemail(self)); return 1; } -static int tolua_faction_set_email(lua_State* L) +static int tolua_faction_set_email(lua_State * L) { - faction* self = (faction*)tolua_tousertype(L, 1, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + faction_setemail(self, tolua_tostring(L, 2, 0)); return 0; } -static int tolua_faction_get_locale(lua_State* L) +static int tolua_faction_get_locale(lua_State * L) { - faction* self = (faction*) tolua_tousertype(L, 1, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, locale_name(self->locale)); return 1; } -static int tolua_faction_set_locale(lua_State* L) +static int tolua_faction_set_locale(lua_State * L) { - faction* self = (faction*)tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + + const char *name = tolua_tostring(L, 2, 0); + self->locale = find_locale(name); return 0; } -static int tolua_faction_get_race(lua_State* L) +static int tolua_faction_get_race(lua_State * L) { - faction* self = (faction*) tolua_tousertype(L, 1, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->race->_name[0]); return 1; } -static int tolua_faction_set_race(lua_State* L) +static int tolua_faction_set_race(lua_State * L) { - faction* self = (faction*)tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - race * rc = rc_find(name); - if (rc!=NULL) { + faction *self = (faction *) tolua_tousertype(L, 1, 0); + + const char *name = tolua_tostring(L, 2, 0); + + race *rc = rc_find(name); + + if (rc != NULL) { self->race = rc; } return 0; } -static int tolua_faction_get_name(lua_State* L) +static int tolua_faction_get_name(lua_State * L) { - faction* self = (faction*) tolua_tousertype(L, 1, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, faction_getname(self)); return 1; } -static int tolua_faction_set_name(lua_State* L) +static int tolua_faction_set_name(lua_State * L) { - faction* self = (faction*)tolua_tousertype(L, 1, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + faction_setname(self, tolua_tostring(L, 2, 0)); return 0; } -static int tolua_faction_get_uid(lua_State* L) +static int tolua_faction_get_uid(lua_State * L) { - faction* f = (faction*) tolua_tousertype(L, 1, 0); + faction *f = (faction *) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, f->subscription); return 1; } -static int tolua_faction_set_uid(lua_State* L) +static int tolua_faction_set_uid(lua_State * L) { - faction* f = (faction*)tolua_tousertype(L, 1, 0); + faction *f = (faction *) tolua_tousertype(L, 1, 0); + f->subscription = (int)tolua_tonumber(L, 2, 0); return 0; } -static int tolua_faction_get_info(lua_State* L) +static int tolua_faction_get_info(lua_State * L) { - faction* self = (faction*) tolua_tousertype(L, 1, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, faction_getbanner(self)); return 1; } -static int tolua_faction_set_info(lua_State* L) +static int tolua_faction_set_info(lua_State * L) { - faction* self = (faction*)tolua_tousertype(L, 1, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + faction_setbanner(self, tolua_tostring(L, 2, 0)); return 0; } -static int tolua_faction_get_alliance(lua_State* L) +static int tolua_faction_get_alliance(lua_State * L) { - faction* self = (faction*) tolua_tousertype(L, 1, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, f_get_alliance(self), TOLUA_CAST "alliance"); return 1; } -static int tolua_faction_set_alliance(lua_State* L) +static int tolua_faction_set_alliance(lua_State * L) { - faction* self = (faction*)tolua_tousertype(L, 1, 0); - alliance* alli = (alliance*)tolua_tousertype(L, 2, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + + alliance *alli = (alliance *) tolua_tousertype(L, 2, 0); setalliance(self, alli); return 0; } -static int tolua_faction_get_items(lua_State* L) +static int tolua_faction_get_items(lua_State * L) { - faction* self = (faction*)tolua_tousertype(L, 1, 0); - item ** item_ptr = (item **)lua_newuserdata(L, sizeof(item *)); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + + item **item_ptr = (item **) lua_newuserdata(L, sizeof(item *)); luaL_getmetatable(L, TOLUA_CAST "item"); lua_setmetatable(L, -2); @@ -460,22 +511,22 @@ static int tolua_faction_get_items(lua_State* L) return 1; } -static int -tolua_faction_tostring(lua_State *L) +static int tolua_faction_tostring(lua_State * L) { - faction * self = (faction *)tolua_tousertype(L, 1, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + lua_pushstring(L, factionname(self)); return 1; } -static int tolua_faction_get_spells(lua_State* L) +static int tolua_faction_get_spells(lua_State * L) { - faction* self = (faction*)tolua_tousertype(L, 1, 0); + faction *self = (faction *) tolua_tousertype(L, 1, 0); + return tolua_quicklist_push(L, "spell_list", "spell", self->spellbook); } -void -tolua_faction_open(lua_State* L) +void tolua_faction_open(lua_State * L) { /* register user types */ tolua_usertype(L, TOLUA_CAST "faction"); @@ -484,30 +535,44 @@ tolua_faction_open(lua_State* L) tolua_module(L, NULL, 0); tolua_beginmodule(L, NULL); { - tolua_cclass(L, TOLUA_CAST "faction", TOLUA_CAST "faction", TOLUA_CAST "", NULL); + tolua_cclass(L, TOLUA_CAST "faction", TOLUA_CAST "faction", TOLUA_CAST "", + NULL); tolua_beginmodule(L, TOLUA_CAST "faction"); { tolua_function(L, TOLUA_CAST "__tostring", tolua_faction_tostring); - tolua_variable(L, TOLUA_CAST "id", tolua_faction_get_id, tolua_faction_set_id); - tolua_variable(L, TOLUA_CAST "uid", &tolua_faction_get_uid, &tolua_faction_set_uid); - tolua_variable(L, TOLUA_CAST "name", &tolua_faction_get_name, &tolua_faction_set_name); - tolua_variable(L, TOLUA_CAST "info", &tolua_faction_get_info, &tolua_faction_set_info); + tolua_variable(L, TOLUA_CAST "id", tolua_faction_get_id, + tolua_faction_set_id); + tolua_variable(L, TOLUA_CAST "uid", &tolua_faction_get_uid, + &tolua_faction_set_uid); + tolua_variable(L, TOLUA_CAST "name", &tolua_faction_get_name, + &tolua_faction_set_name); + tolua_variable(L, TOLUA_CAST "info", &tolua_faction_get_info, + &tolua_faction_set_info); tolua_variable(L, TOLUA_CAST "units", tolua_faction_get_units, NULL); tolua_variable(L, TOLUA_CAST "heroes", tolua_faction_get_heroes, NULL); tolua_variable(L, TOLUA_CAST "spells", tolua_faction_get_spells, 0); - tolua_variable(L, TOLUA_CAST "maxheroes", tolua_faction_get_maxheroes, NULL); - tolua_variable(L, TOLUA_CAST "password", tolua_faction_get_password, tolua_faction_set_password); - tolua_variable(L, TOLUA_CAST "email", tolua_faction_get_email, tolua_faction_set_email); - tolua_variable(L, TOLUA_CAST "locale", tolua_faction_get_locale, tolua_faction_set_locale); - tolua_variable(L, TOLUA_CAST "race", tolua_faction_get_race, tolua_faction_set_race); - tolua_variable(L, TOLUA_CAST "alliance", tolua_faction_get_alliance, tolua_faction_set_alliance); + tolua_variable(L, TOLUA_CAST "maxheroes", tolua_faction_get_maxheroes, + NULL); + tolua_variable(L, TOLUA_CAST "password", tolua_faction_get_password, + tolua_faction_set_password); + tolua_variable(L, TOLUA_CAST "email", tolua_faction_get_email, + tolua_faction_set_email); + tolua_variable(L, TOLUA_CAST "locale", tolua_faction_get_locale, + tolua_faction_set_locale); + tolua_variable(L, TOLUA_CAST "race", tolua_faction_get_race, + tolua_faction_set_race); + tolua_variable(L, TOLUA_CAST "alliance", tolua_faction_get_alliance, + tolua_faction_set_alliance); tolua_variable(L, TOLUA_CAST "score", tolua_faction_get_score, NULL); - tolua_variable(L, TOLUA_CAST "age", tolua_faction_get_age, tolua_faction_set_age); - tolua_variable(L, TOLUA_CAST "options", tolua_faction_get_options, tolua_faction_set_options); + tolua_variable(L, TOLUA_CAST "age", tolua_faction_get_age, + tolua_faction_set_age); + tolua_variable(L, TOLUA_CAST "options", tolua_faction_get_options, + tolua_faction_set_options); tolua_variable(L, TOLUA_CAST "flags", tolua_faction_get_flags, NULL); - tolua_variable(L, TOLUA_CAST "lastturn", tolua_faction_get_lastturn, tolua_faction_set_lastturn); - + tolua_variable(L, TOLUA_CAST "lastturn", tolua_faction_get_lastturn, + tolua_faction_set_lastturn); + tolua_function(L, TOLUA_CAST "set_policy", &tolua_faction_set_policy); tolua_function(L, TOLUA_CAST "get_policy", &tolua_faction_get_policy); tolua_function(L, TOLUA_CAST "get_origin", &tolua_faction_get_origin); @@ -521,16 +586,17 @@ tolua_faction_open(lua_State* L) tolua_function(L, TOLUA_CAST "create", &tolua_faction_create); tolua_function(L, TOLUA_CAST "destroy", &tolua_faction_destroy); #ifdef TODO - def("faction_origin", &faction_getorigin, pure_out_value(_2) + pure_out_value(_3)), + def("faction_origin", &faction_getorigin, + pure_out_value(_2) + pure_out_value(_3)),.def_readwrite("subscription", + &faction::subscription) - .def_readwrite("subscription", &faction::subscription) + .property("x", &faction_getorigin_x, &faction_setorigin_x) + .property("y", &faction_getorigin_y, &faction_setorigin_y) - .property("x", &faction_getorigin_x, &faction_setorigin_x) - .property("y", &faction_getorigin_y, &faction_setorigin_y) - - .def("add_notice", &faction_addnotice) + .def("add_notice", &faction_addnotice) #endif - tolua_variable(L, TOLUA_CAST "objects", tolua_faction_get_objects, NULL); + tolua_variable(L, TOLUA_CAST "objects", tolua_faction_get_objects, + NULL); } tolua_endmodule(L); } diff --git a/src/bindings/bind_gmtool.c b/src/bindings/bind_gmtool.c index 6b57d1740..f699f7f30 100644 --- a/src/bindings/bind_gmtool.c +++ b/src/bindings/bind_gmtool.c @@ -13,48 +13,51 @@ #include #include -static int -tolua_run_mapper(lua_State* L) +static int tolua_run_mapper(lua_State * L) { run_mapper(); return 0; } -static int -tolua_highlight_region(lua_State* L) +static int tolua_highlight_region(lua_State * L) { - region * r = tolua_tousertype(L, 1, 0); + region *r = tolua_tousertype(L, 1, 0); + int select = tolua_toboolean(L, 2, 0); + highlight_region(r, select); return 0; } -static int -tolua_current_region(lua_State* L) +static int tolua_current_region(lua_State * L) { - map_region * mr = cursor_region(¤t_state->display, ¤t_state->cursor); - tolua_pushusertype(L, mr?mr->r:NULL, TOLUA_CAST "region"); + map_region *mr = + cursor_region(¤t_state->display, ¤t_state->cursor); + tolua_pushusertype(L, mr ? mr->r : NULL, TOLUA_CAST "region"); return 1; } -static int -tolua_select_coordinate(lua_State* L) +static int tolua_select_coordinate(lua_State * L) { int nx = (int)tolua_tonumber(L, 1, 0); + int ny = (int)tolua_tonumber(L, 2, 0); + int select = tolua_toboolean(L, 3, 0); + if (current_state) { select_coordinate(current_state->selected, nx, ny, select); } return 0; } -static int -tolua_select_region(lua_State* L) +static int tolua_select_region(lua_State * L) { - region * r = tolua_tousertype(L, 1, 0); + region *r = tolua_tousertype(L, 1, 0); + int select = tolua_toboolean(L, 2, 0); + if (current_state && r) { select_coordinate(current_state->selected, r->x, r->y, select); } @@ -62,16 +65,15 @@ tolua_select_region(lua_State* L) } typedef struct tag_iterator { - selection * list; - tag * node; - region * r; + selection *list; + tag *node; + region *r; int hash; } tag_iterator; -void -tag_advance(tag_iterator * iter) +void tag_advance(tag_iterator * iter) { - while (iter->hash!=MAXTHASH) { + while (iter->hash != MAXTHASH) { if (iter->node) { iter->node = iter->node->nexthash; } @@ -89,8 +91,7 @@ tag_advance(tag_iterator * iter) } } -void -tag_rewind(tag_iterator * iter) +void tag_rewind(tag_iterator * iter) { if (iter->list) { iter->r = NULL; @@ -108,24 +109,23 @@ tag_rewind(tag_iterator * iter) } } -static int -tolua_tags_next(lua_State *L) +static int tolua_tags_next(lua_State * L) { - tag_iterator * iter = (tag_iterator *)lua_touserdata(L, lua_upvalueindex(1)); + tag_iterator *iter = (tag_iterator *) lua_touserdata(L, lua_upvalueindex(1)); + if (iter->node) { - tolua_pushusertype(L, (void*)iter->r, TOLUA_CAST "region"); + tolua_pushusertype(L, (void *)iter->r, TOLUA_CAST "region"); tag_advance(iter); return 1; - } - else { - return 0; /* no more values to return */ + } else { + return 0; /* no more values to return */ } } -static int -tolua_selected_regions(lua_State* L) +static int tolua_selected_regions(lua_State * L) { - tag_iterator * iter = (tag_iterator*)lua_newuserdata(L, sizeof(tag_iterator)); + tag_iterator *iter = + (tag_iterator *) lua_newuserdata(L, sizeof(tag_iterator)); luaL_getmetatable(L, "tag_iterator"); lua_setmetatable(L, -2); @@ -137,28 +137,28 @@ tolua_selected_regions(lua_State* L) return 1; } -static int -tolua_state_open(lua_State* L) +static int tolua_state_open(lua_State * L) { unused(L); state_open(); return 0; } -static int -tolua_state_close(lua_State* L) +static int tolua_state_close(lua_State * L) { unused(L); state_close(current_state); return 0; } -static int -tolua_make_island(lua_State * L) +static int tolua_make_island(lua_State * L) { int x = (int)tolua_tonumber(L, 1, 0); + int y = (int)tolua_tonumber(L, 2, 0); + int s = (int)tolua_tonumber(L, 3, 0); + int n = (int)tolua_tonumber(L, 4, s / 3); n = build_island_e3(x, y, n, s); @@ -167,36 +167,48 @@ tolua_make_island(lua_State * L) } static int paint_handle; -static struct lua_State * paint_state; -static void -lua_paint_info(struct window * wnd, const struct state * st) +static struct lua_State *paint_state; + +static void lua_paint_info(struct window *wnd, const struct state *st) { - struct lua_State * L = paint_state; + struct lua_State *L = paint_state; + int nx = st->cursor.x, ny = st->cursor.y; + pnormalize(&nx, &ny, st->cursor.pl); lua_rawgeti(L, LUA_REGISTRYINDEX, paint_handle); tolua_pushnumber(L, nx); tolua_pushnumber(L, ny); - if (lua_pcall(L, 2, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); + if (lua_pcall(L, 2, 1, 0) != 0) { + const char *error = lua_tostring(L, -1); + log_error(("paint function failed: %s\n", error)); lua_pop(L, 1); tolua_error(L, TOLUA_CAST "event handler call failed", NULL); } else { - const char* result = lua_tostring(L, -1); - WINDOW * win = wnd->handle; - int size = getmaxx(win)-2; - int line = 0, maxline = getmaxy(win)-2; - const char * str = result; + const char *result = lua_tostring(L, -1); + + WINDOW *win = wnd->handle; + + int size = getmaxx(win) - 2; + + int line = 0, maxline = getmaxy(win) - 2; + + const char *str = result; + wxborder(win); - while (*str && line -static int -tolua_hashtable_get(lua_State* L) +static int tolua_hashtable_get(lua_State * L) { hashtable self = (hashtable) tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - attrib * a = a_find(*self, &at_object); + + const char *name = tolua_tostring(L, 2, 0); + + attrib *a = a_find(*self, &at_object); for (; a && a->type == &at_object; a = a->next) { - const char * obj_name = object_name(a); + const char *obj_name = object_name(a); + if (obj_name && name && strcmp(obj_name, name) == 0) { variant val; + object_type type; object_get(a, &type, &val); @@ -47,10 +50,10 @@ tolua_hashtable_get(lua_State* L) lua_pushnil(L); break; case TINTEGER: - lua_pushnumber(L, (lua_Number)val.i); + lua_pushnumber(L, (lua_Number) val.i); break; case TREAL: - lua_pushnumber(L, (lua_Number)val.f); + lua_pushnumber(L, (lua_Number) val.f); break; case TREGION: tolua_pushusertype(L, val.v, TOLUA_CAST "region"); @@ -65,7 +68,7 @@ tolua_hashtable_get(lua_State* L) tolua_pushusertype(L, val.v, TOLUA_CAST "ship"); break; case TSTRING: - tolua_pushstring(L, (const char*) val.v); + tolua_pushstring(L, (const char *)val.v); break; default: assert(!"not implemented"); @@ -77,15 +80,18 @@ tolua_hashtable_get(lua_State* L) return 1; } -static int -tolua_hashtable_set_number(lua_State* L) +static int tolua_hashtable_set_number(lua_State * L) { hashtable self = (hashtable) tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); + + const char *name = tolua_tostring(L, 2, 0); + lua_Number value = tolua_tonumber(L, 3, 0); - attrib * a = a_find(*self, &at_object); + + attrib *a = a_find(*self, &at_object); + variant val; - + val.f = (float)value; for (; a && a->type == &at_object; a = a->next) { @@ -99,13 +105,16 @@ tolua_hashtable_set_number(lua_State* L) return 0; } -static int -tolua_hashtable_set_string(lua_State* L) +static int tolua_hashtable_set_string(lua_State * L) { hashtable self = (hashtable) tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - const char * value = tolua_tostring(L, 3, 0); - attrib * a = a_find(*self, &at_object); + + const char *name = tolua_tostring(L, 2, 0); + + const char *value = tolua_tostring(L, 3, 0); + + attrib *a = a_find(*self, &at_object); + variant val; val.v = strdup(value); @@ -121,13 +130,16 @@ tolua_hashtable_set_string(lua_State* L) return 0; } -static int -tolua_hashtable_set_usertype(lua_State* L, int type) +static int tolua_hashtable_set_usertype(lua_State * L, int type) { hashtable self = (hashtable) tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - unit * value = tolua_tousertype(L, 3, 0); - attrib * a = a_find(*self, &at_object); + + const char *name = tolua_tostring(L, 2, 0); + + unit *value = tolua_tousertype(L, 3, 0); + + attrib *a = a_find(*self, &at_object); + variant val; val.v = value; @@ -144,10 +156,10 @@ tolua_hashtable_set_usertype(lua_State* L, int type) } -static int -tolua_hashtable_set(lua_State* L) +static int tolua_hashtable_set(lua_State * L) { tolua_Error tolua_err; + if (tolua_isnumber(L, 3, 0, &tolua_err)) { return tolua_hashtable_set_number(L); } else if (tolua_isusertype(L, 3, TOLUA_CAST "unit", 0, &tolua_err)) { @@ -166,8 +178,7 @@ tolua_hashtable_set(lua_State* L) -void -tolua_hashtable_open(lua_State* L) +void tolua_hashtable_open(lua_State * L) { /* register user types */ tolua_usertype(L, TOLUA_CAST "hashtable"); @@ -175,7 +186,8 @@ tolua_hashtable_open(lua_State* L) tolua_module(L, NULL, 0); tolua_beginmodule(L, NULL); { - tolua_cclass(L, TOLUA_CAST "hashtable", TOLUA_CAST "hashtable", TOLUA_CAST "", NULL); + tolua_cclass(L, TOLUA_CAST "hashtable", TOLUA_CAST "hashtable", + TOLUA_CAST "", NULL); tolua_beginmodule(L, TOLUA_CAST "hashtable"); { tolua_function(L, TOLUA_CAST "get", tolua_hashtable_get); diff --git a/src/bindings/bind_hashtable.h b/src/bindings/bind_hashtable.h index d137638f2..5e23350f6 100644 --- a/src/bindings/bind_hashtable.h +++ b/src/bindings/bind_hashtable.h @@ -17,7 +17,7 @@ extern "C" { struct lua_State; void tolua_hashtable_open(struct lua_State *L); - typedef struct attrib ** hashtable; + typedef struct attrib **hashtable; #ifdef __cplusplus } diff --git a/src/bindings/bind_message.c b/src/bindings/bind_message.c index 44c5eb0e7..b17024e8a 100644 --- a/src/bindings/bind_message.c +++ b/src/bindings/bind_message.c @@ -25,32 +25,32 @@ #define E_INVALID_PARAMETER_VALUE 4 typedef struct lua_message { - const message_type * mtype; - message * msg; - variant * args; + const message_type *mtype; + message *msg; + variant *args; } lua_message; -int -mtype_get_param(const message_type * mtype, const char * param) +int mtype_get_param(const message_type * mtype, const char *param) { int i; - for (i=0;i!=mtype->nparameters;++i) { - if (strcmp(mtype->pnames[i], param)==0) { + + for (i = 0; i != mtype->nparameters; ++i) { + if (strcmp(mtype->pnames[i], param) == 0) { return i; } } return mtype->nparameters; } -static lua_message * -msg_create_message(const char *type) +static lua_message *msg_create_message(const char *type) { - lua_message * lmsg = malloc(sizeof(lua_message)); + lua_message *lmsg = malloc(sizeof(lua_message)); + lmsg->msg = 0; lmsg->args = 0; lmsg->mtype = mt_find(type); if (lmsg->mtype) { - lmsg->args = (variant*)calloc(lmsg->mtype->nparameters, sizeof(variant)); + lmsg->args = (variant *) calloc(lmsg->mtype->nparameters, sizeof(variant)); } return lmsg; } @@ -70,80 +70,78 @@ msg_destroy_message(lua_message * msg) } } */ -int -msg_set_resource(lua_message * msg, const char * param, const char * resname) +int msg_set_resource(lua_message * msg, const char *param, const char *resname) { if (msg->mtype) { int i = mtype_get_param(msg->mtype, param); - if (i==msg->mtype->nparameters) { + + if (i == msg->mtype->nparameters) { return E_INVALID_PARAMETER_NAME; } - if (strcmp(msg->mtype->types[i]->name, "resource")!=0) { + if (strcmp(msg->mtype->types[i]->name, "resource") != 0) { return E_INVALID_PARAMETER_TYPE; } - msg->args[i].v = (void*)rt_find(resname); + msg->args[i].v = (void *)rt_find(resname); return E_OK; } return E_INVALID_MESSAGE; } -int -msg_set_unit(lua_message * msg, const char * param, const unit * u) +int msg_set_unit(lua_message * msg, const char *param, const unit * u) { if (msg->mtype) { int i = mtype_get_param(msg->mtype, param); - if (i==msg->mtype->nparameters) { + if (i == msg->mtype->nparameters) { return E_INVALID_PARAMETER_NAME; } - if (strcmp(msg->mtype->types[i]->name, "unit")!=0) { + if (strcmp(msg->mtype->types[i]->name, "unit") != 0) { return E_INVALID_PARAMETER_TYPE; } - msg->args[i].v = (void*)u; + msg->args[i].v = (void *)u; return E_OK; } return E_INVALID_MESSAGE; } -int -msg_set_region(lua_message * msg, const char * param, const region * r) +int msg_set_region(lua_message * msg, const char *param, const region * r) { if (msg->mtype) { int i = mtype_get_param(msg->mtype, param); - if (i==msg->mtype->nparameters) { + if (i == msg->mtype->nparameters) { return E_INVALID_PARAMETER_NAME; } - if (strcmp(msg->mtype->types[i]->name, "region")!=0) { + if (strcmp(msg->mtype->types[i]->name, "region") != 0) { return E_INVALID_PARAMETER_TYPE; } - msg->args[i].v = (void*)r; + msg->args[i].v = (void *)r; return E_OK; } return E_INVALID_MESSAGE; } -int -msg_set_string(lua_message * msg, const char * param, const char * value) +int msg_set_string(lua_message * msg, const char *param, const char *value) { if (msg->mtype) { int i = mtype_get_param(msg->mtype, param); + variant var; - if (i==msg->mtype->nparameters) { + if (i == msg->mtype->nparameters) { return E_INVALID_PARAMETER_NAME; } - if (strcmp(msg->mtype->types[i]->name, "string")!=0) { + if (strcmp(msg->mtype->types[i]->name, "string") != 0) { return E_INVALID_PARAMETER_TYPE; } - var.v = (void*)value; + var.v = (void *)value; msg->args[i] = msg->mtype->types[i]->copy(var); return E_OK; @@ -151,15 +149,15 @@ msg_set_string(lua_message * msg, const char * param, const char * value) return E_INVALID_MESSAGE; } -int -msg_set_int(lua_message * msg, const char * param, int value) +int msg_set_int(lua_message * msg, const char *param, int value) { if (msg->mtype) { int i = mtype_get_param(msg->mtype, param); - if (i==msg->mtype->nparameters) { + + if (i == msg->mtype->nparameters) { return E_INVALID_PARAMETER_NAME; } - if (strcmp(msg->mtype->types[i]->name, "int")!=0) { + if (strcmp(msg->mtype->types[i]->name, "int") != 0) { return E_INVALID_PARAMETER_TYPE; } @@ -170,14 +168,13 @@ msg_set_int(lua_message * msg, const char * param, int value) return E_INVALID_MESSAGE; } -int -msg_send_faction(lua_message * msg, faction * f) +int msg_send_faction(lua_message * msg, faction * f) { assert(f); assert(msg); if (msg->mtype) { - if (msg->msg==NULL) { + if (msg->msg == NULL) { msg->msg = msg_create(msg->mtype, msg->args); } add_message(&f->msgs, msg->msg); @@ -186,11 +183,10 @@ msg_send_faction(lua_message * msg, faction * f) return E_INVALID_MESSAGE; } -int -msg_send_region(lua_message * lmsg, region * r) +int msg_send_region(lua_message * lmsg, region * r) { if (lmsg->mtype) { - if (lmsg->msg==NULL) { + if (lmsg->msg == NULL) { lmsg->msg = msg_create(lmsg->mtype, lmsg->args); } add_message(&r->msgs, lmsg->msg); @@ -200,73 +196,90 @@ msg_send_region(lua_message * lmsg, region * r) } -static int -tolua_msg_create(lua_State * L) +static int tolua_msg_create(lua_State * L) { - const char * type = tolua_tostring(L, 1, 0); - lua_message * lmsg = msg_create_message(type); - tolua_pushusertype(L, (void*)lmsg, TOLUA_CAST "message"); + const char *type = tolua_tostring(L, 1, 0); + + lua_message *lmsg = msg_create_message(type); + + tolua_pushusertype(L, (void *)lmsg, TOLUA_CAST "message"); return 1; } -static int -tolua_msg_set_string(lua_State * L) + +static int tolua_msg_set_string(lua_State * L) { - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - const char * param = tolua_tostring(L, 2, 0); - const char * value = tolua_tostring(L, 3, 0); + lua_message *lmsg = (lua_message *) tolua_tousertype(L, 1, 0); + + const char *param = tolua_tostring(L, 2, 0); + + const char *value = tolua_tostring(L, 3, 0); + int result = msg_set_string(lmsg, param, value); - tolua_pushnumber(L, (lua_Number)result); + + tolua_pushnumber(L, (lua_Number) result); return 1; } -static int -tolua_msg_set_int(lua_State * L) +static int tolua_msg_set_int(lua_State * L) { - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - const char * param = tolua_tostring(L, 2, 0); + lua_message *lmsg = (lua_message *) tolua_tousertype(L, 1, 0); + + const char *param = tolua_tostring(L, 2, 0); + int value = (int)tolua_tonumber(L, 3, 0); + int result = msg_set_int(lmsg, param, value); - tolua_pushnumber(L, (lua_Number)result); + + tolua_pushnumber(L, (lua_Number) result); return 1; } -static int -tolua_msg_set_resource(lua_State * L) +static int tolua_msg_set_resource(lua_State * L) { - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - const char * param = tolua_tostring(L, 2, 0); - const char * value = tolua_tostring(L, 3, 0); + lua_message *lmsg = (lua_message *) tolua_tousertype(L, 1, 0); + + const char *param = tolua_tostring(L, 2, 0); + + const char *value = tolua_tostring(L, 3, 0); + int result = msg_set_resource(lmsg, param, value); - tolua_pushnumber(L, (lua_Number)result); + + tolua_pushnumber(L, (lua_Number) result); return 1; } -static int -tolua_msg_set_unit(lua_State * L) +static int tolua_msg_set_unit(lua_State * L) { - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - const char * param = tolua_tostring(L, 2, 0); - unit * value = (unit *)tolua_tousertype(L, 3, 0); + lua_message *lmsg = (lua_message *) tolua_tousertype(L, 1, 0); + + const char *param = tolua_tostring(L, 2, 0); + + unit *value = (unit *) tolua_tousertype(L, 3, 0); + int result = msg_set_unit(lmsg, param, value); - tolua_pushnumber(L, (lua_Number)result); + + tolua_pushnumber(L, (lua_Number) result); return 1; } -static int -tolua_msg_set_region(lua_State * L) +static int tolua_msg_set_region(lua_State * L) { - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - const char * param = tolua_tostring(L, 2, 0); - region * value = (region *)tolua_tousertype(L, 3, 0); + lua_message *lmsg = (lua_message *) tolua_tousertype(L, 1, 0); + + const char *param = tolua_tostring(L, 2, 0); + + region *value = (region *) tolua_tousertype(L, 3, 0); + int result = msg_set_region(lmsg, param, value); - tolua_pushnumber(L, (lua_Number)result); + + tolua_pushnumber(L, (lua_Number) result); return 1; } -static int -tolua_msg_set(lua_State * L) +static int tolua_msg_set(lua_State * L) { tolua_Error err; + if (tolua_isnumber(L, 3, 0, &err)) { return tolua_msg_set_int(L); } else if (tolua_isusertype(L, 3, TOLUA_CAST "region", 0, &err)) { @@ -274,50 +287,56 @@ tolua_msg_set(lua_State * L) } else if (tolua_isusertype(L, 3, TOLUA_CAST "unit", 0, &err)) { return tolua_msg_set_unit(L); } - tolua_pushnumber(L, (lua_Number)-1); + tolua_pushnumber(L, (lua_Number) - 1); return 1; } -static int -tolua_msg_send_region(lua_State * L) +static int tolua_msg_send_region(lua_State * L) { - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - region * r = (region *)tolua_tousertype(L, 2, 0); + lua_message *lmsg = (lua_message *) tolua_tousertype(L, 1, 0); + + region *r = (region *) tolua_tousertype(L, 2, 0); + int result = msg_send_region(lmsg, r); - tolua_pushnumber(L, (lua_Number)result); + + tolua_pushnumber(L, (lua_Number) result); return 1; } -static int -tolua_msg_report_action(lua_State * L) +static int tolua_msg_report_action(lua_State * L) { - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - region * r = (region *)tolua_tousertype(L, 2, 0); - unit * u = (unit *)tolua_tousertype(L, 3, 0); + lua_message *lmsg = (lua_message *) tolua_tousertype(L, 1, 0); + + region *r = (region *) tolua_tousertype(L, 2, 0); + + unit *u = (unit *) tolua_tousertype(L, 3, 0); + int result, flags = (int)tolua_tonumber(L, 4, 0); - if (lmsg->msg==NULL) { + + if (lmsg->msg == NULL) { lmsg->msg = msg_create(lmsg->mtype, lmsg->args); } result = report_action(r, u, lmsg->msg, flags); - tolua_pushnumber(L, (lua_Number)result); + tolua_pushnumber(L, (lua_Number) result); return 1; } -static int -tolua_msg_send_faction(lua_State * L) +static int tolua_msg_send_faction(lua_State * L) { - lua_message * lmsg = (lua_message *)tolua_tousertype(L, 1, 0); - faction * f = (faction *)tolua_tousertype(L, 2, 0); + lua_message *lmsg = (lua_message *) tolua_tousertype(L, 1, 0); + + faction *f = (faction *) tolua_tousertype(L, 2, 0); + if (f && lmsg) { int result = msg_send_faction(lmsg, f); - tolua_pushnumber(L, (lua_Number)result); + + tolua_pushnumber(L, (lua_Number) result); return 1; } return 0; } -void -tolua_message_open(lua_State* L) +void tolua_message_open(lua_State * L) { /* register user types */ tolua_usertype(L, TOLUA_CAST "message"); @@ -327,7 +346,8 @@ tolua_message_open(lua_State* L) { tolua_function(L, TOLUA_CAST "message", tolua_msg_create); - tolua_cclass(L, TOLUA_CAST "message", TOLUA_CAST "message", TOLUA_CAST "", NULL); + tolua_cclass(L, TOLUA_CAST "message", TOLUA_CAST "message", TOLUA_CAST "", + NULL); tolua_beginmodule(L, TOLUA_CAST "message"); { tolua_function(L, TOLUA_CAST "set", tolua_msg_set); diff --git a/src/bindings/bind_region.c b/src/bindings/bind_region.c index 022f65d24..c41c2ef0d 100644 --- a/src/bindings/bind_region.c +++ b/src/bindings/bind_region.c @@ -41,65 +41,69 @@ without prior permission by the authors of Eressea. #include -int tolua_regionlist_next(lua_State *L) +int tolua_regionlist_next(lua_State * L) { - region** region_ptr = (region **)lua_touserdata(L, lua_upvalueindex(1)); - region * r = *region_ptr; + region **region_ptr = (region **) lua_touserdata(L, lua_upvalueindex(1)); + + region *r = *region_ptr; + if (r != NULL) { - tolua_pushusertype(L, (void*)r, TOLUA_CAST "region"); + tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); *region_ptr = r->next; return 1; - } - else return 0; /* no more values to return */ + } else + return 0; /* no more values to return */ } -static int -tolua_region_get_id(lua_State* L) +static int tolua_region_get_id(lua_State * L) { - region * self = (region *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->uid); + region *self = (region *) tolua_tousertype(L, 1, 0); + + tolua_pushnumber(L, (lua_Number) self->uid); return 1; } -static int -tolua_region_get_x(lua_State* L) +static int tolua_region_get_x(lua_State * L) { - region * self = (region *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->x); + region *self = (region *) tolua_tousertype(L, 1, 0); + + tolua_pushnumber(L, (lua_Number) self->x); return 1; } -static int -tolua_region_get_y(lua_State* L) +static int tolua_region_get_y(lua_State * L) { - region * self = (region *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->y); + region *self = (region *) tolua_tousertype(L, 1, 0); + + tolua_pushnumber(L, (lua_Number) self->y); return 1; } -static int -tolua_region_get_plane(lua_State* L) +static int tolua_region_get_plane(lua_State * L) { - region * r = (region *)tolua_tousertype(L, 1, 0); + region *r = (region *) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, rplane(r), TOLUA_CAST "plane"); return 1; } -static int -tolua_region_get_terrain(lua_State* L) +static int tolua_region_get_terrain(lua_State * L) { - region* self = (region*) tolua_tousertype(L, 1, 0); + region *self = (region *) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->terrain->_name); return 1; } -static int -tolua_region_set_terrain(lua_State* L) +static int tolua_region_set_terrain(lua_State * L) { - region* r = (region*) tolua_tousertype(L, 1, 0); - const char * tname = tolua_tostring(L, 2, 0); + region *r = (region *) tolua_tousertype(L, 1, 0); + + const char *tname = tolua_tostring(L, 2, 0); + if (tname) { - const terrain_type * terrain = get_terrain(tname); + const terrain_type *terrain = get_terrain(tname); + if (terrain) { terraform_region(r, terrain); } @@ -107,11 +111,12 @@ tolua_region_set_terrain(lua_State* L) return 0; } -static int -tolua_region_get_terrainname(lua_State* L) +static int tolua_region_get_terrainname(lua_State * L) { - region* self = (region*) tolua_tousertype(L, 1, 0); - attrib * a = a_find(self->attribs, &at_racename); + region *self = (region *) tolua_tousertype(L, 1, 0); + + attrib *a = a_find(self->attribs, &at_racename); + if (a) { tolua_pushstring(L, get_racename(a)); return 1; @@ -119,35 +124,38 @@ tolua_region_get_terrainname(lua_State* L) return 0; } -static int -tolua_region_set_owner(lua_State* L) +static int tolua_region_set_owner(lua_State * L) { - region* r = (region*) tolua_tousertype(L, 1, 0); - struct faction* f = (struct faction*) tolua_tousertype(L, 2, 0); + region *r = (region *) tolua_tousertype(L, 1, 0); + + struct faction *f = (struct faction *)tolua_tousertype(L, 2, 0); + if (r) { region_set_owner(r, f, turn); } return 0; } -static int -tolua_region_get_owner(lua_State* L) +static int tolua_region_get_owner(lua_State * L) { - region* r = (region*) tolua_tousertype(L, 1, 0); + region *r = (region *) tolua_tousertype(L, 1, 0); + if (r) { - struct faction * f = region_get_owner(r); + struct faction *f = region_get_owner(r); + tolua_pushusertype(L, f, TOLUA_CAST "faction"); return 1; } return 0; } -static int -tolua_region_set_terrainname(lua_State* L) +static int tolua_region_set_terrainname(lua_State * L) { - region* self = (region*) tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - if (name==NULL) { + region *self = (region *) tolua_tousertype(L, 1, 0); + + const char *name = tolua_tostring(L, 2, 0); + + if (name == NULL) { a_removeall(&self->attribs, &at_racename); } else { set_racename(&self->attribs, name); @@ -155,59 +163,68 @@ tolua_region_set_terrainname(lua_State* L) return 0; } -static int tolua_region_get_info(lua_State* L) +static int tolua_region_get_info(lua_State * L) { - region* self = (region*) tolua_tousertype(L, 1, 0); + region *self = (region *) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, region_getinfo(self)); return 1; } -static int tolua_region_set_info(lua_State* L) +static int tolua_region_set_info(lua_State * L) { - region* self = (region*)tolua_tousertype(L, 1, 0); + region *self = (region *) tolua_tousertype(L, 1, 0); + region_setinfo(self, tolua_tostring(L, 2, 0)); return 0; } -static int tolua_region_get_name(lua_State* L) +static int tolua_region_get_name(lua_State * L) { - region* self = (region*) tolua_tousertype(L, 1, 0); + region *self = (region *) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, region_getname(self)); return 1; } -static int tolua_region_set_name(lua_State* L) +static int tolua_region_set_name(lua_State * L) { - region* self = (region*)tolua_tousertype(L, 1, 0); + region *self = (region *) tolua_tousertype(L, 1, 0); + region_setname(self, tolua_tostring(L, 2, 0)); return 0; } -static int tolua_region_get_morale(lua_State* L) +static int tolua_region_get_morale(lua_State * L) { - region* r = (region*) tolua_tousertype(L, 1, 0); + region *r = (region *) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, region_get_morale(r)); return 1; } -static int tolua_region_set_morale(lua_State* L) +static int tolua_region_set_morale(lua_State * L) { - region* r = (region*)tolua_tousertype(L, 1, 0); + region *r = (region *) tolua_tousertype(L, 1, 0); + region_set_morale(r, (int)tolua_tonumber(L, 2, 0), turn); return 0; } -static int tolua_region_get_adj(lua_State* L) +static int tolua_region_get_adj(lua_State * L) { - region* r = (region*)tolua_tousertype(L, 1, 0); - region* rn[MAXDIRECTIONS]; + region *r = (region *) tolua_tousertype(L, 1, 0); + + region *rn[MAXDIRECTIONS]; + int d, idx; + get_neighbours(r, rn); lua_createtable(L, MAXDIRECTIONS, 0); - for (d=0,idx=0;d!=MAXDIRECTIONS;++d) { + for (d = 0, idx = 0; d != MAXDIRECTIONS; ++d) { if (rn[d]) { tolua_pushusertype(L, rn[d], TOLUA_CAST "region"); lua_rawseti(L, -2, ++idx); @@ -216,13 +233,16 @@ static int tolua_region_get_adj(lua_State* L) return 1; } -static int tolua_region_get_luxury(lua_State* L) +static int tolua_region_get_luxury(lua_State * L) { - region* r = (region*)tolua_tousertype(L, 1, 0); + region *r = (region *) tolua_tousertype(L, 1, 0); + if (r->land) { - const item_type * lux = r_luxury(r); + const item_type *lux = r_luxury(r); + if (lux) { - const char * name = lux->rtype->_name[0]; + const char *name = lux->rtype->_name[0]; + tolua_pushstring(L, name); return 1; } @@ -230,14 +250,18 @@ static int tolua_region_get_luxury(lua_State* L) return 0; } -static int tolua_region_set_luxury(lua_State* L) +static int tolua_region_set_luxury(lua_State * L) { - region* r = (region*)tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); + region *r = (region *) tolua_tousertype(L, 1, 0); + + const char *name = tolua_tostring(L, 2, 0); + if (r->land && name) { - const item_type * lux = r_luxury(r); - const item_type * itype = it_find(name); - if (lux && itype && lux!=itype) { + const item_type *lux = r_luxury(r); + + const item_type *itype = it_find(name); + + if (lux && itype && lux != itype) { r_setdemand(r, lux->rtype->ltype, 1); r_setdemand(r, itype->rtype->ltype, 0); } @@ -245,73 +269,87 @@ static int tolua_region_set_luxury(lua_State* L) return 0; } -static int tolua_region_set_herb(lua_State* L) +static int tolua_region_set_herb(lua_State * L) { - region* r = (region*)tolua_tousertype(L, 1, 0); + region *r = (region *) tolua_tousertype(L, 1, 0); + if (r->land) { - const char * name = tolua_tostring(L, 2, 0); - const item_type * itype = it_find(name); - if (itype && (itype->flags&ITF_HERB)) { + const char *name = tolua_tostring(L, 2, 0); + + const item_type *itype = it_find(name); + + if (itype && (itype->flags & ITF_HERB)) { r->land->herbtype = itype; } } return 0; } -static int tolua_region_get_herb(lua_State* L) +static int tolua_region_get_herb(lua_State * L) { - region* r = (region*)tolua_tousertype(L, 1, 0); + region *r = (region *) tolua_tousertype(L, 1, 0); + if (r->land && r->land->herbtype) { - const char * name = r->land->herbtype->rtype->_name[0]; + const char *name = r->land->herbtype->rtype->_name[0]; + tolua_pushstring(L, name); return 1; } return 0; } -static int tolua_region_get_next(lua_State* L) +static int tolua_region_get_next(lua_State * L) { - region* self = (region*)tolua_tousertype(L, 1, 0); - direction_t dir = (direction_t)tolua_tonumber(L, 2, 0); + region *self = (region *) tolua_tousertype(L, 1, 0); - if (dir>=0 && dir= 0 && dir < MAXDIRECTIONS) { + tolua_pushusertype(L, (void *)r_connect(self, dir), TOLUA_CAST "region"); return 1; } return 0; } -static int tolua_region_get_flag(lua_State* L) +static int tolua_region_get_flag(lua_State * L) { - region* self = (region*)tolua_tousertype(L, 1, 0); + region *self = (region *) tolua_tousertype(L, 1, 0); + int bit = (int)tolua_tonumber(L, 2, 0); - lua_pushboolean(L, (self->flags & (1<flags & (1 << bit))); return 1; } -static int tolua_region_set_flag(lua_State* L) +static int tolua_region_set_flag(lua_State * L) { - region* self = (region*)tolua_tousertype(L, 1, 0); + region *self = (region *) tolua_tousertype(L, 1, 0); + int bit = (int)tolua_tonumber(L, 2, 0); + int set = tolua_toboolean(L, 3, 1); - if (set) self->flags |= (1<flags &= ~(1<flags |= (1 << bit); + else + self->flags &= ~(1 << bit); return 0; } -static int -tolua_region_get_resourcelevel(lua_State* L) +static int tolua_region_get_resourcelevel(lua_State * L) { - region * r = (region *)tolua_tousertype(L, 1, 0); - const char * type = tolua_tostring(L, 2, 0); - const resource_type * rtype = rt_find(type); - if (rtype!=NULL) { - const rawmaterial * rm; - for (rm=r->resources;rm;rm=rm->next) { - if (rm->type->rtype==rtype) { - tolua_pushnumber(L, (lua_Number)rm->level); + region *r = (region *) tolua_tousertype(L, 1, 0); + + const char *type = tolua_tostring(L, 2, 0); + + const resource_type *rtype = rt_find(type); + + if (rtype != NULL) { + const rawmaterial *rm; + + for (rm = r->resources; rm; rm = rm->next) { + if (rm->type->rtype == rtype) { + tolua_pushnumber(L, (lua_Number) rm->level); return 1; } } @@ -320,88 +358,104 @@ tolua_region_get_resourcelevel(lua_State* L) } #define LUA_ASSERT(c, s) if (!(c)) { log_error(("%s(%d): %s\n", __FILE__, __LINE__, (s))); return 0; } -static int -tolua_region_get_resource(lua_State* L) +static int tolua_region_get_resource(lua_State * L) { - region * r; - const char * type; - const resource_type * rtype; + region *r; + + const char *type; + + const resource_type *rtype; + int result = 0; - r = (region *)tolua_tousertype(L, 1, 0); - LUA_ASSERT(r!=NULL, "invalid parameter"); + r = (region *) tolua_tousertype(L, 1, 0); + LUA_ASSERT(r != NULL, "invalid parameter"); type = tolua_tostring(L, 2, 0); - LUA_ASSERT(type!=NULL, "invalid parameter"); + LUA_ASSERT(type != NULL, "invalid parameter"); rtype = rt_find(type); if (!rtype) { - if (strcmp(type, "seed")==0) result = rtrees(r, 0); - if (strcmp(type, "sapling")==0) result = rtrees(r, 1); - if (strcmp(type, "tree")==0) result = rtrees(r, 2); - if (strcmp(type, "grave")==0) result = deathcount(r); - if (strcmp(type, "chaos")==0) result = chaoscount(r); + if (strcmp(type, "seed") == 0) + result = rtrees(r, 0); + if (strcmp(type, "sapling") == 0) + result = rtrees(r, 1); + if (strcmp(type, "tree") == 0) + result = rtrees(r, 2); + if (strcmp(type, "grave") == 0) + result = deathcount(r); + if (strcmp(type, "chaos") == 0) + result = chaoscount(r); } else { result = region_getresource(r, rtype); } - tolua_pushnumber(L, (lua_Number)result); + tolua_pushnumber(L, (lua_Number) result); return 1; } -static int -tolua_region_set_resource(lua_State* L) +static int tolua_region_set_resource(lua_State * L) { - region * r = (region *)tolua_tousertype(L, 1, 0); - const char * type = tolua_tostring(L, 2, 0); - int value = (int)tolua_tonumber(L, 3, 0); - const resource_type * rtype = rt_find(type); + region *r = (region *) tolua_tousertype(L, 1, 0); - if (rtype!=NULL) { + const char *type = tolua_tostring(L, 2, 0); + + int value = (int)tolua_tonumber(L, 3, 0); + + const resource_type *rtype = rt_find(type); + + if (rtype != NULL) { region_setresource(r, rtype, value); } else { - if (strcmp(type, "seed")==0) { + if (strcmp(type, "seed") == 0) { rsettrees(r, 0, value); - } else if (strcmp(type, "sapling")==0) { + } else if (strcmp(type, "sapling") == 0) { rsettrees(r, 1, value); - } else if (strcmp(type, "tree")==0) { + } else if (strcmp(type, "tree") == 0) { rsettrees(r, 2, value); - } else if (strcmp(type, "grave")==0) { - int fallen = value-deathcount(r); + } else if (strcmp(type, "grave") == 0) { + int fallen = value - deathcount(r); + deathcounts(r, fallen); - } else if (strcmp(type, "chaos")==0) { - int fallen = value-chaoscount(r); + } else if (strcmp(type, "chaos") == 0) { + int fallen = value - chaoscount(r); + chaoscounts(r, fallen); } } return 0; } -static int -tolua_region_get_objects(lua_State* L) +static int tolua_region_get_objects(lua_State * L) { - region * self = (region *)tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); + region *self = (region *) tolua_tousertype(L, 1, 0); + + tolua_pushusertype(L, (void *)&self->attribs, TOLUA_CAST "hashtable"); return 1; } -static int -tolua_region_destroy(lua_State* L) +static int tolua_region_destroy(lua_State * L) { - region * self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *) tolua_tousertype(L, 1, 0); + remove_region(®ions, self); return 0; } -static int -tolua_region_create(lua_State* L) +static int tolua_region_create(lua_State * L) { int x = (int)tolua_tonumber(L, 1, 0); + int y = (int)tolua_tonumber(L, 2, 0); - const char * tname = tolua_tostring(L, 3, 0); + + const char *tname = tolua_tostring(L, 3, 0); + if (tname) { - plane * pl = findplane(x, y); - const terrain_type * terrain = get_terrain(tname); - region * r, * result; + plane *pl = findplane(x, y); + + const terrain_type *terrain = get_terrain(tname); + + region *r, *result; + if (!terrain) { return 0; } @@ -409,10 +463,10 @@ tolua_region_create(lua_State* L) assert(!pnormalize(&x, &y, pl)); r = result = findregion(x, y); - if (terrain==NULL && r!=NULL && r->units!=NULL) { + if (terrain == NULL && r != NULL && r->units != NULL) { /* TODO: error message */ result = NULL; - } else if (r==NULL) { + } else if (r == NULL) { result = new_region(x, y, pl, 0); } if (result) { @@ -426,10 +480,11 @@ tolua_region_create(lua_State* L) return 0; } -static int tolua_region_get_units(lua_State* L) +static int tolua_region_get_units(lua_State * L) { - region * self = (region *)tolua_tousertype(L, 1, 0); - unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); + region *self = (region *) tolua_tousertype(L, 1, 0); + + unit **unit_ptr = (unit **) lua_newuserdata(L, sizeof(unit *)); luaL_getmetatable(L, "unit"); lua_setmetatable(L, -2); @@ -440,10 +495,12 @@ static int tolua_region_get_units(lua_State* L) return 1; } -static int tolua_region_get_buildings(lua_State* L) +static int tolua_region_get_buildings(lua_State * L) { - region * self = (region *)tolua_tousertype(L, 1, 0); - building ** building_ptr = (building**)lua_newuserdata(L, sizeof(building *)); + region *self = (region *) tolua_tousertype(L, 1, 0); + + building **building_ptr = + (building **) lua_newuserdata(L, sizeof(building *)); luaL_getmetatable(L, "building"); lua_setmetatable(L, -2); @@ -454,10 +511,11 @@ static int tolua_region_get_buildings(lua_State* L) return 1; } -static int tolua_region_get_ships(lua_State* L) +static int tolua_region_get_ships(lua_State * L) { - region * self = (region *)tolua_tousertype(L, 1, 0); - ship ** ship_ptr = (ship**)lua_newuserdata(L, sizeof(ship *)); + region *self = (region *) tolua_tousertype(L, 1, 0); + + ship **ship_ptr = (ship **) lua_newuserdata(L, sizeof(ship *)); luaL_getmetatable(L, "ship"); lua_setmetatable(L, -2); @@ -468,9 +526,9 @@ static int tolua_region_get_ships(lua_State* L) return 1; } -static int tolua_region_get_age(lua_State* L) +static int tolua_region_get_age(lua_State * L) { - region * self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *) tolua_tousertype(L, 1, 0); if (self) { lua_pushnumber(L, self->age); @@ -479,136 +537,158 @@ static int tolua_region_get_age(lua_State* L) return 0; } -static int -tolua_region_getkey(lua_State* L) +static int tolua_region_getkey(lua_State * L) { - region * self = (region *)tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); + region *self = (region *) tolua_tousertype(L, 1, 0); + + const char *name = tolua_tostring(L, 2, 0); int flag = atoi36(name); - attrib * a = find_key(self->attribs, flag); - lua_pushboolean(L, a!=NULL); + + attrib *a = find_key(self->attribs, flag); + + lua_pushboolean(L, a != NULL); return 1; } -static int -tolua_region_setkey(lua_State* L) +static int tolua_region_setkey(lua_State * L) { - region * self = (region *)tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); + region *self = (region *) tolua_tousertype(L, 1, 0); + + const char *name = tolua_tostring(L, 2, 0); + int value = tolua_toboolean(L, 3, 0); int flag = atoi36(name); - attrib * a = find_key(self->attribs, flag); - if (a==NULL && value) { + + attrib *a = find_key(self->attribs, flag); + + if (a == NULL && value) { add_key(&self->attribs, flag); - } else if (a!=NULL && !value) { + } else if (a != NULL && !value) { a_remove(&self->attribs, a); } return 0; } -static int -tolua_region_tostring(lua_State *L) +static int tolua_region_tostring(lua_State * L) { - region * self = (region *)tolua_tousertype(L, 1, 0); + region *self = (region *) tolua_tousertype(L, 1, 0); + lua_pushstring(L, regionname(self, NULL)); return 1; } -static int -tolua_plane_get(lua_State* L) +static int tolua_plane_get(lua_State * L) { int id = (int)tolua_tonumber(L, 1, 0); - plane * pl = getplanebyid(id); + + plane *pl = getplanebyid(id); tolua_pushusertype(L, pl, TOLUA_CAST "plane"); return 1; } -static int -tolua_plane_create(lua_State* L) +static int tolua_plane_create(lua_State * L) { int id = (int)tolua_tonumber(L, 1, 0); + int x = (int)tolua_tonumber(L, 2, 0); - int y = (int)tolua_tonumber(L, 3, 0); - int width = (int)tolua_tonumber(L, 4, 0); - int height = (int)tolua_tonumber(L, 5, 0); - const char * name = tolua_tostring(L, 6, 0); - plane * pl; - pl = create_new_plane(id, name, x, x+width-1, y, y+height-1, 0); + int y = (int)tolua_tonumber(L, 3, 0); + + int width = (int)tolua_tonumber(L, 4, 0); + + int height = (int)tolua_tonumber(L, 5, 0); + + const char *name = tolua_tostring(L, 6, 0); + + plane *pl; + + pl = create_new_plane(id, name, x, x + width - 1, y, y + height - 1, 0); tolua_pushusertype(L, pl, TOLUA_CAST "plane"); return 1; } -static int tolua_plane_get_name(lua_State* L) +static int tolua_plane_get_name(lua_State * L) { - plane* self = (plane*) tolua_tousertype(L, 1, 0); + plane *self = (plane *) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->name); return 1; } -static int tolua_plane_set_name(lua_State* L) +static int tolua_plane_set_name(lua_State * L) { - plane* self = (plane*)tolua_tousertype(L, 1, 0); - const char * str = tolua_tostring(L, 2, 0); + plane *self = (plane *) tolua_tousertype(L, 1, 0); + + const char *str = tolua_tostring(L, 2, 0); + free(self->name); - if (str) self->name = strdup(str); - else self->name = 0; + if (str) + self->name = strdup(str); + else + self->name = 0; return 0; } -static int -tolua_plane_get_id(lua_State* L) +static int tolua_plane_get_id(lua_State * L) { - plane * self = (plane *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->id); + plane *self = (plane *) tolua_tousertype(L, 1, 0); + + tolua_pushnumber(L, (lua_Number) self->id); return 1; } -static int -tolua_plane_normalize(lua_State* L) +static int tolua_plane_normalize(lua_State * L) { - plane * self = (plane *)tolua_tousertype(L, 1, 0); + plane *self = (plane *) tolua_tousertype(L, 1, 0); + int x = (int)tolua_tonumber(L, 2, 0); + int y = (int)tolua_tonumber(L, 3, 0); + pnormalize(&x, &y, self); - tolua_pushnumber(L, (lua_Number)x); - tolua_pushnumber(L, (lua_Number)y); + tolua_pushnumber(L, (lua_Number) x); + tolua_pushnumber(L, (lua_Number) y); return 2; } -static int -tolua_plane_tostring(lua_State *L) +static int tolua_plane_tostring(lua_State * L) { - plane * self = (plane *)tolua_tousertype(L, 1, 0); + plane *self = (plane *) tolua_tousertype(L, 1, 0); + lua_pushstring(L, self->name); return 1; } -static int -tolua_plane_get_size(lua_State *L) +static int tolua_plane_get_size(lua_State * L) { - plane * pl = (plane *)tolua_tousertype(L, 1, 0); + plane *pl = (plane *) tolua_tousertype(L, 1, 0); + lua_pushnumber(L, plane_width(pl)); lua_pushnumber(L, plane_height(pl)); return 2; } -static int -tolua_distance(lua_State *L) +static int tolua_distance(lua_State * L) { int x1 = (int)tolua_tonumber(L, 1, 0); + int y1 = (int)tolua_tonumber(L, 2, 0); + int x2 = (int)tolua_tonumber(L, 3, 0); + int y2 = (int)tolua_tonumber(L, 4, 0); - plane * pl = (plane *)tolua_tousertype(L, 5, 0); + + plane *pl = (plane *) tolua_tousertype(L, 5, 0); + int result; - - if (!pl) pl = get_homeplane(); + + if (!pl) + pl = get_homeplane(); pnormalize(&x1, &y1, pl); pnormalize(&x2, &y2, pl); result = koor_distance(x1, y1, x2, y2); @@ -616,8 +696,7 @@ tolua_distance(lua_State *L) return 1; } -void -tolua_region_open(lua_State* L) +void tolua_region_open(lua_State * L) { /* register user types */ tolua_usertype(L, TOLUA_CAST "region"); @@ -628,7 +707,8 @@ tolua_region_open(lua_State* L) { tolua_function(L, TOLUA_CAST "distance", tolua_distance); - tolua_cclass(L, TOLUA_CAST "region", TOLUA_CAST "region", TOLUA_CAST "", NULL); + tolua_cclass(L, TOLUA_CAST "region", TOLUA_CAST "region", TOLUA_CAST "", + NULL); tolua_beginmodule(L, TOLUA_CAST "region"); { tolua_function(L, TOLUA_CAST "create", tolua_region_create); @@ -639,15 +719,21 @@ tolua_region_open(lua_State* L) tolua_variable(L, TOLUA_CAST "x", tolua_region_get_x, NULL); tolua_variable(L, TOLUA_CAST "y", tolua_region_get_y, NULL); tolua_variable(L, TOLUA_CAST "plane", tolua_region_get_plane, NULL); - tolua_variable(L, TOLUA_CAST "name", tolua_region_get_name, tolua_region_set_name); - tolua_variable(L, TOLUA_CAST "morale", tolua_region_get_morale, tolua_region_set_morale); - tolua_variable(L, TOLUA_CAST "info", tolua_region_get_info, tolua_region_set_info); + tolua_variable(L, TOLUA_CAST "name", tolua_region_get_name, + tolua_region_set_name); + tolua_variable(L, TOLUA_CAST "morale", tolua_region_get_morale, + tolua_region_set_morale); + tolua_variable(L, TOLUA_CAST "info", tolua_region_get_info, + tolua_region_set_info); tolua_variable(L, TOLUA_CAST "units", tolua_region_get_units, NULL); tolua_variable(L, TOLUA_CAST "ships", tolua_region_get_ships, NULL); tolua_variable(L, TOLUA_CAST "age", tolua_region_get_age, NULL); - tolua_variable(L, TOLUA_CAST "buildings", tolua_region_get_buildings, NULL); - tolua_variable(L, TOLUA_CAST "terrain", tolua_region_get_terrain, tolua_region_set_terrain); - tolua_function(L, TOLUA_CAST "get_resourcelevel", tolua_region_get_resourcelevel); + tolua_variable(L, TOLUA_CAST "buildings", tolua_region_get_buildings, + NULL); + tolua_variable(L, TOLUA_CAST "terrain", tolua_region_get_terrain, + tolua_region_set_terrain); + tolua_function(L, TOLUA_CAST "get_resourcelevel", + tolua_region_get_resourcelevel); tolua_function(L, TOLUA_CAST "get_resource", tolua_region_get_resource); tolua_function(L, TOLUA_CAST "set_resource", tolua_region_set_resource); tolua_function(L, TOLUA_CAST "get_flag", tolua_region_get_flag); @@ -655,30 +741,35 @@ tolua_region_open(lua_State* L) tolua_function(L, TOLUA_CAST "next", tolua_region_get_next); tolua_variable(L, TOLUA_CAST "adj", tolua_region_get_adj, NULL); - tolua_variable(L, TOLUA_CAST "luxury", &tolua_region_get_luxury, &tolua_region_set_luxury); - tolua_variable(L, TOLUA_CAST "herb", &tolua_region_get_herb, &tolua_region_set_herb); + tolua_variable(L, TOLUA_CAST "luxury", &tolua_region_get_luxury, + &tolua_region_set_luxury); + tolua_variable(L, TOLUA_CAST "herb", &tolua_region_get_herb, + &tolua_region_set_herb); - tolua_variable(L, TOLUA_CAST "terrain_name", &tolua_region_get_terrainname, &tolua_region_set_terrainname); - tolua_variable(L, TOLUA_CAST "owner", &tolua_region_get_owner, &tolua_region_set_owner); + tolua_variable(L, TOLUA_CAST "terrain_name", + &tolua_region_get_terrainname, &tolua_region_set_terrainname); + tolua_variable(L, TOLUA_CAST "owner", &tolua_region_get_owner, + &tolua_region_set_owner); tolua_function(L, TOLUA_CAST "get_key", tolua_region_getkey); tolua_function(L, TOLUA_CAST "set_key", tolua_region_setkey); #if 0 .def("add_notice", ®ion_addnotice) - .def("add_direction", ®ion_adddirection) - .def("move", ®ion_move) - .def("get_road", ®ion_getroad) - .def("set_road", ®ion_setroad) - .def("next", ®ion_next) - .def("add_item", ®ion_additem) - .property("items", ®ion_items, return_stl_iterator) - .property("plane_id", ®ion_plane) + .def("add_direction", ®ion_adddirection) + .def("move", ®ion_move) + .def("get_road", ®ion_getroad) + .def("set_road", ®ion_setroad) + .def("next", ®ion_next) + .def("add_item", ®ion_additem) + .property("items", ®ion_items, return_stl_iterator) + .property("plane_id", ®ion_plane) #endif - tolua_variable(L, TOLUA_CAST "objects", tolua_region_get_objects, 0); + tolua_variable(L, TOLUA_CAST "objects", tolua_region_get_objects, 0); } tolua_endmodule(L); - tolua_cclass(L, TOLUA_CAST "plane", TOLUA_CAST "plane", TOLUA_CAST "", NULL); + tolua_cclass(L, TOLUA_CAST "plane", TOLUA_CAST "plane", TOLUA_CAST "", + NULL); tolua_beginmodule(L, TOLUA_CAST "plane"); { tolua_function(L, TOLUA_CAST "create", tolua_plane_create); @@ -688,7 +779,8 @@ tolua_region_open(lua_State* L) tolua_function(L, TOLUA_CAST "size", tolua_plane_get_size); tolua_variable(L, TOLUA_CAST "id", tolua_plane_get_id, NULL); tolua_function(L, TOLUA_CAST "normalize", tolua_plane_normalize); - tolua_variable(L, TOLUA_CAST "name", tolua_plane_get_name, tolua_plane_set_name); + tolua_variable(L, TOLUA_CAST "name", tolua_plane_get_name, + tolua_plane_set_name); } tolua_endmodule(L); } diff --git a/src/bindings/bind_ship.c b/src/bindings/bind_ship.c index 2162b9933..d8f216c7c 100644 --- a/src/bindings/bind_ship.c +++ b/src/bindings/bind_ship.c @@ -25,36 +25,40 @@ without prior permission by the authors of Eressea. #include #include -int tolua_shiplist_next(lua_State *L) +int tolua_shiplist_next(lua_State * L) { - ship** ship_ptr = (ship **)lua_touserdata(L, lua_upvalueindex(1)); - ship * u = *ship_ptr; + ship **ship_ptr = (ship **) lua_touserdata(L, lua_upvalueindex(1)); + + ship *u = *ship_ptr; + if (u != NULL) { - tolua_pushusertype(L, (void*)u, TOLUA_CAST "ship"); + tolua_pushusertype(L, (void *)u, TOLUA_CAST "ship"); *ship_ptr = u->next; return 1; - } - else return 0; /* no more values to return */ + } else + return 0; /* no more values to return */ } -static int -tolua_ship_get_id(lua_State* L) +static int tolua_ship_get_id(lua_State * L) { - ship * self = (ship *)tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->no); + ship *self = (ship *) tolua_tousertype(L, 1, 0); + + tolua_pushnumber(L, (lua_Number) self->no); return 1; } -static int tolua_ship_get_name(lua_State* L) +static int tolua_ship_get_name(lua_State * L) { - ship* self = (ship*) tolua_tousertype(L, 1, 0); + ship *self = (ship *) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, ship_getname(self)); return 1; } -static int tolua_ship_get_region(lua_State* L) +static int tolua_ship_get_region(lua_State * L) { - ship* self = (ship*) tolua_tousertype(L, 1, 0); + ship *self = (ship *) tolua_tousertype(L, 1, 0); + if (self) { tolua_pushusertype(L, self->region, TOLUA_CAST "region"); return 1; @@ -62,31 +66,36 @@ static int tolua_ship_get_region(lua_State* L) return 0; } -static int tolua_ship_set_region(lua_State* L) +static int tolua_ship_set_region(lua_State * L) { - ship* self = (ship*) tolua_tousertype(L, 1, 0); - region * r = (region*) tolua_tousertype(L, 1, 0); + ship *self = (ship *) tolua_tousertype(L, 1, 0); + + region *r = (region *) tolua_tousertype(L, 1, 0); + if (self) { move_ship(self, self->region, r, NULL); } return 0; } -static int tolua_ship_set_name(lua_State* L) +static int tolua_ship_set_name(lua_State * L) { - ship* self = (ship*)tolua_tousertype(L, 1, 0); + ship *self = (ship *) tolua_tousertype(L, 1, 0); + ship_setname(self, tolua_tostring(L, 2, 0)); return 0; } -static int -tolua_ship_get_units(lua_State* L) +static int tolua_ship_get_units(lua_State * L) { - ship * self = (ship *)tolua_tousertype(L, 1, 0); - unit ** unit_ptr = (unit**)lua_newuserdata(L, sizeof(unit *)); - unit * u = self->region->units; + ship *self = (ship *) tolua_tousertype(L, 1, 0); - while (u && u->ship!=self) u = u->next; + unit **unit_ptr = (unit **) lua_newuserdata(L, sizeof(unit *)); + + unit *u = self->region->units; + + while (u && u->ship != self) + u = u->next; luaL_getmetatable(L, TOLUA_CAST "unit"); lua_setmetatable(L, -2); @@ -96,25 +105,28 @@ tolua_ship_get_units(lua_State* L) return 1; } -static int -tolua_ship_get_objects(lua_State* L) +static int tolua_ship_get_objects(lua_State * L) { - ship * self = (ship *)tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); + ship *self = (ship *) tolua_tousertype(L, 1, 0); + + tolua_pushusertype(L, (void *)&self->attribs, TOLUA_CAST "hashtable"); return 1; } -static int -tolua_ship_create(lua_State* L) +static int tolua_ship_create(lua_State * L) { - region * r = (region *)tolua_tousertype(L, 1, 0); - const char * sname = tolua_tostring(L, 2, 0); + region *r = (region *) tolua_tousertype(L, 1, 0); + + const char *sname = tolua_tostring(L, 2, 0); + if (sname) { - const ship_type * stype = st_find(sname); + const ship_type *stype = st_find(sname); + if (stype) { - ship * sh = new_ship(stype, default_locale, r); + ship *sh = new_ship(stype, default_locale, r); + sh->size = stype->construction->maxsize; - tolua_pushusertype(L, (void*)sh, TOLUA_CAST "ship"); + tolua_pushusertype(L, (void *)sh, TOLUA_CAST "ship"); return 1; } } @@ -122,42 +134,46 @@ tolua_ship_create(lua_State* L) } static int - -tolua_ship_tostring(lua_State *L) + tolua_ship_tostring(lua_State * L) { - ship * self = (ship *)tolua_tousertype(L, 1, 0); + ship *self = (ship *) tolua_tousertype(L, 1, 0); + lua_pushstring(L, shipname(self)); return 1; } -static int tolua_ship_get_flags(lua_State* L) +static int tolua_ship_get_flags(lua_State * L) { - ship* self = (ship*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->flags); + ship *self = (ship *) tolua_tousertype(L, 1, 0); + + tolua_pushnumber(L, (lua_Number) self->flags); return 1; } -static int tolua_ship_set_flags(lua_State* L) +static int tolua_ship_set_flags(lua_State * L) { - ship* self = (ship*)tolua_tousertype(L, 1, 0); + ship *self = (ship *) tolua_tousertype(L, 1, 0); + self->flags = (int)tolua_tonumber(L, 2, 0); return 0; } -static int tolua_ship_set_coast(lua_State* L) +static int tolua_ship_set_coast(lua_State * L) { - ship* self = (ship*)tolua_tousertype(L, 1, 0); + ship *self = (ship *) tolua_tousertype(L, 1, 0); + if (lua_isnil(L, 2)) { self->coast = NODIRECTION; } else if (lua_isnumber(L, 2)) { - self->coast = (direction_t)tolua_tonumber(L, 2, 0); + self->coast = (direction_t) tolua_tonumber(L, 2, 0); } return 0; } -static int tolua_ship_get_coast(lua_State* L) +static int tolua_ship_get_coast(lua_State * L) { - ship* self = (ship*)tolua_tousertype(L, 1, 0); + ship *self = (ship *) tolua_tousertype(L, 1, 0); + if (self->coast) { tolua_pushnumber(L, self->coast); return 1; @@ -166,8 +182,7 @@ static int tolua_ship_get_coast(lua_State* L) } -void -tolua_ship_open(lua_State* L) +void tolua_ship_open(lua_State * L) { /* register user types */ tolua_usertype(L, TOLUA_CAST "ship"); @@ -180,21 +195,25 @@ tolua_ship_open(lua_State* L) { tolua_function(L, TOLUA_CAST "__tostring", tolua_ship_tostring); tolua_variable(L, TOLUA_CAST "id", tolua_ship_get_id, NULL); - tolua_variable(L, TOLUA_CAST "name", tolua_ship_get_name, tolua_ship_set_name); + tolua_variable(L, TOLUA_CAST "name", tolua_ship_get_name, + tolua_ship_set_name); tolua_variable(L, TOLUA_CAST "units", tolua_ship_get_units, NULL); - tolua_variable(L, TOLUA_CAST "flags", &tolua_ship_get_flags, tolua_ship_set_flags); - tolua_variable(L, TOLUA_CAST "region", tolua_ship_get_region, tolua_ship_set_region); - tolua_variable(L, TOLUA_CAST "coast", tolua_ship_get_coast, tolua_ship_set_coast); + tolua_variable(L, TOLUA_CAST "flags", &tolua_ship_get_flags, + tolua_ship_set_flags); + tolua_variable(L, TOLUA_CAST "region", tolua_ship_get_region, + tolua_ship_set_region); + tolua_variable(L, TOLUA_CAST "coast", tolua_ship_get_coast, + tolua_ship_set_coast); #ifdef TODO .property("type", &ship_gettype) - .property("weight", &ship_getweight) - .property("capacity", &ship_getcapacity) - .property("maxsize", &ship_maxsize) - .def_readwrite("damage", &ship::damage) - .def_readwrite("size", &ship::size) - .def_readwrite("coast", &ship::coast) + .property("weight", &ship_getweight) + .property("capacity", &ship_getcapacity) + .property("maxsize", &ship_maxsize) + .def_readwrite("damage", &ship::damage) + .def_readwrite("size", &ship::size) + .def_readwrite("coast", &ship::coast) #endif - tolua_variable(L, TOLUA_CAST "objects", tolua_ship_get_objects, 0); + tolua_variable(L, TOLUA_CAST "objects", tolua_ship_get_objects, 0); tolua_function(L, TOLUA_CAST "create", tolua_ship_create); } diff --git a/src/bindings/bind_sqlite.c b/src/bindings/bind_sqlite.c index ce7f1aed4..63a10914c 100644 --- a/src/bindings/bind_sqlite.c +++ b/src/bindings/bind_sqlite.c @@ -22,58 +22,61 @@ without prior permission by the authors of Eressea. #define LTYPE_DB TOLUA_CAST "db" extern int db_update_factions(sqlite3 * db, boolean force); -static int -tolua_db_update_factions(lua_State* L) -{ - sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); + +static int tolua_db_update_factions(lua_State * L) +{ + sqlite3 *db = (sqlite3 *) tolua_tousertype(L, 1, 0); + db_update_factions(db, tolua_toboolean(L, 2, 0)); return 0; } extern int db_update_scores(sqlite3 * db, boolean force); -static int -tolua_db_update_scores(lua_State* L) -{ - sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); + +static int tolua_db_update_scores(lua_State * L) +{ + sqlite3 *db = (sqlite3 *) tolua_tousertype(L, 1, 0); + db_update_scores(db, tolua_toboolean(L, 2, 0)); return 0; } -static int -tolua_db_execute(lua_State* L) -{ - sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); - const char * sql = tolua_tostring(L, 2, 0); +static int tolua_db_execute(lua_State * L) +{ + sqlite3 *db = (sqlite3 *) tolua_tousertype(L, 1, 0); + + const char *sql = tolua_tostring(L, 2, 0); int res = sqlite3_exec(db, sql, 0, 0, 0); - tolua_pushnumber(L, (LUA_NUMBER)res); + tolua_pushnumber(L, (LUA_NUMBER) res); return 1; } -static int -tolua_db_close(lua_State* L) -{ - sqlite3 * db = (sqlite3 *)tolua_tousertype(L, 1, 0); +static int tolua_db_close(lua_State * L) +{ + sqlite3 *db = (sqlite3 *) tolua_tousertype(L, 1, 0); + sqlite3_close(db); return 0; } -static int -tolua_db_create(lua_State* L) -{ - sqlite3 * db; - const char * dbname = tolua_tostring(L, 1, 0); +static int tolua_db_create(lua_State * L) +{ + sqlite3 *db; + + const char *dbname = tolua_tostring(L, 1, 0); + int result = sqlite3_open_v2(dbname, &db, SQLITE_OPEN_READWRITE, 0); - if (result==SQLITE_OK) { - tolua_pushusertype(L, (void*)db, LTYPE_DB); + + if (result == SQLITE_OK) { + tolua_pushusertype(L, (void *)db, LTYPE_DB); return 1; } return 0; } -int -tolua_sqlite_open(lua_State * L) +int tolua_sqlite_open(lua_State * L) { /* register user types */ @@ -88,7 +91,8 @@ tolua_sqlite_open(lua_State * L) tolua_function(L, TOLUA_CAST "open", &tolua_db_create); tolua_function(L, TOLUA_CAST "close", &tolua_db_close); - tolua_function(L, TOLUA_CAST "update_factions", &tolua_db_update_factions); + tolua_function(L, TOLUA_CAST "update_factions", + &tolua_db_update_factions); tolua_function(L, TOLUA_CAST "update_scores", &tolua_db_update_scores); tolua_function(L, TOLUA_CAST "execute", &tolua_db_execute); } diff --git a/src/bindings/bind_storage.c b/src/bindings/bind_storage.c index a8914a5cb..32f581956 100644 --- a/src/bindings/bind_storage.c +++ b/src/bindings/bind_storage.c @@ -25,13 +25,16 @@ without prior permission by the authors of Eressea. #include -static int -tolua_storage_create(lua_State* L) +static int tolua_storage_create(lua_State * L) { - const char * filename = tolua_tostring(L, 1, 0); - const char * type = tolua_tostring(L, 2, "rb"); - storage * store = 0; + const char *filename = tolua_tostring(L, 1, 0); + + const char *type = tolua_tostring(L, 2, "rb"); + + storage *store = 0; + int mode = IO_READ; + if (strchr(type, 't')) { store = malloc(sizeof(text_store)); memcpy(store, &text_store, sizeof(text_store)); @@ -39,27 +42,31 @@ tolua_storage_create(lua_State* L) store = malloc(sizeof(binary_store)); memcpy(store, &binary_store, sizeof(binary_store)); } - if (strchr(type, 'r')) mode = IO_READ; - if (strchr(type, 'w')) mode = IO_WRITE; + if (strchr(type, 'r')) + mode = IO_READ; + if (strchr(type, 'w')) + mode = IO_WRITE; store->open(store, filename, mode); - tolua_pushusertype(L, (void*)store, TOLUA_CAST "storage"); + tolua_pushusertype(L, (void *)store, TOLUA_CAST "storage"); return 1; } -static int -tolua_storage_read_unit(lua_State *L) +static int tolua_storage_read_unit(lua_State * L) { - storage * self = (storage *)tolua_tousertype(L, 1, 0); - struct unit * u = read_unit(self); - tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); + storage *self = (storage *) tolua_tousertype(L, 1, 0); + + struct unit *u = read_unit(self); + + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); return 1; } -static int -tolua_storage_write_unit(lua_State *L) +static int tolua_storage_write_unit(lua_State * L) { - storage * store = (storage *)tolua_tousertype(L, 1, 0); - struct unit * u = (struct unit *)tolua_tousertype(L, 2, 0); + storage *store = (storage *) tolua_tousertype(L, 1, 0); + + struct unit *u = (struct unit *)tolua_tousertype(L, 2, 0); + if (store->version) { write_unit(store, u); } @@ -67,32 +74,36 @@ tolua_storage_write_unit(lua_State *L) } -static int -tolua_storage_read_float(lua_State *L) +static int tolua_storage_read_float(lua_State * L) { - storage * self = (storage *)tolua_tousertype(L, 1, 0); + storage *self = (storage *) tolua_tousertype(L, 1, 0); + float num = self->r_flt(self); - tolua_pushnumber(L, (lua_Number)num); + + tolua_pushnumber(L, (lua_Number) num); return 1; } -static int -tolua_storage_read_int(lua_State *L) +static int tolua_storage_read_int(lua_State * L) { - storage * self = (storage *)tolua_tousertype(L, 1, 0); + storage *self = (storage *) tolua_tousertype(L, 1, 0); + int num = self->r_int(self); - tolua_pushnumber(L, (lua_Number)num); + + tolua_pushnumber(L, (lua_Number) num); return 1; } -static int -tolua_storage_write(lua_State *L) +static int tolua_storage_write(lua_State * L) { - storage * self = (storage *)tolua_tousertype(L, 1, 0); + storage *self = (storage *) tolua_tousertype(L, 1, 0); + if (self->version && tolua_isnumber(L, 2, 0, 0)) { lua_Number num = tolua_tonumber(L, 2, 0); + double n; - if (modf(num, &n)==0.0) { + + if (modf(num, &n) == 0.0) { self->w_int(self, (int)num); } else { self->w_flt(self, (float)num); @@ -101,26 +112,27 @@ tolua_storage_write(lua_State *L) return 0; } -static int -tolua_storage_tostring(lua_State *L) +static int tolua_storage_tostring(lua_State * L) { - storage * self = (storage *)tolua_tousertype(L, 1, 0); + storage *self = (storage *) tolua_tousertype(L, 1, 0); + char name[64]; - snprintf(name, sizeof(name), "", self->encoding, self->version); + + snprintf(name, sizeof(name), "", self->encoding, + self->version); lua_pushstring(L, name); return 1; } -static int -tolua_storage_close(lua_State *L) +static int tolua_storage_close(lua_State * L) { - storage * self = (storage *)tolua_tousertype(L, 1, 0); + storage *self = (storage *) tolua_tousertype(L, 1, 0); + self->close(self); return 0; } -void -tolua_storage_open(lua_State* L) +void tolua_storage_open(lua_State * L) { /* register user types */ tolua_usertype(L, TOLUA_CAST "storage"); @@ -128,7 +140,8 @@ tolua_storage_open(lua_State* L) tolua_module(L, NULL, 0); tolua_beginmodule(L, NULL); { - tolua_cclass(L, TOLUA_CAST "storage", TOLUA_CAST "storage", TOLUA_CAST "", NULL); + tolua_cclass(L, TOLUA_CAST "storage", TOLUA_CAST "storage", TOLUA_CAST "", + NULL); tolua_beginmodule(L, TOLUA_CAST "storage"); { tolua_function(L, TOLUA_CAST "__tostring", tolua_storage_tostring); diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 80a264fca..fc6a25f8c 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -52,21 +52,22 @@ without prior permission by the authors of Eressea. #include #include -static int -tolua_unit_get_objects(lua_State* L) +static int tolua_unit_get_objects(lua_State * L) { - unit * self = (unit *)tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void*)&self->attribs, TOLUA_CAST "hashtable"); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + tolua_pushusertype(L, (void *)&self->attribs, TOLUA_CAST "hashtable"); return 1; } -static int -tolua_unit_get_attribs(lua_State* L) +static int tolua_unit_get_attribs(lua_State * L) { - unit * self = (unit *)tolua_tousertype(L, 1, 0); - attrib ** attrib_ptr = (attrib**)lua_newuserdata(L, sizeof(attrib *)); - attrib * a = tolua_get_lua_ext(self->attribs); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + attrib **attrib_ptr = (attrib **) lua_newuserdata(L, sizeof(attrib *)); + + attrib *a = tolua_get_lua_ext(self->attribs); luaL_getmetatable(L, "attrib"); lua_setmetatable(L, -2); @@ -77,142 +78,164 @@ tolua_unit_get_attribs(lua_State* L) return 1; } -int tolua_unitlist_nextf(lua_State *L) +int tolua_unitlist_nextf(lua_State * L) { - unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); - unit * u = *unit_ptr; + unit **unit_ptr = (unit **) lua_touserdata(L, lua_upvalueindex(1)); + + unit *u = *unit_ptr; + if (u != NULL) { - tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); *unit_ptr = u->nextF; return 1; - } - else return 0; /* no more values to return */ + } else + return 0; /* no more values to return */ } -int tolua_unitlist_nextb(lua_State *L) +int tolua_unitlist_nextb(lua_State * L) { - unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); - unit * u = *unit_ptr; - if (u != NULL) { - unit * unext = u->next; - tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); + unit **unit_ptr = (unit **) lua_touserdata(L, lua_upvalueindex(1)); - while (unext && unext->building!=u->building) { + unit *u = *unit_ptr; + + if (u != NULL) { + unit *unext = u->next; + + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); + + while (unext && unext->building != u->building) { unext = unext->next; } *unit_ptr = unext; return 1; - } - else return 0; /* no more values to return */ + } else + return 0; /* no more values to return */ } -int tolua_unitlist_nexts(lua_State *L) +int tolua_unitlist_nexts(lua_State * L) { - unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); - unit * u = *unit_ptr; - if (u != NULL) { - unit * unext = u->next; - tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); + unit **unit_ptr = (unit **) lua_touserdata(L, lua_upvalueindex(1)); - while (unext && unext->ship!=u->ship) { + unit *u = *unit_ptr; + + if (u != NULL) { + unit *unext = u->next; + + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); + + while (unext && unext->ship != u->ship) { unext = unext->next; } *unit_ptr = unext; return 1; - } - else return 0; /* no more values to return */ + } else + return 0; /* no more values to return */ } -int tolua_unitlist_next(lua_State *L) +int tolua_unitlist_next(lua_State * L) { - unit** unit_ptr = (unit **)lua_touserdata(L, lua_upvalueindex(1)); - unit * u = *unit_ptr; + unit **unit_ptr = (unit **) lua_touserdata(L, lua_upvalueindex(1)); + + unit *u = *unit_ptr; + if (u != NULL) { - tolua_pushusertype(L, (void*)u, TOLUA_CAST "unit"); + tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); *unit_ptr = u->next; return 1; - } - else return 0; /* no more values to return */ + } else + return 0; /* no more values to return */ } -static int tolua_unit_get_name(lua_State* L) +static int tolua_unit_get_name(lua_State * L) { - unit* self = (unit*) tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->name); return 1; } -static int tolua_unit_set_name(lua_State* L) +static int tolua_unit_set_name(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + unit_setname(self, tolua_tostring(L, 2, 0)); return 0; } -static int tolua_unit_get_info(lua_State* L) +static int tolua_unit_get_info(lua_State * L) { - unit* self = (unit*) tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, unit_getinfo(self)); return 1; } -static int tolua_unit_set_info(lua_State* L) +static int tolua_unit_set_info(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + unit_setinfo(self, tolua_tostring(L, 2, 0)); return 0; } -static int tolua_unit_get_id(lua_State* L) +static int tolua_unit_get_id(lua_State * L) { - unit* self = (unit*) tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + lua_pushinteger(L, unit_getid(self)); return 1; } -static int tolua_unit_set_id(lua_State* L) +static int tolua_unit_set_id(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + unit_setid(self, (int)tolua_tonumber(L, 2, 0)); return 0; } -static int tolua_unit_get_hpmax(lua_State* L) +static int tolua_unit_get_hpmax(lua_State * L) { - unit* self = (unit*) tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + lua_pushinteger(L, unit_max_hp(self)); return 1; } -static int tolua_unit_get_hp(lua_State* L) +static int tolua_unit_get_hp(lua_State * L) { - unit* self = (unit*) tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + lua_pushinteger(L, unit_gethp(self)); return 1; } -static int tolua_unit_set_hp(lua_State* L) +static int tolua_unit_set_hp(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + unit_sethp(self, (int)tolua_tonumber(L, 2, 0)); return 0; } -static int tolua_unit_get_number(lua_State* L) +static int tolua_unit_get_number(lua_State * L) { - unit* self = (unit*) tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + lua_pushinteger(L, self->number); return 1; } -static int tolua_unit_set_number(lua_State* L) +static int tolua_unit_set_number(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + int number = (int)tolua_tonumber(L, 2, 0); - if (self->number==0) { + + if (self->number == 0) { set_number(self, number); self->hp = unit_max_hp(self) * number; } else { @@ -221,108 +244,124 @@ static int tolua_unit_set_number(lua_State* L) return 0; } -static int tolua_unit_get_flags(lua_State* L) +static int tolua_unit_get_flags(lua_State * L) { - unit* self = (unit*) tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + lua_pushinteger(L, self->flags); return 1; } -static int tolua_unit_set_flags(lua_State* L) +static int tolua_unit_set_flags(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + self->flags = (int)tolua_tonumber(L, 2, 0); return 0; } -static const char * -unit_getmagic(const unit * u) +static const char *unit_getmagic(const unit * u) { - sc_mage * mage = get_mage(u); - return mage?magic_school[mage->magietyp]:NULL; + sc_mage *mage = get_mage(u); + + return mage ? magic_school[mage->magietyp] : NULL; } -static int tolua_unit_get_magic(lua_State* L) +static int tolua_unit_get_magic(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + lua_pushstring(L, unit_getmagic(self)); return 1; } -static void -unit_setmagic(unit * u, const char * type) +static void unit_setmagic(unit * u, const char *type) { - sc_mage * mage = get_mage(u); + sc_mage *mage = get_mage(u); + magic_t mtype; - for (mtype=0;mtype!=MAXMAGIETYP;++mtype) { - if (strcmp(magic_school[mtype], type)==0) break; + + for (mtype = 0; mtype != MAXMAGIETYP; ++mtype) { + if (strcmp(magic_school[mtype], type) == 0) + break; } - if (mtype==MAXMAGIETYP) return; - if (mage==NULL) { + if (mtype == MAXMAGIETYP) + return; + if (mage == NULL) { mage = create_mage(u, mtype); } } -static int tolua_unit_set_magic(lua_State* L) +static int tolua_unit_set_magic(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * type = tolua_tostring(L, 2, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + const char *type = tolua_tostring(L, 2, 0); + unit_setmagic(self, type); return 0; } -static int tolua_unit_get_aura(lua_State* L) +static int tolua_unit_get_aura(lua_State * L) { - unit* self = (unit*) tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + lua_pushinteger(L, get_spellpoints(self)); return 1; } -static int tolua_unit_set_aura(lua_State* L) +static int tolua_unit_set_aura(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + set_spellpoints(self, (int)tolua_tonumber(L, 2, 0)); return 0; } -static int tolua_unit_get_age(lua_State* L) +static int tolua_unit_get_age(lua_State * L) { - unit* self = (unit*) tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + lua_pushinteger(L, self->age); return 1; } -static int tolua_unit_set_age(lua_State* L) +static int tolua_unit_set_age(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + self->age = (short)tolua_tonumber(L, 2, 0); return 0; } -static int tolua_unit_get_status(lua_State* L) +static int tolua_unit_get_status(lua_State * L) { - unit* self = (unit*) tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + lua_pushinteger(L, unit_getstatus(self)); return 1; } -static int tolua_unit_set_status(lua_State* L) +static int tolua_unit_set_status(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); - unit_setstatus(self, (status_t)tolua_tonumber(L, 2, 0)); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + unit_setstatus(self, (status_t) tolua_tonumber(L, 2, 0)); return 0; } -static int -tolua_unit_get_item(lua_State* L) +static int tolua_unit_get_item(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * iname = tolua_tostring(L, 2, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + const char *iname = tolua_tostring(L, 2, 0); + int result = -1; - if (iname!=NULL) { - const item_type * itype = it_find(iname); - if (itype!=NULL) { + if (iname != NULL) { + const item_type *itype = it_find(iname); + + if (itype != NULL) { result = i_get(self->items, itype); } } @@ -330,79 +369,92 @@ tolua_unit_get_item(lua_State* L) return 1; } -static int -tolua_unit_add_item(lua_State* L) +static int tolua_unit_add_item(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * iname = tolua_tostring(L, 2, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + const char *iname = tolua_tostring(L, 2, 0); + int number = (int)tolua_tonumber(L, 3, 0); + int result = -1; - if (iname!=NULL) { - const item_type * itype = it_find(iname); - if (itype!=NULL) { - item * i = i_change(&self->items, itype, number); - result = i?i->number:0; + if (iname != NULL) { + const item_type *itype = it_find(iname); + + if (itype != NULL) { + item *i = i_change(&self->items, itype, number); + + result = i ? i->number : 0; } } lua_pushinteger(L, result); return 1; } -static int -tolua_unit_getskill(lua_State* L) +static int tolua_unit_getskill(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * skname = tolua_tostring(L, 2, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + const char *skname = tolua_tostring(L, 2, 0); + skill_t sk = sk_find(skname); + int value = -1; - if (sk!=NOSKILL) { - skill * sv = get_skill(self, sk); + + if (sk != NOSKILL) { + skill *sv = get_skill(self, sk); + if (sv) { value = sv->level; - } - else value = 0; + } else + value = 0; } lua_pushinteger(L, value); return 1; } -static int -tolua_unit_effskill(lua_State* L) +static int tolua_unit_effskill(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * skname = tolua_tostring(L, 2, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + const char *skname = tolua_tostring(L, 2, 0); + skill_t sk = sk_find(skname); - int value = (sk==NOSKILL)?-1:eff_skill(self, sk, self->region); + + int value = (sk == NOSKILL) ? -1 : eff_skill(self, sk, self->region); + lua_pushinteger(L, value); return 1; } typedef struct fctr_data { - unit * target; + unit *target; int fhandle; } fctr_data; typedef struct event { - struct event_arg * args; - char * msg; + struct event_arg *args; + char *msg; } event; -int -fctr_handle(struct trigger * tp, void * data) +int fctr_handle(struct trigger *tp, void *data) { - trigger * t = tp; + trigger *t = tp; event evt = { 0 }; - fctr_data * fd = (fctr_data*)t->data.v; - lua_State * L = (lua_State *)global.vm_state; - unit * u = fd->target; - - evt.args = (event_arg*)data; + fctr_data *fd = (fctr_data *) t->data.v; + + lua_State *L = (lua_State *) global.vm_state; + + unit *u = fd->target; + + evt.args = (event_arg *) data; lua_rawgeti(L, LUA_REGISTRYINDEX, fd->fhandle); tolua_pushusertype(L, u, TOLUA_CAST "unit"); tolua_pushusertype(L, &evt, TOLUA_CAST "event"); - if (lua_pcall(L, 2, 0, 0)!=0) { - const char* error = lua_tostring(L, -1); + if (lua_pcall(L, 2, 0, 0) != 0) { + const char *error = lua_tostring(L, -1); + log_error(("event (%s): %s\n", unitname(u), error)); lua_pop(L, 1); tolua_error(L, TOLUA_CAST "event handler call failed", NULL); @@ -411,17 +463,17 @@ fctr_handle(struct trigger * tp, void * data) return 0; } -static void -fctr_init(trigger * t) +static void fctr_init(trigger * t) { t->data.v = calloc(sizeof(fctr_data), 1); } -static void -fctr_done(trigger * t) +static void fctr_done(trigger * t) { - fctr_data * fd = (fctr_data*)t->data.v; - lua_State * L = (lua_State *)global.vm_state; + fctr_data *fd = (fctr_data *) t->data.v; + + lua_State *L = (lua_State *) global.vm_state; + luaL_unref(L, LUA_REGISTRYINDEX, fd->fhandle); free(fd); } @@ -433,21 +485,23 @@ static struct trigger_type tt_lua = { fctr_handle }; -static trigger * -trigger_lua(struct unit * u, int handle) +static trigger *trigger_lua(struct unit *u, int handle) { - trigger * t = t_new(&tt_lua); - fctr_data * td = (fctr_data*)t->data.v; + trigger *t = t_new(&tt_lua); + + fctr_data *td = (fctr_data *) t->data.v; + td->target = u; td->fhandle = handle; return t; } -static int -tolua_unit_addhandler(lua_State* L) +static int tolua_unit_addhandler(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * ename = tolua_tostring(L, 2, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + const char *ename = tolua_tostring(L, 2, 0); + int handle; lua_pushvalue(L, 3); @@ -457,26 +511,28 @@ tolua_unit_addhandler(lua_State* L) return 0; } -static int -tolua_unit_addnotice(lua_State* L) +static int tolua_unit_addnotice(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * str = tolua_tostring(L, 2, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + const char *str = tolua_tostring(L, 2, 0); addmessage(self->region, self->faction, str, MSG_MESSAGE, ML_IMPORTANT); return 0; } -static void -unit_castspell(unit * u, const char * name) +static void unit_castspell(unit * u, const char *name) { - quicklist * ql = spells; + quicklist *ql = spells; + int qi; - for (ql=spells,qi=0;ql;ql_advance(&ql, &qi, 1)) { - spell * sp = (spell *)ql_get(ql, qi); - if (strcmp(name, sp->sname)==0) { - castorder * co = (castorder*)malloc(sizeof(castorder)); + for (ql = spells, qi = 0; ql; ql_advance(&ql, &qi, 1)) { + spell *sp = (spell *) ql_get(ql, qi); + + if (strcmp(name, sp->sname) == 0) { + castorder *co = (castorder *) malloc(sizeof(castorder)); + co->distance = 0; co->familiar = NULL; co->force = sp->level; @@ -486,7 +542,7 @@ unit_castspell(unit * u, const char * name) co->par = NULL; co->rt = u->region; co->sp = sp; - if (sp->sp_function==NULL) { + if (sp->sp_function == NULL) { log_error(("spell '%s' has no function.\n", sp->sname)); co->level = 0; } else { @@ -497,74 +553,79 @@ unit_castspell(unit * u, const char * name) } } -static int -tolua_unit_castspell(lua_State* L) +static int tolua_unit_castspell(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * str = tolua_tostring(L, 2, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + const char *str = tolua_tostring(L, 2, 0); + unit_castspell(self, str); return 0; } -static int -unit_addspell(unit * u, const char * name) +static int unit_addspell(unit * u, const char *name) { - sc_mage * m = get_mage(u); - spell * spadd = find_spell(m->magietyp, name); + sc_mage *m = get_mage(u); + + spell *spadd = find_spell(m->magietyp, name); if (!spadd) { log_error(("spell %s could not be found\n", name)); return EINVAL; } else { - quicklist ** starget = get_spelllist(m, u->faction); + quicklist **starget = get_spelllist(m, u->faction); + add_spell(starget, spadd); } return 0; } -static int -tolua_unit_addspell(lua_State* L) +static int tolua_unit_addspell(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * str = tolua_tostring(L, 2, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + const char *str = tolua_tostring(L, 2, 0); + int err = unit_addspell(self, str); + lua_pushinteger(L, err); return 1; } -static void -unit_removespell(unit * u, spell * sp) +static void unit_removespell(unit * u, spell * sp) { - quicklist ** isptr; + quicklist **isptr; isptr = get_spelllist(get_mage(u), u->faction); ql_set_remove(isptr, sp); } -static int -tolua_unit_removespell(lua_State* L) +static int tolua_unit_removespell(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); - spell * sp = (spell*)tolua_tousertype(L, 2, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + spell *sp = (spell *) tolua_tousertype(L, 2, 0); + unit_removespell(self, sp); return 0; } -static int -tolua_unit_set_racename(lua_State* L) +static int tolua_unit_set_racename(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * str = tolua_tostring(L, 2, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + const char *str = tolua_tostring(L, 2, 0); set_racename(&self->attribs, str); return 0; } -static int -tolua_unit_get_racename(lua_State* L) +static int tolua_unit_get_racename(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); - attrib * a = a_find(self->attribs, &at_racename); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + attrib *a = a_find(self->attribs, &at_racename); + if (a) { tolua_pushstring(L, get_racename(a)); return 1; @@ -572,14 +633,17 @@ tolua_unit_get_racename(lua_State* L) return 0; } -static int -tolua_unit_setskill(lua_State* L) +static int tolua_unit_setskill(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * skname = tolua_tostring(L, 2, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + const char *skname = tolua_tostring(L, 2, 0); + int level = (int)tolua_tonumber(L, 3, 0); + skill_t sk = sk_find(skname); - if (sk!=NOSKILL) { + + if (sk != NOSKILL) { set_level(self, sk, level); } else { level = -1; @@ -588,152 +652,168 @@ tolua_unit_setskill(lua_State* L) return 1; } -static int -tolua_unit_use_pooled(lua_State* L) +static int tolua_unit_use_pooled(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * iname = tolua_tostring(L, 2, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + const char *iname = tolua_tostring(L, 2, 0); + int number = (int)tolua_tonumber(L, 3, 0); - const resource_type * rtype = rt_find(iname); + + const resource_type *rtype = rt_find(iname); + int result = -1; - if (rtype!=NULL) { + + if (rtype != NULL) { result = use_pooled(self, rtype, GET_DEFAULT, number); } lua_pushinteger(L, result); return 1; } -static int -tolua_unit_get_pooled(lua_State* L) +static int tolua_unit_get_pooled(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * iname = tolua_tostring(L, 2, 0); - const resource_type * rtype = rt_find(iname); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + const char *iname = tolua_tostring(L, 2, 0); + + const resource_type *rtype = rt_find(iname); + int result = -1; - if (rtype!=NULL) { + + if (rtype != NULL) { result = get_pooled(self, rtype, GET_DEFAULT, INT_MAX); } lua_pushinteger(L, result); return 1; } -static unit * -unit_getfamiliar(const unit * u) +static unit *unit_getfamiliar(const unit * u) { - attrib * a = a_find(u->attribs, &at_familiar); - if (a!=NULL) { - return (unit*)a->data.v; + attrib *a = a_find(u->attribs, &at_familiar); + + if (a != NULL) { + return (unit *) a->data.v; } return NULL; } -static int tolua_unit_get_familiar(lua_State* L) +static int tolua_unit_get_familiar(lua_State * L) { - unit* self = (unit*) tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, unit_getfamiliar(self), TOLUA_CAST "unit"); return 1; } -static int tolua_unit_set_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 *self = (unit *) tolua_tousertype(L, 1, 0); + + create_newfamiliar(self, (unit *) tolua_tousertype(L, 2, 0)); return 0; } -static int tolua_unit_get_building(lua_State* L) +static int tolua_unit_get_building(lua_State * L) { - unit* self = (unit*) tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, self->building, TOLUA_CAST "building"); return 1; } -static void -unit_setbuilding(unit * u, building * b) +static void unit_setbuilding(unit * u, building * b) { leave(u, true); - if (b && u->region!=b->region) { + if (b && u->region != b->region) { move_unit(u, b->region, NULL); } u->building = b; } -static int tolua_unit_set_building(lua_State* L) +static int tolua_unit_set_building(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + if (self->faction) { - unit_setbuilding(self, (building *)tolua_tousertype(L, 2, 0)); + unit_setbuilding(self, (building *) tolua_tousertype(L, 2, 0)); } return 0; } -static int tolua_unit_get_ship(lua_State* L) +static int tolua_unit_get_ship(lua_State * L) { - unit* self = (unit*) tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, self->ship, TOLUA_CAST "ship"); return 1; } -static void -unit_setship(unit * u, ship * s) +static void unit_setship(unit * u, ship * s) { leave(u, true); - if (s && u->region!=s->region) { + if (s && u->region != s->region) { move_unit(u, s->region, NULL); } u->ship = s; } -static int tolua_unit_set_ship(lua_State* L) +static int tolua_unit_set_ship(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + if (self->faction) { - unit_setship(self, (ship *)tolua_tousertype(L, 2, 0)); + unit_setship(self, (ship *) tolua_tousertype(L, 2, 0)); } return 0; } -static int tolua_unit_get_region(lua_State* L) +static int tolua_unit_get_region(lua_State * L) { - unit* self = (unit*) tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + tolua_pushusertype(L, self->region, TOLUA_CAST "region"); return 1; } -static void -unit_setregion(unit * u, region * r) +static void unit_setregion(unit * u, region * r) { move_unit(u, r, NULL); } -static int tolua_unit_set_region(lua_State* L) +static int tolua_unit_set_region(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); - unit_setregion(self, (region *)tolua_tousertype(L, 2, 0)); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + unit_setregion(self, (region *) tolua_tousertype(L, 2, 0)); return 0; } -static int tolua_unit_add_order(lua_State* L) +static int tolua_unit_add_order(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * str = tolua_tostring(L, 2, 0); - order * ord = parse_order(str, self->faction->locale); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + const char *str = tolua_tostring(L, 2, 0); + + order *ord = parse_order(str, self->faction->locale); + unit_addorder(self, ord); return 0; } -static int tolua_unit_clear_orders(lua_State* L) +static int tolua_unit_clear_orders(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + free_orders(&self->orders); return 0; } -static int tolua_unit_get_items(lua_State* L) +static int tolua_unit_get_items(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); - item ** item_ptr = (item **)lua_newuserdata(L, sizeof(item *)); + item **item_ptr = (item **) lua_newuserdata(L, sizeof(item *)); luaL_getmetatable(L, TOLUA_CAST "item"); lua_setmetatable(L, -2); @@ -745,14 +825,17 @@ static int tolua_unit_get_items(lua_State* L) return 1; } -static int tolua_unit_get_spells(lua_State* L) +static int tolua_unit_get_spells(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); - sc_mage * mage = get_mage(self); - quicklist * slist = 0; + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + sc_mage *mage = get_mage(self); + + quicklist *slist = 0; if (mage) { - quicklist ** slist_ptr = get_spelllist(mage, self->faction); + quicklist **slist_ptr = get_spelllist(mage, self->faction); + if (slist_ptr) { slist = *slist_ptr; } @@ -761,11 +844,11 @@ static int tolua_unit_get_spells(lua_State* L) return tolua_quicklist_push(L, "spell_list", "spell", slist); } -static int tolua_unit_get_orders(lua_State* L) +static int tolua_unit_get_orders(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); - order ** order_ptr = (order **)lua_newuserdata(L, sizeof(order *)); + order **order_ptr = (order **) lua_newuserdata(L, sizeof(order *)); luaL_getmetatable(L, TOLUA_CAST "order"); lua_setmetatable(L, -2); @@ -777,103 +860,130 @@ static int tolua_unit_get_orders(lua_State* L) return 1; } -static int tolua_unit_get_flag(lua_State* L) +static int tolua_unit_get_flag(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + const char *name = tolua_tostring(L, 2, 0); + int flag = atoi36(name); - attrib * a = find_key(self->attribs, flag); - lua_pushboolean(L, (a!=NULL)); + + attrib *a = find_key(self->attribs, flag); + + lua_pushboolean(L, (a != NULL)); return 1; } -static int tolua_unit_set_flag(lua_State* L) +static int tolua_unit_set_flag(lua_State * L) { - unit* self = (unit*)tolua_tousertype(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + const char *name = tolua_tostring(L, 2, 0); + int value = (int)tolua_tonumber(L, 3, 0); + int flag = atoi36(name); - attrib * a = find_key(self->attribs, flag); - if (a==NULL && value) { + + attrib *a = find_key(self->attribs, flag); + + if (a == NULL && value) { add_key(&self->attribs, flag); - } else if (a!=NULL && !value) { + } else if (a != NULL && !value) { a_remove(&self->attribs, a); } return 0; } -static int tolua_unit_get_weight(lua_State* L) +static int tolua_unit_get_weight(lua_State * L) { - unit* self = (unit*) tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + lua_pushinteger(L, unit_getweight(self)); return 1; } -static int tolua_unit_get_capacity(lua_State* L) +static int tolua_unit_get_capacity(lua_State * L) { - unit* self = (unit*) tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + lua_pushinteger(L, unit_getcapacity(self)); return 1; } -static int tolua_unit_get_faction(lua_State* L) +static int tolua_unit_get_faction(lua_State * L) { - unit* self = (unit*) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void*)self->faction, TOLUA_CAST "faction"); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + tolua_pushusertype(L, (void *)self->faction, TOLUA_CAST "faction"); return 1; } -static int tolua_unit_set_faction(lua_State* L) +static int tolua_unit_set_faction(lua_State * L) { - unit * self = (unit*) tolua_tousertype(L, 1, 0); - faction * f = (faction *)tolua_tousertype(L, 2, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + faction *f = (faction *) tolua_tousertype(L, 2, 0); + u_setfaction(self, f); return 0; } -static int tolua_unit_get_race(lua_State* L) +static int tolua_unit_get_race(lua_State * L) { - unit* self = (unit*) tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->race->_name[0]); return 1; } -static int tolua_unit_set_race(lua_State* L) +static int tolua_unit_set_race(lua_State * L) { - unit * self = (unit*) tolua_tousertype(L, 1, 0); - const char * rcname = tolua_tostring(L, 2, 0); - race * rc = rc_find(rcname); - if (rc!=NULL) { - if (count_unit(self)) --self->faction->no_units; - if (self->irace==self->race) self->irace = NULL; + unit *self = (unit *) tolua_tousertype(L, 1, 0); + + const char *rcname = tolua_tostring(L, 2, 0); + + race *rc = rc_find(rcname); + + if (rc != NULL) { + if (count_unit(self)) + --self->faction->no_units; + if (self->irace == self->race) + self->irace = NULL; self->race = rc; - if (count_unit(self)) --self->faction->no_units; + if (count_unit(self)) + --self->faction->no_units; } return 0; } -static int -tolua_unit_destroy(lua_State* L) +static int tolua_unit_destroy(lua_State * L) { - unit * self = (unit *)tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + if (self) { remove_unit(&self->region->units, self); } return 0; } -static int -tolua_unit_create(lua_State* L) +static int tolua_unit_create(lua_State * L) { - faction * f = (faction *)tolua_tousertype(L, 1, 0); - region * r = (region *)tolua_tousertype(L, 2, 0); + faction *f = (faction *) tolua_tousertype(L, 1, 0); + + region *r = (region *) tolua_tousertype(L, 2, 0); + int num = (int)tolua_tonumber(L, 3, 1); + if (f && r) { - const race * rc = f->race; - const char * rcname = tolua_tostring(L, 4, NULL); - if (rcname) rc = rc_find(rcname); + const race *rc = f->race; + + const char *rcname = tolua_tostring(L, 4, NULL); + + if (rcname) + rc = rc_find(rcname); if (rc) { - unit * u = create_unit(r, f, num, rc, 0, NULL, NULL); + unit *u = create_unit(r, f, num, rc, 0, NULL, NULL); + tolua_pushusertype(L, u, TOLUA_CAST "unit"); return 1; } @@ -881,41 +991,42 @@ tolua_unit_create(lua_State* L) return 0; } -static int -tolua_unit_tostring(lua_State *L) +static int tolua_unit_tostring(lua_State * L) { - unit * self = (unit *)tolua_tousertype(L, 1, 0); + unit *self = (unit *) tolua_tousertype(L, 1, 0); + lua_pushstring(L, unitname(self)); return 1; } -static int -tolua_event_gettype(lua_State *L) +static int tolua_event_gettype(lua_State * L) { - event * self = (event *)tolua_tousertype(L, 1, 0); + event *self = (event *) tolua_tousertype(L, 1, 0); + int index = (int)tolua_tonumber(L, 2, 0); + lua_pushstring(L, self->args[index].type); return 1; } -static int -tolua_event_get(lua_State *L) +static int tolua_event_get(lua_State * L) { - struct event * self = (struct event *)tolua_tousertype(L, 1, 0); + struct event *self = (struct event *)tolua_tousertype(L, 1, 0); + int index = (int)tolua_tonumber(L, 2, 0); - event_arg * arg = self->args+index; + event_arg *arg = self->args + index; if (arg->type) { - if (strcmp(arg->type, "string")==0) { + if (strcmp(arg->type, "string") == 0) { tolua_pushstring(L, (const char *)arg->data.v); - } else if (strcmp(arg->type, "int")==0) { + } else if (strcmp(arg->type, "int") == 0) { lua_pushinteger(L, arg->data.i); - } else if (strcmp(arg->type, "float")==0) { - lua_pushnumber(L, (lua_Number)arg->data.f); + } else if (strcmp(arg->type, "float") == 0) { + lua_pushnumber(L, (lua_Number) arg->data.f); } else { /* this is pretty lazy */ - tolua_pushusertype(L, (void*)arg->data.v, TOLUA_CAST arg->type); + tolua_pushusertype(L, (void *)arg->data.v, TOLUA_CAST arg->type); } return 1; } @@ -923,8 +1034,7 @@ tolua_event_get(lua_State *L) return 0; } -void -tolua_unit_open(lua_State * L) +void tolua_unit_open(lua_State * L) { /* register user types */ tolua_usertype(L, TOLUA_CAST "unit"); @@ -932,7 +1042,8 @@ tolua_unit_open(lua_State * L) tolua_module(L, NULL, 0); tolua_beginmodule(L, NULL); { - tolua_cclass(L, TOLUA_CAST "event", TOLUA_CAST "event", TOLUA_CAST "", NULL); + tolua_cclass(L, TOLUA_CAST "event", TOLUA_CAST "event", TOLUA_CAST "", + NULL); tolua_beginmodule(L, TOLUA_CAST "event"); { tolua_function(L, TOLUA_CAST "get_type", &tolua_event_gettype); @@ -947,13 +1058,18 @@ tolua_unit_open(lua_State * L) tolua_function(L, TOLUA_CAST "create", &tolua_unit_create); tolua_function(L, TOLUA_CAST "destroy", &tolua_unit_destroy); - tolua_variable(L, TOLUA_CAST "name", &tolua_unit_get_name, tolua_unit_set_name); - tolua_variable(L, TOLUA_CAST "faction", &tolua_unit_get_faction, tolua_unit_set_faction); + tolua_variable(L, TOLUA_CAST "name", &tolua_unit_get_name, + tolua_unit_set_name); + tolua_variable(L, TOLUA_CAST "faction", &tolua_unit_get_faction, + tolua_unit_set_faction); tolua_variable(L, TOLUA_CAST "id", &tolua_unit_get_id, tolua_unit_set_id); - tolua_variable(L, TOLUA_CAST "info", &tolua_unit_get_info, tolua_unit_set_info); + tolua_variable(L, TOLUA_CAST "info", &tolua_unit_get_info, + tolua_unit_set_info); tolua_variable(L, TOLUA_CAST "hp", &tolua_unit_get_hp, tolua_unit_set_hp); - tolua_variable(L, TOLUA_CAST "status", &tolua_unit_get_status, tolua_unit_set_status); - tolua_variable(L, TOLUA_CAST "familiar", &tolua_unit_get_familiar, tolua_unit_set_familiar); + tolua_variable(L, TOLUA_CAST "status", &tolua_unit_get_status, + tolua_unit_set_status); + tolua_variable(L, TOLUA_CAST "familiar", &tolua_unit_get_familiar, + tolua_unit_set_familiar); tolua_variable(L, TOLUA_CAST "weight", &tolua_unit_get_weight, 0); tolua_variable(L, TOLUA_CAST "capacity", &tolua_unit_get_capacity, 0); @@ -965,8 +1081,10 @@ tolua_unit_open(lua_State * L) // key-attributes for named flags: tolua_function(L, TOLUA_CAST "set_flag", &tolua_unit_set_flag); tolua_function(L, TOLUA_CAST "get_flag", &tolua_unit_get_flag); - tolua_variable(L, TOLUA_CAST "flags", &tolua_unit_get_flags, &tolua_unit_set_flags); - tolua_variable(L, TOLUA_CAST "age", &tolua_unit_get_age, tolua_unit_set_age); + tolua_variable(L, TOLUA_CAST "flags", &tolua_unit_get_flags, + &tolua_unit_set_flags); + tolua_variable(L, TOLUA_CAST "age", &tolua_unit_get_age, + tolua_unit_set_age); // items: tolua_function(L, TOLUA_CAST "get_item", &tolua_unit_get_item); @@ -985,19 +1103,27 @@ tolua_unit_open(lua_State * L) // npc logic: tolua_function(L, TOLUA_CAST "add_handler", &tolua_unit_addhandler); - tolua_variable(L, TOLUA_CAST "race_name", &tolua_unit_get_racename, &tolua_unit_set_racename); + tolua_variable(L, TOLUA_CAST "race_name", &tolua_unit_get_racename, + &tolua_unit_set_racename); tolua_function(L, TOLUA_CAST "add_spell", &tolua_unit_addspell); tolua_function(L, TOLUA_CAST "remove_spell", &tolua_unit_removespell); tolua_function(L, TOLUA_CAST "cast_spell", &tolua_unit_castspell); - tolua_variable(L, TOLUA_CAST "magic", &tolua_unit_get_magic, tolua_unit_set_magic); - tolua_variable(L, TOLUA_CAST "aura", &tolua_unit_get_aura, tolua_unit_set_aura); - tolua_variable(L, TOLUA_CAST "building", &tolua_unit_get_building, tolua_unit_set_building); - tolua_variable(L, TOLUA_CAST "ship", &tolua_unit_get_ship, tolua_unit_set_ship); - tolua_variable(L, TOLUA_CAST "region", &tolua_unit_get_region, tolua_unit_set_region); + tolua_variable(L, TOLUA_CAST "magic", &tolua_unit_get_magic, + tolua_unit_set_magic); + tolua_variable(L, TOLUA_CAST "aura", &tolua_unit_get_aura, + tolua_unit_set_aura); + tolua_variable(L, TOLUA_CAST "building", &tolua_unit_get_building, + tolua_unit_set_building); + tolua_variable(L, TOLUA_CAST "ship", &tolua_unit_get_ship, + tolua_unit_set_ship); + tolua_variable(L, TOLUA_CAST "region", &tolua_unit_get_region, + tolua_unit_set_region); tolua_variable(L, TOLUA_CAST "spells", &tolua_unit_get_spells, 0); - tolua_variable(L, TOLUA_CAST "number", &tolua_unit_get_number, tolua_unit_set_number); - tolua_variable(L, TOLUA_CAST "race", &tolua_unit_get_race, tolua_unit_set_race); + tolua_variable(L, TOLUA_CAST "number", &tolua_unit_get_number, + tolua_unit_set_number); + tolua_variable(L, TOLUA_CAST "race", &tolua_unit_get_race, + tolua_unit_set_race); tolua_variable(L, TOLUA_CAST "hp_max", &tolua_unit_get_hpmax, 0); tolua_variable(L, TOLUA_CAST "objects", &tolua_unit_get_objects, 0); diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index 8cef22507..dd30566e3 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -67,10 +67,9 @@ without prior permission by the authors of Eressea. #include #include -int -log_lua_error(lua_State * L) +int log_lua_error(lua_State * L) { - const char* error = lua_tostring(L, -1); + const char *error = lua_tostring(L, -1); log_error(("LUA call failed.\n%s\n", error)); lua_pop(L, 1); @@ -78,81 +77,96 @@ log_lua_error(lua_State * L) return 1; } -int tolua_orderlist_next(lua_State *L) +int tolua_orderlist_next(lua_State * L) { - order** order_ptr = (order **)lua_touserdata(L, lua_upvalueindex(1)); - order* ord = *order_ptr; + order **order_ptr = (order **) lua_touserdata(L, lua_upvalueindex(1)); + + order *ord = *order_ptr; + if (ord != NULL) { char cmd[8192]; + write_order(ord, cmd, sizeof(cmd)); tolua_pushstring(L, cmd); *order_ptr = ord->next; return 1; - } - else return 0; /* no more values to return */ + } else + return 0; /* no more values to return */ } -static int tolua_quicklist_iter(lua_State *L) +static int tolua_quicklist_iter(lua_State * L) { - quicklist** qlp = (quicklist **)lua_touserdata(L, lua_upvalueindex(1)); - quicklist* ql = *qlp; + quicklist **qlp = (quicklist **) lua_touserdata(L, lua_upvalueindex(1)); + + quicklist *ql = *qlp; + if (ql != NULL) { int index = lua_tointeger(L, lua_upvalueindex(2)); - const char * type = lua_tostring(L, lua_upvalueindex(3)); - void * data = ql_get(ql, index); + + const char *type = lua_tostring(L, lua_upvalueindex(3)); + + void *data = ql_get(ql, index); + tolua_pushusertype(L, data, TOLUA_CAST type); ql_advance(qlp, &index, 1); tolua_pushnumber(L, index); lua_replace(L, lua_upvalueindex(2)); return 1; - } - else return 0; /* no more values to return */ + } else + return 0; /* no more values to return */ } -int tolua_quicklist_push(struct lua_State *L, const char * list_type, const char * elem_type, struct quicklist * list) +int tolua_quicklist_push(struct lua_State *L, const char *list_type, + const char *elem_type, struct quicklist *list) { if (list) { - quicklist ** qlist_ptr = (quicklist**)lua_newuserdata(L, sizeof(quicklist *)); + quicklist **qlist_ptr = + (quicklist **) lua_newuserdata(L, sizeof(quicklist *)); *qlist_ptr = list; luaL_getmetatable(L, list_type); lua_setmetatable(L, -2); lua_pushnumber(L, 0); lua_pushstring(L, elem_type); - lua_pushcclosure(L, tolua_quicklist_iter, 3); /* OBS: this closure has multiple upvalues (list, index, type_name) */ + lua_pushcclosure(L, tolua_quicklist_iter, 3); /* OBS: this closure has multiple upvalues (list, index, type_name) */ } else { lua_pushnil(L); } return 1; } -int tolua_itemlist_next(lua_State *L) +int tolua_itemlist_next(lua_State * L) { - item** item_ptr = (item **)lua_touserdata(L, lua_upvalueindex(1)); - item* itm = *item_ptr; + item **item_ptr = (item **) lua_touserdata(L, lua_upvalueindex(1)); + + item *itm = *item_ptr; + if (itm != NULL) { tolua_pushstring(L, itm->type->rtype->_name[0]); *item_ptr = itm->next; return 1; - } - else return 0; /* no more values to return */ + } else + return 0; /* no more values to return */ } -static int -tolua_autoseed(lua_State * L) +static int tolua_autoseed(lua_State * L) { - const char * filename = tolua_tostring(L, 1, 0); - int new_island = tolua_toboolean(L, 2, 0); - newfaction * players = read_newfactions(filename); + const char *filename = tolua_tostring(L, 1, 0); - if (players!=NULL) { + int new_island = tolua_toboolean(L, 2, 0); + + newfaction *players = read_newfactions(filename); + + if (players != NULL) { while (players) { int n = listlen(players); - int k = (n+ISLANDSIZE-1)/ISLANDSIZE; + + int k = (n + ISLANDSIZE - 1) / ISLANDSIZE; + k = n / k; - n = autoseed(&players, k, new_island?0:TURNS_PER_ISLAND); - if (n==0) { + n = autoseed(&players, k, new_island ? 0 : TURNS_PER_ISLAND); + if (n == 0) { break; } } @@ -161,24 +175,27 @@ tolua_autoseed(lua_State * L) } -static int -tolua_getkey(lua_State* L) +static int tolua_getkey(lua_State * L) { - const char * name = tolua_tostring(L, 1, 0); + const char *name = tolua_tostring(L, 1, 0); int flag = atoi36(name); - attrib * a = find_key(global.attribs, flag); - lua_pushboolean(L, a!=NULL); + + attrib *a = find_key(global.attribs, flag); + + lua_pushboolean(L, a != NULL); return 1; } -static int -tolua_translate(lua_State* L) +static int tolua_translate(lua_State * L) { - const char * str = tolua_tostring(L, 1, 0); - const char * lang = tolua_tostring(L, 2, 0); - struct locale * loc = lang?find_locale(lang):default_locale; + const char *str = tolua_tostring(L, 1, 0); + + const char *lang = tolua_tostring(L, 2, 0); + + struct locale *loc = lang ? find_locale(lang) : default_locale; + if (loc) { str = locale_string(loc, str); tolua_pushstring(L, str); @@ -187,178 +204,207 @@ tolua_translate(lua_State* L) return 0; } -static int -tolua_setkey(lua_State* L) +static int tolua_setkey(lua_State * L) { - const char * name = tolua_tostring(L, 1, 0); + const char *name = tolua_tostring(L, 1, 0); + int value = tolua_toboolean(L, 2, 0); int flag = atoi36(name); - attrib * a = find_key(global.attribs, flag); - if (a==NULL && value) { + + attrib *a = find_key(global.attribs, flag); + + if (a == NULL && value) { add_key(&global.attribs, flag); - } else if (a!=NULL && !value) { + } else if (a != NULL && !value) { a_remove(&global.attribs, a); } return 0; } -static int -tolua_rng_int(lua_State* L) +static int tolua_rng_int(lua_State * L) { - lua_pushnumber(L, (lua_Number)rng_int()); + lua_pushnumber(L, (lua_Number) rng_int()); return 1; } -static int -tolua_read_orders(lua_State* L) +static int tolua_read_orders(lua_State * L) { - const char * filename = tolua_tostring(L, 1, 0); + const char *filename = tolua_tostring(L, 1, 0); + int result = readorders(filename); - lua_pushnumber(L, (lua_Number)result); + + lua_pushnumber(L, (lua_Number) result); return 1; } -static int -tolua_message_unit(lua_State* L) +static int tolua_message_unit(lua_State * L) { - unit * sender = (unit *)tolua_tousertype(L, 1, 0); - unit * target = (unit *)tolua_tousertype(L, 2, 0); - const char * str = tolua_tostring(L, 3, 0); - if (!target) tolua_error(L, TOLUA_CAST "target is nil", NULL); - if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); + unit *sender = (unit *) tolua_tousertype(L, 1, 0); + + unit *target = (unit *) tolua_tousertype(L, 2, 0); + + const char *str = tolua_tostring(L, 3, 0); + + if (!target) + tolua_error(L, TOLUA_CAST "target is nil", NULL); + if (!sender) + tolua_error(L, TOLUA_CAST "sender is nil", NULL); deliverMail(target->faction, sender->region, sender, str, target); return 0; } -static int -tolua_message_faction(lua_State * L) +static int tolua_message_faction(lua_State * L) { - unit * sender = (unit *)tolua_tousertype(L, 1, 0); - faction * target = (faction *)tolua_tousertype(L, 2, 0); - const char * str = tolua_tostring(L, 3, 0); - if (!target) tolua_error(L, TOLUA_CAST "target is nil", NULL); - if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); + unit *sender = (unit *) tolua_tousertype(L, 1, 0); + + faction *target = (faction *) tolua_tousertype(L, 2, 0); + + const char *str = tolua_tostring(L, 3, 0); + + if (!target) + tolua_error(L, TOLUA_CAST "target is nil", NULL); + if (!sender) + tolua_error(L, TOLUA_CAST "sender is nil", NULL); deliverMail(target, sender->region, sender, str, NULL); return 0; } -static int -tolua_message_region(lua_State * L) +static int tolua_message_region(lua_State * L) { - unit * sender = (unit *)tolua_tousertype(L, 1, 0); - const char * str = tolua_tostring(L, 2, 0); + unit *sender = (unit *) tolua_tousertype(L, 1, 0); - if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); - ADDMSG(&sender->region->msgs, msg_message("mail_result", "unit message", sender, str)); + const char *str = tolua_tostring(L, 2, 0); + + if (!sender) + tolua_error(L, TOLUA_CAST "sender is nil", NULL); + ADDMSG(&sender->region->msgs, msg_message("mail_result", "unit message", + sender, str)); return 0; } -static int -tolua_update_guards(lua_State * L) +static int tolua_update_guards(lua_State * L) { update_guards(); return 0; } -static int -tolua_set_turn(lua_State * L) +static int tolua_set_turn(lua_State * L) { turn = (int)tolua_tonumber(L, 1, 0); return 0; } -static int -tolua_get_turn(lua_State * L) +static int tolua_get_turn(lua_State * L) { - tolua_pushnumber(L, (lua_Number)turn); + tolua_pushnumber(L, (lua_Number) turn); return 1; } -static int -tolua_atoi36(lua_State * L) +static int tolua_atoi36(lua_State * L) { - const char * s = tolua_tostring(L, 1, 0); - tolua_pushnumber(L, (lua_Number)atoi36(s)); + const char *s = tolua_tostring(L, 1, 0); + + tolua_pushnumber(L, (lua_Number) atoi36(s)); return 1; } -static int -tolua_itoa36(lua_State * L) +static int tolua_itoa36(lua_State * L) { int i = (int)tolua_tonumber(L, 1, 0); + tolua_pushstring(L, itoa36(i)); return 1; } -static int -tolua_dice_rand(lua_State * L) +static int tolua_dice_rand(lua_State * L) { - const char * s = tolua_tostring(L, 1, 0); + const char *s = tolua_tostring(L, 1, 0); + tolua_pushnumber(L, dice_rand(s)); return 1; } -static int -tolua_addequipment(lua_State * L) +static int tolua_addequipment(lua_State * L) { - const char * eqname = tolua_tostring(L, 1, 0); - const char * iname = tolua_tostring(L, 2, 0); - const char * value = tolua_tostring(L, 3, 0); + const char *eqname = tolua_tostring(L, 1, 0); + + const char *iname = tolua_tostring(L, 2, 0); + + const char *value = tolua_tostring(L, 3, 0); + int result = -1; - if (iname!=NULL) { - const struct item_type * itype = it_find(iname); - if (itype!=NULL) { + + if (iname != NULL) { + const struct item_type *itype = it_find(iname); + + if (itype != NULL) { equipment_setitem(create_equipment(eqname), itype, value); result = 0; } } - lua_pushnumber(L, (lua_Number)result); + lua_pushnumber(L, (lua_Number) result); return 1; } -static int -tolua_get_season(lua_State * L) +static int tolua_get_season(lua_State * L) { int turnno = (int)tolua_tonumber(L, 1, 0); + gamedate gd; + get_gamedate(turnno, &gd); tolua_pushstring(L, seasonnames[gd.season]); return 1; } -static int -tolua_create_curse(lua_State * L) +static int tolua_create_curse(lua_State * L) { - unit * u = (unit *)tolua_tousertype(L, 1, 0); + unit *u = (unit *) tolua_tousertype(L, 1, 0); + tolua_Error tolua_err; - attrib ** ap = NULL; + + attrib **ap = NULL; if (tolua_isusertype(L, 2, TOLUA_CAST "unit", 0, &tolua_err)) { - unit * target = (unit *)tolua_tousertype(L, 2, 0); - if (target) ap = &target->attribs; + unit *target = (unit *) tolua_tousertype(L, 2, 0); + + if (target) + ap = &target->attribs; } else if (tolua_isusertype(L, 2, TOLUA_CAST "region", 0, &tolua_err)) { - region * target = (region *)tolua_tousertype(L, 2, 0); - if (target) ap = &target->attribs; + region *target = (region *) tolua_tousertype(L, 2, 0); + + if (target) + ap = &target->attribs; } else if (tolua_isusertype(L, 2, TOLUA_CAST "ship", 0, &tolua_err)) { - ship * target = (ship *)tolua_tousertype(L, 2, 0); - if (target) ap = &target->attribs; + ship *target = (ship *) tolua_tousertype(L, 2, 0); + + if (target) + ap = &target->attribs; } else if (tolua_isusertype(L, 2, TOLUA_CAST "building", 0, &tolua_err)) { - building * target = (building *)tolua_tousertype(L, 2, 0); - if (target) ap = &target->attribs; + building *target = (building *) tolua_tousertype(L, 2, 0); + + if (target) + ap = &target->attribs; } if (ap) { - const char * cname = tolua_tostring(L, 3, 0); - const curse_type * ctype = ct_find(cname); + const char *cname = tolua_tostring(L, 3, 0); + + const curse_type *ctype = ct_find(cname); + if (ctype) { double vigour = tolua_tonumber(L, 4, 0); + int duration = (int)tolua_tonumber(L, 5, 0); + double effect = tolua_tonumber(L, 6, 0); - int men = (int)tolua_tonumber(L, 7, 0); /* optional */ - curse * c = create_curse(u, ap, ctype, vigour, duration, effect, men); + + int men = (int)tolua_tonumber(L, 7, 0); /* optional */ + + curse *c = create_curse(u, ap, ctype, vigour, duration, effect, men); if (c) { tolua_pushboolean(L, true); @@ -370,165 +416,178 @@ tolua_create_curse(lua_State * L) return 1; } -static int -tolua_learn_skill(lua_State * L) +static int tolua_learn_skill(lua_State * L) { - unit * u = (unit *)tolua_tousertype(L, 1, 0); - const char * skname = tolua_tostring(L, 2, 0); + unit *u = (unit *) tolua_tousertype(L, 1, 0); + + const char *skname = tolua_tostring(L, 2, 0); + float chances = (float)tolua_tonumber(L, 3, 0); + skill_t sk = sk_find(skname); - if (sk!=NOSKILL) { + + if (sk != NOSKILL) { learn_skill(u, sk, chances); } return 0; } -static int -tolua_update_scores(lua_State * L) +static int tolua_update_scores(lua_State * L) { score(); return 0; } -static int -tolua_update_owners(lua_State * L) +static int tolua_update_owners(lua_State * L) { - region * r; - for (r=regions;r;r=r->next) { + region *r; + + for (r = regions; r; r = r->next) { update_owners(r); } return 0; } -static int -tolua_update_subscriptions(lua_State * L) +static int tolua_update_subscriptions(lua_State * L) { update_subscriptions(); return 0; } -static int -tolua_remove_empty_units(lua_State * L) +static int tolua_remove_empty_units(lua_State * L) { remove_empty_units(); return 0; } -static int -tolua_get_nmrs(lua_State * L) +static int tolua_get_nmrs(lua_State * L) { int result = -1; + int n = (int)tolua_tonumber(L, 1, 0); - if (n>=0 && n<=NMRTimeout()) { - if (nmrs==NULL) { + + if (n >= 0 && n <= NMRTimeout()) { + if (nmrs == NULL) { update_nmrs(); } result = nmrs[n]; } - tolua_pushnumber(L, (lua_Number)result); + tolua_pushnumber(L, (lua_Number) result); return 1; } -static int -tolua_equipunit(lua_State * L) +static int tolua_equipunit(lua_State * L) { - unit * u = (unit *)tolua_tousertype(L, 1, 0); - const char * eqname = tolua_tostring(L, 2, 0); + unit *u = (unit *) tolua_tousertype(L, 1, 0); + + const char *eqname = tolua_tostring(L, 2, 0); equip_unit(u, get_equipment(eqname)); return 0; } -static int -tolua_equipment_setitem(lua_State * L) +static int tolua_equipment_setitem(lua_State * L) { int result = -1; - const char * eqname = tolua_tostring(L, 1, 0); - const char * iname = tolua_tostring(L, 2, 0); - const char * value = tolua_tostring(L, 3, 0); - if (iname!=NULL) { - const struct item_type * itype = it_find(iname); - if (itype!=NULL) { + + const char *eqname = tolua_tostring(L, 1, 0); + + const char *iname = tolua_tostring(L, 2, 0); + + const char *value = tolua_tostring(L, 3, 0); + + if (iname != NULL) { + const struct item_type *itype = it_find(iname); + + if (itype != NULL) { equipment_setitem(create_equipment(eqname), itype, value); result = 0; } } - tolua_pushnumber(L, (lua_Number)result); + tolua_pushnumber(L, (lua_Number) result); return 1; } #ifdef TODO_FOSS -static int -tolua_levitate_ship(lua_State * L) +static int tolua_levitate_ship(lua_State * L) { - ship * sh = (ship *)tolua_tousertype(L, 1, 0); - unit * mage = (unit *)tolua_tousertype(L, 2, 0); + ship *sh = (ship *) tolua_tousertype(L, 1, 0); + + unit *mage = (unit *) tolua_tousertype(L, 2, 0); + double power = (double)tolua_tonumber(L, 3, 0); + int duration = (int)tolua_tonumber(L, 4, 0); + int cno = levitate_ship(sh, mage, power, duration); - tolua_pushnumber(L, (lua_Number)cno); + + tolua_pushnumber(L, (lua_Number) cno); return 1; } #endif -static int -tolua_spawn_braineaters(lua_State * L) +static int tolua_spawn_braineaters(lua_State * L) { float chance = (float)tolua_tonumber(L, 1, 0); + spawn_braineaters(chance); return 0; } -static int -tolua_init_reports(lua_State* L) +static int tolua_init_reports(lua_State * L) { int result = init_reports(); - tolua_pushnumber(L, (lua_Number)result); + + tolua_pushnumber(L, (lua_Number) result); return 1; } -static int -tolua_write_report(lua_State* L) +static int tolua_write_report(lua_State * L) { - faction * f = (faction * )tolua_tousertype(L, 1, 0); + faction *f = (faction *) tolua_tousertype(L, 1, 0); + time_t ltime = time(0); + int result = write_reports(f, ltime); - tolua_pushnumber(L, (lua_Number)result); + tolua_pushnumber(L, (lua_Number) result); return 1; } -static int -tolua_write_reports(lua_State* L) +static int tolua_write_reports(lua_State * L) { int result; init_reports(); result = reports(); - tolua_pushnumber(L, (lua_Number)result); + tolua_pushnumber(L, (lua_Number) result); return 1; } -static void -reset_game(void) +static void reset_game(void) { - region * r; - faction * f; - for (r=regions;r;r=r->next) { - unit * u; - building * b; + region *r; + + faction *f; + + for (r = regions; r; r = r->next) { + unit *u; + + building *b; + r->flags &= RF_SAVEMASK; - for (u=r->units;u;u=u->next) { + for (u = r->units; u; u = u->next) { u->flags &= UFL_SAVEMASK; } - for (b=r->buildings;b;b=b->next) { + for (b = r->buildings; b; b = b->next) { b->flags &= BLD_SAVEMASK; } if (r->land && r->land->ownership && r->land->ownership->owner) { - faction * owner = r->land->ownership->owner; - if (owner==get_monsters()) { + faction *owner = r->land->ownership->owner; + + if (owner == get_monsters()) { /* some compat-fix, i believe. */ owner = update_owners(r); } @@ -537,13 +596,12 @@ reset_game(void) } } } - for (f=factions;f;f=f->next) { + for (f = factions; f; f = f->next) { f->flags &= FFL_SAVEMASK; } } -static int -tolua_process_orders(lua_State* L) +static int tolua_process_orders(lua_State * L) { ++turn; reset_game(); @@ -551,28 +609,27 @@ tolua_process_orders(lua_State* L) return 0; } -static int -tolua_write_passwords(lua_State* L) +static int tolua_write_passwords(lua_State * L) { int result = writepasswd(); - lua_pushnumber(L, (lua_Number)result); + + lua_pushnumber(L, (lua_Number) result); return 0; } -static struct summary * sum_begin = 0; +static struct summary *sum_begin = 0; -static int -tolua_init_summary(lua_State* L) +static int tolua_init_summary(lua_State * L) { sum_begin = make_summary(); return 0; } -static int -tolua_write_summary(lua_State* L) +static int tolua_write_summary(lua_State * L) { if (sum_begin) { - struct summary * sum_end = make_summary(); + struct summary *sum_end = make_summary(); + report_summary(sum_end, sum_begin, false); report_summary(sum_end, sum_begin, true); return 0; @@ -580,76 +637,80 @@ tolua_write_summary(lua_State* L) return 0; } -static int -tolua_free_game(lua_State* L) +static int tolua_free_game(lua_State * L) { free_gamedata(); return 0; } -static int -tolua_write_map(lua_State* L) +static int tolua_write_map(lua_State * L) { - const char * filename = tolua_tostring(L, 1, 0); + const char *filename = tolua_tostring(L, 1, 0); + if (filename) { crwritemap(filename); } return 0; } -static int -tolua_write_game(lua_State* L) +static int tolua_write_game(lua_State * L) { - const char * filename = tolua_tostring(L, 1, 0); - const char * mode = tolua_tostring(L, 2, 0); + const char *filename = tolua_tostring(L, 1, 0); + + const char *mode = tolua_tostring(L, 2, 0); int result, m = IO_BINARY; - if (mode && strcmp(mode, "text")==0) m = IO_TEXT; + + if (mode && strcmp(mode, "text") == 0) + m = IO_TEXT; remove_empty_factions(); result = writegame(filename, m); - tolua_pushnumber(L, (lua_Number)result); + tolua_pushnumber(L, (lua_Number) result); return 1; } -static int -tolua_read_game(lua_State* L) +static int tolua_read_game(lua_State * L) { - const char * filename = tolua_tostring(L, 1, 0); - const char * mode = tolua_tostring(L, 2, 0); + const char *filename = tolua_tostring(L, 1, 0); + + const char *mode = tolua_tostring(L, 2, 0); int rv, m = IO_BINARY; - if (mode && strcmp(mode, "text")==0) m = IO_TEXT; + + if (mode && strcmp(mode, "text") == 0) + m = IO_TEXT; rv = readgame(filename, m, false); - tolua_pushnumber(L, (lua_Number)rv); + tolua_pushnumber(L, (lua_Number) rv); return 1; } -static int -tolua_read_turn(lua_State* L) +static int tolua_read_turn(lua_State * L) { int cturn = current_turn(); - tolua_pushnumber(L, (lua_Number)cturn); + + tolua_pushnumber(L, (lua_Number) cturn); return 1; } -static int -tolua_get_faction(lua_State* L) +static int tolua_get_faction(lua_State * L) { int no = tolua_toid(L, 1, 0); - faction * f = findfaction(no); + + faction *f = findfaction(no); tolua_pushusertype(L, f, TOLUA_CAST "faction"); return 1; } -static int -tolua_get_region(lua_State* L) +static int tolua_get_region(lua_State * L) { int x = (int)tolua_tonumber(L, 1, 0); + int y = (int)tolua_tonumber(L, 2, 0); - region * r; + + region *r; assert(!pnormalize(&x, &y, findplane(x, y))); r = findregion(x, y); @@ -658,72 +719,71 @@ tolua_get_region(lua_State* L) return 1; } -static int -tolua_get_region_byid(lua_State* L) +static int tolua_get_region_byid(lua_State * L) { int uid = (int)tolua_tonumber(L, 1, 0); - region * r = findregionbyid(uid); + + region *r = findregionbyid(uid); tolua_pushusertype(L, r, TOLUA_CAST "region"); return 1; } -static int -tolua_get_building(lua_State* L) +static int tolua_get_building(lua_State * L) { int no = tolua_toid(L, 1, 0); - building * b = findbuilding(no); + + building *b = findbuilding(no); tolua_pushusertype(L, b, TOLUA_CAST "building"); return 1; } -static int -tolua_get_ship(lua_State* L) +static int tolua_get_ship(lua_State * L) { int no = tolua_toid(L, 1, 0); - ship * sh = findship(no); + + ship *sh = findship(no); tolua_pushusertype(L, sh, TOLUA_CAST "ship"); return 1; } -static int -tolua_get_alliance(lua_State* L) +static int tolua_get_alliance(lua_State * L) { int no = tolua_toid(L, 1, 0); - alliance * f = findalliance(no); + + alliance *f = findalliance(no); tolua_pushusertype(L, f, TOLUA_CAST "alliance"); return 1; } -static int -tolua_get_unit(lua_State* L) +static int tolua_get_unit(lua_State * L) { int no = tolua_toid(L, 1, 0); - unit * u = findunit(no); + + unit *u = findunit(no); tolua_pushusertype(L, u, TOLUA_CAST "unit"); return 1; } -static int -tolua_alliance_create(lua_State* L) +static int tolua_alliance_create(lua_State * L) { int id = (int)tolua_tonumber(L, 1, 0); - const char * name = tolua_tostring(L, 2, 0); - alliance * alli = makealliance(id, name); + const char *name = tolua_tostring(L, 2, 0); + + alliance *alli = makealliance(id, name); tolua_pushusertype(L, alli, TOLUA_CAST "alliance"); return 1; } -static int -tolua_get_regions(lua_State* L) +static int tolua_get_regions(lua_State * L) { - region ** region_ptr = (region**)lua_newuserdata(L, sizeof(region *)); + region **region_ptr = (region **) lua_newuserdata(L, sizeof(region *)); luaL_getmetatable(L, "region"); lua_setmetatable(L, -2); @@ -734,10 +794,9 @@ tolua_get_regions(lua_State* L) return 1; } -static int -tolua_get_factions(lua_State* L) +static int tolua_get_factions(lua_State * L) { - faction ** faction_ptr = (faction**)lua_newuserdata(L, sizeof(faction *)); + faction **faction_ptr = (faction **) lua_newuserdata(L, sizeof(faction *)); luaL_getmetatable(L, "faction"); lua_setmetatable(L, -2); @@ -748,30 +807,33 @@ tolua_get_factions(lua_State* L) return 1; } -static int -tolua_get_alliance_factions(lua_State* L) +static int tolua_get_alliance_factions(lua_State * L) { - alliance * self = (alliance *)tolua_tousertype(L, 1, 0); + alliance *self = (alliance *) tolua_tousertype(L, 1, 0); + return tolua_quicklist_push(L, "faction_list", "faction", self->members); } -static int tolua_get_alliance_id(lua_State* L) +static int tolua_get_alliance_id(lua_State * L) { - alliance* self = (alliance*) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number)self->id); + alliance *self = (alliance *) tolua_tousertype(L, 1, 0); + + tolua_pushnumber(L, (lua_Number) self->id); return 1; } -static int tolua_get_alliance_name(lua_State* L) +static int tolua_get_alliance_name(lua_State * L) { - alliance* self = (alliance*) tolua_tousertype(L, 1, 0); + alliance *self = (alliance *) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->name); return 1; } -static int tolua_set_alliance_name(lua_State* L) +static int tolua_set_alliance_name(lua_State * L) { - alliance* self = (alliance*)tolua_tousertype(L, 1, 0); + alliance *self = (alliance *) tolua_tousertype(L, 1, 0); + alliance_setname(self, tolua_tostring(L, 2, 0)); return 0; } @@ -781,37 +843,48 @@ static int tolua_set_alliance_name(lua_State* L) #include #include -static int -tolua_write_spells(lua_State* L) +static int tolua_write_spells(lua_State * L) { - spell_f fun = (spell_f)get_function("lua_castspell"); - const char * filename = "magic.xml"; + spell_f fun = (spell_f) get_function("lua_castspell"); + + const char *filename = "magic.xml"; + xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); + xmlNodePtr root = xmlNewNode(NULL, BAD_CAST "spells"); - quicklist * ql; + + quicklist *ql; + int qi; - for (ql=spells,qi=0;ql;ql_advance(&ql, &qi, 1)) { - spell * sp = (spell *)ql_get(ql, qi); - if (sp->sp_function!=fun) { + for (ql = spells, qi = 0; ql; ql_advance(&ql, &qi, 1)) { + spell *sp = (spell *) ql_get(ql, qi); + + if (sp->sp_function != fun) { int combat = 0; + xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "spell"); + xmlNewProp(node, BAD_CAST "name", BAD_CAST sp->sname); xmlNewProp(node, BAD_CAST "type", BAD_CAST magic_school[sp->magietyp]); xmlNewProp(node, BAD_CAST "rank", xml_i(sp->rank)); xmlNewProp(node, BAD_CAST "level", xml_i(sp->level)); xmlNewProp(node, BAD_CAST "index", xml_i(sp->id)); - if (sp->syntax) xmlNewProp(node, BAD_CAST "syntax", BAD_CAST sp->syntax); - if (sp->parameter) xmlNewProp(node, BAD_CAST "parameters", BAD_CAST sp->parameter); + if (sp->syntax) + xmlNewProp(node, BAD_CAST "syntax", BAD_CAST sp->syntax); + if (sp->parameter) + xmlNewProp(node, BAD_CAST "parameters", BAD_CAST sp->parameter); if (sp->components) { - spell_component * comp = sp->components; - for (;comp->type!=0;++comp) { - static const char * costs[] = { "fixed", "level", "linear" }; + spell_component *comp = sp->components; + + for (; comp->type != 0; ++comp) { + static const char *costs[] = { "fixed", "level", "linear" }; xmlNodePtr cnode = xmlNewNode(NULL, BAD_CAST "resource"); + xmlNewProp(cnode, BAD_CAST "name", BAD_CAST comp->type->_name[0]); xmlNewProp(cnode, BAD_CAST "amount", xml_i(comp->amount)); xmlNewProp(cnode, BAD_CAST "cost", BAD_CAST costs[comp->cost]); - xmlAddChild(node, cnode); + xmlAddChild(node, cnode); } } @@ -831,13 +904,16 @@ tolua_write_spells(lua_State* L) xmlNewProp(node, BAD_CAST "variable", BAD_CAST "true"); } - if (sp->sptyp & POSTCOMBATSPELL) combat = 3; - else if (sp->sptyp & COMBATSPELL) combat = 2; - else if (sp->sptyp & PRECOMBATSPELL) combat = 1; + if (sp->sptyp & POSTCOMBATSPELL) + combat = 3; + else if (sp->sptyp & COMBATSPELL) + combat = 2; + else if (sp->sptyp & PRECOMBATSPELL) + combat = 1; if (combat) { xmlNewProp(node, BAD_CAST "combat", xml_i(combat)); } - xmlAddChild(root, node); + xmlAddChild(root, node); } } xmlDocSetRootElement(doc, root); @@ -847,136 +923,146 @@ tolua_write_spells(lua_State* L) return 0; } -static int -config_get_ships(lua_State *L) +static int config_get_ships(lua_State * L) { - quicklist * ql; - int qi, i=0; + quicklist *ql; + + int qi, i = 0; lua_createtable(L, ql_length(shiptypes), 0); - for (qi=0,ql=shiptypes;ql;ql_advance(&ql, &qi, 1)) { - ship_type * stype = (ship_type *)ql_get(ql, qi); + for (qi = 0, ql = shiptypes; ql; ql_advance(&ql, &qi, 1)) { + ship_type *stype = (ship_type *) ql_get(ql, qi); + tolua_pushstring(L, TOLUA_CAST stype->name[0]); lua_rawseti(L, -2, ++i); } return 1; } -static int -config_get_locales(lua_State *L) +static int config_get_locales(lua_State * L) { - const struct locale * lang; + const struct locale *lang; + int i = 0, n = 0; - for (lang = locales;lang;lang = nextlocale(lang)) ++n; + for (lang = locales; lang; lang = nextlocale(lang)) + ++n; lua_createtable(L, n, 0); - for (lang = locales;lang;lang = nextlocale(lang)) { + for (lang = locales; lang; lang = nextlocale(lang)) { tolua_pushstring(L, TOLUA_CAST locale_name(lang)); lua_rawseti(L, -2, ++i); } return 1; } -static int -config_get_resource(lua_State *L) +static int config_get_resource(lua_State * L) { - const char * name = tolua_tostring(L, 1, 0); + const char *name = tolua_tostring(L, 1, 0); + if (name) { - const struct item_type * itype = it_find(name); + const struct item_type *itype = it_find(name); + if (itype) { lua_newtable(L); - lua_pushstring(L, "weight"); - lua_pushinteger(L, itype->weight); - lua_settable(L, -3); - if (itype->capacity>0) { - lua_pushstring(L, "capacity"); - lua_pushinteger(L, itype->capacity); - lua_settable(L, -3); - } - if (itype->construction) { + lua_pushstring(L, "weight"); + lua_pushinteger(L, itype->weight); + lua_settable(L, -3); + if (itype->capacity > 0) { + lua_pushstring(L, "capacity"); + lua_pushinteger(L, itype->capacity); + lua_settable(L, -3); + } + if (itype->construction) { int i; - lua_pushstring(L, "build_skill_min"); - lua_pushinteger(L, itype->construction->minskill); - lua_settable(L, -3); - lua_pushstring(L, "build_skill_name"); - lua_pushstring(L, skillnames[itype->construction->skill]); - lua_settable(L, -3); - - if (itype->construction->materials) { - lua_pushstring(L, "materials"); - lua_newtable(L); - for (i=0;itype->construction->materials[i].number;++i) { - lua_pushstring(L, itype->construction->materials[i].rtype->_name[0]); - lua_pushinteger(L, itype->construction->materials[i].number); - lua_settable(L, -3); - } - lua_settable(L, -3); - } - } - return 1; + + lua_pushstring(L, "build_skill_min"); + lua_pushinteger(L, itype->construction->minskill); + lua_settable(L, -3); + lua_pushstring(L, "build_skill_name"); + lua_pushstring(L, skillnames[itype->construction->skill]); + lua_settable(L, -3); + if (itype->construction->materials) { + lua_pushstring(L, "materials"); + lua_newtable(L); + for (i = 0; itype->construction->materials[i].number; ++i) { + lua_pushstring(L, + itype->construction->materials[i].rtype->_name[0]); + lua_pushinteger(L, itype->construction->materials[i].number); + lua_settable(L, -3); + } + lua_settable(L, -3); + } + } + return 1; } } return 0; } -static int -tolua_get_spell_text(lua_State *L) +static int tolua_get_spell_text(lua_State * L) { - const struct locale * loc = default_locale; - spell * self = (spell *)tolua_tousertype(L, 1, 0); + const struct locale *loc = default_locale; + + spell *self = (spell *) tolua_tousertype(L, 1, 0); + lua_pushstring(L, spell_info(self, loc)); return 1; } -static int -tolua_get_spell_school(lua_State *L) +static int tolua_get_spell_school(lua_State * L) { - spell * self = (spell *)tolua_tousertype(L, 1, 0); + spell *self = (spell *) tolua_tousertype(L, 1, 0); + lua_pushstring(L, magic_school[self->magietyp]); return 1; } -static int -tolua_get_spell_level(lua_State *L) +static int tolua_get_spell_level(lua_State * L) { - spell * self = (spell *)tolua_tousertype(L, 1, 0); + spell *self = (spell *) tolua_tousertype(L, 1, 0); + lua_pushnumber(L, self->level); return 1; } -static int -tolua_get_spell_name(lua_State *L) +static int tolua_get_spell_name(lua_State * L) { - const struct locale * lang = default_locale; - spell * self = (spell *)tolua_tousertype(L, 1, 0); + const struct locale *lang = default_locale; + + spell *self = (spell *) tolua_tousertype(L, 1, 0); + lua_pushstring(L, spell_name(self, lang)); return 1; } -static int tolua_get_spells(lua_State* L) +static int tolua_get_spells(lua_State * L) { return tolua_quicklist_push(L, "spell_list", "spell", spells); } -int -tolua_read_xml(lua_State* L) +int tolua_read_xml(lua_State * L) { - const char * filename = tolua_tostring(L, 1, 0); - const char * catalog = tolua_tostring(L, 2, 0); + const char *filename = tolua_tostring(L, 1, 0); + + const char *catalog = tolua_tostring(L, 2, 0); + init_data(filename, catalog); return 0; } -int tolua_process_markets(lua_State* L) { +int tolua_process_markets(lua_State * L) +{ do_markets(); return 0; } -int tolua_process_produce(lua_State* L) { - region * r; - for (r=regions;r;r=r->next) { +int tolua_process_produce(lua_State * L) +{ + region *r; + + for (r = regions; r; r = r->next) { produce(r); } return 0; @@ -985,17 +1071,20 @@ int tolua_process_produce(lua_State* L) { typedef struct event_args { int hfunction; int hargs; - const char * sendertype; + const char *sendertype; } event_args; -static void args_free(void * udata) +static void args_free(void *udata) { free(udata); } -static void event_cb(void * sender, const char * event, void * udata) { - lua_State * L = (lua_State *)global.vm_state; - event_args * args = (event_args *)udata; +static void event_cb(void *sender, const char *event, void *udata) +{ + lua_State *L = (lua_State *) global.vm_state; + + event_args *args = (event_args *) udata; + int nargs = 2; lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); @@ -1012,23 +1101,24 @@ static void event_cb(void * sender, const char * event, void * udata) { lua_pcall(L, nargs, 0, 0); } -static int -tolua_eventbus_register(lua_State * L) +static int tolua_eventbus_register(lua_State * L) { /* parameters: - ** 1: sender (usertype) - ** 2: event (string) - ** 3: handler (function) - ** 4: arguments (any, *optional*) - */ - void * sender = tolua_tousertype(L, 1, 0); - const char * event = tolua_tostring(L, 2, 0); - event_args * args = malloc(sizeof(event_args)); + ** 1: sender (usertype) + ** 2: event (string) + ** 3: handler (function) + ** 4: arguments (any, *optional*) + */ + void *sender = tolua_tousertype(L, 1, 0); - args->sendertype = sender?tolua_typename(L, 1):NULL; + const char *event = tolua_tostring(L, 2, 0); + + event_args *args = malloc(sizeof(event_args)); + + args->sendertype = sender ? tolua_typename(L, 1) : NULL; lua_pushvalue(L, 3); args->hfunction = luaL_ref(L, LUA_REGISTRYINDEX); - if (lua_type(L, 4)!=LUA_TNONE) { + if (lua_type(L, 4) != LUA_TNONE) { lua_pushvalue(L, 4); args->hargs = luaL_ref(L, LUA_REGISTRYINDEX); } else { @@ -1038,73 +1128,83 @@ tolua_eventbus_register(lua_State * L) return 0; } -static int -tolua_eventbus_fire(lua_State * L) +static int tolua_eventbus_fire(lua_State * L) { - void * sender = tolua_tousertype(L, 1, 0); - const char * event = tolua_tostring(L, 2, 0); - void * args = NULL; + void *sender = tolua_tousertype(L, 1, 0); + + const char *event = tolua_tostring(L, 2, 0); + + void *args = NULL; + eventbus_fire(sender, event, args); return 0; } -static int -tolua_report_unit(lua_State* L) +static int tolua_report_unit(lua_State * L) { char buffer[512]; - unit * u = (unit *)tolua_tousertype(L, 1, 0); - faction * f = (faction *)tolua_tousertype(L, 2, 0); + + unit *u = (unit *) tolua_tousertype(L, 1, 0); + + faction *f = (faction *) tolua_tousertype(L, 2, 0); + bufunit(f, u, 0, see_unit, buffer, sizeof(buffer)); tolua_pushstring(L, buffer); return 1; } -static int -tolua_settings_get(lua_State* L) +static int tolua_settings_get(lua_State * L) { - const char * name = tolua_tostring(L, 1, 0); + const char *name = tolua_tostring(L, 1, 0); + tolua_pushstring(L, get_param(global.parameters, name)); + return 1; } -static int -tolua_settings_set(lua_State* L) +static int tolua_settings_set(lua_State * L) { - const char * name = tolua_tostring(L, 1, 0); - const char * value = tolua_tostring(L, 2, 0); + const char *name = tolua_tostring(L, 1, 0); + + const char *value = tolua_tostring(L, 2, 0); + set_param(&global.parameters, name, value); + return 0; } -static void -parse_inifile(lua_State* L, dictionary * d, const char * section) +static void parse_inifile(lua_State * L, dictionary * d, const char *section) { int i; - size_t len = strlen(section); - for (i=0;d && i!=d->n;++i) { - const char * key = d->key[i]; - if (strncmp(section, key, len)==0 && key[len]==':') { - const char * str_value = d->val[i]; - char * endp; + size_t len = strlen(section); + + for (i = 0; d && i != d->n; ++i) { + const char *key = d->key[i]; + + if (strncmp(section, key, len) == 0 && key[len] == ':') { + const char *str_value = d->val[i]; + + char *endp; + double num_value = strtod(str_value, &endp); + lua_pushstring(L, key + len + 1); if (*endp) { tolua_pushstring(L, str_value); } else { tolua_pushnumber(L, num_value); } - lua_rawset(L,-3); + lua_rawset(L, -3); } } /* special case */ lua_pushstring(L, "basepath"); lua_pushstring(L, basepath()); - lua_rawset(L,-3); + lua_rawset(L, -3); } -int -tolua_eressea_open(lua_State* L) +int tolua_eressea_open(lua_State * L) { tolua_open(L); @@ -1128,17 +1228,21 @@ tolua_eressea_open(lua_State* L) } tolua_endmodule(L); - tolua_cclass(L, TOLUA_CAST "alliance", TOLUA_CAST "alliance", TOLUA_CAST "", NULL); + tolua_cclass(L, TOLUA_CAST "alliance", TOLUA_CAST "alliance", TOLUA_CAST "", + NULL); tolua_beginmodule(L, TOLUA_CAST "alliance"); { - tolua_variable(L, TOLUA_CAST "name", tolua_get_alliance_name, tolua_set_alliance_name); + tolua_variable(L, TOLUA_CAST "name", tolua_get_alliance_name, + tolua_set_alliance_name); tolua_variable(L, TOLUA_CAST "id", tolua_get_alliance_id, NULL); - tolua_variable(L, TOLUA_CAST "factions", &tolua_get_alliance_factions, NULL); + tolua_variable(L, TOLUA_CAST "factions", &tolua_get_alliance_factions, + NULL); tolua_function(L, TOLUA_CAST "create", tolua_alliance_create); } tolua_endmodule(L); - tolua_cclass(L, TOLUA_CAST "spell", TOLUA_CAST "spell", TOLUA_CAST "", NULL); + tolua_cclass(L, TOLUA_CAST "spell", TOLUA_CAST "spell", TOLUA_CAST "", + NULL); tolua_beginmodule(L, TOLUA_CAST "spell"); { tolua_function(L, TOLUA_CAST "__tostring", tolua_get_spell_name); @@ -1176,6 +1280,7 @@ tolua_eressea_open(lua_State* L) tolua_beginmodule(L, TOLUA_CAST "config"); { parse_inifile(L, global.inifile, "config"); + tolua_variable(L, TOLUA_CAST "locales", &config_get_locales, 0); tolua_function(L, TOLUA_CAST "get_resource", &config_get_resource); tolua_variable(L, TOLUA_CAST "ships", &config_get_ships, 0); @@ -1187,12 +1292,11 @@ tolua_eressea_open(lua_State* L) tolua_function(L, TOLUA_CAST "get_unit", tolua_get_unit); tolua_function(L, TOLUA_CAST "get_alliance", tolua_get_alliance); tolua_function(L, TOLUA_CAST "get_ship", tolua_get_ship), - tolua_function(L, TOLUA_CAST "get_building", tolua_get_building), - tolua_function(L, TOLUA_CAST "get_region", tolua_get_region), - - // deprecated_function(L, TOLUA_CAST "add_faction"); - // deprecated_function(L, TOLUA_CAST "faction_origin"); - tolua_function(L, TOLUA_CAST "factions", tolua_get_factions); + tolua_function(L, TOLUA_CAST "get_building", tolua_get_building), + tolua_function(L, TOLUA_CAST "get_region", tolua_get_region), + // deprecated_function(L, TOLUA_CAST "add_faction"); + // deprecated_function(L, TOLUA_CAST "faction_origin"); + tolua_function(L, TOLUA_CAST "factions", tolua_get_factions); tolua_function(L, TOLUA_CAST "regions", tolua_get_regions); tolua_function(L, TOLUA_CAST "read_turn", tolua_read_turn); @@ -1211,8 +1315,7 @@ tolua_eressea_open(lua_State* L) tolua_function(L, TOLUA_CAST "init_summary", tolua_init_summary); tolua_function(L, TOLUA_CAST "write_summary", tolua_write_summary); tolua_function(L, TOLUA_CAST "write_passwords", tolua_write_passwords), - - tolua_function(L, TOLUA_CAST "message_unit", tolua_message_unit); + tolua_function(L, TOLUA_CAST "message_unit", tolua_message_unit); tolua_function(L, TOLUA_CAST "message_faction", tolua_message_faction); tolua_function(L, TOLUA_CAST "message_region", tolua_message_region); @@ -1239,9 +1342,11 @@ tolua_eressea_open(lua_State* L) tolua_function(L, TOLUA_CAST "dice_roll", tolua_dice_rand); tolua_function(L, TOLUA_CAST "get_nmrs", tolua_get_nmrs); - tolua_function(L, TOLUA_CAST "remove_empty_units", tolua_remove_empty_units); + tolua_function(L, TOLUA_CAST "remove_empty_units", + tolua_remove_empty_units); - tolua_function(L, TOLUA_CAST "update_subscriptions", tolua_update_subscriptions); + tolua_function(L, TOLUA_CAST "update_subscriptions", + tolua_update_subscriptions); tolua_function(L, TOLUA_CAST "update_scores", tolua_update_scores); tolua_function(L, TOLUA_CAST "update_owners", tolua_update_owners); @@ -1261,7 +1366,7 @@ tolua_eressea_open(lua_State* L) tolua_function(L, TOLUA_CAST "write_spells", tolua_write_spells); tolua_function(L, TOLUA_CAST "read_xml", tolua_read_xml); - + } tolua_endmodule(L); return 1; diff --git a/src/bindings/bindings.h b/src/bindings/bindings.h index a289a9d90..d20e20555 100644 --- a/src/bindings/bindings.h +++ b/src/bindings/bindings.h @@ -16,15 +16,16 @@ extern "C" { struct lua_State; struct quicklist; - - int tolua_sqlite_open(struct lua_State * L); - int tolua_eressea_open(struct lua_State* L); + + int tolua_sqlite_open(struct lua_State *L); + int tolua_eressea_open(struct lua_State *L); int tolua_spelllist_next(struct lua_State *L); int tolua_itemlist_next(struct lua_State *L); int tolua_orderlist_next(struct lua_State *L); - int tolua_quicklist_push(struct lua_State *L, const char * list_type, const char * elem_type, struct quicklist * list); + int tolua_quicklist_push(struct lua_State *L, const char *list_type, + const char *elem_type, struct quicklist *list); - int log_lua_error(struct lua_State * L); + int log_lua_error(struct lua_State *L); #ifdef __cplusplus } #endif diff --git a/src/bindings/helpers.c b/src/bindings/helpers.c index 6395bce35..450264a52 100644 --- a/src/bindings/helpers.c +++ b/src/bindings/helpers.c @@ -36,14 +36,18 @@ without prior permission by the authors of Eressea. #include static int -lua_giveitem(unit * s, unit * d, const item_type * itype, int n, struct order * ord) +lua_giveitem(unit * s, unit * d, const item_type * itype, int n, + struct order *ord) { - lua_State * L = (lua_State *)global.vm_state; - char fname[64]; - int result = -1; - const char * iname = itype->rtype->_name[0]; + lua_State *L = (lua_State *) global.vm_state; - assert(s!=NULL); + char fname[64]; + + int result = -1; + + const char *iname = itype->rtype->_name[0]; + + assert(s != NULL); strcat(strcpy(fname, iname), "_give"); lua_pushstring(L, fname); @@ -52,12 +56,12 @@ lua_giveitem(unit * s, unit * d, const item_type * itype, int n, struct order * tolua_pushusertype(L, s, TOLUA_CAST "unit"); tolua_pushusertype(L, d, TOLUA_CAST "unit"); tolua_pushstring(L, iname); - tolua_pushnumber(L, (lua_Number)n); + tolua_pushnumber(L, (lua_Number) n); - if (lua_pcall(L, 4, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("unit %s calling '%s': %s.\n", - unitname(s), fname, error)); + if (lua_pcall(L, 4, 1, 0) != 0) { + const char *error = lua_tostring(L, -1); + + log_error(("unit %s calling '%s': %s.\n", unitname(s), fname, error)); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); @@ -65,19 +69,20 @@ lua_giveitem(unit * s, unit * d, const item_type * itype, int n, struct order * } } else { log_error(("unit %s trying to call '%s' : not a function.\n", - unitname(s), fname)); + unitname(s), fname)); lua_pop(L, 1); } return result; } -static int -limit_resource(const region * r, const resource_type * rtype) +static int limit_resource(const region * r, const resource_type * rtype) { char fname[64]; + int result = -1; - lua_State * L = (lua_State *)global.vm_state; + + lua_State *L = (lua_State *) global.vm_state; snprintf(fname, sizeof(fname), "%s_limit", rtype->_name[0]); @@ -86,10 +91,11 @@ limit_resource(const region * r, const resource_type * rtype) if (lua_isfunction(L, 1)) { tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); - if (lua_pcall(L, 1, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); + if (lua_pcall(L, 1, 1, 0) != 0) { + const char *error = lua_tostring(L, -1); + log_error(("limit(%s) calling '%s': %s.\n", - regionname(r, NULL), fname, error)); + regionname(r, NULL), fname, error)); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); @@ -97,7 +103,7 @@ limit_resource(const region * r, const resource_type * rtype) } } else { log_error(("limit(%s) calling '%s': not a function.\n", - regionname(r, NULL), fname)); + regionname(r, NULL), fname)); lua_pop(L, 1); } @@ -107,42 +113,48 @@ limit_resource(const region * r, const resource_type * rtype) static void produce_resource(region * r, const resource_type * rtype, int norders) { - lua_State * L = (lua_State *)global.vm_state; + lua_State *L = (lua_State *) global.vm_state; + char fname[64]; + snprintf(fname, sizeof(fname), "%s_produce", rtype->_name[0]); lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); if (lua_isfunction(L, 1)) { tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); - tolua_pushnumber(L, (lua_Number)norders); + tolua_pushnumber(L, (lua_Number) norders); + + if (lua_pcall(L, 2, 0, 0) != 0) { + const char *error = lua_tostring(L, -1); - if (lua_pcall(L, 2, 0, 0)!=0) { - const char* error = lua_tostring(L, -1); log_error(("produce(%s) calling '%s': %s.\n", - regionname(r, NULL), fname, error)); + regionname(r, NULL), fname, error)); lua_pop(L, 1); } } else { log_error(("produce(%s) calling '%s': not a function.\n", - regionname(r, NULL), fname)); + regionname(r, NULL), fname)); lua_pop(L, 1); } } -static int -lc_age(struct attrib * a) +static int lc_age(struct attrib *a) { - building_action * data = (building_action*)a->data.v; - const char * fname = data->fname; - const char * fparam = data->param; - building * b = data->b; + building_action *data = (building_action *) a->data.v; + + const char *fname = data->fname; + + const char *fparam = data->param; + + building *b = data->b; + int result = -1; - assert(b!=NULL); - if (fname!=NULL) { - lua_State * L = (lua_State *)global.vm_state; + assert(b != NULL); + if (fname != NULL) { + lua_State *L = (lua_State *) global.vm_state; lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); @@ -152,10 +164,11 @@ lc_age(struct attrib * a) tolua_pushstring(L, fparam); } - if (lua_pcall(L, fparam?2:1, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); + if (lua_pcall(L, fparam ? 2 : 1, 1, 0) != 0) { + const char *error = lua_tostring(L, -1); + log_error(("lc_age(%s) calling '%s': %s.\n", - buildingname(b), fname, error)); + buildingname(b), fname, error)); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); @@ -163,20 +176,25 @@ lc_age(struct attrib * a) } } else { log_error(("lc_age(%s) calling '%s': not a function.\n", - buildingname(b), fname)); + buildingname(b), fname)); lua_pop(L, 1); } } - return (result!=0)?AT_AGE_KEEP:AT_AGE_REMOVE; + return (result != 0) ? AT_AGE_KEEP : AT_AGE_REMOVE; } static void push_param(lua_State * L, char c, spllprm * param) { - if (c=='u') tolua_pushusertype(L, param->data.u, "unit"); - else if (c=='b') tolua_pushusertype(L, param->data.b, "building"); - else if (c=='s') tolua_pushusertype(L, param->data.sh, "ship"); - else if (c=='r') tolua_pushusertype(L, param->data.sh, "region"); - else if (c=='c') tolua_pushstring(L, param->data.s); + if (c == 'u') + tolua_pushusertype(L, param->data.u, "unit"); + else if (c == 'b') + tolua_pushusertype(L, param->data.b, "building"); + else if (c == 's') + tolua_pushusertype(L, param->data.sh, "ship"); + else if (c == 'r') + tolua_pushusertype(L, param->data.sh, "region"); + else if (c == 'c') + tolua_pushstring(L, param->data.s); else { log_error(("unsupported syntax %c.\n", c)); lua_pushnil(L); @@ -184,19 +202,24 @@ static void push_param(lua_State * L, char c, spllprm * param) } /** callback to use lua for spell functions */ -static int -lua_callspell(castorder *co) +static int lua_callspell(castorder * co) { - lua_State * L = (lua_State *)global.vm_state; - const char * fname = co->sp->sname; - unit * mage = co->familiar?co->familiar:co->magician.u; + lua_State *L = (lua_State *) global.vm_state; + + const char *fname = co->sp->sname; + + unit *mage = co->familiar ? co->familiar : co->magician.u; + int result = -1; - const char * hashpos = strchr(fname, '#'); + + const char *hashpos = strchr(fname, '#'); + char fbuf[64]; - if (hashpos!=NULL) { + if (hashpos != NULL) { ptrdiff_t len = hashpos - fname; - assert(len<(ptrdiff_t)sizeof(fbuf)); + + assert(len < (ptrdiff_t) sizeof(fbuf)); strncpy(fbuf, fname, len); fbuf[len] = '\0'; fname = fbuf; @@ -206,20 +229,25 @@ lua_callspell(castorder *co) lua_rawget(L, LUA_GLOBALSINDEX); if (lua_isfunction(L, 1)) { int nparam = 4; + tolua_pushusertype(L, co->rt, TOLUA_CAST "region"); tolua_pushusertype(L, mage, TOLUA_CAST "unit"); - tolua_pushnumber(L, (lua_Number)co->level); - tolua_pushnumber(L, (lua_Number)co->force); + tolua_pushnumber(L, (lua_Number) co->level); + tolua_pushnumber(L, (lua_Number) co->force); if (co->sp->parameter && co->par->length) { - const char * synp = co->sp->parameter; + const char *synp = co->sp->parameter; + int i = 0; + ++nparam; lua_newtable(L); - while (*synp&&ipar->length) { - spllprm * param = co->par->param[i]; + while (*synp && i < co->par->length) { + spllprm *param = co->par->param[i]; + char c = *synp; - if (c=='+') { - push_param(L, *(synp-1), param); + + if (c == '+') { + push_param(L, *(synp - 1), param); } else { push_param(L, c, param); ++synp; @@ -228,10 +256,11 @@ lua_callspell(castorder *co) } } - if (lua_pcall(L, nparam, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); + if (lua_pcall(L, nparam, 1, 0) != 0) { + const char *error = lua_tostring(L, -1); + log_error(("spell(%s) calling '%s': %s.\n", - unitname(mage), fname, error)); + unitname(mage), fname, error)); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); @@ -239,7 +268,7 @@ lua_callspell(castorder *co) } } else { log_error(("spell(%s) calling '%s': not a function.\n", - unitname(mage), fname)); + unitname(mage), fname)); lua_pop(L, 1); } @@ -247,12 +276,14 @@ lua_callspell(castorder *co) } /** callback to initialize a familiar from lua. */ -static void -lua_initfamiliar(unit * u) +static void lua_initfamiliar(unit * u) { - lua_State * L = (lua_State *)global.vm_state; + lua_State *L = (lua_State *) global.vm_state; + char fname[64]; + int result = -1; + snprintf(fname, sizeof(fname), "initfamiliar_%s", u->race->_name[0]); lua_pushstring(L, fname); @@ -260,10 +291,11 @@ lua_initfamiliar(unit * u) if (lua_isfunction(L, 1)) { tolua_pushusertype(L, u, TOLUA_CAST "unit"); - if (lua_pcall(L, 1, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); + if (lua_pcall(L, 1, 1, 0) != 0) { + const char *error = lua_tostring(L, -1); + log_error(("familiar(%s) calling '%s': %s.\n", - unitname(u), fname, error)); + unitname(u), fname, error)); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); @@ -271,7 +303,7 @@ lua_initfamiliar(unit * u) } } else { log_warning(("familiar(%s) calling '%s': not a function.\n", - unitname(u), fname)); + unitname(u), fname)); lua_pop(L, 1); } @@ -282,23 +314,26 @@ lua_initfamiliar(unit * u) } static int -lua_changeresource(unit * u, const struct resource_type * rtype, int delta) +lua_changeresource(unit * u, const struct resource_type *rtype, int delta) { - lua_State * L = (lua_State *)global.vm_state; + lua_State *L = (lua_State *) global.vm_state; + int result = -1; + char fname[64]; + snprintf(fname, sizeof(fname), "%s_changeresource", rtype->_name[0]); lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); if (lua_isfunction(L, 1)) { tolua_pushusertype(L, u, TOLUA_CAST "unit"); - tolua_pushnumber(L, (lua_Number)delta); + tolua_pushnumber(L, (lua_Number) delta); - if (lua_pcall(L, 2, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("change(%s) calling '%s': %s.\n", - unitname(u), fname, error)); + if (lua_pcall(L, 2, 1, 0) != 0) { + const char *error = lua_tostring(L, -1); + + log_error(("change(%s) calling '%s': %s.\n", unitname(u), fname, error)); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); @@ -306,19 +341,21 @@ lua_changeresource(unit * u, const struct resource_type * rtype, int delta) } } else { log_error(("change(%s) calling '%s': not a function.\n", - unitname(u), fname)); + unitname(u), fname)); lua_pop(L, 1); } return result; } -static int -lua_getresource(unit * u, const struct resource_type * rtype) +static int lua_getresource(unit * u, const struct resource_type *rtype) { - lua_State * L = (lua_State *)global.vm_state; + lua_State *L = (lua_State *) global.vm_state; + int result = -1; + char fname[64]; + snprintf(fname, sizeof(fname), "%s_getresource", rtype->_name[0]); lua_pushstring(L, fname); @@ -326,33 +363,33 @@ lua_getresource(unit * u, const struct resource_type * rtype) if (lua_isfunction(L, 1)) { tolua_pushusertype(L, u, TOLUA_CAST "unit"); - if (lua_pcall(L, 1, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("get(%s) calling '%s': %s.\n", - unitname(u), fname, error)); + if (lua_pcall(L, 1, 1, 0) != 0) { + const char *error = lua_tostring(L, -1); + + log_error(("get(%s) calling '%s': %s.\n", unitname(u), fname, error)); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); lua_pop(L, 1); } } else { - log_error(("get(%s) calling '%s': not a function.\n", - unitname(u), fname)); + log_error(("get(%s) calling '%s': not a function.\n", unitname(u), fname)); lua_pop(L, 1); } return result; } -static boolean -lua_canuse_item(const unit * u, const struct item_type * itype) +static boolean lua_canuse_item(const unit * u, const struct item_type *itype) { static int function_exists = 1; + boolean result = true; if (function_exists) { - lua_State * L = (lua_State *)global.vm_state; - const char * fname = "item_canuse"; + lua_State *L = (lua_State *) global.vm_state; + + const char *fname = "item_canuse"; lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); @@ -360,10 +397,10 @@ lua_canuse_item(const unit * u, const struct item_type * itype) tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); tolua_pushstring(L, itype->rtype->_name[0]); - if (lua_pcall(L, 2, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("get(%s) calling '%s': %s.\n", - unitname(u), fname, error)); + if (lua_pcall(L, 2, 1, 0) != 0) { + const char *error = lua_tostring(L, -1); + + log_error(("get(%s) calling '%s': %s.\n", unitname(u), fname, error)); lua_pop(L, 1); } else { result = lua_toboolean(L, -1); @@ -372,7 +409,7 @@ lua_canuse_item(const unit * u, const struct item_type * itype) } else { function_exists = 0; log_error(("get(%s) calling '%s': not a function.\n", - unitname(u), fname)); + unitname(u), fname)); lua_pop(L, 1); } } @@ -382,8 +419,10 @@ lua_canuse_item(const unit * u, const struct item_type * itype) static int lua_wage(const region * r, const faction * f, const race * rc, int in_turn) { - lua_State * L = (lua_State *)global.vm_state; - const char * fname = "wage"; + lua_State *L = (lua_State *) global.vm_state; + + const char *fname = "wage"; + int result = -1; lua_pushstring(L, fname); @@ -391,13 +430,14 @@ lua_wage(const region * r, const faction * f, const race * rc, int in_turn) if (lua_isfunction(L, 1)) { tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); tolua_pushusertype(L, (void *)f, TOLUA_CAST "faction"); - tolua_pushstring(L, rc?rc->_name[0]:0); - tolua_pushnumber(L, (lua_Number)in_turn); + tolua_pushstring(L, rc ? rc->_name[0] : 0); + tolua_pushnumber(L, (lua_Number) in_turn); + + if (lua_pcall(L, 3, 1, 0) != 0) { + const char *error = lua_tostring(L, -1); - if (lua_pcall(L, 3, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); log_error(("wage(%s) calling '%s': %s.\n", - regionname(r, NULL), fname, error)); + regionname(r, NULL), fname, error)); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); @@ -405,17 +445,17 @@ lua_wage(const region * r, const faction * f, const race * rc, int in_turn) } } else { log_error(("wage(%s) calling '%s': not a function.\n", - regionname(r, NULL), fname)); + regionname(r, NULL), fname)); lua_pop(L, 1); } return result; } -static void -lua_agebuilding(building * b) +static void lua_agebuilding(building * b) { - lua_State * L = (lua_State *)global.vm_state; + lua_State *L = (lua_State *) global.vm_state; + char fname[64]; snprintf(fname, sizeof(fname), "age_%s", b->type->_name); @@ -425,24 +465,26 @@ lua_agebuilding(building * b) if (lua_isfunction(L, 1)) { tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); - if (lua_pcall(L, 1, 0, 0)!=0) { - const char* error = lua_tostring(L, -1); + if (lua_pcall(L, 1, 0, 0) != 0) { + const char *error = lua_tostring(L, -1); + log_error(("agebuilding(%s) calling '%s': %s.\n", - buildingname(b), fname, error)); + buildingname(b), fname, error)); lua_pop(L, 1); } } else { log_error(("agebuilding(%s) calling '%s': not a function.\n", - buildingname(b), fname)); + buildingname(b), fname)); lua_pop(L, 1); } } -static int -lua_building_protection(building * b, unit * u) +static int lua_building_protection(building * b, unit * u) { - lua_State * L = (lua_State *)global.vm_state; - const char * fname = "building_protection"; + lua_State *L = (lua_State *) global.vm_state; + + const char *fname = "building_protection"; + int result = 0; lua_pushstring(L, fname); @@ -451,10 +493,11 @@ lua_building_protection(building * b, unit * u) tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); - if (lua_pcall(L, 2, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); + if (lua_pcall(L, 2, 1, 0) != 0) { + const char *error = lua_tostring(L, -1); + log_error(("building_protection(%s, %s) calling '%s': %s.\n", - buildingname(b), unitname(u), fname, error)); + buildingname(b), unitname(u), fname, error)); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); @@ -462,31 +505,34 @@ lua_building_protection(building * b, unit * u) } } else { log_error(("building_protection(%s, %s) calling '%s': not a function.\n", - buildingname(b), unitname(u), fname)); + buildingname(b), unitname(u), fname)); lua_pop(L, 1); } return result; } -static double -lua_building_taxes(building * b, int level) +static double lua_building_taxes(building * b, int level) { - lua_State * L = (lua_State *)global.vm_state; - const char * fname = "building_taxes"; + lua_State *L = (lua_State *) global.vm_state; + + const char *fname = "building_taxes"; + double result = 0.0F; + int type; lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); - type=lua_type(L, 1); + type = lua_type(L, 1); if (lua_isfunction(L, 1)) { tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); tolua_pushnumber(L, level); - if (lua_pcall(L, 2, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); + if (lua_pcall(L, 2, 1, 0) != 0) { + const char *error = lua_tostring(L, -1); + log_error(("building_taxes(%s) calling '%s': %s.\n", - buildingname(b), fname, error)); + buildingname(b), fname, error)); lua_pop(L, 1); } else { result = (double)lua_tonumber(L, -1); @@ -494,17 +540,18 @@ lua_building_taxes(building * b, int level) } } else { log_error(("building_taxes(%s) calling '%s': not a function.\n", - buildingname(b), fname)); + buildingname(b), fname)); lua_pop(L, 1); } return result; } -static int -lua_maintenance(const unit * u) +static int lua_maintenance(const unit * u) { - lua_State * L = (lua_State *)global.vm_state; - const char * fname = "maintenance"; + lua_State *L = (lua_State *) global.vm_state; + + const char *fname = "maintenance"; + int result = -1; lua_pushstring(L, fname); @@ -512,10 +559,11 @@ lua_maintenance(const unit * u) if (lua_isfunction(L, 1)) { tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); - if (lua_pcall(L, 1, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); + if (lua_pcall(L, 1, 1, 0) != 0) { + const char *error = lua_tostring(L, -1); + log_error(("maintenance(%s) calling '%s': %s.\n", - unitname(u), fname, error)); + unitname(u), fname, error)); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); @@ -523,19 +571,21 @@ lua_maintenance(const unit * u) } } else { log_error(("maintenance(%s) calling '%s': not a function.\n", - unitname(u), fname)); + unitname(u), fname)); lua_pop(L, 1); } return result; } -static void -lua_equipmentcallback(const struct equipment * eq, unit * u) +static void lua_equipmentcallback(const struct equipment *eq, unit * u) { - lua_State * L = (lua_State *)global.vm_state; + lua_State *L = (lua_State *) global.vm_state; + char fname[64]; + int result = -1; + snprintf(fname, sizeof(fname), "equip_%s", eq->name); lua_pushstring(L, fname); @@ -543,10 +593,10 @@ lua_equipmentcallback(const struct equipment * eq, unit * u) if (lua_isfunction(L, 1)) { tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); - if (lua_pcall(L, 1, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("equip(%s) calling '%s': %s.\n", - unitname(u), fname, error)); + if (lua_pcall(L, 1, 1, 0) != 0) { + const char *error = lua_tostring(L, -1); + + log_error(("equip(%s) calling '%s': %s.\n", unitname(u), fname, error)); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); @@ -554,111 +604,127 @@ lua_equipmentcallback(const struct equipment * eq, unit * u) } } else { log_error(("equip(%s) calling '%s': not a function.\n", - unitname(u), fname)); + unitname(u), fname)); lua_pop(L, 1); } } /** callback for an item-use function written in lua. */ int -lua_useitem(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +lua_useitem(struct unit *u, const struct item_type *itype, int amount, + struct order *ord) { - lua_State * L = (lua_State *)global.vm_state; + lua_State *L = (lua_State *) global.vm_state; + int result = 0; + char fname[64]; + snprintf(fname, sizeof(fname), "use_%s", itype->rtype->_name[0]); lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); if (lua_isfunction(L, 1)) { tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); - tolua_pushnumber(L, (lua_Number)amount); + tolua_pushnumber(L, (lua_Number) amount); - if (lua_pcall(L, 2, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("use(%s) calling '%s': %s.\n", - unitname(u), fname, error)); + if (lua_pcall(L, 2, 1, 0) != 0) { + const char *error = lua_tostring(L, -1); + + log_error(("use(%s) calling '%s': %s.\n", unitname(u), fname, error)); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); lua_pop(L, 1); } } else { - log_error(("use(%s) calling '%s': not a function.\n", - unitname(u), fname)); + log_error(("use(%s) calling '%s': not a function.\n", unitname(u), fname)); lua_pop(L, 1); } return result; } -static int -lua_recruit(struct unit * u, const struct archetype * arch, int amount) +static int lua_recruit(struct unit *u, const struct archetype *arch, int amount) { - lua_State * L = (lua_State *)global.vm_state; + lua_State *L = (lua_State *) global.vm_state; + int result = 0; + char fname[64]; + snprintf(fname, sizeof(fname), "recruit_%s", arch->name[0]); lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); if (lua_isfunction(L, 1)) { tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); - tolua_pushnumber(L, (lua_Number)amount); + tolua_pushnumber(L, (lua_Number) amount); - if (lua_pcall(L, 2, 1, 0)!=0) { - const char* error = lua_tostring(L, -1); - log_error(("use(%s) calling '%s': %s.\n", - unitname(u), fname, error)); + if (lua_pcall(L, 2, 1, 0) != 0) { + const char *error = lua_tostring(L, -1); + + log_error(("use(%s) calling '%s': %s.\n", unitname(u), fname, error)); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); lua_pop(L, 1); } } else { - log_error(("use(%s) calling '%s': not a function.\n", - unitname(u), fname)); + log_error(("use(%s) calling '%s': not a function.\n", unitname(u), fname)); lua_pop(L, 1); } return result; } -int -tolua_toid(lua_State* L, int idx, int def) +int tolua_toid(lua_State * L, int idx, int def) { int no = 0; + int type = lua_type(L, idx); - if (type==LUA_TNUMBER) { + + if (type == LUA_TNUMBER) { no = (int)tolua_tonumber(L, idx, def); } else { - const char * str = tolua_tostring(L, idx, NULL); - no = str?atoi36(str):def; + const char *str = tolua_tostring(L, idx, NULL); + + no = str ? atoi36(str) : def; } return no; } -void -register_tolua_helpers(void) +void register_tolua_helpers(void) { at_building_action.age = lc_age; - register_function((pf_generic)&lua_building_protection, TOLUA_CAST "lua_building_protection"); - register_function((pf_generic)&lua_building_taxes, TOLUA_CAST "lua_building_taxes"); - register_function((pf_generic)&lua_agebuilding, TOLUA_CAST "lua_agebuilding"); - register_function((pf_generic)&lua_recruit, TOLUA_CAST "lua_recruit"); - register_function((pf_generic)&lua_callspell, TOLUA_CAST "lua_castspell"); - register_function((pf_generic)&lua_initfamiliar, TOLUA_CAST "lua_initfamiliar"); + register_function((pf_generic) & lua_building_protection, + TOLUA_CAST "lua_building_protection"); + register_function((pf_generic) & lua_building_taxes, + TOLUA_CAST "lua_building_taxes"); + register_function((pf_generic) & lua_agebuilding, + TOLUA_CAST "lua_agebuilding"); + register_function((pf_generic) & lua_recruit, TOLUA_CAST "lua_recruit"); + register_function((pf_generic) & lua_callspell, TOLUA_CAST "lua_castspell"); + register_function((pf_generic) & lua_initfamiliar, + TOLUA_CAST "lua_initfamiliar"); register_item_use(&lua_useitem, TOLUA_CAST "lua_useitem"); - register_function((pf_generic)&lua_getresource, TOLUA_CAST "lua_getresource"); - register_function((pf_generic)&lua_canuse_item, TOLUA_CAST "lua_canuse_item"); - register_function((pf_generic)&lua_changeresource, TOLUA_CAST "lua_changeresource"); - register_function((pf_generic)&lua_equipmentcallback, TOLUA_CAST "lua_equip"); + register_function((pf_generic) & lua_getresource, + TOLUA_CAST "lua_getresource"); + register_function((pf_generic) & lua_canuse_item, + TOLUA_CAST "lua_canuse_item"); + register_function((pf_generic) & lua_changeresource, + TOLUA_CAST "lua_changeresource"); + register_function((pf_generic) & lua_equipmentcallback, + TOLUA_CAST "lua_equip"); - register_function((pf_generic)&lua_wage, TOLUA_CAST "lua_wage"); - register_function((pf_generic)&lua_maintenance, TOLUA_CAST "lua_maintenance"); + register_function((pf_generic) & lua_wage, TOLUA_CAST "lua_wage"); + register_function((pf_generic) & lua_maintenance, + TOLUA_CAST "lua_maintenance"); - register_function((pf_generic)produce_resource, TOLUA_CAST "lua_produceresource"); - register_function((pf_generic)limit_resource, TOLUA_CAST "lua_limitresource"); + register_function((pf_generic) produce_resource, + TOLUA_CAST "lua_produceresource"); + register_function((pf_generic) limit_resource, + TOLUA_CAST "lua_limitresource"); register_item_give(lua_giveitem, TOLUA_CAST "lua_giveitem"); } diff --git a/src/bindings/helpers.h b/src/bindings/helpers.h index 8d3370650..acf0d0d73 100644 --- a/src/bindings/helpers.h +++ b/src/bindings/helpers.h @@ -13,10 +13,10 @@ without prior permission by the authors of Eressea. #ifdef __cplusplus extern "C" { #endif - + struct lua_State; void register_tolua_helpers(void); - int tolua_toid(struct lua_State* L, int idx, int def); + int tolua_toid(struct lua_State *L, int idx, int def); #ifdef __cplusplus } diff --git a/src/eressea.c b/src/eressea.c index 3a8dd4740..8ab2bbf3a 100644 --- a/src/eressea.c +++ b/src/eressea.c @@ -52,43 +52,44 @@ static const struct { - const char * name; - int (*func)(lua_State *); + const char *name; + int (*func) (lua_State *); } lualibs[] = { - {"", luaopen_base}, - {LUA_TABLIBNAME, luaopen_table}, - {LUA_IOLIBNAME, luaopen_io}, - {LUA_STRLIBNAME, luaopen_string}, - {LUA_MATHLIBNAME, luaopen_math}, - {LUA_LOADLIBNAME, luaopen_package}, - {LUA_DBLIBNAME, luaopen_debug}, + { + "", luaopen_base}, { + LUA_TABLIBNAME, luaopen_table}, { + LUA_IOLIBNAME, luaopen_io}, { + LUA_STRLIBNAME, luaopen_string}, { + LUA_MATHLIBNAME, luaopen_math}, { + LUA_LOADLIBNAME, luaopen_package}, { + LUA_DBLIBNAME, luaopen_debug}, #if LUA_VERSION_NUM>=501 - {LUA_OSLIBNAME, luaopen_os}, + { + LUA_OSLIBNAME, luaopen_os}, #endif - { NULL, NULL } + { + NULL, NULL} }; -static void -openlibs(lua_State * L) +static void openlibs(lua_State * L) { int i; - for (i=0;lualibs[i].func;++i) { + + for (i = 0; lualibs[i].func; ++i) { lua_pushcfunction(L, lualibs[i].func); lua_pushstring(L, lualibs[i].name); lua_call(L, 1, 0); } } -static void -lua_done(lua_State * L) +static void lua_done(lua_State * L) { lua_close(L); } -static lua_State * -lua_init(void) +static lua_State *lua_init(void) { - lua_State * L = lua_open(); + lua_State *L = lua_open(); openlibs(L); #ifdef BINDINGS_TOLUA @@ -110,14 +111,13 @@ lua_init(void) return L; } -static void -game_done(void) +static void game_done(void) { #ifdef CLEANUP_CODE /* Diese Routine enfernt allen allokierten Speicher wieder. Das ist nur - * zum Debugging interessant, wenn man Leak Detection hat, und nach - * nicht freigegebenem Speicher sucht, der nicht bis zum Ende benötigt - * wird (temporäre Hilsstrukturen) */ + * zum Debugging interessant, wenn man Leak Detection hat, und nach + * nicht freigegebenem Speicher sucht, der nicht bis zum Ende benötigt + * wird (temporäre Hilsstrukturen) */ free_game(); @@ -129,8 +129,7 @@ game_done(void) #endif } -static void -game_init(void) +static void game_init(void) { register_triggers(); register_xmas(); @@ -169,6 +168,7 @@ game_init(void) int eressea_init(void) { global.vm_state = lua_init(); + kernel_init(); game_init(); @@ -179,13 +179,15 @@ void eressea_done(void) { game_done(); kernel_done(); - lua_done((lua_State *)global.vm_state); + lua_done((lua_State *) global.vm_state); } -int eressea_run(const char * luafile, const char * entry_point) +int eressea_run(const char *luafile, const char *entry_point) { int err; - lua_State * L = (lua_State *)global.vm_state; + + lua_State *L = (lua_State *) global.vm_state; + /* run the main script */ if (luafile) { lua_getglobal(L, "dofile"); diff --git a/src/eressea.h b/src/eressea.h index c2d15d458..692255a9b 100644 --- a/src/eressea.h +++ b/src/eressea.h @@ -4,12 +4,11 @@ extern "C" { #endif -int eressea_init(void); -void eressea_done(void); -int eressea_run(const char * luafile, const char * entry_point); + int eressea_init(void); + void eressea_done(void); + int eressea_run(const char *luafile, const char *entry_point); #ifdef __cplusplus } #endif - #endif diff --git a/src/gamecode/archetype.c b/src/gamecode/archetype.c index 8f82e7d31..010ed0612 100644 --- a/src/gamecode/archetype.c +++ b/src/gamecode/archetype.c @@ -24,100 +24,113 @@ #include #include -static struct archetype * archetypes; +static struct archetype *archetypes; struct attrib_type at_recruit = { "recruit", NULL, NULL, NULL, NULL, NULL, ATF_UNIQUE }; -const struct archetype * -find_archetype(const char * s, const struct locale * lang) +const struct archetype *find_archetype(const char *s, const struct locale *lang) { - struct tnode * tokens = get_translations(lang, UT_ARCHETYPES); + struct tnode *tokens = get_translations(lang, UT_ARCHETYPES); + variant token; - if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { + if (findtoken(tokens, s, &token) == E_TOK_SUCCESS) { return (const struct archetype *)token.v; } return NULL; } -void -register_archetype(archetype * arch) +void register_archetype(archetype * arch) { arch->next = archetypes; archetypes = arch; } -void -init_archetypes(void) +void init_archetypes(void) { - const struct locale * lang = locales; - for (;lang;lang=nextlocale(lang)) { + const struct locale *lang = locales; + + for (; lang; lang = nextlocale(lang)) { variant var; - archetype * arch = archetypes; - struct tnode * tokens = get_translations(lang, UT_ARCHETYPES); - for (;arch;arch=arch->next) { + + archetype *arch = archetypes; + + struct tnode *tokens = get_translations(lang, UT_ARCHETYPES); + + for (; arch; arch = arch->next) { const char *s1, *s2; + var.v = arch; s1 = LOC(lang, arch->name[0]); addtoken(tokens, s1, var); s2 = LOC(lang, arch->name[1]); - if (strcmp(s2, s1)!=0) { + if (strcmp(s2, s1) != 0) { addtoken(tokens, s2, var); } } } } -static int -parse_archetypes(xmlDocPtr doc) +static int parse_archetypes(xmlDocPtr doc) { char zName[64]; + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr result = xmlXPathEvalExpression(BAD_CAST "/eressea/archetypes/archetype", xpath); + + xmlXPathObjectPtr result = + xmlXPathEvalExpression(BAD_CAST "/eressea/archetypes/archetype", xpath); xmlNodeSetPtr nodes = result->nodesetval; - xmlChar * propValue; + xmlChar *propValue; + if (nodes) { int i; - for (i=0;i!=nodes->nodeNr;++i) { + + for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; + xmlNodePtr child; - archetype * arch = calloc(1, sizeof(archetype)); + + archetype *arch = calloc(1, sizeof(archetype)); + xmlXPathObjectPtr sub; propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); + assert(propValue != NULL); arch->name[0] = strdup((const char *)propValue); sprintf(zName, "%s_p", arch->name[0]); arch->name[1] = strdup(zName); xmlFree(propValue); propValue = xmlGetProp(node, BAD_CAST "equip"); - if (propValue!=NULL) { - arch->equip = get_equipment((const char*)propValue); + if (propValue != NULL) { + arch->equip = get_equipment((const char *)propValue); xmlFree(propValue); } else { arch->equip = get_equipment(arch->name[0]); } propValue = xmlGetProp(node, BAD_CAST "building"); - if (propValue!=NULL) { - arch->btype = bt_find((const char*)propValue); + if (propValue != NULL) { + arch->btype = bt_find((const char *)propValue); xmlFree(propValue); } arch->size = xml_ivalue(node, "cost", 0); - for (child=node->children;child;child=child->next) { - if (strcmp((const char *)child->name, "function")==0) { - xmlChar * propName = xmlGetProp(child, BAD_CAST "name"); - xmlChar * propValue = xmlGetProp(child, BAD_CAST "value"); + for (child = node->children; child; child = child->next) { + if (strcmp((const char *)child->name, "function") == 0) { + xmlChar *propName = xmlGetProp(child, BAD_CAST "name"); + + xmlChar *propValue = xmlGetProp(child, BAD_CAST "value"); + if (strcmp((const char *)propName, "create")) { pf_generic foo = get_function((const char *)propValue); - arch->exec = (archetype_function)foo; + + arch->exec = (archetype_function) foo; } xmlFree(propValue); xmlFree(propName); @@ -127,10 +140,12 @@ parse_archetypes(xmlDocPtr doc) sub = xmlXPathEvalExpression(BAD_CAST "allow|deny", xpath); if (sub->nodesetval && sub->nodesetval->nodeNr) { int k; - arch->rules = calloc(sub->nodesetval->nodeNr+1, sizeof(rule)); - for (k=0;k!=sub->nodesetval->nodeNr;++k) { + + arch->rules = calloc(sub->nodesetval->nodeNr + 1, sizeof(rule)); + for (k = 0; k != sub->nodesetval->nodeNr; ++k) { xmlNodePtr rule = sub->nodesetval->nodeTab[k]; - arch->rules[k].allow = (rule->name[0]=='a'); + + arch->rules[k].allow = (rule->name[0] == 'a'); propValue = xmlGetProp(rule, BAD_CAST "property"); arch->rules[k].property = strdup((const char *)propValue); @@ -158,8 +173,7 @@ parse_archetypes(xmlDocPtr doc) return 0; } -void -register_archetypes(void) +void register_archetypes(void) { xml_register_callback(parse_archetypes); } diff --git a/src/gamecode/archetype.h b/src/gamecode/archetype.h index 358946ccd..963acd286 100644 --- a/src/gamecode/archetype.h +++ b/src/gamecode/archetype.h @@ -19,27 +19,29 @@ extern "C" { typedef struct rule { boolean allow; - char * property; - char * value; + char *property; + char *value; } rule; struct archetype; - typedef int (*archetype_function)(struct unit * u, const struct archetype *, int); + typedef int (*archetype_function) (struct unit * u, const struct archetype *, + int); typedef struct archetype { - struct archetype * next; - char * name[2]; + struct archetype *next; + char *name[2]; int size; - struct building_type * btype; - struct equipment * equip; - struct construction * ctype; - struct rule * rules; + struct building_type *btype; + struct equipment *equip; + struct construction *ctype; + struct rule *rules; archetype_function exec; } archetype; - extern const struct archetype * find_archetype(const char * s, const struct locale * lang); + extern const struct archetype *find_archetype(const char *s, + const struct locale *lang); extern void init_archetypes(void); - extern void register_archetype(struct archetype * arch); + extern void register_archetype(struct archetype *arch); extern void register_archetypes(void); extern struct attrib_type at_recruit; @@ -47,5 +49,4 @@ extern "C" { #ifdef __cplusplus } #endif - #endif diff --git a/src/gamecode/creation.c b/src/gamecode/creation.c index b22dedaa8..4f0eb9b98 100644 --- a/src/gamecode/creation.c +++ b/src/gamecode/creation.c @@ -49,8 +49,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -faction * -createmonsters(int no) +faction *createmonsters(int no) { faction *f = findfaction(no); @@ -61,12 +60,12 @@ createmonsters(int no) f = (faction *) calloc(1, sizeof(faction)); f->no = no; /* alles ist auf null gesetzt, ausser dem folgenden. achtung - partei - * no 0 muss keine orders einreichen! */ + * no 0 muss keine orders einreichen! */ f->email = strdup("monsters@eressea.de"); f->name = strdup("Monster"); f->alive = 1; - f->options = (char)(1<options = (char)(1 << O_REPORT); addlist(&factions, f); fhash(f); return f; diff --git a/src/gamecode/creation.h b/src/gamecode/creation.h index 19c2667ae..47146d303 100644 --- a/src/gamecode/creation.h +++ b/src/gamecode/creation.h @@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -struct faction * createmonsters(int no); + struct faction *createmonsters(int no); #ifdef __cplusplus } diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index a216b37e0..2eab910d0 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -78,6 +78,7 @@ without prior permission by the authors of Eressea. /* imports */ extern int verbosity; + boolean opt_cr_absolute_coords = false; /* globals */ @@ -85,11 +86,12 @@ boolean opt_cr_absolute_coords = false; #define TAG_LOCALE "de" #ifdef TAG_LOCALE -static const char * -crtag(const char * key) +static const char *crtag(const char *key) { - static const struct locale * lang = NULL; - if (!lang) lang = find_locale(TAG_LOCALE); + static const struct locale *lang = NULL; + + if (!lang) + lang = find_locale(TAG_LOCALE); return locale_string(lang, key); } #else @@ -99,26 +101,30 @@ crtag(const char * key) * translation table */ typedef struct translation { - struct translation * next; - char * key; - const char * value; + struct translation *next; + char *key; + const char *value; } translation; #define TRANSMAXHASH 257 -static translation * translation_table[TRANSMAXHASH]; -static translation * junkyard; +static translation *translation_table[TRANSMAXHASH]; -static const char * -add_translation(const char * key, const char * value) +static translation *junkyard; + +static const char *add_translation(const char *key, const char *value) { int kk = ((key[0] << 5) + key[0]) % TRANSMAXHASH; - translation * t = translation_table[kk]; - while (t && strcmp(t->key, key)!=0) t=t->next; + + translation *t = translation_table[kk]; + + while (t && strcmp(t->key, key) != 0) + t = t->next; if (!t) { if (junkyard) { t = junkyard; junkyard = junkyard->next; - } else t = malloc(sizeof(translation)); + } else + t = malloc(sizeof(translation)); t->key = strdup(key); t->value = value; t->next = translation_table[kk]; @@ -127,13 +133,14 @@ add_translation(const char * key, const char * value) return crtag(key); } -static void -write_translations(FILE * F) +static void write_translations(FILE * F) { int i; + fputs("TRANSLATION\n", F); - for (i=0;i!=TRANSMAXHASH;++i) { - translation * t = translation_table[i]; + for (i = 0; i != TRANSMAXHASH; ++i) { + translation *t = translation_table[i]; + while (t) { fprintf(F, "\"%s\";%s\n", t->value, crtag(t->key)); t = t->next; @@ -141,14 +148,16 @@ write_translations(FILE * F) } } -static void -reset_translations(void) +static void reset_translations(void) { int i; - for (i=0;i!=TRANSMAXHASH;++i) { - translation * t = translation_table[i]; + + for (i = 0; i != TRANSMAXHASH; ++i) { + translation *t = translation_table[i]; + while (t) { - translation * c = t->next; + translation *c = t->next; + free(t->key); t->next = junkyard; junkyard = t; @@ -160,25 +169,30 @@ reset_translations(void) #include -static void -print_items(FILE * F, item * items, const struct locale * lang) +static void print_items(FILE * F, item * items, const struct locale *lang) { - item * itm; + item *itm; - for (itm=items; itm; itm=itm->next) { + for (itm = items; itm; itm = itm->next) { int in = itm->number; - const char * ic = resourcename(itm->type->rtype, 0); - if (itm==items) fputs("GEGENSTAENDE\n", F); + + const char *ic = resourcename(itm->type->rtype, 0); + + if (itm == items) + fputs("GEGENSTAENDE\n", F); fprintf(F, "%d;%s\n", in, add_translation(ic, LOC(lang, ic))); } } static void -cr_output_curses(FILE * F, const faction * viewer, const void * obj, typ_t typ) +cr_output_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ) { boolean header = false; + attrib *a = NULL; + int self = 0; + region *r; /* Die Sichtbarkeit eines Zaubers und die Zaubermeldung sind bei @@ -186,16 +200,19 @@ cr_output_curses(FILE * F, const faction * viewer, const void * obj, typ_t typ) * Bei Einheiten sieht man Wirkungen auf eigene Einheiten immer. * Spezialfälle (besonderes Talent, verursachender Magier usw. werde * bei jedem curse gesondert behandelt. */ - if (typ == TYP_SHIP){ - ship * sh = (ship*)obj; - unit * owner = shipowner(sh); + if (typ == TYP_SHIP) { + ship *sh = (ship *) obj; + + unit *owner = shipowner(sh); + a = sh->attribs; r = sh->region; if (owner != NULL) { - if (owner->faction == viewer){ + if (owner->faction == viewer) { self = 2; - } else { /* steht eine person der Partei auf dem Schiff? */ + } else { /* steht eine person der Partei auf dem Schiff? */ unit *u = NULL; + for (u = r->units; u; u = u->next) { if (u->ship == sh) { self = 1; @@ -205,15 +222,18 @@ cr_output_curses(FILE * F, const faction * viewer, const void * obj, typ_t typ) } } } else if (typ == TYP_BUILDING) { - building * b = (building*)obj; - unit * owner = building_owner(b); + building *b = (building *) obj; + + unit *owner = building_owner(b); + a = b->attribs; r = b->region; - if (owner != NULL){ - if (owner->faction == viewer){ + if (owner != NULL) { + if (owner->faction == viewer) { self = 2; - } else { /* steht eine Person der Partei in der Burg? */ + } else { /* steht eine Person der Partei in der Burg? */ unit *u = NULL; + for (u = r->units; u; u = u->next) { if (u->building == b) { self = 1; @@ -223,14 +243,15 @@ cr_output_curses(FILE * F, const faction * viewer, const void * obj, typ_t typ) } } } else if (typ == TYP_UNIT) { - unit *u = (unit *)obj; + unit *u = (unit *) obj; + a = u->attribs; r = u->region; if (u->faction == viewer) { self = 2; } } else if (typ == TYP_REGION) { - r = (region *)obj; + r = (region *) obj; a = r->attribs; } else { /* fehler */ @@ -238,8 +259,9 @@ cr_output_curses(FILE * F, const faction * viewer, const void * obj, typ_t typ) while (a) { if (fval(a->type, ATF_CURSE)) { - curse * c = (curse *)a->data.v; - message * msg; + curse *c = (curse *) a->data.v; + + message *msg; if (c->type->cansee) { self = c->type->cansee(viewer, obj, typ, c, self); @@ -248,6 +270,7 @@ cr_output_curses(FILE * F, const faction * viewer, const void * obj, typ_t typ) if (msg) { char buf[BUFFERSIZE]; + if (!header) { header = 1; fputs("EFFECTS\n", F); @@ -256,61 +279,67 @@ cr_output_curses(FILE * F, const faction * viewer, const void * obj, typ_t typ) fprintf(F, "\"%s\"\n", buf); msg_release(msg); } - } else if (a->type==&at_effect && self) { - effect_data * data = (effect_data *)a->data.v; - if (data->value>0) { - const char * key = resourcename(data->type->itype->rtype, 0); + } else if (a->type == &at_effect && self) { + effect_data *data = (effect_data *) a->data.v; + + if (data->value > 0) { + const char *key = resourcename(data->type->itype->rtype, 0); + if (!header) { header = 1; fputs("EFFECTS\n", F); } - fprintf(F, "\"%d %s\"\n", data->value, add_translation(key, locale_string(default_locale, key))); + fprintf(F, "\"%d %s\"\n", data->value, add_translation(key, + locale_string(default_locale, key))); } } a = a->next; } } -static int -cr_unit(variant var, char * buffer, const void * userdata) +static int cr_unit(variant var, char *buffer, const void *userdata) { - unit * u = (unit *)var.v; - sprintf(buffer, "%d", u?u->no:-1); + unit *u = (unit *) var.v; + + sprintf(buffer, "%d", u ? u->no : -1); return 0; } -static int -cr_ship(variant var, char * buffer, const void * userdata) +static int cr_ship(variant var, char *buffer, const void *userdata) { - ship * u = (ship *)var.v; - sprintf(buffer, "%d", u?u->no:-1); + ship *u = (ship *) var.v; + + sprintf(buffer, "%d", u ? u->no : -1); return 0; } -static int -cr_building(variant var, char * buffer, const void * userdata) +static int cr_building(variant var, char *buffer, const void *userdata) { - building * u = (building *)var.v; - sprintf(buffer, "%d", u?u->no:-1); + building *u = (building *) var.v; + + sprintf(buffer, "%d", u ? u->no : -1); return 0; } -static int -cr_faction(variant var, char * buffer, const void * userdata) +static int cr_faction(variant var, char *buffer, const void *userdata) { - faction * f = (faction *)var.v; - sprintf(buffer, "%d", f?f->no:-1); + faction *f = (faction *) var.v; + + sprintf(buffer, "%d", f ? f->no : -1); return 0; } -static int -cr_region(variant var, char * buffer, const void * userdata) +static int cr_region(variant var, char *buffer, const void *userdata) { - const faction * report = (const faction*)userdata; - region * r = (region *)var.v; + const faction *report = (const faction *)userdata; + + region *r = (region *) var.v; + if (r) { - plane * pl = rplane(r); + plane *pl = rplane(r); + int nx = r->x, ny = r->y; + pnormalize(&nx, &ny, pl); adjust_coordinates(report, &nx, &ny, pl, r); sprintf(buffer, "%d %d %d", nx, ny, plane_id(pl)); @@ -319,13 +348,15 @@ cr_region(variant var, char * buffer, const void * userdata) return -1; } -static int -cr_resource(variant var, char * buffer, const void * userdata) +static int cr_resource(variant var, char *buffer, const void *userdata) { - const faction * report = (const faction*)userdata; - const resource_type * r = (const resource_type *)var.v; + const faction *report = (const faction *)userdata; + + const resource_type *r = (const resource_type *)var.v; + if (r) { - const char * key = resourcename(r, 0); + const char *key = resourcename(r, 0); + sprintf(buffer, "\"%s\"", add_translation(key, locale_string(report->locale, key))); return 0; @@ -333,104 +364,124 @@ cr_resource(variant var, char * buffer, const void * userdata) return -1; } -static int -cr_race(variant var, char * buffer, const void * userdata) +static int cr_race(variant var, char *buffer, const void *userdata) { - const faction * report = (const faction*)userdata; - const struct race * rc = (const race *)var.v; - const char * key = rc_name(rc, 0); + const faction *report = (const faction *)userdata; + + const struct race *rc = (const race *)var.v; + + const char *key = rc_name(rc, 0); + sprintf(buffer, "\"%s\"", add_translation(key, locale_string(report->locale, key))); return 0; } -static int -cr_alliance(variant var, char * buffer, const void * userdata) +static int cr_alliance(variant var, char *buffer, const void *userdata) { - const alliance * al = (const alliance *)var.v; - if (al!=NULL) { + const alliance *al = (const alliance *)var.v; + + if (al != NULL) { sprintf(buffer, "%d", al->id); } unused(userdata); return 0; } -static int -cr_skill(variant var, char * buffer, const void * userdata) +static int cr_skill(variant var, char *buffer, const void *userdata) { - const faction * report = (const faction*)userdata; - skill_t sk = (skill_t)var.i; - if (sk!=NOSKILL) sprintf(buffer, "\"%s\"", - add_translation(mkname("skill", skillnames[sk]), skillname(sk, report->locale))); - else strcpy(buffer, "\"\""); + const faction *report = (const faction *)userdata; + + skill_t sk = (skill_t) var.i; + + if (sk != NOSKILL) + sprintf(buffer, "\"%s\"", + add_translation(mkname("skill", skillnames[sk]), skillname(sk, + report->locale))); + else + strcpy(buffer, "\"\""); return 0; } -static int -cr_order(variant var, char * buffer, const void * userdata) +static int cr_order(variant var, char *buffer, const void *userdata) { - order * ord = (order*)var.v; - if (ord!=NULL) { - char * wp = buffer; - char * cmd = getcommand(ord); - const char * rp = cmd; + order *ord = (order *) var.v; + + if (ord != NULL) { + char *wp = buffer; + + char *cmd = getcommand(ord); + + const char *rp = cmd; *wp++ = '\"'; while (*rp) { switch (*rp) { - case '\"': - case '\\': - *wp++ = '\\'; - default: - *wp++ = *rp++; + case '\"': + case '\\': + *wp++ = '\\'; + default: + *wp++ = *rp++; } } *wp++ = '\"'; *wp++ = 0; free(cmd); - } - else strcpy(buffer, "\"\""); + } else + strcpy(buffer, "\"\""); return 0; } -static int -cr_resources(variant var, char * buffer, const void * userdata) +static int cr_resources(variant var, char *buffer, const void *userdata) { - faction * f = (faction*)userdata; - resource * rlist = (resource*)var.v; - char * wp = buffer; - if (rlist!=NULL) { - const char * name = resourcename(rlist->type, rlist->number!=1); - wp += sprintf(wp, "\"%d %s", rlist->number, add_translation(name, LOC(f->locale, name))); + faction *f = (faction *) userdata; + + resource *rlist = (resource *) var.v; + + char *wp = buffer; + + if (rlist != NULL) { + const char *name = resourcename(rlist->type, rlist->number != 1); + + wp += + sprintf(wp, "\"%d %s", rlist->number, add_translation(name, LOC(f->locale, + name))); for (;;) { rlist = rlist->next; - if (rlist==NULL) break; - name = resourcename(rlist->type, rlist->number!=1); - wp += sprintf(wp, ", %d %s", rlist->number, add_translation(name, LOC(f->locale, name))); + if (rlist == NULL) + break; + name = resourcename(rlist->type, rlist->number != 1); + wp += + sprintf(wp, ", %d %s", rlist->number, add_translation(name, + LOC(f->locale, name))); } strcat(wp, "\""); } return 0; } -static int -cr_regions(variant var, char * buffer, const void * userdata) +static int cr_regions(variant var, char *buffer, const void *userdata) { - faction * f = (faction*)userdata; - const arg_regions * rdata = (const arg_regions *)var.v; + faction *f = (faction *) userdata; + + const arg_regions *rdata = (const arg_regions *)var.v; + + if (rdata != NULL && rdata->nregions > 0) { + region *r = rdata->regions[0]; + + plane *pl = rplane(r); - if (rdata!=NULL && rdata->nregions>0) { - region * r = rdata->regions[0]; - plane * pl = rplane(r); int i, z = plane_id(pl); - char * wp = buffer; + + char *wp = buffer; + int nx = r->x, ny = r->y; pnormalize(&nx, &ny, pl); adjust_coordinates(f, &nx, &ny, pl, r); wp += sprintf(wp, "\"%d %d %d", nx, ny, z); - for (i=1;i!=rdata->nregions;++i) { + for (i = 1; i != rdata->nregions; ++i) { r = rdata->regions[i]; pl = rplane(r); z = plane_id(pl); @@ -443,24 +494,29 @@ cr_regions(variant var, char * buffer, const void * userdata) return 0; } -static int -cr_spell(variant var, char * buffer, const void * userdata) +static int cr_spell(variant var, char *buffer, const void *userdata) { - const faction * report = (const faction*)userdata; - spell * sp = (spell*)var.v; - if (sp!=NULL) sprintf(buffer, "\"%s\"", spell_name(sp, report->locale)); - else strcpy(buffer, "\"\""); + const faction *report = (const faction *)userdata; + + spell *sp = (spell *) var.v; + + if (sp != NULL) + sprintf(buffer, "\"%s\"", spell_name(sp, report->locale)); + else + strcpy(buffer, "\"\""); return 0; } -static int -cr_curse(variant var, char * buffer, const void * userdata) +static int cr_curse(variant var, char *buffer, const void *userdata) { - const faction * report = (const faction*)userdata; - const curse_type * ctype = (const curse_type*)var.v; - if (ctype!=NULL) { + const faction *report = (const faction *)userdata; + + const curse_type *ctype = (const curse_type *)var.v; + + if (ctype != NULL) { sprintf(buffer, "\"%s\"", curse_name(ctype, report->locale)); - } else strcpy(buffer, "\"\""); + } else + strcpy(buffer, "\"\""); return 0; } @@ -469,20 +525,23 @@ cr_curse(variant var, char * buffer, const void * userdata) #define MTMAXHASH 1021 static struct known_mtype { - const struct message_type * mtype; - struct known_mtype * nexthash; -} * mtypehash[MTMAXHASH]; + const struct message_type *mtype; + struct known_mtype *nexthash; +} *mtypehash[MTMAXHASH]; -static void -report_crtypes(FILE * F, const struct locale* lang) +static void report_crtypes(FILE * F, const struct locale *lang) { int i; - for (i=0;i!=MTMAXHASH;++i) { - struct known_mtype * kmt; - for (kmt=mtypehash[i];kmt;kmt=kmt->nexthash) { - const struct nrmessage_type * nrt = nrt_find(lang, kmt->mtype); + + for (i = 0; i != MTMAXHASH; ++i) { + struct known_mtype *kmt; + + for (kmt = mtypehash[i]; kmt; kmt = kmt->nexthash) { + const struct nrmessage_type *nrt = nrt_find(lang, kmt->mtype); + if (nrt) { unsigned int hash = kmt->mtype->key; + fprintf(F, "MESSAGETYPE %d\n", hash); fputc('\"', F); fputs(escape_string(nrt_string(nrt), NULL, 0), F); @@ -498,27 +557,32 @@ report_crtypes(FILE * F, const struct locale* lang) } } -static unsigned int -messagehash(const struct message * msg) +static unsigned int messagehash(const struct message *msg) { variant var; + var.v = (void *)msg; return (unsigned int)var.i; } -static void -render_messages(FILE * F, faction * f, message_list *msgs) +static void render_messages(FILE * F, faction * f, message_list * msgs) { - struct mlist* m = msgs->begin; + struct mlist *m = msgs->begin; + while (m) { - char crbuffer[BUFFERSIZE]; /* gross, wegen spionage-messages :-( */ + char crbuffer[BUFFERSIZE]; /* gross, wegen spionage-messages :-( */ + boolean printed = false; - const struct message_type * mtype = m->msg->type; + + const struct message_type *mtype = m->msg->type; + unsigned int hash = mtype->key; + #ifdef RENDER_CRMESSAGES - char nrbuffer[1024*32]; + char nrbuffer[1024 * 32]; + nrbuffer[0] = '\0'; - if (nr_render(m->msg, f->locale, nrbuffer, sizeof(nrbuffer), f)>=0) { + if (nr_render(m->msg, f->locale, nrbuffer, sizeof(nrbuffer), f) >= 0) { fprintf(F, "MESSAGE %u\n", messagehash(m->msg)); fprintf(F, "%d;type\n", hash); fwritestr(F, nrbuffer); @@ -527,18 +591,24 @@ render_messages(FILE * F, faction * f, message_list *msgs) } #endif crbuffer[0] = '\0'; - if (cr_render(m->msg, crbuffer, (const void*)f)==0) { - if (!printed) fprintf(F, "MESSAGE %u\n", messagehash(m->msg)); - if (crbuffer[0]) fputs(crbuffer, F); + if (cr_render(m->msg, crbuffer, (const void *)f) == 0) { + if (!printed) + fprintf(F, "MESSAGE %u\n", messagehash(m->msg)); + if (crbuffer[0]) + fputs(crbuffer, F); } else { - log_error(("could not render cr-message %p: %s\n", m->msg, m->msg->type->name)); + log_error(("could not render cr-message %p: %s\n", m->msg, + m->msg->type->name)); } if (printed) { unsigned int ihash = hash % MTMAXHASH; - struct known_mtype * kmt = mtypehash[ihash]; - while (kmt && kmt->mtype != mtype) kmt = kmt->nexthash; - if (kmt==NULL) { - kmt = (struct known_mtype*)malloc(sizeof(struct known_mtype)); + + struct known_mtype *kmt = mtypehash[ihash]; + + while (kmt && kmt->mtype != mtype) + kmt = kmt->nexthash; + if (kmt == NULL) { + kmt = (struct known_mtype *)malloc(sizeof(struct known_mtype)); kmt->nexthash = mtypehash[ihash]; kmt->mtype = mtype; mtypehash[ihash] = kmt; @@ -548,25 +618,28 @@ render_messages(FILE * F, faction * f, message_list *msgs) } } -static void -cr_output_messages(FILE * F, message_list *msgs, faction * f) +static void cr_output_messages(FILE * F, message_list * msgs, faction * f) { - if (msgs) render_messages(F, f, msgs); + if (msgs) + render_messages(F, f, msgs); } /* prints a building */ static void -cr_output_building(FILE * F, building * b, const unit * owner, int fno, faction *f) +cr_output_building(FILE * F, building * b, const unit * owner, int fno, + faction * f) { - const char * bname, * billusion; + const char *bname, *billusion; fprintf(F, "BURG %d\n", b->no); report_building(b, &bname, &billusion); if (billusion) { - fprintf(F, "\"%s\";Typ\n", add_translation(billusion, LOC(f->locale, billusion))); - if (owner && owner->faction==f) { - fprintf(F, "\"%s\";wahrerTyp\n", add_translation(bname, LOC(f->locale, bname))); + fprintf(F, "\"%s\";Typ\n", add_translation(billusion, LOC(f->locale, + billusion))); + if (owner && owner->faction == f) { + fprintf(F, "\"%s\";wahrerTyp\n", add_translation(bname, LOC(f->locale, + bname))); } } else { fprintf(F, "\"%s\";Typ\n", add_translation(bname, LOC(f->locale, bname))); @@ -584,22 +657,27 @@ cr_output_building(FILE * F, building * b, const unit * owner, int fno, faction fprintf(F, "%d;Belagerer\n", b->besieged); cr_output_curses(F, f, b, TYP_BUILDING); } + /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ /* prints a ship */ static void -cr_output_ship(FILE * F, const ship * sh, const unit * u, int fcaptain, const faction * f, const region * r) +cr_output_ship(FILE * F, 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); if (sh->display && sh->display[0]) fprintf(F, "\"%s\";Beschr\n", sh->display); - fprintf(F, "\"%s\";Typ\n", add_translation(sh->type->name[0], locale_string(f->locale, sh->type->name[0]))); + fprintf(F, "\"%s\";Typ\n", add_translation(sh->type->name[0], + locale_string(f->locale, sh->type->name[0]))); fprintf(F, "%d;Groesse\n", sh->size); if (sh->damage) { - int percent = (sh->damage*100+DAMAGE_SCALE-1)/(sh->size*DAMAGE_SCALE); + int percent = + (sh->damage * 100 + DAMAGE_SCALE - 1) / (sh->size * DAMAGE_SCALE); fprintf(F, "%d;Schaden\n", percent); } if (u) @@ -610,7 +688,9 @@ cr_output_ship(FILE * F, const ship * sh, const unit * u, int fcaptain, const fa /* 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); @@ -619,7 +699,8 @@ cr_output_ship(FILE * F, const ship * sh, const unit * u, int fcaptain, const fa } /* shore */ w = NODIRECTION; - if (!fval(r->terrain, SEA_REGION)) w = sh->coast; + if (!fval(r->terrain, SEA_REGION)) + w = sh->coast; if (w != NODIRECTION) fprintf(F, "%d;Kueste\n", w); @@ -627,31 +708,42 @@ cr_output_ship(FILE * F, const ship * sh, const unit * u, int fcaptain, const fa } static void -fwriteorder(FILE * F, const struct order * ord, const struct locale * lang, boolean escape) +fwriteorder(FILE * F, const struct order *ord, const struct locale *lang, + boolean escape) { char ebuf[1024]; + char obuf[1024]; - const char * str = obuf; + + const char *str = obuf; + fputc('"', F); write_order(ord, obuf, sizeof(obuf)); if (escape) { str = escape_string(obuf, ebuf, sizeof(ebuf)); } - if (str[0]) fputs(str, F); + if (str[0]) + fputs(str, F); fputc('"', F); } -static void cr_output_spells(FILE * F, quicklist * slist, const faction * f, int maxlevel) +static void cr_output_spells(FILE * F, quicklist * slist, const faction * f, + int maxlevel) { if (slist) { - quicklist * ql; + quicklist *ql; + int qi; + fprintf(F, "SPRUECHE\n"); - for (ql=slist,qi=0;ql;ql_advance(&ql, &qi, 1)) { - spell * sp = (spell *)ql_get(ql, qi); + for (ql = slist, qi = 0; ql; ql_advance(&ql, &qi, 1)) { + spell *sp = (spell *) ql_get(ql, qi); + if (sp->level <= maxlevel) { - const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, f->locale)); + const char *name = + add_translation(mkname("spell", sp->sname), spell_name(sp, + f->locale)); fprintf(F, "\"%s\"\n", name); } } @@ -659,33 +751,43 @@ static void cr_output_spells(FILE * F, quicklist * slist, const faction * f, int } /* prints all that belongs to a unit */ -static void -cr_output_unit(FILE * F, const region * r, - const faction * f, /* observers faction */ - const unit * u, int mode) +static void cr_output_unit(FILE * F, const region * r, const faction * f, /* observers faction */ + const unit * u, int mode) { /* Race attributes are always plural and item attributes always * singular */ - const char * str; - const item_type * lasttype; + const char *str; + + const item_type *lasttype; + int pr; + item *itm, *show; - building * b; - const char * pzTmp; - skill * sv; + + building *b; + + const char *pzTmp; + + skill *sv; + const attrib *a_fshidden = NULL; + boolean itemcloak = false; - static const curse_type * itemcloak_ct = 0; + + static const curse_type *itemcloak_ct = 0; + static boolean init = false; + item result[MAX_INVENTORY]; - if (fval(u->race, RCF_INVISIBLE)) return; + if (fval(u->race, RCF_INVISIBLE)) + return; if (!init) { init = true; itemcloak_ct = ct_find("itemcloak"); } - if (itemcloak_ct!=NULL) { + if (itemcloak_ct != NULL) { itemcloak = curse_active(get_curse(u->attribs, itemcloak_ct)); } @@ -699,26 +801,34 @@ cr_output_unit(FILE * F, const region * r, } { /* print faction information */ - const faction * sf = visible_faction(f, u); - const char * prefix = raceprefix(u); + const faction *sf = visible_faction(f, u); + + const char *prefix = raceprefix(u); + if (u->faction == f || omniscient(f)) { - const attrib * a_otherfaction = a_find(u->attribs, &at_otherfaction); - const faction * otherfaction = a_otherfaction?get_otherfaction(a_otherfaction):NULL; + const attrib *a_otherfaction = a_find(u->attribs, &at_otherfaction); + + const faction *otherfaction = + a_otherfaction ? get_otherfaction(a_otherfaction) : NULL; /* my own faction, full info */ const attrib *a = NULL; - unit * mage; - if (fval(u, UFL_GROUP)) a = a_find(u->attribs, &at_group); - if (a!=NULL) { - const group * g = (const group*)a->data.v; + unit *mage; + + if (fval(u, UFL_GROUP)) + a = a_find(u->attribs, &at_group); + if (a != NULL) { + const group *g = (const group *)a->data.v; + fprintf(F, "%d;gruppe\n", g->gid); } fprintf(F, "%d;Partei\n", u->faction->no); - if (sf!=u->faction) fprintf(F, "%d;Verkleidung\n", sf->no); + if (sf != u->faction) + fprintf(F, "%d;Verkleidung\n", sf->no); if (fval(u, UFL_ANON_FACTION)) fprintf(F, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION))); if (otherfaction) { - if (otherfaction!=u->faction) { + if (otherfaction != u->faction) { fprintf(F, "%d;Anderepartei\n", otherfaction->no); } } @@ -731,15 +841,17 @@ cr_output_unit(FILE * F, const region * r, /* faction info is hidden */ fprintf(F, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION))); } else { - const attrib * a_otherfaction = a_find(u->attribs, &at_otherfaction); - const faction * otherfaction = a_otherfaction?get_otherfaction(a_otherfaction):NULL; + const attrib *a_otherfaction = a_find(u->attribs, &at_otherfaction); + + const faction *otherfaction = + a_otherfaction ? get_otherfaction(a_otherfaction) : NULL; /* other unit. show visible faction, not u->faction */ fprintf(F, "%d;Partei\n", sf->no); if (sf == f) { fprintf(F, "1;Verraeter\n"); } if (a_otherfaction) { - if (otherfaction!=u->faction) { + if (otherfaction != u->faction) { if (alliedunit(u, f, HELP_FSTEALTH)) { fprintf(F, "%d;Anderepartei\n", otherfaction->no); } @@ -749,11 +861,12 @@ cr_output_unit(FILE * F, const region * r, } if (prefix) { prefix = mkname("prefix", prefix); - fprintf(F, "\"%s\";typprefix\n", add_translation(prefix, LOC(f->locale, prefix))); + fprintf(F, "\"%s\";typprefix\n", add_translation(prefix, LOC(f->locale, + prefix))); } } if (u->faction != f && a_fshidden - && a_fshidden->data.ca[0] == 1 && effskill(u, SK_STEALTH) >= 6) { + && a_fshidden->data.ca[0] == 1 && effskill(u, SK_STEALTH) >= 6) { fprintf(F, "-1;Anzahl\n"); } else { fprintf(F, "%d;Anzahl\n", u->number); @@ -762,18 +875,22 @@ cr_output_unit(FILE * F, const region * r, pzTmp = get_racename(u->attribs); if (pzTmp) { fprintf(F, "\"%s\";Typ\n", pzTmp); - if (u->faction==f && fval(u->race, RCF_SHAPESHIFTANY)) { - const char * zRace = rc_name(u->race, 1); + if (u->faction == f && fval(u->race, RCF_SHAPESHIFTANY)) { + const char *zRace = rc_name(u->race, 1); + fprintf(F, "\"%s\";wahrerTyp\n", add_translation(zRace, locale_string(f->locale, zRace))); } } else { - const race * irace = u_irace(u); - const char * zRace = rc_name(irace, 1); + const race *irace = u_irace(u); + + const char *zRace = rc_name(irace, 1); + fprintf(F, "\"%s\";Typ\n", add_translation(zRace, locale_string(f->locale, zRace))); - if (u->faction==f && irace!=u->race) { - assert(skill_enabled[SK_STEALTH] || !"we're resetting this on load, so.. ircase should never be used"); + if (u->faction == f && irace != u->race) { + assert(skill_enabled[SK_STEALTH] + || !"we're resetting this on load, so.. ircase should never be used"); zRace = rc_name(u->race, 1); fprintf(F, "\"%s\";wahrerTyp\n", add_translation(zRace, locale_string(f->locale, zRace))); @@ -788,23 +905,26 @@ cr_output_unit(FILE * F, const region * r, assert(u->ship->region); fprintf(F, "%d;Schiff\n", u->ship->no); } - if (is_guard(u, GUARD_ALL)!=0) { + if (is_guard(u, GUARD_ALL) != 0) { fprintf(F, "%d;bewacht\n", 1); } - if ((b=usiege(u))!=NULL) { + if ((b = usiege(u)) != NULL) { fprintf(F, "%d;belagert\n", b->no); } /* additional information for own units */ if (u->faction == f || omniscient(f)) { - order * ord; + order *ord; + const char *xc; - const char * c; + + const char *c; + int i; i = ualias(u); - if (i>0) + if (i > 0) fprintf(F, "%d;temp\n", i); - else if (i<0) + else if (i < 0) fprintf(F, "%d;alias\n", -i); i = get_money(u); fprintf(F, "%d;Kampfstatus\n", u->status); @@ -824,7 +944,8 @@ cr_output_unit(FILE * F, const region * r, } c = hp_status(u); if (c && *c && (u->faction == f || omniscient(f))) { - fprintf(F, "\"%s\";hp\n", add_translation(c, locale_string(u->faction->locale, c))); + fprintf(F, "\"%s\";hp\n", add_translation(c, + locale_string(u->faction->locale, c))); } if (fval(u, UFL_HERO)) { fputs("1;hero\n", F); @@ -835,7 +956,7 @@ cr_output_unit(FILE * F, const region * r, } if (is_mage(u)) { fprintf(F, "%d;Aura\n", get_spellpoints(u)); - fprintf(F, "%d;Auramax\n", max_spellpoints(u->region,u)); + fprintf(F, "%d;Auramax\n", max_spellpoints(u->region, u)); } /* default commands */ fprintf(F, "COMMANDS\n"); @@ -847,7 +968,8 @@ cr_output_unit(FILE * F, const region * r, } } for (ord = u->orders; ord; ord = ord->next) { - if (u->old_orders && is_repeated(ord)) continue; /* unit has defaults */ + if (u->old_orders && is_repeated(ord)) + continue; /* unit has defaults */ if (is_persistent(ord)) { fwriteorder(F, ord, f->locale, true); fputc('\n', F); @@ -857,29 +979,37 @@ cr_output_unit(FILE * F, const region * r, /* talents */ pr = 0; for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - if (sv->level>0) { + if (sv->level > 0) { skill_t sk = sv->id; + int esk = eff_skill(u, sk, r); + if (!pr) { pr = 1; fprintf(F, "TALENTE\n"); } - fprintf(F, "%d %d;%s\n", u->number*level_days(sv->level), esk, - add_translation(mkname("skill", skillnames[sk]), skillname(sk, f->locale))); + fprintf(F, "%d %d;%s\n", u->number * level_days(sv->level), esk, + add_translation(mkname("skill", skillnames[sk]), skillname(sk, + f->locale))); } } /* spells */ if (is_mage(u)) { - sc_mage * mage = get_mage(u); - quicklist ** slistp = get_spelllist(mage, u->faction); + sc_mage *mage = get_mage(u); + + quicklist **slistp = get_spelllist(mage, u->faction); + int i, maxlevel = effskill(u, SK_MAGIC); cr_output_spells(F, *slistp, f, maxlevel); - for (i=0;i!=MAXCOMBATSPELLS;++i) { - const spell * sp = mage->combatspells[i].sp; + for (i = 0; i != MAXCOMBATSPELLS; ++i) { + const spell *sp = mage->combatspells[i].sp; + if (sp) { - const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, f->locale)); + const char *name = + add_translation(mkname("spell", sp->sname), spell_name(sp, + f->locale)); fprintf(F, "KAMPFZAUBER %d\n", i); fprintf(F, "\"%s\";name\n", name); fprintf(F, "%d;level\n", mage->combatspells[i].level); @@ -891,55 +1021,65 @@ cr_output_unit(FILE * F, const region * r, pr = 0; if (f == u->faction || omniscient(f)) { show = u->items; - } else if (itemcloak==false && mode>=see_unit && !(a_fshidden - && a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) - { + } else if (itemcloak == false && mode >= see_unit && !(a_fshidden + && a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) { int n = report_items(u->items, result, MAX_INVENTORY, u, f); - assert(n>=0); - if (n>0) show = result; - else show = NULL; + + assert(n >= 0); + if (n > 0) + show = result; + else + show = NULL; } else { show = NULL; } lasttype = NULL; - for (itm=show; itm; itm=itm->next) { - const char * ic; + for (itm = show; itm; itm = itm->next) { + const char *ic; + int in; - assert(itm->type!=lasttype || !"error: list contains two objects of the same item"); + + assert(itm->type != lasttype + || !"error: list contains two objects of the same item"); report_item(u, itm, f, NULL, &ic, &in, true); - if (in==0) continue; + if (in == 0) + continue; if (!pr) { pr = 1; fputs("GEGENSTAENDE\n", F); } - fprintf(F, "%d;%s\n", in, add_translation(ic, locale_string(f->locale, ic))); + fprintf(F, "%d;%s\n", in, add_translation(ic, locale_string(f->locale, + ic))); } cr_output_curses(F, f, u, TYP_UNIT); } + /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ /* prints allies */ -static void -show_allies_cr(FILE * F, const faction * f, const ally * sf) +static void show_allies_cr(FILE * F, const faction * f, const ally * sf) { - for (; sf; sf = sf->next) if (sf->faction) { - int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); - if (mode!=0 && sf->status>0) { - fprintf(F, "ALLIANZ %d\n", sf->faction->no); - fprintf(F, "\"%s\";Parteiname\n", sf->faction->name); - fprintf(F, "%d;Status\n", sf->status & HELP_ALL); + for (; sf; sf = sf->next) + if (sf->faction) { + int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); + + if (mode != 0 && sf->status > 0) { + fprintf(F, "ALLIANZ %d\n", sf->faction->no); + fprintf(F, "\"%s\";Parteiname\n", sf->faction->name); + fprintf(F, "%d;Status\n", sf->status & HELP_ALL); + } } - } } /* prints allies */ -static void -show_alliances_cr(FILE * F, const faction * f) +static void show_alliances_cr(FILE * F, const faction * f) { - alliance * al = f_get_alliance(f); + alliance *al = f_get_alliance(f); + if (al) { - faction * lead = alliance_get_leader(al); + faction *lead = alliance_get_leader(al); + assert(lead); fprintf(F, "ALLIANCE %d\n", al->id); fprintf(F, "\"%s\";name\n", al->name); @@ -948,104 +1088,134 @@ show_alliances_cr(FILE * F, const faction * f) } /* prints all visible spells in a region */ -static void -show_active_spells(const region * r) +static void show_active_spells(const region * r) { char fogwall[MAXDIRECTIONS]; -#ifdef TODO /* alte Regionszauberanzeigen umstellen */ + +#ifdef TODO /* alte Regionszauberanzeigen umstellen */ unit *u; + int env = 0; #endif memset(fogwall, 0, sizeof(char) * MAXDIRECTIONS); } + /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ /* this is a copy of laws.c->find_address output changed. */ -static void -cr_find_address(FILE * F, const faction * uf, quicklist * addresses) +static void cr_find_address(FILE * F, const faction * uf, quicklist * addresses) { int i = 0; - quicklist * flist = addresses; + + quicklist *flist = addresses; + while (flist) { - const faction * f = (const faction *)ql_get(flist, i); - if (uf!=f) { + const faction *f = (const faction *)ql_get(flist, i); + + if (uf != f) { fprintf(F, "PARTEI %d\n", f->no); fprintf(F, "\"%s\";Parteiname\n", f->name); - if (f->email) fprintf(F, "\"%s\";email\n", f->email); - if (f->banner) fprintf(F, "\"%s\";banner\n", f->banner); + if (f->email) + fprintf(F, "\"%s\";email\n", f->email); + if (f->banner) + fprintf(F, "\"%s\";banner\n", f->banner); fprintf(F, "\"%s\";locale\n", locale_name(f->locale)); - if (f->alliance && f->alliance==uf->alliance) { + if (f->alliance && f->alliance == uf->alliance) { fprintf(F, "%d;alliance\n", f->alliance->id); } } ql_advance(&flist, &i, 1); } } + /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ -static void -cr_reportspell(FILE * F, spell *sp, const struct locale * lang) +static void cr_reportspell(FILE * F, spell * sp, const struct locale *lang) { int k; - const char * name = add_translation(mkname("spell", sp->sname), spell_name(sp, lang)); + + const char *name = + add_translation(mkname("spell", sp->sname), spell_name(sp, lang)); fprintf(F, "ZAUBER %d\n", hashstring(sp->sname)); fprintf(F, "\"%s\";name\n", name); fprintf(F, "%d;level\n", sp->level); fprintf(F, "%d;rank\n", sp->rank); fprintf(F, "\"%s\";info\n", spell_info(sp, lang)); - if (sp->parameter) fprintf(F, "\"%s\";syntax\n", sp->parameter); - else fputs("\"\";syntax\n", F); + if (sp->parameter) + fprintf(F, "\"%s\";syntax\n", sp->parameter); + else + fputs("\"\";syntax\n", F); - if (sp->sptyp & PRECOMBATSPELL) fputs("\"precombat\";class\n", F); - else if (sp->sptyp & COMBATSPELL) fputs("\"combat\";class\n", F); - else if (sp->sptyp & POSTCOMBATSPELL) fputs("\"postcombat\";class\n", F); - else fputs("\"normal\";class\n", F); + if (sp->sptyp & PRECOMBATSPELL) + fputs("\"precombat\";class\n", F); + else if (sp->sptyp & COMBATSPELL) + fputs("\"combat\";class\n", F); + else if (sp->sptyp & POSTCOMBATSPELL) + fputs("\"postcombat\";class\n", F); + else + fputs("\"normal\";class\n", F); - if (sp->sptyp & FARCASTING) fputs("1;far\n", F); - if (sp->sptyp & OCEANCASTABLE) fputs("1;ocean\n", F); - if (sp->sptyp & ONSHIPCAST) fputs("1;ship\n", F); - if (!(sp->sptyp & NOTFAMILIARCAST)) fputs("1;familiar\n", F); + if (sp->sptyp & FARCASTING) + fputs("1;far\n", F); + if (sp->sptyp & OCEANCASTABLE) + fputs("1;ocean\n", F); + if (sp->sptyp & ONSHIPCAST) + fputs("1;ship\n", F); + if (!(sp->sptyp & NOTFAMILIARCAST)) + fputs("1;familiar\n", F); fputs("KOMPONENTEN\n", F); for (k = 0; sp->components[k].type; ++k) { - const resource_type * rtype = sp->components[k].type; + const resource_type *rtype = sp->components[k].type; + int itemanz = sp->components[k].amount; + int costtyp = sp->components[k].cost; + if (itemanz > 0) { - const char * name = resourcename(rtype, 0); - fprintf(F, "%d %d;%s\n", itemanz, costtyp == SPC_LEVEL || costtyp == SPC_LINEAR, - add_translation(name, LOC(lang, name))); + const char *name = resourcename(rtype, 0); + + fprintf(F, "%d %d;%s\n", itemanz, costtyp == SPC_LEVEL + || costtyp == SPC_LINEAR, add_translation(name, LOC(lang, name))); } } } -static char * -cr_output_resource(char * buf, const char * name, const struct locale * loc, int amount, int level) +static char *cr_output_resource(char *buf, const char *name, + const struct locale *loc, int amount, int level) { buf += sprintf(buf, "RESOURCE %u\n", hashstring(name)); buf += sprintf(buf, "\"%s\";type\n", add_translation(name, LOC(loc, name))); - if (amount>=0) { - if (level>=0) buf += sprintf(buf, "%d;skill\n", level); + if (amount >= 0) { + if (level >= 0) + buf += sprintf(buf, "%d;skill\n", level); buf += sprintf(buf, "%d;number\n", amount); } return buf; } static void -cr_borders(seen_region ** seen, const region * r, const faction * f, int seemode, FILE * F) +cr_borders(seen_region ** seen, const region * r, const faction * f, + int seemode, FILE * F) { direction_t d; + int g = 0; - for (d = 0; d != MAXDIRECTIONS; d++) - { /* Nachbarregionen, die gesehen werden, ermitteln */ - const region * r2 = rconnect(r, d); - const connection * b; - if (!r2) continue; - if (seemode==see_neighbour) { - seen_region * sr = find_seen(seen, r2); - if (sr==NULL || sr->mode<=see_neighbour) continue; + + for (d = 0; d != MAXDIRECTIONS; d++) { /* Nachbarregionen, die gesehen werden, ermitteln */ + const region *r2 = rconnect(r, d); + + const connection *b; + + if (!r2) + continue; + if (seemode == see_neighbour) { + seen_region *sr = find_seen(seen, r2); + + if (sr == NULL || sr->mode <= see_neighbour) + continue; } b = get_borders(r, r2); while (b) { @@ -1054,25 +1224,30 @@ cr_borders(seen_region ** seen, const region * r, const faction * f, int seemode if (!cs) { cs = b->type->rvisible(b, r); if (!cs) { - unit * us = r->units; + unit *us = r->units; + while (us && !cs) { - if (us->faction==f) { + if (us->faction == f) { cs = b->type->uvisible(b, us); - if (cs) break; + if (cs) + break; } - us=us->next; + us = us->next; } } } if (cs) { - const char * bname = mkname("border", b->type->name(b, r, f, GF_PURE)); + const char *bname = mkname("border", b->type->name(b, r, f, GF_PURE)); + fprintf(F, "GRENZE %d\n", ++g); fprintf(F, "\"%s\";typ\n", LOC(default_locale, bname)); fprintf(F, "%d;richtung\n", d); - if (!b->type->transparent(b, f)) fputs("1;opaque\n", F); + if (!b->type->transparent(b, f)) + fputs("1;opaque\n", F); /* hack: */ - if (b->type==&bt_road) { - int p = rroad(r, d)*100/r->terrain->max_road; + if (b->type == &bt_road) { + int p = rroad(r, d) * 100 / r->terrain->max_road; + fprintf(F, "%d;prozent\n", p); } } @@ -1085,58 +1260,74 @@ static void cr_output_resources(FILE * F, report_context * ctx, seen_region * sr) { char cbuf[BUFFERSIZE], *pos = cbuf; - region * r = sr->r; - faction * f = ctx->f; + + region *r = sr->r; + + faction *f = ctx->f; + resource_report result[MAX_RAWMATERIALS]; + int n, size = report_resources(sr, result, MAX_RAWMATERIALS, f); #ifdef RESOURCECOMPAT int trees = rtrees(r, 2); + int saplings = rtrees(r, 1); - if (trees > 0) fprintf(F, "%d;Baeume\n", trees); - if (saplings > 0) fprintf(F, "%d;Schoesslinge\n", saplings); + if (trees > 0) + fprintf(F, "%d;Baeume\n", trees); + if (saplings > 0) + fprintf(F, "%d;Schoesslinge\n", saplings); if (fval(r, RF_MALLORN) && (trees > 0 || saplings > 0)) fprintf(F, "1;Mallorn\n"); - for (n=0;n=0 && result[n].number>=0) { + for (n = 0; n < size; ++n) { + if (result[n].level >= 0 && result[n].number >= 0) { fprintf(F, "%d;%s\n", result[n].number, crtag(result[n].name)); } } #endif - for (n=0;n=0) { - pos = cr_output_resource(pos, result[n].name, f->locale, result[n].number, result[n].level); + for (n = 0; n < size; ++n) { + if (result[n].number >= 0) { + pos = + cr_output_resource(pos, result[n].name, f->locale, result[n].number, + result[n].level); } } - if (pos!=cbuf) fputs(cbuf, F); + if (pos != cbuf) + fputs(cbuf, F); } static void cr_region_header(FILE * F, int plid, int nx, int ny, unsigned int uid) { - if (plid==0) { + if (plid == 0) { fprintf(F, "REGION %d %d\n", nx, ny); } else { fprintf(F, "REGION %d %d %d\n", nx, ny, plid); } - if (uid) fprintf(F, "%d;id\n", uid); + if (uid) + fprintf(F, "%d;id\n", uid); } -static void -cr_output_region(FILE * F, report_context * ctx, seen_region * sr) +static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr) { - faction * f = ctx->f; - region * r = sr->r; - plane * pl = rplane(r); + faction *f = ctx->f; + + region *r = sr->r; + + plane *pl = rplane(r); + int plid = plane_id(pl), nx, ny; - const char * tname; + + const char *tname; + int oc[4][2], o = 0; + int uid = r->uid; #ifdef OCEAN_NEIGHBORS_GET_NO_ID - if (sr->mode<=see_neighbour && !r->land) { + if (sr->mode <= see_neighbour && !r->land) { uid = 0; } #endif @@ -1151,20 +1342,20 @@ cr_output_region(FILE * F, report_context * ctx, seen_region * sr) } if (pl) { - if (ny==pl->maxy) { + if (ny == pl->maxy) { oc[o][0] = nx; - oc[o++][1] = pl->miny-1; + oc[o++][1] = pl->miny - 1; } - if (nx==pl->maxx) { - oc[o][0] = pl->minx-1; + if (nx == pl->maxx) { + oc[o][0] = pl->minx - 1; oc[o++][1] = ny; } - if (ny==pl->miny) { + if (ny == pl->miny) { oc[o][0] = nx; - oc[o++][1] = pl->maxy+1; + oc[o++][1] = pl->maxy + 1; } - if (nx==pl->minx) { - oc[o][0] = pl->maxx+1; + if (nx == pl->minx) { + oc[o][0] = pl->maxx + 1; oc[o++][1] = ny; } } @@ -1176,35 +1367,42 @@ cr_output_region(FILE * F, report_context * ctx, seen_region * sr) cr_region_header(F, plid, nx, ny, uid); if (r->land) { - const char * str = rname(r, f->locale); + const char *str = rname(r, f->locale); + if (str && str[0]) { fprintf(F, "\"%s\";Name\n", str); } } tname = terrain_name(r); - fprintf(F, "\"%s\";Terrain\n", add_translation(tname, locale_string(f->locale, tname))); - if (sr->mode!=see_unit) fprintf(F, "\"%s\";visibility\n", visibility[sr->mode]); + fprintf(F, "\"%s\";Terrain\n", add_translation(tname, locale_string(f->locale, + tname))); + if (sr->mode != see_unit) + fprintf(F, "\"%s\";visibility\n", visibility[sr->mode]); if (sr->mode == see_neighbour) { cr_borders(ctx->seen, r, f, sr->mode, F); } else { - building * b; - ship * sh; - unit * u; + building *b; + + ship *sh; + + unit *u; + int stealthmod = stealth_modifier(sr->mode); if (r->display && r->display[0]) fprintf(F, "\"%s\";Beschr\n", r->display); if (fval(r->terrain, LAND_REGION)) { fprintf(F, "%d;Bauern\n", rpeasants(r)); - if(fval(r, RF_ORCIFIED)) { + if (fval(r, RF_ORCIFIED)) { fprintf(F, "1;Verorkt\n"); } fprintf(F, "%d;Pferde\n", rhorses(r)); - if (sr->mode>=see_unit) { + if (sr->mode >= see_unit) { if (rule_region_owners()) { - faction * owner = region_get_owner(r); + faction *owner = region_get_owner(r); + if (owner) { fprintf(F, "%d;owner\n", owner->no); } @@ -1213,15 +1411,16 @@ cr_output_region(FILE * F, report_context * ctx, seen_region * sr) if (skill_enabled[SK_ENTERTAINMENT]) { fprintf(F, "%d;Unterh\n", entertainmoney(r)); } - if (is_cursed(r->attribs, C_RIOT, 0)){ + if (is_cursed(r->attribs, C_RIOT, 0)) { fputs("0;Rekruten\n", F); } else { fprintf(F, "%d;Rekruten\n", rpeasants(r) / RECRUITFRACTION); } if (production(r)) { - int p_wage = wage(r, NULL, NULL, turn+1); + int p_wage = wage(r, NULL, NULL, turn + 1); + fprintf(F, "%d;Lohn\n", p_wage); - if (is_mourning(r, turn+1)) { + if (is_mourning(r, turn + 1)) { fputs("1;mourning\n", F); } } @@ -1234,32 +1433,40 @@ cr_output_region(FILE * F, report_context * ctx, seen_region * sr) * must not write any blocks before it */ cr_output_resources(F, ctx, sr); - if (sr->mode>=see_unit) { + if (sr->mode >= see_unit) { /* trade */ if (markets_module() && r->land) { - const item_type * lux = r_luxury(r); - const item_type * herb = r->land->herbtype; + const item_type *lux = r_luxury(r); + + const item_type *herb = r->land->herbtype; + if (lux || herb) { fputs("PREISE\n", F); if (lux) { - const char * ch = resourcename(lux->rtype, 0); - fprintf(F, "%d;%s\n", 1, add_translation(ch, locale_string(f->locale, ch))); + const char *ch = resourcename(lux->rtype, 0); + + fprintf(F, "%d;%s\n", 1, add_translation(ch, + locale_string(f->locale, ch))); } if (herb) { - const char * ch = resourcename(herb->rtype, 0); - fprintf(F, "%d;%s\n", 1, add_translation(ch, locale_string(f->locale, ch))); + const char *ch = resourcename(herb->rtype, 0); + + fprintf(F, "%d;%s\n", 1, add_translation(ch, + locale_string(f->locale, ch))); } } - } else if (rpeasants(r)/TRADE_FRACTION > 0) { - struct demand * dmd = r->land->demands; + } else if (rpeasants(r) / TRADE_FRACTION > 0) { + struct demand *dmd = r->land->demands; + fputs("PREISE\n", F); while (dmd) { - const char * ch = resourcename(dmd->type->itype->rtype, 0); + const char *ch = resourcename(dmd->type->itype->rtype, 0); + fprintf(F, "%d;%s\n", (dmd->value - ? dmd->value*dmd->type->price - : -dmd->type->price), + ? dmd->value * dmd->type->price + : -dmd->type->price), add_translation(ch, locale_string(f->locale, ch))); - dmd=dmd->next; + dmd = dmd->next; } } } @@ -1269,17 +1476,20 @@ cr_output_region(FILE * F, report_context * ctx, seen_region * sr) } cr_output_curses(F, f, r, TYP_REGION); cr_borders(ctx->seen, r, f, sr->mode, F); - if (sr->mode==see_unit && is_astral(r) && !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) - { + if (sr->mode == see_unit && is_astral(r) + && !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) { /* Sonderbehandlung Teleport-Ebene */ region_list *rl = astralregions(r, inhabitable); if (rl) { region_list *rl2 = rl; - while(rl2) { - region * r = rl2->data; + + while (rl2) { + region *r = rl2->data; + int nx = r->x, ny = r->y; - plane * plx = rplane(r); + + plane *plx = rplane(r); pnormalize(&nx, &ny, plx); adjust_coordinates(f, &nx, &ny, plx, r); @@ -1295,22 +1505,32 @@ cr_output_region(FILE * F, report_context * ctx, seen_region * sr) show_active_spells(r); if (fval(r, RF_TRAVELUNIT)) { boolean seeunits = false, seeships = false; - const attrib * ru; + + const attrib *ru; + /* show units pulled through region */ - for (ru = a_find(r->attribs, &at_travelunit); ru && ru->type==&at_travelunit; ru = ru->next) { - unit * u = (unit*)ru->data.v; - if (cansee_durchgezogen(f, r, u, 0) && r!=u->region) { - if (!u->ship || !fval(u, UFL_OWNER)) continue; - if (!seeships) fprintf(F, "DURCHSCHIFFUNG\n"); + for (ru = a_find(r->attribs, &at_travelunit); + ru && ru->type == &at_travelunit; ru = ru->next) { + unit *u = (unit *) ru->data.v; + + if (cansee_durchgezogen(f, r, u, 0) && r != u->region) { + if (!u->ship || !fval(u, UFL_OWNER)) + continue; + if (!seeships) + fprintf(F, "DURCHSCHIFFUNG\n"); seeships = true; fprintf(F, "\"%s\"\n", shipname(u->ship)); } } - for (ru = a_find(r->attribs, &at_travelunit); ru && ru->type==&at_travelunit; ru = ru->next) { - unit * u = (unit*)ru->data.v; - if (cansee_durchgezogen(f, r, u, 0) && r!=u->region) { - if (u->ship) continue; - if (!seeunits) fprintf(F, "DURCHREISE\n"); + for (ru = a_find(r->attribs, &at_travelunit); + ru && ru->type == &at_travelunit; ru = ru->next) { + unit *u = (unit *) ru->data.v; + + if (cansee_durchgezogen(f, r, u, 0) && r != u->region) { + if (u->ship) + continue; + if (!seeunits) + fprintf(F, "DURCHREISE\n"); seeunits = true; fprintf(F, "\"%s\"\n", unitname(u)); } @@ -1318,15 +1538,19 @@ cr_output_region(FILE * F, report_context * ctx, seen_region * sr) } cr_output_messages(F, r->msgs, f); { - message_list * mlist = r_getmessages(r, f); - if (mlist) cr_output_messages(F, mlist, f); + message_list *mlist = r_getmessages(r, f); + + if (mlist) + cr_output_messages(F, mlist, f); } /* buildings */ for (b = rbuildings(r); b; b = b->next) { int fno = -1; + u = building_owner(b); if (u && !fval(u, UFL_ANON_FACTION)) { - const faction * sf = visible_faction(f,u); + const faction *sf = visible_faction(f, u); + fno = sf->no; } cr_output_building(F, b, u, fno, f); @@ -1335,9 +1559,11 @@ cr_output_region(FILE * F, report_context * ctx, seen_region * sr) /* ships */ for (sh = r->ships; sh; sh = sh->next) { int fno = -1; + u = shipowner(sh); if (u && !fval(u, UFL_ANON_FACTION)) { - const faction * sf = visible_faction(f,u); + const faction *sf = visible_faction(f, u); + fno = sf->no; } @@ -1347,7 +1573,8 @@ cr_output_region(FILE * F, report_context * ctx, seen_region * sr) /* visible units */ for (u = r->units; u; u = u->next) { - if (u->building || u->ship || (stealthmod>INT_MIN && cansee(f, r, u, stealthmod))) { + if (u->building || u->ship || (stealthmod > INT_MIN + && cansee(f, r, u, stealthmod))) { cr_output_unit(F, r, f, u, sr->mode); } } @@ -1356,29 +1583,38 @@ cr_output_region(FILE * F, report_context * ctx, seen_region * sr) /* main function of the creport. creates the header and traverses all regions */ static int -report_computer(const char * filename, report_context * ctx, const char * charset) +report_computer(const char *filename, report_context * ctx, const char *charset) { static int era = -1; + int i; - faction * f = ctx->f; - const char * prefix; - region * r; - const char * mailto = locale_string(f->locale, "mailto"); - const attrib * a; - seen_region * sr = NULL; + + faction *f = ctx->f; + + const char *prefix; + + region *r; + + const char *mailto = locale_string(f->locale, "mailto"); + + const attrib *a; + + seen_region *sr = NULL; + #if SCORE_MODULE int score = 0, avgscore = 0; #endif int enc = xmlParseCharEncoding(charset); - FILE * F = fopen(filename, "wt"); - if (era<0) { + FILE *F = fopen(filename, "wt"); + + if (era < 0) { era = get_param_int(global.parameters, "world.era", 2); } - if (F==NULL) { + if (F == NULL) { perror(filename); return -1; - } else if (enc==XML_CHAR_ENCODING_UTF8) { + } else if (enc == XML_CHAR_ENCODING_UTF8) { const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; fwrite(utf8_bom, 1, 3, F); } @@ -1393,12 +1629,13 @@ report_computer(const char * filename, report_context * ctx, const char * charse fprintf(F, "%d;noskillpoints\n", 1); fprintf(F, "%ld;date\n", ctx->report_time); fprintf(F, "\"%s\";Spiel\n", global.gamename); + fprintf(F, "\"%s\";Konfiguration\n", "Standard"); fprintf(F, "\"%s\";Koordinaten\n", "Hex"); fprintf(F, "%d;Basis\n", 36); fprintf(F, "%d;Runde\n", turn); fprintf(F, "%d;Zeitalter\n", era); - if (mailto!=NULL) { + if (mailto != NULL) { fprintf(F, "\"%s\";mailto\n", mailto); fprintf(F, "\"%s\";mailcmd\n", locale_string(f->locale, "mailcmd")); } @@ -1414,7 +1651,7 @@ report_computer(const char * filename, report_context * ctx, const char * charse fprintf(F, "%d;age\n", f->age); fprintf(F, "%d;Optionen\n", f->options); #if SCORE_MODULE - if (f->options & want(O_SCORE) && f->age>DISPLAYSCORE) { + if (f->options & want(O_SCORE) && f->age > DISPLAYSCORE) { score = f->score; avgscore = average_score_of_age(f->age, f->age / 24 + 1); } @@ -1422,11 +1659,12 @@ report_computer(const char * filename, report_context * ctx, const char * charse fprintf(F, "%d;Punktedurchschnitt\n", avgscore); #endif { - const char * zRace = rc_name(f->race, 1); + const char *zRace = rc_name(f->race, 1); + fprintf(F, "\"%s\";Typ\n", add_translation(zRace, LOC(f->locale, zRace))); } prefix = get_prefix(f->attribs); - if (prefix!=NULL) { + if (prefix != NULL) { prefix = mkname("prefix", prefix); fprintf(F, "\"%s\";typprefix\n", add_translation(prefix, LOC(f->locale, prefix))); @@ -1441,36 +1679,41 @@ report_computer(const char * filename, report_context * ctx, const char * charse } i = countheroes(f); - if (i>0) fprintf(F, "%d;heroes\n", i); + if (i > 0) + fprintf(F, "%d;heroes\n", i); i = maxheroes(f); - if (i>0) fprintf(F, "%d;max_heroes\n", i); + if (i > 0) + fprintf(F, "%d;max_heroes\n", i); if (f->age > 1 && f->lastorders != turn) { - fprintf(F, "%d;nmr\n", turn-f->lastorders); + fprintf(F, "%d;nmr\n", turn - f->lastorders); } fprintf(F, "\"%s\";Parteiname\n", f->name); fprintf(F, "\"%s\";email\n", f->email); - if (f->banner) fprintf(F, "\"%s\";banner\n", f->banner); + if (f->banner) + fprintf(F, "\"%s\";banner\n", f->banner); print_items(F, f->items, f->locale); fputs("OPTIONEN\n", F); - for (i=0;i!=MAXOPTIONS;++i) { + for (i = 0; i != MAXOPTIONS; ++i) { int flag = want(i); + if (options[i]) { - fprintf(F, "%d;%s\n", (f->options&flag)?1:0, options[i]); - } else if (f->options&flag) { + fprintf(F, "%d;%s\n", (f->options & flag) ? 1 : 0, options[i]); + } else if (f->options & flag) { f->options &= (~flag); } } show_allies_cr(F, f, f->allies); { - group * g; - for (g=f->groups;g;g=g->next) { + group *g; + + for (g = f->groups; g; g = g->next) { fprintf(F, "GRUPPE %d\n", g->gid); fprintf(F, "\"%s\";name\n", g->name); prefix = get_prefix(g->attribs); - if (prefix!=NULL) { + if (prefix != NULL) { prefix = mkname("prefix", prefix); fprintf(F, "\"%s\";typprefix\n", add_translation(prefix, LOC(f->locale, prefix))); @@ -1481,16 +1724,21 @@ report_computer(const char * filename, report_context * ctx, const char * charse cr_output_messages(F, f->msgs, f); { - struct bmsg * bm; - for (bm=f->battles;bm;bm=bm->next) { - plane * pl = rplane(bm->r); + struct bmsg *bm; + + for (bm = f->battles; bm; bm = bm->next) { + plane *pl = rplane(bm->r); + int plid = plane_id(pl); - region * r = bm->r; + + region *r = bm->r; + int nx = r->x, ny = r->y; pnormalize(&nx, &ny, pl); adjust_coordinates(f, &nx, &ny, pl, r); - if (!plid) fprintf(F, "BATTLE %d %d\n", nx, ny); + if (!plid) + fprintf(F, "BATTLE %d %d\n", nx, ny); else { fprintf(F, "BATTLE %d %d %d\n", nx, ny, plid); } @@ -1500,47 +1748,56 @@ report_computer(const char * filename, report_context * ctx, const char * charse cr_find_address(F, f, ctx->addresses); a = a_find(f->attribs, &at_reportspell); - while (a && a->type==&at_reportspell) { - spell *sp = (spell *)a->data.v; + while (a && a->type == &at_reportspell) { + spell *sp = (spell *) a->data.v; + cr_reportspell(F, sp, f->locale); a = a->next; } - for (a=a_find(f->attribs, &at_showitem);a && a->type==&at_showitem;a=a->next) { - const potion_type * ptype = resource2potion(((const item_type*)a->data.v)->rtype); - const char * ch; - const char * description = NULL; + for (a = a_find(f->attribs, &at_showitem); a && a->type == &at_showitem; + a = a->next) { + const potion_type *ptype = + resource2potion(((const item_type *)a->data.v)->rtype); + const char *ch; - if (ptype==NULL) continue; + const char *description = NULL; + + if (ptype == NULL) + continue; ch = resourcename(ptype->itype->rtype, 0); fprintf(F, "TRANK %d\n", hashstring(ch)); - fprintf(F, "\"%s\";Name\n", add_translation(ch, locale_string(f->locale, ch))); + fprintf(F, "\"%s\";Name\n", add_translation(ch, locale_string(f->locale, + ch))); fprintf(F, "%d;Stufe\n", ptype->level); - if (description==NULL) { - const char * pname = resourcename(ptype->itype->rtype, 0); - const char * potiontext = mkname("potion", pname); + if (description == NULL) { + const char *pname = resourcename(ptype->itype->rtype, 0); + + const char *potiontext = mkname("potion", pname); + description = LOC(f->locale, potiontext); } fprintf(F, "\"%s\";Beschr\n", description); if (ptype->itype->construction) { - requirement * m = ptype->itype->construction->materials; + requirement *m = ptype->itype->construction->materials; fprintf(F, "ZUTATEN\n"); while (m->number) { ch = resourcename(m->rtype, 0); - fprintf(F, "\"%s\"\n", add_translation(ch, locale_string(f->locale, ch))); + fprintf(F, "\"%s\"\n", add_translation(ch, locale_string(f->locale, + ch))); m++; } } } /* traverse all regions */ - for (r=ctx->first;sr==NULL && r!=ctx->last;r=r->next) { + for (r = ctx->first; sr == NULL && r != ctx->last; r = r->next) { sr = find_seen(ctx->seen, r); } - for (;sr!=NULL;sr=sr->next) { + for (; sr != NULL; sr = sr->next) { cr_output_region(F, ctx, sr); } report_crtypes(F, f->locale); @@ -1550,31 +1807,33 @@ report_computer(const char * filename, report_context * ctx, const char * charse return 0; } -int -crwritemap(const char * filename) +int crwritemap(const char *filename) { - FILE * F = fopen(filename, "w"); - region * r; + FILE *F = fopen(filename, "w"); + + region *r; fprintf(F, "VERSION %d\n", C_REPORT_VERSION); fputs("\"UTF-8\";charset\n", F); - for (r=regions;r;r=r->next) { - plane * pl = rplane(r); + for (r = regions; r; r = r->next) { + plane *pl = rplane(r); + int plid = plane_id(pl); + if (plid) { fprintf(F, "REGION %d %d %d\n", r->x, r->y, plid); } else { fprintf(F, "REGION %d %d\n", r->x, r->y); } - fprintf(F, "\"%s\";Name\n\"%s\";Terrain\n", rname(r, default_locale), LOC(default_locale, terrain_name(r))); + fprintf(F, "\"%s\";Name\n\"%s\";Terrain\n", rname(r, default_locale), + LOC(default_locale, terrain_name(r))); } fclose(F); return 0; } -void -register_cr(void) +void register_cr(void) { tsf_register("report", &cr_ignore); tsf_register("string", &cr_string); @@ -1596,18 +1855,17 @@ register_cr(void) tsf_register("items", &cr_resources); tsf_register("regions", &cr_regions); - if (!nocr) register_reporttype("cr", &report_computer, 1<next; free(t); } junkyard = 0; } - - diff --git a/src/gamecode/creport.h b/src/gamecode/creport.h index 473f1f0bc..1f3145b4f 100644 --- a/src/gamecode/creport.h +++ b/src/gamecode/creport.h @@ -17,13 +17,12 @@ extern "C" { #include -extern void creport_cleanup(void); -extern void register_cr(void); + extern void creport_cleanup(void); + extern void register_cr(void); -extern int crwritemap(const char * filename); + extern int crwritemap(const char *filename); #ifdef __cplusplus } #endif #endif - diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index 84bd59144..c7c31d5ef 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -80,24 +80,27 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #pragma endregion typedef struct request { - struct request * next; - struct unit * unit; - struct order * ord; + struct request *next; + struct unit *unit; + struct order *ord; int qty; int no; union { - boolean goblin; /* stealing */ - const struct luxury_type * ltype; /* trading */ + boolean goblin; /* stealing */ + const struct luxury_type *ltype; /* trading */ } type; } request; static int working; static request entertainers[1024]; + static request *nextentertainer; + static int entertaining; static int norders; + static request *oa; #define RECRUIT_MERGE 1 @@ -107,7 +110,7 @@ static int rules_recruit = -1; static void recruit_init(void) { - if (rules_recruit<0) { + if (rules_recruit < 0) { rules_recruit = 0; if (get_param_int(global.parameters, "recruit.allow_merge", 1)) { rules_recruit |= RECRUIT_MERGE; @@ -121,115 +124,127 @@ static void recruit_init(void) } } -int -income(const unit * u) +int income(const unit * u) { - switch(old_race(u->race)) { - case RC_FIREDRAGON: - return 150 * u->number; - case RC_DRAGON: - return 1000 * u->number; - case RC_WYRM: - return 5000 * u->number; - } - return 20 * u->number; + switch (old_race(u->race)) { + case RC_FIREDRAGON: + return 150 * u->number; + case RC_DRAGON: + return 1000 * u->number; + case RC_WYRM: + return 5000 * u->number; + } + return 20 * u->number; } -static void -scramble(void *data, int n, size_t width) +static void scramble(void *data, int n, size_t width) { int j; + char temp[64]; - assert(width<=sizeof(temp)); - for (j=0;j!=n;++j) { + + assert(width <= sizeof(temp)); + for (j = 0; j != n; ++j) { int k = rng_int() % n; - if (k==j) continue; - memcpy(temp, (char*)data+j*width, width); - memcpy((char*)data+j*width, (char*)data+k*width, width); - memcpy((char*)data+k*width, temp, width); + + if (k == j) + continue; + memcpy(temp, (char *)data + j * width, width); + memcpy((char *)data + j * width, (char *)data + k * width, width); + memcpy((char *)data + k * width, temp, width); } } -static void -expandorders(region * r, request * requests) +static void expandorders(region * r, request * requests) { - unit *u; - request *o; + unit *u; - /* Alle Units ohne request haben ein -1, alle units mit orders haben ein - * 0 hier stehen */ + request *o; - for (u = r->units; u; u = u->next) - u->n = -1; + /* Alle Units ohne request haben ein -1, alle units mit orders haben ein + * 0 hier stehen */ - norders = 0; + for (u = r->units; u; u = u->next) + u->n = -1; + + norders = 0; for (o = requests; o; o = o->next) { if (o->qty > 0) { norders += o->qty; } - } + } - if (norders > 0) { + if (norders > 0) { int i = 0; - oa = (request *) calloc(norders, sizeof(request)); - for (o = requests; o; o = o->next) { - if (o->qty > 0) { + + oa = (request *) calloc(norders, sizeof(request)); + for (o = requests; o; o = o->next) { + if (o->qty > 0) { int j; - for (j = o->qty; j; j--) { - oa[i] = *o; - oa[i].unit->n = 0; - i++; - } - } - } - scramble(oa, norders, sizeof(request)); - } else { - oa = NULL; - } - while (requests) { - request * o = requests->next; + + for (j = o->qty; j; j--) { + oa[i] = *o; + oa[i].unit->n = 0; + i++; + } + } + } + scramble(oa, norders, sizeof(request)); + } else { + oa = NULL; + } + while (requests) { + request *o = requests->next; + free_order(requests->ord); - free(requests); - requests = o; - } + free(requests); + requests = o; + } } + /* ------------------------------------------------------------- */ -static void -change_level(unit * u, skill_t sk, int bylevel) +static void change_level(unit * u, skill_t sk, int bylevel) { - skill * sv = get_skill(u, sk); - assert(bylevel>0); - if (sv==0) sv = add_skill(u, sk); - sk_set(sv, sv->level+bylevel); + skill *sv = get_skill(u, sk); + + assert(bylevel > 0); + if (sv == 0) + sv = add_skill(u, sk); + sk_set(sv, sv->level + bylevel); } typedef struct recruitment { - struct recruitment * next; - faction * f; - request * requests; + struct recruitment *next; + faction *f; + request *requests; int total, assigned; } recruitment; -static recruitment * -select_recruitment(request ** rop, int (*quantify)(const struct race*, int), int * total) +static recruitment *select_recruitment(request ** rop, + int (*quantify) (const struct race *, int), int *total) { - recruitment * recruits = NULL; + recruitment *recruits = NULL; while (*rop) { - recruitment * rec = recruits; - request * ro = *rop; - unit * u = ro->unit; - const race * rc = u->race; + recruitment *rec = recruits; + + request *ro = *rop; + + unit *u = ro->unit; + + const race *rc = u->race; + int qty = quantify(rc, ro->qty); - if (qty<0) { - rop = &ro->next; /* skip this one */ + if (qty < 0) { + rop = &ro->next; /* skip this one */ } else { - *rop = ro->next; /* remove this one */ - while (rec && rec->f!=u->faction) rec = rec->next; - if (rec==NULL) { + *rop = ro->next; /* remove this one */ + while (rec && rec->f != u->faction) + rec = rec->next; + if (rec == NULL) { rec = malloc(sizeof(recruitment)); rec->f = u->faction; rec->total = 0; @@ -247,16 +262,17 @@ select_recruitment(request ** rop, int (*quantify)(const struct race*, int), int return recruits; } -static void -add_recruits(unit * u, int number, int wanted) +static void add_recruits(unit * u, int number, int wanted) { - region * r = u->region; - assert(number<=wanted); + region *r = u->region; + + assert(number <= wanted); if (number > 0) { - unit * unew; + unit *unew; + char equipment[64]; - if (u->number==0) { + if (u->number == 0) { set_number(u, number); u->hp = number * unit_max_hp(u); unew = u; @@ -272,102 +288,116 @@ add_recruits(unit * u, int number, int wanted) change_level(unew, SK_RIDING, 1); } - if (unew!=u) { + if (unew != u) { transfermen(unew, u, unew->number); remove_unit(&r->units, unew); } } if (number < wanted) { ADDMSG(&u->faction->msgs, msg_message("recruit", - "unit region amount want", u, r, number, wanted)); + "unit region amount want", u, r, number, wanted)); } } -static int -any_recruiters(const struct race * rc, int qty) +static int any_recruiters(const struct race *rc, int qty) { return (int)(qty * 2 * rc->recruit_multi); } -static int -peasant_recruiters(const struct race * rc, int qty) +static int peasant_recruiters(const struct race *rc, int qty) { - if (rc->ec_flags & ECF_REC_ETHEREAL) return -1; - if (rc->ec_flags & ECF_REC_HORSES) return -1; + if (rc->ec_flags & ECF_REC_ETHEREAL) + return -1; + if (rc->ec_flags & ECF_REC_HORSES) + return -1; return (int)(qty * 2 * rc->recruit_multi); } -static int -horse_recruiters(const struct race * rc, int qty) +static int horse_recruiters(const struct race *rc, int qty) { - if (rc->ec_flags & ECF_REC_ETHEREAL) return -1; - if (rc->ec_flags & ECF_REC_HORSES) return (int)(qty * 2 * rc->recruit_multi); + if (rc->ec_flags & ECF_REC_ETHEREAL) + return -1; + if (rc->ec_flags & ECF_REC_HORSES) + return (int)(qty * 2 * rc->recruit_multi); return -1; } -static int -do_recruiting(recruitment * recruits, int available) +static int do_recruiting(recruitment * recruits, int available) { - recruitment * rec; + recruitment *rec; + int recruited = 0; - while (available>0) { + while (available > 0) { int n = 0; + int rest, mintotal = INT_MAX; - for (rec=recruits;rec!=NULL;rec=rec->next) { + for (rec = recruits; rec != NULL; rec = rec->next) { int want = rec->total - rec->assigned; - if (want>0) { - if (mintotal>want) mintotal = want; + + if (want > 0) { + if (mintotal > want) + mintotal = want; ++n; } } - if (n==0) break; - if (mintotal*n>available) { - mintotal = available/n; + if (n == 0) + break; + if (mintotal * n > available) { + mintotal = available / n; } - rest = available - mintotal*n; + rest = available - mintotal * n; - for (rec=recruits;rec!=NULL;rec=rec->next) { + for (rec = recruits; rec != NULL; rec = rec->next) { int want = rec->total - rec->assigned; - if (want>0) { + if (want > 0) { int get = mintotal; - if (want>mintotal && rest mintotal && rest < n && (rng_int() % n) < rest) { --rest; ++get; } - assert(get<=want); + assert(get <= want); available -= get; rec->assigned += get; } } } - for (rec=recruits;rec!=NULL;rec=rec->next) { - request * req; + for (rec = recruits; rec != NULL; rec = rec->next) { + request *req; + int get = rec->assigned; - for (req=rec->requests;req;req=req->next) { - unit * u = req->unit; - const race * rc = u->race; /* race is set in recruit() */ + for (req = rec->requests; req; req = req->next) { + unit *u = req->unit; + + const race *rc = u->race; /* race is set in recruit() */ + int number, dec; + float multi = 2.0F * rc->recruit_multi; number = MIN(req->qty, (int)(get / multi)); if (rc->recruitcost) { - int afford = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, number*rc->recruitcost) / rc->recruitcost; + int afford = + get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, + number * rc->recruitcost) / rc->recruitcost; number = MIN(number, afford); - use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, rc->recruitcost*number); + use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, + rc->recruitcost * number); } - if (u->number+number>UNIT_MAXSIZE) { - ADDMSG(&u->faction->msgs, msg_feedback(u, req->ord, "error_unit_size", "maxsize", UNIT_MAXSIZE)); - number = UNIT_MAXSIZE-u->number; - assert(number>=0); + if (u->number + number > UNIT_MAXSIZE) { + ADDMSG(&u->faction->msgs, msg_feedback(u, req->ord, "error_unit_size", + "maxsize", UNIT_MAXSIZE)); + number = UNIT_MAXSIZE - u->number; + assert(number >= 0); } add_recruits(u, number, req->qty); dec = (int)(number * multi); - if ((rc->ec_flags & ECF_REC_ETHEREAL)==0) { + if ((rc->ec_flags & ECF_REC_ETHEREAL) == 0) { recruited += dec; } @@ -377,40 +407,47 @@ do_recruiting(recruitment * recruits, int available) return recruited; } -static void -feedback_give_not_allowed(unit * u, order * ord) +static void feedback_give_not_allowed(unit * u, order * ord) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_give_forbidden", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_give_forbidden", + "")); } -static boolean check_give(unit * u, unit * u2, const item_type * itype, int mask) +static boolean check_give(unit * u, unit * u2, const item_type * itype, + int mask) { if (u2) { - if (u->faction!=u2->faction) { + if (u->faction != u2->faction) { int rule = rule_give(); + if (itype) { - assert(mask==0); - if (itype->rtype->ltype) mask |= GIVE_LUXURIES; - else if (fval(itype, ITF_HERB)) mask |= GIVE_HERBS; - else mask |= GIVE_GOODS; + assert(mask == 0); + if (itype->rtype->ltype) + mask |= GIVE_LUXURIES; + else if (fval(itype, ITF_HERB)) + mask |= GIVE_HERBS; + else + mask |= GIVE_GOODS; } - return (rule&mask)!=0; + return (rule & mask) != 0; } } else { int rule = rule_give(); - return (rule & GIVE_PEASANTS)!=0; + + return (rule & GIVE_PEASANTS) != 0; } return true; } -void -free_recruitments(recruitment * recruits) +void free_recruitments(recruitment * recruits) { while (recruits) { - recruitment * rec = recruits; + recruitment *rec = recruits; + recruits = rec->next; while (rec->requests) { - request * req = rec->requests; + request *req = rec->requests; + rec->requests = req->next; free(req); } @@ -419,10 +456,9 @@ free_recruitments(recruitment * recruits) } /* Rekrutierung */ -static void -expandrecruit(region * r, request * recruitorders) +static void expandrecruit(region * r, request * recruitorders) { - recruitment * recruits = NULL; + recruitment *recruits = NULL; int orc_total = 0; @@ -430,7 +466,9 @@ expandrecruit(region * r, request * recruitorders) recruits = select_recruitment(&recruitorders, horse_recruiters, &orc_total); if (recruits) { int recruited, horses = rhorses(r) * 2; - if (orc_total0) { - rsetpeasants(r, peasants - recruited/2); + if (recruited > 0) { + rsetpeasants(r, peasants - recruited / 2); } free_recruitments(recruits); } - assert(recruitorders==NULL); + assert(recruitorders == NULL); } -static int -recruit_cost(const faction * f, const race * rc) +static int recruit_cost(const faction * f, const race * rc) { - if (is_monsters(f) || f->race==rc) { + if (is_monsters(f) || f->race == rc) { return rc->recruitcost; } else if (valid_race(f, rc)) { return rc->recruitcost; @@ -474,44 +515,50 @@ recruit_cost(const faction * f, const race * rc) return -1; } -static void -recruit(unit * u, struct order * ord, request ** recruitorders) +static void recruit(unit * u, struct order *ord, request ** recruitorders) { int n; - region * r = u->region; - plane * pl; + + region *r = u->region; + + plane *pl; + request *o; + int recruitcost = -1; - const faction * f = u->faction; - const struct race * rc = u->race; - const char * str; + + const faction *f = u->faction; + + const struct race *rc = u->race; + + const char *str; init_tokens(ord); skip_token(); n = getuint(); - if (u->number==0) { + if (u->number == 0) { str = getstrtoken(); if (str && str[0]) { /* Monster dürfen REKRUTIERE 15 dracoid machen * also: secondary race */ rc = findrace(str, f->locale); - if (rc!=NULL) { + if (rc != NULL) { recruitcost = recruit_cost(f, rc); } } } - if (recruitcost<0) { + if (recruitcost < 0) { rc = u->race; recruitcost = recruit_cost(f, rc); } u->race = rc; - assert(rc && recruitcost>=0); + assert(rc && recruitcost >= 0); #if GUARD_DISABLES_RECRUIT /* this is a very special case because the recruiting unit may be empty - * at this point and we have to look at the creating unit instead. This - * is done in cansee, which is called indirectly by is_guarded(). */ + * at this point and we have to look at the creating unit instead. This + * is done in cansee, which is called indirectly by is_guarded(). */ if (is_guarded(r, u, GUARD_RECRUIT)) { cmistake(u, ord, 70, MSG_EVENT); return; @@ -520,10 +567,12 @@ recruit(unit * u, struct order * ord, request ** recruitorders) if (rc == new_race[RC_INSECT]) { gamedate date; + get_gamedate(turn, &date); if (date.season == 0 && r->terrain != newterrain(T_DESERT)) { #ifdef INSECT_POTION boolean usepotion = false; + unit *u2; for (u2 = r->units; u2; u2 = u2->next) @@ -531,12 +580,12 @@ recruit(unit * u, struct order * ord, request ** recruitorders) usepotion = true; break; } - if (!usepotion) + if (!usepotion) #endif - { - cmistake(u, ord, 98, MSG_EVENT); - return; - } + { + cmistake(u, ord, 98, MSG_EVENT); + return; + } } /* in Gletschern, Eisbergen gar nicht rekrutieren */ if (r_insectstalled(r)) { @@ -551,8 +600,7 @@ recruit(unit * u, struct order * ord, request ** recruitorders) } if (!(rc->ec_flags & ECF_REC_HORSES) && fval(r, RF_ORCIFIED)) { - if (rc != new_race[RC_ORC]) - { + if (rc != new_race[RC_ORC]) { cmistake(u, ord, 238, MSG_EVENT); return; } @@ -561,12 +609,12 @@ recruit(unit * u, struct order * ord, request ** recruitorders) if (recruitcost) { pl = getplane(r); if (pl && fval(pl, PFL_NORECRUITS)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "error_pflnorecruit", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_pflnorecruit", "")); return; } - if (get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, recruitcost) < recruitcost) { + if (get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, + recruitcost) < recruitcost) { cmistake(u, ord, 142, MSG_EVENT); return; } @@ -578,19 +626,19 @@ recruit(unit * u, struct order * ord, request ** recruitorders) if (has_skill(u, SK_MAGIC)) { /* error158;de;{unit} in {region}: '{command}' - Magier arbeiten - * grundsätzlich nur alleine! */ + * grundsätzlich nur alleine! */ cmistake(u, ord, 158, MSG_EVENT); return; } if (has_skill(u, SK_ALCHEMY) && count_skill(u->faction, SK_ALCHEMY) + n > - skill_limit(u->faction, SK_ALCHEMY)) - { + skill_limit(u->faction, SK_ALCHEMY)) { cmistake(u, ord, 156, MSG_EVENT); return; } - if (recruitcost>0) { - int pooled = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, recruitcost * n); + if (recruitcost > 0) { + int pooled = + get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, recruitcost * n); n = MIN(n, pooled / recruitcost); } @@ -608,26 +656,28 @@ recruit(unit * u, struct order * ord, request ** recruitorders) addlist(recruitorders, o); } -static void -friendly_takeover(region * r, faction * f) +static void friendly_takeover(region * r, faction * f) { int morale = region_get_morale(r); + region_set_owner(r, f, turn); - if (morale>0) { - morale = MAX(0, morale-MORALE_TRANSFER); + if (morale > 0) { + morale = MAX(0, morale - MORALE_TRANSFER); region_set_morale(r, morale, turn); } } -static void -give_control(unit * u, unit * u2) +static void give_control(unit * u, unit * u2) { - if (u->building && u->faction!=u2->faction && rule_region_owners()) { - region * r = u->region; - faction * f = region_get_owner(r); - if (f==u->faction) { - building * b = largestbuilding(r, &cmp_current_owner, false); - if (b==u->building) { + if (u->building && u->faction != u2->faction && rule_region_owners()) { + region *r = u->region; + + faction *f = region_get_owner(r); + + if (f == u->faction) { + building *b = largestbuilding(r, &cmp_current_owner, false); + + if (b == u->building) { friendly_takeover(r, u2->faction); } } @@ -636,12 +686,14 @@ give_control(unit * u, unit * u2) fset(u2, UFL_OWNER); } -int -give_control_cmd(unit * u, order * ord) +int give_control_cmd(unit * u, order * ord) { - region * r = u->region; + region *r = u->region; + unit *u2; - const char * s; + + const char *s; + param_t p; init_tokens(ord); @@ -652,24 +704,20 @@ give_control_cmd(unit * u, order * ord) /* first, do all the ones that do not require HELP_GIVE or CONTACT */ if (p == P_CONTROL) { - message * msg; + message *msg; - if (!u2 || u2->number==0) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } - else if (!u->building && !u->ship) { + if (!u2 || u2->number == 0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", + "")); + } else if (!u->building && !u->ship) { cmistake(u, ord, 140, MSG_EVENT); - } - else if (u->building && u2->building != u->building) { + } else if (u->building && u2->building != u->building) { cmistake(u, ord, 33, MSG_EVENT); - } - else if (u->ship && u2->ship != u->ship) { + } else if (u->ship && u2->ship != u->ship) { cmistake(u, ord, 32, MSG_EVENT); - } - else if (!fval(u, UFL_OWNER)) { + } else if (!fval(u, UFL_OWNER)) { cmistake(u, ord, 49, MSG_EVENT); - } - else { + } else { give_control(u, u2); msg = msg_message("givecommand", "unit recipient", u, u2); @@ -683,16 +731,21 @@ give_control_cmd(unit * u, order * ord) return 0; } -static void -give_cmd(unit * u, order * ord) +static void give_cmd(unit * u, order * ord) { - region * r = u->region; + region *r = u->region; + unit *u2; + const char *s; + int i, n; - const item_type * itype; + + const item_type *itype; + param_t p; - plane * pl; + + plane *pl; init_tokens(ord); skip_token(); @@ -707,7 +760,8 @@ give_cmd(unit * u, order * ord) } if (!u2 && !getunitpeasants) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", + "")); return; } @@ -717,8 +771,11 @@ give_cmd(unit * u, order * ord) } /* Damit Tarner nicht durch die Fehlermeldung enttarnt werden können */ - if (u2 && !alliedunit(u2, u->faction, HELP_GIVE) && !cansee(u->faction,r,u2,0) && !ucontact(u2, u) && !fval(u2, UFL_TAKEALL)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + if (u2 && !alliedunit(u2, u->faction, HELP_GIVE) + && !cansee(u->faction, r, u2, 0) && !ucontact(u2, u) + && !fval(u2, UFL_TAKEALL)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", + "")); return; } if (u == u2) { @@ -727,7 +784,7 @@ give_cmd(unit * u, order * ord) } /* UFL_TAKEALL ist ein grober Hack. Generalisierung tut not, ist aber nicht - * wirklich einfach. */ + * wirklich einfach. */ pl = rplane(r); if (pl && fval(pl, PFL_NOGIVE) && (!u2 || !fval(u2, UFL_TAKEALL))) { cmistake(u, ord, 268, MSG_COMMERCE); @@ -735,7 +792,8 @@ give_cmd(unit * u, order * ord) } if (u2 && u2->race == new_race[RC_SPELL]) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", + "")); return; } @@ -746,7 +804,8 @@ give_cmd(unit * u, order * ord) else if (p == P_HERBS) { boolean given = false; - if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { + + if (!(u->race->ec_flags & GIVEITEM) && u2 != NULL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_nogive", "race", u->race)); return; @@ -762,28 +821,34 @@ give_cmd(unit * u, order * ord) } if (!u2) { if (!getunitpeasants) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, + "feedback_unit_not_found", "")); return; } } if (u->items) { - item **itmp=&u->items; + item **itmp = &u->items; + while (*itmp) { - item * itm = *itmp; - const item_type * itype = itm->type; - if (fval(itype, ITF_HERB) && itm->number>0) { + item *itm = *itmp; + + const item_type *itype = itm->type; + + if (fval(itype, ITF_HERB) && itm->number > 0) { /* give_item ändert im fall,das man alles übergibt, die - * item-liste der unit, darum continue vor pointerumsetzten */ - if (give_item(itm->number, itm->type, u, u2, ord)==0) { + * item-liste der unit, darum continue vor pointerumsetzten */ + if (give_item(itm->number, itm->type, u, u2, ord) == 0) { given = true; - if (*itmp!=itm) continue; + if (*itmp != itm) + continue; continue; } } itmp = &itm->next; } } - if (!given) cmistake(u, ord, 38, MSG_COMMERCE); + if (!given) + cmistake(u, ord, 38, MSG_COMMERCE); return; } @@ -793,7 +858,7 @@ give_cmd(unit * u, order * ord) return; } - else if (p == P_UNIT) { /* Einheiten uebergeben */ + else if (p == P_UNIT) { /* Einheiten uebergeben */ if (!(u->race->ec_flags & GIVEUNIT)) { cmistake(u, ord, 167, MSG_COMMERCE); return; @@ -803,17 +868,17 @@ give_cmd(unit * u, order * ord) return; } - else if (p==P_ANY) { - const char * s = getstrtoken(); + else if (p == P_ANY) { + const char *s = getstrtoken(); if (!check_give(u, u2, NULL, GIVE_ALLITEMS)) { feedback_give_not_allowed(u, ord); return; } - if (*s == 0) { /* Alle Gegenstände übergeben */ + if (*s == 0) { /* Alle Gegenstände übergeben */ /* do these checks once, not for each item we have: */ - if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { + if (!(u->race->ec_flags & GIVEITEM) && u2 != NULL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_nogive", "race", u->race)); return; @@ -827,22 +892,26 @@ give_cmd(unit * u, order * ord) /* für alle items einmal prüfen, ob wir mehr als von diesem Typ * reserviert ist besitzen und diesen Teil dann übergeben */ if (u->items) { - item **itmp=&u->items; + item **itmp = &u->items; + while (*itmp) { - item * itm = *itmp; - const item_type * itype = itm->type; - if (itm->number > 0 && itm->number - get_reservation(u, itype->rtype) > 0) { + item *itm = *itmp; + + const item_type *itype = itm->type; + + if (itm->number > 0 + && itm->number - get_reservation(u, itype->rtype) > 0) { n = itm->number - get_reservation(u, itype->rtype); - if (give_item(n, itype, u, u2, ord)==0) { - if (*itmp!=itm) continue; + if (give_item(n, itype, u, u2, ord) == 0) { + if (*itmp != itm) + continue; } } itmp = &itm->next; } } return; - } - else { + } else { param_t p2 = findparam(s, u->faction->locale); if (p2 == P_PERSON) { @@ -856,7 +925,7 @@ give_cmd(unit * u, order * ord) return; } - if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { + if (!(u->race->ec_flags & GIVEITEM) && u2 != NULL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_nogive", "race", u->race)); return; @@ -868,9 +937,10 @@ give_cmd(unit * u, order * ord) } itype = finditemtype(s, u->faction->locale); - if (itype!=NULL) { - item * i = *i_find(&u->items, itype); - if (i!=NULL) { + if (itype != NULL) { + item *i = *i_find(&u->items, itype); + + if (i != NULL) { if (check_give(u, u2, itype, 0)) { n = i->number - get_reservation(u, itype->rtype); give_item(n, itype, u, u2, ord); @@ -881,17 +951,17 @@ give_cmd(unit * u, order * ord) } } } - } else if (p==P_EACH) { - if (u2==NULL) { + } else if (p == P_EACH) { + if (u2 == NULL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "peasants_give_invalid", "")); return; } - s = getstrtoken(); /* skip one ahead to get the amount. */ + s = getstrtoken(); /* skip one ahead to get the amount. */ } - n = atoip((const char *)s); /* n: Anzahl */ - if (p==P_EACH) { + n = atoip((const char *)s); /* n: Anzahl */ + if (p == P_EACH) { n *= u2->number; } s = getstrtoken(); @@ -912,8 +982,8 @@ give_cmd(unit * u, order * ord) return; } - if (u2!=NULL) { - if (!(u->race->ec_flags & GIVEITEM) && u2!=NULL) { + if (u2 != NULL) { + if (!(u->race->ec_flags & GIVEITEM) && u2 != NULL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_nogive", "race", u->race)); return; @@ -926,7 +996,7 @@ give_cmd(unit * u, order * ord) } itype = finditemtype(s, u->faction->locale); - if (itype!=NULL) { + if (itype != NULL) { if (check_give(u, u2, itype, 0)) { give_item(n, itype, u, u2, ord); } else { @@ -937,10 +1007,10 @@ give_cmd(unit * u, order * ord) cmistake(u, ord, 123, MSG_COMMERCE); } -static int -forget_cmd(unit * u, order * ord) +static int forget_cmd(unit * u, order * ord) { skill_t sk; + const char *s; if (is_cursed(u->attribs, C_SLAVE, 0)) { @@ -953,45 +1023,47 @@ forget_cmd(unit * u, order * ord) s = getstrtoken(); if ((sk = findskill(s, u->faction->locale)) != NOSKILL) { - ADDMSG(&u->faction->msgs, - msg_message("forget", "unit skill", u, sk)); + ADDMSG(&u->faction->msgs, msg_message("forget", "unit skill", u, sk)); set_level(u, sk, 0); } return 0; } -void -add_spende(faction * f1, faction * f2, int amount, region * r) +void add_spende(faction * f1, faction * f2, int amount, region * r) { - donation *sp; + donation *sp; - sp = r->donations; + sp = r->donations; - while (sp) { - if (sp->f1 == f1 && sp->f2 == f2) { - sp->amount += amount; - return; - } - sp = sp->next; - } + while (sp) { + if (sp->f1 == f1 && sp->f2 == f2) { + sp->amount += amount; + return; + } + sp = sp->next; + } - sp = calloc(1, sizeof(donation)); - sp->f1 = f1; - sp->f2 = f2; - sp->amount = amount; - sp->next = r->donations; - r->donations = sp; + sp = calloc(1, sizeof(donation)); + sp->f1 = f1; + sp->f2 = f2; + sp->amount = amount; + sp->next = r->donations; + r->donations = sp; } -static boolean -maintain(building * b, boolean first) +static boolean maintain(building * b, boolean first) /* first==false -> take money from wherever you can */ { int c; - region * r = b->region; + + region *r = b->region; + boolean paid = true, work = first; - unit * u; - if (fval(b, BLD_MAINTAINED) || b->type==NULL || b->type->maintenance==NULL || is_cursed(b->attribs, C_NOCOST, 0)) { + + unit *u; + + if (fval(b, BLD_MAINTAINED) || b->type == NULL || b->type->maintenance == NULL + || is_cursed(b->attribs, C_NOCOST, 0)) { fset(b, BLD_MAINTAINED); fset(b, BLD_WORKING); return true; @@ -1000,32 +1072,42 @@ maintain(building * b, boolean first) return false; } u = building_owner(b); - if (u==NULL) return false; - for (c=0;b->type->maintenance[c].number;++c) { - const maintenance * m = b->type->maintenance+c; + if (u == NULL) + return false; + for (c = 0; b->type->maintenance[c].number; ++c) { + const maintenance *m = b->type->maintenance + c; + int need = m->number; - if (fval(m, MTF_VARIABLE)) need = need * b->size; + if (fval(m, MTF_VARIABLE)) + need = need * b->size; if (u) { /* first ist im ersten versuch true, im zweiten aber false! Das - * bedeutet, das in der Runde in die Region geschafften Resourcen - * nicht genutzt werden können, weil die reserviert sind! */ - if (!first) need -= get_pooled(u, m->rtype, GET_ALL, need); - else need -= get_pooled(u, m->rtype, GET_DEFAULT, need); + * bedeutet, das in der Runde in die Region geschafften Resourcen + * nicht genutzt werden können, weil die reserviert sind! */ + if (!first) + need -= get_pooled(u, m->rtype, GET_ALL, need); + else + need -= get_pooled(u, m->rtype, GET_DEFAULT, need); if (!first && need > 0) { - unit * ua; - for (ua=r->units;ua;ua=ua->next) freset(ua->faction, FFL_SELECT); - fset(u->faction, FFL_SELECT); /* hat schon */ - for (ua=r->units;ua;ua=ua->next) { - if (!fval(ua->faction, FFL_SELECT) && (ua->faction == u->faction || alliedunit(ua, u->faction, HELP_MONEY))) { + unit *ua; + + for (ua = r->units; ua; ua = ua->next) + freset(ua->faction, FFL_SELECT); + fset(u->faction, FFL_SELECT); /* hat schon */ + for (ua = r->units; ua; ua = ua->next) { + if (!fval(ua->faction, FFL_SELECT) && (ua->faction == u->faction + || alliedunit(ua, u->faction, HELP_MONEY))) { need -= get_pooled(ua, m->rtype, GET_ALL, need); fset(ua->faction, FFL_SELECT); - if (need<=0) break; + if (need <= 0) + break; } } } if (need > 0) { - if (!fval(m, MTF_VITAL)) work = false; + if (!fval(m, MTF_VITAL)) + work = false; else { paid = false; break; @@ -1033,10 +1115,11 @@ maintain(building * b, boolean first) } } } - if (paid && c>0) { + if (paid && c > 0) { /* TODO: wieviel von was wurde bezahlt */ if (first) { - ADDMSG(&u->faction->msgs, msg_message("maintenance", "unit building", u, b)); + ADDMSG(&u->faction->msgs, msg_message("maintenance", "unit building", u, + b)); } else { ADDMSG(&u->faction->msgs, msg_message("maintenance_late", "building", b)); } @@ -1044,31 +1127,45 @@ maintain(building * b, boolean first) if (work) { fset(b, BLD_WORKING); } - for (c=0;b->type->maintenance[c].number;++c) { - const maintenance * m = b->type->maintenance+c; + for (c = 0; b->type->maintenance[c].number; ++c) { + const maintenance *m = b->type->maintenance + c; + int cost = m->number; - if (!fval(m, MTF_VITAL) && !work) continue; - if (fval(m, MTF_VARIABLE)) cost = cost * b->size; + if (!fval(m, MTF_VITAL) && !work) + continue; + if (fval(m, MTF_VARIABLE)) + cost = cost * b->size; - if (!first) cost -= use_pooled(u, m->rtype, GET_ALL, cost); - else cost -= use_pooled(u, m->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, cost); + if (!first) + cost -= use_pooled(u, m->rtype, GET_ALL, cost); + else + cost -= + use_pooled(u, m->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, + cost); if (!first && cost > 0) { - unit * ua; - for (ua=r->units;ua;ua=ua->next) freset(ua->faction, FFL_SELECT); - fset(u->faction, FFL_SELECT); /* hat schon */ - for (ua=r->units;ua;ua=ua->next) { - if (!fval(ua->faction, FFL_SELECT) && alliedunit(ua, u->faction, HELP_MONEY)) { + unit *ua; + + for (ua = r->units; ua; ua = ua->next) + freset(ua->faction, FFL_SELECT); + fset(u->faction, FFL_SELECT); /* hat schon */ + for (ua = r->units; ua; ua = ua->next) { + if (!fval(ua->faction, FFL_SELECT) + && alliedunit(ua, u->faction, HELP_MONEY)) { int give = use_pooled(ua, m->rtype, GET_ALL, cost); - if (!give) continue; + + if (!give) + continue; cost -= give; fset(ua->faction, FFL_SELECT); - if (m->rtype==r_silver) add_spende(ua->faction, u->faction, give, r); - if (cost<=0) break; + if (m->rtype == r_silver) + add_spende(ua->faction, u->faction, give, r); + if (cost <= 0) + break; } } } - assert(cost==0); + assert(cost == 0); } } else { ADDMSG(&u->faction->msgs, @@ -1079,14 +1176,17 @@ maintain(building * b, boolean first) } #ifdef COLLAPSE_CHANCE -static void -gebaeude_stuerzt_ein(region * r, building * b) +static void gebaeude_stuerzt_ein(region * r, building * b) { unit *u; + int n, i; + int opfer = 0; + int road = 0; - struct message * msg; + + struct message *msg; for (u = r->units; u; u = u->next) { if (u->building == b) { @@ -1094,7 +1194,7 @@ gebaeude_stuerzt_ein(region * r, building * b) fset(u->faction, FFL_MARK); freset(u, UFL_OWNER); - leave(r,u); + leave(r, u); n = u->number; #ifdef COLLAPSE_SURVIVAL for (i = 0; i < n; i++) { @@ -1108,10 +1208,13 @@ gebaeude_stuerzt_ein(region * r, building * b) } } - msg = msg_message("buildingcrash", "region building opfer road", r, b, opfer, road); + msg = + msg_message("buildingcrash", "region building opfer road", r, b, opfer, + road); add_message(&r->msgs, msg); - for (u=r->units; u; u=u->next) { - faction * f = u->faction; + for (u = r->units; u; u = u->next) { + faction *f = u->faction; + if (fval(f, FFL_MARK)) { freset(u->faction, FFL_MARK); add_message(&f->msgs, msg); @@ -1122,12 +1225,13 @@ gebaeude_stuerzt_ein(region * r, building * b) } #endif -void -maintain_buildings(region * r, boolean crash) +void maintain_buildings(region * r, boolean crash) { building **bp = &r->buildings; + while (*bp) { - building * b = *bp; + building *b = *bp; + boolean maintained = maintain(b, !crash); /* the second time, send a message */ @@ -1139,9 +1243,11 @@ maintain_buildings(region * r, boolean crash) } #endif if (!fval(b, BLD_WORKING)) { - unit * u = building_owner(b); - const char * msgtype = maintained?"maintenance_nowork":"maintenance_none"; - struct message * msg = msg_message(msgtype, "building", b); + unit *u = building_owner(b); + + const char *msgtype = + maintained ? "maintenance_nowork" : "maintenance_none"; + struct message *msg = msg_message(msgtype, "building", b); if (u) { add_message(&u->faction->msgs, msg); @@ -1152,36 +1258,41 @@ maintain_buildings(region * r, boolean crash) msg_release(msg); } } - bp=&b->next; + bp = &b->next; } } -static int -recruit_archetype(unit * u, order * ord) +static int recruit_archetype(unit * u, order * ord) { - boolean merge = (u->number>0); - int want; - const char * s; + boolean merge = (u->number > 0); - if (rules_recruit<0) recruit_init(); + int want; + + const char *s; + + if (rules_recruit < 0) + recruit_init(); init_tokens(ord); skip_token(); want = getuint(); s = getstrtoken(); - if (want>0 && s && s[0]) { + if (want > 0 && s && s[0]) { int n = want; - const archetype * arch = find_archetype(s, u->faction->locale); - attrib * a = NULL; - if ((rules_recruit&RECRUIT_MERGE)==0 && merge) { + const archetype *arch = find_archetype(s, u->faction->locale); + + attrib *a = NULL; + + if ((rules_recruit & RECRUIT_MERGE) == 0 && merge) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_must_be_new", "")); /* TODO: error message */ return 0; } - if (arch==NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unknown_archetype", "name", s)); + if (arch == NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unknown_archetype", + "name", s)); /* TODO: error message */ return 0; } @@ -1193,23 +1304,32 @@ recruit_archetype(unit * u, order * ord) * for each failed rule. */ int k; - for (k=0;arch->rules[k].property;++k) { + + for (k = 0; arch->rules[k].property; ++k) { boolean match = false; - if (arch->rules[k].value[0]=='*') match = true; - else if (strcmp(arch->rules[k].property, "race")==0) { - const race * rc = rc_find(arch->rules[k].value); + + if (arch->rules[k].value[0] == '*') + match = true; + else if (strcmp(arch->rules[k].property, "race") == 0) { + const race *rc = rc_find(arch->rules[k].value); + assert(rc); - if (rc==u->race) match = true; - } else if (strcmp(arch->rules[k].property, "building")==0) { - const building_type * btype = bt_find(arch->rules[k].value); + if (rc == u->race) + match = true; + } else if (strcmp(arch->rules[k].property, "building") == 0) { + const building_type *btype = bt_find(arch->rules[k].value); + assert(btype); - if (u->building && u->building->type==btype) match = true; + if (u->building && u->building->type == btype) + match = true; } if (match) { - if (arch->rules[k].allow) break; + if (arch->rules[k].allow) + break; else { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "recruit_rule_fail", - "property value", arch->rules[k].property, arch->rules[k].value)); + "property value", arch->rules[k].property, + arch->rules[k].value)); /* TODO: error message */ return 0; } @@ -1217,20 +1337,24 @@ recruit_archetype(unit * u, order * ord) } } if (arch->btype) { - if (u->building==NULL || u->building->type!=arch->btype) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_must_be_in_building", "type", arch->btype)); + if (u->building == NULL || u->building->type != arch->btype) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, + "unit_must_be_in_building", "type", arch->btype)); /* TODO: error message */ return 0; } if (arch->size) { int maxsize = u->building->size; - attrib * a = a_find(u->building->attribs, &at_recruit); - if (a!=NULL) { + + attrib *a = a_find(u->building->attribs, &at_recruit); + + if (a != NULL) { maxsize -= a->data.i; } - n = MIN(maxsize/arch->size, n); - if (n<=0) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "recruit_capacity_exhausted", "building", u->building)); + n = MIN(maxsize / arch->size, n); + if (n <= 0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, + "recruit_capacity_exhausted", "building", u->building)); /* TODO: error message */ return 0; } @@ -1238,8 +1362,9 @@ recruit_archetype(unit * u, order * ord) } n = build(u, arch->ctype, 0, n); - if (n>0) { - unit * u2; + if (n > 0) { + unit *u2; + if (merge) { u2 = create_unit(u->region, u->faction, 0, u->race, 0, 0, u); } else { @@ -1247,38 +1372,41 @@ recruit_archetype(unit * u, order * ord) } if (arch->exec) { n = arch->exec(u2, arch, n); - } - else { + } else { set_number(u2, n); equip_unit(u2, arch->equip); u2->hp = n * unit_max_hp(u2); if (arch->size) { - if (a==NULL) a = a_add(&u->building->attribs, a_new(&at_recruit)); - a->data.i += n*arch->size; + if (a == NULL) + a = a_add(&u->building->attribs, a_new(&at_recruit)); + a->data.i += n * arch->size; } } - ADDMSG(&u->faction->msgs, msg_message("recruit_archetype", - "unit amount archetype", u, n, arch->name[n==1])); - if (u!=u2 && u->race==u2->race) { + ADDMSG(&u->faction->msgs, msg_message("recruit_archetype", + "unit amount archetype", u, n, arch->name[n == 1])); + if (u != u2 && u->race == u2->race) { transfermen(u2, u, u2->number); } return n; - } else switch(n) { - case ENOMATERIALS: - ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, arch->ctype, want)); - break; - case ELOWSKILL: - case ENEEDSKILL: - /* no skill, or not enough skill points to build */ - cmistake(u, ord, 50, MSG_PRODUCE); - break; - case EBUILDINGREQ: - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "building_needed", "building", arch->ctype->btype->_name)); - break; - default: - assert(!"unhandled return value from build() in recruit_archetype"); - } + } else + switch (n) { + case ENOMATERIALS: + ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, arch->ctype, + want)); + break; + case ELOWSKILL: + case ENEEDSKILL: + /* no skill, or not enough skill points to build */ + cmistake(u, ord, 50, MSG_PRODUCE); + break; + case EBUILDINGREQ: + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "building_needed", "building", + arch->ctype->btype->_name)); + break; + default: + assert(!"unhandled return value from build() in recruit_archetype"); + } return 0; } return -1; @@ -1286,14 +1414,15 @@ recruit_archetype(unit * u, order * ord) int recruit_archetypes(void) { - if (rules_recruit<0) recruit_init(); - return (rules_recruit&RECRUIT_ARCHETYPES)!=0; + if (rules_recruit < 0) + recruit_init(); + return (rules_recruit & RECRUIT_ARCHETYPES) != 0; } -void -economics(region *r) +void economics(region * r) { unit *u; + request *recruitorders = NULL; /* Geben vor Selbstmord (doquit)! Hier alle unmittelbaren Befehle. @@ -1301,47 +1430,52 @@ economics(region *r) * eintreiben. */ for (u = r->units; u; u = u->next) { - order * ord; + order *ord; + boolean destroyed = false; - if (u->number>0) { + + if (u->number > 0) { for (ord = u->orders; ord; ord = ord->next) { switch (get_keyword(ord)) { - case K_DESTROY: - if (!destroyed) { - if (destroy_cmd(u, ord)!=0) ord = NULL; - destroyed = true; - } - break; + case K_DESTROY: + if (!destroyed) { + if (destroy_cmd(u, ord) != 0) + ord = NULL; + destroyed = true; + } + break; - case K_GIVE: - case K_LIEFERE: - give_cmd(u, ord); - break; + case K_GIVE: + case K_LIEFERE: + give_cmd(u, ord); + break; - case K_FORGET: - forget_cmd(u, ord); - break; + case K_FORGET: + forget_cmd(u, ord); + break; } - if (u->orders==NULL) break; + if (u->orders == NULL) + break; } } } /* RECRUIT orders */ - if (rules_recruit<0) recruit_init(); + if (rules_recruit < 0) + recruit_init(); for (u = r->units; u; u = u->next) { - order * ord; + order *ord; - if ((rules_recruit&RECRUIT_MERGE) || u->number==0) { + if ((rules_recruit & RECRUIT_MERGE) || u->number == 0) { for (ord = u->orders; ord; ord = ord->next) { if (get_keyword(ord) == K_RECRUIT) { - if (rules_recruit&RECRUIT_ARCHETYPES) { - if (recruit_archetype(u, ord)>=0) { + if (rules_recruit & RECRUIT_ARCHETYPES) { + if (recruit_archetype(u, ord) >= 0) { continue; } } - if (rules_recruit&RECRUIT_CLASSIC) { + if (rules_recruit & RECRUIT_CLASSIC) { recruit(u, ord, &recruitorders); } break; @@ -1350,31 +1484,37 @@ economics(region *r) } } - if (recruitorders) expandrecruit(r, recruitorders); + if (recruitorders) + expandrecruit(r, recruitorders); remove_empty_units_in_region(r); } + /* ------------------------------------------------------------- */ -static void -manufacture(unit * u, const item_type * itype, int want) +static void manufacture(unit * u, const item_type * itype, int want) { int n; + int skill; + int minskill = itype->construction->minskill; + skill_t sk = itype->construction->skill; skill = effskill(u, sk); - skill = skillmod(itype->rtype->attribs, u, u->region, sk, skill, SMF_PRODUCTION); + skill = + skillmod(itype->rtype->attribs, u, u->region, sk, skill, SMF_PRODUCTION); if (skill < 0) { /* an error occured */ int err = -skill; + cmistake(u, u->thisorder, err, MSG_PRODUCE); return; } - if (want==0) { + if (want == 0) { want = maxbuild(u, itype->construction); } n = build(u, itype->construction, 0, want); @@ -1385,81 +1525,99 @@ manufacture(unit * u, const item_type * itype, int want) return; case EBUILDINGREQ: ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "building_needed", "building", itype->construction->btype->_name)); + msg_feedback(u, u->thisorder, "building_needed", "building", + itype->construction->btype->_name)); return; case ELOWSKILL: ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "manufacture_skills", "skill minskill product", - sk, minskill, itype->rtype, 1)); + msg_feedback(u, u->thisorder, "manufacture_skills", + "skill minskill product", sk, minskill, itype->rtype, 1)); return; case ENOMATERIALS: - ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, itype->construction, want)); + ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, + itype->construction, want)); return; } - if (n>0) { + if (n > 0) { i_change(&u->items, itype, n); - if (want==INT_MAX) want = n; + if (want == INT_MAX) + want = n; ADDMSG(&u->faction->msgs, msg_message("manufacture", - "unit region amount wanted resource", u, u->region, n, want, itype->rtype)); + "unit region amount wanted resource", u, u->region, n, want, + itype->rtype)); } else { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_cannotmake", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_cannotmake", + "")); } } typedef struct allocation { - struct allocation * next; - int want, get; - double save; - unsigned int flags; - unit * unit; + struct allocation *next; + int want, get; + double save; + unsigned int flags; + unit *unit; } allocation; + #define new_allocation() calloc(sizeof(allocation), 1) #define free_allocation(a) free(a) typedef struct allocation_list { - struct allocation_list * next; - allocation * data; - const resource_type * type; + struct allocation_list *next; + allocation *data; + const resource_type *type; } allocation_list; -static allocation_list * allocations; +static allocation_list *allocations; -static boolean -can_guard(const unit * guard, const unit * u) +static boolean can_guard(const unit * guard, const unit * u) { - if (fval(guard, UFL_ISNEW)) return false; - if (guard->number<=0 || !cansee(guard->faction, guard->region, u, 0)) return false; - if (besieged(guard) || !(fval(guard->race, RCF_UNARMEDGUARD) || armedmen(guard, true))) return false; + if (fval(guard, UFL_ISNEW)) + return false; + if (guard->number <= 0 || !cansee(guard->faction, guard->region, u, 0)) + return false; + if (besieged(guard) || !(fval(guard->race, RCF_UNARMEDGUARD) + || armedmen(guard, true))) + return false; return !alliedunit(guard, u->faction, HELP_GUARD); } enum { - AFL_DONE = 1<<0, - AFL_LOWSKILL = 1<<1 + AFL_DONE = 1 << 0, + AFL_LOWSKILL = 1 << 1 }; -static void -allocate_resource(unit * u, const resource_type * rtype, int want) +static void allocate_resource(unit * u, const resource_type * rtype, int want) { - const item_type * itype = resource2item(rtype); - region * r = u->region; + const item_type *itype = resource2item(rtype); + + region *r = u->region; + int busy = u->number; + int dm = 0; - allocation_list * alist; - allocation * al; - attrib * a = a_find(rtype->attribs, &at_resourcelimit); - resource_limit * rdata = (resource_limit*)a->data.v; + + allocation_list *alist; + + allocation *al; + + attrib *a = a_find(rtype->attribs, &at_resourcelimit); + + resource_limit *rdata = (resource_limit *) a->data.v; + int amount, skill; /* momentan kann man keine ressourcen abbauen, wenn man dafür * Materialverbrauch hat: */ - assert(itype!=NULL && (itype->construction==NULL || itype->construction->materials==NULL)); - assert(rdata!=NULL); - - if (rdata->limit!=NULL) { + assert(itype != NULL && (itype->construction == NULL + || itype->construction->materials == NULL)); + assert(rdata != NULL); + + if (rdata->limit != NULL) { int avail = rdata->limit(r, rtype); - if (avail<=0) { + + if (avail <= 0) { cmistake(u, u->thisorder, 121, MSG_PRODUCE); return; } @@ -1469,75 +1627,84 @@ allocate_resource(unit * u, const resource_type * rtype, int want) cmistake(u, u->thisorder, 60, MSG_PRODUCE); return; } - + if (rdata->modifiers) { - resource_mod * mod = rdata->modifiers; - for (;mod->flags!=0;++mod) { + resource_mod *mod = rdata->modifiers; + + for (; mod->flags != 0; ++mod) { if (mod->flags & RMF_REQUIREDBUILDING) { - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - if (mod->btype && mod->btype!=btype) { + struct building *b = inside_building(u); + + const struct building_type *btype = b ? b->type : NULL; + + if (mod->btype && mod->btype != btype) { cmistake(u, u->thisorder, 104, MSG_PRODUCE); return; } } } } - - if (rdata->guard!=0) { - unit * u2; + + if (rdata->guard != 0) { + unit *u2; + for (u2 = r->units; u2; u2 = u2->next) { - if (is_guard(u2, rdata->guard)!=0 && can_guard(u2, u)) { + if (is_guard(u2, rdata->guard) != 0 && can_guard(u2, u)) { ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "region_guarded", "guard", u2)); + msg_feedback(u, u->thisorder, "region_guarded", "guard", u2)); return; } } } - + /* Bergwächter können Abbau von Eisen/Laen durch Bewachen verhindern. * Als magische Wesen 'sehen' Bergwächter alles und werden durch * Belagerung nicht aufgehalten. (Ansonsten wie oben bei Elfen anpassen). */ if (itype == olditemtype[I_IRON] || itype == olditemtype[I_LAEN]) { - unit * u2; - for (u2 = r->units; u2; u2 = u2->next ) { + unit *u2; + + for (u2 = r->units; u2; u2 = u2->next) { if (is_guard(u, GUARD_MINING) - && !fval(u2, UFL_ISNEW) - && u2->number - && !alliedunit(u2, u->faction, HELP_GUARD)) - { + && !fval(u2, UFL_ISNEW) + && u2->number && !alliedunit(u2, u->faction, HELP_GUARD)) { ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "region_guarded", "guard", u2)); + msg_feedback(u, u->thisorder, "region_guarded", "guard", u2)); return; } } } - - assert(itype->construction->skill!=0 || "limited resource needs a required skill for making it"); + + assert(itype->construction->skill != 0 + || "limited resource needs a required skill for making it"); skill = eff_skill(u, itype->construction->skill, u->region); if (skill == 0) { skill_t sk = itype->construction->skill; + add_message(&u->faction->msgs, - msg_feedback(u, u->thisorder, "skill_needed", "skill", sk)); + msg_feedback(u, u->thisorder, "skill_needed", "skill", sk)); return; } if (skill < itype->construction->minskill) { skill_t sk = itype->construction->skill; + add_message(&u->faction->msgs, - msg_feedback(u, u->thisorder, "manufacture_skills", "skill minskill product", - sk, itype->construction->minskill, itype->rtype)); + msg_feedback(u, u->thisorder, "manufacture_skills", + "skill minskill product", sk, itype->construction->minskill, + itype->rtype)); return; } else { - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - + struct building *b = inside_building(u); + + const struct building_type *btype = b ? b->type : NULL; + if (rdata->modifiers) { - resource_mod * mod = rdata->modifiers; - for (;mod->flags!=0;++mod) { + resource_mod *mod = rdata->modifiers; + + for (; mod->flags != 0; ++mod) { if (mod->flags & RMF_SKILL) { - if (mod->btype==NULL || mod->btype==btype) { - if (mod->race==NULL || mod->race==u->race) { + if (mod->btype == NULL || mod->btype == btype) { + if (mod->race == NULL || mod->race == u->race) { skill += mod->value.i; } } @@ -1547,26 +1714,30 @@ allocate_resource(unit * u, const resource_type * rtype, int want) } amount = skill * u->number; /* nun ist amount die Gesamtproduktion der Einheit (in punkten) */ - + /* mit Flinkfingerring verzehnfacht sich die Produktion */ - amount += skill * MIN(u->number, get_item(u, I_RING_OF_NIMBLEFINGER)) * (roqf_factor()-1); - + amount += + skill * MIN(u->number, get_item(u, + I_RING_OF_NIMBLEFINGER)) * (roqf_factor() - 1); + /* Schaffenstrunk: */ if ((dm = get_effect(u, oldpotiontype[P_DOMORE])) != 0) { dm = MIN(dm, u->number); change_effect(u, oldpotiontype[P_DOMORE], -dm); - amount += dm * skill; /* dm Personen produzieren doppelt */ + amount += dm * skill; /* dm Personen produzieren doppelt */ } - + amount /= itype->construction->minskill; - + /* Limitierung durch Parameter m. */ - if (want > 0 && want < amount) amount = want; - - busy = (amount + skill - 1) / skill; /* wieviel leute tun etwas? */ - + if (want > 0 && want < amount) + amount = want; + + busy = (amount + skill - 1) / skill; /* wieviel leute tun etwas? */ + alist = allocations; - while (alist && alist->type!=rtype) alist = alist->next; + while (alist && alist->type != rtype) + alist = alist->next; if (!alist) { alist = calloc(sizeof(struct allocation_list), 1); alist->next = allocations; @@ -1579,16 +1750,18 @@ allocate_resource(unit * u, const resource_type * rtype, int want) al->next = alist->data; al->unit = u; alist->data = al; - + if (rdata->modifiers) { - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - - resource_mod * mod = rdata->modifiers; - for (;mod->flags!=0;++mod) { + struct building *b = inside_building(u); + + const struct building_type *btype = b ? b->type : NULL; + + resource_mod *mod = rdata->modifiers; + + for (; mod->flags != 0; ++mod) { if (mod->flags & RMF_SAVEMATERIAL) { - if (mod->btype==NULL || mod->btype==btype) { - if (mod->race==NULL || mod->race==u->race) { + if (mod->btype == NULL || mod->btype == btype) { + if (mod->race == NULL || mod->race == u->race) { al->save *= mod->value.f; } } @@ -1597,42 +1770,50 @@ allocate_resource(unit * u, const resource_type * rtype, int want) } } -static int -required(int want, double save) +static int required(int want, double save) { int norders = (int)(want * save); - if (norders < want*save) ++norders; + + if (norders < want * save) + ++norders; return norders; } static void leveled_allocation(const resource_type * rtype, region * r, allocation * alist) { - const item_type * itype = resource2item(rtype); - rawmaterial * rm = rm_get(r, rtype); + const item_type *itype = resource2item(rtype); + + rawmaterial *rm = rm_get(r, rtype); + int need; + boolean first = true; - if (rm!=NULL) { + if (rm != NULL) { do { int avail = rm->amount; - int norders = 0; - allocation * al; - if(avail <= 0) { - for (al=alist;al;al=al->next) { + int norders = 0; + + allocation *al; + + if (avail <= 0) { + for (al = alist; al; al = al->next) { al->get = 0; } break; } - assert(avail>0); + assert(avail > 0); - for (al=alist;al;al=al->next) if (!fval(al, AFL_DONE)) { - int req = required(al->want-al->get, al->save); - assert(al->get<=al->want && al->get >= 0); - if (eff_skill(al->unit, itype->construction->skill, r) - >= rm->level+itype->construction->minskill-1) { + for (al = alist; al; al = al->next) + if (!fval(al, AFL_DONE)) { + int req = required(al->want - al->get, al->save); + + assert(al->get <= al->want && al->get >= 0); + if (eff_skill(al->unit, itype->construction->skill, r) + >= rm->level + itype->construction->minskill - 1) { if (req) { norders += req; } else { @@ -1640,87 +1821,102 @@ leveled_allocation(const resource_type * rtype, region * r, allocation * alist) } } else { fset(al, AFL_DONE); - if (first) fset(al, AFL_LOWSKILL); + if (first) + fset(al, AFL_LOWSKILL); } - } + } need = norders; avail = MIN(avail, norders); - if (need>0) { + if (need > 0) { int use = 0; - for (al=alist;al;al=al->next) if (!fval(al, AFL_DONE)) { - if (avail > 0) { - int want = required(al->want-al->get, al->save); - int x = avail*want/norders; - /* Wenn Rest, dann würfeln, ob ich was bekomme: */ - if (rng_int() % norders < (avail*want) % norders) - ++x; - avail -= x; - use += x; - norders -= want; - need -= x; - al->get = MIN(al->want, al->get+(int)(x/al->save)); + + for (al = alist; al; al = al->next) + if (!fval(al, AFL_DONE)) { + if (avail > 0) { + int want = required(al->want - al->get, al->save); + + int x = avail * want / norders; + + /* Wenn Rest, dann würfeln, ob ich was bekomme: */ + if (rng_int() % norders < (avail * want) % norders) + ++x; + avail -= x; + use += x; + norders -= want; + need -= x; + al->get = MIN(al->want, al->get + (int)(x / al->save)); + } } - } if (use) { - assert(use<=rm->amount); + assert(use <= rm->amount); rm->type->use(rm, r, use); } - assert(avail==0 || norders==0); + assert(avail == 0 || norders == 0); } first = false; - } while (need>0); + } while (need > 0); } } static void attrib_allocation(const resource_type * rtype, region * r, allocation * alist) { - allocation * al; + allocation *al; + int norders = 0; - attrib * a = a_find(rtype->attribs, &at_resourcelimit); - resource_limit * rdata = (resource_limit*)a->data.v; + + attrib *a = a_find(rtype->attribs, &at_resourcelimit); + + resource_limit *rdata = (resource_limit *) a->data.v; + int avail = rdata->value; - for (al=alist;al;al=al->next) { + for (al = alist; al; al = al->next) { norders += required(al->want, al->save); } if (rdata->limit) { avail = rdata->limit(r, rtype); - if (avail < 0) avail = 0; + if (avail < 0) + avail = 0; } avail = MIN(avail, norders); - for (al=alist;al;al=al->next) { + for (al = alist; al; al = al->next) { if (avail > 0) { int want = required(al->want, al->save); - int x = avail*want/norders; + + int x = avail * want / norders; + /* Wenn Rest, dann würfeln, ob ich was bekomme: */ - if (rng_int() % norders < (avail*want) % norders) + if (rng_int() % norders < (avail * want) % norders) ++x; avail -= x; norders -= want; - al->get = MIN(al->want, (int)(x/al->save)); + al->get = MIN(al->want, (int)(x / al->save)); if (rdata->produce) { int use = required(al->get, al->save); - if (use) rdata->produce(r, rtype, use); + + if (use) + rdata->produce(r, rtype, use); } } } - assert(avail==0 || norders==0); + assert(avail == 0 || norders == 0); } -typedef void (*allocate_function)(const resource_type *, struct region *, struct allocation *); +typedef void (*allocate_function) (const resource_type *, struct region *, + struct allocation *); -static allocate_function -get_allocator(const struct resource_type * rtype) +static allocate_function get_allocator(const struct resource_type *rtype) { - attrib * a = a_find(rtype->attribs, &at_resourcelimit); + attrib *a = a_find(rtype->attribs, &at_resourcelimit); - if (a!=NULL) { - resource_limit * rdata = (resource_limit*)a->data.v; - if (rdata->value>0 || rdata->limit!=NULL) { + if (a != NULL) { + resource_limit *rdata = (resource_limit *) a->data.v; + + if (rdata->value > 0 || rdata->limit != NULL) { return attrib_allocation; } return leveled_allocation; @@ -1728,48 +1924,53 @@ get_allocator(const struct resource_type * rtype) return NULL; } -void -split_allocations(region * r) +void split_allocations(region * r) { - allocation_list ** p_alist=&allocations; + allocation_list **p_alist = &allocations; + freset(r, RF_SELECT); while (*p_alist) { - allocation_list * alist = *p_alist; - const resource_type * rtype = alist->type; + allocation_list *alist = *p_alist; + + const resource_type *rtype = alist->type; + allocate_function alloc = get_allocator(rtype); - const item_type * itype = resource2item(rtype); - allocation ** p_al = &alist->data; + + const item_type *itype = resource2item(rtype); + + allocation **p_al = &alist->data; freset(r, RF_SELECT); alloc(rtype, r, alist->data); while (*p_al) { - allocation * al = *p_al; + allocation *al = *p_al; + if (al->get) { assert(itype || !"not implemented for non-items"); i_change(&al->unit->items, itype, al->get); produceexp(al->unit, itype->construction->skill, al->unit->number); fset(r, RF_SELECT); } - if (al->want==INT_MAX) al->want = al->get; - ADDMSG(&al->unit->faction->msgs, msg_message("produce", - "unit region amount wanted resource", - al->unit, al->unit->region, al->get, al->want, rtype)); - *p_al=al->next; + if (al->want == INT_MAX) + al->want = al->get; + ADDMSG(&al->unit->faction->msgs, msg_message("produce", + "unit region amount wanted resource", + al->unit, al->unit->region, al->get, al->want, rtype)); + *p_al = al->next; free_allocation(al); } - *p_alist=alist->next; + *p_alist = alist->next; free(alist); } allocations = NULL; } -static void -create_potion(unit * u, const potion_type * ptype, int want) +static void create_potion(unit * u, const potion_type * ptype, int want) { int built; - if (want==0) { + if (want == 0) { want = maxbuild(u, ptype->itype->construction); } built = build(u, ptype->itype->construction, 0, want); @@ -1781,27 +1982,30 @@ create_potion(unit * u, const potion_type * ptype, int want) break; case EBUILDINGREQ: ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "building_needed", "building", ptype->itype->construction->btype->_name)); + msg_feedback(u, u->thisorder, "building_needed", "building", + ptype->itype->construction->btype->_name)); break; case ECOMPLETE: assert(0); break; case ENOMATERIALS: /* something missing from the list of materials */ - ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, ptype->itype->construction, want)); + ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, + ptype->itype->construction, want)); return; break; default: i_change(&u->items, ptype->itype, built); - if (want==INT_MAX) want = built; + if (want == INT_MAX) + want = built; ADDMSG(&u->faction->msgs, msg_message("manufacture", - "unit region amount wanted resource", u, u->region, built, want, ptype->itype->rtype)); + "unit region amount wanted resource", u, u->region, built, want, + ptype->itype->rtype)); break; } } -static void -create_item(unit * u, const item_type * itype, int want) +static void create_item(unit * u, const item_type * itype, int want) { if (itype->construction && fval(itype->rtype, RTF_LIMITED)) { #if GUARD_DISABLES_PRODUCTION == 1 @@ -1812,26 +2016,37 @@ create_item(unit * u, const item_type * itype, int want) #endif allocate_resource(u, itype->rtype, want); } else { - const potion_type * ptype = resource2potion(itype->rtype); - if (ptype!=NULL) create_potion(u, ptype, want); - else if (itype->construction && itype->construction->materials) manufacture(u, itype, want); + const potion_type *ptype = resource2potion(itype->rtype); + + if (ptype != NULL) + create_potion(u, ptype, want); + else if (itype->construction && itype->construction->materials) + manufacture(u, itype, want); else { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_cannotmake", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, + "error_cannotmake", "")); } } } -int -make_cmd(unit * u, struct order * ord) +int make_cmd(unit * u, struct order *ord) { - region * r = u->region; - const building_type * btype; - const ship_type * stype; + region *r = u->region; + + const building_type *btype; + + const ship_type *stype; + param_t p; + int m; - const item_type * itype; + + const item_type *itype; + const char *s; - const struct locale * lang = u->faction->locale; + + const struct locale *lang = u->faction->locale; + char ibuf[16]; init_tokens(ord); @@ -1850,16 +2065,18 @@ make_cmd(unit * u, struct order * ord) p = findparam(s, u->faction->locale); /* MACHE TEMP kann hier schon gar nicht auftauchen, weil diese nicht in - * thisorder abgespeichert werden - und auf den ist getstrtoken() beim - * aufruf von make geeicht */ + * thisorder abgespeichert werden - und auf den ist getstrtoken() beim + * aufruf von make geeicht */ if (p == P_ROAD) { - plane * pl = rplane(r); + plane *pl = rplane(r); + if (pl && fval(pl, PFL_NOBUILD)) { cmistake(u, ord, 275, MSG_PRODUCE); } else { direction_t d = finddirection(getstrtoken(), u->faction->locale); - if (d!=NODIRECTION) { + + if (d != NODIRECTION) { build_road(r, u, m, d); } else { /* Die Richtung wurde nicht erkannt */ @@ -1868,7 +2085,8 @@ make_cmd(unit * u, struct order * ord) } return 0; } else if (p == P_SHIP) { - plane * pl = rplane(r); + plane *pl = rplane(r); + if (pl && fval(pl, PFL_NOBUILD)) { cmistake(u, ord, 276, MSG_PRODUCE); } else { @@ -1881,53 +2099,66 @@ make_cmd(unit * u, struct order * ord) } /* since the string can match several objects, like in 'academy' and - * 'academy of arts', we need to figure out what the player meant. - * This is not 100% safe. - */ + * 'academy of arts', we need to figure out what the player meant. + * This is not 100% safe. + */ stype = findshiptype(s, lang); btype = findbuildingtype(s, lang); itype = finditemtype(s, lang); - if (itype!=NULL && (btype!=NULL || stype!=NULL)) { - if (itype->construction==NULL) { + if (itype != NULL && (btype != NULL || stype != NULL)) { + if (itype->construction == NULL) { /* if the item cannot be made, we probably didn't mean to make it */ itype = NULL; - } else if (stype!=NULL) { - const char * sname = LOC(lang, stype->name[0]); - const char * iname = LOC(lang, resourcename(itype->rtype, 0)); - if (strlen(iname)name[0]); + + const char *iname = LOC(lang, resourcename(itype->rtype, 0)); + + if (strlen(iname) < strlen(sname)) + stype = NULL; + else + itype = NULL; } else { - const char * bname = LOC(lang, btype->_name); - const char * iname = LOC(lang, resourcename(itype->rtype, 0)); - if (strlen(iname)_name); + + const char *iname = LOC(lang, resourcename(itype->rtype, 0)); + + if (strlen(iname) < strlen(bname)) + btype = NULL; + else + itype = NULL; } } - if (btype!=NULL && stype!=NULL) { - const char * bname = LOC(lang, btype->_name); - const char * sname = LOC(lang, stype->name[0]); - if (strlen(sname)_name); + + const char *sname = LOC(lang, stype->name[0]); + + if (strlen(sname) < strlen(bname)) + btype = NULL; + else + stype = NULL; } if (stype != NOSHIP) { - plane * pl = rplane(r); + plane *pl = rplane(r); + if (pl && fval(pl, PFL_NOBUILD)) { cmistake(u, ord, 276, MSG_PRODUCE); } else { create_ship(r, u, stype, m, ord); } } else if (btype != NOBUILDING) { - plane * pl = rplane(r); + plane *pl = rplane(r); + if (pl && fval(pl, PFL_NOBUILD)) { cmistake(u, ord, 94, MSG_PRODUCE); } else { build_building(u, btype, m, ord); } - } - else if (itype!=NULL) { + } else if (itype != NULL) { create_item(u, itype, m); } else { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_cannotmake", "")); @@ -1935,12 +2166,13 @@ make_cmd(unit * u, struct order * ord) return 0; } + /* ------------------------------------------------------------- */ -static void -free_luxuries(struct attrib * a) +static void free_luxuries(struct attrib *a) { - item * itm = (item*)a->data.v; + item *itm = (item *) a->data.v; + a->data.v = NULL; i_freeall(&itm); } @@ -1949,67 +2181,79 @@ const attrib_type at_luxuries = { "luxuries", NULL, free_luxuries, NULL, NULL, NULL }; -static void -expandbuying(region * r, request * buyorders) +static void expandbuying(region * r, request * buyorders) { int max_products; + unit *u; + static struct trade { - const luxury_type * type; + const luxury_type *type; int number; int multi; } *trades, *trade; - static int ntrades=0; + + static int ntrades = 0; + int i, j; - const luxury_type * ltype; - - if (ntrades==0) { - for (ltype=luxurytypes;ltype;ltype=ltype->next) - ++ntrades; + + const luxury_type *ltype; + + if (ntrades == 0) { + for (ltype = luxurytypes; ltype; ltype = ltype->next) + ++ntrades; trades = gc_add(calloc(sizeof(struct trade), ntrades)); - for (i=0, ltype=luxurytypes;i!=ntrades;++i, ltype=ltype->next) - trades[i].type = ltype; + for (i = 0, ltype = luxurytypes; i != ntrades; ++i, ltype = ltype->next) + trades[i].type = ltype; } - for (i=0;i!=ntrades;++i) { + for (i = 0; i != ntrades; ++i) { trades[i].number = 0; trades[i].multi = 1; } - if (!buyorders) return; - + if (!buyorders) + return; + /* Initialisation. multiplier ist der Multiplikator auf den * Verkaufspreis. Für max_products Produkte kauft man das Produkt zum * einfachen Verkaufspreis, danach erhöht sich der Multiplikator um 1. * counter ist ein Zähler, der die gekauften Produkte zählt. money * wird für die debug message gebraucht. */ - + max_products = rpeasants(r) / TRADE_FRACTION; - + /* Kauf - auch so programmiert, daß er leicht erweiterbar auf mehrere * Güter pro Monat ist. j sind die Befehle, i der Index des * gehandelten Produktes. */ - if (max_products>0) { + if (max_products > 0) { expandorders(r, buyorders); - if (!norders) return; - + if (!norders) + return; + for (j = 0; j != norders; j++) { int price, multi; + ltype = oa[j].type.ltype; trade = trades; - while (trade->type!=ltype) ++trade; + while (trade->type != ltype) + ++trade; multi = trade->multi; price = ltype->price * multi; - - if (get_pooled(oa[j].unit, oldresourcetype[R_SILVER], GET_DEFAULT, price) >= price) { - unit * u = oa[j].unit; - item * items; - + + if (get_pooled(oa[j].unit, oldresourcetype[R_SILVER], GET_DEFAULT, + price) >= price) { + unit *u = oa[j].unit; + + item *items; + /* litems zählt die Güter, die verkauft wurden, u->n das Geld, das * verdient wurde. Dies muß gemacht werden, weil der Preis ständig sinkt, * man sich also das verdiente Geld und die verkauften Produkte separat * merken muß. */ - attrib * a = a_find(u->attribs, &at_luxuries); - if (a==NULL) a = a_add(&u->attribs, a_new(&at_luxuries)); + attrib *a = a_find(u->attribs, &at_luxuries); + + if (a == NULL) + a = a_add(&u->attribs, a_new(&at_luxuries)); items = a->data.v; i_change(&items, ltype->itype, 1); @@ -2017,34 +2261,37 @@ expandbuying(region * r, request * buyorders) i_change(&oa[j].unit->items, ltype->itype, 1); use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, price); if (u->n < 0) - u->n = 0; + u->n = 0; u->n += price; - + rsetmoney(r, rmoney(r) + price); - + /* Falls mehr als max_products Bauern ein Produkt verkauft haben, steigt * der Preis Multiplikator für das Produkt um den Faktor 1. Der Zähler * wird wieder auf 0 gesetzt. */ if (++trade->number == max_products) { trade->number = 0; ++trade->multi; - } - fset(u, UFL_LONGACTION|UFL_NOTMOVING); + } + fset(u, UFL_LONGACTION | UFL_NOTMOVING); } } free(oa); - + /* Ausgabe an Einheiten */ - + for (u = r->units; u; u = u->next) { - attrib * a = a_find(u->attribs, &at_luxuries); - item * itm; - if (a==NULL) continue; + attrib *a = a_find(u->attribs, &at_luxuries); + + item *itm; + + if (a == NULL) + continue; ADDMSG(&u->faction->msgs, msg_message("buy", "unit money", u, u->n)); - for (itm=(item*)a->data.v; itm; itm=itm->next) { + for (itm = (item *) a->data.v; itm; itm = itm->next) { if (itm->number) { ADDMSG(&u->faction->msgs, msg_message("buyamount", - "unit amount resource", u, itm->number, itm->type->rtype)); + "unit amount resource", u, itm->number, itm->type->rtype)); } } a_remove(&u->attribs, a); @@ -2053,23 +2300,28 @@ expandbuying(region * r, request * buyorders) } attrib_type at_trades = { - "trades", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - NO_WRITE, - NO_READ + "trades", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, + NO_WRITE, + NO_READ }; -static void -buy(unit * u, request ** buyorders, struct order * ord) +static void buy(unit * u, request ** buyorders, struct order *ord) { - region * r = u->region; + region *r = u->region; + int n, k; + request *o; - attrib * a; - const item_type * itype = NULL; - const luxury_type * ltype = NULL; + + attrib *a; + + const item_type *itype = NULL; + + const luxury_type *ltype = NULL; + if (u->ship && is_guarded(r, u, GUARD_CREWS)) { cmistake(u, ord, 69, MSG_INCOME); return; @@ -2079,7 +2331,7 @@ buy(unit * u, request ** buyorders, struct order * ord) return; } /* Im Augenblick kann man nur 1 Produkt kaufen. expandbuying ist aber - * schon dafür ausgerüstet, mehrere Produkte zu kaufen. */ + * schon dafür ausgerüstet, mehrere Produkte zu kaufen. */ init_tokens(ord); skip_token(); @@ -2096,19 +2348,24 @@ buy(unit * u, request ** buyorders, struct order * ord) if (u->race == new_race[RC_INSECT]) { /* entweder man ist insekt, oder... */ - if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT) && !rbuildings(r)) { + if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT) + && !rbuildings(r)) { cmistake(u, ord, 119, MSG_COMMERCE); return; } } else { /* ...oder in der Region muß es eine Burg geben. */ - building * b; - static const struct building_type * bt_castle; - if (!bt_castle) bt_castle = bt_find("castle"); - for (b=r->buildings;b;b=b->next) { - if (b->type==bt_castle && b->size>=2) break; + building *b; + + static const struct building_type *bt_castle; + + if (!bt_castle) + bt_castle = bt_find("castle"); + for (b = r->buildings; b; b = b->next) { + if (b->type == bt_castle && b->size >= 2) + break; } - if (b==NULL) { + if (b == NULL) { cmistake(u, ord, 119, MSG_COMMERCE); return; } @@ -2118,7 +2375,7 @@ buy(unit * u, request ** buyorders, struct order * ord) k = u->number * 10 * eff_skill(u, SK_TRADE, r); /* hat der Händler bereits gehandelt, muss die Menge der bereits - * verkauften/gekauften Güter abgezogen werden */ + * verkauften/gekauften Güter abgezogen werden */ a = a_find(u->attribs, &at_trades); if (!a) { a = a_add(&u->attribs, a_new(&at_trades)); @@ -2133,69 +2390,79 @@ buy(unit * u, request ** buyorders, struct order * ord) return; } - assert(n>=0); + assert(n >= 0); /* die Menge der verkauften Güter merken */ a->data.i += n; itype = finditemtype(getstrtoken(), u->faction->locale); - if (itype!=NULL) { + if (itype != NULL) { ltype = resource2luxury(itype->rtype); - if (ltype==NULL) { + if (ltype == NULL) { cmistake(u, ord, 124, MSG_COMMERCE); return; } } if (r_demand(r, ltype)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "luxury_notsold", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "luxury_notsold", "")); return; } o = (request *) calloc(1, sizeof(request)); - o->type.ltype = ltype; /* sollte immer gleich sein */ + o->type.ltype = ltype; /* sollte immer gleich sein */ o->unit = u; o->qty = n; addlist(buyorders, o); } + /* ------------------------------------------------------------- */ /* Steuersätze in % bei Burggröße */ -static int tax_per_size[7] = -{0, 6, 12, 18, 24, 30, 36}; +static int tax_per_size[7] = { 0, 6, 12, 18, 24, 30, 36 }; -static void -expandselling(region * r, request * sellorders, int limit) +static void expandselling(region * r, request * sellorders, int limit) { int money, price, j, max_products; + /* int m, n = 0; */ int maxsize = 0, maxeffsize = 0; + int taxcollected = 0; + int hafencollected = 0; + unit *maxowner = (unit *) NULL; + building *maxb = (building *) NULL; + building *b; + unit *u; + unit *hafenowner; + static int *counter; + static int ncounter = 0; - if (ncounter==0) { - const luxury_type * ltype; - for (ltype=luxurytypes;ltype;ltype=ltype->next) ++ncounter; - counter=(int*)gc_add(calloc(sizeof(int), ncounter)); + if (ncounter == 0) { + const luxury_type *ltype; + + for (ltype = luxurytypes; ltype; ltype = ltype->next) + ++ncounter; + counter = (int *)gc_add(calloc(sizeof(int), ncounter)); } else { - memset(counter, 0, sizeof(int)*ncounter); + memset(counter, 0, sizeof(int) * ncounter); } - - if (!sellorders) { /* NEIN, denn Insekten können in || !r->buildings) */ - return; /* Sümpfen und Wüsten auch so handeln */ + + if (!sellorders) { /* NEIN, denn Insekten können in || !r->buildings) */ + return; /* Sümpfen und Wüsten auch so handeln */ } /* Stelle Eigentümer der größten Burg fest. Bekommt Steuern aus jedem * Verkauf. Wenn zwei Burgen gleicher Größe bekommt gar keiner etwas. */ - + for (b = rbuildings(r); b; b = b->next) { if (b->size > maxsize && building_owner(b) != NULL - && b->type == bt_find("castle")) { + && b->type == bt_find("castle")) { maxb = b; maxsize = b->size; maxowner = building_owner(b); @@ -2204,9 +2471,9 @@ expandselling(region * r, request * sellorders, int limit) maxowner = (unit *) NULL; } } - + hafenowner = owner_buildingtyp(r, bt_find("harbour")); - + if (maxb != (building *) NULL && maxowner != (unit *) NULL) { maxeffsize = buildingeffsize(maxb, false); if (maxeffsize == 0) { @@ -2215,53 +2482,70 @@ expandselling(region * r, request * sellorders, int limit) } } /* Die Region muss genug Geld haben, um die Produkte kaufen zu können. */ - + money = rmoney(r); - + /* max_products sind 1/100 der Bevölkerung, falls soviele Produkte * verkauft werden - counter[] - sinkt die Nachfrage um 1 Punkt. * multiplier speichert r->demand für die debug message ab. */ - + max_products = rpeasants(r) / TRADE_FRACTION; - if (max_products <= 0) return; - - if (r->terrain == newterrain(T_DESERT) && buildingtype_exists(r, bt_find("caravan"), true)) { + if (max_products <= 0) + return; + + if (r->terrain == newterrain(T_DESERT) + && buildingtype_exists(r, bt_find("caravan"), true)) { max_products = rpeasants(r) * 2 / TRADE_FRACTION; } /* Verkauf: so programmiert, dass er leicht auf mehrere Gueter pro * Runde erweitert werden kann. */ - + expandorders(r, sellorders); - if (!norders) return; - + if (!norders) + return; + for (j = 0; j != norders; j++) { - static const luxury_type * search=NULL; - const luxury_type * ltype = oa[j].type.ltype; + static const luxury_type *search = NULL; + + const luxury_type *ltype = oa[j].type.ltype; + int multi = r_demand(r, ltype); - static int i=-1; + + static int i = -1; + int use = 0; - if (search!=ltype) { - i=0; - for (search=luxurytypes;search!=ltype;search=search->next) ++i; + + if (search != ltype) { + i = 0; + for (search = luxurytypes; search != ltype; search = search->next) + ++i; } - if (counter[i]>=limit) continue; - if (counter[i]+1 > max_products && multi > 1) --multi; + if (counter[i] >= limit) + continue; + if (counter[i] + 1 > max_products && multi > 1) + --multi; price = ltype->price * multi; - + if (money >= price) { int abgezogenhafen = 0; + int abgezogensteuer = 0; - unit * u = oa[j].unit; - item * itm; - attrib * a = a_find(u->attribs, &at_luxuries); - if (a==NULL) a = a_add(&u->attribs, a_new(&at_luxuries)); - itm = (item *)a->data.v; + + unit *u = oa[j].unit; + + item *itm; + + attrib *a = a_find(u->attribs, &at_luxuries); + + if (a == NULL) + a = a_add(&u->attribs, a_new(&at_luxuries)); + itm = (item *) a->data.v; i_change(&itm, ltype->itype, 1); a->data.v = itm; ++use; if (u->n < 0) - u->n = 0; - + u->n = 0; + if (hafenowner != NULL) { if (hafenowner->faction != u->faction) { abgezogenhafen = price / 10; @@ -2280,39 +2564,41 @@ expandselling(region * r, request * sellorders, int limit) } u->n += price; change_money(u, price); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - + fset(u, UFL_LONGACTION | UFL_NOTMOVING); + /* r->money -= price; --- dies wird eben nicht ausgeführt, denn die * Produkte können auch als Steuern eingetrieben werden. In der Region * wurden Silberstücke gegen Luxusgüter des selben Wertes eingetauscht! * Falls mehr als max_products Kunden ein Produkt gekauft haben, sinkt * die Nachfrage für das Produkt um 1. Der Zähler wird wieder auf 0 * gesetzt. */ - + if (++counter[i] > max_products) { int d = r_demand(r, ltype); + if (d > 1) { - r_setdemand(r, ltype, d-1); + r_setdemand(r, ltype, d - 1); } counter[i] = 0; } } - if (use>0) { + if (use > 0) { #ifdef NDEBUG use_pooled(oa[j].unit, ltype->itype->rtype, GET_DEFAULT, use); #else - /* int i = */ use_pooled(oa[j].unit, ltype->itype->rtype, GET_DEFAULT, use); + /* int i = */ use_pooled(oa[j].unit, ltype->itype->rtype, GET_DEFAULT, + use); /* assert(i==use); */ #endif } } free(oa); - + /* Steuern. Hier werden die Steuern dem Besitzer der größten Burg gegeben. */ - + if (maxowner) { if (taxcollected > 0) { - change_money(maxowner, (int) taxcollected); + change_money(maxowner, (int)taxcollected); add_income(maxowner, IC_TRADETAX, taxcollected, taxcollected); /* TODO: Meldung * "%s verdient %d Silber durch den Handel in %s.", @@ -2321,21 +2607,24 @@ expandselling(region * r, request * sellorders, int limit) } if (hafenowner) { if (hafencollected > 0) { - change_money(hafenowner, (int) hafencollected); + change_money(hafenowner, (int)hafencollected); add_income(hafenowner, IC_TRADETAX, hafencollected, hafencollected); } } /* Berichte an die Einheiten */ - + for (u = r->units; u; u = u->next) { - - attrib * a = a_find(u->attribs, &at_luxuries); - item * itm; - if (a==NULL) continue; - for (itm=(item*)a->data.v; itm; itm=itm->next) { + + attrib *a = a_find(u->attribs, &at_luxuries); + + item *itm; + + if (a == NULL) + continue; + for (itm = (item *) a->data.v; itm; itm = itm->next) { if (itm->number) { - ADDMSG(&u->faction->msgs, msg_message("sellamount", - "unit amount resource", u, itm->number, itm->type->rtype)); + ADDMSG(&u->faction->msgs, msg_message("sellamount", + "unit amount resource", u, itm->number, itm->type->rtype)); } } a_remove(&u->attribs, a); @@ -2343,91 +2632,102 @@ expandselling(region * r, request * sellorders, int limit) } } -static boolean - sell(unit * u, request ** sellorders, struct order * ord) +static boolean sell(unit * u, request ** sellorders, struct order *ord) { boolean unlimited = true; - const item_type * itype; - const luxury_type * ltype=NULL; + + const item_type *itype; + + const luxury_type *ltype = NULL; + int n; - region * r = u->region; + + region *r = u->region; + const char *s; - + if (u->ship && is_guarded(r, u, GUARD_CREWS)) { - cmistake(u, ord, 69, MSG_INCOME); - return false; - } - /* sellorders sind KEIN array, weil für alle items DIE SELBE resource - * (das geld der region) aufgebraucht wird. */ + cmistake(u, ord, 69, MSG_INCOME); + return false; + } + /* sellorders sind KEIN array, weil für alle items DIE SELBE resource + * (das geld der region) aufgebraucht wird. */ init_tokens(ord); skip_token(); - s = getstrtoken(); + s = getstrtoken(); if (findparam(s, u->faction->locale) == P_ANY) { unlimited = false; - n = rpeasants(r) / TRADE_FRACTION; - if (r->terrain == newterrain(T_DESERT) && buildingtype_exists(r, bt_find("caravan"), true)) - n *= 2; - if (n==0) { - cmistake(u, ord, 303, MSG_COMMERCE); - return false; - } - } else { - n = atoi((const char *)s); - if (n==0) { - cmistake(u, ord, 27, MSG_COMMERCE); - return false; - } - } - /* Belagerte Einheiten können nichts verkaufen. */ - - if (besieged(u)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "error60", "")); - return false; - } - /* In der Region muß es eine Burg geben. */ - - if (u->race == new_race[RC_INSECT]) { - if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT) && !rbuildings(r)) { - cmistake(u, ord, 119, MSG_COMMERCE); - return false; - } - } else { - /* ...oder in der Region muß es eine Burg geben. */ - building * b; - static const struct building_type * bt_castle; - if (!bt_castle) bt_castle = bt_find("castle"); - for (b=r->buildings;b;b=b->next) { - if (b->type==bt_castle && b->size>=2) break; + n = rpeasants(r) / TRADE_FRACTION; + if (r->terrain == newterrain(T_DESERT) + && buildingtype_exists(r, bt_find("caravan"), true)) + n *= 2; + if (n == 0) { + cmistake(u, ord, 303, MSG_COMMERCE); + return false; } - if (b==NULL) { - cmistake(u, ord, 119, MSG_COMMERCE); - return false; - } - } + } else { + n = atoi((const char *)s); + if (n == 0) { + cmistake(u, ord, 27, MSG_COMMERCE); + return false; + } + } + /* Belagerte Einheiten können nichts verkaufen. */ - /* Ein Händler kann nur 10 Güter pro Talentpunkt verkaufen. */ + if (besieged(u)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error60", "")); + return false; + } + /* In der Region muß es eine Burg geben. */ - n = MIN(n, u->number * 10 * eff_skill(u, SK_TRADE, r)); + if (u->race == new_race[RC_INSECT]) { + if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT) + && !rbuildings(r)) { + cmistake(u, ord, 119, MSG_COMMERCE); + return false; + } + } else { + /* ...oder in der Region muß es eine Burg geben. */ + building *b; + + static const struct building_type *bt_castle; + + if (!bt_castle) + bt_castle = bt_find("castle"); + for (b = r->buildings; b; b = b->next) { + if (b->type == bt_castle && b->size >= 2) + break; + } + if (b == NULL) { + cmistake(u, ord, 119, MSG_COMMERCE); + return false; + } + } + + /* Ein Händler kann nur 10 Güter pro Talentpunkt verkaufen. */ + + n = MIN(n, u->number * 10 * eff_skill(u, SK_TRADE, r)); + + if (!n) { + cmistake(u, ord, 54, MSG_COMMERCE); + return false; + } + s = getstrtoken(); + itype = finditemtype(s, u->faction->locale); + if (itype != NULL) + ltype = resource2luxury(itype->rtype); + if (ltype == NULL) { + cmistake(u, ord, 126, MSG_COMMERCE); + return false; + } else { + attrib *a; - if (!n) { - cmistake(u, ord, 54, MSG_COMMERCE); - return false; - } - s=getstrtoken(); - itype = finditemtype(s, u->faction->locale); - if (itype!=NULL) ltype = resource2luxury(itype->rtype); - if (ltype==NULL) { - cmistake(u, ord, 126, MSG_COMMERCE); - return false; - } - else { - attrib * a; request *o; + int k, available; - + if (!r_demand(r, ltype)) { cmistake(u, ord, 263, MSG_COMMERCE); return false; @@ -2436,77 +2736,84 @@ static boolean /* Wenn andere Einheiten das selbe verkaufen, muß ihr Zeug abgezogen * werden damit es nicht zweimal verkauft wird: */ - for (o=*sellorders;o;o=o->next) { - if (o->type.ltype==ltype && o->unit->faction == u->faction) { - int fpool = o->qty - get_pooled(o->unit, itype->rtype, GET_RESERVE, INT_MAX); + for (o = *sellorders; o; o = o->next) { + if (o->type.ltype == ltype && o->unit->faction == u->faction) { + int fpool = + o->qty - get_pooled(o->unit, itype->rtype, GET_RESERVE, INT_MAX); available -= MAX(0, fpool); } } - + n = MIN(n, available); - if (n <= 0) { - cmistake(u, ord, 264, MSG_COMMERCE); - return false; - } - /* Hier wird request->type verwendet, weil die obere limit durch - * das silber gegeben wird (region->money), welches für alle - * (!) produkte als summe gilt, als nicht wie bei der - * produktion, wo für jedes produkt einzeln eine obere limite - * existiert, so dass man arrays von orders machen kann. */ + if (n <= 0) { + cmistake(u, ord, 264, MSG_COMMERCE); + return false; + } + /* Hier wird request->type verwendet, weil die obere limit durch + * das silber gegeben wird (region->money), welches für alle + * (!) produkte als summe gilt, als nicht wie bei der + * produktion, wo für jedes produkt einzeln eine obere limite + * existiert, so dass man arrays von orders machen kann. */ - /* Ein Händler kann nur 10 Güter pro Talentpunkt handeln. */ - k = u->number * 10 * eff_skill(u, SK_TRADE, r); + /* Ein Händler kann nur 10 Güter pro Talentpunkt handeln. */ + k = u->number * 10 * eff_skill(u, SK_TRADE, r); - /* hat der Händler bereits gehandelt, muss die Menge der bereits - * verkauften/gekauften Güter abgezogen werden */ - a = a_find(u->attribs, &at_trades); - if (!a) { - a = a_add(&u->attribs, a_new(&at_trades)); - } else { - k -= a->data.i; - } + /* hat der Händler bereits gehandelt, muss die Menge der bereits + * verkauften/gekauften Güter abgezogen werden */ + a = a_find(u->attribs, &at_trades); + if (!a) { + a = a_add(&u->attribs, a_new(&at_trades)); + } else { + k -= a->data.i; + } - n = MIN(n, k); - assert(n>=0); - /* die Menge der verkauften Güter merken */ - a->data.i += n; - o = (request *) calloc(1, sizeof(request)); - o->unit = u; - o->qty = n; - o->type.ltype = ltype; - addlist(sellorders, o); + n = MIN(n, k); + assert(n >= 0); + /* die Menge der verkauften Güter merken */ + a->data.i += n; + o = (request *) calloc(1, sizeof(request)); + o->unit = u; + o->qty = n; + o->type.ltype = ltype; + addlist(sellorders, o); return unlimited; - } + } } + /* ------------------------------------------------------------- */ -static void -expandstealing(region * r, request * stealorders) +static void expandstealing(region * r, request * stealorders) { - int i; + int i; - expandorders(r, stealorders); - if (!norders) return; + expandorders(r, stealorders); + if (!norders) + return; - /* Für jede unit in der Region wird Geld geklaut, wenn sie Opfer eines - * Beklauen-Orders ist. Jedes Opfer muß einzeln behandelt werden. - * - * u ist die beklaute unit. oa.unit ist die klauende unit. - */ + /* Für jede unit in der Region wird Geld geklaut, wenn sie Opfer eines + * Beklauen-Orders ist. Jedes Opfer muß einzeln behandelt werden. + * + * u ist die beklaute unit. oa.unit ist die klauende unit. + */ for (i = 0; i != norders && oa[i].unit->n <= oa[i].unit->wants; i++) { unit *u = findunitg(oa[i].no, r); + int n = 0; - if (u && u->region==r) { + + if (u && u->region == r) { n = get_pooled(u, r_silver, GET_ALL, INT_MAX); } #ifndef GOBLINKILL - if (oa[i].type.goblin) { /* Goblin-Spezialklau */ + if (oa[i].type.goblin) { /* Goblin-Spezialklau */ int uct = 0; + unit *u2; - assert(effskill(oa[i].unit, SK_STEALTH)>=4 || !"this goblin\'s skill is too low"); + + assert(effskill(oa[i].unit, SK_STEALTH) >= 4 + || !"this goblin\'s skill is too low"); for (u2 = r->units; u2; u2 = u2->next) { if (u2->faction == u->faction) { uct += maintenance_cost(u2); @@ -2515,7 +2822,7 @@ expandstealing(region * r, request * stealorders) n -= uct * 2; } #endif - if (n>10 && rplane(r) && (rplane(r)->flags & PFL_NOALLIANCES)) { + if (n > 10 && rplane(r) && (rplane(r)->flags & PFL_NOALLIANCES)) { /* In Questen nur reduziertes Klauen */ n = 10; } @@ -2524,24 +2831,28 @@ expandstealing(region * r, request * stealorders) use_pooled(u, r_silver, GET_ALL, n); oa[i].unit->n = n; change_money(oa[i].unit, n); - ADDMSG(&u->faction->msgs, msg_message("stealeffect", "unit region amount", u, u->region, n)); + ADDMSG(&u->faction->msgs, msg_message("stealeffect", "unit region amount", + u, u->region, n)); } add_income(oa[i].unit, IC_STEAL, oa[i].unit->wants, oa[i].unit->n); - fset(oa[i].unit, UFL_LONGACTION|UFL_NOTMOVING); + fset(oa[i].unit, UFL_LONGACTION | UFL_NOTMOVING); } free(oa); } /* ------------------------------------------------------------- */ -static void -plant(region *r, unit *u, int raw) +static void plant(region * r, unit * u, int raw) { int n, i, skill, planted = 0; - const item_type * itype; - static const resource_type * rt_water = NULL; - if (rt_water==NULL) rt_water = rt_find("p2"); - - assert(rt_water!=NULL); + + const item_type *itype; + + static const resource_type *rt_water = NULL; + + if (rt_water == NULL) + rt_water = rt_find("p2"); + + assert(rt_water != NULL); if (!fval(r->terrain, LAND_REGION)) { return; } @@ -2549,178 +2860,186 @@ plant(region *r, unit *u, int raw) cmistake(u, u->thisorder, 108, MSG_PRODUCE); return; } - + /* Skill prüfen */ skill = eff_skill(u, SK_HERBALISM, r); itype = rherbtype(r); if (skill < 6) { ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "plant_skills", - "skill minskill product", SK_HERBALISM, 6, itype->rtype, 1)); + msg_feedback(u, u->thisorder, "plant_skills", + "skill minskill product", SK_HERBALISM, 6, itype->rtype, 1)); return; } /* Wasser des Lebens prüfen */ if (get_pooled(u, rt_water, GET_DEFAULT, 1) == 0) { ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "resource_missing", "missing", rt_water)); + msg_feedback(u, u->thisorder, "resource_missing", "missing", rt_water)); return; } - n = get_pooled(u, itype->rtype, GET_DEFAULT, skill*u->number); + n = get_pooled(u, itype->rtype, GET_DEFAULT, skill * u->number); /* Kräuter prüfen */ - if (n==0) { + if (n == 0) { ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "resource_missing", "missing", - itype->rtype)); + msg_feedback(u, u->thisorder, "resource_missing", "missing", + itype->rtype)); return; } - n = MIN(skill*u->number, n); + n = MIN(skill * u->number, n); n = MIN(raw, n); /* Für jedes Kraut Talent*10% Erfolgschance. */ - for(i = n; i>0; i--) { - if (rng_int()%10 < skill) planted++; + for (i = n; i > 0; i--) { + if (rng_int() % 10 < skill) + planted++; } produceexp(u, SK_HERBALISM, u->number); - + /* Alles ok. Abziehen. */ use_pooled(u, rt_water, GET_DEFAULT, 1); use_pooled(u, itype->rtype, GET_DEFAULT, n); - rsetherbs(r, rherbs(r)+planted); - ADDMSG(&u->faction->msgs, msg_message("plant", "unit region amount herb", - u, r, planted, itype->rtype)); + rsetherbs(r, rherbs(r) + planted); + ADDMSG(&u->faction->msgs, msg_message("plant", "unit region amount herb", + u, r, planted, itype->rtype)); } -static void -planttrees(region *r, unit *u, int raw) +static void planttrees(region * r, unit * u, int raw) { int n, i, skill, planted = 0; - const resource_type * rtype; - + + const resource_type *rtype; + if (!fval(r->terrain, LAND_REGION)) { return; } - + /* Mallornbäume kann man nur in Mallornregionen züchten */ if (fval(r, RF_MALLORN)) { rtype = rt_mallornseed; } else { rtype = rt_seed; } - + /* Skill prüfen */ skill = eff_skill(u, SK_HERBALISM, r); if (skill < 6) { ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "plant_skills", - "skill minskill product", SK_HERBALISM, 6, rtype, 1)); + msg_feedback(u, u->thisorder, "plant_skills", + "skill minskill product", SK_HERBALISM, 6, rtype, 1)); return; } - if (fval(r, RF_MALLORN) && skill < 7 ) { + if (fval(r, RF_MALLORN) && skill < 7) { ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "plant_skills", - "skill minskill product", SK_HERBALISM, 7, rtype, 1)); + msg_feedback(u, u->thisorder, "plant_skills", + "skill minskill product", SK_HERBALISM, 7, rtype, 1)); return; } - + /* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */ - raw = MIN(raw, skill*u->number); + raw = MIN(raw, skill * u->number); n = get_pooled(u, rtype, GET_DEFAULT, raw); - if (n==0) { + if (n == 0) { ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype)); + msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype)); return; } n = MIN(raw, n); - + /* Für jeden Samen Talent*10% Erfolgschance. */ - for(i = n; i>0; i--) { - if (rng_int()%10 < skill) planted++; + for (i = n; i > 0; i--) { + if (rng_int() % 10 < skill) + planted++; } - rsettrees(r, 0, rtrees(r, 0)+planted); - + rsettrees(r, 0, rtrees(r, 0) + planted); + /* Alles ok. Abziehen. */ produceexp(u, SK_HERBALISM, u->number); use_pooled(u, rtype, GET_DEFAULT, n); - + ADDMSG(&u->faction->msgs, msg_message("plant", - "unit region amount herb", u, r, planted, rtype)); + "unit region amount herb", u, r, planted, rtype)); } /* züchte bäume */ -static void -breedtrees(region *r, unit *u, int raw) +static void breedtrees(region * r, unit * u, int raw) { int n, i, skill, planted = 0; - const resource_type * rtype; + + const resource_type *rtype; + static int gamecookie = -1; + static int current_season; - - if (gamecookie!=global.cookie) { + + if (gamecookie != global.cookie) { gamedate date; + get_gamedate(turn, &date); current_season = date.season; gamecookie = global.cookie; } - + /* Bäume züchten geht nur im Frühling */ - if (current_season != SEASON_SPRING){ + if (current_season != SEASON_SPRING) { planttrees(r, u, raw); return; } - + if (!fval(r->terrain, LAND_REGION)) { return; } - + /* Mallornbäume kann man nur in Mallornregionen züchten */ if (fval(r, RF_MALLORN)) { rtype = rt_mallornseed; } else { rtype = rt_seed; } - + /* Skill prüfen */ skill = eff_skill(u, SK_HERBALISM, r); if (skill < 12) { planttrees(r, u, raw); return; } - + /* wenn eine Anzahl angegeben wurde, nur soviel verbrauchen */ - raw = MIN(skill*u->number, raw); + raw = MIN(skill * u->number, raw); n = get_pooled(u, rtype, GET_DEFAULT, raw); /* Samen prüfen */ - if (n==0) { + if (n == 0) { ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype)); + msg_feedback(u, u->thisorder, "resource_missing", "missing", rtype)); return; } n = MIN(raw, n); - + /* Für jeden Samen Talent*5% Erfolgschance. */ - for(i = n; i>0; i--) { - if (rng_int()%100 < skill*5) planted++; + for (i = n; i > 0; i--) { + if (rng_int() % 100 < skill * 5) + planted++; } - rsettrees(r, 1, rtrees(r, 1)+planted); - + rsettrees(r, 1, rtrees(r, 1) + planted); + /* Alles ok. Abziehen. */ produceexp(u, SK_HERBALISM, u->number); use_pooled(u, rtype, GET_DEFAULT, n); - + ADDMSG(&u->faction->msgs, msg_message("plant", - "unit region amount herb", u, r, planted, rtype)); + "unit region amount herb", u, r, planted, rtype)); } /* züchte pferde */ -static void -breedhorses(region *r, unit *u) +static void breedhorses(region * r, unit * u) { int n, c; + int gezuechtet = 0; - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - - if (btype!=bt_find("stables")) { + + struct building *b = inside_building(u); + + const struct building_type *btype = b ? b->type : NULL; + + if (btype != bt_find("stables")) { cmistake(u, u->thisorder, 122, MSG_PRODUCE); return; } @@ -2736,23 +3055,26 @@ breedhorses(region *r, unit *u) gezuechtet++; } } - + produceexp(u, SK_HORSE_TRAINING, u->number); - ADDMSG(&u->faction->msgs, msg_message("raised", - "unit amount", u, gezuechtet)); + ADDMSG(&u->faction->msgs, msg_message("raised", + "unit amount", u, gezuechtet)); } -static void -breed_cmd(unit *u, struct order * ord) +static void breed_cmd(unit * u, struct order *ord) { int m; - const char *s; - param_t p; - region *r = u->region; - const resource_type * rtype = NULL; - if (r->land==NULL) { + const char *s; + + param_t p; + + region *r = u->region; + + const resource_type *rtype = NULL; + + if (r->land == NULL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); return; } @@ -2763,71 +3085,69 @@ breed_cmd(unit *u, struct order * ord) s = getstrtoken(); m = atoi((const char *)s); - if (m!=0) { + if (m != 0) { /* first came a want-paramter */ s = getstrtoken(); } else { m = INT_MAX; } - + if (!s[0]) { p = P_ANY; } else { p = findparam(s, u->faction->locale); } - + switch (p) { - case P_HERBS: - plant(r, u, m); - break; - case P_TREES: - breedtrees(r, u, m); - break; - default: - if (p!=P_ANY) { - rtype = findresourcetype(s, u->faction->locale); - if (rtype==rt_mallornseed || rtype==rt_seed) { - breedtrees(r, u, m); - break; - } else if (rtype!=oldresourcetype[R_HORSE]) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_cannotmake", "")); - break; + case P_HERBS: + plant(r, u, m); + break; + case P_TREES: + breedtrees(r, u, m); + break; + default: + if (p != P_ANY) { + rtype = findresourcetype(s, u->faction->locale); + if (rtype == rt_mallornseed || rtype == rt_seed) { + breedtrees(r, u, m); + break; + } else if (rtype != oldresourcetype[R_HORSE]) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_cannotmake", + "")); + break; + } } - } - breedhorses(r, u); - break; + breedhorses(r, u); + break; } } -static const char * -rough_amount(int a, int m) - +static const char *rough_amount(int a, int m) { - int p = (a * 100)/m; + int p = (a * 100) / m; - if (p < 10) { - return "sehr wenige"; - } else if (p < 30) { - return "wenige"; - } else if (p < 60) { - return "relativ viele"; - } else if (p < 90) { - return "viele"; - } - return "sehr viele"; + if (p < 10) { + return "sehr wenige"; + } else if (p < 30) { + return "wenige"; + } else if (p < 60) { + return "relativ viele"; + } else if (p < 90) { + return "viele"; + } + return "sehr viele"; } -static void -research_cmd(unit *u, struct order * ord) +static void research_cmd(unit * u, struct order *ord) { region *r = u->region; init_tokens(ord); skip_token(); /* - const char *s = getstrtoken(); + const char *s = getstrtoken(); - if (findparam(s, u->faction->locale) == P_HERBS) { */ + if (findparam(s, u->faction->locale) == P_HERBS) { */ if (eff_skill(u, SK_HERBALISM, r) < 7) { cmistake(u, ord, 227, MSG_EVENT); @@ -2840,23 +3160,23 @@ research_cmd(unit *u, struct order * ord) const item_type *itype = rherbtype(r); if (itype != NULL) { - ADDMSG(&u->faction->msgs, msg_message("researchherb", - "unit region amount herb", - u, r, rough_amount(rherbs(r), 100), itype->rtype)); + ADDMSG(&u->faction->msgs, msg_message("researchherb", + "unit region amount herb", + u, r, rough_amount(rherbs(r), 100), itype->rtype)); } else { - ADDMSG(&u->faction->msgs, msg_message("researchherb_none", - "unit region", u, r)); + ADDMSG(&u->faction->msgs, msg_message("researchherb_none", + "unit region", u, r)); } } else { ADDMSG(&u->faction->msgs, msg_message("researchherb_none", - "unit region", u, r)); + "unit region", u, r)); } } -static int -max_skill(region * r, faction * f, skill_t sk) +static int max_skill(region * r, faction * f, skill_t sk) { unit *u; + int w = 0; for (u = r->units; u; u = u->next) { @@ -2870,21 +3190,27 @@ max_skill(region * r, faction * f, skill_t sk) return w; } -static void -steal_cmd(unit * u, struct order * ord, request ** stealorders) +static void steal_cmd(unit * u, struct order *ord, request ** stealorders) { int n, i, id; + boolean goblin = false; - request * o; - unit * u2 = NULL; - region * r = u->region; - faction * f = NULL; - plane * pl; + + request *o; + + unit *u2 = NULL; + + region *r = u->region; + + faction *f = NULL; + + plane *pl; assert(skill_enabled[SK_PERCEPTION] && skill_enabled[SK_STEALTH]); if (!fval(u->race, RCF_CANSTEAL)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_nosteal", "race", u->race)); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_nosteal", "race", + u->race)); return; } @@ -2902,129 +3228,141 @@ steal_cmd(unit * u, struct order * ord, request ** stealorders) init_tokens(ord); skip_token(); id = read_unitid(u->faction, r); - u2 = findunitr(r, id); + u2 = findunitr(r, id); - if (u2 && u2->region==u->region) { - f = u2->faction; - } else { - f = dfindhash(id); - } + if (u2 && u2->region == u->region) { + f = u2->faction; + } else { + f = dfindhash(id); + } - for (u2=r->units;u2;u2=u2->next) { - if (u2->faction == f && cansee(u->faction, r, u2, 0)) break; - } + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->faction == f && cansee(u->faction, r, u2, 0)) + break; + } - if (!u2) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return; - } + if (!u2) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", + "")); + return; + } - if (IsImmune(u2->faction)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "newbie_immunity_error", - "turns", NewbieImmunity())); - return; - } + if (IsImmune(u2->faction)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "newbie_immunity_error", "turns", NewbieImmunity())); + return; + } - if (u->faction->alliance && u->faction->alliance == u2->faction->alliance) { - cmistake(u, ord, 47, MSG_INCOME); - return; - } + if (u->faction->alliance && u->faction->alliance == u2->faction->alliance) { + cmistake(u, ord, 47, MSG_INCOME); + return; + } - assert(u->region==u2->region); - if (!can_contact(r, u, u2)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error60", "")); - return; - } + assert(u->region == u2->region); + if (!can_contact(r, u, u2)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error60", "")); + return; + } - n = eff_skill(u, SK_STEALTH, r) - max_skill(r, f, SK_PERCEPTION); + n = eff_skill(u, SK_STEALTH, r) - max_skill(r, f, SK_PERCEPTION); - if (n <= 0) { - /* Wahrnehmung == Tarnung */ - if (u->race != new_race[RC_GOBLIN] || eff_skill(u, SK_STEALTH, r) <= 3) { + if (n <= 0) { + /* Wahrnehmung == Tarnung */ + if (u->race != new_race[RC_GOBLIN] || eff_skill(u, SK_STEALTH, r) <= 3) { ADDMSG(&u->faction->msgs, msg_message("stealfail", "unit target", u, u2)); - if (n==0) { + if (n == 0) { ADDMSG(&u2->faction->msgs, msg_message("stealdetect", "unit", u2)); } else { - ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target", u, u2)); + ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target", + u, u2)); } return; - } else { - ADDMSG(&u->faction->msgs, msg_message("stealfatal", "unit target", u, u2)); - ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target", u, u2)); + } else { + ADDMSG(&u->faction->msgs, msg_message("stealfatal", "unit target", u, + u2)); + ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target", u, + u2)); n = 1; - goblin = true; - } - } + goblin = true; + } + } - i = MIN(u->number, get_item(u, I_RING_OF_NIMBLEFINGER)); - if (i > 0) { - n *= STEALINCOME * (u->number + i * (roqf_factor()-1)); - } else { - n *= u->number * STEALINCOME; - } + i = MIN(u->number, get_item(u, I_RING_OF_NIMBLEFINGER)); + if (i > 0) { + n *= STEALINCOME * (u->number + i * (roqf_factor() - 1)); + } else { + n *= u->number * STEALINCOME; + } - u->wants = n; + u->wants = n; - /* wer dank unsichtbarkeitsringen klauen kann, muss nicht unbedingt ein - * guter dieb sein, schliesslich macht man immer noch sehr viel laerm */ + /* wer dank unsichtbarkeitsringen klauen kann, muss nicht unbedingt ein + * guter dieb sein, schliesslich macht man immer noch sehr viel laerm */ - o = (request *) calloc(1, sizeof(request)); - o->unit = u; - o->qty = 1; /* Betrag steht in u->wants */ - o->no = u2->no; - o->type.goblin = goblin; /* Merken, wenn Goblin-Spezialklau */ - addlist(stealorders, o); + o = (request *) calloc(1, sizeof(request)); + o->unit = u; + o->qty = 1; /* Betrag steht in u->wants */ + o->no = u2->no; + o->type.goblin = goblin; /* Merken, wenn Goblin-Spezialklau */ + addlist(stealorders, o); - /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ + /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ - produceexp(u, SK_STEALTH, MIN(n, u->number)); + produceexp(u, SK_STEALTH, MIN(n, u->number)); } + /* ------------------------------------------------------------- */ -static void -expandentertainment(region * r) +static void expandentertainment(region * r) { - unit *u; - int m = entertainmoney(r); - request *o; + unit *u; - for (o = &entertainers[0]; o != nextentertainer; ++o) { - double part = m / (double) entertaining; - u = o->unit; - if (entertaining <= m) - u->n = o->qty; - else - u->n = (int) (o->qty * part); - change_money(u, u->n); - rsetmoney(r, rmoney(r) - u->n); - m -= u->n; - entertaining -= o->qty; + int m = entertainmoney(r); - /* Nur soviel PRODUCEEXP wie auch tatsächlich gemacht wurde */ - produceexp(u, SK_ENTERTAINMENT, MIN(u->n, u->number)); - add_income(u, IC_ENTERTAIN, o->qty, u->n); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); - } + request *o; + + for (o = &entertainers[0]; o != nextentertainer; ++o) { + double part = m / (double)entertaining; + + u = o->unit; + if (entertaining <= m) + u->n = o->qty; + else + u->n = (int)(o->qty * part); + change_money(u, u->n); + rsetmoney(r, rmoney(r) - u->n); + m -= u->n; + entertaining -= o->qty; + + /* Nur soviel PRODUCEEXP wie auch tatsächlich gemacht wurde */ + produceexp(u, SK_ENTERTAINMENT, MIN(u->n, u->number)); + add_income(u, IC_ENTERTAIN, o->qty, u->n); + fset(u, UFL_LONGACTION | UFL_NOTMOVING); + } } -void -entertain_cmd(unit * u, struct order * ord) +void entertain_cmd(unit * u, struct order *ord) { - region * r = u->region; + region *r = u->region; + int max_e; + request *o; + static int entertainbase = 0; + static int entertainperlevel = 0; if (!entertainbase) { - const char * str = get_param(global.parameters, "entertain.base"); - entertainbase = str?atoi(str):0; + const char *str = get_param(global.parameters, "entertain.base"); + + entertainbase = str ? atoi(str) : 0; } if (!entertainperlevel) { - const char * str = get_param(global.parameters, "entertain.perlevel"); - entertainperlevel = str?atoi(str):0; + const char *str = get_param(global.parameters, "entertain.perlevel"); + + entertainperlevel = str ? atoi(str) : 0; } if (fval(u, UFL_WERE)) { cmistake(u, ord, 58, MSG_INCOME); @@ -3048,13 +3386,13 @@ entertain_cmd(unit * u, struct order * ord) } u->wants = u->number * (entertainbase + effskill(u, SK_ENTERTAINMENT) - * entertainperlevel); + * entertainperlevel); init_tokens(ord); skip_token(); max_e = getuint(); if (max_e != 0) { - u->wants = MIN(u->wants,max_e); + u->wants = MIN(u->wants, max_e); } o = nextentertainer++; o->unit = u; @@ -3069,50 +3407,60 @@ static void expandwork(region * r, request * work_begin, request * work_end, int maxwork) { int earnings; + /* n: verbleibende Einnahmen */ /* fishes: maximale Arbeiter */ int jobs = maxwork; + int p_wage = wage(r, NULL, NULL, turn); + int money = rmoney(r); + request *o; for (o = work_begin; o != work_end; ++o) { - unit * u = o->unit; + unit *u = o->unit; + int workers; - if (u->number == 0) continue; + if (u->number == 0) + continue; - if (jobs>=working) workers = u->number; + if (jobs >= working) + workers = u->number; else { workers = u->number * jobs / working; - if (rng_int() % working < (u->number * jobs) % working) workers++; + if (rng_int() % working < (u->number * jobs) % working) + workers++; } - assert(workers>=0); + assert(workers >= 0); u->n = workers * wage(u->region, u->faction, u->race, turn); jobs -= workers; - assert(jobs>=0); + assert(jobs >= 0); change_money(u, u->n); working -= o->unit->number; add_income(u, IC_WORK, o->qty, u->n); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); + fset(u, UFL_LONGACTION | UFL_NOTMOVING); } - if (jobs>rpeasants(r)) { + if (jobs > rpeasants(r)) { jobs = rpeasants(r); } earnings = jobs * p_wage; - if (rule_blessed_harvest()==HARVEST_TAXES) { + if (rule_blessed_harvest() == HARVEST_TAXES) { /* E3 rules */ - static const curse_type * blessedharvest_ct; + static const curse_type *blessedharvest_ct; + if (!blessedharvest_ct) { blessedharvest_ct = ct_find("blessedharvest"); } if (blessedharvest_ct && r->attribs) { - int happy = (int)curse_geteffect(get_curse(r->attribs, blessedharvest_ct)); + int happy = + (int)curse_geteffect(get_curse(r->attribs, blessedharvest_ct)); happy = MIN(happy, jobs); earnings += happy; } @@ -3120,23 +3468,26 @@ expandwork(region * r, request * work_begin, request * work_end, int maxwork) rsetmoney(r, money + earnings); } -static int -do_work(unit * u, order * ord, request * o) +static int do_work(unit * u, order * ord, request * o) { if (playerrace(u->race)) { - region * r = u->region; + region *r = u->region; + int w; if (fval(u, UFL_WERE)) { - if (ord) cmistake(u, ord, 313, MSG_INCOME); + if (ord) + cmistake(u, ord, 313, MSG_INCOME); return -1; } if (besieged(u)) { - if (ord) cmistake(u, ord, 60, MSG_INCOME); + if (ord) + cmistake(u, ord, 60, MSG_INCOME); return -1; } if (u->ship && is_guarded(r, u, GUARD_CREWS)) { - if (ord) cmistake(u, ord, 69, MSG_INCOME); + if (ord) + cmistake(u, ord, 69, MSG_INCOME); return -1; } w = wage(r, u->faction, u->race, turn); @@ -3145,46 +3496,49 @@ do_work(unit * u, order * ord, request * o) o->qty = u->number * w; working += u->number; return 0; - } - else if (ord && !is_monsters(u->faction)) { + } else if (ord && !is_monsters(u->faction)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_cantwork", "race", u->race)); } return -1; } -static void -expandtax(region * r, request * taxorders) +static void expandtax(region * r, request * taxorders) { unit *u; + int i; expandorders(r, taxorders); - if (!norders) return; + if (!norders) + return; for (i = 0; i != norders && rmoney(r) > TAXFRACTION; i++) { change_money(oa[i].unit, TAXFRACTION); oa[i].unit->n += TAXFRACTION; - rsetmoney(r, rmoney(r) -TAXFRACTION); + rsetmoney(r, rmoney(r) - TAXFRACTION); } free(oa); for (u = r->units; u; u = u->next) { if (u->n >= 0) { add_income(u, IC_TAX, u->wants, u->n); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); + fset(u, UFL_LONGACTION | UFL_NOTMOVING); } } } -void -tax_cmd(unit * u, struct order * ord, request ** taxorders) +void tax_cmd(unit * u, struct order *ord, request ** taxorders) { /* Steuern werden noch vor der Forschung eingetrieben */ - region * r = u->region; + region *r = u->region; + unit *u2; + int n; + request *o; + int max; if (!humanoidrace(u->race) && !is_monsters(u->faction)) { @@ -3212,115 +3566,133 @@ tax_cmd(unit * u, struct order * ord, request ** taxorders) skip_token(); max = getuint(); - if (max == 0) max = INT_MAX; - if (!playerrace(u->race)) { - u->wants = MIN(income(u), max); - } else { - u->wants = MIN(n * eff_skill(u, SK_TAXING, r) * 20, max); - } + if (max == 0) + max = INT_MAX; + if (!playerrace(u->race)) { + u->wants = MIN(income(u), max); + } else { + u->wants = MIN(n * eff_skill(u, SK_TAXING, r) * 20, max); + } - u2 = is_guarded(r, u, GUARD_TAX); - if (u2) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "region_guarded", "guard", u2)); - return; - } + u2 = is_guarded(r, u, GUARD_TAX); + if (u2) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "region_guarded", "guard", u2)); + return; + } - /* die einnahmen werden in fraktionen von 10 silber eingeteilt: diese - * fraktionen werden dann bei eintreiben unter allen eintreibenden - * einheiten aufgeteilt. */ + /* die einnahmen werden in fraktionen von 10 silber eingeteilt: diese + * fraktionen werden dann bei eintreiben unter allen eintreibenden + * einheiten aufgeteilt. */ - o = (request *) calloc(1, sizeof(request)); - o->qty = u->wants / TAXFRACTION; - o->unit = u; - addlist(taxorders, o); - return; + o = (request *) calloc(1, sizeof(request)); + o->qty = u->wants / TAXFRACTION; + o->unit = u; + addlist(taxorders, o); + return; } #define MAX_WORKERS 2048 -void -auto_work(region * r) +void auto_work(region * r) { request workers[MAX_WORKERS]; - request * nextworker = workers; - unit * u; - for (u=r->units;u;u=u->next) { + request *nextworker = workers; + + unit *u; + + for (u = r->units; u; u = u->next) { if (!(u->flags & UFL_LONGACTION) && !is_monsters(u->faction)) { - if (do_work(u, NULL, nextworker)==0) { - assert(nextworker-workersfaction!=f) return; + if (u == NULL || u->faction != f) + return; maxsize = buildingeffsize(b, false); - if (maxsize>0) { + if (maxsize > 0) { double taxfactor = money * b->type->taxes(b, maxsize); + double morale = money * region_get_morale(r) * MORALE_TAX_FACTOR; - if (taxfactor>morale) taxfactor = morale; - if (taxfactor>0) { + + if (taxfactor > morale) + taxfactor = morale; + if (taxfactor > 0) { int taxmoney = (int)taxfactor; + change_money(u, taxmoney); rsetmoney(r, money - taxmoney); - ADDMSG(&u->faction->msgs, msg_message("income_tax", - "unit region amount", u, r, taxmoney)); + ADDMSG(&u->faction->msgs, msg_message("income_tax", + "unit region amount", u, r, taxmoney)); } } } -void -produce(struct region *r) +void produce(struct region *r) { request workers[MAX_WORKERS]; + request *taxorders, *sellorders, *stealorders, *buyorders; + unit *u; + int todo; + static int rule_autowork = -1; + boolean limited = true; - request * nextworker = workers; + + request *nextworker = workers; + assert(r); /* das sind alles befehle, die 30 tage brauchen, und die in thisorder - * stehen! von allen 30-tage befehlen wird einfach der letzte verwendet - * (dosetdefaults). - * - * kaufen vor einnahmequellen. da man in einer region dasselbe produkt - * nicht kaufen und verkaufen kann, ist die reihenfolge wegen der - * produkte egal. nicht so wegen dem geld. - * - * lehren vor lernen. */ + * stehen! von allen 30-tage befehlen wird einfach der letzte verwendet + * (dosetdefaults). + * + * kaufen vor einnahmequellen. da man in einer region dasselbe produkt + * nicht kaufen und verkaufen kann, ist die reihenfolge wegen der + * produkte egal. nicht so wegen dem geld. + * + * lehren vor lernen. */ - if (rule_autowork<0) { + if (rule_autowork < 0) { rule_autowork = get_param_int(global.parameters, "work.auto", 0); } - + assert(rmoney(r) >= 0); assert(rpeasants(r) >= 0); @@ -3338,51 +3710,54 @@ produce(struct region *r) stealorders = 0; for (u = r->units; u; u = u->next) { - order * ord; + order *ord; + boolean trader = false; if (u->race == new_race[RC_SPELL] || fval(u, UFL_LONGACTION)) continue; if (u->race == new_race[RC_INSECT] && r_insectstalled(r) && - !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) + !is_cursed(u->attribs, C_KAELTESCHUTZ, 0)) continue; - if (fval(u, UFL_LONGACTION) && u->thisorder==NULL) { + if (fval(u, UFL_LONGACTION) && u->thisorder == NULL) { /* this message was already given in laws.setdefaults - cmistake(u, u->thisorder, 52, MSG_PRODUCE); - */ + cmistake(u, u->thisorder, 52, MSG_PRODUCE); + */ continue; } - for (ord = u->orders;ord;ord=ord->next) { + for (ord = u->orders; ord; ord = ord->next) { switch (get_keyword(ord)) { - case K_BUY: - buy(u, &buyorders, ord); - trader = true; - break; - case K_SELL: - /* sell returns true if the sale is not limited - * by the region limit */ - limited &= !sell(u, &sellorders, ord); - trader = true; - break; + case K_BUY: + buy(u, &buyorders, ord); + trader = true; + break; + case K_SELL: + /* sell returns true if the sale is not limited + * by the region limit */ + limited &= !sell(u, &sellorders, ord); + trader = true; + break; } } if (trader) { - attrib * a = a_find(u->attribs, &at_trades); + attrib *a = a_find(u->attribs, &at_trades); + if (a && a->data.i) { produceexp(u, SK_TRADE, u->number); } - fset(u, UFL_LONGACTION|UFL_NOTMOVING); + fset(u, UFL_LONGACTION | UFL_NOTMOVING); continue; } todo = get_keyword(u->thisorder); - if (todo == NOKEYWORD) continue; + if (todo == NOKEYWORD) + continue; if (fval(r->terrain, SEA_REGION) && u->race != new_race[RC_AQUARIAN] - && !(u->race->flags & RCF_SWIM) + && !(u->race->flags & RCF_SWIM) && todo != K_STEAL && todo != K_SPY && todo != K_SABOTAGE) continue; @@ -3393,8 +3768,8 @@ produce(struct region *r) break; case K_WORK: - if (!rule_autowork && do_work(u, u->thisorder, nextworker)==0) { - assert(nextworker-workersthisorder, nextworker) == 0) { + assert(nextworker - workers < MAX_WORKERS); ++nextworker; } break; @@ -3427,32 +3802,38 @@ produce(struct region *r) } /* Entertainment (expandentertainment) und Besteuerung (expandtax) vor den - * Befehlen, die den Bauern mehr Geld geben, damit man aus den Zahlen der - * letzten Runde berechnen kann, wieviel die Bauern für Unterhaltung - * auszugeben bereit sind. */ - if (entertaining) expandentertainment(r); + * Befehlen, die den Bauern mehr Geld geben, damit man aus den Zahlen der + * letzten Runde berechnen kann, wieviel die Bauern für Unterhaltung + * auszugeben bereit sind. */ + if (entertaining) + expandentertainment(r); if (!rule_autowork) { expandwork(r, workers, nextworker, maxworkingpeasants(r)); } - if (taxorders) expandtax(r, taxorders); + if (taxorders) + expandtax(r, taxorders); /* An erster Stelle Kaufen (expandbuying), die Bauern so Geld bekommen, um - * nachher zu beim Verkaufen (expandselling) den Spielern abkaufen zu - * können. */ + * nachher zu beim Verkaufen (expandselling) den Spielern abkaufen zu + * können. */ - if (buyorders) expandbuying(r, buyorders); + if (buyorders) + expandbuying(r, buyorders); if (sellorders) { int limit = rpeasants(r) / TRADE_FRACTION; - if (r->terrain == newterrain(T_DESERT) && buildingtype_exists(r, bt_find("caravan"), true)) + + if (r->terrain == newterrain(T_DESERT) + && buildingtype_exists(r, bt_find("caravan"), true)) limit *= 2; - expandselling(r, sellorders, limited?limit:INT_MAX); + expandselling(r, sellorders, limited ? limit : INT_MAX); } /* Die Spieler sollen alles Geld verdienen, bevor sie beklaut werden - * (expandstealing). */ + * (expandstealing). */ - if (stealorders) expandstealing(r, stealorders); + if (stealorders) + expandstealing(r, stealorders); assert(rmoney(r) >= 0); assert(rpeasants(r) >= 0); diff --git a/src/gamecode/economy.h b/src/gamecode/economy.h index db8359a63..9d931e433 100644 --- a/src/gamecode/economy.h +++ b/src/gamecode/economy.h @@ -37,22 +37,24 @@ extern "C" { #define TRADE_FRACTION 100 -extern int income(const struct unit * u); + extern int income(const struct unit *u); /* Wieviel Fremde eine Partei pro Woche aufnehmen kann */ #define MAXNEWBIES 5 -void economics(struct region *r); -void produce(struct region *r); -void auto_work(struct region * r); + void economics(struct region *r); + void produce(struct region *r); + void auto_work(struct region *r); -enum { IC_WORK, IC_ENTERTAIN, IC_TAX, IC_TRADE, IC_TRADETAX, IC_STEAL, IC_MAGIC }; -void maintain_buildings(struct region * r, boolean crash); -extern void add_spende(struct faction * f1, struct faction * f2, int betrag, struct region * r); -extern int make_cmd(struct unit * u, struct order * ord); -extern void split_allocations(struct region * r); -extern int recruit_archetypes(void); -extern int give_control_cmd(struct unit * u, struct order * ord); + enum { IC_WORK, IC_ENTERTAIN, IC_TAX, IC_TRADE, IC_TRADETAX, IC_STEAL, + IC_MAGIC }; + void maintain_buildings(struct region *r, boolean crash); + extern void add_spende(struct faction *f1, struct faction *f2, int betrag, + struct region *r); + extern int make_cmd(struct unit *u, struct order *ord); + extern void split_allocations(struct region *r); + extern int recruit_archetypes(void); + extern int give_control_cmd(struct unit *u, struct order *ord); #ifdef __cplusplus } diff --git a/src/gamecode/give.c b/src/gamecode/give.c index 0bc783645..88cfc637b 100644 --- a/src/gamecode/give.c +++ b/src/gamecode/give.c @@ -48,65 +48,71 @@ /* Wieviel Fremde eine Partei pro Woche aufnehmen kangiven */ #define MAXNEWBIES 5 -#define RESERVE_DONATIONS /* shall we reserve objects given to us by other factions? */ -#define RESERVE_GIVE /* reserve anything that's given from one unit to another? */ +#define RESERVE_DONATIONS /* shall we reserve objects given to us by other factions? */ +#define RESERVE_GIVE /* reserve anything that's given from one unit to another? */ -static int -GiveRestriction(void) { +static int GiveRestriction(void) +{ static int value = -1; - if (value<0) { - const char * str = get_param(global.parameters, "GiveRestriction"); - value = str?atoi(str):0; + + if (value < 0) { + const char *str = get_param(global.parameters, "GiveRestriction"); + + value = str ? atoi(str) : 0; } return value; } static void -add_give(unit * u, unit * u2, int given, int received, const resource_type * rtype, struct order * ord, int error) +add_give(unit * u, unit * u2, int given, int received, + const resource_type * rtype, struct order *ord, int error) { if (error) { cmistake(u, ord, error, MSG_COMMERCE); - } - else if (u2==NULL) { + } else if (u2 == NULL) { ADDMSG(&u->faction->msgs, - msg_message("give_peasants", "unit resource amount", - u, rtype, given)); - } else if (u2->faction!=u->faction) { - message * msg; - - msg = msg_message("give", "unit target resource amount", u, u2, rtype, given); + msg_message("give_peasants", "unit resource amount", u, rtype, given)); + } else if (u2->faction != u->faction) { + message *msg; + + msg = + msg_message("give", "unit target resource amount", u, u2, rtype, given); add_message(&u->faction->msgs, msg); msg_release(msg); - msg = msg_message("receive", "unit target resource amount", u, u2, rtype, received); + msg = + msg_message("receive", "unit target resource amount", u, u2, rtype, + received); add_message(&u2->faction->msgs, msg); msg_release(msg); } } -static boolean -limited_give(const item_type * type) +static boolean limited_give(const item_type * type) { /* trade only money 2:1, if at all */ return (type == i_silver); } -int give_quota(const unit * src, const unit * dst, const item_type * type, int n) +int give_quota(const unit * src, const unit * dst, const item_type * type, + int n) { static float divisor = -1; - if (divisor==0 || !limited_give(type)) { + if (divisor == 0 || !limited_give(type)) { return n; } - if (dst && src && src->faction!=dst->faction) { - if (divisor<0) { + if (dst && src && src->faction != dst->faction) { + if (divisor < 0) { divisor = get_param_flt(global.parameters, "rules.items.give_divisor", 1); - assert(divisor==0 || divisor>=1); + + assert(divisor == 0 || divisor >= 1); } - if (divisor>=1) { + if (divisor >= 1) { /* predictable > correct: */ - int x = (int)(n/divisor); + int x = (int)(n / divisor); + return x; } } @@ -114,34 +120,42 @@ int give_quota(const unit * src, const unit * dst, const item_type * type, int n } int -give_item(int want, const item_type * itype, unit * src, unit * dest, struct order * ord) +give_item(int want, const item_type * itype, unit * src, unit * dest, + struct order *ord) { short error = 0; + int n, r; - assert(itype!=NULL); + assert(itype != NULL); n = get_pooled(src, item2resource(itype), GET_DEFAULT, want); n = MIN(want, n); r = n; - if (dest && src->faction != dest->faction && src->faction->age < GiveRestriction()) { - if (ord!=NULL) { + if (dest && src->faction != dest->faction + && src->faction->age < GiveRestriction()) { + if (ord != NULL) { ADDMSG(&src->faction->msgs, msg_feedback(src, ord, "giverestriction", - "turns", GiveRestriction())); + "turns", GiveRestriction())); } return -1; } else if (n == 0) { int reserve = get_reservation(src, itype->rtype); + if (reserve) { - msg_feedback(src, ord, "nogive_reserved", "resource reservation", + msg_feedback(src, ord, "nogive_reserved", "resource reservation", itype->rtype, reserve); return -1; } error = 36; } else if (itype->flags & ITF_CURSED) { error = 25; - } else if (itype->give==NULL || itype->give(src, dest, itype, n, ord)!=0) { + } else if (itype->give == NULL || itype->give(src, dest, itype, n, ord) != 0) { int use = use_pooled(src, item2resource(itype), GET_SLACK, n); - if (useitems, itype, r); @@ -149,7 +163,7 @@ give_item(int want, const item_type * itype, unit * src, unit * dest, struct ord #ifdef RESERVE_DONATIONS change_reservation(dest, item2resource(itype), r); #else - if (src->faction==dest->faction) { + if (src->faction == dest->faction) { change_reservation(dest, item2resource(itype), r); } #endif @@ -165,20 +179,22 @@ give_item(int want, const item_type * itype, unit * src, unit * dest, struct ord handle_event(src->attribs, "give", dest); } add_give(src, dest, n, r, item2resource(itype), ord, error); - if (error) return -1; + if (error) + return -1; return 0; } -void -give_men(int n, unit * u, unit * u2, struct order * ord) +void give_men(int n, unit * u, unit * u2, struct order *ord) { ship *sh; + int k = 0; + int error = 0; if (u2 && u->faction != u2->faction && u->faction->age < GiveRestriction()) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "giverestriction", - "turns", GiveRestriction())); + "turns", GiveRestriction())); return; } else if (u == u2) { error = 10; @@ -186,7 +202,7 @@ give_men(int n, unit * u, unit * u2, struct order * ord) /* snotlings may not be given to the peasants. */ error = 307; } else if (u2 && u2->number && (fval(u, UFL_HERO) != fval(u2, UFL_HERO))) { - /* heroes may not be given to non-heroes and vice versa*/ + /* heroes may not be given to non-heroes and vice versa */ error = 75; } else if (unit_has_cursed_item(u) || (u2 && unit_has_cursed_item(u2))) { error = 78; @@ -195,10 +211,11 @@ give_men(int n, unit * u, unit * u2, struct order * ord) } else if (u2 && fval(u, UFL_HUNGER)) { /* hungry people cannot be given away */ error = 73; - } else if (u2 && (fval(u2, UFL_LOCKED)|| is_cursed(u2->attribs, C_SLAVE, 0))) { + } else if (u2 && (fval(u2, UFL_LOCKED) || is_cursed(u2->attribs, C_SLAVE, 0))) { error = 75; } else if (u2 && !ucontact(u2, u)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", "target", u2)); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", + "target", u2)); error = -1; } else if (u2 && (has_skill(u, SK_MAGIC) || has_skill(u2, SK_MAGIC))) { /* cannot give units to and from magicians */ @@ -206,21 +223,23 @@ give_men(int n, unit * u, unit * u2, struct order * ord) } else if (u2 && (fval(u, UFL_WERE) != fval(u2, UFL_WERE))) { /* werewolves can't be given to non-werewolves and vice-versa */ error = 312; - } else if (u2 && u2->number!=0 && u2->race != u->race) { + } else if (u2 && u2->number != 0 && u2->race != u->race) { log_warning(("faction %s attempts to give %s to %s.\n", - itoa36(u->faction->no), u->race->_name[0], - u2->race->_name[1])); + itoa36(u->faction->no), u->race->_name[0], u2->race->_name[1])); error = 139; - } else if (u2!=NULL && (get_racename(u2->attribs) || get_racename(u->attribs))) { + } else if (u2 != NULL && (get_racename(u2->attribs) + || get_racename(u->attribs))) { error = 139; - } else if (u2 && u2->faction!=u->faction && !rule_transfermen()) { + } else if (u2 && u2->faction != u->faction && !rule_transfermen()) { error = 74; } else { - if (n > u->number) n = u->number; - if (u2 && n+u2->number > UNIT_MAXSIZE) { - n = UNIT_MAXSIZE-u2->number; - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_unit_size", "maxsize", UNIT_MAXSIZE)); - assert(n>=0); + if (n > u->number) + n = u->number; + if (u2 && n + u2->number > UNIT_MAXSIZE) { + n = UNIT_MAXSIZE - u2->number; + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_unit_size", + "maxsize", UNIT_MAXSIZE)); + assert(n >= 0); } if (n == 0) { error = 96; @@ -230,12 +249,12 @@ give_men(int n, unit * u, unit * u2, struct order * ord) } else if (u->race != u2->faction->race) { if (u2->faction->race != new_race[RC_HUMAN]) { error = 120; - } else if (count_migrants(u2->faction) + n > count_maxmigrants(u2->faction)) { + } else if (count_migrants(u2->faction) + n > + count_maxmigrants(u2->faction)) { error = 128; - } - else if (has_limited_skills(u) || has_limited_skills(u2)) { + } else if (has_limited_skills(u) || has_limited_skills(u2)) { error = 154; - } else if (u2->number!=0) { + } else if (u2->number != 0) { error = 139; } } @@ -246,7 +265,7 @@ give_men(int n, unit * u, unit * u2, struct order * ord) k = count_skill(u2->faction, SK_ALCHEMY); /* Falls die Zieleinheit keine Alchemisten sind, werden sie nun - * welche. */ + * welche. */ if (!has_skill(u2, SK_ALCHEMY) && has_skill(u, SK_ALCHEMY)) k += u2->number; @@ -265,40 +284,50 @@ give_men(int n, unit * u, unit * u2, struct order * ord) } } - if (error==0) { + if (error == 0) { if (u2 && u2->number == 0) { set_racename(&u2->attribs, get_racename(u->attribs)); u2->race = u->race; u2->irace = u->irace; - if (fval(u, UFL_HERO)) fset(u2, UFL_HERO); - else freset(u2, UFL_HERO); + if (fval(u, UFL_HERO)) + fset(u2, UFL_HERO); + else + freset(u2, UFL_HERO); } if (u2) { - if (u2->number!=0 && recruit_archetypes()) { + if (u2->number != 0 && recruit_archetypes()) { /* must have same set of skills */ boolean okay = false; - if (u->skill_size==u2->skill_size) { + + if (u->skill_size == u2->skill_size) { int i; - for (i=0;i!=u->skill_size;++i) { + + for (i = 0; i != u->skill_size; ++i) { int j; - for (j=0;j!=u2->skill_size;++j) { - if (u->skills[i].id==u2->skills[j].id) break; + + for (j = 0; j != u2->skill_size; ++j) { + if (u->skills[i].id == u2->skills[j].id) + break; } - if (j!=u2->skill_size) break; + if (j != u2->skill_size) + break; } - if (i==u->skill_size) okay = true; + if (i == u->skill_size) + okay = true; } if (!okay) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "give_cannot_merge", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "give_cannot_merge", + "")); } } /* Einheiten von Schiffen können nicht NACH in von - * Nicht-alliierten bewachten Regionen ausführen */ + * Nicht-alliierten bewachten Regionen ausführen */ sh = leftship(u); - if (sh) set_leftship(u2, sh); + if (sh) + set_leftship(u2, sh); transfermen(u, u2, n); if (u->faction != u2->faction) { @@ -309,7 +338,9 @@ give_men(int n, unit * u, unit * u2, struct order * ord) #ifdef ORCIFICATION if (u->race == new_race[RC_SNOTLING] && !fval(u->region, RF_ORCIFIED)) { attrib *a = a_find(u->region->attribs, &at_orcification); - if (!a) a = a_add(&u->region->attribs, a_new(&at_orcification)); + + if (!a) + a = a_add(&u->region->attribs, a_new(&at_orcification)); a->data.i += n; } #endif @@ -319,26 +350,27 @@ give_men(int n, unit * u, unit * u2, struct order * ord) } } } - if (error>0) { + if (error > 0) { cmistake(u, ord, error, MSG_COMMERCE); } else if (!u2) { ADDMSG(&u->faction->msgs, msg_message("give_person_peasants", "unit amount", u, n)); - } else if (u2->faction!=u->faction) { - message * msg = msg_message("give_person", "unit target amount", u, u2, n); + } else if (u2->faction != u->faction) { + message *msg = msg_message("give_person", "unit target amount", u, u2, n); + add_message(&u->faction->msgs, msg); add_message(&u2->faction->msgs, msg); msg_release(msg); } } -void -give_unit(unit * u, unit * u2, order * ord) +void give_unit(unit * u, unit * u2, order * ord) { - region * r = u->region; + region *r = u->region; + int n = u->number; - if (!rule_transfermen() && u->faction!=u2->faction) { + if (!rule_transfermen() && u->faction != u2->faction) { cmistake(u, ord, 74, MSG_COMMERCE); return; } @@ -363,14 +395,18 @@ give_unit(unit * u, unit * u2, order * ord) } else if (getunitpeasants) { unit *u3; - for(u3 = r->units; u3; u3 = u3->next) - if(u3->faction == u->faction && u != u3) break; + for (u3 = r->units; u3; u3 = u3->next) + if (u3->faction == u->faction && u != u3) + break; - if(u3) { + if (u3) { while (u->items) { - item * iold = i_remove(&u->items, u->items); - item * inew = *i_find(&u3->items, iold->type); - if (inew==NULL) i_add(&u3->items, iold); + item *iold = i_remove(&u->items, u->items); + + item *inew = *i_find(&u3->items, iold->type); + + if (inew == NULL) + i_add(&u3->items, iold); else { inew->number += iold->number; i_free(iold); @@ -380,13 +416,15 @@ give_unit(unit * u, unit * u2, order * ord) give_men(u->number, u, NULL, ord); cmistake(u, ord, 153, MSG_COMMERCE); } else { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", + "")); } return; } if (!alliedunit(u2, u->faction, HELP_GIVE) && ucontact(u2, u) == 0) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", "target", u2)); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", + "target", u2)); return; } if (u->number == 0) { @@ -402,7 +440,8 @@ give_unit(unit * u, unit * u2, order * ord) cmistake(u, ord, 120, MSG_COMMERCE); return; } - if (count_migrants(u2->faction) + u->number > count_maxmigrants(u2->faction)) { + if (count_migrants(u2->faction) + u->number > + count_maxmigrants(u2->faction)) { cmistake(u, ord, 128, MSG_COMMERCE); return; } @@ -412,10 +451,10 @@ give_unit(unit * u, unit * u2, order * ord) } } if (has_skill(u, SK_MAGIC)) { - sc_mage * mage; + sc_mage *mage; + if (count_skill(u2->faction, SK_MAGIC) + u->number > - skill_limit(u2->faction, SK_MAGIC)) - { + skill_limit(u2->faction, SK_MAGIC)) { cmistake(u, ord, 155, MSG_COMMERCE); return; } @@ -427,8 +466,7 @@ give_unit(unit * u, unit * u2, order * ord) } if (has_skill(u, SK_ALCHEMY) && count_skill(u2->faction, SK_ALCHEMY) + u->number > - skill_limit(u2->faction, SK_ALCHEMY)) - { + skill_limit(u2->faction, SK_ALCHEMY)) { cmistake(u, ord, 156, MSG_COMMERCE); return; } diff --git a/src/gamecode/give.h b/src/gamecode/give.h index 9f4e16a64..9d2553e5e 100644 --- a/src/gamecode/give.h +++ b/src/gamecode/give.h @@ -16,9 +16,11 @@ extern "C" { #endif - extern int give_item(int want, const struct item_type * itype, struct unit * src, struct unit * dest, struct order * ord); - extern void give_men(int n, struct unit * u, struct unit * u2, struct order * ord); - extern void give_unit(struct unit * u, struct unit * u2, struct order * ord); + extern int give_item(int want, const struct item_type *itype, + struct unit *src, struct unit *dest, struct order *ord); + extern void give_men(int n, struct unit *u, struct unit *u2, + struct order *ord); + extern void give_unit(struct unit *u, struct unit *u2, struct order *ord); #ifdef __cplusplus } diff --git a/src/gamecode/items.c b/src/gamecode/items.c index 0a6d00a65..6058218b8 100644 --- a/src/gamecode/items.c +++ b/src/gamecode/items.c @@ -33,11 +33,13 @@ /* BEGIN studypotion */ #define MAXGAIN 15 static int -use_studypotion(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +use_studypotion(struct unit *u, const struct item_type *itype, int amount, + struct order *ord) { if (get_keyword(u->thisorder) == K_STUDY) { skill_t sk; - skill * sv; + + skill *sv; init_tokens(u->thisorder); skip_token(); @@ -46,16 +48,19 @@ use_studypotion(struct unit * u, const struct item_type * itype, int amount, str if (sv && sv->level > 2) { /* TODO: message */ - } else if (study_cost(u, sk)>0) { + } else if (study_cost(u, sk) > 0) { /* TODO: message */ } else { - attrib * a = a_find(u->attribs, &at_learning); - teaching_info * teach; - if (a==NULL) { + attrib *a = a_find(u->attribs, &at_learning); + + teaching_info *teach; + + if (a == NULL) { a = a_add(&u->attribs, a_new(&at_learning)); } - teach = (teaching_info*) a->data.v; - if (amount>MAXGAIN) amount = MAXGAIN; + teach = (teaching_info *) a->data.v; + if (amount > MAXGAIN) + amount = MAXGAIN; teach->value += amount * 30; if (teach->value > MAXGAIN * 30) { teach->value = MAXGAIN * 30; @@ -66,102 +71,126 @@ use_studypotion(struct unit * u, const struct item_type * itype, int amount, str } return EUNUSABLE; } + /* END studypotion */ /* BEGIN speedsail */ #define SPEEDSAIL_EFFECT 1 static int -use_speedsail(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +use_speedsail(struct unit *u, const struct item_type *itype, int amount, + struct order *ord) { - curse *c; + curse *c; + double effect; - ship * sh = u->ship; + + ship *sh = u->ship; + if (!sh) { cmistake(u, ord, 20, MSG_MOVE); return -1; } effect = SPEEDSAIL_EFFECT; - c = create_curse(u, &sh->attribs, ct_find("shipspeedup"), 20, INT_MAX, effect, 0); + c = + create_curse(u, &sh->attribs, ct_find("shipspeedup"), 20, INT_MAX, effect, + 0); c_setflag(c, CURSE_NOAGE); - ADDMSG(&u->faction->msgs, msg_message("use_speedsail", "unit speed", u, SPEEDSAIL_EFFECT)); + ADDMSG(&u->faction->msgs, msg_message("use_speedsail", "unit speed", u, + SPEEDSAIL_EFFECT)); use_pooled(u, itype->rtype, GET_DEFAULT, 1); return 0; } + /* END speedsail */ /* ------------------------------------------------------------- */ /* Kann auch von Nichtmagiern benutzt werden, erzeugt eine * Antimagiezone, die zwei Runden bestehen bleibt */ static int -use_antimagiccrystal(unit * u, const struct item_type * itype, int amount, struct order * ord) +use_antimagiccrystal(unit * u, const struct item_type *itype, int amount, + struct order *ord) { - region * r = u->region; - const resource_type * rt_crystal = NULL; + region *r = u->region; + + const resource_type *rt_crystal = NULL; + int i; if (rt_crystal == NULL) { rt_crystal = rt_find("antimagic"); - assert(rt_crystal!=NULL); + assert(rt_crystal != NULL); } - for (i=0;i!=amount;++i) { + for (i = 0; i != amount; ++i) { int effect, duration = 2; + double force; + spell *sp = find_spell(M_NONE, "antimagiczone"); - attrib ** ap = &r->attribs; + + attrib **ap = &r->attribs; + unused(ord); assert(sp); /* Reduziert die Stärke jedes Spruchs um effect */ - effect = sp->level; + effect = sp->level; /* Hält Sprüche bis zu einem summierten Gesamtlevel von power aus. - * Jeder Zauber reduziert die 'Lebenskraft' (vigour) der Antimagiezone - * um seine Stufe */ - force = sp->level * 20; /* Stufe 5 =~ 100 */ + * Jeder Zauber reduziert die 'Lebenskraft' (vigour) der Antimagiezone + * um seine Stufe */ + force = sp->level * 20; /* Stufe 5 =~ 100 */ /* Regionszauber auflösen */ while (*ap && force > 0) { - curse * c; - attrib * a = *ap; + curse *c; + + attrib *a = *ap; + if (!fval(a->type, ATF_CURSE)) { - do { ap = &(*ap)->next; } while (*ap && a->type==(*ap)->type); + do { + ap = &(*ap)->next; + } while (*ap && a->type == (*ap)->type); continue; } - c = (curse*)a->data.v; + c = (curse *) a->data.v; /* Immunität prüfen */ if (c_flags(c) & CURSE_IMMUNE) { - do { ap = &(*ap)->next; } while (*ap && a->type==(*ap)->type); + do { + ap = &(*ap)->next; + } while (*ap && a->type == (*ap)->type); continue; } force = destr_curse(c, effect, force); - if(c->vigour <= 0) { + if (c->vigour <= 0) { a_remove(&r->attribs, a); } - if(*ap) ap = &(*ap)->next; + if (*ap) + ap = &(*ap)->next; } if (force > 0) { - create_curse(u, &r->attribs, ct_find("antimagiczone"), force, duration, effect, 0); + create_curse(u, &r->attribs, ct_find("antimagiczone"), force, duration, + effect, 0); } } use_pooled(u, rt_crystal, GET_DEFAULT, amount); - ADDMSG(&u->faction->msgs, msg_message("use_antimagiccrystal", - "unit region", u, r)); + ADDMSG(&u->faction->msgs, msg_message("use_antimagiccrystal", + "unit region", u, r)); return 0; } static int -use_instantartsculpture(struct unit * u, const struct item_type * itype, - int amount, struct order * ord) +use_instantartsculpture(struct unit *u, const struct item_type *itype, + int amount, struct order *ord) { building *b; - if(u->region->land == NULL) { + if (u->region->land == NULL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); return -1; } @@ -169,8 +198,8 @@ use_instantartsculpture(struct unit * u, const struct item_type * itype, b = new_building(bt_find("artsculpture"), u->region, u->faction->locale); b->size = 100; - ADDMSG(&u->region->msgs, msg_message("artsculpture_create", "unit region", - u, u->region)); + ADDMSG(&u->region->msgs, msg_message("artsculpture_create", "unit region", + u, u->region)); use_pooled(u, itype->rtype, GET_DEFAULT, 1); @@ -178,12 +207,12 @@ use_instantartsculpture(struct unit * u, const struct item_type * itype, } static int -use_instantartacademy(struct unit * u, const struct item_type * itype, - int amount, struct order * ord) +use_instantartacademy(struct unit *u, const struct item_type *itype, + int amount, struct order *ord) { building *b; - if(u->region->land == NULL) { + if (u->region->land == NULL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); return -1; } @@ -191,8 +220,8 @@ use_instantartacademy(struct unit * u, const struct item_type * itype, b = new_building(bt_find("artacademy"), u->region, u->faction->locale); b->size = 100; - ADDMSG(&u->region->msgs, msg_message( - "artacademy_create", "unit region", u, u->region)); + ADDMSG(&u->region->msgs, msg_message("artacademy_create", "unit region", u, + u->region)); use_pooled(u, itype->rtype, GET_DEFAULT, 1); @@ -203,8 +232,8 @@ use_instantartacademy(struct unit * u, const struct item_type * itype, #define BAGPIPEDURATION dice_rand("2d10+4") static int -use_bagpipeoffear(struct unit * u, const struct item_type * itype, - int amount, struct order * ord) +use_bagpipeoffear(struct unit *u, const struct item_type *itype, + int amount, struct order *ord) { int money; @@ -213,7 +242,7 @@ use_bagpipeoffear(struct unit * u, const struct item_type * itype, return -1; } - money = entertainmoney(u->region)/BAGPIPEFRACTION; + money = entertainmoney(u->region) / BAGPIPEFRACTION; change_money(u, money); rsetmoney(u->region, rmoney(u->region) - money); @@ -221,17 +250,17 @@ use_bagpipeoffear(struct unit * u, const struct item_type * itype, 20, BAGPIPEDURATION, 0.0, 0); ADDMSG(&u->faction->msgs, msg_message("bagpipeoffear_faction", - "unit region command money", u, u->region, ord, money)); + "unit region command money", u, u->region, ord, money)); ADDMSG(&u->region->msgs, msg_message("bagpipeoffear_region", - "unit money", u, money)); + "unit money", u, money)); return 0; } static int -use_aurapotion50(struct unit * u, const struct item_type * itype, - int amount, struct order * ord) +use_aurapotion50(struct unit *u, const struct item_type *itype, + int amount, struct order *ord) { if (!is_mage(u)) { cmistake(u, ord, 214, MSG_MAGIC); @@ -241,7 +270,7 @@ use_aurapotion50(struct unit * u, const struct item_type * itype, change_spellpoints(u, 50); ADDMSG(&u->faction->msgs, msg_message("aurapotion50", - "unit region command", u, u->region, ord)); + "unit region command", u, u->region, ord)); use_pooled(u, itype->rtype, GET_DEFAULT, 1); @@ -249,8 +278,7 @@ use_aurapotion50(struct unit * u, const struct item_type * itype, } -void -register_itemfunctions(void) +void register_itemfunctions(void) { register_demonseye(); register_item_use(use_antimagiccrystal, "use_antimagiccrystal"); diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 94144b370..fd571e620 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -59,7 +59,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include /* for volcanoes in emigration (needs a flag) */ +#include /* for volcanoes in emigration (needs a flag) */ #include /* attributes includes */ @@ -108,44 +108,52 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* Wanderungschance pro Pferd */ #define HORSEMOVE 3 /* Vermehrungschance pro Baum */ -#define FORESTGROWTH 10000 /* In Millionstel */ +#define FORESTGROWTH 10000 /* In Millionstel */ /** Ausbreitung und Vermehrung */ #define MAXDEMAND 25 -#define DMRISE 0.1F /* weekly chance that demand goes up */ -#define DMRISEHAFEN 0.2F /* weekly chance that demand goes up with harbor */ +#define DMRISE 0.1F /* weekly chance that demand goes up */ +#define DMRISEHAFEN 0.2F /* weekly chance that demand goes up with harbor */ /* - exported global symbols ----------------------------------- */ boolean nobattle = false; + boolean nomonsters = false; + /* ------------------------------------------------------------- */ -static int -RemoveNMRNewbie(void) { +static int RemoveNMRNewbie(void) +{ static int value = -1; + static int gamecookie = -1; - if (value<0 || gamecookie!=global.cookie) { + if (value < 0 || gamecookie != global.cookie) { value = get_param_int(global.parameters, "nmr.removenewbie", 0); + gamecookie = global.cookie; } return value; } -static void -restart_race(unit *u, const race * rc) +static void restart_race(unit * u, const race * rc) { - faction * oldf = u->faction; - faction *f = addfaction(oldf->email, oldf->passw, rc, oldf->locale, oldf->subscription); - unit * nu = addplayer(u->region, f); - order ** ordp = &u->orders; + faction *oldf = u->faction; + + faction *f = + addfaction(oldf->email, oldf->passw, rc, oldf->locale, oldf->subscription); + unit *nu = addplayer(u->region, f); + + order **ordp = &u->orders; + f->subscription = u->faction->subscription; f->age = u->faction->age; fset(f, FFL_RESTART); if (f->subscription) { - sql_print(("UPDATE subscriptions set faction='%s', race='%s' where id=%u;\n", - itoa36(f->no), dbrace(rc), f->subscription)); + sql_print( + ("UPDATE subscriptions set faction='%s', race='%s' where id=%u;\n", + itoa36(f->no), dbrace(rc), f->subscription)); } f->magiegebiet = u->faction->magiegebiet; f->options = u->faction->options; @@ -153,11 +161,13 @@ restart_race(unit *u, const race * rc) nu->orders = u->orders; u->orders = NULL; while (*ordp) { - order * ord = *ordp; + order *ord = *ordp; + if (get_keyword(ord) != K_RESTART) { *ordp = ord->next; ord->next = NULL; - if (u->thisorder == ord) set_order(&u->thisorder, NULL); + if (u->thisorder == ord) + set_order(&u->thisorder, NULL); } else { ordp = &ord->next; } @@ -165,32 +175,33 @@ restart_race(unit *u, const race * rc) destroyfaction(u->faction); } -static void -checkorders(void) +static void checkorders(void) { faction *f; - if (verbosity>=1) puts(" - Warne spaete Spieler..."); + if (verbosity >= 1) + puts(" - Warne spaete Spieler..."); for (f = factions; f; f = f->next) if (!is_monsters(f) && turn - f->lastorders == NMRTimeout() - 1) ADDMSG(&f->msgs, msg_message("turnreminder", "")); } -static boolean -help_money(const unit * u) +static boolean help_money(const unit * u) { - if (u->race->ec_flags & GIVEITEM) return true; + if (u->race->ec_flags & GIVEITEM) + return true; return false; } -static void -help_feed(unit * donor, unit * u, int * need_p) +static void help_feed(unit * donor, unit * u, int *need_p) { int need = *need_p; + int give = get_money(donor) - lifestyle(donor); + give = MIN(need, give); - if (give>0) { + if (give > 0) { change_money(donor, -give); change_money(u, give); need -= give; @@ -205,21 +216,25 @@ enum { FOOD_IS_FREE = 4 }; -static void -get_food(region *r) +static void get_food(region * r) { - plane * pl = rplane(r); + plane *pl = rplane(r); + unit *u; - int peasantfood = rpeasants(r)*10; + + int peasantfood = rpeasants(r) * 10; + static int food_rules = -1; + static int gamecookie = -1; - if (food_rules<0 || gamecookie!=global.cookie) { + if (food_rules < 0 || gamecookie != global.cookie) { gamecookie = global.cookie; + food_rules = get_param_int(global.parameters, "rules.economy.food", 0); } - if (food_rules&FOOD_IS_FREE) { + if (food_rules & FOOD_IS_FREE) { return; } /* 1. Versorgung von eigenen Einheiten. Das vorhandene Silber @@ -232,13 +247,16 @@ get_food(region *r) /* Erstmal zurücksetzen */ freset(u, UFL_HUNGER); - if (u->ship && (u->ship->flags&SF_FISHING)) { - unit * v; + if (u->ship && (u->ship->flags & SF_FISHING)) { + unit *v; + int c = 2; - for (v=u;c>0 && v;v=v->next) { - if (v->ship==u->ship) { + + for (v = u; c > 0 && v; v = v->next) { + if (v->ship == u->ship) { int get = 0; - if (v->number<=c) { + + if (v->number <= c) { get = lifestyle(v); } else { get = lifestyle(v) * c / v->number; @@ -252,14 +270,17 @@ get_food(region *r) u->ship->flags -= SF_FISHING; } - if (food_rules&FOOD_FROM_PEASANTS) { - faction * owner = region_get_owner(r); + if (food_rules & FOOD_FROM_PEASANTS) { + faction *owner = region_get_owner(r); + /* if the region is owned, and the owner is nice, then we'll get * food from the peasants - should not be used with WORK */ - if (owner!=NULL && (get_alliance(owner, u->faction) & HELP_MONEY)) { + if (owner != NULL && (get_alliance(owner, u->faction) & HELP_MONEY)) { int rm = rmoney(r); + int use = MIN(rm, need); - rsetmoney(r, rm-use); + + rsetmoney(r, rm - use); need -= use; } } @@ -271,8 +292,9 @@ get_food(region *r) for (v = r->units; need && v; v = v->next) { if (v->faction == u->faction && help_money(v)) { int give = get_money(v) - lifestyle(v); + give = MIN(need, give); - if (give>0) { + if (give > 0) { change_money(v, -give); change_money(u, give); need -= give; @@ -286,19 +308,22 @@ get_food(region *r) * entsprechend verteilt. */ for (u = r->units; u; u = u->next) { int need = lifestyle(u); - faction * f = u->faction; + + faction *f = u->faction; need -= MAX(0, get_money(u)); if (need > 0) { unit *v; - if (food_rules&FOOD_FROM_OWNER) { + if (food_rules & FOOD_FROM_OWNER) { /* the owner of the region is the first faction to help out when you're hungry */ - faction * owner = region_get_owner(r); - if (owner && owner!=u->faction) { - for (v=r->units;v;v=v->next) { - if (v->faction==owner && alliedunit(v, f, HELP_MONEY) && help_money(v)) { + faction *owner = region_get_owner(r); + + if (owner && owner != u->faction) { + for (v = r->units; v; v = v->next) { + if (v->faction == owner && alliedunit(v, f, HELP_MONEY) + && help_money(v)) { help_feed(v, u, &need); break; } @@ -314,10 +339,13 @@ get_food(region *r) /* Die Einheit hat nicht genug Geld zusammengekratzt und * nimmt Schaden: */ if (need > 0) { - int lspp = lifestyle(u)/u->number; + int lspp = lifestyle(u) / u->number; + if (lspp > 0) { - int number = (need+lspp-1)/lspp; - if (hunger(number, u)) fset(u, UFL_HUNGER); + int number = (need + lspp - 1) / lspp; + + if (hunger(number, u)) + fset(u, UFL_HUNGER); } } } @@ -328,28 +356,34 @@ get_food(region *r) */ for (u = r->units; u; u = u->next) { if (u->race == new_race[RC_DAEMON]) { - unit * donor = r->units; + unit *donor = r->units; + int hungry = u->number; - while (donor!=NULL && hungry>0) { + while (donor != NULL && hungry > 0) { /* always start with the first known unit that may have some blood */ - static const struct potion_type * pt_blood; - if (pt_blood==NULL) { - const item_type * it_blood = it_find("peasantblood"); - if (it_blood) pt_blood = it_blood->rtype->ptype; + static const struct potion_type *pt_blood; + + if (pt_blood == NULL) { + const item_type *it_blood = it_find("peasantblood"); + + if (it_blood) + pt_blood = it_blood->rtype->ptype; } - if (pt_blood!=NULL) { - while (donor!=NULL) { - if (donor->race==new_race[RC_DAEMON]) { + if (pt_blood != NULL) { + while (donor != NULL) { + if (donor->race == new_race[RC_DAEMON]) { if (get_effect(donor, pt_blood)) { /* if he's in our faction, drain him: */ - if (donor->faction==u->faction) break; + if (donor->faction == u->faction) + break; } } donor = donor->next; } if (donor != NULL) { int blut = get_effect(donor, pt_blood); + blut = MIN(blut, hungry); change_effect(donor, pt_blood, -blut); hungry -= blut; @@ -357,7 +391,7 @@ get_food(region *r) } } if (pl == NULL || !fval(pl, PFL_NOFEED)) { - if (peasantfood>=hungry) { + if (peasantfood >= hungry) { peasantfood -= hungry; hungry = 0; } else { @@ -366,18 +400,20 @@ get_food(region *r) } if (hungry > 0) { static int demon_hunger = -1; - if (demon_hunger<0) { + + if (demon_hunger < 0) { demon_hunger = get_param_int(global.parameters, "hunger.demons", 0); } - if (demon_hunger==0) { + if (demon_hunger == 0) { /* nicht gefütterte dämonen hungern */ #ifdef PEASANT_HUNGRY_DAEMONS_HAVE_FULL_SKILLS /* wdw special rule */ hunger(hungry, u); #else - if (hunger(hungry, u)) fset(u, UFL_HUNGER); + if (hunger(hungry, u)) + fset(u, UFL_HUNGER); #endif - /* used to be: hunger(hungry, u); */ + /* used to be: hunger(hungry, u); */ } else { /* no damage, but set the hungry-flag */ fset(u, UFL_HUNGER); @@ -386,17 +422,17 @@ get_food(region *r) } } } - rsetpeasants(r, peasantfood/10); + rsetpeasants(r, peasantfood / 10); /* 3. Von den überlebenden das Geld abziehen: */ for (u = r->units; u; u = u->next) { int need = MIN(get_money(u), lifestyle(u)); + change_money(u, -need); } } -static void -age_unit(region * r, unit * u) +static void age_unit(region * r, unit * u) { if (u->race == new_race[RC_SPELL]) { if (--u->age <= 0) { @@ -404,63 +440,70 @@ age_unit(region * r, unit * u) } } else { ++u->age; - if (u->number>0 && u->race->age) { + if (u->number > 0 && u->race->age) { u->race->age(u); } } #ifdef ASTRAL_ITEM_RESTRICTIONS if (u->region && is_astral(u->region)) { - item ** itemp = &u->items; + item **itemp = &u->items; + while (*itemp) { - item * itm = *itemp; + item *itm = *itemp; + if ((itm->type->flags & ITF_NOTLOST) == 0) { - if (itm->type->flags & (ITF_BIG|ITF_ANIMAL|ITF_CURSED)) { - ADDMSG(&u->faction->msgs, msg_message("itemcrumble", "unit region item amount", - u, u->region, itm->type->rtype, itm->number)); + if (itm->type->flags & (ITF_BIG | ITF_ANIMAL | ITF_CURSED)) { + ADDMSG(&u->faction->msgs, msg_message("itemcrumble", + "unit region item amount", u, u->region, itm->type->rtype, + itm->number)); i_free(i_remove(itemp, itm)); continue; } } - itemp=&itm->next; + itemp = &itm->next; } } #endif } -static void -live(region * r) +static void live(region * r) { unit **up = &r->units; get_food(r); while (*up) { - unit * u = *up; + unit *u = *up; + /* IUW: age_unit() kann u loeschen, u->next ist dann - * undefiniert, also muessen wir hier schon das nächste - * Element bestimmen */ + * undefiniert, also muessen wir hier schon das nächste + * Element bestimmen */ int effect = get_effect(u, oldpotiontype[P_FOOL]); - if (effect > 0) { /* Trank "Dumpfbackenbrot" */ - skill * sv = u->skills, * sb = NULL; - while (sv!=u->skills+u->skill_size) { - if (sb==NULL || skill_compare(sv, sb)>0) { + + if (effect > 0) { /* Trank "Dumpfbackenbrot" */ + skill *sv = u->skills, *sb = NULL; + + while (sv != u->skills + u->skill_size) { + if (sb == NULL || skill_compare(sv, sb) > 0) { sb = sv; } ++sv; } /* bestes Talent raussuchen */ - if (sb!=NULL) { + if (sb != NULL) { int weeks = MIN(effect, u->number); + reduce_skill(u, sb, weeks); ADDMSG(&u->faction->msgs, msg_message("dumbeffect", - "unit weeks skill", u, weeks, (skill_t)sb->id)); - } /* sonst Glück gehabt: wer nix weiß, kann nix vergessen... */ + "unit weeks skill", u, weeks, (skill_t) sb->id)); + } /* sonst Glück gehabt: wer nix weiß, kann nix vergessen... */ change_effect(u, oldpotiontype[P_FOOL], -effect); } age_unit(r, u); - if (*up==u) up=&u->next; + if (*up == u) + up = &u->next; } } @@ -487,28 +530,34 @@ live(region * r) #define MAX_EMIGRATION(p) ((p)/MAXDIRECTIONS) #define MAX_IMMIGRATION(p) ((p)*2/3) -static void -calculate_emigration(region *r) +static void calculate_emigration(region * r) { int i; - int maxp = maxworkingpeasants(r); - int rp = rpeasants(r); - int max_immigrants = MAX_IMMIGRATION(maxp-rp); - if (r->terrain == newterrain(T_VOLCANO) || r->terrain == newterrain(T_VOLCANO_SMOKING)) { - max_immigrants = max_immigrants/10; + int maxp = maxworkingpeasants(r); + + int rp = rpeasants(r); + + int max_immigrants = MAX_IMMIGRATION(maxp - rp); + + if (r->terrain == newterrain(T_VOLCANO) + || r->terrain == newterrain(T_VOLCANO_SMOKING)) { + max_immigrants = max_immigrants / 10; } - for (i = 0; max_immigrants>0 && i != MAXDIRECTIONS; i++) { - int dir = (turn+i) % MAXDIRECTIONS; - region *rc = rconnect(r, (direction_t)dir); + for (i = 0; max_immigrants > 0 && i != MAXDIRECTIONS; i++) { + int dir = (turn + i) % MAXDIRECTIONS; + + region *rc = rconnect(r, (direction_t) dir); if (rc != NULL && fval(rc->terrain, LAND_REGION)) { int rp2 = rpeasants(rc); + int maxp2 = maxworkingpeasants(rc); - int max_emigration = MAX_EMIGRATION(rp2-maxp2); - - if (max_emigration>0) { + + int max_emigration = MAX_EMIGRATION(rp2 - maxp2); + + if (max_emigration > 0) { max_emigration = MIN(max_emigration, max_immigrants); r->land->newpeasants += max_emigration; rc->land->newpeasants -= max_emigration; @@ -520,36 +569,42 @@ calculate_emigration(region *r) /** Bauern vermehren sich */ -static void -peasants(region * r) +static void peasants(region * r) { int peasants = rpeasants(r); + int money = rmoney(r); + int maxp = production(r) * MAXPEASANTS_PER_AREA; + int n, satiated; + int dead = 0; /* Bis zu 1000 Bauern können Zwillinge bekommen oder 1000 Bauern * wollen nicht! */ - if (peasants>0) { + if (peasants > 0) { int glueck = 0; - double fraction = peasants * 0.0001F * PEASANTGROWTH; - int births = (int)fraction; - attrib * a = a_find(r->attribs, &at_peasantluck); - if (rng_double()<(fraction-births)) { + double fraction = peasants * 0.0001F * PEASANTGROWTH; + + int births = (int)fraction; + + attrib *a = a_find(r->attribs, &at_peasantluck); + + if (rng_double() < (fraction - births)) { /* because we don't want regions that never grow pga. rounding. */ ++births; } - if (a!=NULL) { + if (a != NULL) { glueck = a->data.i * 1000; } for (n = peasants; n; --n) { int chances = 0; - if (glueck>0) { + if (glueck > 0) { --glueck; chances += PEASANTLUCK; } @@ -558,7 +613,7 @@ peasants(region * r) if (rng_int() % 10000 < PEASANTGROWTH) { /* Only raise with 75% chance if peasants have * reached 90% of maxpopulation */ - if (peasants/(float)maxp < 0.9 || chance(PEASANTFORCE)) { + if (peasants / (float)maxp < 0.9 || chance(PEASANTFORCE)) { ++births; } } @@ -579,10 +634,11 @@ peasants(region * r) /* Es verhungert maximal die unterernährten Bevölkerung. */ n = MIN(peasants - satiated, rpeasants(r)); - dead += (int)(0.5F + n * PEASANT_STARVATION_CHANCE); + dead += (int)(0.5F + n * PEASANT_STARVATION_CHANCE); if (dead > 0) { - message * msg = add_message(&r->msgs, msg_message("phunger", "dead", dead)); + message *msg = add_message(&r->msgs, msg_message("phunger", "dead", dead)); + msg_release(msg); peasants -= dead; } @@ -593,29 +649,33 @@ peasants(region * r) /* ------------------------------------------------------------- */ typedef struct migration { - struct migration * next; - region * r; + struct migration *next; + region *r; int horses; int trees; } migration; #define MSIZE 1023 -migration * migrants[MSIZE]; -migration * free_migrants; +migration *migrants[MSIZE]; -static migration * -get_migrants(region * r) +migration *free_migrants; + +static migration *get_migrants(region * r) { int key = reg_hashkey(r); + int index = key % MSIZE; - migration * m = migrants[index]; + + migration *m = migrants[index]; + while (m && m->r != r) m = m->next; if (m == NULL) { /* Es gibt noch keine Migration. Also eine erzeugen */ m = free_migrants; - if (!m) m = calloc(1, sizeof(migration)); + if (!m) + m = calloc(1, sizeof(migration)); else { free_migrants = free_migrants->next; m->horses = 0; @@ -628,16 +688,20 @@ get_migrants(region * r) return m; } -static void -migrate(region * r) +static void migrate(region * r) { int key = reg_hashkey(r); + int index = key % MSIZE; - migration ** hp = &migrants[index]; + + migration **hp = &migrants[index]; + fset(r, RF_MIGRATION); - while (*hp && (*hp)->r != r) hp = &(*hp)->next; + while (*hp && (*hp)->r != r) + hp = &(*hp)->next; if (*hp) { - migration * m = *hp; + migration *m = *hp; + rsethorses(r, rhorses(r) + m->horses); /* Was macht das denn hier? * Baumwanderung wird in trees() gemacht. @@ -652,25 +716,29 @@ migrate(region * r) } } -static void -horses(region * r) +static void horses(region * r) { int horses, maxhorses; + direction_t n; /* Logistisches Wachstum, Optimum bei halbem Maximalbesatz. */ - maxhorses = maxworkingpeasants(r)/10; + maxhorses = maxworkingpeasants(r) / 10; maxhorses = MAX(0, maxhorses); horses = rhorses(r); if (horses > 0) { if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { - rsethorses(r, (int)(horses*0.9F)); + rsethorses(r, (int)(horses * 0.9F)); } else if (maxhorses) { int i; - double growth = (RESOURCE_QUANTITY * HORSEGROWTH * 200 * (maxhorses-horses))/maxhorses; - if (growth>0) { - if (a_find(r->attribs, &at_horseluck)) growth *= 2; + double growth = + (RESOURCE_QUANTITY * HORSEGROWTH * 200 * (maxhorses - + horses)) / maxhorses; + + if (growth > 0) { + if (a_find(r->attribs, &at_horseluck)) + growth *= 2; /* printf("Horses: <%d> %d -> ", growth, horses); */ i = (int)(0.5F + (horses * 0.0001F) * growth); /* printf("%d\n", horses); */ @@ -685,16 +753,19 @@ horses(region * r) * die dann erst in die Berechnung der Nachbarstruktur einfließt. */ - for(n = 0; n != MAXDIRECTIONS; n++) { - region * r2 = rconnect(r, n); + for (n = 0; n != MAXDIRECTIONS; n++) { + region *r2 = rconnect(r, n); + if (r2 && fval(r2->terrain, WALK_INTO)) { - int pt = (rhorses(r) * HORSEMOVE)/100; - pt = (int)normalvariate(pt, pt/4.0); + int pt = (rhorses(r) * HORSEMOVE) / 100; + + pt = (int)normalvariate(pt, pt / 4.0); pt = MAX(0, pt); if (fval(r2, RF_MIGRATION)) rsethorses(r2, rhorses(r2) + pt); else { - migration * nb; + migration *nb; + /* haben wir die Migration schonmal benutzt? * wenn nicht, müssen wir sie suchen. * Wandernde Pferde vermehren sich nicht. @@ -709,14 +780,15 @@ horses(region * r) assert(rhorses(r) >= 0); } -static int -count_race(const region *r, const race *rc) +static int count_race(const region * r, const race * rc) { unit *u; - int c = 0; - for(u = r->units; u; u=u->next) - if(u->race == rc) c += u->number; + int c = 0; + + for (u = r->units; u; u = u->next) + if (u->race == rc) + c += u->number; return c; } @@ -724,49 +796,63 @@ count_race(const region *r, const race *rc) extern struct attrib_type at_germs; static void -growing_trees_e3(region * r, const int current_season, const int last_weeks_season) +growing_trees_e3(region * r, const int current_season, + const int last_weeks_season) { - const static int transform[4][3] = { - { -1, -1, 0 }, - { TREE_SEED, TREE_SAPLING, 2 }, - { TREE_SAPLING, TREE_TREE, 2 }, - { TREE_TREE, TREE_SEED, 2 } + const static int transform[4][3] = { + {-1, -1, 0}, + {TREE_SEED, TREE_SAPLING, 2}, + {TREE_SAPLING, TREE_TREE, 2}, + {TREE_TREE, TREE_SEED, 2} }; - if (r->land && current_season!=last_weeks_season && transform[current_season][2]) { + if (r->land && current_season != last_weeks_season + && transform[current_season][2]) { int src_type = transform[current_season][0]; - int dst_type = transform[current_season][1]; - int src = rtrees(r, src_type); - int dst = rtrees(r, dst_type); - int grow = src/transform[current_season][2]; - if (grow>0) { - if (src_type!=TREE_TREE) { - rsettrees(r, src_type, src-grow); - } - rsettrees(r, dst_type, dst+grow); - if (dst_type==TREE_SEED && r->terrain->size) { - region * rn[MAXDIRECTIONS]; + int dst_type = transform[current_season][1]; + + int src = rtrees(r, src_type); + + int dst = rtrees(r, dst_type); + + int grow = src / transform[current_season][2]; + + if (grow > 0) { + if (src_type != TREE_TREE) { + rsettrees(r, src_type, src - grow); + } + rsettrees(r, dst_type, dst + grow); + + if (dst_type == TREE_SEED && r->terrain->size) { + region *rn[MAXDIRECTIONS]; + int d; - double fgrow = grow/(double)MAXDIRECTIONS; + + double fgrow = grow / (double)MAXDIRECTIONS; get_neighbours(r, rn); - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rx = rn[d]; + for (d = 0; d != MAXDIRECTIONS; ++d) { + region *rx = rn[d]; + if (rx && rx->land) { double scale = 1.0; + int g; + double fg, ch; + int seeds = rtrees(rx, dst_type); - if (r->terrain->size>rx->terrain->size) { - scale = (scale * rx->terrain->size)/r->terrain->size; + if (r->terrain->size > rx->terrain->size) { + scale = (scale * rx->terrain->size) / r->terrain->size; } fg = scale * fgrow; g = (int)fg; ch = fg - g; - if (chance(ch)) ++g; - if (g>0) { + if (chance(ch)) + ++g; + if (g > 0) { rsettrees(rx, dst_type, seeds + g); } } @@ -780,15 +866,18 @@ static void growing_trees(region * r, const int current_season, const int last_weeks_season) { int growth, grownup_trees, i, seeds, sprout; + direction_t d; + attrib *a; - if(current_season == SEASON_SUMMER || current_season == SEASON_AUTUMN) { + if (current_season == SEASON_SUMMER || current_season == SEASON_AUTUMN) { double seedchance = 0.01F * RESOURCE_QUANTITY; + int elves = count_race(r, new_race[RC_ELF]); a = a_find(r->attribs, &at_germs); - if(a && last_weeks_season == SEASON_SPRING) { + if (a && last_weeks_season == SEASON_SPRING) { /* ungekeimte Samen bleiben erhalten, Sprößlinge wachsen */ sprout = MIN(a->data.sa[1], rtrees(r, 1)); /* aus dem gesamt Sprößlingepool abziehen */ @@ -799,31 +888,33 @@ growing_trees(region * r, const int current_season, const int last_weeks_season) a_removeall(&r->attribs, &at_germs); } - if(is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { + if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { rsettrees(r, 1, (int)(rtrees(r, 1) * 0.9)); rsettrees(r, 2, (int)(rtrees(r, 2) * 0.9)); return; } - if (production(r) <= 0) return; + if (production(r) <= 0) + return; /* Grundchance 1.0% */ /* Jeder Elf in der Region erhöht die Chance marginal */ - elves = MIN(elves, (production(r)*MAXPEASANTS_PER_AREA)/8); + elves = MIN(elves, (production(r) * MAXPEASANTS_PER_AREA) / 8); if (elves) { - seedchance += 1.0-pow(0.99999, elves * RESOURCE_QUANTITY); + seedchance += 1.0 - pow(0.99999, elves * RESOURCE_QUANTITY); } grownup_trees = rtrees(r, 2); seeds = 0; - if (grownup_trees>0) { - double remainder = seedchance*grownup_trees; + if (grownup_trees > 0) { + double remainder = seedchance * grownup_trees; + seeds = (int)(remainder); remainder -= seeds; if (chance(remainder)) { ++seeds; } - if (seeds>0) { + if (seeds > 0) { seeds += rtrees(r, 0); rsettrees(r, 0, seeds); } @@ -833,9 +924,10 @@ growing_trees(region * r, const int current_season, const int last_weeks_season) /* Gesamtzahl der Samen: * bis zu 6% (FORESTGROWTH*3) der Bäume samen in die Nachbarregionen */ - seeds = (rtrees(r, 2) * FORESTGROWTH * 3)/1000000; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * r2 = rconnect(r, d); + seeds = (rtrees(r, 2) * FORESTGROWTH * 3) / 1000000; + for (d = 0; d != MAXDIRECTIONS; ++d) { + region *r2 = rconnect(r, d); + if (r2 && fval(r2->terrain, LAND_REGION) && r2->terrain->size) { /* Eine Landregion, wir versuchen Samen zu verteilen: * Die Chance, das Samen ein Stück Boden finden, in dem sie @@ -844,22 +936,24 @@ growing_trees(region * r, const int current_season, const int last_weeks_season) * Möglichkeiten als in Ebenen. */ sprout = 0; seedchance = (1000 * maxworkingpeasants(r2)) / r2->terrain->size; - for(i=0; iattribs, C_CURSED_BY_THE_GODS, 0)) return; + if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) + return; /* in at_germs merken uns die Zahl der Samen und Sprößlinge, die * dieses Jahr älter werden dürfen, damit nicht ein Same im selben * Zyklus zum Baum werden kann */ a = a_find(r->attribs, &at_germs); - if(!a) { + if (!a) { a = a_add(&r->attribs, a_new(&at_germs)); a->data.sa[0] = (short)rtrees(r, 0); a->data.sa[1] = (short)rtrees(r, 1); @@ -875,8 +969,9 @@ growing_trees(region * r, const int current_season, const int last_weeks_season) seeds = MIN(a->data.sa[0], rtrees(r, 0)); sprout = 0; - for(i=0;idata.sa[0] = (short)(seeds - sprout); @@ -894,8 +989,9 @@ growing_trees(region * r, const int current_season, const int last_weeks_season) sprout = MIN(a->data.sa[1], rtrees(r, 1)); grownup_trees = 0; - for(i=0;idata.sa[1] = (short)(sprout - grownup_trees); @@ -915,92 +1011,106 @@ growing_herbs(region * r, const int current_season, const int last_weeks_season) * Kräuter))% sich zu vermehren. */ if (current_season != SEASON_WINTER) { int i; + for (i = rherbs(r); i > 0; i--) { - if (rng_int()%100 < (100-rherbs(r))) rsetherbs(r, (short)(rherbs(r)+1)); + if (rng_int() % 100 < (100 - rherbs(r))) + rsetherbs(r, (short)(rherbs(r) + 1)); } } } -void -demographics(void) +void demographics(void) { region *r; + static int last_weeks_season = -1; + static int current_season = -1; - if (current_season<0) { + if (current_season < 0) { gamedate date; + get_gamedate(turn, &date); current_season = date.season; - get_gamedate(turn-1, &date); + get_gamedate(turn - 1, &date); last_weeks_season = date.season; } for (r = regions; r; r = r->next) { - ++r->age; /* also oceans. no idea why we didn't always do that */ + ++r->age; /* also oceans. no idea why we didn't always do that */ live(r); /* check_split_dragons(); */ if (!fval(r->terrain, SEA_REGION)) { /* die Nachfrage nach Produkten steigt. */ - struct demand * dmd; + struct demand *dmd; + if (r->land) { static int plant_rules = -1; - if (plant_rules<0) { - plant_rules = get_param_int(global.parameters, "rules.economy.grow", 0); + if (plant_rules < 0) { + plant_rules = + get_param_int(global.parameters, "rules.economy.grow", 0); } - for (dmd=r->land->demands;dmd;dmd=dmd->next) { - if (dmd->value>0 && dmd->value < MAXDEMAND) { + for (dmd = r->land->demands; dmd; dmd = dmd->next) { + if (dmd->value > 0 && dmd->value < MAXDEMAND) { float rise = DMRISE; - if (buildingtype_exists(r, bt_find("harbour"), true)) rise = DMRISEHAFEN; - if (rng_double()value; + + if (buildingtype_exists(r, bt_find("harbour"), true)) + rise = DMRISEHAFEN; + if (rng_double() < rise) + ++dmd->value; } } /* Seuchen erst nachdem die Bauern sich vermehrt haben - * und gewandert sind */ + * und gewandert sind */ calculate_emigration(r); peasants(r); - if (r->age>20) { + if (r->age > 20) { plagues(r, false); } horses(r); - if (plant_rules==0) { /* E1 */ + if (plant_rules == 0) { /* E1 */ growing_trees(r, current_season, last_weeks_season); growing_herbs(r, current_season, last_weeks_season); - } else { /* E3 */ + } else { /* E3 */ growing_trees_e3(r, current_season, last_weeks_season); } } update_resources(r); - if (r->land) migrate(r); + if (r->land) + migrate(r); } } while (free_migrants) { - migration * m = free_migrants->next; + migration *m = free_migrants->next; + free(free_migrants); free_migrants = m; }; - if (verbosity>=1) putchar('\n'); + if (verbosity >= 1) + putchar('\n'); remove_empty_units(); - if (verbosity>=1) puts(" - Einwanderung..."); + if (verbosity >= 1) + puts(" - Einwanderung..."); for (r = regions; r; r = r->next) { if (r->land && r->land->newpeasants) { int rp = rpeasants(r) + r->land->newpeasants; + rsetpeasants(r, MAX(0, rp)); } } checkorders(); } + /* ------------------------------------------------------------- */ -static int -modify(int i) +static int modify(int i) { int c; @@ -1013,10 +1123,10 @@ modify(int i) } } -static void -inactivefaction(faction * f) +static void inactivefaction(faction * f) { FILE *inactiveFILE; + char zText[128]; sprintf(zText, "%s/%s", datapath(), "inactive"); @@ -1026,40 +1136,38 @@ inactivefaction(faction * f) fprintf(inactiveFILE, "%s:%s:%d:%d\n", factionid(f), LOC(default_locale, rc_name(f->race, 1)), - modify(count_all(f)), - turn - f->lastorders); + modify(count_all(f)), turn - f->lastorders); fclose(inactiveFILE); } } -static void -transfer_faction(faction *f, faction *f2) +static void transfer_faction(faction * f, faction * f2) { unit *u, *un; for (u = f->units; u;) { un = u->nextF; - if(!unit_has_cursed_item(u) - && !has_skill(u, SK_MAGIC) - && !has_skill(u, SK_ALCHEMY)) { + if (!unit_has_cursed_item(u) + && !has_skill(u, SK_MAGIC) + && !has_skill(u, SK_ALCHEMY)) { u_setfaction(u, f2); } u = un; } } -static int -restart_cmd(unit * u, struct order * ord) +static int restart_cmd(unit * u, struct order *ord) { init_tokens(ord); - skip_token(); /* skip keyword */ + skip_token(); /* skip keyword */ if (!fval(u->region->terrain, LAND_REGION)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); } else { - const char * s_race = getstrtoken(), * s_pass; - const race * frace = findrace(s_race, u->faction->locale); + const char *s_race = getstrtoken(), *s_pass; + + const race *frace = findrace(s_race, u->faction->locale); if (!frace) { frace = u->faction->race; @@ -1073,7 +1181,7 @@ restart_cmd(unit * u, struct order * ord) return 0; } - if (/* frace != u->faction->race && */ u->faction->age < 81) { + if ( /* frace != u->faction->race && */ u->faction->age < 81) { cmistake(u, ord, 241, MSG_EVENT); return 0; } @@ -1086,7 +1194,7 @@ restart_cmd(unit * u, struct order * ord) if (!checkpasswd(u->faction, (const char *)s_pass, false)) { cmistake(u, ord, 86, MSG_EVENT); log_warning(("RESTART with wrong password, faction %s, pass %s\n", - factionid(u->faction), s_pass)); + factionid(u->faction), s_pass)); return 0; } restart_race(u, frace); @@ -1095,44 +1203,48 @@ restart_cmd(unit * u, struct order * ord) return 0; } -static boolean -EnhancedQuit(void) +static boolean EnhancedQuit(void) { static int value = -1; - if (value<0) { - const char * str = get_param(global.parameters, "alliance.transferquit"); - value = (str!=0 && strcmp(str, "true")==0); + + if (value < 0) { + const char *str = get_param(global.parameters, "alliance.transferquit"); + + value = (str != 0 && strcmp(str, "true") == 0); } return value; } -static int -quit_cmd(unit * u, struct order * ord) +static int quit_cmd(unit * u, struct order *ord) { - faction * f = u->faction; - const char * passwd; + faction *f = u->faction; + + const char *passwd; init_tokens(ord); - skip_token(); /* skip keyword */ + skip_token(); /* skip keyword */ passwd = getstrtoken(); if (checkpasswd(f, (const char *)passwd, false)) { if (EnhancedQuit()) { int f2_id = getid(); - if (f2_id>0) { + + if (f2_id > 0) { faction *f2 = findfaction(f2_id); - if(f2 == NULL) { + if (f2 == NULL) { cmistake(u, ord, 66, MSG_EVENT); return 0; - } else if (!u->faction->alliance || u->faction->alliance != f2->alliance) { + } else if (!u->faction->alliance + || u->faction->alliance != f2->alliance) { cmistake(u, ord, 315, MSG_EVENT); return 0; - } else if(!alliedfaction(NULL, f, f2, HELP_MONEY)) { + } else if (!alliedfaction(NULL, f, f2, HELP_MONEY)) { cmistake(u, ord, 316, MSG_EVENT); return 0; } else { variant var; + var.i = f2_id; a_add(&f->attribs, object_create("quit", TINTEGER, var)); } @@ -1141,57 +1253,68 @@ quit_cmd(unit * u, struct order * ord) fset(f, FFL_QUIT); } else { char buffer[64]; + write_order(ord, buffer, sizeof(buffer)); cmistake(u, ord, 86, MSG_EVENT); log_warning(("QUIT with illegal password for faction %s: %s\n", - factionid(f), buffer)); + factionid(f), buffer)); } return 0; } -static void -quit(void) +static void quit(void) { - faction ** fptr = &factions; + faction **fptr = &factions; + while (*fptr) { - faction * f = *fptr; + faction *f = *fptr; + if (f->flags & FFL_QUIT) { if (EnhancedQuit()) { /* this doesn't work well (use object_name()) */ - attrib * a = a_find(f->attribs, &at_object); + attrib *a = a_find(f->attribs, &at_object); + if (a) { variant var; + object_type type; + var.i = 0; object_get(a, &type, &var); - assert(var.i && type==TINTEGER); + assert(var.i && type == TINTEGER); if (var.i) { int f2_id = var.i; + faction *f2 = findfaction(f2_id); - assert(f2_id>0); - assert(f2!=NULL); + assert(f2_id > 0); + assert(f2 != NULL); transfer_faction(f, f2); } } } destroyfaction(f); } - if (*fptr==f) fptr=&f->next; + if (*fptr == f) + fptr = &f->next; } } int dropouts[2]; -int * age = NULL; -static void -nmr_death(faction * f) +int *age = NULL; + +static void nmr_death(faction * f) { static int rule = -1; - if (rule<0) rule = get_param_int(global.parameters, "rules.nmr.destroy", 0); + + if (rule < 0) + rule = get_param_int(global.parameters, "rules.nmr.destroy", 0); + if (rule) { - unit * u; - for (u=f->units;u;u=u->nextF) { + unit *u; + + for (u = f->units; u; u = u->nextF) { if (u->building && fval(u, UFL_OWNER)) { remove_building(&u->region->buildings, u->building); } @@ -1199,25 +1322,26 @@ nmr_death(faction * f) } } -static void -parse_restart(void) +static void parse_restart(void) { region *r; + faction *f; /* Sterben erst nachdem man allen anderen gegeben hat - bzw. man kann - * alles machen, was nicht ein dreißigtägiger Befehl ist. */ + * alles machen, was nicht ein dreißigtägiger Befehl ist. */ for (r = regions; r; r = r->next) { - unit * u, * un; + unit *u, *un; + for (u = r->units; u;) { - order * ord; + order *ord; un = u->next; - for (ord = u->orders; ord!=NULL; ord = ord->next) { + for (ord = u->orders; ord != NULL; ord = ord->next) { if (get_keyword(ord) == K_RESTART) { if (u->number > 0) { - if (restart_cmd(u, ord)!=0) { + if (restart_cmd(u, ord) != 0) { break; } } @@ -1227,11 +1351,14 @@ parse_restart(void) } } - if (verbosity>=1) puts(" - beseitige Spieler, die sich zu lange nicht mehr gemeldet haben..."); + if (verbosity >= 1) + puts + (" - beseitige Spieler, die sich zu lange nicht mehr gemeldet haben..."); for (f = factions; f; f = f->next) { - if(fval(f, FFL_NOIDLEOUT)) f->lastorders = turn; - if (NMRTimeout()>0 && turn - f->lastorders >= NMRTimeout()) { + if (fval(f, FFL_NOIDLEOUT)) + f->lastorders = turn; + if (NMRTimeout() > 0 && turn - f->lastorders >= NMRTimeout()) { nmr_death(f); destroyfaction(f); continue; @@ -1241,70 +1368,80 @@ parse_restart(void) f->override = strdup(itoa36(rng_int())); freset(f, FFL_OVERRIDE); } - if (turn!=f->lastorders) { + if (turn != f->lastorders) { char info[256]; + sprintf(info, "%d Einheiten, %d Personen, %d Silber", f->no_units, f->num_total, f->money); if (f->subscription) { - sql_print(("UPDATE subscriptions SET lastturn=%d, password='%s', info='%s' WHERE id=%u;\n", - f->lastorders, f->override, info, f->subscription)); + sql_print( + ("UPDATE subscriptions SET lastturn=%d, password='%s', info='%s' WHERE id=%u;\n", + f->lastorders, f->override, info, f->subscription)); } } else { if (f->subscription) { - sql_print(("UPDATE subscriptions SET status='ACTIVE', lastturn=%d, firstturn=greatest(firstturn,%d), password='%s' WHERE id=%u;\n", - f->lastorders, f->lastorders-f->age, - f->override, f->subscription)); + sql_print( + ("UPDATE subscriptions SET status='ACTIVE', lastturn=%d, firstturn=greatest(firstturn,%d), password='%s' WHERE id=%u;\n", + f->lastorders, f->lastorders - f->age, f->override, + f->subscription)); } } - if (NMRTimeout()>0 && turn - f->lastorders >= (NMRTimeout() - 1)) { + if (NMRTimeout() > 0 && turn - f->lastorders >= (NMRTimeout() - 1)) { inactivefaction(f); continue; } } - if (verbosity>=1) { + if (verbosity >= 1) { puts(" - beseitige Spieler, die sich nach der Anmeldung nicht " "gemeldet haben..."); } - age = calloc(MAX(4,turn+1), sizeof(int)); - for (f = factions; f; f = f->next) if (!is_monsters(f)) { - if (RemoveNMRNewbie() && !fval(f, FFL_NOIDLEOUT)) { - if (f->age>=0 && f->age <= turn) ++age[f->age]; - if (f->age == 2 || f->age == 3) { - if (f->lastorders == turn - 2) { - destroyfaction(f); - ++dropouts[f->age-2]; - continue; + age = calloc(MAX(4, turn + 1), sizeof(int)); + for (f = factions; f; f = f->next) + if (!is_monsters(f)) { + if (RemoveNMRNewbie() && !fval(f, FFL_NOIDLEOUT)) { + if (f->age >= 0 && f->age <= turn) + ++age[f->age]; + if (f->age == 2 || f->age == 3) { + if (f->lastorders == turn - 2) { + destroyfaction(f); + ++dropouts[f->age - 2]; + continue; + } } } } - } - if (verbosity>=1) puts(" - beseitige leere Einheiten und leere Parteien..."); + if (verbosity >= 1) + puts(" - beseitige leere Einheiten und leere Parteien..."); remove_empty_units(); } + /* ------------------------------------------------------------- */ /* HELFE partei [] [NICHT] */ -static int -ally_cmd(unit * u, struct order * ord) +static int ally_cmd(unit * u, struct order *ord) { - ally * sf, ** sfp; + ally *sf, **sfp; + faction *f; + int keyword, not_kw; + const char *s; init_tokens(ord); skip_token(); f = getfaction(); - if (f==NULL || is_monsters(f)) { + if (f == NULL || is_monsters(f)) { cmistake(u, ord, 66, MSG_EVENT); return 0; } - if (f == u->faction) return 0; + if (f == u->faction) + return 0; s = getstrtoken(); @@ -1315,14 +1452,16 @@ ally_cmd(unit * u, struct order * ord) sfp = &u->faction->allies; if (fval(u, UFL_GROUP)) { - attrib * a = a_find(u->attribs, &at_group); - if (a) sfp = &((group*)a->data.v)->allies; - } - for (sf=*sfp; sf; sf = sf->next) - if (sf->faction == f) - break; /* Gleich die passende raussuchen, wenn vorhanden */ + attrib *a = a_find(u->attribs, &at_group); - not_kw = getparam(u->faction->locale); /* HELFE partei [modus] NICHT */ + if (a) + sfp = &((group *) a->data.v)->allies; + } + for (sf = *sfp; sf; sf = sf->next) + if (sf->faction == f) + break; /* Gleich die passende raussuchen, wenn vorhanden */ + + not_kw = getparam(u->faction->locale); /* HELFE partei [modus] NICHT */ if (!sf) { if (keyword == P_NOT || not_kw == P_NOT) { @@ -1336,103 +1475,110 @@ ally_cmd(unit * u, struct order * ord) } } switch (keyword) { - case P_NOT: - sf->status = 0; - break; - - case NOPARAM: - cmistake(u, ord, 137, MSG_EVENT); - return 0; - - case P_ANY: - if (not_kw == P_NOT) + case P_NOT: sf->status = 0; - else - sf->status = HELP_ALL; - break; + break; - case P_TRAVEL: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_TRAVEL); - else - sf->status = sf->status | HELP_TRAVEL; - break; + case NOPARAM: + cmistake(u, ord, 137, MSG_EVENT); + return 0; - case P_GIVE: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_GIVE); - else - sf->status = sf->status | HELP_GIVE; - break; + case P_ANY: + if (not_kw == P_NOT) + sf->status = 0; + else + sf->status = HELP_ALL; + break; - case P_MONEY: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_MONEY); - else - sf->status = sf->status | HELP_MONEY; - break; + case P_TRAVEL: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_TRAVEL); + else + sf->status = sf->status | HELP_TRAVEL; + break; - case P_FIGHT: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_FIGHT); - else - sf->status = sf->status | HELP_FIGHT; - break; + case P_GIVE: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_GIVE); + else + sf->status = sf->status | HELP_GIVE; + break; - case P_FACTIONSTEALTH: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_FSTEALTH); - else - sf->status = sf->status | HELP_FSTEALTH; - break; + case P_MONEY: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_MONEY); + else + sf->status = sf->status | HELP_MONEY; + break; - case P_GUARD: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_GUARD); - else - sf->status = sf->status | HELP_GUARD; - break; + case P_FIGHT: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_FIGHT); + else + sf->status = sf->status | HELP_FIGHT; + break; + + case P_FACTIONSTEALTH: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_FSTEALTH); + else + sf->status = sf->status | HELP_FSTEALTH; + break; + + case P_GUARD: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_GUARD); + else + sf->status = sf->status | HELP_GUARD; + break; } sf->status &= HelpMask(); - if (sf->status == 0) { /* Alle HELPs geloescht */ + if (sf->status == 0) { /* Alle HELPs geloescht */ removelist(sfp, sf); } return 0; } -static struct local_names * pnames; +static struct local_names *pnames; -static void -init_prefixnames(void) +static void init_prefixnames(void) { int i; - for (i=0;localenames[i];++i) { - const struct locale * lang = find_locale(localenames[i]); - boolean exist = false; - struct local_names * in = pnames; - while (in!=NULL) { - if (in->lang==lang) { + for (i = 0; localenames[i]; ++i) { + const struct locale *lang = find_locale(localenames[i]); + + boolean exist = false; + + struct local_names *in = pnames; + + while (in != NULL) { + if (in->lang == lang) { exist = true; break; } in = in->next; } - if (in==NULL) in = calloc(sizeof(local_names), 1); + if (in == NULL) + in = calloc(sizeof(local_names), 1); in->next = pnames; in->lang = lang; if (!exist) { int key; - for (key=0;race_prefixes[key];++key) { + + for (key = 0; race_prefixes[key]; ++key) { variant var; - const char * pname = locale_string(lang, mkname("prefix", race_prefixes[key])); - if (findtoken(&in->names, pname, &var)==E_TOK_NOMATCH || var.i!=key) { + + const char *pname = + locale_string(lang, mkname("prefix", race_prefixes[key])); + if (findtoken(&in->names, pname, &var) == E_TOK_NOMATCH || var.i != key) { var.i = key; addtoken(&in->names, pname, var); - addtoken(&in->names, locale_string(lang, mkname("prefix", race_prefixes[key])), var); + addtoken(&in->names, locale_string(lang, mkname("prefix", + race_prefixes[key])), var); } } } @@ -1440,22 +1586,26 @@ init_prefixnames(void) } } -static int -prefix_cmd(unit * u, struct order * ord) +static int prefix_cmd(unit * u, struct order *ord) { attrib **ap; - const char *s; - local_names * in = pnames; - variant var; - const struct locale * lang = u->faction->locale; - while (in!=NULL) { - if (in->lang==lang) break; + const char *s; + + local_names *in = pnames; + + variant var; + + const struct locale *lang = u->faction->locale; + + while (in != NULL) { + if (in->lang == lang) + break; in = in->next; } - if (in==NULL) { + if (in == NULL) { init_prefixnames(); - for (in=pnames;in->lang!=lang;in=in->next) ; + for (in = pnames; in->lang != lang; in = in->next) ; } init_tokens(ord); @@ -1464,11 +1614,13 @@ prefix_cmd(unit * u, struct order * ord) if (!*s) { attrib *a = NULL; + if (fval(u, UFL_GROUP)) { a = a_find(u->attribs, &at_group); } if (a) { - group * g = (group*)a->data.v; + group *g = (group *) a->data.v; + a_removeall(&g->attribs, &at_raceprefix); } else { a_removeall(&u->faction->attribs, &at_raceprefix); @@ -1476,16 +1628,19 @@ prefix_cmd(unit * u, struct order * ord) return 0; } - if (findtoken(&in->names, s, &var)==E_TOK_NOMATCH) { + if (findtoken(&in->names, s, &var) == E_TOK_NOMATCH) { return 0; } else if (race_prefixes[var.i] == NULL) { cmistake(u, ord, 299, MSG_EVENT); } else { ap = &u->faction->attribs; if (fval(u, UFL_GROUP)) { - attrib * a = a_find(u->attribs, &at_group); - group * g = (group*)a->data.v; - if (a) ap = &g->attribs; + attrib *a = a_find(u->attribs, &at_group); + + group *g = (group *) a->data.v; + + if (a) + ap = &g->attribs; } set_prefix(ap, race_prefixes[var.i]); } @@ -1493,8 +1648,7 @@ prefix_cmd(unit * u, struct order * ord) } -static cmp_building_cb -get_cmp_region_owner(void) +static cmp_building_cb get_cmp_region_owner(void) { if (rule_region_owners()) { return &cmp_current_owner; @@ -1503,88 +1657,90 @@ get_cmp_region_owner(void) } } -static int -display_cmd(unit * u, struct order * ord) +static int display_cmd(unit * u, struct order *ord) { - building * b = u->building; + building *b = u->building; + char **s = NULL; - region * r = u->region; + + region *r = u->region; init_tokens(ord); skip_token(); switch (getparam(u->faction->locale)) { - case P_BUILDING: - case P_GEBAEUDE: - if (!b) { - cmistake(u, ord, 145, MSG_PRODUCE); + case P_BUILDING: + case P_GEBAEUDE: + if (!b) { + cmistake(u, ord, 145, MSG_PRODUCE); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 5, MSG_PRODUCE); + break; + } + if (!fval(b->type, BTF_NAMECHANGE) && b->display && b->display[0] != 0) { + cmistake(u, ord, 278, MSG_EVENT); + break; + } + s = &b->display; break; - } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 5, MSG_PRODUCE); - break; - } - if (!fval(b->type, BTF_NAMECHANGE) && b->display && b->display[0] != 0) { - cmistake(u, ord, 278, MSG_EVENT); - break; - } - s = &b->display; - break; - case P_SHIP: - if (!u->ship) { - cmistake(u, ord, 144, MSG_PRODUCE); + case P_SHIP: + if (!u->ship) { + cmistake(u, ord, 144, MSG_PRODUCE); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 12, MSG_PRODUCE); + break; + } + s = &u->ship->display; break; - } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 12, MSG_PRODUCE); + + case P_UNIT: + s = &u->display; break; - } - s = &u->ship->display; - break; - case P_UNIT: - s = &u->display; - break; - - case P_PRIVAT: + case P_PRIVAT: { const char *d = getstrtoken(); - if(d == NULL || *d == 0) { + + if (d == NULL || *d == 0) { usetprivate(u, NULL); } else { usetprivate(u, d); } } - break; + break; - case P_REGION: - if (!b) { - cmistake(u, ord, 145, MSG_EVENT); + case P_REGION: + if (!b) { + cmistake(u, ord, 145, MSG_EVENT); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 148, MSG_EVENT); + break; + } + if (b != largestbuilding(r, get_cmp_region_owner(), false)) { + cmistake(u, ord, 147, MSG_EVENT); + break; + } + s = &r->display; break; - } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 148, MSG_EVENT); - break; - } - if (b != largestbuilding(r, get_cmp_region_owner(), false)) { - cmistake(u, ord, 147, MSG_EVENT); - break; - } - s = &r->display; - break; - default: - cmistake(u, ord, 110, MSG_EVENT); - break; + default: + cmistake(u, ord, 110, MSG_EVENT); + break; } - if (s!=NULL) { - const char * s2 = getstrtoken(); + if (s != NULL) { + const char *s2 = getstrtoken(); free(*s); *s = strdup(s2); - if (strlen(s2)>=DISPLAYSIZE) { + if (strlen(s2) >= DISPLAYSIZE) { (*s)[DISPLAYSIZE] = 0; } } @@ -1592,22 +1748,23 @@ display_cmd(unit * u, struct order * ord) return 0; } -static boolean -renamed_building(const building * b) +static boolean renamed_building(const building * b) { - const struct locale * lang = locales; - for (;lang;lang=nextlocale(lang)) { - const char * bdname = LOC(lang, b->type->_name); + const struct locale *lang = locales; + + for (; lang; lang = nextlocale(lang)) { + const char *bdname = LOC(lang, b->type->_name); + size_t bdlen = strlen(bdname); - if (strlen(b->name)>=bdlen && strncmp(b->name, bdname, bdlen)==0) { + + if (strlen(b->name) >= bdlen && strncmp(b->name, bdname, bdlen) == 0) { return false; } } return true; } -static int -rename_cmd(unit * u, order * ord, char **s, const char * s2) +static int rename_cmd(unit * u, order * ord, char **s, const char *s2) { if (!s2[0]) { cmistake(u, ord, 84, MSG_EVENT); @@ -1615,23 +1772,25 @@ rename_cmd(unit * u, order * ord, char **s, const char * s2) } /* TODO: Validate to make sure people don't have illegal characters in - * names, phishing-style? () come to mind. */ + * names, phishing-style? () come to mind. */ free(*s); *s = strdup(s2); - if (strlen(s2)>=NAMESIZE) { + if (strlen(s2) >= NAMESIZE) { (*s)[NAMESIZE] = 0; } return 0; } -static int -rename_building(unit * u, order * ord, building * b, const char * name) { - unit * owner = b?building_owner(b):0; - boolean foreign = !(owner && owner->faction==u->faction); +static int +rename_building(unit * u, order * ord, building * b, const char *name) +{ + unit *owner = b ? building_owner(b) : 0; + + boolean foreign = !(owner && owner->faction == u->faction); if (!b) { - cmistake(u, ord, u->building?6:145, MSG_EVENT); + cmistake(u, ord, u->building ? 6 : 145, MSG_EVENT); return -1; } @@ -1641,18 +1800,18 @@ rename_building(unit * u, order * ord, building * b, const char * name) { } if (foreign) { - if (renamed_building(b)) { + if (renamed_building(b)) { cmistake(u, ord, 246, MSG_EVENT); return -1; } if (owner) { if (cansee(owner->faction, u->region, u, 0)) { - ADDMSG(&owner->faction->msgs, msg_message("renamed_building_seen", - "building renamer region", b, u, u->region)); + ADDMSG(&owner->faction->msgs, msg_message("renamed_building_seen", + "building renamer region", b, u, u->region)); } else { - ADDMSG(&owner->faction->msgs, msg_message("renamed_building_notseen", - "building region", b, u->region)); + ADDMSG(&owner->faction->msgs, msg_message("renamed_building_notseen", + "building region", b, u->region)); } } } else { @@ -1665,13 +1824,16 @@ rename_building(unit * u, order * ord, building * b, const char * name) { return rename_cmd(u, ord, &b->name, name); } -static int -name_cmd(unit * u, struct order * ord) +static int name_cmd(unit * u, struct order *ord) { - building * b = u->building; - region * r = u->region; + building *b = u->building; + + region *r = u->region; + char **s = NULL; + param_t p; + boolean foreign = false; init_tokens(ord); @@ -1684,165 +1846,185 @@ name_cmd(unit * u, struct order * ord) } switch (p) { - case P_ALLIANCE: - if (foreign==false && f_get_alliance(u->faction)) { - alliance * al = u->faction->alliance; - faction * lead = alliance_get_leader(al); - if (lead==u->faction) { - s = &al->name; - } - } - break; - case P_BUILDING: - case P_GEBAEUDE: - if (foreign) { - b = getbuilding(u->region); - } + case P_ALLIANCE: + if (foreign == false && f_get_alliance(u->faction)) { + alliance *al = u->faction->alliance; - return rename_building(u, ord, b, getstrtoken()); + faction *lead = alliance_get_leader(al); - case P_FACTION: - if (foreign == true) { - faction *f; - - f = getfaction(); - if (!f) { - cmistake(u, ord, 66, MSG_EVENT); - break; - } - if (f->age < 10) { - cmistake(u, ord, 248, MSG_EVENT); - break; - } else { - const struct locale * lang = locales; - for (;lang;lang=nextlocale(lang)) { - const char * fdname = LOC(lang, "factiondefault"); - size_t fdlen = strlen(fdname); - if (strlen(f->name)>=fdlen && strncmp(f->name, fdname, fdlen)==0) { - break; - } + if (lead == u->faction) { + s = &al->name; } - if (lang==NULL) { - cmistake(u, ord, 247, MSG_EVENT); + } + break; + case P_BUILDING: + case P_GEBAEUDE: + if (foreign) { + b = getbuilding(u->region); + } + + return rename_building(u, ord, b, getstrtoken()); + + case P_FACTION: + if (foreign == true) { + faction *f; + + f = getfaction(); + if (!f) { + cmistake(u, ord, 66, MSG_EVENT); break; } - } - if (cansee(f, r, u, 0)) { - ADDMSG(&f->msgs, msg_message("renamed_faction_seen", "unit region", u, r)); - } else { - ADDMSG(&f->msgs, msg_message("renamed_faction_notseen", "", r)); - } - s = &f->name; - } else { - s = &u->faction->name; - } - break; - - case P_SHIP: - if (foreign == true) { - ship *sh = getship(r); - unit *uo; - - if (!sh) { - cmistake(u, ord, 20, MSG_EVENT); - break; - } else { - const struct locale * lang = locales; - for (;lang;lang=nextlocale(lang)) { - const char * sdname = LOC(lang, sh->type->name[0]); - size_t sdlen = strlen(sdname); - if (strlen(sh->name)>=sdlen && strncmp(sh->name, sdname, sdlen)==0) { - break; - } - - sdname = LOC(lang, parameters[P_SHIP]); - sdlen = strlen(sdname); - if (strlen(sh->name)>=sdlen && strncmp(sh->name, sdname, sdlen)==0) { - break; - } - - } - if (lang==NULL) { - cmistake(u, ord, 245, MSG_EVENT); + if (f->age < 10) { + cmistake(u, ord, 248, MSG_EVENT); break; - } - } - uo = shipowner(sh); - if (uo) { - if (cansee(uo->faction, r, u, 0)) { - ADDMSG(&uo->faction->msgs, msg_message("renamed_ship_seen", - "ship renamer region", sh, u, r)); } else { - ADDMSG(&uo->faction->msgs, msg_message("renamed_ship_notseen", - "ship region", sh, r)); + const struct locale *lang = locales; + + for (; lang; lang = nextlocale(lang)) { + const char *fdname = LOC(lang, "factiondefault"); + + size_t fdlen = strlen(fdname); + + if (strlen(f->name) >= fdlen + && strncmp(f->name, fdname, fdlen) == 0) { + break; + } + } + if (lang == NULL) { + cmistake(u, ord, 247, MSG_EVENT); + break; + } } + if (cansee(f, r, u, 0)) { + ADDMSG(&f->msgs, msg_message("renamed_faction_seen", "unit region", u, + r)); + } else { + ADDMSG(&f->msgs, msg_message("renamed_faction_notseen", "", r)); + } + s = &f->name; + } else { + s = &u->faction->name; } - s = &sh->name; - } else { - if (!u->ship) { - cmistake(u, ord, 144, MSG_PRODUCE); + break; + + case P_SHIP: + if (foreign == true) { + ship *sh = getship(r); + + unit *uo; + + if (!sh) { + cmistake(u, ord, 20, MSG_EVENT); + break; + } else { + const struct locale *lang = locales; + + for (; lang; lang = nextlocale(lang)) { + const char *sdname = LOC(lang, sh->type->name[0]); + + size_t sdlen = strlen(sdname); + + if (strlen(sh->name) >= sdlen + && strncmp(sh->name, sdname, sdlen) == 0) { + break; + } + + sdname = LOC(lang, parameters[P_SHIP]); + sdlen = strlen(sdname); + if (strlen(sh->name) >= sdlen + && strncmp(sh->name, sdname, sdlen) == 0) { + break; + } + + } + if (lang == NULL) { + cmistake(u, ord, 245, MSG_EVENT); + break; + } + } + uo = shipowner(sh); + if (uo) { + if (cansee(uo->faction, r, u, 0)) { + ADDMSG(&uo->faction->msgs, msg_message("renamed_ship_seen", + "ship renamer region", sh, u, r)); + } else { + ADDMSG(&uo->faction->msgs, msg_message("renamed_ship_notseen", + "ship region", sh, r)); + } + } + s = &sh->name; + } else { + if (!u->ship) { + cmistake(u, ord, 144, MSG_PRODUCE); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 12, MSG_PRODUCE); + break; + } + s = &u->ship->name; + } + break; + + case P_UNIT: + if (foreign == true) { + unit *u2 = getunit(r, u->faction); + + if (!u2 || !cansee(u->faction, r, u2, 0)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, + "feedback_unit_not_found", "")); + break; + } else { + const char *udefault = LOC(u2->faction->locale, "unitdefault"); + + size_t udlen = strlen(udefault); + + size_t unlen = strlen(u2->name); + + if (unlen >= udlen && strncmp(u2->name, udefault, udlen) != 0) { + cmistake(u2, ord, 244, MSG_EVENT); + break; + } + } + if (cansee(u2->faction, r, u, 0)) { + ADDMSG(&u2->faction->msgs, msg_message("renamed_seen", + "renamer renamed region", u, u2, r)); + } else { + ADDMSG(&u2->faction->msgs, msg_message("renamed_notseen", + "renamed region", u2, r)); + } + s = &u2->name; + } else { + s = &u->name; + } + break; + + case P_REGION: + if (!b) { + cmistake(u, ord, 145, MSG_EVENT); break; } if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 12, MSG_PRODUCE); + cmistake(u, ord, 148, MSG_EVENT); break; } - s = &u->ship->name; - } - break; - case P_UNIT: - if (foreign == true) { - unit *u2 = getunit(r, u->faction); - - if (!u2 || !cansee(u->faction, r, u2, 0)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + if (b != largestbuilding(r, get_cmp_region_owner(), false)) { + cmistake(u, ord, 147, MSG_EVENT); break; - } else { - const char * udefault = LOC(u2->faction->locale, "unitdefault"); - size_t udlen = strlen(udefault); - size_t unlen = strlen(u2->name); - if (unlen>=udlen && strncmp(u2->name, udefault, udlen)!=0) { - cmistake(u2, ord, 244, MSG_EVENT); - break; - } } - if (cansee(u2->faction, r, u, 0)) { - ADDMSG(&u2->faction->msgs, msg_message("renamed_seen", - "renamer renamed region", u, u2, r)); - } else { - ADDMSG(&u2->faction->msgs, msg_message("renamed_notseen", - "renamed region", u2, r)); - } - s = &u2->name; - } else { - s = &u->name; - } - break; + s = &r->land->name; + break; - case P_REGION: - if (!b) { - cmistake(u, ord, 145, MSG_EVENT); - break; - } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 148, MSG_EVENT); - break; - } - - if (b != largestbuilding(r, get_cmp_region_owner(), false)) { - cmistake(u, ord, 147, MSG_EVENT); - break; - } - s = &r->land->name; - break; - - case P_GROUP: + case P_GROUP: { - attrib * a = NULL; - if (fval(u, UFL_GROUP)) a = a_find(u->attribs, &at_group); + attrib *a = NULL; + + if (fval(u, UFL_GROUP)) + a = a_find(u->attribs, &at_group); if (a) { - group * g = (group*)a->data.v; + group *g = (group *) a->data.v; + s = &g->name; break; } else { @@ -1850,18 +2032,19 @@ name_cmd(unit * u, struct order * ord) break; } } - break; - default: - cmistake(u, ord, 109, MSG_EVENT); - break; + break; + default: + cmistake(u, ord, 109, MSG_EVENT); + break; } - if (s!=NULL) { + if (s != NULL) { return rename_cmd(u, ord, s, getstrtoken()); } return 0; } + /* ------------------------------------------------------------- */ void @@ -1870,84 +2053,87 @@ deliverMail(faction * f, region * r, unit * u, const char *s, unit * receiver) if (!cansee(f, r, u, 0)) { u = NULL; } - if (!receiver) { /* BOTSCHAFT an PARTEI */ - ADDMSG(&f->msgs, msg_message("regionmessage", "region sender string", r, u, s)); - } else { /* BOTSCHAFT an EINHEIT */ - ADDMSG(&f->msgs, msg_message("unitmessage", "region unit sender string", r, receiver, u, s)); + if (!receiver) { /* BOTSCHAFT an PARTEI */ + ADDMSG(&f->msgs, msg_message("regionmessage", "region sender string", r, u, + s)); + } else { /* BOTSCHAFT an EINHEIT */ + ADDMSG(&f->msgs, msg_message("unitmessage", "region unit sender string", r, + receiver, u, s)); } } static void -mailunit(region * r, unit * u, int n, struct order * ord, const char * s) +mailunit(region * r, unit * u, int n, struct order *ord, const char *s) { - unit * u2 = findunitr(r,n); + unit *u2 = findunitr(r, n); if (u2 && cansee(u->faction, r, u2, 0)) { deliverMail(u2->faction, r, u, s, u2); /* now done in prepare_mail_cmd */ - } - else { + } else { /* Immer eine Meldung - sonst könnte man so getarnte EHs enttarnen: - * keine Meldung -> EH hier. */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + * keine Meldung -> EH hier. */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", + "")); } } -static void -mailfaction(unit * u, int n, struct order * ord, const char * s) +static void mailfaction(unit * u, int n, struct order *ord, const char *s) { faction *f; f = findfaction(n); - if (f && n>0) + if (f && n > 0) deliverMail(f, u->region, u, s, NULL); else cmistake(u, ord, 66, MSG_MESSAGE); } -static int -mail_cmd(unit * u, struct order * ord) +static int mail_cmd(unit * u, struct order *ord) { - region * r = u->region; + region *r = u->region; + unit *u2; + const char *s; + int n, cont; init_tokens(ord); - skip_token(); /* skip the keyword */ + skip_token(); /* skip the keyword */ s = getstrtoken(); /* Falls kein Parameter, ist das eine Einheitsnummer; - * das Füllwort "AN" muß wegfallen, da gültige Nummer! */ + * das Füllwort "AN" muß wegfallen, da gültige Nummer! */ do { cont = 0; switch (findparam(s, u->faction->locale)) { - case P_REGION: - /* können alle Einheiten in der Region sehen */ - s = getstrtoken(); - if (!s[0]) { - cmistake(u, ord, 30, MSG_MESSAGE); - break; - } else { - ADDMSG(&r->msgs, msg_message("mail_result", "unit message", u, s)); - return 0; - } + case P_REGION: + /* können alle Einheiten in der Region sehen */ + s = getstrtoken(); + if (!s[0]) { + cmistake(u, ord, 30, MSG_MESSAGE); + break; + } else { + ADDMSG(&r->msgs, msg_message("mail_result", "unit message", u, s)); + return 0; + } - case P_FACTION: + case P_FACTION: { boolean see = false; n = getfactionid(); - for(u2=r->units; u2; u2=u2->next) { - if(u2->faction->no == n && seefaction(u->faction, r, u2, 0)) { + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->faction->no == n && seefaction(u->faction, r, u2, 0)) { see = true; break; } } - if(see == false) { + if (see == false) { cmistake(u, ord, 66, MSG_MESSAGE); break; } @@ -1961,12 +2147,13 @@ mail_cmd(unit * u, struct order * ord) return 0; } - case P_UNIT: + case P_UNIT: { boolean see = false; + n = getid(); - for (u2=r->units; u2; u2=u2->next) { + for (u2 = r->units; u2; u2 = u2->next) { if (u2->no == n && cansee(u->faction, r, u2, 0)) { see = true; break; @@ -1974,7 +2161,8 @@ mail_cmd(unit * u, struct order * ord) } if (see == false) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, + "feedback_unit_not_found", "")); return 0; } @@ -1983,12 +2171,14 @@ mail_cmd(unit * u, struct order * ord) cmistake(u, ord, 30, MSG_MESSAGE); break; } else { - attrib * a = a_find(u2->attribs, &at_eventhandler); - if (a!=NULL) { + attrib *a = a_find(u2->attribs, &at_eventhandler); + + if (a != NULL) { event_arg args[3]; - args[0].data.v = (void*)s; + + args[0].data.v = (void *)s; args[0].type = "string"; - args[1].data.v = (void*)u; + args[1].data.v = (void *)u; args[1].type = "unit"; args[2].type = NULL; handle_event(a, "message", args); @@ -1999,12 +2189,12 @@ mail_cmd(unit * u, struct order * ord) return 0; } - case P_BUILDING: - case P_GEBAEUDE: + case P_BUILDING: + case P_GEBAEUDE: { building *b = getbuilding(r); - if(!b) { + if (!b) { cmistake(u, ord, 6, MSG_MESSAGE); break; } @@ -2016,23 +2206,24 @@ mail_cmd(unit * u, struct order * ord) break; } - for (u2 = r->units; u2; u2 = u2->next) freset(u2->faction, FFL_SELECT); + for (u2 = r->units; u2; u2 = u2->next) + freset(u2->faction, FFL_SELECT); - for (u2=r->units; u2; u2=u2->next) { - if(u2->building == b && !fval(u2->faction, FFL_SELECT) + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->building == b && !fval(u2->faction, FFL_SELECT) && cansee(u->faction, r, u2, 0)) { - mailunit(r, u, u2->no, ord, s); - fset(u2->faction, FFL_SELECT); - } + mailunit(r, u, u2->no, ord, s); + fset(u2->faction, FFL_SELECT); + } } return 0; } - case P_SHIP: + case P_SHIP: { ship *sh = getship(r); - if(!sh) { + if (!sh) { cmistake(u, ord, 20, MSG_MESSAGE); break; } @@ -2044,10 +2235,12 @@ mail_cmd(unit * u, struct order * ord) break; } - for (u2 = r->units; u2; u2 = u2->next) freset(u2->faction, FFL_SELECT); + for (u2 = r->units; u2; u2 = u2->next) + freset(u2->faction, FFL_SELECT); - for(u2=r->units; u2; u2=u2->next) { - if(u2->ship == sh && !fval(u2->faction, FFL_SELECT) && cansee(u->faction, r, u2, 0)) { + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->ship == sh && !fval(u2->faction, FFL_SELECT) + && cansee(u->faction, r, u2, 0)) { mailunit(r, u, u2->no, ord, s); fset(u2->faction, FFL_SELECT); } @@ -2055,20 +2248,21 @@ mail_cmd(unit * u, struct order * ord) return 0; } - default: - /* possibly filler token? */ - s = getstrtoken(); - if (s && *s) cont = 1; - break; + default: + /* possibly filler token? */ + s = getstrtoken(); + if (s && *s) + cont = 1; + break; } } while (cont); cmistake(u, ord, 149, MSG_MESSAGE); return 0; } + /* ------------------------------------------------------------- */ -static int -banner_cmd(unit * u, struct order * ord) +static int banner_cmd(unit * u, struct order *ord) { init_tokens(ord); skip_token(); @@ -2076,15 +2270,14 @@ banner_cmd(unit * u, struct order * ord) free(u->faction->banner); u->faction->banner = strdup(getstrtoken()); add_message(&u->faction->msgs, msg_message("changebanner", "value", - u->faction->banner)); + u->faction->banner)); return 0; } -static int -email_cmd(unit * u, struct order * ord) +static int email_cmd(unit * u, struct order *ord) { - const char * s; + const char *s; init_tokens(ord); skip_token(); @@ -2093,9 +2286,11 @@ email_cmd(unit * u, struct order * ord) if (!s[0]) { cmistake(u, ord, 85, MSG_EVENT); } else { - faction * f = u->faction; - if (set_email(&f->email, (const char *)s)!=0) { - log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), s)); + faction *f = u->faction; + + if (set_email(&f->email, (const char *)s) != 0) { + log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), + s)); ADDMSG(&f->msgs, msg_message("changemail_invalid", "value", s)); } else { ADDMSG(&f->msgs, msg_message("changemail", "value", f->email)); @@ -2104,12 +2299,14 @@ email_cmd(unit * u, struct order * ord) return 0; } -static int -password_cmd(unit * u, struct order * ord) +static int password_cmd(unit * u, struct order *ord) { char pwbuf[32]; + int i; - const char * s; + + const char *s; + boolean pwok = true; init_tokens(ord); @@ -2117,7 +2314,8 @@ password_cmd(unit * u, struct order * ord) s = getstrtoken(); if (!s || !*s) { - for(i=0; i<6; i++) pwbuf[i] = (char)(97 + rng_int() % 26); + for (i = 0; i < 6; i++) + pwbuf[i] = (char)(97 + rng_int() % 26); pwbuf[6] = 0; } else { char *c; @@ -2126,7 +2324,8 @@ password_cmd(unit * u, struct order * ord) pwbuf[31] = 0; c = pwbuf; while (*c && pwok) { - if (!isalnum(*(unsigned char*)c)) pwok = false; + if (!isalnum(*(unsigned char *)c)) + pwok = false; c++; } } @@ -2139,14 +2338,14 @@ password_cmd(unit * u, struct order * ord) } fset(u->faction, FFL_OVERRIDE); ADDMSG(&u->faction->msgs, msg_message("changepasswd", - "value", u->faction->passw)); + "value", u->faction->passw)); return 0; } -static int -send_cmd(unit * u, struct order * ord) +static int send_cmd(unit * u, struct order *ord) { - const char * s; + const char *s; + int option; init_tokens(ord); @@ -2162,33 +2361,38 @@ send_cmd(unit * u, struct order * ord) if (option == O_COMPRESS || option == O_BZIP2) { cmistake(u, ord, 305, MSG_EVENT); } else { - u->faction->options = u->faction->options & ~(1<faction->options = u->faction->options & ~(1 << option); } } else { - u->faction->options = u->faction->options | (1<faction->options &= ~(1<faction->options &= ~(1<faction->options = u->faction->options | (1 << option); + if (option == O_COMPRESS) + u->faction->options &= ~(1 << O_BZIP2); + if (option == O_BZIP2) + u->faction->options &= ~(1 << O_COMPRESS); } } return 0; } -static boolean -display_item(faction *f, unit *u, const item_type * itype) +static boolean display_item(faction * f, unit * u, const item_type * itype) { const char *name; + const char *key; + const char *info; - if (u!=NULL) { + if (u != NULL) { int i = i_get(u->items, itype); - if (i==0) { - if (u->region->land!=NULL) { + + if (i == 0) { + if (u->region->land != NULL) { i = i_get(u->region->land->items, itype); } - if (i==0) { + if (i == 0) { i = i_get(u->faction->items, itype); - if (i==0) return false; + if (i == 0) + return false; } } } @@ -2197,147 +2401,186 @@ display_item(faction *f, unit *u, const item_type * itype) key = mkname("iteminfo", name); info = locale_getstring(f->locale, key); - if (info==NULL) { + if (info == NULL) { info = locale_string(f->locale, mkname("iteminfo", "no_info")); } ADDMSG(&f->msgs, msg_message("displayitem", "weight item description", - itype->weight, itype->rtype, info)); + itype->weight, itype->rtype, info)); return true; } -static boolean -display_potion(faction *f, unit *u, const potion_type * ptype) +static boolean display_potion(faction * f, unit * u, const potion_type * ptype) { attrib *a; - if (ptype==NULL) return false; + if (ptype == NULL) + return false; else { int i = i_get(u->items, ptype->itype); - if (i==0 && 2*ptype->level > effskill(u,SK_ALCHEMY)) { + + if (i == 0 && 2 * ptype->level > effskill(u, SK_ALCHEMY)) { return false; } } a = a_find(f->attribs, &at_showitem); - while (a && a->data.v != ptype) a=a->next; + while (a && a->data.v != ptype) + a = a->next; if (!a) { a = a_add(&f->attribs, a_new(&at_showitem)); - a->data.v = (void*) ptype->itype; + a->data.v = (void *)ptype->itype; } return true; } -static boolean -display_race(faction *f, unit *u, const race * rc) +static boolean display_race(faction * f, unit * u, const race * rc) { const char *name, *key; + const char *info; + int a, at_count; - char buf[2048], * bufp = buf; + + char buf[2048], *bufp = buf; + size_t size = sizeof(buf) - 1; + int bytes; - if (u && u->race != rc) return false; + if (u && u->race != rc) + return false; name = rc_name(rc, 0); bytes = slprintf(bufp, size, "%s: ", LOC(f->locale, name)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); key = mkname("raceinfo", rc->_name[0]); info = locale_getstring(f->locale, key); - if (info==NULL) { + if (info == NULL) { info = locale_string(f->locale, mkname("raceinfo", "no_info")); } bytes = (int)strlcpy(bufp, info, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); /* hp_p : Trefferpunkte */ - bytes = snprintf(bufp, size, " %d %s", rc->hitpoints, LOC(f->locale, "stat_hitpoints")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = + snprintf(bufp, size, " %d %s", rc->hitpoints, LOC(f->locale, + "stat_hitpoints")); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); /* b_attacke : Angriff */ - bytes = snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_attack"), (rc->at_default+rc->at_bonus)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = + snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_attack"), + (rc->at_default + rc->at_bonus)); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); /* b_defense : Verteidigung */ - bytes = snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_defense"), (rc->df_default+rc->df_bonus)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = + snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_defense"), + (rc->df_default + rc->df_bonus)); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); /* b_armor : Rüstung */ if (rc->armor > 0) { - bytes = snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_armor"), rc->armor); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = + snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_armor"), rc->armor); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } - if (size>1) { - *bufp++ ='.'; + if (size > 1) { + *bufp++ = '.'; --size; - } else WARN_STATIC_BUFFER(); + } else + WARN_STATIC_BUFFER(); /* b_damage : Schaden */ - at_count=0; + at_count = 0; for (a = 0; a < 6; a++) { - if (rc->attack[a].type != AT_NONE){ + if (rc->attack[a].type != AT_NONE) { at_count++; } } if (rc->battle_flags & BF_EQUIPMENT) { bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_equipment")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } if (rc->battle_flags & BF_RES_PIERCE) { bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_pierce")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } if (rc->battle_flags & BF_RES_CUT) { bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_cut")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } if (rc->battle_flags & BF_RES_BASH) { bytes = snprintf(bufp, size, " %s", LOC(f->locale, "stat_bash")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } - bytes = snprintf(bufp, size, " %d %s", at_count, LOC(f->locale, (at_count==1)?"stat_attack":"stat_attacks")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = + snprintf(bufp, size, " %d %s", at_count, LOC(f->locale, + (at_count == 1) ? "stat_attack" : "stat_attacks")); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); for (a = 0; a < 6; a++) { - if (rc->attack[a].type != AT_NONE){ - if (a!=0) bytes = (int)strlcpy(bufp, ", ", size); - else bytes = (int)strlcpy(bufp, ": ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (rc->attack[a].type != AT_NONE) { + if (a != 0) + bytes = (int)strlcpy(bufp, ", ", size); + else + bytes = (int)strlcpy(bufp, ": ", size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); - switch(rc->attack[a].type) { - case AT_STANDARD: - bytes = snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_standard"), rc->def_damage); - break; - case AT_NATURAL: - bytes = snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_natural"), rc->attack[a].data.dice); - break; - case AT_SPELL: - case AT_COMBATSPELL: - case AT_DRAIN_ST: - case AT_DAZZLE: - bytes = snprintf(bufp, size, "%s", LOC(f->locale, "attack_magical")); - break; - case AT_STRUCTURAL: - bytes = snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_structural"), rc->attack[a].data.dice); - break; - default: - bytes = 0; + switch (rc->attack[a].type) { + case AT_STANDARD: + bytes = + snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_standard"), + rc->def_damage); + break; + case AT_NATURAL: + bytes = + snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_natural"), + rc->attack[a].data.dice); + break; + case AT_SPELL: + case AT_COMBATSPELL: + case AT_DRAIN_ST: + case AT_DAZZLE: + bytes = snprintf(bufp, size, "%s", LOC(f->locale, "attack_magical")); + break; + case AT_STRUCTURAL: + bytes = + snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_structural"), + rc->attack[a].data.dice); + break; + default: + bytes = 0; } - if (bytes && wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (bytes && wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } - if (size>1) { + if (size > 1) { *bufp++ = '.'; --size; - } else WARN_STATIC_BUFFER(); + } else + WARN_STATIC_BUFFER(); *bufp = 0; addmessage(0, f, buf, MSG_EVENT, ML_IMPORTANT); @@ -2345,14 +2588,17 @@ display_race(faction *f, unit *u, const race * rc) return true; } -static void -reshow(unit * u, struct order * ord, const char * s, param_t p) +static void reshow(unit * u, struct order *ord, const char *s, param_t p) { int skill, c; - const potion_type * ptype; - const item_type * itype; - const spell * sp; - const race * rc; + + const potion_type *ptype; + + const item_type *itype; + + const spell *sp; + + const race *rc; switch (p) { case P_ZAUBER: @@ -2361,36 +2607,43 @@ reshow(unit * u, struct order * ord, const char * s, param_t p) case P_POTIONS: skill = effskill(u, SK_ALCHEMY); c = 0; - for (ptype = potiontypes; ptype!=NULL; ptype=ptype->next) { + for (ptype = potiontypes; ptype != NULL; ptype = ptype->next) { if (ptype->level * 2 <= skill) { c += display_potion(u->faction, u, ptype); } } - if (c == 0) cmistake(u, ord, 285, MSG_EVENT); + if (c == 0) + cmistake(u, ord, 285, MSG_EVENT); break; case NOPARAM: /* check if it's an item */ itype = finditemtype(s, u->faction->locale); - if (itype!=NULL) { + if (itype != NULL) { ptype = resource2potion(item2resource(itype)); - if (ptype!=NULL) { - if (display_potion(u->faction, u, ptype)) break; + if (ptype != NULL) { + if (display_potion(u->faction, u, ptype)) + break; } else { - if (display_item(u->faction, u, itype)) break; + if (display_item(u->faction, u, itype)) + break; } } /* try for a spell */ sp = get_spellfromtoken(u, s, u->faction->locale); - if (sp!=NULL && u_hasspell(u, sp)) { + if (sp != NULL && u_hasspell(u, sp)) { attrib *a = a_find(u->faction->attribs, &at_seenspell); - while (a!=NULL && a->type==&at_seenspell && a->data.v!=sp) a = a->next; - if (a!=NULL) a_remove(&u->faction->attribs, a); + + while (a != NULL && a->type == &at_seenspell && a->data.v != sp) + a = a->next; + if (a != NULL) + a_remove(&u->faction->attribs, a); break; } /* last, check if it's a race. */ rc = findrace(s, u->faction->locale); if (rc != NULL) { - if (display_race(u->faction, u, rc)) break; + if (display_race(u->faction, u, rc)) + break; } cmistake(u, ord, 21, MSG_EVENT); break; @@ -2400,8 +2653,7 @@ reshow(unit * u, struct order * ord, const char * s, param_t p) } } -static int -promotion_cmd(unit * u, struct order * ord) +static int promotion_cmd(unit * u, struct order *ord) { int money, people; @@ -2410,35 +2662,34 @@ promotion_cmd(unit * u, struct order * ord) return 0; } - if (maxheroes(u->faction) < countheroes(u->faction)+u->number) { + if (maxheroes(u->faction) < countheroes(u->faction) + u->number) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_maxed", "max count", - maxheroes(u->faction), countheroes(u->faction))); + maxheroes(u->faction), countheroes(u->faction))); return 0; } if (!valid_race(u->faction, u->race)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_race", "race", - u->race)); + u->race)); return 0; } people = count_all(u->faction) * u->number; money = get_pooled(u, i_silver->rtype, GET_ALL, people); - if (people>money) { + if (people > money) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_cost", "cost have", - people, money)); + people, money)); return 0; } use_pooled(u, i_silver->rtype, GET_ALL, people); fset(u, UFL_HERO); ADDMSG(&u->faction->msgs, msg_message("hero_promotion", "unit cost", - u, people)); + u, people)); return 0; } -static int -group_cmd(unit * u, struct order * ord) +static int group_cmd(unit * u, struct order *ord) { - const char * s; + const char *s; init_tokens(ord); skip_token(); @@ -2448,8 +2699,7 @@ group_cmd(unit * u, struct order * ord) return 0; } -static int -origin_cmd(unit * u, struct order * ord) +static int origin_cmd(unit * u, struct order *ord) { short px, py; @@ -2463,10 +2713,9 @@ origin_cmd(unit * u, struct order * ord) return 0; } -static int -guard_off_cmd(unit * u, struct order * ord) +static int guard_off_cmd(unit * u, struct order *ord) { - assert(get_keyword(ord)==K_GUARD); + assert(get_keyword(ord) == K_GUARD); init_tokens(ord); skip_token(); @@ -2476,10 +2725,10 @@ guard_off_cmd(unit * u, struct order * ord) return 0; } -static int -reshow_cmd(unit * u, struct order * ord) +static int reshow_cmd(unit * u, struct order *ord) { - const char * s; + const char *s; + param_t p = NOPARAM; init_tokens(ord); @@ -2495,58 +2744,58 @@ reshow_cmd(unit * u, struct order * ord) return 0; } -static int -status_cmd(unit * u, struct order * ord) +static int status_cmd(unit * u, struct order *ord) { - const char * param; + const char *param; init_tokens(ord); skip_token(); param = getstrtoken(); switch (findparam(param, u->faction->locale)) { - case P_NOT: - setstatus(u, ST_AVOID); - break; - case P_BEHIND: - setstatus(u, ST_BEHIND); - break; - case P_FLEE: - setstatus(u, ST_FLEE); - break; - case P_CHICKEN: - setstatus(u, ST_CHICKEN); - break; - case P_AGGRO: - setstatus(u, ST_AGGRO); - break; - case P_VORNE: - setstatus(u, ST_FIGHT); - break; - case P_HELP: - if (getparam(u->faction->locale) == P_NOT) { - fset(u, UFL_NOAID); - } else { - freset(u, UFL_NOAID); - } - break; - default: - if (param[0]) { - add_message(&u->faction->msgs, - msg_feedback(u, ord, "unknown_status", "")); - } else { + case P_NOT: + setstatus(u, ST_AVOID); + break; + case P_BEHIND: + setstatus(u, ST_BEHIND); + break; + case P_FLEE: + setstatus(u, ST_FLEE); + break; + case P_CHICKEN: + setstatus(u, ST_CHICKEN); + break; + case P_AGGRO: + setstatus(u, ST_AGGRO); + break; + case P_VORNE: setstatus(u, ST_FIGHT); - } + break; + case P_HELP: + if (getparam(u->faction->locale) == P_NOT) { + fset(u, UFL_NOAID); + } else { + freset(u, UFL_NOAID); + } + break; + default: + if (param[0]) { + add_message(&u->faction->msgs, + msg_feedback(u, ord, "unknown_status", "")); + } else { + setstatus(u, ST_FIGHT); + } } return 0; } -static int -combatspell_cmd(unit * u, struct order * ord) +static int combatspell_cmd(unit * u, struct order *ord) { - const char * s; + const char *s; + int level = 0; - spell * spell; + + spell *spell; init_tokens(ord); skip_token(); @@ -2568,7 +2817,7 @@ combatspell_cmd(unit * u, struct order * ord) spell = get_spellfromtoken(u, s, u->faction->locale); - if(!spell){ + if (!spell) { cmistake(u, ord, 173, MSG_MAGIC); return 0; } @@ -2577,7 +2826,7 @@ combatspell_cmd(unit * u, struct order * ord) if (findparam(s, u->faction->locale) == P_NOT) { /* KAMPFZAUBER "" NICHT löscht diesen speziellen - * Kampfzauber */ + * Kampfzauber */ unset_combatspell(u, spell); return 0; } else { @@ -2594,30 +2843,34 @@ combatspell_cmd(unit * u, struct order * ord) enum { E_GUARD_OK, E_GUARD_UNARMED, E_GUARD_NEWBIE, E_GUARD_FLEEING }; -static int -can_start_guarding(const unit * u) +static int can_start_guarding(const unit * u) { - if (u->status>=ST_FLEE) return E_GUARD_FLEEING; - if (fval(u->race, RCF_UNARMEDGUARD)) return E_GUARD_OK; - if (!armedmen(u, true)) return E_GUARD_UNARMED; - if (IsImmune(u->faction)) return E_GUARD_NEWBIE; + if (u->status >= ST_FLEE) + return E_GUARD_FLEEING; + if (fval(u->race, RCF_UNARMEDGUARD)) + return E_GUARD_OK; + if (!armedmen(u, true)) + return E_GUARD_UNARMED; + if (IsImmune(u->faction)) + return E_GUARD_NEWBIE; return E_GUARD_OK; } -void -update_guards(void) +void update_guards(void) { const region *r; for (r = regions; r; r = r->next) { unit *u; + for (u = r->units; u; u = u->next) { if (fval(u, UFL_GUARD)) { - if (can_start_guarding(u)!=E_GUARD_OK) { + if (can_start_guarding(u) != E_GUARD_OK) { setguard(u, GUARD_NONE); } else { - attrib * a = a_find(u->attribs, &at_guard); - if (a && a->data.i==(int)guard_flags(u)) { + attrib *a = a_find(u->attribs, &at_guard); + + if (a && a->data.i == (int)guard_flags(u)) { /* this is really rather not necessary */ a_remove(&u->attribs, a); } @@ -2627,16 +2880,16 @@ update_guards(void) } } -static int -guard_on_cmd(unit * u, struct order * ord) +static int guard_on_cmd(unit * u, struct order *ord) { - assert(get_keyword(ord)==K_GUARD); + assert(get_keyword(ord) == K_GUARD); init_tokens(ord); skip_token(); /* GUARD NOT is handled in goard_off_cmd earlier in the turn */ - if (getparam(u->faction->locale) == P_NOT) return 0; + if (getparam(u->faction->locale) == P_NOT) + return 0; if (fval(u->region->terrain, SEA_REGION)) { cmistake(u, ord, 2, MSG_EVENT); @@ -2651,13 +2904,14 @@ guard_on_cmd(unit * u, struct order * ord) guard(u, GUARD_ALL); } else { int err = can_start_guarding(u); - if (err==E_GUARD_OK) { + + if (err == E_GUARD_OK) { guard(u, GUARD_ALL); - } else if (err==E_GUARD_UNARMED) { + } else if (err == E_GUARD_UNARMED) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_unarmed", "")); - } else if (err==E_GUARD_FLEEING) { + } else if (err == E_GUARD_FLEEING) { cmistake(u, ord, 320, MSG_EVENT); - } else if (err==E_GUARD_NEWBIE) { + } else if (err == E_GUARD_NEWBIE) { cmistake(u, ord, 304, MSG_EVENT); } } @@ -2666,29 +2920,33 @@ guard_on_cmd(unit * u, struct order * ord) return 0; } -static void -sinkships(region * r) +static void sinkships(region * r) { ship **shp = &r->ships; while (*shp) { - ship * sh = *shp; + ship *sh = *shp; - if (!sh->type->construction || sh->size>=sh->type->construction->maxsize) { - if (fval(r->terrain, SEA_REGION) && (!enoughsailors(sh, r) || get_captain(sh)==NULL)) { + if (!sh->type->construction || sh->size >= sh->type->construction->maxsize) { + if (fval(r->terrain, SEA_REGION) && (!enoughsailors(sh, r) + || get_captain(sh) == NULL)) { /* Schiff nicht seetüchtig */ - float dmg = get_param_flt(global.parameters, "rules.ship.damage.nocrewocean", 0.30F); + float dmg = + get_param_flt(global.parameters, "rules.ship.damage.nocrewocean", + 0.30F); damage_ship(sh, dmg); } - if (shipowner(sh)==NULL) { - float dmg = get_param_flt(global.parameters, "rules.ship.damage.nocrew", 0.05F); + if (shipowner(sh) == NULL) { + float dmg = + get_param_flt(global.parameters, "rules.ship.damage.nocrew", 0.05F); damage_ship(sh, dmg); } } if (sh->damage >= sh->size * DAMAGE_SCALE) { remove_ship(shp, sh); } - if (*shp==sh) shp=&sh->next; + if (*shp == sh) + shp = &sh->next; } } @@ -2702,24 +2960,29 @@ static attrib_type at_number = { ATF_UNIQUE }; -static void -renumber_factions(void) +static void renumber_factions(void) /* gibt parteien neue nummern */ { struct renum { - struct renum * next; + struct renum *next; int want; - faction * faction; - attrib * attrib; - } * renum = NULL, * rp; - faction * f; - for (f=factions;f;f=f->next) { - attrib * a = a_find(f->attribs, &at_number); - int want; - struct renum ** rn; - faction * old; + faction *faction; + attrib *attrib; + } *renum = NULL, *rp; - if (!a) continue; + faction *f; + + for (f = factions; f; f = f->next) { + attrib *a = a_find(f->attribs, &at_number); + + int want; + + struct renum **rn; + + faction *old; + + if (!a) + continue; want = a->data.i; if (fval(f, FFL_NEWID)) { ADDMSG(&f->msgs, msg_message("renumber_twice", "id", want)); @@ -2736,13 +2999,15 @@ renumber_factions(void) ADDMSG(&f->msgs, msg_message("renumber_inuse", "id", want)); continue; } - for (rn=&renum; *rn; rn=&(*rn)->next) { - if ((*rn)->want>=want) break; + for (rn = &renum; *rn; rn = &(*rn)->next) { + if ((*rn)->want >= want) + break; } - if (*rn && (*rn)->want==want) { + if (*rn && (*rn)->want == want) { ADDMSG(&f->msgs, msg_message("renumber_inuse", "id", want)); } else { - struct renum * r = calloc(sizeof(struct renum), 1); + struct renum *r = calloc(sizeof(struct renum), 1); + r->next = *rn; r->attrib = a; r->faction = f; @@ -2750,7 +3015,7 @@ renumber_factions(void) *rn = r; } } - for (rp=renum;rp;rp=rp->next) { + for (rp = renum; rp; rp = rp->next) { f = rp->faction; a_remove(&f->attribs, rp->attrib); renumber_faction(f, rp->want); @@ -2762,22 +3027,29 @@ renumber_factions(void) } } -static void -reorder(void) +static void reorder(void) { - region * r; - for (r=regions;r;r=r->next) { - unit ** up=&r->units; - boolean sorted=false; + region *r; + + for (r = regions; r; r = r->next) { + unit **up = &r->units; + + boolean sorted = false; + while (*up) { - unit * u = *up; + unit *u = *up; + if (!fval(u, UFL_MARK)) { - struct order * ord; - for (ord = u->orders;ord;ord=ord->next) { - if (get_keyword(ord)==K_SORT) { - const char * s; + struct order *ord; + + for (ord = u->orders; ord; ord = ord->next) { + if (get_keyword(ord) == K_SORT) { + const char *s; + param_t p; + int id; + unit *v; init_tokens(ord); @@ -2787,32 +3059,34 @@ reorder(void) id = getid(); v = findunit(id); - if (v==NULL || v->faction!=u->faction || v->region!=r) { + if (v == NULL || v->faction != u->faction || v->region != r) { cmistake(u, ord, 258, MSG_EVENT); - } else if (v->building != u->building || v->ship!=u->ship) { + } else if (v->building != u->building || v->ship != u->ship) { cmistake(u, ord, 259, MSG_EVENT); } else if (fval(u, UFL_OWNER)) { cmistake(u, ord, 260, MSG_EVENT); } else if (v == u) { cmistake(u, ord, 10, MSG_EVENT); } else { - switch(p) { - case P_AFTER: - *up = u->next; - u->next = v->next; - v->next = u; - break; - case P_BEFORE: - if (fval(v, UFL_OWNER)) { - cmistake(v, ord, 261, MSG_EVENT); - } else { - unit ** vp=&r->units; - while (*vp!=v) vp=&(*vp)->next; - *vp = u; + switch (p) { + case P_AFTER: *up = u->next; - u->next = v; - } - break; + u->next = v->next; + v->next = u; + break; + case P_BEFORE: + if (fval(v, UFL_OWNER)) { + cmistake(v, ord, 261, MSG_EVENT); + } else { + unit **vp = &r->units; + + while (*vp != v) + vp = &(*vp)->next; + *vp = u; + *up = u->next; + u->next = v; + } + break; } fset(u, UFL_MARK); sorted = true; @@ -2821,91 +3095,103 @@ reorder(void) } } } - if (u==*up) up=&u->next; + if (u == *up) + up = &u->next; } if (sorted) { - unit * u; - for (u=r->units;u;u=u->next) freset(u, UFL_MARK); + unit *u; + + for (u = r->units; u; u = u->next) + freset(u, UFL_MARK); } } } #if 0 /* Aus Gebäude weisen, VERBANNE */ -static void -evict(void) +static void evict(void) { region *r; + strlist *S; - unit * u; - for (r=regions;r;r=r->next) { - for (u=r->units;u;u=u->next) { - for (S = u->orders; S; S = S->next) if (get_keyword(ord)==K_EVICT) { - int id; - unit *u2; - /* Nur der Kapitän bzw Burgherr kann jemanden rausschmeißen */ - if(!fval(u, UFL_OWNER)) { - /* Die Einheit ist nicht der Eigentümer */ - cmistake(u,ord,49,MSG_EVENT); - continue; - } - init_tokens(ord); - skip_token(); - id = getid(); - u2 = findunit(id); + unit *u; - if (u2==NULL) { - /* Einheit nicht gefunden */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - continue; - } + for (r = regions; r; r = r->next) { + for (u = r->units; u; u = u->next) { + for (S = u->orders; S; S = S->next) + if (get_keyword(ord) == K_EVICT) { + int id; - if (u->building){ - /* in der selben Burg? */ - if (u->building != u2->building){ - /* nicht in Burg */ - cmistake(u,ord,33,MSG_EVENT); + unit *u2; + + /* Nur der Kapitän bzw Burgherr kann jemanden rausschmeißen */ + if (!fval(u, UFL_OWNER)) { + /* Die Einheit ist nicht der Eigentümer */ + cmistake(u, ord, 49, MSG_EVENT); continue; } - leave_building(u2); - /* meldung an beide */ - } + init_tokens(ord); + skip_token(); + id = getid(); + u2 = findunit(id); - if (u->ship){ - if (u->ship != u2->ship){ - /* nicht an Bord */ - cmistake(u, ord, 32, MSG_EVENT); + if (u2 == NULL) { + /* Einheit nicht gefunden */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, + "feedback_unit_not_found", "")); continue; } - leave_ship(u2); - /* meldung an beide */ + + if (u->building) { + /* in der selben Burg? */ + if (u->building != u2->building) { + /* nicht in Burg */ + cmistake(u, ord, 33, MSG_EVENT); + continue; + } + leave_building(u2); + /* meldung an beide */ + } + + if (u->ship) { + if (u->ship != u2->ship) { + /* nicht an Bord */ + cmistake(u, ord, 32, MSG_EVENT); + continue; + } + leave_ship(u2); + /* meldung an beide */ + } } - } } } } #endif -static int -renumber_cmd(unit * u, order * ord) +static int renumber_cmd(unit * u, order * ord) { - const char * s; + const char *s; + int i; - faction * f = u->faction; + + faction *f = u->faction; init_tokens(ord); skip_token(); s = getstrtoken(); - switch(findparam(s, u->faction->locale)) { + switch (findparam(s, u->faction->locale)) { case P_FACTION: s = getstrtoken(); if (s && *s) { int id = atoi36((const char *)s); - attrib * a = a_find(f->attribs, &at_number); - if (!a) a = a_add(&f->attribs, a_new(&at_number)); + + attrib *a = a_find(f->attribs, &at_number); + + if (!a) + a = a_add(&f->attribs, a_new(&at_number)); a->data.i = id; } break; @@ -2916,7 +3202,7 @@ renumber_cmd(unit * u, order * ord) i = newunitid(); } else { i = atoi36((const char *)s); - if (i<=0 || i>MAX_UNIT_NR) { + if (i <= 0 || i > MAX_UNIT_NR) { cmistake(u, ord, 114, MSG_EVENT); break; } @@ -2934,6 +3220,7 @@ renumber_cmd(unit * u, order * ord) uunhash(u); if (!ualias(u)) { attrib *a = a_add(&u->attribs, a_new(&at_alias)); + a->data.i = -u->no; } u->no = i; @@ -2958,8 +3245,8 @@ renumber_cmd(unit * u, order * ord) i = newcontainerid(); } else { i = atoi36((const char *)s); - if (i<=0 || i>MAX_CONTAINER_NR) { - cmistake(u,ord,114,MSG_EVENT); + if (i <= 0 || i > MAX_CONTAINER_NR) { + cmistake(u, ord, 114, MSG_EVENT); break; } if (findship(i) || findbuilding(i)) { @@ -2974,24 +3261,24 @@ renumber_cmd(unit * u, order * ord) case P_BUILDING: case P_GEBAEUDE: if (!u->building) { - cmistake(u,ord,145,MSG_EVENT); + cmistake(u, ord, 145, MSG_EVENT); break; } - if(!fval(u, UFL_OWNER)) { - cmistake(u,ord,148,MSG_EVENT); + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 148, MSG_EVENT); break; } s = getstrtoken(); - if(*s == 0) { + if (*s == 0) { i = newcontainerid(); } else { i = atoi36((const char *)s); - if (i<=0 || i>MAX_CONTAINER_NR) { - cmistake(u,ord,114,MSG_EVENT); + if (i <= 0 || i > MAX_CONTAINER_NR) { + cmistake(u, ord, 114, MSG_EVENT); break; } - if(findship(i) || findbuilding(i)) { - cmistake(u,ord,115,MSG_EVENT); + if (findship(i) || findbuilding(i)) { + cmistake(u, ord, 115, MSG_EVENT); break; } } @@ -3006,12 +3293,14 @@ renumber_cmd(unit * u, order * ord) return 0; } -static building * -age_building(building * b) +static building *age_building(building * b) { static boolean init = false; - static const building_type * bt_blessed; - static const curse_type * ct_astralblock; + + static const building_type *bt_blessed; + + static const curse_type *ct_astralblock; + if (!init) { init = true; bt_blessed = bt_find("blessedstonecircle"); @@ -3025,31 +3314,35 @@ age_building(building * b) * * TODO: this would be nicer in a btype->age function, but we don't have it. */ - if (ct_astralblock && bt_blessed && b->type==bt_blessed) { - region * r = b->region; - region * rt = r_standard_to_astral(r); - unit * u, * mage = NULL; + if (ct_astralblock && bt_blessed && b->type == bt_blessed) { + region *r = b->region; - if (fval(rt->terrain, FORBIDDEN_REGION)) rt = NULL; + region *rt = r_standard_to_astral(r); + + unit *u, *mage = NULL; + + if (fval(rt->terrain, FORBIDDEN_REGION)) + rt = NULL; /* step 1: give unicorns to people in the building, * find out if there's a magician in there. */ - for (u=r->units;u;u=u->next) { - if (b==u->building && inside_building(u)) { - if (!(u->race->ec_flags & GIVEITEM)==0) { + for (u = r->units; u; u = u->next) { + if (b == u->building && inside_building(u)) { + if (!(u->race->ec_flags & GIVEITEM) == 0) { int n, unicorns = 0; - for (n=0; n!=u->number; ++n) { + + for (n = 0; n != u->number; ++n) { if (chance(0.02)) { i_change(&u->items, olditemtype[I_ELVENHORSE], 1); ++unicorns; } if (unicorns) { - ADDMSG(&u->faction->msgs, msg_message("scunicorn", - "unit amount rtype", u, unicorns, - olditemtype[I_ELVENHORSE]->rtype)); + ADDMSG(&u->faction->msgs, msg_message("scunicorn", + "unit amount rtype", u, unicorns, + olditemtype[I_ELVENHORSE]->rtype)); } } } - if (mage==NULL && is_mage(u)) { + if (mage == NULL && is_mage(u)) { mage = u; } } @@ -3057,22 +3350,26 @@ age_building(building * b) /* if there's a magician, and a connection to astral space, create the * curse. */ - if (rt!=NULL && mage!=NULL) { - curse * c = get_curse(rt->attribs, ct_astralblock); - if (c==NULL) { - if (mage!=NULL) { + if (rt != NULL && mage != NULL) { + curse *c = get_curse(rt->attribs, ct_astralblock); + + if (c == NULL) { + if (mage != NULL) { int sk = effskill(mage, SK_MAGIC); + double effect; + effect = 100; /* the mage reactivates the circle */ c = create_curse(mage, &rt->attribs, ct_astralblock, - (float)MAX(1, sk), MAX(1, sk/2), effect, 0); - ADDMSG(&r->msgs, msg_message("astralshield_activate", - "region unit", r, mage)); + (float)MAX(1, sk), MAX(1, sk / 2), effect, 0); + ADDMSG(&r->msgs, msg_message("astralshield_activate", + "region unit", r, mage)); } - } else if (mage!=NULL) { + } else if (mage != NULL) { int sk = effskill(mage, SK_MAGIC); - c->duration = MAX(c->duration, sk/2); + + c->duration = MAX(c->duration, sk / 2); c->vigour = MAX(c->vigour, sk); } } @@ -3088,69 +3385,79 @@ age_building(building * b) return b; } -static double rc_popularity(const struct race * rc) +static double rc_popularity(const struct race *rc) { int pop = get_param_int(rc->parameters, "morale", MORALE_AVERAGE); - return 1.0/(pop-MORALE_COOLDOWN); /* 10 turns average */ + + return 1.0 / (pop - MORALE_COOLDOWN); /* 10 turns average */ } -static void age_region(region * r) +static void age_region(region * r) { a_age(&r->attribs); handle_event(r->attribs, "timer", r); - if (!r->land) return; + if (!r->land) + return; if (r->land->ownership && r->land->ownership->owner) { int stability = turn - r->land->ownership->morale_turn; + int maxmorale = MORALE_DEFAULT; - building * b = largestbuilding(r, &cmp_taxes, false); + + building *b = largestbuilding(r, &cmp_taxes, false); + if (b) { int bsize = buildingeffsize(b, false); - maxmorale = (int)(0.5 + b->type->taxes(b, bsize+1) / MORALE_TAX_FACTOR); + + maxmorale = (int)(0.5 + b->type->taxes(b, bsize + 1) / MORALE_TAX_FACTOR); } - if (r->land->moraleMORALE_COOLDOWN && r->land->ownership->owner && r->land->moraleland->morale < maxmorale) { + if (stability > MORALE_COOLDOWN && r->land->ownership->owner + && r->land->morale < MORALE_MAX) { double ch = rc_popularity(r->land->ownership->owner->race); + if (is_cursed(r->attribs, C_GENEROUS, 0)) { - ch *= 1.2; /* 20% improvement */ + ch *= 1.2; /* 20% improvement */ } - if (stability>=MORALE_AVERAGE*2 || chance(ch)) { - region_set_morale(r, r->land->morale+1, turn); + if (stability >= MORALE_AVERAGE * 2 || chance(ch)) { + region_set_morale(r, r->land->morale + 1, turn); } } - } else if (r->land->morale>maxmorale) { - region_set_morale(r, r->land->morale-1, turn); + } else if (r->land->morale > maxmorale) { + region_set_morale(r, r->land->morale - 1, turn); } - } else if (r->land->morale>MORALE_DEFAULT) { - region_set_morale(r, r->land->morale-1, turn); + } else if (r->land->morale > MORALE_DEFAULT) { + region_set_morale(r, r->land->morale - 1, turn); } } -static void -ageing(void) +static void ageing(void) { faction *f; + region *r; /* altern spezieller Attribute, die eine Sonderbehandlung brauchen? */ - for(r=regions;r;r=r->next) { + for (r = regions; r; r = r->next) { unit *u; - for (u=r->units;u;u=u->next) { + for (u = r->units; u; u = u->next) { /* Goliathwasser */ int i = get_effect(u, oldpotiontype[P_STRONG]); - if (i > 0){ + + if (i > 0) { change_effect(u, oldpotiontype[P_STRONG], -1 * MIN(u->number, i)); } - /* Berserkerblut*/ + /* Berserkerblut */ i = get_effect(u, oldpotiontype[P_BERSERK]); - if (i > 0){ + if (i > 0) { change_effect(u, oldpotiontype[P_BERSERK], -1 * MIN(u->number, i)); } - if (is_cursed(u->attribs, C_OLDRACE, 0)){ + if (is_cursed(u->attribs, C_OLDRACE, 0)) { curse *c = get_curse(u->attribs, ct_find("oldrace")); + if (c->duration == 1 && !(c_flags(c) & CURSE_NOAGE)) { u->race = new_race[curse_geteffect_int(c)]; u->irace = NULL; @@ -3163,40 +3470,50 @@ ageing(void) age_borders(); /* Factions */ - for (f=factions;f;f=f->next) { + for (f = factions; f; f = f->next) { a_age(&f->attribs); handle_event(f->attribs, "timer", f); } /* Regionen */ - for (r=regions;r;r=r->next) { - building ** bp; - unit ** up; - ship ** sp; + for (r = regions; r; r = r->next) { + building **bp; + + unit **up; + + ship **sp; age_region(r); /* Einheiten */ - for (up=&r->units;*up;) { - unit * u = *up; + for (up = &r->units; *up;) { + unit *u = *up; + a_age(&u->attribs); - if (u==*up) handle_event(u->attribs, "timer", u); - if (u==*up) up = &(*up)->next; + if (u == *up) + handle_event(u->attribs, "timer", u); + if (u == *up) + up = &(*up)->next; } /* Schiffe */ - for (sp=&r->ships;*sp;) { - ship * s = *sp; + for (sp = &r->ships; *sp;) { + ship *s = *sp; + a_age(&s->attribs); - if (s==*sp) handle_event(s->attribs, "timer", s); - if (s==*sp) sp = &(*sp)->next; + if (s == *sp) + handle_event(s->attribs, "timer", s); + if (s == *sp) + sp = &(*sp)->next; } /* Gebäude */ - for (bp=&r->buildings;*bp;) { - building * b = *bp; + for (bp = &r->buildings; *bp;) { + building *b = *bp; + age_building(b); - if (b==*bp) bp = &b->next; + if (b == *bp) + bp = &b->next; } if (rule_region_owners()) { @@ -3205,30 +3522,31 @@ ageing(void) } } -static int -maxunits(const faction *f) +static int maxunits(const faction * f) { int flimit = rule_faction_limit(); + int alimit = rule_alliance_limit(); - if (alimit==0) { + + if (alimit == 0) { return flimit; } - if (flimit==0) { + if (flimit == 0) { return alimit; } return MIN(alimit, flimit); } -int -checkunitnumber(const faction *f, int add) +int checkunitnumber(const faction * f, int add) { int alimit, flimit; alimit = rule_alliance_limit(); if (alimit) { /* if unitsperalliance is true, maxunits returns the - number of units allowed in an alliance */ + number of units allowed in an alliance */ faction *f2; + int unitsinalliance = add; for (f2 = factions; f2; f2 = f2->next) { @@ -3251,53 +3569,63 @@ checkunitnumber(const faction *f, int add) return 0; } -static void -new_units(void) +static void new_units(void) { region *r; + unit *u, *u2; /* neue einheiten werden gemacht und ihre befehle (bis zum "ende" zu - * ihnen rueberkopiert, damit diese einheiten genauso wie die alten - * einheiten verwendet werden koennen. */ + * ihnen rueberkopiert, damit diese einheiten genauso wie die alten + * einheiten verwendet werden koennen. */ for (r = regions; r; r = r->next) { for (u = r->units; u; u = u->next) { - order ** ordp = &u->orders; + order **ordp = &u->orders; /* this needs to happen very early in the game somewhere. since this is - ** pretty much the first function called per turn, and I am lazy, I - ** decree that it goes here */ - if (u->flags&UFL_GUARD) { + ** pretty much the first function called per turn, and I am lazy, I + ** decree that it goes here */ + if (u->flags & UFL_GUARD) { fset(r, RF_GUARDED); } while (*ordp) { - order * makeord = *ordp; + order *makeord = *ordp; + if (get_keyword(makeord) == K_MAKE) { init_tokens(makeord); skip_token(); if (getparam(u->faction->locale) == P_TEMP) { - const char * token; - char * name = NULL; + const char *token; + + char *name = NULL; + int alias; - ship * sh; - order ** newordersp; + + ship *sh; + + order **newordersp; + int err = checkunitnumber(u->faction, 1); if (err) { - if (err==1) { + if (err == 1) { ADDMSG(&u->faction->msgs, msg_feedback(u, makeord, - "too_many_units_in_alliance", "allowed", maxunits(u->faction))); + "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))); + "too_many_units_in_faction", "allowed", + maxunits(u->faction))); } ordp = &makeord->next; while (*ordp) { - order * ord = *ordp; - if (get_keyword(ord) == K_END) break; + order *ord = *ordp; + + if (get_keyword(ord) == K_END) + break; *ordp = ord->next; ord->next = NULL; free_order(ord); @@ -3310,20 +3638,25 @@ new_units(void) if (token && token[0]) { name = strdup(token); } - u2 = create_unit(r, u->faction, 0, u->faction->race, alias, name, u); - if (name!=NULL) free(name); + u2 = + create_unit(r, u->faction, 0, u->faction->race, alias, name, u); + if (name != NULL) + free(name); fset(u2, UFL_ISNEW); a_add(&u2->attribs, a_new(&at_alias))->data.i = alias; sh = leftship(u); - if (sh) set_leftship(u2, sh); + if (sh) + set_leftship(u2, sh); setstatus(u2, u->status); ordp = &makeord->next; newordersp = &u2->orders; while (*ordp) { - order * ord = *ordp; - if (get_keyword(ord) == K_END) break; + order *ord = *ordp; + + if (get_keyword(ord) == K_END) + break; *ordp = ord->next; ord->next = NULL; *newordersp = ord; @@ -3331,7 +3664,8 @@ new_units(void) } } } - if (*ordp==makeord) ordp=&makeord->next; + if (*ordp == makeord) + ordp = &makeord->next; } } } @@ -3339,8 +3673,10 @@ new_units(void) /** Checks for two long orders and issues a warning if necessary. */ -void check_long_orders(unit *u) { +void check_long_orders(unit * u) +{ order *ord; + keyword_t otherorder = MAXKEYWORDS; for (ord = u->orders; ord; ord = ord->next) { @@ -3348,29 +3684,30 @@ void check_long_orders(unit *u) { cmistake(u, ord, 22, MSG_EVENT); } else if (is_long(ord)) { keyword_t longorder = get_keyword(ord); + if (otherorder != MAXKEYWORDS) { switch (longorder) { - case K_CAST: - if (otherorder!=longorder) { + case K_CAST: + if (otherorder != longorder) { + cmistake(u, ord, 52, MSG_EVENT); + } + break; + case K_BUY: + if (otherorder == K_SELL) { + otherorder = K_BUY; + } else { + cmistake(u, ord, 52, MSG_EVENT); + } + break; + case K_SELL: + if (otherorder != K_SELL && otherorder != K_BUY) { + cmistake(u, ord, 52, MSG_EVENT); + } + break; + case K_WEREWOLF: + /* don't know what WEREWOLF does... */ + default: cmistake(u, ord, 52, MSG_EVENT); - } - break; - case K_BUY: - if (otherorder==K_SELL) { - otherorder=K_BUY; - } else { - cmistake(u, ord, 52, MSG_EVENT); - } - break; - case K_SELL: - if (otherorder!=K_SELL && otherorder!=K_BUY) { - cmistake(u, ord, 52, MSG_EVENT); - } - break; - case K_WEREWOLF: - /* don't know what WEREWOLF does... */ - default: - cmistake(u, ord, 52, MSG_EVENT); } } else { otherorder = longorder; @@ -3379,11 +3716,12 @@ void check_long_orders(unit *u) { } } -static void -setdefaults(unit *u) +static void setdefaults(unit * u) { order *ord; + boolean trade = false; + boolean hunger = LongHunger(u); freset(u, UFL_LONGACTION); @@ -3401,9 +3739,11 @@ setdefaults(unit *u) if (u->old_orders && is_repeated(ord)) { /* this new order will replace the old defaults */ free_orders(&u->old_orders); - if (hunger) break; + if (hunger) + break; } - if (hunger) continue; + if (hunger) + continue; if (is_exclusive(ord)) { /* Über dieser Zeile nur Befehle, die auch eine idle Faction machen darf */ @@ -3415,39 +3755,41 @@ setdefaults(unit *u) break; } else { keyword_t keyword = get_keyword(ord); + switch (keyword) { - /* Wenn gehandelt wird, darf kein langer Befehl ausgeführt - * werden. Da Handel erst nach anderen langen Befehlen kommt, - * muß das vorher abgefangen werden. Wir merken uns also - * hier, ob die Einheit handelt. */ - case K_BUY: - case K_SELL: - /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht - * werden. */ - trade = true; - break; - - case K_CAST: - /* dient dazu, das neben Zaubern kein weiterer Befehl - * ausgeführt werden kann, Zaubern ist ein kurzer Befehl */ - set_order(&u->thisorder, NULL); - break; - - case K_WEREWOLF: - set_order(&u->thisorder, copy_order(ord)); - break; - - /* Wird je diese Ausschliesslichkeit aufgehoben, muss man aufpassen - * mit der Reihenfolge von Kaufen, Verkaufen etc., damit es Spielern - * nicht moeglich ist, Schulden zu machen. */ + /* Wenn gehandelt wird, darf kein langer Befehl ausgeführt + * werden. Da Handel erst nach anderen langen Befehlen kommt, + * muß das vorher abgefangen werden. Wir merken uns also + * hier, ob die Einheit handelt. */ + case K_BUY: + case K_SELL: + /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht + * werden. */ + trade = true; + break; + + case K_CAST: + /* dient dazu, das neben Zaubern kein weiterer Befehl + * ausgeführt werden kann, Zaubern ist ein kurzer Befehl */ + set_order(&u->thisorder, NULL); + break; + + case K_WEREWOLF: + set_order(&u->thisorder, copy_order(ord)); + break; + + /* Wird je diese Ausschliesslichkeit aufgehoben, muss man aufpassen + * mit der Reihenfolge von Kaufen, Verkaufen etc., damit es Spielern + * nicht moeglich ist, Schulden zu machen. */ } } } - if (hunger) return; + if (hunger) + return; /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht - * werden. */ + * werden. */ if (trade == true) { /* fset(u, UFL_LONGACTION|UFL_NOTMOVING); */ @@ -3456,29 +3798,30 @@ setdefaults(unit *u) } static int -use_item(unit * u, const item_type * itype, int amount, struct order * ord) +use_item(unit * u, const item_type * itype, int amount, struct order *ord) { int i; + int target = read_unitid(u->faction, u->region); i = get_pooled(u, itype->rtype, GET_DEFAULT, amount); - if (amount>i) { + if (amount > i) { amount = i; } - if (amount==0) { + if (amount == 0) { cmistake(u, ord, 43, MSG_PRODUCE); return ENOITEM; } - if (target==-1) { - if (itype->use==NULL) { + if (target == -1) { + if (itype->use == NULL) { cmistake(u, ord, 76, MSG_PRODUCE); return EUNUSABLE; } return itype->use(u, itype, amount, ord); } else { - if (itype->useonother==NULL) { + if (itype->useonother == NULL) { cmistake(u, ord, 76, MSG_PRODUCE); return EUNUSABLE; } @@ -3487,19 +3830,20 @@ use_item(unit * u, const item_type * itype, int amount, struct order * ord) } -static double -heal_factor(const unit * u) +static double heal_factor(const unit * u) { static float elf_regen = -1; - switch(old_race(u->race)) { + + switch (old_race(u->race)) { case RC_TROLL: case RC_DAEMON: return 1.5; case RC_GOBLIN: return 2.0; case RC_ELF: - if (elf_regen<0) elf_regen = get_param_flt(u->race->parameters, "regen.forest", 1.0F); - if (elf_regen!=1.0 && r_isforest(u->region)) { + if (elf_regen < 0) + elf_regen = get_param_flt(u->race->parameters, "regen.forest", 1.0F); + if (elf_regen != 1.0 && r_isforest(u->region)) { return elf_regen; } return 1.0; @@ -3507,53 +3851,65 @@ heal_factor(const unit * u) return 1.0; } -static void -monthly_healing(void) +static void monthly_healing(void) { region *r; - static const curse_type * heal_ct = NULL; - if (heal_ct==NULL) heal_ct = ct_find("healingzone"); + + static const curse_type *heal_ct = NULL; + + if (heal_ct == NULL) + heal_ct = ct_find("healingzone"); for (r = regions; r; r = r->next) { unit *u; + double healingcurse = 0; - if (heal_ct!=NULL) { + if (heal_ct != NULL) { /* bonus zurücksetzen */ - curse * c = get_curse(r->attribs, heal_ct); - if (c!=NULL) { + curse *c = get_curse(r->attribs, heal_ct); + + if (c != NULL) { healingcurse = curse_geteffect(c); } } for (u = r->units; u; u = u->next) { int umhp = unit_max_hp(u) * u->number; + double p = 1.0; /* hp über Maximum bauen sich ab. Wird zb durch Elixier der Macht - * oder verändertes Ausdauertalent verursacht */ + * oder verändertes Ausdauertalent verursacht */ if (u->hp > umhp) { - u->hp -= (int) ceil((u->hp - umhp) / 2.0); - if (u->hp < umhp) u->hp = umhp; + u->hp -= (int)ceil((u->hp - umhp) / 2.0); + if (u->hp < umhp) + u->hp = umhp; continue; } - if (u->race->flags & RCF_NOHEAL) continue; - if (fval(u, UFL_HUNGER)) continue; + if (u->race->flags & RCF_NOHEAL) + continue; + if (fval(u, UFL_HUNGER)) + continue; - if (fval(r->terrain, SEA_REGION) && u->ship==NULL && !(canswim(u) || canfly(u))) { + if (fval(r->terrain, SEA_REGION) && u->ship == NULL && !(canswim(u) + || canfly(u))) { continue; } p *= heal_factor(u); if (u->hp < umhp) { #ifdef NEW_DAEMONHUNGER_RULE - double maxheal = MAX(u->number, umhp/20.0); + double maxheal = MAX(u->number, umhp / 20.0); #else - double maxheal = MAX(u->number, umhp/10.0); + double maxheal = MAX(u->number, umhp / 10.0); #endif int addhp; - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; + + struct building *b = inside_building(u); + + const struct building_type *btype = b ? b->type : NULL; + if (btype == bt_find("inn")) { p *= 1.5; } @@ -3563,7 +3919,8 @@ monthly_healing(void) maxheal = p * maxheal; addhp = (int)maxheal; maxheal -= addhp; - if (maxheal>0.0 && chance(maxheal)) ++addhp; + if (maxheal > 0.0 && chance(maxheal)) + ++addhp; /* Aufaddieren der geheilten HP. */ u->hp = MIN(u->hp + addhp, umhp); @@ -3575,11 +3932,11 @@ monthly_healing(void) } } -static void -remove_exclusive(order ** ordp) +static void remove_exclusive(order ** ordp) { while (*ordp) { - order * ord = *ordp; + order *ord = *ordp; + if (is_exclusive(ord)) { *ordp = ord->next; ord->next = NULL; @@ -3590,22 +3947,28 @@ remove_exclusive(order ** ordp) } } -static void -defaultorders (void) +static void defaultorders(void) { region *r; - for (r=regions;r;r=r->next) { + + for (r = regions; r; r = r->next) { unit *u; - for (u=r->units;u;u=u->next) { + + for (u = r->units; u; u = u->next) { boolean neworders = false; - order ** ordp = &u->orders; - while (*ordp!=NULL) { - order * ord = *ordp; - if (get_keyword(ord)==K_DEFAULT) { + + order **ordp = &u->orders; + + while (*ordp != NULL) { + order *ord = *ordp; + + if (get_keyword(ord) == K_DEFAULT) { char lbuf[8192]; - order * new_order; + + order *new_order; + init_tokens(ord); - skip_token(); /* skip the keyword */ + skip_token(); /* skip the keyword */ strcpy(lbuf, getstrtoken()); new_order = parse_order(lbuf, u->faction->locale); *ordp = ord->next; @@ -3616,11 +3979,12 @@ defaultorders (void) remove_exclusive(&u->orders); remove_exclusive(&u->old_orders); neworders = true; - ordp = &u->orders; /* we could have broken ordp */ + ordp = &u->orders; /* we could have broken ordp */ } - if (new_order) addlist(&u->old_orders, new_order); - } - else ordp = &ord->next; + if (new_order) + addlist(&u->old_orders, new_order); + } else + ordp = &ord->next; } } } @@ -3630,67 +3994,71 @@ defaultorders (void) /* GANZ WICHTIG! ALLE GEÄNDERTEN SPRÜCHE NEU ANZEIGEN */ /* GANZ WICHTIG! FÜGT AUCH NEUE ZAUBER IN DIE LISTE DER BEKANNTEN EIN */ /* ************************************************************ */ -#define MAXMAGES 128 /* should be enough */ -static void -update_spells(void) +#define MAXMAGES 128 /* should be enough */ +static void update_spells(void) { - faction * f; + faction *f; + + for (f = factions; f; f = f->next) { + if (f->magiegebiet != M_NONE && !is_monsters(f)) { + unit *mages[MAXMAGES]; - for (f=factions;f;f=f->next) { - if (f->magiegebiet!=M_NONE && !is_monsters(f)) { - unit * mages[MAXMAGES]; unit *u; + int maxlevel = 0, n = 0, i; - - for (u=f->units;u;u=u->nextF) { - if (u->number>0) { + + for (u = f->units; u; u = u->nextF) { + if (u->number > 0) { sc_mage *mage = get_mage(u); + if (mage) { int level = eff_skill(u, SK_MAGIC, u->region); - if (level>maxlevel) maxlevel = level; - assert(n maxlevel) + maxlevel = level; + assert(n < MAXMAGES); mages[n++] = u; } } } - if (FactionSpells() && maxlevel>f->max_spelllevel) { + if (FactionSpells() && maxlevel > f->max_spelllevel) { update_spellbook(f, maxlevel); } - for (i=0;i!=n;++i) { + for (i = 0; i != n; ++i) { updatespelllist(mages[i]); } } } } -static void -age_factions(void) +static void age_factions(void) { faction *f; for (f = factions; f; f = f->next) { ++f->age; - if (f->age+1 < NewbieImmunity()) { - ADDMSG(&f->msgs, msg_message("newbieimmunity", "turns", - NewbieImmunity() - f->age - 1)); + if (f->age + 1 < NewbieImmunity()) { + ADDMSG(&f->msgs, msg_message("newbieimmunity", "turns", + NewbieImmunity() - f->age - 1)); } } } -static int -use_cmd(unit * u, struct order * ord) +static int use_cmd(unit * u, struct order *ord) { - const char * t; + const char *t; + int n; - const item_type * itype; + + const item_type *itype; init_tokens(ord); skip_token(); t = getstrtoken(); n = atoi((const char *)t); - if (n==0) { + if (n == 0) { if (findparam(t, u->faction->locale) == P_ANY) { /* BENUTZE ALLES Yanxspirit */ n = INT_MAX; @@ -3705,31 +4073,34 @@ use_cmd(unit * u, struct order * ord) } itype = finditemtype(t, u->faction->locale); - if (itype!=NULL) { + if (itype != NULL) { int i = use_item(u, itype, n, ord); - assert(i<=0 || !"use_item should not return positive values."); - if (i>0) { - log_error(("use_item returned a value>0 for %s\n", resourcename(itype->rtype, 0))); - } + + assert(i <= 0 || !"use_item should not return positive values."); + if (i > 0) { + log_error(("use_item returned a value>0 for %s\n", + resourcename(itype->rtype, 0))); + } } else { cmistake(u, ord, 43, MSG_PRODUCE); } return 0; } -static int -pay_cmd(unit * u, struct order * ord) +static int pay_cmd(unit * u, struct order *ord) { if (!u->building) { cmistake(u, ord, 6, MSG_EVENT); } else { param_t p; + init_tokens(ord); skip_token(); p = getparam(u->faction->locale); - if (p==P_NOT) { - unit * owner = building_owner(u->building); - if (owner->faction!=u->faction) { + if (p == P_NOT) { + unit *owner = building_owner(u->building); + + if (owner->faction != u->faction) { cmistake(u, ord, 1222, MSG_EVENT); } else { u->building->flags |= BLD_DONTPAY; @@ -3739,28 +4110,30 @@ pay_cmd(unit * u, struct order * ord) return 0; } -static int -claim_cmd(unit * u, struct order * ord) +static int claim_cmd(unit * u, struct order *ord) { - const char * t; + const char *t; + int n; - const item_type * itype; + + const item_type *itype; init_tokens(ord); skip_token(); t = getstrtoken(); n = atoi((const char *)t); - if (n==0) { + if (n == 0) { n = 1; } else { t = getstrtoken(); } itype = finditemtype(t, u->faction->locale); - if (itype!=NULL) { - item ** iclaim = i_find(&u->faction->items, itype); - if (iclaim!=NULL && *iclaim!=NULL) { + if (itype != NULL) { + item **iclaim = i_find(&u->faction->items, itype); + + if (iclaim != NULL && *iclaim != NULL) { n = MIN(n, (*iclaim)->number); i_change(iclaim, itype, -n); i_change(&u->items, itype, n); @@ -3772,44 +4145,47 @@ claim_cmd(unit * u, struct order * ord) } enum { - PROC_THISORDER = 1<<0, - PROC_LONGORDER = 1<<1 + PROC_THISORDER = 1 << 0, + PROC_LONGORDER = 1 << 1 }; + typedef struct processor { - struct processor * next; + struct processor *next; int priority; enum { PR_GLOBAL, PR_REGION_PRE, PR_UNIT, PR_ORDER, PR_REGION_POST } type; unsigned int flags; union { struct { keyword_t kword; - int (*process)(struct unit *, struct order *); + int (*process) (struct unit *, struct order *); } per_order; struct { - void (*process)(struct unit *); + void (*process) (struct unit *); } per_unit; struct { - void (*process)(struct region *); + void (*process) (struct region *); } per_region; struct { - void (*process)(void); + void (*process) (void); } global; } data; - const char * name; + const char *name; } processor; -static processor * processors; +static processor *processors; -processor * -add_proc(int priority, const char * name, int type) +processor *add_proc(int priority, const char *name, int type) { processor **pproc = &processors; + processor *proc; while (*pproc) { proc = *pproc; - if (proc->priority>priority) break; - else if (proc->priority==priority && proc->type>=type) break; + if (proc->priority > priority) + break; + else if (proc->priority == priority && proc->type >= type) + break; pproc = &proc->next; } @@ -3823,10 +4199,12 @@ add_proc(int priority, const char * name, int type) } void -add_proc_order(int priority, keyword_t kword, int (*parser)(struct unit *, struct order *), unsigned int flags, const char * name) +add_proc_order(int priority, keyword_t kword, int (*parser) (struct unit *, + struct order *), unsigned int flags, const char *name) { if (!global.disabled[kword]) { - processor * proc = add_proc(priority, name, PR_ORDER); + processor *proc = add_proc(priority, name, PR_ORDER); + if (proc) { proc->data.per_order.process = parser; proc->data.per_order.kword = kword; @@ -3835,108 +4213,125 @@ add_proc_order(int priority, keyword_t kword, int (*parser)(struct unit *, struc } } -void -add_proc_global(int priority, void (*process)(void), const char * name) +void add_proc_global(int priority, void (*process) (void), const char *name) { - processor * proc = add_proc(priority, name, PR_GLOBAL); + processor *proc = add_proc(priority, name, PR_GLOBAL); + if (proc) { proc->data.global.process = process; } } -void -add_proc_region(int priority, void (*process)(region *), const char * name) +void add_proc_region(int priority, void (*process) (region *), const char *name) { - processor * proc = add_proc(priority, name, PR_REGION_PRE); + processor *proc = add_proc(priority, name, PR_REGION_PRE); + if (proc) { proc->data.per_region.process = process; } } void -add_proc_postregion(int priority, void (*process)(region *), const char * name) +add_proc_postregion(int priority, void (*process) (region *), const char *name) { - processor * proc = add_proc(priority, name, PR_REGION_POST); + processor *proc = add_proc(priority, name, PR_REGION_POST); + if (proc) { proc->data.per_region.process = process; } } -void -add_proc_unit(int priority, void (*process)(unit *), const char * name) +void add_proc_unit(int priority, void (*process) (unit *), const char *name) { - processor * proc = add_proc(priority, name, PR_UNIT); + processor *proc = add_proc(priority, name, PR_UNIT); + if (proc) { proc->data.per_unit.process = process; } } /* per priority, execute processors in order from PR_GLOBAL down to PR_ORDER */ -void -process(void) +void process(void) { processor *proc = processors; - faction * f; + + faction *f; while (proc) { int prio = proc->priority; + region *r; + processor *pglobal = proc; - if (verbosity>=3) printf("- Step %u\n", prio); - while (proc && proc->priority==prio) { - if (proc->name && verbosity>=1) log_stdio(stdout, " - %s\n", proc->name); + if (verbosity >= 3) + printf("- Step %u\n", prio); + while (proc && proc->priority == prio) { + if (proc->name && verbosity >= 1) + log_stdio(stdout, " - %s\n", proc->name); proc = proc->next; } - while (pglobal && pglobal->priority==prio && pglobal->type==PR_GLOBAL) { + while (pglobal && pglobal->priority == prio && pglobal->type == PR_GLOBAL) { pglobal->data.global.process(); + pglobal = pglobal->next; } - if (pglobal==NULL || pglobal->priority!=prio) continue; + if (pglobal == NULL || pglobal->priority != prio) + continue; for (r = regions; r; r = r->next) { unit *u; + processor *pregion = pglobal; - while (pregion && pregion->priority==prio && pregion->type==PR_REGION_PRE) { + while (pregion && pregion->priority == prio + && pregion->type == PR_REGION_PRE) { pregion->data.per_region.process(r); pregion = pregion->next; } - if (pregion==NULL || pregion->priority!=prio) continue; + if (pregion == NULL || pregion->priority != prio) + continue; if (r->units) { - for (u=r->units;u;u=u->next) { + for (u = r->units; u; u = u->next) { processor *porder, *punit = pregion; - while (punit && punit->priority==prio && punit->type==PR_UNIT) { + while (punit && punit->priority == prio && punit->type == PR_UNIT) { punit->data.per_unit.process(u); punit = punit->next; } - if (punit==NULL || punit->priority!=prio) continue; + if (punit == NULL || punit->priority != prio) + continue; porder = punit; - while (porder && porder->priority==prio && porder->type==PR_ORDER) { - order ** ordp = &u->orders; + while (porder && porder->priority == prio && porder->type == PR_ORDER) { + order **ordp = &u->orders; + if (porder->flags & PROC_THISORDER) - ordp = &u->thisorder; + ordp = &u->thisorder; while (*ordp) { - order * ord = *ordp; + order *ord = *ordp; + if (get_keyword(ord) == porder->data.per_order.kword) { if (porder->flags & PROC_LONGORDER) { - if (u->number==0) { + if (u->number == 0) { ord = NULL; - } else if (u->race == new_race[RC_INSECT] && r_insectstalled(r) && !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) { + } else if (u->race == new_race[RC_INSECT] + && r_insectstalled(r) + && !is_cursed(u->attribs, C_KAELTESCHUTZ, 0)) { ord = NULL; } else if (LongHunger(u)) { cmistake(u, ord, 224, MSG_MAGIC); ord = NULL; } else if (fval(u, UFL_LONGACTION)) { /* this message was already given in laws.setdefaults - cmistake(u, ord, 52, MSG_PRODUCE); - */ + cmistake(u, ord, 52, MSG_PRODUCE); + */ ord = NULL; - } else if (fval(r->terrain, SEA_REGION) && u->race != new_race[RC_AQUARIAN] && !(u->race->flags & RCF_SWIM)) { + } else if (fval(r->terrain, SEA_REGION) + && u->race != new_race[RC_AQUARIAN] + && !(u->race->flags & RCF_SWIM)) { /* error message disabled by popular demand */ ord = NULL; } @@ -3945,32 +4340,39 @@ process(void) porder->data.per_order.process(u, ord); } } - if (!ord || *ordp==ord) ordp=&(*ordp)->next; + if (!ord || *ordp == ord) + ordp = &(*ordp)->next; } porder = porder->next; } } } - while (pregion && pregion->priority==prio && pregion->type!=PR_REGION_POST) { + while (pregion && pregion->priority == prio + && pregion->type != PR_REGION_POST) { pregion = pregion->next; } - while (pregion && pregion->priority==prio && pregion->type==PR_REGION_POST) { + while (pregion && pregion->priority == prio + && pregion->type == PR_REGION_POST) { pregion->data.per_region.process(r); pregion = pregion->next; } - if (pregion==NULL || pregion->priority!=prio) continue; + if (pregion == NULL || pregion->priority != prio) + continue; } } - if (verbosity>=3) printf("\n - Leere Gruppen loeschen...\n"); - for (f=factions; f; f=f->next) { - group ** gp = &f->groups; + if (verbosity >= 3) + printf("\n - Leere Gruppen loeschen...\n"); + for (f = factions; f; f = f->next) { + group **gp = &f->groups; + while (*gp) { - group * g = *gp; - if (g->members==0) { + group *g = *gp; + + if (g->members == 0) { *gp = g->next; free_group(g); } else @@ -3980,13 +4382,31 @@ process(void) } -static void enter_1(region * r) { do_misc(r, false); } -static void enter_2(region * r) { do_misc(r, true); } -static void maintain_buildings_1(region * r) { maintain_buildings(r, false); } +static void enter_1(region * r) +{ + do_misc(r, false); +} + +static void enter_2(region * r) +{ + do_misc(r, true); +} + +static void maintain_buildings_1(region * r) +{ + maintain_buildings(r, false); +} + #ifdef COLLAPSE_CHANCE -static void maintain_buildings_2(region * r) { maintain_buildings(r,true); } +static void maintain_buildings_2(region * r) +{ + maintain_buildings(r, true); +} #endif -static void reset_moved(unit * u) { freset(u, UFL_MOVED); } +static void reset_moved(unit * u) +{ + freset(u, UFL_MOVED); +} /** warn about passwords that are not US ASCII. * even though passwords are technically UTF8 strings, the server receives @@ -3994,15 +4414,18 @@ static void reset_moved(unit * u) { freset(u, UFL_MOVED); } * This means that we need to limit them to ASCII characters until that * mechanism has been changed. */ -static int -warn_password(void) +static int warn_password(void) { - faction * f = factions; + faction *f = factions; + while (f) { boolean pwok = true; - const char * c = f->passw; + + const char *c = f->passw; + while (*c && pwok) { - if (!isalnum((unsigned char)*c)) pwok = false; + if (!isalnum((unsigned char)*c)) + pwok = false; c++; } if (!pwok) { @@ -4015,15 +4438,14 @@ warn_password(void) return 0; } -void -init_processor(void) +void init_processor(void) { int p; p = 10; add_proc_global(p, &new_units, "Neue Einheiten erschaffen"); - p+=10; + p += 10; add_proc_unit(p, &setdefaults, "Default-Befehle"); add_proc_order(p, K_BANNER, &banner_cmd, 0, NULL); add_proc_order(p, K_EMAIL, &email_cmd, 0, NULL); @@ -4031,7 +4453,7 @@ init_processor(void) add_proc_order(p, K_SEND, &send_cmd, 0, NULL); add_proc_order(p, K_GROUP, &group_cmd, 0, NULL); - p+=10; + p += 10; add_proc_unit(p, &reset_moved, "Instant-Befehle"); add_proc_order(p, K_QUIT, &quit_cmd, 0, NULL); add_proc_order(p, K_URSPRUNG, &origin_cmd, 0, NULL); @@ -4045,16 +4467,16 @@ init_processor(void) add_proc_order(p, K_GUARD, &guard_off_cmd, 0, NULL); add_proc_order(p, K_RESHOW, &reshow_cmd, 0, NULL); - if (get_param_int(global.parameters, "rules.alliances", 0)==1) { - p+=10; + if (get_param_int(global.parameters, "rules.alliances", 0) == 1) { + p += 10; add_proc_global(p, &alliance_cmd, NULL); } - p+=10; + p += 10; add_proc_global(p, &age_factions, "Parteienalter++"); add_proc_order(p, K_MAIL, &mail_cmd, 0, "Botschaften"); - p+=10; /* all claims must be done before we can USE */ + p += 10; /* all claims must be done before we can USE */ add_proc_region(p, &enter_1, "Kontaktieren & Betreten (1. Versuch)"); add_proc_order(p, K_USE, &use_cmd, 0, "Benutzen"); @@ -4062,10 +4484,10 @@ init_processor(void) add_proc_global(p, &gmcommands, "GM Kommandos"); } - p += 10; /* in case it has any effects on alliance victories */ + p += 10; /* in case it has any effects on alliance victories */ add_proc_order(p, K_GIVE, &give_control_cmd, 0, "GIB KOMMANDO"); - p += 10; /* in case it has any effects on alliance victories */ + p += 10; /* in case it has any effects on alliance victories */ add_proc_order(p, K_LEAVE, &leave_cmd, 0, "Verlassen"); if (!nobattle) { @@ -4073,76 +4495,81 @@ init_processor(void) } if (!global.disabled[K_BESIEGE]) { - p+=10; + p += 10; add_proc_region(p, &do_siege, "Belagern"); } - p+=10; /* can't allow reserve before siege (weapons) */ + p += 10; /* can't allow reserve before siege (weapons) */ add_proc_region(p, &enter_1, "Kontaktieren & Betreten (2. Versuch)"); add_proc_order(p, K_RESERVE, &reserve_cmd, 0, "Reservieren"); add_proc_order(p, K_CLAIM, &claim_cmd, 0, NULL); add_proc_unit(p, &follow_unit, "Folge auf Einheiten setzen"); - p+=10; /* rest rng again before economics */ + p += 10; /* rest rng again before economics */ add_proc_region(p, &economics, "Zerstoeren, Geben, Rekrutieren, Vergessen"); - p+=10; + p += 10; if (!global.disabled[K_PAY]) { add_proc_order(p, K_PAY, &pay_cmd, 0, "Gebaeudeunterhalt (disable)"); } - add_proc_postregion(p, &maintain_buildings_1, "Gebaeudeunterhalt (1. Versuch)"); + add_proc_postregion(p, &maintain_buildings_1, + "Gebaeudeunterhalt (1. Versuch)"); - p+=10; /* QUIT fuer sich alleine */ + p += 10; /* QUIT fuer sich alleine */ add_proc_global(p, &quit, "Sterben"); if (!global.disabled[K_RESTART]) { add_proc_global(p, &parse_restart, "Neustart"); } if (!global.disabled[K_CAST]) { - p+=10; + p += 10; add_proc_global(p, &magic, "Zaubern"); } - p+=10; - add_proc_order(p, K_TEACH, &teach_cmd, PROC_THISORDER|PROC_LONGORDER, "Lehren"); - p+=10; - add_proc_order(p, K_STUDY, &learn_cmd, PROC_THISORDER|PROC_LONGORDER, "Lernen"); + p += 10; + add_proc_order(p, K_TEACH, &teach_cmd, PROC_THISORDER | PROC_LONGORDER, + "Lehren"); + p += 10; + add_proc_order(p, K_STUDY, &learn_cmd, PROC_THISORDER | PROC_LONGORDER, + "Lernen"); - p+=10; - add_proc_order(p, K_MAKE, &make_cmd, PROC_THISORDER|PROC_LONGORDER, "Produktion"); + p += 10; + add_proc_order(p, K_MAKE, &make_cmd, PROC_THISORDER | PROC_LONGORDER, + "Produktion"); add_proc_postregion(p, &produce, "Arbeiten, Handel, Rekruten"); add_proc_postregion(p, &split_allocations, "Produktion II"); - p+=10; + p += 10; add_proc_region(p, &enter_2, "Kontaktieren & Betreten (3. Versuch)"); - p+=10; + p += 10; add_proc_region(p, &sinkships, "Schiffe sinken"); - p+=10; + p += 10; add_proc_global(p, &movement, "Bewegungen"); if (get_param_int(global.parameters, "work.auto", 0)) { - p+=10; + p += 10; add_proc_region(p, &auto_work, "Arbeiten (auto)"); } - p+=10; + p += 10; add_proc_order(p, K_GUARD, &guard_on_cmd, 0, "Bewache (an)"); #if XECMD_MODULE /* can do together with guard */ add_proc_order(p, K_XE, &xecmd, 0, "Zeitung"); #endif - p+=10; + p += 10; add_proc_global(p, &encounters, "Zufallsbegegnungen"); - p+=10; - add_proc_unit(p, &monster_kills_peasants, "Monster fressen und vertreiben Bauern"); + p += 10; + add_proc_unit(p, &monster_kills_peasants, + "Monster fressen und vertreiben Bauern"); - p+=10; + p += 10; add_proc_global(p, &randomevents, "Zufallsereignisse"); - p+=10; + p += 10; add_proc_global(p, &monthly_healing, "Regeneration (HP)"); add_proc_global(p, ®eneration_magiepunkte, "Regeneration (Aura)"); @@ -4152,24 +4579,23 @@ init_processor(void) add_proc_global(p, &demographics, "Nahrung, Seuchen, Wachstum, Wanderung"); #ifdef COLLAPSE_CHANCE - p+=10; + p += 10; add_proc_region(p, &maintain_buildings_2, "Gebaeudeunterhalt (2. Versuch)"); #endif if (!global.disabled[K_SORT]) { - p+=10; + p += 10; add_proc_global(p, &reorder, "Einheiten sortieren"); } add_proc_order(p, K_PROMOTION, &promotion_cmd, 0, "Heldenbefoerderung"); if (!global.disabled[K_NUMBER]) { add_proc_order(p, K_NUMBER, &renumber_cmd, 0, "Neue Nummern (Einheiten)"); - p+=10; + p += 10; add_proc_global(p, &renumber_factions, "Neue Nummern"); } } -void -processorders (void) +void processorders(void) { static int init = 0; @@ -4185,7 +4611,8 @@ processorders (void) do_markets(); } - if (verbosity>=1) puts(" - Attribute altern"); + if (verbosity >= 1) + puts(" - Attribute altern"); ageing(); remove_empty_units(); @@ -4200,16 +4627,17 @@ processorders (void) warn_password(); } -int -writepasswd(void) +int writepasswd(void) { - FILE * F; + FILE *F; + char zText[128]; sprintf(zText, "%s/passwd", basepath()); F = cfopen(zText, "w"); if (F) { faction *f; + puts("writing passwords..."); for (f = factions; f; f = f->next) { @@ -4222,33 +4650,38 @@ writepasswd(void) return 1; } -void -update_subscriptions(void) +void update_subscriptions(void) { - FILE * F; + FILE *F; + char zText[MAX_PATH]; - faction * f; + + faction *f; + strcat(strcpy(zText, basepath()), "/subscriptions"); F = fopen(zText, "r"); - if (F==NULL) { + if (F == NULL) { log_warning((0, "could not open %s.\n", zText)); return; } for (;;) { char zFaction[5]; + int subscription, fno; - if (fscanf(F, "%d %s", &subscription, zFaction)<=0) break; + + if (fscanf(F, "%d %s", &subscription, zFaction) <= 0) + break; fno = atoi36(zFaction); f = findfaction(fno); - if (f!=NULL) { - f->subscription=subscription; + if (f != NULL) { + f->subscription = subscription; } } fclose(F); sprintf(zText, "subscriptions.%u", turn); F = fopen(zText, "w"); - for (f=factions;f!=NULL;f=f->next) { + for (f = factions; f != NULL; f = f->next) { fprintf(F, "%s:%u:%s:%s:%s:%u:\n", itoa36(f->no), f->subscription, f->email, f->override, dbrace(f->race), f->lastorders); @@ -4256,18 +4689,18 @@ update_subscriptions(void) fclose(F); } -int -init_data(const char * filename, const char * catalog) +int init_data(const char *filename, const char *catalog) { int l; l = read_xml(filename, catalog); - if (l) return l; + if (l) + return l; init_locales(); init_archetypes(); - if (turn<0) { + if (turn < 0) { turn = first_turn; } return 0; diff --git a/src/gamecode/laws.h b/src/gamecode/laws.h index 5aa7d6f94..83e3bacc6 100644 --- a/src/gamecode/laws.h +++ b/src/gamecode/laws.h @@ -22,26 +22,26 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern int writepasswd(void); -int getoption(void); -int wanderoff(struct region * r, int p); -void demographics(void); -void last_orders(void); -void find_address(void); -void update_guards(void); -void update_subscriptions(void); -void deliverMail(struct faction * f, struct region * r, struct unit * u, const char *s, struct unit * receiver); -int init_data(const char * filename, const char * catalog); + extern int writepasswd(void); + int getoption(void); + int wanderoff(struct region *r, int p); + void demographics(void); + void last_orders(void); + void find_address(void); + void update_guards(void); + void update_subscriptions(void); + void deliverMail(struct faction *f, struct region *r, struct unit *u, + const char *s, struct unit *receiver); + int init_data(const char *filename, const char *catalog); /* eressea-specific. put somewhere else, please. */ -void processorders(void); -extern struct attrib_type at_germs; + void processorders(void); + extern struct attrib_type at_germs; -extern int dropouts[2]; -extern int * age; + extern int dropouts[2]; + extern int *age; #ifdef __cplusplus } #endif - #endif diff --git a/src/gamecode/laws_test.c b/src/gamecode/laws_test.c index c45719ec5..fdba5fdc0 100644 --- a/src/gamecode/laws_test.c +++ b/src/gamecode/laws_test.c @@ -3,10 +3,13 @@ **/ #include -static void test_new_building_can_be_renamed(CuTest * tc) { - region * r; - building * b; - building_type * btype; +static void test_new_building_can_be_renamed(CuTest * tc) +{ + region *r; + + building *b; + + building_type *btype; test_cleanup(); test_create_world(); @@ -18,12 +21,17 @@ static void test_new_building_can_be_renamed(CuTest * tc) { CuAssertTrue(tc, !renamed_building(b)); } -static void test_rename_building(CuTest * tc) { - region * r; - building * b; - unit * u; - faction * f; - building_type * btype; +static void test_rename_building(CuTest * tc) +{ + region *r; + + building *b; + + unit *u; + + faction *f; + + building_type *btype; test_cleanup(); test_create_world(); @@ -41,12 +49,17 @@ static void test_rename_building(CuTest * tc) { CuAssertStrEquals(tc, "Villa Nagel", b->name); } -static void test_rename_building_twice(CuTest * tc) { - region * r; - building * b; - unit * u; - faction * f; - building_type * btype; +static void test_rename_building_twice(CuTest * tc) +{ + region *r; + + building *b; + + unit *u; + + faction *f; + + building_type *btype; test_cleanup(); test_create_world(); @@ -67,16 +80,20 @@ static void test_rename_building_twice(CuTest * tc) { CuAssertStrEquals(tc, "Villa Kunterbunt", b->name); } -static void test_fishing_feeds_2_people(CuTest * tc) { - region * r; - faction * f; - unit * u; - ship * sh; +static void test_fishing_feeds_2_people(CuTest * tc) +{ + region *r; + + faction *f; + + unit *u; + + ship *sh; test_cleanup(); test_create_world(); r = findregion(-1, 0); - CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ + CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ f = test_create_faction(rc_find("human")); u = test_create_unit(f, r); sh = new_ship(st_find("boat"), NULL, r); @@ -100,21 +117,26 @@ static void test_fishing_feeds_2_people(CuTest * tc) { } -static int not_so_hungry(const unit * u) { +static int not_so_hungry(const unit * u) +{ return 6 * u->number; } -static void test_fishing_does_not_give_goblins_money(CuTest * tc) { - region * r; - faction * f; - unit * u; - ship * sh; +static void test_fishing_does_not_give_goblins_money(CuTest * tc) +{ + region *r; + + faction *f; + + unit *u; + + ship *sh; test_cleanup(); test_create_world(); r = findregion(-1, 0); - CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ + CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ f = test_create_faction(rc_find("human")); u = test_create_unit(f, r); sh = new_ship(st_find("boat"), NULL, r); @@ -122,6 +144,7 @@ static void test_fishing_does_not_give_goblins_money(CuTest * tc) { i_change(&u->items, it_find("money"), 42); global.functions.maintenance = not_so_hungry; + scale_number(u, 2); sh->flags |= SF_FISHING; get_food(r); @@ -129,16 +152,20 @@ static void test_fishing_does_not_give_goblins_money(CuTest * tc) { } -static void test_fishing_gets_reset(CuTest * tc) { - region * r; - faction * f; - unit * u; - ship * sh; +static void test_fishing_gets_reset(CuTest * tc) +{ + region *r; + + faction *f; + + unit *u; + + ship *sh; test_cleanup(); test_create_world(); r = findregion(-1, 0); - CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ + CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ f = test_create_faction(rc_find("human")); u = test_create_unit(f, r); sh = new_ship(st_find("boat"), NULL, r); @@ -156,21 +183,27 @@ static void test_fishing_gets_reset(CuTest * tc) { } -static void test_unit_limit(CuTest * tc) { +static void test_unit_limit(CuTest * tc) +{ set_param(&global.parameters, "rules.limit.faction", "250"); + CuAssertIntEquals(tc, 250, rule_faction_limit()); set_param(&global.parameters, "rules.limit.faction", "200"); + CuAssertIntEquals(tc, 200, rule_faction_limit()); set_param(&global.parameters, "rules.limit.alliance", "250"); + CuAssertIntEquals(tc, 250, rule_alliance_limit()); } -extern int checkunitnumber(const faction *f, int add); -static void test_cannot_create_unit_above_limit(CuTest * tc) { - faction * f; +extern int checkunitnumber(const faction * f, int add); + +static void test_cannot_create_unit_above_limit(CuTest * tc) +{ + faction *f; test_cleanup(); test_create_world(); @@ -181,14 +214,16 @@ static void test_cannot_create_unit_above_limit(CuTest * tc) { CuAssertIntEquals(tc, 2, checkunitnumber(f, 5)); set_param(&global.parameters, "rules.limit.alliance", "3"); + CuAssertIntEquals(tc, 0, checkunitnumber(f, 3)); CuAssertIntEquals(tc, 1, checkunitnumber(f, 4)); } -CuSuite* get_laws_suite(void) +CuSuite *get_laws_suite(void) { - CuSuite* suite = CuSuiteNew(); + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, &test_new_building_can_be_renamed); SUITE_ADD_TEST(suite, &test_rename_building); SUITE_ADD_TEST(suite, &test_rename_building_twice); diff --git a/src/gamecode/market.c b/src/gamecode/market.c index 2f0f3ba2c..c247374fa 100644 --- a/src/gamecode/market.c +++ b/src/gamecode/market.c @@ -30,21 +30,29 @@ without prior permission by the authors of Eressea. #include -static unsigned int -get_markets(region * r, unit ** results, size_t size) +static unsigned int get_markets(region * r, unit ** results, size_t size) { unsigned int n = 0; - building * b; - static building_type * btype; - if (!btype) btype = bt_find("market"); - if (!btype) return 0; - for (b=r->buildings;nnext) { - if (b->type==btype && (b->flags&BLD_WORKING) && b->size>=b->type->maxsize) { - unit * u = building_owner(b); + + building *b; + + static building_type *btype; + + if (!btype) + btype = bt_find("market"); + if (!btype) + return 0; + for (b = r->buildings; n < size && b; b = b->next) { + if (b->type == btype && (b->flags & BLD_WORKING) + && b->size >= b->type->maxsize) { + unit *u = building_owner(b); + unsigned int i; - for (i=0;u && i!=n;++i) { + + for (i = 0; u && i != n; ++i) { /* only one market per faction */ - if (results[i]->faction==u->faction) u = NULL; + if (results[i]->faction == u->faction) + u = NULL; } if (u) { results[n++] = u; @@ -55,10 +63,10 @@ get_markets(region * r, unit ** results, size_t size) } -static void -free_market(attrib * a) +static void free_market(attrib * a) { - item * items = (item *)a->data.v; + item *items = (item *) a->data.v; + i_freeall(&items); a->data.v = 0; } @@ -69,7 +77,7 @@ attrib_type at_market = { NULL, NULL, ATF_UNIQUE }; -static int rc_luxury_trade(const struct race * rc) +static int rc_luxury_trade(const struct race *rc) { if (rc) { return get_param_int(rc->parameters, "luxury_trade", 1000); @@ -77,7 +85,7 @@ static int rc_luxury_trade(const struct race * rc) return 1000; } -static int rc_herb_trade(const struct race * rc) +static int rc_herb_trade(const struct race *rc) { if (rc) { return get_param_int(rc->parameters, "herb_trade", 500); @@ -86,58 +94,77 @@ static int rc_herb_trade(const struct race * rc) } #define MAX_MARKETS 128 -#define MIN_PEASANTS 50 /* if there are at least this many peasants, you will get 1 good */ +#define MIN_PEASANTS 50 /* if there are at least this many peasants, you will get 1 good */ void do_markets(void) { - quicklist * traders = 0; - unit * markets[MAX_MARKETS]; - region * r; - for (r=regions;r;r=r->next) { - if (r->land) { - faction * f = region_get_owner(r); - const struct race * rc = f?f->race:NULL; - int p = rpeasants(r); - int numlux = rc_luxury_trade(rc), numherbs = rc_herb_trade(rc); - numlux = (p+numlux-MIN_PEASANTS)/numlux; - numherbs = (p+numherbs-MIN_PEASANTS)/numherbs; - if (numlux>0 || numherbs>0) { - int d, nmarkets = 0; - const item_type * lux = r_luxury(r); - const item_type * herb = r->land->herbtype; + quicklist *traders = 0; + + unit *markets[MAX_MARKETS]; + + region *r; + + for (r = regions; r; r = r->next) { + if (r->land) { + faction *f = region_get_owner(r); + + const struct race *rc = f ? f->race : NULL; + + int p = rpeasants(r); + + int numlux = rc_luxury_trade(rc), numherbs = rc_herb_trade(rc); + + numlux = (p + numlux - MIN_PEASANTS) / numlux; + numherbs = (p + numherbs - MIN_PEASANTS) / numherbs; + if (numlux > 0 || numherbs > 0) { + int d, nmarkets = 0; + + const item_type *lux = r_luxury(r); + + const item_type *herb = r->land->herbtype; + + nmarkets += get_markets(r, markets + nmarkets, MAX_MARKETS - nmarkets); + for (d = 0; d != MAXDIRECTIONS; ++d) { + region *r2 = rconnect(r, d); - nmarkets += get_markets(r, markets+nmarkets, MAX_MARKETS-nmarkets); - for (d=0;d!=MAXDIRECTIONS;++d) { - region * r2 = rconnect(r, d); if (r2 && r2->buildings) { - nmarkets += get_markets(r2, markets+nmarkets, MAX_MARKETS-nmarkets); + nmarkets += + get_markets(r2, markets + nmarkets, MAX_MARKETS - nmarkets); } } if (nmarkets) { while (lux && numlux--) { int n = rng_int() % nmarkets; - unit * u = markets[n]; - item * items; - attrib * a = a_find(u->attribs, &at_market); - if (a==NULL) { + + unit *u = markets[n]; + + item *items; + + attrib *a = a_find(u->attribs, &at_market); + + if (a == NULL) { a = a_add(&u->attribs, a_new(&at_market)); ql_push(&traders, u); } - items = (item *)a->data.v; + items = (item *) a->data.v; i_change(&items, lux, 1); a->data.v = items; /* give 1 luxury */ } while (herb && numherbs--) { int n = rng_int() % nmarkets; - unit * u = markets[n]; - item * items; - attrib * a = a_find(u->attribs, &at_market); - if (a==NULL) { + + unit *u = markets[n]; + + item *items; + + attrib *a = a_find(u->attribs, &at_market); + + if (a == NULL) { a = a_add(&u->attribs, a_new(&at_market)); ql_push(&traders, u); } - items = (item *)a->data.v; + items = (item *) a->data.v; i_change(&items, herb, 1); a->data.v = items; /* give 1 herb */ @@ -148,21 +175,26 @@ void do_markets(void) } if (traders) { - quicklist * qliter = traders; + quicklist *qliter = traders; + int qli = 0; - for (qli=0;qliter;ql_advance(&qliter, &qli, 1)) { - unit * u = (unit *)ql_get(qliter, qli); - attrib * a = a_find(u->attribs, &at_market); - item * items = (item *)a->data.v; + + for (qli = 0; qliter; ql_advance(&qliter, &qli, 1)) { + unit *u = (unit *) ql_get(qliter, qli); + + attrib *a = a_find(u->attribs, &at_market); + + item *items = (item *) a->data.v; a->data.v = NULL; while (items) { - item * itm = items; + item *itm = items; + items = itm->next; if (itm->number) { ADDMSG(&u->faction->msgs, msg_message("buyamount", - "unit amount resource", u, itm->number, itm->type->rtype)); + "unit amount resource", u, itm->number, itm->type->rtype)); itm->next = NULL; i_add(&u->items, itm); } else { diff --git a/src/gamecode/market_test.c b/src/gamecode/market_test.c index 6b993dc83..f82651ec4 100644 --- a/src/gamecode/market_test.c +++ b/src/gamecode/market_test.c @@ -3,22 +3,35 @@ #include #include -static void market_curse(CuTest * tc) { - region * r; - building * b; - unit * u; - faction * f; +static void market_curse(CuTest * tc) +{ + region *r; + + building *b; + + unit *u; + + faction *f; + int x, y; - const char * names[4] = { "herb", "herbs", "balm", "balms" }; - terrain_type * terrain; - resource_type * hres = new_resourcetype(names, 0, RTF_ITEM|RTF_POOLED); - item_type * htype = new_itemtype(hres, ITF_HERB, 0, 0); - resource_type * lres = new_resourcetype(names+2, 0, RTF_ITEM|RTF_POOLED); - item_type * ltype = new_itemtype(lres, ITF_NONE, 0, 0); - luxury_type * lux = new_luxurytype(ltype, 0); - building_type * btype; - race * rc = rc_add(rc_new("human")); - struct locale * lang = make_locale("en"); + const char *names[4] = { "herb", "herbs", "balm", "balms" }; + terrain_type *terrain; + + resource_type *hres = new_resourcetype(names, 0, RTF_ITEM | RTF_POOLED); + + item_type *htype = new_itemtype(hres, ITF_HERB, 0, 0); + + resource_type *lres = new_resourcetype(names + 2, 0, RTF_ITEM | RTF_POOLED); + + item_type *ltype = new_itemtype(lres, ITF_NONE, 0, 0); + + luxury_type *lux = new_luxurytype(ltype, 0); + + building_type *btype; + + race *rc = rc_add(rc_new("human")); + + struct locale *lang = make_locale("en"); free_gamedata(); @@ -31,10 +44,10 @@ static void market_curse(CuTest * tc) { terrain = calloc(1, sizeof(terrain_type)); terrain->_name = strdup("plain"); register_terrain(terrain); - terrain->flags = LAND_REGION|WALK_INTO; + terrain->flags = LAND_REGION | WALK_INTO; - for (x=0;x!=3;++x) { - for (y=0;y!=3;++y) { + for (x = 0; x != 3; ++x) { + for (y = 0; y != 3; ++y) { r = new_region(x, y, NULL, 0); terraform_region(r, terrain); rsetpeasants(r, 5000); @@ -58,9 +71,10 @@ static void market_curse(CuTest * tc) { CuAssertIntEquals(tc, 35, i_get(u->items, ltype)); } -CuSuite* get_market_suite(void) +CuSuite *get_market_suite(void) { - CuSuite* suite = CuSuiteNew(); + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, market_curse); return suite; } diff --git a/src/gamecode/monster.c b/src/gamecode/monster.c index 50436a947..dad941f93 100644 --- a/src/gamecode/monster.c +++ b/src/gamecode/monster.c @@ -66,44 +66,45 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -#define MOVECHANCE 25 /* chance fuer bewegung */ +#define MOVECHANCE 25 /* chance fuer bewegung */ #define MAXILLUSION_TEXTS 3 -boolean -monster_is_waiting(const unit * u) +boolean monster_is_waiting(const unit * u) { - if (fval(u, UFL_ISNEW|UFL_MOVED)) return true; + if (fval(u, UFL_ISNEW | UFL_MOVED)) + return true; return false; } -static void -eaten_by_monster(unit * u) +static void eaten_by_monster(unit * u) { /* adjustment for smaller worlds */ static double multi = 0.0; + int n = 0; + int horse = 0; - if (multi==0.0) { + if (multi == 0.0) { multi = RESOURCE_QUANTITY * newterrain(T_PLAIN)->size / 10000.0; } switch (old_race(u->race)) { case RC_FIREDRAGON: - n = rng_int()%80 * u->number; + n = rng_int() % 80 * u->number; horse = get_item(u, I_HORSE); break; case RC_DRAGON: - n = rng_int()%200 * u->number; + n = rng_int() % 200 * u->number; horse = get_item(u, I_HORSE); break; case RC_WYRM: - n = rng_int()%500 * u->number; + n = rng_int() % 500 * u->number; horse = get_item(u, I_HORSE); break; default: - n = rng_int()%(u->number/20+1); + n = rng_int() % (u->number / 20 + 1); } n = (int)(n * multi); @@ -123,40 +124,39 @@ eaten_by_monster(unit * u) } } -static void -absorbed_by_monster(unit * u) +static void absorbed_by_monster(unit * u) { int n; switch (old_race(u->race)) { default: - n = rng_int()%(u->number/20+1); + n = rng_int() % (u->number / 20 + 1); } - if(n > 0) { + if (n > 0) { n = lovar(n); n = MIN(rpeasants(u->region), n); - if (n > 0){ + if (n > 0) { rsetpeasants(u->region, rpeasants(u->region) - n); scale_number(u, u->number + n); - ADDMSG(&u->region->msgs, msg_message("absorbpeasants", - "unit race amount", u, u->race, n)); + ADDMSG(&u->region->msgs, msg_message("absorbpeasants", + "unit race amount", u, u->race, n)); } } } -static int -scareaway(region * r, int anzahl) +static int scareaway(region * r, int anzahl) { int n, p, diff = 0, emigrants[MAXDIRECTIONS]; + direction_t d; - anzahl = MIN(MAX(1, anzahl),rpeasants(r)); + anzahl = MIN(MAX(1, anzahl), rpeasants(r)); /* Wandern am Ende der Woche (normal) oder wegen Monster. Die - * Wanderung wird erst am Ende von demographics () ausgefuehrt. - * emigrants[] ist local, weil r->newpeasants durch die Monster - * vielleicht schon hochgezaehlt worden ist. */ + * Wanderung wird erst am Ende von demographics () ausgefuehrt. + * emigrants[] ist local, weil r->newpeasants durch die Monster + * vielleicht schon hochgezaehlt worden ist. */ for (d = 0; d != MAXDIRECTIONS; d++) emigrants[d] = 0; @@ -164,8 +164,9 @@ scareaway(region * r, int anzahl) p = rpeasants(r); assert(p >= 0 && anzahl >= 0); for (n = MIN(p, anzahl); n; n--) { - direction_t dir = (direction_t)(rng_int() % MAXDIRECTIONS); - region * rc = rconnect(r, dir); + direction_t dir = (direction_t) (rng_int() % MAXDIRECTIONS); + + region *rc = rconnect(r, dir); if (rc && fval(rc->terrain, LAND_REGION)) { ++diff; @@ -173,45 +174,43 @@ scareaway(region * r, int anzahl) emigrants[dir]++; } } - rsetpeasants(r, p-diff); + rsetpeasants(r, p - diff); assert(p >= diff); return diff; } -static void -scared_by_monster(unit * u) +static void scared_by_monster(unit * u) { int n; switch (old_race(u->race)) { case RC_FIREDRAGON: - n = rng_int()%160 * u->number; + n = rng_int() % 160 * u->number; break; case RC_DRAGON: - n = rng_int()%400 * u->number; + n = rng_int() % 400 * u->number; break; case RC_WYRM: - n = rng_int()%1000 * u->number; + n = rng_int() % 1000 * u->number; break; default: - n = rng_int()%(u->number/4+1); + n = rng_int() % (u->number / 4 + 1); } - if(n > 0) { + if (n > 0) { n = lovar(n); n = MIN(rpeasants(u->region), n); - if(n > 0) { + if (n > 0) { n = scareaway(u->region, n); - if(n > 0) { - ADDMSG(&u->region->msgs, msg_message("fleescared", - "amount unit", n, u)); + if (n > 0) { + ADDMSG(&u->region->msgs, msg_message("fleescared", + "amount unit", n, u)); } } } } -void -monster_kills_peasants(unit * u) +void monster_kills_peasants(unit * u) { if (!monster_is_waiting(u)) { if (u->race->flags & RCF_SCAREPEASANTS) { diff --git a/src/gamecode/monster.h b/src/gamecode/monster.h index 54e5fec10..0ae45a6bf 100644 --- a/src/gamecode/monster.h +++ b/src/gamecode/monster.h @@ -22,8 +22,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -void monster_kills_peasants(struct unit * u); -boolean monster_is_waiting(const struct unit * u); + void monster_kills_peasants(struct unit *u); + boolean monster_is_waiting(const struct unit *u); #ifdef __cplusplus } diff --git a/src/gamecode/randenc.c b/src/gamecode/randenc.c index 7d6a0d58d..35f13178a 100644 --- a/src/gamecode/randenc.c +++ b/src/gamecode/randenc.c @@ -68,164 +68,185 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include extern struct attrib_type at_unitdissolve; + extern struct attrib_type at_orcification; /* In a->data.ca[1] steht der Prozentsatz mit dem sich die Einheit * auflöst, in a->data.ca[0] kann angegeben werden, wohin die Personen * verschwinden. Passiert bereits in der ersten Runde! */ -static void -dissolve_units(void) +static void dissolve_units(void) { - region *r; - unit *u; - int n; - int i; + region *r; - for (r=regions;r;r=r->next) { - for (u=r->units;u;u=u->next) { - attrib * a = a_find(u->attribs, &at_unitdissolve); - if (a) { - message * msg; + unit *u; - if (u->age == 0 && a->data.ca[1] < 100) continue; + int n; - /* TODO: Durch einzelne Berechnung ersetzen */ - if (a->data.ca[1] == 100) { - n = u->number; - } else { - n = 0; - for (i=0;inumber;i++) { - if (rng_int()%100 < a->data.ca[1]) n++; - } - } + int i; - /* wenn keiner verschwindet, auch keine Meldung */ - if (n == 0) { - continue; - } + for (r = regions; r; r = r->next) { + for (u = r->units; u; u = u->next) { + attrib *a = a_find(u->attribs, &at_unitdissolve); - scale_number(u, u->number - n); + if (a) { + message *msg; - switch(a->data.ca[0]) { - case 1: - rsetpeasants(r, rpeasants(r) + n); - msg = msg_message("dissolve_units_1", "unit region number race", u, r, n, u->race); - break; - case 2: - if (r->land && !fval(r, RF_MALLORN)) { - rsettrees(r, 2, rtrees(r,2) + n); - msg = msg_message("dissolve_units_2", "unit region number race", u, r, n, u->race); - } else { - msg = msg_message("dissolve_units_3", "unit region number race", u, r, n, u->race); - } - break; - default: - if (u->race == new_race[RC_STONEGOLEM] || u->race == new_race[RC_IRONGOLEM]) { - msg = msg_message("dissolve_units_4", "unit region number race", u, r, n, u->race); - } else { - msg = msg_message("dissolve_units_5", "unit region number race", u, r, n, u->race); - } - break; - } + if (u->age == 0 && a->data.ca[1] < 100) + continue; + + /* TODO: Durch einzelne Berechnung ersetzen */ + if (a->data.ca[1] == 100) { + n = u->number; + } else { + n = 0; + for (i = 0; i < u->number; i++) { + if (rng_int() % 100 < a->data.ca[1]) + n++; + } + } + + /* wenn keiner verschwindet, auch keine Meldung */ + if (n == 0) { + continue; + } + + scale_number(u, u->number - n); + + switch (a->data.ca[0]) { + case 1: + rsetpeasants(r, rpeasants(r) + n); + msg = + msg_message("dissolve_units_1", "unit region number race", u, r, + n, u->race); + break; + case 2: + if (r->land && !fval(r, RF_MALLORN)) { + rsettrees(r, 2, rtrees(r, 2) + n); + msg = + msg_message("dissolve_units_2", "unit region number race", u, r, + n, u->race); + } else { + msg = + msg_message("dissolve_units_3", "unit region number race", u, r, + n, u->race); + } + break; + default: + if (u->race == new_race[RC_STONEGOLEM] + || u->race == new_race[RC_IRONGOLEM]) { + msg = + msg_message("dissolve_units_4", "unit region number race", u, r, + n, u->race); + } else { + msg = + msg_message("dissolve_units_5", "unit region number race", u, r, + n, u->race); + } + break; + } add_message(&u->faction->msgs, msg); msg_release(msg); - } - } - } + } + } + } - remove_empty_units(); + remove_empty_units(); } -static int -improve_all(faction * f, skill_t sk, int by_weeks) +static int improve_all(faction * f, skill_t sk, int by_weeks) { unit *u; + boolean ret = by_weeks; - + for (u = f->units; u; u = u->nextF) { if (has_skill(u, sk)) { int weeks = 0; - for (;weeks!=by_weeks;++weeks) { + + for (; weeks != by_weeks; ++weeks) { learn_skill(u, sk, 1.0); ret = 0; } } } - + return ret; } -void -find_manual(region * r, unit * u) +void find_manual(region * r, unit * u) { char zLocation[32]; + char zBook[32]; + skill_t skill = NOSKILL; - message * msg; + + message *msg; switch (rng_int() % 36) { - case 0: - skill = SK_MAGIC; - break; - case 1: - case 2: - case 3: - case 4: - skill = SK_WEAPONSMITH; - break; - case 5: - case 6: - skill = SK_TACTICS; - break; - case 7: - case 8: - case 9: - case 10: - skill = SK_SHIPBUILDING; - break; - case 11: - case 12: - case 13: - case 14: - skill = SK_SAILING; - break; - case 15: - case 16: - case 17: - skill = SK_HERBALISM; - break; - case 18: - case 19: - skill = SK_ALCHEMY; - break; - case 20: - case 21: - case 22: - case 23: - skill = SK_BUILDING; - break; - case 24: - case 25: - case 26: - case 27: - skill = SK_ARMORER; - break; - case 28: - case 29: - case 30: - case 31: - skill = SK_MINING; - break; - case 32: - case 33: - case 34: - case 35: - skill = SK_ENTERTAINMENT; - break; + case 0: + skill = SK_MAGIC; + break; + case 1: + case 2: + case 3: + case 4: + skill = SK_WEAPONSMITH; + break; + case 5: + case 6: + skill = SK_TACTICS; + break; + case 7: + case 8: + case 9: + case 10: + skill = SK_SHIPBUILDING; + break; + case 11: + case 12: + case 13: + case 14: + skill = SK_SAILING; + break; + case 15: + case 16: + case 17: + skill = SK_HERBALISM; + break; + case 18: + case 19: + skill = SK_ALCHEMY; + break; + case 20: + case 21: + case 22: + case 23: + skill = SK_BUILDING; + break; + case 24: + case 25: + case 26: + case 27: + skill = SK_ARMORER; + break; + case 28: + case 29: + case 30: + case 31: + skill = SK_MINING; + break; + case 32: + case 33: + case 34: + case 35: + skill = SK_ENTERTAINMENT; + break; } - snprintf(zLocation, sizeof(zLocation), "manual_location_%d", (int)(rng_int() % 4)); + snprintf(zLocation, sizeof(zLocation), "manual_location_%d", + (int)(rng_int() % 4)); snprintf(zBook, sizeof(zLocation), "manual_title_%s", skillnames[skill]); msg = msg_message("find_manual", "unit location book", u, zLocation, zBook); @@ -234,162 +255,177 @@ find_manual(region * r, unit * u) if (improve_all(u->faction, skill, 3) == 3) { int i; - for (i=0;i!=9;++i) learn_skill(u, skill, 1.0); + + for (i = 0; i != 9; ++i) + learn_skill(u, skill, 1.0); } } -static void -get_villagers(region * r, unit * u) +static void get_villagers(region * r, unit * u) { unit *newunit; - message * msg = msg_message("encounter_villagers", "unit", u); - const char * name = LOC(u->faction->locale, "villagers"); + + message *msg = msg_message("encounter_villagers", "unit", u); + + const char *name = LOC(u->faction->locale, "villagers"); r_addmessage(r, u->faction, msg); msg_release(msg); - newunit = create_unit(r, u->faction, rng_int() % 20 + 3, u->faction->race, 0, name, u); + newunit = + create_unit(r, u->faction, rng_int() % 20 + 3, u->faction->race, 0, name, + u); leave(newunit, true); - fset(newunit, UFL_ISNEW|UFL_MOVED); + fset(newunit, UFL_ISNEW | UFL_MOVED); equip_unit(newunit, get_equipment("random_villagers")); } -static void -get_allies(region * r, unit * u) +static void get_allies(region * r, unit * u) { - unit *newunit = NULL; - const char * name; - const char * equip; + unit *newunit = NULL; + + const char *name; + + const char *equip; + int number; - message * msg; + + message *msg; assert(u->number); switch (rterrain(r)) { - case T_PLAIN: - if (!r_isforest(r)) { - if (get_money(u) / u->number < 100 + rng_int() % 200) - return; - name = "random_plain_men"; - equip = "random_plain"; - number = rng_int() % 8 + 2; - break; - } else { - if (eff_skill(u, SK_LONGBOW, r) < 3 - && eff_skill(u, SK_HERBALISM, r) < 2 - && eff_skill(u, SK_MAGIC, r) < 2) { - return; - } - name = "random_forest_men"; - equip = "random_forest"; + case T_PLAIN: + if (!r_isforest(r)) { + if (get_money(u) / u->number < 100 + rng_int() % 200) + return; + name = "random_plain_men"; + equip = "random_plain"; + number = rng_int() % 8 + 2; + break; + } else { + if (eff_skill(u, SK_LONGBOW, r) < 3 + && eff_skill(u, SK_HERBALISM, r) < 2 + && eff_skill(u, SK_MAGIC, r) < 2) { + return; + } + name = "random_forest_men"; + equip = "random_forest"; + number = rng_int() % 6 + 2; + } + break; + + case T_SWAMP: + if (eff_skill(u, SK_MELEE, r) <= 1) { + return; + } + name = "random_swamp_men"; + equip = "random_swamp"; number = rng_int() % 6 + 2; - } - break; + break; - case T_SWAMP: - if (eff_skill(u, SK_MELEE, r) <= 1) { - return; - } - name = "random_swamp_men"; - equip = "random_swamp"; - number = rng_int() % 6 + 2; - break; + case T_DESERT: + if (eff_skill(u, SK_RIDING, r) <= 2) { + return; + } + name = "random_desert_men"; + equip = "random_desert"; + number = rng_int() % 12 + 2; + break; - case T_DESERT: - if (eff_skill(u, SK_RIDING, r) <= 2) { - return; - } - name = "random_desert_men"; - equip = "random_desert"; - number = rng_int() % 12 + 2; - break; + case T_HIGHLAND: + if (eff_skill(u, SK_MELEE, r) <= 1) { + return; + } + name = "random_highland_men"; + equip = "random_highland"; + number = rng_int() % 8 + 2; + break; - case T_HIGHLAND: - if (eff_skill(u, SK_MELEE, r) <= 1) { - return; - } - name = "random_highland_men"; - equip = "random_highland"; - number = rng_int() % 8 + 2; - break; + case T_MOUNTAIN: + if (eff_skill(u, SK_MELEE, r) <= 1 || eff_skill(u, SK_TRADE, r) <= 2) { + return; + } + name = "random_mountain_men"; + equip = "random_mountain"; + number = rng_int() % 6 + 2; + break; - case T_MOUNTAIN: - if (eff_skill(u, SK_MELEE, r) <= 1 || eff_skill(u, SK_TRADE, r) <= 2) { + case T_GLACIER: + if (eff_skill(u, SK_MELEE, r) <= 1 || eff_skill(u, SK_TRADE, r) <= 1) { + return; + } + name = "random_glacier_men"; + equip = "random_glacier"; + number = rng_int() % 4 + 2; + break; + + default: return; - } - name = "random_mountain_men"; - equip = "random_mountain"; - number = rng_int() % 6 + 2; - break; + } - case T_GLACIER: - if (eff_skill(u, SK_MELEE, r) <= 1 || eff_skill(u, SK_TRADE, r) <= 1) { - return; - } - name = "random_glacier_men"; - equip = "random_glacier"; - number = rng_int() % 4 + 2; - break; - - default: - return; - } - - newunit = create_unit(r, u->faction, number, u->faction->race, 0, LOC(u->faction->locale, name), u); + newunit = + create_unit(r, u->faction, number, u->faction->race, 0, + LOC(u->faction->locale, name), u); equip_unit(newunit, get_equipment(equip)); - u_setfaction(newunit, u->faction); - set_racename(&newunit->attribs, get_racename(u->attribs)); - if (u->race->flags & RCF_SHAPESHIFT) { - newunit->irace = u->irace; - } - if (fval(u, UFL_ANON_FACTION)) fset(newunit, UFL_ANON_FACTION); - fset(newunit, UFL_ISNEW); + u_setfaction(newunit, u->faction); + set_racename(&newunit->attribs, get_racename(u->attribs)); + if (u->race->flags & RCF_SHAPESHIFT) { + newunit->irace = u->irace; + } + if (fval(u, UFL_ANON_FACTION)) + fset(newunit, UFL_ANON_FACTION); + fset(newunit, UFL_ISNEW); msg = msg_message("encounter_allies", "unit name", u, name); r_addmessage(r, u->faction, msg); msg_release(msg); } -static void -encounter(region * r, unit * u) +static void encounter(region * r, unit * u) { - if (!fval(r, RF_ENCOUNTER)) return; - freset(r, RF_ENCOUNTER); - if (rng_int() % 100>=ENCCHANCE) return; - switch (rng_int() % 3) { - case 0: - find_manual(r, u); - break; - case 1: - get_villagers(r, u); - break; - case 2: - get_allies(r, u); - break; - } + if (!fval(r, RF_ENCOUNTER)) + return; + freset(r, RF_ENCOUNTER); + if (rng_int() % 100 >= ENCCHANCE) + return; + switch (rng_int() % 3) { + case 0: + find_manual(r, u); + break; + case 1: + get_villagers(r, u); + break; + case 2: + get_allies(r, u); + break; + } } -void -encounters(void) +void encounters(void) { region *r; for (r = regions; r; r = r->next) { if (!fval(r->terrain, SEA_REGION) && fval(r, RF_ENCOUNTER)) { int c = 0; - unit * u; + + unit *u; + for (u = r->units; u; u = u->next) { c += u->number; } if (c > 0) { int i = 0; + int n = rng_int() % c; for (u = r->units; u; u = u->next) { - if (i+u->number>n) break; - i+=u->number; + if (i + u->number > n) + break; + i += u->number; } assert(u && u->number); encounter(r, u); @@ -398,22 +434,23 @@ encounters(void) } } -static const terrain_type * -chaosterrain(void) +static const terrain_type *chaosterrain(void) { - static const terrain_type ** types; + static const terrain_type **types; + static int numtypes; - if (numtypes==0) { - const terrain_type * terrain; - for (terrain=terrains();terrain!=NULL;terrain=terrain->next) { + if (numtypes == 0) { + const terrain_type *terrain; + + for (terrain = terrains(); terrain != NULL; terrain = terrain->next) { if (fval(terrain, LAND_REGION) && terrain->herbs) { ++numtypes; } } - types = malloc(sizeof(terrain_type)*numtypes); + types = malloc(sizeof(terrain_type) * numtypes); numtypes = 0; - for (terrain=terrains();terrain!=NULL;terrain=terrain->next) { + for (terrain = terrains(); terrain != NULL; terrain = terrain->next) { if (fval(terrain, LAND_REGION) && terrain->herbs) { types[numtypes++] = terrain; } @@ -423,11 +460,12 @@ chaosterrain(void) } -static unit * -random_unit(const region * r) +static unit *random_unit(const region * r) { int c = 0; + int n; + unit *u; for (u = r->units; u; u = u->next) { @@ -453,111 +491,138 @@ random_unit(const region * r) return u; } -void -chaos(region * r) +void chaos(region * r) { if (rng_int() % 100 < 8) { switch (rng_int() % 3) { - case 0: /* Untote */ - if (!fval(r->terrain, SEA_REGION)) { - unit * u = random_unit(r); - if (u && playerrace(u->race)) { - ADDMSG(&u->faction->msgs, msg_message("chaos_disease", "unit", u)); - u_setfaction(u, get_monsters()); - u->race = new_race[RC_GHOUL]; - } - } - break; - case 1: /* Drachen */ - if (random_unit(r)) { - int mfac = 0; - unit * u; - switch (rng_int() % 3) { - case 0: - mfac = 100; - u = createunit(r, get_monsters(), rng_int() % 8 + 1, new_race[RC_FIREDRAGON]); - break; - case 1: - mfac = 500; - u = createunit(r, get_monsters(), rng_int() % 4 + 1, new_race[RC_DRAGON]); - break; - default: - mfac = 1000; - u = createunit(r, get_monsters(), rng_int() % 2 + 1, new_race[RC_WYRM]); - break; - } - if (mfac) set_money(u, u->number * (rng_int() % mfac)); - fset(u, UFL_ISNEW|UFL_MOVED); - } - case 2: /* Terrainveränderung */ - if (!fval(r->terrain, FORBIDDEN_REGION)) { + case 0: /* Untote */ if (!fval(r->terrain, SEA_REGION)) { - direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * rn = rconnect(r, dir); - if (rn && fval(rn->terrain, SEA_REGION)) break; - } - if (dir!=MAXDIRECTIONS) { - ship * sh = r->ships; - unit ** up; + unit *u = random_unit(r); - while (sh) { - ship * nsh = sh->next; - float dmg = get_param_flt(global.parameters, "rules.ship.damage.atlantis", 0.50); - damage_ship(sh, dmg); - if (sh->damage >= sh->size * DAMAGE_SCALE) { - remove_ship(&sh->region->ships, sh); - } - sh = nsh; - } - - for (up = &r->units; *up;) { - unit * u = *up; - if (u->race != new_race[RC_SPELL] && u->ship == 0 && !canfly(u)) { - ADDMSG(&u->faction->msgs, msg_message("tidalwave_kill", "region unit", r, u)); - remove_unit(up, u); - } - if (*up==u) up = &u->next; - } - ADDMSG(&r->msgs, msg_message("tidalwave", "region", r)); - - while (r->buildings) { - remove_building(&r->buildings, r->buildings); - } - terraform_region(r, newterrain(T_OCEAN)); - } - } else { - direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * rn = rconnect(r, dir); - if (rn && fval(rn->terrain, SEA_REGION)) break; - } - if (dir!=MAXDIRECTIONS) { - terraform_region(r, chaosterrain()); + if (u && playerrace(u->race)) { + ADDMSG(&u->faction->msgs, msg_message("chaos_disease", "unit", u)); + u_setfaction(u, get_monsters()); + u->race = new_race[RC_GHOUL]; + } + } + break; + case 1: /* Drachen */ + if (random_unit(r)) { + int mfac = 0; + + unit *u; + + switch (rng_int() % 3) { + case 0: + mfac = 100; + u = + createunit(r, get_monsters(), rng_int() % 8 + 1, + new_race[RC_FIREDRAGON]); + break; + case 1: + mfac = 500; + u = + createunit(r, get_monsters(), rng_int() % 4 + 1, + new_race[RC_DRAGON]); + break; + default: + mfac = 1000; + u = + createunit(r, get_monsters(), rng_int() % 2 + 1, + new_race[RC_WYRM]); + break; + } + if (mfac) + set_money(u, u->number * (rng_int() % mfac)); + fset(u, UFL_ISNEW | UFL_MOVED); + } + case 2: /* Terrainveränderung */ + if (!fval(r->terrain, FORBIDDEN_REGION)) { + if (!fval(r->terrain, SEA_REGION)) { + direction_t dir; + + for (dir = 0; dir != MAXDIRECTIONS; ++dir) { + region *rn = rconnect(r, dir); + + if (rn && fval(rn->terrain, SEA_REGION)) + break; + } + if (dir != MAXDIRECTIONS) { + ship *sh = r->ships; + + unit **up; + + while (sh) { + ship *nsh = sh->next; + + float dmg = + get_param_flt(global.parameters, "rules.ship.damage.atlantis", + 0.50); + damage_ship(sh, dmg); + if (sh->damage >= sh->size * DAMAGE_SCALE) { + remove_ship(&sh->region->ships, sh); + } + sh = nsh; + } + + for (up = &r->units; *up;) { + unit *u = *up; + + if (u->race != new_race[RC_SPELL] && u->ship == 0 && !canfly(u)) { + ADDMSG(&u->faction->msgs, msg_message("tidalwave_kill", + "region unit", r, u)); + remove_unit(up, u); + } + if (*up == u) + up = &u->next; + } + ADDMSG(&r->msgs, msg_message("tidalwave", "region", r)); + + while (r->buildings) { + remove_building(&r->buildings, r->buildings); + } + terraform_region(r, newterrain(T_OCEAN)); + } + } else { + direction_t dir; + + for (dir = 0; dir != MAXDIRECTIONS; ++dir) { + region *rn = rconnect(r, dir); + + if (rn && fval(rn->terrain, SEA_REGION)) + break; + } + if (dir != MAXDIRECTIONS) { + terraform_region(r, chaosterrain()); + } } } - } } } } -static int -nb_armor(const unit *u, int index) +static int nb_armor(const unit * u, int index) { - const item * itm; + const item *itm; + int av = 0; + int s = 0, a = 0; - if (!(u->race->battle_flags & BF_EQUIPMENT)) return 0; + if (!(u->race->battle_flags & BF_EQUIPMENT)) + return 0; /* Normale Rüstung */ - for (itm=u->items;itm;itm=itm->next) { - const armor_type * atype = itm->type->rtype->atype; - if (atype!=NULL) { - int * schutz = &a; - if (atype->flags & ATF_SHIELD) schutz = &s; + for (itm = u->items; itm; itm = itm->next) { + const armor_type *atype = itm->type->rtype->atype; + + if (atype != NULL) { + int *schutz = &a; + + if (atype->flags & ATF_SHIELD) + schutz = &s; if (*schutz <= index) { *schutz += itm->number; if (*schutz > index) { @@ -570,11 +635,14 @@ nb_armor(const unit *u, int index) } static int -damage_unit(unit *u, const char *dam, boolean physical, boolean magic) +damage_unit(unit * u, const char *dam, boolean physical, boolean magic) { int *hp = malloc(u->number * sizeof(int)); - int h; - int i, dead = 0, hp_rem = 0, heiltrank; + + int h; + + int i, dead = 0, hp_rem = 0, heiltrank; + double magres = magic_resistance(u); assert(u->number); @@ -582,28 +650,33 @@ damage_unit(unit *u, const char *dam, boolean physical, boolean magic) return 0; } - h = u->hp/u->number; + h = u->hp / u->number; /* HP verteilen */ - for (i=0; inumber; i++) hp[i] = h; + for (i = 0; i < u->number; i++) + hp[i] = h; h = u->hp - (u->number * h); - for (i=0; inumber; i++) { + for (i = 0; i < u->number; i++) { int damage = dice_rand(dam); - if (magic) damage = (int)(damage * (1.0 - magres)); - if (physical) damage -= nb_armor(u, i); + + if (magic) + damage = (int)(damage * (1.0 - magres)); + if (physical) + damage -= nb_armor(u, i); hp[i] -= damage; } /* Auswirkungen */ - for (i=0; inumber; i++) { - if (hp[i] <= 0){ + for (i = 0; i < u->number; i++) { + if (hp[i] <= 0) { heiltrank = 0; /* Sieben Leben */ if (old_race(u->race) == RC_CAT && (chance(1.0 / 7))) { - hp[i] = u->hp/u->number; + hp[i] = u->hp / u->number; hp_rem += hp[i]; continue; } @@ -619,13 +692,13 @@ damage_unit(unit *u, const char *dam, boolean physical, boolean magic) heiltrank = 1; } if (heiltrank && (chance(0.50))) { - hp[i] = u->hp/u->number; + hp[i] = u->hp / u->number; hp_rem += hp[i]; continue; } } dead++; - } else { + } else { hp_rem += hp[i]; } } @@ -638,72 +711,81 @@ damage_unit(unit *u, const char *dam, boolean physical, boolean magic) return dead; } -void -drown(region *r) +void drown(region * r) { if (fval(r->terrain, SEA_REGION)) { - unit ** up = up=&r->units; + unit **up = up = &r->units; + while (*up) { unit *u = *up; + int amphibian_level = 0; - if (u->ship || u->race == new_race[RC_SPELL] || u->number==0) { - up=&u->next; + + if (u->ship || u->race == new_race[RC_SPELL] || u->number == 0) { + up = &u->next; continue; } if (amphibian_level) { int dead = damage_unit(u, "5d1", false, false); + if (dead) { - ADDMSG(&u->faction->msgs, msg_message("drown_amphibian_dead", - "amount unit region", dead, u, r)); + ADDMSG(&u->faction->msgs, msg_message("drown_amphibian_dead", + "amount unit region", dead, u, r)); } else { - ADDMSG(&u->faction->msgs, msg_message("drown_amphibian_nodead", - "unit region",u, r)); + ADDMSG(&u->faction->msgs, msg_message("drown_amphibian_nodead", + "unit region", u, r)); } } else if (!(canswim(u) || canfly(u))) { scale_number(u, 0); ADDMSG(&u->faction->msgs, msg_message("drown", "unit region", u, r)); } - if (*up==u) up=&u->next; + if (*up == u) + up = &u->next; } remove_empty_units_in_region(r); } } -region * -rrandneighbour(region *r) +region *rrandneighbour(region * r) { - direction_t i; - region *rc = NULL; - int rr, c = 0; + direction_t i; - /* Nachsehen, wieviele Regionen in Frage kommen */ + region *rc = NULL; - for (i = 0; i != MAXDIRECTIONS; i++) { - c++; - } - /* Zufällig eine auswählen */ + int rr, c = 0; - rr = rng_int() % c; + /* Nachsehen, wieviele Regionen in Frage kommen */ - /* Durchzählen */ + for (i = 0; i != MAXDIRECTIONS; i++) { + c++; + } + /* Zufällig eine auswählen */ - c = -1; - for (i = 0; i != MAXDIRECTIONS; i++) { - rc = rconnect(r, i); - c++; - if (c == rr) break; - } - assert(i!=MAXDIRECTIONS); - return rc; + rr = rng_int() % c; + + /* Durchzählen */ + + c = -1; + for (i = 0; i != MAXDIRECTIONS; i++) { + rc = rconnect(r, i); + c++; + if (c == rr) + break; + } + assert(i != MAXDIRECTIONS); + return rc; } static void -volcano_destruction(region * volcano, region * r, region * rn, const char * damage) +volcano_destruction(region * volcano, region * r, region * rn, + const char *damage) { - attrib * a; - unit ** up; - int percent = 25, time = 6 + rng_int()%12; + attrib *a; + + unit **up; + + int percent = 25, time = 6 + rng_int() % 12; rsettrees(r, 2, 0); rsettrees(r, 1, 0); @@ -721,40 +803,44 @@ volcano_destruction(region * volcano, region * r, region * rn, const char * dama /* Personen bekommen 4W10 Punkte Schaden. */ - for (up=&r->units; *up;) { - unit * u = *up; + for (up = &r->units; *up;) { + unit *u = *up; + if (u->number) { int dead = damage_unit(u, damage, true, false); + if (dead) { - ADDMSG(&u->faction->msgs, msg_message("volcano_dead", - "unit region dead", u, volcano, dead)); + ADDMSG(&u->faction->msgs, msg_message("volcano_dead", + "unit region dead", u, volcano, dead)); } - if (r==volcano && !fval(u->faction, FFL_SELECT)) { + if (r == volcano && !fval(u->faction, FFL_SELECT)) { fset(u->faction, FFL_SELECT); if (rn) { - ADDMSG(&u->faction->msgs, msg_message("volcanooutbreak", - "regionv regionn", r, rn)); + ADDMSG(&u->faction->msgs, msg_message("volcanooutbreak", + "regionv regionn", r, rn)); } else { - ADDMSG(&u->faction->msgs, msg_message("volcanooutbreaknn", - "region", r)); + ADDMSG(&u->faction->msgs, msg_message("volcanooutbreaknn", + "region", r)); } } } - if (u==*up) up=&u->next; + if (u == *up) + up = &u->next; } remove_empty_units_in_region(r); } -void -volcano_outbreak(region *r) +void volcano_outbreak(region * r) { region *rn; + unit *u; + faction *f; - for (f=NULL,u=r->units; u; u=u->next) { - if (f!=u->faction) { + for (f = NULL, u = r->units; u; u = u->next) { + if (f != u->faction) { f = u->faction; freset(f, FFL_SELECT); } @@ -769,237 +855,264 @@ volcano_outbreak(region *r) } } -static void -melt_iceberg(region *r) +static void melt_iceberg(region * r) { - attrib *a; - unit *u; + attrib *a; - for (u=r->units; u; u=u->next) freset(u->faction, FFL_SELECT); - for (u=r->units; u; u=u->next) if (!fval(u->faction, FFL_SELECT)) { - fset(u->faction, FFL_SELECT); - ADDMSG(&u->faction->msgs, msg_message("iceberg_melt", "region", r)); - } + unit *u; - /* driftrichtung löschen */ - a = a_find(r->attribs, &at_iceberg); - if (a) a_remove(&r->attribs, a); - - /* Gebäude löschen */ - while (r->buildings) { - remove_building(&r->buildings, r->buildings); + for (u = r->units; u; u = u->next) + freset(u->faction, FFL_SELECT); + for (u = r->units; u; u = u->next) + if (!fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + ADDMSG(&u->faction->msgs, msg_message("iceberg_melt", "region", r)); } - /* in Ozean wandeln */ - terraform_region(r, newterrain(T_OCEAN)); + /* driftrichtung löschen */ + a = a_find(r->attribs, &at_iceberg); + if (a) + a_remove(&r->attribs, a); - /* Einheiten, die nicht schwimmen können oder in Schiffen sind, - * ertrinken */ - drown(r); + /* Gebäude löschen */ + while (r->buildings) { + remove_building(&r->buildings, r->buildings); + } + + /* in Ozean wandeln */ + terraform_region(r, newterrain(T_OCEAN)); + + /* Einheiten, die nicht schwimmen können oder in Schiffen sind, + * ertrinken */ + drown(r); } -static void -move_iceberg(region *r) +static void move_iceberg(region * r) { - attrib *a; - direction_t dir; - region *rc; + attrib *a; - a = a_find(r->attribs, &at_iceberg); - if (!a) { - dir = (direction_t)(rng_int()%MAXDIRECTIONS); - a = a_add(&r->attribs, make_iceberg(dir)); - } else { - if (rng_int()%100 < 20) { - dir = (direction_t)(rng_int()%MAXDIRECTIONS); - a->data.i = dir; - } else { - dir = (direction_t)a->data.i; - } - } + direction_t dir; - rc = rconnect(r, dir); + region *rc; - if (rc && !fval(rc->terrain, ARCTIC_REGION)) { - if (fval(rc->terrain, SEA_REGION)) { /* Eisberg treibt */ - ship *sh, *shn; - unit *u; - int x, y; + a = a_find(r->attribs, &at_iceberg); + if (!a) { + dir = (direction_t) (rng_int() % MAXDIRECTIONS); + a = a_add(&r->attribs, make_iceberg(dir)); + } else { + if (rng_int() % 100 < 20) { + dir = (direction_t) (rng_int() % MAXDIRECTIONS); + a->data.i = dir; + } else { + dir = (direction_t) a->data.i; + } + } + + rc = rconnect(r, dir); + + if (rc && !fval(rc->terrain, ARCTIC_REGION)) { + if (fval(rc->terrain, SEA_REGION)) { /* Eisberg treibt */ + ship *sh, *shn; + + unit *u; + + int x, y; - for (u=r->units; u; u=u->next) freset(u->faction, FFL_SELECT); - for (u=r->units; u; u=u->next) if (!fval(u->faction, FFL_SELECT)) { - fset(u->faction, FFL_SELECT); - ADDMSG(&u->faction->msgs, msg_message("iceberg_drift", - "region dir", r, dir)); - } + for (u = r->units; u; u = u->next) + freset(u->faction, FFL_SELECT); + for (u = r->units; u; u = u->next) + if (!fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + ADDMSG(&u->faction->msgs, msg_message("iceberg_drift", + "region dir", r, dir)); + } - x = r->x; - y = r->y; + x = r->x; + y = r->y; - runhash(r); - runhash(rc); - r->x = rc->x; - r->y = rc->y; - rc->x = x; - rc->y = y; - rhash(rc); - rhash(r); + runhash(r); + runhash(rc); + r->x = rc->x; + r->y = rc->y; + rc->x = x; + rc->y = y; + rhash(rc); + rhash(r); - /* rc ist der Ozean (Ex-Eisberg), r der Eisberg (Ex-Ozean) */ + /* rc ist der Ozean (Ex-Eisberg), r der Eisberg (Ex-Ozean) */ - /* Schiffe aus dem Zielozean werden in den Eisberg transferiert - * und nehmen Schaden. */ + /* Schiffe aus dem Zielozean werden in den Eisberg transferiert + * und nehmen Schaden. */ - for (sh = r->ships; sh; sh=sh->next) freset(sh, SF_SELECT); + for (sh = r->ships; sh; sh = sh->next) + freset(sh, SF_SELECT); - for (sh = r->ships; sh; sh = sh->next) { - /* Meldung an Kapitän */ - float dmg = get_param_flt(global.parameters, "rules.ship.damage.intoiceberg", 0.10F); - damage_ship(sh, dmg); - fset(sh, SF_SELECT); - } + for (sh = r->ships; sh; sh = sh->next) { + /* Meldung an Kapitän */ + float dmg = + get_param_flt(global.parameters, "rules.ship.damage.intoiceberg", + 0.10F); + damage_ship(sh, dmg); + fset(sh, SF_SELECT); + } - /* Personen, Schiffe und Gebäude verschieben */ - while (rc->buildings) { - rc->buildings->region = r; - translist(&rc->buildings, &r->buildings, rc->buildings); - } - while (rc->ships) { - float dmg = get_param_flt(global.parameters, "rules.ship.damage.withiceberg", 0.10F); - fset(rc->ships, SF_SELECT); - damage_ship(rc->ships, dmg); - move_ship(rc->ships, rc, r, NULL); - } - while (rc->units) { - building * b = rc->units->building; - u = rc->units; - move_unit(rc->units, r, NULL); - u->building = b; /* move_unit macht ein leave() */ - } + /* Personen, Schiffe und Gebäude verschieben */ + while (rc->buildings) { + rc->buildings->region = r; + translist(&rc->buildings, &r->buildings, rc->buildings); + } + while (rc->ships) { + float dmg = + get_param_flt(global.parameters, "rules.ship.damage.withiceberg", + 0.10F); + fset(rc->ships, SF_SELECT); + damage_ship(rc->ships, dmg); + move_ship(rc->ships, rc, r, NULL); + } + while (rc->units) { + building *b = rc->units->building; - /* Beschädigte Schiffe können sinken */ + u = rc->units; + move_unit(rc->units, r, NULL); + u->building = b; /* move_unit macht ein leave() */ + } - for (sh = r->ships; sh;) { - shn = sh->next; - if (fval(sh, SF_SELECT)) { - u = captain(sh); - if (sh->damage>=sh->size * DAMAGE_SCALE) { - if (u!=NULL) { - ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg_des", - "ship", sh)); + /* Beschädigte Schiffe können sinken */ + + for (sh = r->ships; sh;) { + shn = sh->next; + if (fval(sh, SF_SELECT)) { + u = captain(sh); + if (sh->damage >= sh->size * DAMAGE_SCALE) { + if (u != NULL) { + ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg_des", + "ship", sh)); } remove_ship(&sh->region->ships, sh); - } else if (u!=NULL) { - ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg", - "ship", sh)); - } - } - sh = shn; - } + } else if (u != NULL) { + ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg", + "ship", sh)); + } + } + sh = shn; + } - } else if (rng_int()%100 < 20) { /* Eisberg bleibt als Gletscher liegen */ - unit *u; + } else if (rng_int() % 100 < 20) { /* Eisberg bleibt als Gletscher liegen */ + unit *u; - rsetterrain(r, T_GLACIER); - a_remove(&r->attribs, a); + rsetterrain(r, T_GLACIER); + a_remove(&r->attribs, a); - for (u=r->units; u; u=u->next) freset(u->faction, FFL_SELECT); - for (u=r->units; u; u=u->next) if (!fval(u->faction, FFL_SELECT)) { - fset(u->faction, FFL_SELECT); - ADDMSG(&u->faction->msgs, msg_message("iceberg_land", "region", r)); - } - } - } + for (u = r->units; u; u = u->next) + freset(u->faction, FFL_SELECT); + for (u = r->units; u; u = u->next) + if (!fval(u->faction, FFL_SELECT)) { + fset(u->faction, FFL_SELECT); + ADDMSG(&u->faction->msgs, msg_message("iceberg_land", "region", r)); + } + } + } } -static void -move_icebergs(void) +static void move_icebergs(void) { - region *r; + region *r; - for (r=regions; r; r=r->next) { + for (r = regions; r; r = r->next) { if (r->terrain == newterrain(T_ICEBERG) && !fval(r, RF_SELECT)) { int select = rng_int() % 10; + if (select < 4) { /* 4% chance */ - fset(r, RF_SELECT); - melt_iceberg(r); - } else if (select<64) { + fset(r, RF_SELECT); + melt_iceberg(r); + } else if (select < 64) { /* 60% chance */ fset(r, RF_SELECT); move_iceberg(r); } - } - } + } + } } -void -create_icebergs(void) +void create_icebergs(void) { - region *r; + region *r; - for (r=regions; r; r=r->next) { + for (r = regions; r; r = r->next) { if (r->terrain == newterrain(T_ICEBERG_SLEEP) && chance(0.05)) { boolean has_ocean_neighbour = false; + direction_t dir; + region *rc; + unit *u; freset(r, RF_SELECT); - for (dir=0; dir < MAXDIRECTIONS; dir++) { + for (dir = 0; dir < MAXDIRECTIONS; dir++) { rc = rconnect(r, dir); if (rc && fval(rc->terrain, SEA_REGION)) { has_ocean_neighbour = true; break; } } - if (!has_ocean_neighbour) continue; + if (!has_ocean_neighbour) + continue; rsetterrain(r, T_ICEBERG); fset(r, RF_SELECT); move_iceberg(r); - for (u=r->units; u; u=u->next) { + for (u = r->units; u; u = u->next) { freset(u->faction, FFL_SELECT); } - for (u=r->units; u; u=u->next) { + for (u = r->units; u; u = u->next) { if (!fval(u->faction, FFL_SELECT)) { fset(u->faction, FFL_SELECT); ADDMSG(&u->faction->msgs, msg_message("iceberg_create", "region", r)); } } } - } + } } -static void -godcurse(void) +static void godcurse(void) { region *r; - for (r=regions; r; r=r->next) { + for (r = regions; r; r = r->next) { if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { - unit * u; - for(u=r->units; u; u=u->next) { - skill * sv = u->skills; - while (sv!=u->skills+u->skill_size) { - int weeks = 1+rng_int()%3; + unit *u; + + for (u = r->units; u; u = u->next) { + skill *sv = u->skills; + + while (sv != u->skills + u->skill_size) { + int weeks = 1 + rng_int() % 3; + reduce_skill(u, sv, weeks); ++sv; } } if (fval(r->terrain, SEA_REGION)) { ship *sh; + for (sh = r->ships; sh;) { ship *shn = sh->next; - float dmg = get_param_flt(global.parameters, "rules.ship.damage.godcurse", 0.10F); + + float dmg = + get_param_flt(global.parameters, "rules.ship.damage.godcurse", + 0.10F); damage_ship(sh, dmg); - if (sh->damage>=sh->size * DAMAGE_SCALE) { - unit * u = shipowner(sh); - if (u) ADDMSG(&u->faction->msgs, - msg_message("godcurse_destroy_ship", "ship", sh)); + if (sh->damage >= sh->size * DAMAGE_SCALE) { + unit *u = shipowner(sh); + + if (u) + ADDMSG(&u->faction->msgs, + msg_message("godcurse_destroy_ship", "ship", sh)); remove_ship(&sh->region->ships, sh); } sh = shn; @@ -1014,26 +1127,35 @@ godcurse(void) * This would probably be better handled in an age-function for the curse, * but it's now being called by randomevents() */ -static void -orc_growth(void) +static void orc_growth(void) { - region * r; + region *r; + for (r = regions; r; r = r->next) { unit *u; + for (u = r->units; u; u = u->next) { static boolean init = false; + static const curse_type *ct_orcish = 0; + curse *c = 0; + if (!init) { init = true; ct_orcish = ct_find("orcish"); } - if (ct_orcish) c = get_curse(u->attribs, ct_orcish); + if (ct_orcish) + c = get_curse(u->attribs, ct_orcish); - if (c && !has_skill(u, SK_MAGIC) && !has_skill(u, SK_ALCHEMY) && !fval(u, UFL_HERO)) { + if (c && !has_skill(u, SK_MAGIC) && !has_skill(u, SK_ALCHEMY) + && !fval(u, UFL_HERO)) { int n; + int increase = 0; - int num = get_cursedmen(u, c); + + int num = get_cursedmen(u, c); + double prob = curse_geteffect(c); for (n = (num - get_item(u, I_CHASTITY_BELT)); n > 0; n--) { @@ -1042,11 +1164,12 @@ orc_growth(void) } } if (increase) { - unit * u2 = create_unit(r, u->faction, increase, u->race, 0, NULL, u); + unit *u2 = create_unit(r, u->faction, increase, u->race, 0, NULL, u); + transfermen(u2, u, u2->number); ADDMSG(&u->faction->msgs, msg_message("orcgrowth", - "unit amount race", u, increase, u->race)); + "unit amount race", u, increase, u->race)); } } } @@ -1055,24 +1178,28 @@ orc_growth(void) /** Talente von Dämonen verschieben sich. */ -static void -demon_skillchanges(void) +static void demon_skillchanges(void) { - region * r; + region *r; for (r = regions; r; r = r->next) { - unit * u; + unit *u; + for (u = r->units; u; u = u->next) { if (u->race == new_race[RC_DAEMON]) { - skill * sv = u->skills; + skill *sv = u->skills; + int upchance = 15; + int downchance = 10; if (fval(u, UFL_HUNGER)) { /* hungry demons only go down, never up in skill */ static int rule_hunger = -1; - if (rule_hunger<0) { - rule_hunger = get_param_int(global.parameters, "hunger.demon.skill", 0); + + if (rule_hunger < 0) { + rule_hunger = + get_param_int(global.parameters, "hunger.demon.skill", 0); } if (rule_hunger) { upchance = 0; @@ -1080,23 +1207,27 @@ demon_skillchanges(void) } } - while (sv!=u->skills+u->skill_size) { + while (sv != u->skills + u->skill_size) { int roll = rng_int() % 100; - if (sv->level>0 && roll < upchance+downchance) { - int weeks = 1+rng_int()%3; + + if (sv->level > 0 && roll < upchance + downchance) { + int weeks = 1 + rng_int() % 3; + if (roll < downchance) { reduce_skill(u, sv, weeks); - if (sv->level<1) { + if (sv->level < 1) { /* demons should never forget below 1 */ set_level(u, sv->id, 1); } } else { - while (weeks--) learn_skill(u, sv->id, 1.0); + while (weeks--) + learn_skill(u, sv->id, 1.0); } - if (sv->old>sv->level) { - if (verbosity>=3) { + if (sv->old > sv->level) { + if (verbosity >= 3) { log_printf("%s dropped from %u to %u:%u in %s\n", - unitname(u), sv->old, sv->level, sv->weeks, skillname(sv->id, NULL)); + unitname(u), sv->old, sv->level, sv->weeks, skillname(sv->id, + NULL)); } } } @@ -1110,45 +1241,56 @@ demon_skillchanges(void) /** Eisberge entstehen und bewegen sich. * Einheiten die im Wasser landen, ertrinken. */ -static void -icebergs(void) +static void icebergs(void) { - region * r; + region *r; + create_icebergs(); move_icebergs(); - for (r=regions; r; r=r->next) { + for (r = regions; r; r = r->next) { drown(r); } } #ifdef HERBS_ROT -static void -rotting_herbs(void) +static void rotting_herbs(void) { static int rule_rot = -1; - region * r; - if (rule_rot<0) { - rule_rot = get_param_int(global.parameters, "rules.economy.herbrot", HERBROTCHANCE); + region *r; + + if (rule_rot < 0) { + rule_rot = + get_param_int(global.parameters, "rules.economy.herbrot", HERBROTCHANCE); } - if (rule_rot==0) return; + if (rule_rot == 0) + return; for (r = regions; r; r = r->next) { - unit * u; - for (u = r->units; u; u=u->next) { - item **itmp = &u->items, *hbag = *i_find(itmp, olditemtype[I_SACK_OF_CONSERVATION]); + unit *u; + + for (u = r->units; u; u = u->next) { + item **itmp = &u->items, *hbag = + *i_find(itmp, olditemtype[I_SACK_OF_CONSERVATION]); int rot_chance = rule_rot; - if (hbag) rot_chance = (rot_chance*2)/5; + if (hbag) + rot_chance = (rot_chance * 2) / 5; while (*itmp) { - item * itm = *itmp; + item *itm = *itmp; + int n = itm->number; - double k = n*rot_chance/100.0; + + double k = n * rot_chance / 100.0; + if (fval(itm->type, ITF_HERB)) { - double nv = normalvariate(k, k/4); + double nv = normalvariate(k, k / 4); + int inv = (int)nv; + int delta = MIN(n, inv); - if (i_change(itmp, itm->type, -delta)==NULL) { + + if (i_change(itmp, itm->type, -delta) == NULL) { continue; } } @@ -1159,11 +1301,10 @@ rotting_herbs(void) } #endif -void -randomevents(void) +void randomevents(void) { region *r; - + icebergs(); godcurse(); orc_growth(); @@ -1174,10 +1315,14 @@ randomevents(void) for (r = regions; r; r = r->next) { if (fval(r, RF_ORCIFIED)) { direction_t dir; + double probability = 0.0; + for (dir = 0; dir < MAXDIRECTIONS; dir++) { region *rc = rconnect(r, dir); - if (rc && rpeasants(rc) > 0 && !fval(rc, RF_ORCIFIED)) probability += 0.02; + + if (rc && rpeasants(rc) > 0 && !fval(rc, RF_ORCIFIED)) + probability += 0.02; } if (chance(probability)) { ADDMSG(&r->msgs, msg_message("deorcified", "region", r)); @@ -1185,17 +1330,21 @@ randomevents(void) } } else { attrib *a = a_find(r->attribs, &at_orcification); - if (a!=NULL) { + + if (a != NULL) { double probability = 0.0; - if (rpeasants(r) <= 0) continue; - probability = a->data.i/(double)rpeasants(r); + + if (rpeasants(r) <= 0) + continue; + probability = a->data.i / (double)rpeasants(r); if (chance(probability)) { fset(r, RF_ORCIFIED); a_remove(&r->attribs, a); ADDMSG(&r->msgs, msg_message("orcified", "region", r)); } else { - a->data.i -= MAX(10,a->data.i/10); - if (a->data.i <= 0) a_remove(&r->attribs, a); + a->data.i -= MAX(10, a->data.i / 10); + if (a->data.i <= 0) + a_remove(&r->attribs, a); } } } @@ -1208,15 +1357,15 @@ randomevents(void) ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r)); rsetterrain(r, T_VOLCANO); } else { - if (rng_int()%100 < 12) { + if (rng_int() % 100 < 12) { ADDMSG(&r->msgs, msg_message("volcanostopsmoke", "region", r)); rsetterrain(r, T_VOLCANO); - } else if (r->age>20 && rng_int()%100 < 8) { + } else if (r->age > 20 && rng_int() % 100 < 8) { volcano_outbreak(r); } } } else if (r->terrain == newterrain(T_VOLCANO)) { - if (rng_int()%100 < 4) { + if (rng_int() % 100 < 4) { ADDMSG(&r->msgs, msg_message("volcanostartsmoke", "region", r)); rsetterrain(r, T_VOLCANO_SMOKING); } @@ -1226,32 +1375,36 @@ randomevents(void) /* Monumente zerfallen, Schiffe verfaulen */ for (r = regions; r; r = r->next) { - building ** blist = &r->buildings; + building **blist = &r->buildings; + while (*blist) { - building * b = *blist; + building *b = *blist; + if (fval(b->type, BTF_DECAY) && !building_owner(b)) { b->size -= MAX(1, (b->size * 20) / 100); if (b->size == 0) { remove_building(blist, r->buildings); } } - if (*blist==b) blist=&b->next; + if (*blist == b) + blist = &b->next; } } /* monster-einheiten desertieren */ - for (r = regions; r; r=r->next) { + for (r = regions; r; r = r->next) { unit *u; - for (u=r->units; u; u=u->next) { + for (u = r->units; u; u = u->next) { if (u->faction && !is_monsters(u->faction) && (u->race->flags & RCF_DESERT)) { - if (fval(u, UFL_ISNEW)) continue; - if (rng_int()%100 < 5) { - ADDMSG(&u->faction->msgs, msg_message("desertion", + if (fval(u, UFL_ISNEW)) + continue; + if (rng_int() % 100 < 5) { + ADDMSG(&u->faction->msgs, msg_message("desertion", "unit region", u, r)); - u_setfaction(u, get_monsters()); - } + u_setfaction(u, get_monsters()); + } } } } @@ -1265,7 +1418,7 @@ randomevents(void) } i = chaoscount(r); if (i) { - chaoscounts(r, -(int) (i * ((double) (rng_int() % 10)) / 100.0)); + chaoscounts(r, -(int)(i * ((double)(rng_int() % 10)) / 100.0)); } } #ifdef HERBS_ROT diff --git a/src/gamecode/randenc.h b/src/gamecode/randenc.h index 31eb0f57f..0f39d9c61 100644 --- a/src/gamecode/randenc.h +++ b/src/gamecode/randenc.h @@ -22,8 +22,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern void encounters(void); -extern void randomevents(void); + extern void encounters(void); + extern void randomevents(void); #ifdef __cplusplus } diff --git a/src/gamecode/report.c b/src/gamecode/report.c index b32c252b0..742a7c63d 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -99,14 +99,17 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #endif extern int verbosity; -extern int *storms; -extern int weeks_per_month; -extern int months_per_year; -static char * -gamedate_season(const struct locale * lang) +extern int *storms; + +extern int weeks_per_month; + +extern int months_per_year; + +static char *gamedate_season(const struct locale *lang) { static char buf[256]; + gamedate gd; get_gamedate(turn, &gd); @@ -115,29 +118,25 @@ gamedate_season(const struct locale * lang) LOC(lang, weeknames[gd.week]), LOC(lang, monthnames[gd.month]), gd.year, - agename?LOC(lang, agename):"", - LOC(lang, seasonnames[gd.season])); + agename ? LOC(lang, agename) : "", LOC(lang, seasonnames[gd.season])); return buf; } -void -rpc(FILE * F, char c, size_t num) +void rpc(FILE * F, char c, size_t num) { - while(num > 0) { + while (num > 0) { putc(c, F); num--; } } -void -rnl(FILE * F) +void rnl(FILE * F) { fputc('\n', F); } -static void -centre(FILE * F, const char *s, boolean breaking) +static void centre(FILE * F, const char *s, boolean breaking) { /* Bei Namen die genau 80 Zeichen lang sind, kann es hier Probleme * geben. Seltsamerweise wird i dann auf MAXINT oder aehnlich @@ -146,6 +145,7 @@ centre(FILE * F, const char *s, boolean breaking) if (breaking && REPORTWIDTH < strlen(s)) { strlist *T, *SP = 0; + sparagraph(&SP, s, 0, 0); T = SP; while (SP) { @@ -154,25 +154,30 @@ centre(FILE * F, const char *s, boolean breaking) } freestrlist(T); } else { - rpc(F, ' ', (REPORTWIDTH - strlen(s)+1) / 2); + rpc(F, ' ', (REPORTWIDTH - strlen(s) + 1) / 2); fputs(s, F); putc('\n', F); } } static void -rparagraph(FILE *F, const char *str, ptrdiff_t indent, int hanging_indent, char mark) +rparagraph(FILE * F, const char *str, ptrdiff_t indent, int hanging_indent, + char mark) { - static const char * spaces = " "; + static const char *spaces = " "; + size_t length = REPORTWIDTH; - const char * end, * begin; + + const char *end, *begin; /* find out if there's a mark + indent already encoded in the string. */ if (!mark) { - const char * x = str; - while (*x == ' ') ++x; + const char *x = str; + + while (*x == ' ') + ++x; indent += x - str; - if (x[0] && indent && x[1]==' ') { + if (x[0] && indent && x[1] == ' ') { indent += 2; mark = x[0]; str = x + 2; @@ -182,48 +187,54 @@ rparagraph(FILE *F, const char *str, ptrdiff_t indent, int hanging_indent, char begin = end = str; do { - const char * last_space = begin; + const char *last_space = begin; - if (mark && indent>=2) { - fwrite(spaces, sizeof(char), indent-2, F); + if (mark && indent >= 2) { + fwrite(spaces, sizeof(char), indent - 2, F); fputc(mark, F); fputc(' ', F); mark = 0; - } else if (begin==str) { + } else if (begin == str) { fwrite(spaces, sizeof(char), indent, F); } else { - fwrite(spaces, sizeof(char), indent+ hanging_indent, F); + fwrite(spaces, sizeof(char), indent + hanging_indent, F); } - while (*end && end<=begin+length-indent) { - if (*end==' ') { + while (*end && end <= begin + length - indent) { + if (*end == ' ') { last_space = end; } ++end; } - if (*end==0) last_space = end; - if (last_space==begin) { + if (*end == 0) + last_space = end; + if (last_space == begin) { /* there was no space in this line. clip it */ last_space = end; } - fwrite(begin, sizeof(char), last_space-begin, F); + fwrite(begin, sizeof(char), last_space - begin, F); begin = last_space; - while (*begin==' ') { + while (*begin == ' ') { ++begin; } - if (begin>end) begin = end; + if (begin > end) + begin = end; fputc('\n', F); } while (*begin); } -static void -nr_spell(FILE * F, spell *sp, const struct locale * lang) +static void nr_spell(FILE * F, spell * sp, const struct locale *lang) { int bytes, k, itemanz, costtyp; + int dh = 0; + char buf[4096]; - char * bufp = buf; + + char *bufp = buf; + size_t size = sizeof(buf) - 1; - const char * params = sp->parameter; + + const char *params = sp->parameter; rnl(F); centre(F, spell_name(sp, lang), true); @@ -232,9 +243,13 @@ nr_spell(FILE * F, spell *sp, const struct locale * lang) rparagraph(F, spell_info(sp, lang), 2, 0, 0); bytes = (int)strlcpy(bufp, LOC(lang, "nr_spell_type"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (size) { *bufp++ = ' '; --size; } + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + + if (size) { + *bufp++ = ' '; + --size; + } if (sp->sptyp & PRECOMBATSPELL) { bytes = (int)strlcpy(bufp, LOC(lang, "sptype_precombat"), size); } else if (sp->sptyp & COMBATSPELL) { @@ -244,7 +259,8 @@ nr_spell(FILE * F, spell *sp, const struct locale * lang) } else { bytes = (int)strlcpy(bufp, LOC(lang, "sptype_normal"), size); } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); *bufp = 0; rparagraph(F, buf, 0, 0, 0); @@ -256,25 +272,33 @@ nr_spell(FILE * F, spell *sp, const struct locale * lang) rparagraph(F, LOC(lang, "nr_spell_components"), 0, 0, 0); for (k = 0; sp->components[k].type; ++k) { - const resource_type * rtype = sp->components[k].type; + const resource_type *rtype = sp->components[k].type; + itemanz = sp->components[k].amount; costtyp = sp->components[k].cost; if (itemanz > 0) { size = sizeof(buf) - 1; bufp = buf; if (sp->sptyp & SPELLLEVEL) { - bytes = snprintf(bufp, size, " %d %s", itemanz, LOC(lang, resourcename(rtype, itemanz!=1))); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR ) { + bytes = + snprintf(bufp, size, " %d %s", itemanz, LOC(lang, resourcename(rtype, + itemanz != 1))); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR) { bytes = snprintf(bufp, size, " * %s", LOC(lang, "nr_level")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } else { - if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR ) { + if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR) { itemanz *= sp->level; } - bytes = snprintf(bufp, size, "%d %s", itemanz, LOC(lang, resourcename(rtype, itemanz!=1))); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = + snprintf(bufp, size, "%d %s", itemanz, LOC(lang, resourcename(rtype, + itemanz != 1))); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } *bufp = 0; rparagraph(F, buf, 2, 2, '-'); @@ -282,30 +306,36 @@ nr_spell(FILE * F, spell *sp, const struct locale * lang) } size = sizeof(buf) - 1; - bufp = buf; + bufp = buf; bytes = (int)strlcpy(buf, LOC(lang, "nr_spell_modifiers"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); if (sp->sptyp & FARCASTING) { bytes = (int)strlcpy(bufp, " Fernzauber", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); dh = 1; } if (sp->sptyp & OCEANCASTABLE) { if (dh == 1) { bytes = (int)strlcpy(bufp, ",", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } bytes = (int)strlcpy(bufp, " Seezauber", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); dh = 1; } if (sp->sptyp & ONSHIPCAST) { - if (dh == 1){ + if (dh == 1) { bytes = (int)strlcpy(bufp, ",", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } bytes = (int)strlcpy(bufp, " Schiffszauber", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); dh = 1; } if (sp->sptyp & NOTFAMILIARCAST) { @@ -314,14 +344,18 @@ nr_spell(FILE * F, spell *sp, const struct locale * lang) } else { bytes = (int)strlcpy(bufp, " K", size); } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, "ann nicht vom Vertrauten gezaubert werden", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + bytes = + (int)strlcpy(bufp, "ann nicht vom Vertrauten gezaubert werden", size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); dh = 1; } if (dh == 0) { bytes = (int)strlcpy(bufp, " Keine", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } *bufp = 0; rparagraph(F, buf, 0, 0, 0); @@ -330,136 +364,165 @@ nr_spell(FILE * F, spell *sp, const struct locale * lang) bufp = buf; size = sizeof(buf) - 1; - + if (sp->sptyp & ISCOMBATSPELL) { bytes = (int)strlcpy(bufp, LOC(lang, keywords[K_COMBATSPELL]), size); } else { bytes = (int)strlcpy(bufp, LOC(lang, keywords[K_CAST]), size); } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); /* Reihenfolge beachten: Erst REGION, dann STUFE! */ if (sp->sptyp & FARCASTING) { bytes = snprintf(bufp, size, " [%s x y]", LOC(lang, parameters[P_REGION])); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } if (sp->sptyp & SPELLLEVEL) { bytes = snprintf(bufp, size, " [%s n]", LOC(lang, parameters[P_LEVEL])); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } bytes = (int)snprintf(bufp, size, " \"%s\"", spell_name(sp, lang)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + while (params && *params) { typedef struct starget { param_t param; int flag; - const char * vars; + const char *vars; } starget; - starget targets[] = { - { P_REGION, REGIONSPELL, NULL }, - { P_UNIT, UNITSPELL, "par_unit" }, - { P_SHIP, SHIPSPELL, "par_ship" }, - { P_BUILDING, BUILDINGSPELL, "par_building" }, - { 0, 0, NULL } - }; - starget * targetp; - char cp = *params++; - int i, maxparam = 0; - const char * locp; - const char * syntaxp = sp->syntax; - if (cp=='u') { - targetp = targets+1; + starget targets[] = { + {P_REGION, REGIONSPELL, NULL}, + {P_UNIT, UNITSPELL, "par_unit"}, + {P_SHIP, SHIPSPELL, "par_ship"}, + {P_BUILDING, BUILDINGSPELL, "par_building"}, + {0, 0, NULL} + }; + starget *targetp; + + char cp = *params++; + + int i, maxparam = 0; + + const char *locp; + + const char *syntaxp = sp->syntax; + + if (cp == 'u') { + targetp = targets + 1; locp = LOC(lang, targetp->vars); bytes = (int)snprintf(bufp, size, " <%s>", locp); - if (*params=='+') { + if (*params == '+') { ++params; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else if (cp=='s') { - targetp = targets+2; + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + } else if (cp == 's') { + targetp = targets + 2; locp = LOC(lang, targetp->vars); bytes = (int)snprintf(bufp, size, " <%s>", locp); - if (*params=='+') { + if (*params == '+') { ++params; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else if (cp=='r') { + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + } else if (cp == 'r') { bytes = (int)strlcpy(bufp, " ", size); - if (*params=='+') { + if (*params == '+') { ++params; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, " [ ...]", size); } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else if (cp=='b') { - targetp = targets+3; + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + } else if (cp == 'b') { + targetp = targets + 3; locp = LOC(lang, targetp->vars); bytes = (int)snprintf(bufp, size, " <%s>", locp); - if (*params=='+') { + if (*params == '+') { ++params; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else if (cp=='k') { - if (*params=='c') { + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + } else if (cp == 'k') { + if (*params == 'c') { /* skip over a potential id */ ++params; } - for (targetp=targets;targetp->flag;++targetp) { - if (sp->sptyp&targetp->flag) ++maxparam; + for (targetp = targets; targetp->flag; ++targetp) { + if (sp->sptyp & targetp->flag) + ++maxparam; } - if (maxparam>1) { + if (maxparam > 1) { bytes = (int)strlcpy(bufp, " (", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } i = 0; - for (targetp=targets;targetp->flag;++targetp) { - if (sp->sptyp&targetp->flag) { - if (i++!=0) { + for (targetp = targets; targetp->flag; ++targetp) { + if (sp->sptyp & targetp->flag) { + if (i++ != 0) { bytes = (int)strlcpy(bufp, " |", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } if (targetp->param) { locp = LOC(lang, targetp->vars); - bytes = (int)snprintf(bufp, size, " %s <%s>", parameters[targetp->param], locp); - if (*params=='+') { + bytes = + (int)snprintf(bufp, size, " %s <%s>", parameters[targetp->param], + locp); + if (*params == '+') { ++params; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)snprintf(bufp, size, " [<%s> ...]", locp); } } else { - bytes = (int)snprintf(bufp, size, " %s", parameters[targetp->param]); + bytes = + (int)snprintf(bufp, size, " %s", parameters[targetp->param]); } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } - if (maxparam>1) { + if (maxparam > 1) { bytes = (int)strlcpy(bufp, " )", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } - } else if (cp=='i' || cp=='c') { - const char * cstr; + } else if (cp == 'i' || cp == 'c') { + const char *cstr; + assert(syntaxp); cstr = strchr(syntaxp, ':'); if (!cstr) { locp = LOC(lang, mkname("spellpar", syntaxp)); } else { char substr[32]; - strncpy(substr, syntaxp, cstr-syntaxp); - substr[cstr-syntaxp] = 0; + + strncpy(substr, syntaxp, cstr - syntaxp); + substr[cstr - syntaxp] = 0; locp = LOC(lang, mkname("spellpar", substr)); syntaxp = substr + 1; } bytes = (int)snprintf(bufp, size, " <%s>", locp); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } *bufp = 0; @@ -467,8 +530,7 @@ nr_spell(FILE * F, spell *sp, const struct locale * lang) rnl(F); } -void -sparagraph(strlist ** SP, const char *s, int indent, char mark) +void sparagraph(strlist ** SP, const char *s, int indent, char mark) { /* Die Liste SP wird mit dem String s aufgefuellt, mit indent und einer @@ -476,7 +538,9 @@ sparagraph(strlist ** SP, const char *s, int indent, char mark) * Vgl. spunit (). */ int i, j, width; + int firstline; + static char buf[REPORTWIDTH + 1]; width = REPORTWIDTH - indent; @@ -523,8 +587,7 @@ sparagraph(strlist ** SP, const char *s, int indent, char mark) } } -int -hat_in_region(item_t it, region * r, faction * f) +int hat_in_region(item_t it, region * r, faction * f) { unit *u; @@ -537,10 +600,13 @@ hat_in_region(item_t it, region * r, faction * f) } static void -nr_curses(FILE *F, const faction *viewer, const void * obj, typ_t typ, int indent) +nr_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ, + int indent) { attrib *a = NULL; + int self = 0; + region *r; /* Die Sichtbarkeit eines Zaubers und die Zaubermeldung sind bei @@ -548,16 +614,19 @@ nr_curses(FILE *F, const faction *viewer, const void * obj, typ_t typ, int inden * Bei Einheiten sieht man Wirkungen auf eigene Einheiten immer. * Spezialfälle (besonderes Talent, verursachender Magier usw. werde * bei jedem curse gesondert behandelt. */ - if (typ == TYP_SHIP){ - ship * sh = (ship*)obj; - unit * owner = shipowner(sh); + if (typ == TYP_SHIP) { + ship *sh = (ship *) obj; + + unit *owner = shipowner(sh); + a = sh->attribs; r = sh->region; if (owner) { - if (owner->faction == viewer){ + if (owner->faction == viewer) { self = 2; - } else { /* steht eine person der Partei auf dem Schiff? */ + } else { /* steht eine person der Partei auf dem Schiff? */ unit *u = NULL; + for (u = r->units; u; u = u->next) { if (u->ship == sh) { self = 1; @@ -567,15 +636,18 @@ nr_curses(FILE *F, const faction *viewer, const void * obj, typ_t typ, int inden } } } else if (typ == TYP_BUILDING) { - building * b = (building*)obj; - unit * owner; + building *b = (building *) obj; + + unit *owner; + a = b->attribs; r = b->region; - if ((owner = building_owner(b)) != NULL){ - if (owner->faction == viewer){ + if ((owner = building_owner(b)) != NULL) { + if (owner->faction == viewer) { self = 2; - } else { /* steht eine Person der Partei in der Burg? */ + } else { /* steht eine Person der Partei in der Burg? */ unit *u = NULL; + for (u = r->units; u; u = u->next) { if (u->building == b) { self = 1; @@ -585,26 +657,28 @@ nr_curses(FILE *F, const faction *viewer, const void * obj, typ_t typ, int inden } } } else if (typ == TYP_UNIT) { - unit *u = (unit *)obj; + unit *u = (unit *) obj; + a = u->attribs; r = u->region; - if (u->faction == viewer){ + if (u->faction == viewer) { self = 2; } } else if (typ == TYP_REGION) { - r = (region *)obj; + r = (region *) obj; a = r->attribs; } else { /* fehler */ } - for (;a;a=a->next) { + for (; a; a = a->next) { char buf[4096]; if (fval(a->type, ATF_CURSE)) { - curse *c = (curse *)a->data.v; - message * msg; - + curse *c = (curse *) a->data.v; + + message *msg; + if (c->type->cansee) { self = c->type->cansee(viewer, obj, typ, c, self); } @@ -616,13 +690,14 @@ nr_curses(FILE *F, const faction *viewer, const void * obj, typ_t typ, int inden rparagraph(F, buf, indent, 2, 0); msg_release(msg); } - } else if (a->type==&at_effect && self) { - effect_data * data = (effect_data *)a->data.v; - if (data->value>0) { + } else if (a->type == &at_effect && self) { + effect_data *data = (effect_data *) a->data.v; + + if (data->value > 0) { sprintf(buf, "Auf der Einheit lieg%s %d Wirkung%s %s.", - (data->value==1 ? "t" : "en"), + (data->value == 1 ? "t" : "en"), data->value, - (data->value==1 ? "" : "en"), + (data->value == 1 ? "" : "en"), LOC(default_locale, resourcename(data->type->itype->rtype, 0))); rnl(F); rparagraph(F, buf, indent, 2, 0); @@ -631,13 +706,13 @@ nr_curses(FILE *F, const faction *viewer, const void * obj, typ_t typ, int inden } } -static void -rps_nowrap(FILE * F, const char *s) +static void rps_nowrap(FILE * F, const char *s) { const char *x = s; + size_t indent = 0; - while (*x++ == ' '); + while (*x++ == ' ') ; indent = x - s - 1; if (*(x - 1) && indent && *x == ' ') indent += 2; @@ -656,12 +731,17 @@ static void nr_unit(FILE * F, const faction * f, const unit * u, int indent, int mode) { attrib *a_otherfaction; + char marker; + int dh; - boolean isbattle = (boolean)(mode == see_battle); + + boolean isbattle = (boolean) (mode == see_battle); + char buf[8192]; - if (fval(u->race, RCF_INVISIBLE)) return; + if (fval(u->race, RCF_INVISIBLE)) + return; { rnl(F); @@ -672,10 +752,11 @@ nr_unit(FILE * F, const faction * f, const unit * u, int indent, int mode) if (u->faction == f) { marker = '*'; - } else if ALLIED(u->faction, f) { + } else if ALLIED + (u->faction, f) { marker = 'o'; - } else if (a_otherfaction && f != u->faction && get_otherfaction(a_otherfaction) == f - && !fval(u, UFL_ANON_FACTION)) { + } else if (a_otherfaction && f != u->faction + && get_otherfaction(a_otherfaction) == f && !fval(u, UFL_ANON_FACTION)) { marker = '!'; } else { if (dh && !fval(u, UFL_ANON_FACTION)) { @@ -692,20 +773,26 @@ nr_unit(FILE * F, const faction * f, const unit * u, int indent, int mode) } static void -rp_messages(FILE * F, message_list * msgs, faction * viewer, int indent, boolean categorized) +rp_messages(FILE * F, message_list * msgs, faction * viewer, int indent, + boolean categorized) { - nrsection * section; - if (!msgs) return; - for (section = sections; section; section=section->next) { + nrsection *section; + + if (!msgs) + return; + for (section = sections; section; section = section->next) { int k = 0; - struct mlist * m = msgs->begin; + + struct mlist *m = msgs->begin; + while (m) { /* messagetype * mt = m->type; */ - if (!categorized || strcmp(nr_section(m->msg), section->name)==0) { + if (!categorized || strcmp(nr_section(m->msg), section->name) == 0) { char lbuf[8192]; if (!k && categorized) { - const char * section_title; + const char *section_title; + char cat_identifier[24]; rnl(F); @@ -720,21 +807,23 @@ rp_messages(FILE * F, message_list * msgs, faction * viewer, int indent, boolean } m = m->next; } - if (!categorized) break; + if (!categorized) + break; } } -static void -rp_battles(FILE * F, faction * f) +static void rp_battles(FILE * F, faction * f) { - if (f->battles!=NULL) { - struct bmsg * bm = f->battles; + if (f->battles != NULL) { + struct bmsg *bm = f->battles; + rnl(F); centre(F, LOC(f->locale, "section_battle"), false); rnl(F); while (bm) { char buf[256]; + RENDER(f, buf, sizeof(buf), ("battle::header", "region", bm->r)); rnl(F); centre(F, buf, true); @@ -745,63 +834,81 @@ rp_battles(FILE * F, faction * f) } } -static void -prices(FILE * F, const region * r, const faction * f) +static void prices(FILE * F, const region * r, const faction * f) { - const luxury_type *sale=NULL; - struct demand * dmd; - message * m; + const luxury_type *sale = NULL; + + struct demand *dmd; + + message *m; + int bytes, n = 0; - char buf[4096], * bufp = buf; + + char buf[4096], *bufp = buf; + size_t size = sizeof(buf) - 1; - if (r->land==NULL || r->land->demands==NULL) return; - for (dmd=r->land->demands;dmd;dmd=dmd->next) { - if (dmd->value==0) sale = dmd->type; - else if (dmd->value > 0) n++; + if (r->land == NULL || r->land->demands == NULL) + return; + for (dmd = r->land->demands; dmd; dmd = dmd->next) { + if (dmd->value == 0) + sale = dmd->type; + else if (dmd->value > 0) + n++; } - assert(sale!=NULL); + assert(sale != NULL); m = msg_message("nr_market_sale", "product price", sale->itype->rtype, sale->price); bytes = (int)nr_render(m, f->locale, bufp, size, f); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); msg_release(m); if (n > 0) { bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_intro"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); - for (dmd=r->land->demands;dmd;dmd=dmd->next) if(dmd->value > 0) { - m = msg_message("nr_market_price", "product price", - dmd->type->itype->rtype, dmd->value * dmd->type->price); - bytes = (int)nr_render(m, f->locale, bufp, size, f); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - msg_release(m); - n--; - if (n == 0) { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_end"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + for (dmd = r->land->demands; dmd; dmd = dmd->next) + if (dmd->value > 0) { + m = msg_message("nr_market_price", "product price", + dmd->type->itype->rtype, dmd->value * dmd->type->price); + bytes = (int)nr_render(m, f->locale, bufp, size, f); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + msg_release(m); + n--; + if (n == 0) { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_end"), size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + } else if (n == 1) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_final"), size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + } else { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_next"), size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + } } - else if (n == 1) { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_final"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } else { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_trade_next"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - } - } } /* Schreibe Paragraphen */ *bufp = 0; @@ -809,68 +916,89 @@ prices(FILE * F, const region * r, const faction * f) } -boolean -see_border(const connection * b, const faction * f, const region * r) +boolean see_border(const connection * b, const faction * f, const region * r) { boolean cs = b->type->fvisible(b, f, r); + if (!cs) { cs = b->type->rvisible(b, r); if (!cs) { - const unit * us = r->units; + const unit *us = r->units; + while (us && !cs) { - if (us->faction==f) { + if (us->faction == f) { cs = b->type->uvisible(b, us); - if (cs) break; + if (cs) + break; } - us=us->next; + us = us->next; } } } return cs; } -static void -describe(FILE * F, const seen_region * sr, faction * f) +static void describe(FILE * F, const seen_region * sr, faction * f) { - const region * r = sr->r; + const region *r = sr->r; + int n; + boolean dh; + direction_t d; + int trees; + int saplings; + attrib *a; + const char *tname; + struct edge { - struct edge * next; - char * name; + struct edge *next; + char *name; boolean transparent; boolean block; boolean exist[MAXDIRECTIONS]; direction_t lastd; - } * edges = NULL, * e; + } *edges = NULL, *e; + boolean see[MAXDIRECTIONS]; + char buf[8192]; - char * bufp = buf; + + char *bufp = buf; + size_t size = sizeof(buf); + int bytes; for (d = 0; d != MAXDIRECTIONS; d++) { /* Nachbarregionen, die gesehen werden, ermitteln */ region *r2 = rconnect(r, d); - connection *b; - see[d] = true; - if (!r2) continue; - for (b=get_borders(r, r2);b;) { - struct edge * e = edges; - boolean transparent = b->type->transparent(b, f); - const char * name = b->type->name(b, r, f, GF_DETAILED|GF_ARTICLE); - if (!transparent) see[d] = false; + connection *b; + + see[d] = true; + if (!r2) + continue; + for (b = get_borders(r, r2); b;) { + struct edge *e = edges; + + boolean transparent = b->type->transparent(b, f); + + const char *name = b->type->name(b, r, f, GF_DETAILED | GF_ARTICLE); + + if (!transparent) + see[d] = false; if (!see_border(b, f, r)) { b = b->next; continue; } - while (e && (e->transparent != transparent || strcmp(name,e->name))) e = e->next; + while (e && (e->transparent != transparent || strcmp(name, e->name))) + e = e->next; if (!e) { e = calloc(sizeof(struct edge), 1); e->name = strdup(name); @@ -878,43 +1006,46 @@ describe(FILE * F, const seen_region * sr, faction * f) e->next = edges; edges = e; } - e->lastd=d; + e->lastd = d; e->exist[d] = true; b = b->next; } } bytes = (int)f_regionid(r, f, bufp, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (sr->mode==see_travel) { + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + + if (sr->mode == see_travel) { bytes = (int)strlcpy(bufp, " (durchgereist)", size); - } - else if (sr->mode==see_neighbour) { + } else if (sr->mode == see_neighbour) { bytes = (int)strlcpy(bufp, " (benachbart)", size); - } - else if (sr->mode==see_lighthouse) { + } else if (sr->mode == see_lighthouse) { bytes = (int)strlcpy(bufp, " (vom Turm erblickt)", size); } else { bytes = 0; } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + /* Terrain */ bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + tname = terrain_name(r); bytes = (int)strlcpy(bufp, LOC(f->locale, tname), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + /* Trees */ - trees = rtrees(r,2); - saplings = rtrees(r,1); + trees = rtrees(r, 2); + saplings = rtrees(r, 1); if (production(r)) { if (trees > 0 || saplings > 0) { bytes = snprintf(bufp, size, ", %d/%d ", trees, saplings); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); if (fval(r, RF_MALLORN)) { if (trees == 1) { @@ -922,26 +1053,28 @@ describe(FILE * F, const seen_region * sr, faction * f) } else { bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_mallorntree_p"), size); } - } - else if (trees == 1) { + } else if (trees == 1) { bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_tree"), size); } else { bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_tree_p"), size); } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } /* iron & stone */ - if (sr->mode==see_unit && f != (faction *) NULL) { + if (sr->mode == see_unit && f != (faction *) NULL) { resource_report result[MAX_RAWMATERIALS]; + int n, numresults = report_resources(sr, result, MAX_RAWMATERIALS, f); - for (n=0;n=0 && result[n].level>=0) { - bytes = snprintf(bufp, size, ", %d %s/%d", result[n].number, + for (n = 0; n < numresults; ++n) { + if (result[n].number >= 0 && result[n].level >= 0) { + bytes = snprintf(bufp, size, ", %d %s/%d", result[n].number, LOC(f->locale, result[n].name), result[n].level); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } } @@ -949,131 +1082,178 @@ describe(FILE * F, const seen_region * sr, faction * f) /* peasants & silver */ if (rpeasants(r)) { int n = rpeasants(r); + bytes = snprintf(bufp, size, ", %d", n); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + if (r->land->ownership) { - const char * str = locale_string(f->locale, mkname("morale", itoa10(r->land->morale))); + const char *str = + locale_string(f->locale, mkname("morale", itoa10(r->land->morale))); bytes = snprintf(bufp, size, " %s", str); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } if (fval(r, RF_ORCIFIED)) { bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - bytes = (int)strlcpy(bufp, LOC(f->locale, n==1?"rc_orc":"rc_orc_p"), size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + + bytes = + (int)strlcpy(bufp, LOC(f->locale, n == 1 ? "rc_orc" : "rc_orc_p"), + size); } else { bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, n==1?"peasant":"peasant_p"), size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + bytes = + (int)strlcpy(bufp, LOC(f->locale, n == 1 ? "peasant" : "peasant_p"), + size); } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (is_mourning(r, turn+1)) { + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + if (is_mourning(r, turn + 1)) { bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_mourning"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } - if (rmoney(r) && sr->mode>=see_travel) { + if (rmoney(r) && sr->mode >= see_travel) { bytes = snprintf(bufp, size, ", %d ", rmoney(r)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, resourcename(oldresourcetype[R_SILVER], rmoney(r)!=1)), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + bytes = + (int)strlcpy(bufp, LOC(f->locale, resourcename(oldresourcetype[R_SILVER], + rmoney(r) != 1)), size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } /* Pferde */ if (rhorses(r)) { bytes = snprintf(bufp, size, ", %d ", rhorses(r)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, resourcename(oldresourcetype[R_HORSE], (rhorses(r)>1)?GR_PLURAL:0)), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + bytes = + (int)strlcpy(bufp, LOC(f->locale, resourcename(oldresourcetype[R_HORSE], + (rhorses(r) > 1) ? GR_PLURAL : 0)), size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + if (r->display && r->display[0]) { bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, r->display, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); n = r->display[strlen(r->display) - 1]; if (n != '!' && n != '?' && n != '.') { bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } if (rule_region_owners()) { - const faction * owner = region_get_owner(r); - if (owner!=NULL) { + const faction *owner = region_get_owner(r); + + if (owner != NULL) { bytes = snprintf(bufp, size, " Die Region ist im Besitz von %s.", - factionname(owner)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + factionname(owner)); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } a = a_find(r->attribs, &at_overrideroads); if (a) { bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, (char *)a->data.v, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } else { int nrd = 0; /* Nachbarregionen, die gesehen werden, ermitteln */ for (d = 0; d != MAXDIRECTIONS; d++) { - if (see[d] && rconnect(r, d)) nrd++; + if (see[d] && rconnect(r, d)) + nrd++; } /* list directions */ dh = false; - for (d = 0; d != MAXDIRECTIONS; d++) if (see[d]) { - region * r2 = rconnect(r, d); - if(!r2) continue; - nrd--; - if (dh) { - char regname[4096]; - if (nrd == 0) { + for (d = 0; d != MAXDIRECTIONS; d++) + if (see[d]) { + region *r2 = rconnect(r, d); + + if (!r2) + continue; + nrd--; + if (dh) { + char regname[4096]; + + if (nrd == 0) { + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nb_final"), size); + } else { + bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nb_next"), size); + } + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, LOC(f->locale, directions[d]), size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nb_final"), size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + f_regionid(r2, f, regname, sizeof(regname)); + bytes = snprintf(bufp, size, trailinto(r2, f->locale), regname); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } else { - bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nb_next"), size); + bytes = (int)strlcpy(bufp, " ", size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + MSG(("nr_vicinitystart", "dir region", d, r2), bufp, size, f->locale, + f); + bufp += strlen(bufp); + dh = true; } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, LOC(f->locale, directions[d]), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - f_regionid(r2, f, regname, sizeof(regname)); - bytes = snprintf(bufp, size, trailinto(r2, f->locale), regname); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); } - else { - bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - MSG(("nr_vicinitystart", "dir region", d, r2), bufp, size, f->locale, f); - bufp += strlen(bufp); - dh = true; - } - } /* Spezielle Richtungen */ - for (a = a_find(r->attribs, &at_direction);a && a->type==&at_direction;a=a->next) { - spec_direction * d = (spec_direction *)(a->data.v); + for (a = a_find(r->attribs, &at_direction); a && a->type == &at_direction; + a = a->next) { + spec_direction *d = (spec_direction *) (a->data.v); + bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, LOC(f->locale, d->desc), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, " (\"", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, LOC(f->locale, d->keyword), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, "\")", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); dh = 1; } } @@ -1081,29 +1261,34 @@ describe(FILE * F, const seen_region * sr, faction * f) *bufp = 0; rparagraph(F, buf, 0, 0, 0); - if (sr->mode==see_unit && is_astral(r) && - !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) { + if (sr->mode == see_unit && is_astral(r) && + !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) { /* Sonderbehandlung Teleport-Ebene */ region_list *rl = astralregions(r, inhabitable); + region_list *rl2; if (rl) { bufp = buf; size = sizeof(buf) - 1; bytes = (int)strlcpy(bufp, "Schemen der Regionen ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); rl2 = rl; while (rl2) { bytes = (int)f_regionid(rl2->data, f, bufp, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); rl2 = rl2->next; if (rl2) { bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } bytes = (int)strlcpy(bufp, " sind erkennbar.", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); free_regionlist(rl); /* Schreibe Paragraphen */ rnl(F); @@ -1115,38 +1300,54 @@ describe(FILE * F, const seen_region * sr, faction * f) n = 0; /* Wirkungen permanenter Sprüche */ - nr_curses(F, f, r, TYP_REGION,0); + nr_curses(F, f, r, TYP_REGION, 0); /* Produktionsreduktion */ a = a_find(r->attribs, &at_reduceproduction); if (a) { - const char * str = LOC(f->locale, "nr_reduced_production"); + const char *str = LOC(f->locale, "nr_reduced_production"); + rparagraph(F, str, 0, 0, 0); } - if (edges) rnl(F); - for (e=edges;e;e=e->next) { + if (edges) + rnl(F); + for (e = edges; e; e = e->next) { boolean first = true; + bufp = buf; size = sizeof(buf) - 1; - for (d=0;d!=MAXDIRECTIONS;++d) { - if (!e->exist[d]) continue; - if (first) bytes = (int)strlcpy(bufp, "Im ", size); - else if (e->lastd==d) bytes = (int)strlcpy(bufp, " und im ", size); - else bytes = (int)strlcpy(bufp, ", im ", size ); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + for (d = 0; d != MAXDIRECTIONS; ++d) { + if (!e->exist[d]) + continue; + if (first) + bytes = (int)strlcpy(bufp, "Im ", size); + else if (e->lastd == d) + bytes = (int)strlcpy(bufp, " und im ", size); + else + bytes = (int)strlcpy(bufp, ", im ", size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, LOC(f->locale, directions[d]), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); first = false; } - if (!e->transparent) bytes = (int)strlcpy(bufp, " versperrt ", size); - else bytes = (int)strlcpy(bufp, " befindet sich ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (!e->transparent) + bytes = (int)strlcpy(bufp, " versperrt ", size); + else + bytes = (int)strlcpy(bufp, " befindet sich ", size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, e->name, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (!e->transparent) bytes = (int)strlcpy(bufp, " die Sicht.", size); - else bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + if (!e->transparent) + bytes = (int)strlcpy(bufp, " die Sicht.", size); + else + bytes = (int)strlcpy(bufp, ".", size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); *bufp = 0; rparagraph(F, buf, 0, 0, 0); } @@ -1160,19 +1361,22 @@ describe(FILE * F, const seen_region * sr, faction * f) } } -static void -statistics(FILE * F, const region * r, const faction * f) +static void statistics(FILE * F, const region * r, const faction * f) { const unit *u; + int number = 0, p = rpeasants(r); - message * m; + + message *m; + item *itm, *items = NULL; + char buf[4096]; /* count */ for (u = r->units; u; u = u->next) { if (u->faction == f && !fval(u->race, RCF_INVISIBLE)) { - for (itm=u->items;itm;itm=itm->next) { + for (itm = u->items; itm; itm = itm->next) { i_change(&items, itm->type, itm->number); } number += u->number; @@ -1187,17 +1391,20 @@ statistics(FILE * F, const region * r, const faction * f) rnl(F); /* Region */ - if (skill_enabled[SK_ENTERTAINMENT] && fval(r->terrain, LAND_REGION) && rmoney(r)) { + if (skill_enabled[SK_ENTERTAINMENT] && fval(r->terrain, LAND_REGION) + && rmoney(r)) { m = msg_message("nr_stat_maxentertainment", "max", entertainmoney(r)); nr_render(m, f->locale, buf, sizeof(buf), f); rparagraph(F, buf, 2, 2, 0); msg_release(m); } - if (production(r) && (!fval(r->terrain, SEA_REGION) || f->race == new_race[RC_AQUARIAN])) { - if (markets_module()) { /* hack */ - m = msg_message("nr_stat_salary_new", "max", wage(r, NULL, NULL, turn+1)); + if (production(r) && (!fval(r->terrain, SEA_REGION) + || f->race == new_race[RC_AQUARIAN])) { + if (markets_module()) { /* hack */ + m = + msg_message("nr_stat_salary_new", "max", wage(r, NULL, NULL, turn + 1)); } else { - m = msg_message("nr_stat_salary", "max", wage(r, f, f->race, turn+1)); + m = msg_message("nr_stat_salary", "max", wage(r, f, f->race, turn + 1)); } nr_render(m, f->locale, buf, sizeof(buf), f); rparagraph(F, buf, 2, 2, 0); @@ -1212,11 +1419,9 @@ statistics(FILE * F, const region * r, const faction * f) if (!markets_module()) { if (buildingtype_exists(r, bt_find("caravan"), true)) { - m = msg_message("nr_stat_luxuries", "max", - (p * 2) / TRADE_FRACTION); + m = msg_message("nr_stat_luxuries", "max", (p * 2) / TRADE_FRACTION); } else { - m = msg_message("nr_stat_luxuries", "max", - p / TRADE_FRACTION); + m = msg_message("nr_stat_luxuries", "max", p / TRADE_FRACTION); } nr_render(m, f->locale, buf, sizeof(buf), f); rparagraph(F, buf, 2, 2, 0); @@ -1239,48 +1444,52 @@ statistics(FILE * F, const region * r, const faction * f) rparagraph(F, buf, 2, 2, 0); msg_release(m); - for (itm = items; itm; itm=itm->next) { + for (itm = items; itm; itm = itm->next) { sprintf(buf, "%s: %d", - LOC(f->locale, resourcename(itm->type->rtype, GR_PLURAL)), - itm->number); + LOC(f->locale, resourcename(itm->type->rtype, GR_PLURAL)), itm->number); rparagraph(F, buf, 2, 2, 0); } - while (items) i_free(i_remove(&items, items)); + while (items) + i_free(i_remove(&items, items)); } -static void -durchreisende(FILE * F, const region * r, const faction * f) +static void durchreisende(FILE * F, const region * r, const faction * f) { if (fval(r, RF_TRAVELUNIT)) { attrib *abegin = a_find(r->attribs, &at_travelunit), *a; + int counter = 0, maxtravel = 0; + char buf[8192]; - char * bufp = buf; + + char *bufp = buf; + int bytes; + size_t size = sizeof(buf) - 1; /* How many are we listing? For grammar. */ - for (a = abegin; a && a->type==&at_travelunit; a = a->next) { - unit * u = (unit*)a->data.v; + for (a = abegin; a && a->type == &at_travelunit; a = a->next) { + unit *u = (unit *) a->data.v; - if (r!=u->region && (u->ship==NULL || fval(u, UFL_OWNER))) { + if (r != u->region && (u->ship == NULL || fval(u, UFL_OWNER))) { if (cansee_durchgezogen(f, r, u, 0)) { ++maxtravel; } } } - if (maxtravel==0) { + if (maxtravel == 0) { return; } /* Auflisten. */ rnl(F); - for (a = abegin; a && a->type==&at_travelunit; a = a->next) { - unit * u = (unit*)a->data.v; + for (a = abegin; a && a->type == &at_travelunit; a = a->next) { + unit *u = (unit *) a->data.v; - if (r!=u->region && (u->ship==NULL || fval(u, UFL_OWNER))) { + if (r != u->region && (u->ship == NULL || fval(u, UFL_OWNER))) { if (cansee_durchgezogen(f, r, u, 0)) { ++counter; if (u->ship != NULL) { @@ -1289,7 +1498,7 @@ durchreisende(FILE * F, const region * r, const faction * f) } else { bytes = (int)strlcpy(bufp, "die ", size); } - if (wrptr(&bufp, &size, bytes)!=0) { + if (wrptr(&bufp, &size, bytes) != 0) { WARN_STATIC_BUFFER(); break; } @@ -1297,20 +1506,20 @@ durchreisende(FILE * F, const region * r, const faction * f) } else { bytes = (int)strlcpy(bufp, unitname(u), size); } - if (wrptr(&bufp, &size, bytes)!=0) { + if (wrptr(&bufp, &size, bytes) != 0) { WARN_STATIC_BUFFER(); break; } - + if (counter + 1 < maxtravel) { bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) { + if (wrptr(&bufp, &size, bytes) != 0) { WARN_STATIC_BUFFER(); break; } } else if (counter + 1 == maxtravel) { bytes = (int)strlcpy(bufp, LOC(f->locale, "list_and"), size); - if (wrptr(&bufp, &size, bytes)!=0) { + if (wrptr(&bufp, &size, bytes) != 0) { WARN_STATIC_BUFFER(); break; } @@ -1324,26 +1533,34 @@ durchreisende(FILE * F, const region * r, const faction * f) } else { bytes = (int)strlcpy(bufp, " haben die Region durchquert.", size); } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); *bufp = 0; rparagraph(F, buf, 0, 0, 0); } } -static int -buildingmaintenance(const building * b, const resource_type * rtype) +static int buildingmaintenance(const building * b, const resource_type * rtype) { - const building_type * bt = b->type; - int c, cost=0; + const building_type *bt = b->type; + + int c, cost = 0; + static boolean init = false; - static const curse_type * nocost_ct; - if (!init) { init = true; nocost_ct = ct_find("nocostbuilding"); } + + static const curse_type *nocost_ct; + + if (!init) { + init = true; + nocost_ct = ct_find("nocostbuilding"); + } if (curse_active(get_curse(b->attribs, nocost_ct))) { return 0; } - for (c=0;bt->maintenance && bt->maintenance[c].number;++c) { - const maintenance * m = bt->maintenance + c; - if (m->rtype==rtype) { + for (c = 0; bt->maintenance && bt->maintenance[c].number; ++c) { + const maintenance *m = bt->maintenance + c; + + if (m->rtype == rtype) { if (fval(m, MTF_VARIABLE)) cost += (b->size * m->number); else @@ -1354,24 +1571,30 @@ buildingmaintenance(const building * b, const resource_type * rtype) } static int -report_template(const char * filename, report_context * ctx, const char * charset) +report_template(const char *filename, report_context * ctx, const char *charset) { - faction * f = ctx->f; + faction *f = ctx->f; + region *r; - FILE * F = fopen(filename, "wt"); - seen_region * sr = NULL; - char buf[8192], * bufp; + + FILE *F = fopen(filename, "wt"); + + seen_region *sr = NULL; + + char buf[8192], *bufp; + size_t size; + int bytes; - + int enc = xmlParseCharEncoding(charset); - if (F==NULL) { + if (F == NULL) { perror(filename); return -1; } - if (enc==XML_CHAR_ENCODING_UTF8) { + if (enc == XML_CHAR_ENCODING_UTF8) { const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; fwrite(utf8_bom, 1, 3, F); } @@ -1383,33 +1606,40 @@ report_template(const char * filename, report_context * ctx, const char * charse rps_nowrap(F, ""); rnl(F); - sprintf(buf, "%s %s \"%s\"", LOC(f->locale, "ERESSEA"), factionid(f), LOC(f->locale, "enterpasswd")); + sprintf(buf, "%s %s \"%s\"", LOC(f->locale, "ERESSEA"), factionid(f), + LOC(f->locale, "enterpasswd")); rps_nowrap(F, buf); rnl(F); rps_nowrap(F, ""); rnl(F); - sprintf(buf, "; ECHECK -l -w4 -r%d -v%s", f->race->recruitcost, ECHECK_VERSION); + sprintf(buf, "; ECHECK -l -w4 -r%d -v%s", f->race->recruitcost, + ECHECK_VERSION); /* -v3.4: ECheck Version 3.4.x */ rps_nowrap(F, buf); rnl(F); - for (r=ctx->first; sr==NULL && r!=ctx->last; r=r->next) { + for (r = ctx->first; sr == NULL && r != ctx->last; r = r->next) { sr = find_seen(ctx->seen, r); } - for (;sr!=NULL;sr=sr->next) { - region * r = sr->r; + for (; sr != NULL; sr = sr->next) { + region *r = sr->r; + unit *u; + int dh = 0; - if (sr->modemode < see_unit) + continue; for (u = r->units; u; u = u->next) { if (u->faction == f && !fval(u->race, RCF_INVISIBLE)) { - order * ord; + order *ord; + if (!dh) { - plane * pl = getplane(r); + plane *pl = getplane(r); + int nx = r->x, ny = r->y; pnormalize(&nx, &ny, pl); @@ -1417,15 +1647,15 @@ report_template(const char * filename, report_context * ctx, const char * charse rps_nowrap(F, ""); rnl(F); if (pl && pl->id != 0) { - sprintf(buf, "%s %d,%d,%d ; %s", LOC(f->locale, parameters[P_REGION]), - nx, ny, pl->id, rname(r, f->locale)); + sprintf(buf, "%s %d,%d,%d ; %s", LOC(f->locale, + parameters[P_REGION]), nx, ny, pl->id, rname(r, f->locale)); } else { - sprintf(buf, "%s %d,%d ; %s", LOC(f->locale, parameters[P_REGION]), + sprintf(buf, "%s %d,%d ; %s", LOC(f->locale, parameters[P_REGION]), nx, ny, rname(r, f->locale)); } rps_nowrap(F, buf); rnl(F); - sprintf(buf,"; ECheck Lohn %d", wage(r, f, f->race, turn+1)); + sprintf(buf, "; ECheck Lohn %d", wage(r, f, f->race, turn + 1)); rps_nowrap(F, buf); rnl(F); rps_nowrap(F, ""); @@ -1436,18 +1666,22 @@ report_template(const char * filename, report_context * ctx, const char * charse bufp = buf; size = sizeof(buf) - 1; bytes = snprintf(bufp, size, "%s %s; %s [%d,%d$", - LOC(u->faction->locale, parameters[P_UNIT]), - unitid(u), u->name, u->number, get_money(u)); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + LOC(u->faction->locale, parameters[P_UNIT]), + unitid(u), u->name, u->number, get_money(u)); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); if (u->building != NULL && fval(u, UFL_OWNER)) { - building * b = u->building; + building *b = u->building; + int cost = buildingmaintenance(b, r_silver); if (cost > 0) { bytes = (int)strlcpy(bufp, ",U", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, itoa10(cost), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } else if (u->ship) { if (fval(u, UFL_OWNER)) { @@ -1455,16 +1689,20 @@ report_template(const char * filename, report_context * ctx, const char * charse } else { bytes = (int)strlcpy(bufp, ",s", size); } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, shipid(u->ship), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } if (lifestyle(u) == 0) { bytes = (int)strlcpy(bufp, ",I", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } bytes = (int)strlcpy(bufp, "]", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); *bufp = 0; rps_nowrap(F, buf); @@ -1473,22 +1711,23 @@ report_template(const char * filename, report_context * ctx, const char * charse for (ord = u->old_orders; ord; ord = ord->next) { /* this new order will replace the old defaults */ strcpy(buf, " "); - write_order(ord, buf+2, sizeof(buf)-2); + write_order(ord, buf + 2, sizeof(buf) - 2); rps_nowrap(F, buf); rnl(F); } for (ord = u->orders; ord; ord = ord->next) { - if (u->old_orders && is_repeated(ord)) continue; /* unit has defaults */ + if (u->old_orders && is_repeated(ord)) + continue; /* unit has defaults */ if (is_persistent(ord)) { strcpy(buf, " "); - write_order(ord, buf+2, sizeof(buf)-2); + write_order(ord, buf + 2, sizeof(buf) - 2); rps_nowrap(F, buf); rnl(F); } } /* If the lastorder begins with an @ it should have - * been printed in the loop before. */ + * been printed in the loop before. */ } } } @@ -1502,24 +1741,32 @@ report_template(const char * filename, report_context * ctx, const char * charse } static void -show_allies(const faction * f, const ally * allies, char * buf, size_t size) +show_allies(const faction * f, const ally * allies, char *buf, size_t size) { int allierte = 0; - int i=0, h, hh = 0; - int bytes, dh = 0; - const ally * sf; - char * bufp = buf; /* buf already contains data */ - --size; /* leave room for a null-terminator */ + int i = 0, h, hh = 0; + + int bytes, dh = 0; + + const ally *sf; + + char *bufp = buf; /* buf already contains data */ + + --size; /* leave room for a null-terminator */ for (sf = allies; sf; sf = sf->next) { int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); - if (mode > 0) ++allierte; + + if (mode > 0) + ++allierte; } for (sf = allies; sf; sf = sf->next) { int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); - if (mode <= 0) continue; + + if (mode <= 0) + continue; i++; if (dh) { if (i == allierte) { @@ -1527,70 +1774,81 @@ show_allies(const faction * f, const ally * allies, char * buf, size_t size) } else { bytes = (int)strlcpy(bufp, ", ", size); } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } dh = 1; hh = 0; bytes = (int)strlcpy(bufp, factionname(sf->faction), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, " (", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); if ((mode & HELP_ALL) == HELP_ALL) { bytes = (int)strlcpy(bufp, "Alles", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } else { for (h = 1; h < HELP_ALL; h *= 2) { int p = MAXPARAMS; + if ((mode & h) == h) { switch (h) { - case HELP_TRAVEL: - p = P_TRAVEL; - break; - case HELP_MONEY: - p = P_MONEY; - break; - case HELP_FIGHT: - p = P_FIGHT; - break; - case HELP_GIVE: - p = P_GIVE; - break; - case HELP_GUARD: - p = P_GUARD; - break; - case HELP_FSTEALTH: - p = P_FACTIONSTEALTH; - break; + case HELP_TRAVEL: + p = P_TRAVEL; + break; + case HELP_MONEY: + p = P_MONEY; + break; + case HELP_FIGHT: + p = P_FIGHT; + break; + case HELP_GIVE: + p = P_GIVE; + break; + case HELP_GUARD: + p = P_GUARD; + break; + case HELP_FSTEALTH: + p = P_FACTIONSTEALTH; + break; } } - if (p!=MAXPARAMS) { + if (p != MAXPARAMS) { if (hh) { bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } bytes = (int)strlcpy(bufp, parameters[p], size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); hh = 1; } } } bytes = (int)strlcpy(bufp, ")", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); *bufp = 0; } -static void -allies(FILE * F, const faction * f) +static void allies(FILE * F, const faction * f) { - const group * g = f->groups; + const group *g = f->groups; + char buf[16384]; if (f->allies) { int bytes; + size_t size = sizeof(buf); + if (!f->allies->next) { bytes = (int)strlcpy(buf, "Wir helfen der Partei ", size); } else { @@ -1605,7 +1863,9 @@ allies(FILE * F, const faction * f) while (g) { if (g->allies) { int bytes; + size_t size = sizeof(buf); + if (!g->allies->next) { bytes = snprintf(buf, size, "%s hilft der Partei ", g->name); } else { @@ -1620,36 +1880,40 @@ allies(FILE * F, const faction * f) } } -static void -guards(FILE * F, const region * r, const faction * see) +static void guards(FILE * F, const region * r, const faction * see) { /* die Partei see sieht dies; wegen * "unbekannte Partei", wenn man es selbst ist... */ - faction* guardians[512]; + faction *guardians[512]; int nextguard = 0; unit *u; + int i; boolean tarned = false; + /* Bewachung */ for (u = r->units; u; u = u->next) { - if (is_guard(u, GUARD_ALL)!=0) { - faction *f = u->faction; + if (is_guard(u, GUARD_ALL) != 0) { + faction *f = u->faction; + faction *fv = visible_faction(see, u); - if(fv != f && see != fv) { + if (fv != f && see != fv) { f = fv; } if (f != see && fval(u, UFL_ANON_FACTION)) { - tarned=true; + tarned = true; } else { - for (i=0;i!=nextguard;++i) if (guardians[i]==f) break; - if (i==nextguard) { + for (i = 0; i != nextguard; ++i) + if (guardians[i] == f) + break; + if (i == nextguard) { guardians[nextguard++] = f; } } @@ -1658,67 +1922,80 @@ guards(FILE * F, const region * r, const faction * see) if (nextguard || tarned) { char buf[8192]; - char * bufp = buf; - size_t size = sizeof(buf) - 1; - int bytes; - - bytes = (int)strlcpy(bufp, "Die Region wird von ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - for (i = 0; i!=nextguard+(tarned?1:0); ++i) { - if (i!=0) { - if (i == nextguard-(tarned?0:1)) { + char *bufp = buf; + + size_t size = sizeof(buf) - 1; + + int bytes; + + bytes = (int)strlcpy(bufp, "Die Region wird von ", size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + + for (i = 0; i != nextguard + (tarned ? 1 : 0); ++i) { + if (i != 0) { + if (i == nextguard - (tarned ? 0 : 1)) { bytes = (int)strlcpy(bufp, LOC(see->locale, "list_and"), size); } else { bytes = (int)strlcpy(bufp, ", ", size); } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } - if (ilocale, "nr_addresses"), false); rnl(F); - while (flist!=NULL) { - const faction * f = (const faction *)ql_get(flist, qi); + while (flist != NULL) { + const faction *f = (const faction *)ql_get(flist, qi); + if (!is_monsters(f)) { char buf[8192]; + char label = '-'; - sprintf(buf, "%s: %s; %s", factionname(f), f->email, f->banner?f->banner:""); - if (uf==f) label = '*'; - else if (ALLIED(uf, f)) label = 'o'; - else if (alliedfaction(NULL, uf, f, HELP_ALL)) label = '+'; + sprintf(buf, "%s: %s; %s", factionname(f), f->email, + f->banner ? f->banner : ""); + if (uf == f) + label = '*'; + else if (ALLIED(uf, f)) + label = 'o'; + else if (alliedfaction(NULL, uf, f, HELP_ALL)) + label = '+'; rparagraph(F, buf, 4, 0, label); } @@ -1729,59 +2006,77 @@ list_address(FILE * F, const faction * uf, quicklist * seenfactions) } static void -nr_ship(FILE * F, const seen_region * sr, const ship * sh, const faction * f, const unit * captain) +nr_ship(FILE * F, const seen_region * sr, const ship * sh, const faction * f, + const unit * captain) { - const region * r = sr->r; - char buffer[8192], * bufp = buffer; + const region *r = sr->r; + + char buffer[8192], *bufp = buffer; + size_t size = sizeof(buffer) - 1; + int bytes; + char ch; rnl(F); if (captain && captain->faction == f) { int n = 0, p = 0; + getshipweight(sh, &n, &p); - n = (n+99) / 100; /* 1 Silber = 1 GE */ + n = (n + 99) / 100; /* 1 Silber = 1 GE */ bytes = snprintf(bufp, size, "%s, %s, (%d/%d)", shipname(sh), LOC(f->locale, sh->type->name[0]), n, shipcapacity(sh) / 100); } else { - bytes = snprintf(bufp, size, "%s, %s", shipname(sh), LOC(f->locale, sh->type->name[0])); + bytes = + snprintf(bufp, size, "%s, %s", shipname(sh), LOC(f->locale, + sh->type->name[0])); } - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); - assert(sh->type->construction->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */ - if (sh->size!=sh->type->construction->maxsize) { + assert(sh->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (sh->size != sh->type->construction->maxsize) { bytes = snprintf(bufp, size, ", %s (%d/%d)", LOC(f->locale, "nr_undercons"), sh->size, sh->type->construction->maxsize); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } if (sh->damage) { - int percent = (sh->damage*100+DAMAGE_SCALE-1)/(sh->size*DAMAGE_SCALE); - bytes = snprintf(bufp, size, ", %d%% %s", percent, LOC(f->locale, "nr_damaged")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + int percent = + (sh->damage * 100 + DAMAGE_SCALE - 1) / (sh->size * DAMAGE_SCALE); + bytes = + snprintf(bufp, size, ", %d%% %s", percent, LOC(f->locale, "nr_damaged")); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } if (!fval(r->terrain, SEA_REGION)) { if (sh->coast != NODIRECTION) { bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, LOC(f->locale, coasts[sh->coast]), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } ch = 0; if (sh->display && sh->display[0]) { bytes = (int)strlcpy(bufp, "; ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, sh->display, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); ch = sh->display[strlen(sh->display) - 1]; } if (ch != '!' && ch != '?' && ch != '.') { bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } *bufp = 0; rparagraph(F, buffer, 2, 0, 0); @@ -1790,61 +2085,79 @@ nr_ship(FILE * F, const seen_region * sr, const ship * sh, const faction * f, co } static void -nr_building(FILE *F, const seen_region * sr, const building * b, const faction * f) +nr_building(FILE * F, const seen_region * sr, const building * b, + const faction * f) { int i, bytes; - const char * name, * bname, * billusion = NULL; - const struct locale * lang = NULL; - char buffer[8192], * bufp = buffer; + + const char *name, *bname, *billusion = NULL; + + const struct locale *lang = NULL; + + char buffer[8192], *bufp = buffer; + size_t size = sizeof(buffer) - 1; rnl(F); - if (f) lang = f->locale; + if (f) + lang = f->locale; - bytes = snprintf(bufp, size, "%s, %s %d, ", buildingname(b), LOC(f->locale, "nr_size"), b->size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = + snprintf(bufp, size, "%s, %s %d, ", buildingname(b), LOC(f->locale, + "nr_size"), b->size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); report_building(b, &bname, &billusion); - name = LOC(lang, billusion?billusion:bname); + name = LOC(lang, billusion ? billusion : bname); bytes = (int)strlcpy(bufp, name, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); if (billusion) { - unit * owner = building_owner(b); - if (owner && owner->faction==f) { + unit *owner = building_owner(b); + + if (owner && owner->faction == f) { /* illusion. report real type */ name = LOC(lang, bname); bytes = snprintf(bufp, size, " (%s)", name); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } if (b->size < b->type->maxsize) { bytes = (int)strlcpy(bufp, " (im Bau)", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } - if (b->besieged > 0 && sr->mode>=see_lighthouse) { + if (b->besieged > 0 && sr->mode >= see_lighthouse) { bytes = (int)strlcpy(bufp, ", belagert von ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, itoa10(b->besieged), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, " Personen ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); if (b->besieged >= b->size * SIEGEFACTOR) { bytes = (int)strlcpy(bufp, "(abgeschnitten)", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } i = 0; if (b->display && b->display[0]) { bytes = (int)strlcpy(bufp, "; ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, b->display, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); i = b->display[strlen(b->display) - 1]; } - #ifdef WDW_PYRAMID if (i != '!' && i != '?' && i != '.') { @@ -1852,39 +2165,42 @@ nr_building(FILE *F, const seen_region * sr, const building * b, const faction * } if (b->type == bt_find("pyramid")) { - unit * owner = building_owner(b); + unit *owner = building_owner(b); + scat("Größenstufe "); icat(wdw_pyramid_level(b)); scat("."); - if (owner && owner->faction==f) { + if (owner && owner->faction == f) { const construction *ctype = b->type->construction; + int completed = b->size; + int c; scat(" Baukosten pro Größenpunkt: "); - while(ctype->improvement != NULL && - ctype->improvement != ctype && - ctype->maxsize > 0 && - ctype->maxsize <= completed) - { + while (ctype->improvement != NULL && + ctype->improvement != ctype && + ctype->maxsize > 0 && ctype->maxsize <= completed) { completed -= ctype->maxsize; ctype = ctype->improvement; } assert(ctype->materials != NULL); - for (c=0;ctype->materials[c].number;c++) { - const resource_type * rtype = ctype->materials[c].rtype; + for (c = 0; ctype->materials[c].number; c++) { + const resource_type *rtype = ctype->materials[c].rtype; + int number = ctype->materials[c].number; - if(c > 0) { + if (c > 0) { scat(", "); } icat(number); scat(" "); - scat(locale_string(lang, resourcename(rtype, number!=1?GR_PLURAL:0))); + scat(locale_string(lang, resourcename(rtype, + number != 1 ? GR_PLURAL : 0))); } scat("."); @@ -1894,82 +2210,108 @@ nr_building(FILE *F, const seen_region * sr, const building * b, const faction * scat("."); } } - #else if (i != '!' && i != '?' && i != '.') { bytes = (int)strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } - #endif *bufp = 0; rparagraph(F, buffer, 2, 0, 0); - if (sr->modemode < see_lighthouse) + return; nr_curses(F, f, b, TYP_BUILDING, 4); } -static void nr_paragraph(FILE * F, message * m, faction * f) +static void nr_paragraph(FILE * F, message * m, faction * f) { int bytes; - char buf[4096], * bufp = buf; + + char buf[4096], *bufp = buf; + size_t size = sizeof(buf) - 1; bytes = (int)nr_render(m, f->locale, bufp, size, f); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); msg_release(m); rparagraph(F, buf, 0, 0, 0); } int -report_plaintext(const char * filename, report_context * ctx, const char * charset) +report_plaintext(const char *filename, report_context * ctx, + const char *charset) { int flag = 0; + char ch; + int anyunits, no_units, no_people; + const struct region *r; - faction * f = ctx->f; + + faction *f = ctx->f; + unit *u; + char pzTime[64]; + attrib *a; - message * m; + + message *m; + unsigned char op; + int bytes, ix = want(O_STATISTICS); + int wants_stats = (f->options & ix); - FILE * F = fopen(filename, "wt"); - seen_region * sr = NULL; + + FILE *F = fopen(filename, "wt"); + + seen_region *sr = NULL; + char buf[8192]; - char * bufp; + + char *bufp; + int enc = xmlParseCharEncoding(charset); + size_t size; /* static variables can cope with writing for different turns */ static int thisseason = -1; + static int nextseason = -1; + static int gamecookie = -1; - if (gamecookie!=global.cookie) { + + if (gamecookie != global.cookie) { gamedate date; - get_gamedate(turn+1, &date); + + get_gamedate(turn + 1, &date); thisseason = date.season; - get_gamedate(turn+2, &date); + get_gamedate(turn + 2, &date); nextseason = date.season; gamecookie = global.cookie; } - if (F==NULL) { + if (F == NULL) { perror(filename); return -1; } - if (enc==XML_CHAR_ENCODING_UTF8) { + if (enc == XML_CHAR_ENCODING_UTF8) { const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; fwrite(utf8_bom, 1, 3, F); } strftime(pzTime, 64, "%A, %d. %B %Y, %H:%M", localtime(&ctx->report_time)); m = msg_message("nr_header_date", "game date", global.gamename, pzTime); + nr_render(m, f->locale, buf, sizeof(buf), f); msg_release(m); centre(F, buf, true); @@ -1977,19 +2319,18 @@ report_plaintext(const char * filename, report_context * ctx, const char * chars centre(F, gamedate_season(f->locale), true); rnl(F); sprintf(buf, "%s, %s/%s (%s)", factionname(f), - LOC(f->locale, rc_name(f->race, 1)), - LOC(f->locale, mkname("school", magic_school[f->magiegebiet])), - f->email); + LOC(f->locale, rc_name(f->race, 1)), + LOC(f->locale, mkname("school", magic_school[f->magiegebiet])), f->email); centre(F, buf, true); if (f_get_alliance(f)) { centre(F, alliancename(f->alliance), true); } if (f->age <= 2) { - const char * s; + const char *s; + if (f->age <= 1) { - ADDMSG(&f->msgs, msg_message("changepasswd", - "value", f->passw)); + ADDMSG(&f->msgs, msg_message("changepasswd", "value", f->passw)); } RENDER(f, buf, sizeof(buf), ("newbie_password", "password", f->passw)); rnl(F); @@ -2016,24 +2357,25 @@ report_plaintext(const char * filename, report_context * ctx, const char * chars rnl(F); #if SCORE_MODULE if (f->options & want(O_SCORE) && f->age > DISPLAYSCORE) { - RENDER(f, buf, sizeof(buf), ("nr_score", "score average", f->score, average_score_of_age(f->age, f->age / 24 + 1))); + RENDER(f, buf, sizeof(buf), ("nr_score", "score average", f->score, + average_score_of_age(f->age, f->age / 24 + 1))); centre(F, buf, true); } #endif #ifdef COUNT_AGAIN no_units = 0; no_people = 0; - for (u=f->units;u;u=u->nextF) { + for (u = f->units; u; u = u->nextF) { if (playerrace(u->race)) { ++no_people; no_units += u->number; - assert(f==u->faction); + assert(f == u->faction); } } - if (no_units!=f->no_units) { + if (no_units != f->no_units) { f->no_units = no_units; } - if (no_people!=f->num_people) { + if (no_people != f->num_people) { f->num_people = no_people; } #else @@ -2046,31 +2388,39 @@ report_plaintext(const char * filename, report_context * ctx, const char * chars centre(F, buf, true); if (f->race == new_race[RC_HUMAN]) { int maxmig = count_maxmigrants(f); - if (maxmig>0) { - m = msg_message("nr_migrants", "units maxunits", count_migrants(f), maxmig); + + if (maxmig > 0) { + m = + msg_message("nr_migrants", "units maxunits", count_migrants(f), maxmig); nr_render(m, f->locale, buf, sizeof(buf), f); msg_release(m); centre(F, buf, true); } } if (f_get_alliance(f)) { - m = msg_message("nr_alliance", "leader name id age", alliance_get_leader(f->alliance), f->alliance->name, f->alliance->id, turn-f->alliance_joindate); + m = + msg_message("nr_alliance", "leader name id age", + alliance_get_leader(f->alliance), f->alliance->name, f->alliance->id, + turn - f->alliance_joindate); nr_render(m, f->locale, buf, sizeof(buf), f); msg_release(m); centre(F, buf, true); } { int maxh = maxheroes(f); + if (maxh) { - message * msg = msg_message("nr_heroes", "units maxunits", countheroes(f), maxh); + message *msg = + msg_message("nr_heroes", "units maxunits", countheroes(f), maxh); nr_render(msg, f->locale, buf, sizeof(buf), f); msg_release(msg); centre(F, buf, true); } } - if (f->items!=NULL) { - message * msg = msg_message("nr_claims", "items", f->items); + if (f->items != NULL) { + message *msg = msg_message("nr_claims", "items", f->items); + nr_render(msg, f->locale, buf, sizeof(buf), f); msg_release(msg); rnl(F); @@ -2092,14 +2442,17 @@ report_plaintext(const char * filename, report_context * ctx, const char * chars bufp = buf; size = sizeof(buf) - 1; - bytes = snprintf(buf, size,"%s:", LOC(f->locale, "nr_options")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = snprintf(buf, size, "%s:", LOC(f->locale, "nr_options")); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); for (op = 0; op != MAXOPTIONS; op++) { if (f->options & want(op) && options[op]) { bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, LOC(f->locale, options[op]), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); flag++; } @@ -2116,21 +2469,25 @@ report_plaintext(const char * filename, report_context * ctx, const char * chars if (a) { rnl(F); centre(F, LOC(f->locale, "section_newspells"), true); - while (a && a->type==&at_reportspell) { - spell *sp = (spell *)a->data.v; + while (a && a->type == &at_reportspell) { + spell *sp = (spell *) a->data.v; + nr_spell(F, sp, f->locale); a = a->next; } } ch = 0; - for (a=a_find(f->attribs, &at_showitem);a && a->type==&at_showitem;a=a->next) { - const potion_type * ptype = resource2potion(((const item_type*)a->data.v)->rtype); - const char * description = NULL; - if (ptype!=NULL) { - const char * pname = resourcename(ptype->itype->rtype, 0); + for (a = a_find(f->attribs, &at_showitem); a && a->type == &at_showitem; + a = a->next) { + const potion_type *ptype = + resource2potion(((const item_type *)a->data.v)->rtype); + const char *description = NULL; - if (ch==0) { + if (ptype != NULL) { + const char *pname = resourcename(ptype->itype->rtype, 0); + + if (ch == 0) { rnl(F); centre(F, LOC(f->locale, "section_newpotions"), true); ch = 1; @@ -2138,31 +2495,38 @@ report_plaintext(const char * filename, report_context * ctx, const char * chars rnl(F); centre(F, LOC(f->locale, pname), true); - snprintf(buf, sizeof(buf), "%s %d", LOC(f->locale, "nr_level"), ptype->level); + snprintf(buf, sizeof(buf), "%s %d", LOC(f->locale, "nr_level"), + ptype->level); centre(F, buf, true); rnl(F); - + bufp = buf; size = sizeof(buf) - 1; bytes = snprintf(bufp, size, "%s: ", LOC(f->locale, "nr_herbsrequired")); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); if (ptype->itype->construction) { - requirement * m = ptype->itype->construction->materials; + requirement *m = ptype->itype->construction->materials; + while (m->number) { - bytes = (int)strlcpy(bufp, LOC(f->locale, resourcename(m->rtype, 0)), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = + (int)strlcpy(bufp, LOC(f->locale, resourcename(m->rtype, 0)), size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); ++m; if (m->number) - bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } *bufp = 0; centre(F, buf, true); rnl(F); - if (description==NULL) { - const char * potiontext = mkname("potion", pname); + if (description == NULL) { + const char *potiontext = mkname("potion", pname); + description = LOC(f->locale, potiontext); } centre(F, description, true); @@ -2178,31 +2542,38 @@ report_plaintext(const char * filename, report_context * ctx, const char * chars anyunits = 0; - for (r=ctx->first;sr==NULL && r!=ctx->last;r=r->next) { + for (r = ctx->first; sr == NULL && r != ctx->last; r = r->next) { sr = find_seen(ctx->seen, r); } - for (;sr!=NULL;sr=sr->next) { - region * r = sr->r; - int stealthmod = stealth_modifier(sr->mode); - building * b = r->buildings; - ship * sh = r->ships; + for (; sr != NULL; sr = sr->next) { + region *r = sr->r; - if (sr->modemode); + + building *b = r->buildings; + + ship *sh = r->ships; + + if (sr->mode < see_lighthouse) + continue; /* Beschreibung */ - if (sr->mode==see_unit) { + if (sr->mode == see_unit) { anyunits = 1; describe(F, sr, f); if (markets_module() && r->land) { - const item_type * lux = r_luxury(r); - const item_type * herb = r->land->herbtype; - message * m = 0; + const item_type *lux = r_luxury(r); + + const item_type *herb = r->land->herbtype; + + message *m = 0; + if (herb && lux) { m = msg_message("nr_market_info_p", "p1 p2", - lux?lux->rtype:0, herb?herb->rtype:0); + lux ? lux->rtype : 0, herb ? herb->rtype : 0); } else if (lux || herb) { m = msg_message("nr_market_info_s", "p1", - lux?lux->rtype:herb->rtype); + lux ? lux->rtype : herb->rtype); } if (m) { rnl(F); @@ -2210,21 +2581,19 @@ report_plaintext(const char * filename, report_context * ctx, const char * chars } // } else { - if (!fval(r->terrain, SEA_REGION) && rpeasants(r)/TRADE_FRACTION > 0) { + if (!fval(r->terrain, SEA_REGION) && rpeasants(r) / TRADE_FRACTION > 0) { rnl(F); prices(F, r, f); } } guards(F, r, f); durchreisende(F, r, f); - } - else { - if (sr->mode==see_far) { + } else { + if (sr->mode == see_far) { describe(F, sr, f); guards(F, r, f); durchreisende(F, r, f); - } - else if (sr->mode==see_lighthouse) { + } else if (sr->mode == see_lighthouse) { describe(F, sr, f); durchreisende(F, r, f); } else { @@ -2234,27 +2603,29 @@ report_plaintext(const char * filename, report_context * ctx, const char * chars } /* Statistik */ - if (wants_stats && sr->mode==see_unit) - statistics(F, r, f); + if (wants_stats && sr->mode == see_unit) + statistics(F, r, f); /* Nachrichten an REGION in der Region */ - if (sr->mode==see_unit || sr->mode==see_travel) { - message_list * mlist = r_getmessages(r, f); + if (sr->mode == see_unit || sr->mode == see_travel) { + message_list *mlist = r_getmessages(r, f); + rp_messages(F, r->msgs, f, 0, true); - if (mlist) rp_messages(F, mlist, f, 0, true); + if (mlist) + rp_messages(F, mlist, f, 0, true); } /* report all units. they are pre-sorted in an efficient manner */ u = r->units; while (b) { - while (b && (!u || u->building!=b)) { + while (b && (!u || u->building != b)) { nr_building(F, sr, b, f); b = b->next; } if (b) { nr_building(F, sr, b, f); - while (u && u->building==b) { + while (u && u->building == b) { nr_unit(F, f, u, 6, sr->mode); u = u->next; } @@ -2262,7 +2633,7 @@ report_plaintext(const char * filename, report_context * ctx, const char * chars } } while (u && !u->ship) { - if (stealthmod>INT_MIN) { + if (stealthmod > INT_MIN) { if (u->faction == f || cansee(f, r, u, stealthmod)) { nr_unit(F, f, u, 4, sr->mode); } @@ -2271,13 +2642,13 @@ report_plaintext(const char * filename, report_context * ctx, const char * chars u = u->next; } while (sh) { - while (sh && (!u || u->ship!=sh)) { + while (sh && (!u || u->ship != sh)) { nr_ship(F, sr, sh, f, NULL); sh = sh->next; } if (sh) { nr_ship(F, sr, sh, f, u); - while (u && u->ship==sh) { + while (u && u->ship == sh) { nr_unit(F, f, u, 6, sr->mode); u = u->next; } @@ -2302,13 +2673,14 @@ report_plaintext(const char * filename, report_context * ctx, const char * chars return 0; } -void -base36conversion(void) +void base36conversion(void) { - region * r; - for (r=regions;r;r=r->next) { - unit * u; - for (u=r->units;u;u=u->next) { + region *r; + + for (r = regions; r; r = r->next) { + unit *u; + + for (u = r->units; u; u = u->next) { if (forbiddenid(u->no)) { uunhash(u); u->no = newunitid(); @@ -2321,14 +2693,14 @@ base36conversion(void) #define FMAXHASH 1021 struct fsee { - struct fsee * nexthash; - faction * f; + struct fsee *nexthash; + faction *f; struct see { - struct see * next; - faction * seen; - unit * proof; - } * see; -} * fsee[FMAXHASH]; + struct see *next; + faction *seen; + unit *proof; + } *see; +} *fsee[FMAXHASH]; #define REPORT_NR (1 << O_REPORT) #define REPORT_CR (1 << O_COMPUTER) @@ -2337,17 +2709,23 @@ struct fsee { #define REPORT_BZIP2 (1 << O_BZIP2) -unit * -can_find(faction * f, faction * f2) +unit *can_find(faction * f, faction * f2) { int key = f->no % FMAXHASH; - struct fsee * fs = fsee[key]; - struct see * ss; - if (f==f2) return f->units; - while (fs && fs->f!=f) fs=fs->nexthash; - if (!fs) return NULL; - ss=fs->see; - while (ss && ss->seen!=f2) ss=ss->next; + + struct fsee *fs = fsee[key]; + + struct see *ss; + + if (f == f2) + return f->units; + while (fs && fs->f != f) + fs = fs->nexthash; + if (!fs) + return NULL; + ss = fs->see; + while (ss && ss->seen != f2) + ss = ss->next; if (ss) { /* bei TARNE PARTEI yxz muss die Partei von unit proof nicht * wirklich Partei f2 sein! */ @@ -2357,81 +2735,94 @@ can_find(faction * f, faction * f2) return NULL; } -static void -add_find(faction * f, unit * u, faction *f2) +static void add_find(faction * f, unit * u, faction * f2) { /* faction f sees f2 through u */ int key = f->no % FMAXHASH; - struct fsee ** fp = &fsee[key]; - struct fsee * fs; - struct see ** sp; - struct see * ss; - while (*fp && (*fp)->f!=f) fp=&(*fp)->nexthash; + + struct fsee **fp = &fsee[key]; + + struct fsee *fs; + + struct see **sp; + + struct see *ss; + + while (*fp && (*fp)->f != f) + fp = &(*fp)->nexthash; if (!*fp) { fs = *fp = calloc(sizeof(struct fsee), 1); fs->f = f; - } else fs = *fp; + } else + fs = *fp; sp = &fs->see; - while (*sp && (*sp)->seen!=f2) sp=&(*sp)->next; + while (*sp && (*sp)->seen != f2) + sp = &(*sp)->next; if (!*sp) { ss = *sp = calloc(sizeof(struct see), 1); ss->proof = u; ss->seen = f2; - } else ss = *sp; + } else + ss = *sp; ss->proof = u; } -static void -update_find(void) +static void update_find(void) { - region * r; + region *r; + static boolean initial = true; - if (initial) for (r=regions;r;r=r->next) { - unit * u; - for (u=r->units;u;u=u->next) { - faction * lastf = u->faction; - unit * u2; - for (u2=r->units;u2;u2=u2->next) { - if (u2->faction==lastf || u2->faction==u->faction) - continue; - if (seefaction(u->faction, r, u2, 0)) { - faction *fv = visible_faction(u->faction, u2); - lastf = fv; - add_find(u->faction, u2, fv); + if (initial) + for (r = regions; r; r = r->next) { + unit *u; + + for (u = r->units; u; u = u->next) { + faction *lastf = u->faction; + + unit *u2; + + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->faction == lastf || u2->faction == u->faction) + continue; + if (seefaction(u->faction, r, u2, 0)) { + faction *fv = visible_faction(u->faction, u2); + + lastf = fv; + add_find(u->faction, u2, fv); + } } } } - } initial = false; } -boolean -kann_finden(faction * f1, faction * f2) +boolean kann_finden(faction * f1, faction * f2) { update_find(); - return (boolean)(can_find(f1, f2)!=NULL); + return (boolean) (can_find(f1, f2) != NULL); } /******* end summary ******/ -void -register_nr(void) +void register_nr(void) { - if (!nocr) register_reporttype("nr", &report_plaintext, 1<nexthash; + struct fsee *fs = fsee[i]->nexthash; + free(fsee[i]); fsee[i] = fs; } } } - diff --git a/src/gamecode/report.h b/src/gamecode/report.h index e294adf6d..8a338115f 100644 --- a/src/gamecode/report.h +++ b/src/gamecode/report.h @@ -22,4 +22,3 @@ extern "C" { } #endif #endif - diff --git a/src/gamecode/spy.c b/src/gamecode/spy.c index 42747dfba..26f543b3d 100644 --- a/src/gamecode/spy.c +++ b/src/gamecode/spy.c @@ -56,72 +56,86 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* in spy steht der Unterschied zwischen Wahrnehmung des Opfers und * Spionage des Spions */ -void -spy_message(int spy, const unit *u, const unit *target) +void spy_message(int spy, const unit * u, const unit * target) { - const char * str = report_kampfstatus(target, u->faction->locale); + const char *str = report_kampfstatus(target, u->faction->locale); - ADDMSG(&u->faction->msgs, msg_message("spyreport", "spy target status", u, target, str)); + ADDMSG(&u->faction->msgs, msg_message("spyreport", "spy target status", u, + target, str)); if (spy > 20) { - sc_mage * mage = get_mage(target); + sc_mage *mage = get_mage(target); + /* bei Magiern Zaubersprüche und Magiegebiet */ if (mage) { - ADDMSG(&u->faction->msgs, msg_message("spyreport_mage", "target type", target, magic_school[mage->magietyp])); + ADDMSG(&u->faction->msgs, msg_message("spyreport_mage", "target type", + target, magic_school[mage->magietyp])); } } if (spy > 6) { - faction * fv = visible_faction(u->faction,target); - if (fv && fv!=target->faction) { + faction *fv = visible_faction(u->faction, target); + + if (fv && fv != target->faction) { /* wahre Partei */ - ADDMSG(&u->faction->msgs, msg_message("spyreport_faction", "target faction", target, target->faction)); + ADDMSG(&u->faction->msgs, msg_message("spyreport_faction", + "target faction", target, target->faction)); ql_set_insert(&u->faction->seen_factions, target->faction); } } if (spy > 0) { int first = 1; + int found = 0; - skill * sv; + + skill *sv; + char buf[4096]; buf[0] = 0; - for (sv = target->skills;sv!=target->skills+target->skill_size;++sv) { - if (sv->level>0) { + for (sv = target->skills; sv != target->skills + target->skill_size; ++sv) { + if (sv->level > 0) { found++; if (first == 1) { first = 0; } else { strncat(buf, ", ", sizeof(buf)); } - strncat(buf, (const char *)skillname(sv->id, u->faction->locale), sizeof(buf)); + strncat(buf, (const char *)skillname(sv->id, u->faction->locale), + sizeof(buf)); strncat(buf, " ", sizeof(buf)); - strncat(buf, itoa10(eff_skill(target, sv->id, target->region)), sizeof(buf)); + strncat(buf, itoa10(eff_skill(target, sv->id, target->region)), + sizeof(buf)); } } if (found) { - ADDMSG(&u->faction->msgs, msg_message("spyreport_skills", "target skills", target, buf)); + ADDMSG(&u->faction->msgs, msg_message("spyreport_skills", "target skills", + target, buf)); } if (target->items) { - ADDMSG(&u->faction->msgs, msg_message("spyreport_items", "target items", target, target->items)); + ADDMSG(&u->faction->msgs, msg_message("spyreport_items", "target items", + target, target->items)); } } } -int -spy_cmd(unit * u, struct order * ord) +int spy_cmd(unit * u, struct order *ord) { unit *target; + int spy, observe; + double spychance, observechance; - region * r = u->region; + + region *r = u->region; init_tokens(ord); skip_token(); target = getunit(r, u->faction); if (!target) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, + "feedback_unit_not_found", "")); return 0; } if (!can_contact(r, u, target)) { @@ -133,10 +147,10 @@ spy_cmd(unit * u, struct order * ord) return 0; } /* Die Grundchance für einen erfolgreichen Spionage-Versuch ist 10%. - * Für jeden Talentpunkt, den das Spionagetalent das Tarnungstalent - * des Opfers übersteigt, erhöht sich dieses um 5%*/ + * Für jeden Talentpunkt, den das Spionagetalent das Tarnungstalent + * des Opfers übersteigt, erhöht sich dieses um 5%*/ spy = eff_skill(u, SK_SPY, r) - eff_skill(target, SK_STEALTH, r); - spychance = 0.1 + MAX(spy*0.05, 0.0); + spychance = 0.1 + MAX(spy * 0.05, 0.0); if (chance(spychance)) { produceexp(u, SK_SPY, u->number); @@ -146,65 +160,74 @@ spy_cmd(unit * u, struct order * ord) } /* der Spion kann identifiziert werden, wenn das Opfer bessere - * Wahrnehmung als das Ziel Tarnung + Spionage/2 hat */ + * Wahrnehmung als das Ziel Tarnung + Spionage/2 hat */ observe = eff_skill(target, SK_PERCEPTION, r) - - (effskill(u, SK_STEALTH) + eff_skill(u, SK_SPY, r)/2); + - (effskill(u, SK_STEALTH) + eff_skill(u, SK_SPY, r) / 2); if (invisible(u, target) >= u->number) { observe = MIN(observe, 0); } /* Anschließend wird - unabhängig vom Erfolg - gewürfelt, ob der - * Spionageversuch bemerkt wurde. Die Wahrscheinlich dafür ist (100 - - * SpionageSpion*5 + WahrnehmungOpfer*2)%. */ + * Spionageversuch bemerkt wurde. Die Wahrscheinlich dafür ist (100 - + * SpionageSpion*5 + WahrnehmungOpfer*2)%. */ observechance = 1.0 - (eff_skill(u, SK_SPY, r) * 0.05) + (eff_skill(target, SK_PERCEPTION, r) * 0.02); if (chance(observechance)) { - ADDMSG(&target->faction->msgs, msg_message("spydetect", - "spy target", observe>0?u:NULL, target)); + ADDMSG(&target->faction->msgs, msg_message("spydetect", + "spy target", observe > 0 ? u : NULL, target)); } return 0; } -void -set_factionstealth(unit * u, faction * f) +void set_factionstealth(unit * u, faction * f) { - region * lastr = NULL; + region *lastr = NULL; + /* for all units mu of our faction, check all the units in the region - * they are in, if their visible faction is f, it's ok. use lastr to - * avoid testing the same region twice in a row. */ - unit * mu = u->faction->units; - while (mu!=NULL) { - if (mu->number && mu->region!=lastr) { - unit * ru = mu->region->units; + * they are in, if their visible faction is f, it's ok. use lastr to + * avoid testing the same region twice in a row. */ + unit *mu = u->faction->units; + + while (mu != NULL) { + if (mu->number && mu->region != lastr) { + unit *ru = mu->region->units; + lastr = mu->region; - while (ru!=NULL) { + while (ru != NULL) { if (ru->number) { - faction * fv = visible_faction(f, ru); - if (fv==f) { - if (cansee(f, lastr, ru, 0)) break; + faction *fv = visible_faction(f, ru); + + if (fv == f) { + if (cansee(f, lastr, ru, 0)) + break; } } ru = ru->next; } - if (ru!=NULL) break; + if (ru != NULL) + break; } mu = mu->nextF; } - if (mu!=NULL) { - attrib * a = a_find(u->attribs, &at_otherfaction); - if (!a) a = a_add(&u->attribs, make_otherfaction(f)); - else a->data.v = f; + if (mu != NULL) { + attrib *a = a_find(u->attribs, &at_otherfaction); + + if (!a) + a = a_add(&u->attribs, make_otherfaction(f)); + else + a->data.v = f; } } -int -setstealth_cmd(unit * u, struct order * ord) +int setstealth_cmd(unit * u, struct order *ord) { const char *s; + int level, rule; - const race * trace; + + const race *trace; init_tokens(ord); skip_token(); @@ -221,12 +244,16 @@ setstealth_cmd(unit * u, struct order * ord) if (trace) { /* Dämonen können sich nur als andere Spielerrassen tarnen */ if (u->race == new_race[RC_DAEMON]) { - race_t allowed[] = { RC_DWARF, RC_ELF, RC_ORC, RC_GOBLIN, RC_HUMAN, + race_t allowed[] = { RC_DWARF, RC_ELF, RC_ORC, RC_GOBLIN, RC_HUMAN, RC_TROLL, RC_DAEMON, RC_INSECT, RC_HALFLING, RC_CAT, RC_AQUARIAN, - NORACE }; + NORACE + }; int i; - for (i=0;allowed[i]!=NORACE;++i) if (new_race[allowed[i]]==trace) break; - if (new_race[allowed[i]]==trace) { + + for (i = 0; allowed[i] != NORACE; ++i) + if (new_race[allowed[i]] == trace) + break; + if (new_race[allowed[i]] == trace) { u->irace = trace; if (u->race->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs)) set_racename(&u->attribs, NULL); @@ -235,8 +262,10 @@ setstealth_cmd(unit * u, struct order * ord) } /* Singdrachen können sich nur als Drachen tarnen */ - if (u->race == new_race[RC_SONGDRAGON] || u->race == new_race[RC_BIRTHDAYDRAGON]) { - if (trace==new_race[RC_SONGDRAGON]||trace==new_race[RC_FIREDRAGON]||trace==new_race[RC_DRAGON]||trace==new_race[RC_WYRM]) { + if (u->race == new_race[RC_SONGDRAGON] + || u->race == new_race[RC_BIRTHDAYDRAGON]) { + if (trace == new_race[RC_SONGDRAGON] || trace == new_race[RC_FIREDRAGON] + || trace == new_race[RC_DRAGON] || trace == new_race[RC_WYRM]) { u->irace = trace; if (u->race->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs)) set_racename(&u->attribs, NULL); @@ -255,83 +284,93 @@ setstealth_cmd(unit * u, struct order * ord) return 0; } - switch(findparam(s, u->faction->locale)) { - case P_FACTION: - /* TARNE PARTEI [NICHT|NUMMER abcd] */ - rule = rule_stealth_faction(); - if (!rule) break; - s = getstrtoken(); - if(!s || *s == 0) { - fset(u, UFL_ANON_FACTION); - } else if (findparam(s, u->faction->locale) == P_NOT) { - freset(u, UFL_ANON_FACTION); - } else if (findkeyword(s, u->faction->locale) == K_NUMBER) { - const char *s2 = (const char *)getstrtoken(); - int nr = -1; + switch (findparam(s, u->faction->locale)) { + case P_FACTION: + /* TARNE PARTEI [NICHT|NUMMER abcd] */ + rule = rule_stealth_faction(); + if (!rule) + break; + s = getstrtoken(); + if (!s || *s == 0) { + fset(u, UFL_ANON_FACTION); + } else if (findparam(s, u->faction->locale) == P_NOT) { + freset(u, UFL_ANON_FACTION); + } else if (findkeyword(s, u->faction->locale) == K_NUMBER) { + const char *s2 = (const char *)getstrtoken(); - if (s2) nr = atoi36(s2); - if (!s2 || *s2 == 0 || nr == u->faction->no) { - a_removeall(&u->attribs, &at_otherfaction); - } else { - struct faction * f = findfaction(nr); - if (f==NULL) { - cmistake(u, ord, 66, MSG_EVENT); + int nr = -1; + + if (s2) + nr = atoi36(s2); + if (!s2 || *s2 == 0 || nr == u->faction->no) { + a_removeall(&u->attribs, &at_otherfaction); } else { - set_factionstealth(u, f); + struct faction *f = findfaction(nr); + + if (f == NULL) { + cmistake(u, ord, 66, MSG_EVENT); + } else { + set_factionstealth(u, f); + } } + } else { + cmistake(u, ord, 289, MSG_EVENT); } - } else { - cmistake(u, ord, 289, MSG_EVENT); - } - break; - case P_ANY: - case P_NOT: - /* TARNE ALLES (was nicht so alles geht?) */ - u_seteffstealth(u, -1); - break; - default: - if (isdigit(s[0])) { - /* Tarnungslevel setzen */ - level = atoi((const char *)s); - if (level > effskill(u, SK_STEALTH)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_lowstealth", "")); - return 0; + break; + case P_ANY: + case P_NOT: + /* TARNE ALLES (was nicht so alles geht?) */ + u_seteffstealth(u, -1); + break; + default: + if (isdigit(s[0])) { + /* Tarnungslevel setzen */ + level = atoi((const char *)s); + if (level > effskill(u, SK_STEALTH)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_lowstealth", + "")); + return 0; + } + u_seteffstealth(u, level); + } else if (u->race->flags & RCF_SHAPESHIFTANY) { + set_racename(&u->attribs, s); } - u_seteffstealth(u, level); - } else if (u->race->flags & RCF_SHAPESHIFTANY) { - set_racename(&u->attribs, s); - } } return 0; } -static int -crew_skill(region * r, faction * f, ship * sh, skill_t sk) +static int crew_skill(region * r, faction * f, ship * sh, skill_t sk) { int value = 0; + unit *u; - for (u=r->units;u;u=u->next) { + for (u = r->units; u; u = u->next) { if (u->ship == sh && u->faction == f) { int s = eff_skill(u, sk, r); + value = MAX(s, value); } } return value; } -static int -try_destruction(unit * u, unit * u2, const ship *sh, int skilldiff) +static int try_destruction(unit * u, unit * u2, const ship * sh, int skilldiff) { const char *destruction_success_msg = "destroy_ship_0"; + const char *destruction_failed_msg = "destroy_ship_1"; + const char *destruction_detected_msg = "destroy_ship_2"; + const char *detect_failure_msg = "destroy_ship_3"; + const char *object_destroyed_msg = "destroy_ship_4"; if (skilldiff == 0) { /* tell the unit that the attempt failed: */ - ADDMSG(&u->faction->msgs, msg_message(destruction_failed_msg, "ship unit", sh, u)); + ADDMSG(&u->faction->msgs, msg_message(destruction_failed_msg, "ship unit", + sh, u)); /* tell the enemy about the attempt: */ if (u2) { ADDMSG(&u2->faction->msgs, msg_message(detect_failure_msg, "ship", sh)); @@ -339,36 +378,43 @@ try_destruction(unit * u, unit * u2, const ship *sh, int skilldiff) return 0; } else if (skilldiff < 0) { /* tell the unit that the attempt was detected: */ - ADDMSG(&u2->faction->msgs, msg_message(destruction_detected_msg, "ship unit", sh, u)); + ADDMSG(&u2->faction->msgs, msg_message(destruction_detected_msg, + "ship unit", sh, u)); /* tell the enemy whodunit: */ if (u2) { ADDMSG(&u2->faction->msgs, msg_message(detect_failure_msg, "ship", sh)); } return 0; } else { - /* tell the unit that the attempt succeeded */ - ADDMSG(&u->faction->msgs, msg_message(destruction_success_msg, "ship unit", sh, u)); + /* tell the unit that the attempt succeeded */ + ADDMSG(&u->faction->msgs, msg_message(destruction_success_msg, "ship unit", + sh, u)); if (u2) { ADDMSG(&u2->faction->msgs, msg_message(object_destroyed_msg, "ship", sh)); } } - return 1; /* success */ + return 1; /* success */ } -static void -sink_ship(region * r, ship * sh, const char *name, unit * saboteur) +static void sink_ship(region * r, ship * sh, const char *name, unit * saboteur) { unit **ui, *u; - region *safety = r; - int i; - direction_t d; - double probability = 0.0; - message * sink_msg = NULL; - faction * f; - for (f=NULL,u=r->units;u;u=u->next) { + region *safety = r; + + int i; + + direction_t d; + + double probability = 0.0; + + message *sink_msg = NULL; + + faction *f; + + for (f = NULL, u = r->units; u; u = u->next) { /* slight optimization to avoid dereferencing u->faction each time */ - if (f!=u->faction) { + if (f != u->faction) { f = u->faction; freset(f, FFL_SELECT); } @@ -379,7 +425,8 @@ sink_ship(region * r, ship * sh, const char *name, unit * saboteur) probability = CANAL_SWIMMER_CHANCE; } else { for (d = 0; d != MAXDIRECTIONS; ++d) { - region * rn = rconnect(r, d); + region *rn = rconnect(r, d); + if (!fval(rn->terrain, SEA_REGION) && !move_blocked(NULL, r, rn)) { safety = rn; probability = OCEAN_SWIMMER_CHANCE; @@ -393,7 +440,7 @@ sink_ship(region * r, ship * sh, const char *name, unit * saboteur) /* inform this faction about the sinking ship: */ if (!fval(u->faction, FFL_SELECT)) { fset(u->faction, FFL_SELECT); - if (sink_msg==NULL) { + if (sink_msg == NULL) { sink_msg = msg_message("sink_msg", "ship region", sh, r); } add_message(&f->msgs, sink_msg); @@ -401,7 +448,8 @@ sink_ship(region * r, ship * sh, const char *name, unit * saboteur) if (u->ship == sh) { int dead = 0; - message * msg; + + message *msg; /* if this fails, I misunderstood something: */ for (i = 0; i != u->number; ++i) @@ -411,7 +459,8 @@ sink_ship(region * r, ship * sh, const char *name, unit * saboteur) if (dead != u->number) { /* she will live. but her items get stripped */ if (dead > 0) { - msg = msg_message("sink_lost_msg", "dead region unit", dead, safety, u); + msg = + msg_message("sink_lost_msg", "dead region unit", dead, safety, u); } else { msg = msg_message("sink_saved_msg", "region unit", safety, u); } @@ -431,26 +480,32 @@ sink_ship(region * r, ship * sh, const char *name, unit * saboteur) msg_release(msg); if (dead == u->number) { /* the poor creature, she dies */ - if (remove_unit(ui, u)!=0) { + if (remove_unit(ui, u) != 0) { ui = &u->next; } } } } - if (sink_msg) msg_release(sink_msg); + if (sink_msg) + msg_release(sink_msg); /* finally, get rid of the ship */ remove_ship(&sh->region->ships, sh); } -int -sabotage_cmd(unit * u, struct order * ord) +int sabotage_cmd(unit * u, struct order *ord) { const char *s; + int i; + ship *sh; + unit *u2; + char buffer[DISPLAYSIZE]; - region * r = u->region; + + region *r = u->region; + int skdiff; init_tokens(ord); @@ -460,21 +515,22 @@ sabotage_cmd(unit * u, struct order * ord) i = findparam(s, u->faction->locale); switch (i) { - case P_SHIP: - sh = u->ship; - if (!sh) { - cmistake(u, u->thisorder, 144, MSG_EVENT); - return 0; - } - u2 = shipowner(sh); - skdiff = eff_skill(u, SK_SPY, r)-crew_skill(r, u2->faction, sh, SK_PERCEPTION); - if (try_destruction(u, u2, sh, skdiff)) { + case P_SHIP: + sh = u->ship; + if (!sh) { + cmistake(u, u->thisorder, 144, MSG_EVENT); + return 0; + } + u2 = shipowner(sh); + skdiff = + eff_skill(u, SK_SPY, r) - crew_skill(r, u2->faction, sh, SK_PERCEPTION); + if (try_destruction(u, u2, sh, skdiff)) { sink_ship(r, sh, buffer, u); - } - break; - default: - cmistake(u, u->thisorder, 9, MSG_EVENT); - return 0; + } + break; + default: + cmistake(u, u->thisorder, 9, MSG_EVENT); + return 0; } return 0; diff --git a/src/gamecode/spy.h b/src/gamecode/spy.h index 6c56eaa53..7f6eded75 100644 --- a/src/gamecode/spy.h +++ b/src/gamecode/spy.h @@ -22,14 +22,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -struct unit; -struct region; -struct strlist; + struct unit; + struct region; + struct strlist; -extern int setstealth_cmd(struct unit * u, struct order * ord); -extern int spy_cmd(struct unit * u, struct order * ord); -extern int sabotage_cmd(struct unit * u, struct order * ord); -extern void spy_message(int spy, const struct unit *u, const struct unit *target); + extern int setstealth_cmd(struct unit *u, struct order *ord); + extern int spy_cmd(struct unit *u, struct order *ord); + extern int sabotage_cmd(struct unit *u, struct order *ord); + extern void spy_message(int spy, const struct unit *u, + const struct unit *target); #define OCEAN_SWIMMER_CHANCE 0.1 #define CANAL_SWIMMER_CHANCE 0.9 diff --git a/src/gamecode/study.c b/src/gamecode/study.c index 2fbcb270e..d3ed0e1f2 100644 --- a/src/gamecode/study.c +++ b/src/gamecode/study.c @@ -57,29 +57,30 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define TEACHNUMBER 10 -static skill_t -getskill(const struct locale * lang) +static skill_t getskill(const struct locale *lang) { - return findskill(getstrtoken(), lang); + return findskill(getstrtoken(), lang); } -magic_t -getmagicskill(const struct locale * lang) +magic_t getmagicskill(const struct locale * lang) { - struct tnode * tokens = get_translations(lang, UT_MAGIC); + struct tnode *tokens = get_translations(lang, UT_MAGIC); + variant token; - const char * s = getstrtoken(); + + const char *s = getstrtoken(); if (s && s[0]) { - if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { - return (magic_t)token.i; + if (findtoken(tokens, s, &token) == E_TOK_SUCCESS) { + return (magic_t) token.i; } else { char buffer[3]; + buffer[0] = s[0]; buffer[1] = s[1]; buffer[2] = '\0'; - if (findtoken(tokens, buffer, &token)==E_TOK_SUCCESS) { - return (magic_t)token.i; + if (findtoken(tokens, buffer, &token) == E_TOK_SUCCESS) { + return (magic_t) token.i; } } } @@ -88,40 +89,45 @@ getmagicskill(const struct locale * lang) /* ------------------------------------------------------------- */ /* Vertraute und Kröten sind keine Migranten */ -boolean -is_migrant(unit *u) +boolean is_migrant(unit * u) { - if (u->race == u->faction->race) return false; + if (u->race == u->faction->race) + return false; - if (fval(u->race, RCF_UNDEAD|RCF_ILLUSIONARY)) return false; - if (is_familiar(u)) return false; - if (u->race == new_race[RC_TOAD]) return false; + if (fval(u->race, RCF_UNDEAD | RCF_ILLUSIONARY)) + return false; + if (is_familiar(u)) + return false; + if (u->race == new_race[RC_TOAD]) + return false; return true; } /* ------------------------------------------------------------- */ -boolean -magic_lowskill(unit *u) +boolean magic_lowskill(unit * u) { - if (u->race == new_race[RC_TOAD]) return true; - return false; + if (u->race == new_race[RC_TOAD]) + return true; + return false; } /* ------------------------------------------------------------- */ -int -study_cost(unit *u, skill_t sk) +int study_cost(unit * u, skill_t sk) { static int cost[MAXSKILLS]; + int stufe, k = 50; - if (cost[sk]==0) { + if (cost[sk] == 0) { char buffer[256]; + sprintf(buffer, "skills.cost.%s", skillnames[sk]); cost[sk] = get_param_int(global.parameters, buffer, -1); } - if (cost[sk]>=0) return cost[sk]; + if (cost[sk] >= 0) + return cost[sk]; switch (sk) { case SK_SPY: @@ -132,10 +138,10 @@ study_cost(unit *u, skill_t sk) case SK_ALCHEMY: return 200; break; - case SK_MAGIC: /* Die Magiekosten betragen 50+Summe(50*Stufe) */ + case SK_MAGIC: /* Die Magiekosten betragen 50+Summe(50*Stufe) */ /* 'Stufe' ist dabei die nächste zu erreichende Stufe */ stufe = 1 + get_level(u, SK_MAGIC); - return k*(1+((stufe+1)*stufe/2)); + return k * (1 + ((stufe + 1) * stufe / 2)); break; } return 0; @@ -143,33 +149,32 @@ study_cost(unit *u, skill_t sk) /* ------------------------------------------------------------- */ -static void -init_learning(struct attrib * a) +static void init_learning(struct attrib *a) { - a->data.v = calloc(sizeof(teaching_info), 1); + a->data.v = calloc(sizeof(teaching_info), 1); } -static void -done_learning(struct attrib * a) +static void done_learning(struct attrib *a) { - free(a->data.v); + free(a->data.v); } const attrib_type at_learning = { - "learning", - init_learning, done_learning, NULL, NULL, NULL, - ATF_UNIQUE + "learning", + init_learning, done_learning, NULL, NULL, NULL, + ATF_UNIQUE }; -static int -study_days(unit * student, skill_t sk) +static int study_days(unit * student, skill_t sk) { int speed = 30; + if (student->race->study_speed) { speed += student->race->study_speed[sk]; - if (speed<30) { - skill * sv = get_skill(student, sk); - if (sv==0) { + if (speed < 30) { + skill *sv = get_skill(student, sk); + + if (sv == 0) { speed = 30; } } @@ -178,94 +183,102 @@ study_days(unit * student, skill_t sk) } static int -teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, - boolean report, int * academy) +teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, + boolean report, int *academy) { - teaching_info * teach = NULL; - attrib * a; + teaching_info *teach = NULL; + + attrib *a; + int n; /* learning sind die Tage, die sie schon durch andere Lehrer zugute - * geschrieben bekommen haben. Total darf dies nicht über 30 Tage pro Mann - * steigen. - * - * n ist die Anzahl zusätzlich gelernter Tage. n darf max. die Differenz - * von schon gelernten Tagen zum MAX(30 Tage pro Mann) betragen. */ + * geschrieben bekommen haben. Total darf dies nicht über 30 Tage pro Mann + * steigen. + * + * n ist die Anzahl zusätzlich gelernter Tage. n darf max. die Differenz + * von schon gelernten Tagen zum MAX(30 Tage pro Mann) betragen. */ - if (magic_lowskill(student)){ + if (magic_lowskill(student)) { cmistake(teacher, teacher->thisorder, 292, MSG_EVENT); return 0; } n = 30 * student->number; a = a_find(student->attribs, &at_learning); - if (a!=NULL) { - teach = (teaching_info*)a->data.v; + if (a != NULL) { + teach = (teaching_info *) a->data.v; n -= teach->value; } n = MIN(n, nteaching); if (n != 0) { - struct building * b = inside_building(teacher); - const struct building_type * btype = b?b->type:NULL; + struct building *b = inside_building(teacher); + + const struct building_type *btype = b ? b->type : NULL; + int index = 0; - if (teach==NULL) { + if (teach == NULL) { a = a_add(&student->attribs, a_new(&at_learning)); - teach = (teaching_info*)a->data.v; + teach = (teaching_info *) a->data.v; } else { - while (teach->teachers[index] && index!=MAXTEACHERS) ++index; + while (teach->teachers[index] && index != MAXTEACHERS) + ++index; } - if (indexteachers[index++] = teacher; - if (indexteachers[index] = NULL; + if (index < MAXTEACHERS) + teach->teachers[index++] = teacher; + if (index < MAXTEACHERS) + teach->teachers[index] = NULL; teach->value += n; /* Solange Akademien größenbeschränkt sind, sollte Lehrer und - * Student auch in unterschiedlichen Gebäuden stehen dürfen */ + * Student auch in unterschiedlichen Gebäuden stehen dürfen */ if (btype == bt_find("academy") - && student->building && student->building->type == bt_find("academy")) - { + && student->building && student->building->type == bt_find("academy")) { int j = study_cost(student, sk); + j = MAX(50, j * 2); /* kann Einheit das zahlen? */ if (get_pooled(student, oldresourcetype[R_SILVER], GET_DEFAULT, j) >= j) { /* Jeder Schüler zusätzlich +10 Tage wenn in Uni. */ - teach->value += (n / 30) * 10; /* learning erhöhen */ + teach->value += (n / 30) * 10; /* learning erhöhen */ /* Lehrer zusätzlich +1 Tag pro Schüler. */ - if (academy) *academy += n; - } /* sonst nehmen sie nicht am Unterricht teil */ + if (academy) + *academy += n; + } /* sonst nehmen sie nicht am Unterricht teil */ } /* Teaching ist die Anzahl Leute, denen man noch was beibringen kann. Da - * hier nicht n verwendet wird, werden die Leute gezählt und nicht die - * effektiv gelernten Tage. -> FALSCH ? (ENNO) - * - * Eine Einheit A von 11 Mann mit Talent 0 profitiert vom ersten Lehrer B - * also 10x30=300 tage, und der zweite Lehrer C lehrt für nur noch 1x30=30 - * Tage (damit das Maximum von 11x30=330 nicht überschritten wird). - * - * Damit es aber in der Ausführung nicht auf die Reihenfolge drauf ankommt, - * darf der zweite Lehrer C keine weiteren Einheiten D mehr lehren. Also - * wird student 30 Tage gutgeschrieben, aber teaching sinkt auf 0 (300-11x30 <= - * 0). - * - * Sonst träte dies auf: - * - * A: lernt B: lehrt A C: lehrt A D D: lernt - * - * Wenn B vor C dran ist, lehrt C nur 30 Tage an A (wie oben) und - * 270 Tage an D. - * - * Ist C aber vor B dran, lehrt C 300 tage an A, und 0 tage an D, - * und B lehrt auch 0 tage an A. - * - * Deswegen darf C D nie lehren dürfen. - * - * -> Das ist wirr. wer hat das entworfen? - * Besser wäre, man macht erst vorab alle zuordnungen, und dann - * die Talentänderung (enno). - */ + * hier nicht n verwendet wird, werden die Leute gezählt und nicht die + * effektiv gelernten Tage. -> FALSCH ? (ENNO) + * + * Eine Einheit A von 11 Mann mit Talent 0 profitiert vom ersten Lehrer B + * also 10x30=300 tage, und der zweite Lehrer C lehrt für nur noch 1x30=30 + * Tage (damit das Maximum von 11x30=330 nicht überschritten wird). + * + * Damit es aber in der Ausführung nicht auf die Reihenfolge drauf ankommt, + * darf der zweite Lehrer C keine weiteren Einheiten D mehr lehren. Also + * wird student 30 Tage gutgeschrieben, aber teaching sinkt auf 0 (300-11x30 <= + * 0). + * + * Sonst träte dies auf: + * + * A: lernt B: lehrt A C: lehrt A D D: lernt + * + * Wenn B vor C dran ist, lehrt C nur 30 Tage an A (wie oben) und + * 270 Tage an D. + * + * Ist C aber vor B dran, lehrt C 300 tage an A, und 0 tage an D, + * und B lehrt auch 0 tage an A. + * + * Deswegen darf C D nie lehren dürfen. + * + * -> Das ist wirr. wer hat das entworfen? + * Besser wäre, man macht erst vorab alle zuordnungen, und dann + * die Talentänderung (enno). + */ nteaching = MAX(0, nteaching - student->number * 30); @@ -273,21 +286,25 @@ teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, return n; } -int -teach_cmd(unit * u, struct order * ord) +int teach_cmd(unit * u, struct order *ord) { - static const curse_type * gbdream_ct = NULL; - plane * pl; - region * r = u->region; - int teaching, i, j, count, academy=0; + static const curse_type *gbdream_ct = NULL; + + plane *pl; + + region *r = u->region; + + int teaching, i, j, count, academy = 0; + unit *u2; + skill_t sk = NOSKILL; - if (gbdream_ct==0) gbdream_ct = ct_find("gbdream"); + if (gbdream_ct == 0) + gbdream_ct = ct_find("gbdream"); if (gbdream_ct) { if (get_curse(u->region->attribs, gbdream_ct)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "gbdream_noteach", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "gbdream_noteach", "")); return 0; } } @@ -305,16 +322,16 @@ teach_cmd(unit * u, struct order * ord) teaching = u->number * 30 * TEACHNUMBER; - if ((i = get_effect(u, oldpotiontype[P_FOOL])) > 0) { /* Trank "Dumpfbackenbrot" */ + if ((i = get_effect(u, oldpotiontype[P_FOOL])) > 0) { /* Trank "Dumpfbackenbrot" */ i = MIN(i, u->number * TEACHNUMBER); /* Trank wirkt pro Schüler, nicht pro Lehrer */ teaching -= i * 30; change_effect(u, oldpotiontype[P_FOOL], -i); j = teaching / 30; - ADDMSG(&u->faction->msgs, msg_message("teachdumb", - "teacher amount", u, j)); + ADDMSG(&u->faction->msgs, msg_message("teachdumb", "teacher amount", u, j)); } - if (teaching == 0) return 0; + if (teaching == 0) + return 0; u2 = 0; @@ -324,31 +341,40 @@ teach_cmd(unit * u, struct order * ord) skip_token(); #if TEACH_ALL - if (getparam(u->faction->locale)==P_ANY) { - unit * student = r->units; + if (getparam(u->faction->locale) == P_ANY) { + unit *student = r->units; + skill_t teachskill[MAXSKILLS]; + int i = 0; + do { sk = getskill(u->faction->locale); - teachskill[i++]=sk; - } while (sk!=NOSKILL); + teachskill[i++] = sk; + } while (sk != NOSKILL); while (teaching && student) { if (student->faction == u->faction) { #ifdef NEW_DAEMONHUNGER_RULE - if (LongHunger(student)) continue; + if (LongHunger(student)) + continue; #else - if (fval(student, UFL_HUNGER)) continue; + if (fval(student, UFL_HUNGER)) + continue; #endif if (get_keyword(student->thisorder) == K_STUDY) { /* Input ist nun von student->thisorder !! */ init_tokens(student->thisorder); skip_token(); sk = getskill(student->faction->locale); - if (sk!=NOSKILL && teachskill[0]!=NOSKILL) { - for (i=0;teachskill[i]!=NOSKILL;++i) if (sk==teachskill[i]) break; + if (sk != NOSKILL && teachskill[0] != NOSKILL) { + for (i = 0; teachskill[i] != NOSKILL; ++i) + if (sk == teachskill[i]) + break; sk = teachskill[i]; } - if (sk != NOSKILL && eff_skill_study(u, sk, r)-TEACHDIFFERENCE > eff_skill_study(student, sk, r)) { + if (sk != NOSKILL + && eff_skill_study(u, sk, + r) - TEACHDIFFERENCE > eff_skill_study(student, sk, r)) { teaching -= teach_unit(u, student, teaching, sk, true, &academy); } } @@ -357,18 +383,23 @@ teach_cmd(unit * u, struct order * ord) } #ifdef TEACH_FRIENDS while (teaching && student) { - if (student->faction != u->faction && alliedunit(u, student->faction, HELP_GUARD)) { + if (student->faction != u->faction + && alliedunit(u, student->faction, HELP_GUARD)) { #ifdef NEW_DAEMONHUNGER_RULE - if (LongHunger(student)) continue; + if (LongHunger(student)) + continue; #else - if (fval(student, UFL_HUNGER)) continue; + if (fval(student, UFL_HUNGER)) + continue; #endif if (get_keyword(student->thisorder) == K_STUDY) { /* Input ist nun von student->thisorder !! */ init_tokens(student->thisorder); skip_token(); sk = getskill(student->faction->locale); - if (sk != NOSKILL && eff_skill_study(u, sk, r)-TEACHDIFFERENCE >= eff_skill(student, sk, r)) { + if (sk != NOSKILL + && eff_skill_study(u, sk, r) - TEACHDIFFERENCE >= eff_skill(student, + sk, r)) { teaching -= teach_unit(u, student, teaching, sk, true, &academy); } } @@ -376,34 +407,39 @@ teach_cmd(unit * u, struct order * ord) student = student->next; } #endif - } - else + } else #endif { char zOrder[4096]; - order * new_order; + + order *new_order; zOrder[0] = '\0'; init_tokens(ord); skip_token(); while (!parser_end()) { - unit * u2 = getunit(r, u->faction); + unit *u2 = getunit(r, u->faction); + boolean feedback; + ++count; /* Falls die Unit nicht gefunden wird, Fehler melden */ if (!u2) { char tbuf[20]; - const char * uid; - const char * token; + + const char *uid; + + const char *token; + /* Finde den string, der den Fehler verursacht hat */ parser_pushstate(); init_tokens(ord); skip_token(); - for (j=0; j!=count-1; ++j) { + for (j = 0; j != count - 1; ++j) { /* skip over the first 'count' units */ getunit(r, u->faction); } @@ -416,21 +452,23 @@ teach_cmd(unit * u, struct order * ord) } else { token = getstrtoken(); sprintf(tbuf, "%s %s", LOC(u->faction->locale, - parameters[P_TEMP]), token); + parameters[P_TEMP]), token); uid = tbuf; } ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unitnotfound_id", - "id", uid)); + "id", uid)); parser_popstate(); continue; } - feedback = u->faction==u2->faction || alliedunit(u2, u->faction, HELP_GUARD); + feedback = u->faction == u2->faction + || alliedunit(u2, u->faction, HELP_GUARD); /* Neuen Befehl zusammenbauen. TEMP-Einheiten werden automatisch in * ihre neuen Nummern übersetzt. */ - if (zOrder[0]) strcat(zOrder, " "); + if (zOrder[0]) + strcat(zOrder, " "); strcat(zOrder, unitid(u2)); if (get_keyword(u2->thisorder) != K_STUDY) { @@ -453,20 +491,26 @@ teach_cmd(unit * u, struct order * ord) } /* u is teacher, u2 is student */ - if (eff_skill_study(u2, sk, r) > eff_skill_study(u, sk, r)-TEACHDIFFERENCE) { + if (eff_skill_study(u2, sk, r) > eff_skill_study(u, sk, + r) - TEACHDIFFERENCE) { if (feedback) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "teach_asgood", "student", u2)); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "teach_asgood", + "student", u2)); } continue; } if (sk == SK_MAGIC) { /* ist der Magier schon spezialisiert, so versteht er nur noch - * Lehrer seines Gebietes */ - sc_mage * mage1 = get_mage(u); - sc_mage * mage2 = get_mage(u2); - if (!mage2 || !mage1 || (mage2->magietyp!=M_GRAY && mage1->magietyp!=mage2->magietyp)) { + * Lehrer seines Gebietes */ + sc_mage *mage1 = get_mage(u); + + sc_mage *mage2 = get_mage(u2); + + if (!mage2 || !mage1 || (mage2->magietyp != M_GRAY + && mage1->magietyp != mage2->magietyp)) { if (feedback) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_different_magic", "target", u2)); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, + "error_different_magic", "target", u2)); } continue; } @@ -476,64 +520,83 @@ teach_cmd(unit * u, struct order * ord) } new_order = create_order(K_TEACH, u->faction->locale, "%s", zOrder); replace_order(&u->orders, ord, new_order); - free_order(new_order); /* parse_order & set_order have each increased the refcount */ + free_order(new_order); /* parse_order & set_order have each increased the refcount */ } - if (academy && sk!=NOSKILL) { - academy = academy/30; /* anzahl gelehrter wochen, max. 10 */ - learn_skill(u, sk, academy/30.0/TEACHNUMBER); + if (academy && sk != NOSKILL) { + academy = academy / 30; /* anzahl gelehrter wochen, max. 10 */ + learn_skill(u, sk, academy / 30.0 / TEACHNUMBER); } return 0; } -static double -study_speedup(unit * u) +static double study_speedup(unit * u) { -#define MINTURN 5 /* 5 */ -#define OFSTURN 2 /* 2 */ - if (turn>MINTURN) { +#define MINTURN 5 /* 5 */ +#define OFSTURN 2 /* 2 */ + if (turn > MINTURN) { static int speed_rule = -1; - if (speed_rule<0) { + + if (speed_rule < 0) { speed_rule = get_param_int(global.parameters, "study.speedup", 0); } - if (speed_rule==1) { + if (speed_rule == 1) { double learn_age = OFSTURN; + int i; - for (i=0;i!=u->skill_size;++i) { - skill * sv = u->skills+i; - double learn_time = sv->level*(sv->level+1)/2.0; + + for (i = 0; i != u->skill_size; ++i) { + skill *sv = u->skills + i; + + double learn_time = sv->level * (sv->level + 1) / 2.0; + learn_age += learn_time; } if (learn_age < turn) { - return 2.0-learn_age/turn; + return 2.0 - learn_age / turn; } } } return 1.0; } -int -learn_cmd(unit * u, order * ord) +int learn_cmd(unit * u, order * ord) { region *r = u->region; + int p; + magic_t mtyp; + int l; + int studycost, days; + double multi = 1.0; - attrib * a = NULL; - teaching_info * teach = NULL; + + attrib *a = NULL; + + teaching_info *teach = NULL; + int money = 0; + skill_t sk; + int maxalchemy = 0; + static int learn_newskills = -1; - if (learn_newskills<0) { - const char * str = get_param(global.parameters, "study.newskills"); - if (str && strcmp(str, "false")==0) learn_newskills = 0; - else learn_newskills = 1; + + if (learn_newskills < 0) { + const char *str = get_param(global.parameters, "study.newskills"); + + if (str && strcmp(str, "false") == 0) + learn_newskills = 0; + else + learn_newskills = 1; } if ((u->race->flags & RCF_NOLEARN) || fval(u, UFL_WERE)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_race_nolearn", "race", u->race)); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_race_nolearn", "race", + u->race)); return 0; } @@ -546,7 +609,7 @@ learn_cmd(unit * u, order * ord) return 0; } if (SkillCap(sk) && SkillCap(sk) <= effskill(u, sk)) { - cmistake(u, ord, 771, MSG_EVENT); + cmistake(u, ord, 771, MSG_EVENT); return 0; } /* Hack: Talente mit Malus -99 können nicht gelernt werden */ @@ -554,9 +617,10 @@ learn_cmd(unit * u, order * ord) cmistake(u, ord, 771, MSG_EVENT); return 0; } - if (learn_newskills==0) { - skill * sv = get_skill(u, sk); - if (sv==NULL) { + if (learn_newskills == 0) { + skill *sv = get_skill(u, sk); + + if (sv == NULL) { /* we can only learn skills we already have */ cmistake(u, ord, 771, MSG_EVENT); return 0; @@ -564,8 +628,8 @@ learn_cmd(unit * u, order * ord) } /* snotlings können Talente nur bis T8 lernen */ - if (u->race == new_race[RC_SNOTLING]){ - if (get_level(u, sk) >= 8){ + if (u->race == new_race[RC_SNOTLING]) { + if (get_level(u, sk) >= 8) { cmistake(u, ord, 308, MSG_EVENT); return 0; } @@ -573,21 +637,23 @@ learn_cmd(unit * u, order * ord) p = studycost = study_cost(u, sk); a = a_find(u->attribs, &at_learning); - if (a!=NULL) { - teach = (teaching_info*)a->data.v; + if (a != NULL) { + teach = (teaching_info *) a->data.v; } /* keine kostenpflichtigen Talente für Migranten. Vertraute sind - * keine Migranten, wird in is_migrant abgefangen. Vorsicht, - * studycost darf hier noch nicht durch Akademie erhöht sein */ + * keine Migranten, wird in is_migrant abgefangen. Vorsicht, + * studycost darf hier noch nicht durch Akademie erhöht sein */ if (studycost > 0 && !ExpensiveMigrants() && is_migrant(u)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_migrants_nolearn", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_migrants_nolearn", + "")); return 0; } /* Akademie: */ { - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; + struct building *b = inside_building(u); + + const struct building_type *btype = b ? b->type : NULL; if (btype && btype == bt_find("academy")) { studycost = MAX(50, studycost * 2); @@ -595,60 +661,63 @@ learn_cmd(unit * u, order * ord) } if (sk == SK_MAGIC) { - if (u->number > 1){ + if (u->number > 1) { cmistake(u, ord, 106, MSG_MAGIC); return 0; } - if (is_familiar(u)){ + if (is_familiar(u)) { /* Vertraute zählen nicht zu den Magiern einer Partei, - * können aber nur Graue Magie lernen */ + * können aber nur Graue Magie lernen */ mtyp = M_GRAY; - if (!is_mage(u)) create_mage(u, mtyp); + if (!is_mage(u)) + create_mage(u, mtyp); } else if (!has_skill(u, SK_MAGIC)) { int mmax = skill_limit(u->faction, SK_MAGIC); + /* Die Einheit ist noch kein Magier */ - if (count_skill(u->faction, SK_MAGIC) + u->number > mmax) - { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_magicians", "amount", mmax)); + if (count_skill(u->faction, SK_MAGIC) + u->number > mmax) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_magicians", + "amount", mmax)); return 0; } mtyp = getmagicskill(u->faction->locale); if (mtyp == M_NONE || mtyp == M_GRAY) { /* wurde kein Magiegebiet angegeben, wird davon - * ausgegangen, daß das normal gelernt werden soll */ - if(u->faction->magiegebiet != 0) { + * ausgegangen, daß das normal gelernt werden soll */ + if (u->faction->magiegebiet != 0) { mtyp = u->faction->magiegebiet; } else { /* Es wurde kein Magiegebiet angegeben und die Partei - * hat noch keins gewählt. */ + * hat noch keins gewählt. */ mtyp = getmagicskill(u->faction->locale); - if (mtyp==M_NONE) { + if (mtyp == M_NONE) { cmistake(u, ord, 178, MSG_MAGIC); return 0; } } } - if (mtyp != u->faction->magiegebiet){ + if (mtyp != u->faction->magiegebiet) { /* Es wurde versucht, ein anderes Magiegebiet zu lernen - * als das der Partei */ - if (u->faction->magiegebiet != 0){ + * als das der Partei */ + if (u->faction->magiegebiet != 0) { cmistake(u, ord, 179, MSG_MAGIC); return 0; } else { /* Lernt zum ersten mal Magie und legt damit das - * Magiegebiet der Partei fest */ + * Magiegebiet der Partei fest */ u->faction->magiegebiet = mtyp; } } - if (!is_mage(u)) create_mage(u, mtyp); + if (!is_mage(u)) + create_mage(u, mtyp); } else { /* ist schon ein Magier und kein Vertrauter */ if (u->faction->magiegebiet == 0) { /* die Partei hat noch kein Magiegebiet gewählt. */ mtyp = getmagicskill(u->faction->locale); - if (mtyp == M_NONE){ + if (mtyp == M_NONE) { mtyp = getmagicskill(u->faction->locale); - if (mtyp==M_NONE) { + if (mtyp == M_NONE) { cmistake(u, ord, 178, MSG_MAGIC); return 0; } @@ -662,35 +731,38 @@ learn_cmd(unit * u, order * ord) maxalchemy = eff_skill(u, SK_ALCHEMY, r); if (!has_skill(u, SK_ALCHEMY)) { int amax = skill_limit(u->faction, SK_ALCHEMY); + if (count_skill(u->faction, SK_ALCHEMY) + u->number > amax) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_alchemists", "amount", amax)); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_alchemists", + "amount", amax)); return 0; } } } if (studycost) { int cost = studycost * u->number; + money = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, cost); money = MIN(money, cost); } if (money < studycost * u->number) { - studycost = p; /* Ohne Univertreurung */ + studycost = p; /* Ohne Univertreurung */ money = MIN(money, studycost); - if (p>0 && money < studycost * u->number) { + if (p > 0 && money < studycost * u->number) { cmistake(u, ord, 65, MSG_EVENT); multi = money / (double)(studycost * u->number); } } - if (teach==NULL) { + if (teach == NULL) { a = a_add(&u->attribs, a_new(&at_learning)); - teach = (teaching_info*)a->data.v; + teach = (teaching_info *) a->data.v; teach->teachers[0] = 0; } - if (money>0) { + if (money > 0) { use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, money); ADDMSG(&u->faction->msgs, msg_message("studycost", - "unit region cost skill", u, u->region, money, sk)); + "unit region cost skill", u, u->region, money, sk)); } if (get_effect(u, oldpotiontype[P_WISE])) { @@ -707,12 +779,12 @@ learn_cmd(unit * u, order * ord) if (p != studycost) { /* ist_in_gebaeude(r, u, BT_UNIVERSITAET) == 1) { */ /* p ist Kosten ohne Uni, studycost mit; wenn - * p!=studycost, ist die Einheit zwangsweise - * in einer Uni */ + * p!=studycost, ist die Einheit zwangsweise + * in einer Uni */ teach->value += u->number * 10; } - if (is_cursed(r->attribs, C_BADLEARN,0)) { + if (is_cursed(r->attribs, C_BADLEARN, 0)) { teach->value -= u->number * 10; } @@ -721,69 +793,80 @@ learn_cmd(unit * u, order * ord) days = (int)((days + teach->value) * multi); /* the artacademy currently improves the learning of entertainment - of all units in the region, to be able to make it cumulative with - with an academy */ + of all units in the region, to be able to make it cumulative with + with an academy */ - if (sk == SK_ENTERTAINMENT && buildingtype_exists(r, bt_find("artacademy"), false)) { + if (sk == SK_ENTERTAINMENT + && buildingtype_exists(r, bt_find("artacademy"), false)) { days *= 2; } - if (fval(u, UFL_HUNGER)) days /= 2; + if (fval(u, UFL_HUNGER)) + days /= 2; while (days) { - if (days>=u->number*30) { + if (days >= u->number * 30) { learn_skill(u, sk, 1.0); - days -= u->number*30; + days -= u->number * 30; } else { - double chance = (double)days/u->number/30; + double chance = (double)days / u->number / 30; + learn_skill(u, sk, chance); days = 0; } } - if (a!=NULL) { - if (teach!=NULL) { + if (a != NULL) { + if (teach != NULL) { int index = 0; - while (teach->teachers[index] && index!=MAXTEACHERS) { - unit * teacher = teach->teachers[index++]; + + while (teach->teachers[index] && index != MAXTEACHERS) { + unit *teacher = teach->teachers[index++]; + if (teacher->faction != u->faction) { boolean feedback = alliedunit(u, teacher->faction, HELP_GUARD); + if (feedback) { ADDMSG(&teacher->faction->msgs, msg_message("teach_teacher", - "teacher student skill level", teacher, u, sk, - effskill(u, sk))); + "teacher student skill level", teacher, u, sk, + effskill(u, sk))); } ADDMSG(&u->faction->msgs, msg_message("teach_student", - "teacher student skill", teacher, u, sk)); + "teacher student skill", teacher, u, sk)); } } } a_remove(&u->attribs, a); a = NULL; } - fset(u, UFL_LONGACTION|UFL_NOTMOVING); + fset(u, UFL_LONGACTION | UFL_NOTMOVING); /* Anzeigen neuer Tränke */ /* Spruchlistenaktualiesierung ist in Regeneration */ if (sk == SK_ALCHEMY) { - const potion_type * ptype; - faction * f = u->faction; + const potion_type *ptype; + + faction *f = u->faction; + int skill = eff_skill(u, SK_ALCHEMY, r); - if (skill>maxalchemy) { - for (ptype=potiontypes; ptype; ptype=ptype->next) { + + if (skill > maxalchemy) { + for (ptype = potiontypes; ptype; ptype = ptype->next) { if (skill == ptype->level * 2) { - attrib * a = a_find(f->attribs, &at_showitem); - while (a && a->type==&at_showitem && a->data.v != ptype) a=a->next; - if (a==NULL || a->type!=&at_showitem) { + attrib *a = a_find(f->attribs, &at_showitem); + + while (a && a->type == &at_showitem && a->data.v != ptype) + a = a->next; + if (a == NULL || a->type != &at_showitem) { a = a_add(&f->attribs, a_new(&at_showitem)); - a->data.v = (void*) ptype->itype; + a->data.v = (void *)ptype->itype; } } } } - } - else if (sk==SK_MAGIC) { - sc_mage * mage = get_mage(u); + } else if (sk == SK_MAGIC) { + sc_mage *mage = get_mage(u); + if (!mage) { mage = create_mage(u, u->faction->magiegebiet); } diff --git a/src/gamecode/study.h b/src/gamecode/study.h index 6ea695a26..3527e3cec 100644 --- a/src/gamecode/study.h +++ b/src/gamecode/study.h @@ -23,23 +23,22 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern int teach_cmd(struct unit * u, struct order * ord); -extern int learn_cmd(struct unit * u, struct order * ord); + extern int teach_cmd(struct unit *u, struct order *ord); + extern int learn_cmd(struct unit *u, struct order *ord); -extern magic_t getmagicskill(const struct locale * lang); -extern boolean is_migrant(struct unit *u); -extern int study_cost(struct unit *u, skill_t talent); + extern magic_t getmagicskill(const struct locale *lang); + extern boolean is_migrant(struct unit *u); + extern int study_cost(struct unit *u, skill_t talent); #define MAXTEACHERS 4 -typedef struct teaching_info { - struct unit * teachers[MAXTEACHERS]; - int value; -} teaching_info; + typedef struct teaching_info { + struct unit *teachers[MAXTEACHERS]; + int value; + } teaching_info; -extern const struct attrib_type at_learning; + extern const struct attrib_type at_learning; #ifdef __cplusplus } #endif - #endif diff --git a/src/gamecode/summary.c b/src/gamecode/summary.c index 5e16a53c4..791aa0bfc 100644 --- a/src/gamecode/summary.c +++ b/src/gamecode/summary.c @@ -35,7 +35,7 @@ #include -#undef SUMMARY_BOM /* write a BOM in the summary file */ +#undef SUMMARY_BOM /* write a BOM in the summary file */ typedef struct summary { int waffen; @@ -63,36 +63,36 @@ typedef struct summary { int spielerpferde; int pferde; struct language { - struct language * next; + struct language *next; int number; - const struct locale * locale; - } * languages; + const struct locale *locale; + } *languages; } summary; -static char * -pcomp(double i, double j) +static char *pcomp(double i, double j) { static char buf[32]; - sprintf(buf, "%.0f (%s%.0f)", i, (i>=j)?"+":"", i-j); + + sprintf(buf, "%.0f (%s%.0f)", i, (i >= j) ? "+" : "", i - j); return buf; } -static char * -rcomp(int i, int j) +static char *rcomp(int i, int j) { static char buf[32]; + sprintf(buf, "%d (%s%d,%s%d%%)", - i, (i>=j)?"+":"", i-j, (i>=j)?"+":"",j?((i-j)*100)/j:0); + i, (i >= j) ? "+" : "", i - j, (i >= j) ? "+" : "", + j ? ((i - j) * 100) / j : 0); return buf; } -static void -out_faction(FILE *file, const struct faction *f) +static void out_faction(FILE * file, const struct faction *f) { - if (alliances!=NULL) { + if (alliances != NULL) { fprintf(file, "%s (%s/%d) (%.3s/%.3s), %d Einh., %d Pers., $%d, %d NMR\n", - f->name, itoa36(f->no), f_get_alliance(f)?f->alliance->id:0, + f->name, itoa36(f->no), f_get_alliance(f) ? f->alliance->id : 0, LOC(default_locale, rc_name(f->race, 0)), magic_school[f->magiegebiet], f->no_units, f->num_total, f->money, turn - f->lastorders); } else { @@ -103,45 +103,48 @@ out_faction(FILE *file, const struct faction *f) } } -static char * -gamedate2(const struct locale * lang) +static char *gamedate2(const struct locale *lang) { static char buf[256]; + gamedate gd; get_gamedate(turn, &gd); sprintf(buf, "in %s des Monats %s im Jahre %d %s.", LOC(lang, weeknames2[gd.week]), LOC(lang, monthnames[gd.month]), - gd.year, - agename?LOC(lang, agename):""); + gd.year, agename ? LOC(lang, agename) : ""); return buf; } -static void -writeturn(void) +static void writeturn(void) { char zText[MAX_PATH]; + FILE *f; sprintf(zText, "%s/datum", basepath()); f = cfopen(zText, "w"); - if (!f) return; + if (!f) + return; fputs(gamedate2(default_locale), f); fclose(f); sprintf(zText, "%s/turn", basepath()); f = cfopen(zText, "w"); - if (!f) return; + if (!f) + return; fprintf(f, "%d\n", turn); fclose(f); } -void -report_summary(summary * s, summary * o, boolean full) +void report_summary(summary * s, summary * o, boolean full) { - FILE * F = NULL; + FILE *F = NULL; + int i, newplayers = 0; - faction * f; + + faction *f; + char zText[MAX_PATH]; if (full) { @@ -150,7 +153,8 @@ report_summary(summary * s, summary * o, boolean full) sprintf(zText, "%s/parteien", basepath()); } F = cfopen(zText, "w"); - if (!F) return; + if (!F) + return; #ifdef SUMMARY_BOM else { const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; @@ -158,15 +162,14 @@ report_summary(summary * s, summary * o, boolean full) } #endif printf("Schreibe Zusammenfassung (parteien)...\n"); - fprintf(F, "%s\n%s\n\n", global.gamename, gamedate2(default_locale)); - fprintf(F, "Auswertung Nr: %d\n\n", turn); - fprintf(F, "Parteien: %s\n", pcomp(s->factions, o->factions)); - fprintf(F, "Einheiten: %s\n", pcomp(s->nunits, o->nunits)); - fprintf(F, "Spielerpopulation: %s\n", - pcomp(s->playerpop, o->playerpop)); - fprintf(F, " davon bewaffnet: %s\n", - pcomp(s->armed_men, o->armed_men)); - fprintf(F, " Helden: %s\n", pcomp(s->heroes, o->heroes)); + fprintf(F, "%s\n%s\n\n", global.gamename, gamedate2(default_locale)); + + fprintf(F, "Auswertung Nr: %d\n\n", turn); + fprintf(F, "Parteien: %s\n", pcomp(s->factions, o->factions)); + fprintf(F, "Einheiten: %s\n", pcomp(s->nunits, o->nunits)); + fprintf(F, "Spielerpopulation: %s\n", pcomp(s->playerpop, o->playerpop)); + fprintf(F, " davon bewaffnet: %s\n", pcomp(s->armed_men, o->armed_men)); + fprintf(F, " Helden: %s\n", pcomp(s->heroes, o->heroes)); if (full) { fprintf(F, "Regionen: %d\n", listlen(regions)); @@ -180,26 +183,33 @@ report_summary(summary * s, summary * o, boolean full) } for (i = 0; i < MAXRACES; i++) { - const race * rc = new_race[i]; + const race *rc = new_race[i]; + if (s->factionrace[i] && rc && playerrace(rc) && i != RC_TEMPLATE && i != RC_CLONE) { - fprintf(F, "%13s%s: %s\n", LOC(default_locale, rc_name(rc, 3)), LOC(default_locale, "stat_tribe_p"), - pcomp(s->factionrace[i], o->factionrace[i])); + fprintf(F, "%13s%s: %s\n", LOC(default_locale, rc_name(rc, 3)), + LOC(default_locale, "stat_tribe_p"), pcomp(s->factionrace[i], + o->factionrace[i])); } } - if(full) { + if (full) { fprintf(F, "\n"); { - struct language * plang = s->languages; - while (plang!=NULL) { - struct language * olang = o->languages; + struct language *plang = s->languages; + + while (plang != NULL) { + struct language *olang = o->languages; + int nold = 0; - while (olang && olang->locale!=plang->locale) olang=olang->next; - if (olang) nold = olang->number; + + while (olang && olang->locale != plang->locale) + olang = olang->next; + if (olang) + nold = olang->number; fprintf(F, "Sprache %12s: %s\n", locale_name(plang->locale), rcomp(plang->number, nold)); - plang=plang->next; + plang = plang->next; } } } @@ -207,7 +217,8 @@ report_summary(summary * s, summary * o, boolean full) fprintf(F, "\n"); if (full) { for (i = 0; i < MAXRACES; i++) { - const race * rc = new_race[i]; + const race *rc = new_race[i]; + if (s->poprace[i]) { fprintf(F, "%20s: %s\n", LOC(default_locale, rc_name(rc, 1)), rcomp(s->poprace[i], o->poprace[i])); @@ -215,35 +226,37 @@ report_summary(summary * s, summary * o, boolean full) } } else { for (i = 0; i < MAXRACES; i++) { - const race * rc = new_race[i]; + const race *rc = new_race[i]; + if (s->poprace[i] && playerrace(rc) && i != RC_TEMPLATE && i != RC_CLONE) { - fprintf(F, "%20s: %s\n", LOC(default_locale, rc_name(rc, 1)), - rcomp(s->poprace[i], o->poprace[i])); + fprintf(F, "%20s: %s\n", LOC(default_locale, rc_name(rc, 1)), + rcomp(s->poprace[i], o->poprace[i])); } } } if (full) { - fprintf(F, "\nWaffen: %s\n", pcomp(s->waffen,o->waffen)); + fprintf(F, "\nWaffen: %s\n", pcomp(s->waffen, o->waffen)); fprintf(F, "Ruestungen: %s\n", - pcomp(s->ruestungen,o->ruestungen)); + pcomp(s->ruestungen, o->ruestungen)); fprintf(F, "ungezaehmte Pferde: %s\n", pcomp(s->pferde, o->pferde)); fprintf(F, "gezaehmte Pferde: %s\n", - pcomp(s->spielerpferde,o->spielerpferde)); + pcomp(s->spielerpferde, o->spielerpferde)); fprintf(F, "Schiffe: %s\n", pcomp(s->schiffe, o->schiffe)); fprintf(F, "Gebaeude: %s\n", pcomp(s->gebaeude, o->gebaeude)); - fprintf(F, "\nBauernpopulation: %s\n", pcomp(s->peasants,o->peasants)); + fprintf(F, "\nBauernpopulation: %s\n", pcomp(s->peasants, o->peasants)); - fprintf(F, "Population gesamt: %d\n\n", s->playerpop+s->peasants); + fprintf(F, "Population gesamt: %d\n\n", s->playerpop + s->peasants); fprintf(F, "Reichtum Spieler: %s Silber\n", - pcomp(s->playermoney,o->playermoney)); + pcomp(s->playermoney, o->playermoney)); fprintf(F, "Reichtum Bauern: %s Silber\n", pcomp(s->peasantmoney, o->peasantmoney)); fprintf(F, "Reichtum gesamt: %s Silber\n\n", - pcomp(s->playermoney+s->peasantmoney, o->playermoney+o->peasantmoney)); + pcomp(s->playermoney + s->peasantmoney, + o->playermoney + o->peasantmoney)); } fprintf(F, "\n\n"); @@ -278,13 +291,13 @@ report_summary(summary * s, summary * o, boolean full) if (NMRTimeout() && full) { fprintf(F, "\n\nFactions with NMRs:\n"); for (i = NMRTimeout(); i > 0; --i) { - for(f=factions; f; f=f->next) { - if(i == NMRTimeout()) { - if(turn - f->lastorders >= i) { + for (f = factions; f; f = f->next) { + if (i == NMRTimeout()) { + if (turn - f->lastorders >= i) { out_faction(F, f); } } else { - if(turn - f->lastorders == i) { + if (turn - f->lastorders == i) { out_faction(F, f); } } @@ -303,18 +316,23 @@ report_summary(summary * s, summary * o, boolean full) nmrs = NULL; } -summary * -make_summary(void) +summary *make_summary(void) { faction *f; + region *r; + unit *u; - summary * s = calloc(1, sizeof(summary)); + + summary *s = calloc(1, sizeof(summary)); for (f = factions; f; f = f->next) { - const struct locale * lang = f->locale; - struct language * plang = s->languages; - while (plang && plang->locale != lang) plang=plang->next; + const struct locale *lang = f->locale; + + struct language *plang = s->languages; + + while (plang && plang->locale != lang) + plang = plang->next; if (!plang) { plang = calloc(sizeof(struct language), 1); plang->next = s->languages; @@ -363,14 +381,16 @@ make_summary(void) s->peasantmoney += rmoney(r); /* Einheiten Info. nregions darf nur einmal pro Partei - * incrementiert werden. */ + * incrementiert werden. */ - for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT); + for (u = r->units; u; u = u->next) + freset(u->faction, FFL_SELECT); for (u = r->units; u; u = u->next) { f = u->faction; if (!is_monsters(u->faction)) { - skill * sv; - item * itm; + skill *sv; + + item *itm; s->nunits++; s->playerpop += u->number; @@ -380,7 +400,7 @@ make_summary(void) s->spielerpferde += get_item(u, I_HORSE); s->playermoney += get_money(u); s->armed_men += armedmen(u, true); - for (itm=u->items;itm;itm=itm->next) { + for (itm = u->items; itm; itm = itm->next) { if (itm->type->rtype->wtype) { s->waffen += itm->number; } @@ -393,8 +413,11 @@ make_summary(void) for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { skill_t sk = sv->id; + int aktskill = eff_skill(u, sk, r); - if (aktskill > s->maxskill) s->maxskill = aktskill; + + if (aktskill > s->maxskill) + s->maxskill = aktskill; } if (!fval(f, FFL_SELECT)) { f->nregions++; diff --git a/src/gamecode/summary.h b/src/gamecode/summary.h index f7419a30b..5da62e688 100644 --- a/src/gamecode/summary.h +++ b/src/gamecode/summary.h @@ -16,8 +16,9 @@ extern "C" { #endif struct summary; - extern void report_summary(struct summary * n, struct summary * o, boolean full); - extern struct summary * make_summary(void); + extern void report_summary(struct summary *n, struct summary *o, + boolean full); + extern struct summary *make_summary(void); #ifdef __cplusplus } diff --git a/src/gamecode/xmlreport.c b/src/gamecode/xmlreport.c index eaa4873a5..eb2c5d083 100644 --- a/src/gamecode/xmlreport.c +++ b/src/gamecode/xmlreport.c @@ -88,7 +88,8 @@ typedef struct xml_context { static xmlNodePtr xml_link(report_context * ctx, const xmlChar * rel, const xmlChar * ref) { - xml_context* xct = (xml_context*)ctx->userdata; + xml_context *xct = (xml_context *) ctx->userdata; + xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "link"); xmlNewNsProp(node, xct->ns_atl, BAD_CAST "rel", rel); @@ -97,78 +98,81 @@ xml_link(report_context * ctx, const xmlChar * rel, const xmlChar * ref) return node; } -static const xmlChar * -xml_ref_unit(const unit * u) +static const xmlChar *xml_ref_unit(const unit * u) { static char idbuf[20]; + snprintf(idbuf, sizeof(idbuf), "unit_%d", u->no); return (const xmlChar *)idbuf; } -static const xmlChar * -xml_ref_faction(const faction * f) +static const xmlChar *xml_ref_faction(const faction * f) { static char idbuf[20]; + snprintf(idbuf, sizeof(idbuf), "fctn_%d", f->no); return (const xmlChar *)idbuf; } -static const xmlChar * -xml_ref_group(const group * g) +static const xmlChar *xml_ref_group(const group * g) { static char idbuf[20]; + snprintf(idbuf, sizeof(idbuf), "grp_%d", g->gid); return (const xmlChar *)idbuf; } -static const xmlChar * -xml_ref_prefix(const char * str) +static const xmlChar *xml_ref_prefix(const char *str) { static char idbuf[20]; + snprintf(idbuf, sizeof(idbuf), "pref_%s", str); return (const xmlChar *)idbuf; } -static const xmlChar * -xml_ref_building(const building * b) +static const xmlChar *xml_ref_building(const building * b) { static char idbuf[20]; + snprintf(idbuf, sizeof(idbuf), "bldg_%d", b->no); return (const xmlChar *)idbuf; } -static const xmlChar * -xml_ref_ship(const ship * sh) +static const xmlChar *xml_ref_ship(const ship * sh) { static char idbuf[20]; + snprintf(idbuf, sizeof(idbuf), "shp_%d", sh->no); return (const xmlChar *)idbuf; } -static const xmlChar * -xml_ref_region(const region * r) +static const xmlChar *xml_ref_region(const region * r) { static char idbuf[20]; + snprintf(idbuf, sizeof(idbuf), "rgn_%d", r->uid); return (const xmlChar *)idbuf; } -static xmlNodePtr -xml_inventory(report_context * ctx, item * items, unit * u) +static xmlNodePtr xml_inventory(report_context * ctx, item * items, unit * u) { - xml_context* xct = (xml_context*)ctx->userdata; - xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "items"); - item * itm; + xml_context *xct = (xml_context *) ctx->userdata; - for (itm=items;itm;itm=itm->next) { + xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "items"); + + item *itm; + + for (itm = items; itm; itm = itm->next) { xmlNodePtr child; - const char * name; + + const char *name; + int n; child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "item")); report_item(u, itm, ctx->f, NULL, &name, &n, true); - xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (xmlChar *)name); - xmlNodeAddContent(child, (xmlChar*)itoab(n, 10)); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (xmlChar *) name); + xmlNodeAddContent(child, (xmlChar *) itoab(n, 10)); } return node; } @@ -176,13 +180,16 @@ xml_inventory(report_context * ctx, item * items, unit * u) static xmlNodePtr xml_spells(report_context * ctx, quicklist * slist, int maxlevel) { - xml_context* xct = (xml_context*)ctx->userdata; + xml_context *xct = (xml_context *) ctx->userdata; + xmlNodePtr child, node = xmlNewNode(xct->ns_atl, BAD_CAST "spells"); - quicklist * ql; + + quicklist *ql; + int qi; - for (ql=slist,qi=0;ql;ql_advance(&ql, &qi, 1)) { - spell * sp = (spell *)ql_get(ql, qi); + for (ql = slist, qi = 0; ql; ql_advance(&ql, &qi, 1)) { + spell *sp = (spell *) ql_get(ql, qi); if (sp->level <= maxlevel) { child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "spell")); @@ -192,19 +199,23 @@ xml_spells(report_context * ctx, quicklist * slist, int maxlevel) return node; } -static xmlNodePtr -xml_skills(report_context * ctx, unit * u) +static xmlNodePtr xml_skills(report_context * ctx, unit * u) { - xml_context* xct = (xml_context*)ctx->userdata; + xml_context *xct = (xml_context *) ctx->userdata; + xmlNodePtr child, node = xmlNewNode(xct->ns_atl, BAD_CAST "skills"); - skill * sv; + + skill *sv; for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - if (sv->level>0) { + if (sv->level > 0) { skill_t sk = sv->id; + int esk = eff_skill(u, sk, u->region); - child = xmlNewTextChild(node, xct->ns_atl, BAD_CAST "skill", BAD_CAST itoab(esk, 10)); + child = + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "skill", BAD_CAST itoab(esk, + 10)); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", BAD_CAST skillnames[sk]); } } @@ -212,15 +223,20 @@ xml_skills(report_context * ctx, unit * u) return node; } -static xmlNodePtr -xml_unit(report_context * ctx, unit * u, int mode) +static xmlNodePtr xml_unit(report_context * ctx, unit * u, int mode) { - xml_context* xct = (xml_context*)ctx->userdata; + xml_context *xct = (xml_context *) ctx->userdata; + xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "unit"); - static const curse_type * itemcloak_ct = 0; + + static const curse_type *itemcloak_ct = 0; + static boolean init = false; + xmlNodePtr child; - const char * str, * rcname, * rcillusion; + + const char *str, *rcname, *rcillusion; + boolean disclosure = (ctx->f == u->faction || omniscient(ctx->f)); /* TODO: hitpoints, aura, combatspells, curses */ @@ -228,26 +244,30 @@ xml_unit(report_context * ctx, unit * u, int mode) xmlNewNsProp(node, xct->ns_xml, XML_XML_ID, xml_ref_unit(u)); xmlNewNsProp(node, xct->ns_atl, BAD_CAST "key", BAD_CAST itoa36(u->no)); xmlNewTextChild(node, xct->ns_atl, BAD_CAST "name", (const xmlChar *)u->name); - xmlNewTextChild(node, xct->ns_atl, BAD_CAST "number", (const xmlChar *)itoab(u->number, 10)); + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "number", + (const xmlChar *)itoab(u->number, 10)); /* optional description */ str = u_description(u, ctx->f->locale); if (str) { - child = xmlNewTextChild(node, xct->ns_atl, BAD_CAST "text", (const xmlChar *)str); + child = + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "text", (const xmlChar *)str); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "public"); - if (str!=u->display) { - xmlNewNsProp(child, xct->ns_atl, XML_XML_LANG, BAD_CAST locale_name(ctx->f->locale)); + if (str != u->display) { + xmlNewNsProp(child, xct->ns_atl, XML_XML_LANG, + BAD_CAST locale_name(ctx->f->locale)); } } /* possible info */ - if (is_guard(u, GUARD_ALL)!=0) { + if (is_guard(u, GUARD_ALL) != 0) { xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "guard")); } /* siege */ if (fval(u, UFL_SIEGE)) { - building * b = usiege(u); + building *b = usiege(u); + if (b) { xmlAddChild(node, xml_link(ctx, BAD_CAST "siege", xml_ref_building(b))); } @@ -264,48 +284,59 @@ xml_unit(report_context * ctx, unit * u, int mode) if (rcillusion) { child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "race")); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "stealth"); - xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (const xmlChar *)rcillusion); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", + (const xmlChar *)rcillusion); } } else { child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "race")); - xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (const xmlChar *)(rcillusion?rcillusion:rcname)); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", + (const xmlChar *)(rcillusion ? rcillusion : rcname)); } /* group and prefix information. we only write the prefix if we really must */ if (fval(u, UFL_GROUP)) { - attrib * a = a_find(u->attribs, &at_group); - if (a!=NULL) { - const group * g = (const group*)a->data.v; + attrib *a = a_find(u->attribs, &at_group); + + if (a != NULL) { + const group *g = (const group *)a->data.v; + if (disclosure) { child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "group")); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", xml_ref_group(g)); } else { - const char * prefix = get_prefix(g->attribs); + const char *prefix = get_prefix(g->attribs); + if (prefix) { child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "prefix")); - xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", xml_ref_prefix(prefix)); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", + xml_ref_prefix(prefix)); } } } } if (disclosure) { - unit * mage; - + unit *mage; + str = uprivate(u); if (str) { - child = xmlNewTextChild(node, xct->ns_atl, BAD_CAST "text", (const xmlChar *)str); + child = + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "text", + (const xmlChar *)str); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "private"); } /* familiar info */ mage = get_familiar_mage(u); - if (mage) xmlAddChild(node, xml_link(ctx, BAD_CAST "familiar_of", xml_ref_unit(mage))); + if (mage) + xmlAddChild(node, xml_link(ctx, BAD_CAST "familiar_of", + xml_ref_unit(mage))); /* combat status */ child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "status")); xmlSetNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "combat"); - xmlSetNsProp(child, xct->ns_atl, BAD_CAST "value", BAD_CAST combatstatus[u->status]); + xmlSetNsProp(child, xct->ns_atl, BAD_CAST "value", + BAD_CAST combatstatus[u->status]); if (fval(u, UFL_NOAID)) { child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "status")); @@ -315,10 +346,12 @@ xml_unit(report_context * ctx, unit * u, int mode) if (fval(u, UFL_STEALTH)) { int i = u_geteffstealth(u); - if (i>=0) { + + if (i >= 0) { child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "status")); xmlSetNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "stealth"); - xmlSetNsProp(child, xct->ns_atl, BAD_CAST "value", BAD_CAST itoab(i, 10)); + xmlSetNsProp(child, xct->ns_atl, BAD_CAST "value", BAD_CAST itoab(i, + 10)); } } if (fval(u, UFL_HERO)) { @@ -340,8 +373,10 @@ xml_unit(report_context * ctx, unit * u, int mode) /* spells */ if (is_mage(u)) { - sc_mage * mage = get_mage(u); - quicklist * slist = mage->spells; + sc_mage *mage = get_mage(u); + + quicklist *slist = mage->spells; + if (slist) { xmlAddChild(node, xml_spells(ctx, slist, effskill(u, SK_MAGIC))); } @@ -352,17 +387,20 @@ xml_unit(report_context * ctx, unit * u, int mode) child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "faction")); if (disclosure) { xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "true"); - xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", xml_ref_faction(u->faction)); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", + xml_ref_faction(u->faction)); if (fval(u, UFL_ANON_FACTION)) { - const faction * sf = visible_faction(NULL, u); + const faction *sf = visible_faction(NULL, u); + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "faction")); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "stealth"); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", xml_ref_faction(sf)); } } else { - const faction * sf = visible_faction(ctx->f, u); - if (sf==ctx->f) { + const faction *sf = visible_faction(ctx->f, u); + + if (sf == ctx->f) { xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "stealth"); } xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", xml_ref_faction(sf)); @@ -371,7 +409,8 @@ xml_unit(report_context * ctx, unit * u, int mode) /* the inventory */ if (u->items) { item result[MAX_INVENTORY]; - item * show = NULL; + + item *show = NULL; if (!init) { init = true; @@ -382,6 +421,7 @@ xml_unit(report_context * ctx, unit * u, int mode) show = u->items; } else { boolean see_items = (mode >= see_unit); + if (see_items) { if (itemcloak_ct && curse_active(get_curse(u->attribs, itemcloak_ct))) { see_items = false; @@ -391,9 +431,12 @@ xml_unit(report_context * ctx, unit * u, int mode) } if (see_items) { int n = report_items(u->items, result, MAX_INVENTORY, u, ctx->f); - assert(n>=0); - if (n>0) show = result; - else show = NULL; + + assert(n >= 0); + if (n > 0) + show = result; + else + show = NULL; } else { show = NULL; } @@ -407,81 +450,93 @@ xml_unit(report_context * ctx, unit * u, int mode) return node; } -static xmlNodePtr -xml_resources(report_context * ctx, const seen_region * sr) +static xmlNodePtr xml_resources(report_context * ctx, const seen_region * sr) { - xml_context* xct = (xml_context*)ctx->userdata; + xml_context *xct = (xml_context *) ctx->userdata; + xmlNodePtr node = NULL; + resource_report result[MAX_RAWMATERIALS]; + int n, size = report_resources(sr, result, MAX_RAWMATERIALS, ctx->f); if (size) { node = xmlNewNode(xct->ns_atl, BAD_CAST "resources"); - for (n=0;n=0) { + for (n = 0; n < size; ++n) { + if (result[n].number >= 0) { xmlNodePtr child; - + child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "resource")); - xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (xmlChar*)result[n].name); - if (result[n].level>=0) { - xmlNewNsProp(child, xct->ns_atl, BAD_CAST "level", (xmlChar*)itoab(result[n].level, 10)); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", + (xmlChar *) result[n].name); + if (result[n].level >= 0) { + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "level", + (xmlChar *) itoab(result[n].level, 10)); } - xmlNodeAddContent(child, (xmlChar*)itoab(result[n].number, 10)); + xmlNodeAddContent(child, (xmlChar *) itoab(result[n].number, 10)); } } } return node; } -static xmlNodePtr -xml_diplomacy(report_context * ctx, const struct ally * allies) +static xmlNodePtr xml_diplomacy(report_context * ctx, const struct ally *allies) { - xml_context* xct = (xml_context*)ctx->userdata; - xmlNodePtr child, node = xmlNewNode(xct->ns_atl, BAD_CAST "diplomacy"); - const struct ally * sf; + xml_context *xct = (xml_context *) ctx->userdata; - for (sf=allies;sf;sf=sf->next) { + xmlNodePtr child, node = xmlNewNode(xct->ns_atl, BAD_CAST "diplomacy"); + + const struct ally *sf; + + for (sf = allies; sf; sf = sf->next) { int i, status = sf->status; - for (i=0;helpmodes[i].name;++i) { - if (sf->faction && (status & helpmodes[i].status)==helpmodes[i].status) { + + for (i = 0; helpmodes[i].name; ++i) { + if (sf->faction && (status & helpmodes[i].status) == helpmodes[i].status) { status -= helpmodes[i].status; child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "status")); - xmlNewNsProp(child, xct->ns_xml, BAD_CAST "faction", xml_ref_faction(sf->faction)); - xmlNewNsProp(child, xct->ns_xml, BAD_CAST "status", (xmlChar*)helpmodes[i].name); + xmlNewNsProp(child, xct->ns_xml, BAD_CAST "faction", + xml_ref_faction(sf->faction)); + xmlNewNsProp(child, xct->ns_xml, BAD_CAST "status", + (xmlChar *) helpmodes[i].name); } } } return node; } -static xmlNodePtr -xml_groups(report_context * ctx, const group * groups) +static xmlNodePtr xml_groups(report_context * ctx, const group * groups) { - xml_context* xct = (xml_context*)ctx->userdata; - xmlNodePtr child, node = xmlNewNode(xct->ns_atl, BAD_CAST "faction"); - const group * g; + xml_context *xct = (xml_context *) ctx->userdata; + + xmlNodePtr child, node = xmlNewNode(xct->ns_atl, BAD_CAST "faction"); + + const group *g; + + for (g = groups; g; g = g->next) { + const char *prefix = get_prefix(g->attribs); - for (g=groups;g;g=g->next) { - const char * prefix = get_prefix(g->attribs); child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "group")); xmlNewNsProp(child, xct->ns_xml, XML_XML_ID, xml_ref_group(g)); - xmlNewTextChild(child, xct->ns_atl, BAD_CAST "name", (const xmlChar *)g->name); + xmlNewTextChild(child, xct->ns_atl, BAD_CAST "name", + (const xmlChar *)g->name); - if (g->allies) xmlAddChild(child, xml_diplomacy(ctx, g->allies)); + if (g->allies) + xmlAddChild(child, xml_diplomacy(ctx, g->allies)); if (prefix) { child = xmlAddChild(child, xmlNewNode(xct->ns_atl, BAD_CAST "prefix")); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", xml_ref_prefix(prefix)); } } - + return node; } -static xmlNodePtr -xml_faction(report_context * ctx, faction * f) +static xmlNodePtr xml_faction(report_context * ctx, faction * f) { - xml_context* xct = (xml_context*)ctx->userdata; + xml_context *xct = (xml_context *) ctx->userdata; + xmlNodePtr child, node = xmlNewNode(xct->ns_atl, BAD_CAST "faction"); /* TODO: alliance, locale */ @@ -489,18 +544,26 @@ xml_faction(report_context * ctx, faction * f) xmlNewNsProp(node, xct->ns_xml, XML_XML_ID, xml_ref_faction(f)); xmlNewNsProp(node, xct->ns_atl, BAD_CAST "key", BAD_CAST itoa36(f->no)); xmlNewTextChild(node, xct->ns_atl, BAD_CAST "name", (const xmlChar *)f->name); - if (f->email) xmlNewTextChild(node, xct->ns_atl, BAD_CAST "email", (const xmlChar *)f->email); + if (f->email) + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "email", + (const xmlChar *)f->email); if (f->banner) { - child = xmlNewTextChild(node, xct->ns_atl, BAD_CAST "text", (const xmlChar *)f->banner); + child = + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "text", + (const xmlChar *)f->banner); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "public"); } - if (ctx->f==f) { - xmlAddChild(node, xml_link(ctx, BAD_CAST "race", BAD_CAST f->race->_name[0])); + if (ctx->f == f) { + xmlAddChild(node, xml_link(ctx, BAD_CAST "race", + BAD_CAST f->race->_name[0])); - if (f->items) xmlAddChild(node, xml_inventory(ctx, f->items, NULL)); - if (f->allies) xmlAddChild(node, xml_diplomacy(ctx, f->allies)); - if (f->groups) xmlAddChild(node, xml_groups(ctx, f->groups)); + if (f->items) + xmlAddChild(node, xml_inventory(ctx, f->items, NULL)); + if (f->allies) + xmlAddChild(node, xml_diplomacy(ctx, f->allies)); + if (f->groups) + xmlAddChild(node, xml_groups(ctx, f->groups)); /* TODO: age, options, score, prefix, magic, immigrants, heroes, nmr, groups */ } @@ -508,93 +571,124 @@ xml_faction(report_context * ctx, faction * f) } static xmlNodePtr -xml_building(report_context * ctx, seen_region * sr, const building * b, const unit * owner) +xml_building(report_context * ctx, seen_region * sr, const building * b, + const unit * owner) { - xml_context* xct = (xml_context*)ctx->userdata; + xml_context *xct = (xml_context *) ctx->userdata; + xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "building"); + xmlNodePtr child; - const char * bname, * billusion; + + const char *bname, *billusion; xmlNewNsProp(node, xct->ns_xml, XML_XML_ID, xml_ref_building(b)); xmlNewNsProp(node, xct->ns_atl, BAD_CAST "key", BAD_CAST itoa36(b->no)); xmlNewTextChild(node, xct->ns_atl, BAD_CAST "name", (const xmlChar *)b->name); - xmlNewTextChild(node, xct->ns_atl, BAD_CAST "size", (const xmlChar *)itoab(b->size, 10)); + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "size", + (const xmlChar *)itoab(b->size, 10)); if (b->display && b->display[0]) { - child = xmlNewTextChild(node, xct->ns_atl, BAD_CAST "text", (const xmlChar *)b->display); + child = + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "text", + (const xmlChar *)b->display); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "public"); } if (b->besieged) { - xmlNewTextChild(node, xct->ns_atl, BAD_CAST "siege", (const xmlChar *)itoab(b->besieged, 10)); + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "siege", + (const xmlChar *)itoab(b->besieged, 10)); } - if (owner) xmlAddChild(node, xml_link(ctx, BAD_CAST "owner", xml_ref_unit(owner))); + if (owner) + xmlAddChild(node, xml_link(ctx, BAD_CAST "owner", xml_ref_unit(owner))); report_building(b, &bname, &billusion); - if (owner && owner->faction==ctx->f) { + if (owner && owner->faction == ctx->f) { child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "type")); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "true"); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (const xmlChar *)bname); if (billusion) { child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "type")); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "illusion"); - xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (const xmlChar *)billusion); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", + (const xmlChar *)billusion); } } else { child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "type")); - xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (const xmlChar *)(billusion?billusion:bname)); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", + (const xmlChar *)(billusion ? billusion : bname)); } return node; } static xmlNodePtr -xml_ship(report_context * ctx, const seen_region * sr, const ship * sh, const unit * owner) +xml_ship(report_context * ctx, const seen_region * sr, const ship * sh, + const unit * owner) { - xml_context* xct = (xml_context*)ctx->userdata; + xml_context *xct = (xml_context *) ctx->userdata; + xmlNodePtr child, node = xmlNewNode(xct->ns_atl, BAD_CAST "ship"); xmlNewNsProp(node, xct->ns_xml, XML_XML_ID, xml_ref_ship(sh)); xmlNewNsProp(node, xct->ns_atl, BAD_CAST "key", BAD_CAST itoa36(sh->no)); - xmlNewTextChild(node, xct->ns_atl, BAD_CAST "name", (const xmlChar *)sh->name); - xmlNewTextChild(node, xct->ns_atl, BAD_CAST "size", (const xmlChar *)itoab(sh->size, 10)); + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "name", + (const xmlChar *)sh->name); + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "size", + (const xmlChar *)itoab(sh->size, 10)); if (sh->damage) { - xmlNewTextChild(node, xct->ns_atl, BAD_CAST "damage", (const xmlChar *)itoab(sh->damage, 10)); + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "damage", + (const xmlChar *)itoab(sh->damage, 10)); } - if (fval(sr->r->terrain, SEA_REGION) && sh->coast!=NODIRECTION) { - xmlNewTextChild(node, xct->ns_atl, BAD_CAST "coast", BAD_CAST directions[sh->coast]); + if (fval(sr->r->terrain, SEA_REGION) && sh->coast != NODIRECTION) { + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "coast", + BAD_CAST directions[sh->coast]); } child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "type")); - xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (const xmlChar *)sh->type->name[0]); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", + (const xmlChar *)sh->type->name[0]); if (sh->display && sh->display[0]) { - child = xmlNewTextChild(node, xct->ns_atl, BAD_CAST "text", (const xmlChar *)sh->display); + child = + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "text", + (const xmlChar *)sh->display); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "public"); } - if (owner) xmlAddChild(node, xml_link(ctx, BAD_CAST "owner", xml_ref_unit(owner))); + if (owner) + xmlAddChild(node, xml_link(ctx, BAD_CAST "owner", xml_ref_unit(owner))); if ((owner && owner->faction == ctx->f) || omniscient(ctx->f)) { int n = 0, p = 0; + getshipweight(sh, &n, &p); - xmlNewTextChild(node, xct->ns_atl, BAD_CAST "cargo", (const xmlChar *)itoab(n, 10)); + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "cargo", + (const xmlChar *)itoab(n, 10)); } return node; } -static xmlNodePtr -xml_region(report_context * ctx, seen_region * sr) +static xmlNodePtr xml_region(report_context * ctx, seen_region * sr) { - xml_context* xct = (xml_context*)ctx->userdata; - const region * r = sr->r; + xml_context *xct = (xml_context *) ctx->userdata; + + const region *r = sr->r; + xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "region"); + xmlNodePtr child; + int stealthmod = stealth_modifier(sr->mode); - unit * u; - ship * sh = r->ships; - building * b = r->buildings; - plane * pl = rplane(r); + + unit *u; + + ship *sh = r->ships; + + building *b = r->buildings; + + plane *pl = rplane(r); + int nx = r->x, ny = r->y; pnormalize(&nx, &ny, pl); @@ -607,39 +701,45 @@ xml_region(report_context * ctx, seen_region * sr) xmlNewNsProp(child, xct->ns_atl, BAD_CAST "x", xml_i(nx)); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "y", xml_i(ny)); if (pl && pl->name) { - xmlNewNsProp(child, xct->ns_atl, BAD_CAST "plane", (xmlChar *)pl->name); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "plane", (xmlChar *) pl->name); } child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "terrain")); - xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (xmlChar *)terrain_name(r)); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (xmlChar *) terrain_name(r)); - if (r->land!=NULL) { - child = xmlNewTextChild(node, xct->ns_atl, BAD_CAST "name", (const xmlChar *)r->land->name); + if (r->land != NULL) { + child = + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "name", + (const xmlChar *)r->land->name); if (r->land->items) { xmlAddChild(node, xml_inventory(ctx, r->land->items, NULL)); } } if (r->display && r->display[0]) { - child = xmlNewTextChild(node, xct->ns_atl, BAD_CAST "text", (const xmlChar *)r->display); + child = + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "text", + (const xmlChar *)r->display); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "public"); } child = xml_resources(ctx, sr); - if (child) xmlAddChild(node, child); + if (child) + xmlAddChild(node, child); child = xmlNewNode(xct->ns_atl, BAD_CAST "terrain"); - xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", (const xmlChar *)terrain_name(r)); + xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", + (const xmlChar *)terrain_name(r)); - if (sr->mode>see_neighbour) { + if (sr->mode > see_neighbour) { /* report all units. they are pre-sorted in an efficient manner */ u = r->units; while (b) { - while (b && (!u || u->building!=b)) { + while (b && (!u || u->building != b)) { xmlAddChild(node, xml_building(ctx, sr, b, NULL)); b = b->next; } if (b) { child = xmlAddChild(node, xml_building(ctx, sr, b, u)); - while (u && u->building==b) { + while (u && u->building == b) { xmlAddChild(child, xml_unit(ctx, u, sr->mode)); u = u->next; } @@ -647,7 +747,7 @@ xml_region(report_context * ctx, seen_region * sr) } } while (u && !u->ship) { - if (stealthmod>INT_MIN) { + if (stealthmod > INT_MIN) { if (u->faction == ctx->f || cansee(ctx->f, r, u, stealthmod)) { xmlAddChild(node, xml_unit(ctx, u, sr->mode)); } @@ -655,13 +755,13 @@ xml_region(report_context * ctx, seen_region * sr) u = u->next; } while (sh) { - while (sh && (!u || u->ship!=sh)) { + while (sh && (!u || u->ship != sh)) { xmlAddChild(node, xml_ship(ctx, sr, sh, NULL)); sh = sh->next; } if (sh) { child = xmlAddChild(node, xml_ship(ctx, sr, sh, u)); - while (u && u->ship==sh) { + while (u && u->ship == sh) { xmlAddChild(child, xml_unit(ctx, u, sr->mode)); u = u->next; } @@ -672,17 +772,24 @@ xml_region(report_context * ctx, seen_region * sr) return node; } -static xmlNodePtr -report_root(report_context * ctx) +static xmlNodePtr report_root(report_context * ctx) { int qi; - quicklist * address; - region * r = ctx->first, * rend = ctx->last; - xml_context* xct = (xml_context*)ctx->userdata; + + quicklist *address; + + region *r = ctx->first, *rend = ctx->last; + + xml_context *xct = (xml_context *) ctx->userdata; + xmlNodePtr node, child, xmlReport = xmlNewNode(NULL, BAD_CAST "atlantis"); - const char * mailto = locale_string(ctx->f->locale, "mailto"); - const char * mailcmd = locale_string(ctx->f->locale, "mailcmd"); + + const char *mailto = locale_string(ctx->f->locale, "mailto"); + + const char *mailcmd = locale_string(ctx->f->locale, "mailcmd"); + char zText[128]; + /* TODO: locale, age, options, messages */ xct->ns_xml = xmlNewNs(xmlReport, XML_XML_NAMESPACE, BAD_CAST "xml"); @@ -696,32 +803,39 @@ report_root(report_context * ctx) xmlNewNsProp(child, xct->ns_atl, BAD_CAST "method", BAD_CAST "mail"); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "href", BAD_CAST zText); } - xmlNewTextChild(node, xct->ns_atl, BAD_CAST "game", (xmlChar *)global.gamename); - strftime(zText, sizeof(zText), "%Y-%m-%dT%H:%M:%SZ", gmtime(&ctx->report_time)); - xmlNewTextChild(node, xct->ns_atl, BAD_CAST "time", (xmlChar *)zText); - xmlNewTextChild(node, xct->ns_atl, BAD_CAST "turn", (xmlChar *)itoab(turn, 10)); + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "game", + (xmlChar *) global.gamename); + strftime(zText, sizeof(zText), "%Y-%m-%dT%H:%M:%SZ", + gmtime(&ctx->report_time)); + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "time", (xmlChar *) zText); + xmlNewTextChild(node, xct->ns_atl, BAD_CAST "turn", (xmlChar *) itoab(turn, + 10)); + + for (qi = 0, address = ctx->addresses; address; ql_advance(&address, &qi, 1)) { + faction *f = (faction *) ql_get(address, qi); - for (qi=0,address=ctx->addresses;address;ql_advance(&address, &qi, 1)) { - faction * f = (faction *)ql_get(address, qi); xmlAddChild(xmlReport, xml_faction(ctx, f)); } - for (;r!=rend;r=r->next) { - seen_region * sr = find_seen(ctx->seen, r); - if (sr!=NULL) xmlAddChild(xmlReport, xml_region(ctx, sr)); + for (; r != rend; r = r->next) { + seen_region *sr = find_seen(ctx->seen, r); + + if (sr != NULL) + xmlAddChild(xmlReport, xml_region(ctx, sr)); } return xmlReport; }; /* main function of the xmlreport. creates the header and traverses all regions */ static int -report_xml(const char * filename, report_context * ctx, const char * encoding) +report_xml(const char *filename, report_context * ctx, const char *encoding) { xml_context xct; + xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); xct.doc = doc; - assert(ctx->userdata==NULL); + assert(ctx->userdata == NULL); ctx->userdata = &xct; xmlDocSetRootElement(doc, report_root(ctx)); @@ -734,17 +848,15 @@ report_xml(const char * filename, report_context * ctx, const char * encoding) return 0; } -void -register_xr(void) +void register_xr(void) { - register_reporttype("xml", &report_xml, 1< -extern void xmlreport_cleanup(void); -extern void register_xr(void); + extern void xmlreport_cleanup(void); + extern void register_xr(void); -extern int crwritemap(const char * filename); + extern int crwritemap(const char *filename); #ifdef __cplusplus } #endif #endif - diff --git a/src/gmtool.c b/src/gmtool.c index 801b68d76..411381cdc 100644 --- a/src/gmtool.c +++ b/src/gmtool.c @@ -69,26 +69,29 @@ #include static int g_quit; + int force_color = 0; -state * current_state = NULL; +state *current_state = NULL; #define IFL_SHIPS (1<<0) #define IFL_UNITS (1<<1) #define IFL_FACTIONS (1<<2) #define IFL_BUILDINGS (1<<3) -static WINDOW * hstatus; +static WINDOW *hstatus; -static void -init_curses(void) +static void init_curses(void) { short fg, bg; + initscr(); if (has_colors() || force_color) { short bcol = COLOR_BLACK; + short hcol = COLOR_MAGENTA; + start_color(); #ifdef WIN32 /* looks crap on putty with TERM=linux */ @@ -97,9 +100,9 @@ init_curses(void) } #endif - for (fg=0;fg!=8;++fg) { - for (bg=0;bg!=2;++bg) { - init_pair(fg+8*bg, fg, bg?hcol:bcol); + for (fg = 0; fg != 8; ++fg) { + for (bg = 0; bg != 2; ++bg) { + init_pair(fg + 8 * bg, fg, bg ? hcol : bcol); } } @@ -108,30 +111,28 @@ init_curses(void) bkgdset(' ' | COLOR_PAIR(COLOR_BLACK)); } - keypad(stdscr, TRUE); /* enable keyboard mapping */ + keypad(stdscr, TRUE); /* enable keyboard mapping */ meta(stdscr, TRUE); - nonl(); /* tell curses not to do NL->CR/NL on output */ - cbreak(); /* take input chars one at a time, no wait for \n */ - noecho(); /* don't echo input */ + nonl(); /* tell curses not to do NL->CR/NL on output */ + cbreak(); /* take input chars one at a time, no wait for \n */ + noecho(); /* don't echo input */ scrollok(stdscr, FALSE); refresh(); } -void cnormalize(const coordinate * c, int * x, int * y) +void cnormalize(const coordinate * c, int *x, int *y) { *x = c->x; *y = c->y; pnormalize(x, y, c->pl); } -map_region * -mr_get(const view * vi, int xofs, int yofs) +map_region *mr_get(const view * vi, int xofs, int yofs) { return vi->regions + xofs + yofs * vi->size.width; } -static point * -coor2point(const coordinate * c, point * p) +static point *coor2point(const coordinate * c, point * p) { assert(c && p); p->x = c->x * TWIDTH + c->y * TWIDTH / 2; @@ -139,14 +140,14 @@ coor2point(const coordinate * c, point * p) return p; } -static window * wnd_first, * wnd_last; +static window *wnd_first, *wnd_last; -static window * -win_create(WINDOW * hwin) +static window *win_create(WINDOW * hwin) { - window * wnd = calloc(1, sizeof(window)); + window *wnd = calloc(1, sizeof(window)); + wnd->handle = hwin; - if (wnd_first!=NULL) { + if (wnd_first != NULL) { wnd->next = wnd_first; wnd_first->prev = wnd; wnd_first = wnd; @@ -157,32 +158,39 @@ win_create(WINDOW * hwin) return wnd; } -static void -untag_region(selection * s, int nx, int ny) +static void untag_region(selection * s, int nx, int ny) { unsigned int key = ((nx << 12) ^ ny); - tag ** tp = &s->tags[key & (MAXTHASH-1)]; - tag * t = NULL; + + tag **tp = &s->tags[key & (MAXTHASH - 1)]; + + tag *t = NULL; + while (*tp) { t = *tp; - if (t->coord.x==nx && t->coord.y==ny) break; - tp=&t->nexthash; + if (t->coord.x == nx && t->coord.y == ny) + break; + tp = &t->nexthash; } - if (!*tp) return; + if (!*tp) + return; *tp = t->nexthash; free(t); return; } -static void -tag_region(selection * s, int nx, int ny) +static void tag_region(selection * s, int nx, int ny) { unsigned int key = ((nx << 12) ^ ny); - tag ** tp = &s->tags[key & (MAXTHASH-1)]; + + tag **tp = &s->tags[key & (MAXTHASH - 1)]; + while (*tp) { - tag * t = *tp; - if (t->coord.x==nx && t->coord.y==ny) return; - tp=&t->nexthash; + tag *t = *tp; + + if (t->coord.x == nx && t->coord.y == ny) + return; + tp = &t->nexthash; } *tp = calloc(1, sizeof(tag)); (*tp)->coord.x = nx; @@ -191,79 +199,92 @@ tag_region(selection * s, int nx, int ny) return; } -static int -tagged_region(selection * s, int nx, int ny) +static int tagged_region(selection * s, int nx, int ny) { unsigned int key = ((nx << 12) ^ ny); - tag ** tp = &s->tags[key & (MAXTHASH-1)]; + + tag **tp = &s->tags[key & (MAXTHASH - 1)]; + while (*tp) { - tag * t = *tp; - if (t->coord.x==nx && t->coord.y==ny) return 1; - tp=&t->nexthash; + tag *t = *tp; + + if (t->coord.x == nx && t->coord.y == ny) + return 1; + tp = &t->nexthash; } return 0; } -static int -mr_tile(const map_region * mr, int highlight) +static int mr_tile(const map_region * mr, int highlight) { int hl = 8 * highlight; - if (mr!=NULL && mr->r!=NULL) { - const region * r = mr->r; + + if (mr != NULL && mr->r != NULL) { + const region *r = mr->r; + switch (r->terrain->_name[0]) { - case 'o' : - return '.' | COLOR_PAIR(hl + COLOR_CYAN); - case 'd' : - return 'D' | COLOR_PAIR(hl + COLOR_YELLOW) | A_BOLD; - case 't' : - return '%' | COLOR_PAIR(hl + COLOR_YELLOW) | A_BOLD; - case 'f' : - if (r->terrain->_name[1]=='o') { /* fog */ - return '.' | COLOR_PAIR(hl + COLOR_YELLOW) | A_NORMAL; - } else if (r->terrain->_name[1]=='i') { /* firewall */ - return '%' | COLOR_PAIR(hl + COLOR_RED) | A_BOLD; - } - break; - case 'h' : - return 'H' | COLOR_PAIR(hl + COLOR_YELLOW) | A_NORMAL; - case 'm' : - return '^' | COLOR_PAIR(hl + COLOR_WHITE) | A_NORMAL; - case 'p' : - if (r->terrain->_name[1]=='l') { /* plain */ - if (r_isforest(r)) return '#' | COLOR_PAIR(hl + COLOR_GREEN) | A_NORMAL; - return '+' | COLOR_PAIR(hl + COLOR_GREEN) | A_BOLD; - } else if (r->terrain->_name[1]=='a') { /* packice */ - return ':' | COLOR_PAIR(hl + COLOR_WHITE) | A_BOLD; - } - break; - case 'g' : - return '*' | COLOR_PAIR(hl + COLOR_WHITE) | A_BOLD; - case 's' : - return 'S' | COLOR_PAIR(hl + COLOR_MAGENTA) | A_NORMAL; + case 'o': + return '.' | COLOR_PAIR(hl + COLOR_CYAN); + case 'd': + return 'D' | COLOR_PAIR(hl + COLOR_YELLOW) | A_BOLD; + case 't': + return '%' | COLOR_PAIR(hl + COLOR_YELLOW) | A_BOLD; + case 'f': + if (r->terrain->_name[1] == 'o') { /* fog */ + return '.' | COLOR_PAIR(hl + COLOR_YELLOW) | A_NORMAL; + } else if (r->terrain->_name[1] == 'i') { /* firewall */ + return '%' | COLOR_PAIR(hl + COLOR_RED) | A_BOLD; + } + break; + case 'h': + return 'H' | COLOR_PAIR(hl + COLOR_YELLOW) | A_NORMAL; + case 'm': + return '^' | COLOR_PAIR(hl + COLOR_WHITE) | A_NORMAL; + case 'p': + if (r->terrain->_name[1] == 'l') { /* plain */ + if (r_isforest(r)) + return '#' | COLOR_PAIR(hl + COLOR_GREEN) | A_NORMAL; + return '+' | COLOR_PAIR(hl + COLOR_GREEN) | A_BOLD; + } else if (r->terrain->_name[1] == 'a') { /* packice */ + return ':' | COLOR_PAIR(hl + COLOR_WHITE) | A_BOLD; + } + break; + case 'g': + return '*' | COLOR_PAIR(hl + COLOR_WHITE) | A_BOLD; + case 's': + return 'S' | COLOR_PAIR(hl + COLOR_MAGENTA) | A_NORMAL; } return r->terrain->_name[0] | COLOR_PAIR(hl + COLOR_RED); } return ' ' | COLOR_PAIR(hl + COLOR_WHITE); } -static void -paint_map(window * wnd, const state * st) +static void paint_map(window * wnd, const state * st) { - WINDOW * win = wnd->handle; + WINDOW *win = wnd->handle; + int lines = getmaxy(win); + int cols = getmaxx(win); + int vx, vy; - lines = lines/THEIGHT; - cols = cols/TWIDTH; - for (vy = 0; vy!=lines; ++vy) { + lines = lines / THEIGHT; + cols = cols / TWIDTH; + for (vy = 0; vy != lines; ++vy) { int yp = (lines - vy - 1) * THEIGHT; - for (vx = 0; vx!=cols; ++vx) { - map_region * mr = mr_get(&st->display, vx, vy); + + for (vx = 0; vx != cols; ++vx) { + map_region *mr = mr_get(&st->display, vx, vy); + int attr = 0; + int hl = 0; - int xp = vx * TWIDTH + (vy & 1) * TWIDTH/2; + + int xp = vx * TWIDTH + (vy & 1) * TWIDTH / 2; + int nx, ny; + if (mr) { if (st) { cnormalize(&mr->coord, &nx, &ny); @@ -271,64 +292,75 @@ paint_map(window * wnd, const state * st) attr |= A_REVERSE; } } - if (mr->r && (mr->r->flags & RF_MAPPER_HIGHLIGHT)) hl = 1; + if (mr->r && (mr->r->flags & RF_MAPPER_HIGHLIGHT)) + hl = 1; mvwaddch(win, yp, xp, mr_tile(mr, hl) | attr); } } } } -map_region * -cursor_region(const view * v, const coordinate * c) +map_region *cursor_region(const view * v, const coordinate * c) { coordinate relpos; + int cx, cy; if (c) { relpos.x = c->x - v->topleft.x; relpos.y = c->y - v->topleft.y; cy = relpos.y; - cx = relpos.x + cy/2; + cx = relpos.x + cy / 2; return mr_get(v, cx, cy); } return NULL; } static void -draw_cursor(WINDOW * win, selection * s, const view * v, const coordinate * c, int show) +draw_cursor(WINDOW * win, selection * s, const view * v, const coordinate * c, + int show) { - int lines = getmaxy(win)/THEIGHT; + int lines = getmaxy(win) / THEIGHT; + int xp, yp, nx, ny; + int attr = 0; - map_region * mr = cursor_region(v, c); + + map_region *mr = cursor_region(v, c); + coordinate relpos; + int cx, cy; - if (!mr) return; + if (!mr) + return; relpos.x = c->x - v->topleft.x; relpos.y = c->y - v->topleft.y; cy = relpos.y; - cx = relpos.x + cy/2; + cx = relpos.x + cy / 2; yp = (lines - cy - 1) * THEIGHT; - xp = cx * TWIDTH + (cy & 1) * TWIDTH/2; + xp = cx * TWIDTH + (cy & 1) * TWIDTH / 2; cnormalize(&mr->coord, &nx, &ny); - if (s && tagged_region(s, nx, ny)) attr = A_REVERSE; + if (s && tagged_region(s, nx, ny)) + attr = A_REVERSE; if (mr->r) { int hl = 0; - if (mr->r->flags & RF_MAPPER_HIGHLIGHT) hl = 1; + + if (mr->r->flags & RF_MAPPER_HIGHLIGHT) + hl = 1; mvwaddch(win, yp, xp, mr_tile(mr, hl) | attr); - } - else mvwaddch(win, yp, xp, ' ' | attr | COLOR_PAIR(COLOR_YELLOW)); + } else + mvwaddch(win, yp, xp, ' ' | attr | COLOR_PAIR(COLOR_YELLOW)); if (show) { attr = A_BOLD; - mvwaddch(win, yp, xp-1, '<' | attr | COLOR_PAIR(COLOR_YELLOW)); - mvwaddch(win, yp, xp+1, '>' | attr | COLOR_PAIR(COLOR_YELLOW)); + mvwaddch(win, yp, xp - 1, '<' | attr | COLOR_PAIR(COLOR_YELLOW)); + mvwaddch(win, yp, xp + 1, '>' | attr | COLOR_PAIR(COLOR_YELLOW)); } else { attr = A_NORMAL; - mvwaddch(win, yp, xp-1, ' ' | attr | COLOR_PAIR(COLOR_WHITE)); - mvwaddch(win, yp, xp+1, ' ' | attr | COLOR_PAIR(COLOR_WHITE)); + mvwaddch(win, yp, xp - 1, ' ' | attr | COLOR_PAIR(COLOR_WHITE)); + mvwaddch(win, yp, xp + 1, ' ' | attr | COLOR_PAIR(COLOR_WHITE)); } wmove(win, yp, xp); wnoutrefresh(win); @@ -336,14 +368,18 @@ draw_cursor(WINDOW * win, selection * s, const view * v, const coordinate * c, i -static void -paint_status(window * wnd, const state * st) +static void paint_status(window * wnd, const state * st) { - WINDOW * win = wnd->handle; - const char * name = ""; + WINDOW *win = wnd->handle; + + const char *name = ""; + int nx, ny, uid = 0; - const char * terrain = "----"; - map_region * mr = cursor_region(&st->display, &st->cursor); + + const char *terrain = "----"; + + map_region *mr = cursor_region(&st->display, &st->cursor); + if (mr && mr->r) { uid = mr->r->uid; if (mr->r->land) { @@ -354,29 +390,32 @@ paint_status(window * wnd, const state * st) terrain = mr->r->terrain->_name; } cnormalize(&st->cursor, &nx, &ny); - mvwprintw(win, 0, 0, "%4d %4d | %.4s | %.20s (%d)", nx, ny, terrain, name, uid); + mvwprintw(win, 0, 0, "%4d %4d | %.4s | %.20s (%d)", nx, ny, terrain, name, + uid); wclrtoeol(win); } -static boolean -handle_info_region(window * wnd, state * st, int c) +static boolean handle_info_region(window * wnd, state * st, int c) { return false; } -static void -paint_info_region(window * wnd, const state * st) +static void paint_info_region(window * wnd, const state * st) { - WINDOW * win = wnd->handle; - int size = getmaxx(win)-2; - int line = 0, maxline = getmaxy(win)-2; - map_region * mr = cursor_region(&st->display, &st->cursor); + WINDOW *win = wnd->handle; + + int size = getmaxx(win) - 2; + + int line = 0, maxline = getmaxy(win) - 2; + + map_region *mr = cursor_region(&st->display, &st->cursor); unused(st); werase(win); wxborder(win); if (mr && mr->r) { - const region * r = mr->r; + const region *r = mr->r; + if (r->land) { mvwaddnstr(win, line++, 1, (char *)r->land->name, size); } else { @@ -385,92 +424,98 @@ paint_info_region(window * wnd, const state * st) line++; mvwprintw(win, line++, 1, "%s, age %d", r->terrain->_name, r->age); if (r->land) { - mvwprintw(win, line++, 1, "$:%6d P:%5d", r->land->money, r->land->peasants); - mvwprintw(win, line++, 1, "H:%6d %s:%5d", r->land->horses, (r->flags&RF_MALLORN)?"M":"T", r->land->trees[1]+r->land->trees[2]); + mvwprintw(win, line++, 1, "$:%6d P:%5d", r->land->money, + r->land->peasants); + mvwprintw(win, line++, 1, "H:%6d %s:%5d", r->land->horses, + (r->flags & RF_MALLORN) ? "M" : "T", + r->land->trees[1] + r->land->trees[2]); } line++; if (r->ships && (st->info_flags & IFL_SHIPS)) { - ship * sh; + ship *sh; + wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - mvwaddnstr(win, line++, 1, "* ships:", size-5); + mvwaddnstr(win, line++, 1, "* ships:", size - 5); wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - for (sh=r->ships;sh && linenext) { + for (sh = r->ships; sh && line < maxline; sh = sh->next) { mvwprintw(win, line, 1, "%.4s ", itoa36(sh->no)); - mvwaddnstr(win, line++, 6, (char*)sh->type->name[0], size-5); + mvwaddnstr(win, line++, 6, (char *)sh->type->name[0], size - 5); } } if (r->units && (st->info_flags & IFL_FACTIONS)) { - unit * u; + unit *u; + wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - mvwaddnstr(win, line++, 1, "* factions:", size-5); + mvwaddnstr(win, line++, 1, "* factions:", size - 5); wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - for (u=r->units;u && linenext) { + for (u = r->units; u && line < maxline; u = u->next) { if (!fval(u->faction, FFL_MARK)) { mvwprintw(win, line, 1, "%.4s ", itoa36(u->faction->no)); - mvwaddnstr(win, line++, 6, (char *)u->faction->name, size-5); + mvwaddnstr(win, line++, 6, (char *)u->faction->name, size - 5); fset(u->faction, FFL_MARK); } } - for (u=r->units;u && linenext) { + for (u = r->units; u && line < maxline; u = u->next) { freset(u->faction, FFL_MARK); } } if (r->units && (st->info_flags & IFL_UNITS)) { - unit * u; + unit *u; + wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - mvwaddnstr(win, line++, 1, "* units:", size-5); + mvwaddnstr(win, line++, 1, "* units:", size - 5); wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); - for (u=r->units;u && linenext) { + for (u = r->units; u && line < maxline; u = u->next) { mvwprintw(win, line, 1, "%.4s ", itoa36(u->no)); - mvwaddnstr(win, line++, 6, (char *)u->name, size-5); + mvwaddnstr(win, line++, 6, (char *)u->name, size - 5); } } } } -static void (*paint_info)(struct window * wnd, const struct state * st); +static void (*paint_info) (struct window * wnd, const struct state * st); -static void -paint_info_default(window * wnd, const state * st) +static void paint_info_default(window * wnd, const state * st) { - if (paint_info) paint_info(wnd, st); - else paint_info_region(wnd, st); + if (paint_info) + paint_info(wnd, st); + else + paint_info_region(wnd, st); } -void set_info_function(void (*callback)(struct window *, const struct state *)) +void set_info_function(void (*callback) (struct window *, const struct state *)) { paint_info = callback; } -static char * -askstring(WINDOW * win, const char * q, char * buffer, size_t size) +static char *askstring(WINDOW * win, const char *q, char *buffer, size_t size) { werase(win); - mvwaddstr(win, 0, 0, (char*)q); - wmove(win, 0, (int)(strlen(q)+1)); + mvwaddstr(win, 0, 0, (char *)q); + wmove(win, 0, (int)(strlen(q) + 1)); echo(); wgetnstr(win, buffer, (int)size); noecho(); return buffer; } -static void -statusline(WINDOW * win, const char * str) +static void statusline(WINDOW * win, const char *str) { - mvwaddstr(win, 0, 0, (char*)str); + mvwaddstr(win, 0, 0, (char *)str); wclrtoeol(win); wnoutrefresh(win); } -static void -terraform_at(coordinate * c, const terrain_type *terrain) +static void terraform_at(coordinate * c, const terrain_type * terrain) { - if (terrain!=NULL) { - region * r; + if (terrain != NULL) { + region *r; + int nx = c->x, ny = c->y; + pnormalize(&nx, &ny, c->pl); r = findregion(nx, ny); - if (r==NULL) { + if (r == NULL) { r = new_region(nx, ny, c->pl, 0); } terraform_region(r, terrain); @@ -478,22 +523,27 @@ terraform_at(coordinate * c, const terrain_type *terrain) } static void -terraform_selection(selection * selected, const terrain_type *terrain) +terraform_selection(selection * selected, const terrain_type * terrain) { int i; - if (terrain==NULL) return; - for (i=0;i!=MAXTHASH;++i) { - tag ** tp = &selected->tags[i]; + if (terrain == NULL) + return; + for (i = 0; i != MAXTHASH; ++i) { + tag **tp = &selected->tags[i]; + while (*tp) { - region * r; - tag * t = *tp; + region *r; + + tag *t = *tp; + int nx = t->coord.x, ny = t->coord.y; - plane * pl = t->coord.pl; - + + plane *pl = t->coord.pl; + pnormalize(&nx, &ny, pl); r = findregion(nx, ny); - if (r==NULL) { + if (r == NULL) { r = new_region(nx, ny, pl, 0); } terraform_region(r, terrain); @@ -502,21 +552,24 @@ terraform_selection(selection * selected, const terrain_type *terrain) } } -static faction * -select_faction(state * st) +static faction *select_faction(state * st) { list_selection *prev, *ilist = NULL, **iinsert; - list_selection *selected = NULL; - faction * f = factions; - if (!f) return NULL; + list_selection *selected = NULL; + + faction *f = factions; + + if (!f) + return NULL; iinsert = &ilist; prev = ilist; while (f) { char buffer[32]; + sprintf(buffer, "%.4s %.26s", itoa36(f->no), f->name); - insert_selection(iinsert, NULL, buffer, (void*)f); + insert_selection(iinsert, NULL, buffer, (void *)f); f = f->next; } selected = do_selection(ilist, "Select Faction", NULL, NULL); @@ -524,23 +577,27 @@ select_faction(state * st) st->wnd_map->update |= 1; st->wnd_status->update |= 1; - if (selected==NULL) return NULL; - return (faction*)selected->data; + if (selected == NULL) + return NULL; + return (faction *) selected->data; } -static const terrain_type * -select_terrain(state * st, const terrain_type * default_terrain) +static const terrain_type *select_terrain(state * st, + const terrain_type * default_terrain) { list_selection *prev, *ilist = NULL, **iinsert; - list_selection *selected = NULL; - const terrain_type * terrain = terrains(); - if (!terrain) return NULL; + list_selection *selected = NULL; + + const terrain_type *terrain = terrains(); + + if (!terrain) + return NULL; iinsert = &ilist; prev = ilist; while (terrain) { - insert_selection(iinsert, NULL, terrain->_name, (void*)terrain); + insert_selection(iinsert, NULL, terrain->_name, (void *)terrain); terrain = terrain->next; } selected = do_selection(ilist, "Terrain", NULL, NULL); @@ -548,12 +605,12 @@ select_terrain(state * st, const terrain_type * default_terrain) st->wnd_map->update |= 1; st->wnd_status->update |= 1; - if (selected==NULL) return NULL; - return (const terrain_type*)selected->data; + if (selected == NULL) + return NULL; + return (const terrain_type *)selected->data; } -static coordinate * -region2coord(const region * r, coordinate * c) +static coordinate *region2coord(const region * r, coordinate * c) { c->x = r->x; c->y = r->y; @@ -573,138 +630,156 @@ region2coord(const region * r, coordinate * c) #define FAST_RIGHT KEY_SRIGHT #endif -void -highlight_region(region *r, int toggle) +void highlight_region(region * r, int toggle) { - if (r!=NULL) { - if (toggle) r->flags |= RF_MAPPER_HIGHLIGHT; - else r->flags &= ~RF_MAPPER_HIGHLIGHT; + if (r != NULL) { + if (toggle) + r->flags |= RF_MAPPER_HIGHLIGHT; + else + r->flags &= ~RF_MAPPER_HIGHLIGHT; } } -void -select_coordinate(struct selection * selected, int nx, int ny, int toggle) +void select_coordinate(struct selection *selected, int nx, int ny, int toggle) { - if (toggle) tag_region(selected, nx, ny); - else untag_region(selected, nx, ny); + if (toggle) + tag_region(selected, nx, ny); + else + untag_region(selected, nx, ny); } enum { MODE_MARK, MODE_SELECT, MODE_UNMARK, MODE_UNSELECT }; -static void -select_regions(state * st, int selectmode) +static void select_regions(state * st, int selectmode) { char sbuffer[80]; + int findmode; - const char * statustext[] = { + + const char *statustext[] = { "mark-", "select-", "unmark-", "deselect-" }; - const char * status = statustext[selectmode]; + const char *status = statustext[selectmode]; + statusline(st->wnd_status->handle, status); doupdate(); findmode = getch(); - if (findmode=='n') { /* none */ + if (findmode == 'n') { /* none */ int i; + sprintf(sbuffer, "%snone", status); statusline(st->wnd_status->handle, sbuffer); - if (selectmode&MODE_SELECT) { - for (i=0;i!=MAXTHASH;++i) { - tag ** tp = &st->selected->tags[i]; + if (selectmode & MODE_SELECT) { + for (i = 0; i != MAXTHASH; ++i) { + tag **tp = &st->selected->tags[i]; + while (*tp) { - tag * t = *tp; + tag *t = *tp; + *tp = t->nexthash; free(t); } } } else { - region * r; - for (r=regions;r;r=r->next) { + region *r; + + for (r = regions; r; r = r->next) { r->flags &= ~RF_MAPPER_HIGHLIGHT; } } - } - else if (findmode=='m') { - region * r; + } else if (findmode == 'm') { + region *r; + sprintf(sbuffer, "%smonsters", status); statusline(st->wnd_status->handle, sbuffer); - for (r=regions;r;r=r->next) { - unit * u = r->units; - for (;u;u=u->next) { - if (fval(u->faction, FFL_NPC)!=0) break; + for (r = regions; r; r = r->next) { + unit *u = r->units; + + for (; u; u = u->next) { + if (fval(u->faction, FFL_NPC) != 0) + break; } if (u) { - if (selectmode&MODE_SELECT) { - select_coordinate(st->selected, r->x, r->y, selectmode==MODE_SELECT); + if (selectmode & MODE_SELECT) { + select_coordinate(st->selected, r->x, r->y, + selectmode == MODE_SELECT); } else { - highlight_region(r, selectmode==MODE_MARK); + highlight_region(r, selectmode == MODE_MARK); } } } - } - else if (findmode=='p') { - region * r; + } else if (findmode == 'p') { + region *r; + sprintf(sbuffer, "%splayers", status); statusline(st->wnd_status->handle, sbuffer); - for (r=regions;r;r=r->next) { - unit * u = r->units; - for (;u;u=u->next) { - if (fval(u->faction, FFL_NPC)==0) break; + for (r = regions; r; r = r->next) { + unit *u = r->units; + + for (; u; u = u->next) { + if (fval(u->faction, FFL_NPC) == 0) + break; } if (u) { - if (selectmode&MODE_SELECT) { - select_coordinate(st->selected, r->x, r->y, selectmode==MODE_SELECT); + if (selectmode & MODE_SELECT) { + select_coordinate(st->selected, r->x, r->y, + selectmode == MODE_SELECT); } else { - highlight_region(r, selectmode==MODE_MARK); + highlight_region(r, selectmode == MODE_MARK); } } } - } - else if (findmode=='u') { - region * r; + } else if (findmode == 'u') { + region *r; + sprintf(sbuffer, "%sunits", status); statusline(st->wnd_status->handle, sbuffer); - for (r=regions;r;r=r->next) { + for (r = regions; r; r = r->next) { if (r->units) { - if (selectmode&MODE_SELECT) { - select_coordinate(st->selected, r->x, r->y, selectmode==MODE_SELECT); + if (selectmode & MODE_SELECT) { + select_coordinate(st->selected, r->x, r->y, + selectmode == MODE_SELECT); } else { - highlight_region(r, selectmode==MODE_MARK); + highlight_region(r, selectmode == MODE_MARK); } } } - } - else if (findmode=='s') { - region * r; + } else if (findmode == 's') { + region *r; + sprintf(sbuffer, "%sships", status); statusline(st->wnd_status->handle, sbuffer); - for (r=regions;r;r=r->next) { + for (r = regions; r; r = r->next) { if (r->ships) { - if (selectmode&MODE_SELECT) { - select_coordinate(st->selected, r->x, r->y, selectmode==MODE_SELECT); + if (selectmode & MODE_SELECT) { + select_coordinate(st->selected, r->x, r->y, + selectmode == MODE_SELECT); } else { - highlight_region(r, selectmode==MODE_MARK); + highlight_region(r, selectmode == MODE_MARK); } } } - } - else if (findmode=='f') { + } else if (findmode == 'f') { char fbuffer[12]; + sprintf(sbuffer, "%sfaction:", status); askstring(st->wnd_status->handle, sbuffer, fbuffer, 12); if (fbuffer[0]) { - faction * f = findfaction(atoi36(fbuffer)); + faction *f = findfaction(atoi36(fbuffer)); - if (f!=NULL) { - unit * u; + if (f != NULL) { + unit *u; sprintf(sbuffer, "%sfaction: %s", status, itoa36(f->no)); statusline(st->wnd_status->handle, sbuffer); - for (u=f->units;u;u=u->nextF) { - region * r = u->region; - if (selectmode&MODE_SELECT) { - select_coordinate(st->selected, r->x, r->y, selectmode==MODE_SELECT); + for (u = f->units; u; u = u->nextF) { + region *r = u->region; + + if (selectmode & MODE_SELECT) { + select_coordinate(st->selected, r->x, r->y, + selectmode == MODE_SELECT); } else { - highlight_region(r, selectmode==MODE_MARK); + highlight_region(r, selectmode == MODE_MARK); } } } else { @@ -713,22 +788,24 @@ select_regions(state * st, int selectmode) return; } } - } - else if (findmode=='t') { - const struct terrain_type * terrain; + } else if (findmode == 't') { + const struct terrain_type *terrain; + sprintf(sbuffer, "%sterrain: ", status); statusline(st->wnd_status->handle, sbuffer); terrain = select_terrain(st, NULL); - if (terrain!=NULL) { - region * r; + if (terrain != NULL) { + region *r; + sprintf(sbuffer, "%sterrain: %s", status, terrain->_name); statusline(st->wnd_status->handle, sbuffer); - for (r=regions;r;r=r->next) { - if (r->terrain==terrain) { - if (selectmode&MODE_SELECT) { - select_coordinate(st->selected, r->x, r->y, selectmode==MODE_SELECT); + for (r = regions; r; r = r->next) { + if (r->terrain == terrain) { + if (selectmode & MODE_SELECT) { + select_coordinate(st->selected, r->x, r->y, + selectmode == MODE_SELECT); } else { - highlight_region(r, selectmode==MODE_MARK); + highlight_region(r, selectmode == MODE_MARK); } } } @@ -743,383 +820,422 @@ select_regions(state * st, int selectmode) st->wnd_map->update |= 3; } -static void -handlekey(state * st, int c) +static void handlekey(state * st, int c) { - window * wnd; - coordinate * cursor = &st->cursor; + window *wnd; + + coordinate *cursor = &st->cursor; + static char locate[80]; + static int findmode = 0; + region *r; + char sbuffer[80]; + static char kbuffer[80]; + int n, nx, ny; - switch(c) { - case FAST_RIGHT: - cursor->x+=10; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case FAST_LEFT: - cursor->x-=10; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case FAST_UP: - cursor->y+=10; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case FAST_DOWN: - cursor->y-=10; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case KEY_UP: - cursor->y++; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case KEY_DOWN: - cursor->y--; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case KEY_RIGHT: - cursor->x++; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case KEY_LEFT: - cursor->x--; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - case 'S': - case KEY_SAVE: - case KEY_F(2): - /* if (st->modified) */ { + switch (c) { + case FAST_RIGHT: + cursor->x += 10; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case FAST_LEFT: + cursor->x -= 10; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case FAST_UP: + cursor->y += 10; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case FAST_DOWN: + cursor->y -= 10; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case KEY_UP: + cursor->y++; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case KEY_DOWN: + cursor->y--; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case KEY_RIGHT: + cursor->x++; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case KEY_LEFT: + cursor->x--; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + break; + case 'S': + case KEY_SAVE: + case KEY_F(2): + /* if (st->modified) */ { char datafile[MAX_PATH]; askstring(st->wnd_status->handle, "save as:", datafile, sizeof(datafile)); - if (strlen(datafile)>0) { + if (strlen(datafile) > 0) { create_backup(datafile); remove_empty_units(); writegame(datafile, IO_DEFAULT); st->modified = 0; } } - break; - case 'B': - /* - make_block(st->cursor.x, st->cursor.y, 6, select_terrain(st, NULL)); - */ - cnormalize(&st->cursor, &nx, &ny); - n = rng_int() % 8 + 8; - build_island_e3(nx, ny, n, n*3); - st->modified = 1; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - st->wnd_map->update |= 1; - break; - case 0x02: /* CTRL+b */ - cnormalize(&st->cursor, &nx, &ny); - make_block(nx, ny, 6, newterrain(T_OCEAN)); - st->modified = 1; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - st->wnd_map->update |= 1; - break; - case 0x09: /* tab = next selected*/ - if (regions!=NULL) { - map_region * mr = cursor_region(&st->display, cursor); - if (mr) { - region * first = mr->r; - region * cur = (first&&first->next)?first->next:regions; - - while (cur!=first) { - coordinate coord; - region2coord(cur, &coord); - cnormalize(&coord, &nx, &ny); - if (tagged_region(st->selected, nx, ny)) { - st->cursor = coord; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - break; - } - cur = cur->next; - if (!cur && first) cur = regions; - } - } - } - break; - - case 'p': - if (planes) { - plane * pl = planes; - if (cursor->pl) { - while (pl && pl!=cursor->pl) { - pl = pl->next; - } - if (pl && pl->next) { - cursor->pl = pl->next; - } else { - cursor->pl = get_homeplane(); - } - } else { - cursor->pl = planes; - } - } - break; - - case 'a': - if (regions!=NULL) { - map_region * mr = cursor_region(&st->display, cursor); - if (mr && mr->r) { - region * cur = mr->r; - plane * pl = rplane(cur); - if (pl==NULL) { - cur = r_standard_to_astral(cur); - } else if (is_astral(cur)) { - cur = r_astral_to_standard(cur); - } else { - cur = NULL; - } - if (cur!=NULL) { - region2coord(cur, &st->cursor); - } else { - beep(); - } - } - } - break; - case 'g': - askstring(st->wnd_status->handle, "goto-x:", sbuffer, 12); - if (sbuffer[0]) { - askstring(st->wnd_status->handle, "goto-y:", sbuffer+16, 12); - if (sbuffer[16]) { - st->cursor.x = atoi(sbuffer); - st->cursor.y = atoi(sbuffer+16); - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - } - } - break; - case 0x14: /* C-t */ - terraform_at(&st->cursor, select_terrain(st, NULL)); - st->modified = 1; - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - st->wnd_map->update |= 1; - break; - case 'I': - statusline(st->wnd_status->handle, "info-"); - doupdate(); - do { - c = getch(); - switch (c) { - case 's': - st->info_flags ^= IFL_SHIPS; - if (st->info_flags & IFL_SHIPS) statusline(st->wnd_status->handle, "info-ships true"); - else statusline(st->wnd_status->handle, "info-ships false"); - break; - case 'b': - st->info_flags ^= IFL_BUILDINGS; - if (st->info_flags & IFL_BUILDINGS) statusline(st->wnd_status->handle, "info-buildings true"); - else statusline(st->wnd_status->handle, "info-buildings false"); - case 'f': - st->info_flags ^= IFL_FACTIONS; - if (st->info_flags & IFL_FACTIONS) statusline(st->wnd_status->handle, "info-factions true"); - else statusline(st->wnd_status->handle, "info-factions false"); - break; - case 'u': - st->info_flags ^= IFL_UNITS; - if (st->info_flags & IFL_UNITS) statusline(st->wnd_status->handle, "info-units true"); - else statusline(st->wnd_status->handle, "info-units false"); - break; - case 27: /* esc */ - break; - default: - beep(); - c = 0; - } - } while (c==0); - break; - case 'L': - if (global.vm_state) { - move(0, 0); - refresh(); - lua_do((struct lua_State*)global.vm_state); - /* todo: do this from inside the script */ - clear(); - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - st->wnd_map->update |= 1; - } - break; - case 12: /* Ctrl-L */ - clear(); - st->wnd_info->update |= 1; - st->wnd_status->update |= 1; - st->wnd_map->update |= 1; - break; - case 'h': - select_regions(st, MODE_MARK); - break; - case 'H': - select_regions(st, MODE_UNMARK); - break; - case 't': - select_regions(st, MODE_SELECT); - break; - case 'T': - select_regions(st, MODE_UNSELECT); - break; - case ';': - statusline(st->wnd_status->handle, "tag-"); - doupdate(); - switch (getch()) { - case 't': - terraform_selection(st->selected, select_terrain(st, NULL)); + break; + case 'B': + /* + make_block(st->cursor.x, st->cursor.y, 6, select_terrain(st, NULL)); + */ + cnormalize(&st->cursor, &nx, &ny); + n = rng_int() % 8 + 8; + build_island_e3(nx, ny, n, n * 3); st->modified = 1; st->wnd_info->update |= 1; st->wnd_status->update |= 1; st->wnd_map->update |= 1; break; - case 'm': + case 0x02: /* CTRL+b */ + cnormalize(&st->cursor, &nx, &ny); + make_block(nx, ny, 6, newterrain(T_OCEAN)); + st->modified = 1; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; break; - default: - statusline(st->wnd_status->handle, "unknown command."); - beep(); - } - break; - case ' ': - cnormalize(cursor, &nx, &ny); - if (tagged_region(st->selected, nx, ny)) untag_region(st->selected, nx, ny); - else tag_region(st->selected, nx, ny); - break; - case 'A': - sprintf(sbuffer, "%s/newfactions", basepath()); - seed_players(sbuffer, false); - st->wnd_map->update |= 1; - break; - case '/': - statusline(st->wnd_status->handle, "find-"); - doupdate(); - findmode = getch(); - if (findmode=='r') { - askstring(st->wnd_status->handle, "find-region:", locate, sizeof(locate)); - } else if (findmode=='u') { - askstring(st->wnd_status->handle, "find-unit:", locate, sizeof(locate)); - } else if (findmode=='f') { - askstring(st->wnd_status->handle, "find-faction:", locate, sizeof(locate)); - } else if (findmode=='F') { - faction * f = select_faction(st); - if (f!=NULL) { - strcpy(locate, itoa36(f->no)); - findmode='f'; - } else { - break; - } - } else { - statusline(st->wnd_status->handle, "unknown command."); - beep(); - break; - } - /* achtung: fall-through ist absicht: */ - if (!strlen(locate)) break; - case 'n': - if (findmode=='u') { - unit * u = findunit(atoi36(locate)); - r = u?u->region:NULL; - } else if (findmode && regions!=NULL) { - struct faction * f = NULL; - map_region * mr = cursor_region(&st->display, cursor); - region * first = (mr && mr->r && mr->r->next)?mr->r->next:regions; + case 0x09: /* tab = next selected */ + if (regions != NULL) { + map_region *mr = cursor_region(&st->display, cursor); - if (findmode=='f') { - sprintf(sbuffer, "find-faction: %s", locate); - statusline(st->wnd_status->handle, sbuffer); - f = findfaction(atoi36(locate)); - if (f==NULL) { - statusline(st->wnd_status->handle, "faction not found."); - beep(); - break; - } - } - for (r=first;;) { - if (findmode=='r' && r->land && r->land->name && strstr((const char*)r->land->name, locate)) { - break; - } else if (findmode=='f') { - unit * u; - for (u=r->units;u;u=u->next) { - if (u->faction==f) { + if (mr) { + region *first = mr->r; + + region *cur = (first && first->next) ? first->next : regions; + + while (cur != first) { + coordinate coord; + + region2coord(cur, &coord); + cnormalize(&coord, &nx, &ny); + if (tagged_region(st->selected, nx, ny)) { + st->cursor = coord; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; break; } + cur = cur->next; + if (!cur && first) + cur = regions; } - if (u) break; } - r = r->next; - if (r==NULL) r = regions; - if (r==first) { - r = NULL; - statusline(st->wnd_status->handle, "not found."); + } + break; + + case 'p': + if (planes) { + plane *pl = planes; + + if (cursor->pl) { + while (pl && pl != cursor->pl) { + pl = pl->next; + } + if (pl && pl->next) { + cursor->pl = pl->next; + } else { + cursor->pl = get_homeplane(); + } + } else { + cursor->pl = planes; + } + } + break; + + case 'a': + if (regions != NULL) { + map_region *mr = cursor_region(&st->display, cursor); + + if (mr && mr->r) { + region *cur = mr->r; + + plane *pl = rplane(cur); + + if (pl == NULL) { + cur = r_standard_to_astral(cur); + } else if (is_astral(cur)) { + cur = r_astral_to_standard(cur); + } else { + cur = NULL; + } + if (cur != NULL) { + region2coord(cur, &st->cursor); + } else { + beep(); + } + } + } + break; + case 'g': + askstring(st->wnd_status->handle, "goto-x:", sbuffer, 12); + if (sbuffer[0]) { + askstring(st->wnd_status->handle, "goto-y:", sbuffer + 16, 12); + if (sbuffer[16]) { + st->cursor.x = atoi(sbuffer); + st->cursor.y = atoi(sbuffer + 16); + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + } + } + break; + case 0x14: /* C-t */ + terraform_at(&st->cursor, select_terrain(st, NULL)); + st->modified = 1; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + break; + case 'I': + statusline(st->wnd_status->handle, "info-"); + doupdate(); + do { + c = getch(); + switch (c) { + case 's': + st->info_flags ^= IFL_SHIPS; + if (st->info_flags & IFL_SHIPS) + statusline(st->wnd_status->handle, "info-ships true"); + else + statusline(st->wnd_status->handle, "info-ships false"); + break; + case 'b': + st->info_flags ^= IFL_BUILDINGS; + if (st->info_flags & IFL_BUILDINGS) + statusline(st->wnd_status->handle, "info-buildings true"); + else + statusline(st->wnd_status->handle, "info-buildings false"); + case 'f': + st->info_flags ^= IFL_FACTIONS; + if (st->info_flags & IFL_FACTIONS) + statusline(st->wnd_status->handle, "info-factions true"); + else + statusline(st->wnd_status->handle, "info-factions false"); + break; + case 'u': + st->info_flags ^= IFL_UNITS; + if (st->info_flags & IFL_UNITS) + statusline(st->wnd_status->handle, "info-units true"); + else + statusline(st->wnd_status->handle, "info-units false"); + break; + case 27: /* esc */ + break; + default: + beep(); + c = 0; + } + } while (c == 0); + break; + case 'L': + if (global.vm_state) { + move(0, 0); + refresh(); + lua_do((struct lua_State *)global.vm_state); + + /* todo: do this from inside the script */ + clear(); + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + } + break; + case 12: /* Ctrl-L */ + clear(); + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + break; + case 'h': + select_regions(st, MODE_MARK); + break; + case 'H': + select_regions(st, MODE_UNMARK); + break; + case 't': + select_regions(st, MODE_SELECT); + break; + case 'T': + select_regions(st, MODE_UNSELECT); + break; + case ';': + statusline(st->wnd_status->handle, "tag-"); + doupdate(); + switch (getch()) { + case 't': + terraform_selection(st->selected, select_terrain(st, NULL)); + st->modified = 1; + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; + st->wnd_map->update |= 1; + break; + case 'm': + break; + default: + statusline(st->wnd_status->handle, "unknown command."); beep(); + } + break; + case ' ': + cnormalize(cursor, &nx, &ny); + if (tagged_region(st->selected, nx, ny)) + untag_region(st->selected, nx, ny); + else + tag_region(st->selected, nx, ny); + break; + case 'A': + sprintf(sbuffer, "%s/newfactions", basepath()); + seed_players(sbuffer, false); + st->wnd_map->update |= 1; + break; + case '/': + statusline(st->wnd_status->handle, "find-"); + doupdate(); + findmode = getch(); + if (findmode == 'r') { + askstring(st->wnd_status->handle, "find-region:", locate, + sizeof(locate)); + } else if (findmode == 'u') { + askstring(st->wnd_status->handle, "find-unit:", locate, sizeof(locate)); + } else if (findmode == 'f') { + askstring(st->wnd_status->handle, "find-faction:", locate, + sizeof(locate)); + } else if (findmode == 'F') { + faction *f = select_faction(st); + + if (f != NULL) { + strcpy(locate, itoa36(f->no)); + findmode = 'f'; + } else { break; } + } else { + statusline(st->wnd_status->handle, "unknown command."); + beep(); + break; } - } else { - r = NULL; - } - if (r!=NULL) { - region2coord(r, &st->cursor); - st->wnd_info->update |=1; - st->wnd_status->update |=1; - } - break; - case 'Q': - g_quit = 1; - break; - default: - for (wnd=wnd_first;wnd!=NULL;wnd=wnd->next) { - if (wnd->handlekey) { - if (wnd->handlekey(wnd, st, c)) break; + /* achtung: fall-through ist absicht: */ + if (!strlen(locate)) + break; + case 'n': + if (findmode == 'u') { + unit *u = findunit(atoi36(locate)); + + r = u ? u->region : NULL; + } else if (findmode && regions != NULL) { + struct faction *f = NULL; + + map_region *mr = cursor_region(&st->display, cursor); + + region *first = (mr && mr->r && mr->r->next) ? mr->r->next : regions; + + if (findmode == 'f') { + sprintf(sbuffer, "find-faction: %s", locate); + statusline(st->wnd_status->handle, sbuffer); + f = findfaction(atoi36(locate)); + if (f == NULL) { + statusline(st->wnd_status->handle, "faction not found."); + beep(); + break; + } + } + for (r = first;;) { + if (findmode == 'r' && r->land && r->land->name + && strstr((const char *)r->land->name, locate)) { + break; + } else if (findmode == 'f') { + unit *u; + + for (u = r->units; u; u = u->next) { + if (u->faction == f) { + break; + } + } + if (u) + break; + } + r = r->next; + if (r == NULL) + r = regions; + if (r == first) { + r = NULL; + statusline(st->wnd_status->handle, "not found."); + beep(); + break; + } + } + } else { + r = NULL; } - } - if (wnd==NULL) { - if (kbuffer[0]==0) { - strcpy(kbuffer, "getch:"); + if (r != NULL) { + region2coord(r, &st->cursor); + st->wnd_info->update |= 1; + st->wnd_status->update |= 1; } - sprintf(sbuffer, " 0x%x", c); - strncat(kbuffer, sbuffer, sizeof(kbuffer)); - statusline(st->wnd_status->handle, kbuffer); - if (strlen(kbuffer)>70) kbuffer[0]=0; - } - break; + break; + case 'Q': + g_quit = 1; + break; + default: + for (wnd = wnd_first; wnd != NULL; wnd = wnd->next) { + if (wnd->handlekey) { + if (wnd->handlekey(wnd, st, c)) + break; + } + } + if (wnd == NULL) { + if (kbuffer[0] == 0) { + strcpy(kbuffer, "getch:"); + } + sprintf(sbuffer, " 0x%x", c); + strncat(kbuffer, sbuffer, sizeof(kbuffer)); + statusline(st->wnd_status->handle, kbuffer); + if (strlen(kbuffer) > 70) + kbuffer[0] = 0; + } + break; } } -static void -init_view(view * display, WINDOW * win) +static void init_view(view * display, WINDOW * win) { display->topleft.x = 1; display->topleft.y = 1; display->topleft.pl = get_homeplane(); display->pl = get_homeplane(); - display->size.width = getmaxx(win)/TWIDTH; - display->size.height = getmaxy(win)/THEIGHT; - display->regions = calloc(display->size.height * display->size.width, sizeof(map_region)); + display->size.width = getmaxx(win) / TWIDTH; + display->size.height = getmaxy(win) / THEIGHT; + display->regions = + calloc(display->size.height * display->size.width, sizeof(map_region)); } -static void -update_view(view * vi) +static void update_view(view * vi) { int i, j; - for (i=0;i!=vi->size.width;++i) { - for (j=0;j!=vi->size.height;++j) { - map_region * mr = mr_get(vi, i, j); - mr->coord.x = vi->topleft.x + i - j/2; + + for (i = 0; i != vi->size.width; ++i) { + for (j = 0; j != vi->size.height; ++j) { + map_region *mr = mr_get(vi, i, j); + + mr->coord.x = vi->topleft.x + i - j / 2; mr->coord.y = vi->topleft.y + j; mr->coord.pl = vi->pl; pnormalize(&mr->coord.x, &mr->coord.y, mr->coord.pl); @@ -1128,10 +1244,10 @@ update_view(view * vi) } } -state * -state_open(void) +state *state_open(void) { - state * st = calloc(sizeof(state), 1); + state *st = calloc(sizeof(state), 1); + st->display.pl = get_homeplane(); st->cursor.pl = get_homeplane(); st->cursor.x = 0; @@ -1144,26 +1260,30 @@ state_open(void) return st; } -void -state_close(state * st) +void state_close(state * st) { - assert(st==current_state); + assert(st == current_state); current_state = st->prev; free(st); } -void -run_mapper(void) +void run_mapper(void) { - WINDOW * hwinstatus; - WINDOW * hwininfo; - WINDOW * hwinmap; + WINDOW *hwinstatus; + + WINDOW *hwininfo; + + WINDOW *hwinmap; + int width, height, x, y; + int split = 20, old_flags = log_flags; - state * st; + + state *st; + point tl; - log_flags &= ~(LOG_CPERROR|LOG_CPWARNING); + log_flags &= ~(LOG_CPERROR | LOG_CPWARNING); init_curses(); curs_set(1); @@ -1173,9 +1293,10 @@ run_mapper(void) width = getmaxx(stdscr); height = getmaxy(stdscr); - hwinmap = subwin(stdscr, getmaxy(stdscr)-1, getmaxx(stdscr)-split, y, x); - hwininfo = subwin(stdscr, getmaxy(stdscr)-1, split, y, x+getmaxx(stdscr)-split); - hwinstatus = subwin(stdscr, 1, width, height-1, x); + hwinmap = subwin(stdscr, getmaxy(stdscr) - 1, getmaxx(stdscr) - split, y, x); + hwininfo = + subwin(stdscr, getmaxy(stdscr) - 1, split, y, x + getmaxx(stdscr) - split); + hwinstatus = subwin(stdscr, 1, width, height - 1, x); st = state_open(); st->wnd_map = win_create(hwinmap); @@ -1192,17 +1313,20 @@ run_mapper(void) init_view(&st->display, hwinmap); coor2point(&st->display.topleft, &tl); - hstatus = st->wnd_status->handle; /* the lua console needs this */ + hstatus = st->wnd_status->handle; /* the lua console needs this */ while (!g_quit) { int c; + point p; - window * wnd; - view * vi = &st->display; + + window *wnd; + + view *vi = &st->display; getbegyx(hwinmap, x, y); - width = getmaxx(hwinmap)-x; - height = getmaxy(hwinmap)-y; + width = getmaxx(hwinmap) - x; + height = getmaxy(hwinmap) - y; coor2point(&st->cursor, &p); if (st->cursor.pl != vi->pl) { @@ -1210,19 +1334,19 @@ run_mapper(void) st->wnd_map->update |= 1; } if (p.y < tl.y) { - vi->topleft.y = st->cursor.y-vi->size.height/2; + vi->topleft.y = st->cursor.y - vi->size.height / 2; st->wnd_map->update |= 1; - } - else if (p.y >= tl.y + vi->size.height * THEIGHT) { - vi->topleft.y = st->cursor.y-vi->size.height/2; + } else if (p.y >= tl.y + vi->size.height * THEIGHT) { + vi->topleft.y = st->cursor.y - vi->size.height / 2; st->wnd_map->update |= 1; } if (p.x <= tl.x) { - vi->topleft.x = st->cursor.x+(st->cursor.y-vi->topleft.y)/2-vi->size.width / 2; + vi->topleft.x = + st->cursor.x + (st->cursor.y - vi->topleft.y) / 2 - vi->size.width / 2; st->wnd_map->update |= 1; - } - else if (p.x >= tl.x + vi->size.width * TWIDTH-1) { - vi->topleft.x = st->cursor.x+(st->cursor.y-vi->topleft.y)/2-vi->size.width / 2; + } else if (p.x >= tl.x + vi->size.width * TWIDTH - 1) { + vi->topleft.x = + st->cursor.x + (st->cursor.y - vi->topleft.y) / 2 - vi->size.width / 2; st->wnd_map->update |= 1; } @@ -1230,7 +1354,7 @@ run_mapper(void) update_view(vi); coor2point(&vi->topleft, &tl); } - for (wnd=wnd_last;wnd!=NULL;wnd=wnd->prev) { + for (wnd = wnd_last; wnd != NULL; wnd = wnd->prev) { if (wnd->update && wnd->paint) { if (wnd->update & 1) { wnd->paint(wnd, st); @@ -1257,43 +1381,49 @@ run_mapper(void) } int -curses_readline(struct lua_State * L, char * buffer, size_t size, const char * prompt) +curses_readline(struct lua_State *L, char *buffer, size_t size, + const char *prompt) { unused(L); askstring(hstatus, prompt, buffer, size); - return buffer[0]!=0; + return buffer[0] != 0; } -void -seed_players(const char * filename, boolean new_island) +void seed_players(const char *filename, boolean new_island) { - newfaction * players = read_newfactions(filename); - if (players!=NULL) { + newfaction *players = read_newfactions(filename); + + if (players != NULL) { while (players) { int n = listlen(players); - int k = (n+ISLANDSIZE-1)/ISLANDSIZE; + + int k = (n + ISLANDSIZE - 1) / ISLANDSIZE; + k = n / k; - n = autoseed(&players, k, new_island?0:TURNS_PER_ISLAND); - if (n==0) { + n = autoseed(&players, k, new_island ? 0 : TURNS_PER_ISLAND); + if (n == 0) { break; } } } } -void -make_block(int x, int y, int radius, const struct terrain_type * terrain) +void make_block(int x, int y, int radius, const struct terrain_type *terrain) { int cx, cy; + region *r; - plane * pl = findplane(x, y); - if (terrain==NULL) return; + plane *pl = findplane(x, y); - for (cx = x - radius; cx != x+radius; ++cx) { - for (cy = y - radius; cy != y+radius; ++cy) { + if (terrain == NULL) + return; + + for (cx = x - radius; cx != x + radius; ++cx) { + for (cy = y - radius; cy != y + radius; ++cy) { int nx = cx, ny = cy; + pnormalize(&nx, &ny, pl); if (koor_distance(nx, ny, x, y) < radius) { if (!findregion(nx, ny)) { diff --git a/src/gmtool.h b/src/gmtool.h index f0bbd6d86..fa2df80e7 100644 --- a/src/gmtool.h +++ b/src/gmtool.h @@ -20,22 +20,22 @@ extern "C" { struct region; int gmmain(int argc, char *argv[]); - int curses_readline(struct lua_State * L, char * buffer, size_t size, const char * prompt); + int curses_readline(struct lua_State *L, char *buffer, size_t size, + const char *prompt); void highlight_region(struct region *r, int on); - void select_coordinate(struct selection * selected, int x, int y, int on); + void select_coordinate(struct selection *selected, int x, int y, int on); void run_mapper(void); extern int force_color; - struct state * state_open(void); - void state_close(struct state * ); + struct state *state_open(void); + void state_close(struct state *); - void make_block(int x, int y, int radius, const struct terrain_type * terrain); - void seed_players(const char * filename, boolean new_island); + void make_block(int x, int y, int radius, const struct terrain_type *terrain); + void seed_players(const char *filename, boolean new_island); #ifdef __cplusplus } #endif - #endif diff --git a/src/gmtool_structs.h b/src/gmtool_structs.h index 129be7775..49acbf526 100644 --- a/src/gmtool_structs.h +++ b/src/gmtool_structs.h @@ -16,78 +16,79 @@ extern "C" { #endif /* types imported from eressea: */ -struct region; + struct region; -typedef struct extent { - /* Ein Vektor */ - int width, height; -} extent; + typedef struct extent { + /* Ein Vektor */ + int width, height; + } extent; -typedef struct point { - /* Eine Koordinate in einer Ascii-Karte */ - int x, y; -} point; + typedef struct point { + /* Eine Koordinate in einer Ascii-Karte */ + int x, y; + } point; -typedef struct coordinate { - /* Eine Koordinate im Editor, nicht normalisiert */ - int x, y; - struct plane * pl; -} coordinate; + typedef struct coordinate { + /* Eine Koordinate im Editor, nicht normalisiert */ + int x, y; + struct plane *pl; + } coordinate; -typedef struct map_region { - struct region * r; - coordinate coord; -} map_region; + typedef struct map_region { + struct region *r; + coordinate coord; + } map_region; -typedef struct view { - struct map_region * regions; - struct plane * pl; - coordinate topleft; /* upper left corner in map. */ - extent size; /* dimensions. */ -} view; + typedef struct view { + struct map_region *regions; + struct plane *pl; + coordinate topleft; /* upper left corner in map. */ + extent size; /* dimensions. */ + } view; -typedef struct tag { - coordinate coord; - struct tag * nexthash; -} tag; + typedef struct tag { + coordinate coord; + struct tag *nexthash; + } tag; #define MAXTHASH 512 -typedef struct selection { - tag * tags[MAXTHASH]; -} selection; + typedef struct selection { + tag *tags[MAXTHASH]; + } selection; -typedef struct state { - coordinate cursor; - selection * selected; - struct state * prev; - view display; - int modified; - unsigned int info_flags; - struct window * wnd_info; - struct window * wnd_map; - struct window * wnd_status; -} state; + typedef struct state { + coordinate cursor; + selection *selected; + struct state *prev; + view display; + int modified; + unsigned int info_flags; + struct window *wnd_info; + struct window *wnd_map; + struct window *wnd_status; + } state; -typedef struct window { - boolean (*handlekey)(struct window * win, struct state * st, int key); - void (*paint)(struct window * win, const struct state * st); + typedef struct window { + boolean(*handlekey) (struct window * win, struct state * st, int key); + void (*paint) (struct window * win, const struct state * st); - WINDOW * handle; - struct window * next; - struct window * prev; - boolean initialized; - int update; -} window; + WINDOW *handle; + struct window *next; + struct window *prev; + boolean initialized; + int update; + } window; -extern map_region * cursor_region(const view * v, const coordinate * c); -extern void cnormalize(const coordinate * c, int * x, int * y); -extern state * current_state; + extern map_region *cursor_region(const view * v, const coordinate * c); + extern void cnormalize(const coordinate * c, int *x, int *y); + extern state *current_state; -extern void set_info_function(void (*callback)(struct window *, const struct state *)); + extern void set_info_function(void (*callback) (struct window *, + const struct state *)); -#define TWIDTH 2 /* width of tile */ -#define THEIGHT 1 /* height of tile */ +#define TWIDTH 2 /* width of tile */ +#define THEIGHT 1 /* height of tile */ #ifdef WIN32 #define wxborder(win) wborder(win, 0, 0, 0, 0, 0, 0, 0, 0) @@ -98,5 +99,4 @@ extern void set_info_function(void (*callback)(struct window *, const struct sta #ifdef __cplusplus } #endif - #endif diff --git a/src/items/artrewards.c b/src/items/artrewards.c index 06b152f6b..59ad8b1ab 100644 --- a/src/items/artrewards.c +++ b/src/items/artrewards.c @@ -47,30 +47,30 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define HORNDURATION 3 #define HORNIMMUNITY 30 -static int -age_peaceimmune(attrib * a) +static int age_peaceimmune(attrib * a) { - return (--a->data.i>0)?AT_AGE_KEEP:AT_AGE_REMOVE; + return (--a->data.i > 0) ? AT_AGE_KEEP : AT_AGE_REMOVE; } static attrib_type at_peaceimmune = { "peaceimmune", - NULL, NULL, - age_peaceimmune, - a_writeint, - a_readint + NULL, NULL, + age_peaceimmune, + a_writeint, + a_readint }; static int -use_hornofdancing(struct unit * u, const struct item_type * itype, - int amount, struct order * ord) +use_hornofdancing(struct unit *u, const struct item_type *itype, + int amount, struct order *ord) { region *r; - int regionsPacified = 0; - for(r=regions; r; r=r->next) { - if(distance(u->region, r) < HORNRANGE) { - if(a_find(r->attribs, &at_peaceimmune) == NULL) { + int regionsPacified = 0; + + for (r = regions; r; r = r->next) { + if (distance(u->region, r) < HORNRANGE) { + if (a_find(r->attribs, &at_peaceimmune) == NULL) { attrib *a; create_curse(u, &r->attribs, ct_find("peacezone"), @@ -80,21 +80,22 @@ use_hornofdancing(struct unit * u, const struct item_type * itype, a->data.i = HORNIMMUNITY; ADDMSG(&r->msgs, msg_message("hornofpeace_r_success", - "unit region", u, u->region)); + "unit region", u, u->region)); regionsPacified++; } else { ADDMSG(&r->msgs, msg_message("hornofpeace_r_nosuccess", - "unit region", u, u->region)); + "unit region", u, u->region)); } } } - if(regionsPacified > 0) { + if (regionsPacified > 0) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "hornofpeace_u_success", - "pacified", regionsPacified)); + "pacified", regionsPacified)); } else { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "hornofpeace_u_nosuccess", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "hornofpeace_u_nosuccess", + "")); } return 0; @@ -104,12 +105,12 @@ use_hornofdancing(struct unit * u, const struct item_type * itype, static int -useonother_trappedairelemental(struct unit * u, int shipId, - const struct item_type * itype, - int amount, struct order * ord) +useonother_trappedairelemental(struct unit *u, int shipId, + const struct item_type *itype, int amount, struct order *ord) { - curse *c; - ship *sh; + curse *c; + + ship *sh; if (shipId <= 0) { cmistake(u, ord, 20, MSG_MOVE); @@ -117,16 +118,18 @@ useonother_trappedairelemental(struct unit * u, int shipId, } sh = findshipr(u->region, shipId); - if(!sh) { + if (!sh) { cmistake(u, ord, 20, MSG_MOVE); return -1; } - c = create_curse(u, &sh->attribs, ct_find("shipspeedup"), 20, INT_MAX, SPEEDUP, 0); + c = + create_curse(u, &sh->attribs, ct_find("shipspeedup"), 20, INT_MAX, SPEEDUP, + 0); c_setflag(c, CURSE_NOAGE); ADDMSG(&u->faction->msgs, msg_message("trappedairelemental_success", - "unit region command ship", u, u->region, ord, sh)); + "unit region command ship", u, u->region, ord, sh)); use_pooled(u, itype->rtype, GET_DEFAULT, 1); @@ -134,24 +137,23 @@ useonother_trappedairelemental(struct unit * u, int shipId, } static int -use_trappedairelemental(struct unit * u, - const struct item_type * itype, - int amount, struct order * ord) +use_trappedairelemental(struct unit *u, + const struct item_type *itype, int amount, struct order *ord) { ship *sh = u->ship; - if(sh == NULL) { + if (sh == NULL) { cmistake(u, ord, 20, MSG_MOVE); return -1; } - return useonother_trappedairelemental(u, sh->no, itype, amount,ord); + return useonother_trappedairelemental(u, sh->no, itype, amount, ord); } -void -register_artrewards(void) +void register_artrewards(void) { at_register(&at_peaceimmune); register_item_use(use_hornofdancing, "use_hornofdancing"); register_item_use(use_trappedairelemental, "use_trappedairelemental"); - register_item_useonother(useonother_trappedairelemental, "useonother_trappedairelemental"); + register_item_useonother(useonother_trappedairelemental, + "useonother_trappedairelemental"); } diff --git a/src/items/artrewards.h b/src/items/artrewards.h index 552a3b27a..4141c9331 100644 --- a/src/items/artrewards.h +++ b/src/items/artrewards.h @@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern void register_artrewards(void); + extern void register_artrewards(void); #ifdef __cplusplus } diff --git a/src/items/demonseye.c b/src/items/demonseye.c index 6c6ddee15..97eb809b4 100644 --- a/src/items/demonseye.c +++ b/src/items/demonseye.c @@ -35,29 +35,31 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include static int -summon_igjarjuk(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +summon_igjarjuk(struct unit *u, const struct item_type *itype, int amount, + struct order *ord) { - struct plane * p = rplane(u->region); - unused(amount); - unused(itype); - if (p!=NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "use_realworld_only", "")); - return EUNUSABLE; - } else { - assert(!"not implemented"); - return EUNUSABLE; - } + struct plane *p = rplane(u->region); + + unused(amount); + unused(itype); + if (p != NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "use_realworld_only", "")); + return EUNUSABLE; + } else { + assert(!"not implemented"); + return EUNUSABLE; + } } static int -give_igjarjuk(struct unit * src, struct unit * d, const struct item_type * itype, int n, struct order * ord) +give_igjarjuk(struct unit *src, struct unit *d, const struct item_type *itype, + int n, struct order *ord) { ADDMSG(&src->faction->msgs, msg_feedback(src, ord, "error_giveeye", "")); return 0; } -void -register_demonseye(void) +void register_demonseye(void) { register_item_use(summon_igjarjuk, "useigjarjuk"); register_item_give(give_igjarjuk, "giveigjarjuk"); diff --git a/src/items/demonseye.h b/src/items/demonseye.h index be802d6dc..155eac8c6 100644 --- a/src/items/demonseye.h +++ b/src/items/demonseye.h @@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern void register_demonseye(void); + extern void register_demonseye(void); #ifdef __cplusplus } diff --git a/src/items/itemtypes.c b/src/items/itemtypes.c index af0efe305..eb72449ea 100644 --- a/src/items/itemtypes.c +++ b/src/items/itemtypes.c @@ -20,8 +20,7 @@ #include "weapons.h" #include "seed.h" -void -register_itemtypes(void) +void register_itemtypes(void) { /* registering misc. functions */ register_weapons(); @@ -30,8 +29,7 @@ register_itemtypes(void) register_phoenixcompass(); } -void -init_itemtypes(void) +void init_itemtypes(void) { init_seed(); init_mallornseed(); diff --git a/src/items/itemtypes.h b/src/items/itemtypes.h index 1cc8fecec..f1a70a705 100644 --- a/src/items/itemtypes.h +++ b/src/items/itemtypes.h @@ -16,8 +16,8 @@ extern "C" { #endif -extern void init_itemtypes(void); -extern void register_itemtypes(void); + extern void init_itemtypes(void); + extern void register_itemtypes(void); #ifdef __cplusplus } diff --git a/src/items/phoenixcompass.c b/src/items/phoenixcompass.c index ffe208797..6828493cc 100644 --- a/src/items/phoenixcompass.c +++ b/src/items/phoenixcompass.c @@ -39,38 +39,48 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include static int -use_phoenixcompass(struct unit * u, const struct item_type * itype, - int amount, struct order * ord) +use_phoenixcompass(struct unit *u, const struct item_type *itype, + int amount, struct order *ord) { - region *r; - unit *closest_phoenix = NULL; - int closest_phoenix_distance = INT_MAX; - boolean confusion = false; - direction_t direction; - unit *u2; - direction_t closest_neighbour_direction = 0; - static race * rc_phoenix = NULL; - - if (rc_phoenix==NULL) { + region *r; + + unit *closest_phoenix = NULL; + + int closest_phoenix_distance = INT_MAX; + + boolean confusion = false; + + direction_t direction; + + unit *u2; + + direction_t closest_neighbour_direction = 0; + + static race *rc_phoenix = NULL; + + if (rc_phoenix == NULL) { rc_phoenix = rc_find("phoenix"); - if (rc_phoenix==NULL) return 0; + if (rc_phoenix == NULL) + return 0; } /* find the closest phoenix. */ - for(r=regions; r; r=r->next) { - for(u2=r->units; u2; u2=u2->next) { + for (r = regions; r; r = r->next) { + for (u2 = r->units; u2; u2 = u2->next) { if (u2->race == rc_phoenix) { - if(closest_phoenix == NULL) { + if (closest_phoenix == NULL) { closest_phoenix = u2; - closest_phoenix_distance = distance(u->region, closest_phoenix->region); + closest_phoenix_distance = + distance(u->region, closest_phoenix->region); } else { int dist = distance(u->region, r); - if(dist < closest_phoenix_distance) { + + if (dist < closest_phoenix_distance) { closest_phoenix = u2; closest_phoenix_distance = dist; confusion = false; - } else if(dist == closest_phoenix_distance) { + } else if (dist == closest_phoenix_distance) { confusion = true; } } @@ -81,9 +91,8 @@ use_phoenixcompass(struct unit * u, const struct item_type * itype, /* no phoenix found at all.* if confusion == true more than one phoenix * at the same distance was found and the device is confused */ - if(closest_phoenix == NULL - || closest_phoenix->region == u->region - || confusion == true) { + if (closest_phoenix == NULL + || closest_phoenix->region == u->region || confusion == true) { add_message(&u->faction->msgs, msg_message("phoenixcompass_confusion", "unit region command", u, u->region, ord)); return 0; @@ -93,17 +102,19 @@ use_phoenixcompass(struct unit * u, const struct item_type * itype, * neighbouring region which is closest to the phoenix found. hardcoded * for readability. */ - for(direction = 0; direction < MAXDIRECTIONS; ++direction) { - region *neighbour; - int closest_neighbour_distance = INT_MAX; - + for (direction = 0; direction < MAXDIRECTIONS; ++direction) { + region *neighbour; + + int closest_neighbour_distance = INT_MAX; + neighbour = r_connect(u->region, direction); - if(neighbour != NULL) { + if (neighbour != NULL) { int dist = distance(neighbour, closest_phoenix->region); - if(dist < closest_neighbour_distance) { + + if (dist < closest_neighbour_distance) { closest_neighbour_direction = direction; closest_neighbour_distance = dist; - } else if(dist == closest_neighbour_distance && rng_int()%100 < 50) { + } else if (dist == closest_neighbour_distance && rng_int() % 100 < 50) { /* there can never be more than two neighbours with the same * distance (except when you are standing in the same region * as the phoenix, but that case has already been handled). @@ -115,15 +126,13 @@ use_phoenixcompass(struct unit * u, const struct item_type * itype, } add_message(&u->faction->msgs, msg_message("phoenixcompass_success", - "unit region command dir", - u, u->region, ord, closest_neighbour_direction)); + "unit region command dir", + u, u->region, ord, closest_neighbour_direction)); return 0; } -void -register_phoenixcompass(void) +void register_phoenixcompass(void) { register_item_use(use_phoenixcompass, "use_phoenixcompass"); } - diff --git a/src/items/phoenixcompass.h b/src/items/phoenixcompass.h index b99876056..7bb03ba62 100644 --- a/src/items/phoenixcompass.h +++ b/src/items/phoenixcompass.h @@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern void register_phoenixcompass(void); + extern void register_phoenixcompass(void); #ifdef __cplusplus } diff --git a/src/items/seed.c b/src/items/seed.c index 3ad84e0c7..ed921eabe 100644 --- a/src/items/seed.c +++ b/src/items/seed.c @@ -28,34 +28,34 @@ /* libc includes */ #include -resource_type * rt_seed = 0; -resource_type * rt_mallornseed = 0; +resource_type *rt_seed = 0; -static void -produce_seeds(region * r, const resource_type * rtype, int norders) +resource_type *rt_mallornseed = 0; + +static void produce_seeds(region * r, const resource_type * rtype, int norders) { - assert(rtype==rt_seed && r->land && r->land->trees[0] >= norders); - r->land->trees[0] -= norders; + assert(rtype == rt_seed && r->land && r->land->trees[0] >= norders); + r->land->trees[0] -= norders; } -static int -limit_seeds(const region * r, const resource_type * rtype) +static int limit_seeds(const region * r, const resource_type * rtype) { - assert(rtype==rt_seed); - if(fval(r, RF_MALLORN)) return 0; - return r->land?r->land->trees[0]:0; + assert(rtype == rt_seed); + if (fval(r, RF_MALLORN)) + return 0; + return r->land ? r->land->trees[0] : 0; } -void -init_seed(void) +void init_seed(void) { - attrib * a; - resource_limit * rdata; + attrib *a; + + resource_limit *rdata; rt_seed = rt_find("seed"); - if (rt_seed!=NULL) { + if (rt_seed != NULL) { a = a_add(&rt_seed->attribs, a_new(&at_resourcelimit)); - rdata = (resource_limit*)a->data.v; + rdata = (resource_limit *) a->data.v; rdata->limit = limit_seeds; rdata->produce = produce_seeds; } @@ -66,34 +66,33 @@ init_seed(void) static void produce_mallornseeds(region * r, const resource_type * rtype, int norders) { - assert(rtype==rt_mallornseed && r->land && r->land->trees[0] >= norders); + assert(rtype == rt_mallornseed && r->land && r->land->trees[0] >= norders); assert(fval(r, RF_MALLORN)); r->land->trees[0] -= norders; } -static int -limit_mallornseeds(const region * r, const resource_type * rtype) +static int limit_mallornseeds(const region * r, const resource_type * rtype) { - assert(rtype==rt_mallornseed); + assert(rtype == rt_mallornseed); if (!fval(r, RF_MALLORN)) { return 0; } - return r->land?r->land->trees[0]:0; + return r->land ? r->land->trees[0] : 0; } -void -init_mallornseed(void) +void init_mallornseed(void) { - attrib * a; - resource_limit * rdata; + attrib *a; + + resource_limit *rdata; rt_mallornseed = rt_find("mallornseed"); - if (rt_mallornseed!=NULL) { + if (rt_mallornseed != NULL) { rt_mallornseed->flags |= RTF_LIMITED; rt_mallornseed->flags |= RTF_POOLED; - + a = a_add(&rt_mallornseed->attribs, a_new(&at_resourcelimit)); - rdata = (resource_limit*)a->data.v; + rdata = (resource_limit *) a->data.v; rdata->limit = limit_mallornseeds; rdata->produce = produce_mallornseeds; } diff --git a/src/items/seed.h b/src/items/seed.h index 7905d8887..ad88fe797 100644 --- a/src/items/seed.h +++ b/src/items/seed.h @@ -23,11 +23,11 @@ extern "C" { #endif -extern struct resource_type * rt_seed; -extern void init_seed(void); + extern struct resource_type *rt_seed; + extern void init_seed(void); -extern struct resource_type * rt_mallornseed; -extern void init_mallornseed(void); + extern struct resource_type *rt_mallornseed; + extern void init_mallornseed(void); #ifdef __cplusplus } diff --git a/src/items/speedsail.c b/src/items/speedsail.c index 0d80e9158..52f1d0c00 100644 --- a/src/items/speedsail.c +++ b/src/items/speedsail.c @@ -38,20 +38,23 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include static int -use_speedsail(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +use_speedsail(struct unit *u, const struct item_type *itype, int amount, + struct order *ord) { - struct plane * p = rplane(u->region); + struct plane *p = rplane(u->region); + unused(amount); unused(itype); - if (p!=NULL) { + if (p != NULL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "use_realworld_only", "")); } else { if (u->ship) { - attrib * a = a_find(u->ship->attribs, &at_speedup); - if (a==NULL) { + attrib *a = a_find(u->ship->attribs, &at_speedup); + + if (a == NULL) { a = a_add(&u->ship->attribs, a_new(&at_speedup)); - a->data.sa[0] = 50; /* speed */ - a->data.sa[1] = 50; /* decay */ + a->data.sa[0] = 50; /* speed */ + a->data.sa[1] = 50; /* decay */ ADDMSG(&u->faction->msgs, msg_message("use_speedsail", "unit", u)); /* Ticket abziehen */ i_change(&u->items, itype, -1); @@ -66,8 +69,7 @@ use_speedsail(struct unit * u, const struct item_type * itype, int amount, struc return EUNUSABLE; } -void -register_speedsail(void) +void register_speedsail(void) { register_item_use(use_speedsail, "use_speedsail"); } diff --git a/src/items/speedsail.h b/src/items/speedsail.h index 2539571a4..45440f358 100644 --- a/src/items/speedsail.h +++ b/src/items/speedsail.h @@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern void register_speedsail(void); + extern void register_speedsail(void); #ifdef __cplusplus } diff --git a/src/items/studypotion.c b/src/items/studypotion.c index 91f7b84f3..960f38cce 100644 --- a/src/items/studypotion.c +++ b/src/items/studypotion.c @@ -15,11 +15,13 @@ /* BEGIN it_studypotion */ #define MAXGAIN 15 static int -use_studypotion(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +use_studypotion(struct unit *u, const struct item_type *itype, int amount, + struct order *ord) { if (get_keyword(u->thisorder) == K_STUDY) { skill_t sk; - skill * sv; + + skill *sv; init_tokens(u->thisorder); skip_token(); @@ -28,16 +30,19 @@ use_studypotion(struct unit * u, const struct item_type * itype, int amount, str if (sv && sv->level > 2) { /* TODO: message */ - } else if (study_cost(u, sk)>0) { + } else if (study_cost(u, sk) > 0) { /* TODO: message */ } else { - attrib * a = a_find(u->attribs, &at_learning); - teaching_info * teach; - if (a==NULL) { + attrib *a = a_find(u->attribs, &at_learning); + + teaching_info *teach; + + if (a == NULL) { a = a_add(&u->attribs, a_new(&at_learning)); } - teach = (teaching_info*) a->data.v; - if (amount>MAXGAIN) amount = MAXGAIN; + teach = (teaching_info *) a->data.v; + if (amount > MAXGAIN) + amount = MAXGAIN; teach->value += amount * 30; if (teach->value > MAXGAIN * 30) { teach->value = MAXGAIN * 30; @@ -49,10 +54,9 @@ use_studypotion(struct unit * u, const struct item_type * itype, int amount, str return EUNUSABLE; } -void -register_studypotion(void) +void register_studypotion(void) { - register_function((pf_generic)use_studypotion, "use_studypotion"); + register_function((pf_generic) use_studypotion, "use_studypotion"); } /* END it_studypotion */ diff --git a/src/items/weapons.c b/src/items/weapons.c index 77a62ce59..a23582c25 100644 --- a/src/items/weapons.c +++ b/src/items/weapons.c @@ -39,64 +39,86 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* damage types */ static boolean -attack_firesword(const troop * at, const struct weapon_type * wtype, int *casualties) +attack_firesword(const troop * at, const struct weapon_type *wtype, + int *casualties) { fighter *fi = at->fighter; + troop dt; + int killed = 0; + const char *damage = "2d8"; - int force = 1+rng_int()%10; - int enemies = count_enemies(fi->side->battle, fi, 0, 1, SELECT_ADVANCE|SELECT_DISTANCE); - + + int force = 1 + rng_int() % 10; + + int enemies = + count_enemies(fi->side->battle, fi, 0, 1, SELECT_ADVANCE | SELECT_DISTANCE); + if (!enemies) { - if (casualties) *casualties = 0; - return true; /* if no enemy found, no use doing standarad attack */ + if (casualties) + *casualties = 0; + return true; /* if no enemy found, no use doing standarad attack */ } - + if (fi->catmsg == -1) { - int i, k=0; - message * msg; - for (i=0;i<=at->index;++i) { - struct weapon * wp = fi->person[i].melee; - if (wp!=NULL && wp->type == wtype) ++k; + int i, k = 0; + + message *msg; + + for (i = 0; i <= at->index; ++i) { + struct weapon *wp = fi->person[i].melee; + + if (wp != NULL && wp->type == wtype) + ++k; } msg = msg_message("battle::useflamingsword", "amount unit", k, fi->unit); message_all(fi->side->battle, msg); msg_release(msg); fi->catmsg = 0; } - + do { - dt = select_enemy(fi, 0, 1, SELECT_ADVANCE|SELECT_DISTANCE); + dt = select_enemy(fi, 0, 1, SELECT_ADVANCE | SELECT_DISTANCE); assert(dt.fighter); --force; killed += terminate(dt, *at, AT_SPELL, damage, 1); } while (force && killed < enemies); - if (casualties) *casualties = killed; + if (casualties) + *casualties = killed; return true; } #define CATAPULT_ATTACKS 6 static boolean -attack_catapult(const troop * at, const struct weapon_type * wtype, int * casualties) +attack_catapult(const troop * at, const struct weapon_type *wtype, + int *casualties) { fighter *af = at->fighter; + unit *au = af->unit; - battle * b = af->side->battle; + + battle *b = af->side->battle; + troop dt; + int d = 0, enemies; - weapon * wp = af->person[at->index].missile; - static item_type * it_catapultammo = NULL; - if (it_catapultammo==NULL) { + + weapon *wp = af->person[at->index].missile; + + static item_type *it_catapultammo = NULL; + + if (it_catapultammo == NULL) { it_catapultammo = it_find("catapultammo"); } - - assert(wp->type==wtype); - assert(af->person[at->index].reload==0); - if (it_catapultammo!=NULL) { - if (get_pooled(au, it_catapultammo->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, 1) <= 0) { + assert(wp->type == wtype); + assert(af->person[at->index].reload == 0); + + if (it_catapultammo != NULL) { + if (get_pooled(au, it_catapultammo->rtype, + GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, 1) <= 0) { /* No ammo. Use other weapon if available. */ return true; } @@ -104,16 +126,18 @@ attack_catapult(const troop * at, const struct weapon_type * wtype, int * casual enemies = count_enemies(b, af, FIGHT_ROW, FIGHT_ROW, SELECT_ADVANCE); enemies = MIN(enemies, CATAPULT_ATTACKS); - if (enemies==0) { - return true; /* allow further attacks */ + if (enemies == 0) { + return true; /* allow further attacks */ } if (af->catmsg == -1) { - int i, k=0; - message * msg; + int i, k = 0; - for (i=0;i<=at->index;++i) { - if (af->person[i].reload==0 && af->person[i].missile == wp) ++k; + message *msg; + + for (i = 0; i <= at->index; ++i) { + if (af->person[i].reload == 0 && af->person[i].missile == wp) + ++k; } msg = msg_message("battle::usecatapult", "amount unit", k, au); message_all(b, msg); @@ -121,37 +145,41 @@ attack_catapult(const troop * at, const struct weapon_type * wtype, int * casual af->catmsg = 0; } - if (it_catapultammo!=NULL) { - use_pooled(au, it_catapultammo->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, 1); + if (it_catapultammo != NULL) { + use_pooled(au, it_catapultammo->rtype, + GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, 1); } - while (--enemies >= 0) { - /* Select defender */ - dt = select_enemy(af, FIGHT_ROW, FIGHT_ROW, SELECT_ADVANCE); - if (!dt.fighter) - break; + while (--enemies >= 0) { + /* Select defender */ + dt = select_enemy(af, FIGHT_ROW, FIGHT_ROW, SELECT_ADVANCE); + if (!dt.fighter) + break; - /* If battle succeeds */ - if (hits(*at, dt, wp)) { - d += terminate(dt, *at, AT_STANDARD, wp->type->damage[0], true); + /* If battle succeeds */ + if (hits(*at, dt, wp)) { + d += terminate(dt, *at, AT_STANDARD, wp->type->damage[0], true); #ifdef CATAPULT_STRUCTURAL_DAMAGE - if (dt.fighter->unit->building && rng_int()%100 < 5) { - float dmg = get_param_flt(global.parameters, "rules.building.damage.catapult", 1); - damage_building(b, dt.fighter->unit->building, dmg); - } else if (dt.fighter->unit->ship && rng_int()%100 < 5) { - float dmg = get_param_flt(global.parameters, "rules.ship.damage.catapult", 0.01); - damage_ship(dt.fighter->unit->ship, dmg) - } + if (dt.fighter->unit->building && rng_int() % 100 < 5) { + float dmg = + get_param_flt(global.parameters, "rules.building.damage.catapult", 1); + damage_building(b, dt.fighter->unit->building, dmg); + } else if (dt.fighter->unit->ship && rng_int() % 100 < 5) { + float dmg = + get_param_flt(global.parameters, "rules.ship.damage.catapult", 0.01); + damage_ship(dt.fighter->unit->ship, dmg) + } #endif - } - } + } + } - if (casualties) *casualties = d; - return false; /* keine weitren attacken */ + if (casualties) + *casualties = d; + return false; /* keine weitren attacken */ } -void -register_weapons(void) + +void register_weapons(void) { - register_function((pf_generic)attack_catapult, "attack_catapult"); - register_function((pf_generic)attack_firesword, "attack_firesword"); + register_function((pf_generic) attack_catapult, "attack_catapult"); + register_function((pf_generic) attack_firesword, "attack_firesword"); } diff --git a/src/items/weapons.h b/src/items/weapons.h index cc44aa390..d63bbd6ee 100644 --- a/src/items/weapons.h +++ b/src/items/weapons.h @@ -16,7 +16,7 @@ extern "C" { #endif -extern void register_weapons(void); + extern void register_weapons(void); #ifdef __cplusplus } diff --git a/src/items/xerewards.c b/src/items/xerewards.c index c7cda363a..953b800b1 100644 --- a/src/items/xerewards.c +++ b/src/items/xerewards.c @@ -39,7 +39,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include static int -use_skillpotion(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +use_skillpotion(struct unit *u, const struct item_type *itype, int amount, + struct order *ord) { /* the problem with making this a lua function is that there's no way * to get the list of skills for a unit. and with the way skills are @@ -47,11 +48,15 @@ use_skillpotion(struct unit * u, const struct item_type * itype, int amount, str * from them) */ int n; - for (n=0;n!=amount;++n) { - skill * sv = u->skills; - while (sv!=u->skills+u->skill_size) { + + for (n = 0; n != amount; ++n) { + skill *sv = u->skills; + + while (sv != u->skills + u->skill_size) { int i; - for (i=0;i!=3;++i) learn_skill(u, sv->id, 1.0); + + for (i = 0; i != 3; ++i) + learn_skill(u, sv->id, 1.0); ++sv; } } @@ -62,30 +67,29 @@ use_skillpotion(struct unit * u, const struct item_type * itype, int amount, str } static int -use_manacrystal(struct unit * u, const struct item_type * itype, int amount, struct order * ord) +use_manacrystal(struct unit *u, const struct item_type *itype, int amount, + struct order *ord) { - int i, sp = 0; + int i, sp = 0; - if(!is_mage(u)) { - cmistake(u, u->thisorder, 295, MSG_EVENT); - return -1; - } + if (!is_mage(u)) { + cmistake(u, u->thisorder, 295, MSG_EVENT); + return -1; + } - for (i=0;i!=amount;++i) { - sp += MAX(25, max_spellpoints(u->region, u)/2); - change_spellpoints(u, sp); - } + for (i = 0; i != amount; ++i) { + sp += MAX(25, max_spellpoints(u->region, u) / 2); + change_spellpoints(u, sp); + } ADDMSG(&u->faction->msgs, msg_message("manacrystal_use", "unit aura", u, sp)); - res_changeitem(u, itype->rtype, -amount); - return 0; + res_changeitem(u, itype->rtype, -amount); + return 0; } -void -register_xerewards(void) +void register_xerewards(void) { register_item_use(use_skillpotion, "use_skillpotion"); register_item_use(use_manacrystal, "use_manacrystal"); } - diff --git a/src/items/xerewards.h b/src/items/xerewards.h index c914c5ed4..8fa8b3859 100644 --- a/src/items/xerewards.h +++ b/src/items/xerewards.h @@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern void register_xerewards(void); + extern void register_xerewards(void); #ifdef __cplusplus } diff --git a/src/kernel/alchemy.c b/src/kernel/alchemy.c index 05f06471a..79a197856 100644 --- a/src/kernel/alchemy.c +++ b/src/kernel/alchemy.c @@ -47,18 +47,18 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* ------------------------------------------------------------- */ -void -herbsearch(region * r, unit * u, int max) +void herbsearch(region * r, unit * u, int max) { int herbsfound; - const item_type * whichherb; + + const item_type *whichherb; if (eff_skill(u, SK_HERBALISM, r) == 0) { cmistake(u, u->thisorder, 59, MSG_PRODUCE); return; } - if(is_guarded(r, u, GUARD_PRODUCE)) { + if (is_guarded(r, u, GUARD_PRODUCE)) { cmistake(u, u->thisorder, 70, MSG_EVENT); return; } @@ -69,118 +69,138 @@ herbsearch(region * r, unit * u, int max) return; } - if (max) max = MIN(max, rherbs(r)); - else max = rherbs(r); + if (max) + max = MIN(max, rherbs(r)); + else + max = rherbs(r); herbsfound = ntimespprob(eff_skill(u, SK_HERBALISM, r) * u->number, - (double)rherbs(r)/100.0F, -0.01F); + (double)rherbs(r) / 100.0F, -0.01F); herbsfound = MIN(herbsfound, max); - rsetherbs(r, rherbs(r)-herbsfound); + rsetherbs(r, rherbs(r) - herbsfound); if (herbsfound) { produceexp(u, SK_HERBALISM, u->number); i_change(&u->items, whichherb, herbsfound); - ADDMSG(&u->faction->msgs, msg_message("herbfound", - "unit region amount herb", u, r, herbsfound, whichherb->rtype)); + ADDMSG(&u->faction->msgs, msg_message("herbfound", + "unit region amount herb", u, r, herbsfound, whichherb->rtype)); } else { ADDMSG(&u->faction->msgs, msg_message("researchherb_none", - "unit region", u, u->region)); + "unit region", u, u->region)); } } -static int -begin_potion(unit * u, const potion_type * ptype, struct order *ord) +static int begin_potion(unit * u, const potion_type * ptype, struct order *ord) { static int rule_multipotion = -1; - assert(ptype!=NULL); - if (rule_multipotion<0) { + assert(ptype != NULL); + + if (rule_multipotion < 0) { /* should we allow multiple different potions to be used the same turn? */ - rule_multipotion = get_param_int(global.parameters, "rules.magic.multipotion", 0); + rule_multipotion = + get_param_int(global.parameters, "rules.magic.multipotion", 0); } if (!rule_multipotion) { - const potion_type * use = ugetpotionuse(u); - if (use != NULL && use!=ptype) { + const potion_type *use = ugetpotionuse(u); + + if (use != NULL && use != ptype) { ADDMSG(&u->faction->msgs, - msg_message("errusingpotion", "unit using command", - u, use->itype->rtype, ord)); + msg_message("errusingpotion", "unit using command", + u, use->itype->rtype, ord)); return ECUSTOM; } } return 0; } -static void -end_potion(unit * u, const potion_type * ptype, int amount) +static void end_potion(unit * u, const potion_type * ptype, int amount) { - use_pooled(u, ptype->itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); + use_pooled(u, ptype->itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, + amount); usetpotionuse(u, ptype); - + ADDMSG(&u->faction->msgs, msg_message("usepotion", - "unit potion", u, ptype->itype->rtype)); + "unit potion", u, ptype->itype->rtype)); } -void -do_potion(unit * u, const potion_type * ptype, int amount) +void do_potion(unit * u, const potion_type * ptype, int amount) { - if (ptype==oldpotiontype[P_LIFE]) { - region * r = u->region; + if (ptype == oldpotiontype[P_LIFE]) { + region *r = u->region; + int holz = 0; + static int tree_type = -1; + static int tree_count = -1; - if (tree_type<0) { + + if (tree_type < 0) { tree_type = get_param_int(global.parameters, "rules.magic.wol_type", 1); - tree_count = get_param_int(global.parameters, "rules.magic.wol_effect", 10); + + tree_count = + get_param_int(global.parameters, "rules.magic.wol_effect", 10); } /* mallorn is required to make mallorn forests, wood for regular ones */ if (fval(r, RF_MALLORN)) { - holz = use_pooled(u, rt_find("mallorn"), - GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, tree_count*amount); + holz = use_pooled(u, rt_find("mallorn"), + GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, tree_count * amount); } else { - holz = use_pooled(u, rt_find("log"), - GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, tree_count*amount); + holz = use_pooled(u, rt_find("log"), + GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, tree_count * amount); } - if (r->land==0) holz = 0; - if (holzland == 0) + holz = 0; + if (holz < tree_count * amount) { + int x = holz / tree_count; + + if (holz % tree_count) + ++x; + if (x < amount) + amount = x; } rsettrees(r, tree_type, rtrees(r, tree_type) + holz); - ADDMSG(&u->faction->msgs, msg_message("growtree_effect", - "mage amount", u, holz)); - } else if (ptype==oldpotiontype[P_HEILWASSER]) { + ADDMSG(&u->faction->msgs, msg_message("growtree_effect", + "mage amount", u, holz)); + } else if (ptype == oldpotiontype[P_HEILWASSER]) { u->hp = MIN(unit_max_hp(u) * u->number, u->hp + 400 * amount); - } else if (ptype==oldpotiontype[P_PEOPLE]) { - region * r = u->region; - attrib * a = (attrib*)a_find(r->attribs, &at_peasantluck); - if (!a) a = a_add(&r->attribs, a_new(&at_peasantluck)); - a->data.i+=amount; - } else if (ptype==oldpotiontype[P_HORSE]) { - region * r = u->region; - attrib * a = (attrib*)a_find(r->attribs, &at_horseluck); - if (!a) a = a_add(&r->attribs, a_new(&at_horseluck)); - a->data.i+=amount; - } else if (ptype==oldpotiontype[P_WAHRHEIT]) { + } else if (ptype == oldpotiontype[P_PEOPLE]) { + region *r = u->region; + + attrib *a = (attrib *) a_find(r->attribs, &at_peasantluck); + + if (!a) + a = a_add(&r->attribs, a_new(&at_peasantluck)); + a->data.i += amount; + } else if (ptype == oldpotiontype[P_HORSE]) { + region *r = u->region; + + attrib *a = (attrib *) a_find(r->attribs, &at_horseluck); + + if (!a) + a = a_add(&r->attribs, a_new(&at_horseluck)); + a->data.i += amount; + } else if (ptype == oldpotiontype[P_WAHRHEIT]) { fset(u, UFL_DISBELIEVES); - amount=1; - } else if (ptype==oldpotiontype[P_MACHT]) { + amount = 1; + } else if (ptype == oldpotiontype[P_MACHT]) { /* Verfünffacht die HP von max. 10 Personen in der Einheit */ - u->hp += MIN(u->number, 10*amount) * unit_max_hp(u) * 4; + u->hp += MIN(u->number, 10 * amount) * unit_max_hp(u) * 4; } else { - change_effect(u, ptype, 10*amount); + change_effect(u, ptype, 10 * amount); } } -int -use_potion(unit * u, const item_type * itype, int amount, struct order *ord) +int use_potion(unit * u, const item_type * itype, int amount, struct order *ord) { - const potion_type * ptype = resource2potion(itype->rtype); + const potion_type *ptype = resource2potion(itype->rtype); - if (oldpotiontype[P_HEAL] && ptype==oldpotiontype[P_HEAL]) { + if (oldpotiontype[P_HEAL] && ptype == oldpotiontype[P_HEAL]) { return EUNUSABLE; } else { int result = begin_potion(u, ptype, ord); - if (result) return result; + + if (result) + return result; do_potion(u, ptype, amount); end_potion(u, ptype, amount); } @@ -188,22 +208,26 @@ use_potion(unit * u, const item_type * itype, int amount, struct order *ord) } typedef struct potiondelay { - unit * u; - const potion_type * ptype; + unit *u; + const potion_type *ptype; int amount; } potiondelay; -static void init_potiondelay(attrib * a) { +static void init_potiondelay(attrib * a) +{ a->data.v = malloc(sizeof(potiondelay)); } -static void free_potiondelay(attrib * a) { +static void free_potiondelay(attrib * a) +{ free(a->data.v); } -static int age_potiondelay(attrib * a) { - potiondelay * pd = (potiondelay *)a->data.v; - do_potion(pd->u, pd->ptype, pd->amount); +static int age_potiondelay(attrib * a) +{ + potiondelay *pd = (potiondelay *) a->data.v; + + do_potion(pd->u, pd->ptype, pd->amount); return AT_AGE_REMOVE; } @@ -218,11 +242,12 @@ attrib_type at_potiondelay = { age_potiondelay, 0, 0 }; -static attrib * -make_potiondelay(unit * u, const potion_type* ptype, int amount) +static attrib *make_potiondelay(unit * u, const potion_type * ptype, int amount) { - attrib * a = a_new(&at_potiondelay); - potiondelay * pd = (potiondelay *)a->data.v; + attrib *a = a_new(&at_potiondelay); + + potiondelay *pd = (potiondelay *) a->data.v; + pd->u = u; pd->ptype = ptype; pd->amount = amount; @@ -230,11 +255,15 @@ make_potiondelay(unit * u, const potion_type* ptype, int amount) } int -use_potion_delayed(unit * u, const item_type * itype, int amount, struct order *ord) +use_potion_delayed(unit * u, const item_type * itype, int amount, + struct order *ord) { - const potion_type * ptype = resource2potion(itype->rtype); + const potion_type *ptype = resource2potion(itype->rtype); + int result = begin_potion(u, ptype, ord); - if (result) return result; + + if (result) + return result; a_add(&u->attribs, make_potiondelay(u, ptype, amount)); @@ -246,39 +275,41 @@ use_potion_delayed(unit * u, const item_type * itype, int amount, struct order * /* at_effect */ /*****************/ -static void -a_initeffect(attrib *a) +static void a_initeffect(attrib * a) { a->data.v = calloc(sizeof(effect_data), 1); } -static void -a_finalizeeffect(attrib * a) +static void a_finalizeeffect(attrib * a) { free(a->data.v); } static void -a_writeeffect(const attrib * a, const void * owner, struct storage * store) +a_writeeffect(const attrib * a, const void *owner, struct storage *store) { - effect_data * edata = (effect_data*)a->data.v; - store->w_tok(store, resourcename(edata->type->itype->rtype, 0)); + effect_data *edata = (effect_data *) a->data.v; + + store->w_tok(store, resourcename(edata->type->itype->rtype, 0)); store->w_int(store, edata->value); } -static int -a_readeffect(attrib *a, void * owner, struct storage * store) +static int a_readeffect(attrib * a, void *owner, struct storage *store) { int power; - const item_type * itype; - effect_data * edata = (effect_data*)a->data.v; + + const item_type *itype; + + effect_data *edata = (effect_data *) a->data.v; + char zText[32]; store->r_tok_buf(store, zText, sizeof(zText)); itype = it_find(zText); power = store->r_int(store); - if (itype==NULL || itype->rtype==NULL || itype->rtype->ptype==NULL || power<=0) { + if (itype == NULL || itype->rtype == NULL || itype->rtype->ptype == NULL + || power <= 0) { return AT_READ_FAIL; } edata->type = itype->rtype->ptype; @@ -295,28 +326,31 @@ attrib_type at_effect = { a_readeffect, }; -int -get_effect(const unit * u, const potion_type * effect) +int get_effect(const unit * u, const potion_type * effect) { - const attrib * a; - for (a=a_find(u->attribs, &at_effect); a!=NULL && a->type==&at_effect; a=a->next) { - const effect_data * data = (const effect_data *)a->data.v; - if (data->type==effect) return data->value; + const attrib *a; + + for (a = a_find(u->attribs, &at_effect); a != NULL && a->type == &at_effect; + a = a->next) { + const effect_data *data = (const effect_data *)a->data.v; + + if (data->type == effect) + return data->value; } return 0; } -int -change_effect (unit * u, const potion_type * effect, int delta) +int change_effect(unit * u, const potion_type * effect, int delta) { - if (delta!=0) { - attrib * a = a_find(u->attribs, &at_effect); - effect_data * data = NULL; + if (delta != 0) { + attrib *a = a_find(u->attribs, &at_effect); - while (a && a->type==&at_effect) { - data = (effect_data *)a->data.v; - if (data->type==effect) { - if (data->value+delta==0) { + effect_data *data = NULL; + + while (a && a->type == &at_effect) { + data = (effect_data *) a->data.v; + if (data->type == effect) { + if (data->value + delta == 0) { a_remove(&u->attribs, a); return 0; } else { @@ -326,9 +360,9 @@ change_effect (unit * u, const potion_type * effect, int delta) } a = a->next; } - + a = a_add(&u->attribs, a_new(&at_effect)); - data = (effect_data*)a->data.v; + data = (effect_data *) a->data.v; data->type = effect; data->value = delta; return data->value; diff --git a/src/kernel/alchemy.h b/src/kernel/alchemy.h index 128286cd1..2654c1a21 100644 --- a/src/kernel/alchemy.h +++ b/src/kernel/alchemy.h @@ -22,49 +22,52 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -enum { - /* Stufe 1 */ - P_FAST, - P_STRONG, - P_LIFE, - /* Stufe 2 */ - P_DOMORE, - P_HEILWASSER, - P_BAUERNBLUT, - /* Stufe 3 */ - P_WISE, /* 6 */ - P_FOOL, + enum { + /* Stufe 1 */ + P_FAST, + P_STRONG, + P_LIFE, + /* Stufe 2 */ + P_DOMORE, + P_HEILWASSER, + P_BAUERNBLUT, + /* Stufe 3 */ + P_WISE, /* 6 */ + P_FOOL, #ifdef INSECT_POTION - P_WARMTH, + P_WARMTH, #else - P_STEEL, + P_STEEL, #endif - P_HORSE, - P_BERSERK, /* 10 */ - /* Stufe 4 */ - P_PEOPLE, - P_WAHRHEIT, - P_MACHT, - P_HEAL, - MAX_POTIONS -}; + P_HORSE, + P_BERSERK, /* 10 */ + /* Stufe 4 */ + P_PEOPLE, + P_WAHRHEIT, + P_MACHT, + P_HEAL, + MAX_POTIONS + }; -extern void herbsearch(struct region * r, struct unit * u, int max); -extern int use_potion(struct unit * u, const struct item_type * itype, int amount, struct order *); -extern int use_potion_delayed(struct unit * u, const struct item_type * itype, int amount, struct order *); -extern void init_potions(void); + extern void herbsearch(struct region *r, struct unit *u, int max); + extern int use_potion(struct unit *u, const struct item_type *itype, + int amount, struct order *); + extern int use_potion_delayed(struct unit *u, const struct item_type *itype, + int amount, struct order *); + extern void init_potions(void); -extern int get_effect(const struct unit * u, const struct potion_type * effect); -extern int change_effect(struct unit * u, const struct potion_type * effect, int value); -extern struct attrib_type at_effect; + extern int get_effect(const struct unit *u, const struct potion_type *effect); + extern int change_effect(struct unit *u, const struct potion_type *effect, + int value); + extern struct attrib_type at_effect; /* rausnehmen, sobald man attribute splitten kann: */ -typedef struct effect_data { - const struct potion_type * type; - int value; -} effect_data; + typedef struct effect_data { + const struct potion_type *type; + int value; + } effect_data; #ifdef __cplusplus } #endif -#endif /* ALCHEMY_H */ +#endif /* ALCHEMY_H */ diff --git a/src/kernel/alliance.c b/src/kernel/alliance.c index fc8cbb452..64d89eb15 100644 --- a/src/kernel/alliance.c +++ b/src/kernel/alliance.c @@ -44,32 +44,32 @@ without prior permission by the authors of Eressea. #pragma endregion -alliance * alliances = NULL; +alliance *alliances = NULL; -void -free_alliance(alliance * al) +void free_alliance(alliance * al) { free(al->name); - if (al->members) ql_free(al->members); + if (al->members) + ql_free(al->members); free(al); } -alliance * -makealliance(int id, const char * name) +alliance *makealliance(int id, const char *name) { - alliance * al;; - + alliance *al;; + for (;;) { - if (id>0) { - for (al=alliances;al;al=al->next) { - if (al->id==id) { + if (id > 0) { + for (al = alliances; al; al = al->next) { + if (al->id == id) { id = 0; break; } } - if (id>0) break; + if (id > 0) + break; } - id = id?id:(1 + (rng_int() % MAX_UNIT_NR)); + id = id ? id : (1 + (rng_int() % MAX_UNIT_NR)); } al = calloc(1, sizeof(alliance)); al->id = id; @@ -79,102 +79,98 @@ makealliance(int id, const char * name) al->flags |= ALF_NON_ALLIED; } al->next = alliances; - return alliances=al; + return alliances = al; } -alliance * -findalliance(int id) +alliance *findalliance(int id) { - alliance * al; - for (al=alliances;al;al=al->next) { - if (al->id==id) return al; + alliance *al; + + for (al = alliances; al; al = al->next) { + if (al->id == id) + return al; } return NULL; } typedef struct alliance_transaction { - struct alliance_transaction * next; - unit * u; - order * ord; + struct alliance_transaction *next; + unit *u; + order *ord; // alliance * al; // variant userdata; } alliance_transaction; -static struct alliance_transaction * transactions[ALLIANCE_MAX]; +static struct alliance_transaction *transactions[ALLIANCE_MAX]; -faction * -alliance_get_leader(alliance * al) +faction *alliance_get_leader(alliance * al) { if (!al->_leader) { if (al->members) { - al->_leader = (faction *)ql_get(al->members, 0); + al->_leader = (faction *) ql_get(al->members, 0); } } return al->_leader; } -static void -create_transaction(int type, unit * u, order * ord) +static void create_transaction(int type, unit * u, order * ord) { - alliance_transaction * tr = (alliance_transaction *)calloc(1, sizeof(alliance_transaction)); + alliance_transaction *tr = + (alliance_transaction *) calloc(1, sizeof(alliance_transaction)); tr->ord = ord; tr->u = u; tr->next = transactions[type]; transactions[type] = tr; } -static void -cmd_kick(const tnode * tnext, void * data, struct order * ord) +static void cmd_kick(const tnode * tnext, void *data, struct order *ord) { - create_transaction(ALLIANCE_KICK, (unit*)data, ord); + create_transaction(ALLIANCE_KICK, (unit *) data, ord); } -static void -cmd_leave(const tnode * tnext, void * data, struct order * ord) +static void cmd_leave(const tnode * tnext, void *data, struct order *ord) { - create_transaction(ALLIANCE_LEAVE, (unit*)data, ord); + create_transaction(ALLIANCE_LEAVE, (unit *) data, ord); } -static void -cmd_transfer(const tnode * tnext, void * data, struct order * ord) +static void cmd_transfer(const tnode * tnext, void *data, struct order *ord) { - create_transaction(ALLIANCE_TRANSFER, (unit*)data, ord); + create_transaction(ALLIANCE_TRANSFER, (unit *) data, ord); } -static void -cmd_new(const tnode * tnext, void * data, struct order * ord) +static void cmd_new(const tnode * tnext, void *data, struct order *ord) { - create_transaction(ALLIANCE_NEW, (unit*)data, ord); + create_transaction(ALLIANCE_NEW, (unit *) data, ord); } -static void -cmd_invite(const tnode * tnext, void * data, struct order * ord) +static void cmd_invite(const tnode * tnext, void *data, struct order *ord) { - create_transaction(ALLIANCE_INVITE, (unit*)data, ord); + create_transaction(ALLIANCE_INVITE, (unit *) data, ord); } -static void -cmd_join(const tnode * tnext, void * data, struct order * ord) +static void cmd_join(const tnode * tnext, void *data, struct order *ord) { - create_transaction(ALLIANCE_JOIN, (unit*)data, ord); + create_transaction(ALLIANCE_JOIN, (unit *) data, ord); } -static void -perform_kick(void) +static void perform_kick(void) { - alliance_transaction ** tap = transactions+ALLIANCE_KICK; + alliance_transaction **tap = transactions + ALLIANCE_KICK; + while (*tap) { - alliance_transaction * ta = *tap; - alliance * al = f_get_alliance(ta->u->faction); + alliance_transaction *ta = *tap; + + alliance *al = f_get_alliance(ta->u->faction); + + if (al && alliance_get_leader(al) == ta->u->faction) { + faction *f; - if (al && alliance_get_leader(al)==ta->u->faction) { - faction * f; init_tokens(ta->ord); skip_token(); skip_token(); f = getfaction(); - if (f && f_get_alliance(f)==al) { + if (f && f_get_alliance(f) == al) { setalliance(f, NULL); } } @@ -183,15 +179,18 @@ perform_kick(void) } } -static void -perform_new(void) +static void perform_new(void) { - alliance_transaction ** tap = transactions+ALLIANCE_NEW; + alliance_transaction **tap = transactions + ALLIANCE_NEW; + while (*tap) { - alliance_transaction * ta = *tap; - alliance * al; + alliance_transaction *ta = *tap; + + alliance *al; + int id; - faction * f = ta->u->faction; + + faction *f = ta->u->faction; init_tokens(ta->ord); skip_token(); @@ -206,13 +205,14 @@ perform_new(void) } } -static void -perform_leave(void) +static void perform_leave(void) { - alliance_transaction ** tap = transactions+ALLIANCE_LEAVE; + alliance_transaction **tap = transactions + ALLIANCE_LEAVE; + while (*tap) { - alliance_transaction * ta = *tap; - faction * f = ta->u->faction; + alliance_transaction *ta = *tap; + + faction *f = ta->u->faction; setalliance(f, NULL); @@ -221,21 +221,23 @@ perform_leave(void) } } -static void -perform_transfer(void) +static void perform_transfer(void) { - alliance_transaction ** tap = transactions+ALLIANCE_TRANSFER; - while (*tap) { - alliance_transaction * ta = *tap; - alliance * al = f_get_alliance(ta->u->faction); + alliance_transaction **tap = transactions + ALLIANCE_TRANSFER; + + while (*tap) { + alliance_transaction *ta = *tap; + + alliance *al = f_get_alliance(ta->u->faction); + + if (al && alliance_get_leader(al) == ta->u->faction) { + faction *f; - if (al && alliance_get_leader(al)==ta->u->faction) { - faction * f; init_tokens(ta->ord); skip_token(); skip_token(); f = getfaction(); - if (f && f_get_alliance(f)==al) { + if (f && f_get_alliance(f) == al) { al->_leader = f; } } @@ -244,13 +246,15 @@ perform_transfer(void) } } -static void -perform_join(void) +static void perform_join(void) { - alliance_transaction ** tap = transactions+ALLIANCE_JOIN; + alliance_transaction **tap = transactions + ALLIANCE_JOIN; + while (*tap) { - alliance_transaction * ta = *tap; - faction * fj = ta->u->faction; + alliance_transaction *ta = *tap; + + faction *fj = ta->u->faction; + int aid; init_tokens(ta->ord); @@ -258,19 +262,24 @@ perform_join(void) skip_token(); aid = getid(); if (aid) { - alliance * al = findalliance(aid); - if (al && f_get_alliance(fj)!=al) { - alliance_transaction ** tip = transactions+ALLIANCE_INVITE; - alliance_transaction * ti = *tip; + alliance *al = findalliance(aid); + + if (al && f_get_alliance(fj) != al) { + alliance_transaction **tip = transactions + ALLIANCE_INVITE; + + alliance_transaction *ti = *tip; + while (ti) { - faction * fi = ti->u->faction; - if (fi && f_get_alliance(fi)==al) { + faction *fi = ti->u->faction; + + if (fi && f_get_alliance(fi) == al) { int fid; + init_tokens(ti->ord); skip_token(); skip_token(); fid = getid(); - if (fid==fj->no) { + if (fid == fj->no) { break; } } @@ -291,21 +300,27 @@ perform_join(void) } } -static void -execute(const struct syntaxtree * syntax, keyword_t kwd) +static void execute(const struct syntaxtree *syntax, keyword_t kwd) { int run = 0; - region ** rp = ®ions; + region **rp = ®ions; + while (*rp) { - region * r = *rp; + region *r = *rp; + unit **up = &r->units; + while (*up) { - unit * u = *up; + unit *u = *up; + if (u->number) { - const struct locale * lang = u->faction->locale; - tnode * root = stree_find(syntax, lang); - order * ord; + const struct locale *lang = u->faction->locale; + + tnode *root = stree_find(syntax, lang); + + order *ord; + for (ord = u->orders; ord; ord = ord->next) { if (get_keyword(ord) == kwd) { do_command(root, u, ord); @@ -313,9 +328,11 @@ execute(const struct syntaxtree * syntax, keyword_t kwd) } } } - if (u==*up) up = &u->next; + if (u == *up) + up = &u->next; } - if (*rp==r) rp = &r->next; + if (*rp == r) + rp = &r->next; } if (run) { @@ -327,15 +344,17 @@ execute(const struct syntaxtree * syntax, keyword_t kwd) } } -void -alliance_cmd(void) +void alliance_cmd(void) { - static syntaxtree * stree = NULL; - if (stree==NULL) { - syntaxtree * slang = stree = stree_create(); + static syntaxtree *stree = NULL; + + if (stree == NULL) { + syntaxtree *slang = stree = stree_create(); + while (slang) { // struct tnode * root = calloc(sizeof(tnode), 1); - struct tnode * leaf = calloc(sizeof(tnode), 1); + struct tnode *leaf = calloc(sizeof(tnode), 1); + // add_command(root, leaf, LOC(slang->lang, "alliance"), NULL); add_command(leaf, NULL, LOC(slang->lang, "new"), &cmd_new); add_command(leaf, NULL, LOC(slang->lang, "invite"), &cmd_invite); @@ -351,15 +370,18 @@ alliance_cmd(void) /* some may have been kicked, must remove f->alliance==NULL */ } -void -alliancejoin(void) +void alliancejoin(void) { - static syntaxtree * stree = NULL; - if (stree==NULL) { - syntaxtree * slang = stree = stree_create(); + static syntaxtree *stree = NULL; + + if (stree == NULL) { + syntaxtree *slang = stree = stree_create(); + while (slang) { - struct tnode * root = calloc(sizeof(tnode), 1); - struct tnode * leaf = calloc(sizeof(tnode), 1); + struct tnode *root = calloc(sizeof(tnode), 1); + + struct tnode *leaf = calloc(sizeof(tnode), 1); + add_command(root, leaf, LOC(slang->lang, "alliance"), NULL); add_command(leaf, NULL, LOC(slang->lang, "join"), &cmd_join); slang = slang->next; @@ -368,25 +390,27 @@ alliancejoin(void) execute(stree, K_ALLIANCE); } -void -setalliance(faction * f, alliance * al) +void setalliance(faction * f, alliance * al) { - if (f->alliance==al) return; - if (f->alliance!=NULL) { + if (f->alliance == al) + return; + if (f->alliance != NULL) { int qi; - quicklist ** flistp = &f->alliance->members; - for (qi=0;*flistp;ql_advance(flistp, &qi, 1)) { - faction * data = (faction *)ql_get(*flistp, qi); - if (data==f) { + quicklist **flistp = &f->alliance->members; + + for (qi = 0; *flistp; ql_advance(flistp, &qi, 1)) { + faction *data = (faction *) ql_get(*flistp, qi); + + if (data == f) { ql_delete(flistp, qi); break; } } - if (f->alliance->_leader==f) { + if (f->alliance->_leader == f) { if (f->alliance->members) { - f->alliance->_leader = (faction *)ql_get(f->alliance->members, 0); + f->alliance->_leader = (faction *) ql_get(f->alliance->members, 0); } else { f->alliance->_leader = NULL; } @@ -394,61 +418,69 @@ setalliance(faction * f, alliance * al) } f->alliance = al; f->alliance_joindate = turn; - if (al!=NULL) { + if (al != NULL) { ql_push(&al->members, f); - if (al->_leader==NULL) { + if (al->_leader == NULL) { al->_leader = f; } } } -const char * -alliancename(const alliance * al) +const char *alliancename(const alliance * al) { typedef char name[OBJECTIDSIZE + 1]; + static name idbuf[8]; + static int nextbuf = 0; char *ibuf = idbuf[(++nextbuf) % 8]; if (al && al->name) { snprintf(ibuf, sizeof(name), "%s (%s)", al->name, itoa36(al->id)); - ibuf[sizeof(name)-1] = 0; + ibuf[sizeof(name) - 1] = 0; } else { return NULL; } return ibuf; } -void -alliancevictory(void) +void alliancevictory(void) { - const struct building_type * btype = bt_find("stronghold"); - region * r = regions; - alliance * al = alliances; - if (btype==NULL) return; - while (r!=NULL) { - building * b = r->buildings; - while (b!=NULL) { - if (b->type==btype) { - unit * u = building_owner(b); + const struct building_type *btype = bt_find("stronghold"); + + region *r = regions; + + alliance *al = alliances; + + if (btype == NULL) + return; + while (r != NULL) { + building *b = r->buildings; + + while (b != NULL) { + if (b->type == btype) { + unit *u = building_owner(b); + if (u) { fset(u->faction->alliance, FFL_MARK); } } b = b->next; } - r=r->next; + r = r->next; } - while (al!=NULL) { + while (al != NULL) { if (!fval(al, FFL_MARK)) { int qi; - quicklist * flist = al->members; - for (qi=0;flist;ql_advance(&flist, &qi, 1)) { - faction * f = (faction *)ql_get(flist, qi); - if (f->alliance==al) { - ADDMSG(&f->msgs, msg_message("alliance::lost", - "alliance", al)); + + quicklist *flist = al->members; + + for (qi = 0; flist; ql_advance(&flist, &qi, 1)) { + faction *f = (faction *) ql_get(flist, qi); + + if (f->alliance == al) { + ADDMSG(&f->msgs, msg_message("alliance::lost", "alliance", al)); destroyfaction(f); } } @@ -459,69 +491,79 @@ alliancevictory(void) } } -int -victorycondition(const alliance * al, const char * name) +int victorycondition(const alliance * al, const char *name) { - const char * gems[] = { "opal", "diamond", "zaphire", "topaz", "beryl", "agate", "garnet", "emerald", NULL }; - if (strcmp(name, "gems")==0) { - const char ** igem; + const char *gems[] = + { "opal", "diamond", "zaphire", "topaz", "beryl", "agate", "garnet", + "emerald", NULL }; + if (strcmp(name, "gems") == 0) { + const char **igem; + + for (igem = gems; *igem; ++igem) { + const struct item_type *itype = it_find(*igem); + + quicklist *flist = al->members; - for (igem=gems;*igem;++igem) { - const struct item_type * itype = it_find(*igem); - quicklist * flist = al->members; int qi; + boolean found = false; - assert(itype!=NULL); - for (qi=0;flist && !found;ql_advance(&flist, &qi, 1)) { - faction * f = (faction *)ql_get(flist, 0); - unit * u; + assert(itype != NULL); + for (qi = 0; flist && !found; ql_advance(&flist, &qi, 1)) { + faction *f = (faction *) ql_get(flist, 0); - for (u=f->units;u;u=u->nextF) { - if (i_get(u->items, itype)>0) { + unit *u; + + for (u = f->units; u; u = u->nextF) { + if (i_get(u->items, itype) > 0) { found = true; break; } } } - if (!found) return 0; + if (!found) + return 0; } return 1; - } else if (strcmp(name, "phoenix")==0) { - quicklist * flist = al->members; + } else if (strcmp(name, "phoenix") == 0) { + quicklist *flist = al->members; + int qi; - for (qi=0;flist;ql_advance(&flist, &qi, 1)) { - faction * f = (faction *)ql_get(flist, qi); + for (qi = 0; flist; ql_advance(&flist, &qi, 1)) { + faction *f = (faction *) ql_get(flist, qi); + if (find_key(f->attribs, atoi36("phnx"))) { return 1; } } return 0; - } else if (strcmp(name, "pyramid")==0) { + } else if (strcmp(name, "pyramid") == 0) { /* Logik: - * - if (pyr > last_passed_size && pyr > all_others) { - * pyr->passed->counter++; - * for(all_other_pyrs) { - * pyr->passed->counter=0; - * } - * - * if(pyr->passed->counter >= 3) { - * set(pyr, passed); - * pyr->owner->set_attrib(pyra); - * } - * last_passed_size = pyr->size; - * } - */ + * - if (pyr > last_passed_size && pyr > all_others) { + * pyr->passed->counter++; + * for(all_other_pyrs) { + * pyr->passed->counter=0; + * } + * + * if(pyr->passed->counter >= 3) { + * set(pyr, passed); + * pyr->owner->set_attrib(pyra); + * } + * last_passed_size = pyr->size; + * } + */ + + quicklist *flist = al->members; - quicklist * flist = al->members; int qi; - for (qi=0;flist;ql_advance(&flist, &qi, 1)) { - faction * f = (faction *)ql_get(flist, qi); + for (qi = 0; flist; ql_advance(&flist, &qi, 1)) { + faction *f = (faction *) ql_get(flist, qi); + if (find_key(f->attribs, atoi36("pyra"))) { return 1; } @@ -531,9 +573,11 @@ victorycondition(const alliance * al, const char * name) return -1; } -void alliance_setname(alliance * self, const char * name) +void alliance_setname(alliance * self, const char *name) { free(self->name); - if (name) self->name = strdup(name); - else self->name = NULL; + if (name) + self->name = strdup(name); + else + self->name = NULL; } diff --git a/src/kernel/alliance.h b/src/kernel/alliance.h index 026bd0c11..a97227ab0 100644 --- a/src/kernel/alliance.h +++ b/src/kernel/alliance.h @@ -22,43 +22,43 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -struct plane; -struct attrib; -struct unit; -struct faction; -struct region; + struct plane; + struct attrib; + struct unit; + struct faction; + struct region; -enum { - ALLIANCE_KICK, - ALLIANCE_LEAVE, - ALLIANCE_TRANSFER, - ALLIANCE_NEW, - ALLIANCE_INVITE, - ALLIANCE_JOIN, - ALLIANCE_MAX -}; + enum { + ALLIANCE_KICK, + ALLIANCE_LEAVE, + ALLIANCE_TRANSFER, + ALLIANCE_NEW, + ALLIANCE_INVITE, + ALLIANCE_JOIN, + ALLIANCE_MAX + }; -#define ALF_NON_ALLIED (1<<0) /* this alliance is just a default for a non-allied faction */ +#define ALF_NON_ALLIED (1<<0) /* this alliance is just a default for a non-allied faction */ -typedef struct alliance { - struct alliance * next; - struct faction * _leader; - struct quicklist * members; - unsigned int flags; - int id; - char * name; -} alliance; + typedef struct alliance { + struct alliance *next; + struct faction *_leader; + struct quicklist *members; + unsigned int flags; + int id; + char *name; + } alliance; -extern alliance * alliances; -extern alliance * findalliance(int id); -extern alliance * makealliance(int id, const char * name); -extern const char * alliancename(const struct alliance * al); -extern void setalliance(struct faction * f, alliance * al); -void free_alliance(struct alliance * al); -extern struct faction * alliance_get_leader(struct alliance * al); -extern void alliance_cmd(void); + extern alliance *alliances; + extern alliance *findalliance(int id); + extern alliance *makealliance(int id, const char *name); + extern const char *alliancename(const struct alliance *al); + extern void setalliance(struct faction *f, alliance * al); + void free_alliance(struct alliance *al); + extern struct faction *alliance_get_leader(struct alliance *al); + extern void alliance_cmd(void); -void alliance_setname(alliance * self, const char * name); + void alliance_setname(alliance * self, const char *name); /* execute commands */ #ifdef __cplusplus diff --git a/src/kernel/battle.c b/src/kernel/battle.c index fee9a4055..875679154 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -76,23 +76,23 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. static FILE *bdebug; -#define TACTICS_BONUS 1 /* when undefined, we have a tactics round. else this is the bonus tactics give */ -#define TACTICS_MODIFIER 1 /* modifier for generals in the fromt/rear */ +#define TACTICS_BONUS 1 /* when undefined, we have a tactics round. else this is the bonus tactics give */ +#define TACTICS_MODIFIER 1 /* modifier for generals in the fromt/rear */ -#define CATAPULT_INITIAL_RELOAD 4 /* erster schuss in runde 1 + rng_int() % INITIAL */ +#define CATAPULT_INITIAL_RELOAD 4 /* erster schuss in runde 1 + rng_int() % INITIAL */ #define CATAPULT_STRUCTURAL_DAMAGE -#define BASE_CHANCE 70 /* 70% Basis-Überlebenschance */ +#define BASE_CHANCE 70 /* 70% Basis-Überlebenschance */ #ifdef NEW_COMBATSKILLS_RULE -#define TDIFF_CHANGE 5 /* 5% höher pro Stufe */ -#define DAMAGE_QUOTIENT 2 /* damage += skilldiff/DAMAGE_QUOTIENT */ +#define TDIFF_CHANGE 5 /* 5% höher pro Stufe */ +#define DAMAGE_QUOTIENT 2 /* damage += skilldiff/DAMAGE_QUOTIENT */ #else #define TDIFF_CHANGE 10 -# define DAMAGE_QUOTIENT 1 /* damage += skilldiff/DAMAGE_QUOTIENT */ +# define DAMAGE_QUOTIENT 1 /* damage += skilldiff/DAMAGE_QUOTIENT */ #endif -#undef DEBUG_FAST /* should be disabled when b->fast and b->rowcache works */ -#define DEBUG_SELECT /* should be disabled if select_enemy works */ +#undef DEBUG_FAST /* should be disabled when b->fast and b->rowcache works */ +#define DEBUG_SELECT /* should be disabled if select_enemy works */ typedef enum combatmagic { DO_PRECOMBATSPELL, @@ -109,25 +109,30 @@ static int obs_count = 0; # define ROW_FACTOR 10 #endif static const double EFFECT_PANIC_SPELL = 0.25; + static const double TROLL_REGENERATION = 0.10; /* Nach dem alten System: */ -static int missile_range[2] = {FIGHT_ROW, BEHIND_ROW}; -static int melee_range[2] = {FIGHT_ROW, FIGHT_ROW}; -static message * msg_separator; +static int missile_range[2] = { FIGHT_ROW, BEHIND_ROW }; +static int melee_range[2] = { FIGHT_ROW, FIGHT_ROW }; -const troop no_troop = {0, 0}; +static message *msg_separator; + +const troop no_troop = { 0, 0 }; static int max_turns = 0; + static int damage_rules = 0; + static int loot_rules = 0; + static int skill_formula = 0; #define FORMULA_ORIG 0 #define FORMULA_NEW 1 #define LOOT_MONSTERS (1<<0) -#define LOOT_SELF (1<<1) /* code is mutually exclusive with LOOT_OTHERS */ +#define LOOT_SELF (1<<1) /* code is mutually exclusive with LOOT_OTHERS */ #define LOOT_OTHERS (1<<2) #define LOOT_KEEPLOOT (1<<4) @@ -138,14 +143,18 @@ static int skill_formula = 0; #define DAMAGE_SKILL_BONUS (1<<4) /** initialize rules from configuration. */ -static void -static_rules(void) +static void static_rules(void) { - loot_rules = get_param_int(global.parameters, "rules.combat.loot", LOOT_MONSTERS|LOOT_OTHERS|LOOT_KEEPLOOT); + loot_rules = + get_param_int(global.parameters, "rules.combat.loot", + LOOT_MONSTERS | LOOT_OTHERS | LOOT_KEEPLOOT); /* new formula to calculate to-hit-chance */ - skill_formula = get_param_int(global.parameters, "rules.combat.skill_formula", FORMULA_ORIG); + skill_formula = + get_param_int(global.parameters, "rules.combat.skill_formula", + FORMULA_ORIG); /* maximum number of combat turns */ - max_turns = get_param_int(global.parameters, "rules.combat.turns", COMBAT_TURNS); + max_turns = + get_param_int(global.parameters, "rules.combat.turns", COMBAT_TURNS); /* damage calculation */ if (get_param_int(global.parameters, "rules.combat.critical", 1)) { damage_rules |= DAMAGE_CRITICAL; @@ -164,34 +173,34 @@ static_rules(void) } } -static int -army_index(side * s) +static int army_index(side * s) { return s->index; } #ifndef SIMPLE_ESCAPE -region * -fleeregion(const unit * u) +region *fleeregion(const unit * u) { region *r = u->region; + region *neighbours[MAXDIRECTIONS]; + int c = 0; + direction_t i; if (u->ship && !fval(r->terrain, SEA_REGION)) return NULL; - if (u->ship && - !(u->race->flags & RCF_SWIM) && - !(u->race->flags & RCF_FLY)) { + if (u->ship && !(u->race->flags & RCF_SWIM) && !(u->race->flags & RCF_FLY)) { return NULL; } for (i = 0; i != MAXDIRECTIONS; ++i) { - region * r2 = rconnect(r, i); + region *r2 = rconnect(r, i); + if (r2) { - if (can_survive(u,r2) && !move_blocked(u, r, r2)) + if (can_survive(u, r2) && !move_blocked(u, r, r2)) neighbours[c++] = r2; } } @@ -202,12 +211,12 @@ fleeregion(const unit * u) } #endif /* SIMPLE_ESCAPE */ -static char * -sidename(side * s) +static char *sidename(side * s) { #define SIDENAMEBUFLEN 256 - static int bufno; /* STATIC_XCALL: used across calls */ - static char sidename_buf[4][SIDENAMEBUFLEN]; /* STATIC_RESULT: used for return, not across calls */ + static int bufno; /* STATIC_XCALL: used across calls */ + + static char sidename_buf[4][SIDENAMEBUFLEN]; /* STATIC_RESULT: used for return, not across calls */ bufno = bufno % 4; if (s->stealthfaction) { @@ -220,11 +229,12 @@ sidename(side * s) return sidename_buf[bufno++]; } -static const char * -sideabkz(side *s, boolean truename) +static const char *sideabkz(side * s, boolean truename) { - static char sideabkz_buf[8]; /* STATIC_RESULT: used for return, not across calls */ - const faction * f = (s->stealthfaction && !truename)?s->stealthfaction:s->faction; + static char sideabkz_buf[8]; /* STATIC_RESULT: used for return, not across calls */ + + const faction *f = (s->stealthfaction + && !truename) ? s->stealthfaction : s->faction; #undef SIDE_ABKZ #ifdef SIDE_ABKZ @@ -235,13 +245,13 @@ sideabkz(side *s, boolean truename) return sideabkz_buf; } -static void -message_faction(battle * b, faction * f, struct message * m) +static void message_faction(battle * b, faction * f, struct message *m) { - region * r = b->region; + region *r = b->region; + + if (f->battles == NULL || f->battles->r != r) { + struct bmsg *bm = calloc(1, sizeof(struct bmsg)); - if (f->battles==NULL || f->battles->r!=r) { - struct bmsg * bm = calloc(1, sizeof(struct bmsg)); bm->next = f->battles; f->battles = bm; bm->r = r; @@ -249,24 +259,29 @@ message_faction(battle * b, faction * f, struct message * m) add_message(&f->battles->msgs, m); } -int -armedmen(const unit * u, boolean siege_weapons) +int armedmen(const unit * u, boolean siege_weapons) { - item * itm; + item *itm; + int n = 0; + if (!(urace(u)->flags & RCF_NOWEAPONS)) { - if (effskill(u, SK_WEAPONLESS)>=1) { + if (effskill(u, SK_WEAPONLESS) >= 1) { /* kann ohne waffen bewachen: fuer drachen */ n = u->number; } else { /* alle Waffen werden gezaehlt, und dann wird auf die Anzahl * Personen minimiert */ - for (itm=u->items;itm;itm=itm->next) { - const weapon_type * wtype = resource2weapon(itm->type->rtype); - if (wtype==NULL || (!siege_weapons && (wtype->flags & WTF_SIEGE))) continue; - if (effskill(u, wtype->skill) >= 1) n += itm->number; + for (itm = u->items; itm; itm = itm->next) { + const weapon_type *wtype = resource2weapon(itm->type->rtype); + + if (wtype == NULL || (!siege_weapons && (wtype->flags & WTF_SIEGE))) + continue; + if (effskill(u, wtype->skill) >= 1) + n += itm->number; /* if (effskill(u, wtype->skill) >= wtype->minskill) n += itm->number; */ - if (n>u->number) break; + if (n > u->number) + break; } n = MIN(n, u->number); } @@ -274,26 +289,31 @@ armedmen(const unit * u, boolean siege_weapons) return n; } -void -message_all(battle * b, message * m) +void message_all(battle * b, message * m) { - bfaction * bf; - plane * p = rplane(b->region); - watcher * w; + bfaction *bf; - for (bf = b->factions;bf;bf=bf->next) { + plane *p = rplane(b->region); + + watcher *w; + + for (bf = b->factions; bf; bf = bf->next) { message_faction(b, bf->faction, m); } - if (p) for (w=p->watchers;w;w=w->next) { - for (bf = b->factions;bf;bf=bf->next) if (bf->faction==w->faction) break; - if (bf==NULL) message_faction(b, w->faction, m); - } + if (p) + for (w = p->watchers; w; w = w->next) { + for (bf = b->factions; bf; bf = bf->next) + if (bf->faction == w->faction) + break; + if (bf == NULL) + message_faction(b, w->faction, m); + } } -static void -fbattlerecord(battle * b, faction * f, const char *s) +static void fbattlerecord(battle * b, faction * f, const char *s) { - message * m = msg_message("battle_msg", "string", s); + message *m = msg_message("battle_msg", "string", s); + message_faction(b, f, m); msg_release(m); } @@ -304,23 +324,28 @@ fbattlerecord(battle * b, faction * f, const char *s) #define enemy(as, ds) (as->relations[ds->index]&E_ENEMY) #define friendly(as, ds) (as->relations[ds->index]&E_FRIEND) -static boolean -set_enemy(side * as, side * ds, boolean attacking) +static boolean set_enemy(side * as, side * ds, boolean attacking) { int i; - for (i=0;i!=MAXSIDES;++i) { - if (ds->enemies[i]==NULL) ds->enemies[i]=as; - if (ds->enemies[i]==as) break; + + for (i = 0; i != MAXSIDES; ++i) { + if (ds->enemies[i] == NULL) + ds->enemies[i] = as; + if (ds->enemies[i] == as) + break; } - for (i=0;i!=MAXSIDES;++i) { - if (as->enemies[i]==NULL) as->enemies[i]=ds; - if (as->enemies[i]==ds) break; + for (i = 0; i != MAXSIDES; ++i) { + if (as->enemies[i] == NULL) + as->enemies[i] = ds; + if (as->enemies[i] == ds) + break; } - assert(i!=MAXSIDES); - if (attacking) as->relations[ds->index] |= E_ATTACKING; - if ((ds->relations[as->index] & E_ENEMY)==0) { + assert(i != MAXSIDES); + if (attacking) + as->relations[ds->index] |= E_ATTACKING; + if ((ds->relations[as->index] & E_ENEMY) == 0) { /* enemy-relation are always symmetrical */ - assert((as->relations[ds->index] & (E_ENEMY|E_FRIEND))==0); + assert((as->relations[ds->index] & (E_ENEMY | E_FRIEND)) == 0); ds->relations[as->index] |= E_ENEMY; as->relations[ds->index] |= E_ENEMY; return true; @@ -328,38 +353,34 @@ set_enemy(side * as, side * ds, boolean attacking) return false; } -static void -set_friendly(side * as, side * ds) +static void set_friendly(side * as, side * ds) { - assert((as->relations[ds->index] & E_ENEMY)==0); + assert((as->relations[ds->index] & E_ENEMY) == 0); ds->relations[as->index] |= E_FRIEND; as->relations[ds->index] |= E_FRIEND; } -static int -allysfm(const side * s, const faction * f, int mode) +static int allysfm(const side * s, const faction * f, int mode) { - if (s->faction==f) return mode; + if (s->faction == f) + return mode; if (s->group) { return alliedgroup(s->battle->plane, s->faction, f, s->group->allies, mode); } return alliedfaction(s->battle->plane, s->faction, f, mode); } -static int -allysf(const side * s, const faction * f) +static int allysf(const side * s, const faction * f) { return allysfm(s, f, HELP_FIGHT); } -static int -dead_fighters(const fighter * df) +static int dead_fighters(const fighter * df) { return df->unit->number - df->alive - df->run.number; } -fighter * -select_corpse(battle * b, fighter * af) +fighter *select_corpse(battle * b, fighter * af) /* Wählt eine Leiche aus, der af hilft. casualties ist die Anzahl der * Toten auf allen Seiten (im Array). Wenn af == NULL, wird die * Parteizugehörigkeit ignoriert, und irgendeine Leiche genommen. @@ -367,22 +388,27 @@ select_corpse(battle * b, fighter * af) * Untote werden nicht ausgewählt (casualties, not dead) */ { int si, di, maxcasualties = 0; + fighter *df; + side *s; - for (si=0;si!=b->nsides;++si) { - side * s = b->sides+si; - if (af==NULL || (!enemy_i(af->side, si) && allysf(af->side, s->faction))) { + for (si = 0; si != b->nsides; ++si) { + side *s = b->sides + si; + + if (af == NULL || (!enemy_i(af->side, si) && allysf(af->side, s->faction))) { maxcasualties += s->casualties; } } di = rng_int() % maxcasualties; - for (s=b->sides;s!=b->sides+b->nsides;++s) { - for (df=s->fighters;df;df=df->next) { + for (s = b->sides; s != b->sides + b->nsides; ++s) { + for (df = s->fighters; df; df = df->next) { /* Geflohene haben auch 0 hp, dürfen hier aber nicht ausgewählt - * werden! */ + * werden! */ int dead = dead_fighters(df); - if (!playerrace(df->unit->race)) continue; + + if (!playerrace(df->unit->race)) + continue; if (af && !helping(af->side, df->side)) continue; @@ -396,121 +422,135 @@ select_corpse(battle * b, fighter * af) return NULL; } -boolean -helping(const side * as, const side * ds) +boolean helping(const side * as, const side * ds) { - if (as->faction==ds->faction) return true; - return (boolean)(!enemy(as, ds) && allysf(as, ds->faction)); + if (as->faction == ds->faction) + return true; + return (boolean) (!enemy(as, ds) && allysf(as, ds->faction)); } -int -statusrow(int status) +int statusrow(int status) { switch (status) { - case ST_AGGRO: - case ST_FIGHT: - return FIGHT_ROW; - case ST_BEHIND: - case ST_CHICKEN: - return BEHIND_ROW; - case ST_AVOID: - return AVOID_ROW; - case ST_FLEE: - return FLEE_ROW; - default: - assert(!"unknown combatrow"); + case ST_AGGRO: + case ST_FIGHT: + return FIGHT_ROW; + case ST_BEHIND: + case ST_CHICKEN: + return BEHIND_ROW; + case ST_AVOID: + return AVOID_ROW; + case ST_FLEE: + return FLEE_ROW; + default: + assert(!"unknown combatrow"); } return FIGHT_ROW; } -static double -hpflee(int status) +static double hpflee(int status) /* if hp drop below this percentage, run away */ { switch (status) { - case ST_AGGRO: - return 0.0; - case ST_FIGHT: - case ST_BEHIND: - return 0.2; - case ST_CHICKEN: - case ST_AVOID: - return 0.9; - case ST_FLEE: - return 1.0; - default: - assert(!"unknown combatrow"); + case ST_AGGRO: + return 0.0; + case ST_FIGHT: + case ST_BEHIND: + return 0.2; + case ST_CHICKEN: + case ST_AVOID: + return 0.9; + case ST_FLEE: + return 1.0; + default: + assert(!"unknown combatrow"); } return 0.0; } -static int -get_row(const side * s, int row, const side * vs) +static int get_row(const side * s, int row, const side * vs) { boolean counted[MAXSIDES]; + int enemyfront = 0; + int line, result; + int retreat = 0; + int size[NUMROWS]; + int front = 0; - battle * b = s->battle; + + battle *b = s->battle; memset(counted, 0, sizeof(counted)); memset(size, 0, sizeof(size)); - for (line=FIRST_ROW;line!=NUMROWS;++line) { + for (line = FIRST_ROW; line != NUMROWS; ++line) { int si, sa_i; + /* how many enemies are there in the first row? */ - for (si=0;s->enemies[si];++si) { + for (si = 0; s->enemies[si]; ++si) { side *se = s->enemies[si]; - if (se->size[line]>0) { - enemyfront += se->size[line]; + + if (se->size[line] > 0) { + enemyfront += se->size[line]; /* - s->nonblockers[line] (nicht, weil angreifer) */ } } - for (sa_i=0; sa_i!=b->nsides; ++sa_i) { - side * sa = b->sides+sa_i; + for (sa_i = 0; sa_i != b->nsides; ++sa_i) { + side *sa = b->sides + sa_i; + /* count people that like me, but don't like my enemy */ if (friendly_i(s, sa_i) && enemy_i(vs, sa_i)) { if (!counted[sa_i]) { int i; - - for (i=0;i!=NUMROWS;++i) { + + for (i = 0; i != NUMROWS; ++i) { size[i] += sa->size[i] - sa->nonblockers[i]; } counted[sa_i] = true; } } } - if (enemyfront) break; + if (enemyfront) + break; } if (enemyfront) { - for (line=FIRST_ROW;line!=NUMROWS;++line) { + for (line = FIRST_ROW; line != NUMROWS; ++line) { front += size[line]; - if (!front || frontstatus); - if (vs==NULL) { + + if (vs == NULL) { int i; - for (i=FIGHT_ROW;i!=row;++i) if (af->side->size[i]) break; - return FIGHT_ROW+(row-i); + + for (i = FIGHT_ROW; i != row; ++i) + if (af->side->size[i]) + break; + return FIGHT_ROW + (row - i); } else { #ifdef FASTROW - battle * b = vs->battle; - if (row!=b->rowcache.row || b->alive!=b->rowcache.alive || af->side!=b->rowcache.as || vs!=b->rowcache.vs) { + battle *b = vs->battle; + + if (row != b->rowcache.row || b->alive != b->rowcache.alive + || af->side != b->rowcache.as || vs != b->rowcache.vs) { b->rowcache.alive = b->alive; b->rowcache.as = af->side; b->rowcache.vs = vs; @@ -518,10 +558,11 @@ get_unitrow(const fighter * af, const side * vs) b->rowcache.result = get_row(af->side, row, vs); return b->rowcache.result; } -#ifdef DEBUG_FAST /* validation code */ +#ifdef DEBUG_FAST /* validation code */ { int i = get_row(af->side, row, vs); - assert(i==b->rowcache.result); + + assert(i == b->rowcache.result); } #endif return b->rowcache.result; @@ -531,16 +572,19 @@ get_unitrow(const fighter * af, const side * vs) } } -static void -reportcasualties(battle * b, fighter * fig, int dead) +static void reportcasualties(battle * b, fighter * fig, int dead) { - struct message * m; - region * r = NULL; - if (fig->alive == fig->unit->number) return; + struct message *m; + + region *r = NULL; + + if (fig->alive == fig->unit->number) + return; #ifndef SIMPLE_ESCAPE if (fig->run.region == NULL) { fig->run.region = fleeregion(fig->unit); - if (fig->run.region == NULL) fig->run.region = b->region; + if (fig->run.region == NULL) + fig->run.region = b->region; } r = fig->run.region; #endif /* SIMPLE_ESCAPE */ @@ -554,6 +598,7 @@ static int contest_classic(int skilldiff, const armor_type * ar, const armor_type * sh) { int p, vw = BASE_CHANCE - TDIFF_CHANGE * skilldiff; + double mod = 1.0; if (ar != NULL) @@ -574,54 +619,64 @@ contest_classic(int skilldiff, const armor_type * ar, const armor_type * sh) * \param skilldiff - the attack skill with every modifier applied */ static int -contest_new(int skilldiff, const troop dt, const armor_type * ar, const armor_type * sh) +contest_new(int skilldiff, const troop dt, const armor_type * ar, + const armor_type * sh) { double tohit = 0.5 + skilldiff * 0.1; - if (tohit<0.5) tohit = 0.5; + + if (tohit < 0.5) + tohit = 0.5; if (chance(tohit)) { int defense = effskill(dt.fighter->unit, SK_STAMINA); + double tosave = defense * 0.05; + return !chance(tosave); } return 0; } static int -contest(int skdiff, const troop dt, const armor_type * ar, const armor_type * sh) +contest(int skdiff, const troop dt, const armor_type * ar, + const armor_type * sh) { - if (skill_formula==FORMULA_ORIG) { + if (skill_formula == FORMULA_ORIG) { return contest_classic(skdiff, ar, sh); } else { return contest_new(skdiff, dt, ar, sh); } } -static boolean -is_riding(const troop t) { - if (t.fighter->building!=NULL) return false; - if (t.fighter->horses + t.fighter->elvenhorses > t.index) return true; +static boolean is_riding(const troop t) +{ + if (t.fighter->building != NULL) + return false; + if (t.fighter->horses + t.fighter->elvenhorses > t.index) + return true; return false; } -static weapon * -preferred_weapon(const troop t, boolean attacking) +static weapon *preferred_weapon(const troop t, boolean attacking) { - weapon * missile = t.fighter->person[t.index].missile; - weapon * melee = t.fighter->person[t.index].melee; + weapon *missile = t.fighter->person[t.index].missile; + + weapon *melee = t.fighter->person[t.index].melee; + if (attacking) { - if (melee==NULL || (missile && missile->attackskill>melee->attackskill)) { + if (melee == NULL || (missile && missile->attackskill > melee->attackskill)) { return missile; } } else { - if (melee==NULL || (missile && missile->defenseskill>melee->defenseskill)) { + if (melee == NULL || (missile + && missile->defenseskill > melee->defenseskill)) { return missile; } } return melee; } -static weapon * -select_weapon(const troop t, boolean attacking, boolean ismissile) +static weapon *select_weapon(const troop t, boolean attacking, + boolean ismissile) /* select the primary weapon for this trooper */ { if (attacking) { @@ -638,8 +693,7 @@ select_weapon(const troop t, boolean attacking, boolean ismissile) return preferred_weapon(t, attacking); } -static boolean -i_canuse(const unit * u, const item_type * itype) +static boolean i_canuse(const unit * u, const item_type * itype) { if (itype->canuse) { return itype->canuse(u, itype); @@ -655,13 +709,15 @@ weapon_skill(const weapon_type * wtype, const unit * u, boolean attacking) { int skill; - if (wtype==NULL) { + if (wtype == NULL) { skill = effskill(u, SK_WEAPONLESS); - if (skill<=0) { + if (skill <= 0) { /* wenn kein waffenloser kampf, dann den rassen-defaultwert */ if (u->race == new_race[RC_ORC]) { int sword = effskill(u, SK_MELEE); + int spear = effskill(u, SK_SPEAR); + skill = MAX(sword, spear) - 3; if (attacking) { skill = MAX(skill, u->race->at_default); @@ -679,23 +735,29 @@ weapon_skill(const weapon_type * wtype, const unit * u, boolean attacking) /* der rassen-defaultwert kann höher sein als der Talentwert von * waffenloser kampf */ if (attacking) { - if (skill < u->race->at_default) skill = u->race->at_default; + if (skill < u->race->at_default) + skill = u->race->at_default; } else { - if (skill < u->race->df_default) skill = u->race->df_default; + if (skill < u->race->df_default) + skill = u->race->df_default; } } if (attacking) { skill += u->race->at_bonus; - if (fval(u->region->terrain, SEA_REGION) && u->ship) skill += u->ship->type->at_bonus; + if (fval(u->region->terrain, SEA_REGION) && u->ship) + skill += u->ship->type->at_bonus; } else { skill += u->race->df_bonus; - if (fval(u->region->terrain, SEA_REGION) && u->ship) skill += u->ship->type->df_bonus; + if (fval(u->region->terrain, SEA_REGION) && u->ship) + skill += u->ship->type->df_bonus; } } else { /* changed: if we own a weapon, we have at least a skill of 0 */ - if (!i_canuse(u, wtype->itype)) return -1; + if (!i_canuse(u, wtype->itype)) + return -1; skill = effskill(u, wtype->skill); - if (skill < wtype->minskill) skill = 0; + if (skill < wtype->minskill) + skill = 0; if (skill > 0) { if (attacking) { skill += u->race->at_bonus; @@ -717,7 +779,7 @@ static int CavalrySkill(void) { static int skill = -1; - if (skill<0) { + if (skill < 0) { skill = get_param_int(global.parameters, "rules.cavalry.skill", 2); } return skill; @@ -725,32 +787,33 @@ static int CavalrySkill(void) #define BONUS_SKILL 1 #define BONUS_DAMAGE 2 -static int -CavalryBonus(const unit * u, troop enemy, int type) +static int CavalryBonus(const unit * u, troop enemy, int type) { static int mode = -1; - if (mode<0) { + if (mode < 0) { mode = get_param_int(global.parameters, "rules.cavalry.mode", 1); } - if (mode==0) { + if (mode == 0) { /* old rule, Eressea 1.0 compat */ - return (type==BONUS_SKILL)?2:0; + return (type == BONUS_SKILL) ? 2 : 0; } else { /* new rule, chargers in Eressea 1.1 */ int skl = effskill(u, SK_RIDING); + /* only half against trolls */ - if (skl>0) { - if (type==BONUS_DAMAGE) { + if (skl > 0) { + if (type == BONUS_DAMAGE) { int dmg = MIN(skl, 8); - if (enemy.fighter->unit->race==new_race[RC_TROLL]) { - dmg = dmg/4; + + if (enemy.fighter->unit->race == new_race[RC_TROLL]) { + dmg = dmg / 4; } else { - dmg = dmg/2; + dmg = dmg / 2; } return dmg; } else { - skl = skl/2; + skl = skl / 2; return MIN(skl, 4); } } @@ -759,17 +822,21 @@ CavalryBonus(const unit * u, troop enemy, int type) } static int -weapon_effskill(troop t, troop enemy, const weapon * w, boolean attacking, boolean missile) +weapon_effskill(troop t, troop enemy, const weapon * w, boolean attacking, + boolean missile) /* effektiver Waffenskill während des Kampfes */ { /* In dieser Runde alle die Modifier berechnen, die fig durch die * Waffen bekommt. */ - fighter * tf = t.fighter; - unit * tu = t.fighter->unit; - int skill; - const weapon_type * wtype = w?w->type:NULL; + fighter *tf = t.fighter; - if (wtype==NULL) { + unit *tu = t.fighter->unit; + + int skill; + + const weapon_type *wtype = w ? w->type : NULL; + + if (wtype == NULL) { /* Ohne Waffe: Waffenlose Angriffe */ skill = weapon_skill(NULL, tu, attacking); } else { @@ -778,25 +845,34 @@ weapon_effskill(troop t, troop enemy, const weapon * w, boolean attacking, boole } else { skill = w->defenseskill; } - if (wtype->modifiers!=NULL) { + if (wtype->modifiers != NULL) { /* Pferdebonus, Lanzenbonus, usw. */ int m; - unsigned int flags = WMF_SKILL|(attacking?WMF_OFFENSIVE:WMF_DEFENSIVE); - if (is_riding(t)) flags |= WMF_RIDING; - else flags |= WMF_WALKING; - if (is_riding(enemy)) flags |= WMF_AGAINST_RIDING; - else flags |= WMF_AGAINST_WALKING; + unsigned int flags = + WMF_SKILL | (attacking ? WMF_OFFENSIVE : WMF_DEFENSIVE); - for (m=0;wtype->modifiers[m].value;++m) { + if (is_riding(t)) + flags |= WMF_RIDING; + else + flags |= WMF_WALKING; + if (is_riding(enemy)) + flags |= WMF_AGAINST_RIDING; + else + flags |= WMF_AGAINST_WALKING; + + for (m = 0; wtype->modifiers[m].value; ++m) { if ((wtype->modifiers[m].flags & flags) == flags) { - race_list * rlist = wtype->modifiers[m].races; - if (rlist!=NULL) { + race_list *rlist = wtype->modifiers[m].races; + + if (rlist != NULL) { while (rlist) { - if (rlist->data == tu->race) break; + if (rlist->data == tu->race) + break; rlist = rlist->next; } - if (rlist==NULL) continue; + if (rlist == NULL) + continue; } skill += wtype->modifiers[m].value; } @@ -805,19 +881,23 @@ weapon_effskill(troop t, troop enemy, const weapon * w, boolean attacking, boole } /* Burgenbonus, Pferdebonus */ - if (is_riding(t) && (wtype==NULL || (fval(wtype, WTF_HORSEBONUS) && !fval(wtype, WTF_MISSILE)))) { + if (is_riding(t) && (wtype == NULL || (fval(wtype, WTF_HORSEBONUS) + && !fval(wtype, WTF_MISSILE)))) { skill += CavalryBonus(tu, enemy, BONUS_SKILL); - if (wtype) skill = skillmod(urace(tu)->attribs, tu, tu->region, wtype->skill, skill, SMF_RIDING); + if (wtype) + skill = + skillmod(urace(tu)->attribs, tu, tu->region, wtype->skill, skill, + SMF_RIDING); } - if (t.indexelvenhorses) { + if (t.index < tf->elvenhorses) { /* Elfenpferde: Helfen dem Reiter, egal ob und welche Waffe. Das ist * eleganter, und vor allem einfacher, sonst muß man noch ein * WMF_ELVENHORSE einbauen. */ skill += 2; } - if (skill>0 && !attacking && missile) { + if (skill > 0 && !attacking && missile) { /* * Wenn ich verteidige, und nicht direkt meinem Feind gegenüberstehe, * halbiert sich mein Skill: (z.B. gegen Fernkämpfer. Nahkämpfer @@ -828,12 +908,14 @@ weapon_effskill(troop t, troop enemy, const weapon * w, boolean attacking, boole return skill; } -static const armor_type * -select_armor(troop t, boolean shield) +static const armor_type *select_armor(troop t, boolean shield) { - unsigned int type = shield?ATF_SHIELD:0; - unit * u = t.fighter->unit; - const armor * a = t.fighter->armors; + unsigned int type = shield ? ATF_SHIELD : 0; + + unit *u = t.fighter->unit; + + const armor *a = t.fighter->armors; + int geschuetzt = 0; /* some monsters should not use armor (dragons in chainmail? ha!) */ @@ -845,8 +927,8 @@ select_armor(troop t, boolean shield) return NULL; } - for (;a;a=a->next) { - if ((a->atype->flags & ATF_SHIELD)==type) { + for (; a; a = a->next) { + if ((a->atype->flags & ATF_SHIELD) == type) { geschuetzt += a->count; if (geschuetzt > t.index) { /* unser Kandidat wird geschuetzt */ @@ -863,46 +945,51 @@ select_armor(troop t, boolean shield) * - Artefakt I_TROLLBELT gibt Rüstung +1 * - Zauber Rindenhaut gibt Rüstung +3 */ -int -select_magicarmor(troop t) +int select_magicarmor(troop t) { unit *u = t.fighter->unit; + int geschuetzt = 0; + int ma = 0; geschuetzt = MIN(get_item(u, I_TROLLBELT), u->number); - if (geschuetzt > t.index) /* unser Kandidat wird geschuetzt */ + if (geschuetzt > t.index) /* unser Kandidat wird geschuetzt */ ma += 1; return ma; } /* Sind side ds und Magier des meffect verbündet, dann return 1*/ -boolean -meffect_protection(battle * b, meffect * s, side * ds) +boolean meffect_protection(battle * b, meffect * s, side * ds) { - if (!s->magician->alive) return false; - if (s->duration <= 0) return false; - if (enemy(s->magician->side, ds)) return false; - if (allysf(s->magician->side, ds->faction)) return true; + if (!s->magician->alive) + return false; + if (s->duration <= 0) + return false; + if (enemy(s->magician->side, ds)) + return false; + if (allysf(s->magician->side, ds->faction)) + return true; return false; } /* Sind side as und Magier des meffect verfeindet, dann return 1*/ -boolean -meffect_blocked(battle *b, meffect *s, side *as) +boolean meffect_blocked(battle * b, meffect * s, side * as) { - if (!s->magician->alive) return false; - if (s->duration <= 0) return false; - if (enemy(s->magician->side, as)) return true; + if (!s->magician->alive) + return false; + if (s->duration <= 0) + return false; + if (enemy(s->magician->side, as)) + return true; return false; } /* rmfighter wird schon im PRAECOMBAT gebraucht, da gibt es noch keine * troops */ -void -rmfighter(fighter *df, int i) +void rmfighter(fighter * df, int i) { side *ds = df->side; @@ -911,7 +998,7 @@ rmfighter(fighter *df, int i) assert(df->alive <= df->unit->number); /* erst ziehen wir die Anzahl der Personen von den Kämpfern in der - * Schlacht, dann von denen auf dieser Seite ab*/ + * Schlacht, dann von denen auf dieser Seite ab*/ df->side->alive -= i; df->side->battle->alive -= i; @@ -930,8 +1017,7 @@ rmfighter(fighter *df, int i) } -static void -rmtroop(troop dt) +static void rmtroop(troop dt) { fighter *df = dt.fighter; @@ -946,44 +1032,48 @@ rmtroop(troop dt) df->person[df->alive].hp = 0; } -void -remove_troop(troop dt) +void remove_troop(troop dt) { - fighter * df = dt.fighter; + fighter *df = dt.fighter; + struct person p = df->person[dt.index]; - battle * b = df->side->battle; + + battle *b = df->side->battle; + #ifdef FASTCOUNT - b->fast.alive = -1; /* invalidate cached value */ + b->fast.alive = -1; /* invalidate cached value */ #endif #ifdef FASTROW - b->rowcache.alive = -1; /* invalidate cached value */ + b->rowcache.alive = -1; /* invalidate cached value */ #endif ++df->removed; ++df->side->removed; - df->person[dt.index] = df->person[df->alive-df->removed]; + df->person[dt.index] = df->person[df->alive - df->removed]; df->person[df->alive - df->removed] = p; } -void -kill_troop(troop dt) +void kill_troop(troop dt) { - fighter * df = dt.fighter; - unit * du = df->unit; + fighter *df = dt.fighter; + + unit *du = df->unit; rmtroop(dt); if (!df->alive) { char eqname[64]; - const struct equipment * eq; - if (du->race->itemdrop) { - item * drops = du->race->itemdrop(du->race, du->number-df->run.number); - if (drops != NULL){ + const struct equipment *eq; + + if (du->race->itemdrop) { + item *drops = du->race->itemdrop(du->race, du->number - df->run.number); + + if (drops != NULL) { i_merge(&du->items, &drops); } } sprintf(eqname, "%s_spoils", du->race->_name[0]); eq = get_equipment(eqname); - if (eq!=NULL) { + if (eq != NULL) { equip_items(&du->items, eq); } } @@ -992,15 +1082,15 @@ kill_troop(troop dt) /** reduces the target's exp by an equivalent of n points learning * 30 points = 1 week */ -void -drain_exp(struct unit *u, int n) +void drain_exp(struct unit *u, int n) { - skill_t sk = (skill_t)(rng_int() % MAXSKILLS); + skill_t sk = (skill_t) (rng_int() % MAXSKILLS); + skill_t ssk; ssk = sk; - while (get_level(u, sk)==0) { + while (get_level(u, sk) == 0) { sk++; if (sk == MAXSKILLS) sk = 0; @@ -1010,23 +1100,24 @@ drain_exp(struct unit *u, int n) } } if (sk != NOSKILL) { - skill * sv = get_skill(u, sk); - while (n>0) { - if (n>=30*u->number) { + skill *sv = get_skill(u, sk); + + while (n > 0) { + if (n >= 30 * u->number) { reduce_skill(u, sv, 1); - n-=30; + n -= 30; } else { - if (rng_int()%(30*u->number)number) < n) + reduce_skill(u, sv, 1); n = 0; } } } } -const char * -rel_dam(int dam, int hp) +const char *rel_dam(int dam, int hp) { - double q = (double)dam/(double)hp; + double q = (double)dam / (double)hp; if (q > 0.75) { return "eine klaffende Wunde"; @@ -1041,32 +1132,44 @@ rel_dam(int dam, int hp) static void vampirism(troop at, int damage) { static int vampire = -1; - if (vampire<0) vampire = get_param_int(global.parameters, "rules.combat.demon_vampire", 0); - if (vampire>0) { - int gain = damage/vampire; + + if (vampire < 0) + vampire = get_param_int(global.parameters, "rules.combat.demon_vampire", 0); + + if (vampire > 0) { + int gain = damage / vampire; + int chance = damage - vampire * gain; - if (chance>0 && (rng_int() % vampire < chance)) ++gain; - if (gain>0) { + + if (chance > 0 && (rng_int() % vampire < chance)) + ++gain; + if (gain > 0) { int maxhp = unit_max_hp(at.fighter->unit); - at.fighter->person[at.index].hp = MIN(gain+at.fighter->person[at.index].hp, maxhp); + + at.fighter->person[at.index].hp = + MIN(gain + at.fighter->person[at.index].hp, maxhp); } } } -static int -natural_armor(unit * du) +static int natural_armor(unit * du) { - static int * bonus = 0; + static int *bonus = 0; + int an = du->race->armor; - if (bonus==0) { + + if (bonus == 0) { bonus = calloc(sizeof(int), num_races); } - if (bonus[du->race->index]==0) { - bonus[du->race->index] = get_param_int(du->race->parameters, "armor.stamina", -1); - if (bonus[du->race->index]==0) bonus[du->race->index] = -1; + if (bonus[du->race->index] == 0) { + bonus[du->race->index] = + get_param_int(du->race->parameters, "armor.stamina", -1); + if (bonus[du->race->index] == 0) + bonus[du->race->index] = -1; } - if (bonus[du->race->index]>0) { + if (bonus[du->race->index] > 0) { int sk = effskill(du, SK_STAMINA); + sk /= bonus[du->race->index]; an += sk; } @@ -1076,70 +1179,88 @@ natural_armor(unit * du) boolean terminate(troop dt, troop at, int type, const char *damage, boolean missile) { - item ** pitm; + item **pitm; + fighter *df = dt.fighter; + fighter *af = at.fighter; + unit *au = af->unit; + unit *du = df->unit; + battle *b = df->side->battle; + int heiltrank = 0; + static int rule_armor = -1; /* Schild */ side *ds = df->side; + int hp; int ar = 0, an, am; - const armor_type * armor = select_armor(dt, true); - const armor_type * shield = select_armor(dt, false); + + const armor_type *armor = select_armor(dt, true); + + const armor_type *shield = select_armor(dt, false); const weapon_type *dwtype = NULL; + const weapon_type *awtype = NULL; - const weapon * weapon; + + const weapon *weapon; int rda, sk = 0, sd; + boolean magic = false; + int da = dice_rand(damage); - assert(du->number>0); + assert(du->number > 0); #ifdef SHOW_KILLS ++at.fighter->hits; #endif switch (type) { - case AT_STANDARD: - weapon = select_weapon(at, true, missile); - sk = weapon_effskill(at, dt, weapon, true, missile); - if (weapon) awtype = weapon->type; - if (awtype && fval(awtype, WTF_MAGICAL)) magic = true; - break; - case AT_NATURAL: - sk = weapon_effskill(at, dt, NULL, true, missile); - break; - case AT_SPELL: - case AT_COMBATSPELL: - magic = true; - break; - default: - break; + case AT_STANDARD: + weapon = select_weapon(at, true, missile); + sk = weapon_effskill(at, dt, weapon, true, missile); + if (weapon) + awtype = weapon->type; + if (awtype && fval(awtype, WTF_MAGICAL)) + magic = true; + break; + case AT_NATURAL: + sk = weapon_effskill(at, dt, NULL, true, missile); + break; + case AT_SPELL: + case AT_COMBATSPELL: + magic = true; + break; + default: + break; } - weapon = select_weapon(dt, false, true); /* missile=true to get the unmodified best weapon she has */ + weapon = select_weapon(dt, false, true); /* missile=true to get the unmodified best weapon she has */ sd = weapon_effskill(dt, at, weapon, false, false); - if (weapon!=NULL) dwtype=weapon->type; + if (weapon != NULL) + dwtype = weapon->type; - if (is_riding(at) && (awtype==NULL || (fval(awtype, WTF_HORSEBONUS) && !fval(awtype, WTF_MISSILE)))) { + if (is_riding(at) && (awtype == NULL || (fval(awtype, WTF_HORSEBONUS) + && !fval(awtype, WTF_MISSILE)))) { da += CavalryBonus(au, dt, BONUS_DAMAGE); } if (armor) { ar += armor->prot; - if (armor->projectile>0 && chance(armor->projectile)) { + if (armor->projectile > 0 && chance(armor->projectile)) { return false; } } if (shield) { ar += shield->prot; - if (shield->projectile>0 && chance(shield->projectile)) { + if (shield->projectile > 0 && chance(shield->projectile)) { return false; } } @@ -1159,24 +1280,24 @@ terminate(troop dt, troop at, int type, const char *damage, boolean missile) } #endif - if (rule_armor<0) { + if (rule_armor < 0) { rule_armor = get_param_int(global.parameters, "rules.combat.nat_armor", 0); } - if (rule_armor==0) { + if (rule_armor == 0) { /* natürliche Rüstung ist halbkumulativ */ - if (ar>0) { - ar += an/2; + if (ar > 0) { + ar += an / 2; } else { ar = an; } } else { /* use the higher value, add half the other value */ - ar = (ar>an)?(ar+an/2):(an+ar/2); + ar = (ar > an) ? (ar + an / 2) : (an + ar / 2); } ar += am; - if (type!=AT_COMBATSPELL && type!=AT_SPELL) { - if (damage_rules&DAMAGE_CRITICAL) { + if (type != AT_COMBATSPELL && type != AT_SPELL) { + if (damage_rules & DAMAGE_CRITICAL) { double kritchance = (sk * 3 - sd) / 200.0; kritchance = MAX(kritchance, 0.005); @@ -1192,26 +1313,26 @@ terminate(troop dt, troop at, int type, const char *damage, boolean missile) da += rc_specialdamage(au->race, du->race, awtype); - if (awtype!=NULL && fval(awtype, WTF_MISSILE)) { + if (awtype != NULL && fval(awtype, WTF_MISSILE)) { /* missile weapon bonus */ - if (damage_rules&DAMAGE_MISSILE_BONUS) { + if (damage_rules & DAMAGE_MISSILE_BONUS) { da += af->person[at.index].damage_rear; } - } else if (awtype==NULL) { + } else if (awtype == NULL) { /* skill bonus for unarmed combat */ - if (damage_rules&DAMAGE_UNARMED_BONUS) { + if (damage_rules & DAMAGE_UNARMED_BONUS) { da += effskill(au, SK_WEAPONLESS); } } else { /* melee bonus */ - if (damage_rules&DAMAGE_MELEE_BONUS) { + if (damage_rules & DAMAGE_MELEE_BONUS) { da += af->person[at.index].damage; } } /* Skilldifferenzbonus */ - if (damage_rules&DAMAGE_SKILL_BONUS) { - da += MAX(0, (sk-sd)/DAMAGE_QUOTIENT); + if (damage_rules & DAMAGE_SKILL_BONUS) { + da += MAX(0, (sk - sd) / DAMAGE_QUOTIENT); } } @@ -1221,49 +1342,61 @@ terminate(troop dt, troop at, int type, const char *damage, boolean missile) double res = 1.0; /* magic_resistance gib x% Resistenzbonus zurück */ - res -= magic_resistance(du)*3.0; + res -= magic_resistance(du) * 3.0; if (du->race->battle_flags & BF_EQUIPMENT) { #ifdef TODO_RUNESWORD /* Runenschwert gibt im Kampf 80% Resistenzbonus */ - if (dwp == WP_RUNESWORD) res -= 0.80; + if (dwp == WP_RUNESWORD) + res -= 0.80; #endif /* der Effekt von Laen steigt nicht linear */ - if (armor && fval(armor, ATF_LAEN)) res *= (1-armor->magres); - if (shield && fval(shield, ATF_LAEN)) res *= (1-shield->magres); - if (dwtype) res *= (1-dwtype->magres); + if (armor && fval(armor, ATF_LAEN)) + res *= (1 - armor->magres); + if (shield && fval(shield, ATF_LAEN)) + res *= (1 - shield->magres); + if (dwtype) + res *= (1 - dwtype->magres); } if (res > 0) { - da = (int) (MAX(da * res, 0)); + da = (int)(MAX(da * res, 0)); } /* gegen Magie wirkt nur natürliche und magische Rüstung */ - ar = an+am; + ar = an + am; } - rda = MAX(da - ar,0); + rda = MAX(da - ar, 0); - if ((du->race->battle_flags & BF_INV_NONMAGIC) && !magic) rda = 0; + if ((du->race->battle_flags & BF_INV_NONMAGIC) && !magic) + rda = 0; else { int qi; - quicklist * ql; + + quicklist *ql; + unsigned int i = 0; - if (du->race->battle_flags & BF_RES_PIERCE) i |= WTF_PIERCE; - if (du->race->battle_flags & BF_RES_CUT) i |= WTF_CUT; - if (du->race->battle_flags & BF_RES_BASH) i |= WTF_BLUNT; + if (du->race->battle_flags & BF_RES_PIERCE) + i |= WTF_PIERCE; + if (du->race->battle_flags & BF_RES_CUT) + i |= WTF_CUT; + if (du->race->battle_flags & BF_RES_BASH) + i |= WTF_BLUNT; - if (i && awtype && fval(awtype, i)) rda /= 2; + if (i && awtype && fval(awtype, i)) + rda /= 2; /* Schilde */ - for (qi=0,ql=b->meffects;ql;ql_advance(&ql, &qi, 1)) { - meffect *me = (meffect *)ql_get(ql, qi); + for (qi = 0, ql = b->meffects; ql; ql_advance(&ql, &qi, 1)) { + meffect *me = (meffect *) ql_get(ql, qi); + if (meffect_protection(b, me, ds) != 0) { - assert(0 <= rda); /* rda sollte hier immer mindestens 0 sein */ + assert(0 <= rda); /* rda sollte hier immer mindestens 0 sein */ /* jeder Schaden wird um effect% reduziert bis der Schild duration - * Trefferpunkte aufgefangen hat */ + * Trefferpunkte aufgefangen hat */ if (me->typ == SHIELD_REDUCE) { - hp = rda * (me->effect/100); + hp = rda * (me->effect / 100); rda -= hp; me->duration -= hp; } @@ -1276,22 +1409,23 @@ terminate(troop dt, troop at, int type, const char *damage, boolean missile) } } - assert(dt.indexnumber); + assert(dt.index < du->number); df->person[dt.index].hp -= rda; - if (au->race==new_race[RC_DAEMON]) { + if (au->race == new_race[RC_DAEMON]) { vampirism(at, rda); } - if (df->person[dt.index].hp > 0) { /* Hat überlebt */ + if (df->person[dt.index].hp > 0) { /* Hat überlebt */ if (bdebug) { fprintf(bdebug, "Damage %d, armor %d: %d -> %d HP\n", da, ar, df->person[dt.index].hp + rda, df->person[dt.index].hp); } if (au->race == new_race[RC_DAEMON]) { #ifdef TODO_RUNESWORD - if (select_weapon(dt, 0, -1) == WP_RUNESWORD) continue; + if (select_weapon(dt, 0, -1) == WP_RUNESWORD) + continue; #endif - if (!(df->person[dt.index].flags & (FL_COURAGE|FL_DAZZLED))) { + if (!(df->person[dt.index].flags & (FL_COURAGE | FL_DAZZLED))) { df->person[dt.index].flags |= FL_DAZZLED; df->person[dt.index].defence--; } @@ -1302,7 +1436,7 @@ terminate(troop dt, troop at, int type, const char *damage, boolean missile) /* Sieben Leben */ if (du->race == new_race[RC_CAT] && (chance(1.0 / 7))) { - assert(dt.index>=0 && dt.indexnumber); + assert(dt.index >= 0 && dt.index < du->number); df->person[dt.index].hp = unit_max_hp(du); return false; } @@ -1319,11 +1453,12 @@ terminate(troop dt, troop at, int type, const char *damage, boolean missile) } if (heiltrank && (chance(0.50))) { { - message * m = msg_message("battle::potionsave", "unit", du); + message *m = msg_message("battle::potionsave", "unit", du); + message_faction(b, du->faction, m); msg_release(m); } - assert(dt.index>=0 && dt.indexnumber); + assert(dt.index >= 0 && dt.index < du->number); df->person[dt.index].hp = du->race->hitpoints; return false; } @@ -1336,16 +1471,18 @@ terminate(troop dt, troop at, int type, const char *damage, boolean missile) fprintf(bdebug, "Damage %d, armor %d, type %d: %d -> %d HP, tot.\n", da, ar, type, df->person[dt.index].hp + rda, df->person[dt.index].hp); } - for (pitm=&du->items; *pitm; ) { - item * itm = *pitm; - const item_type * itype = itm->type; + for (pitm = &du->items; *pitm;) { + item *itm = *pitm; + + const item_type *itype = itm->type; + if (!(itype->flags & ITF_CURSED) && dt.index < itm->number) { /* 25% Grundchance, das ein Item kaputtgeht. */ if (rng_int() % 4 < 1) { i_change(pitm, itype, -1); } } - if (*pitm==itm) { + if (*pitm == itm) { pitm = &itm->next; } } @@ -1357,19 +1494,23 @@ terminate(troop dt, troop at, int type, const char *damage, boolean missile) static int count_side(const side * s, const side * vs, int minrow, int maxrow, int select) { - fighter * fig; + fighter *fig; + int people = 0; + int unitrow[NUMROWS]; - if (maxrowfighters; fig; fig = fig->next) { if (fig->alive - fig->removed > 0) { int row = statusrow(fig->status); - if (select&SELECT_ADVANCE) { + + if (select & SELECT_ADVANCE) { if (unitrow[row] == -1) { unitrow[row] = get_unitrow(fig, vs); } @@ -1377,7 +1518,8 @@ count_side(const side * s, const side * vs, int minrow, int maxrow, int select) } if (row >= minrow && row <= maxrow) { people += fig->alive - fig->removed; - if (people>0 && (select&SELECT_FIND)) break; + if (people > 0 && (select & SELECT_FIND)) + break; } } } @@ -1391,71 +1533,85 @@ int count_allies(const side * as, int minrow, int maxrow, int select, int allytype) { battle *b = as->battle; + side *ds; + int count = 0; - for (ds=b->sides;ds!=b->sides+b->nsides;++ds) { - if ((allytype==ALLY_ANY && helping(as, ds)) || (allytype==ALLY_SELF && as->faction==ds->faction)) { + for (ds = b->sides; ds != b->sides + b->nsides; ++ds) { + if ((allytype == ALLY_ANY && helping(as, ds)) || (allytype == ALLY_SELF + && as->faction == ds->faction)) { count += count_side(ds, NULL, minrow, maxrow, select); - if (count>0 && (select&SELECT_FIND)) break; + if (count > 0 && (select & SELECT_FIND)) + break; } } return count; } static int -count_enemies_i(battle * b, const fighter * af, int minrow, int maxrow, int select) +count_enemies_i(battle * b, const fighter * af, int minrow, int maxrow, + int select) { side *es, *as = af->side; + int i = 0; - for (es=b->sides;es!=b->sides+b->nsides;++es) { - if (as==NULL || enemy(es, as)) { + for (es = b->sides; es != b->sides + b->nsides; ++es) { + if (as == NULL || enemy(es, as)) { int offset = 0; - if (select&SELECT_DISTANCE) { + + if (select & SELECT_DISTANCE) { offset = get_unitrow(af, es) - FIGHT_ROW; } - i += count_side(es, as, minrow-offset, maxrow-offset, select); - if (i>0 && (select&SELECT_FIND)) break; + i += count_side(es, as, minrow - offset, maxrow - offset, select); + if (i > 0 && (select & SELECT_FIND)) + break; } } return i; } int -count_enemies(battle * b, const fighter * af, int minrow, int maxrow, int select) +count_enemies(battle * b, const fighter * af, int minrow, int maxrow, + int select) { #ifdef FASTCOUNT int sr = statusrow(af->status); + side *as = af->side; - if (b->alive==b->fast.alive && as==b->fast.side && sr==b->fast.status && minrow==b->fast.minrow && maxrow==b->fast.maxrow) { - if (b->fast.enemies[select]>=0) { + if (b->alive == b->fast.alive && as == b->fast.side && sr == b->fast.status + && minrow == b->fast.minrow && maxrow == b->fast.maxrow) { + if (b->fast.enemies[select] >= 0) { #ifdef DEBUG_FAST int i = count_enemies_i(b, af, minrow, maxrow, select); - assert(i==b->fast.enemies[select]); + + assert(i == b->fast.enemies[select]); #endif return b->fast.enemies[select]; - } else if (select&SELECT_FIND) { - if (b->fast.enemies[select-SELECT_FIND]>=0) { + } else if (select & SELECT_FIND) { + if (b->fast.enemies[select - SELECT_FIND] >= 0) { #ifdef DEBUG_FAST int i = count_enemies_i(b, af, minrow, maxrow, select); - assert((i>0)==(b->fast.enemies[select-SELECT_FIND]>0)); + + assert((i > 0) == (b->fast.enemies[select - SELECT_FIND] > 0)); #endif - return b->fast.enemies[select-SELECT_FIND]; - } + return b->fast.enemies[select - SELECT_FIND]; + } } - } else if (select!=SELECT_FIND || b->alive!=b->fast.alive) { + } else if (select != SELECT_FIND || b->alive != b->fast.alive) { b->fast.side = as; b->fast.status = sr; b->fast.minrow = minrow; - b->fast.alive=b->alive; + b->fast.alive = b->alive; b->fast.maxrow = maxrow; memset(b->fast.enemies, -1, sizeof(b->fast.enemies)); } #endif - if (maxrow>=FIRST_ROW) { + if (maxrow >= FIRST_ROW) { int i = count_enemies_i(b, af, minrow, maxrow, select); + #ifdef FASTCOUNT b->fast.enemies[select] = i; #endif @@ -1464,19 +1620,22 @@ count_enemies(battle * b, const fighter * af, int minrow, int maxrow, int select return 0; } -troop -select_enemy(fighter * af, int minrow, int maxrow, int select) +troop select_enemy(fighter * af, int minrow, int maxrow, int select) { side *as = af->side; - battle * b = as->battle; + + battle *b = as->battle; + int si, selected; + int enemies; + #ifdef DEBUG_SELECT troop result = no_troop; #endif if (af->unit->race->flags & RCF_FLY) { /* flying races ignore min- and maxrow and can attack anyone fighting - * them */ + * them */ minrow = FIGHT_ROW; maxrow = BEHIND_ROW; } @@ -1485,43 +1644,53 @@ select_enemy(fighter * af, int minrow, int maxrow, int select) enemies = count_enemies(b, af, minrow, maxrow, select); /* Niemand ist in der angegebenen Entfernung? */ - if (enemies<=0) return no_troop; + if (enemies <= 0) + return no_troop; selected = rng_int() % enemies; - for (si=0;as->enemies[si];++si) { + for (si = 0; as->enemies[si]; ++si) { side *ds = as->enemies[si]; - fighter * df; + + fighter *df; + int unitrow[NUMROWS]; + int offset = 0; - if (select&SELECT_DISTANCE) offset = get_unitrow(af, ds) - FIGHT_ROW; + if (select & SELECT_DISTANCE) + offset = get_unitrow(af, ds) - FIGHT_ROW; - if (select&SELECT_ADVANCE) { + if (select & SELECT_ADVANCE) { int ui; - for (ui=0;ui!=NUMROWS;++ui) unitrow[ui] = -1; + + for (ui = 0; ui != NUMROWS; ++ui) + unitrow[ui] = -1; } - for (df=ds->fighters; df ; df = df->next) { + for (df = ds->fighters; df; df = df->next) { int dr; dr = statusrow(df->status); - if (select&SELECT_ADVANCE) { - if (unitrow[dr]<0) { + if (select & SELECT_ADVANCE) { + if (unitrow[dr] < 0) { unitrow[dr] = get_unitrow(df, as); } dr = unitrow[dr]; } - if (select&SELECT_DISTANCE) dr += offset; - if (dr < minrow || dr > maxrow) continue; + if (select & SELECT_DISTANCE) + dr += offset; + if (dr < minrow || dr > maxrow) + continue; if (df->alive - df->removed > selected) { #ifdef DEBUG_SELECT - if (result.fighter==NULL) { + if (result.fighter == NULL) { result.index = selected; result.fighter = df; } #else troop dt; + dt.index = selected; dt.fighter = df; return dt; @@ -1531,7 +1700,7 @@ select_enemy(fighter * af, int minrow, int maxrow, int select) enemies -= (df->alive - df->removed); } } - if (enemies!=0) { + if (enemies != 0) { log_error(("select_enemies has a bug.\n")); } #ifdef DEBUG_SELECT @@ -1542,18 +1711,20 @@ select_enemy(fighter * af, int minrow, int maxrow, int select) #endif } -static int -get_tactics(const side * as, const side * ds) +static int get_tactics(const side * as, const side * ds) { - battle * b = as->battle; + battle *b = as->battle; + side *stac; + int result = 0; + int defense = 0; if (b->max_tactics > 0) { - for (stac=b->sides;stac!=b->sides+b->nsides;++stac) { + for (stac = b->sides; stac != b->sides + b->nsides; ++stac) { if (stac->leader.value > result && helping(stac, as)) { - assert(ds==NULL || !helping(stac, ds)); + assert(ds == NULL || !helping(stac, ds)); result = stac->leader.value; } if (ds && stac->leader.value > defense && helping(stac, ds)) { @@ -1565,36 +1736,40 @@ get_tactics(const side * as, const side * ds) return result - defense; } -static troop -select_opponent(battle * b, troop at, int mindist, int maxdist) +static troop select_opponent(battle * b, troop at, int mindist, int maxdist) { - fighter * af = at.fighter; + fighter *af = at.fighter; + troop dt; if (af->unit->race->flags & RCF_FLY) { /* flying races ignore min- and maxrow and can attack anyone fighting - * them */ + * them */ dt = select_enemy(at.fighter, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); } else { mindist = MAX(mindist, FIGHT_ROW); dt = select_enemy(at.fighter, mindist, maxdist, SELECT_ADVANCE); } - if (b->turn==0 && dt.fighter) { + if (b->turn == 0 && dt.fighter) { int tactics_formula = -1; - if (tactics_formula<0) { - tactics_formula = get_param_int(global.parameters, "rules.tactics.formula", 0); + if (tactics_formula < 0) { + tactics_formula = + get_param_int(global.parameters, "rules.tactics.formula", 0); } - if (tactics_formula==1) { + if (tactics_formula == 1) { int tactics = get_tactics(at.fighter->side, dt.fighter->side); - + /* percentage chance to get this attack */ - if (tactics>0) { + if (tactics > 0) { double tacch = 0.1 * tactics; + if (fval(b->region->terrain, SEA_REGION)) { - ship * sh = at.fighter->unit->ship; - if (sh) tacch *= sh->type->tac_bonus; + ship *sh = at.fighter->unit->ship; + + if (sh) + tacch *= sh->type->tac_bonus; } if (!chance(tacch)) { dt.fighter = NULL; @@ -1608,28 +1783,31 @@ select_opponent(battle * b, troop at, int mindist, int maxdist) return dt; } -quicklist * -fighters(battle *b, const side * vs, int minrow, int maxrow, int mask) +quicklist *fighters(battle * b, const side * vs, int minrow, int maxrow, + int mask) { - side * s; + side *s; + quicklist *fightervp = 0; - assert(vs!=NULL); + assert(vs != NULL); - for (s=b->sides;s!=b->sides+b->nsides;++s) { + for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *fig; - if (mask==FS_ENEMY) { - if (!enemy(s, vs)) continue; - } else if (mask==FS_HELP) { + if (mask == FS_ENEMY) { + if (!enemy(s, vs)) + continue; + } else if (mask == FS_HELP) { if (enemy(s, vs) || !allysf(s, vs->faction)) { continue; } } else { - assert(mask==(FS_HELP|FS_ENEMY) || !"invalid alliance state"); + assert(mask == (FS_HELP | FS_ENEMY) || !"invalid alliance state"); } for (fig = s->fighters; fig; fig = fig->next) { int row = get_unitrow(fig, vs); + if (row >= minrow && row <= maxrow) { ql_push(&fightervp, fig); } @@ -1639,51 +1817,59 @@ fighters(battle *b, const side * vs, int minrow, int maxrow, int mask) return fightervp; } -static void -report_failed_spell(battle * b, unit * mage, const spell * sp) +static void report_failed_spell(battle * b, unit * mage, const spell * sp) { - message * m = msg_message("battle::spell_failed", "unit spell", mage, sp); + message *m = msg_message("battle::spell_failed", "unit spell", mage, sp); + message_all(b, m); msg_release(m); } -void -do_combatmagic(battle *b, combatmagic_t was) +void do_combatmagic(battle * b, combatmagic_t was) { - side * s; + side *s; + region *r = b->region; + castorder *co; + int level, rank, sl; + spellrank spellranks[MAX_SPELLRANK]; memset(spellranks, 0, sizeof(spellranks)); - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter * fig; - for (fig = s->fighters; fig; fig = fig->next) { - unit * mage = fig->unit; + for (s = b->sides; s != b->sides + b->nsides; ++s) { + fighter *fig; - if (fig->alive <= 0) continue; /* fighter kann im Kampf getötet worden sein */ + for (fig = s->fighters; fig; fig = fig->next) { + unit *mage = fig->unit; + + if (fig->alive <= 0) + continue; /* fighter kann im Kampf getötet worden sein */ level = eff_skill(mage, SK_MAGIC, r); if (level > 0) { double power; - const spell *sp; - const struct locale * lang = mage->faction->locale; - order * ord; - switch(was) { - case DO_PRECOMBATSPELL: - sp = get_combatspell(mage, 0); - sl = get_combatspelllevel(mage, 0); - break; - case DO_POSTCOMBATSPELL: - sp = get_combatspell(mage, 2); - sl = get_combatspelllevel(mage, 2); - break; - default: - /* Fehler! */ - return; + const spell *sp; + + const struct locale *lang = mage->faction->locale; + + order *ord; + + switch (was) { + case DO_PRECOMBATSPELL: + sp = get_combatspell(mage, 0); + sl = get_combatspelllevel(mage, 0); + break; + case DO_POSTCOMBATSPELL: + sp = get_combatspell(mage, 2); + sl = get_combatspelllevel(mage, 2); + break; + default: + /* Fehler! */ + return; } if (sp == NULL) continue; @@ -1695,7 +1881,8 @@ do_combatmagic(battle *b, combatmagic_t was) } level = eff_spelllevel(mage, sp, level, 1); - if (sl > 0) level = MIN(sl, level); + if (sl > 0) + level = MIN(sl, level); if (level < 0) { report_failed_spell(b, mage, sp); free_order(ord); @@ -1704,7 +1891,7 @@ do_combatmagic(battle *b, combatmagic_t was) power = spellpower(r, mage, sp, level, ord); free_order(ord); - if (power <= 0) { /* Effekt von Antimagie */ + if (power <= 0) { /* Effekt von Antimagie */ report_failed_spell(b, mage, sp); pay_spell(mage, sp, level, 1); } else if (fumble(r, mage, sp, sp->level) == true) { @@ -1719,15 +1906,18 @@ do_combatmagic(battle *b, combatmagic_t was) } for (rank = 0; rank < MAX_SPELLRANK; rank++) { for (co = spellranks[rank].begin; co; co = co->next) { - fighter * fig = co->magician.fig; - const spell * sp = co->sp; + fighter *fig = co->magician.fig; + + const spell *sp = co->sp; + int level = co->level; + double power = co->force; - if (sp->sp_function==NULL) { + if (sp->sp_function == NULL) { log_error(("spell '%s' has no function.\n", sp->sname)); } else { - level = ((cspell_f)sp->sp_function)(fig, level, power, sp); + level = ((cspell_f) sp->sp_function) (fig, level, power, sp); if (level > 0) { pay_spell(fig->unit, sp, level, 1); } @@ -1739,8 +1929,7 @@ do_combatmagic(battle *b, combatmagic_t was) } } -static void -combat_action(fighter * af, int turn) +static void combat_action(fighter * af, int turn) { #ifndef SIMPLE_COMBAT af->action_counter++; @@ -1749,35 +1938,46 @@ combat_action(fighter * af, int turn) } -static void -do_combatspell(troop at) +static void do_combatspell(troop at) { const spell *sp; + fighter *fi = at.fighter; + unit *mage = fi->unit; + battle *b = fi->side->battle; + region *r = b->region; - quicklist * ql; + + quicklist *ql; + int level, qi; + double power; + int fumblechance = 0; - order * ord; + + order *ord; + int sl; - const struct locale * lang = mage->faction->locale; + + const struct locale *lang = mage->faction->locale; sp = get_combatspell(mage, 1); if (sp == NULL) { - fi->magic = 0; /* Hat keinen Kampfzauber, kämpft nichtmagisch weiter */ + fi->magic = 0; /* Hat keinen Kampfzauber, kämpft nichtmagisch weiter */ return; } ord = create_order(K_CAST, lang, "'%s'", spell_name(sp, lang)); if (cancast(mage, sp, 1, 1, ord) == false) { - fi->magic = 0; /* Kann nicht mehr Zaubern, kämpft nichtmagisch weiter */ + fi->magic = 0; /* Kann nicht mehr Zaubern, kämpft nichtmagisch weiter */ return; } level = eff_spelllevel(mage, sp, fi->magic, 1); - if ((sl = get_combatspelllevel(mage, 1)) > 0) level = MIN(level, sl); + if ((sl = get_combatspelllevel(mage, 1)) > 0) + level = MIN(level, sl); if (fumble(r, mage, sp, sp->level) == true) { report_failed_spell(b, mage, sp); @@ -1785,8 +1985,9 @@ do_combatspell(troop at) return; } - for (qi=0,ql=b->meffects;ql;ql_advance(&ql, &qi, 1)) { - meffect *mblock = (meffect *)ql_get(ql, qi); + for (qi = 0, ql = b->meffects; ql; ql_advance(&ql, &qi, 1)) { + meffect *mblock = (meffect *) ql_get(ql, qi); + if (mblock->typ == SHIELD_BLOCK) { if (meffect_blocked(b, mblock, fi->side) != 0) { fumblechance += mblock->duration; @@ -1796,7 +1997,7 @@ do_combatspell(troop at) } /* Antimagie die Fehlschlag erhöht */ - if (rng_int()%100 < fumblechance) { + if (rng_int() % 100 < fumblechance) { report_failed_spell(b, mage, sp); pay_spell(mage, sp, level, 1); free_order(ord); @@ -1804,16 +2005,16 @@ do_combatspell(troop at) } power = spellpower(r, mage, sp, level, ord); free_order(ord); - if (power <= 0) { /* Effekt von Antimagie */ + if (power <= 0) { /* Effekt von Antimagie */ report_failed_spell(b, mage, sp); pay_spell(mage, sp, level, 1); return; } - if (sp->sp_function==NULL) { + if (sp->sp_function == NULL) { log_error(("spell '%s' has no function.\n", sp->sname)); } else { - level = ((cspell_f)sp->sp_function)(fi, level, power, sp); + level = ((cspell_f) sp->sp_function) (fi, level, power, sp); if (level > 0) { pay_spell(mage, sp, level, 1); combat_action(at.fighter, b->turn); @@ -1827,28 +2028,31 @@ do_combatspell(troop at) * wird, wirkt auch keine Antimagie (wird sonst in spellpower * gemacht) */ -static void -do_extra_spell(troop at, const att *a) +static void do_extra_spell(troop at, const att * a) { const spell *sp = a->data.sp; + fighter *fi = at.fighter; + double power; power = sp->level * MagicPower(); - if (sp->sp_function==NULL) { + if (sp->sp_function == NULL) { log_error(("spell '%s' has no function.\n", sp->sname)); } else { - ((cspell_f)sp->sp_function)(fi, sp->level, power, sp); + ((cspell_f) sp->sp_function) (fi, sp->level, power, sp); } } -static int -skilldiff(troop at, troop dt, int dist) +static int skilldiff(troop at, troop dt, int dist) { fighter *af = at.fighter, *df = dt.fighter; + unit *au = af->unit, *du = df->unit; + int is_protected = 0, skdiff = 0; - weapon * awp = select_weapon(at, true, dist>1); + + weapon *awp = select_weapon(at, true, dist > 1); skdiff += af->person[at.index].attack; skdiff -= df->person[dt.index].defence; @@ -1857,13 +2061,16 @@ skilldiff(troop at, troop dt, int dist) skdiff += 2; /* Effekte durch Rassen */ - if (awp!=NULL && au->race == new_race[RC_HALFLING] && dragonrace(du->race)) { + if (awp != NULL && au->race == new_race[RC_HALFLING] && dragonrace(du->race)) { skdiff += 5; } if (au->race == new_race[RC_GOBLIN]) { static int goblin_bonus = -1; - if (goblin_bonus<0) goblin_bonus = get_param_int(global.parameters, "rules.combat.goblinbonus", 10); + + if (goblin_bonus < 0) + goblin_bonus = + get_param_int(global.parameters, "rules.combat.goblinbonus", 10); if (af->side->size[SUM_ROW] >= df->side->size[SUM_ROW] * goblin_bonus) { skdiff += 1; } @@ -1871,43 +2078,49 @@ skilldiff(troop at, troop dt, int dist) if (df->building) { boolean init = false; - static const curse_type * strongwall_ct, * magicwalls_ct; + + static const curse_type *strongwall_ct, *magicwalls_ct; + if (!init) { strongwall_ct = ct_find("strongwall"); magicwalls_ct = ct_find("magicwalls"); - init=true; + init = true; } if (df->building->type->protection) { int beff = df->building->type->protection(df->building, du); + if (beff) { skdiff -= beff; is_protected = 2; } } if (strongwall_ct) { - curse * c = get_curse(df->building->attribs, strongwall_ct); + curse *c = get_curse(df->building->attribs, strongwall_ct); + if (curse_active(c)) { /* wirkt auf alle Gebäude */ skdiff -= curse_geteffect_int(c); is_protected = 2; } } - if (magicwalls_ct && curse_active(get_curse(df->building->attribs, magicwalls_ct))) { + if (magicwalls_ct + && curse_active(get_curse(df->building->attribs, magicwalls_ct))) { /* Verdoppelt Burgenbonus */ skdiff -= buildingeffsize(df->building, false); } } /* Goblin-Verteidigung * ist direkt in der Rassentabelle als df_default - */ + */ /* Effekte der Waffen */ - skdiff += weapon_effskill(at, dt, awp, true, dist>1); + skdiff += weapon_effskill(at, dt, awp, true, dist > 1); if (awp && fval(awp->type, WTF_MISSILE)) { skdiff -= is_protected; if (awp->type->modifiers) { int w; - for (w=0;awp->type->modifiers[w].value!=0;++w) { + + for (w = 0; awp->type->modifiers[w].value != 0; ++w) { if (awp->type->modifiers[w].flags & WMF_MISSILE_TARGET) { /* skill decreases by targeting difficulty (bow -2, catapult -4) */ skdiff -= awp->type->modifiers[w].value; @@ -1916,54 +2129,62 @@ skilldiff(troop at, troop dt, int dist) } } } - if (skill_formula==FORMULA_ORIG) { - weapon * dwp = select_weapon(dt, false, dist>1); - skdiff -= weapon_effskill(dt, at, dwp, false, dist>1); + if (skill_formula == FORMULA_ORIG) { + weapon *dwp = select_weapon(dt, false, dist > 1); + + skdiff -= weapon_effskill(dt, at, dwp, false, dist > 1); } return skdiff; } -static int -setreload(troop at) +static int setreload(troop at) { - fighter * af = at.fighter; - const weapon_type * wtype = af->person[at.index].missile->type; - if (wtype->reload == 0) return 0; + fighter *af = at.fighter; + + const weapon_type *wtype = af->person[at.index].missile->type; + + if (wtype->reload == 0) + return 0; return af->person[at.index].reload = wtype->reload; } -int -getreload(troop at) +int getreload(troop at) { return at.fighter->person[at.index].reload; } static void -debug_hit(troop at, const weapon * awp, troop dt, const weapon * dwp, int skdiff, int dist, boolean success) +debug_hit(troop at, const weapon * awp, troop dt, const weapon * dwp, + int skdiff, int dist, boolean success) { fprintf(bdebug, "%.4s/%d [%6s/%d] %s %.4s/%d [%6s/%d] with %d, distance %d\n", unitid(at.fighter->unit), at.index, - LOC(default_locale, awp ? resourcename(awp->type->itype->rtype, 0) : "unarmed"), - weapon_effskill(at, dt, awp, true, dist>1), - success?"hits":"misses", - unitid(dt.fighter->unit), dt.index, - LOC(default_locale, dwp ? resourcename(dwp->type->itype->rtype, 0) : "unarmed"), - weapon_effskill(dt, at, dwp, false, dist>1), - skdiff, dist); + LOC(default_locale, awp ? resourcename(awp->type->itype->rtype, + 0) : "unarmed"), weapon_effskill(at, dt, awp, true, dist > 1), + success ? "hits" : "misses", unitid(dt.fighter->unit), dt.index, + LOC(default_locale, dwp ? resourcename(dwp->type->itype->rtype, + 0) : "unarmed"), weapon_effskill(dt, at, dwp, false, dist > 1), skdiff, + dist); } -int -hits(troop at, troop dt, weapon * awp) +int hits(troop at, troop dt, weapon * awp) { fighter *af = at.fighter, *df = dt.fighter; - const armor_type * armor, * shield = 0; - int skdiff = 0; - int dist = get_unitrow(af, df->side) + get_unitrow(df, af->side) - 1; - weapon * dwp = select_weapon(dt, false, dist>1); - if (!df->alive) return 0; - if (getreload(at)) return 0; - if (dist>1 && (awp == NULL || !fval(awp->type, WTF_MISSILE))) return 0; + const armor_type *armor, *shield = 0; + + int skdiff = 0; + + int dist = get_unitrow(af, df->side) + get_unitrow(df, af->side) - 1; + + weapon *dwp = select_weapon(dt, false, dist > 1); + + if (!df->alive) + return 0; + if (getreload(at)) + return 0; + if (dist > 1 && (awp == NULL || !fval(awp->type, WTF_MISSILE))) + return 0; /* mark this person as hit. */ df->person[dt.index].flags |= FL_HIT; @@ -1972,19 +2193,20 @@ hits(troop at, troop dt, weapon * awp) af->person[at.index].flags &= ~FL_STUNNED; return 0; } - if ((af->person[at.index].flags & FL_TIRED && rng_int()%100 < 50) - || (af->person[at.index].flags & FL_SLEEPING)) + if ((af->person[at.index].flags & FL_TIRED && rng_int() % 100 < 50) + || (af->person[at.index].flags & FL_SLEEPING)) return 0; /* effect of sp_reeling_arrows combatspell */ - if (af->side->battle->reelarrow && awp && fval(awp->type, WTF_MISSILE) && rng_double() < 0.5) { + if (af->side->battle->reelarrow && awp && fval(awp->type, WTF_MISSILE) + && rng_double() < 0.5) { return 0; } skdiff = skilldiff(at, dt, dist); /* Verteidiger bekommt eine Rüstung */ armor = select_armor(dt, true); - if (dwp==NULL || (dwp->type->flags & WTF_USESHIELD)) { + if (dwp == NULL || (dwp->type->flags & WTF_USESHIELD)) { shield = select_armor(dt, false); } if (contest(skdiff, dt, armor, shield)) { @@ -1999,11 +2221,11 @@ hits(troop at, troop dt, weapon * awp) return 0; } -void -dazzle(battle *b, troop *td) +void dazzle(battle * b, troop * td) { /* Nicht kumulativ ! */ - if(td->fighter->person[td->index].flags & FL_DAZZLED) return; + if (td->fighter->person[td->index].flags & FL_DAZZLED) + return; #ifdef TODO_RUNESWORD if (td->fighter->weapon[WP_RUNESWORD].count > td->index) { @@ -2025,21 +2247,21 @@ dazzle(battle *b, troop *td) /* TODO: Gebäude/Schiffe sollten auch zerstörbar sein. Schwierig im Kampf, * besonders bei Schiffen. */ -void -damage_building(battle *b, building *bldg, int damage_abs) +void damage_building(battle * b, building * bldg, int damage_abs) { - bldg->size = MAX(1, bldg->size-damage_abs); + bldg->size = MAX(1, bldg->size - damage_abs); /* Wenn Burg, dann gucken, ob die Leute alle noch in das Gebäude passen. */ if (bldg->type->protection) { - side * s; + side *s; bldg->sizeleft = bldg->size; - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter * fig; - for (fig=s->fighters;fig;fig=fig->next) { + for (s = b->sides; s != b->sides + b->nsides; ++s) { + fighter *fig; + + for (fig = s->fighters; fig; fig = fig->next) { if (fig->building == bldg) { if (bldg->sizeleft >= fig->unit->number) { fig->building = bldg; @@ -2053,219 +2275,255 @@ damage_building(battle *b, building *bldg, int damage_abs) } } -static int -attacks_per_round(troop t) +static int attacks_per_round(troop t) { return t.fighter->person[t.index].speed; } -static void -make_heroes(battle * b) +static void make_heroes(battle * b) { - side * s; + side *s; + static int hero_speed = 0; - if (hero_speed==0) { + + if (hero_speed == 0) { hero_speed = get_param_int(global.parameters, "rules.combat.herospeed", 10); } - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter * fig; - for (fig=s->fighters;fig;fig=fig->next) { - unit * u = fig->unit; + for (s = b->sides; s != b->sides + b->nsides; ++s) { + fighter *fig; + + for (fig = s->fighters; fig; fig = fig->next) { + unit *u = fig->unit; + if (fval(u, UFL_HERO)) { int i; + if (!playerrace(u->race)) { log_error(("Hero %s is a %s.\n", unitname(u), u->race->_name[0])); } - for (i=0;i!=u->number;++i) { - fig->person[i].speed += (hero_speed-1); + for (i = 0; i != u->number; ++i) { + fig->person[i].speed += (hero_speed - 1); } } } } } -static void -attack(battle *b, troop ta, const att *a, int numattack) +static void attack(battle * b, troop ta, const att * a, int numattack) { fighter *af = ta.fighter; + troop td; + unit *au = af->unit; - switch(a->type) { - case AT_COMBATSPELL: - /* Magier versuchen immer erstmal zu zaubern, erst wenn das - * fehlschlägt, wird af->magic == 0 und der Magier kämpft - * konventionell weiter */ - if (numattack==0 && af->magic > 0) { - /* wenn der magier in die potenzielle Reichweite von Attacken des - * Feindes kommt, beginnt er auch bei einem Status von KAEMPFE NICHT, - * Kampfzauber zu schleudern: */ - if (count_enemies(b, af, melee_range[0], missile_range[1], SELECT_ADVANCE|SELECT_DISTANCE|SELECT_FIND)) { - do_combatspell(ta); + switch (a->type) { + case AT_COMBATSPELL: + /* Magier versuchen immer erstmal zu zaubern, erst wenn das + * fehlschlägt, wird af->magic == 0 und der Magier kämpft + * konventionell weiter */ + if (numattack == 0 && af->magic > 0) { + /* wenn der magier in die potenzielle Reichweite von Attacken des + * Feindes kommt, beginnt er auch bei einem Status von KAEMPFE NICHT, + * Kampfzauber zu schleudern: */ + if (count_enemies(b, af, melee_range[0], missile_range[1], + SELECT_ADVANCE | SELECT_DISTANCE | SELECT_FIND)) { + do_combatspell(ta); + } } - } - break; - case AT_STANDARD: /* Waffen, mag. Gegenstände, Kampfzauber */ - if (numattack > 0 || af->magic <= 0) { - weapon * wp = ta.fighter->person[ta.index].missile; - int melee = count_enemies(b, af, melee_range[0], melee_range[1], SELECT_ADVANCE|SELECT_DISTANCE|SELECT_FIND); - if (melee) wp = preferred_weapon(ta, true); - /* Sonderbehandlungen */ + break; + case AT_STANDARD: /* Waffen, mag. Gegenstände, Kampfzauber */ + if (numattack > 0 || af->magic <= 0) { + weapon *wp = ta.fighter->person[ta.index].missile; - if (getreload(ta)) { - ta.fighter->person[ta.index].reload--; - } else { - boolean standard_attack = true; - boolean reload = false; - /* spezialattacken der waffe nur, wenn erste attacke in der runde. - * sonst helden mit feuerschwertern zu mächtig */ - if (numattack==0 && wp && wp->type->attack) { - int dead = 0; - standard_attack = wp->type->attack(&ta, wp->type, &dead); - if (!standard_attack) reload = true; - af->catmsg += dead; - if (!standard_attack && af->person[ta.index].last_action < b->turn) { - af->person[ta.index].last_action = b->turn; - combat_action(af, b->turn); - } - } - if (standard_attack) { - boolean missile = false; - if (wp && fval(wp->type, WTF_MISSILE)) missile = true; - if (missile) { - td = select_opponent(b, ta, missile_range[0], missile_range[1]); - } - else { - td = select_opponent(b, ta, melee_range[0], melee_range[1]); - } - if (!td.fighter) return; - if (ta.fighter->person[ta.index].last_action < b->turn) { - ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); - } - reload = true; - if (hits(ta, td, wp)) { - const char * d; - if (wp == NULL) d = au->race->def_damage; - else if (is_riding(ta)) d = wp->type->damage[1]; - else d = wp->type->damage[0]; - terminate(td, ta, a->type, d, missile); - } - } - if (reload && wp && wp->type->reload && !getreload(ta)) { - int i = setreload(ta); - if (bdebug) { - fprintf(bdebug, "%s/%d reloading %d turns\n", unitid(au), ta.index, i); - } - } - } - } - break; - case AT_SPELL: /* Extra-Sprüche. Kampfzauber in AT_COMBATSPELL! */ - do_extra_spell(ta, a); - break; - case AT_NATURAL: - td = select_opponent(b, ta, melee_range[0], melee_range[1]); - if (!td.fighter) return; - if(ta.fighter->person[ta.index].last_action < b->turn) { - ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); - } - if (hits(ta, td, NULL)) { - terminate(td, ta, a->type, a->data.dice, false); - } - break; - case AT_DRAIN_ST: - td = select_opponent(b, ta, melee_range[0], melee_range[1]); - if (!td.fighter) return; - if(ta.fighter->person[ta.index].last_action < b->turn) { - ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); - } - if (hits(ta, td, NULL)) { - int c = dice_rand(a->data.dice); - while(c > 0) { - if (rng_int()%2) { - td.fighter->person[td.index].attack -= 1; + int melee = + count_enemies(b, af, melee_range[0], melee_range[1], + SELECT_ADVANCE | SELECT_DISTANCE | SELECT_FIND); + if (melee) + wp = preferred_weapon(ta, true); + /* Sonderbehandlungen */ + + if (getreload(ta)) { + ta.fighter->person[ta.index].reload--; } else { - td.fighter->person[td.index].defence -= 1; + boolean standard_attack = true; + + boolean reload = false; + + /* spezialattacken der waffe nur, wenn erste attacke in der runde. + * sonst helden mit feuerschwertern zu mächtig */ + if (numattack == 0 && wp && wp->type->attack) { + int dead = 0; + + standard_attack = wp->type->attack(&ta, wp->type, &dead); + if (!standard_attack) + reload = true; + af->catmsg += dead; + if (!standard_attack && af->person[ta.index].last_action < b->turn) { + af->person[ta.index].last_action = b->turn; + combat_action(af, b->turn); + } + } + if (standard_attack) { + boolean missile = false; + + if (wp && fval(wp->type, WTF_MISSILE)) + missile = true; + if (missile) { + td = select_opponent(b, ta, missile_range[0], missile_range[1]); + } else { + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + } + if (!td.fighter) + return; + if (ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + reload = true; + if (hits(ta, td, wp)) { + const char *d; + + if (wp == NULL) + d = au->race->def_damage; + else if (is_riding(ta)) + d = wp->type->damage[1]; + else + d = wp->type->damage[0]; + terminate(td, ta, a->type, d, missile); + } + } + if (reload && wp && wp->type->reload && !getreload(ta)) { + int i = setreload(ta); + + if (bdebug) { + fprintf(bdebug, "%s/%d reloading %d turns\n", unitid(au), + ta.index, i); + } + } } - c--; } - } - break; - case AT_DRAIN_EXP: - td = select_opponent(b, ta, melee_range[0], melee_range[1]); - if (!td.fighter) return; - if(ta.fighter->person[ta.index].last_action < b->turn) { - ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); - } - if (hits(ta, td, NULL)) { - drain_exp(td.fighter->unit, dice_rand(a->data.dice)); - } - break; - case AT_DAZZLE: - td = select_opponent(b, ta, melee_range[0], melee_range[1]); - if (!td.fighter) return; - if(ta.fighter->person[ta.index].last_action < b->turn) { - ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); - } - if (hits(ta, td, NULL)) { - dazzle(b, &td); - } - break; - case AT_STRUCTURAL: - td = select_opponent(b, ta, melee_range[0], melee_range[1]); - if (!td.fighter) return; - if(ta.fighter->person[ta.index].last_action < b->turn) { - ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); - } - if (td.fighter->unit->ship) { - /* FIXME should use damage_ship here? */ - td.fighter->unit->ship->damage += DAMAGE_SCALE * dice_rand(a->data.dice); - } else if (td.fighter->unit->building) { - damage_building(b, td.fighter->unit->building, dice_rand(a->data.dice)); - } + break; + case AT_SPELL: /* Extra-Sprüche. Kampfzauber in AT_COMBATSPELL! */ + do_extra_spell(ta, a); + break; + case AT_NATURAL: + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + if (!td.fighter) + return; + if (ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + if (hits(ta, td, NULL)) { + terminate(td, ta, a->type, a->data.dice, false); + } + break; + case AT_DRAIN_ST: + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + if (!td.fighter) + return; + if (ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + if (hits(ta, td, NULL)) { + int c = dice_rand(a->data.dice); + + while (c > 0) { + if (rng_int() % 2) { + td.fighter->person[td.index].attack -= 1; + } else { + td.fighter->person[td.index].defence -= 1; + } + c--; + } + } + break; + case AT_DRAIN_EXP: + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + if (!td.fighter) + return; + if (ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + if (hits(ta, td, NULL)) { + drain_exp(td.fighter->unit, dice_rand(a->data.dice)); + } + break; + case AT_DAZZLE: + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + if (!td.fighter) + return; + if (ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + if (hits(ta, td, NULL)) { + dazzle(b, &td); + } + break; + case AT_STRUCTURAL: + td = select_opponent(b, ta, melee_range[0], melee_range[1]); + if (!td.fighter) + return; + if (ta.fighter->person[ta.index].last_action < b->turn) { + ta.fighter->person[ta.index].last_action = b->turn; + combat_action(ta.fighter, b->turn); + } + if (td.fighter->unit->ship) { + /* FIXME should use damage_ship here? */ + td.fighter->unit->ship->damage += + DAMAGE_SCALE * dice_rand(a->data.dice); + } else if (td.fighter->unit->building) { + damage_building(b, td.fighter->unit->building, dice_rand(a->data.dice)); + } } } -void -do_attack(fighter * af) +void do_attack(fighter * af) { troop ta; + unit *au = af->unit; + side *side = af->side; + battle *b = side->battle; ta.fighter = af; assert(au && au->number); /* Da das Zuschlagen auf Einheiten und nicht auf den einzelnen - * Kämpfern beruht, darf die Reihenfolge und Größe der Einheit keine - * Rolle spielen, Das tut sie nur dann, wenn jeder, der am Anfang der - * Runde lebte, auch zuschlagen darf. Ansonsten ist der, der zufällig - * mit einer großen Einheit zuerst drankommt, extrem bevorteilt. */ + * Kämpfern beruht, darf die Reihenfolge und Größe der Einheit keine + * Rolle spielen, Das tut sie nur dann, wenn jeder, der am Anfang der + * Runde lebte, auch zuschlagen darf. Ansonsten ist der, der zufällig + * mit einer großen Einheit zuerst drankommt, extrem bevorteilt. */ ta.index = af->fighting; while (ta.index--) { /* Wir suchen eine beliebige Feind-Einheit aus. An der können - * wir feststellen, ob noch jemand da ist. */ + * wir feststellen, ob noch jemand da ist. */ int apr, attacks = attacks_per_round(ta); - if (!count_enemies(b, af, FIGHT_ROW, LAST_ROW, SELECT_FIND)) break; - for (apr=0;apr!=attacks;++apr) { + if (!count_enemies(b, af, FIGHT_ROW, LAST_ROW, SELECT_FIND)) + break; + + for (apr = 0; apr != attacks; ++apr) { int a; - for (a=0; a!=10 && au->race->attack[a].type!=AT_NONE; ++a) { - if (apr>0) { + + for (a = 0; a != 10 && au->race->attack[a].type != AT_NONE; ++a) { + if (apr > 0) { /* Wenn die Waffe nachladen muss, oder es sich nicht um einen - * Waffen-Angriff handelt, dann gilt der Speed nicht. */ - if (au->race->attack[a].type!=AT_STANDARD) continue; + * Waffen-Angriff handelt, dann gilt der Speed nicht. */ + if (au->race->attack[a].type != AT_STANDARD) + continue; else { - weapon * wp = preferred_weapon(ta, true); - if (wp!=NULL && wp->type->reload) continue; + weapon *wp = preferred_weapon(ta, true); + + if (wp != NULL && wp->type->reload) + continue; } } attack(b, ta, &(au->race->attack[a]), apr); @@ -2273,32 +2531,32 @@ do_attack(fighter * af) } } /* Der letzte Katapultschütze setzt die - * Ladezeit neu und generiert die Meldung. */ - if (af->catmsg>=0) { - struct message * m = msg_message("battle::killed", "unit dead", au, af->catmsg); + * Ladezeit neu und generiert die Meldung. */ + if (af->catmsg >= 0) { + struct message *m = + msg_message("battle::killed", "unit dead", au, af->catmsg); message_all(b, m); msg_release(m); af->catmsg = -1; } } -void -do_regenerate(fighter *af) +void do_regenerate(fighter * af) { troop ta; + unit *au = af->unit; ta.fighter = af; ta.index = af->fighting; - while(ta.index--) { + while (ta.index--) { af->person[ta.index].hp += effskill(au, SK_STAMINA); af->person[ta.index].hp = MIN(unit_max_hp(au), af->person[ta.index].hp); } } -static void -add_tactics(tactics * ta, fighter * fig, int value) +static void add_tactics(tactics * ta, fighter * fig, int value) { if (value == 0 || value < ta->value) return; @@ -2313,41 +2571,56 @@ add_tactics(tactics * ta, fighter * fig, int value) static double horsebonus(const unit * u) { - static const item_type * it_horse = 0; - static const item_type * it_elvenhorse = 0; - static const item_type * it_charger = 0; - region * r = u->region; + static const item_type *it_horse = 0; + + static const item_type *it_elvenhorse = 0; + + static const item_type *it_charger = 0; + + region *r = u->region; + int n1 = 0, n2 = 0, n3 = 0; - item * itm = u->items; + + item *itm = u->items; + int skl = eff_skill(u, SK_RIDING, r); - if (skl<1) return 0.0; + if (skl < 1) + return 0.0; - if (it_horse==0) { + if (it_horse == 0) { it_horse = it_find("horse"); it_elvenhorse = it_find("elvenhorse"); it_charger = it_find("charger"); } - for (;itm;itm=itm->next) { - if (itm->type->flags&ITF_ANIMAL) { - if (itm->type==it_elvenhorse) n3 +=itm->number; - else if (itm->type==it_charger) n2 +=itm->number; - else if (itm->type==it_horse) n1 +=itm->number; + for (; itm; itm = itm->next) { + if (itm->type->flags & ITF_ANIMAL) { + if (itm->type == it_elvenhorse) + n3 += itm->number; + else if (itm->type == it_charger) + n2 += itm->number; + else if (itm->type == it_horse) + n1 += itm->number; } } - if (skl >= 5 && n3>=u->number) return 0.30; - if (skl >= 3 && n2+n3>=u->number) return 0.20; - if (skl >= 1 && n1+n2+n3>=u->number) return 0.10; + if (skl >= 5 && n3 >= u->number) + return 0.30; + if (skl >= 3 && n2 + n3 >= u->number) + return 0.20; + if (skl >= 1 && n1 + n2 + n3 >= u->number) + return 0.10; return 0.0F; } -double -fleechance(unit * u) +double fleechance(unit * u) { - double c = 0.20; /* Fluchtwahrscheinlichkeit in % */ - region * r = u->region; - attrib * a = a_find(u->attribs, &at_fleechance); + double c = 0.20; /* Fluchtwahrscheinlichkeit in % */ + + region *r = u->region; + + attrib *a = a_find(u->attribs, &at_fleechance); + /* Einheit u versucht, dem Getümmel zu entkommen */ c += (eff_skill(u, SK_STEALTH, r) * 0.05); @@ -2360,7 +2633,8 @@ fleechance(unit * u) c = MIN(c, 0.75); } - if (a!=NULL) c += a->data.flt; + if (a != NULL) + c += a->data.flt; return c; } @@ -2368,18 +2642,20 @@ fleechance(unit * u) /** add a new army to the conflict * beware: armies need to be added _at the beginning_ of the list because * otherwise join_allies() will get into trouble */ -static side * -make_side(battle * b, const faction * f, const group * g, unsigned int flags, const faction *stealthfaction) +static side *make_side(battle * b, const faction * f, const group * g, + unsigned int flags, const faction * stealthfaction) { - side *s1 = b->sides+b->nsides; - bfaction * bf; + side *s1 = b->sides + b->nsides; + + bfaction *bf; #ifdef SIMPLE_COMBAT if (fval(b->region->terrain, SEA_REGION)) { /* every fight in an ocean is short */ flags |= SIDE_HASGUARDS; } else { - unit * u; + unit *u; + for (u = b->region->units; u; u = u->next) { if (is_guard(u, HELP_ALL)) { if (alliedunit(u, f, HELP_GUARD)) { @@ -2395,8 +2671,8 @@ make_side(battle * b, const faction * f, const group * g, unsigned int flags, co s1->group = g; s1->flags = flags; s1->stealthfaction = stealthfaction; - for (bf = b->factions;bf;bf=bf->next) { - faction * f2 = bf->faction; + for (bf = b->factions; bf; bf = bf->next) { + faction *f2 = bf->faction; if (f2 == f) { s1->bf = bf; @@ -2404,7 +2680,7 @@ make_side(battle * b, const faction * f, const group * g, unsigned int flags, co s1->index = b->nsides++; s1->nextF = bf->sides; bf->sides = s1; - assert(b->nsides<=MAXSIDES); + assert(b->nsides <= MAXSIDES); break; } } @@ -2412,12 +2688,14 @@ make_side(battle * b, const faction * f, const group * g, unsigned int flags, co return s1; } -troop -select_ally(fighter * af, int minrow, int maxrow, int allytype) +troop select_ally(fighter * af, int minrow, int maxrow, int allytype) { side *as = af->side; + battle *b = as->battle; - side * ds; + + side *ds; + int allies = count_allies(as, minrow, maxrow, SELECT_ADVANCE, allytype); if (!allies) { @@ -2425,15 +2703,19 @@ select_ally(fighter * af, int minrow, int maxrow, int allytype) } allies = rng_int() % allies; - for (ds=b->sides;ds!=b->sides+b->nsides;++ds) { - if ((allytype==ALLY_ANY && helping(as, ds)) || (allytype==ALLY_SELF && as->faction==ds->faction)) { - fighter * df; - for (df=ds->fighters; df; df=df->next) { + for (ds = b->sides; ds != b->sides + b->nsides; ++ds) { + if ((allytype == ALLY_ANY && helping(as, ds)) || (allytype == ALLY_SELF + && as->faction == ds->faction)) { + fighter *df; + + for (df = ds->fighters; df; df = df->next) { int dr = get_unitrow(df, NULL); + if (dr >= minrow && dr <= maxrow) { if (df->alive - df->removed > allies) { troop dt; - assert(allies>=0); + + assert(allies >= 0); dt.index = allies; dt.fighter = df; return dt; @@ -2448,20 +2730,25 @@ select_ally(fighter * af, int minrow, int maxrow, int allytype) } -static int loot_quota(const unit * src, const unit * dst, const item_type * type, int n) +static int loot_quota(const unit * src, const unit * dst, + const item_type * type, int n) { static float divisor = -1; - if (dst && src && src->faction!=dst->faction) { - if (divisor<0) { + + if (dst && src && src->faction != dst->faction) { + if (divisor < 0) { divisor = get_param_flt(global.parameters, "rules.items.loot_divisor", 1); - assert(divisor==0 || divisor>=1); + + assert(divisor == 0 || divisor >= 1); } - if (divisor>=1) { + if (divisor >= 1) { double r = n / divisor; + int x = (int)r; r = r - x; - if (chance(r)) ++x; + if (chance(r)) + ++x; return x; } @@ -2469,46 +2756,56 @@ static int loot_quota(const unit * src, const unit * dst, const item_type * type return n; } -static void -loot_items(fighter * corpse) +static void loot_items(fighter * corpse) { - unit * u = corpse->unit; - item * itm = u->items; - battle * b = corpse->side->battle; + unit *u = corpse->unit; + + item *itm = u->items; + + battle *b = corpse->side->battle; + int dead = dead_fighters(corpse); - if (dead<=0) return; + if (dead <= 0) + return; while (itm) { - float lootfactor = dead/(float)u->number; /* only loot the dead! */ - int maxloot = (int)(itm->number*lootfactor); - if (maxloot>0) { - int i = MIN(10, maxloot); - for (; i != 0; --i) { - int loot = maxloot/i; + float lootfactor = dead / (float)u->number; /* only loot the dead! */ - if (loot>0) { + int maxloot = (int)(itm->number * lootfactor); + + if (maxloot > 0) { + int i = MIN(10, maxloot); + + for (; i != 0; --i) { + int loot = maxloot / i; + + if (loot > 0) { fighter *fig = NULL; + int looting = 0; + int maxrow = 0; + /* mustloot: we absolutely, positively must have somebody loot this thing */ - int mustloot = itm->type->flags & (ITF_CURSED|ITF_NOTLOST); + int mustloot = itm->type->flags & (ITF_CURSED | ITF_NOTLOST); itm->number -= loot; maxloot -= loot; if (is_monsters(u->faction) && (loot_rules & LOOT_MONSTERS)) { looting = 1; - } else if (loot_rules&LOOT_OTHERS) { + } else if (loot_rules & LOOT_OTHERS) { looting = 1; - } else if (loot_rules&LOOT_SELF) { + } else if (loot_rules & LOOT_SELF) { looting = 2; } if (looting) { if (mustloot) { maxrow = LAST_ROW; - } else if (loot_rules&LOOT_KEEPLOOT) { + } else if (loot_rules & LOOT_KEEPLOOT) { int lootchance = 50 + b->keeploot; + if (rng_int() % 100 < lootchance) { maxrow = BEHIND_ROW; } @@ -2516,8 +2813,8 @@ loot_items(fighter * corpse) maxrow = LAST_ROW; } } - if (maxrow>0) { - if (looting==1) { + if (maxrow > 0) { + if (looting == 1) { /* enemies get dibs */ fig = select_enemy(corpse, FIGHT_ROW, maxrow, 0).fighter; } @@ -2528,17 +2825,21 @@ loot_items(fighter * corpse) } if (fig) { - int trueloot = mustloot?loot:loot_quota(corpse->unit, fig->unit, itm->type, loot); - if (trueloot>0) { - item * l = fig->loot; - while (l && l->type!=itm->type) l=l->next; + int trueloot = + mustloot ? loot : loot_quota(corpse->unit, fig->unit, itm->type, + loot); + if (trueloot > 0) { + item *l = fig->loot; + + while (l && l->type != itm->type) + l = l->next; if (!l) { l = calloc(sizeof(item), 1); l->next = fig->loot; fig->loot = l; l->type = itm->type; } - l->number += trueloot; + l->number += trueloot; } } } @@ -2549,8 +2850,7 @@ loot_items(fighter * corpse) } #ifndef SIMPLE_ESCAPE -static void -loot_fleeing(fighter* fig, unit* runner) +static void loot_fleeing(fighter * fig, unit * runner) { /* TODO: Vernünftig fixen */ runner->items = NULL; @@ -2559,38 +2859,41 @@ loot_fleeing(fighter* fig, unit* runner) fig->run.items = NULL; } -static void -merge_fleeloot(fighter* fig, unit* u) +static void merge_fleeloot(fighter * fig, unit * u) { i_merge(&u->items, &fig->run.items); } #endif /* SIMPLE_ESCAPE */ -static boolean -seematrix(const faction * f, const side * s) +static boolean seematrix(const faction * f, const side * s) { - if (f==s->faction) return true; - if (s->flags & SIDE_STEALTH) return false; + if (f == s->faction) + return true; + if (s->flags & SIDE_STEALTH) + return false; return true; } -static double -PopulationDamage(void) +static double PopulationDamage(void) { static double value = -1.0; - if (value<0) { - int damage = get_param_int(global.parameters, "rules.combat.populationdamage", BATTLE_KILLS_PEASANTS); - value = damage/100.0; + + if (value < 0) { + int damage = + get_param_int(global.parameters, "rules.combat.populationdamage", + BATTLE_KILLS_PEASANTS); + value = damage / 100.0; } return value; } -static void -battle_effects(battle * b, int dead_players) +static void battle_effects(battle * b, int dead_players) { - region * r = b->region; - int dead_peasants = MIN(rpeasants(r), (int)(dead_players*PopulationDamage())); + region *r = b->region; + + int dead_peasants = + MIN(rpeasants(r), (int)(dead_players * PopulationDamage())); if (dead_peasants) { deathcounts(r, dead_peasants + dead_players); chaoscounts(r, dead_peasants / 2); @@ -2598,24 +2901,27 @@ battle_effects(battle * b, int dead_players) } } -static void -reorder_fleeing(region * r) +static void reorder_fleeing(region * r) { unit **usrc = &r->units; + unit **udst = &r->units; + unit *ufirst = NULL; + unit *u; - for (;*udst;udst=&u->next) { + for (; *udst; udst = &u->next) { u = *udst; } - for (u=*usrc;u!=ufirst;u=*usrc) { + for (u = *usrc; u != ufirst; u = *usrc) { if (u->next && fval(u, UFL_FLEEING)) { *usrc = u->next; *udst = u; udst = &u->next; - if (!ufirst) ufirst = u; + if (!ufirst) + ufirst = u; } else { usrc = &u->next; } @@ -2623,30 +2929,38 @@ reorder_fleeing(region * r) *udst = NULL; } -static void -aftermath(battle * b) +static void aftermath(battle * b) { int i; + region *r = b->region; + ship *sh; + side *s; + int dead_players = 0; - bfaction * bf; - boolean ships_damaged = (boolean)(b->turn+(b->has_tactics_turn?1:0)>2); /* only used for ship damage! */ - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter * df; - s->dead=0; + bfaction *bf; - for (df = s->fighters; df; df=df->next) { + boolean ships_damaged = (boolean) (b->turn + (b->has_tactics_turn ? 1 : 0) > 2); /* only used for ship damage! */ + + for (s = b->sides; s != b->sides + b->nsides; ++s) { + fighter *df; + + s->dead = 0; + + for (df = s->fighters; df; df = df->next) { unit *du = df->unit; + int dead = dead_fighters(df); + int pr_mercy = 0; /* Regeneration durch PR_MERCY */ - if (dead>0 && pr_mercy) { + if (dead > 0 && pr_mercy) { for (i = 0; i != dead; ++i) { - if (rng_int()%100 < pr_mercy) { + if (rng_int() % 100 < pr_mercy) { ++df->alive; ++s->alive; ++s->battle->alive; @@ -2664,7 +2978,9 @@ aftermath(battle * b) } #ifdef SHOW_KILLS if (df->hits + df->kills) { - struct message * m = msg_message("killsandhits", "unit hits kills", du, df->hits, df->kills); + struct message *m = + msg_message("killsandhits", "unit hits kills", du, df->hits, + df->kills); message_faction(b, du->faction, m); msg_release(m); } @@ -2675,18 +2991,23 @@ aftermath(battle * b) /* POSTCOMBAT */ do_combatmagic(b, DO_POSTCOMBATSPELL); - for (s=b->sides;s!=b->sides+b->nsides;++s) { + for (s = b->sides; s != b->sides + b->nsides; ++s) { int snumber = 0; + fighter *df; - boolean relevant = false; /* Kampf relevant für diese Partei? */ + + boolean relevant = false; /* Kampf relevant für diese Partei? */ + #ifdef SIMPLE_COMBAT - if (fval(s, SIDE_HASGUARDS) == 0) relevant = true; -#else - if (s->bf->lastturn>1) { + if (fval(s, SIDE_HASGUARDS) == 0) relevant = true; - } else if (s->bf->lastturn==1 && b->has_tactics_turn) { - side * stac; - for (stac=b->sides; stac; stac=stac->next) { +#else + if (s->bf->lastturn > 1) { + relevant = true; + } else if (s->bf->lastturn == 1 && b->has_tactics_turn) { + side *stac; + + for (stac = b->sides; stac; stac = stac->next) { if (stac->leader.value == b->max_tactics && helping(stac, s)) { relevant = true; break; @@ -2696,10 +3017,13 @@ aftermath(battle * b) #endif s->flee = 0; - for (df=s->fighters;df;df=df->next) { + for (df = s->fighters; df; df = df->next) { unit *du = df->unit; + int dead = dead_fighters(df); + int sum_hp = 0; + int n; for (n = 0; n != df->alive; ++n) { @@ -2710,23 +3034,29 @@ aftermath(battle * b) snumber += du->number; #ifdef SIMPLE_COMBAT if (relevant) { - int flags = UFL_LONGACTION|UFL_NOTMOVING; + int flags = UFL_LONGACTION | UFL_NOTMOVING; + #ifdef SIMPLE_ESCAPE - if (du->status==ST_FLEE) flags -= UFL_NOTMOVING; + if (du->status == ST_FLEE) + flags -= UFL_NOTMOVING; #endif /* SIMPLE_ESCAPE */ fset(du, flags); } - if (sum_hp+df->run.hphp) { + if (sum_hp + df->run.hp < du->hp) { /* someone on the ship got damaged, damage the ship */ - ship * sh = du->ship?du->ship:leftship(du); - if (sh) fset(sh, SF_DAMAGED); + ship *sh = du->ship ? du->ship : leftship(du); + + if (sh) + fset(sh, SF_DAMAGED); } #else if (relevant) { - fset(du, UFL_NOTMOVING); /* unit cannot move this round */ + fset(du, UFL_NOTMOVING); /* unit cannot move this round */ if (df->action_counter >= du->number) { - ship * sh = du->ship?du->ship:leftship(du); - if (sh) fset(sh, SF_DAMAGED); + ship *sh = du->ship ? du->ship : leftship(du); + + if (sh) + fset(sh, SF_DAMAGED); fset(du, UFL_LONGACTION); } } @@ -2734,21 +3064,21 @@ aftermath(battle * b) if (df->alive == du->number) { du->hp = sum_hp; - continue; /* nichts passiert */ + continue; /* nichts passiert */ } else if (df->run.hp) { if (df->alive == 0) { /* Report the casualties */ reportcasualties(b, df, dead); /* Zuerst dürfen die Feinde plündern, die mitgenommenen Items - * stehen in fig->run.items. Dann werden die Fliehenden auf - * die leere (tote) alte Einheit gemapt */ + * stehen in fig->run.items. Dann werden die Fliehenden auf + * die leere (tote) alte Einheit gemapt */ #ifdef SIMPLE_ESCAPE if (!fval(df, FIG_NOLOOT)) { loot_items(df); } #else - if (fval(df, FIG_NOLOOT)){ + if (fval(df, FIG_NOLOOT)) { merge_fleeloot(df, du); } else { loot_items(df); @@ -2761,14 +3091,14 @@ aftermath(battle * b) /* must leave ships or buildings, or a stealthy hobbit * can hold castles indefinitely */ if (!fval(r->terrain, SEA_REGION)) { - leave(du, true); /* even region owners have to flee */ + leave(du, true); /* even region owners have to flee */ } #ifndef SIMPLE_ESCAPE if (df->run.region) { run_to(du, df->run.region); df->run.region = du->region; } - fset(du, UFL_LONGACTION|UFL_NOTMOVING); + fset(du, UFL_LONGACTION | UFL_NOTMOVING); #endif /* SIMPLE_ESCAPE */ fset(du, UFL_FLEEING); } else { @@ -2783,7 +3113,7 @@ aftermath(battle * b) #endif /* SIMPLE_ESCAPE */ df->run.number = 0; df->run.hp = 0; - /* df->run.region = NULL;*/ + /* df->run.region = NULL; */ reportcasualties(b, df, dead); @@ -2791,7 +3121,7 @@ aftermath(battle * b) du->hp = sum_hp; } } else { - if (df->alive==0) { + if (df->alive == 0) { /* alle sind tot, niemand geflohen. Einheit auflösen */ df->run.number = 0; df->run.hp = 0; @@ -2821,32 +3151,34 @@ aftermath(battle * b) if (playerrace(du->race)) { /* tote im kampf werden zu regionsuntoten: - * for each of them, a peasant will die as well */ + * for each of them, a peasant will die as well */ dead_players += dead; } if (du->hp < du->number) { log_error(("%s has less hitpoints (%u) than people (%u)\n", - itoa36(du->no), du->hp, du->number)); + itoa36(du->no), du->hp, du->number)); du->hp = du->number; } } - s->alive+=s->healed; - assert(snumber==s->flee+s->alive+s->dead); + s->alive += s->healed; + assert(snumber == s->flee + s->alive + s->dead); } battle_effects(b, dead_players); - for (s=b->sides;s!=b->sides+b->nsides;++s) { - message * seen = msg_message("battle::army_report", + for (s = b->sides; s != b->sides + b->nsides; ++s) { + message *seen = msg_message("battle::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("battle::army_report", "index abbrev dead fled survived", army_index(s), "-?-", s->dead, s->flee, s->alive); - for (bf=b->factions;bf;bf=bf->next) { - faction * f = bf->faction; - message * m = seematrix(f, s)?seen:unseen; + for (bf = b->factions; bf; bf = bf->next) { + faction *f = bf->faction; + + message *m = seematrix(f, s) ? seen : unseen; message_faction(b, f, m); } @@ -2856,36 +3188,45 @@ aftermath(battle * b) } /* Wir benutzen drifted, um uns zu merken, ob ein Schiff - * schonmal Schaden genommen hat. (moved und drifted - * sollten in flags überführt werden */ + * schonmal Schaden genommen hat. (moved und drifted + * sollten in flags überführt werden */ - for (s=b->sides;s!=b->sides+b->nsides;++s) { + for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *df; - for (df=s->fighters; df; df=df->next) { + for (df = s->fighters; df; df = df->next) { unit *du = df->unit; - item * l; + + item *l; /* Beute verteilen */ - for (l=df->loot; l; l=l->next) { - const item_type * itype = l->type; - message * m = msg_message("battle_loot", "unit amount item", du, l->number, itype->rtype); + for (l = df->loot; l; l = l->next) { + const item_type *itype = l->type; + + message *m = + msg_message("battle_loot", "unit amount item", du, l->number, + itype->rtype); message_faction(b, du->faction, m); msg_release(m); i_change(&du->items, itype, l->number); } /* Wenn sich die Einheit auf einem Schiff befindet, wird - * dieses Schiff beschädigt. Andernfalls ein Schiff, welches - * evt. zuvor verlassen wurde. */ + * dieses Schiff beschädigt. Andernfalls ein Schiff, welches + * evt. zuvor verlassen wurde. */ if (ships_damaged) { - if (du->ship) sh = du->ship; - else sh = leftship(du); + if (du->ship) + sh = du->ship; + else + sh = leftship(du); if (sh && fval(sh, SF_DAMAGED)) { int n = b->turn - 2; - if (n>0) { - float dmg = get_param_flt(global.parameters, "rules.ship.damage.battleround", 0.05F); + + if (n > 0) { + float dmg = + get_param_flt(global.parameters, "rules.ship.damage.battleround", + 0.05F); damage_ship(sh, dmg * n); freset(sh, SF_DAMAGED); } @@ -2898,12 +3239,14 @@ aftermath(battle * b) ship **sp = &r->ships; while (*sp) { - ship * sh = *sp; + ship *sh = *sp; + freset(sh, SF_DAMAGED); if (sh->damage >= sh->size * DAMAGE_SCALE) { remove_ship(sp, sh); } - if (*sp==sh) sp=&sh->next; + if (*sp == sh) + sp = &sh->next; } } @@ -2912,18 +3255,18 @@ aftermath(battle * b) if (bdebug) { fprintf(bdebug, "The battle lasted %d turns, %s and %s.\n", b->turn, - b->has_tactics_turn?"had a tactic turn":"had no tactic turn", - ships_damaged?"was relevant":"was not relevant."); + b->has_tactics_turn ? "had a tactic turn" : "had no tactic turn", + ships_damaged ? "was relevant" : "was not relevant."); } } -static void -battle_punit(unit * u, battle * b) +static void battle_punit(unit * u, battle * b) { - bfaction * bf; + bfaction *bf; + strlist *S, *x; - for (bf = b->factions;bf;bf=bf->next) { + for (bf = b->factions; bf; bf = bf->next) { faction *f = bf->faction; S = 0; @@ -2940,70 +3283,80 @@ battle_punit(unit * u, battle * b) } } -static void -print_fighters(battle * b, const side * s) +static void print_fighters(battle * b, const side * s) { fighter *df; + int row; - for (row=1;row!=NUMROWS;++row) { - message * m = NULL; + for (row = 1; row != NUMROWS; ++row) { + message *m = NULL; - for (df=s->fighters; df; df=df->next) { + for (df = s->fighters; df; df = df->next) { unit *du = df->unit; + int thisrow = statusrow(df->unit->status); if (row == thisrow) { - if (m==NULL) { + if (m == NULL) { m = msg_message("battle::row_header", "row", row); message_all(b, m); } battle_punit(du, b); } } - if (m!=NULL) msg_release(m); + if (m != NULL) + msg_release(m); } } -boolean -is_attacker(const fighter * fig) +boolean is_attacker(const fighter * fig) { - return fval(fig, FIG_ATTACKER)!=0; + return fval(fig, FIG_ATTACKER) != 0; } -static void -set_attacker(fighter * fig) +static void set_attacker(fighter * fig) { fset(fig, FIG_ATTACKER); } -static void -print_header(battle * b) +static void print_header(battle * b) { - bfaction * bf; - char zText[32*MAXSIDES]; + bfaction *bf; + + char zText[32 * MAXSIDES]; + + for (bf = b->factions; bf; bf = bf->next) { + message *m; + + faction *f = bf->faction; + + const char *lastf = NULL; - for (bf=b->factions;bf;bf=bf->next) { - message * m; - faction * f = bf->faction; - const char * lastf = NULL; boolean first = false; - side * s; - char * bufp = zText; + + side *s; + + char *bufp = zText; + size_t size = sizeof(zText) - 1; + int bytes; - for (s=b->sides;s!=b->sides+b->nsides;++s) { + for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *df; - for (df=s->fighters;df;df=df->next) { + + for (df = s->fighters; df; df = df->next) { if (is_attacker(df)) { if (first) { bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } if (lastf) { bytes = (int)strlcpy(bufp, (const char *)lastf, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); first = true; } if (seematrix(f, s) == true) @@ -3016,15 +3369,19 @@ print_header(battle * b) } if (first) { bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, (const char *)LOC(f->locale, "and"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } if (lastf) { bytes = (int)strlcpy(bufp, (const char *)lastf, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } m = msg_message("battle::starters", "factions", zText); @@ -3033,26 +3390,36 @@ print_header(battle * b) } } -static void -print_stats(battle * b) +static void print_stats(battle * b) { side *s2; + side *s; + int i = 0; - for (s=b->sides;s!=b->sides+b->nsides;++s) { + + for (s = b->sides; s != b->sides + b->nsides; ++s) { bfaction *bf; ++i; - for (bf=b->factions;bf;bf=bf->next) { - faction * f = bf->faction; - const char * loc_army = LOC(f->locale, "battle_army"); - char * bufp; - const char * header; + for (bf = b->factions; bf; bf = bf->next) { + faction *f = bf->faction; + + const char *loc_army = LOC(f->locale, "battle_army"); + + char *bufp; + + const char *header; + size_t rsize, size; + int komma; - const char * sname = seematrix(f, s) ? sidename(s) : LOC(f->locale, "unknown_faction"); - message * msg; + + const char *sname = + seematrix(f, s) ? sidename(s) : LOC(f->locale, "unknown_faction"); + message *msg; + char buf[1024]; message_faction(b, f, msg_separator); @@ -3066,59 +3433,74 @@ print_stats(battle * b) komma = 0; header = LOC(f->locale, "battle_opponents"); - for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { + for (s2 = b->sides; s2 != b->sides + b->nsides; ++s2) { if (enemy(s2, s)) { - const char * abbrev = seematrix(f, s2)?sideabkz(s2, false):"-?-"; + const char *abbrev = seematrix(f, s2) ? sideabkz(s2, false) : "-?-"; + rsize = slprintf(bufp, size, "%s %s %d(%s)", - komma++ ? "," : (const char*)header, loc_army, army_index(s2), abbrev); - if (rsize>size) rsize = size-1; + komma++ ? "," : (const char *)header, loc_army, army_index(s2), + abbrev); + if (rsize > size) + rsize = size - 1; size -= rsize; bufp += rsize; } } - if (komma) fbattlerecord(b, f, buf); + if (komma) + fbattlerecord(b, f, buf); bufp = buf; size = sizeof(buf); komma = 0; header = LOC(f->locale, "battle_helpers"); - for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { + for (s2 = b->sides; s2 != b->sides + b->nsides; ++s2) { if (friendly(s2, s)) { - const char * abbrev = seematrix(f, s2)?sideabkz(s2, false):"-?-"; + const char *abbrev = seematrix(f, s2) ? sideabkz(s2, false) : "-?-"; + rsize = slprintf(bufp, size, "%s %s %d(%s)", - komma++ ? "," : (const char*)header, loc_army, army_index(s2), abbrev); - if (rsize>size) rsize = size-1; + komma++ ? "," : (const char *)header, loc_army, army_index(s2), + abbrev); + if (rsize > size) + rsize = size - 1; size -= rsize; bufp += rsize; } } - if (komma) fbattlerecord(b, f, buf); + if (komma) + fbattlerecord(b, f, buf); bufp = buf; size = sizeof(buf); komma = 0; header = LOC(f->locale, "battle_attack"); - for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { + for (s2 = b->sides; s2 != b->sides + b->nsides; ++s2) { if (s->relations[s2->index] & E_ATTACKING) { - const char * abbrev = seematrix(f, s2)?sideabkz(s2, false):"-?-"; - rsize = slprintf(bufp, size, "%s %s %d(%s)", komma++ ? "," : (const char*)header, loc_army, - army_index(s2), abbrev); - if (rsize>size) rsize = size-1; + const char *abbrev = seematrix(f, s2) ? sideabkz(s2, false) : "-?-"; + + rsize = + slprintf(bufp, size, "%s %s %d(%s)", + komma++ ? "," : (const char *)header, loc_army, army_index(s2), + abbrev); + if (rsize > size) + rsize = size - 1; size -= rsize; bufp += rsize; } } - if (komma) fbattlerecord(b, f, buf); + if (komma) + fbattlerecord(b, f, buf); } if (bdebug && s->faction) { if (f_get_alliance(s->faction)) { - fprintf(bdebug, "##### %s (%s/%d)\n", s->faction->name, itoa36(s->faction->no), - s->faction->alliance?s->faction->alliance->id:0); + fprintf(bdebug, "##### %s (%s/%d)\n", s->faction->name, + itoa36(s->faction->no), + s->faction->alliance ? s->faction->alliance->id : 0); } else { - fprintf(bdebug, "##### %s (%s)\n", s->faction->name, itoa36(s->faction->no)); + fprintf(bdebug, "##### %s (%s)\n", s->faction->name, + itoa36(s->faction->no)); } } print_fighters(b, s); @@ -3130,22 +3512,26 @@ print_stats(battle * b) b->max_tactics = 0; - for (s=b->sides;s!=b->sides+b->nsides;++s) { + for (s = b->sides; s != b->sides + b->nsides; ++s) { if (!ql_empty(s->leader.fighters)) { b->max_tactics = MAX(b->max_tactics, s->leader.value); } } if (b->max_tactics > 0) { - for (s=b->sides;s!=b->sides+b->nsides;++s) { + for (s = b->sides; s != b->sides + b->nsides; ++s) { if (s->leader.value == b->max_tactics) { quicklist *ql; + int qi; - for (qi=0,ql=s->leader.fighters;ql;ql_advance(&ql, &qi, 1)) { - fighter *tf = (fighter *)ql_get(ql, qi); + for (qi = 0, ql = s->leader.fighters; ql; ql_advance(&ql, &qi, 1)) { + fighter *tf = (fighter *) ql_get(ql, qi); + unit *u = tf->unit; - message * m = NULL; + + message *m = NULL; + if (!is_attacker(tf)) { m = msg_message("battle::tactics_lost", "unit", u); } else { @@ -3159,8 +3545,7 @@ print_stats(battle * b) } } -static int -weapon_weight(const weapon * w, boolean missile) +static int weapon_weight(const weapon * w, boolean missile) { if (missile == i2b(fval(w->type, WTF_MISSILE))) { return w->attackskill + w->defenseskill; @@ -3168,60 +3553,84 @@ weapon_weight(const weapon * w, boolean missile) return 0; } -fighter * -make_fighter(battle * b, unit * u, side * s1, boolean attack) +fighter *make_fighter(battle * b, unit * u, side * s1, boolean attack) { #define WMAX 20 weapon weapons[WMAX]; + int owp[WMAX]; + int dwp[WMAX]; + int w = 0; + region *r = b->region; - item * itm; + + item *itm; + fighter *fig = NULL; + int i, tactics = eff_skill(u, SK_TACTICS, r); + side *s2; + int h; + int berserk; + int strongmen; + int speeded = 0, speed = 1; + boolean pr_aid = false; + int rest; - const group * g = NULL; + + const group *g = NULL; + const attrib *a = a_find(u->attribs, &at_otherfaction); - const faction *stealthfaction = a?get_otherfaction(a):NULL; + + const faction *stealthfaction = a ? get_otherfaction(a) : NULL; + unsigned int flags = 0; + static int rule_anon_battle = -1; assert(u->number); - if (rule_anon_battle<0) { - rule_anon_battle = get_param_int(global.parameters, "rules.stealth.anon_battle", 1); + if (rule_anon_battle < 0) { + rule_anon_battle = + get_param_int(global.parameters, "rules.stealth.anon_battle", 1); } - if (fval(u, UFL_ANON_FACTION)!=0) flags |= SIDE_STEALTH; + if (fval(u, UFL_ANON_FACTION) != 0) + flags |= SIDE_STEALTH; if (!(AllianceAuto() & HELP_FIGHT) && fval(u, UFL_GROUP)) { - const attrib * agroup = a_find(u->attribs, &at_group); - if (agroup!=NULL) g = (const group*)agroup->data.v; + const attrib *agroup = a_find(u->attribs, &at_group); + + if (agroup != NULL) + g = (const group *)agroup->data.v; } /* Illusionen und Zauber kaempfen nicht */ - if (fval(u->race, RCF_ILLUSIONARY) || idle(u->faction) || u->number==0) { + if (fval(u->race, RCF_ILLUSIONARY) || idle(u->faction) || u->number == 0) { return NULL; } - if (s1==NULL) { - for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { - if (s2->faction == u->faction && s2->group==g) { + if (s1 == NULL) { + for (s2 = b->sides; s2 != b->sides + b->nsides; ++s2) { + if (s2->faction == u->faction && s2->group == g) { #ifdef SIMPLE_COMBAT - int s1flags = flags|SIDE_HASGUARDS; - int s2flags = s2->flags|SIDE_HASGUARDS; + int s1flags = flags | SIDE_HASGUARDS; + + int s2flags = s2->flags | SIDE_HASGUARDS; #else int s1flags = flags; + int s2flags = s2->flags; #endif - if (rule_anon_battle && s2->stealthfaction!=stealthfaction) { + if (rule_anon_battle && s2->stealthfaction != stealthfaction) { continue; } - if (s1flags==s2flags) { + if (s1flags == s2flags) { s1 = s2; break; } @@ -3235,7 +3644,7 @@ make_fighter(battle * b, unit * u, side * s1, boolean attack) s1->stealthfaction = NULL; } /* Zu diesem Zeitpunkt ist attacked noch 0, da die Einheit für noch - * keinen Kampf ausgewählt wurde (sonst würde ein fighter existieren) */ + * keinen Kampf ausgewählt wurde (sonst würde ein fighter existieren) */ } fig = calloc(1, sizeof(struct fighter)); @@ -3248,8 +3657,9 @@ make_fighter(battle * b, unit * u, side * s1, boolean attack) if (attack) { set_attacker(fig); } else { - building * b = u->building; - if (b && b->sizeleft>=u->number && playerrace(u->race)) { + building *b = u->building; + + if (b && b->sizeleft >= u->number && playerrace(u->race)) { fig->building = b; fig->building->sizeleft -= u->number; } @@ -3271,13 +3681,15 @@ make_fighter(battle * b, unit * u, side * s1, boolean attack) /* Effekte von Sprüchen */ { - static const curse_type * speed_ct; + static const curse_type *speed_ct; + speed_ct = ct_find("speed"); if (speed_ct) { curse *c = get_curse(u->attribs, speed_ct); + if (c) { speeded = get_cursedmen(u, c); - speed = curse_geteffect_int(c); + speed = curse_geteffect_int(c); } } } @@ -3310,7 +3722,7 @@ make_fighter(battle * b, unit * u, side * s1, boolean attack) fig->person[i].defence++; fig->person[i].damage++; fig->person[i].damage_rear++; - fig->person[i].flags |= FL_COURAGE; + fig->person[i].flags |= FL_COURAGE; } /* Leute mit Kraftzauber machen +2 Schaden im Nahkampf. */ if (i < strongmen) { @@ -3321,32 +3733,44 @@ make_fighter(battle * b, unit * u, side * s1, boolean attack) /* Für alle Waffengattungen wird bestimmt, wie viele der Personen mit * ihr kämpfen könnten, und was ihr Wert darin ist. */ if (u->race->battle_flags & BF_EQUIPMENT) { - int oi=0, di=0; - for (itm=u->items;itm && w!=WMAX;itm=itm->next) { - const weapon_type * wtype = resource2weapon(itm->type->rtype); - if (wtype==NULL || itm->number==0) continue; + int oi = 0, di = 0; + + for (itm = u->items; itm && w != WMAX; itm = itm->next) { + const weapon_type *wtype = resource2weapon(itm->type->rtype); + + if (wtype == NULL || itm->number == 0) + continue; weapons[w].attackskill = weapon_skill(wtype, u, true); weapons[w].defenseskill = weapon_skill(wtype, u, false); - if (weapons[w].attackskill>=0 || weapons[w].defenseskill>=0) { + if (weapons[w].attackskill >= 0 || weapons[w].defenseskill >= 0) { weapons[w].type = wtype; weapons[w].used = 0; weapons[w].count = itm->number; ++w; } - assert(w!=WMAX); + assert(w != WMAX); } - fig->weapons = (weapon *)calloc(sizeof(weapon), w+1); - memcpy(fig->weapons, weapons, w*sizeof(weapon)); + fig->weapons = (weapon *) calloc(sizeof(weapon), w + 1); + memcpy(fig->weapons, weapons, w * sizeof(weapon)); - for (i=0; i!=w; ++i) { - int j, o=0, d=0; - for (j=0; j!=i; ++j) { - if (weapon_weight(fig->weapons+j, true)>=weapon_weight(fig->weapons+i, true)) ++d; - if (weapon_weight(fig->weapons+j, false)>=weapon_weight(fig->weapons+i, false)) ++o; + for (i = 0; i != w; ++i) { + int j, o = 0, d = 0; + + for (j = 0; j != i; ++j) { + if (weapon_weight(fig->weapons + j, + true) >= weapon_weight(fig->weapons + i, true)) + ++d; + if (weapon_weight(fig->weapons + j, + false) >= weapon_weight(fig->weapons + i, false)) + ++o; } - for (j=i+1; j!=w; ++j) { - if (weapon_weight(fig->weapons+j, true)>weapon_weight(fig->weapons+i, true)) ++d; - if (weapon_weight(fig->weapons+j, false)>weapon_weight(fig->weapons+i, false)) ++o; + for (j = i + 1; j != w; ++j) { + if (weapon_weight(fig->weapons + j, + true) > weapon_weight(fig->weapons + i, true)) + ++d; + if (weapon_weight(fig->weapons + j, + false) > weapon_weight(fig->weapons + i, false)) + ++o; } owp[o] = i; dwp[d] = i; @@ -3356,25 +3780,32 @@ make_fighter(battle * b, unit * u, side * s1, boolean attack) * owp, dwp contain indices to the figther::weapons array */ /* hand out melee weapons: */ - for (i=0; i!=fig->alive; ++i) { + for (i = 0; i != fig->alive; ++i) { int wpless = weapon_skill(NULL, u, true); - while (oi!=w && (fig->weapons[owp[oi]].used==fig->weapons[owp[oi]].count || fval(fig->weapons[owp[oi]].type, WTF_MISSILE))) { + + while (oi != w + && (fig->weapons[owp[oi]].used == fig->weapons[owp[oi]].count + || fval(fig->weapons[owp[oi]].type, WTF_MISSILE))) { ++oi; } - if (oi==w) break; /* no more weapons available */ - if (weapon_weight(fig->weapons+owp[oi], false)<=wpless) { - continue; /* we fight better with bare hands */ + if (oi == w) + break; /* no more weapons available */ + if (weapon_weight(fig->weapons + owp[oi], false) <= wpless) { + continue; /* we fight better with bare hands */ } fig->person[i].melee = &fig->weapons[owp[oi]]; ++fig->weapons[owp[oi]].used; } /* hand out missile weapons (from back to front, in case of mixed troops). */ - for (di=0, i=fig->alive; i--!=0;) { - while (di!=w && (fig->weapons[dwp[di]].used==fig->weapons[dwp[di]].count || !fval(fig->weapons[dwp[di]].type, WTF_MISSILE))) { + for (di = 0, i = fig->alive; i-- != 0;) { + while (di != w + && (fig->weapons[dwp[di]].used == fig->weapons[dwp[di]].count + || !fval(fig->weapons[dwp[di]].type, WTF_MISSILE))) { ++di; } - if (di==w) break; /* no more weapons available */ - if (weapon_weight(fig->weapons+dwp[di], true)>0) { + if (di == w) + break; /* no more weapons available */ + if (weapon_weight(fig->weapons + dwp[di], true) > 0) { fig->person[i].missile = &fig->weapons[dwp[di]]; ++fig->weapons[dwp[di]].used; } @@ -3391,8 +3822,9 @@ make_fighter(battle * b, unit * u, side * s1, boolean attack) fig->horses = fig->unit->number; fig->elvenhorses = 0; } else { - static const item_type * it_charger = 0; - if (it_charger==0) { + static const item_type *it_charger = 0; + + if (it_charger == 0) { it_charger = it_find("charger"); if (!it_charger) { it_charger = it_find("horse"); @@ -3403,14 +3835,16 @@ make_fighter(battle * b, unit * u, side * s1, boolean attack) } if (u->race->battle_flags & BF_EQUIPMENT) { - for (itm=u->items; itm; itm=itm->next) { + for (itm = u->items; itm; itm = itm->next) { if (itm->type->rtype->atype) { if (i_canuse(u, itm->type)) { - struct armor * adata = malloc(sizeof(armor)), **aptr; + struct armor *adata = malloc(sizeof(armor)), **aptr; + adata->atype = itm->type->rtype->atype; adata->count = itm->number; - for (aptr=&fig->armors;*aptr;aptr=&(*aptr)->next) { - if (adata->atype->prot > (*aptr)->atype->prot) break; + for (aptr = &fig->armors; *aptr; aptr = &(*aptr)->next) { + if (adata->atype->prot > (*aptr)->atype->prot) + break; } adata->next = *aptr; *aptr = adata; @@ -3430,18 +3864,20 @@ make_fighter(battle * b, unit * u, side * s1, boolean attack) if (fig->horses) { if (!fval(r->terrain, CAVALRY_REGION) || r_isforest(r) - || eff_skill(u, SK_RIDING, r) < CavalrySkill() || u->race == new_race[RC_TROLL] || fval(u, UFL_WERE)) + || eff_skill(u, SK_RIDING, r) < CavalrySkill() + || u->race == new_race[RC_TROLL] || fval(u, UFL_WERE)) fig->horses = 0; } if (fig->elvenhorses) { - if (eff_skill(u, SK_RIDING, r) < 5 || u->race == new_race[RC_TROLL] || fval(u, UFL_WERE)) + if (eff_skill(u, SK_RIDING, r) < 5 || u->race == new_race[RC_TROLL] + || fval(u, UFL_WERE)) fig->elvenhorses = 0; } /* Schauen, wie gut wir in Taktik sind. */ if (tactics > 0 && u->race == new_race[RC_INSECT]) - tactics -= 1 - (int) log10(fig->side->size[SUM_ROW]); + tactics -= 1 - (int)log10(fig->side->size[SUM_ROW]); #ifdef TACTICS_MODIFIER if (tactics > 0 && statusrow(fig->status) == FIGHT_ROW) tactics += TACTICS_MODIFIER; @@ -3455,17 +3891,18 @@ make_fighter(battle * b, unit * u, side * s1, boolean attack) for (i = 0; i < fig->alive; i++) { int p_bonus = 0; + int rnd; do { - rnd = rng_int()%100; + rnd = rng_int() % 100; if (rnd >= 40 && rnd <= 69) p_bonus += 1; else if (rnd <= 89) p_bonus += 2; else p_bonus += 3; - } while(rnd >= 97); + } while (rnd >= 97); bonus = MAX(p_bonus, bonus); } tactics += bonus; @@ -3477,26 +3914,28 @@ make_fighter(battle * b, unit * u, side * s1, boolean attack) } -static int -join_battle(battle * b, unit * u, boolean attack, fighter ** cp) +static int join_battle(battle * b, unit * u, boolean attack, fighter ** cp) { - side * s; + side *s; + fighter *c = NULL; if (!attack) { - attrib * a = a_find(u->attribs, &at_fleechance); - if (a!=NULL) { - if (rng_double()<=a->data.flt) { + attrib *a = a_find(u->attribs, &at_fleechance); + + if (a != NULL) { + if (rng_double() <= a->data.flt) { *cp = NULL; return false; } } } - for (s=b->sides;s!=b->sides+b->nsides;++s) { + for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *fig; - if (s->faction==u->faction) { - for (fig=s->fighters;fig;fig=fig->next) { + + if (s->faction == u->faction) { + for (fig = s->fighters; fig; fig = fig->next) { if (fig->unit == u) { c = fig; if (attack) { @@ -3509,52 +3948,64 @@ join_battle(battle * b, unit * u, boolean attack, fighter ** cp) } if (!c) { *cp = make_fighter(b, u, NULL, attack); - return *cp!=NULL; + return *cp != NULL; } *cp = c; return false; } -static const char * -simplename(region * r) +static const char *simplename(region * r) { int i; + static char name[17]; - const char * cp = rname(r, default_locale); - for (i=0;*cp && i!=16;++i, ++cp) { + + const char *cp = rname(r, default_locale); + + for (i = 0; *cp && i != 16; ++i, ++cp) { int c = *(unsigned char *)cp; + while (c && !isalpha(c) && !isxspace(c)) { ++cp; - c = *(unsigned char*)cp; + c = *(unsigned char *)cp; } - if (isxspace(c)) name[i] = '_'; - else name[i] = *cp; - if (c==0) break; + if (isxspace(c)) + name[i] = '_'; + else + name[i] = *cp; + if (c == 0) + break; } - name[i]=0; + name[i] = 0; return name; } -static battle * -make_battle(region * r) +static battle *make_battle(region * r) { battle *b = calloc(1, sizeof(struct battle)); + unit *u; - bfaction * bf; - static int max_fac_no = 0; /* need this only once */ + + bfaction *bf; + + static int max_fac_no = 0; /* need this only once */ if (battledebug) { char zText[MAX_PATH]; + char zFilename[MAX_PATH]; + sprintf(zText, "%s/battles", basepath()); os_mkdir(zText, 0700); sprintf(zFilename, "%s/battle-%d-%s.log", zText, obs_count, simplename(r)); bdebug = fopen(zFilename, "w"); - if (!bdebug) log_error(("battles cannot be debugged\n")); + if (!bdebug) + log_error(("battles cannot be debugged\n")); else { const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; fwrite(utf8_bom, 1, 3, bdebug); - fprintf(bdebug, "In %s findet ein Kampf stattactics:\n", rname(r, default_locale)); + fprintf(bdebug, "In %s findet ein Kampf stattactics:\n", rname(r, + default_locale)); } obs_count++; } @@ -3562,12 +4013,13 @@ make_battle(region * r) b->region = r; b->plane = getplane(r); /* Finde alle Parteien, die den Kampf beobachten können: */ - for (u = r->units; u; u=u->next) { + for (u = r->units; u; u = u->next) { if (u->number > 0) { if (!fval(u->faction, FFL_MARK)) { fset(u->faction, FFL_MARK); - for (bf=b->factions;bf;bf=bf->next) { - if (bf->faction==u->faction) break; + for (bf = b->factions; bf; bf = bf->next) { + if (bf->faction == u->faction) + break; } if (!bf) { bf = calloc(sizeof(bfaction), 1); @@ -3580,28 +4032,28 @@ make_battle(region * r) } } - for (bf=b->factions;bf;bf=bf->next) { - faction * f = bf->faction; + for (bf = b->factions; bf; bf = bf->next) { + faction *f = bf->faction; + max_fac_no = MAX(max_fac_no, f->no); freset(f, FFL_MARK); } return b; } -static void -free_side(side * si) +static void free_side(side * si) { ql_free(si->leader.fighters); } -static void -free_fighter(fighter * fig) +static void free_fighter(fighter * fig) { while (fig->loot) { i_free(i_remove(&fig->loot, fig->loot)); } while (fig->armors) { - armor * a = fig->armors; + armor *a = fig->armors; + fig->armors = a->next; free(a); } @@ -3610,10 +4062,10 @@ free_fighter(fighter * fig) } -static void -free_battle(battle * b) +static void free_battle(battle * b) { side *s; + int max_fac_no = 0; if (bdebug) { @@ -3621,17 +4073,21 @@ free_battle(battle * b) } while (b->factions) { - bfaction * bf = b->factions; - faction * f = bf->faction; + bfaction *bf = b->factions; + + faction *f = bf->faction; + b->factions = bf->next; max_fac_no = MAX(max_fac_no, f->no); free(bf); } - for (s=b->sides;s!=b->sides+b->nsides;++s) { + for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *fnext = s->fighters; + while (fnext) { fighter *fig = fnext; + fnext = fig->next; free_fighter(fig); free(fig); @@ -3643,16 +4099,18 @@ free_battle(battle * b) ql_free(b->meffects); } -static int * -get_alive(side * s) +static int *get_alive(side * s) { #if 0 static int alive[NUMROWS]; + fighter *fig; + memset(alive, 0, NUMROWS * sizeof(int)); - for (fig=s->fighters;fig;fig=fig->next) { - if (fig->alive>0) { + for (fig = s->fighters; fig; fig = fig->next) { + if (fig->alive > 0) { int row = statusrow(fig); + alive[row] += fig->alive; } } @@ -3661,82 +4119,103 @@ get_alive(side * s) return s->size; } -static int -battle_report(battle * b) +static int battle_report(battle * b) { side *s, *s2; + boolean cont = false; + boolean komma; + bfaction *bf; - for (s=b->sides;s!=b->sides+b->nsides;++s) { - if (s->alive-s->removed > 0) { - for (s2=b->sides;s2!=b->sides+b->nsides;++s2) { - if (s2->alive-s2->removed > 0 && enemy(s, s2)) { + for (s = b->sides; s != b->sides + b->nsides; ++s) { + if (s->alive - s->removed > 0) { + for (s2 = b->sides; s2 != b->sides + b->nsides; ++s2) { + if (s2->alive - s2->removed > 0 && enemy(s, s2)) { cont = true; break; } } - if (cont) break; + if (cont) + break; } } - if (verbosity>0) log_stdio(stdout, " %d", b->turn); + if (verbosity > 0) + log_stdio(stdout, " %d", b->turn); fflush(stdout); - for (bf=b->factions;bf;bf=bf->next) { - faction * fac = bf->faction; - char buf[32*MAXSIDES]; - char * bufp = buf; + for (bf = b->factions; bf; bf = bf->next) { + faction *fac = bf->faction; + + char buf[32 * MAXSIDES]; + + char *bufp = buf; + int bytes; + size_t size = sizeof(buf) - 1; - message * m; + + message *m; message_faction(b, fac, msg_separator); - if (cont) m = msg_message("battle::lineup", "turn", b->turn); - else m = msg_message("battle::after", ""); + if (cont) + m = msg_message("battle::lineup", "turn", b->turn); + else + m = msg_message("battle::after", ""); message_faction(b, fac, m); msg_release(m); - komma = false; - for (s=b->sides;s!=b->sides+b->nsides;++s) { + komma = false; + for (s = b->sides; s != b->sides + b->nsides; ++s) { if (s->alive) { - int r, k = 0, * alive = get_alive(s); + int r, k = 0, *alive = get_alive(s); + int l = FIGHT_ROW; - const char * abbrev = seematrix(fac, s)?sideabkz(s, false):"-?-"; - const char * loc_army = LOC(fac->locale, "battle_army"); + + const char *abbrev = seematrix(fac, s) ? sideabkz(s, false) : "-?-"; + + const char *loc_army = LOC(fac->locale, "battle_army"); + char buffer[32]; if (komma) { bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } snprintf(buffer, sizeof(buffer), "%s %2d(%s): ", loc_army, army_index(s), abbrev); - buffer[sizeof(buffer)-1] = 0; + buffer[sizeof(buffer) - 1] = 0; bytes = (int)strlcpy(bufp, buffer, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); - for (r=FIGHT_ROW;r!=NUMROWS;++r) { + for (r = FIGHT_ROW; r != NUMROWS; ++r) { if (alive[r]) { - if (l!=FIGHT_ROW) { + if (l != FIGHT_ROW) { bytes = (int)strlcpy(bufp, "+", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } while (k--) { bytes = (int)strlcpy(bufp, "0+", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } sprintf(buffer, "%d", alive[r]); bytes = (int)strlcpy(bufp, buffer, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); k = 0; - l = r+1; - } else ++k; + l = r + 1; + } else + ++k; } komma = true; @@ -3748,81 +4227,93 @@ battle_report(battle * b) return cont; } -static void -join_allies(battle * b) +static void join_allies(battle * b) { region *r = b->region; + unit *u; - side *s, *s_end = b->sides+b->nsides; + + side *s, *s_end = b->sides + b->nsides; + /* make_side might be adding a new faction, but it adds them to the end * of the list, so we're safe in our iteration here if we remember the end * up front. */ - for (u=r->units;u;u=u->next) { + for (u = r->units; u; u = u->next) { /* Was ist mit Schiffen? */ - if (u->status != ST_FLEE && u->status != ST_AVOID && !fval(u, UFL_LONGACTION|UFL_ISNEW) && u->number > 0) { - faction * f = u->faction; - fighter * c = NULL; + if (u->status != ST_FLEE && u->status != ST_AVOID + && !fval(u, UFL_LONGACTION | UFL_ISNEW) && u->number > 0) { + faction *f = u->faction; + + fighter *c = NULL; + + for (s = b->sides; s != s_end; ++s) { + side *se; - for (s=b->sides;s!=s_end;++s) { - side * se; /* Wenn alle attackierten noch FFL_NOAID haben, dann kämpfe nicht mit. */ - if (fval(s->faction, FFL_NOAID)) continue; - if (s->faction!=f) { + if (fval(s->faction, FFL_NOAID)) + continue; + if (s->faction != f) { /* Wenn wir attackiert haben, kommt niemand mehr hinzu: */ - if (s->bf->attacker) continue; + if (s->bf->attacker) + continue; /* alliiert müssen wir schon sein, sonst ist's eh egal : */ - if (!alliedunit(u, s->faction, HELP_FIGHT)) continue; + if (!alliedunit(u, s->faction, HELP_FIGHT)) + continue; /* wenn die partei verborgen ist, oder gar eine andere - * vorgespiegelt wird, und er sich uns gegenüber nicht zu - * erkennen gibt, helfen wir ihm nicht */ - if (s->stealthfaction){ - if(!allysfm(s, u->faction, HELP_FSTEALTH)) { + * vorgespiegelt wird, und er sich uns gegenüber nicht zu + * erkennen gibt, helfen wir ihm nicht */ + if (s->stealthfaction) { + if (!allysfm(s, u->faction, HELP_FSTEALTH)) { continue; } } } /* einen alliierten angreifen dürfen sie nicht, es sei denn, der - * ist mit einem alliierten verfeindet, der nicht attackiert - * hat: */ - for (se=b->sides;se!=s_end;++se) { - if (u->faction==se->faction) continue; + * ist mit einem alliierten verfeindet, der nicht attackiert + * hat: */ + for (se = b->sides; se != s_end; ++se) { + if (u->faction == se->faction) + continue; if (alliedunit(u, se->faction, HELP_FIGHT) && !se->bf->attacker) { continue; } - if (enemy(s, se)) break; + if (enemy(s, se)) + break; } - if (se==s_end) continue; + if (se == s_end) + continue; /* Wenn die Einheit belagert ist, muß auch einer der Alliierten belagert sein: */ if (besieged(u)) { fighter *ally; - for (ally = s->fighters; ally; ally=ally->next) { + + for (ally = s->fighters; ally; ally = ally->next) { if (besieged(ally->unit)) { break; } } - if (ally==NULL) continue; + if (ally == NULL) + continue; } /* keine Einwände, also soll er mitmachen: */ - if (c==NULL) { + if (c == NULL) { if (join_battle(b, u, false, &c)) { if (battledebug) { fprintf(bdebug, "%s joins to help %s against %s.\n", - unitname(u), factionname(s->faction), - factionname(se->faction)); + unitname(u), factionname(s->faction), factionname(se->faction)); } - } else if (c==NULL) { + } else if (c == NULL) { continue; } } /* the enemy of my friend is my enemy: */ - for (se=b->sides;se!=s_end;++se) { - if (se->faction!=u->faction && enemy(s, se)) { + for (se = b->sides; se != s_end; ++se) { + if (se->faction != u->faction && enemy(s, se)) { if (set_enemy(se, c->side, false) && battledebug) { - fprintf(bdebug, "%u/%s hates %u/%s because they are enemies with %u/%s.\n", - c->side->index, sidename(c->side), - se->index, sidename(se), - s->index, sidename(s)); + fprintf(bdebug, + "%u/%s hates %u/%s because they are enemies with %u/%s.\n", + c->side->index, sidename(c->side), se->index, sidename(se), + s->index, sidename(s)); } } } @@ -3830,50 +4321,63 @@ join_allies(battle * b) } } - for (s=b->sides;s!=b->sides+b->nsides;++s) { + for (s = b->sides; s != b->sides + b->nsides; ++s) { int si; - side * sa; - faction * f = s->faction; + + side *sa; + + faction *f = s->faction; /* Den Feinden meiner Feinde gebe ich Deckung (gegen gemeinsame Feinde): */ - for (si=0; s->enemies[si]; ++si) { - side * se = s->enemies[si]; + for (si = 0; s->enemies[si]; ++si) { + side *se = s->enemies[si]; + int ai; - for (ai=0; se->enemies[ai]; ++ai) { - side * as = se->enemies[ai]; - if (as==s || !enemy(as, s)) { + + for (ai = 0; se->enemies[ai]; ++ai) { + side *as = se->enemies[ai]; + + if (as == s || !enemy(as, s)) { set_friendly(as, s); } } } - for (sa=s+1;sa!=b->sides+b->nsides;++sa) { - plane * pl = rplane(r); - if (enemy(s, sa)) continue; - if (friendly(s, sa)) continue; - if (!alliedgroup(pl, f, sa->faction, f->allies, HELP_FIGHT)) continue; - if (!alliedgroup(pl, sa->faction, f, sa->faction->allies, HELP_FIGHT)) continue; + for (sa = s + 1; sa != b->sides + b->nsides; ++sa) { + plane *pl = rplane(r); + + if (enemy(s, sa)) + continue; + if (friendly(s, sa)) + continue; + if (!alliedgroup(pl, f, sa->faction, f->allies, HELP_FIGHT)) + continue; + if (!alliedgroup(pl, sa->faction, f, sa->faction->allies, HELP_FIGHT)) + continue; set_friendly(s, sa); } } } -static void -flee(const troop dt) +static void flee(const troop dt) { - fighter * fig = dt.fighter; - unit * u = fig->unit; + fighter *fig = dt.fighter; + + unit *u = fig->unit; #ifndef SIMPLE_ESCAPE int carry = personcapacity(u) - u->race->weight; + int money; - item ** ip = &u->items; + item **ip = &u->items; while (*ip) { - item * itm = *ip; - const item_type * itype = itm->type; + item *itm = *ip; + + const item_type *itype = itm->type; + int keep = 0; if (fval(itype, ITF_ANIMAL)) { @@ -3888,22 +4392,25 @@ flee(const troop dt) keep = itm->number; } /* jeder troop nimmt seinen eigenen Teil der Sachen mit */ - if (keep>0){ - if (itm->number==keep) { + if (keep > 0) { + if (itm->number == keep) { i_add(&fig->run.items, i_remove(ip, itm)); } else { item *run_itm = i_new(itype, keep); + i_add(&fig->run.items, run_itm); i_change(ip, itype, -keep); } } - if (*ip==itm) ip = &itm->next; + if (*ip == itm) + ip = &itm->next; } /* we will take money with us */ money = get_money(u); /* nur ganzgeflohene/resttote Einheiten verlassen die Region */ - if (money > carry) money = carry; + if (money > carry) + money = carry; if (money > 0) { i_change(&u->items, i_silver, -money); i_change(&fig->run.items, i_silver, +money); @@ -3918,22 +4425,25 @@ flee(const troop dt) kill_troop(dt); } -static boolean -init_battle(region * r, battle **bp) +static boolean init_battle(region * r, battle ** bp) { - battle * b = NULL; - unit * u; + battle *b = NULL; + + unit *u; + boolean fighting = false; /* list_foreach geht nicht, wegen flucht */ for (u = r->units; u != NULL; u = u->next) { - if (fval(u, UFL_LONGACTION)) continue; + if (fval(u, UFL_LONGACTION)) + continue; if (u->number > 0) { - order * ord; + order *ord; - for (ord=u->orders;ord;ord=ord->next) { + for (ord = u->orders; ord; ord = ord->next) { static boolean init = false; - static const curse_type * peace_ct, * slave_ct, * calm_ct; + + static const curse_type *peace_ct, *slave_ct, *calm_ct; if (!init) { init = true; @@ -3943,17 +4453,21 @@ init_battle(region * r, battle **bp) } if (get_keyword(ord) == K_ATTACK) { unit *u2; + fighter *c1, *c2; - ship * lsh = NULL; - plane * pl = rplane(r); + + ship *lsh = NULL; + + plane *pl = rplane(r); if (pl && fval(pl, PFL_NOATTACK)) { cmistake(u, ord, 271, MSG_BATTLE); continue; } - if ((u->race->battle_flags&BF_CANATTACK) == 0) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_no_attack", "race", u->race)); + if ((u->race->battle_flags & BF_CANATTACK) == 0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_no_attack", + "race", u->race)); continue; } /** @@ -3970,7 +4484,8 @@ init_battle(region * r, battle **bp) } /* ist ein Flüchtling aus einem andern Kampf */ - if (fval(u, UFL_LONGACTION)) continue; + if (fval(u, UFL_LONGACTION)) + continue; if (peace_ct && curse_active(get_curse(r->attribs, peace_ct))) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "peace_active", "")); @@ -3982,7 +4497,8 @@ init_battle(region * r, battle **bp) continue; } - if ((u->ship != NULL && !fval(r->terrain, SEA_REGION)) || (lsh = leftship(u))!=NULL) { + if ((u->ship != NULL && !fval(r->terrain, SEA_REGION)) + || (lsh = leftship(u)) != NULL) { if (is_guarded(r, u, GUARD_TRAVELTHRU)) { if (lsh) { cmistake(u, ord, 234, MSG_BATTLE); @@ -4004,7 +4520,8 @@ init_battle(region * r, battle **bp) /* Beginn Fehlerbehandlung */ /* Fehler: "Die Einheit wurde nicht gefunden" */ if (!u2 || u2->number == 0 || !cansee(u->faction, u->region, u2, 0)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, + "feedback_unit_not_found", "")); continue; } /* Fehler: "Die Einheit ist eine der unsrigen" */ @@ -4019,17 +4536,22 @@ init_battle(region * r, battle **bp) } if (IsImmune(u2->faction)) { add_message(&u->faction->msgs, - msg_feedback(u, u->thisorder, "newbie_immunity_error", "turns", NewbieImmunity())); + msg_feedback(u, u->thisorder, "newbie_immunity_error", "turns", + NewbieImmunity())); continue; } /* Fehler: "Die Einheit ist mit uns alliert" */ if (calm_ct) { - attrib * a = a_find(u->attribs, &at_curse); + attrib *a = a_find(u->attribs, &at_curse); + boolean calm = false; - while (a && a->type==&at_curse) { - curse * c = (curse *)a->data.v; - if (c->type==calm_ct && curse_geteffect(c)==u2->faction->subscription) { + + while (a && a->type == &at_curse) { + curse *c = (curse *) a->data.v; + + if (c->type == calm_ct + && curse_geteffect(c) == u2->faction->subscription) { if (curse_active(c)) { calm = true; break; @@ -4043,9 +4565,10 @@ init_battle(region * r, battle **bp) } } /* Ende Fehlerbehandlung */ - if (b==NULL) { - unit * utmp; - for (utmp=r->units; utmp!=NULL; utmp=utmp->next) { + if (b == NULL) { + unit *utmp; + + for (utmp = r->units; utmp != NULL; utmp = utmp->next) { fset(utmp->faction, FFL_NOAID); } b = make_battle(r); @@ -4053,24 +4576,25 @@ init_battle(region * r, battle **bp) if (join_battle(b, u, true, &c1)) { if (battledebug) { fprintf(bdebug, "%s joins by attacking %s.\n", - unitname(u), unitname(u2)); + unitname(u), unitname(u2)); } } if (join_battle(b, u2, false, &c2)) { if (battledebug) { fprintf(bdebug, "%s joins because of an attack from %s.\n", - unitname(u2), unitname(u)); + unitname(u2), unitname(u)); } } /* Hat die attackierte Einheit keinen Noaid-Status, - * wird das Flag von der Faction genommen, andere - * Einheiten greifen ein. */ - if (!fval(u2, UFL_NOAID)) freset(u2->faction, FFL_NOAID); + * wird das Flag von der Faction genommen, andere + * Einheiten greifen ein. */ + if (!fval(u2, UFL_NOAID)) + freset(u2->faction, FFL_NOAID); - if (c1!=NULL && c2!=NULL) { + if (c1 != NULL && c2 != NULL) { /* Merken, wer Angreifer ist, für die Rückzahlung der - * Präcombataura bei kurzem Kampf. */ + * Präcombataura bei kurzem Kampf. */ c1->side->bf->attacker = true; if (set_enemy(c1->side, c2->side, true) && battledebug) { @@ -4088,45 +4612,51 @@ init_battle(region * r, battle **bp) return fighting; } -static void -battle_stats(FILE * F, battle * b) +static void battle_stats(FILE * F, battle * b) { typedef struct stat_info { - struct stat_info * next; - const weapon_type * wtype; + struct stat_info *next; + const weapon_type *wtype; int level; int number; } stat_info; - side * s; - for (s=b->sides;s!=b->sides+b->nsides;++s) { - fighter * df; - stat_info * stats = NULL, * stat; + side *s; + + for (s = b->sides; s != b->sides + b->nsides; ++s) { + fighter *df; + + stat_info *stats = NULL, *stat; for (df = s->fighters; df; df = df->next) { unit *du = df->unit; + troop dt; - stat_info * slast = NULL; + + stat_info *slast = NULL; dt.fighter = df; - for (dt.index=0;dt.index!=du->number;++dt.index) { - weapon * wp = preferred_weapon(dt, true); - int level = wp?wp->attackskill:0; - const weapon_type * wtype = wp?wp->type:NULL; - stat_info ** slist = &stats; + for (dt.index = 0; dt.index != du->number; ++dt.index) { + weapon *wp = preferred_weapon(dt, true); - if (slast && slast->wtype==wtype && slast->level==level) { + int level = wp ? wp->attackskill : 0; + + const weapon_type *wtype = wp ? wp->type : NULL; + + stat_info **slist = &stats; + + if (slast && slast->wtype == wtype && slast->level == level) { ++slast->number; continue; } - while (*slist && (*slist)->wtype!=wtype) { + while (*slist && (*slist)->wtype != wtype) { slist = &(*slist)->next; } - while (*slist && (*slist)->wtype==wtype && (*slist)->level>level) { + while (*slist && (*slist)->wtype == wtype && (*slist)->level > level) { slist = &(*slist)->next; } stat = *slist; - if (stat==NULL || stat->wtype!=wtype || stat->level!=level) { + if (stat == NULL || stat->wtype != wtype || stat->level != level) { stat = calloc(1, sizeof(stat_info)); stat->wtype = wtype; stat->level = level; @@ -4138,15 +4668,19 @@ battle_stats(FILE * F, battle * b) } } - fprintf(F, "##STATS## Heer %u - %s:\n", army_index(s), factionname(s->faction)); - for (stat=stats;stat!=NULL;stat=stat->next) { - fprintf(F, "%s %u : %u\n", stat->wtype?stat->wtype->itype->rtype->_name[0]:"none", stat->level, stat->number); + fprintf(F, "##STATS## Heer %u - %s:\n", army_index(s), + factionname(s->faction)); + for (stat = stats; stat != NULL; stat = stat->next) { + fprintf(F, "%s %u : %u\n", + stat->wtype ? stat->wtype->itype->rtype->_name[0] : "none", stat->level, + stat->number); + } + while (stats) { + stat_info *stat = stats; + + stats = stat->next; + free(stat); } - while(stats) { - stat_info * stat = stats; - stats = stat->next; - free(stat); - } } } @@ -4154,19 +4688,20 @@ battle_stats(FILE * F, battle * b) * fig->fighting is used to determine who attacks, not fig->alive, since * the latter may be influenced by attacks that already took place. */ -static void -battle_attacks(battle * b) +static void battle_attacks(battle * b) { - side * s; + side *s; - for (s=b->sides;s!=b->sides+b->nsides;++s) { + for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *fig; - if (b->turn!=0 || (b->max_tactics > 0 && get_tactics(s, NULL) == b->max_tactics)) { - for (fig=s->fighters;fig;fig=fig->next) { + if (b->turn != 0 || (b->max_tactics > 0 + && get_tactics(s, NULL) == b->max_tactics)) { + for (fig = s->fighters; fig; fig = fig->next) { /* ist in dieser Einheit noch jemand handlungsfähig? */ - if (fig->fighting <= 0) continue; + if (fig->fighting <= 0) + continue; /* Handle the unit's attack on someone */ do_attack(fig); @@ -4179,13 +4714,14 @@ battle_attacks(battle * b) * this has to be calculated _before_ the actual attacks take * place because otherwise dead troops would not strike in the * round they die. */ -static void -battle_update(battle * b) +static void battle_update(battle * b) { - side * s; - for (s=b->sides;s!=b->sides+b->nsides;++s) { + side *s; + + for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *fig; - for (fig=s->fighters;fig;fig=fig->next) { + + for (fig = s->fighters; fig; fig = fig->next) { fig->fighting = fig->alive - fig->removed; } } @@ -4194,24 +4730,28 @@ battle_update(battle * b) /** attempt to flee from battle before the next round begins * there's a double attempt before the first round, but only * one attempt before round zero, the potential tactics round. */ -static void -battle_flee(battle * b) +static void battle_flee(battle * b) { int attempt, flee_ops = 1; - if (b->turn==1) + if (b->turn == 1) flee_ops = 2; - for (attempt=1;attempt<=flee_ops;++attempt) { - side * s; - for (s=b->sides;s!=b->sides+b->nsides;++s) { + for (attempt = 1; attempt <= flee_ops; ++attempt) { + side *s; + + for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *fig; - for (fig=s->fighters;fig;fig=fig->next) { + + for (fig = s->fighters; fig; fig = fig->next) { unit *u = fig->unit; + troop dt; + int runners = 0; + /* Flucht nicht bei mehr als 600 HP. Damit Wyrme tötbar bleiben. */ - int runhp = MIN(600,(int)(0.9+unit_max_hp(u)*hpflee(u->status))); + int runhp = MIN(600, (int)(0.9 + unit_max_hp(u) * hpflee(u->status))); if (u->ship && fval(u->region->terrain, SEA_REGION)) { /* keine Flucht von Schiffen auf hoher See */ @@ -4224,79 +4764,92 @@ battle_flee(battle * b) dt.fighter = fig; #ifndef SIMPLE_ESCAPE - if (!fig->run.region) fig->run.region = fleeregion(u); - if (!fig->run.region) continue; + if (!fig->run.region) + fig->run.region = fleeregion(u); + if (!fig->run.region) + continue; #endif /* SIMPLE_ESCAPE */ dt.index = fig->alive - fig->removed; while (s->size[SUM_ROW] && dt.index != 0) { double ispaniced = 0.0; + --dt.index; - assert(dt.index>=0 && dt.indexunit->number); + assert(dt.index >= 0 && dt.index < fig->unit->number); assert(fig->person[dt.index].hp > 0); /* Versuche zu fliehen, wenn - * - Kampfstatus fliehe - * - schwer verwundet und nicht erste kampfrunde - * - in panik (Zauber) - * aber nicht, wenn der Zaubereffekt Held auf dir liegt! - */ + * - Kampfstatus fliehe + * - schwer verwundet und nicht erste kampfrunde + * - in panik (Zauber) + * aber nicht, wenn der Zaubereffekt Held auf dir liegt! + */ switch (u->status) { - case ST_FLEE: - break; - default: - if ((fig->person[dt.index].flags & FL_HIT) == 0) continue; - if (b->turn<=1) continue; - if (fig->person[dt.index].hp <= runhp) break; - if (fig->person[dt.index].flags & FL_PANICED) { - if ((fig->person[dt.index].flags & FL_COURAGE)==0) break; - } + case ST_FLEE: + break; + default: + if ((fig->person[dt.index].flags & FL_HIT) == 0) continue; + if (b->turn <= 1) + continue; + if (fig->person[dt.index].hp <= runhp) + break; + if (fig->person[dt.index].flags & FL_PANICED) { + if ((fig->person[dt.index].flags & FL_COURAGE) == 0) + break; + } + continue; } if (fig->person[dt.index].flags & FL_PANICED) { ispaniced = EFFECT_PANIC_SPELL; } - if (chance(MIN(fleechance(u)+ispaniced, 0.90))) { + if (chance(MIN(fleechance(u) + ispaniced, 0.90))) { ++runners; flee(dt); } } if (bdebug && runners > 0) { - fprintf(bdebug, "Fleeing: %d from %s\n", runners, itoa36(fig->unit->no)); + fprintf(bdebug, "Fleeing: %d from %s\n", runners, + itoa36(fig->unit->no)); } } } } } -void -do_battle(region * r) +void do_battle(region * r) { battle *b = NULL; + boolean fighting = false; - ship * sh; + + ship *sh; + building *bu; + static int init_rules = 0; if (!init_rules) { static_rules(); init_rules = 1; } - if (msg_separator==NULL) { + if (msg_separator == NULL) { msg_separator = msg_message("battle::section", ""); } fighting = init_battle(r, &b); - if (b==NULL) return; + if (b == NULL) + return; /* Bevor wir die alliierten hineinziehen, sollten wir schauen, * - * Ob jemand fliehen kann. Dann erübrigt sich das ganze ja - * vielleicht schon. */ + * Ob jemand fliehen kann. Dann erübrigt sich das ganze ja + * vielleicht schon. */ print_header(b); if (!fighting) { /* Niemand mehr da, Kampf kann nicht stattfinden. */ - message * m = msg_message("battle::aborted", ""); + message *m = msg_message("battle::aborted", ""); + message_all(b, m); msg_release(m); free_battle(b); @@ -4307,10 +4860,12 @@ do_battle(region * r) make_heroes(b); /* Alle Mann raus aus der Burg! */ - for (bu=r->buildings; bu!=NULL; bu=bu->next) bu->sizeleft = bu->size; + for (bu = r->buildings; bu != NULL; bu = bu->next) + bu->sizeleft = bu->size; /* make sure no ships are damaged initially */ - for (sh=r->ships; sh; sh=sh->next) freset(sh, SF_DAMAGED); + for (sh = r->ships; sh; sh = sh->next) + freset(sh, SF_DAMAGED); /* Gibt es eine Taktikrunde ? */ if (!ql_empty(b->leaders)) { @@ -4321,15 +4876,17 @@ do_battle(region * r) b->has_tactics_turn = false; } - if (b->region->flags & RF_COMBATDEBUG) battle_stats(bdebug, b); + if (b->region->flags & RF_COMBATDEBUG) + battle_stats(bdebug, b); /* PRECOMBATSPELLS */ do_combatmagic(b, DO_PRECOMBATSPELL); - print_stats(b); /* gibt die Kampfaufstellung aus */ - if (verbosity>0) log_stdio(stdout, "%s (%d, %d) : ", rname(r, default_locale), r->x, r->y); + print_stats(b); /* gibt die Kampfaufstellung aus */ + if (verbosity > 0) + log_stdio(stdout, "%s (%d, %d) : ", rname(r, default_locale), r->x, r->y); - for (;battle_report(b) && b->turn<=max_turns;++b->turn) { + for (; battle_report(b) && b->turn <= max_turns; ++b->turn) { if (bdebug) { fprintf(bdebug, "*** Turn: %d\n", b->turn); } @@ -4339,12 +4896,13 @@ do_battle(region * r) } - if (verbosity>0) log_stdio(stdout, "\n"); + if (verbosity > 0) + log_stdio(stdout, "\n"); /* Auswirkungen berechnen: */ aftermath(b); /* Hier ist das Gefecht beendet, und wir können die - * Hilfsstrukturen * wieder löschen: */ + * Hilfsstrukturen * wieder löschen: */ if (b) { free_battle(b); diff --git a/src/kernel/battle.h b/src/kernel/battle.h index 77a3917f2..69299e9dd 100644 --- a/src/kernel/battle.h +++ b/src/kernel/battle.h @@ -41,22 +41,22 @@ extern "C" { #define FLEE_ROW 4 #define LAST_ROW (NUMROWS-1) #define FIRST_ROW FIGHT_ROW -#define MAXSIDES 192 /* if there are ever more than this, we're fucked. */ +#define MAXSIDES 192 /* if there are ever more than this, we're fucked. */ struct message; typedef struct bfaction { - struct bfaction * next; - struct side * sides; + struct bfaction *next; + struct side *sides; struct faction *faction; #ifndef SIMPLE_COMBAT - int lastturn; /* last time this struct faction was involved in combat */ + int lastturn; /* last time this struct faction was involved in combat */ #endif boolean attacker; } bfaction; typedef struct tactics { - struct quicklist * fighters; + struct quicklist *fighters; int value; } tactics; @@ -65,55 +65,55 @@ extern "C" { #define SIDE_HASGUARDS 1<<1 #endif typedef struct side { - struct side * nextF; /* next army of same faction */ - struct battle * battle; - struct bfaction * bf; /* battle info that goes with the faction */ - struct faction * faction; /* cache optimization for bf->faction */ - const struct group * group; - struct tactics leader; /* this army's best tactician */ + struct side *nextF; /* next army of same faction */ + struct battle *battle; + struct bfaction *bf; /* battle info that goes with the faction */ + struct faction *faction; /* cache optimization for bf->faction */ + const struct group *group; + struct tactics leader; /* this army's best tactician */ # define E_ENEMY 1 # define E_FRIEND 2 # define E_ATTACKING 4 unsigned char relations[MAXSIDES]; - struct side * enemies[MAXSIDES]; - struct fighter * fighters; - int index; /* Eintrag der Fraktion in b->matrix/b->enemies */ - int size[NUMROWS]; /* Anzahl Personen in Reihe X. 0 = Summe */ - int nonblockers[NUMROWS]; /* Anzahl nichtblockierender Kämpfer, z.B. Schattenritter. */ - int alive; /* Die Partei hat den Kampf verlassen */ - int removed; /* stoned */ + struct side *enemies[MAXSIDES]; + struct fighter *fighters; + int index; /* Eintrag der Fraktion in b->matrix/b->enemies */ + int size[NUMROWS]; /* Anzahl Personen in Reihe X. 0 = Summe */ + int nonblockers[NUMROWS]; /* Anzahl nichtblockierender Kämpfer, z.B. Schattenritter. */ + int alive; /* Die Partei hat den Kampf verlassen */ + int removed; /* stoned */ int flee; int dead; - int casualties; /* those dead that were real people, not undead! */ + int casualties; /* those dead that were real people, not undead! */ int healed; unsigned int flags; const struct faction *stealthfaction; } side; typedef struct battle { - struct quicklist * leaders; + struct quicklist *leaders; struct region *region; - struct plane *plane; - bfaction * factions; + struct plane *plane; + bfaction *factions; int nfactions; int nfighters; side sides[MAXSIDES]; int nsides; struct quicklist *meffects; - int max_tactics; - int turn; + int max_tactics; + int turn; boolean has_tactics_turn; - int keeploot; + int keeploot; boolean reelarrow; - int alive; + int alive; #ifdef SMALL_BATTLE_MESSAGES boolean small; #endif #define FASTROW #ifdef FASTROW struct { - const struct side * as; - const struct side * vs; + const struct side *as; + const struct side *vs; int alive; int row; int result; @@ -122,7 +122,7 @@ extern "C" { #define FASTCOUNT #ifdef FASTCOUNT struct { - struct side * side; + struct side *side; int status; int alive; int minrow, maxrow; @@ -133,19 +133,19 @@ extern "C" { typedef struct weapon { int count, used; - const struct weapon_type * type; - int attackskill : 8; - int defenseskill : 8; + const struct weapon_type *type; + int attackskill:8; + int defenseskill:8; } weapon; /*** fighter::person::flags ***/ #define FL_TIRED 1 -#define FL_DAZZLED 2 /* durch Untote oder Dämonen eingeschüchtert */ +#define FL_DAZZLED 2 /* durch Untote oder Dämonen eingeschüchtert */ #define FL_PANICED 4 -#define FL_COURAGE 8 /* Helden fliehen nie */ +#define FL_COURAGE 8 /* Helden fliehen nie */ #define FL_SLEEPING 16 -#define FL_STUNNED 32 /* eine Runde keinen Angriff */ -#define FL_HIT 64 /* the person at attacked */ +#define FL_STUNNED 32 /* eine Runde keinen Angriff */ +#define FL_HIT 64 /* the person at attacked */ typedef struct troop { struct fighter *fighter; @@ -153,8 +153,8 @@ extern "C" { } troop; typedef struct armor { - struct armor * next; - const struct armor_type * atype; + struct armor *next; + const struct armor_type *atype; int count; } armor; @@ -162,50 +162,50 @@ extern "C" { #define FIG_ATTACKER 1<<0 #define FIG_NOLOOT 1<<1 typedef struct fighter { - struct fighter * next; + struct fighter *next; struct side *side; - struct unit *unit; /* Die Einheit, die hier kämpft */ - struct building *building; /* Gebäude, in dem die Einheit evtl. steht */ - status_t status; /* Kampfstatus */ - struct weapon * weapons; - struct armor *armors; /* Anzahl Rüstungen jeden Typs */ - int alive; /* Anzahl der noch nicht Toten in der Einheit */ - int fighting; /* Anzahl der Kämpfer in der aktuellen Runde */ - int removed; /* Anzahl Kaempfer, die nicht tot sind, aber - aus dem Kampf raus sind (zB weil sie - versteinert wurden). Diese werden auch - in alive noch mitgezählt! */ - int magic; /* Magietalent der Einheit */ - int horses; /* Anzahl brauchbarer Pferde der Einheit */ - int elvenhorses; /* Anzahl brauchbarer Elfenpferde der Einheit */ - struct item * loot; - int catmsg; /* Merkt sich, ob Katapultmessage schon generiert. */ + struct unit *unit; /* Die Einheit, die hier kämpft */ + struct building *building; /* Gebäude, in dem die Einheit evtl. steht */ + status_t status; /* Kampfstatus */ + struct weapon *weapons; + struct armor *armors; /* Anzahl Rüstungen jeden Typs */ + int alive; /* Anzahl der noch nicht Toten in der Einheit */ + int fighting; /* Anzahl der Kämpfer in der aktuellen Runde */ + int removed; /* Anzahl Kaempfer, die nicht tot sind, aber + aus dem Kampf raus sind (zB weil sie + versteinert wurden). Diese werden auch + in alive noch mitgezählt! */ + int magic; /* Magietalent der Einheit */ + int horses; /* Anzahl brauchbarer Pferde der Einheit */ + int elvenhorses; /* Anzahl brauchbarer Elfenpferde der Einheit */ + struct item *loot; + int catmsg; /* Merkt sich, ob Katapultmessage schon generiert. */ struct person { - int hp; /* Trefferpunkte der Personen */ - int attack : 8; /* (Magie) Attackenbonus der Personen */ - int defence : 8; /* (Magie) Paradenbonus der Personen */ - int damage : 8; /* (Magie) Schadensbonus der Personen im Nahkampf */ - int damage_rear : 8; /* (Magie) Schadensbonus der Personen im Fernkampf */ - int flags : 8; /* (Magie) Diverse Flags auf Kämpfern */ - int speed : 8; /* (Magie) Geschwindigkeitsmultiplkator. */ - int reload : 4; /* Anzahl Runden, die die Waffe x noch laden muss. - * dahinter steckt ein array[RL_MAX] wenn er min. eine hat. */ - int last_action : 4; /* In welcher Runde haben wir zuletzt etwas getan */ - struct weapon * missile; /* missile weapon */ - struct weapon * melee; /* melee weapon */ - } * person; + int hp; /* Trefferpunkte der Personen */ + int attack:8; /* (Magie) Attackenbonus der Personen */ + int defence:8; /* (Magie) Paradenbonus der Personen */ + int damage:8; /* (Magie) Schadensbonus der Personen im Nahkampf */ + int damage_rear:8; /* (Magie) Schadensbonus der Personen im Fernkampf */ + int flags:8; /* (Magie) Diverse Flags auf Kämpfern */ + int speed:8; /* (Magie) Geschwindigkeitsmultiplkator. */ + int reload:4; /* Anzahl Runden, die die Waffe x noch laden muss. + * dahinter steckt ein array[RL_MAX] wenn er min. eine hat. */ + int last_action:4; /* In welcher Runde haben wir zuletzt etwas getan */ + struct weapon *missile; /* missile weapon */ + struct weapon *melee; /* melee weapon */ + } *person; unsigned int flags; struct { - int number; /* number of people who fled */ - int hp; /* accumulated hp of fleeing people */ + int number; /* number of people who fled */ + int hp; /* accumulated hp of fleeing people */ #ifndef SIMPLE_ESCAPE - struct region *region; /* destination of fleeing people */ - struct item * items; /* items they take */ -#endif /* SIMPLE_ESCAPE */ + struct region *region; /* destination of fleeing people */ + struct item *items; /* items they take */ +#endif /* SIMPLE_ESCAPE */ } run; #ifndef SIMPLE_COMBAT - int action_counter; /* number of active actions the struct unit did in the fight */ -#endif /* SIMPLE_COMBAT */ + int action_counter; /* number of active actions the struct unit did in the fight */ +#endif /* SIMPLE_COMBAT */ #ifdef SHOW_KILLS int kills; int hits; @@ -224,46 +224,53 @@ extern "C" { }; typedef struct meffect { - fighter *magician; /* Der Zauberer, der den Schild gezaubert hat */ - int typ; /* Wirkungsweise des Schilds */ + fighter *magician; /* Der Zauberer, der den Schild gezaubert hat */ + int typ; /* Wirkungsweise des Schilds */ int effect; int duration; } meffect; extern const troop no_troop; - extern void do_battle(struct region * r); + extern void do_battle(struct region *r); /* for combat spells and special attacks */ enum { SELECT_ADVANCE = 0x1, SELECT_DISTANCE = 0x2, SELECT_FIND = 0x4 }; enum { ALLY_SELF, ALLY_ANY }; - extern troop select_enemy(struct fighter * af, int minrow, int maxrow, int select); - extern troop select_ally(struct fighter * af, int minrow, int maxrow, int allytype); + extern troop select_enemy(struct fighter *af, int minrow, int maxrow, + int select); + extern troop select_ally(struct fighter *af, int minrow, int maxrow, + int allytype); - extern int count_enemies(struct battle * b, const struct fighter * af, int minrow, int maxrow, int select); - extern boolean terminate(troop dt, troop at, int type, const char *damage, boolean missile); - extern void message_all(battle * b, struct message * m); + extern int count_enemies(struct battle *b, const struct fighter *af, + int minrow, int maxrow, int select); + extern boolean terminate(troop dt, troop at, int type, const char *damage, + boolean missile); + extern void message_all(battle * b, struct message *m); extern int hits(troop at, troop dt, weapon * awp); - extern void damage_building(struct battle *b, struct building *bldg, int damage_abs); - extern struct quicklist * fighters(struct battle *b, const struct side * vs, int minrow, int maxrow, int mask); - extern int count_allies(const struct side * as, int minrow, int maxrow, int select, int allytype); - extern int get_unitrow(const struct fighter * af, const struct side * vs); - extern boolean helping(const struct side * as, const struct side * ds); - extern void rmfighter(fighter *df, int i); + extern void damage_building(struct battle *b, struct building *bldg, + int damage_abs); + extern struct quicklist *fighters(struct battle *b, const struct side *vs, + int minrow, int maxrow, int mask); + extern int count_allies(const struct side *as, int minrow, int maxrow, + int select, int allytype); + extern int get_unitrow(const struct fighter *af, const struct side *vs); + extern boolean helping(const struct side *as, const struct side *ds); + extern void rmfighter(fighter * df, int i); #ifndef SIMPLE_ESCAPE - extern struct region * fleeregion(const struct unit * u); + extern struct region *fleeregion(const struct unit *u); #endif - extern struct fighter * select_corpse(struct battle * b, struct fighter * af); - extern fighter * make_fighter(struct battle * b, struct unit * u, side * s, boolean attack); + extern struct fighter *select_corpse(struct battle *b, struct fighter *af); + extern fighter *make_fighter(struct battle *b, struct unit *u, side * s, + boolean attack); extern int statusrow(int status); extern void drain_exp(struct unit *u, int d); extern void kill_troop(troop dt); - extern void remove_troop(troop dt); /* not the same as the badly named rmtroop */ + extern void remove_troop(troop dt); /* not the same as the badly named rmtroop */ extern boolean is_attacker(const fighter * fig); #ifdef __cplusplus } #endif - #endif diff --git a/src/kernel/binarystore.c b/src/kernel/binarystore.c index 3c35183bc..78b4408e8 100644 --- a/src/kernel/binarystore.c +++ b/src/kernel/binarystore.c @@ -24,44 +24,42 @@ without prior permission by the authors of Eressea. #define STREAM_VERSION 2 -INLINE_FUNCTION size_t -pack_int(int v, char * buffer) +INLINE_FUNCTION size_t pack_int(int v, char *buffer) { - int sign = (v<0); + int sign = (v < 0); if (sign) { v = ~v + 1; sign = 0x40; } - if (v<0x40) { + if (v < 0x40) { buffer[0] = (char)(v | sign); return 1; - } else if (v<0x2000) { - buffer[0] = (char)((v>> 6) | 0x80); + } else if (v < 0x2000) { + buffer[0] = (char)((v >> 6) | 0x80); buffer[1] = (char)((v & 0x3F) | sign); return 2; - } else if (v<0x100000) { - buffer[0] = (char)(((v>>13) & 0x7f) | 0x80); - buffer[1] = (char)(((v>> 6) & 0x7f) | 0x80); + } else if (v < 0x100000) { + buffer[0] = (char)(((v >> 13) & 0x7f) | 0x80); + buffer[1] = (char)(((v >> 6) & 0x7f) | 0x80); buffer[2] = (char)((v & 0x3F) | sign); return 3; - } else if (v<0x8000000) { - buffer[0] = (char)(((v>>20) & 0x7f) | 0x80); - buffer[1] = (char)(((v>>13) & 0x7f) | 0x80); - buffer[2] = (char)(((v>> 6) & 0x7f) | 0x80); + } else if (v < 0x8000000) { + buffer[0] = (char)(((v >> 20) & 0x7f) | 0x80); + buffer[1] = (char)(((v >> 13) & 0x7f) | 0x80); + buffer[2] = (char)(((v >> 6) & 0x7f) | 0x80); buffer[3] = (char)((v & 0x3F) | sign); return 4; } - buffer[0] = (char)(((v>>27) & 0x7f) | 0x80); - buffer[1] = (char)(((v>>20) & 0x7f) | 0x80); - buffer[2] = (char)(((v>>13) & 0x7f) | 0x80); - buffer[3] = (char)(((v>> 6) & 0x7f) | 0x80); + buffer[0] = (char)(((v >> 27) & 0x7f) | 0x80); + buffer[1] = (char)(((v >> 20) & 0x7f) | 0x80); + buffer[2] = (char)(((v >> 13) & 0x7f) | 0x80); + buffer[3] = (char)(((v >> 6) & 0x7f) | 0x80); buffer[4] = (char)((v & 0x3F) | sign); return 5; } -INLINE_FUNCTION int -unpack_int(const char * buffer) +INLINE_FUNCTION int unpack_int(const char *buffer) { int i = 0, v = 0; @@ -76,24 +74,24 @@ unpack_int(const char * buffer) return v; } -static int -bin_w_brk(struct storage * store) +static int bin_w_brk(struct storage *store) { return 0; } -static int -bin_w_int_pak(struct storage * store, int arg) +static int bin_w_int_pak(struct storage *store, int arg) { char buffer[5]; + size_t size = pack_int(arg, buffer); + return (int)fwrite(buffer, sizeof(char), size, file(store)); } -static int -bin_r_int_pak(struct storage * store) +static int bin_r_int_pak(struct storage *store) { int v = 0; + char ch; fread(&ch, sizeof(char), 1, file(store)); @@ -109,103 +107,105 @@ bin_r_int_pak(struct storage * store) return v; } -static int -bin_w_int(struct storage * store, int arg) +static int bin_w_int(struct storage *store, int arg) { return (int)fwrite(&arg, sizeof(arg), 1, file(store)); } -static int -bin_r_int(struct storage * store) +static int bin_r_int(struct storage *store) { int result; + fread(&result, sizeof(result), 1, file(store)); return result; } -static int -bin_w_flt(struct storage * store, float arg) +static int bin_w_flt(struct storage *store, float arg) { return (int)fwrite(&arg, sizeof(arg), 1, file(store)); } -static float -bin_r_flt(struct storage * store) +static float bin_r_flt(struct storage *store) { float result; + fread(&result, sizeof(result), 1, file(store)); return result; } -static int -bin_w_str(struct storage * store, const char * tok) +static int bin_w_str(struct storage *store, const char *tok) { int result; - if (tok==NULL || tok[0]==0) { + + if (tok == NULL || tok[0] == 0) { result = store->w_int(store, 0); } else { int size = (int)strlen(tok); + result = store->w_int(store, size); result += (int)fwrite(tok, size, 1, file(store)); } return result; } -#define FIX_INVALID_CHARS /* required for data pre-574 */ -static char * -bin_r_str(struct storage * store) +#define FIX_INVALID_CHARS /* required for data pre-574 */ +static char *bin_r_str(struct storage *store) { int len; len = store->r_int(store); - if (len>=0) { - char * result = malloc(len+1); + if (len >= 0) { + char *result = malloc(len + 1); fread(result, sizeof(char), len, file(store)); result[len] = 0; #ifdef FIX_INVALID_CHARS { - char * p = strpbrk(result, "\n\r"); + char *p = strpbrk(result, "\n\r"); + while (p) { - log_error(("Invalid character %d in input string \"%s\".\n", *p, result)); - strcpy(p, p+1); + log_error(("Invalid character %d in input string \"%s\".\n", *p, + result)); + strcpy(p, p + 1); p = strpbrk(p, "\n\r"); } } #endif return result; - } else if (len<0) { + } else if (len < 0) { log_error(("invalid string-length %d in input.\n", len)); } return NULL; } -static void -bin_r_str_buf(struct storage * store, char * result, size_t size) +static void bin_r_str_buf(struct storage *store, char *result, size_t size) { int i; + size_t rd, len; i = store->r_int(store); - assert(i>=0); - if (i==0) { + assert(i >= 0); + if (i == 0) { result[0] = 0; } else { - len = (size_t)i; - rd = MIN(len, size-1); + len = (size_t) i; + rd = MIN(len, size - 1); fread(result, sizeof(char), rd, file(store)); - if (rdw_int(store, len); - if (len>0) { + if (len > 0) { result += (int)fwrite(arg, len, 1, file(store)); } return result; } -static void -bin_r_bin(struct storage * store, void * result, size_t size) +static void bin_r_bin(struct storage *store, void *result, size_t size) { int len = store->r_int(store); - if (len>0) { - if ((size_t)len>size) { + + if (len > 0) { + if ((size_t) len > size) { log_error(("destination buffer too small %d %u.\n", len, size)); fseek(file(store), len, SEEK_CUR); } else { @@ -241,52 +241,51 @@ bin_r_bin(struct storage * store, void * result, size_t size) } -static int -bin_open(struct storage * store, const char * filename, int mode) +static int bin_open(struct storage *store, const char *filename, int mode) { - const char * modes[] = { 0, "rb", "wb", "ab" }; - FILE * F = fopen(filename, modes[mode]); + const char *modes[] = { 0, "rb", "wb", "ab" }; + FILE *F = fopen(filename, modes[mode]); + store->userdata = F; - store->encoding=XML_CHAR_ENCODING_UTF8; /* always utf8 it is */ + store->encoding = XML_CHAR_ENCODING_UTF8; /* always utf8 it is */ if (F) { - if (mode==IO_READ) { + if (mode == IO_READ) { int stream_version = 0; + store->version = bin_r_int(store); - if (store->version>=INTPAK_VERSION) { + if (store->version >= INTPAK_VERSION) { stream_version = bin_r_int(store); } - if (stream_version<=1) { + if (stream_version <= 1) { store->r_id = bin_r_int; store->w_id = bin_w_int; } - if (stream_version==0) { + if (stream_version == 0) { store->r_int = bin_r_int; store->w_int = bin_w_int; } - } else if (store->encoding==XML_CHAR_ENCODING_UTF8) { + } else if (store->encoding == XML_CHAR_ENCODING_UTF8) { store->version = RELEASE_VERSION; bin_w_int(store, RELEASE_VERSION); bin_w_int(store, STREAM_VERSION); } } - return (F==NULL); + return (F == NULL); } -static int -bin_close(struct storage * store) +static int bin_close(struct storage *store) { return fclose(file(store)); } const storage binary_store = { - bin_w_brk, /* newline (ignore) */ + bin_w_brk, /* newline (ignore) */ bin_w_int_pak, bin_r_int_pak, /* int storage */ - bin_w_flt, bin_r_flt, /* float storage */ + bin_w_flt, bin_r_flt, /* float storage */ bin_w_int_pak, bin_r_int_pak, /* id storage */ - bin_w_str, bin_r_str, bin_r_str_buf, /* token storage */ - bin_w_str, bin_r_str, bin_r_str_buf, /* string storage */ - bin_w_bin, bin_r_bin, /* binary storage */ + bin_w_str, bin_r_str, bin_r_str_buf, /* token storage */ + bin_w_str, bin_r_str, bin_r_str_buf, /* string storage */ + bin_w_bin, bin_r_bin, /* binary storage */ bin_open, bin_close, 0, 0, NULL }; - diff --git a/src/kernel/binarystore.h b/src/kernel/binarystore.h index 8ba979667..c2ebc1c7b 100644 --- a/src/kernel/binarystore.h +++ b/src/kernel/binarystore.h @@ -15,7 +15,7 @@ extern "C" { #include -extern const storage binary_store; + extern const storage binary_store; #ifdef __cplusplus } diff --git a/src/kernel/build.c b/src/kernel/build.c index 12979a85d..ce6ab7d4e 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -70,11 +70,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * Laen, Mallorn}, UnterSilber, UnterSpezialTyp, UnterSpezial */ -static boolean -CheckOverload(void) +static boolean CheckOverload(void) { static int value = -1; - if (value<0) { + + if (value < 0) { value = get_param_int(global.parameters, "rules.check_overload", 0); } return value; @@ -84,14 +84,14 @@ CheckOverload(void) * returns 0 if siege is successful, or 1 if the building is either * not besieged or the unit can slip through the siege due to better stealth. */ -static int -slipthru(const region * r, const unit * u, const building * b) +static int slipthru(const region * r, const unit * u, const building * b) { unit *u2; + int n, o; /* b ist die burg, in die man hinein oder aus der man heraus will. */ - if (b==NULL || b->besieged < b->size * SIEGEFACTOR) { + if (b == NULL || b->besieged < b->size * SIEGEFACTOR) { return 1; } @@ -102,20 +102,20 @@ slipthru(const region * r, const unit * u, const building * b) for (u2 = r->units; u2; u2 = u2->next) { if (usiege(u2) == b) { - if (invisible(u, u2) >= u->number) continue; + if (invisible(u, u2) >= u->number) + continue; o = eff_skill(u2, SK_PERCEPTION, r); if (o + 2 >= n) { - return 0; /* entdeckt! */ + return 0; /* entdeckt! */ } } } return 1; } -boolean -can_contact(const region * r, const unit * u, const unit * u2) +boolean can_contact(const region * r, const unit * u, const unit * u2) { /* hier geht es nur um die belagerung von burgen */ @@ -128,7 +128,7 @@ can_contact(const region * r, const unit * u, const unit * u2) * slipthru () == 1. ansonsten ist es nur 1, wenn man die belagerer */ if (slipthru(u->region, u, u->building) - && slipthru(u->region, u2, u2->building)) + && slipthru(u->region, u2, u2->building)) return true; if (alliedunit(u, u2->faction, HELP_GIVE)) @@ -138,8 +138,7 @@ can_contact(const region * r, const unit * u, const unit * u2) } -static void -contact_cmd(unit * u, order * ord, boolean tries) +static void contact_cmd(unit * u, order * ord, boolean tries) { /* unit u kontaktiert unit u2. Dies setzt den contact einfach auf 1 - * ein richtiger toggle ist (noch?) nicht noetig. die region als @@ -147,20 +146,23 @@ contact_cmd(unit * u, order * ord, boolean tries) * weitergegeben wird. dies wird fuer das auffinden von tempunits in * getnewunit () verwendet! */ unit *u2; - region * r = u->region; + + region *r = u->region; init_tokens(ord); skip_token(); u2 = getunitg(r, u->faction); - if (u2!=NULL) { + if (u2 != NULL) { if (!can_contact(r, u, u2)) { - if (tries) cmistake(u, u->thisorder, 23, MSG_EVENT); + if (tries) + cmistake(u, u->thisorder, 23, MSG_EVENT); return; } usetcontact(u, u2); } } + /* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */ @@ -168,37 +170,46 @@ contact_cmd(unit * u, order * ord, boolean tries) /* ------------------------------------------------------------- */ -struct building * -getbuilding(const struct region * r) +struct building *getbuilding(const struct region *r) { - building * b = findbuilding(getid()); - if (b==NULL || r!=b->region) return NULL; + building *b = findbuilding(getid()); + + if (b == NULL || r != b->region) + return NULL; return b; } -ship * -getship(const struct region * r) +ship *getship(const struct region * r) { ship *sh, *sx = findship(getshipid()); + for (sh = r->ships; sh; sh = sh->next) { - if (sh == sx) return sh; + if (sh == sx) + return sh; } return NULL; } /* ------------------------------------------------------------- */ -static void -siege_cmd(unit * u, order * ord) +static void siege_cmd(unit * u, order * ord) { - region * r = u->region; + region *r = u->region; + building *b; + int d, pooled; + int bewaffnete, katapultiere = 0; + static boolean init = false; - static const curse_type * magicwalls_ct; - static item_type * it_catapultammo = NULL; - static item_type * it_catapult = NULL; + + static const curse_type *magicwalls_ct; + + static item_type *it_catapultammo = NULL; + + static item_type *it_catapult = NULL; + if (!init) { init = true; magicwalls_ct = ct_find("magicwalls"); @@ -243,13 +254,13 @@ siege_cmd(unit * u, order * ord) if (!is_guard(u, GUARD_TRAVELTHRU)) { /* abbruch, wenn die einheit nicht vorher die region bewacht - als - * warnung fuer alle anderen! */ + * warnung fuer alle anderen! */ cmistake(u, ord, 81, MSG_EVENT); return; } /* einheit und burg markieren - spart zeit beim behandeln der einheiten - * in der burg, falls die burg auch markiert ist und nicht alle - * einheiten wieder abgesucht werden muessen! */ + * in der burg, falls die burg auch markiert ist und nicht alle + * einheiten wieder abgesucht werden muessen! */ usetsiege(u, b); b->besieged += MAX(bewaffnete, katapultiere); @@ -261,19 +272,18 @@ siege_cmd(unit * u, order * ord) /* meldung, schaden anrichten */ if (d && !curse_active(get_curse(b->attribs, magicwalls_ct))) { b->size -= d; - use_pooled(u, it_catapultammo->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, d); + use_pooled(u, it_catapultammo->rtype, + GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, d); /* send message to the entire region */ ADDMSG(&r->msgs, msg_message("siege_catapults", - "unit building destruction", u, b, d)); + "unit building destruction", u, b, d)); } else { /* send message to the entire region */ - ADDMSG(&r->msgs, msg_message("siege", - "unit building", u, b)); + ADDMSG(&r->msgs, msg_message("siege", "unit building", u, b)); } } -void -do_siege(region *r) +void do_siege(region * r) { if (fval(r->terrain, LAND_REGION)) { unit *u; @@ -285,21 +295,26 @@ do_siege(region *r) } } } + /* ------------------------------------------------------------- */ -static void -destroy_road(unit *u, int nmax, struct order * ord) +static void destroy_road(unit * u, int nmax, struct order *ord) { direction_t d = getdirection(u->faction->locale); + unit *u2; + region *r = u->region; + short n = (short)nmax; - if (nmax>SHRT_MAX) n = SHRT_MAX; - else if (nmax<0) n = 0; + if (nmax > SHRT_MAX) + n = SHRT_MAX; + else if (nmax < 0) + n = 0; - for (u2=r->units;u2;u2=u2->next) { - if (u2->faction!=u->faction && is_guard(u2, GUARD_TAX) + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->faction != u->faction && is_guard(u2, GUARD_TAX) && cansee(u2->faction, u->region, u, 0) && !alliedunit(u, u2->faction, HELP_GUARD)) { cmistake(u, ord, 70, MSG_EVENT); @@ -307,37 +322,47 @@ destroy_road(unit *u, int nmax, struct order * ord) } } - if (d==NODIRECTION) { + if (d == NODIRECTION) { /* Die Richtung wurde nicht erkannt */ cmistake(u, ord, 71, MSG_PRODUCE); } else { short road = rroad(r, d); + n = MIN(n, road); - if (n!=0) { - region * r2 = rconnect(r,d); - int willdo = eff_skill(u, SK_ROAD_BUILDING, r)*u->number; + if (n != 0) { + region *r2 = rconnect(r, d); + + int willdo = eff_skill(u, SK_ROAD_BUILDING, r) * u->number; + willdo = MIN(willdo, n); - if (willdo==0) { + if (willdo == 0) { /* TODO: error message */ } - if (willdo>SHRT_MAX) road = 0; - else road = road - (short)willdo; + if (willdo > SHRT_MAX) + road = 0; + else + road = road - (short)willdo; rsetroad(r, d, road); ADDMSG(&u->faction->msgs, msg_message("destroy_road", - "unit from to", u, r, r2)); + "unit from to", u, r, r2)); } } } -int -destroy_cmd(unit * u, struct order * ord) +int destroy_cmd(unit * u, struct order *ord) { ship *sh; + unit *u2; - region * r = u->region; - const construction * con = NULL; + + region *r = u->region; + + const construction *con = NULL; + int size = 0; + const char *s; + int n = INT_MAX; if (u->number < 1) @@ -347,7 +372,7 @@ destroy_cmd(unit * u, struct order * ord) skip_token(); s = getstrtoken(); - if (findparam(s, u->faction->locale)==P_ROAD) { + if (findparam(s, u->faction->locale) == P_ROAD) { destroy_road(u, INT_MAX, ord); return 0; } @@ -376,7 +401,8 @@ destroy_cmd(unit * u, struct order * ord) if (fval(b->type, BTF_INDESTRUCTIBLE)) { cmistake(u, ord, 138, MSG_PRODUCE); return 0; - } if (n >= b->size) { + } + if (n >= b->size) { /* destroy completly */ /* all units leave the building */ for (u2 = r->units; u2; u2 = u2->next) { @@ -385,15 +411,14 @@ destroy_cmd(unit * u, struct order * ord) freset(u2, UFL_OWNER); } } - ADDMSG(&u->faction->msgs, msg_message("destroy", - "building unit", b, u)); + ADDMSG(&u->faction->msgs, msg_message("destroy", "building unit", b, u)); con = b->type->construction; remove_building(&r->buildings, b); } else { /* partial destroy */ b->size -= n; ADDMSG(&u->faction->msgs, msg_message("destroy_partial", - "building unit", b, u)); + "building unit", b, u)); } } else if (u->ship) { sh = u->ship; @@ -403,7 +428,7 @@ destroy_cmd(unit * u, struct order * ord) return 0; } - if (n >= (sh->size*100)/sh->type->construction->maxsize) { + if (n >= (sh->size * 100) / sh->type->construction->maxsize) { /* destroy completly */ /* all units leave the ship */ for (u2 = r->units; u2; u2 = u2->next) { @@ -413,26 +438,30 @@ destroy_cmd(unit * u, struct order * ord) } } ADDMSG(&u->faction->msgs, msg_message("shipdestroy", - "unit region ship", u, r, sh)); + "unit region ship", u, r, sh)); con = sh->type->construction; remove_ship(&sh->region->ships, sh); } else { /* partial destroy */ - sh->size -= (sh->type->construction->maxsize * n)/100; + sh->size -= (sh->type->construction->maxsize * n) / 100; ADDMSG(&u->faction->msgs, msg_message("shipdestroy_partial", - "unit region ship", u, r, sh)); + "unit region ship", u, r, sh)); } } else { - log_error(("Die Einheit %s von %s war owner eines objects, war aber weder in einer Burg noch in einem Schiff.\n", - unitname(u), u->faction->name, u->faction->email)); + log_error( + ("Die Einheit %s von %s war owner eines objects, war aber weder in einer Burg noch in einem Schiff.\n", + unitname(u), u->faction->name, u->faction->email)); } if (con) { /* TODO: Nicht an ZERSTÖRE mit Punktangabe angepaßt! */ int c; - for (c=0;con->materials[c].number;++c) { - const requirement * rq = con->materials+c; - int recycle = (int)(rq->recycle * rq->number * size/con->reqsize); + + for (c = 0; con->materials[c].number; ++c) { + const requirement *rq = con->materials + c; + + int recycle = (int)(rq->recycle * rq->number * size / con->reqsize); + if (recycle) { change_resource(u, rq->rtype, recycle); } @@ -440,13 +469,14 @@ destroy_cmd(unit * u, struct order * ord) } return 0; } + /* ------------------------------------------------------------- */ -void -build_road(region * r, unit * u, int size, direction_t d) +void build_road(region * r, unit * u, int size, direction_t d) { int n, left; - region * rn = rconnect(r,d); + + region *rn = rconnect(r, d); assert(u->number); if (!eff_skill(u, SK_ROAD_BUILDING, r)) { @@ -458,7 +488,7 @@ build_road(region * r, unit * u, int size, direction_t d) return; } - if (rn==NULL || rn->terrain->max_road < 0) { + if (rn == NULL || rn->terrain->max_road < 0) { cmistake(u, u->thisorder, 94, MSG_PRODUCE); return; } @@ -470,16 +500,20 @@ build_road(region * r, unit * u, int size, direction_t d) if (r->terrain == newterrain(T_SWAMP)) { /* wenn kein Damm existiert */ - static const struct building_type * bt_dam; - if (!bt_dam) bt_dam = bt_find("dam"); + static const struct building_type *bt_dam; + + if (!bt_dam) + bt_dam = bt_find("dam"); assert(bt_dam); if (!buildingtype_exists(r, bt_dam, true)) { cmistake(u, u->thisorder, 132, MSG_PRODUCE); return; } } else if (r->terrain == newterrain(T_DESERT)) { - static const struct building_type * bt_caravan; - if (!bt_caravan) bt_caravan = bt_find("caravan"); + static const struct building_type *bt_caravan; + + if (!bt_caravan) + bt_caravan = bt_find("caravan"); assert(bt_caravan); /* wenn keine Karawanserei existiert */ if (!buildingtype_exists(r, bt_caravan, true)) { @@ -487,8 +521,10 @@ build_road(region * r, unit * u, int size, direction_t d) return; } } else if (r->terrain == newterrain(T_GLACIER)) { - static const struct building_type * bt_tunnel; - if (!bt_tunnel) bt_tunnel = bt_find("tunnel"); + static const struct building_type *bt_tunnel; + + if (!bt_tunnel) + bt_tunnel = bt_find("tunnel"); assert(bt_tunnel); /* wenn kein Tunnel existiert */ if (!buildingtype_exists(r, bt_tunnel, true)) { @@ -502,17 +538,19 @@ build_road(region * r, unit * u, int size, direction_t d) /* hoffentlich ist r->road <= r->terrain->max_road, n also >= 0 */ if (left <= 0) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_roads_finished", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, + "error_roads_finished", "")); return; } - if (size>0) left = MIN(size, left); + if (size > 0) + left = MIN(size, left); /* baumaximum anhand der rohstoffe */ - if (u->race == new_race[RC_STONEGOLEM]){ + if (u->race == new_race[RC_STONEGOLEM]) { n = u->number * GOLEM_STONE; } else { n = get_pooled(u, oldresourcetype[R_STONE], GET_DEFAULT, left); - if (n==0) { + if (n == 0) { cmistake(u, u->thisorder, 151, MSG_PRODUCE); return; } @@ -522,22 +560,27 @@ build_road(region * r, unit * u, int size, direction_t d) /* n = maximum by skill. try to maximize it */ n = u->number * eff_skill(u, SK_ROAD_BUILDING, r); if (n < left) { - item * itm = *i_find(&u->items, olditemtype[I_RING_OF_NIMBLEFINGER]); - if (itm!=NULL && itm->number>0) { + item *itm = *i_find(&u->items, olditemtype[I_RING_OF_NIMBLEFINGER]); + + if (itm != NULL && itm->number > 0) { int rings = MIN(u->number, itm->number); - n = n * ((roqf_factor()-1)*rings+u->number) / u->number; + + n = n * ((roqf_factor() - 1) * rings + u->number) / u->number; } } if (n < left) { int dm = get_effect(u, oldpotiontype[P_DOMORE]); + if (dm != 0) { int sk = eff_skill(u, SK_ROAD_BUILDING, r); + int todo = (left - n + sk - 1) / sk; + todo = MIN(todo, u->number); dm = MIN(dm, todo); change_effect(u, oldpotiontype[P_DOMORE], -dm); n += dm * sk; - } /* Auswirkung Schaffenstrunk */ + } /* Auswirkung Schaffenstrunk */ } /* make minimum of possible and available: */ @@ -550,7 +593,8 @@ build_road(region * r, unit * u, int size, direction_t d) if (u->race == new_race[RC_STONEGOLEM]) { int golemsused = n / GOLEM_STONE; - if (n%GOLEM_STONE != 0){ + + if (n % GOLEM_STONE != 0) { ++golemsused; } scale_number(u, u->number - golemsused); @@ -560,16 +604,16 @@ build_road(region * r, unit * u, int size, direction_t d) produceexp(u, SK_ROAD_BUILDING, MIN(n, u->number)); } ADDMSG(&u->faction->msgs, msg_message("buildroad", - "region unit size", r, u, n)); + "region unit size", r, u, n)); } + /* ------------------------------------------------------------- */ /* ** ** ** ** ** ** * * new build rules * * ** ** ** ** ** ** */ -static int -required(int size, int msize, int maxneed) +static int required(int size, int msize, int maxneed) /* um size von msize Punkten zu bauen, * braucht man required von maxneed resourcen */ { @@ -582,12 +626,16 @@ required(int size, int msize, int maxneed) } static int -matmod(const attrib * a, const unit * u, const resource_type * material, int value) +matmod(const attrib * a, const unit * u, const resource_type * material, + int value) { - for (a=a_find((attrib*)a, &at_matmod);a && a->type==&at_matmod;a=a->next) { - mm_fun fun = (mm_fun)a->data.f; + for (a = a_find((attrib *) a, &at_matmod); a && a->type == &at_matmod; + a = a->next) { + mm_fun fun = (mm_fun) a->data.f; + value = fun(u, material, value); - if (value<0) return value; /* pass errors to caller */ + if (value < 0) + return value; /* pass errors to caller */ } return value; } @@ -595,7 +643,8 @@ matmod(const attrib * a, const unit * u, const resource_type * material, int val int roqf_factor(void) { int value = -1; - if (value<0) { + + if (value < 0) { value = get_param_int(global.parameters, "rules.economy.roqf", 10); } return value; @@ -606,50 +655,60 @@ int roqf_factor(void) * of the first object have already been finished. return the * actual size that could be built. */ -int -build(unit * u, const construction * ctype, int completed, int want) +int build(unit * u, const construction * ctype, int completed, int want) { - const construction * type = ctype; - int skills = INT_MAX; /* number of skill points remainig */ + const construction *type = ctype; + + int skills = INT_MAX; /* number of skill points remainig */ + int basesk = 0; + int made = 0; - if (want<=0) return 0; - if (type==NULL) return 0; - if (type->improvement==NULL && completed==type->maxsize) + if (want <= 0) + return 0; + if (type == NULL) + return 0; + if (type->improvement == NULL && completed == type->maxsize) return ECOMPLETE; - if (type->btype!=NULL) { - building * b; - if (!u->building || u->building->type!=type->btype) { + if (type->btype != NULL) { + building *b; + + if (!u->building || u->building->type != type->btype) { return EBUILDINGREQ; } b = inside_building(u); - if (b==NULL) return EBUILDINGREQ; + if (b == NULL) + return EBUILDINGREQ; } - if (type->skill!=NOSKILL) { + if (type->skill != NOSKILL) { int effsk; + int dm = get_effect(u, oldpotiontype[P_DOMORE]); assert(u->number); basesk = effskill(u, type->skill); - if (basesk==0) return ENEEDSKILL; + if (basesk == 0) + return ENEEDSKILL; effsk = basesk; if (inside_building(u)) { effsk = skillmod(u->building->type->attribs, u, u->region, type->skill, - effsk, SMF_PRODUCTION); + effsk, SMF_PRODUCTION); } effsk = skillmod(type->attribs, u, u->region, type->skill, - effsk, SMF_PRODUCTION); - if (effsk<0) return effsk; /* pass errors to caller */ - if (effsk==0) return ENEEDSKILL; + effsk, SMF_PRODUCTION); + if (effsk < 0) + return effsk; /* pass errors to caller */ + if (effsk == 0) + return ENEEDSKILL; skills = effsk * u->number; /* technically, nimblefinge and domore should be in a global set of - * "game"-attributes, (as at_skillmod) but for a while, we're leaving - * them in here. */ + * "game"-attributes, (as at_skillmod) but for a while, we're leaving + * them in here. */ if (dm != 0) { /* Auswirkung Schaffenstrunk */ @@ -658,7 +717,7 @@ build(unit * u, const construction * ctype, int completed, int want) skills += dm * effsk; } } - for (;want>0 && skills>0;) { + for (; want > 0 && skills > 0;) { int c, n; /* skip over everything that's already been done: @@ -666,17 +725,16 @@ build(unit * u, const construction * ctype, int completed, int want) * type->improvement==type means build another object of the same time * while material lasts type->improvement==x means build x when type * is finished */ - while (type->improvement!=NULL && - type->improvement!=type && - type->maxsize>0 && - type->maxsize<=completed) - { + while (type->improvement != NULL && + type->improvement != type && + type->maxsize > 0 && type->maxsize <= completed) { completed -= type->maxsize; type = type->improvement; } - if (type==NULL) { - if (made==0) return ECOMPLETE; - break; /* completed */ + if (type == NULL) { + if (made == 0) + return ECOMPLETE; + break; /* completed */ } /* Hier ist entweder maxsize == -1, oder completed < maxsize. @@ -684,15 +742,16 @@ build(unit * u, const construction * ctype, int completed, int want) * (enno): Nein, das ist für Dinge, bei denen die nächste Ausbaustufe * die gleiche wie die vorherige ist. z.b. gegenstände. */ - if (type->maxsize>1) { + if (type->maxsize > 1) { completed = completed % type->maxsize; - } - else { - completed = 0; assert(type->reqsize>=1); + } else { + completed = 0; + assert(type->reqsize >= 1); } if (basesk < type->minskill) { - if (made==0) return ELOWSKILL; /* not good enough to go on */ + if (made == 0) + return ELOWSKILL; /* not good enough to go on */ } /* n = maximum buildable size */ @@ -703,70 +762,96 @@ build(unit * u, const construction * ctype, int completed, int want) } /* Flinkfingerring wirkt nicht auf Mengenbegrenzte (magische) * Talente */ - if (skill_limit(u->faction, type->skill)==INT_MAX) { + if (skill_limit(u->faction, type->skill) == INT_MAX) { int i = 0; - item * itm = *i_find(&u->items, olditemtype[I_RING_OF_NIMBLEFINGER]); - if (itm!=NULL) i = itm->number; - if (i>0) { + + item *itm = *i_find(&u->items, olditemtype[I_RING_OF_NIMBLEFINGER]); + + if (itm != NULL) + i = itm->number; + if (i > 0) { int rings = MIN(u->number, i); - n = n * ((roqf_factor()-1)*rings+u->number) / u->number; + + n = n * ((roqf_factor() - 1) * rings + u->number) / u->number; } } - if (want>0) { + if (want > 0) { n = MIN(want, n); } - if (type->maxsize>0) { - n = MIN(type->maxsize-completed, n); - if (type->improvement==NULL) { + if (type->maxsize > 0) { + n = MIN(type->maxsize - completed, n); + if (type->improvement == NULL) { want = n; } } - if (type->materials) for (c=0;n>0 && type->materials[c].number;c++) { - const struct resource_type * rtype = type->materials[c].rtype; - int need, prebuilt; - int canuse = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); + if (type->materials) + for (c = 0; n > 0 && type->materials[c].number; c++) { + const struct resource_type *rtype = type->materials[c].rtype; - if (inside_building(u)) { - canuse = matmod(u->building->type->attribs, u, rtype, canuse); - } + int need, prebuilt; - if (canuse<0) return canuse; /* pass errors to caller */ - canuse = matmod(type->attribs, u, rtype, canuse); - if (type->reqsize>1) { - prebuilt = required(completed, type->reqsize, type->materials[c].number); - for (;n;) { - need = required(completed + n, type->reqsize, type->materials[c].number); - if (need-prebuilt<=canuse) break; - --n; /* TODO: optimieren? */ + int canuse = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); + + if (inside_building(u)) { + canuse = matmod(u->building->type->attribs, u, rtype, canuse); + } + + if (canuse < 0) + return canuse; /* pass errors to caller */ + canuse = matmod(type->attribs, u, rtype, canuse); + if (type->reqsize > 1) { + prebuilt = + required(completed, type->reqsize, type->materials[c].number); + for (; n;) { + need = + required(completed + n, type->reqsize, type->materials[c].number); + if (need - prebuilt <= canuse) + break; + --n; /* TODO: optimieren? */ + } + } else { + int maxn = canuse / type->materials[c].number; + + if (maxn < n) + n = maxn; } - } else { - int maxn = canuse / type->materials[c].number; - if (maxn < n) n = maxn; } + if (n <= 0) { + if (made == 0) + return ENOMATERIALS; + else + break; } - if (n<=0) { - if (made==0) return ENOMATERIALS; - else break; - } - if (type->materials) for (c=0;type->materials[c].number;c++) { - const struct resource_type * rtype = type->materials[c].rtype; - int prebuilt = required(completed, type->reqsize, type->materials[c].number); - int need = required(completed + n, type->reqsize, type->materials[c].number); - int multi = 1; - int canuse = 100; /* normalization */ - if (inside_building(u)) canuse = matmod(u->building->type->attribs, u, rtype, canuse); - if (canuse<0) return canuse; /* pass errors to caller */ - canuse = matmod(type->attribs, u, rtype, canuse); + if (type->materials) + for (c = 0; type->materials[c].number; c++) { + const struct resource_type *rtype = type->materials[c].rtype; - assert(canuse % 100 == 0 || !"only constant multipliers are implemented in build()"); - multi = canuse/100; - if (canuse<0) return canuse; /* pass errors to caller */ + int prebuilt = + required(completed, type->reqsize, type->materials[c].number); + int need = + required(completed + n, type->reqsize, type->materials[c].number); + int multi = 1; - use_pooled(u, rtype, GET_DEFAULT, (need-prebuilt+multi-1)/multi); - } + int canuse = 100; /* normalization */ + + if (inside_building(u)) + canuse = matmod(u->building->type->attribs, u, rtype, canuse); + if (canuse < 0) + return canuse; /* pass errors to caller */ + canuse = matmod(type->attribs, u, rtype, canuse); + + assert(canuse % 100 == 0 + || !"only constant multipliers are implemented in build()"); + multi = canuse / 100; + if (canuse < 0) + return canuse; /* pass errors to caller */ + + use_pooled(u, rtype, GET_DEFAULT, + (need - prebuilt + multi - 1) / multi); + } made += n; skills -= n * type->minskill; want -= n; @@ -778,16 +863,19 @@ build(unit * u, const construction * ctype, int completed, int want) return made; } -message * -msg_materials_required(unit * u, order * ord, const construction * ctype, int multi) +message *msg_materials_required(unit * u, order * ord, + const construction * ctype, int multi) { int c; - /* something missing from the list of materials */ - resource * reslist = NULL; - if (multi<=0 || multi==INT_MAX) multi = 1; - for (c=0;ctype->materials[c].number; ++c) { - resource * res = malloc(sizeof(resource)); + /* something missing from the list of materials */ + resource *reslist = NULL; + + if (multi <= 0 || multi == INT_MAX) + multi = 1; + for (c = 0; ctype->materials[c].number; ++c) { + resource *res = malloc(sizeof(resource)); + res->number = multi * ctype->materials[c].number / ctype->reqsize; res->type = ctype->materials[c].rtype; res->next = reslist; @@ -796,21 +884,25 @@ msg_materials_required(unit * u, order * ord, const construction * ctype, int mu return msg_feedback(u, ord, "build_required", "required", reslist); } -int -maxbuild(const unit * u, const construction * cons) +int maxbuild(const unit * u, const construction * cons) /* calculate maximum size that can be built from available material */ - /* !! ignores maximum objectsize and improvements...*/ + /* !! ignores maximum objectsize and improvements... */ { int c; + int maximum = INT_MAX; - for (c=0;cons->materials[c].number;c++) { - const resource_type * rtype = cons->materials[c].rtype; + + for (c = 0; cons->materials[c].number; c++) { + const resource_type *rtype = cons->materials[c].rtype; + int have = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); + int need = required(1, cons->reqsize, cons->materials[c].number); - if (haveregion; + region *r = u->region; + boolean newbuilding = false; + int n = want, built = 0, id; - building * b = NULL; + + building *b = NULL; + /* einmalige Korrektur */ - const char * btname; - order * new_order = NULL; - const struct locale * lang = u->faction->locale; + const char *btname; + + order *new_order = NULL; + + const struct locale *lang = u->faction->locale; + static int rule_other = -1; assert(u->number); @@ -843,11 +942,11 @@ build_building(unit * u, const building_type * btype, int want, order * ord) /* Wenn die angegebene Nummer falsch ist, KEINE Burg bauen! */ id = getid(); - if (id>0) { /* eine Nummer angegeben, keine neue Burg bauen */ + if (id > 0) { /* eine Nummer angegeben, keine neue Burg bauen */ b = findbuilding(id); if (!b || b->region != u->region) { /* eine Burg mit dieser Nummer gibt es hier nicht */ /* vieleicht Tippfehler und die eigene Burg ist gemeint? */ - if (u->building && u->building->type==btype) { + if (u->building && u->building->type == btype) { b = u->building; } else { /* keine neue Burg anfangen wenn eine Nummer angegeben war */ @@ -855,11 +954,12 @@ build_building(unit * u, const building_type * btype, int want, order * ord) return; } } - } else if (u->building && u->building->type==btype) { + } else if (u->building && u->building->type == btype) { b = u->building; } - if (b) btype = b->type; + if (b) + btype = b->type; if (b && fval(btype, BTF_UNIQUE) && buildingtype_exists(r, btype, false)) { /* only one of these per region */ @@ -876,35 +976,38 @@ build_building(unit * u, const building_type * btype, int want, order * ord) cmistake(u, ord, 221, MSG_PRODUCE); return; } - if (r->terrain->max_road<=0) { + if (r->terrain->max_road <= 0) { /* special terrain, cannot build */ cmistake(u, ord, 221, MSG_PRODUCE); return; } if (btype->flags & BTF_ONEPERTURN) { - if(b && fval(b, BLD_EXPANDED)) { + if (b && fval(b, BLD_EXPANDED)) { cmistake(u, ord, 318, MSG_PRODUCE); return; } n = 1; } if (b) { - if (rule_other<0) { - rule_other = get_param_int(global.parameters, "rules.build.other_buildings", 1); + if (rule_other < 0) { + rule_other = + get_param_int(global.parameters, "rules.build.other_buildings", 1); } if (!rule_other) { - unit * owner = building_owner(b); - if (!owner || owner->faction!=u->faction) { + unit *owner = building_owner(b); + + if (!owner || owner->faction != u->faction) { cmistake(u, ord, 1222, MSG_PRODUCE); return; } } } - if (b) built = b->size; - if (n<=0 || n == INT_MAX) { - if(b == NULL) { - if(btype->maxsize > 0) { + if (b) + built = b->size; + if (n <= 0 || n == INT_MAX) { + if (b == NULL) { + if (btype->maxsize > 0) { n = btype->maxsize - built; } else { n = INT_MAX; @@ -920,23 +1023,24 @@ build_building(unit * u, const building_type * btype, int want, order * ord) built = build(u, btype->construction, built, n); switch (built) { - case ECOMPLETE: - /* the building is already complete */ - cmistake(u, ord, 4, MSG_PRODUCE); - return; - case ENOMATERIALS: - ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, btype->construction, want)); - return; - case ELOWSKILL: - case ENEEDSKILL: - /* no skill, or not enough skill points to build */ - cmistake(u, ord, 50, MSG_PRODUCE); - return; + case ECOMPLETE: + /* the building is already complete */ + cmistake(u, ord, 4, MSG_PRODUCE); + return; + case ENOMATERIALS: + ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, + btype->construction, want)); + return; + case ELOWSKILL: + case ENEEDSKILL: + /* no skill, or not enough skill points to build */ + cmistake(u, ord, 50, MSG_PRODUCE); + return; } /* at this point, the building size is increased. */ - if (b==NULL) { + if (b == NULL) { /* build a new building */ b = new_building(btype, r, lang); b->type = btype; @@ -947,10 +1051,10 @@ build_building(unit * u, const building_type * btype, int want, order * ord) u->building = b; fset(u, UFL_OWNER); } - #ifdef WDW_PYRAMID - if(b->type == bt_find("pyramid") && f_get_alliance(u->faction) != NULL) { - attrib * a = a_add(&b->attribs, a_new(&at_alliance)); + if (b->type == bt_find("pyramid") && f_get_alliance(u->faction) != NULL) { + attrib *a = a_add(&b->attribs, a_new(&at_alliance)); + a->data.i = u->faction->alliance->id; } #endif @@ -960,20 +1064,24 @@ build_building(unit * u, const building_type * btype, int want, order * ord) btname = LOC(lang, btype->_name); - if (want-built <= 0) { + if (want - built <= 0) { /* gebäude fertig */ new_order = default_order(lang); - } else if (want!=INT_MAX) { + } else if (want != INT_MAX) { /* reduzierte restgröße */ - const char * hasspace = strchr(btname, ' '); + const char *hasspace = strchr(btname, ' '); + if (hasspace) { - new_order = create_order(K_MAKE, lang, "%d \"%s\" %i", n-built, btname, b->no); + new_order = + create_order(K_MAKE, lang, "%d \"%s\" %i", n - built, btname, b->no); } else { - new_order = create_order(K_MAKE, lang, "%d %s %i", n-built, btname, b->no); + new_order = + create_order(K_MAKE, lang, "%d %s %i", n - built, btname, b->no); } } else if (btname) { /* Neues Haus, Befehl mit Gebäudename */ - const char * hasspace = strchr(btname, ' '); + const char *hasspace = strchr(btname, ' '); + if (hasspace) { new_order = create_order(K_MAKE, lang, "\"%s\" %i", btname, b->no); } else { @@ -993,47 +1101,55 @@ build_building(unit * u, const building_type * btype, int want, order * ord) ADDMSG(&u->faction->msgs, msg_message("buildbuilding", - "building unit size", b, u, built)); + "building unit size", b, u, built)); } -static void -build_ship(unit * u, ship * sh, int want) +static void build_ship(unit * u, ship * sh, int want) { - const construction * construction = sh->type->construction; + const construction *construction = sh->type->construction; + int size = (sh->size * DAMAGE_SCALE - sh->damage) / DAMAGE_SCALE; + int n; + int can = build(u, construction, size, want); - if ((n=construction->maxsize - sh->size)>0 && can>0) { - if (can>=n) { - sh->size += n; - can -= n; - } - else { - sh->size += can; - n=can; - can = 0; + if ((n = construction->maxsize - sh->size) > 0 && can > 0) { + if (can >= n) { + sh->size += n; + can -= n; + } else { + sh->size += can; + n = can; + can = 0; } } if (sh->damage && can) { int repair = MIN(sh->damage, can * DAMAGE_SCALE); + n += repair / DAMAGE_SCALE; - if (repair % DAMAGE_SCALE) ++n; + if (repair % DAMAGE_SCALE) + ++n; sh->damage = sh->damage - repair; } - if (n) ADDMSG(&u->faction->msgs, - msg_message("buildship", "ship unit size", sh, u, n)); + if (n) + ADDMSG(&u->faction->msgs, + msg_message("buildship", "ship unit size", sh, u, n)); } void -create_ship(region * r, unit * u, const struct ship_type * newtype, int want, order * ord) +create_ship(region * r, unit * u, const struct ship_type *newtype, int want, + order * ord) { ship *sh; + int msize; - const construction * cons = newtype->construction; - order * new_order; + + const construction *cons = newtype->construction; + + order *new_order; if (!eff_skill(u, SK_SHIPBUILDING, r)) { cmistake(u, ord, 100, MSG_PRODUCE); @@ -1046,18 +1162,21 @@ create_ship(region * r, unit * u, const struct ship_type * newtype, int want, or /* check if skill and material for 1 size is available */ if (eff_skill(u, cons->skill, r) < cons->minskill) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_build_skill_low", "value name", - cons->minskill, newtype->name[1])); + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, + "error_build_skill_low", "value name", cons->minskill, + newtype->name[1])); return; } msize = maxbuild(u, cons); - if (msize==0) { + if (msize == 0) { cmistake(u, ord, 88, MSG_PRODUCE); return; } - if (want>0) want = MIN(want, msize); - else want = msize; + if (want > 0) + want = MIN(want, msize); + else + want = msize; sh = new_ship(newtype, u->faction->locale, r); @@ -1067,18 +1186,21 @@ create_ship(region * r, unit * u, const struct ship_type * newtype, int want, or fset(u, UFL_OWNER); } } - new_order = create_order(K_MAKE, u->faction->locale, "%s %i", LOC(u->faction->locale, parameters[P_SHIP]), sh->no); + new_order = + create_order(K_MAKE, u->faction->locale, "%s %i", LOC(u->faction->locale, + parameters[P_SHIP]), sh->no); replace_order(&u->orders, ord, new_order); free_order(new_order); build_ship(u, sh, want); } -void -continue_ship(region * r, unit * u, int want) +void continue_ship(region * r, unit * u, int want) { - const construction * cons; + const construction *cons; + ship *sh; + int msize; if (!eff_skill(u, SK_SHIPBUILDING, r)) { @@ -1089,60 +1211,65 @@ continue_ship(region * r, unit * u, int want) /* Die Schiffsnummer bzw der Schiffstyp wird eingelesen */ sh = getship(r); - if (!sh) sh = u->ship; + if (!sh) + sh = u->ship; if (!sh) { cmistake(u, u->thisorder, 20, MSG_PRODUCE); return; } cons = sh->type->construction; - assert(cons->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */ - if (sh->size==cons->maxsize && !sh->damage) { + assert(cons->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (sh->size == cons->maxsize && !sh->damage) { cmistake(u, u->thisorder, 16, MSG_PRODUCE); return; } if (eff_skill(u, cons->skill, r) < cons->minskill) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_build_skill_low", "value name", - cons->minskill, sh->type->name[1])); + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, + "error_build_skill_low", "value name", cons->minskill, + sh->type->name[1])); return; } msize = maxbuild(u, cons); - if (msize==0) { + if (msize == 0) { cmistake(u, u->thisorder, 88, MSG_PRODUCE); return; } - if (want > 0) want = MIN(want, msize); - else want = msize; + if (want > 0) + want = MIN(want, msize); + else + want = msize; build_ship(u, sh, want); } + /* ------------------------------------------------------------- */ -static boolean -mayenter(region * r, unit * u, building * b) +static boolean mayenter(region * r, unit * u, building * b) { unit *u2; - if (fval(b, BLD_UNGUARDED)) return true; + + if (fval(b, BLD_UNGUARDED)) + return true; u2 = building_owner(b); - if (u2==NULL || ucontact(u2, u) - || alliedunit(u2, u->faction, HELP_GUARD)) return true; + if (u2 == NULL || ucontact(u2, u) + || alliedunit(u2, u->faction, HELP_GUARD)) + return true; return false; } -static int -mayboard(const unit * u, const ship * sh) +static int mayboard(const unit * u, const ship * sh) { unit *u2 = shipowner(sh); return (!u2 || ucontact(u2, u) || alliedunit(u2, u->faction, HELP_GUARD)); } -int -leave_cmd(unit * u, struct order * ord) +int leave_cmd(unit * u, struct order *ord) { - region * r = u->region; + region *r = u->region; if (fval(u, UFL_ENTER)) { /* if we just entered this round, then we don't leave again */ @@ -1150,7 +1277,7 @@ leave_cmd(unit * u, struct order * ord) } if (fval(r->terrain, SEA_REGION) && u->ship) { - if(!fval(u->race, RCF_SWIM)) { + if (!fval(u->race, RCF_SWIM)) { cmistake(u, ord, 11, MSG_MOVE); return 0; } @@ -1160,53 +1287,62 @@ leave_cmd(unit * u, struct order * ord) } } if (!slipthru(r, u, u->building)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "entrance_besieged", "building", u->building)); + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "entrance_besieged", + "building", u->building)); } else { leave(u, true); } return 0; } -static boolean -enter_ship(unit * u, struct order * ord, int id, boolean report) +static boolean enter_ship(unit * u, struct order *ord, int id, boolean report) { - region * r = u->region; - ship * sh; + region *r = u->region; + + ship *sh; /* Muß abgefangen werden, sonst könnten Schwimmer an * Bord von Schiffen an Land gelangen. */ - if (!fval(u->race, RCF_CANSAIL) || (!fval(u->race, RCF_WALK) && !fval(u->race, RCF_FLY))) { + if (!fval(u->race, RCF_CANSAIL) || (!fval(u->race, RCF_WALK) + && !fval(u->race, RCF_FLY))) { cmistake(u, ord, 233, MSG_MOVE); return false; } sh = findship(id); - if (sh == NULL || sh->region!=r) { - if (report) cmistake(u, ord, 20, MSG_MOVE); + if (sh == NULL || sh->region != r) { + if (report) + cmistake(u, ord, 20, MSG_MOVE); return false; } - if (sh==u->ship) return true; + if (sh == u->ship) + return true; if (!mayboard(u, sh)) { - if (report) cmistake(u, ord, 34, MSG_MOVE); + if (report) + cmistake(u, ord, 34, MSG_MOVE); return false; } if (CheckOverload()) { int sweight, scabins; + int mweight = shipcapacity(sh); + int mcabins = sh->type->cabins; - - if (mweight>0) { + + if (mweight > 0) { getshipweight(sh, &sweight, &scabins); sweight += weight(u); if (mcabins) { int pweight = u->number * u->race->weight; + /* weight goes into number of cabins, not cargo */ scabins += pweight; sweight -= pweight; } if (sweight > mweight || (mcabins && (scabins > mcabins))) { - if (report) cmistake(u, ord, 34, MSG_MOVE); + if (report) + cmistake(u, ord, 34, MSG_MOVE); return false; } } @@ -1223,14 +1359,14 @@ enter_ship(unit * u, struct order * ord, int id, boolean report) return true; } -static boolean -enter_building(unit * u, order * ord, int id, boolean report) +static boolean enter_building(unit * u, order * ord, int id, boolean report) { - region * r = u->region; - building * b; + region *r = u->region; + + building *b; /* Schwimmer können keine Gebäude betreten, außer diese sind - * auf dem Ozean */ + * auf dem Ozean */ if (!fval(u->race, RCF_WALK) && !fval(u->race, RCF_FLY)) { if (!fval(r->terrain, SEA_REGION)) { if (report) { @@ -1241,7 +1377,7 @@ enter_building(unit * u, order * ord, int id, boolean report) } b = findbuilding(id); - if (b==NULL || b->region!=r) { + if (b == NULL || b->region != r) { if (report) { cmistake(u, ord, 6, MSG_MOVE); } @@ -1249,13 +1385,15 @@ enter_building(unit * u, order * ord, int id, boolean report) } if (!mayenter(r, u, b)) { if (report) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "entrance_denied", "building", b)); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "entrance_denied", + "building", b)); } return false; } if (!slipthru(r, u, b)) { if (report) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "entrance_besieged", "building", b)); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "entrance_besieged", + "building", b)); } return false; } @@ -1271,32 +1409,36 @@ enter_building(unit * u, order * ord, int id, boolean report) return false; } -void -do_misc(region * r, boolean lasttry) +void do_misc(region * r, boolean lasttry) { unit **uptr, *uc; for (uc = r->units; uc; uc = uc->next) { - order * ord; + order *ord; + for (ord = uc->orders; ord; ord = ord->next) { switch (get_keyword(ord)) { - case K_CONTACT: - contact_cmd(uc, ord, lasttry); - break; + case K_CONTACT: + contact_cmd(uc, ord, lasttry); + break; } } } for (uptr = &r->units; *uptr;) { - unit * u = *uptr; - order ** ordp = &u->orders; + unit *u = *uptr; + + order **ordp = &u->orders; while (*ordp) { - order * ord = *ordp; + order *ord = *ordp; + if (get_keyword(ord) == K_ENTER) { param_t p; + int id; - unit * ulast = NULL; + + unit *ulast = NULL; init_tokens(ord); skip_token(); @@ -1304,45 +1446,50 @@ do_misc(region * r, boolean lasttry) id = getid(); switch (p) { - case P_BUILDING: - case P_GEBAEUDE: - if (u->building && u->building->no==id) break; - if (enter_building(u, ord, id, lasttry)) { - unit *ub; - for (ub=u;ub;ub=ub->next) { - if (ub->building==u->building) { - ulast = ub; + case P_BUILDING: + case P_GEBAEUDE: + if (u->building && u->building->no == id) + break; + if (enter_building(u, ord, id, lasttry)) { + unit *ub; + + for (ub = u; ub; ub = ub->next) { + if (ub->building == u->building) { + ulast = ub; + } } } - } - break; + break; - case P_SHIP: - if (u->ship && u->ship->no==id) break; - if (enter_ship(u, ord, id, lasttry)) { - unit *ub; - ulast = u; - for (ub=u;ub;ub=ub->next) { - if (ub->ship==u->ship) { - ulast = ub; + case P_SHIP: + if (u->ship && u->ship->no == id) + break; + if (enter_ship(u, ord, id, lasttry)) { + unit *ub; + + ulast = u; + for (ub = u; ub; ub = ub->next) { + if (ub->ship == u->ship) { + ulast = ub; + } } } - } - break; + break; - default: - if (lasttry) cmistake(u, ord, 79, MSG_MOVE); + default: + if (lasttry) + cmistake(u, ord, 79, MSG_MOVE); } - if (ulast!=NULL) { + if (ulast != NULL) { /* Wenn wir hier angekommen sind, war der Befehl - * erfolgreich und wir löschen ihn, damit er im - * zweiten Versuch nicht nochmal ausgeführt wird. */ + * erfolgreich und wir löschen ihn, damit er im + * zweiten Versuch nicht nochmal ausgeführt wird. */ *ordp = ord->next; ord->next = NULL; free_order(ord); - if (ulast!=u) { + if (ulast != u) { /* put u behind ulast so it's the last unit in the building */ *uptr = u->next; u->next = ulast->next; @@ -1351,8 +1498,10 @@ do_misc(region * r, boolean lasttry) break; } } - if (*ordp==ord) ordp = &ord->next; + if (*ordp == ord) + ordp = &ord->next; } - if (*uptr==u) uptr = &u->next; + if (*uptr == u) + uptr = &u->next; } } diff --git a/src/kernel/build.h b/src/kernel/build.h index 012f06000..710f103f3 100644 --- a/src/kernel/build.h +++ b/src/kernel/build.h @@ -30,61 +30,65 @@ extern "C" { * wichtig */ -struct xml_tag; + struct xml_tag; -typedef struct requirement { - const struct resource_type * rtype; - int number; - double recycle; /* recycling quota */ -} requirement; + typedef struct requirement { + const struct resource_type *rtype; + int number; + double recycle; /* recycling quota */ + } requirement; -typedef struct construction { - skill_t skill; /* skill req'd per point of size */ - int minskill; /* skill req'd per point of size */ + typedef struct construction { + skill_t skill; /* skill req'd per point of size */ + int minskill; /* skill req'd per point of size */ - int maxsize; /* maximum size of this type */ - int reqsize; /* size of object using up 1 set of requirement. */ - requirement * materials; /* material req'd to build one object */ - const struct building_type * btype; - /* building type required to make this thing */ + int maxsize; /* maximum size of this type */ + int reqsize; /* size of object using up 1 set of requirement. */ + requirement *materials; /* material req'd to build one object */ + const struct building_type *btype; + /* building type required to make this thing */ - struct construction * improvement; - /* next level, if upgradable. if more than one of these items - * can be built (weapons, armour) per turn, must not be NULL, - * but point to the same type again: - * const_sword.improvement = &const_sword - * last level of a building points to NULL, as do objects of - * an unlimited size. - */ - struct attrib * attribs; - /* stores skill modifiers and other attributes */ + struct construction *improvement; + /* next level, if upgradable. if more than one of these items + * can be built (weapons, armour) per turn, must not be NULL, + * but point to the same type again: + * const_sword.improvement = &const_sword + * last level of a building points to NULL, as do objects of + * an unlimited size. + */ + struct attrib *attribs; + /* stores skill modifiers and other attributes */ -} construction; + } construction; -extern int destroy_cmd(struct unit * u, struct order * ord); -extern int leave_cmd(struct unit * u, struct order * ord); + extern int destroy_cmd(struct unit *u, struct order *ord); + extern int leave_cmd(struct unit *u, struct order *ord); -extern boolean can_contact(const struct region *r, const struct unit *u, const struct unit *u2); + extern boolean can_contact(const struct region *r, const struct unit *u, + const struct unit *u2); -void do_siege(struct region *r); -void build_road(struct region * r, struct unit * u, int size, direction_t d); -void create_ship(struct region * r, struct unit * u, const struct ship_type * newtype, int size, struct order * ord); -void continue_ship(struct region * r, struct unit * u, int size); + void do_siege(struct region *r); + void build_road(struct region *r, struct unit *u, int size, direction_t d); + void create_ship(struct region *r, struct unit *u, + const struct ship_type *newtype, int size, struct order *ord); + void continue_ship(struct region *r, struct unit *u, int size); -struct building * getbuilding(const struct region * r); -struct ship *getship(const struct region * r); + struct building *getbuilding(const struct region *r); + struct ship *getship(const struct region *r); -void do_misc(struct region *r, boolean tries); + void do_misc(struct region *r, boolean tries); -void reportevent(struct region * r, char *s); + void reportevent(struct region *r, char *s); -void shash(struct ship * sh); -void sunhash(struct ship * sh); -extern int roqf_factor(void); + void shash(struct ship *sh); + void sunhash(struct ship *sh); + extern int roqf_factor(void); -extern int build(struct unit * u, const construction * ctype, int completed, int want); -extern int maxbuild(const struct unit *u, const construction *cons); -extern struct message * msg_materials_required(struct unit * u, struct order * ord, const struct construction * ctype, int multi); + extern int build(struct unit *u, const construction * ctype, int completed, + int want); + extern int maxbuild(const struct unit *u, const construction * cons); + extern struct message *msg_materials_required(struct unit *u, + struct order *ord, const struct construction *ctype, int multi); /** error messages that build may return: */ #define ELOWSKILL -1 #define ENEEDSKILL -2 @@ -96,4 +100,3 @@ extern struct message * msg_materials_required(struct unit * u, struct order * o } #endif #endif - diff --git a/src/kernel/building.c b/src/kernel/building.c index 509cb6d1a..2c4f3ed0a 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -23,7 +23,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* kernel includes */ #include "item.h" -#include "curse.h" /* für C_NOCOST */ +#include "curse.h" /* für C_NOCOST */ #include "unit.h" #include "faction.h" #include "region.h" @@ -52,111 +52,120 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* attributes includes */ #include -static const char * NULLSTRING = "(null)"; +static const char *NULLSTRING = "(null)"; -static void -lc_init(struct attrib *a) +static void lc_init(struct attrib *a) { a->data.v = calloc(1, sizeof(building_action)); } -static void -lc_done(struct attrib *a) +static void lc_done(struct attrib *a) { - building_action * data = (building_action*)a->data.v; - if (data->fname) free(data->fname); - if (data->param) free(data->param); + building_action *data = (building_action *) a->data.v; + + if (data->fname) + free(data->fname); + if (data->param) + free(data->param); 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; - const char * fparam = data->param; - building * b = data->b; + building_action *data = (building_action *) a->data.v; + + const char *fname = data->fname; + + const char *fparam = data->param; + + building *b = data->b; write_building_reference(b, store); store->w_tok(store, fname); - store->w_tok(store, fparam?fparam:NULLSTRING); + store->w_tok(store, fparam ? fparam : NULLSTRING); } -static int -lc_read(struct attrib * a, void * owner, struct storage * store) +static int lc_read(struct attrib *a, void *owner, struct storage *store) { - building_action * data = (building_action*)a->data.v; - int result = read_reference(&data->b, store, read_building_reference, resolve_building); - if (store->versiondata.v; + + int result = + read_reference(&data->b, store, read_building_reference, resolve_building); + if (store->version < UNICODE_VERSION) { data->fname = store->r_str(store); } else { data->fname = store->r_tok(store); } - if (store->version>=BACTION_VERSION) { + if (store->version >= BACTION_VERSION) { char lbuf[256]; - if (store->versionversion < UNICODE_VERSION) { store->r_str_buf(store, lbuf, sizeof(lbuf)); } else { store->r_tok_buf(store, lbuf, sizeof(lbuf)); } - if (strcmp(lbuf, NULLSTRING)==0) data->param = NULL; - else data->param = strdup(lbuf); + if (strcmp(lbuf, NULLSTRING) == 0) + data->param = NULL; + else + data->param = strdup(lbuf); } else { data->param = strdup(NULLSTRING); } - if (result==0 && !data->b) { + if (result == 0 && !data->b) { return AT_READ_FAIL; } return AT_READ_OK; } attrib_type at_building_action = { - "lcbuilding", - lc_init, lc_done, - NULL, + "lcbuilding", + lc_init, lc_done, + NULL, lc_write, lc_read }; typedef struct building_typelist { - struct building_typelist * next; - building_type * type; + struct building_typelist *next; + building_type *type; } building_typelist; static building_typelist *buildingtypes; -building_type * -bt_find(const char* name) +building_type *bt_find(const char *name) { - const struct building_typelist * btl = buildingtypes; + const struct building_typelist *btl = buildingtypes; + assert(name); - while (btl && strcmp(btl->type->_name, name)) btl = btl->next; - if (btl==NULL) { + while (btl && strcmp(btl->type->_name, name)) + btl = btl->next; + if (btl == NULL) { return NULL; } return btl->type; } -void -bt_register(building_type * type) +void bt_register(building_type * type) { - struct building_typelist * btl = malloc(sizeof(building_type)); - if (type->init) type->init(type); - btl->type = type; - btl->next = buildingtypes; - buildingtypes = btl; + struct building_typelist *btl = malloc(sizeof(building_type)); + + if (type->init) + type->init(type); + btl->type = type; + btl->next = buildingtypes; + buildingtypes = btl; } -int -buildingcapacity(const building * b) +int buildingcapacity(const building * b) { - if (b->type->capacity>=0) { - if (b->type->maxcapacity>=0) { + if (b->type->capacity >= 0) { + if (b->type->maxcapacity >= 0) { return MIN(b->type->maxcapacity, b->size * b->type->capacity); } return b->size * b->type->capacity; } - if (b->size>=b->type->maxsize) { - if (b->type->maxcapacity>=0) { + if (b->size >= b->type->maxsize) { + if (b->type->maxcapacity >= 0) { return b->type->maxcapacity; } } @@ -164,15 +173,18 @@ buildingcapacity(const building * b) } attrib_type at_building_generic_type = { - "building_generic_type", NULL, NULL, NULL, a_writestring, a_readstring, ATF_UNIQUE + "building_generic_type", NULL, NULL, NULL, a_writestring, a_readstring, + ATF_UNIQUE }; -const char * -buildingtype(const building_type * btype, const building * b, int bsize) +const char *buildingtype(const building_type * btype, const building * b, + int bsize) { - const char * s = NULL; + const char *s = NULL; + static boolean init_generic = false; - static const struct building_type * bt_generic; + + static const struct building_type *bt_generic; if (!init_generic) { init_generic = true; @@ -181,18 +193,22 @@ buildingtype(const building_type * btype, const building * b, int bsize) if (btype == bt_generic) { const attrib *a = a_find(b->attribs, &at_building_generic_type); - if (a) s = (const char*)a->data.v; + + if (a) + s = (const char *)a->data.v; } - if (btype->name) s = btype->name(btype, b, bsize); - if (s==NULL) s = btype->_name; + if (btype->name) + s = btype->name(btype, b, bsize); + if (s == NULL) + s = btype->_name; return s; } #define BMAXHASH 7919 static building *buildhash[BMAXHASH]; -void -bhash(building * b) + +void bhash(building * b) { building *old = buildhash[b->no % BMAXHASH]; @@ -200,8 +216,7 @@ bhash(building * b) b->nexthash = old; } -void -bunhash(building * b) +void bunhash(building * b) { building **show; @@ -216,58 +231,59 @@ bunhash(building * b) } } -static building * -bfindhash(int i) +static building *bfindhash(int i) { - building *old; + building *old; - for (old = buildhash[i % BMAXHASH]; old; old = old->nexthash) - if (old->no == i) - return old; - return 0; + for (old = buildhash[i % BMAXHASH]; old; old = old->nexthash) + if (old->no == i) + return old; + return 0; } -building * -findbuilding(int i) +building *findbuilding(int i) { - return bfindhash(i); + return bfindhash(i); } + /* ** old building types ** */ -static int -sm_smithy(const unit * u, const region * r, skill_t sk, int value) /* skillmod */ -{ - if (sk==SK_WEAPONSMITH || sk==SK_ARMORER) { - if (u->region == r) return value + 1; - } - return value; -} -static int -mm_smithy(const unit * u, const resource_type * rtype, int value) /* material-mod */ -{ - if (rtype == oldresourcetype[R_IRON]) return value * 2; - return value; -} -static void -init_smithy(struct building_type * bt) -{ - a_add(&bt->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION, sm_smithy, 1.0, 0)); - a_add(&bt->attribs, make_matmod(mm_smithy)); +static int sm_smithy(const unit * u, const region * r, skill_t sk, int value) +{ /* skillmod */ + if (sk == SK_WEAPONSMITH || sk == SK_ARMORER) { + if (u->region == r) + return value + 1; + } + return value; } -static const char * -castle_name_i(const struct building_type* btype, const struct building * b, int bsize, const char * fname[]) +static int mm_smithy(const unit * u, const resource_type * rtype, int value) +{ /* material-mod */ + if (rtype == oldresourcetype[R_IRON]) + return value * 2; + return value; +} + +static void init_smithy(struct building_type *bt) +{ + a_add(&bt->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION, sm_smithy, 1.0, + 0)); + a_add(&bt->attribs, make_matmod(mm_smithy)); +} + +static const char *castle_name_i(const struct building_type *btype, + const struct building *b, int bsize, const char *fname[]) { int i = bt_effsize(btype, b, bsize); return fname[i]; } -static const char * -castle_name_2(const struct building_type* btype, const struct building * b, int bsize) +static const char *castle_name_2(const struct building_type *btype, + const struct building *b, int bsize) { - const char * fname[] = { + const char *fname[] = { "site", "fortification", "tower", @@ -278,10 +294,10 @@ castle_name_2(const struct building_type* btype, const struct building * b, int return castle_name_i(btype, b, bsize, fname); } -static const char * -castle_name(const struct building_type* btype, const struct building * b, int bsize) +static const char *castle_name(const struct building_type *btype, + const struct building *b, int bsize) { - const char * fname[] = { + const char *fname[] = { "site", "tradepost", "fortification", @@ -293,10 +309,10 @@ castle_name(const struct building_type* btype, const struct building * b, int bs return castle_name_i(btype, b, bsize, fname); } -static const char * -fort_name(const struct building_type* btype, const struct building * b, int bsize) +static const char *fort_name(const struct building_type *btype, + const struct building *b, int bsize) { - const char * fname[] = { + const char *fname[] = { "scaffolding", "guardhouse", "guardtower", @@ -306,18 +322,19 @@ fort_name(const struct building_type* btype, const struct building * b, int bsiz #ifdef WDW_PYRAMID -static const char * -pyramid_name(const struct building_type* btype, int bsize) +static const char *pyramid_name(const struct building_type *btype, int bsize) { static char p_name_buf[32]; - int level=0; - const construction * ctype; + + int level = 0; + + const construction *ctype; ctype = btype->construction; - - while (ctype && ctype->maxsize != -1 && ctype->maxsize<=bsize) { - bsize-=ctype->maxsize; - ctype=ctype->improvement; + + while (ctype && ctype->maxsize != -1 && ctype->maxsize <= bsize) { + bsize -= ctype->maxsize; + ctype = ctype->improvement; ++level; } @@ -326,20 +343,19 @@ pyramid_name(const struct building_type* btype, int bsize) return p_name_buf; } -int -wdw_pyramid_level(const struct building *b) +int wdw_pyramid_level(const struct building *b) { const construction *ctype = b->type->construction; + int completed = b->size; + int level = 0; - while(ctype->improvement != NULL && - ctype->improvement != ctype && - ctype->maxsize > 0 && - ctype->maxsize <= completed) - { + while (ctype->improvement != NULL && + ctype->improvement != ctype && + ctype->maxsize > 0 && ctype->maxsize <= completed) { ++level; - completed-=ctype->maxsize; + completed -= ctype->maxsize; ctype = ctype->improvement; } @@ -349,114 +365,125 @@ wdw_pyramid_level(const struct building *b) /* for finding out what was meant by a particular building string */ -static local_names * bnames; +static local_names *bnames; -const building_type * -findbuildingtype(const char * name, const struct locale * lang) +const building_type *findbuildingtype(const char *name, + const struct locale *lang) { variant type; - local_names * bn = bnames; - while (bn) { - if (bn->lang==lang) break; - bn=bn->next; - } - if (!bn) { - struct building_typelist * btl = buildingtypes; - bn = calloc(sizeof(local_names), 1); - bn->next = bnames; - bn->lang = lang; - while (btl) { - const char * n = locale_string(lang, btl->type->_name); - type.v = (void*)btl->type; - addtoken(&bn->names, n, type); - btl=btl->next; - } - bnames = bn; - } - if (findtoken(&bn->names, name, &type)==E_TOK_NOMATCH) return NULL; - return (const building_type*)type.v; + local_names *bn = bnames; + + while (bn) { + if (bn->lang == lang) + break; + bn = bn->next; + } + if (!bn) { + struct building_typelist *btl = buildingtypes; + + bn = calloc(sizeof(local_names), 1); + bn->next = bnames; + bn->lang = lang; + while (btl) { + const char *n = locale_string(lang, btl->type->_name); + + type.v = (void *)btl->type; + addtoken(&bn->names, n, type); + btl = btl->next; + } + bnames = bn; + } + if (findtoken(&bn->names, name, &type) == E_TOK_NOMATCH) + return NULL; + return (const building_type *)type.v; } static int eressea_building_protection(building * b, unit * u) { - int beff = buildingeffsize(b, false)-1; + int beff = buildingeffsize(b, false) - 1; + /* -1 because the tradepost has no protection value */ return beff; } -void -register_buildings(void) +void register_buildings(void) { - register_function((pf_generic)&eressea_building_protection, "eressea_building_protection"); - register_function((pf_generic)&init_smithy, "init_smithy"); - register_function((pf_generic)&castle_name, "castle_name"); - register_function((pf_generic)&castle_name_2, "castle_name_2"); - register_function((pf_generic)&fort_name, "fort_name"); + register_function((pf_generic) & eressea_building_protection, + "eressea_building_protection"); + register_function((pf_generic) & init_smithy, "init_smithy"); + register_function((pf_generic) & castle_name, "castle_name"); + register_function((pf_generic) & castle_name_2, "castle_name_2"); + register_function((pf_generic) & fort_name, "fort_name"); #ifdef WDW_PYRAMID - register_function((pf_generic)&pyramid_name, "pyramid_name"); + register_function((pf_generic) & pyramid_name, "pyramid_name"); #endif } -void -write_building_reference(const struct building * b, struct storage * store) +void write_building_reference(const struct building *b, struct storage *store) { - store->w_id(store, (b && b->region)?b->no:0); + store->w_id(store, (b && b->region) ? b->no : 0); } -int -resolve_building(variant id, void * address) +int resolve_building(variant id, void *address) { int result = 0; - building * b = NULL; - if (id.i!=0) { + + building *b = NULL; + + if (id.i != 0) { b = findbuilding(id.i); - if (b==NULL) { + if (b == NULL) { result = -1; } } - *(building**)address = b; + *(building **) address = b; return result; } -variant -read_building_reference(struct storage * store) +variant read_building_reference(struct storage * store) { variant result; + result.i = store->r_id(store); return result; } -building * -new_building(const struct building_type * btype, region * r, const struct locale * lang) +building *new_building(const struct building_type * btype, region * r, + const struct locale * lang) { - building ** bptr = &r->buildings; + building **bptr = &r->buildings; + building *b = (building *) calloc(1, sizeof(building)); + static boolean init_lighthouse = false; - static const struct building_type * bt_lighthouse = 0; + + static const struct building_type *bt_lighthouse = 0; if (!init_lighthouse) { bt_lighthouse = bt_find("lighthouse"); init_lighthouse = true; } - b->flags = BLD_WORKING|BLD_MAINTAINED; - b->no = newcontainerid(); + b->flags = BLD_WORKING | BLD_MAINTAINED; + b->no = newcontainerid(); bhash(b); - + b->type = btype; b->region = r; - while (*bptr) bptr=&(*bptr)->next; + while (*bptr) + bptr = &(*bptr)->next; *bptr = b; - - if (b->type==bt_lighthouse) { + + if (b->type == bt_lighthouse) { r->flags |= RF_LIGHTHOUSE; } { - const char * bname; - if (b->type->name==NULL) { + const char *bname; + + if (b->type->name == NULL) { bname = LOC(lang, btype->_name); } else { bname = LOC(lang, buildingtype(btype, b, 0)); @@ -466,17 +493,19 @@ new_building(const struct building_type * btype, region * r, const struct locale return b; } -static building * deleted_buildings; +static building *deleted_buildings; /** remove a building from the region. * remove_building lets units leave the building */ -void -remove_building(building ** blist, building * b) +void remove_building(building ** blist, building * b) { unit *u; + direction_t d; - static const struct building_type * bt_caravan, * bt_dam, * bt_tunnel; + + static const struct building_type *bt_caravan, *bt_dam, *bt_tunnel; + static boolean init = false; if (!init) { @@ -489,45 +518,49 @@ remove_building(building ** blist, building * b) assert(bfindhash(b->no)); handle_event(b->attribs, "destroy", b); - for (u=b->region->units; u; u=u->next) { - if (u->building == b) leave(u, true); + for (u = b->region->units; u; u = u->next) { + if (u->building == b) + leave(u, true); } - + b->size = 0; update_lighthouse(b); bunhash(b); - + /* Falls Karawanserei, Damm oder Tunnel einstürzen, wird die schon * gebaute Straße zur Hälfte vernichtet */ if (b->type == bt_caravan || b->type == bt_dam || b->type == bt_tunnel) { - region * r = b->region; - for (d=0;d!=MAXDIRECTIONS;++d) if (rroad(r, d) > 0) { - rsetroad(r, d, rroad(r, d) / 2); - } + region *r = b->region; + + for (d = 0; d != MAXDIRECTIONS; ++d) + if (rroad(r, d) > 0) { + rsetroad(r, d, rroad(r, d) / 2); + } } /* Stattdessen nur aus Liste entfernen, aber im Speicher halten. */ - while (*blist && *blist!=b) blist = &(*blist)->next; + while (*blist && *blist != b) + blist = &(*blist)->next; *blist = b->next; b->region = NULL; b->next = deleted_buildings; deleted_buildings = b; } -void -free_building(building * b) +void free_building(building * b) { - while (b->attribs) a_remove (&b->attribs, b->attribs); + while (b->attribs) + a_remove(&b->attribs, b->attribs); free(b->name); free(b->display); free(b); } -void -free_buildings(void) +void free_buildings(void) { while (deleted_buildings) { - building * b = deleted_buildings; + building *b = deleted_buildings; + deleted_buildings = b->next; } } @@ -537,16 +570,17 @@ extern struct attrib_type at_icastle; /** returns the building's build stage (NOT size in people). * only makes sense for castles or similar buildings with multiple * stages */ -int -buildingeffsize(const building * b, boolean img) +int buildingeffsize(const building * b, boolean img) { - const struct building_type * btype = NULL; + const struct building_type *btype = NULL; - if (b==NULL) return 0; + if (b == NULL) + return 0; btype = b->type; if (img) { - const attrib * a = a_find(b->attribs, &at_icastle); + const attrib *a = a_find(b->attribs, &at_icastle); + if (a) { btype = (const struct building_type *)a->data.v; } @@ -557,11 +591,14 @@ buildingeffsize(const building * b, boolean img) int bt_effsize(const building_type * btype, const building * b, int bsize) { int i = bsize, n = 0; - const construction * cons = btype->construction; + + const construction *cons = btype->construction; /* TECH DEBT: simplest thing that works for E3 dwarf/halfling faction rules */ - if (b && get_param_int(global.parameters, "rules.dwarf_castles", 1) && strcmp(btype->_name, "castle")==0) { - unit * u = building_owner(b); + if (b && get_param_int(global.parameters, "rules.dwarf_castles", 1) + && strcmp(btype->_name, "castle") == 0) { + unit *u = building_owner(b); + if (u && u->faction->race == new_race[RC_HALFLING]) { i = bsize * 10 / 8; } @@ -571,7 +608,7 @@ int bt_effsize(const building_type * btype, const building * b, int bsize) return 0; } - while (cons && cons->maxsize != -1 && i>=cons->maxsize) { + while (cons && cons->maxsize != -1 && i >= cons->maxsize) { i -= cons->maxsize; cons = cons->improvement; ++n; @@ -580,30 +617,34 @@ int bt_effsize(const building_type * btype, const building * b, int bsize) return n; } -const char * -write_buildingname(const building * b, char * ibuf, size_t size) +const char *write_buildingname(const building * b, char *ibuf, size_t size) { - snprintf((char*)ibuf, size, "%s (%s)", b->name, itoa36(b->no)); - ibuf[size-1] = 0; + snprintf((char *)ibuf, size, "%s (%s)", b->name, itoa36(b->no)); + ibuf[size - 1] = 0; return ibuf; } -const char * -buildingname(const building * b) +const char *buildingname(const building * b) { typedef char name[OBJECTIDSIZE + 1]; + static name idbuf[8]; + static int nextbuf = 0; + char *ibuf = idbuf[(++nextbuf) % 8]; + return write_buildingname(b, ibuf, sizeof(name)); } -unit * -building_owner(const building * b) +unit *building_owner(const building * b) { unit *u = NULL; + unit *first = NULL; - region * r = b->region; + + region *r = b->region; + /* Prüfen ob Eigentümer am leben. */ for (u = r->units; u; u = u->next) { @@ -618,7 +659,7 @@ building_owner(const building * b) } /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit - * nehmen. */ + * nehmen. */ if (first) { fset(first, UFL_OWNER); @@ -626,23 +667,26 @@ building_owner(const building * b) return first; } -const char * building_getname(const building * self) +const char *building_getname(const building * self) { return self->name; } -void building_setname(building * self, const char * name) +void building_setname(building * self, const char *name) { free(self->name); - if (name) self->name = strdup(name); - else self->name = NULL; + if (name) + self->name = strdup(name); + else + self->name = NULL; } -void -building_addaction(building * b, const char * fname, const char * param) +void building_addaction(building * b, const char *fname, const char *param) { - attrib * a = a_add(&b->attribs, a_new(&at_building_action)); - building_action * data = (building_action*)a->data.v; + attrib *a = a_add(&b->attribs, a_new(&at_building_action)); + + building_action *data = (building_action *) a->data.v; + data->b = b; data->fname = strdup(fname); if (param) { @@ -650,26 +694,25 @@ building_addaction(building * b, const char * fname, const char * param) } } -region * -building_getregion(const building * b) +region *building_getregion(const building * b) { return b->region; } -void -building_setregion(building * b, region * r) +void building_setregion(building * b, region * r) { - building ** blist = &b->region->buildings; - while (*blist && *blist!=b) { + building **blist = &b->region->buildings; + + while (*blist && *blist != b) { blist = &(*blist)->next; } *blist = b->next; b->next = NULL; blist = &r->buildings; - while (*blist && *blist!=b) blist = &(*blist)->next; + while (*blist && *blist != b) + blist = &(*blist)->next; *blist = b; b->region = r; } - diff --git a/src/kernel/building.h b/src/kernel/building.h index 08ede08bb..08b9527db 100644 --- a/src/kernel/building.h +++ b/src/kernel/building.h @@ -28,14 +28,14 @@ extern "C" { /* maintenance::flags */ #define MTF_NONE 0x00 -#define MTF_VARIABLE 0x01 /* resource usage scales with size */ -#define MTF_VITAL 0x02 /* if resource missing, building may crash */ +#define MTF_VARIABLE 0x01 /* resource usage scales with size */ +#define MTF_VITAL 0x02 /* if resource missing, building may crash */ -typedef struct maintenance { - const struct resource_type * rtype; /* type of resource required */ - int number; /* amount of resources */ - unsigned int flags; /* misc. flags */ -} maintenance; + typedef struct maintenance { + const struct resource_type *rtype; /* type of resource required */ + int number; /* amount of resources */ + unsigned int flags; /* misc. flags */ + } maintenance; /* building_type::flags */ #define BTF_NONE 0x00 @@ -48,32 +48,34 @@ typedef struct maintenance { #define BTF_ONEPERTURN 0x80 /* one one sizepoint can be added per turn */ #define BTF_NAMECHANGE 0x100 /* name and description can be changed more than once */ -typedef struct building_type { - const char * _name; + typedef struct building_type { + const char *_name; - int flags; /* flags */ - int capacity; /* Kapazität pro Größenpunkt */ - int maxcapacity; /* Max. Kapazität */ - int maxsize; /* how big can it get, with all the extensions? */ - int magres; /* how well it resists against spells */ - int magresbonus; /* bonus it gives the target against spells */ - int fumblebonus; /* bonus that reduces fumbling */ - double auraregen; /* modifier for aura regeneration inside building */ - struct maintenance * maintenance; /* array of requirements */ - struct construction * construction; /* construction of 1 building-level */ + int flags; /* flags */ + int capacity; /* Kapazität pro Größenpunkt */ + int maxcapacity; /* Max. Kapazität */ + int maxsize; /* how big can it get, with all the extensions? */ + int magres; /* how well it resists against spells */ + int magresbonus; /* bonus it gives the target against spells */ + int fumblebonus; /* bonus that reduces fumbling */ + double auraregen; /* modifier for aura regeneration inside building */ + struct maintenance *maintenance; /* array of requirements */ + struct construction *construction; /* construction of 1 building-level */ - const char * (*name)(const struct building_type*, const struct building * b, int size); - void (*init)(struct building_type*); - void (*age)(struct building *); - int (*protection)(struct building *, struct unit *); - double (*taxes)(const struct building *, int size); - struct attrib * attribs; -} building_type; + const char *(*name) (const struct building_type *, + const struct building * b, int size); + void (*init) (struct building_type *); + void (*age) (struct building *); + int (*protection) (struct building *, struct unit *); + double (*taxes) (const struct building *, int size); + struct attrib *attribs; + } building_type; -extern building_type * bt_find(const char* name); -extern void register_buildings(void); -extern void bt_register(struct building_type * type); -extern int bt_effsize(const struct building_type * btype, const struct building * b, int bsize); + extern building_type *bt_find(const char *name); + extern void register_buildings(void); + extern void bt_register(struct building_type *type); + extern int bt_effsize(const struct building_type *btype, + const struct building *b, int bsize); /* buildingt => building_type * Name => locale_string(name) @@ -94,74 +96,81 @@ extern int bt_effsize(const struct building_type * btype, const struct building #define BLD_SAVEMASK 0x00 /* mask for persistent flags */ -typedef struct building { - struct building *next; - struct building *nexthash; + typedef struct building { + struct building *next; + struct building *nexthash; - const struct building_type * type; - struct region *region; - char *name; - char *display; - struct attrib * attribs; - int no; - int size; - int sizeleft; /* is only used during battle. should be a temporary attribute */ - int besieged; /* should be an attribute */ - unsigned int flags; -} building; + const struct building_type *type; + struct region *region; + char *name; + char *display; + struct attrib *attribs; + int no; + int size; + int sizeleft; /* is only used during battle. should be a temporary attribute */ + int besieged; /* should be an attribute */ + unsigned int flags; + } building; -extern struct attrib_type at_building_generic_type; -extern const char * buildingtype(const building_type * btype, const struct building * b, int bsize); -extern const char * write_buildingname(const building * b, char * ibuf, size_t size); -extern int buildingcapacity(const struct building * b); -extern struct building *new_building(const struct building_type * typ, struct region * r, const struct locale * lang); -void build_building(struct unit * u, const struct building_type * typ, int size, struct order * ord); + extern struct attrib_type at_building_generic_type; + extern const char *buildingtype(const building_type * btype, + const struct building *b, int bsize); + extern const char *write_buildingname(const building * b, char *ibuf, + size_t size); + extern int buildingcapacity(const struct building *b); + extern struct building *new_building(const struct building_type *typ, + struct region *r, const struct locale *lang); + void build_building(struct unit *u, const struct building_type *typ, int size, + struct order *ord); /* Alte Gebäudetypen: */ /* old functions, still in build.c: */ -int buildingeffsize(const building * b, boolean img); -void bhash(struct building * b); -void bunhash(struct building * b); -int buildingcapacity(const struct building * b); + int buildingeffsize(const building * b, boolean img); + void bhash(struct building *b); + void bunhash(struct building *b); + int buildingcapacity(const struct building *b); -extern void remove_building(struct building * *blist, struct building * b); -extern void free_building(struct building * b); -extern void free_buildings(void); + extern void remove_building(struct building **blist, struct building *b); + extern void free_building(struct building *b); + extern void free_buildings(void); -const struct building_type * findbuildingtype(const char * name, const struct locale * lang); + const struct building_type *findbuildingtype(const char *name, + const struct locale *lang); #include "build.h" #define NOBUILDING NULL -extern int resolve_building(variant data, void * address); -extern void write_building_reference(const struct building * b, struct storage * store); -extern variant read_building_reference(struct storage * store); + extern int resolve_building(variant data, void *address); + extern void write_building_reference(const struct building *b, + struct storage *store); + extern variant read_building_reference(struct storage *store); -extern struct building *findbuilding(int n); + extern struct building *findbuilding(int n); -extern struct unit * building_owner(const struct building * b); + extern struct unit *building_owner(const struct building *b); -extern struct attrib_type at_building_action; -void building_addaction(struct building * b, const char * fname, const char * param); + extern struct attrib_type at_building_action; + void building_addaction(struct building *b, const char *fname, + const char *param); #ifdef WDW_PYRAMID -extern int wdw_pyramid_level(const struct building *b); + extern int wdw_pyramid_level(const struct building *b); #endif -typedef struct building_action { - building * b; - char * fname; - char * param; -} building_action; + typedef struct building_action { + building *b; + char *fname; + char *param; + } building_action; -extern const char * buildingname(const struct building * b); + extern const char *buildingname(const struct building *b); -extern const char * building_getname(const struct building * b); -extern void building_setname(struct building * self, const char * name); + extern const char *building_getname(const struct building *b); + extern void building_setname(struct building *self, const char *name); -struct region * building_getregion(const struct building * b); -void building_setregion(struct building * bld, struct region * r); + struct region *building_getregion(const struct building *b); + void building_setregion(struct building *bld, struct region *r); #ifdef __cplusplus } diff --git a/src/kernel/calendar.c b/src/kernel/calendar.c index 8a4efccca..86f3a7129 100644 --- a/src/kernel/calendar.c +++ b/src/kernel/calendar.c @@ -4,53 +4,63 @@ #include int first_turn = 0; -int first_month = 0; -int weeks_per_month = 0; -int months_per_year = 0; -char **seasonnames = NULL; -char **weeknames = NULL; -char **weeknames2 = NULL; -char **monthnames = NULL; -int *month_season = NULL; -char *agename = NULL; -int seasons = 0; -const gamedate * -get_gamedate(int turn, gamedate * gd) +int first_month = 0; + +int weeks_per_month = 0; + +int months_per_year = 0; + +char **seasonnames = NULL; + +char **weeknames = NULL; + +char **weeknames2 = NULL; + +char **monthnames = NULL; + +int *month_season = NULL; + +char *agename = NULL; + +int seasons = 0; + +const gamedate *get_gamedate(int turn, gamedate * gd) { int weeks_per_year = months_per_year * weeks_per_month; + int t = turn - first_turn; assert(gd); - if (t<0) t = turn; + if (t < 0) + t = turn; - gd->week = t%weeks_per_month; /* 0 - weeks_per_month-1 */ - gd->month = (t/weeks_per_month + first_month)%months_per_year; /* 0 - months_per_year-1 */ - gd->year = t/(weeks_per_year) + 1; + gd->week = t % weeks_per_month; /* 0 - weeks_per_month-1 */ + gd->month = (t / weeks_per_month + first_month) % months_per_year; /* 0 - months_per_year-1 */ + gd->year = t / (weeks_per_year) + 1; gd->season = month_season[gd->month]; return gd; } -void -calendar_cleanup(void) +void calendar_cleanup(void) { int i; free(agename); - for (i=0;i!=seasons;++i) { + for (i = 0; i != seasons; ++i) { free(seasonnames[i]); } free(seasonnames); - for (i=0;i!=months_per_year;++i) { + for (i = 0; i != months_per_year; ++i) { free(monthnames[i]); } free(storms); free(month_season); free(monthnames); - for (i=0;i!=weeks_per_month;++i) { + for (i = 0; i != weeks_per_month; ++i) { free(weeknames[i]); free(weeknames2[i]); } diff --git a/src/kernel/calendar.h b/src/kernel/calendar.h index ae4306d28..21d947339 100644 --- a/src/kernel/calendar.h +++ b/src/kernel/calendar.h @@ -5,39 +5,39 @@ extern "C" { #endif -enum { - SEASON_WINTER, - SEASON_SPRING, - SEASON_SUMMER, - SEASON_AUTUMN -}; + enum { + SEASON_WINTER, + SEASON_SPRING, + SEASON_SUMMER, + SEASON_AUTUMN + }; -extern char *agename; -extern int first_turn; -extern int first_month; + extern char *agename; + extern int first_turn; + extern int first_month; -extern int seasons; -extern char **seasonnames; + extern int seasons; + extern char **seasonnames; -extern int months_per_year; -extern char **monthnames; -extern int *month_season; -extern int *storms; /* in movement.c */ + extern int months_per_year; + extern char **monthnames; + extern int *month_season; + extern int *storms; /* in movement.c */ -extern char **weeknames; -extern char **weeknames2; -extern int weeks_per_month; + extern char **weeknames; + extern char **weeknames2; + extern int weeks_per_month; -typedef struct gamedate { - int year; - int season; - int month; - int week; -} gamedate; + typedef struct gamedate { + int year; + int season; + int month; + int week; + } gamedate; -extern const gamedate * get_gamedate(int turn, gamedate * gd); -extern void calendar_cleanup(void); + extern const gamedate *get_gamedate(int turn, gamedate * gd); + extern void calendar_cleanup(void); #ifdef __cplusplus } diff --git a/src/kernel/command.c b/src/kernel/command.c index 93741e4c2..52883b945 100644 --- a/src/kernel/command.c +++ b/src/kernel/command.c @@ -29,39 +29,42 @@ typedef struct command { parser fun; - struct tnode * nodes; + struct tnode *nodes; } command; -tnode * -stree_find(const syntaxtree * stree, const struct locale * lang) +tnode *stree_find(const syntaxtree * stree, const struct locale *lang) { while (stree) { - if (stree->lang==lang) return stree->root; + if (stree->lang == lang) + return stree->root; stree = stree->next; } return NULL; } -syntaxtree * -stree_create(void) +syntaxtree *stree_create(void) { - syntaxtree * sroot = NULL; - const struct locale * lang = locales; + syntaxtree *sroot = NULL; + + const struct locale *lang = locales; + while (lang) { - syntaxtree * stree = (syntaxtree *)malloc(sizeof(syntaxtree)); + syntaxtree *stree = (syntaxtree *) malloc(sizeof(syntaxtree)); + stree->lang = lang; stree->next = sroot; - sroot=stree; - lang=nextlocale(lang); + sroot = stree; + lang = nextlocale(lang); } return sroot; } void -add_command(struct tnode * keys, struct tnode * tnext, - const char * str, parser fun) +add_command(struct tnode *keys, struct tnode *tnext, + const char *str, parser fun) { - command * cmd = (command *)malloc(sizeof(command)); + command *cmd = (command *) malloc(sizeof(command)); + variant var; cmd->fun = fun; @@ -70,15 +73,16 @@ add_command(struct tnode * keys, struct tnode * tnext, addtoken(keys, str, var); } -static int -do_command_i(const struct tnode * keys, void * u, struct order * ord) +static int do_command_i(const struct tnode *keys, void *u, struct order *ord) { - const char * c; + const char *c; + variant var; c = getstrtoken(); - if (findtoken(keys, c, &var)==E_TOK_SUCCESS) { - command * cmd = (command *)var.v; + if (findtoken(keys, c, &var) == E_TOK_SUCCESS) { + command *cmd = (command *) var.v; + if (cmd->nodes && *c) { assert(!cmd->fun); return do_command_i(cmd->nodes, u, ord); @@ -90,13 +94,13 @@ do_command_i(const struct tnode * keys, void * u, struct order * ord) return E_TOK_NOMATCH; } -void -do_command(const struct tnode * keys, void * u, struct order * ord) +void do_command(const struct tnode *keys, void *u, struct order *ord) { init_tokens(ord); skip_token(); - if (do_command_i(keys, u, ord)!=E_TOK_SUCCESS) { - char * cmd = getcommand(ord); + if (do_command_i(keys, u, ord) != E_TOK_SUCCESS) { + char *cmd = getcommand(ord); + log_warning(("%s failed command '%s'\n", unitname(u), cmd)); free(cmd); } diff --git a/src/kernel/command.h b/src/kernel/command.h index 401b9e8bc..8bdcac745 100644 --- a/src/kernel/command.h +++ b/src/kernel/command.h @@ -16,22 +16,24 @@ extern "C" { #endif -struct tnode; -struct locale; -struct order; + struct tnode; + struct locale; + struct order; -typedef struct syntaxtree { - const struct locale * lang; - struct tnode * root; - struct syntaxtree * next; -} syntaxtree; + typedef struct syntaxtree { + const struct locale *lang; + struct tnode *root; + struct syntaxtree *next; + } syntaxtree; -typedef void (*parser)(const struct tnode *, void *, struct order*); -extern void add_command(struct tnode * troot, struct tnode * tnext, const char * str, parser fun); -extern void do_command(const struct tnode * troot, void * u, struct order *); + typedef void (*parser) (const struct tnode *, void *, struct order *); + extern void add_command(struct tnode *troot, struct tnode *tnext, + const char *str, parser fun); + extern void do_command(const struct tnode *troot, void *u, struct order *); -extern struct syntaxtree * stree_create(void); -extern struct tnode * stree_find(const struct syntaxtree * stree, const struct locale * lang); + extern struct syntaxtree *stree_create(void); + extern struct tnode *stree_find(const struct syntaxtree *stree, + const struct locale *lang); #ifdef __cplusplus } diff --git a/src/kernel/config.c b/src/kernel/config.c index c310d9703..2d9342843 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -87,13 +87,19 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include struct settings global = { - "Eressea", /* gamename */ + "Eressea", /* gamename */ }; -FILE *logfile; -FILE *updatelog; -const struct race * new_race[MAXRACES]; + +FILE *logfile; + +FILE *updatelog; + +const struct race *new_race[MAXRACES]; + boolean sqlpatch = false; + boolean battledebug = false; + int turn = 0; #if XECMD_MODULE @@ -108,73 +114,91 @@ attrib_type at_xontormiaexpress = { }; #endif -int -NewbieImmunity(void) { +int NewbieImmunity(void) +{ static int value = -1; + static int gamecookie = -1; - if (value<0 || gamecookie!=global.cookie) { + + if (value < 0 || gamecookie != global.cookie) { gamecookie = global.cookie; + value = get_param_int(global.parameters, "NewbieImmunity", 0); } return value; } -boolean -IsImmune(const faction * f) +boolean IsImmune(const faction * f) { return !fval(f, FFL_NPC) && f->age < NewbieImmunity(); } -static int -MaxAge(void) { +static int MaxAge(void) +{ static int value = -1; + static int gamecookie = -1; - if (value<0 || gamecookie!=global.cookie) { + + if (value < 0 || gamecookie != global.cookie) { gamecookie = global.cookie; + value = get_param_int(global.parameters, "MaxAge", 0); } return value; } -static int -ally_flag(const char * s, int help_mask) +static int ally_flag(const char *s, int help_mask) { - if ((help_mask&HELP_MONEY) && strcmp(s, "money")==0) return HELP_MONEY; - if ((help_mask&HELP_FIGHT) && strcmp(s, "fight")==0) return HELP_FIGHT; - if ((help_mask&HELP_GIVE) && strcmp(s, "give")==0) return HELP_GIVE; - if ((help_mask&HELP_GUARD) && strcmp(s, "guard")==0) return HELP_GUARD; - if ((help_mask&HELP_FSTEALTH) && strcmp(s, "stealth")==0) return HELP_FSTEALTH; - if ((help_mask&HELP_TRAVEL) && strcmp(s, "travel")==0) return HELP_TRAVEL; + if ((help_mask & HELP_MONEY) && strcmp(s, "money") == 0) + return HELP_MONEY; + if ((help_mask & HELP_FIGHT) && strcmp(s, "fight") == 0) + return HELP_FIGHT; + if ((help_mask & HELP_GIVE) && strcmp(s, "give") == 0) + return HELP_GIVE; + if ((help_mask & HELP_GUARD) && strcmp(s, "guard") == 0) + return HELP_GUARD; + if ((help_mask & HELP_FSTEALTH) && strcmp(s, "stealth") == 0) + return HELP_FSTEALTH; + if ((help_mask & HELP_TRAVEL) && strcmp(s, "travel") == 0) + return HELP_TRAVEL; return 0; } -boolean -ExpensiveMigrants(void) +boolean ExpensiveMigrants(void) { static int value = -1; + static int gamecookie = -1; - if (value<0 || gamecookie!=global.cookie) { + + if (value < 0 || gamecookie != global.cookie) { gamecookie = global.cookie; + value = get_param_int(global.parameters, "study.expensivemigrants", 0); } return value; } + /** Specifies automatic alliance modes. * If this returns a value then the bits set are immutable between alliance * partners (faction::alliance) and cannot be changed with the HELP command. */ -int -AllianceAuto(void) +int AllianceAuto(void) { static int value = -1; + static int gamecookie = -1; - if (value<0 || gamecookie!=global.cookie) { - const char * str = get_param(global.parameters, "alliance.auto"); + + if (value < 0 || gamecookie != global.cookie) { + const char *str = get_param(global.parameters, "alliance.auto"); + gamecookie = global.cookie; + value = 0; - if (str!=NULL) { - char * sstr = strdup(str); - char * tok = strtok(sstr, " "); + if (str != NULL) { + char *sstr = strdup(str); + + char *tok = strtok(sstr, " "); + while (tok) { value |= ally_flag(tok, -1); tok = strtok(NULL, " "); @@ -191,18 +215,23 @@ AllianceAuto(void) * Disabling a status will disable the command sequence entirely (order parsing * uses this function). */ -int -HelpMask(void) +int HelpMask(void) { static int rule = -1; + static int gamecookie = -1; - if (rule<0 || gamecookie!=global.cookie) { - const char * str = get_param(global.parameters, "rules.help.mask"); + + if (rule < 0 || gamecookie != global.cookie) { + const char *str = get_param(global.parameters, "rules.help.mask"); + gamecookie = global.cookie; + rule = 0; - if (str!=NULL) { - char * sstr = strdup(str); - char * tok = strtok(sstr, " "); + if (str != NULL) { + char *sstr = strdup(str); + + char *tok = strtok(sstr, " "); + while (tok) { rule |= ally_flag(tok, -1); tok = strtok(NULL, " "); @@ -215,18 +244,23 @@ HelpMask(void) return rule; } -int -AllianceRestricted(void) +int AllianceRestricted(void) { static int rule = -1; + static int gamecookie = -1; - if (rule<0 || gamecookie!=global.cookie) { - const char * str = get_param(global.parameters, "alliance.restricted"); + + if (rule < 0 || gamecookie != global.cookie) { + const char *str = get_param(global.parameters, "alliance.restricted"); + gamecookie = global.cookie; + rule = 0; - if (str!=NULL) { - char * sstr = strdup(str); - char * tok = strtok(sstr, " "); + if (str != NULL) { + char *sstr = strdup(str); + + char *tok = strtok(sstr, " "); + while (tok) { rule |= ally_flag(tok, -1); tok = strtok(NULL, " "); @@ -238,70 +272,90 @@ AllianceRestricted(void) return rule; } -int -LongHunger(const struct unit * u) { +int LongHunger(const struct unit *u) +{ static int gamecookie = -1; + static int rule = -1; - if (u!=NULL) { - if (!fval(u, UFL_HUNGER)) return false; + + if (u != NULL) { + if (!fval(u, UFL_HUNGER)) + return false; #ifdef NEW_DAEMONHUNGER_RULE - if (u->race==new_race[RC_DAEMON]) return false; + if (u->race == new_race[RC_DAEMON]) + return false; #endif } - if (rule<0 || gamecookie!=global.cookie) { + if (rule < 0 || gamecookie != global.cookie) { gamecookie = global.cookie; + rule = get_param_int(global.parameters, "hunger.long", 0); } return rule; } -int -SkillCap(skill_t sk) { +int SkillCap(skill_t sk) +{ static int gamecookie = -1; + static int rule = -1; - if (sk==SK_MAGIC) return 0; /* no caps on magic */ - if (rule<0 || gamecookie!=global.cookie) { + + if (sk == SK_MAGIC) + return 0; /* no caps on magic */ + if (rule < 0 || gamecookie != global.cookie) { gamecookie = global.cookie; + rule = get_param_int(global.parameters, "skill.maxlevel", 0); } return rule; } -int -NMRTimeout(void) { +int NMRTimeout(void) +{ static int gamecookie = -1; + static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { + + if (rule < 0 || gamecookie != global.cookie) { gamecookie = global.cookie; + rule = get_param_int(global.parameters, "nmr.timeout", 0); } return rule; } -race_t -old_race(const struct race * rc) +race_t old_race(const struct race * rc) { race_t i; - for (i=0;i!=MAXRACES;++i) { - if (new_race[i]==rc) return i; + + for (i = 0; i != MAXRACES; ++i) { + if (new_race[i] == rc) + return i; } return NORACE; } helpmode helpmodes[] = { - { "all", HELP_ALL }, - { "money", HELP_MONEY }, - { "fight", HELP_FIGHT }, - { "observe", HELP_OBSERVE }, - { "give", HELP_GIVE }, - { "guard", HELP_GUARD }, - { "stealth", HELP_FSTEALTH }, - { "travel", HELP_TRAVEL }, - { NULL, 0 } + {"all", HELP_ALL} + , + {"money", HELP_MONEY} + , + {"fight", HELP_FIGHT} + , + {"observe", HELP_OBSERVE} + , + {"give", HELP_GIVE} + , + {"guard", HELP_GUARD} + , + {"stealth", HELP_FSTEALTH} + , + {"travel", HELP_TRAVEL} + , + {NULL, 0} }; -const char *directions[MAXDIRECTIONS+2] = -{ +const char *directions[MAXDIRECTIONS + 2] = { "northwest", "northeast", "east", @@ -314,14 +368,14 @@ const char *directions[MAXDIRECTIONS+2] = /** Returns the English name of the race, which is what the database uses. */ -const char * -dbrace(const struct race * rc) +const char *dbrace(const struct race *rc) { static char zText[32]; - char * zPtr = zText; + + char *zPtr = zText; /* the english names are all in ASCII, so we don't need to worry about UTF8 */ - strcpy(zText, (const char*)LOC(find_locale("en"), rc_name(rc, 0))); + strcpy(zText, (const char *)LOC(find_locale("en"), rc_name(rc, 0))); while (*zPtr) { *zPtr = (char)(toupper(*zPtr)); ++zPtr; @@ -329,8 +383,7 @@ dbrace(const struct race * rc) return zText; } -const char *parameters[MAXPARAMS] = -{ +const char *parameters[MAXPARAMS] = { "LOCALE", "ALLES", "JEDEM", @@ -353,7 +406,7 @@ const char *parameters[MAXPARAMS] = "TEMPORAERE", "FLIEHE", "GEBAEUDE", - "GIB", /* Für HELFE */ + "GIB", /* Für HELFE */ "KAEMPFE", "DURCHREISE", "BEWACHE", @@ -384,8 +437,7 @@ const char *parameters[MAXPARAMS] = }; -const char *keywords[MAXKEYWORDS] = -{ +const char *keywords[MAXKEYWORDS] = { "//", "BANNER", "ARBEITEN", @@ -457,8 +509,7 @@ const char *keywords[MAXKEYWORDS] = "BEZAHLEN", }; -const char *report_options[MAX_MSG] = -{ +const char *report_options[MAX_MSG] = { "Kampf", "Ereignisse", "Bewegung", @@ -471,8 +522,7 @@ const char *report_options[MAX_MSG] = "" }; -const char *message_levels[ML_MAX] = -{ +const char *message_levels[ML_MAX] = { "Wichtig", "Debug", "Fehler", @@ -480,8 +530,7 @@ const char *message_levels[ML_MAX] = "Infos" }; -const char *options[MAXOPTIONS] = -{ +const char *options[MAXOPTIONS] = { "AUSWERTUNG", "COMPUTER", "ZUGVORLAGE", @@ -489,7 +538,7 @@ const char *options[MAXOPTIONS] = "STATISTIK", "DEBUG", "ZIPPED", - "ZEITUNG", /* Option hat Sonderbehandlung! */ + "ZEITUNG", /* Option hat Sonderbehandlung! */ NULL, "ADRESSEN", "BZIP2", @@ -498,33 +547,35 @@ const char *options[MAXOPTIONS] = "XML" }; -static int -allied_skillcount(const faction * f, skill_t sk) +static int allied_skillcount(const faction * f, skill_t sk) { int num = 0; - alliance * a = f_get_alliance(f); - quicklist * members = a->members; + + alliance *a = f_get_alliance(f); + + quicklist *members = a->members; + int qi; - for (qi=0;members;ql_advance(&members, &qi, 1)) { - faction * m = (faction *)ql_get(members, qi); + for (qi = 0; members; ql_advance(&members, &qi, 1)) { + faction *m = (faction *) ql_get(members, qi); + num += count_skill(m, sk); } return num; } -static int -allied_skilllimit(const faction * f, skill_t sk) +static int allied_skilllimit(const faction * f, skill_t sk) { static int value = -1; - if (value<0) { + + if (value < 0) { value = get_param_int(global.parameters, "alliance.skilllimit", 0); } return value; } -static void -init_maxmagicians(struct attrib *a) +static void init_maxmagicians(struct attrib *a) { a->data.i = MAXMAGICIANS; } @@ -539,8 +590,7 @@ static attrib_type at_maxmagicians = { ATF_UNIQUE }; -static void -init_npcfaction(struct attrib *a) +static void init_npcfaction(struct attrib *a) { a->data.i = 1; } @@ -556,55 +606,65 @@ static attrib_type at_npcfaction = { ATF_UNIQUE }; -int -max_magicians(const faction * f) +int max_magicians(const faction * f) { - int m = get_param_int(global.parameters, "rules.maxskills.magic", MAXMAGICIANS); - attrib * a; - + int m = + get_param_int(global.parameters, "rules.maxskills.magic", MAXMAGICIANS); + attrib *a; + if ((a = a_find(f->attribs, &at_maxmagicians)) != NULL) { m = a->data.i; } - if (f->race == new_race[RC_ELF]) ++m; + if (f->race == new_race[RC_ELF]) + ++m; return m; } -int -skill_limit(faction * f, skill_t sk) +int skill_limit(faction * f, skill_t sk) { int m = INT_MAX; + int al = allied_skilllimit(f, sk); - if (al>0) { - if (sk!=SK_ALCHEMY && sk!=SK_MAGIC) return INT_MAX; + + if (al > 0) { + if (sk != SK_ALCHEMY && sk != SK_MAGIC) + return INT_MAX; if (f_get_alliance(f)) { - int ac = listlen(f->alliance->members); /* number of factions */ - int fl = (al+ac-1)/ac; /* faction limit, rounded up */ + int ac = listlen(f->alliance->members); /* number of factions */ + + int fl = (al + ac - 1) / ac; /* faction limit, rounded up */ + /* the faction limit may not be achievable because it would break the alliance-limit */ int sc = al - allied_skillcount(f, sk); - if (sc<=0) return 0; + + if (sc <= 0) + return 0; return fl; } } switch (sk) { - case SK_MAGIC: - m = max_magicians(f); - break; - case SK_ALCHEMY: - m = get_param_int(global.parameters, "rules.maxskills.alchemy", MAXALCHEMISTS); - break; + case SK_MAGIC: + m = max_magicians(f); + break; + case SK_ALCHEMY: + m = + get_param_int(global.parameters, "rules.maxskills.alchemy", + MAXALCHEMISTS); + break; } return m; } -int -count_skill(faction * f, skill_t sk) +int count_skill(faction * f, skill_t sk) { int n = 0; + unit *u; for (u = f->units; u; u = u->nextF) { if (has_skill(u, sk)) { - if (!is_familiar(u)) n += u->number; + if (!is_familiar(u)) + n += u->number; } } return n; @@ -614,30 +674,37 @@ int verbosity = 0; FILE *debug; -static int -ShipSpeedBonus(const unit * u) +static int ShipSpeedBonus(const unit * u) { static int level = -1; - if (level==-1) { - level = get_param_int(global.parameters, "movement.shipspeed.skillbonus", 0); + + if (level == -1) { + level = + get_param_int(global.parameters, "movement.shipspeed.skillbonus", 0); } - if (level>0) { - ship * sh = u->ship; + if (level > 0) { + ship *sh = u->ship; + int skl = effskill(u, SK_SAILING); - int minsk = (sh->type->cptskill+1)/2; - return (skl-minsk)/level; + + int minsk = (sh->type->cptskill + 1) / 2; + + return (skl - minsk) / level; } return 0; } -int -shipspeed(const ship * sh, const unit * u) +int shipspeed(const ship * sh, const unit * u) { double k = sh->type->range; - static const curse_type * stormwind_ct, * nodrift_ct; + + static const curse_type *stormwind_ct, *nodrift_ct; + static boolean init; + attrib *a; - curse *c; + + curse *c; if (!init) { init = true; @@ -645,14 +712,15 @@ shipspeed(const ship * sh, const unit * u) nodrift_ct = ct_find("nodrift"); } - assert(u->ship==sh); - assert(sh->type->construction->improvement==NULL); /* sonst ist construction::size nicht ship_type::maxsize */ - if (sh->size!=sh->type->construction->maxsize) return 0; + assert(u->ship == sh); + assert(sh->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (sh->size != sh->type->construction->maxsize) + return 0; - if( curse_active(get_curse(sh->attribs, stormwind_ct))) - k *= 2; - if( curse_active(get_curse(sh->attribs, nodrift_ct))) - k += 1; + if (curse_active(get_curse(sh->attribs, stormwind_ct))) + k *= 2; + if (curse_active(get_curse(sh->attribs, nodrift_ct))) + k += 1; if (u->faction->race == u->race) { /* race bonus for this faction? */ @@ -664,15 +732,15 @@ shipspeed(const ship * sh, const unit * u) k += ShipSpeedBonus(u); a = a_find(sh->attribs, &at_speedup); - while (a != NULL && a->type==&at_speedup) { + while (a != NULL && a->type == &at_speedup) { k += a->data.sa[0]; a = a->next; } c = get_curse(sh->attribs, ct_find("shipspeedup")); - while(c) { + while (c) { k += curse_geteffect(c); - c = c->nexthash; + c = c->nexthash; } #ifdef SHIPSPEED @@ -680,57 +748,68 @@ shipspeed(const ship * sh, const unit * u) #endif #ifdef SHIPDAMAGE - if (sh->damage) k = (k * (sh->size * DAMAGE_SCALE - sh->damage) + sh->size * DAMAGE_SCALE- 1) / (sh->size*DAMAGE_SCALE); + if (sh->damage) + k = + (k * (sh->size * DAMAGE_SCALE - sh->damage) + sh->size * DAMAGE_SCALE - + 1) / (sh->size * DAMAGE_SCALE); #endif return (int)k; } #define FMAXHASH 2039 -faction * factionhash[FMAXHASH]; +faction *factionhash[FMAXHASH]; -void -fhash(faction * f) +void fhash(faction * f) { int index = f->no % FMAXHASH; + f->nexthash = factionhash[index]; factionhash[index] = f; } -void -funhash(faction * f) +void funhash(faction * f) { int index = f->no % FMAXHASH; - faction ** fp = factionhash+index; - while (*fp && (*fp)!=f) fp = &(*fp)->nexthash; + + faction **fp = factionhash + index; + + while (*fp && (*fp) != f) + fp = &(*fp)->nexthash; *fp = f->nexthash; } -static faction * -ffindhash(int no) +static faction *ffindhash(int no) { int index = no % FMAXHASH; - faction * f = factionhash[index]; - while (f && f->no!=no) f = f->nexthash; + + faction *f = factionhash[index]; + + while (f && f->no != no) + f = f->nexthash; return f; } + /* ----------------------------------------------------------------------- */ -void -verify_data(void) +void verify_data(void) { #ifndef NDEBUG int lf = -1; + faction *f; + unit *u; + int mage, alchemist; - if (verbosity>=1) puts(" - Überprüfe Daten auf Korrektheit..."); + if (verbosity >= 1) + puts(" - Überprüfe Daten auf Korrektheit..."); - for (f=factions; f; f=f->next) { + for (f = factions; f; f = f->next) { mage = 0; alchemist = 0; - for (u=f->units;u;u=u->nextF) { + for (u = f->units; u; u = u->nextF) { if (eff_skill(u, SK_MAGIC, u->region)) { mage += u->number; } @@ -752,11 +831,12 @@ verify_data(void) #endif } -int -distribute(int old, int new_value, int n) +int distribute(int old, int new_value, int n) { int i; + int t; + assert(new_value <= old); if (old == 0) @@ -770,16 +850,15 @@ distribute(int old, int new_value, int n) return t; } -int -change_hitpoints (unit * u, int value) +int change_hitpoints(unit * u, int value) { int hp = u->hp; hp += value; /* Jede Person benötigt mindestens 1 HP */ - if (hp < u->number){ - if (hp < 0){ /* Einheit tot */ + if (hp < u->number) { + if (hp < 0) { /* Einheit tot */ hp = 0; } scale_number(u, hp); @@ -788,12 +867,11 @@ change_hitpoints (unit * u, int value) return hp; } -unsigned int -atoip(const char *s) +unsigned int atoip(const char *s) { int n; - n = atoi (s); + n = atoi(s); if (n < 0) n = 0; @@ -801,73 +879,74 @@ atoip(const char *s) return n; } -region * -findunitregion (const unit * su) +region *findunitregion(const unit * su) { #ifndef SLOW_REGION return su->region; #else region *r; + const unit *u; for (r = regions; r; r = r->next) { for (u = r->units; u; u = u->next) { if (su == u) { - return r; + return r; } } } /* This should never happen */ - assert (!"Die unit wurde nicht gefunden"); + assert(!"Die unit wurde nicht gefunden"); return (region *) NULL; #endif } -int -effskill(const unit * u, skill_t sk) +int effskill(const unit * u, skill_t sk) { return eff_skill(u, sk, u->region); } -int -eff_stealth(const unit * u, const region * r) +int eff_stealth(const unit * u, const region * r) { int e = 0; /* Auf Schiffen keine Tarnung! */ if (!u->ship && skill_enabled[SK_STEALTH]) { - e = eff_skill (u, SK_STEALTH, r); + e = eff_skill(u, SK_STEALTH, r); if (fval(u, UFL_STEALTH)) { int es = u_geteffstealth(u); - if (es >=0 && es < e) return es; + + if (es >= 0 && es < e) + return es; } } return e; } -boolean -unit_has_cursed_item(unit *u) +boolean unit_has_cursed_item(unit * u) { - item * itm = u->items; + item *itm = u->items; + while (itm) { - if (fval(itm->type, ITF_CURSED) && itm->number>0) return true; - itm=itm->next; + if (fval(itm->type, ITF_CURSED) && itm->number > 0) + return true; + itm = itm->next; } return false; } -static void -init_gms(void) +static void init_gms(void) { - faction * f; + faction *f; - for (f=factions;f;f=f->next) { - const attrib * a = a_findc(f->attribs, &at_gm); + for (f = factions; f; f = f->next) { + const attrib *a = a_findc(f->attribs, &at_gm); - if (a!=NULL) fset(f, FFL_GM); + if (a != NULL) + fset(f, FFL_GM); } } @@ -875,42 +954,48 @@ static int autoalliance(const plane * pl, const faction * sf, const faction * f2) { static boolean init = false; + if (!init) { init_gms(); init = true; } - if (pl && (pl->flags & PFL_FRIENDLY)) return HELP_ALL; + if (pl && (pl->flags & PFL_FRIENDLY)) + return HELP_ALL; /* if f2 is a gm in this plane, everyone has an auto-help to it */ if (fval(f2, FFL_GM)) { - attrib * a = a_find(f2->attribs, &at_gm); + attrib *a = a_find(f2->attribs, &at_gm); while (a) { - const plane * p = (const plane*)a->data.v; - if (p==pl) return HELP_ALL; - a=a->next; + const plane *p = (const plane *)a->data.v; + + if (p == pl) + return HELP_ALL; + a = a->next; } } - if (f_get_alliance(sf)!=NULL && AllianceAuto()) { - if (sf->alliance==f2->alliance) return AllianceAuto(); + if (f_get_alliance(sf) != NULL && AllianceAuto()) { + if (sf->alliance == f2->alliance) + return AllianceAuto(); } return 0; } -static int -ally_mode(const ally * sf, int mode) +static int ally_mode(const ally * sf, int mode) { - if (sf==NULL) return 0; + if (sf == NULL) + return 0; return sf->status & mode; } int -alliedgroup(const struct plane * pl, const struct faction * f, - const struct faction * f2, const struct ally * sf, int mode) +alliedgroup(const struct plane *pl, const struct faction *f, + const struct faction *f2, const struct ally *sf, int mode) { - while (sf && sf->faction!=f2) sf=sf->next; - if (sf==NULL) { + while (sf && sf->faction != f2) + sf = sf->next; + if (sf == NULL) { mode = mode & autoalliance(pl, f, f2); } mode = ally_mode(sf, mode) | (mode & autoalliance(pl, f, f2)); @@ -921,7 +1006,7 @@ alliedgroup(const struct plane * pl, const struct faction * f, if (a_findc(f2->attribs, &at_npcfaction)) { return mode; } - if (f->alliance!=f2->alliance) { + if (f->alliance != f2->alliance) { mode &= ~AllianceRestricted(); } } @@ -929,29 +1014,31 @@ alliedgroup(const struct plane * pl, const struct faction * f, } int -alliedfaction(const struct plane * pl, const struct faction * f, - const struct faction * f2, int mode) +alliedfaction(const struct plane *pl, const struct faction *f, + const struct faction *f2, int mode) { return alliedgroup(pl, f, f2, f->allies, mode); } /* Die Gruppe von Einheit u hat helfe zu f2 gesetzt. */ -int -alliedunit(const unit * u, const faction * f2, int mode) +int alliedunit(const unit * u, const faction * f2, int mode) { - ally * sf; + ally *sf; + int automode; - assert(u->region); /* the unit should be in a region, but it's possible that u->number==0 (TEMP units) */ - if (u->faction == f2) return mode; - if (u->faction != NULL && f2!=NULL) { - plane * pl; - - if (mode&HELP_FIGHT) { - if ((u->flags&UFL_DEFENDER) || (u->faction->flags&FFL_DEFENDER)) { - faction * owner = region_get_owner(u->region); + assert(u->region); /* the unit should be in a region, but it's possible that u->number==0 (TEMP units) */ + if (u->faction == f2) + return mode; + if (u->faction != NULL && f2 != NULL) { + plane *pl; + + if (mode & HELP_FIGHT) { + if ((u->flags & UFL_DEFENDER) || (u->faction->flags & FFL_DEFENDER)) { + faction *owner = region_get_owner(u->region); + /* helps the owner of the region */ - if (owner==f2) { + if (owner == f2) { return HELP_FIGHT; } } @@ -960,13 +1047,15 @@ alliedunit(const unit * u, const faction * f2, int mode) pl = rplane(u->region); automode = mode & autoalliance(pl, u->faction, f2); - if (pl!=NULL && (pl->flags & PFL_NOALLIANCES)) + if (pl != NULL && (pl->flags & PFL_NOALLIANCES)) mode = (mode & automode) | (mode & HELP_GIVE); sf = u->faction->allies; if (fval(u, UFL_GROUP)) { - const attrib * a = a_findc(u->attribs, &at_group); - if (a!=NULL) sf = ((group*)a->data.v)->allies; + const attrib *a = a_findc(u->attribs, &at_group); + + if (a != NULL) + sf = ((group *) a->data.v)->allies; } return alliedgroup(pl, u->faction, f2, sf, mode); } @@ -976,7 +1065,8 @@ alliedunit(const unit * u, const faction * f2, int mode) boolean 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)) + if (((f == u->faction) || !fval(u, UFL_ANON_FACTION)) + && cansee(f, r, u, modifier)) return true; return false; } @@ -988,8 +1078,11 @@ cansee(const faction * f, const region * r, const unit * u, int modifier) * erblickt wird */ { int stealth, rings; + unit *u2 = r->units; - static const item_type * itype_grail; + + static const item_type *itype_grail; + static boolean init; if (!init) { @@ -1003,22 +1096,27 @@ cansee(const faction * f, const region * r, const unit * u, int modifier) return false; } else if (u->number == 0) { 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. */ - u = (unit *)a->data.v; + + if (a) { /* u is an empty temporary unit. In this special case + we look at the creating unit. */ + u = (unit *) a->data.v; } else { return false; } } - if (leftship(u)) return true; - if (itype_grail!=NULL && i_get(u->items, itype_grail)) return true; + if (leftship(u)) + return true; + if (itype_grail != NULL && i_get(u->items, itype_grail)) + return true; - while (u2 && u2->faction != f) u2 = u2->next; - if (u2==NULL) return false; + 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, GUARD_ALL)!=0 || usiege(u) || u->building || u->ship) { + if (is_guard(u, GUARD_ALL) != 0 || usiege(u) || u->building || u->ship) { return true; } @@ -1026,7 +1124,7 @@ cansee(const faction * f, const region * r, const unit * u, int modifier) stealth = eff_stealth(u, r) - modifier; while (u2) { - if (ringsnumber || invisible(u, u2) < u->number) { + if (rings < u->number || invisible(u, u2) < u->number) { if (skill_enabled[SK_PERCEPTION]) { int observation = eff_skill(u2, SK_PERCEPTION, r); @@ -1040,28 +1138,30 @@ cansee(const faction * f, const region * r, const unit * u, int modifier) /* find next unit in our faction */ do { - u2=u2->next; + u2 = u2->next; } while (u2 && u2->faction != f); } return false; } -boolean -cansee_unit(const unit * u, const unit * target, int modifier) +boolean cansee_unit(const unit * u, const unit * target, int modifier) /* target->region kann != u->region sein, wenn es um durchreisen geht */ { - if (fval(target->race, RCF_INVISIBLE) || target->number == 0) return false; - else if (target->faction == u->faction) return true; + if (fval(target->race, RCF_INVISIBLE) || target->number == 0) + return false; + else if (target->faction == u->faction) + return true; else { int n, rings, o; - if (is_guard(target, GUARD_ALL)!=0 || usiege(target) || target->building || target->ship) { + if (is_guard(target, GUARD_ALL) != 0 || usiege(target) || target->building + || target->ship) { return true; } n = eff_stealth(target, target->region) - modifier; rings = invisible(target, NULL); - if (rings==0 && n<=0) { + if (rings == 0 && n <= 0) { return true; } @@ -1081,34 +1181,39 @@ cansee_unit(const unit * u, const unit * target, int modifier) } boolean -cansee_durchgezogen(const faction * f, const region * r, const unit * u, int modifier) +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 */ { int n; + unit *u2; - if (fval(u->race, RCF_INVISIBLE) || u->number == 0) return false; - else if (u->faction == f) return true; + if (fval(u->race, RCF_INVISIBLE) || u->number == 0) + return false; + else if (u->faction == f) + return true; else { int rings; - if (is_guard(u, GUARD_ALL)!=0 || usiege(u) || u->building || u->ship) { + if (is_guard(u, GUARD_ALL) != 0 || usiege(u) || u->building || u->ship) { return true; } n = eff_stealth(u, r) - modifier; rings = invisible(u, NULL); - if (rings==0 && n<=0) { + if (rings == 0 && n <= 0) { return true; } - for (u2 = r->units; u2; u2 = u2->next){ + for (u2 = r->units; u2; u2 = u2->next) { if (u2->faction == f) { int o; - if (rings && invisible(u, u2) >= u->number) continue; + if (rings && invisible(u, u2) >= u->number) + continue; o = eff_skill(u2, SK_PERCEPTION, r); @@ -1122,10 +1227,10 @@ cansee_durchgezogen(const faction * f, const region * r, const unit * u, int mod } #ifndef NDEBUG -const char * -strcheck (const char *s, size_t maxlen) +const char *strcheck(const char *s, size_t maxlen) { static char buffer[16 * 1024]; + if (strlen(s) > maxlen) { assert(maxlen < 16 * 1024); log_warning(("[strcheck] String wurde auf %d Zeichen verkürzt:\n%s\n", @@ -1139,7 +1244,7 @@ strcheck (const char *s, size_t maxlen) static attrib_type at_lighthouse = { "lighthouse" - /* Rest ist NULL; temporäres, nicht alterndes Attribut */ + /* Rest ist NULL; temporäres, nicht alterndes Attribut */ }; /* update_lighthouse: call this function whenever the size of a lighthouse changes @@ -1147,83 +1252,97 @@ static attrib_type at_lighthouse = { * The existence of markers says nothing about the quality of the observer in * the lighthouse, for this may change more frequently. */ -void -update_lighthouse(building * lh) +void update_lighthouse(building * lh) { static boolean init_lighthouse = false; - static const struct building_type * bt_lighthouse = 0; + + static const struct building_type *bt_lighthouse = 0; if (!init_lighthouse) { bt_lighthouse = bt_find("lighthouse"); - if (bt_lighthouse==NULL) return; + if (bt_lighthouse == NULL) + return; init_lighthouse = true; } - if (lh->type==bt_lighthouse) { - region * r = lh->region; + if (lh->type == bt_lighthouse) { + region *r = lh->region; + int d = (int)log10(lh->size) + 1; + int x; - if (lh->size>0) { + if (lh->size > 0) { r->flags |= RF_LIGHTHOUSE; } - for (x=-d;x<=d;++x) { + for (x = -d; x <= d; ++x) { int y; - for (y=-d;y<=d;++y) { - attrib * a; - region * r2; - int px = r->x+x, py = r->y+y; + + for (y = -d; y <= d; ++y) { + attrib *a; + + region *r2; + + int px = r->x + x, py = r->y + y; + pnormalize(&px, &py, rplane(r)); r2 = findregion(px, py); - if (r2==NULL) continue; - if (!fval(r2->terrain, SEA_REGION)) continue; - if (distance(r, r2) > d) continue; + if (r2 == NULL) + continue; + if (!fval(r2->terrain, SEA_REGION)) + continue; + if (distance(r, r2) > d) + continue; a = a_find(r2->attribs, &at_lighthouse); - while (a && a->type==&at_lighthouse) { - building * b = (building*)a->data.v; - if (b==lh) break; + while (a && a->type == &at_lighthouse) { + building *b = (building *) a->data.v; + + if (b == lh) + break; a = a->next; } if (!a) { a = a_add(&r2->attribs, a_new(&at_lighthouse)); - a->data.v = (void*)lh; + a->data.v = (void *)lh; } } } } } -int -count_all(const faction * f) +int count_all(const faction * f) { #ifndef NDEBUG int n = 0; + unit *u; - for (u=f->units;u;u=u->nextF) { + + for (u = f->units; u; u = u->nextF) { if (playerrace(u->race)) { n += u->number; - assert(f==u->faction); + assert(f == u->faction); } } if (f->num_people != n) { log_error(("# of people in %s is != num_people: %d should be %d.\n", - factionid(f), f->num_people, n)); + factionid(f), f->num_people, n)); } #endif return f->num_people; } -int -count_migrants (const faction * f) +int count_migrants(const faction * f) { unit *u = f->units; + int n = 0; + while (u) { assert(u->faction == f); - if (u->race != f->race && u->race != new_race[RC_ILLUSION] && u->race != new_race[RC_SPELL] - && !!playerrace(u->race) && !(is_cursed(u->attribs, C_SLAVE, 0))) - { + if (u->race != f->race && u->race != new_race[RC_ILLUSION] + && u->race != new_race[RC_SPELL] + && !!playerrace(u->race) && !(is_cursed(u->attribs, C_SLAVE, 0))) { n += u->number; } u = u->nextF; @@ -1231,21 +1350,23 @@ count_migrants (const faction * f) return n; } -int -count_maxmigrants(const faction * f) +int count_maxmigrants(const faction * f) { static int migrants = -1; - if (migrants<0) { + if (migrants < 0) { migrants = get_param_int(global.parameters, "rules.migrants", INT_MAX); } - if (migrants==INT_MAX) { + if (migrants == INT_MAX) { int x = 0; + if (f->race == new_race[RC_HUMAN]) { int nsize = count_all(f); - if (nsize>0) { + + if (nsize > 0) { x = (int)(log10(nsize / 50.0) * 20); - if (x < 0) x = 0; + if (x < 0) + x = 0; } } return x; @@ -1253,97 +1374,103 @@ count_maxmigrants(const faction * f) return migrants; } -void -init_tokens(const struct order * ord) +void init_tokens(const struct order *ord) { - char * cmd = getcommand(ord); + char *cmd = getcommand(ord); + init_tokens_str(cmd, cmd); } void -parse(keyword_t kword, int (*dofun)(unit *, struct order *), boolean thisorder) +parse(keyword_t kword, int (*dofun) (unit *, struct order *), boolean thisorder) { region *r; for (r = regions; r; r = r->next) { unit **up = &r->units; + while (*up) { - unit * u = *up; - order ** ordp = &u->orders; - if (thisorder) ordp = &u->thisorder; + unit *u = *up; + + order **ordp = &u->orders; + + if (thisorder) + ordp = &u->thisorder; while (*ordp) { - order * ord = *ordp; + order *ord = *ordp; + if (get_keyword(ord) == kword) { - if (dofun(u, ord)!=0) break; - if (u->orders==NULL) break; + if (dofun(u, ord) != 0) + break; + if (u->orders == NULL) + break; } - if (thisorder) break; - if (*ordp==ord) ordp=&ord->next; + if (thisorder) + break; + if (*ordp == ord) + ordp = &ord->next; } - if (*up==u) up=&u->next; + if (*up == u) + up = &u->next; } } } -const char * -igetstrtoken(const char * initstr) +const char *igetstrtoken(const char *initstr) { - if (initstr!=NULL) { + if (initstr != NULL) { init_tokens_str(initstr, NULL); } return getstrtoken(); } -unsigned int -getuint (void) +unsigned int getuint(void) { return atoip((const char *)getstrtoken()); } -int -getint (void) +int getint(void) { return atoi((const char *)getstrtoken()); } -const struct race * -findrace(const char * s, const struct locale * lang) +const struct race *findrace(const char *s, const struct locale *lang) { - struct tnode * tokens = get_translations(lang, UT_RACES); + struct tnode *tokens = get_translations(lang, UT_RACES); + variant token; assert(lang); - if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { + if (findtoken(tokens, s, &token) == E_TOK_SUCCESS) { return (const struct race *)token.v; } return NULL; } -int -findoption(const char *s, const struct locale * lang) +int findoption(const char *s, const struct locale *lang) { - struct tnode * tokens = get_translations(lang, UT_OPTIONS); + struct tnode *tokens = get_translations(lang, UT_OPTIONS); + variant token; - if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { - return (direction_t)token.i; + if (findtoken(tokens, s, &token) == E_TOK_SUCCESS) { + return (direction_t) token.i; } return NODIRECTION; } #if PTRIES -static struct trie_node * ptries[UT_MAX][4]; +static struct trie_node *ptries[UT_MAX][4]; -static struct trie_node ** -get_ptrie(const struct locale * lang, int type) +static struct trie_node **get_ptrie(const struct locale *lang, int type) { - int index = (strcmp(locale_name(lang), "de")==0); + int index = (strcmp(locale_name(lang), "de") == 0); + return &(ptries[type][index]); } -static int -umlaut_substitution(const char * ip, char * op, size_t outlen) +static int umlaut_substitution(const char *ip, char *op, size_t outlen) { #define UMAX 7 static struct replace { @@ -1351,33 +1478,45 @@ umlaut_substitution(const char * ip, char * op, size_t outlen) const char str[3]; } replace[UMAX] = { /* match lower-case (!) umlauts and others to transcriptions */ - { 223, "ss"}, /* szlig */ - { 228, "ae"}, /* auml */ - { 229, "aa"}, /* norsk */ - { 230, "ae"}, /* norsk */ - { 246, "oe"}, /* ouml */ - { 248, "oe"}, /* norsk */ - { 252, "ue"}, /* uuml */ + { + 223, "ss"}, /* szlig */ + { + 228, "ae"}, /* auml */ + { + 229, "aa"}, /* norsk */ + { + 230, "ae"}, /* norsk */ + { + 246, "oe"}, /* ouml */ + { + 248, "oe"}, /* norsk */ + { + 252, "ue"}, /* uuml */ }; int subs = 0; + while (*ip) { ucs4_t ucs = *ip; + size_t size = 1; + size_t cpsize = 1; if (ucs & 0x80) { int ret = unicode_utf8_to_ucs4(&ucs, ip, &size); - if (ret!=0) { + + if (ret != 0) { return ret; } cpsize = size; - if (ucs >= replace[0].ucs && ucs <= replace[UMAX-1].ucs) { + if (ucs >= replace[0].ucs && ucs <= replace[UMAX - 1].ucs) { int i; - for (i=0;i!=UMAX;++i) { - if (replace[i].ucs==ucs) { + + for (i = 0; i != UMAX; ++i) { + if (replace[i].ucs == ucs) { cpsize = 0; memcpy(op, replace[i].str, 2); - op+=2; + op += 2; ++subs; break; } @@ -1385,7 +1524,7 @@ umlaut_substitution(const char * ip, char * op, size_t outlen) } } if (cpsize) { - if (cpsize>outlen) { + if (cpsize > outlen) { return -1; } memcpy(op, ip, cpsize); @@ -1396,7 +1535,7 @@ umlaut_substitution(const char * ip, char * op, size_t outlen) outlen -= cpsize; } - if (outlen<=0) { + if (outlen <= 0) { return -1; } *op = 0; @@ -1404,11 +1543,13 @@ umlaut_substitution(const char * ip, char * op, size_t outlen) } static int -ptrie_find(struct trie_node *ptrie, const char * key, void * data, size_t size) +ptrie_find(struct trie_node *ptrie, const char *key, void *data, size_t size) { - trie_node * node = trie_find_prefix(ptrie, key); + trie_node *node = trie_find_prefix(ptrie, key); + if (node) { - void * result = trie_getdata(node); + void *result = trie_getdata(node); + memcpy(data, result, size); return 0; } @@ -1416,14 +1557,19 @@ ptrie_find(struct trie_node *ptrie, const char * key, void * data, size_t size) } static int -ptrie_insert(struct trie_node **ptrie, const char * name, void * data, size_t size) +ptrie_insert(struct trie_node **ptrie, const char *name, void *data, + size_t size) { char converted[256]; + char simple[256]; + int ret = unicode_utf8_tolower(converted, 256, name); - if (ret==0) { + + if (ret == 0) { int subs = umlaut_substitution(converted, simple, sizeof(simple)); - if (subs>0) { + + if (subs > 0) { trie_insert(ptrie, simple, data, size); } trie_insert(ptrie, converted, data, size); @@ -1432,76 +1578,86 @@ ptrie_insert(struct trie_node **ptrie, const char * name, void * data, size_t si } #endif -skill_t -findskill(const char *s, const struct locale * lang) +skill_t findskill(const char *s, const struct locale * lang) { #if PTRIES char lowercase[256]; + int res = unicode_utf8_tolower(lowercase, sizeof(lowercase), s); - if (res==0) { - trie_node ** ptrie = get_ptrie(lang, UT_SKILLS); + + if (res == 0) { + trie_node **ptrie = get_ptrie(lang, UT_SKILLS); + skill_t sk; + int result = ptrie_find(*ptrie, lowercase, &sk, sizeof(sk)); - if (result==0) return sk; + + if (result == 0) + return sk; } return NOSKILL; #else - struct tnode * tokens = get_translations(lang, UT_SKILLS); + struct tnode *tokens = get_translations(lang, UT_SKILLS); + variant token; - if (findtoken(tokens, s, &token)==E_TOK_NOMATCH) return NOSKILL; - return (skill_t)token.i; + if (findtoken(tokens, s, &token) == E_TOK_NOMATCH) + return NOSKILL; + return (skill_t) token.i; #endif } -keyword_t -findkeyword(const char *s, const struct locale * lang) +keyword_t findkeyword(const char *s, const struct locale * lang) { - struct tnode * tokens = get_translations(lang, UT_KEYWORDS); + struct tnode *tokens = get_translations(lang, UT_KEYWORDS); + variant token; - if (*s == '@') s++; - if (findtoken(tokens, s, &token)==E_TOK_NOMATCH) return NOKEYWORD; - if (global.disabled[token.i]) return NOKEYWORD; + if (*s == '@') + s++; + if (findtoken(tokens, s, &token) == E_TOK_NOMATCH) + return NOKEYWORD; + if (global.disabled[token.i]) + return NOKEYWORD; return (keyword_t) token.i; } -param_t -findparam(const char *s, const struct locale * lang) +param_t findparam(const char *s, const struct locale * lang) { - struct tnode * tokens = get_translations(lang, UT_PARAMS); + struct tnode *tokens = get_translations(lang, UT_PARAMS); + variant token; - if (findtoken(tokens, s, &token)==E_TOK_NOMATCH) { - const building_type * btype = findbuildingtype(s, lang); - if (btype!=NULL) return (param_t) P_GEBAEUDE; + if (findtoken(tokens, s, &token) == E_TOK_NOMATCH) { + const building_type *btype = findbuildingtype(s, lang); + + if (btype != NULL) + return (param_t) P_GEBAEUDE; return NOPARAM; } - if (token.i==P_BUILDING) return P_GEBAEUDE; - return (param_t)token.i; + if (token.i == P_BUILDING) + return P_GEBAEUDE; + return (param_t) token.i; } -param_t -getparam (const struct locale * lang) +param_t getparam(const struct locale * lang) { - return findparam (getstrtoken (), lang); + return findparam(getstrtoken(), lang); } -faction * -findfaction (int n) +faction *findfaction(int n) { - faction * f = ffindhash(n); + faction *f = ffindhash(n); + return f; } -faction * -getfaction (void) +faction *getfaction(void) { - return findfaction (getid()); + return findfaction(getid()); } -unit * -findunitr (const region * r, int n) +unit *findunitr(const region * r, int n) { unit *u; @@ -1522,8 +1678,7 @@ unit *findunit(int n) return ufindhash(n); } -unit * -findunitg (int n, const region * hint) +unit *findunitg(int n, const region * hint) { /* Abfangen von Syntaxfehlern. */ @@ -1535,42 +1690,43 @@ findunitg (int n, const region * hint) return ufindhash(n); } -unit * -getnewunit (const region * r, const faction * f) +unit *getnewunit(const region * r, const faction * f) { int n; + n = getid(); - return findnewunit (r, f, n); + return findnewunit(r, f, n); } -static int -read_newunitid (const faction * f, const region * r) +static int read_newunitid(const faction * f, const region * r) { int n; + unit *u2; + n = getid(); if (n == 0) return -1; u2 = findnewunit(r, f, n); - if (u2) return u2->no; + if (u2) + return u2->no; return -1; } -int -read_unitid (const faction * f, const region * r) +int read_unitid(const faction * f, const region * r) { - const char * s = getstrtoken(); + const char *s = getstrtoken(); /* Da s nun nur einen string enthaelt, suchen wir ihn direkt in der * paramliste. machen wir das nicht, dann wird getnewunit in s nach der * nummer suchen, doch dort steht bei temp-units nur "temp" drinnen! */ switch (findparam(s, f->locale)) { - case P_TEMP: - return read_newunitid(f, r); + case P_TEMP: + return read_newunitid(f, r); } if (!s || *s == 0) return -1; @@ -1579,8 +1735,8 @@ read_unitid (const faction * f, const region * r) /* exported symbol */ boolean getunitpeasants; -unit * -getunitg(const region * r, const faction * f) + +unit *getunitg(const region * r, const faction * f) { int n = read_unitid(f, r); @@ -1589,15 +1745,16 @@ getunitg(const region * r, const faction * f) return NULL; } getunitpeasants = 0; - if (n < 0) return 0; + if (n < 0) + return 0; return findunit(n); } -unit * -getunit(const region * r, const faction * f) +unit *getunit(const region * r, const faction * f) { int n = read_unitid(f, r); + unit *u2; if (n == 0) { @@ -1605,14 +1762,15 @@ getunit(const region * r, const faction * f) return NULL; } getunitpeasants = 0; - if (n < 0) return 0; + if (n < 0) + return 0; u2 = findunit(n); - if (u2!=NULL && u2->region==r) { + if (u2 != NULL && u2->region == r) { /* there used to be a 'u2->flags & UFL_ISNEW || u2->number>0' condition - * here, but it got removed because of a bug that made units disappear: - * http://eressea.upb.de/mantis/bug_view_page.php?bug_id=0000172 - */ + * here, but it got removed because of a bug that made units disappear: + * http://eressea.upb.de/mantis/bug_view_page.php?bug_id=0000172 + */ return u2; } @@ -1620,19 +1778,19 @@ getunit(const region * r, const faction * f) } /* - String Listen --------------------------------------------- */ -void -addstrlist (strlist ** SP, const char *s) +void addstrlist(strlist ** SP, const char *s) { - strlist * slist = malloc(sizeof(strlist)); + strlist *slist = malloc(sizeof(strlist)); + slist->next = NULL; slist->s = strdup(s); addlist(SP, slist); } -void -freestrlist (strlist * s) +void freestrlist(strlist * s) { strlist *q, *p = s; + while (p) { q = p->next; free(p->s); @@ -1646,17 +1804,18 @@ freestrlist (strlist * s) boolean lomem = false; /* - Namen der Strukturen -------------------------------------- */ -typedef char name[OBJECTIDSIZE+1]; +typedef char name[OBJECTIDSIZE + 1]; + static name idbuf[8]; + static int nextbuf = 0; -char * -estring_i(char *ibuf) +char *estring_i(char *ibuf) { char *p = ibuf; while (*p) { - if (isxspace(*(unsigned*)p) == ' ') { + if (isxspace(*(unsigned *)p) == ' ') { *p = '~'; } ++p; @@ -1664,8 +1823,7 @@ estring_i(char *ibuf) return ibuf; } -char * -estring(const char *s) +char *estring(const char *s) { char *ibuf = idbuf[(++nextbuf) % 8]; @@ -1673,8 +1831,7 @@ estring(const char *s) return estring_i(ibuf); } -char * -cstring_i(char *ibuf) +char *cstring_i(char *ibuf) { char *p = ibuf; @@ -1687,8 +1844,7 @@ cstring_i(char *ibuf) return ibuf; } -char * -cstring(const char *s) +char *cstring(const char *s) { char *ibuf = idbuf[(++nextbuf) % 8]; @@ -1696,89 +1852,98 @@ cstring(const char *s) return cstring_i(ibuf); } -building * -largestbuilding(const region * r, cmp_building_cb cmp_gt, boolean imaginary) +building *largestbuilding(const region * r, cmp_building_cb cmp_gt, + boolean imaginary) { building *b, *best = NULL; for (b = rbuildings(r); b; b = b->next) { - if (cmp_gt(b, best)<=0) continue; + if (cmp_gt(b, best) <= 0) + continue; if (!imaginary) { - const attrib * a = a_find(b->attribs, &at_icastle); - if (a) continue; + const attrib *a = a_find(b->attribs, &at_icastle); + + if (a) + continue; } best = b; } return best; } -char * -write_unitname(const unit * u, char * buffer, size_t size) +char *write_unitname(const unit * u, char *buffer, size_t size) { - snprintf((char*)buffer, size, "%s (%s)", (const char*)u->name, itoa36(u->no)); - buffer[size-1] = 0; + snprintf((char *)buffer, size, "%s (%s)", (const char *)u->name, + itoa36(u->no)); + buffer[size - 1] = 0; return buffer; } -const char * -unitname(const unit * u) +const char *unitname(const unit * u) { char *ubuf = idbuf[(++nextbuf) % 8]; + return write_unitname(u, ubuf, sizeof(name)); } /* -- Erschaffung neuer Einheiten ------------------------------ */ -extern faction * dfindhash(int i); +extern faction *dfindhash(int i); -static const char* forbidden[] = { "t", "te", "tem", "temp", NULL }; +static const char *forbidden[] = { "t", "te", "tem", "temp", NULL }; -int -forbiddenid(int id) +int forbiddenid(int id) { - static int * forbid = NULL; + static int *forbid = NULL; + static size_t len; + size_t i; - if (id<=0) return 1; + + if (id <= 0) + return 1; if (!forbid) { - while (forbidden[len]) ++len; + while (forbidden[len]) + ++len; forbid = calloc(len, sizeof(int)); - for (i=0;i!=len;++i) { + for (i = 0; i != len; ++i) { forbid[i] = strtol(forbidden[i], NULL, 36); } } - for (i=0;i!=len;++i) if (id==forbid[i]) return 1; + for (i = 0; i != len; ++i) + if (id == forbid[i]) + return 1; return 0; } /* ID's für Einheiten und Zauber */ -int -newunitid(void) +int newunitid(void) { int random_unit_no; + int start_random_no; + random_unit_no = 1 + (rng_int() % MAX_UNIT_NR); start_random_no = random_unit_no; while (ufindhash(random_unit_no) || dfindhash(random_unit_no) - || cfindhash(random_unit_no) - || forbiddenid(random_unit_no)) - { + || cfindhash(random_unit_no) + || forbiddenid(random_unit_no)) { random_unit_no++; if (random_unit_no == MAX_UNIT_NR + 1) { random_unit_no = 1; } if (random_unit_no == start_random_no) { - random_unit_no = (int) MAX_UNIT_NR + 1; + random_unit_no = (int)MAX_UNIT_NR + 1; } } return random_unit_no; } -int -newcontainerid(void) +int newcontainerid(void) { int random_no; + int start_random_no; random_no = 1 + (rng_int() % MAX_CONTAINER_NR); @@ -1790,56 +1955,60 @@ newcontainerid(void) random_no = 1; } if (random_no == start_random_no) { - random_no = (int) MAX_CONTAINER_NR + 1; + random_no = (int)MAX_CONTAINER_NR + 1; } } return random_no; } -unit * -createunit(region * r, faction * f, int number, const struct race * rc) +unit *createunit(region * r, faction * f, int number, const struct race * rc) { assert(rc); return create_unit(r, f, number, rc, 0, NULL, NULL); } -boolean -idle (faction * f) +boolean idle(faction * f) { return (boolean) (f ? false : true); } -int -maxworkingpeasants(const struct region * r) +int maxworkingpeasants(const struct region *r) { int i = production(r) * MAXPEASANTS_PER_AREA - - ((rtrees(r,2)+rtrees(r,1)/2) * TREESIZE); + - ((rtrees(r, 2) + rtrees(r, 1) / 2) * TREESIZE); return MAX(i, 0); } -int -lighthouse_range(const building * b, const faction * f) +int lighthouse_range(const building * b, const faction * f) { int d = 0; + if (fval(b, BLD_WORKING) && b->size >= 10) { int maxd = (int)log10(b->size) + 1; if (skill_enabled[SK_PERCEPTION]) { - region * r = b->region; + region *r = b->region; + int c = 0; + unit *u; + for (u = r->units; u; u = u->next) { if (u->building == b) { c += u->number; - if (c > buildingcapacity(b)) break; - if (f==NULL || u->faction == f) { + if (c > buildingcapacity(b)) + break; + if (f == NULL || u->faction == f) { int sk = eff_skill(u, SK_PERCEPTION, r) / 3; + d = MAX(d, sk); d = MIN(maxd, d); - if (d==maxd) break; + if (d == maxd) + break; } - } else if (c) break; /* first unit that's no longer in the house ends the search */ + } else if (c) + break; /* first unit that's no longer in the house ends the search */ } } else { /* E3A rule: no perception req'd */ @@ -1849,15 +2018,16 @@ lighthouse_range(const building * b, const faction * f) return d; } -boolean -check_leuchtturm(region * r, faction * f) +boolean check_leuchtturm(region * r, faction * f) { - attrib * a; + attrib *a; - if (!fval(r->terrain, SEA_REGION)) return false; + if (!fval(r->terrain, SEA_REGION)) + return false; - for (a = a_find(r->attribs, &at_lighthouse);a && a->type==&at_lighthouse;a=a->next) { - building *b = (building *)a->data.v; + for (a = a_find(r->attribs, &at_lighthouse); a && a->type == &at_lighthouse; + a = a->next) { + building *b = (building *) a->data.v; assert(b->type == bt_find("lighthouse")); if (fval(b, BLD_WORKING) && b->size >= 10) { @@ -1865,20 +2035,28 @@ check_leuchtturm(region * r, faction * f) if (skill_enabled[SK_PERCEPTION]) { region *r2 = b->region; + unit *u; + int c = 0; + int d = 0; for (u = r2->units; u; u = u->next) { if (u->building == b) { c += u->number; - if (c > buildingcapacity(b)) break; - if (f==NULL || u->faction == f) { - if (!d) d = distance(r, r2); - if (maxd < d) break; - if (eff_skill(u, SK_PERCEPTION, r) >= d * 3) return true; + if (c > buildingcapacity(b)) + break; + if (f == NULL || u->faction == f) { + if (!d) + d = distance(r, r2); + if (maxd < d) + break; + if (eff_skill(u, SK_PERCEPTION, r) >= d * 3) + return true; } - } else if (c) break; /* first unit that's no longer in the house ends the search */ + } else if (c) + break; /* first unit that's no longer in the house ends the search */ } } else { /* E3A rule: no perception req'd */ @@ -1890,33 +2068,37 @@ check_leuchtturm(region * r, faction * f) return false; } -region * -lastregion (faction * f) +region *lastregion(faction * f) { #ifdef SMART_INTERVALS - unit * u = f->units; + unit *u = f->units; + region *r = f->last; - if (u==NULL) return NULL; - if (r!=NULL) return r->next; + if (u == NULL) + return NULL; + if (r != NULL) + return r->next; /* it is safe to start in the region of the first unit. */ f->last = u->region; /* if regions have indices, we can skip ahead: */ - for (u=u->nextF; u!=NULL; u=u->nextF) { + for (u = u->nextF; u != NULL; u = u->nextF) { r = u->region; - if (r->index > f->last->index) f->last = r; + if (r->index > f->last->index) + f->last = r; } /* we continue from the best region and look for travelthru etc. */ for (r = f->last->next; r; r = r->next) { - plane * p = rplane(r); + plane *p = rplane(r); /* search the region for travelthru-attributes: */ if (fval(r, RF_TRAVELUNIT)) { - attrib * ru = a_find(r->attribs, &at_travelunit); - while (ru && ru->type==&at_travelunit) { - u = (unit*)ru->data.v; + attrib *ru = a_find(r->attribs, &at_travelunit); + + while (ru && ru->type == &at_travelunit) { + u = (unit *) ru->data.v; if (u->faction == f) { f->last = r; break; @@ -1924,7 +2106,8 @@ lastregion (faction * f) ru = ru->next; } } - if (f->last == r) continue; + if (f->last == r) + continue; if (check_leuchtturm(r, f)) f->last = r; if (p && is_watcher(p, f)) { @@ -1937,14 +2120,15 @@ lastregion (faction * f) #endif } -region * -firstregion (faction * f) +region *firstregion(faction * f) { #ifdef SMART_INTERVALS region *r = f->first; - if (f->units==NULL) return NULL; - if (r!=NULL) return r; + if (f->units == NULL) + return NULL; + if (r != NULL) + return r; return f->first = regions; #else @@ -1952,109 +2136,121 @@ firstregion (faction * f) #endif } -void ** blk_list[1024]; +void **blk_list[1024]; + int list_index; + int blk_index; -static void -gc_done(void) +static void gc_done(void) { int i, k; - for (i=0;i!=list_index;++i) - { - for (k=0;k!=1024;++k) free(blk_list[i][k]); + + for (i = 0; i != list_index; ++i) { + for (k = 0; k != 1024; ++k) + free(blk_list[i][k]); free(blk_list[i]); } - for (k=0;k!=blk_index;++k) free(blk_list[list_index][k]); + for (k = 0; k != blk_index; ++k) + free(blk_list[list_index][k]); free(blk_list[list_index]); } -void * -gc_add(void * p) +void *gc_add(void *p) { - if (blk_index==0) { - blk_list[list_index] = (void**)malloc(1024 * sizeof(void*)); + if (blk_index == 0) { + blk_list[list_index] = (void **)malloc(1024 * sizeof(void *)); } blk_list[list_index][blk_index] = p; - blk_index = (blk_index+1) % 1024; - if (!blk_index) ++ list_index; + blk_index = (blk_index + 1) % 1024; + if (!blk_index) + ++list_index; return p; } -static void -init_directions(tnode * root, const struct locale * lang) +static void init_directions(tnode * root, const struct locale *lang) { /* mit dieser routine kann man mehrere namen für eine direction geben, * das ist für die hexes ideal. */ const struct { - const char* name; + const char *name; int direction; - } dirs [] = { - { "dir_ne", D_NORTHEAST}, - { "dir_nw", D_NORTHWEST}, - { "dir_se", D_SOUTHEAST}, - { "dir_sw", D_SOUTHWEST}, - { "dir_east", D_EAST}, - { "dir_west", D_WEST}, - { "northeast", D_NORTHEAST}, - { "northwest", D_NORTHWEST}, - { "southeast", D_SOUTHEAST}, - { "southwest", D_SOUTHWEST}, - { "east", D_EAST }, - { "west",D_WEST }, - { "PAUSE", D_PAUSE }, - { NULL, NODIRECTION} + } dirs[] = { + { + "dir_ne", D_NORTHEAST}, { + "dir_nw", D_NORTHWEST}, { + "dir_se", D_SOUTHEAST}, { + "dir_sw", D_SOUTHWEST}, { + "dir_east", D_EAST}, { + "dir_west", D_WEST}, { + "northeast", D_NORTHEAST}, { + "northwest", D_NORTHWEST}, { + "southeast", D_SOUTHEAST}, { + "southwest", D_SOUTHWEST}, { + "east", D_EAST}, { + "west", D_WEST}, { + "PAUSE", D_PAUSE}, { + NULL, NODIRECTION} }; int i; - struct tnode * tokens = get_translations(lang, UT_DIRECTIONS); - for (i=0; dirs[i].direction!=NODIRECTION;++i) { + struct tnode *tokens = get_translations(lang, UT_DIRECTIONS); + + for (i = 0; dirs[i].direction != NODIRECTION; ++i) { variant token; + token.i = dirs[i].direction; addtoken(tokens, LOC(lang, dirs[i].name), token); } } -direction_t -finddirection(const char *s, const struct locale * lang) +direction_t finddirection(const char *s, const struct locale *lang) { - struct tnode * tokens = get_translations(lang, UT_DIRECTIONS); + struct tnode *tokens = get_translations(lang, UT_DIRECTIONS); + variant token; - if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) { - return (direction_t)token.i; + if (findtoken(tokens, s, &token) == E_TOK_SUCCESS) { + return (direction_t) token.i; } return NODIRECTION; } -static void -init_locale(const struct locale * lang) +static void init_locale(const struct locale *lang) { variant var; + int i; - const struct race * rc; - struct tnode * tokens; - const terrain_type * terrain; + + const struct race *rc; + + struct tnode *tokens; + + const terrain_type *terrain; + #if PTRIES - trie_node ** ptrie; + trie_node **ptrie; #endif tokens = get_translations(lang, UT_MAGIC); if (tokens) { - const char * str = get_param(global.parameters, "rules.magic.playerschools"); - char * sstr, * tok; - if (str==NULL) { + const char *str = get_param(global.parameters, "rules.magic.playerschools"); + + char *sstr, *tok; + + if (str == NULL) { str = "gwyrrd illaun draig cerddor tybied"; } sstr = strdup(str); tok = strtok(sstr, " "); while (tok) { - for (i=0;i!=MAXMAGIETYP;++i) { - if (strcmp(tok, magic_school[i])==0) break; + for (i = 0; i != MAXMAGIETYP; ++i) { + if (strcmp(tok, magic_school[i]) == 0) + break; } - assert(i!=MAXMAGIETYP); + assert(i != MAXMAGIETYP); var.i = i; addtoken(tokens, LOC(lang, mkname("school", tok)), var); tok = strtok(NULL, " "); @@ -2066,31 +2262,34 @@ init_locale(const struct locale * lang) init_directions(tokens, lang); tokens = get_translations(lang, UT_RACES); - for (rc=races;rc;rc=rc->next) { - var.v = (void*)rc; + for (rc = races; rc; rc = rc->next) { + var.v = (void *)rc; addtoken(tokens, LOC(lang, rc_name(rc, 1)), var); addtoken(tokens, LOC(lang, rc_name(rc, 0)), var); } tokens = get_translations(lang, UT_PARAMS); - for (i=0;i!=MAXPARAMS;++i) { + for (i = 0; i != MAXPARAMS; ++i) { var.i = i; addtoken(tokens, LOC(lang, parameters[i]), var); } #if PTRIES ptrie = get_ptrie(lang, UT_SKILLS); - for (i=0;i!=MAXSKILLS;++i) { - skill_t sk = (skill_t)i; - const char * skname = skillname(sk, lang); - if (skname!=NULL) { + for (i = 0; i != MAXSKILLS; ++i) { + skill_t sk = (skill_t) i; + + const char *skname = skillname(sk, lang); + + if (skname != NULL) { ptrie_insert(ptrie, skname, &sk, sizeof(sk)); } } #else tokens = get_translations(lang, UT_SKILLS); - for (i=0;i!=MAXSKILLS;++i) { - const char * skname = skillname((skill_t)i, lang); - if (skname!=NULL) { + for (i = 0; i != MAXSKILLS; ++i) { + const char *skname = skillname((skill_t) i, lang); + + if (skname != NULL) { var.i = i; addtoken(tokens, skname, var); } @@ -2098,128 +2297,133 @@ init_locale(const struct locale * lang) #endif tokens = get_translations(lang, UT_KEYWORDS); - for (i=0;i!=MAXKEYWORDS;++i) { + for (i = 0; i != MAXKEYWORDS; ++i) { var.i = i; - if (keywords[i]) addtoken(tokens, LOC(lang, keywords[i]), var); + if (keywords[i]) + addtoken(tokens, LOC(lang, keywords[i]), var); } tokens = get_translations(lang, UT_OPTIONS); - for (i=0;i!=MAXOPTIONS;++i) { + for (i = 0; i != MAXOPTIONS; ++i) { var.i = i; - if (options[i]) addtoken(tokens, LOC(lang, options[i]), var); + if (options[i]) + addtoken(tokens, LOC(lang, options[i]), var); } tokens = get_translations(lang, UT_TERRAINS); - for (terrain=terrains();terrain!=NULL;terrain=terrain->next) { - var.v = (void*)terrain; + for (terrain = terrains(); terrain != NULL; terrain = terrain->next) { + var.v = (void *)terrain; addtoken(tokens, LOC(lang, terrain->_name), var); } } typedef struct param { - struct param * next; - char * name; - char * data; + struct param *next; + char *name; + char *data; } param; -int -getid(void) +int getid(void) { - const char * str = (const char *)getstrtoken(); + const char *str = (const char *)getstrtoken(); + int i = atoi36(str); - if (i<0) { + + if (i < 0) { return -1; } return i; } -const char * -get_param(const struct param * p, const char * key) +const char *get_param(const struct param *p, const char *key) { - while (p!=NULL) { - if (strcmp(p->name, key)==0) return p->data; + while (p != NULL) { + if (strcmp(p->name, key) == 0) + return p->data; p = p->next; } return NULL; } -int -get_param_int(const struct param * p, const char * key, int def) +int get_param_int(const struct param *p, const char *key, int def) { - while (p!=NULL) { - if (strcmp(p->name, key)==0) return atoi(p->data); + while (p != NULL) { + if (strcmp(p->name, key) == 0) + return atoi(p->data); p = p->next; } return def; } -static const char * g_datadir; -const char * -datapath(void) +static const char *g_datadir; + +const char *datapath(void) { static char zText[MAX_PATH]; - if (g_datadir) return g_datadir; + + if (g_datadir) + return g_datadir; return strcat(strcpy(zText, basepath()), "/data"); } -void -set_datapath(const char * path) +void set_datapath(const char *path) { g_datadir = path; } -static const char * g_reportdir; -const char * -reportpath(void) +static const char *g_reportdir; + +const char *reportpath(void) { static char zText[MAX_PATH]; - if (g_reportdir) return g_reportdir; + + if (g_reportdir) + return g_reportdir; return strcat(strcpy(zText, basepath()), "/reports"); } -void -set_reportpath(const char * path) +void set_reportpath(const char *path) { g_reportdir = path; } -static const char * g_basedir; -const char * -basepath(void) +static const char *g_basedir; + +const char *basepath(void) { - if (g_basedir) return g_basedir; + if (g_basedir) + return g_basedir; return "."; } -void -set_basepath(const char * path) +void set_basepath(const char *path) { g_basedir = path; } -float -get_param_flt(const struct param * p, const char * key, float def) +float get_param_flt(const struct param *p, const char *key, float def) { - while (p!=NULL) { - if (strcmp(p->name, key)==0) return (float)atof(p->data); + while (p != NULL) { + if (strcmp(p->name, key) == 0) + return (float)atof(p->data); p = p->next; } return def; } -void -set_param(struct param ** p, const char * key, const char * data) +void set_param(struct param **p, const char *key, const char *data) { ++global.cookie; - while (*p!=NULL) { - if (strcmp((*p)->name, key)==0) { + + while (*p != NULL) { + if (strcmp((*p)->name, key) == 0) { free((*p)->data); (*p)->data = strdup(data); return; } - p=&(*p)->next; + p = &(*p)->next; } *p = malloc(sizeof(param)); (*p)->name = strdup(key); @@ -2227,8 +2431,7 @@ set_param(struct param ** p, const char * key, const char * data) (*p)->next = NULL; } -void -kernel_done(void) +void kernel_done(void) { /* calling this function releases memory assigned to static variables, etc. * calling it is optional, e.g. a release server will most likely not do it. @@ -2238,18 +2441,20 @@ kernel_done(void) sql_done(); } -const char * localenames[] = { +const char *localenames[] = { "de", "en", NULL }; -void -init_locales(void) +void init_locales(void) { int l; - for (l=0;localenames[l];++l) { - const struct locale * lang = find_locale(localenames[l]); - if (lang) init_locale(lang); + + for (l = 0; localenames[l]; ++l) { + const struct locale *lang = find_locale(localenames[l]); + + if (lang) + init_locale(lang); } } @@ -2279,46 +2484,48 @@ attrib_type at_guard = { ATF_UNIQUE }; -void -setstatus(struct unit * u, int status) +void setstatus(struct unit *u, int status) { - assert(status>=ST_AGGRO && status<=ST_FLEE); - if (u->status!=status) { - u->status = (status_t)status; + assert(status >= ST_AGGRO && status <= ST_FLEE); + if (u->status != status) { + u->status = (status_t) status; } } -void -setguard(unit * u, unsigned int flags) +void setguard(unit * u, unsigned int flags) { /* setzt die guard-flags der Einheit */ - attrib * a = NULL; - assert(flags==0 || !fval(u, UFL_MOVED)); - assert(flags==0 || u->statusstatus < ST_FLEE); if (fval(u, UFL_GUARD)) { a = a_find(u->attribs, &at_guard); } if (flags == GUARD_NONE) { freset(u, UFL_GUARD); - if (a) a_remove(&u->attribs, a); + if (a) + a_remove(&u->attribs, a); return; } fset(u, UFL_GUARD); fset(u->region, RF_GUARDED); - if ((int)flags==guard_flags(u)) { - if (a) a_remove(&u->attribs, a); + if ((int)flags == guard_flags(u)) { + if (a) + a_remove(&u->attribs, a); } else { - if (!a) a = a_add(&u->attribs, a_new(&at_guard)); + if (!a) + a = a_add(&u->attribs, a_new(&at_guard)); a->data.i = (int)flags; } } -unsigned int -getguard(const unit * u) +unsigned int getguard(const unit * u) { - attrib * a; - - assert((u->building && fval(u, UFL_OWNER)) || fval(u, UFL_GUARD) || !"you're doing it wrong! check is_guard first"); + attrib *a; + + assert((u->building && fval(u, UFL_OWNER)) || fval(u, UFL_GUARD) + || !"you're doing it wrong! check is_guard first"); a = a_find(u->attribs, &at_guard); if (a) { return (unsigned int)a->data.i; @@ -2327,98 +2534,105 @@ getguard(const unit * u) } #ifndef HAVE_STRDUP -char * -strdup(const char *s) +char *strdup(const char *s) { - return strcpy((char*)malloc(sizeof(char)*(strlen(s)+1)), s); + return strcpy((char *)malloc(sizeof(char) * (strlen(s) + 1)), s); } #endif -void -remove_empty_factions(void) +void remove_empty_factions(void) { faction **fp, *f3; for (fp = &factions; *fp;) { - faction * f = *fp; + faction *f = *fp; + /* monster (0) werden nicht entfernt. alive kann beim readgame * () auf 0 gesetzt werden, wenn monsters keine einheiten mehr * haben. */ - if ((f->units==NULL || f->alive == 0) && !is_monsters(f)) { - ursprung * ur = f->ursprung; - while (ur && ur->id!=0) ur=ur->next; - if (verbosity>=2) log_stdio(stdout, "\t%s\n", factionname(f)); + if ((f->units == NULL || f->alive == 0) && !is_monsters(f)) { + ursprung *ur = f->ursprung; + + while (ur && ur->id != 0) + ur = ur->next; + if (verbosity >= 2) + log_stdio(stdout, "\t%s\n", factionname(f)); /* Einfach in eine Datei schreiben und später vermailen */ - if (updatelog) fprintf(updatelog, "dropout %s\n", itoa36(f->no)); + if (updatelog) + fprintf(updatelog, "dropout %s\n", itoa36(f->no)); for (f3 = factions; f3; f3 = f3->next) { - ally * sf; - group * g; - ally ** sfp = &f3->allies; + ally *sf; + + group *g; + + ally **sfp = &f3->allies; + while (*sfp) { sf = *sfp; if (sf->faction == f || sf->faction == NULL) { *sfp = sf->next; free(sf); - } - else sfp = &(*sfp)->next; + } else + sfp = &(*sfp)->next; } - for (g = f3->groups; g; g=g->next) { + for (g = f3->groups; g; g = g->next) { sfp = &g->allies; while (*sfp) { sf = *sfp; if (sf->faction == f || sf->faction == NULL) { *sfp = sf->next; free(sf); - } - else sfp = &(*sfp)->next; + } else + sfp = &(*sfp)->next; } } } if (f->subscription) { sql_print(("UPDATE subscriptions set status='DEAD' where id=%u;\n", - f->subscription)); + f->subscription)); } *fp = f->next; funhash(f); free_faction(f); free(f); - } - else fp = &(*fp)->next; + } else + fp = &(*fp)->next; } } -void -remove_empty_units_in_region(region *r) +void remove_empty_units_in_region(region * r) { unit **up = &r->units; while (*up) { - unit * u = *up; + unit *u = *up; if (u->number) { - faction * f = u->faction; - if (f==NULL || !f->alive) { + faction *f = u->faction; + + if (f == NULL || !f->alive) { set_number(u, 0); } - if (MaxAge()>0) { + if (MaxAge() > 0) { if ((!fval(f, FFL_NOTIMEOUT) && f->age > MaxAge())) { set_number(u, 0); } } } - if ((u->number == 0 && u->race != new_race[RC_SPELL]) || (u->age <= 0 && u->race == new_race[RC_SPELL])) { + if ((u->number == 0 && u->race != new_race[RC_SPELL]) || (u->age <= 0 + && u->race == new_race[RC_SPELL])) { remove_unit(up, u); } - if (*up==u) up=&u->next; + if (*up == u) + up = &u->next; } } -void -remove_empty_units(void) +void remove_empty_units(void) { region *r; @@ -2427,46 +2641,45 @@ remove_empty_units(void) } } -boolean -faction_id_is_unused(int id) +boolean faction_id_is_unused(int id) { - return findfaction(id)==NULL; + return findfaction(id) == NULL; } -int -weight(const unit * u) +int weight(const unit * u) { int w, n = 0, in_bag = 0; - item * itm; - for (itm=u->items;itm;itm=itm->next) { + item *itm; + + for (itm = u->items; itm; itm = itm->next) { w = itm->type->weight * itm->number; n += w; - if( !fval(itm->type, ITF_BIG)) + if (!fval(itm->type, ITF_BIG)) in_bag += w; } n += u->number * u->race->weight; w = get_item(u, I_BAG_OF_HOLDING) * BAGCAPACITY; - if( w > in_bag ) + if (w > in_bag) w = in_bag; n -= w; return n; } -void -make_undead_unit(unit * u) +void make_undead_unit(unit * u) { free_orders(&u->orders); name_unit(u); fset(u, UFL_ISNEW); } -unsigned int guard_flags(const unit * u) +unsigned int guard_flags(const unit * u) { - unsigned int flags = GUARD_CREWS | GUARD_LANDING | GUARD_TRAVELTHRU | GUARD_TAX; + unsigned int flags = + GUARD_CREWS | GUARD_LANDING | GUARD_TRAVELTHRU | GUARD_TAX; #if GUARD_DISABLES_PRODUCTION == 1 flags |= GUARD_PRODUCE; #endif @@ -2474,46 +2687,49 @@ unsigned int guard_flags(const unit * u) flags |= GUARD_RECRUIT; #endif switch (old_race(u->race)) { - case RC_ELF: - if (u->faction->race != u->race) break; - /* else fallthrough */ - case RC_TREEMAN: - flags |= GUARD_TREES; - break; - case RC_IRONKEEPER: - flags = GUARD_MINING; - break; + case RC_ELF: + if (u->faction->race != u->race) + break; + /* else fallthrough */ + case RC_TREEMAN: + flags |= GUARD_TREES; + break; + case RC_IRONKEEPER: + flags = GUARD_MINING; + break; } return flags; } -void -guard(unit * u, unsigned int mask) +void guard(unit * u, unsigned int mask) { unsigned int flags = guard_flags(u); + setguard(u, flags & mask); } -int -besieged(const unit * u) +int besieged(const unit * u) { /* belagert kann man in schiffen und burgen werden */ return (u && !global.disabled[K_BESIEGE] - && u->building && u->building->besieged - && u->building->besieged >= u->building->size * SIEGEFACTOR); + && u->building && u->building->besieged + && u->building->besieged >= u->building->size * SIEGEFACTOR); } -int -lifestyle(const unit * u) +int lifestyle(const unit * u) { int need; - plane * pl; + + plane *pl; + static int gamecookie = -1; - if (gamecookie!=global.cookie) { + + if (gamecookie != global.cookie) { gamecookie = global.cookie; } - if (is_monsters(u->faction)) return 0; + if (is_monsters(u->faction)) + return 0; need = maintenance_cost(u); @@ -2526,34 +2742,43 @@ lifestyle(const unit * u) boolean has_horses(const struct unit * u) { - item * itm = u->items; - for (;itm;itm=itm->next) { - if (itm->type->flags&ITF_ANIMAL) return true; + item *itm = u->items; + + for (; itm; itm = itm->next) { + if (itm->type->flags & ITF_ANIMAL) + return true; } return false; } -boolean -hunger(int number, unit * u) +boolean hunger(int number, unit * u) { - region * r = u->region; + region *r = u->region; + int dead = 0, hpsub = 0; + int hp = u->hp / u->number; - static const char * damage = 0; - static const char * rcdamage = 0; - static const race * rc = 0; + + static const char *damage = 0; + + static const char *rcdamage = 0; + + static const race *rc = 0; if (!damage) { damage = get_param(global.parameters, "hunger.damage"); - if (damage==NULL) damage = "1d12+12"; + + if (damage == NULL) + damage = "1d12+12"; } - if (rc!=u->race) { + if (rc != u->race) { rcdamage = get_param(u->race->parameters, "hunger.damage"); rc = u->race; } while (number--) { - int dam = dice_rand(rcdamage?rcdamage:damage); + int dam = dice_rand(rcdamage ? rcdamage : damage); + if (dam >= hp) { ++dead; } else { @@ -2565,7 +2790,7 @@ hunger(int number, unit * u) /* Gestorbene aus der Einheit nehmen, * Sie bekommen keine Beerdingung. */ ADDMSG(&u->faction->msgs, msg_message("starvation", - "unit region dead live", u, r, dead, u->number-dead)); + "unit region dead live", u, r, dead, u->number - dead)); scale_number(u, u->number - dead); deathcounts(r, dead); @@ -2576,28 +2801,31 @@ hunger(int number, unit * u) /* Meldung nur, wenn noch keine für Tote generiert. */ if (dead == 0) { /* Durch unzureichende Ernährung wird %s geschwächt */ - ADDMSG(&u->faction->msgs, msg_message("malnourish", - "unit region", u, r)); + ADDMSG(&u->faction->msgs, msg_message("malnourish", "unit region", u, r)); } } return (dead || hpsub); } -void -plagues(region * r, boolean ismagic) +void plagues(region * r, boolean ismagic) { int peasants; + int i; + int dead = 0; /* Seuchenwahrscheinlichkeit in % */ if (!ismagic) { double mwp = MAX(maxworkingpeasants(r), 1); - double prob = pow(rpeasants(r) / (mwp * wage(r, NULL, NULL, turn) * 0.13), 4.0) - * PLAGUE_CHANCE; - if (rng_double() >= prob) return; + double prob = + pow(rpeasants(r) / (mwp * wage(r, NULL, NULL, turn) * 0.13), 4.0) + * PLAGUE_CHANCE; + + if (rng_double() >= prob) + return; } peasants = rpeasants(r); @@ -2610,7 +2838,8 @@ plagues(region * r, boolean ismagic) } if (dead > 0) { - message * msg = add_message(&r->msgs, msg_message("pest", "dead", dead)); + message *msg = add_message(&r->msgs, msg_message("pest", "dead", dead)); + msg_release(msg); deathcounts(r, dead); rsetpeasants(r, peasants - dead); @@ -2621,60 +2850,75 @@ plagues(region * r, boolean ismagic) * Modifikation für Städter. */ static const int wagetable[7][4] = { - {10, 10, 11, -7}, /* Baustelle */ - {10, 10, 11, -5}, /* Handelsposten */ - {11, 11, 12, -3}, /* Befestigung */ - {12, 11, 13, -1}, /* Turm */ - {13, 12, 14, 0}, /* Burg */ - {14, 12, 15, 1}, /* Festung */ - {15, 13, 16, 2} /* Zitadelle */ + {10, 10, 11, -7}, /* Baustelle */ + {10, 10, 11, -5}, /* Handelsposten */ + {11, 11, 12, -3}, /* Befestigung */ + {12, 11, 13, -1}, /* Turm */ + {13, 12, 14, 0}, /* Burg */ + {14, 12, 15, 1}, /* Festung */ + {15, 13, 16, 2} /* Zitadelle */ }; -int -cmp_wage(const struct building * b, const building * a) +int cmp_wage(const struct building *b, const building * a) { - static const struct building_type * bt_castle; - if (!bt_castle) bt_castle = bt_find("castle"); - if (b->type==bt_castle) { - if (!a) return 1; - if (b->size>a->size) return 1; - if (b->size==a->size) return 0; + static const struct building_type *bt_castle; + + if (!bt_castle) + bt_castle = bt_find("castle"); + if (b->type == bt_castle) { + if (!a) + return 1; + if (b->size > a->size) + return 1; + if (b->size == a->size) + return 0; } return -1; } boolean is_owner_building(const struct building * b) { - region * r = b->region; + region *r = b->region; + if (b->type->taxes && r->land && r->land->ownership) { - unit * u = building_owner(b); + unit *u = building_owner(b); + return u && u->faction == r->land->ownership->owner; } return false; } -int -cmp_taxes(const building * b, const building * a) +int cmp_taxes(const building * b, const building * a) { - faction * f = region_get_owner(b->region); + faction *f = region_get_owner(b->region); + if (b->type->taxes) { - unit * u = building_owner(b); + unit *u = building_owner(b); + if (!u) { return -1; } else if (a) { int newsize = buildingeffsize(b, false); + double newtaxes = b->type->taxes(b, newsize); + int oldsize = buildingeffsize(a, false); + double oldtaxes = a->type->taxes(a, oldsize); - if (newtaxesoldtaxes) return 1; - else if (b->sizesize) return -1; - else if (b->size>a->size) return 1; + if (newtaxes < oldtaxes) + return -1; + else if (newtaxes > oldtaxes) + return 1; + else if (b->size < a->size) + return -1; + else if (b->size > a->size) + return 1; else { - if (u && u->faction==f) { + if (u && u->faction == f) { u = building_owner(a); - if (u && u->faction==f) return -1; + if (u && u->faction == f) + return -1; return 1; } } @@ -2685,24 +2929,30 @@ cmp_taxes(const building * b, const building * a) return -1; } -int -cmp_current_owner(const building * b, const building * a) +int cmp_current_owner(const building * b, const building * a) { - faction * f = region_get_owner(b->region); + faction *f = region_get_owner(b->region); assert(rule_region_owners()); if (f && b->type->taxes) { - unit * u = building_owner(b); - if (!u || u->faction!=f) return -1; + unit *u = building_owner(b); + + if (!u || u->faction != f) + return -1; if (a) { int newsize = buildingeffsize(b, false); + double newtaxes = b->type->taxes(b, newsize); + int oldsize = buildingeffsize(a, false); + double oldtaxes = a->type->taxes(a, oldsize); - if (newtaxes!=oldtaxes) return (newtaxes>oldtaxes)?1:-1; - if (newsize!=oldsize) return newsize-oldsize; - return (b->size-a->size); + if (newtaxes != oldtaxes) + return (newtaxes > oldtaxes) ? 1 : -1; + if (newsize != oldsize) + return newsize - oldsize; + return (b->size - a->size); } else { return 1; } @@ -2713,11 +2963,15 @@ cmp_current_owner(const building * b, const building * a) int rule_stealth_faction(void) { static int gamecookie = -1; + static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { + + if (rule < 0 || gamecookie != global.cookie) { rule = get_param_int(global.parameters, "rules.stealth.faction", 1); + gamecookie = global.cookie; - assert(rule>=0); + + assert(rule >= 0); } return rule; } @@ -2725,11 +2979,15 @@ int rule_stealth_faction(void) int rule_region_owners(void) { static int gamecookie = -1; + static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { + + if (rule < 0 || gamecookie != global.cookie) { rule = get_param_int(global.parameters, "rules.region_owners", 0); + gamecookie = global.cookie; - assert(rule>=0); + + assert(rule >= 0); } return rule; } @@ -2737,11 +2995,15 @@ int rule_region_owners(void) int rule_auto_taxation(void) { static int gamecookie = -1; + static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { - rule = get_param_int(global.parameters, "rules.economy.taxation", TAX_ORDER); + + if (rule < 0 || gamecookie != global.cookie) { + rule = + get_param_int(global.parameters, "rules.economy.taxation", TAX_ORDER); gamecookie = global.cookie; - assert(rule>=0); + + assert(rule >= 0); } return rule; } @@ -2749,11 +3011,16 @@ int rule_auto_taxation(void) int rule_blessed_harvest(void) { static int gamecookie = -1; + static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { - rule = get_param_int(global.parameters, "rules.magic.blessed_harvest", HARVEST_WORK); + + if (rule < 0 || gamecookie != global.cookie) { + rule = + get_param_int(global.parameters, "rules.magic.blessed_harvest", + HARVEST_WORK); gamecookie = global.cookie; - assert(rule>=0); + + assert(rule >= 0); } return rule; } @@ -2761,11 +3028,15 @@ int rule_blessed_harvest(void) int rule_alliance_limit(void) { static int gamecookie = -1; + static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { + + if (rule < 0 || gamecookie != global.cookie) { rule = get_param_int(global.parameters, "rules.limit.alliance", 0); + gamecookie = global.cookie; - assert(rule>=0); + + assert(rule >= 0); } return rule; } @@ -2773,11 +3044,15 @@ int rule_alliance_limit(void) int rule_faction_limit(void) { static int gamecookie = -1; + static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { + + if (rule < 0 || gamecookie != global.cookie) { rule = get_param_int(global.parameters, "rules.limit.faction", 0); + gamecookie = global.cookie; - assert(rule>=0); + + assert(rule >= 0); } return rule; } @@ -2785,25 +3060,36 @@ int rule_faction_limit(void) int rule_transfermen(void) { static int gamecookie = -1; + static int rule = -1; - if (rule<0 || gamecookie!=global.cookie) { + + if (rule < 0 || gamecookie != global.cookie) { rule = get_param_int(global.parameters, "rules.transfermen", 1); + gamecookie = global.cookie; - assert(rule>=0); + + assert(rule >= 0); } return rule; } static int -default_wage(const region *r, const faction * f, const race * rc, int in_turn) +default_wage(const region * r, const faction * f, const race * rc, int in_turn) { building *b = largestbuilding(r, &cmp_wage, false); - int esize = 0; - curse * c; + + int esize = 0; + + curse *c; + double wage; - attrib *a; + + attrib *a; + const building_type *artsculpture_type = bt_find("artsculpture"); - static const curse_type * drought_ct, * blessedharvest_ct; + + static const curse_type *drought_ct, *blessedharvest_ct; + static boolean init; if (!init) { @@ -2812,14 +3098,15 @@ default_wage(const region *r, const faction * f, const race * rc, int in_turn) blessedharvest_ct = ct_find("blessedharvest"); } - if (b!=NULL) { + if (b != NULL) { /* TODO: this reveals imaginary castles */ esize = buildingeffsize(b, false); } - if (f!=NULL) { + if (f != NULL) { int index = 0; - if (rc==new_race[RC_ORC] || rc==new_race[RC_SNOTLING]) { + + if (rc == new_race[RC_ORC] || rc == new_race[RC_SNOTLING]) { index = 1; } wage = wagetable[esize][index]; @@ -2833,38 +3120,40 @@ default_wage(const region *r, const faction * f, const race * rc, int in_turn) } else { wage = wagetable[esize][2]; } - if (rule_blessed_harvest()==HARVEST_WORK) { + if (rule_blessed_harvest() == HARVEST_WORK) { /* E1 rules */ wage += curse_geteffect(get_curse(r->attribs, blessedharvest_ct)); } } /* Artsculpture: Income +5 */ - for(b=r->buildings; b; b=b->next) { - if(b->type == artsculpture_type) { + for (b = r->buildings; b; b = b->next) { + if (b->type == artsculpture_type) { wage += 5; } } /* Godcurse: Income -10 */ if (curse_active(get_curse(r->attribs, ct_find("godcursezone")))) { - wage = MAX(0,wage-10); + wage = MAX(0, wage - 10); } /* Bei einer Dürre verdient man nur noch ein Viertel */ if (drought_ct) { c = get_curse(r->attribs, drought_ct); - if (curse_active(c)) wage /= curse_geteffect(c); + if (curse_active(c)) + wage /= curse_geteffect(c); } a = a_find(r->attribs, &at_reduceproduction); - if (a) wage = (wage * a->data.sa[0])/100; + if (a) + wage = (wage * a->data.sa[0]) / 100; return (int)wage; } static int -minimum_wage(const region *r, const faction * f, const race * rc, int in_turn) +minimum_wage(const region * r, const faction * f, const race * rc, int in_turn) { if (f && rc) { return rc->maintenance; @@ -2874,8 +3163,7 @@ minimum_wage(const region *r, const faction * f, const race * rc, int in_turn) /* Gibt Arbeitslohn für entsprechende Rasse zurück, oder für * die Bauern wenn f == NULL. */ -int -wage(const region *r, const faction * f, const race * rc, int in_turn) +int wage(const region * r, const faction * f, const race * rc, int in_turn) { if (global.functions.wage) { return global.functions.wage(r, f, rc, in_turn); @@ -2885,21 +3173,24 @@ wage(const region *r, const faction * f, const race * rc, int in_turn) #define MAINTENANCE 10 -int -maintenance_cost(const struct unit * u) +int maintenance_cost(const struct unit *u) { - if (u==NULL) return MAINTENANCE; + if (u == NULL) + return MAINTENANCE; if (global.functions.maintenance) { int retval = global.functions.maintenance(u); - if (retval>=0) return retval; + + if (retval >= 0) + return retval; } return u->race->maintenance * u->number; } -message * -movement_error(unit * u, const char * token, order * ord, int error_code) +message *movement_error(unit * u, const char *token, order * ord, + int error_code) { direction_t d; + switch (error_code) { case E_MOVE_BLOCKED: d = finddirection(token, u->faction->locale); @@ -2910,10 +3201,10 @@ movement_error(unit * u, const char * token, order * ord, int error_code) return NULL; } -int -movewhere(const unit *u, const char * token, region * r, region** resultp) +int movewhere(const unit * u, const char *token, region * r, region ** resultp) { - region * r2; + region *r2; + direction_t d; if (*token == '\0') { @@ -2923,76 +3214,86 @@ movewhere(const unit *u, const char * token, region * r, region** resultp) d = finddirection(token, u->faction->locale); switch (d) { - case D_PAUSE: - *resultp = r; - break; + case D_PAUSE: + *resultp = r; + break; - case NODIRECTION: - r2 = find_special_direction(r, token, u->faction->locale); - if (r2==NULL) { - return E_MOVE_NOREGION; - } - *resultp = r2; - break; + case NODIRECTION: + r2 = find_special_direction(r, token, u->faction->locale); + if (r2 == NULL) { + return E_MOVE_NOREGION; + } + *resultp = r2; + break; - default: - r2 = rconnect(r, d); - if (r2==NULL || move_blocked(u, r, r2)) { - return E_MOVE_BLOCKED; - } - *resultp = r2; + default: + r2 = rconnect(r, d); + if (r2 == NULL || move_blocked(u, r, r2)) { + return E_MOVE_BLOCKED; + } + *resultp = r2; } return E_MOVE_OK; } -boolean -move_blocked(const unit * u, const region *r, const region *r2) +boolean move_blocked(const unit * u, const region * r, const region * r2) { - connection * b; - curse * c; - static const curse_type * fogtrap_ct = NULL; + connection *b; - if (r2==NULL) return true; + curse *c; + + static const curse_type *fogtrap_ct = NULL; + + if (r2 == NULL) + return true; b = get_borders(r, r2); while (b) { - if (b->type->block && b->type->block(b, u, r)) return true; + if (b->type->block && b->type->block(b, u, r)) + return true; b = b->next; } - if (fogtrap_ct==NULL) fogtrap_ct = ct_find("fogtrap"); + if (fogtrap_ct == NULL) + fogtrap_ct = ct_find("fogtrap"); c = get_curse(r->attribs, fogtrap_ct); - if (curse_active(c)) return true; + if (curse_active(c)) + return true; return false; } -void -add_income(unit * u, int type, int want, int qty) +void add_income(unit * u, int type, int want, int qty) { - if (want==INT_MAX) want = qty; - ADDMSG(&u->faction->msgs, msg_message("income", "unit region mode wanted amount", - u, u->region, type, want, qty)); + if (want == INT_MAX) + want = qty; + ADDMSG(&u->faction->msgs, msg_message("income", + "unit region mode wanted amount", u, u->region, type, want, qty)); } -void -reorder_units(region * r) +void reorder_units(region * r) { - unit ** unext = &r->units; + unit **unext = &r->units; if (r->buildings) { - building * b = r->buildings; + building *b = r->buildings; + while (*unext && b) { - unit ** ufirst = unext; /* where the first unit in the building should go */ - unit ** umove = unext; /* a unit we consider moving */ - unit * owner = NULL; + unit **ufirst = unext; /* where the first unit in the building should go */ + + unit **umove = unext; /* a unit we consider moving */ + + unit *owner = NULL; + while (*umove) { - unit * u = *umove; - if (u->number && u->building==b) { - unit ** uinsert = unext; + unit *u = *umove; + + if (u->number && u->building == b) { + unit **uinsert = unext; + if (fval(u, UFL_OWNER)) { uinsert = ufirst; owner = u; } - if (umove!=uinsert) { + if (umove != uinsert) { *umove = u->next; u->next = *uinsert; *uinsert = u; @@ -3000,7 +3301,7 @@ reorder_units(region * r) /* no need to move, skip ahead */ umove = &u->next; } - if (unext==uinsert) { + if (unext == uinsert) { /* we have a new well-placed unit. jump over it */ unext = &u->next; } @@ -3008,7 +3309,7 @@ reorder_units(region * r) umove = &u->next; } } - if (!owner && ufirst!=unext) { + if (!owner && ufirst != unext) { owner = *ufirst; fset(owner, UFL_OWNER); } @@ -3017,13 +3318,16 @@ reorder_units(region * r) } if (r->ships) { - ship * sh = r->ships; + ship *sh = r->ships; + /* first, move all units up that are not on ships */ - unit ** umove = unext; /* a unit we consider moving */ + unit **umove = unext; /* a unit we consider moving */ + while (*umove) { - unit * u = *umove; + unit *u = *umove; + if (u->number && !u->ship) { - if (umove!=unext) { + if (umove != unext) { *umove = u->next; u->next = *unext; *unext = u; @@ -3039,18 +3343,23 @@ reorder_units(region * r) } while (*unext && sh) { - unit ** ufirst = unext; /* where the first unit in the building should go */ - unit ** umove = unext; /* a unit we consider moving */ - unit * owner = NULL; + unit **ufirst = unext; /* where the first unit in the building should go */ + + unit **umove = unext; /* a unit we consider moving */ + + unit *owner = NULL; + while (*umove) { - unit * u = *umove; - if (u->number && u->ship==sh) { - unit ** uinsert = unext; + unit *u = *umove; + + if (u->number && u->ship == sh) { + unit **uinsert = unext; + if (fval(u, UFL_OWNER)) { uinsert = ufirst; owner = u; } - if (umove!=uinsert) { + if (umove != uinsert) { *umove = u->next; u->next = *uinsert; *uinsert = u; @@ -3058,7 +3367,7 @@ reorder_units(region * r) /* no need to move, skip ahead */ umove = &u->next; } - if (unext==uinsert) { + if (unext == uinsert) { /* we have a new well-placed unit. jump over it */ unext = &u->next; } @@ -3066,7 +3375,7 @@ reorder_units(region * r) umove = &u->next; } } - if (!owner && ufirst!=unext) { + if (!owner && ufirst != unext) { owner = *ufirst; fset(owner, UFL_OWNER); } @@ -3075,26 +3384,26 @@ reorder_units(region * r) } } -int -produceexp(struct unit * u, skill_t sk, int n) +int produceexp(struct unit *u, skill_t sk, int n) { - if (global.producexpchance>0.0F) { - if (n==0 || !playerrace(u->race)) return 0; + if (global.producexpchance > 0.0F) { + if (n == 0 || !playerrace(u->race)) + return 0; learn_skill(u, sk, global.producexpchance); } return 0; } -int -lovar(double xpct_x2) +int lovar(double xpct_x2) { - int n = (int)(xpct_x2 * 500)+1; - if (n==0) return 0; - return (rng_int() % n + rng_int() % n)/1000; + int n = (int)(xpct_x2 * 500) + 1; + + if (n == 0) + return 0; + return (rng_int() % n + rng_int() % n) / 1000; } -boolean -has_limited_skills (const struct unit * u) +boolean has_limited_skills(const struct unit * u) { if (has_skill(u, SK_MAGIC) || has_skill(u, SK_ALCHEMY) || has_skill(u, SK_TACTICS) || has_skill(u, SK_HERBALISM) || @@ -3105,8 +3414,7 @@ has_limited_skills (const struct unit * u) } } -void -attrib_init(void) +void attrib_init(void) { /* Alle speicherbaren Attribute müssen hier registriert werden */ at_register(&at_shiptrail); @@ -3150,20 +3458,20 @@ attrib_init(void) register_bordertype(&bt_road); register_bordertype(&bt_questportal); - register_function((pf_generic)&minimum_wage, "minimum_wage"); + register_function((pf_generic) & minimum_wage, "minimum_wage"); at_register(&at_germs); #if XECMD_MODULE - at_register(&at_xontormiaexpress); /* required for old datafiles */ + at_register(&at_xontormiaexpress); /* required for old datafiles */ #endif at_register(&at_speedup); at_register(&at_building_action); } -void -kernel_init(void) +void kernel_init(void) { char zBuffer[MAX_PATH]; + attrib_init(); translation_init(); @@ -3173,14 +3481,12 @@ kernel_init(void) } } -order * -default_order(const struct locale * lang) +order *default_order(const struct locale *lang) { return parse_order(locale_string(lang, "defaultorder"), lang); } -int -entertainmoney(const region *r) +int entertainmoney(const region * r) { double n; @@ -3200,7 +3506,8 @@ entertainmoney(const region *r) int rule_give(void) { static int value = -1; - if (value<0) { + + if (value < 0) { value = get_param_int(global.parameters, "rules.give", GIVE_DEFAULT); } return value; @@ -3209,7 +3516,8 @@ int rule_give(void) int markets_module(void) { static int value = -1; - if (value<0) { + + if (value < 0) { value = get_param_int(global.parameters, "modules.markets", 0); } return value; @@ -3219,20 +3527,21 @@ int markets_module(void) * call this function before calling read_game() to load a new game * if you have a previously loaded state in memory. */ -void -free_gamedata(void) +void free_gamedata(void) { free_units(); free_regions(); free_borders(); while (alliances) { - alliance * al = alliances; + alliance *al = alliances; + alliances = al->next; free_alliance(al); } while (factions) { - faction * f = factions; + faction *f = factions; + factions = f->next; funhash(f); free_faction(f); @@ -3240,7 +3549,8 @@ free_gamedata(void) } while (planes) { - plane * pl = planes; + plane *pl = planes; + planes = planes->next; free(pl->name); free(pl); @@ -3249,35 +3559,41 @@ free_gamedata(void) while (global.attribs) { a_remove(&global.attribs, global.attribs); } - ++global.cookie; /* readgame() already does this, but sjust in case */ + ++global.cookie; /* readgame() already does this, but sjust in case */ } -void -load_inifile(dictionary * d) +void load_inifile(dictionary * d) { - const char * reportdir = reportpath(); - const char * datadir = datapath(); - const char * basedir = basepath(); - const char * str; + const char *reportdir = reportpath(); + + const char *datadir = datapath(); + + const char *basedir = basepath(); + + const char *str; assert(d); str = iniparser_getstring(d, "eressea:base", basedir); - if (str!=basedir) set_basepath(str); + if (str != basedir) + set_basepath(str); str = iniparser_getstring(d, "eressea:report", reportdir); - if (str!=reportdir) set_reportpath(str); + if (str != reportdir) + set_reportpath(str); str = iniparser_getstring(d, "eressea:data", datadir); - if (str!=datadir) set_datapath(str); + if (str != datadir) + set_datapath(str); - lomem = iniparser_getint(d, "eressea:lomem", lomem)?1:0; + lomem = iniparser_getint(d, "eressea:lomem", lomem) ? 1 : 0; str = iniparser_getstring(d, "eressea:encoding", NULL); - if (str) enc_gamedata = xmlParseCharEncoding(str); + if (str) + enc_gamedata = xmlParseCharEncoding(str); verbosity = iniparser_getint(d, "eressea:verbose", 2); sqlpatch = iniparser_getint(d, "eressea:sqlpatch", false); - battledebug = iniparser_getint(d, "eressea:debug", battledebug)?1:0; + battledebug = iniparser_getint(d, "eressea:debug", battledebug) ? 1 : 0; str = iniparser_getstring(d, "eressea:locales", "de,en"); make_locales(str); diff --git a/src/kernel/config.h b/src/kernel/config.h index 513d2d859..8d6715fd6 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -23,34 +23,34 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif - /* this should always be the first thing included after platform.h */ + /* this should always be the first thing included after platform.h */ #include "types.h" -struct _dictionary_; + struct _dictionary_; /* experimental gameplay features (that don't affect the savefile) */ /* TODO: move these settings to settings.h or into configuration files */ -#define GOBLINKILL /* Goblin-Spezialklau kann tödlich enden */ -#define HERBS_ROT /* herbs owned by units have a chance to rot. */ -#define SHIPDAMAGE /* Schiffsbeschädigungen */ -#define INSECT_POTION /* Spezialtrank für Insekten */ -#define ORCIFICATION /* giving snotlings to the peasants gets counted */ - +#define GOBLINKILL /* Goblin-Spezialklau kann tödlich enden */ +#define HERBS_ROT /* herbs owned by units have a chance to rot. */ +#define SHIPDAMAGE /* Schiffsbeschädigungen */ +#define INSECT_POTION /* Spezialtrank für Insekten */ +#define ORCIFICATION /* giving snotlings to the peasants gets counted */ + #define ALLIED(f1, f2) (f1==f2 || (f1->alliance && f1->alliance==f2->alliance)) /* for some good prime numbers, check http://www.math.niu.edu/~rusin/known-math/98/pi_x */ #ifndef MAXREGIONS -# define MAXREGIONS 524287 /* must be prime for hashing. 262139 was a little small */ +# define MAXREGIONS 524287 /* must be prime for hashing. 262139 was a little small */ #endif #ifndef MAXUNITS -# define MAXUNITS 1048573 /* must be prime for hashing. 524287 was >90% full */ +# define MAXUNITS 1048573 /* must be prime for hashing. 524287 was >90% full */ #endif #define MAXPEASANTS_PER_AREA 10 /* number of peasants per region-size */ -#define TREESIZE (MAXPEASANTS_PER_AREA-2) /* space used by trees (in #peasants) */ +#define TREESIZE (MAXPEASANTS_PER_AREA-2) /* space used by trees (in #peasants) */ -#define PEASANTFORCE 0.75 /* Chance einer Vermehrung trotz 90% Auslastung */ -#define HERBROTCHANCE 5 /* Verrottchance für Kräuter (ifdef HERBS_ROT) */ +#define PEASANTFORCE 0.75 /* Chance einer Vermehrung trotz 90% Auslastung */ +#define HERBROTCHANCE 5 /* Verrottchance für Kräuter (ifdef HERBS_ROT) */ /* Gebäudegröße = Minimalbelagerer */ #define SIEGEFACTOR 2 @@ -62,8 +62,8 @@ struct _dictionary_; /** Plagues **/ #define PLAGUE_CHANCE 0.1F /* Seuchenwahrscheinlichkeit (siehe plagues()) */ #define PLAGUE_VICTIMS 0.2F /* % Betroffene */ -#define PLAGUE_HEALCHANCE 0.25F /* Wahrscheinlichkeit Heilung */ -#define PLAGUE_HEALCOST 30 /* Heilkosten */ +#define PLAGUE_HEALCHANCE 0.25F /* Wahrscheinlichkeit Heilung */ +#define PLAGUE_HEALCOST 30 /* Heilkosten */ /* Chance of a monster attack */ #define MONSTERATTACK 0.4F @@ -84,7 +84,7 @@ struct _dictionary_; #define BP_NORMAL 3 #define BP_ROAD 2 -#define PERSON_WEIGHT 1000 /* weight of a "normal" human unit */ +#define PERSON_WEIGHT 1000 /* weight of a "normal" human unit */ #define STAMINA_AFFECTS_HP 1<<0 /** @@ -92,96 +92,97 @@ struct _dictionary_; * Spielwelt Eressea enthält, und beginnen die allgemeinen Routinen */ -#define ENCCHANCE 10 /* %-Chance für einmalige Zufallsbegegnung */ +#define ENCCHANCE 10 /* %-Chance für einmalige Zufallsbegegnung */ -#define DISPLAYSIZE 8191 /* max. Länge einer Beschreibung, ohne trailing 0 */ -#define NAMESIZE 127 /* max. Länge eines Namens, ohne trailing 0 */ -#define IDSIZE 15 /* max. Länge einer no (als String), ohne trailing 0 */ -#define KEYWORDSIZE 15 /* max. Länge eines Keyword, ohne trailing 0 */ -#define OBJECTIDSIZE (NAMESIZE+5+IDSIZE) /* max. Länge der Strings, die - * von struct unitname, etc. zurückgegeben werden. ohne die 0 */ +#define DISPLAYSIZE 8191 /* max. Länge einer Beschreibung, ohne trailing 0 */ +#define NAMESIZE 127 /* max. Länge eines Namens, ohne trailing 0 */ +#define IDSIZE 15 /* max. Länge einer no (als String), ohne trailing 0 */ +#define KEYWORDSIZE 15 /* max. Länge eines Keyword, ohne trailing 0 */ +#define OBJECTIDSIZE (NAMESIZE+5+IDSIZE) /* max. Länge der Strings, die + * von struct unitname, etc. zurückgegeben werden. ohne die 0 */ -#define BAGCAPACITY 20000 /* soviel paßt in einen Bag of Holding */ -#define STRENGTHCAPACITY 50000 /* zusätzliche Tragkraft beim Kraftzauber (deprecated) */ +#define BAGCAPACITY 20000 /* soviel paßt in einen Bag of Holding */ +#define STRENGTHCAPACITY 50000 /* zusätzliche Tragkraft beim Kraftzauber (deprecated) */ #define STRENGTHMULTIPLIER 50 /* multiplier for trollbelt */ /* ----------------- Befehle ----------------------------------- */ -extern const char *keywords[MAXKEYWORDS]; -extern const char *parameters[MAXPARAMS]; + extern const char *keywords[MAXKEYWORDS]; + extern const char *parameters[MAXPARAMS]; /** report options **/ #define want(option) (1<flags & (i)) #define fset(u, i) ((u)->flags |= (i)) #define freset(u, i) ((u)->flags &= ~(i)) -extern int turn; -extern int verbosity; + extern int turn; + extern int verbosity; /* parteinummern */ -extern boolean faction_id_is_unused(int); + extern boolean faction_id_is_unused(int); /* leuchtturm */ -extern boolean check_leuchtturm(struct region * r, struct faction * f); -extern void update_lighthouse(struct building * lh); -extern int lighthouse_range(const struct building * b, const struct faction * f); + extern boolean check_leuchtturm(struct region *r, struct faction *f); + extern void update_lighthouse(struct building *lh); + extern int lighthouse_range(const struct building *b, + const struct faction *f); /* skills */ -extern int skill_limit(struct faction * f, skill_t sk); -extern int count_skill(struct faction * f, skill_t sk); + extern int skill_limit(struct faction *f, skill_t sk); + extern int count_skill(struct faction *f, skill_t sk); /* direction, geography */ -extern const char *directions[]; -extern direction_t finddirection(const char *s, const struct locale *); + extern const char *directions[]; + extern direction_t finddirection(const char *s, const struct locale *); -extern int findoption(const char *s, const struct locale * lang); + extern int findoption(const char *s, const struct locale *lang); /* special units */ -void make_undead_unit(struct unit *); + void make_undead_unit(struct unit *); -void addstrlist(strlist ** SP, const char *s); + void addstrlist(strlist ** SP, const char *s); -int armedmen(const struct unit * u, boolean siege_weapons); + int armedmen(const struct unit *u, boolean siege_weapons); -unsigned int atoip(const char *s); -unsigned int getuint(void); -int getint(void); + unsigned int atoip(const char *s); + unsigned int getuint(void); + int getint(void); -extern const char *igetstrtoken(const char *s); + extern const char *igetstrtoken(const char *s); -extern void init_tokens(const struct order * ord); /* initialize token parsing */ -extern skill_t findskill(const char *s, const struct locale * lang); + extern void init_tokens(const struct order *ord); /* initialize token parsing */ + extern skill_t findskill(const char *s, const struct locale *lang); -extern keyword_t findkeyword(const char *s, const struct locale * lang); + extern keyword_t findkeyword(const char *s, const struct locale *lang); -extern param_t findparam(const char *s, const struct locale * lang); -extern param_t getparam(const struct locale * lang); + extern param_t findparam(const char *s, const struct locale *lang); + extern param_t getparam(const struct locale *lang); -extern int getid(void); + extern int getid(void); #define unitid(x) itoa36((x)->no) #define getshipid() getid() @@ -192,245 +193,260 @@ extern int getid(void); #define factionid(x) itoa36((x)->no) #define curseid(x) itoa36((x)->no) -extern boolean cansee(const struct faction * f, const struct region * r, const struct unit * u, int modifier); -boolean cansee_durchgezogen(const struct faction * f, const struct region * r, const struct unit * u, int modifier); -extern boolean cansee_unit(const struct unit * u, const struct unit * target, int modifier); -boolean seefaction(const struct faction * f, const struct region * r, const struct unit * u, int modifier); -extern int effskill(const struct unit * u, skill_t sk); + extern boolean cansee(const struct faction *f, const struct region *r, + const struct unit *u, int modifier); + boolean cansee_durchgezogen(const struct faction *f, const struct region *r, + const struct unit *u, int modifier); + extern boolean cansee_unit(const struct unit *u, const struct unit *target, + int modifier); + boolean seefaction(const struct faction *f, const struct region *r, + const struct unit *u, int modifier); + extern int effskill(const struct unit *u, skill_t sk); -extern int lovar(double xpct_x2); + extern int lovar(double xpct_x2); /* returns a value between [0..xpct_2], generated with two dice */ -int distribute(int old, int new_value, int n); + int distribute(int old, int new_value, int n); -int newunitid(void); -int forbiddenid(int id); -int newcontainerid(void); + int newunitid(void); + int forbiddenid(int id); + int newcontainerid(void); -extern struct unit *createunit(struct region * r, struct faction * f, int number, const struct race * rc); -extern void create_unitid(struct unit *u, int id); -extern boolean getunitpeasants; -extern struct unit *getunitg(const struct region * r, const struct faction * f); -extern struct unit *getunit(const struct region * r, const struct faction * f); + extern struct unit *createunit(struct region *r, struct faction *f, + int number, const struct race *rc); + extern void create_unitid(struct unit *u, int id); + extern boolean getunitpeasants; + extern struct unit *getunitg(const struct region *r, const struct faction *f); + extern struct unit *getunit(const struct region *r, const struct faction *f); -extern int read_unitid(const struct faction * f, const struct region * r); + extern int read_unitid(const struct faction *f, const struct region *r); -extern int alliedunit(const struct unit * u, const struct faction * f2, int mode); -extern int alliedfaction(const struct plane * pl, const struct faction * f, - const struct faction * f2, int mode); -extern int alliedgroup(const struct plane * pl, const struct faction * f, - const struct faction * f2, const struct ally * sf, - int mode); + extern int alliedunit(const struct unit *u, const struct faction *f2, + int mode); + extern int alliedfaction(const struct plane *pl, const struct faction *f, + const struct faction *f2, int mode); + extern int alliedgroup(const struct plane *pl, const struct faction *f, + const struct faction *f2, const struct ally *sf, int mode); -struct faction *findfaction(int n); -struct faction *getfaction(void); + struct faction *findfaction(int n); + struct faction *getfaction(void); -struct unit *findunitg(int n, const struct region * hint); -struct unit *findunit(int n); + struct unit *findunitg(int n, const struct region *hint); + struct unit *findunit(int n); -struct unit *findunitr(const struct region * r, int n); -struct region *findunitregion(const struct unit * su); + struct unit *findunitr(const struct region *r, int n); + struct region *findunitregion(const struct unit *su); -extern char *estring(const char *s); -extern char *estring_i(char *s); -extern char *cstring(const char *s); -extern char *cstring_i(char *s); -extern const char *unitname(const struct unit * u); -extern char * write_unitname(const struct unit * u, char * buffer, size_t size); + extern char *estring(const char *s); + extern char *estring_i(char *s); + extern char *cstring(const char *s); + extern char *cstring_i(char *s); + extern const char *unitname(const struct unit *u); + extern char *write_unitname(const struct unit *u, char *buffer, size_t size); -typedef int (*cmp_building_cb)(const struct building * b, const struct building * a); -struct building *largestbuilding(const struct region * r, cmp_building_cb, boolean imaginary); -int cmp_wage(const struct building * b, const struct building * bother); -int cmp_taxes(const struct building * b, const struct building * bother); -int cmp_current_owner(const struct building * b, const struct building * bother); + typedef int (*cmp_building_cb) (const struct building * b, + const struct building * a); + struct building *largestbuilding(const struct region *r, cmp_building_cb, + boolean imaginary); + int cmp_wage(const struct building *b, const struct building *bother); + int cmp_taxes(const struct building *b, const struct building *bother); + int cmp_current_owner(const struct building *b, + const struct building *bother); #define TAX_ORDER 0x00 #define TAX_OWNER 0x01 -int rule_auto_taxation(void); -int rule_transfermen(void); -int rule_region_owners(void); -int rule_stealth_faction(void); + int rule_auto_taxation(void); + int rule_transfermen(void); + int rule_region_owners(void); + int rule_stealth_faction(void); #define HARVEST_WORK 0x00 #define HARVEST_TAXES 0x01 -int rule_blessed_harvest(void); -extern int rule_give(void); -extern int rule_alliance_limit(void); -extern int rule_faction_limit(void); + int rule_blessed_harvest(void); + extern int rule_give(void); + extern int rule_alliance_limit(void); + extern int rule_faction_limit(void); -extern int count_all(const struct faction * f); -extern int count_migrants (const struct faction * f); -extern int count_maxmigrants(const struct faction * f); + extern int count_all(const struct faction *f); + extern int count_migrants(const struct faction *f); + extern int count_maxmigrants(const struct faction *f); -extern boolean has_limited_skills(const struct unit * u); -extern const struct race * findrace(const char *, const struct locale *); + extern boolean has_limited_skills(const struct unit *u); + extern const struct race *findrace(const char *, const struct locale *); -int eff_stealth(const struct unit * u, const struct region * r); -int ispresent(const struct faction * f, const struct region * r); + int eff_stealth(const struct unit *u, const struct region *r); + int ispresent(const struct faction *f, const struct region *r); -int check_option(struct faction * f, int option); -extern void parse(keyword_t kword, int (*dofun)(struct unit *, struct order *), boolean thisorder); + int check_option(struct faction *f, int option); + extern void parse(keyword_t kword, int (*dofun) (struct unit *, + struct order *), boolean thisorder); /* Anzahl Personen in einer Einheit festlegen. NUR (!) mit dieser Routine, * sonst großes Unglück. Durch asserts an ein paar Stellen abgesichert. */ -void verify_data(void); + void verify_data(void); -void freestrlist(strlist * s); + void freestrlist(strlist * s); -int change_hitpoints(struct unit *u, int value); + int change_hitpoints(struct unit *u, int value); -int weight(const struct unit * u); -void changeblockchaos(void); + int weight(const struct unit *u); + void changeblockchaos(void); /* intervall, in dem die regionen der partei zu finden sind */ -extern struct region *firstregion(struct faction * f); -extern struct region *lastregion(struct faction * f); + extern struct region *firstregion(struct faction *f); + extern struct region *lastregion(struct faction *f); -void fhash(struct faction * f); -void funhash(struct faction * f); + void fhash(struct faction *f); + void funhash(struct faction *f); -boolean idle(struct faction * f); -boolean unit_has_cursed_item(struct unit *u); + boolean idle(struct faction *f); + boolean unit_has_cursed_item(struct unit *u); /* simple garbage collection: */ -void * gc_add(void * p); + void *gc_add(void *p); /* grammatik-flags: */ #define GF_NONE 0 - /* singular, ohne was dran */ + /* singular, ohne was dran */ #define GF_PLURAL 1 - /* Angaben in Mehrzahl */ + /* Angaben in Mehrzahl */ #define GF_ARTICLE 8 - /* der, die, eine */ + /* der, die, eine */ #define GF_SPECIFIC 16 - /* der, die, das vs. ein, eine */ + /* der, die, das vs. ein, eine */ #define GF_DETAILED 32 - /* mehr Informationen. z.b. straße zu 50% */ + /* mehr Informationen. z.b. straße zu 50% */ #define GF_PURE 64 - /* untranslated */ + /* untranslated */ #define GUARD_NONE 0 #define GUARD_TAX 1 - /* Verhindert Steuereintreiben */ + /* Verhindert Steuereintreiben */ #define GUARD_MINING 2 - /* Verhindert Bergbau */ + /* Verhindert Bergbau */ #define GUARD_TREES 4 - /* Verhindert Waldarbeiten */ + /* Verhindert Waldarbeiten */ #define GUARD_TRAVELTHRU 8 - /* Blockiert Durchreisende */ + /* Blockiert Durchreisende */ #define GUARD_LANDING 16 - /* Verhindert Ausstieg + Weiterreise */ + /* Verhindert Ausstieg + Weiterreise */ #define GUARD_CREWS 32 - /* Verhindert Unterhaltung auf Schiffen */ + /* Verhindert Unterhaltung auf Schiffen */ #define GUARD_RECRUIT 64 /* Verhindert Rekrutieren */ #define GUARD_PRODUCE 128 - /* Verhindert Abbau von Resourcen mit RTF_LIMITED */ + /* Verhindert Abbau von Resourcen mit RTF_LIMITED */ #define GUARD_ALL 0xFFFF -extern void setstatus(struct unit * u, int status); + extern void setstatus(struct unit *u, int status); /* !< sets combatstatus of a unit */ -extern void setguard(struct unit * u, unsigned int flags); + extern void setguard(struct unit *u, unsigned int flags); /* !< setzt die guard-flags der Einheit */ -extern unsigned int getguard(const struct unit * u); - /* liest die guard-flags der Einheit */ -extern void guard(struct unit * u, unsigned int mask); - /* Einheit setzt "BEWACHE", rassenspezifzisch. - * 'mask' kann einzelne flags zusätzlich und-maskieren. - */ -unsigned int guard_flags(const struct unit * u); + extern unsigned int getguard(const struct unit *u); + /* liest die guard-flags der Einheit */ + extern void guard(struct unit *u, unsigned int mask); + /* Einheit setzt "BEWACHE", rassenspezifzisch. + * 'mask' kann einzelne flags zusätzlich und-maskieren. + */ + unsigned int guard_flags(const struct unit *u); -extern boolean hunger(int number, struct unit * u); -extern int lifestyle(const struct unit*); -extern int besieged(const struct unit * u); -extern int maxworkingpeasants(const struct region * r); -extern boolean has_horses(const struct unit * u); -extern int markets_module(void); -extern int wage(const struct region *r, const struct faction *f, const struct race * rc, int in_turn); -extern int maintenance_cost(const struct unit * u); -extern struct message * movement_error(struct unit * u, const char * token, struct order * ord, int error_code); -extern boolean move_blocked(const struct unit * u, const struct region *src, const struct region *dest); -extern void add_income(struct unit * u, int type, int want, int qty); + extern boolean hunger(int number, struct unit *u); + extern int lifestyle(const struct unit *); + extern int besieged(const struct unit *u); + extern int maxworkingpeasants(const struct region *r); + extern boolean has_horses(const struct unit *u); + extern int markets_module(void); + extern int wage(const struct region *r, const struct faction *f, + const struct race *rc, int in_turn); + extern int maintenance_cost(const struct unit *u); + extern struct message *movement_error(struct unit *u, const char *token, + struct order *ord, int error_code); + extern boolean move_blocked(const struct unit *u, const struct region *src, + const struct region *dest); + extern void add_income(struct unit *u, int type, int want, int qty); /* movewhere error codes */ -enum { - E_MOVE_OK = 0, /* possible to move */ - E_MOVE_NOREGION, /* no region exists in this direction */ - E_MOVE_BLOCKED /* cannot see this region, there is a blocking connection. */ -}; -extern int movewhere(const struct unit *u, const char * token, struct region * r, struct region** resultp); + enum { + E_MOVE_OK = 0, /* possible to move */ + E_MOVE_NOREGION, /* no region exists in this direction */ + E_MOVE_BLOCKED /* cannot see this region, there is a blocking connection. */ + }; + extern int movewhere(const struct unit *u, const char *token, + struct region *r, struct region **resultp); -extern const char * datapath(void); -extern void set_datapath(const char * path); + extern const char *datapath(void); + extern void set_datapath(const char *path); -extern const char * basepath(void); -extern void set_basepath(const char *); -void load_inifile(struct _dictionary_ * d); + extern const char *basepath(void); + extern void set_basepath(const char *); + void load_inifile(struct _dictionary_ *d); -extern const char * reportpath(void); -extern void set_reportpath(const char *); + extern const char *reportpath(void); + extern void set_reportpath(const char *); -extern void kernel_init(void); -extern void kernel_done(void); + extern void kernel_init(void); + extern void kernel_done(void); -extern void reorder_units(struct region * r); + extern void reorder_units(struct region *r); -extern const char *localenames[]; + extern const char *localenames[]; /** compatibility: **/ -extern race_t old_race(const struct race *); -extern const struct race * new_race[]; + extern race_t old_race(const struct race *); + extern const struct race *new_race[]; /* globale settings des Spieles */ -typedef struct settings { - const char *gamename; - struct attrib *attribs; - unsigned int data_turn; - boolean disabled[MAXKEYWORDS]; - struct param * parameters; - void * vm_state; - float producexpchance; - int cookie; - struct _dictionary_ * inifile; + typedef struct settings { + const char *gamename; + struct attrib *attribs; + unsigned int data_turn; + boolean disabled[MAXKEYWORDS]; + struct param *parameters; + void *vm_state; + float producexpchance; + int cookie; + struct _dictionary_ *inifile; - struct global_functions { - int (*wage)(const struct region *r, const struct faction * f, const struct race * rc, int in_turn); - int (*maintenance)(const struct unit * u); - } functions; -} settings; -extern settings global; + struct global_functions { + int (*wage) (const struct region * r, const struct faction * f, + const struct race * rc, int in_turn); + int (*maintenance) (const struct unit * u); + } functions; + } settings; + extern settings global; -extern int produceexp(struct unit * u, skill_t sk, int n); + extern int produceexp(struct unit *u, skill_t sk, int n); -extern boolean battledebug; -extern boolean sqlpatch; -extern boolean lomem; /* save memory */ + extern boolean battledebug; + extern boolean sqlpatch; + extern boolean lomem; /* save memory */ -extern const char * dbrace(const struct race * rc); + extern const char *dbrace(const struct race *rc); -extern void set_param(struct param ** p, const char * name, const char * data); -extern const char* get_param(const struct param * p, const char * name); -extern int get_param_int(const struct param * p, const char * name, int def); -extern float get_param_flt(const struct param * p, const char * name, float def); + extern void set_param(struct param **p, const char *name, const char *data); + extern const char *get_param(const struct param *p, const char *name); + extern int get_param_int(const struct param *p, const char *name, int def); + extern float get_param_flt(const struct param *p, const char *name, + float def); -extern boolean ExpensiveMigrants(void); -extern int NMRTimeout(void); -extern int LongHunger(const struct unit * u); -extern int SkillCap(skill_t sk); -extern int NewbieImmunity(void); -extern boolean IsImmune(const struct faction * f); -extern int AllianceAuto(void); /* flags that allied factions get automatically */ -extern int AllianceRestricted(void); /* flags restricted to allied factions */ -extern int HelpMask(void); /* flags restricted to allied factions */ -extern struct order * default_order(const struct locale * lang); -extern int entertainmoney(const struct region * r); + extern boolean ExpensiveMigrants(void); + extern int NMRTimeout(void); + extern int LongHunger(const struct unit *u); + extern int SkillCap(skill_t sk); + extern int NewbieImmunity(void); + extern boolean IsImmune(const struct faction *f); + extern int AllianceAuto(void); /* flags that allied factions get automatically */ + extern int AllianceRestricted(void); /* flags restricted to allied factions */ + extern int HelpMask(void); /* flags restricted to allied factions */ + extern struct order *default_order(const struct locale *lang); + extern int entertainmoney(const struct region *r); -extern void plagues(struct region * r, boolean ismagic); -typedef struct helpmode { - const char * name; - int status; -} helpmode; + extern void plagues(struct region *r, boolean ismagic); + typedef struct helpmode { + const char *name; + int status; + } helpmode; -extern struct helpmode helpmodes[]; + extern struct helpmode helpmodes[]; #define GIVE_SELF 1 #define GIVE_PEASANTS 2 @@ -441,16 +457,16 @@ extern struct helpmode helpmodes[]; #define GIVE_ALLITEMS (GIVE_GOODS|GIVE_HERBS|GIVE_LUXURIES) #define GIVE_DEFAULT (GIVE_SELF|GIVE_PEASANTS|GIVE_LUXURIES|GIVE_HERBS|GIVE_GOODS) -extern struct attrib_type at_guard; -extern void free_gamedata(void); -#if 1 /* disable to count all units */ + extern struct attrib_type at_guard; + extern void free_gamedata(void); +#if 1 /* disable to count all units */ # define count_unit(u) playerrace(u->race) #else # define count_unit(u) 1 #endif #if XECMD_MODULE -extern struct attrib_type at_xontormiaexpress; + extern struct attrib_type at_xontormiaexpress; #endif #ifdef __cplusplus diff --git a/src/kernel/connection.c b/src/kernel/connection.c index fd8d3d3c9..7f2800028 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -41,23 +41,26 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. unsigned int nextborder = 0; #define BORDER_MAXHASH 8191 -connection * borders[BORDER_MAXHASH]; -border_type * bordertypes; +connection *borders[BORDER_MAXHASH]; -void (*border_convert_cb)(struct connection * con, struct attrib * attr) = 0; +border_type *bordertypes; -void -free_borders(void) +void (*border_convert_cb) (struct connection * con, struct attrib * attr) = 0; + +void free_borders(void) { int i; - for (i=0;i!=BORDER_MAXHASH;++i) { + + for (i = 0; i != BORDER_MAXHASH; ++i) { while (borders[i]) { - connection * b = borders[i]; + connection *b = borders[i]; + borders[i] = b->nexthash; while (b) { - connection * bf = b; + connection *bf = b; + b = b->next; - assert(b==NULL || b->nexthash==NULL); + assert(b == NULL || b->nexthash == NULL); if (bf->type->destroy) { bf->type->destroy(bf); } @@ -67,69 +70,77 @@ free_borders(void) } } -connection * -find_border(unsigned int id) +connection *find_border(unsigned int id) { int key; - for (key=0;key!=BORDER_MAXHASH;key++) { - connection * bhash; - for (bhash=borders[key];bhash!=NULL;bhash=bhash->nexthash) { - connection * b; - for (b=bhash;b;b=b->next) { - if (b->id==id) return b; + + for (key = 0; key != BORDER_MAXHASH; key++) { + connection *bhash; + + for (bhash = borders[key]; bhash != NULL; bhash = bhash->nexthash) { + connection *b; + + for (b = bhash; b; b = b->next) { + if (b->id == id) + return b; } } } return NULL; } -int -resolve_borderid(variant id, void * addr) +int resolve_borderid(variant id, void *addr) { int result = 0; - connection * b = NULL; - if (id.i!=0) { + + connection *b = NULL; + + if (id.i != 0) { b = find_border(id.i); - if (b==NULL) { + if (b == NULL) { result = -1; } } - *(connection**)addr = b; + *(connection **) addr = b; return result; } -static connection ** -get_borders_i(const region * r1, const region * r2) +static connection **get_borders_i(const region * r1, const region * r2) { - connection ** bp; + connection **bp; + int key = reg_hashkey(r1); + int k2 = reg_hashkey(r2); key = MIN(k2, key) % BORDER_MAXHASH; bp = &borders[key]; while (*bp) { - connection * b = *bp; - if ((b->from==r1 && b->to==r2) || (b->from==r2 && b->to==r1)) break; + connection *b = *bp; + + if ((b->from == r1 && b->to == r2) || (b->from == r2 && b->to == r1)) + break; bp = &b->nexthash; } return bp; } -connection * -get_borders(const region * r1, const region * r2) +connection *get_borders(const region * r1, const region * r2) { - connection ** bp = get_borders_i(r1, r2); + connection **bp = get_borders_i(r1, r2); + return *bp; } -connection * -new_border(border_type * type, region * from, region * to) +connection *new_border(border_type * type, region * from, region * to) { - connection * b = calloc(1, sizeof(struct connection)); + connection *b = calloc(1, sizeof(struct connection)); if (from && to) { - connection ** bp = get_borders_i(from, to); - while (*bp) bp = &(*bp)->next; + connection **bp = get_borders_i(from, to); + + while (*bp) + bp = &(*bp)->next; *bp = b; } b->type = type; @@ -137,17 +148,18 @@ new_border(border_type * type, region * from, region * to) b->to = to; b->id = ++nextborder; - if (type->init) type->init(b); + if (type->init) + type->init(b); return b; } -void -erase_border(connection * b) +void erase_border(connection * b) { if (b->from && b->to) { - connection ** bp = get_borders_i(b->from, b->to); - assert(*bp!=NULL || !"error: connection is not registered"); - if (*bp==b) { + connection **bp = get_borders_i(b->from, b->to); + + assert(*bp != NULL || !"error: connection is not registered"); + if (*bp == b) { /* it is the first in the list, so it is in the nexthash list */ if (b->next) { *bp = b->next; @@ -159,7 +171,7 @@ erase_border(connection * b) while (*bp && *bp != b) { bp = &(*bp)->next; } - assert(*bp==b || !"error: connection is not registered"); + assert(*bp == b || !"error: connection is not registered"); *bp = b->next; } } @@ -169,30 +181,31 @@ erase_border(connection * b) free(b); } -void -register_bordertype(border_type * type) +void register_bordertype(border_type * type) { - border_type ** btp = &bordertypes; + border_type **btp = &bordertypes; - while (*btp && *btp!=type) btp = &(*btp)->next; - if (*btp) return; + while (*btp && *btp != type) + btp = &(*btp)->next; + if (*btp) + return; *btp = type; } -border_type * -find_bordertype(const char * name) +border_type *find_bordertype(const char *name) { - border_type * bt = bordertypes; + border_type *bt = bordertypes; - while (bt && strcmp(bt->__name, name)) bt = bt->next; + while (bt && strcmp(bt->__name, name)) + bt = bt->next; return bt; } -void -b_read(connection * b, storage * store) +void b_read(connection * b, storage * store) { int result = 0; + switch (b->type->datatype) { case VAR_NONE: case VAR_INT: @@ -207,11 +220,10 @@ b_read(connection * b, storage * store) assert(!"invalid variant type in connection"); result = 0; } - assert(result>=0 || "EOF encountered?"); + assert(result >= 0 || "EOF encountered?"); } -void -b_write(const connection * b, storage * store) +void b_write(const connection * b, storage * store) { switch (b->type->datatype) { case VAR_NONE: @@ -228,16 +240,79 @@ b_write(const connection * b, storage * store) } } -boolean b_transparent(const connection * b, const struct faction * f) { unused(b); unused(f); return true; } -boolean b_opaque(const connection * b, const struct faction * f) { unused(b); unused(f); return false; } -boolean b_blockall(const connection * b, const unit * u, const region * r) { unused(u); unused(r); unused(b); return true; } -boolean b_blocknone(const connection * b, const unit * u, const region * r) { unused(u); unused(r); unused(b); return false; } -boolean b_rvisible(const connection * b, const region * r) { return (boolean)(b->to==r || b->from==r); } -boolean b_fvisible(const connection * b, const struct faction * f, const region * r) { unused(r); unused(f); unused(b); return true; } -boolean b_uvisible(const connection * b, const unit * u) { unused(u); unused(b); return true; } -boolean b_rinvisible(const connection * b, const region * r) { unused(r); unused(b); return false; } -boolean b_finvisible(const connection * b, const struct faction * f, const region * r) { unused(r); unused(f); unused(b); return false; } -boolean b_uinvisible(const connection * b, const unit * u) { unused(u); unused(b); return false; } +boolean b_transparent(const connection * b, const struct faction *f) +{ + unused(b); + unused(f); + return true; +} + +boolean b_opaque(const connection * b, const struct faction * f) +{ + unused(b); + unused(f); + return false; +} + +boolean b_blockall(const connection * b, const unit * u, const region * r) +{ + unused(u); + unused(r); + unused(b); + return true; +} + +boolean b_blocknone(const connection * b, const unit * u, const region * r) +{ + unused(u); + unused(r); + unused(b); + return false; +} + +boolean b_rvisible(const connection * b, const region * r) +{ + return (boolean) (b->to == r || b->from == r); +} + +boolean b_fvisible(const connection * b, const struct faction * f, + const region * r) +{ + unused(r); + unused(f); + unused(b); + return true; +} + +boolean b_uvisible(const connection * b, const unit * u) +{ + unused(u); + unused(b); + return true; +} + +boolean b_rinvisible(const connection * b, const region * r) +{ + unused(r); + unused(b); + return false; +} + +boolean b_finvisible(const connection * b, const struct faction * f, + const region * r) +{ + unused(r); + unused(f); + unused(b); + return false; +} + +boolean b_uinvisible(const connection * b, const unit * u) +{ + unused(u); + unused(b); + return false; +} /**************************************/ /* at_countdown - legacy, do not use */ @@ -252,27 +327,30 @@ attrib_type at_countdown = { a_readint }; -void -age_borders(void) +void age_borders(void) { - quicklist * deleted = NULL, *ql; + quicklist *deleted = NULL, *ql; + int i; - for (i=0;i!=BORDER_MAXHASH;++i) { - connection * bhash = borders[i]; - for (;bhash;bhash=bhash->nexthash) { - connection * b = bhash; - for (;b;b=b->next) { + for (i = 0; i != BORDER_MAXHASH; ++i) { + connection *bhash = borders[i]; + + for (; bhash; bhash = bhash->nexthash) { + connection *b = bhash; + + for (; b; b = b->next) { if (b->type->age) { - if (b->type->age(b)==AT_AGE_REMOVE) { + if (b->type->age(b) == AT_AGE_REMOVE) { ql_push(&deleted, b); } } } } } - for (ql=deleted,i=0;ql;ql_advance(&ql, &i, 1)) { - connection * b = (connection *)ql_get(ql, i); + for (ql = deleted, i = 0; ql; ql_advance(&ql, &i, 1)) { + connection *b = (connection *) ql_get(ql, i); + erase_border(b); } ql_free(deleted); @@ -285,55 +363,59 @@ age_borders(void) #include "faction.h" -static const char * -b_namewall(const connection * b, const region * r, const struct faction * f, int gflags) +static const char *b_namewall(const connection * b, const region * r, + const struct faction *f, int gflags) { - const char * bname = "wall"; + const char *bname = "wall"; unused(f); unused(r); unused(b); - if (gflags & GF_ARTICLE) bname = "a_wall"; - if (gflags & GF_PURE) return bname; + if (gflags & GF_ARTICLE) + bname = "a_wall"; + if (gflags & GF_PURE) + return bname; return LOC(f->locale, mkname("border", bname)); } border_type bt_wall = { "wall", VAR_INT, b_opaque, - NULL, /* init */ - NULL, /* destroy */ - b_read, /* read */ - b_write, /* write */ - b_blockall, /* block */ - b_namewall, /* name */ - b_rvisible, /* rvisible */ - b_fvisible, /* fvisible */ - b_uvisible, /* uvisible */ + NULL, /* init */ + NULL, /* destroy */ + b_read, /* read */ + b_write, /* write */ + b_blockall, /* block */ + b_namewall, /* name */ + b_rvisible, /* rvisible */ + b_fvisible, /* fvisible */ + b_uvisible, /* uvisible */ }; border_type bt_noway = { "noway", VAR_INT, b_transparent, - NULL, /* init */ - NULL, /* destroy */ - b_read, /* read */ - b_write, /* write */ - b_blockall, /* block */ - NULL, /* name */ - b_rinvisible, /* rvisible */ - b_finvisible, /* fvisible */ - b_uinvisible, /* uvisible */ + NULL, /* init */ + NULL, /* destroy */ + b_read, /* read */ + b_write, /* write */ + b_blockall, /* block */ + NULL, /* name */ + b_rinvisible, /* rvisible */ + b_finvisible, /* fvisible */ + b_uinvisible, /* uvisible */ }; -static const char * -b_namefogwall(const connection * b, const region * r, const struct faction * f, int gflags) +static const char *b_namefogwall(const connection * b, const region * r, + const struct faction *f, int gflags) { unused(f); unused(b); unused(r); - if (gflags & GF_PURE) return "fogwall"; - if (gflags & GF_ARTICLE) return LOC(f->locale, mkname("border", "a_fogwall")); + if (gflags & GF_PURE) + return "fogwall"; + if (gflags & GF_ARTICLE) + return LOC(f->locale, mkname("border", "a_fogwall")); return LOC(f->locale, mkname("border", "fogwall")); } @@ -342,66 +424,76 @@ b_blockfogwall(const connection * b, const unit * u, const region * r) { unused(b); unused(r); - if (!u) return true; - return (boolean)(effskill(u, SK_PERCEPTION) > 4); /* Das ist die alte Nebelwand */ + if (!u) + return true; + return (boolean) (effskill(u, SK_PERCEPTION) > 4); /* Das ist die alte Nebelwand */ } /** Legacy type used in old Eressea games, no longer in use. */ border_type bt_fogwall = { "fogwall", VAR_INT, - b_transparent, /* transparent */ - NULL, /* init */ - NULL, /* destroy */ - b_read, /* read */ - b_write, /* write */ - b_blockfogwall, /* block */ - b_namefogwall, /* name */ - b_rvisible, /* rvisible */ - b_fvisible, /* fvisible */ - b_uvisible, /* uvisible */ + b_transparent, /* transparent */ + NULL, /* init */ + NULL, /* destroy */ + b_read, /* read */ + b_write, /* write */ + b_blockfogwall, /* block */ + b_namefogwall, /* name */ + b_rvisible, /* rvisible */ + b_fvisible, /* fvisible */ + b_uvisible, /* uvisible */ }; -static const char * -b_nameillusionwall(const connection * b, const region * r, const struct faction * f, int gflags) +static const char *b_nameillusionwall(const connection * b, const region * r, + const struct faction *f, int gflags) { int fno = b->data.i; + unused(b); unused(r); - if (gflags & GF_PURE) return (f && fno==f->no)?"illusionwall":"wall"; + if (gflags & GF_PURE) + return (f && fno == f->no) ? "illusionwall" : "wall"; if (gflags & GF_ARTICLE) { - return LOC(f->locale, mkname("border", (f && fno==f->subscription)?"an_illusionwall":"a_wall")); + return LOC(f->locale, mkname("border", (f + && fno == f->subscription) ? "an_illusionwall" : "a_wall")); } - return LOC(f->locale, mkname("border", (f && fno==f->no)?"illusionwall":"wall")); + return LOC(f->locale, mkname("border", (f + && fno == f->no) ? "illusionwall" : "wall")); } border_type bt_illusionwall = { "illusionwall", VAR_INT, b_opaque, - NULL, /* init */ - NULL, /* destroy */ - b_read, /* read */ - b_write, /* write */ - b_blocknone, /* block */ - b_nameillusionwall, /* name */ - b_rvisible, /* rvisible */ - b_fvisible, /* fvisible */ - b_uvisible, /* uvisible */ + NULL, /* init */ + NULL, /* destroy */ + b_read, /* read */ + b_write, /* write */ + b_blocknone, /* block */ + b_nameillusionwall, /* name */ + b_rvisible, /* rvisible */ + b_fvisible, /* fvisible */ + b_uvisible, /* uvisible */ }; /*** * special quest door ***/ -boolean b_blockquestportal(const connection * b, const unit * u, const region * r) { - if(b->data.i > 0) return true; +boolean b_blockquestportal(const connection * b, const unit * u, + const region * r) +{ + if (b->data.i > 0) + return true; return false; } -static const char * -b_namequestportal(const connection * b, const region * r, const struct faction * f, int gflags) +static const char *b_namequestportal(const connection * b, const region * r, + const struct faction *f, int gflags) { - const char * bname; + const char *bname; + int lock = b->data.i; + unused(b); unused(r); @@ -418,90 +510,97 @@ b_namequestportal(const connection * b, const region * r, const struct faction * bname = "gate_open"; } } - if (gflags & GF_PURE) return bname; + if (gflags & GF_PURE) + return bname; return LOC(f->locale, mkname("border", bname)); } border_type bt_questportal = { "questportal", VAR_INT, b_opaque, - NULL, /* init */ - NULL, /* destroy */ - b_read, /* read */ - b_write, /* write */ - b_blockquestportal, /* block */ - b_namequestportal, /* name */ - b_rvisible, /* rvisible */ - b_fvisible, /* fvisible */ - b_uvisible, /* uvisible */ + NULL, /* init */ + NULL, /* destroy */ + b_read, /* read */ + b_write, /* write */ + b_blockquestportal, /* block */ + b_namequestportal, /* name */ + b_rvisible, /* rvisible */ + b_fvisible, /* fvisible */ + b_uvisible, /* uvisible */ }; /*** * roads. meant to replace the old at_road or r->road attribute ***/ -static const char * -b_nameroad(const connection * b, const region * r, const struct faction * f, int gflags) +static const char *b_nameroad(const connection * b, const region * r, + const struct faction *f, int gflags) { - region * r2 = (r==b->to)?b->from:b->to; - int local = (r==b->from)?b->data.sa[0]:b->data.sa[1]; + region *r2 = (r == b->to) ? b->from : b->to; + + int local = (r == b->from) ? b->data.sa[0] : b->data.sa[1]; + static char buffer[64]; unused(f); - if (gflags & GF_PURE) return "road"; + if (gflags & GF_PURE) + return "road"; if (gflags & GF_ARTICLE) { - if (!(gflags & GF_DETAILED)) return LOC(f->locale, mkname("border", "a_road")); - else if (r->terrain->max_road<=local) { - int remote = (r2==b->from)?b->data.sa[0]:b->data.sa[1]; - if (r2->terrain->max_road<=remote) { + if (!(gflags & GF_DETAILED)) + return LOC(f->locale, mkname("border", "a_road")); + else if (r->terrain->max_road <= local) { + int remote = (r2 == b->from) ? b->data.sa[0] : b->data.sa[1]; + + if (r2->terrain->max_road <= remote) { return LOC(f->locale, mkname("border", "a_road")); } else { return LOC(f->locale, mkname("border", "an_incomplete_road")); } } else { - int percent = MAX(1, 100*local/r->terrain->max_road); + int percent = MAX(1, 100 * local / r->terrain->max_road); + if (local) { - snprintf(buffer, sizeof(buffer), LOC(f->locale, mkname("border", "a_road_percent")), percent); + snprintf(buffer, sizeof(buffer), LOC(f->locale, mkname("border", + "a_road_percent")), percent); } else { return LOC(f->locale, mkname("border", "a_road_connection")); } } - } - else if (gflags & GF_PLURAL) return LOC(f->locale, mkname("border", "roads")); - else return LOC(f->locale, mkname("border", "road")); + } else if (gflags & GF_PLURAL) + return LOC(f->locale, mkname("border", "roads")); + else + return LOC(f->locale, mkname("border", "road")); return buffer; } -static void -b_readroad(connection * b, storage * store) +static void b_readroad(connection * b, storage * store) { b->data.sa[0] = (short)store->r_int(store); b->data.sa[1] = (short)store->r_int(store); } -static void -b_writeroad(const connection * b, storage * store) +static void b_writeroad(const connection * b, storage * store) { store->w_int(store, b->data.sa[0]); store->w_int(store, b->data.sa[1]); } -static boolean -b_validroad(const connection * b) +static boolean b_validroad(const connection * b) { - if (b->data.sa[0]==SHRT_MAX) return false; + if (b->data.sa[0] == SHRT_MAX) + return false; return true; } -static boolean -b_rvisibleroad(const connection * b, const region * r) +static boolean b_rvisibleroad(const connection * b, const region * r) { int x = b->data.i; - x = (r==b->from)?b->data.sa[0]:b->data.sa[1]; - if (x==0) { + + x = (r == b->from) ? b->data.sa[0] : b->data.sa[1]; + if (x == 0) { return false; } - if (b->to!=r && b->from!=r) { + if (b->to != r && b->from != r) { return false; } return true; @@ -510,34 +609,38 @@ b_rvisibleroad(const connection * b, const region * r) border_type bt_road = { "road", VAR_INT, b_transparent, - NULL, /* init */ - NULL, /* destroy */ - b_readroad, /* read */ - b_writeroad, /* write */ - b_blocknone, /* block */ - b_nameroad, /* name */ - b_rvisibleroad, /* rvisible */ - b_finvisible, /* fvisible */ - b_uinvisible, /* uvisible */ - b_validroad /* valid */ + NULL, /* init */ + NULL, /* destroy */ + b_readroad, /* read */ + b_writeroad, /* write */ + b_blocknone, /* block */ + b_nameroad, /* name */ + b_rvisibleroad, /* rvisible */ + b_finvisible, /* fvisible */ + b_uinvisible, /* uvisible */ + b_validroad /* valid */ }; -void -write_borders(struct storage * store) +void write_borders(struct storage *store) { int i; - for (i=0;i!=BORDER_MAXHASH;++i) { - connection * bhash; - for (bhash=borders[i];bhash;bhash=bhash->nexthash) { - connection * b; - for (b=bhash;b!=NULL;b=b->next) { - if (b->type->valid && !b->type->valid(b)) continue; + + for (i = 0; i != BORDER_MAXHASH; ++i) { + connection *bhash; + + for (bhash = borders[i]; bhash; bhash = bhash->nexthash) { + connection *b; + + for (b = bhash; b != NULL; b = b->next) { + if (b->type->valid && !b->type->valid(b)) + continue; store->w_tok(store, b->type->__name); store->w_int(store, b->id); store->w_int(store, b->from->uid); store->w_int(store, b->to->uid); - if (b->type->write) b->type->write(b, store); + if (b->type->write) + b->type->write(b, store); store->w_brk(store); } } @@ -545,21 +648,26 @@ write_borders(struct storage * store) store->w_tok(store, "end"); } -int -read_borders(struct storage * store) +int read_borders(struct storage *store) { for (;;) { unsigned int bid = 0; + char zText[32]; - connection * b; - region * from, * to; - border_type * type; + + connection *b; + + region *from, *to; + + border_type *type; store->r_tok_buf(store, zText, sizeof(zText)); - if (!strcmp(zText, "end")) break; + if (!strcmp(zText, "end")) + break; bid = store->r_int(store); - if (store->versionversion < UIDHASH_VERSION) { short fx, fy, tx, ty; + fx = (short)store->r_int(store); fy = (short)store->r_int(store); tx = (short)store->r_int(store); @@ -568,38 +676,48 @@ read_borders(struct storage * store) to = findregion(tx, ty); } else { unsigned int fid = (unsigned int)store->r_int(store); + unsigned int tid = (unsigned int)store->r_int(store); + from = findregionbyid(fid); to = findregionbyid(tid); } type = find_bordertype(zText); - if (type==NULL) { - log_error(("[read_borders] unknown connection type %s in %s\n", zText, - regionname(from, NULL))); + if (type == NULL) { + log_error(("[read_borders] unknown connection type %s in %s\n", zText, + regionname(from, NULL))); assert(type || !"connection type not registered"); } - if (to==from && type && from) { + if (to == from && type && from) { direction_t dir = (direction_t) (rng_int() % MAXDIRECTIONS); - region * r = rconnect(from, dir); - log_error(("[read_borders] invalid %s in %s\n", type->__name, - regionname(from, NULL))); - if (r!=NULL) to = r; + + region *r = rconnect(from, dir); + + log_error(("[read_borders] invalid %s in %s\n", type->__name, + regionname(from, NULL))); + if (r != NULL) + to = r; } b = new_border(type, from, to); - nextborder--; /* new_border erhöht den Wert */ + nextborder--; /* new_border erhöht den Wert */ b->id = bid; - assert(bid<=nextborder); - if (type->read) type->read(b, store); - if (store->versionread) + type->read(b, store); + if (store->version < NOBORDERATTRIBS_VERSION) { + attrib *a = NULL; + int result = a_read(store, &a, b); - if (border_convert_cb) border_convert_cb(b, a); + + if (border_convert_cb) + border_convert_cb(b, a); while (a) { a_remove(&a, a); } - if (result<0) return result; + if (result < 0) + return result; } if (!to || !from) { erase_border(b); diff --git a/src/kernel/connection.h b/src/kernel/connection.h index 9a7091132..71d199b12 100644 --- a/src/kernel/connection.h +++ b/src/kernel/connection.h @@ -28,95 +28,105 @@ extern "C" { extern unsigned int nextborder; typedef struct connection { - struct border_type * type; /* the type of this connection */ - struct connection * next; /* next connection between these regions */ - struct connection * nexthash; /* next connection between these regions */ - struct region * from, * to; /* borders can be directed edges */ + struct border_type *type; /* the type of this connection */ + struct connection *next; /* next connection between these regions */ + struct connection *nexthash; /* next connection between these regions */ + struct region *from, *to; /* borders can be directed edges */ variant data; - unsigned int id; /* unique id */ + unsigned int id; /* unique id */ } connection; typedef struct border_type { - const char* __name; /* internal use only */ + const char *__name; /* internal use only */ variant_type datatype; - boolean (*transparent)(const connection *, const struct faction *); + boolean(*transparent) (const connection *, const struct faction *); /* is it possible to see through this? */ - void (*init)(connection *); + void (*init) (connection *); /* constructor: initialize the connection. allocate extra memory if needed */ - void (*destroy)(connection *); + void (*destroy) (connection *); /* destructor: remove all extra memory for destruction */ - void (*read)(connection *, struct storage *); - void (*write)(const connection *, struct storage *); - boolean (*block)(const connection *, const struct unit *, const struct region * r); + void (*read) (connection *, struct storage *); + void (*write) (const connection *, struct storage *); + boolean(*block) (const connection *, const struct unit *, + const struct region * r); /* return true if it blocks movement of u from - * r to the opposite struct region. - * warning: struct unit may be NULL. - */ - const char *(*name)(const connection * b, const struct region * r, const struct faction * f, int gflags); + * r to the opposite struct region. + * warning: struct unit may be NULL. + */ + const char *(*name) (const connection * b, const struct region * r, + const struct faction * f, int gflags); /* for example "a wall of fog" or "a doorway from r1 to r2" - * may depend on the struct faction, for example "a wall" may - * turn out to be "an illusionary wall" - */ - boolean (*rvisible)(const connection *, const struct region *); + * may depend on the struct faction, for example "a wall" may + * turn out to be "an illusionary wall" + */ + boolean(*rvisible) (const connection *, const struct region *); /* is it visible to everyone in r ? - * if not, it may still be fvisible() for some f. - */ - boolean (*fvisible)(const connection *, const struct faction *, const struct region *); + * if not, it may still be fvisible() for some f. + */ + boolean(*fvisible) (const connection *, const struct faction *, + const struct region *); /* is it visible to units of f in r? - * the function shall not check for - * existence of a struct unit in r. Example: a spell - * may be visible only to the struct faction that created it and thus - * appear in it's report (if there is a struct unit of f in r, which - * the reporting function will have to assure). - * if not true, it may still be uvisible() for some u. - */ - boolean (*uvisible)(const connection *, const struct unit *); + * the function shall not check for + * existence of a struct unit in r. Example: a spell + * may be visible only to the struct faction that created it and thus + * appear in it's report (if there is a struct unit of f in r, which + * the reporting function will have to assure). + * if not true, it may still be uvisible() for some u. + */ + boolean(*uvisible) (const connection *, const struct unit *); /* is it visible to u ? - * a doorway may only be visible to a struct unit with perception > 5 - */ - boolean (*valid)(const connection *); + * a doorway may only be visible to a struct unit with perception > 5 + */ + boolean(*valid) (const connection *); /* is the connection in a valid state, - * or should it be erased at the end of this turn to save space? - */ - struct region * (*move)(const connection *, struct unit * u, struct region * from, struct region * to, boolean routing); + * or should it be erased at the end of this turn to save space? + */ + struct region *(*move) (const connection *, struct unit * u, + struct region * from, struct region * to, boolean routing); /* executed when the units traverses this connection */ - int (*age)(struct connection *); + int (*age) (struct connection *); /* return 0 if connection needs to be removed. >0 if still aging, <0 if not aging */ - struct border_type * next; /* for internal use only */ + struct border_type *next; /* for internal use only */ } border_type; - extern connection * find_border(unsigned int id); - int resolve_borderid(variant data, void * addr); + extern connection *find_border(unsigned int id); + int resolve_borderid(variant data, void *addr); extern void free_borders(void); - extern connection * get_borders(const struct region * r1, const struct region * r2); + extern connection *get_borders(const struct region *r1, + const struct region *r2); /* returns the list of borders between r1 and r2 or r2 and r1 */ - extern connection * new_border(border_type * type, struct region * from, struct region * to); + extern connection *new_border(border_type * type, struct region *from, + struct region *to); /* creates a connection of the specified type */ extern void erase_border(connection * b); /* remove the connection from memory */ - extern border_type * find_bordertype(const char * name); + extern border_type *find_bordertype(const char *name); extern void register_bordertype(border_type * type); /* register a new bordertype */ - extern int read_borders(struct storage * store); - extern void write_borders(struct storage * store); + extern int read_borders(struct storage *store); + extern void write_borders(struct storage *store); extern void age_borders(void); /* provide default implementations for some member functions: */ - extern void b_read(connection * b, struct storage * store); - extern void b_write(const connection * b, struct storage * store); - extern boolean b_blockall(const connection *, const struct unit *, const struct region *); - extern boolean b_blocknone(const connection *, const struct unit *, const struct region *); - extern boolean b_rvisible(const connection *, const struct region * r); - extern boolean b_fvisible(const connection *, const struct faction * f, const struct region *); - extern boolean b_uvisible(const connection *, const struct unit * u); - extern boolean b_rinvisible(const connection *, const struct region * r); - extern boolean b_finvisible(const connection *, const struct faction * f, const struct region *); - extern boolean b_uinvisible(const connection *, const struct unit * u); + extern void b_read(connection * b, struct storage *store); + extern void b_write(const connection * b, struct storage *store); + extern boolean b_blockall(const connection *, const struct unit *, + const struct region *); + extern boolean b_blocknone(const connection *, const struct unit *, + const struct region *); + extern boolean b_rvisible(const connection *, const struct region *r); + extern boolean b_fvisible(const connection *, const struct faction *f, + const struct region *); + extern boolean b_uvisible(const connection *, const struct unit *u); + extern boolean b_rinvisible(const connection *, const struct region *r); + extern boolean b_finvisible(const connection *, const struct faction *f, + const struct region *); + extern boolean b_uinvisible(const connection *, const struct unit *u); extern boolean b_transparent(const connection *, const struct faction *); - extern boolean b_opaque(const connection *, const struct faction *); /* !transparent */ + extern boolean b_opaque(const connection *, const struct faction *); /* !transparent */ extern border_type bt_fogwall; extern border_type bt_noway; @@ -128,7 +138,8 @@ extern "C" { extern struct attrib_type at_countdown; /* game-specific callbacks */ - extern void (*border_convert_cb)(struct connection * con, struct attrib * attr); + extern void (*border_convert_cb) (struct connection * con, + struct attrib * attr); #ifdef __cplusplus } diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 0747d9443..587be847f 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -59,35 +59,33 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define MAXENTITYHASH 7919 curse *cursehash[MAXENTITYHASH]; -void -c_setflag(curse *c, unsigned int flags) +void c_setflag(curse * c, unsigned int flags) { assert(c); c->flags = (c->flags & ~flags) | (flags & (c->type->flags ^ flags)); } + /* -------------------------------------------------------------------------- */ -void -c_clearflag(curse *c, unsigned int flags) +void c_clearflag(curse * c, unsigned int flags) { assert(c); c->flags = (c->flags & ~flags) | (c->type->flags & flags); } -void -chash(curse *c) +void chash(curse * c) { - curse *old = cursehash[c->no %MAXENTITYHASH]; + curse *old = cursehash[c->no % MAXENTITYHASH]; - cursehash[c->no %MAXENTITYHASH] = c; + cursehash[c->no % MAXENTITYHASH] = c; c->nexthash = old; } -static void -cunhash(curse *c) +static void cunhash(curse * c) { curse **show; - for (show = &cursehash[c->no % MAXENTITYHASH]; *show; show = &(*show)->nexthash) { + for (show = &cursehash[c->no % MAXENTITYHASH]; *show; + show = &(*show)->nexthash) { if ((*show)->no == c->no) break; } @@ -98,8 +96,7 @@ cunhash(curse *c) } } -curse * -cfindhash(int i) +curse *cfindhash(int i) { curse *old; @@ -111,15 +108,15 @@ cfindhash(int i) /* ------------------------------------------------------------- */ /* at_curse */ -void -curse_init(attrib * a) { +void curse_init(attrib * a) +{ a->data.v = calloc(1, sizeof(curse)); } -int -curse_age(attrib * a) +int curse_age(attrib * a) { - curse * c = (curse*)a->data.v; + curse *c = (curse *) a->data.v; + int result = 0; if (c_flags(c) & CURSE_NOAGE) { @@ -128,44 +125,56 @@ curse_age(attrib * a) if (c->type->age) { result = c->type->age(c); } - if (result!=0) { + if (result != 0) { c->duration = 0; - } else if (c->duration!=INT_MAX) { - c->duration = MAX(0, c->duration-1); + } else if (c->duration != INT_MAX) { + c->duration = MAX(0, c->duration - 1); } return c->duration; } -void -destroy_curse(curse * c) +void destroy_curse(curse * c) { cunhash(c); free(c); } -void -curse_done(attrib * a) { - destroy_curse((curse *)a->data.v); +void curse_done(attrib * a) +{ + destroy_curse((curse *) a->data.v); } /** reads curses that have been removed from the code */ -static int -read_ccompat(const char * cursename, struct storage * store) +static int read_ccompat(const char *cursename, struct storage *store) { struct compat { - const char * name; - const char * tokens; - } * seek, old_curses[] = { {"disorientationzone", ""}, {"shipdisorientation", ""}, { NULL, NULL } } ; - for (seek=old_curses;seek->name;++seek) { - if (strcmp(seek->tokens, cursename)==0) { - const char * p; - for (p=seek->name;p;++p) { + const char *name; + const char *tokens; + } *seek, old_curses[] = { { + "disorientationzone", ""}, { + "shipdisorientation", ""}, { + NULL, NULL}}; + for (seek = old_curses; seek->name; ++seek) { + if (strcmp(seek->tokens, cursename) == 0) { + const char *p; + + for (p = seek->name; p; ++p) { switch (*p) { - case 'd': store->r_int(store); break; - case 's': store->r_str(store); break; - case 't': store->r_tok(store); break; - case 'i': store->r_id(store); break; - case 'f': store->r_flt(store); break; + case 'd': + store->r_int(store); + break; + case 's': + store->r_str(store); + break; + case 't': + store->r_tok(store); + break; + case 'i': + store->r_id(store); + break; + case 'f': + store->r_flt(store); + break; } } return 0; @@ -174,12 +183,14 @@ read_ccompat(const char * cursename, struct storage * store) return -1; } -int -curse_read(attrib * a, void * owner, struct storage * store) +int curse_read(attrib * a, void *owner, struct storage *store) { - curse * c = (curse*)a->data.v; + curse *c = (curse *) a->data.v; + int ur; + char cursename[64]; + unsigned int flags; c->no = store->r_int(store); @@ -191,25 +202,28 @@ curse_read(attrib * a, void * owner, struct storage * store) c->vigour = store->r_flt(store); } else { int vigour = store->r_int(store); + c->vigour = vigour; } - if (store->versionversion < INTPAK_VERSION) { ur = read_reference(&c->magician, store, read_int, resolve_unit); } else { ur = read_reference(&c->magician, store, read_unit_reference, resolve_unit); } - if (store->versionversion < CURSEFLOAT_VERSION) { c->effect = (double)store->r_int(store); } else { c->effect = store->r_flt(store); } c->type = ct_find(cursename); - if (c->type==NULL) { + if (c->type == NULL) { int result = read_ccompat(cursename, store); - if (result!=0) { - log_error(("missing curse %s, no compatibility code either.\n", cursename)); + + if (result != 0) { + log_error(("missing curse %s, no compatibility code either.\n", + cursename)); } - assert(result==0); + assert(result == 0); return AT_READ_FAIL; } if (store->version < CURSEFLAGS_VERSION) { @@ -218,14 +232,17 @@ curse_read(attrib * a, void * owner, struct storage * store) c->flags = flags; } c_clearflag(c, CURSE_ISNEW); - - if (c->type->read) c->type->read(store, c, owner); - else if (c->type->typ==CURSETYP_UNIT) { + + if (c->type->read) + c->type->read(store, c, owner); + else if (c->type->typ == CURSETYP_UNIT) { c->data.i = store->r_int(store); } if (c->type->typ == CURSETYP_REGION) { - int rr = read_reference(&c->data.v, store, read_region_reference, RESOLVE_REGION(store->version)); - if (ur==0 && rr==0 && !c->data.v) { + int rr = + read_reference(&c->data.v, store, read_region_reference, + RESOLVE_REGION(store->version)); + if (ur == 0 && rr == 0 && !c->data.v) { return AT_READ_FAIL; } } @@ -233,13 +250,15 @@ curse_read(attrib * a, void * owner, struct storage * store) return AT_READ_OK; } -void -curse_write(const attrib * a, const void * owner, struct storage * store) +void curse_write(const attrib * a, const void *owner, struct storage *store) { unsigned int flags; - curse * c = (curse*)a->data.v; - const curse_type * ct = c->type; - unit * mage = (c->magician && c->magician->number)?c->magician:NULL; + + curse *c = (curse *) a->data.v; + + const curse_type *ct = c->type; + + unit *mage = (c->magician && c->magician->number) ? c->magician : NULL; /* copied from c_clearflag */ flags = (c->flags & ~CURSE_ISNEW) | (c->type->flags & CURSE_ISNEW); @@ -252,17 +271,17 @@ curse_write(const attrib * a, const void * owner, struct storage * store) write_unit_reference(mage, store); store->w_flt(store, (float)c->effect); - if (c->type->write) c->type->write(store, c, owner); + if (c->type->write) + c->type->write(store, c, owner); else if (c->type->typ == CURSETYP_UNIT) { store->w_int(store, c->data.i); } if (c->type->typ == CURSETYP_REGION) { - write_region_reference((region*)c->data.v, store); + write_region_reference((region *) c->data.v, store); } } -attrib_type at_curse = -{ +attrib_type at_curse = { "curse", curse_init, curse_done, @@ -271,37 +290,40 @@ attrib_type at_curse = curse_read, ATF_CURSE }; + /* ------------------------------------------------------------- */ /* Spruch identifizieren */ #include #include -static quicklist * cursetypes[256]; +static quicklist *cursetypes[256]; -void -ct_register(const curse_type * ct) +void ct_register(const curse_type * ct) { unsigned int hash = tolower(ct->cname[0]); - quicklist ** ctlp = cursetypes+hash; + + quicklist **ctlp = cursetypes + hash; ql_set_insert(ctlp, (void *)ct); } -const curse_type * -ct_find(const char *c) +const curse_type *ct_find(const char *c) { unsigned int hash = tolower(c[0]); - quicklist * ctl = cursetypes[hash]; + + quicklist *ctl = cursetypes[hash]; + int qi; - for (qi=0;ctl;ql_advance(&ctl, &qi, 1)) { - curse_type * type = (curse_type*)ql_get(ctl, qi); + for (qi = 0; ctl; ql_advance(&ctl, &qi, 1)) { + curse_type *type = (curse_type *) ql_get(ctl, qi); - if (strcmp(c, type->cname)==0) { + if (strcmp(c, type->cname) == 0) { return type; } else { size_t k = MIN(strlen(c), strlen(type->cname)); + if (!strncasecmp(c, type->cname, k)) { return type; } @@ -315,47 +337,56 @@ ct_find(const char *c) * einen pointer auf die struct zurück. */ -boolean -cmp_curse(const attrib * a, const void * data) { - const curse * c = (const curse*)data; +boolean cmp_curse(const attrib * a, const void *data) +{ + const curse *c = (const curse *)data; + if (a->type->flags & ATF_CURSE) { - if (!data || c == (curse*)a->data.v) return true; + if (!data || c == (curse *) a->data.v) + return true; } return false; } -boolean -cmp_cursetype(const attrib * a, const void * data) +boolean cmp_cursetype(const attrib * a, const void *data) { - const curse_type * ct = (const curse_type *)data; + const curse_type *ct = (const curse_type *)data; + if (a->type->flags & ATF_CURSE) { - if (!data || ct == ((curse*)a->data.v)->type) return true; + if (!data || ct == ((curse *) a->data.v)->type) + return true; } return false; } -curse * -get_cursex(attrib *ap, const curse_type * ctype, variant data, boolean(*compare)(const curse *, variant)) +curse *get_cursex(attrib * ap, const curse_type * ctype, variant data, + boolean(*compare) (const curse *, variant)) { - attrib * a = a_select(ap, ctype, cmp_cursetype); + attrib *a = a_select(ap, ctype, cmp_cursetype); + while (a) { - curse * c = (curse*)a->data.v; - if (compare(c, data)) return c; + curse *c = (curse *) a->data.v; + + if (compare(c, data)) + return c; a = a_select(a->next, ctype, cmp_cursetype); } return NULL; } -curse * -get_curse(attrib *ap, const curse_type * ctype) +curse *get_curse(attrib * ap, const curse_type * ctype) { - attrib * a = ap; + attrib *a = ap; + while (a) { if (a->type->flags & ATF_CURSE) { - const attrib_type * at = a->type; - while (a && a->type==at) { - curse* c = (curse *)a->data.v; - if (c->type==ctype) return c; + const attrib_type *at = a->type; + + while (a && a->type == at) { + curse *c = (curse *) a->data.v; + + if (c->type == ctype) + return c; a = a->next; } } else { @@ -368,33 +399,32 @@ get_curse(attrib *ap, const curse_type * ctype) /* ------------------------------------------------------------- */ /* findet einen curse global anhand seiner 'curse-Einheitnummer' */ -curse * -findcurse(int cid) +curse *findcurse(int cid) { return cfindhash(cid); } /* ------------------------------------------------------------- */ -void -remove_curse(attrib **ap, const curse *c) +void remove_curse(attrib ** ap, const curse * c) { attrib *a = a_select(*ap, c, cmp_curse); - if (a) a_remove(ap, a); + + if (a) + a_remove(ap, a); } /* gibt die allgemeine Stärke der Verzauberung zurück. id2 wird wie * oben benutzt. Dies ist nicht die Wirkung, sondern die Kraft und * damit der gegen Antimagie wirkende Widerstand einer Verzauberung */ -static double -get_cursevigour(const curse *c) +static double get_cursevigour(const curse * c) { - if (c) return c->vigour; + if (c) + return c->vigour; return 0; } /* setzt die Stärke der Verzauberung auf i */ -static void -set_cursevigour(curse *c, double vigour) +static void set_cursevigour(curse * c, double vigour) { assert(c && vigour > 0); c->vigour = vigour; @@ -404,8 +434,7 @@ set_cursevigour(curse *c, double vigour) * Stärke zurück. Sollte die Zauberstärke unter Null sinken, löst er * sich auf. */ -double -curse_changevigour(attrib **ap, curse *c, double vigour) +double curse_changevigour(attrib ** ap, curse * c, double vigour) { vigour += get_cursevigour(c); @@ -420,27 +449,30 @@ curse_changevigour(attrib **ap, curse *c, double vigour) /* ------------------------------------------------------------- */ -double -curse_geteffect(const curse *c) +double curse_geteffect(const curse * c) { - if (c==NULL) return 0; - if (c_flags(c) & CURSE_ISNEW) return 0; + if (c == NULL) + return 0; + if (c_flags(c) & CURSE_ISNEW) + return 0; return c->effect; } -int -curse_geteffect_int(const curse *c) +int curse_geteffect_int(const curse * c) { double effect = curse_geteffect(c); - assert(effect-(int)effect == 0); + + assert(effect - (int)effect == 0); return (int)effect; } /* ------------------------------------------------------------- */ static void -set_curseingmagician(struct unit *magician, struct attrib *ap_target, const curse_type *ct) +set_curseingmagician(struct unit *magician, struct attrib *ap_target, + const curse_type * ct) { - curse * c = get_curse(ap_target, ct); + curse *c = get_curse(ap_target, ct); + if (c) { c->magician = magician; } @@ -449,12 +481,12 @@ set_curseingmagician(struct unit *magician, struct attrib *ap_target, const curs /* ------------------------------------------------------------- */ /* gibt bei Personenbeschränkten Verzauberungen die Anzahl der * betroffenen Personen zurück. Ansonsten wird 0 zurückgegeben. */ -int -get_cursedmen(unit *u, const curse *c) +int get_cursedmen(unit * u, const curse * c) { int cursedmen = u->number; - if (!c) return 0; + if (!c) + return 0; /* je nach curse_type andere data struct */ if (c->type->typ == CURSETYP_UNIT) { @@ -465,10 +497,10 @@ get_cursedmen(unit *u, const curse *c) } /* setzt die Anzahl der betroffenen Personen auf cursedmen */ -static void -set_cursedmen(curse *c, int cursedmen) +static void set_cursedmen(curse * c, int cursedmen) { - if (!c) return; + if (!c) + return; /* je nach curse_type andere data struct */ if (c->type->typ == CURSETYP_UNIT) { @@ -480,16 +512,16 @@ set_cursedmen(curse *c, int cursedmen) /* Legt eine neue Verzauberung an. Sollte es schon einen Zauber * dieses Typs geben, gibt es den bestehenden zurück. */ -static curse * -make_curse(unit *mage, attrib **ap, const curse_type *ct, double vigour, - int duration, double effect, int men) +static curse *make_curse(unit * mage, attrib ** ap, const curse_type * ct, + double vigour, int duration, double effect, int men) { curse *c; - attrib * a; + + attrib *a; a = a_new(&at_curse); a_add(ap, a); - c = (curse*)a->data.v; + c = (curse *) a->data.v; c->type = ct; c->flags = 0; @@ -519,43 +551,42 @@ make_curse(unit *mage, attrib **ap, const curse_type *ct, double vigour, /* Mapperfunktion für das Anlegen neuer curse. Automatisch wird zum * passenden Typ verzweigt und die relevanten Variablen weitergegeben. */ -curse * -create_curse(unit *magician, attrib **ap, const curse_type *ct, double vigour, - int duration, double effect, int men) +curse *create_curse(unit * magician, attrib ** ap, const curse_type * ct, + double vigour, int duration, double effect, int men) { curse *c; - /* die Kraft eines Spruchs darf nicht 0 sein*/ + /* die Kraft eines Spruchs darf nicht 0 sein */ assert(vigour > 0); c = get_curse(*ap, ct); - if (c && (c_flags(c) & CURSE_ONLYONE)){ + if (c && (c_flags(c) & CURSE_ONLYONE)) { return NULL; } - assert(c==NULL || ct==c->type); + assert(c == NULL || ct == c->type); /* es gibt schon eins diese Typs */ if (c && ct->mergeflags != NO_MERGE) { - if(ct->mergeflags & M_DURATION){ + if (ct->mergeflags & M_DURATION) { c->duration = MAX(c->duration, duration); } - if(ct->mergeflags & M_SUMDURATION){ + if (ct->mergeflags & M_SUMDURATION) { c->duration += duration; } - if(ct->mergeflags & M_SUMEFFECT){ + if (ct->mergeflags & M_SUMEFFECT) { c->effect += effect; } - if(ct->mergeflags & M_MAXEFFECT){ + if (ct->mergeflags & M_MAXEFFECT) { c->effect = MAX(c->effect, effect); } - if(ct->mergeflags & M_VIGOUR){ + if (ct->mergeflags & M_VIGOUR) { c->vigour = MAX(vigour, c->vigour); } - if(ct->mergeflags & M_VIGOUR_ADD){ + if (ct->mergeflags & M_VIGOUR_ADD) { c->vigour = vigour + c->vigour; } - if(ct->mergeflags & M_MEN){ + if (ct->mergeflags & M_MEN) { switch (ct->typ) { case CURSETYP_UNIT: { @@ -574,12 +605,14 @@ create_curse(unit *magician, attrib **ap, const curse_type *ct, double vigour, /* hier müssen alle c-typen, die auf Einheiten gezaubert werden können, * berücksichtigt werden */ -static void -do_transfer_curse(curse *c, unit * u, unit * u2, int n) +static void do_transfer_curse(curse * c, unit * u, unit * u2, int n) { int cursedmen = 0; + int men = get_cursedmen(u, c); + boolean dogive = false; + const curse_type *ct = c->type; switch ((ct->flags | c->flags) & CURSE_SPREADMASK) { @@ -591,9 +624,11 @@ do_transfer_curse(curse *c, unit * u, unit * u2, int n) case CURSE_SPREADMODULO: { int i; + int u_number = u->number; - for (i=0;i0;i++){ - if (rng_int()%u_number < cursedmen){ + + for (i = 0; i < n + 1 && u_number > 0; i++) { + if (rng_int() % u_number < cursedmen) { ++men; --cursedmen; dogive = true; @@ -603,7 +638,7 @@ do_transfer_curse(curse *c, unit * u, unit * u2, int n) break; } case CURSE_SPREADCHANCE: - if (chance(u2->number/(double)(u2->number + n))) { + if (chance(u2->number / (double)(u2->number + n))) { men = u2->number + n; dogive = true; } @@ -613,22 +648,24 @@ do_transfer_curse(curse *c, unit * u, unit * u2, int n) } if (dogive == true) { - curse * cnew = make_curse(c->magician, &u2->attribs, c->type, c->vigour, + curse *cnew = make_curse(c->magician, &u2->attribs, c->type, c->vigour, c->duration, c->effect, men); + cnew->flags = c->flags; - if (ct->typ == CURSETYP_UNIT) set_cursedmen(cnew, men); + if (ct->typ == CURSETYP_UNIT) + set_cursedmen(cnew, men); } } -void -transfer_curse(unit * u, unit * u2, int n) +void transfer_curse(unit * u, unit * u2, int n) { - attrib * a; + attrib *a; a = a_find(u->attribs, &at_curse); - while (a && a->type==&at_curse) { - curse *c = (curse*)a->data.v; + while (a && a->type == &at_curse) { + curse *c = (curse *) a->data.v; + do_transfer_curse(c, u, u2, n); a = a->next; } @@ -636,18 +673,19 @@ transfer_curse(unit * u, unit * u2, int n) /* ------------------------------------------------------------- */ -boolean -curse_active(const curse *c) +boolean curse_active(const curse * c) { - if (!c) return false; - if (c_flags(c) & CURSE_ISNEW) return false; - if (c->vigour <= 0) return false; + if (!c) + return false; + if (c_flags(c) & CURSE_ISNEW) + return false; + if (c->vigour <= 0) + return false; return true; } -boolean -is_cursed_internal(attrib *ap, const curse_type *ct) +boolean is_cursed_internal(attrib * ap, const curse_type * ct) { curse *c = get_curse(ap, ct); @@ -658,8 +696,7 @@ is_cursed_internal(attrib *ap, const curse_type *ct) } -boolean -is_cursed_with(const attrib *ap, const curse *c) +boolean is_cursed_with(const attrib * ap, const curse * c) { const attrib *a = ap; @@ -672,6 +709,7 @@ is_cursed_with(const attrib *ap, const curse *c) return false; } + /* ------------------------------------------------------------- */ /* cursedata */ /* ------------------------------------------------------------- */ @@ -688,22 +726,23 @@ is_cursed_with(const attrib *ap, const curse *c) * } curse_type; */ -int -resolve_curse(variant id, void * address) +int resolve_curse(variant id, void *address) { int result = 0; - curse * c = NULL; - if (id.i!=0) { + + curse *c = NULL; + + if (id.i != 0) { c = cfindhash(id.i); - if (c==NULL) { + if (c == NULL) { result = -1; } } - *(curse**)address = c; + *(curse **) address = c; return result; } -static const char * oldnames[MAXCURSE] = { +static const char *oldnames[MAXCURSE] = { /* OBS: when removing curses, remember to update read_ccompat() */ "fogtrap", "antimagiczone", @@ -746,24 +785,23 @@ static const char * oldnames[MAXCURSE] = { "skillmod" }; -const char * -oldcursename(int id) +const char *oldcursename(int id) { return oldnames[id]; } /* ------------------------------------------------------------- */ -message * -cinfo_simple(const void * obj, typ_t typ, const struct curse *c, int self) +message *cinfo_simple(const void *obj, typ_t typ, const struct curse * c, + int self) { - struct message * msg; + struct message *msg; unused(typ); unused(self); unused(obj); msg = msg_message(mkname("curseinfo", c->type->cname), "id", c->no); - if (msg==NULL) { + if (msg == NULL) { log_error(("There is no curseinfo for %s.\n", c->type->cname)); } return msg; @@ -781,22 +819,22 @@ cinfo_simple(const void * obj, typ_t typ, const struct curse *c, int self) * die Kraft des Curse um die halbe Stärke der Antimagie reduziert. * Zurückgegeben wird der noch unverbrauchte Rest von force. */ -double -destr_curse(curse* c, int cast_level, double force) +double destr_curse(curse * c, int cast_level, double force) { if (cast_level < c->vigour) { /* Zauber ist nicht stark genug */ - double probability = 0.1 + (cast_level - c->vigour)*0.2; + double probability = 0.1 + (cast_level - c->vigour) * 0.2; + /* pro Stufe Unterschied -20% */ if (chance(probability)) { force -= c->vigour; if (c->type->change_vigour) { - c->type->change_vigour(c, -(cast_level+1/2)); + c->type->change_vigour(c, -(cast_level + 1 / 2)); } else { - c->vigour -= cast_level+1/2; + c->vigour -= cast_level + 1 / 2; } } - } else { /* Zauber ist stärker als curse */ - if (force >= c->vigour) { /* reicht die Kraft noch aus? */ + } else { /* Zauber ist stärker als curse */ + if (force >= c->vigour) { /* reicht die Kraft noch aus? */ force -= c->vigour; if (c->type->change_vigour) { c->type->change_vigour(c, -c->vigour); diff --git a/src/kernel/curse.h b/src/kernel/curse.h index 7adb53477..16419c1f9 100644 --- a/src/kernel/curse.h +++ b/src/kernel/curse.h @@ -96,130 +96,134 @@ extern "C" { /* nicht vergessen curse_type zu aktualisieren und Reihenfolge beachten! */ -enum { + enum { /* struct's vom typ curse: */ - C_FOGTRAP, - C_ANTIMAGICZONE, - C_FARVISION, - C_GBDREAM, - C_AURA, - C_MAELSTROM, - C_BLESSEDHARVEST, - C_DROUGHT, - C_BADLEARN, - C_SHIP_SPEEDUP, /* 9 - Sturmwind-Zauber */ - C_SHIP_FLYING, /* 10 - Luftschiff-Zauber */ - C_SHIP_NODRIFT, /* 11 - GünstigeWinde-Zauber */ - C_DEPRESSION, - C_MAGICWALLS, /* 13 - Heimstein */ - C_STRONGWALL, /* 14 - Feste Mauer - Precombat*/ - C_ASTRALBLOCK, /* 15 - Astralblock */ - C_GENEROUS, /* 16 - Unterhaltung vermehren */ - C_PEACE, /* 17 - Regionsweit Attacken verhindern */ - C_MAGICSTREET, /* 19 - magisches Straßennetz */ - C_RESIST_MAGIC, /* 20 - verändert Magieresistenz von Objekten */ - C_SONG_BADMR, /* 21 - verändert Magieresistenz */ - C_SONG_GOODMR, /* 22 - verändert Magieresistenz */ - C_SLAVE, /* 23 - dient fremder Partei */ - C_CALM, /* 25 - Beinflussung */ - C_OLDRACE, - C_FUMBLE, - C_RIOT, /*region in Aufruhr */ - C_NOCOST, - C_CURSED_BY_THE_GODS, + C_FOGTRAP, + C_ANTIMAGICZONE, + C_FARVISION, + C_GBDREAM, + C_AURA, + C_MAELSTROM, + C_BLESSEDHARVEST, + C_DROUGHT, + C_BADLEARN, + C_SHIP_SPEEDUP, /* 9 - Sturmwind-Zauber */ + C_SHIP_FLYING, /* 10 - Luftschiff-Zauber */ + C_SHIP_NODRIFT, /* 11 - GünstigeWinde-Zauber */ + C_DEPRESSION, + C_MAGICWALLS, /* 13 - Heimstein */ + C_STRONGWALL, /* 14 - Feste Mauer - Precombat */ + C_ASTRALBLOCK, /* 15 - Astralblock */ + C_GENEROUS, /* 16 - Unterhaltung vermehren */ + C_PEACE, /* 17 - Regionsweit Attacken verhindern */ + C_MAGICSTREET, /* 19 - magisches Straßennetz */ + C_RESIST_MAGIC, /* 20 - verändert Magieresistenz von Objekten */ + C_SONG_BADMR, /* 21 - verändert Magieresistenz */ + C_SONG_GOODMR, /* 22 - verändert Magieresistenz */ + C_SLAVE, /* 23 - dient fremder Partei */ + C_CALM, /* 25 - Beinflussung */ + C_OLDRACE, + C_FUMBLE, + C_RIOT, /*region in Aufruhr */ + C_NOCOST, + C_CURSED_BY_THE_GODS, /* struct's vom untertyp curse_unit: */ - C_SPEED, /* Beschleunigt */ - C_ORC, - C_MBOOST, - C_KAELTESCHUTZ, - C_STRENGTH, - C_ALLSKILLS, - C_MAGICRESISTANCE, /* 44 - verändert Magieresistenz */ - C_ITEMCLOAK, - C_SPARKLE, + C_SPEED, /* Beschleunigt */ + C_ORC, + C_MBOOST, + C_KAELTESCHUTZ, + C_STRENGTH, + C_ALLSKILLS, + C_MAGICRESISTANCE, /* 44 - verändert Magieresistenz */ + C_ITEMCLOAK, + C_SPARKLE, /* struct's vom untertyp curse_skill: */ - C_SKILL, - MAXCURSE /* OBS: when removing curses, remember to update read_ccompat() */ -}; + C_SKILL, + MAXCURSE /* OBS: when removing curses, remember to update read_ccompat() */ + }; /* ------------------------------------------------------------- */ /* Flags */ /* Verhalten von Zaubern auf Units beim Übergeben von Personen */ -typedef enum { - CURSE_ISNEW = 0x01, /* wirkt in der zauberrunde nicht (default)*/ - CURSE_NOAGE = 0x02, /* wirkt ewig */ - CURSE_IMMUNE = 0x04, /* ignoriert Antimagie */ - CURSE_ONLYONE = 0x08, /* Verhindert, das ein weiterer Zauber dieser Art auf das Objekt gezaubert wird */ + typedef enum { + CURSE_ISNEW = 0x01, /* wirkt in der zauberrunde nicht (default) */ + CURSE_NOAGE = 0x02, /* wirkt ewig */ + CURSE_IMMUNE = 0x04, /* ignoriert Antimagie */ + CURSE_ONLYONE = 0x08, /* Verhindert, das ein weiterer Zauber dieser Art auf das Objekt gezaubert wird */ - /* the following are mutually exclusive */ - CURSE_SPREADNEVER = 0x00, /* wird nie mit übertragen */ - CURSE_SPREADALWAYS = 0x10, /* wird immer mit übertragen */ - CURSE_SPREADMODULO = 0x20, /* personenweise weitergabe */ - CURSE_SPREADCHANCE = 0x30 /* Ansteckungschance je nach Mengenverhältnis*/ -} curseflags; + /* the following are mutually exclusive */ + CURSE_SPREADNEVER = 0x00, /* wird nie mit übertragen */ + CURSE_SPREADALWAYS = 0x10, /* wird immer mit übertragen */ + CURSE_SPREADMODULO = 0x20, /* personenweise weitergabe */ + CURSE_SPREADCHANCE = 0x30 /* Ansteckungschance je nach Mengenverhältnis */ + } curseflags; #define CURSE_FLAGSMASK 0x0F #define CURSE_SPREADMASK 0x30 /* typ von struct */ -enum { - CURSETYP_NORM, - CURSETYP_UNIT, - CURSETYP_REGION, /* stores the region in c->data.v */ - MAXCURSETYP -}; + enum { + CURSETYP_NORM, + CURSETYP_UNIT, + CURSETYP_REGION, /* stores the region in c->data.v */ + MAXCURSETYP + }; /* Verhalten beim Zusammenfassen mit einem schon bestehenden Zauber * gleichen Typs */ -#define NO_MERGE 0 /* erzeugt jedesmal einen neuen Zauber */ -#define M_DURATION 1 /* Die Zauberdauer ist die maximale Dauer beider */ -#define M_SUMDURATION 2 /* die Dauer des Zaubers wird summiert */ -#define M_MAXEFFECT 4 /* der Effekt ist der maximale Effekt beider */ -#define M_SUMEFFECT 8 /* der Effekt summiert sich */ -#define M_MEN 16 /* die Anzahl der betroffenen Personen summiert - sich */ -#define M_VIGOUR 32 /* das Maximum der beiden Stärken wird die - Stärke des neuen Zaubers */ -#define M_VIGOUR_ADD 64 /* Vigour wird addiert */ +#define NO_MERGE 0 /* erzeugt jedesmal einen neuen Zauber */ +#define M_DURATION 1 /* Die Zauberdauer ist die maximale Dauer beider */ +#define M_SUMDURATION 2 /* die Dauer des Zaubers wird summiert */ +#define M_MAXEFFECT 4 /* der Effekt ist der maximale Effekt beider */ +#define M_SUMEFFECT 8 /* der Effekt summiert sich */ +#define M_MEN 16 /* die Anzahl der betroffenen Personen summiert + sich */ +#define M_VIGOUR 32 /* das Maximum der beiden Stärken wird die + Stärke des neuen Zaubers */ +#define M_VIGOUR_ADD 64 /* Vigour wird addiert */ /* ------------------------------------------------------------- */ /* Allgemeine Zauberwirkungen */ -typedef struct curse { - struct curse *nexthash; - int no; /* 'Einheitennummer' dieses Curse */ - const struct curse_type * type; /* Zeiger auf ein curse_type-struct */ - unsigned int flags; /* WARNING: these are XORed with type->flags! */ - int duration; /* Dauer der Verzauberung. Wird jede Runde vermindert */ - double vigour; /* Stärke der Verzauberung, Widerstand gegen Antimagie */ - struct unit *magician; /* Pointer auf den Magier, der den Spruch gewirkt hat */ - double effect; - variant data; /* pointer auf spezielle curse-unterstructs*/ -} curse; + typedef struct curse { + struct curse *nexthash; + int no; /* 'Einheitennummer' dieses Curse */ + const struct curse_type *type; /* Zeiger auf ein curse_type-struct */ + unsigned int flags; /* WARNING: these are XORed with type->flags! */ + int duration; /* Dauer der Verzauberung. Wird jede Runde vermindert */ + double vigour; /* Stärke der Verzauberung, Widerstand gegen Antimagie */ + struct unit *magician; /* Pointer auf den Magier, der den Spruch gewirkt hat */ + double effect; + variant data; /* pointer auf spezielle curse-unterstructs */ + } curse; #define c_flags(c) ((c)->type->flags ^ (c)->flags) /* ------------------------------------------------------------- */ -typedef struct curse_type { - const char *cname; /* Name der Zauberwirkung, Identifizierung des curse */ - int typ; - unsigned int flags; - unsigned int mergeflags; - struct message * (*curseinfo)(const void*, typ_t, const struct curse*, int); - void (*change_vigour)(curse*, double); - int (*read)(struct storage * store, curse * c, void * target); - int (*write)(struct storage * store, const struct curse * c, const void * target); - int (*cansee)(const struct faction*, const void*, typ_t, const struct curse *, int); - int (*age)(curse *); -} curse_type; + typedef struct curse_type { + const char *cname; /* Name der Zauberwirkung, Identifizierung des curse */ + int typ; + unsigned int flags; + unsigned int mergeflags; + struct message *(*curseinfo) (const void *, typ_t, const struct curse *, + int); + void (*change_vigour) (curse *, double); + int (*read) (struct storage * store, curse * c, void *target); + int (*write) (struct storage * store, const struct curse * c, + const void *target); + int (*cansee) (const struct faction *, const void *, typ_t, + const struct curse *, int); + int (*age) (curse *); + } curse_type; -extern struct attrib_type at_curse; -void curse_write(const struct attrib * a, const void * owner, struct storage * store); -int curse_read(struct attrib * a, void * owner, struct storage * store); + extern struct attrib_type at_curse; + void curse_write(const struct attrib *a, const void *owner, + struct storage *store); + int curse_read(struct attrib *a, void *owner, struct storage *store); /* ------------------------------------------------------------- */ @@ -234,26 +238,27 @@ int curse_read(struct attrib * a, void * owner, struct storage * store); * allgemeine Funktionen * */ -curse * create_curse(struct unit *magician, struct attrib**ap, const curse_type * ctype, - double vigour, int duration, double ceffect, int men); + curse *create_curse(struct unit *magician, struct attrib **ap, + const curse_type * ctype, double vigour, int duration, double ceffect, + int men); /* Verzweigt automatisch zum passenden struct-typ. Sollte es schon * einen Zauber dieses Typs geben, so wird der neue dazuaddiert. Die * Zahl der verzauberten Personen sollte beim Aufruf der Funktion * nochmal gesondert auf min(get_cursedmen, u->number) gesetzt werden. */ -extern void destroy_curse(curse * c); + extern void destroy_curse(curse * c); -boolean is_cursed_internal(struct attrib *ap, const curse_type * ctype); + boolean is_cursed_internal(struct attrib *ap, const curse_type * ctype); /* ignoriert CURSE_ISNEW */ -extern void remove_curse(struct attrib **ap, const struct curse * c); + extern void remove_curse(struct attrib **ap, const struct curse *c); /* löscht einen konkreten Spruch auf einem Objekt. */ -extern int curse_geteffect_int(const struct curse * c); -extern double curse_geteffect(const struct curse * c); + extern int curse_geteffect_int(const struct curse *c); + extern double curse_geteffect(const struct curse *c); /* gibt die Auswirkungen der Verzauberungen zurück. zB bei * Skillmodifiziernden Verzauberungen ist hier der Modifizierer * gespeichert. Wird automatisch beim Anlegen eines neuen curse @@ -261,60 +266,61 @@ extern double curse_geteffect(const struct curse * c); */ -extern double curse_changevigour(struct attrib **ap, curse * c, double i); + extern double curse_changevigour(struct attrib **ap, curse * c, double i); /* verändert die Stärke der Verzauberung um i */ -extern int get_cursedmen(struct unit *u, const struct curse *c); + extern int get_cursedmen(struct unit *u, const struct curse *c); /* gibt bei Personenbeschränkten Verzauberungen die Anzahl der * betroffenen Personen zurück. Ansonsten wird 0 zurückgegeben. */ -extern void c_setflag(curse * c, unsigned int flag); -extern void c_clearflag(curse *c, unsigned int flags); + extern void c_setflag(curse * c, unsigned int flag); + extern void c_clearflag(curse * c, unsigned int flags); /* setzt/loescht Spezialflag einer Verzauberung (zB 'dauert ewig') */ -void transfer_curse(struct unit * u, struct unit * u2, int n); + void transfer_curse(struct unit *u, struct unit *u2, int n); /* sorgt dafür, das bei der Übergabe von Personen die curse-attribute * korrekt gehandhabt werden. Je nach internen Flag kann dies * unterschiedlich gewünscht sein * */ -extern struct curse * get_cursex(struct attrib *ap, const curse_type * ctype, variant data, - boolean(*compare)(const struct curse *, variant)); + extern struct curse *get_cursex(struct attrib *ap, const curse_type * ctype, + variant data, boolean(*compare) (const struct curse *, variant)); /* gibt pointer auf die erste curse-struct zurück, deren Typ ctype ist, * und für die compare() true liefert, oder einen NULL-pointer. * */ -extern struct curse * get_curse(struct attrib *ap, const curse_type * ctype); + extern struct curse *get_curse(struct attrib *ap, const curse_type * ctype); /* gibt pointer auf die erste curse-struct zurück, deren Typ ctype ist, * oder einen NULL-pointer * */ -int find_cursebyname(const char *c); -const curse_type * ct_find(const char *c); -void ct_register(const curse_type *); + int find_cursebyname(const char *c); + const curse_type *ct_find(const char *c); + void ct_register(const curse_type *); /* Regionszauber */ -curse * cfindhash(int i); + curse *cfindhash(int i); -curse * findcurse(int curseid); + curse *findcurse(int curseid); -extern void curse_init(struct attrib * a); -extern void curse_done(struct attrib * a); -extern int curse_age(struct attrib * a); + extern void curse_init(struct attrib *a); + extern void curse_done(struct attrib *a); + extern int curse_age(struct attrib *a); -extern boolean cmp_curse(const struct attrib * a, const void * data); -extern boolean cmp_cursetype(const struct attrib * a, const void * data); + extern boolean cmp_curse(const struct attrib *a, const void *data); + extern boolean cmp_cursetype(const struct attrib *a, const void *data); -extern double destr_curse(struct curse* c, int cast_level, double force); + extern double destr_curse(struct curse *c, int cast_level, double force); -extern int resolve_curse(variant data, void * address); -extern boolean is_cursed_with(const struct attrib *ap, const struct curse *c); + extern int resolve_curse(variant data, void *address); + extern boolean is_cursed_with(const struct attrib *ap, const struct curse *c); -extern boolean curse_active(const struct curse * c); + extern boolean curse_active(const struct curse *c); /* gibt true, wenn der Curse nicht NULL oder inaktiv ist */ /*** COMPATIBILITY MACROS. DO NOT USE FOR NEW CODE, REPLACE IN OLD CODE: */ -extern const char * oldcursename(int id); -extern struct message * cinfo_simple(const void * obj, typ_t typ, const struct curse *c, int self); + extern const char *oldcursename(int id); + extern struct message *cinfo_simple(const void *obj, typ_t typ, + const struct curse *c, int self); #define is_cursed(a, id, id2) \ curse_active(get_curse(a, ct_find(oldcursename(id)))) diff --git a/src/kernel/curse_test.c b/src/kernel/curse_test.c index 0445995bc..131ef05c4 100644 --- a/src/kernel/curse_test.c +++ b/src/kernel/curse_test.c @@ -1,8 +1,11 @@ #include -static void test_curse(CuTest * tc) { - attrib * attrs = NULL; - curse * c, * result; +static void test_curse(CuTest * tc) +{ + attrib *attrs = NULL; + + curse *c, *result; + int cid; curse_type ct_dummy = { "dummy", CURSETYP_NORM, 0, M_SUMEFFECT, NULL }; @@ -15,9 +18,10 @@ static void test_curse(CuTest * tc) { CuAssertPtrEquals(tc, NULL, result); } -CuSuite* get_curse_suite(void) +CuSuite *get_curse_suite(void) { - CuSuite* suite = CuSuiteNew(); + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_curse); return suite; } diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index 34e80a33a..8215eb75e 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -34,16 +34,18 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -static equipment * equipment_sets; +static equipment *equipment_sets; -equipment * -create_equipment(const char * eqname) +equipment *create_equipment(const char *eqname) { - equipment ** eqp = &equipment_sets; + equipment **eqp = &equipment_sets; + for (;;) { - struct equipment * eq = *eqp; - int i = eq?strcmp(eq->name, eqname):1; - if (i>0) { + struct equipment *eq = *eqp; + + int i = eq ? strcmp(eq->name, eqname) : 1; + + if (i > 0) { eq = malloc(sizeof(equipment)); eq->name = strdup(eqname); eq->next = *eqp; @@ -54,7 +56,7 @@ create_equipment(const char * eqname) memset(eq->skills, 0, sizeof(eq->skills)); *eqp = eq; break; - } else if (i==0) { + } else if (i == 0) { break; } eqp = &eq->next; @@ -62,23 +64,25 @@ create_equipment(const char * eqname) return *eqp; } -equipment * -get_equipment(const char * eqname) +equipment *get_equipment(const char *eqname) { - equipment * eq = equipment_sets; - for (;eq;eq=eq->next) { + 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; + + if (i == 0) + return eq; + else if (i > 0) + break; } return NULL; } -void -equipment_setskill(equipment * eq, skill_t sk, const char * value) +void equipment_setskill(equipment * eq, skill_t sk, const char *value) { - if (eq!=NULL) { - if (value!=NULL) { + if (eq != NULL) { + if (value != NULL) { eq->skills[sk] = strdup(value); } else if (eq->skills[sk]) { free(eq->skills[sk]); @@ -86,25 +90,25 @@ equipment_setskill(equipment * eq, skill_t sk, const char * value) } } -void -equipment_addspell(equipment * eq, spell * sp) +void equipment_addspell(equipment * eq, spell * sp) { - if (eq!=NULL) { + if (eq != NULL) { ql_set_insert(&eq->spells, sp); } } -void -equipment_setitem(equipment * eq, const item_type * itype, const char * value) +void +equipment_setitem(equipment * eq, const item_type * itype, const char *value) { - if (eq!=NULL) { - if (itype!=NULL) { - itemdata * idata = eq->items; - while (idata &&idata->itype!=itype) { + if (eq != NULL) { + if (itype != NULL) { + itemdata *idata = eq->items; + + while (idata && idata->itype != itype) { idata = idata->next; } - if (idata==NULL) { - idata = (itemdata *)malloc(sizeof(itemdata)); + if (idata == NULL) { + idata = (itemdata *) malloc(sizeof(itemdata)); idata->itype = itype; idata->value = strdup(value); idata->next = eq->items; @@ -115,53 +119,61 @@ equipment_setitem(equipment * eq, const item_type * itype, const char * value) } void -equipment_setcallback(struct equipment * eq, void (*callback)(const struct equipment *, struct unit *)) +equipment_setcallback(struct equipment *eq, + void (*callback) (const struct equipment *, struct unit *)) { eq->callback = callback; } -void -equip_unit(struct unit * u, const struct equipment * eq) +void equip_unit(struct unit *u, const struct equipment *eq) { equip_unit_mask(u, eq, EQUIP_ALL); } -void -equip_unit_mask(struct unit * u, const struct equipment * eq, int mask) +void equip_unit_mask(struct unit *u, const struct equipment *eq, int mask) { if (eq) { - if (mask&EQUIP_SKILLS) { + if (mask & EQUIP_SKILLS) { skill_t sk; - for (sk=0;sk!=MAXSKILLS;++sk) { - if (eq->skills[sk]!=NULL) { + + for (sk = 0; sk != MAXSKILLS; ++sk) { + if (eq->skills[sk] != NULL) { int i = dice_rand(eq->skills[sk]); - if (i>0) set_level(u, sk, i); + + if (i > 0) + set_level(u, sk, i); } } } - if (mask&EQUIP_SPELLS) { - quicklist * ql = eq->spells; + if (mask & EQUIP_SPELLS) { + quicklist *ql = eq->spells; + if (ql) { - sc_mage * m = get_mage(u); - if (m==NULL) { + sc_mage *m = get_mage(u); + + if (m == NULL) { assert(!"trying to equip spells on a non-mage!"); } else { int qi; - for (qi=0;ql;ql_advance(&ql, &qi, 1)) { - spell * sp = (spell *)ql_get(ql, qi); + + for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { + spell *sp = (spell *) ql_get(ql, qi); + add_spell(get_spelllist(m, u->faction), sp); } } } } - if (mask&EQUIP_ITEMS) { - itemdata * idata; - for (idata=eq->items;idata!=NULL;idata=idata->next) { + if (mask & EQUIP_ITEMS) { + itemdata *idata; + + for (idata = eq->items; idata != NULL; idata = idata->next) { int i = u->number * dice_rand(idata->value); - if (i>0) { + + if (i > 0) { i_add(&u->items, i_new(idata->itype, i)); } } @@ -169,12 +181,15 @@ equip_unit_mask(struct unit * u, const struct equipment * eq, int mask) if (eq->subsets) { int i; - for (i=0;eq->subsets[i].sets;++i) { + + for (i = 0; eq->subsets[i].sets; ++i) { if (chance(eq->subsets[i].chance)) { - float rnd = (1+rng_int() % 1000) / 1000.0f; + float rnd = (1 + rng_int() % 1000) / 1000.0f; + int k; - for (k=0;eq->subsets[i].sets[k].set;++k) { - if (rnd<=eq->subsets[i].sets[k].chance) { + + for (k = 0; eq->subsets[i].sets[k].set; ++k) { + if (rnd <= eq->subsets[i].sets[k].chance) { equip_unit_mask(u, eq->subsets[i].sets[k].set, mask); break; } @@ -184,32 +199,36 @@ equip_unit_mask(struct unit * u, const struct equipment * eq, int mask) } } - if (mask&EQUIP_SPECIAL) { - if (eq->callback) eq->callback(eq, u); + if (mask & EQUIP_SPECIAL) { + if (eq->callback) + eq->callback(eq, u); } } } -void -equip_items(struct item ** items, const struct equipment * eq) +void equip_items(struct item **items, const struct equipment *eq) { if (eq) { - itemdata * idata; + itemdata *idata; - for (idata=eq->items;idata!=NULL;idata=idata->next) { + for (idata = eq->items; idata != NULL; idata = idata->next) { int i = dice_rand(idata->value); - if (i>0) { + + if (i > 0) { i_add(items, i_new(idata->itype, i)); } } if (eq->subsets) { int i; - for (i=0;eq->subsets[i].sets;++i) { + + for (i = 0; eq->subsets[i].sets; ++i) { if (chance(eq->subsets[i].chance)) { - float rnd = (1+rng_int() % 1000) / 1000.0f; + float rnd = (1 + rng_int() % 1000) / 1000.0f; + int k; - for (k=0;eq->subsets[i].sets[k].set;++k) { - if (rnd<=eq->subsets[i].sets[k].chance) { + + for (k = 0; eq->subsets[i].sets[k].set; ++k) { + if (rnd <= eq->subsets[i].sets[k].chance) { equip_items(items, eq->subsets[i].sets[k].set); break; } diff --git a/src/kernel/equipment.h b/src/kernel/equipment.h index a0989c7eb..a483fdcf8 100644 --- a/src/kernel/equipment.h +++ b/src/kernel/equipment.h @@ -24,48 +24,52 @@ extern "C" { struct spell; typedef struct itemdata { - const struct item_type * itype; - char * value; - struct itemdata * next; + const struct item_type *itype; + char *value; + struct itemdata *next; } itemdata; typedef struct subsetitem { - struct equipment * set; + struct equipment *set; float chance; } subsetitem; typedef struct subset { float chance; - subsetitem * sets; + subsetitem *sets; } subset; typedef struct equipment { - char * name; - struct itemdata * items; - char * skills[MAXSKILLS]; - struct quicklist * spells; - struct subset * subsets; - struct equipment * next; - void (*callback)(const struct equipment *, struct unit *); + char *name; + struct itemdata *items; + char *skills[MAXSKILLS]; + struct quicklist *spells; + struct subset *subsets; + struct equipment *next; + void (*callback) (const struct equipment *, struct unit *); } equipment; - extern struct equipment * create_equipment(const char * eqname); - extern struct equipment * get_equipment(const char * eqname); + extern struct equipment *create_equipment(const char *eqname); + extern struct equipment *get_equipment(const char *eqname); - extern void equipment_setitem(struct equipment * eq, const struct item_type * itype, const char * value); - extern void equipment_setskill(struct equipment * eq, skill_t sk, const char * value); - extern void equipment_addspell(struct equipment * eq, struct spell * sp); - extern void equipment_setcallback(struct equipment * eq, void (*callback)(const struct equipment *, struct unit *)); + extern void equipment_setitem(struct equipment *eq, + const struct item_type *itype, const char *value); + extern void equipment_setskill(struct equipment *eq, skill_t sk, + const char *value); + extern void equipment_addspell(struct equipment *eq, struct spell *sp); + extern void equipment_setcallback(struct equipment *eq, + void (*callback) (const struct equipment *, struct unit *)); - extern void equip_unit(struct unit * u, const struct equipment * eq); + extern void equip_unit(struct unit *u, const struct equipment *eq); #define EQUIP_SKILLS (1<<1) #define EQUIP_SPELLS (1<<2) #define EQUIP_ITEMS (1<<3) #define EQUIP_SPECIAL (1<<4) #define EQUIP_ALL (0xFF) - extern void equip_unit_mask(struct unit * u, const struct equipment * eq, int mask); - extern void equip_items(struct item ** items, const struct equipment * eq); + extern void equip_unit_mask(struct unit *u, const struct equipment *eq, + int mask); + extern void equip_items(struct item **items, const struct equipment *eq); #ifdef __cplusplus } diff --git a/src/kernel/faction.c b/src/kernel/faction.c index 7216e9338..91c0f9e85 100644 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -62,19 +62,22 @@ faction *factions; * but you should still call funhash and remove the faction from the * global list. */ -void -free_faction (faction * f) +void free_faction(faction * f) { - if (f->msgs) free_messagelist(f->msgs); + if (f->msgs) + free_messagelist(f->msgs); while (f->battles) { - struct bmsg * bm = f->battles; + struct bmsg *bm = f->battles; + f->battles = bm->next; - if (bm->msgs) free_messagelist(bm->msgs); + if (bm->msgs) + free_messagelist(bm->msgs); free(bm); } while (f->groups) { - group * g = f->groups; + group *g = f->groups; + f->groups = g->next; free_group(g); } @@ -87,7 +90,7 @@ free_faction (faction * f) free(f->name); while (f->attribs) { - a_remove (&f->attribs, f->attribs); + a_remove(&f->attribs, f->attribs); } i_freeall(&f->items); @@ -95,22 +98,23 @@ free_faction (faction * f) freelist(f->ursprung); } -faction * -get_monsters(void) +faction *get_monsters(void) { - static faction * monsters; + static faction *monsters; + static int gamecookie = -1; - if (gamecookie!=global.cookie) { + if (gamecookie != global.cookie) { monsters = NULL; gamecookie = global.cookie; } if (!monsters) { - faction * f; - for (f=factions;f;f=f->next) { - if (f->flags&FFL_NPC) { - return monsters=f; + faction *f; + + for (f = factions; f; f = f->next) { + if (f->flags & FFL_NPC) { + return monsters = f; } } if (!monsters) { @@ -118,88 +122,94 @@ get_monsters(void) monsters = findfaction(666); } if (monsters) { - fset(monsters, FFL_NPC|FFL_NOIDLEOUT); + fset(monsters, FFL_NPC | FFL_NOIDLEOUT); } } return monsters; } -const unit * -random_unit_in_faction(const faction *f) +const unit *random_unit_in_faction(const faction * f) { unit *u; + int c = 0, u_nr; - for(u = f->units; u; u=u->next) c++; + for (u = f->units; u; u = u->next) + c++; - u_nr = rng_int()%c; + u_nr = rng_int() % c; c = 0; - for(u = f->units; u; u=u->next) - if(u_nr == c) return u; + for (u = f->units; u; u = u->next) + if (u_nr == c) + return u; /* Hier sollte er nie ankommen */ return NULL; } -const char * -factionname(const faction * f) +const char *factionname(const faction * f) { - typedef char name[OBJECTIDSIZE+1]; + typedef char name[OBJECTIDSIZE + 1]; + static name idbuf[8]; + static int nextbuf = 0; char *ibuf = idbuf[(++nextbuf) % 8]; if (f && f->name) { snprintf(ibuf, sizeof(name), "%s (%s)", f->name, itoa36(f->no)); - ibuf[sizeof(name)-1] = 0; + ibuf[sizeof(name) - 1] = 0; } else { strcpy(ibuf, "Unbekannte Partei (?)"); } return ibuf; } -int -resolve_faction(variant id, void * address) { +int resolve_faction(variant id, void *address) +{ int result = 0; - faction * f = NULL; - if (id.i!=0) { + + faction *f = NULL; + + if (id.i != 0) { f = findfaction(id.i); - if (f==NULL) { + if (f == NULL) { result = -1; } } - *(faction**)address = f; + *(faction **) address = f; return result; } #define MAX_FACTION_ID (36*36*36*36) -static int -unused_faction_id(void) +static int unused_faction_id(void) { - int id = rng_int()%MAX_FACTION_ID; + int id = rng_int() % MAX_FACTION_ID; while (!faction_id_is_unused(id)) { - id++; if(id == MAX_FACTION_ID) id = 0; + id++; + if (id == MAX_FACTION_ID) + id = 0; } return id; } -faction * -addfaction(const char *email, const char * password, - const struct race * frace, const struct locale *loc, - int subscription) +faction *addfaction(const char *email, const char *password, + const struct race * frace, const struct locale * loc, int subscription) { - faction * f = calloc(sizeof(faction), 1); + faction *f = calloc(sizeof(faction), 1); + char buf[128]; assert(frace); - if (set_email(&f->email, email)!=0) { - log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), email)); + if (set_email(&f->email, email) != 0) { + log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), + email)); } f->override = strdup(itoa36(rng_int())); @@ -214,11 +224,14 @@ addfaction(const char *email, const char * password, f->locale = loc; f->subscription = subscription; - f->options = want(O_REPORT) | want(O_ZUGVORLAGE) | want(O_COMPUTER) | want(O_COMPRESS) | want(O_ADRESSEN) | want(O_STATISTICS); + f->options = + want(O_REPORT) | want(O_ZUGVORLAGE) | want(O_COMPUTER) | want(O_COMPRESS) | + want(O_ADRESSEN) | want(O_STATISTICS); f->no = unused_faction_id(); if (rule_region_owners()) { - alliance * al = makealliance(f->no, NULL); + alliance *al = makealliance(f->no, NULL); + setalliance(f, al); } addlist(&factions, f); @@ -230,13 +243,13 @@ addfaction(const char *email, const char * password, return f; } -unit * -addplayer(region *r, faction * f) +unit *addplayer(region * r, faction * f) { unit *u; + char buffer[32]; - assert(f->units==NULL); + assert(f->units == NULL); set_ursprung(f, 0, r->x, r->y); u = createunit(r, f, 1, f->race); equip_items(&u->faction->items, get_equipment("new_faction")); @@ -247,85 +260,95 @@ addplayer(region *r, faction * f) fset(u, UFL_ISNEW); if (f->race == new_race[RC_DAEMON]) { race_t urc; + do { - urc = (race_t)(rng_int() % MAXRACES); - } while (new_race[urc]==NULL || urc == RC_DAEMON || !playerrace(new_race[urc])); + urc = (race_t) (rng_int() % MAXRACES); + } while (new_race[urc] == NULL || urc == RC_DAEMON + || !playerrace(new_race[urc])); u->irace = new_race[urc]; } return u; } -boolean -checkpasswd(const faction * f, const char * passwd, boolean shortp) +boolean checkpasswd(const faction * f, const char *passwd, boolean shortp) { - if (unicode_utf8_strcasecmp(f->passw, passwd)==0) return true; - if (unicode_utf8_strcasecmp(f->override, passwd)==0) return true; + if (unicode_utf8_strcasecmp(f->passw, passwd) == 0) + return true; + if (unicode_utf8_strcasecmp(f->override, passwd) == 0) + return true; return false; } -variant -read_faction_reference(struct storage * store) +variant read_faction_reference(struct storage * store) { variant id; + id.i = store->r_id(store); return id; } -void -write_faction_reference(const faction * f, struct storage * store) +void write_faction_reference(const faction * f, struct storage *store) { - store->w_id(store, f?f->no:0); + store->w_id(store, f ? f->no : 0); } -void -destroyfaction(faction * f) +void destroyfaction(faction * f) { unit *u = f->units; + faction *ff; - if (!f->alive) return; + if (!f->alive) + return; fset(f, FFL_QUIT); ql_free(f->spellbook); f->spellbook = NULL; while (f->battles) { - struct bmsg * bm = f->battles; + struct bmsg *bm = f->battles; + f->battles = bm->next; - if (bm->msgs) free_messagelist(bm->msgs); + if (bm->msgs) + free_messagelist(bm->msgs); free(bm); } while (u) { /* give away your stuff, make zombies if you cannot (quest items) */ - int result = gift_items(u, GIFT_FRIENDS|GIFT_PEASANTS); - if (result!=0) { - unit * zombie = u; + int result = gift_items(u, GIFT_FRIENDS | GIFT_PEASANTS); + + if (result != 0) { + unit *zombie = u; + u = u->nextF; make_zombie(zombie); } else { - region * r = u->region; + region *r = u->region; if (!fval(r->terrain, SEA_REGION) && !!playerrace(u->race)) { - const race * rc = u->race; + const race *rc = u->race; + int m = rmoney(r); - if ((rc->ec_flags & ECF_REC_ETHEREAL)==0) { + if ((rc->ec_flags & ECF_REC_ETHEREAL) == 0) { int p = rpeasants(u->region); + int h = rhorses(u->region); - item * itm; + + item *itm; /* Personen gehen nur an die Bauern, wenn sie auch von dort * stammen */ - if (rc->ec_flags & ECF_REC_HORSES) { /* Zentauren an die Pferde */ + if (rc->ec_flags & ECF_REC_HORSES) { /* Zentauren an die Pferde */ h += u->number; - } else { /* Orks zählen nur zur Hälfte */ + } else { /* Orks zählen nur zur Hälfte */ p += (int)(u->number * rc->recruit_multi); } - for (itm=u->items;itm;itm=itm->next) { - if (itm->type->flags&ITF_ANIMAL) { + for (itm = u->items; itm; itm = itm->next) { + if (itm->type->flags & ITF_ANIMAL) { h += itm->number; } } @@ -336,7 +359,7 @@ destroyfaction(faction * f) rsetmoney(r, m); } set_number(u, 0); - u=u->nextF; + u = u->nextF; } } f->alive = 0; @@ -344,6 +367,7 @@ destroyfaction(faction * f) handle_event(f->attribs, "destroy", f); for (ff = factions; ff; ff = ff->next) { group *g; + ally *sf, *sfn; /* Alle HELFE für die Partei löschen */ @@ -353,7 +377,7 @@ destroyfaction(faction * f) break; } } - for(g=ff->groups; g; g=g->next) { + for (g = ff->groups; g; g = g->next) { for (sf = g->allies; sf;) { sfn = sf->next; if (sf->faction == f) { @@ -368,11 +392,14 @@ destroyfaction(faction * f) /* units of other factions that were disguised as this faction * have their disguise replaced by ordinary faction hiding. */ if (rule_stealth_faction()) { - region * rc; - for (rc=regions; rc; rc=rc->next) { - for(u=rc->units; u; u=u->next) { + region *rc; + + for (rc = regions; rc; rc = rc->next) { + for (u = rc->units; u; u = u->next) { attrib *a = a_find(u->attribs, &at_otherfaction); - if(!a) continue; + + if (!a) + continue; if (get_otherfaction(a) == f) { a_removeall(&u->attribs, &at_otherfaction); fset(u, UFL_ANON_FACTION); @@ -382,30 +409,33 @@ destroyfaction(faction * f) } } -int -get_alliance(const faction * a, const faction * b) +int get_alliance(const faction * a, const faction * b) { - const ally * sf = a->allies; - for (;sf!=NULL;sf=sf->next) { - if (sf->faction==b) { + const ally *sf = a->allies; + + for (; sf != NULL; sf = sf->next) { + if (sf->faction == b) { return sf->status; } } return 0; } -void -set_alliance(faction * a, faction * b, int status) +void set_alliance(faction * a, faction * b, int status) { - ally ** sfp; + ally **sfp; + sfp = &a->allies; while (*sfp) { - ally * sf = *sfp; - if (sf->faction==b) break; + ally *sf = *sfp; + + if (sf->faction == b) + break; sfp = &sf->next; } - if (*sfp==NULL) { - ally * sf = *sfp = malloc(sizeof(ally)); + if (*sfp == NULL) { + ally *sf = *sfp = malloc(sizeof(ally)); + sf->next = NULL; sf->status = status; sf->faction = b; @@ -414,12 +444,11 @@ set_alliance(faction * a, faction * b, int status) (*sfp)->status |= status; } -void -renumber_faction(faction * f, int no) +void renumber_faction(faction * f, int no) { if (f->subscription) { sql_print(("UPDATE subscriptions set faction='%s' where id=%u;\n", - itoa36(no), f->subscription)); + itoa36(no), f->subscription)); } funhash(f); f->no = no; @@ -428,80 +457,85 @@ renumber_faction(faction * f, int no) } #ifdef SMART_INTERVALS -void -update_interval(struct faction * f, struct region * r) +void update_interval(struct faction *f, struct region *r) { - if (r==NULL || f==NULL) return; - if (f->first==NULL || f->first->index>r->index) { + if (r == NULL || f == NULL) + return; + if (f->first == NULL || f->first->index > r->index) { f->first = r; } - if (f->last==NULL || f->last->index<=r->index) { + if (f->last == NULL || f->last->index <= r->index) { f->last = r; } } #endif -const char * faction_getname(const faction * self) +const char *faction_getname(const faction * self) { - return self->name?self->name:""; + return self->name ? self->name : ""; } -void faction_setname(faction * self, const char * name) +void faction_setname(faction * self, const char *name) { free(self->name); - if (name) self->name = strdup(name); + if (name) + self->name = strdup(name); } -const char * faction_getemail(const faction * self) +const char *faction_getemail(const faction * self) { - return self->email?self->email:""; + return self->email ? self->email : ""; } -void faction_setemail(faction * self, const char * email) +void faction_setemail(faction * self, const char *email) { free(self->email); - if (email) self->email = strdup(email); + if (email) + self->email = strdup(email); } -const char * faction_getbanner(const faction * self) +const char *faction_getbanner(const faction * self) { - return self->banner?self->banner:""; + return self->banner ? self->banner : ""; } -void faction_setbanner(faction * self, const char * banner) +void faction_setbanner(faction * self, const char *banner) { free(self->banner); - if (banner) self->banner = strdup(banner); + if (banner) + self->banner = strdup(banner); } -void -faction_setpassword(faction * f, const char * passw) +void faction_setpassword(faction * f, const char *passw) { free(f->passw); - if (passw) f->passw = strdup(passw); - else f->passw = strdup(itoa36(rng_int())); + if (passw) + f->passw = strdup(passw); + else + f->passw = strdup(itoa36(rng_int())); } -boolean valid_race(const struct faction * f, const struct race * rc) +boolean valid_race(const struct faction *f, const struct race *rc) { - if (f->race==rc) return true; + if (f->race == rc) + return true; else { - const char * str = get_param(f->race->parameters, "other_race"); - if (str) return (boolean)(rc_find(str)==rc); + const char *str = get_param(f->race->parameters, "other_race"); + + if (str) + return (boolean) (rc_find(str) == rc); return false; } } -const char * -faction_getpassword(const faction * f) +const char *faction_getpassword(const faction * f) { return f->passw; } -struct alliance * -f_get_alliance(const struct faction * f) +struct alliance *f_get_alliance(const struct faction *f) { - if (f->alliance && !(f->alliance->flags&ALF_NON_ALLIED)) { + if (f->alliance && !(f->alliance->flags & ALF_NON_ALLIED)) { return f->alliance; } return NULL; diff --git a/src/kernel/faction.h b/src/kernel/faction.h index fc0b71107..377f4f305 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -22,134 +22,135 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -struct player; -struct alliance; -struct item; -struct seen_region; + struct player; + struct alliance; + struct item; + struct seen_region; /* SMART_INTERVALS: define to speed up finding the interval of regions that a faction is in. defining this speeds up the turn by 30-40% */ #define SMART_INTERVALS /* faction flags */ -#define FFL_NEWID (1<<0) /* Die Partei hat bereits einmal ihre no gewechselt */ +#define FFL_NEWID (1<<0) /* Die Partei hat bereits einmal ihre no gewechselt */ #define FFL_ISNEW (1<<1) #define FFL_RESTART (1<<2) #define FFL_QUIT (1<<3) #define FFL_DEFENDER (1<<10) -#define FFL_SELECT (1<<18) /* ehemals f->dh, u->dh, r->dh, etc... */ -#define FFL_NOAID (1<<21) /* Hilfsflag Kampf */ -#define FFL_MARK (1<<23) /* für markierende algorithmen, die das - * hinterher auch wieder löschen müssen! - * (FFL_SELECT muss man vorher initialisieren, - * FL_MARK hinterher löschen) */ -#define FFL_NOIDLEOUT (1<<24) /* Partei stirbt nicht an NMRs */ -#define FFL_OVERRIDE (1<<27) /* Override-Passwort wurde benutzt */ -#define FFL_DBENTRY (1<<28) /* Partei ist in Datenbank eingetragen */ -#define FFL_NOTIMEOUT (1<<29) /* ignore MaxAge() */ -#define FFL_GM (1<<30) /* eine Partei mit Sonderrechten */ -#define FFL_NPC (1<<31) /* eine Partei mit Monstern */ +#define FFL_SELECT (1<<18) /* ehemals f->dh, u->dh, r->dh, etc... */ +#define FFL_NOAID (1<<21) /* Hilfsflag Kampf */ +#define FFL_MARK (1<<23) /* für markierende algorithmen, die das + * hinterher auch wieder löschen müssen! + * (FFL_SELECT muss man vorher initialisieren, + * FL_MARK hinterher löschen) */ +#define FFL_NOIDLEOUT (1<<24) /* Partei stirbt nicht an NMRs */ +#define FFL_OVERRIDE (1<<27) /* Override-Passwort wurde benutzt */ +#define FFL_DBENTRY (1<<28) /* Partei ist in Datenbank eingetragen */ +#define FFL_NOTIMEOUT (1<<29) /* ignore MaxAge() */ +#define FFL_GM (1<<30) /* eine Partei mit Sonderrechten */ +#define FFL_NPC (1<<31) /* eine Partei mit Monstern */ #define FFL_SAVEMASK (FFL_DEFENDER|FFL_NEWID|FFL_GM|FFL_NPC|FFL_NOTIMEOUT|FFL_DBENTRY|FFL_NOTIMEOUT) -struct faction * get_monsters(void); + struct faction *get_monsters(void); #define is_monsters(f) ((f)->flags&FFL_NPC) -typedef struct faction { - struct faction *next; - struct faction *nexthash; + typedef struct faction { + struct faction *next; + struct faction *nexthash; - struct player *owner; + struct player *owner; #ifdef SMART_INTERVALS - struct region *first; - struct region *last; + struct region *first; + struct region *last; #endif - int no; - int subscription; - unsigned int flags; - char *name; - char *banner; - char *email; - char *passw; - char *override; - int max_spelllevel; - struct quicklist * spellbook; - const struct locale * locale; - int lastorders; - int age; - struct ursprung *ursprung; - const struct race * race; - magic_t magiegebiet; - int newbies; - int num_people; /* Anzahl Personen ohne Monster */ - int num_total; /* Anzahl Personen mit Monstern */ - int options; - int no_units; - struct ally *allies; - struct group *groups; - boolean alive; /* enno: sollte ein flag werden */ - int nregions; - int money; + int no; + int subscription; + unsigned int flags; + char *name; + char *banner; + char *email; + char *passw; + char *override; + int max_spelllevel; + struct quicklist *spellbook; + const struct locale *locale; + int lastorders; + int age; + struct ursprung *ursprung; + const struct race *race; + magic_t magiegebiet; + int newbies; + int num_people; /* Anzahl Personen ohne Monster */ + int num_total; /* Anzahl Personen mit Monstern */ + int options; + int no_units; + struct ally *allies; + struct group *groups; + boolean alive; /* enno: sollte ein flag werden */ + int nregions; + int money; #if SCORE_MODULE - int score; + int score; #endif - struct alliance * alliance; - int alliance_joindate; /* the turn on which the faction joined its current alliance (or left the last one) */ + struct alliance *alliance; + int alliance_joindate; /* the turn on which the faction joined its current alliance (or left the last one) */ #ifdef VICTORY_DELAY - unsigned char victory_delay; + unsigned char victory_delay; #endif - struct unit * units; - struct attrib *attribs; - struct message_list * msgs; - struct bmsg { - struct bmsg * next; - struct region * r; - struct message_list * msgs; - } * battles; - struct item * items; /* items this faction can claim */ - struct seen_region ** seen; - struct quicklist * seen_factions; -} faction; + struct unit *units; + struct attrib *attribs; + struct message_list *msgs; + struct bmsg { + struct bmsg *next; + struct region *r; + struct message_list *msgs; + } *battles; + struct item *items; /* items this faction can claim */ + struct seen_region **seen; + struct quicklist *seen_factions; + } faction; -extern struct faction *factions; + extern struct faction *factions; -extern const struct unit * random_unit_in_faction(const struct faction *f); -extern const char * factionname(const struct faction * f); -extern struct unit * addplayer(struct region *r, faction * f); -extern struct faction * addfaction(const char *email, const char* password, - const struct race * frace, - const struct locale *loc, int subscription); -extern boolean checkpasswd(const faction * f, const char * passwd, boolean shortp); -extern void destroyfaction(faction * f); + extern const struct unit *random_unit_in_faction(const struct faction *f); + extern const char *factionname(const struct faction *f); + extern struct unit *addplayer(struct region *r, faction * f); + extern struct faction *addfaction(const char *email, const char *password, + const struct race *frace, const struct locale *loc, int subscription); + extern boolean checkpasswd(const faction * f, const char *passwd, + boolean shortp); + extern void destroyfaction(faction * f); -extern void set_alliance(struct faction * a, struct faction * b, int status); -extern int get_alliance(const struct faction * a, const struct faction * b); + extern void set_alliance(struct faction *a, struct faction *b, int status); + extern int get_alliance(const struct faction *a, const struct faction *b); -extern struct alliance * f_get_alliance(const struct faction * a); + extern struct alliance *f_get_alliance(const struct faction *a); -extern void write_faction_reference(const struct faction * f, struct storage * store); -extern variant read_faction_reference(struct storage * store); -extern int resolve_faction(variant data, void * addr); + extern void write_faction_reference(const struct faction *f, + struct storage *store); + extern variant read_faction_reference(struct storage *store); + extern int resolve_faction(variant data, void *addr); -extern void renumber_faction(faction * f, int no); -void free_faction(struct faction * f); + extern void renumber_faction(faction * f, int no); + void free_faction(struct faction *f); #ifdef SMART_INTERVALS -extern void update_interval(struct faction * f, struct region * r); + extern void update_interval(struct faction *f, struct region *r); #endif -const char * faction_getbanner(const struct faction * self); -void faction_setbanner(struct faction * self, const char * name); + const char *faction_getbanner(const struct faction *self); + void faction_setbanner(struct faction *self, const char *name); -const char * faction_getname(const struct faction * self); -void faction_setname(struct faction * self, const char * name); + const char *faction_getname(const struct faction *self); + void faction_setname(struct faction *self, const char *name); -const char * faction_getemail(const struct faction * self); -void faction_setemail(struct faction * self, const char * email); + const char *faction_getemail(const struct faction *self); + void faction_setemail(struct faction *self, const char *email); -const char * faction_getpassword(const struct faction * self); -void faction_setpassword(struct faction * self, const char * password); -boolean valid_race(const struct faction * f, const struct race * rc); + const char *faction_getpassword(const struct faction *self); + void faction_setpassword(struct faction *self, const char *password); + boolean valid_race(const struct faction *f, const struct race *rc); #ifdef __cplusplus } diff --git a/src/kernel/group.c b/src/kernel/group.c index 4838e26fc..6fa82dedb 100644 --- a/src/kernel/group.c +++ b/src/kernel/group.c @@ -43,64 +43,71 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #define GMAXHASH 2039 -static group * ghash[GMAXHASH]; +static group *ghash[GMAXHASH]; + static int maxgid; -static group * -new_group(faction * f, const char * name, int gid) +static group *new_group(faction * f, const char *name, int gid) { - group ** gp = &f->groups; - int index = gid % GMAXHASH; - group * g = calloc(sizeof(group), 1); + group **gp = &f->groups; - while (*gp) gp = &(*gp)->next; - *gp = g; + int index = gid % GMAXHASH; - maxgid = MAX(gid, maxgid); - g->name = strdup(name); - g->gid = gid; + group *g = calloc(sizeof(group), 1); - g->nexthash = ghash[index]; - return ghash[index] = g; + while (*gp) + gp = &(*gp)->next; + *gp = g; + + maxgid = MAX(gid, maxgid); + g->name = strdup(name); + g->gid = gid; + + g->nexthash = ghash[index]; + return ghash[index] = g; } -static void -init_group(faction * f, group * g) +static void init_group(faction * f, group * g) { - ally * a, ** an; + ally *a, **an; - an = &g->allies; - for (a=f->allies;a;a=a->next) if (a->faction) { - ally * ga = calloc(sizeof(ally), 1); - *ga = *a; - *an = ga; - an = &ga->next; - } + an = &g->allies; + for (a = f->allies; a; a = a->next) + if (a->faction) { + ally *ga = calloc(sizeof(ally), 1); + + *ga = *a; + *an = ga; + an = &ga->next; + } } -static group * -find_groupbyname(group * g, const char * name) +static group *find_groupbyname(group * g, const char *name) { - while (g && unicode_utf8_strcasecmp(name, g->name)!=0) g = g->next; - return g; + while (g && unicode_utf8_strcasecmp(name, g->name) != 0) + g = g->next; + return g; } -static group * -find_group(int gid) +static group *find_group(int gid) { - int index = gid % GMAXHASH; - group * g = ghash[index]; - while (g && g->gid!=gid) g = g->nexthash; - return g; + int index = gid % GMAXHASH; + + group *g = ghash[index]; + + while (g && g->gid != gid) + g = g->nexthash; + return g; } -static int -read_group(attrib * a, void * owner, struct storage * store) +static int read_group(attrib * a, void *owner, struct storage *store) { - group * g; + group *g; + int gid = store->r_int(store); + a->data.v = g = find_group(gid); - if (g!=0) { + if (g != 0) { g->members++; return AT_READ_OK; } @@ -108,34 +115,32 @@ read_group(attrib * a, void * owner, struct storage * store) } static void -write_group(const attrib * a, const void * owner, struct storage * store) +write_group(const attrib * a, const void *owner, struct storage *store) { - group * g = (group*)a->data.v; + group *g = (group *) a->data.v; + store->w_int(store, g->gid); } -attrib_type -at_group = { /* attribute for units assigned to a group */ - "grp", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - write_group, - read_group, - ATF_UNIQUE -}; +attrib_type at_group = { /* attribute for units assigned to a group */ +"grp", + DEFAULT_INIT, + DEFAULT_FINALIZE, DEFAULT_AGE, write_group, read_group, ATF_UNIQUE}; -void -free_group(group * g) +void free_group(group * g) { int index = g->gid % GMAXHASH; - group ** g_ptr = ghash+index; - while (*g_ptr && (*g_ptr)->gid!=g->gid) g_ptr = &(*g_ptr)->nexthash; - assert(*g_ptr==g); + + group **g_ptr = ghash + index; + + while (*g_ptr && (*g_ptr)->gid != g->gid) + g_ptr = &(*g_ptr)->nexthash; + assert(*g_ptr == g); *g_ptr = g->nexthash; while (g->allies) { - ally * a = g->allies; + ally *a = g->allies; + g->allies = a->next; free(a); } @@ -143,18 +148,19 @@ free_group(group * g) free(g); } -void -set_group(struct unit * u, struct group * g) +void set_group(struct unit *u, struct group *g) { - attrib * a = NULL; + attrib *a = NULL; if (fval(u, UFL_GROUP)) { a = a_find(u->attribs, &at_group); } if (a) { - group * og = (group *)a->data.v; - if (og==g) return; + group *og = (group *) a->data.v; + + if (og == g) + return; --og->members; } @@ -171,14 +177,13 @@ set_group(struct unit * u, struct group * g) } } -boolean -join_group(unit * u, const char * name) +boolean join_group(unit * u, const char *name) { - group * g = NULL; + group *g = NULL; if (name && name[0]) { g = find_groupbyname(u->faction->groups, name); - if (g==NULL) { + if (g == NULL) { g = new_group(u->faction, name, ++maxgid); init_group(u->faction, g); } @@ -188,14 +193,14 @@ join_group(unit * u, const char * name) return true; } -void -write_groups(struct storage * store, group * g) +void write_groups(struct storage *store, group * g) { while (g) { - ally * a; + ally *a; + store->w_int(store, g->gid); store->w_str(store, g->name); - for (a=g->allies;a;a=a->next) { + for (a = g->allies; a; a = a->next) { if (a->faction) { write_faction_reference(a->faction, store); store->w_int(store, a->status); @@ -204,38 +209,46 @@ write_groups(struct storage * store, group * g) store->w_id(store, 0); a_write(store, g->attribs, g); store->w_brk(store); - g=g->next; + g = g->next; } store->w_int(store, 0); } -void -read_groups(struct storage * store, faction * f) +void read_groups(struct storage *store, faction * f) { - for(;;) { - ally ** pa; - group * g; + for (;;) { + ally **pa; + + group *g; + int gid; + char buf[1024]; gid = store->r_int(store); - if (gid==0) break; + if (gid == 0) + break; store->r_str_buf(store, buf, sizeof(buf)); g = new_group(f, buf, gid); pa = &g->allies; for (;;) { - ally * a; + ally *a; + variant fid; + fid.i = store->r_id(store); - if (fid.i<=0) break; - if (store->versionversion < STORAGE_VERSION && fid.i == 0) + break; a = malloc(sizeof(ally)); *pa = a; pa = &a->next; a->status = store->r_int(store); a->faction = findfaction(fid.i); - if (!a->faction) ur_add(fid, &a->faction, resolve_faction); + if (!a->faction) + ur_add(fid, &a->faction, resolve_faction); } *pa = 0; a_read(store, &g->attribs, g); diff --git a/src/kernel/group.h b/src/kernel/group.h index 63f8c0ba8..bccbf4540 100644 --- a/src/kernel/group.h +++ b/src/kernel/group.h @@ -23,27 +23,27 @@ extern "C" { #endif /* bitfield value for group::flags */ -#define GFL_ALIVE 0x01 /* There is at least one struct unit in the group */ +#define GFL_ALIVE 0x01 /* There is at least one struct unit in the group */ -typedef struct group { - struct group * next; - struct group * nexthash; - struct faction * f; - struct attrib *attribs; - char * name; - struct ally * allies; - int flags; - int gid; - int members; -} group; + typedef struct group { + struct group *next; + struct group *nexthash; + struct faction *f; + struct attrib *attribs; + char *name; + struct ally *allies; + int flags; + int gid; + int members; + } group; -extern struct attrib_type at_group; /* attribute for units assigned to a group */ -extern boolean join_group(struct unit * u, const char * name); -extern void set_group(struct unit * u, struct group * g); -extern void free_group(struct group * g); + extern struct attrib_type at_group; /* attribute for units assigned to a group */ + extern boolean join_group(struct unit *u, const char *name); + extern void set_group(struct unit *u, struct group *g); + extern void free_group(struct group *g); -extern void write_groups(struct storage * F, struct group * g); -extern void read_groups(struct storage * F, struct faction * f); + extern void write_groups(struct storage *F, struct group *g); + extern void read_groups(struct storage *F, struct faction *f); #ifdef __cplusplus } diff --git a/src/kernel/item.c b/src/kernel/item.c index 7886d88c8..ceade10d4 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -55,87 +55,94 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -resource_type * resourcetypes; -luxury_type * luxurytypes; -potion_type * potiontypes; +resource_type *resourcetypes; + +luxury_type *luxurytypes; + +potion_type *potiontypes; #define IMAXHASH 127 -static item_type * itemtypes[IMAXHASH]; +static item_type *itemtypes[IMAXHASH]; -static int -res_changeaura(unit * u, const resource_type * rtype, int delta) +static int res_changeaura(unit * u, const resource_type * rtype, int delta) { - assert(rtype!=NULL); + assert(rtype != NULL); change_spellpoints(u, delta); return 0; } -static int -res_changeperson(unit * u, const resource_type * rtype, int delta) +static int res_changeperson(unit * u, const resource_type * rtype, int delta) { - assert(rtype!=NULL || !"not implemented"); - scale_number(u, u->number+delta); + assert(rtype != NULL || !"not implemented"); + scale_number(u, u->number + delta); return 0; } -static int -res_changepermaura(unit * u, const resource_type * rtype, int delta) +static int res_changepermaura(unit * u, const resource_type * rtype, int delta) { - assert(rtype!=NULL); + assert(rtype != NULL); change_maxspellpoints(u, delta); return 0; } -static int -res_changehp(unit * u, const resource_type * rtype, int delta) +static int res_changehp(unit * u, const resource_type * rtype, int delta) { - assert(rtype!=NULL); - u->hp+=delta; + assert(rtype != NULL); + u->hp += delta; return 0; } -static int -res_changepeasants(unit * u, const resource_type * rtype, int delta) +static int res_changepeasants(unit * u, const resource_type * rtype, int delta) { - assert(rtype!=NULL && u->region->land); - u->region->land->peasants+=delta; + assert(rtype != NULL && u->region->land); + u->region->land->peasants += delta; return 0; } -int -res_changeitem(unit * u, const resource_type * rtype, int delta) +int res_changeitem(unit * u, const resource_type * rtype, int delta) { int num; - if (rtype == oldresourcetype[R_STONE] && u->race==new_race[RC_STONEGOLEM] && delta<=0) { + + if (rtype == oldresourcetype[R_STONE] && u->race == new_race[RC_STONEGOLEM] + && delta <= 0) { int reduce = delta / GOLEM_STONE; - if (delta % GOLEM_STONE != 0) --reduce; - scale_number(u, u->number+reduce); + + if (delta % GOLEM_STONE != 0) + --reduce; + scale_number(u, u->number + reduce); num = u->number; - } else if (rtype == oldresourcetype[R_IRON] && u->race==new_race[RC_IRONGOLEM] && delta<=0) { + } else if (rtype == oldresourcetype[R_IRON] + && u->race == new_race[RC_IRONGOLEM] && delta <= 0) { int reduce = delta / GOLEM_IRON; - if (delta % GOLEM_IRON != 0) --reduce; - scale_number(u, u->number+reduce); + + if (delta % GOLEM_IRON != 0) + --reduce; + scale_number(u, u->number + reduce); num = u->number; } else { - const item_type * itype = resource2item(rtype); - item * i; - assert(itype!=NULL); + const item_type *itype = resource2item(rtype); + + item *i; + + assert(itype != NULL); i = i_change(&u->items, itype, delta); - if (i==NULL) return 0; + if (i == NULL) + return 0; num = i->number; } return num; } -const char * -resourcename(const resource_type * rtype, int flags) +const char *resourcename(const resource_type * rtype, int flags) { int i = 0; if (rtype) { - if (rtype->name) return rtype->name(rtype, flags); + if (rtype->name) + return rtype->name(rtype, flags); - if (flags & NMF_PLURAL) i = 1; + if (flags & NMF_PLURAL) + i = 1; if (flags & NMF_APPEARANCE && rtype->_appearance[i]) { return rtype->_appearance[i]; } @@ -144,19 +151,22 @@ resourcename(const resource_type * rtype, int flags) return "none"; } -resource_type * -new_resourcetype(const char ** names, const char ** appearances, int flags) +resource_type *new_resourcetype(const char **names, const char **appearances, + int flags) { - resource_type * rtype = rt_find(names[0]); + resource_type *rtype = rt_find(names[0]); - if (rtype==NULL) { + if (rtype == NULL) { int i; + rtype = calloc(sizeof(resource_type), 1); - for (i=0; i!=2; ++i) { + for (i = 0; i != 2; ++i) { rtype->_name[i] = strdup(names[i]); - if (appearances) rtype->_appearance[i] = strdup(appearances[i]); - else rtype->_appearance[i] = NULL; + if (appearances) + rtype->_appearance[i] = strdup(appearances[i]); + else + rtype->_appearance[i] = NULL; } rt_register(rtype); } @@ -169,25 +179,28 @@ new_resourcetype(const char ** names, const char ** appearances, int flags) return rtype; } -void -it_register(item_type * itype) +void it_register(item_type * itype) { int hash = hashstring(itype->rtype->_name[0]); + int key = hash % IMAXHASH; - item_type ** p_itype = &itemtypes[key]; - while (*p_itype && *p_itype != itype) p_itype = &(*p_itype)->next; - if (*p_itype==NULL) { + + item_type **p_itype = &itemtypes[key]; + + while (*p_itype && *p_itype != itype) + p_itype = &(*p_itype)->next; + if (*p_itype == NULL) { itype->rtype->itype = itype; *p_itype = itype; rt_register(itype->rtype); } } -item_type * -new_itemtype(resource_type * rtype, - int iflags, int weight, int capacity) +item_type *new_itemtype(resource_type * rtype, + int iflags, int weight, int capacity) { - item_type * itype; + item_type *itype; + assert(resource2item(rtype) == NULL); assert(rtype->flags & RTF_ITEM); @@ -204,18 +217,16 @@ new_itemtype(resource_type * rtype, return itype; } -static void -lt_register(luxury_type * ltype) +static void lt_register(luxury_type * ltype) { ltype->itype->rtype->ltype = ltype; ltype->next = luxurytypes; luxurytypes = ltype; } -luxury_type * -new_luxurytype(item_type * itype, int price) +luxury_type *new_luxurytype(item_type * itype, int price) { - luxury_type * ltype; + luxury_type *ltype; assert(resource2luxury(itype->rtype) == NULL); @@ -227,13 +238,13 @@ new_luxurytype(item_type * itype, int price) return ltype; } -weapon_type * -new_weapontype(item_type * itype, - int wflags, double magres, const char* damage[], int offmod, int defmod, int reload, skill_t sk, int minskill) +weapon_type *new_weapontype(item_type * itype, + int wflags, double magres, const char *damage[], int offmod, int defmod, + int reload, skill_t sk, int minskill) { - weapon_type * wtype; + weapon_type *wtype; - assert(resource2weapon(itype->rtype)==NULL); + assert(resource2weapon(itype->rtype) == NULL); wtype = calloc(sizeof(weapon_type), 1); if (damage) { @@ -254,12 +265,12 @@ new_weapontype(item_type * itype, } -armor_type * -new_armortype(item_type * itype, double penalty, double magres, int prot, unsigned int flags) +armor_type *new_armortype(item_type * itype, double penalty, double magres, + int prot, unsigned int flags) { - armor_type * atype; + armor_type *atype; - assert(itype->rtype->atype==NULL); + assert(itype->rtype->atype == NULL); atype = calloc(sizeof(armor_type), 1); @@ -273,21 +284,18 @@ new_armortype(item_type * itype, double penalty, double magres, int prot, unsign return atype; } -static void -pt_register(potion_type * ptype) +static void pt_register(potion_type * ptype) { ptype->itype->rtype->ptype = ptype; ptype->next = potiontypes; potiontypes = ptype; } -potion_type * -new_potiontype(item_type * itype, - int level) +potion_type *new_potiontype(item_type * itype, int level) { - potion_type * ptype; + potion_type *ptype; - assert(resource2potion(itype->rtype)==NULL); + assert(resource2potion(itype->rtype) == NULL); ptype = calloc(sizeof(potion_type), 1); ptype->itype = itype; @@ -298,155 +306,161 @@ new_potiontype(item_type * itype, } -void -rt_register(resource_type * rtype) +void rt_register(resource_type * rtype) { - resource_type ** prtype = &resourcetypes; + resource_type **prtype = &resourcetypes; if (!rtype->hashkey) { rtype->hashkey = hashstring(rtype->_name[0]); } - while (*prtype && *prtype!=rtype) prtype=&(*prtype)->next; + while (*prtype && *prtype != rtype) + prtype = &(*prtype)->next; if (*prtype == NULL) { *prtype = rtype; } } -const resource_type * -item2resource(const item_type * itype) +const resource_type *item2resource(const item_type * itype) { - return itype?itype->rtype:NULL; + return itype ? itype->rtype : NULL; } -const item_type * -resource2item(const resource_type * rtype) +const item_type *resource2item(const resource_type * rtype) { - return rtype?rtype->itype:NULL; + return rtype ? rtype->itype : NULL; } -const weapon_type * -resource2weapon(const resource_type * rtype) { +const weapon_type *resource2weapon(const resource_type * rtype) +{ return rtype->wtype; } -const luxury_type * -resource2luxury(const resource_type * rtype) +const luxury_type *resource2luxury(const resource_type * rtype) { #ifdef AT_LTYPE - attrib * a = a_find(rtype->attribs, &at_ltype); - if (a) return (const luxury_type *)a->data.v; + attrib *a = a_find(rtype->attribs, &at_ltype); + + if (a) + return (const luxury_type *)a->data.v; return NULL; #else return rtype->ltype; #endif } -const potion_type * -resource2potion(const resource_type * rtype) +const potion_type *resource2potion(const resource_type * rtype) { #ifdef AT_PTYPE - attrib * a = a_find(rtype->attribs, &at_ptype); - if (a) return (const potion_type *)a->data.v; + attrib *a = a_find(rtype->attribs, &at_ptype); + + if (a) + return (const potion_type *)a->data.v; return NULL; #else return rtype->ptype; #endif } -resource_type * -rt_find(const char * name) +resource_type *rt_find(const char *name) { unsigned int hash = hashstring(name); - resource_type * rtype; - for (rtype=resourcetypes; rtype; rtype=rtype->next) { - if (rtype->hashkey==hash && !strcmp(rtype->_name[0], name)) break; + resource_type *rtype; + + for (rtype = resourcetypes; rtype; rtype = rtype->next) { + if (rtype->hashkey == hash && !strcmp(rtype->_name[0], name)) + break; } return rtype; } -static const char * it_aliases[][2] = { - { "Runenschwert", "runesword" }, - { "p12", "truthpotion" }, - { "p1", "goliathwater" }, - { "p4", "ointment" }, - { "p5", "peasantblood" }, - { "p8", "nestwarmth" }, - { "diamond", "adamantium" }, - { "diamondaxe", "adamantiumaxe" }, - { "diamondplate", "adamantiumplate" }, - { "aoh", "ao_healing" }, - { NULL, NULL }, +static const char *it_aliases[][2] = { + {"Runenschwert", "runesword"}, + {"p12", "truthpotion"}, + {"p1", "goliathwater"}, + {"p4", "ointment"}, + {"p5", "peasantblood"}, + {"p8", "nestwarmth"}, + {"diamond", "adamantium"}, + {"diamondaxe", "adamantiumaxe"}, + {"diamondplate", "adamantiumplate"}, + {"aoh", "ao_healing"}, + {NULL, NULL}, }; -static const char * -it_alias(const char * zname) +static const char *it_alias(const char *zname) { int i; - for (i=0;it_aliases[i][0];++i) { - if (strcmp(it_aliases[i][0], zname)==0) return it_aliases[i][1]; + + for (i = 0; it_aliases[i][0]; ++i) { + if (strcmp(it_aliases[i][0], zname) == 0) + return it_aliases[i][1]; } return zname; } -item_type * -it_find(const char * zname) +item_type *it_find(const char *zname) { - const char * name = it_alias(zname); + const char *name = it_alias(zname); + unsigned int hash = hashstring(name); - item_type * itype; + + item_type *itype; + unsigned int key = hash % IMAXHASH; - for (itype=itemtypes[key]; itype; itype=itype->next) { - if (itype->rtype->hashkey==hash && strcmp(itype->rtype->_name[0], name) == 0) { + for (itype = itemtypes[key]; itype; itype = itype->next) { + if (itype->rtype->hashkey == hash + && strcmp(itype->rtype->_name[0], name) == 0) { break; } } - if (itype==NULL) { - for (itype=itemtypes[key]; itype; itype=itype->next) { - if (strcmp(itype->rtype->_name[1], name) == 0) break; + if (itype == NULL) { + for (itype = itemtypes[key]; itype; itype = itype->next) { + if (strcmp(itype->rtype->_name[1], name) == 0) + break; } } return itype; } -item ** -i_find(item ** i, const item_type * it) +item **i_find(item ** i, const item_type * it) { - while (*i && (*i)->type!=it) i = &(*i)->next; + while (*i && (*i)->type != it) + i = &(*i)->next; return i; } -item * const * -i_findc(item * const * i, const item_type * it) +item *const *i_findc(item * const *i, const item_type * it) { - while (*i && (*i)->type!=it) { + while (*i && (*i)->type != it) { i = &(*i)->next; } return i; } -int -i_get(const item * i, const item_type * it) +int i_get(const item * i, const item_type * it) { - i = *i_find((item**)&i, it); - if (i) return i->number; + i = *i_find((item **) & i, it); + if (i) + return i->number; return 0; } -item * -i_add(item ** pi, item * i) +item *i_add(item ** pi, item * i) { assert(i && i->type && !i->next); while (*pi) { int d = strcmp((*pi)->type->rtype->_name[0], i->type->rtype->_name[0]); - if (d>=0) break; + + if (d >= 0) + break; pi = &(*pi)->next; } - if (*pi && (*pi)->type==i->type) { + if (*pi && (*pi)->type == i->type) { (*pi)->number += i->number; - assert((*pi)->number>=0); + assert((*pi)->number >= 0); i_free(i); } else { i->next = *pi; @@ -455,55 +469,63 @@ i_add(item ** pi, item * i) return *pi; } -void -i_merge(item ** pi, item ** si) +void i_merge(item ** pi, item ** si) { - item * i = *si; + item *i = *si; + while (i) { - item * itmp; + item *itmp; + while (*pi) { int d = strcmp((*pi)->type->rtype->_name[0], i->type->rtype->_name[0]); - if (d>=0) break; - pi=&(*pi)->next; + + if (d >= 0) + break; + pi = &(*pi)->next; } - if (*pi && (*pi)->type==i->type) { + if (*pi && (*pi)->type == i->type) { (*pi)->number += i->number; - assert((*pi)->number>=0); + assert((*pi)->number >= 0); i_free(i_remove(&i, i)); } else { itmp = i->next; - i->next=*pi; + i->next = *pi; *pi = i; i = itmp; } } - *si=NULL; + *si = NULL; } -item * -i_change(item ** pi, const item_type * itype, int delta) +item *i_change(item ** pi, const item_type * itype, int delta) { assert(itype); while (*pi) { int d = strcmp((*pi)->type->rtype->_name[0], itype->rtype->_name[0]); - if (d>=0) break; - pi=&(*pi)->next; + + if (d >= 0) + break; + pi = &(*pi)->next; } - if (!*pi || (*pi)->type!=itype) { - item * i; - if (delta==0) return NULL; + if (!*pi || (*pi)->type != itype) { + item *i; + + if (delta == 0) + return NULL; i = i_new(itype, delta); i->next = *pi; *pi = i; } else { - item * i = *pi; - i->number+=delta; - if (i->number<0) { - log_error(("serious accounting error. number of items is %d.\n", i->number)); - assert(i>=0); + item *i = *pi; + + i->number += delta; + if (i->number < 0) { + log_error(("serious accounting error. number of items is %d.\n", + i->number)); + assert(i >= 0); i->number = 0; } - if (i->number==0) { + if (i->number == 0) { *pi = i->next; i_free(i); return NULL; @@ -512,25 +534,26 @@ i_change(item ** pi, const item_type * itype, int delta) return *pi; } -item * -i_remove(item ** pi, item * i) +item *i_remove(item ** pi, item * i) { assert(i); - while ((*pi)->type!=i->type) pi = &(*pi)->next; + while ((*pi)->type != i->type) + pi = &(*pi)->next; assert(*pi); *pi = i->next; i->next = NULL; return i; } -static item * icache; +static item *icache; + static int icache_size; + #define ICACHE_MAX 100 -void -i_free(item * i) +void i_free(item * i) { - if (icache_size>=ICACHE_MAX) { + if (icache_size >= ICACHE_MAX) { free(i); } else { i->next = icache; @@ -539,11 +562,11 @@ i_free(item * i) } } -void -i_freeall(item **i) { +void i_freeall(item ** i) +{ item *in; - while(*i) { + while (*i) { in = (*i)->next; i_free(*i); *i = in; @@ -551,11 +574,11 @@ i_freeall(item **i) { } -item * -i_new(const item_type * itype, int size) +item *i_new(const item_type * itype, int size) { - item * i; - if (icache_size>0) { + item *i; + + if (icache_size > 0) { i = icache; icache = i->next; --icache_size; @@ -566,34 +589,44 @@ i_new(const item_type * itype, int size) i->next = NULL; i->type = itype; i->number = size; - assert(i->number>=0); + assert(i->number >= 0); return i; } #include "region.h" static int -give_horses(unit * s, unit * d, const item_type * itype, int n, struct order * ord) +give_horses(unit * s, unit * d, const item_type * itype, int n, + struct order *ord) { - if (d==NULL) { + if (d == NULL) { int use = use_pooled(s, item2resource(itype), GET_SLACK, n); - if (useregion, rhorses(s->region) + use); return 0; } - return -1; /* use the mechanism */ + return -1; /* use the mechanism */ } static int -give_money(unit * s, unit * d, const item_type * itype, int n, struct order * ord) +give_money(unit * s, unit * d, const item_type * itype, int n, + struct order *ord) { - if (d==NULL) { + if (d == NULL) { int use = use_pooled(s, item2resource(itype), GET_SLACK, n); - if (useregion, rmoney(s->region) + use); return 0; } - return -1; /* use the mechanism */ + return -1; /* use the mechanism */ } #define R_MINOTHER R_SILVER @@ -609,49 +642,58 @@ give_money(unit * s, unit * d, const item_type * itype, int n, struct order * or #define LASTLUXURY (I_INCENSE +1) #define MAXLUXURIES (LASTLUXURY - FIRSTLUXURY) -const item_type * olditemtype[MAXITEMS+1]; -const resource_type * oldresourcetype[MAXRESOURCES+1]; -const potion_type * oldpotiontype[MAXPOTIONS+1]; +const item_type *olditemtype[MAXITEMS + 1]; + +const resource_type *oldresourcetype[MAXRESOURCES + 1]; + +const potion_type *oldpotiontype[MAXPOTIONS + 1]; /*** alte items ***/ -int -get_item(const unit * u, item_t it) +int get_item(const unit * u, item_t it) { - const item_type * type = olditemtype[it]; - const item * i = *i_findc(&u->items, type); - if (i) assert(i->number>=0); - return i?i->number:0; + const item_type *type = olditemtype[it]; + + const item *i = *i_findc(&u->items, type); + + if (i) + assert(i->number >= 0); + return i ? i->number : 0; } -int -set_item(unit * u, item_t it, int value) +int set_item(unit * u, item_t it, int value) { - const item_type * type = olditemtype[it]; - item * i = *i_find(&u->items, type); + const item_type *type = olditemtype[it]; + + item *i = *i_find(&u->items, type); + if (!i) { i = i_add(&u->items, i_new(type, value)); } else { i->number = value; - assert(i->number>=0); + assert(i->number >= 0); } return value; } static int -use_birthdayamulet(unit * u, const struct item_type * itype, int amount, struct order * ord) +use_birthdayamulet(unit * u, const struct item_type *itype, int amount, + struct order *ord) { direction_t d; - message * msg = msg_message("meow", ""); + + message *msg = msg_message("meow", ""); unused(ord); unused(amount); unused(itype); add_message(&u->region->msgs, msg); - for(d=0;dregion, d); - if (tr) add_message(&tr->msgs, msg); + for (d = 0; d < MAXDIRECTIONS; d++) { + region *tr = rconnect(u->region, d); + + if (tr) + add_message(&tr->msgs, msg); } msg_release(msg); return 0; @@ -661,7 +703,7 @@ use_birthdayamulet(unit * u, const struct item_type * itype, int amount, struct /* t_item::flags */ #define FL_ITEM_CURSED (1<<0) #define FL_ITEM_NOTLOST (1<<1) -#define FL_ITEM_NOTINBAG (1<<2) /* nicht im Bag Of Holding */ +#define FL_ITEM_NOTINBAG (1<<2) /* nicht im Bag Of Holding */ #define FL_ITEM_ANIMAL (1<<3) /* ist ein Tier */ #define FL_ITEM_MOUNT ((1<<4) | FL_ITEM_ANIMAL) /* ist ein Reittier */ @@ -669,18 +711,22 @@ use_birthdayamulet(unit * u, const struct item_type * itype, int amount, struct /* Kann auch von Nichtmagier benutzt werden, modifiziert Taktik für diese * Runde um -1 - 4 Punkte. */ static int -use_tacticcrystal(unit * u, const struct item_type * itype, int amount, struct order * ord) +use_tacticcrystal(unit * u, const struct item_type *itype, int amount, + struct order *ord) { int i; - for (i=0;i!=amount;++i) { - int duration = 1; /* wirkt nur eine Runde */ - float power = 5; /* Widerstand gegen Antimagiesprüche, ist in diesem - Fall egal, da der curse für den Kampf gelten soll, - der vor den Antimagiezaubern passiert */ - curse * c; + + for (i = 0; i != amount; ++i) { + int duration = 1; /* wirkt nur eine Runde */ + + float power = 5; /* Widerstand gegen Antimagiesprüche, ist in diesem + Fall egal, da der curse für den Kampf gelten soll, + der vor den Antimagiezaubern passiert */ + curse *c; + double effect; - effect = rng_int()%6 - 1; + effect = rng_int() % 6 - 1; c = create_curse(u, &u->attribs, ct_find("skillmod"), power, duration, effect, u->number); c->data.i = SK_TACTICS; @@ -688,24 +734,25 @@ use_tacticcrystal(unit * u, const struct item_type * itype, int amount, struct o } use_pooled(u, itype->rtype, GET_DEFAULT, amount); ADDMSG(&u->faction->msgs, msg_message("use_tacticcrystal", - "unit region", u, u->region)); + "unit region", u, u->region)); return 0; } typedef struct t_item { const char *name; /* [0]: Einzahl für eigene; [1]: Mehrzahl für eigene; - * [2]: Einzahl für Fremde; [3]: Mehrzahl für Fremde */ + * [2]: Einzahl für Fremde; [3]: Mehrzahl für Fremde */ boolean is_resource; skill_t skill; int minskill; int gewicht; int preis; unsigned int flags; - void (*benutze_funktion) (struct region *, struct unit *, int amount, struct order *); + void (*benutze_funktion) (struct region *, struct unit *, int amount, + struct order *); } t_item; -const char * itemnames[MAXITEMS] = { +const char *itemnames[MAXITEMS] = { "iron", "stone", "horse", "ao_healing", "aots", "roi", "rop", "ao_chastity", "laen", "fairyboot", "aoc", "pegasus", @@ -719,7 +766,8 @@ const char * itemnames[MAXITEMS] = { static int mod_elves_only(const unit * u, const region * r, skill_t sk, int value) { - if (u->race == new_race[RC_ELF]) return value; + if (u->race == new_race[RC_ELF]) + return value; unused(r); return -118; } @@ -727,24 +775,27 @@ mod_elves_only(const unit * u, const region * r, skill_t sk, int value) static int mod_dwarves_only(const unit * u, const region * r, skill_t sk, int value) { - if (u->race == new_race[RC_DWARF]) return value; + if (u->race == new_race[RC_DWARF]) + return value; unused(r); return -118; } -static void -init_olditems(void) +static void init_olditems(void) { item_t i; + #if 0 - resource_type * rtype; - const struct locale * lang = find_locale("de"); + resource_type *rtype; + + const struct locale *lang = find_locale("de"); + assert(lang); #endif - for (i=0; i!=MAXITEMS; ++i) { + for (i = 0; i != MAXITEMS; ++i) { /* item is defined in XML file, but IT_XYZ enum still in use */ - const item_type * itype = it_find(itemnames[i]); + const item_type *itype = it_find(itemnames[i]); if (itype) { olditemtype[i] = itype; @@ -753,11 +804,11 @@ init_olditems(void) } } -static int -heal(unit * user, int effect) +static int heal(unit * user, int effect) { int req = unit_max_hp(user) * user->number - user->hp; - if (req>0) { + + if (req > 0) { req = MIN(req, effect); effect -= req; user->hp += req; @@ -765,46 +816,54 @@ heal(unit * user, int effect) return effect; } -void -register_item_give(int (*foo) (struct unit *, struct unit *, const struct item_type *, int, struct order *), const char * name) +void +register_item_give(int (*foo) (struct unit *, struct unit *, + const struct item_type *, int, struct order *), const char *name) { - register_function((pf_generic)foo, name); + register_function((pf_generic) foo, name); } void -register_item_use(int (*foo) (struct unit *, const struct item_type *, int, struct order *), const char * name) +register_item_use(int (*foo) (struct unit *, const struct item_type *, int, + struct order *), const char *name) { - register_function((pf_generic)foo, name); + register_function((pf_generic) foo, name); } void -register_item_useonother(int (*foo) (struct unit *, int, const struct item_type *, int, struct order *), const char * name) +register_item_useonother(int (*foo) (struct unit *, int, + const struct item_type *, int, struct order *), const char *name) { - register_function((pf_generic)foo, name); + register_function((pf_generic) foo, name); } static int -use_healingpotion(struct unit *user, const struct item_type *itype, int amount, struct order * ord) +use_healingpotion(struct unit *user, const struct item_type *itype, int amount, + struct order *ord) { int effect = amount * 400; - unit * u = user->region->units; + + unit *u = user->region->units; + effect = heal(user, effect); - while (effect>0 && u!=NULL) { - if (u->faction==user->faction) { + while (effect > 0 && u != NULL) { + if (u->faction == user->faction) { effect = heal(u, effect); } u = u->next; } - use_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); + use_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, + amount); usetpotionuse(user, itype->rtype->ptype); ADDMSG(&user->faction->msgs, msg_message("usepotion", - "unit potion", user, itype->rtype)); + "unit potion", user, itype->rtype)); return 0; } static int -use_warmthpotion(struct unit *u, const struct item_type *itype, int amount, struct order * ord) +use_warmthpotion(struct unit *u, const struct item_type *itype, int amount, + struct order *ord) { if (u->faction->race == new_race[RC_INSECT]) { fset(u, UFL_WARMTH); @@ -813,28 +872,32 @@ use_warmthpotion(struct unit *u, const struct item_type *itype, int amount, stru cmistake(u, ord, 163, MSG_EVENT); return ECUSTOM; } - use_pooled(u, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); + use_pooled(u, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, + amount); usetpotionuse(u, itype->rtype->ptype); ADDMSG(&u->faction->msgs, msg_message("usepotion", - "unit potion", u, itype->rtype)); + "unit potion", u, itype->rtype)); return 0; } static int -use_foolpotion(struct unit *u, int targetno, const struct item_type *itype, int amount, struct order * ord) +use_foolpotion(struct unit *u, int targetno, const struct item_type *itype, + int amount, struct order *ord) { - unit * target = findunit(targetno); - if (target==NULL || u->region!=target->region) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + unit *target = findunit(targetno); + + if (target == NULL || u->region != target->region) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", + "")); return ECUSTOM; } - if (effskill(u, SK_STEALTH)<=effskill(target, SK_PERCEPTION)) { + if (effskill(u, SK_STEALTH) <= effskill(target, SK_PERCEPTION)) { cmistake(u, ord, 64, MSG_EVENT); return ECUSTOM; } ADDMSG(&u->faction->msgs, msg_message("givedumb", - "unit recipient amount", u, target, amount)); + "unit recipient amount", u, target, amount)); change_effect(target, itype->rtype->ptype, amount); use_pooled(u, itype->rtype, GET_DEFAULT, amount); @@ -842,115 +905,137 @@ use_foolpotion(struct unit *u, int targetno, const struct item_type *itype, int } static int -use_bloodpotion(struct unit *u, const struct item_type *itype, int amount, struct order * ord) +use_bloodpotion(struct unit *u, const struct item_type *itype, int amount, + struct order *ord) { if (u->race == new_race[RC_DAEMON]) { - change_effect(u, itype->rtype->ptype, 100*amount); + change_effect(u, itype->rtype->ptype, 100 * amount); } else { - const race * irace = u_irace(u); + const race *irace = u_irace(u); + if (irace == u->race) { - static race * rcfailure; + static race *rcfailure; + if (!rcfailure) { rcfailure = rc_find("smurf"); - if (!rcfailure) rcfailure = rc_find("toad"); + if (!rcfailure) + rcfailure = rc_find("toad"); } if (rcfailure) { - trigger * trestore = trigger_changerace(u, u->race, irace); + trigger *trestore = trigger_changerace(u, u->race, irace); + if (trestore) { int duration = 2 + rng_int() % 8; - add_trigger(&u->attribs, "timer", trigger_timeout(duration, trestore)); + add_trigger(&u->attribs, "timer", trigger_timeout(duration, + trestore)); u->irace = NULL; u->race = rcfailure; } } } } - use_pooled(u, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, amount); + use_pooled(u, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, + amount); usetpotionuse(u, itype->rtype->ptype); ADDMSG(&u->faction->msgs, msg_message("usepotion", - "unit potion", u, itype->rtype)); + "unit potion", u, itype->rtype)); return 0; } #include static int -use_mistletoe(struct unit * user, const struct item_type * itype, int amount, struct order * ord) +use_mistletoe(struct unit *user, const struct item_type *itype, int amount, + struct order *ord) { - int mtoes = get_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); + int mtoes = + get_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, + user->number); - if (user->number>mtoes) { + if (user->number > mtoes) { ADDMSG(&user->faction->msgs, msg_message("use_singleperson", - "unit item region command", user, itype->rtype, user->region, ord)); + "unit item region command", user, itype->rtype, user->region, ord)); return -1; } - use_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); + use_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, + user->number); a_add(&user->attribs, make_fleechance((float)1.0)); ADDMSG(&user->faction->msgs, - msg_message("use_item", "unit item", user, itype->rtype)); + msg_message("use_item", "unit item", user, itype->rtype)); return 0; } static int -use_magicboost(struct unit * user, const struct item_type * itype, int amount, struct order * ord) +use_magicboost(struct unit *user, const struct item_type *itype, int amount, + struct order *ord) { - int mtoes = get_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); - faction * f = user->faction; - if (user->number>mtoes) { + int mtoes = + get_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, + user->number); + faction *f = user->faction; + + if (user->number > mtoes) { ADDMSG(&user->faction->msgs, msg_message("use_singleperson", - "unit item region command", user, itype->rtype, user->region, ord)); + "unit item region command", user, itype->rtype, user->region, ord)); return -1; } - if (!is_mage(user) || find_key(f->attribs, atoi36("mbst"))!=NULL) { + if (!is_mage(user) || find_key(f->attribs, atoi36("mbst")) != NULL) { cmistake(user, user->thisorder, 214, MSG_EVENT); return -1; } - use_pooled(user, itype->rtype, GET_SLACK|GET_RESERVE|GET_POOLED_SLACK, user->number); + use_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, + user->number); a_add(&f->attribs, make_key(atoi36("mbst"))); set_level(user, sk_find("magic"), 3); ADDMSG(&user->faction->msgs, msg_message("use_item", - "unit item", user, itype->rtype)); + "unit item", user, itype->rtype)); return 0; } static int -use_snowball(struct unit * user, const struct item_type * itype, int amount, struct order * ord) +use_snowball(struct unit *user, const struct item_type *itype, int amount, + struct order *ord) { return 0; } -static void -init_oldpotions(void) +static void init_oldpotions(void) { - const char * potionnames[MAX_POTIONS] = { + const char *potionnames[MAX_POTIONS] = { "p0", "goliathwater", "p2", "p3", "ointment", "peasantblood", "p6", - "p7", "nestwarmth", "p9", "p10", "p11", "truthpotion", "p13", "p14" + "p7", "nestwarmth", "p9", "p10", "p11", "truthpotion", "p13", "p14" }; int p; - for (p=0;p!=MAXPOTIONS;++p) { - item_type * itype = it_find(potionnames[p]); - if (itype!=NULL) { + for (p = 0; p != MAXPOTIONS; ++p) { + item_type *itype = it_find(potionnames[p]); + + if (itype != NULL) { oldpotiontype[p] = itype->rtype->ptype; } } } -resource_type * r_silver; -resource_type * r_aura; -resource_type * r_permaura; -resource_type * r_unit; -resource_type * r_hp; +resource_type *r_silver; -resource_type * r_silver; -item_type * i_silver; +resource_type *r_aura; -static const char * names[] = { +resource_type *r_permaura; + +resource_type *r_unit; + +resource_type *r_hp; + +resource_type *r_silver; + +item_type *i_silver; + +static const char *names[] = { "money", "money_p", "person", "person_p", "permaura", "permaura_p", @@ -960,16 +1045,17 @@ static const char * names[] = { "unit", "unit_p" }; -void -init_resources(void) +void init_resources(void) { static boolean initialized = false; - if (initialized) return; + + if (initialized) + return; initialized = true; /* silver was never an item: */ - r_silver = new_resourcetype(&names[0], NULL, RTF_ITEM|RTF_POOLED); - i_silver = new_itemtype(r_silver, ITF_NONE, 1/*weight*/, 0); + r_silver = new_resourcetype(&names[0], NULL, RTF_ITEM | RTF_POOLED); + i_silver = new_itemtype(r_silver, ITF_NONE, 1 /*weight */ , 0); r_silver->uchange = res_changeitem; i_silver->give = give_money; @@ -994,123 +1080,141 @@ init_resources(void) init_oldpotions(); } -int -get_money(const unit * u) +int get_money(const unit * u) { - const item * i = u->items; - while (i && i->type!=i_silver) i=i->next; - if (i==NULL) return 0; + const item *i = u->items; + + while (i && i->type != i_silver) + i = i->next; + if (i == NULL) + return 0; return i->number; } -int -set_money(unit * u, int v) +int set_money(unit * u, int v) { - item ** ip = &u->items; - while (*ip && (*ip)->type!=i_silver) ip = &(*ip)->next; - if ((*ip)==NULL && v) { + item **ip = &u->items; + + while (*ip && (*ip)->type != i_silver) + ip = &(*ip)->next; + if ((*ip) == NULL && v) { i_add(&u->items, i_new(i_silver, v)); return v; } - if ((*ip)!=NULL) { + if ((*ip) != NULL) { if (v) { (*ip)->number = v; - assert((*ip)->number>=0); - } - else i_remove(ip, *ip); + assert((*ip)->number >= 0); + } else + i_remove(ip, *ip); } return v; } -int -change_money(unit * u, int v) +int change_money(unit * u, int v) { - item ** ip = &u->items; - while (*ip && (*ip)->type!=i_silver) ip = &(*ip)->next; - if ((*ip)==NULL && v) { + item **ip = &u->items; + + while (*ip && (*ip)->type != i_silver) + ip = &(*ip)->next; + if ((*ip) == NULL && v) { i_add(&u->items, i_new(i_silver, v)); return v; } - if ((*ip)!=NULL) { - item * i = *ip; + if ((*ip) != NULL) { + item *i = *ip; + if (i->number + v != 0) { i->number += v; - assert(i->number>=0); + assert(i->number >= 0); return i->number; - } - else i_free(i_remove(ip, *ip)); + } else + i_free(i_remove(ip, *ip)); } return 0; } -static local_names * rnames; +static local_names *rnames; -const resource_type * -findresourcetype(const char * name, const struct locale * lang) +const resource_type *findresourcetype(const char *name, + const struct locale *lang) { - local_names * rn = rnames; + local_names *rn = rnames; + variant token; while (rn) { - if (rn->lang==lang) break; + if (rn->lang == lang) + break; rn = rn->next; } if (!rn) { - const resource_type * rtl = resourcetypes; + const resource_type *rtl = resourcetypes; + rn = calloc(sizeof(local_names), 1); rn->next = rnames; rn->lang = lang; while (rtl) { - token.v = (void*)rtl; + token.v = (void *)rtl; addtoken(&rn->names, locale_string(lang, rtl->_name[0]), token); addtoken(&rn->names, locale_string(lang, rtl->_name[1]), token); - rtl=rtl->next; + rtl = rtl->next; } rnames = rn; } - if (findtoken(&rn->names, name, &token)==E_TOK_NOMATCH) return NULL; - return (const resource_type*)token.v; + if (findtoken(&rn->names, name, &token) == E_TOK_NOMATCH) + return NULL; + return (const resource_type *)token.v; } attrib_type at_showitem = { "showitem" }; -static local_names * inames; +static local_names *inames; -void -init_itemnames(void) +void init_itemnames(void) { int i; - for (i=0;localenames[i];++i) { - const struct locale * lang = find_locale(localenames[i]); - boolean exist = false; - local_names * in = inames; - while (in!=NULL) { - if (in->lang==lang) { + for (i = 0; localenames[i]; ++i) { + const struct locale *lang = find_locale(localenames[i]); + + boolean exist = false; + + local_names *in = inames; + + while (in != NULL) { + if (in->lang == lang) { exist = true; break; } in = in->next; } - if (in==NULL) in = calloc(sizeof(local_names), 1); + if (in == NULL) + in = calloc(sizeof(local_names), 1); in->next = inames; in->lang = lang; if (!exist) { int key; - for (key=0;key!=IMAXHASH;++key) { - const item_type * itl; - for (itl=itemtypes[key];itl;itl=itl->next) { + + for (key = 0; key != IMAXHASH; ++key) { + const item_type *itl; + + for (itl = itemtypes[key]; itl; itl = itl->next) { variant var; - const char * iname = locale_string(lang, itl->rtype->_name[0]); - if (findtoken(&in->names, iname, &var)==E_TOK_NOMATCH || var.v!=itl) { - var.v = (void*)itl; + + const char *iname = locale_string(lang, itl->rtype->_name[0]); + + if (findtoken(&in->names, iname, &var) == E_TOK_NOMATCH + || var.v != itl) { + var.v = (void *)itl; addtoken(&in->names, iname, var); - addtoken(&in->names, locale_string(lang, itl->rtype->_name[1]), var); + addtoken(&in->names, locale_string(lang, itl->rtype->_name[1]), + var); } } } @@ -1119,32 +1223,32 @@ init_itemnames(void) } } -const item_type * -finditemtype(const char * name, const struct locale * lang) +const item_type *finditemtype(const char *name, const struct locale *lang) { - local_names * in = inames; + local_names *in = inames; + variant var; - while (in!=NULL) { - if (in->lang==lang) break; - in=in->next; + while (in != NULL) { + if (in->lang == lang) + break; + in = in->next; } - if (in==NULL) { + if (in == NULL) { init_itemnames(); - for (in=inames;in->lang!=lang;in=in->next) ; + for (in = inames; in->lang != lang; in = in->next) ; } - if (findtoken(&in->names, name, &var)==E_TOK_NOMATCH) return NULL; - return (const item_type*)var.v; + if (findtoken(&in->names, name, &var) == E_TOK_NOMATCH) + return NULL; + return (const item_type *)var.v; } -static void -init_resourcelimit(attrib * a) +static void init_resourcelimit(attrib * a) { a->data.v = calloc(sizeof(resource_limit), 1); } -static void -finalize_resourcelimit(attrib * a) +static void finalize_resourcelimit(attrib * a) { free(a->data.v); } @@ -1155,36 +1259,35 @@ attrib_type at_resourcelimit = { finalize_resourcelimit, }; -static item * -default_spoil(const struct race * rc, int size) +static item *default_spoil(const struct race *rc, int size) { - item * itm = NULL; + item *itm = NULL; - if (rng_int()%100 < RACESPOILCHANCE) { + if (rng_int() % 100 < RACESPOILCHANCE) { char spoilname[32]; - const item_type * itype; - sprintf(spoilname, "%sspoil", rc->_name[0]); + const item_type *itype; + + sprintf(spoilname, "%sspoil", rc->_name[0]); itype = it_find(spoilname); - if (itype!=NULL) { + if (itype != NULL) { i_add(&itm, i_new(itype, size)); } } return itm; } -void -register_resources(void) +void register_resources(void) { - register_function((pf_generic)mod_elves_only, "mod_elves_only"); - register_function((pf_generic)mod_dwarves_only, "mod_dwarves_only"); - register_function((pf_generic)res_changeitem, "changeitem"); - register_function((pf_generic)res_changeperson, "changeperson"); - register_function((pf_generic)res_changepeasants, "changepeasants"); - register_function((pf_generic)res_changepermaura, "changepermaura"); - register_function((pf_generic)res_changehp, "changehp"); - register_function((pf_generic)res_changeaura, "changeaura"); - register_function((pf_generic)default_spoil, "defaultdrops"); + register_function((pf_generic) mod_elves_only, "mod_elves_only"); + register_function((pf_generic) mod_dwarves_only, "mod_dwarves_only"); + register_function((pf_generic) res_changeitem, "changeitem"); + register_function((pf_generic) res_changeperson, "changeperson"); + register_function((pf_generic) res_changepeasants, "changepeasants"); + register_function((pf_generic) res_changepermaura, "changepermaura"); + register_function((pf_generic) res_changehp, "changehp"); + register_function((pf_generic) res_changeaura, "changeaura"); + register_function((pf_generic) default_spoil, "defaultdrops"); register_item_use(use_potion, "usepotion"); register_item_use(use_potion_delayed, "usepotion_delayed"); diff --git a/src/kernel/item.h b/src/kernel/item.h index 4898f7603..4d9b3a958 100644 --- a/src/kernel/item.h +++ b/src/kernel/item.h @@ -22,96 +22,101 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -struct unit; -struct attrib; -struct attrib_type; -struct region; -struct resource_type; -struct locale; -struct troop; + struct unit; + struct attrib; + struct attrib_type; + struct region; + struct resource_type; + struct locale; + struct troop; -typedef struct item { - struct item * next; - const struct item_type * type; - int number; -} item; + typedef struct item { + struct item *next; + const struct item_type *type; + int number; + } item; -typedef struct resource { - const struct resource_type * type; - int number; - struct resource * next; -} resource; + typedef struct resource { + const struct resource_type *type; + int number; + struct resource *next; + } resource; /* bitfield values for resource_type::flags */ #define RTF_NONE 0 -#define RTF_ITEM (1<<0) /* this resource is an item */ -#define RTF_LIMITED (1<<1) /* a resource that's freely available, but in - * limited supply */ -#define RTF_POOLED (1<<2) /* resource is available in pool */ +#define RTF_ITEM (1<<0) /* this resource is an item */ +#define RTF_LIMITED (1<<1) /* a resource that's freely available, but in + * limited supply */ +#define RTF_POOLED (1<<2) /* resource is available in pool */ /* flags for resource_type::name() */ #define NMF_PLURAL 0x01 #define NMF_APPEARANCE 0x02 -typedef int (*rtype_uchange)(struct unit * user, const struct resource_type * rtype, int delta); -typedef int (*rtype_uget)(const struct unit * user, const struct resource_type * rtype); -typedef char * (*rtype_name)(const struct resource_type * rtype, int flags); -typedef struct resource_type { - /* --- constants --- */ - char * _name[2]; /* wie es heißt */ - char * _appearance[2]; /* wie es für andere aussieht */ - unsigned int flags; - /* --- functions --- */ - rtype_uchange uchange; - rtype_uget uget; - rtype_name name; - /* --- pointers --- */ - struct attrib * attribs; - struct resource_type * next; - unsigned int hashkey; - struct item_type * itype; - struct potion_type * ptype; - struct luxury_type * ltype; - struct weapon_type * wtype; - struct armor_type * atype; -} resource_type; -extern resource_type * resourcetypes; -extern const char* resourcename(const resource_type * rtype, int flags); -extern const resource_type * findresourcetype(const char * name, const struct locale * lang); + typedef int (*rtype_uchange) (struct unit * user, + const struct resource_type * rtype, int delta); + typedef int (*rtype_uget) (const struct unit * user, + const struct resource_type * rtype); + typedef char *(*rtype_name) (const struct resource_type * rtype, int flags); + typedef struct resource_type { + /* --- constants --- */ + char *_name[2]; /* wie es heißt */ + char *_appearance[2]; /* wie es für andere aussieht */ + unsigned int flags; + /* --- functions --- */ + rtype_uchange uchange; + rtype_uget uget; + rtype_name name; + /* --- pointers --- */ + struct attrib *attribs; + struct resource_type *next; + unsigned int hashkey; + struct item_type *itype; + struct potion_type *ptype; + struct luxury_type *ltype; + struct weapon_type *wtype; + struct armor_type *atype; + } resource_type; + extern resource_type *resourcetypes; + extern const char *resourcename(const resource_type * rtype, int flags); + extern const resource_type *findresourcetype(const char *name, + const struct locale *lang); /* resource-limits for regions */ -#define RMF_SKILL 0x01 /* int, bonus on resource production skill */ -#define RMF_SAVEMATERIAL 0x02 /* float, multiplier on resource usage */ -#define RMF_SAVERESOURCE 0x03 /* int, bonus on resource production skill */ -#define RMF_REQUIREDBUILDING 0x04 /* building, required to build */ +#define RMF_SKILL 0x01 /* int, bonus on resource production skill */ +#define RMF_SAVEMATERIAL 0x02 /* float, multiplier on resource usage */ +#define RMF_SAVERESOURCE 0x03 /* int, bonus on resource production skill */ +#define RMF_REQUIREDBUILDING 0x04 /* building, required to build */ -typedef struct resource_mod { - variant value; - const struct building_type * btype; - const struct race * race; - unsigned int flags; -} resource_mod; + typedef struct resource_mod { + variant value; + const struct building_type *btype; + const struct race *race; + unsigned int flags; + } resource_mod; -extern struct attrib_type at_resourcelimit; -typedef int (*rlimit_limit)(const struct region * r, const struct resource_type * rtype); -typedef void (*rlimit_produce)(struct region * r, const struct resource_type * rtype, int n); -typedef struct resource_limit { - rlimit_limit limit; - rlimit_produce produce; - unsigned int guard; /* how to guard against theft */ - int value; - resource_mod * modifiers; -} resource_limit; + extern struct attrib_type at_resourcelimit; + typedef int (*rlimit_limit) (const struct region * r, + const struct resource_type * rtype); + typedef void (*rlimit_produce) (struct region * r, + const struct resource_type * rtype, int n); + typedef struct resource_limit { + rlimit_limit limit; + rlimit_produce produce; + unsigned int guard; /* how to guard against theft */ + int value; + resource_mod *modifiers; + } resource_limit; /* bitfield values for item_type::flags */ #define ITF_NONE 0x0000 -#define ITF_HERB 0x0001 /* this item is a herb */ -#define ITF_CURSED 0x0010 /* cursed object, cannot be given away */ -#define ITF_NOTLOST 0x0020 /* special object (quests), cannot be lost through death etc. */ -#define ITF_BIG 0x0040 /* big item, e.g. does not fit in a bag of holding */ -#define ITF_ANIMAL 0x0080 /* an animal */ -#define ITF_VEHICLE 0x0100 /* a vehicle, drawn by two animals */ +#define ITF_HERB 0x0001 /* this item is a herb */ +#define ITF_CURSED 0x0010 /* cursed object, cannot be given away */ +#define ITF_NOTLOST 0x0020 /* special object (quests), cannot be lost through death etc. */ +#define ITF_BIG 0x0040 /* big item, e.g. does not fit in a bag of holding */ +#define ITF_ANIMAL 0x0080 /* an animal */ +#define ITF_VEHICLE 0x0100 /* a vehicle, drawn by two animals */ /* error codes for item_type::use */ #define ECUSTOM -1; @@ -119,76 +124,81 @@ typedef struct resource_limit { #define ENOSKILL -3; #define EUNUSABLE -4; -typedef struct item_type { - resource_type * rtype; - /* --- constants --- */ - unsigned int flags; - int weight; - int capacity; - struct construction * construction; - /* --- functions --- */ - boolean (*canuse)(const struct unit * user, const struct item_type * itype); - int (*use)(struct unit * user, const struct item_type * itype, int amount, struct order * ord); - int (*useonother)(struct unit * user, int targetno, const struct item_type * itype, int amount, struct order * ord); - int (*give)(struct unit * src, struct unit * dest, const struct item_type * itm, int number, struct order * ord); + typedef struct item_type { + resource_type *rtype; + /* --- constants --- */ + unsigned int flags; + int weight; + int capacity; + struct construction *construction; + /* --- functions --- */ + boolean(*canuse) (const struct unit * user, + const struct item_type * itype); + int (*use) (struct unit * user, const struct item_type * itype, int amount, + struct order * ord); + int (*useonother) (struct unit * user, int targetno, + const struct item_type * itype, int amount, struct order * ord); + int (*give) (struct unit * src, struct unit * dest, + const struct item_type * itm, int number, struct order * ord); #if SCORE_MODULE - int score; + int score; #endif - struct item_type * next; -} item_type; + struct item_type *next; + } item_type; -extern const item_type * finditemtype(const char * name, const struct locale * lang); -extern void init_itemnames(void); + extern const item_type *finditemtype(const char *name, + const struct locale *lang); + extern void init_itemnames(void); -typedef struct luxury_type { - struct luxury_type * next; - const item_type * itype; - int price; -} luxury_type; -extern luxury_type * luxurytypes; + typedef struct luxury_type { + struct luxury_type *next; + const item_type *itype; + int price; + } luxury_type; + extern luxury_type *luxurytypes; -typedef struct potion_type { - struct potion_type * next; - const item_type * itype; - int level; -} potion_type; -extern potion_type * potiontypes; + typedef struct potion_type { + struct potion_type *next; + const item_type *itype; + int level; + } potion_type; + extern potion_type *potiontypes; #define WMF_WALKING 0x0001 #define WMF_RIDING 0x0002 -#define WMF_ANYONE 0x000F /* convenience */ +#define WMF_ANYONE 0x000F /* convenience */ #define WMF_AGAINST_RIDING 0x0010 #define WMF_AGAINST_WALKING 0x0020 -#define WMF_AGAINST_ANYONE 0x00F0 /* convenience */ +#define WMF_AGAINST_ANYONE 0x00F0 /* convenience */ #define WMF_OFFENSIVE 0x0100 #define WMF_DEFENSIVE 0x0200 -#define WMF_ANYTIME 0x0F00 /* convenience */ +#define WMF_ANYTIME 0x0F00 /* convenience */ #define WMF_DAMAGE 0x1000 #define WMF_SKILL 0x2000 #define WMF_MISSILE_TARGET 0x4000 -struct race_list; -typedef struct weapon_mod { - int value; - unsigned int flags; - struct race_list * races; -} weapon_mod; + struct race_list; + typedef struct weapon_mod { + int value; + unsigned int flags; + struct race_list *races; + } weapon_mod; #define ATF_NONE 0x00 #define ATF_SHIELD 0x01 #define ATF_LAEN 0x02 -typedef struct armor_type { - const item_type * itype; - double penalty; - double magres; - int prot; - float projectile; /* chance, dass ein projektil abprallt */ - unsigned int flags; -} armor_type; + typedef struct armor_type { + const item_type *itype; + double penalty; + double magres; + int prot; + float projectile; /* chance, dass ein projektil abprallt */ + unsigned int flags; + } armor_type; #define WTF_NONE 0x00 #define WTF_MISSILE 0x01 @@ -197,156 +207,164 @@ typedef struct armor_type { #define WTF_CUT 0x08 #define WTF_BLUNT 0x10 #define WTF_SIEGE 0x20 -#define WTF_ARMORPIERCING 0x40 /* armor has only half value */ +#define WTF_ARMORPIERCING 0x40 /* armor has only half value */ #define WTF_HORSEBONUS 0x80 #define WTF_USESHIELD 0x100 -typedef struct weapon_type { - const item_type * itype; - const char * damage[2]; - unsigned int flags; - skill_t skill; - int minskill; - int offmod; - int defmod; - double magres; - int reload; /* time to reload this weapon */ - weapon_mod * modifiers; - /* --- functions --- */ - boolean (*attack)(const struct troop *, const struct weapon_type *, int *deaths); -} weapon_type; + typedef struct weapon_type { + const item_type *itype; + const char *damage[2]; + unsigned int flags; + skill_t skill; + int minskill; + int offmod; + int defmod; + double magres; + int reload; /* time to reload this weapon */ + weapon_mod *modifiers; + /* --- functions --- */ + boolean(*attack) (const struct troop *, const struct weapon_type *, + int *deaths); + } weapon_type; -extern void rt_register(resource_type * it); -extern resource_type * rt_find(const char * name); -extern item_type * it_find(const char * name); + extern void rt_register(resource_type * it); + extern resource_type *rt_find(const char *name); + extern item_type *it_find(const char *name); -extern void it_register(item_type * it); -extern void wt_register(weapon_type * wt); + extern void it_register(item_type * it); + extern void wt_register(weapon_type * wt); -extern const item_type * resource2item(const resource_type * rtype); -extern const resource_type * item2resource(const item_type * i); + extern const item_type *resource2item(const resource_type * rtype); + extern const resource_type *item2resource(const item_type * i); -extern const weapon_type * resource2weapon(const resource_type * i); -extern const potion_type * resource2potion(const resource_type * i); -extern const luxury_type * resource2luxury(const resource_type * i); + extern const weapon_type *resource2weapon(const resource_type * i); + extern const potion_type *resource2potion(const resource_type * i); + extern const luxury_type *resource2luxury(const resource_type * i); -extern item ** i_find(item ** pi, const item_type * it); -extern item * const * i_findc(item * const * pi, const item_type * it); -extern item * i_add(item ** pi, item * it); -extern void i_merge(item ** pi, item ** si); -extern item * i_remove(item ** pi, item * it); -extern void i_free(item * i); -extern void i_freeall(item ** i); -extern item * i_new(const item_type * it, int number); + extern item **i_find(item ** pi, const item_type * it); + extern item *const *i_findc(item * const *pi, const item_type * it); + extern item *i_add(item ** pi, item * it); + extern void i_merge(item ** pi, item ** si); + extern item *i_remove(item ** pi, item * it); + extern void i_free(item * i); + extern void i_freeall(item ** i); + extern item *i_new(const item_type * it, int number); /* convenience: */ -extern item * i_change(item ** items, const item_type * it, int delta); -extern int i_get(const item * i, const item_type * it); + extern item *i_change(item ** items, const item_type * it, int delta); + extern int i_get(const item * i, const item_type * it); /* creation */ -extern resource_type * new_resourcetype(const char ** names, const char ** appearances, int flags); -extern item_type * new_itemtype(resource_type * rtype, int iflags, int weight, int capacity); -extern luxury_type * new_luxurytype(item_type * itype, int price); -extern weapon_type * new_weapontype(item_type * itype, int wflags, double magres, const char* damage[], int offmod, int defmod, int reload, skill_t sk, int minskill); -extern armor_type * new_armortype(item_type * itype, double penalty, double magres, int prot, unsigned int flags); -extern potion_type * new_potiontype(item_type * itype, int level); + extern resource_type *new_resourcetype(const char **names, + const char **appearances, int flags); + extern item_type *new_itemtype(resource_type * rtype, int iflags, int weight, + int capacity); + extern luxury_type *new_luxurytype(item_type * itype, int price); + extern weapon_type *new_weapontype(item_type * itype, int wflags, + double magres, const char *damage[], int offmod, int defmod, int reload, + skill_t sk, int minskill); + extern armor_type *new_armortype(item_type * itype, double penalty, + double magres, int prot, unsigned int flags); + extern potion_type *new_potiontype(item_type * itype, int level); /* for lack of another file: */ /* sonstige resourcen */ -extern resource_type * r_silver; -extern resource_type * r_aura; -extern resource_type * r_permaura; -extern resource_type * r_unit; -extern resource_type * r_hp; + extern resource_type *r_silver; + extern resource_type *r_aura; + extern resource_type *r_permaura; + extern resource_type *r_unit; + extern resource_type *r_hp; -enum { - I_IRON, /* 0 */ - I_STONE, - I_HORSE, - /* alte Artefakte */ - I_AMULET_OF_HEALING, - I_AMULET_OF_TRUE_SEEING, - I_RING_OF_INVISIBILITY, - I_RING_OF_POWER, - I_CHASTITY_BELT, /* bleibt */ - I_LAEN, - I_FEENSTIEFEL, - I_BIRTHDAYAMULET, - I_PEGASUS, - I_ELVENHORSE, - I_DOLPHIN, - I_RING_OF_NIMBLEFINGER, - I_TROLLBELT, - I_PRESSCARD, - I_AURAKULUM, - I_SPHERE_OF_INVISIBILITY, - I_BAG_OF_HOLDING, - I_SACK_OF_CONSERVATION, - I_TACTICCRYSTAL, - MAX_ITEMS /* do not use outside item.c ! */ -}; + enum { + I_IRON, /* 0 */ + I_STONE, + I_HORSE, + /* alte Artefakte */ + I_AMULET_OF_HEALING, + I_AMULET_OF_TRUE_SEEING, + I_RING_OF_INVISIBILITY, + I_RING_OF_POWER, + I_CHASTITY_BELT, /* bleibt */ + I_LAEN, + I_FEENSTIEFEL, + I_BIRTHDAYAMULET, + I_PEGASUS, + I_ELVENHORSE, + I_DOLPHIN, + I_RING_OF_NIMBLEFINGER, + I_TROLLBELT, + I_PRESSCARD, + I_AURAKULUM, + I_SPHERE_OF_INVISIBILITY, + I_BAG_OF_HOLDING, + I_SACK_OF_CONSERVATION, + I_TACTICCRYSTAL, + MAX_ITEMS /* do not use outside item.c ! */ + }; -enum { - /* ITEMS: */ - R_IRON, - R_STONE, - R_HORSE, - /**/ - R_AMULET_OF_HEALING, - R_AMULET_OF_TRUE_SEEING, - R_RING_OF_INVISIBILITY, - R_RING_OF_POWER, - R_CHASTITY_BELT, - R_EOG, - R_FEENSTIEFEL, - R_BIRTHDAYAMULET, - R_PEGASUS, - R_UNICORN, - R_DOLPHIN, - R_RING_OF_NIMBLEFINGER, - R_TROLLBELT, - R_PRESSCARD, - R_AURAKULUM, - R_SPHERE_OF_INVISIBILITY, - R_BAG_OF_HOLDING, - R_SACK_OF_CONSERVATION, - R_TACTICCRYSTAL, + enum { + /* ITEMS: */ + R_IRON, + R_STONE, + R_HORSE, + /**/ R_AMULET_OF_HEALING, + R_AMULET_OF_TRUE_SEEING, + R_RING_OF_INVISIBILITY, + R_RING_OF_POWER, + R_CHASTITY_BELT, + R_EOG, + R_FEENSTIEFEL, + R_BIRTHDAYAMULET, + R_PEGASUS, + R_UNICORN, + R_DOLPHIN, + R_RING_OF_NIMBLEFINGER, + R_TROLLBELT, + R_PRESSCARD, + R_AURAKULUM, + R_SPHERE_OF_INVISIBILITY, + R_BAG_OF_HOLDING, + R_SACK_OF_CONSERVATION, + R_TACTICCRYSTAL, - /* SONSTIGE */ - R_SILVER, - R_AURA, /* Aura */ - R_PERMAURA, /* Permanente Aura */ + /* SONSTIGE */ + R_SILVER, + R_AURA, /* Aura */ + R_PERMAURA, /* Permanente Aura */ - MAX_RESOURCES, /* do not use outside item.c ! */ - NORESOURCE = -1 -}; + MAX_RESOURCES, /* do not use outside item.c ! */ + NORESOURCE = -1 + }; -extern const struct potion_type * oldpotiontype[]; -extern const struct item_type * olditemtype[]; -extern const struct resource_type * oldresourcetype[]; + extern const struct potion_type *oldpotiontype[]; + extern const struct item_type *olditemtype[]; + extern const struct resource_type *oldresourcetype[]; -int get_item(const struct unit *, item_t); -int set_item(struct unit *, item_t, int); + int get_item(const struct unit *, item_t); + int set_item(struct unit *, item_t, int); -int get_money(const struct unit *); -int set_money(struct unit *, int); -int change_money(struct unit *, int); -int res_changeitem(struct unit * u, const resource_type * rtype, int delta); + int get_money(const struct unit *); + int set_money(struct unit *, int); + int change_money(struct unit *, int); + int res_changeitem(struct unit *u, const resource_type * rtype, int delta); -extern struct attrib_type at_showitem; /* show this potion's description */ + extern struct attrib_type at_showitem; /* show this potion's description */ -extern void register_resources(void); -extern void init_resources(void); -extern void init_itemtypes(void); + extern void register_resources(void); + extern void init_resources(void); + extern void init_itemtypes(void); -extern void register_item_give(int (*foo) (struct unit *, struct unit *, const struct item_type *, int, struct order *), const char * name); -extern void register_item_use(int (*foo) (struct unit *, const struct item_type *, int, struct order *), const char * name); -extern void register_item_useonother(int (*foo) (struct unit *, int, const struct item_type *, int, struct order *), const char * name); + extern void register_item_give(int (*foo) (struct unit *, struct unit *, + const struct item_type *, int, struct order *), const char *name); + extern void register_item_use(int (*foo) (struct unit *, + const struct item_type *, int, struct order *), const char *name); + extern void register_item_useonother(int (*foo) (struct unit *, int, + const struct item_type *, int, struct order *), const char *name); -extern struct item_type *i_silver; + extern struct item_type *i_silver; #ifdef __cplusplus } #endif -#endif /* _ITEM_H */ +#endif /* _ITEM_H */ diff --git a/src/kernel/magic.c b/src/kernel/magic.c index fc200c3f3..597342010 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -72,15 +72,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* ------------------------------------------------------------- */ -const char *magic_school[MAXMAGIETYP] = -{ +const char *magic_school[MAXMAGIETYP] = { "gray", "illaun", "tybied", "cerddor", "gwyrrd", "draig", - "common" + "common" }; attrib_type at_reportspell = { @@ -92,34 +91,38 @@ attrib_type at_reportspell = { ** TODO: separate castle-appearance from illusion-effects **/ -static double -MagicRegeneration(void) +static double MagicRegeneration(void) { static double value = -1.0; - if (value<0) { - const char * str = get_param(global.parameters, "magic.regeneration"); - value = str?atof(str):1.0; + + if (value < 0) { + const char *str = get_param(global.parameters, "magic.regeneration"); + + value = str ? atof(str) : 1.0; } return value; } -double -MagicPower(void) +double MagicPower(void) { static double value = -1.0; - if (value<0) { - const char * str = get_param(global.parameters, "magic.power"); - value = str?atof(str):1.0; + + if (value < 0) { + const char *str = get_param(global.parameters, "magic.power"); + + value = str ? atof(str) : 1.0; } return value; } -static int -a_readicastle(attrib * a, void * owner, struct storage * store) +static int a_readicastle(attrib * a, void *owner, struct storage *store) { - icastle_data * data = (icastle_data*)a->data.v; + icastle_data *data = (icastle_data *) a->data.v; + variant bno; + char token[32]; + store->r_tok_buf(store, token, sizeof(token)); bno.i = store->r_int(store); data->time = store->r_int(store); @@ -133,38 +136,39 @@ a_readicastle(attrib * a, void * owner, struct storage * store) } static void -a_writeicastle(const attrib * a, const void * owner, struct storage * store) +a_writeicastle(const attrib * a, const void *owner, struct storage *store) { - icastle_data * data = (icastle_data*)a->data.v; + icastle_data *data = (icastle_data *) a->data.v; + store->w_tok(store, data->type->_name); store->w_int(store, data->building->no); store->w_int(store, data->time); } -static int -a_ageicastle(struct attrib * a) +static int a_ageicastle(struct attrib *a) { - icastle_data * data = (icastle_data*)a->data.v; - if (data->time<=0) { - building * b = data->building; - region * r = b->region; + icastle_data *data = (icastle_data *) a->data.v; + + if (data->time <= 0) { + building *b = data->building; + + region *r = b->region; + ADDMSG(&r->msgs, msg_message("icastle_dissolve", "building", b)); /* remove_building lets units leave the building */ remove_building(&r->buildings, b); return AT_AGE_REMOVE; - } - else data->time--; + } else + data->time--; return AT_AGE_KEEP; } -static void -a_initicastle(struct attrib * a) +static void a_initicastle(struct attrib *a) { a->data.v = calloc(sizeof(icastle_data), 1); } -static void -a_finalizeicastle(struct attrib * a) +static void a_finalizeicastle(struct attrib *a) { free(a->data.v); } @@ -187,15 +191,15 @@ extern int dice(int count, int value); * Umwandlung von alt nach neu gebraucht werden */ /* ------------------------------------------------------------- */ -static void -init_mage(attrib * a) { +static void init_mage(attrib * a) +{ a->data.v = calloc(sizeof(sc_mage), 1); } -static void -free_mage(attrib * a) +static void free_mage(attrib * a) { - sc_mage * mage = (sc_mage*)a->data.v; + sc_mage *mage = (sc_mage *) a->data.v; + freelist(mage->spells); free(mage); } @@ -203,68 +207,83 @@ free_mage(attrib * a) int FactionSpells(void) { static int rules_factionspells = -1; - if (rules_factionspells<0) { - rules_factionspells = get_param_int(global.parameters, "rules.magic.factionlist", 0); + + if (rules_factionspells < 0) { + rules_factionspells = + get_param_int(global.parameters, "rules.magic.factionlist", 0); } return rules_factionspells; } -void read_spells(struct quicklist ** slistp, magic_t mtype, struct storage * store) +void read_spells(struct quicklist **slistp, magic_t mtype, + struct storage *store) { for (;;) { - spell * sp; + spell *sp; + char spname[64]; - if (store->versionversion < SPELLNAME_VERSION) { int i = store->r_int(store); - if (i < 0) break; - sp = find_spellbyid(M_NONE, (spellid_t)i); + + if (i < 0) + break; + sp = find_spellbyid(M_NONE, (spellid_t) i); } else { store->r_tok_buf(store, spname, sizeof(spname)); - if (strcmp(spname, "end")==0) break; + if (strcmp(spname, "end") == 0) + break; sp = find_spell(mtype, spname); } - if (sp!=NULL) { + if (sp != NULL) { add_spell(slistp, sp); } } } -static int -read_mage(attrib * a, void * owner, struct storage * store) +static int read_mage(attrib * a, void *owner, struct storage *store) { int i, mtype; - sc_mage * mage = (sc_mage*)a->data.v; + + sc_mage *mage = (sc_mage *) a->data.v; + char spname[64]; mtype = store->r_int(store); mage->spellpoints = store->r_int(store); mage->spchange = store->r_int(store); - mage->magietyp = (magic_t)mtype; - for (i=0;i!=MAXCOMBATSPELLS;++i) { - spell * sp = NULL; + mage->magietyp = (magic_t) mtype; + for (i = 0; i != MAXCOMBATSPELLS; ++i) { + spell *sp = NULL; + int level = 0; - if (store->versionversion < SPELLNAME_VERSION) { int spid; + spid = store->r_int(store); level = store->r_int(store); - if (spid>=0) { - sp = find_spellbyid(mage->magietyp, (spellid_t)spid); + if (spid >= 0) { + sp = find_spellbyid(mage->magietyp, (spellid_t) spid); } } else { store->r_tok_buf(store, spname, sizeof(spname)); level = store->r_int(store); - if (strcmp("none", spname)!=0) { + if (strcmp("none", spname) != 0) { sp = find_spell(mage->magietyp, spname); } } - if (sp && level>=0) { + if (sp && level >= 0) { int slot = -1; - if (sp->sptyp & PRECOMBATSPELL) slot = 0; - else if (sp->sptyp & COMBATSPELL) slot = 1; - else if (sp->sptyp & POSTCOMBATSPELL) slot = 2; - if (slot>=0) { + + if (sp->sptyp & PRECOMBATSPELL) + slot = 0; + else if (sp->sptyp & COMBATSPELL) + slot = 1; + else if (sp->sptyp & POSTCOMBATSPELL) + slot = 2; + if (slot >= 0) { mage->combatspells[slot].level = level; mage->combatspells[slot].sp = sp; } @@ -274,29 +293,33 @@ read_mage(attrib * a, void * owner, struct storage * store) return AT_READ_OK; } -void write_spells(struct quicklist * slist, struct storage * store) +void write_spells(struct quicklist *slist, struct storage *store) { - quicklist * ql; + quicklist *ql; + int qi; - for (ql=slist,qi=0;ql;ql_advance(&ql, &qi, 1)) { - spell * sp = (spell *)ql_get(ql, qi); + for (ql = slist, qi = 0; ql; ql_advance(&ql, &qi, 1)) { + spell *sp = (spell *) ql_get(ql, qi); + store->w_tok(store, sp->sname); } store->w_tok(store, "end"); } static void -write_mage(const attrib * a, const void * owner, struct storage * store) +write_mage(const attrib * a, const void *owner, struct storage *store) { int i; - sc_mage *mage = (sc_mage*)a->data.v; + + sc_mage *mage = (sc_mage *) a->data.v; store->w_int(store, mage->magietyp); store->w_int(store, mage->spellpoints); store->w_int(store, mage->spchange); - for (i=0;i!=MAXCOMBATSPELLS;++i) { - store->w_tok(store, mage->combatspells[i].sp?mage->combatspells[i].sp->sname:"none"); + for (i = 0; i != MAXCOMBATSPELLS; ++i) { + store->w_tok(store, + mage->combatspells[i].sp ? mage->combatspells[i].sp->sname : "none"); store->w_int(store, mage->combatspells[i].level); } write_spells(mage->spells, store); @@ -312,18 +335,18 @@ attrib_type at_mage = { ATF_UNIQUE }; -boolean -is_mage(const unit * u) +boolean is_mage(const unit * u) { return i2b(get_mage(u) != NULL); } -sc_mage * -get_mage(const unit * u) +sc_mage *get_mage(const unit * u) { if (has_skill(u, SK_MAGIC)) { - attrib * a = a_find(u->attribs, &at_mage); - if (a) return a->data.v; + attrib *a = a_find(u->attribs, &at_mage); + + if (a) + return a->data.v; } return (sc_mage *) NULL; } @@ -337,23 +360,25 @@ get_mage(const unit * u) */ -static int -read_seenspell(attrib * a, void * owner, struct storage * store) +static int read_seenspell(attrib * a, void *owner, struct storage *store) { int i; - spell * sp = NULL; + + spell *sp = NULL; + char token[32]; store->r_tok_buf(store, token, sizeof(token)); i = atoi(token); - if (i!=0) { - sp = find_spellbyid(M_NONE, (spellid_t)i); + if (i != 0) { + sp = find_spellbyid(M_NONE, (spellid_t) i); } else { int mtype; + mtype = store->r_int(store); - sp = find_spell((magic_t)mtype, token); + sp = find_spell((magic_t) mtype, token); } - if (sp==NULL) { + if (sp == NULL) { /* log_error(("could not find seenspell '%s'\n", buf)); */ return AT_READ_FAIL; } @@ -362,9 +387,10 @@ read_seenspell(attrib * a, void * owner, struct storage * store) } static void -write_seenspell(const attrib * a, const void * owner, struct storage * store) +write_seenspell(const attrib * a, const void *owner, struct storage *store) { - const spell * sp = (const spell*)a->data.v; + const spell *sp = (const spell *)a->data.v; + store->w_tok(store, sp->sname); store->w_int(store, sp->magietyp); } @@ -373,13 +399,14 @@ attrib_type at_seenspell = { "seenspell", NULL, NULL, NULL, write_seenspell, read_seenspell }; -static boolean -already_seen(const faction * f, const spell * sp) +static boolean already_seen(const faction * f, const spell * sp) { attrib *a; - for (a = a_find(f->attribs, &at_seenspell); a && a->type==&at_seenspell; a=a->next) { - if (a->data.v==sp) return true; + for (a = a_find(f->attribs, &at_seenspell); a && a->type == &at_seenspell; + a = a->next) { + if (a->data.v == sp) + return true; } return false; } @@ -387,46 +414,53 @@ already_seen(const faction * f, const spell * sp) static boolean know_school(const faction * f, magic_t school) { static int common = MAXMAGIETYP; - if (f->magiegebiet==school) return true; - if (common==MAXMAGIETYP) { - const char * common_school = get_param(global.parameters, "rules.magic.common"); + + if (f->magiegebiet == school) + return true; + if (common == MAXMAGIETYP) { + const char *common_school = + get_param(global.parameters, "rules.magic.common"); if (common_school) { - for (common=0;common!=MAXMAGIETYP;++common) { - if (strcmp(common_school, magic_school[common])==0) break; + for (common = 0; common != MAXMAGIETYP; ++common) { + if (strcmp(common_school, magic_school[common]) == 0) + break; } - if (common==MAXMAGIETYP) { + if (common == MAXMAGIETYP) { common = M_NONE; } } else { return false; } } - return school==common; + return school == common; } -#define COMMONSPELLS 1 /* number of new common spells per level */ +#define COMMONSPELLS 1 /* number of new common spells per level */ #define MAXSPELLS 256 -static boolean -has_spell(quicklist * ql, const spell * sp) +static boolean has_spell(quicklist * ql, const spell * sp) { int qi; - return ql_set_find(&ql, &qi, sp)!=0; + + return ql_set_find(&ql, &qi, sp) != 0; } /** update the spellbook with a new level * Written for Eressea 1.1 */ -void -update_spellbook(faction * f, int level) +void update_spellbook(faction * f, int level) { - spell * commonspells[MAXSPELLS]; - int qi, numspells = 0; - quicklist * ql; + spell *commonspells[MAXSPELLS]; - for (qi=0,ql=spells;ql;ql_advance(&ql, &qi, 1)) { - spell * sp = (spell *)ql_get(ql, qi); - if (sp->magietyp == M_COMMON && level>f->max_spelllevel && sp->level<=level) { + int qi, numspells = 0; + + quicklist *ql; + + for (qi = 0, ql = spells; ql; ql_advance(&ql, &qi, 1)) { + spell *sp = (spell *) ql_get(ql, qi); + + if (sp->magietyp == M_COMMON && level > f->max_spelllevel + && sp->level <= level) { commonspells[numspells++] = sp; } else { if (know_school(f, sp->magietyp) && sp->level <= level) { @@ -434,20 +468,25 @@ update_spellbook(faction * f, int level) } } } - while (numspells>0 && level>f->max_spelllevel) { + while (numspells > 0 && level > f->max_spelllevel) { int i; - for (i=0;i!=COMMONSPELLS;++i) { + + for (i = 0; i != COMMONSPELLS; ++i) { int maxspell = numspells; + int spellno = -1; - spell * sp; + + spell *sp; + do { - if (spellno==maxspell) { + if (spellno == maxspell) { --maxspell; } spellno = rng_int() % maxspell; sp = commonspells[spellno]; } - while (maxspell>0 && sp && sp->level<=f->max_spelllevel && !has_spell(f->spellbook, sp)); + while (maxspell > 0 && sp && sp->level <= f->max_spelllevel + && !has_spell(f->spellbook, sp)); if (sp) { ql_set_insert(&f->spellbook, sp); @@ -458,17 +497,21 @@ update_spellbook(faction * f, int level) } } -void -updatespelllist(unit * u) +void updatespelllist(unit * u) { int sk = eff_skill(u, SK_MAGIC, u->region); - quicklist * ql = spells; - int qi; - struct sc_mage * mage = get_mage(u); - boolean ismonster = is_monsters(u->faction); - quicklist ** dst; - if (mage->magietyp==M_GRAY) { + quicklist *ql = spells; + + int qi; + + struct sc_mage *mage = get_mage(u); + + boolean ismonster = is_monsters(u->faction); + + quicklist **dst; + + if (mage->magietyp == M_GRAY) { /* Magier mit M_GRAY bekommen weder Sprüche angezeigt noch * neue Sprüche in ihre List-of-known-spells. Das sind zb alle alten * Drachen, die noch den Skill Magie haben, und alle familiars */ @@ -480,15 +523,18 @@ updatespelllist(unit * u) } dst = get_spelllist(mage, u->faction); - for (qi=0;ql;ql_advance(&ql, &qi, 1)) { - spell * sp = (spell *)ql_get(ql, qi); - if (sp->level<=sk) { + for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { + spell *sp = (spell *) ql_get(ql, qi); + + if (sp->level <= sk) { boolean know = u_hasspell(u, sp); - if (know || sp->magietyp==M_COMMON || know_school(u->faction, sp->magietyp)) { - faction * f = u->faction; + if (know || sp->magietyp == M_COMMON + || know_school(u->faction, sp->magietyp)) { + faction *f = u->faction; - if (!know) add_spell(dst, sp); + if (!know) + add_spell(dst, sp); if (!ismonster && !already_seen(u->faction, sp)) { a_add(&f->attribs, a_new(&at_reportspell))->data.v = sp; a_add(&f->attribs, a_new(&at_seenspell))->data.v = sp; @@ -501,14 +547,14 @@ updatespelllist(unit * u) /* ------------------------------------------------------------- */ /* Erzeugen eines neuen Magiers */ -sc_mage * -create_mage(unit * u, magic_t mtyp) +sc_mage *create_mage(unit * u, magic_t mtyp) { sc_mage *mage; + attrib *a; a = a_find(u->attribs, &at_mage); - if (a!=NULL) { + if (a != NULL) { a_remove(&u->attribs, a); } a = a_add(&u->attribs, a_new(&at_mage)); @@ -521,33 +567,32 @@ create_mage(unit * u, magic_t mtyp) /* ------------------------------------------------------------- */ /* Funktionen für die Bearbeitung der List-of-known-spells */ -void -add_spell(struct quicklist ** slistp, spell * sp) +void add_spell(struct quicklist **slistp, spell * sp) { - if (ql_set_insert(slistp, sp)!=0) { - log_error(("add_spell: the list already contains the spell '%s'.\n", sp->sname)); + if (ql_set_insert(slistp, sp) != 0) { + log_error(("add_spell: the list already contains the spell '%s'.\n", + sp->sname)); } } -boolean -u_hasspell(const struct unit *u, const struct spell * sp) +boolean u_hasspell(const struct unit *u, const struct spell *sp) { - sc_mage * mage = get_mage(u); - - return (mage)?has_spell(mage->spells, sp):false; + sc_mage *mage = get_mage(u); + + return (mage) ? has_spell(mage->spells, sp) : false; } /* ------------------------------------------------------------- */ /* Eingestellte Kampfzauberstufe ermitteln */ -int -get_combatspelllevel(const unit *u, int nr) +int get_combatspelllevel(const unit * u, int nr) { sc_mage *m = get_mage(u); assert(nr < MAXCOMBATSPELLS); if (m) { int level = eff_skill(u, SK_MAGIC, u->region); + return MIN(m->combatspells[nr].level, level); } return -1; @@ -556,8 +601,7 @@ get_combatspelllevel(const unit *u, int nr) /* ------------------------------------------------------------- */ /* Kampfzauber ermitteln, setzen oder löschen */ -const spell* -get_combatspell(const unit *u, int nr) +const spell *get_combatspell(const unit * u, int nr) { sc_mage *m; @@ -572,15 +616,17 @@ get_combatspell(const unit *u, int nr) return NULL; } -void -set_combatspell(unit *u, spell *sp, struct order * ord, int level) +void set_combatspell(unit * u, spell * sp, struct order *ord, int level) { sc_mage *m = get_mage(u); + int i = -1; - if (!m) return; + + if (!m) + return; /* knowsspell prüft auf ist_magier, ist_spruch, kennt_spruch */ - if (knowsspell(u->region, u, sp) == false){ + if (knowsspell(u->region, u, sp) == false) { /* Fehler 'Spell not found' */ cmistake(u, ord, 173, MSG_MAGIC); return; @@ -596,40 +642,44 @@ set_combatspell(unit *u, spell *sp, struct order * ord, int level) return; } - if (sp->sptyp & PRECOMBATSPELL) i = 0; - else if (sp->sptyp & COMBATSPELL) i = 1; - else if (sp->sptyp & POSTCOMBATSPELL) i = 2; - assert(i>=0); + if (sp->sptyp & PRECOMBATSPELL) + i = 0; + else if (sp->sptyp & COMBATSPELL) + i = 1; + else if (sp->sptyp & POSTCOMBATSPELL) + i = 2; + assert(i >= 0); m->combatspells[i].sp = sp; m->combatspells[i].level = level; return; } -void -unset_combatspell(unit *u, spell *sp) +void unset_combatspell(unit * u, spell * sp) { sc_mage *m; + int nr = 0; + int i; m = get_mage(u); - if (!m) return; + if (!m) + return; if (!sp) { - for (i=0;icombatspells[i].sp = NULL; } - } - else if (sp->sptyp & PRECOMBATSPELL) { - if (sp != get_combatspell(u,0)) + } else if (sp->sptyp & PRECOMBATSPELL) { + if (sp != get_combatspell(u, 0)) return; } else if (sp->sptyp & COMBATSPELL) { - if (sp != get_combatspell(u,1)) { + if (sp != get_combatspell(u, 1)) { return; } nr = 1; } else if (sp->sptyp & POSTCOMBATSPELL) { - if (sp != get_combatspell(u,2)) { + if (sp != get_combatspell(u, 2)) { return; } nr = 2; @@ -641,24 +691,24 @@ unset_combatspell(unit *u, spell *sp) /* ------------------------------------------------------------- */ /* Gibt die aktuelle Anzahl der Magiepunkte der Einheit zurück */ -int -get_spellpoints(const unit * u) +int get_spellpoints(const unit * u) { sc_mage *m; m = get_mage(u); - if (!m) return 0; + if (!m) + return 0; return m->spellpoints; } -void -set_spellpoints(unit * u, int sp) +void set_spellpoints(unit * u, int sp) { sc_mage *m; m = get_mage(u); - if (!m) return; + if (!m) + return; m->spellpoints = sp; @@ -668,14 +718,15 @@ set_spellpoints(unit * u, int sp) /* * verändert die Anzahl der Magiepunkte der Einheit um +mp */ -int -change_spellpoints(unit * u, int mp) +int change_spellpoints(unit * u, int mp) { sc_mage *m; + int sp; m = get_mage(u); - if (!m) return 0; + if (!m) + return 0; /* verhindere negative Magiepunkte */ sp = MAX(m->spellpoints + mp, 0); @@ -687,13 +738,13 @@ change_spellpoints(unit * u, int mp) /* bietet die Möglichkeit, die maximale Anzahl der Magiepunkte mit * Regionszaubern oder Attributen zu beinflussen */ -static int -get_spchange(const unit * u) +static int get_spchange(const unit * u) { sc_mage *m; m = get_mage(u); - if (!m) return 0; + if (!m) + return 0; return m->spchange; } @@ -709,8 +760,7 @@ get_spchange(const unit * u) * Ermöglicht dem Magier mehr Magiepunkte zu 'speichern' */ /** TODO: at_skillmod daraus machen */ -static int -use_item_aura(const region * r, const unit * u) +static int use_item_aura(const region * r, const unit * u) { int sk, n; @@ -720,33 +770,36 @@ use_item_aura(const region * r, const unit * u) return n; } -int -max_spellpoints(const region * r, const unit * u) +int max_spellpoints(const region * r, const unit * u) { int sk; + double n, msp; + double potenz = 2.1; + double divisor = 1.2; sk = eff_skill(u, SK_MAGIC, r); - msp = u->race->maxaura*(pow(sk, potenz)/divisor+1) + get_spchange(u); + msp = u->race->maxaura * (pow(sk, potenz) / divisor + 1) + get_spchange(u); if (get_item(u, I_AURAKULUM) > 0) { msp += use_item_aura(r, u); } n = get_curseeffect(u->attribs, C_AURA, 0); - if (n>0) msp = (msp*n)/100; + if (n > 0) + msp = (msp * n) / 100; return MAX((int)msp, 0); } -int -change_maxspellpoints(unit * u, int csp) +int change_maxspellpoints(unit * u, int csp) { sc_mage *m; m = get_mage(u); - if (!m) return 0; + if (!m) + return 0; m->spchange += csp; return max_spellpoints(u->region, u); @@ -757,10 +810,10 @@ change_maxspellpoints(unit * u, int csp) * Um nur die Zahl der bereits gezauberten Sprüche zu ermitteln mit * step = 0 aufrufen. */ -int -countspells(unit *u, int step) +int countspells(unit * u, int step) { sc_mage *m; + int count; m = get_mage(u); @@ -773,7 +826,7 @@ countspells(unit *u, int step) count = m->spellcount + step; /* negative Werte abfangen. */ - m->spellcount = MAX(0,count); + m->spellcount = MAX(0, count); return m->spellcount; } @@ -783,10 +836,10 @@ countspells(unit *u, int step) * Die Grundkosten pro Stufe werden hier um 2^count erhöht. Der * Parameter count ist dabei die Anzahl der bereits gezauberten Sprüche */ -int -spellcost(unit *u, const spell * sp) +int spellcost(unit * u, const spell * sp) { int k, aura = 0; + int count = countspells(u, 0); for (k = 0; sp->components[k].type; k++) { @@ -794,7 +847,7 @@ spellcost(unit *u, const spell * sp) aura = sp->components[k].amount; } } - aura *= (1<components[k].type; k++) { - if (costtyp == SPC_LINEAR) return SPC_LINEAR; + if (costtyp == SPC_LINEAR) + return SPC_LINEAR; if (sp->components[k].cost == SPC_LINEAR) { return SPC_LINEAR; @@ -833,16 +887,16 @@ spl_costtyp(const spell * sp) * ersten Fehler abbricht, muss die Fehlermeldung später mit cancast() * generiert werden. * */ -int -eff_spelllevel(unit *u, const spell * sp, int cast_level, int range) +int eff_spelllevel(unit * u, const spell * sp, int cast_level, int range) { int k, maxlevel, needplevel; + int costtyp = SPC_FIX; - + for (k = 0; sp->components[k].type; k++) { if (cast_level == 0) - return 0; - + return 0; + if (sp->components[k].amount > 0) { /* Die Kosten für Aura sind auch von der Zahl der bereits * gezauberten Sprüche abhängig */ @@ -851,12 +905,15 @@ eff_spelllevel(unit *u, const spell * sp, int cast_level, int range) } else { needplevel = sp->components[k].amount * range; } - maxlevel = get_pooled(u, sp->components[k].type, GET_DEFAULT, needplevel*cast_level)/needplevel; - + maxlevel = + get_pooled(u, sp->components[k].type, GET_DEFAULT, + needplevel * cast_level) / needplevel; + /* sind die Kosten fix, so muss die Komponente nur einmal vorhanden * sein und der cast_level ändert sich nicht */ if (sp->components[k].cost == SPC_FIX) { - if (maxlevel < 1) cast_level = 0; + if (maxlevel < 1) + cast_level = 0; /* ansonsten wird das Minimum aus maximal möglicher Stufe und der * gewünschten gebildet */ } else if (sp->components[k].cost == SPC_LEVEL) { @@ -866,7 +923,8 @@ eff_spelllevel(unit *u, const spell * sp, int cast_level, int range) * sein, ansonsten schlägt der Spruch fehl */ } else if (sp->components[k].cost == SPC_LINEAR) { costtyp = SPC_LINEAR; - if (maxlevel < cast_level) cast_level = 0; + if (maxlevel < cast_level) + cast_level = 0; } } } @@ -886,10 +944,10 @@ eff_spelllevel(unit *u, const spell * sp, int cast_level, int range) * Je nach Kostenart werden dann die Komponenten noch mit cast_level * multipliziert. */ -void -pay_spell(unit * u, const spell * sp, int cast_level, int range) +void pay_spell(unit * u, const spell * sp, int cast_level, int range) { int k; + int resuse; for (k = 0; sp->components[k].type; k++) { @@ -900,8 +958,7 @@ pay_spell(unit * u, const spell * sp, int cast_level, int range) } if (sp->components[k].cost == SPC_LINEAR - || sp->components[k].cost == SPC_LEVEL) - { + || sp->components[k].cost == SPC_LEVEL) { resuse *= cast_level; } @@ -916,10 +973,10 @@ pay_spell(unit * u, const spell * sp, int cast_level, int range) * aber dann immer noch nicht können, vieleicht ist seine Stufe derzeit * nicht ausreichend oder die Komponenten fehlen. */ -boolean -knowsspell(const region * r, const unit * u, const spell * sp) +boolean knowsspell(const region * r, const unit * u, const spell * sp) { - sc_mage * mage; + sc_mage *mage; + /* Ist überhaupt ein gültiger Spruch angegeben? */ if (!sp || sp->id == 0) { return false; @@ -928,7 +985,7 @@ knowsspell(const region * r, const unit * u, const spell * sp) mage = get_mage(u); if (mage == NULL) { log_warning(("%s ist kein Magier, versucht aber zu zaubern.\n", - unitname(u))); + unitname(u))); return false; } /* steht der Spruch in der Spruchliste? */ @@ -939,7 +996,7 @@ knowsspell(const region * r, const unit * u, const spell * sp) } if (eff_skill(u, SK_MAGIC, u->region) >= sp->level) { log_warning(("%s ist hat die erforderliche Stufe, kennt aber %s nicht.\n", - unitname(u), spell_name(sp, default_locale))); + unitname(u), spell_name(sp, default_locale))); } return false; } @@ -959,8 +1016,10 @@ boolean cancast(unit * u, const spell * sp, int level, int range, struct order * ord) { int k; + int itemanz; - resource * reslist = NULL; + + resource *reslist = NULL; if (knowsspell(u->region, u, sp) == false) { /* Diesen Zauber kennt die Einheit nicht */ @@ -973,10 +1032,11 @@ cancast(unit * u, const spell * sp, int level, int range, struct order * ord) cmistake(u, ord, 169, MSG_MAGIC); return false; } - + for (k = 0; sp->components[k].type; ++k) { if (sp->components[k].amount > 0) { - const resource_type * rtype = sp->components[k].type; + const resource_type *rtype = sp->components[k].type; + int itemhave; /* Die Kosten für Aura sind auch von der Zahl der bereits @@ -986,31 +1046,33 @@ cancast(unit * u, const spell * sp, int level, int range, struct order * ord) } else { itemanz = sp->components[k].amount * range; } - + /* sind die Kosten stufenabhängig, so muss itemanz noch mit dem * level multipliziert werden */ - switch(sp->components[k].cost) { - case SPC_LEVEL: - case SPC_LINEAR: - itemanz *= level; - break; - case SPC_FIX: - default: - break; + switch (sp->components[k].cost) { + case SPC_LEVEL: + case SPC_LINEAR: + itemanz *= level; + break; + case SPC_FIX: + default: + break; } - + itemhave = get_pooled(u, rtype, GET_DEFAULT, itemanz); if (itemhave < itemanz) { - resource * res = malloc(sizeof(resource)); - res->number = itemanz-itemhave; + resource *res = malloc(sizeof(resource)); + + res->number = itemanz - itemhave; res->type = rtype; res->next = reslist; reslist = res; } } } - if (reslist!=NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "missing_components_list", "list", reslist)); + if (reslist != NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "missing_components_list", + "list", reslist)); return false; } return true; @@ -1028,41 +1090,51 @@ cancast(unit * u, const spell * sp, int level, int range, struct order * ord) */ double -spellpower(region * r, unit * u, const spell * sp, int cast_level, struct order * ord) +spellpower(region * r, unit * u, const spell * sp, int cast_level, + struct order *ord) { - curse * c; + curse *c; + double force = cast_level; + int elf_power = -1; - if (sp==NULL) { + if (sp == NULL) { return 0; } else { /* Bonus durch Magieturm und gesegneten Steinkreis */ - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - if (btype && btype->flags & BTF_MAGIC) ++force; + struct building *b = inside_building(u); + + const struct building_type *btype = b ? b->type : NULL; + + if (btype && btype->flags & BTF_MAGIC) + ++force; } - if (get_item(u, I_RING_OF_POWER) > 0) ++force; - if (elf_power<0) { + if (get_item(u, I_RING_OF_POWER) > 0) + ++force; + if (elf_power < 0) { elf_power = get_param_int(global.parameters, "rules.magic.elfpower", 0); } - if (elf_power && u->race==new_race[RC_ELF] && r_isforest(r)) { + if (elf_power && u->race == new_race[RC_ELF] && r_isforest(r)) { ++force; } /* Antimagie in der Zielregion */ c = get_curse(r->attribs, ct_find("antimagiczone")); if (curse_active(c)) { - unit * mage = c->magician; + unit *mage = c->magician; + force -= curse_geteffect(c); curse_changevigour(&r->attribs, c, (float)-cast_level); cmistake(u, ord, 185, MSG_MAGIC); - if (mage!=NULL && mage->faction!=NULL) { - if (force>0) { - ADDMSG(&mage->faction->msgs, msg_message("reduce_spell", "self mage region", mage, u, r)); + if (mage != NULL && mage->faction != NULL) { + if (force > 0) { + ADDMSG(&mage->faction->msgs, msg_message("reduce_spell", + "self mage region", mage, u, r)); } else { - ADDMSG(&mage->faction->msgs, msg_message("block_spell", "self mage region", mage, u, r)); + ADDMSG(&mage->faction->msgs, msg_message("block_spell", + "self mage region", mage, u, r)); } } } @@ -1070,15 +1142,18 @@ spellpower(region * r, unit * u, const spell * sp, int cast_level, struct order /* Patzerfluch-Effekt: */ c = get_curse(r->attribs, ct_find("fumble")); if (curse_active(c)) { - unit * mage = c->magician; + unit *mage = c->magician; + force -= curse_geteffect(c); curse_changevigour(&u->attribs, c, -1); cmistake(u, ord, 185, MSG_MAGIC); - if (mage!=NULL && mage->faction!=NULL) { - if (force>0) { - ADDMSG(&mage->faction->msgs, msg_message("reduce_spell", "self mage region", mage, u, r)); + if (mage != NULL && mage->faction != NULL) { + if (force > 0) { + ADDMSG(&mage->faction->msgs, msg_message("reduce_spell", + "self mage region", mage, u, r)); } else { - ADDMSG(&mage->faction->msgs, msg_message("block_spell", "self mage region", mage, u, r)); + ADDMSG(&mage->faction->msgs, msg_message("block_spell", + "self mage region", mage, u, r)); } } } @@ -1091,10 +1166,10 @@ spellpower(region * r, unit * u, const spell * sp, int cast_level, struct order /* ------------------------------------------------------------- */ /* farcasting() == 1 -> gleiche Region, da man mit Null nicht vernünfigt * rechnen kann */ -static int -farcasting(unit *magician, region *r) +static int farcasting(unit * magician, region * r) { int dist; + int mult; if (!r) { @@ -1103,11 +1178,13 @@ farcasting(unit *magician, region *r) dist = koor_distance(r->x, r->y, magician->region->x, magician->region->y); - if (dist > 24) return INT_MAX; + if (dist > 24) + return INT_MAX; mult = 1 << dist; if (dist > 1) { - if (!path_exists(magician->region, r, dist*2, allowed_fly)) mult = INT_MAX; + if (!path_exists(magician->region, r, dist * 2, allowed_fly)) + mult = INT_MAX; } return mult; @@ -1120,19 +1197,21 @@ farcasting(unit *magician, region *r) /* allgemeine Magieresistenz einer Einheit, * reduziert magischen Schaden */ -double -magic_resistance(unit *target) +double magic_resistance(unit * target) { - attrib * a; + attrib *a; + curse *c; + int n; /* Bonus durch Rassenmagieresistenz */ double probability = target->race->magres; - assert(target->number>0); - /* Magier haben einen Resistenzbonus vom Magietalent * 5%*/ - probability += effskill(target, SK_MAGIC)*0.05; + assert(target->number > 0); + + /* Magier haben einen Resistenzbonus vom Magietalent * 5% */ + probability += effskill(target, SK_MAGIC) * 0.05; /* Auswirkungen von Zaubern auf der Einheit */ c = get_curse(target->attribs, ct_find("magicresistance")); @@ -1142,22 +1221,23 @@ magic_resistance(unit *target) /* Unicorn +10 */ n = get_item(target, I_ELVENHORSE); - if (n) probability += n*0.1/target->number; + if (n) + probability += n * 0.1 / target->number; /* Auswirkungen von Zaubern auf der Region */ a = a_find(target->region->attribs, &at_curse); - while (a && a->type==&at_curse) { - curse *c = (curse*)a->data.v; + while (a && a->type == &at_curse) { + curse *c = (curse *) a->data.v; + unit *mage = c->magician; - if (mage!=NULL) { + if (mage != NULL) { if (c->type == ct_find("goodmagicresistancezone")) { if (alliedunit(mage, target->faction, HELP_GUARD)) { - probability += curse_geteffect(c)*0.01; + probability += curse_geteffect(c) * 0.01; break; } - } - else if (c->type == ct_find("badmagicresistancezone")) { + } else if (c->type == ct_find("badmagicresistancezone")) { if (alliedunit(mage, target->faction, HELP_GUARD)) { /* TODO: hier sollte doch sicher was passieren? */ a = a->next; @@ -1168,15 +1248,17 @@ magic_resistance(unit *target) a = a->next; } /* Bonus durch Artefakte */ - /* TODO (noch gibs keine)*/ + /* TODO (noch gibs keine) */ /* Bonus durch Gebäude */ { - struct building * b = inside_building(target); - const struct building_type * btype = b?b->type:NULL; + struct building *b = inside_building(target); + + const struct building_type *btype = b ? b->type : NULL; /* gesegneter Steinkreis gibt 30% dazu */ - if (btype) probability += btype->magresbonus * 0.01; + if (btype) + probability += btype->magresbonus * 0.01; } return probability; } @@ -1193,55 +1275,64 @@ magic_resistance(unit *target) */ boolean -target_resists_magic(unit *magician, void *obj, int objtyp, int t_bonus) +target_resists_magic(unit * magician, void *obj, int objtyp, int t_bonus) { double probability = 0.0; - if (magician == NULL) return true; - if (obj == NULL) return true; + if (magician == NULL) + return true; + if (obj == NULL) + return true; - switch(objtyp) { + switch (objtyp) { case TYP_UNIT: - { - int at, pa = 0; - skill * sv; - unit * u = (unit*)obj; + { + int at, pa = 0; - at = effskill(magician, SK_MAGIC); + skill *sv; - for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - int sk = effskill(u, sv->id); - if (pa < sk) pa = sk; - } + unit *u = (unit *) obj; - /* Contest */ - probability = 0.05 * (10 + pa - at); + at = effskill(magician, SK_MAGIC); - probability += magic_resistance((unit *)obj); - break; + for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { + int sk = effskill(u, sv->id); + + if (pa < sk) + pa = sk; } + /* Contest */ + probability = 0.05 * (10 + pa - at); + + probability += magic_resistance((unit *) obj); + break; + } + case TYP_REGION: /* Bonus durch Zauber */ - probability += 0.01 * get_curseeffect(((region *)obj)->attribs, C_RESIST_MAGIC, 0); + probability += + 0.01 * get_curseeffect(((region *) obj)->attribs, C_RESIST_MAGIC, 0); break; case TYP_BUILDING: /* Bonus durch Zauber */ - probability += 0.01 * get_curseeffect(((building *)obj)->attribs, C_RESIST_MAGIC, 0); + probability += + 0.01 * get_curseeffect(((building *) obj)->attribs, C_RESIST_MAGIC, 0); /* Bonus durch Typ */ - probability += 0.01 * ((building *)obj)->type->magres; + probability += 0.01 * ((building *) obj)->type->magres; break; case TYP_SHIP: /* Bonus durch Zauber */ - probability += 0.01 * get_curseeffect(((ship *)obj)->attribs, C_RESIST_MAGIC, 0); + probability += + 0.01 * get_curseeffect(((ship *) obj)->attribs, C_RESIST_MAGIC, 0); break; } - probability = MAX(0.02, probability + t_bonus*0.01); + probability = MAX(0.02, probability + t_bonus * 0.01); probability = MIN(0.98, probability); /* gibt true, wenn die Zufallszahl kleiner als die chance ist und @@ -1252,10 +1343,10 @@ target_resists_magic(unit *magician, void *obj, int objtyp, int t_bonus) /* ------------------------------------------------------------- */ -boolean -is_magic_resistant(unit *magician, unit *target, int resist_bonus) +boolean is_magic_resistant(unit * magician, unit * target, int resist_bonus) { - return (boolean)target_resists_magic(magician, target, TYP_UNIT, resist_bonus); + return (boolean) target_resists_magic(magician, target, TYP_UNIT, + resist_bonus); } /* ------------------------------------------------------------- */ @@ -1269,8 +1360,7 @@ is_magic_resistant(unit *magician, unit *target, int resist_bonus) * eben) bis zu etwa 1% bei doppelt so gut wie notwendig */ -boolean -fumble(region * r, unit * u, const spell * sp, int cast_grade) +boolean fumble(region * r, unit * u, const spell * sp, int cast_grade) { /* X ergibt Zahl zwischen 1 und 0, je kleiner, desto besser der Magier. * 0,5*40-20=0, dh wenn der Magier doppelt so gut ist, wie der Spruch @@ -1279,12 +1369,17 @@ fumble(region * r, unit * u, const spell * sp, int cast_grade) * */ int rnd = 0; - double x = (double) cast_grade / (double) eff_skill(u, SK_MAGIC, r); - int patzer = (int) (((double) x * 40.0) - 20.0); - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; - if (btype) patzer -= btype->fumblebonus; + double x = (double)cast_grade / (double)eff_skill(u, SK_MAGIC, r); + + int patzer = (int)(((double)x * 40.0) - 20.0); + + struct building *b = inside_building(u); + + const struct building_type *btype = b ? b->type : NULL; + + if (btype) + patzer -= btype->fumblebonus; /* CHAOSPATZERCHANCE 10 : +10% Chance zu Patzern */ if (sp->magietyp == M_DRAIG) { patzer += CHAOSPATZERCHANCE; @@ -1301,7 +1396,7 @@ fumble(region * r, unit * u, const spell * sp, int cast_grade) if (patzer <= 0) { return false; } - rnd = rng_int()%100; + rnd = rng_int() % 100; if (rnd > patzer) { /* Glück gehabt, kein Patzer */ @@ -1313,8 +1408,7 @@ fumble(region * r, unit * u, const spell * sp, int cast_grade) /* ------------------------------------------------------------- */ /* Dummy-Zauberpatzer, Platzhalter für speziel auf die Sprüche * zugeschnittene Patzer */ -static void -patzer(castorder *co) +static void patzer(castorder * co) { unit *mage = co->magician.u; @@ -1322,101 +1416,111 @@ patzer(castorder *co) return; } + /* Die normalen Spruchkosten müssen immer bezahlt werden, hier noch * alle weiteren Folgen eines Patzers */ -static void -do_fumble(castorder *co) +static void do_fumble(castorder * co) { - curse * c; - region * r = co->rt; - unit * u = co->magician.u; + curse *c; + + region *r = co->rt; + + unit *u = co->magician.u; + const spell *sp = co->sp; + int level = co->level; + int duration; + double effect; ADDMSG(&u->faction->msgs, msg_message("patzer", "unit region spell", - u, r, sp)); + u, r, sp)); switch (rng_int() % 10) { - case 0: - /* wenn vorhanden spezieller Patzer, ansonsten nix */ - if (sp->patzer) sp->patzer(co); - else patzer(co); - break; + case 0: + /* wenn vorhanden spezieller Patzer, ansonsten nix */ + if (sp->patzer) + sp->patzer(co); + else + patzer(co); + break; - case 1: - /* Kröte */ + case 1: + /* Kröte */ { /* 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 triggerlit of the mage gone toad. - */ - trigger * trestore = trigger_changerace(u, u->race, u->irace); + * 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 triggerlit of the mage gone toad. + */ + trigger *trestore = trigger_changerace(u, u->race, u->irace); if (chance(0.7)) { - const item_type * it_toadslime = it_find("toadslime"); - if (it_toadslime!=NULL) { + const item_type *it_toadslime = it_find("toadslime"); + + if (it_toadslime != NULL) { t_add(&trestore, trigger_giveitem(u, it_toadslime, 1)); } } - duration = rng_int()%level/2; - if (duration<2) duration = 2; + duration = rng_int() % level / 2; + if (duration < 2) + duration = 2; add_trigger(&u->attribs, "timer", trigger_timeout(duration, trestore)); u->race = new_race[RC_TOAD]; u->irace = NULL; - ADDMSG(&r->msgs, msg_message("patzer6", "unit region spell", - u, r, sp)); + ADDMSG(&r->msgs, msg_message("patzer6", "unit region spell", u, r, sp)); break; } - /* fall-through is intentional! */ + /* fall-through is intentional! */ - case 2: - /* temporärer Stufenverlust */ - duration = MAX(rng_int()%level/2, 2); - effect = -0.5*level; - c = create_curse(u, &u->attribs, ct_find("skillmod"), (float)level, duration, - effect, 1); - c->data.i = SK_MAGIC; - ADDMSG(&u->faction->msgs, msg_message("patzer2", "unit region", u, r)); - break; - case 3: - case 4: - /* Spruch schlägt fehl, alle Magiepunkte weg */ - set_spellpoints(u, 0); - ADDMSG(&u->faction->msgs, msg_message("patzer3", "unit region spell", - u, r, sp)); - break; + case 2: + /* temporärer Stufenverlust */ + duration = MAX(rng_int() % level / 2, 2); + effect = -0.5 * level; + c = + create_curse(u, &u->attribs, ct_find("skillmod"), (float)level, + duration, effect, 1); + c->data.i = SK_MAGIC; + ADDMSG(&u->faction->msgs, msg_message("patzer2", "unit region", u, r)); + break; + case 3: + case 4: + /* Spruch schlägt fehl, alle Magiepunkte weg */ + set_spellpoints(u, 0); + ADDMSG(&u->faction->msgs, msg_message("patzer3", "unit region spell", + u, r, sp)); + break; - case 5: - case 6: - /* Spruch gelingt, aber alle Magiepunkte weg */ - if (sp->sp_function==NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); - } else { - ((nspell_f)sp->sp_function)(co); - } - set_spellpoints(u, 0); - ADDMSG(&u->faction->msgs, msg_message("patzer4", "unit region spell", - u, r, sp)); - break; + case 5: + case 6: + /* Spruch gelingt, aber alle Magiepunkte weg */ + if (sp->sp_function == NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + } else { + ((nspell_f) sp->sp_function) (co); + } + set_spellpoints(u, 0); + ADDMSG(&u->faction->msgs, msg_message("patzer4", "unit region spell", + u, r, sp)); + break; - case 7: - case 8: - case 9: - default: - /* Spruch gelingt, alle nachfolgenden Sprüche werden 2^4 so teuer */ - if (sp->sp_function==NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); - } else { - ((nspell_f)sp->sp_function)(co); - } - ADDMSG(&u->faction->msgs, msg_message("patzer5", "unit region spell", - u, r, sp)); - countspells(u, 3); + case 7: + case 8: + case 9: + default: + /* Spruch gelingt, alle nachfolgenden Sprüche werden 2^4 so teuer */ + if (sp->sp_function == NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + } else { + ((nspell_f) sp->sp_function) (co); + } + ADDMSG(&u->faction->msgs, msg_message("patzer5", "unit region spell", + u, r, sp)); + countspells(u, 3); } return; @@ -1429,12 +1533,14 @@ do_fumble(castorder *co) /* Ein Magier regeneriert pro Woche W(Stufe^1.5/2+1), mindestens 1 * Zwerge nur die Hälfte */ -static double -regeneration(unit * u) +static double regeneration(unit * u) { int sk; + double aura, d; + double potenz = 1.5; + double divisor = 2.0; sk = effskill(u, SK_MAGIC); @@ -1443,24 +1549,28 @@ regeneration(unit * u) d++; /* Einfluss von Artefakten */ - /* TODO (noch gibs keine)*/ + /* TODO (noch gibs keine) */ /* Würfeln */ - aura = (rng_double() * d + rng_double() * d)/2 + 1; + aura = (rng_double() * d + rng_double() * d) / 2 + 1; aura *= MagicRegeneration(); return aura; } -void -regeneration_magiepunkte(void) +void regeneration_magiepunkte(void) { region *r; + unit *u; + int aura, auramax; + double reg_aura; + int regen; + double mod; for (r = regions; r; r = r->next) { @@ -1469,60 +1579,64 @@ regeneration_magiepunkte(void) aura = get_spellpoints(u); auramax = max_spellpoints(r, u); if (aura < auramax) { - struct building * b = inside_building(u); - const struct building_type * btype = b?b->type:NULL; + struct building *b = inside_building(u); + + const struct building_type *btype = b ? b->type : NULL; + reg_aura = regeneration(u); /* Magierturm erhöht die Regeneration um 75% */ /* Steinkreis erhöht die Regeneration um 50% */ - if (btype) reg_aura *= btype->auraregen; + if (btype) + reg_aura *= btype->auraregen; /* Bonus/Malus durch Zauber */ mod = get_curseeffect(u->attribs, C_AURA, 0); - if (mod>0) { - reg_aura = (reg_aura*mod)/100.0; + if (mod > 0) { + reg_aura = (reg_aura * mod) / 100.0; } /* Einfluss von Artefakten */ - /* TODO (noch gibs keine)*/ + /* TODO (noch gibs keine) */ /* maximal Differenz bis Maximale-Aura regenerieren - * mindestens 1 Aura pro Monat */ + * mindestens 1 Aura pro Monat */ regen = (int)reg_aura; reg_aura -= regen; - if (chance(reg_aura)) ++regen; + if (chance(reg_aura)) + ++regen; regen = MAX(1, regen); regen = MIN((auramax - aura), regen); aura += regen; - ADDMSG(&u->faction->msgs, msg_message( - "regenaura", "unit region amount", - u, r, regen)); + ADDMSG(&u->faction->msgs, msg_message("regenaura", + "unit region amount", u, r, regen)); } set_spellpoints(u, MIN(aura, auramax)); /* Zum letzten Mal Spruchliste aktualisieren */ - /*updatespelllist(u);*/ + /*updatespelllist(u); */ } } } } static boolean -verify_ship(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) +verify_ship(region * r, unit * mage, const spell * sp, spllprm * spobj, + order * ord) { ship *sh = findship(spobj->data.i); - if (sh!=NULL && sh->region!=r && (sp->sptyp & SEARCHLOCAL)) { + if (sh != NULL && sh->region != r && (sp->sptyp & SEARCHLOCAL)) { /* Burg muss in gleicher Region sein */ sh = NULL; } - if (sh==NULL) { + if (sh == NULL) { /* Burg nicht gefunden */ spobj->flag = TARGET_NOTFOUND; - ADDMSG(&mage->faction->msgs, msg_message("spellshipnotfound", - "unit region command id", mage, mage->region, ord, spobj->data.i)); + ADDMSG(&mage->faction->msgs, msg_message("spellshipnotfound", + "unit region command id", mage, mage->region, ord, spobj->data.i)); return false; } spobj->flag = 0; @@ -1531,20 +1645,21 @@ verify_ship(region * r, unit * mage, const spell * sp, spllprm * spobj, order * } static boolean -verify_building(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) +verify_building(region * r, unit * mage, const spell * sp, spllprm * spobj, + order * ord) { building *b = findbuilding(spobj->data.i); - if (b!=NULL && b->region!=r && (sp->sptyp & SEARCHLOCAL)) { + if (b != NULL && b->region != r && (sp->sptyp & SEARCHLOCAL)) { /* Burg muss in gleicher Region sein */ b = NULL; } - if (b==NULL) { + if (b == NULL) { /* Burg nicht gefunden */ spobj->flag = TARGET_NOTFOUND; - ADDMSG(&mage->faction->msgs, msg_message("spellbuildingnotfound", - "unit region command id", mage, mage->region, ord, spobj->data.i)); + ADDMSG(&mage->faction->msgs, msg_message("spellbuildingnotfound", + "unit region command id", mage, mage->region, ord, spobj->data.i)); return false; } spobj->flag = 0; @@ -1552,41 +1667,46 @@ verify_building(region * r, unit * mage, const spell * sp, spllprm * spobj, orde return true; } -message * -msg_unitnotfound(const struct unit * mage, struct order * ord, const struct spllprm * spobj) +message *msg_unitnotfound(const struct unit * mage, struct order * ord, + const struct spllprm * spobj) { /* Einheit nicht gefunden */ char tbuf[20]; - const char * uid; - if (spobj->typ==SPP_UNIT) { + const char *uid; + + if (spobj->typ == SPP_UNIT) { uid = itoa36(spobj->data.i); } else { sprintf(tbuf, "%s %s", LOC(mage->faction->locale, - parameters[P_TEMP]), itoa36(spobj->data.i)); + parameters[P_TEMP]), itoa36(spobj->data.i)); uid = tbuf; } - return msg_message("unitnotfound_id", + return msg_message("unitnotfound_id", "unit region command id", mage, mage->region, ord, uid); } static boolean -verify_unit(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) +verify_unit(region * r, unit * mage, const spell * sp, spllprm * spobj, + order * ord) { unit *u = NULL; + switch (spobj->typ) { case SPP_UNIT: u = findunit(spobj->data.i); break; case SPP_TEMP: u = findnewunit(r, mage->faction, spobj->data.i); - if (u==NULL) u = findnewunit(mage->region, mage->faction, spobj->data.i); + if (u == NULL) + u = findnewunit(mage->region, mage->faction, spobj->data.i); break; default: assert(!"shouldn't happen, this"); } - if (u!=NULL && (sp->sptyp & SEARCHLOCAL)) { - if (u->region!=r) u = NULL; + if (u != NULL && (sp->sptyp & SEARCHLOCAL)) { + if (u->region != r) + u = NULL; else if (sp->sptyp & TESTCANSEE) { if (!cansee(mage->faction, r, u, 0) && !ucontact(u, mage)) { u = NULL; @@ -1594,7 +1714,7 @@ verify_unit(region * r, unit * mage, const spell * sp, spllprm * spobj, order * } } - if (u==NULL) { + if (u == NULL) { /* Einheit nicht gefunden */ spobj->flag = TARGET_NOTFOUND; ADDMSG(&mage->faction->msgs, msg_unitnotfound(mage, ord, spobj)); @@ -1618,12 +1738,16 @@ verify_unit(region * r, unit * mage, const spell * sp, spllprm * spobj, order * /* gibt bei Misserfolg 0 zurück, bei Magieresistenz zumindeste eines * Objektes 1 und bei Erfolg auf ganzer Linie 2 */ static void -verify_targets(castorder *co, int * invalid, int * resist, int * success) +verify_targets(castorder * co, int *invalid, int *resist, int *success) { unit *mage = co->magician.u; + const spell *sp = co->sp; + region *target_r = co->rt; + spellparameter *sa = co->par; + int i; *invalid = 0; @@ -1632,22 +1756,25 @@ verify_targets(castorder *co, int * invalid, int * resist, int * success) if (sa && sa->length) { /* zuerst versuchen wir vorher nicht gefundene Objekte zu finden. - * Wurde ein Objekt durch globalsuche gefunden, obwohl der Zauber - * gar nicht global hätte suchen dürften, setzen wir das Objekt - * zurück. */ - for (i=0;ilength;i++) { - spllprm * spobj = sa->param[i]; + * Wurde ein Objekt durch globalsuche gefunden, obwohl der Zauber + * gar nicht global hätte suchen dürften, setzen wir das Objekt + * zurück. */ + for (i = 0; i < sa->length; i++) { + spllprm *spobj = sa->param[i]; - switch(spobj->typ) { + switch (spobj->typ) { case SPP_TEMP: case SPP_UNIT: - if (!verify_unit(target_r, mage, sp, spobj, co->order)) ++*invalid; + if (!verify_unit(target_r, mage, sp, spobj, co->order)) + ++ * invalid; break; case SPP_BUILDING: - if (!verify_building(target_r, mage, sp, spobj, co->order)) ++*invalid; + if (!verify_building(target_r, mage, sp, spobj, co->order)) + ++ * invalid; break; case SPP_SHIP: - if (!verify_ship(target_r, mage, sp, spobj, co->order)) ++*invalid; + if (!verify_ship(target_r, mage, sp, spobj, co->order)) + ++ * invalid; break; default: break; @@ -1655,29 +1782,33 @@ verify_targets(castorder *co, int * invalid, int * resist, int * success) } /* Nun folgen die Tests auf cansee und Magieresistenz */ - for (i=0;ilength;i++) { - spllprm * spobj = sa->param[i]; - unit * u; - building * b; - ship * sh; - region * tr; + for (i = 0; i < sa->length; i++) { + spllprm *spobj = sa->param[i]; - if (spobj->flag == TARGET_NOTFOUND) continue; - switch(spobj->typ) { + unit *u; + + building *b; + + ship *sh; + + region *tr; + + if (spobj->flag == TARGET_NOTFOUND) + continue; + switch (spobj->typ) { case SPP_TEMP: case SPP_UNIT: u = spobj->data.u; if ((sp->sptyp & TESTRESISTANCE) - && target_resists_magic(mage, u, TYP_UNIT, 0)) - { + && target_resists_magic(mage, u, TYP_UNIT, 0)) { /* Fehlermeldung */ spobj->data.i = u->no; spobj->flag = TARGET_RESISTS; ++*resist; ADDMSG(&mage->faction->msgs, msg_message("spellunitresists", - "unit region command target", - mage, mage->region, co->order, u)); + "unit region command target", + mage, mage->region, co->order, u)); break; } @@ -1688,14 +1819,13 @@ verify_targets(castorder *co, int * invalid, int * resist, int * success) b = spobj->data.b; if ((sp->sptyp & TESTRESISTANCE) - && target_resists_magic(mage, b, TYP_BUILDING, 0)) - { /* Fehlermeldung */ + && target_resists_magic(mage, b, TYP_BUILDING, 0)) { /* Fehlermeldung */ spobj->data.i = b->no; spobj->flag = TARGET_RESISTS; ++*resist; ADDMSG(&mage->faction->msgs, msg_message("spellbuildingresists", - "unit region command id", - mage, mage->region, co->order, spobj->data.i)); + "unit region command id", + mage, mage->region, co->order, spobj->data.i)); break; } ++*success; @@ -1704,13 +1834,12 @@ verify_targets(castorder *co, int * invalid, int * resist, int * success) sh = spobj->data.sh; if ((sp->sptyp & TESTRESISTANCE) - && target_resists_magic(mage, sh, TYP_SHIP, 0)) - { /* Fehlermeldung */ + && target_resists_magic(mage, sh, TYP_SHIP, 0)) { /* Fehlermeldung */ spobj->data.i = sh->no; spobj->flag = TARGET_RESISTS; ++*resist; - ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, - "spellshipresists", "ship", sh)); + ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + "spellshipresists", "ship", sh)); break; } ++*success; @@ -1718,16 +1847,15 @@ verify_targets(castorder *co, int * invalid, int * resist, int * success) case SPP_REGION: /* haben wir ein Regionsobjekt, dann wird auch dieses und - nicht target_r überprüft. */ + nicht target_r überprüft. */ tr = spobj->data.r; if ((sp->sptyp & TESTRESISTANCE) - && target_resists_magic(mage, tr, TYP_REGION, 0)) - { /* Fehlermeldung */ + && target_resists_magic(mage, tr, TYP_REGION, 0)) { /* Fehlermeldung */ spobj->flag = TARGET_RESISTS; ++*resist; ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", - "unit region command", mage, mage->region, co->order)); + "unit region command", mage, mage->region, co->order)); break; } ++*success; @@ -1743,11 +1871,12 @@ verify_targets(castorder *co, int * invalid, int * resist, int * success) } } else { /* der Zauber hat keine expliziten Parameter/Ziele, es kann sich - * aber um einen Regionszauber handeln. Wenn notwendig hier die - * Magieresistenz der Region prüfen. */ + * aber um einen Regionszauber handeln. Wenn notwendig hier die + * Magieresistenz der Region prüfen. */ if ((sp->sptyp & REGIONSPELL)) { /* Zielobjekt Region anlegen */ - spllprm * spobj = malloc(sizeof(spllprm)); + spllprm *spobj = malloc(sizeof(spllprm)); + spobj->flag = 0; spobj->typ = SPP_REGION; spobj->data.r = target_r; @@ -1761,8 +1890,8 @@ verify_targets(castorder *co, int * invalid, int * resist, int * success) if ((sp->sptyp & TESTRESISTANCE)) { if (target_resists_magic(mage, target_r, TYP_REGION, 0)) { /* Fehlermeldung */ - ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", - "unit region command", mage, mage->region, co->order)); + ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", + "unit region command", mage, mage->region, co->order)); spobj->flag = TARGET_RESISTS; ++*resist; } else { @@ -1781,15 +1910,14 @@ verify_targets(castorder *co, int * invalid, int * resist, int * success) /* Hilfsstrukturen für ZAUBERE */ /* ------------------------------------------------------------- */ -static void -free_spellparameter(spellparameter *pa) +static void free_spellparameter(spellparameter * pa) { int i; /* Elemente free'en */ - for (i=0; i < pa->length; i++) { + for (i = 0; i < pa->length; i++) { - switch(pa->param[i]->typ) { + switch (pa->param[i]->typ) { case SPP_STRING: free(pa->param[i]->data.s); break; @@ -1799,15 +1927,16 @@ free_spellparameter(spellparameter *pa) free(pa->param[i]); } - if (pa->param) free(pa->param); + if (pa->param) + free(pa->param); /* struct free'en */ free(pa); } -static int -addparam_string(const char * const param[], spllprm ** spobjp) +static int addparam_string(const char *const param[], spllprm ** spobjp) { - spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); + spllprm *spobj = *spobjp = malloc(sizeof(spllprm)); + assert(param[0]); spobj->flag = 0; @@ -1816,22 +1945,22 @@ addparam_string(const char * const param[], spllprm ** spobjp) return 1; } -static int -addparam_int(const char * const param[], spllprm ** spobjp) +static int addparam_int(const char *const param[], spllprm ** spobjp) { - spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); + spllprm *spobj = *spobjp = malloc(sizeof(spllprm)); + assert(param[0]); spobj->flag = 0; spobj->typ = SPP_INT; - spobj->data.i = atoi((char*)param[0]); + spobj->data.i = atoi((char *)param[0]); return 1; } -static int -addparam_ship(const char * const param[], spllprm ** spobjp) +static int addparam_ship(const char *const param[], spllprm ** spobjp) { - spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); + spllprm *spobj = *spobjp = malloc(sizeof(spllprm)); + int id = atoi36((const char *)param[0]); spobj->flag = 0; @@ -1840,12 +1969,12 @@ addparam_ship(const char * const param[], spllprm ** spobjp) return 1; } -static int -addparam_building(const char * const param[], spllprm ** spobjp) +static int addparam_building(const char *const param[], spllprm ** spobjp) { - spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); + spllprm *spobj = *spobjp = malloc(sizeof(spllprm)); + int id = atoi36((const char *)param[0]); - + spobj->flag = 0; spobj->typ = SPP_BUILDING; spobj->data.i = id; @@ -1853,24 +1982,28 @@ addparam_building(const char * const param[], spllprm ** spobjp) } static int -addparam_region(const char * const param[], spllprm ** spobjp, const unit * u, order * ord, plane * pl) +addparam_region(const char *const param[], spllprm ** spobjp, const unit * u, + order * ord, plane * pl) { assert(param[0]); - if (param[1]==0) { + if (param[1] == 0) { /* Fehler: Zielregion vergessen */ cmistake(u, ord, 194, MSG_MAGIC); return -1; } else { - int tx = atoi((const char*)param[0]), ty = atoi((const char*)param[1]); + int tx = atoi((const char *)param[0]), ty = atoi((const char *)param[1]); + int x = rel_to_abs(pl, u->faction, tx, 0); + int y = rel_to_abs(pl, u->faction, ty, 1); + region *rt; pnormalize(&x, &y, pl); - rt = findregion(x,y); + rt = findregion(x, y); - if (rt!=NULL) { - spllprm * spobj = *spobjp = malloc(sizeof(spllprm)); + if (rt != NULL) { + spllprm *spobj = *spobjp = malloc(sizeof(spllprm)); spobj->flag = 0; spobj->typ = SPP_REGION; @@ -1886,15 +2019,18 @@ addparam_region(const char * const param[], spllprm ** spobjp, const unit * u, o static int -addparam_unit(const char * const param[], spllprm ** spobjp, const unit * u, order * ord) +addparam_unit(const char *const param[], spllprm ** spobjp, const unit * u, + order * ord) { spllprm *spobj; + int i = 0; + sppobj_t otype = SPP_UNIT; *spobjp = NULL; - if (findparam(param[0], u->faction->locale)==P_TEMP) { - if (param[1]==NULL) { + if (findparam(param[0], u->faction->locale) == P_TEMP) { + if (param[1] == NULL) { /* Fehler: Ziel vergessen */ cmistake(u, ord, 203, MSG_MAGIC); return -1; @@ -1906,35 +2042,42 @@ addparam_unit(const char * const param[], spllprm ** spobjp, const unit * u, ord spobj = *spobjp = malloc(sizeof(spllprm)); spobj->flag = 0; spobj->typ = otype; - spobj->data.i = atoi36((const char*)param[i]); + spobj->data.i = atoi36((const char *)param[i]); - return i+1; + return i + 1; } -static spellparameter * -add_spellparameter(region *target_r, unit *u, const char *syntax, const char * const param[], int size, struct order * ord) +static spellparameter *add_spellparameter(region * target_r, unit * u, + const char *syntax, const char *const param[], int size, struct order *ord) { boolean fail = false; + int i = 0; + int p = 0; - const char * c; + + const char *c; + spellparameter *par; + int minlen = 0; - for (c=syntax;*c!=0;++c) { + for (c = syntax; *c != 0; ++c) { /* this makes sure that: * minlen("kc?") = 0 * minlen("kc+") = 1 * minlen("cccc+c?") = 4 */ - if (*c=='?') --minlen; - else if (*c!='+' && *c!='k') ++minlen; + if (*c == '?') + --minlen; + else if (*c != '+' && *c != 'k') + ++minlen; } c = syntax; /* mindestens ein Ziel (Ziellose Zauber werden nicht * geparst) */ - if (minlen && size==0) { + if (minlen && size == 0) { /* Fehler: Ziel vergessen */ cmistake(u, ord, 203, MSG_MAGIC); return 0; @@ -1948,103 +2091,108 @@ add_spellparameter(region *target_r, unit *u, const char *syntax, const char * c } par->param = malloc(size * sizeof(spllprm *)); - while (!fail && *c && ifaction->locale); - switch (pword) { - case P_REGION: - spobj = malloc(sizeof(spllprm)); - spobj->flag = 0; - spobj->typ = SPP_REGION; - spobj->data.r = u->region; + case '?': + /* tja. das sollte moeglichst nur am Ende passieren, + * weil sonst die kacke dampft. */ j = 0; ++c; + assert(*c == 0); break; - case P_UNIT: - if (ifaction->locale); + switch (pword) { + case P_REGION: + spobj = malloc(sizeof(spllprm)); + spobj->flag = 0; + spobj->typ = SPP_REGION; + spobj->data.r = u->region; + j = 0; + ++c; + break; + case P_UNIT: + if (i < size) { + j = addparam_unit(param + i, &spobj, u, ord); + ++c; + } + break; + case P_BUILDING: + case P_GEBAEUDE: + if (i < size) { + j = addparam_building(param + i, &spobj); + ++c; + } + break; + case P_SHIP: + if (i < size) { + j = addparam_ship(param + i, &spobj); + ++c; + } + break; + default: + j = -1; + break; } break; default: j = -1; break; - } - break; - default: - j = -1; - break; } - if (j<0) fail = true; + if (j < 0) + fail = true; else { - if (spobj!=NULL) par->param[p++] = spobj; + if (spobj != NULL) + par->param[p++] = spobj; i += j; } } /* im Endeffekt waren es evtl. nur p parameter (wegen TEMP) */ par->length = p; - if (fail || par->lengthlength < minlen) { cmistake(u, ord, 209, MSG_MAGIC); free_spellparameter(par); return NULL; @@ -2055,9 +2203,8 @@ add_spellparameter(region *target_r, unit *u, const char *syntax, const char * c /* ------------------------------------------------------------- */ -castorder * -new_castorder(void *u, unit *u2, const spell *sp, region *r, int lev, - double force, int range, struct order * ord, spellparameter *p) +castorder *new_castorder(void *u, unit * u2, const spell * sp, region * r, + int lev, double force, int range, struct order * ord, spellparameter * p) { castorder *corder; @@ -2076,21 +2223,19 @@ new_castorder(void *u, unit *u2, const spell *sp, region *r, int lev, } /* Hänge c-order co an die letze c-order von cll an */ -void -add_castorder(spellrank *cll, castorder *co) +void add_castorder(spellrank * cll, castorder * co) { - if (cll->begin==NULL) { + if (cll->begin == NULL) { cll->end = &cll->begin; } - + *cll->end = co; cll->end = &co->next; return; } -void -free_castorders(castorder *co) +void free_castorders(castorder * co) { castorder *co2; @@ -2100,7 +2245,8 @@ free_castorders(castorder *co) if (co2->par) { free_spellparameter(co2->par); } - if (co2->order) free_order(co2->order); + if (co2->order) + free_order(co2->order); free(co2); } return; @@ -2112,36 +2258,39 @@ free_castorders(castorder *co) **/ typedef struct familiar_data { - unit * mage; - unit * familiar; + unit *mage; + unit *familiar; } famililar_data; -boolean -is_familiar(const unit *u) +boolean is_familiar(const unit * u) { - attrib * a = a_find(u->attribs, &at_familiarmage); - return i2b(a!=NULL); + attrib *a = a_find(u->attribs, &at_familiarmage); + + return i2b(a != NULL); } static void -a_write_unit(const attrib * a, const void * owner, struct storage * store) +a_write_unit(const attrib * a, const void *owner, struct storage *store) { - unit * u = (unit*)a->data.v; + unit *u = (unit *) a->data.v; + write_unit_reference(u, store); } -static int -sm_familiar(const unit * u, const region * r, skill_t sk, int value) /* skillmod */ -{ - if (sk==SK_MAGIC) return value; +static int sm_familiar(const unit * u, const region * r, skill_t sk, int value) +{ /* skillmod */ + if (sk == SK_MAGIC) + return value; else { int mod; - unit * familiar = get_familiar(u); - if (familiar==NULL) { + + unit *familiar = get_familiar(u); + + if (familiar == NULL) { /* the familiar is dead */ return value; } - mod = eff_skill(familiar, sk, r)/2; + mod = eff_skill(familiar, sk, r) / 2; if (r != familiar->region) { mod /= distance(r, familiar->region); } @@ -2149,69 +2298,78 @@ sm_familiar(const unit * u, const region * r, skill_t sk, int value) /* skillmod } } -static void -set_familiar(unit * mage, unit * familiar) +static 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); - while (a && a->type==&at_skillmod) { - skillmod_data * smd = (skillmod_data *)a->data.v; - if (smd->special==sm_familiar) break; + attrib *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; + 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; + smd->skill = NOSKILL; } a = a_find(mage->attribs, &at_familiar); - if (a==NULL) { + if (a == NULL) { a = a_add(&mage->attribs, a_new(&at_familiar)); a->data.v = familiar; - } else assert(!a->data.v || a->data.v == familiar); + } else + assert(!a->data.v || a->data.v == familiar); /* TODO: Diese Attribute beim Tod des Familiars entfernen: */ a = a_find(familiar->attribs, &at_familiarmage); - if (a==NULL) { + if (a == NULL) { a = a_add(&familiar->attribs, a_new(&at_familiarmage)); a->data.v = mage; - } else assert(!a->data.v || a->data.v == mage); + } else + assert(!a->data.v || a->data.v == mage); } -void -remove_familiar(unit *mage) +void remove_familiar(unit * mage) { attrib *a = a_find(mage->attribs, &at_familiar); + attrib *an; + skillmod_data *smd; - if (a!=NULL) { + if (a != NULL) { a_remove(&mage->attribs, a); } a = a_find(mage->attribs, &at_skillmod); - while (a && a->type==&at_skillmod) { + while (a && a->type == &at_skillmod) { an = a->next; - smd = (skillmod_data *)a->data.v; - if (smd->special==sm_familiar) a_remove(&mage->attribs, a); + smd = (skillmod_data *) a->data.v; + if (smd->special == sm_familiar) + a_remove(&mage->attribs, a); a = an; } } -boolean -create_newfamiliar(unit * mage, unit * familiar) +boolean create_newfamiliar(unit * mage, unit * familiar) { /* 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); - - if (afam==NULL) { + + if (afam == NULL) { afam = a_add(&mage->attribs, a_new(&at_familiar)); } afam->data.v = familiar; - if (amage==NULL) { + if (amage == NULL) { amage = a_add(&familiar->attribs, a_new(&at_familiarmage)); } amage->data.v = mage; @@ -2221,43 +2379,50 @@ create_newfamiliar(unit * mage, unit * familiar) add_trigger(&mage->attribs, "destroy", trigger_killunit(familiar)); /* 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; + 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; + 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; + smd->skill = NOSKILL; } return true; } -static int -resolve_familiar(variant data, void * addr) +static int resolve_familiar(variant data, void *addr) { - unit * familiar; + unit *familiar; + int result = resolve_unit(data, &familiar); - if (result==0 && familiar) { - attrib * a = a_find(familiar->attribs, &at_familiarmage); - if (a!=NULL && a->data.v) { - unit * mage = (unit *)a->data.v; + + if (result == 0 && familiar) { + 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; + *(unit **) addr = familiar; return result; } -static int -read_familiar(attrib * a, void * owner, struct storage * store) +static int read_familiar(attrib * a, void *owner, struct storage *store) { - int result = read_reference(&a->data.v, store, read_unit_reference, resolve_familiar); - if (result==0 && a->data.v==NULL) { + int result = + read_reference(&a->data.v, store, read_unit_reference, resolve_familiar); + if (result == 0 && a->data.v == NULL) { return AT_READ_FAIL; } return AT_READ_OK; @@ -2265,8 +2430,7 @@ read_familiar(attrib * a, void * owner, struct storage * store) /* clones */ -void -create_newclone(unit * mage, unit * clone) +void create_newclone(unit * mage, unit * clone) { attrib *a; @@ -2274,14 +2438,16 @@ create_newclone(unit * mage, unit * clone) if (a == NULL) { a = a_add(&mage->attribs, a_new(&at_clone)); a->data.v = clone; - } else assert(!a->data.v || a->data.v == clone); + } else + assert(!a->data.v || a->data.v == clone); /* TODO: Diese Attribute beim Tod des Klons entfernen: */ a = a_find(clone->attribs, &at_clonemage); if (a == NULL) { a = a_add(&clone->attribs, a_new(&at_clonemage)); a->data.v = mage; - } else assert(!a->data.v || a->data.v == mage); + } else + assert(!a->data.v || a->data.v == mage); /* Wenn der Magier stirbt, wird das in destroy_unit abgefangen. * Kein Trigger, zu kompliziert. */ @@ -2290,53 +2456,58 @@ create_newclone(unit * mage, unit * clone) add_trigger(&clone->attribs, "destroy", trigger_clonedied(mage)); } -static void -set_clone(unit * mage, unit * clone) +static void set_clone(unit * mage, unit * clone) { attrib *a; a = a_find(mage->attribs, &at_clone); - if (a==NULL) { + if (a == NULL) { a = a_add(&mage->attribs, a_new(&at_clone)); a->data.v = clone; - } else assert(!a->data.v || a->data.v == clone); + } else + assert(!a->data.v || a->data.v == clone); a = a_find(clone->attribs, &at_clonemage); - if (a==NULL) { + if (a == NULL) { a = a_add(&clone->attribs, a_new(&at_clonemage)); a->data.v = mage; - } else assert(!a->data.v || a->data.v == mage); + } else + assert(!a->data.v || a->data.v == mage); } -unit * -has_clone(unit *mage) +unit *has_clone(unit * mage) { attrib *a = a_find(mage->attribs, &at_clone); - if(a) return (unit *)a->data.v; + + if (a) + return (unit *) a->data.v; return NULL; } -static int -resolve_clone(variant data, void * addr) +static int resolve_clone(variant data, void *addr) { - unit * clone; + unit *clone; + int result = resolve_unit(data, &clone); - if (result==0 && clone) { - attrib * a = a_find(clone->attribs, &at_clonemage); - if (a!=NULL && a->data.v) { - unit * mage = (unit *)a->data.v; + + if (result == 0 && clone) { + 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; + *(unit **) addr = clone; return result; } -static int -read_clone(attrib * a, void * owner, struct storage * store) +static int read_clone(attrib * a, void *owner, struct storage *store) { - int result = read_reference(&a->data.v, store, read_unit_reference, resolve_clone); - if (result==0 && a->data.v==NULL) { + int result = + read_reference(&a->data.v, store, read_unit_reference, resolve_clone); + if (result == 0 && a->data.v == NULL) { return AT_READ_FAIL; } return AT_READ_OK; @@ -2344,38 +2515,41 @@ read_clone(attrib * a, void * owner, struct storage * store) /* mages */ -static int -resolve_mage(variant data, void * addr) +static int resolve_mage(variant data, void *addr) { - unit * mage; + unit *mage; + int result = resolve_unit(data, &mage); - if (result==0 && mage) { - attrib * a = a_find(mage->attribs, &at_familiar); - if (a!=NULL && a->data.v) { - unit * familiar = (unit *)a->data.v; + + if (result == 0 && mage) { + 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; + *(unit **) addr = mage; return result; } -static int -read_magician(attrib * a, void * owner, struct storage * store) +static int read_magician(attrib * a, void *owner, struct storage *store) { - int result = read_reference(&a->data.v, store, read_unit_reference, resolve_mage); - if (result==0 && a->data.v==NULL) { + int result = + read_reference(&a->data.v, store, read_unit_reference, resolve_mage); + if (result == 0 && a->data.v == NULL) { return AT_READ_FAIL; } return AT_READ_OK; } -static int -age_unit(attrib * a) +static int age_unit(attrib * a) /* if unit is gone or dead, remove the attribute */ { - unit * u = (unit*)a->data.v; - return (u!=NULL && u->number>0)?AT_AGE_KEEP:AT_AGE_REMOVE; + unit *u = (unit *) a->data.v; + + return (u != NULL && u->number > 0) ? AT_AGE_KEEP : AT_AGE_REMOVE; } attrib_type at_familiarmage = { @@ -2418,74 +2592,88 @@ attrib_type at_clone = { ATF_UNIQUE }; -unit * -get_familiar(const unit *u) +unit *get_familiar(const unit * u) { - attrib * a = a_find(u->attribs, &at_familiar); - if (a!=NULL) { - unit * u = (unit*)a->data.v; - if (u->number>0) return u; + attrib *a = a_find(u->attribs, &at_familiar); + + if (a != NULL) { + unit *u = (unit *) a->data.v; + + if (u->number > 0) + return u; } return NULL; } -unit * -get_familiar_mage(const unit *u) +unit *get_familiar_mage(const unit * u) { - attrib * a = a_find(u->attribs, &at_familiarmage); - if (a!=NULL) { - unit * u = (unit*)a->data.v; - if (u->number>0) return u; - } - return NULL; -} + attrib *a = a_find(u->attribs, &at_familiarmage); -unit * -get_clone(const unit *u) -{ - attrib * a = a_find(u->attribs, &at_clone); - if (a!=NULL) { - unit * u = (unit*)a->data.v; - if (u->number>0) return u; - } - return NULL; -} + if (a != NULL) { + unit *u = (unit *) a->data.v; -unit * -get_clone_mage(const unit *u) -{ - attrib * a = a_find(u->attribs, &at_clonemage); - if (a!=NULL) { - unit * u = (unit*)a->data.v; - if (u->number>0) return u; + if (u->number > 0) + return u; } return NULL; } -static boolean -is_moving_ship(const region * r, const ship *sh) +unit *get_clone(const unit * u) +{ + attrib *a = a_find(u->attribs, &at_clone); + + if (a != NULL) { + unit *u = (unit *) a->data.v; + + if (u->number > 0) + return u; + } + return NULL; +} + +unit *get_clone_mage(const unit * u) +{ + attrib *a = a_find(u->attribs, &at_clonemage); + + if (a != NULL) { + unit *u = (unit *) a->data.v; + + if (u->number > 0) + return u; + } + return NULL; +} + +static boolean is_moving_ship(const region * r, const ship * sh) { const unit *u = shipowner(sh); - if (u) switch (get_keyword(u->thisorder)) { - case K_ROUTE: - case K_MOVE: - case K_FOLLOW: - return true; - } + if (u) + switch (get_keyword(u->thisorder)) { + case K_ROUTE: + case K_MOVE: + case K_FOLLOW: + return true; + } return false; } -static castorder * -cast_cmd(unit * u, order * ord) +static castorder *cast_cmd(unit * u, order * ord) { - region * r = u->region; - region * target_r = r; + region *r = u->region; + + region *target_r = r; + int level, range; + unit *familiar = NULL, *mage = u; - const char * s; - spell * sp; - plane * pl; + + const char *s; + + spell *sp; + + plane *pl; + spellparameter *args = NULL; if (LongHunger(u)) { @@ -2505,6 +2693,7 @@ cast_cmd(unit * u, order * ord) /* für Syntax ' STUFE x REGION y z ' */ if (findparam(s, u->faction->locale) == P_LEVEL) { int p = getint(); + level = MIN(p, level); if (level < 1) { /* Fehler "Das macht wenig Sinn" */ @@ -2515,24 +2704,28 @@ cast_cmd(unit * u, order * ord) } if (findparam(s, u->faction->locale) == P_REGION) { int t_x = getint(); + int t_y = getint(); - plane * pl = getplane(u->region); - t_x = rel_to_abs(pl, u->faction, t_x,0); - t_y = rel_to_abs(pl, u->faction, t_y,1); + + plane *pl = getplane(u->region); + + t_x = rel_to_abs(pl, u->faction, t_x, 0); + t_y = rel_to_abs(pl, u->faction, t_y, 1); pnormalize(&t_x, &t_y, pl); target_r = findregion(t_x, t_y); if (!target_r) { /* Fehler "Die Region konnte nicht verzaubert werden" */ ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", - "unit region command", mage, mage->region, ord)); + "unit region command", mage, mage->region, ord)); return 0; } s = getstrtoken(); } /* für Syntax ' REGION x y STUFE z ' - * hier nach REGION nochmal auf STUFE prüfen */ + * hier nach REGION nochmal auf STUFE prüfen */ if (findparam(s, u->faction->locale) == P_LEVEL) { int p = getint(); + level = MIN(p, level); if (level < 1) { /* Fehler "Das macht wenig Sinn" */ @@ -2549,12 +2742,13 @@ cast_cmd(unit * u, order * ord) sp = get_spellfromtoken(u, s, u->faction->locale); /* Vertraute können auch Zauber sprechen, die sie selbst nicht - * können. get_spellfromtoken findet aber nur jene Sprüche, die - * die Einheit beherrscht. */ + * können. get_spellfromtoken findet aber nur jene Sprüche, die + * die Einheit beherrscht. */ if (sp == NULL && is_familiar(u)) { familiar = u; mage = get_familiar_mage(u); - if (mage!=NULL) sp = get_spellfromtoken(mage, s, mage->faction->locale); + if (mage != NULL) + sp = get_spellfromtoken(mage, s, mage->faction->locale); } if (sp == NULL) { @@ -2563,9 +2757,9 @@ cast_cmd(unit * u, order * ord) return 0; } /* um testen auf spruchnamen zu unterbinden sollte vor allen - * fehlermeldungen die anzeigen das der magier diesen Spruch - * nur in diese Situation nicht anwenden kann, noch eine - * einfache Sicherheitsprüfung kommen */ + * fehlermeldungen die anzeigen das der magier diesen Spruch + * nur in diese Situation nicht anwenden kann, noch eine + * einfache Sicherheitsprüfung kommen */ if (!knowsspell(r, u, sp)) { /* vorsicht! u kann der familiar sein */ if (!familiar) { @@ -2579,24 +2773,24 @@ cast_cmd(unit * u, order * ord) return 0; } /* Auf dem Ozean Zaubern als quasi-langer Befehl können - * normalerweise nur Meermenschen, ausgenommen explizit als - * OCEANCASTABLE deklarierte Sprüche */ + * normalerweise nur Meermenschen, ausgenommen explizit als + * OCEANCASTABLE deklarierte Sprüche */ if (fval(r->terrain, SEA_REGION)) { if (u->race != new_race[RC_AQUARIAN] - && !fval(u->race, RCF_SWIM) + && !fval(u->race, RCF_SWIM) && !(sp->sptyp & OCEANCASTABLE)) { - /* Fehlermeldung */ - ADDMSG(&u->faction->msgs, msg_message("spellfail_onocean", + /* Fehlermeldung */ + ADDMSG(&u->faction->msgs, msg_message("spellfail_onocean", "unit region command", u, u->region, ord)); - return 0; - } - /* Auf bewegenden Schiffen kann man nur explizit als - * ONSHIPCAST deklarierte Zauber sprechen */ + return 0; + } + /* Auf bewegenden Schiffen kann man nur explizit als + * ONSHIPCAST deklarierte Zauber sprechen */ } else if (u->ship) { if (is_moving_ship(r, u->ship)) { if (!(sp->sptyp & ONSHIPCAST)) { /* Fehler: "Diesen Spruch kann man nicht auf einem sich - * bewegenden Schiff stehend zaubern" */ + * bewegenden Schiff stehend zaubern" */ cmistake(u, ord, 175, MSG_MAGIC); return 0; } @@ -2607,82 +2801,90 @@ cast_cmd(unit * u, order * ord) if (range > 1) { if (!(sp->sptyp & FARCASTING)) { /* Fehler "Diesen Spruch kann man nicht in die Ferne - * richten" */ + * richten" */ cmistake(u, ord, 176, MSG_MAGIC); return 0; } - if (range > 1024) { /* (2^10) weiter als 10 Regionen entfernt */ + if (range > 1024) { /* (2^10) weiter als 10 Regionen entfernt */ ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "spellfail::nocontact", - "target", target_r)); + "target", target_r)); return 0; } } /* Stufenangabe bei nicht Stufenvariierbaren Sprüchen abfangen */ if (!(sp->sptyp & SPELLLEVEL)) { int ilevel = eff_skill(u, SK_MAGIC, u->region); - if (ilevel!=level) { + + if (ilevel != level) { level = ilevel; ADDMSG(&u->faction->msgs, msg_message("spellfail::nolevel", - "mage region command", u, u->region, ord)); + "mage region command", u, u->region, ord)); } } /* Vertrautenmagie */ /* Kennt der Vertraute den Spruch, so zaubert er ganz normal. - * Ansonsten zaubert der Magier durch seinen Vertrauten, dh - * zahlt Komponenten und Aura. Dabei ist die maximale Stufe - * die des Vertrauten! - * Der Spruch wirkt dann auf die Region des Vertrauten und - * gilt nicht als Farcasting. */ + * Ansonsten zaubert der Magier durch seinen Vertrauten, dh + * zahlt Komponenten und Aura. Dabei ist die maximale Stufe + * die des Vertrauten! + * Der Spruch wirkt dann auf die Region des Vertrauten und + * gilt nicht als Farcasting. */ if (familiar || is_familiar(u)) { if ((sp->sptyp & NOTFAMILIARCAST)) { /* Fehler: "Diesen Spruch kann der Vertraute nicht zaubern" */ cmistake(u, ord, 177, MSG_MAGIC); return 0; } - if (!knowsspell(r, u, sp)) { /* Magier zaubert durch Vertrauten */ + if (!knowsspell(r, u, sp)) { /* Magier zaubert durch Vertrauten */ mage = get_familiar_mage(u); - if (range > 1) { /* Fehler! Versucht zu Farcasten */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_farcast", - "mage", mage)); + if (range > 1) { /* Fehler! Versucht zu Farcasten */ + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_farcast", + "mage", mage)); return 0; } if (distance(mage->region, r) > eff_skill(mage, SK_MAGIC, mage->region)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_toofar", - "mage", mage)); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_toofar", + "mage", mage)); return 0; } /* mage auf magier setzen, level anpassen, range für Erhöhung - * der Spruchkosten nutzen, langen Befehl des Magiers - * löschen, zaubern kann er noch */ + * der Spruchkosten nutzen, langen Befehl des Magiers + * löschen, zaubern kann er noch */ range *= 2; set_order(&mage->thisorder, NULL); - level = MIN(level, eff_skill(mage, SK_MAGIC, mage->region)/2); + level = MIN(level, eff_skill(mage, SK_MAGIC, mage->region) / 2); familiar = u; } } /* Weitere Argumente zusammenbasteln */ if (sp->parameter) { - char ** params = malloc(2*sizeof(char*)); + char **params = malloc(2 * sizeof(char *)); + int p = 0, size = 2; + for (;;) { s = getstrtoken(); - if (*s==0) break; - if (p+1>=size) { - size*=2; - params = realloc(params, sizeof(char*)*size); + if (*s == 0) + break; + if (p + 1 >= size) { + size *= 2; + params = realloc(params, sizeof(char *) * size); } params[p++] = strdup(s); } params[p] = 0; - args = add_spellparameter(target_r, mage, sp->parameter, (const char * const *)params, p, ord); - for (p=0;params[p];++p) free(params[p]); + args = + add_spellparameter(target_r, mage, sp->parameter, + (const char *const *)params, p, ord); + for (p = 0; params[p]; ++p) + free(params[p]); free(params); - if (args==NULL) { + if (args == NULL) { /* Syntax war falsch */ return 0; } } - return new_castorder(mage, familiar, sp, target_r, level, 0, range, ord, args); + return new_castorder(mage, familiar, sp, target_r, level, 0, range, ord, + args); } /* ------------------------------------------------------------- */ @@ -2703,38 +2905,43 @@ cast_cmd(unit * u, order * ord) * die Stärke/Level durch den realen Skill des Magiers */ -void -magic(void) +void magic(void) { region *r; + int rank; + castorder *co; + spellrank spellranks[MAX_SPELLRANK]; memset(spellranks, 0, sizeof(spellranks)); for (r = regions; r; r = r->next) { unit *u; - for (u = r->units; u; u = u->next) { - order * ord; - if (u->number<=0 || u->race == new_race[RC_SPELL]) + for (u = r->units; u; u = u->next) { + order *ord; + + if (u->number <= 0 || u->race == new_race[RC_SPELL]) continue; if (u->race == new_race[RC_INSECT] && r_insectstalled(r) && - !is_cursed(u->attribs, C_KAELTESCHUTZ,0)) + !is_cursed(u->attribs, C_KAELTESCHUTZ, 0)) continue; - if (fval(u, UFL_WERE|UFL_LONGACTION)) { + if (fval(u, UFL_WERE | UFL_LONGACTION)) { continue; } for (ord = u->orders; ord; ord = ord->next) { if (get_keyword(ord) == K_CAST) { - castorder * co = cast_cmd(u, ord); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); + castorder *co = cast_cmd(u, ord); + + fset(u, UFL_LONGACTION | UFL_NOTMOVING); if (co) { - const spell * sp = co->sp; + const spell *sp = co->sp; + add_castorder(&spellranks[sp->rank], co); } } @@ -2751,12 +2958,17 @@ magic(void) for (rank = 0; rank < MAX_SPELLRANK; rank++) { for (co = spellranks[rank].begin; co; co = co->next) { - order * ord = co->order; + order *ord = co->order; + int invalid, resist, success, cast_level = co->level; + boolean fumbled = false; - unit * u = co->magician.u; + + unit *u = co->magician.u; + const spell *sp = co->sp; - region * target_r = co->rt; + + region *target_r = co->rt; /* reichen die Komponenten nicht, wird der Level reduziert. */ co->level = eff_spelllevel(u, sp, cast_level, co->distance); @@ -2769,15 +2981,15 @@ magic(void) if (cast_level > co->level) { /* Sprüche mit Fixkosten werden immer auf Stufe des Spruchs - * gezaubert, co->level ist aber defaultmäßig Stufe des Magiers */ + * gezaubert, co->level ist aber defaultmäßig Stufe des Magiers */ if (spl_costtyp(sp) != SPC_FIX) { - ADDMSG(&u->faction->msgs, msg_message("missing_components", - "unit spell level", u, sp, cast_level)); + ADDMSG(&u->faction->msgs, msg_message("missing_components", + "unit spell level", u, sp, cast_level)); } } /* Prüfen, ob die realen Kosten für die gewünschten Stufe bezahlt - * werden können */ + * werden können */ if (cancast(u, sp, co->level, co->distance, ord) == false) { /* die Fehlermeldung wird in cancast generiert */ continue; @@ -2787,43 +2999,43 @@ magic(void) /* die Stärke kann durch Antimagie auf 0 sinken */ if (co->force <= 0) { co->force = 0; - ADDMSG(&u->faction->msgs, msg_message("missing_force", - "unit spell level", u, sp, co->level)); + ADDMSG(&u->faction->msgs, msg_message("missing_force", + "unit spell level", u, sp, co->level)); } /* Ziele auf Existenz prüfen und Magieresistenz feststellen. Wurde - * kein Ziel gefunden, so ist verify_targets=0. Scheitert der - * Spruch an der Magieresistenz, so ist verify_targets = 1, bei - * Erfolg auf ganzer Linie ist verify_targets= 2 - */ + * kein Ziel gefunden, so ist verify_targets=0. Scheitert der + * Spruch an der Magieresistenz, so ist verify_targets = 1, bei + * Erfolg auf ganzer Linie ist verify_targets= 2 + */ verify_targets(co, &invalid, &resist, &success); - if (success+resist==0) { + if (success + resist == 0) { /* kein Ziel gefunden, Fehlermeldungen sind in verify_targets */ /* keine kosten für den zauber */ - continue; /* äußere Schleife, nächster Zauberer */ - } else if (co->force>0 && resist>0) { + continue; /* äußere Schleife, nächster Zauberer */ + } else if (co->force > 0 && resist > 0) { /* einige oder alle Ziele waren magieresistent */ - if (success==0) { + if (success == 0) { co->force = 0; /* zwar wurde mindestens ein Ziel gefunden, das widerstand - * jedoch dem Zauber. Kosten abziehen und abbrechen. */ - ADDMSG(&u->faction->msgs, msg_message("spell_resist", "unit region spell", - u, r, sp)); + * jedoch dem Zauber. Kosten abziehen und abbrechen. */ + ADDMSG(&u->faction->msgs, msg_message("spell_resist", + "unit region spell", u, r, sp)); } } /* Auch für Patzer gibt es Erfahrung, müssen die Spruchkosten * bezahlt werden und die nachfolgenden Sprüche werden teurer */ - if (co->force>0) { + if (co->force > 0) { if (fumble(target_r, u, sp, co->level)) { /* zuerst bezahlen, dann evt in do_fumble alle Aura verlieren */ fumbled = true; } else { - if (sp->sp_function==NULL) { + if (sp->sp_function == NULL) { log_error(("spell '%s' has no function.\n", sp->sname)); co->level = 0; } else { - co->level = ((nspell_f)sp->sp_function)(co); + co->level = ((nspell_f) sp->sp_function) (co); } if (co->level <= 0) { /* Kosten nur für real benötige Stufe berechnen */ @@ -2833,7 +3045,8 @@ magic(void) } pay_spell(u, sp, co->level, co->distance); /* erst bezahlen, dann Kostenzähler erhöhen */ - if (fumbled) do_fumble(co); + if (fumbled) + do_fumble(co); countspells(u, 1); } } @@ -2841,6 +3054,7 @@ magic(void) /* Sind alle Zauber gesprochen gibts Erfahrung */ for (r = regions; r; r = r->next) { unit *u; + for (u = r->units; u; u = u->next) { if (is_mage(u) && countspells(u, 0) > 0) { produceexp(u, SK_MAGIC, u->number); @@ -2854,25 +3068,22 @@ magic(void) remove_empty_units(); } -const char * -spell_info(const spell * sp, const struct locale * lang) +const char *spell_info(const spell * sp, const struct locale *lang) { return LOC(lang, mkname("spellinfo", sp->sname)); } -const char * -spell_name(const spell * sp, const struct locale * lang) +const char *spell_name(const spell * sp, const struct locale *lang) { return LOC(lang, mkname("spell", sp->sname)); } -const char * -curse_name(const curse_type * ctype, const struct locale * lang) +const char *curse_name(const curse_type * ctype, const struct locale *lang) { return LOC(lang, mkname("spell", ctype->cname)); } -struct quicklist ** get_spelllist(struct sc_mage * mage, struct faction * f) +struct quicklist **get_spelllist(struct sc_mage *mage, struct faction *f) { if (mage) { return &mage->spells; diff --git a/src/kernel/magic.h b/src/kernel/magic.h index c3b65a038..1375f88c8 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -23,16 +23,16 @@ extern "C" { #endif #include "curse.h" -struct fighter; -struct building; -struct quicklist; + struct fighter; + struct building; + struct quicklist; /* ------------------------------------------------------------- */ -#define MAXCOMBATSPELLS 3 /* PRECOMBAT COMBAT POSTCOMBAT */ -#define MAX_SPELLRANK 9 /* Standard-Rank 5 */ -#define MAXINGREDIENT 5 /* bis zu 5 Komponenten pro Zauber */ -#define CHAOSPATZERCHANCE 10 /* +10% Chance zu Patzern */ +#define MAXCOMBATSPELLS 3 /* PRECOMBAT COMBAT POSTCOMBAT */ +#define MAX_SPELLRANK 9 /* Standard-Rank 5 */ +#define MAXINGREDIENT 5 /* bis zu 5 Komponenten pro Zauber */ +#define CHAOSPATZERCHANCE 10 /* +10% Chance zu Patzern */ /* ------------------------------------------------------------- */ @@ -46,39 +46,39 @@ struct quicklist; * Fällen das Zielobjekt lokal sein dürfte */ /* siehe auch typ_t in objtypes.h */ -typedef enum { - SPP_REGION, /* "r" : findregion(x,y) -> *region */ - SPP_UNIT, /* - : atoi36() -> int */ - SPP_TEMP, /* - : temp einheit */ - SPP_BUILDING, /* - : atoi() -> int */ - SPP_SHIP, /* - : atoi() -> int */ - SPP_STRING, /* "c" */ - SPP_INT, /* "i" : atoi() -> int */ -} sppobj_t; + typedef enum { + SPP_REGION, /* "r" : findregion(x,y) -> *region */ + SPP_UNIT, /* - : atoi36() -> int */ + SPP_TEMP, /* - : temp einheit */ + SPP_BUILDING, /* - : atoi() -> int */ + SPP_SHIP, /* - : atoi() -> int */ + SPP_STRING, /* "c" */ + SPP_INT, /* "i" : atoi() -> int */ + } sppobj_t; -typedef struct spllprm{ - sppobj_t typ; - int flag; - union { - struct region *r; - struct unit *u; - struct building *b; - struct ship *sh; - char *s; - char * xs; - int i; - } data; -} spllprm; + typedef struct spllprm { + sppobj_t typ; + int flag; + union { + struct region *r; + struct unit *u; + struct building *b; + struct ship *sh; + char *s; + char *xs; + int i; + } data; + } spllprm; -typedef struct spellparameter{ - int length; /* Anzahl der Elemente */ - struct spllprm **param; -} spellparameter; + typedef struct spellparameter { + int length; /* Anzahl der Elemente */ + struct spllprm **param; + } spellparameter; -typedef struct strarray { - int length; /* Anzahl der Elemente */ - char **strings; -} strarray; + typedef struct strarray { + int length; /* Anzahl der Elemente */ + char **strings; + } strarray; #define TARGET_RESISTS (1<<0) #define TARGET_NOTFOUND (1<<1) @@ -87,19 +87,19 @@ typedef struct strarray { /* Magierichtungen */ /* typedef unsigned char magic_t; */ -enum { - M_GRAY = 0, /* Gray */ - M_ILLAUN = 1, /* Illaun */ - M_TYBIED = 2, /* Tybied */ - M_CERDDOR = 3, /* Cerddor */ - M_GWYRRD = 4, /* Gwyrrd */ - M_DRAIG = 5, /* Draig */ - M_COMMON = 6, /* common spells */ - MAXMAGIETYP, - /* this enum is stored in the datafile, so do not change the numbers around */ - M_NONE = (magic_t) -1 -}; -extern const char *magic_school[MAXMAGIETYP]; + enum { + M_GRAY = 0, /* Gray */ + M_ILLAUN = 1, /* Illaun */ + M_TYBIED = 2, /* Tybied */ + M_CERDDOR = 3, /* Cerddor */ + M_GWYRRD = 4, /* Gwyrrd */ + M_DRAIG = 5, /* Draig */ + M_COMMON = 6, /* common spells */ + MAXMAGIETYP, + /* this enum is stored in the datafile, so do not change the numbers around */ + M_NONE = (magic_t) - 1 + }; + extern const char *magic_school[MAXMAGIETYP]; /* ------------------------------------------------------------- */ /* Magier: @@ -113,133 +113,134 @@ extern const char *magic_school[MAXMAGIETYP]; * - Spruchliste */ -typedef struct combatspell { - int level; - const struct spell * sp; -} combatspell; + typedef struct combatspell { + int level; + const struct spell *sp; + } combatspell; -typedef struct sc_mage { - magic_t magietyp; - int spellpoints; - int spchange; - int spellcount; - combatspell combatspells[MAXCOMBATSPELLS]; - struct quicklist * spells; -} sc_mage; + typedef struct sc_mage { + magic_t magietyp; + int spellpoints; + int spchange; + int spellcount; + combatspell combatspells[MAXCOMBATSPELLS]; + struct quicklist *spells; + } sc_mage; /* ------------------------------------------------------------- */ /* Zauberliste */ -typedef struct castorder { - struct castorder *next; - union { - struct unit * u; - struct fighter * fig; - } magician; /* Magier (kann vom Typ struct unit oder fighter sein) */ - struct unit *familiar; /* Vertrauter, gesetzt, wenn der Spruch durch - den Vertrauten gezaubert wird */ - const struct spell *sp; /* Spruch */ - int level; /* gewünschte Stufe oder Stufe des Magiers */ - double force; /* Stärke des Zaubers */ - struct region *rt; /* Zielregion des Spruchs */ - int distance; /* Entfernung zur Zielregion */ - struct order * order; /* Befehl */ - struct spellparameter *par; /* für weitere Parameter */ -} castorder; + typedef struct castorder { + struct castorder *next; + union { + struct unit *u; + struct fighter *fig; + } magician; /* Magier (kann vom Typ struct unit oder fighter sein) */ + struct unit *familiar; /* Vertrauter, gesetzt, wenn der Spruch durch + den Vertrauten gezaubert wird */ + const struct spell *sp; /* Spruch */ + int level; /* gewünschte Stufe oder Stufe des Magiers */ + double force; /* Stärke des Zaubers */ + struct region *rt; /* Zielregion des Spruchs */ + int distance; /* Entfernung zur Zielregion */ + struct order *order; /* Befehl */ + struct spellparameter *par; /* für weitere Parameter */ + } castorder; /* irgendwelche zauber: */ -typedef void (*spell_f) (void*); + typedef void (*spell_f) (void *); /* normale zauber: */ -typedef int (*nspell_f)(castorder*); + typedef int (*nspell_f) (castorder *); /* kampfzauber: */ -typedef int (*cspell_f) (struct fighter*, int, double, const struct spell * sp); + typedef int (*cspell_f) (struct fighter *, int, double, + const struct spell * sp); /* zauber-patzer: */ -typedef void (*pspell_f) (castorder *); + typedef void (*pspell_f) (castorder *); -typedef struct spell_component { - const struct resource_type * type; - int amount; - int cost; -} spell_component; + typedef struct spell_component { + const struct resource_type *type; + int amount; + int cost; + } spell_component; -typedef struct spell { - spellid_t id; - char *sname; - char *syntax; - char *parameter; - magic_t magietyp; - int sptyp; - int rank; /* Reihenfolge der Zauber */ - int level; /* Stufe des Zaubers */ - struct spell_component * components; - spell_f sp_function; - void (*patzer) (castorder*); -} spell; + typedef struct spell { + spellid_t id; + char *sname; + char *syntax; + char *parameter; + magic_t magietyp; + int sptyp; + int rank; /* Reihenfolge der Zauber */ + int level; /* Stufe des Zaubers */ + struct spell_component *components; + spell_f sp_function; + void (*patzer) (castorder *); + } spell; /* ------------------------------------------------------------- */ /* besondere Spruchtypen */ -#define FARCASTING (1<<0) /* ZAUBER [struct region x y] */ -#define SPELLLEVEL (1<<1) /* ZAUBER [STUFE x] */ +#define FARCASTING (1<<0) /* ZAUBER [struct region x y] */ +#define SPELLLEVEL (1<<1) /* ZAUBER [STUFE x] */ /* ID's können zu drei unterschiedlichen Entitäten gehören: Einheiten, * Gebäuden und Schiffen. */ -#define UNITSPELL (1<<2) /* ZAUBER .. [ ..] */ -#define SHIPSPELL (1<<3) /* ZAUBER .. [ ..] */ -#define BUILDINGSPELL (1<<4) /* ZAUBER .. [ ..] */ +#define UNITSPELL (1<<2) /* ZAUBER .. [ ..] */ +#define SHIPSPELL (1<<3) /* ZAUBER .. [ ..] */ +#define BUILDINGSPELL (1<<4) /* ZAUBER .. [ ..] */ #define REGIONSPELL (1<<5) /* wirkt auf struct region */ -#define PRECOMBATSPELL (1<<7) /* PRÄKAMPFZAUBER .. */ -#define COMBATSPELL (1<<8) /* KAMPFZAUBER .. */ -#define POSTCOMBATSPELL (1<<9) /* POSTKAMPFZAUBER .. */ +#define PRECOMBATSPELL (1<<7) /* PRÄKAMPFZAUBER .. */ +#define COMBATSPELL (1<<8) /* KAMPFZAUBER .. */ +#define POSTCOMBATSPELL (1<<9) /* POSTKAMPFZAUBER .. */ #define ISCOMBATSPELL (PRECOMBATSPELL|COMBATSPELL|POSTCOMBATSPELL) -#define OCEANCASTABLE (1<<10) /* Können auch nicht-Meermenschen auf - hoher See zaubern */ +#define OCEANCASTABLE (1<<10) /* Können auch nicht-Meermenschen auf + hoher See zaubern */ #define ONSHIPCAST (1<<11) /* kann auch auf von Land ablegenden - Schiffen stehend gezaubert werden */ + Schiffen stehend gezaubert werden */ /* */ #define NOTFAMILIARCAST (1<<12) #define TESTRESISTANCE (1<<13) /* alle Zielobjekte (u, s, b, r) auf - Magieresistenz prüfen */ + Magieresistenz prüfen */ #define SEARCHLOCAL (1<<14) /* Ziel muss in der target_region sein */ #define TESTCANSEE (1<<15) /* alle Zielunits auf cansee prüfen */ #define ANYTARGET (UNITSPELL|REGIONSPELL|BUILDINGSPELL|SHIPSPELL) /* wirkt auf alle objekttypen (unit, ship, building, region) */ /* Flag Spruchkostenberechnung: */ -enum{ - SPC_FIX, /* Fixkosten */ - SPC_LEVEL, /* Komponenten pro Level */ - SPC_LINEAR /* Komponenten pro Level und müssen vorhanden sein */ -}; + enum { + SPC_FIX, /* Fixkosten */ + SPC_LEVEL, /* Komponenten pro Level */ + SPC_LINEAR /* Komponenten pro Level und müssen vorhanden sein */ + }; -enum { - RS_DUMMY, - RS_FARVISION, - MAX_REGIONSPELLS -}; + enum { + RS_DUMMY, + RS_FARVISION, + MAX_REGIONSPELLS + }; /* ------------------------------------------------------------- */ /* Prototypen */ -void magic(void); + void magic(void); -void regeneration_magiepunkte(void); + void regeneration_magiepunkte(void); -extern struct attrib_type at_seenspell; -extern struct attrib_type at_mage; -extern struct attrib_type at_familiarmage; -extern struct attrib_type at_familiar; -extern struct attrib_type at_clonemage; -extern struct attrib_type at_clone; -extern struct attrib_type at_reportspell; -extern struct attrib_type at_icastle; + extern struct attrib_type at_seenspell; + extern struct attrib_type at_mage; + extern struct attrib_type at_familiarmage; + extern struct attrib_type at_familiar; + extern struct attrib_type at_clonemage; + extern struct attrib_type at_clone; + extern struct attrib_type at_reportspell; + extern struct attrib_type at_icastle; -typedef struct icastle_data { - const struct building_type * type; - struct building * building; /* reverse pointer to dissolve the object */ - int time; -} icastle_data; + typedef struct icastle_data { + const struct building_type *type; + struct building *building; /* reverse pointer to dissolve the object */ + int time; + } icastle_data; /* ------------------------------------------------------------- */ @@ -256,130 +257,143 @@ typedef struct icastle_data { */ /* Magier */ -sc_mage * create_mage(struct unit *u, magic_t mtyp); - /* macht die struct unit zu einem neuen Magier: legt die struct u->mage an - * und initialisiert den Magiertypus mit mtyp. */ -sc_mage * get_mage(const struct unit *u); - /* gibt u->mage zurück, bei nicht-Magiern *NULL */ -boolean is_mage(const struct unit *u); - /* gibt true, wenn u->mage gesetzt. */ -boolean is_familiar(const struct unit *u); - /* gibt true, wenn eine Familiar-Relation besteht. */ + sc_mage *create_mage(struct unit *u, magic_t mtyp); + /* macht die struct unit zu einem neuen Magier: legt die struct u->mage an + * und initialisiert den Magiertypus mit mtyp. */ + sc_mage *get_mage(const struct unit *u); + /* gibt u->mage zurück, bei nicht-Magiern *NULL */ + boolean is_mage(const struct unit *u); + /* gibt true, wenn u->mage gesetzt. */ + boolean is_familiar(const struct unit *u); + /* gibt true, wenn eine Familiar-Relation besteht. */ /* Sprüche */ -int get_combatspelllevel(const struct unit *u, int nr); - /* versucht, eine eingestellte maximale Kampfzauberstufe - * zurückzugeben. 0 = Maximum, -1 u ist kein Magier. */ -const spell *get_combatspell(const struct unit *u, int nr); - /* gibt den Kampfzauber nr [pre/kampf/post] oder NULL zurück */ -void set_combatspell(struct unit *u, spell *sp, struct order * ord, int level); - /* setzt Kampfzauber */ -void unset_combatspell(struct unit *u, spell *sp); - /* löscht Kampfzauber */ -void add_spell(struct quicklist ** slistp, spell *sp); - /* fügt den Spruch mit der Id spellid der Spruchliste der Einheit hinzu. */ -boolean u_hasspell(const struct unit * u, const struct spell * sp); - /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ -void update_spellbook(struct faction * f, int level); -void updatespelllist(struct unit *u); - /* fügt alle Zauber des Magiegebietes der Einheit, deren Stufe kleiner - * als das aktuelle Magietalent ist, in die Spruchliste der Einheit - * ein */ -boolean knowsspell(const struct region * r, const struct unit * u, const spell * sp); - /* prüft, ob die Einheit diesen Spruch gerade beherrscht, dh - * mindestens die erforderliche Stufe hat. Hier können auch Abfragen - * auf spezielle Antimagiezauber auf Regionen oder Einheiten eingefügt - * werden - */ + int get_combatspelllevel(const struct unit *u, int nr); + /* versucht, eine eingestellte maximale Kampfzauberstufe + * zurückzugeben. 0 = Maximum, -1 u ist kein Magier. */ + const spell *get_combatspell(const struct unit *u, int nr); + /* gibt den Kampfzauber nr [pre/kampf/post] oder NULL zurück */ + void set_combatspell(struct unit *u, spell * sp, struct order *ord, + int level); + /* setzt Kampfzauber */ + void unset_combatspell(struct unit *u, spell * sp); + /* löscht Kampfzauber */ + void add_spell(struct quicklist **slistp, spell * sp); + /* fügt den Spruch mit der Id spellid der Spruchliste der Einheit hinzu. */ + boolean u_hasspell(const struct unit *u, const struct spell *sp); + /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ + void update_spellbook(struct faction *f, int level); + void updatespelllist(struct unit *u); + /* fügt alle Zauber des Magiegebietes der Einheit, deren Stufe kleiner + * als das aktuelle Magietalent ist, in die Spruchliste der Einheit + * ein */ + boolean knowsspell(const struct region *r, const struct unit *u, + const spell * sp); + /* prüft, ob die Einheit diesen Spruch gerade beherrscht, dh + * mindestens die erforderliche Stufe hat. Hier können auch Abfragen + * auf spezielle Antimagiezauber auf Regionen oder Einheiten eingefügt + * werden + */ /* Magiepunkte */ -int get_spellpoints(const struct unit *u); - /* Gibt die aktuelle Anzahl der Magiepunkte der Einheit zurück */ -void set_spellpoints(struct unit * u, int sp); - /* setzt die Magiepunkte auf sp */ -int change_spellpoints(struct unit *u, int mp); - /* verändert die Anzahl der Magiepunkte der Einheit um +mp */ -int max_spellpoints(const struct region *r, const struct unit *u); - /* gibt die aktuell maximal möglichen Magiepunkte der Einheit zurück */ -int change_maxspellpoints(struct unit * u, int csp); - /* verändert die maximalen Magiepunkte einer Einheit */ + int get_spellpoints(const struct unit *u); + /* Gibt die aktuelle Anzahl der Magiepunkte der Einheit zurück */ + void set_spellpoints(struct unit *u, int sp); + /* setzt die Magiepunkte auf sp */ + int change_spellpoints(struct unit *u, int mp); + /* verändert die Anzahl der Magiepunkte der Einheit um +mp */ + int max_spellpoints(const struct region *r, const struct unit *u); + /* gibt die aktuell maximal möglichen Magiepunkte der Einheit zurück */ + int change_maxspellpoints(struct unit *u, int csp); + /* verändert die maximalen Magiepunkte einer Einheit */ /* Zaubern */ -extern double spellpower(struct region *r, struct unit *u, const spell *sp, int cast_level, struct order * ord); - /* ermittelt die Stärke eines Spruchs */ -boolean fumble (struct region *r, struct unit *u, const spell *sp, int cast_level); - /* true, wenn der Zauber misslingt, bei false gelingt der Zauber */ + extern double spellpower(struct region *r, struct unit *u, const spell * sp, + int cast_level, struct order *ord); + /* ermittelt die Stärke eines Spruchs */ + boolean fumble(struct region *r, struct unit *u, const spell * sp, + int cast_level); + /* true, wenn der Zauber misslingt, bei false gelingt der Zauber */ -typedef struct spellrank { - struct castorder * begin; - struct castorder ** end; -} spellrank; + typedef struct spellrank { + struct castorder *begin; + struct castorder **end; + } spellrank; -castorder *new_castorder(void *u, struct unit *familiar, const spell *sp, struct region *r, - int lev, double force, int distance, struct order * ord, spellparameter *p); - /* Zwischenspreicher für Zauberbefehle, notwendig für Prioritäten */ -void add_castorder(struct spellrank *cll, struct castorder *co); - /* Hänge c-order co an die letze c-order von cll an */ -void free_castorders(struct castorder *co); - /* Speicher wieder freigeben */ + castorder *new_castorder(void *u, struct unit *familiar, const spell * sp, + struct region *r, int lev, double force, int distance, struct order *ord, + spellparameter * p); + /* Zwischenspreicher für Zauberbefehle, notwendig für Prioritäten */ + void add_castorder(struct spellrank *cll, struct castorder *co); + /* Hänge c-order co an die letze c-order von cll an */ + void free_castorders(struct castorder *co); + /* Speicher wieder freigeben */ /* Prüfroutinen für Zaubern */ -int countspells(struct unit *u, int step); - /* erhöht den Counter für Zaubersprüche um 'step' und gibt die neue - * Anzahl der gezauberten Sprüche zurück. */ -int spellcost(struct unit *u, const spell *sp); - /* gibt die für diesen Spruch derzeit notwendigen Magiepunkte auf der - * geringstmöglichen Stufe zurück, schon um den Faktor der bereits - * zuvor gezauberten Sprüche erhöht */ -boolean cancast (struct unit *u, const spell *spruch, int eff_stufe, int distance, struct order * ord); - /* true, wenn Einheit alle Komponenten des Zaubers (incl. MP) für die - * geringstmögliche Stufe hat und den Spruch beherrscht */ -void pay_spell(struct unit *u, const spell *sp, int eff_stufe, int distance); - /* zieht die Komponenten des Zaubers aus dem Inventory der Einheit - * ab. Die effektive Stufe des gezauberten Spruchs ist wichtig für - * die korrekte Bestimmung der Magiepunktkosten */ -int eff_spelllevel(struct unit *u, const spell * sp, int cast_level, int distance); - /* ermittelt die effektive Stufe des Zaubers. Dabei ist cast_level - * die gewünschte maximale Stufe (im Normalfall Stufe des Magiers, - * bei Farcasting Stufe*2^Entfernung) */ -boolean is_magic_resistant(struct unit *magician, struct unit *target, int - resist_bonus); - /* Mapperfunktion für target_resists_magic() vom Typ struct unit. */ -extern double magic_resistance(struct unit *target); - /* gibt die Chance an, mit der einem Zauber widerstanden wird. Je - * größer, desto resistenter ist da Opfer */ -boolean target_resists_magic(struct unit *magician, void *obj, int objtyp, - int resist_bonus); - /* gibt false zurück, wenn der Zauber gelingt, true, wenn das Ziel - * widersteht */ + int countspells(struct unit *u, int step); + /* erhöht den Counter für Zaubersprüche um 'step' und gibt die neue + * Anzahl der gezauberten Sprüche zurück. */ + int spellcost(struct unit *u, const spell * sp); + /* gibt die für diesen Spruch derzeit notwendigen Magiepunkte auf der + * geringstmöglichen Stufe zurück, schon um den Faktor der bereits + * zuvor gezauberten Sprüche erhöht */ + boolean cancast(struct unit *u, const spell * spruch, int eff_stufe, + int distance, struct order *ord); + /* true, wenn Einheit alle Komponenten des Zaubers (incl. MP) für die + * geringstmögliche Stufe hat und den Spruch beherrscht */ + void pay_spell(struct unit *u, const spell * sp, int eff_stufe, int distance); + /* zieht die Komponenten des Zaubers aus dem Inventory der Einheit + * ab. Die effektive Stufe des gezauberten Spruchs ist wichtig für + * die korrekte Bestimmung der Magiepunktkosten */ + int eff_spelllevel(struct unit *u, const spell * sp, int cast_level, + int distance); + /* ermittelt die effektive Stufe des Zaubers. Dabei ist cast_level + * die gewünschte maximale Stufe (im Normalfall Stufe des Magiers, + * bei Farcasting Stufe*2^Entfernung) */ + boolean is_magic_resistant(struct unit *magician, struct unit *target, int + resist_bonus); + /* Mapperfunktion für target_resists_magic() vom Typ struct unit. */ + extern double magic_resistance(struct unit *target); + /* gibt die Chance an, mit der einem Zauber widerstanden wird. Je + * größer, desto resistenter ist da Opfer */ + boolean target_resists_magic(struct unit *magician, void *obj, int objtyp, + int resist_bonus); + /* gibt false zurück, wenn der Zauber gelingt, true, wenn das Ziel + * widersteht */ /* 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 boolean 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); + /* (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 boolean 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); -extern const char * spell_info(const struct spell * sp, const struct locale * lang); -extern const char * spell_name(const struct spell * sp, const struct locale * lang); -extern const char * curse_name(const struct curse_type * ctype, const struct locale * lang); + extern const char *spell_info(const struct spell *sp, + const struct locale *lang); + extern const char *spell_name(const struct spell *sp, + const struct locale *lang); + extern const char *curse_name(const struct curse_type *ctype, + const struct locale *lang); -extern struct message * msg_unitnotfound(const struct unit * mage, struct order * ord, const struct spllprm * spobj); -extern int FactionSpells(void); -extern struct quicklist ** get_spelllist(struct sc_mage * mage, struct faction * f); + extern struct message *msg_unitnotfound(const struct unit *mage, + struct order *ord, const struct spllprm *spobj); + extern int FactionSpells(void); + extern struct quicklist **get_spelllist(struct sc_mage *mage, + struct faction *f); -extern void write_spells(struct quicklist * slist, struct storage * store); -extern void read_spells(struct quicklist ** slistp, magic_t mtype, struct storage * store); -extern double MagicPower(void); + extern void write_spells(struct quicklist *slist, struct storage *store); + extern void read_spells(struct quicklist **slistp, magic_t mtype, + struct storage *store); + extern double MagicPower(void); #ifdef __cplusplus } diff --git a/src/kernel/message.c b/src/kernel/message.c index 3bcf10e64..75528d3fd 100644 --- a/src/kernel/message.c +++ b/src/kernel/message.c @@ -47,9 +47,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include typedef struct msg_setting { - struct msg_setting *next; - const struct message_type *type; - int level; + struct msg_setting *next; + const struct message_type *type; + int level; } msg_setting; /************ Compatibility function *************/ @@ -58,120 +58,148 @@ typedef struct msg_setting { #include static void -arg_set(variant args[], const message_type * mtype, const char * buffer, variant v) +arg_set(variant args[], const message_type * mtype, const char *buffer, + variant v) { - int i; - for (i=0;i!=mtype->nparameters;++i) { - if (!strcmp(buffer, mtype->pnames[i])) break; - } - if (i!=mtype->nparameters) { + int i; + + for (i = 0; i != mtype->nparameters; ++i) { + if (!strcmp(buffer, mtype->pnames[i])) + break; + } + if (i != mtype->nparameters) { args[i] = v; } else { - fprintf(stderr, "invalid parameter %s for message type %s\n", buffer, mtype->name); - assert(!"program aborted."); - } + fprintf(stderr, "invalid parameter %s for message type %s\n", buffer, + mtype->name); + assert(!"program aborted."); + } } -struct message * -msg_feedback(const struct unit * u, struct order * ord, const char * name, const char* sig, ...) +struct message *msg_feedback(const struct unit *u, struct order *ord, + const char *name, const char *sig, ...) { va_list marker; - const message_type * mtype = mt_find(name); + + const message_type *mtype = mt_find(name); + char paramname[64]; + const char *ic = sig; + variant args[16]; + variant var; + memset(args, 0, sizeof(args)); - if (ord==NULL) ord = u->thisorder; + if (ord == NULL) + ord = u->thisorder; if (!mtype) { log_error(("trying to create message of unknown type \"%s\"\n", name)); - return msg_message("missing_feedback", "unit region command name", u, u->region, ord, name); + return msg_message("missing_feedback", "unit region command name", u, + u->region, ord, name); } - var.v = (void*)u; + var.v = (void *)u; arg_set(args, mtype, "unit", var); - var.v = (void*)u->region; + var.v = (void *)u->region; arg_set(args, mtype, "region", var); - var.v = (void*)ord; + var.v = (void *)ord; arg_set(args, mtype, "command", var); va_start(marker, sig); - while (*ic && !isalnum(*ic)) ic++; + while (*ic && !isalnum(*ic)) + ic++; while (*ic) { - char * oc = paramname; + char *oc = paramname; + int i; - while (isalnum(*ic)) *oc++ = *ic++; + while (isalnum(*ic)) + *oc++ = *ic++; *oc = '\0'; - for (i=0;i!=mtype->nparameters;++i) { - if (!strcmp(paramname, mtype->pnames[i])) break; + for (i = 0; i != mtype->nparameters; ++i) { + if (!strcmp(paramname, mtype->pnames[i])) + break; } - if (i!=mtype->nparameters) { - if (mtype->types[i]->vtype==VAR_VOIDPTR) { - args[i].v = va_arg(marker, void*); - } else if (mtype->types[i]->vtype==VAR_INT) { + if (i != mtype->nparameters) { + if (mtype->types[i]->vtype == VAR_VOIDPTR) { + args[i].v = va_arg(marker, void *); + } else if (mtype->types[i]->vtype == VAR_INT) { args[i].i = va_arg(marker, int); } else { assert(!"unknown variant type"); } } else { - log_error(("invalid parameter %s for message type %s\n", paramname, mtype->name)); + log_error(("invalid parameter %s for message type %s\n", paramname, + mtype->name)); assert(!"program aborted."); } - while (*ic && !isalnum(*ic)) ic++; + while (*ic && !isalnum(*ic)) + ic++; } va_end(marker); return msg_create(mtype, args); } -message * -msg_message(const char * name, const char* sig, ...) - /* msg_message("oops_error", "unit region command", u, r, cmd) */ +message *msg_message(const char *name, const char *sig, ...) + /* msg_message("oops_error", "unit region command", u, r, cmd) */ { va_list marker; - const message_type * mtype = mt_find(name); + + const message_type *mtype = mt_find(name); + char paramname[64]; + const char *ic = sig; + variant args[16]; + memset(args, 0, sizeof(args)); - + if (!mtype) { log_warning(("trying to create message of unknown type \"%s\"\n", name)); - if (strcmp(name, "missing_message")!=0) { + if (strcmp(name, "missing_message") != 0) { return msg_message("missing_message", "name", name); } return NULL; } - + va_start(marker, sig); - while (*ic && !isalnum(*ic)) ic++; + while (*ic && !isalnum(*ic)) + ic++; while (*ic) { - char * oc = paramname; + char *oc = paramname; + int i; - - while (isalnum(*ic)) *oc++ = *ic++; + + while (isalnum(*ic)) + *oc++ = *ic++; *oc = '\0'; - - for (i=0;i!=mtype->nparameters;++i) { - if (!strcmp(paramname, mtype->pnames[i])) break; + + for (i = 0; i != mtype->nparameters; ++i) { + if (!strcmp(paramname, mtype->pnames[i])) + break; } - if (i!=mtype->nparameters) { - if (mtype->types[i]->vtype==VAR_VOIDPTR) { - args[i].v = va_arg(marker, void*); - } else if (mtype->types[i]->vtype==VAR_INT) { + if (i != mtype->nparameters) { + if (mtype->types[i]->vtype == VAR_VOIDPTR) { + args[i].v = va_arg(marker, void *); + } else if (mtype->types[i]->vtype == VAR_INT) { args[i].i = va_arg(marker, int); } else { assert(!"unknown variant type"); } } else { - log_error(("invalid parameter %s for message type %s\n", paramname, mtype->name)); + log_error(("invalid parameter %s for message type %s\n", paramname, + mtype->name)); assert(!"program aborted."); } - while (*ic && !isalnum(*ic)) ic++; + while (*ic && !isalnum(*ic)) + ic++; } va_end(marker); @@ -181,11 +209,11 @@ msg_message(const char * name, const char* sig, ...) static void caddmessage(region * r, faction * f, const char *s, msg_t mtype, int level) { - message * m = NULL; + message *m = NULL; #define LOG_ENGLISH #ifdef LOG_ENGLISH - if (f && f->locale!=default_locale) { + if (f && f->locale != default_locale) { log_warning(("message for locale \"%s\": %s\n", locale_name(f->locale), s)); } #endif @@ -221,41 +249,45 @@ caddmessage(region * r, faction * f, const char *s, msg_t mtype, int level) assert(f); m = add_message(&f->msgs, m); } else { - if (f==NULL) add_message(&r->msgs, m); - else r_addmessage(r, f, m); + if (f == NULL) + add_message(&r->msgs, m); + else + r_addmessage(r, f, m); } break; default: assert(!"Ungültige Msg-Klasse!"); } - if (m) msg_release(m); + if (m) + msg_release(m); } -void -addmessage(region * r, faction * f, const char *s, msg_t mtype, int level) +void addmessage(region * r, faction * f, const char *s, msg_t mtype, int level) { caddmessage(r, f, s, mtype, level); } -void -cmistake(const unit * u, struct order *ord, int mno, int mtype) +void cmistake(const unit * u, struct order *ord, int mno, int mtype) { static char msgname[20]; + unused(mtype); - if (is_monsters(u->faction)) return; + if (is_monsters(u->faction)) + return; sprintf(msgname, "error%d", mno); ADDMSG(&u->faction->msgs, msg_feedback(u, ord, msgname, "")); } -extern unsigned int new_hashstring(const char* s); +extern unsigned int new_hashstring(const char *s); -void -free_messagelist(message_list * msgs) +void free_messagelist(message_list * msgs) { - struct mlist ** mlistptr = &msgs->begin; + struct mlist **mlistptr = &msgs->begin; + while (*mlistptr) { - struct mlist * ml = *mlistptr; + struct mlist *ml = *mlistptr; + *mlistptr = ml->next; msg_release(ml->msg); free(ml); @@ -263,21 +295,19 @@ free_messagelist(message_list * msgs) free(msgs); } -message * -add_message(message_list** pm, message * m) +message *add_message(message_list ** pm, message * m) { - if (!lomem && m!=NULL) { - struct mlist * mnew = malloc(sizeof(struct mlist)); - if (*pm==NULL) { - *pm = malloc(sizeof(message_list)); - (*pm)->end=&(*pm)->begin; - } - mnew->msg = msg_addref(m); - mnew->next = NULL; - *((*pm)->end) = mnew; - (*pm)->end=&mnew->next; - } - return m; + if (!lomem && m != NULL) { + struct mlist *mnew = malloc(sizeof(struct mlist)); + + if (*pm == NULL) { + *pm = malloc(sizeof(message_list)); + (*pm)->end = &(*pm)->begin; + } + mnew->msg = msg_addref(m); + mnew->next = NULL; + *((*pm)->end) = mnew; + (*pm)->end = &mnew->next; + } + return m; } - - diff --git a/src/kernel/message.h b/src/kernel/message.h index c3e6e3fbe..6d81b417b 100644 --- a/src/kernel/message.h +++ b/src/kernel/message.h @@ -24,37 +24,40 @@ extern "C" { #include -struct message; -struct faction; -struct msglevel; + struct message; + struct faction; + struct msglevel; -struct message_type; + struct message_type; -typedef struct message_list { - struct mlist { - struct mlist * next; - struct message *msg; - } * begin, **end; -} message_list; + typedef struct message_list { + struct mlist { + struct mlist *next; + struct message *msg; + } *begin, **end; + } message_list; -extern void free_messagelist(message_list * msgs); + extern void free_messagelist(message_list * msgs); -typedef struct msglevel { - /* used to set specialized msg-levels */ - struct msglevel *next; - const struct message_type *type; - int level; -} msglevel; + typedef struct msglevel { + /* used to set specialized msg-levels */ + struct msglevel *next; + const struct message_type *type; + 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, - const char * name, const char* sig, ...); -extern 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); + extern struct message *msg_message(const char *name, const char *sig, ...); + extern 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 *m); + void addmessage(struct region *r, struct faction *f, const char *s, + msg_t mtype, int level); #define ADDMSG(msgs, mcreate) { message * m = mcreate; if (m) { assert(m->refcount>=1); add_message(msgs, m); msg_release(m); } } -extern void cmistake(const struct unit * u, struct order *ord, int mno, int mtype); + extern void cmistake(const struct unit *u, struct order *ord, int mno, + int mtype); #ifdef __cplusplus } #endif diff --git a/src/kernel/move.c b/src/kernel/move.c index dbcedd03d..a3b1219e3 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -68,39 +68,43 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -int * storms; +int *storms; typedef struct traveldir { - int no; - direction_t dir; - int age; + int no; + direction_t dir; + int age; } traveldir; static attrib_type at_traveldir = { - "traveldir", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, /* Weil normales Aging an ungünstiger Stelle */ - a_writechars, - a_readchars + "traveldir", + DEFAULT_INIT, + DEFAULT_FINALIZE, + DEFAULT_AGE, /* Weil normales Aging an ungünstiger Stelle */ + a_writechars, + a_readchars }; typedef struct follower { - struct follower * next; - unit * uf; - unit * ut; - const region_list * route_end; + struct follower *next; + unit *uf; + unit *ut; + const region_list *route_end; } follower; static void -get_followers(unit * target, region * r, const region_list * route_end, follower ** followers) +get_followers(unit * target, region * r, const region_list * route_end, + follower ** followers) { - unit * uf; - for (uf=r->units;uf;uf=uf->next) { + unit *uf; + + for (uf = r->units; uf; uf = uf->next) { if (fval(uf, UFL_FOLLOWING) && !fval(uf, UFL_NOTMOVING)) { - const attrib * a = a_findc(uf->attribs, &at_follow); + const attrib *a = a_findc(uf->attribs, &at_follow); + if (a && a->data.v == target) { - follower * fnew = malloc(sizeof(follower)); + follower *fnew = malloc(sizeof(follower)); + fnew->uf = uf; fnew->ut = target; fnew->route_end = route_end; @@ -111,63 +115,59 @@ get_followers(unit * target, region * r, const region_list * route_end, follower } } -static void -shiptrail_init(attrib *a) +static void shiptrail_init(attrib * a) { - a->data.v = calloc(1, sizeof(traveldir)); + a->data.v = calloc(1, sizeof(traveldir)); +} + +static void shiptrail_finalize(attrib * a) +{ + free(a->data.v); +} + +static int shiptrail_age(attrib * a) +{ + traveldir *t = (traveldir *) (a->data.v); + + t->age--; + return (t->age > 0) ? AT_AGE_KEEP : AT_AGE_REMOVE; +} + +static int shiptrail_read(attrib * a, void *owner, struct storage *store) +{ + traveldir *t = (traveldir *) (a->data.v); + + t->no = store->r_int(store); + t->dir = (direction_t) store->r_int(store); + t->age = store->r_int(store); + return AT_READ_OK; } static void -shiptrail_finalize(attrib *a) +shiptrail_write(const attrib * a, const void *owner, struct storage *store) { - free(a->data.v); -} + traveldir *t = (traveldir *) (a->data.v); -static int -shiptrail_age(attrib *a) -{ - traveldir *t = (traveldir *)(a->data.v); - - t->age--; - return (t->age>0)?AT_AGE_KEEP:AT_AGE_REMOVE; -} - -static int -shiptrail_read(attrib *a, void * owner, struct storage * store) -{ - traveldir *t = (traveldir *)(a->data.v); - - t->no = store->r_int(store); - t->dir = (direction_t)store->r_int(store); - t->age = store->r_int(store); - return AT_READ_OK; -} - -static void -shiptrail_write(const attrib * a, const void * owner, struct storage * store) -{ - traveldir *t = (traveldir *)(a->data.v); store->w_int(store, t->no); store->w_int(store, t->dir); store->w_int(store, t->age); } attrib_type at_shiptrail = { - "traveldir_new", - shiptrail_init, - shiptrail_finalize, - shiptrail_age, - shiptrail_write, - shiptrail_read + "traveldir_new", + shiptrail_init, + shiptrail_finalize, + shiptrail_age, + shiptrail_write, + shiptrail_read }; -static int -age_speedup(attrib *a) +static int age_speedup(attrib * a) { if (a->data.sa[0] > 0) { a->data.sa[0] = a->data.sa[0] - a->data.sa[1]; } - return (a->data.sa[0]>0)?AT_AGE_KEEP:AT_AGE_REMOVE; + return (a->data.sa[0] > 0) ? AT_AGE_KEEP : AT_AGE_REMOVE; } attrib_type at_speedup = { @@ -180,65 +180,74 @@ attrib_type at_speedup = { /* ------------------------------------------------------------- */ -direction_t -getdirection(const struct locale * lang) +direction_t getdirection(const struct locale * lang) { - return finddirection(getstrtoken(), lang); + return finddirection(getstrtoken(), lang); } + /* ------------------------------------------------------------- */ static attrib_type at_driveweight = { - "driveweight", NULL, NULL, NULL, NULL, NULL + "driveweight", NULL, NULL, NULL, NULL, NULL }; -static boolean -entrance_allowed(const struct unit * u, const struct region * r) +static boolean entrance_allowed(const struct unit *u, const struct region *r) { #ifdef REGIONOWNERS - faction * owner = region_get_owner(r); - if (owner == NULL || u->faction == owner) return true; - if (alliedfaction(rplane(r), owner, u->faction, HELP_TRAVEL)) return true; + faction *owner = region_get_owner(r); + + if (owner == NULL || u->faction == owner) + return true; + if (alliedfaction(rplane(r), owner, u->faction, HELP_TRAVEL)) + return true; return false; #else return true; #endif } -int -personcapacity(const unit *u) +int personcapacity(const unit * u) { - int cap = u->race->weight+u->race->capacity; - return cap; + int cap = u->race->weight + u->race->capacity; + + return cap; } -static int -eff_weight(const unit *u) +static int eff_weight(const unit * u) { - attrib *a = a_find(u->attribs, &at_driveweight); + attrib *a = a_find(u->attribs, &at_driveweight); - if (a) return weight(u) + a->data.i; + if (a) + return weight(u) + a->data.i; - return weight(u); + return weight(u); } static void -get_transporters(const item * itm, int * p_animals, int *p_acap, int * p_vehicles, int * p_vcap) +get_transporters(const item * itm, int *p_animals, int *p_acap, int *p_vehicles, + int *p_vcap) { int vehicles = 0, vcap = 0; + int animals = 0, acap = 0; - for (;itm!=NULL;itm=itm->next) { - const item_type * itype = itm->type; - if (itype->capacity>0) { + for (; itm != NULL; itm = itm->next) { + const item_type *itype = itm->type; + + if (itype->capacity > 0) { if (itype->flags & ITF_ANIMAL) { animals += itm->number; - if (acap==0) acap = itype->capacity; - assert(acap==itype->capacity || !"animals with different capacity not supported"); + if (acap == 0) + acap = itype->capacity; + assert(acap == itype->capacity + || !"animals with different capacity not supported"); } if (itype->flags & ITF_VEHICLE) { vehicles += itm->number; - if (vcap==0) vcap = itype->capacity; - assert(vcap==itype->capacity || !"vehicles with different capacity not supported"); + if (vcap == 0) + vcap = itype->capacity; + assert(vcap == itype->capacity + || !"vehicles with different capacity not supported"); } } } @@ -248,20 +257,21 @@ get_transporters(const item * itm, int * p_animals, int *p_acap, int * p_vehicle *p_acap = acap; } -static int -ridingcapacity(unit * u) +static int ridingcapacity(unit * u) { int vehicles = 0, vcap = 0; + int animals = 0, acap = 0; get_transporters(u->items, &animals, &acap, &vehicles, &vcap); /* Man trägt sein eigenes Gewicht plus seine Kapazität! Die Menschen - ** tragen nichts (siehe walkingcapacity). Ein Wagen zählt nur, wenn er - ** von zwei Pferden gezogen wird */ + ** tragen nichts (siehe walkingcapacity). Ein Wagen zählt nur, wenn er + ** von zwei Pferden gezogen wird */ animals = MIN(animals, effskill(u, SK_RIDING) * u->number * 2); - if (fval(u->race, RCF_HORSE)) animals += u->number; + if (fval(u->race, RCF_HORSE)) + animals += u->number; /* maximal diese Pferde können zum Ziehen benutzt werden */ vehicles = MIN(animals / HORSESNEEDED, vehicles); @@ -269,18 +279,20 @@ ridingcapacity(unit * u) return vehicles * vcap + animals * acap; } -int -walkingcapacity(const struct unit * u) +int walkingcapacity(const struct unit *u) { int n, tmp, people, pferde_fuer_wagen; + int wagen_ohne_pferde, wagen_mit_pferden, wagen_mit_trollen; + int vehicles = 0, vcap = 0; + int animals = 0, acap = 0; get_transporters(u->items, &animals, &acap, &vehicles, &vcap); /* Das Gewicht, welches die Pferde tragen, plus das Gewicht, welches - * die Leute tragen */ + * die Leute tragen */ pferde_fuer_wagen = MIN(animals, effskill(u, SK_RIDING) * u->number * 4); if (fval(u->race, RCF_HORSE)) { @@ -312,14 +324,16 @@ walkingcapacity(const struct unit * u) n += people * personcapacity(u); /* Goliathwasser */ tmp = get_effect(u, oldpotiontype[P_STRONG]); - if (tmp>0) { + if (tmp > 0) { int horsecap = olditemtype[I_HORSE]->capacity; - if (tmp>people) tmp = people; + + if (tmp > people) + tmp = people; n += tmp * (horsecap - personcapacity(u)); } /* change_effect wird in ageing gemacht */ tmp = get_item(u, I_TROLLBELT); - n += MIN(people, tmp) * (STRENGTHMULTIPLIER-1) * personcapacity(u); + n += MIN(people, tmp) * (STRENGTHMULTIPLIER - 1) * personcapacity(u); return n; } @@ -331,107 +345,117 @@ enum { E_CANWALK_TOOHEAVY }; -static int -canwalk(unit * u) +static int canwalk(unit * u) { - int maxwagen, maxpferde; + int maxwagen, maxpferde; + int vehicles = 0, vcap = 0; + int animals = 0, acap = 0; /* workaround: monsters are too stupid to drop items, therefore they have - * infinite carrying capacity */ + * infinite carrying capacity */ - if (is_monsters(u->faction)) return E_CANWALK_OK; + if (is_monsters(u->faction)) + return E_CANWALK_OK; get_transporters(u->items, &animals, &acap, &vehicles, &vcap); - maxwagen = effskill(u, SK_RIDING) * u->number * 2; - if (u->race == new_race[RC_TROLL]) { - maxwagen = MAX(maxwagen, u->number / 4); - } - maxpferde = effskill(u, SK_RIDING) * u->number * 4 + u->number; + maxwagen = effskill(u, SK_RIDING) * u->number * 2; + if (u->race == new_race[RC_TROLL]) { + maxwagen = MAX(maxwagen, u->number / 4); + } + maxpferde = effskill(u, SK_RIDING) * u->number * 4 + u->number; - if (animals > maxpferde) - return E_CANWALK_TOOMANYHORSES; + if (animals > maxpferde) + return E_CANWALK_TOOMANYHORSES; - if (walkingcapacity(u) - eff_weight(u) >= 0) - return E_CANWALK_OK; + if (walkingcapacity(u) - eff_weight(u) >= 0) + return E_CANWALK_OK; - /* Stimmt das Gewicht, impliziert dies hier, daß alle Wagen ohne - * Zugpferde/-trolle als Fracht aufgeladen wurden: zu viele Pferde hat - * die Einheit nicht zum Ziehen benutzt, also nicht mehr Wagen gezogen - * als erlaubt. */ + /* Stimmt das Gewicht, impliziert dies hier, daß alle Wagen ohne + * Zugpferde/-trolle als Fracht aufgeladen wurden: zu viele Pferde hat + * die Einheit nicht zum Ziehen benutzt, also nicht mehr Wagen gezogen + * als erlaubt. */ - if (vehicles > maxwagen) - return E_CANWALK_TOOMANYCARTS; - /* Es muß nicht zwingend an den Wagen liegen, aber egal... (man - * könnte z.B. auch 8 Eisen abladen, damit ein weiterer Wagen als - * Fracht draufpaßt) */ + if (vehicles > maxwagen) + return E_CANWALK_TOOMANYCARTS; + /* Es muß nicht zwingend an den Wagen liegen, aber egal... (man + * könnte z.B. auch 8 Eisen abladen, damit ein weiterer Wagen als + * Fracht draufpaßt) */ - return E_CANWALK_TOOHEAVY; + return E_CANWALK_TOOHEAVY; } -boolean -canfly(unit *u) +boolean canfly(unit * u) { - if (get_item(u, I_PEGASUS) >= u->number && effskill(u, SK_RIDING) >= 4) - return true; - - if (fval(u->race, RCF_FLY)) return true; - - if (get_movement(&u->attribs, MV_FLY)) return true; - - return false; -} - -boolean -canswim(unit *u) -{ - if (get_item(u, I_DOLPHIN) >= u->number && effskill(u, SK_RIDING) >= 4) + if (get_item(u, I_PEGASUS) >= u->number && effskill(u, SK_RIDING) >= 4) return true; - if (u->race->flags & RCF_FLY) return true; + if (fval(u->race, RCF_FLY)) + return true; - if (u->race->flags & RCF_SWIM) return true; - - if (get_movement(&u->attribs, MV_FLY)) return true; - - if (get_movement(&u->attribs, MV_SWIM)) return true; + if (get_movement(&u->attribs, MV_FLY)) + return true; return false; } -static int -canride(unit * u) +boolean canswim(unit * u) +{ + if (get_item(u, I_DOLPHIN) >= u->number && effskill(u, SK_RIDING) >= 4) + return true; + + if (u->race->flags & RCF_FLY) + return true; + + if (u->race->flags & RCF_SWIM) + return true; + + if (get_movement(&u->attribs, MV_FLY)) + return true; + + if (get_movement(&u->attribs, MV_SWIM)) + return true; + + return false; +} + +static int canride(unit * u) { int horses = 0, maxhorses, unicorns = 0, maxunicorns; - int skill = effskill(u, SK_RIDING); - item * itm; - static const item_type * it_horse = 0; - static const item_type * it_elvenhorse = 0; - static const item_type * it_charger = 0; - if (it_horse==0) { + int skill = effskill(u, SK_RIDING); + + item *itm; + + static const item_type *it_horse = 0; + + static const item_type *it_elvenhorse = 0; + + static const item_type *it_charger = 0; + + if (it_horse == 0) { it_horse = it_find("horse"); it_elvenhorse = it_find("elvenhorse"); it_charger = it_find("charger"); } - for (itm=u->items;itm;itm=itm->next) { - if (itm->type==it_horse || itm->type==it_charger) { + for (itm = u->items; itm; itm = itm->next) { + if (itm->type == it_horse || itm->type == it_charger) { horses += itm->number; - } else if (itm->type==it_elvenhorse) { + } else if (itm->type == it_elvenhorse) { unicorns += itm->number; } } - maxunicorns = (skill/5) * u->number; + maxunicorns = (skill / 5) * u->number; maxhorses = skill * u->number * 2; - if(!(u->race->flags & RCF_HORSE) + if (!(u->race->flags & RCF_HORSE) && ((horses == 0 && unicorns == 0) - || horses > maxhorses || unicorns > maxunicorns)) { - return 0; + || horses > maxhorses || unicorns > maxunicorns)) { + return 0; } if (ridingcapacity(u) - eff_weight(u) >= 0) { @@ -444,65 +468,70 @@ canride(unit * u) return 0; } -static boolean -cansail(const region * r, ship * sh) +static boolean cansail(const region * r, ship * sh) { /* sonst ist construction:: size nicht ship_type::maxsize */ - assert(!sh->type->construction || sh->type->construction->improvement == NULL); + assert(!sh->type->construction + || sh->type->construction->improvement == NULL); - if (sh->type->construction && sh->size!=sh->type->construction->maxsize) { + if (sh->type->construction && sh->size != sh->type->construction->maxsize) { return false; } else { int n = 0, p = 0; + int mweight = shipcapacity(sh); + int mcabins = sh->type->cabins; getshipweight(sh, &n, &p); - if (n > mweight) return false; - if (mcabins && p > mcabins) return false; + if (n > mweight) + return false; + if (mcabins && p > mcabins) + return false; } return true; } -int -enoughsailors(const ship * sh, const region * r) +int enoughsailors(const ship * sh, const region * r) { - int n; - unit *u; + int n; - n = 0; + unit *u; - for (u = r->units; u; u = u->next) { - if (u->ship == sh) - n += eff_skill(u, SK_SAILING, r) * u->number; + n = 0; + + for (u = r->units; u; u = u->next) { + if (u->ship == sh) + n += eff_skill(u, SK_SAILING, r) * u->number; } - return n >= sh->type->sumskill; + return n >= sh->type->sumskill; } + /* ------------------------------------------------------------- */ -static ship * -do_maelstrom(region *r, unit *u) +static ship *do_maelstrom(region * r, unit * u) { int damage; - ship * sh = u->ship; - damage = rng_int()%75 + rng_int()%75 - eff_skill(u, SK_SAILING, r)*4; + ship *sh = u->ship; + + damage = rng_int() % 75 + rng_int() % 75 - eff_skill(u, SK_SAILING, r) * 4; if (damage <= 0) { return sh; } - damage_ship(u->ship, 0.01*damage); + damage_ship(u->ship, 0.01 * damage); if (sh->damage >= sh->size * DAMAGE_SCALE) { ADDMSG(&u->faction->msgs, msg_message("entermaelstrom", - "region ship damage sink", r, sh, damage, 1)); + "region ship damage sink", r, sh, damage, 1)); remove_ship(&sh->region->ships, sh); return NULL; } ADDMSG(&u->faction->msgs, msg_message("entermaelstrom", - "region ship damage sink", r, sh, damage, 0)); + "region ship damage sink", r, sh, damage, 0)); return u->ship; } @@ -513,14 +542,13 @@ do_maelstrom(region *r, unit *u) * themselves * - to report the region to the traveller */ -void -travelthru(const unit * u, region * r) +void travelthru(const unit * u, region * r) { attrib *ru = a_add(&r->attribs, a_new(&at_travelunit)); fset(r, RF_TRAVELUNIT); - ru->data.v = (void*)u; + ru->data.v = (void *)u; /* the first and last region of the faction gets reset, because travelthrough * could be in regions that are located before the [first, last] interval, @@ -530,30 +558,32 @@ travelthru(const unit * u, region * r) #endif } -static void -leave_trail(ship * sh, region * from, region_list *route) +static void leave_trail(ship * sh, region * from, region_list * route) { - region * r = from; - - while (route!=NULL) { - region * rn = route->data; + region *r = from; + + while (route != NULL) { + region *rn = route->data; + direction_t dir = reldirection(r, rn); /* TODO: we cannot leave a trail into special directions - * if we use this kind of direction-attribute */ - if (dir=0) { - traveldir * td = NULL; - attrib * a = a_find(r->attribs, &at_shiptrail); + * if we use this kind of direction-attribute */ + if (dir < MAXDIRECTIONS && dir >= 0) { + traveldir *td = NULL; - while (a!=NULL && a->type==&at_shiptrail) { - td = (traveldir *)a->data.v; - if (td->no == sh->no) break; + attrib *a = a_find(r->attribs, &at_shiptrail); + + while (a != NULL && a->type == &at_shiptrail) { + td = (traveldir *) a->data.v; + if (td->no == sh->no) + break; a = a->next; } - if (a == NULL || a->type!=&at_shiptrail) { + if (a == NULL || a->type != &at_shiptrail) { a = a_add(&(r->attribs), a_new(&at_shiptrail)); - td = (traveldir *)a->data.v; + td = (traveldir *) a->data.v; td->no = sh->no; } td->dir = dir; @@ -565,24 +595,26 @@ leave_trail(ship * sh, region * from, region_list *route) } static void -mark_travelthru(const unit * u, region * r, const region_list * route, const region_list * route_end) +mark_travelthru(const unit * u, region * r, const region_list * route, + const region_list * route_end) { /* kein travelthru in der letzten region! */ - while (route!=route_end) { + while (route != route_end) { travelthru(u, r); r = route->data; route = route->next; } } -ship * -move_ship(ship * sh, region * from, region * to, region_list * route) +ship *move_ship(ship * sh, region * from, region * to, region_list * route) { unit **iunit = &from->units; + unit **ulist = &to->units; + boolean trail = (route == NULL); - if (from!=to) { + if (from != to) { translist(&from->ships, &to->ships, sh); sh->region = to; } @@ -591,14 +623,16 @@ move_ship(ship * sh, region * from, region * to, region_list * route) trail = true; } - while (*iunit!=NULL) { + while (*iunit != NULL) { unit *u = *iunit; + assert(u->region == from); if (u->ship == sh) { - if (route!=NULL) mark_travelthru(u, from, route, NULL); - if (from!=to) { - u->ship = NULL; /* damit move_unit() kein leave() macht */ + if (route != NULL) + mark_travelthru(u, from, route, NULL); + if (from != to) { + u->ship = NULL; /* damit move_unit() kein leave() macht */ move_unit(u, to, ulist); ulist = &u->next; u->ship = sh; @@ -607,40 +641,45 @@ move_ship(ship * sh, region * from, region * to, region_list * route) produceexp(u, SK_SAILING, u->number); } } - if (*iunit == u) iunit=&u->next; + if (*iunit == u) + iunit = &u->next; } - + return sh; } -static boolean -is_freezing(const unit * u) +static boolean is_freezing(const unit * u) { - if (u->race!=new_race[RC_INSECT]) return false; - if (is_cursed(u->attribs, C_KAELTESCHUTZ, 0)) return false; + if (u->race != new_race[RC_INSECT]) + return false; + if (is_cursed(u->attribs, C_KAELTESCHUTZ, 0)) + return false; return true; } -static boolean -ship_allowed(const struct ship * sh, const region * r) +static boolean ship_allowed(const struct ship *sh, const region * r) { int c = 0; - static const building_type * bt_harbour=NULL; - if (bt_harbour == NULL) bt_harbour=bt_find("harbour"); + static const building_type *bt_harbour = NULL; + + if (bt_harbour == NULL) + bt_harbour = bt_find("harbour"); if (r_insectstalled(r)) { /* insekten dürfen nicht hier rein. haben wir welche? */ - unit * u; + unit *u; - for (u=sh->region->units;u!=NULL;u=u->next) { - if (u->ship!=sh) continue; + for (u = sh->region->units; u != NULL; u = u->next) { + if (u->ship != sh) + continue; if (is_freezing(u)) { - unit * captain = shipowner(sh); + unit *captain = shipowner(sh); + if (captain) { - ADDMSG(&captain->faction->msgs, msg_message("detectforbidden", - "unit region", u, r)); + ADDMSG(&captain->faction->msgs, msg_message("detectforbidden", + "unit region", u, r)); } return false; @@ -648,24 +687,26 @@ ship_allowed(const struct ship * sh, const region * r) } } - if (buildingtype_exists(r, bt_harbour, true)) return true; - for (c=0;sh->type->coasts[c]!=NULL;++c) { - if (sh->type->coasts[c] == r->terrain) return true; + if (buildingtype_exists(r, bt_harbour, true)) + return true; + for (c = 0; sh->type->coasts[c] != NULL; ++c) { + if (sh->type->coasts[c] == r->terrain) + return true; } return false; } -static boolean -flying_ship(const ship * sh) +static boolean flying_ship(const ship * sh) { - if (sh->type->flags & SFL_FLY) return true; - if (sh->flags & SF_FLYING) return true; + if (sh->type->flags & SFL_FLY) + return true; + if (sh->flags & SF_FLYING) + return true; return false; } -static void -set_coast(ship * sh, region * r, region * rnext) +static void set_coast(ship * sh, region * r, region * rnext) { if (sh->type->flags & SFL_NOCOAST) { sh->coast = NODIRECTION; @@ -677,32 +718,37 @@ set_coast(ship * sh, region * r, region * rnext) } } -static float -damage_drift(void) +static float damage_drift(void) { static float value = -1.0F; - if (value<0) { + + if (value < 0) { value = get_param_flt(global.parameters, "rules.ship.damage_drift", 0.02F); } return value; } -static void -drifting_ships(region * r) +static void drifting_ships(region * r) { direction_t d; if (fval(r->terrain, SEA_REGION)) { - ship** shp = &r->ships; + ship **shp = &r->ships; + while (*shp) { - ship * sh = *shp; - region * rnext = NULL; - region_list * route = NULL; + ship *sh = *shp; + + region *rnext = NULL; + + region_list *route = NULL; + unit *firstu = NULL, *captain; + int d_offset; + direction_t dir = 0; - if (sh->type->fishing>0) { + if (sh->type->fishing > 0) { sh->flags |= SF_FISHING; } @@ -714,31 +760,36 @@ drifting_ships(region * r) /* Kapitän bestimmen */ for (captain = r->units; captain; captain = captain->next) { - if (captain->ship != sh) continue; - if (firstu==NULL) firstu = captain; + if (captain->ship != sh) + continue; + if (firstu == NULL) + firstu = captain; if (eff_skill(captain, SK_SAILING, r) >= sh->type->cptskill) { break; } } /* Kapitän da? Beschädigt? Genügend Matrosen? - * Genügend leicht? Dann ist alles OK. */ + * Genügend leicht? Dann ist alles OK. */ - assert(sh->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ - if (captain && sh->size == sh->type->construction->maxsize && enoughsailors(sh, r) && cansail(r, sh)) { + assert(sh->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (captain && sh->size == sh->type->construction->maxsize + && enoughsailors(sh, r) && cansail(r, sh)) { shp = &sh->next; continue; } /* Auswahl einer Richtung: Zuerst auf Land, dann - * zufällig. Falls unmögliches Resultat: vergiß es. */ + * zufällig. Falls unmögliches Resultat: vergiß es. */ d_offset = rng_int() % MAXDIRECTIONS; for (d = 0; d != MAXDIRECTIONS; ++d) { - region * rn; - dir = (direction_t)((d + d_offset) % MAXDIRECTIONS); + region *rn; + + dir = (direction_t) ((d + d_offset) % MAXDIRECTIONS); rn = rconnect(r, dir); - if (rn!=NULL && fval(rn->terrain, SAIL_INTO) && ship_allowed(sh, rn)) { + if (rn != NULL && fval(rn->terrain, SAIL_INTO) && ship_allowed(sh, rn)) { rnext = rn; - if (!fval(rnext->terrain, SEA_REGION)) break; + if (!fval(rnext->terrain, SEA_REGION)) + break; } } @@ -748,99 +799,108 @@ drifting_ships(region * r) } /* Das Schiff und alle Einheiten darin werden nun von r - * nach rnext verschoben. Danach eine Meldung. */ + * nach rnext verschoben. Danach eine Meldung. */ add_regionlist(&route, rnext); set_coast(sh, r, rnext); sh = move_ship(sh, r, rnext, route); free_regionlist(route); - if (firstu!=NULL) { + if (firstu != NULL) { unit *u, *lastu = NULL; - message * msg = msg_message("ship_drift", "ship dir", sh, dir); - for (u=firstu;u;u=u->next) { - if (u->ship==sh && !fval(u->faction, FFL_MARK)) { + + message *msg = msg_message("ship_drift", "ship dir", sh, dir); + + for (u = firstu; u; u = u->next) { + if (u->ship == sh && !fval(u->faction, FFL_MARK)) { fset(u->faction, FFL_MARK); add_message(&u->faction->msgs, msg); lastu = u->next; } } - for (u=firstu;u!=lastu;u=u->next) { + for (u = firstu; u != lastu; u = u->next) { freset(u->faction, FFL_MARK); } msg_release(msg); } - - if (sh!=NULL) { + + if (sh != NULL) { fset(sh, SF_DRIFTED); damage_ship(sh, damage_drift()); - if (sh->damage>=sh->size * DAMAGE_SCALE) { + if (sh->damage >= sh->size * DAMAGE_SCALE) { remove_ship(&sh->region->ships, sh); } } - if (*shp == sh) shp = &sh->next; + if (*shp == sh) + shp = &sh->next; } } } -static boolean -present(region * r, unit * u) +static boolean present(region * r, unit * u) { - return (boolean) (u && u->region == r); + return (boolean) (u && u->region == r); } -static void -caught_target(region * r, unit * u) +static void caught_target(region * r, unit * u) { - attrib * a = a_find(u->attribs, &at_follow); + attrib *a = a_find(u->attribs, &at_follow); - /* Verfolgungen melden */ - /* Misserfolgsmeldung, oder bei erfolgreichem Verfolgen unter - * Umstaenden eine Warnung. */ + /* Verfolgungen melden */ + /* Misserfolgsmeldung, oder bei erfolgreichem Verfolgen unter + * Umstaenden eine Warnung. */ - if (a) { - unit * target = (unit*)a->data.v; + if (a) { + unit *target = (unit *) a->data.v; if (!present(r, target)) { ADDMSG(&u->faction->msgs, msg_message("followfail", "unit follower", - target, u)); + target, u)); } else if (!alliedunit(target, u->faction, HELP_ALL) - && cansee(target->faction, r, u, 0)) - { - ADDMSG(&target->faction->msgs, msg_message("followdetect", - "unit follower", target, u)); + && cansee(target->faction, r, u, 0)) { + ADDMSG(&target->faction->msgs, msg_message("followdetect", + "unit follower", target, u)); } - } + } } /* TODO: Unsichtbarkeit bedenken ! */ -static unit * -bewegung_blockiert_von(unit * reisender, region * r) +static unit *bewegung_blockiert_von(unit * reisender, region * r) { unit *u; - int perception = 0; - boolean contact = false; - unit * guard = NULL; - if (fval(reisender->race, RCF_ILLUSIONARY)) return NULL; - for (u=r->units;u && !contact;u=u->next) { + int perception = 0; + + boolean contact = false; + + unit *guard = NULL; + + if (fval(reisender->race, RCF_ILLUSIONARY)) + return NULL; + for (u = r->units; u && !contact; u = u->next) { if (is_guard(u, GUARD_TRAVELTHRU)) { int sk = eff_skill(u, SK_PERCEPTION, r); - if (invisible(reisender, u) >= reisender->number) continue; - if (u->faction == reisender->faction) contact = true; - else if (ucontact(u, reisender)) contact = true; - else if (alliedunit(u, reisender->faction, HELP_GUARD)) contact = true; - else if (sk>=perception) { + + if (invisible(reisender, u) >= reisender->number) + continue; + if (u->faction == reisender->faction) + contact = true; + else if (ucontact(u, reisender)) + contact = true; + else if (alliedunit(u, reisender->faction, HELP_GUARD)) + contact = true; + else if (sk >= perception) { perception = sk; guard = u; } } } if (!contact && guard) { - double prob = 0.3; /* 30% base chance */ + double prob = 0.3; /* 30% base chance */ + prob += 0.1 * (perception - eff_stealth(reisender, r)); prob += 0.1 * MIN(guard->number, get_item(guard, I_AMULET_OF_TRUE_SEEING)); @@ -851,62 +911,73 @@ bewegung_blockiert_von(unit * reisender, region * r) return NULL; } -static boolean -is_guardian_u(const unit * guard, unit *u, unsigned int mask) +static boolean is_guardian_u(const unit * guard, unit * u, unsigned int mask) { - if (guard->faction == u->faction) return false; - if (is_guard(guard, mask) == 0) return false; - if (alliedunit(guard, u->faction, HELP_GUARD)) return false; - if (ucontact(guard, u)) return false; - if (!cansee(guard->faction, u->region, u, 0)) return false; - + if (guard->faction == u->faction) + return false; + if (is_guard(guard, mask) == 0) + return false; + if (alliedunit(guard, u->faction, HELP_GUARD)) + return false; + if (ucontact(guard, u)) + return false; + if (!cansee(guard->faction, u->region, u, 0)) + return false; + return true; } -static boolean -is_guardian_r(const unit * guard) +static boolean is_guardian_r(const unit * guard) { - if (guard->number == 0) return false; - if (besieged(guard)) return false; + if (guard->number == 0) + return false; + if (besieged(guard)) + return false; /* if region_owners exist then they may be guardians: */ if (guard->building && rule_region_owners() && fval(guard, UFL_OWNER)) { - faction * owner = region_get_owner(guard->region); - if (owner==guard->faction) { - building * bowner = largestbuilding(guard->region, &cmp_taxes, false); - if (bowner==guard->building) { + faction *owner = region_get_owner(guard->region); + + if (owner == guard->faction) { + building *bowner = largestbuilding(guard->region, &cmp_taxes, false); + + if (bowner == guard->building) { return true; } } } - if ((guard->flags&UFL_GUARD)==0) return false; - if (!armedmen(guard, true) && !fval(guard->race, RCF_UNARMEDGUARD)) return false; + if ((guard->flags & UFL_GUARD) == 0) + return false; + if (!armedmen(guard, true) && !fval(guard->race, RCF_UNARMEDGUARD)) + return false; return true; } boolean is_guard(const struct unit * u, int mask) { - return is_guardian_r(u) && (getguard(u) & mask)!=0; + return is_guardian_r(u) && (getguard(u) & mask) != 0; } #define MAXGUARDCACHE 16 /** returns the guard which prevents 'u' from doing 'mask' actions in 'r'. */ -unit * -is_guarded(region * r, unit * u, unsigned int mask) +unit *is_guarded(region * r, unit * u, unsigned int mask) { unit *u2 = NULL; + int i, noguards = 1; - static unit * guardcache[MAXGUARDCACHE], * lastguard; /* STATIC_XCALL: used across calls */ + + static unit *guardcache[MAXGUARDCACHE], *lastguard; /* STATIC_XCALL: used across calls */ + static int gamecookie = -1; if (!fval(r, RF_GUARDED)) { return NULL; } - if (gamecookie!=global.cookie) { - if (gamecookie>=0) { + if (gamecookie != global.cookie) { + if (gamecookie >= 0) { /* clear the previous turn's cache */ memset(guardcache, 0, sizeof(guardcache)); lastguard = NULL; @@ -914,21 +985,22 @@ is_guarded(region * r, unit * u, unsigned int mask) gamecookie = global.cookie; } - if (lastguard && lastguard->region==r) { + if (lastguard && lastguard->region == r) { if (is_guardian_u(lastguard, u, mask)) { return lastguard; } } - for (i=0;i!=MAXGUARDCACHE;++i) { - unit * guard = guardcache[i]; - if (guard && guard!=lastguard && guard->region==r) { + for (i = 0; i != MAXGUARDCACHE; ++i) { + unit *guard = guardcache[i]; + + if (guard && guard != lastguard && guard->region == r) { noguards = 0; if (is_guardian_u(guard, u, mask)) { lastguard = guard; return guard; } - if (u2==guard) { + if (u2 == guard) { /* same guard twice signals we've tested everyone */ return NULL; } @@ -942,12 +1014,13 @@ is_guarded(region * r, unit * u, unsigned int mask) /* at this point, u2 is the last unit we tested to * be a guard (and failed), or NULL * i is the position of the first free slot in the cache */ - - for (u2 = (u2?u2->next:r->units); u2; u2=u2->next) { + + for (u2 = (u2 ? u2->next : r->units); u2; u2 = u2->next) { if (is_guardian_r(u2)) { noguards = 0; /* u2 is a guard, so worth remembering */ - if (i0 && i 0 && i < MAXGUARDCACHE) { + guardcache[i] = guardcache[i - 1]; } if (noguards) { @@ -968,79 +1041,94 @@ is_guarded(region * r, unit * u, unsigned int mask) return NULL; } -static const char *shortdirections[MAXDIRECTIONS] = -{ - "dir_nw", - "dir_ne", - "dir_east", - "dir_se", - "dir_sw", - "dir_west" +static const char *shortdirections[MAXDIRECTIONS] = { + "dir_nw", + "dir_ne", + "dir_east", + "dir_se", + "dir_sw", + "dir_west" }; -static void -cycle_route(order * ord, unit *u, int gereist) +static void cycle_route(order * ord, unit * u, int gereist) { - int bytes, cm = 0; - char tail[1024], * bufp = tail; - char neworder[2048]; - const char *token; - direction_t d = NODIRECTION; - boolean paused = false; - boolean pause; - order * norder; + int bytes, cm = 0; + + char tail[1024], *bufp = tail; + + char neworder[2048]; + + const char *token; + + direction_t d = NODIRECTION; + + boolean paused = false; + + boolean pause; + + order *norder; + size_t size = sizeof(tail) - 1; - if (get_keyword(ord) != K_ROUTE) return; - tail[0] = '\0'; + if (get_keyword(ord) != K_ROUTE) + return; + tail[0] = '\0'; init_tokens(ord); skip_token(); - neworder[0]=0; - for (cm=0;;++cm) { - const struct locale * lang = u->faction->locale; - pause = false; - token = getstrtoken(); - d = finddirection(token, lang); - if(d == D_PAUSE) { - pause = true; - } else if (d == NODIRECTION) { - break; - } - if (cmfaction->locale; + + pause = false; + token = getstrtoken(); + d = finddirection(token, lang); + if (d == D_PAUSE) { + pause = true; + } else if (d == NODIRECTION) { + break; + } + if (cm < gereist) { + /* hier sollte keine PAUSE auftreten */ + assert(!pause); if (!pause) { - const char * loc = LOC(lang, shortdirections[d]); - if (bufp!=tail) { + const char *loc = LOC(lang, shortdirections[d]); + + if (bufp != tail) { bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } bytes = (int)strlcpy(bufp, loc, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } - } - else if (strlen(neworder)>sizeof(neworder)/2) break; - else if (cm == gereist && !paused && pause) { - const char * loc = LOC(lang, parameters[P_PAUSE]); + } else if (strlen(neworder) > sizeof(neworder) / 2) + break; + else if (cm == gereist && !paused && pause) { + const char *loc = LOC(lang, parameters[P_PAUSE]); + bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, loc, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - paused = true; - } - else if (pause) { - /* da PAUSE nicht in ein shortdirections[d] umgesetzt wird (ist - * hier keine normale direction), muss jede PAUSE einzeln - * herausgefiltert und explizit gesetzt werden */ - if (neworder[0]) strcat(neworder, " "); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + paused = true; + } else if (pause) { + /* da PAUSE nicht in ein shortdirections[d] umgesetzt wird (ist + * hier keine normale direction), muss jede PAUSE einzeln + * herausgefiltert und explizit gesetzt werden */ + if (neworder[0]) + strcat(neworder, " "); strcat(neworder, LOC(lang, parameters[P_PAUSE])); - } else { - if (neworder[0]) strcat(neworder, " "); - strcat(neworder, LOC(lang, shortdirections[d])); - } - } + } else { + if (neworder[0]) + strcat(neworder, " "); + strcat(neworder, LOC(lang, shortdirections[d])); + } + } if (neworder[0]) { norder = create_order(K_ROUTE, u->faction->locale, "%s %s", neworder, tail); @@ -1051,10 +1139,9 @@ cycle_route(order * ord, unit *u, int gereist) free_order(norder); } -static boolean -transport(unit * ut, unit * u) +static boolean transport(unit * ut, unit * u) { - order * ord; + order *ord; if (LongHunger(u) || fval(ut->region->terrain, SEA_REGION)) { return false; @@ -1072,41 +1159,44 @@ transport(unit * ut, unit * u) return false; } -static boolean -can_move(const unit * u) +static boolean can_move(const unit * u) { - if (u->race->flags & RCF_CANNOTMOVE) return false; - if (get_movement(&u->attribs, MV_CANNOTMOVE)) return false; + if (u->race->flags & RCF_CANNOTMOVE) + return false; + if (get_movement(&u->attribs, MV_CANNOTMOVE)) + return false; return true; } -static void -init_transportation(void) +static void init_transportation(void) { region *r; - for (r=regions; r; r=r->next) { + for (r = regions; r; r = r->next) { unit *u; /* This is just a simple check for non-corresponding K_TRANSPORT/ * K_DRIVE. This is time consuming for an error check, but there * doesn't seem to be an easy way to speed this up. */ - for (u=r->units; u; u=u->next) { - if (get_keyword(u->thisorder) == K_DRIVE && can_move(u) && !fval(u, UFL_NOTMOVING) && !LongHunger(u)) { - unit * ut; + for (u = r->units; u; u = u->next) { + if (get_keyword(u->thisorder) == K_DRIVE && can_move(u) + && !fval(u, UFL_NOTMOVING) && !LongHunger(u)) { + unit *ut; init_tokens(u->thisorder); skip_token(); ut = getunit(r, u->faction); if (ut == NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, + "feedback_unit_not_found", "")); continue; } if (!transport(ut, u)) { if (cansee(u->faction, r, ut, 0)) { cmistake(u, u->thisorder, 286, MSG_MOVE); } else { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "feedback_unit_not_found", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, + "feedback_unit_not_found", "")); } } } @@ -1115,10 +1205,11 @@ init_transportation(void) /* This calculates the weights of all transported units and * adds them to an internal counter which is used by travel () to * calculate effective weight and movement. */ - + if (!fval(r->terrain, SEA_REGION)) { - for (u=r->units; u; u=u->next) { - order * ord; + for (u = r->units; u; u = u->next) { + order *ord; + int w = 0; for (ord = u->orders; ord; ord = ord->next) { @@ -1126,10 +1217,12 @@ init_transportation(void) init_tokens(ord); skip_token(); for (;;) { - unit * ut = getunit(r, u->faction); + unit *ut = getunit(r, u->faction); - if (ut == NULL) break; - if (get_keyword(ut->thisorder) == K_DRIVE && can_move(ut) && !fval(ut, UFL_NOTMOVING) && !LongHunger(ut)) { + if (ut == NULL) + break; + if (get_keyword(ut->thisorder) == K_DRIVE && can_move(ut) + && !fval(ut, UFL_NOTMOVING) && !LongHunger(ut)) { init_tokens(ut->thisorder); skip_token(); if (getunit(r, ut->faction) == u) { @@ -1139,69 +1232,86 @@ init_transportation(void) } } } - if (w > 0) a_add(&u->attribs, a_new(&at_driveweight))->data.i = w; + if (w > 0) + a_add(&u->attribs, a_new(&at_driveweight))->data.i = w; } } } } -static boolean -roadto(const region * r, direction_t dir) +static boolean roadto(const region * r, direction_t dir) { /* wenn es hier genug strassen gibt, und verbunden ist, und es dort - * genug strassen gibt, dann existiert eine strasse in diese richtung */ - region * r2; - static const curse_type * roads_ct = NULL; + * genug strassen gibt, dann existiert eine strasse in diese richtung */ + region *r2; - if (dir>=MAXDIRECTIONS || dir<0) return false; + static const curse_type *roads_ct = NULL; + + if (dir >= MAXDIRECTIONS || dir < 0) + return false; r2 = rconnect(r, dir); - if (r == NULL || r2 == NULL) return false; + if (r == NULL || r2 == NULL) + return false; - if (roads_ct == NULL) roads_ct = ct_find("magicstreet"); - if (roads_ct!=NULL) { - if (get_curse(r->attribs, roads_ct)!=NULL) return true; - if (get_curse(r2->attribs, roads_ct)!=NULL) return true; + if (roads_ct == NULL) + roads_ct = ct_find("magicstreet"); + if (roads_ct != NULL) { + if (get_curse(r->attribs, roads_ct) != NULL) + return true; + if (get_curse(r2->attribs, roads_ct) != NULL) + return true; } - - if (r->terrain->max_road <= 0) return false; - if (r2->terrain->max_road <= 0) return false; - if (rroad(r, dir) < r->terrain->max_road) return false; - if (rroad(r2, dir_invert(dir)) < r2->terrain->max_road) return false; + + if (r->terrain->max_road <= 0) + return false; + if (r2->terrain->max_road <= 0) + return false; + if (rroad(r, dir) < r->terrain->max_road) + return false; + if (rroad(r2, dir_invert(dir)) < r2->terrain->max_road) + return false; return true; } -static const region_list * -cap_route(region * r, const region_list * route, const region_list * route_end, int speed) +static const region_list *cap_route(region * r, const region_list * route, + const region_list * route_end, int speed) { - region * current = r; + region *current = r; + int moves = speed; - const region_list * iroute = route; - while (iroute!=route_end) { - region * next = iroute->data; + + const region_list *iroute = route; + + while (iroute != route_end) { + region *next = iroute->data; + direction_t reldir = reldirection(current, next); /* adjust the range of the unit */ - if (roadto(current, reldir)) moves -= BP_ROAD; - else moves -= BP_NORMAL; - if (moves<0) break; + if (roadto(current, reldir)) + moves -= BP_ROAD; + else + moves -= BP_NORMAL; + if (moves < 0) + break; iroute = iroute->next; current = next; } return iroute; } -static region * -next_region(unit * u, region * current, region * next) +static region *next_region(unit * u, region * current, region * next) { - connection * b; + connection *b; b = get_borders(current, next); - while (b!=NULL) { + while (b != NULL) { if (b->type->move) { - region * rto = b->type->move(b, u, current, next, true); - if (rto!=next) { + region *rto = b->type->move(b, u, current, next, true); + + if (rto != next) { /* the target region was changed (wisps, for example). check the - * new target region for borders */ + * new target region for borders */ next = rto; b = get_borders(current, next); continue; @@ -1212,37 +1322,44 @@ next_region(unit * u, region * current, region * next) return next; } -static const region_list * -reroute(unit * u, const region_list * route, const region_list * route_end) +static const region_list *reroute(unit * u, const region_list * route, + const region_list * route_end) { - region * current = u->region; - while (route!=route_end) { - region * next = next_region(u, current, route->data); - if (next!=route->data) break; + region *current = u->region; + + while (route != route_end) { + region *next = next_region(u, current, route->data); + + if (next != route->data) + break; route = route->next; } return route; } -static void -make_route(unit * u, order * ord, region_list ** routep) +static void make_route(unit * u, order * ord, region_list ** routep) { region_list **iroute = routep; - region * current = u->region; - region * next = NULL; - const char * token = getstrtoken(); + + region *current = u->region; + + region *next = NULL; + + const char *token = getstrtoken(); + int error = movewhere(u, token, current, &next); - if (error!=E_MOVE_OK) { - message * msg = movement_error(u, token, ord, error); - if (msg!=NULL) { + if (error != E_MOVE_OK) { + message *msg = movement_error(u, token, ord, error); + + if (msg != NULL) { add_message(&u->faction->msgs, msg); msg_release(msg); } next = NULL; } - while (next!=NULL) { + while (next != NULL) { direction_t reldir; if (current == next) { @@ -1251,7 +1368,7 @@ make_route(unit * u, order * ord, region_list ** routep) } next = next_region(u, current, next); reldir = reldirection(current, next); - + add_regionlist(iroute, next); iroute = &(*iroute)->next; @@ -1259,8 +1376,9 @@ make_route(unit * u, order * ord, region_list ** routep) token = getstrtoken(); error = movewhere(u, token, current, &next); if (error) { - message * msg = movement_error(u, token, ord, error); - if (msg!=NULL) { + message *msg = movement_error(u, token, ord, error); + + if (msg != NULL) { add_message(&u->faction->msgs, msg); msg_release(msg); } @@ -1278,12 +1396,14 @@ 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) +static int movement_speed(unit * u) { int mp; - static const curse_type * speed_ct; + + static const curse_type *speed_ct; + static boolean init = false; + double dk = u->race->speed; assert(u->number); @@ -1297,53 +1417,57 @@ movement_speed(unit * u) return BP_DRAGON; } - if (!init) { - init = true; - speed_ct = ct_find("speed"); + if (!init) { + init = true; + speed_ct = ct_find("speed"); } if (speed_ct) { curse *c = get_curse(u->attribs, speed_ct); - if (c!=NULL) { + + if (c != NULL) { int men = get_cursedmen(u, c); - dk *= 1.0 + (double)men/(double)u->number; + + dk *= 1.0 + (double)men / (double)u->number; } } switch (canride(u)) { - case 1: /* Pferd */ - mp = BP_RIDING; - break; + case 1: /* Pferd */ + mp = BP_RIDING; + break; - case 2: /* Einhorn */ - mp = BP_UNICORN; - break; + case 2: /* Einhorn */ + mp = BP_UNICORN; + break; - default: - mp = BP_WALKING; + default: + mp = BP_WALKING; - /* Siebenmeilentee */ - if (get_effect(u, oldpotiontype[P_FAST]) >= u->number) { - mp *= 2; - change_effect(u, oldpotiontype[P_FAST], -u->number); - } + /* 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 <= get_item(u, I_FEENSTIEFEL)) { - mp *= 2; - } - - /* Im Astralraum sind Tyb und Ill-Magier doppelt so schnell. - * Nicht kumulativ mit anderen Beschleunigungen! */ - if (mp*dk <= BP_WALKING*u->race->speed && is_astral(u->region) && is_mage(u)) { - sc_mage * mage = get_mage(u); - if (mage->magietyp == M_TYBIED || mage->magietyp == M_ILLAUN) { + /* unicorn in inventory */ + if (u->number <= get_item(u, I_FEENSTIEFEL)) { mp *= 2; } - } - break; + + /* Im Astralraum sind Tyb und Ill-Magier doppelt so schnell. + * Nicht kumulativ mit anderen Beschleunigungen! */ + if (mp * dk <= BP_WALKING * u->race->speed && is_astral(u->region) + && is_mage(u)) { + sc_mage *mage = get_mage(u); + + if (mage->magietyp == M_TYBIED || mage->magietyp == M_ILLAUN) { + mp *= 2; + } + } + break; } - return (int)(dk*mp); + return (int)(dk * mp); } enum { @@ -1353,17 +1477,18 @@ enum { TRAVEL_RUNNING }; -static arg_regions * -var_copy_regions(const region_list * begin, int size) +static arg_regions *var_copy_regions(const region_list * begin, int size) { - const region_list * rsrc; + const region_list *rsrc; - if (size>0) { + if (size > 0) { int i = 0; - arg_regions * dst = (arg_regions *)malloc(sizeof(arg_regions) + sizeof(region*) * size); + + arg_regions *dst = + (arg_regions *) malloc(sizeof(arg_regions) + sizeof(region *) * size); dst->nregions = size; - dst->regions = (region**)(dst+1); - for (rsrc = begin; i!=size; rsrc=rsrc->next) { + dst->regions = (region **) (dst + 1); + for (rsrc = begin; i != size; rsrc = rsrc->next) { dst->regions[i++] = rsrc->data; } return dst; @@ -1372,26 +1497,35 @@ var_copy_regions(const region_list * begin, int size) } -static const region_list * -travel_route(unit * u, const region_list * route_begin, const region_list * route_end, order * ord, int mode) +static const region_list *travel_route(unit * u, + const region_list * route_begin, const region_list * route_end, order * ord, + int mode) { - region * r = u->region; - region * current = u->region; - const region_list * iroute = route_begin; - int steps = 0; - boolean landing = false; /* aquarians have landed */ + region *r = u->region; + + region *current = u->region; + + const region_list *iroute = route_begin; + + int steps = 0; + + boolean landing = false; /* aquarians have landed */ + + while (iroute && iroute != route_end) { + region *next = iroute->data; - while (iroute && iroute!=route_end) { - region * next = iroute->data; direction_t reldir = reldirection(current, next); - connection * b = get_borders(current, next); + + connection *b = get_borders(current, next); /* check if we are caught by guarding units */ - if (iroute!=route_begin && mode!=TRAVEL_RUNNING && mode!=TRAVEL_TRANSPORTED) { - unit * wache = bewegung_blockiert_von(u, current); - if (wache!=NULL) { - ADDMSG(&u->faction->msgs, msg_message("moveblockedbyguard", - "unit region guard", u, current, wache)); + if (iroute != route_begin && mode != TRAVEL_RUNNING + && mode != TRAVEL_TRANSPORTED) { + unit *wache = bewegung_blockiert_von(u, current); + + if (wache != NULL) { + ADDMSG(&u->faction->msgs, msg_message("moveblockedbyguard", + "unit region guard", u, current, wache)); break; } } @@ -1402,23 +1536,25 @@ travel_route(unit * u, const region_list * route_begin, const region_list * rout if (!fval(next->terrain, SEA_REGION)) { /* next region is land */ if (fval(current->terrain, SEA_REGION)) { - int moving = u->race->flags & (RCF_SWIM|RCF_WALK|RCF_COASTAL); + int moving = u->race->flags & (RCF_SWIM | RCF_WALK | RCF_COASTAL); + /* Die Einheit kann nicht fliegen, ist im Ozean, und will an Land */ - if (moving != (RCF_SWIM|RCF_WALK) && (moving&RCF_COASTAL) == 0) { + if (moving != (RCF_SWIM | RCF_WALK) && (moving & RCF_COASTAL) == 0) { /* can't swim+walk and isn't allowed to enter coast from sea */ - if (ord!=NULL) cmistake(u, ord, 44, MSG_MOVE); + if (ord != NULL) + cmistake(u, ord, 44, MSG_MOVE); break; } landing = true; } else if ((u->race->flags & RCF_WALK) == 0) { /* Spezialeinheiten, die nicht laufen können. */ ADDMSG(&u->faction->msgs, msg_message("detectocean", - "unit region", u, next)); + "unit region", u, next)); break; } else if (landing) { /* wir sind diese woche angelandet */ ADDMSG(&u->faction->msgs, msg_message("detectocean", - "unit region", u, next)); + "unit region", u, next)); break; } } else { @@ -1426,7 +1562,7 @@ travel_route(unit * u, const region_list * route_begin, const region_list * rout * Pferde betreten werden. */ if (!(canswim(u) || canfly(u))) { ADDMSG(&u->faction->msgs, msg_message("detectocean", - "unit region", u, next)); + "unit region", u, next)); break; } } @@ -1435,7 +1571,8 @@ travel_route(unit * u, const region_list * route_begin, const region_list * rout /* trying to enter or exit ocean with horses, are we? */ if (has_horses(u)) { /* tries to do it with horses */ - if (ord!=NULL) cmistake(u, ord, 67, MSG_MOVE); + if (ord != NULL) + cmistake(u, ord, 67, MSG_MOVE); break; } } @@ -1443,22 +1580,23 @@ travel_route(unit * u, const region_list * route_begin, const region_list * rout } /* movement blocked by a wall */ - if (reldir>=0 && move_blocked(u, current, next)) { - ADDMSG(&u->faction->msgs, msg_message("leavefail", - "unit region", u, next)); + if (reldir >= 0 && move_blocked(u, current, next)) { + ADDMSG(&u->faction->msgs, msg_message("leavefail", + "unit region", u, next)); break; } /* region ownership only: region owned by enemies */ if (!entrance_allowed(u, next)) { - ADDMSG(&u->faction->msgs, msg_message("regionowned", - "unit region target", u, current, next)); + ADDMSG(&u->faction->msgs, msg_message("regionowned", + "unit region target", u, current, next)); break; } /* illusionary units disappear in antimagic zones */ if (fval(u->race, RCF_ILLUSIONARY)) { - curse * c = get_curse(next->attribs, ct_find("antimagiczone")); + curse *c = get_curse(next->attribs, ct_find("antimagiczone")); + if (curse_active(c)) { curse_changevigour(&next->attribs, c, (float)-u->number); ADDMSG(&u->faction->msgs, msg_message("illusionantimagic", "unit", u)); @@ -1469,8 +1607,8 @@ travel_route(unit * u, const region_list * route_begin, const region_list * rout /* terrain is marked as forbidden (curse, etc) */ if (fval(next, RF_BLOCKED) || fval(next->terrain, FORBIDDEN_REGION)) { - ADDMSG(&u->faction->msgs, msg_message("detectforbidden", - "unit region", u, next)); + ADDMSG(&u->faction->msgs, msg_message("detectforbidden", + "unit region", u, next)); break; } @@ -1478,13 +1616,13 @@ travel_route(unit * u, const region_list * route_begin, const region_list * rout if (u->race == new_race[RC_INSECT]) { if (r_insectstalled(next) && is_freezing(u)) { ADDMSG(&u->faction->msgs, msg_message("detectforbidden", - "unit region", u, next)); + "unit region", u, next)); break; } } /* effect of borders */ - while (b!=NULL) { + while (b != NULL) { if (b->type->move) { b->type->move(b, u, current, next, false); } @@ -1494,10 +1632,11 @@ travel_route(unit * u, const region_list * route_begin, const region_list * rout current = next; iroute = iroute->next; ++steps; - if (u->number == 0) break; + if (u->number == 0) + break; } - if (iroute!=route_begin) { + if (iroute != route_begin) { /* the unit has moved at least one region */ int walkmode; @@ -1506,7 +1645,8 @@ travel_route(unit * u, const region_list * route_begin, const region_list * rout if (mode == TRAVEL_RUNNING) { walkmode = 0; - } if (canride(u)) { + } + if (canride(u)) { walkmode = 1; produceexp(u, SK_RIDING, u->number); } else { @@ -1515,10 +1655,11 @@ travel_route(unit * u, const region_list * route_begin, const region_list * rout /* Berichte über Durchreiseregionen */ - if (mode!=TRAVEL_TRANSPORTED) { - arg_regions * ar = var_copy_regions(route_begin, steps-1); - ADDMSG(&u->faction->msgs, msg_message("travel", - "unit mode start end regions", u, walkmode, r, current, ar)); + if (mode != TRAVEL_TRANSPORTED) { + arg_regions *ar = var_copy_regions(route_begin, steps - 1); + + ADDMSG(&u->faction->msgs, msg_message("travel", + "unit mode start end regions", u, walkmode, r, current, ar)); } mark_travelthru(u, r, route_begin, iroute); @@ -1526,58 +1667,58 @@ travel_route(unit * u, const region_list * route_begin, const region_list * rout /* make orders for the followers */ } - fset(u, UFL_LONGACTION|UFL_NOTMOVING); + fset(u, UFL_LONGACTION | UFL_NOTMOVING); setguard(u, GUARD_NONE); assert(u->region == current); return iroute; } -static boolean -ship_ready(const region * r, unit * u) +static boolean ship_ready(const region * r, unit * u) { - if (!fval(u, UFL_OWNER)) { - cmistake(u, u->thisorder, 146, MSG_MOVE); - return false; - } - if (eff_skill(u, SK_SAILING, r) < u->ship->type->cptskill) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "error_captain_skill_low", - "value ship", u->ship->type->cptskill, u->ship)); - return false; - } - assert(u->ship->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ - if (u->ship->size!=u->ship->type->construction->maxsize) { - cmistake(u, u->thisorder, 15, MSG_MOVE); - return false; - } - if (!enoughsailors(u->ship, r)) { - cmistake(u, u->thisorder, 1, MSG_MOVE); + if (!fval(u, UFL_OWNER)) { + cmistake(u, u->thisorder, 146, MSG_MOVE); + return false; + } + if (eff_skill(u, SK_SAILING, r) < u->ship->type->cptskill) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, + "error_captain_skill_low", "value ship", u->ship->type->cptskill, + u->ship)); + return false; + } + assert(u->ship->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (u->ship->size != u->ship->type->construction->maxsize) { + cmistake(u, u->thisorder, 15, MSG_MOVE); + return false; + } + if (!enoughsailors(u->ship, r)) { + cmistake(u, u->thisorder, 1, MSG_MOVE); /* mistake(u, u->thisorder, "Auf dem Schiff befinden sich zuwenig erfahrene Seeleute.", MSG_MOVE); */ - return false; - } - if (!cansail(r, u->ship)) { + return false; + } + if (!cansail(r, u->ship)) { cmistake(u, u->thisorder, 18, MSG_MOVE); - return false; - } - return true; + return false; + } + return true; } -unit * -owner_buildingtyp(const region * r, const building_type * bt) +unit *owner_buildingtyp(const region * r, const building_type * bt) { - building *b; - unit *owner; + building *b; - for (b = rbuildings(r); b; b = b->next) { - owner = building_owner(b); - if (b->type == bt && owner != NULL) { - if (b->size >= bt->maxsize) { - return owner; - } - } - } + unit *owner; - return NULL; + for (b = rbuildings(r); b; b = b->next) { + owner = building_owner(b); + if (b->type == bt && owner != NULL) { + if (b->size >= bt->maxsize) { + return owner; + } + } + } + + return NULL; } boolean @@ -1598,18 +1739,20 @@ buildingtype_exists(const region * r, const building_type * bt, boolean working) /* Prüft, ob Ablegen von einer Küste in eine der erlaubten Richtungen erfolgt. */ -static boolean -check_takeoff(ship *sh, region *from, region *to) +static boolean check_takeoff(ship * sh, region * from, region * to) { if (!fval(from->terrain, SEA_REGION) && sh->coast != NODIRECTION) { direction_t coast = sh->coast; - direction_t dir = reldirection(from, to); - direction_t coastr = (direction_t)((coast+1) % MAXDIRECTIONS); - direction_t coastl = (direction_t)((coast+MAXDIRECTIONS-1) % MAXDIRECTIONS); - if (dir!=coast && dir!=coastl && dir!=coastr - && !buildingtype_exists(from, bt_find("harbour"), true)) - { + direction_t dir = reldirection(from, to); + + direction_t coastr = (direction_t) ((coast + 1) % MAXDIRECTIONS); + + direction_t coastl = + (direction_t) ((coast + MAXDIRECTIONS - 1) % MAXDIRECTIONS); + + if (dir != coast && dir != coastl && dir != coastr + && !buildingtype_exists(from, bt_find("harbour"), true)) { return false; } } @@ -1618,34 +1761,45 @@ check_takeoff(ship *sh, region *from, region *to) } static void -sail(unit * u, order * ord, boolean move_on_land, region_list **routep) +sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) { region *starting_point = u->region; - region *current_point, *last_point; - int k, step = 0; - region_list **iroute = routep; - ship * sh = u->ship; - faction * f = u->faction; - region * next_point = NULL; - int error; - const char * token = getstrtoken(); - if (routep) *routep = NULL; + region *current_point, *last_point; + + int k, step = 0; + + region_list **iroute = routep; + + ship *sh = u->ship; + + faction *f = u->faction; + + region *next_point = NULL; + + int error; + + const char *token = getstrtoken(); + + if (routep) + *routep = NULL; error = movewhere(u, token, starting_point, &next_point); if (error) { - message * msg = movement_error(u, token, ord, error); - if (msg!=NULL) { + message *msg = movement_error(u, token, ord, error); + + if (msg != NULL) { add_message(&u->faction->msgs, msg); msg_release(msg); } return; } - if (!ship_ready(starting_point, u)) return; + if (!ship_ready(starting_point, u)) + return; /* Wir suchen so lange nach neuen Richtungen, wie es geht. Diese werden - * dann nacheinander ausgeführt. */ + * dann nacheinander ausgeführt. */ k = shipspeed(sh, u); @@ -1653,35 +1807,42 @@ sail(unit * u, order * ord, boolean move_on_land, region_list **routep) current_point = starting_point; /* die nächste Region, in die man segelt, wird durch movewhere () aus der - * letzten Region bestimmt. - * - * Anfangen tun wir bei starting_point. next_point ist beim ersten - * Durchlauf schon gesetzt (Parameter!). current_point ist die letzte gültige, - * befahrene Region. */ + * letzten Region bestimmt. + * + * Anfangen tun wir bei starting_point. next_point ist beim ersten + * Durchlauf schon gesetzt (Parameter!). current_point ist die letzte gültige, + * befahrene Region. */ + + while (next_point && current_point != next_point && step < k) { + const char *token; - while (next_point && current_point!=next_point && step < k) { - const char * token; int error; - const terrain_type * tthis = current_point->terrain; + + const terrain_type *tthis = current_point->terrain; + /* these values need to be updated if next_point changes (due to storms): */ - const terrain_type * tnext = next_point->terrain; + const terrain_type *tnext = next_point->terrain; + direction_t dir = reldirection(current_point, next_point); assert(sh == u->ship || !"ship has sunk, but we didn't notice it"); if (fval(next_point->terrain, FORBIDDEN_REGION)) { - ADDMSG(&f->msgs, msg_message("sailforbidden", - "ship region", sh, next_point)); + ADDMSG(&f->msgs, msg_message("sailforbidden", + "ship region", sh, next_point)); break; } if (!flying_ship(sh)) { int stormchance; + static int stormyness; + static int gamecookie = -1; if (gamecookie != global.cookie) { gamedate date; + get_gamedate(turn, &date); stormyness = storms[date.month] * 5; gamecookie = global.cookie; @@ -1689,35 +1850,45 @@ sail(unit * u, order * ord, boolean move_on_land, region_list **routep) /* storms should be the first thing we do. */ stormchance = stormyness / shipspeed(sh, u); - if (check_leuchtturm(next_point, NULL)) stormchance /= 3; + if (check_leuchtturm(next_point, NULL)) + stormchance /= 3; - if (rng_int()%10000 < stormchance*sh->type->storm && fval(current_point->terrain, SEA_REGION)) { + if (rng_int() % 10000 < stormchance * sh->type->storm + && fval(current_point->terrain, SEA_REGION)) { if (!is_cursed(sh->attribs, C_SHIP_NODRIFT, 0)) { - region * rnext = NULL; - boolean storm = true; - int d_offset = rng_int() % MAXDIRECTIONS; - direction_t d; - /* Sturm nur, wenn nächste Region Hochsee ist. */ - for (d=0;d!=MAXDIRECTIONS;++d) { - direction_t dnext = (direction_t)((d + d_offset) % MAXDIRECTIONS); - region * rn = rconnect(current_point, dnext); + region *rnext = NULL; - if (rn!=NULL) { - if (fval(rn->terrain, FORBIDDEN_REGION)) continue; + boolean storm = true; + + int d_offset = rng_int() % MAXDIRECTIONS; + + direction_t d; + + /* Sturm nur, wenn nächste Region Hochsee ist. */ + for (d = 0; d != MAXDIRECTIONS; ++d) { + direction_t dnext = (direction_t) ((d + d_offset) % MAXDIRECTIONS); + + region *rn = rconnect(current_point, dnext); + + if (rn != NULL) { + if (fval(rn->terrain, FORBIDDEN_REGION)) + continue; if (!fval(rn->terrain, SEA_REGION)) { storm = false; break; } - if (rn!=next_point) rnext = rn; + if (rn != next_point) + rnext = rn; } } - if (storm && rnext!=NULL) { - ADDMSG(&f->msgs, msg_message("storm", "ship region sink", - sh, current_point, sh->damage>=sh->size * DAMAGE_SCALE)); + if (storm && rnext != NULL) { + ADDMSG(&f->msgs, msg_message("storm", "ship region sink", + sh, current_point, sh->damage >= sh->size * DAMAGE_SCALE)); /* damage the ship. we handle destruction in the end */ damage_ship(sh, damage_drift()); - if (sh->damage>=sh->size * DAMAGE_SCALE) break; + if (sh->damage >= sh->size * DAMAGE_SCALE) + break; next_point = rnext; /* these values need to be updated if next_point changes (due to storms): */ @@ -1732,7 +1903,7 @@ sail(unit * u, order * ord, boolean move_on_land, region_list **routep) if (!move_on_land) { /* check that you're not traveling from one land region to another. */ ADDMSG(&u->faction->msgs, msg_message("shipnoshore", - "ship region", sh, next_point)); + "ship region", sh, next_point)); break; } } else { @@ -1747,10 +1918,12 @@ sail(unit * u, order * ord, boolean move_on_land, region_list **routep) if (!(sh->type->flags & SFL_OPENSEA)) { /* ship can only stay close to shore */ direction_t d; - - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rc = rconnect(next_point, d); - if (rc==NULL || !fval(rc->terrain, SEA_REGION)) break; + + for (d = 0; d != MAXDIRECTIONS; ++d) { + region *rc = rconnect(next_point, d); + + if (rc == NULL || !fval(rc->terrain, SEA_REGION)) + break; } if (d == MAXDIRECTIONS) { /* Schiff kann nicht aufs offene Meer */ @@ -1759,30 +1932,36 @@ sail(unit * u, order * ord, boolean move_on_land, region_list **routep) } } } - + if (!ship_allowed(sh, next_point)) { /* for some reason or another, we aren't allowed in there.. */ if (check_leuchtturm(current_point, NULL)) { ADDMSG(&f->msgs, msg_message("sailnolandingstorm", "ship", sh)); } else { - float dmg = get_param_flt(global.parameters, "rules.ship.damage.nolanding", 0.10F); - ADDMSG(&f->msgs, msg_message("sailnolanding", "ship region", sh, next_point)); + float dmg = + get_param_flt(global.parameters, "rules.ship.damage.nolanding", + 0.10F); + ADDMSG(&f->msgs, msg_message("sailnolanding", "ship region", sh, + next_point)); damage_ship(sh, dmg); /* we handle destruction at the end */ } break; } - + if (curse_active(get_curse(next_point->attribs, ct_find("maelstrom")))) { - if (do_maelstrom(next_point, u) == NULL) break; + if (do_maelstrom(next_point, u) == NULL) + break; } - } /* !flying_ship */ + } + /* !flying_ship */ /* Falls Blockade, endet die Seglerei hier */ if (move_blocked(u, current_point, next_point)) { - ADDMSG(&u->faction->msgs, msg_message("sailfail", "ship region", sh, current_point)); + ADDMSG(&u->faction->msgs, msg_message("sailfail", "ship region", sh, + current_point)); break; } @@ -1797,12 +1976,15 @@ sail(unit * u, order * ord, boolean move_on_land, region_list **routep) last_point = current_point; current_point = next_point; - if (!fval(current_point->terrain, SEA_REGION) && !is_cursed(sh->attribs, C_SHIP_FLYING, 0)) break; + if (!fval(current_point->terrain, SEA_REGION) + && !is_cursed(sh->attribs, C_SHIP_FLYING, 0)) + break; token = getstrtoken(); error = movewhere(u, token, current_point, &next_point); if (error || next_point == NULL) { - message * msg = movement_error(u, token, ord, error); - if (msg!=NULL) { + message *msg = movement_error(u, token, ord, error); + + if (msg != NULL) { add_message(&u->faction->msgs, msg); msg_release(msg); } @@ -1811,7 +1993,7 @@ sail(unit * u, order * ord, boolean move_on_land, region_list **routep) } } - if (sh->damage>=sh->size * DAMAGE_SCALE) { + if (sh->damage >= sh->size * DAMAGE_SCALE) { if (sh->region) { ADDMSG(&f->msgs, msg_message("shipsink", "ship", sh)); remove_ship(&sh->region->ships, sh); @@ -1820,32 +2002,36 @@ sail(unit * u, order * ord, boolean move_on_land, region_list **routep) } /* Nun enthält current_point die Region, in der das Schiff seine Runde - * beendet hat. Wir generieren hier ein Ereignis für den Spieler, das - * ihm sagt, bis wohin er gesegelt ist, falls er überhaupt vom Fleck - * gekommen ist. Das ist nicht der Fall, wenn er von der Küste ins - * Inland zu segeln versuchte */ + * beendet hat. Wir generieren hier ein Ereignis für den Spieler, das + * ihm sagt, bis wohin er gesegelt ist, falls er überhaupt vom Fleck + * gekommen ist. Das ist nicht der Fall, wenn er von der Küste ins + * Inland zu segeln versuchte */ + + if (sh != NULL && fval(sh, SF_MOVED)) { + unit *hafenmeister; - if (sh!=NULL && fval(sh, SF_MOVED)) { - unit * hafenmeister; /* nachdem alle Richtungen abgearbeitet wurden, und alle Einheiten - * transferiert wurden, kann der aktuelle Befehl gelöscht werden. */ + * transferiert wurden, kann der aktuelle Befehl gelöscht werden. */ cycle_route(ord, u, step); set_order(&u->thisorder, NULL); if (!move_on_land) { set_coast(sh, last_point, current_point); } - if( is_cursed(sh->attribs, C_SHIP_FLYING, 0) ) { - ADDMSG(&f->msgs, msg_message("shipfly", "ship from to", sh, starting_point, current_point)); + if (is_cursed(sh->attribs, C_SHIP_FLYING, 0)) { + ADDMSG(&f->msgs, msg_message("shipfly", "ship from to", sh, + starting_point, current_point)); } else { - ADDMSG(&f->msgs, msg_message("shipsail", "ship from to", sh, starting_point, current_point)); + ADDMSG(&f->msgs, msg_message("shipsail", "ship from to", sh, + starting_point, current_point)); } /* Das Schiff und alle Einheiten darin werden nun von - * starting_point nach current_point verschoben */ + * starting_point nach current_point verschoben */ /* Verfolgungen melden */ - if (fval(u, UFL_FOLLOWING)) caught_target(current_point, u); + if (fval(u, UFL_FOLLOWING)) + caught_target(current_point, u); sh = move_ship(sh, starting_point, current_point, *routep); @@ -1853,51 +2039,58 @@ sail(unit * u, order * ord, boolean move_on_land, region_list **routep) hafenmeister = owner_buildingtyp(current_point, bt_find("harbour")); if (sh && hafenmeister != NULL) { - item * itm; - unit * u2; - item * trans = NULL; + item *itm; + + unit *u2; + + item *trans = NULL; for (u2 = current_point->units; u2; u2 = u2->next) { - if (u2->ship == sh && - !alliedunit(hafenmeister, u->faction, HELP_GUARD)) { + if (u2->ship == sh && !alliedunit(hafenmeister, u->faction, HELP_GUARD)) { - if (effskill(hafenmeister, SK_PERCEPTION) > effskill(u2, SK_STEALTH)) { - for (itm=u2->items; itm; itm=itm->next) { - const luxury_type * ltype = resource2luxury(itm->type->rtype); - if (ltype!=NULL && itm->number>0) { - int st = itm->number * effskill(hafenmeister, SK_TRADE) / 50; - st = MIN(itm->number, st); + if (effskill(hafenmeister, SK_PERCEPTION) > effskill(u2, SK_STEALTH)) { + for (itm = u2->items; itm; itm = itm->next) { + const luxury_type *ltype = resource2luxury(itm->type->rtype); - if (st > 0) { - i_change(&u2->items, itm->type, -st); - i_change(&hafenmeister->items, itm->type, st); - i_add(&trans, i_new(itm->type, st)); - } + if (ltype != NULL && itm->number > 0) { + int st = itm->number * effskill(hafenmeister, SK_TRADE) / 50; + + st = MIN(itm->number, st); + + if (st > 0) { + i_change(&u2->items, itm->type, -st); + i_change(&hafenmeister->items, itm->type, st); + i_add(&trans, i_new(itm->type, st)); } } } } + } } if (trans) { - message * msg = msg_message("harbor_trade", "unit items ship", hafenmeister, trans, u->ship); + message *msg = + msg_message("harbor_trade", "unit items ship", hafenmeister, trans, + u->ship); add_message(&u->faction->msgs, msg); add_message(&hafenmeister->faction->msgs, msg); msg_release(msg); - while (trans) i_remove(&trans, trans); + while (trans) + i_remove(&trans, trans); } } } } -unit * -get_captain(const ship * sh) +unit *get_captain(const ship * sh) { - const region * r = sh->region; + const region *r = sh->region; + unit *u; for (u = r->units; u; u = u->next) { - if (u->ship == sh && u->number && eff_skill(u, SK_SAILING, r) >= sh->type->cptskill) + if (u->ship == sh && u->number + && eff_skill(u, SK_SAILING, r) >= sh->type->cptskill) return u; } @@ -1915,20 +2108,20 @@ get_captain(const ship * sh) /** fleeing units use this function */ -void -run_to(unit * u, region * to) +void run_to(unit * u, region * to) { - region_list * route = NULL; + region_list *route = NULL; + add_regionlist(&route, to); travel_route(u, route, NULL, NULL, TRAVEL_RUNNING); free_regionlist(route); /* weder transport noch follow */ } -static const region_list * -travel_i(unit * u, const region_list * route_begin, const region_list * route_end, order * ord, int mode, follower ** followers) +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; + region *r = u->region; if (u->building && !can_leave(u)) { cmistake(u, u->thisorder, 150, MSG_MOVE); @@ -1952,14 +2145,15 @@ travel_i(unit * u, const region_list * route_begin, const region_list * route_en /* transportation */ for (ord = u->orders; ord; ord = ord->next) { - unit * ut; + unit *ut; + + if (get_keyword(ord) != K_TRANSPORT) + continue; - if (get_keyword(ord) != K_TRANSPORT) continue; - init_tokens(ord); skip_token(); ut = getunit(r, u->faction); - if (ut!=NULL) { + if (ut != NULL) { if (get_keyword(ut->thisorder) == K_DRIVE) { if (ut->building && !can_leave(ut)) { cmistake(ut, ut->thisorder, 150, MSG_MOVE); @@ -1973,13 +2167,15 @@ travel_i(unit * u, const region_list * route_begin, const region_list * route_en init_tokens(ut->thisorder); skip_token(); if (getunit(u->region, ut->faction) == u) { - const region_list * route_to = travel_route(ut, route_begin, route_end, ord, TRAVEL_TRANSPORTED); + const region_list *route_to = + travel_route(ut, route_begin, route_end, ord, + TRAVEL_TRANSPORTED); - if (route_to!=route_begin) { + if (route_to != route_begin) { get_followers(ut, r, route_to, followers); } - ADDMSG(&ut->faction->msgs, msg_message("transport", - "unit target start end", u, ut, r, ut->region)); + ADDMSG(&ut->faction->msgs, msg_message("transport", + "unit target start end", u, ut, r, ut->region)); found = true; } } @@ -1987,13 +2183,15 @@ travel_i(unit * u, const region_list * route_begin, const region_list * route_en if (cansee(u->faction, u->region, ut, 0)) { cmistake(u, ord, 90, MSG_MOVE); } else { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, + "feedback_unit_not_found", "")); } } } } } else { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", + "")); } } return route_end; @@ -2002,18 +2200,20 @@ travel_i(unit * u, const region_list * route_begin, const region_list * route_en /** traveling without ships * walking, flying or riding units use this function */ -static void -travel(unit * u, region_list ** routep) +static void travel(unit * u, region_list ** routep) { - region * r = u->region; - region_list * route_begin = NULL; - follower * followers = NULL; + region *r = u->region; - if (routep) *routep = NULL; + region_list *route_begin = NULL; + + follower *followers = NULL; + + if (routep) + *routep = NULL; /* a few pre-checks that need not be done for each step: */ if (!fval(r->terrain, SEA_REGION)) { - ship * sh = u->ship; + ship *sh = u->ship; if (!can_leave(u)) { cmistake(u, u->thisorder, 150, MSG_MOVE); @@ -2023,12 +2223,15 @@ travel(unit * u, region_list ** routep) /* An Land kein NACH wenn in dieser Runde Schiff VERLASSEN! */ if (sh == NULL) { sh = leftship(u); - if (sh && sh->region!=u->region) sh = NULL; + if (sh && sh->region != u->region) + sh = NULL; } if (sh) { - unit * guard = is_guarded(r, u, GUARD_LANDING); + unit *guard = is_guarded(r, u, GUARD_LANDING); + if (guard) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "region_guarded", "guard", guard)); + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, + "region_guarded", "guard", guard)); return; } } @@ -2036,8 +2239,7 @@ travel(unit * u, region_list ** routep) cmistake(u, u->thisorder, 143, MSG_MOVE); return; } - } - else if (u->ship && fval(u->ship, SF_MOVED)) { + } else if (u->ship && fval(u->ship, SF_MOVED)) { /* die Einheit ist auf einem Schiff, das sich bereits bewegt hat */ cmistake(u, u->thisorder, 13, MSG_MOVE); return; @@ -2050,25 +2252,30 @@ travel(unit * u, region_list ** routep) travel_i(u, route_begin, NULL, u->thisorder, TRAVEL_NORMAL, &followers); /* followers */ - while (followers!=NULL) { - follower * fnext = followers->next; - unit * uf = followers->uf; - unit * ut = followers->ut; - const region_list * route_end = followers->route_end; - + while (followers != NULL) { + follower *fnext = followers->next; + + unit *uf = followers->uf; + + unit *ut = followers->ut; + + const region_list *route_end = followers->route_end; + free(followers); followers = fnext; if (uf->region == r) { - order * follow_order; - const struct locale * lang = u->faction->locale; + order *follow_order; + + const struct locale *lang = u->faction->locale; /* construct an order */ follow_order = create_order(K_FOLLOW, lang, "%s %i", LOC(uf->faction->locale, parameters[P_UNIT]), ut->no); route_end = reroute(uf, route_begin, route_end); - travel_i(uf, route_begin, route_end, follow_order, TRAVEL_FOLLOWING, &followers); + travel_i(uf, route_begin, route_end, follow_order, TRAVEL_FOLLOWING, + &followers); caught_target(uf->region, uf); free_order(follow_order); } @@ -2076,10 +2283,9 @@ travel(unit * u, region_list ** routep) } -static void -move(unit * u, boolean move_on_land) +static void move(unit * u, boolean move_on_land) { - region_list * route = NULL; + region_list *route = NULL; assert(u->number); if (u->ship && fval(u, UFL_OWNER)) { @@ -2088,83 +2294,90 @@ move(unit * u, boolean move_on_land) travel(u, &route); } - fset(u, UFL_LONGACTION|UFL_NOTMOVING); + fset(u, UFL_LONGACTION | UFL_NOTMOVING); set_order(&u->thisorder, NULL); - if (route!=NULL) free_regionlist(route); + if (route != NULL) + free_regionlist(route); } typedef struct piracy_data { - const struct faction * pirate; - const struct faction * target; + const struct faction *pirate; + const struct faction *target; direction_t dir; } piracy_data; -static void -piracy_init(struct attrib * a) +static void piracy_init(struct attrib *a) { a->data.v = calloc(1, sizeof(piracy_data)); } -static void -piracy_done(struct attrib * a) +static void piracy_done(struct attrib *a) { free(a->data.v); } static attrib_type at_piracy_direction = { - "piracy_direction", - piracy_init, - piracy_done, - DEFAULT_AGE, - NO_WRITE, - NO_READ + "piracy_direction", + piracy_init, + piracy_done, + DEFAULT_AGE, + NO_WRITE, + NO_READ }; -static attrib * -mk_piracy(const faction * pirate, const faction * target, direction_t target_dir) +static attrib *mk_piracy(const faction * pirate, const faction * target, + direction_t target_dir) { - attrib * a = a_new(&at_piracy_direction); - piracy_data * data = a->data.v; + attrib *a = a_new(&at_piracy_direction); + + piracy_data *data = a->data.v; + data->pirate = pirate; data->target = target; data->dir = target_dir; return a; } -static void -piracy_cmd(unit *u, struct order * ord) +static void piracy_cmd(unit * u, struct order *ord) { region *r = u->region; + ship *sh = u->ship, *sh2; + direction_t dir, target_dir = NODIRECTION; + struct { - const faction * target; + const faction *target; int value; } aff[MAXDIRECTIONS]; + int saff = 0; + int *il = NULL; + const char *s; + attrib *a; - + if (!sh) { cmistake(u, ord, 144, MSG_MOVE); return; } - + if (!fval(u, UFL_OWNER)) { cmistake(u, ord, 146, MSG_MOVE); return; } - + /* Feststellen, ob schon ein anderer alliierter Pirat ein * Ziel gefunden hat. */ - - + + init_tokens(ord); skip_token(); s = getstrtoken(); - if (s!=NULL && *s) { + if (s != NULL && *s) { il = intlist_init(); while (s && *s) { il = intlist_add(il, atoi36(s)); @@ -2172,10 +2385,13 @@ piracy_cmd(unit *u, struct order * ord) } } - for (a = a_find(r->attribs, &at_piracy_direction); a && a->type==&at_piracy_direction; a=a->next) { - piracy_data * data = a->data.v; - const faction * p = data->pirate; - const faction * t = data->target; + for (a = a_find(r->attribs, &at_piracy_direction); + a && a->type == &at_piracy_direction; a = a->next) { + piracy_data *data = a->data.v; + + const faction *p = data->pirate; + + const faction *t = data->target; if (alliedunit(u, p, HELP_FIGHT)) { if (il == 0 || (t && intlist_find(il, t->no))) { @@ -2191,18 +2407,22 @@ piracy_cmd(unit *u, struct order * ord) /* Einheit ist also Kapitän. Jetzt gucken, in wievielen * Nachbarregionen potentielle Opfer sind. */ - for(dir = 0; dir < MAXDIRECTIONS; dir++) { + for (dir = 0; dir < MAXDIRECTIONS; dir++) { region *rc = rconnect(r, dir); + aff[dir].value = 0; aff[dir].target = 0; if (rc && fval(rc->terrain, SWIM_INTO) - && check_takeoff(sh, r, rc) == true) { - + && check_takeoff(sh, r, rc) == true) { + for (sh2 = rc->ships; sh2; sh2 = sh2->next) { - unit * cap = shipowner(sh2); + unit *cap = shipowner(sh2); + if (cap) { - faction * f = visible_faction(cap->faction, cap); - if (alliedunit(u, f, HELP_FIGHT)) continue; + faction *f = visible_faction(cap->faction, cap); + + if (alliedunit(u, f, HELP_FIGHT)) + continue; if (il == 0 || intlist_find(il, cap->faction->no)) { ++aff[dir].value; if (rng_int() % aff[dir].value == 0) { @@ -2216,64 +2436,67 @@ piracy_cmd(unit *u, struct order * ord) saff += aff[dir].value; } } - + if (saff != 0) { saff = rng_int() % saff; - for (dir=0; dir!=MAXDIRECTIONS; ++dir) { - if (saff!=aff[dir].value) break; + for (dir = 0; dir != MAXDIRECTIONS; ++dir) { + if (saff != aff[dir].value) + break; saff -= aff[dir].value; } target_dir = dir; - a = a_add(&r->attribs, mk_piracy(u->faction, aff[dir].target, target_dir)); + a = + a_add(&r->attribs, mk_piracy(u->faction, aff[dir].target, target_dir)); } } - + free(il); - + /* Wenn kein Ziel gefunden, entsprechende Meldung generieren */ if (target_dir == NODIRECTION) { - ADDMSG(&u->faction->msgs, msg_message("piratenovictim", - "ship region", sh, r)); + ADDMSG(&u->faction->msgs, msg_message("piratenovictim", + "ship region", sh, r)); return; } - + /* Meldung generieren */ ADDMSG(&u->faction->msgs, msg_message("piratesawvictim", - "ship region dir", sh, r, target_dir)); - + "ship region dir", sh, r, target_dir)); + /* Befehl konstruieren */ set_order(&u->thisorder, create_order(K_MOVE, u->faction->locale, "%s", - LOC(u->faction->locale, directions[target_dir]))); - + LOC(u->faction->locale, directions[target_dir]))); + /* Bewegung ausführen */ init_tokens(u->thisorder); skip_token(); move(u, true); } -static void -age_traveldir(region *r) +static void age_traveldir(region * r) { - attrib *a = a_find(r->attribs, &at_traveldir); + attrib *a = a_find(r->attribs, &at_traveldir); - while(a && a->type==&at_traveldir) { + while (a && a->type == &at_traveldir) { attrib *an = a->next; - a->data.ca[3]--; - if(a->data.ca[3] <= 0) { - a_remove(&r->attribs, a); - } + + a->data.ca[3]--; + if (a->data.ca[3] <= 0) { + a_remove(&r->attribs, a); + } a = an; - } + } } -static direction_t -hunted_dir(attrib *at, int id) +static direction_t hunted_dir(attrib * at, int id) { attrib *a = a_find(at, &at_shiptrail); + direction_t d = NODIRECTION; - while (a!=NULL && a->type==&at_shiptrail) { - traveldir *t = (traveldir *)(a->data.v); + while (a != NULL && a->type == &at_shiptrail) { + traveldir *t = (traveldir *) (a->data.v); + if (t->no == id) { d = t->dir; /* do not break, because we want the last one for this ship */ @@ -2284,71 +2507,80 @@ hunted_dir(attrib *at, int id) return d; } -static int -hunt(unit *u, order * ord) +static int hunt(unit * u, order * ord) { region *rc = u->region; + int bytes, moves, id, speed; - char command[256], * bufp = command; + + char command[256], *bufp = command; + size_t size = sizeof(command); + direction_t dir; if (fval(u, UFL_NOTMOVING)) { return 0; } else if (u->ship == NULL) { cmistake(u, ord, 144, MSG_MOVE); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ + fset(u, UFL_LONGACTION | UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ return 0; } else if (!fval(u, UFL_OWNER)) { cmistake(u, ord, 146, MSG_MOVE); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ + fset(u, UFL_LONGACTION | UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ return 0; } else if (!can_move(u)) { cmistake(u, ord, 55, MSG_MOVE); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ + fset(u, UFL_LONGACTION | UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ return 0; } id = getshipid(); if (id <= 0) { - cmistake(u, ord, 20, MSG_MOVE); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ + cmistake(u, ord, 20, MSG_MOVE); + fset(u, UFL_LONGACTION | UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ return 0; } dir = hunted_dir(rc->attribs, id); if (dir == NODIRECTION) { - ship * sh = findship(id); - if (sh == NULL || sh->region!=rc) { + ship *sh = findship(id); + + if (sh == NULL || sh->region != rc) { cmistake(u, ord, 20, MSG_MOVE); } - fset(u, UFL_LONGACTION|UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ + fset(u, UFL_LONGACTION | UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ return 0; } bufp = command; - bytes = snprintf(bufp, size, "%s %s", LOC(u->faction->locale, keywords[K_MOVE]), + bytes = + snprintf(bufp, size, "%s %s", LOC(u->faction->locale, keywords[K_MOVE]), LOC(u->faction->locale, directions[dir])); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); moves = 1; speed = getuint(); - if (speed==0) { + if (speed == 0) { speed = shipspeed(u->ship, u); } else { int maxspeed = shipspeed(u->ship, u); - if (maxspeedattribs, id)) != NODIRECTION) - { + while (moves < speed && (dir = hunted_dir(rc->attribs, id)) != NODIRECTION) { bytes = (int)strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, LOC(u->faction->locale, directions[dir]), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); moves++; rc = rconnect(rc, dir); } @@ -2359,24 +2591,24 @@ hunt(unit *u, order * ord) igetstrtoken(command); /* NACH ausführen */ move(u, false); - return 1; /* true -> Einheitenliste von vorne durchgehen */ + return 1; /* true -> Einheitenliste von vorne durchgehen */ } -void -destroy_damaged_ships(void) +void destroy_damaged_ships(void) { - region *r; - ship *sh,*shn; + region *r; - for(r=regions;r;r=r->next) { - for(sh=r->ships;sh;) { - shn = sh->next; - if (sh->damage>=sh->size * DAMAGE_SCALE) { - remove_ship(&sh->region->ships, sh); - } - sh = shn; - } - } + ship *sh, *shn; + + for (r = regions; r; r = r->next) { + for (sh = r->ships; sh;) { + shn = sh->next; + if (sh->damage >= sh->size * DAMAGE_SCALE) { + remove_ship(&sh->region->ships, sh); + } + sh = shn; + } + } } /* Bewegung, Verfolgung, Piraterie */ @@ -2386,21 +2618,20 @@ destroy_damaged_ships(void) * bewegen sich. * Following the trails of other ships. */ -static void -move_hunters(void) +static void move_hunters(void) { region *r; for (r = regions; r; r = r->next) { - unit ** up = &r->units; + unit **up = &r->units; - while (*up!=NULL) { - unit * u = *up; + while (*up != NULL) { + unit *u = *up; - if (!fval(u, UFL_MOVED|UFL_NOTMOVING)) { - order * ord; + if (!fval(u, UFL_MOVED | UFL_NOTMOVING)) { + order *ord; - for (ord=u->orders;ord;ord=ord->next) { + for (ord = u->orders; ord; ord = ord->next) { if (get_keyword(ord) == K_FOLLOW) { param_t p; @@ -2431,7 +2662,8 @@ move_hunters(void) } } } - if (*up == u) up=&u->next; + if (*up == u) + up = &u->next; } } } @@ -2439,28 +2671,27 @@ move_hunters(void) /** Piraten and Drift * */ -static void -move_pirates(void) +static void move_pirates(void) { - region * r; + region *r; for (r = regions; r; r = r->next) { - unit ** up = &r->units; + unit **up = &r->units; while (*up) { unit *u = *up; if (!fval(u, UFL_NOTMOVING) && get_keyword(u->thisorder) == K_PIRACY) { piracy_cmd(u, u->thisorder); - fset(u, UFL_LONGACTION|UFL_NOTMOVING); + fset(u, UFL_LONGACTION | UFL_NOTMOVING); } if (*up == u) { /* not moved, use next unit */ up = &u->next; - } else if (*up && (*up)->region!=r) { + } else if (*up && (*up)->region != r) { /* moved the previous unit along with u (units on same ship) - * must start from the beginning again */ + * must start from the beginning again */ up = &r->units; } /* else *up is already the next unit */ @@ -2471,8 +2702,7 @@ move_pirates(void) } } -void -movement(void) +void movement(void) { int ships; @@ -2480,19 +2710,22 @@ movement(void) init_transportation(); /* Move ships in last phase, others first - * This is to make sure you can't land someplace and then get off the ship - * in the same turn. - */ - for (ships=0;ships<=1;++ships) { - region * r = regions; - while (r!=NULL) { - unit ** up = &r->units; + * This is to make sure you can't land someplace and then get off the ship + * in the same turn. + */ + for (ships = 0; ships <= 1; ++ships) { + region *r = regions; + + while (r != NULL) { + unit **up = &r->units; + boolean repeat = false; while (*up) { unit *u = *up; + keyword_t kword; - + if (u->ship && fval(u->ship, SF_DRIFTED)) { up = &u->next; continue; @@ -2500,51 +2733,51 @@ movement(void) kword = get_keyword(u->thisorder); switch (kword) { - case K_ROUTE: - case K_MOVE: - /* after moving, the unit has no thisorder. this prevents - * it from moving twice (or getting error messages twice). - * UFL_NOTMOVING is set in combat if the unit is not allowed - * to move because it was involved in a battle. - */ - if (fval(u, UFL_NOTMOVING)) { - if (fval(u, UFL_LONGACTION)) { - cmistake(u, u->thisorder, 52, MSG_MOVE); + case K_ROUTE: + case K_MOVE: + /* after moving, the unit has no thisorder. this prevents + * it from moving twice (or getting error messages twice). + * UFL_NOTMOVING is set in combat if the unit is not allowed + * to move because it was involved in a battle. + */ + if (fval(u, UFL_NOTMOVING)) { + if (fval(u, UFL_LONGACTION)) { + cmistake(u, u->thisorder, 52, MSG_MOVE); + set_order(&u->thisorder, NULL); + } else { + cmistake(u, u->thisorder, 319, MSG_MOVE); + set_order(&u->thisorder, NULL); + } + } else if (fval(u, UFL_MOVED)) { + cmistake(u, u->thisorder, 187, MSG_MOVE); + set_order(&u->thisorder, NULL); + } else if (!can_move(u)) { + cmistake(u, u->thisorder, 55, MSG_MOVE); set_order(&u->thisorder, NULL); } else { - cmistake(u, u->thisorder, 319, MSG_MOVE); - set_order(&u->thisorder, NULL); - } - } else if (fval(u, UFL_MOVED)) { - cmistake(u, u->thisorder, 187, MSG_MOVE); - set_order(&u->thisorder, NULL); - } else if (!can_move(u)) { - cmistake(u, u->thisorder, 55, MSG_MOVE); - set_order(&u->thisorder, NULL); - } else { - if (ships) { - if (u->ship && fval(u, UFL_OWNER)) { - init_tokens(u->thisorder); - skip_token(); - move(u, false); - } - } else { - if (u->ship == NULL || !fval(u, UFL_OWNER)) { - init_tokens(u->thisorder); - skip_token(); - move(u, false); + if (ships) { + if (u->ship && fval(u, UFL_OWNER)) { + init_tokens(u->thisorder); + skip_token(); + move(u, false); + } + } else { + if (u->ship == NULL || !fval(u, UFL_OWNER)) { + init_tokens(u->thisorder); + skip_token(); + move(u, false); + } } } - } - break; + break; } if (u->region == r) { /* not moved, use next unit */ up = &u->next; } else { - if (*up && (*up)->region!=r) { + if (*up && (*up)->region != r) { /* moved the upcoming unit along with u (units on ships or followers, - * for example). must start from the beginning again immediately */ + * for example). must start from the beginning again immediately */ up = &r->units; repeat = false; } else { @@ -2553,7 +2786,8 @@ movement(void) } /* else *up is already the next unit */ } - if (repeat) continue; + if (repeat) + continue; if (ships == 0) { /* Abtreiben von beschädigten, unterbemannten, überladenen Schiffen */ drifting_ships(r); @@ -2570,17 +2804,19 @@ movement(void) * FOLLOW SHIP is a long order, and doesn't need to be treated in here. * BUGS: http://bugs.eressea.de/view.php?id=1444 (A folgt B folgt C) */ -void -follow_unit(unit * u) +void follow_unit(unit * u) { - region * r = u->region; - attrib * a = NULL; - order * ord; + region *r = u->region; - if (fval(u, UFL_NOTMOVING) || LongHunger(u)) return; + attrib *a = NULL; - for (ord=u->orders;ord;ord=ord->next) { - const struct locale * lang = u->faction->locale; + order *ord; + + if (fval(u, UFL_NOTMOVING) || LongHunger(u)) + return; + + for (ord = u->orders; ord; ord = ord->next) { + const struct locale *lang = u->faction->locale; if (get_keyword(ord) == K_FOLLOW) { init_tokens(ord); @@ -2588,12 +2824,13 @@ follow_unit(unit * u) if (getparam(lang) == P_UNIT) { int id = read_unitid(u->faction, r); - if (a!=NULL) { + if (a != NULL) { a = a_find(u->attribs, &at_follow); } - if (id>0) { - unit * uf = findunit(id); + if (id > 0) { + unit *uf = findunit(id); + if (!a) { a = a_add(&u->attribs, make_follow(uf)); } else { @@ -2607,11 +2844,12 @@ follow_unit(unit * u) } } - if (a && !fval(u, UFL_MOVED|UFL_NOTMOVING)) { - unit * u2 = a->data.v; + if (a && !fval(u, UFL_MOVED | UFL_NOTMOVING)) { + unit *u2 = a->data.v; + boolean follow = false; - if (!u2 || u2->region!=r || !cansee(u->faction, r, u2, 0)) { + if (!u2 || u2->region != r || !cansee(u->faction, r, u2, 0)) { return; } @@ -2622,7 +2860,7 @@ follow_unit(unit * u) follow = true; break; default: - for (ord=u2->orders;ord;ord=ord->next) { + for (ord = u2->orders; ord; ord = ord->next) { switch (get_keyword(ord)) { case K_FOLLOW: case K_PIRACY: @@ -2636,9 +2874,11 @@ follow_unit(unit * u) break; } if (!follow) { - attrib * a2 = a_find(u2->attribs, &at_follow); - if (a2!=NULL) { - unit * u3 = a2->data.v; + attrib *a2 = a_find(u2->attribs, &at_follow); + + if (a2 != NULL) { + unit *u3 = a2->data.v; + follow = (u3 && u2->region == u2->region); } } diff --git a/src/kernel/move.h b/src/kernel/move.h index 2b5b7bdd1..e53764c29 100644 --- a/src/kernel/move.h +++ b/src/kernel/move.h @@ -22,21 +22,21 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -struct unit; -struct ship; -struct building_type; + struct unit; + struct ship; + struct building_type; /* die Zahlen sind genau äquivalent zu den race Flags */ #define MV_CANNOTMOVE (1<<5) -#define MV_FLY (1<<7) /* kann fliegen */ -#define MV_SWIM (1<<8) /* kann schwimmen */ -#define MV_WALK (1<<9) /* kann über Land gehen */ +#define MV_FLY (1<<7) /* kann fliegen */ +#define MV_SWIM (1<<8) /* kann schwimmen */ +#define MV_WALK (1<<9) /* kann über Land gehen */ /* Die tragekapaz. ist hardcodiert mit defines, da es bis jetzt sowieso nur 2 ** objekte gibt, die etwas tragen. */ #define SILVERWEIGHT 1 -#define SCALEWEIGHT 100 /* Faktor, um den die Anzeige von gewichten - * * skaliert wird */ +#define SCALEWEIGHT 100 /* Faktor, um den die Anzeige von gewichten + * * skaliert wird */ #define HORSECAPACITY 7000 #define WAGONCAPACITY 14000 @@ -46,24 +46,27 @@ struct building_type; ** wagen wird von zwei pferden gezogen und traegt total 140, davon 40 die ** pferde, macht nur noch 100, aber samt eigenem gewicht (40) macht also 140. */ -int personcapacity(const struct unit *u); -direction_t getdirection(const struct locale *); -void movement(void); -void run_to(struct unit * u, struct region * to); -struct unit *is_guarded(struct region * r, struct unit * u, unsigned int mask); -boolean is_guard(const struct unit * u, int mask); -int enoughsailors(const struct ship * sh, const struct region * r); -boolean canswim(struct unit *u); -boolean canfly(struct unit *u); -struct unit *get_captain(const struct ship * sh); -void travelthru(const struct unit * u, struct region * r); -struct ship * move_ship(struct ship * sh, struct region * from, struct region * to, struct region_list * route); -int walkingcapacity(const struct unit * u); -void follow_unit(struct unit * u); -boolean buildingtype_exists(const struct region * r, const struct building_type * bt, boolean working); -struct unit* owner_buildingtyp(const struct region * r, const struct building_type * bt); + int personcapacity(const struct unit *u); + direction_t getdirection(const struct locale *); + void movement(void); + void run_to(struct unit *u, struct region *to); + struct unit *is_guarded(struct region *r, struct unit *u, unsigned int mask); + boolean is_guard(const struct unit *u, int mask); + int enoughsailors(const struct ship *sh, const struct region *r); + boolean canswim(struct unit *u); + boolean canfly(struct unit *u); + struct unit *get_captain(const struct ship *sh); + void travelthru(const struct unit *u, struct region *r); + struct ship *move_ship(struct ship *sh, struct region *from, + struct region *to, struct region_list *route); + int walkingcapacity(const struct unit *u); + void follow_unit(struct unit *u); + boolean buildingtype_exists(const struct region *r, + const struct building_type *bt, boolean working); + struct unit *owner_buildingtyp(const struct region *r, + const struct building_type *bt); -extern struct attrib_type at_speedup; + extern struct attrib_type at_speedup; #ifdef __cplusplus } diff --git a/src/kernel/names.c b/src/kernel/names.c index 9d617cc0b..b56595463 100644 --- a/src/kernel/names.c +++ b/src/kernel/names.c @@ -43,42 +43,47 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -const char * -describe_braineater(unit * u, const struct locale * lang) +const char *describe_braineater(unit * u, const struct locale *lang) { return LOC(lang, "describe_braineater"); } -static const char * -make_names(const char * monster, int * num_postfix, int pprefix, int * num_name, int * num_prefix, int ppostfix) +static const char *make_names(const char *monster, int *num_postfix, + int pprefix, int *num_name, int *num_prefix, int ppostfix) { int uv, uu, un; + static char name[NAMESIZE + 1]; + char zText[32]; - const char * str; - if (*num_prefix==0) { + const char *str; - for (*num_prefix=0;;++*num_prefix) { + if (*num_prefix == 0) { + + for (*num_prefix = 0;; ++*num_prefix) { sprintf(zText, "%s_prefix_%d", monster, *num_prefix); str = locale_getstring(default_locale, zText); - if (str==NULL) break; + if (str == NULL) + break; } - for (*num_name=0;;++*num_name) { + for (*num_name = 0;; ++*num_name) { sprintf(zText, "%s_name_%d", monster, *num_name); str = locale_getstring(default_locale, zText); - if (str==NULL) break; + if (str == NULL) + break; } - for (*num_postfix=0;;++*num_postfix) { + for (*num_postfix = 0;; ++*num_postfix) { sprintf(zText, "%s_postfix_%d", monster, *num_postfix); str = locale_getstring(default_locale, zText); - if (str==NULL) break; + if (str == NULL) + break; } } - if (*num_name==0) { + if (*num_name == 0) { return NULL; } @@ -88,7 +93,7 @@ make_names(const char * monster, int * num_postfix, int pprefix, int * num_name, uu = rng_int() % *num_name; /* nur 50% aller Namen haben "Nach-Teil", wenn kein Vor-Teil */ - if (uv>=*num_prefix) { + if (uv >= *num_prefix) { un = rng_int() % *num_postfix; } else { un = rng_int() % (*num_postfix * ppostfix); @@ -106,7 +111,8 @@ make_names(const char * monster, int * num_postfix, int pprefix, int * num_name, sprintf(zText, "%s_name_%d", monster, uu); str = locale_getstring(default_locale, zText); - if (str) strcat(name, (const char *)str); + if (str) + strcat(name, (const char *)str); if (un < *num_postfix) { sprintf(zText, "%s_postfix_%d", monster, un); @@ -119,31 +125,31 @@ make_names(const char * monster, int * num_postfix, int pprefix, int * num_name, return name; } -const char * -undead_name(const unit * u) +const char *undead_name(const unit * u) { static int num_postfix, num_name, num_prefix; + return make_names("undead", &num_postfix, 2, &num_name, &num_prefix, 2); } -const char * -skeleton_name(const unit * u) +const char *skeleton_name(const unit * u) { static int num_postfix, num_name, num_prefix; + return make_names("skeleton", &num_postfix, 5, &num_name, &num_prefix, 2); } -const char * -zombie_name(const unit * u) +const char *zombie_name(const unit * u) { static int num_postfix, num_name, num_prefix; + return make_names("zombie", &num_postfix, 5, &num_name, &num_prefix, 2); } -const char * -ghoul_name(const unit * u) +const char *ghoul_name(const unit * u) { static int num_postfix, num_name, num_prefix; + return make_names("ghoul", &num_postfix, 5, &num_name, &num_prefix, 4); } @@ -153,68 +159,67 @@ ghoul_name(const unit * u) #define SIL1 15 const char *silbe1[SIL1] = { - "Tar", - "Ter", - "Tor", - "Pan", - "Par", - "Per", - "Nim", - "Nan", - "Nun", - "Gor", - "For", - "Fer", - "Kar", - "Kur", - "Pen", + "Tar", + "Ter", + "Tor", + "Pan", + "Par", + "Per", + "Nim", + "Nan", + "Nun", + "Gor", + "For", + "Fer", + "Kar", + "Kur", + "Pen", }; #define SIL2 19 const char *silbe2[SIL2] = { - "da", - "do", - "dil", - "di", - "dor", - "dar", - "ra", - "ran", - "ras", - "ro", - "rum", - "rin", - "ten", - "tan", - "ta", - "tor", - "gur", - "ga", - "gas", + "da", + "do", + "dil", + "di", + "dor", + "dar", + "ra", + "ran", + "ras", + "ro", + "rum", + "rin", + "ten", + "tan", + "ta", + "tor", + "gur", + "ga", + "gas", }; #define SIL3 14 const char *silbe3[SIL3] = { - "gul", - "gol", - "dol", - "tan", - "tar", - "tur", - "sur", - "sin", - "kur", - "kor", - "kar", - "dul", - "dol", - "bus", + "gul", + "gol", + "dol", + "tan", + "tar", + "tur", + "sur", + "sin", + "kur", + "kor", + "kar", + "dul", + "dol", + "bus", }; -const char * -generic_name(const unit *u) +const char *generic_name(const unit * u) { if (u->no == 1) { return LOC(u->faction->locale, mkname("race", u->race->_name[0])); @@ -222,47 +227,54 @@ generic_name(const unit *u) return LOC(u->faction->locale, mkname("race", u->race->_name[1])); } -const char * -dragon_name(const unit *u) +const char *dragon_name(const unit * u) { static char name[NAMESIZE + 1]; - int rnd, ter = 0; - int anzahl = 1; - static int num_postfix; - char zText[32]; - const char * str; - if (num_postfix==0) { - for (num_postfix=0;;++num_postfix) { + int rnd, ter = 0; + + int anzahl = 1; + + static int num_postfix; + + char zText[32]; + + const char *str; + + if (num_postfix == 0) { + for (num_postfix = 0;; ++num_postfix) { sprintf(zText, "dragon_postfix_%d", num_postfix); str = locale_getstring(default_locale, zText); - if (str==NULL) break; + if (str == NULL) + break; } - if (num_postfix==0) num_postfix = -1; + if (num_postfix == 0) + num_postfix = -1; } - if (num_postfix<=0) { + if (num_postfix <= 0) { return NULL; } if (u) { region *r = u->region; + anzahl = u->number; switch (rterrain(r)) { - case T_PLAIN: - ter = 1; - break; - case T_MOUNTAIN: - ter = 2; - break; - case T_DESERT: - ter = 3; - break; - case T_SWAMP: - ter = 4; - break; - case T_GLACIER: - ter = 5; - break; + case T_PLAIN: + ter = 1; + break; + case T_MOUNTAIN: + ter = 2; + break; + case T_DESERT: + ter = 3; + break; + case T_SWAMP: + ter = 4; + break; + case T_GLACIER: + ter = 5; + break; } } @@ -272,13 +284,15 @@ dragon_name(const unit *u) sprintf(zText, "dragon_postfix_%d", rnd); str = locale_getstring(default_locale, zText); - assert(str!=NULL); + assert(str != NULL); if (anzahl > 1) { - const char * no_article = strchr((const char *)str, ' '); + const char *no_article = strchr((const char *)str, ' '); + assert(no_article); /* TODO: GERMAN */ - sprintf(name, "Die %sn von %s", no_article, rname(u->region, default_locale)); + sprintf(name, "Die %sn von %s", no_article, rname(u->region, + default_locale)); } else { char n[32]; @@ -286,9 +300,9 @@ dragon_name(const unit *u) strcat(n, silbe2[rng_int() % SIL2]); strcat(n, silbe3[rng_int() % SIL3]); if (rng_int() % 5 > 2) { - sprintf(name, "%s, %s", n, str); /* "Name, der Titel" */ + sprintf(name, "%s, %s", n, str); /* "Name, der Titel" */ } else { - strcpy(name, (const char *)str); /* "Der Titel Name" */ + strcpy(name, (const char *)str); /* "Der Titel Name" */ name[0] = (char)toupper(name[0]); /* TODO: UNICODE - should use towupper() */ strcat(name, " "); strcat(name, n); @@ -306,178 +320,182 @@ dragon_name(const unit *u) #define DRAC_PRE 13 static const char *drac_pre[DRAC_PRE] = { - "Siss", - "Xxaa", - "Shht", - "X'xixi", - "Xar", - "X'zish", - "X", - "Sh", - "R", - "Z", - "Y", - "L", - "Ck", + "Siss", + "Xxaa", + "Shht", + "X'xixi", + "Xar", + "X'zish", + "X", + "Sh", + "R", + "Z", + "Y", + "L", + "Ck", }; #define DRAC_MID 12 static const char *drac_mid[DRAC_MID] = { - "siss", - "xxaa", - "shht", - "xxi", - "xar", - "x'zish", - "x", - "sh", - "r", - "z'ck", - "y", - "rl" + "siss", + "xxaa", + "shht", + "xxi", + "xar", + "x'zish", + "x", + "sh", + "r", + "z'ck", + "y", + "rl" }; #define DRAC_SUF 10 static const char *drac_suf[DRAC_SUF] = { - "xil", - "shh", - "s", - "x", - "arr", - "lll", - "lll", - "shack", - "ck", - "k" + "xil", + "shh", + "s", + "x", + "arr", + "lll", + "lll", + "shack", + "ck", + "k" }; -const char * -dracoid_name(const unit *u) +const char *dracoid_name(const unit * u) { - static char name[NAMESIZE + 1]; - int mid_syllabels; + static char name[NAMESIZE + 1]; - u=u; - /* Wieviele Mittelteile? */ + int mid_syllabels; - mid_syllabels = rng_int()%4; + u = u; + /* Wieviele Mittelteile? */ - strcpy(name, drac_pre[rng_int()%DRAC_PRE]); - while(mid_syllabels > 0) { - mid_syllabels--; - if(rng_int()%10 < 4) strcat(name,"'"); - strcat(name, drac_mid[rng_int()%DRAC_MID]); - } - strcat(name, drac_suf[rng_int()%DRAC_SUF]); - return name; + mid_syllabels = rng_int() % 4; + + strcpy(name, drac_pre[rng_int() % DRAC_PRE]); + while (mid_syllabels > 0) { + mid_syllabels--; + if (rng_int() % 10 < 4) + strcat(name, "'"); + strcat(name, drac_mid[rng_int() % DRAC_MID]); + } + strcat(name, drac_suf[rng_int() % DRAC_SUF]); + return name; } /** returns an abbreviation of a string. * TODO: buflen is being ignored */ -const char * -abkz(const char *s, char * buf, size_t buflen, size_t maxchars) +const char *abkz(const char *s, char *buf, size_t buflen, size_t maxchars) { - const char *p = s; - char * bufp; - unsigned int c = 0; - size_t bpt, i; + const char *p = s; + + char *bufp; + + unsigned int c = 0; + + size_t bpt, i; + ucs4_t ucs; + size_t size; + int result; - /* Prüfen, ob Kurz genug */ + /* Prüfen, ob Kurz genug */ - if (strlen(s) <= maxchars) { - return s; - } - /* Anzahl der Wörter feststellen */ + if (strlen(s) <= maxchars) { + return s; + } + /* Anzahl der Wörter feststellen */ + + while (*p != 0) { - while (*p != 0) { - result = unicode_utf8_to_ucs4(&ucs, p, &size); - assert(result==0 || "damnit, we're not handling invalid input here!"); + assert(result == 0 || "damnit, we're not handling invalid input here!"); /* Leerzeichen überspringen */ - while (*p != 0 && !iswalnum((wint_t)ucs)) { - p += size; + while (*p != 0 && !iswalnum((wint_t) ucs)) { + p += size; result = unicode_utf8_to_ucs4(&ucs, p, &size); - assert(result==0 || "damnit, we're not handling invalid input here!"); + assert(result == 0 || "damnit, we're not handling invalid input here!"); } /* Counter erhöhen */ - if (*p != 0) ++c; + if (*p != 0) + ++c; - /* alnums überspringen */ - while (*p != 0 && iswalnum((wint_t)ucs)) { - p+=size; + /* alnums überspringen */ + while (*p != 0 && iswalnum((wint_t) ucs)) { + p += size; result = unicode_utf8_to_ucs4(&ucs, p, &size); - assert(result==0 || "damnit, we're not handling invalid input here!"); + assert(result == 0 || "damnit, we're not handling invalid input here!"); } - } + } - /* Buchstaben pro Teilkürzel = MAX(1,max/AnzWort) */ + /* Buchstaben pro Teilkürzel = MAX(1,max/AnzWort) */ - bpt = MAX(1, maxchars / c); + bpt = MAX(1, maxchars / c); - /* Einzelne Wörter anspringen und jeweils die ersten BpT kopieren */ + /* Einzelne Wörter anspringen und jeweils die ersten BpT kopieren */ - p = s; - c = 0; + p = s; + c = 0; bufp = buf; result = unicode_utf8_to_ucs4(&ucs, p, &size); - assert(result==0 || "damnit, we're not handling invalid input here!"); + assert(result == 0 || "damnit, we're not handling invalid input here!"); - while (*p != 0 && c < maxchars) { - /* Leerzeichen überspringen */ + while (*p != 0 && c < maxchars) { + /* Leerzeichen überspringen */ - while (*p != 0 && !iswalnum((wint_t)ucs)) { - p+=size; + while (*p != 0 && !iswalnum((wint_t) ucs)) { + p += size; result = unicode_utf8_to_ucs4(&ucs, p, &size); - assert(result==0 || "damnit, we're not handling invalid input here!"); + assert(result == 0 || "damnit, we're not handling invalid input here!"); } - /* alnums übertragen */ + /* alnums übertragen */ - for (i = 0; i < bpt && *p != 0 && iswalnum((wint_t)ucs); ++i) { - memcpy(bufp, p, size); - p += size; + for (i = 0; i < bpt && *p != 0 && iswalnum((wint_t) ucs); ++i) { + memcpy(bufp, p, size); + p += size; bufp += size; ++c; result = unicode_utf8_to_ucs4(&ucs, p, &size); - assert(result==0 || "damnit, we're not handling invalid input here!"); - } - - /* Bis zum nächsten Leerzeichen */ - - while (c < maxchars && *p != 0 && iswalnum((wint_t)ucs)) { - p+=size; - result = unicode_utf8_to_ucs4(&ucs, p, &size); - assert(result==0 || "damnit, we're not handling invalid input here!"); + assert(result == 0 || "damnit, we're not handling invalid input here!"); } - } - *bufp = 0; + /* Bis zum nächsten Leerzeichen */ - return buf; + while (c < maxchars && *p != 0 && iswalnum((wint_t) ucs)) { + p += size; + result = unicode_utf8_to_ucs4(&ucs, p, &size); + assert(result == 0 || "damnit, we're not handling invalid input here!"); + } + } + + *bufp = 0; + + return buf; } -void -register_names(void) +void register_names(void) { - register_function((pf_generic)describe_braineater, "describe_braineater"); + register_function((pf_generic) describe_braineater, "describe_braineater"); /* function name * generate a name for a nonplayerunit * race->generate_name() */ - register_function((pf_generic)undead_name, "nameundead"); - register_function((pf_generic)skeleton_name, "nameskeleton"); - register_function((pf_generic)zombie_name, "namezombie"); - register_function((pf_generic)ghoul_name, "nameghoul"); - register_function((pf_generic)dragon_name, "namedragon"); - register_function((pf_generic)dracoid_name, "namedracoid"); - register_function((pf_generic)generic_name, "namegeneric"); + register_function((pf_generic) undead_name, "nameundead"); + register_function((pf_generic) skeleton_name, "nameskeleton"); + register_function((pf_generic) zombie_name, "namezombie"); + register_function((pf_generic) ghoul_name, "nameghoul"); + register_function((pf_generic) dragon_name, "namedragon"); + register_function((pf_generic) dracoid_name, "namedracoid"); + register_function((pf_generic) generic_name, "namegeneric"); } - - diff --git a/src/kernel/names.h b/src/kernel/names.h index d689197d2..03637d097 100644 --- a/src/kernel/names.h +++ b/src/kernel/names.h @@ -21,15 +21,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifdef __cplusplus extern "C" { #endif -extern void register_names(void); -const char *undead_name(const struct unit * u); -const char *skeleton_name(const struct unit * u); -const char *zombie_name(const struct unit * u); -const char *ghoul_name(const struct unit * u); -const char *dragon_name(const struct unit *u); -const char *dracoid_name(const struct unit *u); -const char *generic_name(const struct unit *u); -const char *abkz(const char *s, char * buf, size_t size, size_t maxchars); + extern void register_names(void); + const char *undead_name(const struct unit *u); + const char *skeleton_name(const struct unit *u); + const char *zombie_name(const struct unit *u); + const char *ghoul_name(const struct unit *u); + const char *dragon_name(const struct unit *u); + const char *dracoid_name(const struct unit *u); + const char *generic_name(const struct unit *u); + const char *abkz(const char *s, char *buf, size_t size, size_t maxchars); #ifdef __cplusplus } diff --git a/src/kernel/objtypes.h b/src/kernel/objtypes.h index 789ef0c5d..b676697f3 100644 --- a/src/kernel/objtypes.h +++ b/src/kernel/objtypes.h @@ -22,19 +22,18 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -enum { - TYP_UNIT, - TYP_REGION, - TYP_BUILDING, - TYP_SHIP, - TYP_FACTION, - TYP_ACTION, - TYP_TRIGGER, - TYP_TIMEOUT -}; + enum { + TYP_UNIT, + TYP_REGION, + TYP_BUILDING, + TYP_SHIP, + TYP_FACTION, + TYP_ACTION, + TYP_TRIGGER, + TYP_TIMEOUT + }; #ifdef __cplusplus } #endif #endif - diff --git a/src/kernel/order.c b/src/kernel/order.c index ad05af80a..536284259 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -35,39 +35,41 @@ typedef struct locale_data { - struct order_data * short_orders[MAXKEYWORDS]; - struct order_data * study_orders[MAXSKILLS]; - const struct locale * lang; + struct order_data *short_orders[MAXKEYWORDS]; + struct order_data *study_orders[MAXSKILLS]; + const struct locale *lang; } locale_data; -static struct locale_data * locale_array[16]; +static struct locale_data *locale_array[16]; + static int nlocales = 0; typedef struct order_data { - char * _str; - int _refcount : 20; - int _lindex : 4; + char *_str; + int _refcount:20; + int _lindex:4; keyword_t _keyword; } order_data; -static void -release_data(order_data * data) +static void release_data(order_data * data) { if (data) { if (--data->_refcount == 0) { - if (data->_str) free(data->_str); + if (data->_str) + free(data->_str); free(data); } } } -void -replace_order(order ** dlist, order * orig, const order * src) +void replace_order(order ** dlist, order * orig, const order * src) { - while (*dlist!=NULL) { - order * dst = *dlist; - if (dst->data==orig->data) { - order * cpy = copy_order(src); + while (*dlist != NULL) { + order *dst = *dlist; + + if (dst->data == orig->data) { + order *cpy = copy_order(src); + *dlist = cpy; cpy->next = dst->next; dst->next = 0; @@ -77,10 +79,9 @@ replace_order(order ** dlist, order * orig, const order * src) } } -keyword_t -get_keyword(const order * ord) +keyword_t get_keyword(const order * ord) { - if (ord==NULL) { + if (ord == NULL) { return NOKEYWORD; } return ORD_KEYWORD(ord); @@ -90,73 +91,80 @@ get_keyword(const order * ord) * This is the inverse function to the parse_order command. Note that * keywords are expanded to their full length. */ -static char * -get_command(const order * ord, char * sbuffer, size_t size) +static char *get_command(const order * ord, char *sbuffer, size_t size) { - char * bufp = sbuffer; - const char * text = ORD_STRING(ord); + char *bufp = sbuffer; + + const char *text = ORD_STRING(ord); + keyword_t kwd = ORD_KEYWORD(ord); + int bytes; if (ord->_persistent) { - if (size>0) { + if (size > 0) { *bufp++ = '@'; --size; } else { WARN_STATIC_BUFFER(); } } - if (kwd!=NOKEYWORD) { - const struct locale * lang = ORD_LOCALE(ord); - if (size>0) { - if (text) --size; - bytes = (int)strlcpy(bufp, (const char*)LOC(lang, keywords[kwd]), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (text) *bufp++ = ' '; - } else WARN_STATIC_BUFFER(); + if (kwd != NOKEYWORD) { + const struct locale *lang = ORD_LOCALE(ord); + + if (size > 0) { + if (text) + --size; + bytes = (int)strlcpy(bufp, (const char *)LOC(lang, keywords[kwd]), size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + if (text) + *bufp++ = ' '; + } else + WARN_STATIC_BUFFER(); } if (text) { bytes = (int)strlcpy(bufp, (const char *)text, size); - if (wrptr(&bufp, &size, bytes)!=0) { + if (wrptr(&bufp, &size, bytes) != 0) { WARN_STATIC_BUFFER(); - if (bufp-sbuffer>=6) { + if (bufp - sbuffer >= 6) { bufp -= 6; - while (bufp>sbuffer&& (*bufp&0x80)!=0) { + while (bufp > sbuffer && (*bufp & 0x80) != 0) { ++size; --bufp; } - memcpy(bufp+1, "[...]", 6); /* TODO: make sure this only happens in eval_command */ + memcpy(bufp + 1, "[...]", 6); /* TODO: make sure this only happens in eval_command */ bufp += 6; } } } - if (size>0) *bufp = 0; + if (size > 0) + *bufp = 0; return sbuffer; } -char * -getcommand(const order * ord) +char *getcommand(const order * ord) { - char sbuffer[DISPLAYSIZE*2]; + char sbuffer[DISPLAYSIZE * 2]; + return strdup(get_command(ord, sbuffer, sizeof(sbuffer))); } -void -free_order(order * ord) +void free_order(order * ord) { - if (ord!=NULL) { - assert(ord->next==0); + if (ord != NULL) { + assert(ord->next == 0); release_data(ord->data); free(ord); } } -order * -copy_order(const order * src) +order *copy_order(const order * src) { - if (src!=NULL) { - order * ord = (order*)malloc(sizeof(order)); + if (src != NULL) { + order *ord = (order *) malloc(sizeof(order)); + ord->next = NULL; ord->_persistent = src->_persistent; ord->data = src->data; @@ -166,57 +174,63 @@ copy_order(const order * src) return NULL; } -void -set_order(struct order ** destp, struct order * src) +void set_order(struct order **destp, struct order *src) { - if (*destp==src) return; + if (*destp == src) + return; free_order(*destp); *destp = src; } -void -free_orders(order ** olist) +void free_orders(order ** olist) { - while (*olist) { - order * ord = *olist; - *olist = ord->next; + while (*olist) { + order *ord = *olist; + + *olist = ord->next; ord->next = NULL; - free_order(ord); - } + free_order(ord); + } } -static order_data * -create_data(keyword_t kwd, const char * sptr, int lindex) +static order_data *create_data(keyword_t kwd, const char *sptr, int lindex) { - const char * s = sptr; - order_data * data; - const struct locale * lang = locale_array[lindex]->lang; + const char *s = sptr; - if (kwd!=NOKEYWORD) s = (*sptr)?sptr:NULL; + order_data *data; + + const struct locale *lang = locale_array[lindex]->lang; + + if (kwd != NOKEYWORD) + s = (*sptr) ? sptr : NULL; /* learning, only one order_data per skill required */ - if (kwd==K_STUDY) { + if (kwd == K_STUDY) { skill_t sk = findskill(parse_token(&sptr), lang); + switch (sk) { - case NOSKILL: /* fehler */ + case NOSKILL: /* fehler */ break; - case SK_MAGIC: /* kann parameter haben */ - if (*sptr != 0) break; - default: /* nur skill als Parameter, keine extras */ + case SK_MAGIC: /* kann parameter haben */ + if (*sptr != 0) + break; + default: /* nur skill als Parameter, keine extras */ data = locale_array[lindex]->study_orders[sk]; - if (data==NULL) { - const char * skname = skillname(sk, lang); - data = (order_data*)malloc(sizeof(order_data)); + if (data == NULL) { + const char *skname = skillname(sk, lang); + + data = (order_data *) malloc(sizeof(order_data)); locale_array[lindex]->study_orders[sk] = data; data->_keyword = kwd; data->_lindex = lindex; - if (strchr(skname, ' ')!=NULL) { + if (strchr(skname, ' ') != NULL) { size_t len = strlen(skname); - data->_str = malloc(len+3); - data->_str[0]='\"'; - memcpy(data->_str+1, skname, len); - data->_str[len+1]='\"'; - data->_str[len+2]='\0'; + + data->_str = malloc(len + 3); + data->_str[0] = '\"'; + memcpy(data->_str + 1, skname, len); + data->_str[len + 1] = '\"'; + data->_str[len + 2] = '\0'; } else { data->_str = strdup(skname); } @@ -228,10 +242,10 @@ 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) { + else if (kwd != NOKEYWORD && *sptr == 0) { data = locale_array[lindex]->short_orders[kwd]; if (data == NULL) { - data = (order_data*)malloc(sizeof(order_data)); + data = (order_data *) malloc(sizeof(order_data)); locale_array[lindex]->short_orders[kwd] = data; data->_keyword = kwd; data->_lindex = lindex; @@ -241,45 +255,47 @@ create_data(keyword_t kwd, const char * sptr, int lindex) ++data->_refcount; return data; } - data = (order_data*)malloc(sizeof(order_data)); + data = (order_data *) malloc(sizeof(order_data)); data->_keyword = kwd; data->_lindex = lindex; - data->_str = s?strdup(s):NULL; + data->_str = s ? strdup(s) : NULL; data->_refcount = 1; return data; } -static order * -create_order_i(keyword_t kwd, const char * sptr, int persistent, const struct locale * lang) +static order *create_order_i(keyword_t kwd, const char *sptr, int persistent, + const struct locale *lang) { - order * ord = NULL; + order *ord = NULL; + int lindex; /* if this is just nonsense, then we skip it. */ if (lomem) { switch (kwd) { - case K_KOMMENTAR: - case NOKEYWORD: - return NULL; - case K_LIEFERE: - kwd = K_GIVE; - persistent = 1; - break; - default: - break; + case K_KOMMENTAR: + case NOKEYWORD: + return NULL; + case K_LIEFERE: + kwd = K_GIVE; + persistent = 1; + break; + default: + break; } } - for (lindex=0;lindex!=nlocales;++lindex) { - if (locale_array[lindex]->lang==lang) break; + for (lindex = 0; lindex != nlocales; ++lindex) { + if (locale_array[lindex]->lang == lang) + break; } - if (lindex==nlocales) { - locale_array[nlocales] = (locale_data*)calloc(1, sizeof(locale_data)); + if (lindex == nlocales) { + locale_array[nlocales] = (locale_data *) calloc(1, sizeof(locale_data)); locale_array[nlocales]->lang = lang; ++nlocales; } - ord = (order*)malloc(sizeof(order)); + ord = (order *) malloc(sizeof(order)); ord->_persistent = persistent; ord->next = NULL; @@ -288,42 +304,54 @@ create_order_i(keyword_t kwd, const char * sptr, int persistent, const struct lo return ord; } -order * -create_order(keyword_t kwd, const struct locale * lang, const char * params, ...) +order *create_order(keyword_t kwd, const struct locale * lang, + const char *params, ...) { char zBuffer[DISPLAYSIZE]; + if (params) { - char * bufp = zBuffer; + char *bufp = zBuffer; + int bytes; + size_t size = sizeof(zBuffer) - 1; + va_list marker; va_start(marker, params); while (*params) { - if (*params=='%') { + if (*params == '%') { int i; - const char * s; + + const char *s; + ++params; switch (*params) { case 's': s = va_arg(marker, const char *); + bytes = (int)strlcpy(bufp, s, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); break; case 'd': i = va_arg(marker, int); + bytes = (int)strlcpy(bufp, itoa10(i), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); break; case 'i': i = va_arg(marker, int); + bytes = (int)strlcpy(bufp, itoa36(i), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); break; default: assert(!"unknown format-character in create_order"); } - } else if (size>0) { + } else if (size > 0) { *bufp++ = *params; --size; } @@ -337,23 +365,26 @@ create_order(keyword_t kwd, const struct locale * lang, const char * params, ... return create_order_i(kwd, zBuffer, 0, lang); } -order * -parse_order(const char * s, const struct locale * lang) +order *parse_order(const char *s, const struct locale * lang) { - while (*s && !isalnum(*(unsigned char*)s) && !ispunct(*(unsigned char*)s)) ++s; - if (*s!=0) { + while (*s && !isalnum(*(unsigned char *)s) && !ispunct(*(unsigned char *)s)) + ++s; + if (*s != 0) { keyword_t kwd; - const char * sptr; + + const char *sptr; + int persistent = 0; - while (*s=='@') { + while (*s == '@') { persistent = 1; ++s; } sptr = s; kwd = findkeyword(parse_token(&sptr), lang); - if (kwd!=NOKEYWORD) { - while (isxspace(*(unsigned char*)sptr)) ++sptr; + if (kwd != NOKEYWORD) { + while (isxspace(*(unsigned char *)sptr)) + ++sptr; s = sptr; } return create_order_i(kwd, s, persistent, lang); @@ -369,11 +400,12 @@ parse_order(const char * s, const struct locale * lang) * \return true if the order is long * \sa is_exclusive(), is_repeated(), is_persistent() */ -boolean -is_repeated(const order * ord) +boolean is_repeated(const order * ord) { keyword_t kwd = ORD_KEYWORD(ord); - const struct locale * lang = ORD_LOCALE(ord); + + const struct locale *lang = ORD_LOCALE(ord); + param_t param; switch (kwd) { @@ -407,22 +439,24 @@ is_repeated(const order * ord) param = getparam(lang); parser_popstate(); - if (param == P_SHIP) return true; + if (param == P_SHIP) + return true; break; case K_MAKE: /* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen - * Arten von MACHE zaehlen aber als neue defaults und werden - * behandelt wie die anderen (deswegen kein break nach case - * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) - * abgespeichert). */ + * Arten von MACHE zaehlen aber als neue defaults und werden + * behandelt wie die anderen (deswegen kein break nach case + * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) + * abgespeichert). */ parser_pushstate(); - init_tokens(ord); /* initialize token-parser */ + init_tokens(ord); /* initialize token-parser */ skip_token(); param = getparam(lang); parser_popstate(); - if (param != P_TEMP) return true; + if (param != P_TEMP) + return true; break; } return false; @@ -436,11 +470,12 @@ is_repeated(const order * ord) * \return true if the order is long * \sa is_exclusive(), is_repeated(), is_persistent() */ -boolean -is_exclusive(const order * ord) +boolean is_exclusive(const order * ord) { keyword_t kwd = ORD_KEYWORD(ord); - const struct locale * lang = ORD_LOCALE(ord); + + const struct locale *lang = ORD_LOCALE(ord); + param_t param; switch (kwd) { @@ -474,7 +509,8 @@ is_exclusive(const order * ord) param = getparam(lang); parser_popstate(); - if (param == P_SHIP) return true; + if (param == P_SHIP) + return true; break; case K_MAKE: @@ -484,12 +520,13 @@ is_exclusive(const order * ord) * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) * abgespeichert). */ parser_pushstate(); - init_tokens(ord); /* initialize token-parser */ + init_tokens(ord); /* initialize token-parser */ skip_token(); param = getparam(lang); parser_popstate(); - if (param != P_TEMP) return true; + if (param != P_TEMP) + return true; break; } return false; @@ -503,11 +540,12 @@ is_exclusive(const order * ord) * \return true if the order is long * \sa is_exclusive(), is_repeated(), is_persistent() */ -boolean -is_long(const order * ord) +boolean is_long(const order * ord) { keyword_t kwd = ORD_KEYWORD(ord); - const struct locale * lang = ORD_LOCALE(ord); + + const struct locale *lang = ORD_LOCALE(ord); + param_t param; switch (kwd) { @@ -543,7 +581,8 @@ is_long(const order * ord) param = getparam(lang); parser_popstate(); - if (param == P_SHIP) return true; + if (param == P_SHIP) + return true; break; case K_MAKE: @@ -553,12 +592,13 @@ is_long(const order * ord) * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) * abgespeichert). */ parser_pushstate(); - init_tokens(ord); /* initialize token-parser */ + init_tokens(ord); /* initialize token-parser */ skip_token(); param = getparam(lang); parser_popstate(); - if (param != P_TEMP) return true; + if (param != P_TEMP) + return true; break; } return false; @@ -573,12 +613,13 @@ is_long(const order * ord) * \return true if the order is persistent * \sa is_exclusive(), is_repeated(), is_persistent() */ -boolean -is_persistent(const order * ord) +boolean is_persistent(const order * ord) { keyword_t kwd = ORD_KEYWORD(ord); - boolean persist = ord->_persistent!=0; - switch (kwd) { + + boolean persist = ord->_persistent != 0; + + switch (kwd) { case K_MOVE: case K_WEREWOLF: case NOKEYWORD: @@ -588,20 +629,21 @@ is_persistent(const order * ord) case K_KOMMENTAR: case K_LIEFERE: return true; - } + } - return persist || is_repeated(ord); + return persist || is_repeated(ord); } -char * -write_order(const order * ord, char * buffer, size_t size) +char *write_order(const order * ord, char *buffer, size_t size) { - if (ord==0) { - buffer[0]=0; + if (ord == 0) { + buffer[0] = 0; } else { keyword_t kwd = ORD_KEYWORD(ord); - if (kwd==NOKEYWORD) { - const char * text = ORD_STRING(ord); + + if (kwd == NOKEYWORD) { + const char *text = ORD_STRING(ord); + strlcpy(buffer, (const char *)text, size); } else { get_command(ord, buffer, size); @@ -610,7 +652,9 @@ write_order(const order * ord, char * buffer, size_t size) return buffer; } -void push_order(order ** ordp, order * ord) { - while (*ordp) ordp=&(*ordp)->next; +void push_order(order ** ordp, order * ord) +{ + while (*ordp) + ordp = &(*ordp)->next; *ordp = ord; -} \ No newline at end of file +} diff --git a/src/kernel/order.h b/src/kernel/order.h index 7b229644d..3cb4b6b2d 100644 --- a/src/kernel/order.h +++ b/src/kernel/order.h @@ -25,37 +25,38 @@ extern "C" { * implemented yet) saving approx. 50% of all string-related memory. */ -struct order_data; + struct order_data; -typedef struct order { - struct order * next; - /* do not access this data: */ - struct order_data * data; - int _persistent : 1; -} order; + typedef struct order { + struct order *next; + /* do not access this data: */ + struct order_data *data; + int _persistent:1; + } order; /* constructor */ -extern 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); + extern 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); /* reference counted copies of orders: */ -extern order * copy_order(const order * ord); -extern void free_order(order * ord); -extern void free_orders(order ** olist); + extern order *copy_order(const order * ord); + extern void free_order(order * ord); + extern void free_orders(order ** olist); -extern void push_order(struct order ** olist, struct order * ord); + extern void push_order(struct order **olist, struct order *ord); /* access functions for orders */ -extern keyword_t get_keyword(const order * ord); -extern void set_order(order ** destp, order * src); -extern char * getcommand(const order * ord); -extern boolean is_persistent(const order *ord); -extern boolean is_exclusive(const order *ord); -extern boolean is_repeated(const order * ord); -extern boolean is_long(const order *ord); + extern keyword_t get_keyword(const order * ord); + extern void set_order(order ** destp, order * src); + extern char *getcommand(const order * ord); + extern boolean is_persistent(const order * ord); + extern boolean is_exclusive(const order * ord); + extern boolean is_repeated(const order * ord); + extern boolean is_long(const order * ord); -extern char * write_order(const order * ord, char * buffer, size_t size); + extern char *write_order(const order * ord, char *buffer, size_t size); #ifdef __cplusplus diff --git a/src/kernel/pathfinder.c b/src/kernel/pathfinder.c index 29c52ed8b..c86d728a0 100644 --- a/src/kernel/pathfinder.c +++ b/src/kernel/pathfinder.c @@ -27,100 +27,110 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -boolean -allowed_swim(const region * src, const region * r) +boolean allowed_swim(const region * src, const region * r) { - if (fval(r->terrain, SWIM_INTO)) return true; + if (fval(r->terrain, SWIM_INTO)) + return true; return false; } -boolean -allowed_walk(const region * src, const region * r) +boolean allowed_walk(const region * src, const region * r) { - if (fval(r->terrain, WALK_INTO)) return true; + if (fval(r->terrain, WALK_INTO)) + return true; return false; } -boolean -allowed_fly(const region * src, const region * r) +boolean allowed_fly(const region * src, const region * r) { - if (fval(r->terrain, FLY_INTO)) return true; + if (fval(r->terrain, FLY_INTO)) + return true; return false; } typedef struct node { - struct node * next; - region * r; - struct node * prev; - int distance; + struct node *next; + region *r; + struct node *prev; + int distance; } node; -static node * node_garbage; +static node *node_garbage; -void -pathfinder_cleanup(void) +void pathfinder_cleanup(void) { while (node_garbage) { - node * n = node_garbage; + node *n = node_garbage; + node_garbage = n->next; free(n); } } -static node * -new_node(region * r, int distance, node * prev) +static node *new_node(region * r, int distance, node * prev) { - node * n; - if (node_garbage!=NULL) { - n = node_garbage; - node_garbage = n->next; - } - else n = malloc(sizeof(node)); - n->next = NULL; - n->prev = prev; - n->r= r; - n->distance= distance; - return n; + node *n; + + if (node_garbage != NULL) { + n = node_garbage; + node_garbage = n->next; + } else + n = malloc(sizeof(node)); + n->next = NULL; + n->prev = prev; + n->r = r; + n->distance = distance; + return n; } -static node * -free_node(node * n) +static node *free_node(node * n) { - node * s = n->next; - n->next = node_garbage; - node_garbage = n; - return s; + node *s = n->next; + + n->next = node_garbage; + node_garbage = n; + return s; } -static void -free_nodes(node * root) +static void free_nodes(node * root) { - while (root!=NULL) { - region * r = root->r; + while (root != NULL) { + region *r = root->r; + freset(r, RF_MARK); root = free_node(root); } } -struct region_list * -regions_in_range(struct region * start, int maxdist, boolean (*allowed)(const struct region*, const struct region*)) +struct region_list *regions_in_range(struct region *start, int maxdist, + boolean(*allowed) (const struct region *, const struct region *)) { - region_list * rlist = NULL; - node * root = new_node(start, 0, NULL); - node ** end = &root->next; - node * n = root; + region_list *rlist = NULL; + + node *root = new_node(start, 0, NULL); + + node **end = &root->next; + + node *n = root; + + while (n != NULL) { + region *r = n->r; + + int depth = n->distance + 1; - while (n!=NULL) { - region * r = n->r; - int depth = n->distance+1; direction_t d; - if (n->distance >= maxdist) break; - for (d=0;d!=MAXDIRECTIONS; ++d) { - region * rn = rconnect(r, d); - if (rn==NULL) continue; - if (fval(rn, RF_MARK)) continue; /* already been there */ - if (allowed && !allowed(r, rn)) continue; /* can't go there */ + if (n->distance >= maxdist) + break; + for (d = 0; d != MAXDIRECTIONS; ++d) { + region *rn = rconnect(r, d); + + if (rn == NULL) + continue; + if (fval(rn, RF_MARK)) + continue; /* already been there */ + if (allowed && !allowed(r, rn)) + continue; /* can't go there */ /* add the region to the list of available ones. */ add_regionlist(&rlist, rn); @@ -138,63 +148,84 @@ regions_in_range(struct region * start, int maxdist, boolean (*allowed)(const st return rlist; } -static region ** -internal_path_find(region *start, const region *target, int maxlen, boolean (*allowed)(const region*, const region*)) +static region **internal_path_find(region * start, const region * target, + int maxlen, boolean(*allowed) (const region *, const region *)) { - static region * path[MAXDEPTH+2]; /* STATIC_RETURN: used for return, not across calls */ - direction_t d; - node * root = new_node(start, 0, NULL); - node ** end = &root->next; - node * n = root; - boolean found = false; - assert(maxlen<=MAXDEPTH); - fset(start, RF_MARK); + static region *path[MAXDEPTH + 2]; /* STATIC_RETURN: used for return, not across calls */ - while (n!=NULL) { - region * r = n->r; - int depth = n->distance+1; - if (n->distance >= maxlen) break; - for (d=0;d!=MAXDIRECTIONS; ++d) { - region * rn = rconnect(r, d); - if (rn==NULL) continue; - if (fval(rn, RF_MARK)) continue; /* already been there */ - if (!allowed(r, rn)) continue; /* can't go there */ - if (rn==target) { - int i = depth; - path[i+1] = NULL; - path[i] = rn; - while (n) { - path[--i] = n->r; - n = n->prev; - } - found = true; - break; - } else { - fset(rn, RF_MARK); - *end = new_node(rn, depth, n); - end = &(*end)->next; - } - } - if (found) break; - n = n->next; - } + direction_t d; + + node *root = new_node(start, 0, NULL); + + node **end = &root->next; + + node *n = root; + + boolean found = false; + + assert(maxlen <= MAXDEPTH); + fset(start, RF_MARK); + + while (n != NULL) { + region *r = n->r; + + int depth = n->distance + 1; + + if (n->distance >= maxlen) + break; + for (d = 0; d != MAXDIRECTIONS; ++d) { + region *rn = rconnect(r, d); + + if (rn == NULL) + continue; + if (fval(rn, RF_MARK)) + continue; /* already been there */ + if (!allowed(r, rn)) + continue; /* can't go there */ + if (rn == target) { + int i = depth; + + path[i + 1] = NULL; + path[i] = rn; + while (n) { + path[--i] = n->r; + n = n->prev; + } + found = true; + break; + } else { + fset(rn, RF_MARK); + *end = new_node(rn, depth, n); + end = &(*end)->next; + } + } + if (found) + break; + n = n->next; + } free_nodes(root); - if (found) return path; - return NULL; + if (found) + return path; + return NULL; } boolean -path_exists(region *start, const region *target, int maxlen, boolean (*allowed)(const region*, const region*)) +path_exists(region * start, const region * target, int maxlen, + boolean(*allowed) (const region *, const region *)) { - assert((!fval(start, RF_MARK) && !fval(target, RF_MARK)) || !"Some Algorithm did not clear its RF_MARKs!"); - if (start==target) return true; - if (internal_path_find(start, target, maxlen, allowed)!=NULL) return true; - return false; + assert((!fval(start, RF_MARK) && !fval(target, RF_MARK)) + || !"Some Algorithm did not clear its RF_MARKs!"); + if (start == target) + return true; + if (internal_path_find(start, target, maxlen, allowed) != NULL) + return true; + return false; } -region ** -path_find(region *start, const region *target, int maxlen, boolean (*allowed)(const region*, const region*)) +region **path_find(region * start, const region * target, int maxlen, + boolean(*allowed) (const region *, const region *)) { - assert((!fval(start, RF_MARK) && !fval(target, RF_MARK)) || !"Did you call path_init()?"); - return internal_path_find(start, target, maxlen, allowed); + assert((!fval(start, RF_MARK) && !fval(target, RF_MARK)) + || !"Did you call path_init()?"); + return internal_path_find(start, target, maxlen, allowed); } diff --git a/src/kernel/pathfinder.h b/src/kernel/pathfinder.h index 5ae704509..63f50b7d9 100644 --- a/src/kernel/pathfinder.h +++ b/src/kernel/pathfinder.h @@ -24,17 +24,25 @@ extern "C" { #define MAXDEPTH 1024 -extern int search[MAXDEPTH][2]; -extern int search_len; + extern int search[MAXDEPTH][2]; + extern int search_len; -extern struct region ** path_find(struct region *start, const struct region *target, int maxlen, boolean (*allowed)(const struct region*, const struct region*)); -extern boolean path_exists(struct region *start, const struct region *target, int maxlen, boolean (*allowed)(const struct region*, const struct region*)); -extern boolean allowed_swim(const struct region * src, const struct region * target); -extern boolean allowed_fly(const struct region * src, const struct region * target); -extern boolean allowed_walk(const struct region * src, const struct region * target); -extern struct region_list * regions_in_range(struct region * src, int maxdist, boolean (*allowed)(const struct region*, const struct region*)); + extern struct region **path_find(struct region *start, + const struct region *target, int maxlen, + boolean(*allowed) (const struct region *, const struct region *)); + extern boolean path_exists(struct region *start, const struct region *target, + int maxlen, boolean(*allowed) (const struct region *, + const struct region *)); + extern boolean allowed_swim(const struct region *src, + const struct region *target); + extern boolean allowed_fly(const struct region *src, + const struct region *target); + extern boolean allowed_walk(const struct region *src, + const struct region *target); + extern struct region_list *regions_in_range(struct region *src, int maxdist, + boolean(*allowed) (const struct region *, const struct region *)); -extern void pathfinder_cleanup(void); + extern void pathfinder_cleanup(void); #ifdef __cplusplus } diff --git a/src/kernel/plane.c b/src/kernel/plane.c index f2c544ff3..a4d48f7ba 100644 --- a/src/kernel/plane.c +++ b/src/kernel/plane.c @@ -40,7 +40,7 @@ struct plane *planes; int plane_width(const plane * pl) { if (pl) { - return pl->maxx-pl->minx+1; + return pl->maxx - pl->minx + 1; } return 0; } @@ -48,20 +48,18 @@ int plane_width(const plane * pl) int plane_height(const plane * pl) { if (pl) { - return pl->maxy-pl->miny+1; + return pl->maxy - pl->miny + 1; } return 0; } -plane * -get_homeplane(void) +plane *get_homeplane(void) { return getplanebyid(0); } -plane * -getplane(const region *r) +plane *getplane(const region * r) { if (r) { return r->_plane; @@ -69,12 +67,11 @@ getplane(const region *r) return get_homeplane(); } -plane * -getplanebyid(int id) +plane *getplanebyid(int id) { plane *p; - for (p=planes; p; p=p->next) { + for (p = planes; p; p = p->next) { if (p->id == id) { return p; } @@ -82,42 +79,39 @@ getplanebyid(int id) return NULL; } -plane * -getplanebyname(const char * name) +plane *getplanebyname(const char *name) { plane *p; - for (p=planes; p; p=p->next) + for (p = planes; p; p = p->next) if (p->name && !strcmp(p->name, name)) return p; return NULL; } -plane * -findplane(int x, int y) +plane *findplane(int x, int y) { plane *pl; - for(pl=planes;pl;pl=pl->next) { - if(x >= pl->minx && x <= pl->maxx - && y >= pl->miny && y <= pl->maxy) { + for (pl = planes; pl; pl = pl->next) { + if (x >= pl->minx && x <= pl->maxx && y >= pl->miny && y <= pl->maxy) { return pl; } } return NULL; } -int -getplaneid(const region *r) - +int getplaneid(const region * r) { - if(r) { - plane * pl = getplane(r); - if (pl) return pl->id; + if (r) { + plane *pl = getplane(r); - for(pl=planes;pl;pl=pl->next) { - if(r->x >= pl->minx && r->x <= pl->maxx - && r->y >= pl->miny && r->y <= pl->maxy) { + if (pl) + return pl->id; + + for (pl = planes; pl; pl = pl->next) { + if (r->x >= pl->minx && r->x <= pl->maxx + && r->y >= pl->miny && r->y <= pl->maxy) { return pl->id; } } @@ -126,74 +120,81 @@ getplaneid(const region *r) } static int -ursprung_x(const faction *f, const plane *pl, const region * rdefault) +ursprung_x(const faction * f, const plane * pl, const region * rdefault) { ursprung *ur; + int id = 0; - if(!f) + if (!f) return 0; - if(pl) + if (pl) id = pl->id; - for(ur = f->ursprung; ur; ur = ur->next) { - if(ur->id == id) + for (ur = f->ursprung; ur; ur = ur->next) { + if (ur->id == id) return ur->x; } - if (!rdefault) return 0; - set_ursprung((faction*)f, id, rdefault->x - plane_center_x(pl), rdefault->y - plane_center_y(pl)); + if (!rdefault) + return 0; + set_ursprung((faction *) f, id, rdefault->x - plane_center_x(pl), + rdefault->y - plane_center_y(pl)); return rdefault->x - plane_center_x(pl); } static int -ursprung_y(const faction *f, const plane *pl, const region * rdefault) +ursprung_y(const faction * f, const plane * pl, const region * rdefault) { ursprung *ur; + int id = 0; - if(!f) + if (!f) return 0; - if(pl) + if (pl) id = pl->id; - for(ur = f->ursprung; ur; ur = ur->next) { - if(ur->id == id) + for (ur = f->ursprung; ur; ur = ur->next) { + if (ur->id == id) return ur->y; } - if (!rdefault) return 0; - set_ursprung((faction*)f, id, rdefault->x - plane_center_x(pl), rdefault->y - plane_center_y(pl)); + if (!rdefault) + return 0; + set_ursprung((faction *) f, id, rdefault->x - plane_center_x(pl), + rdefault->y - plane_center_y(pl)); return rdefault->y - plane_center_y(pl); } -int -plane_center_x(const plane *pl) +int plane_center_x(const plane * pl) { - if(pl == NULL) + if (pl == NULL) return 0; - return(pl->minx + pl->maxx)/2; + return (pl->minx + pl->maxx) / 2; } -int -plane_center_y(const plane *pl) +int plane_center_y(const plane * pl) { - if(pl == NULL) + if (pl == NULL) return 0; - return(pl->miny + pl->maxy)/2; + return (pl->miny + pl->maxy) / 2; } void -adjust_coordinates(const faction *f, int *x, int *y, const plane * pl, const region * r) +adjust_coordinates(const faction * f, int *x, int *y, const plane * pl, + const region * r) { int nx = *x; + int ny = *y; + if (f) { nx -= ursprung_x(f, pl, r); ny -= ursprung_y(f, pl, r); - } + } if (pl) { nx -= plane_center_x(pl); ny -= plane_center_y(pl); @@ -201,31 +202,38 @@ adjust_coordinates(const faction *f, int *x, int *y, const plane * pl, const reg if (pl) { int width = plane_width(pl); - int height = plane_height(pl); - int width_2 = width/2; - int height_2 = height/2; - if (nx<0) nx = (width-(-nx)%width); - if (nx>width_2) nx -= width; - if (ny<0) ny = (height-(-ny)%height); - if (ny>height_2) ny -= height; + int height = plane_height(pl); + + int width_2 = width / 2; + + int height_2 = height / 2; + + if (nx < 0) + nx = (width - (-nx) % width); + if (nx > width_2) + nx -= width; + if (ny < 0) + ny = (height - (-ny) % height); + if (ny > height_2) + ny -= height; } - assert(!pl || nx<=pl->maxx - plane_center_x(pl)); - assert(!pl || nx>=pl->minx - plane_center_x(pl)); - assert(!pl || ny<=pl->maxy - plane_center_y(pl)); - assert(!pl || ny>=pl->miny - plane_center_y(pl)); + assert(!pl || nx <= pl->maxx - plane_center_x(pl)); + assert(!pl || nx >= pl->minx - plane_center_x(pl)); + assert(!pl || ny <= pl->maxy - plane_center_y(pl)); + assert(!pl || ny >= pl->miny - plane_center_y(pl)); *x = nx; *y = ny; } -void -set_ursprung(faction *f, int id, int x, int y) +void set_ursprung(faction * f, int id, int x, int y) { ursprung *ur; - assert(f!=NULL); - for(ur=f->ursprung;ur;ur=ur->next) { + + assert(f != NULL); + for (ur = f->ursprung; ur; ur = ur->next) { if (ur->id == id) { ur->x = ur->x + x; ur->y = ur->y + y; @@ -234,24 +242,26 @@ set_ursprung(faction *f, int id, int x, int y) } ur = calloc(1, sizeof(ursprung)); - ur->id = id; - ur->x = x; - ur->y = y; + ur->id = id; + ur->x = x; + ur->y = y; addlist(&f->ursprung, ur); } -plane * -create_new_plane(int id, const char *name, int minx, int maxx, int miny, int maxy, int flags) +plane *create_new_plane(int id, const char *name, int minx, int maxx, int miny, + int maxy, int flags) { plane *pl = getplanebyid(id); - if (pl) return pl; + if (pl) + return pl; pl = calloc(1, sizeof(plane)); - pl->next = NULL; - pl->id = id; - if (name) pl->name = strdup(name); + pl->next = NULL; + pl->id = id; + if (name) + pl->name = strdup(name); pl->minx = minx; pl->maxx = maxx; pl->miny = miny; @@ -263,59 +273,63 @@ create_new_plane(int id, const char *name, int minx, int maxx, int miny, int max } /* Umrechnung Relative-Absolute-Koordinaten */ -int -rel_to_abs(const struct plane *pl, const struct faction * f, int rel, unsigned char index) +int +rel_to_abs(const struct plane *pl, const struct faction *f, int rel, + unsigned char index) { assert(index == 0 || index == 1); - if(index == 0) + if (index == 0) return (rel + ursprung_x(f, pl, NULL) + plane_center_x(pl)); return (rel + ursprung_y(f, pl, NULL) + plane_center_y(pl)); } -int -resolve_plane(variant id, void * addr) +int resolve_plane(variant id, void *addr) { int result = 0; - plane * pl = NULL; - if (id.i!=0) { + + plane *pl = NULL; + + if (id.i != 0) { pl = getplanebyid(id.i); - if (pl==NULL) { + if (pl == NULL) { result = -1; } } - *(plane**)addr = pl; + *(plane **) addr = pl; return result; } -void -write_plane_reference(const plane * u, struct storage * store) +void write_plane_reference(const plane * u, struct storage *store) { - store->w_int(store, u?(u->id):0); + store->w_int(store, u ? (u->id) : 0); } -int -read_plane_reference(plane ** pp, struct storage * store) +int read_plane_reference(plane ** pp, struct storage *store) { variant id; + id.i = store->r_int(store); - if (id.i==0) { + if (id.i == 0) { *pp = NULL; return AT_READ_FAIL; } *pp = getplanebyid(id.i); - if (*pp==NULL) ur_add(id, pp, resolve_plane); + if (*pp == NULL) + ur_add(id, pp, resolve_plane); return AT_READ_OK; } -boolean -is_watcher(const struct plane * p, const struct faction * f) +boolean is_watcher(const struct plane * p, const struct faction * f) { - struct watcher * w; - if (!p) return false; + struct watcher *w; + + if (!p) + return false; w = p->watchers; - while (w && w->faction!=f) w=w->next; - return (w!=NULL); + while (w && w->faction != f) + w = w->next; + return (w != NULL); } diff --git a/src/kernel/plane.h b/src/kernel/plane.h index f7827679f..685a36c71 100644 --- a/src/kernel/plane.h +++ b/src/kernel/plane.h @@ -22,62 +22,65 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -#define PFL_NOCOORDS 1 /* not in use */ +#define PFL_NOCOORDS 1 /* not in use */ #define PFL_NORECRUITS 2 #define PFL_NOALLIANCES 4 #define PFL_LOWSTEALING 8 -#define PFL_NOGIVE 16 /* Übergaben sind unmöglich */ -#define PFL_NOATTACK 32 /* Angriffe und Diebstähle sind unmöglich */ -#define PFL_NOTERRAIN 64 /* Terraintyp wird nicht angezeigt TODO? */ -#define PFL_NOMAGIC 128 /* Zaubern ist unmöglich */ -#define PFL_NOSTEALTH 256 /* Tarnung außer Betrieb */ -#define PFL_NOTEACH 512 /* Lehre außer Betrieb */ -#define PFL_NOBUILD 1024 /* Bauen außer Betrieb */ -#define PFL_NOFEED 2048 /* Kein Unterhalt nötig */ -#define PFL_FRIENDLY 4096 /* everyone is your ally */ -#define PFL_NOORCGROWTH 8192 /* orcs don't grow */ -#define PFL_NOMONSTERS 16384 /* no monster randenc */ -#define PFL_SEESPECIAL 32768 /* far seeing */ +#define PFL_NOGIVE 16 /* Übergaben sind unmöglich */ +#define PFL_NOATTACK 32 /* Angriffe und Diebstähle sind unmöglich */ +#define PFL_NOTERRAIN 64 /* Terraintyp wird nicht angezeigt TODO? */ +#define PFL_NOMAGIC 128 /* Zaubern ist unmöglich */ +#define PFL_NOSTEALTH 256 /* Tarnung außer Betrieb */ +#define PFL_NOTEACH 512 /* Lehre außer Betrieb */ +#define PFL_NOBUILD 1024 /* Bauen außer Betrieb */ +#define PFL_NOFEED 2048 /* Kein Unterhalt nötig */ +#define PFL_FRIENDLY 4096 /* everyone is your ally */ +#define PFL_NOORCGROWTH 8192 /* orcs don't grow */ +#define PFL_NOMONSTERS 16384 /* no monster randenc */ +#define PFL_SEESPECIAL 32768 /* far seeing */ -typedef struct watcher { - struct watcher * next; - struct faction * faction; - unsigned char mode; -} watcher; + typedef struct watcher { + struct watcher *next; + struct faction *faction; + unsigned char mode; + } watcher; -typedef struct plane { - struct plane *next; - struct watcher * watchers; - int id; - char *name; - int minx, maxx, miny, maxy; - unsigned int flags; - struct attrib *attribs; -} plane; + typedef struct plane { + struct plane *next; + struct watcher *watchers; + int id; + char *name; + int minx, maxx, miny, maxy; + unsigned int flags; + struct attrib *attribs; + } plane; #define plane_id(pl) ( (pl) ? (pl)->id : 0 ) -extern struct plane *planes; + extern struct plane *planes; -struct plane *getplane(const struct region *r); -struct plane *findplane(int x, int y); -void init_planes(void); -int getplaneid(const struct region *r); -struct plane * getplanebyid(int id); -int plane_center_x(const struct plane *pl); -int plane_center_y(const struct plane *pl); -void set_ursprung(struct faction *f, int id, int x, int y); -struct plane * create_new_plane(int id, const char *name, int minx, int maxx, int miny, int maxy, int flags); -struct plane * getplanebyname(const char *); -struct plane * get_homeplane(void); -extern int rel_to_abs(const struct plane *pl, const struct faction * f, int rel, unsigned char index); -extern boolean is_watcher(const struct plane * p, const struct faction * f); -extern int resolve_plane(variant data, void * addr); -extern void write_plane_reference(const plane * p, struct storage * store); -extern int read_plane_reference(plane ** pp, struct storage * store); -extern int plane_width(const plane * pl); -extern int plane_height(const plane * pl); -void adjust_coordinates(const struct faction *f, int *x, int *y, const struct plane * pl, const struct region * r); + struct plane *getplane(const struct region *r); + struct plane *findplane(int x, int y); + void init_planes(void); + int getplaneid(const struct region *r); + struct plane *getplanebyid(int id); + int plane_center_x(const struct plane *pl); + int plane_center_y(const struct plane *pl); + void set_ursprung(struct faction *f, int id, int x, int y); + struct plane *create_new_plane(int id, const char *name, int minx, int maxx, + int miny, int maxy, int flags); + struct plane *getplanebyname(const char *); + struct plane *get_homeplane(void); + extern int rel_to_abs(const struct plane *pl, const struct faction *f, + int rel, unsigned char index); + extern boolean is_watcher(const struct plane *p, const struct faction *f); + extern int resolve_plane(variant data, void *addr); + extern void write_plane_reference(const plane * p, struct storage *store); + extern int read_plane_reference(plane ** pp, struct storage *store); + extern int plane_width(const plane * pl); + extern int plane_height(const plane * pl); + void adjust_coordinates(const struct faction *f, int *x, int *y, + const struct plane *pl, const struct region *r); #ifdef __cplusplus } #endif diff --git a/src/kernel/player.c b/src/kernel/player.c index c8076f640..628369664 100644 --- a/src/kernel/player.c +++ b/src/kernel/player.c @@ -22,80 +22,88 @@ #define PMAXHASH 1021 typedef struct player_hash { - struct player * entries; + struct player *entries; } player_hash; -static player_hash * players[PMAXHASH]; +static player_hash *players[PMAXHASH]; -player * -make_player(const struct faction * f) +player *make_player(const struct faction *f) { - player * p = calloc(sizeof(player), 1); - unsigned int hash; - - for (p->id = rng_int();;p->id++) { - /* if there is a hashing conflict, resolve it */ - player * pi = get_player(p->id); - if (pi) p->id++; - else break; - } - hash = p->id % PMAXHASH; - p->faction = f; - p->nexthash = players[hash]->entries; - players[hash]->entries = p; + player *p = calloc(sizeof(player), 1); - return p; + unsigned int hash; + + for (p->id = rng_int();; p->id++) { + /* if there is a hashing conflict, resolve it */ + player *pi = get_player(p->id); + + if (pi) + p->id++; + else + break; + } + hash = p->id % PMAXHASH; + p->faction = f; + p->nexthash = players[hash]->entries; + players[hash]->entries = p; + + return p; } -player * -next_player(player * p) +player *next_player(player * p) { - if (p->nexthash) return p->nexthash; - else { - unsigned int hash = p->id % PMAXHASH; - p = NULL; - while (++hash!=PMAXHASH) { - if (players[hash]->entries!=NULL) { - p = players[hash]->entries; - break; - } - } - return p; - } + if (p->nexthash) + return p->nexthash; + else { + unsigned int hash = p->id % PMAXHASH; + + p = NULL; + while (++hash != PMAXHASH) { + if (players[hash]->entries != NULL) { + p = players[hash]->entries; + break; + } + } + return p; + } } -player * -get_player(unsigned int id) +player *get_player(unsigned int id) { - unsigned int hash = id % PMAXHASH; - struct player * p = players[hash]->entries; + unsigned int hash = id % PMAXHASH; - while (p && p->id!=id) p = p->nexthash; - return p; + struct player *p = players[hash]->entries; + + while (p && p->id != id) + p = p->nexthash; + return p; } -player * -get_players(void) +player *get_players(void) { - struct player * p = NULL; - unsigned int hash = 0; + struct player *p = NULL; - while (p!=NULL && hash!=PMAXHASH) { - p = players[hash++]->entries; - } - return p; + unsigned int hash = 0; + + while (p != NULL && hash != PMAXHASH) { + p = players[hash++]->entries; + } + return p; } -void -players_done(void) +void players_done(void) { - int i; - for (i=0;i!=PMAXHASH;++i) { - player * p = players[i]->entries; - players[i]->entries = p->nexthash; - free(p->name); - if (p->email) free(p->email); - if (p->name) free(p->name); - free(p); - } + int i; + + for (i = 0; i != PMAXHASH; ++i) { + player *p = players[i]->entries; + + players[i]->entries = p->nexthash; + free(p->name); + if (p->email) + free(p->email); + if (p->name) + free(p->name); + free(p); + } } diff --git a/src/kernel/player.h b/src/kernel/player.h index 74fb8c4a5..a53a9e75a 100644 --- a/src/kernel/player.h +++ b/src/kernel/player.h @@ -16,26 +16,26 @@ extern "C" { #endif -struct faction; + struct faction; -typedef struct player { - unsigned int id; - char * name; - char * email; - char * address; - struct vacation { - int weeks; - char * email; - } * vacation; - const struct faction * faction; + typedef struct player { + unsigned int id; + char *name; + char *email; + char *address; + struct vacation { + int weeks; + char *email; + } *vacation; + const struct faction *faction; - struct player * nexthash; /* don't use! */ -} player; + struct player *nexthash; /* don't use! */ + } player; -extern struct player * get_players(void); -extern struct player * get_player(unsigned int id); -extern struct player * make_player(const struct faction * f); -extern struct player * next_player(struct player * p); + extern struct player *get_players(void); + extern struct player *get_player(unsigned int id); + extern struct player *make_player(const struct faction *f); + extern struct player *next_player(struct player *p); #ifdef __cplusplus } diff --git a/src/kernel/pool.c b/src/kernel/pool.c index a7a1e6b02..a9c98698a 100644 --- a/src/kernel/pool.c +++ b/src/kernel/pool.c @@ -37,24 +37,27 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define TODO_POOL #undef TODO_RESOURCES -int -get_resource(const unit * u, const resource_type * rtype) +int get_resource(const unit * u, const resource_type * rtype) { - const item_type * itype = resource2item(rtype); + const item_type *itype = resource2item(rtype); if (rtype->uget) { /* this resource is probably special */ int i = rtype->uget(u, rtype); - if (i>=0) return i; + + if (i >= 0) + return i; } - if (itype!=NULL) { - if (itype == olditemtype[R_STONE] && (u->race->flags&RCF_STONEGOLEM)) { - return u->number*GOLEM_STONE; - } else if (itype==olditemtype[R_IRON] && (u->race->flags&RCF_IRONGOLEM)) { - return u->number*GOLEM_IRON; + if (itype != NULL) { + if (itype == olditemtype[R_STONE] && (u->race->flags & RCF_STONEGOLEM)) { + return u->number * GOLEM_STONE; + } else if (itype == olditemtype[R_IRON] && (u->race->flags & RCF_IRONGOLEM)) { + return u->number * GOLEM_IRON; } else { - const item * i = *i_findc(&u->items, itype); - if (i) return i->number; + const item *i = *i_findc(&u->items, itype); + + if (i) + return i->number; return 0; } } @@ -66,8 +69,7 @@ get_resource(const unit * u, const resource_type * rtype) return 0; } -int -change_resource(unit * u, const resource_type * rtype, int change) +int change_resource(unit * u, const resource_type * rtype, int change) { int i = 0; @@ -79,38 +81,40 @@ change_resource(unit * u, const resource_type * rtype, int change) i = change_maxspellpoints(u, change); else assert(!"undefined resource detected. rtype->uchange not initialized."); - assert(i >= 0 && (i < 100000000)); /* soft test to catch mischief */ + assert(i >= 0 && (i < 100000000)); /* soft test to catch mischief */ return i; } -int -get_reservation(const unit * u, const resource_type * rtype) +int get_reservation(const unit * u, const resource_type * rtype) { - struct reservation * res = u->reservations; + struct reservation *res = u->reservations; - if (rtype==oldresourcetype[R_STONE] && (u->race->flags&RCF_STONEGOLEM)) + if (rtype == oldresourcetype[R_STONE] && (u->race->flags & RCF_STONEGOLEM)) return (u->number * GOLEM_STONE); - if (rtype==oldresourcetype[R_IRON] && (u->race->flags&RCF_IRONGOLEM)) + if (rtype == oldresourcetype[R_IRON] && (u->race->flags & RCF_IRONGOLEM)) return (u->number * GOLEM_IRON); - while (res && res->type!=rtype) res=res->next; - if (res) return res->value; + while (res && res->type != rtype) + res = res->next; + if (res) + return res->value; return 0; } -int -change_reservation(unit * u, const resource_type * rtype, int value) +int change_reservation(unit * u, const resource_type * rtype, int value) { - struct reservation *res, ** rp = &u->reservations; + struct reservation *res, **rp = &u->reservations; - if (!value) return 0; + if (!value) + return 0; - while (*rp && (*rp)->type!=rtype) rp=&(*rp)->next; + while (*rp && (*rp)->type != rtype) + rp = &(*rp)->next; res = *rp; if (!res) { *rp = res = calloc(sizeof(struct reservation), 1); res->type = rtype; res->value = value; - } else if (res && res->value+value<=0) { + } else if (res && res->value + value <= 0) { *rp = res->next; free(res); return 0; @@ -120,19 +124,20 @@ change_reservation(unit * u, const resource_type * rtype, int value) return res->value; } -static int -new_set_resvalue(unit * u, const resource_type * rtype, int value) +static int new_set_resvalue(unit * u, const resource_type * rtype, int value) { - struct reservation *res, ** rp = &u->reservations; + struct reservation *res, **rp = &u->reservations; - while (*rp && (*rp)->type!=rtype) rp=&(*rp)->next; + while (*rp && (*rp)->type != rtype) + rp = &(*rp)->next; res = *rp; if (!res) { - if (!value) return 0; + if (!value) + return 0; *rp = res = calloc(sizeof(struct reservation), 1); res->type = rtype; res->value = value; - } else if (res && value<=0) { + } else if (res && value <= 0) { *rp = res->next; free(res); return 0; @@ -143,39 +148,53 @@ new_set_resvalue(unit * u, const resource_type * rtype, int value) } int -get_pooled(const unit * u, const resource_type * rtype, unsigned int mode, int count) +get_pooled(const unit * u, const resource_type * rtype, unsigned int mode, + int count) { - const faction * f = u->faction; + const faction *f = u->faction; + unit *v; + int use = 0; - region * r = u->region; + + region *r = u->region; + int have = get_resource(u, rtype); if ((u->race->ec_flags & GETITEM) == 0) { - mode &= (GET_SLACK|GET_RESERVE); + mode &= (GET_SLACK | GET_RESERVE); } - if ((mode & GET_SLACK) && (mode & GET_RESERVE)) use = have; + if ((mode & GET_SLACK) && (mode & GET_RESERVE)) + use = have; else { int reserve = get_reservation(u, rtype); - int slack = MAX(0, have-reserve); - if (mode & GET_RESERVE) use = have-slack; - else if (mode & GET_SLACK) use = slack; + + int slack = MAX(0, have - reserve); + + if (mode & GET_RESERVE) + use = have - slack; + else if (mode & GET_SLACK) + use = slack; } - if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK|GET_RESERVE)) { - for (v = r->units; v && usenext) if (u!=v) { - int mask; + if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK | GET_RESERVE)) { + for (v = r->units; v && use < count; v = v->next) + if (u != v) { + int mask; - if (v->items==NULL && rtype->uget==NULL) continue; - if ((urace(v)->ec_flags & GIVEITEM) == 0) continue; + if (v->items == NULL && rtype->uget == NULL) + continue; + if ((urace(v)->ec_flags & GIVEITEM) == 0) + continue; - if (v->faction == f) { - mask = (mode >> 3) & (GET_SLACK|GET_RESERVE); + if (v->faction == f) { + mask = (mode >> 3) & (GET_SLACK | GET_RESERVE); + } else if (alliedunit(v, f, HELP_MONEY)) + mask = (mode >> 6) & (GET_SLACK | GET_RESERVE); + else + continue; + use += get_pooled(v, rtype, mask, count - use); } - else if (alliedunit(v, f, HELP_MONEY)) mask = (mode >> 6) & (GET_SLACK|GET_RESERVE); - else continue; - use += get_pooled(v, rtype, mask, count-use); - } } return use; } @@ -184,73 +203,85 @@ int use_pooled(unit * u, const resource_type * rtype, unsigned int mode, int count) { const faction *f = u->faction; + unit *v; + int use = count; - region * r = u->region; + + region *r = u->region; + int n = 0, have = get_resource(u, rtype); if ((u->race->ec_flags & GETITEM) == 0) { - mode &= (GET_SLACK|GET_RESERVE); + mode &= (GET_SLACK | GET_RESERVE); } if ((mode & GET_SLACK) && (mode & GET_RESERVE)) { n = MIN(use, have); } else { int reserve = get_reservation(u, rtype); - int slack = MAX(0, have-reserve); + + int slack = MAX(0, have - reserve); + if (mode & GET_RESERVE) { - n = have-slack; + n = have - slack; n = MIN(use, n); change_reservation(u, rtype, -n); - } - else if (mode & GET_SLACK) { + } else if (mode & GET_SLACK) { n = MIN(use, slack); } } - if (n>0) { + if (n > 0) { change_resource(u, rtype, -n); use -= n; } - if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK|GET_RESERVE)) { - for (v = r->units; use>0 && v!=NULL; v = v->next) if (u!=v) { - int mask; - if ((urace(v)->ec_flags & GIVEITEM) == 0) continue; - if (v->items==NULL && rtype->uget==NULL) continue; + if (rtype->flags & RTF_POOLED && mode & ~(GET_SLACK | GET_RESERVE)) { + for (v = r->units; use > 0 && v != NULL; v = v->next) + if (u != v) { + int mask; - if (v->faction == f) { - mask = (mode >> 3) & (GET_SLACK|GET_RESERVE); + if ((urace(v)->ec_flags & GIVEITEM) == 0) + continue; + if (v->items == NULL && rtype->uget == NULL) + continue; + + if (v->faction == f) { + mask = (mode >> 3) & (GET_SLACK | GET_RESERVE); + } else if (alliedunit(v, f, HELP_MONEY)) + mask = (mode >> 6) & (GET_SLACK | GET_RESERVE); + else + continue; + use -= use_pooled(v, rtype, mask, use); } - else if (alliedunit(v, f, HELP_MONEY)) mask = (mode >> 6) & (GET_SLACK|GET_RESERVE); - else continue; - use -= use_pooled(v, rtype, mask, use); - } } - return count-use; + return count - use; } -int -reserve_cmd(unit * u, struct order *ord) +int reserve_cmd(unit * u, struct order *ord) { if (u->number > 0 && (urace(u)->ec_flags & GETITEM)) { int use, count; - const resource_type * rtype; - const char * s; + + const resource_type *rtype; + + const char *s; init_tokens(ord); skip_token(); s = getstrtoken(); count = atoip((const char *)s); - if (count == 0 && findparam(s, u->faction->locale)==P_EACH) { + if (count == 0 && findparam(s, u->faction->locale) == P_EACH) { count = getint() * u->number; } rtype = findresourcetype(getstrtoken(), u->faction->locale); - if (rtype == NULL) return 0; + if (rtype == NULL) + return 0; - new_set_resvalue(u, rtype, 0); /* make sure the pool is empty */ + new_set_resvalue(u, rtype, 0); /* make sure the pool is empty */ use = use_pooled(u, rtype, GET_DEFAULT, count); if (use) { new_set_resvalue(u, rtype, use); @@ -259,4 +290,3 @@ reserve_cmd(unit * u, struct order *ord) } return 0; } - diff --git a/src/kernel/pool.h b/src/kernel/pool.h index 124bcb432..b6a5e6833 100644 --- a/src/kernel/pool.h +++ b/src/kernel/pool.h @@ -28,7 +28,7 @@ extern "C" { #define GET_POOLED_SLACK 0x08 #define GET_POOLED_RESERVE 0x10 -#define GET_POOLED_FORCE 0x20 /* ignore f->options pools */ +#define GET_POOLED_FORCE 0x20 /* ignore f->options pools */ #define GET_ALLIED_SLACK 0x30 #define GET_ALLIED_RESERVE 0x40 @@ -36,21 +36,25 @@ extern "C" { #define GET_DEFAULT (GET_RESERVE|GET_SLACK|GET_POOLED_SLACK) #define GET_ALL (GET_SLACK|GET_RESERVE|GET_POOLED_SLACK|GET_POOLED_RESERVE|GET_POOLED_FORCE) -int get_pooled(const struct unit * u, const struct resource_type * res, unsigned int mode, int count); -int use_pooled(struct unit * u, const struct resource_type * res, unsigned int mode, int count); - /** use_pooled + int get_pooled(const struct unit *u, const struct resource_type *res, + unsigned int mode, int count); + int use_pooled(struct unit *u, const struct resource_type *res, + unsigned int mode, int count); + /** use_pooled * verbraucht 'count' Objekte der resource 'itm' * unter zuhilfenahme des Pools der struct region und Aufbrauch des * von der Einheit reservierten Resourcen */ -int get_resource(const struct unit * u, const struct resource_type * res); -int change_resource(struct unit * u, const struct resource_type * res, int change); + int get_resource(const struct unit *u, const struct resource_type *res); + int change_resource(struct unit *u, const struct resource_type *res, + int change); -int get_reservation(const struct unit * u, const struct resource_type * res); -int change_reservation(struct unit * u, const struct resource_type * res, int value); + int get_reservation(const struct unit *u, const struct resource_type *res); + int change_reservation(struct unit *u, const struct resource_type *res, + int value); -int reserve_cmd(struct unit *u, struct order *ord); + int reserve_cmd(struct unit *u, struct order *ord); /** init_pool * initialisiert den regionalen Pool. diff --git a/src/kernel/race.c b/src/kernel/race.c index bc2977b0a..d73829086 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -57,19 +57,21 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /** external variables **/ -race * races; +race *races; + int num_races = 0; -race_list * -get_familiarraces(void) +race_list *get_familiarraces(void) { static int init = 0; - static race_list * familiarraces; + + static race_list *familiarraces; if (!init) { - race * rc = races; - for (;rc!=NULL;rc=rc->next) { - if (rc->init_familiar!=NULL) { + race *rc = races; + + for (; rc != NULL; rc = rc->next) { + if (rc->init_familiar != NULL) { racelist_insert(&familiarraces, rc); } } @@ -78,20 +80,19 @@ get_familiarraces(void) return familiarraces; } -void -racelist_clear(struct race_list **rl) +void racelist_clear(struct race_list **rl) { while (*rl) { - race_list * rl2 = (*rl)->next; + race_list *rl2 = (*rl)->next; + free(*rl); *rl = rl2; } } -void -racelist_insert(struct race_list **rl, const struct race *r) +void racelist_insert(struct race_list **rl, const struct race *r) { - race_list *rl2 = (race_list*)malloc(sizeof(race_list)); + race_list *rl2 = (race_list *) malloc(sizeof(race_list)); rl2->data = r; rl2->next = *rl; @@ -99,14 +100,15 @@ racelist_insert(struct race_list **rl, const struct race *r) *rl = rl2; } -race * -rc_new(const char * zName) +race *rc_new(const char *zName) { char zBuffer[80]; - race * rc = calloc(sizeof(race), 1); - if (strchr(zName, ' ')!=NULL) { + + race *rc = calloc(sizeof(race), 1); + + if (strchr(zName, ' ') != NULL) { log_error(("race '%s' has an invalid name. remove spaces\n", zName)); - assert(strchr(zName, ' ')==NULL); + assert(strchr(zName, ' ') == NULL); } strcpy(zBuffer, zName); rc->_name[0] = strdup(zBuffer); @@ -123,56 +125,59 @@ rc_new(const char * zName) return rc; } -race * -rc_add(race * rc) +race *rc_add(race * rc) { rc->index = num_races++; rc->next = races; return races = rc; } -static const char * racealias[][2] = { - { "uruk", "orc" }, /* there was a time when the orc race was called uruk (and there were other orcs). That was really confusing */ - { "skeletton lord", "skeleton lord" }, /* we once had a typo here. it is fixed */ - { NULL, NULL } +static const char *racealias[][2] = { + {"uruk", "orc"}, /* there was a time when the orc race was called uruk (and there were other orcs). That was really confusing */ + {"skeletton lord", "skeleton lord"}, /* we once had a typo here. it is fixed */ + {NULL, NULL} }; -race * -rc_find(const char * name) +race *rc_find(const char *name) { - const char * rname = name; - race * rc = races; + const char *rname = name; + + race *rc = races; + int i; - for (i=0;racealias[i][0];++i) { - if (strcmp(racealias[i][0], name)==0) { + for (i = 0; racealias[i][0]; ++i) { + if (strcmp(racealias[i][0], name) == 0) { rname = racealias[i][1]; break; } } - while (rc && !strcmp(rname, rc->_name[0])==0) rc = rc->next; + while (rc && !strcmp(rname, rc->_name[0]) == 0) + rc = rc->next; return rc; } /** dragon movement **/ -boolean -allowed_dragon(const region * src, const region * target) +boolean allowed_dragon(const region * src, const region * target) { - if (fval(src->terrain, ARCTIC_REGION) && fval(target->terrain, SEA_REGION)) return false; - return allowed_fly(src, target); + if (fval(src->terrain, ARCTIC_REGION) && fval(target->terrain, SEA_REGION)) + return false; + return allowed_fly(src, target); } -char ** race_prefixes = NULL; +char **race_prefixes = NULL; -extern void -add_raceprefix(const char * prefix) +extern void add_raceprefix(const char *prefix) { static size_t size = 4; + static unsigned int next = 0; - if (race_prefixes==NULL) race_prefixes = malloc(size * sizeof(char*)); - if (next+1==size) { + + if (race_prefixes == NULL) + race_prefixes = malloc(size * sizeof(char *)); + if (next + 1 == size) { size *= 2; - race_prefixes = realloc(race_prefixes, size * sizeof(char*)); + race_prefixes = realloc(race_prefixes, size * sizeof(char *)); } race_prefixes[next++] = strdup(prefix); race_prefixes[next] = NULL; @@ -183,56 +188,59 @@ add_raceprefix(const char * prefix) /* "den Zwergen", "Halblingsparteien" */ -void -set_show_item(faction *f, item_t i) +void set_show_item(faction * f, item_t i) { - attrib *a = a_add(&f->attribs, a_new(&at_showitem)); - a->data.v = (void*)olditemtype[i]; + attrib *a = a_add(&f->attribs, a_new(&at_showitem)); + + a->data.v = (void *)olditemtype[i]; } -boolean -r_insectstalled(const region * r) +boolean r_insectstalled(const region * r) { return fval(r->terrain, ARCTIC_REGION); } -const char * -rc_name(const race * rc, int n) +const char *rc_name(const race * rc, int n) { - return rc?mkname("race", rc->_name[n]):NULL; + return rc ? mkname("race", rc->_name[n]) : NULL; } -const char * -raceprefix(const unit *u) +const char *raceprefix(const unit * u) { - const attrib * asource = u->faction->attribs; + const attrib *asource = u->faction->attribs; if (fval(u, UFL_GROUP)) { - const attrib * agroup = agroup = a_findc(u->attribs, &at_group); - if (agroup!=NULL) asource = ((const group *)(agroup->data.v))->attribs; + const attrib *agroup = agroup = a_findc(u->attribs, &at_group); + + if (agroup != NULL) + asource = ((const group *)(agroup->data.v))->attribs; } return get_prefix(asource); } -const char * -racename(const struct locale *loc, const unit *u, const race * rc) +const char *racename(const struct locale *loc, const unit * u, const race * rc) { - const char * prefix = raceprefix(u); + const char *prefix = raceprefix(u); - if (prefix!=NULL) { + if (prefix != NULL) { static char lbuf[80]; - char * bufp = lbuf; + + char *bufp = lbuf; + size_t size = sizeof(lbuf) - 1; + int ch, bytes; bytes = (int)strlcpy(bufp, LOC(loc, mkname("prefix", prefix)), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, LOC(loc, rc_name(rc, u->number != 1)), size); - assert(~bufp[0] & 0x80|| !"unicode/not implemented"); + assert(~bufp[0] & 0x80 || !"unicode/not implemented"); ch = tolower(*(unsigned char *)bufp); bufp[0] = (char)ch; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); *bufp = 0; return lbuf; @@ -241,28 +249,34 @@ racename(const struct locale *loc, const unit *u, const race * rc) } int -rc_specialdamage(const race * ar, const race * dr, const struct weapon_type * wtype) +rc_specialdamage(const race * ar, const race * dr, + const struct weapon_type *wtype) { race_t art = old_race(ar); + int m, modifier = 0; - if (wtype!=NULL && wtype->modifiers!=NULL) for (m=0;wtype->modifiers[m].value;++m) { - /* weapon damage for this weapon, possibly by race */ - if (wtype->modifiers[m].flags & WMF_DAMAGE) { - race_list * rlist = wtype->modifiers[m].races; - if (rlist!=NULL) { - while (rlist) { - if (rlist->data == ar) break; - rlist = rlist->next; + if (wtype != NULL && wtype->modifiers != NULL) + for (m = 0; wtype->modifiers[m].value; ++m) { + /* weapon damage for this weapon, possibly by race */ + if (wtype->modifiers[m].flags & WMF_DAMAGE) { + race_list *rlist = wtype->modifiers[m].races; + + if (rlist != NULL) { + while (rlist) { + if (rlist->data == ar) + break; + rlist = rlist->next; + } + if (rlist == NULL) + continue; } - if (rlist==NULL) continue; + modifier += wtype->modifiers[m].value; } - modifier += wtype->modifiers[m].value; } - } switch (art) { case RC_HALFLING: - if (wtype!=NULL && dragonrace(dr)) { + if (wtype != NULL && dragonrace(dr)) { modifier += 5; } break; @@ -272,25 +286,25 @@ rc_specialdamage(const race * ar, const race * dr, const struct weapon_type * wt return modifier; } -void -write_race_reference(const race * rc, struct storage * store) +void write_race_reference(const race * rc, struct storage *store) { - store->w_tok(store, rc?rc->_name[0]:"none"); + store->w_tok(store, rc ? rc->_name[0] : "none"); } -variant -read_race_reference(struct storage * store) +variant read_race_reference(struct storage *store) { variant result; + char zName[20]; + store->r_tok_buf(store, zName, sizeof(zName)); - if (strcmp(zName, "none")==0) { + if (strcmp(zName, "none") == 0) { result.v = NULL; return result; } else { result.v = rc_find(zName); } - assert(result.v!=NULL); + assert(result.v != NULL); return result; } diff --git a/src/kernel/race.h b/src/kernel/race.h index 321eb4826..b1ec8f889 100644 --- a/src/kernel/race.h +++ b/src/kernel/race.h @@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -#include "magic.h" /* wegen MAXMAGIETYP */ +#include "magic.h" /* wegen MAXMAGIETYP */ #define AT_NONE 0 #define AT_STANDARD 1 @@ -34,136 +34,138 @@ extern "C" { #define AT_COMBATSPELL 7 #define AT_STRUCTURAL 8 -#define GOLEM_IRON 4 /* Anzahl Eisen in einem Eisengolem */ -#define GOLEM_STONE 4 /* Anzahl Steine in einem Steingolem */ +#define GOLEM_IRON 4 /* Anzahl Eisen in einem Eisengolem */ +#define GOLEM_STONE 4 /* Anzahl Steine in einem Steingolem */ -#define RACESPOILCHANCE 5 /* Chance auf rassentypische Beute */ +#define RACESPOILCHANCE 5 /* Chance auf rassentypische Beute */ -typedef struct att { - int type; - union { - const char * dice; - const struct spell * sp; - } data; - int flags; -} att; + typedef struct att { + int type; + union { + const char *dice; + const struct spell *sp; + } data; + int flags; + } att; -struct param; + struct param; -extern int num_races; + extern int num_races; -typedef struct race { - struct param * parameters; - const char *_name[4]; /* neu: name[4]völker */ - float magres; - float maxaura; /* Faktor auf Maximale Aura */ - float regaura; /* Faktor auf Regeneration */ - float recruit_multi; /* Faktor für Bauernverbrauch */ - int index; - int recruitcost; - int maintenance; - int splitsize; - int weight; - int capacity; - float speed; - float aggression; /* chance that a monster will attack */ - int hitpoints; - const char *def_damage; - char armor; - int at_default; /* Angriffsskill Unbewaffnet (default: -2)*/ - int df_default; /* Verteidigungsskill Unbewaffnet (default: -2)*/ - int at_bonus; /* Verändert den Angriffsskill (default: 0)*/ - int df_bonus; /* Verändert den Verteidigungskill (default: 0)*/ - const spell * precombatspell; - struct att attack[10]; - char bonus[MAXSKILLS]; - signed char * study_speed; /* study-speed-bonus in points/turn (0=30 Tage) */ - boolean __remove_me_nonplayer; - int flags; - int battle_flags; - int ec_flags; - race_t oldfamiliars[MAXMAGIETYP]; + typedef struct race { + struct param *parameters; + const char *_name[4]; /* neu: name[4]völker */ + float magres; + float maxaura; /* Faktor auf Maximale Aura */ + float regaura; /* Faktor auf Regeneration */ + float recruit_multi; /* Faktor für Bauernverbrauch */ + int index; + int recruitcost; + int maintenance; + int splitsize; + int weight; + int capacity; + float speed; + float aggression; /* chance that a monster will attack */ + int hitpoints; + const char *def_damage; + char armor; + int at_default; /* Angriffsskill Unbewaffnet (default: -2) */ + int df_default; /* Verteidigungsskill Unbewaffnet (default: -2) */ + int at_bonus; /* Verändert den Angriffsskill (default: 0) */ + int df_bonus; /* Verändert den Verteidigungskill (default: 0) */ + const spell *precombatspell; + struct att attack[10]; + char bonus[MAXSKILLS]; + signed char *study_speed; /* study-speed-bonus in points/turn (0=30 Tage) */ + boolean __remove_me_nonplayer; + int flags; + int battle_flags; + int ec_flags; + race_t oldfamiliars[MAXMAGIETYP]; - const char *(*generate_name) (const struct unit *); - const char *(*describe) (const struct unit *, const struct locale *); - void (*age)(struct unit *u); - boolean (*move_allowed)(const struct region *, const struct region *); - struct item * (*itemdrop)(const struct race *, int size); - void (*init_familiar)(struct unit *); + const char *(*generate_name) (const struct unit *); + const char *(*describe) (const struct unit *, const struct locale *); + void (*age) (struct unit * u); + boolean(*move_allowed) (const struct region *, const struct region *); + struct item *(*itemdrop) (const struct race *, int size); + void (*init_familiar) (struct unit *); - const struct race * familiars[MAXMAGIETYP]; - struct attrib * attribs; - struct race * next; -} race; + const struct race *familiars[MAXMAGIETYP]; + struct attrib *attribs; + struct race *next; + } race; -typedef struct race_list { - struct race_list * next; - const struct race * data; -} race_list; + typedef struct race_list { + struct race_list *next; + const struct race *data; + } race_list; -extern void racelist_clear(struct race_list **rl); -extern void racelist_insert(struct race_list **rl, const struct race *r); + extern void racelist_clear(struct race_list **rl); + extern void racelist_insert(struct race_list **rl, const struct race *r); -extern struct race_list * get_familiarraces(void); -extern struct race * races; + extern struct race_list *get_familiarraces(void); + extern struct race *races; -extern struct race * rc_find(const char *); -extern const char * rc_name(const struct race *, int); -extern struct race * rc_add(struct race *); -extern struct race * rc_new(const char * zName); -extern int rc_specialdamage(const race *, const race *, const struct weapon_type *); + extern struct race *rc_find(const char *); + extern const char *rc_name(const struct race *, int); + extern struct race *rc_add(struct race *); + extern struct race *rc_new(const char *zName); + extern int rc_specialdamage(const race *, const race *, + const struct weapon_type *); /* Flags */ -#define RCF_PLAYERRACE (1<<0) /* can be played by a player. */ -#define RCF_KILLPEASANTS (1<<1) /* Töten Bauern. Dämonen werden nicht über dieses Flag, sondern in randenc() behandelt. */ +#define RCF_PLAYERRACE (1<<0) /* can be played by a player. */ +#define RCF_KILLPEASANTS (1<<1) /* Töten Bauern. Dämonen werden nicht über dieses Flag, sondern in randenc() behandelt. */ #define RCF_SCAREPEASANTS (1<<2) #define RCF_CANSTEAL (1<<3) #define RCF_MOVERANDOM (1<<4) #define RCF_CANNOTMOVE (1<<5) -#define RCF_LEARN (1<<6) /* Lernt automatisch wenn struct faction == 0 */ -#define RCF_FLY (1<<7) /* kann fliegen */ -#define RCF_SWIM (1<<8) /* kann schwimmen */ -#define RCF_WALK (1<<9) /* kann über Land gehen */ -#define RCF_NOLEARN (1<<10) /* kann nicht normal lernen */ -#define RCF_NOTEACH (1<<11) /* kann nicht lehren */ -#define RCF_HORSE (1<<12) /* Einheit ist Pferd, sozusagen */ -#define RCF_DESERT (1<<13) /* 5% Chance, das Einheit desertiert */ -#define RCF_ILLUSIONARY (1<<14) /* (Illusion & Spell) Does not drop items. */ -#define RCF_ABSORBPEASANTS (1<<15) /* Tötet und absorbiert Bauern */ -#define RCF_NOHEAL (1<<16) /* Einheit kann nicht geheilt werden */ -#define RCF_NOWEAPONS (1<<17) /* Einheit kann keine Waffen benutzen */ -#define RCF_SHAPESHIFT (1<<18) /* Kann TARNE RASSE benutzen. */ -#define RCF_SHAPESHIFTANY (1<<19) /* Kann TARNE RASSE "string" benutzen. */ -#define RCF_UNDEAD (1<<20) /* Undead. */ -#define RCF_DRAGON (1<<21) /* Drachenart (für Zauber)*/ -#define RCF_COASTAL (1<<22) /* kann in Landregionen an der Küste sein */ -#define RCF_UNARMEDGUARD (1<<23) /* kann ohne Waffen bewachen */ -#define RCF_CANSAIL (1<<24) /* Einheit darf Schiffe betreten */ -#define RCF_INVISIBLE (1<<25) /* not visible in any report */ -#define RCF_SHIPSPEED (1<<26) /* race gets +1 on shipspeed */ -#define RCF_STONEGOLEM (1<<27) /* race gets stonegolem properties */ -#define RCF_IRONGOLEM (1<<28) /* race gets irongolem properties */ +#define RCF_LEARN (1<<6) /* Lernt automatisch wenn struct faction == 0 */ +#define RCF_FLY (1<<7) /* kann fliegen */ +#define RCF_SWIM (1<<8) /* kann schwimmen */ +#define RCF_WALK (1<<9) /* kann über Land gehen */ +#define RCF_NOLEARN (1<<10) /* kann nicht normal lernen */ +#define RCF_NOTEACH (1<<11) /* kann nicht lehren */ +#define RCF_HORSE (1<<12) /* Einheit ist Pferd, sozusagen */ +#define RCF_DESERT (1<<13) /* 5% Chance, das Einheit desertiert */ +#define RCF_ILLUSIONARY (1<<14) /* (Illusion & Spell) Does not drop items. */ +#define RCF_ABSORBPEASANTS (1<<15) /* Tötet und absorbiert Bauern */ +#define RCF_NOHEAL (1<<16) /* Einheit kann nicht geheilt werden */ +#define RCF_NOWEAPONS (1<<17) /* Einheit kann keine Waffen benutzen */ +#define RCF_SHAPESHIFT (1<<18) /* Kann TARNE RASSE benutzen. */ +#define RCF_SHAPESHIFTANY (1<<19) /* Kann TARNE RASSE "string" benutzen. */ +#define RCF_UNDEAD (1<<20) /* Undead. */ +#define RCF_DRAGON (1<<21) /* Drachenart (für Zauber) */ +#define RCF_COASTAL (1<<22) /* kann in Landregionen an der Küste sein */ +#define RCF_UNARMEDGUARD (1<<23) /* kann ohne Waffen bewachen */ +#define RCF_CANSAIL (1<<24) /* Einheit darf Schiffe betreten */ +#define RCF_INVISIBLE (1<<25) /* not visible in any report */ +#define RCF_SHIPSPEED (1<<26) /* race gets +1 on shipspeed */ +#define RCF_STONEGOLEM (1<<27) /* race gets stonegolem properties */ +#define RCF_IRONGOLEM (1<<28) /* race gets irongolem properties */ /* Economic flags */ #define GIVEITEM (1<<1) /* gibt Gegenstände weg */ #define GIVEPERSON (1<<2) /* übergibt Personen */ #define GIVEUNIT (1<<3) /* Einheiten an andere Partei übergeben */ #define GETITEM (1<<4) /* nimmt Gegenstände an */ -#define ECF_REC_HORSES (1<<6) /* Rekrutiert aus Pferden */ -#define ECF_REC_ETHEREAL (1<<7) /* Rekrutiert aus dem Nichts */ -#define ECF_REC_UNLIMITED (1<<8) /* Rekrutiert ohne Limit */ +#define ECF_REC_HORSES (1<<6) /* Rekrutiert aus Pferden */ +#define ECF_REC_ETHEREAL (1<<7) /* Rekrutiert aus dem Nichts */ +#define ECF_REC_UNLIMITED (1<<8) /* Rekrutiert ohne Limit */ /* Battle-Flags */ -#define BF_EQUIPMENT (1<<0) /* Kann Ausrüstung benutzen */ -#define BF_NOBLOCK (1<<1) /* Wird in die Rückzugsberechnung nicht einbezogen */ -#define BF_RES_PIERCE (1<<2) /* Halber Schaden durch PIERCE */ -#define BF_RES_CUT (1<<3) /* Halber Schaden durch CUT */ -#define BF_RES_BASH (1<<4) /* Halber Schaden durch BASH */ -#define BF_INV_NONMAGIC (1<<5) /* Immun gegen nichtmagischen Schaden */ -#define BF_CANATTACK (1<<6) /* Kann keine ATTACKIERE Befehle ausfuehren */ +#define BF_EQUIPMENT (1<<0) /* Kann Ausrüstung benutzen */ +#define BF_NOBLOCK (1<<1) /* Wird in die Rückzugsberechnung nicht einbezogen */ +#define BF_RES_PIERCE (1<<2) /* Halber Schaden durch PIERCE */ +#define BF_RES_CUT (1<<3) /* Halber Schaden durch CUT */ +#define BF_RES_BASH (1<<4) /* Halber Schaden durch BASH */ +#define BF_INV_NONMAGIC (1<<5) /* Immun gegen nichtmagischen Schaden */ +#define BF_CANATTACK (1<<6) /* Kann keine ATTACKIERE Befehle ausfuehren */ -extern int unit_old_max_hp(struct unit * u); -extern const char * racename(const struct locale *lang, const struct unit *u, const race * rc); + extern int unit_old_max_hp(struct unit *u); + extern const char *racename(const struct locale *lang, const struct unit *u, + const race * rc); #define omniscient(f) (((f)->race)==new_race[RC_ILLUSION] || ((f)->race)==new_race[RC_TEMPLATE]) @@ -172,19 +174,22 @@ extern const char * racename(const struct locale *lang, const struct unit *u, co #define humanoidrace(rc) (fval((rc), RCF_UNDEAD) || (rc)==new_race[RC_DRACOID] || playerrace(rc)) #define illusionaryrace(rc) (fval(rc, RCF_ILLUSIONARY)) -extern boolean allowed_dragon(const struct region * src, const struct region * target); + extern boolean allowed_dragon(const struct region *src, + const struct region *target); -extern boolean r_insectstalled(const struct region *r); + extern boolean r_insectstalled(const struct region *r); -extern void add_raceprefix(const char *); -extern char ** race_prefixes; + extern void add_raceprefix(const char *); + extern char **race_prefixes; -extern void write_race_reference(const struct race * rc, struct storage * store); -extern variant read_race_reference(struct storage * store); + extern void write_race_reference(const struct race *rc, + struct storage *store); + extern variant read_race_reference(struct storage *store); -extern const char * raceprefix(const struct unit *u); + extern const char *raceprefix(const struct unit *u); -extern void give_starting_equipment(const struct equipment * eq, struct unit *u); + extern void give_starting_equipment(const struct equipment *eq, + struct unit *u); #ifdef __cplusplus } diff --git a/src/kernel/region.c b/src/kernel/region.c index 3eb0354c9..9f7cd62c2 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -62,31 +62,31 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern int dice_rand(const char *s); -region *regions; +region *regions; -int -get_maxluxuries() +int get_maxluxuries() { static int maxluxuries = -1; - if (maxluxuries==-1) { - const luxury_type * ltype; + + if (maxluxuries == -1) { + const luxury_type *ltype; + maxluxuries = 0; - for (ltype = luxurytypes;ltype;ltype=ltype->next) ++maxluxuries; + for (ltype = luxurytypes; ltype; ltype = ltype->next) + ++maxluxuries; } return maxluxuries; } -const int delta_x[MAXDIRECTIONS] = -{ + +const int delta_x[MAXDIRECTIONS] = { -1, 0, 1, 1, 0, -1 }; -const int delta_y[MAXDIRECTIONS] = -{ +const int delta_y[MAXDIRECTIONS] = { 1, 1, 0, -1, -1, 0 }; -static const direction_t back[MAXDIRECTIONS] = -{ +static const direction_t back[MAXDIRECTIONS] = { D_SOUTHEAST, D_SOUTHWEST, D_WEST, @@ -95,8 +95,7 @@ static const direction_t back[MAXDIRECTIONS] = D_EAST, }; -direction_t -dir_invert(direction_t dir) +direction_t dir_invert(direction_t dir) { switch (dir) { case D_PAUSE: @@ -104,82 +103,96 @@ dir_invert(direction_t dir) return dir; break; default: - if (dir>=0 && dir= 0 && dir < MAXDIRECTIONS) + return back[dir]; } assert(!"illegal direction"); return NODIRECTION; } -const char * -write_regionname(const region * r, const faction * f, char * buffer, size_t size) +const char *write_regionname(const region * r, const faction * f, char *buffer, + size_t size) { - char * buf = (char *)buffer; - const struct locale * lang = f ? f->locale : 0; - if (r==NULL) { + char *buf = (char *)buffer; + + const struct locale *lang = f ? f->locale : 0; + + if (r == NULL) { strcpy(buf, "(null)"); } else { - plane * pl = rplane(r); + plane *pl = rplane(r); + int nx = r->x, ny = r->y; + pnormalize(&nx, &ny, pl); adjust_coordinates(f, &nx, &ny, pl, r); snprintf(buf, size, "%s (%d,%d)", rname(r, lang), nx, ny); } - buf[size-1] = 0; + buf[size - 1] = 0; return buffer; } -const char * -regionname(const region * r, const faction * f) +const char *regionname(const region * r, const faction * f) { static char buf[NAMESIZE]; + return write_regionname(r, f, buf, sizeof(buf)); } -int -deathcount(const region * r) +int deathcount(const region * r) { - attrib * a = a_find(r->attribs, &at_deathcount); - if (!a) return 0; + attrib *a = a_find(r->attribs, &at_deathcount); + + if (!a) + return 0; return a->data.i; } -int -chaoscount(const region * r) +int chaoscount(const region * r) { - attrib * a = a_find(r->attribs, &at_chaoscount); - if (!a) return 0; + attrib *a = a_find(r->attribs, &at_chaoscount); + + if (!a) + return 0; return a->data.i; } -void -deathcounts (region * r, int fallen) +void deathcounts(region * r, int fallen) { - attrib * a; - static const curse_type * ctype = NULL; + attrib *a; - if (fallen==0) return; - if (!ctype) ctype = ct_find("holyground"); - if (ctype && curse_active(get_curse(r->attribs, ctype))) return; + static const curse_type *ctype = NULL; + + if (fallen == 0) + return; + if (!ctype) + ctype = ct_find("holyground"); + if (ctype && curse_active(get_curse(r->attribs, ctype))) + return; a = a_find(r->attribs, &at_deathcount); - if (!a) a = a_add(&r->attribs, a_new(&at_deathcount)); + if (!a) + a = a_add(&r->attribs, a_new(&at_deathcount)); a->data.i += fallen; - if (a->data.i<=0) a_remove(&r->attribs, a); + if (a->data.i <= 0) + a_remove(&r->attribs, a); } -void -chaoscounts(region * r, int fallen) +void chaoscounts(region * r, int fallen) { - attrib * a; + attrib *a; - if (fallen==0) return; + if (fallen == 0) + return; a = a_find(r->attribs, &at_chaoscount); - if (!a) a = a_add(&r->attribs, a_new(&at_chaoscount)); + if (!a) + a = a_add(&r->attribs, a_new(&at_chaoscount)); a->data.i += fallen; - if (a->data.i<=0) a_remove(&r->attribs, a); + if (a->data.i <= 0) + a_remove(&r->attribs, a); } @@ -187,43 +200,42 @@ chaoscounts(region * r, int fallen) /********************/ /* at_direction */ /********************/ -static void -a_initdirection(attrib *a) +static void a_initdirection(attrib * a) { a->data.v = calloc(1, sizeof(spec_direction)); } -static void -a_freedirection(attrib *a) +static void a_freedirection(attrib * a) { free(a->data.v); } -static int -a_agedirection(attrib *a) +static int a_agedirection(attrib * a) { - spec_direction *d = (spec_direction *)(a->data.v); + spec_direction *d = (spec_direction *) (a->data.v); + --d->duration; - return (d->duration>0)?AT_AGE_KEEP:AT_AGE_REMOVE; + return (d->duration > 0) ? AT_AGE_KEEP : AT_AGE_REMOVE; } typedef struct dir_lookup { - char * name; - const char * oldname; - struct dir_lookup * next; + char *name; + const char *oldname; + struct dir_lookup *next; } dir_lookup; -static dir_lookup * dir_name_lookup; +static dir_lookup *dir_name_lookup; -void -register_special_direction(const char * name) +void register_special_direction(const char *name) { - struct locale * lang; - char * str = strdup(name); + struct locale *lang; - for (lang=locales;lang;lang=nextlocale(lang)) { - tnode * tokens = get_translations(lang, UT_SPECDIR); - const char * token = LOC(lang, name); + char *str = strdup(name); + + for (lang = locales; lang; lang = nextlocale(lang)) { + tnode *tokens = get_translations(lang, UT_SPECDIR); + + const char *token = LOC(lang, name); if (token) { variant var; @@ -231,8 +243,9 @@ register_special_direction(const char * name) var.v = str; addtoken(tokens, token, var); - if (lang==default_locale) { - dir_lookup * dl = malloc(sizeof(dir_lookup)); + if (lang == default_locale) { + dir_lookup *dl = malloc(sizeof(dir_lookup)); + dl->name = str; dl->oldname = token; dl->next = dir_name_lookup; @@ -240,41 +253,40 @@ register_special_direction(const char * name) } } else { log_error(("no translation for spec_direction '%s' in locale '%s'\n", - name, locale_name(lang))); + name, locale_name(lang))); } } } -static int -a_readdirection(attrib *a, void * owner, struct storage * store) +static int a_readdirection(attrib * a, void *owner, struct storage *store) { - spec_direction *d = (spec_direction *)(a->data.v); + spec_direction *d = (spec_direction *) (a->data.v); d->x = (short)store->r_int(store); d->y = (short)store->r_int(store); d->duration = store->r_int(store); - if (store->versionversion < UNICODE_VERSION) { char lbuf[16]; - dir_lookup * dl = dir_name_lookup; + + dir_lookup *dl = dir_name_lookup; store->r_tok_buf(store, NULL, 0); store->r_tok_buf(store, lbuf, sizeof(lbuf)); - + cstring_i(lbuf); - for (;dl;dl=dl->next) { - if (strcmp(lbuf, dl->oldname)==0) { - d->keyword=strdup(dl->name); + for (; dl; dl = dl->next) { + if (strcmp(lbuf, dl->oldname) == 0) { + d->keyword = strdup(dl->name); sprintf(lbuf, "%s_desc", d->keyword); - d->desc=strdup(dl->name); + d->desc = strdup(dl->name); break; } } - if (dl==NULL) { + if (dl == NULL) { log_error(("unknown spec_direction '%s'\n", lbuf)); assert(!"not implemented"); } - } - else { + } else { d->desc = store->r_tok(store); d->keyword = store->r_tok(store); } @@ -283,9 +295,9 @@ a_readdirection(attrib *a, void * owner, struct storage * store) } static void -a_writedirection(const attrib * a, const void * owner, struct storage * store) +a_writedirection(const attrib * a, const void *owner, struct storage *store) { - spec_direction *d = (spec_direction *)(a->data.v); + spec_direction *d = (spec_direction *) (a->data.v); store->w_int(store, d->x); store->w_int(store, d->y); @@ -303,21 +315,26 @@ attrib_type at_direction = { a_readdirection }; -region * -find_special_direction(const region *r, const char *token, const struct locale * lang) +region *find_special_direction(const region * r, const char *token, + const struct locale *lang) { attrib *a; + spec_direction *d; - if (strlen(token)==0) return NULL; - for (a = a_find(r->attribs, &at_direction);a && a->type==&at_direction;a=a->next) { - d = (spec_direction *)(a->data.v); + if (strlen(token) == 0) + return NULL; + for (a = a_find(r->attribs, &at_direction); a && a->type == &at_direction; + a = a->next) { + d = (spec_direction *) (a->data.v); + + if (d->active) { + tnode *tokens = get_translations(lang, UT_SPECDIR); - if (d->active) { - tnode * tokens = get_translations(lang, UT_SPECDIR); variant var; - if (findtoken(tokens, token, &var)==E_TOK_SUCCESS) { - if (strcmp((const char *)var.v, d->keyword)==0) { + + if (findtoken(tokens, token, &var) == E_TOK_SUCCESS) { + if (strcmp((const char *)var.v, d->keyword) == 0) { return findregion(d->x, d->y); } } @@ -327,13 +344,12 @@ find_special_direction(const region *r, const char *token, const struct locale * return NULL; } -attrib * -create_special_direction(region *r, region * rt, int duration, - const char *desc, const char *keyword) - +attrib *create_special_direction(region * r, region * rt, int duration, + const char *desc, const char *keyword) { attrib *a = a_add(&r->attribs, a_new(&at_direction)); - spec_direction *d = (spec_direction *)(a->data.v); + + spec_direction *d = (spec_direction *) (a->data.v); d->active = false; d->x = rt->x; @@ -352,27 +368,27 @@ create_special_direction(region *r, region * rt, int duration, /********************/ /* at_moveblock */ /********************/ -void -a_initmoveblock(attrib *a) +void a_initmoveblock(attrib * a) { a->data.v = calloc(1, sizeof(moveblock)); } -int -a_readmoveblock(attrib *a, void * owner, struct storage * store) +int a_readmoveblock(attrib * a, void *owner, struct storage *store) { - moveblock *m = (moveblock *)(a->data.v); + moveblock *m = (moveblock *) (a->data.v); + int i; i = store->r_int(store); - m->dir = (direction_t)i; + m->dir = (direction_t) i; return AT_READ_OK; } void -a_writemoveblock(const attrib * a, const void * owner, struct storage * store) +a_writemoveblock(const attrib * a, const void *owner, struct storage *store) { - moveblock *m = (moveblock *)(a->data.v); + moveblock *m = (moveblock *) (a->data.v); + store->w_int(store, (int)m->dir); } @@ -382,50 +398,57 @@ attrib_type at_moveblock = { #define coor_hashkey(x, y) (unsigned int)((x<<16) + y) #define RMAXHASH MAXREGIONS -static region * regionhash[RMAXHASH]; +static region *regionhash[RMAXHASH]; + static int dummy_data; -static region * dummy_ptr = (region*)&dummy_data; /* a funny hack */ + +static region *dummy_ptr = (region *) & dummy_data; /* a funny hack */ typedef struct uidhashentry { unsigned int uid; - region * r; + region *r; } uidhashentry; + static uidhashentry uidhash[MAXREGIONS]; -struct region * -findregionbyid(unsigned int uid) +struct region *findregionbyid(unsigned int uid) { int key = uid % MAXREGIONS; - while (uidhash[key].uid!=0 && uidhash[key].uid!=uid) ++key; + + while (uidhash[key].uid != 0 && uidhash[key].uid != uid) + ++key; return uidhash[key].r; } #define DELMARKER dummy_ptr -static void -unhash_uid(region * r) +static void unhash_uid(region * r) { int key = r->uid % MAXREGIONS; + assert(r->uid); - while (uidhash[key].uid!=0 && uidhash[key].uid!=r->uid) ++key; - assert(uidhash[key].r==r); + while (uidhash[key].uid != 0 && uidhash[key].uid != r->uid) + ++key; + assert(uidhash[key].r == r); uidhash[key].r = NULL; } -static void -hash_uid(region * r) +static void hash_uid(region * r) { unsigned int uid = r->uid; + for (;;) { - if (uid!=0) { + if (uid != 0) { int key = uid % MAXREGIONS; - while (uidhash[key].uid!=0 && uidhash[key].uid!=uid) ++key; - if (uidhash[key].uid==0) { + + while (uidhash[key].uid != 0 && uidhash[key].uid != uid) + ++key; + if (uidhash[key].uid == 0) { uidhash[key].uid = uid; uidhash[key].r = r; break; - } - assert(uidhash[key].r!=r || !"duplicate registration"); + } + assert(uidhash[key].r != r || !"duplicate registration"); } r->uid = uid = rng_int(); } @@ -434,30 +457,34 @@ hash_uid(region * r) #define HASH_STATISTICS 1 #if HASH_STATISTICS static int hash_requests; + static int hash_misses; #endif -boolean pnormalize(int * x, int * y, const plane * pl) +boolean pnormalize(int *x, int *y, const plane * pl) { if (pl) { if (x) { int width = pl->maxx - pl->minx + 1; + int nx = *x - pl->minx; - nx = (nx>0)?nx:(width-(-nx)%width); - *x = nx % width+ pl->minx; + + nx = (nx > 0) ? nx : (width - (-nx) % width); + *x = nx % width + pl->minx; } if (y) { int height = pl->maxy - pl->miny + 1; + int ny = *y - pl->miny; - ny = (ny>0)?ny:(height-(-ny)%height); + + ny = (ny > 0) ? ny : (height - (-ny) % height); *y = ny % height + pl->miny; } } - return false; /* TBD */ + return false; /* TBD */ } -static region * -rfindhash(int x, int y) +static region *rfindhash(int x, int y) { unsigned int rid; @@ -465,9 +492,11 @@ rfindhash(int x, int y) #if HASH_STATISTICS ++hash_requests; #endif - if (rid>=0) { + if (rid >= 0) { int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); - while (regionhash[key]!=NULL && (regionhash[key]==DELMARKER || regionhash[key]->x!=x || regionhash[key]->y!=y)) { + + while (regionhash[key] != NULL && (regionhash[key] == DELMARKER + || regionhash[key]->x != x || regionhash[key]->y != y)) { key = (key + gk) % RMAXHASH; #if HASH_STATISTICS ++hash_misses; @@ -478,53 +507,61 @@ rfindhash(int x, int y) return NULL; } -void -rhash(region * r) +void rhash(region * r) { - unsigned int rid = coor_hashkey(r->x, r->y); + unsigned int rid = coor_hashkey(r->x, r->y); + int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); - while (regionhash[key]!=NULL && regionhash[key]!=DELMARKER && regionhash[key]!=r) { + + while (regionhash[key] != NULL && regionhash[key] != DELMARKER + && regionhash[key] != r) { key = (key + gk) % RMAXHASH; } - assert(regionhash[key]!=r || !"trying to add the same region twice"); + assert(regionhash[key] != r || !"trying to add the same region twice"); regionhash[key] = r; } -void -runhash(region * r) +void runhash(region * r) { - unsigned int rid = coor_hashkey(r->x, r->y); + unsigned int rid = coor_hashkey(r->x, r->y); + int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); #ifdef FAST_CONNECT int d, di; - for (d=0,di=MAXDIRECTIONS/2;d!=MAXDIRECTIONS;++d,++di) { - region * rc = r->connect[d]; - if (rc!=NULL) { - if (di>=MAXDIRECTIONS) di-=MAXDIRECTIONS; + + for (d = 0, di = MAXDIRECTIONS / 2; d != MAXDIRECTIONS; ++d, ++di) { + region *rc = r->connect[d]; + + if (rc != NULL) { + if (di >= MAXDIRECTIONS) + di -= MAXDIRECTIONS; rc->connect[di] = NULL; r->connect[d] = NULL; } } #endif - while (regionhash[key]!=NULL && regionhash[key]!=r) { + while (regionhash[key] != NULL && regionhash[key] != r) { key = (key + gk) % RMAXHASH; } - assert(regionhash[key]==r || !"trying to remove a unit that is not hashed"); + assert(regionhash[key] == r || !"trying to remove a unit that is not hashed"); regionhash[key] = DELMARKER; } -region * -r_connect(const region * r, direction_t dir) +region *r_connect(const region * r, direction_t dir) { - region * result; + region *result; + int x, y; + #ifdef FAST_CONNECT - region * rmodify = (region*)r; - assert (dir>=0 && dirconnect[dir]) return r->connect[dir]; + region *rmodify = (region *) r; + + assert(dir >= 0 && dir < MAXDIRECTIONS); + if (r->connect[dir]) + return r->connect[dir]; #endif - assert(dirx + delta_x[dir]; y = r->y + delta_y[dir]; pnormalize(&x, &y, rplane(r)); @@ -538,8 +575,7 @@ r_connect(const region * r, direction_t dir) return result; } -region * -findregion(int x, int y) +region *findregion(int x, int y) { return rfindhash(x, y); } @@ -547,16 +583,16 @@ findregion(int x, int y) /* Contributed by Hubert Mackenberg. Thanks. * x und y Abstand zwischen x1 und x2 berechnen */ -static int -koor_distance_orig(int x1, int y1, int x2, int y2) +static int koor_distance_orig(int x1, int y1, int x2, int y2) { int dx = x1 - x2; + int dy = y1 - y2; /* Bei negativem dy am Ursprung spiegeln, das veraendert * den Abstand nicht */ - if ( dy < 0 ) { + if (dy < 0) { dy = -dy; dx = -dx; } @@ -564,15 +600,15 @@ koor_distance_orig(int x1, int y1, int x2, int y2) /* * dy ist jetzt >=0, fuer dx sind 3 Faelle zu untescheiden */ - if ( dx >= 0 ) { + if (dx >= 0) { int result = dx + dy; + return result; - } - else if (-dx >= dy) { + } else if (-dx >= dy) { int result = -dx; + return result; - } - else { + } else { return dy; } } @@ -581,48 +617,59 @@ static int koor_distance_wrap_xy(int x1, int y1, int x2, int y2, int width, int height) { int dx = x1 - x2; + int dy = y1 - y2; + int result, dist; + int mindist = MIN(width, height) >> 1; /* Bei negativem dy am Ursprung spiegeln, das veraendert * den Abstand nicht */ - if ( dy < 0 ) { + if (dy < 0) { dy = -dy; dx = -dx; } - if (dx<0) { + if (dx < 0) { dx = width + dx; } /* dx,dy is now pointing northeast */ result = dx + dy; - if (result<=mindist) return result; + if (result <= mindist) + return result; - dist = (width-dx) + (height-dy); /* southwest */ - if (dist>=0 && dist= 0 && dist < result) { result = dist; - if (result<=mindist) return result; + if (result <= mindist) + return result; } - dist = MAX(dx, height-dy); - if (dist>=0 && dist= 0 && dist < result) { result = dist; - if (result<=mindist) return result; + if (result <= mindist) + return result; } - dist = MAX(width-dx, dy); - if (dist>=0 && dist= 0 && dist < result) + result = dist; return result; } -int -koor_distance(int x1, int y1, int x2, int y2) +int koor_distance(int x1, int y1, int x2, int y2) { - const plane * p1 = findplane(x1, y1); - const plane * p2 = findplane(x2, y2); - if (p1!=p2) return INT_MAX; + const plane *p1 = findplane(x1, y1); + + const plane *p2 = findplane(x2, y2); + + if (p1 != p2) + return INT_MAX; else { int width = plane_width(p1); + int height = plane_height(p1); + if (width && height) { return koor_distance_wrap_xy(x1, y1, x2, y2, width, height); } else { @@ -631,68 +678,73 @@ koor_distance(int x1, int y1, int x2, int y2) } } -int -distance(const region * r1, const region * r2) +int distance(const region * r1, const region * r2) { return koor_distance(r1->x, r1->y, r2->x, r2->y); } static direction_t -koor_reldirection(int ax, int ay, int bx, int by, const struct plane * pl) +koor_reldirection(int ax, int ay, int bx, int by, const struct plane *pl) { direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { + + for (dir = 0; dir != MAXDIRECTIONS; ++dir) { int x = ax + delta_x[dir]; + int y = ay + delta_y[dir]; + pnormalize(&x, &y, pl); - if (bx == x && by == y) return dir; + if (bx == x && by == y) + return dir; } return NODIRECTION; } -spec_direction * -special_direction(const region * from, const region * to) +spec_direction *special_direction(const region * from, const region * to) { const attrib *a = a_findc(from->attribs, &at_direction); - while (a!=NULL && a->type==&at_direction) { - spec_direction * sd = (spec_direction *)a->data.v; - if (sd->x==to->x && sd->y==to->y) return sd; + while (a != NULL && a->type == &at_direction) { + spec_direction *sd = (spec_direction *) a->data.v; + + if (sd->x == to->x && sd->y == to->y) + return sd; a = a->next; } return NULL; } -direction_t -reldirection(const region * from, const region * to) +direction_t reldirection(const region * from, const region * to) { - plane * pl = rplane(from); + plane *pl = rplane(from); + if (pl == rplane(to)) { direction_t dir = koor_reldirection(from->x, from->y, to->x, to->y, pl); - if (dir==NODIRECTION) { + if (dir == NODIRECTION) { spec_direction *sd = special_direction(from, to); - if (sd!=NULL && sd->active) return D_SPECIAL; + + if (sd != NULL && sd->active) + return D_SPECIAL; } return dir; } return NODIRECTION; } -void -free_regionlist(region_list *rl) +void free_regionlist(region_list * rl) { while (rl) { - region_list * rl2 = rl->next; + region_list *rl2 = rl->next; + free(rl); rl = rl2; } } -void -add_regionlist(region_list **rl, region *r) +void add_regionlist(region_list ** rl, region * r) { - region_list *rl2 = (region_list*)malloc(sizeof(region_list)); + region_list *rl2 = (region_list *) malloc(sizeof(region_list)); rl2->data = r; rl2->next = *rl; @@ -778,107 +830,117 @@ attrib_type at_travelunit = { NO_READ }; -void -rsetroad(region * r, direction_t d, short val) +void rsetroad(region * r, direction_t d, short val) { - connection * b; - region * r2 = rconnect(r, d); + connection *b; - if (!r2) return; + region *r2 = rconnect(r, d); + + if (!r2) + return; b = get_borders(r, r2); - while (b && b->type!=&bt_road) b = b->next; - if (!b) b = new_border(&bt_road, r, r2); - if (r==b->from) b->data.sa[0] = val; - else b->data.sa[1] = val; + while (b && b->type != &bt_road) + b = b->next; + if (!b) + b = new_border(&bt_road, r, r2); + if (r == b->from) + b->data.sa[0] = val; + else + b->data.sa[1] = val; } -short -rroad(const region * r, direction_t d) +short rroad(const region * r, direction_t d) { int rval; - connection * b; - region * r2 = rconnect(r, d); - if (!r2) return 0; + connection *b; + + region *r2 = rconnect(r, d); + + if (!r2) + return 0; b = get_borders(r, r2); - while (b && b->type!=&bt_road) b = b->next; - if (!b) return 0; + while (b && b->type != &bt_road) + b = b->next; + if (!b) + return 0; rval = b->data.i; - if (r==b->from) return b->data.sa[0]; + if (r == b->from) + return b->data.sa[0]; return b->data.sa[1]; } -boolean -r_isforest(const region * r) +boolean r_isforest(const region * r) { if (fval(r->terrain, FOREST_REGION)) { /* needs to be covered with at leas 48% trees */ int mincover = (int)(r->terrain->size * 0.48); + int trees = rtrees(r, 2) + rtrees(r, 1); - return (trees*TREESIZE >= mincover); + + return (trees * TREESIZE >= mincover); } return false; } -int -is_coastregion(region *r) +int is_coastregion(region * r) { direction_t i; + int res = 0; - for(i=0;iterrain, SEA_REGION)) res++; + for (i = 0; i < MAXDIRECTIONS; i++) { + region *rn = rconnect(r, i); + + if (rn && fval(rn->terrain, SEA_REGION)) + res++; } return res; } -int -rpeasants(const region * r) +int rpeasants(const region * r) { - return ((r)->land?(r)->land->peasants:0); + return ((r)->land ? (r)->land->peasants : 0); } -void -rsetpeasants(region * r, int value) +void rsetpeasants(region * r, int value) { - ((r)->land?((r)->land->peasants=(value)):(assert((value)>=0), (value)),0); + ((r)->land ? ((r)->land->peasants = + (value)) : (assert((value) >= 0), (value)), 0); } -int -rmoney(const region * r) +int rmoney(const region * r) { - return ((r)->land?(r)->land->money:0); + return ((r)->land ? (r)->land->money : 0); } -void -rsethorses(const region *r, int value) +void rsethorses(const region * r, int value) { assert(value >= 0); - if(r->land) + if (r->land) r->land->horses = value; } -int -rhorses(const region *r) +int rhorses(const region * r) { - return r->land?r->land->horses:0; + return r->land ? r->land->horses : 0; } -void -rsetmoney(region * r, int value) +void rsetmoney(region * r, int value) { - ((r)->land?((r)->land->money=(value)):(assert((value)>=0), (value)),0); + ((r)->land ? ((r)->land->money = + (value)) : (assert((value) >= 0), (value)), 0); } -void -r_setdemand(region * r, const luxury_type * ltype, int value) +void r_setdemand(region * r, const luxury_type * ltype, int value) { - struct demand * d, ** dp = &r->land->demands; + struct demand *d, **dp = &r->land->demands; - if (ltype==NULL) return; + if (ltype == NULL) + return; - while (*dp && (*dp)->type != ltype) dp = &(*dp)->next; + while (*dp && (*dp)->type != ltype) + dp = &(*dp)->next; d = *dp; if (!d) { d = *dp = malloc(sizeof(struct demand)); @@ -888,32 +950,34 @@ r_setdemand(region * r, const luxury_type * ltype, int value) d->value = value; } -const item_type * -r_luxury(region * r) +const item_type *r_luxury(region * r) { - struct demand * dmd; + struct demand *dmd; + if (r->land) { if (!r->land->demands) { fix_demand(r); } - for (dmd=r->land->demands;dmd;dmd=dmd->next) { - if (dmd->value==0) return dmd->type->itype; + for (dmd = r->land->demands; dmd; dmd = dmd->next) { + if (dmd->value == 0) + return dmd->type->itype; } } return NULL; } -int -r_demand(const region * r, const luxury_type * ltype) +int r_demand(const region * r, const luxury_type * ltype) { - struct demand * d = r->land->demands; - while (d && d->type != ltype) d = d->next; - if (!d) return -1; + struct demand *d = r->land->demands; + + while (d && d->type != ltype) + d = d->next; + if (!d) + return -1; return d->value; } -const char * -rname(const region * r, const struct locale * lang) +const char *rname(const region * r, const struct locale *lang) { if (r->land && r->land->name) { return r->land->name; @@ -921,19 +985,18 @@ rname(const region * r, const struct locale * lang) return LOC(lang, terrain_name(r)); } -int -rtrees(const region *r, int ageclass) +int rtrees(const region * r, int ageclass) { - return ((r)->land?(r)->land->trees[ageclass]:0); + return ((r)->land ? (r)->land->trees[ageclass] : 0); } -int -rsettrees(const region *r, int ageclass, int value) +int rsettrees(const region * r, int ageclass, int value) { - if (!r->land) assert(value==0); + if (!r->land) + assert(value == 0); else { - assert(value>=0); - return r->land->trees[ageclass]=value; + assert(value >= 0); + return r->land->trees[ageclass] = value; } return 0; } @@ -942,16 +1005,16 @@ static region *last; static unsigned int max_index = 0; -region * -new_region(int x, int y, struct plane * pl, unsigned int uid) +region *new_region(int x, int y, struct plane *pl, unsigned int uid) { region *r; - + pnormalize(&x, &y, pl); r = rfindhash(x, y); if (r) { - log_error(("duplicate region discovered: %s(%d,%d)\n", regionname(r, NULL), x, y)); + log_error(("duplicate region discovered: %s(%d,%d)\n", regionname(r, NULL), + x, y)); if (r->units) log_error(("duplicate region contains units\n")); return r; @@ -969,83 +1032,92 @@ new_region(int x, int y, struct plane * pl, unsigned int uid) else addlist(®ions, r); last = r; - assert(r->next==NULL); + assert(r->next == NULL); r->index = ++max_index; return r; } -static region * deleted_regions; +static region *deleted_regions; -void -remove_region(region ** rlist, region * r) +void remove_region(region ** rlist, region * r) { while (r->units) { - unit * u = r->units; + unit *u = r->units; + i_freeall(&u->items); remove_unit(&r->units, u); } runhash(r); unhash_uid(r); - while (*rlist && *rlist!=r) rlist=&(*rlist)->next; - assert(*rlist==r); + while (*rlist && *rlist != r) + rlist = &(*rlist)->next; + assert(*rlist == r); *rlist = r->next; r->next = deleted_regions; deleted_regions = r; } -static void -freeland(land_region * lr) +static void freeland(land_region * lr) { while (lr->demands) { - struct demand * d = lr->demands; + struct demand *d = lr->demands; + lr->demands = d->next; free(d); } - if (lr->name) free(lr->name); + if (lr->name) + free(lr->name); free(lr); } -void -region_setresource(region * r, const resource_type * rtype, int value) +void region_setresource(region * r, const resource_type * rtype, int value) { - rawmaterial * rm = r->resources; + rawmaterial *rm = r->resources; + while (rm) { - if (rm->type->rtype==rtype) { + if (rm->type->rtype == rtype) { rm->amount = value; break; } - rm=rm->next; + rm = rm->next; } if (!rm) { - if (rtype==rt_find("money")) rsetmoney(r, value); - else if (rtype==rt_find("peasant")) rsetpeasants(r, value); - else if (rtype==rt_find("horse")) rsethorses(r, value); + if (rtype == rt_find("money")) + rsetmoney(r, value); + else if (rtype == rt_find("peasant")) + rsetpeasants(r, value); + else if (rtype == rt_find("horse")) + rsethorses(r, value); } } -int -region_getresource(const region * r, const resource_type * rtype) +int region_getresource(const region * r, const resource_type * rtype) { - const rawmaterial * rm; - for (rm=r->resources;rm;rm=rm->next) { - if (rm->type->rtype==rtype) { + const rawmaterial *rm; + + for (rm = r->resources; rm; rm = rm->next) { + if (rm->type->rtype == rtype) { return rm->amount; } } - if (rtype==rt_find("money")) return rmoney(r); - if (rtype==rt_find("horse")) return rhorses(r); - if (rtype==rt_find("peasant")) return rpeasants(r); + if (rtype == rt_find("money")) + return rmoney(r); + if (rtype == rt_find("horse")) + return rhorses(r); + if (rtype == rt_find("peasant")) + return rpeasants(r); return 0; } -void -free_region(region * r) +void free_region(region * r) { - if (last == r) last = NULL; + if (last == r) + last = NULL; free(r->display); - if (r->land) freeland(r->land); + if (r->land) + freeland(r->land); if (r->msgs) { free_messagelist(r->msgs); @@ -1053,27 +1125,33 @@ free_region(region * r) } while (r->individual_messages) { - struct individual_message * msg = r->individual_messages; + struct individual_message *msg = r->individual_messages; + r->individual_messages = msg->next; - if (msg->msgs) free_messagelist(msg->msgs); + if (msg->msgs) + free_messagelist(msg->msgs); free(msg); } - while (r->attribs) a_remove (&r->attribs, r->attribs); + while (r->attribs) + a_remove(&r->attribs, r->attribs); while (r->resources) { - rawmaterial * res = r->resources; + rawmaterial *res = r->resources; + r->resources = res->next; free(res); } while (r->donations) { - donation * don = r->donations; + donation *don = r->donations; + r->donations = don->next; free(don); } while (r->units) { - unit * u = r->units; + unit *u = r->units; + r->units = u->next; uunhash(u); free_unit(u); @@ -1081,16 +1159,18 @@ free_region(region * r) } while (r->buildings) { - building * b = r->buildings; - assert(b->region==r); + building *b = r->buildings; + + assert(b->region == r); r->buildings = b->next; - bunhash(b); /* must be done here, because remove_building does it, and wasn't called */ + bunhash(b); /* must be done here, because remove_building does it, and wasn't called */ free_building(b); } while (r->ships) { - ship * s = r->ships; - assert(s->region==r); + ship *s = r->ships; + + assert(s->region == r); r->ships = s->next; sunhash(s); free_ship(s); @@ -1099,17 +1179,18 @@ free_region(region * r) free(r); } -void -free_regions(void) +void free_regions(void) { memset(uidhash, 0, sizeof(uidhash)); while (deleted_regions) { - region * r = deleted_regions; + region *r = deleted_regions; + deleted_regions = r->next; free_region(r); } while (regions) { - region * r = regions; + region *r = regions; + regions = r->next; runhash(r); free_region(r); @@ -1122,12 +1203,14 @@ free_regions(void) * TODO: Make vowels XML-configurable and allow non-ascii characters again. * - that will probably require a wchar_t * string to pick from. */ -static char * -makename(void) +static char *makename(void) { int s, v, k, e, p = 0, x = 0; + size_t nk, ne, nv, ns; + static char name[16]; + const char *kons = "bcdfghklmnprstvwz", *start = "bcdgtskpvfr", *end = "nlrdst", @@ -1162,52 +1245,57 @@ makename(void) x = 0; } name[p] = '\0'; - name[0] = (char) toupper(name[0]); + name[0] = (char)toupper(name[0]); return name; } -void -setluxuries(region * r, const luxury_type * sale) +void setluxuries(region * r, const luxury_type * sale) { - const luxury_type * ltype; + const luxury_type *ltype; assert(r->land); - if(r->land->demands) freelist(r->land->demands); + if (r->land->demands) + freelist(r->land->demands); + + for (ltype = luxurytypes; ltype; ltype = ltype->next) { + struct demand *dmd = malloc(sizeof(struct demand)); - for (ltype=luxurytypes; ltype; ltype=ltype->next) { - struct demand * dmd = malloc(sizeof(struct demand)); dmd->type = ltype; - if (ltype!=sale) dmd->value = 1 + rng_int() % 5; - else dmd->value = 0; + if (ltype != sale) + dmd->value = 1 + rng_int() % 5; + else + dmd->value = 0; dmd->next = r->land->demands; r->land->demands = dmd; } } -void -terraform_region(region * r, const terrain_type * terrain) +void terraform_region(region * r, const terrain_type * terrain) { /* Resourcen, die nicht mehr vorkommen können, löschen */ - const terrain_type * oldterrain = r->terrain; - rawmaterial **lrm = &r->resources; + const terrain_type *oldterrain = r->terrain; + + rawmaterial **lrm = &r->resources; assert(terrain); while (*lrm) { rawmaterial *rm = *lrm; - const resource_type * rtype = NULL; - if (terrain->production!=NULL) { + const resource_type *rtype = NULL; + + if (terrain->production != NULL) { int i; - for (i=0;terrain->production[i].type;++i) { + + for (i = 0; terrain->production[i].type; ++i) { if (rm->type->rtype == terrain->production[i].type) { rtype = rm->type->rtype; break; } } } - if (rtype==NULL) { + if (rtype == NULL) { *lrm = rm->next; free(rm); } else { @@ -1220,7 +1308,7 @@ terraform_region(region * r, const terrain_type * terrain) if (!fval(terrain, LAND_REGION)) { region_setinfo(r, NULL); - if (r->land!=NULL) { + if (r->land != NULL) { i_freeall(&r->land->items); freeland(r->land); r->land = NULL; @@ -1241,26 +1329,34 @@ terraform_region(region * r, const terrain_type * terrain) i_freeall(&r->land->items); } else { static struct surround { - struct surround * next; - const luxury_type * type; + struct surround *next; + const luxury_type *type; int value; - } *trash =NULL, *nb = NULL; - const luxury_type * ltype = NULL; + } *trash = NULL, *nb = NULL; + + const luxury_type *ltype = NULL; + direction_t d; + int mnr = 0; r->land = calloc(1, sizeof(land_region)); r->land->ownership = NULL; region_set_morale(r, MORALE_DEFAULT, -1); region_setname(r, makename()); - for (d=0;d!=MAXDIRECTIONS;++d) { - region * nr = rconnect(r, d); + for (d = 0; d != MAXDIRECTIONS; ++d) { + region *nr = rconnect(r, d); + if (nr && nr->land) { - struct demand * sale = r->land->demands; - while (sale && sale->value!=0) sale=sale->next; + struct demand *sale = r->land->demands; + + while (sale && sale->value != 0) + sale = sale->next; if (sale) { - struct surround * sr = nb; - while (sr && sr->type!=sale->type) sr=sr->next; + struct surround *sr = nb; + + while (sr && sr->type != sale->type) + sr = sr->next; if (!sr) { if (trash) { sr = trash; @@ -1272,35 +1368,43 @@ terraform_region(region * r, const terrain_type * terrain) sr->type = sale->type; sr->value = 1; nb = sr; - } else sr->value++; + } else + sr->value++; ++mnr; } } } if (!nb) { int i = get_maxluxuries(); - if (i>0) { + + if (i > 0) { i = rng_int() % i; ltype = luxurytypes; - while (i--) ltype=ltype->next; + while (i--) + ltype = ltype->next; } } else { int i = rng_int() % mnr; - struct surround * srd = nb; - while (i>srd->value) { - i-=srd->value; - srd=srd->next; + + struct surround *srd = nb; + + while (i > srd->value) { + i -= srd->value; + srd = srd->next; } - if (srd->type) setluxuries(r, srd->type); - while (srd->next!=NULL) srd=srd->next; - srd->next=trash; + if (srd->type) + setluxuries(r, srd->type); + while (srd->next != NULL) + srd = srd->next; + srd->next = trash; trash = nb; nb = NULL; } } if (fval(terrain, LAND_REGION)) { - const item_type * itype = NULL; + const item_type *itype = NULL; + char equip_hash[64]; /* TODO: put the equipment in struct terrain, faster */ @@ -1308,45 +1412,51 @@ terraform_region(region * r, const terrain_type * terrain) equip_items(&r->land->items, get_equipment(equip_hash)); if (r->terrain->herbs) { - int len=0; - while (r->terrain->herbs[len]) ++len; - if (len) itype = r->terrain->herbs[rng_int()%len]; + int len = 0; + + while (r->terrain->herbs[len]) + ++len; + if (len) + itype = r->terrain->herbs[rng_int() % len]; } - if (itype!=NULL) { + if (itype != NULL) { rsetherbtype(r, itype); - rsetherbs(r, (short)(50+rng_int()%31)); - } - else { + rsetherbs(r, (short)(50 + rng_int() % 31)); + } else { rsetherbtype(r, NULL); } - if (oldterrain==NULL || !fval(oldterrain, LAND_REGION)) { - if (rng_int() % 100 < 3) fset(r, RF_MALLORN); - else freset(r, RF_MALLORN); + if (oldterrain == NULL || !fval(oldterrain, LAND_REGION)) { + if (rng_int() % 100 < 3) + fset(r, RF_MALLORN); + else + freset(r, RF_MALLORN); if (rng_int() % 100 < ENCCHANCE) { fset(r, RF_ENCOUNTER); } } } - if (oldterrain==NULL || terrain->size!=oldterrain->size) { - if (terrain==newterrain(T_PLAIN)) { + if (oldterrain == NULL || terrain->size != oldterrain->size) { + if (terrain == newterrain(T_PLAIN)) { rsethorses(r, rng_int() % (terrain->size / 50)); - if(rng_int()%100 < 40) { - rsettrees(r, 2, terrain->size * (30+rng_int()%40)/1000); + if (rng_int() % 100 < 40) { + rsettrees(r, 2, terrain->size * (30 + rng_int() % 40) / 1000); } } else if (chance(0.2)) { rsettrees(r, 2, terrain->size * (30 + rng_int() % 40) / 1000); } else { rsettrees(r, 2, 0); } - rsettrees(r, 1, rtrees(r, 2)/4); - rsettrees(r, 0, rtrees(r, 2)/8); + rsettrees(r, 1, rtrees(r, 2) / 4); + rsettrees(r, 0, rtrees(r, 2) / 8); if (!fval(r, RF_CHAOTIC)) { int peasants; - peasants = (maxworkingpeasants(r) * (20+dice_rand("6d10")))/100; + + peasants = (maxworkingpeasants(r) * (20 + dice_rand("6d10"))) / 100; rsetpeasants(r, MAX(100, peasants)); - rsetmoney(r, rpeasants(r) * ((wage(r, NULL, NULL, INT_MAX)+1) + rng_int() % 5)); + rsetmoney(r, rpeasants(r) * ((wage(r, NULL, NULL, + INT_MAX) + 1) + rng_int() % 5)); } } } @@ -1357,47 +1467,49 @@ terraform_region(region * r, const terrain_type * terrain) * egal ob durch den spell oder anderes angelegt. **/ #include "curse.h" -int -production(const region *r) +int production(const region * r) { /* muß rterrain(r) sein, nicht rterrain() wegen rekursion */ int p = r->terrain->size / MAXPEASANTS_PER_AREA; - if (curse_active(get_curse(r->attribs, ct_find("drought")))) p /= 2; + + if (curse_active(get_curse(r->attribs, ct_find("drought")))) + p /= 2; return p; } -int -resolve_region_coor(variant id, void * address) { - region * r = findregion(id.sa[0], id.sa[1]); +int resolve_region_coor(variant id, void *address) +{ + region *r = findregion(id.sa[0], id.sa[1]); + if (r) { - *(region**)address = r; + *(region **) address = r; return 0; } - *(region**)address = NULL; + *(region **) address = NULL; return -1; } -int -resolve_region_id(variant id, void * address) +int resolve_region_id(variant id, void *address) { - region * r = NULL; - if (id.i!=0) { + region *r = NULL; + + if (id.i != 0) { r = findregionbyid((unsigned int)id.i); - if (r==NULL) { - *(region**)address = NULL; + if (r == NULL) { + *(region **) address = NULL; return -1; } } - *(region**)address = r; + *(region **) address = r; return 0; } -variant -read_region_reference(struct storage * store) +variant read_region_reference(struct storage * store) { variant result; - if (store->versionversion < UIDHASH_VERSION) { result.sa[0] = (short)store->r_int(store); result.sa[1] = (short)store->r_int(store); } else { @@ -1406,8 +1518,7 @@ read_region_reference(struct storage * store) return result; } -void -write_region_reference(const region * r, struct storage * store) +void write_region_reference(const region * r, struct storage *store) { if (r) { store->w_int(store, r->uid); @@ -1416,24 +1527,29 @@ write_region_reference(const region * r, struct storage * store) } } -struct message_list * -r_getmessages(const struct region * r, const struct faction * viewer) +struct message_list *r_getmessages(const struct region *r, + const struct faction *viewer) { - struct individual_message * imsg = r->individual_messages; - while (imsg && (imsg)->viewer!=viewer) imsg = imsg->next; - if (imsg) return imsg->msgs; + struct individual_message *imsg = r->individual_messages; + + while (imsg && (imsg)->viewer != viewer) + imsg = imsg->next; + if (imsg) + return imsg->msgs; return NULL; } -struct message * -r_addmessage(struct region * r, const struct faction * viewer, struct message * msg) +struct message *r_addmessage(struct region *r, const struct faction *viewer, + struct message *msg) { assert(r); if (viewer) { - struct individual_message * imsg; + struct individual_message *imsg; + imsg = r->individual_messages; - while (imsg && imsg->viewer!=viewer) imsg = imsg->next; - if (imsg==NULL) { + while (imsg && imsg->viewer != viewer) + imsg = imsg->next; + if (imsg == NULL) { imsg = malloc(sizeof(struct individual_message)); imsg->next = r->individual_messages; imsg->msgs = NULL; @@ -1445,8 +1561,7 @@ r_addmessage(struct region * r, const struct faction * viewer, struct message * return add_message(&r->msgs, msg); } -struct faction * -region_get_owner(const struct region * r) +struct faction *region_get_owner(const struct region *r) { assert(rule_region_owners()); if (r->land && r->land->ownership) { @@ -1455,25 +1570,24 @@ region_get_owner(const struct region * r) return NULL; } -struct alliance * -region_get_alliance(const struct region * r) +struct alliance *region_get_alliance(const struct region *r) { assert(rule_region_owners()); if (r->land && r->land->ownership) { - region_owner * own = r->land->ownership; - return own->owner?own->owner->alliance:own->alliance; + region_owner *own = r->land->ownership; + + return own->owner ? own->owner->alliance : own->alliance; } return NULL; } -void -region_set_owner(struct region * r, struct faction * owner, int turn) +void region_set_owner(struct region *r, struct faction *owner, int turn) { assert(rule_region_owners()); if (r->land) { if (!r->land->ownership) { r->land->ownership = malloc(sizeof(region_owner)); - assert(region_get_morale(r)==MORALE_DEFAULT); + assert(region_get_morale(r) == MORALE_DEFAULT); r->land->ownership->owner = NULL; r->land->ownership->alliance = NULL; r->land->ownership->flags = 0; @@ -1489,32 +1603,38 @@ region_set_owner(struct region * r, struct faction * owner, int turn) } -faction * update_owners(region * r) +faction *update_owners(region * r) { - faction * f = NULL; + faction *f = NULL; + assert(rule_region_owners()); if (r->land) { - building * bowner = largestbuilding(r, &cmp_current_owner, false); - building * blargest = largestbuilding(r, &cmp_taxes, false); + building *bowner = largestbuilding(r, &cmp_current_owner, false); + + building *blargest = largestbuilding(r, &cmp_taxes, false); + if (blargest) { - if (!bowner || bowner->sizesize) { + if (!bowner || bowner->size < blargest->size) { /* region owners update? */ - unit * u = building_owner(blargest); + unit *u = building_owner(blargest); + f = region_get_owner(r); - if (u==NULL) { + if (u == NULL) { if (f) { region_set_owner(r, NULL, turn); r->land->ownership->flags |= OWNER_MOURNING; f = NULL; } - } else if (u->faction!=f) { + } else if (u->faction != f) { if (!r->land->ownership) { /* there has never been a prior owner */ region_set_morale(r, MORALE_DEFAULT, turn); } else { - alliance * al = region_get_alliance(r); - if (al && u->faction->alliance==al) { - int morale = MAX(0, r->land->morale-MORALE_TRANSFER); + alliance *al = region_get_alliance(r); + + if (al && u->faction->alliance == al) { + int morale = MAX(0, r->land->morale - MORALE_TRANSFER); + region_set_morale(r, morale, turn); } else { region_set_morale(r, MORALE_TAKEOVER, turn); @@ -1536,29 +1656,27 @@ faction * update_owners(region * r) return f; } -void -region_setinfo(struct region * r, const char * info) +void region_setinfo(struct region *r, const char *info) { free(r->display); - r->display = info?strdup(info):0; + r->display = info ? strdup(info) : 0; } -const char * -region_getinfo(const region * r) { - return r->display?r->display:""; +const char *region_getinfo(const region * r) +{ + return r->display ? r->display : ""; } -void -region_setname(struct region * r, const char * name) +void region_setname(struct region *r, const char *name) { if (r->land) { free(r->land->name); - r->land->name = name?strdup(name):0; + r->land->name = name ? strdup(name) : 0; } } -const char * -region_getname(const region * r) { +const char *region_getname(const region * r) +{ if (r->land && r->land->name) { return r->land->name; } @@ -1568,7 +1686,7 @@ region_getname(const region * r) { int region_get_morale(const region * r) { if (r->land) { - assert(r->land->morale>=0 && r->land->morale<=MORALE_MAX); + assert(r->land->morale >= 0 && r->land->morale <= MORALE_MAX); return r->land->morale; } return -1; @@ -1578,17 +1696,18 @@ void region_set_morale(region * r, int morale, int turn) { if (r->land) { r->land->morale = (short)morale; - if (turn>=0 && r->land->ownership) { + if (turn >= 0 && r->land->ownership) { r->land->ownership->morale_turn = turn; } - assert(r->land->morale>=0 && r->land->morale<=MORALE_MAX); + assert(r->land->morale >= 0 && r->land->morale <= MORALE_MAX); } } void get_neighbours(const region * r, region ** list) { direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { + + for (dir = 0; dir != MAXDIRECTIONS; ++dir) { list[dir] = rconnect(r, dir); } } @@ -1604,5 +1723,7 @@ int owner_change(const region * r) boolean is_mourning(const region * r, int in_turn) { int change = owner_change(r); - return (change==in_turn-1 && (r->land->ownership->flags&OWNER_MOURNING)); + + return (change == in_turn - 1 + && (r->land->ownership->flags & OWNER_MOURNING)); } diff --git a/src/kernel/region.h b/src/kernel/region.h index 5c226fd2a..4afbfa2f6 100644 --- a/src/kernel/region.h +++ b/src/kernel/region.h @@ -47,8 +47,8 @@ extern "C" { /* debug flags */ #define RF_COMBATDEBUG (1<<14) -#define RF_MAPPER_HIGHLIGHT (1<<14) /* only used by mapper, not stored */ -#define RF_LIGHTHOUSE (1<<15) /* this region may contain a lighthouse */ +#define RF_MAPPER_HIGHLIGHT (1<<14) /* only used by mapper, not stored */ +#define RF_LIGHTHOUSE (1<<15) /* this region may contain a lighthouse */ #define RF_SELECT (1<<17) #define RF_MARK (1<<18) @@ -60,170 +60,173 @@ extern "C" { #define RF_ALL 0xFFFFFF #define RF_SAVEMASK (RF_GUARDED|RF_CHAOTIC|RF_MALLORN|RF_BLOCKED|RF_BLOCK_NORTHWEST|RF_BLOCK_NORTHEAST|RF_BLOCK_EAST|RF_BLOCK_SOUTHEAST|RF_BLOCK_SOUTHWEST|RF_BLOCK_WEST|RF_ENCOUNTER|RF_ORCIFIED) -struct message; -struct message_list; -struct rawmaterial; -struct donation; -struct item; + struct message; + struct message_list; + struct rawmaterial; + struct donation; + struct item; #define MORALE_TAX_FACTOR 0.005 /* 0.5% tax per point of morale */ -#define MORALE_MAX 10 /* Maximum morale allowed */ -#define MORALE_DEFAULT 1 /* Morale of peasants when they are conquered for the first time */ -#define MORALE_TAKEOVER 0 /* Morale of peasants after they lose their lord */ -#define MORALE_COOLDOWN 2 /* minimum cooldown before a morale change occurs */ -#define MORALE_AVERAGE 6 /* default average time for morale to change */ -#define MORALE_TRANSFER 2 /* points of morale lost when GIVE COMMAND */ +#define MORALE_MAX 10 /* Maximum morale allowed */ +#define MORALE_DEFAULT 1 /* Morale of peasants when they are conquered for the first time */ +#define MORALE_TAKEOVER 0 /* Morale of peasants after they lose their lord */ +#define MORALE_COOLDOWN 2 /* minimum cooldown before a morale change occurs */ +#define MORALE_AVERAGE 6 /* default average time for morale to change */ +#define MORALE_TRANSFER 2 /* points of morale lost when GIVE COMMAND */ #define OWNER_MOURNING 0x01 -typedef struct region_owner { - struct faction * owner; - struct alliance * alliance; - int since_turn; /* turn the region changed owners */ - int morale_turn; /* turn when morale has changed most recently */ - unsigned int flags; -} region_owner; + typedef struct region_owner { + struct faction *owner; + struct alliance *alliance; + int since_turn; /* turn the region changed owners */ + int morale_turn; /* turn when morale has changed most recently */ + unsigned int flags; + } region_owner; -typedef struct demand { - struct demand * next; - const struct luxury_type * type; - int value; -} demand; + typedef struct demand { + struct demand *next; + const struct luxury_type *type; + int value; + } demand; -typedef struct land_region { - char *name; - /* TODO: demand kann nach Konvertierung entfernt werden. */ - demand * demands; - const struct item_type * herbtype; - short herbs; - short morale; - int trees[3]; /* 0 -> seeds, 1 -> shoots, 2 -> trees */ - int horses; - int peasants; - int newpeasants; - int money; - struct item * items; /* items that can be claimed */ - struct region_owner * ownership; -} land_region; + typedef struct land_region { + char *name; + /* TODO: demand kann nach Konvertierung entfernt werden. */ + demand *demands; + const struct item_type *herbtype; + short herbs; + short morale; + int trees[3]; /* 0 -> seeds, 1 -> shoots, 2 -> trees */ + int horses; + int peasants; + int newpeasants; + int money; + struct item *items; /* items that can be claimed */ + struct region_owner *ownership; + } land_region; -typedef struct donation { - struct donation *next; - struct faction *f1, *f2; - int amount; -} donation; + typedef struct donation { + struct donation *next; + struct faction *f1, *f2; + int amount; + } donation; -typedef struct region { - struct region *next; - struct land_region *land; - struct unit *units; - struct ship *ships; - struct building *buildings; - unsigned int index; - /* an ascending number, to improve the speed of determining the interval in - which a faction has its units. See the implementations of firstregion - and lastregion */ - unsigned int uid; /* a unique id */ - int x, y; - struct plane * _plane; /* to access, use rplane(r) */ - char *display; - unsigned int flags; - unsigned short age; - struct message_list *msgs; - struct individual_message { - struct individual_message * next; - const struct faction * viewer; + typedef struct region { + struct region *next; + struct land_region *land; + struct unit *units; + struct ship *ships; + struct building *buildings; + unsigned int index; + /* an ascending number, to improve the speed of determining the interval in + which a faction has its units. See the implementations of firstregion + and lastregion */ + unsigned int uid; /* a unique id */ + int x, y; + struct plane *_plane; /* to access, use rplane(r) */ + char *display; + unsigned int flags; + unsigned short age; struct message_list *msgs; - } * individual_messages; - struct attrib *attribs; - struct donation * donations; - const struct terrain_type * terrain; - struct rawmaterial * resources; + struct individual_message { + struct individual_message *next; + const struct faction *viewer; + struct message_list *msgs; + } *individual_messages; + struct attrib *attribs; + struct donation *donations; + const struct terrain_type *terrain; + struct rawmaterial *resources; #ifdef FAST_CONNECT - struct region * connect[MAXDIRECTIONS]; /* use rconnect(r, dir) to access */ + struct region *connect[MAXDIRECTIONS]; /* use rconnect(r, dir) to access */ #endif -} region; + } region; -extern struct region *regions; + extern struct region *regions; -typedef struct region_list { - struct region_list * next; - struct region * data; -} region_list; + typedef struct region_list { + struct region_list *next; + struct region *data; + } region_list; -struct message_list * r_getmessages(const struct region * r, const struct faction * viewer); -struct message * r_addmessage(struct region * r, const struct faction * viewer, struct message * msg); + struct message_list *r_getmessages(const struct region *r, + const struct faction *viewer); + struct message *r_addmessage(struct region *r, const struct faction *viewer, + struct message *msg); -typedef struct spec_direction { - int x, y; - int duration; - boolean active; - char *desc; - char *keyword; -} spec_direction; + typedef struct spec_direction { + int x, y; + int duration; + boolean active; + char *desc; + char *keyword; + } spec_direction; -typedef struct { - direction_t dir; -} moveblock; + typedef struct { + direction_t dir; + } moveblock; #define reg_hashkey(r) (r->index) -int distance(const struct region*, const struct region*); -int koor_distance(int ax, int ay, int bx, int by) ; -direction_t reldirection(const struct region * from, const struct region * to); -struct region * findregion(int x, int y); -struct region * findregionbyid(unsigned int uid); + int distance(const struct region *, const struct region *); + int koor_distance(int ax, int ay, int bx, int by); + direction_t reldirection(const struct region *from, const struct region *to); + struct region *findregion(int x, int y); + struct region *findregionbyid(unsigned int uid); -extern struct attrib_type at_direction; -extern struct attrib_type at_moveblock; -extern struct attrib_type at_peasantluck; -extern struct attrib_type at_horseluck; -extern struct attrib_type at_chaoscount; -extern struct attrib_type at_woodcount; -extern struct attrib_type at_deathcount; -extern struct attrib_type at_travelunit; + extern struct attrib_type at_direction; + extern struct attrib_type at_moveblock; + extern struct attrib_type at_peasantluck; + extern struct attrib_type at_horseluck; + extern struct attrib_type at_chaoscount; + extern struct attrib_type at_woodcount; + extern struct attrib_type at_deathcount; + extern struct attrib_type at_travelunit; -void initrhash(void); -void rhash(struct region * r); -void runhash(struct region * r); + void initrhash(void); + void rhash(struct region *r); + void runhash(struct region *r); -void free_regionlist(region_list *rl); -void add_regionlist(region_list **rl, struct region *r); + void free_regionlist(region_list * rl); + void add_regionlist(region_list ** rl, struct region *r); -struct region * find_special_direction(const struct region *r, const char *token, const struct locale * lang); -void register_special_direction(const char * name); -struct spec_direction * special_direction(const region * from, const region * to); -struct attrib *create_special_direction(struct region *r, struct region *rt, - int duration, const char *desc, - const char *keyword); + struct region *find_special_direction(const struct region *r, + const char *token, const struct locale *lang); + void register_special_direction(const char *name); + struct spec_direction *special_direction(const region * from, + const region * to); + struct attrib *create_special_direction(struct region *r, struct region *rt, + int duration, const char *desc, const char *keyword); -int deathcount(const struct region * r); -int chaoscount(const struct region * r); + int deathcount(const struct region *r); + int chaoscount(const struct region *r); -void deathcounts(struct region * r, int delta); -void chaoscounts(struct region * r, int delta); + void deathcounts(struct region *r, int delta); + void chaoscounts(struct region *r, int delta); -void setluxuries(struct region * r, const struct luxury_type * sale); -int get_maxluxuries(void); + void setluxuries(struct region *r, const struct luxury_type *sale); + int get_maxluxuries(void); -short rroad(const struct region * r, direction_t d); -void rsetroad(struct region * r, direction_t d, short value); + short rroad(const struct region *r, direction_t d); + void rsetroad(struct region *r, direction_t d, short value); -int is_coastregion(struct region *r); + int is_coastregion(struct region *r); -int rtrees(const struct region * r, int ageclass); -enum { - TREE_SEED = 0, - TREE_SAPLING = 1, - TREE_TREE = 2 -}; + int rtrees(const struct region *r, int ageclass); + enum { + TREE_SEED = 0, + TREE_SAPLING = 1, + TREE_TREE = 2 + }; -int rsettrees(const struct region *r, int ageclass, int value); + int rsettrees(const struct region *r, int ageclass, int value); -int rpeasants(const struct region * r); -void rsetpeasants(struct region * r, int value); -int rmoney(const struct region * r); -void rsetmoney(struct region * r, int value); -int rhorses(const struct region * r); -void rsethorses(const struct region * r, int value); + int rpeasants(const struct region *r); + void rsetpeasants(struct region *r, int value); + int rmoney(const struct region *r); + void rsetmoney(struct region *r, int value); + int rhorses(const struct region *r); + void rsethorses(const struct region *r, int value); #define rbuildings(r) ((r)->buildings) @@ -233,68 +236,72 @@ void rsethorses(const struct region * r, int value); #define rherbs(r) ((r)->land?(r)->land->herbs:0) #define rsetherbs(r, value) if ((r)->land) ((r)->land->herbs=(short)(value)) -boolean r_isforest(const struct region * r); + boolean r_isforest(const struct region *r); #define rterrain(r) (oldterrain((r)->terrain)) #define rsetterrain(r, t) ((r)->terrain = newterrain(t)) -const char * rname(const struct region * r, const struct locale * lang); + const char *rname(const struct region *r, const struct locale *lang); #define rplane(r) getplane(r) -void r_setdemand(struct region * r, const struct luxury_type * ltype, int value); -int r_demand(const struct region * r, const struct luxury_type * ltype); + void r_setdemand(struct region *r, const struct luxury_type *ltype, + int value); + int r_demand(const struct region *r, const struct luxury_type *ltype); -const char * write_regionname(const struct region * r, const struct faction * f, char * buffer, size_t size); + const char *write_regionname(const struct region *r, const struct faction *f, + char *buffer, size_t size); -struct region * new_region(int x, int y, struct plane * pl, unsigned int uid); -void remove_region(region ** rlist, region * r); -void terraform_region(struct region * r, const struct terrain_type * terrain); -boolean pnormalize(int * x, int * y, const struct plane * pl); + struct region *new_region(int x, int y, struct plane *pl, unsigned int uid); + void remove_region(region ** rlist, region * r); + void terraform_region(struct region *r, const struct terrain_type *terrain); + boolean pnormalize(int *x, int *y, const struct plane *pl); -extern const int delta_x[MAXDIRECTIONS]; -extern const int delta_y[MAXDIRECTIONS]; -direction_t dir_invert(direction_t dir); -int production(const struct region *r); + extern const int delta_x[MAXDIRECTIONS]; + extern const int delta_y[MAXDIRECTIONS]; + direction_t dir_invert(direction_t dir); + int production(const struct region *r); -void region_set_owner(struct region * r, struct faction * owner, int turn); -struct faction * region_get_owner(const struct region * r); -struct alliance * region_get_alliance(const struct region * r); + void region_set_owner(struct region *r, struct faction *owner, int turn); + struct faction *region_get_owner(const struct region *r); + struct alliance *region_get_alliance(const struct region *r); -struct region * r_connect(const struct region *, direction_t dir); + struct region *r_connect(const struct region *, direction_t dir); #ifdef FAST_CONNECT # define rconnect(r, dir) ((r)->connect[dir]?(r)->connect[dir]:r_connect(r, (direction_t)dir)) #else # define rconnect(r, dir) r_connect(r, (direction_t)dir) #endif -void free_regions(void); + void free_regions(void); -int region_get_morale(const region * r); -void region_set_morale(region * r, int morale, int turn); + int region_get_morale(const region * r); + void region_set_morale(region * r, int morale, int turn); -void write_region_reference(const struct region * r, struct storage * store); -variant read_region_reference(struct storage * store); -int resolve_region_coor(variant id, void * address); -int resolve_region_id(variant id, void * address); + void write_region_reference(const struct region *r, struct storage *store); + variant read_region_reference(struct storage *store); + int resolve_region_coor(variant id, void *address); + int resolve_region_id(variant id, void *address); #define RESOLVE_REGION(version) ((version boolean nocr = false; + boolean nonr = false; + boolean noreports = false; -const char * visibility[] = { +const char *visibility[] = { "none", "neighbour", "lighthouse", @@ -83,35 +85,36 @@ const char * visibility[] = { "battle" }; -const char *coasts[MAXDIRECTIONS] = -{ - "coast::nw", - "coast::ne", - "coast::e", - "coast::se", - "coast::sw", - "coast::w" +const char *coasts[MAXDIRECTIONS] = { + "coast::nw", + "coast::ne", + "coast::e", + "coast::se", + "coast::sw", + "coast::w" }; -static char * -groupid(const struct group * g, const struct faction * f) +static char *groupid(const struct group *g, const struct faction *f) { - typedef char name[OBJECTIDSIZE + 1]; - static name idbuf[8]; - static int nextbuf = 0; - char *buf = idbuf[(++nextbuf) % 8]; - sprintf(buf, "%s (%s)", g->name, factionid(f)); - return buf; + typedef char name[OBJECTIDSIZE + 1]; + + static name idbuf[8]; + + static int nextbuf = 0; + + char *buf = idbuf[(++nextbuf) % 8]; + + sprintf(buf, "%s (%s)", g->name, factionid(f)); + return buf; } -const char * combatstatus[] = { +const char *combatstatus[] = { "status_aggressive", "status_front", "status_rear", "status_defensive", "status_avoid", "status_flee" }; -const char * -report_kampfstatus(const unit * u, const struct locale * lang) +const char *report_kampfstatus(const unit * u, const struct locale *lang) { static char fsbuf[64]; @@ -124,66 +127,95 @@ report_kampfstatus(const unit * u, const struct locale * lang) return fsbuf; } -const char * -hp_status(const unit * u) +const char *hp_status(const unit * u) { - double p = (double) ((double) u->hp / (double) (u->number * unit_max_hp(u))); + double p = (double)((double)u->hp / (double)(u->number * unit_max_hp(u))); - if (p > 2.00) return mkname("damage", "critical"); - if (p > 1.50) return mkname("damage", "heavily"); - if (p < 0.50) return mkname("damage", "badly"); - if (p < 0.75) return mkname("damage", "wounded"); - if (p < 0.99) return mkname("damage", "exhausted"); + if (p > 2.00) + return mkname("damage", "critical"); + if (p > 1.50) + return mkname("damage", "heavily"); + if (p < 0.50) + return mkname("damage", "badly"); + if (p < 0.75) + return mkname("damage", "wounded"); + if (p < 0.99) + return mkname("damage", "exhausted"); - return NULL; + return NULL; } void -report_item(const unit * owner, const item * i, const faction * viewer, const char ** name, const char ** basename, int * number, boolean singular) +report_item(const unit * owner, const item * i, const faction * viewer, + const char **name, const char **basename, int *number, boolean singular) { assert(!owner || owner->number); if (owner && owner->faction == viewer) { - if (name) *name = locale_string(viewer->locale, resourcename(i->type->rtype, ((i->number!=1 && !singular)?GR_PLURAL:0))); - if (basename) *basename = resourcename(i->type->rtype, 0); - if (number) *number = i->number; - } else if (owner && i->type->rtype==r_silver) { - int pp = i->number/owner->number; - if (number) *number = 1; + if (name) + *name = + locale_string(viewer->locale, resourcename(i->type->rtype, + ((i->number != 1 && !singular) ? GR_PLURAL : 0))); + if (basename) + *basename = resourcename(i->type->rtype, 0); + if (number) + *number = i->number; + } else if (owner && i->type->rtype == r_silver) { + int pp = i->number / owner->number; + + if (number) + *number = 1; if (pp > 50000 && dragonrace(owner->race)) { - if (name) *name = locale_string(viewer->locale, "dragonhoard"); - if (basename) *basename = "dragonhoard"; + if (name) + *name = locale_string(viewer->locale, "dragonhoard"); + if (basename) + *basename = "dragonhoard"; } else if (pp > 5000) { - if (name) *name = locale_string(viewer->locale, "moneychest"); - if (basename) *basename = "moneychest"; + if (name) + *name = locale_string(viewer->locale, "moneychest"); + if (basename) + *basename = "moneychest"; } else if (pp > 500) { - if (name) *name = locale_string(viewer->locale, "moneybag"); - if (basename) *basename = "moneybag"; + if (name) + *name = locale_string(viewer->locale, "moneybag"); + if (basename) + *basename = "moneybag"; } else { - if (number) *number = 0; - if (name) *name = NULL; - if (basename) *basename = NULL; + if (number) + *number = 0; + if (name) + *name = NULL; + if (basename) + *basename = NULL; } } else { - if (name) *name = locale_string(viewer->locale, resourcename(i->type->rtype, NMF_APPEARANCE|((i->number!=1 && !singular)?GR_PLURAL:0))); - if (basename) *basename = resourcename(i->type->rtype, NMF_APPEARANCE); + if (name) + *name = + locale_string(viewer->locale, resourcename(i->type->rtype, + NMF_APPEARANCE | ((i->number != 1 && !singular) ? GR_PLURAL : 0))); + if (basename) + *basename = resourcename(i->type->rtype, NMF_APPEARANCE); if (number) { - if (fval(i->type, ITF_HERB)) *number = 1; - else *number = i->number; + if (fval(i->type, ITF_HERB)) + *number = 1; + else + *number = i->number; } } } -int * nmrs = NULL; +int *nmrs = NULL; -int -update_nmrs(void) +int update_nmrs(void) { - int i, newplayers =0; + int i, newplayers = 0; + faction *f; + int turn = global.data_turn; - if (nmrs==NULL) nmrs = malloc(sizeof(int)*(NMRTimeout()+1)); + if (nmrs == NULL) + nmrs = malloc(sizeof(int) * (NMRTimeout() + 1)); for (i = 0; i <= NMRTimeout(); ++i) { nmrs[i] = 0; } @@ -192,8 +224,9 @@ update_nmrs(void) if (fval(f, FFL_ISNEW)) { ++newplayers; } else if (!is_monsters(f) && f->alive) { - int nmr = turn-f->lastorders+1; - if (nmr<0 || nmr>NMRTimeout()) { + int nmr = turn - f->lastorders + 1; + + if (nmr < 0 || nmr > NMRTimeout()) { log_error(("faction %s has %d NMRS\n", factionid(f), nmr)); nmr = MAX(0, nmr); nmr = MIN(nmr, NMRTimeout()); @@ -205,27 +238,30 @@ update_nmrs(void) } #define ORDERS_IN_NR 1 -static size_t -buforder(char * bufp, size_t size, const order * ord, int mode) +static size_t buforder(char *bufp, size_t size, const order * ord, int mode) { size_t tsize = 0; + int bytes; bytes = (int)strlcpy(bufp, ", \"", size); tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (mode1) { - *bufp++ ='\"'; + if (size > 1) { + *bufp++ = '\"'; --size; } else { WARN_STATIC_BUFFER(); @@ -242,80 +278,91 @@ buforder(char * bufp, size_t size, const order * ord, int mode) * \param viewer: the faction looking at the items */ int -report_items(const item * items, item * result, int size, const unit * owner, const faction * viewer) +report_items(const item * items, item * result, int size, const unit * owner, + const faction * viewer) { - const item * itm; - int n = 0; /* number of results */ + const item *itm; - assert(owner==NULL || viewer!=owner->faction || !"not required for owner=viewer!"); + int n = 0; /* number of results */ + + assert(owner == NULL || viewer != owner->faction + || !"not required for owner=viewer!"); assert(size); - for (itm=items;itm;itm=itm->next) { - item * ishow; - const char * ic; + for (itm = items; itm; itm = itm->next) { + item *ishow; + + const char *ic; report_item(owner, itm, viewer, NULL, &ic, NULL, false); if (ic && *ic) { - for (ishow = result; ishow!=result+n; ++ishow) { - const char * sc; + for (ishow = result; ishow != result + n; ++ishow) { + const char *sc; - if (ishow->type==itm->type) sc = ic; - else report_item(owner, ishow, viewer, NULL, &sc, NULL, false); - if (sc==ic || strcmp(sc, ic)==0) { - ishow->number+=itm->number; + if (ishow->type == itm->type) + sc = ic; + else + report_item(owner, ishow, viewer, NULL, &sc, NULL, false); + if (sc == ic || strcmp(sc, ic) == 0) { + ishow->number += itm->number; break; } } - if (ishow==result+n) { - if (n==size) { + if (ishow == result + n) { + if (n == size) { log_error(("too many items to report, increase buffer size.\n")); return -1; } result[n].number = itm->number; result[n].type = itm->type; - result[n].next = (n+1==size)?NULL:result+n+1; + result[n].next = (n + 1 == size) ? NULL : result + n + 1; ++n; } } } - if (n>0) result[n-1].next = NULL; + if (n > 0) + result[n - 1].next = NULL; return n; } static void -report_resource(resource_report * result, const char * name, int number, int level) +report_resource(resource_report * result, const char *name, int number, + int level) { result->name = name; result->number = number; result->level = level; } -void -report_race(const struct unit * u, const char ** name, const char ** illusion) +void report_race(const struct unit *u, const char **name, const char **illusion) { if (illusion) { - const race * irace = u_irace(u); - if (irace && irace!=u->race) { + const race *irace = u_irace(u); + + if (irace && irace != u->race) { *illusion = irace->_name[0]; - } - else { + } else { *illusion = NULL; } } if (name) { *name = u->race->_name[0]; if (fval(u->race, RCF_SHAPESHIFTANY)) { - const char * str = get_racename(u->attribs); - if (str) *name = str; + const char *str = get_racename(u->attribs); + + if (str) + *name = str; } } } void -report_building(const struct building * b, const char ** name, const char ** illusion) +report_building(const struct building *b, const char **name, + const char **illusion) { static int init; - static const struct building_type * bt_illusion; + + static const struct building_type *bt_illusion; if (name) { *name = buildingtype(b->type, b, b->size); @@ -327,10 +374,12 @@ report_building(const struct building * b, const char ** name, const char ** ill bt_illusion = bt_find("illusioncastle"); init = 1; } - if (bt_illusion && b->type==bt_illusion) { - const attrib * a = a_findc(b->attribs, &at_icastle); - if (a!=NULL) { - icastle_data * icastle = (icastle_data*)a->data.v; + if (bt_illusion && b->type == bt_illusion) { + const attrib *a = a_findc(b->attribs, &at_icastle); + + if (a != NULL) { + icastle_data *icastle = (icastle_data *) a->data.v; + *illusion = buildingtype(icastle->type, b, b->size); } } @@ -338,71 +387,93 @@ report_building(const struct building * b, const char ** name, const char ** ill } int -report_resources(const seen_region * sr, resource_report * result, int size, const faction * viewer) +report_resources(const seen_region * sr, resource_report * result, int size, + const faction * viewer) { - const region * r = sr->r; + const region *r = sr->r; + int n = 0; if (r->land) { int peasants = rpeasants(r); + int money = rmoney(r); + int horses = rhorses(r); + int trees = rtrees(r, 2); + int saplings = rtrees(r, 1); - boolean mallorn = fval(r, RF_MALLORN)!=0; + + boolean mallorn = fval(r, RF_MALLORN) != 0; if (money) { - if (n>=size) return -1; - report_resource(result+n, "rm_money", money, -1); + if (n >= size) + return -1; + report_resource(result + n, "rm_money", money, -1); ++n; } if (peasants) { - if (n>=size) return -1; - report_resource(result+n, "rm_peasant", peasants, -1); + if (n >= size) + return -1; + report_resource(result + n, "rm_peasant", peasants, -1); ++n; } if (horses) { - if (n>=size) return -1; - report_resource(result+n, "rm_horse", horses, -1); + if (n >= size) + return -1; + report_resource(result + n, "rm_horse", horses, -1); ++n; } if (saplings) { - if (n>=size) return -1; - report_resource(result+n, mallorn?"rm_mallornsapling":"rm_sapling", saplings, -1); + if (n >= size) + return -1; + report_resource(result + n, mallorn ? "rm_mallornsapling" : "rm_sapling", + saplings, -1); ++n; } if (trees) { - if (n>=size) return -1; - report_resource(result+n, mallorn?"rm_mallorn":"rm_tree", trees, -1); + if (n >= size) + return -1; + report_resource(result + n, mallorn ? "rm_mallorn" : "rm_tree", trees, + -1); ++n; } } - if (sr->mode>=see_unit) { - rawmaterial * res = r->resources; + if (sr->mode >= see_unit) { + rawmaterial *res = r->resources; + while (res) { int maxskill = 0; - const item_type * itype = resource2item(res->type->rtype); + + const item_type *itype = resource2item(res->type->rtype); + int level = res->level + itype->construction->minskill - 1; + int visible = -1; - if (res->type->visible==NULL) { + + if (res->type->visible == NULL) { visible = res->amount; level = res->level + itype->construction->minskill - 1; } else { - const unit * u; - for (u=r->units; visible!=res->amount && u!=NULL; u=u->next) { + const unit *u; + + for (u = r->units; visible != res->amount && u != NULL; u = u->next) { if (u->faction == viewer) { int s = eff_skill(u, itype->construction->skill, r); - if (s>maxskill) { + + if (s > maxskill) { maxskill = s; visible = res->type->visible(res, maxskill); } } } } - if (level>=0 && visible>=0) { - if (n>=size) return -1; - report_resource(result+n, res->type->name, visible, level); + if (level >= 0 && visible >= 0) { + if (n >= size) + return -1; + report_resource(result + n, res->type->name, visible, level); n++; } res = res->next; @@ -412,118 +483,163 @@ report_resources(const seen_region * sr, resource_report * result, int size, con } int -bufunit(const faction * f, const unit * u, int indent, int mode, char * buf, size_t size) +bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, + size_t size) { int i, dh; + int getarnt = fval(u, UFL_ANON_FACTION); + const char *pzTmp, *str; - building * b; - boolean isbattle = (boolean)(mode == see_battle); + + building *b; + + boolean isbattle = (boolean) (mode == see_battle); + int telepath_see = 0; + attrib *a_fshidden = NULL; - item * itm; - item * show; + + item *itm; + + item *show; + faction *fv = visible_faction(f, u); - char * bufp = buf; + + char *bufp = buf; + boolean itemcloak = false; - static const curse_type * itemcloak_ct = 0; + + static const curse_type *itemcloak_ct = 0; + static boolean init = false; + int bytes; + item result[MAX_INVENTORY]; if (!init) { init = true; itemcloak_ct = ct_find("itemcloak"); } - if (itemcloak_ct!=NULL) { + if (itemcloak_ct != NULL) { itemcloak = curse_active(get_curse(u->attribs, itemcloak_ct)); } bytes = (int)strlcpy(bufp, unitname(u), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); if (!isbattle) { attrib *a_otherfaction = a_find(u->attribs, &at_otherfaction); + if (u->faction == f) { if (fval(u, UFL_GROUP)) { attrib *a = a_find(u->attribs, &at_group); + if (a) { - group * g = (group*)a->data.v; + group *g = (group *) a->data.v; + bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, groupid(g, f), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } if (getarnt) { bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, LOC(f->locale, "anonymous"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } else if (a_otherfaction) { - faction * otherfaction = get_otherfaction(a_otherfaction); + faction *otherfaction = get_otherfaction(a_otherfaction); + if (otherfaction) { bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, factionname(otherfaction), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } } else { if (getarnt) { bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, LOC(f->locale, "anonymous"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } else { if (a_otherfaction && alliedunit(u, f, HELP_FSTEALTH)) { - faction * f = get_otherfaction(a_otherfaction); - bytes = snprintf(bufp, size, ", %s (%s)", factionname(f), factionname(u->faction)); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + faction *f = get_otherfaction(a_otherfaction); + + bytes = + snprintf(bufp, size, ", %s (%s)", factionname(f), + factionname(u->faction)); + if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } else { bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, factionname(fv), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } } } bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); - if (u->faction != f && a_fshidden && a_fshidden->data.ca[0] == 1 && effskill(u, SK_STEALTH) >= 6) { + if (u->faction != f && a_fshidden && a_fshidden->data.ca[0] == 1 + && effskill(u, SK_STEALTH) >= 6) { bytes = (int)strlcpy(bufp, "? ", size); } else { bytes = snprintf(bufp, size, "%d ", u->number); } - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); pzTmp = get_racename(u->attribs); if (pzTmp) { bytes = (int)strlcpy(bufp, pzTmp, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (u->faction==f && fval(u->race, RCF_SHAPESHIFTANY)) { + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + if (u->faction == f && fval(u->race, RCF_SHAPESHIFTANY)) { bytes = (int)strlcpy(bufp, " (", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, racename(f->locale, u, u->race), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (size>1) { + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + if (size > 1) { strcpy(bufp++, ")"); --size; } } } else { - const race * irace = u_irace(u); + const race *irace = u_irace(u); + bytes = (int)strlcpy(bufp, racename(f->locale, u, irace), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (u->faction==f && irace!=u->race) { + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + if (u->faction == f && irace != u->race) { bytes = (int)strlcpy(bufp, " (", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, racename(f->locale, u, u->race), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (size>1) { + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + if (size > 1) { strcpy(bufp++, ")"); --size; } @@ -532,56 +648,72 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char * buf, siz if (fval(u, UFL_HERO) && (u->faction == f || omniscient(f))) { bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, LOC(f->locale, "hero"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } /* status */ if (u->number && (u->faction == f || telepath_see || isbattle)) { - const char * c = locale_string(f->locale, hp_status(u)); + const char *c = locale_string(f->locale, hp_status(u)); + bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, report_kampfstatus(u, f->locale), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); if (c || fval(u, UFL_HUNGER)) { bytes = (int)strlcpy(bufp, " (", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); if (c) { bytes = (int)strlcpy(bufp, c, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } if (fval(u, UFL_HUNGER)) { - if (c) bytes = (int)strlcpy(bufp, ", hungert", size); - else bytes = (int)strlcpy(bufp, "hungert", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (c) + bytes = (int)strlcpy(bufp, ", hungert", size); + else + bytes = (int)strlcpy(bufp, "hungert", size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } - if (size>1) { + if (size > 1) { strcpy(bufp++, ")"); --size; } } } - if (is_guard(u, GUARD_ALL)!=0) { + if (is_guard(u, GUARD_ALL) != 0) { bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, LOC(f->locale, "unit_guards"), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } - if ((b = usiege(u))!=NULL) { + if ((b = usiege(u)) != NULL) { bytes = (int)strlcpy(bufp, ", belagert ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, buildingname(b), size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } dh = 0; if (u->faction == f || telepath_see) { - skill * sv; - for (sv = u->skills;sv!=u->skills+u->skill_size;++sv) { + skill *sv; + + for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { bytes = (int)spskill(bufp, size, f->locale, u, sv, &dh, 1); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } @@ -589,26 +721,33 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char * buf, siz if (f == u->faction || telepath_see || omniscient(f)) { show = u->items; } else if (!itemcloak && mode >= see_unit && !(a_fshidden - && a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) - { + && a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) { int n = report_items(u->items, result, MAX_INVENTORY, u, f); - assert(n>=0); - if (n>0) show = result; - else show = NULL; + + assert(n >= 0); + if (n > 0) + show = result; + else + show = NULL; } else { show = NULL; } - for (itm=show; itm; itm=itm->next) { - const char * ic; + for (itm = show; itm; itm = itm->next) { + const char *ic; + int in, bytes; + report_item(u, itm, f, &ic, NULL, &in, false); - if (in==0 || ic==NULL) continue; + if (in == 0 || ic == NULL) + continue; bytes = (int)strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); if (!dh) { bytes = snprintf(bufp, size, "%s: ", LOC(f->locale, "nr_inventory")); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); dh = 1; } if (in == 1) { @@ -616,88 +755,112 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char * buf, siz } else { bytes = snprintf(bufp, size, "%d %s", in, ic); } - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } if (u->faction == f || telepath_see) { - sc_mage * m = get_mage(u); + sc_mage *m = get_mage(u); + + if (m != NULL) { + quicklist *ql = m->spells; - if (m!=NULL) { - quicklist * ql = m->spells; int qi, t = effskill(u, SK_MAGIC); - int bytes = snprintf(bufp, size, ". Aura %d/%d", get_spellpoints(u), max_spellpoints(u->region,u)); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - for (dh=0,qi=0; ql; ql_advance(&ql, &qi, 1)) { - spell * sp = (spell *)ql_get(ql, qi); - if (sp->level > t) continue; + int bytes = + snprintf(bufp, size, ". Aura %d/%d", get_spellpoints(u), + max_spellpoints(u->region, u)); + if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + + for (dh = 0, qi = 0; ql; ql_advance(&ql, &qi, 1)) { + spell *sp = (spell *) ql_get(ql, qi); + + if (sp->level > t) + continue; if (!dh) { bytes = snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_spells")); dh = 1; } else { bytes = (int)strlcpy(bufp, ", ", size); } - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, spell_name(sp, f->locale), size); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } - for (i=0; i!=MAXCOMBATSPELLS; ++i) { - if (get_combatspell(u, i)) break; + for (i = 0; i != MAXCOMBATSPELLS; ++i) { + if (get_combatspell(u, i)) + break; } - if (i!=MAXCOMBATSPELLS) { - bytes = snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_combatspells")); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (i != MAXCOMBATSPELLS) { + bytes = + snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_combatspells")); + if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); dh = 0; - for (i = 0; i < MAXCOMBATSPELLS; i++){ + for (i = 0; i < MAXCOMBATSPELLS; i++) { const spell *sp; - if (!dh){ + + if (!dh) { dh = 1; } else { bytes = (int)strlcpy(bufp, ", ", size); - if (bytes && wrptr(&bufp, &size, bytes)!=0) { + if (bytes && wrptr(&bufp, &size, bytes) != 0) { WARN_STATIC_BUFFER(); } } - sp = get_combatspell(u,i); + sp = get_combatspell(u, i); if (sp) { int sl = get_combatspelllevel(u, i); - bytes = (int)strlcpy(bufp, spell_name(sp, u->faction->locale), size); - if (bytes && wrptr(&bufp, &size, bytes)!=0) { + + bytes = + (int)strlcpy(bufp, spell_name(sp, u->faction->locale), size); + if (bytes && wrptr(&bufp, &size, bytes) != 0) { WARN_STATIC_BUFFER(); } if (sl > 0) { bytes = snprintf(bufp, size, " (%d)", sl); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } else { bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_nospells"), size); - if (bytes && wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (bytes && wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } } } if (!isbattle) { boolean printed = 0; - order * ord;; - for (ord=u->old_orders;ord;ord=ord->next) { + + order *ord;; + for (ord = u->old_orders; ord; ord = ord->next) { if (is_repeated(ord)) { - if (printedorders;ord;ord=ord->next) { - if (is_repeated(ord)) { - if (printedorders; ord; ord = ord->next) { + if (is_repeated(ord)) { + if (printed < ORDERS_IN_NR) { + bytes = (int)buforder(bufp, size, ord, printed++); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + } else + break; + } } - } } } i = 0; @@ -705,15 +868,17 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char * buf, siz str = u_description(u, f->locale); if (str) { bytes = (int)strlcpy(bufp, "; ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, str, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); i = str[strlen(str) - 1]; } if (i != '!' && i != '?' && i != '.') { - if (size>1) { + if (size > 1) { strcpy(bufp++, "."); --size; } @@ -721,21 +886,25 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char * buf, siz pzTmp = uprivate(u); if (u->faction == f && pzTmp) { bytes = (int)strlcpy(bufp, " (Bem: ", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, pzTmp, size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, ")", size); - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } - dh=0; + dh = 0; if (!getarnt && f) { if (alliedfaction(rplane(u->region), f, fv, HELP_ALL)) { dh = 1; } } - if (size<=1) { - log_warning(("bufunit ran out of space after writing %u bytes.\n", (bufp-buf))); + if (size <= 1) { + log_warning(("bufunit ran out of space after writing %u bytes.\n", + (bufp - buf))); } return dh; } @@ -746,158 +915,184 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char * buf, siz */ size_t -spskill(char * buffer, size_t size, const struct locale * lang, const struct unit * u, struct skill * sv, int *dh, int days) +spskill(char *buffer, size_t size, const struct locale * lang, + const struct unit * u, struct skill * sv, int *dh, int days) { - char * bufp = buffer; + char *bufp = buffer; + int i, effsk; + int bytes; + size_t tsize = 0; - if (!u->number) return 0; - if (sv->level<=0) { - if (sv->old<=0 || (u->faction->options & want(O_SHOWSKCHANGE))==0) { + if (!u->number) + return 0; + if (sv->level <= 0) { + if (sv->old <= 0 || (u->faction->options & want(O_SHOWSKCHANGE)) == 0) { return 0; } } bytes = (int)strlcpy(bufp, ", ", size); tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); if (!*dh) { bytes = (int)strlcpy(bufp, LOC(lang, "nr_skills"), size); tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, ": ", size); tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); *dh = 1; } bytes = (int)strlcpy(bufp, skillname(sv->id, lang), size); tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, " ", size); tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - - if (sv->id == SK_MAGIC){ - sc_mage * mage = get_mage(u); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + + if (sv->id == SK_MAGIC) { + sc_mage *mage = get_mage(u); + if (mage && mage->magietyp != M_GRAY) { - bytes = (int)strlcpy(bufp, LOC(lang, mkname("school", magic_school[mage->magietyp])), size); + bytes = + (int)strlcpy(bufp, LOC(lang, mkname("school", + magic_school[mage->magietyp])), size); tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); bytes = (int)strlcpy(bufp, " ", size); tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } - + if (sv->id == SK_STEALTH && fval(u, UFL_STEALTH)) { i = u_geteffstealth(u); - if (i>=0) { + if (i >= 0) { bytes = slprintf(bufp, size, "%d/", i); tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } - + effsk = effskill(u, sv->id); bytes = slprintf(bufp, size, "%d", effsk); tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + if (u->faction->options & want(O_SHOWSKCHANGE)) { int oldeff = 0; + int diff; - + if (sv->old > 0) { oldeff = sv->old + get_modifier(u, sv->id, sv->old, u->region, false); } - + oldeff = MAX(0, oldeff); - diff = effsk - oldeff; - + diff = effsk - oldeff; + if (diff != 0) { - bytes = slprintf(bufp, size, " (%s%d)", (diff>0)?"+":"", diff); + bytes = slprintf(bufp, size, " (%s%d)", (diff > 0) ? "+" : "", diff); tsize += bytes; - if (wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); } } return tsize; } -void -lparagraph(struct strlist ** SP, char *s, int indent, char mark) +void lparagraph(struct strlist **SP, char *s, int indent, char mark) { - /* Die Liste SP wird mit dem String s aufgefuellt, mit indent und einer - * mark, falls angegeben. SP wurde also auf 0 gesetzt vor dem Aufruf. - * Vgl. spunit (). */ + /* Die Liste SP wird mit dem String s aufgefuellt, mit indent und einer + * mark, falls angegeben. SP wurde also auf 0 gesetzt vor dem Aufruf. + * Vgl. spunit (). */ - char *buflocal = calloc(strlen(s) + indent + 1, sizeof(char)); + char *buflocal = calloc(strlen(s) + indent + 1, sizeof(char)); - if (indent) { - memset(buflocal, ' ', indent); - if (mark) - buflocal[indent - 2] = mark; - } - strcpy(buflocal + indent, s); - addstrlist(SP, buflocal); - free(buflocal); + if (indent) { + memset(buflocal, ' ', indent); + if (mark) + buflocal[indent - 2] = mark; + } + strcpy(buflocal + indent, s); + addstrlist(SP, buflocal); + free(buflocal); } void -spunit(struct strlist ** SP, const struct faction * f, const unit * u, int indent, - int mode) +spunit(struct strlist **SP, const struct faction *f, const unit * u, int indent, + int mode) { char buf[DISPLAYSIZE]; + int dh = bufunit(f, u, indent, mode, buf, sizeof(buf)); - lparagraph(SP, buf, indent, (char) ((u->faction == f) ? '*' : (dh ? '+' : '-'))); + + lparagraph(SP, buf, indent, + (char)((u->faction == f) ? '*' : (dh ? '+' : '-'))); } -struct message * -msg_curse(const struct curse * c, const void * obj, typ_t typ, int self) +struct message *msg_curse(const struct curse *c, const void *obj, typ_t typ, + int self) { if (c->type->curseinfo) { /* if curseinfo returns NULL, then we don't want to tell the viewer anything. */ return c->type->curseinfo(obj, typ, c, self); } else { - message * msg = cinfo_simple(obj, typ, c, self); - if (msg==NULL) { - const char * unknown[] = { "unit_unknown", "region_unknown", "building_unknown", "ship_unknown" }; + message *msg = cinfo_simple(obj, typ, c, self); + + if (msg == NULL) { + const char *unknown[] = + { "unit_unknown", "region_unknown", "building_unknown", + "ship_unknown" }; msg = msg_message(mkname("curseinfo", unknown[typ]), "id", c->no); - log_error(("no curseinfo function for %s and no fallback either.\n", c->type->cname)); + log_error(("no curseinfo function for %s and no fallback either.\n", + c->type->cname)); } else { - log_error(("no curseinfo function for %s, using cinfo_simple fallback.\n", c->type->cname)); + log_error(("no curseinfo function for %s, using cinfo_simple fallback.\n", + c->type->cname)); } return msg; } } -const struct unit * -ucansee(const struct faction *f, const struct unit *u, const struct unit *x) +const struct unit *ucansee(const struct faction *f, const struct unit *u, + const struct unit *x) { - if (cansee(f, u->region, u, 0)) return u; + if (cansee(f, u->region, u, 0)) + return u; return x; } -int -stealth_modifier(int seen_mode) +int stealth_modifier(int seen_mode) { switch (seen_mode) { - case see_unit: - return 0; - case see_far: - case see_lighthouse: - return -2; - case see_travel: - return -1; - default: - return INT_MIN; + case see_unit: + return 0; + case see_far: + case see_lighthouse: + return -2; + case see_travel: + return -1; + default: + return INT_MIN; } } @@ -908,57 +1103,69 @@ void transfer_seen(quicklist ** dst, quicklist ** src) *src = NULL; } -static void -get_addresses(report_context * ctx) +static void get_addresses(report_context * ctx) { /* "TODO: travelthru" */ - seen_region * sr = NULL; + seen_region *sr = NULL; + region *r; - const faction * lastf = NULL; - quicklist * flist = 0; - + + const faction *lastf = NULL; + + quicklist *flist = 0; + transfer_seen(&flist, &ctx->f->seen_factions); ctx->f->seen_factions = NULL; /* do not delete it twice */ ql_push(&flist, ctx->f); if (f_get_alliance(ctx->f)) { - quicklist * ql = ctx->f->alliance->members; + quicklist *ql = ctx->f->alliance->members; + int qi; - for (qi=0;ql;ql_advance(&ql, &qi, 1)) { + + for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { ql_set_insert(&flist, ql_get(ql, qi)); } } /* find the first region that this faction can see */ - for (r=ctx->first;sr==NULL && r!=ctx->last;r=r->next) { + for (r = ctx->first; sr == NULL && r != ctx->last; r = r->next) { sr = find_seen(ctx->seen, r); } - - for (;sr!=NULL;sr=sr->next) { + + for (; sr != NULL; sr = sr->next) { int stealthmod = stealth_modifier(sr->mode); + r = sr->r; - if (sr->mode==see_lighthouse) { - unit * u = r->units; - for (;u;u=u->next) { - faction * sf = visible_faction(ctx->f, u); - if (lastf!=sf) { - if (u->building || u->ship || (stealthmod>INT_MIN && cansee(ctx->f, r, u, stealthmod))) { + if (sr->mode == see_lighthouse) { + unit *u = r->units; + + for (; u; u = u->next) { + faction *sf = visible_faction(ctx->f, u); + + if (lastf != sf) { + if (u->building || u->ship || (stealthmod > INT_MIN + && cansee(ctx->f, r, u, stealthmod))) { ql_set_insert(&flist, sf); lastf = sf; } } } - } else if (sr->mode==see_travel) { - unit * u = r->units; + } else if (sr->mode == see_travel) { + unit *u = r->units; + while (u) { - faction * sf = visible_faction(ctx->f, u); - assert(u->faction!=ctx->f); /* if this is see_travel only, then I shouldn't be here. */ - if (lastf!=sf) { - attrib * a = a_find(r->attribs, &at_travelunit); - while (a && a->type==&at_travelunit) { - unit * u2 = (unit*)a->data.v; - if (u2->faction==ctx->f) { + faction *sf = visible_faction(ctx->f, u); + + assert(u->faction != ctx->f); /* if this is see_travel only, then I shouldn't be here. */ + if (lastf != sf) { + attrib *a = a_find(r->attribs, &at_travelunit); + + while (a && a->type == &at_travelunit) { + unit *u2 = (unit *) a->data.v; + + if (u2->faction == ctx->f) { if (cansee_unit(u2, u, stealthmod)) { ql_set_insert(&flist, sf); lastf = sf; @@ -970,12 +1177,14 @@ get_addresses(report_context * ctx) } u = u->next; } - } else if (sr->mode>see_travel) { - const unit * u = r->units; - while (u!=NULL) { - if (u->faction!=ctx->f) { - faction * sf = visible_faction(ctx->f, u); - boolean ballied = sf && sf!=ctx->f && sf!=lastf + } else if (sr->mode > see_travel) { + const unit *u = r->units; + + while (u != NULL) { + if (u->faction != ctx->f) { + faction *sf = visible_faction(ctx->f, u); + + boolean ballied = sf && sf != ctx->f && sf != lastf && !fval(u, UFL_ANON_FACTION) && cansee(ctx->f, r, u, stealthmod); if (ballied || ALLIED(ctx->f, sf)) { ql_set_insert(&flist, sf); @@ -983,12 +1192,13 @@ get_addresses(report_context * ctx) } } u = u->next; - } + } } } - + if (f_get_alliance(ctx->f)) { faction *f2; + for (f2 = factions; f2; f2 = f2->next) { if (f2->alliance == ctx->f->alliance) { ql_set_insert(&flist, f2); @@ -999,22 +1209,24 @@ get_addresses(report_context * ctx) } #define MAXSEEHASH 0x1000 -seen_region * reuse; +seen_region *reuse; -seen_region ** -seen_init(void) +seen_region **seen_init(void) { - return (seen_region **)calloc(MAXSEEHASH, sizeof(seen_region*)); + return (seen_region **) calloc(MAXSEEHASH, sizeof(seen_region *)); } -void -seen_done(seen_region * seehash[]) +void seen_done(seen_region * seehash[]) { int i; - for (i=0;i!=MAXSEEHASH;++i) { - seen_region * sd = seehash[i]; - if (sd==NULL) continue; - while (sd->nextHash!=NULL) sd = sd->nextHash; + + for (i = 0; i != MAXSEEHASH; ++i) { + seen_region *sd = seehash[i]; + + if (sd == NULL) + continue; + while (sd->nextHash != NULL) + sd = sd->nextHash; sd->nextHash = reuse; reuse = seehash[i]; seehash[i] = NULL; @@ -1022,11 +1234,11 @@ seen_done(seen_region * seehash[]) // free(seehash); } -void -free_seen(void) +void free_seen(void) { while (reuse) { - seen_region * r = reuse; + seen_region *r = reuse; + reuse = reuse->nextHash; free(r); } @@ -1035,19 +1247,22 @@ free_seen(void) void link_seen(seen_region * seehash[], const region * first, const region * last) { - const region * r = first; - seen_region * sr = NULL; + const region *r = first; - if (first==last) return; + seen_region *sr = NULL; + + if (first == last) + return; do { sr = find_seen(seehash, r); r = r->next; - } while (sr==NULL && r!=last); + } while (sr == NULL && r != last); - while (r!=last) { - seen_region * sn = find_seen(seehash, r); - if (sn!=NULL) { + while (r != last) { + seen_region *sn = find_seen(seehash, r); + + if (sn != NULL) { sr->next = sn; sr = sn; } @@ -1056,31 +1271,34 @@ link_seen(seen_region * seehash[], const region * first, const region * last) sr->next = 0; } -seen_region * -find_seen(struct seen_region * seehash[], const region * r) +seen_region *find_seen(struct seen_region *seehash[], const region * r) { - unsigned int index = reg_hashkey(r) & (MAXSEEHASH-1); - seen_region * find = seehash[index]; + unsigned int index = reg_hashkey(r) & (MAXSEEHASH - 1); + + seen_region *find = seehash[index]; + while (find) { - if (find->r==r) return find; - find=find->nextHash; + if (find->r == r) + return find; + find = find->nextHash; } return NULL; } -static void -get_seen_interval(report_context * ctx) +static void get_seen_interval(report_context * ctx) { /* this is required to find the neighbour regions of the ones we are in, * which may well be outside of [firstregion, lastregion) */ int i; - for (i=0;i!=MAXSEEHASH;++i) { - seen_region * sr = ctx->seen[i]; - while (sr!=NULL) { - if (ctx->first==NULL || sr->r->indexfirst->index) { + + for (i = 0; i != MAXSEEHASH; ++i) { + seen_region *sr = ctx->seen[i]; + + while (sr != NULL) { + if (ctx->first == NULL || sr->r->index < ctx->first->index) { ctx->first = sr->r; } - if (ctx->last!=NULL && sr->r->index>=ctx->last->index) { + if (ctx->last != NULL && sr->r->index >= ctx->last->index) { ctx->last = sr->r->next; } sr = sr->nextHash; @@ -1090,12 +1308,16 @@ get_seen_interval(report_context * ctx) } boolean -add_seen(struct seen_region * seehash[], struct region * r, unsigned char mode, boolean dis) +add_seen(struct seen_region *seehash[], struct region *r, unsigned char mode, + boolean dis) { - seen_region * find = find_seen(seehash, r); - if (find==NULL) { - unsigned int index = reg_hashkey(r) & (MAXSEEHASH-1); - if (!reuse) reuse = (seen_region*)calloc(1, sizeof(struct seen_region)); + seen_region *find = find_seen(seehash, r); + + if (find == NULL) { + unsigned int index = reg_hashkey(r) & (MAXSEEHASH - 1); + + if (!reuse) + reuse = (seen_region *) calloc(1, sizeof(struct seen_region)); find = reuse; reuse = reuse->nextHash; find->nextHash = seehash[index]; @@ -1110,18 +1332,18 @@ add_seen(struct seen_region * seehash[], struct region * r, unsigned char mode, } typedef struct report_type { - struct report_type * next; + struct report_type *next; report_fun write; - const char * extension; + const char *extension; int flag; } report_type; -static report_type * report_types; +static report_type *report_types; -void -register_reporttype(const char * extension, report_fun write, int flag) +void register_reporttype(const char *extension, report_fun write, int flag) { - report_type * type = malloc(sizeof(report_type)); + report_type *type = malloc(sizeof(report_type)); + type->extension = extension; type->write = write; type->flag = flag; @@ -1129,73 +1351,89 @@ register_reporttype(const char * extension, report_fun write, int flag) report_types = type; } -static region_list * -get_regions_distance(region * root, int radius) +static region_list *get_regions_distance(region * root, int radius) { - region_list * rptr, * rlist = NULL; - region_list ** rp = &rlist; + region_list *rptr, *rlist = NULL; + + region_list **rp = &rlist; + add_regionlist(rp, root); fset(root, RF_MARK); while (*rp) { - region_list * r = *rp; + region_list *r = *rp; + direction_t d; + rp = &r->next; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(r->data, d); - if (rn!=NULL && !fval(rn, RF_MARK) && distance(rn, root)<=radius) { + for (d = 0; d != MAXDIRECTIONS; ++d) { + region *rn = rconnect(r->data, d); + + if (rn != NULL && !fval(rn, RF_MARK) && distance(rn, root) <= radius) { add_regionlist(rp, rn); fset(rn, RF_MARK); } } } - for (rptr=rlist;rptr;rptr=rptr->next) { + for (rptr = rlist; rptr; rptr = rptr->next) { freset(rptr->data, RF_MARK); } return rlist; } -static void -view_default(struct seen_region ** seen, region *r, faction *f) +static void view_default(struct seen_region **seen, region * r, faction * f) { direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * r2 = rconnect(r, dir); + + for (dir = 0; dir != MAXDIRECTIONS; ++dir) { + region *r2 = rconnect(r, dir); + if (r2) { - connection * b = get_borders(r, r2); + connection *b = get_borders(r, r2); + while (b) { - if (!b->type->transparent(b, f)) break; + if (!b->type->transparent(b, f)) + break; b = b->next; } - if (!b) add_seen(seen, r2, see_neighbour, false); + if (!b) + add_seen(seen, r2, see_neighbour, false); } } } -static void -view_neighbours(struct seen_region ** seen, region * r, faction * f) +static void view_neighbours(struct seen_region **seen, region * r, faction * f) { direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * r2 = rconnect(r, dir); + + for (dir = 0; dir != MAXDIRECTIONS; ++dir) { + region *r2 = rconnect(r, dir); + if (r2) { - connection * b = get_borders(r, r2); + connection *b = get_borders(r, r2); + while (b) { - if (!b->type->transparent(b, f)) break; + if (!b->type->transparent(b, f)) + break; b = b->next; } if (!b) { if (add_seen(seen, r2, see_far, false)) { if (!(fval(r2->terrain, FORBIDDEN_REGION))) { direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * r3 = rconnect(r2, dir); + + for (dir = 0; dir != MAXDIRECTIONS; ++dir) { + region *r3 = rconnect(r2, dir); + if (r3) { - connection * b = get_borders(r2, r3); + connection *b = get_borders(r2, r3); + while (b) { - if (!b->type->transparent(b, f)) break; + if (!b->type->transparent(b, f)) + break; b = b->next; } - if (!b) add_seen(seen, r3, see_neighbour, false); + if (!b) + add_seen(seen, r3, see_neighbour, false); } } } @@ -1206,69 +1444,87 @@ view_neighbours(struct seen_region ** seen, region * r, faction * f) } static void -recurse_regatta(struct seen_region ** seen, region *center, region *r, faction *f, int maxdist) +recurse_regatta(struct seen_region **seen, region * center, region * r, + faction * f, int maxdist) { direction_t dir; + int dist = distance(center, r); - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * r2 = rconnect(r, dir); + + for (dir = 0; dir != MAXDIRECTIONS; ++dir) { + region *r2 = rconnect(r, dir); + if (r2) { int ndist = distance(center, r2); - if (ndist>dist && fval(r2->terrain, SEA_REGION)) { - connection * b = get_borders(r, r2); + + if (ndist > dist && fval(r2->terrain, SEA_REGION)) { + connection *b = get_borders(r, r2); + while (b) { - if (!b->type->transparent(b, f)) break; + if (!b->type->transparent(b, f)) + break; b = b->next; } if (!b) { - if (ndistunits; u; u=u->next) { - if (u->faction==f) { + + for (u = r->units; u; u = u->next) { + if (u->faction == f) { int es = effskill(u, SK_PERCEPTION); - if (es>skill) skill=es; + + if (es > skill) + skill = es; } } - recurse_regatta(seen, r, r, f, skill/2); + recurse_regatta(seen, r, r, f, skill / 2); } -static void -prepare_reports(void) +static void prepare_reports(void) { - region * r; - faction * f; - static const struct building_type * bt_lighthouse = NULL; - if (bt_lighthouse==NULL) bt_lighthouse = bt_find("lighthouse"); + region *r; - for (f = factions; f ; f = f->next) { - if (f->seen) seen_done(f->seen); + faction *f; + + static const struct building_type *bt_lighthouse = NULL; + + if (bt_lighthouse == NULL) + bt_lighthouse = bt_find("lighthouse"); + + for (f = factions; f; f = f->next) { + if (f->seen) + seen_done(f->seen); f->seen = seen_init(); } - for (r = regions; r ; r = r->next) { + for (r = regions; r; r = r->next) { attrib *ru; - unit * u; - plane * p = rplane(r); + + unit *u; + + plane *p = rplane(r); reorder_units(r); if (p) { - watcher * w = p->watchers; - for (;w;w=w->next) { + watcher *w = p->watchers; + + for (; w; w = w->next) { add_seen(w->faction->seen, r, w->mode, false); #ifdef SMART_INTERVALS update_interval(w->faction, r); @@ -1277,20 +1533,25 @@ prepare_reports(void) } for (u = r->units; u; u = u->next) { - if (u->building && u->building->type==bt_lighthouse) { + if (u->building && u->building->type == bt_lighthouse) { /* we are in a lighthouse. add the regions we can see from here! */ int range = lighthouse_range(u->building, u->faction); - region_list * rlist = get_regions_distance(r, range); - region_list * rp = rlist; + + region_list *rlist = get_regions_distance(r, range); + + region_list *rp = rlist; while (rp) { - region * rl = rp->data; + region *rl = rp->data; + if (fval(rl->terrain, SEA_REGION)) { direction_t d; + add_seen(u->faction->seen, rl, see_lighthouse, false); - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(rl, d); - if (rn!=NULL) { + for (d = 0; d != MAXDIRECTIONS; ++d) { + region *rn = rconnect(rl, d); + + if (rn != NULL) { add_seen(u->faction->seen, rn, see_neighbour, false); } } @@ -1310,8 +1571,9 @@ prepare_reports(void) } if (fval(r, RF_TRAVELUNIT)) { - for (ru = a_find(r->attribs, &at_travelunit); ru && ru->type==&at_travelunit; ru = ru->next) { - unit * u = (unit*)ru->data.v; + for (ru = a_find(r->attribs, &at_travelunit); + ru && ru->type == &at_travelunit; ru = ru->next) { + unit *u = (unit *) ru->data.v; /* make sure the faction has not been removed this turn: */ if (u->faction) { @@ -1322,28 +1584,34 @@ prepare_reports(void) } } -static seen_region ** -prepare_report(faction * f) +static seen_region **prepare_report(faction * f) { - struct seen_region * sr; - region * r = firstregion(f); - region * last = lastregion(f); + struct seen_region *sr; + + region *r = firstregion(f); + + region *last = lastregion(f); link_seen(f->seen, r, last); - for (sr=NULL; sr==NULL && r!=last; r=r->next) { + for (sr = NULL; sr == NULL && r != last; r = r->next) { sr = find_seen(f->seen, r); } - for (;sr!=NULL;sr=sr->next) { - if (sr->mode>see_neighbour) { - region * r = sr->r; - plane * p = rplane(r); + for (; sr != NULL; sr = sr->next) { + if (sr->mode > see_neighbour) { + region *r = sr->r; + + plane *p = rplane(r); + + void (*view) (struct seen_region **, region *, faction *) = view_default; - void (*view)(struct seen_region **, region *, faction *) = view_default; if (p && fval(p, PFL_SEESPECIAL)) { - attrib * a = a_find(p->attribs, &at_viewrange); - if (a) view = (void (*)(struct seen_region **, region *, faction *))a->data.f; + attrib *a = a_find(p->attribs, &at_viewrange); + + if (a) + view = + (void (*)(struct seen_region **, region *, faction *))a->data.f; } view(f->seen, r, f); } @@ -1351,13 +1619,15 @@ prepare_report(faction * f) return f->seen; } -int -write_reports(faction * f, time_t ltime) +int write_reports(faction * f, time_t ltime) { int backup = 1, maxbackup = 128; + boolean gotit = false; + struct report_context ctx; - const char * encoding = "UTF-8"; + + const char *encoding = "UTF-8"; if (noreports) { return false; @@ -1373,17 +1643,19 @@ write_reports(faction * f, time_t ltime) get_addresses(&ctx); do { - report_type * rtype = report_types; + report_type *rtype = report_types; errno = 0; - if (verbosity>=2) { + if (verbosity >= 2) { log_stdio(stdout, "Reports for %s:", factionname(f)); } - for (;rtype!=NULL;rtype=rtype->next) { + for (; rtype != NULL; rtype = rtype->next) { if (f->options & rtype->flag) { char filename[MAX_PATH]; - sprintf(filename, "%s/%d-%s.%s", reportpath(), turn, factionid(f), rtype->extension); - if (rtype->write(filename, &ctx, encoding)==0) { + + sprintf(filename, "%s/%d-%s.%s", reportpath(), turn, factionid(f), + rtype->extension); + if (rtype->write(filename, &ctx, encoding) == 0) { gotit = true; } } @@ -1391,15 +1663,15 @@ write_reports(faction * f, time_t ltime) if (errno) { char zText[64]; + puts(" ERROR"); sprintf(zText, "Waiting %u seconds before retry", backup); perror(zText); sleep(backup); - if (backup=2) { + } else if (verbosity >= 2) { puts(" DONE"); } } while (errno); @@ -1411,45 +1683,53 @@ write_reports(faction * f, time_t ltime) return 0; } -static void -nmr_warnings(void) +static void nmr_warnings(void) { - faction *f,*fa; + faction *f, *fa; + #define FRIEND (HELP_GUARD|HELP_MONEY) - for (f=factions;f;f=f->next) { - if (!is_monsters(f) && (turn-f->lastorders) >= 2) { - message * msg = NULL; - for (fa=factions;fa;fa=fa->next) { + for (f = factions; f; f = f->next) { + if (!is_monsters(f) && (turn - f->lastorders) >= 2) { + message *msg = NULL; + + for (fa = factions; fa; fa = fa->next) { int warn = 0; - if (get_param_int(global.parameters, "rules.alliances", 0)!=0) { - if (f->alliance && f->alliance==fa->alliance) { + + if (get_param_int(global.parameters, "rules.alliances", 0) != 0) { + if (f->alliance && f->alliance == fa->alliance) { warn = 1; } - } else if (alliedfaction(NULL, f, fa, FRIEND) && alliedfaction(NULL, fa, f, FRIEND)) { + } else if (alliedfaction(NULL, f, fa, FRIEND) + && alliedfaction(NULL, fa, f, FRIEND)) { warn = 1; } if (warn) { - if (msg==NULL) { - msg = msg_message("warn_dropout", "faction turns", f, turn - f->lastorders); + if (msg == NULL) { + msg = + msg_message("warn_dropout", "faction turns", f, + turn - f->lastorders); } add_message(&fa->msgs, msg); } } - if (msg!=NULL) msg_release(msg); + if (msg != NULL) + msg_release(msg); } } } -static void -report_donations(void) +static void report_donations(void) { - region * r; - for (r=regions;r;r=r->next) { + region *r; + + for (r = regions; r; r = r->next) { while (r->donations) { - donation * sp = r->donations; + donation *sp = r->donations; + if (sp->amount > 0) { - struct message * msg = msg_message("donation", + struct message *msg = msg_message("donation", "from to amount", sp->f1, sp->f2, sp->amount); + r_addmessage(r, sp->f1, msg); r_addmessage(r, sp->f2, msg); msg_release(msg); @@ -1460,21 +1740,25 @@ report_donations(void) } } -static void -write_script(FILE * F, const faction * f) +static void write_script(FILE * F, const faction * f) { - report_type * rtype; + report_type *rtype; + char buf[1024]; - fprintf(F, "faction=%s:email=%s:lang=%s", factionid(f), f->email, locale_name(f->locale)); - if (f->options & (1<email, + locale_name(f->locale)); + if (f->options & (1 << O_BZIP2)) + fputs(":compression=bz2", F); + else + fputs(":compression=zip", F); fputs(":reports=", F); buf[0] = 0; - for (rtype=report_types;rtype!=NULL;rtype=rtype->next) { - if (f->options&rtype->flag) { - if (buf[0]) strcat(buf, ","); + for (rtype = report_types; rtype != NULL; rtype = rtype->next) { + if (f->options & rtype->flag) { + if (buf[0]) + strcat(buf, ","); strcat(buf, rtype->extension); } } @@ -1482,18 +1766,19 @@ write_script(FILE * F, const faction * f) fputc('\n', F); } -int -init_reports(void) +int init_reports(void) { prepare_reports(); #ifdef HAVE_STAT { stat_type st; - if (stat(reportpath(), &st)==0) return 0; + + if (stat(reportpath(), &st) == 0) + return 0; } #endif - if (os_mkdir(reportpath(), 0700)!=0) { - if (errno!=EEXIST) { + if (os_mkdir(reportpath(), 0700) != 0) { + if (errno != EEXIST) { perror("could not create reportpath"); return -1; } @@ -1501,17 +1786,21 @@ init_reports(void) return 0; } -int -reports(void) +int reports(void) { faction *f; + FILE *mailit; + time_t ltime = time(NULL); - const char * str; + + const char *str; + int retval = 0; + char path[MAX_PATH]; - if (verbosity>=1) { + if (verbosity >= 1) { log_stdio(stdout, "Writing reports for turn %d:", turn); } nmr_warnings(); @@ -1526,14 +1815,19 @@ reports(void) for (f = factions; f; f = f->next) { int error = write_reports(f, ltime); - if (error) retval = error; - if (mailit) write_script(mailit, f); + + if (error) + retval = error; + if (mailit) + write_script(mailit, f); } - if (mailit) fclose(mailit); + if (mailit) + fclose(mailit); free_seen(); - str = get_param(global.parameters, "globalreport"); + str = get_param(global.parameters, "globalreport"); + #ifdef GLOBAL_REPORT - if (str!=NULL) { + if (str != NULL) { sprintf(path, "%s/%s.%u.cr", reportpath(), str, turn); global_report(path); } @@ -1541,40 +1835,37 @@ reports(void) return retval; } -static variant -var_copy_string(variant x) +static variant var_copy_string(variant x) { - x.v = strdup((const char*)x.v); + x.v = strdup((const char *)x.v); return x; } -static void -var_free_string(variant x) +static void var_free_string(variant x) { free(x.v); } -static variant -var_copy_order(variant x) +static variant var_copy_order(variant x) { - x.v = copy_order((order*)x.v); + x.v = copy_order((order *) x.v); return x; } -static void -var_free_order(variant x) +static void var_free_order(variant x) { free_order(x.v); } -static variant -var_copy_items(variant x) +static variant var_copy_items(variant x) { - item * isrc; - resource * rdst = NULL, ** rptr = &rdst; + item *isrc; + + resource *rdst = NULL, **rptr = &rdst; + + for (isrc = (item *) x.v; isrc != NULL; isrc = isrc->next) { + resource *res = malloc(sizeof(resource)); - for (isrc = (item*)x.v; isrc!=NULL; isrc=isrc->next) { - resource * res = malloc(sizeof(resource)); res->number = isrc->number; res->type = isrc->type->rtype; *rptr = res; @@ -1585,526 +1876,647 @@ var_copy_items(variant x) return x; } -static void -var_free_resources(variant x) +static void var_free_resources(variant x) { - resource * rsrc = (resource*)x.v; + resource *rsrc = (resource *) x.v; + while (rsrc) { - resource * res = rsrc->next; + resource *res = rsrc->next; + free(rsrc); rsrc = res; } x.v = 0; } -static void -var_free_regions(variant x) +static void var_free_regions(variant x) { free(x.v); } -const char * -trailinto(const region * r, const struct locale * lang) +const char *trailinto(const region * r, const struct locale *lang) { char ref[32]; - const char * s; + + const char *s; + if (r) { - const char * tname = terrain_name(r); + const char *tname = terrain_name(r); + strcat(strcpy(ref, tname), "_trail"); s = locale_string(lang, ref); if (s && *s) { - if (strstr(s, "%s")) return s; + if (strstr(s, "%s")) + return s; } } return "%s"; } size_t -f_regionid(const region * r, const faction * f, char * buffer, size_t size) +f_regionid(const region * r, const faction * f, char *buffer, size_t size) { if (!r) { strncpy(buffer, "(Chaos)", size); } else { - plane * pl = rplane(r); - const char * name = pl?pl->name:0; + plane *pl = rplane(r); + + const char *name = pl ? pl->name : 0; + int nx = r->x, ny = r->y; + int named = (name && name[0]); + pnormalize(&nx, &ny, pl); adjust_coordinates(f, &nx, &ny, pl, r); strncpy(buffer, rname(r, f->locale), size); - buffer[size-1]=0; - sprintf(buffer+strlen(buffer), " (%d,%d%s%s)", nx, ny, named?",":"", (named)?name:""); + buffer[size - 1] = 0; + sprintf(buffer + strlen(buffer), " (%d,%d%s%s)", nx, ny, named ? "," : "", + (named) ? name : ""); } return strlen(buffer); } -static char * -f_regionid_s(const region * r, const faction * f) +static char *f_regionid_s(const region * r, const faction * f) { static int i = 0; + static char bufs[4][NAMESIZE + 20]; - char * buf = bufs[(++i)%4]; + + char *buf = bufs[(++i) % 4]; f_regionid(r, f, buf, NAMESIZE + 20); return buf; } /*** BEGIN MESSAGE RENDERING ***/ -static void -eval_localize(struct opstack ** stack, const void * userdata) /* (string, locale) -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct locale * lang = f?f->locale:default_locale; +static void eval_localize(struct opstack **stack, const void *userdata) +{ /* (string, locale) -> string */ + const struct faction *f = (const struct faction *)userdata; + + const struct locale *lang = f ? f->locale : default_locale; + const char *c = (const char *)opop_v(stack); + c = locale_string(lang, c); - opush_v(stack, strcpy(balloc(strlen(c)+1), c)); + opush_v(stack, strcpy(balloc(strlen(c) + 1), c)); } -static void -eval_trailto(struct opstack ** stack, const void * userdata) /* (int, int) -> int */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct locale * lang = f?f->locale:default_locale; - const struct region * r = (const struct region*)opop(stack).v; - const char * trail = trailinto(r, lang); - const char * rn = f_regionid_s(r, f); +static void eval_trailto(struct opstack **stack, const void *userdata) +{ /* (int, int) -> int */ + const struct faction *f = (const struct faction *)userdata; + + const struct locale *lang = f ? f->locale : default_locale; + + const struct region *r = (const struct region *)opop(stack).v; + + const char *trail = trailinto(r, lang); + + const char *rn = f_regionid_s(r, f); + variant var; - char * x = var.v = balloc(strlen(trail)+strlen(rn)); + + char *x = var.v = balloc(strlen(trail) + strlen(rn)); + sprintf(x, trail, rn); opush(stack, var); } -static void -eval_unit(struct opstack ** stack, const void * userdata) /* unit -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct unit * u = (const struct unit *)opop(stack).v; - const char * c = u?unitname(u):LOC(f->locale, "an_unknown_unit"); +static void eval_unit(struct opstack **stack, const void *userdata) +{ /* unit -> string */ + const struct faction *f = (const struct faction *)userdata; + + const struct unit *u = (const struct unit *)opop(stack).v; + + const char *c = u ? unitname(u) : LOC(f->locale, "an_unknown_unit"); + size_t len = strlen(c); + variant var; - var.v = strcpy(balloc(len+1), c); + var.v = strcpy(balloc(len + 1), c); opush(stack, var); } -static void -eval_unit_dative(struct opstack ** stack, const void * userdata) /* unit -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct unit * u = (const struct unit *)opop(stack).v; - const char * c = u?unitname(u):LOC(f->locale, "unknown_unit_dative"); +static void eval_unit_dative(struct opstack **stack, const void *userdata) +{ /* unit -> string */ + const struct faction *f = (const struct faction *)userdata; + + const struct unit *u = (const struct unit *)opop(stack).v; + + const char *c = u ? unitname(u) : LOC(f->locale, "unknown_unit_dative"); + size_t len = strlen(c); + variant var; - var.v = strcpy(balloc(len+1), c); + var.v = strcpy(balloc(len + 1), c); opush(stack, var); } -static void -eval_spell(struct opstack ** stack, const void * userdata) /* unit -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct spell * sp = (const struct spell *)opop(stack).v; - const char * c = sp?spell_name(sp, f->locale):LOC(f->locale, "an_unknown_spell"); +static void eval_spell(struct opstack **stack, const void *userdata) +{ /* unit -> string */ + const struct faction *f = (const struct faction *)userdata; + + const struct spell *sp = (const struct spell *)opop(stack).v; + + const char *c = + sp ? spell_name(sp, f->locale) : LOC(f->locale, "an_unknown_spell"); size_t len = strlen(c); + variant var; - var.v = strcpy(balloc(len+1), c); + var.v = strcpy(balloc(len + 1), c); opush(stack, var); } -static void -eval_curse(struct opstack ** stack, const void * userdata) /* unit -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct curse_type * sp = (const struct curse_type *)opop(stack).v; - const char * c = sp?curse_name(sp, f->locale):LOC(f->locale, "an_unknown_curse"); +static void eval_curse(struct opstack **stack, const void *userdata) +{ /* unit -> string */ + const struct faction *f = (const struct faction *)userdata; + + const struct curse_type *sp = (const struct curse_type *)opop(stack).v; + + const char *c = + sp ? curse_name(sp, f->locale) : LOC(f->locale, "an_unknown_curse"); size_t len = strlen(c); + variant var; - var.v = strcpy(balloc(len+1), c); + var.v = strcpy(balloc(len + 1), c); opush(stack, var); } -static void -eval_unitname(struct opstack ** stack, const void * userdata) /* unit -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct unit * u = (const struct unit *)opop(stack).v; - const char * c = u?u->name:LOC(f->locale, "an_unknown_unit"); +static void eval_unitname(struct opstack **stack, const void *userdata) +{ /* unit -> string */ + const struct faction *f = (const struct faction *)userdata; + + const struct unit *u = (const struct unit *)opop(stack).v; + + const char *c = u ? u->name : LOC(f->locale, "an_unknown_unit"); + size_t len = strlen(c); + variant var; - var.v = strcpy(balloc(len+1), c); + var.v = strcpy(balloc(len + 1), c); opush(stack, var); } -static void -eval_unitid(struct opstack ** stack, const void * userdata) /* unit -> int */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct unit * u = (const struct unit *)opop(stack).v; - const char * c = u?u->name:LOC(f->locale, "an_unknown_unit"); +static void eval_unitid(struct opstack **stack, const void *userdata) +{ /* unit -> int */ + const struct faction *f = (const struct faction *)userdata; + + const struct unit *u = (const struct unit *)opop(stack).v; + + const char *c = u ? u->name : LOC(f->locale, "an_unknown_unit"); + size_t len = strlen(c); + variant var; - var.v = strcpy(balloc(len+1), c); + var.v = strcpy(balloc(len + 1), c); opush(stack, var); } -static void -eval_unitsize(struct opstack ** stack, const void * userdata) /* unit -> int */ -{ - const struct unit * u = (const struct unit *)opop(stack).v; +static void eval_unitsize(struct opstack **stack, const void *userdata) +{ /* unit -> int */ + const struct unit *u = (const struct unit *)opop(stack).v; + variant var; var.i = u->number; opush(stack, var); } -static void -eval_faction(struct opstack ** stack, const void * userdata) /* faction -> string */ -{ - const struct faction * f = (const struct faction *)opop(stack).v; - const char * c = factionname(f); +static void eval_faction(struct opstack **stack, const void *userdata) +{ /* faction -> string */ + const struct faction *f = (const struct faction *)opop(stack).v; + + const char *c = factionname(f); + size_t len = strlen(c); + variant var; - var.v = strcpy(balloc(len+1), c); + var.v = strcpy(balloc(len + 1), c); opush(stack, var); } -static void -eval_alliance(struct opstack ** stack, const void * userdata) /* faction -> string */ -{ - const struct alliance * al = (const struct alliance *)opop(stack).v; - const char * c = alliancename(al); +static void eval_alliance(struct opstack **stack, const void *userdata) +{ /* faction -> string */ + const struct alliance *al = (const struct alliance *)opop(stack).v; + + const char *c = alliancename(al); + variant var; - if (c!=NULL) { + + if (c != NULL) { size_t len = strlen(c); - var.v = strcpy(balloc(len+1), c); - } - else var.v = NULL; + + var.v = strcpy(balloc(len + 1), c); + } else + var.v = NULL; opush(stack, var); } -static void -eval_region(struct opstack ** stack, const void * userdata) /* region -> string */ -{ - char name[NAMESIZE+32]; - const struct faction * f = (const struct faction *)userdata; - const struct region * r = (const struct region *)opop(stack).v; - const char * c = write_regionname(r, f, name, sizeof(name)); +static void eval_region(struct opstack **stack, const void *userdata) +{ /* region -> string */ + char name[NAMESIZE + 32]; + + const struct faction *f = (const struct faction *)userdata; + + const struct region *r = (const struct region *)opop(stack).v; + + const char *c = write_regionname(r, f, name, sizeof(name)); + size_t len = strlen(c); + variant var; - var.v = strcpy(balloc(len+1), c); + var.v = strcpy(balloc(len + 1), c); opush(stack, var); } -static void -eval_terrain(struct opstack ** stack, const void * userdata) /* region -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct region * r = (const struct region *)opop(stack).v; - const char * c = LOC(f->locale, terrain_name(r)); +static void eval_terrain(struct opstack **stack, const void *userdata) +{ /* region -> string */ + const struct faction *f = (const struct faction *)userdata; + + const struct region *r = (const struct region *)opop(stack).v; + + const char *c = LOC(f->locale, terrain_name(r)); + size_t len = strlen(c); + variant var; - var.v = strcpy(balloc(len+1), c); + var.v = strcpy(balloc(len + 1), c); opush(stack, var); } -static void -eval_ship(struct opstack ** stack, const void * userdata) /* ship -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct ship * u = (const struct ship *)opop(stack).v; - const char * c = u?shipname(u):LOC(f->locale, "an_unknown_ship"); +static void eval_ship(struct opstack **stack, const void *userdata) +{ /* ship -> string */ + const struct faction *f = (const struct faction *)userdata; + + const struct ship *u = (const struct ship *)opop(stack).v; + + const char *c = u ? shipname(u) : LOC(f->locale, "an_unknown_ship"); + size_t len = strlen(c); + variant var; - var.v = strcpy(balloc(len+1), c); + var.v = strcpy(balloc(len + 1), c); opush(stack, var); } -static void -eval_building(struct opstack ** stack, const void * userdata) /* building -> string */ -{ - const struct faction * f = (const struct faction *)userdata; - const struct building * u = (const struct building *)opop(stack).v; - const char * c = u?buildingname(u):LOC(f->locale, "an_unknown_building"); +static void eval_building(struct opstack **stack, const void *userdata) +{ /* building -> string */ + const struct faction *f = (const struct faction *)userdata; + + const struct building *u = (const struct building *)opop(stack).v; + + const char *c = u ? buildingname(u) : LOC(f->locale, "an_unknown_building"); + size_t len = strlen(c); + variant var; - var.v = strcpy(balloc(len+1), c); + var.v = strcpy(balloc(len + 1), c); opush(stack, var); } -static void -eval_weight(struct opstack ** stack, const void * userdata) /* region -> string */ -{ +static void eval_weight(struct opstack **stack, const void *userdata) +{ /* region -> string */ char buffer[32]; - const struct faction * f = (const struct faction *)userdata; - const struct locale * lang = f->locale; + + const struct faction *f = (const struct faction *)userdata; + + const struct locale *lang = f->locale; + int weight = opop_i(stack); + variant var; if (weight % SCALEWEIGHT == 0) { - if (weight==SCALEWEIGHT) { + if (weight == SCALEWEIGHT) { sprintf(buffer, "1 %s", LOC(lang, "weight_unit")); } else { - sprintf(buffer, "%u %s", weight/SCALEWEIGHT, LOC(lang, "weight_unit_p")); + sprintf(buffer, "%u %s", weight / SCALEWEIGHT, LOC(lang, + "weight_unit_p")); } } else { - if (weight==1) { + if (weight == 1) { sprintf(buffer, "1 %s %u", LOC(lang, "weight_per"), SCALEWEIGHT); } else { - sprintf(buffer, "%u %s %u", weight, LOC(lang, "weight_per_p"), SCALEWEIGHT); + sprintf(buffer, "%u %s %u", weight, LOC(lang, "weight_per_p"), + SCALEWEIGHT); } } - var.v = strcpy(balloc(strlen(buffer)+1), buffer); + var.v = strcpy(balloc(strlen(buffer) + 1), buffer); opush(stack, var); } -static void -eval_resource(struct opstack ** stack, const void * userdata) +static void eval_resource(struct opstack **stack, const void *userdata) { - const faction * report = (const faction*)userdata; - const struct locale * lang = report?report->locale:default_locale; + const faction *report = (const faction *)userdata; + + const struct locale *lang = report ? report->locale : default_locale; + int j = opop(stack).i; - const struct resource_type * res = (const struct resource_type *)opop(stack).v; - const char * c = LOC(lang, resourcename(res, j!=1)); + + const struct resource_type *res = (const struct resource_type *)opop(stack).v; + + const char *c = LOC(lang, resourcename(res, j != 1)); + size_t len = strlen(c); + variant var; - var.v = strcpy(balloc(len+1), c); + var.v = strcpy(balloc(len + 1), c); opush(stack, var); } -static void -eval_race(struct opstack ** stack, const void * userdata) +static void eval_race(struct opstack **stack, const void *userdata) { - const faction * report = (const faction*)userdata; - const struct locale * lang = report?report->locale:default_locale; + const faction *report = (const faction *)userdata; + + const struct locale *lang = report ? report->locale : default_locale; + int j = opop(stack).i; - const race * r = (const race *)opop(stack).v; - const char * c = LOC(lang, rc_name(r, j!=1)); + + const race *r = (const race *)opop(stack).v; + + const char *c = LOC(lang, rc_name(r, j != 1)); + size_t len = strlen(c); + variant var; - var.v = strcpy(balloc(len+1), c); + var.v = strcpy(balloc(len + 1), c); opush(stack, var); } -static void -eval_order(struct opstack ** stack, const void * userdata) /* order -> string */ -{ - const struct order * ord = (const struct order *)opop(stack).v; +static void eval_order(struct opstack **stack, const void *userdata) +{ /* order -> string */ + const struct order *ord = (const struct order *)opop(stack).v; + static char buf[256]; + size_t len; + variant var; unused(userdata); write_order(ord, buf, sizeof(buf)); len = strlen(buf); - var.v = strcpy(balloc(len+1), buf); + var.v = strcpy(balloc(len + 1), buf); opush(stack, var); } -static void -eval_resources(struct opstack ** stack, const void * userdata) /* order -> string */ -{ - const faction * report = (const faction*)userdata; - const struct locale * lang = report?report->locale:default_locale; - const struct resource * res = (const struct resource *)opop(stack).v; - static char buf[1024]; /* but we only use about half of this */ +static void eval_resources(struct opstack **stack, const void *userdata) +{ /* order -> string */ + const faction *report = (const faction *)userdata; + + const struct locale *lang = report ? report->locale : default_locale; + + const struct resource *res = (const struct resource *)opop(stack).v; + + static char buf[1024]; /* but we only use about half of this */ + size_t size = sizeof(buf) - 1; + variant var; - char * bufp = buf; - while (res!=NULL && size > 4) { - const char * rname = resourcename(res->type, (res->number!=1)?NMF_PLURAL:0); + char *bufp = buf; + + while (res != NULL && size > 4) { + const char *rname = + resourcename(res->type, (res->number != 1) ? NMF_PLURAL : 0); int bytes = snprintf(bufp, size, "%d %s", res->number, LOC(lang, rname)); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0 || sizenext; - if (res!=NULL && size>2) { + if (res != NULL && size > 2) { strcat(bufp, ", "); bufp += 2; size -= 2; } } *bufp = 0; - var.v = strcpy(balloc(bufp-buf+1), buf); + var.v = strcpy(balloc(bufp - buf + 1), buf); opush(stack, var); } -static void -eval_regions(struct opstack ** stack, const void * userdata) /* order -> string */ -{ - const faction * report = (const faction*)userdata; - int i = opop(stack).i; - int end, begin = opop(stack).i; - const arg_regions * regions = (const arg_regions *)opop(stack).v; - static char buf[256]; - size_t size = sizeof(buf) - 1; - variant var; - char * bufp = buf; +static void eval_regions(struct opstack **stack, const void *userdata) +{ /* order -> string */ + const faction *report = (const faction *)userdata; - if (regions==NULL) { + int i = opop(stack).i; + + int end, begin = opop(stack).i; + + const arg_regions *regions = (const arg_regions *)opop(stack).v; + + static char buf[256]; + + size_t size = sizeof(buf) - 1; + + variant var; + + char *bufp = buf; + + if (regions == NULL) { end = begin; } else { - if (i>=0) end = begin+i; - else end = regions->nregions+i; + if (i >= 0) + end = begin + i; + else + end = regions->nregions + i; } - for (i=begin;iregions[i], report); - int bytes = (int)strlcpy(bufp, rname, size); - if (bytes && wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); + for (i = begin; i < end; ++i) { + const char *rname = (const char *)regionname(regions->regions[i], report); - if (i+12) { + int bytes = (int)strlcpy(bufp, rname, size); + + if (bytes && wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + + if (i + 1 < end && size > 2) { strcat(bufp, ", "); bufp += 2; size -= 2; } } *bufp = 0; - var.v = strcpy(balloc(bufp-buf+1), buf); + var.v = strcpy(balloc(bufp - buf + 1), buf); opush(stack, var); } -static void -eval_trail(struct opstack ** stack, const void * userdata) /* order -> string */ -{ - const faction * report = (const faction*)userdata; - const struct locale * lang = report?report->locale:default_locale; +static void eval_trail(struct opstack **stack, const void *userdata) +{ /* order -> string */ + const faction *report = (const faction *)userdata; + + const struct locale *lang = report ? report->locale : default_locale; + int i, end = 0, begin = 0; - const arg_regions * regions = (const arg_regions *)opop(stack).v; + + const arg_regions *regions = (const arg_regions *)opop(stack).v; + static char buf[512]; + size_t size = sizeof(buf) - 1; + variant var; - char * bufp = buf; + + char *bufp = buf; + #ifdef _SECURECRT_ERRCODE_VALUES_DEFINED /* stupid MS broke snprintf */ int eold = errno; #endif - if (regions!=NULL) { + if (regions != NULL) { end = regions->nregions; - for (i=begin;iregions[i]; - const char * trail = trailinto(r, lang); - const char * rn = f_regionid_s(r, report); + for (i = begin; i < end; ++i) { + region *r = regions->regions[i]; + + const char *trail = trailinto(r, lang); + + const char *rn = f_regionid_s(r, report); + int bytes = snprintf(bufp, size, trail, rn); - if (bytes<0 || wrptr(&bufp, &size, bytes)!=0) WARN_STATIC_BUFFER(); - if (i+2locale:default_locale; + const faction *report = (const faction *)userdata; + + const struct locale *lang = report ? report->locale : default_locale; + int i = opop(stack).i; - const char * c = LOC(lang, (i>=0)?directions[i]:"unknown_direction"); + + const char *c = LOC(lang, (i >= 0) ? directions[i] : "unknown_direction"); + size_t len = strlen(c); + variant var; - var.v = strcpy(balloc(len+1), c); + var.v = strcpy(balloc(len + 1), c); opush(stack, var); } -static void -eval_skill(struct opstack ** stack, const void * userdata) +static void eval_skill(struct opstack **stack, const void *userdata) { - const faction * report = (const faction*)userdata; - const struct locale * lang = report?report->locale:default_locale; - skill_t sk = (skill_t)opop(stack).i; - const char * c = skillname(sk, lang); + const faction *report = (const faction *)userdata; + + const struct locale *lang = report ? report->locale : default_locale; + + skill_t sk = (skill_t) opop(stack).i; + + const char *c = skillname(sk, lang); + size_t len = strlen(c); + variant var; - var.v = strcpy(balloc(len+1), c); + var.v = strcpy(balloc(len + 1), c); opush(stack, var); } -static void -eval_int36(struct opstack ** stack, const void * userdata) +static void eval_int36(struct opstack **stack, const void *userdata) { int i = opop(stack).i; - const char * c = itoa36(i); + + const char *c = itoa36(i); + size_t len = strlen(c); + variant var; - var.v = strcpy(balloc(len+1), c); + var.v = strcpy(balloc(len + 1), c); opush(stack, var); unused(userdata); } + /*** END MESSAGE RENDERING ***/ #include -static void log_orders(const struct message * msg) +static void log_orders(const struct message *msg) { - faction * f = get_monsters(); + faction *f = get_monsters(); + char buffer[4096]; + int i; - for (i=0;i!=msg->type->nparameters;++i) { - if (msg->type->types[i]->copy==&var_copy_order) { - const char * section = nr_section(msg); - nr_render(msg, f?f->locale:default_locale, buffer, sizeof(buffer), f); + for (i = 0; i != msg->type->nparameters; ++i) { + if (msg->type->types[i]->copy == &var_copy_order) { + const char *section = nr_section(msg); + + nr_render(msg, f ? f->locale : default_locale, buffer, sizeof(buffer), f); log_printf("MESSAGE [%s]: %s\n", section, buffer); break; } } } -int -report_action(region * r, unit * actor, message * msg, int flags) +int report_action(region * r, unit * actor, message * msg, int flags) { int result = 0; - unit * u; - int view = flags&(ACTION_CANSEE|ACTION_CANNOTSEE); + + unit *u; + + int view = flags & (ACTION_CANSEE | ACTION_CANNOTSEE); /* melden, 1x pro Partei */ - if (flags&ACTION_RESET) { + if (flags & ACTION_RESET) { freset(actor->faction, FFL_SELECT); - for (u = r->units; u; u = u->next ) freset(u->faction, FFL_SELECT); + for (u = r->units; u; u = u->next) + freset(u->faction, FFL_SELECT); } if (view) { - for (u = r->units; u; u = u->next ) { - if (!fval(u->faction, FFL_SELECT) ) { + for (u = r->units; u; u = u->next) { + if (!fval(u->faction, FFL_SELECT)) { boolean show = u->faction == actor->faction; + fset(u->faction, FFL_SELECT); - if (view==ACTION_CANSEE) { + if (view == ACTION_CANSEE) { /* Bei Fernzaubern sieht nur die eigene Partei den Magier */ - show = show || (r==actor->region && cansee(u->faction, r, actor, 0)); - } else if (view==ACTION_CANNOTSEE) { - show = !show && !(r==actor->region && cansee(u->faction, r, actor, 0)); + show = show || (r == actor->region + && cansee(u->faction, r, actor, 0)); + } else if (view == ACTION_CANNOTSEE) { + show = !show && !(r == actor->region + && cansee(u->faction, r, actor, 0)); } else { /* the unliely (or lazy) case */ show = true; @@ -2112,14 +2524,14 @@ report_action(region * r, unit * actor, message * msg, int flags) if (show) { r_addmessage(r, u->faction, msg); - } else { /* Partei des Magiers, sieht diesen immer */ + } else { /* Partei des Magiers, sieht diesen immer */ result = 1; } } } /* Ist niemand von der Partei des Magiers in der Region, dem Magier - * nochmal gesondert melden */ - if ((flags&ACTION_CANSEE) && !fval(actor->faction, FFL_SELECT)) { + * nochmal gesondert melden */ + if ((flags & ACTION_CANSEE) && !fval(actor->faction, FFL_SELECT)) { add_message(&actor->faction->msgs, msg); } } @@ -2127,8 +2539,7 @@ report_action(region * r, unit * actor, message * msg, int flags) } -void -register_reports(void) +void register_reports(void) { /* register datatypes for the different message objects */ register_argtype("alliance", NULL, NULL, VAR_VOIDPTR); @@ -2181,6 +2592,6 @@ register_reports(void) add_function("trail", &eval_trail); /* register alternative visibility functions */ - register_function((pf_generic)view_neighbours, "view_neighbours"); - register_function((pf_generic)view_regatta, "view_regatta"); + register_function((pf_generic) view_neighbours, "view_neighbours"); + register_function((pf_generic) view_regatta, "view_regatta"); } diff --git a/src/kernel/reports.h b/src/kernel/reports.h index d97e204df..18da82306 100644 --- a/src/kernel/reports.h +++ b/src/kernel/reports.h @@ -27,112 +27,131 @@ extern "C" { /* Breite einer Reportzeile: */ #define REPORTWIDTH 78 -extern const char *directions[]; -extern const char *coasts[]; -extern boolean nonr; -extern boolean nocr; -extern boolean noreports; + extern const char *directions[]; + extern const char *coasts[]; + extern boolean nonr; + extern boolean nocr; + extern boolean noreports; /* kann_finden speedups */ -extern boolean kann_finden(struct faction * f1, struct faction * f2); -extern struct unit * can_find(struct faction *, struct faction *); + extern boolean kann_finden(struct faction *f1, struct faction *f2); + extern struct unit *can_find(struct faction *, struct faction *); /* funktionen zum schreiben eines reports */ -void sparagraph(struct strlist ** SP, const char *s, int indent, char mark); -void lparagraph(struct strlist ** SP, char *s, int indent, char mark); -const char *hp_status(const struct unit * u); -extern size_t spskill(char * pbuf, size_t siz, const struct locale * lang, const struct unit * u, struct skill * sv, int *dh, int days); /* mapper */ -extern void spunit(struct strlist ** SP, const struct faction * f, const struct unit * u, int indent, int mode); + void sparagraph(struct strlist **SP, const char *s, int indent, char mark); + void lparagraph(struct strlist **SP, char *s, int indent, char mark); + const char *hp_status(const struct unit *u); + extern size_t spskill(char *pbuf, size_t siz, const struct locale *lang, const struct unit *u, struct skill *sv, int *dh, int days); /* mapper */ + extern void spunit(struct strlist **SP, const struct faction *f, + const struct unit *u, int indent, int mode); -extern int reports(void); -extern int write_reports(struct faction * f, time_t ltime); -extern int init_reports(void); + extern int reports(void); + extern int write_reports(struct faction *f, time_t ltime); + extern int init_reports(void); -extern const struct unit *ucansee(const struct faction *f, const struct unit *u, const struct unit *x); + extern const struct unit *ucansee(const struct faction *f, + const struct unit *u, const struct unit *x); -int hat_in_region(item_t itm, struct region * r, struct faction * f); + int hat_in_region(item_t itm, struct region *r, struct faction *f); /* für fast_region und neuen CR: */ -enum { - see_none, - see_neighbour, - see_lighthouse, - see_travel, - see_far, - see_unit, - see_battle -}; -extern int stealth_modifier(int seen_mode); + enum { + see_none, + see_neighbour, + see_lighthouse, + see_travel, + see_far, + see_unit, + see_battle + }; + extern int stealth_modifier(int seen_mode); -typedef struct seen_region { - struct seen_region * nextHash; - struct seen_region * next; - struct region *r; - unsigned char mode; - boolean disbelieves; -} seen_region; + typedef struct seen_region { + struct seen_region *nextHash; + struct seen_region *next; + struct region *r; + unsigned char mode; + boolean disbelieves; + } seen_region; -extern struct seen_region * find_seen(struct seen_region * seehash[], const struct region * r); -extern boolean add_seen(struct seen_region * seehash[], struct region * r, unsigned char mode, boolean dis); -extern struct seen_region ** seen_init(void); -extern void seen_done(struct seen_region * seehash[]); -extern void free_seen(void); -extern void link_seen(seen_region * seehash[], const struct region * first, const struct region * last); -extern const char * visibility[]; + extern struct seen_region *find_seen(struct seen_region *seehash[], + const struct region *r); + extern boolean add_seen(struct seen_region *seehash[], struct region *r, + unsigned char mode, boolean dis); + extern struct seen_region **seen_init(void); + extern void seen_done(struct seen_region *seehash[]); + extern void free_seen(void); + extern void link_seen(seen_region * seehash[], const struct region *first, + const struct region *last); + extern const char *visibility[]; -typedef struct report_context { - struct faction * f; - struct quicklist * addresses; - struct seen_region ** seen; - struct region * first, * last; - void * userdata; - time_t report_time; -} report_context; + typedef struct report_context { + struct faction *f; + struct quicklist *addresses; + struct seen_region **seen; + struct region *first, *last; + void *userdata; + time_t report_time; + } report_context; -typedef int (*report_fun)(const char * filename, report_context * ctx, const char * charset); -extern void register_reporttype(const char * extension, report_fun write, int flag); + typedef int (*report_fun) (const char *filename, report_context * ctx, + const char *charset); + extern void register_reporttype(const char *extension, report_fun write, + int flag); -extern int bufunit(const struct faction * f, const struct unit * u, int indent, int mode, char * buf, size_t size); + extern int bufunit(const struct faction *f, const struct unit *u, int indent, + int mode, char *buf, size_t size); -extern const char * trailinto(const struct region * r, const struct locale * lang); -extern const char * report_kampfstatus(const struct unit * u, const struct locale * lang); + extern const char *trailinto(const struct region *r, + const struct locale *lang); + extern const char *report_kampfstatus(const struct unit *u, + const struct locale *lang); extern void register_reports(void); extern int update_nmrs(void); - extern int * nmrs; + extern int *nmrs; - extern struct message * msg_curse(const struct curse * c, const void * obj, typ_t typ, int slef); + extern struct message *msg_curse(const struct curse *c, const void *obj, + typ_t typ, int slef); typedef struct arg_regions { int nregions; - struct region ** regions; + struct region **regions; } arg_regions; typedef struct resource_report { - const char * name; + const char *name; int number; int level; } resource_report; - int report_resources(const struct seen_region * sr, struct resource_report * result, int size, const struct faction * viewer); - int report_items(const struct item * items, struct item * result, int size, const struct unit * owner, const struct faction * viewer); - void report_item(const struct unit * owner, const struct item * i, const struct faction * viewer, const char ** name, const char ** basename, int * number, boolean singular); - void report_building(const struct building * b, const char ** btype, const char ** billusion); - void report_race(const struct unit * u, const char ** rcname, const char ** rcillusion); + int report_resources(const struct seen_region *sr, + struct resource_report *result, int size, const struct faction *viewer); + int report_items(const struct item *items, struct item *result, int size, + const struct unit *owner, const struct faction *viewer); + void report_item(const struct unit *owner, const struct item *i, + const struct faction *viewer, const char **name, const char **basename, + int *number, boolean singular); + void report_building(const struct building *b, const char **btype, + const char **billusion); + void report_race(const struct unit *u, const char **rcname, + const char **rcillusion); -#define ACTION_RESET 0x01 /* reset the one-time-flag FFL_SELECT (on first pass) */ -#define ACTION_CANSEE 0x02 /* to people who can see the actor */ -#define ACTION_CANNOTSEE 0x04 /* to people who can not see the actor */ -extern int report_action(struct region * r, struct unit * actor, struct message * msg, int flags); +#define ACTION_RESET 0x01 /* reset the one-time-flag FFL_SELECT (on first pass) */ +#define ACTION_CANSEE 0x02 /* to people who can see the actor */ +#define ACTION_CANNOTSEE 0x04 /* to people who can not see the actor */ + extern int report_action(struct region *r, struct unit *actor, + struct message *msg, int flags); - extern size_t f_regionid(const struct region * r, const struct faction * f, char * buffer, size_t size); + extern size_t f_regionid(const struct region *r, const struct faction *f, + char *buffer, size_t size); - extern const char * combatstatus[]; -#define GR_PLURAL 0x01 /* grammar: plural */ -#define MAX_INVENTORY 128 /* maimum number of different items in an inventory */ -#define MAX_RAWMATERIALS 8 /* maximum kinds of raw materials in a regions */ + extern const char *combatstatus[]; +#define GR_PLURAL 0x01 /* grammar: plural */ +#define MAX_INVENTORY 128 /* maimum number of different items in an inventory */ +#define MAX_RAWMATERIALS 8 /* maximum kinds of raw materials in a regions */ #ifdef __cplusplus } diff --git a/src/kernel/resources.c b/src/kernel/resources.c index 999ff1671..1cffd5d74 100644 --- a/src/kernel/resources.c +++ b/src/kernel/resources.c @@ -27,138 +27,158 @@ #include #include -static double -ResourceFactor(void) +static double ResourceFactor(void) { static double value = -1.0; - if (value<0) { - const char * str = get_param(global.parameters, "resource.factor"); - value = str?atof(str):1.0; + + if (value < 0) { + const char *str = get_param(global.parameters, "resource.factor"); + + value = str ? atof(str) : 1.0; } return value; } -void -update_resources(region * r) +void update_resources(region * r) { - struct rawmaterial * res = r->resources; + struct rawmaterial *res = r->resources; + while (res) { - if (res->type->update) res->type->update(res, r); + if (res->type->update) + res->type->update(res, r); res = res->next; } } extern int dice_rand(const char *s); -static void -update_resource(struct rawmaterial * res, double modifier) +static void update_resource(struct rawmaterial *res, double modifier) { - double amount = 1 + (res->level-res->startlevel) * res->divisor/100.0; + double amount = 1 + (res->level - res->startlevel) * res->divisor / 100.0; + amount = ResourceFactor() * res->base * amount * modifier; - if (amount<1.0) res->amount = 1; - else res->amount = (int)amount; - assert(res->amount>0); + if (amount < 1.0) + res->amount = 1; + else + res->amount = (int)amount; + assert(res->amount > 0); } void -add_resource(region * r, int level, int base, int divisor, const resource_type * rtype) +add_resource(region * r, int level, int base, int divisor, + const resource_type * rtype) { - struct rawmaterial * rm = calloc(sizeof(struct rawmaterial), 1); + struct rawmaterial *rm = calloc(sizeof(struct rawmaterial), 1); rm->next = r->resources; r->resources = rm; - rm->level = level; + rm->level = level; rm->startlevel = level; - rm->base = base; - rm->divisor = divisor; - rm->flags = 0; - rm->type = rmt_get(rtype); + rm->base = base; + rm->divisor = divisor; + rm->flags = 0; + rm->type = rmt_get(rtype); update_resource(rm, 1.0); rm->type->terraform(rm, r); } -void -terraform_resources(region * r) +void terraform_resources(region * r) { int i; - const terrain_type * terrain = r->terrain; - if (terrain->production==NULL) return; - for (i=0;terrain->production[i].type; ++i) { + const terrain_type *terrain = r->terrain; + + if (terrain->production == NULL) + return; + for (i = 0; terrain->production[i].type; ++i) { rawmaterial *rm; - const terrain_production * production = terrain->production+i; - const resource_type * rtype = production->type; - for (rm=r->resources; rm; rm=rm->next) { - if (rm->type->rtype == rtype) break; + const terrain_production *production = terrain->production + i; + + const resource_type *rtype = production->type; + + for (rm = r->resources; rm; rm = rm->next) { + if (rm->type->rtype == rtype) + break; } - if (rm) continue; - + if (rm) + continue; + if (chance(production->chance)) { - add_resource(r, dice_rand(production->startlevel), dice_rand(production->base), dice_rand(production->divisor), production->type); + add_resource(r, dice_rand(production->startlevel), + dice_rand(production->base), dice_rand(production->divisor), + production->type); } } } -static void -terraform_default(struct rawmaterial * res, const region * r) +static void terraform_default(struct rawmaterial *res, const region * r) { #define SHIFT 70 - double modifier = 1.0 + ((rng_int() % (SHIFT*2+1)) - SHIFT) * ((rng_int() % (SHIFT*2+1)) - SHIFT) / 10000.0; - res->amount = (int)(res->amount*modifier); /* random adjustment, +/- 91% */ - if (res->amount<1) res->amount=1; - unused(r); + double modifier = + 1.0 + ((rng_int() % (SHIFT * 2 + 1)) - SHIFT) * ((rng_int() % (SHIFT * 2 + + 1)) - SHIFT) / 10000.0; + res->amount = (int)(res->amount * modifier); /* random adjustment, +/- 91% */ + if (res->amount < 1) + res->amount = 1; + unused(r); } #ifdef RANDOM_CHANGE -static void -resource_random_change(int *pvalue, boolean used) +static void resource_random_change(int *pvalue, boolean used) { - int split = 5; - int rnd = rng_int()%100; + int split = 5; - if (pvalue==0 || rnd %10 >= 10) return; - if (used) split = 4; - /* if a resource was mined this round, there is a 6% probability - * of a decline and a 4% probability of a raise. */ - /* if it wasn't mined this round, there is an equal probability - * of 5% for a decline or a raise. */ - if(rnd < split) { - (*pvalue)++; - } else { - (*pvalue)--; - } - if ((*pvalue) < 0) (*pvalue) = 0; + int rnd = rng_int() % 100; + + if (pvalue == 0 || rnd % 10 >= 10) + return; + if (used) + split = 4; + /* if a resource was mined this round, there is a 6% probability + * of a decline and a 4% probability of a raise. */ + /* if it wasn't mined this round, there is an equal probability + * of 5% for a decline or a raise. */ + if (rnd < split) { + (*pvalue)++; + } else { + (*pvalue)--; + } + if ((*pvalue) < 0) + (*pvalue) = 0; } #endif -static int -visible_default(const rawmaterial *res, int skilllevel) +static int visible_default(const rawmaterial * res, int skilllevel) /* resources are visible, if skill equals minimum skill to mine them * plus current level of difficulty */ { - const struct item_type * itype = res->type->rtype->itype; - if (res->level<=1 && res->level + itype->construction->minskill <= skilllevel+1) { - assert (res->amount>0); - return res->amount; - } else if (res->level + itype->construction->minskill <= skilllevel+2) { - assert (res->amount>0); - return res->amount; - } - return -1; + const struct item_type *itype = res->type->rtype->itype; + + if (res->level <= 1 + && res->level + itype->construction->minskill <= skilllevel + 1) { + assert(res->amount > 0); + return res->amount; + } else if (res->level + itype->construction->minskill <= skilllevel + 2) { + assert(res->amount > 0); + return res->amount; + } + return -1; } -static void -use_default(rawmaterial *res, const region * r, int amount) +static void use_default(rawmaterial * res, const region * r, int amount) { - assert(res->amount>0 && amount>=0 && amount <= res->amount); - res->amount-=amount; - while (res->amount==0) { - double modifier = 1.0 + ((rng_int() % (SHIFT*2+1)) - SHIFT) * ((rng_int() % (SHIFT*2+1)) - SHIFT) / 10000.0; + assert(res->amount > 0 && amount >= 0 && amount <= res->amount); + res->amount -= amount; + while (res->amount == 0) { + double modifier = + 1.0 + ((rng_int() % (SHIFT * 2 + 1)) - SHIFT) * ((rng_int() % (SHIFT * 2 + + 1)) - SHIFT) / 10000.0; int i; - for (i=0;r->terrain->production[i].type;++i) { - if (res->type->rtype == r->terrain->production[i].type) break; + for (i = 0; r->terrain->production[i].type; ++i) { + if (res->type->rtype == r->terrain->production[i].type) + break; } ++res->level; @@ -166,36 +186,40 @@ use_default(rawmaterial *res, const region * r, int amount) } } -struct rawmaterial * -rm_get(region * r, const struct resource_type * rtype) +struct rawmaterial *rm_get(region * r, const struct resource_type *rtype) { - struct rawmaterial * rm = r->resources; - while (rm && rm->type->rtype!=rtype) rm = rm->next; - return rm; + struct rawmaterial *rm = r->resources; + + while (rm && rm->type->rtype != rtype) + rm = rm->next; + return rm; } -struct rawmaterial_type * rawmaterialtypes = 0; +struct rawmaterial_type *rawmaterialtypes = 0; -struct rawmaterial_type * -rmt_find(const char * str) +struct rawmaterial_type *rmt_find(const char *str) { - rawmaterial_type * rmt = rawmaterialtypes; - while (rmt && strcmp(rmt->name, str)!=0) rmt = rmt->next; - return rmt; -} + rawmaterial_type *rmt = rawmaterialtypes; -struct rawmaterial_type * -rmt_get(const struct resource_type * rtype) -{ - rawmaterial_type * rmt = rawmaterialtypes; - while (rmt && rmt->rtype!=rtype) rmt = rmt->next; + while (rmt && strcmp(rmt->name, str) != 0) + rmt = rmt->next; return rmt; } -struct rawmaterial_type * -rmt_create(const struct resource_type * rtype, const char * name) +struct rawmaterial_type *rmt_get(const struct resource_type *rtype) { - rawmaterial_type * rmtype = malloc(sizeof(rawmaterial_type)); + rawmaterial_type *rmt = rawmaterialtypes; + + while (rmt && rmt->rtype != rtype) + rmt = rmt->next; + return rmt; +} + +struct rawmaterial_type *rmt_create(const struct resource_type *rtype, + const char *name) +{ + rawmaterial_type *rmtype = malloc(sizeof(rawmaterial_type)); + rmtype->name = strdup(name); rmtype->rtype = rtype; rmtype->terraform = terraform_default; diff --git a/src/kernel/resources.h b/src/kernel/resources.h index 9c99ad6f8..d2c229657 100644 --- a/src/kernel/resources.h +++ b/src/kernel/resources.h @@ -15,47 +15,50 @@ extern "C" { #endif -enum { - RM_USED = 1<<0, /* resource has been used */ - RM_MALLORN = 1<<1 /* this is not wood. it's mallorn */ -}; + enum { + RM_USED = 1 << 0, /* resource has been used */ + RM_MALLORN = 1 << 1 /* this is not wood. it's mallorn */ + }; -typedef struct rawmaterial { - const struct rawmaterial_type * type; - int amount : 16; - int level : 8; - int flags : 8; - int base : 8; - int divisor : 8; - int startlevel : 8; - struct rawmaterial * next; -} rawmaterial; + typedef struct rawmaterial { + const struct rawmaterial_type *type; + int amount:16; + int level:8; + int flags:8; + int base:8; + int divisor:8; + int startlevel:8; + struct rawmaterial *next; + } rawmaterial; -typedef struct rawmaterial_type { - char * name; - const struct resource_type * rtype; + typedef struct rawmaterial_type { + char *name; + const struct resource_type *rtype; - void (*terraform) (struct rawmaterial *, const struct region *); - void (*update) (struct rawmaterial *, const struct region *); - void (*use) (struct rawmaterial *, const struct region *, int amount); - int (*visible) (const struct rawmaterial *, int skilllevel); + void (*terraform) (struct rawmaterial *, const struct region *); + void (*update) (struct rawmaterial *, const struct region *); + void (*use) (struct rawmaterial *, const struct region *, int amount); + int (*visible) (const struct rawmaterial *, int skilllevel); - /* no initialization required */ - struct rawmaterial_type * next; -} rawmaterial_type; + /* no initialization required */ + struct rawmaterial_type *next; + } rawmaterial_type; -extern struct rawmaterial_type * rawmaterialtypes; + extern struct rawmaterial_type *rawmaterialtypes; -extern void update_resources(struct region * r); -extern void terraform_resources(struct region * r); -extern void read_resources(struct region * r); -extern void write_resources(struct region * r); -extern struct rawmaterial * rm_get(struct region *, const struct resource_type *); -extern struct rawmaterial_type * rmt_find(const char * str); -extern struct rawmaterial_type * rmt_get(const struct resource_type *); + extern void update_resources(struct region *r); + extern void terraform_resources(struct region *r); + extern void read_resources(struct region *r); + extern void write_resources(struct region *r); + extern struct rawmaterial *rm_get(struct region *, + const struct resource_type *); + extern struct rawmaterial_type *rmt_find(const char *str); + extern struct rawmaterial_type *rmt_get(const struct resource_type *); -extern void add_resource(struct region * r, int level, int base, int divisor, const struct resource_type * rtype); -extern struct rawmaterial_type * rmt_create(const struct resource_type * rtype, const char * name); + extern void add_resource(struct region *r, int level, int base, int divisor, + const struct resource_type *rtype); + extern struct rawmaterial_type *rmt_create(const struct resource_type *rtype, + const char *name); #ifdef __cplusplus } diff --git a/src/kernel/save.c b/src/kernel/save.c index 7dedc93b1..0c1fa0a69 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -41,7 +41,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "skill.h" #include "spell.h" #include "terrain.h" -#include "terrainid.h" /* only for conversion code */ +#include "terrainid.h" /* only for conversion code */ #include "unit.h" #include "version.h" @@ -88,113 +88,130 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define MAXPERSISTENT 128 /* exported symbols symbols */ -const char * game_name = "eressea"; +const char *game_name = "eressea"; + int firstx = 0, firsty = 0; + int enc_gamedata = 0; /* local symbols */ -static region * current_region; +static region *current_region; -char * -rns(FILE * f, char *c, size_t size) +char *rns(FILE * f, char *c, size_t size) { - char * s = c; + char *s = c; + do { - *s = (char) getc(f); - } while (*s!='"'); + *s = (char)getc(f); + } while (*s != '"'); for (;;) { - *s = (char) getc(f); - if (*s=='"') break; - if (s0) str+=ret; - else { - log_error(("input data was not iso-8859-1! assuming utf-8\n")); - encoding = XML_CHAR_ENCODING_ERROR; - *str++ = (char)c; + case EOF: + return EOF; + case 'n': + if ((size_t) (str - start + 1) < size) { + *str++ = '\n'; + } + break; + default: + if ((size_t) (str - start + 1) < size) { + if (encoding == XML_CHAR_ENCODING_8859_1 && c & 0x80) { + char inbuf = (char)c; + + size_t inbytes = 1; + + size_t outbytes = size - (str - start); + + int ret = + unicode_latin1_to_utf8(str, &outbytes, &inbuf, &inbytes); + if (ret > 0) + str += ret; + else { + log_error( + ("input data was not iso-8859-1! assuming utf-8\n")); + encoding = XML_CHAR_ENCODING_ERROR; + *str++ = (char)c; + } + } else { + *str++ = (char)c; + } } - } else { - *str++ = (char)c; - } - } } break; default: - if ((size_t)(str-start+1)0) str+=ret; + + if (ret > 0) + str += ret; else { log_error(("input data was not iso-8859-1! assuming utf-8\n")); encoding = XML_CHAR_ENCODING_ERROR; @@ -212,48 +229,52 @@ freadstr(FILE * F, int encoding, char * start, size_t size) /** writes a quoted string to the file * no trailing space, since this is used to make the creport. */ -int -fwritestr(FILE * F, const char * str) +int fwritestr(FILE * F, const char *str) { int nwrite = 0; + fputc('\"', F); - if (str) while (*str) { - int c = (int)(unsigned char)*str++; - switch (c) { - case '"': - case '\\': - fputc('\\', F); - fputc(c, F); - nwrite+=2; - break; - case '\n': - fputc('\\', F); - fputc('n', F); - nwrite+=2; - break; - default: - fputc(c, F); - ++nwrite; + if (str) + while (*str) { + int c = (int)(unsigned char)*str++; + + switch (c) { + case '"': + case '\\': + fputc('\\', F); + fputc(c, F); + nwrite += 2; + break; + case '\n': + fputc('\\', F); + fputc('n', F); + nwrite += 2; + break; + default: + fputc(c, F); + ++nwrite; + } } - } fputc('\"', F); return nwrite + 2; } -static unit * -unitorders(FILE * F, int enc, struct faction * f) +static unit *unitorders(FILE * F, int enc, struct faction *f) { int i; + unit *u; - if (!f) return NULL; + if (!f) + return NULL; i = getid(); u = findunitg(i, NULL); - if (u && u->race == new_race[RC_SPELL]) return NULL; + if (u && u->race == new_race[RC_SPELL]) + return NULL; if (u && u->faction == f) { - order ** ordp; + order **ordp; if (!fval(u, UFL_ORDERS)) { /* alle wiederholbaren, langen befehle werden gesichert: */ @@ -261,7 +282,8 @@ unitorders(FILE * F, int enc, struct faction * f) u->old_orders = u->orders; ordp = &u->old_orders; while (*ordp) { - order * ord = *ordp; + order *ord = *ordp; + if (!is_repeated(ord)) { *ordp = ord->next; ord->next = NULL; @@ -278,21 +300,26 @@ unitorders(FILE * F, int enc, struct faction * f) ordp = &u->orders; for (;;) { - const char * s; + 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 */ + * eingegeben wurde, checken wir, ob nun eine neue + * Einheit oder ein neuer Spieler drankommt */ s = getbuf(F, enc); - if (s==NULL) break; + if (s == NULL) + break; if (s[0]) { - const char * stok = s; + const char *stok = s; + stok = parse_token(&stok); if (stok) { boolean quit = false; + param_t param = findparam(stok, u->faction->locale); + switch (param) { case P_UNIT: case P_REGION: @@ -302,18 +329,20 @@ unitorders(FILE * F, int enc, struct faction * f) case P_NEXT: case P_GAMENAME: /* these terminate the orders, so we apply extra checking */ - if (strlen(stok)>=3) { + if (strlen(stok) >= 3) { quit = true; break; } else { quit = false; } } - if (quit) break; + if (quit) + break; } /* Nun wird der Befehl erzeut und eingehängt */ *ordp = parse_order(s, u->faction->locale); - if (*ordp) ordp = &(*ordp)->next; + if (*ordp) + ordp = &(*ordp)->next; } } @@ -324,61 +353,65 @@ unitorders(FILE * F, int enc, struct faction * f) return u; } -static faction * -factionorders(void) +static faction *factionorders(void) { - faction * f = NULL; + faction *f = NULL; + int fid = getid(); f = findfaction(fid); - - if (f!=NULL && !is_monsters(f)) { - const char * pass = getstrtoken(); + + if (f != NULL && !is_monsters(f)) { + const char *pass = getstrtoken(); if (!checkpasswd(f, (const char *)pass, true)) { log_warning(("Invalid password for faction %s\n", itoa36(fid))); ADDMSG(&f->msgs, msg_message("wrongpasswd", "faction password", - f->no, pass)); + f->no, pass)); return 0; } /* Die Partei hat sich zumindest gemeldet, so daß sie noch * nicht als untätig gilt */ - + /* TODO: +1 ist ein Workaround, weil cturn erst in process_orders * incrementiert wird. */ - f->lastorders = global.data_turn+1; - + f->lastorders = global.data_turn + 1; + } else { log_warning(("orders for invalid faction %s\n", itoa36(fid))); } return f; } -double -version(void) +double version(void) { return RELEASE_VERSION * 0.1; } + /* ------------------------------------------------------------- */ -static param_t -igetparam (const char *s, const struct locale *lang) +static param_t igetparam(const char *s, const struct locale *lang) { - return findparam (igetstrtoken (s), lang); + return findparam(igetstrtoken(s), lang); } -int -readorders(const char *filename) +int readorders(const char *filename) { - FILE * F = NULL; + FILE *F = NULL; + const char *b; - int nfactions=0; + + int nfactions = 0; + struct faction *f = NULL; - if (filename) F = cfopen(filename, "rb"); - if (F==NULL) return 0; + if (filename) + F = cfopen(filename, "rb"); + if (F == NULL) + return 0; - if (verbosity>=1) puts(" - lese Befehlsdatei...\n"); + if (verbosity >= 1) + puts(" - lese Befehlsdatei...\n"); /* TODO: recognize UTF8 BOM */ b = getbuf(F, enc_gamedata); @@ -387,89 +420,96 @@ readorders(const char *filename) * Partei */ while (b) { - const struct locale * lang = f?f->locale:default_locale; + const struct locale *lang = f ? f->locale : default_locale; + int p; - const char * s; + + const char *s; switch (igetparam(b, lang)) { - case P_LOCALE: - s = getstrtoken(); + case P_LOCALE: + s = getstrtoken(); #undef LOCALE_CHANGE #ifdef LOCALE_CHANGE - if (f && find_locale(s)) { - f->locale = find_locale(s); - } + if (f && find_locale(s)) { + f->locale = find_locale(s); + } #endif - b = getbuf(F, enc_gamedata); - break; - 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; - p = igetparam(b, lang); - } while ((p != P_UNIT || !f) && p != P_FACTION && p != P_NEXT && p != P_GAMENAME); - break; + break; + case P_GAMENAME: + case P_FACTION: + f = factionorders(); + if (f) { + ++nfactions; + } - /* 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 - * muß buf erneut gefüllt werden, da die betreffende Information in nur - * einer Zeile steht, und nun die nächste gelesen werden muß. */ + b = getbuf(F, enc_gamedata); + break; - case P_NEXT: - f = NULL; - 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. */ - default: - b = getbuf(F, enc_gamedata); - break; + case P_UNIT: + if (!f || !unitorders(F, enc_gamedata, f)) + do { + b = getbuf(F, enc_gamedata); + if (!b) + break; + p = igetparam(b, lang); + } 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 + * muß buf erneut gefüllt werden, da die betreffende Information in nur + * einer Zeile steht, und nun die nächste gelesen werden muß. */ + + case P_NEXT: + f = NULL; + b = getbuf(F, enc_gamedata); + break; + + default: + b = getbuf(F, enc_gamedata); + break; } } fclose(F); - if (verbosity>=1) puts("\n"); + if (verbosity >= 1) + puts("\n"); log_printf(" %d Befehlsdateien gelesen\n", nfactions); return 0; } + /* ------------------------------------------------------------- */ /* #define INNER_WORLD */ /* fürs debuggen nur den inneren Teil der Welt laden */ /* -9;-27;-1;-19;Sumpfloch */ -int -inner_world(region * r) +int inner_world(region * r) { - static int xy[2] = - {18, -45}; - static int size[2] = - {27, 27}; + static int xy[2] = { 18, -45 }; + static int size[2] = { 27, 27 }; - if (r->x >= xy[0] && r->x < xy[0] + size[0] && r->y >= xy[1] && r->y < xy[1] + size[1]) + if (r->x >= xy[0] && r->x < xy[0] + size[0] && r->y >= xy[1] + && r->y < xy[1] + size[1]) return 2; - if (r->x >= xy[0] - 9 && r->x < xy[0] + size[0] + 9 && r->y >= xy[1] - 9 && r->y < xy[1] + size[1] + 9) + if (r->x >= xy[0] - 9 && r->x < xy[0] + size[0] + 9 && r->y >= xy[1] - 9 + && r->y < xy[1] + size[1] + 9) return 1; return 0; } int maxregions = -1; + int loadplane = 0; enum { @@ -487,88 +527,98 @@ enum { MAXTYPES }; -race_t -typus2race(unsigned char typus) +race_t typus2race(unsigned char typus) { - if (typus>0 && typus <=11) return (race_t)(typus-1); + if (typus > 0 && typus <= 11) + return (race_t) (typus - 1); return NORACE; } -void -create_backup(char *file) +void create_backup(char *file) { #ifdef HAVE_LINK char bfile[MAX_PATH]; + int c = 1; - if (access(file, R_OK) == 0) return; + if (access(file, R_OK) == 0) + return; do { sprintf(bfile, "%s.backup%d", file, c); c++; - } while(access(bfile, R_OK) == 0); + } while (access(bfile, R_OK) == 0); link(file, bfile); #endif } -void -read_items(struct storage * store, item **ilist) +void read_items(struct storage *store, item ** ilist) { for (;;) { char ibuf[32]; - const item_type * itype; + + const item_type *itype; + int i; + store->r_str_buf(store, ibuf, sizeof(ibuf)); - if (!strcmp("end", ibuf)) break; + if (!strcmp("end", ibuf)) + break; itype = it_find(ibuf); i = store->r_int(store); - if (i<=0) { - log_error(("data contains an entry with %d %s\n", i, itype->rtype->_name[1])); + if (i <= 0) { + log_error(("data contains an entry with %d %s\n", i, + itype->rtype->_name[1])); } else { - assert(itype!=NULL); - if (itype!=NULL) { + assert(itype != NULL); + if (itype != NULL) { i_change(ilist, itype, i); } } } } -static void -read_alliances(struct storage * store) +static void read_alliances(struct storage *store) { char pbuf[8]; + int id, terminator = 0; - if (store->versionversion < SAVEALLIANCE_VERSION) { + if (!AllianceRestricted() && !AllianceAuto()) + return; } - if (store->versionversion < ALLIANCELEADER_VERSION) { terminator = atoi36("end"); store->r_str_buf(store, pbuf, sizeof(pbuf)); id = atoi36(pbuf); } else { id = store->r_id(store); } - while (id!=terminator) { + while (id != terminator) { char aname[128]; - alliance * al; + + alliance *al; + store->r_str_buf(store, aname, sizeof(aname)); al = makealliance(id, aname); - if (store->version>=OWNER_2_VERSION) { + if (store->version >= OWNER_2_VERSION) { al->flags = store->r_int(store); } - if (store->version>=ALLIANCELEADER_VERSION) { - read_reference(&al->_leader, store, read_faction_reference, resolve_faction); + if (store->version >= ALLIANCELEADER_VERSION) { + read_reference(&al->_leader, store, read_faction_reference, + resolve_faction); id = store->r_id(store); - } else{ + } else { store->r_str_buf(store, pbuf, sizeof(pbuf)); id = atoi36(pbuf); } } } -void -write_alliances(struct storage * store) +void write_alliances(struct storage *store) { - alliance * al = alliances; + alliance *al = alliances; + while (al) { if (al->_leader) { store->w_id(store, al->id); @@ -583,12 +633,12 @@ write_alliances(struct storage * store) store->w_brk(store); } -void -write_items(struct storage * store, item *ilist) +void write_items(struct storage *store, item * ilist) { - item * itm; - for (itm=ilist;itm;itm=itm->next) { - assert(itm->number>=0); + item *itm; + + for (itm = ilist; itm; itm = itm->next) { + assert(itm->number >= 0); if (itm->number) { store->w_tok(store, resourcename(itm->type->rtype, 0)); store->w_int(store, itm->number); @@ -597,15 +647,17 @@ write_items(struct storage * store, item *ilist) store->w_tok(store, "end"); } -static int -resolve_owner(variant id, void * address) +static int resolve_owner(variant id, void *address) { - region_owner * owner = (region_owner *)address; + region_owner *owner = (region_owner *) address; + int result = 0; - faction * f = NULL; - if (id.i!=0) { + + faction *f = NULL; + + if (id.i != 0) { f = findfaction(id.i); - if (f==NULL) { + if (f == NULL) { log_error(("region has an invalid owner (%s)\n", itoa36(id.i))); f = get_monsters(); } @@ -617,22 +669,24 @@ resolve_owner(variant id, void * address) return result; } -static void -read_owner(struct storage * store, region_owner **powner) +static void read_owner(struct storage *store, region_owner ** powner) { int since_turn = store->r_int(store); - if (since_turn>=0) { - region_owner * owner = malloc(sizeof(region_owner)); + + if (since_turn >= 0) { + region_owner *owner = malloc(sizeof(region_owner)); + owner->since_turn = since_turn; owner->morale_turn = store->r_int(store); - if (store->version>=MOURNING_VERSION) { + if (store->version >= MOURNING_VERSION) { owner->flags = store->r_int(store); } else { owner->flags = 0; } - if (store->version>=OWNER_2_VERSION) { + if (store->version >= OWNER_2_VERSION) { int id = store->r_int(store); - owner->alliance = id?findalliance(id):NULL; + + owner->alliance = id ? findalliance(id) : NULL; } else { owner->alliance = NULL; } @@ -643,26 +697,26 @@ read_owner(struct storage * store, region_owner **powner) } } -static void -write_owner(struct storage * store, region_owner *owner) +static void write_owner(struct storage *store, region_owner * owner) { if (owner) { store->w_int(store, owner->since_turn); store->w_int(store, owner->morale_turn); store->w_int(store, owner->flags); - store->w_id(store, owner->alliance?owner->alliance->id:0); + store->w_id(store, owner->alliance ? owner->alliance->id : 0); write_faction_reference(owner->owner, store); } else { store->w_int(store, -1); } } -int -current_turn(void) +int current_turn(void) { char zText[MAX_PATH]; + int cturn = 0; - FILE * f; + + FILE *f; sprintf(zText, "%s/turn", basepath()); f = cfopen(zText, "r"); @@ -674,34 +728,45 @@ current_turn(void) } static void -writeorder(struct storage * store, const struct order * ord, const struct locale * lang) +writeorder(struct storage *store, const struct order *ord, + const struct locale *lang) { char obuf[1024]; + write_order(ord, obuf, sizeof(obuf)); - if (obuf[0]) store->w_str(store, obuf); + if (obuf[0]) + store->w_str(store, obuf); } -unit * -read_unit(struct storage * store) +unit *read_unit(struct storage *store) { skill_t sk; - unit * u; + + unit *u; + int number, n, p; - order ** orderp; + + order **orderp; + char obuf[1024]; - faction * f; + + faction *f; + char rname[32]; n = store->r_id(store); - if (n<=0) return NULL; + if (n <= 0) + return NULL; u = findunit(n); - if (u==NULL) { + if (u == NULL) { u = calloc(sizeof(unit), 1); u->no = n; uhash(u); } else { - while (u->attribs) a_remove(&u->attribs, u->attribs); - while (u->items) i_free(i_remove(&u->items, u->items)); + while (u->attribs) + a_remove(&u->attribs, u->attribs); + while (u->items) + i_free(i_remove(&u->items, u->items)); free(u->skills); u->skills = 0; u->skill_size = 0; @@ -710,7 +775,8 @@ read_unit(struct storage * store) n = store->r_id(store); f = findfaction(n); - if (f!=u->faction) u_setfaction(u, f); + if (f != u->faction) + u_setfaction(u, f); u->name = store->r_str(store); if (lomem) { @@ -720,19 +786,24 @@ read_unit(struct storage * store) } number = store->r_int(store); u->age = (short)store->r_int(store); - - if (store->versionversion < STORAGE_VERSION) { + char *space; + store->r_str_buf(store, rname, sizeof(rname)); space = strchr(rname, ' '); - if (space!=NULL) { - char * inc = space+1; - char * outc = space; + if (space != NULL) { + char *inc = space + 1; + + char *outc = space; + do { - while (*inc==' ') ++inc; + while (*inc == ' ') + ++inc; while (*inc) { *outc++ = *inc++; - if (*inc==' ') break; + if (*inc == ' ') + break; } } while (*inc); *outc = 0; @@ -742,19 +813,22 @@ read_unit(struct storage * store) } u->race = rc_find(rname); assert(u->race); - if (store->versionversion < STORAGE_VERSION) { store->r_str_buf(store, rname, sizeof(rname)); } else { store->r_tok_buf(store, rname, sizeof(rname)); } - if (rname[0] && skill_enabled[SK_STEALTH]) u->irace = rc_find(rname); - else u->irace = NULL; + if (rname[0] && skill_enabled[SK_STEALTH]) + u->irace = rc_find(rname); + else + u->irace = NULL; if (u->race->describe) { - const char * rcdisp = u->race->describe(u, u->faction->locale); + const char *rcdisp = u->race->describe(u, u->faction->locale); + if (u->display && rcdisp) { /* see if the data file contains old descriptions */ - if (strcmp(rcdisp, u->display)==0) { + if (strcmp(rcdisp, u->display) == 0) { free(u->display); u->display = NULL; } @@ -766,20 +840,23 @@ read_unit(struct storage * store) set_number(u, 0); } - if (count_unit(u) && u->faction) u->faction->no_units++; + if (count_unit(u) && u->faction) + u->faction->no_units++; set_number(u, number); n = store->r_id(store); - if (n>0) u->building = findbuilding(n); + if (n > 0) + u->building = findbuilding(n); n = store->r_id(store); - if (n>0) u->ship = findship(n); + if (n > 0) + u->ship = findship(n); setstatus(u, store->r_int(store)); u->flags = store->r_int(store); u->flags &= UFL_SAVEMASK; - if ((u->flags&UFL_ANON_FACTION) && !rule_stealth_faction()) { + if ((u->flags & UFL_ANON_FACTION) && !rule_stealth_faction()) { /* if this rule is broken, then fix broken units */ u->flags -= UFL_ANON_FACTION; log_warning(("%s was anonymous.\n", unitname(u))); @@ -791,29 +868,33 @@ read_unit(struct storage * store) orderp = &u->orders; while (obuf[0]) { if (!lomem) { - order * ord = parse_order(obuf, u->faction->locale); - if (ord!=NULL) { - if (++nfaction->locale); + + if (ord != NULL) { + if (++n < MAXORDERS) { + if (!is_persistent(ord) || ++p < MAXPERSISTENT) { *orderp = ord; orderp = &ord->next; ord = NULL; - } else if (p==MAXPERSISTENT) { - log_warning(("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT)); + } else if (p == MAXPERSISTENT) { + log_warning(("%s had %d or more persistent orders\n", unitname(u), + MAXPERSISTENT)); } - } else if (n==MAXORDERS) { + } else if (n == MAXORDERS) { log_warning(("%s had %d or more orders\n", unitname(u), MAXORDERS)); } - if (ord!=NULL) free_order(ord); + if (ord != NULL) + free_order(ord); } } store->r_str_buf(store, obuf, sizeof(obuf)); } - if (store->versionversion < NOLASTORDER_VERSION) { + order *ord; + store->r_str_buf(store, obuf, sizeof(obuf)); ord = parse_order(obuf, u->faction->locale); - if (ord!=NULL) { + if (ord != NULL) { addlist(&u->orders, ord); } } @@ -822,9 +903,12 @@ read_unit(struct storage * store) assert(u->race); while ((sk = (skill_t) store->r_int(store)) != NOSKILL) { int level = store->r_int(store); + int weeks = store->r_int(store); + if (level) { - skill * sv = add_skill(u, sk); + skill *sv = add_skill(u, sk); + sv->level = sv->old = (unsigned char)level; sv->weeks = (unsigned char)weeks; } @@ -832,49 +916,54 @@ read_unit(struct storage * store) read_items(store, &u->items); u->hp = store->r_int(store); if (u->hp < u->number) { - log_error(("Einheit %s hat %u Personen, und %u Trefferpunkte\n", itoa36(u->no), - u->number, u->hp)); - u->hp=u->number; + log_error(("Einheit %s hat %u Personen, und %u Trefferpunkte\n", + itoa36(u->no), u->number, u->hp)); + u->hp = u->number; } a_read(store, &u->attribs, u); return u; } -void -write_unit(struct storage * store, const unit * u) +void write_unit(struct storage *store, const unit * u) { - order * ord; + order *ord; + int i, p = 0; - const race * irace = u_irace(u); + + const race *irace = u_irace(u); + write_unit_reference(u, store); write_faction_reference(u->faction, store); store->w_str(store, (const char *)u->name); - store->w_str(store, u->display?(const char *)u->display:""); + store->w_str(store, u->display ? (const char *)u->display : ""); store->w_int(store, u->number); store->w_int(store, u->age); store->w_tok(store, u->race->_name[0]); - store->w_tok(store, (irace && irace!=u->race)?irace->_name[0]:""); + store->w_tok(store, (irace && irace != u->race) ? irace->_name[0] : ""); write_building_reference(u->building, store); write_ship_reference(u->ship, store); store->w_int(store, u->status); store->w_int(store, u->flags & UFL_SAVEMASK); store->w_brk(store); - for (ord = u->old_orders; ord; ord=ord->next) { - if (++pold_orders; ord; ord = ord->next) { + if (++p < MAXPERSISTENT) { writeorder(store, ord, u->faction->locale); } else { - log_error(("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT)); + log_error(("%s had %d or more persistent orders\n", unitname(u), + MAXPERSISTENT)); break; } } - for (ord = u->orders; ord; ord=ord->next) { - if (u->old_orders && is_repeated(ord)) continue; /* has new defaults */ + for (ord = u->orders; ord; ord = ord->next) { + if (u->old_orders && is_repeated(ord)) + continue; /* has new defaults */ if (is_persistent(ord)) { - if (++pfaction->locale); } else { - log_error(("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT)); + log_error(("%s had %d or more persistent orders\n", unitname(u), + MAXPERSISTENT)); break; } } @@ -885,10 +974,11 @@ write_unit(struct storage * store, const unit * u) assert(u->race); - for (i=0;i!=u->skill_size;++i) { - skill * sv = u->skills+i; - assert(sv->weeks<=sv->level*2+1); - if (sv->level>0) { + for (i = 0; i != u->skill_size; ++i) { + skill *sv = u->skills + i; + + assert(sv->weeks <= sv->level * 2 + 1); + if (sv->level > 0) { store->w_int(store, sv->id); store->w_int(store, sv->level); store->w_int(store, sv->weeks); @@ -900,7 +990,7 @@ write_unit(struct storage * store, const unit * u) store->w_brk(store); if (u->hp == 0) { log_error(("unit %s has 0 hitpoints, adjusting.\n", itoa36(u->no))); - ((unit*)u)->hp = u->number; + ((unit *) u)->hp = u->number; } store->w_int(store, u->hp); store->w_brk(store); @@ -908,31 +998,36 @@ write_unit(struct storage * store, const unit * u) store->w_brk(store); } -static region * -readregion(struct storage * store, int x, int y) +static region *readregion(struct storage *store, int x, int y) { - region * r = findregion(x, y); - const terrain_type * terrain; + region *r = findregion(x, y); + + const terrain_type *terrain; + char token[32]; + unsigned int uid = 0; - if (store->version>=UID_VERSION) { + if (store->version >= UID_VERSION) { uid = store->r_int(store); } - if (r==NULL) { - plane * pl = findplane(x, y); + if (r == NULL) { + plane *pl = findplane(x, y); + r = new_region(x, y, pl, uid); } else { - assert(uid==0 || r->uid==uid); + assert(uid == 0 || r->uid == uid); current_region = r; - while (r->attribs) a_remove(&r->attribs, r->attribs); + while (r->attribs) + a_remove(&r->attribs, r->attribs); if (r->land) { - free(r->land); /* mem leak */ - r->land->demands = 0; /* mem leak */ + free(r->land); /* mem leak */ + r->land->demands = 0; /* mem leak */ } while (r->resources) { - rawmaterial * rm = r->resources; + rawmaterial *rm = r->resources; + r->resources = rm->next; free(rm); } @@ -942,30 +1037,35 @@ readregion(struct storage * store, int x, int y) store->r_str_buf(store, NULL, 0); } else { char info[DISPLAYSIZE]; + store->r_str_buf(store, info, sizeof(info)); region_setinfo(r, info); } - + if (store->version < TERRAIN_VERSION) { int ter = store->r_int(store); - terrain = newterrain((terrain_t)ter); - if (terrain==NULL) { - log_error(("while reading datafile from pre-TERRAIN_VERSION, could not find terrain #%d.\n", ter)); + + terrain = newterrain((terrain_t) ter); + if (terrain == NULL) { + log_error( + ("while reading datafile from pre-TERRAIN_VERSION, could not find terrain #%d.\n", + ter)); terrain = newterrain(T_PLAIN); } } else { char name[64]; + store->r_str_buf(store, name, sizeof(name)); terrain = get_terrain(name); - if (terrain==NULL) { + if (terrain == NULL) { log_error(("Unknown terrain '%s'\n", name)); assert(!"unknown terrain"); } } r->terrain = terrain; - r->flags = (char) store->r_int(store); + r->flags = (char)store->r_int(store); - r->age = (unsigned short) store->r_int(store); + r->age = (unsigned short)store->r_int(store); if (fval(r->terrain, LAND_REGION)) { r->land = calloc(1, sizeof(land_region)); @@ -973,42 +1073,44 @@ readregion(struct storage * store, int x, int y) } if (r->land) { int i; - rawmaterial ** pres = &r->resources; + + rawmaterial **pres = &r->resources; i = store->r_int(store); - if (i<0) { - log_error(("number of trees in %s is %d.\n", - regionname(r, NULL), i)); - i=0; + if (i < 0) { + log_error(("number of trees in %s is %d.\n", regionname(r, NULL), i)); + i = 0; } rsettrees(r, 0, i); - i = store->r_int(store); - if (i<0) { - log_error(("number of young trees in %s is %d.\n", - regionname(r, NULL), i)); - i=0; + i = store->r_int(store); + if (i < 0) { + log_error(("number of young trees in %s is %d.\n", + regionname(r, NULL), i)); + i = 0; } rsettrees(r, 1, i); - i = store->r_int(store); - if (i<0) { - log_error(("number of seeds in %s is %d.\n", - regionname(r, NULL), i)); - i=0; + i = store->r_int(store); + if (i < 0) { + log_error(("number of seeds in %s is %d.\n", regionname(r, NULL), i)); + i = 0; } rsettrees(r, 2, i); - i = store->r_int(store); rsethorses(r, i); - assert(*pres==NULL); + i = store->r_int(store); + rsethorses(r, i); + assert(*pres == NULL); for (;;) { - rawmaterial * res; + rawmaterial *res; + store->r_str_buf(store, token, sizeof(token)); - if (strcmp(token, "end")==0) break; + if (strcmp(token, "end") == 0) + break; res = malloc(sizeof(rawmaterial)); res->type = rmt_find(token); - if (res->type==NULL) { + if (res->type == NULL) { log_error(("invalid resourcetype %s in data.\n", token)); } - assert(res->type!=NULL); + assert(res->type != NULL); res->level = store->r_int(store); res->amount = store->r_int(store); res->flags = 0; @@ -1018,13 +1120,14 @@ readregion(struct storage * store, int x, int y) res->divisor = store->r_int(store); *pres = res; - pres=&res->next; + pres = &res->next; } *pres = NULL; store->r_str_buf(store, token, sizeof(token)); if (strcmp(token, "noherb") != 0) { - const resource_type * rtype = rt_find(token); + const resource_type *rtype = rt_find(token); + assert(rtype && rtype->itype && fval(rtype->itype, ITF_HERB)); rsetherbtype(r, rtype->itype); } else { @@ -1035,26 +1138,29 @@ readregion(struct storage * store, int x, int y) rsetmoney(r, store->r_int(store)); } - assert(r->terrain!=NULL); + assert(r->terrain != NULL); assert(rhorses(r) >= 0); assert(rpeasants(r) >= 0); assert(rmoney(r) >= 0); if (r->land) { for (;;) { - const struct item_type * itype; + const struct item_type *itype; + store->r_str_buf(store, token, sizeof(token)); - if (!strcmp(token, "end")) break; + if (!strcmp(token, "end")) + break; itype = it_find(token); assert(itype->rtype->ltype); r_setdemand(r, itype->rtype->ltype, store->r_int(store)); } - if (store->version>=REGIONITEMS_VERSION) { + if (store->version >= REGIONITEMS_VERSION) { read_items(store, &r->land->items); } - if (store->version>=REGIONOWNER_VERSION) { + if (store->version >= REGIONOWNER_VERSION) { r->land->morale = (short)store->r_int(store); - if (r->land->morale<0) r->land->morale = 0; + if (r->land->morale < 0) + r->land->morale = 0; read_owner(store, &r->land->ownership); } } @@ -1063,8 +1169,7 @@ readregion(struct storage * store, int x, int y) return r; } -void -writeregion(struct storage * store, const region * r) +void writeregion(struct storage *store, const region * r) { store->w_int(store, r->uid); store->w_str(store, region_getinfo(r)); @@ -1074,15 +1179,18 @@ writeregion(struct storage * store, const region * r) store->w_brk(store); if (fval(r->terrain, LAND_REGION)) { const item_type *rht; - struct demand * demand; - rawmaterial * res = r->resources; + + struct demand *demand; + + rawmaterial *res = r->resources; + store->w_str(store, (const char *)r->land->name); - assert(rtrees(r,0)>=0); - assert(rtrees(r,1)>=0); - assert(rtrees(r,2)>=0); - store->w_int(store, rtrees(r,0)); - store->w_int(store, rtrees(r,1)); - store->w_int(store, rtrees(r,2)); + assert(rtrees(r, 0) >= 0); + assert(rtrees(r, 1) >= 0); + assert(rtrees(r, 2) >= 0); + store->w_int(store, rtrees(r, 0)); + store->w_int(store, rtrees(r, 1)); + store->w_int(store, rtrees(r, 2)); store->w_int(store, rhorses(r)); while (res) { @@ -1105,10 +1213,11 @@ writeregion(struct storage * store, const region * r) store->w_int(store, rherbs(r)); store->w_int(store, rpeasants(r)); store->w_int(store, rmoney(r)); - if (r->land) for (demand=r->land->demands; demand; demand=demand->next) { - store->w_tok(store, resourcename(demand->type->itype->rtype, 0)); - store->w_int(store, demand->value); - } + if (r->land) + for (demand = r->land->demands; demand; demand = demand->next) { + store->w_tok(store, resourcename(demand->type->itype->rtype, 0)); + store->w_int(store, demand->value); + } store->w_tok(store, "end"); #if RELEASE_VERSION>=REGIONITEMS_VERSION write_items(store, r->land->items); @@ -1124,11 +1233,11 @@ writeregion(struct storage * store, const region * r) store->w_brk(store); } -static ally ** -addally(const faction * f, ally ** sfp, int aid, int state) +static ally **addally(const faction * f, ally ** sfp, int aid, int state) { - struct faction * af = findfaction(aid); - ally * sf; + struct faction *af = findfaction(aid); + + ally *sf; state &= ~HELP_OBSERVE; #ifndef REGIONOWNERS @@ -1136,18 +1245,21 @@ addally(const faction * f, ally ** sfp, int aid, int state) #endif state &= HelpMask(); - if (state==0) return sfp; + if (state == 0) + return sfp; sf = calloc(1, sizeof(ally)); sf->faction = af; if (!sf->faction) { variant id; + id.i = aid; ur_add(id, &sf->faction, resolve_faction); } sf->status = state & HELP_ALL; - while (*sfp) sfp=&(*sfp)->next; + while (*sfp) + sfp = &(*sfp)->next; *sfp = sf; return &sf->next; } @@ -1156,40 +1268,50 @@ addally(const faction * f, ally ** sfp, int aid, int state) * This function requires no context, can be called in any state. The * faction may not already exist, however. */ -faction * -readfaction(struct storage * store) +faction *readfaction(struct storage * store) { ally **sfp; + int planes; + int i = store->r_id(store); - faction * f = findfaction(i); + + faction *f = findfaction(i); + char email[128]; + char token[32]; - if (f==NULL) { + if (f == NULL) { f = (faction *) calloc(1, sizeof(faction)); f->no = i; } else { - f->allies = NULL; /* mem leak */ - while (f->attribs) a_remove(&f->attribs, f->attribs); + f->allies = NULL; /* mem leak */ + while (f->attribs) + a_remove(&f->attribs, f->attribs); } f->subscription = store->r_int(store); - if (alliances || store->version>=OWNER_2_VERSION) { + if (alliances || store->version >= OWNER_2_VERSION) { int allianceid = store->r_id(store); - if (allianceid>0) f->alliance = findalliance(allianceid); + + if (allianceid > 0) + f->alliance = findalliance(allianceid); if (f->alliance) { - alliance * al = f->alliance; - if (al->flags&ALF_NON_ALLIED) { - assert(!al->members || !"non-allied dummy-alliance has more than one member"); + alliance *al = f->alliance; + + if (al->flags & ALF_NON_ALLIED) { + assert(!al->members + || !"non-allied dummy-alliance has more than one member"); } ql_push(&al->members, f); - } else if (rule_region_owners()){ + } else if (rule_region_owners()) { /* compat fix for non-allied factions */ - alliance * al = makealliance(0, NULL); + alliance *al = makealliance(0, NULL); + setalliance(f, al); } - if (store->version>=OWNER_2_VERSION) { + if (store->version >= OWNER_2_VERSION) { f->alliance_joindate = store->r_int(store); } else { f->alliance_joindate = turn - 10; /* we're guessing something safe here */ @@ -1202,8 +1324,9 @@ readfaction(struct storage * store) log_info((3, " - Lese Partei %s (%s)\n", f->name, factionid(f))); store->r_str_buf(store, email, sizeof(email)); - if (set_email(&f->email, email)!=0) { - log_warning(("Invalid email address for faction %s: %s\n", itoa36(f->no), email)); + if (set_email(&f->email, email) != 0) { + log_warning(("Invalid email address for faction %s: %s\n", itoa36(f->no), + email)); set_email(&f->email, ""); } @@ -1221,65 +1344,75 @@ readfaction(struct storage * store) store->r_str_buf(store, token, sizeof(token)); f->race = rc_find(token); assert(f->race); - f->magiegebiet = (magic_t)store->r_int(store); + f->magiegebiet = (magic_t) store->r_int(store); - if (store->versionversion < FOSS_VERSION) { /* ignore karma */ store->r_int(store); } f->flags = store->r_int(store); - if (f->no==0) { + if (f->no == 0) { f->flags |= FFL_NPC; } a_read(store, &f->attribs, f); - if (store->version>=CLAIM_VERSION) { + if (store->version >= CLAIM_VERSION) { read_items(store, &f->items); } for (;;) { int level; + store->r_tok_buf(store, token, sizeof(token)); - if (strcmp("end", token)==0) break; + if (strcmp("end", token) == 0) + break; level = store->r_int(store); - } + } planes = store->r_int(store); - while(--planes >= 0) { + while (--planes >= 0) { int id = store->r_int(store); + int ux = store->r_int(store); + int uy = store->r_int(store); + set_ursprung(f, id, ux, uy); } f->newbies = 0; - + i = f->options = store->r_int(store); - if ((i & (want(O_REPORT)|want(O_COMPUTER)))==0 && !is_monsters(f)) { + if ((i & (want(O_REPORT) | want(O_COMPUTER))) == 0 && !is_monsters(f)) { /* Kein Report eingestellt, Fehler */ f->options = f->options | want(O_REPORT) | want(O_ZUGVORLAGE); } sfp = &f->allies; - if (store->versionversion < ALLIANCES_VERSION) { int p = store->r_int(store); + while (--p >= 0) { int aid = store->r_id(store); + int state = store->r_int(store); + sfp = addally(f, sfp, aid, state); } } else { for (;;) { int aid = 0; - if (store->versionversion < STORAGE_VERSION) { store->r_tok_buf(store, token, sizeof(token)); - if (strcmp(token, "end")!=0) { + if (strcmp(token, "end") != 0) { aid = atoi36(token); } } else { aid = store->r_id(store); } - if (aid>0) { + if (aid > 0) { int state = store->r_int(store); + sfp = addally(f, sfp, aid, state); } else { break; @@ -1288,27 +1421,27 @@ readfaction(struct storage * store) } read_groups(store, f); f->spellbook = NULL; - if (store->version>=REGIONOWNER_VERSION) { + if (store->version >= REGIONOWNER_VERSION) { read_spells(&f->spellbook, f->magiegebiet, store); } return f; } -void -writefaction(struct storage * store, const faction * f) +void writefaction(struct storage *store, const faction * f) { ally *sf; + ursprung *ur; write_faction_reference(f, store); store->w_int(store, f->subscription); if (f->alliance) { store->w_id(store, f->alliance->id); - if (f->alliance->flags&ALF_NON_ALLIED) { - assert(f==f->alliance->_leader || !"non-allied faction is not leader of its own dummy-alliance."); + if (f->alliance->flags & ALF_NON_ALLIED) { + assert(f == f->alliance->_leader + || !"non-allied faction is not leader of its own dummy-alliance."); } - } - else { + } else { store->w_id(store, 0); } store->w_int(store, f->alliance_joindate); @@ -1325,7 +1458,7 @@ writefaction(struct storage * store, const faction * f) store->w_brk(store); store->w_int(store, f->magiegebiet); - store->w_int(store, f->flags&FFL_SAVEMASK); + store->w_int(store, f->flags & FFL_SAVEMASK); a_write(store, f->attribs, f); store->w_brk(store); write_items(store, f->items); @@ -1333,7 +1466,7 @@ writefaction(struct storage * store, const faction * f) store->w_tok(store, "end"); store->w_brk(store); store->w_int(store, listlen(f->ursprung)); - for (ur = f->ursprung;ur;ur=ur->next) { + for (ur = f->ursprung; ur; ur = ur->next) { store->w_int(store, ur->id); store->w_int(store, ur->x); store->w_int(store, ur->y); @@ -1343,9 +1476,11 @@ writefaction(struct storage * store, const faction * f) store->w_brk(store); for (sf = f->allies; sf; sf = sf->next) { - int no = (sf->faction!=NULL)?sf->faction->no:0; + int no = (sf->faction != NULL) ? sf->faction->no : 0; + int status = alliedfaction(NULL, f, sf->faction, HELP_ALL); - if (status!=0) { + + if (status != 0) { store->w_id(store, no); store->w_int(store, sf->status); } @@ -1356,66 +1491,84 @@ writefaction(struct storage * store, const faction * f) write_spells(f->spellbook, store); } -int -readgame(const char * filename, int mode, int backup) +int readgame(const char *filename, int mode, int backup) { int i, n, p; + faction *f, **fp; + region *r; + building *b, **bp; + ship **shp; + unit *u; + int rmax = maxregions; + char path[MAX_PATH]; + char token[32]; - const struct building_type * bt_lighthouse = bt_find("lighthouse"); - storage my_store = (mode==IO_BINARY)?binary_store:text_store; - storage * store = &my_store; - + + const struct building_type *bt_lighthouse = bt_find("lighthouse"); + + storage my_store = (mode == IO_BINARY) ? binary_store : text_store; + + storage *store = &my_store; + sprintf(path, "%s/%s", datapath(), filename); log_printf("- reading game data from %s\n", filename); - if (backup) create_backup(path); + if (backup) + create_backup(path); store->encoding = enc_gamedata; - if (store->open(store, path, IO_READ)!=0) { + if (store->open(store, path, IO_READ) != 0) { return -1; } enc_gamedata = store->encoding; - assert(store->version>=MIN_VERSION || !"unsupported data format"); - assert(store->version<=RELEASE_VERSION || !"unsupported data format"); + assert(store->version >= MIN_VERSION || !"unsupported data format"); + assert(store->version <= RELEASE_VERSION || !"unsupported data format"); if (store->version >= SAVEXMLNAME_VERSION) { char basefile[1024]; store->r_str_buf(store, basefile, sizeof(basefile)); - if (strcmp(game_name, basefile)!=0) { + if (strcmp(game_name, basefile) != 0) { char buffer[64]; + snprintf(buffer, sizeof(buffer), "%s.xml", game_name); - if (strcmp(basefile, buffer)!=0) { - log_warning(("game mismatch: datafile contains %s, game is %s\n", basefile, game_name)); + if (strcmp(basefile, buffer) != 0) { + log_warning(("game mismatch: datafile contains %s, game is %s\n", + basefile, game_name)); printf("WARNING: any key to continue, Ctrl-C to stop\n"); getchar(); } } } a_read(store, &global.attribs, NULL); + global.data_turn = turn = store->r_int(store); + log_info((1, " - reading turn %d\n", turn)); rng_init(turn); ++global.cookie; - store->r_int(store); /* max_unique_id = */ + + store->r_int(store); /* max_unique_id = */ nextborder = store->r_int(store); /* Planes */ planes = NULL; n = store->r_int(store); - while(--n >= 0) { + while (--n >= 0) { int id = store->r_int(store); + variant fno; + plane *pl = getplanebyid(id); - if (pl==NULL) { + if (pl == NULL) { pl = calloc(1, sizeof(plane)); } else { log_warning(("the plane with id=%d already exists.\n", id)); @@ -1429,21 +1582,24 @@ readgame(const char * filename, int mode, int backup) pl->flags = store->r_int(store); /* read watchers */ - if (store->versionversion < FIX_WATCHERS_VERSION) { char rname[64]; + /* before this version, watcher storage was pretty broken. we are incompatible and don't read them */ for (;;) { store->r_tok_buf(store, rname, sizeof(rname)); - if (strcmp(rname, "end")==0) { - break; /* this is most likely the end of the list */ + if (strcmp(rname, "end") == 0) { + break; /* this is most likely the end of the list */ } else { - log_error(("This datafile contains watchers, but we are unable to read them\n")); + log_error( + ("This datafile contains watchers, but we are unable to read them\n")); } } } else { fno = read_faction_reference(store); while (fno.i) { - watcher * w = (watcher *)malloc(sizeof(watcher)); + watcher *w = (watcher *) malloc(sizeof(watcher)); + ur_add(fno, &w->faction, resolve_faction); w->mode = (unsigned char)store->r_int(store); w->next = pl->watchers; @@ -1456,16 +1612,17 @@ readgame(const char * filename, int mode, int backup) } /* Read factions */ - if (store->version>=ALLIANCES_VERSION) { + if (store->version >= ALLIANCES_VERSION) { read_alliances(store); } n = store->r_int(store); log_info((1, " - Einzulesende Parteien: %d\n", n)); fp = &factions; - while (*fp) fp=&(*fp)->next; + while (*fp) + fp = &(*fp)->next; while (--n >= 0) { - faction * f = readfaction(store); + faction *f = readfaction(store); *fp = f; fp = &f->next; @@ -1474,26 +1631,30 @@ readgame(const char * filename, int mode, int backup) *fp = 0; /* Benutzte Faction-Ids */ - if (store->versionversion < STORAGE_VERSION) { i = store->r_int(store); while (i--) { - store->r_int(store); /* used faction ids. ignore. */ + store->r_int(store); /* used faction ids. ignore. */ } } /* Regionen */ n = store->r_int(store); - assert(n= 0) { unit **up; + int x = store->r_int(store); + int y = store->r_int(store); - if ((n & 0x3FF) == 0) { /* das spart extrem Zeit */ - log_info((2, " - Einzulesende Regionen: %d/%d * %d,%d \r", rmax, n, x, y)); + if ((n & 0x3FF) == 0) { /* das spart extrem Zeit */ + log_info((2, " - Einzulesende Regionen: %d/%d * %d,%d \r", rmax, n, x, + y)); } --rmax; @@ -1513,8 +1674,7 @@ readgame(const char * filename, int mode, int backup) b->name = store->r_str(store); if (lomem) { store->r_str_buf(store, NULL, 0); - } - else { + } else { b->display = store->r_str(store); } b->size = store->r_int(store); @@ -1522,7 +1682,7 @@ readgame(const char * filename, int mode, int backup) b->type = bt_find(token); b->region = r; a_read(store, &b->attribs, b); - if (b->type==bt_lighthouse) { + if (b->type == bt_lighthouse) { r->flags |= RF_LIGHTHOUSE; } } @@ -1532,7 +1692,8 @@ readgame(const char * filename, int mode, int backup) shp = &r->ships; while (--p >= 0) { - ship * sh = (ship *) calloc(1, sizeof(ship)); + ship *sh = (ship *) calloc(1, sizeof(ship)); + sh->region = r; sh->no = store->r_id(store); *shp = sh; @@ -1541,26 +1702,25 @@ readgame(const char * filename, int mode, int backup) sh->name = store->r_str(store); if (lomem) { store->r_str_buf(store, NULL, 0); - } - else { + } else { sh->display = store->r_str(store); } store->r_str_buf(store, token, sizeof(token)); sh->type = st_find(token); - if (sh->type==NULL) { + if (sh->type == NULL) { /* old datafiles */ sh->type = st_find((const char *)locale_string(default_locale, token)); } assert(sh->type || !"ship_type not registered!"); sh->size = store->r_int(store); sh->damage = store->r_int(store); - if (store->version>=FOSS_VERSION) { + if (store->version >= FOSS_VERSION) { sh->flags = store->r_int(store); } /* Attribute rekursiv einlesen */ - sh->coast = (direction_t)store->r_int(store); + sh->coast = (direction_t) store->r_int(store); if (sh->type->flags & SFL_NOCOAST) { sh->coast = NODIRECTION; } @@ -1575,10 +1735,11 @@ readgame(const char * filename, int mode, int backup) up = &r->units; while (--p >= 0) { - unit * u = read_unit(store); - sc_mage * mage; + unit *u = read_unit(store); - assert(u->region==NULL); + sc_mage *mage; + + assert(u->region == NULL); u->region = r; *up = u; up = &u->next; @@ -1586,17 +1747,19 @@ readgame(const char * filename, int mode, int backup) update_interval(u->faction, u->region); mage = get_mage(u); if (mage) { - faction * f = u->faction; + faction *f = u->faction; + int skl = effskill(u, SK_MAGIC); - if (!is_monsters(f) && f->magiegebiet==M_GRAY) { - log_error(("faction %s had magic=gray, fixing (%s)\n", - factionname(f), magic_school[mage->magietyp])); + + if (!is_monsters(f) && f->magiegebiet == M_GRAY) { + log_error(("faction %s had magic=gray, fixing (%s)\n", + factionname(f), magic_school[mage->magietyp])); f->magiegebiet = mage->magietyp; } - if (f->max_spelllevelmax_spelllevel < skl) { f->max_spelllevel = skl; } - if (mage->spellcount<0) { + if (mage->spellcount < 0) { mage->spellcount = 0; updatespelllist(u); } @@ -1613,64 +1776,79 @@ readgame(const char * filename, int mode, int backup) resolve(); log_info((1, "updating area information for lighthouses.\n")); - for (r=regions;r;r=r->next) { + for (r = regions; r; r = r->next) { if (r->flags & RF_LIGHTHOUSE) { - building * b; - for (b=r->buildings;b;b=b->next) update_lighthouse(b); + building *b; + + for (b = r->buildings; b; b = b->next) + update_lighthouse(b); } } log_info((1, "marking factions as alive.\n")); for (f = factions; f; f = f->next) { if (f->flags & FFL_NPC) { f->alive = 1; - if (f->no==0) { - int no=666; - while (findfaction(no)) ++no; + if (f->no == 0) { + int no = 666; + + while (findfaction(no)) + ++no; log_warning(("renum(monsters, %d)\n", no)); renumber_faction(f, no); } } else { for (u = f->units; u; u = u->nextF) { - if (u->number>0) { + if (u->number > 0) { f->alive = 1; break; } } } } - if (loadplane || maxregions>=0) { + if (loadplane || maxregions >= 0) { remove_empty_factions(); } log_info((1, "Done loading turn %d.\n", turn)); return 0; } -static void -clear_monster_orders(void) +static void clear_monster_orders(void) { - faction * f = get_monsters(); + faction *f = get_monsters(); + if (f) { - unit * u; - for (u=f->units;u;u=u->nextF) { + unit *u; + + for (u = f->units; u; u = u->nextF) { free_orders(&u->orders); } } } -int -writegame(const char *filename, int mode) +int writegame(const char *filename, int mode) { char *base; + int n; + faction *f; + region *r; + building *b; + ship *sh; + unit *u; + plane *pl; + char path[MAX_PATH]; - storage my_store = (mode==IO_BINARY)?binary_store:text_store; - storage * store = &my_store; + + storage my_store = (mode == IO_BINARY) ? binary_store : text_store; + + storage *store = &my_store; + store->version = RELEASE_VERSION; clear_monster_orders(); @@ -1683,10 +1861,12 @@ writegame(const char *filename, int mode) #endif store->encoding = enc_gamedata; - if (store->open(store, path, IO_WRITE)!=0) { + if (store->open(store, path, IO_WRITE) != 0) { int err = os_mkdir(datapath(), 0700); - if (err) return err; - if (store->open(store, path, IO_WRITE)!=0) { + + if (err) + return err; + if (store->open(store, path, IO_WRITE) != 0) { return -1; } } @@ -1695,17 +1875,18 @@ writegame(const char *filename, int mode) base = strrchr(game_name, '/'); if (base) { - store->w_str(store, base+1); + store->w_str(store, base + 1); } else { store->w_str(store, game_name); } store->w_brk(store); a_write(store, global.attribs, NULL); + store->w_brk(store); store->w_int(store, turn); - store->w_int(store, 0/*max_unique_id*/); + store->w_int(store, 0 /*max_unique_id */ ); store->w_int(store, nextborder); /* Write planes */ @@ -1713,8 +1894,9 @@ writegame(const char *filename, int mode) store->w_int(store, listlen(planes)); store->w_brk(store); - for(pl = planes; pl; pl=pl->next) { - watcher * w; + for (pl = planes; pl; pl = pl->next) { + watcher *w; + store->w_int(store, pl->id); store->w_str(store, pl->name); store->w_int(store, pl->minx); @@ -1730,7 +1912,7 @@ writegame(const char *filename, int mode) } w = w->next; } - write_faction_reference(NULL, store); /* mark the end of the list */ + write_faction_reference(NULL, store); /* mark the end of the list */ a_write(store, pl->attribs, pl); store->w_brk(store); } @@ -1752,14 +1934,14 @@ writegame(const char *filename, int mode) /* Write regions */ - n=listlen(regions); + n = listlen(regions); store->w_int(store, n); store->w_brk(store); log_info((1, " - Schreibe Regionen: %d \r", n)); for (r = regions; r; r = r->next, --n) { /* plus leerzeile */ - if ((n%1024)==0) { /* das spart extrem Zeit */ + if ((n % 1024) == 0) { /* das spart extrem Zeit */ log_info((2, " - Schreibe Regionen: %d \r", n)); fflush(stdout); } @@ -1773,7 +1955,7 @@ writegame(const char *filename, int mode) for (b = r->buildings; b; b = b->next) { write_building_reference(b, store); store->w_str(store, b->name); - store->w_str(store, b->display?b->display:""); + store->w_str(store, b->display ? b->display : ""); store->w_int(store, b->size); store->w_tok(store, b->type->_name); store->w_brk(store); @@ -1787,12 +1969,12 @@ writegame(const char *filename, int mode) assert(sh->region == r); write_ship_reference(sh, store); store->w_str(store, (const char *)sh->name); - store->w_str(store, sh->display?(const char *)sh->display:""); + store->w_str(store, sh->display ? (const char *)sh->display : ""); store->w_tok(store, sh->type->name[0]); store->w_int(store, sh->size); store->w_int(store, sh->damage); store->w_int(store, sh->flags & SFL_SAVEMASK); - assert((sh->type->flags & SFL_NOCOAST)==0 || sh->coast == NODIRECTION); + assert((sh->type->flags & SFL_NOCOAST) == 0 || sh->coast == NODIRECTION); store->w_int(store, sh->coast); store->w_brk(store); a_write(store, sh->attribs, sh); @@ -1808,31 +1990,28 @@ writegame(const char *filename, int mode) store->w_brk(store); write_borders(store); store->w_brk(store); - + store->close(store); log_info((1, "\nOk.\n")); return 0; } -int -a_readint(attrib * a, void * owner, struct storage * store) +int a_readint(attrib * a, void *owner, struct storage *store) { /* assert(sizeof(int)==sizeof(a->data)); */ a->data.i = store->r_int(store); return AT_READ_OK; } -void -a_writeint(const attrib * a, const void * owner, struct storage * store) +void a_writeint(const attrib * a, const void *owner, struct storage *store) { store->w_int(store, a->data.i); } -int -a_readshorts(attrib * a, void * owner, struct storage * store) +int a_readshorts(attrib * a, void *owner, struct storage *store) { - if (store->versionversion < ATTRIBREAD_VERSION) { return a_readint(a, store, owner); } a->data.sa[0] = (short)store->r_int(store); @@ -1840,66 +2019,59 @@ a_readshorts(attrib * a, void * owner, struct storage * store) return AT_READ_OK; } -void -a_writeshorts(const attrib * a, const void * owner, struct storage * store) +void a_writeshorts(const attrib * a, const void *owner, struct storage *store) { store->w_int(store, a->data.sa[0]); store->w_int(store, a->data.sa[1]); } -int -a_readchars(attrib * a, void * owner, struct storage * store) +int a_readchars(attrib * a, void *owner, struct storage *store) { int i; - if (store->versionversion < ATTRIBREAD_VERSION) { return a_readint(a, store, owner); } - for (i=0;i!=4;++i) { + for (i = 0; i != 4; ++i) { a->data.ca[i] = (char)store->r_int(store); } return AT_READ_OK; } -void -a_writechars(const attrib * a, const void * owner, struct storage * store) +void a_writechars(const attrib * a, const void *owner, struct storage *store) { int i; - - for (i=0;i!=4;++i) { + + for (i = 0; i != 4; ++i) { store->w_int(store, a->data.ca[i]); } } -int -a_readvoid(attrib * a, void * owner, struct storage * store) +int a_readvoid(attrib * a, void *owner, struct storage *store) { - if (store->versionversion < ATTRIBREAD_VERSION) { return a_readint(a, store, owner); } return AT_READ_OK; } -void -a_writevoid(const attrib * a, const void * owner, struct storage * store) +void a_writevoid(const attrib * a, const void *owner, struct storage *store) { } -int -a_readstring(attrib * a, void * owner, struct storage * store) +int a_readstring(attrib * a, void *owner, struct storage *store) { a->data.v = store->r_str(store); return AT_READ_OK; } -void -a_writestring(const attrib * a, const void * owner, struct storage * store) +void a_writestring(const attrib * a, const void *owner, struct storage *store) { assert(a->data.v); store->w_str(store, (const char *)a->data.v); } -void -a_finalizestring(attrib * a) +void a_finalizestring(attrib * a) { free(a->data.v); } diff --git a/src/kernel/save.h b/src/kernel/save.h index 4f10e7090..5d3770b26 100644 --- a/src/kernel/save.h +++ b/src/kernel/save.h @@ -22,50 +22,55 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -double version(void); + double version(void); #define MAX_INPUT_SIZE DISPLAYSIZE*2 /* Nach MAX_INPUT_SIZE brechen wir das Einlesen der Zeile ab und nehmen an, * dass hier ein Fehler (fehlende ") vorliegt */ -FILE * cfopen(const char *filename, const char *mode); -int readorders(const char *filename); -int creategame(void); -extern int readgame(const char * filename, int mode, int backup); -int writegame(const char *filename, int mode); + FILE *cfopen(const char *filename, const char *mode); + int readorders(const char *filename); + int creategame(void); + extern int readgame(const char *filename, int mode, int backup); + int writegame(const char *filename, int mode); -extern void rsf(FILE * F, char *s, size_t len); + extern void rsf(FILE * F, char *s, size_t len); /* Versionsänderungen: */ -extern int data_version; -extern const char *game_name; -extern int enc_gamedata; + extern int data_version; + extern const char *game_name; + extern int enc_gamedata; -extern void init_locales(void); -extern int current_turn(void); + extern void init_locales(void); + extern int current_turn(void); -extern void read_items(struct storage * store, struct item **it); -extern void write_items(struct storage * store, struct item *it); + extern void read_items(struct storage *store, struct item **it); + extern void write_items(struct storage *store, struct item *it); -extern void write_unit(struct storage * store, const struct unit * u); -extern struct unit * read_unit(struct storage * store); + extern void write_unit(struct storage *store, const struct unit *u); + extern struct unit *read_unit(struct storage *store); -extern int a_readint(struct attrib * a, void * owner, struct storage * store); -extern void a_writeint(const struct attrib * a, const void * owner, struct storage * store); -extern int a_readshorts(struct attrib * a, void * owner, struct storage * store); -extern void a_writeshorts(const struct attrib * a, const void * owner, struct storage * store); -extern int a_readchars(struct attrib * a, void * owner, struct storage * store); -extern void a_writechars(const struct attrib * a, const void * owner, struct storage * store); -extern int a_readvoid(struct attrib * a, void * owner, struct storage * store); -extern void a_writevoid(const struct attrib * a, const void * owner, struct storage * store); -extern int a_readstring(struct attrib * a, void * owner, struct storage * store); -extern void a_writestring(const struct attrib * a, const void * owner, struct storage * store); -extern void a_finalizestring(struct attrib * a); + extern int a_readint(struct attrib *a, void *owner, struct storage *store); + extern void a_writeint(const struct attrib *a, const void *owner, + struct storage *store); + extern int a_readshorts(struct attrib *a, void *owner, struct storage *store); + extern void a_writeshorts(const struct attrib *a, const void *owner, + struct storage *store); + extern int a_readchars(struct attrib *a, void *owner, struct storage *store); + extern void a_writechars(const struct attrib *a, const void *owner, + struct storage *store); + extern int a_readvoid(struct attrib *a, void *owner, struct storage *store); + extern void a_writevoid(const struct attrib *a, const void *owner, + struct storage *store); + extern int a_readstring(struct attrib *a, void *owner, struct storage *store); + extern void a_writestring(const struct attrib *a, const void *owner, + struct storage *store); + extern void a_finalizestring(struct attrib *a); -extern int freadstr(FILE * F, int encoding, char * str, size_t size); -extern int fwritestr(FILE * F, const char * str); + extern int freadstr(FILE * F, int encoding, char *str, size_t size); + extern int fwritestr(FILE * F, const char *str); -extern void create_backup(char *file); + extern void create_backup(char *file); #ifdef __cplusplus } diff --git a/src/kernel/ship.c b/src/kernel/ship.c index cbb755d3a..85d489dc2 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -48,63 +48,70 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. quicklist *shiptypes = NULL; -static local_names * snames; +static local_names *snames; -const ship_type * -findshiptype(const char * name, const struct locale * lang) +const ship_type *findshiptype(const char *name, const struct locale *lang) { - local_names * sn = snames; + local_names *sn = snames; + variant var; while (sn) { - if (sn->lang==lang) break; - sn=sn->next; + if (sn->lang == lang) + break; + sn = sn->next; } if (!sn) { - quicklist * ql; + quicklist *ql; + int qi; - sn = (local_names *)calloc(sizeof(local_names), 1); + sn = (local_names *) calloc(sizeof(local_names), 1); sn->next = snames; sn->lang = lang; - for (qi=0,ql=shiptypes;ql;ql_advance(&ql, &qi, 1)) { - ship_type * stype = (ship_type *)ql_get(ql, qi); + for (qi = 0, ql = shiptypes; ql; ql_advance(&ql, &qi, 1)) { + ship_type *stype = (ship_type *) ql_get(ql, qi); + variant var; - const char * n = locale_string(lang, stype->name[0]); - var.v = (void*)stype; + + const char *n = locale_string(lang, stype->name[0]); + + var.v = (void *)stype; addtoken(&sn->names, n, var); } snames = sn; } - if (findtoken(&sn->names, name, &var)==E_TOK_NOMATCH) return NULL; - return (const ship_type*)var.v; + if (findtoken(&sn->names, name, &var) == E_TOK_NOMATCH) + return NULL; + return (const ship_type *)var.v; } -const ship_type * -st_find(const char* name) +const ship_type *st_find(const char *name) { - quicklist * ql; + quicklist *ql; + int qi; - - for (qi=0,ql=shiptypes;ql;ql_advance(&ql, &qi, 1)) { - ship_type * stype = (ship_type *)ql_get(ql, qi); - if (strcmp(stype->name[0], name)==0) { + + for (qi = 0, ql = shiptypes; ql; ql_advance(&ql, &qi, 1)) { + ship_type *stype = (ship_type *) ql_get(ql, qi); + + if (strcmp(stype->name[0], name) == 0) { return stype; } } return NULL; } -void -st_register(const ship_type * type) { +void st_register(const ship_type * type) +{ ql_push(&shiptypes, (void *)type); } #define SMAXHASH 7919 ship *shiphash[SMAXHASH]; -void -shash(ship * s) + +void shash(ship * s) { ship *old = shiphash[s->no % SMAXHASH]; @@ -112,8 +119,7 @@ shash(ship * s) s->nexthash = old; } -void -sunhash(ship * s) +void sunhash(ship * s) { ship **show; @@ -128,8 +134,7 @@ sunhash(ship * s) } } -static ship * -sfindhash(int i) +static ship *sfindhash(int i) { ship *old; @@ -139,16 +144,14 @@ sfindhash(int i) return 0; } -struct ship * -findship(int i) +struct ship *findship(int i) { return sfindhash(i); } -struct ship * -findshipr(const region *r, int n) +struct ship *findshipr(const region * r, int n) { - ship * sh; + ship *sh; for (sh = r->ships; sh; sh = sh->next) { if (sh->no == n) { @@ -159,31 +162,31 @@ findshipr(const region *r, int n) return 0; } -void -damage_ship(ship * sh, double percent) +void damage_ship(ship * sh, double percent) { - double damage = DAMAGE_SCALE * sh->type->damage * percent * sh->size + sh->damage; + double damage = + DAMAGE_SCALE * sh->type->damage * percent * sh->size + sh->damage; sh->damage = (int)damage; } -unit * -captain(ship *sh) +unit *captain(ship * sh) { unit *u; - for(u = sh->region->units; u; u = u->next) - if(u->ship == sh && fval(u, UFL_OWNER)) return u; + for (u = sh->region->units; u; u = u->next) + if (u->ship == sh && fval(u, UFL_OWNER)) + return u; return NULL; } /* Alte Schiffstypen: */ -static ship * deleted_ships; +static ship *deleted_ships; -ship * -new_ship(const ship_type * stype, const struct locale * lang, region * r) +ship *new_ship(const ship_type * stype, const struct locale *lang, region * r) { static char buffer[7 + IDSIZE + 1]; + ship *sh = (ship *) calloc(1, sizeof(ship)); assert(stype); @@ -200,11 +203,11 @@ new_ship(const ship_type * stype, const struct locale * lang, region * r) return sh; } -void -remove_ship(ship ** slist, ship * sh) +void remove_ship(ship ** slist, ship * sh) { - region * r = sh->region; - unit * u = r->units; + region *r = sh->region; + + unit *u = r->units; handle_event(sh->attribs, "destroy", sh); while (u) { @@ -214,7 +217,8 @@ remove_ship(ship ** slist, ship * sh) u = u->next; } sunhash(sh); - while (*slist && *slist!=sh) slist = &(*slist)->next; + while (*slist && *slist != sh) + slist = &(*slist)->next; assert(*slist); *slist = sh->next; sh->next = deleted_ships; @@ -222,51 +226,53 @@ remove_ship(ship ** slist, ship * sh) sh->region = NULL; } -void -free_ship(ship * s) +void free_ship(ship * s) { - while (s->attribs) a_remove(&s->attribs, s->attribs); + while (s->attribs) + a_remove(&s->attribs, s->attribs); free(s->name); free(s->display); free(s); } -void -free_ships(void) +void free_ships(void) { while (deleted_ships) { - ship * s = deleted_ships; + ship *s = deleted_ships; + deleted_ships = s->next; } } -const char * -write_shipname(const ship * sh, char * ibuf, size_t size) +const char *write_shipname(const ship * sh, char *ibuf, size_t size) { snprintf(ibuf, size, "%s (%s)", sh->name, itoa36(sh->no)); - ibuf[size-1] = 0; + ibuf[size - 1] = 0; return ibuf; } -const char * -shipname(const ship * sh) +const char *shipname(const ship * sh) { typedef char name[OBJECTIDSIZE + 1]; + static name idbuf[8]; + static int nextbuf = 0; + char *ibuf = idbuf[(++nextbuf) % 8]; + return write_shipname(sh, ibuf, sizeof(name)); } -int -shipcapacity (const ship * sh) +int shipcapacity(const ship * sh) { int i = sh->type->cargo; /* sonst ist construction:: size nicht ship_type::maxsize */ - assert(!sh->type->construction || sh->type->construction->improvement==NULL); + assert(!sh->type->construction + || sh->type->construction->improvement == NULL); - if (sh->type->construction && sh->size!=sh->type->construction->maxsize) + if (sh->type->construction && sh->size != sh->type->construction->maxsize) return 0; #ifdef SHIPDAMAGE @@ -277,10 +283,9 @@ shipcapacity (const ship * sh) return i; } -void -getshipweight(const ship * sh, int *sweight, int *scabins) +void getshipweight(const ship * sh, int *sweight, int *scabins) { - unit * u; + unit *u; *sweight = 0; *scabins = 0; @@ -290,6 +295,7 @@ getshipweight(const ship * sh, int *sweight, int *scabins) *sweight += weight(u); if (sh->type->cabins) { int pweight = u->number * u->race->weight; + /* weight goes into number of cabins, not cargo */ *scabins += pweight; *sweight -= pweight; @@ -298,15 +304,15 @@ getshipweight(const ship * sh, int *sweight, int *scabins) } } -unit * -shipowner(const ship * sh) +unit *shipowner(const ship * sh) { unit *u; + unit *first = NULL; - const region * r = sh->region; + const region *r = sh->region; - /* Prüfen ob Eigentümer am leben. */ + /* Prüfen ob Eigentümer am leben. */ for (u = r->units; u; u = u->next) { if (u->ship == sh) { if (!first && u->number > 0) @@ -326,22 +332,21 @@ shipowner(const ship * sh) return first; } -void -write_ship_reference(const struct ship * sh, struct storage * store) +void write_ship_reference(const struct ship *sh, struct storage *store) { - store->w_id(store, (sh && sh->region)?sh->no:0); + store->w_id(store, (sh && sh->region) ? sh->no : 0); } -void -ship_setname(ship * self, const char * name) +void ship_setname(ship * self, const char *name) { free(self->name); - if (name) self->name = strdup(name); - else self->name = NULL; + if (name) + self->name = strdup(name); + else + self->name = NULL; } -const char * -ship_getname(const ship * self) +const char *ship_getname(const ship * self) { return self->name; } diff --git a/src/kernel/ship.h b/src/kernel/ship.h index 411225bf8..12e501d80 100644 --- a/src/kernel/ship.h +++ b/src/kernel/ship.h @@ -24,97 +24,101 @@ extern "C" { #include "types.h" -#define DAMAGE_SCALE 100 /* multiplier for sh->damage */ +#define DAMAGE_SCALE 100 /* multiplier for sh->damage */ /* ship_type::flags */ #define SFL_OPENSEA 0x01 #define SFL_FLY 0x02 #define SFL_NOCOAST 0x04 -typedef struct ship_type { - const char * name[2]; + typedef struct ship_type { + const char *name[2]; - int range; /* range in regions */ - int flags; /* flags */ - int combat; /* modifier for combat */ + int range; /* range in regions */ + int flags; /* flags */ + int combat; /* modifier for combat */ - double storm; /* multiplier for chance to drift in storm */ - double damage; /* multiplier for damage taken by the ship */ + double storm; /* multiplier for chance to drift in storm */ + double damage; /* multiplier for damage taken by the ship */ - int cabins; /* max. cabins (weight) */ - int cargo; /* max. cargo (weight) */ + int cabins; /* max. cabins (weight) */ + int cargo; /* max. cargo (weight) */ - int cptskill; /* min. skill of captain */ - int minskill; /* min. skill to sail this (crew) */ - int sumskill; /* min. sum of crew+captain */ + int cptskill; /* min. skill of captain */ + int minskill; /* min. skill to sail this (crew) */ + int sumskill; /* min. sum of crew+captain */ - int fishing; /* weekly income from fishing */ + int fishing; /* weekly income from fishing */ - int at_bonus; /* Verändert den Angriffsskill (default: 0)*/ - int df_bonus; /* Verändert den Verteidigungskill (default: 0)*/ - float tac_bonus; + int at_bonus; /* Verändert den Angriffsskill (default: 0) */ + int df_bonus; /* Verändert den Verteidigungskill (default: 0) */ + float tac_bonus; - const struct terrain_type ** coasts; /* coast that this ship can land on */ + const struct terrain_type **coasts; /* coast that this ship can land on */ - struct construction * construction; /* how to build a ship */ -} ship_type; + struct construction *construction; /* how to build a ship */ + } ship_type; -extern struct quicklist *shiptypes; + extern struct quicklist *shiptypes; /* Alte Schiffstypen: */ -extern const ship_type * st_find(const char* name); -extern void st_register(const ship_type * type); + extern const ship_type *st_find(const char *name); + extern void st_register(const ship_type * type); #define NOSHIP NULL #define SF_DRIFTED 1<<0 #define SF_MOVED 1<<1 -#define SF_DAMAGED 1<<2 /* for use in combat */ -#define SF_SELECT 1<<3 /* previously FL_DH */ -#define SF_FISHING 1<<4 /* was on an ocean, can fish */ -#define SF_FLYING 1<<5 /* the ship can fly */ +#define SF_DAMAGED 1<<2 /* for use in combat */ +#define SF_SELECT 1<<3 /* previously FL_DH */ +#define SF_FISHING 1<<4 /* was on an ocean, can fish */ +#define SF_FLYING 1<<5 /* the ship can fly */ #define SFL_SAVEMASK (SF_FLYING) #define INCOME_FISHING 10 -typedef struct ship { - struct ship *next; - struct ship *nexthash; - int no; - struct region *region; - char *name; - char *display; - struct attrib * attribs; - int size; - int damage; /* damage in 100th of a point of size */ - unsigned int flags; - const struct ship_type * type; - direction_t coast; -} ship; + typedef struct ship { + struct ship *next; + struct ship *nexthash; + int no; + struct region *region; + char *name; + char *display; + struct attrib *attribs; + int size; + int damage; /* damage in 100th of a point of size */ + unsigned int flags; + const struct ship_type *type; + direction_t coast; + } ship; -extern void damage_ship(ship *sh, double percent); -extern struct unit *captain(ship *sh); -extern struct unit *shipowner(const struct ship * sh); -extern const char * shipname(const struct ship * self); -extern int shipcapacity(const struct ship * sh); -extern void getshipweight(const struct ship * sh, int *weight, int *cabins); + extern void damage_ship(ship * sh, double percent); + extern struct unit *captain(ship * sh); + extern struct unit *shipowner(const struct ship *sh); + extern const char *shipname(const struct ship *self); + extern int shipcapacity(const struct ship *sh); + extern void getshipweight(const struct ship *sh, int *weight, int *cabins); -extern ship *new_ship(const struct ship_type * stype, const struct locale * lang, struct region * r); -extern const char *write_shipname(const struct ship * sh, char * buffer, size_t size); -extern struct ship *findship(int n); -extern struct ship *findshipr(const struct region *r, int n); + extern ship *new_ship(const struct ship_type *stype, + const struct locale *lang, struct region *r); + extern const char *write_shipname(const struct ship *sh, char *buffer, + size_t size); + extern struct ship *findship(int n); + extern struct ship *findshipr(const struct region *r, int n); -extern const struct ship_type * findshiptype(const char *s, const struct locale * lang); + extern const struct ship_type *findshiptype(const char *s, + const struct locale *lang); -extern void write_ship_reference(const struct ship * sh, struct storage * store); + extern void write_ship_reference(const struct ship *sh, + struct storage *store); -extern void remove_ship(struct ship ** slist, struct ship * s); -extern void free_ship(struct ship * s); -extern void free_ships(void); + extern void remove_ship(struct ship **slist, struct ship *s); + extern void free_ship(struct ship *s); + extern void free_ships(void); -extern const char * ship_getname(const struct ship * self); -extern void ship_setname(struct ship * self, const char * name); + extern const char *ship_getname(const struct ship *self); + extern void ship_setname(struct ship *self, const char *name); #ifdef __cplusplus } diff --git a/src/kernel/skill.c b/src/kernel/skill.c index ebc225d27..c051f8b16 100644 --- a/src/kernel/skill.c +++ b/src/kernel/skill.c @@ -41,43 +41,41 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -const char *skillnames[MAXSKILLS] = -{ - "alchemy", - "crossbow", - "mining", - "bow", - "building", - "trade", - "forestry", - "catapult", - "herbalism", - "magic", - "training", - "riding", - "armorer", - "shipcraft", - "melee", - "sailing", - "polearm", - "espionage", - "quarrying", - "roadwork", - "tactics", - "stealth", - "entertainment", - "weaponsmithing", - "cartmaking", - "perception", - "taxation", - "stamina", - "unarmed" +const char *skillnames[MAXSKILLS] = { + "alchemy", + "crossbow", + "mining", + "bow", + "building", + "trade", + "forestry", + "catapult", + "herbalism", + "magic", + "training", + "riding", + "armorer", + "shipcraft", + "melee", + "sailing", + "polearm", + "espionage", + "quarrying", + "roadwork", + "tactics", + "stealth", + "entertainment", + "weaponsmithing", + "cartmaking", + "perception", + "taxation", + "stamina", + "unarmed" }; boolean skill_enabled[MAXSKILLS]; -const char * -skillname(skill_t sk, const struct locale * lang) +const char *skillname(skill_t sk, const struct locale *lang) { if (skill_enabled[sk]) { return locale_string(lang, mkname("skill", skillnames[sk])); @@ -85,12 +83,12 @@ skillname(skill_t sk, const struct locale * lang) return NULL; } -void -enable_skill(const char * skname, boolean value) +void enable_skill(const char *skname, boolean value) { skill_t sk; - for (sk=0;sk!=MAXSKILLS;++sk) { - if (strcmp(skillnames[sk], skname)==0) { + + for (sk = 0; sk != MAXSKILLS; ++sk) { + if (strcmp(skillnames[sk], skname) == 0) { skill_enabled[sk] = value; return; } @@ -98,226 +96,248 @@ enable_skill(const char * skname, boolean value) log_error(("Trying to set unknown skill %s to %u", skname, value)); } -skill_t -sk_find(const char * name) +skill_t sk_find(const char *name) { skill_t i; - if (name==NULL) return NOSKILL; - if (strncmp(name, "sk_", 3)==0) name+=3; - for (i=0;i!=MAXSKILLS;++i) { + + if (name == NULL) + return NOSKILL; + if (strncmp(name, "sk_", 3) == 0) + name += 3; + for (i = 0; i != MAXSKILLS; ++i) { if (skill_enabled[i]) { - if (strcmp(name, skillnames[i])==0) return i; + if (strcmp(name, skillnames[i]) == 0) + return i; } } return NOSKILL; } /** skillmod attribut **/ -static void -init_skillmod(attrib * a) { - a->data.v = calloc(sizeof(skillmod_data), 1); +static void init_skillmod(attrib * a) +{ + a->data.v = calloc(sizeof(skillmod_data), 1); } -static void -finalize_skillmod(attrib * a) +static void finalize_skillmod(attrib * a) { - free(a->data.v); + free(a->data.v); } /** temporary skill modification (NOT SAVED!). */ attrib_type at_skillmod = { - "skillmod", - init_skillmod, - finalize_skillmod, - NULL, - NULL, /* can't write function pointers */ - NULL, /* can't read function pointers */ - ATF_PRESERVE + "skillmod", + init_skillmod, + finalize_skillmod, + NULL, + NULL, /* can't write function pointers */ + NULL, /* can't read function pointers */ + ATF_PRESERVE }; -attrib * -make_skillmod(skill_t sk, unsigned int flags, skillmod_fun special, double multiplier, int bonus) +attrib *make_skillmod(skill_t sk, unsigned int flags, skillmod_fun special, + double multiplier, int bonus) { - attrib * a = a_new(&at_skillmod); - skillmod_data * smd = (skillmod_data*)a->data.v; + attrib *a = a_new(&at_skillmod); - smd->skill=sk; - smd->special=special; - smd->bonus=bonus; - smd->multiplier=multiplier; - smd->flags=flags; + skillmod_data *smd = (skillmod_data *) a->data.v; - return a; + smd->skill = sk; + smd->special = special; + smd->bonus = bonus; + smd->multiplier = multiplier; + smd->flags = flags; + + return a; } int -skillmod(const attrib * a, const unit * u, const region * r, skill_t sk, int value, int flags) +skillmod(const attrib * a, const unit * u, const region * r, skill_t sk, + int value, int flags) { - for (a = a_find((attrib*)a, &at_skillmod); a && a->type==&at_skillmod; a=a->next) { - skillmod_data * smd = (skillmod_data *)a->data.v; - if (smd->skill!=NOSKILL && smd->skill!=sk) continue; - if (flags!=SMF_ALWAYS && (smd->flags & flags) == 0) continue; - if (smd->special) { - value = smd->special(u, r, sk, value); - if (value<0) return value; /* pass errors back to caller */ - } - if (smd->multiplier) value = (int)(value*smd->multiplier); - value += smd->bonus; - } - return value; + for (a = a_find((attrib *) a, &at_skillmod); a && a->type == &at_skillmod; + a = a->next) { + skillmod_data *smd = (skillmod_data *) a->data.v; + + if (smd->skill != NOSKILL && smd->skill != sk) + continue; + if (flags != SMF_ALWAYS && (smd->flags & flags) == 0) + continue; + if (smd->special) { + value = smd->special(u, r, sk, value); + if (value < 0) + return value; /* pass errors back to caller */ + } + if (smd->multiplier) + value = (int)(value * smd->multiplier); + value += smd->bonus; + } + return value; } -int -skill_mod(const race * rc, skill_t sk, const struct terrain_type * terrain) +int skill_mod(const race * rc, skill_t sk, const struct terrain_type *terrain) { - int result = 0; + int result = 0; - result = rc->bonus[sk]; + result = rc->bonus[sk]; if (rc == new_race[RC_DWARF]) { - if (sk==SK_TACTICS) { + if (sk == SK_TACTICS) { if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION)) ++result; } + } else if (rc == new_race[RC_INSECT]) { + if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION)) + --result; + else if (terrain == newterrain(T_DESERT) || terrain == newterrain(T_SWAMP)) + ++result; } - else if (rc == new_race[RC_INSECT]) { - if (terrain == newterrain(T_MOUNTAIN) || fval(terrain, ARCTIC_REGION)) - --result; - else if (terrain == newterrain(T_DESERT) || terrain == newterrain(T_SWAMP)) - ++result; - } - - return result; + + return result; } #define RCMODMAXHASH 31 #ifdef FASTER_SKILLMOD static struct skillmods { - struct skillmods * next; - const struct race * race; - struct modifiers { - int value[MAXSKILLS]; - } mod[MAXTERRAINS]; -} * modhash[RCMODMAXHASH]; + struct skillmods *next; + const struct race *race; + struct modifiers { + int value[MAXSKILLS]; + } mod[MAXTERRAINS]; +} *modhash[RCMODMAXHASH]; -static struct skillmods * -init_skills(const race * rc) +static struct skillmods *init_skills(const race * rc) { - terrain_t t; - struct skillmods *mods = (struct skillmods*)calloc(1, sizeof(struct skillmods)); - mods->race = rc; + terrain_t t; - for (t=0;t!=MAXTERRAINS;++t) { - skill_t sk; - for (sk=0;sk!=MAXSKILLS;++sk) { - mods->mod[t].value[sk] = skill_mod(rc, sk, newterrain(t)); - } - } - return mods; + struct skillmods *mods = + (struct skillmods *)calloc(1, sizeof(struct skillmods)); + mods->race = rc; + + for (t = 0; t != MAXTERRAINS; ++t) { + skill_t sk; + + for (sk = 0; sk != MAXSKILLS; ++sk) { + mods->mod[t].value[sk] = skill_mod(rc, sk, newterrain(t)); + } + } + return mods; } #endif -int -rc_skillmod(const struct race * rc, const region *r, skill_t sk) +int rc_skillmod(const struct race *rc, const region * r, skill_t sk) { int mods; - if (!skill_enabled[sk]) return 0; + if (!skill_enabled[sk]) + return 0; #ifdef FASTER_SKILLMOD unsigned int index = hashstring(rc->_name[0]) % RCMODMAXHASH; + struct skillmods **imods = &modhash[index]; - while (*imods && (*imods)->race!=rc) imods = &(*imods)->next; - if (*imods==NULL) { + + while (*imods && (*imods)->race != rc) + imods = &(*imods)->next; + if (*imods == NULL) { *imods = init_skills(rc); } mods = (*imods)->mod[rterrain(r)].value[sk]; #else mods = skill_mod(rc, sk, r->terrain); #endif - if (rc == new_race[RC_ELF] && r_isforest(r)) switch (sk) { - case SK_PERCEPTION: - ++mods; - break; - case SK_STEALTH: - if (r_isforest(r)) ++mods; - break; - case SK_TACTICS: - if (r_isforest(r)) mods += 2; - break; - } + if (rc == new_race[RC_ELF] && r_isforest(r)) + switch (sk) { + case SK_PERCEPTION: + ++mods; + break; + case SK_STEALTH: + if (r_isforest(r)) + ++mods; + break; + case SK_TACTICS: + if (r_isforest(r)) + mods += 2; + break; + } return mods; } -int -level_days(int level) +int level_days(int level) { - return 30 * ((level+1) * level / 2); + return 30 * ((level + 1) * level / 2); } -int -level(int days) +int level(int days) { - int i; - static int ldays[64]; - static boolean init = false; - if (!init) { - init = true; - for (i=0;i!=64;++i) ldays[i] = level_days(i+1); - } - for (i=0;i!=64;++i) if (ldays[i]>days) return i; - return i; + int i; + + static int ldays[64]; + + static boolean init = false; + + if (!init) { + init = true; + for (i = 0; i != 64; ++i) + ldays[i] = level_days(i + 1); + } + for (i = 0; i != 64; ++i) + if (ldays[i] > days) + return i; + return i; } -void -sk_set(skill * sv, int level) +void sk_set(skill * sv, int level) { - assert(level!=0); - sv->weeks = (unsigned char)skill_weeks(level); - sv->level = (unsigned char)level; + assert(level != 0); + sv->weeks = (unsigned char)skill_weeks(level); + sv->level = (unsigned char)level; } -static int -rule_random_progress(void) { +static int rule_random_progress(void) +{ return get_param_int(global.parameters, "study.random_progress", 1); } -int -skill_weeks(int level) +int skill_weeks(int level) /* how many weeks must i study to get from level to level+1 */ { if (rule_random_progress()) { - int coins = 2*level; + int coins = 2 * level; + int heads = 1; + while (coins--) { heads += rng_int() % 2; } return heads; } - return level+1; + return level + 1; } -void -reduce_skill(unit * u, skill * sv, unsigned int weeks) +void reduce_skill(unit * u, skill * sv, unsigned int weeks) { - sv->weeks+=weeks; - while (sv->level>0 && sv->level*2+1weeks) { - sv->weeks -= sv->level; - --sv->level; - } - if (sv->level==0) { - /* reroll */ - sv->weeks = (unsigned char)skill_weeks(sv->level); - } + sv->weeks += weeks; + while (sv->level > 0 && sv->level * 2 + 1 < sv->weeks) { + sv->weeks -= sv->level; + --sv->level; + } + if (sv->level == 0) { + /* reroll */ + sv->weeks = (unsigned char)skill_weeks(sv->level); + } } -int -skill_compare(const skill * sk, const skill * sc) +int skill_compare(const skill * sk, const skill * sc) { - if (sk->level > sc->level) return 1; - if (sk->level < sc->level) return -1; - if (sk->weeks < sc->weeks) return 1; - if (sk->weeks > sc->weeks) return -1; - return 0; + if (sk->level > sc->level) + return 1; + if (sk->level < sc->level) + return -1; + if (sk->weeks < sc->weeks) + return 1; + if (sk->weeks > sc->weeks) + return -1; + return 0; } diff --git a/src/kernel/skill.h b/src/kernel/skill.h index 32185ab19..6cf79debf 100644 --- a/src/kernel/skill.h +++ b/src/kernel/skill.h @@ -17,46 +17,50 @@ extern "C" { #endif /* skillmod_data::flags -- wann gilt der modifier? */ -#define SMF_ALWAYS (1<<0) /* immer */ -#define SMF_PRODUCTION (1<<1) /* für Produktion - am gebäude, an der einheit */ -#define SMF_RIDING (1<<2) /* Bonus für berittene - an der rasse*/ +#define SMF_ALWAYS (1<<0) /* immer */ +#define SMF_PRODUCTION (1<<1) /* für Produktion - am gebäude, an der einheit */ +#define SMF_RIDING (1<<2) /* Bonus für berittene - an der rasse */ -typedef struct skill { - skill_t id : 8; - unsigned int level : 8; - unsigned int weeks : 8; - unsigned int old : 8; -} skill; + typedef struct skill { + skill_t id:8; + unsigned int level:8; + unsigned int weeks:8; + unsigned int old:8; + } skill; -typedef int (*skillmod_fun)(const struct unit*, const struct region*, skill_t, int); -typedef struct skillmod_data { - skill_t skill; - skillmod_fun special; - double multiplier; - int number; - int bonus; - int flags; -} skillmod_data; -extern struct attrib_type at_skillmod; -extern int rc_skillmod(const struct race * rc, const struct region *r, skill_t sk); -extern int skillmod(const struct attrib * a, const struct unit * u, const struct region * r, skill_t sk, int value, int flags); -extern struct attrib * make_skillmod(skill_t sk, unsigned int flags, skillmod_fun special, double multiplier, int bonus); + typedef int (*skillmod_fun) (const struct unit *, const struct region *, + skill_t, int); + typedef struct skillmod_data { + skill_t skill; + skillmod_fun special; + double multiplier; + int number; + int bonus; + int flags; + } skillmod_data; + extern struct attrib_type at_skillmod; + extern int rc_skillmod(const struct race *rc, const struct region *r, + skill_t sk); + extern int skillmod(const struct attrib *a, const struct unit *u, + const struct region *r, skill_t sk, int value, int flags); + extern struct attrib *make_skillmod(skill_t sk, unsigned int flags, + skillmod_fun special, double multiplier, int bonus); -extern const char * skillname(skill_t, const struct locale *); -extern skill_t sk_find(const char * name); -extern void enable_skill(const char * name, boolean value); -extern int level_days(int level); -extern int level(int days); + extern const char *skillname(skill_t, const struct locale *); + extern skill_t sk_find(const char *name); + extern void enable_skill(const char *name, boolean value); + extern int level_days(int level); + extern int level(int days); #define skill_level(level) (level) -extern void reduce_skill(struct unit *u, skill * sv, unsigned int change); -extern int skill_weeks(int level); -extern int skill_compare(const skill * sk, const skill * sc); + extern void reduce_skill(struct unit *u, skill * sv, unsigned int change); + extern int skill_weeks(int level); + extern int skill_compare(const skill * sk, const skill * sc); -extern void sk_set(skill * sv, int level); + extern void sk_set(skill * sv, int level); -extern const char *skillnames[]; -extern boolean skill_enabled[]; + extern const char *skillnames[]; + extern boolean skill_enabled[]; #ifdef __cplusplus } diff --git a/src/kernel/spell.c b/src/kernel/spell.c index f48fdd0d5..3079f25f9 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -39,12 +39,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * Reihenfolge wie in Spelldaten tauchen sie auch im Report auf */ -quicklist * spells = NULL; +quicklist *spells = NULL; -void -register_spell(spell * sp) +void register_spell(spell * sp) { - if (sp->id==0) { + if (sp->id == 0) { sp->id = hashstring(sp->sname); } add_spell(&spells, sp); @@ -52,21 +51,24 @@ register_spell(spell * sp) /** versucht einen Spruch über gebiet + name zu identifizieren. * gibt ansonsten NULL zurück */ -spell * -find_spell(magic_t mtype, const char * name) +spell *find_spell(magic_t mtype, const char *name) { - quicklist * ql = spells; - int qi; - spell * spx = NULL; + quicklist *ql = spells; - for (qi=0;ql;ql_advance(&ql, &qi, 1)) { - spell * sp = (spell *)ql_get(ql, qi); - if (strcmp(name, sp->sname)==0) { - if (mtype==M_NONE || sp->magietyp==mtype) return sp; + int qi; + + spell *spx = NULL; + + for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { + spell *sp = (spell *) ql_get(ql, qi); + + if (strcmp(name, sp->sname) == 0) { + if (mtype == M_NONE || sp->magietyp == mtype) + return sp; spx = sp; } } - if (spx==NULL) { + if (spx == NULL) { log_error(("cannot find spell by name: %s\n", name)); } return spx; @@ -77,28 +79,33 @@ find_spell(magic_t mtype, const char * name) /* Spruch identifizieren */ typedef struct spell_names { - struct spell_names * next; - const struct locale * lang; + struct spell_names *next; + const struct locale *lang; magic_t mtype; struct tnode names; } spell_names; -static spell_names * spellnames; +static spell_names *spellnames; -static spell_names * -init_spellnames(const struct locale * lang, magic_t mtype) +static spell_names *init_spellnames(const struct locale *lang, magic_t mtype) { - quicklist * ql; + quicklist *ql; + int qi; - spell_names * sn = (spell_names *)calloc(sizeof(spell_names), 1); + + spell_names *sn = (spell_names *) calloc(sizeof(spell_names), 1); + sn->next = spellnames; sn->lang = lang; sn->mtype = mtype; - for (qi=0,ql=spells;ql;ql_advance(&ql, &qi, 1)) { - spell * sp = (spell *)ql_get(ql, qi); - if (sp->magietyp==mtype) { - const char * n = spell_name(sp, lang); + for (qi = 0, ql = spells; ql; ql_advance(&ql, &qi, 1)) { + spell *sp = (spell *) ql_get(ql, qi); + + if (sp->magietyp == mtype) { + const char *n = spell_name(sp, lang); + variant token; + token.v = sp; addtoken(&sn->names, n, token); } @@ -106,51 +113,60 @@ init_spellnames(const struct locale * lang, magic_t mtype) return spellnames = sn; } -static spell_names * -get_spellnames(const struct locale * lang, magic_t mtype) +static spell_names *get_spellnames(const struct locale *lang, magic_t mtype) { - spell_names * sn = spellnames; + spell_names *sn = spellnames; + while (sn) { - if (sn->mtype==mtype && sn->lang==lang) break; - sn=sn->next; + if (sn->mtype == mtype && sn->lang == lang) + break; + sn = sn->next; } - if (!sn) return init_spellnames(lang, mtype); + if (!sn) + return init_spellnames(lang, mtype); return sn; } -static spell * -get_spellfromtoken_i(const char *name, const struct locale * lang, magic_t mtype) +static spell *get_spellfromtoken_i(const char *name, const struct locale *lang, + magic_t mtype) { variant token = { 0 }; - spell_names * sn; + spell_names *sn; sn = get_spellnames(lang, mtype); - if (findtoken(&sn->names, name, &token)==E_TOK_NOMATCH) { + if (findtoken(&sn->names, name, &token) == E_TOK_NOMATCH) { magic_t mt; + /* if we could not find it in the main magic type, we look through all the others */ - for (mt=0;mt!=MAXMAGIETYP;++mt) { - if (mt!=mtype) { + for (mt = 0; mt != MAXMAGIETYP; ++mt) { + if (mt != mtype) { sn = get_spellnames(lang, mt); - if (findtoken(&sn->names, name, &token)!=E_TOK_NOMATCH) break; + if (findtoken(&sn->names, name, &token) != E_TOK_NOMATCH) + break; } } } - if (token.v!=NULL) return (spell*)token.v; - if (lang==default_locale) return NULL; + if (token.v != NULL) + return (spell *) token.v; + if (lang == default_locale) + return NULL; return get_spellfromtoken_i(name, default_locale, mtype); } -spell * -get_spellfromtoken(unit *u, const char *name, const struct locale * lang) +spell *get_spellfromtoken(unit * u, const char *name, + const struct locale * lang) { - sc_mage * m = get_mage(u); - spell * sp; + sc_mage *m = get_mage(u); - if (m==NULL) return NULL; + spell *sp; + + if (m == NULL) + return NULL; sp = get_spellfromtoken_i(name, lang, m->magietyp); - if (sp!=NULL) { - quicklist * ql = m->spells; + if (sp != NULL) { + quicklist *ql = m->spells; + int qi; if (ql_set_find(&ql, &qi, sp)) { @@ -160,31 +176,34 @@ get_spellfromtoken(unit *u, const char *name, const struct locale * lang) return NULL; } -spell * -find_spellbyid(magic_t mtype, spellid_t id) +spell *find_spellbyid(magic_t mtype, spellid_t id) { - quicklist * ql; + quicklist *ql; + int qi; - assert(id>=0); - if (id==0) return NULL; - for (qi=0, ql=spells; ql; ql_advance(&ql, &qi, 1)) { - spell * sp = (spell *)ql_get(ql, qi); + assert(id >= 0); + if (id == 0) + return NULL; + for (qi = 0, ql = spells; ql; ql_advance(&ql, &qi, 1)) { + spell *sp = (spell *) ql_get(ql, qi); + if (sp->id == id) { return sp; } } - for (qi=0, ql=spells; ql; ql_advance(&ql, &qi, 1)) { - spell * sp = (spell *)ql_get(ql, qi); + for (qi = 0, ql = spells; ql; ql_advance(&ql, &qi, 1)) { + spell *sp = (spell *) ql_get(ql, qi); + unsigned int hashid = hashstring(sp->sname); - if (hashid==id) { - if (sp->magietyp==mtype || mtype==M_NONE) { + + if (hashid == id) { + if (sp->magietyp == mtype || mtype == M_NONE) { return sp; } } - } + } log_warning(("cannot find spell by id: %u\n", id)); return NULL; } - diff --git a/src/kernel/spell.h b/src/kernel/spell.h index 4565d2053..e2c591128 100644 --- a/src/kernel/spell.h +++ b/src/kernel/spell.h @@ -32,8 +32,8 @@ extern "C" { /* Prototypen */ - int use_item_power(struct region * r, struct unit * u); - int use_item_regeneration(struct region * r, struct unit * u); + int use_item_power(struct region *r, struct unit *u); + int use_item_regeneration(struct region *r, struct unit *u); void showspells(struct region *r, struct unit *u); int sp_antimagiczone(struct castorder *co); @@ -42,19 +42,18 @@ extern "C" { extern struct attrib_type at_unitdissolve; extern struct attrib_type at_wdwpyramid; - extern struct quicklist * spells; - extern void register_spell(struct spell * sp); - extern struct spell * find_spell(magic_t mtype, const char * name); - extern struct spell * find_spellbyid(magic_t mtype, spellid_t i); - extern struct spell *get_spellfromtoken(struct unit *u, const char *s, const struct locale * lang); + extern struct quicklist *spells; + extern void register_spell(struct spell *sp); + extern struct spell *find_spell(magic_t mtype, const char *name); + extern struct spell *find_spellbyid(magic_t mtype, spellid_t i); + extern struct spell *get_spellfromtoken(struct unit *u, const char *s, + const struct locale *lang); #ifdef __cplusplus } #endif #endif - -/* ------------------------------------------------------------- */ -/* Erläuterungen zu den Spruchdefinitionen +/* ------------------------------------------------------------- *//* Erläuterungen zu den Spruchdefinitionen * * Spruchstukturdefinition: * spell{ @@ -154,6 +153,4 @@ extern "C" { * Ist eins von mehreren Zielobjekten nicht gefunden worden, so ist * pa->param[n]->flag == TARGET_NOTFOUND * - */ -/* ------------------------------------------------------------- */ - + *//* ------------------------------------------------------------- */ diff --git a/src/kernel/spellid.h b/src/kernel/spellid.h index ffdc411f0..71f13dcda 100644 --- a/src/kernel/spellid.h +++ b/src/kernel/spellid.h @@ -88,7 +88,7 @@ enum { SPL_SPEED2, SPL_FIREDRAGONODEM, SPL_DRAGONODEM, - SPL_WYRMODEM, /* 83 */ + SPL_WYRMODEM, /* 83 */ SPL_MAGICSTREET, SPL_REANIMATE, SPL_RECRUIT, @@ -162,7 +162,7 @@ enum { SPL_MALLORNTREEGROW = 177, SPL_BIGRECRUIT = 179, SPL_IMMOLATION, - SPL_FIREODEM, /* 181 */ + SPL_FIREODEM, /* 181 */ SPL_ICEODEM, SPL_ACIDODEM, /* no longer used, but kept for reference: */ diff --git a/src/kernel/sqlite.c b/src/kernel/sqlite.c index eba6f3b3e..ac175f30a 100644 --- a/src/kernel/sqlite.c +++ b/src/kernel/sqlite.c @@ -8,11 +8,12 @@ #include #include -faction * get_faction_by_id(int uid) +faction *get_faction_by_id(int uid) { - faction * f; - for (f=factions;f;f=f->next) { - if (f->subscription==uid) { + faction *f; + + for (f = factions; f; f = f->next) { + if (f->subscription == uid) { return f; } } @@ -22,36 +23,36 @@ faction * get_faction_by_id(int uid) #define SQL_EXPECT(res, val) if (res!=val) { return val; } #define MAX_EMAIL_LENGTH 64 #define MD5_LENGTH 32 -#define MD5_LENGTH_0 (MD5_LENGTH+1) /* MD5 + zero-terminator */ +#define MD5_LENGTH_0 (MD5_LENGTH+1) /* MD5 + zero-terminator */ #define MAX_FACTION_NAME 64 #define MAX_FACTION_NAME_0 (MAX_FACTION_NAME+1) typedef struct stmt_cache { - sqlite3 * db; - sqlite3_stmt * stmt; - const char * sql; + sqlite3 *db; + sqlite3_stmt *stmt; + const char *sql; int inuse; } stmt_cache; #define MAX_STMT_CACHE 64 static stmt_cache cache[MAX_STMT_CACHE]; + static int cache_insert; -static sqlite3_stmt * -stmt_cache_get(sqlite3 * db, const char * sql) +static sqlite3_stmt *stmt_cache_get(sqlite3 * db, const char *sql) { int i, res; - for (i=0;i!=MAX_STMT_CACHE && cache[i].db;++i) { - if (cache[i].sql==sql && cache[i].db==db) { + for (i = 0; i != MAX_STMT_CACHE && cache[i].db; ++i) { + if (cache[i].sql == sql && cache[i].db == db) { cache[i].inuse = 1; res = sqlite3_reset(cache[i].stmt); return cache[i].stmt; } } - if (i==MAX_STMT_CACHE) { + if (i == MAX_STMT_CACHE) { while (cache[cache_insert].inuse) { cache[cache_insert].inuse = 0; - cache_insert = (cache_insert+1)&(MAX_STMT_CACHE-1); + cache_insert = (cache_insert + 1) & (MAX_STMT_CACHE - 1); } i = cache_insert; res = sqlite3_finalize(cache[i].stmt); @@ -68,24 +69,27 @@ typedef struct db_faction { sqlite3_uint64 id_faction; sqlite3_uint64 id_email; int no; - const char * email; - const char * passwd_md5; - const char * name; + const char *email; + const char *passwd_md5; + const char *name; } db_faction; static int -db_update_email(sqlite3 * db, const faction * f, const db_faction * dbstate, boolean force, /* [OUT] */ sqlite3_uint64 * id_email) +db_update_email(sqlite3 * db, const faction * f, const db_faction * dbstate, + boolean force, /* [OUT] */ sqlite3_uint64 * id_email) { boolean update = force; + int res = SQLITE_OK; + char email_lc[MAX_EMAIL_LENGTH]; if (update) { unicode_utf8_tolower(email_lc, sizeof(email_lc), f->email); } else { - if (strcmp(dbstate->email, f->email)!=0) { + if (strcmp(dbstate->email, f->email) != 0) { unicode_utf8_tolower(email_lc, sizeof(email_lc), f->email); - if (strcmp(dbstate->email, email_lc)!=0) { + if (strcmp(dbstate->email, email_lc) != 0) { update = true; } } @@ -93,29 +97,40 @@ db_update_email(sqlite3 * db, const faction * f, const db_faction * dbstate, boo if (update) { char email_md5[MD5_LENGTH_0]; + int i; + md5_state_t ms; + md5_byte_t digest[16]; - const char sql_insert_email[] = + + const char sql_insert_email[] = "INSERT OR FAIL INTO email (email,md5) VALUES (?,?)"; - const char sql_select_email[] = - "SELECT id FROM email WHERE md5=?"; + const char sql_select_email[] = "SELECT id FROM email WHERE md5=?"; + sqlite3_stmt *stmt_insert_email = stmt_cache_get(db, sql_insert_email); + sqlite3_stmt *stmt_select_email = stmt_cache_get(db, sql_select_email); md5_init(&ms); - md5_append(&ms, (md5_byte_t*)email_lc, (int)strlen(email_lc)); + md5_append(&ms, (md5_byte_t *) email_lc, (int)strlen(email_lc)); md5_finish(&ms, digest); - for (i=0;i!=16;++i) sprintf(email_md5+2*i, "%.02x", digest[i]); + for (i = 0; i != 16; ++i) + sprintf(email_md5 + 2 * i, "%.02x", digest[i]); - res = sqlite3_bind_text(stmt_insert_email, 1, email_lc, -1, SQLITE_TRANSIENT); - res = sqlite3_bind_text(stmt_insert_email, 2, email_md5, MD5_LENGTH, SQLITE_TRANSIENT); + res = + sqlite3_bind_text(stmt_insert_email, 1, email_lc, -1, SQLITE_TRANSIENT); + res = + sqlite3_bind_text(stmt_insert_email, 2, email_md5, MD5_LENGTH, + SQLITE_TRANSIENT); res = sqlite3_step(stmt_insert_email); - if (res==SQLITE_DONE) { + if (res == SQLITE_DONE) { *id_email = sqlite3_last_insert_rowid(db); } else { - res = sqlite3_bind_text(stmt_select_email, 1, email_md5, MD5_LENGTH, SQLITE_TRANSIENT); + res = + sqlite3_bind_text(stmt_select_email, 1, email_md5, MD5_LENGTH, + SQLITE_TRANSIENT); res = sqlite3_step(stmt_select_email); SQL_EXPECT(res, SQLITE_ROW); *id_email = sqlite3_column_int64(stmt_select_email, 0); @@ -125,38 +140,43 @@ db_update_email(sqlite3 * db, const faction * f, const db_faction * dbstate, boo return SQLITE_OK; } -int -db_update_factions(sqlite3 * db, boolean force) +int db_update_factions(sqlite3 * db, boolean force) { int game_id = 6; - const char sql_select[] = - "SELECT faction.id, faction.email_id, faction.code, email.email, faction.password_md5, faction.name, faction.lastturn FROM email, faction" - " WHERE email.id=faction.email_id AND faction.game_id=? AND (lastturn IS NULL OR lastturn>?)"; + + const char sql_select[] = + "SELECT faction.id, faction.email_id, faction.code, email.email, faction.password_md5, faction.name, faction.lastturn FROM email, faction" + " WHERE email.id=faction.email_id AND faction.game_id=? AND (lastturn IS NULL OR lastturn>?)"; sqlite3_stmt *stmt_select = stmt_cache_get(db, sql_select); - faction * f; + + faction *f; + int res; - + res = sqlite3_bind_int(stmt_select, 1, game_id); SQL_EXPECT(res, SQLITE_OK); - res = sqlite3_bind_int(stmt_select, 2, turn-2); + res = sqlite3_bind_int(stmt_select, 2, turn - 2); SQL_EXPECT(res, SQLITE_OK); for (;;) { sqlite3_uint64 id_faction; + int lastturn; - + res = sqlite3_step(stmt_select); - if (res!=SQLITE_ROW) break; + if (res != SQLITE_ROW) + break; id_faction = sqlite3_column_int64(stmt_select, 0); lastturn = sqlite3_column_int(stmt_select, 6); f = get_faction_by_id((int)id_faction); - if (f==NULL || !f->alive) { - if (lastturn==0) { + if (f == NULL || !f->alive) { + if (lastturn == 0) { const char sql_update[] = "UPDATE faction SET lastturn=? WHERE id=?"; + sqlite3_stmt *stmt = stmt_cache_get(db, sql_update); - - lastturn = f?f->lastorders:turn-1; + + lastturn = f ? f->lastorders : turn - 1; sqlite3_bind_int(stmt, 1, lastturn); sqlite3_bind_int64(stmt, 2, id_faction); res = sqlite3_step(stmt); @@ -164,19 +184,26 @@ db_update_factions(sqlite3 * db, boolean force) } } else { md5_state_t ms; + md5_byte_t digest[16]; + int i; + char passwd_md5[MD5_LENGTH_0]; + sqlite3_uint64 id_email; + boolean update = force; + db_faction dbstate; - const char * no_b36; + + const char *no_b36; fset(f, FFL_MARK); dbstate.id_faction = id_faction; dbstate.id_email = sqlite3_column_int64(stmt_select, 1); no_b36 = (const char *)sqlite3_column_text(stmt_select, 2); - dbstate.no = no_b36?atoi36(no_b36):-1; + dbstate.no = no_b36 ? atoi36(no_b36) : -1; dbstate.email = (const char *)sqlite3_column_text(stmt_select, 3); dbstate.passwd_md5 = (const char *)sqlite3_column_text(stmt_select, 4); dbstate.name = (const char *)sqlite3_column_text(stmt_select, 5); @@ -186,29 +213,38 @@ db_update_factions(sqlite3 * db, boolean force) SQL_EXPECT(res, SQLITE_OK); md5_init(&ms); - md5_append(&ms, (md5_byte_t*)f->passw, (int)strlen(f->passw)); + md5_append(&ms, (md5_byte_t *) f->passw, (int)strlen(f->passw)); md5_finish(&ms, digest); - for (i=0;i!=16;++i) sprintf(passwd_md5+2*i, "%.02x", digest[i]); + for (i = 0; i != 16; ++i) + sprintf(passwd_md5 + 2 * i, "%.02x", digest[i]); if (!update) { - update = ((id_email!=0 && dbstate.id_email!=id_email) || dbstate.no!=f->no - || dbstate.passwd_md5==NULL || strcmp(passwd_md5, dbstate.passwd_md5)!=0 - || dbstate.name==NULL || strncmp(f->name, dbstate.name, MAX_FACTION_NAME)!=0); + update = ((id_email != 0 && dbstate.id_email != id_email) + || dbstate.no != f->no || dbstate.passwd_md5 == NULL + || strcmp(passwd_md5, dbstate.passwd_md5) != 0 || dbstate.name == NULL + || strncmp(f->name, dbstate.name, MAX_FACTION_NAME) != 0); } if (update) { - const char sql_update_faction[] = + const char sql_update_faction[] = "UPDATE faction SET email_id=?, password_md5=?, code=?, name=?, firstturn=? WHERE id=?"; - sqlite3_stmt *stmt_update_faction = stmt_cache_get(db, sql_update_faction); + sqlite3_stmt *stmt_update_faction = + stmt_cache_get(db, sql_update_faction); res = sqlite3_bind_int64(stmt_update_faction, 1, id_email); SQL_EXPECT(res, SQLITE_OK); - res = sqlite3_bind_text(stmt_update_faction, 2, passwd_md5, MD5_LENGTH, SQLITE_TRANSIENT); + res = + sqlite3_bind_text(stmt_update_faction, 2, passwd_md5, MD5_LENGTH, + SQLITE_TRANSIENT); SQL_EXPECT(res, SQLITE_OK); - res = sqlite3_bind_text(stmt_update_faction, 3, no_b36, -1, SQLITE_TRANSIENT); + res = + sqlite3_bind_text(stmt_update_faction, 3, no_b36, -1, + SQLITE_TRANSIENT); SQL_EXPECT(res, SQLITE_OK); - res = sqlite3_bind_text(stmt_update_faction, 4, f->name, -1, SQLITE_TRANSIENT); + res = + sqlite3_bind_text(stmt_update_faction, 4, f->name, -1, + SQLITE_TRANSIENT); SQL_EXPECT(res, SQLITE_OK); - res = sqlite3_bind_int(stmt_update_faction, 5, turn-f->age); + res = sqlite3_bind_int(stmt_update_faction, 5, turn - f->age); SQL_EXPECT(res, SQLITE_OK); res = sqlite3_bind_int64(stmt_update_faction, 6, f->subscription); SQL_EXPECT(res, SQLITE_OK); @@ -218,9 +254,10 @@ db_update_factions(sqlite3 * db, boolean force) } } - for (f=factions;f;f=f->next) { + for (f = factions; f; f = f->next) { if (!fval(f, FFL_MARK)) { - log_error(("%s (sub=%d, email=%s) has no entry in the database\n", factionname(f), f->subscription, f->email)); + log_error(("%s (sub=%d, email=%s) has no entry in the database\n", + factionname(f), f->subscription, f->email)); } else { freset(f, FFL_MARK); } @@ -228,22 +265,27 @@ db_update_factions(sqlite3 * db, boolean force) return SQLITE_OK; } -int -db_update_scores(sqlite3 * db, boolean force) +int db_update_scores(sqlite3 * db, boolean force) { - const char * sql_ins = "INSERT OR FAIL INTO score (value,faction_id,turn) VALUES (?,?,?)"; - sqlite3_stmt * stmt_ins = stmt_cache_get(db, sql_ins); - const char * sql_upd = "UPDATE score set value=? WHERE faction_id=? AND turn=?"; - sqlite3_stmt * stmt_upd = stmt_cache_get(db, sql_upd); - faction * f; + const char *sql_ins = + "INSERT OR FAIL INTO score (value,faction_id,turn) VALUES (?,?,?)"; + sqlite3_stmt *stmt_ins = stmt_cache_get(db, sql_ins); + + const char *sql_upd = + "UPDATE score set value=? WHERE faction_id=? AND turn=?"; + sqlite3_stmt *stmt_upd = stmt_cache_get(db, sql_upd); + + faction *f; + sqlite3_exec(db, "BEGIN", 0, 0, 0); - for (f=factions;f;f=f->next) { + for (f = factions; f; f = f->next) { int res; + sqlite3_bind_int(stmt_ins, 1, f->score); sqlite3_bind_int64(stmt_ins, 2, f->subscription); sqlite3_bind_int(stmt_ins, 3, turn); res = sqlite3_step(stmt_ins); - if (res==SQLITE_CONSTRAINT) { + if (res == SQLITE_CONSTRAINT) { sqlite3_bind_int(stmt_upd, 1, f->score); sqlite3_bind_int64(stmt_upd, 2, f->subscription); sqlite3_bind_int(stmt_upd, 3, turn); diff --git a/src/kernel/teleport.c b/src/kernel/teleport.c index 40fc7b8ae..ee744b4b0 100644 --- a/src/kernel/teleport.c +++ b/src/kernel/teleport.c @@ -42,27 +42,29 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define TP_RADIUS 2 #define TP_DISTANCE 4 -static int -real2tp(int rk) { +static int real2tp(int rk) +{ /* in C: - * -4 / 5 = 0; - * +4 / 5 = 0; - * !!!!!!!!!!; - */ - return (rk + (TP_DISTANCE*5000)) / TP_DISTANCE - 5000; + * -4 / 5 = 0; + * +4 / 5 = 0; + * !!!!!!!!!!; + */ + return (rk + (TP_DISTANCE * 5000)) / TP_DISTANCE - 5000; } -static region * -tpregion(const region *r) { - region * rt = findregion(TE_CENTER_X+real2tp(r->x), TE_CENTER_Y+real2tp(r->y)); - if (!is_astral(rt)) return NULL; +static region *tpregion(const region * r) +{ + region *rt = + findregion(TE_CENTER_X + real2tp(r->x), TE_CENTER_Y + real2tp(r->y)); + if (!is_astral(rt)) + return NULL; return rt; } -region_list * -astralregions(const region * r, boolean (*valid)(const region *)) +region_list *astralregions(const region * r, boolean(*valid) (const region *)) { - region_list * rlist = NULL; + region_list *rlist = NULL; + int x, y; assert(is_astral(r)); @@ -71,63 +73,75 @@ astralregions(const region * r, boolean (*valid)(const region *)) return NULL; } r = r_astral_to_standard(r); - if (r==NULL) return NULL; + if (r == NULL) + return NULL; + + for (x = -TP_RADIUS; x <= +TP_RADIUS; ++x) { + for (y = -TP_RADIUS; y <= +TP_RADIUS; ++y) { + region *rn; - for (x=-TP_RADIUS;x<=+TP_RADIUS;++x) { - for (y=-TP_RADIUS;y<=+TP_RADIUS;++y) { - region * rn; int dist = koor_distance(0, 0, x, y); - int nx = r->x+x, ny = r->y+y; - if (dist > TP_RADIUS) continue; + int nx = r->x + x, ny = r->y + y; + + if (dist > TP_RADIUS) + continue; pnormalize(&nx, &ny, rplane(r)); rn = findregion(nx, ny); - if (rn!=NULL && (valid==NULL || valid(rn))) add_regionlist(&rlist, rn); + if (rn != NULL && (valid == NULL || valid(rn))) + add_regionlist(&rlist, rn); } } return rlist; } -region * -r_standard_to_astral(const region *r) +region *r_standard_to_astral(const region * r) { - if (rplane(r) != get_normalplane()) return NULL; + if (rplane(r) != get_normalplane()) + return NULL; return tpregion(r); } -region * -r_astral_to_standard(const region *r) +region *r_astral_to_standard(const region * r) { int x, y; + region *r2; assert(is_astral(r)); - x = (r->x-TE_CENTER_X)*TP_DISTANCE; - y = (r->y-TE_CENTER_Y)*TP_DISTANCE; + x = (r->x - TE_CENTER_X) * TP_DISTANCE; + y = (r->y - TE_CENTER_Y) * TP_DISTANCE; pnormalize(&x, &y, get_normalplane()); r2 = findregion(x, y); - if (r2==NULL || rplane(r2)!=get_normalplane()) return NULL; + if (r2 == NULL || rplane(r2) != get_normalplane()) + return NULL; return r2; } -region_list * -all_in_range(const region *r, int n, boolean (*valid)(const region *)) +region_list *all_in_range(const region * r, int n, + boolean(*valid) (const region *)) { int x, y; + region_list *rlist = NULL; - plane * pl = rplane(r); - if (r == NULL) return NULL; + plane *pl = rplane(r); - for (x = r->x-n; x <= r->x+n; x++) { - for (y = r->y-n; y <= r->y+n; y++) { + if (r == NULL) + return NULL; + + for (x = r->x - n; x <= r->x + n; x++) { + for (y = r->y - n; y <= r->y + n; y++) { if (koor_distance(r->x, r->y, x, y) <= n) { - region * r2; + region *r2; + int nx = x, ny = y; + pnormalize(&nx, &ny, pl); r2 = findregion(nx, ny); - if (r2!=NULL && (valid==NULL || valid(r2))) add_regionlist(&rlist, r2); + if (r2 != NULL && (valid == NULL || valid(r2))) + add_regionlist(&rlist, r2); } } } @@ -135,85 +149,96 @@ all_in_range(const region *r, int n, boolean (*valid)(const region *)) return rlist; } -void -spawn_braineaters(float chance) +void spawn_braineaters(float chance) { region *r; + faction *f0 = get_monsters(); - int next = rng_int() % (int)(chance*100); - - if (f0==NULL) return; + + int next = rng_int() % (int)(chance * 100); + + if (f0 == NULL) + return; for (r = regions; r; r = r->next) { - if (!is_astral(r) || fval(r->terrain, FORBIDDEN_REGION)) continue; + if (!is_astral(r) || fval(r->terrain, FORBIDDEN_REGION)) + continue; /* Neues Monster ? */ if (next-- == 0) { - unit *u = createunit(r, f0, 1+rng_int()%10+rng_int()%10, new_race[RC_HIRNTOETER]); + unit *u = + createunit(r, f0, 1 + rng_int() % 10 + rng_int() % 10, + new_race[RC_HIRNTOETER]); equip_unit(u, get_equipment("monster_braineater")); - next = rng_int() % (int)(chance*100); + next = rng_int() % (int)(chance * 100); } } } -plane * -get_normalplane(void) +plane *get_normalplane(void) { return NULL; } -boolean -is_astral(const region * r) +boolean is_astral(const region * r) { - plane * pl = get_astralplane(); + plane *pl = get_astralplane(); + return (pl && rplane(r) == pl); } -plane * -get_astralplane(void) +plane *get_astralplane(void) { - static plane * astralspace; + static plane *astralspace; + static int rule_astralplane = -1; + static int gamecookie = -1; - if (rule_astralplane<0) { - rule_astralplane = get_param_int(global.parameters, "modules.astralspace", 1); + + if (rule_astralplane < 0) { + rule_astralplane = + get_param_int(global.parameters, "modules.astralspace", 1); } if (!rule_astralplane) { return NULL; } - if (gamecookie!=global.cookie) { + if (gamecookie != global.cookie) { astralspace = getplanebyname("Astralraum"); gamecookie = global.cookie; } - if (astralspace==NULL) { + if (astralspace == NULL) { astralspace = create_new_plane(1, "Astralraum", - TE_CENTER_X-500, TE_CENTER_X+500, - TE_CENTER_Y-500, TE_CENTER_Y+500, 0); + TE_CENTER_X - 500, TE_CENTER_X + 500, + TE_CENTER_Y - 500, TE_CENTER_Y + 500, 0); } return astralspace; } -void -create_teleport_plane(void) +void create_teleport_plane(void) { region *r; - plane * hplane = get_homeplane(); - plane * aplane = get_astralplane(); - const terrain_type * fog = get_terrain("fog"); + plane *hplane = get_homeplane(); + + plane *aplane = get_astralplane(); + + const terrain_type *fog = get_terrain("fog"); + + for (r = regions; r; r = r->next) { + plane *pl = rplane(r); - for (r=regions;r;r=r->next) { - plane * pl = rplane(r); if (pl == hplane) { region *ra = tpregion(r); - if (ra==NULL) { - int x = TE_CENTER_X+real2tp(r->x); - int y = TE_CENTER_Y+real2tp(r->y); + if (ra == NULL) { + int x = TE_CENTER_X + real2tp(r->x); + + int y = TE_CENTER_Y + real2tp(r->y); + pnormalize(&x, &y, aplane); - + ra = new_region(x, y, aplane, 0); terraform_region(ra, fog); } @@ -221,8 +246,7 @@ create_teleport_plane(void) } } -boolean -inhabitable(const region * r) +boolean inhabitable(const region * r) { return fval(r->terrain, LAND_REGION); } diff --git a/src/kernel/teleport.h b/src/kernel/teleport.h index 83f777899..2f3a5bcc0 100644 --- a/src/kernel/teleport.h +++ b/src/kernel/teleport.h @@ -24,12 +24,14 @@ extern "C" { struct region *r_standard_to_astral(const struct region *r); struct region *r_astral_to_standard(const struct region *); - extern struct region_list *astralregions(const struct region * rastral, boolean (*valid)(const struct region *)); - extern struct region_list *all_in_range(const struct region *r, int n, boolean (*valid)(const struct region *)); - extern boolean inhabitable(const struct region * r); - extern boolean is_astral(const struct region * r); - extern struct plane * get_astralplane(void); - extern struct plane * get_normalplane(void); + extern struct region_list *astralregions(const struct region *rastral, + boolean(*valid) (const struct region *)); + extern struct region_list *all_in_range(const struct region *r, int n, + boolean(*valid) (const struct region *)); + extern boolean inhabitable(const struct region *r); + extern boolean is_astral(const struct region *r); + extern struct plane *get_astralplane(void); + extern struct plane *get_normalplane(void); void create_teleport_plane(void); void set_teleport_plane_regiontypes(void); diff --git a/src/kernel/terrain.c b/src/kernel/terrain.c index 15ef6b58f..70304cf0a 100644 --- a/src/kernel/terrain.c +++ b/src/kernel/terrain.c @@ -37,7 +37,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define MAXTERRAINS 20 -const char * terraindata[MAXTERRAINS] = { +const char *terraindata[MAXTERRAINS] = { "ocean", "plain", "swamp", @@ -46,8 +46,8 @@ const char * terraindata[MAXTERRAINS] = { "mountain", "glacier", "firewall", - NULL, /* dungeon module */ - NULL, /* former grassland */ + NULL, /* dungeon module */ + NULL, /* former grassland */ "fog", "thickfog", "volcano", @@ -55,83 +55,85 @@ const char * terraindata[MAXTERRAINS] = { "iceberg_sleep", "iceberg", - NULL, /* museum module */ - NULL, /* museum module */ - NULL, /* former magicstorm */ - NULL /* museum module */ + NULL, /* museum module */ + NULL, /* museum module */ + NULL, /* former magicstorm */ + NULL /* museum module */ }; -static terrain_type * registered_terrains; +static terrain_type *registered_terrains; -const terrain_type * -terrains(void) +const terrain_type *terrains(void) { return registered_terrains; } -static const char * -plain_name(const struct region * r) +static const char *plain_name(const struct region *r) { /* TODO: xml defined */ - if (r_isforest(r)) return "forest"; + if (r_isforest(r)) + return "forest"; return r->terrain->_name; } -void -register_terrain(struct terrain_type * terrain) +void register_terrain(struct terrain_type *terrain) { - assert(terrain->next==NULL), - terrain->next = registered_terrains; + assert(terrain->next == NULL), terrain->next = registered_terrains; registered_terrains = terrain; - if (strcmp("plain", terrain->_name)==0) + if (strcmp("plain", terrain->_name) == 0) terrain->name = &plain_name; } -const struct terrain_type * -get_terrain(const char * name) +const struct terrain_type *get_terrain(const char *name) { - const struct terrain_type * terrain; - for (terrain=registered_terrains;terrain;terrain=terrain->next) { - if (strcmp(terrain->_name, name)==0) break; + const struct terrain_type *terrain; + + for (terrain = registered_terrains; terrain; terrain = terrain->next) { + if (strcmp(terrain->_name, name) == 0) + break; } return terrain; } -static const terrain_type * newterrains[MAXTERRAINS]; +static const terrain_type *newterrains[MAXTERRAINS]; -const struct terrain_type * -newterrain(terrain_t t) +const struct terrain_type *newterrain(terrain_t t) { - if (t==NOTERRAIN) return NULL; - assert(t>=0); - assert(t= 0); + assert(t < MAXTERRAINS); return newterrains[t]; } -terrain_t -oldterrain(const struct terrain_type * terrain) +terrain_t oldterrain(const struct terrain_type * terrain) { terrain_t t; - if (terrain==NULL) return NOTERRAIN; - for (t=0;t!=MAXTERRAINS;++t) { - if (newterrains[t]==terrain) return t; + + if (terrain == NULL) + return NOTERRAIN; + for (t = 0; t != MAXTERRAINS; ++t) { + if (newterrains[t] == terrain) + return t; } log_warning(("%s is not a classic terrain.\n", terrain->_name)); return NOTERRAIN; } -const char * -terrain_name(const struct region * r) +const char *terrain_name(const struct region *r) { if (r->attribs) { - attrib * a = a_find(r->attribs, &at_racename); + attrib *a = a_find(r->attribs, &at_racename); + if (a) { - const char * str = get_racename(a); - if (str) return str; + const char *str = get_racename(a); + + if (str) + return str; } } - if (r->terrain->name!=NULL) { + if (r->terrain->name != NULL) { return r->terrain->name(r); } else if (fval(r->terrain, SEA_REGION)) { if (curse_active(get_curse(r->attribs, ct_find("maelstrom")))) { @@ -141,16 +143,18 @@ terrain_name(const struct region * r) return r->terrain->_name; } -void -init_terrains(void) +void init_terrains(void) { terrain_t t; - for (t=0;t!=MAXTERRAINS;++t) { - const terrain_type * newterrain = newterrains[t]; - if (newterrain!=NULL) continue; - if (terraindata[t]!=NULL) { + + for (t = 0; t != MAXTERRAINS; ++t) { + const terrain_type *newterrain = newterrains[t]; + + if (newterrain != NULL) + continue; + if (terraindata[t] != NULL) { newterrain = get_terrain(terraindata[t]); - if (newterrain!=NULL) { + if (newterrain != NULL) { newterrains[t] = newterrain; } } diff --git a/src/kernel/terrain.h b/src/kernel/terrain.h index b8be715f4..64de714e7 100644 --- a/src/kernel/terrain.h +++ b/src/kernel/terrain.h @@ -24,60 +24,60 @@ extern "C" { /* diverse Flags */ /* Strassen und Gebäude können gebaut werden, wenn max_road > 0 */ -#define LAND_REGION (1<<0) /* Standard-Land-struct region */ -#define SEA_REGION (1<<1) /* hier braucht man ein Boot */ -#define FOREST_REGION (1<<2) /* Elfen- und Kampfvorteil durch Bäume */ -#define ARCTIC_REGION (1<<3) /* Gletscher & co = Keine Insekten! */ -#define CAVALRY_REGION (1<<4) /* Gletscher & co = Keine Insekten! */ +#define LAND_REGION (1<<0) /* Standard-Land-struct region */ +#define SEA_REGION (1<<1) /* hier braucht man ein Boot */ +#define FOREST_REGION (1<<2) /* Elfen- und Kampfvorteil durch Bäume */ +#define ARCTIC_REGION (1<<3) /* Gletscher & co = Keine Insekten! */ +#define CAVALRY_REGION (1<<4) /* Gletscher & co = Keine Insekten! */ /* Achtung: SEA_REGION ist nicht das Gegenteil von LAND_REGION. Die zwei schliessen sich nichtmal aus! */ -#define FORBIDDEN_REGION (1<<5) /* unpassierbare Blockade-struct region */ -#define SAIL_INTO (1<<6) /* man darf hierhin segeln */ -#define FLY_INTO (1<<7) /* man darf hierhin fliegen */ -#define SWIM_INTO (1<<8) /* man darf hierhin schwimmen */ -#define WALK_INTO (1<<9) /* man darf hierhin laufen */ -#define LARGE_SHIPS (1<<10) /* grosse Schiffe dürfen hinfahren */ +#define FORBIDDEN_REGION (1<<5) /* unpassierbare Blockade-struct region */ +#define SAIL_INTO (1<<6) /* man darf hierhin segeln */ +#define FLY_INTO (1<<7) /* man darf hierhin fliegen */ +#define SWIM_INTO (1<<8) /* man darf hierhin schwimmen */ +#define WALK_INTO (1<<9) /* man darf hierhin laufen */ +#define LARGE_SHIPS (1<<10) /* grosse Schiffe dürfen hinfahren */ -typedef struct production_rule { - char * name; - const struct resource_type * rtype; + typedef struct production_rule { + char *name; + const struct resource_type *rtype; - void (*terraform) (struct production_rule *, const struct region *); - void (*update) (struct production_rule *, const struct region *); - void (*use) (struct production_rule *, const struct region *, int amount); - int (*visible) (const struct production_rule *, int skilllevel); + void (*terraform) (struct production_rule *, const struct region *); + void (*update) (struct production_rule *, const struct region *); + void (*use) (struct production_rule *, const struct region *, int amount); + int (*visible) (const struct production_rule *, int skilllevel); - /* no initialization required */ - struct production_rule * next; -} production_rule; + /* no initialization required */ + struct production_rule *next; + } production_rule; -typedef struct terrain_production { - const struct resource_type * type; - const char *startlevel; - const char *base; - const char *divisor; - float chance; -} terrain_production; + typedef struct terrain_production { + const struct resource_type *type; + const char *startlevel; + const char *base; + const char *divisor; + float chance; + } terrain_production; -typedef struct terrain_type { - char * _name; - int size; /* how many peasants can work? */ - unsigned int flags; - short max_road; /* this many stones make a full road */ - short distribution; /* multiplier used for seeding */ - struct terrain_production * production; - const struct item_type ** herbs; /* zero-terminated array of herbs */ - const char * (*name)(const struct region * r); - const struct terrain_type * next; -} terrain_type; + typedef struct terrain_type { + char *_name; + int size; /* how many peasants can work? */ + unsigned int flags; + short max_road; /* this many stones make a full road */ + short distribution; /* multiplier used for seeding */ + struct terrain_production *production; + const struct item_type **herbs; /* zero-terminated array of herbs */ + const char *(*name) (const struct region * r); + const struct terrain_type *next; + } terrain_type; -extern const terrain_type * terrains(void); -extern void register_terrain(struct terrain_type * terrain); -extern const struct terrain_type * get_terrain(const char * name); -extern const char * terrain_name(const struct region * r); + extern const terrain_type *terrains(void); + extern void register_terrain(struct terrain_type *terrain); + extern const struct terrain_type *get_terrain(const char *name); + extern const char *terrain_name(const struct region *r); -extern void init_terrains(void); + extern void init_terrains(void); #ifdef __cplusplus } #endif -#endif /* TERRAIN_H */ +#endif /* TERRAIN_H */ diff --git a/src/kernel/terrainid.h b/src/kernel/terrainid.h index fb2e40dd0..b7f4119d9 100644 --- a/src/kernel/terrainid.h +++ b/src/kernel/terrainid.h @@ -14,35 +14,34 @@ extern "C" { #endif -enum { - T_OCEAN = 0, - T_PLAIN = 1, - T_SWAMP = 2, - T_DESERT = 3, /* kann aus T_PLAIN entstehen */ - T_HIGHLAND = 4, - T_MOUNTAIN = 5, - T_GLACIER = 6, /* kann aus T_MOUNTAIN entstehen */ - T_FIREWALL = 7, /* Unpassierbar */ - /* T_HELL = 8, Hölle */ - /* T_GRASSLAND = 9, */ - T_ASTRAL = 10, - T_ASTRALB = 11, - T_VOLCANO = 12, - T_VOLCANO_SMOKING = 13, - T_ICEBERG_SLEEP = 14, - T_ICEBERG = 15, - /* T_HALL1 = 16, */ - /* T_CORRIDOR1 = 17, */ - /* T_MAGICSTORM = 18, */ - /* T_WALL1 = 19, */ - NOTERRAIN = (terrain_t) - 1 -}; + enum { + T_OCEAN = 0, + T_PLAIN = 1, + T_SWAMP = 2, + T_DESERT = 3, /* kann aus T_PLAIN entstehen */ + T_HIGHLAND = 4, + T_MOUNTAIN = 5, + T_GLACIER = 6, /* kann aus T_MOUNTAIN entstehen */ + T_FIREWALL = 7, /* Unpassierbar */ + /* T_HELL = 8, Hölle */ + /* T_GRASSLAND = 9, */ + T_ASTRAL = 10, + T_ASTRALB = 11, + T_VOLCANO = 12, + T_VOLCANO_SMOKING = 13, + T_ICEBERG_SLEEP = 14, + T_ICEBERG = 15, + /* T_HALL1 = 16, */ + /* T_CORRIDOR1 = 17, */ + /* T_MAGICSTORM = 18, */ + /* T_WALL1 = 19, */ + NOTERRAIN = (terrain_t) - 1 + }; -extern const struct terrain_type * newterrain(terrain_t t); -extern terrain_t oldterrain(const struct terrain_type * terrain); + extern const struct terrain_type *newterrain(terrain_t t); + extern terrain_t oldterrain(const struct terrain_type *terrain); #ifdef __cplusplus } #endif - #endif diff --git a/src/kernel/textstore.c b/src/kernel/textstore.c index 391038f0f..d4055642e 100644 --- a/src/kernel/textstore.c +++ b/src/kernel/textstore.c @@ -22,173 +22,170 @@ without prior permission by the authors of Eressea. #define NULL_TOKEN '@' -static int -txt_w_brk(struct storage * store) +static int txt_w_brk(struct storage *store) { - putc('\n', (FILE *)store->userdata); + putc('\n', (FILE *) store->userdata); return 1; } -static int -txt_w_id(struct storage * store, int arg) +static int txt_w_id(struct storage *store, int arg) { - return fprintf((FILE *)store->userdata, "%s ", itoa36(arg)); + return fprintf((FILE *) store->userdata, "%s ", itoa36(arg)); } -static int -txt_r_id(struct storage * store) +static int txt_r_id(struct storage *store) { char id[8]; - fscanf((FILE *)store->userdata, "%7s", id); + + fscanf((FILE *) store->userdata, "%7s", id); return atoi36(id); } -static int -txt_w_int(struct storage * store, int arg) +static int txt_w_int(struct storage *store, int arg) { - return fprintf((FILE *)store->userdata, "%d ", arg); + return fprintf((FILE *) store->userdata, "%d ", arg); } -static int -txt_r_int(struct storage * store) +static int txt_r_int(struct storage *store) { int result; - fscanf((FILE *)store->userdata, "%d", &result); + + fscanf((FILE *) store->userdata, "%d", &result); return result; } -static int -txt_w_flt(struct storage * store, float arg) +static int txt_w_flt(struct storage *store, float arg) { - return fprintf((FILE *)store->userdata, "%f ", arg); + return fprintf((FILE *) store->userdata, "%f ", arg); } -static float -txt_r_flt(struct storage * store) +static float txt_r_flt(struct storage *store) { double result; - fscanf((FILE *)store->userdata, "%lf", &result); + + fscanf((FILE *) store->userdata, "%lf", &result); return (float)result; } -static int -txt_w_tok(struct storage * store, const char * tok) +static int txt_w_tok(struct storage *store, const char *tok) { int result; - if (tok==NULL || tok[0]==0) { - result = fputc(NULL_TOKEN, (FILE *)store->userdata); + + if (tok == NULL || tok[0] == 0) { + result = fputc(NULL_TOKEN, (FILE *) store->userdata); } else { #ifndef NDEBUG - const char * find = strchr(tok, ' '); - if (!find) find = strchr(tok, NULL_TOKEN); + const char *find = strchr(tok, ' '); + + if (!find) + find = strchr(tok, NULL_TOKEN); assert(!find || !"reserved character in token"); #endif - assert(tok[0]!=' '); - result = fputs(tok, (FILE *)store->userdata); + assert(tok[0] != ' '); + result = fputs(tok, (FILE *) store->userdata); } - fputc(' ', (FILE *)store->userdata); + fputc(' ', (FILE *) store->userdata); return result; } -static char * -txt_r_tok(struct storage * store) + +static char *txt_r_tok(struct storage *store) { char result[256]; - fscanf((FILE *)store->userdata, "%256s", result); - if (result[0]==NULL_TOKEN || result[0]==0) { + + fscanf((FILE *) store->userdata, "%256s", result); + if (result[0] == NULL_TOKEN || result[0] == 0) { return NULL; } return strdup(result); } -static void -txt_r_tok_buf(struct storage * store, char * result, size_t size) + +static void txt_r_tok_buf(struct storage *store, char *result, size_t size) { char format[16]; - if (result && size>0) { - format[0]='%'; - sprintf(format+1, "%us", size); - fscanf((FILE *)store->userdata, format, result); - if (result[0]==NULL_TOKEN) { + + if (result && size > 0) { + format[0] = '%'; + sprintf(format + 1, "%us", size); + fscanf((FILE *) store->userdata, format, result); + if (result[0] == NULL_TOKEN) { result[0] = 0; } } else { /* trick to skip when no result expected */ - fscanf((FILE *)store->userdata, "%*s"); + fscanf((FILE *) store->userdata, "%*s"); } } -static int -txt_w_str(struct storage * store, const char * str) +static int txt_w_str(struct storage *store, const char *str) { - int result = fwritestr((FILE *)store->userdata, str); - fputc(' ', (FILE *)store->userdata); - return result+1; + int result = fwritestr((FILE *) store->userdata, str); + + fputc(' ', (FILE *) store->userdata); + return result + 1; } -static char * -txt_r_str(struct storage * store) +static char *txt_r_str(struct storage *store) { char buffer[DISPLAYSIZE]; + /* you should not use this */ - freadstr((FILE *)store->userdata, store->encoding, buffer, sizeof(buffer)); + freadstr((FILE *) store->userdata, store->encoding, buffer, sizeof(buffer)); return strdup(buffer); } -static void -txt_r_str_buf(struct storage * store, char * result, size_t size) +static void txt_r_str_buf(struct storage *store, char *result, size_t size) { - freadstr((FILE *)store->userdata, store->encoding, result, size); + freadstr((FILE *) store->userdata, store->encoding, result, size); } -static int -txt_open(struct storage * store, const char * filename, int mode) +static int txt_open(struct storage *store, const char *filename, int mode) { - const char * modes[] = { 0, "rt", "wt", "at" }; - FILE * F = fopen(filename, modes[mode]); + const char *modes[] = { 0, "rt", "wt", "at" }; + FILE *F = fopen(filename, modes[mode]); + store->userdata = F; if (F) { const char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; - if (mode==IO_READ) { + if (mode == IO_READ) { char token[8]; + /* recognize UTF8 BOM */ store->r_tok_buf(store, token, sizeof(token)); - if (memcmp(token, utf8_bom, 3)==0) { - if (enc_gamedata!=XML_CHAR_ENCODING_UTF8) { + if (memcmp(token, utf8_bom, 3) == 0) { + if (enc_gamedata != XML_CHAR_ENCODING_UTF8) { log_warning(("Found UTF-8 BOM, assuming unicode game data.\n")); store->encoding = XML_CHAR_ENCODING_UTF8; } - store->version = atoi(token+3); + store->version = atoi(token + 3); } else { - if (store->encoding==XML_CHAR_ENCODING_NONE) { + if (store->encoding == XML_CHAR_ENCODING_NONE) { store->encoding = XML_CHAR_ENCODING_8859_1; log_warning(("No BOM, assuming 8859-1 game data.\n")); } store->version = atoi(token); } - } else if (store->encoding==XML_CHAR_ENCODING_UTF8) { + } else if (store->encoding == XML_CHAR_ENCODING_UTF8) { fputs(utf8_bom, F); fprintf(F, "%d\n", RELEASE_VERSION); } } - return (F==NULL); + return (F == NULL); } -static int -txt_w_bin(struct storage * store, void * arg, size_t size) +static int txt_w_bin(struct storage *store, void *arg, size_t size) { assert(!"not implemented!"); return 0; } -static void -txt_r_bin(struct storage * store, void * result, size_t size) +static void txt_r_bin(struct storage *store, void *result, size_t size) { assert(!"not implemented!"); } -static int -txt_close(struct storage * store) +static int txt_close(struct storage *store) { - return fclose((FILE *)store->userdata); + return fclose((FILE *) store->userdata); } const storage text_store = { @@ -198,8 +195,7 @@ const storage text_store = { txt_w_id, txt_r_id, txt_w_tok, txt_r_tok, txt_r_tok_buf, txt_w_str, txt_r_str, txt_r_str_buf, - txt_w_bin, txt_r_bin, + txt_w_bin, txt_r_bin, txt_open, txt_close, 0, 0, NULL }; - diff --git a/src/kernel/textstore.h b/src/kernel/textstore.h index 134a8da7e..46eb2090a 100644 --- a/src/kernel/textstore.h +++ b/src/kernel/textstore.h @@ -15,7 +15,7 @@ extern "C" { #include -extern const storage text_store; + extern const storage text_store; #ifdef __cplusplus } diff --git a/src/kernel/types.h b/src/kernel/types.h index 0f558386e..2348c055c 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -31,41 +31,75 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include typedef short terrain_t; + typedef short direction_t; + typedef short race_t; + typedef short magic_t; + typedef short skill_t; + typedef short typ_t; + typedef short item_t; + typedef unsigned int spellid_t; struct attrib; + struct attrib_type; + struct building; + struct building_type; + struct curse; + struct equipment; + struct faction; + struct fighter; + struct item; + struct item_type; + struct locale; + struct luxury_type; + struct order; + struct plane; + struct potion_type; + struct race; + struct region; + struct region_list; + struct resource_type; + struct ship; + struct ship_type; + struct skill; + struct spell; + struct storage; + struct strlist; + struct terrain_type; + struct unit; + struct weapon_type; typedef struct ursprung { @@ -77,6 +111,7 @@ typedef struct ursprung { /* ----------------- Befehle ----------------------------------- */ typedef unsigned char keyword_t; + enum { K_KOMMENTAR, K_BANNER, @@ -137,8 +172,8 @@ enum { K_PRAY, K_SORT, K_SETJIHAD, - K_GM, /* perform GM commands */ - K_INFO, /* set player-info */ + K_GM, /* perform GM commands */ + K_INFO, /* set player-info */ K_PREFIX, K_PLANT, K_WEREWOLF, @@ -154,6 +189,7 @@ enum { /* ------------------ Status von Einheiten --------------------- */ typedef unsigned char status_t; + enum { ST_AGGRO, ST_FIGHT, @@ -166,6 +202,7 @@ enum { /* ----------------- Parameter --------------------------------- */ typedef unsigned char param_t; + enum { P_LOCALE, P_ANY, @@ -221,7 +258,7 @@ enum { NOPARAM = (param_t) - 1 }; -typedef enum { /* Fehler und Meldungen im Report */ +typedef enum { /* Fehler und Meldungen im Report */ MSG_BATTLE, MSG_EVENT, MSG_MOVE, @@ -235,8 +272,8 @@ typedef enum { /* Fehler und Meldungen im Report */ MAX_MSG } msg_t; -enum { /* Message-Level */ - ML_IMPORTANT, /* Sachen, die IMO erscheinen _muessen_ */ +enum { /* Message-Level */ + ML_IMPORTANT, /* Sachen, die IMO erscheinen _muessen_ */ ML_DEBUG, ML_MISTAKE, ML_WARN, @@ -249,20 +286,20 @@ extern const char *parameters[MAXPARAMS]; /* --------------- Reports Typen ------------------------------- */ enum { - O_REPORT, /* 1 */ - O_COMPUTER, /* 2 */ - O_ZUGVORLAGE, /* 4 */ + O_REPORT, /* 1 */ + O_COMPUTER, /* 2 */ + O_ZUGVORLAGE, /* 4 */ O_UNUSED_3, - O_STATISTICS, /* 16 */ - O_DEBUG, /* 32 */ - O_COMPRESS, /* 64 */ - O_NEWS, /* 128 */ + O_STATISTICS, /* 16 */ + O_DEBUG, /* 32 */ + O_COMPRESS, /* 64 */ + O_NEWS, /* 128 */ O_UNUSED_8, - O_ADRESSEN, /* 512 */ - O_BZIP2, /* 1024 - compress as bzip2 */ - O_SCORE, /* 2048 - punkte anzeigen? */ - O_SHOWSKCHANGE, /* 4096 - Skillveränderungen anzeigen? */ - O_XML, /* 8192 - XML report versenden */ + O_ADRESSEN, /* 512 */ + O_BZIP2, /* 1024 - compress as bzip2 */ + O_SCORE, /* 2048 - punkte anzeigen? */ + O_SHOWSKCHANGE, /* 4096 - Skillveränderungen anzeigen? */ + O_XML, /* 8192 - XML report versenden */ MAXOPTIONS }; @@ -279,7 +316,7 @@ enum { SK_CATAPULT, SK_HERBALISM, SK_MAGIC, - SK_HORSE_TRAINING, /* 10 */ + SK_HORSE_TRAINING, /* 10 */ SK_RIDING, SK_ARMORER, SK_SHIPBUILDING, @@ -289,7 +326,7 @@ enum { SK_SPY, SK_QUARRYING, SK_ROAD_BUILDING, - SK_TACTICS, /* 20 */ + SK_TACTICS, /* 20 */ SK_STEALTH, SK_ENTERTAINMENT, SK_WEAPONSMITH, @@ -299,13 +336,13 @@ enum { SK_STAMINA, SK_WEAPONLESS, MAXSKILLS, - NOSKILL = (skill_t) -1 + NOSKILL = (skill_t) - 1 }; /* ------------- Typ von Einheiten ----------------------------- */ enum { - RC_DWARF, /* 0 - Zwerg */ + RC_DWARF, /* 0 - Zwerg */ RC_ELF, RC_GOBLIN = 3, RC_HUMAN, @@ -347,7 +384,7 @@ enum { RC_SONGDRAGON = 37, RC_SEASERPENT = 51, - RC_SHADOWKNIGHT, + RC_SHADOWKNIGHT, RC_CENTAUR, RC_SKELETON, @@ -358,8 +395,8 @@ enum { RC_GHOUL_LORD, RC_MUS_SPIRIT, - RC_GNOME, - RC_TEMPLATE, + RC_GNOME, + RC_TEMPLATE, RC_CLONE, MAXRACES, @@ -381,14 +418,14 @@ enum { }; #define DONT_HELP 0 -#define HELP_MONEY 1 /* Mitversorgen von Einheiten */ -#define HELP_FIGHT 2 /* Bei Verteidigung mithelfen */ -#define HELP_OBSERVE 4 /* Bei Wahrnehmung mithelfen */ -#define HELP_GIVE 8 /* Dinge annehmen ohne KONTAKTIERE */ -#define HELP_GUARD 16 /* Laesst Steuern eintreiben etc. */ -#define HELP_FSTEALTH 32 /* Parteitarnung anzeigen. */ -#define HELP_TRAVEL 64 /* Laesst Regionen betreten. */ -#define HELP_ALL (127-HELP_TRAVEL-HELP_OBSERVE) /* Alle "positiven" HELPs zusammen */ +#define HELP_MONEY 1 /* Mitversorgen von Einheiten */ +#define HELP_FIGHT 2 /* Bei Verteidigung mithelfen */ +#define HELP_OBSERVE 4 /* Bei Wahrnehmung mithelfen */ +#define HELP_GIVE 8 /* Dinge annehmen ohne KONTAKTIERE */ +#define HELP_GUARD 16 /* Laesst Steuern eintreiben etc. */ +#define HELP_FSTEALTH 32 /* Parteitarnung anzeigen. */ +#define HELP_TRAVEL 64 /* Laesst Regionen betreten. */ +#define HELP_ALL (127-HELP_TRAVEL-HELP_OBSERVE) /* Alle "positiven" HELPs zusammen */ /* HELP_OBSERVE deaktiviert */ /* ------------------------------------------------------------- */ /* Prototypen */ diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 92ab35e3b..0dbe0ee3d 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -62,51 +62,55 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. attrib_type at_creator = { "creator" - /* Rest ist NULL; temporäres, nicht alterndes Attribut */ + /* Rest ist NULL; temporäres, nicht alterndes Attribut */ }; #define UMAXHASH MAXUNITS -static unit * unithash[UMAXHASH]; -static unit * delmarker = (unit*)unithash; /* a funny hack */ +static unit *unithash[UMAXHASH]; + +static unit *delmarker = (unit *) unithash; /* a funny hack */ #define HASH_STATISTICS 1 #if HASH_STATISTICS static int hash_requests; + static int hash_misses; #endif -void -uhash(unit * u) +void uhash(unit * u) { int key = HASH1(u->no, UMAXHASH), gk = HASH2(u->no, UMAXHASH); - while (unithash[key]!=NULL && unithash[key]!=delmarker && unithash[key]!=u) { + + while (unithash[key] != NULL && unithash[key] != delmarker + && unithash[key] != u) { key = (key + gk) % UMAXHASH; } - assert(unithash[key]!=u || !"trying to add the same unit twice"); + assert(unithash[key] != u || !"trying to add the same unit twice"); unithash[key] = u; } -void -uunhash(unit * u) +void uunhash(unit * u) { int key = HASH1(u->no, UMAXHASH), gk = HASH2(u->no, UMAXHASH); - while (unithash[key]!=NULL && unithash[key]!=u) { + + while (unithash[key] != NULL && unithash[key] != u) { key = (key + gk) % UMAXHASH; } - assert(unithash[key]==u || !"trying to remove a unit that is not hashed"); + assert(unithash[key] == u || !"trying to remove a unit that is not hashed"); unithash[key] = delmarker; } -unit * -ufindhash(int uid) +unit *ufindhash(int uid) { - assert(uid>=0); + assert(uid >= 0); #if HASH_STATISTICS ++hash_requests; #endif - if (uid>=0) { + if (uid >= 0) { int key = HASH1(uid, UMAXHASH), gk = HASH2(uid, UMAXHASH); - while (unithash[key]!=NULL && (unithash[key]==delmarker || unithash[key]->no!=uid)) { + + while (unithash[key] != NULL && (unithash[key] == delmarker + || unithash[key]->no != uid)) { key = (key + gk) % UMAXHASH; #if HASH_STATISTICS ++hash_misses; @@ -119,30 +123,31 @@ ufindhash(int uid) #define DMAXHASH 7919 typedef struct dead { - struct dead * nexthash; - faction * f; + struct dead *nexthash; + faction *f; int no; } dead; -static dead* deadhash[DMAXHASH]; +static dead *deadhash[DMAXHASH]; -static void -dhash(int no, faction * f) +static void dhash(int no, faction * f) { - dead * hash = (dead*)calloc(1, sizeof(dead)); - dead * old = deadhash[no % DMAXHASH]; + dead *hash = (dead *) calloc(1, sizeof(dead)); + + dead *old = deadhash[no % DMAXHASH]; + hash->no = no; hash->f = f; deadhash[no % DMAXHASH] = hash; hash->nexthash = old; } -faction * -dfindhash(int no) +faction *dfindhash(int no) { - dead * old; + dead *old; - if(no < 0) return 0; + if (no < 0) + return 0; for (old = deadhash[no % DMAXHASH]; old; old = old->nexthash) { if (old->no == no) { @@ -153,46 +158,52 @@ dfindhash(int no) } typedef struct buddy { - struct buddy * next; + struct buddy *next; int number; - faction * faction; - unit * unit; + faction *faction; + unit *unit; } buddy; -static buddy * -get_friends(const unit * u, int * numfriends) +static buddy *get_friends(const unit * u, int *numfriends) { - buddy * friends = 0; - faction * f = u->faction; - region * r = u->region; - int number = 0; - unit * u2; + buddy *friends = 0; - for (u2=r->units;u2;u2=u2->next) { - if (u2->faction!=f && u2->number>0) { + faction *f = u->faction; + + region *r = u->region; + + int number = 0; + + unit *u2; + + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->faction != f && u2->number > 0) { int allied = 0; - if (get_param_int(global.parameters, "rules.alliances", 0)!=0) { - allied = (f->alliance && f->alliance==u2->faction->alliance); - } - else if (alliedunit(u, u2->faction, HELP_MONEY) && alliedunit(u2, f, HELP_GIVE)) { + + if (get_param_int(global.parameters, "rules.alliances", 0) != 0) { + allied = (f->alliance && f->alliance == u2->faction->alliance); + } else if (alliedunit(u, u2->faction, HELP_MONEY) + && alliedunit(u2, f, HELP_GIVE)) { allied = 1; } if (allied) { - buddy * nf, ** fr = &friends; + buddy *nf, **fr = &friends; /* some units won't take stuff: */ if (u2->race->ec_flags & GETITEM) { - while (*fr && (*fr)->faction->nofaction->no) fr = &(*fr)->next; + while (*fr && (*fr)->faction->no < u2->faction->no) + fr = &(*fr)->next; nf = *fr; - if (nf==NULL || nf->faction!=u2->faction) { + if (nf == NULL || nf->faction != u2->faction) { nf = malloc(sizeof(buddy)); nf->next = *fr; nf->faction = u2->faction; nf->unit = u2; nf->number = 0; *fr = nf; - } else if (nf->faction==u2->faction && (u2->race->ec_flags & GIVEITEM)) { - /* we don't like to gift it to units that won't give it back */ + } else if (nf->faction == u2->faction + && (u2->race->ec_flags & GIVEITEM)) { + /* we don't like to gift it to units that won't give it back */ if ((nf->unit->race->ec_flags & GIVEITEM) == 0) { nf->unit = u2; } @@ -203,7 +214,8 @@ get_friends(const unit * u, int * numfriends) } } } - if (numfriends) *numfriends = number; + if (numfriends) + *numfriends = number; return friends; } @@ -211,30 +223,38 @@ get_friends(const unit * u, int * numfriends) * this function returns 0 on success, or 1 if there are items that * could not be destroyed. */ -int -gift_items(unit * u, int flags) +int gift_items(unit * u, int flags) { - region * r = u->region; - item ** itm_p = &u->items; + region *r = u->region; + + item **itm_p = &u->items; + int retval = 0; + int rule = rule_give(); assert(u->region); - if ((u->faction->flags&FFL_QUIT)==0 || (rule&GIVE_ONDEATH)==0) { - if ((rule&GIVE_ALLITEMS)==0 && (flags&GIFT_FRIENDS)) flags-=GIFT_FRIENDS; - if ((rule&GIVE_PEASANTS)==0 && (flags&GIFT_PEASANTS)) flags-=GIFT_PEASANTS; - if ((rule&GIVE_SELF)==0 && (flags&GIFT_SELF)) flags-=GIFT_SELF; + if ((u->faction->flags & FFL_QUIT) == 0 || (rule & GIVE_ONDEATH) == 0) { + if ((rule & GIVE_ALLITEMS) == 0 && (flags & GIFT_FRIENDS)) + flags -= GIFT_FRIENDS; + if ((rule & GIVE_PEASANTS) == 0 && (flags & GIFT_PEASANTS)) + flags -= GIFT_PEASANTS; + if ((rule & GIVE_SELF) == 0 && (flags & GIFT_SELF)) + flags -= GIFT_SELF; } - if (u->items==NULL || fval(u->race, RCF_ILLUSIONARY)) return 0; - if ((u->race->ec_flags & GIVEITEM) == 0) return 0; + if (u->items == NULL || fval(u->race, RCF_ILLUSIONARY)) + return 0; + if ((u->race->ec_flags & GIVEITEM) == 0) + return 0; /* at first, I should try giving my crap to my own units in this region */ - if (u->faction && (u->faction->flags&FFL_QUIT)==0 && (flags & GIFT_SELF)) { - unit * u2, * u3 = NULL; + if (u->faction && (u->faction->flags & FFL_QUIT) == 0 && (flags & GIFT_SELF)) { + unit *u2, *u3 = NULL; + for (u2 = r->units; u2; u2 = u2->next) { - if (u2 != u && u2->faction == u->faction && u2->number>0) { + if (u2 != u && u2->faction == u->faction && u2->number > 0) { /* some units won't take stuff: */ if (u2->race->ec_flags & GETITEM) { /* we don't like to gift it to units that won't give it back */ @@ -253,24 +273,32 @@ gift_items(unit * u, int flags) i_merge(&u3->items, &u->items); u->items = NULL; } - if (u->items==NULL) return 0; + if (u->items == NULL) + return 0; } /* if I have friends, I'll try to give my stuff to them */ if (u->faction && (flags & GIFT_FRIENDS)) { int number = 0; - buddy * friends = get_friends(u, &number); + + buddy *friends = get_friends(u, &number); while (friends) { - struct buddy * nf = friends; - unit * u2 = nf->unit; - item * itm = u->items; - while (itm!=NULL) { - const item_type * itype = itm->type; - item * itn = itm->next; + struct buddy *nf = friends; + + unit *u2 = nf->unit; + + item *itm = u->items; + + while (itm != NULL) { + const item_type *itype = itm->type; + + item *itn = itm->next; + int n = itm->number; + n = n * nf->number / number; - if (n>0) { + if (n > 0) { i_change(&u->items, itype, -n); i_change(&u2->items, itype, n); } @@ -280,25 +308,26 @@ gift_items(unit * u, int flags) friends = nf->next; free(nf); } - if (u->items==NULL) return 0; + if (u->items == NULL) + return 0; } /* last, but not least, give money and horses to peasants */ while (*itm_p) { - item * itm = *itm_p; + item *itm = *itm_p; if (flags & GIFT_PEASANTS) { if (!fval(u->region->terrain, SEA_REGION)) { - if (itm->type==olditemtype[I_HORSE]) { + if (itm->type == olditemtype[I_HORSE]) { rsethorses(r, rhorses(r) + itm->number); itm->number = 0; - } else if (itm->type==i_silver) { + } else if (itm->type == i_silver) { rsetmoney(r, rmoney(r) + itm->number); itm->number = 0; } } } - if (itm->number>0 && (itm->type->flags & ITF_NOTLOST)) { + if (itm->number > 0 && (itm->type->flags & ITF_NOTLOST)) { itm_p = &itm->next; retval = -1; } else { @@ -309,8 +338,7 @@ gift_items(unit * u, int flags) return retval; } -void -make_zombie(unit * u) +void make_zombie(unit * u) { u_setfaction(u, get_monsters()); scale_number(u, 1); @@ -325,32 +353,32 @@ make_zombie(unit * u) * returns 0 on success, or -1 if unit could not be removed. */ -static unit * deleted_units = NULL; +static unit *deleted_units = NULL; -int -remove_unit(unit ** ulist, unit * u) +int remove_unit(unit ** ulist, unit * u) { int result; assert(ufindhash(u->no)); handle_event(u->attribs, "destroy", u); - result = gift_items(u, GIFT_SELF|GIFT_FRIENDS|GIFT_PEASANTS); - if (result!=0) { + result = gift_items(u, GIFT_SELF | GIFT_FRIENDS | GIFT_PEASANTS); + if (result != 0) { make_zombie(u); return -1; } - - if (u->number) set_number(u, 0); + + if (u->number) + set_number(u, 0); leave(u, true); u->region = NULL; uunhash(u); if (ulist) { - while (*ulist!=u) { + while (*ulist != u) { ulist = &(*ulist)->next; } - assert(*ulist==u); + assert(*ulist == u); *ulist = u->next; } @@ -364,8 +392,7 @@ remove_unit(unit ** ulist, unit * u) return 0; } -unit * -findnewunit (const region * r, const faction *f, int n) +unit *findnewunit(const region * r, const faction * f, int n) { unit *u2; @@ -398,19 +425,20 @@ attrib_type at_alias = { NO_READ }; -int -ualias(const unit * u) +int ualias(const unit * u) { - attrib * a = a_find(u->attribs, &at_alias); - if (!a) return 0; + attrib *a = a_find(u->attribs, &at_alias); + + if (!a) + return 0; return a->data.i; } -int -a_readprivate(attrib * a, void * owner, struct storage * store) +int a_readprivate(attrib * a, void *owner, struct storage *store) { a->data.v = store->r_str(store); - if (a->data.v) return AT_READ_OK; + if (a->data.v) + return AT_READ_OK; return AT_READ_FAIL; } @@ -426,8 +454,7 @@ attrib_type at_private = { a_readprivate }; -const char * -u_description(const unit * u, const struct locale * lang) +const char *u_description(const unit * u, const struct locale *lang) { if (u->display && u->display[0]) { return u->display; @@ -437,26 +464,29 @@ u_description(const unit * u, const struct locale * lang) return NULL; } -const char * -uprivate(const unit * u) +const char *uprivate(const unit * u) { - attrib * a = a_find(u->attribs, &at_private); - if (!a) return NULL; + attrib *a = a_find(u->attribs, &at_private); + + if (!a) + return NULL; return a->data.v; } -void -usetprivate(unit * u, const char * str) +void usetprivate(unit * u, const char *str) { - attrib * a = a_find(u->attribs, &at_private); + attrib *a = a_find(u->attribs, &at_private); if (str == NULL) { - if (a) a_remove(&u->attribs, a); + if (a) + a_remove(&u->attribs, a); return; } - if (!a) a = a_add(&u->attribs, a_new(&at_private)); - if (a->data.v) free(a->data.v); - a->data.v = strdup((const char*)str); + if (!a) + a = a_add(&u->attribs, a_new(&at_private)); + if (a->data.v) + free(a->data.v); + a->data.v = strdup((const char *)str); } /*********************/ @@ -472,18 +502,21 @@ attrib_type at_potionuser = { NO_READ }; -void -usetpotionuse(unit * u, const potion_type * ptype) +void usetpotionuse(unit * u, const potion_type * ptype) { - attrib * a = a_find(u->attribs, &at_potionuser); - if (!a) a = a_add(&u->attribs, a_new(&at_potionuser)); - a->data.v = (void*)ptype; + attrib *a = a_find(u->attribs, &at_potionuser); + + if (!a) + a = a_add(&u->attribs, a_new(&at_potionuser)); + a->data.v = (void *)ptype; } -const potion_type * -ugetpotionuse(const unit * u) { - attrib * a = a_find(u->attribs, &at_potionuser); - if (!a) return NULL; +const potion_type *ugetpotionuse(const unit * u) +{ + attrib *a = a_find(u->attribs, &at_potionuser); + + if (!a) + return NULL; return (const potion_type *)a->data.v; } @@ -499,27 +532,29 @@ attrib_type at_target = { NO_READ }; -unit * -utarget(const unit * u) { - attrib * a; - if (!fval(u, UFL_TARGET)) return NULL; +unit *utarget(const unit * u) +{ + attrib *a; + + if (!fval(u, UFL_TARGET)) + return NULL; a = a_find(u->attribs, &at_target); - assert (a || !"flag set, but no target found"); - return (unit*)a->data.v; + assert(a || !"flag set, but no target found"); + return (unit *) a->data.v; } -void -usettarget(unit * u, const unit * t) +void usettarget(unit * u, const unit * t) { - attrib * a = a_find(u->attribs, &at_target); - if (!a && t) a = a_add(&u->attribs, a_new(&at_target)); + attrib *a = a_find(u->attribs, &at_target); + + if (!a && t) + a = a_add(&u->attribs, a_new(&at_target)); if (a) { if (!t) { a_remove(&u->attribs, a); freset(u, UFL_TARGET); - } - else { - a->data.v = (void*)t; + } else { + a->data.v = (void *)t; fset(u, UFL_TARGET); } } @@ -529,18 +564,19 @@ usettarget(unit * u, const unit * t) /* at_siege */ /*********************/ -void -a_writesiege(const attrib * a, const void * owner, struct storage * store) +void a_writesiege(const attrib * a, const void *owner, struct storage *store) { - struct building * b = (struct building*)a->data.v; + struct building *b = (struct building *)a->data.v; + write_building_reference(b, store); } -int -a_readsiege(attrib * a, void * owner, struct storage * store) +int a_readsiege(attrib * a, void *owner, struct storage *store) { - int result = read_reference(&a->data.v, store, read_building_reference, resolve_building); - if (result==0 && !a->data.v) { + int result = + read_reference(&a->data.v, store, read_building_reference, + resolve_building); + if (result == 0 && !a->data.v) { return AT_READ_FAIL; } return AT_READ_OK; @@ -555,27 +591,29 @@ attrib_type at_siege = { a_readsiege }; -struct building * - usiege(const unit * u) { - attrib * a; - if (!fval(u, UFL_SIEGE)) return NULL; - a = a_find(u->attribs, &at_siege); - assert (a || !"flag set, but no siege found"); - return (struct building *)a->data.v; +struct building *usiege(const unit * u) +{ + attrib *a; + + if (!fval(u, UFL_SIEGE)) + return NULL; + a = a_find(u->attribs, &at_siege); + assert(a || !"flag set, but no siege found"); + return (struct building *)a->data.v; } -void -usetsiege(unit * u, const struct building * t) +void usetsiege(unit * u, const struct building *t) { - attrib * a = a_find(u->attribs, &at_siege); - if (!a && t) a = a_add(&u->attribs, a_new(&at_siege)); + attrib *a = a_find(u->attribs, &at_siege); + + if (!a && t) + a = a_add(&u->attribs, a_new(&at_siege)); if (a) { if (!t) { a_remove(&u->attribs, a); freset(u, UFL_SIEGE); - } - else { - a->data.v = (void*)t; + } else { + a->data.v = (void *)t; fset(u, UFL_SIEGE); } } @@ -593,25 +631,29 @@ attrib_type at_contact = { NO_READ }; -void -usetcontact(unit * u, const unit * u2) +void usetcontact(unit * u, const unit * u2) { - attrib * a = a_find(u->attribs, &at_contact); - while (a && a->type==&at_contact && a->data.v!=u2) a = a->next; - if (a && a->type==&at_contact) return; - a_add(&u->attribs, a_new(&at_contact))->data.v = (void*)u2; + attrib *a = a_find(u->attribs, &at_contact); + + while (a && a->type == &at_contact && a->data.v != u2) + a = a->next; + if (a && a->type == &at_contact) + return; + a_add(&u->attribs, a_new(&at_contact))->data.v = (void *)u2; } -boolean -ucontact(const unit * u, const unit * u2) +boolean ucontact(const unit * u, const unit * u2) /* Prüft, ob u den Kontaktiere-Befehl zu u2 gesetzt hat. */ { attrib *ru; - if (u->faction==u2->faction) return true; + + if (u->faction == u2->faction) + return true; /* Explizites KONTAKTIERE */ - for (ru = a_find(u->attribs, &at_contact); ru && ru->type==&at_contact; ru = ru->next) { - if (((unit*)ru->data.v) == u2) { + for (ru = a_find(u->attribs, &at_contact); ru && ru->type == &at_contact; + ru = ru->next) { + if (((unit *) ru->data.v) == u2) { return true; } } @@ -623,11 +665,11 @@ ucontact(const unit * u, const unit * u2) ** init & cleanup module **/ -void -free_units(void) +void free_units(void) { while (deleted_units) { - unit * u = deleted_units; + unit *u = deleted_units; + deleted_units = deleted_units->next; free_unit(u); free(u); @@ -635,31 +677,30 @@ free_units(void) } -void -write_unit_reference(const unit * u, struct storage * store) +void write_unit_reference(const unit * u, struct storage *store) { - store->w_id(store, (u && u->region)?u->no:0); + store->w_id(store, (u && u->region) ? u->no : 0); } -int -resolve_unit(variant id, void * address) +int resolve_unit(variant id, void *address) { - unit * u = NULL; - if (id.i!=0) { + unit *u = NULL; + + if (id.i != 0) { u = findunit(id.i); - if (u==NULL) { - *(unit**)address = NULL; + if (u == NULL) { + *(unit **) address = NULL; return -1; } } - *(unit**)address = u; + *(unit **) address = u; return 0; } -variant -read_unit_reference(struct storage * store) +variant read_unit_reference(struct storage * store) { variant var; + var.i = store->r_id(store); return var; } @@ -668,22 +709,22 @@ attrib_type at_stealth = { "stealth", NULL, NULL, NULL, a_writeint, a_readint }; -void -u_seteffstealth(unit * u, int value) +void u_seteffstealth(unit * u, int value) { if (skill_enabled[SK_STEALTH]) { - attrib * a = NULL; + attrib *a = NULL; + if (fval(u, UFL_STEALTH)) { a = a_find(u->attribs, &at_stealth); } - if (value<0) { - if (a!=NULL) { + if (value < 0) { + if (a != NULL) { freset(u, UFL_STEALTH); a_remove(&u->attribs, a); } return; } - if (a==NULL) { + if (a == NULL) { a = a_add(&u->attribs, a_new(&at_stealth)); fset(u, UFL_STEALTH); } @@ -691,23 +732,24 @@ u_seteffstealth(unit * u, int value) } } -int -u_geteffstealth(const struct unit * u) +int u_geteffstealth(const struct unit *u) { if (skill_enabled[SK_STEALTH]) { if (fval(u, UFL_STEALTH)) { - attrib * a = a_find(u->attribs, &at_stealth); - if (a!=NULL) return a->data.i; + attrib *a = a_find(u->attribs, &at_stealth); + + if (a != NULL) + return a->data.i; } } return -1; } -int -get_level(const unit * u, skill_t id) +int get_level(const unit * u, skill_t id) { if (skill_enabled[id]) { - skill * sv = u->skills; + skill *sv = u->skills; + while (sv != u->skills + u->skill_size) { if (sv->id == id) { return sv->level; @@ -718,14 +760,14 @@ get_level(const unit * u, skill_t id) return 0; } -void -set_level(unit * u, skill_t sk, int value) +void set_level(unit * u, skill_t sk, int value) { - skill * sv = u->skills; + skill *sv = u->skills; - if (!skill_enabled[sk]) return; + if (!skill_enabled[sk]) + return; - if (value==0) { + if (value == 0) { remove_skill(u, sk); return; } @@ -739,55 +781,55 @@ set_level(unit * u, skill_t sk, int value) sk_set(add_skill(u, sk), value); } -static int -leftship_age(struct attrib * a) +static int leftship_age(struct attrib *a) { /* must be aged, so it doesn't affect report generation (cansee) */ unused(a); - return AT_AGE_REMOVE; /* remove me */ + return AT_AGE_REMOVE; /* remove me */ } static attrib_type at_leftship = { "leftship", NULL, NULL, leftship_age }; -static attrib * -make_leftship(struct ship * leftship) +static attrib *make_leftship(struct ship *leftship) { - attrib * a = a_new(&at_leftship); + attrib *a = a_new(&at_leftship); + a->data.v = leftship; return a; } -void -set_leftship(unit *u, ship *sh) +void set_leftship(unit * u, ship * sh) { a_add(&u->attribs, make_leftship(sh)); } -ship * -leftship(const unit *u) +ship *leftship(const unit * u) { - attrib * a = a_find(u->attribs, &at_leftship); + attrib *a = a_find(u->attribs, &at_leftship); /* Achtung: Es ist nicht garantiert, daß der Rückgabewert zu jedem - * Zeitpunkt noch auf ein existierendes Schiff zeigt! */ + * Zeitpunkt noch auf ein existierendes Schiff zeigt! */ - if (a) return (ship *)(a->data.v); + if (a) + return (ship *) (a->data.v); return NULL; } -void -leave_ship(unit * u) +void leave_ship(unit * u) { - struct ship * sh = u->ship; - if (sh==NULL) return; + struct ship *sh = u->ship; + + if (sh == NULL) + return; u->ship = NULL; set_leftship(u, sh); if (fval(u, UFL_OWNER)) { unit *u2, *owner = NULL; + freset(u, UFL_OWNER); for (u2 = u->region->units; u2; u2 = u2->next) { @@ -795,23 +837,26 @@ leave_ship(unit * u) if (u2->faction == u->faction) { owner = u2; break; - } - else if (owner==NULL) owner = u2; + } else if (owner == NULL) + owner = u2; } } - if (owner!=NULL) fset(owner, UFL_OWNER); + if (owner != NULL) + fset(owner, UFL_OWNER); } } -void -leave_building(unit * u) +void leave_building(unit * u) { - struct building * b = u->building; - if (!b) return; + struct building *b = u->building; + + if (!b) + return; u->building = NULL; if (fval(u, UFL_OWNER)) { unit *u2, *owner = NULL; + freset(u, UFL_OWNER); for (u2 = u->region->units; u2; u2 = u2->next) { @@ -819,65 +864,63 @@ leave_building(unit * u) if (u2->faction == u->faction) { owner = u2; break; - } - else if (owner==NULL) owner = u2; + } else if (owner == NULL) + owner = u2; } } - if (owner!=NULL) { + if (owner != NULL) { fset(owner, UFL_OWNER); } } } -boolean -can_leave(unit * u) +boolean can_leave(unit * u) { static int rule_leave = -1; if (!u->building) { return true; } - if (rule_leave<0) { + if (rule_leave < 0) { rule_leave = get_param_int(global.parameters, "rules.move.owner_leave", 0); } - if (rule_leave && u->building && u==building_owner(u->building)) { + if (rule_leave && u->building && u == building_owner(u->building)) { return false; } return true; } -boolean -leave(unit * u, boolean force) +boolean leave(unit * u, boolean force) { if (!force) { if (!can_leave(u)) { return false; } } - if (u->building) leave_building(u); - else if (u->ship) leave_ship(u); + if (u->building) + leave_building(u); + else if (u->ship) + leave_ship(u); return true; } -const struct race * -urace(const struct unit * u) +const struct race *urace(const struct unit *u) { return u->race; } -boolean -can_survive(const unit *u, const region *r) +boolean can_survive(const unit * u, const region * r) { if ((fval(r->terrain, WALK_INTO) && (u->race->flags & RCF_WALK)) - || (fval(r->terrain, SWIM_INTO) && (u->race->flags & RCF_SWIM)) - || (fval(r->terrain, FLY_INTO) && (u->race->flags & RCF_FLY))) - { - static const curse_type * ctype = NULL; + || (fval(r->terrain, SWIM_INTO) && (u->race->flags & RCF_SWIM)) + || (fval(r->terrain, FLY_INTO) && (u->race->flags & RCF_FLY))) { + static const curse_type *ctype = NULL; if (has_horses(u) && !fval(r->terrain, WALK_INTO)) return false; - if (!ctype) ctype = ct_find("holyground"); + if (!ctype) + ctype = ct_find("holyground"); if (fval(u->race, RCF_UNDEAD) && curse_active(get_curse(r->attribs, ctype))) return false; @@ -886,16 +929,19 @@ can_survive(const unit *u, const region *r) return false; } -void -move_unit(unit * u, region * r, unit ** ulist) +void move_unit(unit * u, region * r, unit ** ulist) { int maxhp = 0; + assert(u && r); assert(u->faction || !"this unit is dead"); - if (u->region == r) return; - if (u->region!=NULL) maxhp = unit_max_hp(u); - if (!ulist) ulist = (&r->units); + if (u->region == r) + return; + if (u->region != NULL) + maxhp = unit_max_hp(u); + if (!ulist) + ulist = (&r->units); if (u->region) { setguard(u, GUARD_NONE); fset(u, UFL_MOVED); @@ -903,6 +949,7 @@ move_unit(unit * u, region * r, unit ** ulist) /* can_leave must be checked in travel_i */ #ifndef NDEBUG boolean result = leave(u, false); + assert(result); #else leave(u, false); @@ -924,32 +971,37 @@ move_unit(unit * u, region * r, unit ** ulist) /* ist mist, aber wegen nicht skalierender attribute notwendig: */ #include "alchemy.h" -void -transfermen(unit * u, unit * u2, int n) +void transfermen(unit * u, unit * u2, int n) { - const attrib * a; - int hp = u->hp; - region * r = u->region; + const attrib *a; - if (n==0) return; + int hp = u->hp; + + region *r = u->region; + + if (n == 0) + return; assert(n > 0); /* "hat attackiert"-status wird übergeben */ if (u2) { skill *sv, *sn; + skill_t sk; - ship * sh; - assert(u2->number+n>0); + ship *sh; - for (sk=0; sk!=MAXSKILLS; ++sk) { + assert(u2->number + n > 0); + + for (sk = 0; sk != MAXSKILLS; ++sk) { int weeks, level = 0; sv = get_skill(u, sk); sn = get_skill(u2, sk); - if (sv==NULL && sn==NULL) continue; - if (sn==NULL && u2->number==0) { + if (sv == NULL && sn == NULL) + continue; + if (sn == NULL && u2->number == 0) { /* new unit, easy to solve */ level = sv->level; weeks = sv->weeks; @@ -957,51 +1009,60 @@ transfermen(unit * u, unit * u2, int n) double dlevel = 0.0; if (sv && sv->level) { - dlevel += (sv->level + 1 - sv->weeks/(sv->level+1.0)) * n; + dlevel += (sv->level + 1 - sv->weeks / (sv->level + 1.0)) * n; level += sv->level * n; } if (sn && sn->level) { - dlevel += (sn->level + 1 - sn->weeks/(sn->level+1.0)) * u2->number; + dlevel += + (sn->level + 1 - sn->weeks / (sn->level + 1.0)) * u2->number; level += sn->level * u2->number; } dlevel = dlevel / (n + u2->number); level = level / (n + u2->number); - if (level<=dlevel) { + if (level <= dlevel) { /* apply the remaining fraction to the number of weeks to go. - * subtract the according number of weeks, getting closer to the - * next level */ + * subtract the according number of weeks, getting closer to the + * next level */ level = (int)dlevel; - weeks = (level+1) - (int)((dlevel - level) * (level+1)); + weeks = (level + 1) - (int)((dlevel - level) * (level + 1)); } else { /* make it harder to reach the next level. - * weeks+level is the max difficulty, 1 - the fraction between - * level and dlevel applied to the number of weeks between this - * and the previous level is the added difficutly */ - level = (int)dlevel+1; + * weeks+level is the max difficulty, 1 - the fraction between + * level and dlevel applied to the number of weeks between this + * and the previous level is the added difficutly */ + level = (int)dlevel + 1; weeks = 1 + 2 * level - (int)((1 + dlevel - level) * level); } } if (level) { - if (sn==NULL) sn = add_skill(u2, sk); + if (sn == NULL) + sn = add_skill(u2, sk); sn->level = (unsigned char)level; sn->weeks = (unsigned char)weeks; - assert(sn->weeks>0 && sn->weeks<=sn->level*2+1); - assert(u2->number!=0 || (sn->level==sv->level && sn->weeks==sv->weeks)); + assert(sn->weeks > 0 && sn->weeks <= sn->level * 2 + 1); + assert(u2->number != 0 || (sn->level == sv->level + && sn->weeks == sv->weeks)); } else if (sn) { remove_skill(u2, sk); sn = NULL; } } a = a_find(u->attribs, &at_effect); - while (a && a->type==&at_effect) { - effect_data * olde = (effect_data*)a->data.v; - if (olde->value) change_effect(u2, olde->type, olde->value); + while (a && a->type == &at_effect) { + effect_data *olde = (effect_data *) a->data.v; + + if (olde->value) + change_effect(u2, olde->type, olde->value); a = a->next; } sh = leftship(u); - if (sh!=NULL) set_leftship(u2, sh); - u2->flags |= u->flags&(UFL_LONGACTION|UFL_NOTMOVING|UFL_HUNGER|UFL_MOVED|UFL_ENTER); + if (sh != NULL) + set_leftship(u2, sh); + u2->flags |= + u-> + flags & (UFL_LONGACTION | UFL_NOTMOVING | UFL_HUNGER | UFL_MOVED | + UFL_ENTER); if (u->attribs) { transfer_curse(u, u2, n); } @@ -1013,22 +1074,28 @@ transfermen(unit * u, unit * u2, int n) u2->hp += hp; /* TODO: Das ist schnarchlahm! und gehört nicht hierhin */ a = a_find(u2->attribs, &at_effect); - while (a && a->type==&at_effect) { - attrib * an = a->next; - effect_data * olde = (effect_data*)a->data.v; + while (a && a->type == &at_effect) { + attrib *an = a->next; + + effect_data *olde = (effect_data *) a->data.v; + int e = get_effect(u, olde->type); - if (e!=0) change_effect(u2, olde->type, -e); + + if (e != 0) + change_effect(u2, olde->type, -e); a = an; } - } - else if (r->land) { - if ((u->race->ec_flags & ECF_REC_ETHEREAL)==0) { - const race * rc = u->race; - if (rc->ec_flags & ECF_REC_HORSES) { /* Zentauren an die Pferde */ + } else if (r->land) { + if ((u->race->ec_flags & ECF_REC_ETHEREAL) == 0) { + const race *rc = u->race; + + if (rc->ec_flags & ECF_REC_HORSES) { /* Zentauren an die Pferde */ int h = rhorses(r) + n; + rsethorses(r, h); } else { int p = rpeasants(r); + p += (int)(n * rc->recruit_multi); rsetpeasants(r, p); } @@ -1036,10 +1103,10 @@ transfermen(unit * u, unit * u2, int n) } } -struct building * - inside_building(const struct unit * u) +struct building *inside_building(const struct unit *u) { - if (u->building==NULL) return NULL; + if (u->building == NULL) + return NULL; if (!fval(u->building, BLD_WORKING)) { /* Unterhalt nicht bezahlt */ @@ -1049,64 +1116,74 @@ struct building * return NULL; } else { int p = 0, cap = buildingcapacity(u->building); - const unit * u2; + + const unit *u2; + for (u2 = u->region->units; u2; u2 = u2->next) { if (u2->building == u->building) { p += u2->number; if (u2 == u) { - if (p <= cap) return u->building; + if (p <= cap) + return u->building; return NULL; } - if (p > cap) return NULL; + if (p > cap) + return NULL; } - } + } } return NULL; } -void -u_setfaction(unit * u, faction * f) +void u_setfaction(unit * u, faction * f) { int cnt = u->number; - if (u->faction==f) return; + if (u->faction == f) + return; if (u->faction) { set_number(u, 0); - if (count_unit(u)) --u->faction->no_units; + if (count_unit(u)) + --u->faction->no_units; join_group(u, NULL); free_orders(&u->orders); set_order(&u->thisorder, NULL); - if (u->nextF) u->nextF->prevF = u->prevF; - if (u->prevF) u->prevF->nextF = u->nextF; - else u->faction->units = u->nextF; + if (u->nextF) + u->nextF->prevF = u->prevF; + if (u->prevF) + u->prevF->nextF = u->nextF; + else + u->faction->units = u->nextF; } - if (f!=NULL) { - if (f->units) f->units->prevF=u; + if (f != NULL) { + if (f->units) + f->units->prevF = u; u->prevF = NULL; u->nextF = f->units; f->units = u; - } - else u->nextF = NULL; + } else + u->nextF = NULL; u->faction = f; - if (u->region) update_interval(f, u->region); + if (u->region) + update_interval(f, u->region); if (cnt && f) { set_number(u, cnt); - if (count_unit(u)) ++f->no_units; + if (count_unit(u)) + ++f->no_units; } } /* vorsicht Sprüche können u->number == RS_FARVISION haben! */ -void -set_number(unit * u, int count) +void set_number(unit * u, int count) { - assert (count >= 0); - assert (count <= UNIT_MAXSIZE); + assert(count >= 0); + assert(count <= UNIT_MAXSIZE); #ifndef NDEBUG - assert(u->faction || count==0); + assert(u->faction || count == 0); #endif if (count == 0) { @@ -1117,21 +1194,23 @@ set_number(unit * u, int count) u->faction->num_people += count - u->number; } u->number = (unsigned short)count; - } else if (u->number>0) { - assert(!"why doesn't this unit have a faction? this will fuck up num_people"); + } else if (u->number > 0) { + assert + (!"why doesn't this unit have a faction? this will fuck up num_people"); } } -boolean -learn_skill(unit * u, skill_t sk, double chance) +boolean learn_skill(unit * u, skill_t sk, double chance) { - skill * sv = u->skills; - if (chance < 1.0 && rng_int()%10000>=chance*10000) return false; + skill *sv = u->skills; + + if (chance < 1.0 && rng_int() % 10000 >= chance * 10000) + return false; while (sv != u->skills + u->skill_size) { - assert (sv->weeks>0); + assert(sv->weeks > 0); if (sv->id == sk) { - if (sv->weeks<=1) { - sk_set(sv, sv->level+1); + if (sv->weeks <= 1) { + sk_set(sv, sv->level + 1); } else { sv->weeks--; } @@ -1144,14 +1223,15 @@ learn_skill(unit * u, skill_t sk, double chance) return true; } -void -remove_skill(unit *u, skill_t sk) +void remove_skill(unit * u, skill_t sk) { - skill * sv = u->skills; + skill *sv = u->skills; + for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - if (sv->id==sk) { - skill * sl = u->skills + u->skill_size - 1; - if (sl!=sv) { + if (sv->id == sk) { + skill *sl = u->skills + u->skill_size - 1; + + if (sl != sv) { *sv = *sl; } --u->skill_size; @@ -1160,10 +1240,10 @@ remove_skill(unit *u, skill_t sk) } } -skill * -add_skill(unit * u, skill_t id) +skill *add_skill(unit * u, skill_t id) { - skill * sv = u->skills; + skill *sv = u->skills; + #ifndef NDEBUG for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { assert(sv->id != id); @@ -1174,55 +1254,55 @@ add_skill(unit * u, skill_t id) sv = (u->skills + u->skill_size - 1); sv->level = (unsigned char)0; sv->weeks = (unsigned char)1; - sv->old = (unsigned char)0; - sv->id = (unsigned char)id; + sv->old = (unsigned char)0; + sv->id = (unsigned char)id; return sv; } -skill * -get_skill(const unit * u, skill_t sk) +skill *get_skill(const unit * u, skill_t sk) { - skill * sv = u->skills; - while (sv!=u->skills+u->skill_size) { - if (sv->id==sk) return sv; + skill *sv = u->skills; + + while (sv != u->skills + u->skill_size) { + if (sv->id == sk) + return sv; ++sv; } return NULL; } -boolean -has_skill(const unit * u, skill_t sk) +boolean has_skill(const unit * u, skill_t sk) { - skill * sv = u->skills; - while (sv!=u->skills+u->skill_size) { - if (sv->id==sk) { - return (sv->level>0); + skill *sv = u->skills; + + while (sv != u->skills + u->skill_size) { + if (sv->id == sk) { + return (sv->level > 0); } ++sv; } return false; } -static int -item_modification(const unit *u, skill_t sk, int val) +static int item_modification(const unit * u, skill_t sk, int val) { /* Presseausweis: *2 Spionage, 0 Tarnung */ - if(sk == SK_SPY && get_item(u, I_PRESSCARD) >= u->number) { + if (sk == SK_SPY && get_item(u, I_PRESSCARD) >= u->number) { val = val * 2; - } else if(sk == SK_STEALTH) { + } else if (sk == SK_STEALTH) { #if NEWATSROI == 1 if (get_item(u, I_RING_OF_INVISIBILITY) + 100 * get_item(u, I_SPHERE_OF_INVISIBILITY) >= u->number) { - val += ROIBONUS; + val += ROIBONUS; } #endif - if(get_item(u, I_PRESSCARD) >= u->number) { + if (get_item(u, I_PRESSCARD) >= u->number) { val = 0; } } #if NEWATSROI == 1 - if(sk == SK_PERCEPTION) { - if(get_item(u, I_AMULET_OF_TRUE_SEEING) >= u->number) { + if (sk == SK_PERCEPTION) { + if (get_item(u, I_AMULET_OF_TRUE_SEEING) >= u->number) { val += ATSBONUS; } } @@ -1230,30 +1310,37 @@ item_modification(const unit *u, skill_t sk, int val) return val; } -static int -att_modification(const unit *u, skill_t sk) +static int att_modification(const unit * u, skill_t sk) { double bonus = 0, malus = 0; - attrib * a; - double result = 0; - static boolean init = false; - static const curse_type * skillmod_ct, * gbdream_ct, * worse_ct; - curse * c; - if (!init) { - init = true; - skillmod_ct = ct_find("skillmod"); + attrib *a; + + double result = 0; + + static boolean init = false; + + static const curse_type *skillmod_ct, *gbdream_ct, *worse_ct; + + curse *c; + + if (!init) { + init = true; + skillmod_ct = ct_find("skillmod"); gbdream_ct = ct_find("gbdream"); worse_ct = ct_find("worse"); } c = get_curse(u->attribs, worse_ct); - if (c!=NULL) result += curse_geteffect(c); + if (c != NULL) + result += curse_geteffect(c); if (skillmod_ct) { - attrib * a = a_find(u->attribs, &at_curse); - while (a && a->type==&at_curse) { - curse * c = (curse *)a->data.v; - if (c->type==skillmod_ct && c->data.i==sk) { + attrib *a = a_find(u->attribs, &at_curse); + + while (a && a->type == &at_curse) { + curse *c = (curse *) a->data.v; + + if (c->type == skillmod_ct && c->data.i == sk) { result += curse_geteffect(c); break; } @@ -1262,17 +1349,21 @@ att_modification(const unit *u, skill_t sk) } /* TODO hier kann nicht mit get/iscursed gearbeitet werden, da nur der - * jeweils erste vom Typ C_GBDREAM zurückgegen wird, wir aber alle - * durchsuchen und aufaddieren müssen */ + * jeweils erste vom Typ C_GBDREAM zurückgegen wird, wir aber alle + * durchsuchen und aufaddieren müssen */ a = a_find(u->region->attribs, &at_curse); - while (a && a->type==&at_curse) { - curse * c = (curse*)a->data.v; - if (curse_active(c) && c->type==gbdream_ct) { + while (a && a->type == &at_curse) { + curse *c = (curse *) a->data.v; + + if (curse_active(c) && c->type == gbdream_ct) { double mod = curse_geteffect(c); - unit * mage = c->magician; + + unit *mage = c->magician; + /* wir suchen jeweils den größten Bonus und den größten Malus */ - if (mod>bonus) { - if (mage==NULL || mage->number==0 || alliedunit(mage, u->faction, HELP_GUARD)) { + if (mod > bonus) { + if (mage == NULL || mage->number == 0 + || alliedunit(mage, u->faction, HELP_GUARD)) { bonus = mod; } } else if (mod < malus) { @@ -1289,15 +1380,19 @@ att_modification(const unit *u, skill_t sk) } int -get_modifier(const unit *u, skill_t sk, int level, const region *r, boolean noitem) +get_modifier(const unit * u, skill_t sk, int level, const region * r, + boolean noitem) { int bskill = level; + int skill = bskill; assert(r); if (sk == SK_STEALTH) { - plane * pl = rplane(r); - if (pl &&fval(pl, PFL_NOSTEALTH)) return 0; + plane *pl = rplane(r); + + if (pl && fval(pl, PFL_NOSTEALTH)) + return 0; } skill += rc_skillmod(u->race, r, sk); @@ -1310,23 +1405,24 @@ get_modifier(const unit *u, skill_t sk, int level, const region *r, boolean noit #ifdef HUNGER_REDUCES_SKILL if (fval(u, UFL_HUNGER)) { - skill = skill/2; + skill = skill / 2; } #endif return skill - bskill; } -int -eff_skill(const unit * u, skill_t sk, const region * r) +int eff_skill(const unit * u, skill_t sk, const region * r) { if (skill_enabled[sk]) { int level = get_level(u, sk); - if (level>0) { + + if (level > 0) { int mlevel = level + get_modifier(u, sk, level, r, false); - if (mlevel>0) { + if (mlevel > 0) { int skillcap = SkillCap(sk); - if (skillcap && mlevel>skillcap) { + + if (skillcap && mlevel > skillcap) { return skillcap; } return mlevel; @@ -1336,30 +1432,34 @@ eff_skill(const unit * u, skill_t sk, const region * r) return 0; } -int -eff_skill_study(const unit * u, skill_t sk, const region * r) +int eff_skill_study(const unit * u, skill_t sk, const region * r) { int level = get_level(u, sk); - if (level>0) { + + if (level > 0) { int mlevel = level + get_modifier(u, sk, level, r, true); - if (mlevel>0) return mlevel; + if (mlevel > 0) + return mlevel; } return 0; } -int -invisible(const unit *target, const unit * viewer) +int invisible(const unit * target, const unit * viewer) { #if NEWATSROI == 1 return 0; #else - if (viewer && viewer->faction==target->faction) return 0; + if (viewer && viewer->faction == target->faction) + return 0; else { - int hidden = get_item(target, I_RING_OF_INVISIBILITY) + 100 * get_item(target, I_SPHERE_OF_INVISIBILITY); + int hidden = + get_item(target, I_RING_OF_INVISIBILITY) + 100 * get_item(target, + I_SPHERE_OF_INVISIBILITY); if (hidden) { hidden = MIN(hidden, target->number); - if (viewer) hidden -= get_item(viewer, I_AMULET_OF_TRUE_SEEING); + if (viewer) + hidden -= get_item(viewer, I_AMULET_OF_TRUE_SEEING); } return hidden; } @@ -1371,43 +1471,46 @@ invisible(const unit *target, const unit * viewer) * and you should already have called uunhash and removed the unit from the * region. */ -void -free_unit(unit * u) +void free_unit(unit * u) { free(u->name); free(u->display); free_order(u->thisorder); free_orders(&u->orders); - if (u->skills) free(u->skills); + if (u->skills) + free(u->skills); while (u->items) { - item * it = u->items->next; + item *it = u->items->next; + u->items->next = NULL; i_free(u->items); u->items = it; } - while (u->attribs) a_remove (&u->attribs, u->attribs); + while (u->attribs) + a_remove(&u->attribs, u->attribs); while (u->reservations) { struct reservation *res = u->reservations; + u->reservations = res->next; free(res); } } -static void -createunitid(unit *u, int id) +static void createunitid(unit * u, int id) { - if (id<=0 || id > MAX_UNIT_NR || ufindhash(id) || dfindhash(id) || forbiddenid(id)) + if (id <= 0 || id > MAX_UNIT_NR || ufindhash(id) || dfindhash(id) + || forbiddenid(id)) u->no = newunitid(); else u->no = id; uhash(u); } -void -name_unit(unit *u) +void name_unit(unit * u) { if (u->race->generate_name) { - const char * gen_name = u->race->generate_name(u); + const char *gen_name = u->race->generate_name(u); + if (gen_name) { unit_setname(u, gen_name); } else { @@ -1415,7 +1518,9 @@ name_unit(unit *u) } } else { char name[32]; - snprintf(name, sizeof(name), "%s %s", LOC(u->faction->locale, "unitdefault"), itoa36(u->no)); + + snprintf(name, sizeof(name), "%s %s", LOC(u->faction->locale, + "unitdefault"), itoa36(u->no)); unit_setname(u, name); } } @@ -1425,17 +1530,18 @@ name_unit(unit *u) * @param dname: name, set to NULL to get a default. * @param creator: unit to inherit stealth, group, building, ship, etc. from */ -unit * -create_unit(region * r, faction * f, int number, const struct race *urace, int id, const char * dname, unit *creator) +unit *create_unit(region * r, faction * f, int number, const struct race *urace, + int id, const char *dname, unit * creator) { - unit * u = calloc(1, sizeof(unit)); + unit *u = calloc(1, sizeof(unit)); assert(urace); assert(f->alive); u_setfaction(u, f); if (f->locale) { - order * deford = default_order(f->locale); + order *deford = default_order(f->locale); + if (deford) { set_order(&u->thisorder, NULL); addlist(&u->orders, deford); @@ -1448,12 +1554,13 @@ create_unit(region * r, faction * f, int number, const struct race *urace, int i set_number(u, number); /* die nummer der neuen einheit muss vor name_unit generiert werden, - * da der default name immer noch 'Nummer u->no' ist */ + * da der default name immer noch 'Nummer u->no' ist */ createunitid(u, id); /* zuerst in die Region setzen, da zb Drachennamen den Regionsnamen - * enthalten */ - if (r) move_unit(u, r, NULL); + * enthalten */ + if (r) + move_unit(u, r, NULL); /* u->race muss bereits gesetzt sein, wird für default-hp gebraucht */ /* u->region auch */ @@ -1464,27 +1571,30 @@ create_unit(region * r, faction * f, int number, const struct race *urace, int i } else { u->name = strdup(dname); } - if (count_unit(u)) f->no_units++; + if (count_unit(u)) + f->no_units++; if (creator) { - attrib * a; + attrib *a; /* erbt Kampfstatus */ setstatus(u, creator->status); - /* erbt Gebäude/Schiff*/ - if (creator->region==r) { + /* erbt Gebäude/Schiff */ + if (creator->region == r) { u->building = creator->building; - if (creator->ship!=NULL && fval(u->race, RCF_CANSAIL)) { + if (creator->ship != NULL && fval(u->race, RCF_CANSAIL)) { u->ship = creator->ship; } } /* Tarnlimit wird vererbt */ if (fval(creator, UFL_STEALTH)) { - attrib * a = a_find(creator->attribs, &at_stealth); + attrib *a = a_find(creator->attribs, &at_stealth); + if (a) { int stealth = a->data.i; + a = a_add(&u->attribs, a_new(&at_stealth)); a->data.i = stealth; } @@ -1501,10 +1611,11 @@ create_unit(region * r, faction * f, int number, const struct race *urace, int i } /* Gruppen */ - if (creator->faction==f && fval(creator, UFL_GROUP)) { + if (creator->faction == f && fval(creator, UFL_GROUP)) { a = a_find(creator->attribs, &at_group); if (a) { - group * g = (group*)a->data.v; + group *g = (group *) a->data.v; + set_group(u, g); } } @@ -1520,191 +1631,200 @@ create_unit(region * r, faction * f, int number, const struct race *urace, int i return u; } -int -maxheroes(const struct faction * f) +int maxheroes(const struct faction *f) { int nsize = count_all(f); - if (nsize==0) return 0; + + if (nsize == 0) + return 0; else { int nmax = (int)(log10(nsize / 50.0) * 20); - return (nmax<0)?0:nmax; + + return (nmax < 0) ? 0 : nmax; } } -int -countheroes(const struct faction * f) +int countheroes(const struct faction *f) { - const unit * u = f->units; + const unit *u = f->units; + int n = 0; while (u) { - if (fval(u, UFL_HERO)) n+= u->number; + if (fval(u, UFL_HERO)) + n += u->number; u = u->nextF; } #ifdef DEBUG_MAXHEROES int m = maxheroes(f); - if (n>m) { + + if (n > m) { log_warning(("%s has %d of %d heroes\n", factionname(f), n, m)); } #endif return n; } -const char * -unit_getname(const unit * u) +const char *unit_getname(const unit * u) { return (const char *)u->name; } -void -unit_setname(unit * u, const char * name) +void unit_setname(unit * u, const char *name) { free(u->name); - if (name) u->name = strdup(name); - else u->name = NULL; + if (name) + u->name = strdup(name); + else + u->name = NULL; } -const char * -unit_getinfo(const unit * u) +const char *unit_getinfo(const unit * u) { return (const char *)u->display; } -void -unit_setinfo(unit * u, const char * info) +void unit_setinfo(unit * u, const char *info) { free(u->display); - if (info) u->display = strdup(info); - else u->display = NULL; + if (info) + u->display = strdup(info); + else + u->display = NULL; } -int -unit_getid(const unit * u) +int unit_getid(const unit * u) { return u->no; } -void -unit_setid(unit * u, int id) +void unit_setid(unit * u, int id) { - unit * nu = findunit(id); - if (nu==NULL) { + unit *nu = findunit(id); + + if (nu == NULL) { uunhash(u); u->no = id; uhash(u); } } -int -unit_gethp(const unit * u) +int unit_gethp(const unit * u) { return u->hp; } -void -unit_sethp(unit * u, int hp) +void unit_sethp(unit * u, int hp) { u->hp = hp; } -status_t -unit_getstatus(const unit * u) +status_t unit_getstatus(const unit * u) { return u->status; } -void -unit_setstatus(unit * u, status_t status) +void unit_setstatus(unit * u, status_t status) { u->status = status; } -int -unit_getweight(const unit * u) +int unit_getweight(const unit * u) { return weight(u); } -int -unit_getcapacity(const unit * u) +int unit_getcapacity(const unit * u) { return walkingcapacity(u); } -void -unit_addorder(unit * u, order * ord) +void unit_addorder(unit * u, order * ord) { - order ** ordp = &u->orders; - while (*ordp) ordp = &(*ordp)->next; + order **ordp = &u->orders; + + while (*ordp) + ordp = &(*ordp)->next; *ordp = ord; u->faction->lastorders = turn; } -int -unit_max_hp(const unit * u) +int unit_max_hp(const unit * u) { static int rules_stamina = -1; - int h; - double p; - static const curse_type * heal_ct = NULL; - if (rules_stamina<0) { - rules_stamina = get_param_int(global.parameters, "rules.stamina", STAMINA_AFFECTS_HP); + int h; + + double p; + + static const curse_type *heal_ct = NULL; + + if (rules_stamina < 0) { + rules_stamina = + get_param_int(global.parameters, "rules.stamina", STAMINA_AFFECTS_HP); } h = u->race->hitpoints; - if (heal_ct==NULL) heal_ct = ct_find("healingzone"); + if (heal_ct == NULL) + heal_ct = ct_find("healingzone"); if (rules_stamina & 1) { p = pow(effskill(u, SK_STAMINA) / 2.0, 1.5) * 0.2; - h += (int) (h * p + 0.5); + h += (int)(h * p + 0.5); } /* der healing curse verändert die maximalen hp */ if (heal_ct) { curse *c = get_curse(u->region->attribs, heal_ct); + if (c) { - h = (int) (h * (1.0+(curse_geteffect(c)/100))); + h = (int)(h * (1.0 + (curse_geteffect(c) / 100))); } } return h; } -void -scale_number (unit * u, int n) +void scale_number(unit * u, int n) { skill_t sk; - const attrib * a; + + const attrib *a; + int remain; - if (n == u->number) return; - if (n && u->number>0) { + if (n == u->number) + return; + if (n && u->number > 0) { int full; - remain = ((u->hp%u->number) * (n % u->number)) % u->number; - full = u->hp/u->number; /* wieviel kriegt jede person mindestens */ - u->hp = full * n + (u->hp-full*u->number) * n / u->number; - assert(u->hp>=0); + remain = ((u->hp % u->number) * (n % u->number)) % u->number; + + full = u->hp / u->number; /* wieviel kriegt jede person mindestens */ + u->hp = full * n + (u->hp - full * u->number) * n / u->number; + assert(u->hp >= 0); if ((rng_int() % u->number) < remain) - ++u->hp; /* Nachkommastellen */ + ++u->hp; /* Nachkommastellen */ } else { remain = 0; u->hp = 0; } - if (u->number>0) { - for (a = a_find(u->attribs, &at_effect);a && a->type==&at_effect;a=a->next) { - effect_data * data = (effect_data *)a->data.v; + if (u->number > 0) { + for (a = a_find(u->attribs, &at_effect); a && a->type == &at_effect; + a = a->next) { + effect_data *data = (effect_data *) a->data.v; + int snew = data->value / u->number * n; + if (n) { remain = data->value - snew / n * u->number; snew += remain * n / u->number; remain = (remain * n) % u->number; if ((rng_int() % u->number) < remain) - ++snew; /* Nachkommastellen */ + ++snew; /* Nachkommastellen */ } data->value = snew; } } - if (u->number==0 || n==0) { + if (u->number == 0 || n == 0) { for (sk = 0; sk < MAXSKILLS; sk++) { remove_skill(u, sk); } @@ -1713,7 +1833,7 @@ scale_number (unit * u, int n) set_number(u, n); } -const struct race * u_irace(const struct unit * u) +const struct race *u_irace(const struct unit *u) { if (u->irace && skill_enabled[SK_STEALTH]) { return u->irace; diff --git a/src/kernel/unit.h b/src/kernel/unit.h index 3eb2de3d9..ab5ace449 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -26,36 +26,36 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -struct skill; -struct item; + struct skill; + struct item; #define UFL_DEBUG (1<<0) -#define UFL_ISNEW (1<<1) /* 2 */ -#define UFL_LONGACTION (1<<2) /* 4 */ -#define UFL_OWNER (1<<3) /* 8 */ -#define UFL_ANON_FACTION (1<<4) /* 16 */ -#define UFL_DISBELIEVES (1<<5) /* 32 */ -#define UFL_WARMTH (1<<6) /* 64 */ +#define UFL_ISNEW (1<<1) /* 2 */ +#define UFL_LONGACTION (1<<2) /* 4 */ +#define UFL_OWNER (1<<3) /* 8 */ +#define UFL_ANON_FACTION (1<<4) /* 16 */ +#define UFL_DISBELIEVES (1<<5) /* 32 */ +#define UFL_WARMTH (1<<6) /* 64 */ #define UFL_HERO (1<<7) #define UFL_MOVED (1<<8) -#define UFL_NOTMOVING (1<<9) /* Die Einheit kann sich wg. langen Kampfes nicht bewegen */ +#define UFL_NOTMOVING (1<<9) /* Die Einheit kann sich wg. langen Kampfes nicht bewegen */ #define UFL_DEFENDER (1<<10) -#define UFL_HUNGER (1<<11) /* kann im Folgemonat keinen langen Befehl außer ARBEITE ausführen */ -#define UFL_SIEGE (1<<12) /* speedup: belagert eine burg, siehe attribut */ -#define UFL_TARGET (1<<13) /* speedup: hat ein target, siehe attribut */ +#define UFL_HUNGER (1<<11) /* kann im Folgemonat keinen langen Befehl außer ARBEITE ausführen */ +#define UFL_SIEGE (1<<12) /* speedup: belagert eine burg, siehe attribut */ +#define UFL_TARGET (1<<13) /* speedup: hat ein target, siehe attribut */ #define UFL_WERE (1<<14) -#define UFL_ENTER (1<<15) /* unit has entered a ship/building and will not leave it */ +#define UFL_ENTER (1<<15) /* unit has entered a ship/building and will not leave it */ /* warning: von 512/1024 gewechslet, wegen konflikt mit NEW_FOLLOW */ -#define UFL_LOCKED (1<<16) /* Einheit kann keine Personen aufnehmen oder weggeben, nicht rekrutieren. */ -#define UFL_FLEEING (1<<17) /* unit was in a battle, fleeing. */ -#define UFL_STORM (1<<19) /* Kapitän war in einem Sturm */ +#define UFL_LOCKED (1<<16) /* Einheit kann keine Personen aufnehmen oder weggeben, nicht rekrutieren. */ +#define UFL_FLEEING (1<<17) /* unit was in a battle, fleeing. */ +#define UFL_STORM (1<<19) /* Kapitän war in einem Sturm */ #define UFL_FOLLOWING (1<<20) #define UFL_FOLLOWED (1<<21) -#define UFL_NOAID (1<<22) /* Einheit hat Noaid-Status */ -#define UFL_MARK (1<<23) /* same as FL_MARK */ -#define UFL_ORDERS (1<<24) /* Einheit hat Befehle erhalten */ -#define UFL_TAKEALL (1<<25) /* Einheit nimmt alle Gegenstände an */ +#define UFL_NOAID (1<<22) /* Einheit hat Noaid-Status */ +#define UFL_MARK (1<<23) /* same as FL_MARK */ +#define UFL_ORDERS (1<<24) /* Einheit hat Befehle erhalten */ +#define UFL_TAKEALL (1<<25) /* Einheit nimmt alle Gegenstände an */ /* flags that speed up attribute access: */ #define UFL_STEALTH (1<<26) @@ -66,163 +66,170 @@ struct item; #define UFL_SAVEMASK (UFL_DEFENDER|UFL_MOVED|UFL_NOAID|UFL_OWNER|UFL_ANON_FACTION|UFL_LOCKED|UFL_HUNGER|UFL_TAKEALL|UFL_GUARD|UFL_STEALTH|UFL_GROUP|UFL_HERO) #define UNIT_MAXSIZE 50000 -extern int maxheroes(const struct faction * f); -extern int countheroes(const struct faction * f); + extern int maxheroes(const struct faction *f); + extern int countheroes(const struct faction *f); -typedef struct unit { - struct unit *next; /* needs to be first entry, for region's unitlist */ - struct unit *nextF; /* nächste Einheit der Partei */ - struct unit *prevF; /* vorherige Einheit der Partei */ - struct region *region; - int no; - int hp; - char *name; - char *display; - struct faction *faction; - struct building *building; - struct ship *ship; - unsigned short number; - short age; + typedef struct unit { + struct unit *next; /* needs to be first entry, for region's unitlist */ + struct unit *nextF; /* nächste Einheit der Partei */ + struct unit *prevF; /* vorherige Einheit der Partei */ + struct region *region; + int no; + int hp; + char *name; + char *display; + struct faction *faction; + struct building *building; + struct ship *ship; + unsigned short number; + short age; - /* skill data */ - short skill_size; - struct skill *skills; - struct item * items; - struct reservation { - struct reservation * next; - const struct resource_type * type; - int value; - } * reservations; + /* skill data */ + short skill_size; + struct skill *skills; + struct item *items; + struct reservation { + struct reservation *next; + const struct resource_type *type; + int value; + } *reservations; - /* orders */ - struct order * orders; - struct order * thisorder; - struct order * old_orders; + /* orders */ + struct order *orders; + struct order *thisorder; + struct order *old_orders; - /* race and illusionary race */ - const struct race * race; - const struct race * irace; + /* race and illusionary race */ + const struct race *race; + const struct race *irace; - unsigned int flags; - struct attrib * attribs; - status_t status; - int n; /* enno: attribut? */ - int wants; /* enno: attribut? */ -} unit; + unsigned int flags; + struct attrib *attribs; + status_t status; + int n; /* enno: attribut? */ + int wants; /* enno: attribut? */ + } unit; -extern struct attrib_type at_alias; -extern struct attrib_type at_siege; -extern struct attrib_type at_target; -extern struct attrib_type at_potionuser; -extern struct attrib_type at_contact; -extern struct attrib_type at_effect; -extern struct attrib_type at_private; -extern struct attrib_type at_showskchange; + extern struct attrib_type at_alias; + extern struct attrib_type at_siege; + extern struct attrib_type at_target; + extern struct attrib_type at_potionuser; + extern struct attrib_type at_contact; + extern struct attrib_type at_effect; + extern struct attrib_type at_private; + extern struct attrib_type at_showskchange; -int ualias(const struct unit * u); + int ualias(const struct unit *u); -extern struct attrib_type at_stealth; + extern struct attrib_type at_stealth; -void u_seteffstealth(struct unit * u, int value); -int u_geteffstealth(const struct unit * u); -const struct race * u_irace(const struct unit * u); -struct building * usiege(const struct unit * u); -void usetsiege(struct unit * u, const struct building * b); + void u_seteffstealth(struct unit *u, int value); + int u_geteffstealth(const struct unit *u); + const struct race *u_irace(const struct unit *u); + struct building *usiege(const struct unit *u); + void usetsiege(struct unit *u, const struct building *b); -struct unit * utarget(const struct unit * u); -void usettarget(struct unit * u, const struct unit * b); + struct unit *utarget(const struct unit *u); + void usettarget(struct unit *u, const struct unit *b); -struct unit * utarget(const struct unit * u); -void usettarget(struct unit * u, const struct unit * b); + struct unit *utarget(const struct unit *u); + void usettarget(struct unit *u, const struct unit *b); -extern const struct race * urace(const struct unit * u); + extern const struct race *urace(const struct unit *u); -const char * uprivate(const struct unit * u); -void usetprivate(struct unit * u, const char * c); + const char *uprivate(const struct unit *u); + void usetprivate(struct unit *u, const char *c); -const struct potion_type * ugetpotionuse(const struct unit * u); /* benutzt u einein trank? */ -void usetpotionuse(struct unit * u, const struct potion_type * p); /* u benutzt trank p (es darf halt nur einer pro runde) */ + const struct potion_type *ugetpotionuse(const struct unit *u); /* benutzt u einein trank? */ + void usetpotionuse(struct unit *u, const struct potion_type *p); /* u benutzt trank p (es darf halt nur einer pro runde) */ -boolean ucontact(const struct unit * u, const struct unit * u2); -void usetcontact(struct unit * u, const struct unit * c); + boolean ucontact(const struct unit *u, const struct unit *u2); + void usetcontact(struct unit *u, const struct unit *c); -struct unit * findnewunit (const struct region * r, const struct faction *f, int alias); + struct unit *findnewunit(const struct region *r, const struct faction *f, + int alias); -extern const char * u_description(const unit * u, const struct locale * lang); -extern struct skill * add_skill(struct unit * u, skill_t id); -extern void remove_skill(struct unit *u, skill_t sk); -extern struct skill * get_skill(const struct unit * u, skill_t id); -extern boolean has_skill(const unit* u, skill_t sk); + extern const char *u_description(const unit * u, const struct locale *lang); + extern struct skill *add_skill(struct unit *u, skill_t id); + extern void remove_skill(struct unit *u, skill_t sk); + extern struct skill *get_skill(const struct unit *u, skill_t id); + extern boolean has_skill(const unit * u, skill_t sk); -extern void set_level(struct unit * u, skill_t id, int level); -extern int get_level(const struct unit * u, skill_t id); -extern void transfermen(struct unit * u, struct unit * u2, int n); + extern void set_level(struct unit *u, skill_t id, int level); + extern int get_level(const struct unit *u, skill_t id); + extern void transfermen(struct unit *u, struct unit *u2, int n); -extern int eff_skill(const struct unit * u, skill_t sk, const struct region * r); -extern int eff_skill_study(const struct unit * u, skill_t sk, const struct region * r); + extern int eff_skill(const struct unit *u, skill_t sk, + const struct region *r); + extern int eff_skill_study(const struct unit *u, skill_t sk, + const struct region *r); -extern int get_modifier(const struct unit * u, skill_t sk, int lvl, const struct region * r, boolean noitem); -extern int remove_unit(struct unit ** ulist, struct unit * u); + extern int get_modifier(const struct unit *u, skill_t sk, int lvl, + const struct region *r, boolean noitem); + extern int remove_unit(struct unit **ulist, struct unit *u); #define GIFT_SELF 1<<0 #define GIFT_FRIENDS 1<<1 #define GIFT_PEASANTS 1<<2 -int gift_items(struct unit * u, int flags); -void make_zombie(unit * u); + int gift_items(struct unit *u, int flags); + void make_zombie(unit * u); /* see resolve.h */ -extern int resolve_unit(variant data, void * address); -extern void write_unit_reference(const struct unit * u, struct storage * store); -extern variant read_unit_reference(struct storage * store); + extern int resolve_unit(variant data, void *address); + extern void write_unit_reference(const struct unit *u, struct storage *store); + extern variant read_unit_reference(struct storage *store); -extern boolean leave(struct unit * u, boolean force); -extern boolean can_leave(struct unit * u); + extern boolean leave(struct unit *u, boolean force); + extern boolean can_leave(struct unit *u); -extern void leave_ship(unit * u); -extern void leave_building(unit * u); + extern void leave_ship(unit * u); + extern void leave_building(unit * u); -extern void set_leftship(struct unit *u, struct ship *sh); -extern struct ship * leftship(const struct unit *); -extern boolean can_survive(const struct unit *u, const struct region *r); -extern void move_unit(struct unit * u, struct region * target, struct unit ** ulist); + extern void set_leftship(struct unit *u, struct ship *sh); + extern struct ship *leftship(const struct unit *); + extern boolean can_survive(const struct unit *u, const struct region *r); + extern void move_unit(struct unit *u, struct region *target, + struct unit **ulist); -extern struct building * inside_building(const struct unit * u); + extern struct building *inside_building(const struct unit *u); /* cleanup code for this module */ -extern void free_units(void); -extern struct faction * dfindhash(int no); -extern void u_setfaction(struct unit * u, struct faction * f); -extern void set_number(struct unit * u, int count); + extern void free_units(void); + extern struct faction *dfindhash(int no); + extern void u_setfaction(struct unit *u, struct faction *f); + extern void set_number(struct unit *u, int count); -extern boolean learn_skill(struct unit * u, skill_t sk, double chance); + extern boolean learn_skill(struct unit *u, skill_t sk, double chance); -extern int invisible(const struct unit *target, const struct unit * viewer); -extern void free_unit(struct unit * u); + extern int invisible(const struct unit *target, const struct unit *viewer); + extern void free_unit(struct unit *u); -extern void name_unit(struct unit *u); -extern struct unit * create_unit(struct region * r1, struct faction * f, int number, const struct race * rc, int id, const char * dname, struct unit *creator); + extern void name_unit(struct unit *u); + extern struct unit *create_unit(struct region *r1, struct faction *f, + int number, const struct race *rc, int id, const char *dname, + struct unit *creator); -extern void uhash(struct unit * u); -extern void uunhash(struct unit * u); -extern struct unit *ufindhash(int i); + extern void uhash(struct unit *u); + extern void uunhash(struct unit *u); + extern struct unit *ufindhash(int i); -const char * unit_getname(const struct unit * u); -void unit_setname(struct unit * u, const char * name); -const char * unit_getinfo(const struct unit * u); -void unit_setinfo(struct unit * u, const char * name); -int unit_getid(const unit * u); -void unit_setid(unit * u, int id); -int unit_gethp(const unit * u); -void unit_sethp(unit * u, int id); -status_t unit_getstatus(const unit * u); -void unit_setstatus(unit * u, status_t status); -int unit_getweight(const unit * u); -int unit_getcapacity(const unit * u); -void unit_addorder(unit * u, struct order * ord); -int unit_max_hp(const struct unit * u); -void scale_number(struct unit * u, int n); + const char *unit_getname(const struct unit *u); + void unit_setname(struct unit *u, const char *name); + const char *unit_getinfo(const struct unit *u); + void unit_setinfo(struct unit *u, const char *name); + int unit_getid(const unit * u); + void unit_setid(unit * u, int id); + int unit_gethp(const unit * u); + void unit_sethp(unit * u, int id); + status_t unit_getstatus(const unit * u); + void unit_setstatus(unit * u, status_t status); + int unit_getweight(const unit * u); + int unit_getcapacity(const unit * u); + void unit_addorder(unit * u, struct order *ord); + int unit_max_hp(const struct unit *u); + void scale_number(struct unit *u, int n); -extern struct attrib_type at_creator; + extern struct attrib_type at_creator; #ifdef __cplusplus } #endif diff --git a/src/kernel/version.h b/src/kernel/version.h index e1a792b7d..d2b6ba3b9 100644 --- a/src/kernel/version.h +++ b/src/kernel/version.h @@ -38,7 +38,7 @@ #define WATCHERS_VERSION 310 */ #define OVERRIDE_VERSION 311 -#define CURSETYPE_VERSION 312 /* turn 287 */ +#define CURSETYPE_VERSION 312 /* turn 287 */ #define ALLIANCES_VERSION 313 #define DBLINK_VERSION 314 #define CURSEVIGOURISFLOAT_VERSION 315 @@ -46,27 +46,27 @@ #define SAVEALLIANCE_VERSION 317 #define CLAIM_VERSION 318 /* 319 is the HSE4 data version */ -#define BACTION_VERSION 319 /* building action gets a param string */ +#define BACTION_VERSION 319 /* building action gets a param string */ #define NOLASTORDER_VERSION 320 /* do not use lastorder */ -#define SPELLNAME_VERSION 321 /* reference spells by name */ -#define TERRAIN_VERSION 322 /* terrains are a full type and saved by name */ +#define SPELLNAME_VERSION 321 /* reference spells by name */ +#define TERRAIN_VERSION 322 /* terrains are a full type and saved by name */ #define REGIONITEMS_VERSION 323 /* regions have items */ -#define ATTRIBREAD_VERSION 324 /* remove a_readint */ -#define CURSEFLAGS_VERSION 325 /* remove a_readint */ -#define UNICODE_VERSION 326 /* 2007-06-27 everything is stored as UTF8 */ -#define UID_VERSION 327 /* regions have a unique id */ -#define STORAGE_VERSION 328 /* with storage.h, some things are stored smarter (ids as base36, fractions as float) */ -#define INTPAK_VERSION 329 /* in binary, ints can get packed */ -#define NOZEROIDS_VERSION 330 /* 2008-05-16 zero is not a valid ID for anything (including factions) */ -#define NOBORDERATTRIBS_VERSION 331 /* 2008-05-17 connection::attribs has been moved to userdata */ -#define UIDHASH_VERSION 332 /* 2008-05-22 borders use the region.uid to store */ +#define ATTRIBREAD_VERSION 324 /* remove a_readint */ +#define CURSEFLAGS_VERSION 325 /* remove a_readint */ +#define UNICODE_VERSION 326 /* 2007-06-27 everything is stored as UTF8 */ +#define UID_VERSION 327 /* regions have a unique id */ +#define STORAGE_VERSION 328 /* with storage.h, some things are stored smarter (ids as base36, fractions as float) */ +#define INTPAK_VERSION 329 /* in binary, ints can get packed */ +#define NOZEROIDS_VERSION 330 /* 2008-05-16 zero is not a valid ID for anything (including factions) */ +#define NOBORDERATTRIBS_VERSION 331 /* 2008-05-17 connection::attribs has been moved to userdata */ +#define UIDHASH_VERSION 332 /* 2008-05-22 borders use the region.uid to store */ #define REGIONOWNER_VERSION 333 /* 2009-05-14 regions have owners and morale */ -#define ALLIANCELEADER_VERSION 333 /* alliances have a leader */ -#define CURSEFLOAT_VERSION 334 /* all curse-effects are float */ -#define MOURNING_VERSION 335 /* mourning peasants */ -#define FOSS_VERSION 336 /* the open source release */ -#define OWNER_2_VERSION 337 /* region owners contain an alliance */ -#define FIX_WATCHERS_VERSION 338 /* fixed storage of watchers */ +#define ALLIANCELEADER_VERSION 333 /* alliances have a leader */ +#define CURSEFLOAT_VERSION 334 /* all curse-effects are float */ +#define MOURNING_VERSION 335 /* mourning peasants */ +#define FOSS_VERSION 336 /* the open source release */ +#define OWNER_2_VERSION 337 /* region owners contain an alliance */ +#define FIX_WATCHERS_VERSION 338 /* fixed storage of watchers */ -#define MIN_VERSION CURSETYPE_VERSION /* minimal datafile we support */ -#define RELEASE_VERSION FIX_WATCHERS_VERSION /* current datafile */ +#define MIN_VERSION CURSETYPE_VERSION /* minimal datafile we support */ +#define RELEASE_VERSION FIX_WATCHERS_VERSION /* current datafile */ diff --git a/src/kernel/xmlkernel.h b/src/kernel/xmlkernel.h index b2cb331c4..b07b93ee5 100644 --- a/src/kernel/xmlkernel.h +++ b/src/kernel/xmlkernel.h @@ -19,10 +19,10 @@ extern "C" { #include -extern void xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, struct construction ** consPtr); + extern void xml_readconstruction(xmlXPathContextPtr xpath, + xmlNodeSetPtr nodeSet, struct construction **consPtr); #ifdef __cplusplus } #endif - #endif diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 6ead426d1..58d7b1577 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -52,12 +52,14 @@ without prior permission by the authors of Eressea. static boolean gamecode_enabled = false; -void (*set_spelldata_cb)(struct spell * sp) = 0; -static building_type * bt_get_or_create(const char * name) +void (*set_spelldata_cb) (struct spell * sp) = 0; + +static building_type *bt_get_or_create(const char *name) { - if (name!=NULL) { - building_type * btype = bt_find(name); - if (btype==NULL) { + if (name != NULL) { + building_type *btype = bt_find(name); + + if (btype == NULL) { btype = calloc(sizeof(building_type), 1); btype->_name = strdup(name); bt_register(btype); @@ -67,32 +69,33 @@ static building_type * bt_get_or_create(const char * name) return NULL; } -void -enable_xml_gamecode(void) +void enable_xml_gamecode(void) { gamecode_enabled = true; } -static void -xml_readtext(xmlNodePtr node, struct locale ** lang, xmlChar **text) +static void xml_readtext(xmlNodePtr node, struct locale **lang, xmlChar ** text) { - xmlChar * propValue = xmlGetProp(node, BAD_CAST "locale"); - assert(propValue!=NULL); - *lang = find_locale((const char*)propValue); + xmlChar *propValue = xmlGetProp(node, BAD_CAST "locale"); + + assert(propValue != NULL); + *lang = find_locale((const char *)propValue); #ifdef MAKE_LOCALES - if (*lang==NULL) *lang = make_locale((const char*)propValue); + if (*lang == NULL) + *lang = make_locale((const char *)propValue); #endif xmlFree(propValue); *text = xmlNodeListGetString(node->doc, node->children, 1); } -static const spell * -xml_spell(xmlNode * node, const char * name) +static const spell *xml_spell(xmlNode * node, const char *name) { - const spell * sp = NULL; - xmlChar * propValue = xmlGetProp(node, BAD_CAST name); - if (propValue!=NULL) { + const spell *sp = NULL; + + xmlChar *propValue = xmlGetProp(node, BAD_CAST name); + + if (propValue != NULL) { sp = find_spell(M_NONE, (const char *)propValue); assert(sp); xmlFree(propValue); @@ -100,11 +103,11 @@ xml_spell(xmlNode * node, const char * name) return sp; } -static xmlChar * -xml_cleanup_string(xmlChar * str) +static xmlChar *xml_cleanup_string(xmlChar * str) { - xmlChar * read = str; - xmlChar * write = str; + xmlChar *read = str; + + xmlChar *write = str; while (*read) { /* eat leading whitespace */ @@ -115,8 +118,10 @@ xml_cleanup_string(xmlChar * str) *write++ = ' '; } while (*read) { - if (*read== '\n') break; - if (*read== '\r') break; + if (*read == '\n') + break; + if (*read == '\r') + break; *write++ = *read++; } } @@ -124,13 +129,15 @@ xml_cleanup_string(xmlChar * str) return str; } -static const resource_type * -rt_findorcreate(const char * name) +static const resource_type *rt_findorcreate(const char *name) { - resource_type * rtype = rt_find(name); - if (rtype==NULL) { - const char * names[2]; - char * namep = strcat(strcpy((char*)malloc(strlen(name)+3), name), "_p"); + resource_type *rtype = rt_find(name); + + if (rtype == NULL) { + const char *names[2]; + + char *namep = strcat(strcpy((char *)malloc(strlen(name) + 3), name), "_p"); + /* we'll make a placeholder */ names[0] = name; names[1] = namep; @@ -144,22 +151,25 @@ static void xml_readrequirements(xmlNodePtr * nodeTab, int nodeNr, requirement ** reqArray) { int req; - requirement * radd = *reqArray; - assert (radd==NULL); - if (nodeNr==0) return; + requirement *radd = *reqArray; - radd = *reqArray = calloc(sizeof(requirement), nodeNr+1); + assert(radd == NULL); + if (nodeNr == 0) + return; - for (req=0;req!=nodeNr;++req) { + radd = *reqArray = calloc(sizeof(requirement), nodeNr + 1); + + for (req = 0; req != nodeNr; ++req) { xmlNodePtr node = nodeTab[req]; - xmlChar * propValue; + + xmlChar *propValue; radd->number = xml_ivalue(node, "quantity", 1); radd->recycle = xml_fvalue(node, "recycle", 0.5); propValue = xmlGetProp(node, BAD_CAST "type"); - radd->rtype = rt_findorcreate((const char*)propValue); + radd->rtype = rt_findorcreate((const char *)propValue); xmlFree(propValue); ++radd; @@ -167,30 +177,39 @@ xml_readrequirements(xmlNodePtr * nodeTab, int nodeNr, requirement ** reqArray) } void -xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, construction ** consPtr) +xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, + construction ** consPtr) { xmlNodePtr pushNode = xpath->node; + int k; - for (k=0;k!=nodeSet->nodeNr;++k) { + + for (k = 0; k != nodeSet->nodeNr; ++k) { xmlNodePtr node = nodeSet->nodeTab[k]; - xmlChar * propValue; - construction * con; + + xmlChar *propValue; + + construction *con; + xmlXPathObjectPtr req; + int m; + skill_t sk = NOSKILL; propValue = xmlGetProp(node, BAD_CAST "skill"); - if (propValue!=NULL) { - sk = sk_find((const char*)propValue); - if (sk==NOSKILL) { - log_error(("construction requires skill '%s' that does not exist.\n", (const char *)propValue)); + if (propValue != NULL) { + sk = sk_find((const char *)propValue); + if (sk == NOSKILL) { + log_error(("construction requires skill '%s' that does not exist.\n", + (const char *)propValue)); xmlFree(propValue); continue; } xmlFree(propValue); } - assert(*consPtr==NULL); + assert(*consPtr == NULL); *consPtr = con = calloc(sizeof(construction), 1); consPtr = &con->improvement; @@ -199,10 +218,10 @@ xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, constructi con->maxsize = xml_ivalue(node, "maxsize", -1); con->minskill = xml_ivalue(node, "minskill", -1); con->reqsize = xml_ivalue(node, "reqsize", -1); - + propValue = xmlGetProp(node, BAD_CAST "building"); - if (propValue!=NULL) { - con->btype = bt_get_or_create((const char*)propValue); + if (propValue != NULL) { + con->btype = bt_get_or_create((const char *)propValue); xmlFree(propValue); } @@ -216,13 +235,15 @@ xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, constructi /* read construction/modifier */ xpath->node = node; req = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); - for (m=0;m!=req->nodesetval->nodeNr;++m) { + for (m = 0; m != req->nodesetval->nodeNr; ++m) { xmlNodePtr node = req->nodesetval->nodeTab[m]; propValue = xmlGetProp(node, BAD_CAST "function"); - if (propValue!=NULL) { - pf_generic foo = get_function((const char*)propValue); - a_add(&con->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION, (skillmod_fun)foo, 1.0, 0)); + if (propValue != NULL) { + pf_generic foo = get_function((const char *)propValue); + + a_add(&con->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION, + (skillmod_fun) foo, 1.0, 0)); xmlFree(propValue); } @@ -236,10 +257,12 @@ static int parse_function(xmlNodePtr node, pf_generic * funPtr, xmlChar ** namePtr) { pf_generic fun; - xmlChar * propValue = xmlGetProp(node, BAD_CAST "value"); - assert(propValue!=NULL); - fun = get_function((const char*)propValue); - if (fun!=NULL) { + + xmlChar *propValue = xmlGetProp(node, BAD_CAST "value"); + + assert(propValue != NULL); + fun = get_function((const char *)propValue); + if (fun != NULL) { xmlFree(propValue); propValue = xmlGetProp(node, BAD_CAST "name"); @@ -249,27 +272,34 @@ parse_function(xmlNodePtr node, pf_generic * funPtr, xmlChar ** namePtr) return 0; } -static int -parse_buildings(xmlDocPtr doc) +static int parse_buildings(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr buildings; + int i; /* reading eressea/buildings/building */ - buildings = xmlXPathEvalExpression(BAD_CAST "/eressea/buildings/building", xpath); - if (buildings->nodesetval!=NULL) { + buildings = + xmlXPathEvalExpression(BAD_CAST "/eressea/buildings/building", xpath); + if (buildings->nodesetval != NULL) { xmlNodeSetPtr nodes = buildings->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { + + for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; - xmlChar * propValue; - building_type * btype; + + xmlChar *propValue; + + building_type *btype; + xmlXPathObjectPtr result; + int k; propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - btype = bt_get_or_create((const char*)propValue); + assert(propValue != NULL); + btype = bt_get_or_create((const char *)propValue); xmlFree(propValue); btype->capacity = xml_ivalue(node, "capacity", -1); @@ -281,13 +311,20 @@ parse_buildings(xmlDocPtr doc) btype->fumblebonus = xml_ivalue(node, "fumblebonus", 0); btype->auraregen = xml_fvalue(node, "auraregen", 1.0); - if (xml_bvalue(node, "nodestroy", false)) btype->flags |= BTF_INDESTRUCTIBLE; - if (xml_bvalue(node, "oneperturn", false)) btype->flags |= BTF_ONEPERTURN; - if (xml_bvalue(node, "nobuild", false)) btype->flags |= BTF_NOBUILD; - if (xml_bvalue(node, "namechange", true)) btype->flags |= BTF_NAMECHANGE; - if (xml_bvalue(node, "unique", false)) btype->flags |= BTF_UNIQUE; - if (xml_bvalue(node, "decay", false)) btype->flags |= BTF_DECAY; - if (xml_bvalue(node, "magic", false)) btype->flags |= BTF_MAGIC; + if (xml_bvalue(node, "nodestroy", false)) + btype->flags |= BTF_INDESTRUCTIBLE; + if (xml_bvalue(node, "oneperturn", false)) + btype->flags |= BTF_ONEPERTURN; + if (xml_bvalue(node, "nobuild", false)) + btype->flags |= BTF_NOBUILD; + if (xml_bvalue(node, "namechange", true)) + btype->flags |= BTF_NAMECHANGE; + if (xml_bvalue(node, "unique", false)) + btype->flags |= BTF_UNIQUE; + if (xml_bvalue(node, "decay", false)) + btype->flags |= BTF_DECAY; + if (xml_bvalue(node, "magic", false)) + btype->flags |= BTF_MAGIC; /* reading eressea/buildings/building/construction */ xpath->node = node; @@ -299,33 +336,37 @@ parse_buildings(xmlDocPtr doc) /* reading eressea/buildings/building/function */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { + for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; + pf_generic fun; + parse_function(node, &fun, &propValue); - if (fun==NULL) { + if (fun == NULL) { log_error(("unknown function name '%s' for building %s\n", - (const char*)propValue, btype->_name)); + (const char *)propValue, btype->_name)); xmlFree(propValue); continue; } - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "name")==0) { - btype->name = (const char * (*)(const struct building_type*, const struct building *, int))fun; - } else if (strcmp((const char*)propValue, "init")==0) { - btype->init = (void (*)(struct building_type*))fun; - } else if (strcmp((const char*)propValue, "age")==0) { - btype->age = (void (*)(struct building*))fun; - } else if (strcmp((const char*)propValue, "protection")==0) { - btype->protection = (int (*)(struct building*, struct unit *))fun; - } else if (strcmp((const char*)propValue, "taxes")==0) { - btype->taxes = (double (*)(const struct building*, int))fun; - } else if (strcmp((const char*)propValue, "age")==0) { - btype->age = (void (*)(struct building*))fun; + assert(propValue != NULL); + if (strcmp((const char *)propValue, "name") == 0) { + btype->name = + (const char *(*)(const struct building_type *, + const struct building *, int))fun; + } else if (strcmp((const char *)propValue, "init") == 0) { + btype->init = (void (*)(struct building_type *))fun; + } else if (strcmp((const char *)propValue, "age") == 0) { + btype->age = (void (*)(struct building *))fun; + } else if (strcmp((const char *)propValue, "protection") == 0) { + btype->protection = (int (*)(struct building *, struct unit *))fun; + } else if (strcmp((const char *)propValue, "taxes") == 0) { + btype->taxes = (double (*)(const struct building *, int))fun; + } else if (strcmp((const char *)propValue, "age") == 0) { + btype->age = (void (*)(struct building *))fun; } else { log_error(("unknown function type '%s' for building %s\n", - (const char*)propValue, btype->_name)); + (const char *)propValue, btype->_name)); } xmlFree(propValue); } @@ -334,30 +375,35 @@ parse_buildings(xmlDocPtr doc) /* reading eressea/buildings/building/maintenance */ result = xmlXPathEvalExpression(BAD_CAST "maintenance", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { + for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - maintenance * mt; - if (btype->maintenance==NULL) { - btype->maintenance = calloc(sizeof(struct maintenance), result->nodesetval->nodeNr+1); + maintenance *mt; + + if (btype->maintenance == NULL) { + btype->maintenance = + calloc(sizeof(struct maintenance), result->nodesetval->nodeNr + 1); } mt = btype->maintenance + k; mt->number = xml_ivalue(node, "amount", 0); propValue = xmlGetProp(node, BAD_CAST "type"); - assert(propValue!=NULL); - mt->rtype = rt_find((const char*)propValue); - assert(mt->rtype!=NULL); + assert(propValue != NULL); + mt->rtype = rt_find((const char *)propValue); + assert(mt->rtype != NULL); xmlFree(propValue); - if (xml_bvalue(node, "variable", false)) mt->flags |= MTF_VARIABLE; - if (xml_bvalue(node, "vital", false)) mt->flags |= MTF_VITAL; + if (xml_bvalue(node, "variable", false)) + mt->flags |= MTF_VARIABLE; + if (xml_bvalue(node, "vital", false)) + mt->flags |= MTF_VITAL; } xmlXPathFreeObject(result); /* finally, initialize the new building type */ - if (btype->init) btype->init(btype); + if (btype->init) + btype->init(btype); } } xmlXPathFreeObject(buildings); @@ -366,137 +412,158 @@ parse_buildings(xmlDocPtr doc) return 0; } -static int -parse_calendar(xmlDocPtr doc) +static int parse_calendar(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr xpathCalendars; + xmlNodeSetPtr nsetCalendars; + int c, rv = 0; /* reading eressea/buildings/building */ xpathCalendars = xmlXPathEvalExpression(BAD_CAST "/eressea/calendar", xpath); nsetCalendars = xpathCalendars->nodesetval; months_per_year = 0; - if (nsetCalendars==NULL || nsetCalendars->nodeNr==0) { + if (nsetCalendars == NULL || nsetCalendars->nodeNr == 0) { rv = -1; - } else for (c=0;c!=nsetCalendars->nodeNr;++c) { - xmlNodePtr calendar = nsetCalendars->nodeTab[c]; - xmlXPathObjectPtr xpathWeeks, xpathMonths, xpathSeasons; - xmlNodeSetPtr nsetWeeks, nsetMonths, nsetSeasons; - xmlChar * propValue = xmlGetProp(calendar, BAD_CAST "name"); - xmlChar * newyear = xmlGetProp(calendar, BAD_CAST "newyear"); + } else + for (c = 0; c != nsetCalendars->nodeNr; ++c) { + xmlNodePtr calendar = nsetCalendars->nodeTab[c]; - first_turn = xml_ivalue(calendar, "start", first_turn); - if (propValue) { - free(agename); - agename = strdup(mkname("calendar", (const char*)propValue)); - xmlFree(propValue); - } + xmlXPathObjectPtr xpathWeeks, xpathMonths, xpathSeasons; - xpath->node = calendar; - xpathWeeks = xmlXPathEvalExpression(BAD_CAST "week", xpath); - nsetWeeks = xpathWeeks->nodesetval; - if (nsetWeeks!=NULL && nsetWeeks->nodeNr) { - int i; + xmlNodeSetPtr nsetWeeks, nsetMonths, nsetSeasons; - weeks_per_month = nsetWeeks->nodeNr; - assert(!weeknames); - weeknames = malloc(sizeof(char *) * weeks_per_month); - weeknames2 = malloc(sizeof(char *) * weeks_per_month); - for (i=0;i!=nsetWeeks->nodeNr;++i) { - xmlNodePtr week = nsetWeeks->nodeTab[i]; - xmlChar * propValue = xmlGetProp(week, BAD_CAST "name"); - if (propValue) { - weeknames[i] = strdup(mkname("calendar", (const char*)propValue)); - weeknames2[i] = malloc(strlen(weeknames[i])+3); - sprintf(weeknames2[i], "%s_d", weeknames[i]); - xmlFree(propValue); - } + xmlChar *propValue = xmlGetProp(calendar, BAD_CAST "name"); + + xmlChar *newyear = xmlGetProp(calendar, BAD_CAST "newyear"); + + first_turn = xml_ivalue(calendar, "start", first_turn); + if (propValue) { + free(agename); + agename = strdup(mkname("calendar", (const char *)propValue)); + xmlFree(propValue); } - } - xmlXPathFreeObject(xpathWeeks); - xpathSeasons = xmlXPathEvalExpression(BAD_CAST "season", xpath); - nsetSeasons = xpathSeasons->nodesetval; - if (nsetSeasons!=NULL && nsetSeasons->nodeNr) { - int i; + xpath->node = calendar; + xpathWeeks = xmlXPathEvalExpression(BAD_CAST "week", xpath); + nsetWeeks = xpathWeeks->nodesetval; + if (nsetWeeks != NULL && nsetWeeks->nodeNr) { + int i; - seasons = nsetSeasons->nodeNr; - assert(!seasonnames); - seasonnames = malloc(sizeof(char *) * seasons); + weeks_per_month = nsetWeeks->nodeNr; + assert(!weeknames); + weeknames = malloc(sizeof(char *) * weeks_per_month); + weeknames2 = malloc(sizeof(char *) * weeks_per_month); + for (i = 0; i != nsetWeeks->nodeNr; ++i) { + xmlNodePtr week = nsetWeeks->nodeTab[i]; - for (i=0;i!=nsetSeasons->nodeNr;++i) { - xmlNodePtr season = nsetSeasons->nodeTab[i]; - xmlChar * propValue = xmlGetProp(season, BAD_CAST "name"); - if (propValue) { - seasonnames[i] = strdup(mkname("calendar", (const char*)propValue)); - xmlFree(propValue); - } - } - } + xmlChar *propValue = xmlGetProp(week, BAD_CAST "name"); - xpathMonths = xmlXPathEvalExpression(BAD_CAST "season/month", xpath); - nsetMonths = xpathMonths->nodesetval; - if (nsetMonths!=NULL && nsetMonths->nodeNr) { - int i; - - months_per_year = nsetMonths->nodeNr; - assert(!monthnames); - monthnames = malloc(sizeof(char *) * months_per_year); - month_season = malloc(sizeof(int) * months_per_year); - storms = malloc(sizeof(int) * months_per_year); - - for (i=0;i!=nsetMonths->nodeNr;++i) { - xmlNodePtr month = nsetMonths->nodeTab[i]; - xmlChar * propValue = xmlGetProp(month, BAD_CAST "name"); - int j; - - if (propValue) { - if (newyear && strcmp((const char*)newyear, (const char*)propValue)==0) { - first_month = i; - xmlFree(newyear); - newyear = NULL; - } - monthnames[i] = strdup(mkname("calendar", (const char*)propValue)); - xmlFree(propValue); - } - for (j=0;j!=seasons;++j) { - xmlNodePtr season = month->parent; - if (season==nsetSeasons->nodeTab[j]) { - month_season[i] = j; - break; + if (propValue) { + weeknames[i] = strdup(mkname("calendar", (const char *)propValue)); + weeknames2[i] = malloc(strlen(weeknames[i]) + 3); + sprintf(weeknames2[i], "%s_d", weeknames[i]); + xmlFree(propValue); } } - assert(j!=seasons); - storms[i] = xml_ivalue(nsetMonths->nodeTab[i], "storm", 0); } + xmlXPathFreeObject(xpathWeeks); + + xpathSeasons = xmlXPathEvalExpression(BAD_CAST "season", xpath); + nsetSeasons = xpathSeasons->nodesetval; + if (nsetSeasons != NULL && nsetSeasons->nodeNr) { + int i; + + seasons = nsetSeasons->nodeNr; + assert(!seasonnames); + seasonnames = malloc(sizeof(char *) * seasons); + + for (i = 0; i != nsetSeasons->nodeNr; ++i) { + xmlNodePtr season = nsetSeasons->nodeTab[i]; + + xmlChar *propValue = xmlGetProp(season, BAD_CAST "name"); + + if (propValue) { + seasonnames[i] = + strdup(mkname("calendar", (const char *)propValue)); + xmlFree(propValue); + } + } + } + + xpathMonths = xmlXPathEvalExpression(BAD_CAST "season/month", xpath); + nsetMonths = xpathMonths->nodesetval; + if (nsetMonths != NULL && nsetMonths->nodeNr) { + int i; + + months_per_year = nsetMonths->nodeNr; + assert(!monthnames); + monthnames = malloc(sizeof(char *) * months_per_year); + month_season = malloc(sizeof(int) * months_per_year); + storms = malloc(sizeof(int) * months_per_year); + + for (i = 0; i != nsetMonths->nodeNr; ++i) { + xmlNodePtr month = nsetMonths->nodeTab[i]; + + xmlChar *propValue = xmlGetProp(month, BAD_CAST "name"); + + int j; + + if (propValue) { + if (newyear + && strcmp((const char *)newyear, (const char *)propValue) == 0) { + first_month = i; + xmlFree(newyear); + newyear = NULL; + } + monthnames[i] = strdup(mkname("calendar", (const char *)propValue)); + xmlFree(propValue); + } + for (j = 0; j != seasons; ++j) { + xmlNodePtr season = month->parent; + + if (season == nsetSeasons->nodeTab[j]) { + month_season[i] = j; + break; + } + } + assert(j != seasons); + storms[i] = xml_ivalue(nsetMonths->nodeTab[i], "storm", 0); + } + } + xmlXPathFreeObject(xpathMonths); + xmlXPathFreeObject(xpathSeasons); } - xmlXPathFreeObject(xpathMonths); - xmlXPathFreeObject(xpathSeasons); - } xmlXPathFreeObject(xpathCalendars); xmlXPathFreeContext(xpath); - + return rv; } -static int -parse_directions(xmlDocPtr doc) +static int parse_directions(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr xpathDirections; + xmlNodeSetPtr nsetDirections; + int rv = 0; /* reading eressea/directions/dir */ - xpathDirections = xmlXPathEvalExpression(BAD_CAST "/eressea/directions/dir", xpath); + xpathDirections = + xmlXPathEvalExpression(BAD_CAST "/eressea/directions/dir", xpath); nsetDirections = xpathDirections->nodesetval; - if (nsetDirections!=NULL) { + if (nsetDirections != NULL) { int k; - for (k=0;k!=nsetDirections->nodeNr;++k) { + + for (k = 0; k != nsetDirections->nodeNr; ++k) { xmlNodePtr dir = nsetDirections->nodeTab[k]; - xmlChar * propValue = xmlGetProp(dir, BAD_CAST "name"); + + xmlChar *propValue = xmlGetProp(dir, BAD_CAST "name"); register_special_direction((const char *)propValue); xmlFree(propValue); @@ -504,32 +571,39 @@ parse_directions(xmlDocPtr doc) } xmlXPathFreeObject(xpathDirections); xmlXPathFreeContext(xpath); - + return rv; } -static int -parse_ships(xmlDocPtr doc) +static int parse_ships(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr ships; + int i; /* reading eressea/ships/ship */ ships = xmlXPathEvalExpression(BAD_CAST "/eressea/ships/ship", xpath); - if (ships->nodesetval!=NULL) { + if (ships->nodesetval != NULL) { xmlNodeSetPtr nodes = ships->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { + + for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr child, node = nodes->nodeTab[i]; - xmlChar * propValue; - ship_type * st = calloc(sizeof(ship_type), 1); + + xmlChar *propValue; + + ship_type *st = calloc(sizeof(ship_type), 1); + xmlXPathObjectPtr result; + int k, c; propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); + assert(propValue != NULL); st->name[0] = strdup((const char *)propValue); - st->name[1] = strcat(strcpy(malloc(strlen(st->name[0])+3), st->name[0]),"_a"); + st->name[1] = + strcat(strcpy(malloc(strlen(st->name[0]) + 3), st->name[0]), "_a"); xmlFree(propValue); st->cabins = xml_ivalue(node, "cabins", 0) * PERSON_WEIGHT; @@ -537,9 +611,12 @@ parse_ships(xmlDocPtr doc) st->combat = xml_ivalue(node, "combat", 0); st->cptskill = xml_ivalue(node, "cptskill", 0); st->damage = xml_fvalue(node, "damage", 0.0); - if (xml_bvalue(node, "nocoast", false)) st->flags |= SFL_NOCOAST; - if (xml_bvalue(node, "fly", false)) st->flags |= SFL_FLY; - if (xml_bvalue(node, "opensea", false)) st->flags |= SFL_OPENSEA; + if (xml_bvalue(node, "nocoast", false)) + st->flags |= SFL_NOCOAST; + if (xml_bvalue(node, "fly", false)) + st->flags |= SFL_FLY; + if (xml_bvalue(node, "opensea", false)) + st->flags |= SFL_OPENSEA; st->fishing = xml_ivalue(node, "fishing", 0); st->minskill = xml_ivalue(node, "minskill", 0); st->range = xml_ivalue(node, "range", 0); @@ -552,34 +629,42 @@ parse_ships(xmlDocPtr doc) xml_readconstruction(xpath, result->nodesetval, &st->construction); xmlXPathFreeObject(result); - for (child=node->children;child;child=child->next) { - if (strcmp((const char *)child->name, "modifier")==0) { + for (child = node->children; child; child = child->next) { + if (strcmp((const char *)child->name, "modifier") == 0) { double value = xml_fvalue(child, "value", 0.0); + propValue = xmlGetProp(child, BAD_CAST "type"); - if (strcmp((const char *)propValue, "tactics")==0) st->tac_bonus = (float)value; - else if (strcmp((const char *)propValue, "attack")==0) st->at_bonus = (int)value; - else if (strcmp((const char *)propValue, "defense")==0) st->df_bonus = (int)value; + if (strcmp((const char *)propValue, "tactics") == 0) + st->tac_bonus = (float)value; + else if (strcmp((const char *)propValue, "attack") == 0) + st->at_bonus = (int)value; + else if (strcmp((const char *)propValue, "defense") == 0) + st->df_bonus = (int)value; xmlFree(propValue); } } /* reading eressea/ships/ship/coast */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "coast", xpath); - for (c=0,k=0;k!=result->nodesetval->nodeNr;++k) { + for (c = 0, k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - if (k==0) { - assert(st->coasts==NULL); - st->coasts = (const terrain_type**)malloc(sizeof(const terrain_type*) * (result->nodesetval->nodeNr+1)); + if (k == 0) { + assert(st->coasts == NULL); + st->coasts = + (const terrain_type **)malloc(sizeof(const terrain_type *) * + (result->nodesetval->nodeNr + 1)); st->coasts[result->nodesetval->nodeNr] = NULL; } propValue = xmlGetProp(node, BAD_CAST "terrain"); - assert(propValue!=NULL); - st->coasts[c] = get_terrain((const char*)propValue); - if (st->coasts[c]!=NULL) ++c; + assert(propValue != NULL); + st->coasts[c] = get_terrain((const char *)propValue); + if (st->coasts[c] != NULL) + ++c; else { - log_warning(("ship %s mentions a non-existing terrain %s.\n", st->name[0], propValue)); + log_warning(("ship %s mentions a non-existing terrain %s.\n", + st->name[0], propValue)); } xmlFree(propValue); } @@ -595,11 +680,10 @@ parse_ships(xmlDocPtr doc) return 0; } -static void -race_compat(void) +static void race_compat(void) { /* required for old_race, do not change order! */ - const char * oldracenames[MAXRACES] = { + const char *oldracenames[MAXRACES] = { "dwarf", "elf", NULL, "goblin", "human", "troll", "demon", "insect", "halfling", "cat", "aquarian", "orc", "snotling", "undead", "illusion", "youngdragon", "dragon", "wyrm", "ent", "catdragon", "dracoid", @@ -614,108 +698,139 @@ race_compat(void) }; int i; - for (i=0;i!=MAXRACES;++i) { - const char * rcname = oldracenames[i]; - if (rcname==NULL) { + for (i = 0; i != MAXRACES; ++i) { + const char *rcname = oldracenames[i]; + + if (rcname == NULL) { new_race[i] = NULL; } else { - race * rc = rc_find(oldracenames[i]); + race *rc = rc_find(oldracenames[i]); + if (rc) { new_race[i] = rc; if (rc == new_race[RC_TROLL]) { - a_add(&rc->attribs, make_skillmod(NOSKILL, SMF_RIDING, NULL, 0.0, -1)); + a_add(&rc->attribs, make_skillmod(NOSKILL, SMF_RIDING, NULL, 0.0, + -1)); } } } } } -static potion_type * -xml_readpotion(xmlXPathContextPtr xpath, item_type * itype) +static potion_type *xml_readpotion(xmlXPathContextPtr xpath, item_type * itype) { int level = xml_ivalue(xpath->node, "level", 0); - assert(level>0); + assert(level > 0); return new_potiontype(itype, level); } -static luxury_type * -xml_readluxury(xmlXPathContextPtr xpath, item_type * itype) +static luxury_type *xml_readluxury(xmlXPathContextPtr xpath, item_type * itype) { int price = xml_ivalue(xpath->node, "price", 0); + return new_luxurytype(itype, price); } -static armor_type * -xml_readarmor(xmlXPathContextPtr xpath, item_type * itype) +static armor_type *xml_readarmor(xmlXPathContextPtr xpath, item_type * itype) { xmlNodePtr node = xpath->node; - armor_type * atype = NULL; + + armor_type *atype = NULL; + unsigned int flags = ATF_NONE; + int ac = xml_ivalue(node, "ac", 0); + double penalty = xml_fvalue(node, "penalty", 0.0); + double magres = xml_fvalue(node, "magres", 0.0); - if (xml_bvalue(node, "laen", false)) flags |= ATF_LAEN; - if (xml_bvalue(node, "shield", false)) flags |= ATF_SHIELD; + if (xml_bvalue(node, "laen", false)) + flags |= ATF_LAEN; + if (xml_bvalue(node, "shield", false)) + flags |= ATF_SHIELD; atype = new_armortype(itype, penalty, magres, ac, flags); atype->projectile = (float)xml_fvalue(node, "projectile", 0.0); return atype; } -static weapon_type * -xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) +static weapon_type *xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) { xmlNodePtr node = xpath->node; - weapon_type * wtype = NULL; + + weapon_type *wtype = NULL; + unsigned int flags = WTF_NONE; + xmlXPathObjectPtr result; - xmlChar * propValue; + + xmlChar *propValue; + int k; + skill_t sk; + int minskill = xml_ivalue(node, "minskill", 0); + int offmod = xml_ivalue(node, "offmod", 0); + int defmod = xml_ivalue(node, "defmod", 0); + int reload = xml_ivalue(node, "reload", 0); + double magres = xml_fvalue(node, "magres", 0.0); - if (xml_bvalue(node, "armorpiercing", false)) flags |= WTF_ARMORPIERCING; - if (xml_bvalue(node, "magical", false)) flags |= WTF_MAGICAL; - if (xml_bvalue(node, "missile", false)) flags |= WTF_MISSILE; - if (xml_bvalue(node, "pierce", false)) flags |= WTF_PIERCE; - if (xml_bvalue(node, "cut", false)) flags |= WTF_CUT; - if (xml_bvalue(node, "blunt", false)) flags |= WTF_BLUNT; - if (xml_bvalue(node, "siege", false)) flags |= WTF_SIEGE; - if (xml_bvalue(node, "horse", (flags&WTF_MISSILE)==0)) flags |= WTF_HORSEBONUS; - if (xml_bvalue(node, "useshield", true)) flags |= WTF_USESHIELD; + if (xml_bvalue(node, "armorpiercing", false)) + flags |= WTF_ARMORPIERCING; + if (xml_bvalue(node, "magical", false)) + flags |= WTF_MAGICAL; + if (xml_bvalue(node, "missile", false)) + flags |= WTF_MISSILE; + if (xml_bvalue(node, "pierce", false)) + flags |= WTF_PIERCE; + if (xml_bvalue(node, "cut", false)) + flags |= WTF_CUT; + if (xml_bvalue(node, "blunt", false)) + flags |= WTF_BLUNT; + if (xml_bvalue(node, "siege", false)) + flags |= WTF_SIEGE; + if (xml_bvalue(node, "horse", (flags & WTF_MISSILE) == 0)) + flags |= WTF_HORSEBONUS; + if (xml_bvalue(node, "useshield", true)) + flags |= WTF_USESHIELD; propValue = xmlGetProp(node, BAD_CAST "skill"); - assert(propValue!=NULL); - sk = sk_find((const char*)propValue); - assert(sk!=NOSKILL); + assert(propValue != NULL); + sk = sk_find((const char *)propValue); + assert(sk != NOSKILL); xmlFree(propValue); - wtype = new_weapontype(itype, flags, magres, NULL, offmod, defmod, reload, sk, minskill); + wtype = + new_weapontype(itype, flags, magres, NULL, offmod, defmod, reload, sk, + minskill); /* reading weapon/damage */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "damage", xpath); - assert(result->nodesetval->nodeNr<=2); - for (k=0;k!=result->nodesetval->nodeNr;++k) { + assert(result->nodesetval->nodeNr <= 2); + for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; + int pos = 0; propValue = xmlGetProp(node, BAD_CAST "type"); - if (strcmp((const char *)propValue, "footman")!=0) { + if (strcmp((const char *)propValue, "footman") != 0) { pos = 1; } xmlFree(propValue); propValue = xmlGetProp(node, BAD_CAST "value"); - wtype->damage[pos] = gc_add(strdup((const char*)propValue)); - if (k==0) wtype->damage[1-pos] = wtype->damage[pos]; + wtype->damage[pos] = gc_add(strdup((const char *)propValue)); + if (k == 0) + wtype->damage[1 - pos] = wtype->damage[pos]; xmlFree(propValue); } xmlXPathFreeObject(result); @@ -723,24 +838,35 @@ xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) /* reading weapon/modifier */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); - assert(wtype->modifiers==NULL); - wtype->modifiers = calloc(result->nodesetval->nodeNr+1, sizeof(weapon_mod)); - for (k=0;k!=result->nodesetval->nodeNr;++k) { + assert(wtype->modifiers == NULL); + wtype->modifiers = calloc(result->nodesetval->nodeNr + 1, sizeof(weapon_mod)); + for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; + xmlXPathObjectPtr races; + int r, flags = 0; - if (xml_bvalue(node, "walking", false)) flags|=WMF_WALKING; - if (xml_bvalue(node, "riding", false)) flags|=WMF_RIDING; - if (xml_bvalue(node, "against_walking", false)) flags|=WMF_AGAINST_WALKING; - if (xml_bvalue(node, "against_riding", false)) flags|=WMF_AGAINST_RIDING; - if (xml_bvalue(node, "offensive", false)) flags|=WMF_OFFENSIVE; - if (xml_bvalue(node, "defensive", false)) flags|=WMF_DEFENSIVE; + if (xml_bvalue(node, "walking", false)) + flags |= WMF_WALKING; + if (xml_bvalue(node, "riding", false)) + flags |= WMF_RIDING; + if (xml_bvalue(node, "against_walking", false)) + flags |= WMF_AGAINST_WALKING; + if (xml_bvalue(node, "against_riding", false)) + flags |= WMF_AGAINST_RIDING; + if (xml_bvalue(node, "offensive", false)) + flags |= WMF_OFFENSIVE; + if (xml_bvalue(node, "defensive", false)) + flags |= WMF_DEFENSIVE; propValue = xmlGetProp(node, BAD_CAST "type"); - if (strcmp((const char*)propValue, "damage")==0) flags|=WMF_DAMAGE; - else if (strcmp((const char*)propValue, "skill")==0) flags|=WMF_SKILL; - else if (strcmp((const char*)propValue, "missile_target")==0) flags|=WMF_MISSILE_TARGET; + if (strcmp((const char *)propValue, "damage") == 0) + flags |= WMF_DAMAGE; + else if (strcmp((const char *)propValue, "skill") == 0) + flags |= WMF_SKILL; + else if (strcmp((const char *)propValue, "missile_target") == 0) + flags |= WMF_MISSILE_TARGET; xmlFree(propValue); wtype->modifiers[k].flags = flags; @@ -748,13 +874,15 @@ xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) xpath->node = node; races = xmlXPathEvalExpression(BAD_CAST "race", xpath); - for (r=0;r!=races->nodesetval->nodeNr;++r) { + for (r = 0; r != races->nodesetval->nodeNr; ++r) { xmlNodePtr node = races->nodesetval->nodeTab[r]; propValue = xmlGetProp(node, BAD_CAST "name"); - if (propValue!=NULL) { - const race * rc = rc_find((const char*)propValue); - if (rc==NULL) rc = rc_add(rc_new((const char*)propValue)); + if (propValue != NULL) { + const race *rc = rc_find((const char *)propValue); + + if (rc == NULL) + rc = rc_add(rc_new((const char *)propValue)); racelist_insert(&wtype->modifiers[k].races, rc); xmlFree(propValue); } @@ -767,24 +895,28 @@ xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) /* reading weapon/function */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { + for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - xmlChar * propValue; + + xmlChar *propValue; + pf_generic fun; parse_function(node, &fun, &propValue); - if (fun==NULL) { + if (fun == NULL) { log_error(("unknown function name '%s' for item '%s'\n", - (const char*)propValue, itype->rtype->_name[0])); + (const char *)propValue, itype->rtype->_name[0])); xmlFree(propValue); continue; } - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "attack")==0) { - wtype->attack = (boolean (*)(const struct troop*, const struct weapon_type *, int*))fun; + assert(propValue != NULL); + if (strcmp((const char *)propValue, "attack") == 0) { + wtype->attack = + (boolean(*)(const struct troop *, const struct weapon_type *, + int *))fun; } else { log_error(("unknown function type '%s' for item '%s'\n", - (const char*)propValue, itype->rtype->_name[0])); + (const char *)propValue, itype->rtype->_name[0])); } xmlFree(propValue); } @@ -795,24 +927,34 @@ xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) return wtype; } -static item_type * -xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) +static item_type *xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) { xmlNodePtr node = xpath->node; - item_type * itype = NULL; + + item_type *itype = NULL; + unsigned int flags = ITF_NONE; + xmlXPathObjectPtr result; + int k; int weight = xml_ivalue(node, "weight", 0); + int capacity = xml_ivalue(node, "capacity", 0); - if (xml_bvalue(node, "cursed", false)) flags |= ITF_CURSED; - if (xml_bvalue(node, "notlost", false)) flags |= ITF_NOTLOST; - if (xml_bvalue(node, "herb", false)) flags |= ITF_HERB; - if (xml_bvalue(node, "big", false)) flags |= ITF_BIG; - if (xml_bvalue(node, "animal", false)) flags |= ITF_ANIMAL; - if (xml_bvalue(node, "vehicle", false)) flags |= ITF_VEHICLE; + if (xml_bvalue(node, "cursed", false)) + flags |= ITF_CURSED; + if (xml_bvalue(node, "notlost", false)) + flags |= ITF_NOTLOST; + if (xml_bvalue(node, "herb", false)) + flags |= ITF_HERB; + if (xml_bvalue(node, "big", false)) + flags |= ITF_BIG; + if (xml_bvalue(node, "animal", false)) + flags |= ITF_ANIMAL; + if (xml_bvalue(node, "vehicle", false)) + flags |= ITF_VEHICLE; itype = new_itemtype(rtype, flags, weight, capacity); #if SCORE_MODULE itype->score = xml_ivalue(node, "score", 0); @@ -827,8 +969,8 @@ xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) /* reading item/weapon */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "weapon", xpath); - assert(result->nodesetval->nodeNr<=1); - if (result->nodesetval->nodeNr!=0) { + assert(result->nodesetval->nodeNr <= 1); + if (result->nodesetval->nodeNr != 0) { xpath->node = result->nodesetval->nodeTab[0]; rtype->wtype = xml_readweapon(xpath, itype); } @@ -837,8 +979,8 @@ xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) /* reading item/potion */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "potion", xpath); - assert(result->nodesetval->nodeNr<=1); - if (result->nodesetval->nodeNr!=0) { + assert(result->nodesetval->nodeNr <= 1); + if (result->nodesetval->nodeNr != 0) { xpath->node = result->nodesetval->nodeTab[0]; rtype->ptype = xml_readpotion(xpath, itype); } @@ -847,8 +989,8 @@ xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) /* reading item/luxury */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "luxury", xpath); - assert(result->nodesetval->nodeNr<=1); - if (result->nodesetval->nodeNr!=0) { + assert(result->nodesetval->nodeNr <= 1); + if (result->nodesetval->nodeNr != 0) { xpath->node = result->nodesetval->nodeTab[0]; rtype->ltype = xml_readluxury(xpath, itype); } @@ -857,8 +999,8 @@ xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) /* reading item/armor */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "armor", xpath); - assert(result->nodesetval->nodeNr<=1); - if (result->nodesetval->nodeNr!=0) { + assert(result->nodesetval->nodeNr <= 1); + if (result->nodesetval->nodeNr != 0) { xpath->node = result->nodesetval->nodeTab[0]; rtype->atype = xml_readarmor(xpath, itype); } @@ -868,30 +1010,39 @@ xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) /* reading item/function */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { + for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - xmlChar * propValue; + + xmlChar *propValue; + pf_generic fun; parse_function(node, &fun, &propValue); - if (fun==NULL) { + if (fun == NULL) { log_error(("unknown function name '%s' for item '%s'\n", - (const char*)propValue, rtype->_name[0])); + (const char *)propValue, rtype->_name[0])); xmlFree(propValue); continue; } - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "give")==0) { - itype->give = (int (*)(struct unit*, struct unit*, const struct item_type *, int, struct order *))fun; - } else if (strcmp((const char*)propValue, "use")==0) { - itype->use = (int (*)(struct unit *, const struct item_type *, int, struct order *))fun; - } else if (strcmp((const char*)propValue, "canuse")==0) { - itype->canuse = (boolean (*)(const struct unit *, const struct item_type *))fun; - } else if (strcmp((const char*)propValue, "useonother")==0) { - itype->useonother = (int (*)(struct unit *, int, const struct item_type *, int, struct order *))fun; + assert(propValue != NULL); + if (strcmp((const char *)propValue, "give") == 0) { + itype->give = + (int (*)(struct unit *, struct unit *, const struct item_type *, int, + struct order *))fun; + } else if (strcmp((const char *)propValue, "use") == 0) { + itype->use = + (int (*)(struct unit *, const struct item_type *, int, + struct order *))fun; + } else if (strcmp((const char *)propValue, "canuse") == 0) { + itype->canuse = + (boolean(*)(const struct unit *, const struct item_type *))fun; + } else if (strcmp((const char *)propValue, "useonother") == 0) { + itype->useonother = + (int (*)(struct unit *, int, const struct item_type *, int, + struct order *))fun; } else { log_error(("unknown function type '%s' for item '%s'\n", - (const char*)propValue, rtype->_name[0])); + (const char *)propValue, rtype->_name[0])); } xmlFree(propValue); } @@ -901,37 +1052,43 @@ xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) return itype; } -static int -parse_rules(xmlDocPtr doc) +static int parse_rules(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr functions; + xmlNodeSetPtr nodes; + int i; /* reading eressea/resources/resource */ functions = xmlXPathEvalExpression(BAD_CAST "/eressea/rules/function", xpath); nodes = functions->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { + for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; + xmlChar *propValue; + pf_generic fun; parse_function(node, &fun, &propValue); - if (fun==NULL) { - log_error(("unknown function for rule '%s' %s\n", (const char*)propValue)); + if (fun == NULL) { + log_error(("unknown function for rule '%s' %s\n", + (const char *)propValue)); xmlFree(propValue); continue; } - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "wage")==0) { - global.functions.wage = (int (*)(const struct region*, const struct faction*, const struct race*, int))fun; - } else if (strcmp((const char*)propValue, "maintenance")==0) { - global.functions.maintenance = (int (*)(const struct unit*))fun; + assert(propValue != NULL); + if (strcmp((const char *)propValue, "wage") == 0) { + global.functions.wage = + (int (*)(const struct region *, const struct faction *, + const struct race *, int))fun; + } else if (strcmp((const char *)propValue, "maintenance") == 0) { + global.functions.maintenance = (int (*)(const struct unit *))fun; } else { - log_error(("unknown function for rule '%s'\n", - (const char*)propValue)); + log_error(("unknown function for rule '%s'\n", (const char *)propValue)); } xmlFree(propValue); } @@ -940,55 +1097,73 @@ parse_rules(xmlDocPtr doc) return 0; } -static int -parse_resources(xmlDocPtr doc) +static int parse_resources(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr resources; + xmlNodeSetPtr nodes; + int i; /* reading eressea/resources/resource */ - resources = xmlXPathEvalExpression(BAD_CAST "/eressea/resources/resource", xpath); + resources = + xmlXPathEvalExpression(BAD_CAST "/eressea/resources/resource", xpath); nodes = resources->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { + for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; + xmlChar *propValue, *name, *appearance; + const char *names[2], *appearances[2]; - char * namep = NULL, * appearancep = NULL; - resource_type * rtype; + + char *namep = NULL, *appearancep = NULL; + + resource_type *rtype; + unsigned int flags = RTF_NONE; + xmlXPathObjectPtr result; + int k; - if (xml_bvalue(node, "pooled", true)) flags |= RTF_POOLED; - if (xml_bvalue(node, "limited", false)) flags |= RTF_LIMITED; + if (xml_bvalue(node, "pooled", true)) + flags |= RTF_POOLED; + if (xml_bvalue(node, "limited", false)) + flags |= RTF_LIMITED; name = xmlGetProp(node, BAD_CAST "name"); appearance = xmlGetProp(node, BAD_CAST "appearance"); - assert(name!=NULL); + assert(name != NULL); - if (appearance!=NULL) { - appearancep = strcat(strcpy((char*)malloc(strlen((char*)appearance)+3), (char*)appearance), "_p"); + if (appearance != NULL) { + appearancep = + strcat(strcpy((char *)malloc(strlen((char *)appearance) + 3), + (char *)appearance), "_p"); } rtype = rt_find((const char *)name); - if (rtype!=NULL) { + if (rtype != NULL) { /* dependency from another item, was created earlier */ rtype->flags |= flags; if (appearance) { - rtype->_appearance[0] = strdup((const char*)appearance); + rtype->_appearance[0] = strdup((const char *)appearance); rtype->_appearance[1] = appearancep; free(appearancep); } } else { - namep = strcat(strcpy((char*)malloc(strlen((char*)name)+3), (char*)name), "_p"); - names[0] = (const char*)name; + namep = + strcat(strcpy((char *)malloc(strlen((char *)name) + 3), (char *)name), + "_p"); + names[0] = (const char *)name; names[1] = namep; if (appearance) { - appearances[0] = (const char*)appearance; + appearances[0] = (const char *)appearance; appearances[1] = appearancep; - rtype = new_resourcetype((const char**)names, (const char**)appearances, flags); + rtype = + new_resourcetype((const char **)names, (const char **)appearances, + flags); free(appearancep); } else { rtype = new_resourcetype(names, NULL, flags); @@ -996,8 +1171,10 @@ parse_resources(xmlDocPtr doc) free(namep); } - if (name) xmlFree(name); - if (appearance) xmlFree(appearance); + if (name) + xmlFree(name); + if (appearance) + xmlFree(appearance); name = xmlGetProp(node, BAD_CAST "material"); if (name) { @@ -1010,94 +1187,104 @@ parse_resources(xmlDocPtr doc) /* reading eressea/resources/resource/function */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - if (result->nodesetval!=NULL) for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - pf_generic fun; + if (result->nodesetval != NULL) + for (k = 0; k != result->nodesetval->nodeNr; ++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; - parse_function(node, &fun, &propValue); - if (fun==NULL) { - log_error(("unknown function name '%s' for resource %s\n", - (const char*)propValue, rtype->_name[0])); + pf_generic fun; + + parse_function(node, &fun, &propValue); + if (fun == NULL) { + log_error(("unknown function name '%s' for resource %s\n", + (const char *)propValue, rtype->_name[0])); + xmlFree(propValue); + continue; + } + + assert(propValue != NULL); + if (strcmp((const char *)propValue, "change") == 0) { + rtype->uchange = (rtype_uchange) fun; + } else if (strcmp((const char *)propValue, "get") == 0) { + rtype->uget = (rtype_uget) fun; + } else if (strcmp((const char *)propValue, "name") == 0) { + rtype->name = (rtype_name) fun; + } else { + log_error(("unknown function type '%s' for resource %s\n", + (const char *)propValue, rtype->_name[0])); + } xmlFree(propValue); - continue; } - - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "change")==0) { - rtype->uchange = (rtype_uchange)fun; - } else if (strcmp((const char*)propValue, "get")==0) { - rtype->uget = (rtype_uget)fun; - } else if (strcmp((const char*)propValue, "name")==0) { - rtype->name = (rtype_name)fun; - } else { - log_error(("unknown function type '%s' for resource %s\n", - (const char*)propValue, rtype->_name[0])); - } - xmlFree(propValue); - } xmlXPathFreeObject(result); } /* reading eressea/resources/resource/resourcelimit */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "resourcelimit", xpath); - assert(result->nodesetval->nodeNr<=1); - if (result->nodesetval->nodeNr!=0) { - resource_limit * rdata; - attrib * a = a_find(rtype->attribs, &at_resourcelimit); + assert(result->nodesetval->nodeNr <= 1); + if (result->nodesetval->nodeNr != 0) { + resource_limit *rdata; + + attrib *a = a_find(rtype->attribs, &at_resourcelimit); + xmlNodePtr limit = result->nodesetval->nodeTab[0]; - if (a==NULL) a = a_add(&rtype->attribs, a_new(&at_resourcelimit)); - rdata = (resource_limit*)a->data.v; + if (a == NULL) + a = a_add(&rtype->attribs, a_new(&at_resourcelimit)); + rdata = (resource_limit *) a->data.v; rtype->flags |= RTF_LIMITED; xpath->node = limit; xmlXPathFreeObject(result); result = xmlXPathEvalExpression(BAD_CAST "modifier", xpath); - if (result->nodesetval!=NULL) { - rdata->modifiers = calloc(result->nodesetval->nodeNr+1, sizeof(resource_mod)); - for (k=0;k!=result->nodesetval->nodeNr;++k) { + if (result->nodesetval != NULL) { + rdata->modifiers = + calloc(result->nodesetval->nodeNr + 1, sizeof(resource_mod)); + for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - building_type * btype = NULL; - const race * rc = NULL; + + building_type *btype = NULL; + + const race *rc = NULL; propValue = xmlGetProp(node, BAD_CAST "race"); - if (propValue!=NULL) { - rc = rc_find((const char*)propValue); - if (rc==NULL) rc = rc_add(rc_new((const char*)propValue)); + if (propValue != NULL) { + rc = rc_find((const char *)propValue); + if (rc == NULL) + rc = rc_add(rc_new((const char *)propValue)); xmlFree(propValue); } rdata->modifiers[k].race = rc; propValue = xmlGetProp(node, BAD_CAST "building"); - if (propValue!=NULL) { - btype = bt_get_or_create((const char*)propValue); + if (propValue != NULL) { + btype = bt_get_or_create((const char *)propValue); xmlFree(propValue); } rdata->modifiers[k].btype = btype; propValue = xmlGetProp(node, BAD_CAST "type"); - assert(propValue!=NULL); - if (strcmp((const char *)propValue, "skill")==0) { + assert(propValue != NULL); + if (strcmp((const char *)propValue, "skill") == 0) { rdata->modifiers[k].value.i = xml_ivalue(node, "value", 0); rdata->modifiers[k].flags = RMF_SKILL; - } else if (strcmp((const char *)propValue, "material")==0) { + } else if (strcmp((const char *)propValue, "material") == 0) { rdata->modifiers[k].value.f = (float)xml_fvalue(node, "value", 0); rdata->modifiers[k].flags = RMF_SAVEMATERIAL; - } else if (strcmp((const char *)propValue, "resource")==0) { + } else if (strcmp((const char *)propValue, "resource") == 0) { rdata->modifiers[k].value.f = (float)xml_fvalue(node, "value", 0); rdata->modifiers[k].flags = RMF_SAVERESOURCE; - } else if (strcmp((const char *)propValue, "require")==0) { - xmlChar * propBldg = xmlGetProp(node, BAD_CAST "building"); - if (propBldg!=NULL) { - btype = bt_get_or_create((const char*)propBldg); + } else if (strcmp((const char *)propValue, "require") == 0) { + xmlChar *propBldg = xmlGetProp(node, BAD_CAST "building"); + + if (propBldg != NULL) { + btype = bt_get_or_create((const char *)propBldg); rdata->modifiers[k].btype = btype; rdata->modifiers[k].flags = RMF_REQUIREDBUILDING; xmlFree(propBldg); } } else { log_error(("unknown type '%s' for resourcelimit-modifier '%s'\n", - (const char*)propValue, rtype->_name[0])); + (const char *)propValue, rtype->_name[0])); } xmlFree(propValue); } @@ -1105,50 +1292,54 @@ parse_resources(xmlDocPtr doc) xmlXPathFreeObject(result); result = xmlXPathEvalExpression(BAD_CAST "guard", xpath); - if (result->nodesetval!=NULL) for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - xmlChar * propFlag = xmlGetProp(node, BAD_CAST "flag"); - - if (propFlag!=NULL) { - if (strcmp((const char *)propFlag, "logging")==0) { - rdata->guard |= GUARD_TREES; - } else if (strcmp((const char *)propFlag, "mining")==0) { - rdata->guard |= GUARD_MINING; + if (result->nodesetval != NULL) + for (k = 0; k != result->nodesetval->nodeNr; ++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + + xmlChar *propFlag = xmlGetProp(node, BAD_CAST "flag"); + + if (propFlag != NULL) { + if (strcmp((const char *)propFlag, "logging") == 0) { + rdata->guard |= GUARD_TREES; + } else if (strcmp((const char *)propFlag, "mining") == 0) { + rdata->guard |= GUARD_MINING; + } + xmlFree(propFlag); } - xmlFree(propFlag); } - } xmlXPathFreeObject(result); /* reading eressea/resources/resource/resourcelimit/function */ result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - if (result->nodesetval!=NULL) for (k=0;k!=result->nodesetval->nodeNr;++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - pf_generic fun; + if (result->nodesetval != NULL) + for (k = 0; k != result->nodesetval->nodeNr; ++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; - propValue = xmlGetProp(node, BAD_CAST "value"); - assert(propValue!=NULL); - fun = get_function((const char*)propValue); - if (fun==NULL) { - log_error(("unknown limit '%s' for resource %s\n", - (const char*)propValue, rtype->_name[0])); + pf_generic fun; + + propValue = xmlGetProp(node, BAD_CAST "value"); + assert(propValue != NULL); + fun = get_function((const char *)propValue); + if (fun == NULL) { + log_error(("unknown limit '%s' for resource %s\n", + (const char *)propValue, rtype->_name[0])); + xmlFree(propValue); + continue; + } xmlFree(propValue); - continue; - } - xmlFree(propValue); - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "produce")==0) { - rdata->produce = (rlimit_produce)fun; - } else if (strcmp((const char*)propValue, "limit")==0) { - rdata->limit = (rlimit_limit)fun; - } else { - log_error(("unknown limit '%s' for resource %s\n", - (const char*)propValue, rtype->_name[0])); + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue != NULL); + if (strcmp((const char *)propValue, "produce") == 0) { + rdata->produce = (rlimit_produce) fun; + } else if (strcmp((const char *)propValue, "limit") == 0) { + rdata->limit = (rlimit_limit) fun; + } else { + log_error(("unknown limit '%s' for resource %s\n", + (const char *)propValue, rtype->_name[0])); + } + xmlFree(propValue); } - xmlFree(propValue); - } } xmlXPathFreeObject(result); @@ -1160,8 +1351,8 @@ parse_resources(xmlDocPtr doc) /* reading eressea/resources/resource/item */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "item", xpath); - assert(result->nodesetval->nodeNr<=1); - if (result->nodesetval->nodeNr!=0) { + assert(result->nodesetval->nodeNr <= 1); + if (result->nodesetval->nodeNr != 0) { rtype->flags |= RTF_ITEM; xpath->node = result->nodesetval->nodeTab[0]; rtype->itype = xml_readitem(xpath, rtype); @@ -1179,24 +1370,26 @@ parse_resources(xmlDocPtr doc) return 0; } -static void -add_items(equipment * eq, xmlNodeSetPtr nsetItems) +static void add_items(equipment * eq, xmlNodeSetPtr nsetItems) { - if (nsetItems!=NULL && nsetItems->nodeNr>0) { + if (nsetItems != NULL && nsetItems->nodeNr > 0) { int i; - for (i=0;i!=nsetItems->nodeNr;++i) { + + for (i = 0; i != nsetItems->nodeNr; ++i) { xmlNodePtr node = nsetItems->nodeTab[i]; - xmlChar * propValue; - const struct item_type * itype; + + xmlChar *propValue; + + const struct item_type *itype; propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - itype = it_find((const char*)propValue); + assert(propValue != NULL); + itype = it_find((const char *)propValue); xmlFree(propValue); - if (itype!=NULL) { + if (itype != NULL) { propValue = xmlGetProp(node, BAD_CAST "amount"); - if (propValue!=NULL) { - equipment_setitem(eq, itype, (const char*)propValue); + if (propValue != NULL) { + equipment_setitem(eq, itype, (const char *)propValue); xmlFree(propValue); } } @@ -1204,21 +1397,24 @@ add_items(equipment * eq, xmlNodeSetPtr nsetItems) } } -static void -add_callbacks(equipment * eq, xmlNodeSetPtr nsetItems) +static void add_callbacks(equipment * eq, xmlNodeSetPtr nsetItems) { - if (nsetItems!=NULL && nsetItems->nodeNr>0) { + if (nsetItems != NULL && nsetItems->nodeNr > 0) { int i; - for (i=0;i!=nsetItems->nodeNr;++i) { + + for (i = 0; i != nsetItems->nodeNr; ++i) { xmlNodePtr node = nsetItems->nodeTab[i]; - xmlChar * propValue; + + xmlChar *propValue; + pf_generic fun; propValue = xmlGetProp(node, BAD_CAST "name"); - if (propValue!=NULL) { - fun = get_function((const char*)propValue); + if (propValue != NULL) { + fun = get_function((const char *)propValue); if (fun) { - equipment_setcallback(eq, (void (*)(const struct equipment *, struct unit *))fun); + equipment_setcallback(eq, (void (*)(const struct equipment *, + struct unit *))fun); } xmlFree(propValue); } @@ -1226,59 +1422,66 @@ add_callbacks(equipment * eq, xmlNodeSetPtr nsetItems) } } -static void -add_spells(equipment * eq, xmlNodeSetPtr nsetItems) +static void add_spells(equipment * eq, xmlNodeSetPtr nsetItems) { - if (nsetItems!=NULL && nsetItems->nodeNr>0) { + if (nsetItems != NULL && nsetItems->nodeNr > 0) { int i; - for (i=0;i!=nsetItems->nodeNr;++i) { + + for (i = 0; i != nsetItems->nodeNr; ++i) { xmlNodePtr node = nsetItems->nodeTab[i]; - xmlChar * propValue; + + xmlChar *propValue; + magic_t mtype = M_NONE; - struct spell * sp; + + struct spell *sp; propValue = xmlGetProp(node, BAD_CAST "school"); - if (propValue!=NULL) { - for (mtype=0;mtype!=MAXMAGIETYP;++mtype) { - if (strcmp((const char*)propValue, magic_school[mtype])==0) break; + if (propValue != NULL) { + for (mtype = 0; mtype != MAXMAGIETYP; ++mtype) { + if (strcmp((const char *)propValue, magic_school[mtype]) == 0) + break; } - assert(mtype!=MAXMAGIETYP); + assert(mtype != MAXMAGIETYP); xmlFree(propValue); } propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - sp = find_spell(mtype, (const char*)propValue); + assert(propValue != NULL); + sp = find_spell(mtype, (const char *)propValue); assert(sp); xmlFree(propValue); - if (sp!=NULL) { + if (sp != NULL) { equipment_addspell(eq, sp); } } } } -static void -add_skills(equipment * eq, xmlNodeSetPtr nsetSkills) +static void add_skills(equipment * eq, xmlNodeSetPtr nsetSkills) { - if (nsetSkills!=NULL && nsetSkills->nodeNr>0) { + if (nsetSkills != NULL && nsetSkills->nodeNr > 0) { int i; - for (i=0;i!=nsetSkills->nodeNr;++i) { + + for (i = 0; i != nsetSkills->nodeNr; ++i) { xmlNodePtr node = nsetSkills->nodeTab[i]; - xmlChar * propValue; + + xmlChar *propValue; + skill_t sk; propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - sk = sk_find((const char*)propValue); - if (sk==NOSKILL) { - log_error(("unknown skill '%s' in equipment-set %s\n", (const char*)propValue, eq->name)); + assert(propValue != NULL); + sk = sk_find((const char *)propValue); + if (sk == NOSKILL) { + log_error(("unknown skill '%s' in equipment-set %s\n", + (const char *)propValue, eq->name)); xmlFree(propValue); } else { xmlFree(propValue); propValue = xmlGetProp(node, BAD_CAST "level"); - if (propValue!=NULL) { - equipment_setskill(eq, sk, (const char*)propValue); + if (propValue != NULL) { + equipment_setskill(eq, sk, (const char *)propValue); xmlFree(propValue); } } @@ -1290,18 +1493,21 @@ static void add_subsets(xmlDocPtr doc, equipment * eq, xmlNodeSetPtr nsetSubsets) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - if (nsetSubsets!=NULL && nsetSubsets->nodeNr>0) { + + if (nsetSubsets != NULL && nsetSubsets->nodeNr > 0) { int i; - eq->subsets = calloc(nsetSubsets->nodeNr+1, sizeof(subset)); - for (i=0;i!=nsetSubsets->nodeNr;++i) { + eq->subsets = calloc(nsetSubsets->nodeNr + 1, sizeof(subset)); + for (i = 0; i != nsetSubsets->nodeNr; ++i) { xmlXPathObjectPtr xpathResult; + xmlNodePtr node = nsetSubsets->nodeTab[i]; - xmlChar * propValue; + + xmlChar *propValue; eq->subsets[i].chance = 1.0f; propValue = xmlGetProp(node, BAD_CAST "chance"); - if (propValue!=NULL) { + if (propValue != NULL) { eq->subsets[i].chance = (float)atof((const char *)propValue); xmlFree(propValue); } @@ -1309,32 +1515,37 @@ add_subsets(xmlDocPtr doc, equipment * eq, xmlNodeSetPtr nsetSubsets) xpathResult = xmlXPathEvalExpression(BAD_CAST "set", xpath); if (xpathResult->nodesetval) { xmlNodeSetPtr nsetSets = xpathResult->nodesetval; + float totalChance = 0.0f; - if (nsetSets->nodeNr>0) { + if (nsetSets->nodeNr > 0) { int set; - eq->subsets[i].sets = calloc(nsetSets->nodeNr+1, sizeof(subsetitem)); - for (set=0;set!=nsetSets->nodeNr;++set) { + + eq->subsets[i].sets = + calloc(nsetSets->nodeNr + 1, sizeof(subsetitem)); + for (set = 0; set != nsetSets->nodeNr; ++set) { xmlNodePtr nodeSet = nsetSets->nodeTab[set]; + float chance = 1.0f; propValue = xmlGetProp(nodeSet, BAD_CAST "chance"); - if (propValue!=NULL) { + if (propValue != NULL) { chance = (float)atof((const char *)propValue); xmlFree(propValue); } totalChance += chance; propValue = xmlGetProp(nodeSet, BAD_CAST "name"); - assert(propValue!=NULL); + assert(propValue != NULL); eq->subsets[i].sets[set].chance = chance; - eq->subsets[i].sets[set].set = create_equipment((const char*)propValue); + eq->subsets[i].sets[set].set = + create_equipment((const char *)propValue); xmlFree(propValue); } } - if (totalChance>1.0f) { - log_error(("total chance exceeds 1.0: %f in equipment set %s.\n", - totalChance, eq->name)); + if (totalChance > 1.0f) { + log_error(("total chance exceeds 1.0: %f in equipment set %s.\n", + totalChance, eq->name)); } } xmlXPathFreeObject(xpathResult); @@ -1343,24 +1554,27 @@ add_subsets(xmlDocPtr doc, equipment * eq, xmlNodeSetPtr nsetSubsets) xmlXPathFreeContext(xpath); } -static int -parse_equipment(xmlDocPtr doc) +static int parse_equipment(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr xpathRaces; /* reading eressea/equipment/set */ xpathRaces = xmlXPathEvalExpression(BAD_CAST "/eressea/equipment/set", xpath); if (xpathRaces->nodesetval) { xmlNodeSetPtr nsetRaces = xpathRaces->nodesetval; + int i; - for (i=0;i!=nsetRaces->nodeNr;++i) { + for (i = 0; i != nsetRaces->nodeNr; ++i) { xmlNodePtr node = nsetRaces->nodeTab[i]; - xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); - if (propName!=NULL) { - equipment * eq = create_equipment((const char*)propName); + xmlChar *propName = xmlGetProp(node, BAD_CAST "name"); + + if (propName != NULL) { + equipment *eq = create_equipment((const char *)propName); + xmlXPathObjectPtr xpathResult; xpath->node = node; @@ -1400,95 +1614,111 @@ parse_equipment(xmlDocPtr doc) return 0; } -static int -parse_spells(xmlDocPtr doc) +static int parse_spells(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr spells; /* reading eressea/spells/spell */ spells = xmlXPathEvalExpression(BAD_CAST "/eressea/spells/spell", xpath); - if (spells->nodesetval!=NULL) { + if (spells->nodesetval != NULL) { xmlNodeSetPtr nodes = spells->nodesetval; + int i; - for (i=0;i!=nodes->nodeNr;++i) { + for (i = 0; i != nodes->nodeNr; ++i) { xmlXPathObjectPtr result; + xmlNodePtr node = nodes->nodeTab[i]; - xmlChar * propValue; + + xmlChar *propValue; + int k; - spell_component * component; - spell * sp = (spell *)calloc(1, sizeof(spell)); + + spell_component *component; + + spell *sp = (spell *) calloc(1, sizeof(spell)); static int modes[] = { 0, PRECOMBATSPELL, COMBATSPELL, POSTCOMBATSPELL }; /* spellname */ propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - sp->sname = strdup((const char*)propValue); + assert(propValue != NULL); + sp->sname = strdup((const char *)propValue); xmlFree(propValue); propValue = xmlGetProp(node, BAD_CAST "parameters"); if (propValue) { - sp->parameter=strdup((const char *)propValue); + sp->parameter = strdup((const char *)propValue); xmlFree(propValue); } propValue = xmlGetProp(node, BAD_CAST "syntax"); if (propValue) { - sp->syntax=strdup((const char *)propValue); + sp->syntax = strdup((const char *)propValue); xmlFree(propValue); } /* magic type */ propValue = xmlGetProp(node, BAD_CAST "type"); - assert(propValue!=NULL); - for (sp->magietyp=0;sp->magietyp!=MAXMAGIETYP;++sp->magietyp) { - if (strcmp(magic_school[sp->magietyp], (const char *)propValue)==0) break; + assert(propValue != NULL); + for (sp->magietyp = 0; sp->magietyp != MAXMAGIETYP; ++sp->magietyp) { + if (strcmp(magic_school[sp->magietyp], (const char *)propValue) == 0) + break; } - assert(sp->magietyp!=MAXMAGIETYP); + assert(sp->magietyp != MAXMAGIETYP); xmlFree(propValue); /* level, rank and flags */ sp->id = xml_ivalue(node, "index", 0); sp->level = xml_ivalue(node, "level", -1); sp->rank = (char)xml_ivalue(node, "rank", -1); - if (xml_bvalue(node, "los", false)) sp->sptyp |= TESTCANSEE; /* must see or have contact */ - if (!xml_bvalue(node, "target_global", false)) sp->sptyp |= SEARCHLOCAL; /* must be in same region */ - if (xml_bvalue(node, "ship", false)) sp->sptyp |= ONSHIPCAST; - if (xml_bvalue(node, "ocean", false)) sp->sptyp |= OCEANCASTABLE; - if (xml_bvalue(node, "far", false)) sp->sptyp |= FARCASTING; - if (xml_bvalue(node, "variable", false)) sp->sptyp |= SPELLLEVEL; + if (xml_bvalue(node, "los", false)) + sp->sptyp |= TESTCANSEE; /* must see or have contact */ + if (!xml_bvalue(node, "target_global", false)) + sp->sptyp |= SEARCHLOCAL; /* must be in same region */ + if (xml_bvalue(node, "ship", false)) + sp->sptyp |= ONSHIPCAST; + if (xml_bvalue(node, "ocean", false)) + sp->sptyp |= OCEANCASTABLE; + if (xml_bvalue(node, "far", false)) + sp->sptyp |= FARCASTING; + if (xml_bvalue(node, "variable", false)) + sp->sptyp |= SPELLLEVEL; k = xml_ivalue(node, "combat", 0); - if (k>=0 && k<=3) sp->sptyp |= modes[k]; + if (k >= 0 && k <= 3) + sp->sptyp |= modes[k]; if (gamecode_enabled) { /* reading eressea/spells/spell/function */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - if (result->nodesetval->nodeNr==0) { + if (result->nodesetval->nodeNr == 0) { /* deprecated style: this spell gets its' function from a callback */ - if (set_spelldata_cb) set_spelldata_cb(sp); + if (set_spelldata_cb) + set_spelldata_cb(sp); } else { - for (k=0;k!=result->nodesetval->nodeNr;++k) { + for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; + pf_generic fun; parse_function(node, &fun, &propValue); - if (fun==NULL) { + if (fun == NULL) { log_error(("unknown function name '%s' for spell '%s'\n", - (const char*)propValue, sp->sname)); + (const char *)propValue, sp->sname)); xmlFree(propValue); continue; } - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "cast")==0) { - sp->sp_function = (spell_f)fun; - } else if (strcmp((const char*)propValue, "fumble")==0) { - sp->patzer = (pspell_f)fun; + assert(propValue != NULL); + if (strcmp((const char *)propValue, "cast") == 0) { + sp->sp_function = (spell_f) fun; + } else if (strcmp((const char *)propValue, "fumble") == 0) { + sp->patzer = (pspell_f) fun; } else { - log_error(("unknown function type '%s' for spell %s\n", - (const char*)propValue, sp->sname)); + log_error(("unknown function type '%s' for spell %s\n", + (const char *)propValue, sp->sname)); } xmlFree(propValue); } @@ -1500,17 +1730,23 @@ parse_spells(xmlDocPtr doc) xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "resource", xpath); if (result->nodesetval->nodeNr) { - sp->components = (spell_component *)malloc(sizeof(spell_component)*(result->nodesetval->nodeNr+1)); + sp->components = + (spell_component *) malloc(sizeof(spell_component) * + (result->nodesetval->nodeNr + 1)); sp->components[result->nodesetval->nodeNr].type = 0; } - for (component=sp->components,k=0;k!=result->nodesetval->nodeNr;++k) { - const resource_type * rtype; + for (component = sp->components, k = 0; k != result->nodesetval->nodeNr; + ++k) { + const resource_type *rtype; + xmlNodePtr node = result->nodesetval->nodeTab[k]; + propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue); rtype = rt_find((const char *)propValue); if (!rtype) { - log_error(("spell %s uses unknown component %s.\n", sp->sname, (const char*)propValue)); + log_error(("spell %s uses unknown component %s.\n", sp->sname, + (const char *)propValue)); xmlFree(propValue); continue; } @@ -1519,10 +1755,10 @@ parse_spells(xmlDocPtr doc) component->amount = xml_ivalue(node, "amount", 1); component->cost = SPC_FIX; propValue = xmlGetProp(node, BAD_CAST "cost"); - if (propValue!=NULL) { - if (strcmp((const char *)propValue, "linear")==0) { + if (propValue != NULL) { + if (strcmp((const char *)propValue, "linear") == 0) { component->cost = SPC_LINEAR; - } else if (strcmp((const char *)propValue, "level")==0) { + } else if (strcmp((const char *)propValue, "level") == 0) { component->cost = SPC_LEVEL; } xmlFree(propValue); @@ -1541,57 +1777,68 @@ parse_spells(xmlDocPtr doc) return 0; } -static void -parse_param(struct param ** params, xmlNodePtr node) +static void parse_param(struct param **params, xmlNodePtr node) { - xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); - xmlChar * propValue = xmlGetProp(node, BAD_CAST "value"); + xmlChar *propName = xmlGetProp(node, BAD_CAST "name"); - set_param(params, (const char*)propName, (const char*)propValue); + xmlChar *propValue = xmlGetProp(node, BAD_CAST "value"); + + set_param(params, (const char *)propName, (const char *)propValue); xmlFree(propName); xmlFree(propValue); } -static void -parse_ai(race * rc, xmlNodePtr node) +static void parse_ai(race * rc, xmlNodePtr node) { rc->splitsize = xml_ivalue(node, "splitsize", 0); rc->aggression = (float)xml_fvalue(node, "aggression", 0.04); - if (xml_bvalue(node, "killpeasants", false)) rc->flags |= RCF_KILLPEASANTS; - if (xml_bvalue(node, "moverandom", false)) rc->flags |= RCF_MOVERANDOM; - if (xml_bvalue(node, "learn", false)) rc->flags |= RCF_LEARN; + if (xml_bvalue(node, "killpeasants", false)) + rc->flags |= RCF_KILLPEASANTS; + if (xml_bvalue(node, "moverandom", false)) + rc->flags |= RCF_MOVERANDOM; + if (xml_bvalue(node, "learn", false)) + rc->flags |= RCF_LEARN; } -static int -parse_races(xmlDocPtr doc) +static int parse_races(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr races; + xmlNodeSetPtr nodes; + int i; /* reading eressea/races/race */ races = xmlXPathEvalExpression(BAD_CAST "/eressea/races/race", xpath); nodes = races->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { + for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; + xmlNodePtr child; - xmlChar * propValue; - race * rc; + + xmlChar *propValue; + + race *rc; + xmlXPathObjectPtr result; + int k, study_speed_base; - struct att * attack; + + struct att *attack; propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - rc = rc_find((const char*)propValue); - if (rc==NULL) rc = rc_add(rc_new((const char*)propValue)); + assert(propValue != NULL); + rc = rc_find((const char *)propValue); + if (rc == NULL) + rc = rc_add(rc_new((const char *)propValue)); xmlFree(propValue); propValue = xmlGetProp(node, BAD_CAST "damage"); - assert(propValue!=NULL); - rc->def_damage = strdup((const char*)propValue); + assert(propValue != NULL); + rc->def_damage = strdup((const char *)propValue); xmlFree(propValue); rc->magres = (float)xml_fvalue(node, "magres", 0.0); @@ -1611,53 +1858,93 @@ parse_races(xmlDocPtr doc) rc->at_bonus = (char)xml_ivalue(node, "attackmodifier", 0); rc->df_bonus = (char)xml_ivalue(node, "defensemodifier", 0); - if (xml_bvalue(node, "playerrace", false)) rc->flags |= RCF_PLAYERRACE; - if (xml_bvalue(node, "scarepeasants", false)) rc->flags |= RCF_SCAREPEASANTS; - if (xml_bvalue(node, "cansteal", true)) rc->flags |= RCF_CANSTEAL; - if (xml_bvalue(node, "cansail", true)) rc->flags |= RCF_CANSAIL; - if (xml_bvalue(node, "cannotmove", false)) rc->flags |= RCF_CANNOTMOVE; - if (xml_bvalue(node, "fly", false)) rc->flags |= RCF_FLY; - if (xml_bvalue(node, "invisible", false)) rc->flags |= RCF_INVISIBLE; - if (xml_bvalue(node, "coastal", false)) rc->flags |= RCF_COASTAL; - if (xml_bvalue(node, "unarmedguard", false)) rc->flags |= RCF_UNARMEDGUARD; - if (xml_bvalue(node, "swim", false)) rc->flags |= RCF_SWIM; - if (xml_bvalue(node, "walk", false)) rc->flags |= RCF_WALK; - if (!xml_bvalue(node, "canlearn", true)) rc->flags |= RCF_NOLEARN; - if (!xml_bvalue(node, "canteach", true)) rc->flags |= RCF_NOTEACH; - if (xml_bvalue(node, "horse", false)) rc->flags |= RCF_HORSE; - if (xml_bvalue(node, "desert", false)) rc->flags |= RCF_DESERT; - if (xml_bvalue(node, "absorbpeasants", false)) rc->flags |= RCF_ABSORBPEASANTS; - if (xml_bvalue(node, "noheal", false)) rc->flags |= RCF_NOHEAL; - if (xml_bvalue(node, "noweapons", false)) rc->flags |= RCF_NOWEAPONS; - if (xml_bvalue(node, "shapeshift", false)) rc->flags |= RCF_SHAPESHIFT; - if (xml_bvalue(node, "shapeshiftany", false)) rc->flags |= RCF_SHAPESHIFTANY; - if (xml_bvalue(node, "illusionary", false)) rc->flags |= RCF_ILLUSIONARY; - if (xml_bvalue(node, "undead", false)) rc->flags |= RCF_UNDEAD; - if (xml_bvalue(node, "dragon", false)) rc->flags |= RCF_DRAGON; - if (xml_bvalue(node, "shipspeed", false)) rc->flags |= RCF_SHIPSPEED; - if (xml_bvalue(node, "stonegolem", false)) rc->flags |= RCF_STONEGOLEM; - if (xml_bvalue(node, "irongolem", false)) rc->flags |= RCF_IRONGOLEM; + if (xml_bvalue(node, "playerrace", false)) + rc->flags |= RCF_PLAYERRACE; + if (xml_bvalue(node, "scarepeasants", false)) + rc->flags |= RCF_SCAREPEASANTS; + if (xml_bvalue(node, "cansteal", true)) + rc->flags |= RCF_CANSTEAL; + if (xml_bvalue(node, "cansail", true)) + rc->flags |= RCF_CANSAIL; + if (xml_bvalue(node, "cannotmove", false)) + rc->flags |= RCF_CANNOTMOVE; + if (xml_bvalue(node, "fly", false)) + rc->flags |= RCF_FLY; + if (xml_bvalue(node, "invisible", false)) + rc->flags |= RCF_INVISIBLE; + if (xml_bvalue(node, "coastal", false)) + rc->flags |= RCF_COASTAL; + if (xml_bvalue(node, "unarmedguard", false)) + rc->flags |= RCF_UNARMEDGUARD; + if (xml_bvalue(node, "swim", false)) + rc->flags |= RCF_SWIM; + if (xml_bvalue(node, "walk", false)) + rc->flags |= RCF_WALK; + if (!xml_bvalue(node, "canlearn", true)) + rc->flags |= RCF_NOLEARN; + if (!xml_bvalue(node, "canteach", true)) + rc->flags |= RCF_NOTEACH; + if (xml_bvalue(node, "horse", false)) + rc->flags |= RCF_HORSE; + if (xml_bvalue(node, "desert", false)) + rc->flags |= RCF_DESERT; + if (xml_bvalue(node, "absorbpeasants", false)) + rc->flags |= RCF_ABSORBPEASANTS; + if (xml_bvalue(node, "noheal", false)) + rc->flags |= RCF_NOHEAL; + if (xml_bvalue(node, "noweapons", false)) + rc->flags |= RCF_NOWEAPONS; + if (xml_bvalue(node, "shapeshift", false)) + rc->flags |= RCF_SHAPESHIFT; + if (xml_bvalue(node, "shapeshiftany", false)) + rc->flags |= RCF_SHAPESHIFTANY; + if (xml_bvalue(node, "illusionary", false)) + rc->flags |= RCF_ILLUSIONARY; + if (xml_bvalue(node, "undead", false)) + rc->flags |= RCF_UNDEAD; + if (xml_bvalue(node, "dragon", false)) + rc->flags |= RCF_DRAGON; + if (xml_bvalue(node, "shipspeed", false)) + rc->flags |= RCF_SHIPSPEED; + if (xml_bvalue(node, "stonegolem", false)) + rc->flags |= RCF_STONEGOLEM; + if (xml_bvalue(node, "irongolem", false)) + rc->flags |= RCF_IRONGOLEM; - if (xml_bvalue(node, "giveitem", false)) rc->ec_flags |= GIVEITEM; - if (xml_bvalue(node, "giveperson", false)) rc->ec_flags |= GIVEPERSON; - if (xml_bvalue(node, "giveunit", false)) rc->ec_flags |= GIVEUNIT; - if (xml_bvalue(node, "getitem", false)) rc->ec_flags |= GETITEM; - if (xml_bvalue(node, "recruithorses", false)) rc->ec_flags |= ECF_REC_HORSES; - if (xml_bvalue(node, "recruitethereal", false)) rc->ec_flags |= ECF_REC_ETHEREAL; - if (xml_bvalue(node, "recruitunlimited", false)) rc->ec_flags |= ECF_REC_UNLIMITED; + if (xml_bvalue(node, "giveitem", false)) + rc->ec_flags |= GIVEITEM; + if (xml_bvalue(node, "giveperson", false)) + rc->ec_flags |= GIVEPERSON; + if (xml_bvalue(node, "giveunit", false)) + rc->ec_flags |= GIVEUNIT; + if (xml_bvalue(node, "getitem", false)) + rc->ec_flags |= GETITEM; + if (xml_bvalue(node, "recruithorses", false)) + rc->ec_flags |= ECF_REC_HORSES; + if (xml_bvalue(node, "recruitethereal", false)) + rc->ec_flags |= ECF_REC_ETHEREAL; + if (xml_bvalue(node, "recruitunlimited", false)) + rc->ec_flags |= ECF_REC_UNLIMITED; - if (xml_bvalue(node, "equipment", false)) rc->battle_flags |= BF_EQUIPMENT; - if (xml_bvalue(node, "noblock", false)) rc->battle_flags |= BF_NOBLOCK; - if (xml_bvalue(node, "invinciblenonmagic", false)) rc->battle_flags |= BF_INV_NONMAGIC; - if (xml_bvalue(node, "resistbash", false)) rc->battle_flags |= BF_RES_BASH; - if (xml_bvalue(node, "resistcut", false)) rc->battle_flags |= BF_RES_CUT; - if (xml_bvalue(node, "resistpierce", false)) rc->battle_flags |= BF_RES_PIERCE; - if (xml_bvalue(node, "canattack", true)) rc->battle_flags |= BF_CANATTACK; + if (xml_bvalue(node, "equipment", false)) + rc->battle_flags |= BF_EQUIPMENT; + if (xml_bvalue(node, "noblock", false)) + rc->battle_flags |= BF_NOBLOCK; + if (xml_bvalue(node, "invinciblenonmagic", false)) + rc->battle_flags |= BF_INV_NONMAGIC; + if (xml_bvalue(node, "resistbash", false)) + rc->battle_flags |= BF_RES_BASH; + if (xml_bvalue(node, "resistcut", false)) + rc->battle_flags |= BF_RES_CUT; + if (xml_bvalue(node, "resistpierce", false)) + rc->battle_flags |= BF_RES_PIERCE; + if (xml_bvalue(node, "canattack", true)) + rc->battle_flags |= BF_CANATTACK; - for (child=node->children;child;child=child->next) { - if (strcmp((const char *)child->name, "ai")==0) { + for (child = node->children; child; child = child->next) { + if (strcmp((const char *)child->name, "ai") == 0) { parse_ai(rc, child); - } else if (strcmp((const char *)child->name, "param")==0) { + } else if (strcmp((const char *)child->name, "param") == 0) { parse_param(&rc->parameters, child); } } @@ -1667,24 +1954,28 @@ parse_races(xmlDocPtr doc) xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "skill", xpath); memset(rc->bonus, 0, sizeof(rc->bonus)); - for (k=0;k!=result->nodesetval->nodeNr;++k) { + for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; + int mod = xml_ivalue(node, "modifier", 0); + int speed = xml_ivalue(node, "speed", study_speed_base); + skill_t sk; propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); - sk = sk_find((const char*)propValue); - if (sk!=NOSKILL) { + assert(propValue != NULL); + sk = sk_find((const char *)propValue); + if (sk != NOSKILL) { rc->bonus[sk] = (char)mod; if (speed) { - if (!rc->study_speed) rc->study_speed = calloc(1, MAXSKILLS); + if (!rc->study_speed) + rc->study_speed = calloc(1, MAXSKILLS); rc->study_speed[sk] = (char)speed; } } else { log_error(("unknown skill '%s' in race '%s'\n", - (const char*)propValue, rc->_name[0])); + (const char *)propValue, rc->_name[0])); } xmlFree(propValue); } @@ -1694,33 +1985,36 @@ parse_races(xmlDocPtr doc) /* reading eressea/races/race/function */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { + for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; + pf_generic fun; parse_function(node, &fun, &propValue); - if (fun==NULL) { + if (fun == NULL) { log_error(("unknown function name '%s' for race %s\n", - (const char*)propValue, rc->_name[0])); + (const char *)propValue, rc->_name[0])); xmlFree(propValue); continue; } - assert(propValue!=NULL); - if (strcmp((const char*)propValue, "name")==0) { - rc->generate_name = (const char * (*)(const struct unit*))fun; - } else if (strcmp((const char*)propValue, "describe")==0) { - rc->describe = (const char * (*)(const struct unit*, const struct locale *))fun; - } else if (strcmp((const char*)propValue, "age")==0) { - rc->age = (void(*)(struct unit*))fun; - } else if (strcmp((const char*)propValue, "move")==0) { - rc->move_allowed = (boolean(*)(const struct region *, const struct region *))fun; - } else if (strcmp((const char*)propValue, "itemdrop")==0) { - rc->itemdrop = (struct item *(*)(const struct race *, int))fun; - } else if (strcmp((const char*)propValue, "initfamiliar")==0) { - rc->init_familiar = (void(*)(struct unit *))fun; + assert(propValue != NULL); + if (strcmp((const char *)propValue, "name") == 0) { + rc->generate_name = (const char *(*)(const struct unit *))fun; + } else if (strcmp((const char *)propValue, "describe") == 0) { + rc->describe = + (const char *(*)(const struct unit *, const struct locale *))fun; + } else if (strcmp((const char *)propValue, "age") == 0) { + rc->age = (void (*)(struct unit *))fun; + } else if (strcmp((const char *)propValue, "move") == 0) { + rc->move_allowed = + (boolean(*)(const struct region *, const struct region *))fun; + } else if (strcmp((const char *)propValue, "itemdrop") == 0) { + rc->itemdrop = (struct item * (*)(const struct race *, int))fun; + } else if (strcmp((const char *)propValue, "initfamiliar") == 0) { + rc->init_familiar = (void (*)(struct unit *))fun; } else { log_error(("unknown function type '%s' for race %s\n", - (const char*)propValue, rc->_name[0])); + (const char *)propValue, rc->_name[0])); } xmlFree(propValue); } @@ -1730,18 +2024,19 @@ parse_races(xmlDocPtr doc) /* reading eressea/races/race/familiar */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "familiar", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { + for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - race * frc; + + race *frc; propValue = xmlGetProp(node, BAD_CAST "race"); - assert(propValue!=NULL); + assert(propValue != NULL); frc = rc_find((const char *)propValue); if (frc == NULL) { // log_error(("%s not registered, is familiar for %s\n", // (const char*)propValue, rc->_name[0])); // assert(frc!=NULL); - frc = rc_add(rc_new((const char*)propValue)); + frc = rc_add(rc_new((const char *)propValue)); } if (xml_bvalue(node, "default", false)) { rc->familiars[k] = rc->familiars[0]; @@ -1756,9 +2051,11 @@ parse_races(xmlDocPtr doc) /* reading eressea/races/race/precombatspell */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "precombatspell", xpath); - assert(rc->precombatspell==NULL || !"precombatspell is already initialized"); - for (k=0;k!=result->nodesetval->nodeNr;++k) { + assert(rc->precombatspell == NULL + || !"precombatspell is already initialized"); + for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; + rc->precombatspell = xml_spell(node, "spell"); } xmlXPathFreeObject(result); @@ -1767,13 +2064,15 @@ parse_races(xmlDocPtr doc) xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "attack", xpath); attack = rc->attack; - for (k=0;k!=result->nodesetval->nodeNr;++k) { + for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - while (attack->type!=AT_NONE) ++attack; + + while (attack->type != AT_NONE) + ++attack; propValue = xmlGetProp(node, BAD_CAST "damage"); - if (propValue!=NULL) { - attack->data.dice = strdup((const char*)propValue); + if (propValue != NULL) { + attack->data.dice = strdup((const char *)propValue); xmlFree(propValue); } else { attack->data.sp = xml_spell(node, "spell"); @@ -1791,67 +2090,87 @@ parse_races(xmlDocPtr doc) return 0; } -static int -parse_terrains(xmlDocPtr doc) +static int parse_terrains(xmlDocPtr doc) { xmlXPathContextPtr xpath; + xmlXPathObjectPtr terrains; + xmlNodeSetPtr nodes; + int i; xpath = xmlXPathNewContext(doc); /* reading eressea/terrains/terrain */ - terrains = xmlXPathEvalExpression(BAD_CAST "/eressea/terrains/terrain", xpath); + terrains = + xmlXPathEvalExpression(BAD_CAST "/eressea/terrains/terrain", xpath); nodes = terrains->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { + for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; - terrain_type * terrain = calloc(1, sizeof(terrain_type)); - xmlChar * propValue; + + terrain_type *terrain = calloc(1, sizeof(terrain_type)); + + xmlChar *propValue; + xmlXPathObjectPtr xpathChildren; + xmlNodeSetPtr children; propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue!=NULL); + assert(propValue != NULL); terrain->_name = strdup((const char *)propValue); xmlFree(propValue); terrain->max_road = (short)xml_ivalue(node, "road", 0); - assert(terrain->max_road>=0); + assert(terrain->max_road >= 0); terrain->size = xml_ivalue(node, "size", 0); - if (xml_bvalue(node, "forbidden", false)) terrain->flags |= FORBIDDEN_REGION; + if (xml_bvalue(node, "forbidden", false)) + terrain->flags |= FORBIDDEN_REGION; else { - if (xml_bvalue(node, "fly", true)) terrain->flags |= FLY_INTO; - if (xml_bvalue(node, "sail", true)) terrain->flags |= SAIL_INTO; - if (xml_bvalue(node, "walk", true)) terrain->flags |= WALK_INTO; - if (xml_bvalue(node, "swim", false)) terrain->flags |= SWIM_INTO; - if (xml_bvalue(node, "shallow", true)) terrain->flags |= LARGE_SHIPS; - if (xml_bvalue(node, "cavalry", false)) terrain->flags |= CAVALRY_REGION; + if (xml_bvalue(node, "fly", true)) + terrain->flags |= FLY_INTO; + if (xml_bvalue(node, "sail", true)) + terrain->flags |= SAIL_INTO; + if (xml_bvalue(node, "walk", true)) + terrain->flags |= WALK_INTO; + if (xml_bvalue(node, "swim", false)) + terrain->flags |= SWIM_INTO; + if (xml_bvalue(node, "shallow", true)) + terrain->flags |= LARGE_SHIPS; + if (xml_bvalue(node, "cavalry", false)) + terrain->flags |= CAVALRY_REGION; } - if (xml_bvalue(node, "sea", false)) terrain->flags |= SEA_REGION; - if (xml_bvalue(node, "arctic", false)) terrain->flags |= ARCTIC_REGION; - if (xml_bvalue(node, "land", true)) terrain->flags |= LAND_REGION; - if (xml_bvalue(node, "forest", false)) terrain->flags |= FOREST_REGION; + if (xml_bvalue(node, "sea", false)) + terrain->flags |= SEA_REGION; + if (xml_bvalue(node, "arctic", false)) + terrain->flags |= ARCTIC_REGION; + if (xml_bvalue(node, "land", true)) + terrain->flags |= LAND_REGION; + if (xml_bvalue(node, "forest", false)) + terrain->flags |= FOREST_REGION; terrain->distribution = (short)xml_ivalue(node, "seed", 0); xpath->node = node; xpathChildren = xmlXPathEvalExpression(BAD_CAST "herb", xpath); children = xpathChildren->nodesetval; - if (children->nodeNr>0) { + if (children->nodeNr > 0) { int k; - terrain->herbs = malloc((children->nodeNr+1) * sizeof(item_type*)); + terrain->herbs = malloc((children->nodeNr + 1) * sizeof(item_type *)); terrain->herbs[children->nodeNr] = NULL; - for (k=0;k!=children->nodeNr;++k) { + for (k = 0; k != children->nodeNr; ++k) { xmlNodePtr nodeHerb = children->nodeTab[k]; - const struct resource_type * rtype; + + const struct resource_type *rtype; propValue = xmlGetProp(nodeHerb, BAD_CAST "name"); - assert(propValue!=NULL); - rtype = rt_find((const char*)propValue); - assert(rtype!=NULL && rtype->itype!=NULL && fval(rtype->itype, ITF_HERB)); + assert(propValue != NULL); + rtype = rt_find((const char *)propValue); + assert(rtype != NULL && rtype->itype != NULL + && fval(rtype->itype, ITF_HERB)); terrain->herbs[k] = rtype->itype; xmlFree(propValue); } @@ -1861,17 +2180,18 @@ parse_terrains(xmlDocPtr doc) xpath->node = node; xpathChildren = xmlXPathEvalExpression(BAD_CAST "resource", xpath); children = xpathChildren->nodesetval; - if (children->nodeNr>0) { + if (children->nodeNr > 0) { int k; - terrain->production = malloc((children->nodeNr+1) * sizeof(terrain_production)); + terrain->production = + malloc((children->nodeNr + 1) * sizeof(terrain_production)); terrain->production[children->nodeNr].type = NULL; - for (k=0;k!=children->nodeNr;++k) { + for (k = 0; k != children->nodeNr; ++k) { xmlNodePtr nodeProd = children->nodeTab[k]; propValue = xmlGetProp(nodeProd, BAD_CAST "name"); - assert(propValue!=NULL); - terrain->production[k].type = rt_find((const char*)propValue); + assert(propValue != NULL); + terrain->production[k].type = rt_find((const char *)propValue); assert(terrain->production[k].type); xmlFree(propValue); @@ -1890,7 +2210,8 @@ parse_terrains(xmlDocPtr doc) terrain->production[k].divisor = strdup((const char *)propValue); xmlFree(propValue); - terrain->production[k].chance = (float)xml_fvalue(nodeProd, "chance", 1.0); + terrain->production[k].chance = + (float)xml_fvalue(nodeProd, "chance", 1.0); } } xmlXPathFreeObject(xpathChildren); @@ -1905,44 +2226,58 @@ parse_terrains(xmlDocPtr doc) return 0; } -static int -parse_messages(xmlDocPtr doc) +static int parse_messages(xmlDocPtr doc) { xmlXPathContextPtr xpath; + xmlXPathObjectPtr messages; + xmlNodeSetPtr nodes; + int i; - if (!gamecode_enabled) return 0; + if (!gamecode_enabled) + return 0; xpath = xmlXPathNewContext(doc); /* reading eressea/messages/message */ - messages = xmlXPathEvalExpression(BAD_CAST "/eressea/messages/message", xpath); + messages = + xmlXPathEvalExpression(BAD_CAST "/eressea/messages/message", xpath); nodes = messages->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { + for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; - const char * default_section = "events"; - xmlChar * propSection; - xmlChar * propValue; + + const char *default_section = "events"; + + xmlChar *propSection; + + xmlChar *propValue; + xmlXPathObjectPtr result; + int k; - char ** argv = NULL; - const message_type * mtype; + + char **argv = NULL; + + const message_type *mtype; /* arguments */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "type/arg", xpath); - if (result->nodesetval && result->nodesetval->nodeNr>0) { - argv = malloc(sizeof(char*)*(result->nodesetval->nodeNr+1)); - for (k=0;k!=result->nodesetval->nodeNr;++k) { + if (result->nodesetval && result->nodesetval->nodeNr > 0) { + argv = malloc(sizeof(char *) * (result->nodesetval->nodeNr + 1)); + for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; + char zBuffer[128]; - xmlChar * propName, * propType; + + xmlChar *propName, *propType; propName = xmlGetProp(node, BAD_CAST "name"); propType = xmlGetProp(node, BAD_CAST "type"); - sprintf(zBuffer, "%s:%s", (const char*)propName, (const char*)propType); + sprintf(zBuffer, "%s:%s", (const char *)propName, + (const char *)propType); xmlFree(propName); xmlFree(propType); argv[k] = strdup(zBuffer); @@ -1954,10 +2289,10 @@ parse_messages(xmlDocPtr doc) /* add the messagetype */ propValue = xmlGetProp(node, BAD_CAST "name"); mtype = mt_find((const char *)propValue); - if (mtype==NULL) { - mtype = mt_register(mt_new((const char *)propValue, (const char**)argv)); + if (mtype == NULL) { + mtype = mt_register(mt_new((const char *)propValue, (const char **)argv)); } else { - assert(argv!=NULL || !"cannot redefine arguments of message now"); + assert(argv != NULL || !"cannot redefine arguments of message now"); } xmlFree(propValue); @@ -1965,33 +2300,39 @@ parse_messages(xmlDocPtr doc) crt_register(mtype); /* let's clean up the mess */ - if (argv!=NULL) { - for (k=0;argv[k]!=NULL;++k) free(argv[k]); + if (argv != NULL) { + for (k = 0; argv[k] != NULL; ++k) + free(argv[k]); free(argv); } propSection = xmlGetProp(node, BAD_CAST "section"); - if (propSection==NULL) propSection = BAD_CAST default_section; + if (propSection == NULL) + propSection = BAD_CAST default_section; /* strings */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "text", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { + for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - struct locale * lang; - xmlChar * propText; + + struct locale *lang; + + xmlChar *propText; xml_readtext(node, &lang, &propText); if (lang) { xml_cleanup_string(propText); - nrt_register(mtype, lang, (const char *)propText, 0, (const char*)propSection); + nrt_register(mtype, lang, (const char *)propText, 0, + (const char *)propSection); } xmlFree(propText); } xmlXPathFreeObject(result); - if (propSection != BAD_CAST default_section) xmlFree(propSection); + if (propSection != BAD_CAST default_section) + xmlFree(propSection); } xmlXPathFreeObject(messages); @@ -2001,35 +2342,46 @@ parse_messages(xmlDocPtr doc) } static void -xml_readstrings(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, boolean names) +xml_readstrings(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, + boolean names) { int i; - for (i=0;i!=nodeNr;++i) { + for (i = 0; i != nodeNr; ++i) { xmlNodePtr stringNode = nodeTab[i]; - xmlChar * propName = xmlGetProp(stringNode, BAD_CAST "name"); - xmlChar * propNamespace = NULL; + + xmlChar *propName = xmlGetProp(stringNode, BAD_CAST "name"); + + xmlChar *propNamespace = NULL; + xmlXPathObjectPtr result; + int k; + char zName[128]; - assert(propName!=NULL); - if (names) propNamespace = xmlGetProp(stringNode->parent, BAD_CAST "name"); - mkname_buf((const char*)propNamespace, (const char*)propName, zName); - if (propNamespace!=NULL) xmlFree(propNamespace); + assert(propName != NULL); + if (names) + propNamespace = xmlGetProp(stringNode->parent, BAD_CAST "name"); + mkname_buf((const char *)propNamespace, (const char *)propName, zName); + if (propNamespace != NULL) + xmlFree(propNamespace); xmlFree(propName); /* strings */ xpath->node = stringNode; result = xmlXPathEvalExpression(BAD_CAST "text", xpath); - for (k=0;k!=result->nodesetval->nodeNr;++k) { + for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr textNode = result->nodesetval->nodeTab[k]; - struct locale * lang; - xmlChar * propText; + + struct locale *lang; + + xmlChar *propText; xml_readtext(textNode, &lang, &propText); - if (propText!=NULL) { - assert(strcmp(zName, (const char*)xml_cleanup_string(BAD_CAST zName))==0); + if (propText != NULL) { + assert(strcmp(zName, + (const char *)xml_cleanup_string(BAD_CAST zName)) == 0); if (lang) { xml_cleanup_string(propText); locale_setstring(lang, zName, (const char *)propText); @@ -2037,26 +2389,29 @@ xml_readstrings(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, bool xmlFree(propText); } else { log_warning(("string %s has no text in locale %s\n", - zName, locale_name(lang))); + zName, locale_name(lang))); } } xmlXPathFreeObject(result); } } -static int -parse_strings(xmlDocPtr doc) +static int parse_strings(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr strings; /* reading eressea/strings/string */ strings = xmlXPathEvalExpression(BAD_CAST "/eressea/strings/string", xpath); - xml_readstrings(xpath, strings->nodesetval->nodeTab, strings->nodesetval->nodeNr, false); + xml_readstrings(xpath, strings->nodesetval->nodeTab, + strings->nodesetval->nodeNr, false); xmlXPathFreeObject(strings); - strings = xmlXPathEvalExpression(BAD_CAST "/eressea/strings/namespace/string", xpath); - xml_readstrings(xpath, strings->nodesetval->nodeTab, strings->nodesetval->nodeNr, true); + strings = + xmlXPathEvalExpression(BAD_CAST "/eressea/strings/namespace/string", xpath); + xml_readstrings(xpath, strings->nodesetval->nodeTab, + strings->nodesetval->nodeNr, true); xmlXPathFreeObject(strings); xmlXPathFreeContext(xpath); @@ -2064,53 +2419,61 @@ parse_strings(xmlDocPtr doc) } static void -xml_readprefixes(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, boolean names) +xml_readprefixes(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, + boolean names) { int i; - for (i=0;i!=nodeNr;++i) { + for (i = 0; i != nodeNr; ++i) { xmlNodePtr node = nodeTab[i]; - xmlChar * propText = xmlNodeListGetString(node->doc, node->children, 1); - if (propText!=NULL) { - add_raceprefix((const char*)propText); + xmlChar *propText = xmlNodeListGetString(node->doc, node->children, 1); + + if (propText != NULL) { + add_raceprefix((const char *)propText); xmlFree(propText); } } } -static int -parse_prefixes(xmlDocPtr doc) +static int parse_prefixes(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr strings; /* reading eressea/strings/string */ strings = xmlXPathEvalExpression(BAD_CAST "/eressea/prefixes/prefix", xpath); - xml_readprefixes(xpath, strings->nodesetval->nodeTab, strings->nodesetval->nodeNr, false); + xml_readprefixes(xpath, strings->nodesetval->nodeTab, + strings->nodesetval->nodeNr, false); xmlXPathFreeObject(strings); xmlXPathFreeContext(xpath); return 0; } -static int -parse_main(xmlDocPtr doc) +static int parse_main(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr result = xmlXPathEvalExpression(BAD_CAST "/eressea/game", xpath); + + xmlXPathObjectPtr result = + xmlXPathEvalExpression(BAD_CAST "/eressea/game", xpath); xmlNodeSetPtr nodes = result->nodesetval; + int i; - xmlChar * propValue; - if (nodes->nodeNr>0) { + xmlChar *propValue; + + if (nodes->nodeNr > 0) { xmlNodePtr node = nodes->nodeTab[0]; - global.producexpchance = (float)xml_fvalue(node, "learningbydoing", 1.0/3); + global.producexpchance = + (float)xml_fvalue(node, "learningbydoing", 1.0 / 3); propValue = xmlGetProp(node, BAD_CAST "name"); - if (propValue!=NULL) { - global.gamename = strdup((const char*)propValue); + if (propValue != NULL) { + global.gamename = strdup((const char *)propValue); + xmlFree(propValue); } @@ -2120,8 +2483,9 @@ parse_main(xmlDocPtr doc) xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "param", xpath); nodes = result->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { + for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; + parse_param(&global.parameters, node); } @@ -2130,21 +2494,26 @@ parse_main(xmlDocPtr doc) /* reading eressea/game/order */ result = xmlXPathEvalExpression(BAD_CAST "order", xpath); nodes = result->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { + for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; - xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); + + xmlChar *propName = xmlGetProp(node, BAD_CAST "name"); + boolean disable = xml_bvalue(node, "disable", false); if (disable) { int k; - for (k=0;k!=MAXKEYWORDS;++k) { - if (strcmp(keywords[k], (const char*)propName)==0) { - global.disabled[k]=1; + + for (k = 0; k != MAXKEYWORDS; ++k) { + if (strcmp(keywords[k], (const char *)propName) == 0) { + global.disabled[k] = 1; + break; } } - if (k==MAXKEYWORDS) { - log_error(("trying to disable unknown comand %s\n", (const char*)propName)); + if (k == MAXKEYWORDS) { + log_error(("trying to disable unknown comand %s\n", + (const char *)propName)); } } xmlFree(propName); @@ -2155,11 +2524,14 @@ parse_main(xmlDocPtr doc) /* reading eressea/game/skill */ result = xmlXPathEvalExpression(BAD_CAST "skill", xpath); nodes = result->nodesetval; - for (i=0;i!=nodes->nodeNr;++i) { + for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; - xmlChar * propName = xmlGetProp(node, BAD_CAST "name"); + + xmlChar *propName = xmlGetProp(node, BAD_CAST "name"); + boolean enable = xml_bvalue(node, "enable", true); - enable_skill((const char*)propName, enable); + + enable_skill((const char *)propName, enable); xmlFree(propName); } } @@ -2169,8 +2541,7 @@ parse_main(xmlDocPtr doc) return 0; } -void -register_xmlreader(void) +void register_xmlreader(void) { xml_register_callback(parse_main); @@ -2180,12 +2551,12 @@ register_xmlreader(void) xml_register_callback(parse_resources); xml_register_callback(parse_rules); - xml_register_callback(parse_terrains); /* requires resources */ - xml_register_callback(parse_buildings); /* requires resources */ - xml_register_callback(parse_ships); /* requires terrains */ - xml_register_callback(parse_spells); /* requires resources */ - xml_register_callback(parse_equipment); /* requires spells */ - xml_register_callback(parse_races); /* requires spells */ + xml_register_callback(parse_terrains); /* requires resources */ + xml_register_callback(parse_buildings); /* requires resources */ + xml_register_callback(parse_ships); /* requires terrains */ + xml_register_callback(parse_spells); /* requires resources */ + xml_register_callback(parse_equipment); /* requires spells */ + xml_register_callback(parse_races); /* requires spells */ xml_register_callback(parse_calendar); xml_register_callback(parse_directions); } diff --git a/src/kernel/xmlreader.h b/src/kernel/xmlreader.h index 4c4457da1..7209b40eb 100644 --- a/src/kernel/xmlreader.h +++ b/src/kernel/xmlreader.h @@ -19,9 +19,8 @@ extern "C" { extern void enable_xml_gamecode(void); /* game-specific callbacks */ - extern void (*set_spelldata_cb)(struct spell * sp); + extern void (*set_spelldata_cb) (struct spell * sp); #ifdef __cplusplus } #endif - #endif diff --git a/src/modules/arena.c b/src/modules/arena.c index 84081797e..eb31f2f8e 100644 --- a/src/modules/arena.c +++ b/src/modules/arena.c @@ -68,7 +68,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* exports: */ -plane * arena = NULL; +plane *arena = NULL; /* local vars */ @@ -76,69 +76,84 @@ plane * arena = NULL; #ifdef ARENA_CREATION static unsigned int arena_id = 0; -static region * arena_center = NULL; + +static region *arena_center = NULL; + static int newarena = 0; #endif -static region * tower_region[6]; -static region * start_region[6]; +static region *tower_region[6]; -static region * -arena_region(int school) +static region *start_region[6]; + +static region *arena_region(int school) { return tower_region[school]; } -static building * -arena_tower(int school) +static building *arena_tower(int school) { return arena_region(school)->buildings; } -static int -leave_fail(unit * u) +static int leave_fail(unit * u) { ADDMSG(&u->faction->msgs, msg_message("arena_leave_fail", "unit", u)); return 1; } static int -leave_arena(struct unit * u, const struct item_type * itype, int amount, order * ord) +leave_arena(struct unit *u, const struct item_type *itype, int amount, + order * ord) { - if (!u->building && leave_fail(u)) return -1; - if (u->building!=arena_tower(u->faction->magiegebiet) && leave_fail(u)) return -1; - unused(amount); - unused(ord); - unused(itype); - assert(!"not implemented"); - return 0; + if (!u->building && leave_fail(u)) + return -1; + if (u->building != arena_tower(u->faction->magiegebiet) && leave_fail(u)) + return -1; + unused(amount); + unused(ord); + unused(itype); + assert(!"not implemented"); + return 0; } -static int -enter_fail(unit * u) +static int enter_fail(unit * u) { - ADDMSG(&u->faction->msgs, msg_message("arena_enter_fail", "region unit", u->region, u)); - return 1; + ADDMSG(&u->faction->msgs, msg_message("arena_enter_fail", "region unit", + u->region, u)); + return 1; } static int enter_arena(unit * u, const item_type * itype, int amount, order * ord) { skill_t sk; - region * r = u->region; - unit * u2; + + region *r = u->region; + + unit *u2; + int fee = u->faction->score / 5; + unused(ord); unused(amount); unused(itype); - if (fee>2000) fee = 2000; - if (getplane(r)==arena) return -1; - if (u->number!=1 && enter_fail(u)) return -1; - if (get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, fee) < fee && enter_fail(u)) return -1; - for (sk=0;sk!=MAXSKILLS;++sk) { - if (get_level(u, sk)>1 && enter_fail(u)) return -1; + if (fee > 2000) + fee = 2000; + if (getplane(r) == arena) + return -1; + if (u->number != 1 && enter_fail(u)) + return -1; + if (get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, fee) < fee + && enter_fail(u)) + return -1; + for (sk = 0; sk != MAXSKILLS; ++sk) { + if (get_level(u, sk) > 1 && enter_fail(u)) + return -1; } - for (u2=r->units;u2;u2=u2->next) if (u2->faction==u->faction) break; - + for (u2 = r->units; u2; u2 = u2->next) + if (u2->faction == u->faction) + break; + assert(!"not implemented"); /* for (res=0;res!=MAXRESOURCES;++res) if (res!=R_SILVER && res!=R_ARENA_GATE && (is_item(res) || is_herb(res) || is_potion(res))) { @@ -153,11 +168,14 @@ enter_arena(unit * u, const item_type * itype, int amount, order * ord) } */ if (get_money(u) > fee) { - if (u2) change_money(u2, get_money(u) - fee); - else if (enter_fail(u)) return -1; + if (u2) + change_money(u2, get_money(u) - fee); + else if (enter_fail(u)) + return -1; } - ADDMSG(&u->faction->msgs, msg_message("arena_enter_fail", "region unit", u->region, u)); - use_pooled(u, itype->rtype, GET_SLACK|GET_RESERVE, 1); + ADDMSG(&u->faction->msgs, msg_message("arena_enter_fail", "region unit", + u->region, u)); + use_pooled(u, itype->rtype, GET_SLACK | GET_RESERVE, 1); use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, fee); set_money(u, 109); fset(u, UFL_ANON_FACTION); @@ -170,98 +188,117 @@ enter_arena(unit * u, const item_type * itype, int amount, order * ord) ***/ static int -use_wand_of_tears(unit * user, const struct item_type * itype, int amount, order * ord) +use_wand_of_tears(unit * user, const struct item_type *itype, int amount, + order * ord) { int n; + unused(ord); - for (n=0;n!=amount;++n) { - unit * u; - for (u=user->region->units;u;u=u->next) { + for (n = 0; n != amount; ++n) { + unit *u; + + for (u = user->region->units; u; u = u->next) { if (u->faction != user->faction) { int i; - - for (i=0;i!=u->skill_size;++i) { - if (rng_int()%3) reduce_skill(u, u->skills+i, 1); + + for (i = 0; i != u->skill_size; ++i) { + if (rng_int() % 3) + reduce_skill(u, u->skills + i, 1); } ADDMSG(&u->faction->msgs, msg_message("wand_of_tears_effect", - "unit", u)); + "unit", u)); } } } - ADDMSG(&user->region->msgs, msg_message("wand_of_tears_usage", - "unit", user)); + ADDMSG(&user->region->msgs, msg_message("wand_of_tears_usage", "unit", user)); return 0; } /** * Tempel der Schreie, Demo-Gebäude **/ -static int -age_hurting(attrib * a) { - building * b = (building *)a->data.v; - unit * u; - int active = 0; - if (b==NULL) return AT_AGE_REMOVE; - for (u=b->region->units;u;u=u->next) { - if (u->building==b) { - if (u->faction->magiegebiet==M_DRAIG) { - active ++; - ADDMSG(&b->region->msgs, msg_message("praytoigjarjuk", "unit", u)); - } - } - } - if (active) for (u=b->region->units;u;u=u->next) if (playerrace(u->faction->race)) { - int i; - if (u->faction->magiegebiet!=M_DRAIG) { - for (i=0;i!=active;++i) u->hp = (u->hp+1) / 2; /* make them suffer, but not die */ - ADDMSG(&b->region->msgs, msg_message("cryinpain", "unit", u)); - } - } - return AT_AGE_KEEP; +static int age_hurting(attrib * a) +{ + building *b = (building *) a->data.v; + + unit *u; + + int active = 0; + + if (b == NULL) + return AT_AGE_REMOVE; + for (u = b->region->units; u; u = u->next) { + if (u->building == b) { + if (u->faction->magiegebiet == M_DRAIG) { + active++; + ADDMSG(&b->region->msgs, msg_message("praytoigjarjuk", "unit", u)); + } + } + } + if (active) + for (u = b->region->units; u; u = u->next) + if (playerrace(u->faction->race)) { + int i; + + if (u->faction->magiegebiet != M_DRAIG) { + for (i = 0; i != active; ++i) + u->hp = (u->hp + 1) / 2; /* make them suffer, but not die */ + ADDMSG(&b->region->msgs, msg_message("cryinpain", "unit", u)); + } + } + return AT_AGE_KEEP; } static void -write_hurting(const attrib * a, const void * owner, struct storage * store) { - building * b = a->data.v; - store->w_int(store, b->no); +write_hurting(const attrib * a, const void *owner, struct storage *store) +{ + building *b = a->data.v; + + store->w_int(store, b->no); } -static int -read_hurting(attrib * a, void * owner, struct storage * store) { - int i; - i = store->r_int(store); - a->data.v = (void*)findbuilding(i); - if (a->data.v==NULL) { - log_error(("temple of pain is broken\n")); - return AT_READ_FAIL; - } - return AT_READ_OK; +static int read_hurting(attrib * a, void *owner, struct storage *store) +{ + int i; + + i = store->r_int(store); + a->data.v = (void *)findbuilding(i); + if (a->data.v == NULL) { + log_error(("temple of pain is broken\n")); + return AT_READ_FAIL; + } + return AT_READ_OK; } static attrib_type at_hurting = { - "hurting", NULL, NULL, age_hurting, write_hurting, read_hurting + "hurting", NULL, NULL, age_hurting, write_hurting, read_hurting }; #ifdef ARENA_CREATION -static void -make_temple(region * r) +static void make_temple(region * r) { - const building_type * btype = bt_find("temple"); - building * b; - if (btype==NULL) { + const building_type *btype = bt_find("temple"); + + building *b; + + if (btype == NULL) { log_error(("could not find buildingtype 'temple'\n")); return; } b = r->buildings; - while (b!=NULL && b->type!=btype) b = b->next; - if (b!=NULL) return; /* gibt schon einen */ + while (b != NULL && b->type != btype) + b = b->next; + if (b != NULL) + return; /* gibt schon einen */ - b = new_building(btype, r, NULL); - b->size = btype->maxsize; - b->name = strdup("Igjarjuk's Tempel der Schreie"); - b->display = strdup("Ein Schrein aus spitzen Knochen und lodernden Flammen, gewidmet dem Wyrm der Wyrme"); - a_add(&b->attribs, a_new(&at_hurting))->data.v=b; + b = new_building(btype, r, NULL); + b->size = btype->maxsize; + b->name = strdup("Igjarjuk's Tempel der Schreie"); + b->display = + strdup + ("Ein Schrein aus spitzen Knochen und lodernden Flammen, gewidmet dem Wyrm der Wyrme"); + a_add(&b->attribs, a_new(&at_hurting))->data.v = b; } #endif @@ -269,158 +306,182 @@ make_temple(region * r) * Initialisierung Türme */ #ifdef ARENA_CREATION -static void -tower_init(void) +static void tower_init(void) { - int i, first = newarena; - item_type * it_demonseye = it_find("demonseye"); - item_type * it_griphonwing = it_find("griphonwing"); + int i, first = newarena; + + item_type *it_demonseye = it_find("demonseye"); + + item_type *it_griphonwing = it_find("griphonwing"); + assert(it_griphonwing && it_demonseye); - for (i=0;i!=6;++i) { - region * r = tower_region[i] = findregion(arena_center->x+delta_x[i]*3, arena_center->y+delta_y[i]*3); - if (r) { - start_region[i] = findregion(arena_center->x+delta_x[i]*2, arena_center->y+delta_y[i]*2); - if (rterrain(r)!=T_DESERT) terraform(r, T_DESERT); - if (!r->buildings) { - building * b = new_building(bt_find("castle"), r, NULL); - b->size = 10; - if (i!=0) { - sprintf(buf, "Turm des %s", + for (i = 0; i != 6; ++i) { + region *r = tower_region[i] = + findregion(arena_center->x + delta_x[i] * 3, + arena_center->y + delta_y[i] * 3); + if (r) { + start_region[i] = + findregion(arena_center->x + delta_x[i] * 2, + arena_center->y + delta_y[i] * 2); + if (rterrain(r) != T_DESERT) + terraform(r, T_DESERT); + if (!r->buildings) { + building *b = new_building(bt_find("castle"), r, NULL); + + b->size = 10; + if (i != 0) { + sprintf(buf, "Turm des %s", LOC(default_locale, mkname("school", magic_school[i]))); - } - else sprintf(buf, "Turm der Ahnungslosen"); - set_string(&b->name, buf); - } - } - } - if (first && !arena_center->buildings) { - building * b = new_building(bt_find("castle"), arena_center, NULL); - attrib * a; - item * items; + } else + sprintf(buf, "Turm der Ahnungslosen"); + set_string(&b->name, buf); + } + } + } + if (first && !arena_center->buildings) { + building *b = new_building(bt_find("castle"), arena_center, NULL); - i_add(&items, i_new(it_griphonwing, 1)); - i_add(&items, i_new(it_demonseye, 1)); - a = a_add(&b->attribs, make_giveitem(b, items)); + attrib *a; - b->size = 10; - set_string(&b->name, "Höhle des Greifen"); - } + item *items; + + i_add(&items, i_new(it_griphonwing, 1)); + i_add(&items, i_new(it_demonseye, 1)); + a = a_add(&b->attribs, make_giveitem(b, items)); + + b->size = 10; + set_string(&b->name, "Höhle des Greifen"); + } } #endif #ifdef ARENA_CREATION -static void -guardian_faction(plane * pl, int id) +static void guardian_faction(plane * pl, int id) { - region * r; - faction * f = findfaction(id); + region *r; - if (!f) { - f = calloc(1, sizeof(faction)); - f->banner = strdup("Sie dienen dem großen Wyrm"); - f->passw = strdup(itoa36(rng_int())); - f->override = strdup(itoa36(rng_int())); + faction *f = findfaction(id); + + if (!f) { + f = calloc(1, sizeof(faction)); + f->banner = strdup("Sie dienen dem großen Wyrm"); + f->passw = strdup(itoa36(rng_int())); + f->override = strdup(itoa36(rng_int())); set_email(&f->email, "igjarjuk@eressea.de"); - f->name = strdup("Igjarjuks Kundschafter"); - f->race = new_race[RC_ILLUSION]; - f->age = turn; - f->locale = find_locale("de"); - f->options = want(O_COMPRESS) | want(O_REPORT) | want(O_COMPUTER) | want(O_ADRESSEN) | want(O_DEBUG); + f->name = strdup("Igjarjuks Kundschafter"); + f->race = new_race[RC_ILLUSION]; + f->age = turn; + f->locale = find_locale("de"); + f->options = + want(O_COMPRESS) | want(O_REPORT) | want(O_COMPUTER) | want(O_ADRESSEN) | + want(O_DEBUG); - f->no = id; - addlist(&factions, f); + f->no = id; + addlist(&factions, f); fhash(f); - } - if (f->race != new_race[RC_ILLUSION]) { - assert(!"guardian id vergeben"); - exit(0); - } - f->lastorders = turn; - f->alive = true; - for (r=regions;r;r=r->next) if (getplane(r)==pl && rterrain(r)!=T_FIREWALL) - { - unit * u; - freset(r, RF_ENCOUNTER); - for (u=r->units;u;u=u->next) { - if (u->faction==f) break; - } - if (u) continue; - u = createunit(r, f, 1, new_race[RC_GOBLIN]); - set_string(&u->name, "Igjarjuks Auge"); - set_item(u, I_RING_OF_INVISIBILITY, 1); - set_order(&u->thisorder, NULL); - fset(u, UFL_ANON_FACTION); - set_money(u, 1000); - } + } + if (f->race != new_race[RC_ILLUSION]) { + assert(!"guardian id vergeben"); + exit(0); + } + f->lastorders = turn; + f->alive = true; + for (r = regions; r; r = r->next) + if (getplane(r) == pl && rterrain(r) != T_FIREWALL) { + unit *u; + + freset(r, RF_ENCOUNTER); + for (u = r->units; u; u = u->next) { + if (u->faction == f) + break; + } + if (u) + continue; + u = createunit(r, f, 1, new_race[RC_GOBLIN]); + set_string(&u->name, "Igjarjuks Auge"); + set_item(u, I_RING_OF_INVISIBILITY, 1); + set_order(&u->thisorder, NULL); + fset(u, UFL_ANON_FACTION); + set_money(u, 1000); + } } #endif #define BLOCKSIZE 9 #ifdef ARENA_CREATION -static void -block_create(int x1, int y1, char terrain) +static void block_create(int x1, int y1, char terrain) { - int x, y; - for (x=0;x!=BLOCKSIZE;++x) { - for (y=0;y!=BLOCKSIZE;++y) { - region * r = new_region(x1 + x, y1 + y, 0); - terraform(r, terrain); - } - } + int x, y; + + for (x = 0; x != BLOCKSIZE; ++x) { + for (y = 0; y != BLOCKSIZE; ++y) { + region *r = new_region(x1 + x, y1 + y, 0); + + terraform(r, terrain); + } + } } #endif #ifdef CENTRAL_VOLCANO -static int -caldera_handle(trigger * t, void * data) +static int caldera_handle(trigger * t, void *data) { - /* call an event handler on caldera. - * data.v -> ( variant event, int timer ) - */ - building *b = (building *)t->data.v; - if (b!=NULL) { - unit ** up = &b->region->units; - while (*up) { - unit * u = *up; - if (u->building==b) { - message * msg; - if (u->items) { - item ** ip = &u->items; + /* call an event handler on caldera. + * data.v -> ( variant event, int timer ) + */ + building *b = (building *) t->data.v; + + if (b != NULL) { + unit **up = &b->region->units; + + while (*up) { + unit *u = *up; + + if (u->building == b) { + message *msg; + + if (u->items) { + item **ip = &u->items; + msg = msg_message("caldera_handle_1", "unit items", u, u->items); - while (*ip) { - item * i = *ip; - i_remove(ip, i); - if (*ip==i) ip=&i->next; - } + while (*ip) { + item *i = *ip; + + i_remove(ip, i); + if (*ip == i) + ip = &i->next; + } } else { msg = msg_message("caldera_handle_0", "unit", u); } - add_message(&u->region->msgs, msg); - set_number(u, 0); - } - if (*up==u) up = &u->next; - } + add_message(&u->region->msgs, msg); + set_number(u, 0); + } + if (*up == u) + up = &u->next; + } } else { - log_error(("could not perform caldera::handle()\n")); + log_error(("could not perform caldera::handle()\n")); } - unused(data); - return 0; + unused(data); + return 0; } -static void -caldera_write(const trigger * t, struct storage * store) +static void caldera_write(const trigger * t, struct storage *store) { - building *b = (building *)t->data.v; + building *b = (building *) t->data.v; + write_building_reference(b, store); } -static int -caldera_read(trigger * t, struct storage * store) +static int caldera_read(trigger * t, struct storage *store) { - int rb = read_reference(&t->data.v, store, read_building_reference, resolve_building); - if (rb==0 && !t->data.v) { + int rb = + read_reference(&t->data.v, store, read_building_reference, + resolve_building); + if (rb == 0 && !t->data.v) { return AT_READ_FAIL; } return AT_READ_OK; @@ -436,91 +497,101 @@ struct trigger_type tt_caldera = { }; #ifdef ARENA_CREATION -static trigger * -trigger_caldera(building * b) +static trigger *trigger_caldera(building * b) { - trigger * t = t_new(&tt_caldera); + trigger *t = t_new(&tt_caldera); + t->data.v = b; return t; } #endif #ifdef ARENA_CREATION -static void -init_volcano(void) +static void init_volcano(void) { - building * b; - region * r = arena_center; - assert(arena_center); - if (rterrain(r)!=T_DESERT) return; /* been done before */ - terraform(arena_center, T_VOLCANO_SMOKING); - b = new_building(bt_find("caldera"), r, NULL); - b->size = 1; - b->name = strdup("Igjarjuk's Schlund"); - b->display = strdup("Feurige Lava fließt aus dem Krater des großen Vulkans. Alles wird von ihr verschlungen."); - add_trigger(&b->attribs, "timer", trigger_caldera(b)); - tt_register(&tt_caldera); + building *b; + + region *r = arena_center; + + assert(arena_center); + if (rterrain(r) != T_DESERT) + return; /* been done before */ + terraform(arena_center, T_VOLCANO_SMOKING); + b = new_building(bt_find("caldera"), r, NULL); + b->size = 1; + b->name = strdup("Igjarjuk's Schlund"); + b->display = + strdup + ("Feurige Lava fließt aus dem Krater des großen Vulkans. Alles wird von ihr verschlungen."); + add_trigger(&b->attribs, "timer", trigger_caldera(b)); + tt_register(&tt_caldera); } #endif #endif #ifdef ARENA_CREATION -void -create_arena(void) +void create_arena(void) { - int x; - arena_id = hashstring("arena"); - arena = getplanebyid(arena_id); - if (arena!=NULL) return; - score(); /* ist wichtig, damit alle Parteien einen score haben, wenn sie durchs Tor wollen. */ - guardian_faction(arena, 999); - if (arena) arena_center = findregion(plane_center_x(arena), plane_center_y(arena)); - if (!arena_center) { - newarena = 1; - arena = create_new_plane(arena_id, "Arena", -10000, -10000, 0, BLOCKSIZE-1, PFL_LOWSTEALING | PFL_NORECRUITS | PFL_NOALLIANCES); - block_create(arena->minx, arena->miny, T_OCEAN); - arena_center = findregion(plane_center_x(arena), plane_center_y(arena)); - for (x=0;x!=BLOCKSIZE;++x) { - int y; - for (y=0;y!=BLOCKSIZE;++y) { - region * r = findregion(arena->minx+x, arena->miny+y); - freset(r, RF_ENCOUNTER); - r->planep = arena; - switch (distance(r, arena_center)) { - case 4: - terraform(r, T_FIREWALL); - break; - case 0: - terraform(r, T_GLACIER); - break; - case 1: - terraform(r, T_SWAMP); - break; - case 2: - terraform(r, T_MOUNTAIN); - break; - } - } - } - } - make_temple(arena_center); + int x; + + arena_id = hashstring("arena"); + arena = getplanebyid(arena_id); + if (arena != NULL) + return; + score(); /* ist wichtig, damit alle Parteien einen score haben, wenn sie durchs Tor wollen. */ + guardian_faction(arena, 999); + if (arena) + arena_center = findregion(plane_center_x(arena), plane_center_y(arena)); + if (!arena_center) { + newarena = 1; + arena = + create_new_plane(arena_id, "Arena", -10000, -10000, 0, BLOCKSIZE - 1, + PFL_LOWSTEALING | PFL_NORECRUITS | PFL_NOALLIANCES); + block_create(arena->minx, arena->miny, T_OCEAN); + arena_center = findregion(plane_center_x(arena), plane_center_y(arena)); + for (x = 0; x != BLOCKSIZE; ++x) { + int y; + + for (y = 0; y != BLOCKSIZE; ++y) { + region *r = findregion(arena->minx + x, arena->miny + y); + + freset(r, RF_ENCOUNTER); + r->planep = arena; + switch (distance(r, arena_center)) { + case 4: + terraform(r, T_FIREWALL); + break; + case 0: + terraform(r, T_GLACIER); + break; + case 1: + terraform(r, T_SWAMP); + break; + case 2: + terraform(r, T_MOUNTAIN); + break; + } + } + } + } + make_temple(arena_center); #ifdef CENTRAL_VOLCANO - init_volcano(); + init_volcano(); #else - if (arena_center->terrain!=T_DESERT) terraform(arena_center, T_DESERT); + if (arena_center->terrain != T_DESERT) + terraform(arena_center, T_DESERT); #endif - rsetmoney(arena_center, 0); - rsetpeasants(arena_center, 0); - tower_init(); + rsetmoney(arena_center, 0); + rsetpeasants(arena_center, 0); + tower_init(); } #endif -void -register_arena(void) +void register_arena(void) { at_register(&at_hurting); register_item_use(use_wand_of_tears, "use_wand_of_tears"); - register_function((pf_generic)enter_arena, "enter_arena"); - register_function((pf_generic)leave_arena, "leave_arena"); + register_function((pf_generic) enter_arena, "enter_arena"); + register_function((pf_generic) leave_arena, "leave_arena"); tt_register(&tt_caldera); } diff --git a/src/modules/arena.h b/src/modules/arena.h index 6dbec6e93..0b68d0471 100644 --- a/src/modules/arena.h +++ b/src/modules/arena.h @@ -26,11 +26,11 @@ extern "C" { #error "must define ARENA_MODULE to use this module" #endif /* exports: */ -extern struct plane * arena; + extern struct plane *arena; -extern void register_arena(void); + extern void register_arena(void); #ifdef ARENA_CREATION -extern void create_arena(void); + extern void create_arena(void); #endif #ifdef __cplusplus diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c index c28a3f1bd..f2fa68150 100644 --- a/src/modules/autoseed.c +++ b/src/modules/autoseed.c @@ -48,16 +48,18 @@ #include #include -const terrain_type * -random_terrain(const terrain_type * terrains[], int distribution[], int size) +const terrain_type *random_terrain(const terrain_type * terrains[], + int distribution[], int size) { int ndistribution = size; - const terrain_type * terrain; + + const terrain_type *terrain; + int n; if (distribution) { ndistribution = 0; - for (n=0;n!=size;++n) { + for (n = 0; n != size; ++n) { ndistribution += distribution[n]; } } @@ -65,11 +67,13 @@ random_terrain(const terrain_type * terrains[], int distribution[], int size) n = rng_int() % ndistribution; if (distribution) { int i; - for (i=0;i!=size;++i) { + + for (i = 0; i != size; ++i) { n -= distribution[i]; - if (n<0) break; + if (n < 0) + break; } - assert(iresources;rm;rm=rm->next) { - if (rm->type->rtype==rtype) break; + const resource_type *rtype = rt_find("adamantium"); + + rawmaterial *rm; + + for (rm = r->resources; rm; rm = rm->next) { + if (rm->type->rtype == rtype) + break; } if (!rm) { add_resource(r, 1, base, 150, rtype); @@ -92,83 +98,107 @@ seed_adamantium(region * r, int base) } -static int -count_demand(const region *r) +static int count_demand(const region * r) { struct demand *dmd; + int c = 0; + if (r->land) { - for (dmd=r->land->demands;dmd;dmd=dmd->next) c++; + for (dmd = r->land->demands; dmd; dmd = dmd->next) + c++; } return c; } static int -recurse_regions(region *r, region_list **rlist, boolean(*fun)(const region *r)) +recurse_regions(region * r, region_list ** rlist, + boolean(*fun) (const region * r)) { - if (!fun(r)) return 0; + if (!fun(r)) + return 0; else { int len = 0; + direction_t d; - region_list * rl = calloc(sizeof(region_list), 1); + + region_list *rl = calloc(sizeof(region_list), 1); + rl->next = *rlist; rl->data = r; (*rlist) = rl; fset(r, RF_MARK); - for (d=0;d!=MAXDIRECTIONS;++d) { - region * nr = rconnect(r, d); - if (nr && !fval(nr, RF_MARK)) len += recurse_regions(nr, rlist, fun); + for (d = 0; d != MAXDIRECTIONS; ++d) { + region *nr = rconnect(r, d); + + if (nr && !fval(nr, RF_MARK)) + len += recurse_regions(nr, rlist, fun); } - return len+1; + return len + 1; } } -static boolean -f_nolux(const region * r) +static boolean f_nolux(const region * r) { - if (r->land && count_demand(r) != get_maxluxuries()) return true; + if (r->land && count_demand(r) != get_maxluxuries()) + return true; return false; } -int -fix_demand(region *rd) +int fix_demand(region * rd) { region_list *rl, *rlist = NULL; - static const struct luxury_type **mlux = 0, ** ltypes; + + static const struct luxury_type **mlux = 0, **ltypes; + const luxury_type *sale = NULL; + int maxlux = 0; + int maxluxuries = get_maxluxuries(); - - if (maxluxuries==0) return 0; + + if (maxluxuries == 0) + return 0; recurse_regions(rd, &rlist, f_nolux); - if (mlux==0) { + if (mlux == 0) { int i = 0; - mlux = (const luxury_type **)gc_add(calloc(maxluxuries, sizeof(const luxury_type *))); - ltypes = (const luxury_type **)gc_add(calloc(maxluxuries, sizeof(const luxury_type *))); - for (sale=luxurytypes;sale;sale=sale->next) { + + mlux = + (const luxury_type **)gc_add(calloc(maxluxuries, + sizeof(const luxury_type *))); + ltypes = + (const luxury_type **)gc_add(calloc(maxluxuries, + sizeof(const luxury_type *))); + for (sale = luxurytypes; sale; sale = sale->next) { ltypes[i++] = sale; } - } - else { + } else { int i; - for (i=0;i!=maxluxuries;++i) mlux[i] = 0; + + for (i = 0; i != maxluxuries; ++i) + mlux[i] = 0; } - for (rl=rlist;rl;rl=rl->next) { - region * r = rl->data; + for (rl = rlist; rl; rl = rl->next) { + region *r = rl->data; + direction_t d; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * nr = rconnect(r, d); + + for (d = 0; d != MAXDIRECTIONS; ++d) { + region *nr = rconnect(r, d); + if (nr && nr->land && nr->land->demands) { - struct demand * dmd; - for (dmd = nr->land->demands;dmd;dmd=dmd->next) { + struct demand *dmd; + + for (dmd = nr->land->demands; dmd; dmd = dmd->next) { if (dmd->value == 0) { int i; - for (i=0;i!=maxluxuries;++i) { - if (mlux[i]==NULL) { + + for (i = 0; i != maxluxuries; ++i) { + if (mlux[i] == NULL) { maxlux = i; mlux[i] = dmd->type; break; - } else if (mlux[i]==dmd->type) { + } else if (mlux[i] == dmd->type) { break; } } @@ -177,29 +207,35 @@ fix_demand(region *rd) } } } - freset(r, RF_MARK); /* undo recursive marker */ + freset(r, RF_MARK); /* undo recursive marker */ } - if (maxlux<2) { + if (maxlux < 2) { int i; - for (i=maxlux;i!=2;++i) { + + for (i = maxlux; i != 2; ++i) { int j; + do { int k = rng_int() % maxluxuries; + mlux[i] = ltypes[k]; - for (j=0;j!=i;++j) { - if (mlux[j]==mlux[i]) break; + for (j = 0; j != i; ++j) { + if (mlux[j] == mlux[i]) + break; } - } while (j!=i); + } while (j != i); } maxlux = 2; } - for (rl=rlist;rl;rl=rl->next) { - region * r = rl->data; + for (rl = rlist; rl; rl = rl->next) { + region *r = rl->data; + if (!fval(r, RF_CHAOTIC)) { log_info((LOG_INFO1, "fixing demand in %s\n", regionname(r, NULL))); } sale = mlux[rng_int() % maxlux]; - if (sale) setluxuries(r, sale); + if (sale) + setluxuries(r, sale); } while (rlist) { rl = rlist->next; @@ -211,53 +247,70 @@ fix_demand(region *rd) /* nach 150 Runden ist Neustart erlaubt */ #define MINAGE_MULTI 150 -newfaction * -read_newfactions(const char * filename) +newfaction *read_newfactions(const char *filename) { - newfaction * newfactions = NULL; - FILE * F = fopen(filename, "r"); + newfaction *newfactions = NULL; + + FILE *F = fopen(filename, "r"); + char buf[1024]; - if (F==NULL) return NULL; + if (F == NULL) + return NULL; for (;;) { - faction * f; + faction *f; + char race[20], email[64], lang[8], password[16]; + newfaction *nf, **nfi; + int bonus = 0, subscription = 0; + int alliance = 0; - if (fgets(buf, sizeof(buf), F)==NULL) break; + if (fgets(buf, sizeof(buf), F) == NULL) + break; email[0] = '\0'; password[0] = '\0'; - if (sscanf(buf, "%54s %20s %8s %d %d %16s %d", email, race, lang, &bonus, &subscription, password, &alliance)<6) break; - if (email[0]=='\0') break; - if (password[0]=='\0') { + if (sscanf(buf, "%54s %20s %8s %d %d %16s %d", email, race, lang, &bonus, + &subscription, password, &alliance) < 6) + break; + if (email[0] == '\0') + break; + if (password[0] == '\0') { strcpy(password, itoa36(rng_int())); strcat(password, itoa36(rng_int())); } - for (f=factions;f;f=f->next) { - if (strcmp(f->email, email)==0 && f->subscription && f->agenext) { + if (strcmp(f->email, email) == 0 && f->subscription + && f->age < MINAGE_MULTI) + break; } - if (f && f->units) continue; /* skip the ones we've already got */ - for (nf=newfactions;nf;nf=nf->next) { - if (strcmp(nf->email, email)==0) break; + if (f && f->units) + continue; /* skip the ones we've already got */ + for (nf = newfactions; nf; nf = nf->next) { + if (strcmp(nf->email, email) == 0) + break; } - if (nf) continue; + if (nf) + continue; nf = calloc(sizeof(newfaction), 1); - if (set_email(&nf->email, email)!=0) { - log_error(("Invalid email address for subscription %s: %s\n", - itoa36(subscription), email)); + if (set_email(&nf->email, email) != 0) { + log_error(("Invalid email address for subscription %s: %s\n", + itoa36(subscription), email)); continue; } nf->password = strdup(password); nf->race = rc_find(race); nf->subscription = subscription; - if (alliances!=NULL) { - struct alliance * al = findalliance(alliance); - if (al==NULL) { + if (alliances != NULL) { + struct alliance *al = findalliance(alliance); + + if (al == NULL) { char zText[64]; + sprintf(zText, "Allianz %d", alliance); al = makealliance(alliance, zText); } @@ -265,18 +318,21 @@ read_newfactions(const char * filename) } else { nf->allies = NULL; } - if (nf->race==NULL) { + if (nf->race == NULL) { /* if the script didn't supply the race as a token, then it gives us a * race in the default locale (which means that itis a UTF8 string) */ nf->race = findrace(race, default_locale); - if (nf->race==NULL) { + if (nf->race == NULL) { char buffer[32]; + size_t outbytes = sizeof(buffer) - 1; + size_t inbytes = strlen(race); + unicode_latin1_to_utf8(buffer, &outbytes, race, &inbytes); buffer[outbytes] = 0; nf->race = findrace(buffer, default_locale); - if (nf->race==NULL) { + if (nf->race == NULL) { log_error(("new faction has unknown race '%s'.\n", race)); free(nf); continue; @@ -288,8 +344,9 @@ read_newfactions(const char * filename) assert(nf->race && nf->email && nf->lang); nfi = &newfactions; while (*nfi) { - if ((*nfi)->race==nf->race) break; - nfi=&(*nfi)->next; + if ((*nfi)->race == nf->race) + break; + nfi = &(*nfi)->next; } nf->next = *nfi; *nfi = nf; @@ -300,14 +357,18 @@ read_newfactions(const char * filename) extern int numnewbies; -static const terrain_type * -preferred_terrain(const struct race * rc) +static const terrain_type *preferred_terrain(const struct race *rc) { terrain_t t = T_PLAIN; - if (rc==rc_find("dwarf")) t = T_MOUNTAIN; - if (rc==rc_find("insect")) t = T_DESERT; - if (rc==rc_find("halfling")) t = T_SWAMP; - if (rc==rc_find("troll")) t = T_MOUNTAIN; + + if (rc == rc_find("dwarf")) + t = T_MOUNTAIN; + if (rc == rc_find("insect")) + t = T_DESERT; + if (rc == rc_find("halfling")) + t = T_SWAMP; + if (rc == rc_find("troll")) + t = T_MOUNTAIN; return newterrain(t); } @@ -317,18 +378,24 @@ preferred_terrain(const struct race * rc) #define MINFACTIONS 1 #define VOLCANO_CHANCE 100 -static boolean -virgin_region(const region * r) +static boolean virgin_region(const region * r) { direction_t d; - if (r==NULL) return true; - if (fval(r->terrain, FORBIDDEN_REGION)) return false; - if (r->units) return false; - for (d=0;d!=MAXDIRECTIONS;++d) { - const region * rn = rconnect(r, d); + + if (r == NULL) + return true; + if (fval(r->terrain, FORBIDDEN_REGION)) + return false; + if (r->units) + return false; + for (d = 0; d != MAXDIRECTIONS; ++d) { + const region *rn = rconnect(r, d); + if (rn) { - if (rn->age>r->age+1) return false; - if (rn->units) return false; + if (rn->age > r->age + 1) + return false; + if (rn->units) + return false; if (fval(rn->terrain, FORBIDDEN_REGION)) { /* because it kinda sucks to have islands that are adjacent to a firewall */ return false; @@ -338,11 +405,12 @@ virgin_region(const region * r) return true; } -void -get_island(region * root, region_list ** rlist) +void get_island(region * root, region_list ** rlist) { - region_list ** rnext = rlist; - while (*rnext) rnext=&(*rnext)->next; + region_list **rnext = rlist; + + while (*rnext) + rnext = &(*rnext)->next; fset(root, RF_MARK); add_regionlist(rnext, root); @@ -350,40 +418,49 @@ get_island(region * root, region_list ** rlist) while (*rnext) { direction_t dir; - region * rcurrent = (*rnext)->data; + region *rcurrent = (*rnext)->data; + rnext = &(*rnext)->next; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * r = rconnect(rcurrent, dir); - if (r!=NULL && r->land && !fval(r, RF_MARK)) { + for (dir = 0; dir != MAXDIRECTIONS; ++dir) { + region *r = rconnect(rcurrent, dir); + + if (r != NULL && r->land && !fval(r, RF_MARK)) { fset(r, RF_MARK); add_regionlist(rnext, r); } } } - rnext=rlist; + rnext = rlist; while (*rnext) { - region_list * rptr = *rnext; + region_list *rptr = *rnext; + freset(rptr->data, RF_MARK); rnext = &rptr->next; } } static void -get_island_info(region * root, int * size_p, int * inhabited_p, int * maxage_p) +get_island_info(region * root, int *size_p, int *inhabited_p, int *maxage_p) { int size = 0, maxage = 0, inhabited = 0; - region_list * rlist = NULL; - region_list * island = NULL; + + region_list *rlist = NULL; + + region_list *island = NULL; + add_regionlist(&rlist, root); island = rlist; fset(root, RF_MARK); while (rlist) { direction_t d; - region * r = rlist->data; + + region *r = rlist->data; + if (r->units) { - unit * u; - for (u=r->units; u; u=u->next) { + unit *u; + + for (u = r->units; u; u = u->next) { if (!is_monsters(u->faction) && u->faction->age > maxage) { maxage = u->faction->age; } @@ -391,10 +468,12 @@ get_island_info(region * root, int * size_p, int * inhabited_p, int * maxage_p) ++inhabited; } ++size; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(r, d); + for (d = 0; d != MAXDIRECTIONS; ++d) { + region *rn = rconnect(r, d); + if (rn && !fval(rn, RF_MARK) && rn->land) { - region_list * rnew = malloc(sizeof(region_list)); + region_list *rnew = malloc(sizeof(region_list)); + rnew->data = rn; rnew->next = rlist->next; rlist->next = rnew; @@ -403,77 +482,90 @@ get_island_info(region * root, int * size_p, int * inhabited_p, int * maxage_p) } rlist = rlist->next; } - for (rlist=island;rlist;rlist=rlist->next) { + for (rlist = island; rlist; rlist = rlist->next) { freset(rlist->data, RF_MARK); } free_regionlist(island); - if (size_p) *size_p = size; - if (inhabited_p) *inhabited_p = inhabited; - if (maxage_p) *maxage_p = maxage; + if (size_p) + *size_p = size; + if (inhabited_p) + *inhabited_p = inhabited; + if (maxage_p) + *maxage_p = maxage; } -void -free_newfaction(newfaction * nf) +void free_newfaction(newfaction * nf) { free(nf->email); free(nf->password); free(nf); } -static void -frame_regions(int age, const terrain_type * terrain) +static void frame_regions(int age, const terrain_type * terrain) { - plane * hplane = get_homeplane(); - region * r = regions; - for (r=regions;r;r=r->next) { - plane * pl = rplane(r); - direction_t d; - if (r->ageterrain == terrain) continue; + plane *hplane = get_homeplane(); - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(r, d); - if (rn==NULL) { + region *r = regions; + + for (r = regions; r; r = r->next) { + plane *pl = rplane(r); + + direction_t d; + + if (r->age < age) + continue; + if (pl != hplane) + continue; /* only do this on the main world */ + if (r->terrain == terrain) + continue; + + for (d = 0; d != MAXDIRECTIONS; ++d) { + region *rn = rconnect(r, d); + + if (rn == NULL) { int x = r->x + delta_x[d]; + int y = r->y + delta_y[d]; + pnormalize(&x, &y, pl); rn = new_region(x, y, pl, 0); terraform_region(rn, terrain); - rn->age=r->age; + rn->age = r->age; } } } } -static void -prepare_starting_region(region * r) +static void prepare_starting_region(region * r) { int n, t; + double p; assert(r->land); /* population between 30% and 60% of max */ p = rng_double(); - n = (int)(r->terrain->size * (0.3 + p*0.3)); + n = (int)(r->terrain->size * (0.3 + p * 0.3)); rsetpeasants(r, n); /* trees: don't squash the peasants, and at least 5% should be forrest */ - t = (rtrees(r, 2) + rtrees(r, 1)/2) * TREESIZE; - if (t < r->terrain->size/20 || t+n > r->terrain->size) { - double p2 = 0.05 + rng_double()*(1.0-p-0.05); - int maxtrees = (int)(r->terrain->size/1.25/TREESIZE); /* 1.25 = each young tree will take 1/2 the space of old trees */ + t = (rtrees(r, 2) + rtrees(r, 1) / 2) * TREESIZE; + if (t < r->terrain->size / 20 || t + n > r->terrain->size) { + double p2 = 0.05 + rng_double() * (1.0 - p - 0.05); + + int maxtrees = (int)(r->terrain->size / 1.25 / TREESIZE); /* 1.25 = each young tree will take 1/2 the space of old trees */ + int trees = (int)(p2 * maxtrees); rsettrees(r, 2, trees); - rsettrees(r, 1, trees/2); - rsettrees(r, 0, trees/4); + rsettrees(r, 1, trees / 2); + rsettrees(r, 0, trees / 4); } /* horses: between 1% and 2% */ p = rng_double(); - rsethorses(r, (int)(r->terrain->size * (0.01 + p*0.01))); + rsethorses(r, (int)(r->terrain->size * (0.01 + p * 0.01))); if (!markets_module()) { fix_demand(r); @@ -483,30 +575,39 @@ prepare_starting_region(region * r) /** create new island with up to nsize players * returns the number of players placed on the new island. */ -int -autoseed(newfaction ** players, int nsize, int max_agediff) +int autoseed(newfaction ** players, int nsize, int max_agediff) { - region * r = NULL; - region_list * rlist = NULL; - int rsize = 0, tsize = 0; - int isize = REGIONS_PER_FACTION; /* target size for the island */ - int psize = 0; /* players on this island */ - const terrain_type * volcano_terrain = get_terrain("volcano"); - static int nterrains = -1; - static const terrain_type ** terrainarr = 0; - static int * distribution; + region *r = NULL; - if (nterrains<0) { + region_list *rlist = NULL; + + int rsize = 0, tsize = 0; + + int isize = REGIONS_PER_FACTION; /* target size for the island */ + + int psize = 0; /* players on this island */ + + const terrain_type *volcano_terrain = get_terrain("volcano"); + + static int nterrains = -1; + + static const terrain_type **terrainarr = 0; + + static int *distribution; + + if (nterrains < 0) { int n = 0; - const terrain_type * terrain = terrains(); - for (nterrains=0;terrain;terrain=terrain->next) { + + const terrain_type *terrain = terrains(); + + for (nterrains = 0; terrain; terrain = terrain->next) { if (terrain->distribution) { ++nterrains; } } terrainarr = malloc(sizeof(terrain_type *) * nterrains); distribution = malloc(sizeof(int) * nterrains); - for (terrain = terrains();terrain;terrain = terrain->next) { + for (terrain = terrains(); terrain; terrain = terrain->next) { if (terrain->distribution) { terrainarr[n] = terrain; distribution[n++] = terrain->distribution; @@ -515,40 +616,52 @@ autoseed(newfaction ** players, int nsize, int max_agediff) } frame_regions(16, newterrain(T_FIREWALL)); - if (listlen(*players) 0) { + region *rmin = NULL; + + plane *hplane = get_homeplane(); - if (max_agediff>0) { - region * rmin = NULL; - plane * hplane = get_homeplane(); /* find a spot that's adjacent to the previous island, but virgin. * like the last land virgin ocean region adjacent to land. */ - for (r=regions;r;r=r->next) { - struct plane * pl = rplane(r); - if (r->age<=max_agediff && r->terrain == newterrain(T_OCEAN) && pl==hplane && virgin_region(r)) { + for (r = regions; r; r = r->next) { + struct plane *pl = rplane(r); + + if (r->age <= max_agediff && r->terrain == newterrain(T_OCEAN) + && pl == hplane && virgin_region(r)) { direction_t d; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(r, d); - if (rn && rn->land && rn->age<=max_agediff && virgin_region(rn)) { + + for (d = 0; d != MAXDIRECTIONS; ++d) { + region *rn = rconnect(r, d); + + if (rn && rn->land && rn->age <= max_agediff && virgin_region(rn)) { /* only expand islands that aren't single-islands and not too big already */ int size, inhabitants, maxage; + get_island_info(rn, &size, &inhabitants, &maxage); - if (maxage<=max_agediff && size>=2 && size= 2 && size < MAXISLANDSIZE) { rmin = rn; break; } } } - } + } } - if (rmin!=NULL) { - region_list * rlist = NULL, * rptr; - faction * f; + if (rmin != NULL) { + region_list *rlist = NULL, *rptr; + + faction *f; + get_island(rmin, &rlist); - for (rptr=rlist;rptr;rptr=rptr->next) { - region * r = rlist->data; - unit * u; - for (u=r->units;u;u=u->next) { + for (rptr = rlist; rptr; rptr = rptr->next) { + region *r = rlist->data; + + unit *u; + + for (u = r->units; u; u = u->next) { f = u->faction; if (!fval(f, FFL_MARK)) { ++psize; @@ -557,73 +670,96 @@ autoseed(newfaction ** players, int nsize, int max_agediff) } } free_regionlist(rlist); - if (psize>0) for (f=factions;f;f=f->next) freset(f, FFL_MARK); - if (psize 0) + for (f = factions; f; f = f->next) + freset(f, FFL_MARK); + if (psize < PLAYERS_PER_ISLAND) { r = rmin; } } } - if (r==NULL) { - region * rmin = NULL; + if (r == NULL) { + region *rmin = NULL; + direction_t dmin = MAXDIRECTIONS; - plane * hplane = get_homeplane(); + + plane *hplane = get_homeplane(); + /* find an empty spot. * rmin = the youngest ocean region that has a missing neighbour * dmin = direction in which it's empty */ - for (r=regions;r;r=r->next) { - struct plane * pl = rplane(r); - if (r->terrain == newterrain(T_OCEAN) && pl==hplane && (rmin==NULL || r->age<=max_agediff)) { + for (r = regions; r; r = r->next) { + struct plane *pl = rplane(r); + + if (r->terrain == newterrain(T_OCEAN) && pl == hplane && (rmin == NULL + || r->age <= max_agediff)) { direction_t d; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(r, d); - if (rn==NULL) break; + + for (d = 0; d != MAXDIRECTIONS; ++d) { + region *rn = rconnect(r, d); + + if (rn == NULL) + break; } - if (d!=MAXDIRECTIONS) { - rmin=r; - dmin=d; + if (d != MAXDIRECTIONS) { + rmin = r; + dmin = d; } } } /* create a new region where we found the empty spot, and make it the first - * in our island. island regions are kept in rlist, so only new regions can - * get populated, and old regions are not overwritten */ - if (rmin!=NULL) { - plane * pl = rplane(rmin); + * in our island. island regions are kept in rlist, so only new regions can + * get populated, and old regions are not overwritten */ + if (rmin != NULL) { + plane *pl = rplane(rmin); + int x = rmin->x + delta_x[dmin]; + int y = rmin->y + delta_y[dmin]; + pnormalize(&x, &y, pl); assert(virgin_region(rconnect(rmin, dmin))); r = new_region(x, y, pl, 0); terraform_region(r, newterrain(T_OCEAN)); } } - if (r!=NULL) { + if (r != NULL) { add_regionlist(&rlist, r); fset(r, RF_MARK); rsize = 1; } - while (rsize && (nsize || isize>=REGIONS_PER_FACTION)) { + while (rsize && (nsize || isize >= REGIONS_PER_FACTION)) { int i = rng_int() % rsize; - region_list ** rnext = &rlist; - region_list * rfind; + + region_list **rnext = &rlist; + + region_list *rfind; + direction_t d; - while (i--) rnext=&(*rnext)->next; + + while (i--) + rnext = &(*rnext)->next; rfind = *rnext; r = rfind->data; freset(r, RF_MARK); *rnext = rfind->next; free(rfind); --rsize; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(r, d); - if (rn && fval(rn, RF_MARK)) continue; - if (rn==NULL) { - plane * pl = rplane(r); + for (d = 0; d != MAXDIRECTIONS; ++d) { + region *rn = rconnect(r, d); + + if (rn && fval(rn, RF_MARK)) + continue; + if (rn == NULL) { + plane *pl = rplane(r); + int x = r->x + delta_x[d]; + int y = r->y + delta_y[d]; + pnormalize(&x, &y, pl); rn = new_region(x, y, pl, 0); terraform_region(rn, newterrain(T_OCEAN)); @@ -634,39 +770,44 @@ autoseed(newfaction ** players, int nsize, int max_agediff) ++rsize; } } - if (volcano_terrain!=NULL && (rng_int() % VOLCANO_CHANCE == 0)) { + if (volcano_terrain != NULL && (rng_int() % VOLCANO_CHANCE == 0)) { terraform_region(r, volcano_terrain); - } else if (nsize && (rng_int() % isize == 0 || rsize==0)) { - newfaction ** nfp, * nextf = *players; - faction * f; - unit * u; + } else if (nsize && (rng_int() % isize == 0 || rsize == 0)) { + newfaction **nfp, *nextf = *players; + + faction *f; + + unit *u; isize += REGIONS_PER_FACTION; terraform_region(r, preferred_terrain(nextf->race)); prepare_starting_region(r); ++tsize; - assert(r->land && r->units==0); + assert(r->land && r->units == 0); u = addplayer(r, addfaction(nextf->email, nextf->password, nextf->race, - nextf->lang, nextf->subscription)); + nextf->lang, nextf->subscription)); f = u->faction; fset(f, FFL_ISNEW); - f->alliance = nextf->allies; - log_printf("New faction (%s), %s at %s\n", itoa36(f->no), - f->email, regionname(r, NULL)); + f->alliance = nextf->allies; + log_printf("New faction (%s), %s at %s\n", itoa36(f->no), + f->email, regionname(r, NULL)); if (f->subscription) { - sql_print(("UPDATE subscriptions SET status='ACTIVE', faction='%s', firstturn=%d, lastturn=%d, password='%s' WHERE id=%u;\n", - factionid(f), f->lastorders, f->lastorders, f->override, f->subscription)); + sql_print( + ("UPDATE subscriptions SET status='ACTIVE', faction='%s', firstturn=%d, lastturn=%d, password='%s' WHERE id=%u;\n", + factionid(f), f->lastorders, f->lastorders, f->override, + f->subscription)); } /* remove duplicate email addresses */ nfp = &nextf->next; while (*nfp) { - newfaction * nf = *nfp; - if (strcmp(nextf->email, nf->email)==0) { + newfaction *nf = *nfp; + + if (strcmp(nextf->email, nf->email) == 0) { *nfp = nf->next; free_newfaction(nf); - } - else nfp = &nf->next; + } else + nfp = &nf->next; } *players = nextf->next; free_newfaction(nextf); @@ -674,86 +815,112 @@ autoseed(newfaction ** players, int nsize, int max_agediff) ++psize; --nsize; --isize; - if (psize>=PLAYERS_PER_ISLAND) break; + if (psize >= PLAYERS_PER_ISLAND) + break; } else { terraform_region(r, random_terrain(terrainarr, distribution, nterrains)); --isize; } } - if (nsize!=0) { - log_error(("Could not place all factions on the same island as requested\n")); + if (nsize != 0) { + log_error( + ("Could not place all factions on the same island as requested\n")); } - - + + if (rlist) { #define MINOCEANDIST 3 #define MAXOCEANDIST 6 #define MAXFILLDIST 10 #define SPECIALCHANCE 80 - region_list ** rbegin = &rlist; + region_list **rbegin = &rlist; + int special = 1; - int oceandist = MINOCEANDIST + (rng_int() % (MAXOCEANDIST-MINOCEANDIST)); + + int oceandist = MINOCEANDIST + (rng_int() % (MAXOCEANDIST - MINOCEANDIST)); + while (oceandist--) { - region_list ** rend = rbegin; - while (*rend) rend=&(*rend)->next; - while (rbegin!=rend) { + region_list **rend = rbegin; + + while (*rend) + rend = &(*rend)->next; + while (rbegin != rend) { direction_t d; - region * r = (*rbegin)->data; - rbegin=&(*rbegin)->next; - for (d=0;d!=MAXDIRECTIONS;++d) { - region * rn = rconnect(r, d); - if (rn==NULL) { - const struct terrain_type * terrain = newterrain(T_OCEAN); - plane * pl = rplane(r); + + region *r = (*rbegin)->data; + + rbegin = &(*rbegin)->next; + for (d = 0; d != MAXDIRECTIONS; ++d) { + region *rn = rconnect(r, d); + + if (rn == NULL) { + const struct terrain_type *terrain = newterrain(T_OCEAN); + + plane *pl = rplane(r); + int x = r->x + delta_x[d]; + int y = r->y + delta_y[d]; + pnormalize(&x, &y, pl); rn = new_region(x, y, pl, 0); if (rng_int() % SPECIALCHANCE < special) { terrain = random_terrain(terrainarr, distribution, nterrains); - special = SPECIALCHANCE / 3; /* 33% chance auf noch eines */ + special = SPECIALCHANCE / 3; /* 33% chance auf noch eines */ } else { special = 1; } terraform_region(rn, terrain); /* the new region has an extra 20% chance to have mallorn */ - if (rng_int() % 100 < 20) fset(r, RF_MALLORN); + if (rng_int() % 100 < 20) + fset(r, RF_MALLORN); add_regionlist(rend, rn); } } } - + } while (*rbegin) { - region * r = (*rbegin)->data; - plane * pl = rplane(r); + region *r = (*rbegin)->data; + + plane *pl = rplane(r); + direction_t d; - rbegin=&(*rbegin)->next; - for (d=0;d!=MAXDIRECTIONS;++d) if (rconnect(r, d)==NULL) { - int i; - for (i=1;i!=MAXFILLDIST;++i) { - int x = r->x + delta_x[d]*i; - int y = r->y + delta_y[d]*i; - pnormalize(&x, &y, pl); - if (findregion(x, y)) { - break; - } - } - if (i!=MAXFILLDIST) { - while (--i) { - region * rn; - int x = r->x + delta_x[d]*i; - int y = r->y + delta_y[d]*i; + + rbegin = &(*rbegin)->next; + for (d = 0; d != MAXDIRECTIONS; ++d) + if (rconnect(r, d) == NULL) { + int i; + + for (i = 1; i != MAXFILLDIST; ++i) { + int x = r->x + delta_x[d] * i; + + int y = r->y + delta_y[d] * i; + pnormalize(&x, &y, pl); - rn = new_region(x, y, pl, 0); - terraform_region(rn, newterrain(T_OCEAN)); + if (findregion(x, y)) { + break; + } + } + if (i != MAXFILLDIST) { + while (--i) { + region *rn; + + int x = r->x + delta_x[d] * i; + + int y = r->y + delta_y[d] * i; + + pnormalize(&x, &y, pl); + rn = new_region(x, y, pl, 0); + terraform_region(rn, newterrain(T_OCEAN)); + } } } - } } while (rlist) { - region_list * self = rlist; + region_list *self = rlist; + rlist = rlist->next; freset(self->data, RF_MARK); free(self); @@ -762,21 +929,26 @@ autoseed(newfaction ** players, int nsize, int max_agediff) return tsize; } -region_list * regionqueue_push(region_list ** rlist, region * r) +region_list *regionqueue_push(region_list ** rlist, region * r) { - region_list * rnew = malloc(sizeof(region_list)); + region_list *rnew = malloc(sizeof(region_list)); + rnew->data = r; rnew->next = 0; - while (*rlist) { rlist = &(*rlist)->next; } + while (*rlist) { + rlist = &(*rlist)->next; + } *rlist = rnew; return rnew; } -region * regionqueue_pop(region_list ** rlist) +region *regionqueue_pop(region_list ** rlist) { if (*rlist) { - region * r = (*rlist)->data; - region_list * rpop = *rlist; + region *r = (*rlist)->data; + + region_list *rpop = *rlist; + *rlist = rpop->next; free(rpop); return r; @@ -785,31 +957,33 @@ region * regionqueue_pop(region_list ** rlist) } #define GEOMAX 8 -static struct geo { +static struct geo { int distribution; terrain_t type; } geography_e3[GEOMAX] = { - { 8, T_OCEAN }, - { 3, T_SWAMP }, - { 1, T_VOLCANO }, - { 3, T_DESERT }, - { 4, T_HIGHLAND }, - { 3, T_MOUNTAIN }, - { 2, T_GLACIER }, - { 1, T_PLAIN } + { + 8, T_OCEAN}, { + 3, T_SWAMP}, { + 1, T_VOLCANO}, { + 3, T_DESERT}, { + 4, T_HIGHLAND}, { + 3, T_MOUNTAIN}, { + 2, T_GLACIER}, { + 1, T_PLAIN} }; -const terrain_type * random_terrain_e3(direction_t dir) +const terrain_type *random_terrain_e3(direction_t dir) { - static const terrain_type ** terrainarr = 0; - static int * distribution = 0; + static const terrain_type **terrainarr = 0; + + static int *distribution = 0; if (!distribution) { int n = 0; - + terrainarr = malloc(GEOMAX * sizeof(const terrain_type *)); distribution = malloc(GEOMAX * sizeof(int)); - for (n=0;n!=GEOMAX;++n) { + for (n = 0; n != GEOMAX; ++n) { terrainarr[n] = newterrain(geography_e3[n].type); distribution[n] = geography_e3[n].distribution; } @@ -818,17 +992,25 @@ const terrain_type * random_terrain_e3(direction_t dir) } int -random_neighbours(region * r, region_list ** rlist, const terrain_type *(*terraformer)(direction_t)) +random_neighbours(region * r, region_list ** rlist, + const terrain_type * (*terraformer) (direction_t)) { int nsize = 0; + direction_t dir; - for (dir=0;dir!=MAXDIRECTIONS;++dir) { - region * rn = rconnect(r, dir); - if (rn==NULL) { - const terrain_type * terrain = terraformer(dir); - plane * pl = rplane(r); + + for (dir = 0; dir != MAXDIRECTIONS; ++dir) { + region *rn = rconnect(r, dir); + + if (rn == NULL) { + const terrain_type *terrain = terraformer(dir); + + plane *pl = rplane(r); + int x = r->x + delta_x[dir]; + int y = r->y + delta_y[dir]; + pnormalize(&x, &y, pl); rn = new_region(x, y, pl, 0); terraform_region(rn, terrain); @@ -841,7 +1023,7 @@ random_neighbours(region * r, region_list ** rlist, const terrain_type *(*terraf return nsize; } -const terrain_type * get_ocean(direction_t dir) +const terrain_type *get_ocean(direction_t dir) { return newterrain(T_OCEAN); } @@ -850,9 +1032,9 @@ int region_quality(const region * r, region * rn[]) { int n, result = 0; - for (n=0;n!=MAXDIRECTIONS;++n) { + for (n = 0; n != MAXDIRECTIONS; ++n) { if (rn[n] && rn[n]->land) { - if (rn[n]->terrain==newterrain(T_VOLCANO)) { + if (rn[n]->terrain == newterrain(T_VOLCANO)) { /* nobody likes volcanoes */ result -= 2000; } @@ -862,16 +1044,20 @@ int region_quality(const region * r, region * rn[]) return result; } -static void -oceans_around(region * r, region * rn[]) +static void oceans_around(region * r, region * rn[]) { int n; - for (n=0;n!=MAXDIRECTIONS;++n) { - region * rx = rn[n]; - if (rx==NULL) { - plane * pl = rplane(r); + + for (n = 0; n != MAXDIRECTIONS; ++n) { + region *rx = rn[n]; + + if (rx == NULL) { + plane *pl = rplane(r); + int x = r->x + delta_x[n]; + int y = r->y + delta_y[n]; + pnormalize(&x, &y, pl); rx = new_region(x, y, pl, 0); terraform_region(rx, newterrain(T_OCEAN)); @@ -880,36 +1066,42 @@ oceans_around(region * r, region * rn[]) } } -static void -smooth_island(region_list * island) +static void smooth_island(region_list * island) { - region * rn[MAXDIRECTIONS]; - region_list * rlist = NULL; - for (rlist=island;rlist;rlist=rlist->next) { - region * r = rlist->data; + region *rn[MAXDIRECTIONS]; + + region_list *rlist = NULL; + + for (rlist = island; rlist; rlist = rlist->next) { + region *r = rlist->data; + int n, nland = 0; - + if (r->land) { get_neighbours(r, rn); - for (n=0;n!=MAXDIRECTIONS && nland<=1;++n) { + for (n = 0; n != MAXDIRECTIONS && nland <= 1; ++n) { if (rn[n]->land) { ++nland; r = rn[n]; } } - if (nland==1) { + if (nland == 1) { get_neighbours(r, rn); oceans_around(r, rn); - for (n=0;n!=MAXDIRECTIONS;++n) { - int n1 = (n+1)%MAXDIRECTIONS; - int n2 = (n+1+MAXDIRECTIONS)%MAXDIRECTIONS; - if (!rn[n]->land && rn[n1]!=r && rn[n2]!=r) { + for (n = 0; n != MAXDIRECTIONS; ++n) { + int n1 = (n + 1) % MAXDIRECTIONS; + + int n2 = (n + 1 + MAXDIRECTIONS) % MAXDIRECTIONS; + + if (!rn[n]->land && rn[n1] != r && rn[n2] != r) { r = rlist->data; runhash(r); runhash(rn[n]); SWAP_VARS(int, r->x, rn[n]->x); + SWAP_VARS(int, r->y, rn[n]->y); + rhash(r); rhash(rn[n]); rlist->data = r; @@ -922,36 +1114,43 @@ smooth_island(region_list * island) } } -static void -starting_region(region * r, region * rn[]) +static void starting_region(region * r, region * rn[]) { - unit * u; + unit *u; + int n; oceans_around(r, rn); freset(r, RF_MARK); - for (n=0;n!=MAXDIRECTIONS;++n) { + for (n = 0; n != MAXDIRECTIONS; ++n) { freset(rn[n], RF_MARK); } terraform_region(r, newterrain(T_PLAIN)); prepare_starting_region(r); u = addplayer(r, addfaction("enno@eressea.de", itoa36(rng_int()), races, - default_locale, 0)); + default_locale, 0)); } + /* E3A island generation */ -int -build_island_e3(int x, int y, int numfactions, int minsize) +int build_island_e3(int x, int y, int numfactions, int minsize) { #define MIN_QUALITY 1000 int nfactions = 0; - region_list * rlist = NULL; - region_list * island = NULL; - plane * pl = findplane(x, y); - region * r = findregion(x, y); + + region_list *rlist = NULL; + + region_list *island = NULL; + + plane *pl = findplane(x, y); + + region *r = findregion(x, y); + int nsize = 1; + int q, maxq = INT_MIN, minq = INT_MAX; - - if (!r) r = new_region(x, y, pl, 0); + + if (!r) + r = new_region(x, y, pl, 0); assert(!r->units); do { terraform_region(r, random_terrain_e3(NODIRECTION)); @@ -960,7 +1159,7 @@ build_island_e3(int x, int y, int numfactions, int minsize) while (r) { fset(r, RF_MARK); if (r->land) { - if (nsizeminsize/2) { - for (rlist=island;rlist;rlist=rlist->next) { + if (nsize > minsize / 2) { + for (rlist = island; rlist; rlist = rlist->next) { r = rlist->data; if (r->land && fval(r, RF_MARK)) { region *rn[MAXDIRECTIONS]; get_neighbours(r, rn); - q = region_quality(r,rn); - if (q>=MIN_QUALITY && nfactions= MIN_QUALITY && nfactions < numfactions) { starting_region(r, rn); minq = MIN(minq, q); maxq = MAX(maxq, q); @@ -989,13 +1188,14 @@ build_island_e3(int x, int y, int numfactions, int minsize) } } - for (rlist=island;rlist && nfactionsnext) { + for (rlist = island; rlist && nfactions < numfactions; rlist = rlist->next) { r = rlist->data; if (!r->land && fval(r, RF_MARK)) { region *rn[MAXDIRECTIONS]; + get_neighbours(r, rn); q = region_quality(r, rn); - if (q>=MIN_QUALITY*4/3 && nfactions= MIN_QUALITY * 4 / 3 && nfactions < numfactions) { starting_region(r, rn); minq = MIN(minq, q); maxq = MAX(maxq, q); @@ -1005,17 +1205,18 @@ build_island_e3(int x, int y, int numfactions, int minsize) } } - for (rlist=island;rlist;rlist=rlist->next) { + for (rlist = island; rlist; rlist = rlist->next) { r = rlist->data; if (r->units) { region *rn[MAXDIRECTIONS]; + get_neighbours(r, rn); q = region_quality(r, rn); - if (q-minq > (maxq-minq)*2/3) { + if (q - minq > (maxq - minq) * 2 / 3) { terraform_region(r, newterrain(T_HIGHLAND)); prepare_starting_region(r); } - r->land->money = 50000; /* 2% = 1000 silver */ + r->land->money = 50000; /* 2% = 1000 silver */ } else if (r->land) { r->land->money *= 4; } diff --git a/src/modules/autoseed.h b/src/modules/autoseed.h index 0fcb75da5..c1fcc064c 100644 --- a/src/modules/autoseed.h +++ b/src/modules/autoseed.h @@ -17,32 +17,33 @@ extern "C" { #endif -struct region_list; -struct newfaction; + struct region_list; + struct newfaction; -typedef struct newfaction { - struct newfaction * next; - char * email; - char * password; - const struct locale * lang; - const struct race * race; - int bonus; - int subscription; - boolean oldregions; - struct alliance * allies; -} newfaction; + typedef struct newfaction { + struct newfaction *next; + char *email; + char *password; + const struct locale *lang; + const struct race *race; + int bonus; + int subscription; + boolean oldregions; + struct alliance *allies; + } newfaction; #define ISLANDSIZE 20 #define TURNS_PER_ISLAND 5 -extern int autoseed(newfaction ** players, int nsize, int max_agediff); -extern newfaction * read_newfactions(const char * filename); -extern void get_island(struct region * root, struct region_list ** rlist); -extern int fix_demand(struct region *r); -extern const struct terrain_type * random_terrain(const struct terrain_type * terrains[], int distribution[], int size); + extern int autoseed(newfaction ** players, int nsize, int max_agediff); + extern newfaction *read_newfactions(const char *filename); + extern void get_island(struct region *root, struct region_list **rlist); + extern int fix_demand(struct region *r); + extern const struct terrain_type *random_terrain(const struct terrain_type + *terrains[], int distribution[], int size); -extern int seed_adamantium(struct region * r, int base); -extern int build_island_e3(int x, int y, int numfactions, int minsize); + extern int seed_adamantium(struct region *r, int base); + extern int build_island_e3(int x, int y, int numfactions, int minsize); #ifdef __cplusplus } diff --git a/src/modules/dungeon.c b/src/modules/dungeon.c index a8275bbda..ff4b8448d 100644 --- a/src/modules/dungeon.c +++ b/src/modules/dungeon.c @@ -40,229 +40,264 @@ #include typedef struct treasure { - const struct item_type * itype; - int amount; - struct treasure * next; + const struct item_type *itype; + int amount; + struct treasure *next; } treasure; typedef struct monster { - const struct race * race; - double chance; - int maxunits; - int avgsize; - struct treasure * treasures; - struct monster * next; - struct itemtype_list * weapons; + const struct race *race; + double chance; + int maxunits; + int avgsize; + struct treasure *treasures; + struct monster *next; + struct itemtype_list *weapons; } monster; typedef struct skilllimit { - skill_t skill; - int minskill; - int maxskill; - struct skilllimit * next; + skill_t skill; + int minskill; + int maxskill; + struct skilllimit *next; } skilllimit; typedef struct dungeon { - int level; - int radius; - int size; - int maxpeople; - struct skilllimit * limits; - double connect; - struct monster * boss; - struct monster * monsters; - struct dungeon * next; + int level; + int radius; + int size; + int maxpeople; + struct skilllimit *limits; + double connect; + struct monster *boss; + struct monster *monsters; + struct dungeon *next; } dungeon; -dungeon * dungeonstyles; +dungeon *dungeonstyles; -region * -make_dungeon(const dungeon * data) +region *make_dungeon(const dungeon * data) { - int nb[2][3][2] = { - { { -1, 0 }, { 0, 1 }, { 1, -1 } }, - { { 1, 0 }, { -1, 1 }, { 0, -1 } } - }; - const struct race * bossrace = data->boss->race; - char name[128]; - int size = data->size; - int iterations = size * size; - unsigned int flags = PFL_NORECRUITS; - int n = 0; - struct faction * fmonsters = get_monsters(); - plane * p; - region *r, *center; - region * rnext; - region_list * iregion, * rlist = NULL; - const terrain_type * terrain_hell = get_terrain("hell"); + int nb[2][3][2] = { + {{-1, 0}, {0, 1}, {1, -1}}, + {{1, 0}, {-1, 1}, {0, -1}} + }; + const struct race *bossrace = data->boss->race; - assert(terrain_hell!=NULL); - sprintf(name, "Die Höhlen von %s", bossrace->generate_name(NULL)); - p = gm_addplane(data->radius, flags, name); + char name[128]; - center = findregion(p->minx+(p->maxx-p->minx)/2, p->miny+(p->maxy-p->miny)/2); - assert(center); - terraform_region(center, terrain_hell); - add_regionlist(&rlist, center); - rnext = r = center; - while (size>0 && iterations--) { - int d, o = rng_int() % 3; - for (d=0;d!=3;++d) { - int index = (d+o) % 3; - region * rn = findregion(r->x+nb[n][index][0], r->y+nb[n][index][1]); - assert(r->terrain==terrain_hell); - if (rn) { - if (rn->terrain==terrain_hell) { + int size = data->size; + + int iterations = size * size; + + unsigned int flags = PFL_NORECRUITS; + + int n = 0; + + struct faction *fmonsters = get_monsters(); + + plane *p; + + region *r, *center; + + region *rnext; + + region_list *iregion, *rlist = NULL; + + const terrain_type *terrain_hell = get_terrain("hell"); + + assert(terrain_hell != NULL); + sprintf(name, "Die Höhlen von %s", bossrace->generate_name(NULL)); + p = gm_addplane(data->radius, flags, name); + + center = + findregion(p->minx + (p->maxx - p->minx) / 2, + p->miny + (p->maxy - p->miny) / 2); + assert(center); + terraform_region(center, terrain_hell); + add_regionlist(&rlist, center); + rnext = r = center; + while (size > 0 && iterations--) { + int d, o = rng_int() % 3; + + for (d = 0; d != 3; ++d) { + int index = (d + o) % 3; + + region *rn = findregion(r->x + nb[n][index][0], r->y + nb[n][index][1]); + + assert(r->terrain == terrain_hell); + if (rn) { + if (rn->terrain == terrain_hell) { rnext = rn; } else if (fval(rn->terrain, SEA_REGION)) { - if (rng_int() % 100 < data->connect*100) { - terraform_region(rn, terrain_hell); - --size; - rnext = rn; - add_regionlist(&rlist, rn); - } - else terraform(rn, T_FIREWALL); - } - if (size == 0) break; - } - rn = findregion(r->x+nb[(n+1)%2][index][0], r->y+nb[(n+1)%2][index][1]); + if (rng_int() % 100 < data->connect * 100) { + terraform_region(rn, terrain_hell); + --size; + rnext = rn; + add_regionlist(&rlist, rn); + } else + terraform(rn, T_FIREWALL); + } + if (size == 0) + break; + } + rn = + findregion(r->x + nb[(n + 1) % 2][index][0], + r->y + nb[(n + 1) % 2][index][1]); if (rn && fval(rn->terrain, SEA_REGION)) { terraform(rn, T_FIREWALL); } - } - if (size==0) break; - if (r==rnext) { - /* error */ - break; - } - r = rnext; - n = (n+1) % 2; - } + } + if (size == 0) + break; + if (r == rnext) { + /* error */ + break; + } + r = rnext; + n = (n + 1) % 2; + } - for (iregion=rlist;iregion;iregion=iregion->next) { - monster * m = data->monsters; - region * r = iregion->data; - while (m) { - if ((rng_int() % 100) < (m->chance * 100)) { - /* TODO: check maxunits. */ - treasure * loot = m->treasures; - struct itemtype_list * weapon = m->weapons; - int size = 1 + (rng_int() % m->avgsize) + (rng_int() % m->avgsize); - unit * u = createunit(r, fmonsters, size, m->race); - while (weapon) { - i_change(&u->items, weapon->type, size); - weapon = weapon->next; - } - while (loot) { - i_change(&u->items, loot->itype, loot->amount*size); - loot = loot->next; - } - } - m = m->next; - } - } - return center; + for (iregion = rlist; iregion; iregion = iregion->next) { + monster *m = data->monsters; + + region *r = iregion->data; + + while (m) { + if ((rng_int() % 100) < (m->chance * 100)) { + /* TODO: check maxunits. */ + treasure *loot = m->treasures; + + struct itemtype_list *weapon = m->weapons; + + int size = 1 + (rng_int() % m->avgsize) + (rng_int() % m->avgsize); + + unit *u = createunit(r, fmonsters, size, m->race); + + while (weapon) { + i_change(&u->items, weapon->type, size); + weapon = weapon->next; + } + while (loot) { + i_change(&u->items, loot->itype, loot->amount * size); + loot = loot->next; + } + } + m = m->next; + } + } + return center; } -void -make_dungeongate(region * source, region * target, const struct dungeon * d) +void make_dungeongate(region * source, region * target, const struct dungeon *d) { - building *bsource, *btarget; + building *bsource, *btarget; - if (source==NULL || target==NULL || d==NULL) return; - bsource = new_building(bt_find("castle"), source, default_locale); - set_string(&bsource->name, "Pforte zur Hölle"); - bsource->size = 50; - add_trigger(&bsource->attribs, "timer", trigger_gate(bsource, target)); - add_trigger(&bsource->attribs, "create", trigger_unguard(bsource)); - fset(bsource, BLD_UNGUARDED); + if (source == NULL || target == NULL || d == NULL) + return; + bsource = new_building(bt_find("castle"), source, default_locale); + set_string(&bsource->name, "Pforte zur Hölle"); + bsource->size = 50; + add_trigger(&bsource->attribs, "timer", trigger_gate(bsource, target)); + add_trigger(&bsource->attribs, "create", trigger_unguard(bsource)); + fset(bsource, BLD_UNGUARDED); - btarget = new_building(bt_find("castle"), target, default_locale); - set_string(&btarget->name, "Pforte zur Außenwelt"); - btarget->size = 50; - add_trigger(&btarget->attribs, "timer", trigger_gate(btarget, source)); - add_trigger(&btarget->attribs, "create", trigger_unguard(btarget)); - fset(btarget, BLD_UNGUARDED); + btarget = new_building(bt_find("castle"), target, default_locale); + set_string(&btarget->name, "Pforte zur Außenwelt"); + btarget->size = 50; + add_trigger(&btarget->attribs, "timer", trigger_gate(btarget, source)); + add_trigger(&btarget->attribs, "create", trigger_unguard(btarget)); + fset(btarget, BLD_UNGUARDED); } -static int -tagbegin(xml_stack *stack) +static int tagbegin(xml_stack * stack) { - xml_tag * tag = stack->tag; - if (strcmp(tag->name, "dungeon")==0) { - dungeon * d = (dungeon*)calloc(sizeof(dungeon), 1); - d->maxpeople = xml_ivalue(tag, "maxpeople"); - if (d->maxpeople==0) d->maxpeople = INT_MAX; - d->level = xml_ivalue(tag, "level"); - d->radius = xml_ivalue(tag, "radius"); - d->connect = xml_fvalue(tag, "connect"); - d->size = xml_ivalue(tag, "size"); - stack->state = d; - } else { - dungeon * d = (dungeon*)stack->state; - if (strcmp(tag->name, "skilllimit")==0) { - skill_t sk = sk_find(xml_value(tag, "name")); - if (sk!=NOSKILL) { - skilllimit * skl = calloc(sizeof(skilllimit), 1); - skl->skill = sk; - if (xml_value(tag, "max")!=NULL) { - skl->maxskill = xml_ivalue(tag, "max"); - } else skl->maxskill = INT_MAX; - if (xml_value(tag, "min")!=NULL) { - skl->minskill = xml_ivalue(tag, "min"); - } else skl->maxskill = INT_MIN; - skl->next = d->limits; - d->limits = skl; - } - } else if (strcmp(tag->name, "monster")==0) { - monster * m = calloc(sizeof(monster), 1); - m->race = rc_find(xml_value(tag, "race")); - m->chance = xml_fvalue(tag, "chance"); - m->avgsize = MAX(1, xml_ivalue(tag, "size")); - m->maxunits = MIN(1, xml_ivalue(tag, "maxunits")); + xml_tag *tag = stack->tag; - if (m->race) { - if (xml_bvalue(tag, "boss")) { - d->boss = m; - } else { - m->next = d->monsters; - d->monsters = m; - } - } - } else if (strcmp(tag->name, "weapon")==0) { - monster * m = d->monsters; - itemtype_list * w = calloc(sizeof(itemtype_list), 1); - w->type = it_find(xml_value(tag, "type")); - if (w->type) { - w->next = m->weapons; - m->weapons = w; - } - } - } - return XML_OK; + if (strcmp(tag->name, "dungeon") == 0) { + dungeon *d = (dungeon *) calloc(sizeof(dungeon), 1); + + d->maxpeople = xml_ivalue(tag, "maxpeople"); + if (d->maxpeople == 0) + d->maxpeople = INT_MAX; + d->level = xml_ivalue(tag, "level"); + d->radius = xml_ivalue(tag, "radius"); + d->connect = xml_fvalue(tag, "connect"); + d->size = xml_ivalue(tag, "size"); + stack->state = d; + } else { + dungeon *d = (dungeon *) stack->state; + + if (strcmp(tag->name, "skilllimit") == 0) { + skill_t sk = sk_find(xml_value(tag, "name")); + + if (sk != NOSKILL) { + skilllimit *skl = calloc(sizeof(skilllimit), 1); + + skl->skill = sk; + if (xml_value(tag, "max") != NULL) { + skl->maxskill = xml_ivalue(tag, "max"); + } else + skl->maxskill = INT_MAX; + if (xml_value(tag, "min") != NULL) { + skl->minskill = xml_ivalue(tag, "min"); + } else + skl->maxskill = INT_MIN; + skl->next = d->limits; + d->limits = skl; + } + } else if (strcmp(tag->name, "monster") == 0) { + monster *m = calloc(sizeof(monster), 1); + + m->race = rc_find(xml_value(tag, "race")); + m->chance = xml_fvalue(tag, "chance"); + m->avgsize = MAX(1, xml_ivalue(tag, "size")); + m->maxunits = MIN(1, xml_ivalue(tag, "maxunits")); + + if (m->race) { + if (xml_bvalue(tag, "boss")) { + d->boss = m; + } else { + m->next = d->monsters; + d->monsters = m; + } + } + } else if (strcmp(tag->name, "weapon") == 0) { + monster *m = d->monsters; + + itemtype_list *w = calloc(sizeof(itemtype_list), 1); + + w->type = it_find(xml_value(tag, "type")); + if (w->type) { + w->next = m->weapons; + m->weapons = w; + } + } + } + return XML_OK; } -static int -tagend(xml_stack * stack) +static int tagend(xml_stack * stack) { - xml_tag * tag = stack->tag; - if (strcmp(tag->name, "dungeon")) { - dungeon * d = (dungeon*)stack->state; - stack->state = NULL; - d->next = dungeonstyles; - dungeonstyles = d; - } - return XML_OK; + xml_tag *tag = stack->tag; + + if (strcmp(tag->name, "dungeon")) { + dungeon *d = (dungeon *) stack->state; + + stack->state = NULL; + d->next = dungeonstyles; + dungeonstyles = d; + } + return XML_OK; } xml_callbacks xml_dungeon = { - tagbegin, tagend, NULL + tagbegin, tagend, NULL }; -void -register_dungeon(void) +void register_dungeon(void) { - xml_register(&xml_dungeon, "eressea dungeon", 0); + xml_register(&xml_dungeon, "eressea dungeon", 0); } #endif diff --git a/src/modules/dungeon.h b/src/modules/dungeon.h index b0526e5a9..cb7715856 100644 --- a/src/modules/dungeon.h +++ b/src/modules/dungeon.h @@ -20,15 +20,16 @@ extern "C" { #error "must define DUNGEON_MODULE to use this module" #endif -struct region; -struct plane; -struct building; -struct dungeon; + struct region; + struct plane; + struct building; + struct dungeon; -extern struct dungeon * dungeonstyles; -extern struct region * make_dungeon(const struct dungeon*); -extern void make_dungeongate(struct region * source, struct region * target, const struct dungeon *); -extern void register_dungeon(void); + extern struct dungeon *dungeonstyles; + extern struct region *make_dungeon(const struct dungeon *); + extern void make_dungeongate(struct region *source, struct region *target, + const struct dungeon *); + extern void register_dungeon(void); #ifdef __cplusplus } diff --git a/src/modules/gmcmd.c b/src/modules/gmcmd.c index 61b216e4e..cc21e8961 100644 --- a/src/modules/gmcmd.c +++ b/src/modules/gmcmd.c @@ -57,25 +57,24 @@ ** at_permissions **/ -static void -mistake(const unit * u, struct order * ord, const char *comment) +static void mistake(const unit * u, struct order *ord, const char *comment) { if (!is_monsters(u->faction)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "mistake", - "error", comment)); + "error", comment)); } } static void -write_permissions(const attrib * a, const void * owner, struct storage * store) +write_permissions(const attrib * a, const void *owner, struct storage *store) { - a_write(store, (attrib*)a->data.v, owner); + a_write(store, (attrib *) a->data.v, owner); } -static int -read_permissions(attrib * a, void * owner, struct storage * store) +static int read_permissions(attrib * a, void *owner, struct storage *store) { - attrib * attr = NULL; + attrib *attr = NULL; + a_read(store, &attr, NULL); a->data.v = attr; return AT_READ_OK; @@ -88,8 +87,7 @@ struct attrib_type at_permissions = { ATF_UNIQUE }; -attrib * -make_atpermissions(void) +attrib *make_atpermissions(void) { return a_new(&at_permissions); } @@ -99,17 +97,18 @@ make_atpermissions(void) **/ static void -write_gmcreate(const attrib * a, const void * owner, struct storage * store) +write_gmcreate(const attrib * a, const void *owner, struct storage *store) { - const item_type * itype = (const item_type *)a->data.v; + const item_type *itype = (const item_type *)a->data.v; + assert(itype); store->w_tok(store, resourcename(itype->rtype, 0)); } -static int -read_gmcreate(attrib * a, void * owner, struct storage * store) +static int read_gmcreate(attrib * a, void *owner, struct storage *store) { char zText[32]; + store->r_tok_buf(store, zText, sizeof(zText)); a->data.v = it_find(zText); if (a->data.v == NULL) { @@ -126,73 +125,87 @@ attrib_type at_gmcreate = { write_gmcreate, read_gmcreate }; -attrib * -make_atgmcreate(const struct item_type * itype) +attrib *make_atgmcreate(const struct item_type * itype) { - attrib * a = a_new(&at_gmcreate); - a->data.v = (void*)itype; + attrib *a = a_new(&at_gmcreate); + + a->data.v = (void *)itype; return a; } -static void -gm_create(const tnode * tnext, void * data, struct order * ord) +static void gm_create(const tnode * tnext, void *data, struct order *ord) { - unit * u = (unit*)data; + unit *u = (unit *) data; + int i; - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (permissions) permissions = (attrib*)permissions->data.v; - if (!permissions) return; + + attrib *permissions = a_find(u->faction->attribs, &at_permissions); + + if (permissions) + permissions = (attrib *) permissions->data.v; + if (!permissions) + return; i = getint(); - if (i>0) { - const char * iname = getstrtoken(); - const item_type * itype = finditemtype(iname, u->faction->locale); - if (itype==NULL) { + if (i > 0) { + const char *iname = getstrtoken(); + + const item_type *itype = finditemtype(iname, u->faction->locale); + + if (itype == NULL) { mistake(u, ord, "unknown item."); } else { - attrib * a = a_find(permissions, &at_gmcreate); + attrib *a = a_find(permissions, &at_gmcreate); - while (a && a->type==&at_gmcreate && a->data.v!=(void*)itype) a=a->next; - if (a) i_change(&u->items, itype, i); - else mistake(u, ord, "your faction cannot create this item."); + while (a && a->type == &at_gmcreate && a->data.v != (void *)itype) + a = a->next; + if (a) + i_change(&u->items, itype, i); + else + mistake(u, ord, "your faction cannot create this item."); } } } -static boolean -has_permission(const attrib * permissions, unsigned int key) +static boolean has_permission(const attrib * permissions, unsigned int key) { - return (find_key((attrib*)permissions->data.v, key) || - find_key((attrib*)permissions->data.v, atoi36("master"))); + return (find_key((attrib *) permissions->data.v, key) || + find_key((attrib *) permissions->data.v, atoi36("master"))); } /** ** GM: GATE ** requires: permission-key "gmgate" **/ -static void -gm_gate(const tnode * tnext, void * data, struct order * ord) +static void gm_gate(const tnode * tnext, void *data, struct order *ord) { - unit * u = (unit*)data; - const struct plane * pl = rplane(u->region); + unit *u = (unit *) data; + + const struct plane *pl = rplane(u->region); + int id = getid(); + int x = rel_to_abs(pl, u->faction, getint(), 0); + int y = rel_to_abs(pl, u->faction, getint(), 1); - building * b = findbuilding(id); - region * r; + + building *b = findbuilding(id); + + region *r; pnormalize(&x, &y, pl); r = findregion(x, y); - if (b==NULL || r==NULL || pl!=rplane(b->region) || pl!=rplane(r)) { + if (b == NULL || r == NULL || pl != rplane(b->region) || pl != rplane(r)) { mistake(u, ord, "the unit cannot transform this building."); return; } else { /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); + attrib *permissions = a_find(u->faction->attribs, &at_permissions); + if (permissions && has_permission(permissions, atoi36("gmgate"))) { remove_triggers(&b->attribs, "timer", &tt_gate); remove_triggers(&b->attribs, "create", &tt_unguard); - if (r!=b->region) { + if (r != b->region) { add_trigger(&b->attribs, "timer", trigger_gate(b, r)); add_trigger(&b->attribs, "create", trigger_unguard(b)); fset(b, BLD_UNGUARDED); @@ -206,31 +219,41 @@ gm_gate(const tnode * tnext, void * data, struct order * ord) ** GM: TERRAFORM ** requires: permission-key "gmterf" **/ -static void -gm_terraform(const tnode * tnext, void * data, struct order * ord) +static void gm_terraform(const tnode * tnext, void *data, struct order *ord) { - unit * u = (unit*)data; - const struct plane * p = rplane(u->region); + unit *u = (unit *) data; + + const struct plane *p = rplane(u->region); + int x = rel_to_abs(p, u->faction, getint(), 0); + int y = rel_to_abs(p, u->faction, getint(), 1); - const char * c = getstrtoken(); + + const char *c = getstrtoken(); + variant token; - tnode * tokens = get_translations(u->faction->locale, UT_TERRAINS); - region * r; + + tnode *tokens = get_translations(u->faction->locale, UT_TERRAINS); + + region *r; + pnormalize(&x, &y, p); r = findregion(x, y); - if (r==NULL || p!=rplane(r)) { + if (r == NULL || p != rplane(r)) { mistake(u, ord, "region is in another plane."); return; } else { /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmterf"))) return; + attrib *permissions = a_find(u->faction->attribs, &at_permissions); + + if (!permissions || !has_permission(permissions, atoi36("gmterf"))) + return; } - if (findtoken(tokens, c, &token)!=E_TOK_NOMATCH) { - const terrain_type * terrain = (const terrain_type *)token.v; + if (findtoken(tokens, c, &token) != E_TOK_NOMATCH) { + const terrain_type *terrain = (const terrain_type *)token.v; + terraform_region(r, terrain); } } @@ -239,29 +262,36 @@ gm_terraform(const tnode * tnext, void * data, struct order * ord) ** GM: TELEPORT ** requires: permission-key "gmtele" **/ -static void -gm_teleport(const tnode * tnext, void * data, struct order * ord) +static void gm_teleport(const tnode * tnext, void *data, struct order *ord) { - unit * u = (unit*)data; - const struct plane * p = rplane(u->region); - unit * to = findunit(getid()); - int x = rel_to_abs(p, u->faction, getint(), 0); - int y = rel_to_abs(p, u->faction, getint(), 1); - region * r = findregion(x, y); + unit *u = (unit *) data; - if (r==NULL || p!=rplane(r)) { + const struct plane *p = rplane(u->region); + + unit *to = findunit(getid()); + + int x = rel_to_abs(p, u->faction, getint(), 0); + + int y = rel_to_abs(p, u->faction, getint(), 1); + + region *r = findregion(x, y); + + if (r == NULL || p != rplane(r)) { mistake(u, ord, "region is in another plane."); - } else if (to==NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } else if (rplane(to->region)!=rplane(r) && !ucontact(to, u)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", "target", to)); + } else if (to == NULL) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", + "")); + } else if (rplane(to->region) != rplane(r) && !ucontact(to, u)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact", + "target", to)); } else { /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); + attrib *permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmtele"))) { mistake(u, ord, "permission denied."); - } - else move_unit(to, r, NULL); + } else + move_unit(to, r, NULL); } } @@ -269,35 +299,43 @@ gm_teleport(const tnode * tnext, void * data, struct order * ord) ** GM: TELL PLANE ** requires: permission-key "gmmsgr" **/ -static void -gm_messageplane(const tnode * tnext, void * data, struct order * ord) +static void gm_messageplane(const tnode * tnext, void *data, struct order *ord) { - unit * gm = (unit*)data; - const struct plane * p = rplane(gm->region); - const char * zmsg = getstrtoken(); - if (p==NULL) { + unit *gm = (unit *) data; + + const struct plane *p = rplane(gm->region); + + const char *zmsg = getstrtoken(); + + if (p == NULL) { mistake(gm, ord, "In diese Ebene kann keine Nachricht gesandt werden."); } else { /* checking permissions */ - attrib * permissions = a_find(gm->faction->attribs, &at_permissions); + attrib *permissions = a_find(gm->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { mistake(gm, ord, "permission denied."); - } - else { - message * msg = msg_message("msg_event", "string", zmsg); - faction * f; - region * r; - for (f=factions;f;f=f->next) { + } else { + message *msg = msg_message("msg_event", "string", zmsg); + + faction *f; + + region *r; + + for (f = factions; f; f = f->next) { freset(f, FFL_SELECT); } - for (r=regions;r;r=r->next) { - unit * u; - if (rplane(r)!=p) continue; - for (u=r->units;u;u=u->next) if (!fval(u->faction, FFL_SELECT)) { - f = u->faction; - fset(f, FFL_SELECT); - add_message(&f->msgs, msg); - } + for (r = regions; r; r = r->next) { + unit *u; + + if (rplane(r) != p) + continue; + for (u = r->units; u; u = u->next) + if (!fval(u->faction, FFL_SELECT)) { + f = u->faction; + fset(f, FFL_SELECT); + add_message(&f->msgs, msg); + } } msg_release(msg); } @@ -305,27 +343,37 @@ gm_messageplane(const tnode * tnext, void * data, struct order * ord) } static void -gm_messagefaction(const tnode * tnext, void * data, struct order * ord) +gm_messagefaction(const tnode * tnext, void *data, struct order *ord) { - unit * gm = (unit*)data; + unit *gm = (unit *) data; + int n = getid(); - faction * f = findfaction(n); - const char * msg = getstrtoken(); - plane * p = rplane(gm->region); - attrib * permissions = a_find(gm->faction->attribs, &at_permissions); + + faction *f = findfaction(n); + + const char *msg = getstrtoken(); + + plane *p = rplane(gm->region); + + attrib *permissions = a_find(gm->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { mistake(gm, ord, "permission denied."); return; } - if (f!=NULL) { - region * r; - for (r=regions;r;r=r->next) if (rplane(r)==p) { - unit * u; - for (u=r->units;u;u=u->next) if (u->faction==f) { - add_message(&f->msgs, msg_message("msg_event", "string", msg)); - return; + if (f != NULL) { + region *r; + + for (r = regions; r; r = r->next) + if (rplane(r) == p) { + unit *u; + + for (u = r->units; u; u = u->next) + if (u->faction == f) { + add_message(&f->msgs, msg_message("msg_event", "string", msg)); + return; + } } - } } mistake(gm, ord, "cannot send messages to this faction."); } @@ -334,25 +382,29 @@ gm_messagefaction(const tnode * tnext, void * data, struct order * ord) ** GM: TELL REGION ** requires: permission-key "gmmsgr" **/ -static void -gm_messageregion(const tnode * tnext, void * data, struct order * ord) +static void gm_messageregion(const tnode * tnext, void *data, struct order *ord) { - unit * u = (unit*)data; - const struct plane * p = rplane(u->region); - int x = rel_to_abs(p, u->faction, getint(), 0); - int y = rel_to_abs(p, u->faction, getint(), 1); - const char * msg = getstrtoken(); - region * r = findregion(x, y); + unit *u = (unit *) data; - if (r==NULL || p!=rplane(r)) { + const struct plane *p = rplane(u->region); + + int x = rel_to_abs(p, u->faction, getint(), 0); + + int y = rel_to_abs(p, u->faction, getint(), 1); + + const char *msg = getstrtoken(); + + region *r = findregion(x, y); + + if (r == NULL || p != rplane(r)) { mistake(u, ord, "region is in another plane."); } else { /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); + attrib *permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { mistake(u, ord, "permission denied."); - } - else { + } else { add_message(&r->msgs, msg_message("msg_event", "string", msg)); } } @@ -362,27 +414,30 @@ gm_messageregion(const tnode * tnext, void * data, struct order * ord) ** GM: KILL UNIT ** requires: permission-key "gmkill" **/ -static void -gm_killunit(const tnode * tnext, void * data, struct order * ord) +static void gm_killunit(const tnode * tnext, void *data, struct order *ord) { - unit * u = (unit*)data; - const struct plane * p = rplane(u->region); - unit * target = findunit(getid()); - const char * msg = getstrtoken(); - region * r = target->region; + unit *u = (unit *) data; - if (r==NULL || p!=rplane(r)) { + const struct plane *p = rplane(u->region); + + unit *target = findunit(getid()); + + const char *msg = getstrtoken(); + + region *r = target->region; + + if (r == NULL || p != rplane(r)) { mistake(u, ord, "region is in another plane."); } else { /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); + attrib *permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmkill"))) { mistake(u, ord, "permission denied."); - } - else { + } else { scale_number(target, 0); ADDMSG(&target->faction->msgs, msg_message("killedbygm", - "region unit string", r, target, msg)); + "region unit string", r, target, msg)); } } } @@ -392,32 +447,40 @@ gm_killunit(const tnode * tnext, void * data, struct order * ord) ** GM: KILL FACTION ** requires: permission-key "gmmsgr" **/ -static void -gm_killfaction(const tnode * tnext, void * data, struct order * ord) +static void gm_killfaction(const tnode * tnext, void *data, struct order *ord) { - unit * u = (unit*)data; + unit *u = (unit *) data; + int n = getid(); - faction * f = findfaction(n); - const char * msg = getstrtoken(); - plane * p = rplane(u->region); - attrib * permissions = a_find(u->faction->attribs, &at_permissions); + + faction *f = findfaction(n); + + const char *msg = getstrtoken(); + + plane *p = rplane(u->region); + + attrib *permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmkill"))) { mistake(u, ord, "permission denied."); return; } - if (f!=NULL) { - region * r; - for (r=regions;r;r=r->next) if (rplane(r)==p) { - unit * target; - for (target=r->units;target;target=target->next) { - if (target->faction==f) { - scale_number(target, 0); - ADDMSG(&target->faction->msgs, msg_message("killedbygm", - "region unit string", r, target, msg)); - return; + if (f != NULL) { + region *r; + + for (r = regions; r; r = r->next) + if (rplane(r) == p) { + unit *target; + + for (target = r->units; target; target = target->next) { + if (target->faction == f) { + scale_number(target, 0); + ADDMSG(&target->faction->msgs, msg_message("killedbygm", + "region unit string", r, target, msg)); + return; + } } } - } } mistake(u, ord, "cannot remove a unit from this faction."); } @@ -426,31 +489,35 @@ gm_killfaction(const tnode * tnext, void * data, struct order * ord) ** GM: TELL ** requires: permission-key "gmmsgr" **/ -static void -gm_messageunit(const tnode * tnext, void * data, struct order * ord) +static void gm_messageunit(const tnode * tnext, void *data, struct order *ord) { - unit * u = (unit*)data; - const struct plane * p = rplane(u->region); - unit * target = findunit(getid()); - const char * msg = getstrtoken(); - region * r; + unit *u = (unit *) data; + + const struct plane *p = rplane(u->region); + + unit *target = findunit(getid()); + + const char *msg = getstrtoken(); + + region *r; if (target == NULL) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", + "")); return; } r = target->region; - if (r==NULL || p!=rplane(r)) { + if (r == NULL || p != rplane(r)) { mistake(u, ord, "region is in another plane."); } else { /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); + attrib *permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmmsgu"))) { mistake(u, ord, "permission denied."); - } - else { + } else { add_message(&target->faction->msgs, msg_message("regionmessage", "region sender string", r, u, msg)); } @@ -461,29 +528,34 @@ gm_messageunit(const tnode * tnext, void * data, struct order * ord) ** GM: GIVE ** requires: permission-key "gmgive" **/ -static void -gm_give(const tnode * tnext, void * data, struct order * ord) +static void gm_give(const tnode * tnext, void *data, struct order *ord) { - unit * u = (unit*)data; - unit * to = findunit(getid()); - int num = getint(); - const item_type * itype = finditemtype(getstrtoken(), u->faction->locale); + unit *u = (unit *) data; - if (to==NULL || rplane(to->region) != rplane(u->region)) { + unit *to = findunit(getid()); + + int num = getint(); + + const item_type *itype = finditemtype(getstrtoken(), u->faction->locale); + + if (to == NULL || rplane(to->region) != rplane(u->region)) { /* unknown or in another plane */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } else if (itype==NULL || i_get(u->items, itype)==0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", + "")); + } else if (itype == NULL || i_get(u->items, itype) == 0) { /* unknown or not enough */ mistake(u, ord, "invalid item or item not found."); } else { /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); + attrib *permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmgive"))) { mistake(u, ord, "permission denied."); - } - else { + } else { int i = i_get(u->items, itype); - if (iitems, itype, -num); i_change(&to->items, itype, num); @@ -496,29 +568,34 @@ gm_give(const tnode * tnext, void * data, struct order * ord) ** GM: TAKE ** requires: permission-key "gmtake" **/ -static void -gm_take(const tnode * tnext, void * data, struct order * ord) +static void gm_take(const tnode * tnext, void *data, struct order *ord) { - unit * u = (unit*)data; - unit * to = findunit(getid()); - int num = getint(); - const item_type * itype = finditemtype(getstrtoken(), u->faction->locale); + unit *u = (unit *) data; - if (to==NULL || rplane(to->region) != rplane(u->region)) { + unit *to = findunit(getid()); + + int num = getint(); + + const item_type *itype = finditemtype(getstrtoken(), u->faction->locale); + + if (to == NULL || rplane(to->region) != rplane(u->region)) { /* unknown or in another plane */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } else if (itype==NULL || i_get(to->items, itype)==0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", + "")); + } else if (itype == NULL || i_get(to->items, itype) == 0) { /* unknown or not enough */ mistake(u, ord, "invalid item or item not found."); } else { /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); + attrib *permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmtake"))) { mistake(u, ord, "permission denied."); - } - else { + } else { int i = i_get(to->items, itype); - if (iitems, itype, -num); i_change(&u->items, itype, num); @@ -531,42 +608,47 @@ gm_take(const tnode * tnext, void * data, struct order * ord) ** GM: SKILL ** requires: permission-key "gmskil" **/ -static void -gm_skill(const tnode * tnext, void * data, struct order * ord) +static void gm_skill(const tnode * tnext, void *data, struct order *ord) { - unit * u = (unit*)data; - unit * to = findunit(getid()); + unit *u = (unit *) data; + + unit *to = findunit(getid()); + skill_t skill = findskill(getstrtoken(), u->faction->locale); + int num = getint(); - if (to==NULL || rplane(to->region) != rplane(u->region)) { + if (to == NULL || rplane(to->region) != rplane(u->region)) { /* unknown or in another plane */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - } else if (skill==NOSKILL || skill==SK_MAGIC || skill==SK_ALCHEMY) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", + "")); + } else if (skill == NOSKILL || skill == SK_MAGIC || skill == SK_ALCHEMY) { /* unknown or not enough */ mistake(u, ord, "unknown skill, or skill cannot be raised."); - } else if (num<0 || num>30) { + } else if (num < 0 || num > 30) { /* sanity check failed */ mistake(u, ord, "invalid value."); } else { /* checking permissions */ - attrib * permissions = a_find(u->faction->attribs, &at_permissions); + attrib *permissions = a_find(u->faction->attribs, &at_permissions); + if (!permissions || !has_permission(permissions, atoi36("gmskil"))) { mistake(u, ord, "permission denied."); - } - else { + } else { set_level(to, skill, num); } } } static tnode g_keys; + static tnode g_root; + static tnode g_tell; + static tnode g_kill; -void -register_gmcmd(void) +void register_gmcmd(void) { at_register(&at_gmcreate); at_register(&at_permissions); @@ -592,67 +674,86 @@ register_gmcmd(void) * execute gm-commands for all units in the game */ -void -gmcommands(void) +void gmcommands(void) { - region ** rp = ®ions; + region **rp = ®ions; + while (*rp) { - region * r = *rp; + region *r = *rp; + unit **up = &r->units; + while (*up) { - unit * u = *up; - struct order * ord; + unit *u = *up; + + struct order *ord; + for (ord = u->orders; ord; ord = ord->next) { if (get_keyword(ord) == K_GM) { do_command(&g_root, u, ord); } } - if (u==*up) up = &u->next; + if (u == *up) + up = &u->next; } - if (*rp==r) rp = &r->next; + if (*rp == r) + rp = &r->next; } } #define EXTENSION 10000 -faction * -gm_addquest(const char * email, const char * name, int radius, unsigned int flags) +faction *gm_addquest(const char *email, const char *name, int radius, + unsigned int flags) { - plane * pl; - watcher * w = calloc(sizeof(watcher), 1); - region * center; + plane *pl; + + watcher *w = calloc(sizeof(watcher), 1); + + region *center; + boolean invalid = false; + int minx, miny, maxx, maxy, cx, cy; + int x; - faction * f; + + faction *f; /* GM playfield */ do { - minx = ((rng_int() % (2*EXTENSION)) - EXTENSION); - miny = ((rng_int() % (2*EXTENSION)) - EXTENSION); - for (x=0;!invalid && x<=radius*2;++x) { + minx = ((rng_int() % (2 * EXTENSION)) - EXTENSION); + miny = ((rng_int() % (2 * EXTENSION)) - EXTENSION); + for (x = 0; !invalid && x <= radius * 2; ++x) { int y; - for (y=0;!invalid && y<=radius*2;++y) { - region * r = findregion(minx+x, miny+y); - if (r) invalid = true; + + for (y = 0; !invalid && y <= radius * 2; ++y) { + region *r = findregion(minx + x, miny + y); + + if (r) + invalid = true; } } } while (invalid); - maxx = minx+2*radius; cx = minx+radius; - maxy = miny+2*radius; cy = miny+radius; + maxx = minx + 2 * radius; + cx = minx + radius; + maxy = miny + 2 * radius; + cy = miny + radius; pl = create_new_plane(rng_int(), name, minx, maxx, miny, maxy, flags); center = new_region(cx, cy, pl, 0); - for (x=0;x<=2*radius;++x) { + for (x = 0; x <= 2 * radius; ++x) { int y; - for (y=0;y<=2*radius;++y) { - region * r = findregion(minx+x, miny+y); + + for (y = 0; y <= 2 * radius; ++y) { + region *r = findregion(minx + x, miny + y); + if (!r) { - r = new_region(minx+x, miny+y, pl, 0); + r = new_region(minx + x, miny + y, pl, 0); } freset(r, RF_ENCOUNTER); - if (distance(r, center)==radius) { + if (distance(r, center) == radius) { terraform_region(r, newterrain(T_FIREWALL)); - } else if (r==center) { + } else if (r == center) { terraform_region(r, newterrain(T_PLAIN)); } else { terraform_region(r, newterrain(T_OCEAN)); @@ -670,14 +771,15 @@ gm_addquest(const char * email, const char * name, int radius, unsigned int flag return f; } -faction * -gm_addfaction(const char * email, plane * p, region * r) +faction *gm_addfaction(const char *email, plane * p, region * r) { - attrib * a; - unit * u; - faction * f = calloc(1, sizeof(faction)); + attrib *a; - assert(p!=NULL); + unit *u; + + faction *f = calloc(1, sizeof(faction)); + + assert(p != NULL); /* GM faction */ a_add(&f->attribs, make_key(atoi36("quest"))); @@ -685,18 +787,22 @@ gm_addfaction(const char * email, plane * p, region * r) f->name = strdup("quest faction"); f->passw = strdup(itoa36(rng_int())); f->override = strdup(itoa36(rng_int())); - if (set_email(&f->email, email)!=0) { - log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), email)); + if (set_email(&f->email, email) != 0) { + log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), + email)); } f->race = new_race[RC_TEMPLATE]; f->age = 0; f->lastorders = turn; f->alive = true; f->locale = default_locale; - f->options = want(O_COMPRESS) | want(O_REPORT) | want(O_COMPUTER) | want(O_ADRESSEN); + f->options = + want(O_COMPRESS) | want(O_REPORT) | want(O_COMPUTER) | want(O_ADRESSEN); { - faction * xist; - int id = atoi36("gm00")-1; + faction *xist; + + int id = atoi36("gm00") - 1; + do { xist = findfaction(++id); } while (xist); @@ -709,9 +815,12 @@ gm_addfaction(const char * email, plane * p, region * r) /* generic permissions */ a = a_add(&f->attribs, a_new(&at_permissions)); if (a) { - attrib * ap = (attrib*)a->data.v; - const char* keys[] = { "gmterf", "gmtele", "gmgive", "gmskil", "gmtake", "gmmsgr", "gmmsgu", "gmgate", 0 }; - const char ** key_p = keys; + attrib *ap = (attrib *) a->data.v; + const char *keys[] = + { "gmterf", "gmtele", "gmgive", "gmskil", "gmtake", "gmmsgr", "gmmsgu", + "gmgate", 0 }; + const char **key_p = keys; + while (*key_p) { add_key(&ap, atoi36(*key_p)); ++key_p; @@ -720,7 +829,7 @@ gm_addfaction(const char * email, plane * p, region * r) a->data.v = ap; } - + /* one initial unit */ u = create_unit(r, f, 1, new_race[RC_TEMPLATE], 1, "quest master", NULL); u->irace = new_race[RC_GNOME]; @@ -728,40 +837,51 @@ gm_addfaction(const char * email, plane * p, region * r) return f; } -plane * -gm_addplane(int radius, unsigned int flags, const char * name) +plane *gm_addplane(int radius, unsigned int flags, const char *name) { - region * center; - plane * pl; + region *center; + + plane *pl; + boolean invalid = false; + int minx, miny, maxx, maxy, cx, cy; + int x; /* GM playfield */ do { - minx = (rng_int() % (2*EXTENSION)) - EXTENSION; - miny = (rng_int() % (2*EXTENSION)) - EXTENSION; - for (x=0;!invalid && x<=radius*2;++x) { + minx = (rng_int() % (2 * EXTENSION)) - EXTENSION; + miny = (rng_int() % (2 * EXTENSION)) - EXTENSION; + for (x = 0; !invalid && x <= radius * 2; ++x) { int y; - for (y=0;!invalid && y<=radius*2;++y) { - region * r = findregion(minx+x, miny+y); - if (r) invalid = true; + + for (y = 0; !invalid && y <= radius * 2; ++y) { + region *r = findregion(minx + x, miny + y); + + if (r) + invalid = true; } } } while (invalid); - maxx = minx+2*radius; cx = minx+radius; - maxy = miny+2*radius; cy = miny+radius; + maxx = minx + 2 * radius; + cx = minx + radius; + maxy = miny + 2 * radius; + cy = miny + radius; pl = create_new_plane(rng_int(), name, minx, maxx, miny, maxy, flags); center = new_region(cx, cy, pl, 0); - for (x=0;x<=2*radius;++x) { + for (x = 0; x <= 2 * radius; ++x) { int y; - for (y=0;y<=2*radius;++y) { - region * r = findregion(minx+x, miny+y); - if (!r) r = new_region(minx+x, miny+y, pl, 0); + + for (y = 0; y <= 2 * radius; ++y) { + region *r = findregion(minx + x, miny + y); + + if (!r) + r = new_region(minx + x, miny + y, pl, 0); freset(r, RF_ENCOUNTER); - if (distance(r, center)==radius) { + if (distance(r, center) == radius) { terraform_region(r, newterrain(T_FIREWALL)); - } else if (r==center) { + } else if (r == center) { terraform_region(r, newterrain(T_PLAIN)); } else { terraform_region(r, newterrain(T_OCEAN)); diff --git a/src/modules/gmcmd.h b/src/modules/gmcmd.h index 2e830b51c..490792d2e 100644 --- a/src/modules/gmcmd.h +++ b/src/modules/gmcmd.h @@ -22,25 +22,27 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -struct plane; -struct attrib; -struct unit; -struct faction; -struct region; + struct plane; + struct attrib; + struct unit; + struct faction; + struct region; -extern void register_gmcmd(void); + extern void register_gmcmd(void); /* initialize this module */ -extern void gmcommands(void); + extern void gmcommands(void); /* execute commands */ -extern struct faction * gm_addfaction(const char * email, struct plane * p, struct region * r); -extern struct plane * gm_addplane(int radius, unsigned int flags, const char * name); + extern struct faction *gm_addfaction(const char *email, struct plane *p, + struct region *r); + extern struct plane *gm_addplane(int radius, unsigned int flags, + const char *name); /* * doesn't belong in here: */ -struct attrib * find_key(struct attrib * attribs, int key); + struct attrib *find_key(struct attrib *attribs, int key); #ifdef __cplusplus } diff --git a/src/modules/museum.c b/src/modules/museum.c index 7186f177d..9284ce0d1 100644 --- a/src/modules/museum.c +++ b/src/modules/museum.c @@ -52,299 +52,334 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define PFL_MUSEUM PFL_NOMONSTERS | PFL_NORECRUITS | PFL_NOGIVE | PFL_NOATTACK | PFL_NOTERRAIN | PFL_NOMAGIC | PFL_NOSTEALTH | PFL_NOTEACH | PFL_NOBUILD | PFL_NOFEED attrib_type at_museumexit = { - "museumexit", NULL, NULL, NULL, a_writeshorts, a_readshorts + "museumexit", NULL, NULL, NULL, a_writeshorts, a_readshorts }; -static void -a_initmuseumgivebackcookie(attrib *a) +static void a_initmuseumgivebackcookie(attrib * a) { - a->data.v = calloc(1,sizeof(museumgivebackcookie)); + a->data.v = calloc(1, sizeof(museumgivebackcookie)); +} + +static void a_finalizemuseumgivebackcookie(attrib * a) +{ + free(a->data.v); } static void -a_finalizemuseumgivebackcookie(attrib *a) +a_writemuseumgivebackcookie(const attrib * a, const void *owner, + struct storage *store) { - free(a->data.v); -} + museumgivebackcookie *gbc = (museumgivebackcookie *) a->data.v; -static void -a_writemuseumgivebackcookie(const attrib * a, const void * owner, struct storage * store) -{ - museumgivebackcookie *gbc = (museumgivebackcookie *)a->data.v; store->w_int(store, gbc->warden_no); store->w_int(store, gbc->cookie); } static int -a_readmuseumgivebackcookie(attrib *a, void * owner, struct storage * store) +a_readmuseumgivebackcookie(attrib * a, void *owner, struct storage *store) { - museumgivebackcookie *gbc = (museumgivebackcookie *)a->data.v; + museumgivebackcookie *gbc = (museumgivebackcookie *) a->data.v; + gbc->warden_no = store->r_int(store); gbc->cookie = store->r_int(store); return AT_READ_OK; } attrib_type at_museumgivebackcookie = { - "museumgivebackcookie", - a_initmuseumgivebackcookie, - a_finalizemuseumgivebackcookie, - NULL, - a_writemuseumgivebackcookie, - a_readmuseumgivebackcookie + "museumgivebackcookie", + a_initmuseumgivebackcookie, + a_finalizemuseumgivebackcookie, + NULL, + a_writemuseumgivebackcookie, + a_readmuseumgivebackcookie }; attrib_type at_warden = { - "itemwarden", NULL, NULL, NULL, a_writeint, a_readint + "itemwarden", NULL, NULL, NULL, a_writeint, a_readint }; -static void -a_initmuseumgiveback(attrib *a) +static void a_initmuseumgiveback(attrib * a) { - a->data.v = calloc(1, sizeof(museumgiveback)); + a->data.v = calloc(1, sizeof(museumgiveback)); +} + +static void a_finalizemuseumgiveback(attrib * a) +{ + museumgiveback *gb = (museumgiveback *) a->data.v; + + i_freeall(&gb->items); + free(a->data.v); } static void -a_finalizemuseumgiveback(attrib *a) +a_writemuseumgiveback(const attrib * a, const void *owner, + struct storage *store) { - museumgiveback *gb = (museumgiveback *)a->data.v; - i_freeall(&gb->items); - free(a->data.v); + museumgiveback *gb = (museumgiveback *) a->data.v; + + store->w_int(store, gb->cookie); + write_items(store, gb->items); } -static void -a_writemuseumgiveback(const attrib * a, const void * owner, struct storage * store) +static int a_readmuseumgiveback(attrib * a, void *owner, struct storage *store) { - museumgiveback *gb = (museumgiveback *)a->data.v; - store->w_int(store, gb->cookie); - write_items(store, gb->items); -} + museumgiveback *gb = (museumgiveback *) a->data.v; -static int -a_readmuseumgiveback(attrib *a, void * owner, struct storage * store) -{ - museumgiveback *gb = (museumgiveback *)a->data.v; - gb->cookie = store->r_int(store); - read_items(store, &gb->items); - return AT_READ_OK; + gb->cookie = store->r_int(store); + read_items(store, &gb->items); + return AT_READ_OK; } attrib_type at_museumgiveback = { - "museumgiveback", - a_initmuseumgiveback, - a_finalizemuseumgiveback, - NULL, - a_writemuseumgiveback, - a_readmuseumgiveback + "museumgiveback", + a_initmuseumgiveback, + a_finalizemuseumgiveback, + NULL, + a_writemuseumgiveback, + a_readmuseumgiveback }; -void -warden_add_give(unit *src, unit *u, const item_type *itype, int n) +void warden_add_give(unit * src, unit * u, const item_type * itype, int n) { - attrib *aw = a_find(u->attribs, &at_warden); - museumgiveback *gb = NULL; - museumgivebackcookie *gbc; - attrib *a; + attrib *aw = a_find(u->attribs, &at_warden); - /* has the giver a cookie corresponding to the warden */ - for(a = a_find(src->attribs, &at_museumgivebackcookie); a && a->type==&at_museumgivebackcookie; a=a->next) { - if(((museumgivebackcookie *)(a->data.v))->warden_no == u->no) break; - } + museumgiveback *gb = NULL; - /* if not give it one */ - if (a==NULL || a->type!=&at_museumgivebackcookie) { - a = a_add(&src->attribs, a_new(&at_museumgivebackcookie)); - gbc = (museumgivebackcookie *)a->data.v; - gbc->warden_no = u->no; - gbc->cookie = aw->data.i; - assert(aw->data.i < INT_MAX); - aw->data.i++; - } else { - gbc = (museumgivebackcookie *)(a->data.v); - } + museumgivebackcookie *gbc; - /* now we search for the warden's corresponding item list */ - for (a = a_find(u->attribs, &at_museumgiveback); a && a->type==&at_museumgiveback; a=a->next) { - gb = (museumgiveback *)a->data.v; - if (gb->cookie == gbc->cookie) { - break; - } - } + attrib *a; - /* if there's none, give it one */ - if (!gb) { - a = a_add(&u->attribs, a_new(&at_museumgiveback)); - gb = (museumgiveback *)a->data.v; - gb->cookie = gbc->cookie; - } + /* has the giver a cookie corresponding to the warden */ + for (a = a_find(src->attribs, &at_museumgivebackcookie); + a && a->type == &at_museumgivebackcookie; a = a->next) { + if (((museumgivebackcookie *) (a->data.v))->warden_no == u->no) + break; + } - /* now register the items */ - i_change(&gb->items, itype, n); + /* if not give it one */ + if (a == NULL || a->type != &at_museumgivebackcookie) { + a = a_add(&src->attribs, a_new(&at_museumgivebackcookie)); + gbc = (museumgivebackcookie *) a->data.v; + gbc->warden_no = u->no; + gbc->cookie = aw->data.i; + assert(aw->data.i < INT_MAX); + aw->data.i++; + } else { + gbc = (museumgivebackcookie *) (a->data.v); + } - /* done */ + /* now we search for the warden's corresponding item list */ + for (a = a_find(u->attribs, &at_museumgiveback); + a && a->type == &at_museumgiveback; a = a->next) { + gb = (museumgiveback *) a->data.v; + if (gb->cookie == gbc->cookie) { + break; + } + } - /* this has a caveat: If the src-unit is destroyed while inside - * the museum, the corresponding itemlist of the warden will never - * be removed. to circumvent that in a generic way will be extremly - * difficult. */ + /* if there's none, give it one */ + if (!gb) { + a = a_add(&u->attribs, a_new(&at_museumgiveback)); + gb = (museumgiveback *) a->data.v; + gb->cookie = gbc->cookie; + } + + /* now register the items */ + i_change(&gb->items, itype, n); + + /* done */ + + /* this has a caveat: If the src-unit is destroyed while inside + * the museum, the corresponding itemlist of the warden will never + * be removed. to circumvent that in a generic way will be extremly + * difficult. */ } -void -create_museum(void) +void create_museum(void) { -#if 0 /* TODO: move this to LUA. It should be possible. */ - unsigned int museum_id = hashstring("museum"); - plane *museum = getplanebyid(museum_id); - region *r; - building *b; - const terrain_type * terrain_hall = get_terrain("hall1"); - const terrain_type * terrain_corridor = get_terrain("corridor1"); +#if 0 /* TODO: move this to LUA. It should be possible. */ + unsigned int museum_id = hashstring("museum"); + + plane *museum = getplanebyid(museum_id); + + region *r; + + building *b; + + const terrain_type *terrain_hall = get_terrain("hall1"); + + const terrain_type *terrain_corridor = get_terrain("corridor1"); assert(terrain_corridor && terrain_hall); - if (!museum) { - museum = create_new_plane(museum_id, "Museum", 9500, 9550, - 9500, 9550, PFL_MUSEUM); - } + if (!museum) { + museum = create_new_plane(museum_id, "Museum", 9500, 9550, + 9500, 9550, PFL_MUSEUM); + } - if (findregion(9525, 9525) == NULL) { - /* Eingangshalle */ - r = new_region(9525, 9525, 0); - terraform_region(r, terrain_hall); - r->planep = museum; - rsetname(r, "Eingangshalle"); - rsethorses(r, 0); - rsetmoney(r, 0); - rsetpeasants(r, 0); - set_string(&r->display, "Die Eingangshalle des Großen Museum der 1. Welt ist bereits jetzt ein beeindruckender Anblick. Obwohl das Museum noch nicht eröffnet ist, vermittelt sie bereits einen Flair exotischer Welten. In den Boden ist ein großer Kompass eingelassen, der den Besuchern bei Orientierung helfen soll."); - } + if (findregion(9525, 9525) == NULL) { + /* Eingangshalle */ + r = new_region(9525, 9525, 0); + terraform_region(r, terrain_hall); + r->planep = museum; + rsetname(r, "Eingangshalle"); + rsethorses(r, 0); + rsetmoney(r, 0); + rsetpeasants(r, 0); + set_string(&r->display, + "Die Eingangshalle des Großen Museum der 1. Welt ist bereits jetzt ein beeindruckender Anblick. Obwohl das Museum noch nicht eröffnet ist, vermittelt sie bereits einen Flair exotischer Welten. In den Boden ist ein großer Kompass eingelassen, der den Besuchern bei Orientierung helfen soll."); + } - r = findregion(9526, 9525); - if(!r) { - /* Lounge */ - r = new_region(9526, 9525, 0); - terraform_region(r, terrain_hall); - r->planep = museum; - rsetname(r, "Lounge"); - rsethorses(r, 0); - rsetmoney(r, 0); - rsetpeasants(r, 0); - set_string(&r->display, "Die Lounge des großen Museums ist ein Platz, in dem sich die Besucher treffen, um die Eindrücke, die sie gewonnen haben, zu verarbeiten. Gemütliche Sitzgruppen laden zum Verweilen ein."); - } + r = findregion(9526, 9525); + if (!r) { + /* Lounge */ + r = new_region(9526, 9525, 0); + terraform_region(r, terrain_hall); + r->planep = museum; + rsetname(r, "Lounge"); + rsethorses(r, 0); + rsetmoney(r, 0); + rsetpeasants(r, 0); + set_string(&r->display, + "Die Lounge des großen Museums ist ein Platz, in dem sich die Besucher treffen, um die Eindrücke, die sie gewonnen haben, zu verarbeiten. Gemütliche Sitzgruppen laden zum Verweilen ein."); + } - r = findregion(9526, 9525); - if(!r->buildings) { - const building_type * bt_generic = bt_find("generic"); - b = new_building(bt_generic, r, NULL); - set_string(&b->name, "Séparée im dämonischen Stil"); - set_string(&b->display, "Diese ganz im dämonischen Stil gehaltene Sitzgruppe ist ganz in dunklen Schwarztönen gehalten. Muster fremdartiger Runen bedecken das merkwürdig geformte Mobiliar, das unangenehm lebendig wirkt."); + r = findregion(9526, 9525); + if (!r->buildings) { + const building_type *bt_generic = bt_find("generic"); - b = new_building(bt_generic, r, NULL); - set_string(&b->name, "Séparée im elfischen Stil"); - set_string(&b->display, "Ganz in Grün- und Brauntönen gehalten wirkt die Sitzgruppe fast lebendig. Bei näherer Betrachtung erschließt sich dem Betrachter, daß sie tatsächlich aus lebenden Pflanzen erstellt ist. So ist der Tisch aus einem eizigen Baum gewachsen, und die Polster bestehen aus weichen Grassoden. Ein wunderschön gemusterter Webteppich mit tausenden naturgetreu eingestickter Blumensarten bedeckt den Boden."); + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im dämonischen Stil"); + set_string(&b->display, + "Diese ganz im dämonischen Stil gehaltene Sitzgruppe ist ganz in dunklen Schwarztönen gehalten. Muster fremdartiger Runen bedecken das merkwürdig geformte Mobiliar, das unangenehm lebendig wirkt."); - b = new_building(bt_generic, r, NULL); - set_string(&b->name, "Séparée im halblingschen Stil"); - set_string(&b->display, "Dieses rustikale Mobiliar ist aus einem einzigen, gewaltigen Baum hergestellt worden. Den Stamm haben fleißige Halblinge der Länge nach gevierteilt und aus den vier langen Viertelstämmen die Sitzbänke geschnitzt, während der verbleibende Stumpf als Tisch dient. Schon von weitem steigen dem Besucher die Gerüche der Köstlichkeiten entgegen, die auf dem Tisch stapeln."); + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im elfischen Stil"); + set_string(&b->display, + "Ganz in Grün- und Brauntönen gehalten wirkt die Sitzgruppe fast lebendig. Bei näherer Betrachtung erschließt sich dem Betrachter, daß sie tatsächlich aus lebenden Pflanzen erstellt ist. So ist der Tisch aus einem eizigen Baum gewachsen, und die Polster bestehen aus weichen Grassoden. Ein wunderschön gemusterter Webteppich mit tausenden naturgetreu eingestickter Blumensarten bedeckt den Boden."); - b = new_building(bt_generic, r, NULL); - set_string(&b->name, "Séparée im orkischen Stil"); - set_string(&b->display, "Grobgeschreinerte, elfenhautbespannte Stühle und ein Tisch aus Knochen, über deren Herkunft man sich lieber keine Gedanken macht, bilden die Sitzgruppe im orkischen Stil. Überall haben Orks ihre Namen, und anderes wenig zitierenswertes in das Holz und Gebein geritzt."); + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im halblingschen Stil"); + set_string(&b->display, + "Dieses rustikale Mobiliar ist aus einem einzigen, gewaltigen Baum hergestellt worden. Den Stamm haben fleißige Halblinge der Länge nach gevierteilt und aus den vier langen Viertelstämmen die Sitzbänke geschnitzt, während der verbleibende Stumpf als Tisch dient. Schon von weitem steigen dem Besucher die Gerüche der Köstlichkeiten entgegen, die auf dem Tisch stapeln."); - b = new_building(bt_generic, r, NULL); - set_string(&b->name, "Séparée im Meermenschenstil"); - set_string(&b->display, "Ganz in Blau- und Grüntönen gehalten, mit Algen und Muscheln verziert wirken die aus altem Meerholz geschnitzten Stühle immer ein wenig feucht. Seltsammerweise hat der schwere aus alten Planken gezimmerte Tisch einen Mast mit kompletten Segel in der Mitte."); + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im orkischen Stil"); + set_string(&b->display, + "Grobgeschreinerte, elfenhautbespannte Stühle und ein Tisch aus Knochen, über deren Herkunft man sich lieber keine Gedanken macht, bilden die Sitzgruppe im orkischen Stil. Überall haben Orks ihre Namen, und anderes wenig zitierenswertes in das Holz und Gebein geritzt."); - b = new_building(bt_generic, r, NULL); - set_string(&b->name, "Séparée im Katzenstil"); - set_string(&b->display, "Die Wände dieses Séparée sind aus dunklem Holz. Was aus der Ferne wie ein chaotisch durchbrochenes Flechtwerk wirkt, entpuppt sich bei näherer Betrachtung als eine bis in winzige Details gestaltete dschungelartige Landschaft, in die eine Vielzahl von kleinen Bildergeschichten eingewoben sind. Wie es scheint hat sich der Künstler Mühe gegeben wirklich jedes Katzenvolk Eresseas zu porträtieren. Das schummrige Innere wird von einem Kamin dominiert, vor dem einige Sessel und weiche Kissen zu einem gemütlichen Nickerchen einladen. Feiner Anduner Sisal bezieht die Lehnen der Sessel und verlockt dazu, seine Krallen hinein zu versenken. Auf einem kleinen Ecktisch steht ein großer Korb mit roten Wollknäulen und grauen und braunen Spielmäusen."); - } else { - for(b=r->buildings; b; b=b->next) { - b->size = b->type->maxsize; - } - } + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im Meermenschenstil"); + set_string(&b->display, + "Ganz in Blau- und Grüntönen gehalten, mit Algen und Muscheln verziert wirken die aus altem Meerholz geschnitzten Stühle immer ein wenig feucht. Seltsammerweise hat der schwere aus alten Planken gezimmerte Tisch einen Mast mit kompletten Segel in der Mitte."); - r = findregion(9524, 9526); - if(!r) { - r = new_region(9524, 9526, 0); - terraform_region(r, terrain_corridor); - r->planep = museum; - rsetname(r, "Nördliche Promenade"); - rsethorses(r, 0); - rsetmoney(r, 0); - rsetpeasants(r, 0); - set_string(&r->display, "Die Nördliche Promenade führt direkt in den naturgeschichtlichen Teil des Museums."); - } - r = findregion(9525, 9524); - if(!r) { - r = new_region(9525, 9524, 0); - terraform_region(r, terrain_corridor); - r->planep = museum; - rsetname(r, "Südliche Promenade"); - rsethorses(r, 0); - rsetmoney(r, 0); - rsetpeasants(r, 0); - set_string(&r->display, "Die Südliche Promenade führt den Besucher in den kulturgeschichtlichen Teil des Museums."); - } + b = new_building(bt_generic, r, NULL); + set_string(&b->name, "Séparée im Katzenstil"); + set_string(&b->display, + "Die Wände dieses Séparée sind aus dunklem Holz. Was aus der Ferne wie ein chaotisch durchbrochenes Flechtwerk wirkt, entpuppt sich bei näherer Betrachtung als eine bis in winzige Details gestaltete dschungelartige Landschaft, in die eine Vielzahl von kleinen Bildergeschichten eingewoben sind. Wie es scheint hat sich der Künstler Mühe gegeben wirklich jedes Katzenvolk Eresseas zu porträtieren. Das schummrige Innere wird von einem Kamin dominiert, vor dem einige Sessel und weiche Kissen zu einem gemütlichen Nickerchen einladen. Feiner Anduner Sisal bezieht die Lehnen der Sessel und verlockt dazu, seine Krallen hinein zu versenken. Auf einem kleinen Ecktisch steht ein großer Korb mit roten Wollknäulen und grauen und braunen Spielmäusen."); + } else { + for (b = r->buildings; b; b = b->next) { + b->size = b->type->maxsize; + } + } + + r = findregion(9524, 9526); + if (!r) { + r = new_region(9524, 9526, 0); + terraform_region(r, terrain_corridor); + r->planep = museum; + rsetname(r, "Nördliche Promenade"); + rsethorses(r, 0); + rsetmoney(r, 0); + rsetpeasants(r, 0); + set_string(&r->display, + "Die Nördliche Promenade führt direkt in den naturgeschichtlichen Teil des Museums."); + } + r = findregion(9525, 9524); + if (!r) { + r = new_region(9525, 9524, 0); + terraform_region(r, terrain_corridor); + r->planep = museum; + rsetname(r, "Südliche Promenade"); + rsethorses(r, 0); + rsetmoney(r, 0); + rsetpeasants(r, 0); + set_string(&r->display, + "Die Südliche Promenade führt den Besucher in den kulturgeschichtlichen Teil des Museums."); + } #endif } static int -use_museumexitticket(unit *u, const struct item_type *itype, int amount, order * ord) +use_museumexitticket(unit * u, const struct item_type *itype, int amount, + order * ord) { - attrib *a; - region *r; - unit *warden = findunit(atoi36("mwar")); - int unit_cookie; + attrib *a; - unused(amount); + region *r; - /* Prüfen ob in Eingangshalle */ - if(u->region->x != 9525 || u->region->y != 9525) { - cmistake(u, ord, 266, MSG_MAGIC); - return 0; - } + unit *warden = findunit(atoi36("mwar")); - a = a_find(u->attribs, &at_museumexit); assert(a); - r = findregion(a->data.sa[0], a->data.sa[1]); assert(r); - a_remove(&u->attribs, a); + int unit_cookie; - /* Übergebene Gegenstände zurückgeben */ + unused(amount); - a = a_find(u->attribs, &at_museumgivebackcookie); - unit_cookie = a->data.i; - a_remove(&u->attribs, a); + /* Prüfen ob in Eingangshalle */ + if (u->region->x != 9525 || u->region->y != 9525) { + cmistake(u, ord, 266, MSG_MAGIC); + return 0; + } - if (a) { - for(a = a_find(warden->attribs, &at_museumgiveback); a && a->type==&at_museumgiveback; a = a->next) { - if(((museumgiveback *)(a->data.v))->cookie == unit_cookie) break; - } - if (a && a->type==&at_museumgiveback) { - museumgiveback *gb = (museumgiveback *)(a->data.v); - item *it; + a = a_find(u->attribs, &at_museumexit); + assert(a); + r = findregion(a->data.sa[0], a->data.sa[1]); + assert(r); + a_remove(&u->attribs, a); - for (it = gb->items; it; it = it->next) { - i_change(&u->items, it->type, it->number); - } - ADDMSG(&u->faction->msgs, msg_message("museumgiveback", "region unit sender items", r, u, warden, gb->items)); - a_remove(&warden->attribs, a); - } - } + /* Übergebene Gegenstände zurückgeben */ - /* Benutzer zurück teleportieren */ - move_unit(u, r, NULL); + a = a_find(u->attribs, &at_museumgivebackcookie); + unit_cookie = a->data.i; + a_remove(&u->attribs, a); - /* Exitticket abziehen */ - i_change(&u->items, itype, -1); + if (a) { + for (a = a_find(warden->attribs, &at_museumgiveback); + a && a->type == &at_museumgiveback; a = a->next) { + if (((museumgiveback *) (a->data.v))->cookie == unit_cookie) + break; + } + if (a && a->type == &at_museumgiveback) { + museumgiveback *gb = (museumgiveback *) (a->data.v); - return 0; + item *it; + + for (it = gb->items; it; it = it->next) { + i_change(&u->items, it->type, it->number); + } + ADDMSG(&u->faction->msgs, msg_message("museumgiveback", + "region unit sender items", r, u, warden, gb->items)); + a_remove(&warden->attribs, a); + } + } + + /* Benutzer zurück teleportieren */ + move_unit(u, r, NULL); + + /* Exitticket abziehen */ + i_change(&u->items, itype, -1); + + return 0; } static int -use_museumticket(unit *u, const struct item_type *itype, int amount, order * ord) +use_museumticket(unit * u, const struct item_type *itype, int amount, + order * ord) { attrib *a; + region *r = u->region; - plane * pl = rplane(r); + + plane *pl = rplane(r); unused(amount); @@ -353,7 +388,7 @@ use_museumticket(unit *u, const struct item_type *itype, int amount, order * ord cmistake(u, ord, 265, MSG_MAGIC); return 0; } - if(u->number != 1) { + if (u->number != 1) { cmistake(u, ord, 267, MSG_MAGIC); return 0; } @@ -363,7 +398,7 @@ use_museumticket(unit *u, const struct item_type *itype, int amount, order * ord } /* In diesem Attribut merken wir uns, wohin die Einheit zurückgesetzt - * wird, wenn sie das Museum verläßt. */ + * wird, wenn sie das Museum verläßt. */ a = a_add(&u->attribs, a_new(&at_museumexit)); a->data.sa[0] = (short)r->x; @@ -381,16 +416,15 @@ use_museumticket(unit *u, const struct item_type *itype, int amount, order * ord return 0; } -void -register_museum(void) +void register_museum(void) { - at_register(&at_warden); - at_register(&at_museumexit); - at_register(&at_museumgivebackcookie); - at_register(&at_museumgiveback); + at_register(&at_warden); + at_register(&at_museumexit); + at_register(&at_museumgivebackcookie); + at_register(&at_museumgiveback); - register_item_use(use_museumticket, "use_museumticket"); - register_item_use(use_museumexitticket, "use_museumexitticket"); + register_item_use(use_museumticket, "use_museumticket"); + register_item_use(use_museumexitticket, "use_museumexitticket"); } #endif diff --git a/src/modules/museum.h b/src/modules/museum.h index bcf8457ef..1073afcf0 100644 --- a/src/modules/museum.h +++ b/src/modules/museum.h @@ -26,28 +26,27 @@ extern "C" { #error "must define MUSEUM_MODULE to use this module" #endif -extern struct attrib_type at_warden; -extern struct attrib_type at_museumexit; -extern struct attrib_type at_museumgivebackcookie; -extern struct attrib_type at_museumgiveback; + extern struct attrib_type at_warden; + extern struct attrib_type at_museumexit; + extern struct attrib_type at_museumgivebackcookie; + extern struct attrib_type at_museumgiveback; -typedef struct { - int warden_no; - int cookie; -} museumgivebackcookie; + typedef struct { + int warden_no; + int cookie; + } museumgivebackcookie; -typedef struct { - int cookie; - struct item *items; -} museumgiveback; + typedef struct { + int cookie; + struct item *items; + } museumgiveback; -extern void register_museum(void); -extern void create_museum(void); -extern void warden_add_give(struct unit *src, struct unit *u, const struct item_type *itype, int n); + extern void register_museum(void); + extern void create_museum(void); + extern void warden_add_give(struct unit *src, struct unit *u, + const struct item_type *itype, int n); #ifdef __cplusplus } #endif - - #endif diff --git a/src/modules/score.c b/src/modules/score.c index 46b61f418..63d3029b1 100644 --- a/src/modules/score.c +++ b/src/modules/score.c @@ -41,14 +41,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* libc includes */ #include -int -average_score_of_age(int age, int a) +int average_score_of_age(int age, int a) { faction *f; + int sum = 0, count = 0; for (f = factions; f; f = f->next) { - if (!is_monsters(f) && f->race != new_race[RC_TEMPLATE] && f->age <= age + a && f->age >= age - a) { + if (!is_monsters(f) && f->race != new_race[RC_TEMPLATE] && f->age <= age + a + && f->age >= age - a) { sum += f->score; count++; } @@ -60,31 +61,38 @@ average_score_of_age(int age, int a) return sum / count; } -void -score(void) +void score(void) { FILE *scoreFP; + region *r; + faction *fc; + int allscores = 0; + char path[MAX_PATH]; - for (fc = factions; fc; fc = fc->next) fc->score = 0; + for (fc = factions; fc; fc = fc->next) + fc->score = 0; for (r = regions; r; r = r->next) { - unit * u; - building * b; - ship * s; + unit *u; + + building *b; + + ship *s; if (rule_region_owners()) { fc = region_get_owner(r); - if (fc) fc->score += 10; + if (fc) + fc->score += 10; } for (b = r->buildings; b; b = b->next) { u = building_owner(b); - if (u!=NULL) { - faction * fbo = u->faction; + if (u != NULL) { + faction *fbo = u->faction; if (fbo) { fbo->score += b->size * 5; @@ -93,19 +101,24 @@ score(void) } for (s = r->ships; s; s = s->next) { - unit * cap = shipowner(s); + unit *cap = shipowner(s); + if (cap && cap->faction) { cap->faction->score += s->size * 2; } } - - for (u = r->units; u; u = u->next) { - item * itm; - int itemscore = 0; - int i; - faction * f = u->faction; - if (f==NULL || u->race == new_race[RC_SPELL] || u->race == new_race[RC_BIRTHDAYDRAGON]) { + for (u = r->units; u; u = u->next) { + item *itm; + + int itemscore = 0; + + int i; + + faction *f = u->faction; + + if (f == NULL || u->race == new_race[RC_SPELL] + || u->race == new_race[RC_BIRTHDAYDRAGON]) { continue; } @@ -113,28 +126,29 @@ score(void) f->score += (u->race->recruitcost * u->number) / 50; } f->score += get_money(u) / 50; - for (itm=u->items; itm; itm=itm->next) { + for (itm = u->items; itm; itm = itm->next) { itemscore += itm->number * itm->type->score; } f->score += itemscore / 10; - for (i=0;i!=u->skill_size;++i) { - skill * sv = u->skills+i; + for (i = 0; i != u->skill_size; ++i) { + skill *sv = u->skills + i; + switch (sv->id) { - case SK_MAGIC: - f->score += (int)(u->number * pow(sv->level, 4)); - break; - case SK_TACTICS: - f->score += (int)(u->number * pow(sv->level, 3)); - break; - case SK_SPY: - case SK_ALCHEMY: - case SK_HERBALISM: - f->score += (int)(u->number * pow(sv->level, 2.5)); - break; - default: - f->score += (int)(u->number * pow(sv->level, 2.5) / 10); - break; + case SK_MAGIC: + f->score += (int)(u->number * pow(sv->level, 4)); + break; + case SK_TACTICS: + f->score += (int)(u->number * pow(sv->level, 3)); + break; + case SK_SPY: + case SK_ALCHEMY: + case SK_HERBALISM: + f->score += (int)(u->number * pow(sv->level, 2.5)); + break; + default: + f->score += (int)(u->number * pow(sv->level, 2.5) / 10); + break; } } } @@ -154,20 +168,24 @@ score(void) scoreFP = fopen(path, "w"); if (scoreFP) { const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; - faction * f; + faction *f; + fwrite(utf8_bom, 1, 3, scoreFP); - for (f = factions; f; f = f->next) if (f->num_total != 0) { - fprintf(scoreFP, "%8d (%8d/%4.2f%%/%5.2f) %30.30s (%3.3s) %5s (%3d)\n", - f->score, f->score - average_score_of_age(f->age, f->age / 24 + 1), - ((float) f->score / (float) allscores) * 100.0, - (float) f->score / f->num_total, - f->name, LOC(default_locale, rc_name(f->race, 0)), factionid(f), f->age); - } + for (f = factions; f; f = f->next) + if (f->num_total != 0) { + fprintf(scoreFP, "%8d (%8d/%4.2f%%/%5.2f) %30.30s (%3.3s) %5s (%3d)\n", + f->score, f->score - average_score_of_age(f->age, f->age / 24 + 1), + ((float)f->score / (float)allscores) * 100.0, + (float)f->score / f->num_total, + f->name, LOC(default_locale, rc_name(f->race, 0)), factionid(f), + f->age); + } fclose(scoreFP); } - if (alliances!=NULL) { + if (alliances != NULL) { alliance *a; - const item_type * token = it_find("conquesttoken"); + + const item_type *token = it_find("conquesttoken"); sprintf(path, "%s/score.alliances", basepath()); scoreFP = fopen(path, "w"); @@ -179,29 +197,35 @@ score(void) for (a = alliances; a; a = a->next) { int alliance_score = 0, alliance_number = 0, alliance_factions = 0; + int grails = 0; - faction * f; + + faction *f; for (f = factions; f; f = f->next) { if (f->alliance && f->alliance == a) { alliance_factions++; - alliance_score += f->score; + alliance_score += f->score; alliance_number += f->num_total; - if (token!=NULL) { - unit * u = f->units; - while (u!=NULL) { - item ** iitem = i_find(&u->items, token); - if (iitem!=NULL && *iitem!=NULL) { + if (token != NULL) { + unit *u = f->units; + + while (u != NULL) { + item **iitem = i_find(&u->items, token); + + if (iitem != NULL && *iitem != NULL) { grails += (*iitem)->number; } - u=u->nextF; + u = u->nextF; } } } } - fprintf(scoreFP, "%d:%d:%d:%d", a->id, alliance_factions, alliance_number, alliance_score); - if (token!=NULL) fprintf(scoreFP, ":%d", grails); + fprintf(scoreFP, "%d:%d:%d:%d", a->id, alliance_factions, + alliance_number, alliance_score); + if (token != NULL) + fprintf(scoreFP, ":%d", grails); fputc('\n', scoreFP); } fclose(scoreFP); diff --git a/src/modules/score.h b/src/modules/score.h index 335afc23d..d63542aa3 100644 --- a/src/modules/score.h +++ b/src/modules/score.h @@ -27,8 +27,8 @@ extern "C" { #endif -extern void score(void); -extern int average_score_of_age(int age, int a); + extern void score(void); + extern int average_score_of_age(int age, int a); #ifdef __cplusplus } diff --git a/src/modules/weather.c b/src/modules/weather.c index 03b5b035c..4c998c456 100644 --- a/src/modules/weather.c +++ b/src/modules/weather.c @@ -25,40 +25,36 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* libc includes */ #include -weather * -create_weather(region *r, weather_t type) - +weather *create_weather(region * r, weather_t type) { - weather *w; + weather *w; - w = calloc(1, sizeof(weather)); - w->center[0] = r->x; - w->center[1] = r->y; - w->type = type; - w->move[0] = (rng_int()%3) - 1; - w->move[1] = (rng_int()%3) - 1; + w = calloc(1, sizeof(weather)); + w->center[0] = r->x; + w->center[1] = r->y; + w->type = type; + w->move[0] = (rng_int() % 3) - 1; + w->move[1] = (rng_int() % 3) - 1; - switch(type) { - case WEATHER_STORM: - w->radius = rng_int()%2+1; - break; - case WEATHER_HURRICANE: - w->radius = 1; - break; - default: - w->radius = 0; - } + switch (type) { + case WEATHER_STORM: + w->radius = rng_int() % 2 + 1; + break; + case WEATHER_HURRICANE: + w->radius = 1; + break; + default: + w->radius = 0; + } - addlist(&weathers, w); + addlist(&weathers, w); - return w; + return w; } -double -distance(int x1, int y1, int x2, int y2) - +double distance(int x1, int y1, int x2, int y2) { - return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); + return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); } /* Diese Funktion ermittelt für jede Region, welches Wetter in ihr @@ -76,66 +72,66 @@ distance(int x1, int y1, int x2, int y2) Diese Routine ist sehr rechenaufwendig! */ -void -set_weather(void) - +void set_weather(void) { - weather_t i; - weather *w; - short x, y; - int d; - region *r; + weather_t i; - for(r=regions;r;r=r->next) { - r->weathertype = WEATHER_NONE; - } + weather *w; - for(i = 0; i < MAXWEATHERS; i++) { - for(w = weathers; w; w = w->next) { - if(w->type == i) { - for(x=w->center[0]-w->radius; x<=w->center[0]+w->radius; x++) { - for(y=w->center[1]-w->radius; y<=w->center[1]+w->radius; y++) { - d = distance(w->center[0], w->center[1], x, y); - if(floor(d+0.5) <= w->radius) { - r = findregion(x,y); - if(r) { - r->weathertype = w->type; - } - } - } - } - } - } - } + short x, y; + + int d; + + region *r; + + for (r = regions; r; r = r->next) { + r->weathertype = WEATHER_NONE; + } + + for (i = 0; i < MAXWEATHERS; i++) { + for (w = weathers; w; w = w->next) { + if (w->type == i) { + for (x = w->center[0] - w->radius; x <= w->center[0] + w->radius; x++) { + for (y = w->center[1] - w->radius; y <= w->center[1] + w->radius; y++) { + d = distance(w->center[0], w->center[1], x, y); + if (floor(d + 0.5) <= w->radius) { + r = findregion(x, y); + if (r) { + r->weathertype = w->type; + } + } + } + } + } + } + } } -void -move_weather(void) - +void move_weather(void) { - weather *w, *wnext; - region *r; + weather *w, *wnext; - for(w = weathers; w;) { - wnext = w->next; - w->center[0] = w->center[0] + w->move[0]; - w->center[1] = w->center[1] + w->move[1]; - r = findregion(w->center[0], w->center[1]); - if(!r || rng_int()%100 < 5) { - removelist(&weathers, w); - } - w = wnext; - } + region *r; + + for (w = weathers; w;) { + wnext = w->next; + w->center[0] = w->center[0] + w->move[0]; + w->center[1] = w->center[1] + w->move[1]; + r = findregion(w->center[0], w->center[1]); + if (!r || rng_int() % 100 < 5) { + removelist(&weathers, w); + } + w = wnext; + } } #else #include -static const char* copyright = "(c) Eressea PBEM 2000"; +static const char *copyright = "(c) Eressea PBEM 2000"; -void -init_weather(void) +void init_weather(void) { - fputs(copyright, stderr); - /* TODO: Initialization */ + fputs(copyright, stderr); + /* TODO: Initialization */ } #endif diff --git a/src/modules/weather.h b/src/modules/weather.h index 6ec87dd14..b991dbaf9 100644 --- a/src/modules/weather.h +++ b/src/modules/weather.h @@ -26,27 +26,27 @@ extern "C" { # error "the weather system is disabled" #endif -enum { - WEATHER_NONE, - WEATHER_STORM, - WEATHER_HURRICANE, - MAXWEATHERS -}; + enum { + WEATHER_NONE, + WEATHER_STORM, + WEATHER_HURRICANE, + MAXWEATHERS + }; -typedef unsigned char weather_t; + typedef unsigned char weather_t; -typedef struct weather { - struct weather *next; - weather_t type; /* Typ der Wetterzone */ - int center[2]; /* Koordinaten des Zentrums */ - int radius; - int move[2]; -} weather; + typedef struct weather { + struct weather *next; + weather_t type; /* Typ der Wetterzone */ + int center[2]; /* Koordinaten des Zentrums */ + int radius; + int move[2]; + } weather; -weather *weathers; + weather *weathers; -void set_weather(void); -void move_weather(void); + void set_weather(void); + void move_weather(void); #ifdef __cplusplus } diff --git a/src/modules/wormhole.c b/src/modules/wormhole.c index 0f0062398..091a1388f 100644 --- a/src/modules/wormhole.c +++ b/src/modules/wormhole.c @@ -36,59 +36,63 @@ #include #include -static boolean -good_region(const region * r) +static boolean good_region(const region * r) { - return (!fval(r, RF_CHAOTIC) && r->age>30 && rplane(r)==NULL && r->units!=NULL && r->land!=NULL); + return (!fval(r, RF_CHAOTIC) && r->age > 30 && rplane(r) == NULL + && r->units != NULL && r->land != NULL); } -static int -cmp_age(const void * v1, const void *v2) +static int cmp_age(const void *v1, const void *v2) { - const region * r1 = (const region*)v1; - const region * r2 = (const region*)v2; - if (r1->ageage) return -1; - if (r1->age>r2->age) return 1; + const region *r1 = (const region *)v1; + + const region *r2 = (const region *)v2; + + if (r1->age < r2->age) + return -1; + if (r1->age > r2->age) + return 1; return 0; } typedef struct wormhole_data { - building * entry; - region * exit; + building *entry; + region *exit; } wormhole_data; -static void -wormhole_init(struct attrib *a) +static void wormhole_init(struct attrib *a) { a->data.v = calloc(1, sizeof(wormhole_data)); } -static void -wormhole_done(struct attrib * a) +static void wormhole_done(struct attrib *a) { free(a->data.v); } -static int -wormhole_age(struct attrib * a) +static int wormhole_age(struct attrib *a) { - wormhole_data * data = (wormhole_data*)a->data.v; - int maxtransport = data->entry->size; - region * r = data->entry->region; - unit * u = r->units; + wormhole_data *data = (wormhole_data *) a->data.v; - for (;u!=NULL && maxtransport!=0;u=u->next) { - if (u->building==data->entry) { - message * m = NULL; - if (u->number>maxtransport || has_limited_skills(u)) { + int maxtransport = data->entry->size; + + region *r = data->entry->region; + + unit *u = r->units; + + for (; u != NULL && maxtransport != 0; u = u->next) { + if (u->building == data->entry) { + message *m = NULL; + + if (u->number > maxtransport || has_limited_skills(u)) { m = msg_message("wormhole_requirements", "unit region", u, u->region); - } else if (data->exit!=NULL) { + } else if (data->exit != NULL) { move_unit(u, data->exit, NULL); maxtransport -= u->number; m = msg_message("wormhole_exit", "unit region", u, data->exit); add_message(&data->exit->msgs, m); } - if (m!=NULL) { + if (m != NULL) { add_message(&u->faction->msgs, m); msg_release(m); } @@ -103,19 +107,21 @@ wormhole_age(struct attrib * a) } static void -wormhole_write(const struct attrib * a, const void * owner, struct storage * store) +wormhole_write(const struct attrib *a, const void *owner, struct storage *store) { - wormhole_data * data = (wormhole_data*)a->data.v; + wormhole_data *data = (wormhole_data *) a->data.v; + write_building_reference(data->entry, store); write_region_reference(data->exit, store); } /** conversion code, turn 573, 2008-05-23 */ -static int -resolve_exit(variant id, void * address) +static int resolve_exit(variant id, void *address) { - building * b = findbuilding(id.i); - region ** rp = address; + building *b = findbuilding(id.i); + + region **rp = address; + if (b) { *rp = b->region; return 0; @@ -124,16 +130,22 @@ resolve_exit(variant id, void * address) return -1; } -static int -wormhole_read(struct attrib * a, void * owner, struct storage * store) +static int wormhole_read(struct attrib *a, void *owner, struct storage *store) { - wormhole_data * data = (wormhole_data*)a->data.v; - resolve_fun resolver = (store->versionversiondata.v; - int rb = read_reference(&data->entry, store, read_building_reference, resolve_building); + resolve_fun resolver = + (store->version < UIDHASH_VERSION) ? resolve_exit : resolve_region_id; + read_fun reader = + (store->version < + UIDHASH_VERSION) ? read_building_reference : read_region_reference; + + int rb = + read_reference(&data->entry, store, read_building_reference, + resolve_building); int rr = read_reference(&data->exit, store, reader, resolver); - if (rb==0 && rr==0) { + + if (rb == 0 && rr == 0) { if (!data->exit || !data->entry) { return AT_READ_FAIL; } @@ -154,12 +166,18 @@ static attrib_type at_wormhole = { static void make_wormhole(const building_type * bt_wormhole, region * r1, region * r2) { - building * b1 = new_building(bt_wormhole, r1, default_locale); - building * b2 = new_building(bt_wormhole, r2, default_locale); - attrib * a1 = a_add(&b1->attribs, a_new(&at_wormhole)); - attrib * a2 = a_add(&b2->attribs, a_new(&at_wormhole)); - wormhole_data * d1 = (wormhole_data*)a1->data.v; - wormhole_data * d2 = (wormhole_data*)a2->data.v; + building *b1 = new_building(bt_wormhole, r1, default_locale); + + building *b2 = new_building(bt_wormhole, r2, default_locale); + + attrib *a1 = a_add(&b1->attribs, a_new(&at_wormhole)); + + attrib *a2 = a_add(&b2->attribs, a_new(&at_wormhole)); + + wormhole_data *d1 = (wormhole_data *) a1->data.v; + + wormhole_data *d2 = (wormhole_data *) a2->data.v; + d1->entry = b1; d2->entry = b2; d1->exit = b2->region; @@ -170,39 +188,46 @@ make_wormhole(const building_type * bt_wormhole, region * r1, region * r2) ADDMSG(&r2->msgs, msg_message("wormhole_appear", "region", r2)); } -void -create_wormholes(void) +void create_wormholes(void) { #define WORMHOLE_CHANCE 10000 - const building_type * bt_wormhole = bt_find("wormhole"); - region_list *rptr, * rlist = NULL; - region * r = regions; - int i = 0, count = 0; - region ** match; + const building_type *bt_wormhole = bt_find("wormhole"); - if (bt_wormhole==NULL) return; + region_list *rptr, *rlist = NULL; + + region *r = regions; + + int i = 0, count = 0; + + region **match; + + if (bt_wormhole == NULL) + return; /* * select a list of regions. we'll sort them by age later. */ - while (r!=NULL) { - int next = rng_int() % (2*WORMHOLE_CHANCE); - while (r!=NULL && (next!=0 || !good_region(r))) { + while (r != NULL) { + int next = rng_int() % (2 * WORMHOLE_CHANCE); + + while (r != NULL && (next != 0 || !good_region(r))) { if (good_region(r)) { --next; } - r=r->next; + r = r->next; } - if (r==NULL) break; + if (r == NULL) + break; add_regionlist(&rlist, r); ++count; - r=r->next; + r = r->next; } - if (count<2) return; + if (count < 2) + return; - match = (region**)malloc(sizeof(region*) * count); + match = (region **) malloc(sizeof(region *) * count); rptr = rlist; - while (i!=count) { + while (i != count) { match[i++] = rptr->data; rptr = rptr->next; } @@ -210,13 +235,12 @@ create_wormholes(void) free_regionlist(rlist); count /= 2; - for (i=0;i!=count;++i) { - make_wormhole(bt_wormhole, match[i], match[i+count]); + for (i = 0; i != count; ++i) { + make_wormhole(bt_wormhole, match[i], match[i + count]); } } -void -register_wormholes(void) +void register_wormholes(void) { at_register(&at_wormhole); } diff --git a/src/modules/xecmd.c b/src/modules/xecmd.c index b181766b2..c4166dade 100644 --- a/src/modules/xecmd.c +++ b/src/modules/xecmd.c @@ -40,38 +40,39 @@ #include #include -static void -xe_givelaen(unit *u, struct order * ord) -{ - unit *u2 =getunitg(u->region, u->faction); - - if(!u2) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return; - } - i_change(&u2->items, olditemtype[I_LAEN], 5); -} - -static void -xe_givepotion(unit *u, struct order *ord) -{ - unit *u2 =getunitg(u->region, u->faction); - - if(!u2) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); - return; - } - i_change(&u2->items, it_find("skillpotion"), 1); -} - -static void -xe_giveballon(unit *u, struct order *ord) +static void xe_givelaen(unit * u, struct order *ord) { unit *u2 = getunitg(u->region, u->faction); + + if (!u2) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", + "")); + return; + } + i_change(&u2->items, olditemtype[I_LAEN], 5); +} + +static void xe_givepotion(unit * u, struct order *ord) +{ + unit *u2 = getunitg(u->region, u->faction); + + if (!u2) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", + "")); + return; + } + i_change(&u2->items, it_find("skillpotion"), 1); +} + +static void xe_giveballon(unit * u, struct order *ord) +{ + unit *u2 = getunitg(u->region, u->faction); + ship *sh; if (!u2) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", + "")); return; } @@ -83,8 +84,7 @@ xe_giveballon(unit *u, struct order *ord) fset(u2, UFL_OWNER); } -int -xecmd(unit * u, order * ord) +int xecmd(unit * u, order * ord) { faction *f = u->faction; @@ -92,7 +92,7 @@ xecmd(unit * u, order * ord) if (get_keyword(ord) == K_XE) { init_tokens(ord); skip_token(); - switch(findparam(getstrtoken(),f->locale)) { + switch (findparam(getstrtoken(), f->locale)) { case P_XEPOTION: xe_givepotion(u, ord); break; diff --git a/src/modules/xecmd.h b/src/modules/xecmd.h index a964d38da..cf1beef00 100644 --- a/src/modules/xecmd.h +++ b/src/modules/xecmd.h @@ -17,11 +17,10 @@ extern "C" { #endif #if XECMD_MODULE -int xecmd(struct unit * u, struct order * ord); + int xecmd(struct unit *u, struct order *ord); #endif #ifdef __cplusplus } #endif #endif - diff --git a/src/modules/xmas.c b/src/modules/xmas.c index 01f0b4297..5bf8c779c 100644 --- a/src/modules/xmas.c +++ b/src/modules/xmas.c @@ -34,49 +34,47 @@ /* libc includes */ #include -static int -xmasgate_handle(trigger * t, void * data) +static int xmasgate_handle(trigger * t, void *data) { - return -1; + return -1; } -static void -xmasgate_write(const trigger * t, struct storage * store) +static void xmasgate_write(const trigger * t, struct storage *store) { - building *b = (building *)t->data.v; + building *b = (building *) t->data.v; + store->w_tok(store, itoa36(b->no)); } -static int -xmasgate_read(trigger * t, struct storage * store) +static int xmasgate_read(trigger * t, struct storage *store) { - int bc = read_reference(&t->data.v, store, read_building_reference, resolve_building); - if (bc==0 && !t->data.v) { + int bc = + read_reference(&t->data.v, store, read_building_reference, + resolve_building); + if (bc == 0 && !t->data.v) { return AT_READ_FAIL; } return AT_READ_OK; } struct trigger_type tt_xmasgate = { - "xmasgate", - NULL, - NULL, - xmasgate_handle, - xmasgate_write, - xmasgate_read + "xmasgate", + NULL, + NULL, + xmasgate_handle, + xmasgate_write, + xmasgate_read }; -trigger * -trigger_xmasgate(building * b) +trigger *trigger_xmasgate(building * b) { - trigger * t = t_new(&tt_xmasgate); - t->data.v = b; - return t; + trigger *t = t_new(&tt_xmasgate); + + t->data.v = b; + return t; } -void -register_xmas(void) +void register_xmas(void) { - tt_register(&tt_xmasgate); + tt_register(&tt_xmasgate); } - diff --git a/src/modules/xmas.h b/src/modules/xmas.h index 334ab8b38..8cd6086fe 100644 --- a/src/modules/xmas.h +++ b/src/modules/xmas.h @@ -16,12 +16,12 @@ extern "C" { #endif -struct region; -struct unit; + struct region; + struct unit; -extern struct trigger *trigger_xmasgate(struct building * b); + extern struct trigger *trigger_xmasgate(struct building *b); -extern void register_xmas(void); + extern void register_xmas(void); #ifdef __cplusplus } diff --git a/src/platform.h b/src/platform.h index 96903dde7..7d369273f 100644 --- a/src/platform.h +++ b/src/platform.h @@ -24,7 +24,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # define WIN32_LEAN_AND_MEAN # include # undef MOUSE_MOVED -# define STDIO_CP 1252 /* log.c, convert to console character set */ +# define STDIO_CP 1252 /* log.c, convert to console character set */ # pragma warning (disable: 4201 4214 4514 4115 4711) # pragma warning(disable: 4056) /* warning C4056: overflow in floating point constant arithmetic */ @@ -95,7 +95,7 @@ extern "C" { # define __USE_BSD # endif /* # include */ -# include /* strncasecmp-Prototyp */ +# include /* strncasecmp-Prototyp */ #endif #ifdef _BSD_SOURCE @@ -115,10 +115,11 @@ extern "C" { # define HAVE_ACCESS # define HAVE_STAT typedef struct stat stat_type; + # include # define HAVE_STRDUP # define HAVE_SNPRINTF -#ifdef _POSIX_SOURCE /* MINGW doesn't seem to have these */ +#ifdef _POSIX_SOURCE /* MINGW doesn't seem to have these */ # define HAVE_EXECINFO # define HAVE_SIGACTION # define HAVE_LINK @@ -129,9 +130,9 @@ typedef struct stat stat_type; /* TinyCC */ #ifdef TINYCC # undef HAVE_INLINE -# define INLINE_FUNCTION +# define INLINE_FUNCTION #endif - + /* lcc-win32 */ #ifdef __LCC__ # include @@ -140,6 +141,7 @@ typedef struct stat stat_type; # define HAVE_ACCESS # define HAVE_STAT typedef struct stat stat_type; + # define HAVE_STRICMP # define HAVE_STRNICMP # define HAVE_STRDUP @@ -153,7 +155,7 @@ typedef struct stat stat_type; /* Microsoft Visual C */ #ifdef _MSC_VER -# include /* must be included here so strdup is not redefined */ +# include /* must be included here so strdup is not redefined */ # define R_OK 4 # define HAVE_INLINE # define INLINE_FUNCTION __inline @@ -205,7 +207,7 @@ typedef struct _stat stat_type; #endif #ifndef HAVE_STRDUP -extern char * strdup(const char *s); +extern char *strdup(const char *s); #endif #ifndef HAVE_SLEEP @@ -235,9 +237,9 @@ extern char * strdup(const char *s); # define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif #endif - + #if defined (__GNUC__) -# define unused(a) /* unused: a */ +# define unused(a) /* unused: a */ #elif defined (ghs) || defined (__hpux) || defined (__sgi) || defined (__DECCXX) || defined (__KCC) || defined (__rational__) || defined (__USLC__) || defined (ACE_RM544) # define unused(a) do {/* null */} while (&a == 0) #else /* ghs || __GNUC__ || ..... */ @@ -250,7 +252,7 @@ extern char * strdup(const char *s); #if defined(BOOLEAN) # define boolean BOOLEAN #else - typedef int boolean; /* not bool! wrong size. */ +typedef int boolean; /* not bool! wrong size. */ #endif #ifndef __cplusplus # define false ((boolean)0) @@ -269,4 +271,3 @@ extern char * strdup(const char *s); #define TOLUA_CAST (char*) #endif - diff --git a/src/settings.h b/src/settings.h index c866d648e..3333ec8de 100644 --- a/src/settings.h +++ b/src/settings.h @@ -19,7 +19,7 @@ #define GUARD_DISABLES_RECRUIT 1 #define GUARD_DISABLES_PRODUCTION 1 #define RESOURCE_QUANTITY 0.5 -#define RECRUITFRACTION 40 /* 100/RECRUITFRACTION% */ +#define RECRUITFRACTION 40 /* 100/RECRUITFRACTION% */ #define COMBAT_TURNS 5 #define NEWATSROI 0 @@ -29,13 +29,13 @@ #define BATTLE_KILLS_PEASANTS 20 #define PEASANTLUCK 10 -#define HUNGER_REDUCES_SKILL /* Hunger reduziert den Talentwert - auf die Hälfte */ +#define HUNGER_REDUCES_SKILL /* Hunger reduziert den Talentwert + auf die Hälfte */ -#define ASTRAL_ITEM_RESTRICTIONS /* keine grossen dinge im astralraum */ +#define ASTRAL_ITEM_RESTRICTIONS /* keine grossen dinge im astralraum */ #define NEW_DAEMONHUNGER_RULE #define NEW_COMBATSKILLS_RULE -#define ROW_FACTOR 3 /* factor for combat row advancement rule */ +#define ROW_FACTOR 3 /* factor for combat row advancement rule */ /* optional game components. TODO: These should either be * configuration variables (XML), script extensions (lua), @@ -46,8 +46,8 @@ #define ARENA_MODULE 1 #define XECMD_MODULE 1 #define DUNGEON_MODULE 0 -#define CHANGED_CROSSBOWS 0 /* use the WTF_ARMORPIERCING flag */ -#undef GLOBAL_WARMING /* number of turns before global warming sets in */ +#define CHANGED_CROSSBOWS 0 /* use the WTF_ARMORPIERCING flag */ +#undef GLOBAL_WARMING /* number of turns before global warming sets in */ #define SIMPLE_COMBAT #define SIMPLE_ESCAPE @@ -57,7 +57,7 @@ #elif defined(BINDINGS_TOLUA) # undef BINDINGS_LUABIND #else -# define BINDINGS_TOLUA /* new default */ +# define BINDINGS_TOLUA /* new default */ #endif -#undef REGIONOWNERS /* (WIP) region-owner uses HELP_TRAVEL to control entry to region */ +#undef REGIONOWNERS /* (WIP) region-owner uses HELP_TRAVEL to control entry to region */ diff --git a/src/tests.c b/src/tests.c index ca5497d25..0b338f20b 100644 --- a/src/tests.c +++ b/src/tests.c @@ -7,9 +7,11 @@ #include #include -CuSuite* get_curse_suite(void); -CuSuite* get_market_suite(void); -CuSuite* get_laws_suite(void); +CuSuite *get_curse_suite(void); + +CuSuite *get_market_suite(void); + +CuSuite *get_laws_suite(void); #include #include @@ -21,12 +23,15 @@ CuSuite* get_laws_suite(void); #include #include -int RunAllTests(void) { +int RunAllTests(void) +{ CuString *output = CuStringNew(); - CuSuite* suite = CuSuiteNew(); + + CuSuite *suite = CuSuiteNew(); + int flags = log_flags; - log_flags = LOG_FLUSH|LOG_CPERROR; + log_flags = LOG_FLUSH | LOG_CPERROR; init_resources(); CuSuiteAddSuite(suite, get_base36_suite()); @@ -44,15 +49,18 @@ int RunAllTests(void) { return suite->failCount; } -struct race * test_create_race(const char * name) +struct race *test_create_race(const char *name) { - race * rc = rc_add(rc_new("human")); + race *rc = rc_add(rc_new("human")); + return rc; } -struct region * test_create_region(int x, int y, const struct terrain_type * terrain) +struct region *test_create_region(int x, int y, + const struct terrain_type *terrain) { - region * r = new_region(x, y, NULL, 0); + region *r = new_region(x, y, NULL, 0); + terraform_region(r, terrain); rsettrees(r, 0, 0); rsettrees(r, 1, 0); @@ -62,21 +70,26 @@ struct region * test_create_region(int x, int y, const struct terrain_type * ter return r; } -struct faction * test_create_faction(const struct race * rc) +struct faction *test_create_faction(const struct race *rc) { - faction * f = addfaction("nobody@eressea.de", NULL, rc, default_locale, 0); + faction *f = addfaction("nobody@eressea.de", NULL, rc, default_locale, 0); + return f; } -struct unit * test_create_unit(struct faction * f, struct region * r) +struct unit *test_create_unit(struct faction *f, struct region *r) { - unit * u = create_unit(r, f, 1, f->race, 0, 0, 0); + unit *u = create_unit(r, f, 1, f->race, 0, 0, 0); + return u; } -void test_cleanup(void) { +void test_cleanup(void) +{ global.functions.maintenance = NULL; + global.functions.wage = NULL; + free_gamedata(); } @@ -89,32 +102,40 @@ void test_cleanup(void) { */ void test_create_world(void) { - terrain_type * t_plain, * t_ocean; - region * island[2]; - race * rc_human; + terrain_type *t_plain, *t_ocean; + + region *island[2]; + + race *rc_human; + int i; - building_type * btype; - ship_type * stype; + + building_type *btype; + + ship_type *stype; t_plain = calloc(1, sizeof(terrain_type)); t_plain->_name = strdup("plain"); - t_plain->flags = LAND_REGION|FOREST_REGION|WALK_INTO; + t_plain->flags = LAND_REGION | FOREST_REGION | WALK_INTO; register_terrain(t_plain); t_ocean = calloc(1, sizeof(terrain_type)); t_ocean->_name = strdup("ocean"); - t_ocean->flags = SEA_REGION|SAIL_INTO|SWIM_INTO; + t_ocean->flags = SEA_REGION | SAIL_INTO | SWIM_INTO; register_terrain(t_ocean); island[0] = test_create_region(0, 0, t_plain); island[1] = test_create_region(1, 0, t_plain); - for (i=0;i!=2;++i) { + for (i = 0; i != 2; ++i) { direction_t j; - region * r = island[i]; - for (j=0;j!=MAXDIRECTIONS;++j) { - region * rn = r_connect(r, j); + + region *r = island[i]; + + for (j = 0; j != MAXDIRECTIONS; ++j) { + region *rn = r_connect(r, j); + if (!rn) { - rn = test_create_region(r->x+delta_x[j], r->y+delta_y[j], t_ocean); + rn = test_create_region(r->x + delta_x[j], r->y + delta_y[j], t_ocean); } } } diff --git a/src/tests.h b/src/tests.h index 1bf6a1304..51ee4aecb 100644 --- a/src/tests.h +++ b/src/tests.h @@ -3,15 +3,16 @@ extern "C" { #endif #ifndef DISABLE_TESTS -void test_cleanup(void); + void test_cleanup(void); -struct race * test_create_race(const char * name); -struct region * test_create_region(int x, int y, const struct terrain_type * terrain); -struct faction * test_create_faction(const struct race * rc); -struct unit * test_create_unit(struct faction * f, struct region * r); -void test_create_world(void); + struct race *test_create_race(const char *name); + struct region *test_create_region(int x, int y, + const struct terrain_type *terrain); + struct faction *test_create_faction(const struct race *rc); + struct unit *test_create_unit(struct faction *f, struct region *r); + void test_create_world(void); -int RunAllTests(void); + int RunAllTests(void); #else #define RunAllTests() 0 #endif diff --git a/src/triggers/changefaction.c b/src/triggers/changefaction.c index e704dd241..db44e4b8a 100644 --- a/src/triggers/changefaction.c +++ b/src/triggers/changefaction.c @@ -23,7 +23,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* kernel includes */ #include #include -#include /* FIXME: resolve_faction */ +#include /* FIXME: resolve_faction */ /* util includes */ #include @@ -45,70 +45,69 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ typedef struct changefaction_data { - struct unit * unit; - struct faction * faction; + struct unit *unit; + struct faction *faction; } changefaction_data; -static void -changefaction_init(trigger * t) +static void changefaction_init(trigger * t) { - t->data.v = calloc(sizeof(changefaction_data), 1); + t->data.v = calloc(sizeof(changefaction_data), 1); } -static void -changefaction_free(trigger * t) +static void changefaction_free(trigger * t) { - free(t->data.v); + free(t->data.v); } -static int -changefaction_handle(trigger * t, void * data) +static int changefaction_handle(trigger * t, void *data) { - /* call an event handler on changefaction. - * data.v -> ( variant event, int timer ) - */ - changefaction_data * td = (changefaction_data*)t->data.v; - if (td->unit && td->faction) { - u_setfaction(td->unit, td->faction); - } else { - log_error(("could not perform changefaction::handle()\n")); - } - unused(data); - return 0; + /* call an event handler on changefaction. + * data.v -> ( variant event, int timer ) + */ + changefaction_data *td = (changefaction_data *) t->data.v; + + if (td->unit && td->faction) { + u_setfaction(td->unit, td->faction); + } else { + log_error(("could not perform changefaction::handle()\n")); + } + unused(data); + return 0; } -static void -changefaction_write(const trigger * t, struct storage * store) +static void changefaction_write(const trigger * t, struct storage *store) { - changefaction_data * td = (changefaction_data*)t->data.v; - write_unit_reference(td->unit, store); - write_faction_reference(td->faction, store); + changefaction_data *td = (changefaction_data *) t->data.v; + + write_unit_reference(td->unit, store); + write_faction_reference(td->faction, store); } -static int -changefaction_read(trigger * t, struct storage * store) +static int changefaction_read(trigger * t, struct storage *store) { - changefaction_data * td = (changefaction_data*)t->data.v; + changefaction_data *td = (changefaction_data *) t->data.v; + read_reference(&td->unit, store, read_unit_reference, resolve_unit); read_reference(&td->faction, store, read_faction_reference, resolve_faction); return AT_READ_OK; } trigger_type tt_changefaction = { - "changefaction", - changefaction_init, - changefaction_free, - changefaction_handle, - changefaction_write, - changefaction_read + "changefaction", + changefaction_init, + changefaction_free, + changefaction_handle, + changefaction_write, + changefaction_read }; -trigger * -trigger_changefaction(unit * u, struct faction * f) +trigger *trigger_changefaction(unit * u, struct faction * f) { - trigger * t = t_new(&tt_changefaction); - changefaction_data * td = (changefaction_data*)t->data.v; - td->unit = u; - td->faction = f; - return t; + trigger *t = t_new(&tt_changefaction); + + changefaction_data *td = (changefaction_data *) t->data.v; + + td->unit = u; + td->faction = f; + return t; } diff --git a/src/triggers/changefaction.h b/src/triggers/changefaction.h index dd2a302c5..02039d9f0 100644 --- a/src/triggers/changefaction.h +++ b/src/triggers/changefaction.h @@ -23,15 +23,16 @@ extern "C" { #endif /* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; + struct trigger_type; + struct trigger; -struct unit; -struct faction; + struct unit; + struct faction; -extern struct trigger_type tt_changefaction; + extern struct trigger_type tt_changefaction; -extern struct trigger * trigger_changefaction(struct unit * u, struct faction * f); + extern struct trigger *trigger_changefaction(struct unit *u, + struct faction *f); #ifdef __cplusplus } diff --git a/src/triggers/changerace.c b/src/triggers/changerace.c index db5904d23..b94607761 100644 --- a/src/triggers/changerace.c +++ b/src/triggers/changerace.c @@ -44,75 +44,76 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ typedef struct changerace_data { - struct unit * u; - const struct race * race; - const struct race * irace; + struct unit *u; + const struct race *race; + const struct race *irace; } changerace_data; -static void -changerace_init(trigger * t) +static void changerace_init(trigger * t) { - t->data.v = calloc(sizeof(changerace_data), 1); + t->data.v = calloc(sizeof(changerace_data), 1); } -static void -changerace_free(trigger * t) +static void changerace_free(trigger * t) { - free(t->data.v); + free(t->data.v); } -static int -changerace_handle(trigger * t, void * data) +static int changerace_handle(trigger * t, void *data) { - /* call an event handler on changerace. - * data.v -> ( variant event, int timer ) - */ - changerace_data * td = (changerace_data*)t->data.v; - if (td->u) { - if (td->race!=NULL) td->u->race = td->race; - if (td->irace!=NULL) td->u->irace = td->irace; - } else { - log_error(("could not perform changerace::handle()\n")); - } - unused(data); - return 0; + /* call an event handler on changerace. + * data.v -> ( variant event, int timer ) + */ + changerace_data *td = (changerace_data *) t->data.v; + + if (td->u) { + if (td->race != NULL) + td->u->race = td->race; + if (td->irace != NULL) + td->u->irace = td->irace; + } else { + log_error(("could not perform changerace::handle()\n")); + } + unused(data); + return 0; } -static void -changerace_write(const trigger * t, struct storage * store) +static void changerace_write(const trigger * t, struct storage *store) { - changerace_data * td = (changerace_data*)t->data.v; - write_unit_reference(td->u, store); - write_race_reference(td->race, store); - write_race_reference(td->irace, store); + changerace_data *td = (changerace_data *) t->data.v; + + write_unit_reference(td->u, store); + write_race_reference(td->race, store); + write_race_reference(td->irace, store); } -static int -changerace_read(trigger * t, struct storage * store) +static int changerace_read(trigger * t, struct storage *store) { - changerace_data * td = (changerace_data*)t->data.v; + changerace_data *td = (changerace_data *) t->data.v; + read_reference(&td->u, store, read_unit_reference, resolve_unit); - td->race = (const struct race*)read_race_reference(store).v; - td->irace = (const struct race*)read_race_reference(store).v; + td->race = (const struct race *)read_race_reference(store).v; + td->irace = (const struct race *)read_race_reference(store).v; return AT_READ_OK; } trigger_type tt_changerace = { - "changerace", - changerace_init, - changerace_free, - changerace_handle, - changerace_write, - changerace_read + "changerace", + changerace_init, + changerace_free, + changerace_handle, + changerace_write, + changerace_read }; -trigger * -trigger_changerace(struct unit * u, const struct race * prace, const struct race * irace) +trigger *trigger_changerace(struct unit * u, const struct race * prace, + const struct race * irace) { - trigger * t = t_new(&tt_changerace); - changerace_data * td = (changerace_data*)t->data.v; + trigger *t = t_new(&tt_changerace); - assert(u->race==u_irace(u) || "!changerace-triggers cannot stack!"); + changerace_data *td = (changerace_data *) t->data.v; + + assert(u->race == u_irace(u) || "!changerace-triggers cannot stack!"); td->u = u; td->race = prace; td->irace = irace; diff --git a/src/triggers/changerace.h b/src/triggers/changerace.h index dc2c55111..b04b1a3e1 100644 --- a/src/triggers/changerace.h +++ b/src/triggers/changerace.h @@ -23,13 +23,14 @@ extern "C" { #endif /* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; -struct unit; + struct trigger_type; + struct trigger; + struct unit; -extern struct trigger_type tt_changerace; + extern struct trigger_type tt_changerace; -extern struct trigger * trigger_changerace(struct unit * u, 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 } diff --git a/src/triggers/clonedied.c b/src/triggers/clonedied.c index 98f156afd..1b3f3dc77 100644 --- a/src/triggers/clonedied.c +++ b/src/triggers/clonedied.c @@ -45,51 +45,52 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. It simply removes the clone-attribute from the mage. */ -static int -clonedied_handle(trigger * t, void * data) +static int clonedied_handle(trigger * t, void *data) { - /* destroy the unit */ - unit * u = (unit*)t->data.v; - if (u) { - attrib *a = a_find(u->attribs, &at_clone); - if(a) a_remove(&u->attribs, a); - } else - log_error(("could not perform clonedied::handle()\n")); - unused(data); - return 0; + /* destroy the unit */ + unit *u = (unit *) t->data.v; + + if (u) { + attrib *a = a_find(u->attribs, &at_clone); + + if (a) + a_remove(&u->attribs, a); + } else + log_error(("could not perform clonedied::handle()\n")); + unused(data); + return 0; } -static void -clonedied_write(const trigger * t, struct storage * store) +static void clonedied_write(const trigger * t, struct storage *store) { - unit * u = (unit*)t->data.v; + unit *u = (unit *) t->data.v; + write_unit_reference(u, store); } -static int -clonedied_read(trigger * t, struct storage * store) +static int clonedied_read(trigger * t, struct storage *store) { - int result = read_reference(&t->data.v, store, read_unit_reference, resolve_unit); - if (result==0 && t->data.v==NULL) { + int result = + read_reference(&t->data.v, store, read_unit_reference, resolve_unit); + if (result == 0 && t->data.v == NULL) { return AT_READ_FAIL; } return AT_READ_OK; } trigger_type tt_clonedied = { - "clonedied", - NULL, - NULL, - clonedied_handle, - clonedied_write, - clonedied_read + "clonedied", + NULL, + NULL, + clonedied_handle, + clonedied_write, + clonedied_read }; -trigger * -trigger_clonedied(unit * u) +trigger *trigger_clonedied(unit * u) { - trigger * t = t_new(&tt_clonedied); - t->data.v = (void*)u; - return t; -} + trigger *t = t_new(&tt_clonedied); + t->data.v = (void *)u; + return t; +} diff --git a/src/triggers/clonedied.h b/src/triggers/clonedied.h index 607a1c415..51b846057 100644 --- a/src/triggers/clonedied.h +++ b/src/triggers/clonedied.h @@ -22,13 +22,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -struct trigger_type; -struct trigger; + struct trigger_type; + struct trigger; -struct unit; + struct unit; -extern struct trigger_type tt_clonedied; -extern struct trigger * trigger_clonedied(struct unit * u); + extern struct trigger_type tt_clonedied; + extern struct trigger *trigger_clonedied(struct unit *u); #ifdef __cplusplus } diff --git a/src/triggers/createcurse.c b/src/triggers/createcurse.c index 085b08317..d600d1d21 100644 --- a/src/triggers/createcurse.c +++ b/src/triggers/createcurse.c @@ -45,34 +45,32 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ typedef struct createcurse_data { - struct unit * mage; - struct unit * target; - const curse_type * type; - double vigour; - int duration; - double effect; - int men; + struct unit *mage; + struct unit *target; + const curse_type *type; + double vigour; + int duration; + double effect; + int men; } createcurse_data; -static void -createcurse_init(trigger * t) +static void createcurse_init(trigger * t) { - t->data.v = calloc(sizeof(createcurse_data), 1); + t->data.v = calloc(sizeof(createcurse_data), 1); } -static void -createcurse_free(trigger * t) +static void createcurse_free(trigger * t) { - free(t->data.v); + free(t->data.v); } -static int -createcurse_handle(trigger * t, void * data) +static int createcurse_handle(trigger * t, void *data) { /* call an event handler on createcurse. - * data.v -> ( variant event, int timer ) - */ - createcurse_data * td = (createcurse_data*)t->data.v; + * data.v -> ( variant event, int timer ) + */ + createcurse_data *td = (createcurse_data *) t->data.v; + if (td->mage && td->target && td->mage->number && td->target->number) { create_curse(td->mage, &td->target->attribs, td->type, td->vigour, td->duration, td->effect, td->men); @@ -83,10 +81,10 @@ createcurse_handle(trigger * t, void * data) return 0; } -static void -createcurse_write(const trigger * t, struct storage * store) +static void createcurse_write(const trigger * t, struct storage *store) { - createcurse_data * td = (createcurse_data*)t->data.v; + createcurse_data *td = (createcurse_data *) t->data.v; + write_unit_reference(td->mage, store); write_unit_reference(td->target, store); store->w_tok(store, td->type->cname); @@ -96,20 +94,21 @@ createcurse_write(const trigger * t, struct storage * store) store->w_int(store, td->men); } -static int -createcurse_read(trigger * t, struct storage * store) +static int createcurse_read(trigger * t, struct storage *store) { - createcurse_data * td = (createcurse_data*)t->data.v; + createcurse_data *td = (createcurse_data *) t->data.v; + char zText[128]; read_reference(&td->mage, store, read_unit_reference, resolve_unit); read_reference(&td->target, store, read_unit_reference, resolve_unit); - if (store->versionversion < CURSETYPE_VERSION) { int id1, id2; + id1 = store->r_int(store); id2 = store->r_int(store); - assert(id2==0); + assert(id2 == 0); td->vigour = store->r_flt(store); td->duration = store->r_int(store); td->effect = store->r_int(store); @@ -120,7 +119,7 @@ createcurse_read(trigger * t, struct storage * store) td->type = ct_find(zText); td->vigour = store->r_flt(store); td->duration = store->r_int(store); - if (store->versionversion < CURSEFLOAT_VERSION) { td->effect = (double)store->r_int(store); } else { td->effect = store->r_flt(store); @@ -131,27 +130,27 @@ createcurse_read(trigger * t, struct storage * store) } trigger_type tt_createcurse = { - "createcurse", - createcurse_init, - createcurse_free, - createcurse_handle, - createcurse_write, - createcurse_read + "createcurse", + createcurse_init, + createcurse_free, + createcurse_handle, + createcurse_write, + createcurse_read }; -trigger * -trigger_createcurse(struct unit * mage, struct unit * target, - const curse_type * ct, double vigour, int duration, - double effect, int men) +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); - createcurse_data * td = (createcurse_data*)t->data.v; - td->mage = mage; - td->target = target; - td->type = ct; - td->vigour = vigour; - td->duration = duration; - td->effect = effect; - td->men = men; - return t; + trigger *t = t_new(&tt_createcurse); + + createcurse_data *td = (createcurse_data *) t->data.v; + + td->mage = mage; + td->target = target; + td->type = ct; + td->vigour = vigour; + td->duration = duration; + td->effect = effect; + td->men = men; + return t; } diff --git a/src/triggers/createcurse.h b/src/triggers/createcurse.h index bc3d2e797..eaa3b35e6 100644 --- a/src/triggers/createcurse.h +++ b/src/triggers/createcurse.h @@ -23,16 +23,18 @@ extern "C" { #endif /* all types we use are defined here to reduce dependencies */ -struct curse_type; -struct trigger_type; -struct trigger; -struct region; -struct faction; -struct unit; + struct curse_type; + struct trigger_type; + struct trigger; + struct region; + struct faction; + struct unit; -extern struct trigger_type tt_createcurse; + extern struct trigger_type tt_createcurse; -extern struct trigger * trigger_createcurse(struct unit * mage, struct unit * target, const struct curse_type * ct, double vigour, int duration, double effect, int men); + extern struct trigger *trigger_createcurse(struct unit *mage, + struct unit *target, const struct curse_type *ct, double vigour, + int duration, double effect, int men); #ifdef __cplusplus } diff --git a/src/triggers/createunit.c b/src/triggers/createunit.c index 48610c9d1..4f83cd91e 100644 --- a/src/triggers/createunit.c +++ b/src/triggers/createunit.c @@ -47,61 +47,62 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ typedef struct createunit_data { - struct region * r; - struct faction * f; - const struct race * race; - int number; + struct region *r; + struct faction *f; + const struct race *race; + int number; } createunit_data; -static void -createunit_init(trigger * t) +static void createunit_init(trigger * t) { - t->data.v = calloc(sizeof(createunit_data), 1); + t->data.v = calloc(sizeof(createunit_data), 1); } -static void -createunit_free(trigger * t) +static void createunit_free(trigger * t) { - free(t->data.v); + free(t->data.v); } -static int -createunit_handle(trigger * t, void * data) +static int createunit_handle(trigger * t, void *data) { - /* call an event handler on createunit. - * data.v -> ( variant event, int timer ) - */ - createunit_data * td = (createunit_data*)t->data.v; - if (td->r!=NULL && td->f!=NULL) { - create_unit(td->r, td->f, td->number, td->race, 0, NULL, NULL); - } else { - log_error(("could not perform createunit::handle()\n")); - } - unused(data); - return 0; + /* call an event handler on createunit. + * data.v -> ( variant event, int timer ) + */ + createunit_data *td = (createunit_data *) t->data.v; + + if (td->r != NULL && td->f != NULL) { + create_unit(td->r, td->f, td->number, td->race, 0, NULL, NULL); + } else { + log_error(("could not perform createunit::handle()\n")); + } + unused(data); + return 0; } -static void -createunit_write(const trigger * t, struct storage * store) +static void createunit_write(const trigger * t, struct storage *store) { - createunit_data * td = (createunit_data*)t->data.v; - write_faction_reference(td->f, store); - write_region_reference(td->r, store); - write_race_reference(td->race, store); - store->w_int(store, td->number); + createunit_data *td = (createunit_data *) t->data.v; + + write_faction_reference(td->f, store); + write_region_reference(td->r, store); + write_race_reference(td->race, store); + store->w_int(store, td->number); } -static int -createunit_read(trigger * t, struct storage * store) +static int createunit_read(trigger * t, struct storage *store) { - createunit_data * td = (createunit_data*)t->data.v; + createunit_data *td = (createunit_data *) t->data.v; - int uc = read_reference(&td->f, store, read_faction_reference, resolve_faction); - int rc = read_reference(&td->r, store, read_region_reference, RESOLVE_REGION(store->version)); - td->race = (const struct race*)read_race_reference(store).v; + int uc = + read_reference(&td->f, store, read_faction_reference, resolve_faction); + int rc = + read_reference(&td->r, store, read_region_reference, + RESOLVE_REGION(store->version)); + td->race = (const struct race *)read_race_reference(store).v; - if (uc==0 && rc==0) { - if (!td->f || !td->r) return AT_READ_FAIL; + if (uc == 0 && rc == 0) { + if (!td->f || !td->r) + return AT_READ_FAIL; } td->number = store->r_int(store); @@ -109,22 +110,24 @@ createunit_read(trigger * t, struct storage * store) } trigger_type tt_createunit = { - "createunit", - createunit_init, - createunit_free, - createunit_handle, - createunit_write, - createunit_read + "createunit", + createunit_init, + createunit_free, + createunit_handle, + createunit_write, + createunit_read }; -trigger * -trigger_createunit(region * r, struct faction * f, const struct race * rc, int number) +trigger *trigger_createunit(region * r, struct faction * f, + const struct race * rc, int number) { - trigger * t = t_new(&tt_createunit); - createunit_data * td = (createunit_data*)t->data.v; - td->r = r; - td->f = f; - td->race = rc; - td->number = number; - return t; + trigger *t = t_new(&tt_createunit); + + createunit_data *td = (createunit_data *) t->data.v; + + td->r = r; + td->f = f; + td->race = rc; + td->number = number; + return t; } diff --git a/src/triggers/createunit.h b/src/triggers/createunit.h index 7dd6894f2..bd9d02c71 100644 --- a/src/triggers/createunit.h +++ b/src/triggers/createunit.h @@ -23,15 +23,16 @@ extern "C" { #endif /* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; -struct region; -struct faction; -struct unit; + struct trigger_type; + struct trigger; + struct region; + struct faction; + struct unit; -extern struct trigger_type tt_createunit; + extern struct trigger_type tt_createunit; -extern struct trigger * trigger_createunit(struct region * r, struct faction * f, const struct race * rc, int number); + extern struct trigger *trigger_createunit(struct region *r, struct faction *f, + const struct race *rc, int number); #ifdef __cplusplus } diff --git a/src/triggers/gate.c b/src/triggers/gate.c index ef1344495..ae542a72b 100644 --- a/src/triggers/gate.c +++ b/src/triggers/gate.c @@ -30,88 +30,96 @@ #include typedef struct gate_data { - struct building * gate; - struct region * target; + struct building *gate; + struct region *target; } gate_data; -static int -gate_handle(trigger * t, void * data) +static int gate_handle(trigger * t, void *data) { - /* call an event handler on gate. - * data.v -> ( variant event, int timer ) - */ - gate_data * gd = (gate_data*)t->data.v; - struct building * b = gd->gate; - struct region * r = gd->target; + /* call an event handler on gate. + * data.v -> ( variant event, int timer ) + */ + gate_data *gd = (gate_data *) t->data.v; - if (b && b->region && r) { - unit ** up = &b->region->units; - while (*up) { - unit * u = *up; - if (u->building==b) move_unit(u, r, NULL); - if (*up==u) up = &u->next; - } - } else { - log_error(("could not perform gate::handle()\n")); - return -1; - } - unused(data); - return 0; -} + struct building *b = gd->gate; -static void -gate_write(const trigger * t, struct storage * store) -{ - gate_data * gd = (gate_data*)t->data.v; - building * b = gd->gate; - region * r = gd->target; + struct region *r = gd->target; - write_building_reference(b, store); - write_region_reference(r, store); -} + if (b && b->region && r) { + unit **up = &b->region->units; -static int -gate_read(trigger * t, struct storage * store) -{ - gate_data * gd = (gate_data*)t->data.v; + while (*up) { + unit *u = *up; - int bc = read_reference(&gd->gate, store, read_building_reference, resolve_building); - int rc = read_reference(&gd->target, store, read_region_reference, RESOLVE_REGION(store->version)); - - if (bc==0 && rc==0) { - if (!gd->gate || !gd->target) return AT_READ_FAIL; + if (u->building == b) + move_unit(u, r, NULL); + if (*up == u) + up = &u->next; } - return AT_READ_OK; + } else { + log_error(("could not perform gate::handle()\n")); + return -1; + } + unused(data); + return 0; } -static void -gate_init(trigger * t) +static void gate_write(const trigger * t, struct storage *store) { - t->data.v = calloc(sizeof(gate_data), 1); + gate_data *gd = (gate_data *) t->data.v; + + building *b = gd->gate; + + region *r = gd->target; + + write_building_reference(b, store); + write_region_reference(r, store); } -static void -gate_done(trigger * t) +static int gate_read(trigger * t, struct storage *store) { - free(t->data.v); + gate_data *gd = (gate_data *) t->data.v; + + int bc = + read_reference(&gd->gate, store, read_building_reference, resolve_building); + int rc = + read_reference(&gd->target, store, read_region_reference, + RESOLVE_REGION(store->version)); + + if (bc == 0 && rc == 0) { + if (!gd->gate || !gd->target) + return AT_READ_FAIL; + } + return AT_READ_OK; +} + +static void gate_init(trigger * t) +{ + t->data.v = calloc(sizeof(gate_data), 1); +} + +static void gate_done(trigger * t) +{ + free(t->data.v); } struct trigger_type tt_gate = { - "gate", - gate_init, - gate_done, - gate_handle, - gate_write, - gate_read + "gate", + gate_init, + gate_done, + gate_handle, + gate_write, + gate_read }; -trigger * -trigger_gate(building * b, region * target) +trigger *trigger_gate(building * b, region * target) { - trigger * t = t_new(&tt_gate); - gate_data * td = (gate_data*)t->data.v; - td->gate = b; - td->target = target; - return t; + trigger *t = t_new(&tt_gate); + + gate_data *td = (gate_data *) t->data.v; + + td->gate = b; + td->target = target; + return t; } diff --git a/src/triggers/gate.h b/src/triggers/gate.h index 677118330..6e80effba 100644 --- a/src/triggers/gate.h +++ b/src/triggers/gate.h @@ -17,14 +17,14 @@ extern "C" { #endif /* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; -struct region; -struct building; + struct trigger_type; + struct trigger; + struct region; + struct building; -extern struct trigger_type tt_gate; + extern struct trigger_type tt_gate; -extern struct trigger * trigger_gate(struct building * b, struct region * r); + extern struct trigger *trigger_gate(struct building *b, struct region *r); #ifdef __cplusplus } diff --git a/src/triggers/giveitem.c b/src/triggers/giveitem.c index 53a06f24b..1ccf1b5a3 100644 --- a/src/triggers/giveitem.c +++ b/src/triggers/giveitem.c @@ -42,30 +42,28 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ typedef struct giveitem_data { - struct unit * u; - const struct item_type * itype; - int number; + struct unit *u; + const struct item_type *itype; + int number; } giveitem_data; -static void -giveitem_init(trigger * t) +static void giveitem_init(trigger * t) { - t->data.v = calloc(sizeof(giveitem_data), 1); + t->data.v = calloc(sizeof(giveitem_data), 1); } -static void -giveitem_free(trigger * t) +static void giveitem_free(trigger * t) { - free(t->data.v); + free(t->data.v); } -static int -giveitem_handle(trigger * t, void * data) +static int giveitem_handle(trigger * t, void *data) { /* call an event handler on giveitem. - * data.v -> ( variant event, int timer ) - */ - giveitem_data * td = (giveitem_data*)t->data.v; + * data.v -> ( variant event, int timer ) + */ + giveitem_data *td = (giveitem_data *) t->data.v; + if (td->u && td->u->number) { i_change(&td->u->items, td->itype, td->number); } else { @@ -75,19 +73,19 @@ giveitem_handle(trigger * t, void * data) return 0; } -static void -giveitem_write(const trigger * t, struct storage * store) +static void giveitem_write(const trigger * t, struct storage *store) { - giveitem_data * td = (giveitem_data*)t->data.v; - write_unit_reference(td->u, store); - store->w_int(store, td->number); - store->w_tok(store, td->itype->rtype->_name[0]); + giveitem_data *td = (giveitem_data *) t->data.v; + + write_unit_reference(td->u, store); + store->w_int(store, td->number); + store->w_tok(store, td->itype->rtype->_name[0]); } -static int -giveitem_read(trigger * t, struct storage * store) +static int giveitem_read(trigger * t, struct storage *store) { - giveitem_data * td = (giveitem_data*)t->data.v; + giveitem_data *td = (giveitem_data *) t->data.v; + char zText[128]; int result = read_reference(&td->u, store, read_unit_reference, resolve_unit); @@ -97,28 +95,29 @@ giveitem_read(trigger * t, struct storage * store) td->itype = it_find(zText); assert(td->itype); - if (result==0 && td->u==NULL) { + if (result == 0 && td->u == NULL) { return AT_READ_FAIL; } return AT_READ_OK; } trigger_type tt_giveitem = { - "giveitem", - giveitem_init, - giveitem_free, - giveitem_handle, - giveitem_write, - giveitem_read + "giveitem", + giveitem_init, + giveitem_free, + giveitem_handle, + giveitem_write, + giveitem_read }; -trigger * -trigger_giveitem(unit * u, const item_type * itype, int number) +trigger *trigger_giveitem(unit * u, const item_type * itype, int number) { - trigger * t = t_new(&tt_giveitem); - giveitem_data * td = (giveitem_data*)t->data.v; - td->number = number; - td->u = u; - td->itype = itype; - return t; + trigger *t = t_new(&tt_giveitem); + + giveitem_data *td = (giveitem_data *) t->data.v; + + td->number = number; + td->u = u; + td->itype = itype; + return t; } diff --git a/src/triggers/giveitem.h b/src/triggers/giveitem.h index 048b4a5cd..0bf1f3293 100644 --- a/src/triggers/giveitem.h +++ b/src/triggers/giveitem.h @@ -23,14 +23,15 @@ extern "C" { #endif /* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; -struct unit; -struct item_type; + struct trigger_type; + struct trigger; + struct unit; + struct item_type; -extern struct trigger_type tt_giveitem; + extern struct trigger_type tt_giveitem; -extern struct trigger * trigger_giveitem(struct unit * mage, const struct item_type * itype, int number); + extern struct trigger *trigger_giveitem(struct unit *mage, + const struct item_type *itype, int number); #ifdef __cplusplus } diff --git a/src/triggers/killunit.c b/src/triggers/killunit.c index b1d5a4064..fc7c341a3 100644 --- a/src/triggers/killunit.c +++ b/src/triggers/killunit.c @@ -37,13 +37,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ** killunit **/ -static int -killunit_handle(trigger * t, void * data) +static int killunit_handle(trigger * t, void *data) { /* call an event handler on killunit. - * data.v -> ( variant event, int timer ) - */ - unit * u = (unit*)t->data.v; + * data.v -> ( variant event, int timer ) + */ + unit *u = (unit *) t->data.v; + if (u) { /* we can't remove_unit() here, because that's what's calling us. */ set_number(u, 0); @@ -52,36 +52,36 @@ killunit_handle(trigger * t, void * data) return 0; } -static void -killunit_write(const trigger * t, struct storage * store) +static void killunit_write(const trigger * t, struct storage *store) { - unit * u = (unit*)t->data.v; + unit *u = (unit *) t->data.v; + write_unit_reference(u, store); } -static int -killunit_read(trigger * t, struct storage * store) +static int killunit_read(trigger * t, struct storage *store) { - int result = read_reference(&t->data.v, store, read_unit_reference, resolve_unit); - if (result==0 && t->data.v==NULL) { + int result = + read_reference(&t->data.v, store, read_unit_reference, resolve_unit); + if (result == 0 && t->data.v == NULL) { return AT_READ_FAIL; } return AT_READ_OK; } trigger_type tt_killunit = { - "killunit", - NULL, - NULL, - killunit_handle, - killunit_write, - killunit_read + "killunit", + NULL, + NULL, + killunit_handle, + killunit_write, + killunit_read }; -trigger * -trigger_killunit(unit * u) +trigger *trigger_killunit(unit * u) { - trigger * t = t_new(&tt_killunit); - t->data.v = (void*)u; - return t; + trigger *t = t_new(&tt_killunit); + + t->data.v = (void *)u; + return t; } diff --git a/src/triggers/killunit.h b/src/triggers/killunit.h index f9aa652fa..548e85093 100644 --- a/src/triggers/killunit.h +++ b/src/triggers/killunit.h @@ -22,13 +22,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -struct trigger_type; -struct trigger; + struct trigger_type; + struct trigger; -struct unit; + struct unit; -extern struct trigger_type tt_killunit; -extern struct trigger * trigger_killunit(struct unit * u); + extern struct trigger_type tt_killunit; + extern struct trigger *trigger_killunit(struct unit *u); #ifdef __cplusplus } diff --git a/src/triggers/removecurse.c b/src/triggers/removecurse.c index 0377974cf..4bb2c3426 100644 --- a/src/triggers/removecurse.c +++ b/src/triggers/removecurse.c @@ -41,74 +41,73 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include typedef struct removecurse_data { - curse * curse; - unit * target; + curse *curse; + unit *target; } removecurse_data; -static void -removecurse_init(trigger * t) +static void removecurse_init(trigger * t) { - t->data.v = calloc(sizeof(removecurse_data), 1); + t->data.v = calloc(sizeof(removecurse_data), 1); } -static void -removecurse_free(trigger * t) +static void removecurse_free(trigger * t) { - free(t->data.v); + free(t->data.v); } -static int -removecurse_handle(trigger * t, void * data) +static int removecurse_handle(trigger * t, void *data) { /* call an event handler on removecurse. - * data.v -> ( variant event, int timer ) - */ - removecurse_data * td = (removecurse_data*)t->data.v; + * data.v -> ( variant event, int timer ) + */ + removecurse_data *td = (removecurse_data *) t->data.v; + if (td->curse && td->target) { - attrib * a = a_select(td->target->attribs, td->curse, cmp_curse); + attrib *a = a_select(td->target->attribs, td->curse, cmp_curse); + if (a) { a_remove(&td->target->attribs, a); - } - else log_error(("could not perform removecurse::handle()\n")); + } else + log_error(("could not perform removecurse::handle()\n")); } unused(data); return 0; } -static void -removecurse_write(const trigger * t, struct storage * store) +static void removecurse_write(const trigger * t, struct storage *store) { - removecurse_data * td = (removecurse_data*)t->data.v; - store->w_tok(store, td->target?itoa36(td->target->no):0); - store->w_int(store, td->curse?td->curse->no:0); + removecurse_data *td = (removecurse_data *) t->data.v; + + store->w_tok(store, td->target ? itoa36(td->target->no) : 0); + store->w_int(store, td->curse ? td->curse->no : 0); } -static int -removecurse_read(trigger * t, struct storage * store) +static int removecurse_read(trigger * t, struct storage *store) { - removecurse_data * td = (removecurse_data*)t->data.v; + removecurse_data *td = (removecurse_data *) t->data.v; read_reference(&td->target, store, read_unit_reference, resolve_unit); read_reference(&td->curse, store, read_int, resolve_curse); - + return AT_READ_OK; } trigger_type tt_removecurse = { - "removecurse", - removecurse_init, - removecurse_free, - removecurse_handle, - removecurse_write, - removecurse_read + "removecurse", + removecurse_init, + removecurse_free, + removecurse_handle, + removecurse_write, + removecurse_read }; -trigger * -trigger_removecurse(curse * c, unit * target) +trigger *trigger_removecurse(curse * c, unit * target) { - trigger * t = t_new(&tt_removecurse); - removecurse_data * td = (removecurse_data*)t->data.v; - td->curse = c; - td->target = target; - return t; + trigger *t = t_new(&tt_removecurse); + + removecurse_data *td = (removecurse_data *) t->data.v; + + td->curse = c; + td->target = target; + return t; } diff --git a/src/triggers/removecurse.h b/src/triggers/removecurse.h index 0a89a5e97..e531d65a6 100644 --- a/src/triggers/removecurse.h +++ b/src/triggers/removecurse.h @@ -23,15 +23,16 @@ extern "C" { #endif /* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; + struct trigger_type; + struct trigger; -struct unit; -struct curse; + struct unit; + struct curse; -extern struct trigger_type tt_removecurse; + extern struct trigger_type tt_removecurse; -extern struct trigger * trigger_removecurse(struct curse * c, struct unit * target); + extern struct trigger *trigger_removecurse(struct curse *c, + struct unit *target); #ifdef __cplusplus } diff --git a/src/triggers/shock.c b/src/triggers/shock.c index 4cb361478..bb5a7b578 100644 --- a/src/triggers/shock.c +++ b/src/triggers/shock.c @@ -52,48 +52,51 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* Vertrauten. */ /* ------------------------------------------------------------- */ -static void -do_shock(unit *u, const char *reason) +static void do_shock(unit * u, const char *reason) { int i; if (u->number > 0) { /* HP - Verlust */ - u->hp = (unit_max_hp(u) * u->number)/10; + u->hp = (unit_max_hp(u) * u->number) / 10; u->hp = MAX(1, u->hp); } /* Aura - Verlust */ if (is_mage(u)) { - set_spellpoints(u, max_spellpoints(u->region,u)/10); + set_spellpoints(u, max_spellpoints(u->region, u) / 10); } /* Evt. Talenttageverlust */ - for (i=0;i!=u->skill_size;++i) if (rng_int()%5==0) { - skill * sv = u->skills+i; - int weeks = (sv->level * sv->level - sv->level) / 2; - int change = (weeks+9) / 10; - reduce_skill(u, sv, change); - } + for (i = 0; i != u->skill_size; ++i) + if (rng_int() % 5 == 0) { + skill *sv = u->skills + i; + + int weeks = (sv->level * sv->level - sv->level) / 2; + + int change = (weeks + 9) / 10; + + reduce_skill(u, sv, change); + } /* Dies ist ein Hack, um das skillmod und familiar-Attribut beim Mage - * zu löschen wenn der Familiar getötet wird. Da sollten wir über eine - * saubere Implementation nachdenken. */ + * zu löschen wenn der Familiar getötet wird. Da sollten wir über eine + * saubere Implementation nachdenken. */ - if (strcmp(reason, "trigger")==0) { + if (strcmp(reason, "trigger") == 0) { remove_familiar(u); } - if (u->faction!=NULL) { + if (u->faction != NULL) { ADDMSG(&u->faction->msgs, msg_message("shock", - "mage reason", u, strdup(reason))); + "mage reason", u, strdup(reason))); } } -static int -shock_handle(trigger * t, void * data) +static int shock_handle(trigger * t, void *data) { /* destroy the unit */ - unit * u = (unit*)t->data.v; + unit *u = (unit *) t->data.v; + if (u && u->number) { do_shock(u, "trigger"); } @@ -101,48 +104,50 @@ shock_handle(trigger * t, void * data) return 0; } -static void -shock_write(const trigger * t, struct storage * store) +static void shock_write(const trigger * t, struct storage *store) { - unit * u = (unit*)t->data.v; - trigger * next = t->next; + unit *u = (unit *) t->data.v; + + trigger *next = t->next; + while (next) { /* make sure it is unique! */ - if (next->type==t->type && next->data.v==t->data.v) break; - next=next->next; + if (next->type == t->type && next->data.v == t->data.v) + break; + next = next->next; } if (next && u) { log_error(("more than one shock-attribut for %s on a unit. FIXED.\n", - unitid(u))); + unitid(u))); write_unit_reference(NULL, store); } else { write_unit_reference(u, store); } } -static int -shock_read(trigger * t, struct storage * store) +static int shock_read(trigger * t, struct storage *store) { - int result = read_reference(&t->data.v, store, read_unit_reference, resolve_unit); - if (result==0 && t->data.v==NULL) { + int result = + read_reference(&t->data.v, store, read_unit_reference, resolve_unit); + if (result == 0 && t->data.v == NULL) { return AT_READ_FAIL; } return AT_READ_OK; } trigger_type tt_shock = { - "shock", - NULL, - NULL, - shock_handle, - shock_write, - shock_read + "shock", + NULL, + NULL, + shock_handle, + shock_write, + shock_read }; -trigger * -trigger_shock(unit * u) +trigger *trigger_shock(unit * u) { - trigger * t = t_new(&tt_shock); - t->data.v = (void*)u; - return t; + trigger *t = t_new(&tt_shock); + + t->data.v = (void *)u; + return t; } diff --git a/src/triggers/shock.h b/src/triggers/shock.h index 07e59cb30..2c0e4fb27 100644 --- a/src/triggers/shock.h +++ b/src/triggers/shock.h @@ -22,13 +22,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -struct trigger_type; -struct trigger; + struct trigger_type; + struct trigger; -struct unit; + struct unit; -extern struct trigger_type tt_shock; -extern struct trigger * trigger_shock(struct unit * u); + extern struct trigger_type tt_shock; + extern struct trigger *trigger_shock(struct unit *u); #ifdef __cplusplus } diff --git a/src/triggers/timeout.c b/src/triggers/timeout.c index e0770ed39..e764b6002 100644 --- a/src/triggers/timeout.c +++ b/src/triggers/timeout.c @@ -33,33 +33,32 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ typedef struct timeout_data { - trigger * triggers; + trigger *triggers; int timer; variant trigger_data; } timeout_data; -static void -timeout_init(trigger * t) +static void timeout_init(trigger * t) { t->data.v = calloc(sizeof(timeout_data), 1); } -static void -timeout_free(trigger * t) +static void timeout_free(trigger * t) { - timeout_data * td = (timeout_data*)t->data.v; + timeout_data *td = (timeout_data *) t->data.v; + free_triggers(td->triggers); free(t->data.v); } -static int -timeout_handle(trigger * t, void * data) +static int timeout_handle(trigger * t, void *data) { /* call an event handler on timeout. * data.v -> ( variant event, int timer ) */ - timeout_data * td = (timeout_data*)t->data.v; - if (--td->timer==0) { + timeout_data *td = (timeout_data *) t->data.v; + + if (--td->timer == 0) { handle_triggers(&td->triggers, NULL); return -1; } @@ -67,29 +66,32 @@ timeout_handle(trigger * t, void * data) return 0; } -static void -timeout_write(const trigger * t, struct storage * store) +static void timeout_write(const trigger * t, struct storage *store) { - timeout_data * td = (timeout_data*)t->data.v; + timeout_data *td = (timeout_data *) t->data.v; + store->w_int(store, td->timer); write_triggers(store, td->triggers); } -static int -timeout_read(trigger * t, struct storage * store) +static int timeout_read(trigger * t, struct storage *store) { - timeout_data * td = (timeout_data*)t->data.v; + timeout_data *td = (timeout_data *) t->data.v; + td->timer = store->r_int(store); read_triggers(store, &td->triggers); - if (td->timer>20) { - trigger * tr = td->triggers; - log_warning(("there is a timeout lasting for another %d turns\n", td->timer)); + if (td->timer > 20) { + trigger *tr = td->triggers; + + log_warning(("there is a timeout lasting for another %d turns\n", + td->timer)); while (tr) { log_warning((" timeout triggers: %s\n", tr->type->name)); tr = tr->next; } } - if (td->triggers!=NULL && td->timer>0) return AT_READ_OK; + if (td->triggers != NULL && td->timer > 0) + return AT_READ_OK; return AT_READ_FAIL; } @@ -102,11 +104,12 @@ trigger_type tt_timeout = { timeout_read }; -trigger * -trigger_timeout(int time, trigger * callbacks) +trigger *trigger_timeout(int time, trigger * callbacks) { - trigger * t = t_new(&tt_timeout); - timeout_data * td = (timeout_data*)t->data.v; + trigger *t = t_new(&tt_timeout); + + timeout_data *td = (timeout_data *) t->data.v; + td->triggers = callbacks; td->timer = time; return t; diff --git a/src/triggers/timeout.h b/src/triggers/timeout.h index 3f9f122ef..4dc7ab07e 100644 --- a/src/triggers/timeout.h +++ b/src/triggers/timeout.h @@ -22,12 +22,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -struct trigger_type; -struct trigger; + struct trigger_type; + struct trigger; -extern struct trigger_type tt_timeout; + extern struct trigger_type tt_timeout; -extern struct trigger * trigger_timeout(int time, struct trigger * callbacks); + extern struct trigger *trigger_timeout(int time, struct trigger *callbacks); #ifdef __cplusplus } diff --git a/src/triggers/triggers.c b/src/triggers/triggers.c index 7df6cffc1..ac9ccca95 100644 --- a/src/triggers/triggers.c +++ b/src/triggers/triggers.c @@ -40,21 +40,21 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* libc includes */ #include -void -register_triggers(void) +void register_triggers(void) { - if (verbosity>=2) printf("- registering triggers\n"); - tt_register(&tt_changefaction); - tt_register(&tt_changerace); - tt_register(&tt_createcurse); - tt_register(&tt_createunit); - tt_register(&tt_gate); - tt_register(&tt_unguard); - tt_register(&tt_giveitem); - tt_register(&tt_killunit); - tt_register(&tt_removecurse); - tt_register(&tt_shock); - tt_register(&tt_unitmessage); - tt_register(&tt_timeout); - tt_register(&tt_clonedied); + if (verbosity >= 2) + printf("- registering triggers\n"); + tt_register(&tt_changefaction); + tt_register(&tt_changerace); + tt_register(&tt_createcurse); + tt_register(&tt_createunit); + tt_register(&tt_gate); + tt_register(&tt_unguard); + tt_register(&tt_giveitem); + tt_register(&tt_killunit); + tt_register(&tt_removecurse); + tt_register(&tt_shock); + tt_register(&tt_unitmessage); + tt_register(&tt_timeout); + tt_register(&tt_clonedied); } diff --git a/src/triggers/triggers.h b/src/triggers/triggers.h index def5f4072..c17f75d71 100644 --- a/src/triggers/triggers.h +++ b/src/triggers/triggers.h @@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -void register_triggers(void); + void register_triggers(void); #ifdef __cplusplus } diff --git a/src/triggers/unguard.c b/src/triggers/unguard.c index 1c4cb42ea..50b6e4ac3 100644 --- a/src/triggers/unguard.c +++ b/src/triggers/unguard.c @@ -28,50 +28,49 @@ /* libc includes */ #include -static int -unguard_handle(trigger * t, void * data) +static int unguard_handle(trigger * t, void *data) { - building * b = (building*)t->data.v; + building *b = (building *) t->data.v; - if (b) { - fset(b, BLD_UNGUARDED); - } else { - log_error(("could not perform unguard::handle()\n")); - return -1; - } - unused(data); - return 0; + if (b) { + fset(b, BLD_UNGUARDED); + } else { + log_error(("could not perform unguard::handle()\n")); + return -1; + } + unused(data); + return 0; } -static void -unguard_write(const trigger * t, struct storage * store) +static void unguard_write(const trigger * t, struct storage *store) { - write_building_reference((building*)t->data.v, store); + write_building_reference((building *) t->data.v, store); } -static int -unguard_read(trigger * t, struct storage * store) +static int unguard_read(trigger * t, struct storage *store) { - int rb = read_reference(&t->data.v, store, read_building_reference, resolve_building); - if (rb==0 && !t->data.v) { + int rb = + read_reference(&t->data.v, store, read_building_reference, + resolve_building); + if (rb == 0 && !t->data.v) { return AT_READ_FAIL; } return AT_READ_OK; } struct trigger_type tt_unguard = { - "building", - NULL, - NULL, - unguard_handle, - unguard_write, - unguard_read + "building", + NULL, + NULL, + unguard_handle, + unguard_write, + unguard_read }; -trigger * -trigger_unguard(building * b) +trigger *trigger_unguard(building * b) { - trigger * t = t_new(&tt_unguard); - t->data.v = (void*)b; - return t; + trigger *t = t_new(&tt_unguard); + + t->data.v = (void *)b; + return t; } diff --git a/src/triggers/unguard.h b/src/triggers/unguard.h index 7748e5a92..691ea761b 100644 --- a/src/triggers/unguard.h +++ b/src/triggers/unguard.h @@ -17,14 +17,14 @@ extern "C" { #endif /* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; -struct region; -struct building; + struct trigger_type; + struct trigger; + struct region; + struct building; -extern struct trigger_type tt_unguard; + extern struct trigger_type tt_unguard; -extern struct trigger * trigger_unguard(struct building * b); + extern struct trigger *trigger_unguard(struct building *b); #ifdef __cplusplus } diff --git a/src/triggers/unitmessage.c b/src/triggers/unitmessage.c index f1d7d7dbf..87add8101 100644 --- a/src/triggers/unitmessage.c +++ b/src/triggers/unitmessage.c @@ -37,65 +37,67 @@ without prior permission by the authors of Eressea. **/ typedef struct unitmessage_data { - struct unit * target; - char * string; + struct unit *target; + char *string; int type; int level; } unitmessage_data; -static void -unitmessage_init(trigger * t) +static void unitmessage_init(trigger * t) { t->data.v = calloc(sizeof(unitmessage_data), 1); } -static void -unitmessage_free(trigger * t) +static void unitmessage_free(trigger * t) { - unitmessage_data * sd = (unitmessage_data*)t->data.v; + unitmessage_data *sd = (unitmessage_data *) t->data.v; + free(sd->string); free(t->data.v); } -static int -unitmessage_handle(trigger * t, void * data) +static int unitmessage_handle(trigger * t, void *data) { /* call an event handler on unitmessage. - * data.v -> ( variant event, int timer ) - */ - unitmessage_data * td = (unitmessage_data*)t->data.v; + * data.v -> ( variant event, int timer ) + */ + unitmessage_data *td = (unitmessage_data *) t->data.v; + if (td->target && td->target->no) { - struct faction * f = td->target->faction; - addmessage(td->target->region, f, LOC(f->locale, td->string), td->type, td->level); + struct faction *f = td->target->faction; + + addmessage(td->target->region, f, LOC(f->locale, td->string), td->type, + td->level); } unused(data); return 0; } -static void -unitmessage_write(const trigger * t, struct storage * store) +static void unitmessage_write(const trigger * t, struct storage *store) { - unitmessage_data * td = (unitmessage_data*)t->data.v; + unitmessage_data *td = (unitmessage_data *) t->data.v; + write_unit_reference(td->target, store); store->w_tok(store, td->string); store->w_int(store, td->type); store->w_int(store, td->level); } -static int -unitmessage_read(trigger * t, struct storage * store) +static int unitmessage_read(trigger * t, struct storage *store) { - unitmessage_data * td = (unitmessage_data*)t->data.v; + unitmessage_data *td = (unitmessage_data *) t->data.v; + char zText[256]; - int result = read_reference(&td->target, store, read_unit_reference, resolve_unit); + int result = + read_reference(&td->target, store, read_unit_reference, resolve_unit); td->string = store->r_tok(store); td->type = store->r_int(store); td->level = store->r_int(store); td->string = strdup(zText); - if (result==0 && td->target==NULL) { + if (result == 0 && td->target == NULL) { return AT_READ_FAIL; } return AT_READ_OK; @@ -110,11 +112,13 @@ trigger_type tt_unitmessage = { unitmessage_read }; -trigger * -trigger_unitmessage(unit * target, const char * string, int type, int level) +trigger *trigger_unitmessage(unit * target, const char *string, int type, + int level) { - trigger * t = t_new(&tt_unitmessage); - unitmessage_data * td = (unitmessage_data*)t->data.v; + trigger *t = t_new(&tt_unitmessage); + + unitmessage_data *td = (unitmessage_data *) t->data.v; + td->target = target; td->string = strdup(string); td->type = type; diff --git a/src/triggers/unitmessage.h b/src/triggers/unitmessage.h index dcc8df47d..054a65b65 100644 --- a/src/triggers/unitmessage.h +++ b/src/triggers/unitmessage.h @@ -23,12 +23,13 @@ extern "C" { #endif /* all types we use are defined here to reduce dependencies */ -struct trigger_type; -struct trigger; -struct unit; + struct trigger_type; + struct trigger; + struct unit; -extern struct trigger_type tt_unitmessage; -extern struct trigger * trigger_unitmessage(struct unit * target, const char * string, int type, int level); + extern struct trigger_type tt_unitmessage; + extern struct trigger *trigger_unitmessage(struct unit *target, + const char *string, int type, int level); #ifdef __cplusplus } diff --git a/src/util/attrib.c b/src/util/attrib.c index 97d3a0d97..f8be18964 100644 --- a/src/util/attrib.c +++ b/src/util/attrib.c @@ -27,32 +27,32 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #define MAXATHASH 61 -attrib_type * at_hash[MAXATHASH]; +attrib_type *at_hash[MAXATHASH]; -static unsigned int -__at_hashkey(const char* s) +static unsigned int __at_hashkey(const char *s) { - int key = 0; - size_t i = strlen(s); + int key = 0; - while (i>0) { - key = (s[--i] + key*37); - } - return key & 0x7fffffff; + size_t i = strlen(s); + + while (i > 0) { + key = (s[--i] + key * 37); + } + return key & 0x7fffffff; } -void -at_register(attrib_type * at) +void at_register(attrib_type * at) { - attrib_type * find; + attrib_type *find; - if (at->read==NULL) { + if (at->read == NULL) { log_warning(("registering non-persistent attribute %s.\n", at->name)); } at->hashkey = __at_hashkey(at->name); find = at_hash[at->hashkey % MAXATHASH]; - while (find && at->hashkey!=find->hashkey) find = find->nexthash; - if (find && find==at) { + while (find && at->hashkey != find->hashkey) + find = find->nexthash; + if (find && find == at) { log_warning(("attribute '%s' was registered more than once\n", at->name)); return; } else { @@ -62,84 +62,90 @@ at_register(attrib_type * at) at_hash[at->hashkey % MAXATHASH] = at; } -static attrib_type * -at_find(unsigned int hk) +static attrib_type *at_find(unsigned int hk) { - const char* translate[3][2] = { - { "zielregion", "targetregion" }, /* remapping: from 'zielregion, heute targetregion */ - { "verzaubert", "curse" }, /* remapping: früher verzaubert, jetzt curse */ - { NULL, NULL } - }; - attrib_type * find = at_hash[hk % MAXATHASH]; - while (find && hk!=find->hashkey) find = find->nexthash; - if (!find) { - int i = 0; - while (translate[i][0]) { - if (__at_hashkey(translate[i][0])==hk) - return at_find(__at_hashkey(translate[i][1])); - ++i; - } - } - return find; + const char *translate[3][2] = { + {"zielregion", "targetregion"}, /* remapping: from 'zielregion, heute targetregion */ + {"verzaubert", "curse"}, /* remapping: früher verzaubert, jetzt curse */ + {NULL, NULL} + }; + attrib_type *find = at_hash[hk % MAXATHASH]; + + while (find && hk != find->hashkey) + find = find->nexthash; + if (!find) { + int i = 0; + + while (translate[i][0]) { + if (__at_hashkey(translate[i][0]) == hk) + return at_find(__at_hashkey(translate[i][1])); + ++i; + } + } + return find; } -attrib * -a_select(attrib * a, const void * data, boolean(*compare)(const attrib *, const void *)) +attrib *a_select(attrib * a, const void *data, + boolean(*compare) (const attrib *, const void *)) { - while (a && !compare(a, data)) a = a->next; - return a; + while (a && !compare(a, data)) + a = a->next; + return a; } -attrib * -a_find(attrib * a, const attrib_type * at) +attrib *a_find(attrib * a, const attrib_type * at) { - while (a && a->type!=at) a = a->nexttype; - return a; + while (a && a->type != at) + a = a->nexttype; + return a; } -const attrib * -a_findc(const attrib * a, const attrib_type * at) +const attrib *a_findc(const attrib * a, const attrib_type * at) { - while (a && a->type!=at) a = a->nexttype; - return a; + while (a && a->type != at) + a = a->nexttype; + return a; } -static attrib * -a_insert(attrib * head, attrib * a) +static attrib *a_insert(attrib * head, attrib * a) { - attrib ** pa=&head->next; + attrib **pa = &head->next; assert(!(a->type->flags & ATF_UNIQUE)); - assert(head && head->type==a->type); + assert(head && head->type == a->type); - while (*pa && (*pa)->type==a->type) { + while (*pa && (*pa)->type == a->type) { pa = &(*pa)->next; } a->next = *pa; return *pa = a; } -attrib * -a_add(attrib ** pa, attrib * a) +attrib *a_add(attrib ** pa, attrib * a) { - attrib * first = *pa; - assert(a->next==NULL && a->nexttype==NULL); + attrib *first = *pa; - if (first==NULL) return *pa = a; - if (first->type==a->type) { + assert(a->next == NULL && a->nexttype == NULL); + + if (first == NULL) + return *pa = a; + if (first->type == a->type) { return a_insert(first, a); } for (;;) { - attrib * next = first->nexttype; - if (next==NULL) { + attrib *next = first->nexttype; + + if (next == NULL) { /* the type is not in the list, append it behind the last type */ - attrib ** insert = &first->next; + attrib **insert = &first->next; + first->nexttype = a; - while (*insert) insert = &(*insert)->next; + while (*insert) + insert = &(*insert)->next; *insert = a; break; } - if (next->type==a->type) { + if (next->type == a->type) { return a_insert(next, a); } first = next; @@ -147,40 +153,45 @@ a_add(attrib ** pa, attrib * a) return a; } -void -a_free(attrib * a) +void a_free(attrib * a) { - const attrib_type * at = a->type; - if (at->finalize) at->finalize(a); - free(a); + const attrib_type *at = a->type; + + if (at->finalize) + at->finalize(a); + free(a); } -static int -a_unlink(attrib ** pa, attrib * a) +static int a_unlink(attrib ** pa, attrib * a) { - attrib ** pnexttype = pa; - attrib ** pnext = NULL; + attrib **pnexttype = pa; - assert(a!=NULL); + attrib **pnext = NULL; + + assert(a != NULL); while (*pnexttype) { - attrib * next = *pnexttype; - if (next->type==a->type) break; + attrib *next = *pnexttype; + + if (next->type == a->type) + break; pnexttype = &next->nexttype; pnext = &next->next; } - if (*pnexttype && (*pnexttype)->type==a->type) { - if (*pnexttype==a) { + if (*pnexttype && (*pnexttype)->type == a->type) { + if (*pnexttype == a) { *pnexttype = a->next; - if (a->next!=a->nexttype) { + if (a->next != a->nexttype) { a->next->nexttype = a->nexttype; } - if (pnext==NULL) return 1; - while (*pnext && (*pnext)->type!=a->type) pnext = &(*pnext)->next; + if (pnext == NULL) + return 1; + while (*pnext && (*pnext)->type != a->type) + pnext = &(*pnext)->next; } else { pnext = &(*pnexttype)->next; } - while (*pnext && (*pnext)->type==a->type) { - if (*pnext==a) { + while (*pnext && (*pnext)->type == a->type) { + if (*pnext == a) { *pnext = a->next; return 1; } @@ -190,96 +201,110 @@ a_unlink(attrib ** pa, attrib * a) return 0; } -int -a_remove(attrib ** pa, attrib * a) +int a_remove(attrib ** pa, attrib * a) { int ok; - assert(a!=NULL); + + assert(a != NULL); ok = a_unlink(pa, a); - if (ok) a_free(a); + if (ok) + a_free(a); return ok; } -void -a_removeall(attrib **pa, const attrib_type * at) +void a_removeall(attrib ** pa, const attrib_type * at) { - attrib ** pnexttype = pa; - attrib ** pnext = NULL; + attrib **pnexttype = pa; + + attrib **pnext = NULL; while (*pnexttype) { - attrib * next = *pnexttype; - if (next->type==at) break; + attrib *next = *pnexttype; + + if (next->type == at) + break; pnexttype = &next->nexttype; pnext = &next->next; } - if (*pnexttype && (*pnexttype)->type==at) { - attrib * a = *pnexttype; + if (*pnexttype && (*pnexttype)->type == at) { + attrib *a = *pnexttype; *pnexttype = a->nexttype; if (pnext) { - while (*pnext && (*pnext)->type!=at) pnext = &(*pnext)->next; + while (*pnext && (*pnext)->type != at) + pnext = &(*pnext)->next; *pnext = a->nexttype; } - while (a && a->type==at) { - attrib * ra = a; + while (a && a->type == at) { + attrib *ra = a; + a = a->next; a_free(ra); } } } -attrib * -a_new(const attrib_type * at) +attrib *a_new(const attrib_type * at) { - attrib * a = (attrib*)calloc(1, sizeof(attrib)); - assert(at!=NULL); - a->type = at; - if (at->initialize) at->initialize(a); - return a; + attrib *a = (attrib *) calloc(1, sizeof(attrib)); + + assert(at != NULL); + a->type = at; + if (at->initialize) + at->initialize(a); + return a; } -int -a_age(attrib ** p) +int a_age(attrib ** p) { - attrib ** ap = p; - /* Attribute altern, und die Entfernung (age()==0) eines Attributs - * hat Einfluß auf den Besitzer */ - while(*ap) { - attrib * a = *ap; - if (a->type->age) { - int result = a->type->age(a); - assert(result>=0 || !"age() returned a negative value"); - if (result==0) { - a_remove(p, a); - continue; - } - } - ap = &a->next; - } - return (*p!=NULL); + attrib **ap = p; + + /* Attribute altern, und die Entfernung (age()==0) eines Attributs + * hat Einfluß auf den Besitzer */ + while (*ap) { + attrib *a = *ap; + + if (a->type->age) { + int result = a->type->age(a); + + assert(result >= 0 || !"age() returned a negative value"); + if (result == 0) { + a_remove(p, a); + continue; + } + } + ap = &a->next; + } + return (*p != NULL); } -int -a_read(struct storage * store, attrib ** attribs, void * owner) +int a_read(struct storage *store, attrib ** attribs, void *owner) { int key, retval = AT_READ_OK; + char zText[128]; + strcpy(zText, "unknown"); key = -1; store->r_tok_buf(store, zText, sizeof(zText)); - if (strcmp(zText, "end")==0) return retval; - else key = __at_hashkey(zText); + if (strcmp(zText, "end") == 0) + return retval; + else + key = __at_hashkey(zText); + + while (key != -1) { + attrib_type *at = at_find(key); - while(key!=-1) { - attrib_type * at = at_find(key); if (!at) { fprintf(stderr, "attribute hash: %d (%s)\n", key, zText); assert(at || !"attribute not registered"); } if (at->read) { - attrib * na = a_new(at); + attrib *na = a_new(at); + int i = at->read(na, owner, store); + switch (i) { case AT_READ_OK: a_add(attribs, na); @@ -297,18 +322,18 @@ a_read(struct storage * store, attrib ** attribs, void * owner) } store->r_tok_buf(store, zText, sizeof(zText)); - if (!strcmp(zText, "end")) break; + if (!strcmp(zText, "end")) + break; key = __at_hashkey(zText); } return retval; } -void -a_write(struct storage * store, const attrib * attribs, const void * owner) +void a_write(struct storage *store, const attrib * attribs, const void *owner) { - const attrib * na = attribs; + const attrib *na = attribs; - while(na) { + while (na) { if (na->type->write) { assert(na->type->hashkey || !"attribute not registered"); store->w_tok(store, na->type->name); diff --git a/src/util/attrib.h b/src/util/attrib.h index f5c6648fb..a2805e8c7 100644 --- a/src/util/attrib.h +++ b/src/util/attrib.h @@ -22,58 +22,60 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -struct storage; -typedef void (*afun)(void); + struct storage; + typedef void (*afun) (void); -typedef struct attrib { - const struct attrib_type * type; - union { - afun f; - void * v; - int i; - float flt; - char c; - short s; - short sa[2]; - char ca[4]; - } data; - /* internal data, do not modify: */ - struct attrib * next; /* next attribute in the list */ - struct attrib * nexttype; /* skip to attribute of a different type */ -} attrib; + typedef struct attrib { + const struct attrib_type *type; + union { + afun f; + void *v; + int i; + float flt; + char c; + short s; + short sa[2]; + char ca[4]; + } data; + /* internal data, do not modify: */ + struct attrib *next; /* next attribute in the list */ + struct attrib *nexttype; /* skip to attribute of a different type */ + } attrib; -#define ATF_UNIQUE (1<<0) /* only one per attribute-list */ -#define ATF_PRESERVE (1<<1) /* preserve order in list. append to back */ +#define ATF_UNIQUE (1<<0) /* only one per attribute-list */ +#define ATF_PRESERVE (1<<1) /* preserve order in list. append to back */ #define ATF_USER_DEFINED (1<<2) /* use this to make udf */ -typedef struct attrib_type { - const char* name; - void (*initialize)(struct attrib *); - void (*finalize)(struct attrib *); - int (*age)(struct attrib *); - /* age returns 0 if the attribute needs to be removed, !=0 otherwise */ - void (*write)(const struct attrib *, const void * owner, struct storage *); - int (*read)(struct attrib *, void * owner, struct storage *); /* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */ - unsigned int flags; - /* ---- internal data, do not modify: ---- */ - struct attrib_type * nexthash; - unsigned int hashkey; -} attrib_type; + typedef struct attrib_type { + const char *name; + void (*initialize) (struct attrib *); + void (*finalize) (struct attrib *); + int (*age) (struct attrib *); + /* age returns 0 if the attribute needs to be removed, !=0 otherwise */ + void (*write) (const struct attrib *, const void *owner, struct storage *); + int (*read) (struct attrib *, void *owner, struct storage *); /* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */ + unsigned int flags; + /* ---- internal data, do not modify: ---- */ + struct attrib_type *nexthash; + unsigned int hashkey; + } attrib_type; -extern void at_register(attrib_type * at); + extern void at_register(attrib_type * at); -extern attrib * a_select(attrib * a, const void * data, boolean(*compare)(const attrib *, const void *)); -extern attrib * a_find(attrib * a, const attrib_type * at); -extern const attrib * a_findc(const attrib * a, const attrib_type * at); -extern attrib * a_add(attrib ** pa, attrib * at); -extern int a_remove(attrib ** pa, attrib * at); -extern void a_removeall(attrib ** a, const attrib_type * at); -extern attrib * a_new(const attrib_type * at); -extern void a_free(attrib * a); + extern attrib *a_select(attrib * a, const void *data, + boolean(*compare) (const attrib *, const void *)); + extern attrib *a_find(attrib * a, const attrib_type * at); + extern const attrib *a_findc(const attrib * a, const attrib_type * at); + extern attrib *a_add(attrib ** pa, attrib * at); + extern int a_remove(attrib ** pa, attrib * at); + extern void a_removeall(attrib ** a, const attrib_type * at); + extern attrib *a_new(const attrib_type * at); + extern void a_free(attrib * a); -extern int a_age(attrib ** attribs); -extern int a_read(struct storage * store, attrib ** attribs, void * owner); -extern void a_write(struct storage * store, const attrib * attribs, const void * owner); + extern int a_age(attrib ** attribs); + extern int a_read(struct storage *store, attrib ** attribs, void *owner); + extern void a_write(struct storage *store, const attrib * attribs, + const void *owner); #define DEFAULT_AGE NULL #define DEFAULT_INIT NULL @@ -84,8 +86,8 @@ extern void a_write(struct storage * store, const attrib * attribs, const void * #define AT_READ_OK 0 #define AT_READ_FAIL -1 -#define AT_AGE_REMOVE 0 /* remove the attribute after calling age() */ -#define AT_AGE_KEEP 1 /* keep the attribute for another turn */ +#define AT_AGE_REMOVE 0 /* remove the attribute after calling age() */ +#define AT_AGE_KEEP 1 /* keep the attribute for another turn */ #ifdef __cplusplus } diff --git a/src/util/base36.c b/src/util/base36.c index 149d42e24..2f5bffebd 100644 --- a/src/util/base36.c +++ b/src/util/base36.c @@ -23,88 +23,104 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -int -atoi36(const char * str) +int atoi36(const char *str) { /* cannot use strtol, because invalid strings will cause crash */ - const unsigned char * s = (const unsigned char *)str; - int i = 0, sign = 1; - assert(s); - if(!(*s)) return 0; + const unsigned char *s = (const unsigned char *)str; - while(isxspace(*(unsigned char*)s)) ++s; + int i = 0, sign = 1; + + assert(s); + if (!(*s)) + return 0; + + while (isxspace(*(unsigned char *)s)) + ++s; if (*s == '-') { sign = -1; ++s; } - while(isalnum(*(unsigned char*)s)) { - if (isupper(*(unsigned char*)s)) i = i*36 + (*s)-'A' + 10; - else if (islower(*(unsigned char*)s)) i=i*36 + (*s)-'a' + 10; - else if (isdigit(*(unsigned char*)s)) i=i*36 + (*s)-'0'; + while (isalnum(*(unsigned char *)s)) { + if (isupper(*(unsigned char *)s)) + i = i * 36 + (*s) - 'A' + 10; + else if (islower(*(unsigned char *)s)) + i = i * 36 + (*s) - 'a' + 10; + else if (isdigit(*(unsigned char *)s)) + i = i * 36 + (*s) - '0'; else break; ++s; } - if (i<0) return 0; + if (i < 0) + return 0; return i * sign; } -const char* -itoab(int i, int base) +const char *itoab(int i, int base) { - static char **as = NULL; /* STATIC_RETURN: used for return, not across calls */ - char * s, * dst; - static int index = 0; /* STATIC_XCALL: used across calls */ + static char **as = NULL; /* STATIC_RETURN: used for return, not across calls */ + + char *s, *dst; + + static int index = 0; /* STATIC_XCALL: used across calls */ + int neg = 0; if (!as) { int j; - char * x = (char*)calloc(sizeof(char), 8*4); /* STATIC_LEAK: malloc in static variable */ - as = (char **)calloc(sizeof(char*), 4); - for (j=0;j!=4;++j) as[j] = x+j*8; + + char *x = (char *)calloc(sizeof(char), 8 * 4); /* STATIC_LEAK: malloc in static variable */ + + as = (char **)calloc(sizeof(char *), 4); + for (j = 0; j != 4; ++j) + as[j] = x + j * 8; } s = as[index]; - index = (index+1) & 3; /* quick for % 4 */ - dst = s+7; - (*dst--)=0; - if (i!=0) { - if (i<0) { - i=-i; + index = (index + 1) & 3; /* quick for % 4 */ + dst = s + 7; + (*dst--) = 0; + if (i != 0) { + if (i < 0) { + i = -i; neg = 1; } while (i) { int x = i % base; + i = i / base; - if (x<10) *(dst--) = (char)('0' + x); - else if ('a' + x - 10 == 'l') *(dst--) = 'L'; - else *(dst--) = (char)('a' + (x-10)); + if (x < 10) + *(dst--) = (char)('0' + x); + else if ('a' + x - 10 == 'l') + *(dst--) = 'L'; + else + *(dst--) = (char)('a' + (x - 10)); } - if (neg) *(dst) = '-'; - else ++dst; - } - else *dst = '0'; + if (neg) + *(dst) = '-'; + else + ++dst; + } else + *dst = '0'; return dst; } -const char* -itoa36(int i) +const char *itoa36(int i) { return itoab(i, 36); } -const char* -itoa10(int i) +const char *itoa10(int i) { return itoab(i, 10); } -int -i10toi36(int i) +int i10toi36(int i) { int r = 0; - while(i) { - r = r*36 + i % 10; + + while (i) { + r = r * 36 + i % 10; i = i / 10; } return r; diff --git a/src/util/base36.h b/src/util/base36.h index e11be7ec2..67663a821 100644 --- a/src/util/base36.h +++ b/src/util/base36.h @@ -22,11 +22,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern int atoi36(const char * s); -extern const char* itoab(int i, int base); -extern const char* itoa36(int i); -extern const char* itoa10(int i); -extern int i10toi36(int i); + extern int atoi36(const char *s); + extern const char *itoab(int i, int base); + extern const char *itoa36(int i); + extern const char *itoa10(int i); + extern int i10toi36(int i); #ifdef __cplusplus } diff --git a/src/util/base36_test.c b/src/util/base36_test.c index 2658becc1..6fd019334 100644 --- a/src/util/base36_test.c +++ b/src/util/base36_test.c @@ -3,7 +3,8 @@ #include #include -static void test_atoi36(CuTest * tc) { +static void test_atoi36(CuTest * tc) +{ CuAssertIntEquals(tc, 0, atoi36("0")); CuAssertIntEquals(tc, 666, atoi36("ii")); CuAssertIntEquals(tc, -10, atoi36("-a")); @@ -12,7 +13,8 @@ static void test_atoi36(CuTest * tc) { CuAssertIntEquals(tc, -10, atoi("-10")); } -static void test_itoa36(CuTest * tc) { +static void test_itoa36(CuTest * tc) +{ CuAssertStrEquals(tc, itoa36(0), "0"); CuAssertStrEquals(tc, itoa10(INT_MAX), "2147483647"); CuAssertStrEquals(tc, itoab(-1, 5), "-1"); @@ -21,9 +23,10 @@ static void test_itoa36(CuTest * tc) { CuAssertStrEquals(tc, itoa36(666), "ii"); } -CuSuite* get_base36_suite(void) +CuSuite *get_base36_suite(void) { - CuSuite* suite = CuSuiteNew(); + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_itoa36); SUITE_ADD_TEST(suite, test_atoi36); return suite; diff --git a/src/util/bsdstring.c b/src/util/bsdstring.c index 84802c70e..9fa8d8bce 100644 --- a/src/util/bsdstring.c +++ b/src/util/bsdstring.c @@ -7,19 +7,18 @@ #include "bsdstring.h" #endif -INLINE_FUNCTION int -wrptr(char ** ptr, size_t * size, int bytes) +INLINE_FUNCTION int wrptr(char **ptr, size_t * size, int bytes) { - assert(bytes>=0 || !"you're not using snprintf right, maybe?"); + assert(bytes >= 0 || !"you're not using snprintf right, maybe?"); - if (bytes==0) { + if (bytes == 0) { return 0; } - if (bytes<0) { + if (bytes < 0) { *size = 0; return EINVAL; } - if (bytes<=*(int*)size) { + if (bytes <= *(int *)size) { *ptr += bytes; *size -= bytes; return 0; @@ -31,11 +30,12 @@ wrptr(char ** ptr, size_t * size, int bytes) } #if !defined(HAVE_STRLCPY) -INLINE_FUNCTION size_t -strlcpy(char *dst, const char *src, size_t siz) /* copied from OpenBSD source code */ -{ +INLINE_FUNCTION size_t strlcpy(char *dst, const char *src, size_t siz) +{ /* copied from OpenBSD source code */ register char *d = dst; + register const char *s = src; + register size_t n = siz; /* Copy as many bytes as will fit */ @@ -49,21 +49,22 @@ strlcpy(char *dst, const char *src, size_t siz) /* copied from OpenBSD source /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) - *d = '\0'; /* NUL-terminate dst */ - while (*s++) - ; + *d = '\0'; /* NUL-terminate dst */ + while (*s++) ; } - return(s - src - 1); /* count does not include NUL */ + return (s - src - 1); /* count does not include NUL */ } -INLINE_FUNCTION size_t -strlcat(char * dst, const char * src, size_t siz) +INLINE_FUNCTION size_t strlcat(char *dst, const char *src, size_t siz) { register char *d = dst; + register const char *s = src; + register size_t n = siz; + size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ @@ -73,7 +74,7 @@ strlcat(char * dst, const char * src, size_t siz) n = siz - dlen; if (n == 0) - return(dlen + strlen(s)); + return (dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; @@ -83,6 +84,6 @@ strlcat(char * dst, const char * src, size_t siz) } *d = '\0'; - return(dlen + (s - src)); /* count does not include NUL */ + return (dlen + (s - src)); /* count does not include NUL */ } #endif diff --git a/src/util/bsdstring.h b/src/util/bsdstring.h index 90feb2165..a7c77a6c7 100644 --- a/src/util/bsdstring.h +++ b/src/util/bsdstring.h @@ -4,9 +4,11 @@ #ifdef HAVE_INLINE # include "bsdstring.c" #else - extern size_t strlcpy(char *dst, const char *src, size_t siz); - extern size_t strlcat(char * dst, const char * src, size_t siz); - extern int wrptr(char ** ptr, size_t * size, int bytes); +extern size_t strlcpy(char *dst, const char *src, size_t siz); + +extern size_t strlcat(char *dst, const char *src, size_t siz); + +extern int wrptr(char **ptr, size_t * size, int bytes); #endif #define WARN_STATIC_BUFFER() log_warning(("static buffer too small in %s:%d\n", __FILE__, __LINE__)) diff --git a/src/util/console.c b/src/util/console.c index 62353604a..6ffbb7c7f 100644 --- a/src/util/console.c +++ b/src/util/console.c @@ -30,18 +30,19 @@ #define default_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) #define lua_saveline(L,idx) \ if (lua_strlen(L,idx) > 0) /* non-empty line? */ \ - add_history(lua_tostring(L, idx)); /* add it to history */ + add_history(lua_tostring(L, idx)); /* add it to history */ #define lua_freeline(L,b) ((void)L, free(b)) #else #define default_readline(L,b,p) \ ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ - fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ + fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ #define lua_saveline(L,idx) { (void)L; (void)idx; } #define lua_freeline(L,b) { (void)L; (void)b; } #endif -static int (*my_readline)(lua_State *l, char *, size_t, const char *prompt) = NULL; -static int lua_readline(lua_State *l, char *b, const char *prompt) +static int (*my_readline) (lua_State * l, char *, size_t, const char *prompt) = + NULL; +static int lua_readline(lua_State * l, char *b, const char *prompt) { if (my_readline) { return my_readline(l, b, LUA_MAXINPUT, prompt); @@ -50,7 +51,8 @@ static int lua_readline(lua_State *l, char *b, const char *prompt) } } -void set_readline(readline foo) { +void set_readline(readline foo) +{ my_readline = foo; } @@ -64,44 +66,51 @@ void set_readline(readline foo) { /* BAD hack, all this action stuff. */ #define STATESTACK_MAX 16 -static lua_State * state_stack[STATESTACK_MAX]; +static lua_State *state_stack[STATESTACK_MAX]; + int state_stack_top = -1; static const char *progname = "eressea"; -static void -lstop(lua_State *l, lua_Debug *ar) +static void lstop(lua_State * l, lua_Debug * ar) { - (void)ar; /* unused arg. */ + (void)ar; /* unused arg. */ lua_sethook(l, NULL, 0, 0); luaL_error(l, "interrupted!"); } -static void -laction(int i) +static void laction(int i) { - signal(i, SIG_DFL); /* if another SIGINT happens before lstop, - terminate process (default action) */ - assert(state_stack_top>=0 && state_stack_top= 0 && state_stack_top < STATESTACK_MAX); + lua_sethook(state_stack[state_stack_top], lstop, + LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1); } -static void l_message (const char *pname, const char *msg) { - if (pname) fprintf(stderr, "%s: ", pname); + +static void l_message(const char *pname, const char *msg) +{ + if (pname) + fprintf(stderr, "%s: ", pname); fprintf(stderr, "%s\n", msg); fflush(stderr); } -static int report (lua_State *L, int status) { +static int report(lua_State * L, int status) +{ if (status && !lua_isnil(L, -1)) { const char *msg = lua_tostring(L, -1); - if (msg == NULL) msg = "(error object is not a string)"; + + if (msg == NULL) + msg = "(error object is not a string)"; l_message(progname, msg); lua_pop(L, 1); } return status; } -static int traceback (lua_State *L) { +static int traceback(lua_State * L) +{ lua_getfield(L, LUA_GLOBALSINDEX, "debug"); if (!lua_istable(L, -1)) { lua_pop(L, 1); @@ -112,66 +121,77 @@ static int traceback (lua_State *L) { lua_pop(L, 2); return 1; } - lua_pushvalue(L, 1); /* pass error message */ - lua_pushinteger(L, 2); /* skip this function and traceback */ - lua_call(L, 2, 1); /* call debug.traceback */ + lua_pushvalue(L, 1); /* pass error message */ + lua_pushinteger(L, 2); /* skip this function and traceback */ + lua_call(L, 2, 1); /* call debug.traceback */ return 1; } -static int docall (lua_State *L, int narg, int clear) { +static int docall(lua_State * L, int narg, int clear) +{ int status, pop_state = state_stack_top; - int base = lua_gettop(L) - narg; /* function index */ - lua_pushcfunction(L, traceback); /* push traceback function */ - lua_insert(L, base); /* put it under chunk and args */ - if (state_stack_top<0 || L != state_stack[state_stack_top]) { - assert(state_stack_top+1'") == NULL) return 0; + if (status != LUA_ERRSYNTAX) + return 0; + if (strstr(lua_tostring(L, -1), "near `'") == NULL) + return 0; lua_pop(L, 1); return 1; } -static int pushline (lua_State *L, int firstline) { +static int pushline(lua_State * L, int firstline) +{ char buffer[LUA_MAXINPUT]; + char *b = buffer; + size_t l; + const char *prmt = get_prompt(L, firstline); + if (lua_readline(L, b, prmt) == 0) - return 0; /* no input */ + return 0; /* no input */ l = strlen(b); - if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ - b[l-1] = '\0'; /* remove it */ - if (firstline && b[0] == '=') /* first line starts with `=' ? */ - lua_pushfstring(L, "return %s", b+1); /* change it to `return' */ + if (l > 0 && b[l - 1] == '\n') /* line ends with newline? */ + b[l - 1] = '\0'; /* remove it */ + if (firstline && b[0] == '=') /* first line starts with `=' ? */ + lua_pushfstring(L, "return %s", b + 1); /* change it to `return' */ else lua_pushstring(L, b); lua_freeline(L, b); @@ -179,69 +199,75 @@ static int pushline (lua_State *L, int firstline) { } -static int loadline (lua_State *L) { +static int loadline(lua_State * L) +{ int status; + lua_settop(L, 0); if (!pushline(L, 1)) - return -1; /* no input */ - for (;;) { /* repeat until gets a complete line */ + return -1; /* no input */ + for (;;) { /* repeat until gets a complete line */ status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); - if (!incomplete(L, status)) break; /* cannot try to add lines? */ - if (!pushline(L, 0)) /* no more input? */ + if (!incomplete(L, status)) + break; /* cannot try to add lines? */ + if (!pushline(L, 0)) /* no more input? */ return -1; - lua_pushliteral(L, "\n"); /* add a new line... */ - lua_insert(L, -2); /* ...between the two lines */ - lua_concat(L, 3); /* join them */ + lua_pushliteral(L, "\n"); /* add a new line... */ + lua_insert(L, -2); /* ...between the two lines */ + lua_concat(L, 3); /* join them */ } lua_saveline(L, 1); - lua_remove(L, 1); /* remove line */ + lua_remove(L, 1); /* remove line */ return status; } -static void dotty (lua_State *L) { +static void dotty(lua_State * L) +{ int status; + const char *oldprogname = progname; + progname = NULL; while ((status = loadline(L)) != -1) { - if (status == 0) status = docall(L, 0, 0); + if (status == 0) + status = docall(L, 0, 0); report(L, status); - if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ + if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ lua_getglobal(L, "print"); lua_insert(L, 1); - if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) + if (lua_pcall(L, lua_gettop(L) - 1, 0, 0) != 0) l_message(progname, lua_pushfstring(L, - "error calling " LUA_QL("print") " (%s)", - lua_tostring(L, -1))); + "error calling " LUA_QL("print") " (%s)", lua_tostring(L, -1))); } } - lua_settop(L, 0); /* clear stack */ + lua_settop(L, 0); /* clear stack */ fputs("\n", stdout); fflush(stdout); progname = oldprogname; } -int -lua_console(lua_State * L) +int lua_console(lua_State * L) { dotty(L); return 0; } -int -lua_do(lua_State * L) +int lua_do(lua_State * L) { int status = loadline(L); + if (status != -1) { - if (status == 0) status = docall(L, 0, 0); + if (status == 0) + status = docall(L, 0, 0); report(L, status); - if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ + if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */ lua_getglobal(L, "print"); lua_insert(L, 1); - if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0) + if (lua_pcall(L, lua_gettop(L) - 1, 0, 0) != 0) l_message(NULL, lua_pushfstring(L, "error calling `print' (%s)", - lua_tostring(L, -1))); + lua_tostring(L, -1))); } } - lua_settop(L, 0); /* clear stack */ + lua_settop(L, 0); /* clear stack */ return 0; } diff --git a/src/util/console.h b/src/util/console.h index d5821135b..8afdeb0d0 100644 --- a/src/util/console.h +++ b/src/util/console.h @@ -24,14 +24,13 @@ extern "C" { struct lua_State; - extern int lua_console(struct lua_State * L); - extern int lua_do(struct lua_State * L); + extern int lua_console(struct lua_State *L); + extern int lua_do(struct lua_State *L); - typedef int (*readline)(struct lua_State *, char *, size_t, const char *); + typedef int (*readline) (struct lua_State *, char *, size_t, const char *); extern void set_readline(readline foo); #ifdef __cplusplus } #endif - #endif diff --git a/src/util/crmessage.c b/src/util/crmessage.c index 6cb1ba349..6cceb9fa9 100644 --- a/src/util/crmessage.c +++ b/src/util/crmessage.c @@ -25,135 +25,142 @@ /** type to string conversion **/ typedef struct tsf_list { - struct tsf_list * next; - const char * name; - tostring_f fun; + struct tsf_list *next; + const char *name; + tostring_f fun; } tsf_list; -static tsf_list * tostringfs; +static tsf_list *tostringfs; -static tostring_f -tsf_find(const char * name) +static tostring_f tsf_find(const char *name) { - if (name!=NULL) { - tsf_list * tsf; - for (tsf=tostringfs;tsf;tsf=tsf->next) { - if (!strcmp(tsf->name, name)) return tsf->fun; - } - } - return NULL; + if (name != NULL) { + tsf_list *tsf; + + for (tsf = tostringfs; tsf; tsf = tsf->next) { + if (!strcmp(tsf->name, name)) + return tsf->fun; + } + } + return NULL; } -void -tsf_register(const char * name, tostring_f fun) +void tsf_register(const char *name, tostring_f fun) { - tsf_list * tsf; - for (tsf=tostringfs;tsf;tsf=tsf->next) { - if (!strcmp(tsf->name, name)) break; - } - if (tsf==NULL) { - tsf = malloc(sizeof(tsf_list)); - tsf->fun = fun; - tsf->name = name; - tsf->next = tostringfs; - tostringfs = tsf; - } + tsf_list *tsf; + + for (tsf = tostringfs; tsf; tsf = tsf->next) { + if (!strcmp(tsf->name, name)) + break; + } + if (tsf == NULL) { + tsf = malloc(sizeof(tsf_list)); + tsf->fun = fun; + tsf->name = name; + tsf->next = tostringfs; + tostringfs = tsf; + } } /** crmesssage **/ typedef struct crmessage_type { - const struct message_type * mtype; - tostring_f * renderers; - struct crmessage_type * next; + const struct message_type *mtype; + tostring_f *renderers; + struct crmessage_type *next; } crmessage_type; #define CRMAXHASH 63 -static crmessage_type * crtypes[CRMAXHASH]; +static crmessage_type *crtypes[CRMAXHASH]; -static crmessage_type * -crt_find(const struct message_type * mtype) +static crmessage_type *crt_find(const struct message_type *mtype) { unsigned int hash = hashstring(mtype->name) % CRMAXHASH; - crmessage_type * found = NULL; - crmessage_type * type = crtypes[hash]; + + crmessage_type *found = NULL; + + crmessage_type *type = crtypes[hash]; + while (type) { - if (type->mtype==mtype) found = type; + if (type->mtype == mtype) + found = type; type = type->next; } return found; } -void -crt_register(const struct message_type * mtype) +void crt_register(const struct message_type *mtype) { unsigned int hash = hashstring(mtype->name) % CRMAXHASH; - crmessage_type * crt = crtypes[hash]; - while (crt && crt->mtype!=mtype) { + + crmessage_type *crt = crtypes[hash]; + + while (crt && crt->mtype != mtype) { crt = crt->next; } if (!crt) { int i; + crt = malloc(sizeof(crmessage_type)); crt->mtype = mtype; crt->next = crtypes[hash]; crtypes[hash] = crt; - if(mtype->nparameters > 0) { - crt->renderers = malloc(sizeof(tostring_f)*mtype->nparameters); + if (mtype->nparameters > 0) { + crt->renderers = malloc(sizeof(tostring_f) * mtype->nparameters); } else { crt->renderers = NULL; } - + /* can be scrapped for memory vs. speed */ - for (i=0;i!=mtype->nparameters;++i) { + for (i = 0; i != mtype->nparameters; ++i) { crt->renderers[i] = tsf_find(mtype->types[i]->name); } } } -int -cr_render(const message * msg, char * buffer, const void * userdata) +int cr_render(const message * msg, char *buffer, const void *userdata) { - int i; - char * c = buffer; - struct crmessage_type * crt = crt_find(msg->type); + int i; - if (crt==NULL) return -1; - for (i=0;i!=msg->type->nparameters;++i) { - if (crt->renderers[i]==NULL) { - log_error(("No renderer for argument %s:%s of \"%s\"\n", - msg->type->pnames[i], msg->type->types[i]->name, msg->type->name)); - continue; /* strcpy(c, (const char*)msg->locale_string(u->faction->locale, parameters[i])); */ - } else { - if (crt->renderers[i](msg->parameters[i], c, userdata)!=0) continue; - } - c += strlen(c); - sprintf(c, ";%s\n", msg->type->pnames[i]); - c += strlen(c); - } - return 0; + char *c = buffer; + + struct crmessage_type *crt = crt_find(msg->type); + + if (crt == NULL) + return -1; + for (i = 0; i != msg->type->nparameters; ++i) { + if (crt->renderers[i] == NULL) { + log_error(("No renderer for argument %s:%s of \"%s\"\n", + msg->type->pnames[i], msg->type->types[i]->name, msg->type->name)); + continue; /* strcpy(c, (const char*)msg->locale_string(u->faction->locale, parameters[i])); */ + } else { + if (crt->renderers[i] (msg->parameters[i], c, userdata) != 0) + continue; + } + c += strlen(c); + sprintf(c, ";%s\n", msg->type->pnames[i]); + c += strlen(c); + } + return 0; } -int -cr_string(variant var, char * buffer, const void * userdata) +int cr_string(variant var, char *buffer, const void *userdata) { - sprintf(buffer, "\"%s\"", (const char *)var.v); - unused(userdata); - return 0; + sprintf(buffer, "\"%s\"", (const char *)var.v); + unused(userdata); + return 0; } -int -cr_int(variant var, char * buffer, const void * userdata) +int cr_int(variant var, char *buffer, const void *userdata) { - sprintf(buffer, "%d", var.i); - unused(userdata); - return 0; + sprintf(buffer, "%d", var.i); + unused(userdata); + return 0; } -int -cr_ignore(variant var, char * buffer, const void * userdata) +int cr_ignore(variant var, char *buffer, const void *userdata) { - unused(var); - unused(buffer); - unused(userdata); - return -1; + unused(var); + unused(buffer); + unused(userdata); + return -1; } diff --git a/src/util/crmessage.h b/src/util/crmessage.h index 7861aaffe..c56e9a85c 100644 --- a/src/util/crmessage.h +++ b/src/util/crmessage.h @@ -18,20 +18,21 @@ extern "C" { #endif -struct locale; -struct message; -struct message_type; + struct locale; + struct message; + struct message_type; -typedef int (*tostring_f)(variant data, char * buffer, const void * userdata); -extern void tsf_register(const char * name, tostring_f fun); - /* registers a new type->string-function */ + typedef int (*tostring_f) (variant data, char *buffer, const void *userdata); + extern void tsf_register(const char *name, tostring_f fun); + /* registers a new type->string-function */ -extern int cr_string(variant v, char * buffer, const void * userdata); -extern int cr_int(variant v, char * buffer, const void * userdata); -extern int cr_ignore(variant v, char * buffer, const void * userdata); + extern int cr_string(variant v, char *buffer, const void *userdata); + extern int cr_int(variant v, char *buffer, const void *userdata); + extern int cr_ignore(variant v, char *buffer, const void *userdata); -extern void crt_register(const struct message_type * mtype); -extern int cr_render(const struct message * msg, char * buffer, const void * userdata); + extern void crt_register(const struct message_type *mtype); + extern int cr_render(const struct message *msg, char *buffer, + const void *userdata); #ifdef __cplusplus } diff --git a/src/util/dice.c b/src/util/dice.c index bf8593d0c..213b96a2a 100644 --- a/src/util/dice.c +++ b/src/util/dice.c @@ -26,12 +26,12 @@ /** rolls a number of n-sided dice. * Usage: 3d6-3d4+5 = dice(3,6)-dice(3,4)+5 */ -int -dice(int count, int value) +int dice(int count, int value) { int d = 0, c; - if (value<=0) return 0; /* (enno) %0 geht nicht. echt wahr. */ + if (value <= 0) + return 0; /* (enno) %0 geht nicht. echt wahr. */ if (count >= 0) for (c = count; c > 0; c--) d += rng_int() % value + 1; @@ -42,56 +42,59 @@ dice(int count, int value) return d; } -static int -term_eval(const char **sptr) +static int term_eval(const char **sptr) { const char *c = *sptr; + int m = 0, d = 0, k = 0, term = 1, multi = 1; + int state = 1; for (;;) { - if (isdigit(*(unsigned char*)c)) { - k = k*10+(*c-'0'); - } - else if (*c=='+' || *c=='-' || *c==0 || *c=='*' || *c==')' || *c=='(') { - if (state==1) /* konstante k addieren */ - m+=k*multi; - else if (state==2) { /* dDk */ + if (isdigit(*(unsigned char *)c)) { + k = k * 10 + (*c - '0'); + } else if (*c == '+' || *c == '-' || *c == 0 || *c == '*' || *c == ')' + || *c == '(') { + if (state == 1) /* konstante k addieren */ + m += k * multi; + else if (state == 2) { /* dDk */ int i; - if (k == 0) k = 6; /* 3d == 3d6 */ - for (i=0;i!=d;++i) m += (1 + rng_int() % k)*multi; - } - else assert(!"dice_rand: illegal token"); - if (*c=='*') { + + if (k == 0) + k = 6; /* 3d == 3d6 */ + for (i = 0; i != d; ++i) + m += (1 + rng_int() % k) * multi; + } else + assert(!"dice_rand: illegal token"); + if (*c == '*') { term *= m; m = 0; } k = d = 0; state = 1; - multi = (*c=='-')?-1:1; + multi = (*c == '-') ? -1 : 1; - if (*c=='(') { + if (*c == '(') { ++c; k = term_eval(&c); - } - else if (*c==0 || *c==')') { + } else if (*c == 0 || *c == ')') { break; } - } else if (*c=='d' || *c=='D') { - if (k==0) k = 1; /* d9 == 1d9 */ - assert(state==1 || !"dice_rand: illegal token"); + } else if (*c == 'd' || *c == 'D') { + if (k == 0) + k = 1; /* d9 == 1d9 */ + assert(state == 1 || !"dice_rand: illegal token"); d = k; k = 0; - state=2; + state = 2; } c++; } *sptr = c; - return m*term; + return m * term; } -int -dice_rand(const char *s) +int dice_rand(const char *s) { return term_eval(&s); } diff --git a/src/util/encoding.h b/src/util/encoding.h index 0fe33d4ef..73d1038b2 100644 --- a/src/util/encoding.h +++ b/src/util/encoding.h @@ -4,14 +4,14 @@ extern "C" { #endif -enum { - ENCODING_ERROR = -1, - ENCODING_NONE = 0, - ENCODING_8859_1 = 1, - ENCODING_UTF8 = 10 -}; + enum { + ENCODING_ERROR = -1, + ENCODING_NONE = 0, + ENCODING_8859_1 = 1, + ENCODING_UTF8 = 10 + }; -int get_encoding_by_name(const char * name); + int get_encoding_by_name(const char *name); #ifdef __cplusplus } diff --git a/src/util/event.c b/src/util/event.c index 50f652ec2..1701e8c7a 100644 --- a/src/util/event.c +++ b/src/util/event.c @@ -30,8 +30,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -void -write_triggers(struct storage * store, const trigger * t) +void write_triggers(struct storage *store, const trigger * t) { while (t) { if (t->type->write) { @@ -43,20 +42,22 @@ write_triggers(struct storage * store, const trigger * t) store->w_tok(store, "end"); } -int -read_triggers(struct storage * store, trigger ** tp) +int read_triggers(struct storage *store, trigger ** tp) { for (;;) { - trigger_type * ttype; + trigger_type *ttype; + char zText[128]; store->r_tok_buf(store, zText, sizeof(zText)); - if (!strcmp(zText, "end")) break; + if (!strcmp(zText, "end")) + break; ttype = tt_find(zText); assert(ttype || !"unknown trigger-type"); *tp = t_new(ttype); if (ttype->read) { int i = ttype->read(*tp, store); + switch (i) { case AT_READ_OK: tp = &(*tp)->next; @@ -74,44 +75,46 @@ read_triggers(struct storage * store, trigger ** tp) return 0; } -trigger * -t_new(trigger_type * ttype) +trigger *t_new(trigger_type * ttype) { - trigger * t = calloc(sizeof(trigger), 1); - t->type=ttype; - if (ttype->initialize) ttype->initialize(t); - return t; + trigger *t = calloc(sizeof(trigger), 1); + + t->type = ttype; + if (ttype->initialize) + ttype->initialize(t); + return t; } -void -t_free(trigger * t) +void t_free(trigger * t) { - if (t->type->finalize) t->type->finalize(t); + if (t->type->finalize) + t->type->finalize(t); } -void -free_triggers(trigger * triggers) +void free_triggers(trigger * triggers) { - while (triggers) { - trigger * t = triggers; - triggers = t->next; - t_free(t); - } + while (triggers) { + trigger *t = triggers; + + triggers = t->next; + t_free(t); + } } -int -handle_triggers(trigger ** triggers, void * param) +int handle_triggers(trigger ** triggers, void *param) { - trigger ** tp = triggers; - while (*tp) { - trigger * t = *tp; - if (t->type->handle(t, param)!=0) { - *tp=t->next; - t_free(t); - } - else tp=&t->next; - } - return (*triggers!=NULL); + trigger **tp = triggers; + + while (*tp) { + trigger *t = *tp; + + if (t->type->handle(t, param) != 0) { + *tp = t->next; + t_free(t); + } else + tp = &t->next; + } + return (*triggers != NULL); } /*** @@ -119,152 +122,164 @@ handle_triggers(trigger ** triggers, void * param) **/ typedef struct handler_info { - char * event; - trigger * triggers; + char *event; + trigger *triggers; } handler_info; -static void -init_handler(attrib * a) { - a->data.v = calloc(sizeof(handler_info), 1); +static void init_handler(attrib * a) +{ + a->data.v = calloc(sizeof(handler_info), 1); +} + +static void free_handler(attrib * a) +{ + handler_info *hi = (handler_info *) a->data.v; + + free_triggers(hi->triggers); + free(hi->event); + free(hi); } static void -free_handler(attrib * a) { - handler_info *hi = (handler_info*)a->data.v; - free_triggers(hi->triggers); - free(hi->event); - free(hi); +write_handler(const attrib * a, const void *owner, struct storage *store) +{ + handler_info *hi = (handler_info *) a->data.v; + + store->w_tok(store, hi->event); + write_triggers(store, hi->triggers); } -static void -write_handler(const attrib * a, const void * owner, struct storage * store) +static int read_handler(attrib * a, void *owner, struct storage *store) { - handler_info *hi = (handler_info*)a->data.v; - store->w_tok(store, hi->event); - write_triggers(store, hi->triggers); -} + char zText[128]; -static int -read_handler(attrib * a, void * owner, struct storage * store) -{ - char zText[128]; - handler_info *hi = (handler_info*)a->data.v; + handler_info *hi = (handler_info *) a->data.v; - store->r_tok_buf(store, zText, sizeof(zText)); - hi->event = strdup(zText); - read_triggers(store, &hi->triggers); - if (hi->triggers!=NULL) { - return AT_READ_OK; - } - return AT_READ_FAIL; + store->r_tok_buf(store, zText, sizeof(zText)); + hi->event = strdup(zText); + read_triggers(store, &hi->triggers); + if (hi->triggers != NULL) { + return AT_READ_OK; + } + return AT_READ_FAIL; } attrib_type at_eventhandler = { - "eventhandler", - init_handler, - free_handler, - NULL, - write_handler, - read_handler + "eventhandler", + init_handler, + free_handler, + NULL, + write_handler, + read_handler }; -struct trigger ** -get_triggers(struct attrib * ap, const char * eventname) +struct trigger **get_triggers(struct attrib *ap, const char *eventname) { - handler_info * td = NULL; - attrib * a = a_find(ap, &at_eventhandler); - while (a!=NULL && a->type==&at_eventhandler) { - td = (handler_info *)a->data.v; - if (strcmp(td->event, eventname)==0) { - return &td->triggers; - } - a = a->next; - } - return NULL; + handler_info *td = NULL; + + attrib *a = a_find(ap, &at_eventhandler); + + while (a != NULL && a->type == &at_eventhandler) { + td = (handler_info *) a->data.v; + if (strcmp(td->event, eventname) == 0) { + return &td->triggers; + } + a = a->next; + } + return NULL; } -void -add_trigger(struct attrib ** ap, const char * eventname, struct trigger * t) +void add_trigger(struct attrib **ap, const char *eventname, struct trigger *t) { - trigger ** tp; - handler_info * td = NULL; - attrib * a = a_find(*ap, &at_eventhandler); - assert(t->next==NULL); - while (a!=NULL && a->type==&at_eventhandler) { - td = (handler_info *)a->data.v; - if (!strcmp(td->event, eventname)) { - break; - } - a = a->next; - } - if (a==NULL || a->type!=&at_eventhandler) { - a = a_add(ap, a_new(&at_eventhandler)); - td = (handler_info *)a->data.v; - td->event = strdup(eventname); - } - tp = &td->triggers; - while (*tp) tp=&(*tp)->next; - *tp = t; + trigger **tp; + + handler_info *td = NULL; + + attrib *a = a_find(*ap, &at_eventhandler); + + assert(t->next == NULL); + while (a != NULL && a->type == &at_eventhandler) { + td = (handler_info *) a->data.v; + if (!strcmp(td->event, eventname)) { + break; + } + a = a->next; + } + if (a == NULL || a->type != &at_eventhandler) { + a = a_add(ap, a_new(&at_eventhandler)); + td = (handler_info *) a->data.v; + td->event = strdup(eventname); + } + tp = &td->triggers; + while (*tp) + tp = &(*tp)->next; + *tp = t; } -void -handle_event(attrib * attribs, const char * eventname, void * data) +void handle_event(attrib * attribs, const char *eventname, void *data) { - while (attribs) { - if (attribs->type==&at_eventhandler) break; - attribs = attribs->nexttype; - } - while (attribs && attribs->type==&at_eventhandler) { - handler_info * tl = (handler_info*)attribs->data.v; + while (attribs) { + if (attribs->type == &at_eventhandler) + break; + attribs = attribs->nexttype; + } + while (attribs && attribs->type == &at_eventhandler) { + handler_info *tl = (handler_info *) attribs->data.v; + if (!strcmp(tl->event, eventname)) { - handler_info * tl = (handler_info*)attribs->data.v; + handler_info *tl = (handler_info *) attribs->data.v; + handle_triggers(&tl->triggers, data); break; } - attribs = attribs->next; - } + attribs = attribs->next; + } +} + +void t_add(struct trigger **tlist, struct trigger *t) +{ + while (*tlist) + tlist = &(*tlist)->next; + *tlist = t; +} + +static trigger_type *triggertypes; + +void tt_register(trigger_type * tt) +{ + tt->next = triggertypes; + triggertypes = tt; +} + +trigger_type *tt_find(const char *name) +{ + trigger_type *tt = triggertypes; + + while (tt && strcmp(tt->name, name)) + tt = tt->next; + return tt; } void -t_add(struct trigger ** tlist, struct trigger * t) +remove_triggers(struct attrib **ap, const char *eventname, + const trigger_type * tt) { - while (*tlist) tlist = &(*tlist)->next; - *tlist = t; -} + trigger **tp = get_triggers(*ap, eventname); -static trigger_type * triggertypes; + if (tp == NULL) + return; + while (*tp) { + /* first, remove all gate-triggers */ + trigger *t = *tp; -void -tt_register(trigger_type * tt) -{ - tt->next = triggertypes; - triggertypes = tt; -} - -trigger_type * -tt_find(const char * name) -{ - trigger_type * tt = triggertypes; - while (tt && strcmp(tt->name, name)) tt = tt->next; - return tt; -} - -void -remove_triggers(struct attrib ** ap, const char * eventname, const trigger_type * tt) -{ - trigger ** tp = get_triggers(*ap, eventname); - if(tp == NULL) return; - while (*tp) { - /* first, remove all gate-triggers */ - trigger * t = *tp; - if (t->type == tt) { - *tp = t->next; - t_free(t); - } else tp = &t->next; - } + if (t->type == tt) { + *tp = t->next; + t_free(t); + } else + tp = &t->next; + } } /*** ** default events **/ - diff --git a/src/util/event.h b/src/util/event.h index 23f272952..ef230219c 100644 --- a/src/util/event.h +++ b/src/util/event.h @@ -24,55 +24,59 @@ extern "C" { #include "variant.h" -struct attrib; -struct trigger; -struct storage; - -typedef struct trigger_type { - const char * name; - void (*initialize)(struct trigger *); - void (*finalize)(struct trigger *); - int (*handle)(struct trigger *, void *); - void (*write)(const struct trigger *, struct storage * store); - int (*read)(struct trigger *, struct storage * store); + struct attrib; + struct trigger; + struct storage; - struct trigger_type * next; -} trigger_type; + typedef struct trigger_type { + const char *name; + void (*initialize) (struct trigger *); + void (*finalize) (struct trigger *); + int (*handle) (struct trigger *, void *); + void (*write) (const struct trigger *, struct storage * store); + int (*read) (struct trigger *, struct storage * store); -extern trigger_type * tt_find(const char * name); -extern void tt_register(trigger_type * ttype); + struct trigger_type *next; + } trigger_type; -typedef struct trigger { - struct trigger_type * type; - struct trigger * next; + extern trigger_type *tt_find(const char *name); + extern void tt_register(trigger_type * ttype); - variant data; -} trigger; + typedef struct trigger { + struct trigger_type *type; + struct trigger *next; -typedef struct event_arg { - const char * type; - variant data; -} event_arg; + variant data; + } trigger; -extern trigger * t_new(trigger_type * ttype); -extern void t_free(trigger * t); -extern void t_add(trigger ** tlist, trigger * t); + typedef struct event_arg { + const char *type; + variant data; + } event_arg; + + extern trigger *t_new(trigger_type * ttype); + extern void t_free(trigger * t); + extern void t_add(trigger ** tlist, trigger * t); /** add and handle triggers **/ /* add a trigger to a list of attributes */ -extern void add_trigger(struct attrib ** ap, const char * eventname, struct trigger * t); -extern void remove_triggers(struct attrib ** ap, const char * eventname, const trigger_type * tt); -extern struct trigger ** get_triggers(struct attrib * ap, const char * eventname); + extern void add_trigger(struct attrib **ap, const char *eventname, + struct trigger *t); + extern void remove_triggers(struct attrib **ap, const char *eventname, + const trigger_type * tt); + extern struct trigger **get_triggers(struct attrib *ap, + const char *eventname); /* calls handle() for each of these. e.g. used in timeout */ -extern void handle_event(struct attrib * attribs, const char * eventname, void * data); + extern void handle_event(struct attrib *attribs, const char *eventname, + void *data); /* functions for making complex triggers: */ -extern void free_triggers(trigger * triggers); /* release all these triggers */ -extern void write_triggers(struct storage * store, const trigger * t); -extern int read_triggers(struct storage * store, trigger ** tp); -extern int handle_triggers(trigger ** triggers, void * data); + extern void free_triggers(trigger * triggers); /* release all these triggers */ + extern void write_triggers(struct storage *store, const trigger * t); + extern int read_triggers(struct storage *store, trigger ** tp); + extern int handle_triggers(trigger ** triggers, void *data); -extern struct attrib_type at_eventhandler; + extern struct attrib_type at_eventhandler; #ifdef __cplusplus } diff --git a/src/util/eventbus.c b/src/util/eventbus.c index 77e81b578..a9f937748 100644 --- a/src/util/eventbus.c +++ b/src/util/eventbus.c @@ -7,25 +7,27 @@ */ typedef struct listener { - struct listener * next; + struct listener *next; event_handler callback; event_arg_free destroy; - void * sender; - char * event; - void * arguments; + void *sender; + char *event; + void *arguments; } listener; -static listener * listeners; +static listener *listeners; -void -eventbus_fire(void * sender, const char * event, void * args) +void eventbus_fire(void *sender, const char *event, void *args) { - listener * lst = listeners; + listener *lst = listeners; + while (lst) { int i = strcmp(lst->event, event); - if (i>0) break; - if (i==0) { - if (!lst->sender || lst->sender==sender) { + + if (i > 0) + break; + if (i == 0) { + if (!lst->sender || lst->sender == sender) { lst->callback(sender, event, args); } } @@ -33,17 +35,20 @@ eventbus_fire(void * sender, const char * event, void * args) } } -void -eventbus_register(void * sender, const char * event, event_handler cb, event_arg_free arg_free, void * args) +void +eventbus_register(void *sender, const char *event, event_handler cb, + event_arg_free arg_free, void *args) { - listener * lst; - listener ** lstp = &listeners; + listener *lst; + + listener **lstp = &listeners; + while (*lstp) { lst = *lstp; - if (strcmp(lst->event, event)>=0) { + if (strcmp(lst->event, event) >= 0) { break; } - lstp=&lst->next; + lstp = &lst->next; } lst = malloc(sizeof(listener)); lst->sender = sender; diff --git a/src/util/eventbus.h b/src/util/eventbus.h index b217c686c..3667069d9 100644 --- a/src/util/eventbus.h +++ b/src/util/eventbus.h @@ -18,10 +18,11 @@ extern "C" { #endif - typedef void (*event_handler)(void *, const char *, void *); - typedef void (*event_arg_free)(void *); - void eventbus_fire(void * sender, const char * event, void * args); - void eventbus_register(void * sender, const char * event, event_handler callback, event_arg_free arg_free, void * args); + typedef void (*event_handler) (void *, const char *, void *); + typedef void (*event_arg_free) (void *); + void eventbus_fire(void *sender, const char *event, void *args); + void eventbus_register(void *sender, const char *event, + event_handler callback, event_arg_free arg_free, void *args); #ifdef __cplusplus } diff --git a/src/util/filereader.c b/src/util/filereader.c index a87427a54..02f850f7f 100644 --- a/src/util/filereader.c +++ b/src/util/filereader.c @@ -13,16 +13,15 @@ #define CONTINUE_CHAR '\\' #define MAXLINE 4096*16 static char lbuf[MAXLINE]; + static char fbuf[MAXLINE]; -static void -unicode_warning(const char * bp) +static void unicode_warning(const char *bp) { log_warning(("invalid sequence in UTF-8 string: %s\n", bp)); } -INLINE_FUNCTION int -eatwhite(const char * ptr, size_t * total_size) +INLINE_FUNCTION int eatwhite(const char *ptr, size_t * total_size) { int ret = 0; @@ -30,43 +29,53 @@ eatwhite(const char * ptr, size_t * total_size) while (*ptr) { ucs4_t ucs; + size_t size = 0; + ret = unicode_utf8_to_ucs4(&ucs, ptr, &size); - if (ret!=0) break; - if (!iswxspace((wint_t)ucs)) break; + if (ret != 0) + break; + if (!iswxspace((wint_t) ucs)) + break; *total_size += size; ptr += size; } return ret; } -static const char * -getbuf_latin1(FILE * F) +static const char *getbuf_latin1(FILE * F) { boolean cont = false; + char quote = 0; + boolean comment = false; - char * cp = fbuf; - char * tail = lbuf+MAXLINE-2; - tail[1] = '@'; /* if this gets overwritten by fgets then the line was very long. */ + char *cp = fbuf; + + char *tail = lbuf + MAXLINE - 2; + + tail[1] = '@'; /* if this gets overwritten by fgets then the line was very long. */ do { - const char * bp = fgets(lbuf, MAXLINE, F); + const char *bp = fgets(lbuf, MAXLINE, F); - if (bp==NULL) return NULL; - while (*bp && isxspace(*(unsigned char*)bp)) ++bp; /* eatwhite */ + if (bp == NULL) + return NULL; + while (*bp && isxspace(*(unsigned char *)bp)) + ++bp; /* eatwhite */ - comment = (boolean)(comment && cont); - quote = (boolean)(quote && cont); + comment = (boolean) (comment && cont); + quote = (boolean) (quote && cont); - if (tail[1]==0) { + if (tail[1] == 0) { /* we read he maximum number of bytes! */ - if (tail[0]!='\n') { + if (tail[0] != '\n') { /* it wasn't enough space to finish the line, eat the rest */ for (;;) { tail[1] = '@'; bp = fgets(lbuf, MAXLINE, F); - if (bp==NULL) return NULL; + if (bp == NULL) + return NULL; if (tail[1]) { /* read enough this time to end the line */ break; @@ -81,53 +90,58 @@ getbuf_latin1(FILE * F) } } cont = false; - while (*bp && cp0) cp+=ret; + + if (ret > 0) + cp += ret; else { log_error(("input data was not iso-8859-1! assuming utf-8\n")); return NULL; @@ -161,45 +180,51 @@ getbuf_latin1(FILE * F) continue; } } - if (cp==fbuf+MAXLINE) { + if (cp == fbuf + MAXLINE) { --cp; } - *cp=0; - } while (cont || cp==fbuf); + *cp = 0; + } while (cont || cp == fbuf); return fbuf; } -static const char * -getbuf_utf8(FILE * F) +static const char *getbuf_utf8(FILE * F) { boolean cont = false; - char quote = 0; - boolean comment = false; - char * cp = fbuf; - char * tail = lbuf+MAXLINE-2; - tail[1] = '@'; /* if this gets overwritten by fgets then the line was very long. */ + char quote = 0; + + boolean comment = false; + + char *cp = fbuf; + + char *tail = lbuf + MAXLINE - 2; + + tail[1] = '@'; /* if this gets overwritten by fgets then the line was very long. */ do { - const char * bp = fgets(lbuf, MAXLINE, F); + const char *bp = fgets(lbuf, MAXLINE, F); + size_t white; - if (bp==NULL) { + + if (bp == NULL) { return NULL; } - eatwhite(bp, &white); /* decoding errors will get caught later on, don't have to check */ + eatwhite(bp, &white); /* decoding errors will get caught later on, don't have to check */ bp += white; - comment = (boolean)(comment && cont); - quote = (boolean)(quote && cont); + comment = (boolean) (comment && cont); + quote = (boolean) (quote && cont); - if (tail[1]==0) { + if (tail[1] == 0) { /* we read the maximum number of bytes! */ - if (tail[0]!='\n') { + if (tail[0] != '\n') { /* it wasn't enough space to finish the line, eat the rest */ for (;;) { tail[1] = '@'; bp = fgets(lbuf, MAXLINE, F); - if (bp==NULL) return NULL; + if (bp == NULL) + return NULL; if (tail[1]) { /* read enough this time to end the line */ break; @@ -214,85 +239,93 @@ getbuf_utf8(FILE * F) } } cont = false; - while (*bp && cpname, name)!=0) fl=fl->next; - if (fl) return fl->fun; - return NULL; + function_list *fl = functionlist; + + if (name == NULL) + return NULL; + while (fl && strcmp(fl->name, name) != 0) + fl = fl->next; + if (fl) + return fl->fun; + return NULL; } -const char * -get_functionname(pf_generic fun) +const char *get_functionname(pf_generic fun) { - function_list * fl = functionlist; - while (fl && fl->fun!=fun) fl=fl->next; - if (fl) return fl->name; - return NULL; + function_list *fl = functionlist; + + while (fl && fl->fun != fun) + fl = fl->next; + if (fl) + return fl->name; + return NULL; } -void -register_function(pf_generic fun, const char * name) +void register_function(pf_generic fun, const char *name) { - function_list * fl = (function_list *)malloc(sizeof(function_list)); + function_list *fl = (function_list *) malloc(sizeof(function_list)); + fl->next = functionlist; fl->fun = fun; fl->name = strdup(name); functionlist = fl; } -void -list_registered_functions(void) +void list_registered_functions(void) { - function_list * fl = functionlist; + function_list *fl = functionlist; - while(fl) { + while (fl) { printf("%s\n", fl->name); fl = fl->next; } diff --git a/src/util/functions.h b/src/util/functions.h index f8fd090a6..6ca496044 100644 --- a/src/util/functions.h +++ b/src/util/functions.h @@ -22,12 +22,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -typedef void (*pf_generic)(void); + typedef void (*pf_generic) (void); -extern const char *get_functionname(pf_generic fun); -extern pf_generic get_function(const char * name); -extern void register_function(pf_generic fun, const char * name); -extern void list_registered_functions(void); + extern const char *get_functionname(pf_generic fun); + extern pf_generic get_function(const char *name); + extern void register_function(pf_generic fun, const char *name); + extern void list_registered_functions(void); #ifdef __cplusplus } diff --git a/src/util/goodies.c b/src/util/goodies.c index 231bbd9e9..2d99ec4d2 100644 --- a/src/util/goodies.c +++ b/src/util/goodies.c @@ -28,41 +28,38 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* Simple Integer-Liste */ -int * -intlist_init(void) +int *intlist_init(void) { - return (calloc(1, sizeof(int))); + return (calloc(1, sizeof(int))); } -int * -intlist_add(int *i_p, int i) +int *intlist_add(int *i_p, int i) { i_p[0]++; - i_p = realloc(i_p, (i_p[0]+1) * sizeof(int)); - + i_p = realloc(i_p, (i_p[0] + 1) * sizeof(int)); + i_p[i_p[0]] = i; return (i_p); } -int * -intlist_find(int *i_p, int fi) +int *intlist_find(int *i_p, int fi) { int i; - - for(i=1; i <= i_p[0]; i++) { - if(i_p[i] == fi) return (&i_p[i]); + + for (i = 1; i <= i_p[0]; i++) { + if (i_p[i] == fi) + return (&i_p[i]); } return NULL; } -char * -set_string (char **s, const char *neu) +char *set_string(char **s, const char *neu) { - if (neu==NULL) { + if (neu == NULL) { free(*s); *s = NULL; } else if (*s == NULL) { - *s = malloc(strlen(neu)+1); + *s = malloc(strlen(neu) + 1); strcpy(*s, neu); } else { *s = realloc(*s, strlen(neu) + 1); @@ -72,54 +69,69 @@ set_string (char **s, const char *neu) } -static int -spc_email_isvalid(const char *address) +static int spc_email_isvalid(const char *address) { - int count = 0; + int count = 0; + const char *c, *domain; - static const char *rfc822_specials = "()<>@,;:\\\"[]"; /* STATIC_CONST: contains a constant value */ + + static const char *rfc822_specials = "()<>@,;:\\\"[]"; /* STATIC_CONST: contains a constant value */ /* first we validate the name portion (name@domain) */ - for (c = address; *c; c++) { - if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == - '\"')) { - while (*++c) { - if (*c == '\"') break; - if (*c == '\\' && (*++c == ' ')) continue; - if (*c <= ' ' || *c >= 127) return 0; - } - if (!*c++) return 0; - if (*c == '@') break; - if (*c != '.') return 0; - continue; + for (c = address; *c; c++) { + if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == '\"')) { + while (*++c) { + if (*c == '\"') + break; + if (*c == '\\' && (*++c == ' ')) + continue; + if (*c <= ' ' || *c >= 127) + return 0; } - if (*c == '@') break; - if (*c <= ' ' || *c >= 127) return 0; - if (strchr(rfc822_specials, *c)) return 0; + if (!*c++) + return 0; + if (*c == '@') + break; + if (*c != '.') + return 0; + continue; + } + if (*c == '@') + break; + if (*c <= ' ' || *c >= 127) + return 0; + if (strchr(rfc822_specials, *c)) + return 0; } - if (c == address || *(c - 1) == '.') return 0; + if (c == address || *(c - 1) == '.') + return 0; /* next we validate the domain portion (name@domain) */ - if (!*(domain = ++c)) return 0; + if (!*(domain = ++c)) + return 0; do { if (*c == '.') { - if (c == domain || *(c - 1) == '.') return 0; + if (c == domain || *(c - 1) == '.') + return 0; count++; } - if (*c <= ' ' || *c >= 127) return 0; - if (strchr(rfc822_specials, *c)) return 0; + if (*c <= ' ' || *c >= 127) + return 0; + if (strchr(rfc822_specials, *c)) + return 0; } while (*++c); return (count >= 1); } -int -set_email(char** pemail, const char *newmail) +int set_email(char **pemail, const char *newmail) { if (newmail && *newmail) { - if (spc_email_isvalid(newmail)<=0) return -1; + if (spc_email_isvalid(newmail) <= 0) + return -1; } - if (*pemail) free(*pemail); + if (*pemail) + free(*pemail); *pemail = 0; if (newmail) { *pemail = strdup(newmail); diff --git a/src/util/goodies.h b/src/util/goodies.h index aabf0cb4b..3f4725bc7 100644 --- a/src/util/goodies.h +++ b/src/util/goodies.h @@ -22,20 +22,21 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -extern char * set_string(char **s, const char *neu); -extern int set_email(char** pemail, const char *newmail); + extern char *set_string(char **s, const char *neu); + extern int set_email(char **pemail, const char *newmail); -extern int *intlist_init(void); -extern int *intlist_add(int *i_p, int i); -extern int *intlist_find(int *i_p, int i); + extern int *intlist_init(void); + extern int *intlist_add(int *i_p, int i); + extern int *intlist_find(int *i_p, int i); #ifdef HAVE_INLINE # include "strings.c" #else -extern unsigned int hashstring(const char* s); -extern const char *escape_string(const char * str, char * buffer, unsigned int len); -extern unsigned int jenkins_hash(unsigned int a); -extern unsigned int wang_hash(unsigned int a); + extern unsigned int hashstring(const char *s); + extern const char *escape_string(const char *str, char *buffer, + unsigned int len); + extern unsigned int jenkins_hash(unsigned int a); + extern unsigned int wang_hash(unsigned int a); #endif /* benchmark for units: @@ -60,4 +61,4 @@ extern unsigned int wang_hash(unsigned int a); #ifdef __cplusplus } #endif -#endif /* GOODIES_H */ +#endif /* GOODIES_H */ diff --git a/src/util/graph.c b/src/util/graph.c index 9ea181466..bced4ee05 100644 --- a/src/util/graph.c +++ b/src/util/graph.c @@ -17,187 +17,196 @@ #include "vset.h" #include "graph.h" -void -graph_init(graph *g) +void graph_init(graph * g) { - vset_init(&g->nodes); - vset_init(&g->edges); + vset_init(&g->nodes); + vset_init(&g->edges); } -void -graph_free(graph *g) +void graph_free(graph * g) { - vset_destroy(&g->nodes); - vset_destroy(&g->edges); + vset_destroy(&g->nodes); + vset_destroy(&g->edges); } -void -graph_add_node(graph *g, node *n) +void graph_add_node(graph * g, node * n) { - vset_add(&g->nodes, n); + vset_add(&g->nodes, n); } -void -graph_add_edge(graph *g, edge *v) +void graph_add_edge(graph * g, edge * v) { - vset_add(&g->nodes, v); + vset_add(&g->nodes, v); } -void -graph_remove_node(graph *g, node *n) +void graph_remove_node(graph * g, node * n) { - unsigned int i; + unsigned int i; - for(i=0; i != g->edges.size; ++i) { - edge *v = g->edges.data[i]; - if(v->node1 == n || v->node2 == n) { - vset_erase(&g->nodes, v); - i--; - } - } - vset_erase(&g->nodes, n); + for (i = 0; i != g->edges.size; ++i) { + edge *v = g->edges.data[i]; + + if (v->node1 == n || v->node2 == n) { + vset_erase(&g->nodes, v); + i--; + } + } + vset_erase(&g->nodes, n); } -node * -graph_find_node(graph *g, void *object) +node *graph_find_node(graph * g, void *object) { - unsigned int i; + unsigned int i; - for(i=0; i != g->nodes.size; ++i) { - node *node = g->nodes.data[i]; - if(node->object == object) { - return g->nodes.data[i]; - } - } - return NULL; + for (i = 0; i != g->nodes.size; ++i) { + node *node = g->nodes.data[i]; + + if (node->object == object) { + return g->nodes.data[i]; + } + } + return NULL; } /* The vset returned has to freed externally, else this will be a memory leak. */ -vset * -graph_neighbours(graph *g, node *n) +vset *graph_neighbours(graph * g, node * n) { - unsigned int i; - vset * vs = malloc(sizeof(vs)); - vset_init(vs); - for(i=0; i != g->edges.size; ++i) { - edge *v = g->edges.data[i]; - if(v->node1 == n && vset_count(vs, v->node2) == 0) { - vset_add(vs, v->node2); - } else if(v->node2 == n && vset_count(vs, v->node1) == 0) { - vset_add(vs, v->node1); - } - } + unsigned int i; - return vs; + vset *vs = malloc(sizeof(vs)); + + vset_init(vs); + for (i = 0; i != g->edges.size; ++i) { + edge *v = g->edges.data[i]; + + if (v->node1 == n && vset_count(vs, v->node2) == 0) { + vset_add(vs, v->node2); + } else if (v->node2 == n && vset_count(vs, v->node1) == 0) { + vset_add(vs, v->node1); + } + } + + return vs; } -void -graph_resetmarkers(graph *g) +void graph_resetmarkers(graph * g) { - unsigned int i; + unsigned int i; - for(i=0; i != g->nodes.size; ++i) { - node *node = g->nodes.data[i]; - node->marker = 0; - } - for(i=0; i != g->edges.size; ++i) { - edge *edge = g->edges.data[i]; - edge->marker = 0; - } + for (i = 0; i != g->nodes.size; ++i) { + node *node = g->nodes.data[i]; + + node->marker = 0; + } + for (i = 0; i != g->edges.size; ++i) { + edge *edge = g->edges.data[i]; + + edge->marker = 0; + } } /* The vset returned has to freed externally, else this will be a memory leak. */ -vset * -graph_connected_nodes(graph *g, node *n) +vset *graph_connected_nodes(graph * g, node * n) { - vset * vs = malloc(sizeof(vset)); - vset s; + vset *vs = malloc(sizeof(vset)); - vset_init(vs); - vset_init(&s); - graph_resetmarkers(g); - vset_add(vs, n); - n->marker = 1; - vset_add(&s, n); - while(s.size > 0) { - node *n = vset_pop(&s); - vset *vs_nb = graph_neighbours(g, n); - unsigned int i; - for(i=0; i != vs_nb->size; ++i) { - node *nb = vs_nb->data[i]; - if(nb->marker == 0) { - nb->marker = 1; - vset_add(vs, nb); - vset_add(&s, nb); - } - } - vset_destroy(vs_nb); - free(vs_nb); - } + vset s; - vset_destroy(&s); + vset_init(vs); + vset_init(&s); + graph_resetmarkers(g); + vset_add(vs, n); + n->marker = 1; + vset_add(&s, n); + while (s.size > 0) { + node *n = vset_pop(&s); - return vs; + vset *vs_nb = graph_neighbours(g, n); + + unsigned int i; + + for (i = 0; i != vs_nb->size; ++i) { + node *nb = vs_nb->data[i]; + + if (nb->marker == 0) { + nb->marker = 1; + vset_add(vs, nb); + vset_add(&s, nb); + } + } + vset_destroy(vs_nb); + free(vs_nb); + } + + vset_destroy(&s); + + return vs; } /* The vset returned has to freed externally, else this will be a memory leak. */ -vset * -graph_disjunct_graphs(graph *g) +vset *graph_disjunct_graphs(graph * g) { - vset * dg = malloc(sizeof(vset)); - vset nodes; + vset *dg = malloc(sizeof(vset)); - vset_init(dg); - vset_init(&nodes); - vset_concat(&nodes, &g->nodes); - - while(nodes.size > 0) { - graph *gt = malloc(sizeof(graph)); - vset s; - unsigned int i; - node *start; + vset nodes; - graph_init(gt); - start = vset_pop(&nodes); - graph_resetmarkers(g); - graph_add_node(gt, start); - start->marker = 1; - vset_init(&s); - vset_add(&s,start); - while(s.size > 0) { - vset * nbs = graph_neighbours(g,vset_pop(&s)); - for(i=0; i != nbs->size; ++i) { - node *nb = nbs->data[i]; - if(nb->marker == 0) { - nb->marker = 1; - graph_add_node(gt,nb); - vset_erase(&nodes,nb); - vset_add(&s,nb); - } - } - vset_destroy(nbs); free(nbs); - } + vset_init(dg); + vset_init(&nodes); + vset_concat(&nodes, &g->nodes); - vset_destroy(&s); + while (nodes.size > 0) { + graph *gt = malloc(sizeof(graph)); - for(i=0;i != g->edges.size; ++i) { - edge *v = g->edges.data[i]; - if(vset_count(&g->nodes, v->node1)) { - graph_add_edge(gt, v); - } - } + vset s; - vset_add(dg, gt); - } + unsigned int i; - vset_destroy(&nodes); + node *start; - return dg; + graph_init(gt); + start = vset_pop(&nodes); + graph_resetmarkers(g); + graph_add_node(gt, start); + start->marker = 1; + vset_init(&s); + vset_add(&s, start); + while (s.size > 0) { + vset *nbs = graph_neighbours(g, vset_pop(&s)); + + for (i = 0; i != nbs->size; ++i) { + node *nb = nbs->data[i]; + + if (nb->marker == 0) { + nb->marker = 1; + graph_add_node(gt, nb); + vset_erase(&nodes, nb); + vset_add(&s, nb); + } + } + vset_destroy(nbs); + free(nbs); + } + + vset_destroy(&s); + + for (i = 0; i != g->edges.size; ++i) { + edge *v = g->edges.data[i]; + + if (vset_count(&g->nodes, v->node1)) { + graph_add_edge(gt, v); + } + } + + vset_add(dg, gt); + } + + vset_destroy(&nodes); + + return dg; } - diff --git a/src/util/graph.h b/src/util/graph.h index e5480d1ab..19303acc8 100644 --- a/src/util/graph.h +++ b/src/util/graph.h @@ -16,21 +16,21 @@ extern "C" { #endif -typedef struct node { - int marker; - void *object; -} node; + typedef struct node { + int marker; + void *object; + } node; -typedef struct edge { - int marker; - node *node1; - node *node2; -} edge; + typedef struct edge { + int marker; + node *node1; + node *node2; + } edge; -typedef struct graph { - vset nodes; - vset edges; -} graph; + typedef struct graph { + vset nodes; + vset edges; + } graph; #ifdef __cplusplus } diff --git a/src/util/language.c b/src/util/language.c index 00e1adff8..246391308 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -31,35 +31,39 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /** importing **/ -locale * default_locale; -locale * locales; +locale *default_locale; -unsigned int -locale_hashkey(const locale * lang) +locale *locales; + +unsigned int locale_hashkey(const locale * lang) { - assert(lang); - return lang->hashkey; + assert(lang); + return lang->hashkey; } -locale * -find_locale(const char * name) +locale *find_locale(const char *name) { - unsigned int hkey = hashstring(name); - locale * l = locales; - while (l && l->hashkey!=hkey) l=l->next; - return l; + unsigned int hkey = hashstring(name); + + locale *l = locales; + + while (l && l->hashkey != hkey) + l = l->next; + return l; } static int nextlocaleindex = 0; -locale * -make_locale(const char * name) +locale *make_locale(const char *name) { unsigned int hkey = hashstring(name); - locale * l = (locale *)calloc(sizeof(locale), 1); - locale ** lp = &locales; - while (*lp && (*lp)->hashkey!=hkey) lp=&(*lp)->next; + locale *l = (locale *) calloc(sizeof(locale), 1); + + locale **lp = &locales; + + while (*lp && (*lp)->hashkey != hkey) + lp = &(*lp)->next; if (*lp) { return *lp; } @@ -68,9 +72,10 @@ make_locale(const char * name) l->name = strdup(name); l->next = NULL; l->index = nextlocaleindex++; - assert(nextlocaleindex<=MAXLOCALES); + assert(nextlocaleindex <= MAXLOCALES); *lp = l; - if (default_locale==NULL) default_locale = l; + if (default_locale == NULL) + default_locale = l; return l; } @@ -79,15 +84,17 @@ make_locale(const char * name) * the locales using the make_locale function (useful for ini-files). * For maximum performance, locales should be created in order of popularity. */ -void -make_locales(const char * str) +void make_locales(const char *str) { - const char * tok = str; + const char *tok = str; + while (*tok) { char zText[32]; - while (*tok && *tok !=',') ++tok; - strncpy(zText, str, tok-str); - zText[tok-str] = 0; + + while (*tok && *tok != ',') + ++tok; + strncpy(zText, str, tok - str); + zText[tok - str] = 0; make_locale(zText); if (*tok) { str = ++tok; @@ -95,33 +102,35 @@ make_locales(const char * str) } } -static FILE * s_debug = NULL; -static char * s_logfile = NULL; +static FILE *s_debug = NULL; -void -debug_language(const char * log) +static char *s_logfile = NULL; + +void debug_language(const char *log) { s_logfile = strdup(log); } -const char * -locale_getstring(const locale * lang, const char * key) +const char *locale_getstring(const locale * lang, const char *key) { unsigned int hkey = hashstring(key); - unsigned int id = hkey & (SMAXHASH-1); - const struct locale_str * find; + + unsigned int id = hkey & (SMAXHASH - 1); + + const struct locale_str *find; assert(lang); - if (key==NULL || *key==0) return NULL; + if (key == NULL || *key == 0) + return NULL; find = lang->strings[id]; while (find) { if (find->hashkey == hkey) { - if (find->nexthash==NULL) { + if (find->nexthash == NULL) { /* if this is the only entry with this hash, fine. */ - assert(strcmp(key, find->key)==0); + assert(strcmp(key, find->key) == 0); return find->str; } - if (strcmp(key, find->key)==0) { + if (strcmp(key, find->key) == 0) { return find->str; } } @@ -130,42 +139,48 @@ locale_getstring(const locale * lang, const char * key) return NULL; } -const char * -locale_string(const locale * lang, const char * key) +const char *locale_string(const locale * lang, const char *key) { - assert(lang!=0); + assert(lang != 0); - if (key!=NULL) { + if (key != NULL) { unsigned int hkey = hashstring(key); - unsigned int id = hkey & (SMAXHASH-1); - struct locale_str * find; - - if (*key==0) return NULL; - if (lang == NULL) return key; + + unsigned int id = hkey & (SMAXHASH - 1); + + struct locale_str *find; + + if (*key == 0) + return NULL; + if (lang == NULL) + return key; find = lang->strings[id]; while (find) { if (find->hashkey == hkey) { - if (find->nexthash==NULL) { + if (find->nexthash == NULL) { /* if this is the only entry with this hash, fine. */ - assert(strcmp(key, find->key)==0); + assert(strcmp(key, find->key) == 0); break; } - if (strcmp(key, find->key)==0) break; + if (strcmp(key, find->key) == 0) + break; } find = find->nexthash; } if (!find) { - const char * s = key; - log_warning(("missing translation for \"%s\" in locale %s\n", key, lang->name)); - if (lang!=default_locale) { + const char *s = key; + + log_warning(("missing translation for \"%s\" in locale %s\n", key, + lang->name)); + if (lang != default_locale) { s = locale_string(default_locale, key); } if (s_logfile) { - s_debug = s_debug?s_debug:fopen(s_logfile, "w"); + s_debug = s_debug ? s_debug : fopen(s_logfile, "w"); if (s_debug) { fprintf(s_debug, "%s;%s;%s\n", key, lang->name, s); fflush(s_debug); - locale_setstring((struct locale*)lang, key, s); + locale_setstring((struct locale *)lang, key, s); } } return s; @@ -175,16 +190,20 @@ locale_string(const locale * lang, const char * key) return NULL; } -void -locale_setstring(locale * lang, const char * key, const char * value) +void locale_setstring(locale * lang, const char *key, const char *value) { unsigned int hkey = hashstring(key); - unsigned int id = hkey & (SMAXHASH-1); - struct locale_str * find; - if (lang==NULL) lang=default_locale; + + unsigned int id = hkey & (SMAXHASH - 1); + + struct locale_str *find; + + if (lang == NULL) + lang = default_locale; find = lang->strings[id]; while (find) { - if (find->hashkey==hkey && strcmp(key, find->key)==0) break; + if (find->hashkey == hkey && strcmp(key, find->key) == 0) + break; find = find->nexthash; } if (!find) { @@ -194,24 +213,21 @@ locale_setstring(locale * lang, const char * key, const char * value) find->hashkey = hkey; find->key = strdup(key); find->str = strdup(value); - } - else { - if (strcmp(find->str, value)!=0) { + } else { + if (strcmp(find->str, value) != 0) { log_error(("duplicate translation '%s' for key %s\n", value, key)); } assert(!strcmp(find->str, value) || !"duplicate string for key"); } } -const char * -locale_name(const locale * lang) +const char *locale_name(const locale * lang) { - assert(lang); - return lang->name; + assert(lang); + return lang->name; } -char * -mkname_buf(const char * space, const char * name, char * buffer) +char *mkname_buf(const char *space, const char *name, char *buffer) { if (space && *space) { sprintf(buffer, "%s::%s", space, name); @@ -221,17 +237,16 @@ mkname_buf(const char * space, const char * name, char * buffer) return buffer; } -const char * -mkname(const char * space, const char * name) +const char *mkname(const char *space, const char *name) { - static char zBuffer[128]; /* STATIC_RESULT: used for return, not across calls */ + static char zBuffer[128]; /* STATIC_RESULT: used for return, not across calls */ + return mkname_buf(space, name, zBuffer); } -locale * -nextlocale(const struct locale * lang) +locale *nextlocale(const struct locale * lang) { - return lang->next; + return lang->next; } typedef struct lstr { @@ -240,13 +255,13 @@ typedef struct lstr { static lstr lstrs[MAXLOCALES]; -struct tnode * -get_translations(const struct locale * lang, int index) +struct tnode *get_translations(const struct locale *lang, int index) { assert(lang); - assert(lang->indexindexindex].tokens+index; + assert(lang->index < MAXLOCALES + || "you have to increase MAXLOCALES and recompile"); + if (lang->index < MAXLOCALES) { + return lstrs[lang->index].tokens + index; } - return lstrs[0].tokens+index; + return lstrs[0].tokens + index; } diff --git a/src/util/language.h b/src/util/language.h index a051bc6f0..42e1c81c3 100644 --- a/src/util/language.h +++ b/src/util/language.h @@ -22,46 +22,48 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -struct locale; + struct locale; /** managing multiple locales: **/ -extern struct locale * find_locale(const char * name); -extern struct locale * make_locale(const char * key); + extern struct locale *find_locale(const char *name); + extern struct locale *make_locale(const char *key); /** operations on locales: **/ -extern void locale_setstring(struct locale * lang, const char * key, const char * value); -extern const char * locale_getstring(const struct locale * lang, const char * key); -extern const char * locale_string(const struct locale * lang, const char * key); /* does fallback */ -extern unsigned int locale_hashkey(const struct locale * lang); -extern const char * locale_name(const struct locale * lang); + extern void locale_setstring(struct locale *lang, const char *key, + const char *value); + extern const char *locale_getstring(const struct locale *lang, + const char *key); + extern const char *locale_string(const struct locale *lang, const char *key); /* does fallback */ + extern unsigned int locale_hashkey(const struct locale *lang); + extern const char *locale_name(const struct locale *lang); -extern const char * mkname(const char * namespc, const char * key); -extern char * mkname_buf(const char * namespc, const char * key, char * buffer); + extern const char *mkname(const char *namespc, const char *key); + extern char *mkname_buf(const char *namespc, const char *key, char *buffer); -extern void debug_language(const char * log); -extern void make_locales(const char * str); + extern void debug_language(const char *log); + extern void make_locales(const char *str); #define LOC(lang, s) (lang?locale_string(lang, s):s) -extern struct locale * default_locale; -extern struct locale * locales; -extern struct locale * nextlocale(const struct locale * lang); + extern struct locale *default_locale; + extern struct locale *locales; + extern struct locale *nextlocale(const struct locale *lang); -enum { - UT_PARAMS, - UT_KEYWORDS, - UT_SKILLS, - UT_RACES, - UT_OPTIONS, - UT_DIRECTIONS, - UT_ARCHETYPES, - UT_MAGIC, - UT_TERRAINS, - UT_SPECDIR, - UT_MAX -}; + enum { + UT_PARAMS, + UT_KEYWORDS, + UT_SKILLS, + UT_RACES, + UT_OPTIONS, + UT_DIRECTIONS, + UT_ARCHETYPES, + UT_MAGIC, + UT_TERRAINS, + UT_SPECDIR, + UT_MAX + }; -struct tnode * get_translations(const struct locale * lang, int index); + struct tnode *get_translations(const struct locale *lang, int index); #ifdef __cplusplus } diff --git a/src/util/language_struct.h b/src/util/language_struct.h index 1f09a071b..0818c2da4 100644 --- a/src/util/language_struct.h +++ b/src/util/language_struct.h @@ -9,20 +9,21 @@ #define SMAXHASH 2048 typedef struct locale_str { unsigned int hashkey; - struct locale_str * nexthash; - char * str; - char * key; + struct locale_str *nexthash; + char *str; + char *key; } locale_str; typedef struct locale { int index; - struct locale * next; - unsigned int hashkey; - const char * name; - struct locale_str * strings[SMAXHASH]; + struct locale *next; + unsigned int hashkey; + const char *name; + struct locale_str *strings[SMAXHASH]; } locale; -extern locale * default_locale; -extern locale * locales; +extern locale *default_locale; + +extern locale *locales; #endif diff --git a/src/util/listbox.c b/src/util/listbox.c index 0dfefe4b2..181ac2347 100644 --- a/src/util/listbox.c +++ b/src/util/listbox.c @@ -22,46 +22,52 @@ #include void -insert_selection(list_selection ** p_sel, list_selection * prev, const char * str, void * payload) +insert_selection(list_selection ** p_sel, list_selection * prev, + const char *str, void *payload) { - list_selection * sel = calloc(sizeof(list_selection), 1); + list_selection *sel = calloc(sizeof(list_selection), 1); + sel->str = strdup(str); sel->data = payload; if (*p_sel) { - list_selection * s; + list_selection *s; + sel->next = *p_sel; sel->prev = sel->next->prev; - sel->next->prev=sel; + sel->next->prev = sel; if (sel->prev) { sel->prev->next = sel; - sel->index=sel->prev->index+1; + sel->index = sel->prev->index + 1; } - for (s=sel->next;s;s=s->next) { - s->index = s->prev->index+1; + for (s = sel->next; s; s = s->next) { + s->index = s->prev->index + 1; } *p_sel = sel; } else { *p_sel = sel; sel->prev = prev; - if (prev) sel->index=prev->index+1; + if (prev) + sel->index = prev->index + 1; } } -list_selection ** -push_selection(list_selection ** p_sel, char * str, void * payload) +list_selection **push_selection(list_selection ** p_sel, char *str, + void *payload) { - list_selection * sel = calloc(sizeof(list_selection), 1); - list_selection * prev = NULL; + list_selection *sel = calloc(sizeof(list_selection), 1); + + list_selection *prev = NULL; + sel->str = str; sel->data = payload; while (*p_sel) { prev = *p_sel; - p_sel=&prev->next; + p_sel = &prev->next; } *p_sel = sel; if (prev) { sel->prev = prev; - sel->index = prev->index+1; + sel->index = prev->index + 1; } return p_sel; } @@ -69,36 +75,49 @@ push_selection(list_selection ** p_sel, char * str, void * payload) #define SX (getmaxx(stdscr)) #define SY (getmaxy(stdscr)) -list_selection * -do_selection(list_selection * sel, const char * title, void (*perform)(list_selection *, void *), void * data) +list_selection *do_selection(list_selection * sel, const char *title, + void (*perform) (list_selection *, void *), void *data) { - WINDOW * wn; + WINDOW *wn; + boolean update = true; + list_selection *s; + list_selection *top = sel; + list_selection *current = top; + int i; - int height = 0, width = (int)strlen(title)+8; - for (s=sel;s;s=s->next) { - if ((int)strlen(s->str)>width) width = (int)strlen(s->str); + + int height = 0, width = (int)strlen(title) + 8; + + for (s = sel; s; s = s->next) { + if ((int)strlen(s->str) > width) + width = (int)strlen(s->str); ++height; - if (verbosity>=5) + if (verbosity >= 5) log_info((1, "s %s w %d h %d\n", s->str, width, height)); } - if (height==0 || width==0) return NULL; - if (width+3>SX) width=SX-4; - if (height+2>SY) height=SY-2; + if (height == 0 || width == 0) + return NULL; + if (width + 3 > SX) + width = SX - 4; + if (height + 2 > SY) + height = SY - 2; - if (verbosity>=5) + if (verbosity >= 5) log_info((1, "w %d h %d\n", width, height)); - wn = newwin(height+2, width+4, (SY - height - 2) / 2, (SX - width - 4) / 2); + wn = + newwin(height + 2, width + 4, (SY - height - 2) / 2, (SX - width - 4) / 2); for (;;) { int input; + if (update) { - for (s=top;s!=NULL && top->index+height!=s->index;s=s->next) { - i = s->index-top->index; + for (s = top; s != NULL && top->index + height != s->index; s = s->next) { + i = s->index - top->index; wmove(wn, i + 1, 4); waddnstr(wn, s->str, -1); wclrtoeol(wn); @@ -108,12 +127,12 @@ do_selection(list_selection * sel, const char * title, void (*perform)(list_sele mvwprintw(wn, 0, 2, "[ %s ]", title); update = false; } - i = current->index-top->index; + i = current->index - top->index; wattron(wn, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); wmove(wn, i + 1, 2); waddstr(wn, "->"); wmove(wn, i + 1, 4); - waddnstr(wn, current->str, width-2); + waddnstr(wn, current->str, width - 2); wattroff(wn, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); wrefresh(wn); @@ -126,76 +145,81 @@ do_selection(list_selection * sel, const char * title, void (*perform)(list_sele waddnstr(wn, current->str, width); switch (input) { - case KEY_NPAGE: - for (i=0;i!=height/2;++i) { + case KEY_NPAGE: + for (i = 0; i != height / 2; ++i) { + if (current->next) { + current = current->next; + if (current->index - height >= top->index) { + top = current; + update = true; + } + } + } + break; + case KEY_PPAGE: + for (i = 0; i != height / 2; ++i) { + if (current->prev) { + if (current == top) { + top = sel; + while (top->index + height < current->index) + top = top->next; + update = true; + } + current = current->prev; + } + } + break; + case KEY_DOWN: if (current->next) { current = current->next; - if (current->index-height>=top->index) { - top=current; + if (current->index - height >= top->index) { + top = current; update = true; } } - } - break; - case KEY_PPAGE: - for (i=0;i!=height/2;++i) { + break; + case KEY_UP: if (current->prev) { - if (current==top) { + if (current == top) { top = sel; - while (top->index+heightindex) top=top->next; + while (top->index + height < current->index) + top = top->next; update = true; } current = current->prev; } - } - break; - case KEY_DOWN: - if (current->next) { - current = current->next; - if (current->index-height>=top->index) { - top=current; - update = true; - } - } - break; - case KEY_UP: - if (current->prev) { - if (current==top) { - top = sel; - while (top->index+heightindex) top=top->next; - update = true; - } - current = current->prev; - } - break; - case 27: - case 'q': - delwin(wn); - return NULL; - case 10: - case 13: - if (perform) perform(current, data); - else { + break; + case 27: + case 'q': delwin(wn); - return current; - } - break; - default: - s = current->next; - if (s==NULL) s = top; - while (s!=current) { - if (tolower(s->str[0])==tolower(input)) { - current = s; - update = true; - } else { - s = s->next; - if (s==NULL) s = top; + return NULL; + case 10: + case 13: + if (perform) + perform(current, data); + else { + delwin(wn); + return current; + } + break; + default: + s = current->next; + if (s == NULL) + s = top; + while (s != current) { + if (tolower(s->str[0]) == tolower(input)) { + current = s; + update = true; + } else { + s = s->next; + if (s == NULL) + s = top; + } + } + if (current->index - height >= top->index) { + top = current; + update = true; } - } - if (current->index-height>=top->index) { - top=current; - update = true; - } } } } diff --git a/src/util/listbox.h b/src/util/listbox.h index ab2c7f9bc..4c2d74428 100644 --- a/src/util/listbox.h +++ b/src/util/listbox.h @@ -2,15 +2,19 @@ #define CURSES_LISTBOX typedef struct list_selection { - struct list_selection * next; - struct list_selection * prev; + struct list_selection *next; + struct list_selection *prev; int index; - char * str; - void * data; + char *str; + void *data; } list_selection; -extern struct list_selection * do_selection(struct list_selection * sel, const char * title, void (*perform)(struct list_selection *, void *), void * data); -extern struct list_selection ** push_selection(struct list_selection ** p_sel, char * str, void * payload); -extern void insert_selection(struct list_selection ** p_sel, struct list_selection * prev, const char * str, void * payload); +extern struct list_selection *do_selection(struct list_selection *sel, + const char *title, void (*perform) (struct list_selection *, void *), + void *data); +extern struct list_selection **push_selection(struct list_selection **p_sel, + char *str, void *payload); +extern void insert_selection(struct list_selection **p_sel, + struct list_selection *prev, const char *str, void *payload); #endif /* CURSES_LISTBOX */ diff --git a/src/util/lists.c b/src/util/lists.c index 4c4173cb5..da997bcd3 100644 --- a/src/util/lists.c +++ b/src/util/lists.c @@ -23,21 +23,21 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "lists.h" typedef struct void_list { - struct void_list * next; - void * data; + struct void_list *next; + void *data; } void_list; -void -addlist(void *l1, void *p1) +void addlist(void *l1, void *p1) { /* add entry p to the end of list l */ void_list **l; + void_list *p, *q; - l = (void_list **)l1; - p = (void_list *)p1; + l = (void_list **) l1; + p = (void_list *) p1; assert(p->next == 0); if (*l) { @@ -48,10 +48,10 @@ addlist(void *l1, void *p1) *l = p; } -static void -choplist(void * a, void * b) +static void choplist(void *a, void *b) { - void_list **l = (void_list**)a, *p = (void_list*)b; + void_list **l = (void_list **) a, *p = (void_list *) b; + /* remove entry p from list l - when called, a pointer to p must be * kept in order to use (and free) p; if omitted, this will be a * memory leak */ @@ -67,8 +67,7 @@ choplist(void * a, void * b) } } -void -translist(void *l1, void *l2, void *p) +void translist(void *l1, void *l2, void *p) { /* remove entry p from list l1 and add it at the end of list l2 */ @@ -77,8 +76,7 @@ translist(void *l1, void *l2, void *p) addlist(l2, p); } -void -insertlist(void_list ** l, void_list * p) +void insertlist(void_list ** l, void_list * p) { /* insert entry p at the beginning of list l */ @@ -88,8 +86,7 @@ insertlist(void_list ** l, void_list * p) } -void -removelist(void *l, void *p) +void removelist(void *l, void *p) { /* remove entry p from list l; free p */ @@ -98,15 +95,14 @@ removelist(void *l, void *p) free(p); } -void -freelist(void *p1) +void freelist(void *p1) { /* remove all entries following and including entry p from a listlist */ void_list *p, *p2; - p = (void_list *)p1; + p = (void_list *) p1; while (p) { p2 = p->next; @@ -115,15 +111,15 @@ freelist(void *p1) } } -unsigned int -listlen(void *l) +unsigned int listlen(void *l) { /* count entries p in list l */ unsigned int i; + void_list *p; - for (p = (void_list *)l, i = 0; p; p = p->next, i++); + for (p = (void_list *) l, i = 0; p; p = p->next, i++) ; return i; } diff --git a/src/util/lists.h b/src/util/lists.h index 848831817..b12edd316 100644 --- a/src/util/lists.h +++ b/src/util/lists.h @@ -24,17 +24,17 @@ extern "C" { #include -void addlist(void *l1, void *p1); -void translist(void *l1, void *l2, void *p); + void addlist(void *l1, void *p1); + void translist(void *l1, void *l2, void *p); #ifndef MALLOCDBG -void freelist(void *p1); -void removelist(void *l, void *p); + void freelist(void *p1); + void removelist(void *l, void *p); #else #define freelist(p) { while (p) { void * p2 = p->next; free(p); p = p2; } } #define removelist(l,p) { choplist(l, p); free(p); } #endif -unsigned int listlen(void *l); + unsigned int listlen(void *l); #ifdef __cplusplus } diff --git a/src/util/log.c b/src/util/log.c index 93203d54a..c13c5bf6c 100644 --- a/src/util/log.c +++ b/src/util/log.c @@ -20,60 +20,64 @@ without prior permission by the authors of Eressea. #include /* TODO: set from external function */ -int log_flags = LOG_FLUSH|LOG_CPERROR|LOG_CPWARNING; +int log_flags = LOG_FLUSH | LOG_CPERROR | LOG_CPWARNING; + #ifdef STDIO_CP static int stdio_codepage = STDIO_CP; #else static int stdio_codepage = 0; #endif -static FILE * logfile; +static FILE *logfile; -#define MAXLENGTH 4096 /* because I am lazy, CP437 output is limited to this many chars */ -void -log_flush(void) +#define MAXLENGTH 4096 /* because I am lazy, CP437 output is limited to this many chars */ +void log_flush(void) { fflush(logfile); } -void -log_puts(const char * str) +void log_puts(const char *str) { fflush(stdout); - if (!logfile) logfile = stderr; + if (!logfile) + logfile = stderr; fputs(str, logfile); } static int -cp_convert(const char * format, char * buffer, size_t length, int codepage) +cp_convert(const char *format, char *buffer, size_t length, int codepage) { /* when console output on MSDOS, convert to codepage */ - const char * input = format; - char * pos = buffer; + const char *input = format; - while (pos+1=level) { + if (!logfile) + logfile = stderr; + if (logfile_level >= level) { fprintf(logfile, "INFO[%u]: ", level); va_start(marker, format); vfprintf(logfile, format, marker); va_end(marker); - if (logfile!=stderr) { - if (stderr_level>=level) { - fprintf(stderr, "INFO[%u]: ", level); - va_start(marker, format); - if (stdio_codepage) { - char buffer[MAXLENGTH]; - char converted[MAXLENGTH]; + if (logfile != stderr) { + if (stderr_level >= level) { + fprintf(stderr, "INFO[%u]: ", level); + va_start(marker, format); + if (stdio_codepage) { + char buffer[MAXLENGTH]; - vsnprintf(buffer, sizeof(buffer), format, marker); - if (cp_convert(buffer, converted, MAXLENGTH, stdio_codepage)==0) { - fputs(converted, stderr); - } else { - /* fall back to non-converted output */ - va_end(marker); - va_start(marker, format); - vfprintf(stderr, format, marker); - } - } else { - vfprintf(stderr, format, marker); - } - va_end(marker); - } - if (log_flags & LOG_FLUSH) { - log_flush(); - } + char converted[MAXLENGTH]; + + vsnprintf(buffer, sizeof(buffer), format, marker); + if (cp_convert(buffer, converted, MAXLENGTH, stdio_codepage) == 0) { + fputs(converted, stderr); + } else { + /* fall back to non-converted output */ + va_end(marker); + va_start(marker, format); + vfprintf(stderr, format, marker); + } + } else { + vfprintf(stderr, format, marker); + } + va_end(marker); + } + if (log_flags & LOG_FLUSH) { + log_flush(); + } } } } diff --git a/src/util/log.h b/src/util/log.h index 87a35dfee..a9e8eabd3 100644 --- a/src/util/log.h +++ b/src/util/log.h @@ -15,21 +15,21 @@ without prior permission by the authors of Eressea. extern "C" { #endif - extern void log_open(const char * filename); - extern void log_printf(const char * str, ...); - extern void log_puts(const char * str); + extern void log_open(const char *filename); + extern void log_printf(const char *str, ...); + extern void log_puts(const char *str); extern void log_close(void); extern void log_flush(void); - extern void log_stdio(FILE * io, const char * format, ...); + extern void log_stdio(FILE * io, const char *format, ...); #define log_warning(x) _log_warn x #define log_error(x) _log_error x #define log_info(x) _log_info x /* use macros above instead of these: */ - extern void _log_warn(const char * format, ...); - extern void _log_error(const char * format, ...); - extern void _log_info(unsigned int flag, const char * format, ...); + extern void _log_warn(const char *format, ...); + extern void _log_error(const char *format, ...); + extern void _log_info(unsigned int flag, const char *format, ...); #define LOG_FLUSH 0x01 #define LOG_CPWARNING 0x02 diff --git a/src/util/message.c b/src/util/message.c index 2fdeb14ba..49fd0300e 100644 --- a/src/util/message.c +++ b/src/util/message.c @@ -25,80 +25,89 @@ #include #include -void (*msg_log_create)(const struct message * msg) = 0; +void (*msg_log_create) (const struct message * msg) = 0; -const char * -mt_name(const message_type* mtype) +const char *mt_name(const message_type * mtype) { return mtype->name; } -message_type * -mt_new(const char * name, const char * args[]) +message_type *mt_new(const char *name, const char *args[]) { int i, nparameters = 0; - message_type * mtype = (message_type *)malloc(sizeof(message_type)); - assert(name!=NULL); - if (name==NULL) { + message_type *mtype = (message_type *) malloc(sizeof(message_type)); + + assert(name != NULL); + if (name == NULL) { log_error(("Trying to create message_type with name=0x0\n")); return NULL; } - if (args!=NULL) for (nparameters=0;args[nparameters];++nparameters); + if (args != NULL) + for (nparameters = 0; args[nparameters]; ++nparameters) ; mtype->name = strdup(name); mtype->nparameters = nparameters; if (nparameters > 0) { - mtype->pnames = (const char**)malloc(sizeof(char*) * nparameters); - mtype->types = (const arg_type**)malloc(sizeof(arg_type*) * nparameters); + mtype->pnames = (const char **)malloc(sizeof(char *) * nparameters); + mtype->types = (const arg_type **)malloc(sizeof(arg_type *) * nparameters); } else { mtype->pnames = NULL; mtype->types = NULL; } - if (args!=NULL) for (i=0;args[i];++i) { - const char * x = args[i]; - const char * spos = strchr(x, ':'); - if (spos==NULL) { - mtype->pnames[i] = strdup(x); - mtype->types[i] = NULL; - } else { - char * cp = strncpy((char*)malloc(spos-x+1), x, spos-x); - cp[spos-x] = '\0'; - mtype->pnames[i] = cp; - mtype->types[i] = find_argtype(spos+1); - if (mtype->types[i]==NULL) { - log_error(("unknown argument type %s for message type %s\n", - spos+1, mtype->name)); + if (args != NULL) + for (i = 0; args[i]; ++i) { + const char *x = args[i]; + + const char *spos = strchr(x, ':'); + + if (spos == NULL) { + mtype->pnames[i] = strdup(x); + mtype->types[i] = NULL; + } else { + char *cp = strncpy((char *)malloc(spos - x + 1), x, spos - x); + + cp[spos - x] = '\0'; + mtype->pnames[i] = cp; + mtype->types[i] = find_argtype(spos + 1); + if (mtype->types[i] == NULL) { + log_error(("unknown argument type %s for message type %s\n", + spos + 1, mtype->name)); + } + assert(mtype->types[i]); } - assert(mtype->types[i]); } - } return mtype; } -message_type * -mt_new_va(const char * name, ...) +message_type *mt_new_va(const char *name, ...) { - const char * args[16]; + const char *args[16]; + int i = 0; + va_list marker; va_start(marker, name); for (;;) { - const char * c = va_arg(marker, const char*); + const char *c = va_arg(marker, const char *); + args[i++] = c; - if (c==NULL) break; + if (c == NULL) + break; } va_end(marker); return mt_new(name, args); } -arg_type * argtypes = NULL; +arg_type *argtypes = NULL; void -register_argtype(const char * name, void(*free_arg)(variant), variant (*copy_arg)(variant), variant_type type) +register_argtype(const char *name, void (*free_arg) (variant), + variant(*copy_arg) (variant), variant_type type) { - arg_type * atype = (arg_type *)malloc(sizeof(arg_type)); + arg_type *atype = (arg_type *) malloc(sizeof(arg_type)); + atype->name = name; atype->next = argtypes; atype->release = free_arg; @@ -107,122 +116,124 @@ register_argtype(const char * name, void(*free_arg)(variant), variant (*copy_arg argtypes = atype; } -const arg_type * -find_argtype(const char * name) +const arg_type *find_argtype(const char *name) { - arg_type * atype = argtypes; - while (atype!=NULL) { - if (strcmp(atype->name, name)==0) return atype; + arg_type *atype = argtypes; + + while (atype != NULL) { + if (strcmp(atype->name, name) == 0) + return atype; atype = atype->next; } return NULL; } -static variant -copy_arg(const arg_type * atype, variant data) +static variant copy_arg(const arg_type * atype, variant data) { - assert(atype!=NULL); - if (atype->copy==NULL) return data; + assert(atype != NULL); + if (atype->copy == NULL) + return data; return atype->copy(data); } -static void -free_arg(const arg_type * atype, variant data) +static void free_arg(const arg_type * atype, variant data) { - assert(atype!=NULL); - if (atype->release) atype->release(data); + assert(atype != NULL); + if (atype->release) + atype->release(data); } -message * -msg_create(const struct message_type * mtype, variant args[]) +message *msg_create(const struct message_type *mtype, variant args[]) { int i; - message * msg = (message *)malloc(sizeof(message)); - assert(mtype!=NULL); - if (mtype==NULL) { + message *msg = (message *) malloc(sizeof(message)); + + assert(mtype != NULL); + if (mtype == NULL) { log_error(("Trying to create message with type=0x0\n")); return NULL; } msg->type = mtype; - msg->parameters = (variant*)calloc(mtype->nparameters, sizeof(variant)); - msg->refcount=1; - for (i=0;i!=mtype->nparameters;++i) { + msg->parameters = (variant *) calloc(mtype->nparameters, sizeof(variant)); + msg->refcount = 1; + for (i = 0; i != mtype->nparameters; ++i) { msg->parameters[i] = copy_arg(mtype->types[i], args[i]); } - if (msg_log_create) msg_log_create(msg); + if (msg_log_create) + msg_log_create(msg); return msg; } #define MT_MAXHASH 1021 -static quicklist * messagetypes[MT_MAXHASH]; +static quicklist *messagetypes[MT_MAXHASH]; -const message_type * -mt_find(const char * name) +const message_type *mt_find(const char *name) { unsigned int hash = hashstring(name) % MT_MAXHASH; - quicklist * ql = messagetypes[hash]; + + quicklist *ql = messagetypes[hash]; + int qi; - for (qi=0;ql;ql_advance(&ql, &qi, 1)) { - message_type * data = (message_type *)ql_get(ql, qi); - if (strcmp(data->name, name)==0) { + for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { + message_type *data = (message_type *) ql_get(ql, qi); + + if (strcmp(data->name, name) == 0) { return data; } } return 0; } -static unsigned int -mt_id(const message_type * mtype) +static unsigned int mt_id(const message_type * mtype) { unsigned int key = 0; + size_t i = strlen(mtype->name); - while (i>0) { - key = (mtype->name[--i] + key*37); + while (i > 0) { + key = (mtype->name[--i] + key * 37); } return key % 0x7FFFFFFF; } -const message_type * -mt_register(message_type * type) +const message_type *mt_register(message_type * type) { unsigned int hash = hashstring(type->name) % MT_MAXHASH; - quicklist ** qlp = messagetypes+hash; - if (ql_set_insert(qlp, type)==0) { + quicklist **qlp = messagetypes + hash; + + if (ql_set_insert(qlp, type) == 0) { type->key = mt_id(type); } return type; } -void -msg_free(message *msg) +void msg_free(message * msg) { int i; - assert(msg->refcount==0); - for (i=0;i!=msg->type->nparameters;++i) { + + assert(msg->refcount == 0); + for (i = 0; i != msg->type->nparameters; ++i) { free_arg(msg->type->types[i], msg->parameters[i]); } - free((void*)msg->parameters); + free((void *)msg->parameters); free(msg); } -void -msg_release(struct message * msg) +void msg_release(struct message *msg) { - assert(msg->refcount>0); - if (--msg->refcount>0) return; + assert(msg->refcount > 0); + if (--msg->refcount > 0) + return; msg_free(msg); } -struct message * -msg_addref(struct message * msg) +struct message *msg_addref(struct message *msg) { - assert(msg->refcount>0); + assert(msg->refcount > 0); ++msg->refcount; return msg; } - diff --git a/src/util/message.h b/src/util/message.h index 021283903..b5fb81185 100644 --- a/src/util/message.h +++ b/src/util/message.h @@ -18,52 +18,54 @@ extern "C" { #endif -struct locale; + struct locale; -typedef struct arg_type { - struct arg_type * next; - variant_type vtype; - const char * name; - void (*release)(variant); - variant (*copy)(variant); -} arg_type; + typedef struct arg_type { + struct arg_type *next; + variant_type vtype; + const char *name; + void (*release) (variant); + variant(*copy) (variant); + } arg_type; -typedef struct message_type { - unsigned int key; - const char * name; - int nparameters; - const char ** pnames; - const struct arg_type ** types; -} message_type; + typedef struct message_type { + unsigned int key; + const char *name; + int nparameters; + const char **pnames; + const struct arg_type **types; + } message_type; -typedef struct message { - const struct message_type * type; - variant * parameters; - int refcount; -} message; + typedef struct message { + const struct message_type *type; + variant *parameters; + int refcount; + } message; -extern struct message_type * mt_new(const char * name, const char ** args); -extern struct message_type * mt_new_va(const char * name, ...); - /* mt_new("simple_sentence", "subject:string", "predicate:string", - * "object:string", "lang:locale", NULL); */ + extern struct message_type *mt_new(const char *name, const char **args); + extern struct message_type *mt_new_va(const char *name, ...); + /* mt_new("simple_sentence", "subject:string", "predicate:string", + * "object:string", "lang:locale", NULL); */ -extern struct message * msg_create(const struct message_type * type, variant args[]); - /* msg_create(&mt_simplesentence, "enno", "eats", "chocolate", &locale_de); - * parameters must be in the same order as they were for mt_new! */ + extern struct message *msg_create(const struct message_type *type, + variant args[]); + /* msg_create(&mt_simplesentence, "enno", "eats", "chocolate", &locale_de); + * parameters must be in the same order as they were for mt_new! */ -extern void msg_release(struct message * msg); -extern struct message * msg_addref(struct message * msg); + extern void msg_release(struct message *msg); + extern struct message *msg_addref(struct message *msg); -extern const char * mt_name(const struct message_type* mtype); + extern const char *mt_name(const struct message_type *mtype); /** message_type registry (optional): **/ -extern const struct message_type * mt_register(struct message_type *); -extern const struct message_type * mt_find(const char *); + extern const struct message_type *mt_register(struct message_type *); + extern const struct message_type *mt_find(const char *); -extern void register_argtype(const char * name, void(*free_arg)(variant), variant (*copy_arg)(variant), variant_type); -extern const struct arg_type * find_argtype(const char * name); + extern void register_argtype(const char *name, void (*free_arg) (variant), + variant(*copy_arg) (variant), variant_type); + extern const struct arg_type *find_argtype(const char *name); -extern void (*msg_log_create)(const struct message * msg); + extern void (*msg_log_create) (const struct message * msg); #ifdef __cplusplus } diff --git a/src/util/nrmessage.c b/src/util/nrmessage.c index 0086159d5..3612d7c73 100644 --- a/src/util/nrmessage.c +++ b/src/util/nrmessage.c @@ -29,25 +29,29 @@ #include #define NRT_MAXHASH 1021 -static nrmessage_type * nrtypes[NRT_MAXHASH]; +static nrmessage_type *nrtypes[NRT_MAXHASH]; -const char * -nrt_string(const struct nrmessage_type *type) +const char *nrt_string(const struct nrmessage_type *type) { return type->string; } -nrmessage_type * -nrt_find(const struct locale * lang, const struct message_type * mtype) +nrmessage_type *nrt_find(const struct locale * lang, + const struct message_type * mtype) { - nrmessage_type * found = NULL; + nrmessage_type *found = NULL; + unsigned int hash = hashstring(mtype->name) % NRT_MAXHASH; - nrmessage_type * type = nrtypes[hash]; + + nrmessage_type *type = nrtypes[hash]; + while (type) { - if (type->mtype==mtype) { - if (found==NULL) found = type; - else if (type->lang==NULL) found = type; - if (lang==type->lang) { + if (type->mtype == mtype) { + if (found == NULL) + found = type; + else if (type->lang == NULL) + found = type; + if (lang == type->lang) { found = type; break; } @@ -56,40 +60,47 @@ nrt_find(const struct locale * lang, const struct message_type * mtype) } if (!found) { log_warning(("could not find nr-type %s for locale %s\n", - mtype->name, locale_name(lang))); + mtype->name, locale_name(lang))); } - if (lang && found && found->lang!=lang) { + if (lang && found && found->lang != lang) { log_warning(("could not find nr-type %s for locale %s, using %s\n", - mtype->name, locale_name(lang), locale_name(found->lang))); + mtype->name, locale_name(lang), locale_name(found->lang))); } return found; } -nrsection * sections; +nrsection *sections; -const nrsection * -section_find(const char * name) +const nrsection *section_find(const char *name) { - nrsection ** mcp = §ions; - if (name==NULL) return NULL; - for (;*mcp;mcp=&(*mcp)->next) { - nrsection * mc = *mcp; - if (!strcmp(mc->name, name)) break; + nrsection **mcp = §ions; + + if (name == NULL) + return NULL; + for (; *mcp; mcp = &(*mcp)->next) { + nrsection *mc = *mcp; + + if (!strcmp(mc->name, name)) + break; } return *mcp; } -const nrsection * -section_add(const char * name) +const nrsection *section_add(const char *name) { - nrsection ** mcp = §ions; - if (name==NULL) return NULL; - for (;*mcp;mcp=&(*mcp)->next) { - nrsection * mc = *mcp; - if (!strcmp(mc->name, name)) break; + nrsection **mcp = §ions; + + if (name == NULL) + return NULL; + for (; *mcp; mcp = &(*mcp)->next) { + nrsection *mc = *mcp; + + if (!strcmp(mc->name, name)) + break; } if (!*mcp) { - nrsection * mc = calloc(sizeof(nrsection), 1); + nrsection *mc = calloc(sizeof(nrsection), 1); + mc->name = strdup(name); *mcp = mc; } @@ -97,11 +108,14 @@ section_add(const char * name) } void -nrt_register(const struct message_type * mtype, const struct locale * lang, const char * string, int level, const char * section) +nrt_register(const struct message_type *mtype, const struct locale *lang, + const char *string, int level, const char *section) { unsigned int hash = hashstring(mtype->name) % NRT_MAXHASH; - nrmessage_type * nrt = nrtypes[hash]; - while (nrt && (nrt->lang!=lang || nrt->mtype!=mtype)) { + + nrmessage_type *nrt = nrtypes[hash]; + + while (nrt && (nrt->lang != lang || nrt->mtype != mtype)) { nrt = nrt->next; } if (nrt) { @@ -109,66 +123,73 @@ nrt_register(const struct message_type * mtype, const struct locale * lang, cons assert(!nrt || !"trying to register same nr-type twice"); } else { int i; + char zNames[256]; - char * c = zNames; + + char *c = zNames; + nrt = malloc(sizeof(nrmessage_type)); nrt->lang = lang; nrt->mtype = mtype; nrt->next = nrtypes[hash]; - nrt->level=level; + nrt->level = level; if (section) { - const nrsection * s = section_find(section); - if (s==NULL) { + const nrsection *s = section_find(section); + + if (s == NULL) { s = section_add(section); } nrt->section = s->name; - } - else nrt->section = NULL; + } else + nrt->section = NULL; nrtypes[hash] = nrt; assert(string && *string); nrt->string = strdup(string); *c = '\0'; - for (i=0;i!=mtype->nparameters;++i) { - if (i!=0) *c++ = ' '; - c+= strlen(strcpy(c, mtype->pnames[i])); + for (i = 0; i != mtype->nparameters; ++i) { + if (i != 0) + *c++ = ' '; + c += strlen(strcpy(c, mtype->pnames[i])); } nrt->vars = strdup(zNames); } } size_t -nr_render(const struct message * msg, const struct locale * lang, char * buffer, size_t size, const void * userdata) +nr_render(const struct message *msg, const struct locale *lang, char *buffer, + size_t size, const void *userdata) { - struct nrmessage_type * nrt = nrt_find(lang, msg->type); + struct nrmessage_type *nrt = nrt_find(lang, msg->type); if (nrt) { - const char * m = translate(nrt->string, userdata, nrt->vars, msg->parameters); + const char *m = + translate(nrt->string, userdata, nrt->vars, msg->parameters); if (m) { - return strlcpy((char*)buffer, m, size); + return strlcpy((char *)buffer, m, size); } else { log_error(("Couldn't render message %s\n", nrt->mtype->name)); } } - if (size>0 && buffer) buffer[0] = 0; + if (size > 0 && buffer) + buffer[0] = 0; return 0; } -int -nr_level(const struct message *msg) +int nr_level(const struct message *msg) { - nrmessage_type * nrt = nrt_find(NULL, msg->type); - return nrt?nrt->level:0; + nrmessage_type *nrt = nrt_find(NULL, msg->type); + + return nrt ? nrt->level : 0; } -const char * -nr_section(const struct message *msg) +const char *nr_section(const struct message *msg) { - nrmessage_type * nrt = nrt_find(default_locale, msg->type); - return nrt?nrt->section:NULL; + nrmessage_type *nrt = nrt_find(default_locale, msg->type); + + return nrt ? nrt->section : NULL; } -const char * -nrt_section(const nrmessage_type * nrt) +const char *nrt_section(const nrmessage_type * nrt) { - return nrt?nrt->section:NULL; + return nrt ? nrt->section : NULL; } diff --git a/src/util/nrmessage.h b/src/util/nrmessage.h index f36d8e79f..c73e8ee7c 100644 --- a/src/util/nrmessage.h +++ b/src/util/nrmessage.h @@ -16,30 +16,30 @@ extern "C" { #endif -struct locale; -struct message; -struct message_type; -struct nrmessage_type; + struct locale; + struct message; + struct message_type; + struct nrmessage_type; -typedef struct nrsection { - char * name; - struct nrsection * next; -} nrsection; + typedef struct nrsection { + char *name; + struct nrsection *next; + } nrsection; -extern nrsection * sections; + extern nrsection *sections; -extern void nrt_register(const struct message_type * mtype, - const struct locale * lang, const char * script, - int level, const char * section); -extern struct nrmessage_type * nrt_find(const struct locale *, - const struct message_type *); -extern const char * nrt_string(const struct nrmessage_type *type); -extern const char * nrt_section(const struct nrmessage_type * mt); + extern void nrt_register(const struct message_type *mtype, + const struct locale *lang, const char *script, + int level, const char *section); + extern struct nrmessage_type *nrt_find(const struct locale *, + const struct message_type *); + extern const char *nrt_string(const struct nrmessage_type *type); + extern const char *nrt_section(const struct nrmessage_type *mt); -extern size_t nr_render(const struct message * msg, const struct locale * lang, - char * buffer, size_t size, const void * userdata); -extern int nr_level(const struct message *msg); -extern const char * nr_section(const struct message *msg); + extern size_t nr_render(const struct message *msg, const struct locale *lang, + char *buffer, size_t size, const void *userdata); + extern int nr_level(const struct message *msg); + extern const char *nr_section(const struct message *msg); /* before: diff --git a/src/util/nrmessage_struct.h b/src/util/nrmessage_struct.h index ac14bef82..6a3a1d9b0 100644 --- a/src/util/nrmessage_struct.h +++ b/src/util/nrmessage_struct.h @@ -6,15 +6,15 @@ * do something BAD. */ typedef struct nrmessage_type { - const struct message_type * mtype; - const struct locale * lang; - const char * string; - const char * vars; - struct nrmessage_type * next; - int level; - const char * section; + const struct message_type *mtype; + const struct locale *lang; + const char *string; + const char *vars; + struct nrmessage_type *next; + int level; + const char *section; } nrmessage_type; -extern nrmessage_type * get_nrmessagetypes(void); +extern nrmessage_type *get_nrmessagetypes(void); #endif diff --git a/src/util/os.c b/src/util/os.c index 263b44e42..1278e0f7c 100644 --- a/src/util/os.c +++ b/src/util/os.c @@ -2,16 +2,20 @@ #if defined(WIN32) #include -#else +#else /* */ #include -#endif - -int os_mkdir(const char * path, int mode) -{ +#endif /* */ + int os_mkdir(const char *path, int mode) +{ + #ifdef WIN32 - mode = mode; - return _mkdir(path); -#else /* POSIX is our last hope */ - return mkdir(path, (mode_t)mode); -#endif -} + mode = mode; + return _mkdir(path); + +#else /* POSIX is our last hope */ + return mkdir(path, (mode_t) mode); + +#endif /* */ +} + + diff --git a/src/util/os.h b/src/util/os.h index 64e17e5e9..cf4bb06ea 100644 --- a/src/util/os.h +++ b/src/util/os.h @@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif - extern int os_mkdir(const char * path, int mode); + extern int os_mkdir(const char *path, int mode); #ifdef __cplusplus } #endif diff --git a/src/util/parser.c b/src/util/parser.c index 1dfff3798..d5ef5cfcc 100644 --- a/src/util/parser.c +++ b/src/util/parser.c @@ -13,106 +13,115 @@ typedef struct parser_state { const char *current_token; - char * current_cmd; - struct parser_state * next; + char *current_cmd; + struct parser_state *next; } parser_state; -static parser_state * state; +static parser_state *state; -static int -eatwhitespace_c(const char ** str_p) +static int eatwhitespace_c(const char **str_p) { int ret = 0; + ucs4_t ucs; + size_t len; - const char * str = *str_p; + + const char *str = *str_p; /* skip over potential whitespace */ for (;;) { unsigned char utf8_character = (unsigned char)*str; + if (~utf8_character & 0x80) { - if (!iswxspace(utf8_character)) break; + if (!iswxspace(utf8_character)) + break; ++str; } else { ret = unicode_utf8_to_ucs4(&ucs, str, &len); - if (ret!=0) { + if (ret != 0) { log_warning(("illegal character sequence in UTF8 string: %s\n", str)); break; } - if (!iswxspace((wint_t)ucs)) break; - str+=len; + if (!iswxspace((wint_t) ucs)) + break; + str += len; } } *str_p = str; return ret; } -void -init_tokens_str(const char * initstr, char * cmd) +void init_tokens_str(const char *initstr, char *cmd) { - if (state==NULL) { + if (state == NULL) { state = malloc(sizeof(parser_state)); - } - else if (state->current_cmd) free(state->current_cmd); + } else if (state->current_cmd) + free(state->current_cmd); state->current_cmd = cmd; state->current_token = initstr; } -void -parser_pushstate(void) +void parser_pushstate(void) { - parser_state * new_state = malloc(sizeof(parser_state)); + parser_state *new_state = malloc(sizeof(parser_state)); + new_state->current_cmd = NULL; new_state->current_token = NULL; new_state->next = state; state = new_state; } -void -parser_popstate(void) +void parser_popstate(void) { - parser_state * new_state = state->next; - if (state->current_cmd!=NULL) free(state->current_cmd); + parser_state *new_state = state->next; + + if (state->current_cmd != NULL) + free(state->current_cmd); free(state); state = new_state; } -boolean -parser_end(void) +boolean parser_end(void) { eatwhitespace_c(&state->current_token); return *state->current_token == 0; } -void -skip_token(void) +void skip_token(void) { char quotechar = 0; + eatwhitespace_c(&state->current_token); while (*state->current_token) { ucs4_t ucs; + size_t len; unsigned char utf8_character = (unsigned char)state->current_token[0]; + if (~utf8_character & 0x80) { ucs = utf8_character; ++state->current_token; } else { int ret = unicode_utf8_to_ucs4(&ucs, state->current_token, &len); - if (ret==0) { - state->current_token+=len; + + if (ret == 0) { + state->current_token += len; } else { - log_warning(("illegal character sequence in UTF8 string: %s\n", state->current_token)); + log_warning(("illegal character sequence in UTF8 string: %s\n", + state->current_token)); } } - if (iswxspace((wint_t)ucs) && quotechar==0) { + if (iswxspace((wint_t) ucs) && quotechar == 0) { return; } else { - switch(utf8_character) { + switch (utf8_character) { case '"': case '\'': - if (utf8_character==quotechar) return; + if (utf8_character == quotechar) + return; quotechar = utf8_character; break; case ESCAPE_CHAR: @@ -123,54 +132,63 @@ skip_token(void) } } -const char * -parse_token(const char ** str) +const char *parse_token(const char **str) { - static char lbuf[MAXTOKENSIZE]; /* STATIC_RESULT: used for return, not across calls */ - char * cursor = lbuf; + static char lbuf[MAXTOKENSIZE]; /* STATIC_RESULT: used for return, not across calls */ + + char *cursor = lbuf; + char quotechar = 0; + boolean escape = false; - const char * ctoken = *str; + + const char *ctoken = *str; assert(ctoken); eatwhitespace_c(&ctoken); - while (*ctoken && cursor-lbuf < MAXTOKENSIZE-1) { + while (*ctoken && cursor - lbuf < MAXTOKENSIZE - 1) { ucs4_t ucs; + size_t len; + boolean copy = false; unsigned char utf8_character = *(unsigned char *)ctoken; + if (~utf8_character & 0x80) { ucs = utf8_character; len = 1; } else { int ret = unicode_utf8_to_ucs4(&ucs, ctoken, &len); - if (ret!=0) { - log_warning(("illegal character sequence in UTF8 string: %s\n", ctoken)); + + if (ret != 0) { + log_warning(("illegal character sequence in UTF8 string: %s\n", + ctoken)); break; } } if (escape) { copy = true; escape = false; - } else if (iswxspace((wint_t)ucs)) { - if (quotechar==0) break; + } else if (iswxspace((wint_t) ucs)) { + if (quotechar == 0) + break; copy = true; - } else if (utf8_character=='"' || utf8_character=='\'') { - if (utf8_character==quotechar) { + } else if (utf8_character == '"' || utf8_character == '\'') { + if (utf8_character == quotechar) { ++ctoken; break; - } else if (quotechar==0) { + } else if (quotechar == 0) { quotechar = utf8_character; ++ctoken; } else { *cursor++ = *ctoken++; } - } else if (utf8_character==SPACE_REPLACEMENT) { + } else if (utf8_character == SPACE_REPLACEMENT) { *cursor++ = ' '; ++ctoken; - } else if (utf8_character==ESCAPE_CHAR) { + } else if (utf8_character == ESCAPE_CHAR) { escape = true; ++ctoken; } else { @@ -178,8 +196,8 @@ parse_token(const char ** str) } if (copy) { memcpy(cursor, ctoken, len); - cursor+=len; - ctoken+=len; + cursor += len; + ctoken += len; } } @@ -188,8 +206,7 @@ parse_token(const char ** str) return lbuf; } -const char * -getstrtoken(void) +const char *getstrtoken(void) { return parse_token((const char **)&state->current_token); } diff --git a/src/util/parser.h b/src/util/parser.h index fecb5ff9f..dc1ab3717 100644 --- a/src/util/parser.h +++ b/src/util/parser.h @@ -14,16 +14,15 @@ extern "C" { #endif -extern void init_tokens_str(const char * initstr, char * cmd); /* initialize token parsing, take ownership of cmd */ -extern void skip_token(void); -extern const char * parse_token(const char ** str); -extern void parser_pushstate(void); -extern void parser_popstate(void); -extern boolean parser_end(void); -extern const char *getstrtoken(void); + extern void init_tokens_str(const char *initstr, char *cmd); /* initialize token parsing, take ownership of cmd */ + extern void skip_token(void); + extern const char *parse_token(const char **str); + extern void parser_pushstate(void); + extern void parser_popstate(void); + extern boolean parser_end(void); + extern const char *getstrtoken(void); #ifdef __cplusplus } #endif - #endif diff --git a/src/util/quicklist.c b/src/util/quicklist.c index 8356106ca..3346377c1 100644 --- a/src/util/quicklist.c +++ b/src/util/quicklist.c @@ -19,45 +19,54 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -#define QL_MAXSIZE 14 /* total struct is 64 bytes */ +#define QL_MAXSIZE 14 /* total struct is 64 bytes */ #define QL_LIMIT 8 struct quicklist { - struct quicklist * next; + struct quicklist *next; int num_elements; - void * elements[QL_MAXSIZE]; + void *elements[QL_MAXSIZE]; }; -void * ql_get(const quicklist * ql, int index) { - return (ql && indexnum_elements)?ql->elements[index]:ql_get(ql->next, index-ql->num_elements); +void *ql_get(const quicklist * ql, int index) +{ + return (ql + && index < ql->num_elements) ? ql->elements[index] : ql_get(ql->next, + index - ql->num_elements); } -void * ql_replace(quicklist * ql, int index, void * data) { - if (ql && indexnum_elements) { - void * orig = ql->elements[index]; +void *ql_replace(quicklist * ql, int index, void *data) +{ + if (ql && index < ql->num_elements) { + void *orig = ql->elements[index]; + ql->elements[index] = data; return orig; } else { - return ql_replace(ql->next, index-ql->num_elements, data); + return ql_replace(ql->next, index - ql->num_elements, data); } } -int ql_length(const quicklist * ql) { - return ql?ql->num_elements+ql_length(ql->next):0; +int ql_length(const quicklist * ql) +{ + return ql ? ql->num_elements + ql_length(ql->next) : 0; } -int ql_empty(const quicklist * ql) { +int ql_empty(const quicklist * ql) +{ return !ql; } -void ql_push(quicklist ** qlp, void * data) { - quicklist * ql = 0; - while(*qlp && ((*qlp)->next || (*qlp)->num_elements==QL_MAXSIZE)) { +void ql_push(quicklist ** qlp, void *data) +{ + quicklist *ql = 0; + + while (*qlp && ((*qlp)->next || (*qlp)->num_elements == QL_MAXSIZE)) { qlp = &(*qlp)->next; } if (!*qlp) { - ql = (quicklist *)malloc(sizeof(quicklist)); + ql = (quicklist *) malloc(sizeof(quicklist)); ql->num_elements = 0; ql->next = 0; *qlp = ql; @@ -67,28 +76,35 @@ void ql_push(quicklist ** qlp, void * data) { ql->elements[ql->num_elements++] = data; } -int ql_delete(quicklist ** qlp, int index) { - quicklist * ql = *qlp; - if (index<0) return EINVAL; - if (ql && index>=ql->num_elements) { - return ql_delete(&ql->next, index-ql->num_elements); +int ql_delete(quicklist ** qlp, int index) +{ + quicklist *ql = *qlp; + + if (index < 0) + return EINVAL; + if (ql && index >= ql->num_elements) { + return ql_delete(&ql->next, index - ql->num_elements); } else if (ql) { - if (index+1num_elements) { - memmove(ql->elements+index, ql->elements+index+1, (ql->num_elements-index-1)*sizeof(void*)); + if (index + 1 < ql->num_elements) { + memmove(ql->elements + index, ql->elements + index + 1, + (ql->num_elements - index - 1) * sizeof(void *)); } --ql->num_elements; - if (ql->num_elements==0) { + if (ql->num_elements == 0) { *qlp = ql->next; free(ql); - } else if (ql->next && ql->num_elementsnext; - if (ql->num_elements+qn->num_elements>QL_MAXSIZE) { - memcpy(ql->elements+ql->num_elements, qn->elements, sizeof(void*)); + } else if (ql->next && ql->num_elements < QL_LIMIT) { + quicklist *qn = ql->next; + + if (ql->num_elements + qn->num_elements > QL_MAXSIZE) { + memcpy(ql->elements + ql->num_elements, qn->elements, sizeof(void *)); --qn->num_elements; ++ql->num_elements; - memmove(qn->elements, qn->elements+1, qn->num_elements*sizeof(void*)); + memmove(qn->elements, qn->elements + 1, + qn->num_elements * sizeof(void *)); } else { - memcpy(ql->elements+ql->num_elements, qn->elements, qn->num_elements*sizeof(void*)); + memcpy(ql->elements + ql->num_elements, qn->elements, + qn->num_elements * sizeof(void *)); ql->num_elements += qn->num_elements; ql->next = qn->next; free(qn); @@ -98,29 +114,34 @@ int ql_delete(quicklist ** qlp, int index) { return 0; } -int ql_insert(quicklist ** qlp, int index, void * data) { - quicklist * ql = *qlp; +int ql_insert(quicklist ** qlp, int index, void *data) +{ + quicklist *ql = *qlp; + if (ql) { - if (index>=QL_MAXSIZE) { - return ql_insert(&ql->next, index-ql->num_elements, data); - } else if (ql->num_elementselements+index+1, ql->elements+index, (ql->num_elements-index)*sizeof(void*)); - ql->elements[index]=data; + if (index >= QL_MAXSIZE) { + return ql_insert(&ql->next, index - ql->num_elements, data); + } else if (ql->num_elements < QL_MAXSIZE) { + memmove(ql->elements + index + 1, ql->elements + index, + (ql->num_elements - index) * sizeof(void *)); + ql->elements[index] = data; ++ql->num_elements; } else { - quicklist * qn = (quicklist *)malloc(sizeof(quicklist)); + quicklist *qn = (quicklist *) malloc(sizeof(quicklist)); + qn->next = ql->next; ql->next = qn; qn->num_elements = QL_LIMIT; ql->num_elements -= QL_LIMIT; - memcpy(qn->elements, ql->elements+ql->num_elements, QL_LIMIT*sizeof(void*)); - if (index<=ql->num_elements) { + memcpy(qn->elements, ql->elements + ql->num_elements, + QL_LIMIT * sizeof(void *)); + if (index <= ql->num_elements) { return ql_insert(qlp, index, data); } else { - return ql_insert(&ql->next, index-ql->num_elements, data); + return ql_insert(&ql->next, index - ql->num_elements, data); } } - } else if (index==0) { + } else if (index == 0) { ql_push(qlp, data); } else { return EINVAL; @@ -128,23 +149,26 @@ int ql_insert(quicklist ** qlp, int index, void * data) { return 0; } -void ql_foreach(struct quicklist * ql, void (*cb)(void *)) +void ql_foreach(struct quicklist *ql, void (*cb) (void *)) { - for (;ql;ql=ql->next) { + for (; ql; ql = ql->next) { int i; - for (i=0;i!=ql->num_elements;++i) { + + for (i = 0; i != ql->num_elements; ++i) { cb(ql->elements[i]); } } } -int ql_advance(struct quicklist ** iterator, int * index, int stride) +int ql_advance(struct quicklist **iterator, int *index, int stride) { - quicklist * ql = *iterator; + quicklist *ql = *iterator; + int i = *index; - if (!ql || i<0 || stride<0) { + + if (!ql || i < 0 || stride < 0) { return ERANGE; - } else if (i + stridenum_elements) { + } else if (i + stride < ql->num_elements) { *index = i + stride; return 0; } else { @@ -154,35 +178,42 @@ int ql_advance(struct quicklist ** iterator, int * index, int stride) } } -void ql_free(struct quicklist * ql) +void ql_free(struct quicklist *ql) { - if (!ql) return; - if (ql->next) ql_free(ql->next); + if (!ql) + return; + if (ql->next) + ql_free(ql->next); free(ql); } -int ql_set_remove(struct quicklist ** qlp, void * data) +int ql_set_remove(struct quicklist **qlp, void *data) { int qi; - quicklist * ql = *qlp; - if (!ql) return 0; + quicklist *ql = *qlp; - for (qi=0;qi!=ql->num_elements;++qi) { - void * qd = ql_get(ql, qi); - if (qd==data) { - return ql_delete(qlp, qi)==0; + if (!ql) + return 0; + + for (qi = 0; qi != ql->num_elements; ++qi) { + void *qd = ql_get(ql, qi); + + if (qd == data) { + return ql_delete(qlp, qi) == 0; } } return ql_set_remove(&ql->next, data); } -int ql_set_insert(struct quicklist ** qlp, void * data) +int ql_set_insert(struct quicklist **qlp, void *data) { if (*qlp) { - quicklist * ql = *qlp; - if (ql->num_elements>0 && ql->elements[ql->num_elements-1] < data) { - if (ql->num_elements==QL_MAXSIZE || (ql->next && ql->next->elements[0]<=data)) { + quicklist *ql = *qlp; + + if (ql->num_elements > 0 && ql->elements[ql->num_elements - 1] < data) { + if (ql->num_elements == QL_MAXSIZE || (ql->next + && ql->next->elements[0] <= data)) { return ql_set_insert(&ql->next, data); } else { ql->elements[ql->num_elements++] = data; @@ -190,8 +221,9 @@ int ql_set_insert(struct quicklist ** qlp, void * data) return 0; } else { int i; + /* TODO: OPT | binary search */ - for (i=0;i!=ql->num_elements;++i) { + for (i = 0; i != ql->num_elements; ++i) { if (data < ql->elements[i]) { ql_insert(qlp, i, data); return 0; @@ -206,23 +238,25 @@ int ql_set_insert(struct quicklist ** qlp, void * data) return 0; } -int ql_set_find(struct quicklist ** qlp, int * qip, const void * data) +int ql_set_find(struct quicklist **qlp, int *qip, const void *data) { - quicklist * ql = *qlp; + quicklist *ql = *qlp; + int qi; - while (ql && ql->elements[ql->num_elements-1]next; + while (ql && ql->elements[ql->num_elements - 1] < data) { + ql = ql->next; } - - if (!ql) return 0; + + if (!ql) + return 0; /* TODO: OPT | binary search */ - for (qi=0;qi!=ql->num_elements;++qi) { - if (ql->elements[qi]>data) { + for (qi = 0; qi != ql->num_elements; ++qi) { + if (ql->elements[qi] > data) { return 0; } - if (ql->elements[qi]==data) { + if (ql->elements[qi] == data) { if (qip) { *qip = qi; *qlp = ql; diff --git a/src/util/quicklist.h b/src/util/quicklist.h index d70fa648c..01b918543 100644 --- a/src/util/quicklist.h +++ b/src/util/quicklist.h @@ -22,22 +22,22 @@ extern "C" { #endif /* see http://en.wikipedia.org/wiki/Unrolled_linked_list */ -typedef struct quicklist quicklist; -void * ql_get(const struct quicklist * ql, int index); -int ql_length(const struct quicklist * ql); -int ql_empty(const struct quicklist * ql); -void ql_push(struct quicklist ** qlp, void * data); -int ql_delete(struct quicklist ** qlp, int index); -int ql_insert(struct quicklist ** qlp, int index, void * data); -void ql_foreach(struct quicklist * ql, void (*cb)(void *)); -int ql_advance(struct quicklist ** iterator, int * index, int stride); -void ql_free(struct quicklist * ql); -void * ql_replace(struct quicklist * ql, int index, void * data); + typedef struct quicklist quicklist; + void *ql_get(const struct quicklist *ql, int index); + int ql_length(const struct quicklist *ql); + int ql_empty(const struct quicklist *ql); + void ql_push(struct quicklist **qlp, void *data); + int ql_delete(struct quicklist **qlp, int index); + int ql_insert(struct quicklist **qlp, int index, void *data); + void ql_foreach(struct quicklist *ql, void (*cb) (void *)); + int ql_advance(struct quicklist **iterator, int *index, int stride); + void ql_free(struct quicklist *ql); + void *ql_replace(struct quicklist *ql, int index, void *data); /* you can use it as a set (sorted pointers)*/ -int ql_set_insert(struct quicklist ** qlp, void * data); -int ql_set_find(struct quicklist ** qlp, int * qip, const void * data); -int ql_set_remove(struct quicklist ** qlp, void * data); + int ql_set_insert(struct quicklist **qlp, void *data); + int ql_set_find(struct quicklist **qlp, int *qip, const void *data); + int ql_set_remove(struct quicklist **qlp, void *data); #ifdef __cplusplus } diff --git a/src/util/quicklist_test.c b/src/util/quicklist_test.c index ead3d2c78..13df9a3c6 100644 --- a/src/util/quicklist_test.c +++ b/src/util/quicklist_test.c @@ -3,51 +3,62 @@ #include #include "quicklist.h" -static const char * hello = "Hello World"; +static const char *hello = "Hello World"; + +static void test_insert(CuTest * tc) +{ + struct quicklist *ql = NULL; -static void test_insert(CuTest * tc) { - struct quicklist * ql = NULL; int i; - for (i=0;i!=32;++i) { + + for (i = 0; i != 32; ++i) { CuAssertIntEquals(tc, i, ql_length(ql)); - ql_insert(&ql, 0, (void*)i); + ql_insert(&ql, 0, (void *)i); } - for (i=0;i!=32;++i) { - CuAssertIntEquals(tc, 31-i, (int)ql_get(ql, i)); + for (i = 0; i != 32; ++i) { + CuAssertIntEquals(tc, 31 - i, (int)ql_get(ql, i)); } } -static void test_insert_delete_gives_null(CuTest * tc) { - struct quicklist * ql = NULL; +static void test_insert_delete_gives_null(CuTest * tc) +{ + struct quicklist *ql = NULL; + CuAssertIntEquals(tc, 1, ql_empty(ql)); - ql_push(&ql, (void*)42); + ql_push(&ql, (void *)42); CuAssertIntEquals(tc, 0, ql_empty(ql)); ql_delete(&ql, 0); CuAssertPtrEquals(tc, 0, ql); } -static void test_replace(CuTest * tc) { - struct quicklist * ql = NULL; +static void test_replace(CuTest * tc) +{ + struct quicklist *ql = NULL; + int a; - ql_push(&ql, (void*)42); + + ql_push(&ql, (void *)42); a = (int)ql_replace(ql, 0, (void *)43); CuAssertIntEquals(tc, 42, a); CuAssertIntEquals(tc, 43, (int)ql_get(ql, 0)); } -static void test_set_insert(CuTest * tc) { - struct quicklist * ql = NULL; +static void test_set_insert(CuTest * tc) +{ + struct quicklist *ql = NULL; + int a, qi; - a = ql_set_insert(&ql, (void*)42); + + a = ql_set_insert(&ql, (void *)42); CuAssertIntEquals(tc, 1, ql_length(ql)); CuAssertIntEquals(tc, 0, a); - a = ql_set_insert(&ql, (void*)43); + a = ql_set_insert(&ql, (void *)43); CuAssertIntEquals(tc, 2, ql_length(ql)); CuAssertIntEquals(tc, 0, a); - a = ql_set_insert(&ql, (void*)42); + a = ql_set_insert(&ql, (void *)42); CuAssertIntEquals(tc, 2, ql_length(ql)); CuAssertIntEquals(tc, 1, a); - a = ql_set_insert(&ql, (void*)41); + a = ql_set_insert(&ql, (void *)41); CuAssertIntEquals(tc, 0, a); CuAssertIntEquals(tc, 3, ql_length(ql)); CuAssertIntEquals(tc, 41, (int)ql_get(ql, 0)); @@ -61,37 +72,41 @@ static void test_set_insert(CuTest * tc) { CuAssertIntEquals(tc, 42, (int)ql_get(ql, qi)); } -static void test_set_remove(CuTest * tc) { - struct quicklist * ql = NULL, * q2; +static void test_set_remove(CuTest * tc) +{ + struct quicklist *ql = NULL, *q2; + int a; - ql_set_insert(&ql, (void*)41); - ql_set_insert(&ql, (void*)42); - ql_set_insert(&ql, (void*)43); + ql_set_insert(&ql, (void *)41); + ql_set_insert(&ql, (void *)42); + ql_set_insert(&ql, (void *)43); q2 = ql; - a = ql_set_remove(&ql, (void*)42); + a = ql_set_remove(&ql, (void *)42); CuAssertPtrEquals(tc, q2, ql); CuAssertIntEquals(tc, 1, a); CuAssertIntEquals(tc, 41, (int)ql_get(ql, 0)); CuAssertIntEquals(tc, 43, (int)ql_get(ql, 1)); CuAssertIntEquals(tc, 2, ql_length(ql)); - a = ql_set_remove(&ql, (void*)42); + a = ql_set_remove(&ql, (void *)42); CuAssertPtrEquals(tc, q2, ql); CuAssertIntEquals(tc, 0, a); - ql_set_remove(&ql, (void*)41); - ql_set_remove(&ql, (void*)43); + ql_set_remove(&ql, (void *)41); + ql_set_remove(&ql, (void *)43); CuAssertPtrEquals(tc, 0, ql); } -static void test_set_find(CuTest * tc) { - struct quicklist * ql = NULL, * q2; +static void test_set_find(CuTest * tc) +{ + struct quicklist *ql = NULL, *q2; + int a, qi; - for (a=0;a!=32;++a) { + for (a = 0; a != 32; ++a) { ql_set_insert(&ql, (void *)a); } @@ -110,61 +125,75 @@ static void test_set_find(CuTest * tc) { a = ql_set_find(&ql, &qi, (void *)31); CuAssertIntEquals(tc, 1, a); CuAssertIntEquals(tc, 31, (int)ql_get(ql, qi)); - CuAssertTrue(tc, ql!=q2); + CuAssertTrue(tc, ql != q2); } -static void test_advance(CuTest * tc) { - struct quicklist * ql = NULL, *qli; +static void test_advance(CuTest * tc) +{ + struct quicklist *ql = NULL, *qli; + int i, n = 31; - for (i=0;i!=32;++i) { - ql_insert(&ql, 0, (void*)i); + + for (i = 0; i != 32; ++i) { + ql_insert(&ql, 0, (void *)i); } - for (i=0,qli=ql;qli;ql_advance(&qli, &i, 1),n--) { + for (i = 0, qli = ql; qli; ql_advance(&qli, &i, 1), n--) { int g = (int)ql_get(qli, i); + CuAssertIntEquals(tc, n, g); } } -static void test_push(CuTest * tc) { - struct quicklist * ql = NULL; +static void test_push(CuTest * tc) +{ + struct quicklist *ql = NULL; + CuAssertIntEquals(tc, 0, ql_length(ql)); - ql_push(&ql, (void*)hello); + ql_push(&ql, (void *)hello); CuAssertIntEquals(tc, 1, ql_length(ql)); CuAssertStrEquals(tc, "Hello World", (const char *)ql_get(ql, 0)); ql_delete(&ql, 0); CuAssertPtrEquals(tc, 0, ql); } -static void test_delete_edgecases(CuTest * tc) { - struct quicklist * ql = NULL; +static void test_delete_edgecases(CuTest * tc) +{ + struct quicklist *ql = NULL; + ql_delete(&ql, 0); CuAssertPtrEquals(tc, 0, ql); - ql_push(&ql, (void*)hello); + ql_push(&ql, (void *)hello); ql_delete(&ql, -1); ql_delete(&ql, 32); CuAssertIntEquals(tc, 1, ql_length(ql)); } -static void test_insert_many(CuTest * tc) { - struct quicklist * ql = NULL; +static void test_insert_many(CuTest * tc) +{ + struct quicklist *ql = NULL; + int i; - for (i=0;i!=32;++i) { - ql_push(&ql, (void*)i); + + for (i = 0; i != 32; ++i) { + ql_push(&ql, (void *)i); } - for (i=0;i!=32;++i) { - CuAssertIntEquals(tc, 32-i, ql_length(ql)); + for (i = 0; i != 32; ++i) { + CuAssertIntEquals(tc, 32 - i, ql_length(ql)); CuAssertIntEquals(tc, i, (int)ql_get(ql, 0)); - CuAssertIntEquals(tc, 31, (int)ql_get(ql, ql_length(ql)-1)); + CuAssertIntEquals(tc, 31, (int)ql_get(ql, ql_length(ql) - 1)); ql_delete(&ql, 0); } CuAssertPtrEquals(tc, 0, ql); } -static void test_delete_rand(CuTest * tc) { - struct quicklist * ql = NULL; +static void test_delete_rand(CuTest * tc) +{ + struct quicklist *ql = NULL; + int i; - for (i=0;i!=32;++i) { - ql_push(&ql, (void*)i); + + for (i = 0; i != 32; ++i) { + ql_push(&ql, (void *)i); } CuAssertIntEquals(tc, 32, ql_length(ql)); ql_delete(&ql, 0); @@ -174,9 +203,10 @@ static void test_delete_rand(CuTest * tc) { CuAssertIntEquals(tc, 30, ql_length(ql)); } -CuSuite* get_quicklist_suite(void) +CuSuite *get_quicklist_suite(void) { - CuSuite* suite = CuSuiteNew(); + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_advance); SUITE_ADD_TEST(suite, test_replace); SUITE_ADD_TEST(suite, test_push); diff --git a/src/util/rand.c b/src/util/rand.c index 9694c182c..1bff35e04 100644 --- a/src/util/rand.c +++ b/src/util/rand.c @@ -26,36 +26,39 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -#define M_PIl 3.1415926535897932384626433832795029L /* pi */ +#define M_PIl 3.1415926535897932384626433832795029L /* pi */ /* NormalRand aus python, random.py geklaut, dort ist Referenz auf * den Algorithmus. mu = Mittelwert, sigma = Standardabweichung. * http://de.wikipedia.org/wiki/Standardabweichung#Diskrete_Gleichverteilung.2C_W.C3.BCrfel */ -double -normalvariate(double mu, double sigma) +double normalvariate(double mu, double sigma) { - static const double NV_MAGICCONST = 1.7155277699214135; /* STATIC_CONST: a constant */ + static const double NV_MAGICCONST = 1.7155277699214135; /* STATIC_CONST: a constant */ + double z; + for (;;) { double u1 = rng_double(); + double u2 = 1.0 - rng_double(); - z = NV_MAGICCONST*(u1-0.5)/u2; - if (z*z/4.0 <= -log(u2)) { + + z = NV_MAGICCONST * (u1 - 0.5) / u2; + if (z * z / 4.0 <= -log(u2)) { break; } } - return mu+z*sigma; + return mu + z * sigma; } -int -ntimespprob(int n, double p, double mod) +int ntimespprob(int n, double p, double mod) { int count = 0; + int i; - for(i=0; i0; i++) { - if(rng_double() < p) { + for (i = 0; i < n && p > 0; i++) { + if (rng_double() < p) { count++; p += mod; } @@ -63,10 +66,9 @@ ntimespprob(int n, double p, double mod) return count; } -boolean -chance(double x) +boolean chance(double x) { - if (x>=1.0) return true; + if (x >= 1.0) + return true; return rng_double() < x; } - diff --git a/src/util/resolve.c b/src/util/resolve.c index 224fbff52..780cf46fa 100644 --- a/src/util/resolve.c +++ b/src/util/resolve.c @@ -24,47 +24,50 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "variant.h" typedef struct unresolved { - void * ptrptr; - /* address to pass to the resolve-function */ - variant data; - /* information on how to resolve the missing object */ - resolve_fun resolve; - /* function to resolve the unknown object */ + void *ptrptr; + /* address to pass to the resolve-function */ + variant data; + /* information on how to resolve the missing object */ + resolve_fun resolve; + /* function to resolve the unknown object */ } unresolved; #define BLOCKSIZE 1024 -static unresolved * ur_list; -static unresolved * ur_begin; -static unresolved * ur_current; +static unresolved *ur_list; -variant -read_int(struct storage * store) +static unresolved *ur_begin; + +static unresolved *ur_current; + +variant read_int(struct storage *store) { variant var; + var.i = store->r_int(store); return var; } int -read_reference(void * address, storage * store, read_fun reader, resolve_fun resolver) +read_reference(void *address, storage * store, read_fun reader, + resolve_fun resolver) { variant var = reader(store); + int result = resolver(var, address); - if (result!=0) { + + if (result != 0) { ur_add(var, address, resolver); } return result; } -void -ur_add(variant data, void * ptrptr, resolve_fun fun) +void ur_add(variant data, void *ptrptr, resolve_fun fun) { - if (ur_list==NULL) { - ur_list = malloc(BLOCKSIZE*sizeof(unresolved)); + if (ur_list == NULL) { + ur_list = malloc(BLOCKSIZE * sizeof(unresolved)); ur_begin = ur_current = ur_list; - } - else if (ur_current-ur_begin==BLOCKSIZE-1) { - ur_begin = malloc(BLOCKSIZE*sizeof(unresolved)); + } else if (ur_current - ur_begin == BLOCKSIZE - 1) { + ur_begin = malloc(BLOCKSIZE * sizeof(unresolved)); ur_current->data.v = ur_begin; ur_current = ur_begin; } @@ -77,12 +80,12 @@ ur_add(variant data, void * ptrptr, resolve_fun fun) ur_current->data.v = NULL; } -void -resolve(void) +void resolve(void) { - unresolved * ur = ur_list; + unresolved *ur = ur_list; + while (ur) { - if (ur->resolve==NULL) { + if (ur->resolve == NULL) { ur = ur->data.v; free(ur_list); ur_list = ur; diff --git a/src/util/resolve.h b/src/util/resolve.h index c6deb4f77..64b9441a6 100644 --- a/src/util/resolve.h +++ b/src/util/resolve.h @@ -26,14 +26,15 @@ struct storage; extern "C" { #endif - typedef int (*resolve_fun)(variant data, void * address); - typedef variant (*read_fun)(struct storage* store); - extern int read_reference(void * address, struct storage * store, read_fun reader, resolve_fun resolver); + typedef int (*resolve_fun) (variant data, void *address); + typedef variant(*read_fun) (struct storage * store); + extern int read_reference(void *address, struct storage *store, + read_fun reader, resolve_fun resolver); - extern void ur_add(variant data, void * address, resolve_fun fun); + extern void ur_add(variant data, void *address, resolve_fun fun); extern void resolve(void); - extern variant read_int(struct storage * store); + extern variant read_int(struct storage *store); #ifdef __cplusplus } diff --git a/src/util/rng.h b/src/util/rng.h index 3ef39d49e..8737190c6 100644 --- a/src/util/rng.h +++ b/src/util/rng.h @@ -15,13 +15,13 @@ extern "C" { #define RNG_MT -#ifdef RNG_MT +#ifdef RNG_MT /* initializes mt[N] with a seed */ extern void init_genrand(unsigned long s); /* generates a random number on [0,0xffffffff]-interval */ extern unsigned long genrand_int32(void); - + /* generates a random number on [0,1)-real-interval */ extern double genrand_real2(void); diff --git a/src/util/sql.c b/src/util/sql.c index 9f653e8af..b6ca44ec2 100644 --- a/src/util/sql.c +++ b/src/util/sql.c @@ -25,58 +25,64 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -static FILE * sqlstream = NULL; -static char * sqlfilename = NULL; +static FILE *sqlstream = NULL; -void -sql_init(const char * filename) +static char *sqlfilename = NULL; + +void sql_init(const char *filename) { - if (sqlfilename!=NULL) free(sqlfilename); + if (sqlfilename != NULL) + free(sqlfilename); sqlfilename = strdup(filename); } -void -_sql_print(const char * format, ...) +void _sql_print(const char *format, ...) { if (!sqlstream && sqlfilename) { - sqlstream=fopen(sqlfilename, "wt+"); + sqlstream = fopen(sqlfilename, "wt+"); free(sqlfilename); - sqlfilename=NULL; + sqlfilename = NULL; } - if (sqlstream!=NULL) { + if (sqlstream != NULL) { va_list marker; + va_start(marker, format); vfprintf(sqlstream, format, marker); va_end(marker); } } -void -sql_done(void) +void sql_done(void) { - if (sqlstream) fclose(sqlstream); - if (sqlfilename) free(sqlfilename); - sqlstream=NULL; - sqlfilename=NULL; + if (sqlstream) + fclose(sqlstream); + if (sqlfilename) + free(sqlfilename); + sqlstream = NULL; + sqlfilename = NULL; } -const char * -sqlquote(const char * str) +const char *sqlquote(const char *str) { #define BUFFERS 4 #define BUFSIZE 1024 - static char sqlstring[BUFSIZE*BUFFERS]; /* STATIC_RESULT: used for return, not across calls */ - static int index = 0; /* STATIC_XCALL: used across calls */ - char * start = sqlstring+index*BUFSIZE; - char * o = start; - const char * i = str; - while (*i && o-start < BUFSIZE-1) { - if (*i!='\'' && *i!='\"') { - *o++ = *i++; - } else ++i; - } - *o = '\0'; - index = (index+1) % BUFFERS; - return start; -} + static char sqlstring[BUFSIZE * BUFFERS]; /* STATIC_RESULT: used for return, not across calls */ + static int index = 0; /* STATIC_XCALL: used across calls */ + + char *start = sqlstring + index * BUFSIZE; + + char *o = start; + + const char *i = str; + + while (*i && o - start < BUFSIZE - 1) { + if (*i != '\'' && *i != '\"') { + *o++ = *i++; + } else + ++i; + } + *o = '\0'; + index = (index + 1) % BUFFERS; + return start; +} diff --git a/src/util/sql.h b/src/util/sql.h index b16fa7930..2cbc9f5a1 100644 --- a/src/util/sql.h +++ b/src/util/sql.h @@ -22,10 +22,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif - extern void sql_init(const char * filename); + extern void sql_init(const char *filename); extern void sql_done(void); - extern const char * sqlquote(const char * str); - extern void _sql_print(const char * format, ...); + extern const char *sqlquote(const char *str); + extern void _sql_print(const char *format, ...); #define sql_print(x) _sql_print x diff --git a/src/util/storage.h b/src/util/storage.h index 96b62216b..15f5ce3ae 100644 --- a/src/util/storage.h +++ b/src/util/storage.h @@ -4,37 +4,37 @@ extern "C" { #endif -typedef struct storage { - /* separator for readable files: */ - int (*w_brk)(struct storage *); - /* integer values: */ - int (*w_int)(struct storage *, int arg); - int (*r_int)(struct storage *); - /* float values: */ - int (*w_flt)(struct storage *, float arg); - float (*r_flt)(struct storage *); - /* id values: */ - int (*w_id)(struct storage *, int arg); - int (*r_id)(struct storage *); - /* tokens that contain no whitespace: */ - int (*w_tok)(struct storage *, const char * tok); - char *(*r_tok)(struct storage *); - void (*r_tok_buf)(struct storage *, char * result, size_t size); - /* strings that need to be quoted: */ - int (*w_str)(struct storage *, const char * tok); - char * (*r_str)(struct storage *); - void (*r_str_buf)(struct storage *, char * result, size_t size); - /* binary data: */ - int (*w_bin)(struct storage *, void * arg, size_t size); - void (*r_bin)(struct storage *, void * result, size_t size); + typedef struct storage { + /* separator for readable files: */ + int (*w_brk) (struct storage *); + /* integer values: */ + int (*w_int) (struct storage *, int arg); + int (*r_int) (struct storage *); + /* float values: */ + int (*w_flt) (struct storage *, float arg); + float (*r_flt) (struct storage *); + /* id values: */ + int (*w_id) (struct storage *, int arg); + int (*r_id) (struct storage *); + /* tokens that contain no whitespace: */ + int (*w_tok) (struct storage *, const char *tok); + char *(*r_tok) (struct storage *); + void (*r_tok_buf) (struct storage *, char *result, size_t size); + /* strings that need to be quoted: */ + int (*w_str) (struct storage *, const char *tok); + char *(*r_str) (struct storage *); + void (*r_str_buf) (struct storage *, char *result, size_t size); + /* binary data: */ + int (*w_bin) (struct storage *, void *arg, size_t size); + void (*r_bin) (struct storage *, void *result, size_t size); - int (*open)(struct storage *, const char * filename, int mode); - int (*close)(struct storage *); + int (*open) (struct storage *, const char *filename, int mode); + int (*close) (struct storage *); - int encoding; - int version; - void * userdata; -} storage; + int encoding; + int version; + void *userdata; + } storage; #define IO_READ 0x01 #define IO_WRITE 0x02 diff --git a/src/util/strings.c b/src/util/strings.c index 390bc5462..d804f170c 100644 --- a/src/util/strings.c +++ b/src/util/strings.c @@ -21,12 +21,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* libc includes */ #include -INLINE_FUNCTION unsigned int -hashstring(const char* s) +INLINE_FUNCTION unsigned int hashstring(const char *s) { unsigned int key = 0; + while (*s) { - key = key*37 + *s++; + key = key * 37 + *s++; } return key & 0x7FFFFFFF; } @@ -70,17 +70,21 @@ escape_string_inplace(char * buffer, unsigned int len, unsigned int offset) } */ -INLINE_FUNCTION const char * -escape_string(const char * str, char * buffer, unsigned int len) +INLINE_FUNCTION const char *escape_string(const char *str, char *buffer, + unsigned int len) { - const char * start = strchr(str, '\"'); + const char *start = strchr(str, '\"'); + if (start) { static char s_buffer[4096]; /* STATIC_RESULT: used for return, not across calls */ - const char * p; - char * o; - size_t skip = start-str; - if (buffer==NULL) { + const char *p; + + char *o; + + size_t skip = start - str; + + if (buffer == NULL) { buffer = s_buffer; len = sizeof(s_buffer); } @@ -88,15 +92,15 @@ escape_string(const char * str, char * buffer, unsigned int len) o = buffer + skip; p = str + skip; do { - if (*p == '\"' || *p=='\\') { - if (len<2) { + if (*p == '\"' || *p == '\\') { + if (len < 2) { *o = '\0'; break; } (*o++) = '\\'; len -= 2; } else { - if (len<1) { + if (len < 1) { *o = '\0'; break; } @@ -111,22 +115,22 @@ escape_string(const char * str, char * buffer, unsigned int len) INLINE_FUNCTION unsigned int jenkins_hash(unsigned int a) { - a = (a+0x7ed55d16) + (a<<12); - a = (a^0xc761c23c) ^ (a>>19); - a = (a+0x165667b1) + (a<<5); - a = (a+0xd3a2646c) ^ (a<<9); - a = (a+0xfd7046c5) + (a<<3); - a = (a^0xb55a4f09) ^ (a>>16); + a = (a + 0x7ed55d16) + (a << 12); + a = (a ^ 0xc761c23c) ^ (a >> 19); + a = (a + 0x165667b1) + (a << 5); + a = (a + 0xd3a2646c) ^ (a << 9); + a = (a + 0xfd7046c5) + (a << 3); + a = (a ^ 0xb55a4f09) ^ (a >> 16); return a; } INLINE_FUNCTION unsigned int wang_hash(unsigned int a) { - a = ~a + (a << 15); // a = (a << 15) - a - 1; + a = ~a + (a << 15); // a = (a << 15) - a - 1; a = a ^ (a >> 12); a = a + (a << 2); a = a ^ (a >> 4); - a = a * 2057; // a = (a + (a << 3)) + (a << 11); + a = a * 2057; // a = (a + (a << 3)) + (a << 11); a = a ^ (a >> 16); return a; } diff --git a/src/util/strncpy.c b/src/util/strncpy.c index 8da32d488..9759a1ff9 100644 --- a/src/util/strncpy.c +++ b/src/util/strncpy.c @@ -5,18 +5,20 @@ #include -char * -strncpy(char *to, const char *from, size_t size) +char *strncpy(char *to, const char *from, size_t size) { char *t = to, *f = (char *)from; + int copied = 0; - while(copied < size) { + while (copied < size) { *t = *f; - if(*f == '\0') break; - t++; f++; copied++; + if (*f == '\0') + break; + t++; + f++; + copied++; } return to; } - diff --git a/src/util/translation.c b/src/util/translation.c index b92246a19..7946fd0e7 100644 --- a/src/util/translation.c +++ b/src/util/translation.c @@ -27,27 +27,26 @@ **/ typedef struct opstack { - variant * begin; - variant * top; + variant *begin; + variant *top; int size; } opstack; -variant -opstack_pop(opstack ** stackp) +variant opstack_pop(opstack ** stackp) { - opstack * stack = *stackp; - + opstack *stack = *stackp; + assert(stack); - assert(stack->top>stack->begin); + assert(stack->top > stack->begin); return *(--stack->top); } -void -opstack_push(opstack ** stackp, variant data) +void opstack_push(opstack ** stackp, variant data) { - opstack * stack = *stackp; - if (stack==NULL) { - stack = (opstack*)malloc(sizeof(opstack)); + opstack *stack = *stackp; + + if (stack == NULL) { + stack = (opstack *) malloc(sizeof(opstack)); stack->size = 1; stack->begin = malloc(sizeof(variant) * stack->size); stack->top = stack->begin; @@ -55,10 +54,11 @@ opstack_push(opstack ** stackp, variant data) } if (stack->top - stack->begin == stack->size) { size_t pos = stack->top - stack->begin; + stack->size += stack->size; stack->begin = realloc(stack->begin, sizeof(variant) * stack->size); stack->top = stack->begin + pos; - } + } *stack->top++ = data; } @@ -68,43 +68,42 @@ opstack_push(opstack ** stackp, variant data) #define BBUFSIZE 128*1024 static struct { - char * begin; - char * end; - char * last; - char * current; + char *begin; + char *end; + char *last; + char *current; } buffer; -char * -balloc(size_t size) +char *balloc(size_t size) { - static int init = 0; /* STATIC_XCALL: used across calls */ - if (!init) { - init = 1; - buffer.current = buffer.begin = malloc(BBUFSIZE); - buffer.end = buffer.begin + BBUFSIZE; - } - if (buffer.current + size > buffer.end) { - /* out of memory! */ - return NULL; - } - buffer.last = buffer.current; - buffer.current +=size; - return buffer.last; + static int init = 0; /* STATIC_XCALL: used across calls */ + + if (!init) { + init = 1; + buffer.current = buffer.begin = malloc(BBUFSIZE); + buffer.end = buffer.begin + BBUFSIZE; + } + if (buffer.current + size > buffer.end) { + /* out of memory! */ + return NULL; + } + buffer.last = buffer.current; + buffer.current += size; + return buffer.last; } -void -bfree(char * c) +void bfree(char *c) /* only release this memory if it was part of the last allocation * that's a joke, but who cares. */ { - if (c>=buffer.last && c= buffer.last && c < buffer.current) + buffer.current = c; } -void -brelease(void) +void brelease(void) { - buffer.last = buffer.current = buffer.begin; + buffer.last = buffer.current = buffer.begin; } @@ -113,40 +112,39 @@ brelease(void) **/ typedef struct variable { - struct variable * next; - const char * symbol; - variant value; + struct variable *next; + const char *symbol; + variant value; } variable; -static variable * variables; +static variable *variables; -static void -free_variables(void) +static void free_variables(void) { - variables = NULL; + variables = NULL; } -static void -add_variable(const char * symbol, variant value) +static void add_variable(const char *symbol, variant value) { - variable * var = (variable*)balloc(sizeof(variable)); + variable *var = (variable *) balloc(sizeof(variable)); - var->value = value; - var->symbol = symbol; + var->value = value; + var->symbol = symbol; - var->next = variables; - variables = var; + var->next = variables; + variables = var; } -static variable * -find_variable(const char * symbol) +static variable *find_variable(const char *symbol) { - variable * var = variables; - while (var) { - if (!strcmp(var->symbol, symbol)) break; - var = var->next; - } - return var; + variable *var = variables; + + while (var) { + if (!strcmp(var->symbol, symbol)) + break; + var = var->next; + } + return var; } /** @@ -154,87 +152,94 @@ find_variable(const char * symbol) **/ typedef struct function { - struct function * next; - const char * symbol; - evalfun parse; + struct function *next; + const char *symbol; + evalfun parse; } function; -static function * functions; +static function *functions; -static void -free_functions(void) +static void free_functions(void) { - while (functions) { - function * fun = functions; - functions = fun->next; - free(fun); - } + while (functions) { + function *fun = functions; + + functions = fun->next; + free(fun); + } } -void -add_function(const char * symbol, evalfun parse) +void add_function(const char *symbol, evalfun parse) { - function * fun = (function*)malloc(sizeof(function)); + function *fun = (function *) malloc(sizeof(function)); - fun->parse = parse; - fun->symbol = symbol; + fun->parse = parse; + fun->symbol = symbol; - fun->next = functions; - functions = fun; + fun->next = functions; + functions = fun; } -static function * -find_function(const char * symbol) +static function *find_function(const char *symbol) { - function * fun = functions; - while (fun) { - if (!strcmp(fun->symbol, symbol)) break; - fun = fun->next; - } - return fun; + function *fun = functions; + + while (fun) { + if (!strcmp(fun->symbol, symbol)) + break; + fun = fun->next; + } + return fun; } -static const char * parse(opstack **, const char* in, const void *); +static const char *parse(opstack **, const char *in, const void *); + /* static const char * sample = "\"enno and $bool($if($eq($i,0),\"noone else\",\"$i other people\"))\""; */ -static const char * -parse_symbol(opstack ** stack, const char* in, const void * userdata) +static const char *parse_symbol(opstack ** stack, const char *in, + const void *userdata) /* in is the symbol name and following text, starting after the $ * result goes on the stack */ { boolean braces = false; - char symbol[32]; - char *cp = symbol; /* current position */ - if (*in=='{') { + char symbol[32]; + + char *cp = symbol; /* current position */ + + if (*in == '{') { braces = true; ++in; } - while (isalnum(*in) || *in=='.') *cp++ = *in++; + while (isalnum(*in) || *in == '.') + *cp++ = *in++; *cp = '\0'; /* symbol will now contain the symbol name */ - if (*in=='(') { + if (*in == '(') { /* it's a function we need to parse, start by reading the parameters */ - function * foo; + function *foo; + while (*in != ')') { - in = parse(stack, ++in, userdata); /* will push the result on the stack */ - if (in==NULL) return NULL; + in = parse(stack, ++in, userdata); /* will push the result on the stack */ + if (in == NULL) + return NULL; } ++in; foo = find_function(symbol); - if (foo==NULL) { + if (foo == NULL) { log_error(("parser does not know about \"%s\" function.\n", symbol)); return NULL; } - foo->parse(stack, userdata); /* will pop parameters from stack (reverse order!) and push the result */ + foo->parse(stack, userdata); /* will pop parameters from stack (reverse order!) and push the result */ } else { - variable * var = find_variable(symbol); - if (braces && *in=='}') { + variable *var = find_variable(symbol); + + if (braces && *in == '}') { ++in; } /* it's a constant (variable is a misnomer, but heck, const was taken;)) */ - if (var==NULL) { + if (var == NULL) { log_error(("parser does not know about \"%s\" variable.\n", symbol)); return NULL; } @@ -244,17 +249,24 @@ parse_symbol(opstack ** stack, const char* in, const void * userdata) } #define TOKENSIZE 4096 -static const char * -parse_string(opstack ** stack, const char* in, const void * userdata) /* (char*) -> char* */ -{ - char * c; - char * buffer = balloc(TOKENSIZE); +static const char *parse_string(opstack ** stack, const char *in, + const void *userdata) +{ /* (char*) -> char* */ + char *c; + + char *buffer = balloc(TOKENSIZE); + size_t size = TOKENSIZE - 1; - const char * ic = in; - char * oc = buffer; + + const char *ic = in; + + char *oc = buffer; + /* mode flags */ boolean f_escape = false; + boolean bDone = false; + variant var; while (*ic && !bDone) { @@ -262,16 +274,26 @@ parse_string(opstack ** stack, const char* in, const void * userdata) /* (char*) f_escape = false; switch (*ic) { case 'n': - if (size>0) { *oc++='\n'; --size; } + if (size > 0) { + *oc++ = '\n'; + --size; + } break; case 't': - if (size>0) { *oc++='\t'; --size; } + if (size > 0) { + *oc++ = '\t'; + --size; + } break; default: - if (size>0) { *oc++=*ic++; --size; } + if (size > 0) { + *oc++ = *ic++; + --size; + } } } else { int ch = (unsigned char)(*ic); + int bytes; switch (ch) { @@ -285,16 +307,22 @@ parse_string(opstack ** stack, const char* in, const void * userdata) /* (char*) break; case '$': ic = parse_symbol(stack, ++ic, userdata); - if (ic==NULL) return NULL; - c = (char*)opop_v(stack); + if (ic == NULL) + return NULL; + c = (char *)opop_v(stack); bytes = (int)strlcpy(oc, c, size); - if (bytes<(int)size) oc += bytes; - else oc += size; + if (bytes < (int)size) + oc += bytes; + else + oc += size; bfree(c); break; default: - if (size>0) { *oc++=*ic++; --size; } - else ++ic; + if (size > 0) { + *oc++ = *ic++; + --size; + } else + ++ic; } } } @@ -305,13 +333,16 @@ parse_string(opstack ** stack, const char* in, const void * userdata) /* (char*) return ic; } -static const char * -parse_int(opstack ** stack, const char * in) +static const char *parse_int(opstack ** stack, const char *in) { int k = 0; + int vz = 1; + boolean ok = false; + variant var; + do { switch (*in) { case '+': @@ -319,25 +350,26 @@ parse_int(opstack ** stack, const char * in) break; case '-': ++in; - vz=vz*-1; + vz = vz * -1; break; default: ok = true; } } while (!ok); - while (isdigit(*(unsigned char*)in)) { - k = k * 10 + (*in++)-'0'; + while (isdigit(*(unsigned char *)in)) { + k = k * 10 + (*in++) - '0'; } - var.i = k*vz; + var.i = k * vz; opush(stack, var); return in; } -static const char * -parse(opstack ** stack, const char* inn, const void * userdata) +static const char *parse(opstack ** stack, const char *inn, + const void *userdata) { - const char * b = inn; + const char *b = inn; + while (*b) { switch (*b) { case '"': @@ -347,25 +379,30 @@ parse(opstack ** stack, const char* inn, const void * userdata) return parse_symbol(stack, ++b, userdata); break; default: - if (isdigit(*(unsigned char*)b) || *b=='-' || *b=='+') { + if (isdigit(*(unsigned char *)b) || *b == '-' || *b == '+') { return parse_int(stack, b); - } - else ++b; + } else + ++b; } } log_error(("could not parse \"%s\". Probably invalid message syntax.", inn)); return NULL; } -const char * -translate(const char* format, const void * userdata, const char* vars, variant args[]) +const char *translate(const char *format, const void *userdata, + const char *vars, variant args[]) { int i = 0; + const char *ic = vars; + char symbol[32]; + char *oc = symbol; - opstack * stack = NULL; - const char * rv; + + opstack *stack = NULL; + + const char *rv; brelease(); free_variables(); @@ -376,100 +413,109 @@ translate(const char* format, const void * userdata, const char* vars, variant a *oc++ = *ic++; if (!isalnum(*ic)) { variant x = args[i++]; + *oc = '\0'; oc = symbol; - add_variable(strcpy(balloc(strlen(symbol)+1), symbol), x); - while (*ic && !isalnum(*ic)) ++ic; + add_variable(strcpy(balloc(strlen(symbol) + 1), symbol), x); + while (*ic && !isalnum(*ic)) + ++ic; } } - if (format[0]=='"') { + if (format[0] == '"') { rv = parse(&stack, format, userdata); - } - else { + } else { rv = parse_string(&stack, format, userdata); } - if (rv!=NULL) { + if (rv != NULL) { if (rv[0]) { log_error(("residual data after parsing: %s\n", rv)); } - rv = (const char*)opop(&stack).v; + rv = (const char *)opop(&stack).v; free(stack->begin); free(stack); } return rv; } -static void -eval_lt(opstack ** stack, const void * userdata) /* (int, int) -> int */ -{ +static void eval_lt(opstack ** stack, const void *userdata) +{ /* (int, int) -> int */ int a = opop_i(stack); + int b = opop_i(stack); - int rval = (b int */ -{ +static void eval_eq(opstack ** stack, const void *userdata) +{ /* (int, int) -> int */ int a = opop_i(stack); + int b = opop_i(stack); - int rval = (a==b)?1:0; + + int rval = (a == b) ? 1 : 0; + opush_i(stack, rval); unused(userdata); } -static void -eval_add(opstack ** stack, const void * userdata) /* (int, int) -> int */ -{ - int a = opop_i(stack); - int b = opop_i(stack); - opush_i(stack, a+b); - unused(userdata); +static void eval_add(opstack ** stack, const void *userdata) +{ /* (int, int) -> int */ + int a = opop_i(stack); + + int b = opop_i(stack); + + opush_i(stack, a + b); + unused(userdata); } -static void -eval_isnull(opstack ** stack, const void * userdata) /* (int, int) -> int */ -{ - void * a = opop_v(stack); - opush_i(stack, (a==NULL)?1:0); - unused(userdata); +static void eval_isnull(opstack ** stack, const void *userdata) +{ /* (int, int) -> int */ + void *a = opop_v(stack); + + opush_i(stack, (a == NULL) ? 1 : 0); + unused(userdata); } -static void -eval_if(opstack ** stack, const void * userdata) /* (int, int) -> int */ -{ - void * a = opop_v(stack); - void * b = opop_v(stack); - int cond = opop_i(stack); - opush_v(stack, cond?b:a); - unused(userdata); +static void eval_if(opstack ** stack, const void *userdata) +{ /* (int, int) -> int */ + void *a = opop_v(stack); + + void *b = opop_v(stack); + + int cond = opop_i(stack); + + opush_v(stack, cond ? b : a); + unused(userdata); } -static void -eval_strlen(opstack ** stack, const void * userdata) /* string -> int */ -{ - const char * c = (const char *)opop_v(stack); - opush_i(stack, c?(int)strlen(c):0); - unused(userdata); +static void eval_strlen(opstack ** stack, const void *userdata) +{ /* string -> int */ + const char *c = (const char *)opop_v(stack); + + opush_i(stack, c ? (int)strlen(c) : 0); + unused(userdata); } #include "base36.h" -static void -eval_int(opstack ** stack, const void * userdata) +static void eval_int(opstack ** stack, const void *userdata) { - int i = opop_i(stack); - const char * c = itoa10(i); + int i = opop_i(stack); + + const char *c = itoa10(i); + size_t len = strlen(c); + variant var; - var.v = strcpy(balloc(len+1), c); + var.v = strcpy(balloc(len + 1), c); opush(stack, var); } -void -translation_init(void) +void translation_init(void) { add_function("lt", &eval_lt); add_function("eq", &eval_eq); @@ -480,9 +526,8 @@ translation_init(void) add_function("isnull", &eval_isnull); } -void -translation_done(void) +void translation_done(void) { - free_functions(); - free(buffer.begin); + free_functions(); + free(buffer.begin); } diff --git a/src/util/translation.h b/src/util/translation.h index 6aa6dd28d..f918c3357 100644 --- a/src/util/translation.h +++ b/src/util/translation.h @@ -17,27 +17,28 @@ extern "C" { #endif #include "variant.h" -struct opstack; -extern void opstack_push(struct opstack ** stack, variant data); + struct opstack; + extern void opstack_push(struct opstack **stack, variant data); #define opush_i(stack, x) { variant localvar; localvar.i = x; opstack_push(stack, localvar); } #define opush_v(stack, x) { variant localvar; localvar.v = x; opstack_push(stack, localvar); } #define opush(stack, i) opstack_push(stack, i) -extern variant opstack_pop(struct opstack ** stack); + extern variant opstack_pop(struct opstack **stack); #define opop_v(stack) opstack_pop(stack).v #define opop_i(stack) opstack_pop(stack).i #define opop(stack) opstack_pop(stack) -extern void translation_init(void); -extern void translation_done(void); -extern const char * translate(const char* format, const void * userdata, const char* vars, variant args[]); + extern void translation_init(void); + extern void translation_done(void); + extern const char *translate(const char *format, const void *userdata, + const char *vars, variant args[]); /* eval_x functions */ -typedef void (*evalfun)(struct opstack ** stack, const void *); -extern void add_function(const char * symbol, evalfun parse); + typedef void (*evalfun) (struct opstack ** stack, const void *); + extern void add_function(const char *symbol, evalfun parse); /* transient memory blocks */ -extern char * balloc(size_t size); + extern char *balloc(size_t size); #ifdef __cplusplus } diff --git a/src/util/umlaut.c b/src/util/umlaut.c index 67bd03964..d2c707afa 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -28,43 +28,53 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include typedef struct tref { - struct tref * nexthash; + struct tref *nexthash; ucs4_t ucs; - struct tnode * node; + struct tnode *node; } tref; -#define LEAF 1 /* leaf node for a word. always matches */ -#define SHARED 2 /* at least two words share the node */ +#define LEAF 1 /* leaf node for a word. always matches */ +#define SHARED 2 /* at least two words share the node */ -void -addtoken(tnode * root, const char * str, variant id) +void addtoken(tnode * root, const char *str, variant id) { static const struct replace { /* STATIC_CONST: constant value */ ucs4_t ucs; const char str[3]; } replace[] = { /* match lower-case (!) umlauts and others to transcriptions */ - { 228, "AE"}, /* auml */ - { 246, "OE"}, /* ouml */ - { 252, "UE"}, /* uuml */ - { 223, "SS"}, /* szlig */ - { 230, "AE"}, /* norsk */ - { 248, "OE"}, /* norsk */ - { 229, "AA"}, /* norsk */ - { 0, "" } + { + 228, "AE"}, /* auml */ + { + 246, "OE"}, /* ouml */ + { + 252, "UE"}, /* uuml */ + { + 223, "SS"}, /* szlig */ + { + 230, "AE"}, /* norsk */ + { + 248, "OE"}, /* norsk */ + { + 229, "AA"}, /* norsk */ + { + 0, ""} }; if (!*str) { root->id = id; root->flags |= LEAF; } else { - tref * next; + tref *next; + int ret, index, i = 0; + ucs4_t ucs, lcs; + size_t len; ret = unicode_utf8_to_ucs4(&ucs, str, &len); - assert(ret==0 || !"invalid utf8 string"); + assert(ret == 0 || !"invalid utf8 string"); lcs = ucs; #if NODEHASHSIZE == 8 @@ -72,29 +82,32 @@ addtoken(tnode * root, const char * str, variant id) #else index = ucs % NODEHASHSIZE; #endif - assert(index>=0); + assert(index >= 0); next = root->next[index]; - if (!(root->flags & LEAF)) root->id = id; - while (next && next->ucs != ucs) next = next->nexthash; + if (!(root->flags & LEAF)) + root->id = id; + while (next && next->ucs != ucs) + next = next->nexthash; if (!next) { - tref * ref; - tnode * node = calloc(1, sizeof(tnode)); + tref *ref; - if (ucs<'a' || ucs>'z') { - lcs = towlower((wint_t)ucs); + tnode *node = calloc(1, sizeof(tnode)); + + if (ucs < 'a' || ucs > 'z') { + lcs = towlower((wint_t) ucs); } - if (ucs==lcs) { - ucs = towupper((wint_t)ucs); + if (ucs == lcs) { + ucs = towupper((wint_t) ucs); } ref = malloc(sizeof(tref)); ref->ucs = ucs; ref->node = node; - ref->nexthash=root->next[index]; + ref->nexthash = root->next[index]; root->next[index] = ref; /* try lower/upper casing the character, and try again */ - if (ucs!=lcs) { + if (ucs != lcs) { #if NODEHASHSIZE == 8 index = lcs & 7; #else @@ -106,17 +119,19 @@ addtoken(tnode * root, const char * str, variant id) ref->nexthash = root->next[index]; root->next[index] = ref; } - next=ref; + next = ref; } else { next->node->flags |= SHARED; - if ((next->node->flags & LEAF) == 0) next->node->id.v = NULL; /* why?*/ + if ((next->node->flags & LEAF) == 0) + next->node->id.v = NULL; /* why? */ } - addtoken(next->node, str+len, id); + addtoken(next->node, str + len, id); while (replace[i].str[0]) { - if (lcs==replace[i].ucs) { + if (lcs == replace[i].ucs) { char zText[1024]; + memcpy(zText, replace[i].str, 3); - strcpy(zText+2, (const char*)str+len); + strcpy(zText + 2, (const char *)str + len); addtoken(root, zText, id); break; } @@ -125,19 +140,23 @@ addtoken(tnode * root, const char * str, variant id) } } -int -findtoken(const tnode * tk, const char * str, variant* result) +int findtoken(const tnode * tk, const char *str, variant * result) { - if (!str || *str==0) return E_TOK_NOMATCH; + if (!str || *str == 0) + return E_TOK_NOMATCH; do { int index; - const tref * ref; + + const tref *ref; + ucs4_t ucs; + size_t len; + int ret = unicode_utf8_to_ucs4(&ucs, str, &len); - if (ret!=0) { + if (ret != 0) { /* encoding is broken. youch */ return E_TOK_NOMATCH; } @@ -147,9 +166,11 @@ findtoken(const tnode * tk, const char * str, variant* result) index = ucs % NODEHASHSIZE; #endif ref = tk->next[index]; - while (ref && ref->ucs!=ucs) ref = ref->nexthash; - str+=len; - if (!ref) return E_TOK_NOMATCH; + while (ref && ref->ucs != ucs) + ref = ref->nexthash; + str += len; + if (!ref) + return E_TOK_NOMATCH; tk = ref->node; } while (*str); if (tk) { diff --git a/src/util/umlaut.h b/src/util/umlaut.h index a89f3df77..aeabccc39 100644 --- a/src/util/umlaut.h +++ b/src/util/umlaut.h @@ -28,22 +28,22 @@ extern "C" { #define E_TOK_NOMATCH (-1) #define E_TOK_SUCCESS 0 #define NODEHASHSIZE 8 -struct tref; + struct tref; -typedef struct tnode { - struct tref * next[NODEHASHSIZE]; - unsigned char flags; - variant id; -} tnode; + typedef struct tnode { + struct tref *next[NODEHASHSIZE]; + unsigned char flags; + variant id; + } tnode; -int findtoken(const struct tnode * tk, const char * str, variant* result); -void addtoken(struct tnode * root, const char * str, variant id); + int findtoken(const struct tnode *tk, const char *str, variant * result); + void addtoken(struct tnode *root, const char *str, variant id); -typedef struct local_names { - struct local_names * next; - const struct locale * lang; - struct tnode names; -} local_names; + typedef struct local_names { + struct local_names *next; + const struct locale *lang; + struct tnode names; + } local_names; #ifdef __cplusplus } diff --git a/src/util/unicode.c b/src/util/unicode.c index adda90870..91642a5bd 100644 --- a/src/util/unicode.c +++ b/src/util/unicode.c @@ -30,38 +30,40 @@ #define B00000011 0x03 #define B00000001 0x01 -int -unicode_utf8_tolower(utf8_t *op, size_t outlen, const utf8_t *ip) +int unicode_utf8_tolower(utf8_t * op, size_t outlen, const utf8_t * ip) { while (*ip) { ucs4_t ucs = *ip; + ucs4_t low; + size_t size = 1; if (ucs & 0x80) { int ret = unicode_utf8_to_ucs4(&ucs, ip, &size); - if (ret!=0) { + + if (ret != 0) { return ret; } } - if (size>outlen) { + if (size > outlen) { return ENOMEM; } - low = towlower((wint_t)ucs); - if (low==ucs) { + low = towlower((wint_t) ucs); + if (low == ucs) { memcpy(op, ip, size); ip += size; op += size; - outlen -=size; + outlen -= size; } else { ip += size; unicode_ucs4_to_utf8(op, &size, low); op += size; - outlen -=size; + outlen -= size; } } - if (outlen<=0) { + if (outlen <= 0) { return ENOMEM; } *op = 0; @@ -69,117 +71,135 @@ unicode_utf8_tolower(utf8_t *op, size_t outlen, const utf8_t *ip) } int -unicode_latin1_to_utf8(utf8_t *out, size_t *outlen, const char *in, size_t *inlen) +unicode_latin1_to_utf8(utf8_t * out, size_t * outlen, const char *in, + size_t * inlen) { int is = (int)*inlen; - int os = (int)*outlen; - const char * ip = in; - utf8_t * op = out; - while (ip-in 0xBF) { - if (op-out>=os-1) break; + if (op - out >= os - 1) + break; *op++ = 0xC3; - *op++ = c-64; - } else if (c>0x7F) { - if (op-out>=os-1) break; + *op++ = c - 64; + } else if (c > 0x7F) { + if (op - out >= os - 1) + break; *op++ = 0xC2; *op++ = c; } else { - if (op-out>=os) break; + if (op - out >= os) + break; *op++ = c; } ++ip; } - *outlen = op-out; - *inlen = ip-in; + *outlen = op - out; + *inlen = ip - in; return (int)*outlen; } -int -unicode_utf8_strcasecmp(const utf8_t * a, const char * b) +int unicode_utf8_strcasecmp(const utf8_t * a, const char *b) { while (*a && *b) { int ret; + size_t size; + ucs4_t ucsa = *a, ucsb = *b; if (ucsa & 0x80) { ret = unicode_utf8_to_ucs4(&ucsa, a, &size); - if (ret!=0) return -1; + if (ret != 0) + return -1; a += size; - } else ++a; + } else + ++a; if (ucsb & 0x80) { ret = unicode_utf8_to_ucs4(&ucsb, b, &size); - if (ret!=0) return -1; + if (ret != 0) + return -1; b += size; - } else ++b; + } else + ++b; - if (ucsb!=ucsa) { - ucsb = towlower((wint_t)ucsb); - ucsa = towlower((wint_t)ucsa); - if (ucsbucsa) return -1; + if (ucsb != ucsa) { + ucsb = towlower((wint_t) ucsb); + ucsa = towlower((wint_t) ucsa); + if (ucsb < ucsa) + return 1; + if (ucsb > ucsa) + return -1; } } - if (*b) return -1; - if (*a) return 1; + if (*b) + return -1; + if (*a) + return 1; return 0; } /* Convert a UCS-4 character to UTF-8. */ int -unicode_ucs4_to_utf8 (utf8_t *utf8_character, size_t *size, ucs4_t ucs4_character) +unicode_ucs4_to_utf8(utf8_t * utf8_character, size_t * size, + ucs4_t ucs4_character) { int utf8_bytes; if (ucs4_character <= 0x0000007F) { /* 0xxxxxxx */ utf8_bytes = 1; - utf8_character[0] = (char) ucs4_character; - } - else if (ucs4_character <= 0x000007FF) { + utf8_character[0] = (char)ucs4_character; + } else if (ucs4_character <= 0x000007FF) { /* 110xxxxx 10xxxxxx */ utf8_bytes = 2; - utf8_character[0] = (char) ((ucs4_character >> 6) | B11000000); - utf8_character[1] = (char) ((ucs4_character & B00111111) | B10000000); - } - else if (ucs4_character <= 0x0000FFFF) { + utf8_character[0] = (char)((ucs4_character >> 6) | B11000000); + utf8_character[1] = (char)((ucs4_character & B00111111) | B10000000); + } else if (ucs4_character <= 0x0000FFFF) { /* 1110xxxx 10xxxxxx 10xxxxxx */ utf8_bytes = 3; - utf8_character[0] = (char) ((ucs4_character >> 12) | B11100000); - utf8_character[1] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); - utf8_character[2] = (char) ((ucs4_character & B00111111) | B10000000); - } - else if (ucs4_character <= 0x001FFFFF) { + utf8_character[0] = (char)((ucs4_character >> 12) | B11100000); + utf8_character[1] = (char)(((ucs4_character >> 6) & B00111111) | B10000000); + utf8_character[2] = (char)((ucs4_character & B00111111) | B10000000); + } else if (ucs4_character <= 0x001FFFFF) { /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ utf8_bytes = 4; - utf8_character[0] = (char) ((ucs4_character >> 18) | B11110000); - utf8_character[1] = (char) (((ucs4_character >> 12) & B00111111) | B10000000); - utf8_character[2] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); - utf8_character[3] = (char) ((ucs4_character & B00111111) | B10000000); - } - else if (ucs4_character <= 0x03FFFFFF) { + utf8_character[0] = (char)((ucs4_character >> 18) | B11110000); + utf8_character[1] = + (char)(((ucs4_character >> 12) & B00111111) | B10000000); + utf8_character[2] = (char)(((ucs4_character >> 6) & B00111111) | B10000000); + utf8_character[3] = (char)((ucs4_character & B00111111) | B10000000); + } else if (ucs4_character <= 0x03FFFFFF) { /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ utf8_bytes = 5; - utf8_character[0] = (char) ((ucs4_character >> 24) | B11111000); - utf8_character[1] = (char) (((ucs4_character >> 18) & B00111111) | B10000000); - utf8_character[2] = (char) (((ucs4_character >> 12) & B00111111) | B10000000); - utf8_character[3] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); - utf8_character[4] = (char) ((ucs4_character & B00111111) | B10000000); - } - else if (ucs4_character <= 0x7FFFFFFF) { + utf8_character[0] = (char)((ucs4_character >> 24) | B11111000); + utf8_character[1] = + (char)(((ucs4_character >> 18) & B00111111) | B10000000); + utf8_character[2] = + (char)(((ucs4_character >> 12) & B00111111) | B10000000); + utf8_character[3] = (char)(((ucs4_character >> 6) & B00111111) | B10000000); + utf8_character[4] = (char)((ucs4_character & B00111111) | B10000000); + } else if (ucs4_character <= 0x7FFFFFFF) { /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ utf8_bytes = 6; - utf8_character[0] = (char) ((ucs4_character >> 30) | B11111100); - utf8_character[1] = (char) (((ucs4_character >> 24) & B00111111) | B10000000); - utf8_character[2] = (char) (((ucs4_character >> 18) & B00111111) | B10000000); - utf8_character[3] = (char) (((ucs4_character >> 12) & B00111111) | B10000000); - utf8_character[4] = (char) (((ucs4_character >> 6) & B00111111) | B10000000); - utf8_character[5] = (char) ((ucs4_character & B00111111) | B10000000); - } - else { + utf8_character[0] = (char)((ucs4_character >> 30) | B11111100); + utf8_character[1] = + (char)(((ucs4_character >> 24) & B00111111) | B10000000); + utf8_character[2] = + (char)(((ucs4_character >> 18) & B00111111) | B10000000); + utf8_character[3] = + (char)(((ucs4_character >> 12) & B00111111) | B10000000); + utf8_character[4] = (char)(((ucs4_character >> 6) & B00111111) | B10000000); + utf8_character[5] = (char)((ucs4_character & B00111111) | B10000000); + } else { return EILSEQ; } @@ -191,99 +211,76 @@ unicode_ucs4_to_utf8 (utf8_t *utf8_character, size_t *size, ucs4_t ucs4_characte /* Convert a UTF-8 encoded character to UCS-4. */ int -unicode_utf8_to_ucs4(ucs4_t *ucs4_character, const utf8_t *utf8_string, - size_t *length) +unicode_utf8_to_ucs4(ucs4_t * ucs4_character, const utf8_t * utf8_string, + size_t * length) { utf8_t utf8_character = utf8_string[0]; /* Is the character in the ASCII range? If so, just copy it to the - output. */ - if (~utf8_character & 0x80) - { + output. */ + if (~utf8_character & 0x80) { *ucs4_character = utf8_character; *length = 1; - } - else if ((utf8_character & 0xE0) == 0xC0) - { + } else if ((utf8_character & 0xE0) == 0xC0) { /* A two-byte UTF-8 sequence. Make sure the other byte is good. */ - if (utf8_string[1] != '\0' && - (utf8_string[1] & 0xC0) != 0x80) - { + if (utf8_string[1] != '\0' && (utf8_string[1] & 0xC0) != 0x80) { return EILSEQ; } *ucs4_character = - ((utf8_string[1] & 0x3F) << 0) + - ((utf8_character & 0x1F) << 6); + ((utf8_string[1] & 0x3F) << 0) + ((utf8_character & 0x1F) << 6); *length = 2; - } - else if ((utf8_character & 0xF0) == 0xE0) - { + } else if ((utf8_character & 0xF0) == 0xE0) { /* A three-byte UTF-8 sequence. Make sure the other bytes are - good. */ + good. */ if ((utf8_string[1] != '\0') && (utf8_string[1] & 0xC0) != 0x80 && - (utf8_string[2] != '\0') && - (utf8_string[2] & 0xC0) != 0x80) - { + (utf8_string[2] != '\0') && (utf8_string[2] & 0xC0) != 0x80) { return EILSEQ; } - *ucs4_character = + *ucs4_character = ((utf8_string[2] & 0x3F) << 0) + - ((utf8_string[1] & 0x3F) << 6) + - ((utf8_character & 0x0F) << 12); + ((utf8_string[1] & 0x3F) << 6) + ((utf8_character & 0x0F) << 12); *length = 3; - } - else if ((utf8_character & 0xF8) == 0xF0) - { + } else if ((utf8_character & 0xF8) == 0xF0) { /* A four-byte UTF-8 sequence. Make sure the other bytes are - good. */ + good. */ if ((utf8_string[1] != '\0') && (utf8_string[1] & 0xC0) != 0x80 && (utf8_string[2] != '\0') && (utf8_string[2] & 0xC0) != 0x80 && - (utf8_string[3] != '\0') && - (utf8_string[3] & 0xC0) != 0x80) - { + (utf8_string[3] != '\0') && (utf8_string[3] & 0xC0) != 0x80) { return EILSEQ; } - *ucs4_character = + *ucs4_character = ((utf8_string[3] & 0x3F) << 0) + ((utf8_string[2] & 0x3F) << 6) + - ((utf8_string[1] & 0x3F) << 12) + - ((utf8_character & 0x07) << 18); + ((utf8_string[1] & 0x3F) << 12) + ((utf8_character & 0x07) << 18); *length = 4; - } - else if ((utf8_character & 0xFC) == 0xF8) - { + } else if ((utf8_character & 0xFC) == 0xF8) { /* A five-byte UTF-8 sequence. Make sure the other bytes are - good. */ + good. */ if ((utf8_string[1] != '\0') && (utf8_string[1] & 0xC0) != 0x80 && (utf8_string[2] != '\0') && (utf8_string[2] & 0xC0) != 0x80 && (utf8_string[3] != '\0') && (utf8_string[3] & 0xC0) != 0x80 && - (utf8_string[4] != '\0') && - (utf8_string[4] & 0xC0) != 0x80) - { + (utf8_string[4] != '\0') && (utf8_string[4] & 0xC0) != 0x80) { return EILSEQ; } - *ucs4_character = + *ucs4_character = ((utf8_string[4] & 0x3F) << 0) + ((utf8_string[3] & 0x3F) << 6) + ((utf8_string[2] & 0x3F) << 12) + - ((utf8_string[1] & 0x3F) << 18) + - ((utf8_character & 0x03) << 24); + ((utf8_string[1] & 0x3F) << 18) + ((utf8_character & 0x03) << 24); *length = 5; - } - else if ((utf8_character & 0xFE) == 0xFC) - { + } else if ((utf8_character & 0xFE) == 0xFC) { /* A six-byte UTF-8 sequence. Make sure the other bytes are - good. */ + good. */ if ((utf8_string[1] != '\0') && (utf8_string[1] & 0xC0) != 0x80 && (utf8_string[2] != '\0') && @@ -292,23 +289,18 @@ unicode_utf8_to_ucs4(ucs4_t *ucs4_character, const utf8_t *utf8_string, (utf8_string[3] & 0xC0) != 0x80 && (utf8_string[4] != '\0') && (utf8_string[4] & 0xC0) != 0x80 && - (utf8_string[5] != '\0') && - (utf8_string[5] & 0xC0) != 0x80) - { + (utf8_string[5] != '\0') && (utf8_string[5] & 0xC0) != 0x80) { return EILSEQ; } - *ucs4_character = + *ucs4_character = ((utf8_string[5] & 0x3F) << 0) + ((utf8_string[4] & 0x3F) << 6) + ((utf8_string[3] & 0x3F) << 12) + ((utf8_string[2] & 0x3F) << 18) + - ((utf8_string[1] & 0x3F) << 24) + - ((utf8_character & 0x01) << 30); + ((utf8_string[1] & 0x3F) << 24) + ((utf8_character & 0x01) << 30); *length = 6; - } - else - { + } else { return EILSEQ; } @@ -317,74 +309,202 @@ unicode_utf8_to_ucs4(ucs4_t *ucs4_character, const utf8_t *utf8_string, /** Convert a UTF-8 encoded character to CP437. */ int -unicode_utf8_to_cp437(char *cp_character, const utf8_t *utf8_string, - size_t *length) +unicode_utf8_to_cp437(char *cp_character, const utf8_t * utf8_string, + size_t * length) { ucs4_t ucs4_character; + int result; result = unicode_utf8_to_ucs4(&ucs4_character, utf8_string, length); - if (result!=0) { + if (result != 0) { /* pass decoding characters upstream */ return result; } - - if (ucs4_character<0x7F) { + + if (ucs4_character < 0x7F) { *cp_character = (char)ucs4_character; } else { - struct { ucs4_t ucs4; unsigned char cp437; } xref[160] = { - {0x00A0, 255}, {0x00A1, 173}, {0x00A2, 155}, {0x00A3, 156}, - {0x00A5, 157}, {0x00A7, 21}, {0x00AA, 166}, {0x00AB, 174}, - {0x00AC, 170}, {0x00B0, 248}, {0x00B1, 241}, {0x00B2, 253}, - {0x00B5, 230}, {0x00B6, 20}, {0x00B7, 250}, {0x00BA, 167}, - {0x00BB, 175}, {0x00BC, 172}, {0x00BD, 171}, {0x00BF, 168}, - {0x00C4, 142}, {0x00C5, 143}, {0x00C6, 146}, {0x00C7, 128}, - {0x00C9, 144}, {0x00D1, 165}, {0x00D6, 153}, {0x00DC, 154}, - {0x00DF, 225}, {0x00E0, 133}, {0x00E1, 160}, {0x00E2, 131}, - {0x00E4, 132}, {0x00E5, 134}, {0x00E6, 145}, {0x00E7, 135}, - {0x00E8, 138}, {0x00E9, 130}, {0x00EA, 136}, {0x00EB, 137}, - {0x00EC, 141}, {0x00ED, 161}, {0x00EE, 140}, {0x00EF, 139}, - {0x00F1, 164}, {0x00F2, 149}, {0x00F3, 162}, {0x00F4, 147}, - {0x00F6, 148}, {0x00F7, 246}, {0x00F9, 151}, {0x00FA, 163}, - {0x00FB, 150}, {0x00FC, 129}, {0x00FF, 152}, {0x0192, 159}, - {0x0393, 226}, {0x0398, 233}, {0x03A3, 228}, {0x03A6, 232}, - {0x03A9, 234}, {0x03B1, 224}, {0x03B4, 235}, {0x03B5, 238}, - {0x03C0, 227}, {0x03C3, 229}, {0x03C4, 231}, {0x03C6, 237}, - {0x2022, 7}, {0x203C, 19}, {0x207F, 252}, {0x20A7, 158}, - {0x2190, 27}, {0x2191, 24}, {0x2192, 26}, {0x2193, 25}, - {0x2194, 29}, {0x2195, 18}, {0x21A8, 23}, {0x2219, 249}, - {0x221A, 251}, {0x221E, 236}, {0x221F, 28}, {0x2229, 239}, - {0x2248, 247}, {0x2261, 240}, {0x2264, 243}, {0x2265, 242}, - {0x2302, 127}, {0x2310, 169}, {0x2320, 244}, {0x2321, 245}, - {0x2500, 196}, {0x2502, 179}, {0x250C, 218}, {0x2510, 191}, - {0x2514, 192}, {0x2518, 217}, {0x251C, 195}, {0x2524, 180}, - {0x252C, 194}, {0x2534, 193}, {0x253C, 197}, {0x2550, 205}, - {0x2551, 186}, {0x2552, 213}, {0x2553, 214}, {0x2554, 201}, - {0x2555, 184}, {0x2556, 183}, {0x2557, 187}, {0x2558, 212}, - {0x2559, 211}, {0x255A, 200}, {0x255B, 190}, {0x255C, 189}, - {0x255D, 188}, {0x255E, 198}, {0x255F, 199}, {0x2560, 204}, - {0x2561, 181}, {0x2562, 182}, {0x2563, 185}, {0x2564, 209}, - {0x2565, 210}, {0x2566, 203}, {0x2567, 207}, {0x2568, 208}, - {0x2569, 202}, {0x256A, 216}, {0x256B, 215}, {0x256C, 206}, - {0x2580, 223}, {0x2584, 220}, {0x2588, 219}, {0x258C, 221}, - {0x2590, 222}, {0x2591, 176}, {0x2592, 177}, {0x2593, 178}, - {0x25A0, 254}, {0x25AC, 22}, {0x25B2, 30}, {0x25BA, 16}, - {0x25BC, 31}, {0x25C4, 17}, {0x25CB, 9}, {0x25D8, 8}, - {0x25D9, 10}, {0x263A, 1}, {0x263B, 2}, {0x263C, 15}, - {0x2640, 12}, {0x2642, 11}, {0x2660, 6}, {0x2663, 5}, - {0x2665, 3}, {0x2666, 4}, {0x266A, 13}, {0x266B, 14} + struct { + ucs4_t ucs4; + unsigned char cp437; + } xref[160] = { + { + 0x00A0, 255}, { + 0x00A1, 173}, { + 0x00A2, 155}, { + 0x00A3, 156}, { + 0x00A5, 157}, { + 0x00A7, 21}, { + 0x00AA, 166}, { + 0x00AB, 174}, { + 0x00AC, 170}, { + 0x00B0, 248}, { + 0x00B1, 241}, { + 0x00B2, 253}, { + 0x00B5, 230}, { + 0x00B6, 20}, { + 0x00B7, 250}, { + 0x00BA, 167}, { + 0x00BB, 175}, { + 0x00BC, 172}, { + 0x00BD, 171}, { + 0x00BF, 168}, { + 0x00C4, 142}, { + 0x00C5, 143}, { + 0x00C6, 146}, { + 0x00C7, 128}, { + 0x00C9, 144}, { + 0x00D1, 165}, { + 0x00D6, 153}, { + 0x00DC, 154}, { + 0x00DF, 225}, { + 0x00E0, 133}, { + 0x00E1, 160}, { + 0x00E2, 131}, { + 0x00E4, 132}, { + 0x00E5, 134}, { + 0x00E6, 145}, { + 0x00E7, 135}, { + 0x00E8, 138}, { + 0x00E9, 130}, { + 0x00EA, 136}, { + 0x00EB, 137}, { + 0x00EC, 141}, { + 0x00ED, 161}, { + 0x00EE, 140}, { + 0x00EF, 139}, { + 0x00F1, 164}, { + 0x00F2, 149}, { + 0x00F3, 162}, { + 0x00F4, 147}, { + 0x00F6, 148}, { + 0x00F7, 246}, { + 0x00F9, 151}, { + 0x00FA, 163}, { + 0x00FB, 150}, { + 0x00FC, 129}, { + 0x00FF, 152}, { + 0x0192, 159}, { + 0x0393, 226}, { + 0x0398, 233}, { + 0x03A3, 228}, { + 0x03A6, 232}, { + 0x03A9, 234}, { + 0x03B1, 224}, { + 0x03B4, 235}, { + 0x03B5, 238}, { + 0x03C0, 227}, { + 0x03C3, 229}, { + 0x03C4, 231}, { + 0x03C6, 237}, { + 0x2022, 7}, { + 0x203C, 19}, { + 0x207F, 252}, { + 0x20A7, 158}, { + 0x2190, 27}, { + 0x2191, 24}, { + 0x2192, 26}, { + 0x2193, 25}, { + 0x2194, 29}, { + 0x2195, 18}, { + 0x21A8, 23}, { + 0x2219, 249}, { + 0x221A, 251}, { + 0x221E, 236}, { + 0x221F, 28}, { + 0x2229, 239}, { + 0x2248, 247}, { + 0x2261, 240}, { + 0x2264, 243}, { + 0x2265, 242}, { + 0x2302, 127}, { + 0x2310, 169}, { + 0x2320, 244}, { + 0x2321, 245}, { + 0x2500, 196}, { + 0x2502, 179}, { + 0x250C, 218}, { + 0x2510, 191}, { + 0x2514, 192}, { + 0x2518, 217}, { + 0x251C, 195}, { + 0x2524, 180}, { + 0x252C, 194}, { + 0x2534, 193}, { + 0x253C, 197}, { + 0x2550, 205}, { + 0x2551, 186}, { + 0x2552, 213}, { + 0x2553, 214}, { + 0x2554, 201}, { + 0x2555, 184}, { + 0x2556, 183}, { + 0x2557, 187}, { + 0x2558, 212}, { + 0x2559, 211}, { + 0x255A, 200}, { + 0x255B, 190}, { + 0x255C, 189}, { + 0x255D, 188}, { + 0x255E, 198}, { + 0x255F, 199}, { + 0x2560, 204}, { + 0x2561, 181}, { + 0x2562, 182}, { + 0x2563, 185}, { + 0x2564, 209}, { + 0x2565, 210}, { + 0x2566, 203}, { + 0x2567, 207}, { + 0x2568, 208}, { + 0x2569, 202}, { + 0x256A, 216}, { + 0x256B, 215}, { + 0x256C, 206}, { + 0x2580, 223}, { + 0x2584, 220}, { + 0x2588, 219}, { + 0x258C, 221}, { + 0x2590, 222}, { + 0x2591, 176}, { + 0x2592, 177}, { + 0x2593, 178}, { + 0x25A0, 254}, { + 0x25AC, 22}, { + 0x25B2, 30}, { + 0x25BA, 16}, { + 0x25BC, 31}, { + 0x25C4, 17}, { + 0x25CB, 9}, { + 0x25D8, 8}, { + 0x25D9, 10}, { + 0x263A, 1}, { + 0x263B, 2}, { + 0x263C, 15}, { + 0x2640, 12}, { + 0x2642, 11}, { + 0x2660, 6}, { + 0x2663, 5}, { + 0x2665, 3}, { + 0x2666, 4}, { + 0x266A, 13}, { + 0x266B, 14} }; - int l=0, r=160; - while (l!=r) { - int m = (l+r)/2; - if (xref[m].ucs4==ucs4_character) { + int l = 0, r = 160; + + while (l != r) { + int m = (l + r) / 2; + + if (xref[m].ucs4 == ucs4_character) { *cp_character = (char)xref[m].cp437; break; - } - else if (xref[m].ucs4=0xA0) { + if (ucs4_character <= 0x7F || ucs4_character >= 0xA0) { *cp_character = (char)ucs4_character; } else { - struct { ucs4_t ucs4; unsigned char cp; } xref[] = { - {0x20ac, 0x80}, {0x0081, 0x81}, {0x201a, 0x82}, {0x0192, 0x83}, - {0x201e, 0x84}, {0x2026, 0x85}, {0x2020, 0x86}, {0x2021, 0x87}, - {0x02c6, 0x88}, {0x2030, 0x89}, {0x0160, 0x8a}, {0x2039, 0x8b}, - {0x0152, 0x8c}, {0x008d, 0x8d}, {0x017d, 0x8e}, {0x008f, 0x8f}, - {0x0090, 0x90}, {0x2018, 0x91}, {0x2019, 0x92}, {0x201c, 0x93}, - {0x201d, 0x94}, {0x2022, 0x95}, {0x2013, 0x96}, {0x2014, 0x97}, - {0x02dc, 0x98}, {0x2122, 0x99}, {0x0161, 0x9a}, {0x203a, 0x9b}, - {0x0153, 0x9c}, {0x009d, 0x9d}, {0x017e, 0x9e}, {0x0178, 0x9f} + struct { + ucs4_t ucs4; + unsigned char cp; + } xref[] = { + { + 0x20ac, 0x80}, { + 0x0081, 0x81}, { + 0x201a, 0x82}, { + 0x0192, 0x83}, { + 0x201e, 0x84}, { + 0x2026, 0x85}, { + 0x2020, 0x86}, { + 0x2021, 0x87}, { + 0x02c6, 0x88}, { + 0x2030, 0x89}, { + 0x0160, 0x8a}, { + 0x2039, 0x8b}, { + 0x0152, 0x8c}, { + 0x008d, 0x8d}, { + 0x017d, 0x8e}, { + 0x008f, 0x8f}, { + 0x0090, 0x90}, { + 0x2018, 0x91}, { + 0x2019, 0x92}, { + 0x201c, 0x93}, { + 0x201d, 0x94}, { + 0x2022, 0x95}, { + 0x2013, 0x96}, { + 0x2014, 0x97}, { + 0x02dc, 0x98}, { + 0x2122, 0x99}, { + 0x0161, 0x9a}, { + 0x203a, 0x9b}, { + 0x0153, 0x9c}, { + 0x009d, 0x9d}, { + 0x017e, 0x9e}, { + 0x0178, 0x9f} }; - int l=0, r=sizeof(xref)/sizeof(xref[0]); - while (l!=r) { - int m = (l+r)/2; - if (xref[m].ucs4==ucs4_character) { + int l = 0, r = sizeof(xref) / sizeof(xref[0]); + + while (l != r) { + int m = (l + r) / 2; + + if (xref[m].ucs4 == ucs4_character) { *cp_character = (char)xref[m].cp; break; - } - else if (xref[m].ucs4 #include -const xmlChar * -xml_i(double number) +const xmlChar *xml_i(double number) { static char buffer[128]; + snprintf(buffer, sizeof(buffer), "%.0lf", number); return (const xmlChar *)buffer; } -int -xml_ivalue(xmlNodePtr node, const char * name, int dflt) +int xml_ivalue(xmlNodePtr node, const char *name, int dflt) { int i = dflt; - xmlChar * propValue = xmlGetProp(node, BAD_CAST name); - if (propValue!=NULL) { - i = atoi((const char*)propValue); + + xmlChar *propValue = xmlGetProp(node, BAD_CAST name); + + if (propValue != NULL) { + i = atoi((const char *)propValue); xmlFree(propValue); } return i; } -boolean -xml_bvalue(xmlNodePtr node, const char * name, boolean dflt) +boolean xml_bvalue(xmlNodePtr node, const char *name, boolean dflt) { boolean result = dflt; - xmlChar * propValue = xmlGetProp(node, BAD_CAST name); - if (propValue!=NULL) { - if (strcmp((const char*)propValue, "no")==0) result = false; - else if (strcmp((const char*)propValue, "yes")==0) result = true; - else if (strcmp((const char*)propValue, "false")==0) result = false; - else if (strcmp((const char*)propValue, "true")==0) result = true; - else if (strcmp((const char*)propValue, "1")==0) { + + xmlChar *propValue = xmlGetProp(node, BAD_CAST name); + + if (propValue != NULL) { + if (strcmp((const char *)propValue, "no") == 0) + result = false; + else if (strcmp((const char *)propValue, "yes") == 0) + result = true; + else if (strcmp((const char *)propValue, "false") == 0) + result = false; + else if (strcmp((const char *)propValue, "true") == 0) + result = true; + else if (strcmp((const char *)propValue, "1") == 0) { log_warning(("boolean value is '1': %s::%s\n", node->name, name)); result = true; - } - else if (strcmp((const char*)propValue, "0")==0) { + } else if (strcmp((const char *)propValue, "0") == 0) { log_warning(("boolean value is '0': %s::%s\n", node->name, name)); result = false; } @@ -68,13 +73,14 @@ xml_bvalue(xmlNodePtr node, const char * name, boolean dflt) return result; } -double -xml_fvalue(xmlNodePtr node, const char * name, double dflt) +double xml_fvalue(xmlNodePtr node, const char *name, double dflt) { double result = dflt; - xmlChar * propValue = xmlGetProp(node, BAD_CAST name); - if (propValue!=NULL) { - result = atof((const char*)propValue); + + xmlChar *propValue = xmlGetProp(node, BAD_CAST name); + + if (propValue != NULL) { + result = atof((const char *)propValue); xmlFree(propValue); } return result; @@ -87,28 +93,30 @@ xml_fvalue(xmlNodePtr node, const char * name, double dflt) #include typedef struct xml_reader { - struct xml_reader * next; + struct xml_reader *next; xml_callback callback; } xml_reader; -static xml_reader * xmlReaders; +static xml_reader *xmlReaders; -void -xml_register_callback(xml_callback callback) +void xml_register_callback(xml_callback callback) { - xml_reader * reader = (xml_reader *)malloc(sizeof(xml_reader)); - xml_reader ** insert = &xmlReaders; + xml_reader *reader = (xml_reader *) malloc(sizeof(xml_reader)); + + xml_reader **insert = &xmlReaders; + reader->callback = callback; reader->next = NULL; - while (*insert) insert = &(*insert)->next; + while (*insert) + insert = &(*insert)->next; *insert = reader; } -int -read_xml(const char * filename, const char * catalog) +int read_xml(const char *filename, const char *catalog) { - xml_reader * reader = xmlReaders; + xml_reader *reader = xmlReaders; + xmlDocPtr doc; if (catalog) { @@ -119,16 +127,17 @@ read_xml(const char * filename, const char * catalog) #else doc = xmlParseFile(filename); #endif - if (doc==NULL) { + if (doc == NULL) { log_error(("could not open %s\n", filename)); return -1; } xmlXIncludeProcess(doc); - while (reader!=NULL) { + while (reader != NULL) { int i = reader->callback(doc); - if (i!=0) { + + if (i != 0) { return i; } reader = reader->next; @@ -136,4 +145,3 @@ read_xml(const char * filename, const char * catalog) xmlFreeDoc(doc); return 0; } - diff --git a/src/util/xml.h b/src/util/xml.h index 540b886e9..6c4366990 100644 --- a/src/util/xml.h +++ b/src/util/xml.h @@ -17,18 +17,18 @@ #ifdef __cplusplus extern "C" { #endif - + /* new xml functions: */ #include - typedef int (*xml_callback)(xmlDocPtr); + typedef int (*xml_callback) (xmlDocPtr); extern void xml_register_callback(xml_callback callback); - extern int read_xml(const char * filename, const char * catalog); - extern double xml_fvalue(xmlNodePtr node, const char * name, double dflt); - extern int xml_ivalue(xmlNodePtr node, const char * name, int dflt); - extern boolean xml_bvalue(xmlNodePtr node, const char * name, boolean dflt); + extern int read_xml(const char *filename, const char *catalog); + extern double xml_fvalue(xmlNodePtr node, const char *name, double dflt); + extern int xml_ivalue(xmlNodePtr node, const char *name, int dflt); + extern boolean xml_bvalue(xmlNodePtr node, const char *name, boolean dflt); - const xmlChar * xml_i(double number); + const xmlChar *xml_i(double number); #ifdef __cplusplus } diff --git a/tools/atoi36.c b/tools/atoi36.c index a935e7650..c98fe20e5 100644 --- a/tools/atoi36.c +++ b/tools/atoi36.c @@ -15,21 +15,23 @@ #include #include -int main(int argc, char**argv) +int main(int argc, char **argv) { - int i=1, reverse = 0; - if (strstr(argv[0], "itoa36")) reverse=1; - if (argc>1) { - if (strcmp(argv[1], "-r")==0) { - i=2; - reverse=1; + int i = 1, reverse = 0; + + if (strstr(argv[0], "itoa36")) + reverse = 1; + if (argc > 1) { + if (strcmp(argv[1], "-r") == 0) { + i = 2; + reverse = 1; } } - for (;i!=argc;++i) { + for (; i != argc; ++i) { if (reverse) { printf("%s -> %s\n", argv[i], itoa36(atoi(argv[i]))); - } - else printf("%s -> %d\n", argv[i], atoi36(argv[i])); + } else + printf("%s -> %d\n", argv[i], atoi36(argv[i])); } return 0; } diff --git a/tools/gethash.c b/tools/gethash.c index 65fc1ef76..59de29005 100644 --- a/tools/gethash.c +++ b/tools/gethash.c @@ -2,21 +2,28 @@ #include #include -int main(int argc, char ** argv) +int main(int argc, char **argv) { char key[4]; + char code[4]; + char result[4]; + int a, i, rot; - for (a=1;a #include -static char *dwarf_syllable1[] = -{ - "B", "D", "F", "G", "Gl", "H", "K", "L", "M", "N", "R", "S", "T", "Th", "V", +static char *dwarf_syllable1[] = { + "B", "D", "F", "G", "Gl", "H", "K", "L", "M", "N", "R", "S", "T", "Th", "V", }; -static char *dwarf_syllable2[] = -{ - "a", "e", "i", "o", "oi", "u", +static char *dwarf_syllable2[] = { + "a", "e", "i", "o", "oi", "u", }; -static char *dwarf_syllable3[] = -{ - "bur", "fur", "gan", "gnus", "gnar", "li", "lin", "lir", "mli", "nar", "nus", "rin", "ran", "sin", "sil", "sur", +static char *dwarf_syllable3[] = { + "bur", "fur", "gan", "gnus", "gnar", "li", "lin", "lir", "mli", "nar", "nus", + "rin", "ran", "sin", "sil", "sur", }; -static char *elf_syllable1[] = -{ - "Al", "An", "Bal", "Bel", "Cal", "Cel", "El", "Elr", "Elv", "Eow", "Ear", "F", "Fal", "Fel", "Fin", "G", "Gal", "Gel", "Gl", "Is", "Lan", "Leg", "Lom", "N", "Nal", "Nel", "S", "Sal", "Sel", "T", "Tal", "Tel", "Thr", "Tin", +static char *elf_syllable1[] = { + "Al", "An", "Bal", "Bel", "Cal", "Cel", "El", "Elr", "Elv", "Eow", "Ear", "F", + "Fal", "Fel", "Fin", "G", "Gal", "Gel", "Gl", "Is", "Lan", "Leg", "Lom", + "N", "Nal", "Nel", "S", "Sal", "Sel", "T", "Tal", "Tel", "Thr", "Tin", }; -static char *elf_syllable2[] = -{ - "a", "adrie", "ara", "e", "ebri", "ele", "ere", "i", "io", "ithra", "ilma", "il-Ga", "ili", "o", "orfi", "u", "y", +static char *elf_syllable2[] = { + "a", "adrie", "ara", "e", "ebri", "ele", "ere", "i", "io", "ithra", "ilma", + "il-Ga", "ili", "o", "orfi", "u", "y", }; -static char *elf_syllable3[] = -{ - "l", "las", "lad", "ldor", "ldur", "linde", "lith", "mir", "n", "nd", "ndel", "ndil", "ndir", "nduil", "ng", "mbor", "r", "rith", "ril", "riand", "rion", "s", "thien", "viel", "wen", "wyn", +static char *elf_syllable3[] = { + "l", "las", "lad", "ldor", "ldur", "linde", "lith", "mir", "n", "nd", "ndel", + "ndil", "ndir", "nduil", "ng", "mbor", "r", "rith", "ril", "riand", "rion", + "s", "thien", "viel", "wen", "wyn", }; -static char *gnome_syllable1[] = -{ - "Aar", "An", "Ar", "As", "C", "H", "Han", "Har", "Hel", "Iir", "J", "Jan", "Jar", "K", "L", "M", "Mar", "N", "Nik", "Os", "Ol", "P", "R", "S", "Sam", "San", "T", "Ter", "Tom", "Ul", "V", "W", "Y", +static char *gnome_syllable1[] = { + "Aar", "An", "Ar", "As", "C", "H", "Han", "Har", "Hel", "Iir", "J", "Jan", + "Jar", "K", "L", "M", "Mar", "N", "Nik", "Os", "Ol", "P", "R", "S", "Sam", + "San", "T", "Ter", "Tom", "Ul", "V", "W", "Y", }; -static char *gnome_syllable2[] = -{ - "a", "aa", "ai", "e", "ei", "i", "o", "uo", "u", "uu", +static char *gnome_syllable2[] = { + "a", "aa", "ai", "e", "ei", "i", "o", "uo", "u", "uu", }; -static char *gnome_syllable3[] = -{ - "ron", "re", "la", "ki", "kseli", "ksi", "ku", "ja", "ta", "na", "namari", "neli", "nika", "nikki", "nu", "nukka", "ka", "ko", "li", "kki", "rik", "po", "to", "pekka", "rjaana", "rjatta", "rjukka", "la", "lla", "lli", "mo", "nni", +static char *gnome_syllable3[] = { + "ron", "re", "la", "ki", "kseli", "ksi", "ku", "ja", "ta", "na", "namari", + "neli", "nika", "nikki", "nu", "nukka", "ka", "ko", "li", "kki", "rik", + "po", "to", "pekka", "rjaana", "rjatta", "rjukka", "la", "lla", "lli", "mo", + "nni", }; -static char *hobbit_syllable1[] = -{ - "B", "Ber", "Br", "D", "Der", "Dr", "F", "Fr", "G", "H", "L", "Ler", "M", "Mer", "N", "P", "Pr", "Per", "R", "S", "T", "W", +static char *hobbit_syllable1[] = { + "B", "Ber", "Br", "D", "Der", "Dr", "F", "Fr", "G", "H", "L", "Ler", "M", + "Mer", "N", "P", "Pr", "Per", "R", "S", "T", "W", }; -static char *hobbit_syllable2[] = -{ - "a", "e", "i", "ia", "o", "oi", "u", +static char *hobbit_syllable2[] = { + "a", "e", "i", "ia", "o", "oi", "u", }; -static char *hobbit_syllable3[] = -{ - "bo", "ck", "decan", "degar", "do", "doc", "go", "grin", "lba", "lbo", "lda", "ldo", "lla", "ll", "lo", "m", "mwise", "nac", "noc", "nwise", "p", "ppin", "pper", "tho", "to", +static char *hobbit_syllable3[] = { + "bo", "ck", "decan", "degar", "do", "doc", "go", "grin", "lba", "lbo", "lda", + "ldo", "lla", "ll", "lo", "m", "mwise", "nac", "noc", "nwise", "p", "ppin", + "pper", "tho", "to", }; -static char *human_syllable1[] = -{ - "Ab", "Ac", "Ad", "Af", "Agr", "Ast", "As", "Al", "Adw", "Adr", "Ar", "B", "Br", "C", "Cr", "Ch", "Cad", "D", "Dr", "Dw", "Ed", "Eth", "Et", "Er", "El", "Eow", "F", "Fr", "G", "Gr", "Gw", "Gal", "Gl", "H", "Ha", "Ib", "Jer", "K", "Ka", "Ked", "L", "Loth", "Lar", "Leg", "M", "Mir", "N", "Nyd", "Ol", "Oc", "On", "P", "Pr", "R", "Rh", "S", "Sev", "T", "Tr", "Th", "V", "Y", "Z", "W", "Wic", +static char *human_syllable1[] = { + "Ab", "Ac", "Ad", "Af", "Agr", "Ast", "As", "Al", "Adw", "Adr", "Ar", "B", + "Br", "C", "Cr", "Ch", "Cad", "D", "Dr", "Dw", "Ed", "Eth", "Et", "Er", + "El", "Eow", "F", "Fr", "G", "Gr", "Gw", "Gal", "Gl", "H", "Ha", "Ib", + "Jer", "K", "Ka", "Ked", "L", "Loth", "Lar", "Leg", "M", "Mir", "N", "Nyd", + "Ol", "Oc", "On", "P", "Pr", "R", "Rh", "S", "Sev", "T", "Tr", "Th", "V", + "Y", "Z", "W", "Wic", }; -static char *human_syllable2[] = -{ - "a", "ae", "au", "ao", "are", "ale", "ali", "ay", "ardo", "e", "ei", "ea", "eri", "era", "ela", "eli", "enda", "erra", "i", "ia", "ie", "ire", "ira", "ila", "ili", "ira", "igo", "o", "oa", "oi", "oe", "ore", "u", "y", +static char *human_syllable2[] = { + "a", "ae", "au", "ao", "are", "ale", "ali", "ay", "ardo", "e", "ei", "ea", + "eri", "era", "ela", "eli", "enda", "erra", "i", "ia", "ie", "ire", "ira", + "ila", "ili", "ira", "igo", "o", "oa", "oi", "oe", "ore", "u", "y", }; -static char *human_syllable3[] = -{ - "a", "and", "b", "bwyn", "baen", "bard", "c", "ctred", "cred", "ch", "can", "d", "dan", "don", "der", "dric", "dfrid", "dus", "f", "g", "gord", "gan", "l", "li", "lgrin", "lin", "lith", "lath", "loth", "ld", "ldric", "ldan", "m", "mas", "mos", "mar", "mond", "n", "nydd", "nidd", "nnon", "nwan", "nyth", "nad", "nn", "nnor", "nd", "p", "r", "ron", "rd", "s", "sh", "seth", "sean", "t", "th", "tha", "tlan", "trem", "tram", "v", "vudd", "w", "wan", "win", "wyn", "wyr", "wyr", "wyth", +static char *human_syllable3[] = { + "a", "and", "b", "bwyn", "baen", "bard", "c", "ctred", "cred", "ch", "can", + "d", "dan", "don", "der", "dric", "dfrid", "dus", "f", "g", "gord", "gan", + "l", "li", "lgrin", "lin", "lith", "lath", "loth", "ld", "ldric", "ldan", + "m", "mas", "mos", "mar", "mond", "n", "nydd", "nidd", "nnon", "nwan", + "nyth", "nad", "nn", "nnor", "nd", "p", "r", "ron", "rd", "s", "sh", "seth", + "sean", "t", "th", "tha", "tlan", "trem", "tram", "v", "vudd", "w", "wan", + "win", "wyn", "wyr", "wyr", "wyth", }; -static char *orc_syllable1[] = -{ - "B", "Er", "G", "Gr", "H", "P", "Pr", "R", "V", "Vr", "T", "Tr", "M", "Dr", +static char *orc_syllable1[] = { + "B", "Er", "G", "Gr", "H", "P", "Pr", "R", "V", "Vr", "T", "Tr", "M", "Dr", }; -static char *orc_syllable2[] = -{ - "a", "i", "o", "oo", "u", "ui", +static char *orc_syllable2[] = { + "a", "i", "o", "oo", "u", "ui", }; -static char *orc_syllable3[] = -{ - "dash", "dish", "dush", "gar", "gor", "gdush", "lo", "gdish", "k", "lg", "nak", "rag", "rbag", "rg", "rk", "ng", "nk", "rt", "ol", "urk", "shnak", "mog", "mak", "rak", +static char *orc_syllable3[] = { + "dash", "dish", "dush", "gar", "gor", "gdush", "lo", "gdish", "k", "lg", + "nak", "rag", "rbag", "rg", "rk", "ng", "nk", "rt", "ol", "urk", "shnak", + "mog", "mak", "rak", }; -static char *entish_syllable1[] = -{ - "Baum","Wurzel","Rinden","Ast","Blatt", +static char *entish_syllable1[] = { + "Baum", "Wurzel", "Rinden", "Ast", "Blatt", }; -static char *entish_syllable2[] = -{ - "-", +static char *entish_syllable2[] = { + "-", }; -static char *entish_syllable3[] = -{ - "Hüter","Pflanzer","Hirte","Wächter","Wachser","Beschützer", +static char *entish_syllable3[] = { + "Hüter", "Pflanzer", "Hirte", "Wächter", "Wachser", "Beschützer", }; -static char *cthuloid_syllable1[] = -{ - "Cth","Az","Fth","Ts","Xo","Q'N","R'L","Ghata","L","Zz","Fl","Cl","S","Y", +static char *cthuloid_syllable1[] = { + "Cth", "Az", "Fth", "Ts", "Xo", "Q'N", "R'L", "Ghata", "L", "Zz", "Fl", "Cl", + "S", "Y", }; -static char *cthuloid_syllable2[] = -{ - "nar","loi","ul","lu","noth","thon","ath","'N","rhy","oth","aza","agn","oa","og", +static char *cthuloid_syllable2[] = { + "nar", "loi", "ul", "lu", "noth", "thon", "ath", "'N", "rhy", "oth", "aza", + "agn", "oa", "og", }; -static char *cthuloid_syllable3[] = -{ - "l","a","u","oa","oggua","oth","ath","aggua","lu","lo","loth","lotha","agn","axl", +static char *cthuloid_syllable3[] = { + "l", "a", "u", "oa", "oggua", "oth", "ath", "aggua", "lu", "lo", "loth", + "lotha", "agn", "axl", }; -static char * -create_random_name(race_t race) +static char *create_random_name(race_t race) { - static char name[64]; + static char name[64]; - switch (race) - { - case RC_DWARF: - strcpy(name, dwarf_syllable1[rng_int()%(sizeof(dwarf_syllable1) / sizeof(char*))]); - strcat(name, dwarf_syllable2[rand()%(sizeof(dwarf_syllable2) / sizeof(char*))]); - strcat(name, dwarf_syllable3[rand()%(sizeof(dwarf_syllable3) / sizeof(char*))]); - break; - case RC_ELF: - strcpy(name, elf_syllable1[rand()%(sizeof(elf_syllable1) / sizeof(char*))]); - strcat(name, elf_syllable2[rand()%(sizeof(elf_syllable2) / sizeof(char*))]); - strcat(name, elf_syllable3[rand()%(sizeof(elf_syllable3) / sizeof(char*))]); - break; + switch (race) { + case RC_DWARF: + strcpy(name, + dwarf_syllable1[rng_int() % (sizeof(dwarf_syllable1) / + sizeof(char *))]); + strcat(name, + dwarf_syllable2[rand() % (sizeof(dwarf_syllable2) / sizeof(char *))]); + strcat(name, + dwarf_syllable3[rand() % (sizeof(dwarf_syllable3) / sizeof(char *))]); + break; + case RC_ELF: + strcpy(name, + elf_syllable1[rand() % (sizeof(elf_syllable1) / sizeof(char *))]); + strcat(name, + elf_syllable2[rand() % (sizeof(elf_syllable2) / sizeof(char *))]); + strcat(name, + elf_syllable3[rand() % (sizeof(elf_syllable3) / sizeof(char *))]); + break; /* case RACE_GNOME: strcpy(name, gnome_syllable1[rand()%(sizeof(gnome_syllable1) / sizeof(char*))]); @@ -159,25 +172,34 @@ create_random_name(race_t race) strcat(name, gnome_syllable3[rand()%(sizeof(gnome_syllable3) / sizeof(char*))]); break; */ - case RC_HALFLING: - strcpy(name, hobbit_syllable1[rand()%(sizeof(hobbit_syllable1) / sizeof(char*))]); - strcat(name, hobbit_syllable2[rand()%(sizeof(hobbit_syllable2) / sizeof(char*))]); - strcat(name, hobbit_syllable3[rand()%(sizeof(hobbit_syllable3) / sizeof(char*))]); - break; - case RC_HUMAN: - case RC_AQUARIAN: - case RC_CAT: - strcpy(name, human_syllable1[rand()%(sizeof(human_syllable1) / sizeof(char*))]); - strcat(name, human_syllable2[rand()%(sizeof(human_syllable2) / sizeof(char*))]); - strcat(name, human_syllable3[rand()%(sizeof(human_syllable3) / sizeof(char*))]); - break; - case RC_ORC: - case RC_TROLL: - case RC_GOBLIN: - strcpy(name, orc_syllable1[rand()%(sizeof(orc_syllable1) / sizeof(char*))]); - strcat(name, orc_syllable2[rand()%(sizeof(orc_syllable2) / sizeof(char*))]); - strcat(name, orc_syllable3[rand()%(sizeof(orc_syllable3) / sizeof(char*))]); - break; + case RC_HALFLING: + strcpy(name, + hobbit_syllable1[rand() % (sizeof(hobbit_syllable1) / sizeof(char *))]); + strcat(name, + hobbit_syllable2[rand() % (sizeof(hobbit_syllable2) / sizeof(char *))]); + strcat(name, + hobbit_syllable3[rand() % (sizeof(hobbit_syllable3) / sizeof(char *))]); + break; + case RC_HUMAN: + case RC_AQUARIAN: + case RC_CAT: + strcpy(name, + human_syllable1[rand() % (sizeof(human_syllable1) / sizeof(char *))]); + strcat(name, + human_syllable2[rand() % (sizeof(human_syllable2) / sizeof(char *))]); + strcat(name, + human_syllable3[rand() % (sizeof(human_syllable3) / sizeof(char *))]); + break; + case RC_ORC: + case RC_TROLL: + case RC_GOBLIN: + strcpy(name, + orc_syllable1[rand() % (sizeof(orc_syllable1) / sizeof(char *))]); + strcat(name, + orc_syllable2[rand() % (sizeof(orc_syllable2) / sizeof(char *))]); + strcat(name, + orc_syllable3[rand() % (sizeof(orc_syllable3) / sizeof(char *))]); + break; /* case RC_TREEMAN: strcpy(name, entish_syllable1[rand()%(sizeof(entish_syllable1) / sizeof(char*))]); @@ -185,29 +207,35 @@ create_random_name(race_t race) strcat(name, entish_syllable3[rand()%(sizeof(entish_syllable3) / sizeof(char*))]); break; */ - case RC_DAEMON: - case RC_INSECT: - strcpy(name, cthuloid_syllable1[rand()%(sizeof(cthuloid_syllable1) / sizeof(char*))]); - strcat(name, cthuloid_syllable2[rand()%(sizeof(cthuloid_syllable2) / sizeof(char*))]); - strcat(name, cthuloid_syllable3[rand()%(sizeof(cthuloid_syllable3) / sizeof(char*))]); - break; - default: - name[0] = 0; - break; - } + case RC_DAEMON: + case RC_INSECT: + strcpy(name, + cthuloid_syllable1[rand() % (sizeof(cthuloid_syllable1) / + sizeof(char *))]); + strcat(name, + cthuloid_syllable2[rand() % (sizeof(cthuloid_syllable2) / + sizeof(char *))]); + strcat(name, + cthuloid_syllable3[rand() % (sizeof(cthuloid_syllable3) / + sizeof(char *))]); + break; + default: + name[0] = 0; + break; + } - return name; + return name; } -int -main(void) +int main(void) { race_t race; - for(race=0; race<11; race++) { + for (race = 0; race < 11; race++) { int i; + printf("%d:", (int)race); - for(i=0;i<20;i++) { + for (i = 0; i < 20; i++) { printf(" %s", create_random_name(race)); } printf("\n"); @@ -215,4 +243,3 @@ main(void) return 0; } - From 9f539b8c12a30f350e6b243d3df3bb8f8528bc91 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 6 Mar 2011 23:07:04 -0800 Subject: [PATCH 108/400] CRLF confusion? --- src/bindings/bindings.c | 73 +++++++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index dd30566e3..881e55273 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -967,35 +967,60 @@ static int config_get_resource(lua_State * L) if (itype) { lua_newtable(L); lua_pushstring(L, "weight"); - lua_pushinteger(L, itype->weight); - lua_settable(L, -3); - if (itype->capacity > 0) { + +lua_pushinteger(L, itype->weight); + +lua_settable(L, -3); + +if (itype->capacity > 0) { lua_pushstring(L, "capacity"); - lua_pushinteger(L, itype->capacity); - lua_settable(L, -3); - } - if (itype->construction) { + +lua_pushinteger(L, itype->capacity); + +lua_settable(L, -3); + +} + +if (itype->construction) { int i; lua_pushstring(L, "build_skill_min"); - lua_pushinteger(L, itype->construction->minskill); - lua_settable(L, -3); - lua_pushstring(L, "build_skill_name"); - lua_pushstring(L, skillnames[itype->construction->skill]); - lua_settable(L, -3); - if (itype->construction->materials) { - lua_pushstring(L, "materials"); - lua_newtable(L); - for (i = 0; itype->construction->materials[i].number; ++i) { - lua_pushstring(L, + +lua_pushinteger(L, itype->construction->minskill); + +lua_settable(L, -3); + +lua_pushstring(L, "build_skill_name"); + +lua_pushstring(L, skillnames[itype->construction->skill]); + +lua_settable(L, -3); + + +if (itype->construction->materials) { + +lua_pushstring(L, "materials"); + +lua_newtable(L); + +for (i = 0; itype->construction->materials[i].number; ++i) { + +lua_pushstring(L, itype->construction->materials[i].rtype->_name[0]); - lua_pushinteger(L, itype->construction->materials[i].number); - lua_settable(L, -3); - } - lua_settable(L, -3); - } - } - return 1; + +lua_pushinteger(L, itype->construction->materials[i].number); + +lua_settable(L, -3); + +} + +lua_settable(L, -3); + +} + +} + +return 1; } } return 0; From 9c8779b303823d327d8f77176fa927a593f13bec Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 7 Mar 2011 08:24:52 +0100 Subject: [PATCH 109/400] indentation rules, slightly updated --- src/attributes/fleechance.c | 1 - src/attributes/follow.c | 1 - src/attributes/giveitem.c | 11 - src/attributes/gm.c | 4 - src/attributes/hate.c | 1 - src/attributes/iceberg.c | 1 - src/attributes/key.c | 3 - src/attributes/matmod.c | 1 - src/attributes/moved.c | 1 - src/attributes/movement.c | 2 - src/attributes/object.c | 9 - src/attributes/orcification.c | 1 - src/attributes/otherfaction.c | 6 - src/attributes/otherfaction.h | 2 +- src/attributes/racename.c | 2 - src/attributes/raceprefix.c | 2 - src/attributes/reduceproduction.c | 2 - src/attributes/targetregion.c | 1 - src/attributes/viewrange.c | 4 - src/bindings/bind_attrib.c | 55 - src/bindings/bind_building.c | 32 - src/bindings/bind_faction.c | 72 - src/bindings/bind_gmtool.c | 29 - src/bindings/bind_hashtable.c | 20 - src/bindings/bind_message.c | 39 - src/bindings/bind_region.c | 97 -- src/bindings/bind_ship.c | 21 - src/bindings/bind_sqlite.c | 9 - src/bindings/bind_storage.c | 20 - src/bindings/bind_unit.c | 141 -- src/bindings/bindings.c | 2167 +++++++++++++---------------- src/bindings/helpers.c | 74 - src/eressea.c | 5 - src/gamecode/archetype.c | 18 - src/gamecode/creport.c | 193 --- src/gamecode/economy.c | 285 ---- src/gamecode/give.c | 20 - src/gamecode/items.c | 15 - src/gamecode/laws.c | 311 ----- src/gamecode/laws_test.c | 27 - src/gamecode/market.c | 30 - src/gamecode/market_test.c | 13 - src/gamecode/monster.c | 4 - src/gamecode/randenc.c | 104 -- src/gamecode/report.c | 198 --- src/gamecode/spy.c | 39 - src/gamecode/study.c | 61 - src/gamecode/summary.c | 23 - src/gamecode/xmlreport.c | 71 - src/gmtool.c | 113 -- src/items/artrewards.c | 3 - src/items/demonseye.c | 1 - src/items/phoenixcompass.c | 10 - src/items/seed.c | 3 - src/items/seed.h | 1 - src/items/speedsail.c | 2 - src/items/studypotion.c | 3 - src/items/weapons.c | 16 - src/items/xerewards.c | 3 - src/kernel/alchemy.c | 26 - src/kernel/alliance.c | 56 - src/kernel/battle.c | 399 ------ src/kernel/battle.h | 1 - src/kernel/binarystore.c | 15 - src/kernel/build.c | 99 -- src/kernel/building.c | 47 - src/kernel/calendar.c | 11 - src/kernel/calendar.h | 1 - src/kernel/command.c | 7 - src/kernel/config.c | 288 ---- src/kernel/connection.c | 43 - src/kernel/connection.h | 1 - src/kernel/curse.c | 38 - src/kernel/curse.h | 4 - src/kernel/curse_test.c | 3 - src/kernel/equipment.c | 21 - src/kernel/equipment.h | 1 - src/kernel/faction.c | 30 - src/kernel/group.c | 19 - src/kernel/item.c | 80 -- src/kernel/item.h | 1 - src/kernel/magic.c | 196 --- src/kernel/magic.h | 4 - src/kernel/message.c | 18 - src/kernel/move.c | 173 --- src/kernel/names.c | 22 - src/kernel/order.c | 38 - src/kernel/order.h | 1 - src/kernel/pathfinder.c | 20 - src/kernel/plane.c | 15 - src/kernel/player.c | 7 - src/kernel/pool.c | 18 - src/kernel/race.c | 19 - src/kernel/region.c | 118 -- src/kernel/reports.c | 297 ---- src/kernel/reports.h | 1 - src/kernel/resources.c | 13 - src/kernel/save.c | 148 -- src/kernel/ship.c | 18 - src/kernel/skill.c | 14 - src/kernel/spell.c | 18 - src/kernel/sqlite.c | 27 - src/kernel/teleport.c | 19 - src/kernel/terrain.c | 6 - src/kernel/textstore.c | 11 - src/kernel/types.h | 39 - src/kernel/unit.c | 112 +- src/kernel/xmlreader.c | 210 --- src/modules/arena.c | 42 - src/modules/autoseed.c | 157 --- src/modules/autoseed.h | 1 - src/modules/dungeon.c | 30 - src/modules/gmcmd.c | 119 -- src/modules/museum.c | 20 - src/modules/score.c | 18 - src/modules/score.h | 1 - src/modules/weather.c | 5 - src/modules/wormhole.c | 22 - src/modules/xecmd.c | 1 - src/modules/xmas.c | 2 - src/platform.h | 3 - src/tests.c | 18 - src/triggers/changefaction.c | 6 - src/triggers/changerace.c | 5 - src/triggers/clonedied.c | 4 - src/triggers/createcurse.c | 7 - src/triggers/createunit.c | 5 - src/triggers/gate.c | 9 - src/triggers/giveitem.c | 5 - src/triggers/killunit.c | 3 - src/triggers/removecurse.c | 6 - src/triggers/shock.c | 7 - src/triggers/timeout.c | 7 - src/triggers/unguard.c | 1 - src/triggers/unitmessage.c | 7 - src/util/attrib.c | 22 - src/util/base36.c | 9 - src/util/base36_test.c | 1 - src/util/bsdstring.c | 6 - src/util/bsdstring.h | 2 - src/util/console.c | 15 - src/util/crmessage.c | 10 - src/util/dice.c | 3 - src/util/event.c | 19 - src/util/eventbus.c | 4 - src/util/eventbus.h | 1 - src/util/filereader.c | 21 - src/util/functions.c | 5 - src/util/goodies.c | 3 - src/util/graph.c | 19 - src/util/language.c | 17 - src/util/language_struct.h | 1 - src/util/listbox.c | 12 - src/util/lists.c | 3 - src/util/log.c | 21 - src/util/message.c | 17 - src/util/nrmessage.c | 16 - src/util/nrmessage.h | 1 - src/util/parser.c | 18 - src/util/quicklist.c | 15 - src/util/quicklist_test.c | 19 - src/util/rand.c | 5 - src/util/resolve.c | 6 - src/util/sql.c | 7 - src/util/strings.c | 5 - src/util/strncpy.c | 1 - src/util/translation.c | 48 - src/util/umlaut.c | 9 - src/util/unicode.c | 16 - src/util/xml.c | 11 - src/util/xml.h | 1 - tools/atoi36.c | 1 - tools/gethash.c | 6 - tools/namegen.c | 1 - 174 files changed, 965 insertions(+), 7119 deletions(-) diff --git a/src/attributes/fleechance.c b/src/attributes/fleechance.c index 505158dab..a33237c58 100644 --- a/src/attributes/fleechance.c +++ b/src/attributes/fleechance.c @@ -33,7 +33,6 @@ attrib_type at_fleechance = { attrib *make_fleechance(float fleechance) { attrib *a = a_new(&at_fleechance); - a->data.flt = fleechance; return a; } diff --git a/src/attributes/follow.c b/src/attributes/follow.c index 66c7c7eb2..6d5f1b540 100644 --- a/src/attributes/follow.c +++ b/src/attributes/follow.c @@ -39,7 +39,6 @@ attrib_type at_follow = { attrib *make_follow(struct unit * u) { attrib *a = a_new(&at_follow); - a->data.v = u; return a; } diff --git a/src/attributes/giveitem.c b/src/attributes/giveitem.c index b248428d5..b9ceb0f33 100644 --- a/src/attributes/giveitem.c +++ b/src/attributes/giveitem.c @@ -46,9 +46,7 @@ static void a_writegive(const attrib * a, const void *owner, struct storage *store) { give_data *gdata = (give_data *) a->data.v; - item *itm; - write_building_reference(gdata->building, store); for (itm = gdata->items; itm; itm = itm->next) { store->w_tok(store, resourcename(itm->type->rtype, 0)); @@ -60,9 +58,7 @@ a_writegive(const attrib * a, const void *owner, struct storage *store) static int a_readgive(attrib * a, void *owner, struct storage *store) { give_data *gdata = (give_data *) a->data.v; - variant var; - char zText[32]; var.i = store->r_id(store); @@ -76,7 +72,6 @@ static int a_readgive(attrib * a, void *owner, struct storage *store) } for (;;) { int i; - store->r_tok_buf(store, zText, sizeof(zText)); if (!strcmp("end", zText)) break; @@ -100,11 +95,8 @@ static void a_finalizegive(struct attrib *a) static int a_giveitem(attrib * a) { give_data *gdata = (give_data *) a->data.v; - region *r; - unit *u; - if (gdata->building == NULL || gdata->items == NULL) return 0; r = gdata->building->region; @@ -113,7 +105,6 @@ static int a_giveitem(attrib * a) return 1; while (gdata->items) { item *itm = gdata->items; - i_change(&u->items, itm->type, itm->number); i_free(i_remove(&gdata->items, itm)); } @@ -130,9 +121,7 @@ attrib_type at_giveitem = { attrib *make_giveitem(struct building * b, struct item * ip) { attrib *a = a_new(&at_giveitem); - give_data *gd = (give_data *) a->data.v; - gd->building = b; gd->items = ip; return a; diff --git a/src/attributes/gm.c b/src/attributes/gm.c index b320ee477..a507b679c 100644 --- a/src/attributes/gm.c +++ b/src/attributes/gm.c @@ -35,14 +35,11 @@ static void write_gm(const attrib * a, const void *owner, struct storage *store) static int read_gm(attrib * a, void *owner, struct storage *store) { plane *pl; - int result = read_plane_reference(&pl, store); - a->data.v = pl; return result; } - attrib_type at_gm = { "gm", NULL, @@ -55,7 +52,6 @@ attrib_type at_gm = { attrib *make_gm(const struct plane * pl) { attrib *a = a_new(&at_gm); - a->data.v = (void *)pl; return a; } diff --git a/src/attributes/hate.c b/src/attributes/hate.c index e2531e921..c2c9d0536 100644 --- a/src/attributes/hate.c +++ b/src/attributes/hate.c @@ -63,7 +63,6 @@ attrib_type at_hate = { attrib *make_hate(struct unit * u) { attrib *a = a_new(&at_hate); - a->data.v = u; return a; } diff --git a/src/attributes/iceberg.c b/src/attributes/iceberg.c index 5c51f02fb..8a36d1f56 100644 --- a/src/attributes/iceberg.c +++ b/src/attributes/iceberg.c @@ -36,7 +36,6 @@ attrib_type at_iceberg = { attrib *make_iceberg(direction_t dir) { attrib *a = a_new(&at_iceberg); - a->data.i = (int)dir; return a; } diff --git a/src/attributes/key.c b/src/attributes/key.c index 5d3147a45..19a7bcd44 100644 --- a/src/attributes/key.c +++ b/src/attributes/key.c @@ -35,7 +35,6 @@ attrib_type at_key = { attrib *add_key(attrib ** alist, int key) { attrib *a = find_key(*alist, key); - if (a == NULL) a = a_add(alist, make_key(key)); return a; @@ -44,7 +43,6 @@ attrib *add_key(attrib ** alist, int key) attrib *make_key(int key) { attrib *a = a_new(&at_key); - a->data.i = key; return a; } @@ -52,7 +50,6 @@ attrib *make_key(int key) attrib *find_key(attrib * alist, int key) { attrib *a = a_find(alist, &at_key); - while (a && a->type == &at_key && a->data.i != key) { a = a->next; } diff --git a/src/attributes/matmod.c b/src/attributes/matmod.c index 6a520ce43..fe38ac20a 100644 --- a/src/attributes/matmod.c +++ b/src/attributes/matmod.c @@ -34,7 +34,6 @@ attrib_type at_matmod = { attrib *make_matmod(mm_fun function) { attrib *a = a_new(&at_matmod); - a->data.f = (void (*)(void))function; return a; } diff --git a/src/attributes/moved.c b/src/attributes/moved.c index 16d2e0de4..d73b3e541 100644 --- a/src/attributes/moved.c +++ b/src/attributes/moved.c @@ -56,7 +56,6 @@ boolean get_moved(attrib ** alist) void set_moved(attrib ** alist) { attrib *a = a_find(*alist, &at_moved); - if (a == NULL) a = a_add(alist, a_new(&at_moved)); a->data.i = 2; diff --git a/src/attributes/movement.c b/src/attributes/movement.c index f46d839b9..8e2515854 100644 --- a/src/attributes/movement.c +++ b/src/attributes/movement.c @@ -45,7 +45,6 @@ attrib_type at_movement = { boolean get_movement(attrib * const *alist, int type) { const attrib *a = a_findc(*alist, &at_movement); - if (a == NULL) return false; if (a->data.i & type) @@ -56,7 +55,6 @@ boolean get_movement(attrib * const *alist, int type) void set_movement(attrib ** alist, int type) { attrib *a = a_find(*alist, &at_movement); - if (a == NULL) a = a_add(alist, a_new(&at_movement)); a->data.i |= type; diff --git a/src/attributes/object.c b/src/attributes/object.c index ab8de87d5..9322acb6c 100644 --- a/src/attributes/object.c +++ b/src/attributes/object.c @@ -57,9 +57,7 @@ static void object_write(const attrib * a, const void *owner, struct storage *store) { const object_data *data = (object_data *) a->data.v; - int type = (int)data->type; - store->w_tok(store, data->name); store->w_int(store, type); switch (data->type) { @@ -98,7 +96,6 @@ object_write(const attrib * a, const void *owner, struct storage *store) static int object_read(attrib * a, void *owner, struct storage *store) { object_data *data = (object_data *) a->data.v; - int result; data->name = store->r_str(store); @@ -159,7 +156,6 @@ static int object_read(attrib * a, void *owner, struct storage *store) static void object_init(attrib * a) { object_data *data; - a->data.v = malloc(sizeof(object_data)); data = (object_data *) a->data.v; data->type = TNONE; @@ -168,7 +164,6 @@ static void object_init(attrib * a) static void object_done(attrib * a) { object_data *data = (object_data *) a->data.v; - if (data->type == TSTRING) free(data->data.str); free(data->name); @@ -183,16 +178,13 @@ attrib_type at_object = { const char *object_name(const attrib * a) { object_data *data = (object_data *) a->data.v; - return data->name; } struct attrib *object_create(const char *name, object_type type, variant value) { attrib *a = a_new(&at_object); - object_data *data = (object_data *) a->data.v; - data->name = strdup(name); object_set(a, type, value); @@ -242,7 +234,6 @@ void object_set(attrib * a, object_type type, variant value) void object_get(const struct attrib *a, object_type * type, variant * value) { object_data *data = (object_data *) a->data.v; - *type = data->type; switch (data->type) { case TSTRING: diff --git a/src/attributes/orcification.c b/src/attributes/orcification.c index 2cd820dea..5aa6b8717 100644 --- a/src/attributes/orcification.c +++ b/src/attributes/orcification.c @@ -34,7 +34,6 @@ attrib_type at_orcification = { attrib *make_orcification(int orcification) { attrib *a = a_new(&at_orcification); - a->data.i = orcification; return a; } diff --git a/src/attributes/otherfaction.c b/src/attributes/otherfaction.c index 697a203d2..706660c34 100644 --- a/src/attributes/otherfaction.c +++ b/src/attributes/otherfaction.c @@ -30,18 +30,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * simple attributes that do not yet have their own file */ - void write_of(const struct attrib *a, const void *owner, struct storage *store) { const faction *f = (faction *) a->data.v; - store->w_int(store, f->no); } int read_of(struct attrib *a, void *owner, struct storage *store) { /* return 1 on success, 0 if attrib needs removal */ int of = store->r_int(store); - a->data.v = findfaction(of); if (a->data.v) return AT_READ_OK; @@ -60,7 +57,6 @@ struct faction *get_otherfaction(const struct attrib *a) struct attrib *make_otherfaction(struct faction *f) { attrib *a = a_new(&at_otherfaction); - a->data.v = (void *)f; return a; } @@ -69,10 +65,8 @@ faction *visible_faction(const faction * f, const unit * u) { if (f == NULL || !alliedunit(u, f, HELP_FSTEALTH)) { attrib *a = a_find(u->attribs, &at_otherfaction); - if (a) { faction *fv = get_otherfaction(a); - assert(fv != NULL); /* fv should never be NULL! */ return fv; } diff --git a/src/attributes/otherfaction.h b/src/attributes/otherfaction.h index 4bb2608d0..783f5fb07 100644 --- a/src/attributes/otherfaction.h +++ b/src/attributes/otherfaction.h @@ -30,5 +30,5 @@ extern "C" { const struct unit *u); #ifdef __cplusplus -} + extern "C" { #endif diff --git a/src/attributes/racename.c b/src/attributes/racename.c index 7bc19f259..e53da10ec 100644 --- a/src/attributes/racename.c +++ b/src/attributes/racename.c @@ -34,7 +34,6 @@ attrib_type at_racename = { const char *get_racename(attrib * alist) { attrib *a = a_find(alist, &at_racename); - if (a) return (const char *)a->data.v; return NULL; @@ -43,7 +42,6 @@ const char *get_racename(attrib * alist) void set_racename(attrib ** palist, const char *name) { attrib *a = a_find(*palist, &at_racename); - if (!a && name) { a = a_add(palist, a_new(&at_racename)); a->data.v = strdup(name); diff --git a/src/attributes/raceprefix.c b/src/attributes/raceprefix.c index 4163c8523..550cc54b6 100644 --- a/src/attributes/raceprefix.c +++ b/src/attributes/raceprefix.c @@ -34,7 +34,6 @@ attrib_type at_raceprefix = { void set_prefix(attrib ** ap, const char *str) { attrib *a = a_find(*ap, &at_raceprefix); - if (a == NULL) { a = a_add(ap, a_new(&at_raceprefix)); } else { @@ -47,7 +46,6 @@ void set_prefix(attrib ** ap, const char *str) const char *get_prefix(const attrib * a) { char *str; - a = a_findc(a, &at_raceprefix); if (a == NULL) return NULL; diff --git a/src/attributes/reduceproduction.c b/src/attributes/reduceproduction.c index d69633b16..ba7f905bb 100644 --- a/src/attributes/reduceproduction.c +++ b/src/attributes/reduceproduction.c @@ -25,7 +25,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. static int age_reduceproduction(attrib * a) { int reduce = 100 - (5 * --a->data.sa[1]); - if (reduce < 10) reduce = 10; a->data.sa[0] = (short)reduce; @@ -45,7 +44,6 @@ attrib_type at_reduceproduction = { attrib *make_reduceproduction(int percent, int time) { attrib *a = a_new(&at_reduceproduction); - a->data.sa[0] = (short)percent; a->data.sa[1] = (short)time; return a; diff --git a/src/attributes/targetregion.c b/src/attributes/targetregion.c index 275705d01..4900016f1 100644 --- a/src/attributes/targetregion.c +++ b/src/attributes/targetregion.c @@ -57,7 +57,6 @@ attrib_type at_targetregion = { attrib *make_targetregion(struct region * r) { attrib *a = a_new(&at_targetregion); - a->data.v = r; return a; } diff --git a/src/attributes/viewrange.c b/src/attributes/viewrange.c index c2f31d047..be21c0877 100644 --- a/src/attributes/viewrange.c +++ b/src/attributes/viewrange.c @@ -32,7 +32,6 @@ a_writefunction(const struct attrib *a, const void *owner, struct storage *store) { const char *str = get_functionname((pf_generic) a->data.f); - store->w_tok(store, str); } @@ -40,7 +39,6 @@ static int a_readfunction(struct attrib *a, void *owner, struct storage *store) /* return 1 on success, 0 if attrib needs removal */ { char buf[64]; - store->r_tok_buf(store, buf, sizeof(buf)); a->data.f = get_function(buf); return AT_READ_OK; @@ -58,7 +56,6 @@ attrib_type at_viewrange = { attrib *add_viewrange(attrib ** alist, const char *function) { attrib *a = a_find(*alist, &at_viewrange); - if (a == NULL) a = a_add(alist, make_viewrange(function)); return a; @@ -67,7 +64,6 @@ attrib *add_viewrange(attrib ** alist, const char *function) attrib *make_viewrange(const char *function) { attrib *a = a_new(&at_viewrange); - a->data.f = get_function(function); assert(a->data.f); return a; diff --git a/src/bindings/bind_attrib.c b/src/bindings/bind_attrib.c index 65295af79..cdb2f0c6b 100644 --- a/src/bindings/bind_attrib.c +++ b/src/bindings/bind_attrib.c @@ -44,7 +44,6 @@ static void init_ext(attrib * a) lua_rawgeti(L, LUA_REGISTRYINDEX, a->data.i); if (lua_pcall(L, 1, 0, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("attrib_init '%d': %s.\n", a->data.i, error)); } } @@ -54,7 +53,6 @@ static void init_ext(attrib * a) static void free_ext(attrib * a) { lua_State *L = (lua_State *) global.vm_state; - if (a->data.i > 0) { luaL_unref(L, LUA_REGISTRYINDEX, a->data.i); } @@ -68,34 +66,27 @@ static int age_ext(attrib * a) static void write_ext_i(lua_State * L, const char *name, bson_buffer * bb) { int type = lua_type(L, -1); - switch (type) { case LUA_TNUMBER: { double value = tolua_tonumber(L, -1, 0); - bson_append_double(bb, name, value); } break; case LUA_TSTRING: { const char *value = tolua_tostring(L, -1, 0); - bson_append_string(bb, name, value); } break; case LUA_TTABLE: { int n = luaL_getn(L, -1); - if (n) { bson_buffer *arr = bson_append_start_array(bb, name); - int i; - for (i = 0; i != n; ++i) { char num[12]; - bson_numstr(num, i); lua_rawgeti(L, -1, i + 1); write_ext_i(L, num, arr); @@ -104,11 +95,9 @@ static void write_ext_i(lua_State * L, const char *name, bson_buffer * bb) bson_append_finish_object(arr); } else { bson_buffer *sub = bson_append_start_object(bb, name); - lua_pushnil(L); /* first key */ while (lua_next(L, -2) != 0) { const char *key; - /* uses 'key' (at index -2) and 'value' (at index -1) */ lua_pushvalue(L, -2); key = lua_tolstring(L, -1, 0); @@ -126,36 +115,27 @@ static void write_ext_i(lua_State * L, const char *name, bson_buffer * bb) case LUA_TUSERDATA: { tolua_Error tolua_err; - if (tolua_isusertype(L, -1, "unit", 0, &tolua_err)) { unit *u = (unit *) tolua_tousertype(L, -1, 0); - bson_oid_t oid; - oid.ints[0] = TYP_UNIT; oid.ints[1] = u->no; bson_append_oid(bb, name, &oid); } else if (tolua_isusertype(L, -1, "region", 0, &tolua_err)) { region *r = (region *) tolua_tousertype(L, -1, 0); - bson_oid_t oid; - oid.ints[0] = TYP_REGION; oid.ints[1] = r->uid; bson_append_oid(bb, name, &oid); } else if (tolua_isusertype(L, -1, "ship", 0, &tolua_err)) { ship *sh = (ship *) tolua_tousertype(L, -1, 0); - bson_oid_t oid; - oid.ints[0] = TYP_SHIP; oid.ints[1] = sh->no; bson_append_oid(bb, name, &oid); } else if (tolua_isusertype(L, -1, "building", 0, &tolua_err)) { building *b = (building *) tolua_tousertype(L, -1, 0); - bson_oid_t oid; - oid.ints[0] = TYP_BUILDING; oid.ints[1] = b->no; bson_append_oid(bb, name, &oid); @@ -175,12 +155,9 @@ static void write_ext(const attrib * a, const void *owner, struct storage *store) { lua_State *L = (lua_State *) global.vm_state; - if (a->data.i > 0) { int handle = a->data.i; - bson_buffer bb; - bson b; bson_buffer_init(&bb); @@ -209,18 +186,14 @@ static int read_ext_i(lua_State * L, bson_iterator * it, bson_type type) case bson_array: { bson_iterator sub; - int err; - bson_iterator_subiterator(it, &sub); lua_newtable(L); if (bson_iterator_more(&sub)) { bson_type ctype; - for (ctype = bson_iterator_next(&sub); bson_iterator_more(&sub); ctype = bson_iterator_next(&sub)) { int i = atoi(bson_iterator_key(&sub)); - err = read_ext_i(L, &sub, ctype); if (err) { lua_pop(L, 1); @@ -234,14 +207,11 @@ static int read_ext_i(lua_State * L, bson_iterator * it, bson_type type) case bson_object: { bson_iterator sub; - int err; - bson_iterator_subiterator(it, &sub); lua_newtable(L); if (bson_iterator_more(&sub)) { bson_type ctype; - for (ctype = bson_iterator_next(&sub); bson_iterator_more(&sub); ctype = bson_iterator_next(&sub)) { lua_pushstring(L, bson_iterator_key(&sub)); @@ -258,31 +228,26 @@ static int read_ext_i(lua_State * L, bson_iterator * it, bson_type type) case bson_oid: { bson_oid_t *oid = bson_iterator_oid(it); - if (oid->ints[0] == TYP_UNIT) { unit *u = findunit(oid->ints[1]); - if (u) tolua_pushusertype(L, u, "unit"); else lua_pushnil(L); } else if (oid->ints[0] == TYP_REGION) { region *r = findregionbyid(oid->ints[1]); - if (r) tolua_pushusertype(L, r, "region"); else lua_pushnil(L); } else if (oid->ints[0] == TYP_SHIP) { ship *sh = findship(oid->ints[1]); - if (sh) tolua_pushusertype(L, sh, "ship"); else lua_pushnil(L); } else if (oid->ints[0] == TYP_BUILDING) { building *b = findbuilding(oid->ints[1]); - if (b) tolua_pushusertype(L, b, "building"); else @@ -308,15 +273,10 @@ static int read_ext_i(lua_State * L, bson_iterator * it, bson_type type) static int resolve_bson(variant data, void *address) { lua_State *L = (lua_State *) global.vm_state; - bson b; - int err; - bson_iterator it; - attrib *a = (attrib *) address; - char *buffer = data.v; bson_init(&b, buffer, 1); @@ -330,9 +290,7 @@ static int resolve_bson(variant data, void *address) static int read_ext(attrib * a, void *owner, struct storage *store) { variant data; - int len = store->r_int(store); - data.v = bson_malloc(len); store->r_bin(store, data.v, (size_t) len); a->data.v = 0; @@ -347,27 +305,22 @@ attrib_type at_lua_ext = { static attrib **get_attribs(lua_State * L, int idx) { attrib **ap = NULL; - tolua_Error tolua_err; if (tolua_isusertype(L, idx, TOLUA_CAST "unit", 0, &tolua_err)) { unit *u = (unit *) tolua_tousertype(L, idx, 0); - if (u) ap = &u->attribs; } else if (tolua_isusertype(L, idx, TOLUA_CAST "region", 0, &tolua_err)) { region *r = (region *) tolua_tousertype(L, idx, 0); - if (r) ap = &r->attribs; } else if (tolua_isusertype(L, idx, TOLUA_CAST "faction", 0, &tolua_err)) { faction *f = (faction *) tolua_tousertype(L, idx, 0); - if (f) ap = &f->attribs; } else if (lua_isstring(L, idx)) { const char *str = tolua_tostring(L, idx, NULL); - if (str && strcmp(str, "global") == 0) { ap = &global.attribs; } @@ -378,10 +331,8 @@ static attrib **get_attribs(lua_State * L, int idx) static int tolua_attrib_create(lua_State * L) { attrib **ap = get_attribs(L, 1); - if (ap) { attrib *a = a_new(&at_lua_ext); - int handle; lua_pushvalue(L, 2); @@ -398,7 +349,6 @@ static int tolua_attrib_create(lua_State * L) int tolua_attrib_data(lua_State * L) { attrib *a = (attrib *) tolua_tousertype(L, 1, 0); - if (a && a->data.i) { lua_rawgeti(L, LUA_REGISTRYINDEX, a->data.i); return 1; @@ -416,9 +366,7 @@ attrib *tolua_get_lua_ext(struct attrib * alist) int tolua_attriblist_next(lua_State * L) { attrib **attrib_ptr = (attrib **) lua_touserdata(L, lua_upvalueindex(1)); - attrib *a = *attrib_ptr; - if (a != NULL) { tolua_pushusertype(L, (void *)a, TOLUA_CAST "attrib"); *attrib_ptr = tolua_get_lua_ext(a->next); @@ -430,12 +378,9 @@ int tolua_attriblist_next(lua_State * L) int tolua_attrib_get(lua_State * L) { attrib **ap = get_attribs(L, 1); - if (ap) { attrib *a = tolua_get_lua_ext(*ap); - attrib **attrib_ptr = (attrib **) lua_newuserdata(L, sizeof(attrib *)); - luaL_getmetatable(L, "attrib"); lua_setmetatable(L, -2); *attrib_ptr = a; diff --git a/src/bindings/bind_building.c b/src/bindings/bind_building.c index 3f5f53bd0..1a220b4e5 100644 --- a/src/bindings/bind_building.c +++ b/src/bindings/bind_building.c @@ -29,7 +29,6 @@ int tolua_buildinglist_next(lua_State * L) building **building_ptr = (building **) lua_touserdata(L, lua_upvalueindex(1)); building *u = *building_ptr; - if (u != NULL) { tolua_pushusertype(L, (void *)u, TOLUA_CAST "building"); *building_ptr = u->next; @@ -38,13 +37,10 @@ int tolua_buildinglist_next(lua_State * L) return 0; /* no more values to return */ } - static int tolua_building_addaction(lua_State * L) { building *self = (building *) tolua_tousertype(L, 1, 0); - const char *fname = tolua_tostring(L, 2, 0); - const char *param = tolua_tostring(L, 3, 0); building_addaction(self, fname, param); @@ -55,7 +51,6 @@ static int tolua_building_addaction(lua_State * L) static int tolua_building_get_objects(lua_State * L) { building *self = (building *) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void *)&self->attribs, TOLUA_CAST "hashtable"); return 1; } @@ -63,7 +58,6 @@ static int tolua_building_get_objects(lua_State * L) static int tolua_building_get_region(lua_State * L) { building *self = (building *) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, building_getregion(self), TOLUA_CAST "region"); return 1; } @@ -71,16 +65,13 @@ static int tolua_building_get_region(lua_State * L) static int tolua_building_set_region(lua_State * L) { building *self = (building *) tolua_tousertype(L, 1, 0); - building_setregion(self, (region *) tolua_tousertype(L, 2, 0)); return 0; } - static int tolua_building_get_info(lua_State * L) { building *self = (building *) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->display); return 1; } @@ -88,9 +79,7 @@ static int tolua_building_get_info(lua_State * L) static int tolua_building_set_info(lua_State * L) { building *self = (building *) tolua_tousertype(L, 1, 0); - const char *info = tolua_tostring(L, 2, 0); - free(self->display); if (info) self->display = strdup(info); @@ -102,7 +91,6 @@ static int tolua_building_set_info(lua_State * L) static int tolua_building_get_name(lua_State * L) { building *self = (building *) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, building_getname(self)); return 1; } @@ -110,7 +98,6 @@ static int tolua_building_get_name(lua_State * L) static int tolua_building_set_name(lua_State * L) { building *self = (building *) tolua_tousertype(L, 1, 0); - building_setname(self, tolua_tostring(L, 2, 0)); return 0; } @@ -118,7 +105,6 @@ static int tolua_building_set_name(lua_State * L) static int tolua_building_get_size(lua_State * L) { building *self = (building *) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, self->size); return 1; } @@ -126,7 +112,6 @@ static int tolua_building_get_size(lua_State * L) static int tolua_building_set_size(lua_State * L) { building *self = (building *) tolua_tousertype(L, 1, 0); - self->size = (int)tolua_tonumber(L, 2, 0); return 0; } @@ -134,9 +119,7 @@ static int tolua_building_set_size(lua_State * L) static int tolua_building_get_units(lua_State * L) { building *self = (building *) tolua_tousertype(L, 1, 0); - unit **unit_ptr = (unit **) lua_newuserdata(L, sizeof(unit *)); - unit *u = self->region->units; while (u && u->building != self) @@ -153,7 +136,6 @@ static int tolua_building_get_units(lua_State * L) static int tolua_building_get_id(lua_State * L) { building *self = (building *) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number) self->no); return 1; } @@ -161,7 +143,6 @@ static int tolua_building_get_id(lua_State * L) static int tolua_building_get_type(lua_State * L) { building *self = (building *) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->type->_name); return 1; } @@ -169,10 +150,8 @@ static int tolua_building_get_type(lua_State * L) static int tolua_building_get_typename(lua_State * L) { building *b = (building *) tolua_tousertype(L, 1, 0); - if (b) { int size = (int)tolua_tonumber(L, 2, b->size); - tolua_pushstring(L, buildingtype(b->type, b, size)); return 1; } @@ -182,9 +161,7 @@ static int tolua_building_get_typename(lua_State * L) static int tolua_building_get_owner(lua_State * L) { building *b = (building *) tolua_tousertype(L, 1, 0); - unit *u = b ? building_owner(b) : NULL; - tolua_pushusertype(L, u, TOLUA_CAST "unit"); return 1; } @@ -192,11 +169,8 @@ static int tolua_building_get_owner(lua_State * L) static int tolua_building_set_owner(lua_State * L) { building *b = (building *) tolua_tousertype(L, 1, 0); - unit *u = (unit *) tolua_tousertype(L, 2, 0); - unit *o = b ? building_owner(b) : NULL; - if (o && o != u) { freset(o, UFL_OWNER); } @@ -209,15 +183,11 @@ static int tolua_building_set_owner(lua_State * L) static int tolua_building_create(lua_State * L) { region *r = (region *) tolua_tousertype(L, 1, 0); - const char *bname = tolua_tostring(L, 2, 0); - if (bname) { const building_type *btype = bt_find(bname); - if (btype) { building *b = new_building(btype, r, default_locale); - tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); return 1; } @@ -228,7 +198,6 @@ static int tolua_building_create(lua_State * L) static int tolua_building_tostring(lua_State * L) { building *self = (building *) tolua_tousertype(L, 1, 0); - lua_pushstring(L, buildingname(self)); return 1; } @@ -236,7 +205,6 @@ static int tolua_building_tostring(lua_State * L) static int tolua_building_destroy(lua_State * L) { building *self = (building *) tolua_tousertype(L, 1, 0); - remove_building(&self->region->buildings, self); return 0; } diff --git a/src/bindings/bind_faction.c b/src/bindings/bind_faction.c index abfff18e0..c0ca97b8c 100644 --- a/src/bindings/bind_faction.c +++ b/src/bindings/bind_faction.c @@ -31,13 +31,10 @@ without prior permission by the authors of Eressea. #include #include - int tolua_factionlist_next(lua_State * L) { faction **faction_ptr = (faction **) lua_touserdata(L, lua_upvalueindex(1)); - faction *f = *faction_ptr; - if (f != NULL) { tolua_pushusertype(L, (void *)f, TOLUA_CAST "faction"); *faction_ptr = f->next; @@ -49,7 +46,6 @@ int tolua_factionlist_next(lua_State * L) static int tolua_faction_get_units(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - unit **unit_ptr = (unit **) lua_newuserdata(L, sizeof(unit *)); luaL_getmetatable(L, TOLUA_CAST "unit"); @@ -64,19 +60,14 @@ static int tolua_faction_get_units(lua_State * L) int tolua_faction_add_item(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - const char *iname = tolua_tostring(L, 2, 0); - int number = (int)tolua_tonumber(L, 3, 0); - int result = -1; if (iname != NULL) { const item_type *itype = it_find(iname); - if (itype != NULL) { item *i = i_change(&self->items, itype, number); - result = i ? i->number : 0; } // if (itype!=NULL) } @@ -87,7 +78,6 @@ int tolua_faction_add_item(lua_State * L) static int tolua_faction_get_maxheroes(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number) maxheroes(self)); return 1; } @@ -95,7 +85,6 @@ static int tolua_faction_get_maxheroes(lua_State * L) static int tolua_faction_get_heroes(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number) countheroes(self)); return 1; } @@ -103,7 +92,6 @@ static int tolua_faction_get_heroes(lua_State * L) static int tolua_faction_get_score(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number) self->score); return 1; } @@ -111,7 +99,6 @@ static int tolua_faction_get_score(lua_State * L) static int tolua_faction_get_id(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number) self->no); return 1; } @@ -119,9 +106,7 @@ static int tolua_faction_get_id(lua_State * L) static int tolua_faction_set_id(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - int id = (int)tolua_tonumber(L, 2, 0); - if (findfaction(id) == NULL) { renumber_faction(self, id); lua_pushboolean(L, 1); @@ -134,7 +119,6 @@ static int tolua_faction_set_id(lua_State * L) static int tolua_faction_get_age(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number) self->age); return 1; } @@ -142,9 +126,7 @@ static int tolua_faction_get_age(lua_State * L) static int tolua_faction_set_age(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - int age = (int)tolua_tonumber(L, 2, 0); - self->age = age; return 0; } @@ -152,7 +134,6 @@ static int tolua_faction_set_age(lua_State * L) static int tolua_faction_get_flags(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number) self->flags); return 1; } @@ -160,7 +141,6 @@ static int tolua_faction_get_flags(lua_State * L) static int tolua_faction_get_options(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number) self->options); return 1; } @@ -168,9 +148,7 @@ static int tolua_faction_get_options(lua_State * L) static int tolua_faction_set_options(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - int options = (int)tolua_tonumber(L, 2, self->options); - self->options = options; return 1; } @@ -178,7 +156,6 @@ static int tolua_faction_set_options(lua_State * L) static int tolua_faction_get_lastturn(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number) self->lastorders); return 1; } @@ -186,7 +163,6 @@ static int tolua_faction_get_lastturn(lua_State * L) static int tolua_faction_set_lastturn(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - if (self) { self->lastorders = (int)tolua_tonumber(L, 2, self->lastorders); } @@ -196,7 +172,6 @@ static int tolua_faction_set_lastturn(lua_State * L) static int tolua_faction_renumber(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - int no = (int)tolua_tonumber(L, 2, 0); renumber_faction(self, no); @@ -206,7 +181,6 @@ static int tolua_faction_renumber(lua_State * L) static int tolua_faction_get_objects(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void *)&self->attribs, TOLUA_CAST "hashtable"); return 1; } @@ -214,13 +188,10 @@ static int tolua_faction_get_objects(lua_State * L) static int tolua_faction_get_policy(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - faction *other = (faction *) tolua_tousertype(L, 2, 0); - const char *policy = tolua_tostring(L, 3, 0); int result = 0, mode; - for (mode = 0; helpmodes[mode].name != NULL; ++mode) { if (strcmp(policy, helpmodes[mode].name) == 0) { result = get_alliance(self, other) & mode; @@ -232,19 +203,14 @@ static int tolua_faction_get_policy(lua_State * L) return 1; } - static int tolua_faction_set_policy(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - faction *other = (faction *) tolua_tousertype(L, 2, 0); - const char *policy = tolua_tostring(L, 3, 0); - int value = tolua_toboolean(L, 4, 0); int mode; - for (mode = 0; helpmodes[mode].name != NULL; ++mode) { if (strcmp(policy, helpmodes[mode].name) == 0) { if (value) { @@ -264,14 +230,10 @@ static int tolua_faction_set_policy(lua_State * L) static int tolua_faction_normalize(lua_State * L) { faction *f = (faction *) tolua_tousertype(L, 1, 0); - region *r = (region *) tolua_tousertype(L, 2, 0); - if (r) { plane *pl = rplane(r); - int nx = r->x, ny = r->y; - pnormalize(&nx, &ny, pl); adjust_coordinates(f, &nx, &ny, pl, r); tolua_pushnumber(L, (lua_Number) nx); @@ -284,11 +246,8 @@ static int tolua_faction_normalize(lua_State * L) static int tolua_faction_set_origin(lua_State * L) { faction *f = (faction *) tolua_tousertype(L, 1, 0); - region *r = (region *) tolua_tousertype(L, 2, 0); - plane *pl = rplane(r); - int id = pl ? pl->id : 0; set_ursprung(f, id, r->x - plane_center_x(pl), r->y - plane_center_y(pl)); @@ -300,9 +259,7 @@ static int tolua_faction_get_origin(lua_State * L) faction *self = (faction *) tolua_tousertype(L, 1, 0); ursprung *origin = self->ursprung; - int x, y; - while (origin != NULL && origin->id != 0) { origin = origin->next; } @@ -322,7 +279,6 @@ static int tolua_faction_get_origin(lua_State * L) static int tolua_faction_destroy(lua_State * L) { faction *f = (faction *) tolua_tousertype(L, 1, 0); - destroyfaction(f); return 0; } @@ -330,17 +286,11 @@ static int tolua_faction_destroy(lua_State * L) static int tolua_faction_create(lua_State * L) { const char *email = tolua_tostring(L, 1, 0); - const char *racename = tolua_tostring(L, 2, 0); - const char *lang = tolua_tostring(L, 3, 0); - struct locale *loc = find_locale(lang); - faction *f = NULL; - const struct race *frace = rc_find(racename); - if (frace == NULL) frace = findrace(racename, find_locale("de")); if (frace == NULL) @@ -358,7 +308,6 @@ static int tolua_faction_create(lua_State * L) static int tolua_faction_get_password(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, faction_getpassword(self)); return 1; } @@ -366,7 +315,6 @@ static int tolua_faction_get_password(lua_State * L) static int tolua_faction_set_password(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - faction_setpassword(self, tolua_tostring(L, 2, 0)); return 0; } @@ -374,7 +322,6 @@ static int tolua_faction_set_password(lua_State * L) static int tolua_faction_get_email(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, faction_getemail(self)); return 1; } @@ -382,7 +329,6 @@ static int tolua_faction_get_email(lua_State * L) static int tolua_faction_set_email(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - faction_setemail(self, tolua_tostring(L, 2, 0)); return 0; } @@ -390,7 +336,6 @@ static int tolua_faction_set_email(lua_State * L) static int tolua_faction_get_locale(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, locale_name(self->locale)); return 1; } @@ -398,9 +343,7 @@ static int tolua_faction_get_locale(lua_State * L) static int tolua_faction_set_locale(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); - self->locale = find_locale(name); return 0; } @@ -408,7 +351,6 @@ static int tolua_faction_set_locale(lua_State * L) static int tolua_faction_get_race(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->race->_name[0]); return 1; } @@ -416,11 +358,8 @@ static int tolua_faction_get_race(lua_State * L) static int tolua_faction_set_race(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); - race *rc = rc_find(name); - if (rc != NULL) { self->race = rc; } @@ -431,7 +370,6 @@ static int tolua_faction_set_race(lua_State * L) static int tolua_faction_get_name(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, faction_getname(self)); return 1; } @@ -439,7 +377,6 @@ static int tolua_faction_get_name(lua_State * L) static int tolua_faction_set_name(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - faction_setname(self, tolua_tostring(L, 2, 0)); return 0; } @@ -447,7 +384,6 @@ static int tolua_faction_set_name(lua_State * L) static int tolua_faction_get_uid(lua_State * L) { faction *f = (faction *) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, f->subscription); return 1; } @@ -455,7 +391,6 @@ static int tolua_faction_get_uid(lua_State * L) static int tolua_faction_set_uid(lua_State * L) { faction *f = (faction *) tolua_tousertype(L, 1, 0); - f->subscription = (int)tolua_tonumber(L, 2, 0); return 0; } @@ -463,7 +398,6 @@ static int tolua_faction_set_uid(lua_State * L) static int tolua_faction_get_info(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, faction_getbanner(self)); return 1; } @@ -471,7 +405,6 @@ static int tolua_faction_get_info(lua_State * L) static int tolua_faction_set_info(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - faction_setbanner(self, tolua_tostring(L, 2, 0)); return 0; } @@ -479,7 +412,6 @@ static int tolua_faction_set_info(lua_State * L) static int tolua_faction_get_alliance(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, f_get_alliance(self), TOLUA_CAST "alliance"); return 1; } @@ -487,7 +419,6 @@ static int tolua_faction_get_alliance(lua_State * L) static int tolua_faction_set_alliance(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - alliance *alli = (alliance *) tolua_tousertype(L, 2, 0); setalliance(self, alli); @@ -498,7 +429,6 @@ static int tolua_faction_set_alliance(lua_State * L) static int tolua_faction_get_items(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - item **item_ptr = (item **) lua_newuserdata(L, sizeof(item *)); luaL_getmetatable(L, TOLUA_CAST "item"); @@ -514,7 +444,6 @@ static int tolua_faction_get_items(lua_State * L) static int tolua_faction_tostring(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - lua_pushstring(L, factionname(self)); return 1; } @@ -522,7 +451,6 @@ static int tolua_faction_tostring(lua_State * L) static int tolua_faction_get_spells(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - return tolua_quicklist_push(L, "spell_list", "spell", self->spellbook); } diff --git a/src/bindings/bind_gmtool.c b/src/bindings/bind_gmtool.c index f699f7f30..5fe23c6e6 100644 --- a/src/bindings/bind_gmtool.c +++ b/src/bindings/bind_gmtool.c @@ -22,9 +22,7 @@ static int tolua_run_mapper(lua_State * L) static int tolua_highlight_region(lua_State * L) { region *r = tolua_tousertype(L, 1, 0); - int select = tolua_toboolean(L, 2, 0); - highlight_region(r, select); return 0; } @@ -37,15 +35,11 @@ static int tolua_current_region(lua_State * L) return 1; } - static int tolua_select_coordinate(lua_State * L) { int nx = (int)tolua_tonumber(L, 1, 0); - int ny = (int)tolua_tonumber(L, 2, 0); - int select = tolua_toboolean(L, 3, 0); - if (current_state) { select_coordinate(current_state->selected, nx, ny, select); } @@ -55,9 +49,7 @@ static int tolua_select_coordinate(lua_State * L) static int tolua_select_region(lua_State * L) { region *r = tolua_tousertype(L, 1, 0); - int select = tolua_toboolean(L, 2, 0); - if (current_state && r) { select_coordinate(current_state->selected, r->x, r->y, select); } @@ -112,7 +104,6 @@ void tag_rewind(tag_iterator * iter) static int tolua_tags_next(lua_State * L) { tag_iterator *iter = (tag_iterator *) lua_touserdata(L, lua_upvalueindex(1)); - if (iter->node) { tolua_pushusertype(L, (void *)iter->r, TOLUA_CAST "region"); tag_advance(iter); @@ -154,11 +145,8 @@ static int tolua_state_close(lua_State * L) static int tolua_make_island(lua_State * L) { int x = (int)tolua_tonumber(L, 1, 0); - int y = (int)tolua_tonumber(L, 2, 0); - int s = (int)tolua_tonumber(L, 3, 0); - int n = (int)tolua_tonumber(L, 4, s / 3); n = build_island_e3(x, y, n, s); @@ -167,48 +155,36 @@ static int tolua_make_island(lua_State * L) } static int paint_handle; - static struct lua_State *paint_state; static void lua_paint_info(struct window *wnd, const struct state *st) { struct lua_State *L = paint_state; - int nx = st->cursor.x, ny = st->cursor.y; - pnormalize(&nx, &ny, st->cursor.pl); lua_rawgeti(L, LUA_REGISTRYINDEX, paint_handle); tolua_pushnumber(L, nx); tolua_pushnumber(L, ny); if (lua_pcall(L, 2, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("paint function failed: %s\n", error)); lua_pop(L, 1); tolua_error(L, TOLUA_CAST "event handler call failed", NULL); } else { const char *result = lua_tostring(L, -1); - WINDOW *win = wnd->handle; - int size = getmaxx(win) - 2; - int line = 0, maxline = getmaxy(win) - 2; - const char *str = result; - wxborder(win); while (*str && line < maxline) { const char *end = strchr(str, '\n'); - if (!end) break; else { size_t len = end - str; - int bytes = MIN((int)len, size); - mvwaddnstr(win, line++, 1, str, bytes); wclrtoeol(win); str = end + 1; @@ -220,7 +196,6 @@ static void lua_paint_info(struct window *wnd, const struct state *st) static int tolua_set_display(lua_State * L) { int type = lua_type(L, 1); - if (type == LUA_TFUNCTION) { lua_pushvalue(L, 1); paint_handle = luaL_ref(L, LUA_REGISTRYINDEX); @@ -236,13 +211,9 @@ static int tolua_set_display(lua_State * L) static int tolua_make_block(lua_State * L) { int x = (int)tolua_tonumber(L, 1, 0); - int y = (int)tolua_tonumber(L, 2, 0); - int r = (int)tolua_tonumber(L, 3, 6); - const char *str = tolua_tostring(L, 4, TOLUA_CAST "ocean"); - const struct terrain_type *ter = get_terrain(str); make_block(x, y, r, ter); diff --git a/src/bindings/bind_hashtable.c b/src/bindings/bind_hashtable.c index ab9a247b6..2069e272b 100644 --- a/src/bindings/bind_hashtable.c +++ b/src/bindings/bind_hashtable.c @@ -31,17 +31,13 @@ without prior permission by the authors of Eressea. static int tolua_hashtable_get(lua_State * L) { hashtable self = (hashtable) tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); - attrib *a = a_find(*self, &at_object); for (; a && a->type == &at_object; a = a->next) { const char *obj_name = object_name(a); - if (obj_name && name && strcmp(obj_name, name) == 0) { variant val; - object_type type; object_get(a, &type, &val); @@ -83,13 +79,9 @@ static int tolua_hashtable_get(lua_State * L) static int tolua_hashtable_set_number(lua_State * L) { hashtable self = (hashtable) tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); - lua_Number value = tolua_tonumber(L, 3, 0); - attrib *a = a_find(*self, &at_object); - variant val; val.f = (float)value; @@ -108,13 +100,9 @@ static int tolua_hashtable_set_number(lua_State * L) static int tolua_hashtable_set_string(lua_State * L) { hashtable self = (hashtable) tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); - const char *value = tolua_tostring(L, 3, 0); - attrib *a = a_find(*self, &at_object); - variant val; val.v = strdup(value); @@ -133,13 +121,9 @@ static int tolua_hashtable_set_string(lua_State * L) static int tolua_hashtable_set_usertype(lua_State * L, int type) { hashtable self = (hashtable) tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); - unit *value = tolua_tousertype(L, 3, 0); - attrib *a = a_find(*self, &at_object); - variant val; val.v = value; @@ -155,11 +139,9 @@ static int tolua_hashtable_set_usertype(lua_State * L, int type) return 0; } - static int tolua_hashtable_set(lua_State * L) { tolua_Error tolua_err; - if (tolua_isnumber(L, 3, 0, &tolua_err)) { return tolua_hashtable_set_number(L); } else if (tolua_isusertype(L, 3, TOLUA_CAST "unit", 0, &tolua_err)) { @@ -176,8 +158,6 @@ static int tolua_hashtable_set(lua_State * L) return tolua_hashtable_set_string(L); } - - void tolua_hashtable_open(lua_State * L) { /* register user types */ diff --git a/src/bindings/bind_message.c b/src/bindings/bind_message.c index b17024e8a..cd7bcc8a7 100644 --- a/src/bindings/bind_message.c +++ b/src/bindings/bind_message.c @@ -33,7 +33,6 @@ typedef struct lua_message { int mtype_get_param(const message_type * mtype, const char *param) { int i; - for (i = 0; i != mtype->nparameters; ++i) { if (strcmp(mtype->pnames[i], param) == 0) { return i; @@ -45,7 +44,6 @@ int mtype_get_param(const message_type * mtype, const char *param) static lua_message *msg_create_message(const char *type) { lua_message *lmsg = malloc(sizeof(lua_message)); - lmsg->msg = 0; lmsg->args = 0; lmsg->mtype = mt_find(type); @@ -74,7 +72,6 @@ int msg_set_resource(lua_message * msg, const char *param, const char *resname) { if (msg->mtype) { int i = mtype_get_param(msg->mtype, param); - if (i == msg->mtype->nparameters) { return E_INVALID_PARAMETER_NAME; } @@ -131,7 +128,6 @@ int msg_set_string(lua_message * msg, const char *param, const char *value) { if (msg->mtype) { int i = mtype_get_param(msg->mtype, param); - variant var; if (i == msg->mtype->nparameters) { @@ -153,7 +149,6 @@ int msg_set_int(lua_message * msg, const char *param, int value) { if (msg->mtype) { int i = mtype_get_param(msg->mtype, param); - if (i == msg->mtype->nparameters) { return E_INVALID_PARAMETER_NAME; } @@ -195,13 +190,10 @@ int msg_send_region(lua_message * lmsg, region * r) return E_INVALID_MESSAGE; } - static int tolua_msg_create(lua_State * L) { const char *type = tolua_tostring(L, 1, 0); - lua_message *lmsg = msg_create_message(type); - tolua_pushusertype(L, (void *)lmsg, TOLUA_CAST "message"); return 1; } @@ -209,13 +201,9 @@ static int tolua_msg_create(lua_State * L) static int tolua_msg_set_string(lua_State * L) { lua_message *lmsg = (lua_message *) tolua_tousertype(L, 1, 0); - const char *param = tolua_tostring(L, 2, 0); - const char *value = tolua_tostring(L, 3, 0); - int result = msg_set_string(lmsg, param, value); - tolua_pushnumber(L, (lua_Number) result); return 1; } @@ -223,13 +211,9 @@ static int tolua_msg_set_string(lua_State * L) static int tolua_msg_set_int(lua_State * L) { lua_message *lmsg = (lua_message *) tolua_tousertype(L, 1, 0); - const char *param = tolua_tostring(L, 2, 0); - int value = (int)tolua_tonumber(L, 3, 0); - int result = msg_set_int(lmsg, param, value); - tolua_pushnumber(L, (lua_Number) result); return 1; } @@ -237,13 +221,9 @@ static int tolua_msg_set_int(lua_State * L) static int tolua_msg_set_resource(lua_State * L) { lua_message *lmsg = (lua_message *) tolua_tousertype(L, 1, 0); - const char *param = tolua_tostring(L, 2, 0); - const char *value = tolua_tostring(L, 3, 0); - int result = msg_set_resource(lmsg, param, value); - tolua_pushnumber(L, (lua_Number) result); return 1; } @@ -251,13 +231,9 @@ static int tolua_msg_set_resource(lua_State * L) static int tolua_msg_set_unit(lua_State * L) { lua_message *lmsg = (lua_message *) tolua_tousertype(L, 1, 0); - const char *param = tolua_tostring(L, 2, 0); - unit *value = (unit *) tolua_tousertype(L, 3, 0); - int result = msg_set_unit(lmsg, param, value); - tolua_pushnumber(L, (lua_Number) result); return 1; } @@ -265,13 +241,9 @@ static int tolua_msg_set_unit(lua_State * L) static int tolua_msg_set_region(lua_State * L) { lua_message *lmsg = (lua_message *) tolua_tousertype(L, 1, 0); - const char *param = tolua_tostring(L, 2, 0); - region *value = (region *) tolua_tousertype(L, 3, 0); - int result = msg_set_region(lmsg, param, value); - tolua_pushnumber(L, (lua_Number) result); return 1; } @@ -279,7 +251,6 @@ static int tolua_msg_set_region(lua_State * L) static int tolua_msg_set(lua_State * L) { tolua_Error err; - if (tolua_isnumber(L, 3, 0, &err)) { return tolua_msg_set_int(L); } else if (tolua_isusertype(L, 3, TOLUA_CAST "region", 0, &err)) { @@ -294,11 +265,8 @@ static int tolua_msg_set(lua_State * L) static int tolua_msg_send_region(lua_State * L) { lua_message *lmsg = (lua_message *) tolua_tousertype(L, 1, 0); - region *r = (region *) tolua_tousertype(L, 2, 0); - int result = msg_send_region(lmsg, r); - tolua_pushnumber(L, (lua_Number) result); return 1; } @@ -306,13 +274,9 @@ static int tolua_msg_send_region(lua_State * L) static int tolua_msg_report_action(lua_State * L) { lua_message *lmsg = (lua_message *) tolua_tousertype(L, 1, 0); - region *r = (region *) tolua_tousertype(L, 2, 0); - unit *u = (unit *) tolua_tousertype(L, 3, 0); - int result, flags = (int)tolua_tonumber(L, 4, 0); - if (lmsg->msg == NULL) { lmsg->msg = msg_create(lmsg->mtype, lmsg->args); } @@ -324,12 +288,9 @@ static int tolua_msg_report_action(lua_State * L) static int tolua_msg_send_faction(lua_State * L) { lua_message *lmsg = (lua_message *) tolua_tousertype(L, 1, 0); - faction *f = (faction *) tolua_tousertype(L, 2, 0); - if (f && lmsg) { int result = msg_send_faction(lmsg, f); - tolua_pushnumber(L, (lua_Number) result); return 1; } diff --git a/src/bindings/bind_region.c b/src/bindings/bind_region.c index c41c2ef0d..3ec4d8e5b 100644 --- a/src/bindings/bind_region.c +++ b/src/bindings/bind_region.c @@ -44,9 +44,7 @@ without prior permission by the authors of Eressea. int tolua_regionlist_next(lua_State * L) { region **region_ptr = (region **) lua_touserdata(L, lua_upvalueindex(1)); - region *r = *region_ptr; - if (r != NULL) { tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); *region_ptr = r->next; @@ -58,7 +56,6 @@ int tolua_regionlist_next(lua_State * L) static int tolua_region_get_id(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number) self->uid); return 1; } @@ -66,7 +63,6 @@ static int tolua_region_get_id(lua_State * L) static int tolua_region_get_x(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number) self->x); return 1; } @@ -74,7 +70,6 @@ static int tolua_region_get_x(lua_State * L) static int tolua_region_get_y(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number) self->y); return 1; } @@ -82,7 +77,6 @@ static int tolua_region_get_y(lua_State * L) static int tolua_region_get_plane(lua_State * L) { region *r = (region *) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, rplane(r), TOLUA_CAST "plane"); return 1; } @@ -90,7 +84,6 @@ static int tolua_region_get_plane(lua_State * L) static int tolua_region_get_terrain(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->terrain->_name); return 1; } @@ -98,12 +91,9 @@ static int tolua_region_get_terrain(lua_State * L) static int tolua_region_set_terrain(lua_State * L) { region *r = (region *) tolua_tousertype(L, 1, 0); - const char *tname = tolua_tostring(L, 2, 0); - if (tname) { const terrain_type *terrain = get_terrain(tname); - if (terrain) { terraform_region(r, terrain); } @@ -114,9 +104,7 @@ static int tolua_region_set_terrain(lua_State * L) static int tolua_region_get_terrainname(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); - attrib *a = a_find(self->attribs, &at_racename); - if (a) { tolua_pushstring(L, get_racename(a)); return 1; @@ -127,9 +115,7 @@ static int tolua_region_get_terrainname(lua_State * L) static int tolua_region_set_owner(lua_State * L) { region *r = (region *) tolua_tousertype(L, 1, 0); - struct faction *f = (struct faction *)tolua_tousertype(L, 2, 0); - if (r) { region_set_owner(r, f, turn); } @@ -139,10 +125,8 @@ static int tolua_region_set_owner(lua_State * L) static int tolua_region_get_owner(lua_State * L) { region *r = (region *) tolua_tousertype(L, 1, 0); - if (r) { struct faction *f = region_get_owner(r); - tolua_pushusertype(L, f, TOLUA_CAST "faction"); return 1; } @@ -152,9 +136,7 @@ static int tolua_region_get_owner(lua_State * L) static int tolua_region_set_terrainname(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); - if (name == NULL) { a_removeall(&self->attribs, &at_racename); } else { @@ -166,7 +148,6 @@ static int tolua_region_set_terrainname(lua_State * L) static int tolua_region_get_info(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, region_getinfo(self)); return 1; } @@ -174,16 +155,13 @@ static int tolua_region_get_info(lua_State * L) static int tolua_region_set_info(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); - region_setinfo(self, tolua_tostring(L, 2, 0)); return 0; } - static int tolua_region_get_name(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, region_getname(self)); return 1; } @@ -191,16 +169,13 @@ static int tolua_region_get_name(lua_State * L) static int tolua_region_set_name(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); - region_setname(self, tolua_tostring(L, 2, 0)); return 0; } - static int tolua_region_get_morale(lua_State * L) { region *r = (region *) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, region_get_morale(r)); return 1; } @@ -208,7 +183,6 @@ static int tolua_region_get_morale(lua_State * L) static int tolua_region_set_morale(lua_State * L) { region *r = (region *) tolua_tousertype(L, 1, 0); - region_set_morale(r, (int)tolua_tonumber(L, 2, 0), turn); return 0; } @@ -216,11 +190,8 @@ static int tolua_region_set_morale(lua_State * L) static int tolua_region_get_adj(lua_State * L) { region *r = (region *) tolua_tousertype(L, 1, 0); - region *rn[MAXDIRECTIONS]; - int d, idx; - get_neighbours(r, rn); lua_createtable(L, MAXDIRECTIONS, 0); @@ -236,13 +207,10 @@ static int tolua_region_get_adj(lua_State * L) static int tolua_region_get_luxury(lua_State * L) { region *r = (region *) tolua_tousertype(L, 1, 0); - if (r->land) { const item_type *lux = r_luxury(r); - if (lux) { const char *name = lux->rtype->_name[0]; - tolua_pushstring(L, name); return 1; } @@ -253,14 +221,10 @@ static int tolua_region_get_luxury(lua_State * L) static int tolua_region_set_luxury(lua_State * L) { region *r = (region *) tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); - if (r->land && name) { const item_type *lux = r_luxury(r); - const item_type *itype = it_find(name); - if (lux && itype && lux != itype) { r_setdemand(r, lux->rtype->ltype, 1); r_setdemand(r, itype->rtype->ltype, 0); @@ -272,12 +236,9 @@ static int tolua_region_set_luxury(lua_State * L) static int tolua_region_set_herb(lua_State * L) { region *r = (region *) tolua_tousertype(L, 1, 0); - if (r->land) { const char *name = tolua_tostring(L, 2, 0); - const item_type *itype = it_find(name); - if (itype && (itype->flags & ITF_HERB)) { r->land->herbtype = itype; } @@ -288,10 +249,8 @@ static int tolua_region_set_herb(lua_State * L) static int tolua_region_get_herb(lua_State * L) { region *r = (region *) tolua_tousertype(L, 1, 0); - if (r->land && r->land->herbtype) { const char *name = r->land->herbtype->rtype->_name[0]; - tolua_pushstring(L, name); return 1; } @@ -301,7 +260,6 @@ static int tolua_region_get_herb(lua_State * L) static int tolua_region_get_next(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); - direction_t dir = (direction_t) tolua_tonumber(L, 2, 0); if (dir >= 0 && dir < MAXDIRECTIONS) { @@ -314,7 +272,6 @@ static int tolua_region_get_next(lua_State * L) static int tolua_region_get_flag(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); - int bit = (int)tolua_tonumber(L, 2, 0); lua_pushboolean(L, (self->flags & (1 << bit))); @@ -324,9 +281,7 @@ static int tolua_region_get_flag(lua_State * L) static int tolua_region_set_flag(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); - int bit = (int)tolua_tonumber(L, 2, 0); - int set = tolua_toboolean(L, 3, 1); if (set) @@ -339,14 +294,10 @@ static int tolua_region_set_flag(lua_State * L) static int tolua_region_get_resourcelevel(lua_State * L) { region *r = (region *) tolua_tousertype(L, 1, 0); - const char *type = tolua_tostring(L, 2, 0); - const resource_type *rtype = rt_find(type); - if (rtype != NULL) { const rawmaterial *rm; - for (rm = r->resources; rm; rm = rm->next) { if (rm->type->rtype == rtype) { tolua_pushnumber(L, (lua_Number) rm->level); @@ -361,11 +312,8 @@ static int tolua_region_get_resourcelevel(lua_State * L) static int tolua_region_get_resource(lua_State * L) { region *r; - const char *type; - const resource_type *rtype; - int result = 0; r = (region *) tolua_tousertype(L, 1, 0); @@ -396,11 +344,8 @@ static int tolua_region_get_resource(lua_State * L) static int tolua_region_set_resource(lua_State * L) { region *r = (region *) tolua_tousertype(L, 1, 0); - const char *type = tolua_tostring(L, 2, 0); - int value = (int)tolua_tonumber(L, 3, 0); - const resource_type *rtype = rt_find(type); if (rtype != NULL) { @@ -414,11 +359,9 @@ static int tolua_region_set_resource(lua_State * L) rsettrees(r, 2, value); } else if (strcmp(type, "grave") == 0) { int fallen = value - deathcount(r); - deathcounts(r, fallen); } else if (strcmp(type, "chaos") == 0) { int fallen = value - chaoscount(r); - chaoscounts(r, fallen); } } @@ -428,7 +371,6 @@ static int tolua_region_set_resource(lua_State * L) static int tolua_region_get_objects(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void *)&self->attribs, TOLUA_CAST "hashtable"); return 1; } @@ -436,7 +378,6 @@ static int tolua_region_get_objects(lua_State * L) static int tolua_region_destroy(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); - remove_region(®ions, self); return 0; } @@ -444,18 +385,12 @@ static int tolua_region_destroy(lua_State * L) static int tolua_region_create(lua_State * L) { int x = (int)tolua_tonumber(L, 1, 0); - int y = (int)tolua_tonumber(L, 2, 0); - const char *tname = tolua_tostring(L, 3, 0); - if (tname) { plane *pl = findplane(x, y); - const terrain_type *terrain = get_terrain(tname); - region *r, *result; - if (!terrain) { return 0; } @@ -483,7 +418,6 @@ static int tolua_region_create(lua_State * L) static int tolua_region_get_units(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); - unit **unit_ptr = (unit **) lua_newuserdata(L, sizeof(unit *)); luaL_getmetatable(L, "unit"); @@ -498,7 +432,6 @@ static int tolua_region_get_units(lua_State * L) static int tolua_region_get_buildings(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); - building **building_ptr = (building **) lua_newuserdata(L, sizeof(building *)); @@ -514,7 +447,6 @@ static int tolua_region_get_buildings(lua_State * L) static int tolua_region_get_ships(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); - ship **ship_ptr = (ship **) lua_newuserdata(L, sizeof(ship *)); luaL_getmetatable(L, "ship"); @@ -540,13 +472,10 @@ static int tolua_region_get_age(lua_State * L) static int tolua_region_getkey(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); int flag = atoi36(name); - attrib *a = find_key(self->attribs, flag); - lua_pushboolean(L, a != NULL); return 1; @@ -555,15 +484,11 @@ static int tolua_region_getkey(lua_State * L) static int tolua_region_setkey(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); - int value = tolua_toboolean(L, 3, 0); int flag = atoi36(name); - attrib *a = find_key(self->attribs, flag); - if (a == NULL && value) { add_key(&self->attribs, flag); } else if (a != NULL && !value) { @@ -575,7 +500,6 @@ static int tolua_region_setkey(lua_State * L) static int tolua_region_tostring(lua_State * L) { region *self = (region *) tolua_tousertype(L, 1, 0); - lua_pushstring(L, regionname(self, NULL)); return 1; } @@ -583,7 +507,6 @@ static int tolua_region_tostring(lua_State * L) static int tolua_plane_get(lua_State * L) { int id = (int)tolua_tonumber(L, 1, 0); - plane *pl = getplanebyid(id); tolua_pushusertype(L, pl, TOLUA_CAST "plane"); @@ -593,17 +516,11 @@ static int tolua_plane_get(lua_State * L) static int tolua_plane_create(lua_State * L) { int id = (int)tolua_tonumber(L, 1, 0); - int x = (int)tolua_tonumber(L, 2, 0); - int y = (int)tolua_tonumber(L, 3, 0); - int width = (int)tolua_tonumber(L, 4, 0); - int height = (int)tolua_tonumber(L, 5, 0); - const char *name = tolua_tostring(L, 6, 0); - plane *pl; pl = create_new_plane(id, name, x, x + width - 1, y, y + height - 1, 0); @@ -615,7 +532,6 @@ static int tolua_plane_create(lua_State * L) static int tolua_plane_get_name(lua_State * L) { plane *self = (plane *) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->name); return 1; } @@ -623,9 +539,7 @@ static int tolua_plane_get_name(lua_State * L) static int tolua_plane_set_name(lua_State * L) { plane *self = (plane *) tolua_tousertype(L, 1, 0); - const char *str = tolua_tostring(L, 2, 0); - free(self->name); if (str) self->name = strdup(str); @@ -637,7 +551,6 @@ static int tolua_plane_set_name(lua_State * L) static int tolua_plane_get_id(lua_State * L) { plane *self = (plane *) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number) self->id); return 1; } @@ -645,11 +558,8 @@ static int tolua_plane_get_id(lua_State * L) static int tolua_plane_normalize(lua_State * L) { plane *self = (plane *) tolua_tousertype(L, 1, 0); - int x = (int)tolua_tonumber(L, 2, 0); - int y = (int)tolua_tonumber(L, 3, 0); - pnormalize(&x, &y, self); tolua_pushnumber(L, (lua_Number) x); tolua_pushnumber(L, (lua_Number) y); @@ -659,7 +569,6 @@ static int tolua_plane_normalize(lua_State * L) static int tolua_plane_tostring(lua_State * L) { plane *self = (plane *) tolua_tousertype(L, 1, 0); - lua_pushstring(L, self->name); return 1; } @@ -667,7 +576,6 @@ static int tolua_plane_tostring(lua_State * L) static int tolua_plane_get_size(lua_State * L) { plane *pl = (plane *) tolua_tousertype(L, 1, 0); - lua_pushnumber(L, plane_width(pl)); lua_pushnumber(L, plane_height(pl)); return 2; @@ -676,15 +584,10 @@ static int tolua_plane_get_size(lua_State * L) static int tolua_distance(lua_State * L) { int x1 = (int)tolua_tonumber(L, 1, 0); - int y1 = (int)tolua_tonumber(L, 2, 0); - int x2 = (int)tolua_tonumber(L, 3, 0); - int y2 = (int)tolua_tonumber(L, 4, 0); - plane *pl = (plane *) tolua_tousertype(L, 5, 0); - int result; if (!pl) diff --git a/src/bindings/bind_ship.c b/src/bindings/bind_ship.c index d8f216c7c..a72dec778 100644 --- a/src/bindings/bind_ship.c +++ b/src/bindings/bind_ship.c @@ -28,9 +28,7 @@ without prior permission by the authors of Eressea. int tolua_shiplist_next(lua_State * L) { ship **ship_ptr = (ship **) lua_touserdata(L, lua_upvalueindex(1)); - ship *u = *ship_ptr; - if (u != NULL) { tolua_pushusertype(L, (void *)u, TOLUA_CAST "ship"); *ship_ptr = u->next; @@ -42,7 +40,6 @@ int tolua_shiplist_next(lua_State * L) static int tolua_ship_get_id(lua_State * L) { ship *self = (ship *) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number) self->no); return 1; } @@ -50,7 +47,6 @@ static int tolua_ship_get_id(lua_State * L) static int tolua_ship_get_name(lua_State * L) { ship *self = (ship *) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, ship_getname(self)); return 1; } @@ -58,7 +54,6 @@ static int tolua_ship_get_name(lua_State * L) static int tolua_ship_get_region(lua_State * L) { ship *self = (ship *) tolua_tousertype(L, 1, 0); - if (self) { tolua_pushusertype(L, self->region, TOLUA_CAST "region"); return 1; @@ -69,9 +64,7 @@ static int tolua_ship_get_region(lua_State * L) static int tolua_ship_set_region(lua_State * L) { ship *self = (ship *) tolua_tousertype(L, 1, 0); - region *r = (region *) tolua_tousertype(L, 1, 0); - if (self) { move_ship(self, self->region, r, NULL); } @@ -81,7 +74,6 @@ static int tolua_ship_set_region(lua_State * L) static int tolua_ship_set_name(lua_State * L) { ship *self = (ship *) tolua_tousertype(L, 1, 0); - ship_setname(self, tolua_tostring(L, 2, 0)); return 0; } @@ -89,9 +81,7 @@ static int tolua_ship_set_name(lua_State * L) static int tolua_ship_get_units(lua_State * L) { ship *self = (ship *) tolua_tousertype(L, 1, 0); - unit **unit_ptr = (unit **) lua_newuserdata(L, sizeof(unit *)); - unit *u = self->region->units; while (u && u->ship != self) @@ -108,7 +98,6 @@ static int tolua_ship_get_units(lua_State * L) static int tolua_ship_get_objects(lua_State * L) { ship *self = (ship *) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void *)&self->attribs, TOLUA_CAST "hashtable"); return 1; } @@ -116,15 +105,11 @@ static int tolua_ship_get_objects(lua_State * L) static int tolua_ship_create(lua_State * L) { region *r = (region *) tolua_tousertype(L, 1, 0); - const char *sname = tolua_tostring(L, 2, 0); - if (sname) { const ship_type *stype = st_find(sname); - if (stype) { ship *sh = new_ship(stype, default_locale, r); - sh->size = stype->construction->maxsize; tolua_pushusertype(L, (void *)sh, TOLUA_CAST "ship"); return 1; @@ -137,7 +122,6 @@ static int tolua_ship_tostring(lua_State * L) { ship *self = (ship *) tolua_tousertype(L, 1, 0); - lua_pushstring(L, shipname(self)); return 1; } @@ -145,7 +129,6 @@ static int static int tolua_ship_get_flags(lua_State * L) { ship *self = (ship *) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number) self->flags); return 1; } @@ -153,7 +136,6 @@ static int tolua_ship_get_flags(lua_State * L) static int tolua_ship_set_flags(lua_State * L) { ship *self = (ship *) tolua_tousertype(L, 1, 0); - self->flags = (int)tolua_tonumber(L, 2, 0); return 0; } @@ -161,7 +143,6 @@ static int tolua_ship_set_flags(lua_State * L) static int tolua_ship_set_coast(lua_State * L) { ship *self = (ship *) tolua_tousertype(L, 1, 0); - if (lua_isnil(L, 2)) { self->coast = NODIRECTION; } else if (lua_isnumber(L, 2)) { @@ -173,7 +154,6 @@ static int tolua_ship_set_coast(lua_State * L) static int tolua_ship_get_coast(lua_State * L) { ship *self = (ship *) tolua_tousertype(L, 1, 0); - if (self->coast) { tolua_pushnumber(L, self->coast); return 1; @@ -181,7 +161,6 @@ static int tolua_ship_get_coast(lua_State * L) return 0; } - void tolua_ship_open(lua_State * L) { /* register user types */ diff --git a/src/bindings/bind_sqlite.c b/src/bindings/bind_sqlite.c index 63a10914c..be1eacec7 100644 --- a/src/bindings/bind_sqlite.c +++ b/src/bindings/bind_sqlite.c @@ -22,21 +22,17 @@ without prior permission by the authors of Eressea. #define LTYPE_DB TOLUA_CAST "db" extern int db_update_factions(sqlite3 * db, boolean force); - static int tolua_db_update_factions(lua_State * L) { sqlite3 *db = (sqlite3 *) tolua_tousertype(L, 1, 0); - db_update_factions(db, tolua_toboolean(L, 2, 0)); return 0; } extern int db_update_scores(sqlite3 * db, boolean force); - static int tolua_db_update_scores(lua_State * L) { sqlite3 *db = (sqlite3 *) tolua_tousertype(L, 1, 0); - db_update_scores(db, tolua_toboolean(L, 2, 0)); return 0; } @@ -44,7 +40,6 @@ static int tolua_db_update_scores(lua_State * L) static int tolua_db_execute(lua_State * L) { sqlite3 *db = (sqlite3 *) tolua_tousertype(L, 1, 0); - const char *sql = tolua_tostring(L, 2, 0); int res = sqlite3_exec(db, sql, 0, 0, 0); @@ -56,7 +51,6 @@ static int tolua_db_execute(lua_State * L) static int tolua_db_close(lua_State * L) { sqlite3 *db = (sqlite3 *) tolua_tousertype(L, 1, 0); - sqlite3_close(db); return 0; } @@ -64,11 +58,8 @@ static int tolua_db_close(lua_State * L) static int tolua_db_create(lua_State * L) { sqlite3 *db; - const char *dbname = tolua_tostring(L, 1, 0); - int result = sqlite3_open_v2(dbname, &db, SQLITE_OPEN_READWRITE, 0); - if (result == SQLITE_OK) { tolua_pushusertype(L, (void *)db, LTYPE_DB); return 1; diff --git a/src/bindings/bind_storage.c b/src/bindings/bind_storage.c index 32f581956..f96367ddc 100644 --- a/src/bindings/bind_storage.c +++ b/src/bindings/bind_storage.c @@ -24,17 +24,12 @@ without prior permission by the authors of Eressea. #include #include - static int tolua_storage_create(lua_State * L) { const char *filename = tolua_tostring(L, 1, 0); - const char *type = tolua_tostring(L, 2, "rb"); - storage *store = 0; - int mode = IO_READ; - if (strchr(type, 't')) { store = malloc(sizeof(text_store)); memcpy(store, &text_store, sizeof(text_store)); @@ -54,9 +49,7 @@ static int tolua_storage_create(lua_State * L) static int tolua_storage_read_unit(lua_State * L) { storage *self = (storage *) tolua_tousertype(L, 1, 0); - struct unit *u = read_unit(self); - tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); return 1; } @@ -64,22 +57,17 @@ static int tolua_storage_read_unit(lua_State * L) static int tolua_storage_write_unit(lua_State * L) { storage *store = (storage *) tolua_tousertype(L, 1, 0); - struct unit *u = (struct unit *)tolua_tousertype(L, 2, 0); - if (store->version) { write_unit(store, u); } return 0; } - static int tolua_storage_read_float(lua_State * L) { storage *self = (storage *) tolua_tousertype(L, 1, 0); - float num = self->r_flt(self); - tolua_pushnumber(L, (lua_Number) num); return 1; } @@ -87,9 +75,7 @@ static int tolua_storage_read_float(lua_State * L) static int tolua_storage_read_int(lua_State * L) { storage *self = (storage *) tolua_tousertype(L, 1, 0); - int num = self->r_int(self); - tolua_pushnumber(L, (lua_Number) num); return 1; } @@ -97,12 +83,9 @@ static int tolua_storage_read_int(lua_State * L) static int tolua_storage_write(lua_State * L) { storage *self = (storage *) tolua_tousertype(L, 1, 0); - if (self->version && tolua_isnumber(L, 2, 0, 0)) { lua_Number num = tolua_tonumber(L, 2, 0); - double n; - if (modf(num, &n) == 0.0) { self->w_int(self, (int)num); } else { @@ -115,9 +98,7 @@ static int tolua_storage_write(lua_State * L) static int tolua_storage_tostring(lua_State * L) { storage *self = (storage *) tolua_tousertype(L, 1, 0); - char name[64]; - snprintf(name, sizeof(name), "", self->encoding, self->version); lua_pushstring(L, name); @@ -127,7 +108,6 @@ static int tolua_storage_tostring(lua_State * L) static int tolua_storage_close(lua_State * L) { storage *self = (storage *) tolua_tousertype(L, 1, 0); - self->close(self); return 0; } diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index fc6a25f8c..8542d60c7 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -55,18 +55,14 @@ without prior permission by the authors of Eressea. static int tolua_unit_get_objects(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void *)&self->attribs, TOLUA_CAST "hashtable"); return 1; } - static int tolua_unit_get_attribs(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - attrib **attrib_ptr = (attrib **) lua_newuserdata(L, sizeof(attrib *)); - attrib *a = tolua_get_lua_ext(self->attribs); luaL_getmetatable(L, "attrib"); @@ -81,9 +77,7 @@ static int tolua_unit_get_attribs(lua_State * L) int tolua_unitlist_nextf(lua_State * L) { unit **unit_ptr = (unit **) lua_touserdata(L, lua_upvalueindex(1)); - unit *u = *unit_ptr; - if (u != NULL) { tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); *unit_ptr = u->nextF; @@ -95,12 +89,9 @@ int tolua_unitlist_nextf(lua_State * L) int tolua_unitlist_nextb(lua_State * L) { unit **unit_ptr = (unit **) lua_touserdata(L, lua_upvalueindex(1)); - unit *u = *unit_ptr; - if (u != NULL) { unit *unext = u->next; - tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); while (unext && unext->building != u->building) { @@ -116,12 +107,9 @@ int tolua_unitlist_nextb(lua_State * L) int tolua_unitlist_nexts(lua_State * L) { unit **unit_ptr = (unit **) lua_touserdata(L, lua_upvalueindex(1)); - unit *u = *unit_ptr; - if (u != NULL) { unit *unext = u->next; - tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); while (unext && unext->ship != u->ship) { @@ -137,9 +125,7 @@ int tolua_unitlist_nexts(lua_State * L) int tolua_unitlist_next(lua_State * L) { unit **unit_ptr = (unit **) lua_touserdata(L, lua_upvalueindex(1)); - unit *u = *unit_ptr; - if (u != NULL) { tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); *unit_ptr = u->next; @@ -148,11 +134,9 @@ int tolua_unitlist_next(lua_State * L) return 0; /* no more values to return */ } - static int tolua_unit_get_name(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->name); return 1; } @@ -160,7 +144,6 @@ static int tolua_unit_get_name(lua_State * L) static int tolua_unit_set_name(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - unit_setname(self, tolua_tostring(L, 2, 0)); return 0; } @@ -168,7 +151,6 @@ static int tolua_unit_set_name(lua_State * L) static int tolua_unit_get_info(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, unit_getinfo(self)); return 1; } @@ -176,7 +158,6 @@ static int tolua_unit_get_info(lua_State * L) static int tolua_unit_set_info(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - unit_setinfo(self, tolua_tostring(L, 2, 0)); return 0; } @@ -184,7 +165,6 @@ static int tolua_unit_set_info(lua_State * L) static int tolua_unit_get_id(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - lua_pushinteger(L, unit_getid(self)); return 1; } @@ -192,7 +172,6 @@ static int tolua_unit_get_id(lua_State * L) static int tolua_unit_set_id(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - unit_setid(self, (int)tolua_tonumber(L, 2, 0)); return 0; } @@ -200,7 +179,6 @@ static int tolua_unit_set_id(lua_State * L) static int tolua_unit_get_hpmax(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - lua_pushinteger(L, unit_max_hp(self)); return 1; } @@ -208,7 +186,6 @@ static int tolua_unit_get_hpmax(lua_State * L) static int tolua_unit_get_hp(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - lua_pushinteger(L, unit_gethp(self)); return 1; } @@ -216,7 +193,6 @@ static int tolua_unit_get_hp(lua_State * L) static int tolua_unit_set_hp(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - unit_sethp(self, (int)tolua_tonumber(L, 2, 0)); return 0; } @@ -224,7 +200,6 @@ static int tolua_unit_set_hp(lua_State * L) static int tolua_unit_get_number(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - lua_pushinteger(L, self->number); return 1; } @@ -232,9 +207,7 @@ static int tolua_unit_get_number(lua_State * L) static int tolua_unit_set_number(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - int number = (int)tolua_tonumber(L, 2, 0); - if (self->number == 0) { set_number(self, number); self->hp = unit_max_hp(self) * number; @@ -247,7 +220,6 @@ static int tolua_unit_set_number(lua_State * L) static int tolua_unit_get_flags(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - lua_pushinteger(L, self->flags); return 1; } @@ -255,7 +227,6 @@ static int tolua_unit_get_flags(lua_State * L) static int tolua_unit_set_flags(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - self->flags = (int)tolua_tonumber(L, 2, 0); return 0; } @@ -263,14 +234,12 @@ static int tolua_unit_set_flags(lua_State * L) static const char *unit_getmagic(const unit * u) { sc_mage *mage = get_mage(u); - return mage ? magic_school[mage->magietyp] : NULL; } static int tolua_unit_get_magic(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - lua_pushstring(L, unit_getmagic(self)); return 1; } @@ -278,9 +247,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); - magic_t mtype; - for (mtype = 0; mtype != MAXMAGIETYP; ++mtype) { if (strcmp(magic_school[mtype], type) == 0) break; @@ -295,9 +262,7 @@ static void unit_setmagic(unit * u, const char *type) static int tolua_unit_set_magic(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - const char *type = tolua_tostring(L, 2, 0); - unit_setmagic(self, type); return 0; } @@ -305,7 +270,6 @@ static int tolua_unit_set_magic(lua_State * L) static int tolua_unit_get_aura(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - lua_pushinteger(L, get_spellpoints(self)); return 1; } @@ -313,7 +277,6 @@ static int tolua_unit_get_aura(lua_State * L) static int tolua_unit_set_aura(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - set_spellpoints(self, (int)tolua_tonumber(L, 2, 0)); return 0; } @@ -321,7 +284,6 @@ static int tolua_unit_set_aura(lua_State * L) static int tolua_unit_get_age(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - lua_pushinteger(L, self->age); return 1; } @@ -329,7 +291,6 @@ static int tolua_unit_get_age(lua_State * L) static int tolua_unit_set_age(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - self->age = (short)tolua_tonumber(L, 2, 0); return 0; } @@ -337,7 +298,6 @@ static int tolua_unit_set_age(lua_State * L) static int tolua_unit_get_status(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - lua_pushinteger(L, unit_getstatus(self)); return 1; } @@ -345,7 +305,6 @@ static int tolua_unit_get_status(lua_State * L) static int tolua_unit_set_status(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - unit_setstatus(self, (status_t) tolua_tonumber(L, 2, 0)); return 0; } @@ -353,14 +312,11 @@ static int tolua_unit_set_status(lua_State * L) static int tolua_unit_get_item(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - const char *iname = tolua_tostring(L, 2, 0); - int result = -1; if (iname != NULL) { const item_type *itype = it_find(iname); - if (itype != NULL) { result = i_get(self->items, itype); } @@ -372,19 +328,14 @@ static int tolua_unit_get_item(lua_State * L) static int tolua_unit_add_item(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - const char *iname = tolua_tostring(L, 2, 0); - int number = (int)tolua_tonumber(L, 3, 0); - int result = -1; if (iname != NULL) { const item_type *itype = it_find(iname); - if (itype != NULL) { item *i = i_change(&self->items, itype, number); - result = i ? i->number : 0; } } @@ -395,16 +346,11 @@ static int tolua_unit_add_item(lua_State * L) static int tolua_unit_getskill(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - const char *skname = tolua_tostring(L, 2, 0); - skill_t sk = sk_find(skname); - int value = -1; - if (sk != NOSKILL) { skill *sv = get_skill(self, sk); - if (sv) { value = sv->level; } else @@ -417,13 +363,9 @@ static int tolua_unit_getskill(lua_State * L) static int tolua_unit_effskill(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - const char *skname = tolua_tostring(L, 2, 0); - skill_t sk = sk_find(skname); - int value = (sk == NOSKILL) ? -1 : eff_skill(self, sk, self->region); - lua_pushinteger(L, value); return 1; } @@ -443,9 +385,7 @@ int fctr_handle(struct trigger *tp, void *data) trigger *t = tp; event evt = { 0 }; fctr_data *fd = (fctr_data *) t->data.v; - lua_State *L = (lua_State *) global.vm_state; - unit *u = fd->target; evt.args = (event_arg *) data; @@ -454,7 +394,6 @@ int fctr_handle(struct trigger *tp, void *data) tolua_pushusertype(L, &evt, TOLUA_CAST "event"); if (lua_pcall(L, 2, 0, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("event (%s): %s\n", unitname(u), error)); lua_pop(L, 1); tolua_error(L, TOLUA_CAST "event handler call failed", NULL); @@ -471,9 +410,7 @@ static void fctr_init(trigger * t) static void fctr_done(trigger * t) { fctr_data *fd = (fctr_data *) t->data.v; - lua_State *L = (lua_State *) global.vm_state; - luaL_unref(L, LUA_REGISTRYINDEX, fd->fhandle); free(fd); } @@ -488,9 +425,7 @@ static struct trigger_type tt_lua = { static trigger *trigger_lua(struct unit *u, int handle) { trigger *t = t_new(&tt_lua); - fctr_data *td = (fctr_data *) t->data.v; - td->target = u; td->fhandle = handle; return t; @@ -499,9 +434,7 @@ static trigger *trigger_lua(struct unit *u, int handle) static int tolua_unit_addhandler(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - const char *ename = tolua_tostring(L, 2, 0); - int handle; lua_pushvalue(L, 3); @@ -514,7 +447,6 @@ static int tolua_unit_addhandler(lua_State * L) static int tolua_unit_addnotice(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - const char *str = tolua_tostring(L, 2, 0); addmessage(self->region, self->faction, str, MSG_MESSAGE, ML_IMPORTANT); @@ -524,15 +456,12 @@ static int tolua_unit_addnotice(lua_State * L) static void unit_castspell(unit * u, const char *name) { quicklist *ql = spells; - int qi; for (ql = spells, qi = 0; ql; ql_advance(&ql, &qi, 1)) { spell *sp = (spell *) ql_get(ql, qi); - if (strcmp(name, sp->sname) == 0) { castorder *co = (castorder *) malloc(sizeof(castorder)); - co->distance = 0; co->familiar = NULL; co->force = sp->level; @@ -556,9 +485,7 @@ static void unit_castspell(unit * u, const char *name) static int tolua_unit_castspell(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - const char *str = tolua_tostring(L, 2, 0); - unit_castspell(self, str); return 0; } @@ -566,7 +493,6 @@ static int tolua_unit_castspell(lua_State * L) static int unit_addspell(unit * u, const char *name) { sc_mage *m = get_mage(u); - spell *spadd = find_spell(m->magietyp, name); if (!spadd) { @@ -574,7 +500,6 @@ static int unit_addspell(unit * u, const char *name) return EINVAL; } else { quicklist **starget = get_spelllist(m, u->faction); - add_spell(starget, spadd); } return 0; @@ -583,11 +508,8 @@ static int unit_addspell(unit * u, const char *name) static int tolua_unit_addspell(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - const char *str = tolua_tostring(L, 2, 0); - int err = unit_addspell(self, str); - lua_pushinteger(L, err); return 1; } @@ -603,9 +525,7 @@ static void unit_removespell(unit * u, spell * sp) static int tolua_unit_removespell(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - spell *sp = (spell *) tolua_tousertype(L, 2, 0); - unit_removespell(self, sp); return 0; } @@ -613,7 +533,6 @@ static int tolua_unit_removespell(lua_State * L) static int tolua_unit_set_racename(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - const char *str = tolua_tostring(L, 2, 0); set_racename(&self->attribs, str); @@ -623,9 +542,7 @@ static int tolua_unit_set_racename(lua_State * L) static int tolua_unit_get_racename(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - attrib *a = a_find(self->attribs, &at_racename); - if (a) { tolua_pushstring(L, get_racename(a)); return 1; @@ -636,13 +553,9 @@ static int tolua_unit_get_racename(lua_State * L) static int tolua_unit_setskill(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - const char *skname = tolua_tostring(L, 2, 0); - int level = (int)tolua_tonumber(L, 3, 0); - skill_t sk = sk_find(skname); - if (sk != NOSKILL) { set_level(self, sk, level); } else { @@ -655,15 +568,10 @@ static int tolua_unit_setskill(lua_State * L) static int tolua_unit_use_pooled(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - const char *iname = tolua_tostring(L, 2, 0); - int number = (int)tolua_tonumber(L, 3, 0); - const resource_type *rtype = rt_find(iname); - int result = -1; - if (rtype != NULL) { result = use_pooled(self, rtype, GET_DEFAULT, number); } @@ -674,13 +582,9 @@ static int tolua_unit_use_pooled(lua_State * L) static int tolua_unit_get_pooled(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - const char *iname = tolua_tostring(L, 2, 0); - const resource_type *rtype = rt_find(iname); - int result = -1; - if (rtype != NULL) { result = get_pooled(self, rtype, GET_DEFAULT, INT_MAX); } @@ -691,7 +595,6 @@ static int tolua_unit_get_pooled(lua_State * L) static unit *unit_getfamiliar(const unit * u) { attrib *a = a_find(u->attribs, &at_familiar); - if (a != NULL) { return (unit *) a->data.v; } @@ -701,7 +604,6 @@ static unit *unit_getfamiliar(const unit * u) static int tolua_unit_get_familiar(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, unit_getfamiliar(self), TOLUA_CAST "unit"); return 1; } @@ -709,7 +611,6 @@ 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)); return 0; } @@ -717,7 +618,6 @@ static int tolua_unit_set_familiar(lua_State * L) static int tolua_unit_get_building(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, self->building, TOLUA_CAST "building"); return 1; } @@ -734,7 +634,6 @@ static void unit_setbuilding(unit * u, building * b) static int tolua_unit_set_building(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - if (self->faction) { unit_setbuilding(self, (building *) tolua_tousertype(L, 2, 0)); } @@ -744,7 +643,6 @@ static int tolua_unit_set_building(lua_State * L) static int tolua_unit_get_ship(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, self->ship, TOLUA_CAST "ship"); return 1; } @@ -761,7 +659,6 @@ static void unit_setship(unit * u, ship * s) static int tolua_unit_set_ship(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - if (self->faction) { unit_setship(self, (ship *) tolua_tousertype(L, 2, 0)); } @@ -771,7 +668,6 @@ static int tolua_unit_set_ship(lua_State * L) static int tolua_unit_get_region(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, self->region, TOLUA_CAST "region"); return 1; } @@ -784,7 +680,6 @@ static void unit_setregion(unit * u, region * r) static int tolua_unit_set_region(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - unit_setregion(self, (region *) tolua_tousertype(L, 2, 0)); return 0; } @@ -792,11 +687,8 @@ static int tolua_unit_set_region(lua_State * L) static int tolua_unit_add_order(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - const char *str = tolua_tostring(L, 2, 0); - order *ord = parse_order(str, self->faction->locale); - unit_addorder(self, ord); return 0; } @@ -804,7 +696,6 @@ static int tolua_unit_add_order(lua_State * L) static int tolua_unit_clear_orders(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - free_orders(&self->orders); return 0; } @@ -828,14 +719,11 @@ 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 = get_mage(self); - quicklist *slist = 0; if (mage) { quicklist **slist_ptr = get_spelllist(mage, self->faction); - if (slist_ptr) { slist = *slist_ptr; } @@ -863,13 +751,9 @@ static int tolua_unit_get_orders(lua_State * L) static int tolua_unit_get_flag(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); - int flag = atoi36(name); - attrib *a = find_key(self->attribs, flag); - lua_pushboolean(L, (a != NULL)); return 1; } @@ -877,15 +761,10 @@ static int tolua_unit_get_flag(lua_State * L) static int tolua_unit_set_flag(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); - int value = (int)tolua_tonumber(L, 3, 0); - int flag = atoi36(name); - attrib *a = find_key(self->attribs, flag); - if (a == NULL && value) { add_key(&self->attribs, flag); } else if (a != NULL && !value) { @@ -897,7 +776,6 @@ static int tolua_unit_set_flag(lua_State * L) static int tolua_unit_get_weight(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - lua_pushinteger(L, unit_getweight(self)); return 1; } @@ -905,7 +783,6 @@ static int tolua_unit_get_weight(lua_State * L) static int tolua_unit_get_capacity(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - lua_pushinteger(L, unit_getcapacity(self)); return 1; } @@ -913,7 +790,6 @@ static int tolua_unit_get_capacity(lua_State * L) static int tolua_unit_get_faction(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - tolua_pushusertype(L, (void *)self->faction, TOLUA_CAST "faction"); return 1; } @@ -921,9 +797,7 @@ static int tolua_unit_get_faction(lua_State * L) static int tolua_unit_set_faction(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - faction *f = (faction *) tolua_tousertype(L, 2, 0); - u_setfaction(self, f); return 0; } @@ -931,7 +805,6 @@ static int tolua_unit_set_faction(lua_State * L) static int tolua_unit_get_race(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->race->_name[0]); return 1; } @@ -939,11 +812,8 @@ static int tolua_unit_get_race(lua_State * L) static int tolua_unit_set_race(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - const char *rcname = tolua_tostring(L, 2, 0); - race *rc = rc_find(rcname); - if (rc != NULL) { if (count_unit(self)) --self->faction->no_units; @@ -959,7 +829,6 @@ static int tolua_unit_set_race(lua_State * L) static int tolua_unit_destroy(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - if (self) { remove_unit(&self->region->units, self); } @@ -969,21 +838,15 @@ static int tolua_unit_destroy(lua_State * L) static int tolua_unit_create(lua_State * L) { faction *f = (faction *) tolua_tousertype(L, 1, 0); - region *r = (region *) tolua_tousertype(L, 2, 0); - int num = (int)tolua_tonumber(L, 3, 1); - if (f && r) { const race *rc = f->race; - const char *rcname = tolua_tostring(L, 4, NULL); - if (rcname) rc = rc_find(rcname); if (rc) { unit *u = create_unit(r, f, num, rc, 0, NULL, NULL); - tolua_pushusertype(L, u, TOLUA_CAST "unit"); return 1; } @@ -994,7 +857,6 @@ static int tolua_unit_create(lua_State * L) static int tolua_unit_tostring(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - lua_pushstring(L, unitname(self)); return 1; } @@ -1002,9 +864,7 @@ static int tolua_unit_tostring(lua_State * L) static int tolua_event_gettype(lua_State * L) { event *self = (event *) tolua_tousertype(L, 1, 0); - int index = (int)tolua_tonumber(L, 2, 0); - lua_pushstring(L, self->args[index].type); return 1; } @@ -1012,7 +872,6 @@ static int tolua_event_gettype(lua_State * L) static int tolua_event_get(lua_State * L) { struct event *self = (struct event *)tolua_tousertype(L, 1, 0); - int index = (int)tolua_tonumber(L, 2, 0); event_arg *arg = self->args + index; diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index 881e55273..4b0ea958e 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -1,1398 +1,1155 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include "bindings.h" -#include "bind_unit.h" -#include "bind_faction.h" -#include "bind_region.h" -#include "helpers.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -int log_lua_error(lua_State * L) +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bindings.h" +#include "bind_unit.h" +#include "bind_faction.h" +#include "bind_region.h" +#include "helpers.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + int log_lua_error(lua_State * L) { - const char *error = lua_tostring(L, -1); + const char *error = lua_tostring(L, -1); + log_error(("LUA call failed.\n%s\n", error)); + lua_pop(L, 1); + return 1; + } - log_error(("LUA call failed.\n%s\n", error)); - lua_pop(L, 1); - - return 1; -} - -int tolua_orderlist_next(lua_State * L) + int tolua_orderlist_next(lua_State * L) { - order **order_ptr = (order **) lua_touserdata(L, lua_upvalueindex(1)); - - order *ord = *order_ptr; - - if (ord != NULL) { - char cmd[8192]; - - write_order(ord, cmd, sizeof(cmd)); - tolua_pushstring(L, cmd); - *order_ptr = ord->next; - return 1; - } else + order ** order_ptr = (order **) lua_touserdata(L, lua_upvalueindex(1)); + order * ord = *order_ptr; + if (ord != NULL) { + char cmd[8192]; + write_order(ord, cmd, sizeof(cmd)); + tolua_pushstring(L, cmd); + *order_ptr = ord->next; + return 1; + } + + else return 0; /* no more values to return */ -} + } -static int tolua_quicklist_iter(lua_State * L) + static int tolua_quicklist_iter(lua_State * L) { - quicklist **qlp = (quicklist **) lua_touserdata(L, lua_upvalueindex(1)); - - quicklist *ql = *qlp; - - if (ql != NULL) { - int index = lua_tointeger(L, lua_upvalueindex(2)); - - const char *type = lua_tostring(L, lua_upvalueindex(3)); - - void *data = ql_get(ql, index); - - tolua_pushusertype(L, data, TOLUA_CAST type); - ql_advance(qlp, &index, 1); - - tolua_pushnumber(L, index); - lua_replace(L, lua_upvalueindex(2)); - return 1; - } else + quicklist ** qlp = (quicklist **) lua_touserdata(L, lua_upvalueindex(1)); + quicklist * ql = *qlp; + if (ql != NULL) { + int index = lua_tointeger(L, lua_upvalueindex(2)); + const char *type = lua_tostring(L, lua_upvalueindex(3)); + void *data = ql_get(ql, index); + tolua_pushusertype(L, data, TOLUA_CAST type); + ql_advance(qlp, &index, 1); + tolua_pushnumber(L, index); + lua_replace(L, lua_upvalueindex(2)); + return 1; + } + + else return 0; /* no more values to return */ -} + } -int tolua_quicklist_push(struct lua_State *L, const char *list_type, - const char *elem_type, struct quicklist *list) + int tolua_quicklist_push(struct lua_State *L, const char *list_type, + const char *elem_type, struct quicklist *list) { - if (list) { - quicklist **qlist_ptr = + if (list) { + quicklist ** qlist_ptr = (quicklist **) lua_newuserdata(L, sizeof(quicklist *)); - *qlist_ptr = list; + *qlist_ptr = list; + luaL_getmetatable(L, list_type); + lua_setmetatable(L, -2); + lua_pushnumber(L, 0); + lua_pushstring(L, elem_type); + lua_pushcclosure(L, tolua_quicklist_iter, 3); /* OBS: this closure has multiple upvalues (list, index, type_name) */ + } else { + lua_pushnil(L); + } + return 1; + } - luaL_getmetatable(L, list_type); - lua_setmetatable(L, -2); - lua_pushnumber(L, 0); - lua_pushstring(L, elem_type); - lua_pushcclosure(L, tolua_quicklist_iter, 3); /* OBS: this closure has multiple upvalues (list, index, type_name) */ - } else { - lua_pushnil(L); - } - return 1; -} - -int tolua_itemlist_next(lua_State * L) + int tolua_itemlist_next(lua_State * L) { - item **item_ptr = (item **) lua_touserdata(L, lua_upvalueindex(1)); - - item *itm = *item_ptr; - - if (itm != NULL) { - tolua_pushstring(L, itm->type->rtype->_name[0]); - *item_ptr = itm->next; - return 1; - } else + item ** item_ptr = (item **) lua_touserdata(L, lua_upvalueindex(1)); + item * itm = *item_ptr; + if (itm != NULL) { + tolua_pushstring(L, itm->type->rtype->_name[0]); + *item_ptr = itm->next; + return 1; + } + + else return 0; /* no more values to return */ -} + } -static int tolua_autoseed(lua_State * L) + static int tolua_autoseed(lua_State * L) { - const char *filename = tolua_tostring(L, 1, 0); + const char *filename = tolua_tostring(L, 1, 0); + int new_island = tolua_toboolean(L, 2, 0); + newfaction * players = read_newfactions(filename); + if (players != NULL) { + while (players) { + int n = listlen(players); + int k = (n + ISLANDSIZE - 1) / ISLANDSIZE; + k = n / k; + n = autoseed(&players, k, new_island ? 0 : TURNS_PER_ISLAND); + if (n == 0) { + break; + } + } + } + return 0; + } - int new_island = tolua_toboolean(L, 2, 0); - - newfaction *players = read_newfactions(filename); - - if (players != NULL) { - while (players) { - int n = listlen(players); - - int k = (n + ISLANDSIZE - 1) / ISLANDSIZE; - - k = n / k; - n = autoseed(&players, k, new_island ? 0 : TURNS_PER_ISLAND); - if (n == 0) { - break; - } - } - } - return 0; -} - - -static int tolua_getkey(lua_State * L) + static int tolua_getkey(lua_State * L) { - const char *name = tolua_tostring(L, 1, 0); + const char *name = tolua_tostring(L, 1, 0); + int flag = atoi36(name); + attrib * a = find_key(global.attribs, flag); + lua_pushboolean(L, a != NULL); + return 1; + } - int flag = atoi36(name); - - attrib *a = find_key(global.attribs, flag); - - lua_pushboolean(L, a != NULL); - - return 1; -} - -static int tolua_translate(lua_State * L) + static int tolua_translate(lua_State * L) { - const char *str = tolua_tostring(L, 1, 0); + const char *str = tolua_tostring(L, 1, 0); + const char *lang = tolua_tostring(L, 2, 0); + struct locale *loc = lang ? find_locale(lang) : default_locale; + if (loc) { + str = locale_string(loc, str); + tolua_pushstring(L, str); + return 1; + } + return 0; + } - const char *lang = tolua_tostring(L, 2, 0); - - struct locale *loc = lang ? find_locale(lang) : default_locale; - - if (loc) { - str = locale_string(loc, str); - tolua_pushstring(L, str); - return 1; - } - return 0; -} - -static int tolua_setkey(lua_State * L) + static int tolua_setkey(lua_State * L) { - const char *name = tolua_tostring(L, 1, 0); + const char *name = tolua_tostring(L, 1, 0); + int value = tolua_toboolean(L, 2, 0); + int flag = atoi36(name); + attrib * a = find_key(global.attribs, flag); + if (a == NULL && value) { + add_key(&global.attribs, flag); + } else if (a != NULL && !value) { + a_remove(&global.attribs, a); + } + return 0; + } - int value = tolua_toboolean(L, 2, 0); - - int flag = atoi36(name); - - attrib *a = find_key(global.attribs, flag); - - if (a == NULL && value) { - add_key(&global.attribs, flag); - } else if (a != NULL && !value) { - a_remove(&global.attribs, a); - } - - return 0; -} - -static int tolua_rng_int(lua_State * L) + static int tolua_rng_int(lua_State * L) { - lua_pushnumber(L, (lua_Number) rng_int()); - return 1; -} + lua_pushnumber(L, (lua_Number) rng_int()); + return 1; + } -static int tolua_read_orders(lua_State * L) + static int tolua_read_orders(lua_State * L) { - const char *filename = tolua_tostring(L, 1, 0); + const char *filename = tolua_tostring(L, 1, 0); + int result = readorders(filename); + lua_pushnumber(L, (lua_Number) result); + return 1; + } - int result = readorders(filename); - - lua_pushnumber(L, (lua_Number) result); - return 1; -} - -static int tolua_message_unit(lua_State * L) + static int tolua_message_unit(lua_State * L) { - unit *sender = (unit *) tolua_tousertype(L, 1, 0); - - unit *target = (unit *) tolua_tousertype(L, 2, 0); - - const char *str = tolua_tostring(L, 3, 0); - - if (!target) + unit * sender = (unit *) tolua_tousertype(L, 1, 0); + unit * target = (unit *) tolua_tousertype(L, 2, 0); + const char *str = tolua_tostring(L, 3, 0); + if (!target) tolua_error(L, TOLUA_CAST "target is nil", NULL); - if (!sender) + if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); - deliverMail(target->faction, sender->region, sender, str, target); - return 0; -} + deliverMail(target->faction, sender->region, sender, str, target); + return 0; + } -static int tolua_message_faction(lua_State * L) + static int tolua_message_faction(lua_State * L) { - unit *sender = (unit *) tolua_tousertype(L, 1, 0); - - faction *target = (faction *) tolua_tousertype(L, 2, 0); - - const char *str = tolua_tostring(L, 3, 0); - - if (!target) + unit * sender = (unit *) tolua_tousertype(L, 1, 0); + faction * target = (faction *) tolua_tousertype(L, 2, 0); + const char *str = tolua_tostring(L, 3, 0); + if (!target) tolua_error(L, TOLUA_CAST "target is nil", NULL); - if (!sender) + if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); + deliverMail(target, sender->region, sender, str, NULL); + return 0; + } - deliverMail(target, sender->region, sender, str, NULL); - return 0; -} - -static int tolua_message_region(lua_State * L) + static int tolua_message_region(lua_State * L) { - unit *sender = (unit *) tolua_tousertype(L, 1, 0); - - const char *str = tolua_tostring(L, 2, 0); - - if (!sender) + unit * sender = (unit *) tolua_tousertype(L, 1, 0); + const char *str = tolua_tostring(L, 2, 0); + if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); - ADDMSG(&sender->region->msgs, msg_message("mail_result", "unit message", + ADDMSG(&sender->region->msgs, msg_message("mail_result", "unit message", sender, str)); + return 0; + } - return 0; -} - -static int tolua_update_guards(lua_State * L) + static int tolua_update_guards(lua_State * L) { - update_guards(); - return 0; -} + update_guards(); + return 0; + } -static int tolua_set_turn(lua_State * L) + static int tolua_set_turn(lua_State * L) { - turn = (int)tolua_tonumber(L, 1, 0); - return 0; -} + turn = (int)tolua_tonumber(L, 1, 0); + return 0; + } -static int tolua_get_turn(lua_State * L) + static int tolua_get_turn(lua_State * L) { - tolua_pushnumber(L, (lua_Number) turn); - return 1; -} + tolua_pushnumber(L, (lua_Number) turn); + return 1; + } -static int tolua_atoi36(lua_State * L) + static int tolua_atoi36(lua_State * L) { - const char *s = tolua_tostring(L, 1, 0); + const char *s = tolua_tostring(L, 1, 0); + tolua_pushnumber(L, (lua_Number) atoi36(s)); + return 1; + } - tolua_pushnumber(L, (lua_Number) atoi36(s)); - return 1; -} - -static int tolua_itoa36(lua_State * L) + static int tolua_itoa36(lua_State * L) { - int i = (int)tolua_tonumber(L, 1, 0); + int i = (int)tolua_tonumber(L, 1, 0); + tolua_pushstring(L, itoa36(i)); + return 1; + } - tolua_pushstring(L, itoa36(i)); - return 1; -} - -static int tolua_dice_rand(lua_State * L) + static int tolua_dice_rand(lua_State * L) { - const char *s = tolua_tostring(L, 1, 0); + const char *s = tolua_tostring(L, 1, 0); + tolua_pushnumber(L, dice_rand(s)); + return 1; + } - tolua_pushnumber(L, dice_rand(s)); - return 1; -} - -static int tolua_addequipment(lua_State * L) + static int tolua_addequipment(lua_State * L) { - const char *eqname = tolua_tostring(L, 1, 0); + const char *eqname = tolua_tostring(L, 1, 0); + const char *iname = tolua_tostring(L, 2, 0); + const char *value = tolua_tostring(L, 3, 0); + int result = -1; + if (iname != NULL) { + const struct item_type *itype = it_find(iname); + if (itype != NULL) { + equipment_setitem(create_equipment(eqname), itype, value); + result = 0; + } + } + lua_pushnumber(L, (lua_Number) result); + return 1; + } - const char *iname = tolua_tostring(L, 2, 0); - - const char *value = tolua_tostring(L, 3, 0); - - int result = -1; - - if (iname != NULL) { - const struct item_type *itype = it_find(iname); - - if (itype != NULL) { - equipment_setitem(create_equipment(eqname), itype, value); - result = 0; - } - } - lua_pushnumber(L, (lua_Number) result); - return 1; -} - -static int tolua_get_season(lua_State * L) + static int tolua_get_season(lua_State * L) { - int turnno = (int)tolua_tonumber(L, 1, 0); + int turnno = (int)tolua_tonumber(L, 1, 0); + gamedate gd; + get_gamedate(turnno, &gd); + tolua_pushstring(L, seasonnames[gd.season]); + return 1; + } - gamedate gd; - - get_gamedate(turnno, &gd); - tolua_pushstring(L, seasonnames[gd.season]); - return 1; -} - -static int tolua_create_curse(lua_State * L) + static int tolua_create_curse(lua_State * L) { - unit *u = (unit *) tolua_tousertype(L, 1, 0); - - tolua_Error tolua_err; - - attrib **ap = NULL; - - if (tolua_isusertype(L, 2, TOLUA_CAST "unit", 0, &tolua_err)) { - unit *target = (unit *) tolua_tousertype(L, 2, 0); - - if (target) + unit * u = (unit *) tolua_tousertype(L, 1, 0); + tolua_Error tolua_err; + attrib ** ap = NULL; + if (tolua_isusertype(L, 2, TOLUA_CAST "unit", 0, &tolua_err)) { + unit * target = (unit *) tolua_tousertype(L, 2, 0); + if (target) ap = &target->attribs; - } else if (tolua_isusertype(L, 2, TOLUA_CAST "region", 0, &tolua_err)) { - region *target = (region *) tolua_tousertype(L, 2, 0); - - if (target) + } else if (tolua_isusertype(L, 2, TOLUA_CAST "region", 0, &tolua_err)) { + region * target = (region *) tolua_tousertype(L, 2, 0); + if (target) ap = &target->attribs; - } else if (tolua_isusertype(L, 2, TOLUA_CAST "ship", 0, &tolua_err)) { - ship *target = (ship *) tolua_tousertype(L, 2, 0); - - if (target) + } else if (tolua_isusertype(L, 2, TOLUA_CAST "ship", 0, &tolua_err)) { + ship * target = (ship *) tolua_tousertype(L, 2, 0); + if (target) ap = &target->attribs; - } else if (tolua_isusertype(L, 2, TOLUA_CAST "building", 0, &tolua_err)) { - building *target = (building *) tolua_tousertype(L, 2, 0); - - if (target) + } else if (tolua_isusertype(L, 2, TOLUA_CAST "building", 0, &tolua_err)) { + building * target = (building *) tolua_tousertype(L, 2, 0); + if (target) ap = &target->attribs; - } - if (ap) { - const char *cname = tolua_tostring(L, 3, 0); + } + if (ap) { + const char *cname = tolua_tostring(L, 3, 0); + const curse_type *ctype = ct_find(cname); + if (ctype) { + double vigour = tolua_tonumber(L, 4, 0); + int duration = (int)tolua_tonumber(L, 5, 0); + double effect = tolua_tonumber(L, 6, 0); + int men = (int)tolua_tonumber(L, 7, 0); /* optional */ + curse * c = create_curse(u, ap, ctype, vigour, duration, effect, men); + if (c) { + tolua_pushboolean(L, true); + return 1; + } + } + } + tolua_pushboolean(L, false); + return 1; + } - const curse_type *ctype = ct_find(cname); - - if (ctype) { - double vigour = tolua_tonumber(L, 4, 0); - - int duration = (int)tolua_tonumber(L, 5, 0); - - double effect = tolua_tonumber(L, 6, 0); - - int men = (int)tolua_tonumber(L, 7, 0); /* optional */ - - curse *c = create_curse(u, ap, ctype, vigour, duration, effect, men); - - if (c) { - tolua_pushboolean(L, true); - return 1; - } - } - } - tolua_pushboolean(L, false); - return 1; -} - -static int tolua_learn_skill(lua_State * L) + static int tolua_learn_skill(lua_State * L) { - unit *u = (unit *) tolua_tousertype(L, 1, 0); + unit * u = (unit *) tolua_tousertype(L, 1, 0); + const char *skname = tolua_tostring(L, 2, 0); + float chances = (float)tolua_tonumber(L, 3, 0); + skill_t sk = sk_find(skname); + if (sk != NOSKILL) { + learn_skill(u, sk, chances); + } + return 0; + } - const char *skname = tolua_tostring(L, 2, 0); - - float chances = (float)tolua_tonumber(L, 3, 0); - - skill_t sk = sk_find(skname); - - if (sk != NOSKILL) { - learn_skill(u, sk, chances); - } - return 0; -} - -static int tolua_update_scores(lua_State * L) + static int tolua_update_scores(lua_State * L) { - score(); - return 0; -} + score(); + return 0; + } -static int tolua_update_owners(lua_State * L) + static int tolua_update_owners(lua_State * L) { - region *r; + region * r; + for (r = regions; r; r = r->next) { + update_owners(r); + } + return 0; + } - for (r = regions; r; r = r->next) { - update_owners(r); - } - return 0; -} - -static int tolua_update_subscriptions(lua_State * L) + static int tolua_update_subscriptions(lua_State * L) { - update_subscriptions(); - return 0; -} + update_subscriptions(); + return 0; + } -static int tolua_remove_empty_units(lua_State * L) + static int tolua_remove_empty_units(lua_State * L) { - remove_empty_units(); - return 0; -} + remove_empty_units(); + return 0; + } -static int tolua_get_nmrs(lua_State * L) + static int tolua_get_nmrs(lua_State * L) { - int result = -1; + int result = -1; + int n = (int)tolua_tonumber(L, 1, 0); + if (n >= 0 && n <= NMRTimeout()) { + if (nmrs == NULL) { + update_nmrs(); + } + result = nmrs[n]; + } + tolua_pushnumber(L, (lua_Number) result); + return 1; + } - int n = (int)tolua_tonumber(L, 1, 0); - - if (n >= 0 && n <= NMRTimeout()) { - if (nmrs == NULL) { - update_nmrs(); - } - result = nmrs[n]; - } - tolua_pushnumber(L, (lua_Number) result); - return 1; -} - -static int tolua_equipunit(lua_State * L) + static int tolua_equipunit(lua_State * L) { - unit *u = (unit *) tolua_tousertype(L, 1, 0); + unit * u = (unit *) tolua_tousertype(L, 1, 0); + const char *eqname = tolua_tostring(L, 2, 0); + equip_unit(u, get_equipment(eqname)); + return 0; + } - const char *eqname = tolua_tostring(L, 2, 0); - - equip_unit(u, get_equipment(eqname)); - - return 0; -} - -static int tolua_equipment_setitem(lua_State * L) + static int tolua_equipment_setitem(lua_State * L) { - int result = -1; + int result = -1; + const char *eqname = tolua_tostring(L, 1, 0); + const char *iname = tolua_tostring(L, 2, 0); + const char *value = tolua_tostring(L, 3, 0); + if (iname != NULL) { + const struct item_type *itype = it_find(iname); + if (itype != NULL) { + equipment_setitem(create_equipment(eqname), itype, value); + result = 0; + } + } + tolua_pushnumber(L, (lua_Number) result); + return 1; + } - const char *eqname = tolua_tostring(L, 1, 0); - - const char *iname = tolua_tostring(L, 2, 0); - - const char *value = tolua_tostring(L, 3, 0); - - if (iname != NULL) { - const struct item_type *itype = it_find(iname); - - if (itype != NULL) { - equipment_setitem(create_equipment(eqname), itype, value); - result = 0; - } - } - tolua_pushnumber(L, (lua_Number) result); - return 1; -} - -#ifdef TODO_FOSS -static int tolua_levitate_ship(lua_State * L) + +#ifdef TODO_FOSS +static int tolua_levitate_ship(lua_State * L) { - ship *sh = (ship *) tolua_tousertype(L, 1, 0); + ship * sh = (ship *) tolua_tousertype(L, 1, 0); + unit * mage = (unit *) tolua_tousertype(L, 2, 0); + double power = (double)tolua_tonumber(L, 3, 0); + int duration = (int)tolua_tonumber(L, 4, 0); + int cno = levitate_ship(sh, mage, power, duration); + tolua_pushnumber(L, (lua_Number) cno); + return 1; + } - unit *mage = (unit *) tolua_tousertype(L, 2, 0); - - double power = (double)tolua_tonumber(L, 3, 0); - - int duration = (int)tolua_tonumber(L, 4, 0); - - int cno = levitate_ship(sh, mage, power, duration); - - tolua_pushnumber(L, (lua_Number) cno); - return 1; -} -#endif - -static int tolua_spawn_braineaters(lua_State * L) + +#endif /* */ + static int tolua_spawn_braineaters(lua_State * L) { - float chance = (float)tolua_tonumber(L, 1, 0); + float chance = (float)tolua_tonumber(L, 1, 0); + spawn_braineaters(chance); + return 0; + } - spawn_braineaters(chance); - return 0; -} - -static int tolua_init_reports(lua_State * L) + static int tolua_init_reports(lua_State * L) { - int result = init_reports(); + int result = init_reports(); + tolua_pushnumber(L, (lua_Number) result); + return 1; + } - tolua_pushnumber(L, (lua_Number) result); - return 1; -} - -static int tolua_write_report(lua_State * L) + static int tolua_write_report(lua_State * L) { - faction *f = (faction *) tolua_tousertype(L, 1, 0); + faction * f = (faction *) tolua_tousertype(L, 1, 0); + time_t ltime = time(0); + int result = write_reports(f, ltime); + tolua_pushnumber(L, (lua_Number) result); + return 1; + } - time_t ltime = time(0); - - int result = write_reports(f, ltime); - - tolua_pushnumber(L, (lua_Number) result); - return 1; -} - -static int tolua_write_reports(lua_State * L) + static int tolua_write_reports(lua_State * L) { - int result; + int result; + init_reports(); + result = reports(); + tolua_pushnumber(L, (lua_Number) result); + return 1; + } - init_reports(); - result = reports(); - tolua_pushnumber(L, (lua_Number) result); - return 1; -} - -static void reset_game(void) + static void reset_game(void) { - region *r; + region * r; + faction * f; + for (r = regions; r; r = r->next) { + unit * u; + building * b; + r->flags &= RF_SAVEMASK; + for (u = r->units; u; u = u->next) { + u->flags &= UFL_SAVEMASK; + } + for (b = r->buildings; b; b = b->next) { + b->flags &= BLD_SAVEMASK; + } + if (r->land && r->land->ownership && r->land->ownership->owner) { + faction * owner = r->land->ownership->owner; + if (owner == get_monsters()) { + + /* some compat-fix, i believe. */ + owner = update_owners(r); + } + if (owner) { + fset(r, RF_GUARDED); + } + } + } + for (f = factions; f; f = f->next) { + f->flags &= FFL_SAVEMASK; + } + } - faction *f; - - for (r = regions; r; r = r->next) { - unit *u; - - building *b; - - r->flags &= RF_SAVEMASK; - for (u = r->units; u; u = u->next) { - u->flags &= UFL_SAVEMASK; - } - for (b = r->buildings; b; b = b->next) { - b->flags &= BLD_SAVEMASK; - } - - if (r->land && r->land->ownership && r->land->ownership->owner) { - faction *owner = r->land->ownership->owner; - - if (owner == get_monsters()) { - /* some compat-fix, i believe. */ - owner = update_owners(r); - } - if (owner) { - fset(r, RF_GUARDED); - } - } - } - for (f = factions; f; f = f->next) { - f->flags &= FFL_SAVEMASK; - } -} - -static int tolua_process_orders(lua_State * L) + static int tolua_process_orders(lua_State * L) { - ++turn; - reset_game(); - processorders(); - return 0; -} + ++turn; + reset_game(); + processorders(); + return 0; + } -static int tolua_write_passwords(lua_State * L) + static int tolua_write_passwords(lua_State * L) { - int result = writepasswd(); + int result = writepasswd(); + lua_pushnumber(L, (lua_Number) result); + return 0; + } - lua_pushnumber(L, (lua_Number) result); - return 0; -} - -static struct summary *sum_begin = 0; - -static int tolua_init_summary(lua_State * L) + static struct summary *sum_begin = 0; + static int tolua_init_summary(lua_State * L) { - sum_begin = make_summary(); - return 0; -} + sum_begin = make_summary(); + return 0; + } -static int tolua_write_summary(lua_State * L) + static int tolua_write_summary(lua_State * L) { - if (sum_begin) { - struct summary *sum_end = make_summary(); + if (sum_begin) { + struct summary *sum_end = make_summary(); + report_summary(sum_end, sum_begin, false); + report_summary(sum_end, sum_begin, true); + return 0; + } + return 0; + } - report_summary(sum_end, sum_begin, false); - report_summary(sum_end, sum_begin, true); - return 0; - } - return 0; -} - -static int tolua_free_game(lua_State * L) + static int tolua_free_game(lua_State * L) { - free_gamedata(); - return 0; -} + free_gamedata(); + return 0; + } -static int tolua_write_map(lua_State * L) + static int tolua_write_map(lua_State * L) { - const char *filename = tolua_tostring(L, 1, 0); + const char *filename = tolua_tostring(L, 1, 0); + if (filename) { + crwritemap(filename); + } + return 0; + } - if (filename) { - crwritemap(filename); - } - return 0; -} - -static int tolua_write_game(lua_State * L) + static int tolua_write_game(lua_State * L) { - const char *filename = tolua_tostring(L, 1, 0); - - const char *mode = tolua_tostring(L, 2, 0); - - int result, m = IO_BINARY; - - if (mode && strcmp(mode, "text") == 0) + const char *filename = tolua_tostring(L, 1, 0); + const char *mode = tolua_tostring(L, 2, 0); + int result, m = IO_BINARY; + if (mode && strcmp(mode, "text") == 0) m = IO_TEXT; - remove_empty_factions(); - result = writegame(filename, m); + remove_empty_factions(); + result = writegame(filename, m); + tolua_pushnumber(L, (lua_Number) result); + return 1; + } - tolua_pushnumber(L, (lua_Number) result); - return 1; -} - -static int tolua_read_game(lua_State * L) + static int tolua_read_game(lua_State * L) { - const char *filename = tolua_tostring(L, 1, 0); - - const char *mode = tolua_tostring(L, 2, 0); - - int rv, m = IO_BINARY; - - if (mode && strcmp(mode, "text") == 0) + const char *filename = tolua_tostring(L, 1, 0); + const char *mode = tolua_tostring(L, 2, 0); + int rv, m = IO_BINARY; + if (mode && strcmp(mode, "text") == 0) m = IO_TEXT; - rv = readgame(filename, m, false); + rv = readgame(filename, m, false); + tolua_pushnumber(L, (lua_Number) rv); + return 1; + } - tolua_pushnumber(L, (lua_Number) rv); - return 1; -} - -static int tolua_read_turn(lua_State * L) + static int tolua_read_turn(lua_State * L) { - int cturn = current_turn(); + int cturn = current_turn(); + tolua_pushnumber(L, (lua_Number) cturn); + return 1; + } - tolua_pushnumber(L, (lua_Number) cturn); - return 1; -} - -static int tolua_get_faction(lua_State * L) + static int tolua_get_faction(lua_State * L) { - int no = tolua_toid(L, 1, 0); + int no = tolua_toid(L, 1, 0); + faction * f = findfaction(no); + tolua_pushusertype(L, f, TOLUA_CAST "faction"); + return 1; + } - faction *f = findfaction(no); - - tolua_pushusertype(L, f, TOLUA_CAST "faction"); - return 1; -} - -static int tolua_get_region(lua_State * L) + static int tolua_get_region(lua_State * L) { - int x = (int)tolua_tonumber(L, 1, 0); + int x = (int)tolua_tonumber(L, 1, 0); + int y = (int)tolua_tonumber(L, 2, 0); + region * r; + assert(!pnormalize(&x, &y, findplane(x, y))); + r = findregion(x, y); + tolua_pushusertype(L, r, TOLUA_CAST "region"); + return 1; + } - int y = (int)tolua_tonumber(L, 2, 0); - - region *r; - - assert(!pnormalize(&x, &y, findplane(x, y))); - r = findregion(x, y); - - tolua_pushusertype(L, r, TOLUA_CAST "region"); - return 1; -} - -static int tolua_get_region_byid(lua_State * L) + static int tolua_get_region_byid(lua_State * L) { - int uid = (int)tolua_tonumber(L, 1, 0); + int uid = (int)tolua_tonumber(L, 1, 0); + region * r = findregionbyid(uid); + tolua_pushusertype(L, r, TOLUA_CAST "region"); + return 1; + } - region *r = findregionbyid(uid); - - tolua_pushusertype(L, r, TOLUA_CAST "region"); - return 1; -} - -static int tolua_get_building(lua_State * L) + static int tolua_get_building(lua_State * L) { - int no = tolua_toid(L, 1, 0); + int no = tolua_toid(L, 1, 0); + building * b = findbuilding(no); + tolua_pushusertype(L, b, TOLUA_CAST "building"); + return 1; + } - building *b = findbuilding(no); - - tolua_pushusertype(L, b, TOLUA_CAST "building"); - return 1; -} - -static int tolua_get_ship(lua_State * L) + static int tolua_get_ship(lua_State * L) { - int no = tolua_toid(L, 1, 0); + int no = tolua_toid(L, 1, 0); + ship * sh = findship(no); + tolua_pushusertype(L, sh, TOLUA_CAST "ship"); + return 1; + } - ship *sh = findship(no); - - tolua_pushusertype(L, sh, TOLUA_CAST "ship"); - return 1; -} - -static int tolua_get_alliance(lua_State * L) + static int tolua_get_alliance(lua_State * L) { - int no = tolua_toid(L, 1, 0); + int no = tolua_toid(L, 1, 0); + alliance * f = findalliance(no); + tolua_pushusertype(L, f, TOLUA_CAST "alliance"); + return 1; + } - alliance *f = findalliance(no); - - tolua_pushusertype(L, f, TOLUA_CAST "alliance"); - return 1; -} - -static int tolua_get_unit(lua_State * L) + static int tolua_get_unit(lua_State * L) { - int no = tolua_toid(L, 1, 0); + int no = tolua_toid(L, 1, 0); + unit * u = findunit(no); + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + return 1; + } - unit *u = findunit(no); - - tolua_pushusertype(L, u, TOLUA_CAST "unit"); - return 1; -} - -static int tolua_alliance_create(lua_State * L) + static int tolua_alliance_create(lua_State * L) { - int id = (int)tolua_tonumber(L, 1, 0); + int id = (int)tolua_tonumber(L, 1, 0); + const char *name = tolua_tostring(L, 2, 0); + alliance * alli = makealliance(id, name); + tolua_pushusertype(L, alli, TOLUA_CAST "alliance"); + return 1; + } - const char *name = tolua_tostring(L, 2, 0); - - alliance *alli = makealliance(id, name); - - tolua_pushusertype(L, alli, TOLUA_CAST "alliance"); - return 1; -} - -static int tolua_get_regions(lua_State * L) + static int tolua_get_regions(lua_State * L) { - region **region_ptr = (region **) lua_newuserdata(L, sizeof(region *)); + region ** region_ptr = (region **) lua_newuserdata(L, sizeof(region *)); + luaL_getmetatable(L, "region"); + lua_setmetatable(L, -2); + *region_ptr = regions; + lua_pushcclosure(L, tolua_regionlist_next, 1); + return 1; + } - luaL_getmetatable(L, "region"); - lua_setmetatable(L, -2); - - *region_ptr = regions; - - lua_pushcclosure(L, tolua_regionlist_next, 1); - return 1; -} - -static int tolua_get_factions(lua_State * L) + static int tolua_get_factions(lua_State * L) { - faction **faction_ptr = (faction **) lua_newuserdata(L, sizeof(faction *)); + faction ** faction_ptr = (faction **) lua_newuserdata(L, sizeof(faction *)); + luaL_getmetatable(L, "faction"); + lua_setmetatable(L, -2); + *faction_ptr = factions; + lua_pushcclosure(L, tolua_factionlist_next, 1); + return 1; + } - luaL_getmetatable(L, "faction"); - lua_setmetatable(L, -2); - - *faction_ptr = factions; - - lua_pushcclosure(L, tolua_factionlist_next, 1); - return 1; -} - -static int tolua_get_alliance_factions(lua_State * L) + static int tolua_get_alliance_factions(lua_State * L) { - alliance *self = (alliance *) tolua_tousertype(L, 1, 0); + alliance * self = (alliance *) tolua_tousertype(L, 1, 0); + return tolua_quicklist_push(L, "faction_list", "faction", self->members); + } - return tolua_quicklist_push(L, "faction_list", "faction", self->members); -} - -static int tolua_get_alliance_id(lua_State * L) + static int tolua_get_alliance_id(lua_State * L) { - alliance *self = (alliance *) tolua_tousertype(L, 1, 0); + alliance * self = (alliance *) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number) self->id); + return 1; + } - tolua_pushnumber(L, (lua_Number) self->id); - return 1; -} - -static int tolua_get_alliance_name(lua_State * L) + static int tolua_get_alliance_name(lua_State * L) { - alliance *self = (alliance *) tolua_tousertype(L, 1, 0); + alliance * self = (alliance *) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->name); + return 1; + } - tolua_pushstring(L, self->name); - return 1; -} - -static int tolua_set_alliance_name(lua_State * L) + static int tolua_set_alliance_name(lua_State * L) { - alliance *self = (alliance *) tolua_tousertype(L, 1, 0); + alliance * self = (alliance *) tolua_tousertype(L, 1, 0); + alliance_setname(self, tolua_tostring(L, 2, 0)); + return 0; + } - alliance_setname(self, tolua_tostring(L, 2, 0)); - return 0; -} - -#include -#include -#include -#include - -static int tolua_write_spells(lua_State * L) + +#include +#include +#include +#include + static int tolua_write_spells(lua_State * L) { - spell_f fun = (spell_f) get_function("lua_castspell"); - - const char *filename = "magic.xml"; - - xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); - - xmlNodePtr root = xmlNewNode(NULL, BAD_CAST "spells"); - - quicklist *ql; - - int qi; - - for (ql = spells, qi = 0; ql; ql_advance(&ql, &qi, 1)) { - spell *sp = (spell *) ql_get(ql, qi); - - if (sp->sp_function != fun) { - int combat = 0; - - xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "spell"); - - xmlNewProp(node, BAD_CAST "name", BAD_CAST sp->sname); - xmlNewProp(node, BAD_CAST "type", BAD_CAST magic_school[sp->magietyp]); - xmlNewProp(node, BAD_CAST "rank", xml_i(sp->rank)); - xmlNewProp(node, BAD_CAST "level", xml_i(sp->level)); - xmlNewProp(node, BAD_CAST "index", xml_i(sp->id)); - if (sp->syntax) + spell_f fun = (spell_f) get_function("lua_castspell"); + const char *filename = "magic.xml"; + xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); + xmlNodePtr root = xmlNewNode(NULL, BAD_CAST "spells"); + quicklist * ql; + int qi; + for (ql = spells, qi = 0; ql; ql_advance(&ql, &qi, 1)) { + spell * sp = (spell *) ql_get(ql, qi); + if (sp->sp_function != fun) { + int combat = 0; + xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "spell"); + xmlNewProp(node, BAD_CAST "name", BAD_CAST sp->sname); + xmlNewProp(node, BAD_CAST "type", BAD_CAST magic_school[sp->magietyp]); + xmlNewProp(node, BAD_CAST "rank", xml_i(sp->rank)); + xmlNewProp(node, BAD_CAST "level", xml_i(sp->level)); + xmlNewProp(node, BAD_CAST "index", xml_i(sp->id)); + if (sp->syntax) xmlNewProp(node, BAD_CAST "syntax", BAD_CAST sp->syntax); - if (sp->parameter) + if (sp->parameter) xmlNewProp(node, BAD_CAST "parameters", BAD_CAST sp->parameter); - if (sp->components) { - spell_component *comp = sp->components; - - for (; comp->type != 0; ++comp) { - static const char *costs[] = { "fixed", "level", "linear" }; - xmlNodePtr cnode = xmlNewNode(NULL, BAD_CAST "resource"); - - xmlNewProp(cnode, BAD_CAST "name", BAD_CAST comp->type->_name[0]); - xmlNewProp(cnode, BAD_CAST "amount", xml_i(comp->amount)); - xmlNewProp(cnode, BAD_CAST "cost", BAD_CAST costs[comp->cost]); - xmlAddChild(node, cnode); - } - } - - if (sp->sptyp & TESTCANSEE) { - xmlNewProp(node, BAD_CAST "los", BAD_CAST "true"); - } - if (sp->sptyp & ONSHIPCAST) { - xmlNewProp(node, BAD_CAST "ship", BAD_CAST "true"); - } - if (sp->sptyp & OCEANCASTABLE) { - xmlNewProp(node, BAD_CAST "ocean", BAD_CAST "true"); - } - if (sp->sptyp & FARCASTING) { - xmlNewProp(node, BAD_CAST "far", BAD_CAST "true"); - } - if (sp->sptyp & SPELLLEVEL) { - xmlNewProp(node, BAD_CAST "variable", BAD_CAST "true"); - } - - if (sp->sptyp & POSTCOMBATSPELL) + if (sp->components) { + spell_component * comp = sp->components; + for (; comp->type != 0; ++comp) { + static const char *costs[] = { "fixed", "level", "linear" }; + xmlNodePtr cnode = xmlNewNode(NULL, BAD_CAST "resource"); + xmlNewProp(cnode, BAD_CAST "name", BAD_CAST comp->type->_name[0]); + xmlNewProp(cnode, BAD_CAST "amount", xml_i(comp->amount)); + xmlNewProp(cnode, BAD_CAST "cost", BAD_CAST costs[comp->cost]); + xmlAddChild(node, cnode); + } } + if (sp->sptyp & TESTCANSEE) { + xmlNewProp(node, BAD_CAST "los", BAD_CAST "true"); + } + if (sp->sptyp & ONSHIPCAST) { + xmlNewProp(node, BAD_CAST "ship", BAD_CAST "true"); + } + if (sp->sptyp & OCEANCASTABLE) { + xmlNewProp(node, BAD_CAST "ocean", BAD_CAST "true"); + } + if (sp->sptyp & FARCASTING) { + xmlNewProp(node, BAD_CAST "far", BAD_CAST "true"); + } + if (sp->sptyp & SPELLLEVEL) { + xmlNewProp(node, BAD_CAST "variable", BAD_CAST "true"); + } + if (sp->sptyp & POSTCOMBATSPELL) combat = 3; + else if (sp->sptyp & COMBATSPELL) combat = 2; + else if (sp->sptyp & PRECOMBATSPELL) combat = 1; - if (combat) { - xmlNewProp(node, BAD_CAST "combat", xml_i(combat)); - } - xmlAddChild(root, node); - } - } - xmlDocSetRootElement(doc, root); - xmlKeepBlanksDefault(0); - xmlSaveFormatFileEnc(filename, doc, "utf-8", 1); - xmlFreeDoc(doc); - return 0; -} + if (combat) { + xmlNewProp(node, BAD_CAST "combat", xml_i(combat)); + } + xmlAddChild(root, node); + } + } + xmlDocSetRootElement(doc, root); + xmlKeepBlanksDefault(0); + xmlSaveFormatFileEnc(filename, doc, "utf-8", 1); + xmlFreeDoc(doc); + return 0; + } -static int config_get_ships(lua_State * L) + static int config_get_ships(lua_State * L) { - quicklist *ql; + quicklist * ql; + int qi, i = 0; + lua_createtable(L, ql_length(shiptypes), 0); + for (qi = 0, ql = shiptypes; ql; ql_advance(&ql, &qi, 1)) { + ship_type * stype = (ship_type *) ql_get(ql, qi); + tolua_pushstring(L, TOLUA_CAST stype->name[0]); + lua_rawseti(L, -2, ++i); + } + return 1; + } - int qi, i = 0; - - lua_createtable(L, ql_length(shiptypes), 0); - - for (qi = 0, ql = shiptypes; ql; ql_advance(&ql, &qi, 1)) { - ship_type *stype = (ship_type *) ql_get(ql, qi); - - tolua_pushstring(L, TOLUA_CAST stype->name[0]); - lua_rawseti(L, -2, ++i); - } - return 1; -} - -static int config_get_locales(lua_State * L) + static int config_get_locales(lua_State * L) { - const struct locale *lang; - - int i = 0, n = 0; - - for (lang = locales; lang; lang = nextlocale(lang)) + const struct locale *lang; + int i = 0, n = 0; + for (lang = locales; lang; lang = nextlocale(lang)) ++n; - lua_createtable(L, n, 0); + lua_createtable(L, n, 0); + for (lang = locales; lang; lang = nextlocale(lang)) { + tolua_pushstring(L, TOLUA_CAST locale_name(lang)); + lua_rawseti(L, -2, ++i); + } + return 1; + } - for (lang = locales; lang; lang = nextlocale(lang)) { - tolua_pushstring(L, TOLUA_CAST locale_name(lang)); - lua_rawseti(L, -2, ++i); - } - return 1; -} - -static int config_get_resource(lua_State * L) + static int config_get_resource(lua_State * L) { - const char *name = tolua_tostring(L, 1, 0); - - if (name) { - const struct item_type *itype = it_find(name); - - if (itype) { - lua_newtable(L); - lua_pushstring(L, "weight"); - -lua_pushinteger(L, itype->weight); - -lua_settable(L, -3); - -if (itype->capacity > 0) { - lua_pushstring(L, "capacity"); - -lua_pushinteger(L, itype->capacity); - -lua_settable(L, -3); - -} - -if (itype->construction) { - int i; - - lua_pushstring(L, "build_skill_min"); - -lua_pushinteger(L, itype->construction->minskill); - -lua_settable(L, -3); - -lua_pushstring(L, "build_skill_name"); - -lua_pushstring(L, skillnames[itype->construction->skill]); - -lua_settable(L, -3); - - -if (itype->construction->materials) { - -lua_pushstring(L, "materials"); - -lua_newtable(L); - -for (i = 0; itype->construction->materials[i].number; ++i) { - -lua_pushstring(L, + const char *name = tolua_tostring(L, 1, 0); + if (name) { + const struct item_type *itype = it_find(name); + if (itype) { + lua_newtable(L); + lua_pushstring(L, "weight"); + lua_pushinteger(L, itype->weight); + lua_settable(L, -3); + if (itype->capacity > 0) { + lua_pushstring(L, "capacity"); + lua_pushinteger(L, itype->capacity); + lua_settable(L, -3); + } + if (itype->construction) { + int i; + lua_pushstring(L, "build_skill_min"); + lua_pushinteger(L, itype->construction->minskill); + lua_settable(L, -3); + lua_pushstring(L, "build_skill_name"); + lua_pushstring(L, skillnames[itype->construction->skill]); + lua_settable(L, -3); + if (itype->construction->materials) { + lua_pushstring(L, "materials"); + lua_newtable(L); + for (i = 0; itype->construction->materials[i].number; ++i) { + lua_pushstring(L, itype->construction->materials[i].rtype->_name[0]); - -lua_pushinteger(L, itype->construction->materials[i].number); - -lua_settable(L, -3); - -} - -lua_settable(L, -3); - -} - -} - -return 1; - } - } - return 0; -} + lua_pushinteger(L, itype->construction->materials[i].number); + lua_settable(L, -3); + } + lua_settable(L, -3); + } + } + return 1; + } + } + return 0; + } -static int tolua_get_spell_text(lua_State * L) + static int tolua_get_spell_text(lua_State * L) { - const struct locale *loc = default_locale; + const struct locale *loc = default_locale; + spell * self = (spell *) tolua_tousertype(L, 1, 0); + lua_pushstring(L, spell_info(self, loc)); + return 1; + } - spell *self = (spell *) tolua_tousertype(L, 1, 0); - - lua_pushstring(L, spell_info(self, loc)); - return 1; -} - -static int tolua_get_spell_school(lua_State * L) + static int tolua_get_spell_school(lua_State * L) { - spell *self = (spell *) tolua_tousertype(L, 1, 0); + spell * self = (spell *) tolua_tousertype(L, 1, 0); + lua_pushstring(L, magic_school[self->magietyp]); + return 1; + } - lua_pushstring(L, magic_school[self->magietyp]); - return 1; -} - -static int tolua_get_spell_level(lua_State * L) + static int tolua_get_spell_level(lua_State * L) { - spell *self = (spell *) tolua_tousertype(L, 1, 0); + spell * self = (spell *) tolua_tousertype(L, 1, 0); + lua_pushnumber(L, self->level); + return 1; + } - lua_pushnumber(L, self->level); - return 1; -} - -static int tolua_get_spell_name(lua_State * L) + static int tolua_get_spell_name(lua_State * L) { - const struct locale *lang = default_locale; + const struct locale *lang = default_locale; + spell * self = (spell *) tolua_tousertype(L, 1, 0); + lua_pushstring(L, spell_name(self, lang)); + return 1; + } - spell *self = (spell *) tolua_tousertype(L, 1, 0); - - lua_pushstring(L, spell_name(self, lang)); - return 1; -} - -static int tolua_get_spells(lua_State * L) + static int tolua_get_spells(lua_State * L) { - return tolua_quicklist_push(L, "spell_list", "spell", spells); -} + return tolua_quicklist_push(L, "spell_list", "spell", spells); + } -int tolua_read_xml(lua_State * L) + int tolua_read_xml(lua_State * L) { - const char *filename = tolua_tostring(L, 1, 0); + const char *filename = tolua_tostring(L, 1, 0); + const char *catalog = tolua_tostring(L, 2, 0); + init_data(filename, catalog); + return 0; + } - const char *catalog = tolua_tostring(L, 2, 0); - - init_data(filename, catalog); - return 0; -} - -int tolua_process_markets(lua_State * L) + int tolua_process_markets(lua_State * L) { - do_markets(); - return 0; -} + do_markets(); + return 0; + } -int tolua_process_produce(lua_State * L) + int tolua_process_produce(lua_State * L) { - region *r; + region * r; + for (r = regions; r; r = r->next) { + produce(r); + } + return 0; + } - for (r = regions; r; r = r->next) { - produce(r); - } - return 0; -} - -typedef struct event_args { - int hfunction; - int hargs; - const char *sendertype; -} event_args; - -static void args_free(void *udata) + typedef struct event_args { + int hfunction; + int hargs; + const char *sendertype; + } event_args; + static void args_free(void *udata) { - free(udata); -} - -static void event_cb(void *sender, const char *event, void *udata) + free(udata); + } static void event_cb(void *sender, const char *event, void *udata) { - lua_State *L = (lua_State *) global.vm_state; + lua_State * L = (lua_State *) global.vm_state; + event_args * args = (event_args *) udata; + int nargs = 2; + lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); + if (sender && args->sendertype) { + tolua_pushusertype(L, sender, TOLUA_CAST args->sendertype); + } else { + lua_pushnil(L); + } + tolua_pushstring(L, event); + if (args->hargs) { + lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); + ++nargs; + } + lua_pcall(L, nargs, 0, 0); + } - event_args *args = (event_args *) udata; - - int nargs = 2; - - lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); - if (sender && args->sendertype) { - tolua_pushusertype(L, sender, TOLUA_CAST args->sendertype); - } else { - lua_pushnil(L); - } - tolua_pushstring(L, event); - if (args->hargs) { - lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); - ++nargs; - } - lua_pcall(L, nargs, 0, 0); -} - -static int tolua_eventbus_register(lua_State * L) + static int tolua_eventbus_register(lua_State * L) { - /* parameters: - ** 1: sender (usertype) - ** 2: event (string) - ** 3: handler (function) - ** 4: arguments (any, *optional*) - */ + + /* parameters: + ** 1: sender (usertype) + ** 2: event (string) + ** 3: handler (function) + ** 4: arguments (any, *optional*) + */ void *sender = tolua_tousertype(L, 1, 0); + const char *event = tolua_tostring(L, 2, 0); + event_args * args = malloc(sizeof(event_args)); + args->sendertype = sender ? tolua_typename(L, 1) : NULL; + lua_pushvalue(L, 3); + args->hfunction = luaL_ref(L, LUA_REGISTRYINDEX); + if (lua_type(L, 4) != LUA_TNONE) { + lua_pushvalue(L, 4); + args->hargs = luaL_ref(L, LUA_REGISTRYINDEX); + } else { + args->hargs = 0; + } + eventbus_register(sender, event, &event_cb, &args_free, args); + return 0; + } - const char *event = tolua_tostring(L, 2, 0); - - event_args *args = malloc(sizeof(event_args)); - - args->sendertype = sender ? tolua_typename(L, 1) : NULL; - lua_pushvalue(L, 3); - args->hfunction = luaL_ref(L, LUA_REGISTRYINDEX); - if (lua_type(L, 4) != LUA_TNONE) { - lua_pushvalue(L, 4); - args->hargs = luaL_ref(L, LUA_REGISTRYINDEX); - } else { - args->hargs = 0; - } - eventbus_register(sender, event, &event_cb, &args_free, args); - return 0; -} - -static int tolua_eventbus_fire(lua_State * L) + static int tolua_eventbus_fire(lua_State * L) { - void *sender = tolua_tousertype(L, 1, 0); + void *sender = tolua_tousertype(L, 1, 0); + const char *event = tolua_tostring(L, 2, 0); + void *args = NULL; + eventbus_fire(sender, event, args); + return 0; + } - const char *event = tolua_tostring(L, 2, 0); - - void *args = NULL; - - eventbus_fire(sender, event, args); - return 0; -} - -static int tolua_report_unit(lua_State * L) + static int tolua_report_unit(lua_State * L) { - char buffer[512]; + char buffer[512]; + unit * u = (unit *) tolua_tousertype(L, 1, 0); + faction * f = (faction *) tolua_tousertype(L, 2, 0); + bufunit(f, u, 0, see_unit, buffer, sizeof(buffer)); + tolua_pushstring(L, buffer); + return 1; + } - unit *u = (unit *) tolua_tousertype(L, 1, 0); - - faction *f = (faction *) tolua_tousertype(L, 2, 0); - - bufunit(f, u, 0, see_unit, buffer, sizeof(buffer)); - tolua_pushstring(L, buffer); - return 1; -} - -static int tolua_settings_get(lua_State * L) + static int tolua_settings_get(lua_State * L) { - const char *name = tolua_tostring(L, 1, 0); + const char *name = tolua_tostring(L, 1, 0); + tolua_pushstring(L, get_param(global.parameters, name)); + return 1; + } - tolua_pushstring(L, get_param(global.parameters, name)); - - return 1; -} - -static int tolua_settings_set(lua_State * L) + static int tolua_settings_set(lua_State * L) { - const char *name = tolua_tostring(L, 1, 0); + const char *name = tolua_tostring(L, 1, 0); + const char *value = tolua_tostring(L, 2, 0); + set_param(&global.parameters, name, value); + return 0; + } - const char *value = tolua_tostring(L, 2, 0); - - set_param(&global.parameters, name, value); - - return 0; -} - -static void parse_inifile(lua_State * L, dictionary * d, const char *section) + static void +parse_inifile(lua_State * L, dictionary * d, const char *section) { - int i; + int i; + size_t len = strlen(section); + for (i = 0; d && i != d->n; ++i) { + const char *key = d->key[i]; + if (strncmp(section, key, len) == 0 && key[len] == ':') { + const char *str_value = d->val[i]; + char *endp; + double num_value = strtod(str_value, &endp); + lua_pushstring(L, key + len + 1); + if (*endp) { + tolua_pushstring(L, str_value); + } else { + tolua_pushnumber(L, num_value); + } + lua_rawset(L, -3); + } + } + + /* special case */ + lua_pushstring(L, "basepath"); + lua_pushstring(L, basepath()); + lua_rawset(L, -3); + } - size_t len = strlen(section); - - for (i = 0; d && i != d->n; ++i) { - const char *key = d->key[i]; - - if (strncmp(section, key, len) == 0 && key[len] == ':') { - const char *str_value = d->val[i]; - - char *endp; - - double num_value = strtod(str_value, &endp); - - lua_pushstring(L, key + len + 1); - if (*endp) { - tolua_pushstring(L, str_value); - } else { - tolua_pushnumber(L, num_value); - } - lua_rawset(L, -3); - } - } - /* special case */ - lua_pushstring(L, "basepath"); - lua_pushstring(L, basepath()); - lua_rawset(L, -3); -} - -int tolua_eressea_open(lua_State * L) + int tolua_eressea_open(lua_State * L) { - tolua_open(L); - - /* register user types */ - tolua_usertype(L, TOLUA_CAST "spell"); - tolua_usertype(L, TOLUA_CAST "spell_list"); - tolua_usertype(L, TOLUA_CAST "order"); - tolua_usertype(L, TOLUA_CAST "item"); - tolua_usertype(L, TOLUA_CAST "alliance"); - tolua_usertype(L, TOLUA_CAST "event"); - tolua_usertype(L, TOLUA_CAST "faction_list"); - - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_module(L, "process", 0); - tolua_beginmodule(L, "process"); - { - tolua_function(L, "markets", &tolua_process_markets); - tolua_function(L, "produce", &tolua_process_produce); - } - tolua_endmodule(L); - - tolua_cclass(L, TOLUA_CAST "alliance", TOLUA_CAST "alliance", TOLUA_CAST "", - NULL); - tolua_beginmodule(L, TOLUA_CAST "alliance"); - { - tolua_variable(L, TOLUA_CAST "name", tolua_get_alliance_name, + tolua_open(L); + + /* register user types */ + tolua_usertype(L, TOLUA_CAST "spell"); + tolua_usertype(L, TOLUA_CAST "spell_list"); + tolua_usertype(L, TOLUA_CAST "order"); + tolua_usertype(L, TOLUA_CAST "item"); + tolua_usertype(L, TOLUA_CAST "alliance"); + tolua_usertype(L, TOLUA_CAST "event"); + tolua_usertype(L, TOLUA_CAST "faction_list"); + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_module(L, "process", 0); + tolua_beginmodule(L, "process"); + { + tolua_function(L, "markets", &tolua_process_markets); + tolua_function(L, "produce", &tolua_process_produce); + } tolua_endmodule(L); + tolua_cclass(L, TOLUA_CAST "alliance", TOLUA_CAST "alliance", + TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "alliance"); + { + tolua_variable(L, TOLUA_CAST "name", tolua_get_alliance_name, tolua_set_alliance_name); - tolua_variable(L, TOLUA_CAST "id", tolua_get_alliance_id, NULL); - tolua_variable(L, TOLUA_CAST "factions", &tolua_get_alliance_factions, + tolua_variable(L, TOLUA_CAST "id", tolua_get_alliance_id, NULL); + tolua_variable(L, TOLUA_CAST "factions", &tolua_get_alliance_factions, NULL); - tolua_function(L, TOLUA_CAST "create", tolua_alliance_create); - } - tolua_endmodule(L); - - tolua_cclass(L, TOLUA_CAST "spell", TOLUA_CAST "spell", TOLUA_CAST "", + tolua_function(L, TOLUA_CAST "create", tolua_alliance_create); + } tolua_endmodule(L); + tolua_cclass(L, TOLUA_CAST "spell", TOLUA_CAST "spell", TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "spell"); - { - tolua_function(L, TOLUA_CAST "__tostring", tolua_get_spell_name); - tolua_variable(L, TOLUA_CAST "name", tolua_get_spell_name, 0); - tolua_variable(L, TOLUA_CAST "school", tolua_get_spell_school, 0); - tolua_variable(L, TOLUA_CAST "level", tolua_get_spell_level, 0); - tolua_variable(L, TOLUA_CAST "text", tolua_get_spell_text, 0); - } - tolua_endmodule(L); - - tolua_module(L, TOLUA_CAST "eventbus", 1); - tolua_beginmodule(L, TOLUA_CAST "eventbus"); - { - tolua_function(L, TOLUA_CAST "register", &tolua_eventbus_register); - tolua_function(L, TOLUA_CAST "fire", &tolua_eventbus_fire); - } - tolua_endmodule(L); - - tolua_module(L, TOLUA_CAST "settings", 1); - tolua_beginmodule(L, TOLUA_CAST "settings"); - { - tolua_function(L, TOLUA_CAST "set", &tolua_settings_set); - tolua_function(L, TOLUA_CAST "get", &tolua_settings_get); - } - tolua_endmodule(L); - - tolua_module(L, TOLUA_CAST "report", 1); - tolua_beginmodule(L, TOLUA_CAST "report"); - { - tolua_function(L, TOLUA_CAST "report_unit", &tolua_report_unit); - } - tolua_endmodule(L); - - tolua_module(L, TOLUA_CAST "config", 1); - tolua_beginmodule(L, TOLUA_CAST "config"); - { - parse_inifile(L, global.inifile, "config"); - - tolua_variable(L, TOLUA_CAST "locales", &config_get_locales, 0); - tolua_function(L, TOLUA_CAST "get_resource", &config_get_resource); - tolua_variable(L, TOLUA_CAST "ships", &config_get_ships, 0); - } - tolua_endmodule(L); - - tolua_function(L, TOLUA_CAST "get_region_by_id", tolua_get_region_byid); - tolua_function(L, TOLUA_CAST "get_faction", tolua_get_faction); - tolua_function(L, TOLUA_CAST "get_unit", tolua_get_unit); - tolua_function(L, TOLUA_CAST "get_alliance", tolua_get_alliance); - tolua_function(L, TOLUA_CAST "get_ship", tolua_get_ship), - tolua_function(L, TOLUA_CAST "get_building", tolua_get_building), - tolua_function(L, TOLUA_CAST "get_region", tolua_get_region), - // deprecated_function(L, TOLUA_CAST "add_faction"); - // deprecated_function(L, TOLUA_CAST "faction_origin"); + tolua_beginmodule(L, TOLUA_CAST "spell"); + { + tolua_function(L, TOLUA_CAST "__tostring", tolua_get_spell_name); + tolua_variable(L, TOLUA_CAST "name", tolua_get_spell_name, 0); + tolua_variable(L, TOLUA_CAST "school", tolua_get_spell_school, 0); + tolua_variable(L, TOLUA_CAST "level", tolua_get_spell_level, 0); + tolua_variable(L, TOLUA_CAST "text", tolua_get_spell_text, 0); + } tolua_endmodule(L); + tolua_module(L, TOLUA_CAST "eventbus", 1); + tolua_beginmodule(L, TOLUA_CAST "eventbus"); + { + tolua_function(L, TOLUA_CAST "register", &tolua_eventbus_register); + tolua_function(L, TOLUA_CAST "fire", &tolua_eventbus_fire); + } tolua_endmodule(L); + tolua_module(L, TOLUA_CAST "settings", 1); + tolua_beginmodule(L, TOLUA_CAST "settings"); + { + tolua_function(L, TOLUA_CAST "set", &tolua_settings_set); + tolua_function(L, TOLUA_CAST "get", &tolua_settings_get); + } tolua_endmodule(L); + tolua_module(L, TOLUA_CAST "report", 1); + tolua_beginmodule(L, TOLUA_CAST "report"); + { + tolua_function(L, TOLUA_CAST "report_unit", &tolua_report_unit); + } tolua_endmodule(L); + tolua_module(L, TOLUA_CAST "config", 1); + tolua_beginmodule(L, TOLUA_CAST "config"); + { + parse_inifile(L, global.inifile, "config"); + tolua_variable(L, TOLUA_CAST "locales", &config_get_locales, 0); + tolua_function(L, TOLUA_CAST "get_resource", &config_get_resource); + tolua_variable(L, TOLUA_CAST "ships", &config_get_ships, 0); + } tolua_endmodule(L); + tolua_function(L, TOLUA_CAST "get_region_by_id", tolua_get_region_byid); + tolua_function(L, TOLUA_CAST "get_faction", tolua_get_faction); + tolua_function(L, TOLUA_CAST "get_unit", tolua_get_unit); + tolua_function(L, TOLUA_CAST "get_alliance", tolua_get_alliance); + tolua_function(L, TOLUA_CAST "get_ship", tolua_get_ship), + tolua_function(L, TOLUA_CAST "get_building", tolua_get_building), + tolua_function(L, TOLUA_CAST "get_region", tolua_get_region), + // deprecated_function(L, TOLUA_CAST "add_faction"); + // deprecated_function(L, TOLUA_CAST "faction_origin"); tolua_function(L, TOLUA_CAST "factions", tolua_get_factions); - tolua_function(L, TOLUA_CAST "regions", tolua_get_regions); - - tolua_function(L, TOLUA_CAST "read_turn", tolua_read_turn); - tolua_function(L, TOLUA_CAST "read_game", tolua_read_game); - tolua_function(L, TOLUA_CAST "write_game", tolua_write_game); - tolua_function(L, TOLUA_CAST "free_game", tolua_free_game); - tolua_function(L, TOLUA_CAST "write_map", &tolua_write_map); - - tolua_function(L, TOLUA_CAST "read_orders", tolua_read_orders); - tolua_function(L, TOLUA_CAST "process_orders", tolua_process_orders); - - tolua_function(L, TOLUA_CAST "init_reports", tolua_init_reports); - tolua_function(L, TOLUA_CAST "write_reports", tolua_write_reports); - tolua_function(L, TOLUA_CAST "write_report", tolua_write_report); - - tolua_function(L, TOLUA_CAST "init_summary", tolua_init_summary); - tolua_function(L, TOLUA_CAST "write_summary", tolua_write_summary); - tolua_function(L, TOLUA_CAST "write_passwords", tolua_write_passwords), - tolua_function(L, TOLUA_CAST "message_unit", tolua_message_unit); - tolua_function(L, TOLUA_CAST "message_faction", tolua_message_faction); - tolua_function(L, TOLUA_CAST "message_region", tolua_message_region); - - /* scripted monsters */ - tolua_function(L, TOLUA_CAST "spawn_braineaters", tolua_spawn_braineaters); - -#ifdef TODO_FOSS - /* spells and stuff */ - tolua_function(L, TOLUA_CAST "levitate_ship", tolua_levitate_ship); -#endif - - tolua_function(L, TOLUA_CAST "update_guards", tolua_update_guards); - - tolua_function(L, TOLUA_CAST "set_turn", &tolua_set_turn); - tolua_function(L, TOLUA_CAST "get_turn", &tolua_get_turn); - tolua_function(L, TOLUA_CAST "get_season", tolua_get_season); - - tolua_function(L, TOLUA_CAST "equipment_setitem", tolua_equipment_setitem); - tolua_function(L, TOLUA_CAST "equip_unit", tolua_equipunit); - tolua_function(L, TOLUA_CAST "add_equipment", tolua_addequipment); - - tolua_function(L, TOLUA_CAST "atoi36", tolua_atoi36); - tolua_function(L, TOLUA_CAST "itoa36", tolua_itoa36); - tolua_function(L, TOLUA_CAST "dice_roll", tolua_dice_rand); - - tolua_function(L, TOLUA_CAST "get_nmrs", tolua_get_nmrs); - tolua_function(L, TOLUA_CAST "remove_empty_units", + tolua_function(L, TOLUA_CAST "regions", tolua_get_regions); + tolua_function(L, TOLUA_CAST "read_turn", tolua_read_turn); + tolua_function(L, TOLUA_CAST "read_game", tolua_read_game); + tolua_function(L, TOLUA_CAST "write_game", tolua_write_game); + tolua_function(L, TOLUA_CAST "free_game", tolua_free_game); + tolua_function(L, TOLUA_CAST "write_map", &tolua_write_map); + tolua_function(L, TOLUA_CAST "read_orders", tolua_read_orders); + tolua_function(L, TOLUA_CAST "process_orders", tolua_process_orders); + tolua_function(L, TOLUA_CAST "init_reports", tolua_init_reports); + tolua_function(L, TOLUA_CAST "write_reports", tolua_write_reports); + tolua_function(L, TOLUA_CAST "write_report", tolua_write_report); + tolua_function(L, TOLUA_CAST "init_summary", tolua_init_summary); + tolua_function(L, TOLUA_CAST "write_summary", tolua_write_summary); + tolua_function(L, TOLUA_CAST "write_passwords", tolua_write_passwords), + tolua_function(L, TOLUA_CAST "message_unit", tolua_message_unit); + tolua_function(L, TOLUA_CAST "message_faction", tolua_message_faction); + tolua_function(L, TOLUA_CAST "message_region", tolua_message_region); + + /* scripted monsters */ + tolua_function(L, TOLUA_CAST "spawn_braineaters", + tolua_spawn_braineaters); + +#ifdef TODO_FOSS + /* spells and stuff */ + tolua_function(L, TOLUA_CAST "levitate_ship", tolua_levitate_ship); + +#endif /* */ + tolua_function(L, TOLUA_CAST "update_guards", tolua_update_guards); + tolua_function(L, TOLUA_CAST "set_turn", &tolua_set_turn); + tolua_function(L, TOLUA_CAST "get_turn", &tolua_get_turn); + tolua_function(L, TOLUA_CAST "get_season", tolua_get_season); + tolua_function(L, TOLUA_CAST "equipment_setitem", + tolua_equipment_setitem); + tolua_function(L, TOLUA_CAST "equip_unit", tolua_equipunit); + tolua_function(L, TOLUA_CAST "add_equipment", tolua_addequipment); + tolua_function(L, TOLUA_CAST "atoi36", tolua_atoi36); + tolua_function(L, TOLUA_CAST "itoa36", tolua_itoa36); + tolua_function(L, TOLUA_CAST "dice_roll", tolua_dice_rand); + tolua_function(L, TOLUA_CAST "get_nmrs", tolua_get_nmrs); + tolua_function(L, TOLUA_CAST "remove_empty_units", tolua_remove_empty_units); - - tolua_function(L, TOLUA_CAST "update_subscriptions", + tolua_function(L, TOLUA_CAST "update_subscriptions", tolua_update_subscriptions); - tolua_function(L, TOLUA_CAST "update_scores", tolua_update_scores); - tolua_function(L, TOLUA_CAST "update_owners", tolua_update_owners); + tolua_function(L, TOLUA_CAST "update_scores", tolua_update_scores); + tolua_function(L, TOLUA_CAST "update_owners", tolua_update_owners); + tolua_function(L, TOLUA_CAST "learn_skill", tolua_learn_skill); + tolua_function(L, TOLUA_CAST "create_curse", tolua_create_curse); + tolua_function(L, TOLUA_CAST "autoseed", tolua_autoseed); + tolua_function(L, TOLUA_CAST "get_key", tolua_getkey); + tolua_function(L, TOLUA_CAST "set_key", tolua_setkey); + tolua_function(L, TOLUA_CAST "translate", &tolua_translate); + tolua_function(L, TOLUA_CAST "rng_int", tolua_rng_int); + tolua_function(L, TOLUA_CAST "spells", tolua_get_spells); + tolua_function(L, TOLUA_CAST "write_spells", tolua_write_spells); + tolua_function(L, TOLUA_CAST "read_xml", tolua_read_xml); + } tolua_endmodule(L); + return 1; + } - tolua_function(L, TOLUA_CAST "learn_skill", tolua_learn_skill); - tolua_function(L, TOLUA_CAST "create_curse", tolua_create_curse); - - tolua_function(L, TOLUA_CAST "autoseed", tolua_autoseed); - - tolua_function(L, TOLUA_CAST "get_key", tolua_getkey); - tolua_function(L, TOLUA_CAST "set_key", tolua_setkey); - - tolua_function(L, TOLUA_CAST "translate", &tolua_translate); - - tolua_function(L, TOLUA_CAST "rng_int", tolua_rng_int); - - tolua_function(L, TOLUA_CAST "spells", tolua_get_spells); - tolua_function(L, TOLUA_CAST "write_spells", tolua_write_spells); - - tolua_function(L, TOLUA_CAST "read_xml", tolua_read_xml); - - } - tolua_endmodule(L); - return 1; -} + diff --git a/src/bindings/helpers.c b/src/bindings/helpers.c index 450264a52..7e8f5d5ba 100644 --- a/src/bindings/helpers.c +++ b/src/bindings/helpers.c @@ -40,11 +40,8 @@ lua_giveitem(unit * s, unit * d, const item_type * itype, int n, struct order *ord) { lua_State *L = (lua_State *) global.vm_state; - char fname[64]; - int result = -1; - const char *iname = itype->rtype->_name[0]; assert(s != NULL); @@ -60,7 +57,6 @@ lua_giveitem(unit * s, unit * d, const item_type * itype, int n, if (lua_pcall(L, 4, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("unit %s calling '%s': %s.\n", unitname(s), fname, error)); lua_pop(L, 1); } else { @@ -79,9 +75,7 @@ lua_giveitem(unit * s, unit * d, const item_type * itype, int n, static int limit_resource(const region * r, const resource_type * rtype) { char fname[64]; - int result = -1; - lua_State *L = (lua_State *) global.vm_state; snprintf(fname, sizeof(fname), "%s_limit", rtype->_name[0]); @@ -93,7 +87,6 @@ static int limit_resource(const region * r, const resource_type * rtype) if (lua_pcall(L, 1, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("limit(%s) calling '%s': %s.\n", regionname(r, NULL), fname, error)); lua_pop(L, 1); @@ -114,9 +107,7 @@ static void produce_resource(region * r, const resource_type * rtype, int norders) { lua_State *L = (lua_State *) global.vm_state; - char fname[64]; - snprintf(fname, sizeof(fname), "%s_produce", rtype->_name[0]); lua_pushstring(L, fname); @@ -127,7 +118,6 @@ produce_resource(region * r, const resource_type * rtype, int norders) if (lua_pcall(L, 2, 0, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("produce(%s) calling '%s': %s.\n", regionname(r, NULL), fname, error)); lua_pop(L, 1); @@ -139,17 +129,12 @@ produce_resource(region * r, const resource_type * rtype, int norders) } } - static int lc_age(struct attrib *a) { building_action *data = (building_action *) a->data.v; - const char *fname = data->fname; - const char *fparam = data->param; - building *b = data->b; - int result = -1; assert(b != NULL); @@ -166,7 +151,6 @@ static int lc_age(struct attrib *a) if (lua_pcall(L, fparam ? 2 : 1, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("lc_age(%s) calling '%s': %s.\n", buildingname(b), fname, error)); lua_pop(L, 1); @@ -205,20 +189,14 @@ static void push_param(lua_State * L, char c, spllprm * param) static int lua_callspell(castorder * co) { lua_State *L = (lua_State *) global.vm_state; - const char *fname = co->sp->sname; - unit *mage = co->familiar ? co->familiar : co->magician.u; - int result = -1; - const char *hashpos = strchr(fname, '#'); - char fbuf[64]; if (hashpos != NULL) { ptrdiff_t len = hashpos - fname; - assert(len < (ptrdiff_t) sizeof(fbuf)); strncpy(fbuf, fname, len); fbuf[len] = '\0'; @@ -229,23 +207,18 @@ static int lua_callspell(castorder * co) lua_rawget(L, LUA_GLOBALSINDEX); if (lua_isfunction(L, 1)) { int nparam = 4; - tolua_pushusertype(L, co->rt, TOLUA_CAST "region"); tolua_pushusertype(L, mage, TOLUA_CAST "unit"); tolua_pushnumber(L, (lua_Number) co->level); tolua_pushnumber(L, (lua_Number) co->force); if (co->sp->parameter && co->par->length) { const char *synp = co->sp->parameter; - int i = 0; - ++nparam; lua_newtable(L); while (*synp && i < co->par->length) { spllprm *param = co->par->param[i]; - char c = *synp; - if (c == '+') { push_param(L, *(synp - 1), param); } else { @@ -258,7 +231,6 @@ static int lua_callspell(castorder * co) if (lua_pcall(L, nparam, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("spell(%s) calling '%s': %s.\n", unitname(mage), fname, error)); lua_pop(L, 1); @@ -279,11 +251,8 @@ static int lua_callspell(castorder * co) static void lua_initfamiliar(unit * u) { lua_State *L = (lua_State *) global.vm_state; - char fname[64]; - int result = -1; - snprintf(fname, sizeof(fname), "initfamiliar_%s", u->race->_name[0]); lua_pushstring(L, fname); @@ -293,7 +262,6 @@ static void lua_initfamiliar(unit * u) if (lua_pcall(L, 1, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("familiar(%s) calling '%s': %s.\n", unitname(u), fname, error)); lua_pop(L, 1); @@ -317,11 +285,8 @@ static int lua_changeresource(unit * u, const struct resource_type *rtype, int delta) { lua_State *L = (lua_State *) global.vm_state; - int result = -1; - char fname[64]; - snprintf(fname, sizeof(fname), "%s_changeresource", rtype->_name[0]); lua_pushstring(L, fname); @@ -332,7 +297,6 @@ lua_changeresource(unit * u, const struct resource_type *rtype, int delta) if (lua_pcall(L, 2, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("change(%s) calling '%s': %s.\n", unitname(u), fname, error)); lua_pop(L, 1); } else { @@ -351,11 +315,8 @@ lua_changeresource(unit * u, const struct resource_type *rtype, int delta) static int lua_getresource(unit * u, const struct resource_type *rtype) { lua_State *L = (lua_State *) global.vm_state; - int result = -1; - char fname[64]; - snprintf(fname, sizeof(fname), "%s_getresource", rtype->_name[0]); lua_pushstring(L, fname); @@ -365,7 +326,6 @@ static int lua_getresource(unit * u, const struct resource_type *rtype) if (lua_pcall(L, 1, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("get(%s) calling '%s': %s.\n", unitname(u), fname, error)); lua_pop(L, 1); } else { @@ -383,12 +343,10 @@ static int lua_getresource(unit * u, const struct resource_type *rtype) static boolean lua_canuse_item(const unit * u, const struct item_type *itype) { static int function_exists = 1; - boolean result = true; if (function_exists) { lua_State *L = (lua_State *) global.vm_state; - const char *fname = "item_canuse"; lua_pushstring(L, fname); @@ -399,7 +357,6 @@ static boolean lua_canuse_item(const unit * u, const struct item_type *itype) if (lua_pcall(L, 2, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("get(%s) calling '%s': %s.\n", unitname(u), fname, error)); lua_pop(L, 1); } else { @@ -420,9 +377,7 @@ static int lua_wage(const region * r, const faction * f, const race * rc, int in_turn) { lua_State *L = (lua_State *) global.vm_state; - const char *fname = "wage"; - int result = -1; lua_pushstring(L, fname); @@ -435,7 +390,6 @@ lua_wage(const region * r, const faction * f, const race * rc, int in_turn) if (lua_pcall(L, 3, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("wage(%s) calling '%s': %s.\n", regionname(r, NULL), fname, error)); lua_pop(L, 1); @@ -455,7 +409,6 @@ lua_wage(const region * r, const faction * f, const race * rc, int in_turn) static void lua_agebuilding(building * b) { lua_State *L = (lua_State *) global.vm_state; - char fname[64]; snprintf(fname, sizeof(fname), "age_%s", b->type->_name); @@ -467,7 +420,6 @@ static void lua_agebuilding(building * b) if (lua_pcall(L, 1, 0, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("agebuilding(%s) calling '%s': %s.\n", buildingname(b), fname, error)); lua_pop(L, 1); @@ -482,9 +434,7 @@ static void lua_agebuilding(building * b) static int lua_building_protection(building * b, unit * u) { lua_State *L = (lua_State *) global.vm_state; - const char *fname = "building_protection"; - int result = 0; lua_pushstring(L, fname); @@ -495,7 +445,6 @@ static int lua_building_protection(building * b, unit * u) if (lua_pcall(L, 2, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("building_protection(%s, %s) calling '%s': %s.\n", buildingname(b), unitname(u), fname, error)); lua_pop(L, 1); @@ -514,11 +463,8 @@ static int lua_building_protection(building * b, unit * u) static double lua_building_taxes(building * b, int level) { lua_State *L = (lua_State *) global.vm_state; - const char *fname = "building_taxes"; - double result = 0.0F; - int type; lua_pushstring(L, fname); @@ -530,7 +476,6 @@ static double lua_building_taxes(building * b, int level) if (lua_pcall(L, 2, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("building_taxes(%s) calling '%s': %s.\n", buildingname(b), fname, error)); lua_pop(L, 1); @@ -549,9 +494,7 @@ static double lua_building_taxes(building * b, int level) static int lua_maintenance(const unit * u) { lua_State *L = (lua_State *) global.vm_state; - const char *fname = "maintenance"; - int result = -1; lua_pushstring(L, fname); @@ -561,7 +504,6 @@ static int lua_maintenance(const unit * u) if (lua_pcall(L, 1, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("maintenance(%s) calling '%s': %s.\n", unitname(u), fname, error)); lua_pop(L, 1); @@ -581,11 +523,8 @@ static int lua_maintenance(const unit * u) static void lua_equipmentcallback(const struct equipment *eq, unit * u) { lua_State *L = (lua_State *) global.vm_state; - char fname[64]; - int result = -1; - snprintf(fname, sizeof(fname), "equip_%s", eq->name); lua_pushstring(L, fname); @@ -595,7 +534,6 @@ static void lua_equipmentcallback(const struct equipment *eq, unit * u) if (lua_pcall(L, 1, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("equip(%s) calling '%s': %s.\n", unitname(u), fname, error)); lua_pop(L, 1); } else { @@ -615,11 +553,8 @@ lua_useitem(struct unit *u, const struct item_type *itype, int amount, struct order *ord) { lua_State *L = (lua_State *) global.vm_state; - int result = 0; - char fname[64]; - snprintf(fname, sizeof(fname), "use_%s", itype->rtype->_name[0]); lua_pushstring(L, fname); @@ -630,7 +565,6 @@ lua_useitem(struct unit *u, const struct item_type *itype, int amount, if (lua_pcall(L, 2, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("use(%s) calling '%s': %s.\n", unitname(u), fname, error)); lua_pop(L, 1); } else { @@ -648,11 +582,8 @@ lua_useitem(struct unit *u, const struct item_type *itype, int amount, static int lua_recruit(struct unit *u, const struct archetype *arch, int amount) { lua_State *L = (lua_State *) global.vm_state; - int result = 0; - char fname[64]; - snprintf(fname, sizeof(fname), "recruit_%s", arch->name[0]); lua_pushstring(L, fname); @@ -663,7 +594,6 @@ static int lua_recruit(struct unit *u, const struct archetype *arch, int amount) if (lua_pcall(L, 2, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("use(%s) calling '%s': %s.\n", unitname(u), fname, error)); lua_pop(L, 1); } else { @@ -680,14 +610,11 @@ static int lua_recruit(struct unit *u, const struct archetype *arch, int amount) int tolua_toid(lua_State * L, int idx, int def) { int no = 0; - int type = lua_type(L, idx); - if (type == LUA_TNUMBER) { no = (int)tolua_tonumber(L, idx, def); } else { const char *str = tolua_tostring(L, idx, NULL); - no = str ? atoi36(str) : def; } return no; @@ -721,7 +648,6 @@ void register_tolua_helpers(void) register_function((pf_generic) & lua_maintenance, TOLUA_CAST "lua_maintenance"); - register_function((pf_generic) produce_resource, TOLUA_CAST "lua_produceresource"); register_function((pf_generic) limit_resource, diff --git a/src/eressea.c b/src/eressea.c index 8ab2bbf3a..f1a9c1ab3 100644 --- a/src/eressea.c +++ b/src/eressea.c @@ -50,7 +50,6 @@ #include #include - static const struct { const char *name; int (*func) (lua_State *); @@ -74,7 +73,6 @@ static const struct { static void openlibs(lua_State * L) { int i; - for (i = 0; lualibs[i].func; ++i) { lua_pushcfunction(L, lualibs[i].func); lua_pushstring(L, lualibs[i].name); @@ -168,7 +166,6 @@ static void game_init(void) int eressea_init(void) { global.vm_state = lua_init(); - kernel_init(); game_init(); @@ -185,9 +182,7 @@ void eressea_done(void) int eressea_run(const char *luafile, const char *entry_point) { int err; - lua_State *L = (lua_State *) global.vm_state; - /* run the main script */ if (luafile) { lua_getglobal(L, "dofile"); diff --git a/src/gamecode/archetype.c b/src/gamecode/archetype.c index 010ed0612..7ac51f338 100644 --- a/src/gamecode/archetype.c +++ b/src/gamecode/archetype.c @@ -33,7 +33,6 @@ struct attrib_type at_recruit = { const struct archetype *find_archetype(const char *s, const struct locale *lang) { struct tnode *tokens = get_translations(lang, UT_ARCHETYPES); - variant token; if (findtoken(tokens, s, &token) == E_TOK_SUCCESS) { @@ -51,17 +50,12 @@ void register_archetype(archetype * arch) void init_archetypes(void) { const struct locale *lang = locales; - for (; lang; lang = nextlocale(lang)) { variant var; - archetype *arch = archetypes; - struct tnode *tokens = get_translations(lang, UT_ARCHETYPES); - for (; arch; arch = arch->next) { const char *s1, *s2; - var.v = arch; s1 = LOC(lang, arch->name[0]); @@ -77,25 +71,18 @@ void init_archetypes(void) static int parse_archetypes(xmlDocPtr doc) { char zName[64]; - xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr result = xmlXPathEvalExpression(BAD_CAST "/eressea/archetypes/archetype", xpath); xmlNodeSetPtr nodes = result->nodesetval; xmlChar *propValue; - if (nodes) { int i; - for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; - xmlNodePtr child; - archetype *arch = calloc(1, sizeof(archetype)); - xmlXPathObjectPtr sub; propValue = xmlGetProp(node, BAD_CAST "name"); @@ -124,12 +111,9 @@ static int parse_archetypes(xmlDocPtr doc) for (child = node->children; child; child = child->next) { if (strcmp((const char *)child->name, "function") == 0) { xmlChar *propName = xmlGetProp(child, BAD_CAST "name"); - xmlChar *propValue = xmlGetProp(child, BAD_CAST "value"); - if (strcmp((const char *)propName, "create")) { pf_generic foo = get_function((const char *)propValue); - arch->exec = (archetype_function) foo; } xmlFree(propValue); @@ -140,11 +124,9 @@ static int parse_archetypes(xmlDocPtr doc) sub = xmlXPathEvalExpression(BAD_CAST "allow|deny", xpath); if (sub->nodesetval && sub->nodesetval->nodeNr) { int k; - arch->rules = calloc(sub->nodesetval->nodeNr + 1, sizeof(rule)); for (k = 0; k != sub->nodesetval->nodeNr; ++k) { xmlNodePtr rule = sub->nodesetval->nodeTab[k]; - arch->rules[k].allow = (rule->name[0] == 'a'); propValue = xmlGetProp(rule, BAD_CAST "property"); diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index 2eab910d0..b8b2a975f 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -78,7 +78,6 @@ without prior permission by the authors of Eressea. /* imports */ extern int verbosity; - boolean opt_cr_absolute_coords = false; /* globals */ @@ -89,7 +88,6 @@ boolean opt_cr_absolute_coords = false; static const char *crtag(const char *key) { static const struct locale *lang = NULL; - if (!lang) lang = find_locale(TAG_LOCALE); return locale_string(lang, key); @@ -108,15 +106,12 @@ typedef struct translation { #define TRANSMAXHASH 257 static translation *translation_table[TRANSMAXHASH]; - static translation *junkyard; static const char *add_translation(const char *key, const char *value) { int kk = ((key[0] << 5) + key[0]) % TRANSMAXHASH; - translation *t = translation_table[kk]; - while (t && strcmp(t->key, key) != 0) t = t->next; if (!t) { @@ -136,11 +131,9 @@ static const char *add_translation(const char *key, const char *value) static void write_translations(FILE * F) { int i; - fputs("TRANSLATION\n", F); for (i = 0; i != TRANSMAXHASH; ++i) { translation *t = translation_table[i]; - while (t) { fprintf(F, "\"%s\";%s\n", t->value, crtag(t->key)); t = t->next; @@ -151,13 +144,10 @@ static void write_translations(FILE * F) static void reset_translations(void) { int i; - for (i = 0; i != TRANSMAXHASH; ++i) { translation *t = translation_table[i]; - while (t) { translation *c = t->next; - free(t->key); t->next = junkyard; junkyard = t; @@ -175,9 +165,7 @@ static void print_items(FILE * F, item * items, const struct locale *lang) for (itm = items; itm; itm = itm->next) { int in = itm->number; - const char *ic = resourcename(itm->type->rtype, 0); - if (itm == items) fputs("GEGENSTAENDE\n", F); fprintf(F, "%d;%s\n", in, add_translation(ic, LOC(lang, ic))); @@ -188,11 +176,8 @@ static void cr_output_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ) { boolean header = false; - attrib *a = NULL; - int self = 0; - region *r; /* Die Sichtbarkeit eines Zaubers und die Zaubermeldung sind bei @@ -202,9 +187,7 @@ cr_output_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ) * bei jedem curse gesondert behandelt. */ if (typ == TYP_SHIP) { ship *sh = (ship *) obj; - unit *owner = shipowner(sh); - a = sh->attribs; r = sh->region; if (owner != NULL) { @@ -212,7 +195,6 @@ cr_output_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ) self = 2; } else { /* steht eine person der Partei auf dem Schiff? */ unit *u = NULL; - for (u = r->units; u; u = u->next) { if (u->ship == sh) { self = 1; @@ -223,9 +205,7 @@ cr_output_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ) } } else if (typ == TYP_BUILDING) { building *b = (building *) obj; - unit *owner = building_owner(b); - a = b->attribs; r = b->region; if (owner != NULL) { @@ -233,7 +213,6 @@ cr_output_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ) self = 2; } else { /* steht eine Person der Partei in der Burg? */ unit *u = NULL; - for (u = r->units; u; u = u->next) { if (u->building == b) { self = 1; @@ -244,7 +223,6 @@ cr_output_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ) } } else if (typ == TYP_UNIT) { unit *u = (unit *) obj; - a = u->attribs; r = u->region; if (u->faction == viewer) { @@ -260,7 +238,6 @@ cr_output_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ) while (a) { if (fval(a->type, ATF_CURSE)) { curse *c = (curse *) a->data.v; - message *msg; if (c->type->cansee) { @@ -270,7 +247,6 @@ cr_output_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ) if (msg) { char buf[BUFFERSIZE]; - if (!header) { header = 1; fputs("EFFECTS\n", F); @@ -281,10 +257,8 @@ cr_output_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ) } } else if (a->type == &at_effect && self) { effect_data *data = (effect_data *) a->data.v; - if (data->value > 0) { const char *key = resourcename(data->type->itype->rtype, 0); - if (!header) { header = 1; fputs("EFFECTS\n", F); @@ -300,7 +274,6 @@ cr_output_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ) static int cr_unit(variant var, char *buffer, const void *userdata) { unit *u = (unit *) var.v; - sprintf(buffer, "%d", u ? u->no : -1); return 0; } @@ -308,7 +281,6 @@ static int cr_unit(variant var, char *buffer, const void *userdata) static int cr_ship(variant var, char *buffer, const void *userdata) { ship *u = (ship *) var.v; - sprintf(buffer, "%d", u ? u->no : -1); return 0; } @@ -316,7 +288,6 @@ static int cr_ship(variant var, char *buffer, const void *userdata) static int cr_building(variant var, char *buffer, const void *userdata) { building *u = (building *) var.v; - sprintf(buffer, "%d", u ? u->no : -1); return 0; } @@ -324,7 +295,6 @@ static int cr_building(variant var, char *buffer, const void *userdata) static int cr_faction(variant var, char *buffer, const void *userdata) { faction *f = (faction *) var.v; - sprintf(buffer, "%d", f ? f->no : -1); return 0; } @@ -332,14 +302,10 @@ static int cr_faction(variant var, char *buffer, const void *userdata) static int cr_region(variant var, char *buffer, const void *userdata) { const faction *report = (const faction *)userdata; - region *r = (region *) var.v; - if (r) { plane *pl = rplane(r); - int nx = r->x, ny = r->y; - pnormalize(&nx, &ny, pl); adjust_coordinates(report, &nx, &ny, pl, r); sprintf(buffer, "%d %d %d", nx, ny, plane_id(pl)); @@ -351,12 +317,9 @@ static int cr_region(variant var, char *buffer, const void *userdata) static int cr_resource(variant var, char *buffer, const void *userdata) { const faction *report = (const faction *)userdata; - const resource_type *r = (const resource_type *)var.v; - if (r) { const char *key = resourcename(r, 0); - sprintf(buffer, "\"%s\"", add_translation(key, locale_string(report->locale, key))); return 0; @@ -367,11 +330,8 @@ static int cr_resource(variant var, char *buffer, const void *userdata) static int cr_race(variant var, char *buffer, const void *userdata) { const faction *report = (const faction *)userdata; - const struct race *rc = (const race *)var.v; - const char *key = rc_name(rc, 0); - sprintf(buffer, "\"%s\"", add_translation(key, locale_string(report->locale, key))); return 0; @@ -380,7 +340,6 @@ static int cr_race(variant var, char *buffer, const void *userdata) static int cr_alliance(variant var, char *buffer, const void *userdata) { const alliance *al = (const alliance *)var.v; - if (al != NULL) { sprintf(buffer, "%d", al->id); } @@ -391,9 +350,7 @@ static int cr_alliance(variant var, char *buffer, const void *userdata) static int cr_skill(variant var, char *buffer, const void *userdata) { const faction *report = (const faction *)userdata; - skill_t sk = (skill_t) var.i; - if (sk != NOSKILL) sprintf(buffer, "\"%s\"", add_translation(mkname("skill", skillnames[sk]), skillname(sk, @@ -406,12 +363,9 @@ static int cr_skill(variant var, char *buffer, const void *userdata) static int cr_order(variant var, char *buffer, const void *userdata) { order *ord = (order *) var.v; - if (ord != NULL) { char *wp = buffer; - char *cmd = getcommand(ord); - const char *rp = cmd; *wp++ = '\"'; @@ -436,14 +390,10 @@ static int cr_order(variant var, char *buffer, const void *userdata) static int cr_resources(variant var, char *buffer, const void *userdata) { faction *f = (faction *) userdata; - resource *rlist = (resource *) var.v; - char *wp = buffer; - if (rlist != NULL) { const char *name = resourcename(rlist->type, rlist->number != 1); - wp += sprintf(wp, "\"%d %s", rlist->number, add_translation(name, LOC(f->locale, name))); @@ -464,18 +414,13 @@ static int cr_resources(variant var, char *buffer, const void *userdata) static int cr_regions(variant var, char *buffer, const void *userdata) { faction *f = (faction *) userdata; - const arg_regions *rdata = (const arg_regions *)var.v; if (rdata != NULL && rdata->nregions > 0) { region *r = rdata->regions[0]; - plane *pl = rplane(r); - int i, z = plane_id(pl); - char *wp = buffer; - int nx = r->x, ny = r->y; pnormalize(&nx, &ny, pl); @@ -497,9 +442,7 @@ static int cr_regions(variant var, char *buffer, const void *userdata) static int cr_spell(variant var, char *buffer, const void *userdata) { const faction *report = (const faction *)userdata; - spell *sp = (spell *) var.v; - if (sp != NULL) sprintf(buffer, "\"%s\"", spell_name(sp, report->locale)); else @@ -510,9 +453,7 @@ static int cr_spell(variant var, char *buffer, const void *userdata) static int cr_curse(variant var, char *buffer, const void *userdata) { const faction *report = (const faction *)userdata; - const curse_type *ctype = (const curse_type *)var.v; - if (ctype != NULL) { sprintf(buffer, "\"%s\"", curse_name(ctype, report->locale)); } else @@ -532,16 +473,12 @@ static struct known_mtype { static void report_crtypes(FILE * F, const struct locale *lang) { int i; - for (i = 0; i != MTMAXHASH; ++i) { struct known_mtype *kmt; - for (kmt = mtypehash[i]; kmt; kmt = kmt->nexthash) { const struct nrmessage_type *nrt = nrt_find(lang, kmt->mtype); - if (nrt) { unsigned int hash = kmt->mtype->key; - fprintf(F, "MESSAGETYPE %d\n", hash); fputc('\"', F); fputs(escape_string(nrt_string(nrt), NULL, 0), F); @@ -560,7 +497,6 @@ static void report_crtypes(FILE * F, const struct locale *lang) static unsigned int messagehash(const struct message *msg) { variant var; - var.v = (void *)msg; return (unsigned int)var.i; } @@ -568,19 +504,13 @@ static unsigned int messagehash(const struct message *msg) static void render_messages(FILE * F, faction * f, message_list * msgs) { struct mlist *m = msgs->begin; - while (m) { char crbuffer[BUFFERSIZE]; /* gross, wegen spionage-messages :-( */ - boolean printed = false; - const struct message_type *mtype = m->msg->type; - unsigned int hash = mtype->key; - #ifdef RENDER_CRMESSAGES char nrbuffer[1024 * 32]; - nrbuffer[0] = '\0'; if (nr_render(m->msg, f->locale, nrbuffer, sizeof(nrbuffer), f) >= 0) { fprintf(F, "MESSAGE %u\n", messagehash(m->msg)); @@ -602,9 +532,7 @@ static void render_messages(FILE * F, faction * f, message_list * msgs) } if (printed) { unsigned int ihash = hash % MTMAXHASH; - struct known_mtype *kmt = mtypehash[ihash]; - while (kmt && kmt->mtype != mtype) kmt = kmt->nexthash; if (kmt == NULL) { @@ -666,7 +594,6 @@ cr_output_ship(FILE * F, 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); @@ -688,9 +615,7 @@ cr_output_ship(FILE * F, const ship * sh, const unit * u, int 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); @@ -712,11 +637,8 @@ fwriteorder(FILE * F, const struct order *ord, const struct locale *lang, boolean escape) { char ebuf[1024]; - char obuf[1024]; - const char *str = obuf; - fputc('"', F); write_order(ord, obuf, sizeof(obuf)); if (escape) { @@ -732,14 +654,11 @@ static void cr_output_spells(FILE * F, quicklist * slist, const faction * f, { if (slist) { quicklist *ql; - int qi; - fprintf(F, "SPRUECHE\n"); for (ql = slist, qi = 0; ql; ql_advance(&ql, &qi, 1)) { spell *sp = (spell *) ql_get(ql, qi); - if (sp->level <= maxlevel) { const char *name = add_translation(mkname("spell", sp->sname), spell_name(sp, @@ -757,27 +676,16 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, /* Race attributes are always plural and item attributes always * singular */ const char *str; - const item_type *lasttype; - int pr; - item *itm, *show; - building *b; - const char *pzTmp; - skill *sv; - const attrib *a_fshidden = NULL; - boolean itemcloak = false; - static const curse_type *itemcloak_ct = 0; - static boolean init = false; - item result[MAX_INVENTORY]; if (fval(u->race, RCF_INVISIBLE)) @@ -802,24 +710,19 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, { /* print faction information */ const faction *sf = visible_faction(f, u); - const char *prefix = raceprefix(u); - if (u->faction == f || omniscient(f)) { const attrib *a_otherfaction = a_find(u->attribs, &at_otherfaction); - const faction *otherfaction = a_otherfaction ? get_otherfaction(a_otherfaction) : NULL; /* my own faction, full info */ const attrib *a = NULL; - unit *mage; if (fval(u, UFL_GROUP)) a = a_find(u->attribs, &at_group); if (a != NULL) { const group *g = (const group *)a->data.v; - fprintf(F, "%d;gruppe\n", g->gid); } fprintf(F, "%d;Partei\n", u->faction->no); @@ -842,7 +745,6 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, fprintf(F, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION))); } else { const attrib *a_otherfaction = a_find(u->attribs, &at_otherfaction); - const faction *otherfaction = a_otherfaction ? get_otherfaction(a_otherfaction) : NULL; /* other unit. show visible faction, not u->faction */ @@ -877,15 +779,12 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, fprintf(F, "\"%s\";Typ\n", pzTmp); if (u->faction == f && fval(u->race, RCF_SHAPESHIFTANY)) { const char *zRace = rc_name(u->race, 1); - fprintf(F, "\"%s\";wahrerTyp\n", add_translation(zRace, locale_string(f->locale, zRace))); } } else { const race *irace = u_irace(u); - const char *zRace = rc_name(irace, 1); - fprintf(F, "\"%s\";Typ\n", add_translation(zRace, locale_string(f->locale, zRace))); if (u->faction == f && irace != u->race) { @@ -914,11 +813,8 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, /* additional information for own units */ if (u->faction == f || omniscient(f)) { order *ord; - const char *xc; - const char *c; - int i; i = ualias(u); @@ -981,9 +877,7 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { if (sv->level > 0) { skill_t sk = sv->id; - int esk = eff_skill(u, sk, r); - if (!pr) { pr = 1; fprintf(F, "TALENTE\n"); @@ -996,16 +890,13 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, /* spells */ if (is_mage(u)) { sc_mage *mage = get_mage(u); - quicklist **slistp = get_spelllist(mage, u->faction); - int i, maxlevel = effskill(u, SK_MAGIC); cr_output_spells(F, *slistp, f, maxlevel); for (i = 0; i != MAXCOMBATSPELLS; ++i) { const spell *sp = mage->combatspells[i].sp; - if (sp) { const char *name = add_translation(mkname("spell", sp->sname), spell_name(sp, @@ -1024,7 +915,6 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, } else if (itemcloak == false && mode >= see_unit && !(a_fshidden && a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) { int n = report_items(u->items, result, MAX_INVENTORY, u, f); - assert(n >= 0); if (n > 0) show = result; @@ -1036,9 +926,7 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, lasttype = NULL; for (itm = show; itm; itm = itm->next) { const char *ic; - int in; - assert(itm->type != lasttype || !"error: list contains two objects of the same item"); report_item(u, itm, f, NULL, &ic, &in, true); @@ -1063,7 +951,6 @@ static void show_allies_cr(FILE * F, const faction * f, const ally * sf) for (; sf; sf = sf->next) if (sf->faction) { int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); - if (mode != 0 && sf->status > 0) { fprintf(F, "ALLIANZ %d\n", sf->faction->no); fprintf(F, "\"%s\";Parteiname\n", sf->faction->name); @@ -1076,10 +963,8 @@ static void show_allies_cr(FILE * F, const faction * f, const ally * sf) static void show_alliances_cr(FILE * F, const faction * f) { alliance *al = f_get_alliance(f); - if (al) { faction *lead = alliance_get_leader(al); - assert(lead); fprintf(F, "ALLIANCE %d\n", al->id); fprintf(F, "\"%s\";name\n", al->name); @@ -1091,10 +976,8 @@ static void show_alliances_cr(FILE * F, const faction * f) static void show_active_spells(const region * r) { char fogwall[MAXDIRECTIONS]; - #ifdef TODO /* alte Regionszauberanzeigen umstellen */ unit *u; - int env = 0; #endif memset(fogwall, 0, sizeof(char) * MAXDIRECTIONS); @@ -1107,12 +990,9 @@ static void show_active_spells(const region * r) static void cr_find_address(FILE * F, const faction * uf, quicklist * addresses) { int i = 0; - quicklist *flist = addresses; - while (flist) { const faction *f = (const faction *)ql_get(flist, i); - if (uf != f) { fprintf(F, "PARTEI %d\n", f->no); fprintf(F, "\"%s\";Parteiname\n", f->name); @@ -1134,7 +1014,6 @@ static void cr_find_address(FILE * F, const faction * uf, quicklist * addresses) static void cr_reportspell(FILE * F, spell * sp, const struct locale *lang) { int k; - const char *name = add_translation(mkname("spell", sp->sname), spell_name(sp, lang)); @@ -1169,14 +1048,10 @@ static void cr_reportspell(FILE * F, spell * sp, const struct locale *lang) for (k = 0; sp->components[k].type; ++k) { const resource_type *rtype = sp->components[k].type; - int itemanz = sp->components[k].amount; - int costtyp = sp->components[k].cost; - if (itemanz > 0) { const char *name = resourcename(rtype, 0); - fprintf(F, "%d %d;%s\n", itemanz, costtyp == SPC_LEVEL || costtyp == SPC_LINEAR, add_translation(name, LOC(lang, name))); } @@ -1201,19 +1076,14 @@ cr_borders(seen_region ** seen, const region * r, const faction * f, int seemode, FILE * F) { direction_t d; - int g = 0; - for (d = 0; d != MAXDIRECTIONS; d++) { /* Nachbarregionen, die gesehen werden, ermitteln */ const region *r2 = rconnect(r, d); - const connection *b; - if (!r2) continue; if (seemode == see_neighbour) { seen_region *sr = find_seen(seen, r2); - if (sr == NULL || sr->mode <= see_neighbour) continue; } @@ -1225,7 +1095,6 @@ cr_borders(seen_region ** seen, const region * r, const faction * f, cs = b->type->rvisible(b, r); if (!cs) { unit *us = r->units; - while (us && !cs) { if (us->faction == f) { cs = b->type->uvisible(b, us); @@ -1238,7 +1107,6 @@ cr_borders(seen_region ** seen, const region * r, const faction * f, } if (cs) { const char *bname = mkname("border", b->type->name(b, r, f, GF_PURE)); - fprintf(F, "GRENZE %d\n", ++g); fprintf(F, "\"%s\";typ\n", LOC(default_locale, bname)); fprintf(F, "%d;richtung\n", d); @@ -1247,7 +1115,6 @@ cr_borders(seen_region ** seen, const region * r, const faction * f, /* hack: */ if (b->type == &bt_road) { int p = rroad(r, d) * 100 / r->terrain->max_road; - fprintf(F, "%d;prozent\n", p); } } @@ -1260,18 +1127,13 @@ static void cr_output_resources(FILE * F, report_context * ctx, seen_region * sr) { char cbuf[BUFFERSIZE], *pos = cbuf; - region *r = sr->r; - faction *f = ctx->f; - resource_report result[MAX_RAWMATERIALS]; - int n, size = report_resources(sr, result, MAX_RAWMATERIALS, f); #ifdef RESOURCECOMPAT int trees = rtrees(r, 2); - int saplings = rtrees(r, 1); if (trees > 0) @@ -1313,17 +1175,11 @@ cr_region_header(FILE * F, int plid, int nx, int ny, unsigned int uid) static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr) { faction *f = ctx->f; - region *r = sr->r; - plane *pl = rplane(r); - int plid = plane_id(pl), nx, ny; - const char *tname; - int oc[4][2], o = 0; - int uid = r->uid; #ifdef OCEAN_NEIGHBORS_GET_NO_ID @@ -1368,7 +1224,6 @@ static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr) if (r->land) { const char *str = rname(r, f->locale); - if (str && str[0]) { fprintf(F, "\"%s\";Name\n", str); } @@ -1383,11 +1238,8 @@ static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr) cr_borders(ctx->seen, r, f, sr->mode, F); } else { building *b; - ship *sh; - unit *u; - int stealthmod = stealth_modifier(sr->mode); if (r->display && r->display[0]) @@ -1402,7 +1254,6 @@ static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr) if (sr->mode >= see_unit) { if (rule_region_owners()) { faction *owner = region_get_owner(r); - if (owner) { fprintf(F, "%d;owner\n", owner->no); } @@ -1418,7 +1269,6 @@ static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr) } if (production(r)) { int p_wage = wage(r, NULL, NULL, turn + 1); - fprintf(F, "%d;Lohn\n", p_wage); if (is_mourning(r, turn + 1)) { fputs("1;mourning\n", F); @@ -1437,31 +1287,25 @@ static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr) /* trade */ if (markets_module() && r->land) { const item_type *lux = r_luxury(r); - const item_type *herb = r->land->herbtype; - if (lux || herb) { fputs("PREISE\n", F); if (lux) { const char *ch = resourcename(lux->rtype, 0); - fprintf(F, "%d;%s\n", 1, add_translation(ch, locale_string(f->locale, ch))); } if (herb) { const char *ch = resourcename(herb->rtype, 0); - fprintf(F, "%d;%s\n", 1, add_translation(ch, locale_string(f->locale, ch))); } } } else if (rpeasants(r) / TRADE_FRACTION > 0) { struct demand *dmd = r->land->demands; - fputs("PREISE\n", F); while (dmd) { const char *ch = resourcename(dmd->type->itype->rtype, 0); - fprintf(F, "%d;%s\n", (dmd->value ? dmd->value * dmd->type->price : -dmd->type->price), @@ -1483,12 +1327,9 @@ static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr) if (rl) { region_list *rl2 = rl; - while (rl2) { region *r = rl2->data; - int nx = r->x, ny = r->y; - plane *plx = rplane(r); pnormalize(&nx, &ny, plx); @@ -1505,14 +1346,11 @@ static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr) show_active_spells(r); if (fval(r, RF_TRAVELUNIT)) { boolean seeunits = false, seeships = false; - const attrib *ru; - /* show units pulled through region */ for (ru = a_find(r->attribs, &at_travelunit); ru && ru->type == &at_travelunit; ru = ru->next) { unit *u = (unit *) ru->data.v; - if (cansee_durchgezogen(f, r, u, 0) && r != u->region) { if (!u->ship || !fval(u, UFL_OWNER)) continue; @@ -1525,7 +1363,6 @@ static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr) for (ru = a_find(r->attribs, &at_travelunit); ru && ru->type == &at_travelunit; ru = ru->next) { unit *u = (unit *) ru->data.v; - if (cansee_durchgezogen(f, r, u, 0) && r != u->region) { if (u->ship) continue; @@ -1539,18 +1376,15 @@ static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr) cr_output_messages(F, r->msgs, f); { message_list *mlist = r_getmessages(r, f); - if (mlist) cr_output_messages(F, mlist, f); } /* buildings */ for (b = rbuildings(r); b; b = b->next) { int fno = -1; - u = building_owner(b); if (u && !fval(u, UFL_ANON_FACTION)) { const faction *sf = visible_faction(f, u); - fno = sf->no; } cr_output_building(F, b, u, fno, f); @@ -1559,11 +1393,9 @@ static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr) /* ships */ for (sh = r->ships; sh; sh = sh->next) { int fno = -1; - u = shipowner(sh); if (u && !fval(u, UFL_ANON_FACTION)) { const faction *sf = visible_faction(f, u); - fno = sf->no; } @@ -1586,26 +1418,17 @@ static int report_computer(const char *filename, report_context * ctx, const char *charset) { static int era = -1; - int i; - faction *f = ctx->f; - const char *prefix; - region *r; - const char *mailto = locale_string(f->locale, "mailto"); - const attrib *a; - seen_region *sr = NULL; - #if SCORE_MODULE int score = 0, avgscore = 0; #endif int enc = xmlParseCharEncoding(charset); - FILE *F = fopen(filename, "wt"); if (era < 0) { @@ -1629,7 +1452,6 @@ report_computer(const char *filename, report_context * ctx, const char *charset) fprintf(F, "%d;noskillpoints\n", 1); fprintf(F, "%ld;date\n", ctx->report_time); fprintf(F, "\"%s\";Spiel\n", global.gamename); - fprintf(F, "\"%s\";Konfiguration\n", "Standard"); fprintf(F, "\"%s\";Koordinaten\n", "Hex"); fprintf(F, "%d;Basis\n", 36); @@ -1660,7 +1482,6 @@ report_computer(const char *filename, report_context * ctx, const char *charset) #endif { const char *zRace = rc_name(f->race, 1); - fprintf(F, "\"%s\";Typ\n", add_translation(zRace, LOC(f->locale, zRace))); } prefix = get_prefix(f->attribs); @@ -1697,7 +1518,6 @@ report_computer(const char *filename, report_context * ctx, const char *charset) fputs("OPTIONEN\n", F); for (i = 0; i != MAXOPTIONS; ++i) { int flag = want(i); - if (options[i]) { fprintf(F, "%d;%s\n", (f->options & flag) ? 1 : 0, options[i]); } else if (f->options & flag) { @@ -1707,7 +1527,6 @@ report_computer(const char *filename, report_context * ctx, const char *charset) show_allies_cr(F, f, f->allies); { group *g; - for (g = f->groups; g; g = g->next) { fprintf(F, "GRUPPE %d\n", g->gid); @@ -1725,14 +1544,10 @@ report_computer(const char *filename, report_context * ctx, const char *charset) cr_output_messages(F, f->msgs, f); { struct bmsg *bm; - for (bm = f->battles; bm; bm = bm->next) { plane *pl = rplane(bm->r); - int plid = plane_id(pl); - region *r = bm->r; - int nx = r->x, ny = r->y; pnormalize(&nx, &ny, pl); @@ -1750,7 +1565,6 @@ report_computer(const char *filename, report_context * ctx, const char *charset) a = a_find(f->attribs, &at_reportspell); while (a && a->type == &at_reportspell) { spell *sp = (spell *) a->data.v; - cr_reportspell(F, sp, f->locale); a = a->next; } @@ -1759,7 +1573,6 @@ report_computer(const char *filename, report_context * ctx, const char *charset) const potion_type *ptype = resource2potion(((const item_type *)a->data.v)->rtype); const char *ch; - const char *description = NULL; if (ptype == NULL) @@ -1772,9 +1585,7 @@ report_computer(const char *filename, report_context * ctx, const char *charset) if (description == NULL) { const char *pname = resourcename(ptype->itype->rtype, 0); - const char *potiontext = mkname("potion", pname); - description = LOC(f->locale, potiontext); } @@ -1810,7 +1621,6 @@ report_computer(const char *filename, report_context * ctx, const char *charset) int crwritemap(const char *filename) { FILE *F = fopen(filename, "w"); - region *r; fprintf(F, "VERSION %d\n", C_REPORT_VERSION); @@ -1818,9 +1628,7 @@ int crwritemap(const char *filename) for (r = regions; r; r = r->next) { plane *pl = rplane(r); - int plid = plane_id(pl); - if (plid) { fprintf(F, "REGION %d %d %d\n", r->x, r->y, plid); } else { @@ -1863,7 +1671,6 @@ void creport_cleanup(void) { while (junkyard) { translation *t = junkyard; - junkyard = junkyard->next; free(t); } diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index c7c31d5ef..dd97be767 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -94,13 +94,10 @@ typedef struct request { static int working; static request entertainers[1024]; - static request *nextentertainer; - static int entertaining; static int norders; - static request *oa; #define RECRUIT_MERGE 1 @@ -140,13 +137,10 @@ int income(const unit * u) static void scramble(void *data, int n, size_t width) { int j; - char temp[64]; - assert(width <= sizeof(temp)); for (j = 0; j != n; ++j) { int k = rng_int() % n; - if (k == j) continue; memcpy(temp, (char *)data + j * width, width); @@ -158,7 +152,6 @@ static void scramble(void *data, int n, size_t width) static void expandorders(region * r, request * requests) { unit *u; - request *o; /* Alle Units ohne request haben ein -1, alle units mit orders haben ein @@ -177,12 +170,10 @@ static void expandorders(region * r, request * requests) if (norders > 0) { int i = 0; - oa = (request *) calloc(norders, sizeof(request)); for (o = requests; o; o = o->next) { if (o->qty > 0) { int j; - for (j = o->qty; j; j--) { oa[i] = *o; oa[i].unit->n = 0; @@ -196,7 +187,6 @@ static void expandorders(region * r, request * requests) } while (requests) { request *o = requests->next; - free_order(requests->ord); free(requests); requests = o; @@ -208,7 +198,6 @@ static void expandorders(region * r, request * requests) static void change_level(unit * u, skill_t sk, int bylevel) { skill *sv = get_skill(u, sk); - assert(bylevel > 0); if (sv == 0) sv = add_skill(u, sk); @@ -229,13 +218,9 @@ static recruitment *select_recruitment(request ** rop, while (*rop) { recruitment *rec = recruits; - request *ro = *rop; - unit *u = ro->unit; - const race *rc = u->race; - int qty = quantify(rc, ro->qty); if (qty < 0) { @@ -265,11 +250,9 @@ static recruitment *select_recruitment(request ** rop, static void add_recruits(unit * u, int number, int wanted) { region *r = u->region; - assert(number <= wanted); if (number > 0) { unit *unew; - char equipment[64]; if (u->number == 0) { @@ -283,7 +266,6 @@ static void add_recruits(unit * u, int number, int wanted) snprintf(equipment, sizeof(equipment), "new_%s_unit", u->race->_name[0]); equip_unit(unew, get_equipment(equipment)); - if (unew->race->ec_flags & ECF_REC_HORSES) { change_level(unew, SK_RIDING, 1); } @@ -325,17 +307,14 @@ static int horse_recruiters(const struct race *rc, int qty) static int do_recruiting(recruitment * recruits, int available) { recruitment *rec; - int recruited = 0; while (available > 0) { int n = 0; - int rest, mintotal = INT_MAX; for (rec = recruits; rec != NULL; rec = rec->next) { int want = rec->total - rec->assigned; - if (want > 0) { if (mintotal > want) mintotal = want; @@ -354,7 +333,6 @@ static int do_recruiting(recruitment * recruits, int available) if (want > 0) { int get = mintotal; - if (want > mintotal && rest < n && (rng_int() % n) < rest) { --rest; ++get; @@ -368,16 +346,12 @@ static int do_recruiting(recruitment * recruits, int available) for (rec = recruits; rec != NULL; rec = rec->next) { request *req; - int get = rec->assigned; for (req = rec->requests; req; req = req->next) { unit *u = req->unit; - const race *rc = u->race; /* race is set in recruit() */ - int number, dec; - float multi = 2.0F * rc->recruit_multi; number = MIN(req->qty, (int)(get / multi)); @@ -419,7 +393,6 @@ static boolean check_give(unit * u, unit * u2, const item_type * itype, if (u2) { if (u->faction != u2->faction) { int rule = rule_give(); - if (itype) { assert(mask == 0); if (itype->rtype->ltype) @@ -433,7 +406,6 @@ static boolean check_give(unit * u, unit * u2, const item_type * itype, } } else { int rule = rule_give(); - return (rule & GIVE_PEASANTS) != 0; } return true; @@ -443,11 +415,9 @@ void free_recruitments(recruitment * recruits) { while (recruits) { recruitment *rec = recruits; - recruits = rec->next; while (rec->requests) { request *req = rec->requests; - rec->requests = req->next; free(req); } @@ -466,7 +436,6 @@ static void expandrecruit(region * r, request * recruitorders) recruits = select_recruitment(&recruitorders, horse_recruiters, &orc_total); if (recruits) { int recruited, horses = rhorses(r) * 2; - if (orc_total < horses) horses = orc_total; recruited = do_recruiting(recruits, horses); @@ -478,9 +447,7 @@ static void expandrecruit(region * r, request * recruitorders) recruits = select_recruitment(&recruitorders, peasant_recruiters, &orc_total); if (recruits) { int orc_recruited, orc_peasants = rpeasants(r) * 2; - int orc_frac = orc_peasants / RECRUITFRACTION; /* anzahl orks. 2 ork = 1 bauer */ - if (orc_total < orc_frac) orc_frac = orc_total; orc_recruited = do_recruiting(recruits, orc_frac); @@ -493,7 +460,6 @@ static void expandrecruit(region * r, request * recruitorders) recruits = select_recruitment(&recruitorders, any_recruiters, &orc_total); if (recruits) { int recruited, peasants = rpeasants(r); - recruited = do_recruiting(recruits, INT_MAX); if (recruited > 0) { rsetpeasants(r, peasants - recruited / 2); @@ -518,19 +484,12 @@ static int recruit_cost(const faction * f, const race * rc) static void recruit(unit * u, struct order *ord, request ** recruitorders) { int n; - region *r = u->region; - plane *pl; - request *o; - int recruitcost = -1; - const faction *f = u->faction; - const struct race *rc = u->race; - const char *str; init_tokens(ord); @@ -567,12 +526,10 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders) if (rc == new_race[RC_INSECT]) { gamedate date; - get_gamedate(turn, &date); if (date.season == 0 && r->terrain != newterrain(T_DESERT)) { #ifdef INSECT_POTION boolean usepotion = false; - unit *u2; for (u2 = r->units; u2; u2 = u2->next) @@ -659,7 +616,6 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders) static void friendly_takeover(region * r, faction * f) { int morale = region_get_morale(r); - region_set_owner(r, f, turn); if (morale > 0) { morale = MAX(0, morale - MORALE_TRANSFER); @@ -671,12 +627,9 @@ static void give_control(unit * u, unit * u2) { if (u->building && u->faction != u2->faction && rule_region_owners()) { region *r = u->region; - faction *f = region_get_owner(r); - if (f == u->faction) { building *b = largestbuilding(r, &cmp_current_owner, false); - if (b == u->building) { friendly_takeover(r, u2->faction); } @@ -689,11 +642,8 @@ static void give_control(unit * u, unit * u2) int give_control_cmd(unit * u, order * ord) { region *r = u->region; - unit *u2; - const char *s; - param_t p; init_tokens(ord); @@ -734,17 +684,11 @@ int give_control_cmd(unit * u, order * ord) static void give_cmd(unit * u, order * ord) { region *r = u->region; - unit *u2; - const char *s; - int i, n; - const item_type *itype; - param_t p; - plane *pl; init_tokens(ord); @@ -804,7 +748,6 @@ static void give_cmd(unit * u, order * ord) else if (p == P_HERBS) { boolean given = false; - if (!(u->race->ec_flags & GIVEITEM) && u2 != NULL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_nogive", "race", u->race)); @@ -828,12 +771,9 @@ static void give_cmd(unit * u, order * ord) } if (u->items) { item **itmp = &u->items; - while (*itmp) { item *itm = *itmp; - const item_type *itype = itm->type; - if (fval(itype, ITF_HERB) && itm->number > 0) { /* give_item ändert im fall,das man alles übergibt, die * item-liste der unit, darum continue vor pointerumsetzten */ @@ -893,12 +833,9 @@ static void give_cmd(unit * u, order * ord) * reserviert ist besitzen und diesen Teil dann übergeben */ if (u->items) { item **itmp = &u->items; - while (*itmp) { item *itm = *itmp; - const item_type *itype = itm->type; - if (itm->number > 0 && itm->number - get_reservation(u, itype->rtype) > 0) { n = itm->number - get_reservation(u, itype->rtype); @@ -939,7 +876,6 @@ static void give_cmd(unit * u, order * ord) itype = finditemtype(s, u->faction->locale); if (itype != NULL) { item *i = *i_find(&u->items, itype); - if (i != NULL) { if (check_give(u, u2, itype, 0)) { n = i->number - get_reservation(u, itype->rtype); @@ -1010,7 +946,6 @@ static void give_cmd(unit * u, order * ord) static int forget_cmd(unit * u, order * ord) { skill_t sk; - const char *s; if (is_cursed(u->attribs, C_SLAVE, 0)) { @@ -1055,13 +990,9 @@ static boolean maintain(building * b, boolean first) /* first==false -> take money from wherever you can */ { int c; - region *r = b->region; - boolean paid = true, work = first; - unit *u; - if (fval(b, BLD_MAINTAINED) || b->type == NULL || b->type->maintenance == NULL || is_cursed(b->attribs, C_NOCOST, 0)) { fset(b, BLD_MAINTAINED); @@ -1076,7 +1007,6 @@ static boolean maintain(building * b, boolean first) return false; for (c = 0; b->type->maintenance[c].number; ++c) { const maintenance *m = b->type->maintenance + c; - int need = m->number; if (fval(m, MTF_VARIABLE)) @@ -1091,7 +1021,6 @@ static boolean maintain(building * b, boolean first) need -= get_pooled(u, m->rtype, GET_DEFAULT, need); if (!first && need > 0) { unit *ua; - for (ua = r->units; ua; ua = ua->next) freset(ua->faction, FFL_SELECT); fset(u->faction, FFL_SELECT); /* hat schon */ @@ -1129,7 +1058,6 @@ static boolean maintain(building * b, boolean first) } for (c = 0; b->type->maintenance[c].number; ++c) { const maintenance *m = b->type->maintenance + c; - int cost = m->number; if (!fval(m, MTF_VITAL) && !work) @@ -1145,7 +1073,6 @@ static boolean maintain(building * b, boolean first) cost); if (!first && cost > 0) { unit *ua; - for (ua = r->units; ua; ua = ua->next) freset(ua->faction, FFL_SELECT); fset(u->faction, FFL_SELECT); /* hat schon */ @@ -1153,7 +1080,6 @@ static boolean maintain(building * b, boolean first) if (!fval(ua->faction, FFL_SELECT) && alliedunit(ua, u->faction, HELP_MONEY)) { int give = use_pooled(ua, m->rtype, GET_ALL, cost); - if (!give) continue; cost -= give; @@ -1179,13 +1105,9 @@ static boolean maintain(building * b, boolean first) static void gebaeude_stuerzt_ein(region * r, building * b) { unit *u; - int n, i; - int opfer = 0; - int road = 0; - struct message *msg; for (u = r->units; u; u = u->next) { @@ -1214,7 +1136,6 @@ static void gebaeude_stuerzt_ein(region * r, building * b) add_message(&r->msgs, msg); for (u = r->units; u; u = u->next) { faction *f = u->faction; - if (fval(f, FFL_MARK)) { freset(u->faction, FFL_MARK); add_message(&f->msgs, msg); @@ -1228,10 +1149,8 @@ static void gebaeude_stuerzt_ein(region * r, building * b) void maintain_buildings(region * r, boolean crash) { building **bp = &r->buildings; - while (*bp) { building *b = *bp; - boolean maintained = maintain(b, !crash); /* the second time, send a message */ @@ -1244,7 +1163,6 @@ void maintain_buildings(region * r, boolean crash) #endif if (!fval(b, BLD_WORKING)) { unit *u = building_owner(b); - const char *msgtype = maintained ? "maintenance_nowork" : "maintenance_none"; struct message *msg = msg_message(msgtype, "building", b); @@ -1265,9 +1183,7 @@ void maintain_buildings(region * r, boolean crash) static int recruit_archetype(unit * u, order * ord) { boolean merge = (u->number > 0); - int want; - const char *s; if (rules_recruit < 0) @@ -1279,9 +1195,7 @@ static int recruit_archetype(unit * u, order * ord) s = getstrtoken(); if (want > 0 && s && s[0]) { int n = want; - const archetype *arch = find_archetype(s, u->faction->locale); - attrib *a = NULL; if ((rules_recruit & RECRUIT_MERGE) == 0 && merge) { @@ -1304,21 +1218,17 @@ static int recruit_archetype(unit * u, order * ord) * for each failed rule. */ int k; - for (k = 0; arch->rules[k].property; ++k) { boolean match = false; - if (arch->rules[k].value[0] == '*') match = true; else if (strcmp(arch->rules[k].property, "race") == 0) { const race *rc = rc_find(arch->rules[k].value); - assert(rc); if (rc == u->race) match = true; } else if (strcmp(arch->rules[k].property, "building") == 0) { const building_type *btype = bt_find(arch->rules[k].value); - assert(btype); if (u->building && u->building->type == btype) match = true; @@ -1345,9 +1255,7 @@ static int recruit_archetype(unit * u, order * ord) } if (arch->size) { int maxsize = u->building->size; - attrib *a = a_find(u->building->attribs, &at_recruit); - if (a != NULL) { maxsize -= a->data.i; } @@ -1364,7 +1272,6 @@ static int recruit_archetype(unit * u, order * ord) n = build(u, arch->ctype, 0, n); if (n > 0) { unit *u2; - if (merge) { u2 = create_unit(u->region, u->faction, 0, u->race, 0, 0, u); } else { @@ -1422,7 +1329,6 @@ int recruit_archetypes(void) void economics(region * r) { unit *u; - request *recruitorders = NULL; /* Geben vor Selbstmord (doquit)! Hier alle unmittelbaren Befehle. @@ -1431,9 +1337,7 @@ void economics(region * r) for (u = r->units; u; u = u->next) { order *ord; - boolean destroyed = false; - if (u->number > 0) { for (ord = u->orders; ord; ord = ord->next) { switch (get_keyword(ord)) { @@ -1491,15 +1395,11 @@ void economics(region * r) /* ------------------------------------------------------------- */ - static void manufacture(unit * u, const item_type * itype, int want) { int n; - int skill; - int minskill = itype->construction->minskill; - skill_t sk = itype->construction->skill; skill = effskill(u, sk); @@ -1509,7 +1409,6 @@ static void manufacture(unit * u, const item_type * itype, int want) if (skill < 0) { /* an error occured */ int err = -skill; - cmistake(u, u->thisorder, err, MSG_PRODUCE); return; } @@ -1558,7 +1457,6 @@ typedef struct allocation { unsigned int flags; unit *unit; } allocation; - #define new_allocation() calloc(sizeof(allocation), 1) #define free_allocation(a) free(a) @@ -1591,21 +1489,13 @@ enum { static void allocate_resource(unit * u, const resource_type * rtype, int want) { const item_type *itype = resource2item(rtype); - region *r = u->region; - int busy = u->number; - int dm = 0; - allocation_list *alist; - allocation *al; - attrib *a = a_find(rtype->attribs, &at_resourcelimit); - resource_limit *rdata = (resource_limit *) a->data.v; - int amount, skill; /* momentan kann man keine ressourcen abbauen, wenn man dafür @@ -1616,7 +1506,6 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) if (rdata->limit != NULL) { int avail = rdata->limit(r, rtype); - if (avail <= 0) { cmistake(u, u->thisorder, 121, MSG_PRODUCE); return; @@ -1630,13 +1519,10 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) if (rdata->modifiers) { resource_mod *mod = rdata->modifiers; - for (; mod->flags != 0; ++mod) { if (mod->flags & RMF_REQUIREDBUILDING) { struct building *b = inside_building(u); - const struct building_type *btype = b ? b->type : NULL; - if (mod->btype && mod->btype != btype) { cmistake(u, u->thisorder, 104, MSG_PRODUCE); return; @@ -1647,7 +1533,6 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) if (rdata->guard != 0) { unit *u2; - for (u2 = r->units; u2; u2 = u2->next) { if (is_guard(u2, rdata->guard) != 0 && can_guard(u2, u)) { ADDMSG(&u->faction->msgs, @@ -1663,7 +1548,6 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) */ if (itype == olditemtype[I_IRON] || itype == olditemtype[I_LAEN]) { unit *u2; - for (u2 = r->units; u2; u2 = u2->next) { if (is_guard(u, GUARD_MINING) && !fval(u2, UFL_ISNEW) @@ -1680,14 +1564,12 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) skill = eff_skill(u, itype->construction->skill, u->region); if (skill == 0) { skill_t sk = itype->construction->skill; - add_message(&u->faction->msgs, msg_feedback(u, u->thisorder, "skill_needed", "skill", sk)); return; } if (skill < itype->construction->minskill) { skill_t sk = itype->construction->skill; - add_message(&u->faction->msgs, msg_feedback(u, u->thisorder, "manufacture_skills", "skill minskill product", sk, itype->construction->minskill, @@ -1695,12 +1577,10 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) return; } else { struct building *b = inside_building(u); - const struct building_type *btype = b ? b->type : NULL; if (rdata->modifiers) { resource_mod *mod = rdata->modifiers; - for (; mod->flags != 0; ++mod) { if (mod->flags & RMF_SKILL) { if (mod->btype == NULL || mod->btype == btype) { @@ -1753,11 +1633,9 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) if (rdata->modifiers) { struct building *b = inside_building(u); - const struct building_type *btype = b ? b->type : NULL; resource_mod *mod = rdata->modifiers; - for (; mod->flags != 0; ++mod) { if (mod->flags & RMF_SAVEMATERIAL) { if (mod->btype == NULL || mod->btype == btype) { @@ -1773,7 +1651,6 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) static int required(int want, double save) { int norders = (int)(want * save); - if (norders < want * save) ++norders; return norders; @@ -1783,19 +1660,14 @@ static void leveled_allocation(const resource_type * rtype, region * r, allocation * alist) { const item_type *itype = resource2item(rtype); - rawmaterial *rm = rm_get(r, rtype); - int need; - boolean first = true; if (rm != NULL) { do { int avail = rm->amount; - int norders = 0; - allocation *al; if (avail <= 0) { @@ -1810,7 +1682,6 @@ leveled_allocation(const resource_type * rtype, region * r, allocation * alist) for (al = alist; al; al = al->next) if (!fval(al, AFL_DONE)) { int req = required(al->want - al->get, al->save); - assert(al->get <= al->want && al->get >= 0); if (eff_skill(al->unit, itype->construction->skill, r) >= rm->level + itype->construction->minskill - 1) { @@ -1830,14 +1701,11 @@ leveled_allocation(const resource_type * rtype, region * r, allocation * alist) avail = MIN(avail, norders); if (need > 0) { int use = 0; - for (al = alist; al; al = al->next) if (!fval(al, AFL_DONE)) { if (avail > 0) { int want = required(al->want - al->get, al->save); - int x = avail * want / norders; - /* Wenn Rest, dann würfeln, ob ich was bekomme: */ if (rng_int() % norders < (avail * want) % norders) ++x; @@ -1863,13 +1731,9 @@ static void attrib_allocation(const resource_type * rtype, region * r, allocation * alist) { allocation *al; - int norders = 0; - attrib *a = a_find(rtype->attribs, &at_resourcelimit); - resource_limit *rdata = (resource_limit *) a->data.v; - int avail = rdata->value; for (al = alist; al; al = al->next) { @@ -1886,9 +1750,7 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist) for (al = alist; al; al = al->next) { if (avail > 0) { int want = required(al->want, al->save); - int x = avail * want / norders; - /* Wenn Rest, dann würfeln, ob ich was bekomme: */ if (rng_int() % norders < (avail * want) % norders) ++x; @@ -1897,7 +1759,6 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist) al->get = MIN(al->want, (int)(x / al->save)); if (rdata->produce) { int use = required(al->get, al->save); - if (use) rdata->produce(r, rtype, use); } @@ -1915,7 +1776,6 @@ static allocate_function get_allocator(const struct resource_type *rtype) if (a != NULL) { resource_limit *rdata = (resource_limit *) a->data.v; - if (rdata->value > 0 || rdata->limit != NULL) { return attrib_allocation; } @@ -1927,17 +1787,12 @@ static allocate_function get_allocator(const struct resource_type *rtype) void split_allocations(region * r) { allocation_list **p_alist = &allocations; - freset(r, RF_SELECT); while (*p_alist) { allocation_list *alist = *p_alist; - const resource_type *rtype = alist->type; - allocate_function alloc = get_allocator(rtype); - const item_type *itype = resource2item(rtype); - allocation **p_al = &alist->data; freset(r, RF_SELECT); @@ -1945,7 +1800,6 @@ void split_allocations(region * r) while (*p_al) { allocation *al = *p_al; - if (al->get) { assert(itype || !"not implemented for non-items"); i_change(&al->unit->items, itype, al->get); @@ -2017,7 +1871,6 @@ static void create_item(unit * u, const item_type * itype, int want) allocate_resource(u, itype->rtype, want); } else { const potion_type *ptype = resource2potion(itype->rtype); - if (ptype != NULL) create_potion(u, ptype, want); else if (itype->construction && itype->construction->materials) @@ -2032,21 +1885,13 @@ static void create_item(unit * u, const item_type * itype, int want) int make_cmd(unit * u, struct order *ord) { region *r = u->region; - const building_type *btype; - const ship_type *stype; - param_t p; - int m; - const item_type *itype; - const char *s; - const struct locale *lang = u->faction->locale; - char ibuf[16]; init_tokens(ord); @@ -2070,12 +1915,10 @@ int make_cmd(unit * u, struct order *ord) if (p == P_ROAD) { plane *pl = rplane(r); - if (pl && fval(pl, PFL_NOBUILD)) { cmistake(u, ord, 275, MSG_PRODUCE); } else { direction_t d = finddirection(getstrtoken(), u->faction->locale); - if (d != NODIRECTION) { build_road(r, u, m, d); } else { @@ -2086,7 +1929,6 @@ int make_cmd(unit * u, struct order *ord) return 0; } else if (p == P_SHIP) { plane *pl = rplane(r); - if (pl && fval(pl, PFL_NOBUILD)) { cmistake(u, ord, 276, MSG_PRODUCE); } else { @@ -2112,18 +1954,14 @@ int make_cmd(unit * u, struct order *ord) itype = NULL; } else if (stype != NULL) { const char *sname = LOC(lang, stype->name[0]); - const char *iname = LOC(lang, resourcename(itype->rtype, 0)); - if (strlen(iname) < strlen(sname)) stype = NULL; else itype = NULL; } else { const char *bname = LOC(lang, btype->_name); - const char *iname = LOC(lang, resourcename(itype->rtype, 0)); - if (strlen(iname) < strlen(bname)) btype = NULL; else @@ -2133,9 +1971,7 @@ int make_cmd(unit * u, struct order *ord) if (btype != NULL && stype != NULL) { const char *bname = LOC(lang, btype->_name); - const char *sname = LOC(lang, stype->name[0]); - if (strlen(sname) < strlen(bname)) btype = NULL; else @@ -2144,7 +1980,6 @@ int make_cmd(unit * u, struct order *ord) if (stype != NOSHIP) { plane *pl = rplane(r); - if (pl && fval(pl, PFL_NOBUILD)) { cmistake(u, ord, 276, MSG_PRODUCE); } else { @@ -2152,7 +1987,6 @@ int make_cmd(unit * u, struct order *ord) } } else if (btype != NOBUILDING) { plane *pl = rplane(r); - if (pl && fval(pl, PFL_NOBUILD)) { cmistake(u, ord, 94, MSG_PRODUCE); } else { @@ -2172,7 +2006,6 @@ int make_cmd(unit * u, struct order *ord) static void free_luxuries(struct attrib *a) { item *itm = (item *) a->data.v; - a->data.v = NULL; i_freeall(&itm); } @@ -2184,19 +2017,14 @@ const attrib_type at_luxuries = { static void expandbuying(region * r, request * buyorders) { int max_products; - unit *u; - static struct trade { const luxury_type *type; int number; int multi; } *trades, *trade; - static int ntrades = 0; - int i, j; - const luxury_type *ltype; if (ntrades == 0) { @@ -2232,7 +2060,6 @@ static void expandbuying(region * r, request * buyorders) for (j = 0; j != norders; j++) { int price, multi; - ltype = oa[j].type.ltype; trade = trades; while (trade->type != ltype) @@ -2243,7 +2070,6 @@ static void expandbuying(region * r, request * buyorders) if (get_pooled(oa[j].unit, oldresourcetype[R_SILVER], GET_DEFAULT, price) >= price) { unit *u = oa[j].unit; - item *items; /* litems zählt die Güter, die verkauft wurden, u->n das Geld, das @@ -2251,7 +2077,6 @@ static void expandbuying(region * r, request * buyorders) * man sich also das verdiente Geld und die verkauften Produkte separat * merken muß. */ attrib *a = a_find(u->attribs, &at_luxuries); - if (a == NULL) a = a_add(&u->attribs, a_new(&at_luxuries)); @@ -2282,9 +2107,7 @@ static void expandbuying(region * r, request * buyorders) for (u = r->units; u; u = u->next) { attrib *a = a_find(u->attribs, &at_luxuries); - item *itm; - if (a == NULL) continue; ADDMSG(&u->faction->msgs, msg_message("buy", "unit money", u, u->n)); @@ -2311,17 +2134,11 @@ attrib_type at_trades = { static void buy(unit * u, request ** buyorders, struct order *ord) { region *r = u->region; - int n, k; - request *o; - attrib *a; - const item_type *itype = NULL; - const luxury_type *ltype = NULL; - if (u->ship && is_guarded(r, u, GUARD_CREWS)) { cmistake(u, ord, 69, MSG_INCOME); return; @@ -2356,9 +2173,7 @@ static void buy(unit * u, request ** buyorders, struct order *ord) } else { /* ...oder in der Region muß es eine Burg geben. */ building *b; - static const struct building_type *bt_castle; - if (!bt_castle) bt_castle = bt_find("castle"); for (b = r->buildings; b; b = b->next) { @@ -2422,31 +2237,20 @@ static int tax_per_size[7] = { 0, 6, 12, 18, 24, 30, 36 }; static void expandselling(region * r, request * sellorders, int limit) { int money, price, j, max_products; - /* int m, n = 0; */ int maxsize = 0, maxeffsize = 0; - int taxcollected = 0; - int hafencollected = 0; - unit *maxowner = (unit *) NULL; - building *maxb = (building *) NULL; - building *b; - unit *u; - unit *hafenowner; - static int *counter; - static int ncounter = 0; if (ncounter == 0) { const luxury_type *ltype; - for (ltype = luxurytypes; ltype; ltype = ltype->next) ++ncounter; counter = (int *)gc_add(calloc(sizeof(int), ncounter)); @@ -2506,15 +2310,10 @@ static void expandselling(region * r, request * sellorders, int limit) for (j = 0; j != norders; j++) { static const luxury_type *search = NULL; - const luxury_type *ltype = oa[j].type.ltype; - int multi = r_demand(r, ltype); - static int i = -1; - int use = 0; - if (search != ltype) { i = 0; for (search = luxurytypes; search != ltype; search = search->next) @@ -2528,15 +2327,10 @@ static void expandselling(region * r, request * sellorders, int limit) if (money >= price) { int abgezogenhafen = 0; - int abgezogensteuer = 0; - unit *u = oa[j].unit; - item *itm; - attrib *a = a_find(u->attribs, &at_luxuries); - if (a == NULL) a = a_add(&u->attribs, a_new(&at_luxuries)); itm = (item *) a->data.v; @@ -2575,7 +2369,6 @@ static void expandselling(region * r, request * sellorders, int limit) if (++counter[i] > max_products) { int d = r_demand(r, ltype); - if (d > 1) { r_setdemand(r, ltype, d - 1); } @@ -2616,9 +2409,7 @@ static void expandselling(region * r, request * sellorders, int limit) for (u = r->units; u; u = u->next) { attrib *a = a_find(u->attribs, &at_luxuries); - item *itm; - if (a == NULL) continue; for (itm = (item *) a->data.v; itm; itm = itm->next) { @@ -2635,15 +2426,10 @@ static void expandselling(region * r, request * sellorders, int limit) static boolean sell(unit * u, request ** sellorders, struct order *ord) { boolean unlimited = true; - const item_type *itype; - const luxury_type *ltype = NULL; - int n; - region *r = u->region; - const char *s; if (u->ship && is_guarded(r, u, GUARD_CREWS)) { @@ -2691,9 +2477,7 @@ static boolean sell(unit * u, request ** sellorders, struct order *ord) } else { /* ...oder in der Region muß es eine Burg geben. */ building *b; - static const struct building_type *bt_castle; - if (!bt_castle) bt_castle = bt_find("castle"); for (b = r->buildings; b; b = b->next) { @@ -2723,9 +2507,7 @@ static boolean sell(unit * u, request ** sellorders, struct order *ord) return false; } else { attrib *a; - request *o; - int k, available; if (!r_demand(r, ltype)) { @@ -2800,18 +2582,14 @@ static void expandstealing(region * r, request * stealorders) for (i = 0; i != norders && oa[i].unit->n <= oa[i].unit->wants; i++) { unit *u = findunitg(oa[i].no, r); - int n = 0; - if (u && u->region == r) { n = get_pooled(u, r_silver, GET_ALL, INT_MAX); } #ifndef GOBLINKILL if (oa[i].type.goblin) { /* Goblin-Spezialklau */ int uct = 0; - unit *u2; - assert(effskill(oa[i].unit, SK_STEALTH) >= 4 || !"this goblin\'s skill is too low"); for (u2 = r->units; u2; u2 = u2->next) { @@ -2844,11 +2622,8 @@ static void expandstealing(region * r, request * stealorders) static void plant(region * r, unit * u, int raw) { int n, i, skill, planted = 0; - const item_type *itype; - static const resource_type *rt_water = NULL; - if (rt_water == NULL) rt_water = rt_find("p2"); @@ -2905,7 +2680,6 @@ static void plant(region * r, unit * u, int raw) static void planttrees(region * r, unit * u, int raw) { int n, i, skill, planted = 0; - const resource_type *rtype; if (!fval(r->terrain, LAND_REGION)) { @@ -2963,16 +2737,12 @@ static void planttrees(region * r, unit * u, int raw) static void breedtrees(region * r, unit * u, int raw) { int n, i, skill, planted = 0; - const resource_type *rtype; - static int gamecookie = -1; - static int current_season; if (gamecookie != global.cookie) { gamedate date; - get_gamedate(turn, &date); current_season = date.season; gamecookie = global.cookie; @@ -3032,11 +2802,8 @@ static void breedtrees(region * r, unit * u, int raw) static void breedhorses(region * r, unit * u) { int n, c; - int gezuechtet = 0; - struct building *b = inside_building(u); - const struct building_type *btype = b ? b->type : NULL; if (btype != bt_find("stables")) { @@ -3065,13 +2832,9 @@ static void breedhorses(region * r, unit * u) static void breed_cmd(unit * u, struct order *ord) { int m; - const char *s; - param_t p; - region *r = u->region; - const resource_type *rtype = NULL; if (r->land == NULL) { @@ -3176,7 +2939,6 @@ static void research_cmd(unit * u, struct order *ord) static int max_skill(region * r, faction * f, skill_t sk) { unit *u; - int w = 0; for (u = r->units; u; u = u->next) { @@ -3193,17 +2955,11 @@ static int max_skill(region * r, faction * f, skill_t sk) static void steal_cmd(unit * u, struct order *ord, request ** stealorders) { int n, i, id; - boolean goblin = false; - request *o; - unit *u2 = NULL; - region *r = u->region; - faction *f = NULL; - plane *pl; assert(skill_enabled[SK_PERCEPTION] && skill_enabled[SK_STEALTH]); @@ -3313,18 +3069,14 @@ static void steal_cmd(unit * u, struct order *ord, request ** stealorders) /* ------------------------------------------------------------- */ - static void expandentertainment(region * r) { unit *u; - int m = entertainmoney(r); - request *o; for (o = &entertainers[0]; o != nextentertainer; ++o) { double part = m / (double)entertaining; - u = o->unit; if (entertaining <= m) u->n = o->qty; @@ -3345,23 +3097,17 @@ static void expandentertainment(region * r) void entertain_cmd(unit * u, struct order *ord) { region *r = u->region; - int max_e; - request *o; - static int entertainbase = 0; - static int entertainperlevel = 0; if (!entertainbase) { const char *str = get_param(global.parameters, "entertain.base"); - entertainbase = str ? atoi(str) : 0; } if (!entertainperlevel) { const char *str = get_param(global.parameters, "entertain.perlevel"); - entertainperlevel = str ? atoi(str) : 0; } if (fval(u, UFL_WERE)) { @@ -3407,20 +3153,15 @@ static void expandwork(region * r, request * work_begin, request * work_end, int maxwork) { int earnings; - /* n: verbleibende Einnahmen */ /* fishes: maximale Arbeiter */ int jobs = maxwork; - int p_wage = wage(r, NULL, NULL, turn); - int money = rmoney(r); - request *o; for (o = work_begin; o != work_end; ++o) { unit *u = o->unit; - int workers; if (u->number == 0) @@ -3454,7 +3195,6 @@ expandwork(region * r, request * work_begin, request * work_end, int maxwork) if (rule_blessed_harvest() == HARVEST_TAXES) { /* E3 rules */ static const curse_type *blessedharvest_ct; - if (!blessedharvest_ct) { blessedharvest_ct = ct_find("blessedharvest"); } @@ -3472,7 +3212,6 @@ static int do_work(unit * u, order * ord, request * o) { if (playerrace(u->race)) { region *r = u->region; - int w; if (fval(u, UFL_WERE)) { @@ -3506,7 +3245,6 @@ static int do_work(unit * u, order * ord, request * o) static void expandtax(region * r, request * taxorders) { unit *u; - int i; expandorders(r, taxorders); @@ -3532,13 +3270,9 @@ void tax_cmd(unit * u, struct order *ord, request ** taxorders) { /* Steuern werden noch vor der Forschung eingetrieben */ region *r = u->region; - unit *u2; - int n; - request *o; - int max; if (!humanoidrace(u->race) && !is_monsters(u->faction)) { @@ -3596,9 +3330,7 @@ void tax_cmd(unit * u, struct order *ord, request ** taxorders) void auto_work(region * r) { request workers[MAX_WORKERS]; - request *nextworker = workers; - unit *u; for (u = r->units; u; u = u->next) { @@ -3617,13 +3349,9 @@ void auto_work(region * r) static void peasant_taxes(region * r) { faction *f; - unit *u; - building *b; - int money; - int maxsize; f = region_get_owner(r); @@ -3645,14 +3373,11 @@ static void peasant_taxes(region * r) maxsize = buildingeffsize(b, false); if (maxsize > 0) { double taxfactor = money * b->type->taxes(b, maxsize); - double morale = money * region_get_morale(r) * MORALE_TAX_FACTOR; - if (taxfactor > morale) taxfactor = morale; if (taxfactor > 0) { int taxmoney = (int)taxfactor; - change_money(u, taxmoney); rsetmoney(r, money - taxmoney); ADDMSG(&u->faction->msgs, msg_message("income_tax", @@ -3664,19 +3389,12 @@ static void peasant_taxes(region * r) void produce(struct region *r) { request workers[MAX_WORKERS]; - request *taxorders, *sellorders, *stealorders, *buyorders; - unit *u; - int todo; - static int rule_autowork = -1; - boolean limited = true; - request *nextworker = workers; - assert(r); /* das sind alles befehle, die 30 tage brauchen, und die in thisorder @@ -3711,7 +3429,6 @@ void produce(struct region *r) for (u = r->units; u; u = u->next) { order *ord; - boolean trader = false; if (u->race == new_race[RC_SPELL] || fval(u, UFL_LONGACTION)) @@ -3744,7 +3461,6 @@ void produce(struct region *r) } if (trader) { attrib *a = a_find(u->attribs, &at_trades); - if (a && a->data.i) { produceexp(u, SK_TRADE, u->number); } @@ -3822,7 +3538,6 @@ void produce(struct region *r) if (sellorders) { int limit = rpeasants(r) / TRADE_FRACTION; - if (r->terrain == newterrain(T_DESERT) && buildingtype_exists(r, bt_find("caravan"), true)) limit *= 2; diff --git a/src/gamecode/give.c b/src/gamecode/give.c index 88cfc637b..25e735812 100644 --- a/src/gamecode/give.c +++ b/src/gamecode/give.c @@ -51,14 +51,11 @@ #define RESERVE_DONATIONS /* shall we reserve objects given to us by other factions? */ #define RESERVE_GIVE /* reserve anything that's given from one unit to another? */ - static int GiveRestriction(void) { static int value = -1; - if (value < 0) { const char *str = get_param(global.parameters, "GiveRestriction"); - value = str ? atoi(str) : 0; } return value; @@ -106,13 +103,11 @@ int give_quota(const unit * src, const unit * dst, const item_type * type, if (dst && src && src->faction != dst->faction) { if (divisor < 0) { divisor = get_param_flt(global.parameters, "rules.items.give_divisor", 1); - assert(divisor == 0 || divisor >= 1); } if (divisor >= 1) { /* predictable > correct: */ int x = (int)(n / divisor); - return x; } } @@ -124,7 +119,6 @@ give_item(int want, const item_type * itype, unit * src, unit * dest, struct order *ord) { short error = 0; - int n, r; assert(itype != NULL); @@ -140,7 +134,6 @@ give_item(int want, const item_type * itype, unit * src, unit * dest, return -1; } else if (n == 0) { int reserve = get_reservation(src, itype->rtype); - if (reserve) { msg_feedback(src, ord, "nogive_reserved", "resource reservation", itype->rtype, reserve); @@ -151,7 +144,6 @@ give_item(int want, const item_type * itype, unit * src, unit * dest, error = 25; } else if (itype->give == NULL || itype->give(src, dest, itype, n, ord) != 0) { int use = use_pooled(src, item2resource(itype), GET_SLACK, n); - if (use < n) use += use_pooled(src, item2resource(itype), GET_RESERVE | GET_POOLED_SLACK, @@ -187,9 +179,7 @@ give_item(int want, const item_type * itype, unit * src, unit * dest, void give_men(int n, unit * u, unit * u2, struct order *ord) { ship *sh; - int k = 0; - int error = 0; if (u2 && u->faction != u2->faction && u->faction->age < GiveRestriction()) { @@ -299,13 +289,10 @@ void give_men(int n, unit * u, unit * u2, struct order *ord) if (u2->number != 0 && recruit_archetypes()) { /* must have same set of skills */ boolean okay = false; - if (u->skill_size == u2->skill_size) { int i; - for (i = 0; i != u->skill_size; ++i) { int j; - for (j = 0; j != u2->skill_size; ++j) { if (u->skills[i].id == u2->skills[j].id) break; @@ -322,7 +309,6 @@ void give_men(int n, unit * u, unit * u2, struct order *ord) } } - /* Einheiten von Schiffen können nicht NACH in von * Nicht-alliierten bewachten Regionen ausführen */ sh = leftship(u); @@ -338,7 +324,6 @@ void give_men(int n, unit * u, unit * u2, struct order *ord) #ifdef ORCIFICATION if (u->race == new_race[RC_SNOTLING] && !fval(u->region, RF_ORCIFIED)) { attrib *a = a_find(u->region->attribs, &at_orcification); - if (!a) a = a_add(&u->region->attribs, a_new(&at_orcification)); a->data.i += n; @@ -357,7 +342,6 @@ void give_men(int n, unit * u, unit * u2, struct order *ord) msg_message("give_person_peasants", "unit amount", u, n)); } else if (u2->faction != u->faction) { message *msg = msg_message("give_person", "unit target amount", u, u2, n); - add_message(&u->faction->msgs, msg); add_message(&u2->faction->msgs, msg); msg_release(msg); @@ -367,7 +351,6 @@ void give_men(int n, unit * u, unit * u2, struct order *ord) void give_unit(unit * u, unit * u2, order * ord) { region *r = u->region; - int n = u->number; if (!rule_transfermen() && u->faction != u2->faction) { @@ -402,9 +385,7 @@ void give_unit(unit * u, unit * u2, order * ord) if (u3) { while (u->items) { item *iold = i_remove(&u->items, u->items); - item *inew = *i_find(&u3->items, iold->type); - if (inew == NULL) i_add(&u3->items, iold); else { @@ -452,7 +433,6 @@ void give_unit(unit * u, unit * u2, order * ord) } if (has_skill(u, SK_MAGIC)) { sc_mage *mage; - if (count_skill(u2->faction, SK_MAGIC) + u->number > skill_limit(u2->faction, SK_MAGIC)) { cmistake(u, ord, 155, MSG_COMMERCE); diff --git a/src/gamecode/items.c b/src/gamecode/items.c index 6058218b8..3c2767278 100644 --- a/src/gamecode/items.c +++ b/src/gamecode/items.c @@ -38,7 +38,6 @@ use_studypotion(struct unit *u, const struct item_type *itype, int amount, { if (get_keyword(u->thisorder) == K_STUDY) { skill_t sk; - skill *sv; init_tokens(u->thisorder); @@ -52,9 +51,7 @@ use_studypotion(struct unit *u, const struct item_type *itype, int amount, /* TODO: message */ } else { attrib *a = a_find(u->attribs, &at_learning); - teaching_info *teach; - if (a == NULL) { a = a_add(&u->attribs, a_new(&at_learning)); } @@ -81,11 +78,8 @@ use_speedsail(struct unit *u, const struct item_type *itype, int amount, struct order *ord) { curse *c; - double effect; - ship *sh = u->ship; - if (!sh) { cmistake(u, ord, 20, MSG_MOVE); return -1; @@ -114,9 +108,7 @@ use_antimagiccrystal(unit * u, const struct item_type *itype, int amount, struct order *ord) { region *r = u->region; - const resource_type *rt_crystal = NULL; - int i; if (rt_crystal == NULL) { @@ -125,13 +117,9 @@ use_antimagiccrystal(unit * u, const struct item_type *itype, int amount, } for (i = 0; i != amount; ++i) { int effect, duration = 2; - double force; - spell *sp = find_spell(M_NONE, "antimagiczone"); - attrib **ap = &r->attribs; - unused(ord); assert(sp); @@ -146,9 +134,7 @@ use_antimagiccrystal(unit * u, const struct item_type *itype, int amount, /* Regionszauber auflösen */ while (*ap && force > 0) { curse *c; - attrib *a = *ap; - if (!fval(a->type, ATF_CURSE)) { do { ap = &(*ap)->next; @@ -277,7 +263,6 @@ use_aurapotion50(struct unit *u, const struct item_type *itype, return 0; } - void register_itemfunctions(void) { register_demonseye(); diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index fd571e620..b9472dcf3 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -115,23 +115,18 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define DMRISE 0.1F /* weekly chance that demand goes up */ #define DMRISEHAFEN 0.2F /* weekly chance that demand goes up with harbor */ - /* - exported global symbols ----------------------------------- */ boolean nobattle = false; - boolean nomonsters = false; - /* ------------------------------------------------------------- */ static int RemoveNMRNewbie(void) { static int value = -1; - static int gamecookie = -1; if (value < 0 || gamecookie != global.cookie) { value = get_param_int(global.parameters, "nmr.removenewbie", 0); - gamecookie = global.cookie; } return value; @@ -140,13 +135,10 @@ static int RemoveNMRNewbie(void) static void restart_race(unit * u, const race * rc) { faction *oldf = u->faction; - faction *f = addfaction(oldf->email, oldf->passw, rc, oldf->locale, oldf->subscription); unit *nu = addplayer(u->region, f); - order **ordp = &u->orders; - f->subscription = u->faction->subscription; f->age = u->faction->age; fset(f, FFL_RESTART); @@ -162,7 +154,6 @@ static void restart_race(unit * u, const race * rc) u->orders = NULL; while (*ordp) { order *ord = *ordp; - if (get_keyword(ord) != K_RESTART) { *ordp = ord->next; ord->next = NULL; @@ -196,9 +187,7 @@ static boolean help_money(const unit * u) static void help_feed(unit * donor, unit * u, int *need_p) { int need = *need_p; - int give = get_money(donor) - lifestyle(donor); - give = MIN(need, give); if (give > 0) { @@ -219,18 +208,13 @@ enum { static void get_food(region * r) { plane *pl = rplane(r); - unit *u; - int peasantfood = rpeasants(r) * 10; - static int food_rules = -1; - static int gamecookie = -1; if (food_rules < 0 || gamecookie != global.cookie) { gamecookie = global.cookie; - food_rules = get_param_int(global.parameters, "rules.economy.food", 0); } @@ -249,13 +233,10 @@ static void get_food(region * r) if (u->ship && (u->ship->flags & SF_FISHING)) { unit *v; - int c = 2; - for (v = u; c > 0 && v; v = v->next) { if (v->ship == u->ship) { int get = 0; - if (v->number <= c) { get = lifestyle(v); } else { @@ -272,14 +253,11 @@ static void get_food(region * r) if (food_rules & FOOD_FROM_PEASANTS) { faction *owner = region_get_owner(r); - /* if the region is owned, and the owner is nice, then we'll get * food from the peasants - should not be used with WORK */ if (owner != NULL && (get_alliance(owner, u->faction) & HELP_MONEY)) { int rm = rmoney(r); - int use = MIN(rm, need); - rsetmoney(r, rm - use); need -= use; } @@ -292,7 +270,6 @@ static void get_food(region * r) for (v = r->units; need && v; v = v->next) { if (v->faction == u->faction && help_money(v)) { int give = get_money(v) - lifestyle(v); - give = MIN(need, give); if (give > 0) { change_money(v, -give); @@ -308,7 +285,6 @@ static void get_food(region * r) * entsprechend verteilt. */ for (u = r->units; u; u = u->next) { int need = lifestyle(u); - faction *f = u->faction; need -= MAX(0, get_money(u)); @@ -319,7 +295,6 @@ static void get_food(region * r) if (food_rules & FOOD_FROM_OWNER) { /* the owner of the region is the first faction to help out when you're hungry */ faction *owner = region_get_owner(r); - if (owner && owner != u->faction) { for (v = r->units; v; v = v->next) { if (v->faction == owner && alliedunit(v, f, HELP_MONEY) @@ -340,10 +315,8 @@ static void get_food(region * r) * nimmt Schaden: */ if (need > 0) { int lspp = lifestyle(u) / u->number; - if (lspp > 0) { int number = (need + lspp - 1) / lspp; - if (hunger(number, u)) fset(u, UFL_HUNGER); } @@ -357,16 +330,13 @@ static void get_food(region * r) for (u = r->units; u; u = u->next) { if (u->race == new_race[RC_DAEMON]) { unit *donor = r->units; - int hungry = u->number; while (donor != NULL && hungry > 0) { /* always start with the first known unit that may have some blood */ static const struct potion_type *pt_blood; - if (pt_blood == NULL) { const item_type *it_blood = it_find("peasantblood"); - if (it_blood) pt_blood = it_blood->rtype->ptype; } @@ -383,7 +353,6 @@ static void get_food(region * r) } if (donor != NULL) { int blut = get_effect(donor, pt_blood); - blut = MIN(blut, hungry); change_effect(donor, pt_blood, -blut); hungry -= blut; @@ -400,7 +369,6 @@ static void get_food(region * r) } if (hungry > 0) { static int demon_hunger = -1; - if (demon_hunger < 0) { demon_hunger = get_param_int(global.parameters, "hunger.demons", 0); } @@ -427,7 +395,6 @@ static void get_food(region * r) /* 3. Von den überlebenden das Geld abziehen: */ for (u = r->units; u; u = u->next) { int need = MIN(get_money(u), lifestyle(u)); - change_money(u, -need); } } @@ -447,10 +414,8 @@ static void age_unit(region * r, unit * u) #ifdef ASTRAL_ITEM_RESTRICTIONS if (u->region && is_astral(u->region)) { item **itemp = &u->items; - while (*itemp) { item *itm = *itemp; - if ((itm->type->flags & ITF_NOTLOST) == 0) { if (itm->type->flags & (ITF_BIG | ITF_ANIMAL | ITF_CURSED)) { ADDMSG(&u->faction->msgs, msg_message("itemcrumble", @@ -466,7 +431,6 @@ static void age_unit(region * r, unit * u) #endif } - static void live(region * r) { unit **up = &r->units; @@ -475,16 +439,13 @@ static void live(region * r) while (*up) { unit *u = *up; - /* IUW: age_unit() kann u loeschen, u->next ist dann * undefiniert, also muessen wir hier schon das nächste * Element bestimmen */ int effect = get_effect(u, oldpotiontype[P_FOOL]); - if (effect > 0) { /* Trank "Dumpfbackenbrot" */ skill *sv = u->skills, *sb = NULL; - while (sv != u->skills + u->skill_size) { if (sb == NULL || skill_compare(sv, sb) > 0) { sb = sv; @@ -494,7 +455,6 @@ static void live(region * r) /* bestes Talent raussuchen */ if (sb != NULL) { int weeks = MIN(effect, u->number); - reduce_skill(u, sb, weeks); ADDMSG(&u->faction->msgs, msg_message("dumbeffect", "unit weeks skill", u, weeks, (skill_t) sb->id)); @@ -533,11 +493,8 @@ static void live(region * r) static void calculate_emigration(region * r) { int i; - int maxp = maxworkingpeasants(r); - int rp = rpeasants(r); - int max_immigrants = MAX_IMMIGRATION(maxp - rp); if (r->terrain == newterrain(T_VOLCANO) @@ -547,14 +504,11 @@ static void calculate_emigration(region * r) for (i = 0; max_immigrants > 0 && i != MAXDIRECTIONS; i++) { int dir = (turn + i) % MAXDIRECTIONS; - region *rc = rconnect(r, (direction_t) dir); if (rc != NULL && fval(rc->terrain, LAND_REGION)) { int rp2 = rpeasants(rc); - int maxp2 = maxworkingpeasants(rc); - int max_emigration = MAX_EMIGRATION(rp2 - maxp2); if (max_emigration > 0) { @@ -572,13 +526,9 @@ static void calculate_emigration(region * r) static void peasants(region * r) { int peasants = rpeasants(r); - int money = rmoney(r); - int maxp = production(r) * MAXPEASANTS_PER_AREA; - int n, satiated; - int dead = 0; /* Bis zu 1000 Bauern können Zwillinge bekommen oder 1000 Bauern @@ -586,11 +536,8 @@ static void peasants(region * r) if (peasants > 0) { int glueck = 0; - double fraction = peasants * 0.0001F * PEASANTGROWTH; - int births = (int)fraction; - attrib *a = a_find(r->attribs, &at_peasantluck); if (rng_double() < (fraction - births)) { @@ -638,7 +585,6 @@ static void peasants(region * r) if (dead > 0) { message *msg = add_message(&r->msgs, msg_message("phunger", "dead", dead)); - msg_release(msg); peasants -= dead; } @@ -657,17 +603,13 @@ typedef struct migration { #define MSIZE 1023 migration *migrants[MSIZE]; - migration *free_migrants; static migration *get_migrants(region * r) { int key = reg_hashkey(r); - int index = key % MSIZE; - migration *m = migrants[index]; - while (m && m->r != r) m = m->next; if (m == NULL) { @@ -691,17 +633,13 @@ static migration *get_migrants(region * r) static void migrate(region * r) { int key = reg_hashkey(r); - int index = key % MSIZE; - migration **hp = &migrants[index]; - fset(r, RF_MIGRATION); while (*hp && (*hp)->r != r) hp = &(*hp)->next; if (*hp) { migration *m = *hp; - rsethorses(r, rhorses(r) + m->horses); /* Was macht das denn hier? * Baumwanderung wird in trees() gemacht. @@ -719,7 +657,6 @@ static void migrate(region * r) static void horses(region * r) { int horses, maxhorses; - direction_t n; /* Logistisches Wachstum, Optimum bei halbem Maximalbesatz. */ @@ -731,7 +668,6 @@ static void horses(region * r) rsethorses(r, (int)(horses * 0.9F)); } else if (maxhorses) { int i; - double growth = (RESOURCE_QUANTITY * HORSEGROWTH * 200 * (maxhorses - horses)) / maxhorses; @@ -755,17 +691,14 @@ static void horses(region * r) for (n = 0; n != MAXDIRECTIONS; n++) { region *r2 = rconnect(r, n); - if (r2 && fval(r2->terrain, WALK_INTO)) { int pt = (rhorses(r) * HORSEMOVE) / 100; - pt = (int)normalvariate(pt, pt / 4.0); pt = MAX(0, pt); if (fval(r2, RF_MIGRATION)) rsethorses(r2, rhorses(r2) + pt); else { migration *nb; - /* haben wir die Migration schonmal benutzt? * wenn nicht, müssen wir sie suchen. * Wandernde Pferde vermehren sich nicht. @@ -783,7 +716,6 @@ static void horses(region * r) static int count_race(const region * r, const race * rc) { unit *u; - int c = 0; for (u = r->units; u; u = u->next) @@ -809,15 +741,10 @@ growing_trees_e3(region * r, const int current_season, if (r->land && current_season != last_weeks_season && transform[current_season][2]) { int src_type = transform[current_season][0]; - int dst_type = transform[current_season][1]; - int src = rtrees(r, src_type); - int dst = rtrees(r, dst_type); - int grow = src / transform[current_season][2]; - if (grow > 0) { if (src_type != TREE_TREE) { rsettrees(r, src_type, src - grow); @@ -826,22 +753,16 @@ growing_trees_e3(region * r, const int current_season, if (dst_type == TREE_SEED && r->terrain->size) { region *rn[MAXDIRECTIONS]; - int d; - double fgrow = grow / (double)MAXDIRECTIONS; get_neighbours(r, rn); for (d = 0; d != MAXDIRECTIONS; ++d) { region *rx = rn[d]; - if (rx && rx->land) { double scale = 1.0; - int g; - double fg, ch; - int seeds = rtrees(rx, dst_type); if (r->terrain->size > rx->terrain->size) { @@ -866,14 +787,11 @@ static void growing_trees(region * r, const int current_season, const int last_weeks_season) { int growth, grownup_trees, i, seeds, sprout; - direction_t d; - attrib *a; if (current_season == SEASON_SUMMER || current_season == SEASON_AUTUMN) { double seedchance = 0.01F * RESOURCE_QUANTITY; - int elves = count_race(r, new_race[RC_ELF]); a = a_find(r->attribs, &at_germs); @@ -908,7 +826,6 @@ growing_trees(region * r, const int current_season, const int last_weeks_season) if (grownup_trees > 0) { double remainder = seedchance * grownup_trees; - seeds = (int)(remainder); remainder -= seeds; if (chance(remainder)) { @@ -927,7 +844,6 @@ growing_trees(region * r, const int current_season, const int last_weeks_season) seeds = (rtrees(r, 2) * FORESTGROWTH * 3) / 1000000; for (d = 0; d != MAXDIRECTIONS; ++d) { region *r2 = rconnect(r, d); - if (r2 && fval(r2->terrain, LAND_REGION) && r2->terrain->size) { /* Eine Landregion, wir versuchen Samen zu verteilen: * Die Chance, das Samen ein Stück Boden finden, in dem sie @@ -1011,7 +927,6 @@ growing_herbs(region * r, const int current_season, const int last_weeks_season) * Kräuter))% sich zu vermehren. */ if (current_season != SEASON_WINTER) { int i; - for (i = rherbs(r); i > 0; i--) { if (rng_int() % 100 < (100 - rherbs(r))) rsetherbs(r, (short)(rherbs(r) + 1)); @@ -1022,14 +937,11 @@ growing_herbs(region * r, const int current_season, const int last_weeks_season) void demographics(void) { region *r; - static int last_weeks_season = -1; - static int current_season = -1; if (current_season < 0) { gamedate date; - get_gamedate(turn, &date); current_season = date.season; get_gamedate(turn - 1, &date); @@ -1044,7 +956,6 @@ void demographics(void) if (!fval(r->terrain, SEA_REGION)) { /* die Nachfrage nach Produkten steigt. */ struct demand *dmd; - if (r->land) { static int plant_rules = -1; @@ -1055,7 +966,6 @@ void demographics(void) for (dmd = r->land->demands; dmd; dmd = dmd->next) { if (dmd->value > 0 && dmd->value < MAXDEMAND) { float rise = DMRISE; - if (buildingtype_exists(r, bt_find("harbour"), true)) rise = DMRISEHAFEN; if (rng_double() < rise) @@ -1086,7 +996,6 @@ void demographics(void) } while (free_migrants) { migration *m = free_migrants->next; - free(free_migrants); free_migrants = m; }; @@ -1100,7 +1009,6 @@ void demographics(void) for (r = regions; r; r = r->next) { if (r->land && r->land->newpeasants) { int rp = rpeasants(r) + r->land->newpeasants; - rsetpeasants(r, MAX(0, rp)); } } @@ -1126,7 +1034,6 @@ static int modify(int i) static void inactivefaction(faction * f) { FILE *inactiveFILE; - char zText[128]; sprintf(zText, "%s/%s", datapath(), "inactive"); @@ -1166,7 +1073,6 @@ static int restart_cmd(unit * u, struct order *ord) ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); } else { const char *s_race = getstrtoken(), *s_pass; - const race *frace = findrace(s_race, u->faction->locale); if (!frace) { @@ -1206,10 +1112,8 @@ static int restart_cmd(unit * u, struct order *ord) static boolean EnhancedQuit(void) { static int value = -1; - if (value < 0) { const char *str = get_param(global.parameters, "alliance.transferquit"); - value = (str != 0 && strcmp(str, "true") == 0); } return value; @@ -1218,7 +1122,6 @@ static boolean EnhancedQuit(void) static int quit_cmd(unit * u, struct order *ord) { faction *f = u->faction; - const char *passwd; init_tokens(ord); @@ -1228,7 +1131,6 @@ static int quit_cmd(unit * u, struct order *ord) if (checkpasswd(f, (const char *)passwd, false)) { if (EnhancedQuit()) { int f2_id = getid(); - if (f2_id > 0) { faction *f2 = findfaction(f2_id); @@ -1244,7 +1146,6 @@ static int quit_cmd(unit * u, struct order *ord) return 0; } else { variant var; - var.i = f2_id; a_add(&f->attribs, object_create("quit", TINTEGER, var)); } @@ -1253,7 +1154,6 @@ static int quit_cmd(unit * u, struct order *ord) fset(f, FFL_QUIT); } else { char buffer[64]; - write_order(ord, buffer, sizeof(buffer)); cmistake(u, ord, 86, MSG_EVENT); log_warning(("QUIT with illegal password for faction %s: %s\n", @@ -1265,26 +1165,20 @@ static int quit_cmd(unit * u, struct order *ord) static void quit(void) { faction **fptr = &factions; - while (*fptr) { faction *f = *fptr; - if (f->flags & FFL_QUIT) { if (EnhancedQuit()) { /* this doesn't work well (use object_name()) */ attrib *a = a_find(f->attribs, &at_object); - if (a) { variant var; - object_type type; - var.i = 0; object_get(a, &type, &var); assert(var.i && type == TINTEGER); if (var.i) { int f2_id = var.i; - faction *f2 = findfaction(f2_id); assert(f2_id > 0); @@ -1301,19 +1195,15 @@ static void quit(void) } int dropouts[2]; - int *age = NULL; static void nmr_death(faction * f) { static int rule = -1; - if (rule < 0) rule = get_param_int(global.parameters, "rules.nmr.destroy", 0); - if (rule) { unit *u; - for (u = f->units; u; u = u->nextF) { if (u->building && fval(u, UFL_OWNER)) { remove_building(&u->region->buildings, u->building); @@ -1325,7 +1215,6 @@ static void nmr_death(faction * f) static void parse_restart(void) { region *r; - faction *f; /* Sterben erst nachdem man allen anderen gegeben hat - bzw. man kann @@ -1333,7 +1222,6 @@ static void parse_restart(void) for (r = regions; r; r = r->next) { unit *u, *un; - for (u = r->units; u;) { order *ord; @@ -1370,7 +1258,6 @@ static void parse_restart(void) } if (turn != f->lastorders) { char info[256]; - sprintf(info, "%d Einheiten, %d Personen, %d Silber", f->no_units, f->num_total, f->money); if (f->subscription) { @@ -1425,11 +1312,8 @@ static void parse_restart(void) static int ally_cmd(unit * u, struct order *ord) { ally *sf, **sfp; - faction *f; - int keyword, not_kw; - const char *s; init_tokens(ord); @@ -1453,7 +1337,6 @@ static int ally_cmd(unit * u, struct order *ord) sfp = &u->faction->allies; if (fval(u, UFL_GROUP)) { attrib *a = a_find(u->attribs, &at_group); - if (a) sfp = &((group *) a->data.v)->allies; } @@ -1546,12 +1429,9 @@ static struct local_names *pnames; static void init_prefixnames(void) { int i; - for (i = 0; localenames[i]; ++i) { const struct locale *lang = find_locale(localenames[i]); - boolean exist = false; - struct local_names *in = pnames; while (in != NULL) { @@ -1568,10 +1448,8 @@ static void init_prefixnames(void) if (!exist) { int key; - for (key = 0; race_prefixes[key]; ++key) { variant var; - const char *pname = locale_string(lang, mkname("prefix", race_prefixes[key])); if (findtoken(&in->names, pname, &var) == E_TOK_NOMATCH || var.i != key) { @@ -1589,13 +1467,9 @@ static void init_prefixnames(void) static int prefix_cmd(unit * u, struct order *ord) { attrib **ap; - const char *s; - local_names *in = pnames; - variant var; - const struct locale *lang = u->faction->locale; while (in != NULL) { @@ -1614,13 +1488,11 @@ static int prefix_cmd(unit * u, struct order *ord) if (!*s) { attrib *a = NULL; - if (fval(u, UFL_GROUP)) { a = a_find(u->attribs, &at_group); } if (a) { group *g = (group *) a->data.v; - a_removeall(&g->attribs, &at_raceprefix); } else { a_removeall(&u->faction->attribs, &at_raceprefix); @@ -1636,9 +1508,7 @@ static int prefix_cmd(unit * u, struct order *ord) ap = &u->faction->attribs; if (fval(u, UFL_GROUP)) { attrib *a = a_find(u->attribs, &at_group); - group *g = (group *) a->data.v; - if (a) ap = &g->attribs; } @@ -1647,7 +1517,6 @@ static int prefix_cmd(unit * u, struct order *ord) return 0; } - static cmp_building_cb get_cmp_region_owner(void) { if (rule_region_owners()) { @@ -1660,9 +1529,7 @@ static cmp_building_cb get_cmp_region_owner(void) static int display_cmd(unit * u, struct order *ord) { building *b = u->building; - char **s = NULL; - region *r = u->region; init_tokens(ord); @@ -1705,7 +1572,6 @@ static int display_cmd(unit * u, struct order *ord) case P_PRIVAT: { const char *d = getstrtoken(); - if (d == NULL || *d == 0) { usetprivate(u, NULL); } else { @@ -1751,12 +1617,9 @@ static int display_cmd(unit * u, struct order *ord) static boolean renamed_building(const building * b) { const struct locale *lang = locales; - for (; lang; lang = nextlocale(lang)) { const char *bdname = LOC(lang, b->type->_name); - size_t bdlen = strlen(bdname); - if (strlen(b->name) >= bdlen && strncmp(b->name, bdname, bdlen) == 0) { return false; } @@ -1786,7 +1649,6 @@ static int rename_building(unit * u, order * ord, building * b, const char *name) { unit *owner = b ? building_owner(b) : 0; - boolean foreign = !(owner && owner->faction == u->faction); if (!b) { @@ -1827,13 +1689,9 @@ rename_building(unit * u, order * ord, building * b, const char *name) static int name_cmd(unit * u, struct order *ord) { building *b = u->building; - region *r = u->region; - char **s = NULL; - param_t p; - boolean foreign = false; init_tokens(ord); @@ -1849,9 +1707,7 @@ static int name_cmd(unit * u, struct order *ord) case P_ALLIANCE: if (foreign == false && f_get_alliance(u->faction)) { alliance *al = u->faction->alliance; - faction *lead = alliance_get_leader(al); - if (lead == u->faction) { s = &al->name; } @@ -1879,12 +1735,9 @@ static int name_cmd(unit * u, struct order *ord) break; } else { const struct locale *lang = locales; - for (; lang; lang = nextlocale(lang)) { const char *fdname = LOC(lang, "factiondefault"); - size_t fdlen = strlen(fdname); - if (strlen(f->name) >= fdlen && strncmp(f->name, fdname, fdlen) == 0) { break; @@ -1910,7 +1763,6 @@ static int name_cmd(unit * u, struct order *ord) case P_SHIP: if (foreign == true) { ship *sh = getship(r); - unit *uo; if (!sh) { @@ -1918,12 +1770,9 @@ static int name_cmd(unit * u, struct order *ord) break; } else { const struct locale *lang = locales; - for (; lang; lang = nextlocale(lang)) { const char *sdname = LOC(lang, sh->type->name[0]); - size_t sdlen = strlen(sdname); - if (strlen(sh->name) >= sdlen && strncmp(sh->name, sdname, sdlen) == 0) { break; @@ -1976,11 +1825,8 @@ static int name_cmd(unit * u, struct order *ord) break; } else { const char *udefault = LOC(u2->faction->locale, "unitdefault"); - size_t udlen = strlen(udefault); - size_t unlen = strlen(u2->name); - if (unlen >= udlen && strncmp(u2->name, udefault, udlen) != 0) { cmistake(u2, ord, 244, MSG_EVENT); break; @@ -2019,12 +1865,10 @@ static int name_cmd(unit * u, struct order *ord) case P_GROUP: { attrib *a = NULL; - if (fval(u, UFL_GROUP)) a = a_find(u->attribs, &at_group); if (a) { group *g = (group *) a->data.v; - s = &g->name; break; } else { @@ -2092,11 +1936,8 @@ static void mailfaction(unit * u, int n, struct order *ord, const char *s) static int mail_cmd(unit * u, struct order *ord) { region *r = u->region; - unit *u2; - const char *s; - int n, cont; init_tokens(ord); @@ -2150,7 +1991,6 @@ static int mail_cmd(unit * u, struct order *ord) case P_UNIT: { boolean see = false; - n = getid(); for (u2 = r->units; u2; u2 = u2->next) { @@ -2172,10 +2012,8 @@ static int mail_cmd(unit * u, struct order *ord) break; } else { attrib *a = a_find(u2->attribs, &at_eventhandler); - if (a != NULL) { event_arg args[3]; - args[0].data.v = (void *)s; args[0].type = "string"; args[1].data.v = (void *)u; @@ -2287,7 +2125,6 @@ static int email_cmd(unit * u, struct order *ord) cmistake(u, ord, 85, MSG_EVENT); } else { faction *f = u->faction; - if (set_email(&f->email, (const char *)s) != 0) { log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), s)); @@ -2302,11 +2139,8 @@ static int email_cmd(unit * u, struct order *ord) static int password_cmd(unit * u, struct order *ord) { char pwbuf[32]; - int i; - const char *s; - boolean pwok = true; init_tokens(ord); @@ -2345,7 +2179,6 @@ static int password_cmd(unit * u, struct order *ord) static int send_cmd(unit * u, struct order *ord) { const char *s; - int option; init_tokens(ord); @@ -2377,14 +2210,11 @@ static int send_cmd(unit * u, struct order *ord) static boolean display_item(faction * f, unit * u, const item_type * itype) { const char *name; - const char *key; - const char *info; if (u != NULL) { int i = i_get(u->items, itype); - if (i == 0) { if (u->region->land != NULL) { i = i_get(u->region->land->items, itype); @@ -2418,7 +2248,6 @@ static boolean display_potion(faction * f, unit * u, const potion_type * ptype) return false; else { int i = i_get(u->items, ptype->itype); - if (i == 0 && 2 * ptype->level > effskill(u, SK_ALCHEMY)) { return false; } @@ -2438,15 +2267,10 @@ static boolean display_potion(faction * f, unit * u, const potion_type * ptype) static boolean display_race(faction * f, unit * u, const race * rc) { const char *name, *key; - const char *info; - int a, at_count; - char buf[2048], *bufp = buf; - size_t size = sizeof(buf) - 1; - int bytes; if (u && u->race != rc) @@ -2591,13 +2415,9 @@ static boolean display_race(faction * f, unit * u, const race * rc) static void reshow(unit * u, struct order *ord, const char *s, param_t p) { int skill, c; - const potion_type *ptype; - const item_type *itype; - const spell *sp; - const race *rc; switch (p) { @@ -2632,7 +2452,6 @@ static void reshow(unit * u, struct order *ord, const char *s, param_t p) sp = get_spellfromtoken(u, s, u->faction->locale); if (sp != NULL && u_hasspell(u, sp)) { attrib *a = a_find(u->faction->attribs, &at_seenspell); - while (a != NULL && a->type == &at_seenspell && a->data.v != sp) a = a->next; if (a != NULL) @@ -2728,7 +2547,6 @@ static int guard_off_cmd(unit * u, struct order *ord) static int reshow_cmd(unit * u, struct order *ord) { const char *s; - param_t p = NOPARAM; init_tokens(ord); @@ -2792,9 +2610,7 @@ static int status_cmd(unit * u, struct order *ord) static int combatspell_cmd(unit * u, struct order *ord) { const char *s; - int level = 0; - spell *spell; init_tokens(ord); @@ -2862,14 +2678,12 @@ void update_guards(void) for (r = regions; r; r = r->next) { unit *u; - for (u = r->units; u; u = u->next) { if (fval(u, UFL_GUARD)) { if (can_start_guarding(u) != E_GUARD_OK) { setguard(u, GUARD_NONE); } else { attrib *a = a_find(u->attribs, &at_guard); - if (a && a->data.i == (int)guard_flags(u)) { /* this is really rather not necessary */ a_remove(&u->attribs, a); @@ -2904,7 +2718,6 @@ static int guard_on_cmd(unit * u, struct order *ord) guard(u, GUARD_ALL); } else { int err = can_start_guarding(u); - if (err == E_GUARD_OK) { guard(u, GUARD_ALL); } else if (err == E_GUARD_UNARMED) { @@ -2969,16 +2782,11 @@ static void renumber_factions(void) faction *faction; attrib *attrib; } *renum = NULL, *rp; - faction *f; - for (f = factions; f; f = f->next) { attrib *a = a_find(f->attribs, &at_number); - int want; - struct renum **rn; - faction *old; if (!a) @@ -3007,7 +2815,6 @@ static void renumber_factions(void) ADDMSG(&f->msgs, msg_message("renumber_inuse", "id", want)); } else { struct renum *r = calloc(sizeof(struct renum), 1); - r->next = *rn; r->attrib = a; r->faction = f; @@ -3030,26 +2837,18 @@ static void renumber_factions(void) static void reorder(void) { region *r; - for (r = regions; r; r = r->next) { unit **up = &r->units; - boolean sorted = false; - while (*up) { unit *u = *up; - if (!fval(u, UFL_MARK)) { struct order *ord; - for (ord = u->orders; ord; ord = ord->next) { if (get_keyword(ord) == K_SORT) { const char *s; - param_t p; - int id; - unit *v; init_tokens(ord); @@ -3079,7 +2878,6 @@ static void reorder(void) cmistake(v, ord, 261, MSG_EVENT); } else { unit **vp = &r->units; - while (*vp != v) vp = &(*vp)->next; *vp = u; @@ -3100,7 +2898,6 @@ static void reorder(void) } if (sorted) { unit *u; - for (u = r->units; u; u = u->next) freset(u, UFL_MARK); } @@ -3112,9 +2909,7 @@ static void reorder(void) static void evict(void) { region *r; - strlist *S; - unit *u; for (r = regions; r; r = r->next) { @@ -3122,9 +2917,7 @@ static void evict(void) for (S = u->orders; S; S = S->next) if (get_keyword(ord) == K_EVICT) { int id; - unit *u2; - /* Nur der Kapitän bzw Burgherr kann jemanden rausschmeißen */ if (!fval(u, UFL_OWNER)) { /* Die Einheit ist nicht der Eigentümer */ @@ -3169,13 +2962,10 @@ static void evict(void) } #endif - static int renumber_cmd(unit * u, order * ord) { const char *s; - int i; - faction *f = u->faction; init_tokens(ord); @@ -3187,9 +2977,7 @@ static int renumber_cmd(unit * u, order * ord) s = getstrtoken(); if (s && *s) { int id = atoi36((const char *)s); - attrib *a = a_find(f->attribs, &at_number); - if (!a) a = a_add(&f->attribs, a_new(&at_number)); a->data.i = id; @@ -3220,7 +3008,6 @@ static int renumber_cmd(unit * u, order * ord) uunhash(u); if (!ualias(u)) { attrib *a = a_add(&u->attribs, a_new(&at_alias)); - a->data.i = -u->no; } u->no = i; @@ -3296,11 +3083,8 @@ static int renumber_cmd(unit * u, order * ord) static building *age_building(building * b) { static boolean init = false; - static const building_type *bt_blessed; - static const curse_type *ct_astralblock; - if (!init) { init = true; bt_blessed = bt_find("blessedstonecircle"); @@ -3316,9 +3100,7 @@ static building *age_building(building * b) */ if (ct_astralblock && bt_blessed && b->type == bt_blessed) { region *r = b->region; - region *rt = r_standard_to_astral(r); - unit *u, *mage = NULL; if (fval(rt->terrain, FORBIDDEN_REGION)) @@ -3329,7 +3111,6 @@ static building *age_building(building * b) if (b == u->building && inside_building(u)) { if (!(u->race->ec_flags & GIVEITEM) == 0) { int n, unicorns = 0; - for (n = 0; n != u->number; ++n) { if (chance(0.02)) { i_change(&u->items, olditemtype[I_ELVENHORSE], 1); @@ -3352,13 +3133,10 @@ static building *age_building(building * b) * curse. */ if (rt != NULL && mage != NULL) { curse *c = get_curse(rt->attribs, ct_astralblock); - if (c == NULL) { if (mage != NULL) { int sk = effskill(mage, SK_MAGIC); - double effect; - effect = 100; /* the mage reactivates the circle */ c = create_curse(mage, &rt->attribs, ct_astralblock, @@ -3368,7 +3146,6 @@ static building *age_building(building * b) } } else if (mage != NULL) { int sk = effskill(mage, SK_MAGIC); - c->duration = MAX(c->duration, sk / 2); c->vigour = MAX(c->vigour, sk); } @@ -3388,7 +3165,6 @@ static building *age_building(building * b) static double rc_popularity(const struct race *rc) { int pop = get_param_int(rc->parameters, "morale", MORALE_AVERAGE); - return 1.0 / (pop - MORALE_COOLDOWN); /* 10 turns average */ } @@ -3402,21 +3178,16 @@ static void age_region(region * r) if (r->land->ownership && r->land->ownership->owner) { int stability = turn - r->land->ownership->morale_turn; - int maxmorale = MORALE_DEFAULT; - building *b = largestbuilding(r, &cmp_taxes, false); - if (b) { int bsize = buildingeffsize(b, false); - maxmorale = (int)(0.5 + b->type->taxes(b, bsize + 1) / MORALE_TAX_FACTOR); } if (r->land->morale < maxmorale) { if (stability > MORALE_COOLDOWN && r->land->ownership->owner && r->land->morale < MORALE_MAX) { double ch = rc_popularity(r->land->ownership->owner->race); - if (is_cursed(r->attribs, C_GENEROUS, 0)) { ch *= 1.2; /* 20% improvement */ } @@ -3435,7 +3206,6 @@ static void age_region(region * r) static void ageing(void) { faction *f; - region *r; /* altern spezieller Attribute, die eine Sonderbehandlung brauchen? */ @@ -3445,7 +3215,6 @@ static void ageing(void) for (u = r->units; u; u = u->next) { /* Goliathwasser */ int i = get_effect(u, oldpotiontype[P_STRONG]); - if (i > 0) { change_effect(u, oldpotiontype[P_STRONG], -1 * MIN(u->number, i)); } @@ -3457,7 +3226,6 @@ static void ageing(void) if (is_cursed(u->attribs, C_OLDRACE, 0)) { curse *c = get_curse(u->attribs, ct_find("oldrace")); - if (c->duration == 1 && !(c_flags(c) & CURSE_NOAGE)) { u->race = new_race[curse_geteffect_int(c)]; u->irace = NULL; @@ -3478,9 +3246,7 @@ static void ageing(void) /* Regionen */ for (r = regions; r; r = r->next) { building **bp; - unit **up; - ship **sp; age_region(r); @@ -3488,7 +3254,6 @@ static void ageing(void) /* Einheiten */ for (up = &r->units; *up;) { unit *u = *up; - a_age(&u->attribs); if (u == *up) handle_event(u->attribs, "timer", u); @@ -3499,7 +3264,6 @@ static void ageing(void) /* Schiffe */ for (sp = &r->ships; *sp;) { ship *s = *sp; - a_age(&s->attribs); if (s == *sp) handle_event(s->attribs, "timer", s); @@ -3510,7 +3274,6 @@ static void ageing(void) /* Gebäude */ for (bp = &r->buildings; *bp;) { building *b = *bp; - age_building(b); if (b == *bp) bp = &b->next; @@ -3525,9 +3288,7 @@ static void ageing(void) static int maxunits(const faction * f) { int flimit = rule_faction_limit(); - int alimit = rule_alliance_limit(); - if (alimit == 0) { return flimit; } @@ -3546,7 +3307,6 @@ int checkunitnumber(const faction * f, int add) /* if unitsperalliance is true, maxunits returns the number of units allowed in an alliance */ faction *f2; - int unitsinalliance = add; for (f2 = factions; f2; f2 = f2->next) { @@ -3572,7 +3332,6 @@ int checkunitnumber(const faction * f, int add) static void new_units(void) { region *r; - unit *u, *u2; /* neue einheiten werden gemacht und ihre befehle (bis zum "ende" zu @@ -3592,21 +3351,15 @@ static void new_units(void) while (*ordp) { order *makeord = *ordp; - if (get_keyword(makeord) == K_MAKE) { init_tokens(makeord); skip_token(); if (getparam(u->faction->locale) == P_TEMP) { const char *token; - char *name = NULL; - int alias; - ship *sh; - order **newordersp; - int err = checkunitnumber(u->faction, 1); if (err) { @@ -3623,7 +3376,6 @@ static void new_units(void) while (*ordp) { order *ord = *ordp; - if (get_keyword(ord) == K_END) break; *ordp = ord->next; @@ -3654,7 +3406,6 @@ static void new_units(void) newordersp = &u2->orders; while (*ordp) { order *ord = *ordp; - if (get_keyword(ord) == K_END) break; *ordp = ord->next; @@ -3676,7 +3427,6 @@ static void new_units(void) void check_long_orders(unit * u) { order *ord; - keyword_t otherorder = MAXKEYWORDS; for (ord = u->orders; ord; ord = ord->next) { @@ -3684,7 +3434,6 @@ void check_long_orders(unit * u) cmistake(u, ord, 22, MSG_EVENT); } else if (is_long(ord)) { keyword_t longorder = get_keyword(ord); - if (otherorder != MAXKEYWORDS) { switch (longorder) { case K_CAST: @@ -3719,9 +3468,7 @@ void check_long_orders(unit * u) static void setdefaults(unit * u) { order *ord; - boolean trade = false; - boolean hunger = LongHunger(u); freset(u, UFL_LONGACTION); @@ -3755,7 +3502,6 @@ static void setdefaults(unit * u) break; } else { keyword_t keyword = get_keyword(ord); - switch (keyword) { /* Wenn gehandelt wird, darf kein langer Befehl ausgeführt * werden. Da Handel erst nach anderen langen Befehlen kommt, @@ -3801,7 +3547,6 @@ static int use_item(unit * u, const item_type * itype, int amount, struct order *ord) { int i; - int target = read_unitid(u->faction, u->region); i = get_pooled(u, itype->rtype, GET_DEFAULT, amount); @@ -3829,11 +3574,9 @@ use_item(unit * u, const item_type * itype, int amount, struct order *ord) } } - static double heal_factor(const unit * u) { static float elf_regen = -1; - switch (old_race(u->race)) { case RC_TROLL: case RC_DAEMON: @@ -3854,28 +3597,23 @@ static double heal_factor(const unit * u) static void monthly_healing(void) { region *r; - static const curse_type *heal_ct = NULL; - if (heal_ct == NULL) heal_ct = ct_find("healingzone"); for (r = regions; r; r = r->next) { unit *u; - double healingcurse = 0; if (heal_ct != NULL) { /* bonus zurücksetzen */ curse *c = get_curse(r->attribs, heal_ct); - if (c != NULL) { healingcurse = curse_geteffect(c); } } for (u = r->units; u; u = u->next) { int umhp = unit_max_hp(u) * u->number; - double p = 1.0; /* hp über Maximum bauen sich ab. Wird zb durch Elixier der Macht @@ -3905,11 +3643,8 @@ static void monthly_healing(void) double maxheal = MAX(u->number, umhp / 10.0); #endif int addhp; - struct building *b = inside_building(u); - const struct building_type *btype = b ? b->type : NULL; - if (btype == bt_find("inn")) { p *= 1.5; } @@ -3936,7 +3671,6 @@ static void remove_exclusive(order ** ordp) { while (*ordp) { order *ord = *ordp; - if (is_exclusive(ord)) { *ordp = ord->next; ord->next = NULL; @@ -3950,23 +3684,16 @@ static void remove_exclusive(order ** ordp) static void defaultorders(void) { region *r; - for (r = regions; r; r = r->next) { unit *u; - for (u = r->units; u; u = u->next) { boolean neworders = false; - order **ordp = &u->orders; - while (*ordp != NULL) { order *ord = *ordp; - if (get_keyword(ord) == K_DEFAULT) { char lbuf[8192]; - order *new_order; - init_tokens(ord); skip_token(); /* skip the keyword */ strcpy(lbuf, getstrtoken()); @@ -4002,18 +3729,14 @@ static void update_spells(void) for (f = factions; f; f = f->next) { if (f->magiegebiet != M_NONE && !is_monsters(f)) { unit *mages[MAXMAGES]; - unit *u; - int maxlevel = 0, n = 0, i; for (u = f->units; u; u = u->nextF) { if (u->number > 0) { sc_mage *mage = get_mage(u); - if (mage) { int level = eff_skill(u, SK_MAGIC, u->region); - if (level > maxlevel) maxlevel = level; assert(n < MAXMAGES); @@ -4048,9 +3771,7 @@ static void age_factions(void) static int use_cmd(unit * u, struct order *ord) { const char *t; - int n; - const item_type *itype; init_tokens(ord); @@ -4075,7 +3796,6 @@ static int use_cmd(unit * u, struct order *ord) if (itype != NULL) { int i = use_item(u, itype, n, ord); - assert(i <= 0 || !"use_item should not return positive values."); if (i > 0) { log_error(("use_item returned a value>0 for %s\n", @@ -4093,13 +3813,11 @@ static int pay_cmd(unit * u, struct order *ord) cmistake(u, ord, 6, MSG_EVENT); } else { param_t p; - init_tokens(ord); skip_token(); p = getparam(u->faction->locale); if (p == P_NOT) { unit *owner = building_owner(u->building); - if (owner->faction != u->faction) { cmistake(u, ord, 1222, MSG_EVENT); } else { @@ -4113,9 +3831,7 @@ static int pay_cmd(unit * u, struct order *ord) static int claim_cmd(unit * u, struct order *ord) { const char *t; - int n; - const item_type *itype; init_tokens(ord); @@ -4132,7 +3848,6 @@ static int claim_cmd(unit * u, struct order *ord) if (itype != NULL) { item **iclaim = i_find(&u->faction->items, itype); - if (iclaim != NULL && *iclaim != NULL) { n = MIN(n, (*iclaim)->number); i_change(iclaim, itype, -n); @@ -4148,7 +3863,6 @@ enum { PROC_THISORDER = 1 << 0, PROC_LONGORDER = 1 << 1 }; - typedef struct processor { struct processor *next; int priority; @@ -4177,7 +3891,6 @@ static processor *processors; processor *add_proc(int priority, const char *name, int type) { processor **pproc = &processors; - processor *proc; while (*pproc) { @@ -4204,7 +3917,6 @@ add_proc_order(int priority, keyword_t kword, int (*parser) (struct unit *, { if (!global.disabled[kword]) { processor *proc = add_proc(priority, name, PR_ORDER); - if (proc) { proc->data.per_order.process = parser; proc->data.per_order.kword = kword; @@ -4216,7 +3928,6 @@ add_proc_order(int priority, keyword_t kword, int (*parser) (struct unit *, void add_proc_global(int priority, void (*process) (void), const char *name) { processor *proc = add_proc(priority, name, PR_GLOBAL); - if (proc) { proc->data.global.process = process; } @@ -4225,7 +3936,6 @@ void add_proc_global(int priority, void (*process) (void), const char *name) void add_proc_region(int priority, void (*process) (region *), const char *name) { processor *proc = add_proc(priority, name, PR_REGION_PRE); - if (proc) { proc->data.per_region.process = process; } @@ -4235,7 +3945,6 @@ void add_proc_postregion(int priority, void (*process) (region *), const char *name) { processor *proc = add_proc(priority, name, PR_REGION_POST); - if (proc) { proc->data.per_region.process = process; } @@ -4244,7 +3953,6 @@ add_proc_postregion(int priority, void (*process) (region *), const char *name) void add_proc_unit(int priority, void (*process) (unit *), const char *name) { processor *proc = add_proc(priority, name, PR_UNIT); - if (proc) { proc->data.per_unit.process = process; } @@ -4254,14 +3962,11 @@ void add_proc_unit(int priority, void (*process) (unit *), const char *name) void process(void) { processor *proc = processors; - faction *f; while (proc) { int prio = proc->priority; - region *r; - processor *pglobal = proc; if (verbosity >= 3) @@ -4274,7 +3979,6 @@ void process(void) while (pglobal && pglobal->priority == prio && pglobal->type == PR_GLOBAL) { pglobal->data.global.process(); - pglobal = pglobal->next; } if (pglobal == NULL || pglobal->priority != prio) @@ -4282,7 +3986,6 @@ void process(void) for (r = regions; r; r = r->next) { unit *u; - processor *pregion = pglobal; while (pregion && pregion->priority == prio @@ -4307,12 +4010,10 @@ void process(void) porder = punit; while (porder && porder->priority == prio && porder->type == PR_ORDER) { order **ordp = &u->orders; - if (porder->flags & PROC_THISORDER) ordp = &u->thisorder; while (*ordp) { order *ord = *ordp; - if (get_keyword(ord) == porder->data.per_order.kword) { if (porder->flags & PROC_LONGORDER) { if (u->number == 0) { @@ -4368,10 +4069,8 @@ void process(void) printf("\n - Leere Gruppen loeschen...\n"); for (f = factions; f; f = f->next) { group **gp = &f->groups; - while (*gp) { group *g = *gp; - if (g->members == 0) { *gp = g->next; free_group(g); @@ -4417,12 +4116,9 @@ static void reset_moved(unit * u) static int warn_password(void) { faction *f = factions; - while (f) { boolean pwok = true; - const char *c = f->passw; - while (*c && pwok) { if (!isalnum((unsigned char)*c)) pwok = false; @@ -4630,14 +4326,12 @@ void processorders(void) int writepasswd(void) { FILE *F; - char zText[128]; sprintf(zText, "%s/passwd", basepath()); F = cfopen(zText, "w"); if (F) { faction *f; - puts("writing passwords..."); for (f = factions; f; f = f->next) { @@ -4653,11 +4347,8 @@ int writepasswd(void) void update_subscriptions(void) { FILE *F; - char zText[MAX_PATH]; - faction *f; - strcat(strcpy(zText, basepath()), "/subscriptions"); F = fopen(zText, "r"); if (F == NULL) { @@ -4666,9 +4357,7 @@ void update_subscriptions(void) } for (;;) { char zFaction[5]; - int subscription, fno; - if (fscanf(F, "%d %s", &subscription, zFaction) <= 0) break; fno = atoi36(zFaction); diff --git a/src/gamecode/laws_test.c b/src/gamecode/laws_test.c index fdba5fdc0..9587117f4 100644 --- a/src/gamecode/laws_test.c +++ b/src/gamecode/laws_test.c @@ -6,9 +6,7 @@ static void test_new_building_can_be_renamed(CuTest * tc) { region *r; - building *b; - building_type *btype; test_cleanup(); @@ -24,13 +22,9 @@ static void test_new_building_can_be_renamed(CuTest * tc) static void test_rename_building(CuTest * tc) { region *r; - building *b; - unit *u; - faction *f; - building_type *btype; test_cleanup(); @@ -52,13 +46,9 @@ static void test_rename_building(CuTest * tc) static void test_rename_building_twice(CuTest * tc) { region *r; - building *b; - unit *u; - faction *f; - building_type *btype; test_cleanup(); @@ -83,11 +73,8 @@ static void test_rename_building_twice(CuTest * tc) static void test_fishing_feeds_2_people(CuTest * tc) { region *r; - faction *f; - unit *u; - ship *sh; test_cleanup(); @@ -125,11 +112,8 @@ static int not_so_hungry(const unit * u) static void test_fishing_does_not_give_goblins_money(CuTest * tc) { region *r; - faction *f; - unit *u; - ship *sh; test_cleanup(); @@ -144,7 +128,6 @@ static void test_fishing_does_not_give_goblins_money(CuTest * tc) i_change(&u->items, it_find("money"), 42); global.functions.maintenance = not_so_hungry; - scale_number(u, 2); sh->flags |= SF_FISHING; get_food(r); @@ -155,11 +138,8 @@ static void test_fishing_does_not_give_goblins_money(CuTest * tc) static void test_fishing_gets_reset(CuTest * tc) { region *r; - faction *f; - unit *u; - ship *sh; test_cleanup(); @@ -186,21 +166,17 @@ static void test_fishing_gets_reset(CuTest * tc) static void test_unit_limit(CuTest * tc) { set_param(&global.parameters, "rules.limit.faction", "250"); - CuAssertIntEquals(tc, 250, rule_faction_limit()); set_param(&global.parameters, "rules.limit.faction", "200"); - CuAssertIntEquals(tc, 200, rule_faction_limit()); set_param(&global.parameters, "rules.limit.alliance", "250"); - CuAssertIntEquals(tc, 250, rule_alliance_limit()); } extern int checkunitnumber(const faction * f, int add); - static void test_cannot_create_unit_above_limit(CuTest * tc) { faction *f; @@ -214,16 +190,13 @@ static void test_cannot_create_unit_above_limit(CuTest * tc) CuAssertIntEquals(tc, 2, checkunitnumber(f, 5)); set_param(&global.parameters, "rules.limit.alliance", "3"); - CuAssertIntEquals(tc, 0, checkunitnumber(f, 3)); CuAssertIntEquals(tc, 1, checkunitnumber(f, 4)); } - CuSuite *get_laws_suite(void) { CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, &test_new_building_can_be_renamed); SUITE_ADD_TEST(suite, &test_rename_building); SUITE_ADD_TEST(suite, &test_rename_building_twice); diff --git a/src/gamecode/market.c b/src/gamecode/market.c index c247374fa..569a29b37 100644 --- a/src/gamecode/market.c +++ b/src/gamecode/market.c @@ -33,11 +33,8 @@ without prior permission by the authors of Eressea. static unsigned int get_markets(region * r, unit ** results, size_t size) { unsigned int n = 0; - building *b; - static building_type *btype; - if (!btype) btype = bt_find("market"); if (!btype) @@ -46,9 +43,7 @@ static unsigned int get_markets(region * r, unit ** results, size_t size) if (b->type == btype && (b->flags & BLD_WORKING) && b->size >= b->type->maxsize) { unit *u = building_owner(b); - unsigned int i; - for (i = 0; u && i != n; ++i) { /* only one market per faction */ if (results[i]->faction == u->faction) @@ -62,11 +57,9 @@ static unsigned int get_markets(region * r, unit ** results, size_t size) return n; } - static void free_market(attrib * a) { item *items = (item *) a->data.v; - i_freeall(&items); a->data.v = 0; } @@ -99,34 +92,24 @@ static int rc_herb_trade(const struct race *rc) void do_markets(void) { quicklist *traders = 0; - unit *markets[MAX_MARKETS]; - region *r; - for (r = regions; r; r = r->next) { if (r->land) { faction *f = region_get_owner(r); - const struct race *rc = f ? f->race : NULL; - int p = rpeasants(r); - int numlux = rc_luxury_trade(rc), numherbs = rc_herb_trade(rc); - numlux = (p + numlux - MIN_PEASANTS) / numlux; numherbs = (p + numherbs - MIN_PEASANTS) / numherbs; if (numlux > 0 || numherbs > 0) { int d, nmarkets = 0; - const item_type *lux = r_luxury(r); - const item_type *herb = r->land->herbtype; nmarkets += get_markets(r, markets + nmarkets, MAX_MARKETS - nmarkets); for (d = 0; d != MAXDIRECTIONS; ++d) { region *r2 = rconnect(r, d); - if (r2 && r2->buildings) { nmarkets += get_markets(r2, markets + nmarkets, MAX_MARKETS - nmarkets); @@ -135,13 +118,9 @@ void do_markets(void) if (nmarkets) { while (lux && numlux--) { int n = rng_int() % nmarkets; - unit *u = markets[n]; - item *items; - attrib *a = a_find(u->attribs, &at_market); - if (a == NULL) { a = a_add(&u->attribs, a_new(&at_market)); ql_push(&traders, u); @@ -153,13 +132,9 @@ void do_markets(void) } while (herb && numherbs--) { int n = rng_int() % nmarkets; - unit *u = markets[n]; - item *items; - attrib *a = a_find(u->attribs, &at_market); - if (a == NULL) { a = a_add(&u->attribs, a_new(&at_market)); ql_push(&traders, u); @@ -176,20 +151,15 @@ void do_markets(void) if (traders) { quicklist *qliter = traders; - int qli = 0; - for (qli = 0; qliter; ql_advance(&qliter, &qli, 1)) { unit *u = (unit *) ql_get(qliter, qli); - attrib *a = a_find(u->attribs, &at_market); - item *items = (item *) a->data.v; a->data.v = NULL; while (items) { item *itm = items; - items = itm->next; if (itm->number) { diff --git a/src/gamecode/market_test.c b/src/gamecode/market_test.c index f82651ec4..edf27b2bb 100644 --- a/src/gamecode/market_test.c +++ b/src/gamecode/market_test.c @@ -6,31 +6,19 @@ static void market_curse(CuTest * tc) { region *r; - building *b; - unit *u; - faction *f; - int x, y; const char *names[4] = { "herb", "herbs", "balm", "balms" }; terrain_type *terrain; - resource_type *hres = new_resourcetype(names, 0, RTF_ITEM | RTF_POOLED); - item_type *htype = new_itemtype(hres, ITF_HERB, 0, 0); - resource_type *lres = new_resourcetype(names + 2, 0, RTF_ITEM | RTF_POOLED); - item_type *ltype = new_itemtype(lres, ITF_NONE, 0, 0); - luxury_type *lux = new_luxurytype(ltype, 0); - building_type *btype; - race *rc = rc_add(rc_new("human")); - struct locale *lang = make_locale("en"); free_gamedata(); @@ -74,7 +62,6 @@ static void market_curse(CuTest * tc) CuSuite *get_market_suite(void) { CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, market_curse); return suite; } diff --git a/src/gamecode/monster.c b/src/gamecode/monster.c index dad941f93..1c4911cd1 100644 --- a/src/gamecode/monster.c +++ b/src/gamecode/monster.c @@ -81,9 +81,7 @@ static void eaten_by_monster(unit * u) { /* adjustment for smaller worlds */ static double multi = 0.0; - int n = 0; - int horse = 0; if (multi == 0.0) { @@ -148,7 +146,6 @@ static void absorbed_by_monster(unit * u) static int scareaway(region * r, int anzahl) { int n, p, diff = 0, emigrants[MAXDIRECTIONS]; - direction_t d; anzahl = MIN(MAX(1, anzahl), rpeasants(r)); @@ -165,7 +162,6 @@ static int scareaway(region * r, int anzahl) assert(p >= 0 && anzahl >= 0); for (n = MIN(p, anzahl); n; n--) { direction_t dir = (direction_t) (rng_int() % MAXDIRECTIONS); - region *rc = rconnect(r, dir); if (rc && fval(rc->terrain, LAND_REGION)) { diff --git a/src/gamecode/randenc.c b/src/gamecode/randenc.c index 35f13178a..0bdfbcd94 100644 --- a/src/gamecode/randenc.c +++ b/src/gamecode/randenc.c @@ -68,7 +68,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include extern struct attrib_type at_unitdissolve; - extern struct attrib_type at_orcification; /* In a->data.ca[1] steht der Prozentsatz mit dem sich die Einheit @@ -77,17 +76,13 @@ extern struct attrib_type at_orcification; static void dissolve_units(void) { region *r; - unit *u; - int n; - int i; for (r = regions; r; r = r->next) { for (u = r->units; u; u = u->next) { attrib *a = a_find(u->attribs, &at_unitdissolve); - if (a) { message *msg; @@ -157,13 +152,11 @@ static void dissolve_units(void) static int improve_all(faction * f, skill_t sk, int by_weeks) { unit *u; - boolean ret = by_weeks; for (u = f->units; u; u = u->nextF) { if (has_skill(u, sk)) { int weeks = 0; - for (; weeks != by_weeks; ++weeks) { learn_skill(u, sk, 1.0); ret = 0; @@ -177,11 +170,8 @@ static int improve_all(faction * f, skill_t sk, int by_weeks) void find_manual(region * r, unit * u) { char zLocation[32]; - char zBook[32]; - skill_t skill = NOSKILL; - message *msg; switch (rng_int() % 36) { @@ -255,7 +245,6 @@ void find_manual(region * r, unit * u) if (improve_all(u->faction, skill, 3) == 3) { int i; - for (i = 0; i != 9; ++i) learn_skill(u, skill, 1.0); } @@ -264,9 +253,7 @@ void find_manual(region * r, unit * u) static void get_villagers(region * r, unit * u) { unit *newunit; - message *msg = msg_message("encounter_villagers", "unit", u); - const char *name = LOC(u->faction->locale, "villagers"); r_addmessage(r, u->faction, msg); @@ -283,13 +270,9 @@ static void get_villagers(region * r, unit * u) static void get_allies(region * r, unit * u) { unit *newunit = NULL; - const char *name; - const char *equip; - int number; - message *msg; assert(u->number); @@ -410,16 +393,13 @@ void encounters(void) for (r = regions; r; r = r->next) { if (!fval(r->terrain, SEA_REGION) && fval(r, RF_ENCOUNTER)) { int c = 0; - unit *u; - for (u = r->units; u; u = u->next) { c += u->number; } if (c > 0) { int i = 0; - int n = rng_int() % c; for (u = r->units; u; u = u->next) { @@ -437,12 +417,10 @@ void encounters(void) static const terrain_type *chaosterrain(void) { static const terrain_type **types; - static int numtypes; if (numtypes == 0) { const terrain_type *terrain; - for (terrain = terrains(); terrain != NULL; terrain = terrain->next) { if (fval(terrain, LAND_REGION) && terrain->herbs) { ++numtypes; @@ -459,13 +437,10 @@ static const terrain_type *chaosterrain(void) return types[rng_int() % numtypes]; } - static unit *random_unit(const region * r) { int c = 0; - int n; - unit *u; for (u = r->units; u; u = u->next) { @@ -498,7 +473,6 @@ void chaos(region * r) case 0: /* Untote */ if (!fval(r->terrain, SEA_REGION)) { unit *u = random_unit(r); - if (u && playerrace(u->race)) { ADDMSG(&u->faction->msgs, msg_message("chaos_disease", "unit", u)); u_setfaction(u, get_monsters()); @@ -509,9 +483,7 @@ void chaos(region * r) case 1: /* Drachen */ if (random_unit(r)) { int mfac = 0; - unit *u; - switch (rng_int() % 3) { case 0: mfac = 100; @@ -540,21 +512,17 @@ void chaos(region * r) if (!fval(r->terrain, FORBIDDEN_REGION)) { if (!fval(r->terrain, SEA_REGION)) { direction_t dir; - for (dir = 0; dir != MAXDIRECTIONS; ++dir) { region *rn = rconnect(r, dir); - if (rn && fval(rn->terrain, SEA_REGION)) break; } if (dir != MAXDIRECTIONS) { ship *sh = r->ships; - unit **up; while (sh) { ship *nsh = sh->next; - float dmg = get_param_flt(global.parameters, "rules.ship.damage.atlantis", 0.50); @@ -567,7 +535,6 @@ void chaos(region * r) for (up = &r->units; *up;) { unit *u = *up; - if (u->race != new_race[RC_SPELL] && u->ship == 0 && !canfly(u)) { ADDMSG(&u->faction->msgs, msg_message("tidalwave_kill", "region unit", r, u)); @@ -585,10 +552,8 @@ void chaos(region * r) } } else { direction_t dir; - for (dir = 0; dir != MAXDIRECTIONS; ++dir) { region *rn = rconnect(r, dir); - if (rn && fval(rn->terrain, SEA_REGION)) break; } @@ -601,13 +566,10 @@ void chaos(region * r) } } - static int nb_armor(const unit * u, int index) { const item *itm; - int av = 0; - int s = 0, a = 0; if (!(u->race->battle_flags & BF_EQUIPMENT)) @@ -617,10 +579,8 @@ static int nb_armor(const unit * u, int index) for (itm = u->items; itm; itm = itm->next) { const armor_type *atype = itm->type->rtype->atype; - if (atype != NULL) { int *schutz = &a; - if (atype->flags & ATF_SHIELD) schutz = &s; if (*schutz <= index) { @@ -638,11 +598,8 @@ static int damage_unit(unit * u, const char *dam, boolean physical, boolean magic) { int *hp = malloc(u->number * sizeof(int)); - int h; - int i, dead = 0, hp_rem = 0, heiltrank; - double magres = magic_resistance(u); assert(u->number); @@ -661,7 +618,6 @@ damage_unit(unit * u, const char *dam, boolean physical, boolean magic) /* Schaden */ for (i = 0; i < u->number; i++) { int damage = dice_rand(dam); - if (magic) damage = (int)(damage * (1.0 - magres)); if (physical) @@ -715,12 +671,9 @@ void drown(region * r) { if (fval(r->terrain, SEA_REGION)) { unit **up = up = &r->units; - while (*up) { unit *u = *up; - int amphibian_level = 0; - if (u->ship || u->race == new_race[RC_SPELL] || u->number == 0) { up = &u->next; continue; @@ -728,7 +681,6 @@ void drown(region * r) if (amphibian_level) { int dead = damage_unit(u, "5d1", false, false); - if (dead) { ADDMSG(&u->faction->msgs, msg_message("drown_amphibian_dead", "amount unit region", dead, u, r)); @@ -750,9 +702,7 @@ void drown(region * r) region *rrandneighbour(region * r) { direction_t i; - region *rc = NULL; - int rr, c = 0; /* Nachsehen, wieviele Regionen in Frage kommen */ @@ -782,9 +732,7 @@ volcano_destruction(region * volcano, region * r, region * rn, const char *damage) { attrib *a; - unit **up; - int percent = 25, time = 6 + rng_int() % 12; rsettrees(r, 2, 0); @@ -805,10 +753,8 @@ volcano_destruction(region * volcano, region * r, region * rn, for (up = &r->units; *up;) { unit *u = *up; - if (u->number) { int dead = damage_unit(u, damage, true, false); - if (dead) { ADDMSG(&u->faction->msgs, msg_message("volcano_dead", "unit region dead", u, volcano, dead)); @@ -834,9 +780,7 @@ volcano_destruction(region * volcano, region * r, region * rn, void volcano_outbreak(region * r) { region *rn; - unit *u; - faction *f; for (f = NULL, u = r->units; u; u = u->next) { @@ -858,7 +802,6 @@ void volcano_outbreak(region * r) static void melt_iceberg(region * r) { attrib *a; - unit *u; for (u = r->units; u; u = u->next) @@ -890,9 +833,7 @@ static void melt_iceberg(region * r) static void move_iceberg(region * r) { attrib *a; - direction_t dir; - region *rc; a = a_find(r->attribs, &at_iceberg); @@ -913,12 +854,9 @@ static void move_iceberg(region * r) if (rc && !fval(rc->terrain, ARCTIC_REGION)) { if (fval(rc->terrain, SEA_REGION)) { /* Eisberg treibt */ ship *sh, *shn; - unit *u; - int x, y; - for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT); for (u = r->units; u; u = u->next) @@ -972,7 +910,6 @@ static void move_iceberg(region * r) } while (rc->units) { building *b = rc->units->building; - u = rc->units; move_unit(rc->units, r, NULL); u->building = b; /* move_unit macht ein leave() */ @@ -1022,7 +959,6 @@ static void move_icebergs(void) for (r = regions; r; r = r->next) { if (r->terrain == newterrain(T_ICEBERG) && !fval(r, RF_SELECT)) { int select = rng_int() % 10; - if (select < 4) { /* 4% chance */ fset(r, RF_SELECT); @@ -1043,11 +979,8 @@ void create_icebergs(void) for (r = regions; r; r = r->next) { if (r->terrain == newterrain(T_ICEBERG_SLEEP) && chance(0.05)) { boolean has_ocean_neighbour = false; - direction_t dir; - region *rc; - unit *u; freset(r, RF_SELECT); @@ -1086,30 +1019,24 @@ static void godcurse(void) for (r = regions; r; r = r->next) { if (is_cursed(r->attribs, C_CURSED_BY_THE_GODS, 0)) { unit *u; - for (u = r->units; u; u = u->next) { skill *sv = u->skills; - while (sv != u->skills + u->skill_size) { int weeks = 1 + rng_int() % 3; - reduce_skill(u, sv, weeks); ++sv; } } if (fval(r->terrain, SEA_REGION)) { ship *sh; - for (sh = r->ships; sh;) { ship *shn = sh->next; - float dmg = get_param_flt(global.parameters, "rules.ship.damage.godcurse", 0.10F); damage_ship(sh, dmg); if (sh->damage >= sh->size * DAMAGE_SCALE) { unit *u = shipowner(sh); - if (u) ADDMSG(&u->faction->msgs, msg_message("godcurse_destroy_ship", "ship", sh)); @@ -1130,17 +1057,12 @@ static void godcurse(void) static void orc_growth(void) { region *r; - for (r = regions; r; r = r->next) { unit *u; - for (u = r->units; u; u = u->next) { static boolean init = false; - static const curse_type *ct_orcish = 0; - curse *c = 0; - if (!init) { init = true; ct_orcish = ct_find("orcish"); @@ -1151,11 +1073,8 @@ static void orc_growth(void) if (c && !has_skill(u, SK_MAGIC) && !has_skill(u, SK_ALCHEMY) && !fval(u, UFL_HERO)) { int n; - int increase = 0; - int num = get_cursedmen(u, c); - double prob = curse_geteffect(c); for (n = (num - get_item(u, I_CHASTITY_BELT)); n > 0; n--) { @@ -1165,7 +1084,6 @@ static void orc_growth(void) } if (increase) { unit *u2 = create_unit(r, u->faction, increase, u->race, 0, NULL, u); - transfermen(u2, u, u2->number); ADDMSG(&u->faction->msgs, msg_message("orcgrowth", @@ -1184,19 +1102,15 @@ static void demon_skillchanges(void) for (r = regions; r; r = r->next) { unit *u; - for (u = r->units; u; u = u->next) { if (u->race == new_race[RC_DAEMON]) { skill *sv = u->skills; - int upchance = 15; - int downchance = 10; if (fval(u, UFL_HUNGER)) { /* hungry demons only go down, never up in skill */ static int rule_hunger = -1; - if (rule_hunger < 0) { rule_hunger = get_param_int(global.parameters, "hunger.demon.skill", 0); @@ -1209,10 +1123,8 @@ static void demon_skillchanges(void) while (sv != u->skills + u->skill_size) { int roll = rng_int() % 100; - if (sv->level > 0 && roll < upchance + downchance) { int weeks = 1 + rng_int() % 3; - if (roll < downchance) { reduce_skill(u, sv, weeks); if (sv->level < 1) { @@ -1244,7 +1156,6 @@ static void demon_skillchanges(void) static void icebergs(void) { region *r; - create_icebergs(); move_icebergs(); for (r = regions; r; r = r->next) { @@ -1256,7 +1167,6 @@ static void icebergs(void) static void rotting_herbs(void) { static int rule_rot = -1; - region *r; if (rule_rot < 0) { @@ -1268,7 +1178,6 @@ static void rotting_herbs(void) for (r = regions; r; r = r->next) { unit *u; - for (u = r->units; u; u = u->next) { item **itmp = &u->items, *hbag = *i_find(itmp, olditemtype[I_SACK_OF_CONSERVATION]); @@ -1278,18 +1187,12 @@ static void rotting_herbs(void) rot_chance = (rot_chance * 2) / 5; while (*itmp) { item *itm = *itmp; - int n = itm->number; - double k = n * rot_chance / 100.0; - if (fval(itm->type, ITF_HERB)) { double nv = normalvariate(k, k / 4); - int inv = (int)nv; - int delta = MIN(n, inv); - if (i_change(itmp, itm->type, -delta) == NULL) { continue; } @@ -1315,12 +1218,9 @@ void randomevents(void) for (r = regions; r; r = r->next) { if (fval(r, RF_ORCIFIED)) { direction_t dir; - double probability = 0.0; - for (dir = 0; dir < MAXDIRECTIONS; dir++) { region *rc = rconnect(r, dir); - if (rc && rpeasants(rc) > 0 && !fval(rc, RF_ORCIFIED)) probability += 0.02; } @@ -1330,10 +1230,8 @@ void randomevents(void) } } else { attrib *a = a_find(r->attribs, &at_orcification); - if (a != NULL) { double probability = 0.0; - if (rpeasants(r) <= 0) continue; probability = a->data.i / (double)rpeasants(r); @@ -1376,10 +1274,8 @@ void randomevents(void) for (r = regions; r; r = r->next) { building **blist = &r->buildings; - while (*blist) { building *b = *blist; - if (fval(b->type, BTF_DECAY) && !building_owner(b)) { b->size -= MAX(1, (b->size * 20) / 100); if (b->size == 0) { diff --git a/src/gamecode/report.c b/src/gamecode/report.c index 742a7c63d..1d64a60ba 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -99,17 +99,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #endif extern int verbosity; - extern int *storms; - extern int weeks_per_month; - extern int months_per_year; static char *gamedate_season(const struct locale *lang) { static char buf[256]; - gamedate gd; get_gamedate(turn, &gd); @@ -145,7 +141,6 @@ static void centre(FILE * F, const char *s, boolean breaking) if (breaking && REPORTWIDTH < strlen(s)) { strlist *T, *SP = 0; - sparagraph(&SP, s, 0, 0); T = SP; while (SP) { @@ -165,15 +160,12 @@ rparagraph(FILE * F, const char *str, ptrdiff_t indent, int hanging_indent, char mark) { static const char *spaces = " "; - size_t length = REPORTWIDTH; - const char *end, *begin; /* find out if there's a mark + indent already encoded in the string. */ if (!mark) { const char *x = str; - while (*x == ' ') ++x; indent += x - str; @@ -225,15 +217,10 @@ rparagraph(FILE * F, const char *str, ptrdiff_t indent, int hanging_indent, static void nr_spell(FILE * F, spell * sp, const struct locale *lang) { int bytes, k, itemanz, costtyp; - int dh = 0; - char buf[4096]; - char *bufp = buf; - size_t size = sizeof(buf) - 1; - const char *params = sp->parameter; rnl(F); @@ -273,7 +260,6 @@ static void nr_spell(FILE * F, spell * sp, const struct locale *lang) rparagraph(F, LOC(lang, "nr_spell_components"), 0, 0, 0); for (k = 0; sp->components[k].type; ++k) { const resource_type *rtype = sp->components[k].type; - itemanz = sp->components[k].amount; costtyp = sp->components[k].cost; if (itemanz > 0) { @@ -395,7 +381,6 @@ static void nr_spell(FILE * F, spell * sp, const struct locale *lang) int flag; const char *vars; } starget; - starget targets[] = { {P_REGION, REGIONSPELL, NULL}, {P_UNIT, UNITSPELL, "par_unit"}, @@ -404,13 +389,9 @@ static void nr_spell(FILE * F, spell * sp, const struct locale *lang) {0, 0, NULL} }; starget *targetp; - char cp = *params++; - int i, maxparam = 0; - const char *locp; - const char *syntaxp = sp->syntax; if (cp == 'u') { @@ -507,14 +488,12 @@ static void nr_spell(FILE * F, spell * sp, const struct locale *lang) } } else if (cp == 'i' || cp == 'c') { const char *cstr; - assert(syntaxp); cstr = strchr(syntaxp, ':'); if (!cstr) { locp = LOC(lang, mkname("spellpar", syntaxp)); } else { char substr[32]; - strncpy(substr, syntaxp, cstr - syntaxp); substr[cstr - syntaxp] = 0; locp = LOC(lang, mkname("spellpar", substr)); @@ -538,9 +517,7 @@ void sparagraph(strlist ** SP, const char *s, int indent, char mark) * Vgl. spunit (). */ int i, j, width; - int firstline; - static char buf[REPORTWIDTH + 1]; width = REPORTWIDTH - indent; @@ -604,9 +581,7 @@ nr_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ, int indent) { attrib *a = NULL; - int self = 0; - region *r; /* Die Sichtbarkeit eines Zaubers und die Zaubermeldung sind bei @@ -616,9 +591,7 @@ nr_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ, * bei jedem curse gesondert behandelt. */ if (typ == TYP_SHIP) { ship *sh = (ship *) obj; - unit *owner = shipowner(sh); - a = sh->attribs; r = sh->region; if (owner) { @@ -626,7 +599,6 @@ nr_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ, self = 2; } else { /* steht eine person der Partei auf dem Schiff? */ unit *u = NULL; - for (u = r->units; u; u = u->next) { if (u->ship == sh) { self = 1; @@ -637,9 +609,7 @@ nr_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ, } } else if (typ == TYP_BUILDING) { building *b = (building *) obj; - unit *owner; - a = b->attribs; r = b->region; if ((owner = building_owner(b)) != NULL) { @@ -647,7 +617,6 @@ nr_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ, self = 2; } else { /* steht eine Person der Partei in der Burg? */ unit *u = NULL; - for (u = r->units; u; u = u->next) { if (u->building == b) { self = 1; @@ -658,7 +627,6 @@ nr_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ, } } else if (typ == TYP_UNIT) { unit *u = (unit *) obj; - a = u->attribs; r = u->region; if (u->faction == viewer) { @@ -676,7 +644,6 @@ nr_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ, if (fval(a->type, ATF_CURSE)) { curse *c = (curse *) a->data.v; - message *msg; if (c->type->cansee) { @@ -692,7 +659,6 @@ nr_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ, } } else if (a->type == &at_effect && self) { effect_data *data = (effect_data *) a->data.v; - if (data->value > 0) { sprintf(buf, "Auf der Einheit lieg%s %d Wirkung%s %s.", (data->value == 1 ? "t" : "en"), @@ -709,7 +675,6 @@ nr_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ, static void rps_nowrap(FILE * F, const char *s) { const char *x = s; - size_t indent = 0; while (*x++ == ' ') ; @@ -731,13 +696,9 @@ static void nr_unit(FILE * F, const faction * f, const unit * u, int indent, int mode) { attrib *a_otherfaction; - char marker; - int dh; - boolean isbattle = (boolean) (mode == see_battle); - char buf[8192]; if (fval(u->race, RCF_INVISIBLE)) @@ -777,14 +738,11 @@ rp_messages(FILE * F, message_list * msgs, faction * viewer, int indent, boolean categorized) { nrsection *section; - if (!msgs) return; for (section = sections; section; section = section->next) { int k = 0; - struct mlist *m = msgs->begin; - while (m) { /* messagetype * mt = m->type; */ if (!categorized || strcmp(nr_section(m->msg), section->name) == 0) { @@ -792,7 +750,6 @@ rp_messages(FILE * F, message_list * msgs, faction * viewer, int indent, if (!k && categorized) { const char *section_title; - char cat_identifier[24]; rnl(F); @@ -816,14 +773,12 @@ static void rp_battles(FILE * F, faction * f) { if (f->battles != NULL) { struct bmsg *bm = f->battles; - rnl(F); centre(F, LOC(f->locale, "section_battle"), false); rnl(F); while (bm) { char buf[256]; - RENDER(f, buf, sizeof(buf), ("battle::header", "region", bm->r)); rnl(F); centre(F, buf, true); @@ -837,15 +792,10 @@ static void rp_battles(FILE * F, faction * f) static void prices(FILE * F, const region * r, const faction * f) { const luxury_type *sale = NULL; - struct demand *dmd; - message *m; - int bytes, n = 0; - char buf[4096], *bufp = buf; - size_t size = sizeof(buf) - 1; if (r->land == NULL || r->land->demands == NULL) @@ -919,12 +869,10 @@ static void prices(FILE * F, const region * r, const faction * f) boolean see_border(const connection * b, const faction * f, const region * r) { boolean cs = b->type->fvisible(b, f, r); - if (!cs) { cs = b->type->rvisible(b, r); if (!cs) { const unit *us = r->units; - while (us && !cs) { if (us->faction == f) { cs = b->type->uvisible(b, us); @@ -941,21 +889,13 @@ boolean see_border(const connection * b, const faction * f, const region * r) static void describe(FILE * F, const seen_region * sr, faction * f) { const region *r = sr->r; - int n; - boolean dh; - direction_t d; - int trees; - int saplings; - attrib *a; - const char *tname; - struct edge { struct edge *next; char *name; @@ -964,31 +904,22 @@ static void describe(FILE * F, const seen_region * sr, faction * f) boolean exist[MAXDIRECTIONS]; direction_t lastd; } *edges = NULL, *e; - boolean see[MAXDIRECTIONS]; - char buf[8192]; - char *bufp = buf; - size_t size = sizeof(buf); - int bytes; for (d = 0; d != MAXDIRECTIONS; d++) { /* Nachbarregionen, die gesehen werden, ermitteln */ region *r2 = rconnect(r, d); - connection *b; - see[d] = true; if (!r2) continue; for (b = get_borders(r, r2); b;) { struct edge *e = edges; - boolean transparent = b->type->transparent(b, f); - const char *name = b->type->name(b, r, f, GF_DETAILED | GF_ARTICLE); if (!transparent) @@ -1066,7 +997,6 @@ static void describe(FILE * F, const seen_region * sr, faction * f) /* iron & stone */ if (sr->mode == see_unit && f != (faction *) NULL) { resource_report result[MAX_RAWMATERIALS]; - int n, numresults = report_resources(sr, result, MAX_RAWMATERIALS, f); for (n = 0; n < numresults; ++n) { @@ -1082,7 +1012,6 @@ static void describe(FILE * F, const seen_region * sr, faction * f) /* peasants & silver */ if (rpeasants(r)) { int n = rpeasants(r); - bytes = snprintf(bufp, size, ", %d", n); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -1144,7 +1073,6 @@ static void describe(FILE * F, const seen_region * sr, faction * f) if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - if (r->display && r->display[0]) { bytes = (int)strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) @@ -1163,7 +1091,6 @@ static void describe(FILE * F, const seen_region * sr, faction * f) if (rule_region_owners()) { const faction *owner = region_get_owner(r); - if (owner != NULL) { bytes = snprintf(bufp, size, " Die Region ist im Besitz von %s.", factionname(owner)); @@ -1194,13 +1121,11 @@ static void describe(FILE * F, const seen_region * sr, faction * f) for (d = 0; d != MAXDIRECTIONS; d++) if (see[d]) { region *r2 = rconnect(r, d); - if (!r2) continue; nrd--; if (dh) { char regname[4096]; - if (nrd == 0) { bytes = (int)strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) @@ -1235,7 +1160,6 @@ static void describe(FILE * F, const seen_region * sr, faction * f) for (a = a_find(r->attribs, &at_direction); a && a->type == &at_direction; a = a->next) { spec_direction *d = (spec_direction *) (a->data.v); - bytes = (int)strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -1265,7 +1189,6 @@ static void describe(FILE * F, const seen_region * sr, faction * f) !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) { /* Sonderbehandlung Teleport-Ebene */ region_list *rl = astralregions(r, inhabitable); - region_list *rl2; if (rl) { @@ -1306,7 +1229,6 @@ static void describe(FILE * F, const seen_region * sr, faction * f) a = a_find(r->attribs, &at_reduceproduction); if (a) { const char *str = LOC(f->locale, "nr_reduced_production"); - rparagraph(F, str, 0, 0, 0); } @@ -1314,7 +1236,6 @@ static void describe(FILE * F, const seen_region * sr, faction * f) rnl(F); for (e = edges; e; e = e->next) { boolean first = true; - bufp = buf; size = sizeof(buf) - 1; for (d = 0; d != MAXDIRECTIONS; ++d) { @@ -1364,13 +1285,9 @@ static void describe(FILE * F, const seen_region * sr, faction * f) static void statistics(FILE * F, const region * r, const faction * f) { const unit *u; - int number = 0, p = rpeasants(r); - message *m; - item *itm, *items = NULL; - char buf[4096]; /* count */ @@ -1435,7 +1352,6 @@ static void statistics(FILE * F, const region * r, const faction * f) msg_release(m); } - } /* info about units */ @@ -1457,15 +1373,10 @@ static void durchreisende(FILE * F, const region * r, const faction * f) { if (fval(r, RF_TRAVELUNIT)) { attrib *abegin = a_find(r->attribs, &at_travelunit), *a; - int counter = 0, maxtravel = 0; - char buf[8192]; - char *bufp = buf; - int bytes; - size_t size = sizeof(buf) - 1; /* How many are we listing? For grammar. */ @@ -1543,13 +1454,9 @@ static void durchreisende(FILE * F, const region * r, const faction * f) static int buildingmaintenance(const building * b, const resource_type * rtype) { const building_type *bt = b->type; - int c, cost = 0; - static boolean init = false; - static const curse_type *nocost_ct; - if (!init) { init = true; nocost_ct = ct_find("nocostbuilding"); @@ -1559,7 +1466,6 @@ static int buildingmaintenance(const building * b, const resource_type * rtype) } for (c = 0; bt->maintenance && bt->maintenance[c].number; ++c) { const maintenance *m = bt->maintenance + c; - if (m->rtype == rtype) { if (fval(m, MTF_VARIABLE)) cost += (b->size * m->number); @@ -1574,17 +1480,11 @@ static int report_template(const char *filename, report_context * ctx, const char *charset) { faction *f = ctx->f; - region *r; - FILE *F = fopen(filename, "wt"); - seen_region *sr = NULL; - char buf[8192], *bufp; - size_t size; - int bytes; int enc = xmlParseCharEncoding(charset); @@ -1625,9 +1525,7 @@ report_template(const char *filename, report_context * ctx, const char *charset) for (; sr != NULL; sr = sr->next) { region *r = sr->r; - unit *u; - int dh = 0; if (sr->mode < see_unit) @@ -1636,10 +1534,8 @@ report_template(const char *filename, report_context * ctx, const char *charset) for (u = r->units; u; u = u->next) { if (u->faction == f && !fval(u->race, RCF_INVISIBLE)) { order *ord; - if (!dh) { plane *pl = getplane(r); - int nx = r->x, ny = r->y; pnormalize(&nx, &ny, pl); @@ -1672,7 +1568,6 @@ report_template(const char *filename, report_context * ctx, const char *charset) WARN_STATIC_BUFFER(); if (u->building != NULL && fval(u, UFL_OWNER)) { building *b = u->building; - int cost = buildingmaintenance(b, r_silver); if (cost > 0) { @@ -1744,27 +1639,21 @@ static void show_allies(const faction * f, const ally * allies, char *buf, size_t size) { int allierte = 0; - int i = 0, h, hh = 0; - int bytes, dh = 0; - const ally *sf; - char *bufp = buf; /* buf already contains data */ --size; /* leave room for a null-terminator */ for (sf = allies; sf; sf = sf->next) { int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); - if (mode > 0) ++allierte; } for (sf = allies; sf; sf = sf->next) { int mode = alliedgroup(NULL, f, sf->faction, sf, HELP_ALL); - if (mode <= 0) continue; i++; @@ -1792,7 +1681,6 @@ show_allies(const faction * f, const ally * allies, char *buf, size_t size) } else { for (h = 1; h < HELP_ALL; h *= 2) { int p = MAXPARAMS; - if ((mode & h) == h) { switch (h) { case HELP_TRAVEL: @@ -1841,14 +1729,11 @@ show_allies(const faction * f, const ally * allies, char *buf, size_t size) static void allies(FILE * F, const faction * f) { const group *g = f->groups; - char buf[16384]; if (f->allies) { int bytes; - size_t size = sizeof(buf); - if (!f->allies->next) { bytes = (int)strlcpy(buf, "Wir helfen der Partei ", size); } else { @@ -1863,9 +1748,7 @@ static void allies(FILE * F, const faction * f) while (g) { if (g->allies) { int bytes; - size_t size = sizeof(buf); - if (!g->allies->next) { bytes = snprintf(buf, size, "%s hilft der Partei ", g->name); } else { @@ -1890,17 +1773,14 @@ static void guards(FILE * F, const region * r, const faction * see) int nextguard = 0; unit *u; - int i; boolean tarned = false; - /* Bewachung */ for (u = r->units; u; u = u->next) { if (is_guard(u, GUARD_ALL) != 0) { faction *f = u->faction; - faction *fv = visible_faction(see, u); if (fv != f && see != fv) { @@ -1922,11 +1802,8 @@ static void guards(FILE * F, const region * r, const faction * see) if (nextguard || tarned) { char buf[8192]; - char *bufp = buf; - size_t size = sizeof(buf) - 1; - int bytes; bytes = (int)strlcpy(bufp, "Die Region wird von ", size); @@ -1963,7 +1840,6 @@ static void guards(FILE * F, const region * r, const faction * see) static void rpline(FILE * F) { static char line[REPORTWIDTH + 1]; - if (line[0] != '-') { memset(line, '-', sizeof(line)); line[REPORTWIDTH] = '\n'; @@ -1974,7 +1850,6 @@ static void rpline(FILE * F) static void list_address(FILE * F, const faction * uf, quicklist * seenfactions) { int qi = 0; - quicklist *flist = seenfactions; centre(F, LOC(uf->locale, "nr_addresses"), false); @@ -1982,10 +1857,8 @@ static void list_address(FILE * F, const faction * uf, quicklist * seenfactions) while (flist != NULL) { const faction *f = (const faction *)ql_get(flist, qi); - if (!is_monsters(f)) { char buf[8192]; - char label = '-'; sprintf(buf, "%s: %s; %s", factionname(f), f->email, @@ -2010,20 +1883,15 @@ nr_ship(FILE * F, const seen_region * sr, const ship * sh, const faction * f, const unit * captain) { const region *r = sr->r; - char buffer[8192], *bufp = buffer; - size_t size = sizeof(buffer) - 1; - int bytes; - char ch; rnl(F); if (captain && captain->faction == f) { int n = 0, p = 0; - getshipweight(sh, &n, &p); n = (n + 99) / 100; /* 1 Silber = 1 GE */ @@ -2089,13 +1957,9 @@ nr_building(FILE * F, const seen_region * sr, const building * b, const faction * f) { int i, bytes; - const char *name, *bname, *billusion = NULL; - const struct locale *lang = NULL; - char buffer[8192], *bufp = buffer; - size_t size = sizeof(buffer) - 1; rnl(F); @@ -2116,7 +1980,6 @@ nr_building(FILE * F, const seen_region * sr, const building * b, WARN_STATIC_BUFFER(); if (billusion) { unit *owner = building_owner(b); - if (owner && owner->faction == f) { /* illusion. report real type */ name = LOC(lang, bname); @@ -2166,16 +2029,13 @@ nr_building(FILE * F, const seen_region * sr, const building * b, if (b->type == bt_find("pyramid")) { unit *owner = building_owner(b); - scat("Größenstufe "); icat(wdw_pyramid_level(b)); scat("."); if (owner && owner->faction == f) { const construction *ctype = b->type->construction; - int completed = b->size; - int c; scat(" Baukosten pro Größenpunkt: "); @@ -2191,7 +2051,6 @@ nr_building(FILE * F, const seen_region * sr, const building * b, for (c = 0; ctype->materials[c].number; c++) { const resource_type *rtype = ctype->materials[c].rtype; - int number = ctype->materials[c].number; if (c > 0) { @@ -2230,9 +2089,7 @@ nr_building(FILE * F, const seen_region * sr, const building * b, static void nr_paragraph(FILE * F, message * m, faction * f) { int bytes; - char buf[4096], *bufp = buf; - size_t size = sizeof(buf) - 1; bytes = (int)nr_render(m, f->locale, bufp, size, f); @@ -2248,51 +2105,30 @@ report_plaintext(const char *filename, report_context * ctx, const char *charset) { int flag = 0; - char ch; - int anyunits, no_units, no_people; - const struct region *r; - faction *f = ctx->f; - unit *u; - char pzTime[64]; - attrib *a; - message *m; - unsigned char op; - int bytes, ix = want(O_STATISTICS); - int wants_stats = (f->options & ix); - FILE *F = fopen(filename, "wt"); - seen_region *sr = NULL; - char buf[8192]; - char *bufp; - int enc = xmlParseCharEncoding(charset); - size_t size; /* static variables can cope with writing for different turns */ static int thisseason = -1; - static int nextseason = -1; - static int gamecookie = -1; - if (gamecookie != global.cookie) { gamedate date; - get_gamedate(turn + 1, &date); thisseason = date.season; get_gamedate(turn + 2, &date); @@ -2311,7 +2147,6 @@ report_plaintext(const char *filename, report_context * ctx, strftime(pzTime, 64, "%A, %d. %B %Y, %H:%M", localtime(&ctx->report_time)); m = msg_message("nr_header_date", "game date", global.gamename, pzTime); - nr_render(m, f->locale, buf, sizeof(buf), f); msg_release(m); centre(F, buf, true); @@ -2328,7 +2163,6 @@ report_plaintext(const char *filename, report_context * ctx, if (f->age <= 2) { const char *s; - if (f->age <= 1) { ADDMSG(&f->msgs, msg_message("changepasswd", "value", f->passw)); } @@ -2388,7 +2222,6 @@ report_plaintext(const char *filename, report_context * ctx, centre(F, buf, true); if (f->race == new_race[RC_HUMAN]) { int maxmig = count_maxmigrants(f); - if (maxmig > 0) { m = msg_message("nr_migrants", "units maxunits", count_migrants(f), maxmig); @@ -2408,7 +2241,6 @@ report_plaintext(const char *filename, report_context * ctx, } { int maxh = maxheroes(f); - if (maxh) { message *msg = msg_message("nr_heroes", "units maxunits", countheroes(f), maxh); @@ -2420,7 +2252,6 @@ report_plaintext(const char *filename, report_context * ctx, if (f->items != NULL) { message *msg = msg_message("nr_claims", "items", f->items); - nr_render(msg, f->locale, buf, sizeof(buf), f); msg_release(msg); rnl(F); @@ -2471,7 +2302,6 @@ report_plaintext(const char *filename, report_context * ctx, centre(F, LOC(f->locale, "section_newspells"), true); while (a && a->type == &at_reportspell) { spell *sp = (spell *) a->data.v; - nr_spell(F, sp, f->locale); a = a->next; } @@ -2483,7 +2313,6 @@ report_plaintext(const char *filename, report_context * ctx, const potion_type *ptype = resource2potion(((const item_type *)a->data.v)->rtype); const char *description = NULL; - if (ptype != NULL) { const char *pname = resourcename(ptype->itype->rtype, 0); @@ -2508,7 +2337,6 @@ report_plaintext(const char *filename, report_context * ctx, if (ptype->itype->construction) { requirement *m = ptype->itype->construction->materials; - while (m->number) { bytes = (int)strlcpy(bufp, LOC(f->locale, resourcename(m->rtype, 0)), size); @@ -2526,7 +2354,6 @@ report_plaintext(const char *filename, report_context * ctx, rnl(F); if (description == NULL) { const char *potiontext = mkname("potion", pname); - description = LOC(f->locale, potiontext); } centre(F, description, true); @@ -2547,11 +2374,8 @@ report_plaintext(const char *filename, report_context * ctx, } for (; sr != NULL; sr = sr->next) { region *r = sr->r; - int stealthmod = stealth_modifier(sr->mode); - building *b = r->buildings; - ship *sh = r->ships; if (sr->mode < see_lighthouse) @@ -2563,11 +2387,8 @@ report_plaintext(const char *filename, report_context * ctx, describe(F, sr, f); if (markets_module() && r->land) { const item_type *lux = r_luxury(r); - const item_type *herb = r->land->herbtype; - message *m = 0; - if (herb && lux) { m = msg_message("nr_market_info_p", "p1 p2", lux ? lux->rtype : 0, herb ? herb->rtype : 0); @@ -2610,7 +2431,6 @@ report_plaintext(const char *filename, report_context * ctx, if (sr->mode == see_unit || sr->mode == see_travel) { message_list *mlist = r_getmessages(r, f); - rp_messages(F, r->msgs, f, 0, true); if (mlist) rp_messages(F, mlist, f, 0, true); @@ -2676,10 +2496,8 @@ report_plaintext(const char *filename, report_context * ctx, void base36conversion(void) { region *r; - for (r = regions; r; r = r->next) { unit *u; - for (u = r->units; u; u = u->next) { if (forbiddenid(u->no)) { uunhash(u); @@ -2708,15 +2526,11 @@ struct fsee { #define REPORT_ZIP (1 << O_COMPRESS) #define REPORT_BZIP2 (1 << O_BZIP2) - unit *can_find(faction * f, faction * f2) { int key = f->no % FMAXHASH; - struct fsee *fs = fsee[key]; - struct see *ss; - if (f == f2) return f->units; while (fs && fs->f != f) @@ -2739,15 +2553,10 @@ static void add_find(faction * f, unit * u, faction * f2) { /* faction f sees f2 through u */ int key = f->no % FMAXHASH; - struct fsee **fp = &fsee[key]; - struct fsee *fs; - struct see **sp; - struct see *ss; - while (*fp && (*fp)->f != f) fp = &(*fp)->nexthash; if (!*fp) { @@ -2770,24 +2579,19 @@ static void add_find(faction * f, unit * u, faction * f2) static void update_find(void) { region *r; - static boolean initial = true; if (initial) for (r = regions; r; r = r->next) { unit *u; - for (u = r->units; u; u = u->next) { faction *lastf = u->faction; - unit *u2; - for (u2 = r->units; u2; u2 = u2->next) { if (u2->faction == lastf || u2->faction == u->faction) continue; if (seefaction(u->faction, r, u2, 0)) { faction *fv = visible_faction(u->faction, u2); - lastf = fv; add_find(u->faction, u2, fv); } @@ -2816,11 +2620,9 @@ void register_nr(void) void report_cleanup(void) { int i; - for (i = 0; i != FMAXHASH; ++i) { while (fsee[i]) { struct fsee *fs = fsee[i]->nexthash; - free(fsee[i]); fsee[i] = fs; } diff --git a/src/gamecode/spy.c b/src/gamecode/spy.c index 26f543b3d..0eee13d5a 100644 --- a/src/gamecode/spy.c +++ b/src/gamecode/spy.c @@ -64,7 +64,6 @@ void spy_message(int spy, const unit * u, const unit * target) target, str)); if (spy > 20) { sc_mage *mage = get_mage(target); - /* bei Magiern Zaubersprüche und Magiegebiet */ if (mage) { ADDMSG(&u->faction->msgs, msg_message("spyreport_mage", "target type", @@ -73,7 +72,6 @@ void spy_message(int spy, const unit * u, const unit * target) } if (spy > 6) { faction *fv = visible_faction(u->faction, target); - if (fv && fv != target->faction) { /* wahre Partei */ ADDMSG(&u->faction->msgs, msg_message("spyreport_faction", @@ -83,11 +81,8 @@ void spy_message(int spy, const unit * u, const unit * target) } if (spy > 0) { int first = 1; - int found = 0; - skill *sv; - char buf[4096]; buf[0] = 0; @@ -118,15 +113,11 @@ void spy_message(int spy, const unit * u, const unit * target) } } - int spy_cmd(unit * u, struct order *ord) { unit *target; - int spy, observe; - double spychance, observechance; - region *r = u->region; init_tokens(ord); @@ -184,21 +175,17 @@ int spy_cmd(unit * u, struct order *ord) void set_factionstealth(unit * u, faction * f) { region *lastr = NULL; - /* for all units mu of our faction, check all the units in the region * they are in, if their visible faction is f, it's ok. use lastr to * avoid testing the same region twice in a row. */ unit *mu = u->faction->units; - while (mu != NULL) { if (mu->number && mu->region != lastr) { unit *ru = mu->region->units; - lastr = mu->region; while (ru != NULL) { if (ru->number) { faction *fv = visible_faction(f, ru); - if (fv == f) { if (cansee(f, lastr, ru, 0)) break; @@ -213,7 +200,6 @@ void set_factionstealth(unit * u, faction * f) } if (mu != NULL) { attrib *a = a_find(u->attribs, &at_otherfaction); - if (!a) a = a_add(&u->attribs, make_otherfaction(f)); else @@ -224,9 +210,7 @@ void set_factionstealth(unit * u, faction * f) int setstealth_cmd(unit * u, struct order *ord) { const char *s; - int level, rule; - const race *trace; init_tokens(ord); @@ -249,7 +233,6 @@ int setstealth_cmd(unit * u, struct order *ord) NORACE }; int i; - for (i = 0; allowed[i] != NORACE; ++i) if (new_race[allowed[i]] == trace) break; @@ -297,7 +280,6 @@ int setstealth_cmd(unit * u, struct order *ord) freset(u, UFL_ANON_FACTION); } else if (findkeyword(s, u->faction->locale) == K_NUMBER) { const char *s2 = (const char *)getstrtoken(); - int nr = -1; if (s2) @@ -306,7 +288,6 @@ int setstealth_cmd(unit * u, struct order *ord) a_removeall(&u->attribs, &at_otherfaction); } else { struct faction *f = findfaction(nr); - if (f == NULL) { cmistake(u, ord, 66, MSG_EVENT); } else { @@ -342,13 +323,11 @@ int setstealth_cmd(unit * u, struct order *ord) static int crew_skill(region * r, faction * f, ship * sh, skill_t sk) { int value = 0; - unit *u; for (u = r->units; u; u = u->next) { if (u->ship == sh && u->faction == f) { int s = eff_skill(u, sk, r); - value = MAX(s, value); } } @@ -358,13 +337,9 @@ static int crew_skill(region * r, faction * f, ship * sh, skill_t sk) static int try_destruction(unit * u, unit * u2, const ship * sh, int skilldiff) { const char *destruction_success_msg = "destroy_ship_0"; - const char *destruction_failed_msg = "destroy_ship_1"; - const char *destruction_detected_msg = "destroy_ship_2"; - const char *detect_failure_msg = "destroy_ship_3"; - const char *object_destroyed_msg = "destroy_ship_4"; if (skilldiff == 0) { @@ -399,17 +374,11 @@ static int try_destruction(unit * u, unit * u2, const ship * sh, int skilldiff) static void sink_ship(region * r, ship * sh, const char *name, unit * saboteur) { unit **ui, *u; - region *safety = r; - int i; - direction_t d; - double probability = 0.0; - message *sink_msg = NULL; - faction *f; for (f = NULL, u = r->units; u; u = u->next) { @@ -426,7 +395,6 @@ static void sink_ship(region * r, ship * sh, const char *name, unit * saboteur) } else { for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r, d); - if (!fval(rn->terrain, SEA_REGION) && !move_blocked(NULL, r, rn)) { safety = rn; probability = OCEAN_SWIMMER_CHANCE; @@ -448,7 +416,6 @@ static void sink_ship(region * r, ship * sh, const char *name, unit * saboteur) if (u->ship == sh) { int dead = 0; - message *msg; /* if this fails, I misunderstood something: */ @@ -495,17 +462,11 @@ static void sink_ship(region * r, ship * sh, const char *name, unit * saboteur) int sabotage_cmd(unit * u, struct order *ord) { const char *s; - int i; - ship *sh; - unit *u2; - char buffer[DISPLAYSIZE]; - region *r = u->region; - int skdiff; init_tokens(ord); diff --git a/src/gamecode/study.c b/src/gamecode/study.c index d3ed0e1f2..48ac70971 100644 --- a/src/gamecode/study.c +++ b/src/gamecode/study.c @@ -65,9 +65,7 @@ static skill_t getskill(const struct locale *lang) magic_t getmagicskill(const struct locale * lang) { struct tnode *tokens = get_translations(lang, UT_MAGIC); - variant token; - const char *s = getstrtoken(); if (s && s[0]) { @@ -75,7 +73,6 @@ magic_t getmagicskill(const struct locale * lang) return (magic_t) token.i; } else { char buffer[3]; - buffer[0] = s[0]; buffer[1] = s[1]; buffer[2] = '\0'; @@ -117,12 +114,10 @@ boolean magic_lowskill(unit * u) int study_cost(unit * u, skill_t sk) { static int cost[MAXSKILLS]; - int stufe, k = 50; if (cost[sk] == 0) { char buffer[256]; - sprintf(buffer, "skills.cost.%s", skillnames[sk]); cost[sk] = get_param_int(global.parameters, buffer, -1); } @@ -168,12 +163,10 @@ const attrib_type at_learning = { static int study_days(unit * student, skill_t sk) { int speed = 30; - if (student->race->study_speed) { speed += student->race->study_speed[sk]; if (speed < 30) { skill *sv = get_skill(student, sk); - if (sv == 0) { speed = 30; } @@ -187,9 +180,7 @@ teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, boolean report, int *academy) { teaching_info *teach = NULL; - attrib *a; - int n; /* learning sind die Tage, die sie schon durch andere Lehrer zugute @@ -215,9 +206,7 @@ teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, if (n != 0) { struct building *b = inside_building(teacher); - const struct building_type *btype = b ? b->type : NULL; - int index = 0; if (teach == NULL) { @@ -238,7 +227,6 @@ teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, if (btype == bt_find("academy") && student->building && student->building->type == bt_find("academy")) { int j = study_cost(student, sk); - j = MAX(50, j * 2); /* kann Einheit das zahlen? */ if (get_pooled(student, oldresourcetype[R_SILVER], GET_DEFAULT, j) >= j) { @@ -289,15 +277,10 @@ teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, int teach_cmd(unit * u, struct order *ord) { static const curse_type *gbdream_ct = NULL; - plane *pl; - region *r = u->region; - int teaching, i, j, count, academy = 0; - unit *u2; - skill_t sk = NOSKILL; if (gbdream_ct == 0) @@ -333,7 +316,6 @@ int teach_cmd(unit * u, struct order *ord) if (teaching == 0) return 0; - u2 = 0; count = 0; @@ -343,11 +325,8 @@ int teach_cmd(unit * u, struct order *ord) #if TEACH_ALL if (getparam(u->faction->locale) == P_ANY) { unit *student = r->units; - skill_t teachskill[MAXSKILLS]; - int i = 0; - do { sk = getskill(u->faction->locale); teachskill[i++] = sk; @@ -411,7 +390,6 @@ int teach_cmd(unit * u, struct order *ord) #endif { char zOrder[4096]; - order *new_order; zOrder[0] = '\0'; @@ -420,20 +398,15 @@ int teach_cmd(unit * u, struct order *ord) while (!parser_end()) { unit *u2 = getunit(r, u->faction); - boolean feedback; - ++count; /* Falls die Unit nicht gefunden wird, Fehler melden */ if (!u2) { char tbuf[20]; - const char *uid; - const char *token; - /* Finde den string, der den Fehler verursacht hat */ parser_pushstate(); init_tokens(ord); @@ -503,9 +476,7 @@ int teach_cmd(unit * u, struct order *ord) /* ist der Magier schon spezialisiert, so versteht er nur noch * Lehrer seines Gebietes */ sc_mage *mage1 = get_mage(u); - sc_mage *mage2 = get_mage(u2); - if (!mage2 || !mage1 || (mage2->magietyp != M_GRAY && mage1->magietyp != mage2->magietyp)) { if (feedback) { @@ -535,20 +506,15 @@ static double study_speedup(unit * u) #define OFSTURN 2 /* 2 */ if (turn > MINTURN) { static int speed_rule = -1; - if (speed_rule < 0) { speed_rule = get_param_int(global.parameters, "study.speedup", 0); } if (speed_rule == 1) { double learn_age = OFSTURN; - int i; - for (i = 0; i != u->skill_size; ++i) { skill *sv = u->skills + i; - double learn_time = sv->level * (sv->level + 1) / 2.0; - learn_age += learn_time; } if (learn_age < turn) { @@ -562,32 +528,19 @@ static double study_speedup(unit * u) int learn_cmd(unit * u, order * ord) { region *r = u->region; - int p; - magic_t mtyp; - int l; - int studycost, days; - double multi = 1.0; - attrib *a = NULL; - teaching_info *teach = NULL; - int money = 0; - skill_t sk; - int maxalchemy = 0; - static int learn_newskills = -1; - if (learn_newskills < 0) { const char *str = get_param(global.parameters, "study.newskills"); - if (str && strcmp(str, "false") == 0) learn_newskills = 0; else @@ -619,7 +572,6 @@ int learn_cmd(unit * u, order * ord) } if (learn_newskills == 0) { skill *sv = get_skill(u, sk); - if (sv == NULL) { /* we can only learn skills we already have */ cmistake(u, ord, 771, MSG_EVENT); @@ -652,7 +604,6 @@ int learn_cmd(unit * u, order * ord) /* Akademie: */ { struct building *b = inside_building(u); - const struct building_type *btype = b ? b->type : NULL; if (btype && btype == bt_find("academy")) { @@ -673,7 +624,6 @@ int learn_cmd(unit * u, order * ord) create_mage(u, mtyp); } else if (!has_skill(u, SK_MAGIC)) { int mmax = skill_limit(u->faction, SK_MAGIC); - /* Die Einheit ist noch kein Magier */ if (count_skill(u->faction, SK_MAGIC) + u->number > mmax) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_magicians", @@ -731,7 +681,6 @@ int learn_cmd(unit * u, order * ord) maxalchemy = eff_skill(u, SK_ALCHEMY, r); if (!has_skill(u, SK_ALCHEMY)) { int amax = skill_limit(u->faction, SK_ALCHEMY); - if (count_skill(u->faction, SK_ALCHEMY) + u->number > amax) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_max_alchemists", "amount", amax)); @@ -741,7 +690,6 @@ int learn_cmd(unit * u, order * ord) } if (studycost) { int cost = studycost * u->number; - money = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, cost); money = MIN(money, cost); } @@ -810,7 +758,6 @@ int learn_cmd(unit * u, order * ord) days -= u->number * 30; } else { double chance = (double)days / u->number / 30; - learn_skill(u, sk, chance); days = 0; } @@ -818,13 +765,10 @@ int learn_cmd(unit * u, order * ord) if (a != NULL) { if (teach != NULL) { int index = 0; - while (teach->teachers[index] && index != MAXTEACHERS) { unit *teacher = teach->teachers[index++]; - if (teacher->faction != u->faction) { boolean feedback = alliedunit(u, teacher->faction, HELP_GUARD); - if (feedback) { ADDMSG(&teacher->faction->msgs, msg_message("teach_teacher", "teacher student skill level", teacher, u, sk, @@ -845,16 +789,12 @@ int learn_cmd(unit * u, order * ord) if (sk == SK_ALCHEMY) { const potion_type *ptype; - faction *f = u->faction; - int skill = eff_skill(u, SK_ALCHEMY, r); - if (skill > maxalchemy) { for (ptype = potiontypes; ptype; ptype = ptype->next) { if (skill == ptype->level * 2) { attrib *a = a_find(f->attribs, &at_showitem); - while (a && a->type == &at_showitem && a->data.v != ptype) a = a->next; if (a == NULL || a->type != &at_showitem) { @@ -866,7 +806,6 @@ int learn_cmd(unit * u, order * ord) } } else if (sk == SK_MAGIC) { sc_mage *mage = get_mage(u); - if (!mage) { mage = create_mage(u, u->faction->magiegebiet); } diff --git a/src/gamecode/summary.c b/src/gamecode/summary.c index 791aa0bfc..a734eeba4 100644 --- a/src/gamecode/summary.c +++ b/src/gamecode/summary.c @@ -72,7 +72,6 @@ typedef struct summary { static char *pcomp(double i, double j) { static char buf[32]; - sprintf(buf, "%.0f (%s%.0f)", i, (i >= j) ? "+" : "", i - j); return buf; } @@ -80,14 +79,12 @@ static char *pcomp(double i, double j) static char *rcomp(int i, int j) { static char buf[32]; - sprintf(buf, "%d (%s%d,%s%d%%)", i, (i >= j) ? "+" : "", i - j, (i >= j) ? "+" : "", j ? ((i - j) * 100) / j : 0); return buf; } - static void out_faction(FILE * file, const struct faction *f) { if (alliances != NULL) { @@ -106,7 +103,6 @@ static void out_faction(FILE * file, const struct faction *f) static char *gamedate2(const struct locale *lang) { static char buf[256]; - gamedate gd; get_gamedate(turn, &gd); @@ -120,7 +116,6 @@ static char *gamedate2(const struct locale *lang) static void writeturn(void) { char zText[MAX_PATH]; - FILE *f; sprintf(zText, "%s/datum", basepath()); @@ -140,11 +135,8 @@ static void writeturn(void) void report_summary(summary * s, summary * o, boolean full) { FILE *F = NULL; - int i, newplayers = 0; - faction *f; - char zText[MAX_PATH]; if (full) { @@ -163,7 +155,6 @@ void report_summary(summary * s, summary * o, boolean full) #endif printf("Schreibe Zusammenfassung (parteien)...\n"); fprintf(F, "%s\n%s\n\n", global.gamename, gamedate2(default_locale)); - fprintf(F, "Auswertung Nr: %d\n\n", turn); fprintf(F, "Parteien: %s\n", pcomp(s->factions, o->factions)); fprintf(F, "Einheiten: %s\n", pcomp(s->nunits, o->nunits)); @@ -184,7 +175,6 @@ void report_summary(summary * s, summary * o, boolean full) for (i = 0; i < MAXRACES; i++) { const race *rc = new_race[i]; - if (s->factionrace[i] && rc && playerrace(rc) && i != RC_TEMPLATE && i != RC_CLONE) { fprintf(F, "%13s%s: %s\n", LOC(default_locale, rc_name(rc, 3)), @@ -197,12 +187,9 @@ void report_summary(summary * s, summary * o, boolean full) fprintf(F, "\n"); { struct language *plang = s->languages; - while (plang != NULL) { struct language *olang = o->languages; - int nold = 0; - while (olang && olang->locale != plang->locale) olang = olang->next; if (olang) @@ -218,7 +205,6 @@ void report_summary(summary * s, summary * o, boolean full) if (full) { for (i = 0; i < MAXRACES; i++) { const race *rc = new_race[i]; - if (s->poprace[i]) { fprintf(F, "%20s: %s\n", LOC(default_locale, rc_name(rc, 1)), rcomp(s->poprace[i], o->poprace[i])); @@ -227,7 +213,6 @@ void report_summary(summary * s, summary * o, boolean full) } else { for (i = 0; i < MAXRACES; i++) { const race *rc = new_race[i]; - if (s->poprace[i] && playerrace(rc) && i != RC_TEMPLATE && i != RC_CLONE) { fprintf(F, "%20s: %s\n", LOC(default_locale, rc_name(rc, 1)), @@ -319,18 +304,13 @@ void report_summary(summary * s, summary * o, boolean full) summary *make_summary(void) { faction *f; - region *r; - unit *u; - summary *s = calloc(1, sizeof(summary)); for (f = factions; f; f = f->next) { const struct locale *lang = f->locale; - struct language *plang = s->languages; - while (plang && plang->locale != lang) plang = plang->next; if (!plang) { @@ -389,7 +369,6 @@ summary *make_summary(void) f = u->faction; if (!is_monsters(u->faction)) { skill *sv; - item *itm; s->nunits++; @@ -413,9 +392,7 @@ summary *make_summary(void) for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { skill_t sk = sv->id; - int aktskill = eff_skill(u, sk, r); - if (aktskill > s->maxskill) s->maxskill = aktskill; } diff --git a/src/gamecode/xmlreport.c b/src/gamecode/xmlreport.c index eb2c5d083..afcb067eb 100644 --- a/src/gamecode/xmlreport.c +++ b/src/gamecode/xmlreport.c @@ -89,7 +89,6 @@ static xmlNodePtr xml_link(report_context * ctx, const xmlChar * rel, const xmlChar * ref) { xml_context *xct = (xml_context *) ctx->userdata; - xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "link"); xmlNewNsProp(node, xct->ns_atl, BAD_CAST "rel", rel); @@ -101,7 +100,6 @@ xml_link(report_context * ctx, const xmlChar * rel, const xmlChar * ref) static const xmlChar *xml_ref_unit(const unit * u) { static char idbuf[20]; - snprintf(idbuf, sizeof(idbuf), "unit_%d", u->no); return (const xmlChar *)idbuf; } @@ -109,7 +107,6 @@ static const xmlChar *xml_ref_unit(const unit * u) static const xmlChar *xml_ref_faction(const faction * f) { static char idbuf[20]; - snprintf(idbuf, sizeof(idbuf), "fctn_%d", f->no); return (const xmlChar *)idbuf; } @@ -117,7 +114,6 @@ static const xmlChar *xml_ref_faction(const faction * f) static const xmlChar *xml_ref_group(const group * g) { static char idbuf[20]; - snprintf(idbuf, sizeof(idbuf), "grp_%d", g->gid); return (const xmlChar *)idbuf; } @@ -125,7 +121,6 @@ static const xmlChar *xml_ref_group(const group * g) static const xmlChar *xml_ref_prefix(const char *str) { static char idbuf[20]; - snprintf(idbuf, sizeof(idbuf), "pref_%s", str); return (const xmlChar *)idbuf; } @@ -133,7 +128,6 @@ static const xmlChar *xml_ref_prefix(const char *str) static const xmlChar *xml_ref_building(const building * b) { static char idbuf[20]; - snprintf(idbuf, sizeof(idbuf), "bldg_%d", b->no); return (const xmlChar *)idbuf; } @@ -141,7 +135,6 @@ static const xmlChar *xml_ref_building(const building * b) static const xmlChar *xml_ref_ship(const ship * sh) { static char idbuf[20]; - snprintf(idbuf, sizeof(idbuf), "shp_%d", sh->no); return (const xmlChar *)idbuf; } @@ -149,7 +142,6 @@ static const xmlChar *xml_ref_ship(const ship * sh) static const xmlChar *xml_ref_region(const region * r) { static char idbuf[20]; - snprintf(idbuf, sizeof(idbuf), "rgn_%d", r->uid); return (const xmlChar *)idbuf; } @@ -157,16 +149,12 @@ static const xmlChar *xml_ref_region(const region * r) static xmlNodePtr xml_inventory(report_context * ctx, item * items, unit * u) { xml_context *xct = (xml_context *) ctx->userdata; - xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "items"); - item *itm; for (itm = items; itm; itm = itm->next) { xmlNodePtr child; - const char *name; - int n; child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "item")); @@ -181,11 +169,8 @@ static xmlNodePtr xml_spells(report_context * ctx, quicklist * slist, int maxlevel) { xml_context *xct = (xml_context *) ctx->userdata; - xmlNodePtr child, node = xmlNewNode(xct->ns_atl, BAD_CAST "spells"); - quicklist *ql; - int qi; for (ql = slist, qi = 0; ql; ql_advance(&ql, &qi, 1)) { @@ -202,15 +187,12 @@ xml_spells(report_context * ctx, quicklist * slist, int maxlevel) static xmlNodePtr xml_skills(report_context * ctx, unit * u) { xml_context *xct = (xml_context *) ctx->userdata; - xmlNodePtr child, node = xmlNewNode(xct->ns_atl, BAD_CAST "skills"); - skill *sv; for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { if (sv->level > 0) { skill_t sk = sv->id; - int esk = eff_skill(u, sk, u->region); child = @@ -226,17 +208,11 @@ static xmlNodePtr xml_skills(report_context * ctx, unit * u) static xmlNodePtr xml_unit(report_context * ctx, unit * u, int mode) { xml_context *xct = (xml_context *) ctx->userdata; - xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "unit"); - static const curse_type *itemcloak_ct = 0; - static boolean init = false; - xmlNodePtr child; - const char *str, *rcname, *rcillusion; - boolean disclosure = (ctx->f == u->faction || omniscient(ctx->f)); /* TODO: hitpoints, aura, combatspells, curses */ @@ -267,7 +243,6 @@ static xmlNodePtr xml_unit(report_context * ctx, unit * u, int mode) /* siege */ if (fval(u, UFL_SIEGE)) { building *b = usiege(u); - if (b) { xmlAddChild(node, xml_link(ctx, BAD_CAST "siege", xml_ref_building(b))); } @@ -296,16 +271,13 @@ static xmlNodePtr xml_unit(report_context * ctx, unit * u, int mode) /* group and prefix information. we only write the prefix if we really must */ if (fval(u, UFL_GROUP)) { attrib *a = a_find(u->attribs, &at_group); - if (a != NULL) { const group *g = (const group *)a->data.v; - if (disclosure) { child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "group")); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", xml_ref_group(g)); } else { const char *prefix = get_prefix(g->attribs); - if (prefix) { child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "prefix")); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", @@ -346,7 +318,6 @@ static xmlNodePtr xml_unit(report_context * ctx, unit * u, int mode) if (fval(u, UFL_STEALTH)) { int i = u_geteffstealth(u); - if (i >= 0) { child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "status")); xmlSetNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "stealth"); @@ -374,9 +345,7 @@ static xmlNodePtr xml_unit(report_context * ctx, unit * u, int mode) /* spells */ if (is_mage(u)) { sc_mage *mage = get_mage(u); - quicklist *slist = mage->spells; - if (slist) { xmlAddChild(node, xml_spells(ctx, slist, effskill(u, SK_MAGIC))); } @@ -392,14 +361,12 @@ static xmlNodePtr xml_unit(report_context * ctx, unit * u, int mode) if (fval(u, UFL_ANON_FACTION)) { const faction *sf = visible_faction(NULL, u); - child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "faction")); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "stealth"); xmlNewNsProp(child, xct->ns_atl, BAD_CAST "ref", xml_ref_faction(sf)); } } else { const faction *sf = visible_faction(ctx->f, u); - if (sf == ctx->f) { xmlNewNsProp(child, xct->ns_atl, BAD_CAST "rel", BAD_CAST "stealth"); } @@ -409,7 +376,6 @@ static xmlNodePtr xml_unit(report_context * ctx, unit * u, int mode) /* the inventory */ if (u->items) { item result[MAX_INVENTORY]; - item *show = NULL; if (!init) { @@ -421,7 +387,6 @@ static xmlNodePtr xml_unit(report_context * ctx, unit * u, int mode) show = u->items; } else { boolean see_items = (mode >= see_unit); - if (see_items) { if (itemcloak_ct && curse_active(get_curse(u->attribs, itemcloak_ct))) { see_items = false; @@ -431,7 +396,6 @@ static xmlNodePtr xml_unit(report_context * ctx, unit * u, int mode) } if (see_items) { int n = report_items(u->items, result, MAX_INVENTORY, u, ctx->f); - assert(n >= 0); if (n > 0) show = result; @@ -453,11 +417,8 @@ static xmlNodePtr xml_unit(report_context * ctx, unit * u, int mode) static xmlNodePtr xml_resources(report_context * ctx, const seen_region * sr) { xml_context *xct = (xml_context *) ctx->userdata; - xmlNodePtr node = NULL; - resource_report result[MAX_RAWMATERIALS]; - int n, size = report_resources(sr, result, MAX_RAWMATERIALS, ctx->f); if (size) { @@ -483,14 +444,11 @@ static xmlNodePtr xml_resources(report_context * ctx, const seen_region * sr) static xmlNodePtr xml_diplomacy(report_context * ctx, const struct ally *allies) { xml_context *xct = (xml_context *) ctx->userdata; - xmlNodePtr child, node = xmlNewNode(xct->ns_atl, BAD_CAST "diplomacy"); - const struct ally *sf; for (sf = allies; sf; sf = sf->next) { int i, status = sf->status; - for (i = 0; helpmodes[i].name; ++i) { if (sf->faction && (status & helpmodes[i].status) == helpmodes[i].status) { status -= helpmodes[i].status; @@ -508,14 +466,11 @@ static xmlNodePtr xml_diplomacy(report_context * ctx, const struct ally *allies) static xmlNodePtr xml_groups(report_context * ctx, const group * groups) { xml_context *xct = (xml_context *) ctx->userdata; - xmlNodePtr child, node = xmlNewNode(xct->ns_atl, BAD_CAST "faction"); - const group *g; for (g = groups; g; g = g->next) { const char *prefix = get_prefix(g->attribs); - child = xmlAddChild(node, xmlNewNode(xct->ns_atl, BAD_CAST "group")); xmlNewNsProp(child, xct->ns_xml, XML_XML_ID, xml_ref_group(g)); xmlNewTextChild(child, xct->ns_atl, BAD_CAST "name", @@ -536,7 +491,6 @@ static xmlNodePtr xml_groups(report_context * ctx, const group * groups) static xmlNodePtr xml_faction(report_context * ctx, faction * f) { xml_context *xct = (xml_context *) ctx->userdata; - xmlNodePtr child, node = xmlNewNode(xct->ns_atl, BAD_CAST "faction"); /* TODO: alliance, locale */ @@ -575,11 +529,8 @@ xml_building(report_context * ctx, seen_region * sr, const building * b, const unit * owner) { xml_context *xct = (xml_context *) ctx->userdata; - xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "building"); - xmlNodePtr child; - const char *bname, *billusion; xmlNewNsProp(node, xct->ns_xml, XML_XML_ID, xml_ref_building(b)); @@ -625,7 +576,6 @@ xml_ship(report_context * ctx, const seen_region * sr, const ship * sh, const unit * owner) { xml_context *xct = (xml_context *) ctx->userdata; - xmlNodePtr child, node = xmlNewNode(xct->ns_atl, BAD_CAST "ship"); xmlNewNsProp(node, xct->ns_xml, XML_XML_ID, xml_ref_ship(sh)); @@ -661,7 +611,6 @@ xml_ship(report_context * ctx, const seen_region * sr, const ship * sh, if ((owner && owner->faction == ctx->f) || omniscient(ctx->f)) { int n = 0, p = 0; - getshipweight(sh, &n, &p); xmlNewTextChild(node, xct->ns_atl, BAD_CAST "cargo", (const xmlChar *)itoab(n, 10)); @@ -672,23 +621,14 @@ xml_ship(report_context * ctx, const seen_region * sr, const ship * sh, static xmlNodePtr xml_region(report_context * ctx, seen_region * sr) { xml_context *xct = (xml_context *) ctx->userdata; - const region *r = sr->r; - xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "region"); - xmlNodePtr child; - int stealthmod = stealth_modifier(sr->mode); - unit *u; - ship *sh = r->ships; - building *b = r->buildings; - plane *pl = rplane(r); - int nx = r->x, ny = r->y; pnormalize(&nx, &ny, pl); @@ -775,21 +715,13 @@ static xmlNodePtr xml_region(report_context * ctx, seen_region * sr) static xmlNodePtr report_root(report_context * ctx) { int qi; - quicklist *address; - region *r = ctx->first, *rend = ctx->last; - xml_context *xct = (xml_context *) ctx->userdata; - xmlNodePtr node, child, xmlReport = xmlNewNode(NULL, BAD_CAST "atlantis"); - const char *mailto = locale_string(ctx->f->locale, "mailto"); - const char *mailcmd = locale_string(ctx->f->locale, "mailcmd"); - char zText[128]; - /* TODO: locale, age, options, messages */ xct->ns_xml = xmlNewNs(xmlReport, XML_XML_NAMESPACE, BAD_CAST "xml"); @@ -813,13 +745,11 @@ static xmlNodePtr report_root(report_context * ctx) for (qi = 0, address = ctx->addresses; address; ql_advance(&address, &qi, 1)) { faction *f = (faction *) ql_get(address, qi); - xmlAddChild(xmlReport, xml_faction(ctx, f)); } for (; r != rend; r = r->next) { seen_region *sr = find_seen(ctx->seen, r); - if (sr != NULL) xmlAddChild(xmlReport, xml_region(ctx, sr)); } @@ -831,7 +761,6 @@ static int report_xml(const char *filename, report_context * ctx, const char *encoding) { xml_context xct; - xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); xct.doc = doc; diff --git a/src/gmtool.c b/src/gmtool.c index 411381cdc..dfc48b1e2 100644 --- a/src/gmtool.c +++ b/src/gmtool.c @@ -69,7 +69,6 @@ #include static int g_quit; - int force_color = 0; state *current_state = NULL; @@ -84,14 +83,11 @@ static WINDOW *hstatus; static void init_curses(void) { short fg, bg; - initscr(); if (has_colors() || force_color) { short bcol = COLOR_BLACK; - short hcol = COLOR_MAGENTA; - start_color(); #ifdef WIN32 /* looks crap on putty with TERM=linux */ @@ -145,7 +141,6 @@ static window *wnd_first, *wnd_last; static window *win_create(WINDOW * hwin) { window *wnd = calloc(1, sizeof(window)); - wnd->handle = hwin; if (wnd_first != NULL) { wnd->next = wnd_first; @@ -161,11 +156,8 @@ static window *win_create(WINDOW * hwin) static void untag_region(selection * s, int nx, int ny) { unsigned int key = ((nx << 12) ^ ny); - tag **tp = &s->tags[key & (MAXTHASH - 1)]; - tag *t = NULL; - while (*tp) { t = *tp; if (t->coord.x == nx && t->coord.y == ny) @@ -182,12 +174,9 @@ static void untag_region(selection * s, int nx, int ny) static void tag_region(selection * s, int nx, int ny) { unsigned int key = ((nx << 12) ^ ny); - tag **tp = &s->tags[key & (MAXTHASH - 1)]; - while (*tp) { tag *t = *tp; - if (t->coord.x == nx && t->coord.y == ny) return; tp = &t->nexthash; @@ -202,12 +191,9 @@ static void tag_region(selection * s, int nx, int ny) static int tagged_region(selection * s, int nx, int ny) { unsigned int key = ((nx << 12) ^ ny); - tag **tp = &s->tags[key & (MAXTHASH - 1)]; - while (*tp) { tag *t = *tp; - if (t->coord.x == nx && t->coord.y == ny) return 1; tp = &t->nexthash; @@ -218,10 +204,8 @@ static int tagged_region(selection * s, int nx, int ny) static int mr_tile(const map_region * mr, int highlight) { int hl = 8 * highlight; - if (mr != NULL && mr->r != NULL) { const region *r = mr->r; - switch (r->terrain->_name[0]) { case 'o': return '.' | COLOR_PAIR(hl + COLOR_CYAN); @@ -262,29 +246,20 @@ static int mr_tile(const map_region * mr, int highlight) static void paint_map(window * wnd, const state * st) { WINDOW *win = wnd->handle; - int lines = getmaxy(win); - int cols = getmaxx(win); - int vx, vy; lines = lines / THEIGHT; cols = cols / TWIDTH; for (vy = 0; vy != lines; ++vy) { int yp = (lines - vy - 1) * THEIGHT; - for (vx = 0; vx != cols; ++vx) { map_region *mr = mr_get(&st->display, vx, vy); - int attr = 0; - int hl = 0; - int xp = vx * TWIDTH + (vy & 1) * TWIDTH / 2; - int nx, ny; - if (mr) { if (st) { cnormalize(&mr->coord, &nx, &ny); @@ -303,7 +278,6 @@ static void paint_map(window * wnd, const state * st) map_region *cursor_region(const view * v, const coordinate * c) { coordinate relpos; - int cx, cy; if (c) { @@ -321,15 +295,10 @@ draw_cursor(WINDOW * win, selection * s, const view * v, const coordinate * c, int show) { int lines = getmaxy(win) / THEIGHT; - int xp, yp, nx, ny; - int attr = 0; - map_region *mr = cursor_region(v, c); - coordinate relpos; - int cx, cy; if (!mr) @@ -347,7 +316,6 @@ draw_cursor(WINDOW * win, selection * s, const view * v, const coordinate * c, attr = A_REVERSE; if (mr->r) { int hl = 0; - if (mr->r->flags & RF_MAPPER_HIGHLIGHT) hl = 1; mvwaddch(win, yp, xp, mr_tile(mr, hl) | attr); @@ -366,20 +334,13 @@ draw_cursor(WINDOW * win, selection * s, const view * v, const coordinate * c, wnoutrefresh(win); } - - static void paint_status(window * wnd, const state * st) { WINDOW *win = wnd->handle; - const char *name = ""; - int nx, ny, uid = 0; - const char *terrain = "----"; - map_region *mr = cursor_region(&st->display, &st->cursor); - if (mr && mr->r) { uid = mr->r->uid; if (mr->r->land) { @@ -403,11 +364,8 @@ static boolean handle_info_region(window * wnd, state * st, int c) static void paint_info_region(window * wnd, const state * st) { WINDOW *win = wnd->handle; - int size = getmaxx(win) - 2; - int line = 0, maxline = getmaxy(win) - 2; - map_region *mr = cursor_region(&st->display, &st->cursor); unused(st); @@ -415,7 +373,6 @@ static void paint_info_region(window * wnd, const state * st) wxborder(win); if (mr && mr->r) { const region *r = mr->r; - if (r->land) { mvwaddnstr(win, line++, 1, (char *)r->land->name, size); } else { @@ -433,7 +390,6 @@ static void paint_info_region(window * wnd, const state * st) line++; if (r->ships && (st->info_flags & IFL_SHIPS)) { ship *sh; - wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); mvwaddnstr(win, line++, 1, "* ships:", size - 5); wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); @@ -444,7 +400,6 @@ static void paint_info_region(window * wnd, const state * st) } if (r->units && (st->info_flags & IFL_FACTIONS)) { unit *u; - wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); mvwaddnstr(win, line++, 1, "* factions:", size - 5); wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); @@ -461,7 +416,6 @@ static void paint_info_region(window * wnd, const state * st) } if (r->units && (st->info_flags & IFL_UNITS)) { unit *u; - wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); mvwaddnstr(win, line++, 1, "* units:", size - 5); wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW)); @@ -510,9 +464,7 @@ static void terraform_at(coordinate * c, const terrain_type * terrain) { if (terrain != NULL) { region *r; - int nx = c->x, ny = c->y; - pnormalize(&nx, &ny, c->pl); r = findregion(nx, ny); if (r == NULL) { @@ -531,14 +483,10 @@ terraform_selection(selection * selected, const terrain_type * terrain) return; for (i = 0; i != MAXTHASH; ++i) { tag **tp = &selected->tags[i]; - while (*tp) { region *r; - tag *t = *tp; - int nx = t->coord.x, ny = t->coord.y; - plane *pl = t->coord.pl; pnormalize(&nx, &ny, pl); @@ -555,9 +503,7 @@ terraform_selection(selection * selected, const terrain_type * terrain) static faction *select_faction(state * st) { list_selection *prev, *ilist = NULL, **iinsert; - list_selection *selected = NULL; - faction *f = factions; if (!f) @@ -567,7 +513,6 @@ static faction *select_faction(state * st) while (f) { char buffer[32]; - sprintf(buffer, "%.4s %.26s", itoa36(f->no), f->name); insert_selection(iinsert, NULL, buffer, (void *)f); f = f->next; @@ -586,9 +531,7 @@ static const terrain_type *select_terrain(state * st, const terrain_type * default_terrain) { list_selection *prev, *ilist = NULL, **iinsert; - list_selection *selected = NULL; - const terrain_type *terrain = terrains(); if (!terrain) @@ -653,48 +596,39 @@ enum { MODE_MARK, MODE_SELECT, MODE_UNMARK, MODE_UNSELECT }; static void select_regions(state * st, int selectmode) { char sbuffer[80]; - int findmode; - const char *statustext[] = { "mark-", "select-", "unmark-", "deselect-" }; const char *status = statustext[selectmode]; - statusline(st->wnd_status->handle, status); doupdate(); findmode = getch(); if (findmode == 'n') { /* none */ int i; - sprintf(sbuffer, "%snone", status); statusline(st->wnd_status->handle, sbuffer); if (selectmode & MODE_SELECT) { for (i = 0; i != MAXTHASH; ++i) { tag **tp = &st->selected->tags[i]; - while (*tp) { tag *t = *tp; - *tp = t->nexthash; free(t); } } } else { region *r; - for (r = regions; r; r = r->next) { r->flags &= ~RF_MAPPER_HIGHLIGHT; } } } else if (findmode == 'm') { region *r; - sprintf(sbuffer, "%smonsters", status); statusline(st->wnd_status->handle, sbuffer); for (r = regions; r; r = r->next) { unit *u = r->units; - for (; u; u = u->next) { if (fval(u->faction, FFL_NPC) != 0) break; @@ -710,12 +644,10 @@ static void select_regions(state * st, int selectmode) } } else if (findmode == 'p') { region *r; - sprintf(sbuffer, "%splayers", status); statusline(st->wnd_status->handle, sbuffer); for (r = regions; r; r = r->next) { unit *u = r->units; - for (; u; u = u->next) { if (fval(u->faction, FFL_NPC) == 0) break; @@ -731,7 +663,6 @@ static void select_regions(state * st, int selectmode) } } else if (findmode == 'u') { region *r; - sprintf(sbuffer, "%sunits", status); statusline(st->wnd_status->handle, sbuffer); for (r = regions; r; r = r->next) { @@ -746,7 +677,6 @@ static void select_regions(state * st, int selectmode) } } else if (findmode == 's') { region *r; - sprintf(sbuffer, "%sships", status); statusline(st->wnd_status->handle, sbuffer); for (r = regions; r; r = r->next) { @@ -761,7 +691,6 @@ static void select_regions(state * st, int selectmode) } } else if (findmode == 'f') { char fbuffer[12]; - sprintf(sbuffer, "%sfaction:", status); askstring(st->wnd_status->handle, sbuffer, fbuffer, 12); if (fbuffer[0]) { @@ -774,7 +703,6 @@ static void select_regions(state * st, int selectmode) statusline(st->wnd_status->handle, sbuffer); for (u = f->units; u; u = u->nextF) { region *r = u->region; - if (selectmode & MODE_SELECT) { select_coordinate(st->selected, r->x, r->y, selectmode == MODE_SELECT); @@ -790,13 +718,11 @@ static void select_regions(state * st, int selectmode) } } else if (findmode == 't') { const struct terrain_type *terrain; - sprintf(sbuffer, "%sterrain: ", status); statusline(st->wnd_status->handle, sbuffer); terrain = select_terrain(st, NULL); if (terrain != NULL) { region *r; - sprintf(sbuffer, "%sterrain: %s", status, terrain->_name); statusline(st->wnd_status->handle, sbuffer); for (r = regions; r; r = r->next) { @@ -823,19 +749,12 @@ static void select_regions(state * st, int selectmode) static void handlekey(state * st, int c) { window *wnd; - coordinate *cursor = &st->cursor; - static char locate[80]; - static int findmode = 0; - region *r; - char sbuffer[80]; - static char kbuffer[80]; - int n, nx, ny; switch (c) { @@ -917,15 +836,12 @@ static void handlekey(state * st, int c) case 0x09: /* tab = next selected */ if (regions != NULL) { map_region *mr = cursor_region(&st->display, cursor); - if (mr) { region *first = mr->r; - region *cur = (first && first->next) ? first->next : regions; while (cur != first) { coordinate coord; - region2coord(cur, &coord); cnormalize(&coord, &nx, &ny); if (tagged_region(st->selected, nx, ny)) { @@ -945,7 +861,6 @@ static void handlekey(state * st, int c) case 'p': if (planes) { plane *pl = planes; - if (cursor->pl) { while (pl && pl != cursor->pl) { pl = pl->next; @@ -964,12 +879,9 @@ static void handlekey(state * st, int c) case 'a': if (regions != NULL) { map_region *mr = cursor_region(&st->display, cursor); - if (mr && mr->r) { region *cur = mr->r; - plane *pl = rplane(cur); - if (pl == NULL) { cur = r_standard_to_astral(cur); } else if (is_astral(cur)) { @@ -1050,7 +962,6 @@ static void handlekey(state * st, int c) move(0, 0); refresh(); lua_do((struct lua_State *)global.vm_state); - /* todo: do this from inside the script */ clear(); st->wnd_info->update |= 1; @@ -1120,7 +1031,6 @@ static void handlekey(state * st, int c) sizeof(locate)); } else if (findmode == 'F') { faction *f = select_faction(st); - if (f != NULL) { strcpy(locate, itoa36(f->no)); findmode = 'f'; @@ -1138,13 +1048,10 @@ static void handlekey(state * st, int c) case 'n': if (findmode == 'u') { unit *u = findunit(atoi36(locate)); - r = u ? u->region : NULL; } else if (findmode && regions != NULL) { struct faction *f = NULL; - map_region *mr = cursor_region(&st->display, cursor); - region *first = (mr && mr->r && mr->r->next) ? mr->r->next : regions; if (findmode == 'f') { @@ -1163,7 +1070,6 @@ static void handlekey(state * st, int c) break; } else if (findmode == 'f') { unit *u; - for (u = r->units; u; u = u->next) { if (u->faction == f) { break; @@ -1230,11 +1136,9 @@ static void init_view(view * display, WINDOW * win) static void update_view(view * vi) { int i, j; - for (i = 0; i != vi->size.width; ++i) { for (j = 0; j != vi->size.height; ++j) { map_region *mr = mr_get(vi, i, j); - mr->coord.x = vi->topleft.x + i - j / 2; mr->coord.y = vi->topleft.y + j; mr->coord.pl = vi->pl; @@ -1247,7 +1151,6 @@ static void update_view(view * vi) state *state_open(void) { state *st = calloc(sizeof(state), 1); - st->display.pl = get_homeplane(); st->cursor.pl = get_homeplane(); st->cursor.x = 0; @@ -1270,17 +1173,11 @@ void state_close(state * st) void run_mapper(void) { WINDOW *hwinstatus; - WINDOW *hwininfo; - WINDOW *hwinmap; - int width, height, x, y; - int split = 20, old_flags = log_flags; - state *st; - point tl; log_flags &= ~(LOG_CPERROR | LOG_CPWARNING); @@ -1317,11 +1214,8 @@ void run_mapper(void) while (!g_quit) { int c; - point p; - window *wnd; - view *vi = &st->display; getbegyx(hwinmap, x, y); @@ -1389,17 +1283,13 @@ curses_readline(struct lua_State *L, char *buffer, size_t size, return buffer[0] != 0; } - void seed_players(const char *filename, boolean new_island) { newfaction *players = read_newfactions(filename); - if (players != NULL) { while (players) { int n = listlen(players); - int k = (n + ISLANDSIZE - 1) / ISLANDSIZE; - k = n / k; n = autoseed(&players, k, new_island ? 0 : TURNS_PER_ISLAND); if (n == 0) { @@ -1412,9 +1302,7 @@ void seed_players(const char *filename, boolean new_island) void make_block(int x, int y, int radius, const struct terrain_type *terrain) { int cx, cy; - region *r; - plane *pl = findplane(x, y); if (terrain == NULL) @@ -1423,7 +1311,6 @@ void make_block(int x, int y, int radius, const struct terrain_type *terrain) for (cx = x - radius; cx != x + radius; ++cx) { for (cy = y - radius; cy != y + radius; ++cy) { int nx = cx, ny = cy; - pnormalize(&nx, &ny, pl); if (koor_distance(nx, ny, x, y) < radius) { if (!findregion(nx, ny)) { diff --git a/src/items/artrewards.c b/src/items/artrewards.c index 59ad8b1ab..a5b67bc58 100644 --- a/src/items/artrewards.c +++ b/src/items/artrewards.c @@ -65,7 +65,6 @@ use_hornofdancing(struct unit *u, const struct item_type *itype, int amount, struct order *ord) { region *r; - int regionsPacified = 0; for (r = regions; r; r = r->next) { @@ -103,13 +102,11 @@ use_hornofdancing(struct unit *u, const struct item_type *itype, #define SPEEDUP 2 - static int useonother_trappedairelemental(struct unit *u, int shipId, const struct item_type *itype, int amount, struct order *ord) { curse *c; - ship *sh; if (shipId <= 0) { diff --git a/src/items/demonseye.c b/src/items/demonseye.c index 97eb809b4..53a06bd59 100644 --- a/src/items/demonseye.c +++ b/src/items/demonseye.c @@ -39,7 +39,6 @@ summon_igjarjuk(struct unit *u, const struct item_type *itype, int amount, struct order *ord) { struct plane *p = rplane(u->region); - unused(amount); unused(itype); if (p != NULL) { diff --git a/src/items/phoenixcompass.c b/src/items/phoenixcompass.c index 6828493cc..fe35d444e 100644 --- a/src/items/phoenixcompass.c +++ b/src/items/phoenixcompass.c @@ -43,19 +43,12 @@ use_phoenixcompass(struct unit *u, const struct item_type *itype, int amount, struct order *ord) { region *r; - unit *closest_phoenix = NULL; - int closest_phoenix_distance = INT_MAX; - boolean confusion = false; - direction_t direction; - unit *u2; - direction_t closest_neighbour_direction = 0; - static race *rc_phoenix = NULL; if (rc_phoenix == NULL) { @@ -75,7 +68,6 @@ use_phoenixcompass(struct unit *u, const struct item_type *itype, distance(u->region, closest_phoenix->region); } else { int dist = distance(u->region, r); - if (dist < closest_phoenix_distance) { closest_phoenix = u2; closest_phoenix_distance = dist; @@ -104,13 +96,11 @@ use_phoenixcompass(struct unit *u, const struct item_type *itype, for (direction = 0; direction < MAXDIRECTIONS; ++direction) { region *neighbour; - int closest_neighbour_distance = INT_MAX; neighbour = r_connect(u->region, direction); if (neighbour != NULL) { int dist = distance(neighbour, closest_phoenix->region); - if (dist < closest_neighbour_distance) { closest_neighbour_direction = direction; closest_neighbour_distance = dist; diff --git a/src/items/seed.c b/src/items/seed.c index ed921eabe..683e4714b 100644 --- a/src/items/seed.c +++ b/src/items/seed.c @@ -29,7 +29,6 @@ #include resource_type *rt_seed = 0; - resource_type *rt_mallornseed = 0; static void produce_seeds(region * r, const resource_type * rtype, int norders) @@ -49,7 +48,6 @@ static int limit_seeds(const region * r, const resource_type * rtype) void init_seed(void) { attrib *a; - resource_limit *rdata; rt_seed = rt_find("seed"); @@ -83,7 +81,6 @@ static int limit_mallornseeds(const region * r, const resource_type * rtype) void init_mallornseed(void) { attrib *a; - resource_limit *rdata; rt_mallornseed = rt_find("mallornseed"); diff --git a/src/items/seed.h b/src/items/seed.h index ad88fe797..810d8bd08 100644 --- a/src/items/seed.h +++ b/src/items/seed.h @@ -22,7 +22,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif - extern struct resource_type *rt_seed; extern void init_seed(void); diff --git a/src/items/speedsail.c b/src/items/speedsail.c index 52f1d0c00..cc7cff3e3 100644 --- a/src/items/speedsail.c +++ b/src/items/speedsail.c @@ -42,7 +42,6 @@ use_speedsail(struct unit *u, const struct item_type *itype, int amount, struct order *ord) { struct plane *p = rplane(u->region); - unused(amount); unused(itype); if (p != NULL) { @@ -50,7 +49,6 @@ use_speedsail(struct unit *u, const struct item_type *itype, int amount, } else { if (u->ship) { attrib *a = a_find(u->ship->attribs, &at_speedup); - if (a == NULL) { a = a_add(&u->ship->attribs, a_new(&at_speedup)); a->data.sa[0] = 50; /* speed */ diff --git a/src/items/studypotion.c b/src/items/studypotion.c index 960f38cce..df77793e1 100644 --- a/src/items/studypotion.c +++ b/src/items/studypotion.c @@ -20,7 +20,6 @@ use_studypotion(struct unit *u, const struct item_type *itype, int amount, { if (get_keyword(u->thisorder) == K_STUDY) { skill_t sk; - skill *sv; init_tokens(u->thisorder); @@ -34,9 +33,7 @@ use_studypotion(struct unit *u, const struct item_type *itype, int amount, /* TODO: message */ } else { attrib *a = a_find(u->attribs, &at_learning); - teaching_info *teach; - if (a == NULL) { a = a_add(&u->attribs, a_new(&at_learning)); } diff --git a/src/items/weapons.c b/src/items/weapons.c index a23582c25..05fbc31a5 100644 --- a/src/items/weapons.c +++ b/src/items/weapons.c @@ -43,15 +43,10 @@ attack_firesword(const troop * at, const struct weapon_type *wtype, int *casualties) { fighter *fi = at->fighter; - troop dt; - int killed = 0; - const char *damage = "2d8"; - int force = 1 + rng_int() % 10; - int enemies = count_enemies(fi->side->battle, fi, 0, 1, SELECT_ADVANCE | SELECT_DISTANCE); @@ -63,12 +58,9 @@ attack_firesword(const troop * at, const struct weapon_type *wtype, if (fi->catmsg == -1) { int i, k = 0; - message *msg; - for (i = 0; i <= at->index; ++i) { struct weapon *wp = fi->person[i].melee; - if (wp != NULL && wp->type == wtype) ++k; } @@ -96,19 +88,12 @@ attack_catapult(const troop * at, const struct weapon_type *wtype, int *casualties) { fighter *af = at->fighter; - unit *au = af->unit; - battle *b = af->side->battle; - troop dt; - int d = 0, enemies; - weapon *wp = af->person[at->index].missile; - static item_type *it_catapultammo = NULL; - if (it_catapultammo == NULL) { it_catapultammo = it_find("catapultammo"); } @@ -132,7 +117,6 @@ attack_catapult(const troop * at, const struct weapon_type *wtype, if (af->catmsg == -1) { int i, k = 0; - message *msg; for (i = 0; i <= at->index; ++i) { diff --git a/src/items/xerewards.c b/src/items/xerewards.c index 953b800b1..f06a667ac 100644 --- a/src/items/xerewards.c +++ b/src/items/xerewards.c @@ -48,13 +48,10 @@ use_skillpotion(struct unit *u, const struct item_type *itype, int amount, * from them) */ int n; - for (n = 0; n != amount; ++n) { skill *sv = u->skills; - while (sv != u->skills + u->skill_size) { int i; - for (i = 0; i != 3; ++i) learn_skill(u, sv->id, 1.0); ++sv; diff --git a/src/kernel/alchemy.c b/src/kernel/alchemy.c index 79a197856..3fff02206 100644 --- a/src/kernel/alchemy.c +++ b/src/kernel/alchemy.c @@ -50,7 +50,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. void herbsearch(region * r, unit * u, int max) { int herbsfound; - const item_type *whichherb; if (eff_skill(u, SK_HERBALISM, r) == 0) { @@ -92,7 +91,6 @@ void herbsearch(region * r, unit * u, int max) static int begin_potion(unit * u, const potion_type * ptype, struct order *ord) { static int rule_multipotion = -1; - assert(ptype != NULL); if (rule_multipotion < 0) { @@ -102,7 +100,6 @@ static int begin_potion(unit * u, const potion_type * ptype, struct order *ord) } if (!rule_multipotion) { const potion_type *use = ugetpotionuse(u); - if (use != NULL && use != ptype) { ADDMSG(&u->faction->msgs, msg_message("errusingpotion", "unit using command", @@ -127,16 +124,11 @@ void do_potion(unit * u, const potion_type * ptype, int amount) { if (ptype == oldpotiontype[P_LIFE]) { region *r = u->region; - int holz = 0; - static int tree_type = -1; - static int tree_count = -1; - if (tree_type < 0) { tree_type = get_param_int(global.parameters, "rules.magic.wol_type", 1); - tree_count = get_param_int(global.parameters, "rules.magic.wol_effect", 10); } @@ -152,7 +144,6 @@ void do_potion(unit * u, const potion_type * ptype, int amount) holz = 0; if (holz < tree_count * amount) { int x = holz / tree_count; - if (holz % tree_count) ++x; if (x < amount) @@ -165,17 +156,13 @@ void do_potion(unit * u, const potion_type * ptype, int amount) u->hp = MIN(unit_max_hp(u) * u->number, u->hp + 400 * amount); } else if (ptype == oldpotiontype[P_PEOPLE]) { region *r = u->region; - attrib *a = (attrib *) a_find(r->attribs, &at_peasantluck); - if (!a) a = a_add(&r->attribs, a_new(&at_peasantluck)); a->data.i += amount; } else if (ptype == oldpotiontype[P_HORSE]) { region *r = u->region; - attrib *a = (attrib *) a_find(r->attribs, &at_horseluck); - if (!a) a = a_add(&r->attribs, a_new(&at_horseluck)); a->data.i += amount; @@ -198,7 +185,6 @@ int use_potion(unit * u, const item_type * itype, int amount, struct order *ord) return EUNUSABLE; } else { int result = begin_potion(u, ptype, ord); - if (result) return result; do_potion(u, ptype, amount); @@ -226,7 +212,6 @@ static void free_potiondelay(attrib * a) static int age_potiondelay(attrib * a) { potiondelay *pd = (potiondelay *) a->data.v; - do_potion(pd->u, pd->ptype, pd->amount); return AT_AGE_REMOVE; } @@ -245,9 +230,7 @@ attrib_type at_potiondelay = { static attrib *make_potiondelay(unit * u, const potion_type * ptype, int amount) { attrib *a = a_new(&at_potiondelay); - potiondelay *pd = (potiondelay *) a->data.v; - pd->u = u; pd->ptype = ptype; pd->amount = amount; @@ -259,9 +242,7 @@ use_potion_delayed(unit * u, const item_type * itype, int amount, struct order *ord) { const potion_type *ptype = resource2potion(itype->rtype); - int result = begin_potion(u, ptype, ord); - if (result) return result; @@ -289,7 +270,6 @@ static void a_writeeffect(const attrib * a, const void *owner, struct storage *store) { effect_data *edata = (effect_data *) a->data.v; - store->w_tok(store, resourcename(edata->type->itype->rtype, 0)); store->w_int(store, edata->value); } @@ -297,11 +277,8 @@ a_writeeffect(const attrib * a, const void *owner, struct storage *store) static int a_readeffect(attrib * a, void *owner, struct storage *store) { int power; - const item_type *itype; - effect_data *edata = (effect_data *) a->data.v; - char zText[32]; store->r_tok_buf(store, zText, sizeof(zText)); @@ -329,11 +306,9 @@ attrib_type at_effect = { int get_effect(const unit * u, const potion_type * effect) { const attrib *a; - for (a = a_find(u->attribs, &at_effect); a != NULL && a->type == &at_effect; a = a->next) { const effect_data *data = (const effect_data *)a->data.v; - if (data->type == effect) return data->value; } @@ -344,7 +319,6 @@ int change_effect(unit * u, const potion_type * effect, int delta) { if (delta != 0) { attrib *a = a_find(u->attribs, &at_effect); - effect_data *data = NULL; while (a && a->type == &at_effect) { diff --git a/src/kernel/alliance.c b/src/kernel/alliance.c index 64d89eb15..f9e93637a 100644 --- a/src/kernel/alliance.c +++ b/src/kernel/alliance.c @@ -85,7 +85,6 @@ alliance *makealliance(int id, const char *name) alliance *findalliance(int id) { alliance *al; - for (al = alliances; al; al = al->next) { if (al->id == id) return al; @@ -103,7 +102,6 @@ typedef struct alliance_transaction { static struct alliance_transaction *transactions[ALLIANCE_MAX]; - faction *alliance_get_leader(alliance * al) { if (!al->_leader) { @@ -157,15 +155,12 @@ static void cmd_join(const tnode * tnext, void *data, struct order *ord) static void perform_kick(void) { alliance_transaction **tap = transactions + ALLIANCE_KICK; - while (*tap) { alliance_transaction *ta = *tap; - alliance *al = f_get_alliance(ta->u->faction); if (al && alliance_get_leader(al) == ta->u->faction) { faction *f; - init_tokens(ta->ord); skip_token(); skip_token(); @@ -182,14 +177,10 @@ static void perform_kick(void) static void perform_new(void) { alliance_transaction **tap = transactions + ALLIANCE_NEW; - while (*tap) { alliance_transaction *ta = *tap; - alliance *al; - int id; - faction *f = ta->u->faction; init_tokens(ta->ord); @@ -208,10 +199,8 @@ static void perform_new(void) static void perform_leave(void) { alliance_transaction **tap = transactions + ALLIANCE_LEAVE; - while (*tap) { alliance_transaction *ta = *tap; - faction *f = ta->u->faction; setalliance(f, NULL); @@ -224,15 +213,12 @@ static void perform_leave(void) static void perform_transfer(void) { alliance_transaction **tap = transactions + ALLIANCE_TRANSFER; - while (*tap) { alliance_transaction *ta = *tap; - alliance *al = f_get_alliance(ta->u->faction); if (al && alliance_get_leader(al) == ta->u->faction) { faction *f; - init_tokens(ta->ord); skip_token(); skip_token(); @@ -249,12 +235,9 @@ static void perform_transfer(void) static void perform_join(void) { alliance_transaction **tap = transactions + ALLIANCE_JOIN; - while (*tap) { alliance_transaction *ta = *tap; - faction *fj = ta->u->faction; - int aid; init_tokens(ta->ord); @@ -263,18 +246,13 @@ static void perform_join(void) aid = getid(); if (aid) { alliance *al = findalliance(aid); - if (al && f_get_alliance(fj) != al) { alliance_transaction **tip = transactions + ALLIANCE_INVITE; - alliance_transaction *ti = *tip; - while (ti) { faction *fi = ti->u->faction; - if (fi && f_get_alliance(fi) == al) { int fid; - init_tokens(ti->ord); skip_token(); skip_token(); @@ -305,22 +283,15 @@ static void execute(const struct syntaxtree *syntax, keyword_t kwd) int run = 0; region **rp = ®ions; - while (*rp) { region *r = *rp; - unit **up = &r->units; - while (*up) { unit *u = *up; - if (u->number) { const struct locale *lang = u->faction->locale; - tnode *root = stree_find(syntax, lang); - order *ord; - for (ord = u->orders; ord; ord = ord->next) { if (get_keyword(ord) == kwd) { do_command(root, u, ord); @@ -347,14 +318,11 @@ static void execute(const struct syntaxtree *syntax, keyword_t kwd) void alliance_cmd(void) { static syntaxtree *stree = NULL; - if (stree == NULL) { syntaxtree *slang = stree = stree_create(); - while (slang) { // struct tnode * root = calloc(sizeof(tnode), 1); struct tnode *leaf = calloc(sizeof(tnode), 1); - // add_command(root, leaf, LOC(slang->lang, "alliance"), NULL); add_command(leaf, NULL, LOC(slang->lang, "new"), &cmd_new); add_command(leaf, NULL, LOC(slang->lang, "invite"), &cmd_invite); @@ -373,15 +341,11 @@ void alliance_cmd(void) void alliancejoin(void) { static syntaxtree *stree = NULL; - if (stree == NULL) { syntaxtree *slang = stree = stree_create(); - while (slang) { struct tnode *root = calloc(sizeof(tnode), 1); - struct tnode *leaf = calloc(sizeof(tnode), 1); - add_command(root, leaf, LOC(slang->lang, "alliance"), NULL); add_command(leaf, NULL, LOC(slang->lang, "join"), &cmd_join); slang = slang->next; @@ -396,12 +360,10 @@ void setalliance(faction * f, alliance * al) return; if (f->alliance != NULL) { int qi; - quicklist **flistp = &f->alliance->members; for (qi = 0; *flistp; ql_advance(flistp, &qi, 1)) { faction *data = (faction *) ql_get(*flistp, qi); - if (data == f) { ql_delete(flistp, qi); break; @@ -429,9 +391,7 @@ void setalliance(faction * f, alliance * al) const char *alliancename(const alliance * al) { typedef char name[OBJECTIDSIZE + 1]; - static name idbuf[8]; - static int nextbuf = 0; char *ibuf = idbuf[(++nextbuf) % 8]; @@ -448,20 +408,15 @@ const char *alliancename(const alliance * al) void alliancevictory(void) { const struct building_type *btype = bt_find("stronghold"); - region *r = regions; - alliance *al = alliances; - if (btype == NULL) return; while (r != NULL) { building *b = r->buildings; - while (b != NULL) { if (b->type == btype) { unit *u = building_owner(b); - if (u) { fset(u->faction->alliance, FFL_MARK); } @@ -473,12 +428,9 @@ void alliancevictory(void) while (al != NULL) { if (!fval(al, FFL_MARK)) { int qi; - quicklist *flist = al->members; - for (qi = 0; flist; ql_advance(&flist, &qi, 1)) { faction *f = (faction *) ql_get(flist, qi); - if (f->alliance == al) { ADDMSG(&f->msgs, msg_message("alliance::lost", "alliance", al)); destroyfaction(f); @@ -501,17 +453,13 @@ int victorycondition(const alliance * al, const char *name) for (igem = gems; *igem; ++igem) { const struct item_type *itype = it_find(*igem); - quicklist *flist = al->members; - int qi; - boolean found = false; assert(itype != NULL); for (qi = 0; flist && !found; ql_advance(&flist, &qi, 1)) { faction *f = (faction *) ql_get(flist, 0); - unit *u; for (u = f->units; u; u = u->nextF) { @@ -528,12 +476,10 @@ int victorycondition(const alliance * al, const char *name) } else if (strcmp(name, "phoenix") == 0) { quicklist *flist = al->members; - int qi; for (qi = 0; flist; ql_advance(&flist, &qi, 1)) { faction *f = (faction *) ql_get(flist, qi); - if (find_key(f->attribs, atoi36("phnx"))) { return 1; } @@ -558,12 +504,10 @@ int victorycondition(const alliance * al, const char *name) */ quicklist *flist = al->members; - int qi; for (qi = 0; flist; ql_advance(&flist, &qi, 1)) { faction *f = (faction *) ql_get(flist, qi); - if (find_key(f->attribs, atoi36("pyra"))) { return 1; } diff --git a/src/kernel/battle.c b/src/kernel/battle.c index 875679154..4af7ace44 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -109,7 +109,6 @@ static int obs_count = 0; # define ROW_FACTOR 10 #endif static const double EFFECT_PANIC_SPELL = 0.25; - static const double TROLL_REGENERATION = 0.10; /* Nach dem alten System: */ @@ -121,11 +120,8 @@ static message *msg_separator; const troop no_troop = { 0, 0 }; static int max_turns = 0; - static int damage_rules = 0; - static int loot_rules = 0; - static int skill_formula = 0; #define FORMULA_ORIG 0 @@ -182,11 +178,8 @@ static int army_index(side * s) region *fleeregion(const unit * u) { region *r = u->region; - region *neighbours[MAXDIRECTIONS]; - int c = 0; - direction_t i; if (u->ship && !fval(r->terrain, SEA_REGION)) @@ -198,7 +191,6 @@ region *fleeregion(const unit * u) for (i = 0; i != MAXDIRECTIONS; ++i) { region *r2 = rconnect(r, i); - if (r2) { if (can_survive(u, r2) && !move_blocked(u, r, r2)) neighbours[c++] = r2; @@ -215,7 +207,6 @@ static char *sidename(side * s) { #define SIDENAMEBUFLEN 256 static int bufno; /* STATIC_XCALL: used across calls */ - static char sidename_buf[4][SIDENAMEBUFLEN]; /* STATIC_RESULT: used for return, not across calls */ bufno = bufno % 4; @@ -232,7 +223,6 @@ static char *sidename(side * s) static const char *sideabkz(side * s, boolean truename) { static char sideabkz_buf[8]; /* STATIC_RESULT: used for return, not across calls */ - const faction *f = (s->stealthfaction && !truename) ? s->stealthfaction : s->faction; @@ -251,7 +241,6 @@ static void message_faction(battle * b, faction * f, struct message *m) if (f->battles == NULL || f->battles->r != r) { struct bmsg *bm = calloc(1, sizeof(struct bmsg)); - bm->next = f->battles; f->battles = bm; bm->r = r; @@ -262,9 +251,7 @@ static void message_faction(battle * b, faction * f, struct message *m) int armedmen(const unit * u, boolean siege_weapons) { item *itm; - int n = 0; - if (!(urace(u)->flags & RCF_NOWEAPONS)) { if (effskill(u, SK_WEAPONLESS) >= 1) { /* kann ohne waffen bewachen: fuer drachen */ @@ -274,7 +261,6 @@ int armedmen(const unit * u, boolean siege_weapons) * Personen minimiert */ for (itm = u->items; itm; itm = itm->next) { const weapon_type *wtype = resource2weapon(itm->type->rtype); - if (wtype == NULL || (!siege_weapons && (wtype->flags & WTF_SIEGE))) continue; if (effskill(u, wtype->skill) >= 1) @@ -292,9 +278,7 @@ int armedmen(const unit * u, boolean siege_weapons) void message_all(battle * b, message * m) { bfaction *bf; - plane *p = rplane(b->region); - watcher *w; for (bf = b->factions; bf; bf = bf->next) { @@ -313,7 +297,6 @@ void message_all(battle * b, message * m) static void fbattlerecord(battle * b, faction * f, const char *s) { message *m = msg_message("battle_msg", "string", s); - message_faction(b, f, m); msg_release(m); } @@ -327,7 +310,6 @@ static void fbattlerecord(battle * b, faction * f, const char *s) static boolean set_enemy(side * as, side * ds, boolean attacking) { int i; - for (i = 0; i != MAXSIDES; ++i) { if (ds->enemies[i] == NULL) ds->enemies[i] = as; @@ -388,14 +370,11 @@ fighter *select_corpse(battle * b, fighter * af) * Untote werden nicht ausgewählt (casualties, not dead) */ { int si, di, maxcasualties = 0; - fighter *df; - side *s; for (si = 0; si != b->nsides; ++si) { side *s = b->sides + si; - if (af == NULL || (!enemy_i(af->side, si) && allysf(af->side, s->faction))) { maxcasualties += s->casualties; } @@ -406,7 +385,6 @@ fighter *select_corpse(battle * b, fighter * af) /* Geflohene haben auch 0 hp, dürfen hier aber nicht ausgewählt * werden! */ int dead = dead_fighters(df); - if (!playerrace(df->unit->race)) continue; @@ -471,28 +449,20 @@ static double hpflee(int status) static int get_row(const side * s, int row, const side * vs) { boolean counted[MAXSIDES]; - int enemyfront = 0; - int line, result; - int retreat = 0; - int size[NUMROWS]; - int front = 0; - battle *b = s->battle; memset(counted, 0, sizeof(counted)); memset(size, 0, sizeof(size)); for (line = FIRST_ROW; line != NUMROWS; ++line) { int si, sa_i; - /* how many enemies are there in the first row? */ for (si = 0; s->enemies[si]; ++si) { side *se = s->enemies[si]; - if (se->size[line] > 0) { enemyfront += se->size[line]; /* - s->nonblockers[line] (nicht, weil angreifer) */ @@ -500,7 +470,6 @@ static int get_row(const side * s, int row, const side * vs) } for (sa_i = 0; sa_i != b->nsides; ++sa_i) { side *sa = b->sides + sa_i; - /* count people that like me, but don't like my enemy */ if (friendly_i(s, sa_i) && enemy_i(vs, sa_i)) { if (!counted[sa_i]) { @@ -537,10 +506,8 @@ static int get_row(const side * s, int row, const side * vs) int get_unitrow(const fighter * af, const side * vs) { int row = statusrow(af->status); - if (vs == NULL) { int i; - for (i = FIGHT_ROW; i != row; ++i) if (af->side->size[i]) break; @@ -548,7 +515,6 @@ int get_unitrow(const fighter * af, const side * vs) } else { #ifdef FASTROW battle *b = vs->battle; - if (row != b->rowcache.row || b->alive != b->rowcache.alive || af->side != b->rowcache.as || vs != b->rowcache.vs) { b->rowcache.alive = b->alive; @@ -561,7 +527,6 @@ int get_unitrow(const fighter * af, const side * vs) #ifdef DEBUG_FAST /* validation code */ { int i = get_row(af->side, row, vs); - assert(i == b->rowcache.result); } #endif @@ -575,9 +540,7 @@ int get_unitrow(const fighter * af, const side * vs) static void reportcasualties(battle * b, fighter * fig, int dead) { struct message *m; - region *r = NULL; - if (fig->alive == fig->unit->number) return; #ifndef SIMPLE_ESCAPE @@ -598,7 +561,6 @@ static int contest_classic(int skilldiff, const armor_type * ar, const armor_type * sh) { int p, vw = BASE_CHANCE - TDIFF_CHANGE * skilldiff; - double mod = 1.0; if (ar != NULL) @@ -623,14 +585,11 @@ contest_new(int skilldiff, const troop dt, const armor_type * ar, const armor_type * sh) { double tohit = 0.5 + skilldiff * 0.1; - if (tohit < 0.5) tohit = 0.5; if (chance(tohit)) { int defense = effskill(dt.fighter->unit, SK_STAMINA); - double tosave = defense * 0.05; - return !chance(tosave); } return 0; @@ -659,9 +618,7 @@ static boolean is_riding(const troop t) static weapon *preferred_weapon(const troop t, boolean attacking) { weapon *missile = t.fighter->person[t.index].missile; - weapon *melee = t.fighter->person[t.index].melee; - if (attacking) { if (melee == NULL || (missile && missile->attackskill > melee->attackskill)) { return missile; @@ -715,9 +672,7 @@ weapon_skill(const weapon_type * wtype, const unit * u, boolean attacking) /* wenn kein waffenloser kampf, dann den rassen-defaultwert */ if (u->race == new_race[RC_ORC]) { int sword = effskill(u, SK_MELEE); - int spear = effskill(u, SK_SPEAR); - skill = MAX(sword, spear) - 3; if (attacking) { skill = MAX(skill, u->race->at_default); @@ -800,12 +755,10 @@ static int CavalryBonus(const unit * u, troop enemy, int type) } else { /* new rule, chargers in Eressea 1.1 */ int skl = effskill(u, SK_RIDING); - /* only half against trolls */ if (skl > 0) { if (type == BONUS_DAMAGE) { int dmg = MIN(skl, 8); - if (enemy.fighter->unit->race == new_race[RC_TROLL]) { dmg = dmg / 4; } else { @@ -829,11 +782,8 @@ weapon_effskill(troop t, troop enemy, const weapon * w, boolean attacking, /* In dieser Runde alle die Modifier berechnen, die fig durch die * Waffen bekommt. */ fighter *tf = t.fighter; - unit *tu = t.fighter->unit; - int skill; - const weapon_type *wtype = w ? w->type : NULL; if (wtype == NULL) { @@ -848,7 +798,6 @@ weapon_effskill(troop t, troop enemy, const weapon * w, boolean attacking, if (wtype->modifiers != NULL) { /* Pferdebonus, Lanzenbonus, usw. */ int m; - unsigned int flags = WMF_SKILL | (attacking ? WMF_OFFENSIVE : WMF_DEFENSIVE); @@ -864,7 +813,6 @@ weapon_effskill(troop t, troop enemy, const weapon * w, boolean attacking, for (m = 0; wtype->modifiers[m].value; ++m) { if ((wtype->modifiers[m].flags & flags) == flags) { race_list *rlist = wtype->modifiers[m].races; - if (rlist != NULL) { while (rlist) { if (rlist->data == tu->race) @@ -911,11 +859,8 @@ weapon_effskill(troop t, troop enemy, const weapon * w, boolean attacking, static const armor_type *select_armor(troop t, boolean shield) { unsigned int type = shield ? ATF_SHIELD : 0; - unit *u = t.fighter->unit; - const armor *a = t.fighter->armors; - int geschuetzt = 0; /* some monsters should not use armor (dragons in chainmail? ha!) */ @@ -939,7 +884,6 @@ static const armor_type *select_armor(troop t, boolean shield) return NULL; } - /* Hier ist zu beachten, ob und wie sich Zauber und Artefakte, die * Rüstungschutz geben, addieren. * - Artefakt I_TROLLBELT gibt Rüstung +1 @@ -948,9 +892,7 @@ static const armor_type *select_armor(troop t, boolean shield) int select_magicarmor(troop t) { unit *u = t.fighter->unit; - int geschuetzt = 0; - int ma = 0; geschuetzt = MIN(get_item(u, I_TROLLBELT), u->number); @@ -1016,7 +958,6 @@ void rmfighter(fighter * df, int i) df->alive -= i; } - static void rmtroop(troop dt) { fighter *df = dt.fighter; @@ -1035,11 +976,8 @@ static void rmtroop(troop dt) void remove_troop(troop dt) { fighter *df = dt.fighter; - struct person p = df->person[dt.index]; - battle *b = df->side->battle; - #ifdef FASTCOUNT b->fast.alive = -1; /* invalidate cached value */ #endif @@ -1055,15 +993,12 @@ void remove_troop(troop dt) void kill_troop(troop dt) { fighter *df = dt.fighter; - unit *du = df->unit; rmtroop(dt); if (!df->alive) { char eqname[64]; - const struct equipment *eq; - if (du->race->itemdrop) { item *drops = du->race->itemdrop(du->race, du->number - df->run.number); @@ -1085,7 +1020,6 @@ void kill_troop(troop dt) void drain_exp(struct unit *u, int n) { skill_t sk = (skill_t) (rng_int() % MAXSKILLS); - skill_t ssk; ssk = sk; @@ -1101,7 +1035,6 @@ void drain_exp(struct unit *u, int n) } if (sk != NOSKILL) { skill *sv = get_skill(u, sk); - while (n > 0) { if (n >= 30 * u->number) { reduce_skill(u, sv, 1); @@ -1132,20 +1065,15 @@ const char *rel_dam(int dam, int hp) static void vampirism(troop at, int damage) { static int vampire = -1; - if (vampire < 0) vampire = get_param_int(global.parameters, "rules.combat.demon_vampire", 0); - if (vampire > 0) { int gain = damage / vampire; - int chance = damage - vampire * gain; - if (chance > 0 && (rng_int() % vampire < chance)) ++gain; if (gain > 0) { int maxhp = unit_max_hp(at.fighter->unit); - at.fighter->person[at.index].hp = MIN(gain + at.fighter->person[at.index].hp, maxhp); } @@ -1155,9 +1083,7 @@ static void vampirism(troop at, int damage) static int natural_armor(unit * du) { static int *bonus = 0; - int an = du->race->armor; - if (bonus == 0) { bonus = calloc(sizeof(int), num_races); } @@ -1169,7 +1095,6 @@ static int natural_armor(unit * du) } if (bonus[du->race->index] > 0) { int sk = effskill(du, SK_STAMINA); - sk /= bonus[du->race->index]; an += sk; } @@ -1180,42 +1105,28 @@ boolean terminate(troop dt, troop at, int type, const char *damage, boolean missile) { item **pitm; - fighter *df = dt.fighter; - fighter *af = at.fighter; - unit *au = af->unit; - unit *du = df->unit; - battle *b = df->side->battle; - int heiltrank = 0; - static int rule_armor = -1; /* Schild */ side *ds = df->side; - int hp; int ar = 0, an, am; - const armor_type *armor = select_armor(dt, true); - const armor_type *shield = select_armor(dt, false); const weapon_type *dwtype = NULL; - const weapon_type *awtype = NULL; - const weapon *weapon; int rda, sk = 0, sd; - boolean magic = false; - int da = dice_rand(damage); assert(du->number > 0); @@ -1336,7 +1247,6 @@ terminate(troop dt, troop at, int type, const char *damage, boolean missile) } } - if (magic) { /* Magischer Schaden durch Spruch oder magische Waffe */ double res = 1.0; @@ -1372,9 +1282,7 @@ terminate(troop dt, troop at, int type, const char *damage, boolean missile) rda = 0; else { int qi; - quicklist *ql; - unsigned int i = 0; if (du->race->battle_flags & BF_RES_PIERCE) @@ -1390,7 +1298,6 @@ terminate(troop dt, troop at, int type, const char *damage, boolean missile) /* Schilde */ for (qi = 0, ql = b->meffects; ql; ql_advance(&ql, &qi, 1)) { meffect *me = (meffect *) ql_get(ql, qi); - if (meffect_protection(b, me, ds) != 0) { assert(0 <= rda); /* rda sollte hier immer mindestens 0 sein */ /* jeder Schaden wird um effect% reduziert bis der Schild duration @@ -1454,7 +1361,6 @@ terminate(troop dt, troop at, int type, const char *damage, boolean missile) if (heiltrank && (chance(0.50))) { { message *m = msg_message("battle::potionsave", "unit", du); - message_faction(b, du->faction, m); msg_release(m); } @@ -1473,9 +1379,7 @@ terminate(troop dt, troop at, int type, const char *damage, boolean missile) } for (pitm = &du->items; *pitm;) { item *itm = *pitm; - const item_type *itype = itm->type; - if (!(itype->flags & ITF_CURSED) && dt.index < itm->number) { /* 25% Grundchance, das ein Item kaputtgeht. */ if (rng_int() % 4 < 1) { @@ -1495,9 +1399,7 @@ static int count_side(const side * s, const side * vs, int minrow, int maxrow, int select) { fighter *fig; - int people = 0; - int unitrow[NUMROWS]; if (maxrow < FIGHT_ROW) @@ -1509,7 +1411,6 @@ count_side(const side * s, const side * vs, int minrow, int maxrow, int select) for (fig = s->fighters; fig; fig = fig->next) { if (fig->alive - fig->removed > 0) { int row = statusrow(fig->status); - if (select & SELECT_ADVANCE) { if (unitrow[row] == -1) { unitrow[row] = get_unitrow(fig, vs); @@ -1533,9 +1434,7 @@ int count_allies(const side * as, int minrow, int maxrow, int select, int allytype) { battle *b = as->battle; - side *ds; - int count = 0; for (ds = b->sides; ds != b->sides + b->nsides; ++ds) { @@ -1554,13 +1453,11 @@ count_enemies_i(battle * b, const fighter * af, int minrow, int maxrow, int select) { side *es, *as = af->side; - int i = 0; for (es = b->sides; es != b->sides + b->nsides; ++es) { if (as == NULL || enemy(es, as)) { int offset = 0; - if (select & SELECT_DISTANCE) { offset = get_unitrow(af, es) - FIGHT_ROW; } @@ -1578,7 +1475,6 @@ count_enemies(battle * b, const fighter * af, int minrow, int maxrow, { #ifdef FASTCOUNT int sr = statusrow(af->status); - side *as = af->side; if (b->alive == b->fast.alive && as == b->fast.side && sr == b->fast.status @@ -1586,7 +1482,6 @@ count_enemies(battle * b, const fighter * af, int minrow, int maxrow, if (b->fast.enemies[select] >= 0) { #ifdef DEBUG_FAST int i = count_enemies_i(b, af, minrow, maxrow, select); - assert(i == b->fast.enemies[select]); #endif return b->fast.enemies[select]; @@ -1594,7 +1489,6 @@ count_enemies(battle * b, const fighter * af, int minrow, int maxrow, if (b->fast.enemies[select - SELECT_FIND] >= 0) { #ifdef DEBUG_FAST int i = count_enemies_i(b, af, minrow, maxrow, select); - assert((i > 0) == (b->fast.enemies[select - SELECT_FIND] > 0)); #endif return b->fast.enemies[select - SELECT_FIND]; @@ -1611,7 +1505,6 @@ count_enemies(battle * b, const fighter * af, int minrow, int maxrow, #endif if (maxrow >= FIRST_ROW) { int i = count_enemies_i(b, af, minrow, maxrow, select); - #ifdef FASTCOUNT b->fast.enemies[select] = i; #endif @@ -1623,13 +1516,9 @@ count_enemies(battle * b, const fighter * af, int minrow, int maxrow, troop select_enemy(fighter * af, int minrow, int maxrow, int select) { side *as = af->side; - battle *b = as->battle; - int si, selected; - int enemies; - #ifdef DEBUG_SELECT troop result = no_troop; #endif @@ -1650,11 +1539,8 @@ troop select_enemy(fighter * af, int minrow, int maxrow, int select) selected = rng_int() % enemies; for (si = 0; as->enemies[si]; ++si) { side *ds = as->enemies[si]; - fighter *df; - int unitrow[NUMROWS]; - int offset = 0; if (select & SELECT_DISTANCE) @@ -1662,7 +1548,6 @@ troop select_enemy(fighter * af, int minrow, int maxrow, int select) if (select & SELECT_ADVANCE) { int ui; - for (ui = 0; ui != NUMROWS; ++ui) unitrow[ui] = -1; } @@ -1690,7 +1575,6 @@ troop select_enemy(fighter * af, int minrow, int maxrow, int select) } #else troop dt; - dt.index = selected; dt.fighter = df; return dt; @@ -1714,11 +1598,8 @@ troop select_enemy(fighter * af, int minrow, int maxrow, int select) static int get_tactics(const side * as, const side * ds) { battle *b = as->battle; - side *stac; - int result = 0; - int defense = 0; if (b->max_tactics > 0) { @@ -1739,7 +1620,6 @@ static int get_tactics(const side * as, const side * ds) static troop select_opponent(battle * b, troop at, int mindist, int maxdist) { fighter *af = at.fighter; - troop dt; if (af->unit->race->flags & RCF_FLY) { @@ -1764,10 +1644,8 @@ static troop select_opponent(battle * b, troop at, int mindist, int maxdist) /* percentage chance to get this attack */ if (tactics > 0) { double tacch = 0.1 * tactics; - if (fval(b->region->terrain, SEA_REGION)) { ship *sh = at.fighter->unit->ship; - if (sh) tacch *= sh->type->tac_bonus; } @@ -1787,7 +1665,6 @@ quicklist *fighters(battle * b, const side * vs, int minrow, int maxrow, int mask) { side *s; - quicklist *fightervp = 0; assert(vs != NULL); @@ -1807,7 +1684,6 @@ quicklist *fighters(battle * b, const side * vs, int minrow, int maxrow, } for (fig = s->fighters; fig; fig = fig->next) { int row = get_unitrow(fig, vs); - if (row >= minrow && row <= maxrow) { ql_push(&fightervp, fig); } @@ -1820,7 +1696,6 @@ quicklist *fighters(battle * b, const side * vs, int minrow, int maxrow, static void report_failed_spell(battle * b, unit * mage, const spell * sp) { message *m = msg_message("battle::spell_failed", "unit spell", mage, sp); - message_all(b, m); msg_release(m); } @@ -1828,20 +1703,15 @@ static void report_failed_spell(battle * b, unit * mage, const spell * sp) void do_combatmagic(battle * b, combatmagic_t was) { side *s; - region *r = b->region; - castorder *co; - int level, rank, sl; - spellrank spellranks[MAX_SPELLRANK]; memset(spellranks, 0, sizeof(spellranks)); for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *fig; - for (fig = s->fighters; fig; fig = fig->next) { unit *mage = fig->unit; @@ -1851,11 +1721,8 @@ void do_combatmagic(battle * b, combatmagic_t was) level = eff_skill(mage, SK_MAGIC, r); if (level > 0) { double power; - const spell *sp; - const struct locale *lang = mage->faction->locale; - order *ord; switch (was) { @@ -1907,11 +1774,8 @@ void do_combatmagic(battle * b, combatmagic_t was) for (rank = 0; rank < MAX_SPELLRANK; rank++) { for (co = spellranks[rank].begin; co; co = co->next) { fighter *fig = co->magician.fig; - const spell *sp = co->sp; - int level = co->level; - double power = co->force; if (sp->sp_function == NULL) { @@ -1937,31 +1801,19 @@ static void combat_action(fighter * af, int turn) #endif } - static void do_combatspell(troop at) { const spell *sp; - fighter *fi = at.fighter; - unit *mage = fi->unit; - battle *b = fi->side->battle; - region *r = b->region; - quicklist *ql; - int level, qi; - double power; - int fumblechance = 0; - order *ord; - int sl; - const struct locale *lang = mage->faction->locale; sp = get_combatspell(mage, 1); @@ -1987,7 +1839,6 @@ static void do_combatspell(troop at) for (qi = 0, ql = b->meffects; ql; ql_advance(&ql, &qi, 1)) { meffect *mblock = (meffect *) ql_get(ql, qi); - if (mblock->typ == SHIELD_BLOCK) { if (meffect_blocked(b, mblock, fi->side) != 0) { fumblechance += mblock->duration; @@ -2022,7 +1873,6 @@ static void do_combatspell(troop at) } } - /* Sonderattacken: Monster patzern nicht und zahlen auch keine * Spruchkosten. Da die Spruchstärke direkt durch den Level bestimmt * wird, wirkt auch keine Antimagie (wird sonst in spellpower @@ -2031,9 +1881,7 @@ static void do_combatspell(troop at) static void do_extra_spell(troop at, const att * a) { const spell *sp = a->data.sp; - fighter *fi = at.fighter; - double power; power = sp->level * MagicPower(); @@ -2047,11 +1895,8 @@ static void do_extra_spell(troop at, const att * a) static int skilldiff(troop at, troop dt, int dist) { fighter *af = at.fighter, *df = dt.fighter; - unit *au = af->unit, *du = df->unit; - int is_protected = 0, skdiff = 0; - weapon *awp = select_weapon(at, true, dist > 1); skdiff += af->person[at.index].attack; @@ -2067,7 +1912,6 @@ static int skilldiff(troop at, troop dt, int dist) if (au->race == new_race[RC_GOBLIN]) { static int goblin_bonus = -1; - if (goblin_bonus < 0) goblin_bonus = get_param_int(global.parameters, "rules.combat.goblinbonus", 10); @@ -2078,9 +1922,7 @@ static int skilldiff(troop at, troop dt, int dist) if (df->building) { boolean init = false; - static const curse_type *strongwall_ct, *magicwalls_ct; - if (!init) { strongwall_ct = ct_find("strongwall"); magicwalls_ct = ct_find("magicwalls"); @@ -2088,7 +1930,6 @@ static int skilldiff(troop at, troop dt, int dist) } if (df->building->type->protection) { int beff = df->building->type->protection(df->building, du); - if (beff) { skdiff -= beff; is_protected = 2; @@ -2096,7 +1937,6 @@ static int skilldiff(troop at, troop dt, int dist) } if (strongwall_ct) { curse *c = get_curse(df->building->attribs, strongwall_ct); - if (curse_active(c)) { /* wirkt auf alle Gebäude */ skdiff -= curse_geteffect_int(c); @@ -2119,7 +1959,6 @@ static int skilldiff(troop at, troop dt, int dist) skdiff -= is_protected; if (awp->type->modifiers) { int w; - for (w = 0; awp->type->modifiers[w].value != 0; ++w) { if (awp->type->modifiers[w].flags & WMF_MISSILE_TARGET) { /* skill decreases by targeting difficulty (bow -2, catapult -4) */ @@ -2131,7 +1970,6 @@ static int skilldiff(troop at, troop dt, int dist) } if (skill_formula == FORMULA_ORIG) { weapon *dwp = select_weapon(dt, false, dist > 1); - skdiff -= weapon_effskill(dt, at, dwp, false, dist > 1); } return skdiff; @@ -2140,9 +1978,7 @@ static int skilldiff(troop at, troop dt, int dist) static int setreload(troop at) { fighter *af = at.fighter; - const weapon_type *wtype = af->person[at.index].missile->type; - if (wtype->reload == 0) return 0; return af->person[at.index].reload = wtype->reload; @@ -2170,13 +2006,9 @@ debug_hit(troop at, const weapon * awp, troop dt, const weapon * dwp, int hits(troop at, troop dt, weapon * awp) { fighter *af = at.fighter, *df = dt.fighter; - const armor_type *armor, *shield = 0; - int skdiff = 0; - int dist = get_unitrow(af, df->side) + get_unitrow(df, af->side) - 1; - weapon *dwp = select_weapon(dt, false, dist > 1); if (!df->alive) @@ -2260,7 +2092,6 @@ void damage_building(battle * b, building * bldg, int damage_abs) for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *fig; - for (fig = s->fighters; fig; fig = fig->next) { if (fig->building == bldg) { if (bldg->sizeleft >= fig->unit->number) { @@ -2283,21 +2114,16 @@ static int attacks_per_round(troop t) static void make_heroes(battle * b) { side *s; - static int hero_speed = 0; - if (hero_speed == 0) { hero_speed = get_param_int(global.parameters, "rules.combat.herospeed", 10); } for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *fig; - for (fig = s->fighters; fig; fig = fig->next) { unit *u = fig->unit; - if (fval(u, UFL_HERO)) { int i; - if (!playerrace(u->race)) { log_error(("Hero %s is a %s.\n", unitname(u), u->race->_name[0])); } @@ -2312,9 +2138,7 @@ static void make_heroes(battle * b) static void attack(battle * b, troop ta, const att * a, int numattack) { fighter *af = ta.fighter; - troop td; - unit *au = af->unit; switch (a->type) { @@ -2335,7 +2159,6 @@ static void attack(battle * b, troop ta, const att * a, int numattack) case AT_STANDARD: /* Waffen, mag. Gegenstände, Kampfzauber */ if (numattack > 0 || af->magic <= 0) { weapon *wp = ta.fighter->person[ta.index].missile; - int melee = count_enemies(b, af, melee_range[0], melee_range[1], SELECT_ADVANCE | SELECT_DISTANCE | SELECT_FIND); @@ -2347,14 +2170,11 @@ static void attack(battle * b, troop ta, const att * a, int numattack) ta.fighter->person[ta.index].reload--; } else { boolean standard_attack = true; - boolean reload = false; - /* spezialattacken der waffe nur, wenn erste attacke in der runde. * sonst helden mit feuerschwertern zu mächtig */ if (numattack == 0 && wp && wp->type->attack) { int dead = 0; - standard_attack = wp->type->attack(&ta, wp->type, &dead); if (!standard_attack) reload = true; @@ -2366,7 +2186,6 @@ static void attack(battle * b, troop ta, const att * a, int numattack) } if (standard_attack) { boolean missile = false; - if (wp && fval(wp->type, WTF_MISSILE)) missile = true; if (missile) { @@ -2383,7 +2202,6 @@ static void attack(battle * b, troop ta, const att * a, int numattack) reload = true; if (hits(ta, td, wp)) { const char *d; - if (wp == NULL) d = au->race->def_damage; else if (is_riding(ta)) @@ -2395,7 +2213,6 @@ static void attack(battle * b, troop ta, const att * a, int numattack) } if (reload && wp && wp->type->reload && !getreload(ta)) { int i = setreload(ta); - if (bdebug) { fprintf(bdebug, "%s/%d reloading %d turns\n", unitid(au), ta.index, i); @@ -2429,7 +2246,6 @@ static void attack(battle * b, troop ta, const att * a, int numattack) } if (hits(ta, td, NULL)) { int c = dice_rand(a->data.dice); - while (c > 0) { if (rng_int() % 2) { td.fighter->person[td.index].attack -= 1; @@ -2485,11 +2301,8 @@ static void attack(battle * b, troop ta, const att * a, int numattack) void do_attack(fighter * af) { troop ta; - unit *au = af->unit; - side *side = af->side; - battle *b = side->battle; ta.fighter = af; @@ -2506,13 +2319,11 @@ void do_attack(fighter * af) /* Wir suchen eine beliebige Feind-Einheit aus. An der können * wir feststellen, ob noch jemand da ist. */ int apr, attacks = attacks_per_round(ta); - if (!count_enemies(b, af, FIGHT_ROW, LAST_ROW, SELECT_FIND)) break; for (apr = 0; apr != attacks; ++apr) { int a; - for (a = 0; a != 10 && au->race->attack[a].type != AT_NONE; ++a) { if (apr > 0) { /* Wenn die Waffe nachladen muss, oder es sich nicht um einen @@ -2521,7 +2332,6 @@ void do_attack(fighter * af) continue; else { weapon *wp = preferred_weapon(ta, true); - if (wp != NULL && wp->type->reload) continue; } @@ -2544,7 +2354,6 @@ void do_attack(fighter * af) void do_regenerate(fighter * af) { troop ta; - unit *au = af->unit; ta.fighter = af; @@ -2572,17 +2381,11 @@ static void add_tactics(tactics * ta, fighter * fig, int value) static double horsebonus(const unit * u) { static const item_type *it_horse = 0; - static const item_type *it_elvenhorse = 0; - static const item_type *it_charger = 0; - region *r = u->region; - int n1 = 0, n2 = 0, n3 = 0; - item *itm = u->items; - int skl = eff_skill(u, SK_RIDING, r); if (skl < 1) @@ -2616,11 +2419,8 @@ static double horsebonus(const unit * u) double fleechance(unit * u) { double c = 0.20; /* Fluchtwahrscheinlichkeit in % */ - region *r = u->region; - attrib *a = a_find(u->attribs, &at_fleechance); - /* Einheit u versucht, dem Getümmel zu entkommen */ c += (eff_skill(u, SK_STEALTH, r) * 0.05); @@ -2646,7 +2446,6 @@ static side *make_side(battle * b, const faction * f, const group * g, unsigned int flags, const faction * stealthfaction) { side *s1 = b->sides + b->nsides; - bfaction *bf; #ifdef SIMPLE_COMBAT @@ -2655,7 +2454,6 @@ static side *make_side(battle * b, const faction * f, const group * g, flags |= SIDE_HASGUARDS; } else { unit *u; - for (u = b->region->units; u; u = u->next) { if (is_guard(u, HELP_ALL)) { if (alliedunit(u, f, HELP_GUARD)) { @@ -2691,11 +2489,8 @@ static side *make_side(battle * b, const faction * f, const group * g, troop select_ally(fighter * af, int minrow, int maxrow, int allytype) { side *as = af->side; - battle *b = as->battle; - side *ds; - int allies = count_allies(as, minrow, maxrow, SELECT_ADVANCE, allytype); if (!allies) { @@ -2707,14 +2502,11 @@ troop select_ally(fighter * af, int minrow, int maxrow, int allytype) if ((allytype == ALLY_ANY && helping(as, ds)) || (allytype == ALLY_SELF && as->faction == ds->faction)) { fighter *df; - for (df = ds->fighters; df; df = df->next) { int dr = get_unitrow(df, NULL); - if (dr >= minrow && dr <= maxrow) { if (df->alive - df->removed > allies) { troop dt; - assert(allies >= 0); dt.index = allies; dt.fighter = df; @@ -2729,21 +2521,17 @@ troop select_ally(fighter * af, int minrow, int maxrow, int allytype) return no_troop; } - static int loot_quota(const unit * src, const unit * dst, const item_type * type, int n) { static float divisor = -1; - if (dst && src && src->faction != dst->faction) { if (divisor < 0) { divisor = get_param_flt(global.parameters, "rules.items.loot_divisor", 1); - assert(divisor == 0 || divisor >= 1); } if (divisor >= 1) { double r = n / divisor; - int x = (int)r; r = r - x; @@ -2759,11 +2547,8 @@ static int loot_quota(const unit * src, const unit * dst, static void loot_items(fighter * corpse) { unit *u = corpse->unit; - item *itm = u->items; - battle *b = corpse->side->battle; - int dead = dead_fighters(corpse); if (dead <= 0) @@ -2771,22 +2556,16 @@ static void loot_items(fighter * corpse) while (itm) { float lootfactor = dead / (float)u->number; /* only loot the dead! */ - int maxloot = (int)(itm->number * lootfactor); - if (maxloot > 0) { int i = MIN(10, maxloot); - for (; i != 0; --i) { int loot = maxloot / i; if (loot > 0) { fighter *fig = NULL; - int looting = 0; - int maxrow = 0; - /* mustloot: we absolutely, positively must have somebody loot this thing */ int mustloot = itm->type->flags & (ITF_CURSED | ITF_NOTLOST); @@ -2805,7 +2584,6 @@ static void loot_items(fighter * corpse) maxrow = LAST_ROW; } else if (loot_rules & LOOT_KEEPLOOT) { int lootchance = 50 + b->keeploot; - if (rng_int() % 100 < lootchance) { maxrow = BEHIND_ROW; } @@ -2830,7 +2608,6 @@ static void loot_items(fighter * corpse) loot); if (trueloot > 0) { item *l = fig->loot; - while (l && l->type != itm->type) l = l->next; if (!l) { @@ -2877,7 +2654,6 @@ static boolean seematrix(const faction * f, const side * s) static double PopulationDamage(void) { static double value = -1.0; - if (value < 0) { int damage = get_param_int(global.parameters, "rules.combat.populationdamage", @@ -2887,11 +2663,9 @@ static double PopulationDamage(void) return value; } - static void battle_effects(battle * b, int dead_players) { region *r = b->region; - int dead_peasants = MIN(rpeasants(r), (int)(dead_players * PopulationDamage())); if (dead_peasants) { @@ -2904,11 +2678,8 @@ static void battle_effects(battle * b, int dead_players) static void reorder_fleeing(region * r) { unit **usrc = &r->units; - unit **udst = &r->units; - unit *ufirst = NULL; - unit *u; for (; *udst; udst = &u->next) { @@ -2932,29 +2703,20 @@ static void reorder_fleeing(region * r) static void aftermath(battle * b) { int i; - region *r = b->region; - ship *sh; - side *s; - int dead_players = 0; - bfaction *bf; - boolean ships_damaged = (boolean) (b->turn + (b->has_tactics_turn ? 1 : 0) > 2); /* only used for ship damage! */ for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *df; - s->dead = 0; for (df = s->fighters; df; df = df->next) { unit *du = df->unit; - int dead = dead_fighters(df); - int pr_mercy = 0; /* Regeneration durch PR_MERCY */ @@ -2993,11 +2755,8 @@ static void aftermath(battle * b) for (s = b->sides; s != b->sides + b->nsides; ++s) { int snumber = 0; - fighter *df; - boolean relevant = false; /* Kampf relevant für diese Partei? */ - #ifdef SIMPLE_COMBAT if (fval(s, SIDE_HASGUARDS) == 0) relevant = true; @@ -3006,7 +2765,6 @@ static void aftermath(battle * b) relevant = true; } else if (s->bf->lastturn == 1 && b->has_tactics_turn) { side *stac; - for (stac = b->sides; stac; stac = stac->next) { if (stac->leader.value == b->max_tactics && helping(stac, s)) { relevant = true; @@ -3019,11 +2777,8 @@ static void aftermath(battle * b) for (df = s->fighters; df; df = df->next) { unit *du = df->unit; - int dead = dead_fighters(df); - int sum_hp = 0; - int n; for (n = 0; n != df->alive; ++n) { @@ -3035,7 +2790,6 @@ static void aftermath(battle * b) #ifdef SIMPLE_COMBAT if (relevant) { int flags = UFL_LONGACTION | UFL_NOTMOVING; - #ifdef SIMPLE_ESCAPE if (du->status == ST_FLEE) flags -= UFL_NOTMOVING; @@ -3045,7 +2799,6 @@ static void aftermath(battle * b) if (sum_hp + df->run.hp < du->hp) { /* someone on the ship got damaged, damage the ship */ ship *sh = du->ship ? du->ship : leftship(du); - if (sh) fset(sh, SF_DAMAGED); } @@ -3054,7 +2807,6 @@ static void aftermath(battle * b) fset(du, UFL_NOTMOVING); /* unit cannot move this round */ if (df->action_counter >= du->number) { ship *sh = du->ship ? du->ship : leftship(du); - if (sh) fset(sh, SF_DAMAGED); fset(du, UFL_LONGACTION); @@ -3170,14 +2922,12 @@ static void aftermath(battle * b) message *seen = msg_message("battle::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", "index abbrev dead fled survived", army_index(s), "-?-", s->dead, s->flee, s->alive); for (bf = b->factions; bf; bf = bf->next) { faction *f = bf->faction; - message *m = seematrix(f, s) ? seen : unseen; message_faction(b, f, m); @@ -3196,13 +2946,11 @@ static void aftermath(battle * b) for (df = s->fighters; df; df = df->next) { unit *du = df->unit; - item *l; /* Beute verteilen */ for (l = df->loot; l; l = l->next) { const item_type *itype = l->type; - message *m = msg_message("battle_loot", "unit amount item", du, l->number, itype->rtype); @@ -3222,7 +2970,6 @@ static void aftermath(battle * b) if (sh && fval(sh, SF_DAMAGED)) { int n = b->turn - 2; - if (n > 0) { float dmg = get_param_flt(global.parameters, "rules.ship.damage.battleround", @@ -3240,7 +2987,6 @@ static void aftermath(battle * b) while (*sp) { ship *sh = *sp; - freset(sh, SF_DAMAGED); if (sh->damage >= sh->size * DAMAGE_SCALE) { remove_ship(sp, sh); @@ -3263,7 +3009,6 @@ static void aftermath(battle * b) static void battle_punit(unit * u, battle * b) { bfaction *bf; - strlist *S, *x; for (bf = b->factions; bf; bf = bf->next) { @@ -3286,7 +3031,6 @@ static void battle_punit(unit * u, battle * b) static void print_fighters(battle * b, const side * s) { fighter *df; - int row; for (row = 1; row != NUMROWS; ++row) { @@ -3294,7 +3038,6 @@ static void print_fighters(battle * b, const side * s) for (df = s->fighters; df; df = df->next) { unit *du = df->unit; - int thisrow = statusrow(df->unit->status); if (row == thisrow) { @@ -3323,29 +3066,20 @@ static void set_attacker(fighter * fig) static void print_header(battle * b) { bfaction *bf; - char zText[32 * MAXSIDES]; for (bf = b->factions; bf; bf = bf->next) { message *m; - faction *f = bf->faction; - const char *lastf = NULL; - boolean first = false; - side *s; - char *bufp = zText; - size_t size = sizeof(zText) - 1; - int bytes; for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *df; - for (df = s->fighters; df; df = df->next) { if (is_attacker(df)) { if (first) { @@ -3393,11 +3127,8 @@ static void print_header(battle * b) static void print_stats(battle * b) { side *s2; - side *s; - int i = 0; - for (s = b->sides; s != b->sides + b->nsides; ++s) { bfaction *bf; @@ -3405,21 +3136,14 @@ static void print_stats(battle * b) for (bf = b->factions; bf; bf = bf->next) { faction *f = bf->faction; - const char *loc_army = LOC(f->locale, "battle_army"); - char *bufp; - const char *header; - size_t rsize, size; - int komma; - const char *sname = seematrix(f, s) ? sidename(s) : LOC(f->locale, "unknown_faction"); message *msg; - char buf[1024]; message_faction(b, f, msg_separator); @@ -3436,7 +3160,6 @@ static void print_stats(battle * b) for (s2 = b->sides; s2 != b->sides + b->nsides; ++s2) { if (enemy(s2, s)) { const char *abbrev = seematrix(f, s2) ? sideabkz(s2, false) : "-?-"; - rsize = slprintf(bufp, size, "%s %s %d(%s)", komma++ ? "," : (const char *)header, loc_army, army_index(s2), abbrev); @@ -3457,7 +3180,6 @@ static void print_stats(battle * b) for (s2 = b->sides; s2 != b->sides + b->nsides; ++s2) { if (friendly(s2, s)) { const char *abbrev = seematrix(f, s2) ? sideabkz(s2, false) : "-?-"; - rsize = slprintf(bufp, size, "%s %s %d(%s)", komma++ ? "," : (const char *)header, loc_army, army_index(s2), abbrev); @@ -3478,7 +3200,6 @@ static void print_stats(battle * b) for (s2 = b->sides; s2 != b->sides + b->nsides; ++s2) { if (s->relations[s2->index] & E_ATTACKING) { const char *abbrev = seematrix(f, s2) ? sideabkz(s2, false) : "-?-"; - rsize = slprintf(bufp, size, "%s %s %d(%s)", komma++ ? "," : (const char *)header, loc_army, army_index(s2), @@ -3522,16 +3243,12 @@ static void print_stats(battle * b) for (s = b->sides; s != b->sides + b->nsides; ++s) { if (s->leader.value == b->max_tactics) { quicklist *ql; - int qi; for (qi = 0, ql = s->leader.fighters; ql; ql_advance(&ql, &qi, 1)) { fighter *tf = (fighter *) ql_get(ql, qi); - unit *u = tf->unit; - message *m = NULL; - if (!is_attacker(tf)) { m = msg_message("battle::tactics_lost", "unit", u); } else { @@ -3557,43 +3274,24 @@ fighter *make_fighter(battle * b, unit * u, side * s1, boolean attack) { #define WMAX 20 weapon weapons[WMAX]; - int owp[WMAX]; - int dwp[WMAX]; - int w = 0; - region *r = b->region; - item *itm; - fighter *fig = NULL; - int i, tactics = eff_skill(u, SK_TACTICS, r); - side *s2; - int h; - int berserk; - int strongmen; - int speeded = 0, speed = 1; - boolean pr_aid = false; - int rest; - const group *g = NULL; - const attrib *a = a_find(u->attribs, &at_otherfaction); - const faction *stealthfaction = a ? get_otherfaction(a) : NULL; - unsigned int flags = 0; - static int rule_anon_battle = -1; assert(u->number); @@ -3606,7 +3304,6 @@ fighter *make_fighter(battle * b, unit * u, side * s1, boolean attack) flags |= SIDE_STEALTH; if (!(AllianceAuto() & HELP_FIGHT) && fval(u, UFL_GROUP)) { const attrib *agroup = a_find(u->attribs, &at_group); - if (agroup != NULL) g = (const group *)agroup->data.v; } @@ -3620,11 +3317,9 @@ fighter *make_fighter(battle * b, unit * u, side * s1, boolean attack) if (s2->faction == u->faction && s2->group == g) { #ifdef SIMPLE_COMBAT int s1flags = flags | SIDE_HASGUARDS; - int s2flags = s2->flags | SIDE_HASGUARDS; #else int s1flags = flags; - int s2flags = s2->flags; #endif if (rule_anon_battle && s2->stealthfaction != stealthfaction) { @@ -3658,7 +3353,6 @@ fighter *make_fighter(battle * b, unit * u, side * s1, boolean attack) set_attacker(fig); } else { building *b = u->building; - if (b && b->sizeleft >= u->number && playerrace(u->race)) { fig->building = b; fig->building->sizeleft -= u->number; @@ -3682,11 +3376,9 @@ fighter *make_fighter(battle * b, unit * u, side * s1, boolean attack) { static const curse_type *speed_ct; - speed_ct = ct_find("speed"); if (speed_ct) { curse *c = get_curse(u->attribs, speed_ct); - if (c) { speeded = get_cursedmen(u, c); speed = curse_geteffect_int(c); @@ -3734,10 +3426,8 @@ fighter *make_fighter(battle * b, unit * u, side * s1, boolean attack) * ihr kämpfen könnten, und was ihr Wert darin ist. */ if (u->race->battle_flags & BF_EQUIPMENT) { int oi = 0, di = 0; - for (itm = u->items; itm && w != WMAX; itm = itm->next) { const weapon_type *wtype = resource2weapon(itm->type->rtype); - if (wtype == NULL || itm->number == 0) continue; weapons[w].attackskill = weapon_skill(wtype, u, true); @@ -3755,7 +3445,6 @@ fighter *make_fighter(battle * b, unit * u, side * s1, boolean attack) for (i = 0; i != w; ++i) { int j, o = 0, d = 0; - for (j = 0; j != i; ++j) { if (weapon_weight(fig->weapons + j, true) >= weapon_weight(fig->weapons + i, true)) @@ -3782,7 +3471,6 @@ fighter *make_fighter(battle * b, unit * u, side * s1, boolean attack) /* hand out melee weapons: */ for (i = 0; i != fig->alive; ++i) { int wpless = weapon_skill(NULL, u, true); - while (oi != w && (fig->weapons[owp[oi]].used == fig->weapons[owp[oi]].count || fval(fig->weapons[owp[oi]].type, WTF_MISSILE))) { @@ -3823,7 +3511,6 @@ fighter *make_fighter(battle * b, unit * u, side * s1, boolean attack) fig->elvenhorses = 0; } else { static const item_type *it_charger = 0; - if (it_charger == 0) { it_charger = it_find("charger"); if (!it_charger) { @@ -3839,7 +3526,6 @@ fighter *make_fighter(battle * b, unit * u, side * s1, boolean attack) if (itm->type->rtype->atype) { if (i_canuse(u, itm->type)) { struct armor *adata = malloc(sizeof(armor)), **aptr; - adata->atype = itm->type->rtype->atype; adata->count = itm->number; for (aptr = &fig->armors; *aptr; aptr = &(*aptr)->next) { @@ -3853,7 +3539,6 @@ fighter *make_fighter(battle * b, unit * u, side * s1, boolean attack) } } - /* Jetzt muß noch geschaut werden, wo die Einheit die jeweils besten * Werte hat, das kommt aber erst irgendwo später. Ich entscheide * wärend des Kampfes, welche ich nehme, je nach Gegner. Deswegen auch @@ -3891,7 +3576,6 @@ fighter *make_fighter(battle * b, unit * u, side * s1, boolean attack) for (i = 0; i < fig->alive; i++) { int p_bonus = 0; - int rnd; do { @@ -3913,16 +3597,13 @@ fighter *make_fighter(battle * b, unit * u, side * s1, boolean attack) return fig; } - static int join_battle(battle * b, unit * u, boolean attack, fighter ** cp) { side *s; - fighter *c = NULL; if (!attack) { attrib *a = a_find(u->attribs, &at_fleechance); - if (a != NULL) { if (rng_double() <= a->data.flt) { *cp = NULL; @@ -3933,7 +3614,6 @@ static int join_battle(battle * b, unit * u, boolean attack, fighter ** cp) for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *fig; - if (s->faction == u->faction) { for (fig = s->fighters; fig; fig = fig->next) { if (fig->unit == u) { @@ -3957,14 +3637,10 @@ static int join_battle(battle * b, unit * u, boolean attack, fighter ** cp) static const char *simplename(region * r) { int i; - static char name[17]; - const char *cp = rname(r, default_locale); - for (i = 0; *cp && i != 16; ++i, ++cp) { int c = *(unsigned char *)cp; - while (c && !isalpha(c) && !isxspace(c)) { ++cp; c = *(unsigned char *)cp; @@ -3983,18 +3659,13 @@ static const char *simplename(region * r) static battle *make_battle(region * r) { battle *b = calloc(1, sizeof(struct battle)); - unit *u; - bfaction *bf; - static int max_fac_no = 0; /* need this only once */ if (battledebug) { char zText[MAX_PATH]; - char zFilename[MAX_PATH]; - sprintf(zText, "%s/battles", basepath()); os_mkdir(zText, 0700); sprintf(zFilename, "%s/battle-%d-%s.log", zText, obs_count, simplename(r)); @@ -4034,7 +3705,6 @@ static battle *make_battle(region * r) for (bf = b->factions; bf; bf = bf->next) { faction *f = bf->faction; - max_fac_no = MAX(max_fac_no, f->no); freset(f, FFL_MARK); } @@ -4053,7 +3723,6 @@ static void free_fighter(fighter * fig) } while (fig->armors) { armor *a = fig->armors; - fig->armors = a->next; free(a); } @@ -4065,7 +3734,6 @@ static void free_fighter(fighter * fig) static void free_battle(battle * b) { side *s; - int max_fac_no = 0; if (bdebug) { @@ -4074,9 +3742,7 @@ static void free_battle(battle * b) while (b->factions) { bfaction *bf = b->factions; - faction *f = bf->faction; - b->factions = bf->next; max_fac_no = MAX(max_fac_no, f->no); free(bf); @@ -4084,10 +3750,8 @@ static void free_battle(battle * b) for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *fnext = s->fighters; - while (fnext) { fighter *fig = fnext; - fnext = fig->next; free_fighter(fig); free(fig); @@ -4103,14 +3767,11 @@ static int *get_alive(side * s) { #if 0 static int alive[NUMROWS]; - fighter *fig; - memset(alive, 0, NUMROWS * sizeof(int)); for (fig = s->fighters; fig; fig = fig->next) { if (fig->alive > 0) { int row = statusrow(fig); - alive[row] += fig->alive; } } @@ -4122,11 +3783,8 @@ static int *get_alive(side * s) static int battle_report(battle * b) { side *s, *s2; - boolean cont = false; - boolean komma; - bfaction *bf; for (s = b->sides; s != b->sides + b->nsides; ++s) { @@ -4148,15 +3806,10 @@ static int battle_report(battle * b) for (bf = b->factions; bf; bf = bf->next) { faction *fac = bf->faction; - char buf[32 * MAXSIDES]; - char *bufp = buf; - int bytes; - size_t size = sizeof(buf) - 1; - message *m; message_faction(b, fac, msg_separator); @@ -4172,13 +3825,9 @@ static int battle_report(battle * b) for (s = b->sides; s != b->sides + b->nsides; ++s) { if (s->alive) { int r, k = 0, *alive = get_alive(s); - int l = FIGHT_ROW; - const char *abbrev = seematrix(fac, s) ? sideabkz(s, false) : "-?-"; - const char *loc_army = LOC(fac->locale, "battle_army"); - char buffer[32]; if (komma) { @@ -4230,11 +3879,8 @@ static int battle_report(battle * b) static void join_allies(battle * b) { region *r = b->region; - unit *u; - side *s, *s_end = b->sides + b->nsides; - /* make_side might be adding a new faction, but it adds them to the end * of the list, so we're safe in our iteration here if we remember the end * up front. */ @@ -4243,12 +3889,10 @@ static void join_allies(battle * b) if (u->status != ST_FLEE && u->status != ST_AVOID && !fval(u, UFL_LONGACTION | UFL_ISNEW) && u->number > 0) { faction *f = u->faction; - fighter *c = NULL; for (s = b->sides; s != s_end; ++s) { side *se; - /* Wenn alle attackierten noch FFL_NOAID haben, dann kämpfe nicht mit. */ if (fval(s->faction, FFL_NOAID)) continue; @@ -4285,7 +3929,6 @@ static void join_allies(battle * b) /* Wenn die Einheit belagert ist, muß auch einer der Alliierten belagert sein: */ if (besieged(u)) { fighter *ally; - for (ally = s->fighters; ally; ally = ally->next) { if (besieged(ally->unit)) { break; @@ -4323,20 +3966,15 @@ static void join_allies(battle * b) for (s = b->sides; s != b->sides + b->nsides; ++s) { int si; - side *sa; - faction *f = s->faction; /* Den Feinden meiner Feinde gebe ich Deckung (gegen gemeinsame Feinde): */ for (si = 0; s->enemies[si]; ++si) { side *se = s->enemies[si]; - int ai; - for (ai = 0; se->enemies[ai]; ++ai) { side *as = se->enemies[ai]; - if (as == s || !enemy(as, s)) { set_friendly(as, s); } @@ -4345,7 +3983,6 @@ static void join_allies(battle * b) for (sa = s + 1; sa != b->sides + b->nsides; ++sa) { plane *pl = rplane(r); - if (enemy(s, sa)) continue; if (friendly(s, sa)) @@ -4363,21 +4000,17 @@ static void join_allies(battle * b) static void flee(const troop dt) { fighter *fig = dt.fighter; - unit *u = fig->unit; #ifndef SIMPLE_ESCAPE int carry = personcapacity(u) - u->race->weight; - int money; item **ip = &u->items; while (*ip) { item *itm = *ip; - const item_type *itype = itm->type; - int keep = 0; if (fval(itype, ITF_ANIMAL)) { @@ -4397,7 +4030,6 @@ static void flee(const troop dt) i_add(&fig->run.items, i_remove(ip, itm)); } else { item *run_itm = i_new(itype, keep); - i_add(&fig->run.items, run_itm); i_change(ip, itype, -keep); } @@ -4428,9 +4060,7 @@ static void flee(const troop dt) static boolean init_battle(region * r, battle ** bp) { battle *b = NULL; - unit *u; - boolean fighting = false; /* list_foreach geht nicht, wegen flucht */ @@ -4442,7 +4072,6 @@ static boolean init_battle(region * r, battle ** bp) for (ord = u->orders; ord; ord = ord->next) { static boolean init = false; - static const curse_type *peace_ct, *slave_ct, *calm_ct; if (!init) { @@ -4453,11 +4082,8 @@ static boolean init_battle(region * r, battle ** bp) } if (get_keyword(ord) == K_ATTACK) { unit *u2; - fighter *c1, *c2; - ship *lsh = NULL; - plane *pl = rplane(r); if (pl && fval(pl, PFL_NOATTACK)) { @@ -4544,12 +4170,9 @@ static boolean init_battle(region * r, battle ** bp) if (calm_ct) { attrib *a = a_find(u->attribs, &at_curse); - boolean calm = false; - while (a && a->type == &at_curse) { curse *c = (curse *) a->data.v; - if (c->type == calm_ct && curse_geteffect(c) == u2->faction->subscription) { if (curse_active(c)) { @@ -4567,7 +4190,6 @@ static boolean init_battle(region * r, battle ** bp) /* Ende Fehlerbehandlung */ if (b == NULL) { unit *utmp; - for (utmp = r->units; utmp != NULL; utmp = utmp->next) { fset(utmp->faction, FFL_NOAID); } @@ -4620,29 +4242,22 @@ static void battle_stats(FILE * F, battle * b) int level; int number; } stat_info; - side *s; for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *df; - stat_info *stats = NULL, *stat; for (df = s->fighters; df; df = df->next) { unit *du = df->unit; - troop dt; - stat_info *slast = NULL; dt.fighter = df; for (dt.index = 0; dt.index != du->number; ++dt.index) { weapon *wp = preferred_weapon(dt, true); - int level = wp ? wp->attackskill : 0; - const weapon_type *wtype = wp ? wp->type : NULL; - stat_info **slist = &stats; if (slast && slast->wtype == wtype && slast->level == level) { @@ -4677,7 +4292,6 @@ static void battle_stats(FILE * F, battle * b) } while (stats) { stat_info *stat = stats; - stats = stat->next; free(stat); } @@ -4717,10 +4331,8 @@ static void battle_attacks(battle * b) static void battle_update(battle * b) { side *s; - for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *fig; - for (fig = s->fighters; fig; fig = fig->next) { fig->fighting = fig->alive - fig->removed; } @@ -4739,17 +4351,12 @@ static void battle_flee(battle * b) for (attempt = 1; attempt <= flee_ops; ++attempt) { side *s; - for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *fig; - for (fig = s->fighters; fig; fig = fig->next) { unit *u = fig->unit; - troop dt; - int runners = 0; - /* Flucht nicht bei mehr als 600 HP. Damit Wyrme tötbar bleiben. */ int runhp = MIN(600, (int)(0.9 + unit_max_hp(u) * hpflee(u->status))); @@ -4772,7 +4379,6 @@ static void battle_flee(battle * b) dt.index = fig->alive - fig->removed; while (s->size[SUM_ROW] && dt.index != 0) { double ispaniced = 0.0; - --dt.index; assert(dt.index >= 0 && dt.index < fig->unit->number); assert(fig->person[dt.index].hp > 0); @@ -4820,13 +4426,9 @@ static void battle_flee(battle * b) void do_battle(region * r) { battle *b = NULL; - boolean fighting = false; - ship *sh; - building *bu; - static int init_rules = 0; if (!init_rules) { @@ -4849,7 +4451,6 @@ void do_battle(region * r) if (!fighting) { /* Niemand mehr da, Kampf kann nicht stattfinden. */ message *m = msg_message("battle::aborted", ""); - message_all(b, m); msg_release(m); free_battle(b); diff --git a/src/kernel/battle.h b/src/kernel/battle.h index 69299e9dd..46cd3c4ce 100644 --- a/src/kernel/battle.h +++ b/src/kernel/battle.h @@ -212,7 +212,6 @@ extern "C" { #endif } fighter; - /* schilde */ enum { diff --git a/src/kernel/binarystore.c b/src/kernel/binarystore.c index 78b4408e8..f74882fe7 100644 --- a/src/kernel/binarystore.c +++ b/src/kernel/binarystore.c @@ -82,16 +82,13 @@ static int bin_w_brk(struct storage *store) static int bin_w_int_pak(struct storage *store, int arg) { char buffer[5]; - size_t size = pack_int(arg, buffer); - return (int)fwrite(buffer, sizeof(char), size, file(store)); } static int bin_r_int_pak(struct storage *store) { int v = 0; - char ch; fread(&ch, sizeof(char), 1, file(store)); @@ -115,7 +112,6 @@ static int bin_w_int(struct storage *store, int arg) static int bin_r_int(struct storage *store) { int result; - fread(&result, sizeof(result), 1, file(store)); return result; } @@ -128,7 +124,6 @@ static int bin_w_flt(struct storage *store, float arg) static float bin_r_flt(struct storage *store) { float result; - fread(&result, sizeof(result), 1, file(store)); return result; } @@ -136,12 +131,10 @@ static float bin_r_flt(struct storage *store) static int bin_w_str(struct storage *store, const char *tok) { int result; - if (tok == NULL || tok[0] == 0) { result = store->w_int(store, 0); } else { int size = (int)strlen(tok); - result = store->w_int(store, size); result += (int)fwrite(tok, size, 1, file(store)); } @@ -162,7 +155,6 @@ static char *bin_r_str(struct storage *store) #ifdef FIX_INVALID_CHARS { char *p = strpbrk(result, "\n\r"); - while (p) { log_error(("Invalid character %d in input string \"%s\".\n", *p, result)); @@ -181,7 +173,6 @@ static char *bin_r_str(struct storage *store) static void bin_r_str_buf(struct storage *store, char *result, size_t size) { int i; - size_t rd, len; i = store->r_int(store); @@ -201,7 +192,6 @@ static void bin_r_str_buf(struct storage *store, char *result, size_t size) #ifdef FIX_INVALID_CHARS { char *p = strpbrk(result, "\n\r"); - while (p) { log_error(("Invalid character %d in input string \"%s\".\n", *p, result)); @@ -216,7 +206,6 @@ static void bin_r_str_buf(struct storage *store, char *result, size_t size) static int bin_w_bin(struct storage *store, void *arg, size_t size) { int result; - int len = (int)size; result = store->w_int(store, len); @@ -229,7 +218,6 @@ static int bin_w_bin(struct storage *store, void *arg, size_t size) static void bin_r_bin(struct storage *store, void *result, size_t size) { int len = store->r_int(store); - if (len > 0) { if ((size_t) len > size) { log_error(("destination buffer too small %d %u.\n", len, size)); @@ -240,18 +228,15 @@ static void bin_r_bin(struct storage *store, void *result, size_t size) } } - static int bin_open(struct storage *store, const char *filename, int mode) { const char *modes[] = { 0, "rb", "wb", "ab" }; FILE *F = fopen(filename, modes[mode]); - store->userdata = F; store->encoding = XML_CHAR_ENCODING_UTF8; /* always utf8 it is */ if (F) { if (mode == IO_READ) { int stream_version = 0; - store->version = bin_r_int(store); if (store->version >= INTPAK_VERSION) { stream_version = bin_r_int(store); diff --git a/src/kernel/build.c b/src/kernel/build.c index ce6ab7d4e..7ae38fe48 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -69,11 +69,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* Name, MaxGroesse, MinBauTalent, Kapazitaet, {Eisen, Holz, Stein, BauSilber, * Laen, Mallorn}, UnterSilber, UnterSpezialTyp, UnterSpezial */ - static boolean CheckOverload(void) { static int value = -1; - if (value < 0) { value = get_param_int(global.parameters, "rules.check_overload", 0); } @@ -87,7 +85,6 @@ static boolean CheckOverload(void) static int slipthru(const region * r, const unit * u, const building * b) { unit *u2; - int n, o; /* b ist die burg, in die man hinein oder aus der man heraus will. */ @@ -137,7 +134,6 @@ boolean can_contact(const region * r, const unit * u, const unit * u2) return false; } - static void contact_cmd(unit * u, order * ord, boolean tries) { /* unit u kontaktiert unit u2. Dies setzt den contact einfach auf 1 - @@ -146,7 +142,6 @@ static void contact_cmd(unit * u, order * ord, boolean tries) * weitergegeben wird. dies wird fuer das auffinden von tempunits in * getnewunit () verwendet! */ unit *u2; - region *r = u->region; init_tokens(ord); @@ -167,13 +162,11 @@ static void contact_cmd(unit * u, order * ord, boolean tries) /* ------------------------------------------------------------- */ - /* ------------------------------------------------------------- */ struct building *getbuilding(const struct region *r) { building *b = findbuilding(getid()); - if (b == NULL || r != b->region) return NULL; return b; @@ -182,7 +175,6 @@ struct building *getbuilding(const struct region *r) ship *getship(const struct region * r) { ship *sh, *sx = findship(getshipid()); - for (sh = r->ships; sh; sh = sh->next) { if (sh == sx) return sh; @@ -195,21 +187,13 @@ ship *getship(const struct region * r) static void siege_cmd(unit * u, order * ord) { region *r = u->region; - building *b; - int d, pooled; - int bewaffnete, katapultiere = 0; - static boolean init = false; - static const curse_type *magicwalls_ct; - static item_type *it_catapultammo = NULL; - static item_type *it_catapult = NULL; - if (!init) { init = true; magicwalls_ct = ct_find("magicwalls"); @@ -301,11 +285,8 @@ void do_siege(region * r) static void destroy_road(unit * u, int nmax, struct order *ord) { direction_t d = getdirection(u->faction->locale); - unit *u2; - region *r = u->region; - short n = (short)nmax; if (nmax > SHRT_MAX) @@ -327,13 +308,10 @@ static void destroy_road(unit * u, int nmax, struct order *ord) cmistake(u, ord, 71, MSG_PRODUCE); } else { short road = rroad(r, d); - n = MIN(n, road); if (n != 0) { region *r2 = rconnect(r, d); - int willdo = eff_skill(u, SK_ROAD_BUILDING, r) * u->number; - willdo = MIN(willdo, n); if (willdo == 0) { /* TODO: error message */ @@ -352,17 +330,11 @@ static void destroy_road(unit * u, int nmax, struct order *ord) int destroy_cmd(unit * u, struct order *ord) { ship *sh; - unit *u2; - region *r = u->region; - const construction *con = NULL; - int size = 0; - const char *s; - int n = INT_MAX; if (u->number < 1) @@ -456,12 +428,9 @@ int destroy_cmd(unit * u, struct order *ord) if (con) { /* TODO: Nicht an ZERSTÖRE mit Punktangabe angepaßt! */ int c; - for (c = 0; con->materials[c].number; ++c) { const requirement *rq = con->materials + c; - int recycle = (int)(rq->recycle * rq->number * size / con->reqsize); - if (recycle) { change_resource(u, rq->rtype, recycle); } @@ -475,7 +444,6 @@ int destroy_cmd(unit * u, struct order *ord) void build_road(region * r, unit * u, int size, direction_t d) { int n, left; - region *rn = rconnect(r, d); assert(u->number); @@ -501,7 +469,6 @@ void build_road(region * r, unit * u, int size, direction_t d) if (r->terrain == newterrain(T_SWAMP)) { /* wenn kein Damm existiert */ static const struct building_type *bt_dam; - if (!bt_dam) bt_dam = bt_find("dam"); assert(bt_dam); @@ -511,7 +478,6 @@ void build_road(region * r, unit * u, int size, direction_t d) } } else if (r->terrain == newterrain(T_DESERT)) { static const struct building_type *bt_caravan; - if (!bt_caravan) bt_caravan = bt_find("caravan"); assert(bt_caravan); @@ -522,7 +488,6 @@ void build_road(region * r, unit * u, int size, direction_t d) } } else if (r->terrain == newterrain(T_GLACIER)) { static const struct building_type *bt_tunnel; - if (!bt_tunnel) bt_tunnel = bt_find("tunnel"); assert(bt_tunnel); @@ -561,21 +526,16 @@ void build_road(region * r, unit * u, int size, direction_t d) n = u->number * eff_skill(u, SK_ROAD_BUILDING, r); if (n < left) { item *itm = *i_find(&u->items, olditemtype[I_RING_OF_NIMBLEFINGER]); - if (itm != NULL && itm->number > 0) { int rings = MIN(u->number, itm->number); - n = n * ((roqf_factor() - 1) * rings + u->number) / u->number; } } if (n < left) { int dm = get_effect(u, oldpotiontype[P_DOMORE]); - if (dm != 0) { int sk = eff_skill(u, SK_ROAD_BUILDING, r); - int todo = (left - n + sk - 1) / sk; - todo = MIN(todo, u->number); dm = MIN(dm, todo); change_effect(u, oldpotiontype[P_DOMORE], -dm); @@ -593,7 +553,6 @@ void build_road(region * r, unit * u, int size, direction_t d) if (u->race == new_race[RC_STONEGOLEM]) { int golemsused = n / GOLEM_STONE; - if (n % GOLEM_STONE != 0) { ++golemsused; } @@ -632,7 +591,6 @@ matmod(const attrib * a, const unit * u, const resource_type * material, for (a = a_find((attrib *) a, &at_matmod); a && a->type == &at_matmod; a = a->next) { mm_fun fun = (mm_fun) a->data.f; - value = fun(u, material, value); if (value < 0) return value; /* pass errors to caller */ @@ -643,7 +601,6 @@ matmod(const attrib * a, const unit * u, const resource_type * material, int roqf_factor(void) { int value = -1; - if (value < 0) { value = get_param_int(global.parameters, "rules.economy.roqf", 10); } @@ -658,11 +615,8 @@ int roqf_factor(void) int build(unit * u, const construction * ctype, int completed, int want) { const construction *type = ctype; - int skills = INT_MAX; /* number of skill points remainig */ - int basesk = 0; - int made = 0; if (want <= 0) @@ -673,7 +627,6 @@ int build(unit * u, const construction * ctype, int completed, int want) return ECOMPLETE; if (type->btype != NULL) { building *b; - if (!u->building || u->building->type != type->btype) { return EBUILDINGREQ; } @@ -684,7 +637,6 @@ int build(unit * u, const construction * ctype, int completed, int want) if (type->skill != NOSKILL) { int effsk; - int dm = get_effect(u, oldpotiontype[P_DOMORE]); assert(u->number); @@ -764,14 +716,11 @@ int build(unit * u, const construction * ctype, int completed, int want) * Talente */ if (skill_limit(u->faction, type->skill) == INT_MAX) { int i = 0; - item *itm = *i_find(&u->items, olditemtype[I_RING_OF_NIMBLEFINGER]); - if (itm != NULL) i = itm->number; if (i > 0) { int rings = MIN(u->number, i); - n = n * ((roqf_factor() - 1) * rings + u->number) / u->number; } } @@ -790,9 +739,7 @@ int build(unit * u, const construction * ctype, int completed, int want) if (type->materials) for (c = 0; n > 0 && type->materials[c].number; c++) { const struct resource_type *rtype = type->materials[c].rtype; - int need, prebuilt; - int canuse = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); if (inside_building(u)) { @@ -814,7 +761,6 @@ int build(unit * u, const construction * ctype, int completed, int want) } } else { int maxn = canuse / type->materials[c].number; - if (maxn < n) n = maxn; } @@ -828,15 +774,12 @@ int build(unit * u, const construction * ctype, int completed, int want) if (type->materials) for (c = 0; type->materials[c].number; c++) { const struct resource_type *rtype = type->materials[c].rtype; - int prebuilt = required(completed, type->reqsize, type->materials[c].number); int need = required(completed + n, type->reqsize, type->materials[c].number); int multi = 1; - int canuse = 100; /* normalization */ - if (inside_building(u)) canuse = matmod(u->building->type->attribs, u, rtype, canuse); if (canuse < 0) @@ -867,7 +810,6 @@ message *msg_materials_required(unit * u, order * ord, const construction * ctype, int multi) { int c; - /* something missing from the list of materials */ resource *reslist = NULL; @@ -875,7 +817,6 @@ message *msg_materials_required(unit * u, order * ord, multi = 1; for (c = 0; ctype->materials[c].number; ++c) { resource *res = malloc(sizeof(resource)); - res->number = multi * ctype->materials[c].number / ctype->reqsize; res->type = ctype->materials[c].rtype; res->next = reslist; @@ -889,16 +830,11 @@ int maxbuild(const unit * u, const construction * cons) /* !! ignores maximum objectsize and improvements... */ { int c; - int maximum = INT_MAX; - for (c = 0; cons->materials[c].number; c++) { const resource_type *rtype = cons->materials[c].rtype; - int have = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); - int need = required(1, cons->reqsize, cons->materials[c].number); - if (have < need) { return 0; } else @@ -913,20 +849,13 @@ void build_building(unit * u, const building_type * btype, int want, order * ord) { region *r = u->region; - boolean newbuilding = false; - int n = want, built = 0, id; - building *b = NULL; - /* einmalige Korrektur */ const char *btname; - order *new_order = NULL; - const struct locale *lang = u->faction->locale; - static int rule_other = -1; assert(u->number); @@ -995,7 +924,6 @@ build_building(unit * u, const building_type * btype, int want, order * ord) } if (!rule_other) { unit *owner = building_owner(b); - if (!owner || owner->faction != u->faction) { cmistake(u, ord, 1222, MSG_PRODUCE); return; @@ -1038,7 +966,6 @@ build_building(unit * u, const building_type * btype, int want, order * ord) return; } - /* at this point, the building size is increased. */ if (b == NULL) { /* build a new building */ @@ -1054,7 +981,6 @@ build_building(unit * u, const building_type * btype, int want, order * ord) #ifdef WDW_PYRAMID if (b->type == bt_find("pyramid") && f_get_alliance(u->faction) != NULL) { attrib *a = a_add(&b->attribs, a_new(&at_alliance)); - a->data.i = u->faction->alliance->id; } #endif @@ -1070,7 +996,6 @@ build_building(unit * u, const building_type * btype, int want, order * ord) } else if (want != INT_MAX) { /* reduzierte restgröße */ const char *hasspace = strchr(btname, ' '); - if (hasspace) { new_order = create_order(K_MAKE, lang, "%d \"%s\" %i", n - built, btname, b->no); @@ -1081,7 +1006,6 @@ build_building(unit * u, const building_type * btype, int want, order * ord) } else if (btname) { /* Neues Haus, Befehl mit Gebäudename */ const char *hasspace = strchr(btname, ' '); - if (hasspace) { new_order = create_order(K_MAKE, lang, "\"%s\" %i", btname, b->no); } else { @@ -1099,7 +1023,6 @@ build_building(unit * u, const building_type * btype, int want, order * ord) update_lighthouse(b); - ADDMSG(&u->faction->msgs, msg_message("buildbuilding", "building unit size", b, u, built)); } @@ -1107,11 +1030,8 @@ build_building(unit * u, const building_type * btype, int want, order * ord) static void build_ship(unit * u, ship * sh, int want) { const construction *construction = sh->type->construction; - int size = (sh->size * DAMAGE_SCALE - sh->damage) / DAMAGE_SCALE; - int n; - int can = build(u, construction, size, want); if ((n = construction->maxsize - sh->size) > 0 && can > 0) { @@ -1127,7 +1047,6 @@ static void build_ship(unit * u, ship * sh, int want) if (sh->damage && can) { int repair = MIN(sh->damage, can * DAMAGE_SCALE); - n += repair / DAMAGE_SCALE; if (repair % DAMAGE_SCALE) ++n; @@ -1144,11 +1063,8 @@ create_ship(region * r, unit * u, const struct ship_type *newtype, int want, order * ord) { ship *sh; - int msize; - const construction *cons = newtype->construction; - order *new_order; if (!eff_skill(u, SK_SHIPBUILDING, r)) { @@ -1198,9 +1114,7 @@ create_ship(region * r, unit * u, const struct ship_type *newtype, int want, void continue_ship(region * r, unit * u, int want) { const construction *cons; - ship *sh; - int msize; if (!eff_skill(u, SK_SHIPBUILDING, r)) { @@ -1248,7 +1162,6 @@ void continue_ship(region * r, unit * u, int want) static boolean mayenter(region * r, unit * u, building * b) { unit *u2; - if (fval(b, BLD_UNGUARDED)) return true; u2 = building_owner(b); @@ -1298,7 +1211,6 @@ int leave_cmd(unit * u, struct order *ord) static boolean enter_ship(unit * u, struct order *ord, int id, boolean report) { region *r = u->region; - ship *sh; /* Muß abgefangen werden, sonst könnten Schwimmer an @@ -1324,9 +1236,7 @@ static boolean enter_ship(unit * u, struct order *ord, int id, boolean report) } if (CheckOverload()) { int sweight, scabins; - int mweight = shipcapacity(sh); - int mcabins = sh->type->cabins; if (mweight > 0) { @@ -1334,7 +1244,6 @@ static boolean enter_ship(unit * u, struct order *ord, int id, boolean report) sweight += weight(u); if (mcabins) { int pweight = u->number * u->race->weight; - /* weight goes into number of cabins, not cargo */ scabins += pweight; sweight -= pweight; @@ -1362,7 +1271,6 @@ static boolean enter_ship(unit * u, struct order *ord, int id, boolean report) static boolean enter_building(unit * u, order * ord, int id, boolean report) { region *r = u->region; - building *b; /* Schwimmer können keine Gebäude betreten, außer diese sind @@ -1415,7 +1323,6 @@ void do_misc(region * r, boolean lasttry) for (uc = r->units; uc; uc = uc->next) { order *ord; - for (ord = uc->orders; ord; ord = ord->next) { switch (get_keyword(ord)) { case K_CONTACT: @@ -1427,17 +1334,13 @@ void do_misc(region * r, boolean lasttry) for (uptr = &r->units; *uptr;) { unit *u = *uptr; - order **ordp = &u->orders; while (*ordp) { order *ord = *ordp; - if (get_keyword(ord) == K_ENTER) { param_t p; - int id; - unit *ulast = NULL; init_tokens(ord); @@ -1452,7 +1355,6 @@ void do_misc(region * r, boolean lasttry) break; if (enter_building(u, ord, id, lasttry)) { unit *ub; - for (ub = u; ub; ub = ub->next) { if (ub->building == u->building) { ulast = ub; @@ -1466,7 +1368,6 @@ void do_misc(region * r, boolean lasttry) break; if (enter_ship(u, ord, id, lasttry)) { unit *ub; - ulast = u; for (ub = u; ub; ub = ub->next) { if (ub->ship == u->ship) { diff --git a/src/kernel/building.c b/src/kernel/building.c index 2c4f3ed0a..972fe2179 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -62,7 +62,6 @@ static void lc_init(struct attrib *a) static void lc_done(struct attrib *a) { building_action *data = (building_action *) a->data.v; - if (data->fname) free(data->fname); if (data->param) @@ -74,11 +73,8 @@ 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; - const char *fparam = data->param; - building *b = data->b; write_building_reference(b, store); @@ -89,7 +85,6 @@ lc_write(const struct attrib *a, const void *owner, struct storage *store) static int lc_read(struct attrib *a, void *owner, struct storage *store) { building_action *data = (building_action *) a->data.v; - int result = read_reference(&data->b, store, read_building_reference, resolve_building); if (store->version < UNICODE_VERSION) { @@ -99,7 +94,6 @@ static int lc_read(struct attrib *a, void *owner, struct storage *store) } if (store->version >= BACTION_VERSION) { char lbuf[256]; - if (store->version < UNICODE_VERSION) { store->r_str_buf(store, lbuf, sizeof(lbuf)); } else { @@ -135,7 +129,6 @@ static building_typelist *buildingtypes; building_type *bt_find(const char *name) { const struct building_typelist *btl = buildingtypes; - assert(name); while (btl && strcmp(btl->type->_name, name)) btl = btl->next; @@ -148,7 +141,6 @@ building_type *bt_find(const char *name) void bt_register(building_type * type) { struct building_typelist *btl = malloc(sizeof(building_type)); - if (type->init) type->init(type); btl->type = type; @@ -181,9 +173,7 @@ const char *buildingtype(const building_type * btype, const building * b, int bsize) { const char *s = NULL; - static boolean init_generic = false; - static const struct building_type *bt_generic; if (!init_generic) { @@ -193,7 +183,6 @@ const char *buildingtype(const building_type * btype, const building * b, if (btype == bt_generic) { const attrib *a = a_find(b->attribs, &at_building_generic_type); - if (a) s = (const char *)a->data.v; } @@ -207,7 +196,6 @@ const char *buildingtype(const building_type * btype, const building * b, #define BMAXHASH 7919 static building *buildhash[BMAXHASH]; - void bhash(building * b) { building *old = buildhash[b->no % BMAXHASH]; @@ -248,7 +236,6 @@ building *findbuilding(int i) /* ** old building types ** */ - static int sm_smithy(const unit * u, const region * r, skill_t sk, int value) { /* skillmod */ if (sk == SK_WEAPONSMITH || sk == SK_ARMORER) { @@ -325,9 +312,7 @@ static const char *fort_name(const struct building_type *btype, static const char *pyramid_name(const struct building_type *btype, int bsize) { static char p_name_buf[32]; - int level = 0; - const construction *ctype; ctype = btype->construction; @@ -346,9 +331,7 @@ static const char *pyramid_name(const struct building_type *btype, int bsize) int wdw_pyramid_level(const struct building *b) { const construction *ctype = b->type->construction; - int completed = b->size; - int level = 0; while (ctype->improvement != NULL && @@ -371,7 +354,6 @@ const building_type *findbuildingtype(const char *name, const struct locale *lang) { variant type; - local_names *bn = bnames; while (bn) { @@ -381,13 +363,11 @@ const building_type *findbuildingtype(const char *name, } if (!bn) { struct building_typelist *btl = buildingtypes; - bn = calloc(sizeof(local_names), 1); bn->next = bnames; bn->lang = lang; while (btl) { const char *n = locale_string(lang, btl->type->_name); - type.v = (void *)btl->type; addtoken(&bn->names, n, type); btl = btl->next; @@ -402,7 +382,6 @@ const building_type *findbuildingtype(const char *name, static int eressea_building_protection(building * b, unit * u) { int beff = buildingeffsize(b, false) - 1; - /* -1 because the tradepost has no protection value */ return beff; @@ -426,13 +405,10 @@ void write_building_reference(const struct building *b, struct storage *store) store->w_id(store, (b && b->region) ? b->no : 0); } - int resolve_building(variant id, void *address) { int result = 0; - building *b = NULL; - if (id.i != 0) { b = findbuilding(id.i); if (b == NULL) { @@ -446,7 +422,6 @@ int resolve_building(variant id, void *address) variant read_building_reference(struct storage * store) { variant result; - result.i = store->r_id(store); return result; } @@ -455,11 +430,8 @@ building *new_building(const struct building_type * btype, region * r, const struct locale * lang) { building **bptr = &r->buildings; - building *b = (building *) calloc(1, sizeof(building)); - static boolean init_lighthouse = false; - static const struct building_type *bt_lighthouse = 0; if (!init_lighthouse) { @@ -482,7 +454,6 @@ building *new_building(const struct building_type * btype, region * r, } { const char *bname; - if (b->type->name == NULL) { bname = LOC(lang, btype->_name); } else { @@ -501,11 +472,8 @@ static building *deleted_buildings; void remove_building(building ** blist, building * b) { unit *u; - direction_t d; - static const struct building_type *bt_caravan, *bt_dam, *bt_tunnel; - static boolean init = false; if (!init) { @@ -531,7 +499,6 @@ void remove_building(building ** blist, building * b) * gebaute Straße zur Hälfte vernichtet */ if (b->type == bt_caravan || b->type == bt_dam || b->type == bt_tunnel) { region *r = b->region; - for (d = 0; d != MAXDIRECTIONS; ++d) if (rroad(r, d) > 0) { rsetroad(r, d, rroad(r, d) / 2); @@ -560,7 +527,6 @@ void free_buildings(void) { while (deleted_buildings) { building *b = deleted_buildings; - deleted_buildings = b->next; } } @@ -580,7 +546,6 @@ int buildingeffsize(const building * b, boolean img) btype = b->type; if (img) { const attrib *a = a_find(b->attribs, &at_icastle); - if (a) { btype = (const struct building_type *)a->data.v; } @@ -591,14 +556,12 @@ int buildingeffsize(const building * b, boolean img) int bt_effsize(const building_type * btype, const building * b, int bsize) { int i = bsize, n = 0; - const construction *cons = btype->construction; /* TECH DEBT: simplest thing that works for E3 dwarf/halfling faction rules */ if (b && get_param_int(global.parameters, "rules.dwarf_castles", 1) && strcmp(btype->_name, "castle") == 0) { unit *u = building_owner(b); - if (u && u->faction->race == new_race[RC_HALFLING]) { i = bsize * 10 / 8; } @@ -627,24 +590,17 @@ const char *write_buildingname(const building * b, char *ibuf, size_t size) const char *buildingname(const building * b) { typedef char name[OBJECTIDSIZE + 1]; - static name idbuf[8]; - static int nextbuf = 0; - char *ibuf = idbuf[(++nextbuf) % 8]; - return write_buildingname(b, ibuf, sizeof(name)); } unit *building_owner(const building * b) { unit *u = NULL; - unit *first = NULL; - region *r = b->region; - /* Prüfen ob Eigentümer am leben. */ for (u = r->units; u; u = u->next) { @@ -684,9 +640,7 @@ void building_setname(building * self, const char *name) void building_addaction(building * b, const char *fname, const char *param) { attrib *a = a_add(&b->attribs, a_new(&at_building_action)); - building_action *data = (building_action *) a->data.v; - data->b = b; data->fname = strdup(fname); if (param) { @@ -702,7 +656,6 @@ region *building_getregion(const building * b) void building_setregion(building * b, region * r) { building **blist = &b->region->buildings; - while (*blist && *blist != b) { blist = &(*blist)->next; } diff --git a/src/kernel/calendar.c b/src/kernel/calendar.c index 86f3a7129..5a09ff738 100644 --- a/src/kernel/calendar.c +++ b/src/kernel/calendar.c @@ -4,31 +4,20 @@ #include int first_turn = 0; - int first_month = 0; - int weeks_per_month = 0; - int months_per_year = 0; - char **seasonnames = NULL; - char **weeknames = NULL; - char **weeknames2 = NULL; - char **monthnames = NULL; - int *month_season = NULL; - char *agename = NULL; - int seasons = 0; const gamedate *get_gamedate(int turn, gamedate * gd) { int weeks_per_year = months_per_year * weeks_per_month; - int t = turn - first_turn; assert(gd); diff --git a/src/kernel/calendar.h b/src/kernel/calendar.h index 21d947339..6085627fa 100644 --- a/src/kernel/calendar.h +++ b/src/kernel/calendar.h @@ -12,7 +12,6 @@ extern "C" { SEASON_AUTUMN }; - extern char *agename; extern int first_turn; extern int first_month; diff --git a/src/kernel/command.c b/src/kernel/command.c index 52883b945..b03d6679c 100644 --- a/src/kernel/command.c +++ b/src/kernel/command.c @@ -45,12 +45,9 @@ tnode *stree_find(const syntaxtree * stree, const struct locale *lang) syntaxtree *stree_create(void) { syntaxtree *sroot = NULL; - const struct locale *lang = locales; - while (lang) { syntaxtree *stree = (syntaxtree *) malloc(sizeof(syntaxtree)); - stree->lang = lang; stree->next = sroot; sroot = stree; @@ -64,7 +61,6 @@ add_command(struct tnode *keys, struct tnode *tnext, const char *str, parser fun) { command *cmd = (command *) malloc(sizeof(command)); - variant var; cmd->fun = fun; @@ -76,13 +72,11 @@ add_command(struct tnode *keys, struct tnode *tnext, static int do_command_i(const struct tnode *keys, void *u, struct order *ord) { const char *c; - variant var; c = getstrtoken(); if (findtoken(keys, c, &var) == E_TOK_SUCCESS) { command *cmd = (command *) var.v; - if (cmd->nodes && *c) { assert(!cmd->fun); return do_command_i(cmd->nodes, u, ord); @@ -100,7 +94,6 @@ void do_command(const struct tnode *keys, void *u, struct order *ord) skip_token(); if (do_command_i(keys, u, ord) != E_TOK_SUCCESS) { char *cmd = getcommand(ord); - log_warning(("%s failed command '%s'\n", unitname(u), cmd)); free(cmd); } diff --git a/src/kernel/config.c b/src/kernel/config.c index 2d9342843..2962b9a7f 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -91,15 +91,10 @@ struct settings global = { }; FILE *logfile; - FILE *updatelog; - const struct race *new_race[MAXRACES]; - boolean sqlpatch = false; - boolean battledebug = false; - int turn = 0; #if XECMD_MODULE @@ -117,12 +112,9 @@ attrib_type at_xontormiaexpress = { int NewbieImmunity(void) { static int value = -1; - static int gamecookie = -1; - if (value < 0 || gamecookie != global.cookie) { gamecookie = global.cookie; - value = get_param_int(global.parameters, "NewbieImmunity", 0); } return value; @@ -136,12 +128,9 @@ boolean IsImmune(const faction * f) static int MaxAge(void) { static int value = -1; - static int gamecookie = -1; - if (value < 0 || gamecookie != global.cookie) { gamecookie = global.cookie; - value = get_param_int(global.parameters, "MaxAge", 0); } return value; @@ -167,12 +156,9 @@ static int ally_flag(const char *s, int help_mask) boolean ExpensiveMigrants(void) { static int value = -1; - static int gamecookie = -1; - if (value < 0 || gamecookie != global.cookie) { gamecookie = global.cookie; - value = get_param_int(global.parameters, "study.expensivemigrants", 0); } return value; @@ -185,20 +171,14 @@ boolean ExpensiveMigrants(void) int AllianceAuto(void) { static int value = -1; - static int gamecookie = -1; - if (value < 0 || gamecookie != global.cookie) { const char *str = get_param(global.parameters, "alliance.auto"); - gamecookie = global.cookie; - value = 0; if (str != NULL) { char *sstr = strdup(str); - char *tok = strtok(sstr, " "); - while (tok) { value |= ally_flag(tok, -1); tok = strtok(NULL, " "); @@ -218,20 +198,14 @@ int AllianceAuto(void) int HelpMask(void) { static int rule = -1; - static int gamecookie = -1; - if (rule < 0 || gamecookie != global.cookie) { const char *str = get_param(global.parameters, "rules.help.mask"); - gamecookie = global.cookie; - rule = 0; if (str != NULL) { char *sstr = strdup(str); - char *tok = strtok(sstr, " "); - while (tok) { rule |= ally_flag(tok, -1); tok = strtok(NULL, " "); @@ -247,20 +221,14 @@ int HelpMask(void) int AllianceRestricted(void) { static int rule = -1; - static int gamecookie = -1; - if (rule < 0 || gamecookie != global.cookie) { const char *str = get_param(global.parameters, "alliance.restricted"); - gamecookie = global.cookie; - rule = 0; if (str != NULL) { char *sstr = strdup(str); - char *tok = strtok(sstr, " "); - while (tok) { rule |= ally_flag(tok, -1); tok = strtok(NULL, " "); @@ -275,9 +243,7 @@ int AllianceRestricted(void) int LongHunger(const struct unit *u) { static int gamecookie = -1; - static int rule = -1; - if (u != NULL) { if (!fval(u, UFL_HUNGER)) return false; @@ -288,7 +254,6 @@ int LongHunger(const struct unit *u) } if (rule < 0 || gamecookie != global.cookie) { gamecookie = global.cookie; - rule = get_param_int(global.parameters, "hunger.long", 0); } return rule; @@ -297,14 +262,11 @@ int LongHunger(const struct unit *u) int SkillCap(skill_t sk) { static int gamecookie = -1; - static int rule = -1; - if (sk == SK_MAGIC) return 0; /* no caps on magic */ if (rule < 0 || gamecookie != global.cookie) { gamecookie = global.cookie; - rule = get_param_int(global.parameters, "skill.maxlevel", 0); } return rule; @@ -313,12 +275,9 @@ int SkillCap(skill_t sk) int NMRTimeout(void) { static int gamecookie = -1; - static int rule = -1; - if (rule < 0 || gamecookie != global.cookie) { gamecookie = global.cookie; - rule = get_param_int(global.parameters, "nmr.timeout", 0); } return rule; @@ -327,7 +286,6 @@ int NMRTimeout(void) race_t old_race(const struct race * rc) { race_t i; - for (i = 0; i != MAXRACES; ++i) { if (new_race[i] == rc) return i; @@ -371,7 +329,6 @@ const char *directions[MAXDIRECTIONS + 2] = { const char *dbrace(const struct race *rc) { static char zText[32]; - char *zPtr = zText; /* the english names are all in ASCII, so we don't need to worry about UTF8 */ @@ -436,7 +393,6 @@ const char *parameters[MAXPARAMS] = { "ALLIANZ" }; - const char *keywords[MAXKEYWORDS] = { "//", "BANNER", @@ -550,16 +506,12 @@ const char *options[MAXOPTIONS] = { static int allied_skillcount(const faction * f, skill_t sk) { int num = 0; - alliance *a = f_get_alliance(f); - quicklist *members = a->members; - int qi; for (qi = 0; members; ql_advance(&members, &qi, 1)) { faction *m = (faction *) ql_get(members, qi); - num += count_skill(m, sk); } return num; @@ -568,7 +520,6 @@ static int allied_skillcount(const faction * f, skill_t sk) static int allied_skilllimit(const faction * f, skill_t sk) { static int value = -1; - if (value < 0) { value = get_param_int(global.parameters, "alliance.skilllimit", 0); } @@ -595,7 +546,6 @@ static void init_npcfaction(struct attrib *a) a->data.i = 1; } - static attrib_type at_npcfaction = { "npcfaction", init_npcfaction, @@ -623,20 +573,15 @@ int max_magicians(const faction * f) int skill_limit(faction * f, skill_t sk) { int m = INT_MAX; - int al = allied_skilllimit(f, sk); - if (al > 0) { if (sk != SK_ALCHEMY && sk != SK_MAGIC) return INT_MAX; if (f_get_alliance(f)) { int ac = listlen(f->alliance->members); /* number of factions */ - int fl = (al + ac - 1) / ac; /* faction limit, rounded up */ - /* the faction limit may not be achievable because it would break the alliance-limit */ int sc = al - allied_skillcount(f, sk); - if (sc <= 0) return 0; return fl; @@ -658,7 +603,6 @@ int skill_limit(faction * f, skill_t sk) int count_skill(faction * f, skill_t sk) { int n = 0; - unit *u; for (u = f->units; u; u = u->nextF) { @@ -677,18 +621,14 @@ FILE *debug; static int ShipSpeedBonus(const unit * u) { static int level = -1; - if (level == -1) { level = get_param_int(global.parameters, "movement.shipspeed.skillbonus", 0); } if (level > 0) { ship *sh = u->ship; - int skl = effskill(u, SK_SAILING); - int minsk = (sh->type->cptskill + 1) / 2; - return (skl - minsk) / level; } return 0; @@ -697,13 +637,9 @@ static int ShipSpeedBonus(const unit * u) int shipspeed(const ship * sh, const unit * u) { double k = sh->type->range; - static const curse_type *stormwind_ct, *nodrift_ct; - static boolean init; - attrib *a; - curse *c; if (!init) { @@ -763,7 +699,6 @@ faction *factionhash[FMAXHASH]; void fhash(faction * f) { int index = f->no % FMAXHASH; - f->nexthash = factionhash[index]; factionhash[index] = f; } @@ -771,9 +706,7 @@ void fhash(faction * f) void funhash(faction * f) { int index = f->no % FMAXHASH; - faction **fp = factionhash + index; - while (*fp && (*fp) != f) fp = &(*fp)->nexthash; *fp = f->nexthash; @@ -782,9 +715,7 @@ void funhash(faction * f) static faction *ffindhash(int no) { int index = no % FMAXHASH; - faction *f = factionhash[index]; - while (f && f->no != no) f = f->nexthash; return f; @@ -796,11 +727,8 @@ void verify_data(void) { #ifndef NDEBUG int lf = -1; - faction *f; - unit *u; - int mage, alchemist; if (verbosity >= 1) @@ -834,9 +762,7 @@ void verify_data(void) int distribute(int old, int new_value, int n) { int i; - int t; - assert(new_value <= old); if (old == 0) @@ -885,7 +811,6 @@ region *findunitregion(const unit * su) return su->region; #else region *r; - const unit *u; for (r = regions; r; r = r->next) { @@ -918,7 +843,6 @@ int eff_stealth(const unit * u, const region * r) if (fval(u, UFL_STEALTH)) { int es = u_geteffstealth(u); - if (es >= 0 && es < e) return es; } @@ -929,7 +853,6 @@ int eff_stealth(const unit * u, const region * r) boolean unit_has_cursed_item(unit * u) { item *itm = u->items; - while (itm) { if (fval(itm->type, ITF_CURSED) && itm->number > 0) return true; @@ -954,7 +877,6 @@ static int autoalliance(const plane * pl, const faction * sf, const faction * f2) { static boolean init = false; - if (!init) { init_gms(); init = true; @@ -967,7 +889,6 @@ autoalliance(const plane * pl, const faction * sf, const faction * f2) while (a) { const plane *p = (const plane *)a->data.v; - if (p == pl) return HELP_ALL; a = a->next; @@ -1024,7 +945,6 @@ alliedfaction(const struct plane *pl, const struct faction *f, int alliedunit(const unit * u, const faction * f2, int mode) { ally *sf; - int automode; assert(u->region); /* the unit should be in a region, but it's possible that u->number==0 (TEMP units) */ @@ -1036,7 +956,6 @@ int alliedunit(const unit * u, const faction * f2, int mode) if (mode & HELP_FIGHT) { if ((u->flags & UFL_DEFENDER) || (u->faction->flags & FFL_DEFENDER)) { faction *owner = region_get_owner(u->region); - /* helps the owner of the region */ if (owner == f2) { return HELP_FIGHT; @@ -1053,7 +972,6 @@ int alliedunit(const unit * u, const faction * f2, int mode) sf = u->faction->allies; if (fval(u, UFL_GROUP)) { const attrib *a = a_findc(u->attribs, &at_group); - if (a != NULL) sf = ((group *) a->data.v)->allies; } @@ -1078,11 +996,8 @@ cansee(const faction * f, const region * r, const unit * u, int modifier) * erblickt wird */ { int stealth, rings; - unit *u2 = r->units; - static const item_type *itype_grail; - static boolean init; if (!init) { @@ -1096,7 +1011,6 @@ cansee(const faction * f, const region * r, const unit * u, int modifier) return false; } else if (u->number == 0) { 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. */ u = (unit *) a->data.v; @@ -1188,7 +1102,6 @@ cansee_durchgezogen(const faction * f, const region * r, const unit * u, * erblickt wird */ { int n; - unit *u2; if (fval(u->race, RCF_INVISIBLE) || u->number == 0) @@ -1230,7 +1143,6 @@ cansee_durchgezogen(const faction * f, const region * r, const unit * u, const char *strcheck(const char *s, size_t maxlen) { static char buffer[16 * 1024]; - if (strlen(s) > maxlen) { assert(maxlen < 16 * 1024); log_warning(("[strcheck] String wurde auf %d Zeichen verkürzt:\n%s\n", @@ -1255,7 +1167,6 @@ static attrib_type at_lighthouse = { void update_lighthouse(building * lh) { static boolean init_lighthouse = false; - static const struct building_type *bt_lighthouse = 0; if (!init_lighthouse) { @@ -1267,9 +1178,7 @@ void update_lighthouse(building * lh) if (lh->type == bt_lighthouse) { region *r = lh->region; - int d = (int)log10(lh->size) + 1; - int x; if (lh->size > 0) { @@ -1278,14 +1187,10 @@ void update_lighthouse(building * lh) for (x = -d; x <= d; ++x) { int y; - for (y = -d; y <= d; ++y) { attrib *a; - region *r2; - int px = r->x + x, py = r->y + y; - pnormalize(&px, &py, rplane(r)); r2 = findregion(px, py); if (r2 == NULL) @@ -1297,7 +1202,6 @@ void update_lighthouse(building * lh) a = a_find(r2->attribs, &at_lighthouse); while (a && a->type == &at_lighthouse) { building *b = (building *) a->data.v; - if (b == lh) break; a = a->next; @@ -1315,9 +1219,7 @@ int count_all(const faction * f) { #ifndef NDEBUG int n = 0; - unit *u; - for (u = f->units; u; u = u->nextF) { if (playerrace(u->race)) { n += u->number; @@ -1335,9 +1237,7 @@ int count_all(const faction * f) int count_migrants(const faction * f) { unit *u = f->units; - int n = 0; - while (u) { assert(u->faction == f); if (u->race != f->race && u->race != new_race[RC_ILLUSION] @@ -1359,10 +1259,8 @@ int count_maxmigrants(const faction * f) } if (migrants == INT_MAX) { int x = 0; - if (f->race == new_race[RC_HUMAN]) { int nsize = count_all(f); - if (nsize > 0) { x = (int)(log10(nsize / 50.0) * 20); if (x < 0) @@ -1377,7 +1275,6 @@ int count_maxmigrants(const faction * f) void init_tokens(const struct order *ord) { char *cmd = getcommand(ord); - init_tokens_str(cmd, cmd); } @@ -1388,17 +1285,13 @@ parse(keyword_t kword, int (*dofun) (unit *, struct order *), boolean thisorder) for (r = regions; r; r = r->next) { unit **up = &r->units; - while (*up) { unit *u = *up; - order **ordp = &u->orders; - if (thisorder) ordp = &u->thisorder; while (*ordp) { order *ord = *ordp; - if (get_keyword(ord) == kword) { if (dofun(u, ord) != 0) break; @@ -1438,7 +1331,6 @@ int getint(void) const struct race *findrace(const char *s, const struct locale *lang) { struct tnode *tokens = get_translations(lang, UT_RACES); - variant token; assert(lang); @@ -1451,7 +1343,6 @@ const struct race *findrace(const char *s, const struct locale *lang) int findoption(const char *s, const struct locale *lang) { struct tnode *tokens = get_translations(lang, UT_OPTIONS); - variant token; if (findtoken(tokens, s, &token) == E_TOK_SUCCESS) { @@ -1466,7 +1357,6 @@ static struct trie_node *ptries[UT_MAX][4]; static struct trie_node **get_ptrie(const struct locale *lang, int type) { int index = (strcmp(locale_name(lang), "de") == 0); - return &(ptries[type][index]); } @@ -1494,24 +1384,19 @@ static int umlaut_substitution(const char *ip, char *op, size_t outlen) 252, "ue"}, /* uuml */ }; int subs = 0; - while (*ip) { ucs4_t ucs = *ip; - size_t size = 1; - size_t cpsize = 1; if (ucs & 0x80) { int ret = unicode_utf8_to_ucs4(&ucs, ip, &size); - if (ret != 0) { return ret; } cpsize = size; if (ucs >= replace[0].ucs && ucs <= replace[UMAX - 1].ucs) { int i; - for (i = 0; i != UMAX; ++i) { if (replace[i].ucs == ucs) { cpsize = 0; @@ -1546,10 +1431,8 @@ static int ptrie_find(struct trie_node *ptrie, const char *key, void *data, size_t size) { trie_node *node = trie_find_prefix(ptrie, key); - if (node) { void *result = trie_getdata(node); - memcpy(data, result, size); return 0; } @@ -1561,14 +1444,10 @@ ptrie_insert(struct trie_node **ptrie, const char *name, void *data, size_t size) { char converted[256]; - char simple[256]; - int ret = unicode_utf8_tolower(converted, 256, name); - if (ret == 0) { int subs = umlaut_substitution(converted, simple, sizeof(simple)); - if (subs > 0) { trie_insert(ptrie, simple, data, size); } @@ -1582,23 +1461,17 @@ skill_t findskill(const char *s, const struct locale * lang) { #if PTRIES char lowercase[256]; - int res = unicode_utf8_tolower(lowercase, sizeof(lowercase), s); - if (res == 0) { trie_node **ptrie = get_ptrie(lang, UT_SKILLS); - skill_t sk; - int result = ptrie_find(*ptrie, lowercase, &sk, sizeof(sk)); - if (result == 0) return sk; } return NOSKILL; #else struct tnode *tokens = get_translations(lang, UT_SKILLS); - variant token; if (findtoken(tokens, s, &token) == E_TOK_NOMATCH) @@ -1610,7 +1483,6 @@ skill_t findskill(const char *s, const struct locale * lang) keyword_t findkeyword(const char *s, const struct locale * lang) { struct tnode *tokens = get_translations(lang, UT_KEYWORDS); - variant token; if (*s == '@') @@ -1625,12 +1497,10 @@ keyword_t findkeyword(const char *s, const struct locale * lang) param_t findparam(const char *s, const struct locale * lang) { struct tnode *tokens = get_translations(lang, UT_PARAMS); - variant token; if (findtoken(tokens, s, &token) == E_TOK_NOMATCH) { const building_type *btype = findbuildingtype(s, lang); - if (btype != NULL) return (param_t) P_GEBAEUDE; return NOPARAM; @@ -1648,7 +1518,6 @@ param_t getparam(const struct locale * lang) faction *findfaction(int n) { faction *f = ffindhash(n); - return f; } @@ -1693,7 +1562,6 @@ unit *findunitg(int n, const region * hint) unit *getnewunit(const region * r, const faction * f) { int n; - n = getid(); return findnewunit(r, f, n); @@ -1702,9 +1570,7 @@ unit *getnewunit(const region * r, const faction * f) static int read_newunitid(const faction * f, const region * r) { int n; - unit *u2; - n = getid(); if (n == 0) return -1; @@ -1735,7 +1601,6 @@ int read_unitid(const faction * f, const region * r) /* exported symbol */ boolean getunitpeasants; - unit *getunitg(const region * r, const faction * f) { int n = read_unitid(f, r); @@ -1754,7 +1619,6 @@ unit *getunitg(const region * r, const faction * f) unit *getunit(const region * r, const faction * f) { int n = read_unitid(f, r); - unit *u2; if (n == 0) { @@ -1781,7 +1645,6 @@ unit *getunit(const region * r, const faction * f) void addstrlist(strlist ** SP, const char *s) { strlist *slist = malloc(sizeof(strlist)); - slist->next = NULL; slist->s = strdup(s); addlist(SP, slist); @@ -1790,7 +1653,6 @@ void addstrlist(strlist ** SP, const char *s) void freestrlist(strlist * s) { strlist *q, *p = s; - while (p) { q = p->next; free(p->s); @@ -1805,9 +1667,7 @@ boolean lomem = false; /* - Namen der Strukturen -------------------------------------- */ typedef char name[OBJECTIDSIZE + 1]; - static name idbuf[8]; - static int nextbuf = 0; char *estring_i(char *ibuf) @@ -1862,7 +1722,6 @@ building *largestbuilding(const region * r, cmp_building_cb cmp_gt, continue; if (!imaginary) { const attrib *a = a_find(b->attribs, &at_icastle); - if (a) continue; } @@ -1882,7 +1741,6 @@ char *write_unitname(const unit * u, char *buffer, size_t size) const char *unitname(const unit * u) { char *ubuf = idbuf[(++nextbuf) % 8]; - return write_unitname(u, ubuf, sizeof(name)); } @@ -1895,11 +1753,8 @@ static const char *forbidden[] = { "t", "te", "tem", "temp", NULL }; int forbiddenid(int id) { static int *forbid = NULL; - static size_t len; - size_t i; - if (id <= 0) return 1; if (!forbid) { @@ -1920,9 +1775,7 @@ int forbiddenid(int id) int newunitid(void) { int random_unit_no; - int start_random_no; - random_unit_no = 1 + (rng_int() % MAX_UNIT_NR); start_random_no = random_unit_no; @@ -1943,7 +1796,6 @@ int newunitid(void) int newcontainerid(void) { int random_no; - int start_random_no; random_no = 1 + (rng_int() % MAX_CONTAINER_NR); @@ -1972,7 +1824,6 @@ boolean idle(faction * f) return (boolean) (f ? false : true); } - int maxworkingpeasants(const struct region *r) { int i = production(r) * MAXPEASANTS_PER_AREA @@ -1983,17 +1834,13 @@ int maxworkingpeasants(const struct region *r) int lighthouse_range(const building * b, const faction * f) { int d = 0; - if (fval(b, BLD_WORKING) && b->size >= 10) { int maxd = (int)log10(b->size) + 1; if (skill_enabled[SK_PERCEPTION]) { region *r = b->region; - int c = 0; - unit *u; - for (u = r->units; u; u = u->next) { if (u->building == b) { c += u->number; @@ -2001,7 +1848,6 @@ int lighthouse_range(const building * b, const faction * f) break; if (f == NULL || u->faction == f) { int sk = eff_skill(u, SK_PERCEPTION, r) / 3; - d = MAX(d, sk); d = MIN(maxd, d); if (d == maxd) @@ -2035,11 +1881,8 @@ boolean check_leuchtturm(region * r, faction * f) if (skill_enabled[SK_PERCEPTION]) { region *r2 = b->region; - unit *u; - int c = 0; - int d = 0; for (u = r2->units; u; u = u->next) { @@ -2072,7 +1915,6 @@ region *lastregion(faction * f) { #ifdef SMART_INTERVALS unit *u = f->units; - region *r = f->last; if (u == NULL) @@ -2096,7 +1938,6 @@ region *lastregion(faction * f) /* search the region for travelthru-attributes: */ if (fval(r, RF_TRAVELUNIT)) { attrib *ru = a_find(r->attribs, &at_travelunit); - while (ru && ru->type == &at_travelunit) { u = (unit *) ru->data.v; if (u->faction == f) { @@ -2137,15 +1978,12 @@ region *firstregion(faction * f) } void **blk_list[1024]; - int list_index; - int blk_index; static void gc_done(void) { int i, k; - for (i = 0; i != list_index; ++i) { for (k = 0; k != 1024; ++k) free(blk_list[i][k]); @@ -2194,12 +2032,10 @@ static void init_directions(tnode * root, const struct locale *lang) NULL, NODIRECTION} }; int i; - struct tnode *tokens = get_translations(lang, UT_DIRECTIONS); for (i = 0; dirs[i].direction != NODIRECTION; ++i) { variant token; - token.i = dirs[i].direction; addtoken(tokens, LOC(lang, dirs[i].name), token); } @@ -2208,7 +2044,6 @@ static void init_directions(tnode * root, const struct locale *lang) direction_t finddirection(const char *s, const struct locale *lang) { struct tnode *tokens = get_translations(lang, UT_DIRECTIONS); - variant token; if (findtoken(tokens, s, &token) == E_TOK_SUCCESS) { @@ -2220,15 +2055,10 @@ direction_t finddirection(const char *s, const struct locale *lang) static void init_locale(const struct locale *lang) { variant var; - int i; - const struct race *rc; - struct tnode *tokens; - const terrain_type *terrain; - #if PTRIES trie_node **ptrie; #endif @@ -2236,9 +2066,7 @@ static void init_locale(const struct locale *lang) tokens = get_translations(lang, UT_MAGIC); if (tokens) { const char *str = get_param(global.parameters, "rules.magic.playerschools"); - char *sstr, *tok; - if (str == NULL) { str = "gwyrrd illaun draig cerddor tybied"; } @@ -2277,9 +2105,7 @@ static void init_locale(const struct locale *lang) ptrie = get_ptrie(lang, UT_SKILLS); for (i = 0; i != MAXSKILLS; ++i) { skill_t sk = (skill_t) i; - const char *skname = skillname(sk, lang); - if (skname != NULL) { ptrie_insert(ptrie, skname, &sk, sizeof(sk)); } @@ -2288,7 +2114,6 @@ static void init_locale(const struct locale *lang) tokens = get_translations(lang, UT_SKILLS); for (i = 0; i != MAXSKILLS; ++i) { const char *skname = skillname((skill_t) i, lang); - if (skname != NULL) { var.i = i; addtoken(tokens, skname, var); @@ -2326,9 +2151,7 @@ typedef struct param { int getid(void) { const char *str = (const char *)getstrtoken(); - int i = atoi36(str); - if (i < 0) { return -1; } @@ -2356,11 +2179,9 @@ int get_param_int(const struct param *p, const char *key, int def) } static const char *g_datadir; - const char *datapath(void) { static char zText[MAX_PATH]; - if (g_datadir) return g_datadir; return strcat(strcpy(zText, basepath()), "/data"); @@ -2371,13 +2192,10 @@ void set_datapath(const char *path) g_datadir = path; } - static const char *g_reportdir; - const char *reportpath(void) { static char zText[MAX_PATH]; - if (g_reportdir) return g_reportdir; return strcat(strcpy(zText, basepath()), "/reports"); @@ -2389,7 +2207,6 @@ void set_reportpath(const char *path) } static const char *g_basedir; - const char *basepath(void) { if (g_basedir) @@ -2397,7 +2214,6 @@ const char *basepath(void) return "."; } - void set_basepath(const char *path) { g_basedir = path; @@ -2416,7 +2232,6 @@ float get_param_flt(const struct param *p, const char *key, float def) void set_param(struct param **p, const char *key, const char *data) { ++global.cookie; - while (*p != NULL) { if (strcmp((*p)->name, key) == 0) { free((*p)->data); @@ -2449,10 +2264,8 @@ const char *localenames[] = { void init_locales(void) { int l; - for (l = 0; localenames[l]; ++l) { const struct locale *lang = find_locale(localenames[l]); - if (lang) init_locale(lang); } @@ -2496,7 +2309,6 @@ void setguard(unit * u, unsigned int flags) { /* setzt die guard-flags der Einheit */ attrib *a = NULL; - assert(flags == 0 || !fval(u, UFL_MOVED)); assert(flags == 0 || u->status < ST_FLEE); if (fval(u, UFL_GUARD)) { @@ -2546,13 +2358,11 @@ void remove_empty_factions(void) for (fp = &factions; *fp;) { faction *f = *fp; - /* monster (0) werden nicht entfernt. alive kann beim readgame * () auf 0 gesetzt werden, wenn monsters keine einheiten mehr * haben. */ if ((f->units == NULL || f->alive == 0) && !is_monsters(f)) { ursprung *ur = f->ursprung; - while (ur && ur->id != 0) ur = ur->next; if (verbosity >= 2) @@ -2565,11 +2375,8 @@ void remove_empty_factions(void) for (f3 = factions; f3; f3 = f3->next) { ally *sf; - group *g; - ally **sfp = &f3->allies; - while (*sfp) { sf = *sfp; if (sf->faction == f || sf->faction == NULL) { @@ -2613,7 +2420,6 @@ void remove_empty_units_in_region(region * r) if (u->number) { faction *f = u->faction; - if (f == NULL || !f->alive) { set_number(u, 0); } @@ -2651,7 +2457,6 @@ int weight(const unit * u) int w, n = 0, in_bag = 0; item *itm; - for (itm = u->items; itm; itm = itm->next) { w = itm->type->weight * itm->number; n += w; @@ -2704,7 +2509,6 @@ unsigned int guard_flags(const unit * u) void guard(unit * u, unsigned int mask) { unsigned int flags = guard_flags(u); - setguard(u, flags & mask); } @@ -2719,11 +2523,8 @@ int besieged(const unit * u) int lifestyle(const unit * u) { int need; - plane *pl; - static int gamecookie = -1; - if (gamecookie != global.cookie) { gamecookie = global.cookie; } @@ -2743,7 +2544,6 @@ int lifestyle(const unit * u) boolean has_horses(const struct unit * u) { item *itm = u->items; - for (; itm; itm = itm->next) { if (itm->type->flags & ITF_ANIMAL) return true; @@ -2754,20 +2554,14 @@ boolean has_horses(const struct unit * u) boolean hunger(int number, unit * u) { region *r = u->region; - int dead = 0, hpsub = 0; - int hp = u->hp / u->number; - static const char *damage = 0; - static const char *rcdamage = 0; - static const race *rc = 0; if (!damage) { damage = get_param(global.parameters, "hunger.damage"); - if (damage == NULL) damage = "1d12+12"; } @@ -2778,7 +2572,6 @@ boolean hunger(int number, unit * u) while (number--) { int dam = dice_rand(rcdamage ? rcdamage : damage); - if (dam >= hp) { ++dead; } else { @@ -2810,16 +2603,13 @@ boolean hunger(int number, unit * u) void plagues(region * r, boolean ismagic) { int peasants; - int i; - int dead = 0; /* Seuchenwahrscheinlichkeit in % */ if (!ismagic) { double mwp = MAX(maxworkingpeasants(r), 1); - double prob = pow(rpeasants(r) / (mwp * wage(r, NULL, NULL, turn) * 0.13), 4.0) * PLAGUE_CHANCE; @@ -2839,7 +2629,6 @@ void plagues(region * r, boolean ismagic) if (dead > 0) { message *msg = add_message(&r->msgs, msg_message("pest", "dead", dead)); - msg_release(msg); deathcounts(r, dead); rsetpeasants(r, peasants - dead); @@ -2862,7 +2651,6 @@ static const int wagetable[7][4] = { int cmp_wage(const struct building *b, const building * a) { static const struct building_type *bt_castle; - if (!bt_castle) bt_castle = bt_find("castle"); if (b->type == bt_castle) { @@ -2879,10 +2667,8 @@ int cmp_wage(const struct building *b, const building * a) boolean is_owner_building(const struct building * b) { region *r = b->region; - if (b->type->taxes && r->land && r->land->ownership) { unit *u = building_owner(b); - return u && u->faction == r->land->ownership->owner; } return false; @@ -2891,19 +2677,14 @@ boolean is_owner_building(const struct building * b) int cmp_taxes(const building * b, const building * a) { faction *f = region_get_owner(b->region); - if (b->type->taxes) { unit *u = building_owner(b); - if (!u) { return -1; } else if (a) { int newsize = buildingeffsize(b, false); - double newtaxes = b->type->taxes(b, newsize); - int oldsize = buildingeffsize(a, false); - double oldtaxes = a->type->taxes(a, oldsize); if (newtaxes < oldtaxes) @@ -2936,16 +2717,12 @@ int cmp_current_owner(const building * b, const building * a) assert(rule_region_owners()); if (f && b->type->taxes) { unit *u = building_owner(b); - if (!u || u->faction != f) return -1; if (a) { int newsize = buildingeffsize(b, false); - double newtaxes = b->type->taxes(b, newsize); - int oldsize = buildingeffsize(a, false); - double oldtaxes = a->type->taxes(a, oldsize); if (newtaxes != oldtaxes) @@ -2963,14 +2740,10 @@ int cmp_current_owner(const building * b, const building * a) int rule_stealth_faction(void) { static int gamecookie = -1; - static int rule = -1; - if (rule < 0 || gamecookie != global.cookie) { rule = get_param_int(global.parameters, "rules.stealth.faction", 1); - gamecookie = global.cookie; - assert(rule >= 0); } return rule; @@ -2979,14 +2752,10 @@ int rule_stealth_faction(void) int rule_region_owners(void) { static int gamecookie = -1; - static int rule = -1; - if (rule < 0 || gamecookie != global.cookie) { rule = get_param_int(global.parameters, "rules.region_owners", 0); - gamecookie = global.cookie; - assert(rule >= 0); } return rule; @@ -2995,14 +2764,11 @@ int rule_region_owners(void) int rule_auto_taxation(void) { static int gamecookie = -1; - static int rule = -1; - if (rule < 0 || gamecookie != global.cookie) { rule = get_param_int(global.parameters, "rules.economy.taxation", TAX_ORDER); gamecookie = global.cookie; - assert(rule >= 0); } return rule; @@ -3011,15 +2777,12 @@ int rule_auto_taxation(void) int rule_blessed_harvest(void) { static int gamecookie = -1; - static int rule = -1; - if (rule < 0 || gamecookie != global.cookie) { rule = get_param_int(global.parameters, "rules.magic.blessed_harvest", HARVEST_WORK); gamecookie = global.cookie; - assert(rule >= 0); } return rule; @@ -3028,14 +2791,10 @@ int rule_blessed_harvest(void) int rule_alliance_limit(void) { static int gamecookie = -1; - static int rule = -1; - if (rule < 0 || gamecookie != global.cookie) { rule = get_param_int(global.parameters, "rules.limit.alliance", 0); - gamecookie = global.cookie; - assert(rule >= 0); } return rule; @@ -3044,14 +2803,10 @@ int rule_alliance_limit(void) int rule_faction_limit(void) { static int gamecookie = -1; - static int rule = -1; - if (rule < 0 || gamecookie != global.cookie) { rule = get_param_int(global.parameters, "rules.limit.faction", 0); - gamecookie = global.cookie; - assert(rule >= 0); } return rule; @@ -3060,14 +2815,10 @@ int rule_faction_limit(void) int rule_transfermen(void) { static int gamecookie = -1; - static int rule = -1; - if (rule < 0 || gamecookie != global.cookie) { rule = get_param_int(global.parameters, "rules.transfermen", 1); - gamecookie = global.cookie; - assert(rule >= 0); } return rule; @@ -3077,19 +2828,12 @@ static int default_wage(const region * r, const faction * f, const race * rc, int in_turn) { building *b = largestbuilding(r, &cmp_wage, false); - int esize = 0; - curse *c; - double wage; - attrib *a; - const building_type *artsculpture_type = bt_find("artsculpture"); - static const curse_type *drought_ct, *blessedharvest_ct; - static boolean init; if (!init) { @@ -3105,7 +2849,6 @@ default_wage(const region * r, const faction * f, const race * rc, int in_turn) if (f != NULL) { int index = 0; - if (rc == new_race[RC_ORC] || rc == new_race[RC_SNOTLING]) { index = 1; } @@ -3171,7 +2914,6 @@ int wage(const region * r, const faction * f, const race * rc, int in_turn) return default_wage(r, f, rc, in_turn); } - #define MAINTENANCE 10 int maintenance_cost(const struct unit *u) { @@ -3179,7 +2921,6 @@ int maintenance_cost(const struct unit *u) return MAINTENANCE; if (global.functions.maintenance) { int retval = global.functions.maintenance(u); - if (retval >= 0) return retval; } @@ -3190,7 +2931,6 @@ message *movement_error(unit * u, const char *token, order * ord, int error_code) { direction_t d; - switch (error_code) { case E_MOVE_BLOCKED: d = finddirection(token, u->faction->locale); @@ -3204,7 +2944,6 @@ message *movement_error(unit * u, const char *token, order * ord, int movewhere(const unit * u, const char *token, region * r, region ** resultp) { region *r2; - direction_t d; if (*token == '\0') { @@ -3239,9 +2978,7 @@ int movewhere(const unit * u, const char *token, region * r, region ** resultp) boolean move_blocked(const unit * u, const region * r, const region * r2) { connection *b; - curse *c; - static const curse_type *fogtrap_ct = NULL; if (r2 == NULL) @@ -3275,20 +3012,14 @@ void reorder_units(region * r) if (r->buildings) { building *b = r->buildings; - while (*unext && b) { unit **ufirst = unext; /* where the first unit in the building should go */ - unit **umove = unext; /* a unit we consider moving */ - unit *owner = NULL; - while (*umove) { unit *u = *umove; - if (u->number && u->building == b) { unit **uinsert = unext; - if (fval(u, UFL_OWNER)) { uinsert = ufirst; owner = u; @@ -3319,13 +3050,10 @@ void reorder_units(region * r) if (r->ships) { ship *sh = r->ships; - /* first, move all units up that are not on ships */ unit **umove = unext; /* a unit we consider moving */ - while (*umove) { unit *u = *umove; - if (u->number && !u->ship) { if (umove != unext) { *umove = u->next; @@ -3344,17 +3072,12 @@ void reorder_units(region * r) while (*unext && sh) { unit **ufirst = unext; /* where the first unit in the building should go */ - unit **umove = unext; /* a unit we consider moving */ - unit *owner = NULL; - while (*umove) { unit *u = *umove; - if (u->number && u->ship == sh) { unit **uinsert = unext; - if (fval(u, UFL_OWNER)) { uinsert = ufirst; owner = u; @@ -3397,7 +3120,6 @@ int produceexp(struct unit *u, skill_t sk, int n) int lovar(double xpct_x2) { int n = (int)(xpct_x2 * 500) + 1; - if (n == 0) return 0; return (rng_int() % n + rng_int() % n) / 1000; @@ -3471,7 +3193,6 @@ void attrib_init(void) void kernel_init(void) { char zBuffer[MAX_PATH]; - attrib_init(); translation_init(); @@ -3506,7 +3227,6 @@ int entertainmoney(const region * r) int rule_give(void) { static int value = -1; - if (value < 0) { value = get_param_int(global.parameters, "rules.give", GIVE_DEFAULT); } @@ -3516,7 +3236,6 @@ int rule_give(void) int markets_module(void) { static int value = -1; - if (value < 0) { value = get_param_int(global.parameters, "modules.markets", 0); } @@ -3535,13 +3254,11 @@ void free_gamedata(void) while (alliances) { alliance *al = alliances; - alliances = al->next; free_alliance(al); } while (factions) { faction *f = factions; - factions = f->next; funhash(f); free_faction(f); @@ -3550,7 +3267,6 @@ void free_gamedata(void) while (planes) { plane *pl = planes; - planes = planes->next; free(pl->name); free(pl); @@ -3562,15 +3278,11 @@ void free_gamedata(void) ++global.cookie; /* readgame() already does this, but sjust in case */ } - void load_inifile(dictionary * d) { const char *reportdir = reportpath(); - const char *datadir = datapath(); - const char *basedir = basepath(); - const char *str; assert(d); diff --git a/src/kernel/connection.c b/src/kernel/connection.c index 7f2800028..816e42a84 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -42,7 +42,6 @@ unsigned int nextborder = 0; #define BORDER_MAXHASH 8191 connection *borders[BORDER_MAXHASH]; - border_type *bordertypes; void (*border_convert_cb) (struct connection * con, struct attrib * attr) = 0; @@ -50,15 +49,12 @@ void (*border_convert_cb) (struct connection * con, struct attrib * attr) = 0; void free_borders(void) { int i; - for (i = 0; i != BORDER_MAXHASH; ++i) { while (borders[i]) { connection *b = borders[i]; - borders[i] = b->nexthash; while (b) { connection *bf = b; - b = b->next; assert(b == NULL || b->nexthash == NULL); if (bf->type->destroy) { @@ -73,13 +69,10 @@ void free_borders(void) connection *find_border(unsigned int id) { int key; - for (key = 0; key != BORDER_MAXHASH; key++) { connection *bhash; - for (bhash = borders[key]; bhash != NULL; bhash = bhash->nexthash) { connection *b; - for (b = bhash; b; b = b->next) { if (b->id == id) return b; @@ -92,9 +85,7 @@ connection *find_border(unsigned int id) int resolve_borderid(variant id, void *addr) { int result = 0; - connection *b = NULL; - if (id.i != 0) { b = find_border(id.i); if (b == NULL) { @@ -108,16 +99,13 @@ int resolve_borderid(variant id, void *addr) static connection **get_borders_i(const region * r1, const region * r2) { connection **bp; - int key = reg_hashkey(r1); - int k2 = reg_hashkey(r2); key = MIN(k2, key) % BORDER_MAXHASH; bp = &borders[key]; while (*bp) { connection *b = *bp; - if ((b->from == r1 && b->to == r2) || (b->from == r2 && b->to == r1)) break; bp = &b->nexthash; @@ -128,7 +116,6 @@ static connection **get_borders_i(const region * r1, const region * r2) connection *get_borders(const region * r1, const region * r2) { connection **bp = get_borders_i(r1, r2); - return *bp; } @@ -138,7 +125,6 @@ connection *new_border(border_type * type, region * from, region * to) if (from && to) { connection **bp = get_borders_i(from, to); - while (*bp) bp = &(*bp)->next; *bp = b; @@ -157,7 +143,6 @@ void erase_border(connection * b) { if (b->from && b->to) { connection **bp = get_borders_i(b->from, b->to); - assert(*bp != NULL || !"error: connection is not registered"); if (*bp == b) { /* it is the first in the list, so it is in the nexthash list */ @@ -192,7 +177,6 @@ void register_bordertype(border_type * type) *btp = type; } - border_type *find_bordertype(const char *name) { border_type *bt = bordertypes; @@ -205,7 +189,6 @@ border_type *find_bordertype(const char *name) void b_read(connection * b, storage * store) { int result = 0; - switch (b->type->datatype) { case VAR_NONE: case VAR_INT: @@ -330,15 +313,12 @@ attrib_type at_countdown = { void age_borders(void) { quicklist *deleted = NULL, *ql; - int i; for (i = 0; i != BORDER_MAXHASH; ++i) { connection *bhash = borders[i]; - for (; bhash; bhash = bhash->nexthash) { connection *b = bhash; - for (; b; b = b->next) { if (b->type->age) { if (b->type->age(b) == AT_AGE_REMOVE) { @@ -350,7 +330,6 @@ void age_borders(void) } for (ql = deleted, i = 0; ql; ql_advance(&ql, &i, 1)) { connection *b = (connection *) ql_get(ql, i); - erase_border(b); } ql_free(deleted); @@ -448,7 +427,6 @@ static const char *b_nameillusionwall(const connection * b, const region * r, const struct faction *f, int gflags) { int fno = b->data.i; - unused(b); unused(r); if (gflags & GF_PURE) @@ -491,9 +469,7 @@ static const char *b_namequestportal(const connection * b, const region * r, const struct faction *f, int gflags) { const char *bname; - int lock = b->data.i; - unused(b); unused(r); @@ -537,9 +513,7 @@ static const char *b_nameroad(const connection * b, const region * r, const struct faction *f, int gflags) { region *r2 = (r == b->to) ? b->from : b->to; - int local = (r == b->from) ? b->data.sa[0] : b->data.sa[1]; - static char buffer[64]; unused(f); @@ -550,7 +524,6 @@ static const char *b_nameroad(const connection * b, const region * r, return LOC(f->locale, mkname("border", "a_road")); else if (r->terrain->max_road <= local) { int remote = (r2 == b->from) ? b->data.sa[0] : b->data.sa[1]; - if (r2->terrain->max_road <= remote) { return LOC(f->locale, mkname("border", "a_road")); } else { @@ -558,7 +531,6 @@ static const char *b_nameroad(const connection * b, const region * r, } } else { int percent = MAX(1, 100 * local / r->terrain->max_road); - if (local) { snprintf(buffer, sizeof(buffer), LOC(f->locale, mkname("border", "a_road_percent")), percent); @@ -595,7 +567,6 @@ static boolean b_validroad(const connection * b) static boolean b_rvisibleroad(const connection * b, const region * r) { int x = b->data.i; - x = (r == b->from) ? b->data.sa[0] : b->data.sa[1]; if (x == 0) { return false; @@ -624,13 +595,10 @@ border_type bt_road = { void write_borders(struct storage *store) { int i; - for (i = 0; i != BORDER_MAXHASH; ++i) { connection *bhash; - for (bhash = borders[i]; bhash; bhash = bhash->nexthash) { connection *b; - for (b = bhash; b != NULL; b = b->next) { if (b->type->valid && !b->type->valid(b)) continue; @@ -652,13 +620,9 @@ int read_borders(struct storage *store) { for (;;) { unsigned int bid = 0; - char zText[32]; - connection *b; - region *from, *to; - border_type *type; store->r_tok_buf(store, zText, sizeof(zText)); @@ -667,7 +631,6 @@ int read_borders(struct storage *store) bid = store->r_int(store); if (store->version < UIDHASH_VERSION) { short fx, fy, tx, ty; - fx = (short)store->r_int(store); fy = (short)store->r_int(store); tx = (short)store->r_int(store); @@ -676,9 +639,7 @@ int read_borders(struct storage *store) to = findregion(tx, ty); } else { unsigned int fid = (unsigned int)store->r_int(store); - unsigned int tid = (unsigned int)store->r_int(store); - from = findregionbyid(fid); to = findregionbyid(tid); } @@ -692,9 +653,7 @@ int read_borders(struct storage *store) if (to == from && type && from) { direction_t dir = (direction_t) (rng_int() % MAXDIRECTIONS); - region *r = rconnect(from, dir); - log_error(("[read_borders] invalid %s in %s\n", type->__name, regionname(from, NULL))); if (r != NULL) @@ -708,9 +667,7 @@ int read_borders(struct storage *store) type->read(b, store); if (store->version < NOBORDERATTRIBS_VERSION) { attrib *a = NULL; - int result = a_read(store, &a, b); - if (border_convert_cb) border_convert_cb(b, a); while (a) { diff --git a/src/kernel/connection.h b/src/kernel/connection.h index 71d199b12..62e09771e 100644 --- a/src/kernel/connection.h +++ b/src/kernel/connection.h @@ -89,7 +89,6 @@ extern "C" { struct border_type *next; /* for internal use only */ } border_type; - extern connection *find_border(unsigned int id); int resolve_borderid(variant data, void *addr); extern void free_borders(void); diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 587be847f..2fff1a498 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -116,7 +116,6 @@ void curse_init(attrib * a) int curse_age(attrib * a) { curse *c = (curse *) a->data.v; - int result = 0; if (c_flags(c) & CURSE_NOAGE) { @@ -157,7 +156,6 @@ static int read_ccompat(const char *cursename, struct storage *store) for (seek = old_curses; seek->name; ++seek) { if (strcmp(seek->tokens, cursename) == 0) { const char *p; - for (p = seek->name; p; ++p) { switch (*p) { case 'd': @@ -186,11 +184,8 @@ static int read_ccompat(const char *cursename, struct storage *store) int curse_read(attrib * a, void *owner, struct storage *store) { curse *c = (curse *) a->data.v; - int ur; - char cursename[64]; - unsigned int flags; c->no = store->r_int(store); @@ -202,7 +197,6 @@ int curse_read(attrib * a, void *owner, struct storage *store) c->vigour = store->r_flt(store); } else { int vigour = store->r_int(store); - c->vigour = vigour; } if (store->version < INTPAK_VERSION) { @@ -218,7 +212,6 @@ int curse_read(attrib * a, void *owner, struct storage *store) c->type = ct_find(cursename); if (c->type == NULL) { int result = read_ccompat(cursename, store); - if (result != 0) { log_error(("missing curse %s, no compatibility code either.\n", cursename)); @@ -253,11 +246,8 @@ int curse_read(attrib * a, void *owner, struct storage *store) void curse_write(const attrib * a, const void *owner, struct storage *store) { unsigned int flags; - curse *c = (curse *) a->data.v; - const curse_type *ct = c->type; - unit *mage = (c->magician && c->magician->number) ? c->magician : NULL; /* copied from c_clearflag */ @@ -302,7 +292,6 @@ static quicklist *cursetypes[256]; void ct_register(const curse_type * ct) { unsigned int hash = tolower(ct->cname[0]); - quicklist **ctlp = cursetypes + hash; ql_set_insert(ctlp, (void *)ct); @@ -311,9 +300,7 @@ void ct_register(const curse_type * ct) const curse_type *ct_find(const char *c) { unsigned int hash = tolower(c[0]); - quicklist *ctl = cursetypes[hash]; - int qi; for (qi = 0; ctl; ql_advance(&ctl, &qi, 1)) { @@ -323,7 +310,6 @@ const curse_type *ct_find(const char *c) return type; } else { size_t k = MIN(strlen(c), strlen(type->cname)); - if (!strncasecmp(c, type->cname, k)) { return type; } @@ -340,7 +326,6 @@ const curse_type *ct_find(const char *c) boolean cmp_curse(const attrib * a, const void *data) { const curse *c = (const curse *)data; - if (a->type->flags & ATF_CURSE) { if (!data || c == (curse *) a->data.v) return true; @@ -351,7 +336,6 @@ boolean cmp_curse(const attrib * a, const void *data) boolean cmp_cursetype(const attrib * a, const void *data) { const curse_type *ct = (const curse_type *)data; - if (a->type->flags & ATF_CURSE) { if (!data || ct == ((curse *) a->data.v)->type) return true; @@ -363,10 +347,8 @@ curse *get_cursex(attrib * ap, const curse_type * ctype, variant data, boolean(*compare) (const curse *, variant)) { attrib *a = a_select(ap, ctype, cmp_cursetype); - while (a) { curse *c = (curse *) a->data.v; - if (compare(c, data)) return c; a = a_select(a->next, ctype, cmp_cursetype); @@ -377,14 +359,11 @@ curse *get_cursex(attrib * ap, const curse_type * ctype, variant data, curse *get_curse(attrib * ap, const curse_type * ctype) { attrib *a = ap; - while (a) { if (a->type->flags & ATF_CURSE) { const attrib_type *at = a->type; - while (a && a->type == at) { curse *c = (curse *) a->data.v; - if (c->type == ctype) return c; a = a->next; @@ -408,7 +387,6 @@ curse *findcurse(int cid) void remove_curse(attrib ** ap, const curse * c) { attrib *a = a_select(*ap, c, cmp_curse); - if (a) a_remove(ap, a); } @@ -461,7 +439,6 @@ double curse_geteffect(const curse * c) int curse_geteffect_int(const curse * c) { double effect = curse_geteffect(c); - assert(effect - (int)effect == 0); return (int)effect; } @@ -472,7 +449,6 @@ set_curseingmagician(struct unit *magician, struct attrib *ap_target, const curse_type * ct) { curse *c = get_curse(ap_target, ct); - if (c) { c->magician = magician; } @@ -516,7 +492,6 @@ static curse *make_curse(unit * mage, attrib ** ap, const curse_type * ct, double vigour, int duration, double effect, int men) { curse *c; - attrib *a; a = a_new(&at_curse); @@ -547,7 +522,6 @@ static curse *make_curse(unit * mage, attrib ** ap, const curse_type * ct, return c; } - /* Mapperfunktion für das Anlegen neuer curse. Automatisch wird zum * passenden Typ verzweigt und die relevanten Variablen weitergegeben. */ @@ -608,11 +582,8 @@ curse *create_curse(unit * magician, attrib ** ap, const curse_type * ct, static void do_transfer_curse(curse * c, unit * u, unit * u2, int n) { int cursedmen = 0; - int men = get_cursedmen(u, c); - boolean dogive = false; - const curse_type *ct = c->type; switch ((ct->flags | c->flags) & CURSE_SPREADMASK) { @@ -624,9 +595,7 @@ static void do_transfer_curse(curse * c, unit * u, unit * u2, int n) case CURSE_SPREADMODULO: { int i; - int u_number = u->number; - for (i = 0; i < n + 1 && u_number > 0; i++) { if (rng_int() % u_number < cursedmen) { ++men; @@ -650,7 +619,6 @@ static void do_transfer_curse(curse * c, unit * u, unit * u2, int n) if (dogive == true) { curse *cnew = make_curse(c->magician, &u2->attribs, c->type, c->vigour, c->duration, c->effect, men); - cnew->flags = c->flags; if (ct->typ == CURSETYP_UNIT) @@ -665,7 +633,6 @@ void transfer_curse(unit * u, unit * u2, int n) a = a_find(u->attribs, &at_curse); while (a && a->type == &at_curse) { curse *c = (curse *) a->data.v; - do_transfer_curse(c, u, u2, n); a = a->next; } @@ -695,7 +662,6 @@ boolean is_cursed_internal(attrib * ap, const curse_type * ct) return true; } - boolean is_cursed_with(const attrib * ap, const curse * c) { const attrib *a = ap; @@ -729,9 +695,7 @@ boolean is_cursed_with(const attrib * ap, const curse * c) int resolve_curse(variant id, void *address) { int result = 0; - curse *c = NULL; - if (id.i != 0) { c = cfindhash(id.i); if (c == NULL) { @@ -807,7 +771,6 @@ message *cinfo_simple(const void *obj, typ_t typ, const struct curse * c, return msg; } - /* ------------------------------------------------------------- */ /* Antimagie - curse auflösen */ /* ------------------------------------------------------------- */ @@ -823,7 +786,6 @@ double destr_curse(curse * c, int cast_level, double force) { if (cast_level < c->vigour) { /* Zauber ist nicht stark genug */ double probability = 0.1 + (cast_level - c->vigour) * 0.2; - /* pro Stufe Unterschied -20% */ if (chance(probability)) { force -= c->vigour; diff --git a/src/kernel/curse.h b/src/kernel/curse.h index 16419c1f9..b9af001e0 100644 --- a/src/kernel/curse.h +++ b/src/kernel/curse.h @@ -145,7 +145,6 @@ extern "C" { /* ------------------------------------------------------------- */ /* Flags */ - /* Verhalten von Zaubern auf Units beim Übergeben von Personen */ typedef enum { CURSE_ISNEW = 0x01, /* wirkt in der zauberrunde nicht (default) */ @@ -225,7 +224,6 @@ extern "C" { struct storage *store); int curse_read(struct attrib *a, void *owner, struct storage *store); - /* ------------------------------------------------------------- */ /* Kommentare: * Bei einigen Typen von Verzauberungen (z.B.Skillmodif.) muss neben @@ -249,7 +247,6 @@ extern "C" { extern void destroy_curse(curse * c); - boolean is_cursed_internal(struct attrib *ap, const curse_type * ctype); /* ignoriert CURSE_ISNEW */ @@ -265,7 +262,6 @@ extern "C" { * gesetzt. Gibt immer den ersten Treffer von ap aus zurück. */ - extern double curse_changevigour(struct attrib **ap, curse * c, double i); /* verändert die Stärke der Verzauberung um i */ diff --git a/src/kernel/curse_test.c b/src/kernel/curse_test.c index 131ef05c4..e26366a5f 100644 --- a/src/kernel/curse_test.c +++ b/src/kernel/curse_test.c @@ -3,9 +3,7 @@ static void test_curse(CuTest * tc) { attrib *attrs = NULL; - curse *c, *result; - int cid; curse_type ct_dummy = { "dummy", CURSETYP_NORM, 0, M_SUMEFFECT, NULL }; @@ -21,7 +19,6 @@ static void test_curse(CuTest * tc) CuSuite *get_curse_suite(void) { CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, test_curse); return suite; } diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index 8215eb75e..150a70e65 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -39,12 +39,9 @@ static equipment *equipment_sets; equipment *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 = malloc(sizeof(equipment)); eq->name = strdup(eqname); @@ -67,10 +64,8 @@ equipment *create_equipment(const char *eqname) 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) @@ -103,7 +98,6 @@ equipment_setitem(equipment * eq, const item_type * itype, const char *value) if (eq != NULL) { if (itype != NULL) { itemdata *idata = eq->items; - while (idata && idata->itype != itype) { idata = idata->next; } @@ -136,11 +130,9 @@ void equip_unit_mask(struct unit *u, const struct equipment *eq, int mask) if (mask & EQUIP_SKILLS) { skill_t sk; - for (sk = 0; sk != MAXSKILLS; ++sk) { if (eq->skills[sk] != NULL) { int i = dice_rand(eq->skills[sk]); - if (i > 0) set_level(u, sk, i); } @@ -149,18 +141,14 @@ void equip_unit_mask(struct unit *u, const struct equipment *eq, int mask) if (mask & EQUIP_SPELLS) { quicklist *ql = eq->spells; - if (ql) { sc_mage *m = get_mage(u); - if (m == NULL) { assert(!"trying to equip spells on a non-mage!"); } else { int qi; - for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { spell *sp = (spell *) ql_get(ql, qi); - add_spell(get_spelllist(m, u->faction), sp); } } @@ -169,10 +157,8 @@ void equip_unit_mask(struct unit *u, const struct equipment *eq, int mask) if (mask & EQUIP_ITEMS) { itemdata *idata; - for (idata = eq->items; idata != NULL; idata = idata->next) { int i = u->number * dice_rand(idata->value); - if (i > 0) { i_add(&u->items, i_new(idata->itype, i)); } @@ -181,13 +167,10 @@ void equip_unit_mask(struct unit *u, const struct equipment *eq, int mask) if (eq->subsets) { int i; - for (i = 0; eq->subsets[i].sets; ++i) { if (chance(eq->subsets[i].chance)) { float rnd = (1 + rng_int() % 1000) / 1000.0f; - int k; - for (k = 0; eq->subsets[i].sets[k].set; ++k) { if (rnd <= eq->subsets[i].sets[k].chance) { equip_unit_mask(u, eq->subsets[i].sets[k].set, mask); @@ -213,20 +196,16 @@ void equip_items(struct item **items, const struct equipment *eq) for (idata = eq->items; idata != NULL; idata = idata->next) { int i = dice_rand(idata->value); - if (i > 0) { i_add(items, i_new(idata->itype, i)); } } if (eq->subsets) { int i; - for (i = 0; eq->subsets[i].sets; ++i) { if (chance(eq->subsets[i].chance)) { float rnd = (1 + rng_int() % 1000) / 1000.0f; - int k; - for (k = 0; eq->subsets[i].sets[k].set; ++k) { if (rnd <= eq->subsets[i].sets[k].chance) { equip_items(items, eq->subsets[i].sets[k].set); diff --git a/src/kernel/equipment.h b/src/kernel/equipment.h index a483fdcf8..eae6a23c9 100644 --- a/src/kernel/equipment.h +++ b/src/kernel/equipment.h @@ -49,7 +49,6 @@ extern "C" { void (*callback) (const struct equipment *, struct unit *); } equipment; - extern struct equipment *create_equipment(const char *eqname); extern struct equipment *get_equipment(const char *eqname); diff --git a/src/kernel/faction.c b/src/kernel/faction.c index 91c0f9e85..75aa7e26a 100644 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -68,7 +68,6 @@ void free_faction(faction * f) free_messagelist(f->msgs); while (f->battles) { struct bmsg *bm = f->battles; - f->battles = bm->next; if (bm->msgs) free_messagelist(bm->msgs); @@ -77,7 +76,6 @@ void free_faction(faction * f) while (f->groups) { group *g = f->groups; - f->groups = g->next; free_group(g); } @@ -101,7 +99,6 @@ void free_faction(faction * f) faction *get_monsters(void) { static faction *monsters; - static int gamecookie = -1; if (gamecookie != global.cookie) { @@ -111,7 +108,6 @@ faction *get_monsters(void) if (!monsters) { faction *f; - for (f = factions; f; f = f->next) { if (f->flags & FFL_NPC) { return monsters = f; @@ -131,7 +127,6 @@ faction *get_monsters(void) const unit *random_unit_in_faction(const faction * f) { unit *u; - int c = 0, u_nr; for (u = f->units; u; u = u->next) @@ -151,9 +146,7 @@ const unit *random_unit_in_faction(const faction * f) const char *factionname(const faction * f) { typedef char name[OBJECTIDSIZE + 1]; - static name idbuf[8]; - static int nextbuf = 0; char *ibuf = idbuf[(++nextbuf) % 8]; @@ -170,9 +163,7 @@ const char *factionname(const faction * f) int resolve_faction(variant id, void *address) { int result = 0; - faction *f = NULL; - if (id.i != 0) { f = findfaction(id.i); if (f == NULL) { @@ -202,7 +193,6 @@ faction *addfaction(const char *email, const char *password, const struct race * frace, const struct locale * loc, int subscription) { faction *f = calloc(sizeof(faction), 1); - char buf[128]; assert(frace); @@ -231,7 +221,6 @@ faction *addfaction(const char *email, const char *password, f->no = unused_faction_id(); if (rule_region_owners()) { alliance *al = makealliance(f->no, NULL); - setalliance(f, al); } addlist(&factions, f); @@ -246,7 +235,6 @@ faction *addfaction(const char *email, const char *password, unit *addplayer(region * r, faction * f) { unit *u; - char buffer[32]; assert(f->units == NULL); @@ -260,7 +248,6 @@ unit *addplayer(region * r, faction * f) fset(u, UFL_ISNEW); if (f->race == new_race[RC_DAEMON]) { race_t urc; - do { urc = (race_t) (rng_int() % MAXRACES); } while (new_race[urc] == NULL || urc == RC_DAEMON @@ -280,11 +267,9 @@ boolean checkpasswd(const faction * f, const char *passwd, boolean shortp) return false; } - variant read_faction_reference(struct storage * store) { variant id; - id.i = store->r_id(store); return id; } @@ -297,7 +282,6 @@ void write_faction_reference(const faction * f, struct storage *store) void destroyfaction(faction * f) { unit *u = f->units; - faction *ff; if (!f->alive) @@ -309,7 +293,6 @@ void destroyfaction(faction * f) while (f->battles) { struct bmsg *bm = f->battles; - f->battles = bm->next; if (bm->msgs) free_messagelist(bm->msgs); @@ -319,10 +302,8 @@ void destroyfaction(faction * f) while (u) { /* give away your stuff, make zombies if you cannot (quest items) */ int result = gift_items(u, GIFT_FRIENDS | GIFT_PEASANTS); - if (result != 0) { unit *zombie = u; - u = u->nextF; make_zombie(zombie); } else { @@ -330,14 +311,11 @@ void destroyfaction(faction * f) if (!fval(r->terrain, SEA_REGION) && !!playerrace(u->race)) { const race *rc = u->race; - int m = rmoney(r); if ((rc->ec_flags & ECF_REC_ETHEREAL) == 0) { int p = rpeasants(u->region); - int h = rhorses(u->region); - item *itm; /* Personen gehen nur an die Bauern, wenn sie auch von dort @@ -367,7 +345,6 @@ void destroyfaction(faction * f) handle_event(f->attribs, "destroy", f); for (ff = factions; ff; ff = ff->next) { group *g; - ally *sf, *sfn; /* Alle HELFE für die Partei löschen */ @@ -393,11 +370,9 @@ void destroyfaction(faction * f) * have their disguise replaced by ordinary faction hiding. */ if (rule_stealth_faction()) { region *rc; - for (rc = regions; rc; rc = rc->next) { for (u = rc->units; u; u = u->next) { attrib *a = a_find(u->attribs, &at_otherfaction); - if (!a) continue; if (get_otherfaction(a) == f) { @@ -412,7 +387,6 @@ void destroyfaction(faction * f) int get_alliance(const faction * a, const faction * b) { const ally *sf = a->allies; - for (; sf != NULL; sf = sf->next) { if (sf->faction == b) { return sf->status; @@ -424,18 +398,15 @@ int get_alliance(const faction * a, const faction * b) void set_alliance(faction * a, faction * b, int status) { ally **sfp; - sfp = &a->allies; while (*sfp) { ally *sf = *sfp; - if (sf->faction == b) break; sfp = &sf->next; } if (*sfp == NULL) { ally *sf = *sfp = malloc(sizeof(ally)); - sf->next = NULL; sf->status = status; sf->faction = b; @@ -521,7 +492,6 @@ boolean valid_race(const struct faction *f, const struct race *rc) return true; else { const char *str = get_param(f->race->parameters, "other_race"); - if (str) return (boolean) (rc_find(str) == rc); return false; diff --git a/src/kernel/group.c b/src/kernel/group.c index 6fa82dedb..c61966968 100644 --- a/src/kernel/group.c +++ b/src/kernel/group.c @@ -44,15 +44,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define GMAXHASH 2039 static group *ghash[GMAXHASH]; - static int maxgid; static group *new_group(faction * f, const char *name, int gid) { group **gp = &f->groups; - int index = gid % GMAXHASH; - group *g = calloc(sizeof(group), 1); while (*gp) @@ -75,7 +72,6 @@ static void init_group(faction * f, group * g) for (a = f->allies; a; a = a->next) if (a->faction) { ally *ga = calloc(sizeof(ally), 1); - *ga = *a; *an = ga; an = &ga->next; @@ -92,9 +88,7 @@ static group *find_groupbyname(group * g, const char *name) static group *find_group(int gid) { int index = gid % GMAXHASH; - group *g = ghash[index]; - while (g && g->gid != gid) g = g->nexthash; return g; @@ -103,9 +97,7 @@ static group *find_group(int gid) static int read_group(attrib * a, void *owner, struct storage *store) { group *g; - int gid = store->r_int(store); - a->data.v = g = find_group(gid); if (g != 0) { g->members++; @@ -118,7 +110,6 @@ static void write_group(const attrib * a, const void *owner, struct storage *store) { group *g = (group *) a->data.v; - store->w_int(store, g->gid); } @@ -130,9 +121,7 @@ attrib_type at_group = { /* attribute for units assigned to a group */ void free_group(group * g) { int index = g->gid % GMAXHASH; - group **g_ptr = ghash + index; - while (*g_ptr && (*g_ptr)->gid != g->gid) g_ptr = &(*g_ptr)->nexthash; assert(*g_ptr == g); @@ -140,7 +129,6 @@ void free_group(group * g) while (g->allies) { ally *a = g->allies; - g->allies = a->next; free(a); } @@ -158,7 +146,6 @@ void set_group(struct unit *u, struct group *g) if (a) { group *og = (group *) a->data.v; - if (og == g) return; --og->members; @@ -197,7 +184,6 @@ void write_groups(struct storage *store, group * g) { while (g) { ally *a; - store->w_int(store, g->gid); store->w_str(store, g->name); for (a = g->allies; a; a = a->next) { @@ -218,11 +204,8 @@ void read_groups(struct storage *store, faction * f) { for (;;) { ally **pa; - group *g; - int gid; - char buf[1024]; gid = store->r_int(store); @@ -233,9 +216,7 @@ void read_groups(struct storage *store, faction * f) pa = &g->allies; for (;;) { ally *a; - variant fid; - fid.i = store->r_id(store); if (fid.i <= 0) break; diff --git a/src/kernel/item.c b/src/kernel/item.c index ceade10d4..9f56280ea 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -56,9 +56,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include resource_type *resourcetypes; - luxury_type *luxurytypes; - potion_type *potiontypes; #define IMAXHASH 127 @@ -102,11 +100,9 @@ static int res_changepeasants(unit * u, const resource_type * rtype, int delta) int res_changeitem(unit * u, const resource_type * rtype, int delta) { int num; - if (rtype == oldresourcetype[R_STONE] && u->race == new_race[RC_STONEGOLEM] && delta <= 0) { int reduce = delta / GOLEM_STONE; - if (delta % GOLEM_STONE != 0) --reduce; scale_number(u, u->number + reduce); @@ -114,16 +110,13 @@ int res_changeitem(unit * u, const resource_type * rtype, int delta) } else if (rtype == oldresourcetype[R_IRON] && u->race == new_race[RC_IRONGOLEM] && delta <= 0) { int reduce = delta / GOLEM_IRON; - if (delta % GOLEM_IRON != 0) --reduce; scale_number(u, u->number + reduce); num = u->number; } else { const item_type *itype = resource2item(rtype); - item *i; - assert(itype != NULL); i = i_change(&u->items, itype, delta); if (i == NULL) @@ -158,7 +151,6 @@ resource_type *new_resourcetype(const char **names, const char **appearances, if (rtype == NULL) { int i; - rtype = calloc(sizeof(resource_type), 1); for (i = 0; i != 2; ++i) { @@ -182,11 +174,8 @@ resource_type *new_resourcetype(const char **names, const char **appearances, void it_register(item_type * itype) { int hash = hashstring(itype->rtype->_name[0]); - int key = hash % IMAXHASH; - item_type **p_itype = &itemtypes[key]; - while (*p_itype && *p_itype != itype) p_itype = &(*p_itype)->next; if (*p_itype == NULL) { @@ -200,7 +189,6 @@ item_type *new_itemtype(resource_type * rtype, int iflags, int weight, int capacity) { item_type *itype; - assert(resource2item(rtype) == NULL); assert(rtype->flags & RTF_ITEM); @@ -264,7 +252,6 @@ weapon_type *new_weapontype(item_type * itype, return wtype; } - armor_type *new_armortype(item_type * itype, double penalty, double magres, int prot, unsigned int flags) { @@ -305,7 +292,6 @@ potion_type *new_potiontype(item_type * itype, int level) return ptype; } - void rt_register(resource_type * rtype) { resource_type **prtype = &resourcetypes; @@ -339,7 +325,6 @@ const luxury_type *resource2luxury(const resource_type * rtype) { #ifdef AT_LTYPE attrib *a = a_find(rtype->attribs, &at_ltype); - if (a) return (const luxury_type *)a->data.v; return NULL; @@ -352,7 +337,6 @@ const potion_type *resource2potion(const resource_type * rtype) { #ifdef AT_PTYPE attrib *a = a_find(rtype->attribs, &at_ptype); - if (a) return (const potion_type *)a->data.v; return NULL; @@ -364,7 +348,6 @@ const potion_type *resource2potion(const resource_type * rtype) resource_type *rt_find(const char *name) { unsigned int hash = hashstring(name); - resource_type *rtype; for (rtype = resourcetypes; rtype; rtype = rtype->next) { @@ -392,7 +375,6 @@ static const char *it_aliases[][2] = { static const char *it_alias(const char *zname) { int i; - for (i = 0; it_aliases[i][0]; ++i) { if (strcmp(it_aliases[i][0], zname) == 0) return it_aliases[i][1]; @@ -403,11 +385,8 @@ static const char *it_alias(const char *zname) item_type *it_find(const char *zname) { const char *name = it_alias(zname); - unsigned int hash = hashstring(name); - item_type *itype; - unsigned int key = hash % IMAXHASH; for (itype = itemtypes[key]; itype; itype = itype->next) { @@ -453,7 +432,6 @@ item *i_add(item ** pi, item * i) assert(i && i->type && !i->next); while (*pi) { int d = strcmp((*pi)->type->rtype->_name[0], i->type->rtype->_name[0]); - if (d >= 0) break; pi = &(*pi)->next; @@ -472,13 +450,10 @@ item *i_add(item ** pi, item * i) void i_merge(item ** pi, item ** si) { item *i = *si; - while (i) { item *itmp; - while (*pi) { int d = strcmp((*pi)->type->rtype->_name[0], i->type->rtype->_name[0]); - if (d >= 0) break; pi = &(*pi)->next; @@ -502,14 +477,12 @@ item *i_change(item ** pi, const item_type * itype, int delta) assert(itype); while (*pi) { int d = strcmp((*pi)->type->rtype->_name[0], itype->rtype->_name[0]); - if (d >= 0) break; pi = &(*pi)->next; } if (!*pi || (*pi)->type != itype) { item *i; - if (delta == 0) return NULL; i = i_new(itype, delta); @@ -517,7 +490,6 @@ item *i_change(item ** pi, const item_type * itype, int delta) *pi = i; } else { item *i = *pi; - i->number += delta; if (i->number < 0) { log_error(("serious accounting error. number of items is %d.\n", @@ -546,9 +518,7 @@ item *i_remove(item ** pi, item * i) } static item *icache; - static int icache_size; - #define ICACHE_MAX 100 void i_free(item * i) @@ -573,11 +543,9 @@ void i_freeall(item ** i) } } - item *i_new(const item_type * itype, int size) { item *i; - if (icache_size > 0) { i = icache; icache = i->next; @@ -601,7 +569,6 @@ give_horses(unit * s, unit * d, const item_type * itype, int n, { if (d == NULL) { int use = use_pooled(s, item2resource(itype), GET_SLACK, n); - if (use < n) use += use_pooled(s, item2resource(itype), GET_RESERVE | GET_POOLED_SLACK, @@ -618,7 +585,6 @@ give_money(unit * s, unit * d, const item_type * itype, int n, { if (d == NULL) { int use = use_pooled(s, item2resource(itype), GET_SLACK, n); - if (use < n) use += use_pooled(s, item2resource(itype), GET_RESERVE | GET_POOLED_SLACK, @@ -643,9 +609,7 @@ give_money(unit * s, unit * d, const item_type * itype, int n, #define MAXLUXURIES (LASTLUXURY - FIRSTLUXURY) const item_type *olditemtype[MAXITEMS + 1]; - const resource_type *oldresourcetype[MAXRESOURCES + 1]; - const potion_type *oldpotiontype[MAXPOTIONS + 1]; /*** alte items ***/ @@ -653,9 +617,7 @@ const potion_type *oldpotiontype[MAXPOTIONS + 1]; int get_item(const unit * u, item_t it) { const item_type *type = olditemtype[it]; - const item *i = *i_findc(&u->items, type); - if (i) assert(i->number >= 0); return i ? i->number : 0; @@ -664,9 +626,7 @@ int get_item(const unit * u, item_t it) int set_item(unit * u, item_t it, int value) { const item_type *type = olditemtype[it]; - item *i = *i_find(&u->items, type); - if (!i) { i = i_add(&u->items, i_new(type, value)); } else { @@ -681,7 +641,6 @@ use_birthdayamulet(unit * u, const struct item_type *itype, int amount, struct order *ord) { direction_t d; - message *msg = msg_message("meow", ""); unused(ord); @@ -691,7 +650,6 @@ use_birthdayamulet(unit * u, const struct item_type *itype, int amount, add_message(&u->region->msgs, msg); for (d = 0; d < MAXDIRECTIONS; d++) { region *tr = rconnect(u->region, d); - if (tr) add_message(&tr->msgs, msg); } @@ -699,7 +657,6 @@ use_birthdayamulet(unit * u, const struct item_type *itype, int amount, return 0; } - /* t_item::flags */ #define FL_ITEM_CURSED (1<<0) #define FL_ITEM_NOTLOST (1<<1) @@ -715,15 +672,12 @@ use_tacticcrystal(unit * u, const struct item_type *itype, int amount, struct order *ord) { int i; - for (i = 0; i != amount; ++i) { int duration = 1; /* wirkt nur eine Runde */ - float power = 5; /* Widerstand gegen Antimagiesprüche, ist in diesem Fall egal, da der curse für den Kampf gelten soll, der vor den Antimagiezaubern passiert */ curse *c; - double effect; effect = rng_int() % 6 - 1; @@ -784,12 +738,9 @@ mod_dwarves_only(const unit * u, const region * r, skill_t sk, int value) static void init_olditems(void) { item_t i; - #if 0 resource_type *rtype; - const struct locale *lang = find_locale("de"); - assert(lang); #endif @@ -807,7 +758,6 @@ static void init_olditems(void) static int heal(unit * user, int effect) { int req = unit_max_hp(user) * user->number - user->hp; - if (req > 0) { req = MIN(req, effect); effect -= req; @@ -842,9 +792,7 @@ use_healingpotion(struct unit *user, const struct item_type *itype, int amount, struct order *ord) { int effect = amount * 400; - unit *u = user->region->units; - effect = heal(user, effect); while (effect > 0 && u != NULL) { if (u->faction == user->faction) { @@ -886,7 +834,6 @@ use_foolpotion(struct unit *u, int targetno, const struct item_type *itype, int amount, struct order *ord) { unit *target = findunit(targetno); - if (target == NULL || u->region != target->region) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); @@ -912,10 +859,8 @@ use_bloodpotion(struct unit *u, const struct item_type *itype, int amount, change_effect(u, itype->rtype->ptype, 100 * amount); } else { const race *irace = u_irace(u); - if (irace == u->race) { static race *rcfailure; - if (!rcfailure) { rcfailure = rc_find("smurf"); if (!rcfailure) @@ -923,7 +868,6 @@ use_bloodpotion(struct unit *u, const struct item_type *itype, int amount, } if (rcfailure) { trigger *trestore = trigger_changerace(u, u->race, irace); - if (trestore) { int duration = 2 + rng_int() % 8; @@ -975,7 +919,6 @@ use_magicboost(struct unit *user, const struct item_type *itype, int amount, get_pooled(user, itype->rtype, GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, user->number); faction *f = user->faction; - if (user->number > mtoes) { ADDMSG(&user->faction->msgs, msg_message("use_singleperson", "unit item region command", user, itype->rtype, user->region, ord)); @@ -1014,7 +957,6 @@ static void init_oldpotions(void) for (p = 0; p != MAXPOTIONS; ++p) { item_type *itype = it_find(potionnames[p]); - if (itype != NULL) { oldpotiontype[p] = itype->rtype->ptype; } @@ -1022,17 +964,12 @@ static void init_oldpotions(void) } resource_type *r_silver; - resource_type *r_aura; - resource_type *r_permaura; - resource_type *r_unit; - resource_type *r_hp; resource_type *r_silver; - item_type *i_silver; static const char *names[] = { @@ -1048,7 +985,6 @@ static const char *names[] = { void init_resources(void) { static boolean initialized = false; - if (initialized) return; initialized = true; @@ -1083,7 +1019,6 @@ void init_resources(void) int get_money(const unit * u) { const item *i = u->items; - while (i && i->type != i_silver) i = i->next; if (i == NULL) @@ -1094,7 +1029,6 @@ int get_money(const unit * u) int set_money(unit * u, int v) { item **ip = &u->items; - while (*ip && (*ip)->type != i_silver) ip = &(*ip)->next; if ((*ip) == NULL && v) { @@ -1114,7 +1048,6 @@ int set_money(unit * u, int v) int change_money(unit * u, int v) { item **ip = &u->items; - while (*ip && (*ip)->type != i_silver) ip = &(*ip)->next; if ((*ip) == NULL && v) { @@ -1123,7 +1056,6 @@ int change_money(unit * u, int v) } if ((*ip) != NULL) { item *i = *ip; - if (i->number + v != 0) { i->number += v; assert(i->number >= 0); @@ -1134,14 +1066,12 @@ int change_money(unit * u, int v) return 0; } - static local_names *rnames; const resource_type *findresourcetype(const char *name, const struct locale *lang) { local_names *rn = rnames; - variant token; while (rn) { @@ -1151,7 +1081,6 @@ const resource_type *findresourcetype(const char *name, } if (!rn) { const resource_type *rtl = resourcetypes; - rn = calloc(sizeof(local_names), 1); rn->next = rnames; rn->lang = lang; @@ -1178,12 +1107,9 @@ static local_names *inames; void init_itemnames(void) { int i; - for (i = 0; localenames[i]; ++i) { const struct locale *lang = find_locale(localenames[i]); - boolean exist = false; - local_names *in = inames; while (in != NULL) { @@ -1200,15 +1126,11 @@ void init_itemnames(void) if (!exist) { int key; - for (key = 0; key != IMAXHASH; ++key) { const item_type *itl; - for (itl = itemtypes[key]; itl; itl = itl->next) { variant var; - const char *iname = locale_string(lang, itl->rtype->_name[0]); - if (findtoken(&in->names, iname, &var) == E_TOK_NOMATCH || var.v != itl) { var.v = (void *)itl; @@ -1226,7 +1148,6 @@ void init_itemnames(void) const item_type *finditemtype(const char *name, const struct locale *lang) { local_names *in = inames; - variant var; while (in != NULL) { @@ -1265,7 +1186,6 @@ static item *default_spoil(const struct race *rc, int size) if (rng_int() % 100 < RACESPOILCHANCE) { char spoilname[32]; - const item_type *itype; sprintf(spoilname, "%sspoil", rc->_name[0]); diff --git a/src/kernel/item.h b/src/kernel/item.h index 4d9b3a958..d4ce242f2 100644 --- a/src/kernel/item.h +++ b/src/kernel/item.h @@ -108,7 +108,6 @@ extern "C" { resource_mod *modifiers; } resource_limit; - /* bitfield values for item_type::flags */ #define ITF_NONE 0x0000 #define ITF_HERB 0x0001 /* this item is a herb */ diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 597342010..8bfdd4760 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -94,10 +94,8 @@ attrib_type at_reportspell = { static double MagicRegeneration(void) { static double value = -1.0; - if (value < 0) { const char *str = get_param(global.parameters, "magic.regeneration"); - value = str ? atof(str) : 1.0; } return value; @@ -106,10 +104,8 @@ static double MagicRegeneration(void) double MagicPower(void) { static double value = -1.0; - if (value < 0) { const char *str = get_param(global.parameters, "magic.power"); - value = str ? atof(str) : 1.0; } return value; @@ -118,11 +114,8 @@ double MagicPower(void) static int a_readicastle(attrib * a, void *owner, struct storage *store) { icastle_data *data = (icastle_data *) a->data.v; - variant bno; - char token[32]; - store->r_tok_buf(store, token, sizeof(token)); bno.i = store->r_int(store); data->time = store->r_int(store); @@ -139,7 +132,6 @@ static void a_writeicastle(const attrib * a, const void *owner, struct storage *store) { icastle_data *data = (icastle_data *) a->data.v; - store->w_tok(store, data->type->_name); store->w_int(store, data->building->no); store->w_int(store, data->time); @@ -148,12 +140,9 @@ a_writeicastle(const attrib * a, const void *owner, struct storage *store) static int a_ageicastle(struct attrib *a) { icastle_data *data = (icastle_data *) a->data.v; - if (data->time <= 0) { building *b = data->building; - region *r = b->region; - ADDMSG(&r->msgs, msg_message("icastle_dissolve", "building", b)); /* remove_building lets units leave the building */ remove_building(&r->buildings, b); @@ -199,7 +188,6 @@ static void init_mage(attrib * a) static void free_mage(attrib * a) { sc_mage *mage = (sc_mage *) a->data.v; - freelist(mage->spells); free(mage); } @@ -207,7 +195,6 @@ static void free_mage(attrib * a) int FactionSpells(void) { static int rules_factionspells = -1; - if (rules_factionspells < 0) { rules_factionspells = get_param_int(global.parameters, "rules.magic.factionlist", 0); @@ -220,12 +207,10 @@ void read_spells(struct quicklist **slistp, magic_t mtype, { for (;;) { spell *sp; - char spname[64]; if (store->version < SPELLNAME_VERSION) { int i = store->r_int(store); - if (i < 0) break; sp = find_spellbyid(M_NONE, (spellid_t) i); @@ -244,9 +229,7 @@ void read_spells(struct quicklist **slistp, magic_t mtype, static int read_mage(attrib * a, void *owner, struct storage *store) { int i, mtype; - sc_mage *mage = (sc_mage *) a->data.v; - char spname[64]; mtype = store->r_int(store); @@ -255,12 +238,9 @@ static int read_mage(attrib * a, void *owner, struct storage *store) mage->magietyp = (magic_t) mtype; for (i = 0; i != MAXCOMBATSPELLS; ++i) { spell *sp = NULL; - int level = 0; - if (store->version < SPELLNAME_VERSION) { int spid; - spid = store->r_int(store); level = store->r_int(store); if (spid >= 0) { @@ -276,7 +256,6 @@ static int read_mage(attrib * a, void *owner, struct storage *store) } if (sp && level >= 0) { int slot = -1; - if (sp->sptyp & PRECOMBATSPELL) slot = 0; else if (sp->sptyp & COMBATSPELL) @@ -296,12 +275,10 @@ static int read_mage(attrib * a, void *owner, struct storage *store) void write_spells(struct quicklist *slist, struct storage *store) { quicklist *ql; - int qi; for (ql = slist, qi = 0; ql; ql_advance(&ql, &qi, 1)) { spell *sp = (spell *) ql_get(ql, qi); - store->w_tok(store, sp->sname); } store->w_tok(store, "end"); @@ -311,7 +288,6 @@ static void write_mage(const attrib * a, const void *owner, struct storage *store) { int i; - sc_mage *mage = (sc_mage *) a->data.v; store->w_int(store, mage->magietyp); @@ -344,7 +320,6 @@ sc_mage *get_mage(const unit * u) { if (has_skill(u, SK_MAGIC)) { attrib *a = a_find(u->attribs, &at_mage); - if (a) return a->data.v; } @@ -359,13 +334,10 @@ sc_mage *get_mage(const unit * u) * Spruch zu seiner List-of-known-spells hinzugefügt werden. */ - static int read_seenspell(attrib * a, void *owner, struct storage *store) { int i; - spell *sp = NULL; - char token[32]; store->r_tok_buf(store, token, sizeof(token)); @@ -374,7 +346,6 @@ static int read_seenspell(attrib * a, void *owner, struct storage *store) sp = find_spellbyid(M_NONE, (spellid_t) i); } else { int mtype; - mtype = store->r_int(store); sp = find_spell((magic_t) mtype, token); } @@ -390,7 +361,6 @@ static void write_seenspell(const attrib * a, const void *owner, struct storage *store) { const spell *sp = (const spell *)a->data.v; - store->w_tok(store, sp->sname); store->w_int(store, sp->magietyp); } @@ -414,7 +384,6 @@ static boolean already_seen(const faction * f, const spell * sp) static boolean know_school(const faction * f, magic_t school) { static int common = MAXMAGIETYP; - if (f->magiegebiet == school) return true; if (common == MAXMAGIETYP) { @@ -441,7 +410,6 @@ static boolean know_school(const faction * f, magic_t school) static boolean has_spell(quicklist * ql, const spell * sp) { int qi; - return ql_set_find(&ql, &qi, sp) != 0; } @@ -451,14 +419,11 @@ static boolean has_spell(quicklist * ql, const spell * sp) void update_spellbook(faction * f, int level) { spell *commonspells[MAXSPELLS]; - int qi, numspells = 0; - quicklist *ql; for (qi = 0, ql = spells; ql; ql_advance(&ql, &qi, 1)) { spell *sp = (spell *) ql_get(ql, qi); - if (sp->magietyp == M_COMMON && level > f->max_spelllevel && sp->level <= level) { commonspells[numspells++] = sp; @@ -470,14 +435,10 @@ void update_spellbook(faction * f, int level) } while (numspells > 0 && level > f->max_spelllevel) { int i; - for (i = 0; i != COMMONSPELLS; ++i) { int maxspell = numspells; - int spellno = -1; - spell *sp; - do { if (spellno == maxspell) { --maxspell; @@ -500,15 +461,10 @@ void update_spellbook(faction * f, int level) void updatespelllist(unit * u) { int sk = eff_skill(u, SK_MAGIC, u->region); - quicklist *ql = spells; - int qi; - struct sc_mage *mage = get_mage(u); - boolean ismonster = is_monsters(u->faction); - quicklist **dst; if (mage->magietyp == M_GRAY) { @@ -525,7 +481,6 @@ void updatespelllist(unit * u) for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { spell *sp = (spell *) ql_get(ql, qi); - if (sp->level <= sk) { boolean know = u_hasspell(u, sp); @@ -550,7 +505,6 @@ void updatespelllist(unit * u) sc_mage *create_mage(unit * u, magic_t mtyp) { sc_mage *mage; - attrib *a; a = a_find(u->attribs, &at_mage); @@ -592,7 +546,6 @@ int get_combatspelllevel(const unit * u, int nr) assert(nr < MAXCOMBATSPELLS); if (m) { int level = eff_skill(u, SK_MAGIC, u->region); - return MIN(m->combatspells[nr].level, level); } return -1; @@ -619,9 +572,7 @@ const spell *get_combatspell(const unit * u, int nr) void set_combatspell(unit * u, spell * sp, struct order *ord, int level) { sc_mage *m = get_mage(u); - int i = -1; - if (!m) return; @@ -657,9 +608,7 @@ void set_combatspell(unit * u, spell * sp, struct order *ord, int level) void unset_combatspell(unit * u, spell * sp) { sc_mage *m; - int nr = 0; - int i; m = get_mage(u); @@ -721,7 +670,6 @@ void set_spellpoints(unit * u, int sp) int change_spellpoints(unit * u, int mp) { sc_mage *m; - int sp; m = get_mage(u); @@ -773,11 +721,8 @@ static int use_item_aura(const region * r, const unit * u) int max_spellpoints(const region * r, const unit * u) { int sk; - double n, msp; - double potenz = 2.1; - double divisor = 1.2; sk = eff_skill(u, SK_MAGIC, r); @@ -813,7 +758,6 @@ int change_maxspellpoints(unit * u, int csp) int countspells(unit * u, int step) { sc_mage *m; - int count; m = get_mage(u); @@ -839,7 +783,6 @@ int countspells(unit * u, int step) int spellcost(unit * u, const spell * sp) { int k, aura = 0; - int count = countspells(u, 0); for (k = 0; sp->components[k].type; k++) { @@ -861,7 +804,6 @@ int spellcost(unit * u, const spell * sp) static int spl_costtyp(const spell * sp) { int k; - int costtyp = SPC_FIX; for (k = 0; sp->components[k].type; k++) { @@ -890,7 +832,6 @@ static int spl_costtyp(const spell * sp) int eff_spelllevel(unit * u, const spell * sp, int cast_level, int range) { int k, maxlevel, needplevel; - int costtyp = SPC_FIX; for (k = 0; sp->components[k].type; k++) { @@ -947,7 +888,6 @@ int eff_spelllevel(unit * u, const spell * sp, int cast_level, int range) void pay_spell(unit * u, const spell * sp, int cast_level, int range) { int k; - int resuse; for (k = 0; sp->components[k].type; k++) { @@ -966,7 +906,6 @@ void pay_spell(unit * u, const spell * sp, int cast_level, int range) } } - /* ------------------------------------------------------------- */ /* Ein Magier kennt den Spruch und kann sich die Beschreibung anzeigen * lassen, wenn diese in seiner Spruchliste steht. Zaubern muss er ihn @@ -976,7 +915,6 @@ void pay_spell(unit * u, const spell * sp, int cast_level, int range) boolean knowsspell(const region * r, const unit * u, const spell * sp) { sc_mage *mage; - /* Ist überhaupt ein gültiger Spruch angegeben? */ if (!sp || sp->id == 0) { return false; @@ -1016,9 +954,7 @@ boolean cancast(unit * u, const spell * sp, int level, int range, struct order * ord) { int k; - int itemanz; - resource *reslist = NULL; if (knowsspell(u->region, u, sp) == false) { @@ -1036,7 +972,6 @@ cancast(unit * u, const spell * sp, int level, int range, struct order * ord) for (k = 0; sp->components[k].type; ++k) { if (sp->components[k].amount > 0) { const resource_type *rtype = sp->components[k].type; - int itemhave; /* Die Kosten für Aura sind auch von der Zahl der bereits @@ -1062,7 +997,6 @@ cancast(unit * u, const spell * sp, int level, int range, struct order * ord) itemhave = get_pooled(u, rtype, GET_DEFAULT, itemanz); if (itemhave < itemanz) { resource *res = malloc(sizeof(resource)); - res->number = itemanz - itemhave; res->type = rtype; res->next = reslist; @@ -1094,9 +1028,7 @@ spellpower(region * r, unit * u, const spell * sp, int cast_level, struct order *ord) { curse *c; - double force = cast_level; - int elf_power = -1; if (sp == NULL) { @@ -1104,9 +1036,7 @@ spellpower(region * r, unit * u, const spell * sp, int cast_level, } else { /* Bonus durch Magieturm und gesegneten Steinkreis */ struct building *b = inside_building(u); - const struct building_type *btype = b ? b->type : NULL; - if (btype && btype->flags & BTF_MAGIC) ++force; } @@ -1124,7 +1054,6 @@ spellpower(region * r, unit * u, const spell * sp, int cast_level, c = get_curse(r->attribs, ct_find("antimagiczone")); if (curse_active(c)) { unit *mage = c->magician; - force -= curse_geteffect(c); curse_changevigour(&r->attribs, c, (float)-cast_level); cmistake(u, ord, 185, MSG_MAGIC); @@ -1143,7 +1072,6 @@ spellpower(region * r, unit * u, const spell * sp, int cast_level, c = get_curse(r->attribs, ct_find("fumble")); if (curse_active(c)) { unit *mage = c->magician; - force -= curse_geteffect(c); curse_changevigour(&u->attribs, c, -1); cmistake(u, ord, 185, MSG_MAGIC); @@ -1169,7 +1097,6 @@ spellpower(region * r, unit * u, const spell * sp, int cast_level, static int farcasting(unit * magician, region * r) { int dist; - int mult; if (!r) { @@ -1190,7 +1117,6 @@ static int farcasting(unit * magician, region * r) return mult; } - /* ------------------------------------------------------------- */ /* Antimagie - Magieresistenz */ /* ------------------------------------------------------------- */ @@ -1200,14 +1126,11 @@ static int farcasting(unit * magician, region * r) double magic_resistance(unit * target) { attrib *a; - curse *c; - int n; /* Bonus durch Rassenmagieresistenz */ double probability = target->race->magres; - assert(target->number > 0); /* Magier haben einen Resistenzbonus vom Magietalent * 5% */ @@ -1228,7 +1151,6 @@ double magic_resistance(unit * target) a = a_find(target->region->attribs, &at_curse); while (a && a->type == &at_curse) { curse *c = (curse *) a->data.v; - unit *mage = c->magician; if (mage != NULL) { @@ -1253,7 +1175,6 @@ double magic_resistance(unit * target) /* Bonus durch Gebäude */ { struct building *b = inside_building(target); - const struct building_type *btype = b ? b->type : NULL; /* gesegneter Steinkreis gibt 30% dazu */ @@ -1288,16 +1209,13 @@ target_resists_magic(unit * magician, void *obj, int objtyp, int t_bonus) case TYP_UNIT: { int at, pa = 0; - skill *sv; - unit *u = (unit *) obj; at = effskill(magician, SK_MAGIC); for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { int sk = effskill(u, sv->id); - if (pa < sk) pa = sk; } @@ -1369,13 +1287,9 @@ boolean fumble(region * r, unit * u, const spell * sp, int cast_grade) * */ int rnd = 0; - double x = (double)cast_grade / (double)eff_skill(u, SK_MAGIC, r); - int patzer = (int)(((double)x * 40.0) - 20.0); - struct building *b = inside_building(u); - const struct building_type *btype = b ? b->type : NULL; if (btype) @@ -1424,17 +1338,11 @@ static void patzer(castorder * co) static void do_fumble(castorder * co) { curse *c; - region *r = co->rt; - unit *u = co->magician.u; - const spell *sp = co->sp; - int level = co->level; - int duration; - double effect; ADDMSG(&u->faction->msgs, msg_message("patzer", "unit region spell", @@ -1460,7 +1368,6 @@ static void do_fumble(castorder * co) if (chance(0.7)) { const item_type *it_toadslime = it_find("toadslime"); - if (it_toadslime != NULL) { t_add(&trestore, trigger_giveitem(u, it_toadslime, 1)); } @@ -1536,11 +1443,8 @@ static void do_fumble(castorder * co) static double regeneration(unit * u) { int sk; - double aura, d; - double potenz = 1.5; - double divisor = 2.0; sk = effskill(u, SK_MAGIC); @@ -1562,15 +1466,10 @@ static double regeneration(unit * u) void regeneration_magiepunkte(void) { region *r; - unit *u; - int aura, auramax; - double reg_aura; - int regen; - double mod; for (r = regions; r; r = r->next) { @@ -1580,9 +1479,7 @@ void regeneration_magiepunkte(void) auramax = max_spellpoints(r, u); if (aura < auramax) { struct building *b = inside_building(u); - const struct building_type *btype = b ? b->type : NULL; - reg_aura = regeneration(u); /* Magierturm erhöht die Regeneration um 75% */ @@ -1672,7 +1569,6 @@ message *msg_unitnotfound(const struct unit * mage, struct order * ord, { /* Einheit nicht gefunden */ char tbuf[20]; - const char *uid; if (spobj->typ == SPP_UNIT) { @@ -1691,7 +1587,6 @@ verify_unit(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) { unit *u = NULL; - switch (spobj->typ) { case SPP_UNIT: u = findunit(spobj->data.i); @@ -1741,13 +1636,9 @@ static void verify_targets(castorder * co, int *invalid, int *resist, int *success) { unit *mage = co->magician.u; - const spell *sp = co->sp; - region *target_r = co->rt; - spellparameter *sa = co->par; - int i; *invalid = 0; @@ -1784,13 +1675,9 @@ verify_targets(castorder * co, int *invalid, int *resist, int *success) /* Nun folgen die Tests auf cansee und Magieresistenz */ for (i = 0; i < sa->length; i++) { spllprm *spobj = sa->param[i]; - unit *u; - building *b; - ship *sh; - region *tr; if (spobj->flag == TARGET_NOTFOUND) @@ -1876,7 +1763,6 @@ verify_targets(castorder * co, int *invalid, int *resist, int *success) if ((sp->sptyp & REGIONSPELL)) { /* Zielobjekt Region anlegen */ spllprm *spobj = malloc(sizeof(spllprm)); - spobj->flag = 0; spobj->typ = SPP_REGION; spobj->data.r = target_r; @@ -1936,7 +1822,6 @@ static void free_spellparameter(spellparameter * pa) static int addparam_string(const char *const param[], spllprm ** spobjp) { spllprm *spobj = *spobjp = malloc(sizeof(spllprm)); - assert(param[0]); spobj->flag = 0; @@ -1948,7 +1833,6 @@ static int addparam_string(const char *const param[], spllprm ** spobjp) static int addparam_int(const char *const param[], spllprm ** spobjp) { spllprm *spobj = *spobjp = malloc(sizeof(spllprm)); - assert(param[0]); spobj->flag = 0; @@ -1960,7 +1844,6 @@ static int addparam_int(const char *const param[], spllprm ** spobjp) static int addparam_ship(const char *const param[], spllprm ** spobjp) { spllprm *spobj = *spobjp = malloc(sizeof(spllprm)); - int id = atoi36((const char *)param[0]); spobj->flag = 0; @@ -1972,7 +1855,6 @@ static int addparam_ship(const char *const param[], spllprm ** spobjp) static int addparam_building(const char *const param[], spllprm ** spobjp) { spllprm *spobj = *spobjp = malloc(sizeof(spllprm)); - int id = atoi36((const char *)param[0]); spobj->flag = 0; @@ -1992,11 +1874,8 @@ addparam_region(const char *const param[], spllprm ** spobjp, const unit * u, return -1; } else { int tx = atoi((const char *)param[0]), ty = atoi((const char *)param[1]); - int x = rel_to_abs(pl, u->faction, tx, 0); - int y = rel_to_abs(pl, u->faction, ty, 1); - region *rt; pnormalize(&x, &y, pl); @@ -2017,15 +1896,12 @@ addparam_region(const char *const param[], spllprm ** spobjp, const unit * u, } } - static int addparam_unit(const char *const param[], spllprm ** spobjp, const unit * u, order * ord) { spllprm *spobj; - int i = 0; - sppobj_t otype = SPP_UNIT; *spobjp = NULL; @@ -2051,15 +1927,10 @@ static spellparameter *add_spellparameter(region * target_r, unit * u, const char *syntax, const char *const param[], int size, struct order *ord) { boolean fail = false; - int i = 0; - int p = 0; - const char *c; - spellparameter *par; - int minlen = 0; for (c = syntax; *c != 0; ++c) { @@ -2093,11 +1964,8 @@ static spellparameter *add_spellparameter(region * target_r, unit * u, while (!fail && *c && i < size && param[i] != NULL) { spllprm *spobj = NULL; - param_t pword; - int j = -1; - switch (*c) { case '?': /* tja. das sollte moeglichst nur am Ende passieren, @@ -2265,7 +2133,6 @@ typedef struct familiar_data { boolean is_familiar(const unit * u) { attrib *a = a_find(u->attribs, &at_familiarmage); - return i2b(a != NULL); } @@ -2273,7 +2140,6 @@ static void a_write_unit(const attrib * a, const void *owner, struct storage *store) { unit *u = (unit *) a->data.v; - write_unit_reference(u, store); } @@ -2283,9 +2149,7 @@ static int sm_familiar(const unit * u, const region * r, skill_t sk, int value) return value; else { int mod; - unit *familiar = get_familiar(u); - if (familiar == NULL) { /* the familiar is dead */ return value; @@ -2302,19 +2166,15 @@ static 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); - 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; } @@ -2338,9 +2198,7 @@ static void set_familiar(unit * mage, unit * familiar) void remove_familiar(unit * mage) { attrib *a = a_find(mage->attribs, &at_familiar); - attrib *an; - skillmod_data *smd; if (a != NULL) { @@ -2360,9 +2218,7 @@ boolean create_newfamiliar(unit * mage, unit * familiar) { /* 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); if (afam == NULL) { @@ -2383,16 +2239,13 @@ boolean create_newfamiliar(unit * mage, unit * familiar) 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; } @@ -2402,15 +2255,11 @@ boolean create_newfamiliar(unit * mage, unit * familiar) static int resolve_familiar(variant data, void *addr) { unit *familiar; - int result = resolve_unit(data, &familiar); - if (result == 0 && familiar) { attrib *a = a_find(familiar->attribs, &at_familiarmage); - if (a != NULL && a->data.v) { unit *mage = (unit *) a->data.v; - set_familiar(mage, familiar); } } @@ -2478,7 +2327,6 @@ static void set_clone(unit * mage, unit * clone) unit *has_clone(unit * mage) { attrib *a = a_find(mage->attribs, &at_clone); - if (a) return (unit *) a->data.v; return NULL; @@ -2487,15 +2335,11 @@ unit *has_clone(unit * mage) static int resolve_clone(variant data, void *addr) { unit *clone; - int result = resolve_unit(data, &clone); - if (result == 0 && clone) { attrib *a = a_find(clone->attribs, &at_clonemage); - if (a != NULL && a->data.v) { unit *mage = (unit *) a->data.v; - set_clone(mage, clone); } } @@ -2518,15 +2362,11 @@ static int read_clone(attrib * a, void *owner, struct storage *store) static int resolve_mage(variant data, void *addr) { unit *mage; - int result = resolve_unit(data, &mage); - if (result == 0 && mage) { attrib *a = a_find(mage->attribs, &at_familiar); - if (a != NULL && a->data.v) { unit *familiar = (unit *) a->data.v; - set_familiar(mage, familiar); } } @@ -2548,7 +2388,6 @@ static int age_unit(attrib * a) /* if unit is gone or dead, remove the attribute */ { unit *u = (unit *) a->data.v; - return (u != NULL && u->number > 0) ? AT_AGE_KEEP : AT_AGE_REMOVE; } @@ -2595,10 +2434,8 @@ attrib_type at_clone = { unit *get_familiar(const unit * u) { attrib *a = a_find(u->attribs, &at_familiar); - if (a != NULL) { unit *u = (unit *) a->data.v; - if (u->number > 0) return u; } @@ -2608,10 +2445,8 @@ unit *get_familiar(const unit * u) unit *get_familiar_mage(const unit * u) { attrib *a = a_find(u->attribs, &at_familiarmage); - if (a != NULL) { unit *u = (unit *) a->data.v; - if (u->number > 0) return u; } @@ -2621,10 +2456,8 @@ unit *get_familiar_mage(const unit * u) unit *get_clone(const unit * u) { attrib *a = a_find(u->attribs, &at_clone); - if (a != NULL) { unit *u = (unit *) a->data.v; - if (u->number > 0) return u; } @@ -2634,10 +2467,8 @@ unit *get_clone(const unit * u) unit *get_clone_mage(const unit * u) { attrib *a = a_find(u->attribs, &at_clonemage); - if (a != NULL) { unit *u = (unit *) a->data.v; - if (u->number > 0) return u; } @@ -2661,19 +2492,12 @@ static boolean is_moving_ship(const region * r, const ship * sh) static castorder *cast_cmd(unit * u, order * ord) { region *r = u->region; - region *target_r = r; - int level, range; - unit *familiar = NULL, *mage = u; - const char *s; - spell *sp; - plane *pl; - spellparameter *args = NULL; if (LongHunger(u)) { @@ -2693,7 +2517,6 @@ static castorder *cast_cmd(unit * u, order * ord) /* für Syntax ' STUFE x REGION y z ' */ if (findparam(s, u->faction->locale) == P_LEVEL) { int p = getint(); - level = MIN(p, level); if (level < 1) { /* Fehler "Das macht wenig Sinn" */ @@ -2704,11 +2527,8 @@ static castorder *cast_cmd(unit * u, order * ord) } if (findparam(s, u->faction->locale) == P_REGION) { int t_x = getint(); - int t_y = getint(); - plane *pl = getplane(u->region); - t_x = rel_to_abs(pl, u->faction, t_x, 0); t_y = rel_to_abs(pl, u->faction, t_y, 1); pnormalize(&t_x, &t_y, pl); @@ -2725,7 +2545,6 @@ static castorder *cast_cmd(unit * u, order * ord) * hier nach REGION nochmal auf STUFE prüfen */ if (findparam(s, u->faction->locale) == P_LEVEL) { int p = getint(); - level = MIN(p, level); if (level < 1) { /* Fehler "Das macht wenig Sinn" */ @@ -2814,7 +2633,6 @@ static castorder *cast_cmd(unit * u, order * ord) /* Stufenangabe bei nicht Stufenvariierbaren Sprüchen abfangen */ if (!(sp->sptyp & SPELLLEVEL)) { int ilevel = eff_skill(u, SK_MAGIC, u->region); - if (ilevel != level) { level = ilevel; ADDMSG(&u->faction->msgs, msg_message("spellfail::nolevel", @@ -2858,9 +2676,7 @@ static castorder *cast_cmd(unit * u, order * ord) /* Weitere Argumente zusammenbasteln */ if (sp->parameter) { char **params = malloc(2 * sizeof(char *)); - int p = 0, size = 2; - for (;;) { s = getstrtoken(); if (*s == 0) @@ -2908,18 +2724,14 @@ static castorder *cast_cmd(unit * u, order * ord) void magic(void) { region *r; - int rank; - castorder *co; - spellrank spellranks[MAX_SPELLRANK]; memset(spellranks, 0, sizeof(spellranks)); for (r = regions; r; r = r->next) { unit *u; - for (u = r->units; u; u = u->next) { order *ord; @@ -2937,11 +2749,9 @@ void magic(void) for (ord = u->orders; ord; ord = ord->next) { if (get_keyword(ord) == K_CAST) { castorder *co = cast_cmd(u, ord); - fset(u, UFL_LONGACTION | UFL_NOTMOVING); if (co) { const spell *sp = co->sp; - add_castorder(&spellranks[sp->rank], co); } } @@ -2959,15 +2769,10 @@ void magic(void) for (rank = 0; rank < MAX_SPELLRANK; rank++) { for (co = spellranks[rank].begin; co; co = co->next) { order *ord = co->order; - int invalid, resist, success, cast_level = co->level; - boolean fumbled = false; - unit *u = co->magician.u; - const spell *sp = co->sp; - region *target_r = co->rt; /* reichen die Komponenten nicht, wird der Level reduziert. */ @@ -3054,7 +2859,6 @@ void magic(void) /* Sind alle Zauber gesprochen gibts Erfahrung */ for (r = regions; r; r = r->next) { unit *u; - for (u = r->units; u; u = u->next) { if (is_mage(u) && countspells(u, 0) > 0) { produceexp(u, SK_MAGIC, u->number); diff --git a/src/kernel/magic.h b/src/kernel/magic.h index 1375f88c8..74cd5eb33 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -242,7 +242,6 @@ extern "C" { int time; } icastle_data; - /* ------------------------------------------------------------- */ /* Kommentare: * @@ -295,7 +294,6 @@ extern "C" { * werden */ - /* Magiepunkte */ int get_spellpoints(const struct unit *u); /* Gibt die aktuelle Anzahl der Magiepunkte der Einheit zurück */ @@ -316,7 +314,6 @@ extern "C" { int cast_level); /* true, wenn der Zauber misslingt, bei false gelingt der Zauber */ - typedef struct spellrank { struct castorder *begin; struct castorder **end; @@ -363,7 +360,6 @@ extern "C" { /* gibt false zurück, wenn der Zauber gelingt, true, wenn das Ziel * widersteht */ - /* Sprüche in der struct region */ /* (sind in curse) */ extern struct unit *get_familiar(const struct unit *u); diff --git a/src/kernel/message.c b/src/kernel/message.c index 75528d3fd..c7ca71b06 100644 --- a/src/kernel/message.c +++ b/src/kernel/message.c @@ -62,7 +62,6 @@ arg_set(variant args[], const message_type * mtype, const char *buffer, variant v) { int i; - for (i = 0; i != mtype->nparameters; ++i) { if (!strcmp(buffer, mtype->pnames[i])) break; @@ -80,17 +79,11 @@ struct message *msg_feedback(const struct unit *u, struct order *ord, const char *name, const char *sig, ...) { va_list marker; - const message_type *mtype = mt_find(name); - char paramname[64]; - const char *ic = sig; - variant args[16]; - variant var; - memset(args, 0, sizeof(args)); if (ord == NULL) @@ -114,7 +107,6 @@ struct message *msg_feedback(const struct unit *u, struct order *ord, ic++; while (*ic) { char *oc = paramname; - int i; while (isalnum(*ic)) @@ -150,15 +142,10 @@ message *msg_message(const char *name, const char *sig, ...) /* msg_message("oops_error", "unit region command", u, r, cmd) */ { va_list marker; - const message_type *mtype = mt_find(name); - char paramname[64]; - const char *ic = sig; - variant args[16]; - memset(args, 0, sizeof(args)); if (!mtype) { @@ -174,7 +161,6 @@ message *msg_message(const char *name, const char *sig, ...) ic++; while (*ic) { char *oc = paramname; - int i; while (isalnum(*ic)) @@ -270,7 +256,6 @@ void addmessage(region * r, faction * f, const char *s, msg_t mtype, int level) void cmistake(const unit * u, struct order *ord, int mno, int mtype) { static char msgname[20]; - unused(mtype); if (is_monsters(u->faction)) @@ -284,10 +269,8 @@ extern unsigned int new_hashstring(const char *s); void free_messagelist(message_list * msgs) { struct mlist **mlistptr = &msgs->begin; - while (*mlistptr) { struct mlist *ml = *mlistptr; - *mlistptr = ml->next; msg_release(ml->msg); free(ml); @@ -299,7 +282,6 @@ message *add_message(message_list ** pm, message * m) { if (!lomem && m != NULL) { struct mlist *mnew = malloc(sizeof(struct mlist)); - if (*pm == NULL) { *pm = malloc(sizeof(message_list)); (*pm)->end = &(*pm)->begin; diff --git a/src/kernel/move.c b/src/kernel/move.c index a3b1219e3..094fdf97d 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -97,14 +97,11 @@ get_followers(unit * target, region * r, const region_list * route_end, follower ** followers) { unit *uf; - for (uf = r->units; uf; uf = uf->next) { if (fval(uf, UFL_FOLLOWING) && !fval(uf, UFL_NOTMOVING)) { const attrib *a = a_findc(uf->attribs, &at_follow); - if (a && a->data.v == target) { follower *fnew = malloc(sizeof(follower)); - fnew->uf = uf; fnew->ut = target; fnew->route_end = route_end; @@ -147,7 +144,6 @@ static void shiptrail_write(const attrib * a, const void *owner, struct storage *store) { traveldir *t = (traveldir *) (a->data.v); - store->w_int(store, t->no); store->w_int(store, t->dir); store->w_int(store, t->age); @@ -195,7 +191,6 @@ static boolean entrance_allowed(const struct unit *u, const struct region *r) { #ifdef REGIONOWNERS faction *owner = region_get_owner(r); - if (owner == NULL || u->faction == owner) return true; if (alliedfaction(rplane(r), owner, u->faction, HELP_TRAVEL)) @@ -209,7 +204,6 @@ static boolean entrance_allowed(const struct unit *u, const struct region *r) int personcapacity(const unit * u) { int cap = u->race->weight + u->race->capacity; - return cap; } @@ -228,12 +222,10 @@ get_transporters(const item * itm, int *p_animals, int *p_acap, int *p_vehicles, int *p_vcap) { int vehicles = 0, vcap = 0; - int animals = 0, acap = 0; for (; itm != NULL; itm = itm->next) { const item_type *itype = itm->type; - if (itype->capacity > 0) { if (itype->flags & ITF_ANIMAL) { animals += itm->number; @@ -260,7 +252,6 @@ get_transporters(const item * itm, int *p_animals, int *p_acap, int *p_vehicles, static int ridingcapacity(unit * u) { int vehicles = 0, vcap = 0; - int animals = 0, acap = 0; get_transporters(u->items, &animals, &acap, &vehicles, &vcap); @@ -282,11 +273,8 @@ static int ridingcapacity(unit * u) int walkingcapacity(const struct unit *u) { int n, tmp, people, pferde_fuer_wagen; - int wagen_ohne_pferde, wagen_mit_pferden, wagen_mit_trollen; - int vehicles = 0, vcap = 0; - int animals = 0, acap = 0; get_transporters(u->items, &animals, &acap, &vehicles, &vcap); @@ -326,7 +314,6 @@ int walkingcapacity(const struct unit *u) tmp = get_effect(u, oldpotiontype[P_STRONG]); if (tmp > 0) { int horsecap = olditemtype[I_HORSE]->capacity; - if (tmp > people) tmp = people; n += tmp * (horsecap - personcapacity(u)); @@ -348,9 +335,7 @@ enum { static int canwalk(unit * u) { int maxwagen, maxpferde; - int vehicles = 0, vcap = 0; - int animals = 0, acap = 0; /* workaround: monsters are too stupid to drop items, therefore they have @@ -424,15 +409,10 @@ boolean canswim(unit * u) static int canride(unit * u) { int horses = 0, maxhorses, unicorns = 0, maxunicorns; - int skill = effskill(u, SK_RIDING); - item *itm; - static const item_type *it_horse = 0; - static const item_type *it_elvenhorse = 0; - static const item_type *it_charger = 0; if (it_horse == 0) { @@ -478,9 +458,7 @@ static boolean cansail(const region * r, ship * sh) return false; } else { int n = 0, p = 0; - int mweight = shipcapacity(sh); - int mcabins = sh->type->cabins; getshipweight(sh, &n, &p); @@ -496,7 +474,6 @@ static boolean cansail(const region * r, ship * sh) int enoughsailors(const ship * sh, const region * r) { int n; - unit *u; n = 0; @@ -513,7 +490,6 @@ int enoughsailors(const ship * sh, const region * r) static ship *do_maelstrom(region * r, unit * u) { int damage; - ship *sh = u->ship; damage = rng_int() % 75 + rng_int() % 75 - eff_skill(u, SK_SAILING, r) * 4; @@ -564,14 +540,12 @@ static void leave_trail(ship * sh, region * from, region_list * route) while (route != NULL) { region *rn = route->data; - direction_t dir = reldirection(r, rn); /* TODO: we cannot leave a trail into special directions * if we use this kind of direction-attribute */ if (dir < MAXDIRECTIONS && dir >= 0) { traveldir *td = NULL; - attrib *a = a_find(r->attribs, &at_shiptrail); while (a != NULL && a->type == &at_shiptrail) { @@ -609,9 +583,7 @@ mark_travelthru(const unit * u, region * r, const region_list * route, ship *move_ship(ship * sh, region * from, region * to, region_list * route) { unit **iunit = &from->units; - unit **ulist = &to->units; - boolean trail = (route == NULL); if (from != to) { @@ -625,7 +597,6 @@ ship *move_ship(ship * sh, region * from, region * to, region_list * route) while (*iunit != NULL) { unit *u = *iunit; - assert(u->region == from); if (u->ship == sh) { @@ -660,7 +631,6 @@ static boolean is_freezing(const unit * u) static boolean ship_allowed(const struct ship *sh, const region * r) { int c = 0; - static const building_type *bt_harbour = NULL; if (bt_harbour == NULL) @@ -676,7 +646,6 @@ static boolean ship_allowed(const struct ship *sh, const region * r) if (is_freezing(u)) { unit *captain = shipowner(sh); - if (captain) { ADDMSG(&captain->faction->msgs, msg_message("detectforbidden", "unit region", u, r)); @@ -721,7 +690,6 @@ static void set_coast(ship * sh, region * r, region * rnext) static float damage_drift(void) { static float value = -1.0F; - if (value < 0) { value = get_param_flt(global.parameters, "rules.ship.damage_drift", 0.02F); } @@ -734,18 +702,12 @@ static void drifting_ships(region * r) if (fval(r->terrain, SEA_REGION)) { ship **shp = &r->ships; - while (*shp) { ship *sh = *shp; - region *rnext = NULL; - region_list *route = NULL; - unit *firstu = NULL, *captain; - int d_offset; - direction_t dir = 0; if (sh->type->fishing > 0) { @@ -783,7 +745,6 @@ static void drifting_ships(region * r) d_offset = rng_int() % MAXDIRECTIONS; for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn; - dir = (direction_t) ((d + d_offset) % MAXDIRECTIONS); rn = rconnect(r, dir); if (rn != NULL && fval(rn->terrain, SAIL_INTO) && ship_allowed(sh, rn)) { @@ -808,9 +769,7 @@ static void drifting_ships(region * r) if (firstu != NULL) { unit *u, *lastu = NULL; - message *msg = msg_message("ship_drift", "ship dir", sh, dir); - for (u = firstu; u; u = u->next) { if (u->ship == sh && !fval(u->faction, FFL_MARK)) { fset(u->faction, FFL_MARK); @@ -871,11 +830,8 @@ static void caught_target(region * r, unit * u) static unit *bewegung_blockiert_von(unit * reisender, region * r) { unit *u; - int perception = 0; - boolean contact = false; - unit *guard = NULL; if (fval(reisender->race, RCF_ILLUSIONARY)) @@ -883,7 +839,6 @@ static unit *bewegung_blockiert_von(unit * reisender, region * r) for (u = r->units; u && !contact; u = u->next) { if (is_guard(u, GUARD_TRAVELTHRU)) { int sk = eff_skill(u, SK_PERCEPTION, r); - if (invisible(reisender, u) >= reisender->number) continue; if (u->faction == reisender->faction) @@ -900,7 +855,6 @@ static unit *bewegung_blockiert_von(unit * reisender, region * r) } if (!contact && guard) { double prob = 0.3; /* 30% base chance */ - prob += 0.1 * (perception - eff_stealth(reisender, r)); prob += 0.1 * MIN(guard->number, get_item(guard, I_AMULET_OF_TRUE_SEEING)); @@ -937,10 +891,8 @@ static boolean is_guardian_r(const unit * guard) /* if region_owners exist then they may be guardians: */ if (guard->building && rule_region_owners() && fval(guard, UFL_OWNER)) { faction *owner = region_get_owner(guard->region); - if (owner == guard->faction) { building *bowner = largestbuilding(guard->region, &cmp_taxes, false); - if (bowner == guard->building) { return true; } @@ -965,11 +917,8 @@ boolean is_guard(const struct unit * u, int mask) unit *is_guarded(region * r, unit * u, unsigned int mask) { unit *u2 = NULL; - int i, noguards = 1; - static unit *guardcache[MAXGUARDCACHE], *lastguard; /* STATIC_XCALL: used across calls */ - static int gamecookie = -1; if (!fval(r, RF_GUARDED)) { @@ -993,7 +942,6 @@ unit *is_guarded(region * r, unit * u, unsigned int mask) for (i = 0; i != MAXGUARDCACHE; ++i) { unit *guard = guardcache[i]; - if (guard && guard != lastguard && guard->region == r) { noguards = 0; if (is_guardian_u(guard, u, mask)) { @@ -1053,21 +1001,13 @@ static const char *shortdirections[MAXDIRECTIONS] = { static void cycle_route(order * ord, unit * u, int gereist) { int bytes, cm = 0; - char tail[1024], *bufp = tail; - char neworder[2048]; - const char *token; - direction_t d = NODIRECTION; - boolean paused = false; - boolean pause; - order *norder; - size_t size = sizeof(tail) - 1; if (get_keyword(ord) != K_ROUTE) @@ -1080,7 +1020,6 @@ static void cycle_route(order * ord, unit * u, int gereist) neworder[0] = 0; for (cm = 0;; ++cm) { const struct locale *lang = u->faction->locale; - pause = false; token = getstrtoken(); d = finddirection(token, lang); @@ -1094,7 +1033,6 @@ static void cycle_route(order * ord, unit * u, int gereist) assert(!pause); if (!pause) { const char *loc = LOC(lang, shortdirections[d]); - if (bufp != tail) { bytes = (int)strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) @@ -1108,7 +1046,6 @@ static void cycle_route(order * ord, unit * u, int gereist) break; else if (cm == gereist && !paused && pause) { const char *loc = LOC(lang, parameters[P_PAUSE]); - bytes = (int)strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -1209,7 +1146,6 @@ static void init_transportation(void) if (!fval(r->terrain, SEA_REGION)) { for (u = r->units; u; u = u->next) { order *ord; - int w = 0; for (ord = u->orders; ord; ord = ord->next) { @@ -1244,7 +1180,6 @@ static boolean roadto(const region * r, direction_t dir) /* wenn es hier genug strassen gibt, und verbunden ist, und es dort * genug strassen gibt, dann existiert eine strasse in diese richtung */ region *r2; - static const curse_type *roads_ct = NULL; if (dir >= MAXDIRECTIONS || dir < 0) @@ -1277,14 +1212,10 @@ static const region_list *cap_route(region * r, const region_list * route, const region_list * route_end, int speed) { region *current = r; - int moves = speed; - const region_list *iroute = route; - while (iroute != route_end) { region *next = iroute->data; - direction_t reldir = reldirection(current, next); /* adjust the range of the unit */ @@ -1308,7 +1239,6 @@ static region *next_region(unit * u, region * current, region * next) while (b != NULL) { if (b->type->move) { region *rto = b->type->move(b, u, current, next, true); - if (rto != next) { /* the target region was changed (wisps, for example). check the * new target region for borders */ @@ -1326,10 +1256,8 @@ static const region_list *reroute(unit * u, const region_list * route, const region_list * route_end) { region *current = u->region; - while (route != route_end) { region *next = next_region(u, current, route->data); - if (next != route->data) break; route = route->next; @@ -1340,18 +1268,13 @@ static const region_list *reroute(unit * u, const region_list * route, static void make_route(unit * u, order * ord, region_list ** routep) { region_list **iroute = routep; - region *current = u->region; - region *next = NULL; - const char *token = getstrtoken(); - int error = movewhere(u, token, current, &next); if (error != E_MOVE_OK) { message *msg = movement_error(u, token, ord, error); - if (msg != NULL) { add_message(&u->faction->msgs, msg); msg_release(msg); @@ -1377,7 +1300,6 @@ static void make_route(unit * u, order * ord, region_list ** routep) error = movewhere(u, token, current, &next); if (error) { message *msg = movement_error(u, token, ord, error); - if (msg != NULL) { add_message(&u->faction->msgs, msg); msg_release(msg); @@ -1399,11 +1321,8 @@ static void make_route(unit * u, order * ord, region_list ** routep) static int movement_speed(unit * u) { int mp; - static const curse_type *speed_ct; - static boolean init = false; - double dk = u->race->speed; assert(u->number); @@ -1423,10 +1342,8 @@ static int movement_speed(unit * u) } if (speed_ct) { curse *c = get_curse(u->attribs, speed_ct); - if (c != NULL) { int men = get_cursedmen(u, c); - dk *= 1.0 + (double)men / (double)u->number; } } @@ -1460,7 +1377,6 @@ static int movement_speed(unit * u) if (mp * dk <= BP_WALKING * u->race->speed && is_astral(u->region) && is_mage(u)) { sc_mage *mage = get_mage(u); - if (mage->magietyp == M_TYBIED || mage->magietyp == M_ILLAUN) { mp *= 2; } @@ -1483,7 +1399,6 @@ static arg_regions *var_copy_regions(const region_list * begin, int size) if (size > 0) { int i = 0; - arg_regions *dst = (arg_regions *) malloc(sizeof(arg_regions) + sizeof(region *) * size); dst->nregions = size; @@ -1496,33 +1411,25 @@ static arg_regions *var_copy_regions(const region_list * begin, int size) return NULL; } - static const region_list *travel_route(unit * u, const region_list * route_begin, const region_list * route_end, order * ord, int mode) { region *r = u->region; - region *current = u->region; - const region_list *iroute = route_begin; - int steps = 0; - boolean landing = false; /* aquarians have landed */ while (iroute && iroute != route_end) { region *next = iroute->data; - direction_t reldir = reldirection(current, next); - connection *b = get_borders(current, next); /* check if we are caught by guarding units */ if (iroute != route_begin && mode != TRAVEL_RUNNING && mode != TRAVEL_TRANSPORTED) { unit *wache = bewegung_blockiert_von(u, current); - if (wache != NULL) { ADDMSG(&u->faction->msgs, msg_message("moveblockedbyguard", "unit region guard", u, current, wache)); @@ -1537,7 +1444,6 @@ static const region_list *travel_route(unit * u, /* next region is land */ if (fval(current->terrain, SEA_REGION)) { int moving = u->race->flags & (RCF_SWIM | RCF_WALK | RCF_COASTAL); - /* Die Einheit kann nicht fliegen, ist im Ozean, und will an Land */ if (moving != (RCF_SWIM | RCF_WALK) && (moving & RCF_COASTAL) == 0) { /* can't swim+walk and isn't allowed to enter coast from sea */ @@ -1596,7 +1502,6 @@ static const region_list *travel_route(unit * u, /* illusionary units disappear in antimagic zones */ if (fval(u->race, RCF_ILLUSIONARY)) { curse *c = get_curse(next->attribs, ct_find("antimagiczone")); - if (curse_active(c)) { curse_changevigour(&next->attribs, c, (float)-u->number); ADDMSG(&u->faction->msgs, msg_message("illusionantimagic", "unit", u)); @@ -1657,7 +1562,6 @@ static const region_list *travel_route(unit * u, if (mode != TRAVEL_TRANSPORTED) { arg_regions *ar = var_copy_regions(route_begin, steps - 1); - ADDMSG(&u->faction->msgs, msg_message("travel", "unit mode start end regions", u, walkmode, r, current, ar)); } @@ -1706,7 +1610,6 @@ static boolean ship_ready(const region * r, unit * u) unit *owner_buildingtyp(const region * r, const building_type * bt) { building *b; - unit *owner; for (b = rbuildings(r); b; b = b->next) { @@ -1743,11 +1646,8 @@ static boolean check_takeoff(ship * sh, region * from, region * to) { if (!fval(from->terrain, SEA_REGION) && sh->coast != NODIRECTION) { direction_t coast = sh->coast; - direction_t dir = reldirection(from, to); - direction_t coastr = (direction_t) ((coast + 1) % MAXDIRECTIONS); - direction_t coastl = (direction_t) ((coast + MAXDIRECTIONS - 1) % MAXDIRECTIONS); @@ -1764,21 +1664,13 @@ static void sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) { region *starting_point = u->region; - region *current_point, *last_point; - int k, step = 0; - region_list **iroute = routep; - ship *sh = u->ship; - faction *f = u->faction; - region *next_point = NULL; - int error; - const char *token = getstrtoken(); if (routep) @@ -1787,7 +1679,6 @@ sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) error = movewhere(u, token, starting_point, &next_point); if (error) { message *msg = movement_error(u, token, ord, error); - if (msg != NULL) { add_message(&u->faction->msgs, msg); msg_release(msg); @@ -1815,14 +1706,10 @@ sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) while (next_point && current_point != next_point && step < k) { const char *token; - int error; - const terrain_type *tthis = current_point->terrain; - /* these values need to be updated if next_point changes (due to storms): */ const terrain_type *tnext = next_point->terrain; - direction_t dir = reldirection(current_point, next_point); assert(sh == u->ship || !"ship has sunk, but we didn't notice it"); @@ -1835,14 +1722,11 @@ sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) if (!flying_ship(sh)) { int stormchance; - static int stormyness; - static int gamecookie = -1; if (gamecookie != global.cookie) { gamedate date; - get_gamedate(turn, &date); stormyness = storms[date.month] * 5; gamecookie = global.cookie; @@ -1857,17 +1741,12 @@ sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) && fval(current_point->terrain, SEA_REGION)) { if (!is_cursed(sh->attribs, C_SHIP_NODRIFT, 0)) { region *rnext = NULL; - boolean storm = true; - int d_offset = rng_int() % MAXDIRECTIONS; - direction_t d; - /* Sturm nur, wenn nächste Region Hochsee ist. */ for (d = 0; d != MAXDIRECTIONS; ++d) { direction_t dnext = (direction_t) ((d + d_offset) % MAXDIRECTIONS); - region *rn = rconnect(current_point, dnext); if (rn != NULL) { @@ -1921,7 +1800,6 @@ sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) for (d = 0; d != MAXDIRECTIONS; ++d) { region *rc = rconnect(next_point, d); - if (rc == NULL || !fval(rc->terrain, SEA_REGION)) break; } @@ -1949,7 +1827,6 @@ sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) break; } - if (curse_active(get_curse(next_point->attribs, ct_find("maelstrom")))) { if (do_maelstrom(next_point, u) == NULL) break; @@ -1983,7 +1860,6 @@ sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) error = movewhere(u, token, current_point, &next_point); if (error || next_point == NULL) { message *msg = movement_error(u, token, ord, error); - if (msg != NULL) { add_message(&u->faction->msgs, msg); msg_release(msg); @@ -2009,7 +1885,6 @@ sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) if (sh != NULL && fval(sh, SF_MOVED)) { unit *hafenmeister; - /* nachdem alle Richtungen abgearbeitet wurden, und alle Einheiten * transferiert wurden, kann der aktuelle Befehl gelöscht werden. */ cycle_route(ord, u, step); @@ -2040,22 +1915,17 @@ sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) hafenmeister = owner_buildingtyp(current_point, bt_find("harbour")); if (sh && hafenmeister != NULL) { item *itm; - unit *u2; - item *trans = NULL; for (u2 = current_point->units; u2; u2 = u2->next) { if (u2->ship == sh && !alliedunit(hafenmeister, u->faction, HELP_GUARD)) { - if (effskill(hafenmeister, SK_PERCEPTION) > effskill(u2, SK_STEALTH)) { for (itm = u2->items; itm; itm = itm->next) { const luxury_type *ltype = resource2luxury(itm->type->rtype); - if (ltype != NULL && itm->number > 0) { int st = itm->number * effskill(hafenmeister, SK_TRADE) / 50; - st = MIN(itm->number, st); if (st > 0) { @@ -2085,7 +1955,6 @@ sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) unit *get_captain(const ship * sh) { const region *r = sh->region; - unit *u; for (u = r->units; u; u = u->next) { @@ -2111,7 +1980,6 @@ unit *get_captain(const ship * sh) void run_to(unit * u, region * to) { region_list *route = NULL; - add_regionlist(&route, to); travel_route(u, route, NULL, NULL, TRAVEL_RUNNING); free_regionlist(route); @@ -2203,9 +2071,7 @@ static const region_list *travel_i(unit * u, const region_list * route_begin, static void travel(unit * u, region_list ** routep) { region *r = u->region; - region_list *route_begin = NULL; - follower *followers = NULL; if (routep) @@ -2228,7 +2094,6 @@ static void travel(unit * u, region_list ** routep) } if (sh) { unit *guard = is_guarded(r, u, GUARD_LANDING); - if (guard) { ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "region_guarded", "guard", guard)); @@ -2254,11 +2119,8 @@ static void travel(unit * u, region_list ** routep) /* followers */ while (followers != NULL) { follower *fnext = followers->next; - unit *uf = followers->uf; - unit *ut = followers->ut; - const region_list *route_end = followers->route_end; free(followers); @@ -2266,7 +2128,6 @@ static void travel(unit * u, region_list ** routep) if (uf->region == r) { order *follow_order; - const struct locale *lang = u->faction->locale; /* construct an order */ @@ -2330,9 +2191,7 @@ static attrib *mk_piracy(const faction * pirate, const faction * target, direction_t target_dir) { attrib *a = a_new(&at_piracy_direction); - piracy_data *data = a->data.v; - data->pirate = pirate; data->target = target; data->dir = target_dir; @@ -2342,22 +2201,15 @@ static attrib *mk_piracy(const faction * pirate, const faction * target, static void piracy_cmd(unit * u, struct order *ord) { region *r = u->region; - ship *sh = u->ship, *sh2; - direction_t dir, target_dir = NODIRECTION; - struct { const faction *target; int value; } aff[MAXDIRECTIONS]; - int saff = 0; - int *il = NULL; - const char *s; - attrib *a; if (!sh) { @@ -2373,7 +2225,6 @@ static void piracy_cmd(unit * u, struct order *ord) /* Feststellen, ob schon ein anderer alliierter Pirat ein * Ziel gefunden hat. */ - init_tokens(ord); skip_token(); s = getstrtoken(); @@ -2388,9 +2239,7 @@ static void piracy_cmd(unit * u, struct order *ord) for (a = a_find(r->attribs, &at_piracy_direction); a && a->type == &at_piracy_direction; a = a->next) { piracy_data *data = a->data.v; - const faction *p = data->pirate; - const faction *t = data->target; if (alliedunit(u, p, HELP_FIGHT)) { @@ -2409,7 +2258,6 @@ static void piracy_cmd(unit * u, struct order *ord) for (dir = 0; dir < MAXDIRECTIONS; dir++) { region *rc = rconnect(r, dir); - aff[dir].value = 0; aff[dir].target = 0; if (rc && fval(rc->terrain, SWIM_INTO) @@ -2417,10 +2265,8 @@ static void piracy_cmd(unit * u, struct order *ord) for (sh2 = rc->ships; sh2; sh2 = sh2->next) { unit *cap = shipowner(sh2); - if (cap) { faction *f = visible_faction(cap->faction, cap); - if (alliedunit(u, f, HELP_FIGHT)) continue; if (il == 0 || intlist_find(il, cap->faction->no)) { @@ -2479,7 +2325,6 @@ static void age_traveldir(region * r) while (a && a->type == &at_traveldir) { attrib *an = a->next; - a->data.ca[3]--; if (a->data.ca[3] <= 0) { a_remove(&r->attribs, a); @@ -2491,12 +2336,10 @@ static void age_traveldir(region * r) static direction_t hunted_dir(attrib * at, int id) { attrib *a = a_find(at, &at_shiptrail); - direction_t d = NODIRECTION; while (a != NULL && a->type == &at_shiptrail) { traveldir *t = (traveldir *) (a->data.v); - if (t->no == id) { d = t->dir; /* do not break, because we want the last one for this ship */ @@ -2510,13 +2353,9 @@ static direction_t hunted_dir(attrib * at, int id) static int hunt(unit * u, order * ord) { region *rc = u->region; - int bytes, moves, id, speed; - char command[256], *bufp = command; - size_t size = sizeof(command); - direction_t dir; if (fval(u, UFL_NOTMOVING)) { @@ -2547,7 +2386,6 @@ static int hunt(unit * u, order * ord) if (dir == NODIRECTION) { ship *sh = findship(id); - if (sh == NULL || sh->region != rc) { cmistake(u, ord, 20, MSG_MOVE); } @@ -2569,7 +2407,6 @@ static int hunt(unit * u, order * ord) speed = shipspeed(u->ship, u); } else { int maxspeed = shipspeed(u->ship, u); - if (maxspeed < speed) speed = maxspeed; } @@ -2597,7 +2434,6 @@ static int hunt(unit * u, order * ord) void destroy_damaged_ships(void) { region *r; - ship *sh, *shn; for (r = regions; r; r = r->next) { @@ -2715,15 +2551,12 @@ void movement(void) */ for (ships = 0; ships <= 1; ++ships) { region *r = regions; - while (r != NULL) { unit **up = &r->units; - boolean repeat = false; while (*up) { unit *u = *up; - keyword_t kword; if (u->ship && fval(u->ship, SF_DRIFTED)) { @@ -2807,9 +2640,7 @@ void movement(void) void follow_unit(unit * u) { region *r = u->region; - attrib *a = NULL; - order *ord; if (fval(u, UFL_NOTMOVING) || LongHunger(u)) @@ -2830,7 +2661,6 @@ void follow_unit(unit * u) if (id > 0) { unit *uf = findunit(id); - if (!a) { a = a_add(&u->attribs, make_follow(uf)); } else { @@ -2846,7 +2676,6 @@ void follow_unit(unit * u) if (a && !fval(u, UFL_MOVED | UFL_NOTMOVING)) { unit *u2 = a->data.v; - boolean follow = false; if (!u2 || u2->region != r || !cansee(u->faction, r, u2, 0)) { @@ -2875,10 +2704,8 @@ void follow_unit(unit * u) } if (!follow) { attrib *a2 = a_find(u2->attribs, &at_follow); - if (a2 != NULL) { unit *u3 = a2->data.v; - follow = (u3 && u2->region == u2->region); } } diff --git a/src/kernel/names.c b/src/kernel/names.c index b56595463..7fddc01d5 100644 --- a/src/kernel/names.c +++ b/src/kernel/names.c @@ -52,11 +52,8 @@ static const char *make_names(const char *monster, int *num_postfix, int pprefix, int *num_name, int *num_prefix, int ppostfix) { int uv, uu, un; - static char name[NAMESIZE + 1]; - char zText[32]; - const char *str; if (*num_prefix == 0) { @@ -128,32 +125,27 @@ static const char *make_names(const char *monster, int *num_postfix, const char *undead_name(const unit * u) { static int num_postfix, num_name, num_prefix; - return make_names("undead", &num_postfix, 2, &num_name, &num_prefix, 2); } const char *skeleton_name(const unit * u) { static int num_postfix, num_name, num_prefix; - return make_names("skeleton", &num_postfix, 5, &num_name, &num_prefix, 2); } const char *zombie_name(const unit * u) { static int num_postfix, num_name, num_prefix; - return make_names("zombie", &num_postfix, 5, &num_name, &num_prefix, 2); } const char *ghoul_name(const unit * u) { static int num_postfix, num_name, num_prefix; - return make_names("ghoul", &num_postfix, 5, &num_name, &num_prefix, 4); } - /* Drachen */ #define SIL1 15 @@ -230,15 +222,10 @@ const char *generic_name(const unit * u) const char *dragon_name(const unit * u) { static char name[NAMESIZE + 1]; - int rnd, ter = 0; - int anzahl = 1; - static int num_postfix; - char zText[32]; - const char *str; if (num_postfix == 0) { @@ -257,7 +244,6 @@ const char *dragon_name(const unit * u) if (u) { region *r = u->region; - anzahl = u->number; switch (rterrain(r)) { case T_PLAIN: @@ -288,7 +274,6 @@ const char *dragon_name(const unit * u) if (anzahl > 1) { const char *no_article = strchr((const char *)str, ' '); - assert(no_article); /* TODO: GERMAN */ sprintf(name, "Die %sn von %s", no_article, rname(u->region, @@ -368,7 +353,6 @@ static const char *drac_suf[DRAC_SUF] = { const char *dracoid_name(const unit * u) { static char name[NAMESIZE + 1]; - int mid_syllabels; u = u; @@ -393,17 +377,11 @@ const char *dracoid_name(const unit * u) const char *abkz(const char *s, char *buf, size_t buflen, size_t maxchars) { const char *p = s; - char *bufp; - unsigned int c = 0; - size_t bpt, i; - ucs4_t ucs; - size_t size; - int result; /* Prüfen, ob Kurz genug */ diff --git a/src/kernel/order.c b/src/kernel/order.c index 536284259..ffb955e9f 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -33,7 +33,6 @@ # 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 *study_orders[MAXSKILLS]; @@ -41,7 +40,6 @@ typedef struct locale_data { } locale_data; static struct locale_data *locale_array[16]; - static int nlocales = 0; typedef struct order_data { @@ -66,10 +64,8 @@ void replace_order(order ** dlist, order * orig, const order * src) { while (*dlist != NULL) { order *dst = *dlist; - if (dst->data == orig->data) { order *cpy = copy_order(src); - *dlist = cpy; cpy->next = dst->next; dst->next = 0; @@ -94,11 +90,8 @@ keyword_t get_keyword(const order * ord) static char *get_command(const order * ord, char *sbuffer, size_t size) { char *bufp = sbuffer; - const char *text = ORD_STRING(ord); - keyword_t kwd = ORD_KEYWORD(ord); - int bytes; if (ord->_persistent) { @@ -111,7 +104,6 @@ static char *get_command(const order * ord, char *sbuffer, size_t size) } if (kwd != NOKEYWORD) { const struct locale *lang = ORD_LOCALE(ord); - if (size > 0) { if (text) --size; @@ -146,7 +138,6 @@ static char *get_command(const order * ord, char *sbuffer, size_t size) char *getcommand(const order * ord) { char sbuffer[DISPLAYSIZE * 2]; - return strdup(get_command(ord, sbuffer, sizeof(sbuffer))); } @@ -164,7 +155,6 @@ order *copy_order(const order * src) { if (src != NULL) { order *ord = (order *) malloc(sizeof(order)); - ord->next = NULL; ord->_persistent = src->_persistent; ord->data = src->data; @@ -186,7 +176,6 @@ void free_orders(order ** olist) { while (*olist) { order *ord = *olist; - *olist = ord->next; ord->next = NULL; free_order(ord); @@ -196,9 +185,7 @@ void free_orders(order ** olist) static order_data *create_data(keyword_t kwd, const char *sptr, int lindex) { const char *s = sptr; - order_data *data; - const struct locale *lang = locale_array[lindex]->lang; if (kwd != NOKEYWORD) @@ -207,7 +194,6 @@ static order_data *create_data(keyword_t kwd, const char *sptr, int lindex) /* learning, only one order_data per skill required */ if (kwd == K_STUDY) { skill_t sk = findskill(parse_token(&sptr), lang); - switch (sk) { case NOSKILL: /* fehler */ break; @@ -218,14 +204,12 @@ static order_data *create_data(keyword_t kwd, const char *sptr, int lindex) data = locale_array[lindex]->study_orders[sk]; if (data == NULL) { const char *skname = skillname(sk, lang); - data = (order_data *) malloc(sizeof(order_data)); locale_array[lindex]->study_orders[sk] = data; data->_keyword = kwd; data->_lindex = lindex; if (strchr(skname, ' ') != NULL) { size_t len = strlen(skname); - data->_str = malloc(len + 3); data->_str[0] = '\"'; memcpy(data->_str + 1, skname, len); @@ -267,7 +251,6 @@ static order *create_order_i(keyword_t kwd, const char *sptr, int persistent, const struct locale *lang) { order *ord = NULL; - int lindex; /* if this is just nonsense, then we skip it. */ @@ -308,42 +291,33 @@ order *create_order(keyword_t kwd, const struct locale * lang, const char *params, ...) { char zBuffer[DISPLAYSIZE]; - if (params) { char *bufp = zBuffer; - int bytes; - size_t size = sizeof(zBuffer) - 1; - va_list marker; va_start(marker, params); while (*params) { if (*params == '%') { int i; - const char *s; - ++params; switch (*params) { case 's': s = va_arg(marker, const char *); - bytes = (int)strlcpy(bufp, s, size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); break; case 'd': i = va_arg(marker, int); - bytes = (int)strlcpy(bufp, itoa10(i), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); break; case 'i': i = va_arg(marker, int); - bytes = (int)strlcpy(bufp, itoa36(i), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -371,9 +345,7 @@ order *parse_order(const char *s, const struct locale * lang) ++s; if (*s != 0) { keyword_t kwd; - const char *sptr; - int persistent = 0; while (*s == '@') { @@ -403,9 +375,7 @@ order *parse_order(const char *s, const struct locale * lang) boolean is_repeated(const order * ord) { keyword_t kwd = ORD_KEYWORD(ord); - const struct locale *lang = ORD_LOCALE(ord); - param_t param; switch (kwd) { @@ -473,9 +443,7 @@ boolean is_repeated(const order * ord) boolean is_exclusive(const order * ord) { keyword_t kwd = ORD_KEYWORD(ord); - const struct locale *lang = ORD_LOCALE(ord); - param_t param; switch (kwd) { @@ -543,9 +511,7 @@ boolean is_exclusive(const order * ord) boolean is_long(const order * ord) { keyword_t kwd = ORD_KEYWORD(ord); - const struct locale *lang = ORD_LOCALE(ord); - param_t param; switch (kwd) { @@ -616,9 +582,7 @@ boolean is_long(const order * ord) boolean is_persistent(const order * ord) { keyword_t kwd = ORD_KEYWORD(ord); - boolean persist = ord->_persistent != 0; - switch (kwd) { case K_MOVE: case K_WEREWOLF: @@ -640,10 +604,8 @@ char *write_order(const order * ord, char *buffer, size_t size) buffer[0] = 0; } else { keyword_t kwd = ORD_KEYWORD(ord); - if (kwd == NOKEYWORD) { const char *text = ORD_STRING(ord); - strlcpy(buffer, (const char *)text, size); } else { get_command(ord, buffer, size); diff --git a/src/kernel/order.h b/src/kernel/order.h index 3cb4b6b2d..3dd97bcae 100644 --- a/src/kernel/order.h +++ b/src/kernel/order.h @@ -58,7 +58,6 @@ extern "C" { extern char *write_order(const order * ord, char *buffer, size_t size); - #ifdef __cplusplus } #endif diff --git a/src/kernel/pathfinder.c b/src/kernel/pathfinder.c index c86d728a0..26b4f62db 100644 --- a/src/kernel/pathfinder.c +++ b/src/kernel/pathfinder.c @@ -61,7 +61,6 @@ void pathfinder_cleanup(void) { while (node_garbage) { node *n = node_garbage; - node_garbage = n->next; free(n); } @@ -70,7 +69,6 @@ void pathfinder_cleanup(void) static node *new_node(region * r, int distance, node * prev) { node *n; - if (node_garbage != NULL) { n = node_garbage; node_garbage = n->next; @@ -86,7 +84,6 @@ static node *new_node(region * r, int distance, node * prev) static node *free_node(node * n) { node *s = n->next; - n->next = node_garbage; node_garbage = n; return s; @@ -96,7 +93,6 @@ static void free_nodes(node * root) { while (root != NULL) { region *r = root->r; - freset(r, RF_MARK); root = free_node(root); } @@ -106,25 +102,19 @@ struct region_list *regions_in_range(struct region *start, int maxdist, boolean(*allowed) (const struct region *, const struct region *)) { region_list *rlist = NULL; - node *root = new_node(start, 0, NULL); - node **end = &root->next; - node *n = root; while (n != NULL) { region *r = n->r; - int depth = n->distance + 1; - direction_t d; if (n->distance >= maxdist) break; for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r, d); - if (rn == NULL) continue; if (fval(rn, RF_MARK)) @@ -152,30 +142,21 @@ static region **internal_path_find(region * start, const region * target, int maxlen, boolean(*allowed) (const region *, const region *)) { static region *path[MAXDEPTH + 2]; /* STATIC_RETURN: used for return, not across calls */ - direction_t d; - node *root = new_node(start, 0, NULL); - node **end = &root->next; - node *n = root; - boolean found = false; - assert(maxlen <= MAXDEPTH); fset(start, RF_MARK); while (n != NULL) { region *r = n->r; - int depth = n->distance + 1; - if (n->distance >= maxlen) break; for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r, d); - if (rn == NULL) continue; if (fval(rn, RF_MARK)) @@ -184,7 +165,6 @@ static region **internal_path_find(region * start, const region * target, continue; /* can't go there */ if (rn == target) { int i = depth; - path[i + 1] = NULL; path[i] = rn; while (n) { diff --git a/src/kernel/plane.c b/src/kernel/plane.c index a4d48f7ba..0a1c856c3 100644 --- a/src/kernel/plane.c +++ b/src/kernel/plane.c @@ -58,7 +58,6 @@ plane *get_homeplane(void) return getplanebyid(0); } - plane *getplane(const region * r) { if (r) { @@ -105,7 +104,6 @@ int getplaneid(const region * r) { if (r) { plane *pl = getplane(r); - if (pl) return pl->id; @@ -123,7 +121,6 @@ static int ursprung_x(const faction * f, const plane * pl, const region * rdefault) { ursprung *ur; - int id = 0; if (!f) @@ -147,7 +144,6 @@ static int ursprung_y(const faction * f, const plane * pl, const region * rdefault) { ursprung *ur; - int id = 0; if (!f) @@ -188,9 +184,7 @@ adjust_coordinates(const faction * f, int *x, int *y, const plane * pl, const region * r) { int nx = *x; - int ny = *y; - if (f) { nx -= ursprung_x(f, pl, r); ny -= ursprung_y(f, pl, r); @@ -202,11 +196,8 @@ adjust_coordinates(const faction * f, int *x, int *y, const plane * pl, if (pl) { int width = plane_width(pl); - int height = plane_height(pl); - int width_2 = width / 2; - int height_2 = height / 2; if (nx < 0) @@ -231,7 +222,6 @@ adjust_coordinates(const faction * f, int *x, int *y, const plane * pl, void set_ursprung(faction * f, int id, int x, int y) { ursprung *ur; - assert(f != NULL); for (ur = f->ursprung; ur; ur = ur->next) { if (ur->id == id) { @@ -285,13 +275,10 @@ rel_to_abs(const struct plane *pl, const struct faction *f, int rel, return (rel + ursprung_y(f, pl, NULL) + plane_center_y(pl)); } - int resolve_plane(variant id, void *addr) { int result = 0; - plane *pl = NULL; - if (id.i != 0) { pl = getplanebyid(id.i); if (pl == NULL) { @@ -310,7 +297,6 @@ void write_plane_reference(const plane * u, struct storage *store) int read_plane_reference(plane ** pp, struct storage *store) { variant id; - id.i = store->r_int(store); if (id.i == 0) { *pp = NULL; @@ -325,7 +311,6 @@ int read_plane_reference(plane ** pp, struct storage *store) boolean is_watcher(const struct plane * p, const struct faction * f) { struct watcher *w; - if (!p) return false; w = p->watchers; diff --git a/src/kernel/player.c b/src/kernel/player.c index 628369664..f914580c9 100644 --- a/src/kernel/player.c +++ b/src/kernel/player.c @@ -30,13 +30,11 @@ static player_hash *players[PMAXHASH]; player *make_player(const struct faction *f) { player *p = calloc(sizeof(player), 1); - unsigned int hash; for (p->id = rng_int();; p->id++) { /* if there is a hashing conflict, resolve it */ player *pi = get_player(p->id); - if (pi) p->id++; else @@ -56,7 +54,6 @@ player *next_player(player * p) return p->nexthash; else { unsigned int hash = p->id % PMAXHASH; - p = NULL; while (++hash != PMAXHASH) { if (players[hash]->entries != NULL) { @@ -71,7 +68,6 @@ player *next_player(player * p) player *get_player(unsigned int id) { unsigned int hash = id % PMAXHASH; - struct player *p = players[hash]->entries; while (p && p->id != id) @@ -82,7 +78,6 @@ player *get_player(unsigned int id) player *get_players(void) { struct player *p = NULL; - unsigned int hash = 0; while (p != NULL && hash != PMAXHASH) { @@ -94,10 +89,8 @@ player *get_players(void) void players_done(void) { int i; - for (i = 0; i != PMAXHASH; ++i) { player *p = players[i]->entries; - players[i]->entries = p->nexthash; free(p->name); if (p->email) diff --git a/src/kernel/pool.c b/src/kernel/pool.c index a9c98698a..9eb7b7ca1 100644 --- a/src/kernel/pool.c +++ b/src/kernel/pool.c @@ -44,7 +44,6 @@ int get_resource(const unit * u, const resource_type * rtype) if (rtype->uget) { /* this resource is probably special */ int i = rtype->uget(u, rtype); - if (i >= 0) return i; } @@ -55,7 +54,6 @@ int get_resource(const unit * u, const resource_type * rtype) return u->number * GOLEM_IRON; } else { const item *i = *i_findc(&u->items, itype); - if (i) return i->number; return 0; @@ -152,13 +150,9 @@ get_pooled(const unit * u, const resource_type * rtype, unsigned int mode, int count) { const faction *f = u->faction; - unit *v; - int use = 0; - region *r = u->region; - int have = get_resource(u, rtype); if ((u->race->ec_flags & GETITEM) == 0) { @@ -169,9 +163,7 @@ get_pooled(const unit * u, const resource_type * rtype, unsigned int mode, use = have; else { int reserve = get_reservation(u, rtype); - int slack = MAX(0, have - reserve); - if (mode & GET_RESERVE) use = have - slack; else if (mode & GET_SLACK) @@ -203,13 +195,9 @@ int use_pooled(unit * u, const resource_type * rtype, unsigned int mode, int count) { const faction *f = u->faction; - unit *v; - int use = count; - region *r = u->region; - int n = 0, have = get_resource(u, rtype); if ((u->race->ec_flags & GETITEM) == 0) { @@ -220,9 +208,7 @@ use_pooled(unit * u, const resource_type * rtype, unsigned int mode, int count) n = MIN(use, have); } else { int reserve = get_reservation(u, rtype); - int slack = MAX(0, have - reserve); - if (mode & GET_RESERVE) { n = have - slack; n = MIN(use, n); @@ -240,7 +226,6 @@ use_pooled(unit * u, const resource_type * rtype, unsigned int mode, int count) for (v = r->units; use > 0 && v != NULL; v = v->next) if (u != v) { int mask; - if ((urace(v)->ec_flags & GIVEITEM) == 0) continue; if (v->items == NULL && rtype->uget == NULL) @@ -258,14 +243,11 @@ use_pooled(unit * u, const resource_type * rtype, unsigned int mode, int count) return count - use; } - int reserve_cmd(unit * u, struct order *ord) { if (u->number > 0 && (urace(u)->ec_flags & GETITEM)) { int use, count; - const resource_type *rtype; - const char *s; init_tokens(ord); diff --git a/src/kernel/race.c b/src/kernel/race.c index d73829086..dc35e62f1 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -58,18 +58,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /** external variables **/ race *races; - int num_races = 0; race_list *get_familiarraces(void) { static int init = 0; - static race_list *familiarraces; if (!init) { race *rc = races; - for (; rc != NULL; rc = rc->next) { if (rc->init_familiar != NULL) { racelist_insert(&familiarraces, rc); @@ -84,7 +81,6 @@ void racelist_clear(struct race_list **rl) { while (*rl) { race_list *rl2 = (*rl)->next; - free(*rl); *rl = rl2; } @@ -103,9 +99,7 @@ void racelist_insert(struct race_list **rl, const struct race *r) race *rc_new(const char *zName) { char zBuffer[80]; - race *rc = calloc(sizeof(race), 1); - if (strchr(zName, ' ') != NULL) { log_error(("race '%s' has an invalid name. remove spaces\n", zName)); assert(strchr(zName, ' ') == NULL); @@ -141,9 +135,7 @@ static const char *racealias[][2] = { race *rc_find(const char *name) { const char *rname = name; - race *rc = races; - int i; for (i = 0; racealias[i][0]; ++i) { @@ -170,9 +162,7 @@ char **race_prefixes = NULL; extern void add_raceprefix(const char *prefix) { static size_t size = 4; - static unsigned int next = 0; - if (race_prefixes == NULL) race_prefixes = malloc(size * sizeof(char *)); if (next + 1 == size) { @@ -191,7 +181,6 @@ extern void add_raceprefix(const char *prefix) void set_show_item(faction * f, item_t i) { attrib *a = a_add(&f->attribs, a_new(&at_showitem)); - a->data.v = (void *)olditemtype[i]; } @@ -211,7 +200,6 @@ const char *raceprefix(const unit * u) if (fval(u, UFL_GROUP)) { const attrib *agroup = agroup = a_findc(u->attribs, &at_group); - if (agroup != NULL) asource = ((const group *)(agroup->data.v))->attribs; } @@ -224,11 +212,8 @@ const char *racename(const struct locale *loc, const unit * u, const race * rc) if (prefix != NULL) { static char lbuf[80]; - char *bufp = lbuf; - size_t size = sizeof(lbuf) - 1; - int ch, bytes; bytes = (int)strlcpy(bufp, LOC(loc, mkname("prefix", prefix)), size); @@ -253,7 +238,6 @@ rc_specialdamage(const race * ar, const race * dr, const struct weapon_type *wtype) { race_t art = old_race(ar); - int m, modifier = 0; if (wtype != NULL && wtype->modifiers != NULL) @@ -261,7 +245,6 @@ rc_specialdamage(const race * ar, const race * dr, /* weapon damage for this weapon, possibly by race */ if (wtype->modifiers[m].flags & WMF_DAMAGE) { race_list *rlist = wtype->modifiers[m].races; - if (rlist != NULL) { while (rlist) { if (rlist->data == ar) @@ -294,9 +277,7 @@ void write_race_reference(const race * rc, struct storage *store) variant read_race_reference(struct storage *store) { variant result; - char zName[20]; - store->r_tok_buf(store, zName, sizeof(zName)); if (strcmp(zName, "none") == 0) { diff --git a/src/kernel/region.c b/src/kernel/region.c index 9f7cd62c2..aea63223f 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -67,10 +67,8 @@ region *regions; int get_maxluxuries() { static int maxluxuries = -1; - if (maxluxuries == -1) { const luxury_type *ltype; - maxluxuries = 0; for (ltype = luxurytypes; ltype; ltype = ltype->next) ++maxluxuries; @@ -114,16 +112,12 @@ const char *write_regionname(const region * r, const faction * f, char *buffer, size_t size) { char *buf = (char *)buffer; - const struct locale *lang = f ? f->locale : 0; - if (r == NULL) { strcpy(buf, "(null)"); } else { plane *pl = rplane(r); - int nx = r->x, ny = r->y; - pnormalize(&nx, &ny, pl); adjust_coordinates(f, &nx, &ny, pl, r); snprintf(buf, size, "%s (%d,%d)", rname(r, lang), nx, ny); @@ -135,14 +129,12 @@ const char *write_regionname(const region * r, const faction * f, char *buffer, const char *regionname(const region * r, const faction * f) { static char buf[NAMESIZE]; - return write_regionname(r, f, buf, sizeof(buf)); } int deathcount(const region * r) { attrib *a = a_find(r->attribs, &at_deathcount); - if (!a) return 0; return a->data.i; @@ -151,7 +143,6 @@ int deathcount(const region * r) int chaoscount(const region * r) { attrib *a = a_find(r->attribs, &at_chaoscount); - if (!a) return 0; return a->data.i; @@ -160,7 +151,6 @@ int chaoscount(const region * r) void deathcounts(region * r, int fallen) { attrib *a; - static const curse_type *ctype = NULL; if (fallen == 0) @@ -195,8 +185,6 @@ void chaoscounts(region * r, int fallen) a_remove(&r->attribs, a); } - - /********************/ /* at_direction */ /********************/ @@ -213,7 +201,6 @@ static void a_freedirection(attrib * a) static int a_agedirection(attrib * a) { spec_direction *d = (spec_direction *) (a->data.v); - --d->duration; return (d->duration > 0) ? AT_AGE_KEEP : AT_AGE_REMOVE; } @@ -229,12 +216,10 @@ static dir_lookup *dir_name_lookup; void register_special_direction(const char *name) { struct locale *lang; - char *str = strdup(name); for (lang = locales; lang; lang = nextlocale(lang)) { tnode *tokens = get_translations(lang, UT_SPECDIR); - const char *token = LOC(lang, name); if (token) { @@ -245,7 +230,6 @@ void register_special_direction(const char *name) if (lang == default_locale) { dir_lookup *dl = malloc(sizeof(dir_lookup)); - dl->name = str; dl->oldname = token; dl->next = dir_name_lookup; @@ -267,7 +251,6 @@ static int a_readdirection(attrib * a, void *owner, struct storage *store) d->duration = store->r_int(store); if (store->version < UNICODE_VERSION) { char lbuf[16]; - dir_lookup *dl = dir_name_lookup; store->r_tok_buf(store, NULL, 0); @@ -319,7 +302,6 @@ region *find_special_direction(const region * r, const char *token, const struct locale *lang) { attrib *a; - spec_direction *d; if (strlen(token) == 0) @@ -330,9 +312,7 @@ region *find_special_direction(const region * r, const char *token, if (d->active) { tnode *tokens = get_translations(lang, UT_SPECDIR); - variant var; - if (findtoken(tokens, token, &var) == E_TOK_SUCCESS) { if (strcmp((const char *)var.v, d->keyword) == 0) { return findregion(d->x, d->y); @@ -348,7 +328,6 @@ attrib *create_special_direction(region * r, region * rt, int duration, const char *desc, const char *keyword) { attrib *a = a_add(&r->attribs, a_new(&at_direction)); - spec_direction *d = (spec_direction *) (a->data.v); d->active = false; @@ -376,7 +355,6 @@ void a_initmoveblock(attrib * a) int a_readmoveblock(attrib * a, void *owner, struct storage *store) { moveblock *m = (moveblock *) (a->data.v); - int i; i = store->r_int(store); @@ -388,7 +366,6 @@ void a_writemoveblock(const attrib * a, const void *owner, struct storage *store) { moveblock *m = (moveblock *) (a->data.v); - store->w_int(store, (int)m->dir); } @@ -399,22 +376,18 @@ attrib_type at_moveblock = { #define coor_hashkey(x, y) (unsigned int)((x<<16) + y) #define RMAXHASH MAXREGIONS static region *regionhash[RMAXHASH]; - static int dummy_data; - static region *dummy_ptr = (region *) & dummy_data; /* a funny hack */ typedef struct uidhashentry { unsigned int uid; region *r; } uidhashentry; - static uidhashentry uidhash[MAXREGIONS]; struct region *findregionbyid(unsigned int uid) { int key = uid % MAXREGIONS; - while (uidhash[key].uid != 0 && uidhash[key].uid != uid) ++key; return uidhash[key].r; @@ -425,7 +398,6 @@ struct region *findregionbyid(unsigned int uid) static void unhash_uid(region * r) { int key = r->uid % MAXREGIONS; - assert(r->uid); while (uidhash[key].uid != 0 && uidhash[key].uid != r->uid) ++key; @@ -436,11 +408,9 @@ static void unhash_uid(region * r) static void hash_uid(region * r) { unsigned int uid = r->uid; - for (;;) { if (uid != 0) { int key = uid % MAXREGIONS; - while (uidhash[key].uid != 0 && uidhash[key].uid != uid) ++key; if (uidhash[key].uid == 0) { @@ -457,7 +427,6 @@ static void hash_uid(region * r) #define HASH_STATISTICS 1 #if HASH_STATISTICS static int hash_requests; - static int hash_misses; #endif @@ -466,17 +435,13 @@ boolean pnormalize(int *x, int *y, const plane * pl) if (pl) { if (x) { int width = pl->maxx - pl->minx + 1; - int nx = *x - pl->minx; - nx = (nx > 0) ? nx : (width - (-nx) % width); *x = nx % width + pl->minx; } if (y) { int height = pl->maxy - pl->miny + 1; - int ny = *y - pl->miny; - ny = (ny > 0) ? ny : (height - (-ny) % height); *y = ny % height + pl->miny; } @@ -494,7 +459,6 @@ static region *rfindhash(int x, int y) #endif if (rid >= 0) { int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); - while (regionhash[key] != NULL && (regionhash[key] == DELMARKER || regionhash[key]->x != x || regionhash[key]->y != y)) { key = (key + gk) % RMAXHASH; @@ -510,9 +474,7 @@ static region *rfindhash(int x, int y) void rhash(region * r) { unsigned int rid = coor_hashkey(r->x, r->y); - int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); - while (regionhash[key] != NULL && regionhash[key] != DELMARKER && regionhash[key] != r) { key = (key + gk) % RMAXHASH; @@ -524,15 +486,12 @@ void rhash(region * r) void runhash(region * r) { unsigned int rid = coor_hashkey(r->x, r->y); - int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); #ifdef FAST_CONNECT int d, di; - for (d = 0, di = MAXDIRECTIONS / 2; d != MAXDIRECTIONS; ++d, ++di) { region *rc = r->connect[d]; - if (rc != NULL) { if (di >= MAXDIRECTIONS) di -= MAXDIRECTIONS; @@ -551,12 +510,9 @@ void runhash(region * r) region *r_connect(const region * r, direction_t dir) { region *result; - int x, y; - #ifdef FAST_CONNECT region *rmodify = (region *) r; - assert(dir >= 0 && dir < MAXDIRECTIONS); if (r->connect[dir]) return r->connect[dir]; @@ -586,7 +542,6 @@ region *findregion(int x, int y) static int koor_distance_orig(int x1, int y1, int x2, int y2) { int dx = x1 - x2; - int dy = y1 - y2; /* Bei negativem dy am Ursprung spiegeln, das veraendert @@ -602,11 +557,9 @@ static int koor_distance_orig(int x1, int y1, int x2, int y2) */ if (dx >= 0) { int result = dx + dy; - return result; } else if (-dx >= dy) { int result = -dx; - return result; } else { return dy; @@ -617,11 +570,8 @@ static int koor_distance_wrap_xy(int x1, int y1, int x2, int y2, int width, int height) { int dx = x1 - x2; - int dy = y1 - y2; - int result, dist; - int mindist = MIN(width, height) >> 1; /* Bei negativem dy am Ursprung spiegeln, das veraendert @@ -660,16 +610,12 @@ koor_distance_wrap_xy(int x1, int y1, int x2, int y2, int width, int height) int koor_distance(int x1, int y1, int x2, int y2) { const plane *p1 = findplane(x1, y1); - const plane *p2 = findplane(x2, y2); - if (p1 != p2) return INT_MAX; else { int width = plane_width(p1); - int height = plane_height(p1); - if (width && height) { return koor_distance_wrap_xy(x1, y1, x2, y2, width, height); } else { @@ -687,12 +633,9 @@ static direction_t koor_reldirection(int ax, int ay, int bx, int by, const struct plane *pl) { direction_t dir; - for (dir = 0; dir != MAXDIRECTIONS; ++dir) { int x = ax + delta_x[dir]; - int y = ay + delta_y[dir]; - pnormalize(&x, &y, pl); if (bx == x && by == y) return dir; @@ -706,7 +649,6 @@ spec_direction *special_direction(const region * from, const region * to) while (a != NULL && a->type == &at_direction) { spec_direction *sd = (spec_direction *) a->data.v; - if (sd->x == to->x && sd->y == to->y) return sd; a = a->next; @@ -717,13 +659,11 @@ spec_direction *special_direction(const region * from, const region * to) direction_t reldirection(const region * from, const region * to) { plane *pl = rplane(from); - if (pl == rplane(to)) { direction_t dir = koor_reldirection(from->x, from->y, to->x, to->y, pl); if (dir == NODIRECTION) { spec_direction *sd = special_direction(from, to); - if (sd != NULL && sd->active) return D_SPECIAL; } @@ -736,7 +676,6 @@ void free_regionlist(region_list * rl) { while (rl) { region_list *rl2 = rl->next; - free(rl); rl = rl2; } @@ -765,7 +704,6 @@ attrib_type at_horseluck = { ATF_UNIQUE }; - /**********************/ /* at_peasantluck */ /**********************/ @@ -833,7 +771,6 @@ attrib_type at_travelunit = { void rsetroad(region * r, direction_t d, short val) { connection *b; - region *r2 = rconnect(r, d); if (!r2) @@ -852,9 +789,7 @@ void rsetroad(region * r, direction_t d, short val) short rroad(const region * r, direction_t d) { int rval; - connection *b; - region *r2 = rconnect(r, d); if (!r2) @@ -875,9 +810,7 @@ boolean r_isforest(const region * r) if (fval(r->terrain, FOREST_REGION)) { /* needs to be covered with at leas 48% trees */ int mincover = (int)(r->terrain->size * 0.48); - int trees = rtrees(r, 2) + rtrees(r, 1); - return (trees * TREESIZE >= mincover); } return false; @@ -886,12 +819,10 @@ boolean r_isforest(const region * r) int is_coastregion(region * r) { direction_t i; - int res = 0; for (i = 0; i < MAXDIRECTIONS; i++) { region *rn = rconnect(r, i); - if (rn && fval(rn->terrain, SEA_REGION)) res++; } @@ -953,7 +884,6 @@ void r_setdemand(region * r, const luxury_type * ltype, int value) const item_type *r_luxury(region * r) { struct demand *dmd; - if (r->land) { if (!r->land->demands) { fix_demand(r); @@ -969,7 +899,6 @@ const item_type *r_luxury(region * r) int r_demand(const region * r, const luxury_type * ltype) { struct demand *d = r->land->demands; - while (d && d->type != ltype) d = d->next; if (!d) @@ -1044,7 +973,6 @@ void remove_region(region ** rlist, region * r) while (r->units) { unit *u = r->units; - i_freeall(&u->items); remove_unit(&r->units, u); } @@ -1063,7 +991,6 @@ static void freeland(land_region * lr) { while (lr->demands) { struct demand *d = lr->demands; - lr->demands = d->next; free(d); } @@ -1075,7 +1002,6 @@ static void freeland(land_region * lr) void region_setresource(region * r, const resource_type * rtype, int value) { rawmaterial *rm = r->resources; - while (rm) { if (rm->type->rtype == rtype) { rm->amount = value; @@ -1096,7 +1022,6 @@ void region_setresource(region * r, const resource_type * rtype, int value) int region_getresource(const region * r, const resource_type * rtype) { const rawmaterial *rm; - for (rm = r->resources; rm; rm = rm->next) { if (rm->type->rtype == rtype) { return rm->amount; @@ -1126,7 +1051,6 @@ void free_region(region * r) while (r->individual_messages) { struct individual_message *msg = r->individual_messages; - r->individual_messages = msg->next; if (msg->msgs) free_messagelist(msg->msgs); @@ -1137,21 +1061,18 @@ void free_region(region * r) a_remove(&r->attribs, r->attribs); while (r->resources) { rawmaterial *res = r->resources; - r->resources = res->next; free(res); } while (r->donations) { donation *don = r->donations; - r->donations = don->next; free(don); } while (r->units) { unit *u = r->units; - r->units = u->next; uunhash(u); free_unit(u); @@ -1160,7 +1081,6 @@ void free_region(region * r) while (r->buildings) { building *b = r->buildings; - assert(b->region == r); r->buildings = b->next; bunhash(b); /* must be done here, because remove_building does it, and wasn't called */ @@ -1169,7 +1089,6 @@ void free_region(region * r) while (r->ships) { ship *s = r->ships; - assert(s->region == r); r->ships = s->next; sunhash(s); @@ -1184,13 +1103,11 @@ void free_regions(void) memset(uidhash, 0, sizeof(uidhash)); while (deleted_regions) { region *r = deleted_regions; - deleted_regions = r->next; free_region(r); } while (regions) { region *r = regions; - regions = r->next; runhash(r); free_region(r); @@ -1206,11 +1123,8 @@ void free_regions(void) static char *makename(void) { int s, v, k, e, p = 0, x = 0; - size_t nk, ne, nv, ns; - static char name[16]; - const char *kons = "bcdfghklmnprstvwz", *start = "bcdgtskpvfr", *end = "nlrdst", @@ -1260,7 +1174,6 @@ void setluxuries(region * r, const luxury_type * sale) for (ltype = luxurytypes; ltype; ltype = ltype->next) { struct demand *dmd = malloc(sizeof(struct demand)); - dmd->type = ltype; if (ltype != sale) dmd->value = 1 + rng_int() % 5; @@ -1275,19 +1188,16 @@ void terraform_region(region * r, const terrain_type * terrain) { /* Resourcen, die nicht mehr vorkommen können, löschen */ const terrain_type *oldterrain = r->terrain; - rawmaterial **lrm = &r->resources; assert(terrain); while (*lrm) { rawmaterial *rm = *lrm; - const resource_type *rtype = NULL; if (terrain->production != NULL) { int i; - for (i = 0; terrain->production[i].type; ++i) { if (rm->type->rtype == terrain->production[i].type) { rtype = rm->type->rtype; @@ -1333,11 +1243,8 @@ void terraform_region(region * r, const terrain_type * terrain) const luxury_type *type; int value; } *trash = NULL, *nb = NULL; - const luxury_type *ltype = NULL; - direction_t d; - int mnr = 0; r->land = calloc(1, sizeof(land_region)); @@ -1346,15 +1253,12 @@ void terraform_region(region * r, const terrain_type * terrain) region_setname(r, makename()); for (d = 0; d != MAXDIRECTIONS; ++d) { region *nr = rconnect(r, d); - if (nr && nr->land) { struct demand *sale = r->land->demands; - while (sale && sale->value != 0) sale = sale->next; if (sale) { struct surround *sr = nb; - while (sr && sr->type != sale->type) sr = sr->next; if (!sr) { @@ -1376,7 +1280,6 @@ void terraform_region(region * r, const terrain_type * terrain) } if (!nb) { int i = get_maxluxuries(); - if (i > 0) { i = rng_int() % i; ltype = luxurytypes; @@ -1385,9 +1288,7 @@ void terraform_region(region * r, const terrain_type * terrain) } } else { int i = rng_int() % mnr; - struct surround *srd = nb; - while (i > srd->value) { i -= srd->value; srd = srd->next; @@ -1404,7 +1305,6 @@ void terraform_region(region * r, const terrain_type * terrain) if (fval(terrain, LAND_REGION)) { const item_type *itype = NULL; - char equip_hash[64]; /* TODO: put the equipment in struct terrain, faster */ @@ -1413,7 +1313,6 @@ void terraform_region(region * r, const terrain_type * terrain) if (r->terrain->herbs) { int len = 0; - while (r->terrain->herbs[len]) ++len; if (len) @@ -1452,7 +1351,6 @@ void terraform_region(region * r, const terrain_type * terrain) if (!fval(r, RF_CHAOTIC)) { int peasants; - peasants = (maxworkingpeasants(r) * (20 + dice_rand("6d10"))) / 100; rsetpeasants(r, MAX(100, peasants)); rsetmoney(r, rpeasants(r) * ((wage(r, NULL, NULL, @@ -1471,7 +1369,6 @@ int production(const region * r) { /* muß rterrain(r) sein, nicht rterrain() wegen rekursion */ int p = r->terrain->size / MAXPEASANTS_PER_AREA; - if (curse_active(get_curse(r->attribs, ct_find("drought")))) p /= 2; @@ -1481,7 +1378,6 @@ int production(const region * r) int resolve_region_coor(variant id, void *address) { region *r = findregion(id.sa[0], id.sa[1]); - if (r) { *(region **) address = r; return 0; @@ -1493,7 +1389,6 @@ int resolve_region_coor(variant id, void *address) int resolve_region_id(variant id, void *address) { region *r = NULL; - if (id.i != 0) { r = findregionbyid((unsigned int)id.i); if (r == NULL) { @@ -1508,7 +1403,6 @@ int resolve_region_id(variant id, void *address) variant read_region_reference(struct storage * store) { variant result; - if (store->version < UIDHASH_VERSION) { result.sa[0] = (short)store->r_int(store); result.sa[1] = (short)store->r_int(store); @@ -1531,7 +1425,6 @@ struct message_list *r_getmessages(const struct region *r, const struct faction *viewer) { struct individual_message *imsg = r->individual_messages; - while (imsg && (imsg)->viewer != viewer) imsg = imsg->next; if (imsg) @@ -1545,7 +1438,6 @@ struct message *r_addmessage(struct region *r, const struct faction *viewer, assert(r); if (viewer) { struct individual_message *imsg; - imsg = r->individual_messages; while (imsg && imsg->viewer != viewer) imsg = imsg->next; @@ -1575,7 +1467,6 @@ struct alliance *region_get_alliance(const struct region *r) assert(rule_region_owners()); if (r->land && r->land->ownership) { region_owner *own = r->land->ownership; - return own->owner ? own->owner->alliance : own->alliance; } return NULL; @@ -1602,22 +1493,17 @@ void region_set_owner(struct region *r, struct faction *owner, int turn) } } - faction *update_owners(region * r) { faction *f = NULL; - assert(rule_region_owners()); if (r->land) { building *bowner = largestbuilding(r, &cmp_current_owner, false); - building *blargest = largestbuilding(r, &cmp_taxes, false); - if (blargest) { if (!bowner || bowner->size < blargest->size) { /* region owners update? */ unit *u = building_owner(blargest); - f = region_get_owner(r); if (u == NULL) { if (f) { @@ -1631,10 +1517,8 @@ faction *update_owners(region * r) region_set_morale(r, MORALE_DEFAULT, turn); } else { alliance *al = region_get_alliance(r); - if (al && u->faction->alliance == al) { int morale = MAX(0, r->land->morale - MORALE_TRANSFER); - region_set_morale(r, morale, turn); } else { region_set_morale(r, MORALE_TAKEOVER, turn); @@ -1706,7 +1590,6 @@ void region_set_morale(region * r, int morale, int turn) void get_neighbours(const region * r, region ** list) { direction_t dir; - for (dir = 0; dir != MAXDIRECTIONS; ++dir) { list[dir] = rconnect(r, dir); } @@ -1723,7 +1606,6 @@ int owner_change(const region * r) boolean is_mourning(const region * r, int in_turn) { int change = owner_change(r); - return (change == in_turn - 1 && (r->land->ownership->flags & OWNER_MOURNING)); } diff --git a/src/kernel/reports.c b/src/kernel/reports.c index b2356841c..79cb31fa6 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -70,9 +70,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include boolean nocr = false; - boolean nonr = false; - boolean noreports = false; const char *visibility[] = { @@ -97,13 +95,9 @@ const char *coasts[MAXDIRECTIONS] = { static char *groupid(const struct group *g, const struct faction *f) { typedef char name[OBJECTIDSIZE + 1]; - static name idbuf[8]; - static int nextbuf = 0; - char *buf = idbuf[(++nextbuf) % 8]; - sprintf(buf, "%s (%s)", g->name, factionid(f)); return buf; } @@ -161,7 +155,6 @@ report_item(const unit * owner, const item * i, const faction * viewer, *number = i->number; } else if (owner && i->type->rtype == r_silver) { int pp = i->number / owner->number; - if (number) *number = 1; if (pp > 50000 && dragonrace(owner->race)) { @@ -203,15 +196,12 @@ report_item(const unit * owner, const item * i, const faction * viewer, } } - int *nmrs = NULL; int update_nmrs(void) { int i, newplayers = 0; - faction *f; - int turn = global.data_turn; if (nmrs == NULL) @@ -225,7 +215,6 @@ int update_nmrs(void) ++newplayers; } else if (!is_monsters(f) && f->alive) { int nmr = turn - f->lastorders + 1; - if (nmr < 0 || nmr > NMRTimeout()) { log_error(("faction %s has %d NMRS\n", factionid(f), nmr)); nmr = MAX(0, nmr); @@ -241,7 +230,6 @@ int update_nmrs(void) static size_t buforder(char *bufp, size_t size, const order * ord, int mode) { size_t tsize = 0; - int bytes; bytes = (int)strlcpy(bufp, ", \"", size); @@ -250,7 +238,6 @@ static size_t buforder(char *bufp, size_t size, const order * ord, int mode) WARN_STATIC_BUFFER(); if (mode < ORDERS_IN_NR) { char *cmd = getcommand(ord); - bytes = (int)strlcpy(bufp, cmd, size); free(cmd); } else { @@ -282,7 +269,6 @@ report_items(const item * items, item * result, int size, const unit * owner, const faction * viewer) { const item *itm; - int n = 0; /* number of results */ assert(owner == NULL || viewer != owner->faction @@ -291,7 +277,6 @@ report_items(const item * items, item * result, int size, const unit * owner, for (itm = items; itm; itm = itm->next) { item *ishow; - const char *ic; report_item(owner, itm, viewer, NULL, &ic, NULL, false); @@ -338,7 +323,6 @@ void report_race(const struct unit *u, const char **name, const char **illusion) { if (illusion) { const race *irace = u_irace(u); - if (irace && irace != u->race) { *illusion = irace->_name[0]; } else { @@ -349,7 +333,6 @@ void report_race(const struct unit *u, const char **name, const char **illusion) *name = u->race->_name[0]; if (fval(u->race, RCF_SHAPESHIFTANY)) { const char *str = get_racename(u->attribs); - if (str) *name = str; } @@ -361,7 +344,6 @@ report_building(const struct building *b, const char **name, const char **illusion) { static int init; - static const struct building_type *bt_illusion; if (name) { @@ -376,10 +358,8 @@ report_building(const struct building *b, const char **name, } if (bt_illusion && b->type == bt_illusion) { const attrib *a = a_findc(b->attribs, &at_icastle); - if (a != NULL) { icastle_data *icastle = (icastle_data *) a->data.v; - *illusion = buildingtype(icastle->type, b, b->size); } } @@ -391,20 +371,14 @@ report_resources(const seen_region * sr, resource_report * result, int size, const faction * viewer) { const region *r = sr->r; - int n = 0; if (r->land) { int peasants = rpeasants(r); - int money = rmoney(r); - int horses = rhorses(r); - int trees = rtrees(r, 2); - int saplings = rtrees(r, 1); - boolean mallorn = fval(r, RF_MALLORN) != 0; if (money) { @@ -443,26 +417,19 @@ report_resources(const seen_region * sr, resource_report * result, int size, if (sr->mode >= see_unit) { rawmaterial *res = r->resources; - while (res) { int maxskill = 0; - const item_type *itype = resource2item(res->type->rtype); - int level = res->level + itype->construction->minskill - 1; - int visible = -1; - if (res->type->visible == NULL) { visible = res->amount; level = res->level + itype->construction->minskill - 1; } else { const unit *u; - for (u = r->units; visible != res->amount && u != NULL; u = u->next) { if (u->faction == viewer) { int s = eff_skill(u, itype->construction->skill, r); - if (s > maxskill) { maxskill = s; visible = res->type->visible(res, maxskill); @@ -487,35 +454,20 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, size_t size) { int i, dh; - int getarnt = fval(u, UFL_ANON_FACTION); - const char *pzTmp, *str; - building *b; - boolean isbattle = (boolean) (mode == see_battle); - int telepath_see = 0; - attrib *a_fshidden = NULL; - item *itm; - item *show; - faction *fv = visible_faction(f, u); - char *bufp = buf; - boolean itemcloak = false; - static const curse_type *itemcloak_ct = 0; - static boolean init = false; - int bytes; - item result[MAX_INVENTORY]; if (!init) { @@ -532,14 +484,11 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, if (!isbattle) { attrib *a_otherfaction = a_find(u->attribs, &at_otherfaction); - if (u->faction == f) { if (fval(u, UFL_GROUP)) { attrib *a = a_find(u->attribs, &at_group); - if (a) { group *g = (group *) a->data.v; - bytes = (int)strlcpy(bufp, ", ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -557,7 +506,6 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, WARN_STATIC_BUFFER(); } else if (a_otherfaction) { faction *otherfaction = get_otherfaction(a_otherfaction); - if (otherfaction) { bytes = (int)strlcpy(bufp, ", ", size); if (wrptr(&bufp, &size, bytes) != 0) @@ -578,7 +526,6 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, } else { if (a_otherfaction && alliedunit(u, f, HELP_FSTEALTH)) { faction *f = get_otherfaction(a_otherfaction); - bytes = snprintf(bufp, size, ", %s (%s)", factionname(f), factionname(u->faction)); @@ -628,7 +575,6 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, } } else { const race *irace = u_irace(u); - bytes = (int)strlcpy(bufp, racename(f->locale, u, irace), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -658,7 +604,6 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, if (u->number && (u->faction == f || telepath_see || isbattle)) { const char *c = locale_string(f->locale, hp_status(u)); - bytes = (int)strlcpy(bufp, ", ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -709,7 +654,6 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, dh = 0; if (u->faction == f || telepath_see) { skill *sv; - for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { bytes = (int)spskill(bufp, size, f->locale, u, sv, &dh, 1); if (wrptr(&bufp, &size, bytes) != 0) @@ -723,7 +667,6 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, } else if (!itemcloak && mode >= see_unit && !(a_fshidden && a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) { int n = report_items(u->items, result, MAX_INVENTORY, u, f); - assert(n >= 0); if (n > 0) show = result; @@ -734,9 +677,7 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, } for (itm = show; itm; itm = itm->next) { const char *ic; - int in, bytes; - report_item(u, itm, f, &ic, NULL, &in, false); if (in == 0 || ic == NULL) continue; @@ -764,9 +705,7 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, if (m != NULL) { quicklist *ql = m->spells; - int qi, t = effskill(u, SK_MAGIC); - int bytes = snprintf(bufp, size, ". Aura %d/%d", get_spellpoints(u), max_spellpoints(u->region, u)); @@ -775,7 +714,6 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, for (dh = 0, qi = 0; ql; ql_advance(&ql, &qi, 1)) { spell *sp = (spell *) ql_get(ql, qi); - if (sp->level > t) continue; if (!dh) { @@ -804,7 +742,6 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, dh = 0; for (i = 0; i < MAXCOMBATSPELLS; i++) { const spell *sp; - if (!dh) { dh = 1; } else { @@ -816,7 +753,6 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, sp = get_combatspell(u, i); if (sp) { int sl = get_combatspelllevel(u, i); - bytes = (int)strlcpy(bufp, spell_name(sp, u->faction->locale), size); if (bytes && wrptr(&bufp, &size, bytes) != 0) { @@ -838,7 +774,6 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, } if (!isbattle) { boolean printed = 0; - order *ord;; for (ord = u->old_orders; ord; ord = ord->next) { if (is_repeated(ord)) { @@ -919,11 +854,8 @@ spskill(char *buffer, size_t size, const struct locale * lang, const struct unit * u, struct skill * sv, int *dh, int days) { char *bufp = buffer; - int i, effsk; - int bytes; - size_t tsize = 0; if (!u->number) @@ -964,7 +896,6 @@ spskill(char *buffer, size_t size, const struct locale * lang, if (sv->id == SK_MAGIC) { sc_mage *mage = get_mage(u); - if (mage && mage->magietyp != M_GRAY) { bytes = (int)strlcpy(bufp, LOC(lang, mkname("school", @@ -998,7 +929,6 @@ spskill(char *buffer, size_t size, const struct locale * lang, if (u->faction->options & want(O_SHOWSKCHANGE)) { int oldeff = 0; - int diff; if (sv->old > 0) { @@ -1042,9 +972,7 @@ spunit(struct strlist **SP, const struct faction *f, const unit * u, int indent, int mode) { char buf[DISPLAYSIZE]; - int dh = bufunit(f, u, indent, mode, buf, sizeof(buf)); - lparagraph(SP, buf, indent, (char)((u->faction == f) ? '*' : (dh ? '+' : '-'))); } @@ -1057,7 +985,6 @@ struct message *msg_curse(const struct curse *c, const void *obj, typ_t typ, return c->type->curseinfo(obj, typ, c, self); } else { message *msg = cinfo_simple(obj, typ, c, self); - if (msg == NULL) { const char *unknown[] = { "unit_unknown", "region_unknown", "building_unknown", @@ -1107,11 +1034,8 @@ static void get_addresses(report_context * ctx) { /* "TODO: travelthru" */ seen_region *sr = NULL; - region *r; - const faction *lastf = NULL; - quicklist *flist = 0; transfer_seen(&flist, &ctx->f->seen_factions); @@ -1121,9 +1045,7 @@ static void get_addresses(report_context * ctx) if (f_get_alliance(ctx->f)) { quicklist *ql = ctx->f->alliance->members; - int qi; - for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { ql_set_insert(&flist, ql_get(ql, qi)); } @@ -1136,14 +1058,11 @@ static void get_addresses(report_context * ctx) for (; sr != NULL; sr = sr->next) { int stealthmod = stealth_modifier(sr->mode); - r = sr->r; if (sr->mode == see_lighthouse) { unit *u = r->units; - for (; u; u = u->next) { faction *sf = visible_faction(ctx->f, u); - if (lastf != sf) { if (u->building || u->ship || (stealthmod > INT_MIN && cansee(ctx->f, r, u, stealthmod))) { @@ -1154,17 +1073,13 @@ static void get_addresses(report_context * ctx) } } else if (sr->mode == see_travel) { unit *u = r->units; - while (u) { faction *sf = visible_faction(ctx->f, u); - assert(u->faction != ctx->f); /* if this is see_travel only, then I shouldn't be here. */ if (lastf != sf) { attrib *a = a_find(r->attribs, &at_travelunit); - while (a && a->type == &at_travelunit) { unit *u2 = (unit *) a->data.v; - if (u2->faction == ctx->f) { if (cansee_unit(u2, u, stealthmod)) { ql_set_insert(&flist, sf); @@ -1179,11 +1094,9 @@ static void get_addresses(report_context * ctx) } } else if (sr->mode > see_travel) { const unit *u = r->units; - while (u != NULL) { if (u->faction != ctx->f) { faction *sf = visible_faction(ctx->f, u); - boolean ballied = sf && sf != ctx->f && sf != lastf && !fval(u, UFL_ANON_FACTION) && cansee(ctx->f, r, u, stealthmod); if (ballied || ALLIED(ctx->f, sf)) { @@ -1198,7 +1111,6 @@ static void get_addresses(report_context * ctx) if (f_get_alliance(ctx->f)) { faction *f2; - for (f2 = factions; f2; f2 = f2->next) { if (f2->alliance == ctx->f->alliance) { ql_set_insert(&flist, f2); @@ -1219,10 +1131,8 @@ seen_region **seen_init(void) void seen_done(seen_region * seehash[]) { int i; - for (i = 0; i != MAXSEEHASH; ++i) { seen_region *sd = seehash[i]; - if (sd == NULL) continue; while (sd->nextHash != NULL) @@ -1238,7 +1148,6 @@ void free_seen(void) { while (reuse) { seen_region *r = reuse; - reuse = reuse->nextHash; free(r); } @@ -1248,7 +1157,6 @@ void link_seen(seen_region * seehash[], const region * first, const region * last) { const region *r = first; - seen_region *sr = NULL; if (first == last) @@ -1261,7 +1169,6 @@ link_seen(seen_region * seehash[], const region * first, const region * last) while (r != last) { seen_region *sn = find_seen(seehash, r); - if (sn != NULL) { sr->next = sn; sr = sn; @@ -1274,9 +1181,7 @@ link_seen(seen_region * seehash[], const region * first, const region * last) seen_region *find_seen(struct seen_region *seehash[], const region * r) { unsigned int index = reg_hashkey(r) & (MAXSEEHASH - 1); - seen_region *find = seehash[index]; - while (find) { if (find->r == r) return find; @@ -1290,10 +1195,8 @@ static void get_seen_interval(report_context * ctx) /* this is required to find the neighbour regions of the ones we are in, * which may well be outside of [firstregion, lastregion) */ int i; - for (i = 0; i != MAXSEEHASH; ++i) { seen_region *sr = ctx->seen[i]; - while (sr != NULL) { if (ctx->first == NULL || sr->r->index < ctx->first->index) { ctx->first = sr->r; @@ -1312,10 +1215,8 @@ add_seen(struct seen_region *seehash[], struct region *r, unsigned char mode, boolean dis) { seen_region *find = find_seen(seehash, r); - if (find == NULL) { unsigned int index = reg_hashkey(r) & (MAXSEEHASH - 1); - if (!reuse) reuse = (seen_region *) calloc(1, sizeof(struct seen_region)); find = reuse; @@ -1343,7 +1244,6 @@ static report_type *report_types; void register_reporttype(const char *extension, report_fun write, int flag) { report_type *type = malloc(sizeof(report_type)); - type->extension = extension; type->write = write; type->flag = flag; @@ -1354,20 +1254,15 @@ void register_reporttype(const char *extension, report_fun write, int flag) static region_list *get_regions_distance(region * root, int radius) { region_list *rptr, *rlist = NULL; - region_list **rp = &rlist; - add_regionlist(rp, root); fset(root, RF_MARK); while (*rp) { region_list *r = *rp; - direction_t d; - rp = &r->next; for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r->data, d); - if (rn != NULL && !fval(rn, RF_MARK) && distance(rn, root) <= radius) { add_regionlist(rp, rn); fset(rn, RF_MARK); @@ -1383,13 +1278,10 @@ static region_list *get_regions_distance(region * root, int radius) static void view_default(struct seen_region **seen, region * r, faction * f) { direction_t dir; - for (dir = 0; dir != MAXDIRECTIONS; ++dir) { region *r2 = rconnect(r, dir); - if (r2) { connection *b = get_borders(r, r2); - while (b) { if (!b->type->transparent(b, f)) break; @@ -1404,13 +1296,10 @@ static void view_default(struct seen_region **seen, region * r, faction * f) static void view_neighbours(struct seen_region **seen, region * r, faction * f) { direction_t dir; - for (dir = 0; dir != MAXDIRECTIONS; ++dir) { region *r2 = rconnect(r, dir); - if (r2) { connection *b = get_borders(r, r2); - while (b) { if (!b->type->transparent(b, f)) break; @@ -1420,13 +1309,10 @@ static void view_neighbours(struct seen_region **seen, region * r, faction * f) if (add_seen(seen, r2, see_far, false)) { if (!(fval(r2->terrain, FORBIDDEN_REGION))) { direction_t dir; - for (dir = 0; dir != MAXDIRECTIONS; ++dir) { region *r3 = rconnect(r2, dir); - if (r3) { connection *b = get_borders(r2, r3); - while (b) { if (!b->type->transparent(b, f)) break; @@ -1448,18 +1334,13 @@ recurse_regatta(struct seen_region **seen, region * center, region * r, faction * f, int maxdist) { direction_t dir; - int dist = distance(center, r); - for (dir = 0; dir != MAXDIRECTIONS; ++dir) { region *r2 = rconnect(r, dir); - if (r2) { int ndist = distance(center, r2); - if (ndist > dist && fval(r2->terrain, SEA_REGION)) { connection *b = get_borders(r, r2); - while (b) { if (!b->type->transparent(b, f)) break; @@ -1481,13 +1362,10 @@ recurse_regatta(struct seen_region **seen, region * center, region * r, static void view_regatta(struct seen_region **seen, region * r, faction * f) { unit *u; - int skill = 0; - for (u = r->units; u; u = u->next) { if (u->faction == f) { int es = effskill(u, SK_PERCEPTION); - if (es > skill) skill = es; } @@ -1498,11 +1376,8 @@ static void view_regatta(struct seen_region **seen, region * r, faction * f) static void prepare_reports(void) { region *r; - faction *f; - static const struct building_type *bt_lighthouse = NULL; - if (bt_lighthouse == NULL) bt_lighthouse = bt_find("lighthouse"); @@ -1514,16 +1389,13 @@ static void prepare_reports(void) for (r = regions; r; r = r->next) { attrib *ru; - unit *u; - plane *p = rplane(r); reorder_units(r); if (p) { watcher *w = p->watchers; - for (; w; w = w->next) { add_seen(w->faction->seen, r, w->mode, false); #ifdef SMART_INTERVALS @@ -1536,21 +1408,16 @@ static void prepare_reports(void) if (u->building && u->building->type == bt_lighthouse) { /* we are in a lighthouse. add the regions we can see from here! */ int range = lighthouse_range(u->building, u->faction); - region_list *rlist = get_regions_distance(r, range); - region_list *rp = rlist; while (rp) { region *rl = rp->data; - if (fval(rl->terrain, SEA_REGION)) { direction_t d; - add_seen(u->faction->seen, rl, see_lighthouse, false); for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(rl, d); - if (rn != NULL) { add_seen(u->faction->seen, rn, see_neighbour, false); } @@ -1587,9 +1454,7 @@ static void prepare_reports(void) static seen_region **prepare_report(faction * f) { struct seen_region *sr; - region *r = firstregion(f); - region *last = lastregion(f); link_seen(f->seen, r, last); @@ -1601,14 +1466,11 @@ static seen_region **prepare_report(faction * f) for (; sr != NULL; sr = sr->next) { if (sr->mode > see_neighbour) { region *r = sr->r; - plane *p = rplane(r); void (*view) (struct seen_region **, region *, faction *) = view_default; - if (p && fval(p, PFL_SEESPECIAL)) { attrib *a = a_find(p->attribs, &at_viewrange); - if (a) view = (void (*)(struct seen_region **, region *, faction *))a->data.f; @@ -1622,11 +1484,8 @@ static seen_region **prepare_report(faction * f) int write_reports(faction * f, time_t ltime) { int backup = 1, maxbackup = 128; - boolean gotit = false; - struct report_context ctx; - const char *encoding = "UTF-8"; if (noreports) { @@ -1652,7 +1511,6 @@ int write_reports(faction * f, time_t ltime) for (; rtype != NULL; rtype = rtype->next) { if (f->options & rtype->flag) { char filename[MAX_PATH]; - sprintf(filename, "%s/%d-%s.%s", reportpath(), turn, factionid(f), rtype->extension); if (rtype->write(filename, &ctx, encoding) == 0) { @@ -1663,7 +1521,6 @@ int write_reports(faction * f, time_t ltime) if (errno) { char zText[64]; - puts(" ERROR"); sprintf(zText, "Waiting %u seconds before retry", backup); perror(zText); @@ -1686,15 +1543,12 @@ int write_reports(faction * f, time_t ltime) static void nmr_warnings(void) { faction *f, *fa; - #define FRIEND (HELP_GUARD|HELP_MONEY) for (f = factions; f; f = f->next) { if (!is_monsters(f) && (turn - f->lastorders) >= 2) { message *msg = NULL; - for (fa = factions; fa; fa = fa->next) { int warn = 0; - if (get_param_int(global.parameters, "rules.alliances", 0) != 0) { if (f->alliance && f->alliance == fa->alliance) { warn = 1; @@ -1721,15 +1575,12 @@ static void nmr_warnings(void) static void report_donations(void) { region *r; - for (r = regions; r; r = r->next) { while (r->donations) { donation *sp = r->donations; - if (sp->amount > 0) { struct message *msg = msg_message("donation", "from to amount", sp->f1, sp->f2, sp->amount); - r_addmessage(r, sp->f1, msg); r_addmessage(r, sp->f2, msg); msg_release(msg); @@ -1743,7 +1594,6 @@ static void report_donations(void) static void write_script(FILE * F, const faction * f) { report_type *rtype; - char buf[1024]; fprintf(F, "faction=%s:email=%s:lang=%s", factionid(f), f->email, @@ -1772,7 +1622,6 @@ int init_reports(void) #ifdef HAVE_STAT { stat_type st; - if (stat(reportpath(), &st) == 0) return 0; } @@ -1789,15 +1638,10 @@ int init_reports(void) int reports(void) { faction *f; - FILE *mailit; - time_t ltime = time(NULL); - const char *str; - int retval = 0; - char path[MAX_PATH]; if (verbosity >= 1) { @@ -1815,7 +1659,6 @@ int reports(void) for (f = factions; f; f = f->next) { int error = write_reports(f, ltime); - if (error) retval = error; if (mailit) @@ -1825,7 +1668,6 @@ int reports(void) fclose(mailit); free_seen(); str = get_param(global.parameters, "globalreport"); - #ifdef GLOBAL_REPORT if (str != NULL) { sprintf(path, "%s/%s.%u.cr", reportpath(), str, turn); @@ -1860,12 +1702,10 @@ static void var_free_order(variant x) static variant var_copy_items(variant x) { item *isrc; - resource *rdst = NULL, **rptr = &rdst; for (isrc = (item *) x.v; isrc != NULL; isrc = isrc->next) { resource *res = malloc(sizeof(resource)); - res->number = isrc->number; res->type = isrc->type->rtype; *rptr = res; @@ -1879,10 +1719,8 @@ static variant var_copy_items(variant x) static void var_free_resources(variant x) { resource *rsrc = (resource *) x.v; - while (rsrc) { resource *res = rsrc->next; - free(rsrc); rsrc = res; } @@ -1897,12 +1735,9 @@ static void var_free_regions(variant x) const char *trailinto(const region * r, const struct locale *lang) { char ref[32]; - const char *s; - if (r) { const char *tname = terrain_name(r); - strcat(strcpy(ref, tname), "_trail"); s = locale_string(lang, ref); if (s && *s) { @@ -1920,13 +1755,9 @@ f_regionid(const region * r, const faction * f, char *buffer, size_t size) strncpy(buffer, "(Chaos)", size); } else { plane *pl = rplane(r); - const char *name = pl ? pl->name : 0; - int nx = r->x, ny = r->y; - int named = (name && name[0]); - pnormalize(&nx, &ny, pl); adjust_coordinates(f, &nx, &ny, pl, r); strncpy(buffer, rname(r, f->locale), size); @@ -1940,9 +1771,7 @@ f_regionid(const region * r, const faction * f, char *buffer, size_t size) static char *f_regionid_s(const region * r, const faction * f) { static int i = 0; - static char bufs[4][NAMESIZE + 20]; - char *buf = bufs[(++i) % 4]; f_regionid(r, f, buf, NAMESIZE + 20); @@ -1953,11 +1782,8 @@ static char *f_regionid_s(const region * r, const faction * f) static void eval_localize(struct opstack **stack, const void *userdata) { /* (string, locale) -> string */ const struct faction *f = (const struct faction *)userdata; - const struct locale *lang = f ? f->locale : default_locale; - const char *c = (const char *)opop_v(stack); - c = locale_string(lang, c); opush_v(stack, strcpy(balloc(strlen(c) + 1), c)); } @@ -1965,19 +1791,12 @@ static void eval_localize(struct opstack **stack, const void *userdata) static void eval_trailto(struct opstack **stack, const void *userdata) { /* (int, int) -> int */ const struct faction *f = (const struct faction *)userdata; - const struct locale *lang = f ? f->locale : default_locale; - const struct region *r = (const struct region *)opop(stack).v; - const char *trail = trailinto(r, lang); - const char *rn = f_regionid_s(r, f); - variant var; - char *x = var.v = balloc(strlen(trail) + strlen(rn)); - sprintf(x, trail, rn); opush(stack, var); } @@ -1985,13 +1804,9 @@ static void eval_trailto(struct opstack **stack, const void *userdata) static void eval_unit(struct opstack **stack, const void *userdata) { /* unit -> string */ const struct faction *f = (const struct faction *)userdata; - const struct unit *u = (const struct unit *)opop(stack).v; - const char *c = u ? unitname(u) : LOC(f->locale, "an_unknown_unit"); - size_t len = strlen(c); - variant var; var.v = strcpy(balloc(len + 1), c); @@ -2001,13 +1816,9 @@ static void eval_unit(struct opstack **stack, const void *userdata) static void eval_unit_dative(struct opstack **stack, const void *userdata) { /* unit -> string */ const struct faction *f = (const struct faction *)userdata; - const struct unit *u = (const struct unit *)opop(stack).v; - const char *c = u ? unitname(u) : LOC(f->locale, "unknown_unit_dative"); - size_t len = strlen(c); - variant var; var.v = strcpy(balloc(len + 1), c); @@ -2017,13 +1828,10 @@ static void eval_unit_dative(struct opstack **stack, const void *userdata) static void eval_spell(struct opstack **stack, const void *userdata) { /* unit -> string */ const struct faction *f = (const struct faction *)userdata; - const struct spell *sp = (const struct spell *)opop(stack).v; - const char *c = sp ? spell_name(sp, f->locale) : LOC(f->locale, "an_unknown_spell"); size_t len = strlen(c); - variant var; var.v = strcpy(balloc(len + 1), c); @@ -2033,13 +1841,10 @@ static void eval_spell(struct opstack **stack, const void *userdata) static void eval_curse(struct opstack **stack, const void *userdata) { /* unit -> string */ const struct faction *f = (const struct faction *)userdata; - const struct curse_type *sp = (const struct curse_type *)opop(stack).v; - const char *c = sp ? curse_name(sp, f->locale) : LOC(f->locale, "an_unknown_curse"); size_t len = strlen(c); - variant var; var.v = strcpy(balloc(len + 1), c); @@ -2049,30 +1854,21 @@ static void eval_curse(struct opstack **stack, const void *userdata) static void eval_unitname(struct opstack **stack, const void *userdata) { /* unit -> string */ const struct faction *f = (const struct faction *)userdata; - const struct unit *u = (const struct unit *)opop(stack).v; - const char *c = u ? u->name : LOC(f->locale, "an_unknown_unit"); - size_t len = strlen(c); - variant var; var.v = strcpy(balloc(len + 1), c); opush(stack, var); } - static void eval_unitid(struct opstack **stack, const void *userdata) { /* unit -> int */ const struct faction *f = (const struct faction *)userdata; - const struct unit *u = (const struct unit *)opop(stack).v; - const char *c = u ? u->name : LOC(f->locale, "an_unknown_unit"); - size_t len = strlen(c); - variant var; var.v = strcpy(balloc(len + 1), c); @@ -2082,7 +1878,6 @@ static void eval_unitid(struct opstack **stack, const void *userdata) static void eval_unitsize(struct opstack **stack, const void *userdata) { /* unit -> int */ const struct unit *u = (const struct unit *)opop(stack).v; - variant var; var.i = u->number; @@ -2092,11 +1887,8 @@ static void eval_unitsize(struct opstack **stack, const void *userdata) static void eval_faction(struct opstack **stack, const void *userdata) { /* faction -> string */ const struct faction *f = (const struct faction *)opop(stack).v; - const char *c = factionname(f); - size_t len = strlen(c); - variant var; var.v = strcpy(balloc(len + 1), c); @@ -2106,14 +1898,10 @@ static void eval_faction(struct opstack **stack, const void *userdata) static void eval_alliance(struct opstack **stack, const void *userdata) { /* faction -> string */ const struct alliance *al = (const struct alliance *)opop(stack).v; - const char *c = alliancename(al); - variant var; - if (c != NULL) { size_t len = strlen(c); - var.v = strcpy(balloc(len + 1), c); } else var.v = NULL; @@ -2123,15 +1911,10 @@ static void eval_alliance(struct opstack **stack, const void *userdata) static void eval_region(struct opstack **stack, const void *userdata) { /* region -> string */ char name[NAMESIZE + 32]; - const struct faction *f = (const struct faction *)userdata; - const struct region *r = (const struct region *)opop(stack).v; - const char *c = write_regionname(r, f, name, sizeof(name)); - size_t len = strlen(c); - variant var; var.v = strcpy(balloc(len + 1), c); @@ -2141,13 +1924,9 @@ static void eval_region(struct opstack **stack, const void *userdata) static void eval_terrain(struct opstack **stack, const void *userdata) { /* region -> string */ const struct faction *f = (const struct faction *)userdata; - const struct region *r = (const struct region *)opop(stack).v; - const char *c = LOC(f->locale, terrain_name(r)); - size_t len = strlen(c); - variant var; var.v = strcpy(balloc(len + 1), c); @@ -2157,13 +1936,9 @@ static void eval_terrain(struct opstack **stack, const void *userdata) static void eval_ship(struct opstack **stack, const void *userdata) { /* ship -> string */ const struct faction *f = (const struct faction *)userdata; - const struct ship *u = (const struct ship *)opop(stack).v; - const char *c = u ? shipname(u) : LOC(f->locale, "an_unknown_ship"); - size_t len = strlen(c); - variant var; var.v = strcpy(balloc(len + 1), c); @@ -2173,13 +1948,9 @@ static void eval_ship(struct opstack **stack, const void *userdata) static void eval_building(struct opstack **stack, const void *userdata) { /* building -> string */ const struct faction *f = (const struct faction *)userdata; - const struct building *u = (const struct building *)opop(stack).v; - const char *c = u ? buildingname(u) : LOC(f->locale, "an_unknown_building"); - size_t len = strlen(c); - variant var; var.v = strcpy(balloc(len + 1), c); @@ -2189,13 +1960,9 @@ static void eval_building(struct opstack **stack, const void *userdata) static void eval_weight(struct opstack **stack, const void *userdata) { /* region -> string */ char buffer[32]; - const struct faction *f = (const struct faction *)userdata; - const struct locale *lang = f->locale; - int weight = opop_i(stack); - variant var; if (weight % SCALEWEIGHT == 0) { @@ -2221,17 +1988,11 @@ static void eval_weight(struct opstack **stack, const void *userdata) static void eval_resource(struct opstack **stack, const void *userdata) { const faction *report = (const faction *)userdata; - const struct locale *lang = report ? report->locale : default_locale; - int j = opop(stack).i; - const struct resource_type *res = (const struct resource_type *)opop(stack).v; - const char *c = LOC(lang, resourcename(res, j != 1)); - size_t len = strlen(c); - variant var; var.v = strcpy(balloc(len + 1), c); @@ -2241,17 +2002,11 @@ static void eval_resource(struct opstack **stack, const void *userdata) static void eval_race(struct opstack **stack, const void *userdata) { const faction *report = (const faction *)userdata; - const struct locale *lang = report ? report->locale : default_locale; - int j = opop(stack).i; - const race *r = (const race *)opop(stack).v; - const char *c = LOC(lang, rc_name(r, j != 1)); - size_t len = strlen(c); - variant var; var.v = strcpy(balloc(len + 1), c); @@ -2261,11 +2016,8 @@ static void eval_race(struct opstack **stack, const void *userdata) static void eval_order(struct opstack **stack, const void *userdata) { /* order -> string */ const struct order *ord = (const struct order *)opop(stack).v; - static char buf[256]; - size_t len; - variant var; unused(userdata); @@ -2278,24 +2030,17 @@ static void eval_order(struct opstack **stack, const void *userdata) static void eval_resources(struct opstack **stack, const void *userdata) { /* order -> string */ const faction *report = (const faction *)userdata; - const struct locale *lang = report ? report->locale : default_locale; - const struct resource *res = (const struct resource *)opop(stack).v; - static char buf[1024]; /* but we only use about half of this */ - size_t size = sizeof(buf) - 1; - variant var; char *bufp = buf; - while (res != NULL && size > 4) { const char *rname = resourcename(res->type, (res->number != 1) ? NMF_PLURAL : 0); int bytes = snprintf(bufp, size, "%d %s", res->number, LOC(lang, rname)); - if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0 || size < sizeof(buf) / 2) { WARN_STATIC_BUFFER(); break; @@ -2316,19 +2061,12 @@ static void eval_resources(struct opstack **stack, const void *userdata) static void eval_regions(struct opstack **stack, const void *userdata) { /* order -> string */ const faction *report = (const faction *)userdata; - int i = opop(stack).i; - int end, begin = opop(stack).i; - const arg_regions *regions = (const arg_regions *)opop(stack).v; - static char buf[256]; - size_t size = sizeof(buf) - 1; - variant var; - char *bufp = buf; if (regions == NULL) { @@ -2341,9 +2079,7 @@ static void eval_regions(struct opstack **stack, const void *userdata) } for (i = begin; i < end; ++i) { const char *rname = (const char *)regionname(regions->regions[i], report); - int bytes = (int)strlcpy(bufp, rname, size); - if (bytes && wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -2361,21 +2097,13 @@ static void eval_regions(struct opstack **stack, const void *userdata) static void eval_trail(struct opstack **stack, const void *userdata) { /* order -> string */ const faction *report = (const faction *)userdata; - const struct locale *lang = report ? report->locale : default_locale; - int i, end = 0, begin = 0; - const arg_regions *regions = (const arg_regions *)opop(stack).v; - static char buf[512]; - size_t size = sizeof(buf) - 1; - variant var; - char *bufp = buf; - #ifdef _SECURECRT_ERRCODE_VALUES_DEFINED /* stupid MS broke snprintf */ int eold = errno; @@ -2385,13 +2113,9 @@ static void eval_trail(struct opstack **stack, const void *userdata) end = regions->nregions; for (i = begin; i < end; ++i) { region *r = regions->regions[i]; - const char *trail = trailinto(r, lang); - const char *rn = f_regionid_s(r, report); - int bytes = snprintf(bufp, size, trail, rn); - if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -2419,15 +2143,10 @@ static void eval_trail(struct opstack **stack, const void *userdata) static void eval_direction(struct opstack **stack, const void *userdata) { const faction *report = (const faction *)userdata; - const struct locale *lang = report ? report->locale : default_locale; - int i = opop(stack).i; - const char *c = LOC(lang, (i >= 0) ? directions[i] : "unknown_direction"); - size_t len = strlen(c); - variant var; var.v = strcpy(balloc(len + 1), c); @@ -2437,15 +2156,10 @@ static void eval_direction(struct opstack **stack, const void *userdata) static void eval_skill(struct opstack **stack, const void *userdata) { const faction *report = (const faction *)userdata; - const struct locale *lang = report ? report->locale : default_locale; - skill_t sk = (skill_t) opop(stack).i; - const char *c = skillname(sk, lang); - size_t len = strlen(c); - variant var; var.v = strcpy(balloc(len + 1), c); @@ -2455,11 +2169,8 @@ static void eval_skill(struct opstack **stack, const void *userdata) static void eval_int36(struct opstack **stack, const void *userdata) { int i = opop(stack).i; - const char *c = itoa36(i); - size_t len = strlen(c); - variant var; var.v = strcpy(balloc(len + 1), c); @@ -2474,15 +2185,12 @@ static void eval_int36(struct opstack **stack, const void *userdata) static void log_orders(const struct message *msg) { faction *f = get_monsters(); - char buffer[4096]; - int i; for (i = 0; i != msg->type->nparameters; ++i) { if (msg->type->types[i]->copy == &var_copy_order) { const char *section = nr_section(msg); - nr_render(msg, f ? f->locale : default_locale, buffer, sizeof(buffer), f); log_printf("MESSAGE [%s]: %s\n", section, buffer); break; @@ -2493,9 +2201,7 @@ static void log_orders(const struct message *msg) int report_action(region * r, unit * actor, message * msg, int flags) { int result = 0; - unit *u; - int view = flags & (ACTION_CANSEE | ACTION_CANNOTSEE); /* melden, 1x pro Partei */ @@ -2508,7 +2214,6 @@ int report_action(region * r, unit * actor, message * msg, int flags) for (u = r->units; u; u = u->next) { if (!fval(u->faction, FFL_SELECT)) { boolean show = u->faction == actor->faction; - fset(u->faction, FFL_SELECT); if (view == ACTION_CANSEE) { /* Bei Fernzaubern sieht nur die eigene Partei den Magier */ @@ -2538,7 +2243,6 @@ int report_action(region * r, unit * actor, message * msg, int flags) return result; } - void register_reports(void) { /* register datatypes for the different message objects */ @@ -2561,7 +2265,6 @@ void register_reports(void) register_argtype("items", var_free_resources, var_copy_items, VAR_VOIDPTR); register_argtype("regions", var_free_regions, NULL, VAR_VOIDPTR); - msg_log_create = &log_orders; /* register functions that turn message contents to readable strings */ diff --git a/src/kernel/reports.h b/src/kernel/reports.h index 18da82306..5a643cc01 100644 --- a/src/kernel/reports.h +++ b/src/kernel/reports.h @@ -100,7 +100,6 @@ extern "C" { extern void register_reporttype(const char *extension, report_fun write, int flag); - extern int bufunit(const struct faction *f, const struct unit *u, int indent, int mode, char *buf, size_t size); diff --git a/src/kernel/resources.c b/src/kernel/resources.c index 1cffd5d74..0cd731869 100644 --- a/src/kernel/resources.c +++ b/src/kernel/resources.c @@ -30,10 +30,8 @@ static double ResourceFactor(void) { static double value = -1.0; - if (value < 0) { const char *str = get_param(global.parameters, "resource.factor"); - value = str ? atof(str) : 1.0; } return value; @@ -42,7 +40,6 @@ static double ResourceFactor(void) void update_resources(region * r) { struct rawmaterial *res = r->resources; - while (res) { if (res->type->update) res->type->update(res, r); @@ -55,7 +52,6 @@ extern int dice_rand(const char *s); static void update_resource(struct rawmaterial *res, double modifier) { double amount = 1 + (res->level - res->startlevel) * res->divisor / 100.0; - amount = ResourceFactor() * res->base * amount * modifier; if (amount < 1.0) res->amount = 1; @@ -85,16 +81,13 @@ add_resource(region * r, int level, int base, int divisor, void terraform_resources(region * r) { int i; - const terrain_type *terrain = r->terrain; if (terrain->production == NULL) return; for (i = 0; terrain->production[i].type; ++i) { rawmaterial *rm; - const terrain_production *production = terrain->production + i; - const resource_type *rtype = production->type; for (rm = r->resources; rm; rm = rm->next) { @@ -128,7 +121,6 @@ static void terraform_default(struct rawmaterial *res, const region * r) static void resource_random_change(int *pvalue, boolean used) { int split = 5; - int rnd = rng_int() % 100; if (pvalue == 0 || rnd % 10 >= 10) @@ -154,7 +146,6 @@ static int visible_default(const rawmaterial * res, int skilllevel) * plus current level of difficulty */ { const struct item_type *itype = res->type->rtype->itype; - if (res->level <= 1 && res->level + itype->construction->minskill <= skilllevel + 1) { assert(res->amount > 0); @@ -189,7 +180,6 @@ static void use_default(rawmaterial * res, const region * r, int amount) struct rawmaterial *rm_get(region * r, const struct resource_type *rtype) { struct rawmaterial *rm = r->resources; - while (rm && rm->type->rtype != rtype) rm = rm->next; return rm; @@ -200,7 +190,6 @@ struct rawmaterial_type *rawmaterialtypes = 0; struct rawmaterial_type *rmt_find(const char *str) { rawmaterial_type *rmt = rawmaterialtypes; - while (rmt && strcmp(rmt->name, str) != 0) rmt = rmt->next; return rmt; @@ -209,7 +198,6 @@ struct rawmaterial_type *rmt_find(const char *str) struct rawmaterial_type *rmt_get(const struct resource_type *rtype) { rawmaterial_type *rmt = rawmaterialtypes; - while (rmt && rmt->rtype != rtype) rmt = rmt->next; return rmt; @@ -219,7 +207,6 @@ struct rawmaterial_type *rmt_create(const struct resource_type *rtype, const char *name) { rawmaterial_type *rmtype = malloc(sizeof(rawmaterial_type)); - rmtype->name = strdup(name); rmtype->rtype = rtype; rmtype->terraform = terraform_default; diff --git a/src/kernel/save.c b/src/kernel/save.c index 0c1fa0a69..194598b1a 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -89,9 +89,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* exported symbols symbols */ const char *game_name = "eressea"; - int firstx = 0, firsty = 0; - int enc_gamedata = 0; /* local symbols */ @@ -100,7 +98,6 @@ static region *current_region; char *rns(FILE * f, char *c, size_t size) { char *s = c; - do { *s = (char)getc(f); } while (*s != '"'); @@ -133,9 +130,7 @@ FILE *cfopen(const char *filename, const char *mode) int freadstr(FILE * F, int encoding, char *start, size_t size) { char *str = start; - boolean quote = false; - for (;;) { int c = fgetc(F); @@ -178,11 +173,8 @@ int freadstr(FILE * F, int encoding, char *start, size_t size) if ((size_t) (str - start + 1) < size) { if (encoding == XML_CHAR_ENCODING_8859_1 && c & 0x80) { char inbuf = (char)c; - size_t inbytes = 1; - size_t outbytes = size - (str - start); - int ret = unicode_latin1_to_utf8(str, &outbytes, &inbuf, &inbytes); if (ret > 0) @@ -203,13 +195,9 @@ int freadstr(FILE * F, int encoding, char *start, size_t size) if ((size_t) (str - start + 1) < size) { if (encoding == XML_CHAR_ENCODING_8859_1 && c & 0x80) { char inbuf = (char)c; - size_t inbytes = 1; - size_t outbytes = size - (str - start); - int ret = unicode_latin1_to_utf8(str, &outbytes, &inbuf, &inbytes); - if (ret > 0) str += ret; else { @@ -225,19 +213,16 @@ int freadstr(FILE * F, int encoding, char *start, size_t size) } } - /** writes a quoted string to the file * no trailing space, since this is used to make the creport. */ int fwritestr(FILE * F, const char *str) { int nwrite = 0; - fputc('\"', F); if (str) while (*str) { int c = (int)(unsigned char)*str++; - switch (c) { case '"': case '\\': @@ -262,7 +247,6 @@ int fwritestr(FILE * F, const char *str) static unit *unitorders(FILE * F, int enc, struct faction *f) { int i; - unit *u; if (!f) @@ -283,7 +267,6 @@ static unit *unitorders(FILE * F, int enc, struct faction *f) ordp = &u->old_orders; while (*ordp) { order *ord = *ordp; - if (!is_repeated(ord)) { *ordp = ord->next; ord->next = NULL; @@ -301,7 +284,6 @@ static unit *unitorders(FILE * F, int enc, struct faction *f) 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 */ @@ -312,14 +294,11 @@ static unit *unitorders(FILE * F, int enc, struct faction *f) if (s[0]) { const char *stok = s; - stok = parse_token(&stok); if (stok) { boolean quit = false; - param_t param = findparam(stok, u->faction->locale); - switch (param) { case P_UNIT: case P_REGION: @@ -356,7 +335,6 @@ static unit *unitorders(FILE * F, int enc, struct faction *f) static faction *factionorders(void) { faction *f = NULL; - int fid = getid(); f = findfaction(fid); @@ -398,11 +376,8 @@ static param_t igetparam(const char *s, const struct locale *lang) int readorders(const char *filename) { FILE *F = NULL; - const char *b; - int nfactions = 0; - struct faction *f = NULL; if (filename) @@ -421,9 +396,7 @@ int readorders(const char *filename) while (b) { const struct locale *lang = f ? f->locale : default_locale; - int p; - const char *s; switch (igetparam(b, lang)) { @@ -509,7 +482,6 @@ int inner_world(region * r) } int maxregions = -1; - int loadplane = 0; enum { @@ -538,7 +510,6 @@ void create_backup(char *file) { #ifdef HAVE_LINK char bfile[MAX_PATH]; - int c = 1; if (access(file, R_OK) == 0) @@ -555,11 +526,8 @@ void read_items(struct storage *store, item ** ilist) { for (;;) { char ibuf[32]; - const item_type *itype; - int i; - store->r_str_buf(store, ibuf, sizeof(ibuf)); if (!strcmp("end", ibuf)) break; @@ -580,9 +548,7 @@ void read_items(struct storage *store, item ** ilist) static void read_alliances(struct storage *store) { char pbuf[8]; - int id, terminator = 0; - if (store->version < SAVEALLIANCE_VERSION) { if (!AllianceRestricted() && !AllianceAuto()) return; @@ -596,9 +562,7 @@ static void read_alliances(struct storage *store) } while (id != terminator) { char aname[128]; - alliance *al; - store->r_str_buf(store, aname, sizeof(aname)); al = makealliance(id, aname); if (store->version >= OWNER_2_VERSION) { @@ -618,7 +582,6 @@ static void read_alliances(struct storage *store) void write_alliances(struct storage *store) { alliance *al = alliances; - while (al) { if (al->_leader) { store->w_id(store, al->id); @@ -636,7 +599,6 @@ void write_alliances(struct storage *store) void write_items(struct storage *store, item * ilist) { item *itm; - for (itm = ilist; itm; itm = itm->next) { assert(itm->number >= 0); if (itm->number) { @@ -650,11 +612,8 @@ void write_items(struct storage *store, item * ilist) 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) { @@ -672,10 +631,8 @@ static int resolve_owner(variant id, void *address) static void read_owner(struct storage *store, region_owner ** powner) { int since_turn = store->r_int(store); - if (since_turn >= 0) { region_owner *owner = malloc(sizeof(region_owner)); - owner->since_turn = since_turn; owner->morale_turn = store->r_int(store); if (store->version >= MOURNING_VERSION) { @@ -685,7 +642,6 @@ static void read_owner(struct storage *store, region_owner ** powner) } if (store->version >= OWNER_2_VERSION) { int id = store->r_int(store); - owner->alliance = id ? findalliance(id) : NULL; } else { owner->alliance = NULL; @@ -713,9 +669,7 @@ static void write_owner(struct storage *store, region_owner * owner) int current_turn(void) { char zText[MAX_PATH]; - int cturn = 0; - FILE *f; sprintf(zText, "%s/turn", basepath()); @@ -732,7 +686,6 @@ writeorder(struct storage *store, const struct order *ord, const struct locale *lang) { char obuf[1024]; - write_order(ord, obuf, sizeof(obuf)); if (obuf[0]) store->w_str(store, obuf); @@ -741,17 +694,11 @@ writeorder(struct storage *store, const struct order *ord, unit *read_unit(struct storage *store) { skill_t sk; - unit *u; - int number, n, p; - order **orderp; - char obuf[1024]; - faction *f; - char rname[32]; n = store->r_id(store); @@ -789,14 +736,11 @@ unit *read_unit(struct storage *store) if (store->version < STORAGE_VERSION) { char *space; - store->r_str_buf(store, rname, sizeof(rname)); space = strchr(rname, ' '); if (space != NULL) { char *inc = space + 1; - char *outc = space; - do { while (*inc == ' ') ++inc; @@ -825,7 +769,6 @@ unit *read_unit(struct storage *store) if (u->race->describe) { const char *rcdisp = u->race->describe(u, u->faction->locale); - if (u->display && rcdisp) { /* see if the data file contains old descriptions */ if (strcmp(rcdisp, u->display) == 0) { @@ -869,7 +812,6 @@ unit *read_unit(struct storage *store) while (obuf[0]) { if (!lomem) { order *ord = parse_order(obuf, u->faction->locale); - if (ord != NULL) { if (++n < MAXORDERS) { if (!is_persistent(ord) || ++p < MAXPERSISTENT) { @@ -891,7 +833,6 @@ unit *read_unit(struct storage *store) } if (store->version < NOLASTORDER_VERSION) { order *ord; - store->r_str_buf(store, obuf, sizeof(obuf)); ord = parse_order(obuf, u->faction->locale); if (ord != NULL) { @@ -903,12 +844,9 @@ unit *read_unit(struct storage *store) assert(u->race); while ((sk = (skill_t) store->r_int(store)) != NOSKILL) { int level = store->r_int(store); - int weeks = store->r_int(store); - if (level) { skill *sv = add_skill(u, sk); - sv->level = sv->old = (unsigned char)level; sv->weeks = (unsigned char)weeks; } @@ -928,11 +866,8 @@ unit *read_unit(struct storage *store) void write_unit(struct storage *store, const unit * u) { order *ord; - int i, p = 0; - const race *irace = u_irace(u); - write_unit_reference(u, store); write_faction_reference(u->faction, store); store->w_str(store, (const char *)u->name); @@ -976,7 +911,6 @@ void write_unit(struct storage *store, const unit * 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) { store->w_int(store, sv->id); @@ -1001,11 +935,8 @@ void write_unit(struct storage *store, const unit * u) static region *readregion(struct storage *store, int x, int y) { region *r = findregion(x, y); - const terrain_type *terrain; - char token[32]; - unsigned int uid = 0; if (store->version >= UID_VERSION) { @@ -1014,7 +945,6 @@ static region *readregion(struct storage *store, int x, int y) if (r == NULL) { plane *pl = findplane(x, y); - r = new_region(x, y, pl, uid); } else { assert(uid == 0 || r->uid == uid); @@ -1027,7 +957,6 @@ static region *readregion(struct storage *store, int x, int y) } while (r->resources) { rawmaterial *rm = r->resources; - r->resources = rm->next; free(rm); } @@ -1037,14 +966,12 @@ static region *readregion(struct storage *store, int x, int y) store->r_str_buf(store, NULL, 0); } else { char info[DISPLAYSIZE]; - store->r_str_buf(store, info, sizeof(info)); region_setinfo(r, info); } if (store->version < TERRAIN_VERSION) { int ter = store->r_int(store); - terrain = newterrain((terrain_t) ter); if (terrain == NULL) { log_error( @@ -1054,7 +981,6 @@ static region *readregion(struct storage *store, int x, int y) } } else { char name[64]; - store->r_str_buf(store, name, sizeof(name)); terrain = get_terrain(name); if (terrain == NULL) { @@ -1073,7 +999,6 @@ static region *readregion(struct storage *store, int x, int y) } if (r->land) { int i; - rawmaterial **pres = &r->resources; i = store->r_int(store); @@ -1101,7 +1026,6 @@ static region *readregion(struct storage *store, int x, int y) assert(*pres == NULL); for (;;) { rawmaterial *res; - store->r_str_buf(store, token, sizeof(token)); if (strcmp(token, "end") == 0) break; @@ -1127,7 +1051,6 @@ static region *readregion(struct storage *store, int x, int y) store->r_str_buf(store, token, sizeof(token)); if (strcmp(token, "noherb") != 0) { const resource_type *rtype = rt_find(token); - assert(rtype && rtype->itype && fval(rtype->itype, ITF_HERB)); rsetherbtype(r, rtype->itype); } else { @@ -1146,7 +1069,6 @@ static region *readregion(struct storage *store, int x, int y) if (r->land) { for (;;) { const struct item_type *itype; - store->r_str_buf(store, token, sizeof(token)); if (!strcmp(token, "end")) break; @@ -1179,11 +1101,8 @@ void writeregion(struct storage *store, const region * r) store->w_brk(store); if (fval(r->terrain, LAND_REGION)) { const item_type *rht; - struct demand *demand; - rawmaterial *res = r->resources; - store->w_str(store, (const char *)r->land->name); assert(rtrees(r, 0) >= 0); assert(rtrees(r, 1) >= 0); @@ -1236,7 +1155,6 @@ void writeregion(struct storage *store, const region * r) static ally **addally(const faction * f, ally ** sfp, int aid, int state) { struct faction *af = findfaction(aid); - ally *sf; state &= ~HELP_OBSERVE; @@ -1252,7 +1170,6 @@ static ally **addally(const faction * f, ally ** sfp, int aid, int state) sf->faction = af; if (!sf->faction) { variant id; - id.i = aid; ur_add(id, &sf->faction, resolve_faction); } @@ -1271,15 +1188,10 @@ static ally **addally(const faction * f, ally ** sfp, int aid, int state) faction *readfaction(struct storage * store) { ally **sfp; - int planes; - int i = store->r_id(store); - faction *f = findfaction(i); - char email[128]; - char token[32]; if (f == NULL) { @@ -1294,12 +1206,10 @@ faction *readfaction(struct storage * store) if (alliances || store->version >= OWNER_2_VERSION) { int allianceid = store->r_id(store); - if (allianceid > 0) f->alliance = findalliance(allianceid); if (f->alliance) { alliance *al = f->alliance; - if (al->flags & ALF_NON_ALLIED) { assert(!al->members || !"non-allied dummy-alliance has more than one member"); @@ -1308,7 +1218,6 @@ faction *readfaction(struct storage * store) } else if (rule_region_owners()) { /* compat fix for non-allied factions */ alliance *al = makealliance(0, NULL); - setalliance(f, al); } if (store->version >= OWNER_2_VERSION) { @@ -1362,7 +1271,6 @@ faction *readfaction(struct storage * store) } for (;;) { int level; - store->r_tok_buf(store, token, sizeof(token)); if (strcmp("end", token) == 0) break; @@ -1371,11 +1279,8 @@ faction *readfaction(struct storage * store) planes = store->r_int(store); while (--planes >= 0) { int id = store->r_int(store); - int ux = store->r_int(store); - int uy = store->r_int(store); - set_ursprung(f, id, ux, uy); } f->newbies = 0; @@ -1390,18 +1295,14 @@ faction *readfaction(struct storage * store) sfp = &f->allies; if (store->version < ALLIANCES_VERSION) { int p = store->r_int(store); - while (--p >= 0) { int aid = store->r_id(store); - int state = store->r_int(store); - sfp = addally(f, sfp, aid, state); } } else { for (;;) { int aid = 0; - if (store->version < STORAGE_VERSION) { store->r_tok_buf(store, token, sizeof(token)); if (strcmp(token, "end") != 0) { @@ -1412,7 +1313,6 @@ faction *readfaction(struct storage * store) } if (aid > 0) { int state = store->r_int(store); - sfp = addally(f, sfp, aid, state); } else { break; @@ -1430,7 +1330,6 @@ faction *readfaction(struct storage * store) void writefaction(struct storage *store, const faction * f) { ally *sf; - ursprung *ur; write_faction_reference(f, store); @@ -1477,9 +1376,7 @@ void writefaction(struct storage *store, const faction * f) for (sf = f->allies; sf; sf = sf->next) { int no = (sf->faction != NULL) ? sf->faction->no : 0; - int status = alliedfaction(NULL, f, sf->faction, HELP_ALL); - if (status != 0) { store->w_id(store, no); store->w_int(store, sf->status); @@ -1494,27 +1391,16 @@ void writefaction(struct storage *store, const faction * f) int readgame(const char *filename, int mode, int backup) { int i, n, p; - faction *f, **fp; - region *r; - building *b, **bp; - ship **shp; - unit *u; - int rmax = maxregions; - char path[MAX_PATH]; - char token[32]; - const struct building_type *bt_lighthouse = bt_find("lighthouse"); - storage my_store = (mode == IO_BINARY) ? binary_store : text_store; - storage *store = &my_store; sprintf(path, "%s/%s", datapath(), filename); @@ -1537,7 +1423,6 @@ int readgame(const char *filename, int mode, int backup) store->r_str_buf(store, basefile, sizeof(basefile)); if (strcmp(game_name, basefile) != 0) { char buffer[64]; - snprintf(buffer, sizeof(buffer), "%s.xml", game_name); if (strcmp(basefile, buffer) != 0) { log_warning(("game mismatch: datafile contains %s, game is %s\n", @@ -1548,13 +1433,10 @@ int readgame(const char *filename, int mode, int backup) } } a_read(store, &global.attribs, NULL); - global.data_turn = turn = store->r_int(store); - log_info((1, " - reading turn %d\n", turn)); rng_init(turn); ++global.cookie; - store->r_int(store); /* max_unique_id = */ nextborder = store->r_int(store); @@ -1563,9 +1445,7 @@ int readgame(const char *filename, int mode, int backup) n = store->r_int(store); while (--n >= 0) { int id = store->r_int(store); - variant fno; - plane *pl = getplanebyid(id); if (pl == NULL) { @@ -1584,7 +1464,6 @@ int readgame(const char *filename, int mode, int backup) /* read watchers */ if (store->version < FIX_WATCHERS_VERSION) { char rname[64]; - /* before this version, watcher storage was pretty broken. we are incompatible and don't read them */ for (;;) { store->r_tok_buf(store, rname, sizeof(rname)); @@ -1599,7 +1478,6 @@ int readgame(const char *filename, int mode, int backup) fno = read_faction_reference(store); while (fno.i) { watcher *w = (watcher *) malloc(sizeof(watcher)); - ur_add(fno, &w->faction, resolve_faction); w->mode = (unsigned char)store->r_int(store); w->next = pl->watchers; @@ -1647,9 +1525,7 @@ int readgame(const char *filename, int mode, int backup) log_info((1, " - Einzulesende Regionen: %d/%d\r", rmax, n)); while (--n >= 0) { unit **up; - int x = store->r_int(store); - int y = store->r_int(store); if ((n & 0x3FF) == 0) { /* das spart extrem Zeit */ @@ -1693,7 +1569,6 @@ int readgame(const char *filename, int mode, int backup) while (--p >= 0) { ship *sh = (ship *) calloc(1, sizeof(ship)); - sh->region = r; sh->no = store->r_id(store); *shp = sh; @@ -1736,7 +1611,6 @@ int readgame(const char *filename, int mode, int backup) while (--p >= 0) { unit *u = read_unit(store); - sc_mage *mage; assert(u->region == NULL); @@ -1748,9 +1622,7 @@ int readgame(const char *filename, int mode, int backup) mage = get_mage(u); if (mage) { faction *f = u->faction; - int skl = effskill(u, SK_MAGIC); - if (!is_monsters(f) && f->magiegebiet == M_GRAY) { log_error(("faction %s had magic=gray, fixing (%s)\n", factionname(f), magic_school[mage->magietyp])); @@ -1779,7 +1651,6 @@ int readgame(const char *filename, int mode, int backup) for (r = regions; r; r = r->next) { if (r->flags & RF_LIGHTHOUSE) { building *b; - for (b = r->buildings; b; b = b->next) update_lighthouse(b); } @@ -1790,7 +1661,6 @@ int readgame(const char *filename, int mode, int backup) f->alive = 1; if (f->no == 0) { int no = 666; - while (findfaction(no)) ++no; log_warning(("renum(monsters, %d)\n", no)); @@ -1815,10 +1685,8 @@ int readgame(const char *filename, int mode, int backup) static void clear_monster_orders(void) { faction *f = get_monsters(); - if (f) { unit *u; - for (u = f->units; u; u = u->nextF) { free_orders(&u->orders); } @@ -1828,27 +1696,16 @@ static void clear_monster_orders(void) int writegame(const char *filename, int mode) { char *base; - int n; - faction *f; - region *r; - building *b; - ship *sh; - unit *u; - plane *pl; - char path[MAX_PATH]; - storage my_store = (mode == IO_BINARY) ? binary_store : text_store; - storage *store = &my_store; - store->version = RELEASE_VERSION; clear_monster_orders(); @@ -1863,7 +1720,6 @@ int writegame(const char *filename, int mode) store->encoding = enc_gamedata; if (store->open(store, path, IO_WRITE) != 0) { int err = os_mkdir(datapath(), 0700); - if (err) return err; if (store->open(store, path, IO_WRITE) != 0) { @@ -1882,7 +1738,6 @@ int writegame(const char *filename, int mode) store->w_brk(store); a_write(store, global.attribs, NULL); - store->w_brk(store); store->w_int(store, turn); @@ -1896,7 +1751,6 @@ int writegame(const char *filename, int mode) for (pl = planes; pl; pl = pl->next) { watcher *w; - store->w_int(store, pl->id); store->w_str(store, pl->name); store->w_int(store, pl->minx); @@ -1917,7 +1771,6 @@ int writegame(const char *filename, int mode) store->w_brk(store); } - /* Write factions */ #if RELEASE_VERSION>=ALLIANCES_VERSION write_alliances(store); @@ -2028,7 +1881,6 @@ void a_writeshorts(const attrib * a, const void *owner, struct storage *store) int a_readchars(attrib * a, void *owner, struct storage *store) { int i; - if (store->version < ATTRIBREAD_VERSION) { return a_readint(a, store, owner); } diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 85d489dc2..2b399afa2 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -45,7 +45,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include - quicklist *shiptypes = NULL; static local_names *snames; @@ -53,7 +52,6 @@ static local_names *snames; const ship_type *findshiptype(const char *name, const struct locale *lang) { local_names *sn = snames; - variant var; while (sn) { @@ -63,7 +61,6 @@ const ship_type *findshiptype(const char *name, const struct locale *lang) } if (!sn) { quicklist *ql; - int qi; sn = (local_names *) calloc(sizeof(local_names), 1); @@ -72,11 +69,8 @@ const ship_type *findshiptype(const char *name, const struct locale *lang) for (qi = 0, ql = shiptypes; ql; ql_advance(&ql, &qi, 1)) { ship_type *stype = (ship_type *) ql_get(ql, qi); - variant var; - const char *n = locale_string(lang, stype->name[0]); - var.v = (void *)stype; addtoken(&sn->names, n, var); } @@ -90,12 +84,10 @@ const ship_type *findshiptype(const char *name, const struct locale *lang) const ship_type *st_find(const char *name) { quicklist *ql; - int qi; for (qi = 0, ql = shiptypes; ql; ql_advance(&ql, &qi, 1)) { ship_type *stype = (ship_type *) ql_get(ql, qi); - if (strcmp(stype->name[0], name) == 0) { return stype; } @@ -110,7 +102,6 @@ void st_register(const ship_type * type) #define SMAXHASH 7919 ship *shiphash[SMAXHASH]; - void shash(ship * s) { ship *old = shiphash[s->no % SMAXHASH]; @@ -186,7 +177,6 @@ static ship *deleted_ships; ship *new_ship(const ship_type * stype, const struct locale *lang, region * r) { static char buffer[7 + IDSIZE + 1]; - ship *sh = (ship *) calloc(1, sizeof(ship)); assert(stype); @@ -206,7 +196,6 @@ ship *new_ship(const ship_type * stype, const struct locale *lang, region * r) void remove_ship(ship ** slist, ship * sh) { region *r = sh->region; - unit *u = r->units; handle_event(sh->attribs, "destroy", sh); @@ -239,7 +228,6 @@ void free_ships(void) { while (deleted_ships) { ship *s = deleted_ships; - deleted_ships = s->next; } } @@ -254,13 +242,9 @@ const char *write_shipname(const ship * sh, char *ibuf, size_t size) const char *shipname(const ship * sh) { typedef char name[OBJECTIDSIZE + 1]; - static name idbuf[8]; - static int nextbuf = 0; - char *ibuf = idbuf[(++nextbuf) % 8]; - return write_shipname(sh, ibuf, sizeof(name)); } @@ -295,7 +279,6 @@ void getshipweight(const ship * sh, int *sweight, int *scabins) *sweight += weight(u); if (sh->type->cabins) { int pweight = u->number * u->race->weight; - /* weight goes into number of cabins, not cargo */ *scabins += pweight; *sweight -= pweight; @@ -307,7 +290,6 @@ void getshipweight(const ship * sh, int *sweight, int *scabins) unit *shipowner(const ship * sh) { unit *u; - unit *first = NULL; const region *r = sh->region; diff --git a/src/kernel/skill.c b/src/kernel/skill.c index c051f8b16..89431ad81 100644 --- a/src/kernel/skill.c +++ b/src/kernel/skill.c @@ -86,7 +86,6 @@ const char *skillname(skill_t sk, const struct locale *lang) void enable_skill(const char *skname, boolean value) { skill_t sk; - for (sk = 0; sk != MAXSKILLS; ++sk) { if (strcmp(skillnames[sk], skname) == 0) { skill_enabled[sk] = value; @@ -99,7 +98,6 @@ void enable_skill(const char *skname, boolean value) skill_t sk_find(const char *name) { skill_t i; - if (name == NULL) return NOSKILL; if (strncmp(name, "sk_", 3) == 0) @@ -139,7 +137,6 @@ attrib *make_skillmod(skill_t sk, unsigned int flags, skillmod_fun special, double multiplier, int bonus) { attrib *a = a_new(&at_skillmod); - skillmod_data *smd = (skillmod_data *) a->data.v; smd->skill = sk; @@ -158,7 +155,6 @@ skillmod(const attrib * a, const unit * u, const region * r, skill_t sk, for (a = a_find((attrib *) a, &at_skillmod); a && a->type == &at_skillmod; a = a->next) { skillmod_data *smd = (skillmod_data *) a->data.v; - if (smd->skill != NOSKILL && smd->skill != sk) continue; if (flags != SMF_ALWAYS && (smd->flags & flags) == 0) @@ -209,14 +205,12 @@ static struct skillmods { static struct skillmods *init_skills(const race * rc) { terrain_t t; - struct skillmods *mods = (struct skillmods *)calloc(1, sizeof(struct skillmods)); mods->race = rc; for (t = 0; t != MAXTERRAINS; ++t) { skill_t sk; - for (sk = 0; sk != MAXSKILLS; ++sk) { mods->mod[t].value[sk] = skill_mod(rc, sk, newterrain(t)); } @@ -233,9 +227,7 @@ int rc_skillmod(const struct race *rc, const region * r, skill_t sk) return 0; #ifdef FASTER_SKILLMOD unsigned int index = hashstring(rc->_name[0]) % RCMODMAXHASH; - struct skillmods **imods = &modhash[index]; - while (*imods && (*imods)->race != rc) imods = &(*imods)->next; if (*imods == NULL) { @@ -271,11 +263,8 @@ int level_days(int level) int level(int days) { int i; - static int ldays[64]; - static boolean init = false; - if (!init) { init = true; for (i = 0; i != 64; ++i) @@ -304,9 +293,7 @@ int skill_weeks(int level) { if (rule_random_progress()) { int coins = 2 * level; - int heads = 1; - while (coins--) { heads += rng_int() % 2; } @@ -328,7 +315,6 @@ void reduce_skill(unit * u, skill * sv, unsigned int weeks) } } - int skill_compare(const skill * sk, const skill * sc) { if (sk->level > sc->level) diff --git a/src/kernel/spell.c b/src/kernel/spell.c index 3079f25f9..5f9e6e8f8 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -54,14 +54,11 @@ void register_spell(spell * sp) spell *find_spell(magic_t mtype, const char *name) { quicklist *ql = spells; - int qi; - spell *spx = NULL; for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { spell *sp = (spell *) ql_get(ql, qi); - if (strcmp(name, sp->sname) == 0) { if (mtype == M_NONE || sp->magietyp == mtype) return sp; @@ -74,7 +71,6 @@ spell *find_spell(magic_t mtype, const char *name) return spx; } - /* ------------------------------------------------------------- */ /* Spruch identifizieren */ @@ -90,22 +86,16 @@ static spell_names *spellnames; static spell_names *init_spellnames(const struct locale *lang, magic_t mtype) { quicklist *ql; - int qi; - spell_names *sn = (spell_names *) calloc(sizeof(spell_names), 1); - sn->next = spellnames; sn->lang = lang; sn->mtype = mtype; for (qi = 0, ql = spells; ql; ql_advance(&ql, &qi, 1)) { spell *sp = (spell *) ql_get(ql, qi); - if (sp->magietyp == mtype) { const char *n = spell_name(sp, lang); - variant token; - token.v = sp; addtoken(&sn->names, n, token); } @@ -116,7 +106,6 @@ static spell_names *init_spellnames(const struct locale *lang, magic_t mtype) static spell_names *get_spellnames(const struct locale *lang, magic_t mtype) { spell_names *sn = spellnames; - while (sn) { if (sn->mtype == mtype && sn->lang == lang) break; @@ -136,7 +125,6 @@ static spell *get_spellfromtoken_i(const char *name, const struct locale *lang, sn = get_spellnames(lang, mtype); if (findtoken(&sn->names, name, &token) == E_TOK_NOMATCH) { magic_t mt; - /* if we could not find it in the main magic type, we look through all the others */ for (mt = 0; mt != MAXMAGIETYP; ++mt) { if (mt != mtype) { @@ -158,7 +146,6 @@ spell *get_spellfromtoken(unit * u, const char *name, const struct locale * lang) { sc_mage *m = get_mage(u); - spell *sp; if (m == NULL) @@ -166,7 +153,6 @@ spell *get_spellfromtoken(unit * u, const char *name, sp = get_spellfromtoken_i(name, lang, m->magietyp); if (sp != NULL) { quicklist *ql = m->spells; - int qi; if (ql_set_find(&ql, &qi, sp)) { @@ -179,7 +165,6 @@ spell *get_spellfromtoken(unit * u, const char *name, spell *find_spellbyid(magic_t mtype, spellid_t id) { quicklist *ql; - int qi; assert(id >= 0); @@ -187,16 +172,13 @@ spell *find_spellbyid(magic_t mtype, spellid_t id) return NULL; for (qi = 0, ql = spells; ql; ql_advance(&ql, &qi, 1)) { spell *sp = (spell *) ql_get(ql, qi); - if (sp->id == id) { return sp; } } for (qi = 0, ql = spells; ql; ql_advance(&ql, &qi, 1)) { spell *sp = (spell *) ql_get(ql, qi); - unsigned int hashid = hashstring(sp->sname); - if (hashid == id) { if (sp->magietyp == mtype || mtype == M_NONE) { return sp; diff --git a/src/kernel/sqlite.c b/src/kernel/sqlite.c index ac175f30a..496a902d3 100644 --- a/src/kernel/sqlite.c +++ b/src/kernel/sqlite.c @@ -11,7 +11,6 @@ faction *get_faction_by_id(int uid) { faction *f; - for (f = factions; f; f = f->next) { if (f->subscription == uid) { return f; @@ -35,7 +34,6 @@ typedef struct stmt_cache { #define MAX_STMT_CACHE 64 static stmt_cache cache[MAX_STMT_CACHE]; - static int cache_insert; static sqlite3_stmt *stmt_cache_get(sqlite3 * db, const char *sql) @@ -64,7 +62,6 @@ static sqlite3_stmt *stmt_cache_get(sqlite3 * db, const char *sql) return cache[i].stmt; } - typedef struct db_faction { sqlite3_uint64 id_faction; sqlite3_uint64 id_email; @@ -79,9 +76,7 @@ db_update_email(sqlite3 * db, const faction * f, const db_faction * dbstate, boolean force, /* [OUT] */ sqlite3_uint64 * id_email) { boolean update = force; - int res = SQLITE_OK; - char email_lc[MAX_EMAIL_LENGTH]; if (update) { @@ -97,19 +92,13 @@ db_update_email(sqlite3 * db, const faction * f, const db_faction * dbstate, if (update) { char email_md5[MD5_LENGTH_0]; - int i; - md5_state_t ms; - md5_byte_t digest[16]; - const char sql_insert_email[] = "INSERT OR FAIL INTO email (email,md5) VALUES (?,?)"; const char sql_select_email[] = "SELECT id FROM email WHERE md5=?"; - sqlite3_stmt *stmt_insert_email = stmt_cache_get(db, sql_insert_email); - sqlite3_stmt *stmt_select_email = stmt_cache_get(db, sql_select_email); md5_init(&ms); @@ -143,14 +132,11 @@ db_update_email(sqlite3 * db, const faction * f, const db_faction * dbstate, int db_update_factions(sqlite3 * db, boolean force) { int game_id = 6; - const char sql_select[] = "SELECT faction.id, faction.email_id, faction.code, email.email, faction.password_md5, faction.name, faction.lastturn FROM email, faction" " WHERE email.id=faction.email_id AND faction.game_id=? AND (lastturn IS NULL OR lastturn>?)"; sqlite3_stmt *stmt_select = stmt_cache_get(db, sql_select); - faction *f; - int res; res = sqlite3_bind_int(stmt_select, 1, game_id); @@ -159,7 +145,6 @@ int db_update_factions(sqlite3 * db, boolean force) SQL_EXPECT(res, SQLITE_OK); for (;;) { sqlite3_uint64 id_faction; - int lastturn; res = sqlite3_step(stmt_select); @@ -173,7 +158,6 @@ int db_update_factions(sqlite3 * db, boolean force) if (f == NULL || !f->alive) { if (lastturn == 0) { const char sql_update[] = "UPDATE faction SET lastturn=? WHERE id=?"; - sqlite3_stmt *stmt = stmt_cache_get(db, sql_update); lastturn = f ? f->lastorders : turn - 1; @@ -184,19 +168,12 @@ int db_update_factions(sqlite3 * db, boolean force) } } else { md5_state_t ms; - md5_byte_t digest[16]; - int i; - char passwd_md5[MD5_LENGTH_0]; - sqlite3_uint64 id_email; - boolean update = force; - db_faction dbstate; - const char *no_b36; fset(f, FFL_MARK); @@ -270,17 +247,13 @@ int db_update_scores(sqlite3 * db, boolean force) const char *sql_ins = "INSERT OR FAIL INTO score (value,faction_id,turn) VALUES (?,?,?)"; sqlite3_stmt *stmt_ins = stmt_cache_get(db, sql_ins); - const char *sql_upd = "UPDATE score set value=? WHERE faction_id=? AND turn=?"; sqlite3_stmt *stmt_upd = stmt_cache_get(db, sql_upd); - faction *f; - sqlite3_exec(db, "BEGIN", 0, 0, 0); for (f = factions; f; f = f->next) { int res; - sqlite3_bind_int(stmt_ins, 1, f->score); sqlite3_bind_int64(stmt_ins, 2, f->subscription); sqlite3_bind_int(stmt_ins, 3, turn); diff --git a/src/kernel/teleport.c b/src/kernel/teleport.c index ee744b4b0..311f185ec 100644 --- a/src/kernel/teleport.c +++ b/src/kernel/teleport.c @@ -64,7 +64,6 @@ static region *tpregion(const region * r) region_list *astralregions(const region * r, boolean(*valid) (const region *)) { region_list *rlist = NULL; - int x, y; assert(is_astral(r)); @@ -79,9 +78,7 @@ region_list *astralregions(const region * r, boolean(*valid) (const region *)) for (x = -TP_RADIUS; x <= +TP_RADIUS; ++x) { for (y = -TP_RADIUS; y <= +TP_RADIUS; ++y) { region *rn; - int dist = koor_distance(0, 0, x, y); - int nx = r->x + x, ny = r->y + y; if (dist > TP_RADIUS) @@ -105,7 +102,6 @@ region *r_standard_to_astral(const region * r) region *r_astral_to_standard(const region * r) { int x, y; - region *r2; assert(is_astral(r)); @@ -123,9 +119,7 @@ region_list *all_in_range(const region * r, int n, boolean(*valid) (const region *)) { int x, y; - region_list *rlist = NULL; - plane *pl = rplane(r); if (r == NULL) @@ -135,9 +129,7 @@ region_list *all_in_range(const region * r, int n, for (y = r->y - n; y <= r->y + n; y++) { if (koor_distance(r->x, r->y, x, y) <= n) { region *r2; - int nx = x, ny = y; - pnormalize(&nx, &ny, pl); r2 = findregion(nx, ny); if (r2 != NULL && (valid == NULL || valid(r2))) @@ -152,9 +144,7 @@ region_list *all_in_range(const region * r, int n, void spawn_braineaters(float chance) { region *r; - faction *f0 = get_monsters(); - int next = rng_int() % (int)(chance * 100); if (f0 == NULL) @@ -184,18 +174,14 @@ plane *get_normalplane(void) boolean is_astral(const region * r) { plane *pl = get_astralplane(); - return (pl && rplane(r) == pl); } plane *get_astralplane(void) { static plane *astralspace; - static int rule_astralplane = -1; - static int gamecookie = -1; - if (rule_astralplane < 0) { rule_astralplane = get_param_int(global.parameters, "modules.astralspace", 1); @@ -219,24 +205,19 @@ plane *get_astralplane(void) void create_teleport_plane(void) { region *r; - plane *hplane = get_homeplane(); - plane *aplane = get_astralplane(); const terrain_type *fog = get_terrain("fog"); for (r = regions; r; r = r->next) { plane *pl = rplane(r); - if (pl == hplane) { region *ra = tpregion(r); if (ra == NULL) { int x = TE_CENTER_X + real2tp(r->x); - int y = TE_CENTER_Y + real2tp(r->y); - pnormalize(&x, &y, aplane); ra = new_region(x, y, aplane, 0); diff --git a/src/kernel/terrain.c b/src/kernel/terrain.c index 70304cf0a..2f5b677ea 100644 --- a/src/kernel/terrain.c +++ b/src/kernel/terrain.c @@ -87,7 +87,6 @@ void register_terrain(struct terrain_type *terrain) const struct terrain_type *get_terrain(const char *name) { const struct terrain_type *terrain; - for (terrain = registered_terrains; terrain; terrain = terrain->next) { if (strcmp(terrain->_name, name) == 0) break; @@ -109,7 +108,6 @@ const struct terrain_type *newterrain(terrain_t t) terrain_t oldterrain(const struct terrain_type * terrain) { terrain_t t; - if (terrain == NULL) return NOTERRAIN; for (t = 0; t != MAXTERRAINS; ++t) { @@ -124,10 +122,8 @@ const char *terrain_name(const struct region *r) { if (r->attribs) { attrib *a = a_find(r->attribs, &at_racename); - if (a) { const char *str = get_racename(a); - if (str) return str; } @@ -146,10 +142,8 @@ const char *terrain_name(const struct region *r) void init_terrains(void) { terrain_t t; - for (t = 0; t != MAXTERRAINS; ++t) { const terrain_type *newterrain = newterrains[t]; - if (newterrain != NULL) continue; if (terraindata[t] != NULL) { diff --git a/src/kernel/textstore.c b/src/kernel/textstore.c index d4055642e..fe2fd251a 100644 --- a/src/kernel/textstore.c +++ b/src/kernel/textstore.c @@ -36,7 +36,6 @@ static int txt_w_id(struct storage *store, int arg) static int txt_r_id(struct storage *store) { char id[8]; - fscanf((FILE *) store->userdata, "%7s", id); return atoi36(id); } @@ -49,7 +48,6 @@ static int txt_w_int(struct storage *store, int arg) static int txt_r_int(struct storage *store) { int result; - fscanf((FILE *) store->userdata, "%d", &result); return result; } @@ -62,7 +60,6 @@ static int txt_w_flt(struct storage *store, float arg) static float txt_r_flt(struct storage *store) { double result; - fscanf((FILE *) store->userdata, "%lf", &result); return (float)result; } @@ -70,13 +67,11 @@ static float txt_r_flt(struct storage *store) static int txt_w_tok(struct storage *store, const char *tok) { int result; - if (tok == NULL || tok[0] == 0) { result = fputc(NULL_TOKEN, (FILE *) store->userdata); } else { #ifndef NDEBUG const char *find = strchr(tok, ' '); - if (!find) find = strchr(tok, NULL_TOKEN); assert(!find || !"reserved character in token"); @@ -91,7 +86,6 @@ static int txt_w_tok(struct storage *store, const char *tok) static char *txt_r_tok(struct storage *store) { char result[256]; - fscanf((FILE *) store->userdata, "%256s", result); if (result[0] == NULL_TOKEN || result[0] == 0) { return NULL; @@ -102,7 +96,6 @@ static char *txt_r_tok(struct storage *store) static void txt_r_tok_buf(struct storage *store, char *result, size_t size) { char format[16]; - if (result && size > 0) { format[0] = '%'; sprintf(format + 1, "%us", size); @@ -119,7 +112,6 @@ static void txt_r_tok_buf(struct storage *store, char *result, size_t size) static int txt_w_str(struct storage *store, const char *str) { int result = fwritestr((FILE *) store->userdata, str); - fputc(' ', (FILE *) store->userdata); return result + 1; } @@ -127,7 +119,6 @@ static int txt_w_str(struct storage *store, const char *str) static char *txt_r_str(struct storage *store) { char buffer[DISPLAYSIZE]; - /* you should not use this */ freadstr((FILE *) store->userdata, store->encoding, buffer, sizeof(buffer)); return strdup(buffer); @@ -142,13 +133,11 @@ static int txt_open(struct storage *store, const char *filename, int mode) { const char *modes[] = { 0, "rt", "wt", "at" }; FILE *F = fopen(filename, modes[mode]); - store->userdata = F; if (F) { const char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; if (mode == IO_READ) { char token[8]; - /* recognize UTF8 BOM */ store->r_tok_buf(store, token, sizeof(token)); if (memcmp(token, utf8_bom, 3) == 0) { diff --git a/src/kernel/types.h b/src/kernel/types.h index 2348c055c..2ec5585f3 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -31,75 +31,41 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include typedef short terrain_t; - typedef short direction_t; - typedef short race_t; - typedef short magic_t; - typedef short skill_t; - typedef short typ_t; - typedef short item_t; - typedef unsigned int spellid_t; struct attrib; - struct attrib_type; - struct building; - struct building_type; - struct curse; - struct equipment; - struct faction; - struct fighter; - struct item; - struct item_type; - struct locale; - struct luxury_type; - struct order; - struct plane; - struct potion_type; - struct race; - struct region; - struct region_list; - struct resource_type; - struct ship; - struct ship_type; - struct skill; - struct spell; - struct storage; - struct strlist; - struct terrain_type; - struct unit; - struct weapon_type; typedef struct ursprung { @@ -111,7 +77,6 @@ typedef struct ursprung { /* ----------------- Befehle ----------------------------------- */ typedef unsigned char keyword_t; - enum { K_KOMMENTAR, K_BANNER, @@ -189,7 +154,6 @@ enum { /* ------------------ Status von Einheiten --------------------- */ typedef unsigned char status_t; - enum { ST_AGGRO, ST_FIGHT, @@ -202,7 +166,6 @@ enum { /* ----------------- Parameter --------------------------------- */ typedef unsigned char param_t; - enum { P_LOCALE, P_ANY, @@ -430,7 +393,6 @@ enum { /* ------------------------------------------------------------- */ /* Prototypen */ - #define ALLIED_TAX 1 #define ALLIED_NOBLOCK 2 #define ALLIED_HELP 4 @@ -439,5 +401,4 @@ enum { #define MAX_UNIT_NR (36*36*36*36-1) #define MAX_CONTAINER_NR (36*36*36*36-1) - #endif diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 0dbe0ee3d..2739aff0b 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -67,20 +67,17 @@ attrib_type at_creator = { #define UMAXHASH MAXUNITS static unit *unithash[UMAXHASH]; - static unit *delmarker = (unit *) unithash; /* a funny hack */ #define HASH_STATISTICS 1 #if HASH_STATISTICS static int hash_requests; - static int hash_misses; #endif void uhash(unit * u) { int key = HASH1(u->no, UMAXHASH), gk = HASH2(u->no, UMAXHASH); - while (unithash[key] != NULL && unithash[key] != delmarker && unithash[key] != u) { key = (key + gk) % UMAXHASH; @@ -92,7 +89,6 @@ void uhash(unit * u) void uunhash(unit * u) { int key = HASH1(u->no, UMAXHASH), gk = HASH2(u->no, UMAXHASH); - while (unithash[key] != NULL && unithash[key] != u) { key = (key + gk) % UMAXHASH; } @@ -108,7 +104,6 @@ unit *ufindhash(int uid) #endif if (uid >= 0) { int key = HASH1(uid, UMAXHASH), gk = HASH2(uid, UMAXHASH); - while (unithash[key] != NULL && (unithash[key] == delmarker || unithash[key]->no != uid)) { key = (key + gk) % UMAXHASH; @@ -133,9 +128,7 @@ static dead *deadhash[DMAXHASH]; static void dhash(int no, faction * f) { dead *hash = (dead *) calloc(1, sizeof(dead)); - dead *old = deadhash[no % DMAXHASH]; - hash->no = no; hash->f = f; deadhash[no % DMAXHASH] = hash; @@ -167,19 +160,14 @@ typedef struct buddy { static buddy *get_friends(const unit * u, int *numfriends) { buddy *friends = 0; - faction *f = u->faction; - region *r = u->region; - int number = 0; - unit *u2; for (u2 = r->units; u2; u2 = u2->next) { if (u2->faction != f && u2->number > 0) { int allied = 0; - if (get_param_int(global.parameters, "rules.alliances", 0) != 0) { allied = (f->alliance && f->alliance == u2->faction->alliance); } else if (alliedunit(u, u2->faction, HELP_MONEY) @@ -226,11 +214,8 @@ static buddy *get_friends(const unit * u, int *numfriends) int gift_items(unit * u, int flags) { region *r = u->region; - item **itm_p = &u->items; - int retval = 0; - int rule = rule_give(); assert(u->region); @@ -252,7 +237,6 @@ int gift_items(unit * u, int flags) /* at first, I should try giving my crap to my own units in this region */ if (u->faction && (u->faction->flags & FFL_QUIT) == 0 && (flags & GIFT_SELF)) { unit *u2, *u3 = NULL; - for (u2 = r->units; u2; u2 = u2->next) { if (u2 != u && u2->faction == u->faction && u2->number > 0) { /* some units won't take stuff: */ @@ -280,23 +264,16 @@ int gift_items(unit * u, int flags) /* if I have friends, I'll try to give my stuff to them */ if (u->faction && (flags & GIFT_FRIENDS)) { int number = 0; - buddy *friends = get_friends(u, &number); while (friends) { struct buddy *nf = friends; - unit *u2 = nf->unit; - item *itm = u->items; - while (itm != NULL) { const item_type *itype = itm->type; - item *itn = itm->next; - int n = itm->number; - n = n * nf->number / number; if (n > 0) { i_change(&u->items, itype, -n); @@ -412,7 +389,6 @@ unit *findnewunit(const region * r, const faction * f, int n) /* ------------------------------------------------------------- */ - /*********************/ /* at_alias */ /*********************/ @@ -428,7 +404,6 @@ attrib_type at_alias = { int ualias(const unit * u) { attrib *a = a_find(u->attribs, &at_alias); - if (!a) return 0; return a->data.i; @@ -467,7 +442,6 @@ const char *u_description(const unit * u, const struct locale *lang) const char *uprivate(const unit * u) { attrib *a = a_find(u->attribs, &at_private); - if (!a) return NULL; return a->data.v; @@ -505,7 +479,6 @@ attrib_type at_potionuser = { void usetpotionuse(unit * u, const potion_type * ptype) { attrib *a = a_find(u->attribs, &at_potionuser); - if (!a) a = a_add(&u->attribs, a_new(&at_potionuser)); a->data.v = (void *)ptype; @@ -514,7 +487,6 @@ void usetpotionuse(unit * u, const potion_type * ptype) const potion_type *ugetpotionuse(const unit * u) { attrib *a = a_find(u->attribs, &at_potionuser); - if (!a) return NULL; return (const potion_type *)a->data.v; @@ -535,7 +507,6 @@ attrib_type at_target = { unit *utarget(const unit * u) { attrib *a; - if (!fval(u, UFL_TARGET)) return NULL; a = a_find(u->attribs, &at_target); @@ -546,7 +517,6 @@ unit *utarget(const unit * u) void usettarget(unit * u, const unit * t) { attrib *a = a_find(u->attribs, &at_target); - if (!a && t) a = a_add(&u->attribs, a_new(&at_target)); if (a) { @@ -567,14 +537,12 @@ void usettarget(unit * u, const unit * t) void a_writesiege(const attrib * a, const void *owner, struct storage *store) { struct building *b = (struct building *)a->data.v; - write_building_reference(b, store); } int a_readsiege(attrib * a, void *owner, struct storage *store) { - int result = - read_reference(&a->data.v, store, read_building_reference, + int result = read_reference(&a->data.v, store, read_building_reference, resolve_building); if (result == 0 && !a->data.v) { return AT_READ_FAIL; @@ -594,7 +562,6 @@ attrib_type at_siege = { struct building *usiege(const unit * u) { attrib *a; - if (!fval(u, UFL_SIEGE)) return NULL; a = a_find(u->attribs, &at_siege); @@ -605,7 +572,6 @@ struct building *usiege(const unit * u) void usetsiege(unit * u, const struct building *t) { attrib *a = a_find(u->attribs, &at_siege); - if (!a && t) a = a_add(&u->attribs, a_new(&at_siege)); if (a) { @@ -634,7 +600,6 @@ attrib_type at_contact = { void usetcontact(unit * u, const unit * u2) { attrib *a = a_find(u->attribs, &at_contact); - while (a && a->type == &at_contact && a->data.v != u2) a = a->next; if (a && a->type == &at_contact) @@ -646,7 +611,6 @@ boolean ucontact(const unit * u, const unit * u2) /* Prüft, ob u den Kontaktiere-Befehl zu u2 gesetzt hat. */ { attrib *ru; - if (u->faction == u2->faction) return true; @@ -669,14 +633,12 @@ void free_units(void) { while (deleted_units) { unit *u = deleted_units; - deleted_units = deleted_units->next; free_unit(u); free(u); } } - void write_unit_reference(const unit * u, struct storage *store) { store->w_id(store, (u && u->region) ? u->no : 0); @@ -685,7 +647,6 @@ void write_unit_reference(const unit * u, struct storage *store) int resolve_unit(variant id, void *address) { unit *u = NULL; - if (id.i != 0) { u = findunit(id.i); if (u == NULL) { @@ -700,7 +661,6 @@ int resolve_unit(variant id, void *address) variant read_unit_reference(struct storage * store) { variant var; - var.i = store->r_id(store); return var; } @@ -713,7 +673,6 @@ void u_seteffstealth(unit * u, int value) { if (skill_enabled[SK_STEALTH]) { attrib *a = NULL; - if (fval(u, UFL_STEALTH)) { a = a_find(u->attribs, &at_stealth); } @@ -737,7 +696,6 @@ int u_geteffstealth(const struct unit *u) if (skill_enabled[SK_STEALTH]) { if (fval(u, UFL_STEALTH)) { attrib *a = a_find(u->attribs, &at_stealth); - if (a != NULL) return a->data.i; } @@ -749,7 +707,6 @@ int get_level(const unit * u, skill_t id) { if (skill_enabled[id]) { skill *sv = u->skills; - while (sv != u->skills + u->skill_size) { if (sv->id == id) { return sv->level; @@ -795,7 +752,6 @@ static attrib_type at_leftship = { static attrib *make_leftship(struct ship *leftship) { attrib *a = a_new(&at_leftship); - a->data.v = leftship; return a; } @@ -821,7 +777,6 @@ ship *leftship(const unit * u) void leave_ship(unit * u) { struct ship *sh = u->ship; - if (sh == NULL) return; u->ship = NULL; @@ -829,7 +784,6 @@ void leave_ship(unit * u) if (fval(u, UFL_OWNER)) { unit *u2, *owner = NULL; - freset(u, UFL_OWNER); for (u2 = u->region->units; u2; u2 = u2->next) { @@ -849,14 +803,12 @@ void leave_ship(unit * u) void leave_building(unit * u) { struct building *b = u->building; - if (!b) return; u->building = NULL; if (fval(u, UFL_OWNER)) { unit *u2, *owner = NULL; - freset(u, UFL_OWNER); for (u2 = u->region->units; u2; u2 = u2->next) { @@ -932,7 +884,6 @@ boolean can_survive(const unit * u, const region * r) void move_unit(unit * u, region * r, unit ** ulist) { int maxhp = 0; - assert(u && r); assert(u->faction || !"this unit is dead"); @@ -949,7 +900,6 @@ void move_unit(unit * u, region * r, unit ** ulist) /* can_leave must be checked in travel_i */ #ifndef NDEBUG boolean result = leave(u, false); - assert(result); #else leave(u, false); @@ -974,9 +924,7 @@ void move_unit(unit * u, region * r, unit ** ulist) void transfermen(unit * u, unit * u2, int n) { const attrib *a; - int hp = u->hp; - region *r = u->region; if (n == 0) @@ -986,9 +934,7 @@ void transfermen(unit * u, unit * u2, int n) if (u2) { skill *sv, *sn; - skill_t sk; - ship *sh; assert(u2->number + n > 0); @@ -1051,7 +997,6 @@ void transfermen(unit * u, unit * u2, int n) a = a_find(u->attribs, &at_effect); while (a && a->type == &at_effect) { effect_data *olde = (effect_data *) a->data.v; - if (olde->value) change_effect(u2, olde->type, olde->value); a = a->next; @@ -1060,8 +1005,7 @@ void transfermen(unit * u, unit * u2, int n) if (sh != NULL) set_leftship(u2, sh); u2->flags |= - u-> - flags & (UFL_LONGACTION | UFL_NOTMOVING | UFL_HUNGER | UFL_MOVED | + u->flags & (UFL_LONGACTION | UFL_NOTMOVING | UFL_HUNGER | UFL_MOVED | UFL_ENTER); if (u->attribs) { transfer_curse(u, u2, n); @@ -1076,11 +1020,8 @@ void transfermen(unit * u, unit * u2, int n) a = a_find(u2->attribs, &at_effect); while (a && a->type == &at_effect) { attrib *an = a->next; - effect_data *olde = (effect_data *) a->data.v; - int e = get_effect(u, olde->type); - if (e != 0) change_effect(u2, olde->type, -e); a = an; @@ -1088,14 +1029,11 @@ void transfermen(unit * u, unit * u2, int n) } else if (r->land) { if ((u->race->ec_flags & ECF_REC_ETHEREAL) == 0) { const race *rc = u->race; - if (rc->ec_flags & ECF_REC_HORSES) { /* Zentauren an die Pferde */ int h = rhorses(r) + n; - rsethorses(r, h); } else { int p = rpeasants(r); - p += (int)(n * rc->recruit_multi); rsetpeasants(r, p); } @@ -1116,9 +1054,7 @@ struct building *inside_building(const struct unit *u) return NULL; } else { int p = 0, cap = buildingcapacity(u->building); - const unit *u2; - for (u2 = u->region->units; u2; u2 = u2->next) { if (u2->building == u->building) { p += u2->number; @@ -1203,7 +1139,6 @@ void set_number(unit * u, int count) boolean learn_skill(unit * u, skill_t sk, double chance) { skill *sv = u->skills; - if (chance < 1.0 && rng_int() % 10000 >= chance * 10000) return false; while (sv != u->skills + u->skill_size) { @@ -1226,11 +1161,9 @@ boolean learn_skill(unit * u, skill_t sk, double chance) void remove_skill(unit * u, skill_t sk) { skill *sv = u->skills; - for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { if (sv->id == sk) { skill *sl = u->skills + u->skill_size - 1; - if (sl != sv) { *sv = *sl; } @@ -1243,7 +1176,6 @@ void remove_skill(unit * u, skill_t sk) skill *add_skill(unit * u, skill_t id) { skill *sv = u->skills; - #ifndef NDEBUG for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { assert(sv->id != id); @@ -1262,7 +1194,6 @@ skill *add_skill(unit * u, skill_t id) skill *get_skill(const unit * u, skill_t sk) { skill *sv = u->skills; - while (sv != u->skills + u->skill_size) { if (sv->id == sk) return sv; @@ -1274,7 +1205,6 @@ skill *get_skill(const unit * u, skill_t sk) boolean has_skill(const unit * u, skill_t sk) { skill *sv = u->skills; - while (sv != u->skills + u->skill_size) { if (sv->id == sk) { return (sv->level > 0); @@ -1313,15 +1243,10 @@ static int item_modification(const unit * u, skill_t sk, int val) static int att_modification(const unit * u, skill_t sk) { double bonus = 0, malus = 0; - attrib *a; - double result = 0; - static boolean init = false; - static const curse_type *skillmod_ct, *gbdream_ct, *worse_ct; - curse *c; if (!init) { @@ -1336,10 +1261,8 @@ static int att_modification(const unit * u, skill_t sk) result += curse_geteffect(c); if (skillmod_ct) { attrib *a = a_find(u->attribs, &at_curse); - while (a && a->type == &at_curse) { curse *c = (curse *) a->data.v; - if (c->type == skillmod_ct && c->data.i == sk) { result += curse_geteffect(c); break; @@ -1354,12 +1277,9 @@ static int att_modification(const unit * u, skill_t sk) a = a_find(u->region->attribs, &at_curse); while (a && a->type == &at_curse) { curse *c = (curse *) a->data.v; - if (curse_active(c) && c->type == gbdream_ct) { double mod = curse_geteffect(c); - unit *mage = c->magician; - /* wir suchen jeweils den größten Bonus und den größten Malus */ if (mod > bonus) { if (mage == NULL || mage->number == 0 @@ -1384,13 +1304,11 @@ get_modifier(const unit * u, skill_t sk, int level, const region * r, boolean noitem) { int bskill = level; - int skill = bskill; assert(r); if (sk == SK_STEALTH) { plane *pl = rplane(r); - if (pl && fval(pl, PFL_NOSTEALTH)) return 0; } @@ -1415,13 +1333,11 @@ int eff_skill(const unit * u, skill_t sk, const region * r) { if (skill_enabled[sk]) { int level = get_level(u, sk); - if (level > 0) { int mlevel = level + get_modifier(u, sk, level, r, false); if (mlevel > 0) { int skillcap = SkillCap(sk); - if (skillcap && mlevel > skillcap) { return skillcap; } @@ -1435,7 +1351,6 @@ int eff_skill(const unit * u, skill_t sk, const region * r) int eff_skill_study(const unit * u, skill_t sk, const region * r) { int level = get_level(u, sk); - if (level > 0) { int mlevel = level + get_modifier(u, sk, level, r, true); @@ -1481,7 +1396,6 @@ void free_unit(unit * u) free(u->skills); while (u->items) { item *it = u->items->next; - u->items->next = NULL; i_free(u->items); u->items = it; @@ -1490,7 +1404,6 @@ void free_unit(unit * u) a_remove(&u->attribs, u->attribs); while (u->reservations) { struct reservation *res = u->reservations; - u->reservations = res->next; free(res); } @@ -1510,7 +1423,6 @@ void name_unit(unit * u) { if (u->race->generate_name) { const char *gen_name = u->race->generate_name(u); - if (gen_name) { unit_setname(u, gen_name); } else { @@ -1518,7 +1430,6 @@ void name_unit(unit * u) } } else { char name[32]; - snprintf(name, sizeof(name), "%s %s", LOC(u->faction->locale, "unitdefault"), itoa36(u->no)); unit_setname(u, name); @@ -1541,7 +1452,6 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace, if (f->locale) { order *deford = default_order(f->locale); - if (deford) { set_order(&u->thisorder, NULL); addlist(&u->orders, deford); @@ -1591,10 +1501,8 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace, /* Tarnlimit wird vererbt */ if (fval(creator, UFL_STEALTH)) { attrib *a = a_find(creator->attribs, &at_stealth); - if (a) { int stealth = a->data.i; - a = a_add(&u->attribs, a_new(&at_stealth)); a->data.i = stealth; } @@ -1615,7 +1523,6 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace, a = a_find(creator->attribs, &at_group); if (a) { group *g = (group *) a->data.v; - set_group(u, g); } } @@ -1634,12 +1541,10 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace, int maxheroes(const struct faction *f) { int nsize = count_all(f); - if (nsize == 0) return 0; else { int nmax = (int)(log10(nsize / 50.0) * 20); - return (nmax < 0) ? 0 : nmax; } } @@ -1647,7 +1552,6 @@ int maxheroes(const struct faction *f) int countheroes(const struct faction *f) { const unit *u = f->units; - int n = 0; while (u) { @@ -1657,7 +1561,6 @@ int countheroes(const struct faction *f) } #ifdef DEBUG_MAXHEROES int m = maxheroes(f); - if (n > m) { log_warning(("%s has %d of %d heroes\n", factionname(f), n, m)); } @@ -1701,7 +1604,6 @@ int unit_getid(const unit * u) void unit_setid(unit * u, int id) { unit *nu = findunit(id); - if (nu == NULL) { uunhash(u); u->no = id; @@ -1742,7 +1644,6 @@ int unit_getcapacity(const unit * u) void unit_addorder(unit * u, order * ord) { order **ordp = &u->orders; - while (*ordp) ordp = &(*ordp)->next; *ordp = ord; @@ -1752,11 +1653,8 @@ void unit_addorder(unit * u, order * ord) int unit_max_hp(const unit * u) { static int rules_stamina = -1; - int h; - double p; - static const curse_type *heal_ct = NULL; if (rules_stamina < 0) { @@ -1774,7 +1672,6 @@ int unit_max_hp(const unit * u) /* der healing curse verändert die maximalen hp */ if (heal_ct) { curse *c = get_curse(u->region->attribs, heal_ct); - if (c) { h = (int)(h * (1.0 + (curse_geteffect(c) / 100))); } @@ -1786,16 +1683,13 @@ int unit_max_hp(const unit * u) void scale_number(unit * u, int n) { skill_t sk; - const attrib *a; - int remain; if (n == u->number) return; if (n && u->number > 0) { int full; - remain = ((u->hp % u->number) * (n % u->number)) % u->number; full = u->hp / u->number; /* wieviel kriegt jede person mindestens */ @@ -1811,9 +1705,7 @@ void scale_number(unit * u, int n) for (a = a_find(u->attribs, &at_effect); a && a->type == &at_effect; a = a->next) { effect_data *data = (effect_data *) a->data.v; - int snew = data->value / u->number * n; - if (n) { remain = data->value - snew / n * u->number; snew += remain * n / u->number; diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 58d7b1577..c3cfd2de9 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -38,7 +38,6 @@ without prior permission by the authors of Eressea. #include #include - /* libxml includes */ #include #include @@ -53,12 +52,10 @@ without prior permission by the authors of Eressea. static boolean gamecode_enabled = false; void (*set_spelldata_cb) (struct spell * sp) = 0; - static building_type *bt_get_or_create(const char *name) { if (name != NULL) { building_type *btype = bt_find(name); - if (btype == NULL) { btype = calloc(sizeof(building_type), 1); btype->_name = strdup(name); @@ -77,7 +74,6 @@ void enable_xml_gamecode(void) static void xml_readtext(xmlNodePtr node, struct locale **lang, xmlChar ** text) { xmlChar *propValue = xmlGetProp(node, BAD_CAST "locale"); - assert(propValue != NULL); *lang = find_locale((const char *)propValue); #ifdef MAKE_LOCALES @@ -92,9 +88,7 @@ static void xml_readtext(xmlNodePtr node, struct locale **lang, xmlChar ** text) static const spell *xml_spell(xmlNode * node, const char *name) { const spell *sp = NULL; - xmlChar *propValue = xmlGetProp(node, BAD_CAST name); - if (propValue != NULL) { sp = find_spell(M_NONE, (const char *)propValue); assert(sp); @@ -106,7 +100,6 @@ static const spell *xml_spell(xmlNode * node, const char *name) static xmlChar *xml_cleanup_string(xmlChar * str) { xmlChar *read = str; - xmlChar *write = str; while (*read) { @@ -132,12 +125,9 @@ static xmlChar *xml_cleanup_string(xmlChar * str) static const resource_type *rt_findorcreate(const char *name) { resource_type *rtype = rt_find(name); - if (rtype == NULL) { const char *names[2]; - char *namep = strcat(strcpy((char *)malloc(strlen(name) + 3), name), "_p"); - /* we'll make a placeholder */ names[0] = name; names[1] = namep; @@ -151,7 +141,6 @@ static void xml_readrequirements(xmlNodePtr * nodeTab, int nodeNr, requirement ** reqArray) { int req; - requirement *radd = *reqArray; assert(radd == NULL); @@ -162,7 +151,6 @@ xml_readrequirements(xmlNodePtr * nodeTab, int nodeNr, requirement ** reqArray) for (req = 0; req != nodeNr; ++req) { xmlNodePtr node = nodeTab[req]; - xmlChar *propValue; radd->number = xml_ivalue(node, "quantity", 1); @@ -181,20 +169,13 @@ xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, construction ** consPtr) { xmlNodePtr pushNode = xpath->node; - int k; - for (k = 0; k != nodeSet->nodeNr; ++k) { xmlNodePtr node = nodeSet->nodeTab[k]; - xmlChar *propValue; - construction *con; - xmlXPathObjectPtr req; - int m; - skill_t sk = NOSKILL; propValue = xmlGetProp(node, BAD_CAST "skill"); @@ -241,7 +222,6 @@ xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, propValue = xmlGetProp(node, BAD_CAST "function"); if (propValue != NULL) { pf_generic foo = get_function((const char *)propValue); - a_add(&con->attribs, make_skillmod(NOSKILL, SMF_PRODUCTION, (skillmod_fun) foo, 1.0, 0)); xmlFree(propValue); @@ -257,9 +237,7 @@ static int parse_function(xmlNodePtr node, pf_generic * funPtr, xmlChar ** namePtr) { pf_generic fun; - xmlChar *propValue = xmlGetProp(node, BAD_CAST "value"); - assert(propValue != NULL); fun = get_function((const char *)propValue); if (fun != NULL) { @@ -275,9 +253,7 @@ parse_function(xmlNodePtr node, pf_generic * funPtr, xmlChar ** namePtr) static int parse_buildings(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr buildings; - int i; /* reading eressea/buildings/building */ @@ -285,16 +261,11 @@ static int parse_buildings(xmlDocPtr doc) xmlXPathEvalExpression(BAD_CAST "/eressea/buildings/building", xpath); if (buildings->nodesetval != NULL) { xmlNodeSetPtr nodes = buildings->nodesetval; - for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; - xmlChar *propValue; - building_type *btype; - xmlXPathObjectPtr result; - int k; propValue = xmlGetProp(node, BAD_CAST "name"); @@ -338,9 +309,7 @@ static int parse_buildings(xmlDocPtr doc) result = xmlXPathEvalExpression(BAD_CAST "function", xpath); for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - pf_generic fun; - parse_function(node, &fun, &propValue); if (fun == NULL) { @@ -377,7 +346,6 @@ static int parse_buildings(xmlDocPtr doc) result = xmlXPathEvalExpression(BAD_CAST "maintenance", xpath); for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - maintenance *mt; if (btype->maintenance == NULL) { @@ -415,11 +383,8 @@ static int parse_buildings(xmlDocPtr doc) static int parse_calendar(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr xpathCalendars; - xmlNodeSetPtr nsetCalendars; - int c, rv = 0; /* reading eressea/buildings/building */ @@ -431,13 +396,9 @@ static int parse_calendar(xmlDocPtr doc) } else for (c = 0; c != nsetCalendars->nodeNr; ++c) { xmlNodePtr calendar = nsetCalendars->nodeTab[c]; - xmlXPathObjectPtr xpathWeeks, xpathMonths, xpathSeasons; - xmlNodeSetPtr nsetWeeks, nsetMonths, nsetSeasons; - xmlChar *propValue = xmlGetProp(calendar, BAD_CAST "name"); - xmlChar *newyear = xmlGetProp(calendar, BAD_CAST "newyear"); first_turn = xml_ivalue(calendar, "start", first_turn); @@ -459,9 +420,7 @@ static int parse_calendar(xmlDocPtr doc) weeknames2 = malloc(sizeof(char *) * weeks_per_month); for (i = 0; i != nsetWeeks->nodeNr; ++i) { xmlNodePtr week = nsetWeeks->nodeTab[i]; - xmlChar *propValue = xmlGetProp(week, BAD_CAST "name"); - if (propValue) { weeknames[i] = strdup(mkname("calendar", (const char *)propValue)); weeknames2[i] = malloc(strlen(weeknames[i]) + 3); @@ -483,9 +442,7 @@ static int parse_calendar(xmlDocPtr doc) for (i = 0; i != nsetSeasons->nodeNr; ++i) { xmlNodePtr season = nsetSeasons->nodeTab[i]; - xmlChar *propValue = xmlGetProp(season, BAD_CAST "name"); - if (propValue) { seasonnames[i] = strdup(mkname("calendar", (const char *)propValue)); @@ -507,9 +464,7 @@ static int parse_calendar(xmlDocPtr doc) for (i = 0; i != nsetMonths->nodeNr; ++i) { xmlNodePtr month = nsetMonths->nodeTab[i]; - xmlChar *propValue = xmlGetProp(month, BAD_CAST "name"); - int j; if (propValue) { @@ -524,7 +479,6 @@ static int parse_calendar(xmlDocPtr doc) } for (j = 0; j != seasons; ++j) { xmlNodePtr season = month->parent; - if (season == nsetSeasons->nodeTab[j]) { month_season[i] = j; break; @@ -546,11 +500,8 @@ static int parse_calendar(xmlDocPtr doc) static int parse_directions(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr xpathDirections; - xmlNodeSetPtr nsetDirections; - int rv = 0; /* reading eressea/directions/dir */ @@ -559,10 +510,8 @@ static int parse_directions(xmlDocPtr doc) nsetDirections = xpathDirections->nodesetval; if (nsetDirections != NULL) { int k; - for (k = 0; k != nsetDirections->nodeNr; ++k) { xmlNodePtr dir = nsetDirections->nodeTab[k]; - xmlChar *propValue = xmlGetProp(dir, BAD_CAST "name"); register_special_direction((const char *)propValue); @@ -578,25 +527,18 @@ static int parse_directions(xmlDocPtr doc) static int parse_ships(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr ships; - int i; /* reading eressea/ships/ship */ ships = xmlXPathEvalExpression(BAD_CAST "/eressea/ships/ship", xpath); if (ships->nodesetval != NULL) { xmlNodeSetPtr nodes = ships->nodesetval; - for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr child, node = nodes->nodeTab[i]; - xmlChar *propValue; - ship_type *st = calloc(sizeof(ship_type), 1); - xmlXPathObjectPtr result; - int k, c; propValue = xmlGetProp(node, BAD_CAST "name"); @@ -632,7 +574,6 @@ static int parse_ships(xmlDocPtr doc) for (child = node->children; child; child = child->next) { if (strcmp((const char *)child->name, "modifier") == 0) { double value = xml_fvalue(child, "value", 0.0); - propValue = xmlGetProp(child, BAD_CAST "type"); if (strcmp((const char *)propValue, "tactics") == 0) st->tac_bonus = (float)value; @@ -700,12 +641,10 @@ static void race_compat(void) for (i = 0; i != MAXRACES; ++i) { const char *rcname = oldracenames[i]; - if (rcname == NULL) { new_race[i] = NULL; } else { race *rc = rc_find(oldracenames[i]); - if (rc) { new_race[i] = rc; if (rc == new_race[RC_TROLL]) { @@ -728,23 +667,16 @@ static potion_type *xml_readpotion(xmlXPathContextPtr xpath, item_type * itype) static luxury_type *xml_readluxury(xmlXPathContextPtr xpath, item_type * itype) { int price = xml_ivalue(xpath->node, "price", 0); - return new_luxurytype(itype, price); } - static armor_type *xml_readarmor(xmlXPathContextPtr xpath, item_type * itype) { xmlNodePtr node = xpath->node; - armor_type *atype = NULL; - unsigned int flags = ATF_NONE; - int ac = xml_ivalue(node, "ac", 0); - double penalty = xml_fvalue(node, "penalty", 0.0); - double magres = xml_fvalue(node, "magres", 0.0); if (xml_bvalue(node, "laen", false)) @@ -760,27 +692,16 @@ static armor_type *xml_readarmor(xmlXPathContextPtr xpath, item_type * itype) static weapon_type *xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) { xmlNodePtr node = xpath->node; - weapon_type *wtype = NULL; - unsigned int flags = WTF_NONE; - xmlXPathObjectPtr result; - xmlChar *propValue; - int k; - skill_t sk; - int minskill = xml_ivalue(node, "minskill", 0); - int offmod = xml_ivalue(node, "offmod", 0); - int defmod = xml_ivalue(node, "defmod", 0); - int reload = xml_ivalue(node, "reload", 0); - double magres = xml_fvalue(node, "magres", 0.0); if (xml_bvalue(node, "armorpiercing", false)) @@ -818,7 +739,6 @@ static weapon_type *xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) assert(result->nodesetval->nodeNr <= 2); for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - int pos = 0; propValue = xmlGetProp(node, BAD_CAST "type"); @@ -842,9 +762,7 @@ static weapon_type *xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) wtype->modifiers = calloc(result->nodesetval->nodeNr + 1, sizeof(weapon_mod)); for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - xmlXPathObjectPtr races; - int r, flags = 0; if (xml_bvalue(node, "walking", false)) @@ -880,7 +798,6 @@ static weapon_type *xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) propValue = xmlGetProp(node, BAD_CAST "name"); if (propValue != NULL) { const race *rc = rc_find((const char *)propValue); - if (rc == NULL) rc = rc_add(rc_new((const char *)propValue)); racelist_insert(&wtype->modifiers[k].races, rc); @@ -897,9 +814,7 @@ static weapon_type *xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) result = xmlXPathEvalExpression(BAD_CAST "function", xpath); for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - xmlChar *propValue; - pf_generic fun; parse_function(node, &fun, &propValue); @@ -930,17 +845,12 @@ static weapon_type *xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) static item_type *xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) { xmlNodePtr node = xpath->node; - item_type *itype = NULL; - unsigned int flags = ITF_NONE; - xmlXPathObjectPtr result; - int k; int weight = xml_ivalue(node, "weight", 0); - int capacity = xml_ivalue(node, "capacity", 0); if (xml_bvalue(node, "cursed", false)) @@ -1012,9 +922,7 @@ static item_type *xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) result = xmlXPathEvalExpression(BAD_CAST "function", xpath); for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - xmlChar *propValue; - pf_generic fun; parse_function(node, &fun, &propValue); @@ -1055,11 +963,8 @@ static item_type *xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) static int parse_rules(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr functions; - xmlNodeSetPtr nodes; - int i; /* reading eressea/resources/resource */ @@ -1067,9 +972,7 @@ static int parse_rules(xmlDocPtr doc) nodes = functions->nodesetval; for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; - xmlChar *propValue; - pf_generic fun; parse_function(node, &fun, &propValue); @@ -1100,11 +1003,8 @@ static int parse_rules(xmlDocPtr doc) static int parse_resources(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr resources; - xmlNodeSetPtr nodes; - int i; /* reading eressea/resources/resource */ @@ -1113,19 +1013,12 @@ static int parse_resources(xmlDocPtr doc) nodes = resources->nodesetval; for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; - xmlChar *propValue, *name, *appearance; - const char *names[2], *appearances[2]; - char *namep = NULL, *appearancep = NULL; - resource_type *rtype; - unsigned int flags = RTF_NONE; - xmlXPathObjectPtr result; - int k; if (xml_bvalue(node, "pooled", true)) @@ -1182,7 +1075,6 @@ static int parse_resources(xmlDocPtr doc) xmlFree(name); } - if (gamecode_enabled) { /* reading eressea/resources/resource/function */ xpath->node = node; @@ -1190,7 +1082,6 @@ static int parse_resources(xmlDocPtr doc) if (result->nodesetval != NULL) for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - pf_generic fun; parse_function(node, &fun, &propValue); @@ -1223,9 +1114,7 @@ static int parse_resources(xmlDocPtr doc) assert(result->nodesetval->nodeNr <= 1); if (result->nodesetval->nodeNr != 0) { resource_limit *rdata; - attrib *a = a_find(rtype->attribs, &at_resourcelimit); - xmlNodePtr limit = result->nodesetval->nodeTab[0]; if (a == NULL) @@ -1241,9 +1130,7 @@ static int parse_resources(xmlDocPtr doc) calloc(result->nodesetval->nodeNr + 1, sizeof(resource_mod)); for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - building_type *btype = NULL; - const race *rc = NULL; propValue = xmlGetProp(node, BAD_CAST "race"); @@ -1275,7 +1162,6 @@ static int parse_resources(xmlDocPtr doc) rdata->modifiers[k].flags = RMF_SAVERESOURCE; } else if (strcmp((const char *)propValue, "require") == 0) { xmlChar *propBldg = xmlGetProp(node, BAD_CAST "building"); - if (propBldg != NULL) { btype = bt_get_or_create((const char *)propBldg); rdata->modifiers[k].btype = btype; @@ -1295,7 +1181,6 @@ static int parse_resources(xmlDocPtr doc) if (result->nodesetval != NULL) for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - xmlChar *propFlag = xmlGetProp(node, BAD_CAST "flag"); if (propFlag != NULL) { @@ -1314,7 +1199,6 @@ static int parse_resources(xmlDocPtr doc) if (result->nodesetval != NULL) for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - pf_generic fun; propValue = xmlGetProp(node, BAD_CAST "value"); @@ -1374,12 +1258,9 @@ static void add_items(equipment * eq, xmlNodeSetPtr nsetItems) { if (nsetItems != NULL && nsetItems->nodeNr > 0) { int i; - for (i = 0; i != nsetItems->nodeNr; ++i) { xmlNodePtr node = nsetItems->nodeTab[i]; - xmlChar *propValue; - const struct item_type *itype; propValue = xmlGetProp(node, BAD_CAST "name"); @@ -1401,12 +1282,9 @@ static void add_callbacks(equipment * eq, xmlNodeSetPtr nsetItems) { if (nsetItems != NULL && nsetItems->nodeNr > 0) { int i; - for (i = 0; i != nsetItems->nodeNr; ++i) { xmlNodePtr node = nsetItems->nodeTab[i]; - xmlChar *propValue; - pf_generic fun; propValue = xmlGetProp(node, BAD_CAST "name"); @@ -1426,14 +1304,10 @@ static void add_spells(equipment * eq, xmlNodeSetPtr nsetItems) { if (nsetItems != NULL && nsetItems->nodeNr > 0) { int i; - for (i = 0; i != nsetItems->nodeNr; ++i) { xmlNodePtr node = nsetItems->nodeTab[i]; - xmlChar *propValue; - magic_t mtype = M_NONE; - struct spell *sp; propValue = xmlGetProp(node, BAD_CAST "school"); @@ -1462,12 +1336,9 @@ static void add_skills(equipment * eq, xmlNodeSetPtr nsetSkills) { if (nsetSkills != NULL && nsetSkills->nodeNr > 0) { int i; - for (i = 0; i != nsetSkills->nodeNr; ++i) { xmlNodePtr node = nsetSkills->nodeTab[i]; - xmlChar *propValue; - skill_t sk; propValue = xmlGetProp(node, BAD_CAST "name"); @@ -1493,16 +1364,13 @@ static void add_subsets(xmlDocPtr doc, equipment * eq, xmlNodeSetPtr nsetSubsets) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - if (nsetSubsets != NULL && nsetSubsets->nodeNr > 0) { int i; eq->subsets = calloc(nsetSubsets->nodeNr + 1, sizeof(subset)); for (i = 0; i != nsetSubsets->nodeNr; ++i) { xmlXPathObjectPtr xpathResult; - xmlNodePtr node = nsetSubsets->nodeTab[i]; - xmlChar *propValue; eq->subsets[i].chance = 1.0f; @@ -1515,17 +1383,14 @@ add_subsets(xmlDocPtr doc, equipment * eq, xmlNodeSetPtr nsetSubsets) xpathResult = xmlXPathEvalExpression(BAD_CAST "set", xpath); if (xpathResult->nodesetval) { xmlNodeSetPtr nsetSets = xpathResult->nodesetval; - float totalChance = 0.0f; if (nsetSets->nodeNr > 0) { int set; - eq->subsets[i].sets = calloc(nsetSets->nodeNr + 1, sizeof(subsetitem)); for (set = 0; set != nsetSets->nodeNr; ++set) { xmlNodePtr nodeSet = nsetSets->nodeTab[set]; - float chance = 1.0f; propValue = xmlGetProp(nodeSet, BAD_CAST "chance"); @@ -1557,24 +1422,20 @@ add_subsets(xmlDocPtr doc, equipment * eq, xmlNodeSetPtr nsetSubsets) static int parse_equipment(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr xpathRaces; /* reading eressea/equipment/set */ xpathRaces = xmlXPathEvalExpression(BAD_CAST "/eressea/equipment/set", xpath); if (xpathRaces->nodesetval) { xmlNodeSetPtr nsetRaces = xpathRaces->nodesetval; - int i; for (i = 0; i != nsetRaces->nodeNr; ++i) { xmlNodePtr node = nsetRaces->nodeTab[i]; - xmlChar *propName = xmlGetProp(node, BAD_CAST "name"); if (propName != NULL) { equipment *eq = create_equipment((const char *)propName); - xmlXPathObjectPtr xpathResult; xpath->node = node; @@ -1617,27 +1478,20 @@ static int parse_equipment(xmlDocPtr doc) static int parse_spells(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr spells; /* reading eressea/spells/spell */ spells = xmlXPathEvalExpression(BAD_CAST "/eressea/spells/spell", xpath); if (spells->nodesetval != NULL) { xmlNodeSetPtr nodes = spells->nodesetval; - int i; for (i = 0; i != nodes->nodeNr; ++i) { xmlXPathObjectPtr result; - xmlNodePtr node = nodes->nodeTab[i]; - xmlChar *propValue; - int k; - spell_component *component; - spell *sp = (spell *) calloc(1, sizeof(spell)); static int modes[] = { 0, PRECOMBATSPELL, COMBATSPELL, POSTCOMBATSPELL }; @@ -1701,7 +1555,6 @@ static int parse_spells(xmlDocPtr doc) } else { for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - pf_generic fun; parse_function(node, &fun, &propValue); @@ -1738,9 +1591,7 @@ static int parse_spells(xmlDocPtr doc) for (component = sp->components, k = 0; k != result->nodesetval->nodeNr; ++k) { const resource_type *rtype; - xmlNodePtr node = result->nodesetval->nodeTab[k]; - propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue); rtype = rt_find((const char *)propValue); @@ -1780,7 +1631,6 @@ static int parse_spells(xmlDocPtr doc) static void parse_param(struct param **params, xmlNodePtr node) { xmlChar *propName = xmlGetProp(node, BAD_CAST "name"); - xmlChar *propValue = xmlGetProp(node, BAD_CAST "value"); set_param(params, (const char *)propName, (const char *)propValue); @@ -1804,11 +1654,8 @@ static void parse_ai(race * rc, xmlNodePtr node) static int parse_races(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr races; - xmlNodeSetPtr nodes; - int i; /* reading eressea/races/race */ @@ -1816,17 +1663,11 @@ static int parse_races(xmlDocPtr doc) nodes = races->nodesetval; for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; - xmlNodePtr child; - xmlChar *propValue; - race *rc; - xmlXPathObjectPtr result; - int k, study_speed_base; - struct att *attack; propValue = xmlGetProp(node, BAD_CAST "name"); @@ -1956,11 +1797,8 @@ static int parse_races(xmlDocPtr doc) memset(rc->bonus, 0, sizeof(rc->bonus)); for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - int mod = xml_ivalue(node, "modifier", 0); - int speed = xml_ivalue(node, "speed", study_speed_base); - skill_t sk; propValue = xmlGetProp(node, BAD_CAST "name"); @@ -1987,7 +1825,6 @@ static int parse_races(xmlDocPtr doc) result = xmlXPathEvalExpression(BAD_CAST "function", xpath); for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - pf_generic fun; parse_function(node, &fun, &propValue); @@ -2026,7 +1863,6 @@ static int parse_races(xmlDocPtr doc) result = xmlXPathEvalExpression(BAD_CAST "familiar", xpath); for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - race *frc; propValue = xmlGetProp(node, BAD_CAST "race"); @@ -2055,7 +1891,6 @@ static int parse_races(xmlDocPtr doc) || !"precombatspell is already initialized"); for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - rc->precombatspell = xml_spell(node, "spell"); } xmlXPathFreeObject(result); @@ -2066,7 +1901,6 @@ static int parse_races(xmlDocPtr doc) attack = rc->attack; for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - while (attack->type != AT_NONE) ++attack; @@ -2093,11 +1927,8 @@ static int parse_races(xmlDocPtr doc) static int parse_terrains(xmlDocPtr doc) { xmlXPathContextPtr xpath; - xmlXPathObjectPtr terrains; - xmlNodeSetPtr nodes; - int i; xpath = xmlXPathNewContext(doc); @@ -2108,13 +1939,9 @@ static int parse_terrains(xmlDocPtr doc) nodes = terrains->nodesetval; for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; - terrain_type *terrain = calloc(1, sizeof(terrain_type)); - xmlChar *propValue; - xmlXPathObjectPtr xpathChildren; - xmlNodeSetPtr children; propValue = xmlGetProp(node, BAD_CAST "name"); @@ -2163,7 +1990,6 @@ static int parse_terrains(xmlDocPtr doc) terrain->herbs[children->nodeNr] = NULL; for (k = 0; k != children->nodeNr; ++k) { xmlNodePtr nodeHerb = children->nodeTab[k]; - const struct resource_type *rtype; propValue = xmlGetProp(nodeHerb, BAD_CAST "name"); @@ -2229,11 +2055,8 @@ static int parse_terrains(xmlDocPtr doc) static int parse_messages(xmlDocPtr doc) { xmlXPathContextPtr xpath; - xmlXPathObjectPtr messages; - xmlNodeSetPtr nodes; - int i; if (!gamecode_enabled) @@ -2247,19 +2070,12 @@ static int parse_messages(xmlDocPtr doc) nodes = messages->nodesetval; for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; - const char *default_section = "events"; - xmlChar *propSection; - xmlChar *propValue; - xmlXPathObjectPtr result; - int k; - char **argv = NULL; - const message_type *mtype; /* arguments */ @@ -2269,9 +2085,7 @@ static int parse_messages(xmlDocPtr doc) argv = malloc(sizeof(char *) * (result->nodesetval->nodeNr + 1)); for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - char zBuffer[128]; - xmlChar *propName, *propType; propName = xmlGetProp(node, BAD_CAST "name"); @@ -2315,9 +2129,7 @@ static int parse_messages(xmlDocPtr doc) result = xmlXPathEvalExpression(BAD_CAST "text", xpath); for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - struct locale *lang; - xmlChar *propText; xml_readtext(node, &lang, &propText); @@ -2349,15 +2161,10 @@ xml_readstrings(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, for (i = 0; i != nodeNr; ++i) { xmlNodePtr stringNode = nodeTab[i]; - xmlChar *propName = xmlGetProp(stringNode, BAD_CAST "name"); - xmlChar *propNamespace = NULL; - xmlXPathObjectPtr result; - int k; - char zName[128]; assert(propName != NULL); @@ -2373,9 +2180,7 @@ xml_readstrings(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, result = xmlXPathEvalExpression(BAD_CAST "text", xpath); for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr textNode = result->nodesetval->nodeTab[k]; - struct locale *lang; - xmlChar *propText; xml_readtext(textNode, &lang, &propText); @@ -2399,7 +2204,6 @@ xml_readstrings(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, static int parse_strings(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr strings; /* reading eressea/strings/string */ @@ -2426,7 +2230,6 @@ xml_readprefixes(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, for (i = 0; i != nodeNr; ++i) { xmlNodePtr node = nodeTab[i]; - xmlChar *propText = xmlNodeListGetString(node->doc, node->children, 1); if (propText != NULL) { @@ -2439,7 +2242,6 @@ xml_readprefixes(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, static int parse_prefixes(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr strings; /* reading eressea/strings/string */ @@ -2455,15 +2257,12 @@ static int parse_prefixes(xmlDocPtr doc) static int parse_main(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); - xmlXPathObjectPtr result = xmlXPathEvalExpression(BAD_CAST "/eressea/game", xpath); xmlNodeSetPtr nodes = result->nodesetval; - int i; xmlChar *propValue; - if (nodes->nodeNr > 0) { xmlNodePtr node = nodes->nodeTab[0]; @@ -2473,7 +2272,6 @@ static int parse_main(xmlDocPtr doc) propValue = xmlGetProp(node, BAD_CAST "name"); if (propValue != NULL) { global.gamename = strdup((const char *)propValue); - xmlFree(propValue); } @@ -2485,7 +2283,6 @@ static int parse_main(xmlDocPtr doc) nodes = result->nodesetval; for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; - parse_param(&global.parameters, node); } @@ -2496,18 +2293,14 @@ static int parse_main(xmlDocPtr doc) nodes = result->nodesetval; for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; - xmlChar *propName = xmlGetProp(node, BAD_CAST "name"); - boolean disable = xml_bvalue(node, "disable", false); if (disable) { int k; - for (k = 0; k != MAXKEYWORDS; ++k) { if (strcmp(keywords[k], (const char *)propName) == 0) { global.disabled[k] = 1; - break; } } @@ -2526,11 +2319,8 @@ static int parse_main(xmlDocPtr doc) nodes = result->nodesetval; for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; - xmlChar *propName = xmlGetProp(node, BAD_CAST "name"); - boolean enable = xml_bvalue(node, "enable", true); - enable_skill((const char *)propName, enable); xmlFree(propName); } diff --git a/src/modules/arena.c b/src/modules/arena.c index eb31f2f8e..52e6e351f 100644 --- a/src/modules/arena.c +++ b/src/modules/arena.c @@ -66,23 +66,18 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include - /* exports: */ plane *arena = NULL; - /* local vars */ #define CENTRAL_VOLCANO 1 #ifdef ARENA_CREATION static unsigned int arena_id = 0; - static region *arena_center = NULL; - static int newarena = 0; #endif static region *tower_region[6]; - static region *start_region[6]; static region *arena_region(int school) @@ -127,13 +122,9 @@ static int enter_arena(unit * u, const item_type * itype, int amount, order * ord) { skill_t sk; - region *r = u->region; - unit *u2; - int fee = u->faction->score / 5; - unused(ord); unused(amount); unused(itype); @@ -192,11 +183,9 @@ use_wand_of_tears(unit * user, const struct item_type *itype, int amount, order * ord) { int n; - unused(ord); for (n = 0; n != amount; ++n) { unit *u; - for (u = user->region->units; u; u = u->next) { if (u->faction != user->faction) { int i; @@ -220,11 +209,8 @@ use_wand_of_tears(unit * user, const struct item_type *itype, int amount, static int age_hurting(attrib * a) { building *b = (building *) a->data.v; - unit *u; - int active = 0; - if (b == NULL) return AT_AGE_REMOVE; for (u = b->region->units; u; u = u->next) { @@ -239,7 +225,6 @@ static int age_hurting(attrib * a) for (u = b->region->units; u; u = u->next) if (playerrace(u->faction->race)) { int i; - if (u->faction->magiegebiet != M_DRAIG) { for (i = 0; i != active; ++i) u->hp = (u->hp + 1) / 2; /* make them suffer, but not die */ @@ -253,14 +238,12 @@ static void write_hurting(const attrib * a, const void *owner, struct storage *store) { building *b = a->data.v; - store->w_int(store, b->no); } static int read_hurting(attrib * a, void *owner, struct storage *store) { int i; - i = store->r_int(store); a->data.v = (void *)findbuilding(i); if (a->data.v == NULL) { @@ -278,9 +261,7 @@ static attrib_type at_hurting = { static void make_temple(region * r) { const building_type *btype = bt_find("temple"); - building *b; - if (btype == NULL) { log_error(("could not find buildingtype 'temple'\n")); return; @@ -309,11 +290,8 @@ static void make_temple(region * r) static void tower_init(void) { int i, first = newarena; - item_type *it_demonseye = it_find("demonseye"); - item_type *it_griphonwing = it_find("griphonwing"); - assert(it_griphonwing && it_demonseye); for (i = 0; i != 6; ++i) { region *r = tower_region[i] = @@ -327,7 +305,6 @@ static void tower_init(void) terraform(r, T_DESERT); if (!r->buildings) { building *b = new_building(bt_find("castle"), r, NULL); - b->size = 10; if (i != 0) { sprintf(buf, "Turm des %s", @@ -340,9 +317,7 @@ static void tower_init(void) } if (first && !arena_center->buildings) { building *b = new_building(bt_find("castle"), arena_center, NULL); - attrib *a; - item *items; i_add(&items, i_new(it_griphonwing, 1)); @@ -359,7 +334,6 @@ static void tower_init(void) static void guardian_faction(plane * pl, int id) { region *r; - faction *f = findfaction(id); if (!f) { @@ -389,7 +363,6 @@ static void guardian_faction(plane * pl, int id) for (r = regions; r; r = r->next) if (getplane(r) == pl && rterrain(r) != T_FIREWALL) { unit *u; - freset(r, RF_ENCOUNTER); for (u = r->units; u; u = u->next) { if (u->faction == f) @@ -413,11 +386,9 @@ static void guardian_faction(plane * pl, int id) static void block_create(int x1, int y1, char terrain) { int x, y; - for (x = 0; x != BLOCKSIZE; ++x) { for (y = 0; y != BLOCKSIZE; ++y) { region *r = new_region(x1 + x, y1 + y, 0); - terraform(r, terrain); } } @@ -432,23 +403,17 @@ static int caldera_handle(trigger * t, void *data) * data.v -> ( variant event, int timer ) */ building *b = (building *) t->data.v; - if (b != NULL) { unit **up = &b->region->units; - while (*up) { unit *u = *up; - if (u->building == b) { message *msg; - if (u->items) { item **ip = &u->items; - msg = msg_message("caldera_handle_1", "unit items", u, u->items); while (*ip) { item *i = *ip; - i_remove(ip, i); if (*ip == i) ip = &i->next; @@ -472,7 +437,6 @@ static int caldera_handle(trigger * t, void *data) static void caldera_write(const trigger * t, struct storage *store) { building *b = (building *) t->data.v; - write_building_reference(b, store); } @@ -500,7 +464,6 @@ struct trigger_type tt_caldera = { static trigger *trigger_caldera(building * b) { trigger *t = t_new(&tt_caldera); - t->data.v = b; return t; } @@ -510,9 +473,7 @@ static trigger *trigger_caldera(building * b) static void init_volcano(void) { building *b; - region *r = arena_center; - assert(arena_center); if (rterrain(r) != T_DESERT) return; /* been done before */ @@ -533,7 +494,6 @@ static void init_volcano(void) void create_arena(void) { int x; - arena_id = hashstring("arena"); arena = getplanebyid(arena_id); if (arena != NULL) @@ -551,10 +511,8 @@ void create_arena(void) arena_center = findregion(plane_center_x(arena), plane_center_y(arena)); for (x = 0; x != BLOCKSIZE; ++x) { int y; - for (y = 0; y != BLOCKSIZE; ++y) { region *r = findregion(arena->minx + x, arena->miny + y); - freset(r, RF_ENCOUNTER); r->planep = arena; switch (distance(r, arena_center)) { diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c index f2fa68150..dc8013e29 100644 --- a/src/modules/autoseed.c +++ b/src/modules/autoseed.c @@ -52,9 +52,7 @@ const terrain_type *random_terrain(const terrain_type * terrains[], int distribution[], int size) { int ndistribution = size; - const terrain_type *terrain; - int n; if (distribution) { @@ -67,7 +65,6 @@ const terrain_type *random_terrain(const terrain_type * terrains[], n = rng_int() % ndistribution; if (distribution) { int i; - for (i = 0; i != size; ++i) { n -= distribution[i]; if (n < 0) @@ -84,9 +81,7 @@ const terrain_type *random_terrain(const terrain_type * terrains[], int seed_adamantium(region * r, int base) { const resource_type *rtype = rt_find("adamantium"); - rawmaterial *rm; - for (rm = r->resources; rm; rm = rm->next) { if (rm->type->rtype == rtype) break; @@ -97,13 +92,10 @@ int seed_adamantium(region * r, int base) return 0; } - static int count_demand(const region * r) { struct demand *dmd; - int c = 0; - if (r->land) { for (dmd = r->land->demands; dmd; dmd = dmd->next) c++; @@ -119,18 +111,14 @@ recurse_regions(region * r, region_list ** rlist, return 0; else { int len = 0; - direction_t d; - region_list *rl = calloc(sizeof(region_list), 1); - rl->next = *rlist; rl->data = r; (*rlist) = rl; fset(r, RF_MARK); for (d = 0; d != MAXDIRECTIONS; ++d) { region *nr = rconnect(r, d); - if (nr && !fval(nr, RF_MARK)) len += recurse_regions(nr, rlist, fun); } @@ -148,13 +136,9 @@ static boolean f_nolux(const region * r) int fix_demand(region * rd) { region_list *rl, *rlist = NULL; - static const struct luxury_type **mlux = 0, **ltypes; - const luxury_type *sale = NULL; - int maxlux = 0; - int maxluxuries = get_maxluxuries(); if (maxluxuries == 0) @@ -162,7 +146,6 @@ int fix_demand(region * rd) recurse_regions(rd, &rlist, f_nolux); if (mlux == 0) { int i = 0; - mlux = (const luxury_type **)gc_add(calloc(maxluxuries, sizeof(const luxury_type *))); @@ -174,25 +157,19 @@ int fix_demand(region * rd) } } else { int i; - for (i = 0; i != maxluxuries; ++i) mlux[i] = 0; } for (rl = rlist; rl; rl = rl->next) { region *r = rl->data; - direction_t d; - for (d = 0; d != MAXDIRECTIONS; ++d) { region *nr = rconnect(r, d); - if (nr && nr->land && nr->land->demands) { struct demand *dmd; - for (dmd = nr->land->demands; dmd; dmd = dmd->next) { if (dmd->value == 0) { int i; - for (i = 0; i != maxluxuries; ++i) { if (mlux[i] == NULL) { maxlux = i; @@ -211,13 +188,10 @@ int fix_demand(region * rd) } if (maxlux < 2) { int i; - for (i = maxlux; i != 2; ++i) { int j; - do { int k = rng_int() % maxluxuries; - mlux[i] = ltypes[k]; for (j = 0; j != i; ++j) { if (mlux[j] == mlux[i]) @@ -229,7 +203,6 @@ int fix_demand(region * rd) } for (rl = rlist; rl; rl = rl->next) { region *r = rl->data; - if (!fval(r, RF_CHAOTIC)) { log_info((LOG_INFO1, "fixing demand in %s\n", regionname(r, NULL))); } @@ -250,22 +223,16 @@ int fix_demand(region * rd) newfaction *read_newfactions(const char *filename) { newfaction *newfactions = NULL; - FILE *F = fopen(filename, "r"); - char buf[1024]; if (F == NULL) return NULL; for (;;) { faction *f; - char race[20], email[64], lang[8], password[16]; - newfaction *nf, **nfi; - int bonus = 0, subscription = 0; - int alliance = 0; if (fgets(buf, sizeof(buf), F) == NULL) @@ -307,10 +274,8 @@ newfaction *read_newfactions(const char *filename) nf->subscription = subscription; if (alliances != NULL) { struct alliance *al = findalliance(alliance); - if (al == NULL) { char zText[64]; - sprintf(zText, "Allianz %d", alliance); al = makealliance(alliance, zText); } @@ -324,11 +289,8 @@ newfaction *read_newfactions(const char *filename) nf->race = findrace(race, default_locale); if (nf->race == NULL) { char buffer[32]; - size_t outbytes = sizeof(buffer) - 1; - size_t inbytes = strlen(race); - unicode_latin1_to_utf8(buffer, &outbytes, race, &inbytes); buffer[outbytes] = 0; nf->race = findrace(buffer, default_locale); @@ -360,7 +322,6 @@ extern int numnewbies; static const terrain_type *preferred_terrain(const struct race *rc) { terrain_t t = T_PLAIN; - if (rc == rc_find("dwarf")) t = T_MOUNTAIN; if (rc == rc_find("insect")) @@ -381,7 +342,6 @@ static const terrain_type *preferred_terrain(const struct race *rc) static boolean virgin_region(const region * r) { direction_t d; - if (r == NULL) return true; if (fval(r->terrain, FORBIDDEN_REGION)) @@ -390,7 +350,6 @@ static boolean virgin_region(const region * r) return false; for (d = 0; d != MAXDIRECTIONS; ++d) { const region *rn = rconnect(r, d); - if (rn) { if (rn->age > r->age + 1) return false; @@ -408,7 +367,6 @@ static boolean virgin_region(const region * r) void get_island(region * root, region_list ** rlist) { region_list **rnext = rlist; - while (*rnext) rnext = &(*rnext)->next; @@ -419,12 +377,10 @@ void get_island(region * root, region_list ** rlist) direction_t dir; region *rcurrent = (*rnext)->data; - rnext = &(*rnext)->next; for (dir = 0; dir != MAXDIRECTIONS; ++dir) { region *r = rconnect(rcurrent, dir); - if (r != NULL && r->land && !fval(r, RF_MARK)) { fset(r, RF_MARK); add_regionlist(rnext, r); @@ -434,7 +390,6 @@ void get_island(region * root, region_list ** rlist) rnext = rlist; while (*rnext) { region_list *rptr = *rnext; - freset(rptr->data, RF_MARK); rnext = &rptr->next; } @@ -444,22 +399,16 @@ static void get_island_info(region * root, int *size_p, int *inhabited_p, int *maxage_p) { int size = 0, maxage = 0, inhabited = 0; - region_list *rlist = NULL; - region_list *island = NULL; - add_regionlist(&rlist, root); island = rlist; fset(root, RF_MARK); while (rlist) { direction_t d; - region *r = rlist->data; - if (r->units) { unit *u; - for (u = r->units; u; u = u->next) { if (!is_monsters(u->faction) && u->faction->age > maxage) { maxage = u->faction->age; @@ -470,10 +419,8 @@ get_island_info(region * root, int *size_p, int *inhabited_p, int *maxage_p) ++size; for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r, d); - if (rn && !fval(rn, RF_MARK) && rn->land) { region_list *rnew = malloc(sizeof(region_list)); - rnew->data = rn; rnew->next = rlist->next; rlist->next = rnew; @@ -504,14 +451,10 @@ void free_newfaction(newfaction * nf) static void frame_regions(int age, const terrain_type * terrain) { plane *hplane = get_homeplane(); - region *r = regions; - for (r = regions; r; r = r->next) { plane *pl = rplane(r); - direction_t d; - if (r->age < age) continue; if (pl != hplane) @@ -521,12 +464,9 @@ static void frame_regions(int age, const terrain_type * terrain) for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r, d); - if (rn == NULL) { int x = r->x + delta_x[d]; - int y = r->y + delta_y[d]; - pnormalize(&x, &y, pl); rn = new_region(x, y, pl, 0); terraform_region(rn, terrain); @@ -539,7 +479,6 @@ static void frame_regions(int age, const terrain_type * terrain) static void prepare_starting_region(region * r) { int n, t; - double p; assert(r->land); @@ -553,9 +492,7 @@ static void prepare_starting_region(region * r) t = (rtrees(r, 2) + rtrees(r, 1) / 2) * TREESIZE; if (t < r->terrain->size / 20 || t + n > r->terrain->size) { double p2 = 0.05 + rng_double() * (1.0 - p - 0.05); - int maxtrees = (int)(r->terrain->size / 1.25 / TREESIZE); /* 1.25 = each young tree will take 1/2 the space of old trees */ - int trees = (int)(p2 * maxtrees); rsettrees(r, 2, trees); @@ -578,28 +515,18 @@ static void prepare_starting_region(region * r) int autoseed(newfaction ** players, int nsize, int max_agediff) { region *r = NULL; - region_list *rlist = NULL; - int rsize = 0, tsize = 0; - int isize = REGIONS_PER_FACTION; /* target size for the island */ - int psize = 0; /* players on this island */ - const terrain_type *volcano_terrain = get_terrain("volcano"); - static int nterrains = -1; - static const terrain_type **terrainarr = 0; - static int *distribution; if (nterrains < 0) { int n = 0; - const terrain_type *terrain = terrains(); - for (nterrains = 0; terrain; terrain = terrain->next) { if (terrain->distribution) { ++nterrains; @@ -621,26 +548,20 @@ int autoseed(newfaction ** players, int nsize, int max_agediff) if (max_agediff > 0) { region *rmin = NULL; - plane *hplane = get_homeplane(); - /* find a spot that's adjacent to the previous island, but virgin. * like the last land virgin ocean region adjacent to land. */ for (r = regions; r; r = r->next) { struct plane *pl = rplane(r); - if (r->age <= max_agediff && r->terrain == newterrain(T_OCEAN) && pl == hplane && virgin_region(r)) { direction_t d; - for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r, d); - if (rn && rn->land && rn->age <= max_agediff && virgin_region(rn)) { /* only expand islands that aren't single-islands and not too big already */ int size, inhabitants, maxage; - get_island_info(rn, &size, &inhabitants, &maxage); if (maxage <= max_agediff && size >= 2 && size < MAXISLANDSIZE) { rmin = rn; @@ -652,15 +573,11 @@ int autoseed(newfaction ** players, int nsize, int max_agediff) } if (rmin != NULL) { region_list *rlist = NULL, *rptr; - faction *f; - get_island(rmin, &rlist); for (rptr = rlist; rptr; rptr = rptr->next) { region *r = rlist->data; - unit *u; - for (u = r->units; u; u = u->next) { f = u->faction; if (!fval(f, FFL_MARK)) { @@ -680,25 +597,19 @@ int autoseed(newfaction ** players, int nsize, int max_agediff) } if (r == NULL) { region *rmin = NULL; - direction_t dmin = MAXDIRECTIONS; - plane *hplane = get_homeplane(); - /* find an empty spot. * rmin = the youngest ocean region that has a missing neighbour * dmin = direction in which it's empty */ for (r = regions; r; r = r->next) { struct plane *pl = rplane(r); - if (r->terrain == newterrain(T_OCEAN) && pl == hplane && (rmin == NULL || r->age <= max_agediff)) { direction_t d; - for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r, d); - if (rn == NULL) break; } @@ -714,11 +625,8 @@ int autoseed(newfaction ** players, int nsize, int max_agediff) * get populated, and old regions are not overwritten */ if (rmin != NULL) { plane *pl = rplane(rmin); - int x = rmin->x + delta_x[dmin]; - int y = rmin->y + delta_y[dmin]; - pnormalize(&x, &y, pl); assert(virgin_region(rconnect(rmin, dmin))); r = new_region(x, y, pl, 0); @@ -733,13 +641,9 @@ int autoseed(newfaction ** players, int nsize, int max_agediff) while (rsize && (nsize || isize >= REGIONS_PER_FACTION)) { int i = rng_int() % rsize; - region_list **rnext = &rlist; - region_list *rfind; - direction_t d; - while (i--) rnext = &(*rnext)->next; rfind = *rnext; @@ -750,16 +654,12 @@ int autoseed(newfaction ** players, int nsize, int max_agediff) --rsize; for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r, d); - if (rn && fval(rn, RF_MARK)) continue; if (rn == NULL) { plane *pl = rplane(r); - int x = r->x + delta_x[d]; - int y = r->y + delta_y[d]; - pnormalize(&x, &y, pl); rn = new_region(x, y, pl, 0); terraform_region(rn, newterrain(T_OCEAN)); @@ -774,9 +674,7 @@ int autoseed(newfaction ** players, int nsize, int max_agediff) terraform_region(r, volcano_terrain); } else if (nsize && (rng_int() % isize == 0 || rsize == 0)) { newfaction **nfp, *nextf = *players; - faction *f; - unit *u; isize += REGIONS_PER_FACTION; @@ -802,7 +700,6 @@ int autoseed(newfaction ** players, int nsize, int max_agediff) nfp = &nextf->next; while (*nfp) { newfaction *nf = *nfp; - if (strcmp(nextf->email, nf->email) == 0) { *nfp = nf->next; free_newfaction(nf); @@ -828,41 +725,29 @@ int autoseed(newfaction ** players, int nsize, int max_agediff) ("Could not place all factions on the same island as requested\n")); } - if (rlist) { #define MINOCEANDIST 3 #define MAXOCEANDIST 6 #define MAXFILLDIST 10 #define SPECIALCHANCE 80 region_list **rbegin = &rlist; - int special = 1; - int oceandist = MINOCEANDIST + (rng_int() % (MAXOCEANDIST - MINOCEANDIST)); - while (oceandist--) { region_list **rend = rbegin; - while (*rend) rend = &(*rend)->next; while (rbegin != rend) { direction_t d; - region *r = (*rbegin)->data; - rbegin = &(*rbegin)->next; for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r, d); - if (rn == NULL) { const struct terrain_type *terrain = newterrain(T_OCEAN); - plane *pl = rplane(r); - int x = r->x + delta_x[d]; - int y = r->y + delta_y[d]; - pnormalize(&x, &y, pl); rn = new_region(x, y, pl, 0); if (rng_int() % SPECIALCHANCE < special) { @@ -883,21 +768,15 @@ int autoseed(newfaction ** players, int nsize, int max_agediff) } while (*rbegin) { region *r = (*rbegin)->data; - plane *pl = rplane(r); - direction_t d; - rbegin = &(*rbegin)->next; for (d = 0; d != MAXDIRECTIONS; ++d) if (rconnect(r, d) == NULL) { int i; - for (i = 1; i != MAXFILLDIST; ++i) { int x = r->x + delta_x[d] * i; - int y = r->y + delta_y[d] * i; - pnormalize(&x, &y, pl); if (findregion(x, y)) { break; @@ -906,11 +785,8 @@ int autoseed(newfaction ** players, int nsize, int max_agediff) if (i != MAXFILLDIST) { while (--i) { region *rn; - int x = r->x + delta_x[d] * i; - int y = r->y + delta_y[d] * i; - pnormalize(&x, &y, pl); rn = new_region(x, y, pl, 0); terraform_region(rn, newterrain(T_OCEAN)); @@ -920,7 +796,6 @@ int autoseed(newfaction ** players, int nsize, int max_agediff) } while (rlist) { region_list *self = rlist; - rlist = rlist->next; freset(self->data, RF_MARK); free(self); @@ -932,7 +807,6 @@ int autoseed(newfaction ** players, int nsize, int max_agediff) region_list *regionqueue_push(region_list ** rlist, region * r) { region_list *rnew = malloc(sizeof(region_list)); - rnew->data = r; rnew->next = 0; while (*rlist) { @@ -946,9 +820,7 @@ region *regionqueue_pop(region_list ** rlist) { if (*rlist) { region *r = (*rlist)->data; - region_list *rpop = *rlist; - *rlist = rpop->next; free(rpop); return r; @@ -975,7 +847,6 @@ static struct geo { const terrain_type *random_terrain_e3(direction_t dir) { static const terrain_type **terrainarr = 0; - static int *distribution = 0; if (!distribution) { @@ -996,21 +867,14 @@ random_neighbours(region * r, region_list ** rlist, const terrain_type * (*terraformer) (direction_t)) { int nsize = 0; - direction_t dir; - for (dir = 0; dir != MAXDIRECTIONS; ++dir) { region *rn = rconnect(r, dir); - if (rn == NULL) { const terrain_type *terrain = terraformer(dir); - plane *pl = rplane(r); - int x = r->x + delta_x[dir]; - int y = r->y + delta_y[dir]; - pnormalize(&x, &y, pl); rn = new_region(x, y, pl, 0); terraform_region(rn, terrain); @@ -1047,17 +911,12 @@ int region_quality(const region * r, region * rn[]) static void oceans_around(region * r, region * rn[]) { int n; - for (n = 0; n != MAXDIRECTIONS; ++n) { region *rx = rn[n]; - if (rx == NULL) { plane *pl = rplane(r); - int x = r->x + delta_x[n]; - int y = r->y + delta_y[n]; - pnormalize(&x, &y, pl); rx = new_region(x, y, pl, 0); terraform_region(rx, newterrain(T_OCEAN)); @@ -1069,12 +928,9 @@ static void oceans_around(region * r, region * rn[]) static void smooth_island(region_list * island) { region *rn[MAXDIRECTIONS]; - region_list *rlist = NULL; - for (rlist = island; rlist; rlist = rlist->next) { region *r = rlist->data; - int n, nland = 0; if (r->land) { @@ -1091,17 +947,13 @@ static void smooth_island(region_list * island) oceans_around(r, rn); for (n = 0; n != MAXDIRECTIONS; ++n) { int n1 = (n + 1) % MAXDIRECTIONS; - int n2 = (n + 1 + MAXDIRECTIONS) % MAXDIRECTIONS; - if (!rn[n]->land && rn[n1] != r && rn[n2] != r) { r = rlist->data; runhash(r); runhash(rn[n]); SWAP_VARS(int, r->x, rn[n]->x); - SWAP_VARS(int, r->y, rn[n]->y); - rhash(r); rhash(rn[n]); rlist->data = r; @@ -1117,7 +969,6 @@ static void smooth_island(region_list * island) static void starting_region(region * r, region * rn[]) { unit *u; - int n; oceans_around(r, rn); @@ -1136,17 +987,11 @@ int build_island_e3(int x, int y, int numfactions, int minsize) { #define MIN_QUALITY 1000 int nfactions = 0; - region_list *rlist = NULL; - region_list *island = NULL; - plane *pl = findplane(x, y); - region *r = findregion(x, y); - int nsize = 1; - int q, maxq = INT_MIN, minq = INT_MAX; if (!r) @@ -1192,7 +1037,6 @@ int build_island_e3(int x, int y, int numfactions, int minsize) r = rlist->data; if (!r->land && fval(r, RF_MARK)) { region *rn[MAXDIRECTIONS]; - get_neighbours(r, rn); q = region_quality(r, rn); if (q >= MIN_QUALITY * 4 / 3 && nfactions < numfactions) { @@ -1209,7 +1053,6 @@ int build_island_e3(int x, int y, int numfactions, int minsize) r = rlist->data; if (r->units) { region *rn[MAXDIRECTIONS]; - get_neighbours(r, rn); q = region_quality(r, rn); if (q - minq > (maxq - minq) * 2 / 3) { diff --git a/src/modules/autoseed.h b/src/modules/autoseed.h index c1fcc064c..f5b38b01c 100644 --- a/src/modules/autoseed.h +++ b/src/modules/autoseed.h @@ -16,7 +16,6 @@ extern "C" { #endif - struct region_list; struct newfaction; diff --git a/src/modules/dungeon.c b/src/modules/dungeon.c index ff4b8448d..657b20837 100644 --- a/src/modules/dungeon.c +++ b/src/modules/dungeon.c @@ -83,27 +83,16 @@ region *make_dungeon(const dungeon * data) {{1, 0}, {-1, 1}, {0, -1}} }; const struct race *bossrace = data->boss->race; - char name[128]; - int size = data->size; - int iterations = size * size; - unsigned int flags = PFL_NORECRUITS; - int n = 0; - struct faction *fmonsters = get_monsters(); - plane *p; - region *r, *center; - region *rnext; - region_list *iregion, *rlist = NULL; - const terrain_type *terrain_hell = get_terrain("hell"); assert(terrain_hell != NULL); @@ -119,12 +108,9 @@ region *make_dungeon(const dungeon * data) rnext = r = center; while (size > 0 && iterations--) { int d, o = rng_int() % 3; - for (d = 0; d != 3; ++d) { int index = (d + o) % 3; - region *rn = findregion(r->x + nb[n][index][0], r->y + nb[n][index][1]); - assert(r->terrain == terrain_hell); if (rn) { if (rn->terrain == terrain_hell) { @@ -160,20 +146,14 @@ region *make_dungeon(const dungeon * data) for (iregion = rlist; iregion; iregion = iregion->next) { monster *m = data->monsters; - region *r = iregion->data; - while (m) { if ((rng_int() % 100) < (m->chance * 100)) { /* TODO: check maxunits. */ treasure *loot = m->treasures; - struct itemtype_list *weapon = m->weapons; - int size = 1 + (rng_int() % m->avgsize) + (rng_int() % m->avgsize); - unit *u = createunit(r, fmonsters, size, m->race); - while (weapon) { i_change(&u->items, weapon->type, size); weapon = weapon->next; @@ -213,10 +193,8 @@ void make_dungeongate(region * source, region * target, const struct dungeon *d) static int tagbegin(xml_stack * stack) { xml_tag *tag = stack->tag; - if (strcmp(tag->name, "dungeon") == 0) { dungeon *d = (dungeon *) calloc(sizeof(dungeon), 1); - d->maxpeople = xml_ivalue(tag, "maxpeople"); if (d->maxpeople == 0) d->maxpeople = INT_MAX; @@ -227,13 +205,10 @@ static int tagbegin(xml_stack * stack) stack->state = d; } else { dungeon *d = (dungeon *) stack->state; - if (strcmp(tag->name, "skilllimit") == 0) { skill_t sk = sk_find(xml_value(tag, "name")); - if (sk != NOSKILL) { skilllimit *skl = calloc(sizeof(skilllimit), 1); - skl->skill = sk; if (xml_value(tag, "max") != NULL) { skl->maxskill = xml_ivalue(tag, "max"); @@ -248,7 +223,6 @@ static int tagbegin(xml_stack * stack) } } else if (strcmp(tag->name, "monster") == 0) { monster *m = calloc(sizeof(monster), 1); - m->race = rc_find(xml_value(tag, "race")); m->chance = xml_fvalue(tag, "chance"); m->avgsize = MAX(1, xml_ivalue(tag, "size")); @@ -264,9 +238,7 @@ static int tagbegin(xml_stack * stack) } } else if (strcmp(tag->name, "weapon") == 0) { monster *m = d->monsters; - itemtype_list *w = calloc(sizeof(itemtype_list), 1); - w->type = it_find(xml_value(tag, "type")); if (w->type) { w->next = m->weapons; @@ -280,10 +252,8 @@ static int tagbegin(xml_stack * stack) static int tagend(xml_stack * stack) { xml_tag *tag = stack->tag; - if (strcmp(tag->name, "dungeon")) { dungeon *d = (dungeon *) stack->state; - stack->state = NULL; d->next = dungeonstyles; dungeonstyles = d; diff --git a/src/modules/gmcmd.c b/src/modules/gmcmd.c index cc21e8961..a038ae39e 100644 --- a/src/modules/gmcmd.c +++ b/src/modules/gmcmd.c @@ -74,7 +74,6 @@ write_permissions(const attrib * a, const void *owner, struct storage *store) static int read_permissions(attrib * a, void *owner, struct storage *store) { attrib *attr = NULL; - a_read(store, &attr, NULL); a->data.v = attr; return AT_READ_OK; @@ -100,7 +99,6 @@ static void write_gmcreate(const attrib * a, const void *owner, struct storage *store) { const item_type *itype = (const item_type *)a->data.v; - assert(itype); store->w_tok(store, resourcename(itype->rtype, 0)); } @@ -108,7 +106,6 @@ write_gmcreate(const attrib * a, const void *owner, struct storage *store) static int read_gmcreate(attrib * a, void *owner, struct storage *store) { char zText[32]; - store->r_tok_buf(store, zText, sizeof(zText)); a->data.v = it_find(zText); if (a->data.v == NULL) { @@ -128,7 +125,6 @@ attrib_type at_gmcreate = { attrib *make_atgmcreate(const struct item_type * itype) { attrib *a = a_new(&at_gmcreate); - a->data.v = (void *)itype; return a; } @@ -136,11 +132,8 @@ attrib *make_atgmcreate(const struct item_type * itype) static void gm_create(const tnode * tnext, void *data, struct order *ord) { unit *u = (unit *) data; - int i; - attrib *permissions = a_find(u->faction->attribs, &at_permissions); - if (permissions) permissions = (attrib *) permissions->data.v; if (!permissions) @@ -149,9 +142,7 @@ static void gm_create(const tnode * tnext, void *data, struct order *ord) if (i > 0) { const char *iname = getstrtoken(); - const item_type *itype = finditemtype(iname, u->faction->locale); - if (itype == NULL) { mistake(u, ord, "unknown item."); } else { @@ -180,17 +171,11 @@ static boolean has_permission(const attrib * permissions, unsigned int key) static void gm_gate(const tnode * tnext, void *data, struct order *ord) { unit *u = (unit *) data; - const struct plane *pl = rplane(u->region); - int id = getid(); - int x = rel_to_abs(pl, u->faction, getint(), 0); - int y = rel_to_abs(pl, u->faction, getint(), 1); - building *b = findbuilding(id); - region *r; pnormalize(&x, &y, pl); @@ -201,7 +186,6 @@ static void gm_gate(const tnode * tnext, void *data, struct order *ord) } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); - if (permissions && has_permission(permissions, atoi36("gmgate"))) { remove_triggers(&b->attribs, "timer", &tt_gate); remove_triggers(&b->attribs, "create", &tt_unguard); @@ -214,7 +198,6 @@ static void gm_gate(const tnode * tnext, void *data, struct order *ord) } } - /** ** GM: TERRAFORM ** requires: permission-key "gmterf" @@ -222,21 +205,13 @@ static void gm_gate(const tnode * tnext, void *data, struct order *ord) static void gm_terraform(const tnode * tnext, void *data, struct order *ord) { unit *u = (unit *) data; - const struct plane *p = rplane(u->region); - int x = rel_to_abs(p, u->faction, getint(), 0); - int y = rel_to_abs(p, u->faction, getint(), 1); - const char *c = getstrtoken(); - variant token; - tnode *tokens = get_translations(u->faction->locale, UT_TERRAINS); - region *r; - pnormalize(&x, &y, p); r = findregion(x, y); @@ -246,14 +221,12 @@ static void gm_terraform(const tnode * tnext, void *data, struct order *ord) } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmterf"))) return; } if (findtoken(tokens, c, &token) != E_TOK_NOMATCH) { const terrain_type *terrain = (const terrain_type *)token.v; - terraform_region(r, terrain); } } @@ -265,15 +238,10 @@ static void gm_terraform(const tnode * tnext, void *data, struct order *ord) static void gm_teleport(const tnode * tnext, void *data, struct order *ord) { unit *u = (unit *) data; - const struct plane *p = rplane(u->region); - unit *to = findunit(getid()); - int x = rel_to_abs(p, u->faction, getint(), 0); - int y = rel_to_abs(p, u->faction, getint(), 1); - region *r = findregion(x, y); if (r == NULL || p != rplane(r)) { @@ -287,7 +255,6 @@ static void gm_teleport(const tnode * tnext, void *data, struct order *ord) } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmtele"))) { mistake(u, ord, "permission denied."); } else @@ -302,32 +269,24 @@ static void gm_teleport(const tnode * tnext, void *data, struct order *ord) static void gm_messageplane(const tnode * tnext, void *data, struct order *ord) { unit *gm = (unit *) data; - const struct plane *p = rplane(gm->region); - const char *zmsg = getstrtoken(); - if (p == NULL) { mistake(gm, ord, "In diese Ebene kann keine Nachricht gesandt werden."); } else { /* checking permissions */ attrib *permissions = a_find(gm->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { mistake(gm, ord, "permission denied."); } else { message *msg = msg_message("msg_event", "string", zmsg); - faction *f; - region *r; - for (f = factions; f; f = f->next) { freset(f, FFL_SELECT); } for (r = regions; r; r = r->next) { unit *u; - if (rplane(r) != p) continue; for (u = r->units; u; u = u->next) @@ -346,28 +305,20 @@ static void gm_messagefaction(const tnode * tnext, void *data, struct order *ord) { unit *gm = (unit *) data; - int n = getid(); - faction *f = findfaction(n); - const char *msg = getstrtoken(); - plane *p = rplane(gm->region); - attrib *permissions = a_find(gm->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { mistake(gm, ord, "permission denied."); return; } if (f != NULL) { region *r; - for (r = regions; r; r = r->next) if (rplane(r) == p) { unit *u; - for (u = r->units; u; u = u->next) if (u->faction == f) { add_message(&f->msgs, msg_message("msg_event", "string", msg)); @@ -385,15 +336,10 @@ gm_messagefaction(const tnode * tnext, void *data, struct order *ord) static void gm_messageregion(const tnode * tnext, void *data, struct order *ord) { unit *u = (unit *) data; - const struct plane *p = rplane(u->region); - int x = rel_to_abs(p, u->faction, getint(), 0); - int y = rel_to_abs(p, u->faction, getint(), 1); - const char *msg = getstrtoken(); - region *r = findregion(x, y); if (r == NULL || p != rplane(r)) { @@ -401,7 +347,6 @@ static void gm_messageregion(const tnode * tnext, void *data, struct order *ord) } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) { mistake(u, ord, "permission denied."); } else { @@ -417,13 +362,9 @@ static void gm_messageregion(const tnode * tnext, void *data, struct order *ord) static void gm_killunit(const tnode * tnext, void *data, struct order *ord) { unit *u = (unit *) data; - const struct plane *p = rplane(u->region); - unit *target = findunit(getid()); - const char *msg = getstrtoken(); - region *r = target->region; if (r == NULL || p != rplane(r)) { @@ -431,7 +372,6 @@ static void gm_killunit(const tnode * tnext, void *data, struct order *ord) } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmkill"))) { mistake(u, ord, "permission denied."); } else { @@ -442,7 +382,6 @@ static void gm_killunit(const tnode * tnext, void *data, struct order *ord) } } - /** ** GM: KILL FACTION ** requires: permission-key "gmmsgr" @@ -450,28 +389,20 @@ static void gm_killunit(const tnode * tnext, void *data, struct order *ord) static void gm_killfaction(const tnode * tnext, void *data, struct order *ord) { unit *u = (unit *) data; - int n = getid(); - faction *f = findfaction(n); - const char *msg = getstrtoken(); - plane *p = rplane(u->region); - attrib *permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmkill"))) { mistake(u, ord, "permission denied."); return; } if (f != NULL) { region *r; - for (r = regions; r; r = r->next) if (rplane(r) == p) { unit *target; - for (target = r->units; target; target = target->next) { if (target->faction == f) { scale_number(target, 0); @@ -492,13 +423,9 @@ static void gm_killfaction(const tnode * tnext, void *data, struct order *ord) static void gm_messageunit(const tnode * tnext, void *data, struct order *ord) { unit *u = (unit *) data; - const struct plane *p = rplane(u->region); - unit *target = findunit(getid()); - const char *msg = getstrtoken(); - region *r; if (target == NULL) { @@ -514,7 +441,6 @@ static void gm_messageunit(const tnode * tnext, void *data, struct order *ord) } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmmsgu"))) { mistake(u, ord, "permission denied."); } else { @@ -531,11 +457,8 @@ static void gm_messageunit(const tnode * tnext, void *data, struct order *ord) static void gm_give(const tnode * tnext, void *data, struct order *ord) { unit *u = (unit *) data; - unit *to = findunit(getid()); - int num = getint(); - const item_type *itype = finditemtype(getstrtoken(), u->faction->locale); if (to == NULL || rplane(to->region) != rplane(u->region)) { @@ -548,12 +471,10 @@ static void gm_give(const tnode * tnext, void *data, struct order *ord) } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmgive"))) { mistake(u, ord, "permission denied."); } else { int i = i_get(u->items, itype); - if (i < num) num = i; if (num) { @@ -571,11 +492,8 @@ static void gm_give(const tnode * tnext, void *data, struct order *ord) static void gm_take(const tnode * tnext, void *data, struct order *ord) { unit *u = (unit *) data; - unit *to = findunit(getid()); - int num = getint(); - const item_type *itype = finditemtype(getstrtoken(), u->faction->locale); if (to == NULL || rplane(to->region) != rplane(u->region)) { @@ -588,12 +506,10 @@ static void gm_take(const tnode * tnext, void *data, struct order *ord) } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmtake"))) { mistake(u, ord, "permission denied."); } else { int i = i_get(to->items, itype); - if (i < num) num = i; if (num) { @@ -611,11 +527,8 @@ static void gm_take(const tnode * tnext, void *data, struct order *ord) static void gm_skill(const tnode * tnext, void *data, struct order *ord) { unit *u = (unit *) data; - unit *to = findunit(getid()); - skill_t skill = findskill(getstrtoken(), u->faction->locale); - int num = getint(); if (to == NULL || rplane(to->region) != rplane(u->region)) { @@ -631,7 +544,6 @@ static void gm_skill(const tnode * tnext, void *data, struct order *ord) } else { /* checking permissions */ attrib *permissions = a_find(u->faction->attribs, &at_permissions); - if (!permissions || !has_permission(permissions, atoi36("gmskil"))) { mistake(u, ord, "permission denied."); } else { @@ -641,11 +553,8 @@ static void gm_skill(const tnode * tnext, void *data, struct order *ord) } static tnode g_keys; - static tnode g_root; - static tnode g_tell; - static tnode g_kill; void register_gmcmd(void) @@ -677,17 +586,12 @@ void register_gmcmd(void) void gmcommands(void) { region **rp = ®ions; - while (*rp) { region *r = *rp; - unit **up = &r->units; - while (*up) { unit *u = *up; - struct order *ord; - for (ord = u->orders; ord; ord = ord->next) { if (get_keyword(ord) == K_GM) { do_command(&g_root, u, ord); @@ -707,17 +611,11 @@ faction *gm_addquest(const char *email, const char *name, int radius, unsigned int flags) { plane *pl; - watcher *w = calloc(sizeof(watcher), 1); - region *center; - boolean invalid = false; - int minx, miny, maxx, maxy, cx, cy; - int x; - faction *f; /* GM playfield */ @@ -726,10 +624,8 @@ faction *gm_addquest(const char *email, const char *name, int radius, miny = ((rng_int() % (2 * EXTENSION)) - EXTENSION); for (x = 0; !invalid && x <= radius * 2; ++x) { int y; - for (y = 0; !invalid && y <= radius * 2; ++y) { region *r = findregion(minx + x, miny + y); - if (r) invalid = true; } @@ -743,10 +639,8 @@ faction *gm_addquest(const char *email, const char *name, int radius, center = new_region(cx, cy, pl, 0); for (x = 0; x <= 2 * radius; ++x) { int y; - for (y = 0; y <= 2 * radius; ++y) { region *r = findregion(minx + x, miny + y); - if (!r) { r = new_region(minx + x, miny + y, pl, 0); } @@ -774,9 +668,7 @@ faction *gm_addquest(const char *email, const char *name, int radius, faction *gm_addfaction(const char *email, plane * p, region * r) { attrib *a; - unit *u; - faction *f = calloc(1, sizeof(faction)); assert(p != NULL); @@ -800,9 +692,7 @@ faction *gm_addfaction(const char *email, plane * p, region * r) want(O_COMPRESS) | want(O_REPORT) | want(O_COMPUTER) | want(O_ADRESSEN); { faction *xist; - int id = atoi36("gm00") - 1; - do { xist = findfaction(++id); } while (xist); @@ -820,7 +710,6 @@ faction *gm_addfaction(const char *email, plane * p, region * r) { "gmterf", "gmtele", "gmgive", "gmskil", "gmtake", "gmmsgr", "gmmsgu", "gmgate", 0 }; const char **key_p = keys; - while (*key_p) { add_key(&ap, atoi36(*key_p)); ++key_p; @@ -840,13 +729,9 @@ faction *gm_addfaction(const char *email, plane * p, region * r) plane *gm_addplane(int radius, unsigned int flags, const char *name) { region *center; - plane *pl; - boolean invalid = false; - int minx, miny, maxx, maxy, cx, cy; - int x; /* GM playfield */ @@ -855,10 +740,8 @@ plane *gm_addplane(int radius, unsigned int flags, const char *name) miny = (rng_int() % (2 * EXTENSION)) - EXTENSION; for (x = 0; !invalid && x <= radius * 2; ++x) { int y; - for (y = 0; !invalid && y <= radius * 2; ++y) { region *r = findregion(minx + x, miny + y); - if (r) invalid = true; } @@ -872,10 +755,8 @@ plane *gm_addplane(int radius, unsigned int flags, const char *name) center = new_region(cx, cy, pl, 0); for (x = 0; x <= 2 * radius; ++x) { int y; - for (y = 0; y <= 2 * radius; ++y) { region *r = findregion(minx + x, miny + y); - if (!r) r = new_region(minx + x, miny + y, pl, 0); freset(r, RF_ENCOUNTER); diff --git a/src/modules/museum.c b/src/modules/museum.c index 9284ce0d1..ba9a28cfa 100644 --- a/src/modules/museum.c +++ b/src/modules/museum.c @@ -70,7 +70,6 @@ a_writemuseumgivebackcookie(const attrib * a, const void *owner, struct storage *store) { museumgivebackcookie *gbc = (museumgivebackcookie *) a->data.v; - store->w_int(store, gbc->warden_no); store->w_int(store, gbc->cookie); } @@ -79,7 +78,6 @@ static int a_readmuseumgivebackcookie(attrib * a, void *owner, struct storage *store) { museumgivebackcookie *gbc = (museumgivebackcookie *) a->data.v; - gbc->warden_no = store->r_int(store); gbc->cookie = store->r_int(store); return AT_READ_OK; @@ -106,7 +104,6 @@ static void a_initmuseumgiveback(attrib * a) static void a_finalizemuseumgiveback(attrib * a) { museumgiveback *gb = (museumgiveback *) a->data.v; - i_freeall(&gb->items); free(a->data.v); } @@ -116,7 +113,6 @@ a_writemuseumgiveback(const attrib * a, const void *owner, struct storage *store) { museumgiveback *gb = (museumgiveback *) a->data.v; - store->w_int(store, gb->cookie); write_items(store, gb->items); } @@ -124,7 +120,6 @@ a_writemuseumgiveback(const attrib * a, const void *owner, static int a_readmuseumgiveback(attrib * a, void *owner, struct storage *store) { museumgiveback *gb = (museumgiveback *) a->data.v; - gb->cookie = store->r_int(store); read_items(store, &gb->items); return AT_READ_OK; @@ -142,11 +137,8 @@ attrib_type at_museumgiveback = { void warden_add_give(unit * src, unit * u, const item_type * itype, int n) { attrib *aw = a_find(u->attribs, &at_warden); - museumgiveback *gb = NULL; - museumgivebackcookie *gbc; - attrib *a; /* has the giver a cookie corresponding to the warden */ @@ -199,15 +191,10 @@ void create_museum(void) { #if 0 /* TODO: move this to LUA. It should be possible. */ unsigned int museum_id = hashstring("museum"); - plane *museum = getplanebyid(museum_id); - region *r; - building *b; - const terrain_type *terrain_hall = get_terrain("hall1"); - const terrain_type *terrain_corridor = get_terrain("corridor1"); assert(terrain_corridor && terrain_hall); @@ -247,7 +234,6 @@ void create_museum(void) r = findregion(9526, 9525); if (!r->buildings) { const building_type *bt_generic = bt_find("generic"); - b = new_building(bt_generic, r, NULL); set_string(&b->name, "Séparée im dämonischen Stil"); set_string(&b->display, @@ -315,11 +301,8 @@ use_museumexitticket(unit * u, const struct item_type *itype, int amount, order * ord) { attrib *a; - region *r; - unit *warden = findunit(atoi36("mwar")); - int unit_cookie; unused(amount); @@ -350,7 +333,6 @@ use_museumexitticket(unit * u, const struct item_type *itype, int amount, } if (a && a->type == &at_museumgiveback) { museumgiveback *gb = (museumgiveback *) (a->data.v); - item *it; for (it = gb->items; it; it = it->next) { @@ -376,9 +358,7 @@ use_museumticket(unit * u, const struct item_type *itype, int amount, order * ord) { attrib *a; - region *r = u->region; - plane *pl = rplane(r); unused(amount); diff --git a/src/modules/score.c b/src/modules/score.c index 63d3029b1..40c4f8e29 100644 --- a/src/modules/score.c +++ b/src/modules/score.c @@ -44,7 +44,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. int average_score_of_age(int age, int a) { faction *f; - int sum = 0, count = 0; for (f = factions; f; f = f->next) { @@ -64,13 +63,9 @@ int average_score_of_age(int age, int a) void score(void) { FILE *scoreFP; - region *r; - faction *fc; - int allscores = 0; - char path[MAX_PATH]; for (fc = factions; fc; fc = fc->next) @@ -78,9 +73,7 @@ void score(void) for (r = regions; r; r = r->next) { unit *u; - building *b; - ship *s; if (rule_region_owners()) { @@ -102,7 +95,6 @@ void score(void) for (s = r->ships; s; s = s->next) { unit *cap = shipowner(s); - if (cap && cap->faction) { cap->faction->score += s->size * 2; } @@ -110,11 +102,8 @@ void score(void) for (u = r->units; u; u = u->next) { item *itm; - int itemscore = 0; - int i; - faction *f = u->faction; if (f == NULL || u->race == new_race[RC_SPELL] @@ -133,7 +122,6 @@ void score(void) for (i = 0; i != u->skill_size; ++i) { skill *sv = u->skills + i; - switch (sv->id) { case SK_MAGIC: f->score += (int)(u->number * pow(sv->level, 4)); @@ -169,7 +157,6 @@ void score(void) if (scoreFP) { const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; faction *f; - fwrite(utf8_bom, 1, 3, scoreFP); for (f = factions; f; f = f->next) if (f->num_total != 0) { @@ -184,7 +171,6 @@ void score(void) } if (alliances != NULL) { alliance *a; - const item_type *token = it_find("conquesttoken"); sprintf(path, "%s/score.alliances", basepath()); @@ -197,9 +183,7 @@ void score(void) for (a = alliances; a; a = a->next) { int alliance_score = 0, alliance_number = 0, alliance_factions = 0; - int grails = 0; - faction *f; for (f = factions; f; f = f->next) { @@ -209,10 +193,8 @@ void score(void) alliance_number += f->num_total; if (token != NULL) { unit *u = f->units; - while (u != NULL) { item **iitem = i_find(&u->items, token); - if (iitem != NULL && *iitem != NULL) { grails += (*iitem)->number; } diff --git a/src/modules/score.h b/src/modules/score.h index d63542aa3..1140e0568 100644 --- a/src/modules/score.h +++ b/src/modules/score.h @@ -26,7 +26,6 @@ extern "C" { #error "must define SCORE_MODULE to use this module" #endif - extern void score(void); extern int average_score_of_age(int age, int a); diff --git a/src/modules/weather.c b/src/modules/weather.c index 4c998c456..793e7da73 100644 --- a/src/modules/weather.c +++ b/src/modules/weather.c @@ -75,13 +75,9 @@ double distance(int x1, int y1, int x2, int y2) void set_weather(void) { weather_t i; - weather *w; - short x, y; - int d; - region *r; for (r = regions; r; r = r->next) { @@ -110,7 +106,6 @@ void set_weather(void) void move_weather(void) { weather *w, *wnext; - region *r; for (w = weathers; w;) { diff --git a/src/modules/wormhole.c b/src/modules/wormhole.c index 091a1388f..4553d46b9 100644 --- a/src/modules/wormhole.c +++ b/src/modules/wormhole.c @@ -45,9 +45,7 @@ static boolean good_region(const region * r) static int cmp_age(const void *v1, const void *v2) { const region *r1 = (const region *)v1; - const region *r2 = (const region *)v2; - if (r1->age < r2->age) return -1; if (r1->age > r2->age) @@ -73,17 +71,13 @@ static void wormhole_done(struct attrib *a) static int wormhole_age(struct attrib *a) { wormhole_data *data = (wormhole_data *) a->data.v; - int maxtransport = data->entry->size; - region *r = data->entry->region; - unit *u = r->units; for (; u != NULL && maxtransport != 0; u = u->next) { if (u->building == data->entry) { message *m = NULL; - if (u->number > maxtransport || has_limited_skills(u)) { m = msg_message("wormhole_requirements", "unit region", u, u->region); } else if (data->exit != NULL) { @@ -110,7 +104,6 @@ static void wormhole_write(const struct attrib *a, const void *owner, struct storage *store) { wormhole_data *data = (wormhole_data *) a->data.v; - write_building_reference(data->entry, store); write_region_reference(data->exit, store); } @@ -119,9 +112,7 @@ wormhole_write(const struct attrib *a, const void *owner, struct storage *store) static int resolve_exit(variant id, void *address) { building *b = findbuilding(id.i); - region **rp = address; - if (b) { *rp = b->region; return 0; @@ -133,7 +124,6 @@ static int resolve_exit(variant id, void *address) static int wormhole_read(struct attrib *a, void *owner, struct storage *store) { wormhole_data *data = (wormhole_data *) a->data.v; - resolve_fun resolver = (store->version < UIDHASH_VERSION) ? resolve_exit : resolve_region_id; read_fun reader = @@ -144,7 +134,6 @@ static int wormhole_read(struct attrib *a, void *owner, struct storage *store) read_reference(&data->entry, store, read_building_reference, resolve_building); int rr = read_reference(&data->exit, store, reader, resolver); - if (rb == 0 && rr == 0) { if (!data->exit || !data->entry) { return AT_READ_FAIL; @@ -167,17 +156,11 @@ static void make_wormhole(const building_type * bt_wormhole, region * r1, region * r2) { building *b1 = new_building(bt_wormhole, r1, default_locale); - building *b2 = new_building(bt_wormhole, r2, default_locale); - attrib *a1 = a_add(&b1->attribs, a_new(&at_wormhole)); - attrib *a2 = a_add(&b2->attribs, a_new(&at_wormhole)); - wormhole_data *d1 = (wormhole_data *) a1->data.v; - wormhole_data *d2 = (wormhole_data *) a2->data.v; - d1->entry = b1; d2->entry = b2; d1->exit = b2->region; @@ -192,13 +175,9 @@ void create_wormholes(void) { #define WORMHOLE_CHANCE 10000 const building_type *bt_wormhole = bt_find("wormhole"); - region_list *rptr, *rlist = NULL; - region *r = regions; - int i = 0, count = 0; - region **match; if (bt_wormhole == NULL) @@ -208,7 +187,6 @@ void create_wormholes(void) */ while (r != NULL) { int next = rng_int() % (2 * WORMHOLE_CHANCE); - while (r != NULL && (next != 0 || !good_region(r))) { if (good_region(r)) { --next; diff --git a/src/modules/xecmd.c b/src/modules/xecmd.c index c4166dade..939b882a5 100644 --- a/src/modules/xecmd.c +++ b/src/modules/xecmd.c @@ -67,7 +67,6 @@ static void xe_givepotion(unit * u, struct order *ord) static void xe_giveballon(unit * u, struct order *ord) { unit *u2 = getunitg(u->region, u->faction); - ship *sh; if (!u2) { diff --git a/src/modules/xmas.c b/src/modules/xmas.c index 5bf8c779c..9c44011b1 100644 --- a/src/modules/xmas.c +++ b/src/modules/xmas.c @@ -42,7 +42,6 @@ static int xmasgate_handle(trigger * t, void *data) static void xmasgate_write(const trigger * t, struct storage *store) { building *b = (building *) t->data.v; - store->w_tok(store, itoa36(b->no)); } @@ -69,7 +68,6 @@ struct trigger_type tt_xmasgate = { trigger *trigger_xmasgate(building * b) { trigger *t = t_new(&tt_xmasgate); - t->data.v = b; return t; } diff --git a/src/platform.h b/src/platform.h index 7d369273f..cdf87ea37 100644 --- a/src/platform.h +++ b/src/platform.h @@ -48,7 +48,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #endif /* _MSC_VER_ */ - #ifdef __cplusplus # include # include @@ -115,7 +114,6 @@ extern "C" { # define HAVE_ACCESS # define HAVE_STAT typedef struct stat stat_type; - # include # define HAVE_STRDUP # define HAVE_SNPRINTF @@ -141,7 +139,6 @@ typedef struct stat stat_type; # define HAVE_ACCESS # define HAVE_STAT typedef struct stat stat_type; - # define HAVE_STRICMP # define HAVE_STRNICMP # define HAVE_STRDUP diff --git a/src/tests.c b/src/tests.c index 0b338f20b..4f061e01a 100644 --- a/src/tests.c +++ b/src/tests.c @@ -8,9 +8,7 @@ #include CuSuite *get_curse_suite(void); - CuSuite *get_market_suite(void); - CuSuite *get_laws_suite(void); #include @@ -26,9 +24,7 @@ CuSuite *get_laws_suite(void); int RunAllTests(void) { CuString *output = CuStringNew(); - CuSuite *suite = CuSuiteNew(); - int flags = log_flags; log_flags = LOG_FLUSH | LOG_CPERROR; @@ -52,7 +48,6 @@ int RunAllTests(void) struct race *test_create_race(const char *name) { race *rc = rc_add(rc_new("human")); - return rc; } @@ -60,7 +55,6 @@ struct region *test_create_region(int x, int y, const struct terrain_type *terrain) { region *r = new_region(x, y, NULL, 0); - terraform_region(r, terrain); rsettrees(r, 0, 0); rsettrees(r, 1, 0); @@ -73,23 +67,19 @@ struct region *test_create_region(int x, int y, struct faction *test_create_faction(const struct race *rc) { faction *f = addfaction("nobody@eressea.de", NULL, rc, default_locale, 0); - return f; } struct unit *test_create_unit(struct faction *f, struct region *r) { unit *u = create_unit(r, f, 1, f->race, 0, 0, 0); - return u; } void test_cleanup(void) { global.functions.maintenance = NULL; - global.functions.wage = NULL; - free_gamedata(); } @@ -103,15 +93,10 @@ void test_cleanup(void) void test_create_world(void) { terrain_type *t_plain, *t_ocean; - region *island[2]; - race *rc_human; - int i; - building_type *btype; - ship_type *stype; t_plain = calloc(1, sizeof(terrain_type)); @@ -128,12 +113,9 @@ void test_create_world(void) island[1] = test_create_region(1, 0, t_plain); for (i = 0; i != 2; ++i) { direction_t j; - region *r = island[i]; - for (j = 0; j != MAXDIRECTIONS; ++j) { region *rn = r_connect(r, j); - if (!rn) { rn = test_create_region(r->x + delta_x[j], r->y + delta_y[j], t_ocean); } diff --git a/src/triggers/changefaction.c b/src/triggers/changefaction.c index db44e4b8a..a368bd567 100644 --- a/src/triggers/changefaction.c +++ b/src/triggers/changefaction.c @@ -38,7 +38,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include - #include /*** ** restore a mage that was turned into a toad @@ -65,7 +64,6 @@ static int changefaction_handle(trigger * t, void *data) * data.v -> ( variant event, int timer ) */ changefaction_data *td = (changefaction_data *) t->data.v; - if (td->unit && td->faction) { u_setfaction(td->unit, td->faction); } else { @@ -78,7 +76,6 @@ static int changefaction_handle(trigger * t, void *data) static void changefaction_write(const trigger * t, struct storage *store) { changefaction_data *td = (changefaction_data *) t->data.v; - write_unit_reference(td->unit, store); write_faction_reference(td->faction, store); } @@ -86,7 +83,6 @@ static void changefaction_write(const trigger * t, struct storage *store) static int changefaction_read(trigger * t, struct storage *store) { changefaction_data *td = (changefaction_data *) t->data.v; - read_reference(&td->unit, store, read_unit_reference, resolve_unit); read_reference(&td->faction, store, read_faction_reference, resolve_faction); return AT_READ_OK; @@ -104,9 +100,7 @@ trigger_type tt_changefaction = { trigger *trigger_changefaction(unit * u, struct faction * f) { trigger *t = t_new(&tt_changefaction); - changefaction_data *td = (changefaction_data *) t->data.v; - td->unit = u; td->faction = f; return t; diff --git a/src/triggers/changerace.c b/src/triggers/changerace.c index b94607761..b7bbd9859 100644 --- a/src/triggers/changerace.c +++ b/src/triggers/changerace.c @@ -37,7 +37,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include - #include /*** ** restore a mage that was turned into a toad @@ -65,7 +64,6 @@ static int changerace_handle(trigger * t, void *data) * data.v -> ( variant event, int timer ) */ changerace_data *td = (changerace_data *) t->data.v; - if (td->u) { if (td->race != NULL) td->u->race = td->race; @@ -81,7 +79,6 @@ static int changerace_handle(trigger * t, void *data) static void changerace_write(const trigger * t, struct storage *store) { changerace_data *td = (changerace_data *) t->data.v; - write_unit_reference(td->u, store); write_race_reference(td->race, store); write_race_reference(td->irace, store); @@ -90,7 +87,6 @@ static void changerace_write(const trigger * t, struct storage *store) static int changerace_read(trigger * t, struct storage *store) { changerace_data *td = (changerace_data *) t->data.v; - read_reference(&td->u, store, read_unit_reference, resolve_unit); td->race = (const struct race *)read_race_reference(store).v; td->irace = (const struct race *)read_race_reference(store).v; @@ -110,7 +106,6 @@ trigger *trigger_changerace(struct unit * u, const struct race * prace, const struct race * irace) { trigger *t = t_new(&tt_changerace); - changerace_data *td = (changerace_data *) t->data.v; assert(u->race == u_irace(u) || "!changerace-triggers cannot stack!"); diff --git a/src/triggers/clonedied.c b/src/triggers/clonedied.c index 1b3f3dc77..f861a54a2 100644 --- a/src/triggers/clonedied.c +++ b/src/triggers/clonedied.c @@ -49,10 +49,8 @@ static int clonedied_handle(trigger * t, void *data) { /* destroy the unit */ unit *u = (unit *) t->data.v; - if (u) { attrib *a = a_find(u->attribs, &at_clone); - if (a) a_remove(&u->attribs, a); } else @@ -64,7 +62,6 @@ static int clonedied_handle(trigger * t, void *data) static void clonedied_write(const trigger * t, struct storage *store) { unit *u = (unit *) t->data.v; - write_unit_reference(u, store); } @@ -90,7 +87,6 @@ trigger_type tt_clonedied = { trigger *trigger_clonedied(unit * u) { trigger *t = t_new(&tt_clonedied); - t->data.v = (void *)u; return t; } diff --git a/src/triggers/createcurse.c b/src/triggers/createcurse.c index d600d1d21..56e1d9d6f 100644 --- a/src/triggers/createcurse.c +++ b/src/triggers/createcurse.c @@ -38,7 +38,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include - #include /*** ** restore a mage that was turned into a toad @@ -70,7 +69,6 @@ static int createcurse_handle(trigger * t, void *data) * data.v -> ( variant event, int timer ) */ createcurse_data *td = (createcurse_data *) t->data.v; - if (td->mage && td->target && td->mage->number && td->target->number) { create_curse(td->mage, &td->target->attribs, td->type, td->vigour, td->duration, td->effect, td->men); @@ -84,7 +82,6 @@ static int createcurse_handle(trigger * t, void *data) static void createcurse_write(const trigger * t, struct storage *store) { createcurse_data *td = (createcurse_data *) t->data.v; - write_unit_reference(td->mage, store); write_unit_reference(td->target, store); store->w_tok(store, td->type->cname); @@ -97,7 +94,6 @@ static void createcurse_write(const trigger * t, struct storage *store) static int createcurse_read(trigger * t, struct storage *store) { createcurse_data *td = (createcurse_data *) t->data.v; - char zText[128]; read_reference(&td->mage, store, read_unit_reference, resolve_unit); @@ -105,7 +101,6 @@ static int createcurse_read(trigger * t, struct storage *store) if (store->version < CURSETYPE_VERSION) { int id1, id2; - id1 = store->r_int(store); id2 = store->r_int(store); assert(id2 == 0); @@ -142,9 +137,7 @@ 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); - createcurse_data *td = (createcurse_data *) t->data.v; - td->mage = mage; td->target = target; td->type = ct; diff --git a/src/triggers/createunit.c b/src/triggers/createunit.c index 4f83cd91e..9973b2385 100644 --- a/src/triggers/createunit.c +++ b/src/triggers/createunit.c @@ -40,7 +40,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include - #include /*** ** restore a mage that was turned into a toad @@ -69,7 +68,6 @@ static int createunit_handle(trigger * t, void *data) * data.v -> ( variant event, int timer ) */ createunit_data *td = (createunit_data *) t->data.v; - if (td->r != NULL && td->f != NULL) { create_unit(td->r, td->f, td->number, td->race, 0, NULL, NULL); } else { @@ -82,7 +80,6 @@ static int createunit_handle(trigger * t, void *data) static void createunit_write(const trigger * t, struct storage *store) { createunit_data *td = (createunit_data *) t->data.v; - write_faction_reference(td->f, store); write_region_reference(td->r, store); write_race_reference(td->race, store); @@ -122,9 +119,7 @@ trigger *trigger_createunit(region * r, struct faction * f, const struct race * rc, int number) { trigger *t = t_new(&tt_createunit); - createunit_data *td = (createunit_data *) t->data.v; - td->r = r; td->f = f; td->race = rc; diff --git a/src/triggers/gate.c b/src/triggers/gate.c index ae542a72b..20be3ae4c 100644 --- a/src/triggers/gate.c +++ b/src/triggers/gate.c @@ -40,17 +40,13 @@ static int gate_handle(trigger * t, void *data) * data.v -> ( variant event, int timer ) */ gate_data *gd = (gate_data *) t->data.v; - struct building *b = gd->gate; - struct region *r = gd->target; if (b && b->region && r) { unit **up = &b->region->units; - while (*up) { unit *u = *up; - if (u->building == b) move_unit(u, r, NULL); if (*up == u) @@ -67,9 +63,7 @@ static int gate_handle(trigger * t, void *data) static void gate_write(const trigger * t, struct storage *store) { gate_data *gd = (gate_data *) t->data.v; - building *b = gd->gate; - region *r = gd->target; write_building_reference(b, store); @@ -103,7 +97,6 @@ static void gate_done(trigger * t) free(t->data.v); } - struct trigger_type tt_gate = { "gate", gate_init, @@ -116,9 +109,7 @@ struct trigger_type tt_gate = { trigger *trigger_gate(building * b, region * target) { trigger *t = t_new(&tt_gate); - gate_data *td = (gate_data *) t->data.v; - td->gate = b; td->target = target; return t; diff --git a/src/triggers/giveitem.c b/src/triggers/giveitem.c index 1ccf1b5a3..2aaf9b6b9 100644 --- a/src/triggers/giveitem.c +++ b/src/triggers/giveitem.c @@ -63,7 +63,6 @@ static int giveitem_handle(trigger * t, void *data) * data.v -> ( variant event, int timer ) */ giveitem_data *td = (giveitem_data *) t->data.v; - if (td->u && td->u->number) { i_change(&td->u->items, td->itype, td->number); } else { @@ -76,7 +75,6 @@ static int giveitem_handle(trigger * t, void *data) static void giveitem_write(const trigger * t, struct storage *store) { giveitem_data *td = (giveitem_data *) t->data.v; - write_unit_reference(td->u, store); store->w_int(store, td->number); store->w_tok(store, td->itype->rtype->_name[0]); @@ -85,7 +83,6 @@ static void giveitem_write(const trigger * t, struct storage *store) static int giveitem_read(trigger * t, struct storage *store) { giveitem_data *td = (giveitem_data *) t->data.v; - char zText[128]; int result = read_reference(&td->u, store, read_unit_reference, resolve_unit); @@ -113,9 +110,7 @@ trigger_type tt_giveitem = { trigger *trigger_giveitem(unit * u, const item_type * itype, int number) { trigger *t = t_new(&tt_giveitem); - giveitem_data *td = (giveitem_data *) t->data.v; - td->number = number; td->u = u; td->itype = itype; diff --git a/src/triggers/killunit.c b/src/triggers/killunit.c index fc7c341a3..aa24982de 100644 --- a/src/triggers/killunit.c +++ b/src/triggers/killunit.c @@ -43,7 +43,6 @@ static int killunit_handle(trigger * t, void *data) * data.v -> ( variant event, int timer ) */ unit *u = (unit *) t->data.v; - if (u) { /* we can't remove_unit() here, because that's what's calling us. */ set_number(u, 0); @@ -55,7 +54,6 @@ static int killunit_handle(trigger * t, void *data) static void killunit_write(const trigger * t, struct storage *store) { unit *u = (unit *) t->data.v; - write_unit_reference(u, store); } @@ -81,7 +79,6 @@ trigger_type tt_killunit = { trigger *trigger_killunit(unit * u) { trigger *t = t_new(&tt_killunit); - t->data.v = (void *)u; return t; } diff --git a/src/triggers/removecurse.c b/src/triggers/removecurse.c index 4bb2c3426..aa084ad61 100644 --- a/src/triggers/removecurse.c +++ b/src/triggers/removecurse.c @@ -37,7 +37,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include - #include typedef struct removecurse_data { @@ -61,10 +60,8 @@ static int removecurse_handle(trigger * t, void *data) * data.v -> ( variant event, int timer ) */ removecurse_data *td = (removecurse_data *) t->data.v; - if (td->curse && td->target) { attrib *a = a_select(td->target->attribs, td->curse, cmp_curse); - if (a) { a_remove(&td->target->attribs, a); } else @@ -77,7 +74,6 @@ static int removecurse_handle(trigger * t, void *data) static void removecurse_write(const trigger * t, struct storage *store) { removecurse_data *td = (removecurse_data *) t->data.v; - store->w_tok(store, td->target ? itoa36(td->target->no) : 0); store->w_int(store, td->curse ? td->curse->no : 0); } @@ -104,9 +100,7 @@ trigger_type tt_removecurse = { trigger *trigger_removecurse(curse * c, unit * target) { trigger *t = t_new(&tt_removecurse); - removecurse_data *td = (removecurse_data *) t->data.v; - td->curse = c; td->target = target; return t; diff --git a/src/triggers/shock.c b/src/triggers/shock.c index bb5a7b578..3b6b4a885 100644 --- a/src/triggers/shock.c +++ b/src/triggers/shock.c @@ -71,11 +71,8 @@ static void do_shock(unit * u, const char *reason) for (i = 0; i != u->skill_size; ++i) if (rng_int() % 5 == 0) { skill *sv = u->skills + i; - int weeks = (sv->level * sv->level - sv->level) / 2; - int change = (weeks + 9) / 10; - reduce_skill(u, sv, change); } @@ -96,7 +93,6 @@ static int shock_handle(trigger * t, void *data) { /* destroy the unit */ unit *u = (unit *) t->data.v; - if (u && u->number) { do_shock(u, "trigger"); } @@ -107,9 +103,7 @@ static int shock_handle(trigger * t, void *data) static void shock_write(const trigger * t, struct storage *store) { unit *u = (unit *) t->data.v; - trigger *next = t->next; - while (next) { /* make sure it is unique! */ if (next->type == t->type && next->data.v == t->data.v) @@ -147,7 +141,6 @@ trigger_type tt_shock = { trigger *trigger_shock(unit * u) { trigger *t = t_new(&tt_shock); - t->data.v = (void *)u; return t; } diff --git a/src/triggers/timeout.c b/src/triggers/timeout.c index e764b6002..44226099d 100644 --- a/src/triggers/timeout.c +++ b/src/triggers/timeout.c @@ -46,7 +46,6 @@ static void timeout_init(trigger * t) static void timeout_free(trigger * t) { timeout_data *td = (timeout_data *) t->data.v; - free_triggers(td->triggers); free(t->data.v); } @@ -57,7 +56,6 @@ static int timeout_handle(trigger * t, void *data) * data.v -> ( variant event, int timer ) */ timeout_data *td = (timeout_data *) t->data.v; - if (--td->timer == 0) { handle_triggers(&td->triggers, NULL); return -1; @@ -69,7 +67,6 @@ static int timeout_handle(trigger * t, void *data) static void timeout_write(const trigger * t, struct storage *store) { timeout_data *td = (timeout_data *) t->data.v; - store->w_int(store, td->timer); write_triggers(store, td->triggers); } @@ -77,12 +74,10 @@ static void timeout_write(const trigger * t, struct storage *store) static int timeout_read(trigger * t, struct storage *store) { timeout_data *td = (timeout_data *) t->data.v; - td->timer = store->r_int(store); read_triggers(store, &td->triggers); if (td->timer > 20) { trigger *tr = td->triggers; - log_warning(("there is a timeout lasting for another %d turns\n", td->timer)); while (tr) { @@ -107,9 +102,7 @@ trigger_type tt_timeout = { trigger *trigger_timeout(int time, trigger * callbacks) { trigger *t = t_new(&tt_timeout); - timeout_data *td = (timeout_data *) t->data.v; - td->triggers = callbacks; td->timer = time; return t; diff --git a/src/triggers/unguard.c b/src/triggers/unguard.c index 50b6e4ac3..2ff3302cf 100644 --- a/src/triggers/unguard.c +++ b/src/triggers/unguard.c @@ -70,7 +70,6 @@ struct trigger_type tt_unguard = { trigger *trigger_unguard(building * b) { trigger *t = t_new(&tt_unguard); - t->data.v = (void *)b; return t; } diff --git a/src/triggers/unitmessage.c b/src/triggers/unitmessage.c index 87add8101..4fa83dff0 100644 --- a/src/triggers/unitmessage.c +++ b/src/triggers/unitmessage.c @@ -51,7 +51,6 @@ static void unitmessage_init(trigger * t) static void unitmessage_free(trigger * t) { unitmessage_data *sd = (unitmessage_data *) t->data.v; - free(sd->string); free(t->data.v); } @@ -62,10 +61,8 @@ static int unitmessage_handle(trigger * t, void *data) * data.v -> ( variant event, int timer ) */ unitmessage_data *td = (unitmessage_data *) t->data.v; - if (td->target && td->target->no) { struct faction *f = td->target->faction; - addmessage(td->target->region, f, LOC(f->locale, td->string), td->type, td->level); } @@ -76,7 +73,6 @@ static int unitmessage_handle(trigger * t, void *data) static void unitmessage_write(const trigger * t, struct storage *store) { unitmessage_data *td = (unitmessage_data *) t->data.v; - write_unit_reference(td->target, store); store->w_tok(store, td->string); store->w_int(store, td->type); @@ -86,7 +82,6 @@ static void unitmessage_write(const trigger * t, struct storage *store) static int unitmessage_read(trigger * t, struct storage *store) { unitmessage_data *td = (unitmessage_data *) t->data.v; - char zText[256]; int result = @@ -116,9 +111,7 @@ trigger *trigger_unitmessage(unit * target, const char *string, int type, int level) { trigger *t = t_new(&tt_unitmessage); - unitmessage_data *td = (unitmessage_data *) t->data.v; - td->target = target; td->string = strdup(string); td->type = type; diff --git a/src/util/attrib.c b/src/util/attrib.c index f8be18964..9c04c80d6 100644 --- a/src/util/attrib.c +++ b/src/util/attrib.c @@ -32,7 +32,6 @@ attrib_type *at_hash[MAXATHASH]; static unsigned int __at_hashkey(const char *s) { int key = 0; - size_t i = strlen(s); while (i > 0) { @@ -70,12 +69,10 @@ static attrib_type *at_find(unsigned int hk) {NULL, NULL} }; attrib_type *find = at_hash[hk % MAXATHASH]; - while (find && hk != find->hashkey) find = find->nexthash; if (!find) { int i = 0; - while (translate[i][0]) { if (__at_hashkey(translate[i][0]) == hk) return at_find(__at_hashkey(translate[i][1])); @@ -124,7 +121,6 @@ static attrib *a_insert(attrib * head, attrib * a) attrib *a_add(attrib ** pa, attrib * a) { attrib *first = *pa; - assert(a->next == NULL && a->nexttype == NULL); if (first == NULL) @@ -134,11 +130,9 @@ attrib *a_add(attrib ** pa, attrib * a) } for (;;) { attrib *next = first->nexttype; - if (next == NULL) { /* the type is not in the list, append it behind the last type */ attrib **insert = &first->next; - first->nexttype = a; while (*insert) insert = &(*insert)->next; @@ -156,7 +150,6 @@ attrib *a_add(attrib ** pa, attrib * a) void a_free(attrib * a) { const attrib_type *at = a->type; - if (at->finalize) at->finalize(a); free(a); @@ -165,13 +158,11 @@ void a_free(attrib * a) static int a_unlink(attrib ** pa, attrib * a) { attrib **pnexttype = pa; - attrib **pnext = NULL; assert(a != NULL); while (*pnexttype) { attrib *next = *pnexttype; - if (next->type == a->type) break; pnexttype = &next->nexttype; @@ -204,7 +195,6 @@ static int a_unlink(attrib ** pa, attrib * a) int a_remove(attrib ** pa, attrib * a) { int ok; - assert(a != NULL); ok = a_unlink(pa, a); if (ok) @@ -215,12 +205,10 @@ int a_remove(attrib ** pa, attrib * a) void a_removeall(attrib ** pa, const attrib_type * at) { attrib **pnexttype = pa; - attrib **pnext = NULL; while (*pnexttype) { attrib *next = *pnexttype; - if (next->type == at) break; pnexttype = &next->nexttype; @@ -237,7 +225,6 @@ void a_removeall(attrib ** pa, const attrib_type * at) } while (a && a->type == at) { attrib *ra = a; - a = a->next; a_free(ra); } @@ -247,7 +234,6 @@ void a_removeall(attrib ** pa, const attrib_type * at) attrib *a_new(const attrib_type * at) { attrib *a = (attrib *) calloc(1, sizeof(attrib)); - assert(at != NULL); a->type = at; if (at->initialize) @@ -258,15 +244,12 @@ attrib *a_new(const attrib_type * at) int a_age(attrib ** p) { attrib **ap = p; - /* Attribute altern, und die Entfernung (age()==0) eines Attributs * hat Einfluß auf den Besitzer */ while (*ap) { attrib *a = *ap; - if (a->type->age) { int result = a->type->age(a); - assert(result >= 0 || !"age() returned a negative value"); if (result == 0) { a_remove(p, a); @@ -281,9 +264,7 @@ int a_age(attrib ** p) int a_read(struct storage *store, attrib ** attribs, void *owner) { int key, retval = AT_READ_OK; - char zText[128]; - strcpy(zText, "unknown"); key = -1; @@ -295,16 +276,13 @@ int a_read(struct storage *store, attrib ** attribs, void *owner) while (key != -1) { attrib_type *at = at_find(key); - if (!at) { fprintf(stderr, "attribute hash: %d (%s)\n", key, zText); assert(at || !"attribute not registered"); } if (at->read) { attrib *na = a_new(at); - int i = at->read(na, owner, store); - switch (i) { case AT_READ_OK: a_add(attribs, na); diff --git a/src/util/base36.c b/src/util/base36.c index 2f5bffebd..0ae284bc2 100644 --- a/src/util/base36.c +++ b/src/util/base36.c @@ -27,9 +27,7 @@ int atoi36(const char *str) { /* cannot use strtol, because invalid strings will cause crash */ const unsigned char *s = (const unsigned char *)str; - int i = 0, sign = 1; - assert(s); if (!(*s)) return 0; @@ -59,18 +57,13 @@ int atoi36(const char *str) const char *itoab(int i, int base) { static char **as = NULL; /* STATIC_RETURN: used for return, not across calls */ - char *s, *dst; - static int index = 0; /* STATIC_XCALL: used across calls */ - int neg = 0; if (!as) { int j; - char *x = (char *)calloc(sizeof(char), 8 * 4); /* STATIC_LEAK: malloc in static variable */ - as = (char **)calloc(sizeof(char *), 4); for (j = 0; j != 4; ++j) as[j] = x + j * 8; @@ -86,7 +79,6 @@ const char *itoab(int i, int base) } while (i) { int x = i % base; - i = i / base; if (x < 10) *(dst--) = (char)('0' + x); @@ -118,7 +110,6 @@ const char *itoa10(int i) int i10toi36(int i) { int r = 0; - while (i) { r = r * 36 + i % 10; i = i / 10; diff --git a/src/util/base36_test.c b/src/util/base36_test.c index 6fd019334..25313cfe4 100644 --- a/src/util/base36_test.c +++ b/src/util/base36_test.c @@ -26,7 +26,6 @@ static void test_itoa36(CuTest * tc) CuSuite *get_base36_suite(void) { CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, test_itoa36); SUITE_ADD_TEST(suite, test_atoi36); return suite; diff --git a/src/util/bsdstring.c b/src/util/bsdstring.c index 9fa8d8bce..a2467229f 100644 --- a/src/util/bsdstring.c +++ b/src/util/bsdstring.c @@ -33,9 +33,7 @@ INLINE_FUNCTION int wrptr(char **ptr, size_t * size, int bytes) INLINE_FUNCTION size_t strlcpy(char *dst, const char *src, size_t siz) { /* copied from OpenBSD source code */ register char *d = dst; - register const char *s = src; - register size_t n = siz; /* Copy as many bytes as will fit */ @@ -56,15 +54,11 @@ INLINE_FUNCTION size_t strlcpy(char *dst, const char *src, size_t siz) return (s - src - 1); /* count does not include NUL */ } - INLINE_FUNCTION size_t strlcat(char *dst, const char *src, size_t siz) { register char *d = dst; - register const char *s = src; - register size_t n = siz; - size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ diff --git a/src/util/bsdstring.h b/src/util/bsdstring.h index a7c77a6c7..0ed276b61 100644 --- a/src/util/bsdstring.h +++ b/src/util/bsdstring.h @@ -5,9 +5,7 @@ # include "bsdstring.c" #else extern size_t strlcpy(char *dst, const char *src, size_t siz); - extern size_t strlcat(char *dst, const char *src, size_t siz); - extern int wrptr(char **ptr, size_t * size, int bytes); #endif diff --git a/src/util/console.c b/src/util/console.c index 6ffbb7c7f..28586f704 100644 --- a/src/util/console.c +++ b/src/util/console.c @@ -67,7 +67,6 @@ void set_readline(readline foo) /* BAD hack, all this action stuff. */ #define STATESTACK_MAX 16 static lua_State *state_stack[STATESTACK_MAX]; - int state_stack_top = -1; static const char *progname = "eressea"; @@ -100,7 +99,6 @@ static int report(lua_State * L, int status) { if (status && !lua_isnil(L, -1)) { const char *msg = lua_tostring(L, -1); - if (msg == NULL) msg = "(error object is not a string)"; l_message(progname, msg); @@ -130,9 +128,7 @@ static int traceback(lua_State * L) static int docall(lua_State * L, int narg, int clear) { int status, pop_state = state_stack_top; - int base = lua_gettop(L) - narg; /* function index */ - lua_pushcfunction(L, traceback); /* push traceback function */ lua_insert(L, base); /* put it under chunk and args */ if (state_stack_top < 0 || L != state_stack[state_stack_top]) { @@ -153,7 +149,6 @@ static int docall(lua_State * L, int narg, int clear) static const char *get_prompt(lua_State * L, int firstline) { const char *p = NULL; - lua_pushstring(L, firstline ? "_PROMPT" : "_PROMPT2"); lua_rawget(L, LUA_GLOBALSINDEX); p = lua_tostring(L, -1); @@ -174,17 +169,12 @@ static int incomplete(lua_State * L, int status) return 1; } - static int pushline(lua_State * L, int firstline) { char buffer[LUA_MAXINPUT]; - char *b = buffer; - size_t l; - const char *prmt = get_prompt(L, firstline); - if (lua_readline(L, b, prmt) == 0) return 0; /* no input */ l = strlen(b); @@ -198,11 +188,9 @@ static int pushline(lua_State * L, int firstline) return 1; } - static int loadline(lua_State * L) { int status; - lua_settop(L, 0); if (!pushline(L, 1)) return -1; /* no input */ @@ -224,9 +212,7 @@ static int loadline(lua_State * L) static void dotty(lua_State * L) { int status; - const char *oldprogname = progname; - progname = NULL; while ((status = loadline(L)) != -1) { if (status == 0) @@ -255,7 +241,6 @@ int lua_console(lua_State * L) int lua_do(lua_State * L) { int status = loadline(L); - if (status != -1) { if (status == 0) status = docall(L, 0, 0); diff --git a/src/util/crmessage.c b/src/util/crmessage.c index 6cceb9fa9..886931c4c 100644 --- a/src/util/crmessage.c +++ b/src/util/crmessage.c @@ -36,7 +36,6 @@ static tostring_f tsf_find(const char *name) { if (name != NULL) { tsf_list *tsf; - for (tsf = tostringfs; tsf; tsf = tsf->next) { if (!strcmp(tsf->name, name)) return tsf->fun; @@ -48,7 +47,6 @@ static tostring_f tsf_find(const char *name) void tsf_register(const char *name, tostring_f fun) { tsf_list *tsf; - for (tsf = tostringfs; tsf; tsf = tsf->next) { if (!strcmp(tsf->name, name)) break; @@ -75,11 +73,8 @@ static crmessage_type *crtypes[CRMAXHASH]; static crmessage_type *crt_find(const struct message_type *mtype) { unsigned int hash = hashstring(mtype->name) % CRMAXHASH; - crmessage_type *found = NULL; - crmessage_type *type = crtypes[hash]; - while (type) { if (type->mtype == mtype) found = type; @@ -91,15 +86,12 @@ static crmessage_type *crt_find(const struct message_type *mtype) void crt_register(const struct message_type *mtype) { unsigned int hash = hashstring(mtype->name) % CRMAXHASH; - crmessage_type *crt = crtypes[hash]; - while (crt && crt->mtype != mtype) { crt = crt->next; } if (!crt) { int i; - crt = malloc(sizeof(crmessage_type)); crt->mtype = mtype; crt->next = crtypes[hash]; @@ -120,9 +112,7 @@ void crt_register(const struct message_type *mtype) int cr_render(const message * msg, char *buffer, const void *userdata) { int i; - char *c = buffer; - struct crmessage_type *crt = crt_find(msg->type); if (crt == NULL) diff --git a/src/util/dice.c b/src/util/dice.c index 213b96a2a..6549c33a8 100644 --- a/src/util/dice.c +++ b/src/util/dice.c @@ -45,9 +45,7 @@ int dice(int count, int value) static int term_eval(const char **sptr) { const char *c = *sptr; - int m = 0, d = 0, k = 0, term = 1, multi = 1; - int state = 1; for (;;) { @@ -59,7 +57,6 @@ static int term_eval(const char **sptr) m += k * multi; else if (state == 2) { /* dDk */ int i; - if (k == 0) k = 6; /* 3d == 3d6 */ for (i = 0; i != d; ++i) diff --git a/src/util/event.c b/src/util/event.c index 1701e8c7a..10df24c8c 100644 --- a/src/util/event.c +++ b/src/util/event.c @@ -46,7 +46,6 @@ int read_triggers(struct storage *store, trigger ** tp) { for (;;) { trigger_type *ttype; - char zText[128]; store->r_tok_buf(store, zText, sizeof(zText)); @@ -57,7 +56,6 @@ int read_triggers(struct storage *store, trigger ** tp) *tp = t_new(ttype); if (ttype->read) { int i = ttype->read(*tp, store); - switch (i) { case AT_READ_OK: tp = &(*tp)->next; @@ -78,7 +76,6 @@ int read_triggers(struct storage *store, trigger ** tp) trigger *t_new(trigger_type * ttype) { trigger *t = calloc(sizeof(trigger), 1); - t->type = ttype; if (ttype->initialize) ttype->initialize(t); @@ -95,7 +92,6 @@ void free_triggers(trigger * triggers) { while (triggers) { trigger *t = triggers; - triggers = t->next; t_free(t); } @@ -104,10 +100,8 @@ void free_triggers(trigger * triggers) int handle_triggers(trigger ** triggers, void *param) { trigger **tp = triggers; - while (*tp) { trigger *t = *tp; - if (t->type->handle(t, param) != 0) { *tp = t->next; t_free(t); @@ -134,7 +128,6 @@ static void init_handler(attrib * a) static void free_handler(attrib * a) { handler_info *hi = (handler_info *) a->data.v; - free_triggers(hi->triggers); free(hi->event); free(hi); @@ -144,7 +137,6 @@ static void write_handler(const attrib * a, const void *owner, struct storage *store) { handler_info *hi = (handler_info *) a->data.v; - store->w_tok(store, hi->event); write_triggers(store, hi->triggers); } @@ -152,7 +144,6 @@ write_handler(const attrib * a, const void *owner, struct storage *store) static int read_handler(attrib * a, void *owner, struct storage *store) { char zText[128]; - handler_info *hi = (handler_info *) a->data.v; store->r_tok_buf(store, zText, sizeof(zText)); @@ -176,9 +167,7 @@ attrib_type at_eventhandler = { struct trigger **get_triggers(struct attrib *ap, const char *eventname) { handler_info *td = NULL; - attrib *a = a_find(ap, &at_eventhandler); - while (a != NULL && a->type == &at_eventhandler) { td = (handler_info *) a->data.v; if (strcmp(td->event, eventname) == 0) { @@ -192,11 +181,8 @@ struct trigger **get_triggers(struct attrib *ap, const char *eventname) void add_trigger(struct attrib **ap, const char *eventname, struct trigger *t) { trigger **tp; - handler_info *td = NULL; - attrib *a = a_find(*ap, &at_eventhandler); - assert(t->next == NULL); while (a != NULL && a->type == &at_eventhandler) { td = (handler_info *) a->data.v; @@ -225,10 +211,8 @@ void handle_event(attrib * attribs, const char *eventname, void *data) } while (attribs && attribs->type == &at_eventhandler) { handler_info *tl = (handler_info *) attribs->data.v; - if (!strcmp(tl->event, eventname)) { handler_info *tl = (handler_info *) attribs->data.v; - handle_triggers(&tl->triggers, data); break; } @@ -254,7 +238,6 @@ void tt_register(trigger_type * tt) trigger_type *tt_find(const char *name) { trigger_type *tt = triggertypes; - while (tt && strcmp(tt->name, name)) tt = tt->next; return tt; @@ -265,13 +248,11 @@ remove_triggers(struct attrib **ap, const char *eventname, const trigger_type * tt) { trigger **tp = get_triggers(*ap, eventname); - if (tp == NULL) return; while (*tp) { /* first, remove all gate-triggers */ trigger *t = *tp; - if (t->type == tt) { *tp = t->next; t_free(t); diff --git a/src/util/eventbus.c b/src/util/eventbus.c index a9f937748..d4c7829fd 100644 --- a/src/util/eventbus.c +++ b/src/util/eventbus.c @@ -20,10 +20,8 @@ static listener *listeners; void eventbus_fire(void *sender, const char *event, void *args) { listener *lst = listeners; - while (lst) { int i = strcmp(lst->event, event); - if (i > 0) break; if (i == 0) { @@ -40,9 +38,7 @@ eventbus_register(void *sender, const char *event, event_handler cb, event_arg_free arg_free, void *args) { listener *lst; - listener **lstp = &listeners; - while (*lstp) { lst = *lstp; if (strcmp(lst->event, event) >= 0) { diff --git a/src/util/eventbus.h b/src/util/eventbus.h index 3667069d9..6bd266e51 100644 --- a/src/util/eventbus.h +++ b/src/util/eventbus.h @@ -13,7 +13,6 @@ #ifndef H_UTIL_EVTBUS #define H_UTIL_EVTBUS - #ifdef __cplusplus extern "C" { #endif diff --git a/src/util/filereader.c b/src/util/filereader.c index 02f850f7f..a70457b70 100644 --- a/src/util/filereader.c +++ b/src/util/filereader.c @@ -13,7 +13,6 @@ #define CONTINUE_CHAR '\\' #define MAXLINE 4096*16 static char lbuf[MAXLINE]; - static char fbuf[MAXLINE]; static void unicode_warning(const char *bp) @@ -29,9 +28,7 @@ INLINE_FUNCTION int eatwhite(const char *ptr, size_t * total_size) while (*ptr) { ucs4_t ucs; - size_t size = 0; - ret = unicode_utf8_to_ucs4(&ucs, ptr, &size); if (ret != 0) break; @@ -46,13 +43,9 @@ INLINE_FUNCTION int eatwhite(const char *ptr, size_t * total_size) static const char *getbuf_latin1(FILE * F) { boolean cont = false; - char quote = 0; - boolean comment = false; - char *cp = fbuf; - char *tail = lbuf + MAXLINE - 2; tail[1] = '@'; /* if this gets overwritten by fgets then the line was very long. */ @@ -139,7 +132,6 @@ static const char *getbuf_latin1(FILE * F) continue; } else if (c == CONTINUE_CHAR) { const char *end = ++bp; - while (*end && isxspace(*(unsigned char *)end)) ++end; /* eatwhite */ if (*end == '\0') { @@ -162,13 +154,9 @@ static const char *getbuf_latin1(FILE * F) } } else { char inbuf = (char)c; - size_t inbytes = 1; - size_t outbytes = MAXLINE - (cp - fbuf); - int ret = unicode_latin1_to_utf8(cp, &outbytes, &inbuf, &inbytes); - if (ret > 0) cp += ret; else { @@ -191,21 +179,15 @@ static const char *getbuf_latin1(FILE * F) static const char *getbuf_utf8(FILE * F) { boolean cont = false; - char quote = 0; - boolean comment = false; - char *cp = fbuf; - char *tail = lbuf + MAXLINE - 2; tail[1] = '@'; /* if this gets overwritten by fgets then the line was very long. */ do { const char *bp = fgets(lbuf, MAXLINE, F); - size_t white; - if (bp == NULL) { return NULL; } @@ -241,9 +223,7 @@ static const char *getbuf_utf8(FILE * F) cont = false; while (*bp && cp < fbuf + MAXLINE) { ucs4_t ucs; - size_t size; - int ret; if (!quote) { @@ -310,7 +290,6 @@ static const char *getbuf_utf8(FILE * F) } else { if (*bp == CONTINUE_CHAR) { const char *end; - eatwhite(bp + 1, &white); end = bp + 1 + white; if (*end == '\0') { diff --git a/src/util/functions.c b/src/util/functions.c index e270a6df2..be5e069c1 100644 --- a/src/util/functions.c +++ b/src/util/functions.c @@ -23,8 +23,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include - - typedef struct function_list { struct function_list *next; pf_generic fun; @@ -36,7 +34,6 @@ static function_list *functionlist; pf_generic get_function(const char *name) { function_list *fl = functionlist; - if (name == NULL) return NULL; while (fl && strcmp(fl->name, name) != 0) @@ -49,7 +46,6 @@ pf_generic get_function(const char *name) const char *get_functionname(pf_generic fun) { function_list *fl = functionlist; - while (fl && fl->fun != fun) fl = fl->next; if (fl) @@ -60,7 +56,6 @@ const char *get_functionname(pf_generic fun) void register_function(pf_generic fun, const char *name) { function_list *fl = (function_list *) malloc(sizeof(function_list)); - fl->next = functionlist; fl->fun = fun; fl->name = strdup(name); diff --git a/src/util/goodies.c b/src/util/goodies.c index 2d99ec4d2..a4c02a32b 100644 --- a/src/util/goodies.c +++ b/src/util/goodies.c @@ -68,13 +68,10 @@ char *set_string(char **s, const char *neu) return *s; } - static int spc_email_isvalid(const char *address) { int count = 0; - const char *c, *domain; - static const char *rfc822_specials = "()<>@,;:\\\"[]"; /* STATIC_CONST: contains a constant value */ /* first we validate the name portion (name@domain) */ diff --git a/src/util/graph.c b/src/util/graph.c index bced4ee05..ec234aebf 100644 --- a/src/util/graph.c +++ b/src/util/graph.c @@ -45,7 +45,6 @@ void graph_remove_node(graph * g, node * n) for (i = 0; i != g->edges.size; ++i) { edge *v = g->edges.data[i]; - if (v->node1 == n || v->node2 == n) { vset_erase(&g->nodes, v); i--; @@ -60,7 +59,6 @@ node *graph_find_node(graph * g, void *object) for (i = 0; i != g->nodes.size; ++i) { node *node = g->nodes.data[i]; - if (node->object == object) { return g->nodes.data[i]; } @@ -74,13 +72,10 @@ node *graph_find_node(graph * g, void *object) vset *graph_neighbours(graph * g, node * n) { unsigned int i; - vset *vs = malloc(sizeof(vs)); - vset_init(vs); for (i = 0; i != g->edges.size; ++i) { edge *v = g->edges.data[i]; - if (v->node1 == n && vset_count(vs, v->node2) == 0) { vset_add(vs, v->node2); } else if (v->node2 == n && vset_count(vs, v->node1) == 0) { @@ -97,12 +92,10 @@ void graph_resetmarkers(graph * g) for (i = 0; i != g->nodes.size; ++i) { node *node = g->nodes.data[i]; - node->marker = 0; } for (i = 0; i != g->edges.size; ++i) { edge *edge = g->edges.data[i]; - edge->marker = 0; } } @@ -113,7 +106,6 @@ void graph_resetmarkers(graph * g) vset *graph_connected_nodes(graph * g, node * n) { vset *vs = malloc(sizeof(vset)); - vset s; vset_init(vs); @@ -124,14 +116,10 @@ vset *graph_connected_nodes(graph * g, node * n) vset_add(&s, n); while (s.size > 0) { node *n = vset_pop(&s); - vset *vs_nb = graph_neighbours(g, n); - unsigned int i; - for (i = 0; i != vs_nb->size; ++i) { node *nb = vs_nb->data[i]; - if (nb->marker == 0) { nb->marker = 1; vset_add(vs, nb); @@ -153,7 +141,6 @@ vset *graph_connected_nodes(graph * g, node * n) vset *graph_disjunct_graphs(graph * g) { vset *dg = malloc(sizeof(vset)); - vset nodes; vset_init(dg); @@ -162,11 +149,8 @@ vset *graph_disjunct_graphs(graph * g) while (nodes.size > 0) { graph *gt = malloc(sizeof(graph)); - vset s; - unsigned int i; - node *start; graph_init(gt); @@ -178,10 +162,8 @@ vset *graph_disjunct_graphs(graph * g) vset_add(&s, start); while (s.size > 0) { vset *nbs = graph_neighbours(g, vset_pop(&s)); - for (i = 0; i != nbs->size; ++i) { node *nb = nbs->data[i]; - if (nb->marker == 0) { nb->marker = 1; graph_add_node(gt, nb); @@ -197,7 +179,6 @@ vset *graph_disjunct_graphs(graph * g) for (i = 0; i != g->edges.size; ++i) { edge *v = g->edges.data[i]; - if (vset_count(&g->nodes, v->node1)) { graph_add_edge(gt, v); } diff --git a/src/util/language.c b/src/util/language.c index 246391308..ae41b69ed 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -32,7 +32,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /** importing **/ locale *default_locale; - locale *locales; unsigned int locale_hashkey(const locale * lang) @@ -44,9 +43,7 @@ unsigned int locale_hashkey(const locale * lang) locale *find_locale(const char *name) { unsigned int hkey = hashstring(name); - locale *l = locales; - while (l && l->hashkey != hkey) l = l->next; return l; @@ -57,9 +54,7 @@ static int nextlocaleindex = 0; locale *make_locale(const char *name) { unsigned int hkey = hashstring(name); - locale *l = (locale *) calloc(sizeof(locale), 1); - locale **lp = &locales; while (*lp && (*lp)->hashkey != hkey) @@ -87,10 +82,8 @@ locale *make_locale(const char *name) void make_locales(const char *str) { const char *tok = str; - while (*tok) { char zText[32]; - while (*tok && *tok != ',') ++tok; strncpy(zText, str, tok - str); @@ -103,7 +96,6 @@ void make_locales(const char *str) } static FILE *s_debug = NULL; - static char *s_logfile = NULL; void debug_language(const char *log) @@ -114,9 +106,7 @@ void debug_language(const char *log) const char *locale_getstring(const locale * lang, const char *key) { unsigned int hkey = hashstring(key); - unsigned int id = hkey & (SMAXHASH - 1); - const struct locale_str *find; assert(lang); @@ -145,9 +135,7 @@ const char *locale_string(const locale * lang, const char *key) if (key != NULL) { unsigned int hkey = hashstring(key); - unsigned int id = hkey & (SMAXHASH - 1); - struct locale_str *find; if (*key == 0) @@ -169,7 +157,6 @@ const char *locale_string(const locale * lang, const char *key) } if (!find) { const char *s = key; - log_warning(("missing translation for \"%s\" in locale %s\n", key, lang->name)); if (lang != default_locale) { @@ -193,11 +180,8 @@ const char *locale_string(const locale * lang, const char *key) void locale_setstring(locale * lang, const char *key, const char *value) { unsigned int hkey = hashstring(key); - unsigned int id = hkey & (SMAXHASH - 1); - struct locale_str *find; - if (lang == NULL) lang = default_locale; find = lang->strings[id]; @@ -240,7 +224,6 @@ char *mkname_buf(const char *space, const char *name, char *buffer) const char *mkname(const char *space, const char *name) { static char zBuffer[128]; /* STATIC_RESULT: used for return, not across calls */ - return mkname_buf(space, name, zBuffer); } diff --git a/src/util/language_struct.h b/src/util/language_struct.h index 0818c2da4..3b1d0e9bc 100644 --- a/src/util/language_struct.h +++ b/src/util/language_struct.h @@ -23,7 +23,6 @@ typedef struct locale { } locale; extern locale *default_locale; - extern locale *locales; #endif diff --git a/src/util/listbox.c b/src/util/listbox.c index 181ac2347..0f573a2f8 100644 --- a/src/util/listbox.c +++ b/src/util/listbox.c @@ -26,12 +26,10 @@ insert_selection(list_selection ** p_sel, list_selection * prev, const char *str, void *payload) { list_selection *sel = calloc(sizeof(list_selection), 1); - sel->str = strdup(str); sel->data = payload; if (*p_sel) { list_selection *s; - sel->next = *p_sel; sel->prev = sel->next->prev; sel->next->prev = sel; @@ -55,9 +53,7 @@ list_selection **push_selection(list_selection ** p_sel, char *str, void *payload) { list_selection *sel = calloc(sizeof(list_selection), 1); - list_selection *prev = NULL; - sel->str = str; sel->data = payload; while (*p_sel) { @@ -79,19 +75,12 @@ list_selection *do_selection(list_selection * sel, const char *title, void (*perform) (list_selection *, void *), void *data) { WINDOW *wn; - boolean update = true; - list_selection *s; - list_selection *top = sel; - list_selection *current = top; - int i; - int height = 0, width = (int)strlen(title) + 8; - for (s = sel; s; s = s->next) { if ((int)strlen(s->str) > width) width = (int)strlen(s->str); @@ -114,7 +103,6 @@ list_selection *do_selection(list_selection * sel, const char *title, for (;;) { int input; - if (update) { for (s = top; s != NULL && top->index + height != s->index; s = s->next) { i = s->index - top->index; diff --git a/src/util/lists.c b/src/util/lists.c index da997bcd3..912699bc7 100644 --- a/src/util/lists.c +++ b/src/util/lists.c @@ -33,7 +33,6 @@ void addlist(void *l1, void *p1) /* add entry p to the end of list l */ void_list **l; - void_list *p, *q; l = (void_list **) l1; @@ -51,7 +50,6 @@ void addlist(void *l1, void *p1) static void choplist(void *a, void *b) { void_list **l = (void_list **) a, *p = (void_list *) b; - /* remove entry p from list l - when called, a pointer to p must be * kept in order to use (and free) p; if omitted, this will be a * memory leak */ @@ -117,7 +115,6 @@ unsigned int listlen(void *l) /* count entries p in list l */ unsigned int i; - void_list *p; for (p = (void_list *) l, i = 0; p; p = p->next, i++) ; diff --git a/src/util/log.c b/src/util/log.c index c13c5bf6c..ec93d625c 100644 --- a/src/util/log.c +++ b/src/util/log.c @@ -21,7 +21,6 @@ without prior permission by the authors of Eressea. /* TODO: set from external function */ int log_flags = LOG_FLUSH | LOG_CPERROR | LOG_CPWARNING; - #ifdef STDIO_CP static int stdio_codepage = STDIO_CP; #else @@ -48,14 +47,11 @@ cp_convert(const char *format, char *buffer, size_t length, int codepage) { /* when console output on MSDOS, convert to codepage */ const char *input = format; - char *pos = buffer; while (pos + 1 < buffer + length && *input) { size_t length = 0; - int result = 0; - if (codepage == 437) { result = unicode_utf8_to_cp437(pos, input, &length); } else if (codepage == 1252) { @@ -75,7 +71,6 @@ cp_convert(const char *format, char *buffer, size_t length, int codepage) void log_printf(const char *format, ...) { va_list marker; - if (!logfile) logfile = stderr; va_start(marker, format); @@ -89,13 +84,11 @@ void log_printf(const char *format, ...) void log_stdio(FILE * io, const char *format, ...) { va_list marker; - if (!logfile) logfile = stderr; va_start(marker, format); if (stdio_codepage) { char buffer[MAXLENGTH]; - char converted[MAXLENGTH]; vsnprintf(buffer, sizeof(buffer), format, marker); @@ -124,7 +117,6 @@ void log_open(const char *filename) if (logfile) { /* Get UNIX-style time and display as number and string. */ time_t ltime; - time(<ime); log_printf("===\n=== Logfile started at %s===\n", ctime(<ime)); } @@ -137,7 +129,6 @@ void log_close(void) if (logfile) { /* Get UNIX-style time and display as number and string. */ time_t ltime; - time(<ime); log_printf("===\n=== Logfile closed at %s===\n\n", ctime(<ime)); } @@ -148,11 +139,8 @@ void log_close(void) static int check_dupe(const char *format, const char *type) { static const char *last_type; /* STATIC_XCALL: used across calls */ - static char last_message[32]; /* STATIC_XCALL: used across calls */ - static int dupes = 0; /* STATIC_XCALL: used across calls */ - if (strncmp(last_message, format, sizeof(last_message)) == 0) { ++dupes; return 1; @@ -179,7 +167,6 @@ void _log_warn(const char *format, ...) logfile = stderr; if (logfile != stderr) { va_list marker; - fputs("WARNING: ", logfile); va_start(marker, format); vfprintf(logfile, format, marker); @@ -187,12 +174,10 @@ void _log_warn(const char *format, ...) } if (!dupe) { va_list marker; - fputs("WARNING: ", stderr); va_start(marker, format); if (stdio_codepage) { char buffer[MAXLENGTH]; - char converted[MAXLENGTH]; vsnprintf(buffer, sizeof(buffer), format, marker); @@ -218,14 +203,12 @@ void _log_warn(const char *format, ...) void _log_error(const char *format, ...) { int dupe = check_dupe(format, "ERROR"); - fflush(stdout); if (!logfile) logfile = stderr; if (logfile != stderr) { va_list marker; - fputs("ERROR: ", logfile); va_start(marker, format); vfprintf(logfile, format, marker); @@ -240,7 +223,6 @@ void _log_error(const char *format, ...) va_start(marker, format); if (stdio_codepage) { char buffer[MAXLENGTH]; - char converted[MAXLENGTH]; vsnprintf(buffer, sizeof(buffer), format, marker); @@ -263,13 +245,11 @@ void _log_error(const char *format, ...) } static unsigned int logfile_level = 0; - static unsigned int stderr_level = 1; void _log_info(unsigned int level, const char *format, ...) { va_list marker; - fflush(stdout); if (!logfile) logfile = stderr; @@ -284,7 +264,6 @@ void _log_info(unsigned int level, const char *format, ...) va_start(marker, format); if (stdio_codepage) { char buffer[MAXLENGTH]; - char converted[MAXLENGTH]; vsnprintf(buffer, sizeof(buffer), format, marker); diff --git a/src/util/message.c b/src/util/message.c index 49fd0300e..9bf78821b 100644 --- a/src/util/message.c +++ b/src/util/message.c @@ -35,7 +35,6 @@ const char *mt_name(const message_type * mtype) message_type *mt_new(const char *name, const char *args[]) { int i, nparameters = 0; - message_type *mtype = (message_type *) malloc(sizeof(message_type)); assert(name != NULL); @@ -58,15 +57,12 @@ message_type *mt_new(const char *name, const char *args[]) if (args != NULL) for (i = 0; args[i]; ++i) { const char *x = args[i]; - const char *spos = strchr(x, ':'); - if (spos == NULL) { mtype->pnames[i] = strdup(x); mtype->types[i] = NULL; } else { char *cp = strncpy((char *)malloc(spos - x + 1), x, spos - x); - cp[spos - x] = '\0'; mtype->pnames[i] = cp; mtype->types[i] = find_argtype(spos + 1); @@ -83,15 +79,12 @@ message_type *mt_new(const char *name, const char *args[]) message_type *mt_new_va(const char *name, ...) { const char *args[16]; - int i = 0; - va_list marker; va_start(marker, name); for (;;) { const char *c = va_arg(marker, const char *); - args[i++] = c; if (c == NULL) break; @@ -107,7 +100,6 @@ register_argtype(const char *name, void (*free_arg) (variant), variant(*copy_arg) (variant), variant_type type) { arg_type *atype = (arg_type *) malloc(sizeof(arg_type)); - atype->name = name; atype->next = argtypes; atype->release = free_arg; @@ -119,7 +111,6 @@ register_argtype(const char *name, void (*free_arg) (variant), const arg_type *find_argtype(const char *name) { arg_type *atype = argtypes; - while (atype != NULL) { if (strcmp(atype->name, name) == 0) return atype; @@ -146,7 +137,6 @@ static void free_arg(const arg_type * atype, variant data) message *msg_create(const struct message_type *mtype, variant args[]) { int i; - message *msg = (message *) malloc(sizeof(message)); assert(mtype != NULL); @@ -171,14 +161,11 @@ static quicklist *messagetypes[MT_MAXHASH]; const message_type *mt_find(const char *name) { unsigned int hash = hashstring(name) % MT_MAXHASH; - quicklist *ql = messagetypes[hash]; - int qi; for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { message_type *data = (message_type *) ql_get(ql, qi); - if (strcmp(data->name, name) == 0) { return data; } @@ -189,7 +176,6 @@ const message_type *mt_find(const char *name) static unsigned int mt_id(const message_type * mtype) { unsigned int key = 0; - size_t i = strlen(mtype->name); while (i > 0) { @@ -198,11 +184,9 @@ static unsigned int mt_id(const message_type * mtype) return key % 0x7FFFFFFF; } - const message_type *mt_register(message_type * type) { unsigned int hash = hashstring(type->name) % MT_MAXHASH; - quicklist **qlp = messagetypes + hash; if (ql_set_insert(qlp, type) == 0) { @@ -214,7 +198,6 @@ const message_type *mt_register(message_type * type) void msg_free(message * msg) { int i; - assert(msg->refcount == 0); for (i = 0; i != msg->type->nparameters; ++i) { free_arg(msg->type->types[i], msg->parameters[i]); diff --git a/src/util/nrmessage.c b/src/util/nrmessage.c index 3612d7c73..adb047df1 100644 --- a/src/util/nrmessage.c +++ b/src/util/nrmessage.c @@ -40,11 +40,8 @@ nrmessage_type *nrt_find(const struct locale * lang, const struct message_type * mtype) { nrmessage_type *found = NULL; - unsigned int hash = hashstring(mtype->name) % NRT_MAXHASH; - nrmessage_type *type = nrtypes[hash]; - while (type) { if (type->mtype == mtype) { if (found == NULL) @@ -74,12 +71,10 @@ nrsection *sections; const nrsection *section_find(const char *name) { nrsection **mcp = §ions; - if (name == NULL) return NULL; for (; *mcp; mcp = &(*mcp)->next) { nrsection *mc = *mcp; - if (!strcmp(mc->name, name)) break; } @@ -89,18 +84,15 @@ const nrsection *section_find(const char *name) const nrsection *section_add(const char *name) { nrsection **mcp = §ions; - if (name == NULL) return NULL; for (; *mcp; mcp = &(*mcp)->next) { nrsection *mc = *mcp; - if (!strcmp(mc->name, name)) break; } if (!*mcp) { nrsection *mc = calloc(sizeof(nrsection), 1); - mc->name = strdup(name); *mcp = mc; } @@ -112,9 +104,7 @@ nrt_register(const struct message_type *mtype, const struct locale *lang, const char *string, int level, const char *section) { unsigned int hash = hashstring(mtype->name) % NRT_MAXHASH; - nrmessage_type *nrt = nrtypes[hash]; - while (nrt && (nrt->lang != lang || nrt->mtype != mtype)) { nrt = nrt->next; } @@ -123,11 +113,8 @@ nrt_register(const struct message_type *mtype, const struct locale *lang, assert(!nrt || !"trying to register same nr-type twice"); } else { int i; - char zNames[256]; - char *c = zNames; - nrt = malloc(sizeof(nrmessage_type)); nrt->lang = lang; nrt->mtype = mtype; @@ -135,7 +122,6 @@ nrt_register(const struct message_type *mtype, const struct locale *lang, nrt->level = level; if (section) { const nrsection *s = section_find(section); - if (s == NULL) { s = section_add(section); } @@ -178,14 +164,12 @@ nr_render(const struct message *msg, const struct locale *lang, char *buffer, int nr_level(const struct message *msg) { nrmessage_type *nrt = nrt_find(NULL, msg->type); - return nrt ? nrt->level : 0; } const char *nr_section(const struct message *msg) { nrmessage_type *nrt = nrt_find(default_locale, msg->type); - return nrt ? nrt->section : NULL; } diff --git a/src/util/nrmessage.h b/src/util/nrmessage.h index c73e8ee7c..1c8781d41 100644 --- a/src/util/nrmessage.h +++ b/src/util/nrmessage.h @@ -41,7 +41,6 @@ extern "C" { extern int nr_level(const struct message *msg); extern const char *nr_section(const struct message *msg); - /* before: * fogblock;movement:0;de;{unit} konnte von {region} nicht nach {$dir direction} ausreisen, der Nebel war zu dicht. * after: diff --git a/src/util/parser.c b/src/util/parser.c index d5ef5cfcc..d6ae46c47 100644 --- a/src/util/parser.c +++ b/src/util/parser.c @@ -22,17 +22,13 @@ static parser_state *state; static int eatwhitespace_c(const char **str_p) { int ret = 0; - ucs4_t ucs; - size_t len; - const char *str = *str_p; /* skip over potential whitespace */ for (;;) { unsigned char utf8_character = (unsigned char)*str; - if (~utf8_character & 0x80) { if (!iswxspace(utf8_character)) break; @@ -65,7 +61,6 @@ void init_tokens_str(const char *initstr, char *cmd) void parser_pushstate(void) { parser_state *new_state = malloc(sizeof(parser_state)); - new_state->current_cmd = NULL; new_state->current_token = NULL; new_state->next = state; @@ -75,7 +70,6 @@ void parser_pushstate(void) void parser_popstate(void) { parser_state *new_state = state->next; - if (state->current_cmd != NULL) free(state->current_cmd); free(state); @@ -91,22 +85,18 @@ boolean parser_end(void) void skip_token(void) { char quotechar = 0; - eatwhitespace_c(&state->current_token); while (*state->current_token) { ucs4_t ucs; - size_t len; unsigned char utf8_character = (unsigned char)state->current_token[0]; - if (~utf8_character & 0x80) { ucs = utf8_character; ++state->current_token; } else { int ret = unicode_utf8_to_ucs4(&ucs, state->current_token, &len); - if (ret == 0) { state->current_token += len; } else { @@ -135,13 +125,9 @@ void skip_token(void) const char *parse_token(const char **str) { static char lbuf[MAXTOKENSIZE]; /* STATIC_RESULT: used for return, not across calls */ - char *cursor = lbuf; - char quotechar = 0; - boolean escape = false; - const char *ctoken = *str; assert(ctoken); @@ -149,19 +135,15 @@ const char *parse_token(const char **str) eatwhitespace_c(&ctoken); while (*ctoken && cursor - lbuf < MAXTOKENSIZE - 1) { ucs4_t ucs; - size_t len; - boolean copy = false; unsigned char utf8_character = *(unsigned char *)ctoken; - if (~utf8_character & 0x80) { ucs = utf8_character; len = 1; } else { int ret = unicode_utf8_to_ucs4(&ucs, ctoken, &len); - if (ret != 0) { log_warning(("illegal character sequence in UTF8 string: %s\n", ctoken)); diff --git a/src/util/quicklist.c b/src/util/quicklist.c index 3346377c1..42941f086 100644 --- a/src/util/quicklist.c +++ b/src/util/quicklist.c @@ -28,7 +28,6 @@ struct quicklist { void *elements[QL_MAXSIZE]; }; - void *ql_get(const quicklist * ql, int index) { return (ql @@ -40,7 +39,6 @@ void *ql_replace(quicklist * ql, int index, void *data) { if (ql && index < ql->num_elements) { void *orig = ql->elements[index]; - ql->elements[index] = data; return orig; } else { @@ -61,7 +59,6 @@ int ql_empty(const quicklist * ql) void ql_push(quicklist ** qlp, void *data) { quicklist *ql = 0; - while (*qlp && ((*qlp)->next || (*qlp)->num_elements == QL_MAXSIZE)) { qlp = &(*qlp)->next; } @@ -79,7 +76,6 @@ void ql_push(quicklist ** qlp, void *data) int ql_delete(quicklist ** qlp, int index) { quicklist *ql = *qlp; - if (index < 0) return EINVAL; if (ql && index >= ql->num_elements) { @@ -95,7 +91,6 @@ int ql_delete(quicklist ** qlp, int index) free(ql); } else if (ql->next && ql->num_elements < QL_LIMIT) { quicklist *qn = ql->next; - if (ql->num_elements + qn->num_elements > QL_MAXSIZE) { memcpy(ql->elements + ql->num_elements, qn->elements, sizeof(void *)); --qn->num_elements; @@ -117,7 +112,6 @@ int ql_delete(quicklist ** qlp, int index) int ql_insert(quicklist ** qlp, int index, void *data) { quicklist *ql = *qlp; - if (ql) { if (index >= QL_MAXSIZE) { return ql_insert(&ql->next, index - ql->num_elements, data); @@ -128,7 +122,6 @@ int ql_insert(quicklist ** qlp, int index, void *data) ++ql->num_elements; } else { quicklist *qn = (quicklist *) malloc(sizeof(quicklist)); - qn->next = ql->next; ql->next = qn; qn->num_elements = QL_LIMIT; @@ -153,7 +146,6 @@ void ql_foreach(struct quicklist *ql, void (*cb) (void *)) { for (; ql; ql = ql->next) { int i; - for (i = 0; i != ql->num_elements; ++i) { cb(ql->elements[i]); } @@ -163,9 +155,7 @@ void ql_foreach(struct quicklist *ql, void (*cb) (void *)) int ql_advance(struct quicklist **iterator, int *index, int stride) { quicklist *ql = *iterator; - int i = *index; - if (!ql || i < 0 || stride < 0) { return ERANGE; } else if (i + stride < ql->num_elements) { @@ -190,7 +180,6 @@ void ql_free(struct quicklist *ql) int ql_set_remove(struct quicklist **qlp, void *data) { int qi; - quicklist *ql = *qlp; if (!ql) @@ -198,7 +187,6 @@ int ql_set_remove(struct quicklist **qlp, void *data) for (qi = 0; qi != ql->num_elements; ++qi) { void *qd = ql_get(ql, qi); - if (qd == data) { return ql_delete(qlp, qi) == 0; } @@ -210,7 +198,6 @@ int ql_set_insert(struct quicklist **qlp, void *data) { if (*qlp) { quicklist *ql = *qlp; - if (ql->num_elements > 0 && ql->elements[ql->num_elements - 1] < data) { if (ql->num_elements == QL_MAXSIZE || (ql->next && ql->next->elements[0] <= data)) { @@ -221,7 +208,6 @@ int ql_set_insert(struct quicklist **qlp, void *data) return 0; } else { int i; - /* TODO: OPT | binary search */ for (i = 0; i != ql->num_elements; ++i) { if (data < ql->elements[i]) { @@ -241,7 +227,6 @@ int ql_set_insert(struct quicklist **qlp, void *data) int ql_set_find(struct quicklist **qlp, int *qip, const void *data) { quicklist *ql = *qlp; - int qi; while (ql && ql->elements[ql->num_elements - 1] < data) { diff --git a/src/util/quicklist_test.c b/src/util/quicklist_test.c index 13df9a3c6..7b8564909 100644 --- a/src/util/quicklist_test.c +++ b/src/util/quicklist_test.c @@ -8,9 +8,7 @@ static const char *hello = "Hello World"; static void test_insert(CuTest * tc) { struct quicklist *ql = NULL; - int i; - for (i = 0; i != 32; ++i) { CuAssertIntEquals(tc, i, ql_length(ql)); ql_insert(&ql, 0, (void *)i); @@ -23,7 +21,6 @@ static void test_insert(CuTest * tc) static void test_insert_delete_gives_null(CuTest * tc) { struct quicklist *ql = NULL; - CuAssertIntEquals(tc, 1, ql_empty(ql)); ql_push(&ql, (void *)42); CuAssertIntEquals(tc, 0, ql_empty(ql)); @@ -34,9 +31,7 @@ static void test_insert_delete_gives_null(CuTest * tc) static void test_replace(CuTest * tc) { struct quicklist *ql = NULL; - int a; - ql_push(&ql, (void *)42); a = (int)ql_replace(ql, 0, (void *)43); CuAssertIntEquals(tc, 42, a); @@ -46,9 +41,7 @@ static void test_replace(CuTest * tc) static void test_set_insert(CuTest * tc) { struct quicklist *ql = NULL; - int a, qi; - a = ql_set_insert(&ql, (void *)42); CuAssertIntEquals(tc, 1, ql_length(ql)); CuAssertIntEquals(tc, 0, a); @@ -75,7 +68,6 @@ static void test_set_insert(CuTest * tc) static void test_set_remove(CuTest * tc) { struct quicklist *ql = NULL, *q2; - int a; ql_set_insert(&ql, (void *)41); @@ -103,7 +95,6 @@ static void test_set_remove(CuTest * tc) static void test_set_find(CuTest * tc) { struct quicklist *ql = NULL, *q2; - int a, qi; for (a = 0; a != 32; ++a) { @@ -131,15 +122,12 @@ static void test_set_find(CuTest * tc) static void test_advance(CuTest * tc) { struct quicklist *ql = NULL, *qli; - int i, n = 31; - for (i = 0; i != 32; ++i) { ql_insert(&ql, 0, (void *)i); } for (i = 0, qli = ql; qli; ql_advance(&qli, &i, 1), n--) { int g = (int)ql_get(qli, i); - CuAssertIntEquals(tc, n, g); } } @@ -147,7 +135,6 @@ static void test_advance(CuTest * tc) static void test_push(CuTest * tc) { struct quicklist *ql = NULL; - CuAssertIntEquals(tc, 0, ql_length(ql)); ql_push(&ql, (void *)hello); CuAssertIntEquals(tc, 1, ql_length(ql)); @@ -159,7 +146,6 @@ static void test_push(CuTest * tc) static void test_delete_edgecases(CuTest * tc) { struct quicklist *ql = NULL; - ql_delete(&ql, 0); CuAssertPtrEquals(tc, 0, ql); ql_push(&ql, (void *)hello); @@ -171,9 +157,7 @@ static void test_delete_edgecases(CuTest * tc) static void test_insert_many(CuTest * tc) { struct quicklist *ql = NULL; - int i; - for (i = 0; i != 32; ++i) { ql_push(&ql, (void *)i); } @@ -189,9 +173,7 @@ static void test_insert_many(CuTest * tc) static void test_delete_rand(CuTest * tc) { struct quicklist *ql = NULL; - int i; - for (i = 0; i != 32; ++i) { ql_push(&ql, (void *)i); } @@ -206,7 +188,6 @@ static void test_delete_rand(CuTest * tc) CuSuite *get_quicklist_suite(void) { CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, test_advance); SUITE_ADD_TEST(suite, test_replace); SUITE_ADD_TEST(suite, test_push); diff --git a/src/util/rand.c b/src/util/rand.c index 1bff35e04..ac02786b7 100644 --- a/src/util/rand.c +++ b/src/util/rand.c @@ -35,14 +35,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. double normalvariate(double mu, double sigma) { static const double NV_MAGICCONST = 1.7155277699214135; /* STATIC_CONST: a constant */ - double z; - for (;;) { double u1 = rng_double(); - double u2 = 1.0 - rng_double(); - z = NV_MAGICCONST * (u1 - 0.5) / u2; if (z * z / 4.0 <= -log(u2)) { break; @@ -54,7 +50,6 @@ double normalvariate(double mu, double sigma) int ntimespprob(int n, double p, double mod) { int count = 0; - int i; for (i = 0; i < n && p > 0; i++) { diff --git a/src/util/resolve.c b/src/util/resolve.c index 780cf46fa..dbe6d2cc2 100644 --- a/src/util/resolve.c +++ b/src/util/resolve.c @@ -34,15 +34,12 @@ typedef struct unresolved { #define BLOCKSIZE 1024 static unresolved *ur_list; - static unresolved *ur_begin; - static unresolved *ur_current; variant read_int(struct storage *store) { variant var; - var.i = store->r_int(store); return var; } @@ -52,9 +49,7 @@ read_reference(void *address, storage * store, read_fun reader, resolve_fun resolver) { variant var = reader(store); - int result = resolver(var, address); - if (result != 0) { ur_add(var, address, resolver); } @@ -83,7 +78,6 @@ void ur_add(variant data, void *ptrptr, resolve_fun fun) void resolve(void) { unresolved *ur = ur_list; - while (ur) { if (ur->resolve == NULL) { ur = ur->data.v; diff --git a/src/util/sql.c b/src/util/sql.c index b6ca44ec2..127751aa9 100644 --- a/src/util/sql.c +++ b/src/util/sql.c @@ -26,7 +26,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include static FILE *sqlstream = NULL; - static char *sqlfilename = NULL; void sql_init(const char *filename) @@ -45,7 +44,6 @@ void _sql_print(const char *format, ...) } if (sqlstream != NULL) { va_list marker; - va_start(marker, format); vfprintf(sqlstream, format, marker); va_end(marker); @@ -67,15 +65,10 @@ const char *sqlquote(const char *str) #define BUFFERS 4 #define BUFSIZE 1024 static char sqlstring[BUFSIZE * BUFFERS]; /* STATIC_RESULT: used for return, not across calls */ - static int index = 0; /* STATIC_XCALL: used across calls */ - char *start = sqlstring + index * BUFSIZE; - char *o = start; - const char *i = str; - while (*i && o - start < BUFSIZE - 1) { if (*i != '\'' && *i != '\"') { *o++ = *i++; diff --git a/src/util/strings.c b/src/util/strings.c index d804f170c..94e0577f8 100644 --- a/src/util/strings.c +++ b/src/util/strings.c @@ -24,7 +24,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. INLINE_FUNCTION unsigned int hashstring(const char *s) { unsigned int key = 0; - while (*s) { key = key * 37 + *s++; } @@ -74,14 +73,10 @@ INLINE_FUNCTION const char *escape_string(const char *str, char *buffer, unsigned int len) { const char *start = strchr(str, '\"'); - if (start) { static char s_buffer[4096]; /* STATIC_RESULT: used for return, not across calls */ - const char *p; - char *o; - size_t skip = start - str; if (buffer == NULL) { diff --git a/src/util/strncpy.c b/src/util/strncpy.c index 9759a1ff9..954da8811 100644 --- a/src/util/strncpy.c +++ b/src/util/strncpy.c @@ -8,7 +8,6 @@ char *strncpy(char *to, const char *from, size_t size) { char *t = to, *f = (char *)from; - int copied = 0; while (copied < size) { diff --git a/src/util/translation.c b/src/util/translation.c index 7946fd0e7..37c86c20a 100644 --- a/src/util/translation.c +++ b/src/util/translation.c @@ -44,7 +44,6 @@ variant opstack_pop(opstack ** stackp) void opstack_push(opstack ** stackp, variant data) { opstack *stack = *stackp; - if (stack == NULL) { stack = (opstack *) malloc(sizeof(opstack)); stack->size = 1; @@ -54,7 +53,6 @@ void opstack_push(opstack ** stackp, variant data) } if (stack->top - stack->begin == stack->size) { size_t pos = stack->top - stack->begin; - stack->size += stack->size; stack->begin = realloc(stack->begin, sizeof(variant) * stack->size); stack->top = stack->begin + pos; @@ -77,7 +75,6 @@ static struct { char *balloc(size_t size) { static int init = 0; /* STATIC_XCALL: used across calls */ - if (!init) { init = 1; buffer.current = buffer.begin = malloc(BBUFSIZE); @@ -106,7 +103,6 @@ void brelease(void) buffer.last = buffer.current = buffer.begin; } - /** ** constant values **/ @@ -138,7 +134,6 @@ static void add_variable(const char *symbol, variant value) static variable *find_variable(const char *symbol) { variable *var = variables; - while (var) { if (!strcmp(var->symbol, symbol)) break; @@ -163,7 +158,6 @@ static void free_functions(void) { while (functions) { function *fun = functions; - functions = fun->next; free(fun); } @@ -183,7 +177,6 @@ void add_function(const char *symbol, evalfun parse) static function *find_function(const char *symbol) { function *fun = functions; - while (fun) { if (!strcmp(fun->symbol, symbol)) break; @@ -193,7 +186,6 @@ static function *find_function(const char *symbol) } static const char *parse(opstack **, const char *in, const void *); - /* static const char * sample = "\"enno and $bool($if($eq($i,0),\"noone else\",\"$i other people\"))\""; */ static const char *parse_symbol(opstack ** stack, const char *in, @@ -203,9 +195,7 @@ static const char *parse_symbol(opstack ** stack, const char *in, */ { boolean braces = false; - char symbol[32]; - char *cp = symbol; /* current position */ if (*in == '{') { @@ -219,7 +209,6 @@ static const char *parse_symbol(opstack ** stack, const char *in, if (*in == '(') { /* it's a function we need to parse, start by reading the parameters */ function *foo; - while (*in != ')') { in = parse(stack, ++in, userdata); /* will push the result on the stack */ if (in == NULL) @@ -234,7 +223,6 @@ static const char *parse_symbol(opstack ** stack, const char *in, foo->parse(stack, userdata); /* will pop parameters from stack (reverse order!) and push the result */ } else { variable *var = find_variable(symbol); - if (braces && *in == '}') { ++in; } @@ -253,20 +241,13 @@ static const char *parse_string(opstack ** stack, const char *in, const void *userdata) { /* (char*) -> char* */ char *c; - char *buffer = balloc(TOKENSIZE); - size_t size = TOKENSIZE - 1; - const char *ic = in; - char *oc = buffer; - /* mode flags */ boolean f_escape = false; - boolean bDone = false; - variant var; while (*ic && !bDone) { @@ -293,7 +274,6 @@ static const char *parse_string(opstack ** stack, const char *in, } } else { int ch = (unsigned char)(*ic); - int bytes; switch (ch) { @@ -336,13 +316,9 @@ static const char *parse_string(opstack ** stack, const char *in, static const char *parse_int(opstack ** stack, const char *in) { int k = 0; - int vz = 1; - boolean ok = false; - variant var; - do { switch (*in) { case '+': @@ -364,12 +340,10 @@ static const char *parse_int(opstack ** stack, const char *in) return in; } - static const char *parse(opstack ** stack, const char *inn, const void *userdata) { const char *b = inn; - while (*b) { switch (*b) { case '"': @@ -393,15 +367,10 @@ const char *translate(const char *format, const void *userdata, const char *vars, variant args[]) { int i = 0; - const char *ic = vars; - char symbol[32]; - char *oc = symbol; - opstack *stack = NULL; - const char *rv; brelease(); @@ -413,7 +382,6 @@ const char *translate(const char *format, const void *userdata, *oc++ = *ic++; if (!isalnum(*ic)) { variant x = args[i++]; - *oc = '\0'; oc = symbol; add_variable(strcpy(balloc(strlen(symbol) + 1), symbol), x); @@ -441,11 +409,8 @@ const char *translate(const char *format, const void *userdata, static void eval_lt(opstack ** stack, const void *userdata) { /* (int, int) -> int */ int a = opop_i(stack); - int b = opop_i(stack); - int rval = (b < a) ? 1 : 0; - opush_i(stack, rval); unused(userdata); } @@ -453,11 +418,8 @@ static void eval_lt(opstack ** stack, const void *userdata) static void eval_eq(opstack ** stack, const void *userdata) { /* (int, int) -> int */ int a = opop_i(stack); - int b = opop_i(stack); - int rval = (a == b) ? 1 : 0; - opush_i(stack, rval); unused(userdata); } @@ -465,9 +427,7 @@ static void eval_eq(opstack ** stack, const void *userdata) static void eval_add(opstack ** stack, const void *userdata) { /* (int, int) -> int */ int a = opop_i(stack); - int b = opop_i(stack); - opush_i(stack, a + b); unused(userdata); } @@ -475,7 +435,6 @@ static void eval_add(opstack ** stack, const void *userdata) static void eval_isnull(opstack ** stack, const void *userdata) { /* (int, int) -> int */ void *a = opop_v(stack); - opush_i(stack, (a == NULL) ? 1 : 0); unused(userdata); } @@ -483,11 +442,8 @@ static void eval_isnull(opstack ** stack, const void *userdata) static void eval_if(opstack ** stack, const void *userdata) { /* (int, int) -> int */ void *a = opop_v(stack); - void *b = opop_v(stack); - int cond = opop_i(stack); - opush_v(stack, cond ? b : a); unused(userdata); } @@ -495,7 +451,6 @@ static void eval_if(opstack ** stack, const void *userdata) static void eval_strlen(opstack ** stack, const void *userdata) { /* string -> int */ const char *c = (const char *)opop_v(stack); - opush_i(stack, c ? (int)strlen(c) : 0); unused(userdata); } @@ -504,11 +459,8 @@ static void eval_strlen(opstack ** stack, const void *userdata) static void eval_int(opstack ** stack, const void *userdata) { int i = opop_i(stack); - const char *c = itoa10(i); - size_t len = strlen(c); - variant var; var.v = strcpy(balloc(len + 1), c); diff --git a/src/util/umlaut.c b/src/util/umlaut.c index d2c707afa..cb3f22ea4 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -66,11 +66,8 @@ void addtoken(tnode * root, const char *str, variant id) root->flags |= LEAF; } else { tref *next; - int ret, index, i = 0; - ucs4_t ucs, lcs; - size_t len; ret = unicode_utf8_to_ucs4(&ucs, str, &len); @@ -90,7 +87,6 @@ void addtoken(tnode * root, const char *str, variant id) next = next->nexthash; if (!next) { tref *ref; - tnode *node = calloc(1, sizeof(tnode)); if (ucs < 'a' || ucs > 'z') { @@ -129,7 +125,6 @@ void addtoken(tnode * root, const char *str, variant id) while (replace[i].str[0]) { if (lcs == replace[i].ucs) { char zText[1024]; - memcpy(zText, replace[i].str, 3); strcpy(zText + 2, (const char *)str + len); addtoken(root, zText, id); @@ -147,13 +142,9 @@ int findtoken(const tnode * tk, const char *str, variant * result) do { int index; - const tref *ref; - ucs4_t ucs; - size_t len; - int ret = unicode_utf8_to_ucs4(&ucs, str, &len); if (ret != 0) { diff --git a/src/util/unicode.c b/src/util/unicode.c index 91642a5bd..e15aa44f3 100644 --- a/src/util/unicode.c +++ b/src/util/unicode.c @@ -34,14 +34,11 @@ int unicode_utf8_tolower(utf8_t * op, size_t outlen, const utf8_t * ip) { while (*ip) { ucs4_t ucs = *ip; - ucs4_t low; - size_t size = 1; if (ucs & 0x80) { int ret = unicode_utf8_to_ucs4(&ucs, ip, &size); - if (ret != 0) { return ret; } @@ -75,16 +72,12 @@ unicode_latin1_to_utf8(utf8_t * out, size_t * outlen, const char *in, size_t * inlen) { int is = (int)*inlen; - int os = (int)*outlen; - const char *ip = in; - utf8_t *op = out; while (ip - in < is) { unsigned char c = *ip; - if (c > 0xBF) { if (op - out >= os - 1) break; @@ -111,9 +104,7 @@ int unicode_utf8_strcasecmp(const utf8_t * a, const char *b) { while (*a && *b) { int ret; - size_t size; - ucs4_t ucsa = *a, ucsb = *b; if (ucsa & 0x80) { @@ -208,7 +199,6 @@ unicode_ucs4_to_utf8(utf8_t * utf8_character, size_t * size, return 0; } - /* Convert a UTF-8 encoded character to UCS-4. */ int unicode_utf8_to_ucs4(ucs4_t * ucs4_character, const utf8_t * utf8_string, @@ -313,7 +303,6 @@ unicode_utf8_to_cp437(char *cp_character, const utf8_t * utf8_string, size_t * length) { ucs4_t ucs4_character; - int result; result = unicode_utf8_to_ucs4(&ucs4_character, utf8_string, length); @@ -492,10 +481,8 @@ unicode_utf8_to_cp437(char *cp_character, const utf8_t * utf8_string, 0x266B, 14} }; int l = 0, r = 160; - while (l != r) { int m = (l + r) / 2; - if (xref[m].ucs4 == ucs4_character) { *cp_character = (char)xref[m].cp437; break; @@ -517,7 +504,6 @@ unicode_utf8_to_cp1252(char *cp_character, const utf8_t * utf8_string, size_t * length) { ucs4_t ucs4_character; - int result; result = unicode_utf8_to_ucs4(&ucs4_character, utf8_string, length); @@ -568,10 +554,8 @@ unicode_utf8_to_cp1252(char *cp_character, const utf8_t * utf8_string, 0x0178, 0x9f} }; int l = 0, r = sizeof(xref) / sizeof(xref[0]); - while (l != r) { int m = (l + r) / 2; - if (xref[m].ucs4 == ucs4_character) { *cp_character = (char)xref[m].cp; break; diff --git a/src/util/xml.c b/src/util/xml.c index 8dd82c18d..de9aa0cd1 100644 --- a/src/util/xml.c +++ b/src/util/xml.c @@ -28,7 +28,6 @@ const xmlChar *xml_i(double number) { static char buffer[128]; - snprintf(buffer, sizeof(buffer), "%.0lf", number); return (const xmlChar *)buffer; } @@ -36,9 +35,7 @@ const xmlChar *xml_i(double number) int xml_ivalue(xmlNodePtr node, const char *name, int dflt) { int i = dflt; - xmlChar *propValue = xmlGetProp(node, BAD_CAST name); - if (propValue != NULL) { i = atoi((const char *)propValue); xmlFree(propValue); @@ -49,9 +46,7 @@ int xml_ivalue(xmlNodePtr node, const char *name, int dflt) boolean xml_bvalue(xmlNodePtr node, const char *name, boolean dflt) { boolean result = dflt; - xmlChar *propValue = xmlGetProp(node, BAD_CAST name); - if (propValue != NULL) { if (strcmp((const char *)propValue, "no") == 0) result = false; @@ -76,9 +71,7 @@ boolean xml_bvalue(xmlNodePtr node, const char *name, boolean dflt) double xml_fvalue(xmlNodePtr node, const char *name, double dflt) { double result = dflt; - xmlChar *propValue = xmlGetProp(node, BAD_CAST name); - if (propValue != NULL) { result = atof((const char *)propValue); xmlFree(propValue); @@ -102,9 +95,7 @@ static xml_reader *xmlReaders; void xml_register_callback(xml_callback callback) { xml_reader *reader = (xml_reader *) malloc(sizeof(xml_reader)); - xml_reader **insert = &xmlReaders; - reader->callback = callback; reader->next = NULL; @@ -116,7 +107,6 @@ void xml_register_callback(xml_callback callback) int read_xml(const char *filename, const char *catalog) { xml_reader *reader = xmlReaders; - xmlDocPtr doc; if (catalog) { @@ -136,7 +126,6 @@ int read_xml(const char *filename, const char *catalog) while (reader != NULL) { int i = reader->callback(doc); - if (i != 0) { return i; } diff --git a/src/util/xml.h b/src/util/xml.h index 6c4366990..f14cbedeb 100644 --- a/src/util/xml.h +++ b/src/util/xml.h @@ -13,7 +13,6 @@ #ifndef H_UTIL_XML #define H_UTIL_XML - #ifdef __cplusplus extern "C" { #endif diff --git a/tools/atoi36.c b/tools/atoi36.c index c98fe20e5..678fa248d 100644 --- a/tools/atoi36.c +++ b/tools/atoi36.c @@ -18,7 +18,6 @@ int main(int argc, char **argv) { int i = 1, reverse = 0; - if (strstr(argv[0], "itoa36")) reverse = 1; if (argc > 1) { diff --git a/tools/gethash.c b/tools/gethash.c index 59de29005..75054b11e 100644 --- a/tools/gethash.c +++ b/tools/gethash.c @@ -5,18 +5,12 @@ int main(int argc, char **argv) { char key[4]; - char code[4]; - char result[4]; - int a, i, rot; - for (a = 1; a < argc; ++a) { const char *str = argv[a]; - size_t len = strlen(str); - str = str + len - 6; memcpy(key, str, 3); memcpy(code, str + 3, 3); diff --git a/tools/namegen.c b/tools/namegen.c index ed6eeea2d..175e1cbe0 100644 --- a/tools/namegen.c +++ b/tools/namegen.c @@ -233,7 +233,6 @@ int main(void) for (race = 0; race < 11; race++) { int i; - printf("%d:", (int)race); for (i = 0; i < 20; i++) { printf(" %s", create_random_name(race)); From 610c6799ea88884dd601555d4ab49038f56c1363 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 7 Mar 2011 08:31:59 +0100 Subject: [PATCH 110/400] fix CRLF massacre --- src/bindings/bindings.c | 410 ++++++++++++++++++++-------------------- 1 file changed, 205 insertions(+), 205 deletions(-) diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index 4b0ea958e..f7bb55328 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -66,12 +66,12 @@ without prior permission by the authors of Eressea. #include #include - int log_lua_error(lua_State * L) + int log_lua_error(lua_State * L) { const char *error = lua_tostring(L, -1); - log_error(("LUA call failed.\n%s\n", error)); + log_error(("LUA call failed.\n%s\n", error)); lua_pop(L, 1); - return 1; + return 1; } int tolua_orderlist_next(lua_State * L) @@ -85,9 +85,9 @@ without prior permission by the authors of Eressea. *order_ptr = ord->next; return 1; } - + else - return 0; /* no more values to return */ + return 0; /* no more values to return */ } static int tolua_quicklist_iter(lua_State * L) @@ -100,23 +100,23 @@ without prior permission by the authors of Eressea. void *data = ql_get(ql, index); tolua_pushusertype(L, data, TOLUA_CAST type); ql_advance(qlp, &index, 1); - tolua_pushnumber(L, index); + tolua_pushnumber(L, index); lua_replace(L, lua_upvalueindex(2)); return 1; } - + else - return 0; /* no more values to return */ + return 0; /* no more values to return */ } int tolua_quicklist_push(struct lua_State *L, const char *list_type, - const char *elem_type, struct quicklist *list) + const char *elem_type, struct quicklist *list) { if (list) { - quicklist ** qlist_ptr = + quicklist ** qlist_ptr = (quicklist **) lua_newuserdata(L, sizeof(quicklist *)); *qlist_ptr = list; - luaL_getmetatable(L, list_type); + luaL_getmetatable(L, list_type); lua_setmetatable(L, -2); lua_pushnumber(L, 0); lua_pushstring(L, elem_type); @@ -136,17 +136,17 @@ without prior permission by the authors of Eressea. *item_ptr = itm->next; return 1; } - + else - return 0; /* no more values to return */ + return 0; /* no more values to return */ } - static int tolua_autoseed(lua_State * L) + static int tolua_autoseed(lua_State * L) { const char *filename = tolua_tostring(L, 1, 0); int new_island = tolua_toboolean(L, 2, 0); newfaction * players = read_newfactions(filename); - if (players != NULL) { + if (players != NULL) { while (players) { int n = listlen(players); int k = (n + ISLANDSIZE - 1) / ISLANDSIZE; @@ -160,16 +160,16 @@ without prior permission by the authors of Eressea. return 0; } - static int tolua_getkey(lua_State * L) + static int tolua_getkey(lua_State * L) { const char *name = tolua_tostring(L, 1, 0); - int flag = atoi36(name); + int flag = atoi36(name); attrib * a = find_key(global.attribs, flag); lua_pushboolean(L, a != NULL); - return 1; + return 1; } - static int tolua_translate(lua_State * L) + static int tolua_translate(lua_State * L) { const char *str = tolua_tostring(L, 1, 0); const char *lang = tolua_tostring(L, 2, 0); @@ -182,27 +182,27 @@ without prior permission by the authors of Eressea. return 0; } - static int tolua_setkey(lua_State * L) + static int tolua_setkey(lua_State * L) { const char *name = tolua_tostring(L, 1, 0); int value = tolua_toboolean(L, 2, 0); - int flag = atoi36(name); + int flag = atoi36(name); attrib * a = find_key(global.attribs, flag); if (a == NULL && value) { add_key(&global.attribs, flag); } else if (a != NULL && !value) { a_remove(&global.attribs, a); } - return 0; + return 0; } - static int tolua_rng_int(lua_State * L) + static int tolua_rng_int(lua_State * L) { lua_pushnumber(L, (lua_Number) rng_int()); return 1; } - static int tolua_read_orders(lua_State * L) + static int tolua_read_orders(lua_State * L) { const char *filename = tolua_tostring(L, 1, 0); int result = readorders(filename); @@ -210,83 +210,83 @@ without prior permission by the authors of Eressea. return 1; } - static int tolua_message_unit(lua_State * L) + static int tolua_message_unit(lua_State * L) { unit * sender = (unit *) tolua_tousertype(L, 1, 0); unit * target = (unit *) tolua_tousertype(L, 2, 0); const char *str = tolua_tostring(L, 3, 0); if (!target) - tolua_error(L, TOLUA_CAST "target is nil", NULL); + tolua_error(L, TOLUA_CAST "target is nil", NULL); if (!sender) - tolua_error(L, TOLUA_CAST "sender is nil", NULL); + tolua_error(L, TOLUA_CAST "sender is nil", NULL); deliverMail(target->faction, sender->region, sender, str, target); return 0; } - static int tolua_message_faction(lua_State * L) + static int tolua_message_faction(lua_State * L) { unit * sender = (unit *) tolua_tousertype(L, 1, 0); faction * target = (faction *) tolua_tousertype(L, 2, 0); const char *str = tolua_tostring(L, 3, 0); if (!target) - tolua_error(L, TOLUA_CAST "target is nil", NULL); + tolua_error(L, TOLUA_CAST "target is nil", NULL); if (!sender) - tolua_error(L, TOLUA_CAST "sender is nil", NULL); - deliverMail(target, sender->region, sender, str, NULL); + tolua_error(L, TOLUA_CAST "sender is nil", NULL); + deliverMail(target, sender->region, sender, str, NULL); return 0; } - static int tolua_message_region(lua_State * L) + static int tolua_message_region(lua_State * L) { unit * sender = (unit *) tolua_tousertype(L, 1, 0); const char *str = tolua_tostring(L, 2, 0); - if (!sender) - tolua_error(L, TOLUA_CAST "sender is nil", NULL); + if (!sender) + tolua_error(L, TOLUA_CAST "sender is nil", NULL); ADDMSG(&sender->region->msgs, msg_message("mail_result", "unit message", - sender, str)); - return 0; + sender, str)); + return 0; } - static int tolua_update_guards(lua_State * L) + static int tolua_update_guards(lua_State * L) { update_guards(); return 0; } - static int tolua_set_turn(lua_State * L) + static int tolua_set_turn(lua_State * L) { turn = (int)tolua_tonumber(L, 1, 0); return 0; } - static int tolua_get_turn(lua_State * L) + static int tolua_get_turn(lua_State * L) { tolua_pushnumber(L, (lua_Number) turn); return 1; } - static int tolua_atoi36(lua_State * L) + static int tolua_atoi36(lua_State * L) { const char *s = tolua_tostring(L, 1, 0); tolua_pushnumber(L, (lua_Number) atoi36(s)); return 1; } - static int tolua_itoa36(lua_State * L) + static int tolua_itoa36(lua_State * L) { int i = (int)tolua_tonumber(L, 1, 0); tolua_pushstring(L, itoa36(i)); return 1; } - static int tolua_dice_rand(lua_State * L) + static int tolua_dice_rand(lua_State * L) { const char *s = tolua_tostring(L, 1, 0); tolua_pushnumber(L, dice_rand(s)); return 1; } - static int tolua_addequipment(lua_State * L) + static int tolua_addequipment(lua_State * L) { const char *eqname = tolua_tostring(L, 1, 0); const char *iname = tolua_tostring(L, 2, 0); @@ -303,7 +303,7 @@ without prior permission by the authors of Eressea. return 1; } - static int tolua_get_season(lua_State * L) + static int tolua_get_season(lua_State * L) { int turnno = (int)tolua_tonumber(L, 1, 0); gamedate gd; @@ -312,27 +312,27 @@ without prior permission by the authors of Eressea. return 1; } - static int tolua_create_curse(lua_State * L) + static int tolua_create_curse(lua_State * L) { unit * u = (unit *) tolua_tousertype(L, 1, 0); tolua_Error tolua_err; attrib ** ap = NULL; - if (tolua_isusertype(L, 2, TOLUA_CAST "unit", 0, &tolua_err)) { + if (tolua_isusertype(L, 2, TOLUA_CAST "unit", 0, &tolua_err)) { unit * target = (unit *) tolua_tousertype(L, 2, 0); if (target) - ap = &target->attribs; + ap = &target->attribs; } else if (tolua_isusertype(L, 2, TOLUA_CAST "region", 0, &tolua_err)) { region * target = (region *) tolua_tousertype(L, 2, 0); if (target) - ap = &target->attribs; + ap = &target->attribs; } else if (tolua_isusertype(L, 2, TOLUA_CAST "ship", 0, &tolua_err)) { ship * target = (ship *) tolua_tousertype(L, 2, 0); if (target) - ap = &target->attribs; + ap = &target->attribs; } else if (tolua_isusertype(L, 2, TOLUA_CAST "building", 0, &tolua_err)) { building * target = (building *) tolua_tousertype(L, 2, 0); if (target) - ap = &target->attribs; + ap = &target->attribs; } if (ap) { const char *cname = tolua_tostring(L, 3, 0); @@ -343,7 +343,7 @@ without prior permission by the authors of Eressea. double effect = tolua_tonumber(L, 6, 0); int men = (int)tolua_tonumber(L, 7, 0); /* optional */ curse * c = create_curse(u, ap, ctype, vigour, duration, effect, men); - if (c) { + if (c) { tolua_pushboolean(L, true); return 1; } @@ -353,7 +353,7 @@ without prior permission by the authors of Eressea. return 1; } - static int tolua_learn_skill(lua_State * L) + static int tolua_learn_skill(lua_State * L) { unit * u = (unit *) tolua_tousertype(L, 1, 0); const char *skname = tolua_tostring(L, 2, 0); @@ -365,13 +365,13 @@ without prior permission by the authors of Eressea. return 0; } - static int tolua_update_scores(lua_State * L) + static int tolua_update_scores(lua_State * L) { score(); return 0; } - static int tolua_update_owners(lua_State * L) + static int tolua_update_owners(lua_State * L) { region * r; for (r = regions; r; r = r->next) { @@ -380,19 +380,19 @@ without prior permission by the authors of Eressea. return 0; } - static int tolua_update_subscriptions(lua_State * L) + static int tolua_update_subscriptions(lua_State * L) { update_subscriptions(); return 0; } - static int tolua_remove_empty_units(lua_State * L) + static int tolua_remove_empty_units(lua_State * L) { remove_empty_units(); return 0; } - static int tolua_get_nmrs(lua_State * L) + static int tolua_get_nmrs(lua_State * L) { int result = -1; int n = (int)tolua_tonumber(L, 1, 0); @@ -406,15 +406,15 @@ without prior permission by the authors of Eressea. return 1; } - static int tolua_equipunit(lua_State * L) + static int tolua_equipunit(lua_State * L) { unit * u = (unit *) tolua_tousertype(L, 1, 0); const char *eqname = tolua_tostring(L, 2, 0); - equip_unit(u, get_equipment(eqname)); - return 0; + equip_unit(u, get_equipment(eqname)); + return 0; } - static int tolua_equipment_setitem(lua_State * L) + static int tolua_equipment_setitem(lua_State * L) { int result = -1; const char *eqname = tolua_tostring(L, 1, 0); @@ -431,9 +431,9 @@ without prior permission by the authors of Eressea. return 1; } - + #ifdef TODO_FOSS -static int tolua_levitate_ship(lua_State * L) +static int tolua_levitate_ship(lua_State * L) { ship * sh = (ship *) tolua_tousertype(L, 1, 0); unit * mage = (unit *) tolua_tousertype(L, 2, 0); @@ -444,41 +444,41 @@ static int tolua_levitate_ship(lua_State * L) return 1; } - -#endif /* */ - static int tolua_spawn_braineaters(lua_State * L) + +#endif /* */ +static int tolua_spawn_braineaters(lua_State * L) { float chance = (float)tolua_tonumber(L, 1, 0); spawn_braineaters(chance); return 0; } - static int tolua_init_reports(lua_State * L) + static int tolua_init_reports(lua_State * L) { int result = init_reports(); tolua_pushnumber(L, (lua_Number) result); return 1; } - static int tolua_write_report(lua_State * L) + static int tolua_write_report(lua_State * L) { faction * f = (faction *) tolua_tousertype(L, 1, 0); time_t ltime = time(0); int result = write_reports(f, ltime); - tolua_pushnumber(L, (lua_Number) result); + tolua_pushnumber(L, (lua_Number) result); return 1; } - static int tolua_write_reports(lua_State * L) + static int tolua_write_reports(lua_State * L) { int result; - init_reports(); + init_reports(); result = reports(); tolua_pushnumber(L, (lua_Number) result); return 1; } - static void reset_game(void) + static void reset_game(void) { region * r; faction * f; @@ -492,10 +492,10 @@ static int tolua_levitate_ship(lua_State * L) for (b = r->buildings; b; b = b->next) { b->flags &= BLD_SAVEMASK; } - if (r->land && r->land->ownership && r->land->ownership->owner) { + if (r->land && r->land->ownership && r->land->ownership->owner) { faction * owner = r->land->ownership->owner; if (owner == get_monsters()) { - + /* some compat-fix, i believe. */ owner = update_owners(r); } @@ -509,7 +509,7 @@ static int tolua_levitate_ship(lua_State * L) } } - static int tolua_process_orders(lua_State * L) + static int tolua_process_orders(lua_State * L) { ++turn; reset_game(); @@ -517,7 +517,7 @@ static int tolua_levitate_ship(lua_State * L) return 0; } - static int tolua_write_passwords(lua_State * L) + static int tolua_write_passwords(lua_State * L) { int result = writepasswd(); lua_pushnumber(L, (lua_Number) result); @@ -525,13 +525,13 @@ static int tolua_levitate_ship(lua_State * L) } static struct summary *sum_begin = 0; - static int tolua_init_summary(lua_State * L) + static int tolua_init_summary(lua_State * L) { sum_begin = make_summary(); return 0; } - static int tolua_write_summary(lua_State * L) + static int tolua_write_summary(lua_State * L) { if (sum_begin) { struct summary *sum_end = make_summary(); @@ -542,13 +542,13 @@ static int tolua_levitate_ship(lua_State * L) return 0; } - static int tolua_free_game(lua_State * L) + static int tolua_free_game(lua_State * L) { free_gamedata(); return 0; } - static int tolua_write_map(lua_State * L) + static int tolua_write_map(lua_State * L) { const char *filename = tolua_tostring(L, 1, 0); if (filename) { @@ -557,127 +557,127 @@ static int tolua_levitate_ship(lua_State * L) return 0; } - static int tolua_write_game(lua_State * L) + static int tolua_write_game(lua_State * L) { const char *filename = tolua_tostring(L, 1, 0); const char *mode = tolua_tostring(L, 2, 0); - int result, m = IO_BINARY; + int result, m = IO_BINARY; if (mode && strcmp(mode, "text") == 0) - m = IO_TEXT; + m = IO_TEXT; remove_empty_factions(); result = writegame(filename, m); - tolua_pushnumber(L, (lua_Number) result); + tolua_pushnumber(L, (lua_Number) result); return 1; } - static int tolua_read_game(lua_State * L) + static int tolua_read_game(lua_State * L) { const char *filename = tolua_tostring(L, 1, 0); const char *mode = tolua_tostring(L, 2, 0); - int rv, m = IO_BINARY; + int rv, m = IO_BINARY; if (mode && strcmp(mode, "text") == 0) - m = IO_TEXT; + m = IO_TEXT; rv = readgame(filename, m, false); - tolua_pushnumber(L, (lua_Number) rv); + tolua_pushnumber(L, (lua_Number) rv); return 1; } - static int tolua_read_turn(lua_State * L) + static int tolua_read_turn(lua_State * L) { int cturn = current_turn(); tolua_pushnumber(L, (lua_Number) cturn); return 1; } - static int tolua_get_faction(lua_State * L) + static int tolua_get_faction(lua_State * L) { int no = tolua_toid(L, 1, 0); faction * f = findfaction(no); - tolua_pushusertype(L, f, TOLUA_CAST "faction"); + tolua_pushusertype(L, f, TOLUA_CAST "faction"); return 1; } - static int tolua_get_region(lua_State * L) + static int tolua_get_region(lua_State * L) { int x = (int)tolua_tonumber(L, 1, 0); int y = (int)tolua_tonumber(L, 2, 0); region * r; - assert(!pnormalize(&x, &y, findplane(x, y))); + assert(!pnormalize(&x, &y, findplane(x, y))); r = findregion(x, y); - tolua_pushusertype(L, r, TOLUA_CAST "region"); + tolua_pushusertype(L, r, TOLUA_CAST "region"); return 1; } - static int tolua_get_region_byid(lua_State * L) + static int tolua_get_region_byid(lua_State * L) { int uid = (int)tolua_tonumber(L, 1, 0); region * r = findregionbyid(uid); - tolua_pushusertype(L, r, TOLUA_CAST "region"); + tolua_pushusertype(L, r, TOLUA_CAST "region"); return 1; } - static int tolua_get_building(lua_State * L) + static int tolua_get_building(lua_State * L) { int no = tolua_toid(L, 1, 0); building * b = findbuilding(no); - tolua_pushusertype(L, b, TOLUA_CAST "building"); + tolua_pushusertype(L, b, TOLUA_CAST "building"); return 1; } - static int tolua_get_ship(lua_State * L) + static int tolua_get_ship(lua_State * L) { int no = tolua_toid(L, 1, 0); ship * sh = findship(no); - tolua_pushusertype(L, sh, TOLUA_CAST "ship"); + tolua_pushusertype(L, sh, TOLUA_CAST "ship"); return 1; } - static int tolua_get_alliance(lua_State * L) + static int tolua_get_alliance(lua_State * L) { int no = tolua_toid(L, 1, 0); alliance * f = findalliance(no); - tolua_pushusertype(L, f, TOLUA_CAST "alliance"); + tolua_pushusertype(L, f, TOLUA_CAST "alliance"); return 1; } - static int tolua_get_unit(lua_State * L) + static int tolua_get_unit(lua_State * L) { int no = tolua_toid(L, 1, 0); unit * u = findunit(no); - tolua_pushusertype(L, u, TOLUA_CAST "unit"); + tolua_pushusertype(L, u, TOLUA_CAST "unit"); return 1; } - static int tolua_alliance_create(lua_State * L) + static int tolua_alliance_create(lua_State * L) { int id = (int)tolua_tonumber(L, 1, 0); const char *name = tolua_tostring(L, 2, 0); - alliance * alli = makealliance(id, name); - tolua_pushusertype(L, alli, TOLUA_CAST "alliance"); + alliance * alli = makealliance(id, name); + tolua_pushusertype(L, alli, TOLUA_CAST "alliance"); return 1; } - static int tolua_get_regions(lua_State * L) + static int tolua_get_regions(lua_State * L) { region ** region_ptr = (region **) lua_newuserdata(L, sizeof(region *)); - luaL_getmetatable(L, "region"); + luaL_getmetatable(L, "region"); lua_setmetatable(L, -2); - *region_ptr = regions; - lua_pushcclosure(L, tolua_regionlist_next, 1); + *region_ptr = regions; + lua_pushcclosure(L, tolua_regionlist_next, 1); return 1; } - static int tolua_get_factions(lua_State * L) + static int tolua_get_factions(lua_State * L) { faction ** faction_ptr = (faction **) lua_newuserdata(L, sizeof(faction *)); - luaL_getmetatable(L, "faction"); + luaL_getmetatable(L, "faction"); lua_setmetatable(L, -2); - *faction_ptr = factions; - lua_pushcclosure(L, tolua_factionlist_next, 1); + *faction_ptr = factions; + lua_pushcclosure(L, tolua_factionlist_next, 1); return 1; } - static int tolua_get_alliance_factions(lua_State * L) + static int tolua_get_alliance_factions(lua_State * L) { alliance * self = (alliance *) tolua_tousertype(L, 1, 0); return tolua_quicklist_push(L, "faction_list", "faction", self->members); @@ -704,12 +704,12 @@ static int tolua_levitate_ship(lua_State * L) return 0; } - + #include #include #include #include - static int tolua_write_spells(lua_State * L) +static int tolua_write_spells(lua_State * L) { spell_f fun = (spell_f) get_function("lua_castspell"); const char *filename = "magic.xml"; @@ -717,7 +717,7 @@ static int tolua_levitate_ship(lua_State * L) xmlNodePtr root = xmlNewNode(NULL, BAD_CAST "spells"); quicklist * ql; int qi; - for (ql = spells, qi = 0; ql; ql_advance(&ql, &qi, 1)) { + for (ql = spells, qi = 0; ql; ql_advance(&ql, &qi, 1)) { spell * sp = (spell *) ql_get(ql, qi); if (sp->sp_function != fun) { int combat = 0; @@ -728,9 +728,9 @@ static int tolua_levitate_ship(lua_State * L) xmlNewProp(node, BAD_CAST "level", xml_i(sp->level)); xmlNewProp(node, BAD_CAST "index", xml_i(sp->id)); if (sp->syntax) - xmlNewProp(node, BAD_CAST "syntax", BAD_CAST sp->syntax); + xmlNewProp(node, BAD_CAST "syntax", BAD_CAST sp->syntax); if (sp->parameter) - xmlNewProp(node, BAD_CAST "parameters", BAD_CAST sp->parameter); + xmlNewProp(node, BAD_CAST "parameters", BAD_CAST sp->parameter); if (sp->components) { spell_component * comp = sp->components; for (; comp->type != 0; ++comp) { @@ -740,8 +740,8 @@ static int tolua_levitate_ship(lua_State * L) xmlNewProp(cnode, BAD_CAST "amount", xml_i(comp->amount)); xmlNewProp(cnode, BAD_CAST "cost", BAD_CAST costs[comp->cost]); xmlAddChild(node, cnode); - } } - if (sp->sptyp & TESTCANSEE) { + }} + if (sp->sptyp & TESTCANSEE) { xmlNewProp(node, BAD_CAST "los", BAD_CAST "true"); } if (sp->sptyp & ONSHIPCAST) { @@ -756,14 +756,14 @@ static int tolua_levitate_ship(lua_State * L) if (sp->sptyp & SPELLLEVEL) { xmlNewProp(node, BAD_CAST "variable", BAD_CAST "true"); } - if (sp->sptyp & POSTCOMBATSPELL) - combat = 3; - + if (sp->sptyp & POSTCOMBATSPELL) + combat = 3; + else if (sp->sptyp & COMBATSPELL) - combat = 2; - + combat = 2; + else if (sp->sptyp & PRECOMBATSPELL) - combat = 1; + combat = 1; if (combat) { xmlNewProp(node, BAD_CAST "combat", xml_i(combat)); } @@ -777,12 +777,12 @@ static int tolua_levitate_ship(lua_State * L) return 0; } - static int config_get_ships(lua_State * L) + static int config_get_ships(lua_State * L) { quicklist * ql; int qi, i = 0; - lua_createtable(L, ql_length(shiptypes), 0); - for (qi = 0, ql = shiptypes; ql; ql_advance(&ql, &qi, 1)) { + lua_createtable(L, ql_length(shiptypes), 0); + for (qi = 0, ql = shiptypes; ql; ql_advance(&ql, &qi, 1)) { ship_type * stype = (ship_type *) ql_get(ql, qi); tolua_pushstring(L, TOLUA_CAST stype->name[0]); lua_rawseti(L, -2, ++i); @@ -790,21 +790,21 @@ static int tolua_levitate_ship(lua_State * L) return 1; } - static int config_get_locales(lua_State * L) + static int config_get_locales(lua_State * L) { const struct locale *lang; int i = 0, n = 0; - for (lang = locales; lang; lang = nextlocale(lang)) - ++n; + for (lang = locales; lang; lang = nextlocale(lang)) + ++n; lua_createtable(L, n, 0); - for (lang = locales; lang; lang = nextlocale(lang)) { + for (lang = locales; lang; lang = nextlocale(lang)) { tolua_pushstring(L, TOLUA_CAST locale_name(lang)); lua_rawseti(L, -2, ++i); } return 1; } - static int config_get_resource(lua_State * L) + static int config_get_resource(lua_State * L) { const char *name = tolua_tostring(L, 1, 0); if (name) { @@ -827,12 +827,12 @@ static int tolua_levitate_ship(lua_State * L) lua_pushstring(L, "build_skill_name"); lua_pushstring(L, skillnames[itype->construction->skill]); lua_settable(L, -3); - if (itype->construction->materials) { + if (itype->construction->materials) { lua_pushstring(L, "materials"); lua_newtable(L); for (i = 0; itype->construction->materials[i].number; ++i) { lua_pushstring(L, - itype->construction->materials[i].rtype->_name[0]); + itype->construction->materials[i].rtype->_name[0]); lua_pushinteger(L, itype->construction->materials[i].number); lua_settable(L, -3); } @@ -845,7 +845,7 @@ static int tolua_levitate_ship(lua_State * L) return 0; } - static int tolua_get_spell_text(lua_State * L) + static int tolua_get_spell_text(lua_State * L) { const struct locale *loc = default_locale; spell * self = (spell *) tolua_tousertype(L, 1, 0); @@ -853,21 +853,21 @@ static int tolua_levitate_ship(lua_State * L) return 1; } - static int tolua_get_spell_school(lua_State * L) + static int tolua_get_spell_school(lua_State * L) { spell * self = (spell *) tolua_tousertype(L, 1, 0); lua_pushstring(L, magic_school[self->magietyp]); return 1; } - static int tolua_get_spell_level(lua_State * L) + static int tolua_get_spell_level(lua_State * L) { spell * self = (spell *) tolua_tousertype(L, 1, 0); lua_pushnumber(L, self->level); return 1; } - static int tolua_get_spell_name(lua_State * L) + static int tolua_get_spell_name(lua_State * L) { const struct locale *lang = default_locale; spell * self = (spell *) tolua_tousertype(L, 1, 0); @@ -880,7 +880,7 @@ static int tolua_levitate_ship(lua_State * L) return tolua_quicklist_push(L, "spell_list", "spell", spells); } - int tolua_read_xml(lua_State * L) + int tolua_read_xml(lua_State * L) { const char *filename = tolua_tostring(L, 1, 0); const char *catalog = tolua_tostring(L, 2, 0); @@ -888,13 +888,13 @@ static int tolua_levitate_ship(lua_State * L) return 0; } - int tolua_process_markets(lua_State * L) + int tolua_process_markets(lua_State * L) { do_markets(); return 0; } - int tolua_process_produce(lua_State * L) + int tolua_process_produce(lua_State * L) { region * r; for (r = regions; r; r = r->next) { @@ -908,15 +908,15 @@ static int tolua_levitate_ship(lua_State * L) int hargs; const char *sendertype; } event_args; - static void args_free(void *udata) + static void args_free(void *udata) { free(udata); - } static void event_cb(void *sender, const char *event, void *udata) + } static void event_cb(void *sender, const char *event, void *udata) { lua_State * L = (lua_State *) global.vm_state; event_args * args = (event_args *) udata; int nargs = 2; - lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); + lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); if (sender && args->sendertype) { tolua_pushusertype(L, sender, TOLUA_CAST args->sendertype); } else { @@ -930,9 +930,9 @@ static int tolua_levitate_ship(lua_State * L) lua_pcall(L, nargs, 0, 0); } - static int tolua_eventbus_register(lua_State * L) + static int tolua_eventbus_register(lua_State * L) { - + /* parameters: ** 1: sender (usertype) ** 2: event (string) @@ -942,7 +942,7 @@ static int tolua_levitate_ship(lua_State * L) void *sender = tolua_tousertype(L, 1, 0); const char *event = tolua_tostring(L, 2, 0); event_args * args = malloc(sizeof(event_args)); - args->sendertype = sender ? tolua_typename(L, 1) : NULL; + args->sendertype = sender ? tolua_typename(L, 1) : NULL; lua_pushvalue(L, 3); args->hfunction = luaL_ref(L, LUA_REGISTRYINDEX); if (lua_type(L, 4) != LUA_TNONE) { @@ -955,7 +955,7 @@ static int tolua_levitate_ship(lua_State * L) return 0; } - static int tolua_eventbus_fire(lua_State * L) + static int tolua_eventbus_fire(lua_State * L) { void *sender = tolua_tousertype(L, 1, 0); const char *event = tolua_tostring(L, 2, 0); @@ -964,7 +964,7 @@ static int tolua_levitate_ship(lua_State * L) return 0; } - static int tolua_report_unit(lua_State * L) + static int tolua_report_unit(lua_State * L) { char buffer[512]; unit * u = (unit *) tolua_tousertype(L, 1, 0); @@ -974,14 +974,14 @@ static int tolua_levitate_ship(lua_State * L) return 1; } - static int tolua_settings_get(lua_State * L) + static int tolua_settings_get(lua_State * L) { const char *name = tolua_tostring(L, 1, 0); tolua_pushstring(L, get_param(global.parameters, name)); return 1; } - static int tolua_settings_set(lua_State * L) + static int tolua_settings_set(lua_State * L) { const char *name = tolua_tostring(L, 1, 0); const char *value = tolua_tostring(L, 2, 0); @@ -996,7 +996,7 @@ parse_inifile(lua_State * L, dictionary * d, const char *section) size_t len = strlen(section); for (i = 0; d && i != d->n; ++i) { const char *key = d->key[i]; - if (strncmp(section, key, len) == 0 && key[len] == ':') { + if (strncmp(section, key, len) == 0 && key[len] == ':') { const char *str_value = d->val[i]; char *endp; double num_value = strtod(str_value, &endp); @@ -1009,14 +1009,14 @@ parse_inifile(lua_State * L, dictionary * d, const char *section) lua_rawset(L, -3); } } - + /* special case */ lua_pushstring(L, "basepath"); lua_pushstring(L, basepath()); lua_rawset(L, -3); } - int tolua_eressea_open(lua_State * L) + int tolua_eressea_open(lua_State * L) { tolua_open(L); @@ -1028,7 +1028,7 @@ parse_inifile(lua_State * L, dictionary * d, const char *section) tolua_usertype(L, TOLUA_CAST "alliance"); tolua_usertype(L, TOLUA_CAST "event"); tolua_usertype(L, TOLUA_CAST "faction_list"); - tolua_module(L, NULL, 0); + tolua_module(L, NULL, 0); tolua_beginmodule(L, NULL); { tolua_module(L, "process", 0); @@ -1036,20 +1036,20 @@ parse_inifile(lua_State * L, dictionary * d, const char *section) { tolua_function(L, "markets", &tolua_process_markets); tolua_function(L, "produce", &tolua_process_produce); - } tolua_endmodule(L); - tolua_cclass(L, TOLUA_CAST "alliance", TOLUA_CAST "alliance", - TOLUA_CAST "", NULL); + } tolua_endmodule(L); + tolua_cclass(L, TOLUA_CAST "alliance", TOLUA_CAST "alliance", + TOLUA_CAST "", NULL); tolua_beginmodule(L, TOLUA_CAST "alliance"); { tolua_variable(L, TOLUA_CAST "name", tolua_get_alliance_name, - tolua_set_alliance_name); + tolua_set_alliance_name); tolua_variable(L, TOLUA_CAST "id", tolua_get_alliance_id, NULL); tolua_variable(L, TOLUA_CAST "factions", &tolua_get_alliance_factions, - NULL); + NULL); tolua_function(L, TOLUA_CAST "create", tolua_alliance_create); - } tolua_endmodule(L); - tolua_cclass(L, TOLUA_CAST "spell", TOLUA_CAST "spell", TOLUA_CAST "", - NULL); + } tolua_endmodule(L); + tolua_cclass(L, TOLUA_CAST "spell", TOLUA_CAST "spell", TOLUA_CAST "", + NULL); tolua_beginmodule(L, TOLUA_CAST "spell"); { tolua_function(L, TOLUA_CAST "__tostring", tolua_get_spell_name); @@ -1057,99 +1057,99 @@ parse_inifile(lua_State * L, dictionary * d, const char *section) tolua_variable(L, TOLUA_CAST "school", tolua_get_spell_school, 0); tolua_variable(L, TOLUA_CAST "level", tolua_get_spell_level, 0); tolua_variable(L, TOLUA_CAST "text", tolua_get_spell_text, 0); - } tolua_endmodule(L); - tolua_module(L, TOLUA_CAST "eventbus", 1); + } tolua_endmodule(L); + tolua_module(L, TOLUA_CAST "eventbus", 1); tolua_beginmodule(L, TOLUA_CAST "eventbus"); { tolua_function(L, TOLUA_CAST "register", &tolua_eventbus_register); tolua_function(L, TOLUA_CAST "fire", &tolua_eventbus_fire); - } tolua_endmodule(L); - tolua_module(L, TOLUA_CAST "settings", 1); + } tolua_endmodule(L); + tolua_module(L, TOLUA_CAST "settings", 1); tolua_beginmodule(L, TOLUA_CAST "settings"); { tolua_function(L, TOLUA_CAST "set", &tolua_settings_set); tolua_function(L, TOLUA_CAST "get", &tolua_settings_get); - } tolua_endmodule(L); - tolua_module(L, TOLUA_CAST "report", 1); + } tolua_endmodule(L); + tolua_module(L, TOLUA_CAST "report", 1); tolua_beginmodule(L, TOLUA_CAST "report"); { tolua_function(L, TOLUA_CAST "report_unit", &tolua_report_unit); - } tolua_endmodule(L); - tolua_module(L, TOLUA_CAST "config", 1); + } tolua_endmodule(L); + tolua_module(L, TOLUA_CAST "config", 1); tolua_beginmodule(L, TOLUA_CAST "config"); { parse_inifile(L, global.inifile, "config"); tolua_variable(L, TOLUA_CAST "locales", &config_get_locales, 0); tolua_function(L, TOLUA_CAST "get_resource", &config_get_resource); tolua_variable(L, TOLUA_CAST "ships", &config_get_ships, 0); - } tolua_endmodule(L); - tolua_function(L, TOLUA_CAST "get_region_by_id", tolua_get_region_byid); + } tolua_endmodule(L); + tolua_function(L, TOLUA_CAST "get_region_by_id", tolua_get_region_byid); tolua_function(L, TOLUA_CAST "get_faction", tolua_get_faction); tolua_function(L, TOLUA_CAST "get_unit", tolua_get_unit); tolua_function(L, TOLUA_CAST "get_alliance", tolua_get_alliance); tolua_function(L, TOLUA_CAST "get_ship", tolua_get_ship), tolua_function(L, TOLUA_CAST "get_building", tolua_get_building), - tolua_function(L, TOLUA_CAST "get_region", tolua_get_region), + tolua_function(L, TOLUA_CAST "get_region", tolua_get_region), // deprecated_function(L, TOLUA_CAST "add_faction"); // deprecated_function(L, TOLUA_CAST "faction_origin"); tolua_function(L, TOLUA_CAST "factions", tolua_get_factions); tolua_function(L, TOLUA_CAST "regions", tolua_get_regions); - tolua_function(L, TOLUA_CAST "read_turn", tolua_read_turn); + tolua_function(L, TOLUA_CAST "read_turn", tolua_read_turn); tolua_function(L, TOLUA_CAST "read_game", tolua_read_game); tolua_function(L, TOLUA_CAST "write_game", tolua_write_game); tolua_function(L, TOLUA_CAST "free_game", tolua_free_game); tolua_function(L, TOLUA_CAST "write_map", &tolua_write_map); - tolua_function(L, TOLUA_CAST "read_orders", tolua_read_orders); + tolua_function(L, TOLUA_CAST "read_orders", tolua_read_orders); tolua_function(L, TOLUA_CAST "process_orders", tolua_process_orders); - tolua_function(L, TOLUA_CAST "init_reports", tolua_init_reports); + tolua_function(L, TOLUA_CAST "init_reports", tolua_init_reports); tolua_function(L, TOLUA_CAST "write_reports", tolua_write_reports); tolua_function(L, TOLUA_CAST "write_report", tolua_write_report); - tolua_function(L, TOLUA_CAST "init_summary", tolua_init_summary); + tolua_function(L, TOLUA_CAST "init_summary", tolua_init_summary); tolua_function(L, TOLUA_CAST "write_summary", tolua_write_summary); tolua_function(L, TOLUA_CAST "write_passwords", tolua_write_passwords), - tolua_function(L, TOLUA_CAST "message_unit", tolua_message_unit); + tolua_function(L, TOLUA_CAST "message_unit", tolua_message_unit); tolua_function(L, TOLUA_CAST "message_faction", tolua_message_faction); tolua_function(L, TOLUA_CAST "message_region", tolua_message_region); /* scripted monsters */ tolua_function(L, TOLUA_CAST "spawn_braineaters", - tolua_spawn_braineaters); + tolua_spawn_braineaters); #ifdef TODO_FOSS /* spells and stuff */ tolua_function(L, TOLUA_CAST "levitate_ship", tolua_levitate_ship); - -#endif /* */ - tolua_function(L, TOLUA_CAST "update_guards", tolua_update_guards); - tolua_function(L, TOLUA_CAST "set_turn", &tolua_set_turn); + +#endif /* */ + tolua_function(L, TOLUA_CAST "update_guards", tolua_update_guards); + tolua_function(L, TOLUA_CAST "set_turn", &tolua_set_turn); tolua_function(L, TOLUA_CAST "get_turn", &tolua_get_turn); tolua_function(L, TOLUA_CAST "get_season", tolua_get_season); - tolua_function(L, TOLUA_CAST "equipment_setitem", - tolua_equipment_setitem); + tolua_function(L, TOLUA_CAST "equipment_setitem", + tolua_equipment_setitem); tolua_function(L, TOLUA_CAST "equip_unit", tolua_equipunit); tolua_function(L, TOLUA_CAST "add_equipment", tolua_addequipment); - tolua_function(L, TOLUA_CAST "atoi36", tolua_atoi36); + tolua_function(L, TOLUA_CAST "atoi36", tolua_atoi36); tolua_function(L, TOLUA_CAST "itoa36", tolua_itoa36); tolua_function(L, TOLUA_CAST "dice_roll", tolua_dice_rand); - tolua_function(L, TOLUA_CAST "get_nmrs", tolua_get_nmrs); + tolua_function(L, TOLUA_CAST "get_nmrs", tolua_get_nmrs); tolua_function(L, TOLUA_CAST "remove_empty_units", - tolua_remove_empty_units); - tolua_function(L, TOLUA_CAST "update_subscriptions", - tolua_update_subscriptions); + tolua_remove_empty_units); + tolua_function(L, TOLUA_CAST "update_subscriptions", + tolua_update_subscriptions); tolua_function(L, TOLUA_CAST "update_scores", tolua_update_scores); tolua_function(L, TOLUA_CAST "update_owners", tolua_update_owners); - tolua_function(L, TOLUA_CAST "learn_skill", tolua_learn_skill); + tolua_function(L, TOLUA_CAST "learn_skill", tolua_learn_skill); tolua_function(L, TOLUA_CAST "create_curse", tolua_create_curse); - tolua_function(L, TOLUA_CAST "autoseed", tolua_autoseed); - tolua_function(L, TOLUA_CAST "get_key", tolua_getkey); + tolua_function(L, TOLUA_CAST "autoseed", tolua_autoseed); + tolua_function(L, TOLUA_CAST "get_key", tolua_getkey); tolua_function(L, TOLUA_CAST "set_key", tolua_setkey); - tolua_function(L, TOLUA_CAST "translate", &tolua_translate); - tolua_function(L, TOLUA_CAST "rng_int", tolua_rng_int); - tolua_function(L, TOLUA_CAST "spells", tolua_get_spells); + tolua_function(L, TOLUA_CAST "translate", &tolua_translate); + tolua_function(L, TOLUA_CAST "rng_int", tolua_rng_int); + tolua_function(L, TOLUA_CAST "spells", tolua_get_spells); tolua_function(L, TOLUA_CAST "write_spells", tolua_write_spells); - tolua_function(L, TOLUA_CAST "read_xml", tolua_read_xml); - } tolua_endmodule(L); + tolua_function(L, TOLUA_CAST "read_xml", tolua_read_xml); + } tolua_endmodule(L); return 1; } - + From 791e4cd673b94042a0fa61fa01bc557a04cb2807 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 7 Mar 2011 08:35:23 +0100 Subject: [PATCH 111/400] fix CRLF massacre --- src/bindings/bindings.c | 1966 +++++++++++++++++++-------------------- 1 file changed, 983 insertions(+), 983 deletions(-) diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index f7bb55328..d6a5efaa9 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -1,1155 +1,1155 @@ -/* vi: set ts=2: -+-------------------+ -| | Enno Rehling -| Eressea PBEM host | Christian Schlittchen -| (c) 1998 - 2008 | Katja Zedel -| | Henning Peters -+-------------------+ - -This program may not be used, modified or distributed -without prior permission by the authors of Eressea. -*/ - -#include -#include "bindings.h" -#include "bind_unit.h" -#include "bind_faction.h" -#include "bind_region.h" -#include "helpers.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - int log_lua_error(lua_State * L) -{ - const char *error = lua_tostring(L, -1); - log_error(("LUA call failed.\n%s\n", error)); - lua_pop(L, 1); - return 1; - } +/* vi: set ts=2: ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ - int tolua_orderlist_next(lua_State * L) +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include +#include "bindings.h" +#include "bind_unit.h" +#include "bind_faction.h" +#include "bind_region.h" +#include "helpers.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +int log_lua_error(lua_State * L) { - order ** order_ptr = (order **) lua_touserdata(L, lua_upvalueindex(1)); - order * ord = *order_ptr; - if (ord != NULL) { - char cmd[8192]; - write_order(ord, cmd, sizeof(cmd)); - tolua_pushstring(L, cmd); - *order_ptr = ord->next; - return 1; - } - + const char *error = lua_tostring(L, -1); + log_error(("LUA call failed.\n%s\n", error)); + lua_pop(L, 1); + return 1; +} + +int tolua_orderlist_next(lua_State * L) +{ + order ** order_ptr = (order **) lua_touserdata(L, lua_upvalueindex(1)); + order * ord = *order_ptr; + if (ord != NULL) { + char cmd[8192]; + write_order(ord, cmd, sizeof(cmd)); + tolua_pushstring(L, cmd); + *order_ptr = ord->next; + return 1; + } + else - return 0; /* no more values to return */ - } + return 0; /* no more values to return */ +} - static int tolua_quicklist_iter(lua_State * L) +static int tolua_quicklist_iter(lua_State * L) { - quicklist ** qlp = (quicklist **) lua_touserdata(L, lua_upvalueindex(1)); - quicklist * ql = *qlp; - if (ql != NULL) { - int index = lua_tointeger(L, lua_upvalueindex(2)); - const char *type = lua_tostring(L, lua_upvalueindex(3)); - void *data = ql_get(ql, index); - tolua_pushusertype(L, data, TOLUA_CAST type); - ql_advance(qlp, &index, 1); - tolua_pushnumber(L, index); - lua_replace(L, lua_upvalueindex(2)); - return 1; - } - + quicklist ** qlp = (quicklist **) lua_touserdata(L, lua_upvalueindex(1)); + quicklist * ql = *qlp; + if (ql != NULL) { + int index = lua_tointeger(L, lua_upvalueindex(2)); + const char *type = lua_tostring(L, lua_upvalueindex(3)); + void *data = ql_get(ql, index); + tolua_pushusertype(L, data, TOLUA_CAST type); + ql_advance(qlp, &index, 1); + tolua_pushnumber(L, index); + lua_replace(L, lua_upvalueindex(2)); + return 1; + } + else - return 0; /* no more values to return */ - } + return 0; /* no more values to return */ +} - int tolua_quicklist_push(struct lua_State *L, const char *list_type, - const char *elem_type, struct quicklist *list) +int tolua_quicklist_push(struct lua_State *L, const char *list_type, + const char *elem_type, struct quicklist *list) { - if (list) { - quicklist ** qlist_ptr = + if (list) { + quicklist ** qlist_ptr = (quicklist **) lua_newuserdata(L, sizeof(quicklist *)); - *qlist_ptr = list; - luaL_getmetatable(L, list_type); - lua_setmetatable(L, -2); - lua_pushnumber(L, 0); - lua_pushstring(L, elem_type); - lua_pushcclosure(L, tolua_quicklist_iter, 3); /* OBS: this closure has multiple upvalues (list, index, type_name) */ - } else { - lua_pushnil(L); - } - return 1; - } + *qlist_ptr = list; + luaL_getmetatable(L, list_type); + lua_setmetatable(L, -2); + lua_pushnumber(L, 0); + lua_pushstring(L, elem_type); + lua_pushcclosure(L, tolua_quicklist_iter, 3); /* OBS: this closure has multiple upvalues (list, index, type_name) */ + } else { + lua_pushnil(L); + } + return 1; +} - int tolua_itemlist_next(lua_State * L) +int tolua_itemlist_next(lua_State * L) { - item ** item_ptr = (item **) lua_touserdata(L, lua_upvalueindex(1)); - item * itm = *item_ptr; - if (itm != NULL) { - tolua_pushstring(L, itm->type->rtype->_name[0]); - *item_ptr = itm->next; - return 1; - } - + item ** item_ptr = (item **) lua_touserdata(L, lua_upvalueindex(1)); + item * itm = *item_ptr; + if (itm != NULL) { + tolua_pushstring(L, itm->type->rtype->_name[0]); + *item_ptr = itm->next; + return 1; + } + else - return 0; /* no more values to return */ - } + return 0; /* no more values to return */ +} - static int tolua_autoseed(lua_State * L) +static int tolua_autoseed(lua_State * L) { - const char *filename = tolua_tostring(L, 1, 0); - int new_island = tolua_toboolean(L, 2, 0); - newfaction * players = read_newfactions(filename); - if (players != NULL) { - while (players) { - int n = listlen(players); - int k = (n + ISLANDSIZE - 1) / ISLANDSIZE; - k = n / k; - n = autoseed(&players, k, new_island ? 0 : TURNS_PER_ISLAND); - if (n == 0) { - break; - } - } - } - return 0; - } + const char *filename = tolua_tostring(L, 1, 0); + int new_island = tolua_toboolean(L, 2, 0); + newfaction * players = read_newfactions(filename); + if (players != NULL) { + while (players) { + int n = listlen(players); + int k = (n + ISLANDSIZE - 1) / ISLANDSIZE; + k = n / k; + n = autoseed(&players, k, new_island ? 0 : TURNS_PER_ISLAND); + if (n == 0) { + break; + } + } + } + return 0; +} - static int tolua_getkey(lua_State * L) +static int tolua_getkey(lua_State * L) { - const char *name = tolua_tostring(L, 1, 0); - int flag = atoi36(name); - attrib * a = find_key(global.attribs, flag); - lua_pushboolean(L, a != NULL); - return 1; - } + const char *name = tolua_tostring(L, 1, 0); + int flag = atoi36(name); + attrib * a = find_key(global.attribs, flag); + lua_pushboolean(L, a != NULL); + return 1; +} - static int tolua_translate(lua_State * L) +static int tolua_translate(lua_State * L) { - const char *str = tolua_tostring(L, 1, 0); - const char *lang = tolua_tostring(L, 2, 0); - struct locale *loc = lang ? find_locale(lang) : default_locale; - if (loc) { - str = locale_string(loc, str); - tolua_pushstring(L, str); - return 1; - } - return 0; - } + const char *str = tolua_tostring(L, 1, 0); + const char *lang = tolua_tostring(L, 2, 0); + struct locale *loc = lang ? find_locale(lang) : default_locale; + if (loc) { + str = locale_string(loc, str); + tolua_pushstring(L, str); + return 1; + } + return 0; +} - static int tolua_setkey(lua_State * L) +static int tolua_setkey(lua_State * L) { - const char *name = tolua_tostring(L, 1, 0); - int value = tolua_toboolean(L, 2, 0); - int flag = atoi36(name); - attrib * a = find_key(global.attribs, flag); - if (a == NULL && value) { - add_key(&global.attribs, flag); - } else if (a != NULL && !value) { - a_remove(&global.attribs, a); - } - return 0; - } + const char *name = tolua_tostring(L, 1, 0); + int value = tolua_toboolean(L, 2, 0); + int flag = atoi36(name); + attrib * a = find_key(global.attribs, flag); + if (a == NULL && value) { + add_key(&global.attribs, flag); + } else if (a != NULL && !value) { + a_remove(&global.attribs, a); + } + return 0; +} - static int tolua_rng_int(lua_State * L) +static int tolua_rng_int(lua_State * L) { - lua_pushnumber(L, (lua_Number) rng_int()); - return 1; - } + lua_pushnumber(L, (lua_Number) rng_int()); + return 1; +} - static int tolua_read_orders(lua_State * L) +static int tolua_read_orders(lua_State * L) { - const char *filename = tolua_tostring(L, 1, 0); - int result = readorders(filename); - lua_pushnumber(L, (lua_Number) result); - return 1; - } + const char *filename = tolua_tostring(L, 1, 0); + int result = readorders(filename); + lua_pushnumber(L, (lua_Number) result); + return 1; +} - static int tolua_message_unit(lua_State * L) +static int tolua_message_unit(lua_State * L) { - unit * sender = (unit *) tolua_tousertype(L, 1, 0); - unit * target = (unit *) tolua_tousertype(L, 2, 0); - const char *str = tolua_tostring(L, 3, 0); - if (!target) - tolua_error(L, TOLUA_CAST "target is nil", NULL); - if (!sender) - tolua_error(L, TOLUA_CAST "sender is nil", NULL); - deliverMail(target->faction, sender->region, sender, str, target); - return 0; - } + unit * sender = (unit *) tolua_tousertype(L, 1, 0); + unit * target = (unit *) tolua_tousertype(L, 2, 0); + const char *str = tolua_tostring(L, 3, 0); + if (!target) + tolua_error(L, TOLUA_CAST "target is nil", NULL); + if (!sender) + tolua_error(L, TOLUA_CAST "sender is nil", NULL); + deliverMail(target->faction, sender->region, sender, str, target); + return 0; +} - static int tolua_message_faction(lua_State * L) +static int tolua_message_faction(lua_State * L) { - unit * sender = (unit *) tolua_tousertype(L, 1, 0); - faction * target = (faction *) tolua_tousertype(L, 2, 0); - const char *str = tolua_tostring(L, 3, 0); - if (!target) - tolua_error(L, TOLUA_CAST "target is nil", NULL); - if (!sender) - tolua_error(L, TOLUA_CAST "sender is nil", NULL); - deliverMail(target, sender->region, sender, str, NULL); - return 0; - } + unit * sender = (unit *) tolua_tousertype(L, 1, 0); + faction * target = (faction *) tolua_tousertype(L, 2, 0); + const char *str = tolua_tostring(L, 3, 0); + if (!target) + tolua_error(L, TOLUA_CAST "target is nil", NULL); + if (!sender) + tolua_error(L, TOLUA_CAST "sender is nil", NULL); + deliverMail(target, sender->region, sender, str, NULL); + return 0; +} - static int tolua_message_region(lua_State * L) +static int tolua_message_region(lua_State * L) { - unit * sender = (unit *) tolua_tousertype(L, 1, 0); - const char *str = tolua_tostring(L, 2, 0); - if (!sender) - tolua_error(L, TOLUA_CAST "sender is nil", NULL); - ADDMSG(&sender->region->msgs, msg_message("mail_result", "unit message", - sender, str)); - return 0; - } + unit * sender = (unit *) tolua_tousertype(L, 1, 0); + const char *str = tolua_tostring(L, 2, 0); + if (!sender) + tolua_error(L, TOLUA_CAST "sender is nil", NULL); + ADDMSG(&sender->region->msgs, msg_message("mail_result", "unit message", + sender, str)); + return 0; +} - static int tolua_update_guards(lua_State * L) +static int tolua_update_guards(lua_State * L) { - update_guards(); - return 0; - } + update_guards(); + return 0; +} - static int tolua_set_turn(lua_State * L) +static int tolua_set_turn(lua_State * L) { - turn = (int)tolua_tonumber(L, 1, 0); - return 0; - } + turn = (int)tolua_tonumber(L, 1, 0); + return 0; +} - static int tolua_get_turn(lua_State * L) +static int tolua_get_turn(lua_State * L) { - tolua_pushnumber(L, (lua_Number) turn); - return 1; - } + tolua_pushnumber(L, (lua_Number) turn); + return 1; +} - static int tolua_atoi36(lua_State * L) +static int tolua_atoi36(lua_State * L) { - const char *s = tolua_tostring(L, 1, 0); - tolua_pushnumber(L, (lua_Number) atoi36(s)); - return 1; - } + const char *s = tolua_tostring(L, 1, 0); + tolua_pushnumber(L, (lua_Number) atoi36(s)); + return 1; +} - static int tolua_itoa36(lua_State * L) +static int tolua_itoa36(lua_State * L) { - int i = (int)tolua_tonumber(L, 1, 0); - tolua_pushstring(L, itoa36(i)); - return 1; - } + int i = (int)tolua_tonumber(L, 1, 0); + tolua_pushstring(L, itoa36(i)); + return 1; +} - static int tolua_dice_rand(lua_State * L) +static int tolua_dice_rand(lua_State * L) { - const char *s = tolua_tostring(L, 1, 0); - tolua_pushnumber(L, dice_rand(s)); - return 1; - } + const char *s = tolua_tostring(L, 1, 0); + tolua_pushnumber(L, dice_rand(s)); + return 1; +} - static int tolua_addequipment(lua_State * L) +static int tolua_addequipment(lua_State * L) { - const char *eqname = tolua_tostring(L, 1, 0); - const char *iname = tolua_tostring(L, 2, 0); - const char *value = tolua_tostring(L, 3, 0); - int result = -1; - if (iname != NULL) { - const struct item_type *itype = it_find(iname); - if (itype != NULL) { - equipment_setitem(create_equipment(eqname), itype, value); - result = 0; - } - } - lua_pushnumber(L, (lua_Number) result); - return 1; - } + const char *eqname = tolua_tostring(L, 1, 0); + const char *iname = tolua_tostring(L, 2, 0); + const char *value = tolua_tostring(L, 3, 0); + int result = -1; + if (iname != NULL) { + const struct item_type *itype = it_find(iname); + if (itype != NULL) { + equipment_setitem(create_equipment(eqname), itype, value); + result = 0; + } + } + lua_pushnumber(L, (lua_Number) result); + return 1; +} - static int tolua_get_season(lua_State * L) +static int tolua_get_season(lua_State * L) { - int turnno = (int)tolua_tonumber(L, 1, 0); - gamedate gd; - get_gamedate(turnno, &gd); - tolua_pushstring(L, seasonnames[gd.season]); - return 1; - } + int turnno = (int)tolua_tonumber(L, 1, 0); + gamedate gd; + get_gamedate(turnno, &gd); + tolua_pushstring(L, seasonnames[gd.season]); + return 1; +} - static int tolua_create_curse(lua_State * L) +static int tolua_create_curse(lua_State * L) { - unit * u = (unit *) tolua_tousertype(L, 1, 0); - tolua_Error tolua_err; - attrib ** ap = NULL; - if (tolua_isusertype(L, 2, TOLUA_CAST "unit", 0, &tolua_err)) { - unit * target = (unit *) tolua_tousertype(L, 2, 0); - if (target) - ap = &target->attribs; - } else if (tolua_isusertype(L, 2, TOLUA_CAST "region", 0, &tolua_err)) { - region * target = (region *) tolua_tousertype(L, 2, 0); - if (target) - ap = &target->attribs; - } else if (tolua_isusertype(L, 2, TOLUA_CAST "ship", 0, &tolua_err)) { - ship * target = (ship *) tolua_tousertype(L, 2, 0); - if (target) - ap = &target->attribs; - } else if (tolua_isusertype(L, 2, TOLUA_CAST "building", 0, &tolua_err)) { - building * target = (building *) tolua_tousertype(L, 2, 0); - if (target) - ap = &target->attribs; - } - if (ap) { - const char *cname = tolua_tostring(L, 3, 0); - const curse_type *ctype = ct_find(cname); - if (ctype) { - double vigour = tolua_tonumber(L, 4, 0); - int duration = (int)tolua_tonumber(L, 5, 0); - double effect = tolua_tonumber(L, 6, 0); - int men = (int)tolua_tonumber(L, 7, 0); /* optional */ - curse * c = create_curse(u, ap, ctype, vigour, duration, effect, men); - if (c) { - tolua_pushboolean(L, true); - return 1; - } - } - } - tolua_pushboolean(L, false); - return 1; - } + unit * u = (unit *) tolua_tousertype(L, 1, 0); + tolua_Error tolua_err; + attrib ** ap = NULL; + if (tolua_isusertype(L, 2, TOLUA_CAST "unit", 0, &tolua_err)) { + unit * target = (unit *) tolua_tousertype(L, 2, 0); + if (target) + ap = &target->attribs; + } else if (tolua_isusertype(L, 2, TOLUA_CAST "region", 0, &tolua_err)) { + region * target = (region *) tolua_tousertype(L, 2, 0); + if (target) + ap = &target->attribs; + } else if (tolua_isusertype(L, 2, TOLUA_CAST "ship", 0, &tolua_err)) { + ship * target = (ship *) tolua_tousertype(L, 2, 0); + if (target) + ap = &target->attribs; + } else if (tolua_isusertype(L, 2, TOLUA_CAST "building", 0, &tolua_err)) { + building * target = (building *) tolua_tousertype(L, 2, 0); + if (target) + ap = &target->attribs; + } + if (ap) { + const char *cname = tolua_tostring(L, 3, 0); + const curse_type *ctype = ct_find(cname); + if (ctype) { + double vigour = tolua_tonumber(L, 4, 0); + int duration = (int)tolua_tonumber(L, 5, 0); + double effect = tolua_tonumber(L, 6, 0); + int men = (int)tolua_tonumber(L, 7, 0); /* optional */ + curse * c = create_curse(u, ap, ctype, vigour, duration, effect, men); + if (c) { + tolua_pushboolean(L, true); + return 1; + } + } + } + tolua_pushboolean(L, false); + return 1; +} - static int tolua_learn_skill(lua_State * L) +static int tolua_learn_skill(lua_State * L) { - unit * u = (unit *) tolua_tousertype(L, 1, 0); - const char *skname = tolua_tostring(L, 2, 0); - float chances = (float)tolua_tonumber(L, 3, 0); - skill_t sk = sk_find(skname); - if (sk != NOSKILL) { - learn_skill(u, sk, chances); - } - return 0; - } + unit * u = (unit *) tolua_tousertype(L, 1, 0); + const char *skname = tolua_tostring(L, 2, 0); + float chances = (float)tolua_tonumber(L, 3, 0); + skill_t sk = sk_find(skname); + if (sk != NOSKILL) { + learn_skill(u, sk, chances); + } + return 0; +} - static int tolua_update_scores(lua_State * L) +static int tolua_update_scores(lua_State * L) { - score(); - return 0; - } + score(); + return 0; +} - static int tolua_update_owners(lua_State * L) +static int tolua_update_owners(lua_State * L) { - region * r; - for (r = regions; r; r = r->next) { - update_owners(r); - } - return 0; - } + region * r; + for (r = regions; r; r = r->next) { + update_owners(r); + } + return 0; +} - static int tolua_update_subscriptions(lua_State * L) +static int tolua_update_subscriptions(lua_State * L) { - update_subscriptions(); - return 0; - } + update_subscriptions(); + return 0; +} - static int tolua_remove_empty_units(lua_State * L) +static int tolua_remove_empty_units(lua_State * L) { - remove_empty_units(); - return 0; - } + remove_empty_units(); + return 0; +} - static int tolua_get_nmrs(lua_State * L) +static int tolua_get_nmrs(lua_State * L) { - int result = -1; - int n = (int)tolua_tonumber(L, 1, 0); - if (n >= 0 && n <= NMRTimeout()) { - if (nmrs == NULL) { - update_nmrs(); - } - result = nmrs[n]; - } - tolua_pushnumber(L, (lua_Number) result); - return 1; - } + int result = -1; + int n = (int)tolua_tonumber(L, 1, 0); + if (n >= 0 && n <= NMRTimeout()) { + if (nmrs == NULL) { + update_nmrs(); + } + result = nmrs[n]; + } + tolua_pushnumber(L, (lua_Number) result); + return 1; +} - static int tolua_equipunit(lua_State * L) +static int tolua_equipunit(lua_State * L) { - unit * u = (unit *) tolua_tousertype(L, 1, 0); - const char *eqname = tolua_tostring(L, 2, 0); - equip_unit(u, get_equipment(eqname)); - return 0; - } + unit * u = (unit *) tolua_tousertype(L, 1, 0); + const char *eqname = tolua_tostring(L, 2, 0); + equip_unit(u, get_equipment(eqname)); + return 0; +} - static int tolua_equipment_setitem(lua_State * L) +static int tolua_equipment_setitem(lua_State * L) { - int result = -1; - const char *eqname = tolua_tostring(L, 1, 0); - const char *iname = tolua_tostring(L, 2, 0); - const char *value = tolua_tostring(L, 3, 0); - if (iname != NULL) { - const struct item_type *itype = it_find(iname); - if (itype != NULL) { - equipment_setitem(create_equipment(eqname), itype, value); - result = 0; - } - } - tolua_pushnumber(L, (lua_Number) result); - return 1; - } + int result = -1; + const char *eqname = tolua_tostring(L, 1, 0); + const char *iname = tolua_tostring(L, 2, 0); + const char *value = tolua_tostring(L, 3, 0); + if (iname != NULL) { + const struct item_type *itype = it_find(iname); + if (itype != NULL) { + equipment_setitem(create_equipment(eqname), itype, value); + result = 0; + } + } + tolua_pushnumber(L, (lua_Number) result); + return 1; +} - -#ifdef TODO_FOSS -static int tolua_levitate_ship(lua_State * L) -{ - ship * sh = (ship *) tolua_tousertype(L, 1, 0); - unit * mage = (unit *) tolua_tousertype(L, 2, 0); - double power = (double)tolua_tonumber(L, 3, 0); - int duration = (int)tolua_tonumber(L, 4, 0); - int cno = levitate_ship(sh, mage, power, duration); - tolua_pushnumber(L, (lua_Number) cno); - return 1; - } - -#endif /* */ -static int tolua_spawn_braineaters(lua_State * L) +#ifdef TODO_FOSS +static int tolua_levitate_ship(lua_State * L) { - float chance = (float)tolua_tonumber(L, 1, 0); - spawn_braineaters(chance); - return 0; - } + ship * sh = (ship *) tolua_tousertype(L, 1, 0); + unit * mage = (unit *) tolua_tousertype(L, 2, 0); + double power = (double)tolua_tonumber(L, 3, 0); + int duration = (int)tolua_tonumber(L, 4, 0); + int cno = levitate_ship(sh, mage, power, duration); + tolua_pushnumber(L, (lua_Number) cno); + return 1; +} - static int tolua_init_reports(lua_State * L) -{ - int result = init_reports(); - tolua_pushnumber(L, (lua_Number) result); - return 1; - } - static int tolua_write_report(lua_State * L) +#endif /* */ +static int tolua_spawn_braineaters(lua_State * L) { - faction * f = (faction *) tolua_tousertype(L, 1, 0); - time_t ltime = time(0); - int result = write_reports(f, ltime); - tolua_pushnumber(L, (lua_Number) result); - return 1; - } + float chance = (float)tolua_tonumber(L, 1, 0); + spawn_braineaters(chance); + return 0; +} - static int tolua_write_reports(lua_State * L) +static int tolua_init_reports(lua_State * L) { - int result; - init_reports(); - result = reports(); - tolua_pushnumber(L, (lua_Number) result); - return 1; - } + int result = init_reports(); + tolua_pushnumber(L, (lua_Number) result); + return 1; +} - static void reset_game(void) +static int tolua_write_report(lua_State * L) { - region * r; - faction * f; - for (r = regions; r; r = r->next) { - unit * u; - building * b; - r->flags &= RF_SAVEMASK; - for (u = r->units; u; u = u->next) { - u->flags &= UFL_SAVEMASK; - } - for (b = r->buildings; b; b = b->next) { - b->flags &= BLD_SAVEMASK; - } - if (r->land && r->land->ownership && r->land->ownership->owner) { - faction * owner = r->land->ownership->owner; - if (owner == get_monsters()) { - - /* some compat-fix, i believe. */ + faction * f = (faction *) tolua_tousertype(L, 1, 0); + time_t ltime = time(0); + int result = write_reports(f, ltime); + tolua_pushnumber(L, (lua_Number) result); + return 1; +} + +static int tolua_write_reports(lua_State * L) +{ + int result; + init_reports(); + result = reports(); + tolua_pushnumber(L, (lua_Number) result); + return 1; +} + +static void reset_game(void) +{ + region * r; + faction * f; + for (r = regions; r; r = r->next) { + unit * u; + building * b; + r->flags &= RF_SAVEMASK; + for (u = r->units; u; u = u->next) { + u->flags &= UFL_SAVEMASK; + } + for (b = r->buildings; b; b = b->next) { + b->flags &= BLD_SAVEMASK; + } + if (r->land && r->land->ownership && r->land->ownership->owner) { + faction * owner = r->land->ownership->owner; + if (owner == get_monsters()) { + + /* some compat-fix, i believe. */ owner = update_owners(r); - } - if (owner) { - fset(r, RF_GUARDED); - } - } - } - for (f = factions; f; f = f->next) { - f->flags &= FFL_SAVEMASK; - } - } + } + if (owner) { + fset(r, RF_GUARDED); + } + } + } + for (f = factions; f; f = f->next) { + f->flags &= FFL_SAVEMASK; + } +} - static int tolua_process_orders(lua_State * L) +static int tolua_process_orders(lua_State * L) { - ++turn; - reset_game(); - processorders(); - return 0; - } + ++turn; + reset_game(); + processorders(); + return 0; +} - static int tolua_write_passwords(lua_State * L) +static int tolua_write_passwords(lua_State * L) { - int result = writepasswd(); - lua_pushnumber(L, (lua_Number) result); - return 0; - } + int result = writepasswd(); + lua_pushnumber(L, (lua_Number) result); + return 0; +} - static struct summary *sum_begin = 0; - static int tolua_init_summary(lua_State * L) +static struct summary *sum_begin = 0; +static int tolua_init_summary(lua_State * L) { - sum_begin = make_summary(); - return 0; - } + sum_begin = make_summary(); + return 0; +} - static int tolua_write_summary(lua_State * L) +static int tolua_write_summary(lua_State * L) { - if (sum_begin) { - struct summary *sum_end = make_summary(); - report_summary(sum_end, sum_begin, false); - report_summary(sum_end, sum_begin, true); - return 0; - } - return 0; - } + if (sum_begin) { + struct summary *sum_end = make_summary(); + report_summary(sum_end, sum_begin, false); + report_summary(sum_end, sum_begin, true); + return 0; + } + return 0; +} - static int tolua_free_game(lua_State * L) +static int tolua_free_game(lua_State * L) { - free_gamedata(); - return 0; - } + free_gamedata(); + return 0; +} - static int tolua_write_map(lua_State * L) +static int tolua_write_map(lua_State * L) { - const char *filename = tolua_tostring(L, 1, 0); - if (filename) { - crwritemap(filename); - } - return 0; - } + const char *filename = tolua_tostring(L, 1, 0); + if (filename) { + crwritemap(filename); + } + return 0; +} - static int tolua_write_game(lua_State * L) +static int tolua_write_game(lua_State * L) { - const char *filename = tolua_tostring(L, 1, 0); - const char *mode = tolua_tostring(L, 2, 0); - int result, m = IO_BINARY; - if (mode && strcmp(mode, "text") == 0) - m = IO_TEXT; - remove_empty_factions(); - result = writegame(filename, m); - tolua_pushnumber(L, (lua_Number) result); - return 1; - } + const char *filename = tolua_tostring(L, 1, 0); + const char *mode = tolua_tostring(L, 2, 0); + int result, m = IO_BINARY; + if (mode && strcmp(mode, "text") == 0) + m = IO_TEXT; + remove_empty_factions(); + result = writegame(filename, m); + tolua_pushnumber(L, (lua_Number) result); + return 1; +} - static int tolua_read_game(lua_State * L) +static int tolua_read_game(lua_State * L) { - const char *filename = tolua_tostring(L, 1, 0); - const char *mode = tolua_tostring(L, 2, 0); - int rv, m = IO_BINARY; - if (mode && strcmp(mode, "text") == 0) - m = IO_TEXT; - rv = readgame(filename, m, false); - tolua_pushnumber(L, (lua_Number) rv); - return 1; - } + const char *filename = tolua_tostring(L, 1, 0); + const char *mode = tolua_tostring(L, 2, 0); + int rv, m = IO_BINARY; + if (mode && strcmp(mode, "text") == 0) + m = IO_TEXT; + rv = readgame(filename, m, false); + tolua_pushnumber(L, (lua_Number) rv); + return 1; +} - static int tolua_read_turn(lua_State * L) +static int tolua_read_turn(lua_State * L) { - int cturn = current_turn(); - tolua_pushnumber(L, (lua_Number) cturn); - return 1; - } + int cturn = current_turn(); + tolua_pushnumber(L, (lua_Number) cturn); + return 1; +} - static int tolua_get_faction(lua_State * L) +static int tolua_get_faction(lua_State * L) { - int no = tolua_toid(L, 1, 0); - faction * f = findfaction(no); - tolua_pushusertype(L, f, TOLUA_CAST "faction"); - return 1; - } + int no = tolua_toid(L, 1, 0); + faction * f = findfaction(no); + tolua_pushusertype(L, f, TOLUA_CAST "faction"); + return 1; +} - static int tolua_get_region(lua_State * L) +static int tolua_get_region(lua_State * L) { - int x = (int)tolua_tonumber(L, 1, 0); - int y = (int)tolua_tonumber(L, 2, 0); - region * r; - assert(!pnormalize(&x, &y, findplane(x, y))); - r = findregion(x, y); - tolua_pushusertype(L, r, TOLUA_CAST "region"); - return 1; - } + int x = (int)tolua_tonumber(L, 1, 0); + int y = (int)tolua_tonumber(L, 2, 0); + region * r; + assert(!pnormalize(&x, &y, findplane(x, y))); + r = findregion(x, y); + tolua_pushusertype(L, r, TOLUA_CAST "region"); + return 1; +} - static int tolua_get_region_byid(lua_State * L) +static int tolua_get_region_byid(lua_State * L) { - int uid = (int)tolua_tonumber(L, 1, 0); - region * r = findregionbyid(uid); - tolua_pushusertype(L, r, TOLUA_CAST "region"); - return 1; - } + int uid = (int)tolua_tonumber(L, 1, 0); + region * r = findregionbyid(uid); + tolua_pushusertype(L, r, TOLUA_CAST "region"); + return 1; +} - static int tolua_get_building(lua_State * L) +static int tolua_get_building(lua_State * L) { - int no = tolua_toid(L, 1, 0); - building * b = findbuilding(no); - tolua_pushusertype(L, b, TOLUA_CAST "building"); - return 1; - } + int no = tolua_toid(L, 1, 0); + building * b = findbuilding(no); + tolua_pushusertype(L, b, TOLUA_CAST "building"); + return 1; +} - static int tolua_get_ship(lua_State * L) +static int tolua_get_ship(lua_State * L) { - int no = tolua_toid(L, 1, 0); - ship * sh = findship(no); - tolua_pushusertype(L, sh, TOLUA_CAST "ship"); - return 1; - } + int no = tolua_toid(L, 1, 0); + ship * sh = findship(no); + tolua_pushusertype(L, sh, TOLUA_CAST "ship"); + return 1; +} - static int tolua_get_alliance(lua_State * L) +static int tolua_get_alliance(lua_State * L) { - int no = tolua_toid(L, 1, 0); - alliance * f = findalliance(no); - tolua_pushusertype(L, f, TOLUA_CAST "alliance"); - return 1; - } + int no = tolua_toid(L, 1, 0); + alliance * f = findalliance(no); + tolua_pushusertype(L, f, TOLUA_CAST "alliance"); + return 1; +} - static int tolua_get_unit(lua_State * L) +static int tolua_get_unit(lua_State * L) { - int no = tolua_toid(L, 1, 0); - unit * u = findunit(no); - tolua_pushusertype(L, u, TOLUA_CAST "unit"); - return 1; - } + int no = tolua_toid(L, 1, 0); + unit * u = findunit(no); + tolua_pushusertype(L, u, TOLUA_CAST "unit"); + return 1; +} - static int tolua_alliance_create(lua_State * L) +static int tolua_alliance_create(lua_State * L) { - int id = (int)tolua_tonumber(L, 1, 0); - const char *name = tolua_tostring(L, 2, 0); - alliance * alli = makealliance(id, name); - tolua_pushusertype(L, alli, TOLUA_CAST "alliance"); - return 1; - } + int id = (int)tolua_tonumber(L, 1, 0); + const char *name = tolua_tostring(L, 2, 0); + alliance * alli = makealliance(id, name); + tolua_pushusertype(L, alli, TOLUA_CAST "alliance"); + return 1; +} - static int tolua_get_regions(lua_State * L) +static int tolua_get_regions(lua_State * L) { - region ** region_ptr = (region **) lua_newuserdata(L, sizeof(region *)); - luaL_getmetatable(L, "region"); - lua_setmetatable(L, -2); - *region_ptr = regions; - lua_pushcclosure(L, tolua_regionlist_next, 1); - return 1; - } + region ** region_ptr = (region **) lua_newuserdata(L, sizeof(region *)); + luaL_getmetatable(L, "region"); + lua_setmetatable(L, -2); + *region_ptr = regions; + lua_pushcclosure(L, tolua_regionlist_next, 1); + return 1; +} - static int tolua_get_factions(lua_State * L) +static int tolua_get_factions(lua_State * L) { - faction ** faction_ptr = (faction **) lua_newuserdata(L, sizeof(faction *)); - luaL_getmetatable(L, "faction"); - lua_setmetatable(L, -2); - *faction_ptr = factions; - lua_pushcclosure(L, tolua_factionlist_next, 1); - return 1; - } + faction ** faction_ptr = (faction **) lua_newuserdata(L, sizeof(faction *)); + luaL_getmetatable(L, "faction"); + lua_setmetatable(L, -2); + *faction_ptr = factions; + lua_pushcclosure(L, tolua_factionlist_next, 1); + return 1; +} - static int tolua_get_alliance_factions(lua_State * L) +static int tolua_get_alliance_factions(lua_State * L) { - alliance * self = (alliance *) tolua_tousertype(L, 1, 0); - return tolua_quicklist_push(L, "faction_list", "faction", self->members); - } + alliance * self = (alliance *) tolua_tousertype(L, 1, 0); + return tolua_quicklist_push(L, "faction_list", "faction", self->members); +} - static int tolua_get_alliance_id(lua_State * L) +static int tolua_get_alliance_id(lua_State * L) { - alliance * self = (alliance *) tolua_tousertype(L, 1, 0); - tolua_pushnumber(L, (lua_Number) self->id); - return 1; - } + alliance * self = (alliance *) tolua_tousertype(L, 1, 0); + tolua_pushnumber(L, (lua_Number) self->id); + return 1; +} - static int tolua_get_alliance_name(lua_State * L) +static int tolua_get_alliance_name(lua_State * L) { - alliance * self = (alliance *) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->name); - return 1; - } + alliance * self = (alliance *) tolua_tousertype(L, 1, 0); + tolua_pushstring(L, self->name); + return 1; +} - static int tolua_set_alliance_name(lua_State * L) +static int tolua_set_alliance_name(lua_State * L) { - alliance * self = (alliance *) tolua_tousertype(L, 1, 0); - alliance_setname(self, tolua_tostring(L, 2, 0)); - return 0; - } + alliance * self = (alliance *) tolua_tousertype(L, 1, 0); + alliance_setname(self, tolua_tostring(L, 2, 0)); + return 0; +} - -#include -#include -#include -#include -static int tolua_write_spells(lua_State * L) + +#include +#include +#include +#include +static int tolua_write_spells(lua_State * L) { - spell_f fun = (spell_f) get_function("lua_castspell"); - const char *filename = "magic.xml"; - xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); - xmlNodePtr root = xmlNewNode(NULL, BAD_CAST "spells"); - quicklist * ql; - int qi; - for (ql = spells, qi = 0; ql; ql_advance(&ql, &qi, 1)) { - spell * sp = (spell *) ql_get(ql, qi); - if (sp->sp_function != fun) { - int combat = 0; - xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "spell"); - xmlNewProp(node, BAD_CAST "name", BAD_CAST sp->sname); - xmlNewProp(node, BAD_CAST "type", BAD_CAST magic_school[sp->magietyp]); - xmlNewProp(node, BAD_CAST "rank", xml_i(sp->rank)); - xmlNewProp(node, BAD_CAST "level", xml_i(sp->level)); - xmlNewProp(node, BAD_CAST "index", xml_i(sp->id)); - if (sp->syntax) - xmlNewProp(node, BAD_CAST "syntax", BAD_CAST sp->syntax); - if (sp->parameter) - xmlNewProp(node, BAD_CAST "parameters", BAD_CAST sp->parameter); - if (sp->components) { - spell_component * comp = sp->components; - for (; comp->type != 0; ++comp) { - static const char *costs[] = { "fixed", "level", "linear" }; - xmlNodePtr cnode = xmlNewNode(NULL, BAD_CAST "resource"); - xmlNewProp(cnode, BAD_CAST "name", BAD_CAST comp->type->_name[0]); - xmlNewProp(cnode, BAD_CAST "amount", xml_i(comp->amount)); - xmlNewProp(cnode, BAD_CAST "cost", BAD_CAST costs[comp->cost]); - xmlAddChild(node, cnode); - }} - if (sp->sptyp & TESTCANSEE) { - xmlNewProp(node, BAD_CAST "los", BAD_CAST "true"); - } - if (sp->sptyp & ONSHIPCAST) { - xmlNewProp(node, BAD_CAST "ship", BAD_CAST "true"); - } - if (sp->sptyp & OCEANCASTABLE) { - xmlNewProp(node, BAD_CAST "ocean", BAD_CAST "true"); - } - if (sp->sptyp & FARCASTING) { - xmlNewProp(node, BAD_CAST "far", BAD_CAST "true"); - } - if (sp->sptyp & SPELLLEVEL) { - xmlNewProp(node, BAD_CAST "variable", BAD_CAST "true"); - } - if (sp->sptyp & POSTCOMBATSPELL) - combat = 3; - + spell_f fun = (spell_f) get_function("lua_castspell"); + const char *filename = "magic.xml"; + xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); + xmlNodePtr root = xmlNewNode(NULL, BAD_CAST "spells"); + quicklist * ql; + int qi; + for (ql = spells, qi = 0; ql; ql_advance(&ql, &qi, 1)) { + spell * sp = (spell *) ql_get(ql, qi); + if (sp->sp_function != fun) { + int combat = 0; + xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "spell"); + xmlNewProp(node, BAD_CAST "name", BAD_CAST sp->sname); + xmlNewProp(node, BAD_CAST "type", BAD_CAST magic_school[sp->magietyp]); + xmlNewProp(node, BAD_CAST "rank", xml_i(sp->rank)); + xmlNewProp(node, BAD_CAST "level", xml_i(sp->level)); + xmlNewProp(node, BAD_CAST "index", xml_i(sp->id)); + if (sp->syntax) + xmlNewProp(node, BAD_CAST "syntax", BAD_CAST sp->syntax); + if (sp->parameter) + xmlNewProp(node, BAD_CAST "parameters", BAD_CAST sp->parameter); + if (sp->components) { + spell_component * comp = sp->components; + for (; comp->type != 0; ++comp) { + static const char *costs[] = { "fixed", "level", "linear" }; + xmlNodePtr cnode = xmlNewNode(NULL, BAD_CAST "resource"); + xmlNewProp(cnode, BAD_CAST "name", BAD_CAST comp->type->_name[0]); + xmlNewProp(cnode, BAD_CAST "amount", xml_i(comp->amount)); + xmlNewProp(cnode, BAD_CAST "cost", BAD_CAST costs[comp->cost]); + xmlAddChild(node, cnode); + }} + if (sp->sptyp & TESTCANSEE) { + xmlNewProp(node, BAD_CAST "los", BAD_CAST "true"); + } + if (sp->sptyp & ONSHIPCAST) { + xmlNewProp(node, BAD_CAST "ship", BAD_CAST "true"); + } + if (sp->sptyp & OCEANCASTABLE) { + xmlNewProp(node, BAD_CAST "ocean", BAD_CAST "true"); + } + if (sp->sptyp & FARCASTING) { + xmlNewProp(node, BAD_CAST "far", BAD_CAST "true"); + } + if (sp->sptyp & SPELLLEVEL) { + xmlNewProp(node, BAD_CAST "variable", BAD_CAST "true"); + } + if (sp->sptyp & POSTCOMBATSPELL) + combat = 3; + else if (sp->sptyp & COMBATSPELL) - combat = 2; - + combat = 2; + else if (sp->sptyp & PRECOMBATSPELL) - combat = 1; - if (combat) { - xmlNewProp(node, BAD_CAST "combat", xml_i(combat)); - } - xmlAddChild(root, node); - } - } - xmlDocSetRootElement(doc, root); - xmlKeepBlanksDefault(0); - xmlSaveFormatFileEnc(filename, doc, "utf-8", 1); - xmlFreeDoc(doc); - return 0; - } + combat = 1; + if (combat) { + xmlNewProp(node, BAD_CAST "combat", xml_i(combat)); + } + xmlAddChild(root, node); + } + } + xmlDocSetRootElement(doc, root); + xmlKeepBlanksDefault(0); + xmlSaveFormatFileEnc(filename, doc, "utf-8", 1); + xmlFreeDoc(doc); + return 0; +} - static int config_get_ships(lua_State * L) +static int config_get_ships(lua_State * L) { - quicklist * ql; - int qi, i = 0; - lua_createtable(L, ql_length(shiptypes), 0); - for (qi = 0, ql = shiptypes; ql; ql_advance(&ql, &qi, 1)) { - ship_type * stype = (ship_type *) ql_get(ql, qi); - tolua_pushstring(L, TOLUA_CAST stype->name[0]); - lua_rawseti(L, -2, ++i); - } - return 1; - } + quicklist * ql; + int qi, i = 0; + lua_createtable(L, ql_length(shiptypes), 0); + for (qi = 0, ql = shiptypes; ql; ql_advance(&ql, &qi, 1)) { + ship_type * stype = (ship_type *) ql_get(ql, qi); + tolua_pushstring(L, TOLUA_CAST stype->name[0]); + lua_rawseti(L, -2, ++i); + } + return 1; +} - static int config_get_locales(lua_State * L) +static int config_get_locales(lua_State * L) { - const struct locale *lang; - int i = 0, n = 0; - for (lang = locales; lang; lang = nextlocale(lang)) - ++n; - lua_createtable(L, n, 0); - for (lang = locales; lang; lang = nextlocale(lang)) { - tolua_pushstring(L, TOLUA_CAST locale_name(lang)); - lua_rawseti(L, -2, ++i); - } - return 1; - } + const struct locale *lang; + int i = 0, n = 0; + for (lang = locales; lang; lang = nextlocale(lang)) + ++n; + lua_createtable(L, n, 0); + for (lang = locales; lang; lang = nextlocale(lang)) { + tolua_pushstring(L, TOLUA_CAST locale_name(lang)); + lua_rawseti(L, -2, ++i); + } + return 1; +} - static int config_get_resource(lua_State * L) +static int config_get_resource(lua_State * L) { - const char *name = tolua_tostring(L, 1, 0); - if (name) { - const struct item_type *itype = it_find(name); - if (itype) { - lua_newtable(L); - lua_pushstring(L, "weight"); - lua_pushinteger(L, itype->weight); - lua_settable(L, -3); - if (itype->capacity > 0) { - lua_pushstring(L, "capacity"); - lua_pushinteger(L, itype->capacity); - lua_settable(L, -3); - } - if (itype->construction) { - int i; - lua_pushstring(L, "build_skill_min"); - lua_pushinteger(L, itype->construction->minskill); - lua_settable(L, -3); - lua_pushstring(L, "build_skill_name"); - lua_pushstring(L, skillnames[itype->construction->skill]); - lua_settable(L, -3); - if (itype->construction->materials) { - lua_pushstring(L, "materials"); - lua_newtable(L); - for (i = 0; itype->construction->materials[i].number; ++i) { - lua_pushstring(L, - itype->construction->materials[i].rtype->_name[0]); - lua_pushinteger(L, itype->construction->materials[i].number); - lua_settable(L, -3); - } - lua_settable(L, -3); - } - } - return 1; - } - } - return 0; - } + const char *name = tolua_tostring(L, 1, 0); + if (name) { + const struct item_type *itype = it_find(name); + if (itype) { + lua_newtable(L); + lua_pushstring(L, "weight"); + lua_pushinteger(L, itype->weight); + lua_settable(L, -3); + if (itype->capacity > 0) { + lua_pushstring(L, "capacity"); + lua_pushinteger(L, itype->capacity); + lua_settable(L, -3); + } + if (itype->construction) { + int i; + lua_pushstring(L, "build_skill_min"); + lua_pushinteger(L, itype->construction->minskill); + lua_settable(L, -3); + lua_pushstring(L, "build_skill_name"); + lua_pushstring(L, skillnames[itype->construction->skill]); + lua_settable(L, -3); + if (itype->construction->materials) { + lua_pushstring(L, "materials"); + lua_newtable(L); + for (i = 0; itype->construction->materials[i].number; ++i) { + lua_pushstring(L, + itype->construction->materials[i].rtype->_name[0]); + lua_pushinteger(L, itype->construction->materials[i].number); + lua_settable(L, -3); + } + lua_settable(L, -3); + } + } + return 1; + } + } + return 0; +} - static int tolua_get_spell_text(lua_State * L) +static int tolua_get_spell_text(lua_State * L) { - const struct locale *loc = default_locale; - spell * self = (spell *) tolua_tousertype(L, 1, 0); - lua_pushstring(L, spell_info(self, loc)); - return 1; - } + const struct locale *loc = default_locale; + spell * self = (spell *) tolua_tousertype(L, 1, 0); + lua_pushstring(L, spell_info(self, loc)); + return 1; +} - static int tolua_get_spell_school(lua_State * L) +static int tolua_get_spell_school(lua_State * L) { - spell * self = (spell *) tolua_tousertype(L, 1, 0); - lua_pushstring(L, magic_school[self->magietyp]); - return 1; - } + spell * self = (spell *) tolua_tousertype(L, 1, 0); + lua_pushstring(L, magic_school[self->magietyp]); + return 1; +} - static int tolua_get_spell_level(lua_State * L) +static int tolua_get_spell_level(lua_State * L) { - spell * self = (spell *) tolua_tousertype(L, 1, 0); - lua_pushnumber(L, self->level); - return 1; - } + spell * self = (spell *) tolua_tousertype(L, 1, 0); + lua_pushnumber(L, self->level); + return 1; +} - static int tolua_get_spell_name(lua_State * L) +static int tolua_get_spell_name(lua_State * L) { - const struct locale *lang = default_locale; - spell * self = (spell *) tolua_tousertype(L, 1, 0); - lua_pushstring(L, spell_name(self, lang)); - return 1; - } + const struct locale *lang = default_locale; + spell * self = (spell *) tolua_tousertype(L, 1, 0); + lua_pushstring(L, spell_name(self, lang)); + return 1; +} - static int tolua_get_spells(lua_State * L) +static int tolua_get_spells(lua_State * L) { - return tolua_quicklist_push(L, "spell_list", "spell", spells); - } + return tolua_quicklist_push(L, "spell_list", "spell", spells); +} - int tolua_read_xml(lua_State * L) +int tolua_read_xml(lua_State * L) { - const char *filename = tolua_tostring(L, 1, 0); - const char *catalog = tolua_tostring(L, 2, 0); - init_data(filename, catalog); - return 0; - } + const char *filename = tolua_tostring(L, 1, 0); + const char *catalog = tolua_tostring(L, 2, 0); + init_data(filename, catalog); + return 0; +} - int tolua_process_markets(lua_State * L) +int tolua_process_markets(lua_State * L) { - do_markets(); - return 0; - } + do_markets(); + return 0; +} - int tolua_process_produce(lua_State * L) +int tolua_process_produce(lua_State * L) { - region * r; - for (r = regions; r; r = r->next) { - produce(r); - } - return 0; - } + region * r; + for (r = regions; r; r = r->next) { + produce(r); + } + return 0; +} - typedef struct event_args { - int hfunction; - int hargs; - const char *sendertype; - } event_args; - static void args_free(void *udata) +typedef struct event_args { + int hfunction; + int hargs; + const char *sendertype; +} event_args; +static void args_free(void *udata) { - free(udata); - } static void event_cb(void *sender, const char *event, void *udata) + free(udata); +} static void event_cb(void *sender, const char *event, void *udata) { - lua_State * L = (lua_State *) global.vm_state; - event_args * args = (event_args *) udata; - int nargs = 2; - lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); - if (sender && args->sendertype) { - tolua_pushusertype(L, sender, TOLUA_CAST args->sendertype); - } else { - lua_pushnil(L); - } - tolua_pushstring(L, event); - if (args->hargs) { - lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); - ++nargs; - } - lua_pcall(L, nargs, 0, 0); - } + lua_State * L = (lua_State *) global.vm_state; + event_args * args = (event_args *) udata; + int nargs = 2; + lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); + if (sender && args->sendertype) { + tolua_pushusertype(L, sender, TOLUA_CAST args->sendertype); + } else { + lua_pushnil(L); + } + tolua_pushstring(L, event); + if (args->hargs) { + lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); + ++nargs; + } + lua_pcall(L, nargs, 0, 0); +} - static int tolua_eventbus_register(lua_State * L) +static int tolua_eventbus_register(lua_State * L) { - - /* parameters: - ** 1: sender (usertype) - ** 2: event (string) - ** 3: handler (function) - ** 4: arguments (any, *optional*) - */ + + /* parameters: + ** 1: sender (usertype) + ** 2: event (string) + ** 3: handler (function) + ** 4: arguments (any, *optional*) + */ void *sender = tolua_tousertype(L, 1, 0); - const char *event = tolua_tostring(L, 2, 0); - event_args * args = malloc(sizeof(event_args)); - args->sendertype = sender ? tolua_typename(L, 1) : NULL; - lua_pushvalue(L, 3); - args->hfunction = luaL_ref(L, LUA_REGISTRYINDEX); - if (lua_type(L, 4) != LUA_TNONE) { - lua_pushvalue(L, 4); - args->hargs = luaL_ref(L, LUA_REGISTRYINDEX); - } else { - args->hargs = 0; - } - eventbus_register(sender, event, &event_cb, &args_free, args); - return 0; - } + const char *event = tolua_tostring(L, 2, 0); + event_args * args = malloc(sizeof(event_args)); + args->sendertype = sender ? tolua_typename(L, 1) : NULL; + lua_pushvalue(L, 3); + args->hfunction = luaL_ref(L, LUA_REGISTRYINDEX); + if (lua_type(L, 4) != LUA_TNONE) { + lua_pushvalue(L, 4); + args->hargs = luaL_ref(L, LUA_REGISTRYINDEX); + } else { + args->hargs = 0; + } + eventbus_register(sender, event, &event_cb, &args_free, args); + return 0; +} - static int tolua_eventbus_fire(lua_State * L) +static int tolua_eventbus_fire(lua_State * L) { - void *sender = tolua_tousertype(L, 1, 0); - const char *event = tolua_tostring(L, 2, 0); - void *args = NULL; - eventbus_fire(sender, event, args); - return 0; - } + void *sender = tolua_tousertype(L, 1, 0); + const char *event = tolua_tostring(L, 2, 0); + void *args = NULL; + eventbus_fire(sender, event, args); + return 0; +} - static int tolua_report_unit(lua_State * L) +static int tolua_report_unit(lua_State * L) { - char buffer[512]; - unit * u = (unit *) tolua_tousertype(L, 1, 0); - faction * f = (faction *) tolua_tousertype(L, 2, 0); - bufunit(f, u, 0, see_unit, buffer, sizeof(buffer)); - tolua_pushstring(L, buffer); - return 1; - } + char buffer[512]; + unit * u = (unit *) tolua_tousertype(L, 1, 0); + faction * f = (faction *) tolua_tousertype(L, 2, 0); + bufunit(f, u, 0, see_unit, buffer, sizeof(buffer)); + tolua_pushstring(L, buffer); + return 1; +} - static int tolua_settings_get(lua_State * L) +static int tolua_settings_get(lua_State * L) { - const char *name = tolua_tostring(L, 1, 0); - tolua_pushstring(L, get_param(global.parameters, name)); - return 1; - } + const char *name = tolua_tostring(L, 1, 0); + tolua_pushstring(L, get_param(global.parameters, name)); + return 1; +} - static int tolua_settings_set(lua_State * L) +static int tolua_settings_set(lua_State * L) { - const char *name = tolua_tostring(L, 1, 0); - const char *value = tolua_tostring(L, 2, 0); - set_param(&global.parameters, name, value); - return 0; - } + const char *name = tolua_tostring(L, 1, 0); + const char *value = tolua_tostring(L, 2, 0); + set_param(&global.parameters, name, value); + return 0; +} - static void -parse_inifile(lua_State * L, dictionary * d, const char *section) +static void +parse_inifile(lua_State * L, dictionary * d, const char *section) { - int i; - size_t len = strlen(section); - for (i = 0; d && i != d->n; ++i) { - const char *key = d->key[i]; - if (strncmp(section, key, len) == 0 && key[len] == ':') { - const char *str_value = d->val[i]; - char *endp; - double num_value = strtod(str_value, &endp); - lua_pushstring(L, key + len + 1); - if (*endp) { - tolua_pushstring(L, str_value); - } else { - tolua_pushnumber(L, num_value); - } - lua_rawset(L, -3); - } - } - - /* special case */ + int i; + size_t len = strlen(section); + for (i = 0; d && i != d->n; ++i) { + const char *key = d->key[i]; + if (strncmp(section, key, len) == 0 && key[len] == ':') { + const char *str_value = d->val[i]; + char *endp; + double num_value = strtod(str_value, &endp); + lua_pushstring(L, key + len + 1); + if (*endp) { + tolua_pushstring(L, str_value); + } else { + tolua_pushnumber(L, num_value); + } + lua_rawset(L, -3); + } + } + + /* special case */ lua_pushstring(L, "basepath"); - lua_pushstring(L, basepath()); - lua_rawset(L, -3); - } + lua_pushstring(L, basepath()); + lua_rawset(L, -3); +} - int tolua_eressea_open(lua_State * L) +int tolua_eressea_open(lua_State * L) { - tolua_open(L); - - /* register user types */ + tolua_open(L); + + /* register user types */ tolua_usertype(L, TOLUA_CAST "spell"); - tolua_usertype(L, TOLUA_CAST "spell_list"); - tolua_usertype(L, TOLUA_CAST "order"); - tolua_usertype(L, TOLUA_CAST "item"); - tolua_usertype(L, TOLUA_CAST "alliance"); - tolua_usertype(L, TOLUA_CAST "event"); - tolua_usertype(L, TOLUA_CAST "faction_list"); - tolua_module(L, NULL, 0); - tolua_beginmodule(L, NULL); - { - tolua_module(L, "process", 0); - tolua_beginmodule(L, "process"); - { - tolua_function(L, "markets", &tolua_process_markets); - tolua_function(L, "produce", &tolua_process_produce); - } tolua_endmodule(L); - tolua_cclass(L, TOLUA_CAST "alliance", TOLUA_CAST "alliance", - TOLUA_CAST "", NULL); - tolua_beginmodule(L, TOLUA_CAST "alliance"); - { - tolua_variable(L, TOLUA_CAST "name", tolua_get_alliance_name, - tolua_set_alliance_name); - tolua_variable(L, TOLUA_CAST "id", tolua_get_alliance_id, NULL); - tolua_variable(L, TOLUA_CAST "factions", &tolua_get_alliance_factions, - NULL); - tolua_function(L, TOLUA_CAST "create", tolua_alliance_create); - } tolua_endmodule(L); - tolua_cclass(L, TOLUA_CAST "spell", TOLUA_CAST "spell", TOLUA_CAST "", - NULL); - tolua_beginmodule(L, TOLUA_CAST "spell"); - { - tolua_function(L, TOLUA_CAST "__tostring", tolua_get_spell_name); - tolua_variable(L, TOLUA_CAST "name", tolua_get_spell_name, 0); - tolua_variable(L, TOLUA_CAST "school", tolua_get_spell_school, 0); - tolua_variable(L, TOLUA_CAST "level", tolua_get_spell_level, 0); - tolua_variable(L, TOLUA_CAST "text", tolua_get_spell_text, 0); - } tolua_endmodule(L); - tolua_module(L, TOLUA_CAST "eventbus", 1); - tolua_beginmodule(L, TOLUA_CAST "eventbus"); - { - tolua_function(L, TOLUA_CAST "register", &tolua_eventbus_register); - tolua_function(L, TOLUA_CAST "fire", &tolua_eventbus_fire); - } tolua_endmodule(L); - tolua_module(L, TOLUA_CAST "settings", 1); - tolua_beginmodule(L, TOLUA_CAST "settings"); - { - tolua_function(L, TOLUA_CAST "set", &tolua_settings_set); - tolua_function(L, TOLUA_CAST "get", &tolua_settings_get); - } tolua_endmodule(L); - tolua_module(L, TOLUA_CAST "report", 1); - tolua_beginmodule(L, TOLUA_CAST "report"); - { - tolua_function(L, TOLUA_CAST "report_unit", &tolua_report_unit); - } tolua_endmodule(L); - tolua_module(L, TOLUA_CAST "config", 1); - tolua_beginmodule(L, TOLUA_CAST "config"); - { - parse_inifile(L, global.inifile, "config"); - tolua_variable(L, TOLUA_CAST "locales", &config_get_locales, 0); - tolua_function(L, TOLUA_CAST "get_resource", &config_get_resource); - tolua_variable(L, TOLUA_CAST "ships", &config_get_ships, 0); - } tolua_endmodule(L); - tolua_function(L, TOLUA_CAST "get_region_by_id", tolua_get_region_byid); - tolua_function(L, TOLUA_CAST "get_faction", tolua_get_faction); - tolua_function(L, TOLUA_CAST "get_unit", tolua_get_unit); - tolua_function(L, TOLUA_CAST "get_alliance", tolua_get_alliance); - tolua_function(L, TOLUA_CAST "get_ship", tolua_get_ship), - tolua_function(L, TOLUA_CAST "get_building", tolua_get_building), - tolua_function(L, TOLUA_CAST "get_region", tolua_get_region), - // deprecated_function(L, TOLUA_CAST "add_faction"); - // deprecated_function(L, TOLUA_CAST "faction_origin"); + tolua_usertype(L, TOLUA_CAST "spell_list"); + tolua_usertype(L, TOLUA_CAST "order"); + tolua_usertype(L, TOLUA_CAST "item"); + tolua_usertype(L, TOLUA_CAST "alliance"); + tolua_usertype(L, TOLUA_CAST "event"); + tolua_usertype(L, TOLUA_CAST "faction_list"); + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_module(L, "process", 0); + tolua_beginmodule(L, "process"); + { + tolua_function(L, "markets", &tolua_process_markets); + tolua_function(L, "produce", &tolua_process_produce); + } tolua_endmodule(L); + tolua_cclass(L, TOLUA_CAST "alliance", TOLUA_CAST "alliance", + TOLUA_CAST "", NULL); + tolua_beginmodule(L, TOLUA_CAST "alliance"); + { + tolua_variable(L, TOLUA_CAST "name", tolua_get_alliance_name, + tolua_set_alliance_name); + tolua_variable(L, TOLUA_CAST "id", tolua_get_alliance_id, NULL); + tolua_variable(L, TOLUA_CAST "factions", &tolua_get_alliance_factions, + NULL); + tolua_function(L, TOLUA_CAST "create", tolua_alliance_create); + } tolua_endmodule(L); + tolua_cclass(L, TOLUA_CAST "spell", TOLUA_CAST "spell", TOLUA_CAST "", + NULL); + tolua_beginmodule(L, TOLUA_CAST "spell"); + { + tolua_function(L, TOLUA_CAST "__tostring", tolua_get_spell_name); + tolua_variable(L, TOLUA_CAST "name", tolua_get_spell_name, 0); + tolua_variable(L, TOLUA_CAST "school", tolua_get_spell_school, 0); + tolua_variable(L, TOLUA_CAST "level", tolua_get_spell_level, 0); + tolua_variable(L, TOLUA_CAST "text", tolua_get_spell_text, 0); + } tolua_endmodule(L); + tolua_module(L, TOLUA_CAST "eventbus", 1); + tolua_beginmodule(L, TOLUA_CAST "eventbus"); + { + tolua_function(L, TOLUA_CAST "register", &tolua_eventbus_register); + tolua_function(L, TOLUA_CAST "fire", &tolua_eventbus_fire); + } tolua_endmodule(L); + tolua_module(L, TOLUA_CAST "settings", 1); + tolua_beginmodule(L, TOLUA_CAST "settings"); + { + tolua_function(L, TOLUA_CAST "set", &tolua_settings_set); + tolua_function(L, TOLUA_CAST "get", &tolua_settings_get); + } tolua_endmodule(L); + tolua_module(L, TOLUA_CAST "report", 1); + tolua_beginmodule(L, TOLUA_CAST "report"); + { + tolua_function(L, TOLUA_CAST "report_unit", &tolua_report_unit); + } tolua_endmodule(L); + tolua_module(L, TOLUA_CAST "config", 1); + tolua_beginmodule(L, TOLUA_CAST "config"); + { + parse_inifile(L, global.inifile, "config"); + tolua_variable(L, TOLUA_CAST "locales", &config_get_locales, 0); + tolua_function(L, TOLUA_CAST "get_resource", &config_get_resource); + tolua_variable(L, TOLUA_CAST "ships", &config_get_ships, 0); + } tolua_endmodule(L); + tolua_function(L, TOLUA_CAST "get_region_by_id", tolua_get_region_byid); + tolua_function(L, TOLUA_CAST "get_faction", tolua_get_faction); + tolua_function(L, TOLUA_CAST "get_unit", tolua_get_unit); + tolua_function(L, TOLUA_CAST "get_alliance", tolua_get_alliance); + tolua_function(L, TOLUA_CAST "get_ship", tolua_get_ship), + tolua_function(L, TOLUA_CAST "get_building", tolua_get_building), + tolua_function(L, TOLUA_CAST "get_region", tolua_get_region), + // deprecated_function(L, TOLUA_CAST "add_faction"); + // deprecated_function(L, TOLUA_CAST "faction_origin"); tolua_function(L, TOLUA_CAST "factions", tolua_get_factions); - tolua_function(L, TOLUA_CAST "regions", tolua_get_regions); - tolua_function(L, TOLUA_CAST "read_turn", tolua_read_turn); - tolua_function(L, TOLUA_CAST "read_game", tolua_read_game); - tolua_function(L, TOLUA_CAST "write_game", tolua_write_game); - tolua_function(L, TOLUA_CAST "free_game", tolua_free_game); - tolua_function(L, TOLUA_CAST "write_map", &tolua_write_map); - tolua_function(L, TOLUA_CAST "read_orders", tolua_read_orders); - tolua_function(L, TOLUA_CAST "process_orders", tolua_process_orders); - tolua_function(L, TOLUA_CAST "init_reports", tolua_init_reports); - tolua_function(L, TOLUA_CAST "write_reports", tolua_write_reports); - tolua_function(L, TOLUA_CAST "write_report", tolua_write_report); - tolua_function(L, TOLUA_CAST "init_summary", tolua_init_summary); - tolua_function(L, TOLUA_CAST "write_summary", tolua_write_summary); - tolua_function(L, TOLUA_CAST "write_passwords", tolua_write_passwords), - tolua_function(L, TOLUA_CAST "message_unit", tolua_message_unit); - tolua_function(L, TOLUA_CAST "message_faction", tolua_message_faction); - tolua_function(L, TOLUA_CAST "message_region", tolua_message_region); - - /* scripted monsters */ + tolua_function(L, TOLUA_CAST "regions", tolua_get_regions); + tolua_function(L, TOLUA_CAST "read_turn", tolua_read_turn); + tolua_function(L, TOLUA_CAST "read_game", tolua_read_game); + tolua_function(L, TOLUA_CAST "write_game", tolua_write_game); + tolua_function(L, TOLUA_CAST "free_game", tolua_free_game); + tolua_function(L, TOLUA_CAST "write_map", &tolua_write_map); + tolua_function(L, TOLUA_CAST "read_orders", tolua_read_orders); + tolua_function(L, TOLUA_CAST "process_orders", tolua_process_orders); + tolua_function(L, TOLUA_CAST "init_reports", tolua_init_reports); + tolua_function(L, TOLUA_CAST "write_reports", tolua_write_reports); + tolua_function(L, TOLUA_CAST "write_report", tolua_write_report); + tolua_function(L, TOLUA_CAST "init_summary", tolua_init_summary); + tolua_function(L, TOLUA_CAST "write_summary", tolua_write_summary); + tolua_function(L, TOLUA_CAST "write_passwords", tolua_write_passwords), + tolua_function(L, TOLUA_CAST "message_unit", tolua_message_unit); + tolua_function(L, TOLUA_CAST "message_faction", tolua_message_faction); + tolua_function(L, TOLUA_CAST "message_region", tolua_message_region); + + /* scripted monsters */ tolua_function(L, TOLUA_CAST "spawn_braineaters", - tolua_spawn_braineaters); - -#ifdef TODO_FOSS - /* spells and stuff */ + tolua_spawn_braineaters); + +#ifdef TODO_FOSS + /* spells and stuff */ tolua_function(L, TOLUA_CAST "levitate_ship", tolua_levitate_ship); - -#endif /* */ + +#endif /* */ tolua_function(L, TOLUA_CAST "update_guards", tolua_update_guards); - tolua_function(L, TOLUA_CAST "set_turn", &tolua_set_turn); - tolua_function(L, TOLUA_CAST "get_turn", &tolua_get_turn); - tolua_function(L, TOLUA_CAST "get_season", tolua_get_season); - tolua_function(L, TOLUA_CAST "equipment_setitem", - tolua_equipment_setitem); - tolua_function(L, TOLUA_CAST "equip_unit", tolua_equipunit); - tolua_function(L, TOLUA_CAST "add_equipment", tolua_addequipment); - tolua_function(L, TOLUA_CAST "atoi36", tolua_atoi36); - tolua_function(L, TOLUA_CAST "itoa36", tolua_itoa36); - tolua_function(L, TOLUA_CAST "dice_roll", tolua_dice_rand); - tolua_function(L, TOLUA_CAST "get_nmrs", tolua_get_nmrs); - tolua_function(L, TOLUA_CAST "remove_empty_units", - tolua_remove_empty_units); - tolua_function(L, TOLUA_CAST "update_subscriptions", - tolua_update_subscriptions); - tolua_function(L, TOLUA_CAST "update_scores", tolua_update_scores); - tolua_function(L, TOLUA_CAST "update_owners", tolua_update_owners); - tolua_function(L, TOLUA_CAST "learn_skill", tolua_learn_skill); - tolua_function(L, TOLUA_CAST "create_curse", tolua_create_curse); - tolua_function(L, TOLUA_CAST "autoseed", tolua_autoseed); - tolua_function(L, TOLUA_CAST "get_key", tolua_getkey); - tolua_function(L, TOLUA_CAST "set_key", tolua_setkey); - tolua_function(L, TOLUA_CAST "translate", &tolua_translate); - tolua_function(L, TOLUA_CAST "rng_int", tolua_rng_int); - tolua_function(L, TOLUA_CAST "spells", tolua_get_spells); - tolua_function(L, TOLUA_CAST "write_spells", tolua_write_spells); - tolua_function(L, TOLUA_CAST "read_xml", tolua_read_xml); - } tolua_endmodule(L); - return 1; - } + tolua_function(L, TOLUA_CAST "set_turn", &tolua_set_turn); + tolua_function(L, TOLUA_CAST "get_turn", &tolua_get_turn); + tolua_function(L, TOLUA_CAST "get_season", tolua_get_season); + tolua_function(L, TOLUA_CAST "equipment_setitem", + tolua_equipment_setitem); + tolua_function(L, TOLUA_CAST "equip_unit", tolua_equipunit); + tolua_function(L, TOLUA_CAST "add_equipment", tolua_addequipment); + tolua_function(L, TOLUA_CAST "atoi36", tolua_atoi36); + tolua_function(L, TOLUA_CAST "itoa36", tolua_itoa36); + tolua_function(L, TOLUA_CAST "dice_roll", tolua_dice_rand); + tolua_function(L, TOLUA_CAST "get_nmrs", tolua_get_nmrs); + tolua_function(L, TOLUA_CAST "remove_empty_units", + tolua_remove_empty_units); + tolua_function(L, TOLUA_CAST "update_subscriptions", + tolua_update_subscriptions); + tolua_function(L, TOLUA_CAST "update_scores", tolua_update_scores); + tolua_function(L, TOLUA_CAST "update_owners", tolua_update_owners); + tolua_function(L, TOLUA_CAST "learn_skill", tolua_learn_skill); + tolua_function(L, TOLUA_CAST "create_curse", tolua_create_curse); + tolua_function(L, TOLUA_CAST "autoseed", tolua_autoseed); + tolua_function(L, TOLUA_CAST "get_key", tolua_getkey); + tolua_function(L, TOLUA_CAST "set_key", tolua_setkey); + tolua_function(L, TOLUA_CAST "translate", &tolua_translate); + tolua_function(L, TOLUA_CAST "rng_int", tolua_rng_int); + tolua_function(L, TOLUA_CAST "spells", tolua_get_spells); + tolua_function(L, TOLUA_CAST "write_spells", tolua_write_spells); + tolua_function(L, TOLUA_CAST "read_xml", tolua_read_xml); + } tolua_endmodule(L); + return 1; +} + - From 78b7dcd727ec4665499456fd151b8163e856f30d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 6 Mar 2011 23:40:55 -0800 Subject: [PATCH 112/400] more indentation cleanup --- src/bindings/bindings.c | 108 ++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 70 deletions(-) diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index d6a5efaa9..94cdf3b8a 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -66,6 +66,7 @@ without prior permission by the authors of Eressea. #include #include + int log_lua_error(lua_State * L) { const char *error = lua_tostring(L, -1); @@ -85,9 +86,7 @@ int tolua_orderlist_next(lua_State * L) *order_ptr = ord->next; return 1; } - - else - return 0; /* no more values to return */ + return 0; } static int tolua_quicklist_iter(lua_State * L) @@ -104,9 +103,7 @@ static int tolua_quicklist_iter(lua_State * L) lua_replace(L, lua_upvalueindex(2)); return 1; } - - else - return 0; /* no more values to return */ + return 0; } int tolua_quicklist_push(struct lua_State *L, const char *list_type, @@ -136,9 +133,7 @@ int tolua_itemlist_next(lua_State * L) *item_ptr = itm->next; return 1; } - - else - return 0; /* no more values to return */ + return 0; } static int tolua_autoseed(lua_State * L) @@ -431,21 +426,6 @@ static int tolua_equipment_setitem(lua_State * L) return 1; } - -#ifdef TODO_FOSS -static int tolua_levitate_ship(lua_State * L) -{ - ship * sh = (ship *) tolua_tousertype(L, 1, 0); - unit * mage = (unit *) tolua_tousertype(L, 2, 0); - double power = (double)tolua_tonumber(L, 3, 0); - int duration = (int)tolua_tonumber(L, 4, 0); - int cno = levitate_ship(sh, mage, power, duration); - tolua_pushnumber(L, (lua_Number) cno); - return 1; -} - - -#endif /* */ static int tolua_spawn_braineaters(lua_State * L) { float chance = (float)tolua_tonumber(L, 1, 0); @@ -495,7 +475,6 @@ static void reset_game(void) if (r->land && r->land->ownership && r->land->ownership->owner) { faction * owner = r->land->ownership->owner; if (owner == get_monsters()) { - /* some compat-fix, i believe. */ owner = update_owners(r); } @@ -908,10 +887,13 @@ typedef struct event_args { int hargs; const char *sendertype; } event_args; + static void args_free(void *udata) { free(udata); -} static void event_cb(void *sender, const char *event, void *udata) +} + +static void event_cb(void *sender, const char *event, void *udata) { lua_State * L = (lua_State *) global.vm_state; event_args * args = (event_args *) udata; @@ -930,15 +912,14 @@ static void args_free(void *udata) lua_pcall(L, nargs, 0, 0); } +/* arguments: + * 1: sender (usertype) + * 2: event (string) + * 3: handler (function) + * 4: arguments (any, *optional*) +**/ static int tolua_eventbus_register(lua_State * L) { - - /* parameters: - ** 1: sender (usertype) - ** 2: event (string) - ** 3: handler (function) - ** 4: arguments (any, *optional*) - */ void *sender = tolua_tousertype(L, 1, 0); const char *event = tolua_tostring(L, 2, 0); event_args * args = malloc(sizeof(event_args)); @@ -1020,8 +1001,8 @@ int tolua_eressea_open(lua_State * L) { tolua_open(L); - /* register user types */ - tolua_usertype(L, TOLUA_CAST "spell"); + /* register user types */ + tolua_usertype(L, TOLUA_CAST "spell"); tolua_usertype(L, TOLUA_CAST "spell_list"); tolua_usertype(L, TOLUA_CAST "order"); tolua_usertype(L, TOLUA_CAST "item"); @@ -1030,17 +1011,17 @@ int tolua_eressea_open(lua_State * L) tolua_usertype(L, TOLUA_CAST "faction_list"); tolua_module(L, NULL, 0); tolua_beginmodule(L, NULL); - { + { tolua_module(L, "process", 0); tolua_beginmodule(L, "process"); - { + { tolua_function(L, "markets", &tolua_process_markets); tolua_function(L, "produce", &tolua_process_produce); } tolua_endmodule(L); tolua_cclass(L, TOLUA_CAST "alliance", TOLUA_CAST "alliance", TOLUA_CAST "", NULL); tolua_beginmodule(L, TOLUA_CAST "alliance"); - { + { tolua_variable(L, TOLUA_CAST "name", tolua_get_alliance_name, tolua_set_alliance_name); tolua_variable(L, TOLUA_CAST "id", tolua_get_alliance_id, NULL); @@ -1048,10 +1029,9 @@ int tolua_eressea_open(lua_State * L) NULL); tolua_function(L, TOLUA_CAST "create", tolua_alliance_create); } tolua_endmodule(L); - tolua_cclass(L, TOLUA_CAST "spell", TOLUA_CAST "spell", TOLUA_CAST "", - NULL); + tolua_cclass(L, TOLUA_CAST "spell", TOLUA_CAST "spell", TOLUA_CAST "", NULL); tolua_beginmodule(L, TOLUA_CAST "spell"); - { + { tolua_function(L, TOLUA_CAST "__tostring", tolua_get_spell_name); tolua_variable(L, TOLUA_CAST "name", tolua_get_spell_name, 0); tolua_variable(L, TOLUA_CAST "school", tolua_get_spell_school, 0); @@ -1060,24 +1040,24 @@ int tolua_eressea_open(lua_State * L) } tolua_endmodule(L); tolua_module(L, TOLUA_CAST "eventbus", 1); tolua_beginmodule(L, TOLUA_CAST "eventbus"); - { + { tolua_function(L, TOLUA_CAST "register", &tolua_eventbus_register); tolua_function(L, TOLUA_CAST "fire", &tolua_eventbus_fire); } tolua_endmodule(L); tolua_module(L, TOLUA_CAST "settings", 1); tolua_beginmodule(L, TOLUA_CAST "settings"); - { + { tolua_function(L, TOLUA_CAST "set", &tolua_settings_set); tolua_function(L, TOLUA_CAST "get", &tolua_settings_get); } tolua_endmodule(L); tolua_module(L, TOLUA_CAST "report", 1); tolua_beginmodule(L, TOLUA_CAST "report"); - { + { tolua_function(L, TOLUA_CAST "report_unit", &tolua_report_unit); } tolua_endmodule(L); tolua_module(L, TOLUA_CAST "config", 1); tolua_beginmodule(L, TOLUA_CAST "config"); - { + { parse_inifile(L, global.inifile, "config"); tolua_variable(L, TOLUA_CAST "locales", &config_get_locales, 0); tolua_function(L, TOLUA_CAST "get_resource", &config_get_resource); @@ -1087,12 +1067,10 @@ int tolua_eressea_open(lua_State * L) tolua_function(L, TOLUA_CAST "get_faction", tolua_get_faction); tolua_function(L, TOLUA_CAST "get_unit", tolua_get_unit); tolua_function(L, TOLUA_CAST "get_alliance", tolua_get_alliance); - tolua_function(L, TOLUA_CAST "get_ship", tolua_get_ship), - tolua_function(L, TOLUA_CAST "get_building", tolua_get_building), - tolua_function(L, TOLUA_CAST "get_region", tolua_get_region), - // deprecated_function(L, TOLUA_CAST "add_faction"); - // deprecated_function(L, TOLUA_CAST "faction_origin"); - tolua_function(L, TOLUA_CAST "factions", tolua_get_factions); + tolua_function(L, TOLUA_CAST "get_ship", tolua_get_ship); + tolua_function(L, TOLUA_CAST "get_building", tolua_get_building); + tolua_function(L, TOLUA_CAST "get_region", tolua_get_region); + tolua_function(L, TOLUA_CAST "factions", tolua_get_factions); tolua_function(L, TOLUA_CAST "regions", tolua_get_regions); tolua_function(L, TOLUA_CAST "read_turn", tolua_read_turn); tolua_function(L, TOLUA_CAST "read_game", tolua_read_game); @@ -1106,36 +1084,28 @@ int tolua_eressea_open(lua_State * L) tolua_function(L, TOLUA_CAST "write_report", tolua_write_report); tolua_function(L, TOLUA_CAST "init_summary", tolua_init_summary); tolua_function(L, TOLUA_CAST "write_summary", tolua_write_summary); - tolua_function(L, TOLUA_CAST "write_passwords", tolua_write_passwords), - tolua_function(L, TOLUA_CAST "message_unit", tolua_message_unit); + tolua_function(L, TOLUA_CAST "write_passwords", tolua_write_passwords); + tolua_function(L, TOLUA_CAST "message_unit", tolua_message_unit); tolua_function(L, TOLUA_CAST "message_faction", tolua_message_faction); tolua_function(L, TOLUA_CAST "message_region", tolua_message_region); - /* scripted monsters */ - tolua_function(L, TOLUA_CAST "spawn_braineaters", - tolua_spawn_braineaters); + /* scripted monsters */ + tolua_function(L, TOLUA_CAST "spawn_braineaters", + tolua_spawn_braineaters); -#ifdef TODO_FOSS - /* spells and stuff */ - tolua_function(L, TOLUA_CAST "levitate_ship", tolua_levitate_ship); - -#endif /* */ - tolua_function(L, TOLUA_CAST "update_guards", tolua_update_guards); + tolua_function(L, TOLUA_CAST "update_guards", tolua_update_guards); tolua_function(L, TOLUA_CAST "set_turn", &tolua_set_turn); tolua_function(L, TOLUA_CAST "get_turn", &tolua_get_turn); tolua_function(L, TOLUA_CAST "get_season", tolua_get_season); - tolua_function(L, TOLUA_CAST "equipment_setitem", - tolua_equipment_setitem); + tolua_function(L, TOLUA_CAST "equipment_setitem", tolua_equipment_setitem); tolua_function(L, TOLUA_CAST "equip_unit", tolua_equipunit); tolua_function(L, TOLUA_CAST "add_equipment", tolua_addequipment); tolua_function(L, TOLUA_CAST "atoi36", tolua_atoi36); tolua_function(L, TOLUA_CAST "itoa36", tolua_itoa36); tolua_function(L, TOLUA_CAST "dice_roll", tolua_dice_rand); tolua_function(L, TOLUA_CAST "get_nmrs", tolua_get_nmrs); - tolua_function(L, TOLUA_CAST "remove_empty_units", - tolua_remove_empty_units); - tolua_function(L, TOLUA_CAST "update_subscriptions", - tolua_update_subscriptions); + tolua_function(L, TOLUA_CAST "remove_empty_units", tolua_remove_empty_units); + tolua_function(L, TOLUA_CAST "update_subscriptions", tolua_update_subscriptions); tolua_function(L, TOLUA_CAST "update_scores", tolua_update_scores); tolua_function(L, TOLUA_CAST "update_owners", tolua_update_owners); tolua_function(L, TOLUA_CAST "learn_skill", tolua_learn_skill); @@ -1151,5 +1121,3 @@ int tolua_eressea_open(lua_State * L) } tolua_endmodule(L); return 1; } - - From 496aa22e652531a32b9711ffdd3c1fe277724260 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 7 Mar 2011 17:26:50 +0100 Subject: [PATCH 113/400] fixes for -ansi -pedantic --- src/attributes/object.h | 2 +- src/bindings/bind_attrib.c | 2 +- src/bindings/bind_faction.c | 2 +- src/bindings/bind_message.c | 6 +++--- src/bindings/bind_unit.c | 14 +++++++------- src/eressea.c | 2 +- src/gamecode/laws.c | 2 +- src/gamecode/report.c | 2 +- src/gamecode/xmlreport.c | 2 +- src/kernel/alliance.c | 8 ++++---- src/kernel/item.c | 2 ++ src/kernel/magic.h | 2 +- src/kernel/reports.c | 2 +- src/kernel/skill.h | 2 +- src/kernel/textstore.c | 2 +- src/kernel/xmlreader.c | 6 +++--- src/platform.h | 2 ++ src/util/strings.c | 6 +++--- src/util/unicode.c | 4 ++-- src/util/xml.c | 2 +- 20 files changed, 38 insertions(+), 34 deletions(-) diff --git a/src/attributes/object.h b/src/attributes/object.h index 44bec8b56..b4d3f7870 100644 --- a/src/attributes/object.h +++ b/src/attributes/object.h @@ -21,7 +21,7 @@ extern "C" { typedef enum { TNONE = 0, TINTEGER = 1, TREAL = 2, TSTRING = 3, - TUNIT = 10, TFACTION = 11, TREGION = 12, TBUILDING = 13, TSHIP = 14, + TUNIT = 10, TFACTION = 11, TREGION = 12, TBUILDING = 13, TSHIP = 14 } object_type; extern struct attrib_type at_object; diff --git a/src/bindings/bind_attrib.c b/src/bindings/bind_attrib.c index cdb2f0c6b..9e8d1a9c2 100644 --- a/src/bindings/bind_attrib.c +++ b/src/bindings/bind_attrib.c @@ -296,7 +296,7 @@ static int read_ext(attrib * a, void *owner, struct storage *store) a->data.v = 0; ur_add(data, a, resolve_bson); return AT_READ_OK; -}; +} attrib_type at_lua_ext = { "lua", init_ext, free_ext, age_ext, write_ext, read_ext diff --git a/src/bindings/bind_faction.c b/src/bindings/bind_faction.c index c0ca97b8c..a9a181f78 100644 --- a/src/bindings/bind_faction.c +++ b/src/bindings/bind_faction.c @@ -69,7 +69,7 @@ int tolua_faction_add_item(lua_State * L) if (itype != NULL) { item *i = i_change(&self->items, itype, number); result = i ? i->number : 0; - } // if (itype!=NULL) + } /* if (itype!=NULL) */ } lua_pushnumber(L, result); return 1; diff --git a/src/bindings/bind_message.c b/src/bindings/bind_message.c index cd7bcc8a7..ae27573d9 100644 --- a/src/bindings/bind_message.c +++ b/src/bindings/bind_message.c @@ -1,7 +1,7 @@ #include #include -// kernel includes +/* kernel includes */ #include #include #include @@ -9,10 +9,10 @@ #include #include -// util includes +/* util includes */ #include -// lua includes +/* lua includes */ #include #include diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 8542d60c7..49c65d786 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -16,11 +16,11 @@ without prior permission by the authors of Eressea. #include "bind_attrib.h" #include "bindings.h" -// attributes includes +/* attributes includes */ #include #include -// kernel includes +/* kernel includes */ #include #include #include @@ -37,7 +37,7 @@ without prior permission by the authors of Eressea. #include #include -// util includes +/* util includes */ #include #include #include @@ -937,7 +937,7 @@ void tolua_unit_open(lua_State * L) tolua_function(L, TOLUA_CAST "clear_orders", &tolua_unit_clear_orders); tolua_variable(L, TOLUA_CAST "orders", &tolua_unit_get_orders, 0); - // key-attributes for named flags: + /* key-attributes for named flags: */ tolua_function(L, TOLUA_CAST "set_flag", &tolua_unit_set_flag); tolua_function(L, TOLUA_CAST "get_flag", &tolua_unit_get_flag); tolua_variable(L, TOLUA_CAST "flags", &tolua_unit_get_flags, @@ -945,21 +945,21 @@ void tolua_unit_open(lua_State * L) tolua_variable(L, TOLUA_CAST "age", &tolua_unit_get_age, tolua_unit_set_age); - // items: + /* items: */ tolua_function(L, TOLUA_CAST "get_item", &tolua_unit_get_item); tolua_function(L, TOLUA_CAST "add_item", &tolua_unit_add_item); tolua_variable(L, TOLUA_CAST "items", &tolua_unit_get_items, 0); tolua_function(L, TOLUA_CAST "get_pooled", &tolua_unit_get_pooled); tolua_function(L, TOLUA_CAST "use_pooled", &tolua_unit_use_pooled); - // skills: + /* skills: */ tolua_function(L, TOLUA_CAST "get_skill", &tolua_unit_getskill); tolua_function(L, TOLUA_CAST "eff_skill", &tolua_unit_effskill); tolua_function(L, TOLUA_CAST "set_skill", &tolua_unit_setskill); tolua_function(L, TOLUA_CAST "add_notice", &tolua_unit_addnotice); - // npc logic: + /* npc logic: */ tolua_function(L, TOLUA_CAST "add_handler", &tolua_unit_addhandler); tolua_variable(L, TOLUA_CAST "race_name", &tolua_unit_get_racename, diff --git a/src/eressea.c b/src/eressea.c index f1a9c1ab3..e637d2292 100644 --- a/src/eressea.c +++ b/src/eressea.c @@ -23,7 +23,7 @@ #include #include #include -#endif // BINDINGS_TOLUA +#endif /* BINDINGS_TOLUA */ #if MUSEUM_MODULE #include diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index b9472dcf3..19dd3dbd6 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -731,7 +731,7 @@ static void growing_trees_e3(region * r, const int current_season, const int last_weeks_season) { - const static int transform[4][3] = { + static const int transform[4][3] = { {-1, -1, 0}, {TREE_SEED, TREE_SAPLING, 2}, {TREE_SAPLING, TREE_TREE, 2}, diff --git a/src/gamecode/report.c b/src/gamecode/report.c index 1d64a60ba..5d635992d 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -2400,7 +2400,7 @@ report_plaintext(const char *filename, report_context * ctx, rnl(F); nr_paragraph(F, m, f); } - // + /* */ } else { if (!fval(r->terrain, SEA_REGION) && rpeasants(r) / TRADE_FRACTION > 0) { rnl(F); diff --git a/src/gamecode/xmlreport.c b/src/gamecode/xmlreport.c index afcb067eb..fc4666f37 100644 --- a/src/gamecode/xmlreport.c +++ b/src/gamecode/xmlreport.c @@ -754,7 +754,7 @@ static xmlNodePtr report_root(report_context * ctx) xmlAddChild(xmlReport, xml_region(ctx, sr)); } return xmlReport; -}; +} /* main function of the xmlreport. creates the header and traverses all regions */ static int diff --git a/src/kernel/alliance.c b/src/kernel/alliance.c index f9e93637a..aca0c35a8 100644 --- a/src/kernel/alliance.c +++ b/src/kernel/alliance.c @@ -96,8 +96,8 @@ typedef struct alliance_transaction { struct alliance_transaction *next; unit *u; order *ord; -// alliance * al; -// variant userdata; +/* alliance * al; */ +/* variant userdata; */ } alliance_transaction; static struct alliance_transaction *transactions[ALLIANCE_MAX]; @@ -321,9 +321,9 @@ void alliance_cmd(void) if (stree == NULL) { syntaxtree *slang = stree = stree_create(); while (slang) { - // struct tnode * root = calloc(sizeof(tnode), 1); + /* struct tnode * root = calloc(sizeof(tnode), 1); */ struct tnode *leaf = calloc(sizeof(tnode), 1); - // add_command(root, leaf, LOC(slang->lang, "alliance"), NULL); + /* add_command(root, leaf, LOC(slang->lang, "alliance"), NULL); */ add_command(leaf, NULL, LOC(slang->lang, "new"), &cmd_new); add_command(leaf, NULL, LOC(slang->lang, "invite"), &cmd_invite); add_command(leaf, NULL, LOC(slang->lang, "join"), &cmd_join); diff --git a/src/kernel/item.c b/src/kernel/item.c index 9f56280ea..72f21cac8 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -494,7 +494,9 @@ item *i_change(item ** pi, const item_type * itype, int delta) if (i->number < 0) { log_error(("serious accounting error. number of items is %d.\n", i->number)); + /* FIXME what's this supposed to mean?? assert(i >= 0); + */ i->number = 0; } if (i->number == 0) { diff --git a/src/kernel/magic.h b/src/kernel/magic.h index 74cd5eb33..311024d54 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -53,7 +53,7 @@ extern "C" { SPP_BUILDING, /* - : atoi() -> int */ SPP_SHIP, /* - : atoi() -> int */ SPP_STRING, /* "c" */ - SPP_INT, /* "i" : atoi() -> int */ + SPP_INT /* "i" : atoi() -> int */ } sppobj_t; typedef struct spllprm { diff --git a/src/kernel/reports.c b/src/kernel/reports.c index 79cb31fa6..219660ca7 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -1141,7 +1141,7 @@ void seen_done(seen_region * seehash[]) reuse = seehash[i]; seehash[i] = NULL; } - // free(seehash); + /* free(seehash); */ } void free_seen(void) diff --git a/src/kernel/skill.h b/src/kernel/skill.h index 6cf79debf..8d91aab37 100644 --- a/src/kernel/skill.h +++ b/src/kernel/skill.h @@ -22,7 +22,7 @@ extern "C" { #define SMF_RIDING (1<<2) /* Bonus für berittene - an der rasse */ typedef struct skill { - skill_t id:8; + unsigned int id:8; unsigned int level:8; unsigned int weeks:8; unsigned int old:8; diff --git a/src/kernel/textstore.c b/src/kernel/textstore.c index fe2fd251a..7c12d89be 100644 --- a/src/kernel/textstore.c +++ b/src/kernel/textstore.c @@ -135,7 +135,7 @@ static int txt_open(struct storage *store, const char *filename, int mode) FILE *F = fopen(filename, modes[mode]); store->userdata = F; if (F) { - const char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + char utf8_bom[4] = { (char)0xef, (char)0xbb, (char)0xbf }; if (mode == IO_READ) { char token[8]; /* recognize UTF8 BOM */ diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index c3cfd2de9..6cef9d00c 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1869,9 +1869,9 @@ static int parse_races(xmlDocPtr doc) assert(propValue != NULL); frc = rc_find((const char *)propValue); if (frc == NULL) { -// log_error(("%s not registered, is familiar for %s\n", -// (const char*)propValue, rc->_name[0])); -// assert(frc!=NULL); +/* log_error(("%s not registered, is familiar for %s\n", */ +/* (const char*)propValue, rc->_name[0])); */ +/* assert(frc!=NULL); */ frc = rc_add(rc_new((const char *)propValue)); } if (xml_bvalue(node, "default", false)) { diff --git a/src/platform.h b/src/platform.h index cdf87ea37..b6d201040 100644 --- a/src/platform.h +++ b/src/platform.h @@ -16,6 +16,8 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ +#define _GNU_SOURCE + #ifndef CONFIG_H #define CONFIG_H diff --git a/src/util/strings.c b/src/util/strings.c index 94e0577f8..ade70fe35 100644 --- a/src/util/strings.c +++ b/src/util/strings.c @@ -51,7 +51,7 @@ escape_string_inplace(char * buffer, unsigned int len, unsigned int offset) } d[i] = o; if (i> 12); a = a + (a << 2); a = a ^ (a >> 4); - a = a * 2057; // a = (a + (a << 3)) + (a << 11); + a = a * 2057; /* a = (a + (a << 3)) + (a << 11); */ a = a ^ (a >> 16); return a; } diff --git a/src/util/unicode.c b/src/util/unicode.c index e15aa44f3..ca7d0fbad 100644 --- a/src/util/unicode.c +++ b/src/util/unicode.c @@ -81,12 +81,12 @@ unicode_latin1_to_utf8(utf8_t * out, size_t * outlen, const char *in, if (c > 0xBF) { if (op - out >= os - 1) break; - *op++ = 0xC3; + *op++ = (char) 0xC3; *op++ = c - 64; } else if (c > 0x7F) { if (op - out >= os - 1) break; - *op++ = 0xC2; + *op++ = (char) 0xC2; *op++ = c; } else { if (op - out >= os) diff --git a/src/util/xml.c b/src/util/xml.c index de9aa0cd1..cd1878206 100644 --- a/src/util/xml.c +++ b/src/util/xml.c @@ -28,7 +28,7 @@ const xmlChar *xml_i(double number) { static char buffer[128]; - snprintf(buffer, sizeof(buffer), "%.0lf", number); + snprintf(buffer, sizeof(buffer), "%.0f", number); return (const xmlChar *)buffer; } From 04b3d7ff459d53f23f68acbc299e5880c9dfbb96 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 7 Mar 2011 22:31:06 -0800 Subject: [PATCH 114/400] use enums, fix typecasts --- src/gamecode/creport.c | 2 +- src/gamecode/report.c | 4 ++-- src/gamecode/summary.c | 2 +- src/kernel/battle.c | 2 +- src/kernel/skill.h | 2 +- src/kernel/textstore.c | 6 ++--- src/kernel/types.h | 35 ++++++++++++---------------- src/lua-bindings.vcxproj | 3 --- src/lua-bindings.vcxproj.filters | 3 --- src/modules/score.c | 4 ++-- src/platform.h | 2 -- src/util/strings.c | 39 -------------------------------- src/util/unicode.c | 8 +++---- 13 files changed, 30 insertions(+), 82 deletions(-) diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index b8b2a975f..4a0e767c8 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -1438,7 +1438,7 @@ report_computer(const char *filename, report_context * ctx, const char *charset) perror(filename); return -1; } else if (enc == XML_CHAR_ENCODING_UTF8) { - const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf, 0 }; fwrite(utf8_bom, 1, 3, F); } diff --git a/src/gamecode/report.c b/src/gamecode/report.c index 5d635992d..9907dc182 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -1495,7 +1495,7 @@ report_template(const char *filename, report_context * ctx, const char *charset) } if (enc == XML_CHAR_ENCODING_UTF8) { - const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf, 0 }; fwrite(utf8_bom, 1, 3, F); } @@ -2141,7 +2141,7 @@ report_plaintext(const char *filename, report_context * ctx, return -1; } if (enc == XML_CHAR_ENCODING_UTF8) { - const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf, 0 }; fwrite(utf8_bom, 1, 3, F); } diff --git a/src/gamecode/summary.c b/src/gamecode/summary.c index a734eeba4..03690dee7 100644 --- a/src/gamecode/summary.c +++ b/src/gamecode/summary.c @@ -149,7 +149,7 @@ void report_summary(summary * s, summary * o, boolean full) return; #ifdef SUMMARY_BOM else { - const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf, 0 }; fwrite(utf8_bom, 1, 3, F); } #endif diff --git a/src/kernel/battle.c b/src/kernel/battle.c index 4af7ace44..5c1fa233f 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -3673,7 +3673,7 @@ static battle *make_battle(region * r) if (!bdebug) log_error(("battles cannot be debugged\n")); else { - const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf, 0 }; fwrite(utf8_bom, 1, 3, bdebug); fprintf(bdebug, "In %s findet ein Kampf stattactics:\n", rname(r, default_locale)); diff --git a/src/kernel/skill.h b/src/kernel/skill.h index 8d91aab37..dde1c0721 100644 --- a/src/kernel/skill.h +++ b/src/kernel/skill.h @@ -22,7 +22,7 @@ extern "C" { #define SMF_RIDING (1<<2) /* Bonus für berittene - an der rasse */ typedef struct skill { - unsigned int id:8; + int id:8; unsigned int level:8; unsigned int weeks:8; unsigned int old:8; diff --git a/src/kernel/textstore.c b/src/kernel/textstore.c index 7c12d89be..9fc80f01e 100644 --- a/src/kernel/textstore.c +++ b/src/kernel/textstore.c @@ -60,7 +60,7 @@ static int txt_w_flt(struct storage *store, float arg) static float txt_r_flt(struct storage *store) { double result; - fscanf((FILE *) store->userdata, "%lf", &result); + fscanf((FILE *) store->userdata, "%f", &result); return (float)result; } @@ -135,7 +135,7 @@ static int txt_open(struct storage *store, const char *filename, int mode) FILE *F = fopen(filename, modes[mode]); store->userdata = F; if (F) { - char utf8_bom[4] = { (char)0xef, (char)0xbb, (char)0xbf }; + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; if (mode == IO_READ) { char token[8]; /* recognize UTF8 BOM */ @@ -154,7 +154,7 @@ static int txt_open(struct storage *store, const char *filename, int mode) store->version = atoi(token); } } else if (store->encoding == XML_CHAR_ENCODING_UTF8) { - fputs(utf8_bom, F); + fputs((const char*)utf8_bom, F); fprintf(F, "%d\n", RELEASE_VERSION); } } diff --git a/src/kernel/types.h b/src/kernel/types.h index 2ec5585f3..866a72cc2 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -31,10 +31,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include typedef short terrain_t; -typedef short direction_t; -typedef short race_t; typedef short magic_t; -typedef short skill_t; typedef short typ_t; typedef short item_t; typedef unsigned int spellid_t; @@ -76,8 +73,7 @@ typedef struct ursprung { /* ----------------- Befehle ----------------------------------- */ -typedef unsigned char keyword_t; -enum { +typedef enum { K_KOMMENTAR, K_BANNER, K_WORK, @@ -148,8 +144,8 @@ enum { K_PROMOTION, K_PAY, MAXKEYWORDS, - NOKEYWORD = (keyword_t) - 1 -}; + NOKEYWORD = -1 +} keyword_t; /* ------------------ Status von Einheiten --------------------- */ @@ -165,8 +161,7 @@ enum { /* ----------------- Parameter --------------------------------- */ -typedef unsigned char param_t; -enum { +typedef enum { P_LOCALE, P_ANY, P_EACH, @@ -218,8 +213,8 @@ enum { P_XELAEN, P_ALLIANCE, MAXPARAMS, - NOPARAM = (param_t) - 1 -}; + NOPARAM = -1 +} param_t; typedef enum { /* Fehler und Meldungen im Report */ MSG_BATTLE, @@ -268,7 +263,7 @@ enum { /* ------------------ Talente ---------------------------------- */ -enum { +typedef enum { SK_ALCHEMY, SK_CROSSBOW, SK_MINING, @@ -299,12 +294,12 @@ enum { SK_STAMINA, SK_WEAPONLESS, MAXSKILLS, - NOSKILL = (skill_t) - 1 -}; + NOSKILL = -1 +} skill_t; /* ------------- Typ von Einheiten ----------------------------- */ -enum { +typedef enum { RC_DWARF, /* 0 - Zwerg */ RC_ELF, RC_GOBLIN = 3, @@ -363,11 +358,11 @@ enum { RC_CLONE, MAXRACES, - NORACE = (race_t) - 1 -}; + NORACE = -1 +} race_t; /* Richtungen */ -enum { +typedef enum { D_NORTHWEST, D_NORTHEAST, D_EAST, @@ -377,8 +372,8 @@ enum { MAXDIRECTIONS, D_PAUSE, D_SPECIAL, - NODIRECTION = (direction_t) - 1 -}; + NODIRECTION = -1 +} direction_t; #define DONT_HELP 0 #define HELP_MONEY 1 /* Mitversorgen von Einheiten */ diff --git a/src/lua-bindings.vcxproj b/src/lua-bindings.vcxproj index 3929ae569..5714a1cbd 100644 --- a/src/lua-bindings.vcxproj +++ b/src/lua-bindings.vcxproj @@ -115,9 +115,6 @@ - - - diff --git a/src/lua-bindings.vcxproj.filters b/src/lua-bindings.vcxproj.filters index cb23911a8..83b65c358 100644 --- a/src/lua-bindings.vcxproj.filters +++ b/src/lua-bindings.vcxproj.filters @@ -89,7 +89,4 @@ Header Files - - - \ No newline at end of file diff --git a/src/modules/score.c b/src/modules/score.c index 40c4f8e29..c65dac5d9 100644 --- a/src/modules/score.c +++ b/src/modules/score.c @@ -155,7 +155,7 @@ void score(void) sprintf(path, "%s/score", basepath()); scoreFP = fopen(path, "w"); if (scoreFP) { - const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf, 0 }; faction *f; fwrite(utf8_bom, 1, 3, scoreFP); for (f = factions; f; f = f->next) @@ -176,7 +176,7 @@ void score(void) sprintf(path, "%s/score.alliances", basepath()); scoreFP = fopen(path, "w"); if (scoreFP) { - const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf }; + const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf, 0 }; fwrite(utf8_bom, 1, 3, scoreFP); fprintf(scoreFP, "# alliance:factions:persons:score\n"); diff --git a/src/platform.h b/src/platform.h index b6d201040..cdf87ea37 100644 --- a/src/platform.h +++ b/src/platform.h @@ -16,8 +16,6 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ -#define _GNU_SOURCE - #ifndef CONFIG_H #define CONFIG_H diff --git a/src/util/strings.c b/src/util/strings.c index ade70fe35..7efa9c032 100644 --- a/src/util/strings.c +++ b/src/util/strings.c @@ -30,45 +30,6 @@ INLINE_FUNCTION unsigned int hashstring(const char *s) return key & 0x7FFFFFFF; } -/* -static const char * -escape_string_inplace(char * buffer, unsigned int len, unsigned int offset) -{ -#define MAXQUOTES 32 - char * o; - char * d[MAXQUOTES+1]; - int i = 0; - - o = strchr(buffer, '"'); - if (!o) { - return buffer; - } - - while (*o && i0) { - const char * src = d[i]; - char * dst = d[i] + i + offset; - size_t mlen = d[i+1] - d[i]; - memmove(dst--, src, mlen); - *dst = '\\'; - } - return buffer; -} -*/ - INLINE_FUNCTION const char *escape_string(const char *str, char *buffer, unsigned int len) { diff --git a/src/util/unicode.c b/src/util/unicode.c index ca7d0fbad..33db457e7 100644 --- a/src/util/unicode.c +++ b/src/util/unicode.c @@ -68,25 +68,25 @@ int unicode_utf8_tolower(utf8_t * op, size_t outlen, const utf8_t * ip) } int -unicode_latin1_to_utf8(utf8_t * out, size_t * outlen, const char *in, +unicode_latin1_to_utf8(utf8_t * dst, size_t * outlen, const char *in, size_t * inlen) { int is = (int)*inlen; int os = (int)*outlen; const char *ip = in; - utf8_t *op = out; + unsigned char *out = (unsigned char *)dst, *op = out; while (ip - in < is) { unsigned char c = *ip; if (c > 0xBF) { if (op - out >= os - 1) break; - *op++ = (char) 0xC3; + *op++ = 0xC3; *op++ = c - 64; } else if (c > 0x7F) { if (op - out >= os - 1) break; - *op++ = (char) 0xC2; + *op++ = 0xC2; *op++ = c; } else { if (op - out >= os) From b4c5607747af47fec592a43411e6985e32bb8263 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 8 Mar 2011 08:44:20 +0100 Subject: [PATCH 115/400] compiling with -pedantic on linux --- src/bindings/bind_storage.c | 1 + src/bindings/bindings.c | 346 ++++----- src/gamecode/economy.c | 285 ++++--- src/gamecode/laws.c | 1415 ++++++++++++++++++----------------- src/gamecode/study.c | 33 +- src/kernel/build.c | 83 +- src/kernel/config.c | 87 +-- src/kernel/magic.c | 563 +++++++------- src/kernel/move.c | 179 +++-- src/kernel/order.c | 408 +++++----- src/kernel/reports.h | 3 + src/kernel/save.c | 229 +++--- src/kernel/skill.c | 30 +- src/kernel/spellid.h | 2 +- src/kernel/textstore.c | 4 +- src/modules/xecmd.c | 19 +- 16 files changed, 1850 insertions(+), 1837 deletions(-) diff --git a/src/bindings/bind_storage.c b/src/bindings/bind_storage.c index f96367ddc..5e7768d2d 100644 --- a/src/bindings/bind_storage.c +++ b/src/bindings/bind_storage.c @@ -20,6 +20,7 @@ without prior permission by the authors of Eressea. #include #include +#include #include #include diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index 94cdf3b8a..30a058467 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -8,17 +8,17 @@ This program may not be used, modified or distributed without prior permission by the authors of Eressea. -*/ - +*/ + #include #include "bindings.h" #include "bind_unit.h" #include "bind_faction.h" #include "bind_region.h" #include "helpers.h" - + #include - + #include #include #include @@ -37,18 +37,18 @@ without prior permission by the authors of Eressea. #include #include #include - + #include #include #include #include #include #include - + #include #include #include - + #include #include #include @@ -59,15 +59,15 @@ without prior permission by the authors of Eressea. #include #include #include - + #include #include #include - + #include #include -int log_lua_error(lua_State * L) +int log_lua_error(lua_State * L) { const char *error = lua_tostring(L, -1); log_error(("LUA call failed.\n%s\n", error)); @@ -75,10 +75,10 @@ int log_lua_error(lua_State * L) return 1; } -int tolua_orderlist_next(lua_State * L) +int tolua_orderlist_next(lua_State * L) { - order ** order_ptr = (order **) lua_touserdata(L, lua_upvalueindex(1)); - order * ord = *order_ptr; + order **order_ptr = (order **) lua_touserdata(L, lua_upvalueindex(1)); + order *ord = *order_ptr; if (ord != NULL) { char cmd[8192]; write_order(ord, cmd, sizeof(cmd)); @@ -89,10 +89,10 @@ int tolua_orderlist_next(lua_State * L) return 0; } -static int tolua_quicklist_iter(lua_State * L) +static int tolua_quicklist_iter(lua_State * L) { - quicklist ** qlp = (quicklist **) lua_touserdata(L, lua_upvalueindex(1)); - quicklist * ql = *qlp; + quicklist **qlp = (quicklist **) lua_touserdata(L, lua_upvalueindex(1)); + quicklist *ql = *qlp; if (ql != NULL) { int index = lua_tointeger(L, lua_upvalueindex(2)); const char *type = lua_tostring(L, lua_upvalueindex(3)); @@ -107,27 +107,27 @@ static int tolua_quicklist_iter(lua_State * L) } int tolua_quicklist_push(struct lua_State *L, const char *list_type, - const char *elem_type, struct quicklist *list) + const char *elem_type, struct quicklist *list) { if (list) { - quicklist ** qlist_ptr = + quicklist **qlist_ptr = (quicklist **) lua_newuserdata(L, sizeof(quicklist *)); *qlist_ptr = list; luaL_getmetatable(L, list_type); lua_setmetatable(L, -2); lua_pushnumber(L, 0); lua_pushstring(L, elem_type); - lua_pushcclosure(L, tolua_quicklist_iter, 3); /* OBS: this closure has multiple upvalues (list, index, type_name) */ + lua_pushcclosure(L, tolua_quicklist_iter, 3); /* OBS: this closure has multiple upvalues (list, index, type_name) */ } else { lua_pushnil(L); } return 1; } -int tolua_itemlist_next(lua_State * L) +int tolua_itemlist_next(lua_State * L) { - item ** item_ptr = (item **) lua_touserdata(L, lua_upvalueindex(1)); - item * itm = *item_ptr; + item **item_ptr = (item **) lua_touserdata(L, lua_upvalueindex(1)); + item *itm = *item_ptr; if (itm != NULL) { tolua_pushstring(L, itm->type->rtype->_name[0]); *item_ptr = itm->next; @@ -136,11 +136,11 @@ int tolua_itemlist_next(lua_State * L) return 0; } -static int tolua_autoseed(lua_State * L) +static int tolua_autoseed(lua_State * L) { const char *filename = tolua_tostring(L, 1, 0); int new_island = tolua_toboolean(L, 2, 0); - newfaction * players = read_newfactions(filename); + newfaction *players = read_newfactions(filename); if (players != NULL) { while (players) { int n = listlen(players); @@ -155,16 +155,16 @@ static int tolua_autoseed(lua_State * L) return 0; } -static int tolua_getkey(lua_State * L) +static int tolua_getkey(lua_State * L) { const char *name = tolua_tostring(L, 1, 0); int flag = atoi36(name); - attrib * a = find_key(global.attribs, flag); + attrib *a = find_key(global.attribs, flag); lua_pushboolean(L, a != NULL); return 1; } -static int tolua_translate(lua_State * L) +static int tolua_translate(lua_State * L) { const char *str = tolua_tostring(L, 1, 0); const char *lang = tolua_tostring(L, 2, 0); @@ -177,12 +177,12 @@ static int tolua_translate(lua_State * L) return 0; } -static int tolua_setkey(lua_State * L) +static int tolua_setkey(lua_State * L) { const char *name = tolua_tostring(L, 1, 0); int value = tolua_toboolean(L, 2, 0); int flag = atoi36(name); - attrib * a = find_key(global.attribs, flag); + attrib *a = find_key(global.attribs, flag); if (a == NULL && value) { add_key(&global.attribs, flag); } else if (a != NULL && !value) { @@ -191,13 +191,13 @@ static int tolua_setkey(lua_State * L) return 0; } -static int tolua_rng_int(lua_State * L) +static int tolua_rng_int(lua_State * L) { lua_pushnumber(L, (lua_Number) rng_int()); return 1; } -static int tolua_read_orders(lua_State * L) +static int tolua_read_orders(lua_State * L) { const char *filename = tolua_tostring(L, 1, 0); int result = readorders(filename); @@ -205,10 +205,10 @@ static int tolua_read_orders(lua_State * L) return 1; } -static int tolua_message_unit(lua_State * L) +static int tolua_message_unit(lua_State * L) { - unit * sender = (unit *) tolua_tousertype(L, 1, 0); - unit * target = (unit *) tolua_tousertype(L, 2, 0); + unit *sender = (unit *) tolua_tousertype(L, 1, 0); + unit *target = (unit *) tolua_tousertype(L, 2, 0); const char *str = tolua_tostring(L, 3, 0); if (!target) tolua_error(L, TOLUA_CAST "target is nil", NULL); @@ -218,10 +218,10 @@ static int tolua_message_unit(lua_State * L) return 0; } -static int tolua_message_faction(lua_State * L) +static int tolua_message_faction(lua_State * L) { - unit * sender = (unit *) tolua_tousertype(L, 1, 0); - faction * target = (faction *) tolua_tousertype(L, 2, 0); + unit *sender = (unit *) tolua_tousertype(L, 1, 0); + faction *target = (faction *) tolua_tousertype(L, 2, 0); const char *str = tolua_tostring(L, 3, 0); if (!target) tolua_error(L, TOLUA_CAST "target is nil", NULL); @@ -231,9 +231,9 @@ static int tolua_message_faction(lua_State * L) return 0; } -static int tolua_message_region(lua_State * L) +static int tolua_message_region(lua_State * L) { - unit * sender = (unit *) tolua_tousertype(L, 1, 0); + unit *sender = (unit *) tolua_tousertype(L, 1, 0); const char *str = tolua_tostring(L, 2, 0); if (!sender) tolua_error(L, TOLUA_CAST "sender is nil", NULL); @@ -242,46 +242,46 @@ static int tolua_message_region(lua_State * L) return 0; } -static int tolua_update_guards(lua_State * L) +static int tolua_update_guards(lua_State * L) { update_guards(); return 0; } -static int tolua_set_turn(lua_State * L) +static int tolua_set_turn(lua_State * L) { turn = (int)tolua_tonumber(L, 1, 0); return 0; } -static int tolua_get_turn(lua_State * L) +static int tolua_get_turn(lua_State * L) { tolua_pushnumber(L, (lua_Number) turn); return 1; } -static int tolua_atoi36(lua_State * L) +static int tolua_atoi36(lua_State * L) { const char *s = tolua_tostring(L, 1, 0); tolua_pushnumber(L, (lua_Number) atoi36(s)); return 1; } -static int tolua_itoa36(lua_State * L) +static int tolua_itoa36(lua_State * L) { int i = (int)tolua_tonumber(L, 1, 0); tolua_pushstring(L, itoa36(i)); return 1; } -static int tolua_dice_rand(lua_State * L) +static int tolua_dice_rand(lua_State * L) { const char *s = tolua_tostring(L, 1, 0); tolua_pushnumber(L, dice_rand(s)); return 1; } -static int tolua_addequipment(lua_State * L) +static int tolua_addequipment(lua_State * L) { const char *eqname = tolua_tostring(L, 1, 0); const char *iname = tolua_tostring(L, 2, 0); @@ -298,7 +298,7 @@ static int tolua_addequipment(lua_State * L) return 1; } -static int tolua_get_season(lua_State * L) +static int tolua_get_season(lua_State * L) { int turnno = (int)tolua_tonumber(L, 1, 0); gamedate gd; @@ -307,25 +307,25 @@ static int tolua_get_season(lua_State * L) return 1; } -static int tolua_create_curse(lua_State * L) +static int tolua_create_curse(lua_State * L) { - unit * u = (unit *) tolua_tousertype(L, 1, 0); + unit *u = (unit *) tolua_tousertype(L, 1, 0); tolua_Error tolua_err; - attrib ** ap = NULL; + attrib **ap = NULL; if (tolua_isusertype(L, 2, TOLUA_CAST "unit", 0, &tolua_err)) { - unit * target = (unit *) tolua_tousertype(L, 2, 0); + unit *target = (unit *) tolua_tousertype(L, 2, 0); if (target) ap = &target->attribs; } else if (tolua_isusertype(L, 2, TOLUA_CAST "region", 0, &tolua_err)) { - region * target = (region *) tolua_tousertype(L, 2, 0); + region *target = (region *) tolua_tousertype(L, 2, 0); if (target) ap = &target->attribs; } else if (tolua_isusertype(L, 2, TOLUA_CAST "ship", 0, &tolua_err)) { - ship * target = (ship *) tolua_tousertype(L, 2, 0); + ship *target = (ship *) tolua_tousertype(L, 2, 0); if (target) ap = &target->attribs; } else if (tolua_isusertype(L, 2, TOLUA_CAST "building", 0, &tolua_err)) { - building * target = (building *) tolua_tousertype(L, 2, 0); + building *target = (building *) tolua_tousertype(L, 2, 0); if (target) ap = &target->attribs; } @@ -336,8 +336,8 @@ static int tolua_create_curse(lua_State * L) double vigour = tolua_tonumber(L, 4, 0); int duration = (int)tolua_tonumber(L, 5, 0); double effect = tolua_tonumber(L, 6, 0); - int men = (int)tolua_tonumber(L, 7, 0); /* optional */ - curse * c = create_curse(u, ap, ctype, vigour, duration, effect, men); + int men = (int)tolua_tonumber(L, 7, 0); /* optional */ + curse *c = create_curse(u, ap, ctype, vigour, duration, effect, men); if (c) { tolua_pushboolean(L, true); return 1; @@ -348,9 +348,9 @@ static int tolua_create_curse(lua_State * L) return 1; } -static int tolua_learn_skill(lua_State * L) +static int tolua_learn_skill(lua_State * L) { - unit * u = (unit *) tolua_tousertype(L, 1, 0); + unit *u = (unit *) tolua_tousertype(L, 1, 0); const char *skname = tolua_tostring(L, 2, 0); float chances = (float)tolua_tonumber(L, 3, 0); skill_t sk = sk_find(skname); @@ -360,34 +360,34 @@ static int tolua_learn_skill(lua_State * L) return 0; } -static int tolua_update_scores(lua_State * L) +static int tolua_update_scores(lua_State * L) { score(); return 0; } -static int tolua_update_owners(lua_State * L) +static int tolua_update_owners(lua_State * L) { - region * r; + region *r; for (r = regions; r; r = r->next) { update_owners(r); } return 0; } -static int tolua_update_subscriptions(lua_State * L) +static int tolua_update_subscriptions(lua_State * L) { update_subscriptions(); return 0; } -static int tolua_remove_empty_units(lua_State * L) +static int tolua_remove_empty_units(lua_State * L) { remove_empty_units(); return 0; } -static int tolua_get_nmrs(lua_State * L) +static int tolua_get_nmrs(lua_State * L) { int result = -1; int n = (int)tolua_tonumber(L, 1, 0); @@ -401,15 +401,15 @@ static int tolua_get_nmrs(lua_State * L) return 1; } -static int tolua_equipunit(lua_State * L) +static int tolua_equipunit(lua_State * L) { - unit * u = (unit *) tolua_tousertype(L, 1, 0); + unit *u = (unit *) tolua_tousertype(L, 1, 0); const char *eqname = tolua_tostring(L, 2, 0); equip_unit(u, get_equipment(eqname)); return 0; } -static int tolua_equipment_setitem(lua_State * L) +static int tolua_equipment_setitem(lua_State * L) { int result = -1; const char *eqname = tolua_tostring(L, 1, 0); @@ -426,30 +426,30 @@ static int tolua_equipment_setitem(lua_State * L) return 1; } -static int tolua_spawn_braineaters(lua_State * L) +static int tolua_spawn_braineaters(lua_State * L) { float chance = (float)tolua_tonumber(L, 1, 0); spawn_braineaters(chance); return 0; } -static int tolua_init_reports(lua_State * L) +static int tolua_init_reports(lua_State * L) { int result = init_reports(); tolua_pushnumber(L, (lua_Number) result); return 1; } -static int tolua_write_report(lua_State * L) +static int tolua_write_report(lua_State * L) { - faction * f = (faction *) tolua_tousertype(L, 1, 0); + faction *f = (faction *) tolua_tousertype(L, 1, 0); time_t ltime = time(0); int result = write_reports(f, ltime); tolua_pushnumber(L, (lua_Number) result); return 1; } -static int tolua_write_reports(lua_State * L) +static int tolua_write_reports(lua_State * L) { int result; init_reports(); @@ -458,13 +458,13 @@ static int tolua_write_reports(lua_State * L) return 1; } -static void reset_game(void) +static void reset_game(void) { - region * r; - faction * f; + region *r; + faction *f; for (r = regions; r; r = r->next) { - unit * u; - building * b; + unit *u; + building *b; r->flags &= RF_SAVEMASK; for (u = r->units; u; u = u->next) { u->flags &= UFL_SAVEMASK; @@ -473,10 +473,10 @@ static void reset_game(void) b->flags &= BLD_SAVEMASK; } if (r->land && r->land->ownership && r->land->ownership->owner) { - faction * owner = r->land->ownership->owner; + faction *owner = r->land->ownership->owner; if (owner == get_monsters()) { - /* some compat-fix, i believe. */ - owner = update_owners(r); + /* some compat-fix, i believe. */ + owner = update_owners(r); } if (owner) { fset(r, RF_GUARDED); @@ -488,7 +488,7 @@ static void reset_game(void) } } -static int tolua_process_orders(lua_State * L) +static int tolua_process_orders(lua_State * L) { ++turn; reset_game(); @@ -496,7 +496,7 @@ static int tolua_process_orders(lua_State * L) return 0; } -static int tolua_write_passwords(lua_State * L) +static int tolua_write_passwords(lua_State * L) { int result = writepasswd(); lua_pushnumber(L, (lua_Number) result); @@ -504,13 +504,13 @@ static int tolua_write_passwords(lua_State * L) } static struct summary *sum_begin = 0; -static int tolua_init_summary(lua_State * L) +static int tolua_init_summary(lua_State * L) { sum_begin = make_summary(); return 0; } -static int tolua_write_summary(lua_State * L) +static int tolua_write_summary(lua_State * L) { if (sum_begin) { struct summary *sum_end = make_summary(); @@ -521,13 +521,13 @@ static int tolua_write_summary(lua_State * L) return 0; } -static int tolua_free_game(lua_State * L) +static int tolua_free_game(lua_State * L) { free_gamedata(); return 0; } -static int tolua_write_map(lua_State * L) +static int tolua_write_map(lua_State * L) { const char *filename = tolua_tostring(L, 1, 0); if (filename) { @@ -536,7 +536,7 @@ static int tolua_write_map(lua_State * L) return 0; } -static int tolua_write_game(lua_State * L) +static int tolua_write_game(lua_State * L) { const char *filename = tolua_tostring(L, 1, 0); const char *mode = tolua_tostring(L, 2, 0); @@ -549,7 +549,7 @@ static int tolua_write_game(lua_State * L) return 1; } -static int tolua_read_game(lua_State * L) +static int tolua_read_game(lua_State * L) { const char *filename = tolua_tostring(L, 1, 0); const char *mode = tolua_tostring(L, 2, 0); @@ -561,84 +561,84 @@ static int tolua_read_game(lua_State * L) return 1; } -static int tolua_read_turn(lua_State * L) +static int tolua_read_turn(lua_State * L) { int cturn = current_turn(); tolua_pushnumber(L, (lua_Number) cturn); return 1; } -static int tolua_get_faction(lua_State * L) +static int tolua_get_faction(lua_State * L) { int no = tolua_toid(L, 1, 0); - faction * f = findfaction(no); + faction *f = findfaction(no); tolua_pushusertype(L, f, TOLUA_CAST "faction"); return 1; } -static int tolua_get_region(lua_State * L) +static int tolua_get_region(lua_State * L) { int x = (int)tolua_tonumber(L, 1, 0); int y = (int)tolua_tonumber(L, 2, 0); - region * r; + region *r; assert(!pnormalize(&x, &y, findplane(x, y))); r = findregion(x, y); tolua_pushusertype(L, r, TOLUA_CAST "region"); return 1; } -static int tolua_get_region_byid(lua_State * L) +static int tolua_get_region_byid(lua_State * L) { int uid = (int)tolua_tonumber(L, 1, 0); - region * r = findregionbyid(uid); + region *r = findregionbyid(uid); tolua_pushusertype(L, r, TOLUA_CAST "region"); return 1; } -static int tolua_get_building(lua_State * L) +static int tolua_get_building(lua_State * L) { int no = tolua_toid(L, 1, 0); - building * b = findbuilding(no); + building *b = findbuilding(no); tolua_pushusertype(L, b, TOLUA_CAST "building"); return 1; } -static int tolua_get_ship(lua_State * L) +static int tolua_get_ship(lua_State * L) { int no = tolua_toid(L, 1, 0); - ship * sh = findship(no); + ship *sh = findship(no); tolua_pushusertype(L, sh, TOLUA_CAST "ship"); return 1; } -static int tolua_get_alliance(lua_State * L) +static int tolua_get_alliance(lua_State * L) { int no = tolua_toid(L, 1, 0); - alliance * f = findalliance(no); + alliance *f = findalliance(no); tolua_pushusertype(L, f, TOLUA_CAST "alliance"); return 1; } -static int tolua_get_unit(lua_State * L) +static int tolua_get_unit(lua_State * L) { int no = tolua_toid(L, 1, 0); - unit * u = findunit(no); + unit *u = findunit(no); tolua_pushusertype(L, u, TOLUA_CAST "unit"); return 1; } -static int tolua_alliance_create(lua_State * L) +static int tolua_alliance_create(lua_State * L) { int id = (int)tolua_tonumber(L, 1, 0); const char *name = tolua_tostring(L, 2, 0); - alliance * alli = makealliance(id, name); + alliance *alli = makealliance(id, name); tolua_pushusertype(L, alli, TOLUA_CAST "alliance"); return 1; } -static int tolua_get_regions(lua_State * L) +static int tolua_get_regions(lua_State * L) { - region ** region_ptr = (region **) lua_newuserdata(L, sizeof(region *)); + region **region_ptr = (region **) lua_newuserdata(L, sizeof(region *)); luaL_getmetatable(L, "region"); lua_setmetatable(L, -2); *region_ptr = regions; @@ -646,9 +646,9 @@ static int tolua_get_regions(lua_State * L) return 1; } -static int tolua_get_factions(lua_State * L) +static int tolua_get_factions(lua_State * L) { - faction ** faction_ptr = (faction **) lua_newuserdata(L, sizeof(faction *)); + faction **faction_ptr = (faction **) lua_newuserdata(L, sizeof(faction *)); luaL_getmetatable(L, "faction"); lua_setmetatable(L, -2); *faction_ptr = factions; @@ -656,48 +656,47 @@ static int tolua_get_factions(lua_State * L) return 1; } -static int tolua_get_alliance_factions(lua_State * L) +static int tolua_get_alliance_factions(lua_State * L) { - alliance * self = (alliance *) tolua_tousertype(L, 1, 0); + alliance *self = (alliance *) tolua_tousertype(L, 1, 0); return tolua_quicklist_push(L, "faction_list", "faction", self->members); } -static int tolua_get_alliance_id(lua_State * L) +static int tolua_get_alliance_id(lua_State * L) { - alliance * self = (alliance *) tolua_tousertype(L, 1, 0); + alliance *self = (alliance *) tolua_tousertype(L, 1, 0); tolua_pushnumber(L, (lua_Number) self->id); return 1; } -static int tolua_get_alliance_name(lua_State * L) +static int tolua_get_alliance_name(lua_State * L) { - alliance * self = (alliance *) tolua_tousertype(L, 1, 0); + alliance *self = (alliance *) tolua_tousertype(L, 1, 0); tolua_pushstring(L, self->name); return 1; } -static int tolua_set_alliance_name(lua_State * L) +static int tolua_set_alliance_name(lua_State * L) { - alliance * self = (alliance *) tolua_tousertype(L, 1, 0); + alliance *self = (alliance *) tolua_tousertype(L, 1, 0); alliance_setname(self, tolua_tostring(L, 2, 0)); return 0; } - #include #include #include #include -static int tolua_write_spells(lua_State * L) +static int tolua_write_spells(lua_State * L) { spell_f fun = (spell_f) get_function("lua_castspell"); const char *filename = "magic.xml"; xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); xmlNodePtr root = xmlNewNode(NULL, BAD_CAST "spells"); - quicklist * ql; + quicklist *ql; int qi; for (ql = spells, qi = 0; ql; ql_advance(&ql, &qi, 1)) { - spell * sp = (spell *) ql_get(ql, qi); + spell *sp = (spell *) ql_get(ql, qi); if (sp->sp_function != fun) { int combat = 0; xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "spell"); @@ -711,7 +710,7 @@ static int tolua_write_spells(lua_State * L) if (sp->parameter) xmlNewProp(node, BAD_CAST "parameters", BAD_CAST sp->parameter); if (sp->components) { - spell_component * comp = sp->components; + spell_component *comp = sp->components; for (; comp->type != 0; ++comp) { static const char *costs[] = { "fixed", "level", "linear" }; xmlNodePtr cnode = xmlNewNode(NULL, BAD_CAST "resource"); @@ -737,10 +736,10 @@ static int tolua_write_spells(lua_State * L) } if (sp->sptyp & POSTCOMBATSPELL) combat = 3; - + else if (sp->sptyp & COMBATSPELL) combat = 2; - + else if (sp->sptyp & PRECOMBATSPELL) combat = 1; if (combat) { @@ -756,20 +755,20 @@ static int tolua_write_spells(lua_State * L) return 0; } -static int config_get_ships(lua_State * L) +static int config_get_ships(lua_State * L) { - quicklist * ql; + quicklist *ql; int qi, i = 0; lua_createtable(L, ql_length(shiptypes), 0); for (qi = 0, ql = shiptypes; ql; ql_advance(&ql, &qi, 1)) { - ship_type * stype = (ship_type *) ql_get(ql, qi); + ship_type *stype = (ship_type *) ql_get(ql, qi); tolua_pushstring(L, TOLUA_CAST stype->name[0]); lua_rawseti(L, -2, ++i); } return 1; } -static int config_get_locales(lua_State * L) +static int config_get_locales(lua_State * L) { const struct locale *lang; int i = 0, n = 0; @@ -783,7 +782,7 @@ static int config_get_locales(lua_State * L) return 1; } -static int config_get_resource(lua_State * L) +static int config_get_resource(lua_State * L) { const char *name = tolua_tostring(L, 1, 0); if (name) { @@ -824,42 +823,42 @@ static int config_get_resource(lua_State * L) return 0; } -static int tolua_get_spell_text(lua_State * L) +static int tolua_get_spell_text(lua_State * L) { const struct locale *loc = default_locale; - spell * self = (spell *) tolua_tousertype(L, 1, 0); + spell *self = (spell *) tolua_tousertype(L, 1, 0); lua_pushstring(L, spell_info(self, loc)); return 1; } -static int tolua_get_spell_school(lua_State * L) +static int tolua_get_spell_school(lua_State * L) { - spell * self = (spell *) tolua_tousertype(L, 1, 0); + spell *self = (spell *) tolua_tousertype(L, 1, 0); lua_pushstring(L, magic_school[self->magietyp]); return 1; } -static int tolua_get_spell_level(lua_State * L) +static int tolua_get_spell_level(lua_State * L) { - spell * self = (spell *) tolua_tousertype(L, 1, 0); + spell *self = (spell *) tolua_tousertype(L, 1, 0); lua_pushnumber(L, self->level); return 1; } -static int tolua_get_spell_name(lua_State * L) +static int tolua_get_spell_name(lua_State * L) { const struct locale *lang = default_locale; - spell * self = (spell *) tolua_tousertype(L, 1, 0); + spell *self = (spell *) tolua_tousertype(L, 1, 0); lua_pushstring(L, spell_name(self, lang)); return 1; } -static int tolua_get_spells(lua_State * L) +static int tolua_get_spells(lua_State * L) { return tolua_quicklist_push(L, "spell_list", "spell", spells); } -int tolua_read_xml(lua_State * L) +int tolua_read_xml(lua_State * L) { const char *filename = tolua_tostring(L, 1, 0); const char *catalog = tolua_tostring(L, 2, 0); @@ -867,15 +866,15 @@ int tolua_read_xml(lua_State * L) return 0; } -int tolua_process_markets(lua_State * L) +int tolua_process_markets(lua_State * L) { do_markets(); return 0; } -int tolua_process_produce(lua_State * L) +int tolua_process_produce(lua_State * L) { - region * r; + region *r; for (r = regions; r; r = r->next) { produce(r); } @@ -884,19 +883,19 @@ int tolua_process_produce(lua_State * L) typedef struct event_args { int hfunction; - int hargs; - const char *sendertype; + int hargs; + const char *sendertype; } event_args; -static void args_free(void *udata) +static void args_free(void *udata) { free(udata); } -static void event_cb(void *sender, const char *event, void *udata) +static void event_cb(void *sender, const char *event, void *udata) { - lua_State * L = (lua_State *) global.vm_state; - event_args * args = (event_args *) udata; + lua_State *L = (lua_State *) global.vm_state; + event_args *args = (event_args *) udata; int nargs = 2; lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); if (sender && args->sendertype) { @@ -917,12 +916,12 @@ static void event_cb(void *sender, const char *event, void *udata) * 2: event (string) * 3: handler (function) * 4: arguments (any, *optional*) -**/ -static int tolua_eventbus_register(lua_State * L) +**/ +static int tolua_eventbus_register(lua_State * L) { void *sender = tolua_tousertype(L, 1, 0); const char *event = tolua_tostring(L, 2, 0); - event_args * args = malloc(sizeof(event_args)); + event_args *args = malloc(sizeof(event_args)); args->sendertype = sender ? tolua_typename(L, 1) : NULL; lua_pushvalue(L, 3); args->hfunction = luaL_ref(L, LUA_REGISTRYINDEX); @@ -936,7 +935,7 @@ static int tolua_eventbus_register(lua_State * L) return 0; } -static int tolua_eventbus_fire(lua_State * L) +static int tolua_eventbus_fire(lua_State * L) { void *sender = tolua_tousertype(L, 1, 0); const char *event = tolua_tostring(L, 2, 0); @@ -945,24 +944,24 @@ static int tolua_eventbus_fire(lua_State * L) return 0; } -static int tolua_report_unit(lua_State * L) +static int tolua_report_unit(lua_State * L) { char buffer[512]; - unit * u = (unit *) tolua_tousertype(L, 1, 0); - faction * f = (faction *) tolua_tousertype(L, 2, 0); + unit *u = (unit *) tolua_tousertype(L, 1, 0); + faction *f = (faction *) tolua_tousertype(L, 2, 0); bufunit(f, u, 0, see_unit, buffer, sizeof(buffer)); tolua_pushstring(L, buffer); return 1; } -static int tolua_settings_get(lua_State * L) +static int tolua_settings_get(lua_State * L) { const char *name = tolua_tostring(L, 1, 0); tolua_pushstring(L, get_param(global.parameters, name)); return 1; } -static int tolua_settings_set(lua_State * L) +static int tolua_settings_set(lua_State * L) { const char *name = tolua_tostring(L, 1, 0); const char *value = tolua_tostring(L, 2, 0); @@ -970,8 +969,7 @@ static int tolua_settings_set(lua_State * L) return 0; } -static void -parse_inifile(lua_State * L, dictionary * d, const char *section) +static void parse_inifile(lua_State * L, dictionary * d, const char *section) { int i; size_t len = strlen(section); @@ -990,18 +988,18 @@ parse_inifile(lua_State * L, dictionary * d, const char *section) lua_rawset(L, -3); } } - - /* special case */ - lua_pushstring(L, "basepath"); + + /* special case */ + lua_pushstring(L, "basepath"); lua_pushstring(L, basepath()); lua_rawset(L, -3); } -int tolua_eressea_open(lua_State * L) +int tolua_eressea_open(lua_State * L) { tolua_open(L); - - /* register user types */ + + /* register user types */ tolua_usertype(L, TOLUA_CAST "spell"); tolua_usertype(L, TOLUA_CAST "spell_list"); tolua_usertype(L, TOLUA_CAST "order"); @@ -1029,7 +1027,8 @@ int tolua_eressea_open(lua_State * L) NULL); tolua_function(L, TOLUA_CAST "create", tolua_alliance_create); } tolua_endmodule(L); - tolua_cclass(L, TOLUA_CAST "spell", TOLUA_CAST "spell", TOLUA_CAST "", NULL); + tolua_cclass(L, TOLUA_CAST "spell", TOLUA_CAST "spell", TOLUA_CAST "", + NULL); tolua_beginmodule(L, TOLUA_CAST "spell"); { tolua_function(L, TOLUA_CAST "__tostring", tolua_get_spell_name); @@ -1088,11 +1087,10 @@ int tolua_eressea_open(lua_State * L) tolua_function(L, TOLUA_CAST "message_unit", tolua_message_unit); tolua_function(L, TOLUA_CAST "message_faction", tolua_message_faction); tolua_function(L, TOLUA_CAST "message_region", tolua_message_region); - - /* scripted monsters */ - tolua_function(L, TOLUA_CAST "spawn_braineaters", - tolua_spawn_braineaters); - + + /* scripted monsters */ + tolua_function(L, TOLUA_CAST "spawn_braineaters", tolua_spawn_braineaters); + tolua_function(L, TOLUA_CAST "update_guards", tolua_update_guards); tolua_function(L, TOLUA_CAST "set_turn", &tolua_set_turn); tolua_function(L, TOLUA_CAST "get_turn", &tolua_get_turn); @@ -1104,8 +1102,10 @@ int tolua_eressea_open(lua_State * L) tolua_function(L, TOLUA_CAST "itoa36", tolua_itoa36); tolua_function(L, TOLUA_CAST "dice_roll", tolua_dice_rand); tolua_function(L, TOLUA_CAST "get_nmrs", tolua_get_nmrs); - tolua_function(L, TOLUA_CAST "remove_empty_units", tolua_remove_empty_units); - tolua_function(L, TOLUA_CAST "update_subscriptions", tolua_update_subscriptions); + tolua_function(L, TOLUA_CAST "remove_empty_units", + tolua_remove_empty_units); + tolua_function(L, TOLUA_CAST "update_subscriptions", + tolua_update_subscriptions); tolua_function(L, TOLUA_CAST "update_scores", tolua_update_scores); tolua_function(L, TOLUA_CAST "update_owners", tolua_update_owners); tolua_function(L, TOLUA_CAST "learn_skill", tolua_learn_skill); diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index dd97be767..4097b055f 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -124,14 +124,15 @@ static void recruit_init(void) int income(const unit * u) { switch (old_race(u->race)) { - case RC_FIREDRAGON: - return 150 * u->number; - case RC_DRAGON: - return 1000 * u->number; - case RC_WYRM: - return 5000 * u->number; + case RC_FIREDRAGON: + return 150 * u->number; + case RC_DRAGON: + return 1000 * u->number; + case RC_WYRM: + return 5000 * u->number; + default: + return 20 * u->number; } - return 20 * u->number; } static void scramble(void *data, int n, size_t width) @@ -356,8 +357,7 @@ static int do_recruiting(recruitment * recruits, int available) number = MIN(req->qty, (int)(get / multi)); if (rc->recruitcost) { - int afford = - get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, + int afford = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, number * rc->recruitcost) / rc->recruitcost; number = MIN(number, afford); use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, @@ -1297,22 +1297,22 @@ static int recruit_archetype(unit * u, order * ord) return n; } else switch (n) { - case ENOMATERIALS: - ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, arch->ctype, - want)); - break; - case ELOWSKILL: - case ENEEDSKILL: - /* no skill, or not enough skill points to build */ - cmistake(u, ord, 50, MSG_PRODUCE); - break; - case EBUILDINGREQ: - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "building_needed", "building", - arch->ctype->btype->_name)); - break; - default: - assert(!"unhandled return value from build() in recruit_archetype"); + case ENOMATERIALS: + ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, arch->ctype, + want)); + break; + case ELOWSKILL: + case ENEEDSKILL: + /* no skill, or not enough skill points to build */ + cmistake(u, ord, 50, MSG_PRODUCE); + break; + case EBUILDINGREQ: + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "building_needed", "building", + arch->ctype->btype->_name)); + break; + default: + assert(!"unhandled return value from build() in recruit_archetype"); } return 0; } @@ -1340,27 +1340,21 @@ void economics(region * r) boolean destroyed = false; if (u->number > 0) { for (ord = u->orders; ord; ord = ord->next) { - switch (get_keyword(ord)) { - case K_DESTROY: - if (!destroyed) { - if (destroy_cmd(u, ord) != 0) - ord = NULL; - destroyed = true; - } - break; - - case K_GIVE: - case K_LIEFERE: - give_cmd(u, ord); - break; - - case K_FORGET: - forget_cmd(u, ord); - break; - + keyword_t kwd = get_keyword(ord); + if (kwd == K_DESTROY) { + if (!destroyed) { + if (destroy_cmd(u, ord) != 0) + ord = NULL; + destroyed = true; + } + } else if (kwd == K_GIVE || kwd == K_LIEFERE) { + give_cmd(u, ord); + } else if (kwd == K_FORGET) { + forget_cmd(u, ord); } - if (u->orders == NULL) + if (u->orders == NULL) { break; + } } } } @@ -1418,24 +1412,24 @@ static void manufacture(unit * u, const item_type * itype, int want) } n = build(u, itype->construction, 0, want); switch (n) { - case ENEEDSKILL: - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "skill_needed", "skill", sk)); - return; - case EBUILDINGREQ: - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "building_needed", "building", - itype->construction->btype->_name)); - return; - case ELOWSKILL: - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "manufacture_skills", - "skill minskill product", sk, minskill, itype->rtype, 1)); - return; - case ENOMATERIALS: - ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, - itype->construction, want)); - return; + case ENEEDSKILL: + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "skill_needed", "skill", sk)); + return; + case EBUILDINGREQ: + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "building_needed", "building", + itype->construction->btype->_name)); + return; + case ELOWSKILL: + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "manufacture_skills", + "skill minskill product", sk, minskill, itype->rtype, 1)); + return; + case ENOMATERIALS: + ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, + itype->construction, want)); + return; } if (n > 0) { i_change(&u->items, itype, n); @@ -1829,33 +1823,33 @@ static void create_potion(unit * u, const potion_type * ptype, int want) } built = build(u, ptype->itype->construction, 0, want); switch (built) { - case ELOWSKILL: - case ENEEDSKILL: - /* no skill, or not enough skill points to build */ - cmistake(u, u->thisorder, 50, MSG_PRODUCE); - break; - case EBUILDINGREQ: - ADDMSG(&u->faction->msgs, - msg_feedback(u, u->thisorder, "building_needed", "building", - ptype->itype->construction->btype->_name)); - break; - case ECOMPLETE: - assert(0); - break; - case ENOMATERIALS: - /* something missing from the list of materials */ - ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, - ptype->itype->construction, want)); - return; - break; - default: - i_change(&u->items, ptype->itype, built); - if (want == INT_MAX) - want = built; - ADDMSG(&u->faction->msgs, msg_message("manufacture", - "unit region amount wanted resource", u, u->region, built, want, - ptype->itype->rtype)); - break; + case ELOWSKILL: + case ENEEDSKILL: + /* no skill, or not enough skill points to build */ + cmistake(u, u->thisorder, 50, MSG_PRODUCE); + break; + case EBUILDINGREQ: + ADDMSG(&u->faction->msgs, + msg_feedback(u, u->thisorder, "building_needed", "building", + ptype->itype->construction->btype->_name)); + break; + case ECOMPLETE: + assert(0); + break; + case ENOMATERIALS: + /* something missing from the list of materials */ + ADDMSG(&u->faction->msgs, msg_materials_required(u, u->thisorder, + ptype->itype->construction, want)); + return; + break; + default: + i_change(&u->items, ptype->itype, built); + if (want == INT_MAX) + want = built; + ADDMSG(&u->faction->msgs, msg_message("manufacture", + "unit region amount wanted resource", u, u->region, built, want, + ptype->itype->rtype)); + break; } } @@ -2862,26 +2856,25 @@ static void breed_cmd(unit * u, struct order *ord) } switch (p) { - case P_HERBS: - plant(r, u, m); - break; - case P_TREES: - breedtrees(r, u, m); - break; - default: - if (p != P_ANY) { - rtype = findresourcetype(s, u->faction->locale); - if (rtype == rt_mallornseed || rtype == rt_seed) { - breedtrees(r, u, m); - break; - } else if (rtype != oldresourcetype[R_HORSE]) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_cannotmake", - "")); - break; - } + case P_HERBS: + plant(r, u, m); + break; + case P_TREES: + breedtrees(r, u, m); + break; + default: + if (p != P_ANY) { + rtype = findresourcetype(s, u->faction->locale); + if (rtype == rt_mallornseed || rtype == rt_seed) { + breedtrees(r, u, m); + break; + } else if (rtype != oldresourcetype[R_HORSE]) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_cannotmake", "")); + break; } - breedhorses(r, u); - break; + } + breedhorses(r, u); + break; } } @@ -3446,17 +3439,15 @@ void produce(struct region *r) } for (ord = u->orders; ord; ord = ord->next) { - switch (get_keyword(ord)) { - case K_BUY: - buy(u, &buyorders, ord); - trader = true; - break; - case K_SELL: - /* sell returns true if the sale is not limited - * by the region limit */ - limited &= !sell(u, &sellorders, ord); - trader = true; - break; + keyword_t kwd = get_keyword(ord); + if (kwd == K_BUY) { + buy(u, &buyorders, ord); + trader = true; + } else if (kwd == K_SELL) { + /* sell returns true if the sale is not limited + * by the region limit */ + limited &= !sell(u, &sellorders, ord); + trader = true; } } if (trader) { @@ -3479,41 +3470,41 @@ void produce(struct region *r) switch (todo) { - case K_ENTERTAIN: - entertain_cmd(u, u->thisorder); - break; + case K_ENTERTAIN: + entertain_cmd(u, u->thisorder); + break; - case K_WORK: - if (!rule_autowork && do_work(u, u->thisorder, nextworker) == 0) { - assert(nextworker - workers < MAX_WORKERS); - ++nextworker; - } - break; + case K_WORK: + if (!rule_autowork && do_work(u, u->thisorder, nextworker) == 0) { + assert(nextworker - workers < MAX_WORKERS); + ++nextworker; + } + break; - case K_TAX: - tax_cmd(u, u->thisorder, &taxorders); - break; + case K_TAX: + tax_cmd(u, u->thisorder, &taxorders); + break; - case K_STEAL: - steal_cmd(u, u->thisorder, &stealorders); - break; + case K_STEAL: + steal_cmd(u, u->thisorder, &stealorders); + break; - case K_SPY: - spy_cmd(u, u->thisorder); - break; + case K_SPY: + spy_cmd(u, u->thisorder); + break; - case K_SABOTAGE: - sabotage_cmd(u, u->thisorder); - break; + case K_SABOTAGE: + sabotage_cmd(u, u->thisorder); + break; - case K_PLANT: - case K_BREED: - breed_cmd(u, u->thisorder); - break; + case K_PLANT: + case K_BREED: + breed_cmd(u, u->thisorder); + break; - case K_RESEARCH: - research_cmd(u, u->thisorder); - break; + case K_RESEARCH: + research_cmd(u, u->thisorder); + break; } } diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 19dd3dbd6..a0c16ada4 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -135,8 +135,8 @@ static int RemoveNMRNewbie(void) static void restart_race(unit * u, const race * rc) { faction *oldf = u->faction; - faction *f = - addfaction(oldf->email, oldf->passw, rc, oldf->locale, oldf->subscription); + faction *f = addfaction(oldf->email, oldf->passw, rc, oldf->locale, + oldf->subscription); unit *nu = addplayer(u->region, f); order **ordp = &u->orders; f->subscription = u->faction->subscription; @@ -306,7 +306,8 @@ static void get_food(region * r) } } for (v = r->units; need && v; v = v->next) { - if (v->faction != f && alliedunit(v, f, HELP_MONEY) && help_money(v)) { + if (v->faction != f && alliedunit(v, f, HELP_MONEY) + && help_money(v)) { help_feed(v, u, &need); } } @@ -419,8 +420,8 @@ static void age_unit(region * r, unit * u) if ((itm->type->flags & ITF_NOTLOST) == 0) { if (itm->type->flags & (ITF_BIG | ITF_ANIMAL | ITF_CURSED)) { ADDMSG(&u->faction->msgs, msg_message("itemcrumble", - "unit region item amount", u, u->region, itm->type->rtype, - itm->number)); + "unit region item amount", + u, u->region, itm->type->rtype, itm->number)); i_free(i_remove(itemp, itm)); continue; } @@ -1056,8 +1057,7 @@ static void transfer_faction(faction * f, faction * f2) for (u = f->units; u;) { un = u->nextF; if (!unit_has_cursed_item(u) - && !has_skill(u, SK_MAGIC) - && !has_skill(u, SK_ALCHEMY)) { + && !has_skill(u, SK_MAGIC) && !has_skill(u, SK_ALCHEMY)) { u_setfaction(u, f2); } u = un; @@ -1358,62 +1358,62 @@ static int ally_cmd(unit * u, struct order *ord) } } switch (keyword) { - case P_NOT: + case P_NOT: + sf->status = 0; + break; + + case NOPARAM: + cmistake(u, ord, 137, MSG_EVENT); + return 0; + + case P_ANY: + if (not_kw == P_NOT) sf->status = 0; - break; + else + sf->status = HELP_ALL; + break; - case NOPARAM: - cmistake(u, ord, 137, MSG_EVENT); - return 0; + case P_TRAVEL: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_TRAVEL); + else + sf->status = sf->status | HELP_TRAVEL; + break; - case P_ANY: - if (not_kw == P_NOT) - sf->status = 0; - else - sf->status = HELP_ALL; - break; + case P_GIVE: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_GIVE); + else + sf->status = sf->status | HELP_GIVE; + break; - case P_TRAVEL: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_TRAVEL); - else - sf->status = sf->status | HELP_TRAVEL; - break; + case P_MONEY: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_MONEY); + else + sf->status = sf->status | HELP_MONEY; + break; - case P_GIVE: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_GIVE); - else - sf->status = sf->status | HELP_GIVE; - break; + case P_FIGHT: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_FIGHT); + else + sf->status = sf->status | HELP_FIGHT; + break; - case P_MONEY: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_MONEY); - else - sf->status = sf->status | HELP_MONEY; - break; + case P_FACTIONSTEALTH: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_FSTEALTH); + else + sf->status = sf->status | HELP_FSTEALTH; + break; - case P_FIGHT: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_FIGHT); - else - sf->status = sf->status | HELP_FIGHT; - break; - - case P_FACTIONSTEALTH: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_FSTEALTH); - else - sf->status = sf->status | HELP_FSTEALTH; - break; - - case P_GUARD: - if (not_kw == P_NOT) - sf->status = sf->status & (HELP_ALL - HELP_GUARD); - else - sf->status = sf->status | HELP_GUARD; - break; + case P_GUARD: + if (not_kw == P_NOT) + sf->status = sf->status & (HELP_ALL - HELP_GUARD); + else + sf->status = sf->status | HELP_GUARD; + break; } sf->status &= HelpMask(); @@ -1536,69 +1536,69 @@ static int display_cmd(unit * u, struct order *ord) skip_token(); switch (getparam(u->faction->locale)) { - case P_BUILDING: - case P_GEBAEUDE: - if (!b) { - cmistake(u, ord, 145, MSG_PRODUCE); - break; - } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 5, MSG_PRODUCE); - break; - } - if (!fval(b->type, BTF_NAMECHANGE) && b->display && b->display[0] != 0) { - cmistake(u, ord, 278, MSG_EVENT); - break; - } - s = &b->display; + case P_BUILDING: + case P_GEBAEUDE: + if (!b) { + cmistake(u, ord, 145, MSG_PRODUCE); break; - - case P_SHIP: - if (!u->ship) { - cmistake(u, ord, 144, MSG_PRODUCE); - break; - } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 12, MSG_PRODUCE); - break; - } - s = &u->ship->display; - break; - - case P_UNIT: - s = &u->display; - break; - - case P_PRIVAT: - { - const char *d = getstrtoken(); - if (d == NULL || *d == 0) { - usetprivate(u, NULL); - } else { - usetprivate(u, d); - } } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 5, MSG_PRODUCE); break; + } + if (!fval(b->type, BTF_NAMECHANGE) && b->display && b->display[0] != 0) { + cmistake(u, ord, 278, MSG_EVENT); + break; + } + s = &b->display; + break; - case P_REGION: - if (!b) { - cmistake(u, ord, 145, MSG_EVENT); - break; - } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 148, MSG_EVENT); - break; - } - if (b != largestbuilding(r, get_cmp_region_owner(), false)) { - cmistake(u, ord, 147, MSG_EVENT); - break; - } - s = &r->display; + case P_SHIP: + if (!u->ship) { + cmistake(u, ord, 144, MSG_PRODUCE); break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 12, MSG_PRODUCE); + break; + } + s = &u->ship->display; + break; - default: - cmistake(u, ord, 110, MSG_EVENT); + case P_UNIT: + s = &u->display; + break; + + case P_PRIVAT: + { + const char *d = getstrtoken(); + if (d == NULL || *d == 0) { + usetprivate(u, NULL); + } else { + usetprivate(u, d); + } + } + break; + + case P_REGION: + if (!b) { + cmistake(u, ord, 145, MSG_EVENT); break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 148, MSG_EVENT); + break; + } + if (b != largestbuilding(r, get_cmp_region_owner(), false)) { + cmistake(u, ord, 147, MSG_EVENT); + break; + } + s = &r->display; + break; + + default: + cmistake(u, ord, 110, MSG_EVENT); + break; } if (s != NULL) { @@ -1669,10 +1669,12 @@ rename_building(unit * u, order * ord, building * b, const char *name) if (owner) { if (cansee(owner->faction, u->region, u, 0)) { - ADDMSG(&owner->faction->msgs, msg_message("renamed_building_seen", + ADDMSG(&owner->faction->msgs, + msg_message("renamed_building_seen", "building renamer region", b, u, u->region)); } else { - ADDMSG(&owner->faction->msgs, msg_message("renamed_building_notseen", + ADDMSG(&owner->faction->msgs, + msg_message("renamed_building_notseen", "building region", b, u->region)); } } @@ -1704,182 +1706,181 @@ static int name_cmd(unit * u, struct order *ord) } switch (p) { - case P_ALLIANCE: - if (foreign == false && f_get_alliance(u->faction)) { - alliance *al = u->faction->alliance; - faction *lead = alliance_get_leader(al); - if (lead == u->faction) { - s = &al->name; - } + case P_ALLIANCE: + if (foreign == false && f_get_alliance(u->faction)) { + alliance *al = u->faction->alliance; + faction *lead = alliance_get_leader(al); + if (lead == u->faction) { + s = &al->name; } - break; - case P_BUILDING: - case P_GEBAEUDE: - if (foreign) { - b = getbuilding(u->region); + } + break; + case P_BUILDING: + case P_GEBAEUDE: + if (foreign) { + b = getbuilding(u->region); + } + + return rename_building(u, ord, b, getstrtoken()); + + case P_FACTION: + if (foreign == true) { + faction *f; + + f = getfaction(); + if (!f) { + cmistake(u, ord, 66, MSG_EVENT); + break; } - - return rename_building(u, ord, b, getstrtoken()); - - case P_FACTION: - if (foreign == true) { - faction *f; - - f = getfaction(); - if (!f) { - cmistake(u, ord, 66, MSG_EVENT); - break; - } - if (f->age < 10) { - cmistake(u, ord, 248, MSG_EVENT); - break; - } else { - const struct locale *lang = locales; - for (; lang; lang = nextlocale(lang)) { - const char *fdname = LOC(lang, "factiondefault"); - size_t fdlen = strlen(fdname); - if (strlen(f->name) >= fdlen - && strncmp(f->name, fdname, fdlen) == 0) { - break; - } - } - if (lang == NULL) { - cmistake(u, ord, 247, MSG_EVENT); + if (f->age < 10) { + cmistake(u, ord, 248, MSG_EVENT); + break; + } else { + const struct locale *lang = locales; + for (; lang; lang = nextlocale(lang)) { + const char *fdname = LOC(lang, "factiondefault"); + size_t fdlen = strlen(fdname); + if (strlen(f->name) >= fdlen && strncmp(f->name, fdname, fdlen) == 0) { break; } } - if (cansee(f, r, u, 0)) { - ADDMSG(&f->msgs, msg_message("renamed_faction_seen", "unit region", u, - r)); - } else { - ADDMSG(&f->msgs, msg_message("renamed_faction_notseen", "", r)); - } - s = &f->name; - } else { - s = &u->faction->name; - } - break; - - case P_SHIP: - if (foreign == true) { - ship *sh = getship(r); - unit *uo; - - if (!sh) { - cmistake(u, ord, 20, MSG_EVENT); + if (lang == NULL) { + cmistake(u, ord, 247, MSG_EVENT); break; - } else { - const struct locale *lang = locales; - for (; lang; lang = nextlocale(lang)) { - const char *sdname = LOC(lang, sh->type->name[0]); - size_t sdlen = strlen(sdname); - if (strlen(sh->name) >= sdlen - && strncmp(sh->name, sdname, sdlen) == 0) { - break; - } + } + } + if (cansee(f, r, u, 0)) { + ADDMSG(&f->msgs, + msg_message("renamed_faction_seen", "unit region", u, r)); + } else { + ADDMSG(&f->msgs, msg_message("renamed_faction_notseen", "", r)); + } + s = &f->name; + } else { + s = &u->faction->name; + } + break; - sdname = LOC(lang, parameters[P_SHIP]); - sdlen = strlen(sdname); - if (strlen(sh->name) >= sdlen - && strncmp(sh->name, sdname, sdlen) == 0) { - break; - } + case P_SHIP: + if (foreign == true) { + ship *sh = getship(r); + unit *uo; - } - if (lang == NULL) { - cmistake(u, ord, 245, MSG_EVENT); + if (!sh) { + cmistake(u, ord, 20, MSG_EVENT); + break; + } else { + const struct locale *lang = locales; + for (; lang; lang = nextlocale(lang)) { + const char *sdname = LOC(lang, sh->type->name[0]); + size_t sdlen = strlen(sdname); + if (strlen(sh->name) >= sdlen + && strncmp(sh->name, sdname, sdlen) == 0) { break; } - } - uo = shipowner(sh); - if (uo) { - if (cansee(uo->faction, r, u, 0)) { - ADDMSG(&uo->faction->msgs, msg_message("renamed_ship_seen", - "ship renamer region", sh, u, r)); - } else { - ADDMSG(&uo->faction->msgs, msg_message("renamed_ship_notseen", - "ship region", sh, r)); - } - } - s = &sh->name; - } else { - if (!u->ship) { - cmistake(u, ord, 144, MSG_PRODUCE); - break; - } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 12, MSG_PRODUCE); - break; - } - s = &u->ship->name; - } - break; - case P_UNIT: - if (foreign == true) { - unit *u2 = getunit(r, u->faction); - - if (!u2 || !cansee(u->faction, r, u2, 0)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, - "feedback_unit_not_found", "")); - break; - } else { - const char *udefault = LOC(u2->faction->locale, "unitdefault"); - size_t udlen = strlen(udefault); - size_t unlen = strlen(u2->name); - if (unlen >= udlen && strncmp(u2->name, udefault, udlen) != 0) { - cmistake(u2, ord, 244, MSG_EVENT); + sdname = LOC(lang, parameters[P_SHIP]); + sdlen = strlen(sdname); + if (strlen(sh->name) >= sdlen + && strncmp(sh->name, sdname, sdlen) == 0) { break; } - } - if (cansee(u2->faction, r, u, 0)) { - ADDMSG(&u2->faction->msgs, msg_message("renamed_seen", - "renamer renamed region", u, u2, r)); - } else { - ADDMSG(&u2->faction->msgs, msg_message("renamed_notseen", - "renamed region", u2, r)); - } - s = &u2->name; - } else { - s = &u->name; - } - break; - case P_REGION: - if (!b) { - cmistake(u, ord, 145, MSG_EVENT); + } + if (lang == NULL) { + cmistake(u, ord, 245, MSG_EVENT); + break; + } + } + uo = shipowner(sh); + if (uo) { + if (cansee(uo->faction, r, u, 0)) { + ADDMSG(&uo->faction->msgs, + msg_message("renamed_ship_seen", "ship renamer region", sh, u, r)); + } else { + ADDMSG(&uo->faction->msgs, + msg_message("renamed_ship_notseen", "ship region", sh, r)); + } + } + s = &sh->name; + } else { + if (!u->ship) { + cmistake(u, ord, 144, MSG_PRODUCE); break; } if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 148, MSG_EVENT); + cmistake(u, ord, 12, MSG_PRODUCE); break; } + s = &u->ship->name; + } + break; - if (b != largestbuilding(r, get_cmp_region_owner(), false)) { - cmistake(u, ord, 147, MSG_EVENT); - break; - } - s = &r->land->name; - break; + case P_UNIT: + if (foreign == true) { + unit *u2 = getunit(r, u->faction); - case P_GROUP: - { - attrib *a = NULL; - if (fval(u, UFL_GROUP)) - a = a_find(u->attribs, &at_group); - if (a) { - group *g = (group *) a->data.v; - s = &g->name; + if (!u2 || !cansee(u->faction, r, u2, 0)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, + "feedback_unit_not_found", "")); break; } else { - cmistake(u, ord, 109, MSG_EVENT); - break; + const char *udefault = LOC(u2->faction->locale, "unitdefault"); + size_t udlen = strlen(udefault); + size_t unlen = strlen(u2->name); + if (unlen >= udlen && strncmp(u2->name, udefault, udlen) != 0) { + cmistake(u2, ord, 244, MSG_EVENT); + break; + } } + if (cansee(u2->faction, r, u, 0)) { + ADDMSG(&u2->faction->msgs, msg_message("renamed_seen", + "renamer renamed region", u, u2, r)); + } else { + ADDMSG(&u2->faction->msgs, msg_message("renamed_notseen", + "renamed region", u2, r)); + } + s = &u2->name; + } else { + s = &u->name; } + break; + + case P_REGION: + if (!b) { + cmistake(u, ord, 145, MSG_EVENT); break; - default: + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 148, MSG_EVENT); + break; + } + + if (b != largestbuilding(r, get_cmp_region_owner(), false)) { + cmistake(u, ord, 147, MSG_EVENT); + break; + } + s = &r->land->name; + break; + + case P_GROUP: + { + attrib *a = NULL; + if (fval(u, UFL_GROUP)) + a = a_find(u->attribs, &at_group); + if (a) { + group *g = (group *) a->data.v; + s = &g->name; + break; + } else { cmistake(u, ord, 109, MSG_EVENT); break; + } + } + break; + default: + cmistake(u, ord, 109, MSG_EVENT); + break; } if (s != NULL) { @@ -1898,10 +1899,11 @@ deliverMail(faction * f, region * r, unit * u, const char *s, unit * receiver) u = NULL; } if (!receiver) { /* BOTSCHAFT an PARTEI */ - ADDMSG(&f->msgs, msg_message("regionmessage", "region sender string", r, u, - s)); + ADDMSG(&f->msgs, + msg_message("regionmessage", "region sender string", r, u, s)); } else { /* BOTSCHAFT an EINHEIT */ - ADDMSG(&f->msgs, msg_message("unitmessage", "region unit sender string", r, + ADDMSG(&f->msgs, + msg_message("unitmessage", "region unit sender string", r, receiver, u, s)); } } @@ -1917,8 +1919,8 @@ mailunit(region * r, unit * u, int n, struct order *ord, const char *s) } else { /* Immer eine Meldung - sonst könnte man so getarnte EHs enttarnen: * keine Meldung -> EH hier. */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", - "")); + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "feedback_unit_not_found", "")); } } @@ -1950,150 +1952,151 @@ static int mail_cmd(unit * u, struct order *ord) do { cont = 0; switch (findparam(s, u->faction->locale)) { - case P_REGION: - /* können alle Einheiten in der Region sehen */ - s = getstrtoken(); - if (!s[0]) { - cmistake(u, ord, 30, MSG_MESSAGE); - break; - } else { - ADDMSG(&r->msgs, msg_message("mail_result", "unit message", u, s)); - return 0; - } - - case P_FACTION: - { - boolean see = false; - - n = getfactionid(); - - for (u2 = r->units; u2; u2 = u2->next) { - if (u2->faction->no == n && seefaction(u->faction, r, u2, 0)) { - see = true; - break; - } - } - - if (see == false) { - cmistake(u, ord, 66, MSG_MESSAGE); - break; - } - - s = getstrtoken(); - if (!s[0]) { - cmistake(u, ord, 30, MSG_MESSAGE); - break; - } - mailfaction(u, n, ord, s); - return 0; - } - - case P_UNIT: - { - boolean see = false; - n = getid(); - - for (u2 = r->units; u2; u2 = u2->next) { - if (u2->no == n && cansee(u->faction, r, u2, 0)) { - see = true; - break; - } - } - - if (see == false) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, - "feedback_unit_not_found", "")); - return 0; - } - - s = getstrtoken(); - if (!s[0]) { - cmistake(u, ord, 30, MSG_MESSAGE); - break; - } else { - attrib *a = a_find(u2->attribs, &at_eventhandler); - if (a != NULL) { - event_arg args[3]; - args[0].data.v = (void *)s; - args[0].type = "string"; - args[1].data.v = (void *)u; - args[1].type = "unit"; - args[2].type = NULL; - handle_event(a, "message", args); - } - - mailunit(r, u, n, ord, s); - } - return 0; - } - - case P_BUILDING: - case P_GEBAEUDE: - { - building *b = getbuilding(r); - - if (!b) { - cmistake(u, ord, 6, MSG_MESSAGE); - break; - } - - s = getstrtoken(); - - if (!s[0]) { - cmistake(u, ord, 30, MSG_MESSAGE); - break; - } - - for (u2 = r->units; u2; u2 = u2->next) - freset(u2->faction, FFL_SELECT); - - for (u2 = r->units; u2; u2 = u2->next) { - if (u2->building == b && !fval(u2->faction, FFL_SELECT) - && cansee(u->faction, r, u2, 0)) { - mailunit(r, u, u2->no, ord, s); - fset(u2->faction, FFL_SELECT); - } - } - return 0; - } - - case P_SHIP: - { - ship *sh = getship(r); - - if (!sh) { - cmistake(u, ord, 20, MSG_MESSAGE); - break; - } - - s = getstrtoken(); - - if (!s[0]) { - cmistake(u, ord, 30, MSG_MESSAGE); - break; - } - - for (u2 = r->units; u2; u2 = u2->next) - freset(u2->faction, FFL_SELECT); - - for (u2 = r->units; u2; u2 = u2->next) { - if (u2->ship == sh && !fval(u2->faction, FFL_SELECT) - && cansee(u->faction, r, u2, 0)) { - mailunit(r, u, u2->no, ord, s); - fset(u2->faction, FFL_SELECT); - } - } - return 0; - } - - default: - /* possibly filler token? */ - s = getstrtoken(); - if (s && *s) - cont = 1; + case P_REGION: + /* können alle Einheiten in der Region sehen */ + s = getstrtoken(); + if (!s[0]) { + cmistake(u, ord, 30, MSG_MESSAGE); break; + } else { + ADDMSG(&r->msgs, msg_message("mail_result", "unit message", u, s)); + return 0; + } + + case P_FACTION: + { + boolean see = false; + + n = getfactionid(); + + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->faction->no == n && seefaction(u->faction, r, u2, 0)) { + see = true; + break; + } + } + + if (see == false) { + cmistake(u, ord, 66, MSG_MESSAGE); + break; + } + + s = getstrtoken(); + if (!s[0]) { + cmistake(u, ord, 30, MSG_MESSAGE); + break; + } + mailfaction(u, n, ord, s); + return 0; } - } while (cont); + + case P_UNIT: + { + boolean see = false; + n = getid(); + + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->no == n && cansee(u->faction, r, u2, 0)) { + see = true; + break; + } + } + + if (see == false) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, + "feedback_unit_not_found", "")); + return 0; + } + + s = getstrtoken(); + if (!s[0]) { + cmistake(u, ord, 30, MSG_MESSAGE); + break; + } else { + attrib *a = a_find(u2->attribs, &at_eventhandler); + if (a != NULL) { + event_arg args[3]; + args[0].data.v = (void *)s; + args[0].type = "string"; + args[1].data.v = (void *)u; + args[1].type = "unit"; + args[2].type = NULL; + handle_event(a, "message", args); + } + + mailunit(r, u, n, ord, s); + } + return 0; + } + + case P_BUILDING: + case P_GEBAEUDE: + { + building *b = getbuilding(r); + + if (!b) { + cmistake(u, ord, 6, MSG_MESSAGE); + break; + } + + s = getstrtoken(); + + if (!s[0]) { + cmistake(u, ord, 30, MSG_MESSAGE); + break; + } + + for (u2 = r->units; u2; u2 = u2->next) + freset(u2->faction, FFL_SELECT); + + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->building == b && !fval(u2->faction, FFL_SELECT) + && cansee(u->faction, r, u2, 0)) { + mailunit(r, u, u2->no, ord, s); + fset(u2->faction, FFL_SELECT); + } + } + return 0; + } + + case P_SHIP: + { + ship *sh = getship(r); + + if (!sh) { + cmistake(u, ord, 20, MSG_MESSAGE); + break; + } + + s = getstrtoken(); + + if (!s[0]) { + cmistake(u, ord, 30, MSG_MESSAGE); + break; + } + + for (u2 = r->units; u2; u2 = u2->next) + freset(u2->faction, FFL_SELECT); + + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->ship == sh && !fval(u2->faction, FFL_SELECT) + && cansee(u->faction, r, u2, 0)) { + mailunit(r, u, u2->no, ord, s); + fset(u2->faction, FFL_SELECT); + } + } + return 0; + } + + default: + /* possibly filler token? */ + s = getstrtoken(); + if (s && *s) + cont = 1; + break; + } + } + while (cont); cmistake(u, ord, 149, MSG_MESSAGE); return 0; } @@ -2126,8 +2129,8 @@ static int email_cmd(unit * u, struct order *ord) } else { faction *f = u->faction; if (set_email(&f->email, (const char *)s) != 0) { - log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), - s)); + log_error(("Invalid email address for faction %s: %s\n", + itoa36(f->no), s)); ADDMSG(&f->msgs, msg_message("changemail_invalid", "value", s)); } else { ADDMSG(&f->msgs, msg_message("changemail", "value", f->email)); @@ -2370,29 +2373,29 @@ static boolean display_race(faction * f, unit * u, const race * rc) WARN_STATIC_BUFFER(); switch (rc->attack[a].type) { - case AT_STANDARD: - bytes = - snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_standard"), - rc->def_damage); - break; - case AT_NATURAL: - bytes = - snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_natural"), - rc->attack[a].data.dice); - break; - case AT_SPELL: - case AT_COMBATSPELL: - case AT_DRAIN_ST: - case AT_DAZZLE: - bytes = snprintf(bufp, size, "%s", LOC(f->locale, "attack_magical")); - break; - case AT_STRUCTURAL: - bytes = - snprintf(bufp, size, "%s (%s)", LOC(f->locale, "attack_structural"), - rc->attack[a].data.dice); - break; - default: - bytes = 0; + case AT_STANDARD: + bytes = + snprintf(bufp, size, "%s (%s)", + LOC(f->locale, "attack_standard"), rc->def_damage); + break; + case AT_NATURAL: + bytes = + snprintf(bufp, size, "%s (%s)", + LOC(f->locale, "attack_natural"), rc->attack[a].data.dice); + break; + case AT_SPELL: + case AT_COMBATSPELL: + case AT_DRAIN_ST: + case AT_DAZZLE: + bytes = snprintf(bufp, size, "%s", LOC(f->locale, "attack_magical")); + break; + case AT_STRUCTURAL: + bytes = + snprintf(bufp, size, "%s (%s)", + LOC(f->locale, "attack_structural"), rc->attack[a].data.dice); + break; + default: + bytes = 0; } if (bytes && wrptr(&bufp, &size, bytes) != 0) @@ -2421,54 +2424,54 @@ static void reshow(unit * u, struct order *ord, const char *s, param_t p) const race *rc; switch (p) { - case P_ZAUBER: - a_removeall(&u->faction->attribs, &at_seenspell); - break; - case P_POTIONS: - skill = effskill(u, SK_ALCHEMY); - c = 0; - for (ptype = potiontypes; ptype != NULL; ptype = ptype->next) { - if (ptype->level * 2 <= skill) { - c += display_potion(u->faction, u, ptype); - } + case P_ZAUBER: + a_removeall(&u->faction->attribs, &at_seenspell); + break; + case P_POTIONS: + skill = effskill(u, SK_ALCHEMY); + c = 0; + for (ptype = potiontypes; ptype != NULL; ptype = ptype->next) { + if (ptype->level * 2 <= skill) { + c += display_potion(u->faction, u, ptype); } - if (c == 0) - cmistake(u, ord, 285, MSG_EVENT); - break; - case NOPARAM: - /* check if it's an item */ - itype = finditemtype(s, u->faction->locale); - if (itype != NULL) { - ptype = resource2potion(item2resource(itype)); - if (ptype != NULL) { - if (display_potion(u->faction, u, ptype)) - break; - } else { - if (display_item(u->faction, u, itype)) - break; - } - } - /* try for a spell */ - sp = get_spellfromtoken(u, s, u->faction->locale); - if (sp != NULL && u_hasspell(u, sp)) { - attrib *a = a_find(u->faction->attribs, &at_seenspell); - while (a != NULL && a->type == &at_seenspell && a->data.v != sp) - a = a->next; - if (a != NULL) - a_remove(&u->faction->attribs, a); - break; - } - /* last, check if it's a race. */ - rc = findrace(s, u->faction->locale); - if (rc != NULL) { - if (display_race(u->faction, u, rc)) + } + if (c == 0) + cmistake(u, ord, 285, MSG_EVENT); + break; + case NOPARAM: + /* check if it's an item */ + itype = finditemtype(s, u->faction->locale); + if (itype != NULL) { + ptype = resource2potion(item2resource(itype)); + if (ptype != NULL) { + if (display_potion(u->faction, u, ptype)) + break; + } else { + if (display_item(u->faction, u, itype)) break; } - cmistake(u, ord, 21, MSG_EVENT); - break; - default: - cmistake(u, ord, 222, MSG_EVENT); + } + /* try for a spell */ + sp = get_spellfromtoken(u, s, u->faction->locale); + if (sp != NULL && u_hasspell(u, sp)) { + attrib *a = a_find(u->faction->attribs, &at_seenspell); + while (a != NULL && a->type == &at_seenspell && a->data.v != sp) + a = a->next; + if (a != NULL) + a_remove(&u->faction->attribs, a); break; + } + /* last, check if it's a race. */ + rc = findrace(s, u->faction->locale); + if (rc != NULL) { + if (display_race(u->faction, u, rc)) + break; + } + cmistake(u, ord, 21, MSG_EVENT); + break; + default: + cmistake(u, ord, 222, MSG_EVENT); + break; } } @@ -2482,7 +2485,8 @@ static int promotion_cmd(unit * u, struct order *ord) } if (maxheroes(u->faction) < countheroes(u->faction) + u->number) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_maxed", "max count", + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "heroes_maxed", "max count", maxheroes(u->faction), countheroes(u->faction))); return 0; } @@ -2495,8 +2499,8 @@ static int promotion_cmd(unit * u, struct order *ord) money = get_pooled(u, i_silver->rtype, GET_ALL, people); if (people > money) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_cost", "cost have", - people, money)); + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "heroes_cost", "cost have", people, money)); return 0; } use_pooled(u, i_silver->rtype, GET_ALL, people); @@ -2571,38 +2575,38 @@ static int status_cmd(unit * u, struct order *ord) param = getstrtoken(); switch (findparam(param, u->faction->locale)) { - case P_NOT: - setstatus(u, ST_AVOID); - break; - case P_BEHIND: - setstatus(u, ST_BEHIND); - break; - case P_FLEE: - setstatus(u, ST_FLEE); - break; - case P_CHICKEN: - setstatus(u, ST_CHICKEN); - break; - case P_AGGRO: - setstatus(u, ST_AGGRO); - break; - case P_VORNE: + case P_NOT: + setstatus(u, ST_AVOID); + break; + case P_BEHIND: + setstatus(u, ST_BEHIND); + break; + case P_FLEE: + setstatus(u, ST_FLEE); + break; + case P_CHICKEN: + setstatus(u, ST_CHICKEN); + break; + case P_AGGRO: + setstatus(u, ST_AGGRO); + break; + case P_VORNE: + setstatus(u, ST_FIGHT); + break; + case P_HELP: + if (getparam(u->faction->locale) == P_NOT) { + fset(u, UFL_NOAID); + } else { + freset(u, UFL_NOAID); + } + break; + default: + if (param[0]) { + add_message(&u->faction->msgs, + msg_feedback(u, ord, "unknown_status", "")); + } else { setstatus(u, ST_FIGHT); - break; - case P_HELP: - if (getparam(u->faction->locale) == P_NOT) { - fset(u, UFL_NOAID); - } else { - freset(u, UFL_NOAID); - } - break; - default: - if (param[0]) { - add_message(&u->faction->msgs, - msg_feedback(u, ord, "unknown_status", "")); - } else { - setstatus(u, ST_FIGHT); - } + } } return 0; } @@ -2710,7 +2714,8 @@ static int guard_on_cmd(unit * u, struct order *ord) } else { if (fval(u, UFL_MOVED)) { cmistake(u, ord, 187, MSG_EVENT); - } else if (fval(u->race, RCF_ILLUSIONARY) || u->race == new_race[RC_SPELL]) { + } else if (fval(u->race, RCF_ILLUSIONARY) + || u->race == new_race[RC_SPELL]) { cmistake(u, ord, 95, MSG_EVENT); } else { /* Monster der Monsterpartei dürfen immer bewachen */ @@ -2744,14 +2749,14 @@ static void sinkships(region * r) if (fval(r->terrain, SEA_REGION) && (!enoughsailors(sh, r) || get_captain(sh) == NULL)) { /* Schiff nicht seetüchtig */ - float dmg = - get_param_flt(global.parameters, "rules.ship.damage.nocrewocean", + float dmg = get_param_flt(global.parameters, + "rules.ship.damage.nocrewocean", 0.30F); damage_ship(sh, dmg); } if (shipowner(sh) == NULL) { - float dmg = - get_param_flt(global.parameters, "rules.ship.damage.nocrew", 0.05F); + float dmg = get_param_flt(global.parameters, "rules.ship.damage.nocrew", + 0.05F); damage_ship(sh, dmg); } } @@ -2868,26 +2873,31 @@ static void reorder(void) cmistake(u, ord, 10, MSG_EVENT); } else { switch (p) { - case P_AFTER: + case P_AFTER: + *up = u->next; + u->next = v->next; + v->next = u; + fset(u, UFL_MARK); + sorted = true; + break; + case P_BEFORE: + if (fval(v, UFL_OWNER)) { + cmistake(v, ord, 261, MSG_EVENT); + } else { + unit **vp = &r->units; + while (*vp != v) + vp = &(*vp)->next; + *vp = u; *up = u->next; - u->next = v->next; - v->next = u; - break; - case P_BEFORE: - if (fval(v, UFL_OWNER)) { - cmistake(v, ord, 261, MSG_EVENT); - } else { - unit **vp = &r->units; - while (*vp != v) - vp = &(*vp)->next; - *vp = u; - *up = u->next; - u->next = v; - } - break; + u->next = v; + } + fset(u, UFL_MARK); + sorted = true; + break; + default: + /* TODO: syntax error message? */ + break; } - fset(u, UFL_MARK); - sorted = true; } break; } @@ -2898,8 +2908,9 @@ static void reorder(void) } if (sorted) { unit *u; - for (u = r->units; u; u = u->next) + for (u = r->units; u; u = u->next) { freset(u, UFL_MARK); + } } } } @@ -2973,109 +2984,109 @@ static int renumber_cmd(unit * u, order * ord) s = getstrtoken(); switch (findparam(s, u->faction->locale)) { - case P_FACTION: - s = getstrtoken(); - if (s && *s) { - int id = atoi36((const char *)s); - attrib *a = a_find(f->attribs, &at_number); - if (!a) - a = a_add(&f->attribs, a_new(&at_number)); - a->data.i = id; - } - break; + case P_FACTION: + s = getstrtoken(); + if (s && *s) { + int id = atoi36((const char *)s); + attrib *a = a_find(f->attribs, &at_number); + if (!a) + a = a_add(&f->attribs, a_new(&at_number)); + a->data.i = id; + } + break; - case P_UNIT: - s = getstrtoken(); - if (s == NULL || *s == 0) { - i = newunitid(); - } else { - i = atoi36((const char *)s); - if (i <= 0 || i > MAX_UNIT_NR) { - cmistake(u, ord, 114, MSG_EVENT); - break; - } - - if (forbiddenid(i)) { - cmistake(u, ord, 116, MSG_EVENT); - break; - } - - if (findunitg(i, u->region)) { - cmistake(u, ord, 115, MSG_EVENT); - break; - } - } - uunhash(u); - if (!ualias(u)) { - attrib *a = a_add(&u->attribs, a_new(&at_alias)); - a->data.i = -u->no; - } - u->no = i; - uhash(u); - break; - - case P_SHIP: - if (!u->ship) { - cmistake(u, ord, 144, MSG_EVENT); + case P_UNIT: + s = getstrtoken(); + if (s == NULL || *s == 0) { + i = newunitid(); + } else { + i = atoi36((const char *)s); + if (i <= 0 || i > MAX_UNIT_NR) { + cmistake(u, ord, 114, MSG_EVENT); break; } - if (u->ship->coast != NODIRECTION) { + + if (forbiddenid(i)) { cmistake(u, ord, 116, MSG_EVENT); break; } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 146, MSG_EVENT); - break; - } - s = getstrtoken(); - if (s == NULL || *s == 0) { - i = newcontainerid(); - } else { - i = atoi36((const char *)s); - if (i <= 0 || i > MAX_CONTAINER_NR) { - cmistake(u, ord, 114, MSG_EVENT); - break; - } - if (findship(i) || findbuilding(i)) { - cmistake(u, ord, 115, MSG_EVENT); - break; - } - } - sunhash(u->ship); - u->ship->no = i; - shash(u->ship); - break; - case P_BUILDING: - case P_GEBAEUDE: - if (!u->building) { - cmistake(u, ord, 145, MSG_EVENT); - break; - } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 148, MSG_EVENT); - break; - } - s = getstrtoken(); - if (*s == 0) { - i = newcontainerid(); - } else { - i = atoi36((const char *)s); - if (i <= 0 || i > MAX_CONTAINER_NR) { - cmistake(u, ord, 114, MSG_EVENT); - break; - } - if (findship(i) || findbuilding(i)) { - cmistake(u, ord, 115, MSG_EVENT); - break; - } - } - bunhash(u->building); - u->building->no = i; - bhash(u->building); - break; - default: - cmistake(u, ord, 239, MSG_EVENT); + if (findunitg(i, u->region)) { + cmistake(u, ord, 115, MSG_EVENT); + break; + } + } + uunhash(u); + if (!ualias(u)) { + attrib *a = a_add(&u->attribs, a_new(&at_alias)); + a->data.i = -u->no; + } + u->no = i; + uhash(u); + break; + + case P_SHIP: + if (!u->ship) { + cmistake(u, ord, 144, MSG_EVENT); + break; + } + if (u->ship->coast != NODIRECTION) { + cmistake(u, ord, 116, MSG_EVENT); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 146, MSG_EVENT); + break; + } + s = getstrtoken(); + if (s == NULL || *s == 0) { + i = newcontainerid(); + } else { + i = atoi36((const char *)s); + if (i <= 0 || i > MAX_CONTAINER_NR) { + cmistake(u, ord, 114, MSG_EVENT); + break; + } + if (findship(i) || findbuilding(i)) { + cmistake(u, ord, 115, MSG_EVENT); + break; + } + } + sunhash(u->ship); + u->ship->no = i; + shash(u->ship); + break; + case P_BUILDING: + case P_GEBAEUDE: + if (!u->building) { + cmistake(u, ord, 145, MSG_EVENT); + break; + } + if (!fval(u, UFL_OWNER)) { + cmistake(u, ord, 148, MSG_EVENT); + break; + } + s = getstrtoken(); + if (*s == 0) { + i = newcontainerid(); + } else { + i = atoi36((const char *)s); + if (i <= 0 || i > MAX_CONTAINER_NR) { + cmistake(u, ord, 114, MSG_EVENT); + break; + } + if (findship(i) || findbuilding(i)) { + cmistake(u, ord, 115, MSG_EVENT); + break; + } + } + bunhash(u->building); + u->building->no = i; + bhash(u->building); + break; + + default: + cmistake(u, ord, 239, MSG_EVENT); } return 0; } @@ -3118,8 +3129,8 @@ static building *age_building(building * b) } if (unicorns) { ADDMSG(&u->faction->msgs, msg_message("scunicorn", - "unit amount rtype", u, unicorns, - olditemtype[I_ELVENHORSE]->rtype)); + "unit amount rtype", + u, unicorns, olditemtype[I_ELVENHORSE]->rtype)); } } } @@ -3141,8 +3152,8 @@ static building *age_building(building * b) /* the mage reactivates the circle */ c = create_curse(mage, &rt->attribs, ct_astralblock, (float)MAX(1, sk), MAX(1, sk / 2), effect, 0); - ADDMSG(&r->msgs, msg_message("astralshield_activate", - "region unit", r, mage)); + ADDMSG(&r->msgs, + msg_message("astralshield_activate", "region unit", r, mage)); } } else if (mage != NULL) { int sk = effskill(mage, SK_MAGIC); @@ -3364,13 +3375,15 @@ static void new_units(void) if (err) { if (err == 1) { - ADDMSG(&u->faction->msgs, msg_feedback(u, makeord, - "too_many_units_in_alliance", "allowed", - maxunits(u->faction))); + 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))); + ADDMSG(&u->faction->msgs, + msg_feedback(u, makeord, + "too_many_units_in_faction", + "allowed", maxunits(u->faction))); } ordp = &makeord->next; @@ -3436,27 +3449,27 @@ void check_long_orders(unit * u) keyword_t longorder = get_keyword(ord); if (otherorder != MAXKEYWORDS) { switch (longorder) { - case K_CAST: - if (otherorder != longorder) { - cmistake(u, ord, 52, MSG_EVENT); - } - break; - case K_BUY: - if (otherorder == K_SELL) { - otherorder = K_BUY; - } else { - cmistake(u, ord, 52, MSG_EVENT); - } - break; - case K_SELL: - if (otherorder != K_SELL && otherorder != K_BUY) { - cmistake(u, ord, 52, MSG_EVENT); - } - break; - case K_WEREWOLF: - /* don't know what WEREWOLF does... */ - default: + case K_CAST: + if (otherorder != longorder) { cmistake(u, ord, 52, MSG_EVENT); + } + break; + case K_BUY: + if (otherorder == K_SELL) { + otherorder = K_BUY; + } else { + cmistake(u, ord, 52, MSG_EVENT); + } + break; + case K_SELL: + if (otherorder != K_SELL && otherorder != K_BUY) { + cmistake(u, ord, 52, MSG_EVENT); + } + break; + case K_WEREWOLF: + /* don't know what WEREWOLF does... */ + default: + cmistake(u, ord, 52, MSG_EVENT); } } else { otherorder = longorder; @@ -3503,37 +3516,39 @@ static void setdefaults(unit * u) } else { keyword_t keyword = get_keyword(ord); switch (keyword) { - /* Wenn gehandelt wird, darf kein langer Befehl ausgeführt - * werden. Da Handel erst nach anderen langen Befehlen kommt, - * muß das vorher abgefangen werden. Wir merken uns also - * hier, ob die Einheit handelt. */ - case K_BUY: - case K_SELL: - /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht - * werden. */ - trade = true; - break; + /* Wenn gehandelt wird, darf kein langer Befehl ausgeführt + * werden. Da Handel erst nach anderen langen Befehlen kommt, + * muß das vorher abgefangen werden. Wir merken uns also + * hier, ob die Einheit handelt. */ + case K_BUY: + case K_SELL: + /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht + * werden. */ + trade = true; + break; - case K_CAST: - /* dient dazu, das neben Zaubern kein weiterer Befehl - * ausgeführt werden kann, Zaubern ist ein kurzer Befehl */ - set_order(&u->thisorder, NULL); - break; + case K_CAST: + /* dient dazu, das neben Zaubern kein weiterer Befehl + * ausgeführt werden kann, Zaubern ist ein kurzer Befehl */ + set_order(&u->thisorder, NULL); + break; - case K_WEREWOLF: - set_order(&u->thisorder, copy_order(ord)); - break; + case K_WEREWOLF: + set_order(&u->thisorder, copy_order(ord)); + break; - /* Wird je diese Ausschliesslichkeit aufgehoben, muss man aufpassen - * mit der Reihenfolge von Kaufen, Verkaufen etc., damit es Spielern - * nicht moeglich ist, Schulden zu machen. */ + /* Wird je diese Ausschliesslichkeit aufgehoben, muss man aufpassen + * mit der Reihenfolge von Kaufen, Verkaufen etc., damit es Spielern + * nicht moeglich ist, Schulden zu machen. */ + default: + break; } } } - if (hunger) + if (hunger) { return; - + } /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht * werden. */ @@ -3578,18 +3593,20 @@ static double heal_factor(const unit * u) { static float elf_regen = -1; switch (old_race(u->race)) { - case RC_TROLL: - case RC_DAEMON: - return 1.5; - case RC_GOBLIN: - return 2.0; - case RC_ELF: - if (elf_regen < 0) - elf_regen = get_param_flt(u->race->parameters, "regen.forest", 1.0F); - if (elf_regen != 1.0 && r_isforest(u->region)) { - return elf_regen; - } - return 1.0; + case RC_TROLL: + case RC_DAEMON: + return 1.5; + case RC_GOBLIN: + return 2.0; + case RC_ELF: + if (elf_regen < 0) + elf_regen = get_param_flt(u->race->parameters, "regen.forest", 1.0F); + if (elf_regen != 1.0 && r_isforest(u->region)) { + return elf_regen; + } + return 1.0; + default: + return 1.0; } return 1.0; } @@ -3630,8 +3647,8 @@ static void monthly_healing(void) if (fval(u, UFL_HUNGER)) continue; - if (fval(r->terrain, SEA_REGION) && u->ship == NULL && !(canswim(u) - || canfly(u))) { + if (fval(r->terrain, SEA_REGION) && u->ship == NULL + && !(canswim(u) || canfly(u))) { continue; } diff --git a/src/gamecode/study.c b/src/gamecode/study.c index 48ac70971..7138a81b7 100644 --- a/src/gamecode/study.c +++ b/src/gamecode/study.c @@ -104,9 +104,7 @@ boolean is_migrant(unit * u) /* ------------------------------------------------------------- */ boolean magic_lowskill(unit * u) { - if (u->race == new_race[RC_TOAD]) - return true; - return false; + return (u->race == new_race[RC_TOAD]) ? true : false; } /* ------------------------------------------------------------- */ @@ -121,23 +119,22 @@ int study_cost(unit * u, skill_t sk) sprintf(buffer, "skills.cost.%s", skillnames[sk]); cost[sk] = get_param_int(global.parameters, buffer, -1); } - if (cost[sk] >= 0) + if (cost[sk] >= 0) { return cost[sk]; - + } switch (sk) { - case SK_SPY: - return 100; - break; - case SK_TACTICS: - case SK_HERBALISM: - case SK_ALCHEMY: - return 200; - break; - case SK_MAGIC: /* Die Magiekosten betragen 50+Summe(50*Stufe) */ - /* 'Stufe' ist dabei die nächste zu erreichende Stufe */ - stufe = 1 + get_level(u, SK_MAGIC); - return k * (1 + ((stufe + 1) * stufe / 2)); - break; + case SK_SPY: + return 100; + case SK_TACTICS: + case SK_HERBALISM: + case SK_ALCHEMY: + return 200; + case SK_MAGIC: /* Die Magiekosten betragen 50+Summe(50*Stufe) */ + /* 'Stufe' ist dabei die nächste zu erreichende Stufe */ + stufe = 1 + get_level(u, SK_MAGIC); + return k * (1 + ((stufe + 1) * stufe / 2)); + default: + return 0; } return 0; } diff --git a/src/kernel/build.c b/src/kernel/build.c index 7ae38fe48..e75883d8d 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -951,19 +951,19 @@ build_building(unit * u, const building_type * btype, int want, order * ord) built = build(u, btype->construction, built, n); switch (built) { - case ECOMPLETE: - /* the building is already complete */ - cmistake(u, ord, 4, MSG_PRODUCE); - return; - case ENOMATERIALS: - ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, - btype->construction, want)); - return; - case ELOWSKILL: - case ENEEDSKILL: - /* no skill, or not enough skill points to build */ - cmistake(u, ord, 50, MSG_PRODUCE); - return; + case ECOMPLETE: + /* the building is already complete */ + cmistake(u, ord, 4, MSG_PRODUCE); + return; + case ENOMATERIALS: + ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, + btype->construction, want)); + return; + case ELOWSKILL: + case ENEEDSKILL: + /* no skill, or not enough skill points to build */ + cmistake(u, ord, 50, MSG_PRODUCE); + return; } /* at this point, the building size is increased. */ @@ -1324,10 +1324,9 @@ void do_misc(region * r, boolean lasttry) for (uc = r->units; uc; uc = uc->next) { order *ord; for (ord = uc->orders; ord; ord = ord->next) { - switch (get_keyword(ord)) { - case K_CONTACT: - contact_cmd(uc, ord, lasttry); - break; + keyword_t kwd = get_keyword(ord); + if (kwd == K_CONTACT) { + contact_cmd(uc, ord, lasttry); } } } @@ -1349,37 +1348,37 @@ void do_misc(region * r, boolean lasttry) id = getid(); switch (p) { - case P_BUILDING: - case P_GEBAEUDE: - if (u->building && u->building->no == id) - break; - if (enter_building(u, ord, id, lasttry)) { - unit *ub; - for (ub = u; ub; ub = ub->next) { - if (ub->building == u->building) { - ulast = ub; - } + case P_BUILDING: + case P_GEBAEUDE: + if (u->building && u->building->no == id) + break; + if (enter_building(u, ord, id, lasttry)) { + unit *ub; + for (ub = u; ub; ub = ub->next) { + if (ub->building == u->building) { + ulast = ub; } } - break; + } + break; - case P_SHIP: - if (u->ship && u->ship->no == id) - break; - if (enter_ship(u, ord, id, lasttry)) { - unit *ub; - ulast = u; - for (ub = u; ub; ub = ub->next) { - if (ub->ship == u->ship) { - ulast = ub; - } + case P_SHIP: + if (u->ship && u->ship->no == id) + break; + if (enter_ship(u, ord, id, lasttry)) { + unit *ub; + ulast = u; + for (ub = u; ub; ub = ub->next) { + if (ub->ship == u->ship) { + ulast = ub; } } - break; + } + break; - default: - if (lasttry) - cmistake(u, ord, 79, MSG_MOVE); + default: + if (lasttry) + cmistake(u, ord, 79, MSG_MOVE); } if (ulast != NULL) { diff --git a/src/kernel/config.c b/src/kernel/config.c index 2962b9a7f..adaba27db 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -587,15 +587,11 @@ int skill_limit(faction * f, skill_t sk) return fl; } } - switch (sk) { - case SK_MAGIC: - m = max_magicians(f); - break; - case SK_ALCHEMY: - m = - get_param_int(global.parameters, "rules.maxskills.alchemy", - MAXALCHEMISTS); - break; + if (sk == SK_MAGIC) { + m = max_magicians(f); + } else if (sk == SK_ALCHEMY) { + m = get_param_int(global.parameters, "rules.maxskills.alchemy", + MAXALCHEMISTS); } return m; } @@ -607,8 +603,9 @@ int count_skill(faction * f, skill_t sk) for (u = f->units; u; u = u->nextF) { if (has_skill(u, sk)) { - if (!is_familiar(u)) + if (!is_familiar(u)) { n += u->number; + } } } return n; @@ -1585,14 +1582,15 @@ static int read_newunitid(const faction * f, const region * r) int read_unitid(const faction * f, const region * r) { const char *s = getstrtoken(); + param_t param; /* Da s nun nur einen string enthaelt, suchen wir ihn direkt in der * paramliste. machen wir das nicht, dann wird getnewunit in s nach der * nummer suchen, doch dort steht bei temp-units nur "temp" drinnen! */ - switch (findparam(s, f->locale)) { - case P_TEMP: - return read_newunitid(f, r); + param = findparam(s, f->locale); + if (param == P_TEMP) { + return read_newunitid(f, r); } if (!s || *s == 0) return -1; @@ -2492,16 +2490,19 @@ unsigned int guard_flags(const unit * u) flags |= GUARD_RECRUIT; #endif switch (old_race(u->race)) { - case RC_ELF: - if (u->faction->race != u->race) - break; - /* else fallthrough */ - case RC_TREEMAN: - flags |= GUARD_TREES; - break; - case RC_IRONKEEPER: - flags = GUARD_MINING; + case RC_ELF: + if (u->faction->race != u->race) break; + /* else fallthrough */ + case RC_TREEMAN: + flags |= GUARD_TREES; + break; + case RC_IRONKEEPER: + flags = GUARD_MINING; + break; + default: + /* TODO: This should be configuration variables, all of it */ + break; } return flags; } @@ -2932,11 +2933,11 @@ message *movement_error(unit * u, const char *token, order * ord, { direction_t d; switch (error_code) { - case E_MOVE_BLOCKED: - d = finddirection(token, u->faction->locale); - return msg_message("moveblocked", "unit direction", u, d); - case E_MOVE_NOREGION: - return msg_feedback(u, ord, "unknowndirection", "dirname", token); + case E_MOVE_BLOCKED: + d = finddirection(token, u->faction->locale); + return msg_message("moveblocked", "unit direction", u, d); + case E_MOVE_NOREGION: + return msg_feedback(u, ord, "unknowndirection", "dirname", token); } return NULL; } @@ -2953,24 +2954,24 @@ int movewhere(const unit * u, const char *token, region * r, region ** resultp) d = finddirection(token, u->faction->locale); switch (d) { - case D_PAUSE: - *resultp = r; - break; + case D_PAUSE: + *resultp = r; + break; - case NODIRECTION: - r2 = find_special_direction(r, token, u->faction->locale); - if (r2 == NULL) { - return E_MOVE_NOREGION; - } - *resultp = r2; - break; + case NODIRECTION: + r2 = find_special_direction(r, token, u->faction->locale); + if (r2 == NULL) { + return E_MOVE_NOREGION; + } + *resultp = r2; + break; - default: - r2 = rconnect(r, d); - if (r2 == NULL || move_blocked(u, r, r2)) { - return E_MOVE_BLOCKED; - } - *resultp = r2; + default: + r2 = rconnect(r, d); + if (r2 == NULL || move_blocked(u, r, r2)) { + return E_MOVE_BLOCKED; + } + *resultp = r2; } return E_MOVE_OK; } diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 8bfdd4760..fdc206731 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -985,13 +985,13 @@ cancast(unit * u, const spell * sp, int level, int range, struct order * ord) /* sind die Kosten stufenabhängig, so muss itemanz noch mit dem * level multipliziert werden */ switch (sp->components[k].cost) { - case SPC_LEVEL: - case SPC_LINEAR: - itemanz *= level; - break; - case SPC_FIX: - default: - break; + case SPC_LEVEL: + case SPC_LINEAR: + itemanz *= level; + break; + case SPC_FIX: + default: + break; } itemhave = get_pooled(u, rtype, GET_DEFAULT, itemanz); @@ -1206,48 +1206,48 @@ target_resists_magic(unit * magician, void *obj, int objtyp, int t_bonus) return true; switch (objtyp) { - case TYP_UNIT: - { - int at, pa = 0; - skill *sv; - unit *u = (unit *) obj; + case TYP_UNIT: + { + int at, pa = 0; + skill *sv; + unit *u = (unit *) obj; - at = effskill(magician, SK_MAGIC); + at = effskill(magician, SK_MAGIC); - for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - int sk = effskill(u, sv->id); - if (pa < sk) - pa = sk; - } - - /* Contest */ - probability = 0.05 * (10 + pa - at); - - probability += magic_resistance((unit *) obj); - break; + for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { + int sk = effskill(u, sv->id); + if (pa < sk) + pa = sk; } - case TYP_REGION: - /* Bonus durch Zauber */ - probability += - 0.01 * get_curseeffect(((region *) obj)->attribs, C_RESIST_MAGIC, 0); - break; + /* Contest */ + probability = 0.05 * (10 + pa - at); - case TYP_BUILDING: - /* Bonus durch Zauber */ - probability += - 0.01 * get_curseeffect(((building *) obj)->attribs, C_RESIST_MAGIC, 0); + probability += magic_resistance((unit *) obj); + break; + } - /* Bonus durch Typ */ - probability += 0.01 * ((building *) obj)->type->magres; + case TYP_REGION: + /* Bonus durch Zauber */ + probability += + 0.01 * get_curseeffect(((region *) obj)->attribs, C_RESIST_MAGIC, 0); + break; - break; + case TYP_BUILDING: + /* Bonus durch Zauber */ + probability += + 0.01 * get_curseeffect(((building *) obj)->attribs, C_RESIST_MAGIC, 0); - case TYP_SHIP: - /* Bonus durch Zauber */ - probability += - 0.01 * get_curseeffect(((ship *) obj)->attribs, C_RESIST_MAGIC, 0); - break; + /* Bonus durch Typ */ + probability += 0.01 * ((building *) obj)->type->magres; + + break; + + case TYP_SHIP: + /* Bonus durch Zauber */ + probability += + 0.01 * get_curseeffect(((ship *) obj)->attribs, C_RESIST_MAGIC, 0); + break; } probability = MAX(0.02, probability + t_bonus * 0.01); @@ -1348,86 +1348,86 @@ static void do_fumble(castorder * co) ADDMSG(&u->faction->msgs, msg_message("patzer", "unit region spell", u, r, sp)); switch (rng_int() % 10) { - case 0: - /* wenn vorhanden spezieller Patzer, ansonsten nix */ - if (sp->patzer) - sp->patzer(co); - else - patzer(co); - break; + case 0: + /* wenn vorhanden spezieller Patzer, ansonsten nix */ + if (sp->patzer) + sp->patzer(co); + else + patzer(co); + break; - case 1: - /* Kröte */ - { - /* 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 triggerlit of the mage gone toad. - */ - trigger *trestore = trigger_changerace(u, u->race, u->irace); + case 1: + /* Kröte */ + { + /* 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 triggerlit of the mage gone toad. + */ + trigger *trestore = trigger_changerace(u, u->race, u->irace); - if (chance(0.7)) { - const item_type *it_toadslime = it_find("toadslime"); - if (it_toadslime != NULL) { - t_add(&trestore, trigger_giveitem(u, it_toadslime, 1)); - } + if (chance(0.7)) { + const item_type *it_toadslime = it_find("toadslime"); + if (it_toadslime != NULL) { + t_add(&trestore, trigger_giveitem(u, it_toadslime, 1)); } - - duration = rng_int() % level / 2; - if (duration < 2) - duration = 2; - add_trigger(&u->attribs, "timer", trigger_timeout(duration, trestore)); - u->race = new_race[RC_TOAD]; - u->irace = NULL; - ADDMSG(&r->msgs, msg_message("patzer6", "unit region spell", u, r, sp)); - break; } - /* fall-through is intentional! */ - case 2: - /* temporärer Stufenverlust */ - duration = MAX(rng_int() % level / 2, 2); - effect = -0.5 * level; - c = - create_curse(u, &u->attribs, ct_find("skillmod"), (float)level, - duration, effect, 1); - c->data.i = SK_MAGIC; - ADDMSG(&u->faction->msgs, msg_message("patzer2", "unit region", u, r)); - break; - case 3: - case 4: - /* Spruch schlägt fehl, alle Magiepunkte weg */ - set_spellpoints(u, 0); - ADDMSG(&u->faction->msgs, msg_message("patzer3", "unit region spell", - u, r, sp)); - break; + duration = rng_int() % level / 2; + if (duration < 2) + duration = 2; + add_trigger(&u->attribs, "timer", trigger_timeout(duration, trestore)); + u->race = new_race[RC_TOAD]; + u->irace = NULL; + ADDMSG(&r->msgs, msg_message("patzer6", "unit region spell", u, r, sp)); + break; + } + /* fall-through is intentional! */ - case 5: - case 6: - /* Spruch gelingt, aber alle Magiepunkte weg */ - if (sp->sp_function == NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); - } else { - ((nspell_f) sp->sp_function) (co); - } - set_spellpoints(u, 0); - ADDMSG(&u->faction->msgs, msg_message("patzer4", "unit region spell", - u, r, sp)); - break; + case 2: + /* temporärer Stufenverlust */ + duration = MAX(rng_int() % level / 2, 2); + effect = -0.5 * level; + c = + create_curse(u, &u->attribs, ct_find("skillmod"), (float)level, + duration, effect, 1); + c->data.i = SK_MAGIC; + ADDMSG(&u->faction->msgs, msg_message("patzer2", "unit region", u, r)); + break; + case 3: + case 4: + /* Spruch schlägt fehl, alle Magiepunkte weg */ + set_spellpoints(u, 0); + ADDMSG(&u->faction->msgs, msg_message("patzer3", "unit region spell", + u, r, sp)); + break; - case 7: - case 8: - case 9: - default: - /* Spruch gelingt, alle nachfolgenden Sprüche werden 2^4 so teuer */ - if (sp->sp_function == NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); - } else { - ((nspell_f) sp->sp_function) (co); - } - ADDMSG(&u->faction->msgs, msg_message("patzer5", "unit region spell", - u, r, sp)); - countspells(u, 3); + case 5: + case 6: + /* Spruch gelingt, aber alle Magiepunkte weg */ + if (sp->sp_function == NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + } else { + ((nspell_f) sp->sp_function) (co); + } + set_spellpoints(u, 0); + ADDMSG(&u->faction->msgs, msg_message("patzer4", "unit region spell", + u, r, sp)); + break; + + case 7: + case 8: + case 9: + default: + /* Spruch gelingt, alle nachfolgenden Sprüche werden 2^4 so teuer */ + if (sp->sp_function == NULL) { + log_error(("spell '%s' has no function.\n", sp->sname)); + } else { + ((nspell_f) sp->sp_function) (co); + } + ADDMSG(&u->faction->msgs, msg_message("patzer5", "unit region spell", + u, r, sp)); + countspells(u, 3); } return; @@ -1588,16 +1588,16 @@ verify_unit(region * r, unit * mage, const spell * sp, spllprm * spobj, { unit *u = NULL; switch (spobj->typ) { - case SPP_UNIT: - u = findunit(spobj->data.i); - break; - case SPP_TEMP: - u = findnewunit(r, mage->faction, spobj->data.i); - if (u == NULL) - u = findnewunit(mage->region, mage->faction, spobj->data.i); - break; - default: - assert(!"shouldn't happen, this"); + case SPP_UNIT: + u = findunit(spobj->data.i); + break; + case SPP_TEMP: + u = findnewunit(r, mage->faction, spobj->data.i); + if (u == NULL) + u = findnewunit(mage->region, mage->faction, spobj->data.i); + break; + default: + assert(!"shouldn't happen, this"); } if (u != NULL && (sp->sptyp & SEARCHLOCAL)) { if (u->region != r) @@ -1654,21 +1654,21 @@ verify_targets(castorder * co, int *invalid, int *resist, int *success) spllprm *spobj = sa->param[i]; switch (spobj->typ) { - case SPP_TEMP: - case SPP_UNIT: - if (!verify_unit(target_r, mage, sp, spobj, co->order)) - ++ * invalid; - break; - case SPP_BUILDING: - if (!verify_building(target_r, mage, sp, spobj, co->order)) - ++ * invalid; - break; - case SPP_SHIP: - if (!verify_ship(target_r, mage, sp, spobj, co->order)) - ++ * invalid; - break; - default: - break; + case SPP_TEMP: + case SPP_UNIT: + if (!verify_unit(target_r, mage, sp, spobj, co->order)) + ++ * invalid; + break; + case SPP_BUILDING: + if (!verify_building(target_r, mage, sp, spobj, co->order)) + ++ * invalid; + break; + case SPP_SHIP: + if (!verify_ship(target_r, mage, sp, spobj, co->order)) + ++ * invalid; + break; + default: + break; } } @@ -1683,77 +1683,76 @@ verify_targets(castorder * co, int *invalid, int *resist, int *success) if (spobj->flag == TARGET_NOTFOUND) continue; switch (spobj->typ) { - case SPP_TEMP: - case SPP_UNIT: - u = spobj->data.u; + case SPP_TEMP: + case SPP_UNIT: + u = spobj->data.u; - if ((sp->sptyp & TESTRESISTANCE) - && target_resists_magic(mage, u, TYP_UNIT, 0)) { - /* Fehlermeldung */ - spobj->data.i = u->no; - spobj->flag = TARGET_RESISTS; - ++*resist; - ADDMSG(&mage->faction->msgs, msg_message("spellunitresists", - "unit region command target", - mage, mage->region, co->order, u)); - break; - } - - /* TODO: Test auf Parteieigenschaft Magieresistsenz */ - ++*success; + if ((sp->sptyp & TESTRESISTANCE) + && target_resists_magic(mage, u, TYP_UNIT, 0)) { + /* Fehlermeldung */ + spobj->data.i = u->no; + spobj->flag = TARGET_RESISTS; + ++*resist; + ADDMSG(&mage->faction->msgs, msg_message("spellunitresists", + "unit region command target", mage, mage->region, co->order, u)); break; - case SPP_BUILDING: - b = spobj->data.b; + } - if ((sp->sptyp & TESTRESISTANCE) - && target_resists_magic(mage, b, TYP_BUILDING, 0)) { /* Fehlermeldung */ - spobj->data.i = b->no; - spobj->flag = TARGET_RESISTS; - ++*resist; - ADDMSG(&mage->faction->msgs, msg_message("spellbuildingresists", - "unit region command id", - mage, mage->region, co->order, spobj->data.i)); - break; - } - ++*success; - break; - case SPP_SHIP: - sh = spobj->data.sh; + /* TODO: Test auf Parteieigenschaft Magieresistsenz */ + ++*success; + break; + case SPP_BUILDING: + b = spobj->data.b; - if ((sp->sptyp & TESTRESISTANCE) - && target_resists_magic(mage, sh, TYP_SHIP, 0)) { /* Fehlermeldung */ - spobj->data.i = sh->no; - spobj->flag = TARGET_RESISTS; - ++*resist; - ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, - "spellshipresists", "ship", sh)); - break; - } - ++*success; + if ((sp->sptyp & TESTRESISTANCE) + && target_resists_magic(mage, b, TYP_BUILDING, 0)) { /* Fehlermeldung */ + spobj->data.i = b->no; + spobj->flag = TARGET_RESISTS; + ++*resist; + ADDMSG(&mage->faction->msgs, msg_message("spellbuildingresists", + "unit region command id", + mage, mage->region, co->order, spobj->data.i)); break; + } + ++*success; + break; + case SPP_SHIP: + sh = spobj->data.sh; - case SPP_REGION: - /* haben wir ein Regionsobjekt, dann wird auch dieses und - nicht target_r überprüft. */ - tr = spobj->data.r; + if ((sp->sptyp & TESTRESISTANCE) + && target_resists_magic(mage, sh, TYP_SHIP, 0)) { /* Fehlermeldung */ + spobj->data.i = sh->no; + spobj->flag = TARGET_RESISTS; + ++*resist; + ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, + "spellshipresists", "ship", sh)); + break; + } + ++*success; + break; - if ((sp->sptyp & TESTRESISTANCE) - && target_resists_magic(mage, tr, TYP_REGION, 0)) { /* Fehlermeldung */ - spobj->flag = TARGET_RESISTS; - ++*resist; - ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", - "unit region command", mage, mage->region, co->order)); - break; - } - ++*success; - break; - case SPP_INT: - case SPP_STRING: - ++*success; - break; + case SPP_REGION: + /* haben wir ein Regionsobjekt, dann wird auch dieses und + nicht target_r überprüft. */ + tr = spobj->data.r; - default: + if ((sp->sptyp & TESTRESISTANCE) + && target_resists_magic(mage, tr, TYP_REGION, 0)) { /* Fehlermeldung */ + spobj->flag = TARGET_RESISTS; + ++*resist; + ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", + "unit region command", mage, mage->region, co->order)); break; + } + ++*success; + break; + case SPP_INT: + case SPP_STRING: + ++*success; + break; + + default: + break; } } } else { @@ -1804,11 +1803,11 @@ static void free_spellparameter(spellparameter * pa) for (i = 0; i < pa->length; i++) { switch (pa->param[i]->typ) { - case SPP_STRING: - free(pa->param[i]->data.s); - break; - default: - break; + case SPP_STRING: + free(pa->param[i]->data.s); + break; + default: + break; } free(pa->param[i]); } @@ -1967,87 +1966,87 @@ static spellparameter *add_spellparameter(region * target_r, unit * u, param_t pword; int j = -1; switch (*c) { - case '?': - /* tja. das sollte moeglichst nur am Ende passieren, - * weil sonst die kacke dampft. */ + case '?': + /* tja. das sollte moeglichst nur am Ende passieren, + * weil sonst die kacke dampft. */ + j = 0; + ++c; + assert(*c == 0); + break; + case '+': + /* das vorhergehende Element kommt ein oder mehrmals vor, wir + * springen zum key zurück */ + j = 0; + --c; + break; + case 'u': + /* Parameter ist eine Einheit, evtl. TEMP */ + j = addparam_unit(param + i, &spobj, u, ord); + ++c; + break; + case 'r': + /* Parameter sind zwei Regionskoordinaten */ + /* this silly thing only works in the normal plane! */ + j = addparam_region(param + i, &spobj, u, ord, get_normalplane()); + ++c; + break; + case 'b': + /* Parameter ist eine Burgnummer */ + j = addparam_building(param + i, &spobj); + ++c; + break; + case 's': + j = addparam_ship(param + i, &spobj); + ++c; + break; + case 'c': + /* Text, wird im Spruch ausgewertet */ + j = addparam_string(param + i, &spobj); + ++c; + break; + case 'i': /* Zahl */ + j = addparam_int(param + i, &spobj); + ++c; + break; + case 'k': + ++c; + pword = findparam(param[i++], u->faction->locale); + switch (pword) { + case P_REGION: + spobj = malloc(sizeof(spllprm)); + spobj->flag = 0; + spobj->typ = SPP_REGION; + spobj->data.r = u->region; j = 0; ++c; - assert(*c == 0); break; - case '+': - /* das vorhergehende Element kommt ein oder mehrmals vor, wir - * springen zum key zurück */ - j = 0; - --c; + case P_UNIT: + if (i < size) { + j = addparam_unit(param + i, &spobj, u, ord); + ++c; + } break; - case 'u': - /* Parameter ist eine Einheit, evtl. TEMP */ - j = addparam_unit(param + i, &spobj, u, ord); - ++c; + case P_BUILDING: + case P_GEBAEUDE: + if (i < size) { + j = addparam_building(param + i, &spobj); + ++c; + } break; - case 'r': - /* Parameter sind zwei Regionskoordinaten */ - /* this silly thing only works in the normal plane! */ - j = addparam_region(param + i, &spobj, u, ord, get_normalplane()); - ++c; - break; - case 'b': - /* Parameter ist eine Burgnummer */ - j = addparam_building(param + i, &spobj); - ++c; - break; - case 's': - j = addparam_ship(param + i, &spobj); - ++c; - break; - case 'c': - /* Text, wird im Spruch ausgewertet */ - j = addparam_string(param + i, &spobj); - ++c; - break; - case 'i': /* Zahl */ - j = addparam_int(param + i, &spobj); - ++c; - break; - case 'k': - ++c; - pword = findparam(param[i++], u->faction->locale); - switch (pword) { - case P_REGION: - spobj = malloc(sizeof(spllprm)); - spobj->flag = 0; - spobj->typ = SPP_REGION; - spobj->data.r = u->region; - j = 0; - ++c; - break; - case P_UNIT: - if (i < size) { - j = addparam_unit(param + i, &spobj, u, ord); - ++c; - } - break; - case P_BUILDING: - case P_GEBAEUDE: - if (i < size) { - j = addparam_building(param + i, &spobj); - ++c; - } - break; - case P_SHIP: - if (i < size) { - j = addparam_ship(param + i, &spobj); - ++c; - } - break; - default: - j = -1; - break; + case P_SHIP: + if (i < size) { + j = addparam_ship(param + i, &spobj); + ++c; } break; default: j = -1; break; + } + break; + default: + j = -1; + break; } if (j < 0) fail = true; @@ -2481,10 +2480,12 @@ static boolean is_moving_ship(const region * r, const ship * sh) if (u) switch (get_keyword(u->thisorder)) { - case K_ROUTE: - case K_MOVE: - case K_FOLLOW: - return true; + case K_ROUTE: + case K_MOVE: + case K_FOLLOW: + return true; + default: + return false; } return false; } diff --git a/src/kernel/move.c b/src/kernel/move.c index 094fdf97d..82a2a51cc 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -1328,12 +1328,14 @@ static int movement_speed(unit * u) assert(u->number); /* dragons have a fixed speed, and no other effects work on them: */ switch (old_race(u->race)) { - case RC_DRAGON: - case RC_WYRM: - case RC_FIREDRAGON: - case RC_BIRTHDAYDRAGON: - case RC_SONGDRAGON: - return BP_DRAGON; + case RC_DRAGON: + case RC_WYRM: + case RC_FIREDRAGON: + case RC_BIRTHDAYDRAGON: + case RC_SONGDRAGON: + return BP_DRAGON; + default: + break; } if (!init) { @@ -1350,38 +1352,38 @@ static int movement_speed(unit * u) switch (canride(u)) { - case 1: /* Pferd */ - mp = BP_RIDING; - break; + case 1: /* Pferd */ + mp = BP_RIDING; + break; - case 2: /* Einhorn */ - mp = BP_UNICORN; - break; + case 2: /* Einhorn */ + mp = BP_UNICORN; + break; - default: - mp = BP_WALKING; + default: + mp = BP_WALKING; - /* Siebenmeilentee */ - if (get_effect(u, oldpotiontype[P_FAST]) >= u->number) { - mp *= 2; - change_effect(u, oldpotiontype[P_FAST], -u->number); - } + /* 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 <= get_item(u, I_FEENSTIEFEL)) { + /* unicorn in inventory */ + if (u->number <= get_item(u, I_FEENSTIEFEL)) { + mp *= 2; + } + + /* Im Astralraum sind Tyb und Ill-Magier doppelt so schnell. + * Nicht kumulativ mit anderen Beschleunigungen! */ + if (mp * dk <= BP_WALKING * u->race->speed && is_astral(u->region) + && is_mage(u)) { + sc_mage *mage = get_mage(u); + if (mage->magietyp == M_TYBIED || mage->magietyp == M_ILLAUN) { mp *= 2; } - - /* Im Astralraum sind Tyb und Ill-Magier doppelt so schnell. - * Nicht kumulativ mit anderen Beschleunigungen! */ - if (mp * dk <= BP_WALKING * u->race->speed && is_astral(u->region) - && is_mage(u)) { - sc_mage *mage = get_mage(u); - if (mage->magietyp == M_TYBIED || mage->magietyp == M_ILLAUN) { - mp *= 2; - } - } - break; + } + break; } return (int)(dk * mp); } @@ -1996,15 +1998,15 @@ static const region_list *travel_i(unit * u, const region_list * route_begin, return route_begin; } switch (canwalk(u)) { - case E_CANWALK_TOOHEAVY: - cmistake(u, ord, 57, MSG_MOVE); - return route_begin; - case E_CANWALK_TOOMANYHORSES: - cmistake(u, ord, 56, MSG_MOVE); - return route_begin; - case E_CANWALK_TOOMANYCARTS: - cmistake(u, ord, 42, MSG_MOVE); - return route_begin; + case E_CANWALK_TOOHEAVY: + cmistake(u, ord, 57, MSG_MOVE); + return route_begin; + case E_CANWALK_TOOMANYHORSES: + cmistake(u, ord, 56, MSG_MOVE); + return route_begin; + case E_CANWALK_TOOMANYCARTS: + cmistake(u, ord, 42, MSG_MOVE); + return route_begin; } route_end = cap_route(r, route_begin, route_end, movement_speed(u)); @@ -2565,44 +2567,41 @@ void movement(void) } kword = get_keyword(u->thisorder); - switch (kword) { - case K_ROUTE: - case K_MOVE: - /* after moving, the unit has no thisorder. this prevents - * it from moving twice (or getting error messages twice). - * UFL_NOTMOVING is set in combat if the unit is not allowed - * to move because it was involved in a battle. - */ - if (fval(u, UFL_NOTMOVING)) { - if (fval(u, UFL_LONGACTION)) { - cmistake(u, u->thisorder, 52, MSG_MOVE); - set_order(&u->thisorder, NULL); - } else { - cmistake(u, u->thisorder, 319, MSG_MOVE); - set_order(&u->thisorder, NULL); - } - } else if (fval(u, UFL_MOVED)) { - cmistake(u, u->thisorder, 187, MSG_MOVE); - set_order(&u->thisorder, NULL); - } else if (!can_move(u)) { - cmistake(u, u->thisorder, 55, MSG_MOVE); + if (kword == K_ROUTE || kword == K_MOVE) { + /* after moving, the unit has no thisorder. this prevents + * it from moving twice (or getting error messages twice). + * UFL_NOTMOVING is set in combat if the unit is not allowed + * to move because it was involved in a battle. + */ + if (fval(u, UFL_NOTMOVING)) { + if (fval(u, UFL_LONGACTION)) { + cmistake(u, u->thisorder, 52, MSG_MOVE); set_order(&u->thisorder, NULL); } else { - if (ships) { - if (u->ship && fval(u, UFL_OWNER)) { - init_tokens(u->thisorder); - skip_token(); - move(u, false); - } - } else { - if (u->ship == NULL || !fval(u, UFL_OWNER)) { - init_tokens(u->thisorder); - skip_token(); - move(u, false); - } + cmistake(u, u->thisorder, 319, MSG_MOVE); + set_order(&u->thisorder, NULL); + } + } else if (fval(u, UFL_MOVED)) { + cmistake(u, u->thisorder, 187, MSG_MOVE); + set_order(&u->thisorder, NULL); + } else if (!can_move(u)) { + cmistake(u, u->thisorder, 55, MSG_MOVE); + set_order(&u->thisorder, NULL); + } else { + if (ships) { + if (u->ship && fval(u, UFL_OWNER)) { + init_tokens(u->thisorder); + skip_token(); + move(u, false); + } + } else { + if (u->ship == NULL || !fval(u, UFL_OWNER)) { + init_tokens(u->thisorder); + skip_token(); + move(u, false); } } - break; + } } if (u->region == r) { /* not moved, use next unit */ @@ -2683,24 +2682,24 @@ void follow_unit(unit * u) } switch (get_keyword(u2->thisorder)) { - case K_MOVE: - case K_ROUTE: - case K_DRIVE: - follow = true; - break; - default: - for (ord = u2->orders; ord; ord = ord->next) { - switch (get_keyword(ord)) { - case K_FOLLOW: - case K_PIRACY: - follow = true; - break; - default: - continue; - } + case K_MOVE: + case K_ROUTE: + case K_DRIVE: + follow = true; + break; + default: + for (ord = u2->orders; ord; ord = ord->next) { + switch (get_keyword(ord)) { + case K_FOLLOW: + case K_PIRACY: + follow = true; break; + default: + continue; } break; + } + break; } if (!follow) { attrib *a2 = a_find(u2->attribs, &at_follow); diff --git a/src/kernel/order.c b/src/kernel/order.c index ffb955e9f..5ce1f5ffd 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -195,33 +195,33 @@ static order_data *create_data(keyword_t kwd, const char *sptr, int lindex) if (kwd == K_STUDY) { skill_t sk = findskill(parse_token(&sptr), lang); switch (sk) { - case NOSKILL: /* fehler */ + case NOSKILL: /* fehler */ + break; + case SK_MAGIC: /* kann parameter haben */ + if (*sptr != 0) break; - case SK_MAGIC: /* kann parameter haben */ - if (*sptr != 0) - break; - default: /* nur skill als Parameter, keine extras */ - data = locale_array[lindex]->study_orders[sk]; - if (data == NULL) { - const char *skname = skillname(sk, lang); - data = (order_data *) malloc(sizeof(order_data)); - locale_array[lindex]->study_orders[sk] = data; - data->_keyword = kwd; - data->_lindex = lindex; - if (strchr(skname, ' ') != NULL) { - size_t len = strlen(skname); - data->_str = malloc(len + 3); - data->_str[0] = '\"'; - memcpy(data->_str + 1, skname, len); - data->_str[len + 1] = '\"'; - data->_str[len + 2] = '\0'; - } else { - data->_str = strdup(skname); - } - data->_refcount = 1; + default: /* nur skill als Parameter, keine extras */ + data = locale_array[lindex]->study_orders[sk]; + if (data == NULL) { + const char *skname = skillname(sk, lang); + data = (order_data *) malloc(sizeof(order_data)); + locale_array[lindex]->study_orders[sk] = data; + data->_keyword = kwd; + data->_lindex = lindex; + if (strchr(skname, ' ') != NULL) { + size_t len = strlen(skname); + data->_str = malloc(len + 3); + data->_str[0] = '\"'; + memcpy(data->_str + 1, skname, len); + data->_str[len + 1] = '\"'; + data->_str[len + 2] = '\0'; + } else { + data->_str = strdup(skname); } - ++data->_refcount; - return data; + data->_refcount = 1; + } + ++data->_refcount; + return data; } } @@ -256,15 +256,15 @@ static order *create_order_i(keyword_t kwd, const char *sptr, int persistent, /* if this is just nonsense, then we skip it. */ if (lomem) { switch (kwd) { - case K_KOMMENTAR: - case NOKEYWORD: - return NULL; - case K_LIEFERE: - kwd = K_GIVE; - persistent = 1; - break; - default: - break; + case K_KOMMENTAR: + case NOKEYWORD: + return NULL; + case K_LIEFERE: + kwd = K_GIVE; + persistent = 1; + break; + default: + break; } } @@ -304,26 +304,26 @@ order *create_order(keyword_t kwd, const struct locale * lang, const char *s; ++params; switch (*params) { - case 's': - s = va_arg(marker, const char *); - bytes = (int)strlcpy(bufp, s, size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - break; - case 'd': - i = va_arg(marker, int); - bytes = (int)strlcpy(bufp, itoa10(i), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - break; - case 'i': - i = va_arg(marker, int); - bytes = (int)strlcpy(bufp, itoa36(i), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - break; - default: - assert(!"unknown format-character in create_order"); + case 's': + s = va_arg(marker, const char *); + bytes = (int)strlcpy(bufp, s, size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + break; + case 'd': + i = va_arg(marker, int); + bytes = (int)strlcpy(bufp, itoa10(i), size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + break; + case 'i': + i = va_arg(marker, int); + bytes = (int)strlcpy(bufp, itoa36(i), size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + break; + default: + assert(!"unknown format-character in create_order"); } } else if (size > 0) { *bufp++ = *params; @@ -379,55 +379,55 @@ boolean is_repeated(const order * ord) param_t param; switch (kwd) { - case K_CAST: - case K_BUY: - case K_SELL: - case K_ROUTE: - case K_DRIVE: - case K_WORK: - case K_BESIEGE: - case K_ENTERTAIN: - case K_TAX: - case K_RESEARCH: - case K_SPY: - case K_STEAL: - case K_SABOTAGE: - case K_STUDY: - case K_TEACH: - case K_BREED: - case K_PIRACY: + case K_CAST: + case K_BUY: + case K_SELL: + case K_ROUTE: + case K_DRIVE: + case K_WORK: + case K_BESIEGE: + case K_ENTERTAIN: + case K_TAX: + case K_RESEARCH: + case K_SPY: + case K_STEAL: + case K_SABOTAGE: + case K_STUDY: + case K_TEACH: + case K_BREED: + case K_PIRACY: + case K_PLANT: + return true; + + case K_FOLLOW: + /* FOLLOW is only a long order if we are following a ship. */ + parser_pushstate(); + init_tokens(ord); + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param == P_SHIP) return true; + break; - case K_PLANT: + case K_MAKE: + /* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen + * Arten von MACHE zaehlen aber als neue defaults und werden + * behandelt wie die anderen (deswegen kein break nach case + * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) + * abgespeichert). */ + parser_pushstate(); + init_tokens(ord); /* initialize token-parser */ + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param != P_TEMP) return true; - - case K_FOLLOW: - /* FOLLOW is only a long order if we are following a ship. */ - parser_pushstate(); - init_tokens(ord); - skip_token(); - param = getparam(lang); - parser_popstate(); - - if (param == P_SHIP) - return true; - break; - - case K_MAKE: - /* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen - * Arten von MACHE zaehlen aber als neue defaults und werden - * behandelt wie die anderen (deswegen kein break nach case - * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) - * abgespeichert). */ - parser_pushstate(); - init_tokens(ord); /* initialize token-parser */ - skip_token(); - param = getparam(lang); - parser_popstate(); - - if (param != P_TEMP) - return true; - break; + break; + default: + return false; } return false; } @@ -447,55 +447,55 @@ boolean is_exclusive(const order * ord) param_t param; switch (kwd) { - case K_MOVE: - case K_WEREWOLF: - /* these should not become persistent */ - case K_ROUTE: - case K_DRIVE: - case K_WORK: - case K_BESIEGE: - case K_ENTERTAIN: - case K_TAX: - case K_RESEARCH: - case K_SPY: - case K_STEAL: - case K_SABOTAGE: - case K_STUDY: - case K_TEACH: - case K_BREED: - case K_PIRACY: + case K_MOVE: + case K_WEREWOLF: + /* these should not become persistent */ + case K_ROUTE: + case K_DRIVE: + case K_WORK: + case K_BESIEGE: + case K_ENTERTAIN: + case K_TAX: + case K_RESEARCH: + case K_SPY: + case K_STEAL: + case K_SABOTAGE: + case K_STUDY: + case K_TEACH: + case K_BREED: + case K_PIRACY: + case K_PLANT: + return true; + + case K_FOLLOW: + /* FOLLOW is only a long order if we are following a ship. */ + parser_pushstate(); + init_tokens(ord); + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param == P_SHIP) return true; + break; - case K_PLANT: + case K_MAKE: + /* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen + * Arten von MACHE zaehlen aber als neue defaults und werden + * behandelt wie die anderen (deswegen kein break nach case + * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) + * abgespeichert). */ + parser_pushstate(); + init_tokens(ord); /* initialize token-parser */ + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param != P_TEMP) return true; - - case K_FOLLOW: - /* FOLLOW is only a long order if we are following a ship. */ - parser_pushstate(); - init_tokens(ord); - skip_token(); - param = getparam(lang); - parser_popstate(); - - if (param == P_SHIP) - return true; - break; - - case K_MAKE: - /* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen - * Arten von MACHE zaehlen aber als neue defaults und werden - * behandelt wie die anderen (deswegen kein break nach case - * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) - * abgespeichert). */ - parser_pushstate(); - init_tokens(ord); /* initialize token-parser */ - skip_token(); - param = getparam(lang); - parser_popstate(); - - if (param != P_TEMP) - return true; - break; + break; + default: + return false; } return false; } @@ -515,57 +515,57 @@ boolean is_long(const order * ord) param_t param; switch (kwd) { - case K_CAST: - case K_BUY: - case K_SELL: - case K_MOVE: - case K_WEREWOLF: - case K_ROUTE: - case K_DRIVE: - case K_WORK: - case K_BESIEGE: - case K_ENTERTAIN: - case K_TAX: - case K_RESEARCH: - case K_SPY: - case K_STEAL: - case K_SABOTAGE: - case K_STUDY: - case K_TEACH: - case K_BREED: - case K_PIRACY: + case K_CAST: + case K_BUY: + case K_SELL: + case K_MOVE: + case K_WEREWOLF: + case K_ROUTE: + case K_DRIVE: + case K_WORK: + case K_BESIEGE: + case K_ENTERTAIN: + case K_TAX: + case K_RESEARCH: + case K_SPY: + case K_STEAL: + case K_SABOTAGE: + case K_STUDY: + case K_TEACH: + case K_BREED: + case K_PIRACY: + case K_PLANT: + return true; + + case K_FOLLOW: + /* FOLLOW is only a long order if we are following a ship. */ + parser_pushstate(); + init_tokens(ord); + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param == P_SHIP) return true; + break; - case K_PLANT: + case K_MAKE: + /* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen + * Arten von MACHE zaehlen aber als neue defaults und werden + * behandelt wie die anderen (deswegen kein break nach case + * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) + * abgespeichert). */ + parser_pushstate(); + init_tokens(ord); /* initialize token-parser */ + skip_token(); + param = getparam(lang); + parser_popstate(); + + if (param != P_TEMP) return true; - - case K_FOLLOW: - /* FOLLOW is only a long order if we are following a ship. */ - parser_pushstate(); - init_tokens(ord); - skip_token(); - param = getparam(lang); - parser_popstate(); - - if (param == P_SHIP) - return true; - break; - - case K_MAKE: - /* Falls wir MACHE TEMP haben, ignorieren wir es. Alle anderen - * Arten von MACHE zaehlen aber als neue defaults und werden - * behandelt wie die anderen (deswegen kein break nach case - * K_MAKE) - und in thisorder (der aktuelle 30-Tage Befehl) - * abgespeichert). */ - parser_pushstate(); - init_tokens(ord); /* initialize token-parser */ - skip_token(); - param = getparam(lang); - parser_popstate(); - - if (param != P_TEMP) - return true; - break; + break; + default: + return false; } return false; } @@ -584,18 +584,20 @@ boolean is_persistent(const order * ord) keyword_t kwd = ORD_KEYWORD(ord); boolean persist = ord->_persistent != 0; switch (kwd) { - case K_MOVE: - case K_WEREWOLF: - case NOKEYWORD: - /* lang, aber niemals persistent! */ - return false; + case K_MOVE: + case K_WEREWOLF: + case NOKEYWORD: + /* lang, aber niemals persistent! */ + return false; - case K_KOMMENTAR: - case K_LIEFERE: - return true; + case K_KOMMENTAR: + case K_LIEFERE: + return true; + + default: + return persist || is_repeated(ord); } - return persist || is_repeated(ord); } char *write_order(const order * ord, char *buffer, size_t size) diff --git a/src/kernel/reports.h b/src/kernel/reports.h index 5a643cc01..632c3df86 100644 --- a/src/kernel/reports.h +++ b/src/kernel/reports.h @@ -18,6 +18,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifndef H_KRNL_REPORTS #define H_KRNL_REPORTS + +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/src/kernel/save.c b/src/kernel/save.c index 194598b1a..0d7c534cd 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -144,51 +144,29 @@ int freadstr(FILE * F, int encoding, char *start, size_t size) } } switch (c) { + case EOF: + return EOF; + case '"': + if (!quote && str != start) { + log_error( + ("datafile contains a \" that isn't at the start of a string.\n")); + assert + (!"datafile contains a \" that isn't at the start of a string.\n"); + } + if (quote) { + *str = 0; + return (int)(str - start); + } + quote = true; + break; + case '\\': + c = fgetc(F); + switch (c) { case EOF: return EOF; - case '"': - if (!quote && str != start) { - log_error( - ("datafile contains a \" that isn't at the start of a string.\n")); - assert - (!"datafile contains a \" that isn't at the start of a string.\n"); - } - if (quote) { - *str = 0; - return (int)(str - start); - } - quote = true; - break; - case '\\': - c = fgetc(F); - switch (c) { - case EOF: - return EOF; - case 'n': - if ((size_t) (str - start + 1) < size) { - *str++ = '\n'; - } - break; - default: - if ((size_t) (str - start + 1) < size) { - if (encoding == XML_CHAR_ENCODING_8859_1 && c & 0x80) { - char inbuf = (char)c; - size_t inbytes = 1; - size_t outbytes = size - (str - start); - int ret = - unicode_latin1_to_utf8(str, &outbytes, &inbuf, &inbytes); - if (ret > 0) - str += ret; - else { - log_error( - ("input data was not iso-8859-1! assuming utf-8\n")); - encoding = XML_CHAR_ENCODING_ERROR; - *str++ = (char)c; - } - } else { - *str++ = (char)c; - } - } + case 'n': + if ((size_t) (str - start + 1) < size) { + *str++ = '\n'; } break; default: @@ -209,6 +187,26 @@ int freadstr(FILE * F, int encoding, char *start, size_t size) *str++ = (char)c; } } + } + break; + default: + if ((size_t) (str - start + 1) < size) { + if (encoding == XML_CHAR_ENCODING_8859_1 && c & 0x80) { + char inbuf = (char)c; + size_t inbytes = 1; + size_t outbytes = size - (str - start); + int ret = unicode_latin1_to_utf8(str, &outbytes, &inbuf, &inbytes); + if (ret > 0) + str += ret; + else { + log_error(("input data was not iso-8859-1! assuming utf-8\n")); + encoding = XML_CHAR_ENCODING_ERROR; + *str++ = (char)c; + } + } else { + *str++ = (char)c; + } + } } } } @@ -224,20 +222,20 @@ int fwritestr(FILE * F, const char *str) while (*str) { int c = (int)(unsigned char)*str++; switch (c) { - case '"': - case '\\': - fputc('\\', F); - fputc(c, F); - nwrite += 2; - break; - case '\n': - fputc('\\', F); - fputc('n', F); - nwrite += 2; - break; - default: - fputc(c, F); - ++nwrite; + case '"': + case '\\': + fputc('\\', F); + fputc(c, F); + nwrite += 2; + break; + case '\n': + fputc('\\', F); + fputc('n', F); + nwrite += 2; + break; + default: + fputc(c, F); + ++nwrite; } } fputc('\"', F); @@ -300,23 +298,28 @@ static unit *unitorders(FILE * F, int enc, struct faction *f) boolean quit = false; param_t param = findparam(stok, u->faction->locale); switch (param) { - case P_UNIT: - case P_REGION: + 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; - 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; - } - } - if (quit) + } else { + quit = false; + } break; + default: + /* TODO: syntax error message */ + break; + } + if (quit) { + break; + } } /* Nun wird der Befehl erzeut und eingehängt */ *ordp = parse_order(s, u->faction->locale); @@ -400,58 +403,58 @@ int readorders(const char *filename) const char *s; switch (igetparam(b, lang)) { - case P_LOCALE: - s = getstrtoken(); + case P_LOCALE: + s = getstrtoken(); #undef LOCALE_CHANGE #ifdef LOCALE_CHANGE - if (f && find_locale(s)) { - f->locale = find_locale(s); - } + if (f && find_locale(s)) { + f->locale = find_locale(s); + } #endif - b = getbuf(F, enc_gamedata); - break; - case P_GAMENAME: - case P_FACTION: - f = factionorders(); - if (f) { - ++nfactions; - } + b = getbuf(F, enc_gamedata); + break; + case P_GAMENAME: + case P_FACTION: + f = factionorders(); + if (f) { + ++nfactions; + } - b = getbuf(F, enc_gamedata); - break; + 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. */ + /* 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; - p = igetparam(b, lang); - } while ((p != P_UNIT || !f) && p != P_FACTION && p != P_NEXT - && p != P_GAMENAME); - break; + case P_UNIT: + if (!f || !unitorders(F, enc_gamedata, f)) + do { + b = getbuf(F, enc_gamedata); + if (!b) + break; + p = igetparam(b, lang); + } 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 - * muß buf erneut gefüllt werden, da die betreffende Information in nur - * einer Zeile steht, und nun die nächste gelesen werden muß. */ + /* 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 + * muß buf erneut gefüllt werden, da die betreffende Information in nur + * einer Zeile steht, und nun die nächste gelesen werden muß. */ - case P_NEXT: - f = NULL; - b = getbuf(F, enc_gamedata); - break; + case P_NEXT: + f = NULL; + b = getbuf(F, enc_gamedata); + break; - default: - b = getbuf(F, enc_gamedata); - break; + default: + b = getbuf(F, enc_gamedata); + break; } } diff --git a/src/kernel/skill.c b/src/kernel/skill.c index 89431ad81..7a41b8b33 100644 --- a/src/kernel/skill.c +++ b/src/kernel/skill.c @@ -223,13 +223,15 @@ int rc_skillmod(const struct race *rc, const region * r, skill_t sk) { int mods; - if (!skill_enabled[sk]) + if (!skill_enabled[sk]) { return 0; + } #ifdef FASTER_SKILLMOD unsigned int index = hashstring(rc->_name[0]) % RCMODMAXHASH; struct skillmods **imods = &modhash[index]; - while (*imods && (*imods)->race != rc) + while (*imods && (*imods)->race != rc) { imods = &(*imods)->next; + } if (*imods == NULL) { *imods = init_skills(rc); } @@ -237,21 +239,19 @@ int rc_skillmod(const struct race *rc, const region * r, skill_t sk) #else mods = skill_mod(rc, sk, r->terrain); #endif - if (rc == new_race[RC_ELF] && r_isforest(r)) - switch (sk) { - case SK_PERCEPTION: + if (rc == new_race[RC_ELF] && r_isforest(r)) { + if (sk == SK_PERCEPTION) { + ++mods; + } else if (sk == SK_STEALTH) { + if (r_isforest(r)) { ++mods; - break; - case SK_STEALTH: - if (r_isforest(r)) - ++mods; - break; - case SK_TACTICS: - if (r_isforest(r)) - mods += 2; - break; + } + } else if (sk == SK_TACTICS) { + if (r_isforest(r)) { + mods += 2; + } } - + } return mods; } diff --git a/src/kernel/spellid.h b/src/kernel/spellid.h index 71f13dcda..8b0e7c668 100644 --- a/src/kernel/spellid.h +++ b/src/kernel/spellid.h @@ -170,7 +170,7 @@ enum { XMLSPL_WDWPYRAMID_ASTRAL = 185, XMLSPL_WDWPYRAMID_DRUIDE = 186, XMLSPL_WDWPYRAMID_BARDE = 187, - XMLSPL_WDWPYRAMID_CHAOS = 188, + XMLSPL_WDWPYRAMID_CHAOS = 188 }; #endif diff --git a/src/kernel/textstore.c b/src/kernel/textstore.c index 9fc80f01e..4c812158b 100644 --- a/src/kernel/textstore.c +++ b/src/kernel/textstore.c @@ -60,7 +60,7 @@ static int txt_w_flt(struct storage *store, float arg) static float txt_r_flt(struct storage *store) { double result; - fscanf((FILE *) store->userdata, "%f", &result); + fscanf((FILE *) store->userdata, "%lf", &result); return (float)result; } @@ -154,7 +154,7 @@ static int txt_open(struct storage *store, const char *filename, int mode) store->version = atoi(token); } } else if (store->encoding == XML_CHAR_ENCODING_UTF8) { - fputs((const char*)utf8_bom, F); + fputs((const char *)utf8_bom, F); fprintf(F, "%d\n", RELEASE_VERSION); } } diff --git a/src/modules/xecmd.c b/src/modules/xecmd.c index 939b882a5..67ebeb094 100644 --- a/src/modules/xecmd.c +++ b/src/modules/xecmd.c @@ -89,18 +89,17 @@ int xecmd(unit * u, order * ord) if (a_find(f->attribs, &at_xontormiaexpress)) { if (get_keyword(ord) == K_XE) { + param_t param; + init_tokens(ord); skip_token(); - switch (findparam(getstrtoken(), f->locale)) { - case P_XEPOTION: - xe_givepotion(u, ord); - break; - case P_XEBALLOON: - xe_giveballon(u, ord); - break; - case P_XELAEN: - xe_givelaen(u, ord); - break; + param = findparam(getstrtoken(), f->locale); + if (param == P_XEPOTION) { + xe_givepotion(u, ord); + } else if (param == P_XEBALLOON) { + xe_giveballon(u, ord); + } else if (param == P_XELAEN) { + xe_givelaen(u, ord); } } } From 54d05f8544ae808007795a899dcfacac3a4e4c62 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 7 Mar 2011 23:46:56 -0800 Subject: [PATCH 116/400] MSVC warns about unreachable code. --- src/gamecode/laws.c | 1 - src/gamecode/study.c | 1 - 2 files changed, 2 deletions(-) diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index a0c16ada4..470ab9fda 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -3608,7 +3608,6 @@ static double heal_factor(const unit * u) default: return 1.0; } - return 1.0; } static void monthly_healing(void) diff --git a/src/gamecode/study.c b/src/gamecode/study.c index 7138a81b7..e4592383e 100644 --- a/src/gamecode/study.c +++ b/src/gamecode/study.c @@ -136,7 +136,6 @@ int study_cost(unit * u, skill_t sk) default: return 0; } - return 0; } /* ------------------------------------------------------------- */ From d65d03db9c22c78f58a94e129454eac3f18e955b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 8 Mar 2011 15:36:14 +0100 Subject: [PATCH 117/400] fixed oops with __cplusplus --- src/attributes/otherfaction.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/attributes/otherfaction.h b/src/attributes/otherfaction.h index 783f5fb07..4bb2608d0 100644 --- a/src/attributes/otherfaction.h +++ b/src/attributes/otherfaction.h @@ -30,5 +30,5 @@ extern "C" { const struct unit *u); #ifdef __cplusplus - extern "C" { +} #endif From 8714957a619a44e842a59db8a00680ce80da43d2 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 9 Mar 2011 00:25:51 +0100 Subject: [PATCH 118/400] fixed two bugs: harbours were not unique and multiple instances of unique buildings could still be built --- res/common/buildings.xml | 2 +- scripts/tests/common.lua | 107 ++++++++++++++++++++++++++++ src/bindings/bindings.c | 147 +++++++++++++++++++++++++++++++++++++++ src/kernel/build.c | 2 +- src/kernel/building.c | 36 +++++----- src/kernel/building.h | 2 + src/kernel/move.c | 4 ++ src/kernel/ship.c | 6 +- src/tests.c | 2 + 9 files changed, 287 insertions(+), 21 deletions(-) diff --git a/res/common/buildings.xml b/res/common/buildings.xml index 5c52bfbb3..63ac3e650 100644 --- a/res/common/buildings.xml +++ b/res/common/buildings.xml @@ -128,7 +128,7 @@ - + diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 808d68ff4..0c4bb6ad3 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -5,6 +5,19 @@ local function _test_create_ship(r) return s end +local function _test_unique_btype() + local utype = nil + for i = 1, #config.buildings do + bt = config.buildings[i] + if (((config.get_building(bt).flags / 4) % 2) ~= 0) then -- #define BTF_UNIQUE 0x04 + if (((config.get_building(bt).flags / 2) % 2) == 0) then -- #define BTF_NOBUILD 0x02 + utype = bt + end + end + end + return utype +end + local function one_unit(r, f) local u = unit.create(f, r, 1) u:add_item("money", u.number * 100) @@ -943,3 +956,97 @@ function test_bson_with_multiple_attribs() end assert_equal(6, total) end + +function test_building_unique0() + local r = region.create(0, 0, "mountain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 20) + local f2 = faction.create("noreply@eressea.de", "human", "de") + local u2 = unit.create(f2, r, 20) + local utype = _test_unique_btype() + + if (utype ~= nil) then + assert_equal("harbour", utype) + u:set_skill("building", 20) + u:add_item("log", 10000) + u:add_item("iron", 10000) + u:add_item("stone", 10000) + u:add_item("money", 10000) + u2:set_skill("building", 20) + u2:add_item("log", 10000) + u2:add_item("iron", 10000) + u2:add_item("stone", 10000) + u2:add_item("money", 10000) + + -- build two harbours in one go + u:clear_orders() + u:add_order("MACHEN ".. translate(utype)) + u2:clear_orders() + u2:add_order("MACHEN ".. translate(utype)) + process_orders() + assert_not_nil(r.buildings) + bcount = 0 + for bs in r.buildings do + assert_equal(1, string.find(bs.name, translate(utype))) + if (bs.size >= config.get_building(utype).maxsize) then + bcount = bcount + 1 + end + end + assert_equal(1, bcount) -- only one should be completed + else + -- fail() -- no unique building in rules + end +end + +function test_building_unique() + local r = region.create(0, 0, "mountain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 20) + local f2 = faction.create("noreply@eressea.de", "human", "de") + local u2 = unit.create(f2, r, 20) + local utype = _test_unique_btype() + + if (utype ~= nil) then + u:set_skill("building", 20) + u:add_item("log", 10000) + u:add_item("iron", 10000) + u:add_item("stone", 10000) + u:add_item("money", 10000) + u2:set_skill("building", 20) + u2:add_item("log", 10000) + u2:add_item("iron", 10000) + u2:add_item("stone", 10000) + u2:add_item("money", 10000) + + -- start building two harbours + u:clear_orders() + u:add_order("MACHEN 1 Hafen") + u2:clear_orders() + u2:add_order("MACHEN 1 Hafen") + process_orders() + -- finish building partial harbours + u:clear_orders() + u:add_order("MACHEN ".. translate("harbour")) + u2:clear_orders() + u2:add_order("MACHEN Hafen") + process_orders() + if (r.buildings() == nil) then + process_orders() + end + assert_not_nil(r.buildings) + bcount = 0 + local h1 = nil + for bs in r.buildings do + if (h1 == nil) then + h1 = bs.name + else + assert_equal(h1, bs.name) + end + assert_equal(1, string.find(bs.name, "Hafen")) + if (bs.size >= 25) then + bcount = bcount + 1 + end + end + assert_equal(1, bcount) -- only one should be completed + end +end diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index 30a058467..0e13e7543 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -20,6 +20,7 @@ without prior permission by the authors of Eressea. #include #include +#include #include #include #include @@ -768,6 +769,19 @@ static int config_get_ships(lua_State * L) return 1; } +static int config_get_buildings(lua_State * L) +{ + quicklist *ql; + int qi, i = 0; + lua_createtable(L, ql_length(buildingtypes), 0); + for (qi = 0, ql = buildingtypes; ql; ql_advance(&ql, &qi, 1)) { + building_type *btype = (building_type *) ql_get(ql, qi); + tolua_pushstring(L, TOLUA_CAST btype->_name); + lua_rawseti(L, -2, ++i); + } + return 1; +} + static int config_get_locales(lua_State * L) { const struct locale *lang; @@ -823,6 +837,136 @@ static int config_get_resource(lua_State * L) return 0; } +static int config_get_btype(lua_State * L) +{ + const char *name = tolua_tostring(L, 1, 0); + + if (name) { + const struct building_type *btype = bt_find(name); + if (btype) { + lua_newtable(L); + lua_pushstring(L, "flags"); + lua_pushinteger(L, btype->flags); + lua_settable(L, -3); + if (btype->capacity > 0) { + lua_pushstring(L, "capacity"); + lua_pushinteger(L, btype->capacity); + lua_settable(L, -3); + } + if (btype->maxcapacity > 0) { + lua_pushstring(L, "maxcapacity"); + lua_pushinteger(L, btype->maxcapacity); + lua_settable(L, -3); + } + if (btype->maxsize > 0) { + lua_pushstring(L, "maxsize"); + lua_pushinteger(L, btype->maxsize); + lua_settable(L, -3); + } + if (btype->maintenance) { + int i; + lua_pushstring(L, "maintenance"); + lua_newtable(L); + for (i = 0; btype->maintenance[i].number; ++i) { + lua_pushstring(L, + btype->maintenance[i].rtype->_name[0]); + lua_pushinteger(L, btype->maintenance[i].number); + lua_settable(L, -3); + } + lua_settable(L, -3); + } + if (btype->construction) { + int i; + lua_pushstring(L, "build_skill_min"); + lua_pushinteger(L, btype->construction->minskill); + lua_settable(L, -3); + lua_pushstring(L, "build_skill_name"); + lua_pushstring(L, skillnames[btype->construction->skill]); + lua_settable(L, -3); + if (btype->construction->materials) { + lua_pushstring(L, "materials"); + lua_newtable(L); + for (i = 0; btype->construction->materials[i].number; ++i) { + lua_pushstring(L, + btype->construction->materials[i].rtype->_name[0]); + lua_pushinteger(L, btype->construction->materials[i].number); + lua_settable(L, -3); + } + lua_settable(L, -3); + } + } + return 1; + } + } + return 0; +} + +static int config_get_stype(lua_State * L) +{ + const char *name = tolua_tostring(L, 1, 0); + + if (name) { + const struct ship_type *stype = st_find(name); + if (stype) { + lua_newtable(L); + lua_pushstring(L, "range"); + lua_pushinteger(L, stype->range); + lua_settable(L, -3); + lua_pushstring(L, "cabins"); + lua_pushinteger(L, stype->cabins); + lua_settable(L, -3); + lua_pushstring(L, "cargo"); + lua_pushinteger(L, stype->cargo); + lua_settable(L, -3); + lua_pushstring(L, "cptskill"); + lua_pushinteger(L, stype->cptskill); + lua_settable(L, -3); + lua_pushstring(L, "minskill"); + lua_pushinteger(L, stype->minskill); + lua_settable(L, -3); + lua_pushstring(L, "sumskill"); + lua_pushinteger(L, stype->sumskill); + lua_settable(L, -3); + lua_pushstring(L, "fishing"); + lua_pushinteger(L, stype->fishing); + lua_settable(L, -3); + if (stype->coasts) { + const terrain_type *coast = *stype->coasts; + lua_pushstring(L, "coasts"); + lua_newtable(L); + while(coast) { + lua_pushstring(L, coast->_name); + lua_pushinteger(L, 1); + lua_settable(L, -3); + coast = coast->next; + } + } + if (stype->construction) { + int i; + lua_pushstring(L, "build_skill_min"); + lua_pushinteger(L, stype->construction->minskill); + lua_settable(L, -3); + lua_pushstring(L, "build_skill_name"); + lua_pushstring(L, skillnames[stype->construction->skill]); + lua_settable(L, -3); + if (stype->construction->materials) { + lua_pushstring(L, "materials"); + lua_newtable(L); + for (i = 0; stype->construction->materials[i].number; ++i) { + lua_pushstring(L, + stype->construction->materials[i].rtype->_name[0]); + lua_pushinteger(L, stype->construction->materials[i].number); + lua_settable(L, -3); + } + lua_settable(L, -3); + } + } + return 1; + } + } + return 0; +} + static int tolua_get_spell_text(lua_State * L) { const struct locale *loc = default_locale; @@ -1060,7 +1204,10 @@ int tolua_eressea_open(lua_State * L) parse_inifile(L, global.inifile, "config"); tolua_variable(L, TOLUA_CAST "locales", &config_get_locales, 0); tolua_function(L, TOLUA_CAST "get_resource", &config_get_resource); + tolua_variable(L, TOLUA_CAST "buildings", &config_get_buildings, 0); + tolua_function(L, TOLUA_CAST "get_building", &config_get_btype); tolua_variable(L, TOLUA_CAST "ships", &config_get_ships, 0); + tolua_function(L, TOLUA_CAST "get_ship", &config_get_stype); } tolua_endmodule(L); tolua_function(L, TOLUA_CAST "get_region_by_id", tolua_get_region_byid); tolua_function(L, TOLUA_CAST "get_faction", tolua_get_faction); diff --git a/src/kernel/build.c b/src/kernel/build.c index e75883d8d..805c5ad32 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -890,7 +890,7 @@ build_building(unit * u, const building_type * btype, int want, order * ord) if (b) btype = b->type; - if (b && fval(btype, BTF_UNIQUE) && buildingtype_exists(r, btype, false)) { + if (fval(btype, BTF_UNIQUE) && buildingtype_exists(r, btype, false)) { /* only one of these per region */ cmistake(u, ord, 93, MSG_PRODUCE); return; diff --git a/src/kernel/building.c b/src/kernel/building.c index 972fe2179..45d6f84fe 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -124,28 +124,28 @@ typedef struct building_typelist { building_type *type; } building_typelist; -static building_typelist *buildingtypes; +quicklist *buildingtypes = NULL; building_type *bt_find(const char *name) { - const struct building_typelist *btl = buildingtypes; + quicklist *ql; + int qi; + assert(name); - while (btl && strcmp(btl->type->_name, name)) - btl = btl->next; - if (btl == NULL) { - return NULL; + + for (qi = 0, ql = buildingtypes; ql; ql_advance(&ql, &qi, 1)) { + building_type *btype = (building_type *) ql_get(ql, qi); + if (strcmp(btype->_name, name) == 0) + return btype; } - return btl->type; + return NULL; } void bt_register(building_type * type) { - struct building_typelist *btl = malloc(sizeof(building_type)); if (type->init) type->init(type); - btl->type = type; - btl->next = buildingtypes; - buildingtypes = btl; + ql_push(&buildingtypes, (void *)type); } int buildingcapacity(const building * b) @@ -362,15 +362,19 @@ const building_type *findbuildingtype(const char *name, bn = bn->next; } if (!bn) { - struct building_typelist *btl = buildingtypes; + quicklist *ql = buildingtypes; + int qi; + bn = calloc(sizeof(local_names), 1); bn->next = bnames; bn->lang = lang; - while (btl) { - const char *n = locale_string(lang, btl->type->_name); - type.v = (void *)btl->type; + + for (qi = 0, ql = buildingtypes; ql; ql_advance(&ql, &qi, 1)) { + building_type *btype = (building_type *) ql_get(ql, qi); + + const char *n = locale_string(lang, btype->_name); + type.v = (void *)btype; addtoken(&bn->names, n, type); - btl = btl->next; } bnames = bn; } diff --git a/src/kernel/building.h b/src/kernel/building.h index 08b9527db..8055e3731 100644 --- a/src/kernel/building.h +++ b/src/kernel/building.h @@ -71,6 +71,8 @@ extern "C" { struct attrib *attribs; } building_type; + extern struct quicklist *buildingtypes; + extern building_type *bt_find(const char *name); extern void register_buildings(void); extern void bt_register(struct building_type *type); diff --git a/src/kernel/move.c b/src/kernel/move.c index 82a2a51cc..12f7e85c3 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -2715,3 +2715,7 @@ void follow_unit(unit * u) } } } + +#ifndef DISABLE_TESTS +#include "move_test.c" +#endif diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 2b399afa2..3ce64196f 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -69,10 +69,10 @@ const ship_type *findshiptype(const char *name, const struct locale *lang) for (qi = 0, ql = shiptypes; ql; ql_advance(&ql, &qi, 1)) { ship_type *stype = (ship_type *) ql_get(ql, qi); - variant var; + variant var2; const char *n = locale_string(lang, stype->name[0]); - var.v = (void *)stype; - addtoken(&sn->names, n, var); + var2.v = (void *)stype; + addtoken(&sn->names, n, var2); } snames = sn; } diff --git a/src/tests.c b/src/tests.c index 4f061e01a..9999c79bc 100644 --- a/src/tests.c +++ b/src/tests.c @@ -9,6 +9,7 @@ CuSuite *get_curse_suite(void); CuSuite *get_market_suite(void); +CuSuite *get_move_suite(void); CuSuite *get_laws_suite(void); #include @@ -34,6 +35,7 @@ int RunAllTests(void) CuSuiteAddSuite(suite, get_quicklist_suite()); CuSuiteAddSuite(suite, get_curse_suite()); CuSuiteAddSuite(suite, get_market_suite()); + CuSuiteAddSuite(suite, get_move_suite()); CuSuiteAddSuite(suite, get_laws_suite()); CuSuiteRun(suite); From e01c6bb8b1dfa7fefafe583829e5875b2198b0b1 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 8 Mar 2011 21:06:38 -0800 Subject: [PATCH 119/400] make merge request sing with Eressea added a missing file (move_test.c) changing the way tests are included making some lua code prettier (too many parens) --- scripts/tests/common.lua | 22 +++++++++++----------- src/bindings/bind_region.c | 14 ++------------ src/kernel.vcxproj | 6 ++---- src/kernel.vcxproj.filters | 3 +++ src/kernel/curse.c | 4 ---- src/kernel/curse_test.c | 6 ++++++ src/kernel/move.c | 4 ---- src/kernel/move_test.c | 7 +++++++ src/tests.c | 3 ++- 9 files changed, 33 insertions(+), 36 deletions(-) create mode 100644 src/kernel/move_test.c diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 0c4bb6ad3..e2fe94daf 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -9,8 +9,8 @@ local function _test_unique_btype() local utype = nil for i = 1, #config.buildings do bt = config.buildings[i] - if (((config.get_building(bt).flags / 4) % 2) ~= 0) then -- #define BTF_UNIQUE 0x04 - if (((config.get_building(bt).flags / 2) % 2) == 0) then -- #define BTF_NOBUILD 0x02 + if ((config.get_building(bt).flags / 4) % 2) ~= 0 then -- #define BTF_UNIQUE 0x04 + if ((config.get_building(bt).flags / 2) % 2) == 0 then -- #define BTF_NOBUILD 0x02 utype = bt end end @@ -89,7 +89,7 @@ function test_plane() local r, x, y for x = -3, 3 do for y = -3, 3 do r = region.create(x, y, "plain") - if (x==y) then + if x==y then local u = unit.create(f, r, 1) end end end @@ -752,7 +752,7 @@ function test_ride_with_horses_and_cart() u:add_item("sword", capacity / sword_cfg.weight) u:add_item("horse", 1) - if (cart_cfg~=nil) then + if cart_cfg~=nil then -- we need 2 horses for a cart, so this should fail: u:add_item("cart", 1) u:clear_orders() @@ -965,7 +965,7 @@ function test_building_unique0() local u2 = unit.create(f2, r, 20) local utype = _test_unique_btype() - if (utype ~= nil) then + if utype ~= nil then assert_equal("harbour", utype) u:set_skill("building", 20) u:add_item("log", 10000) @@ -988,7 +988,7 @@ function test_building_unique0() bcount = 0 for bs in r.buildings do assert_equal(1, string.find(bs.name, translate(utype))) - if (bs.size >= config.get_building(utype).maxsize) then + if bs.size >= config.get_building(utype).maxsize then bcount = bcount + 1 end end @@ -1006,7 +1006,7 @@ function test_building_unique() local u2 = unit.create(f2, r, 20) local utype = _test_unique_btype() - if (utype ~= nil) then + if utype ~= nil then u:set_skill("building", 20) u:add_item("log", 10000) u:add_item("iron", 10000) @@ -1030,20 +1030,20 @@ function test_building_unique() u2:clear_orders() u2:add_order("MACHEN Hafen") process_orders() - if (r.buildings() == nil) then - process_orders() + if r.buildings == nil then + process_orders() end assert_not_nil(r.buildings) bcount = 0 local h1 = nil for bs in r.buildings do - if (h1 == nil) then + if h1 == nil then h1 = bs.name else assert_equal(h1, bs.name) end assert_equal(1, string.find(bs.name, "Hafen")) - if (bs.size >= 25) then + if bs.size >= 25 then bcount = bcount + 1 end end diff --git a/src/bindings/bind_region.c b/src/bindings/bind_region.c index 3ec4d8e5b..1b4244d81 100644 --- a/src/bindings/bind_region.c +++ b/src/bindings/bind_region.c @@ -656,18 +656,8 @@ void tolua_region_open(lua_State * L) tolua_function(L, TOLUA_CAST "get_key", tolua_region_getkey); tolua_function(L, TOLUA_CAST "set_key", tolua_region_setkey); -#if 0 - .def("add_notice", ®ion_addnotice) - .def("add_direction", ®ion_adddirection) - .def("move", ®ion_move) - .def("get_road", ®ion_getroad) - .def("set_road", ®ion_setroad) - .def("next", ®ion_next) - .def("add_item", ®ion_additem) - .property("items", ®ion_items, return_stl_iterator) - .property("plane_id", ®ion_plane) -#endif - tolua_variable(L, TOLUA_CAST "objects", tolua_region_get_objects, 0); + + tolua_variable(L, TOLUA_CAST "objects", tolua_region_get_objects, 0); } tolua_endmodule(L); diff --git a/src/kernel.vcxproj b/src/kernel.vcxproj index b6beb08b2..1cce4c98b 100644 --- a/src/kernel.vcxproj +++ b/src/kernel.vcxproj @@ -105,6 +105,7 @@ + @@ -178,10 +179,7 @@ - - true - true - + diff --git a/src/kernel.vcxproj.filters b/src/kernel.vcxproj.filters index 1eba9e2a2..566a12419 100644 --- a/src/kernel.vcxproj.filters +++ b/src/kernel.vcxproj.filters @@ -292,6 +292,9 @@ attributes + + kernel + diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 2fff1a498..0c3b74cd9 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -808,7 +808,3 @@ double destr_curse(curse * c, int cast_level, double force) } return force; } - -#ifndef DISABLE_TESTS -#include "curse_test.c" -#endif diff --git a/src/kernel/curse_test.c b/src/kernel/curse_test.c index e26366a5f..7ccdd9a90 100644 --- a/src/kernel/curse_test.c +++ b/src/kernel/curse_test.c @@ -1,3 +1,9 @@ +#include +#include "types.h" +#include "curse.h" + +#include + #include static void test_curse(CuTest * tc) diff --git a/src/kernel/move.c b/src/kernel/move.c index 12f7e85c3..82a2a51cc 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -2715,7 +2715,3 @@ void follow_unit(unit * u) } } } - -#ifndef DISABLE_TESTS -#include "move_test.c" -#endif diff --git a/src/kernel/move_test.c b/src/kernel/move_test.c new file mode 100644 index 000000000..cd4447f3e --- /dev/null +++ b/src/kernel/move_test.c @@ -0,0 +1,7 @@ +#include + +CuSuite *get_move_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + return suite; +} diff --git a/src/tests.c b/src/tests.c index 9999c79bc..a21a2a73d 100644 --- a/src/tests.c +++ b/src/tests.c @@ -6,10 +6,11 @@ #include #include +#include +#include CuSuite *get_curse_suite(void); CuSuite *get_market_suite(void); -CuSuite *get_move_suite(void); CuSuite *get_laws_suite(void); #include From 5bf42bd8e9c2f93bf2919fdf6ec5668a5b4f5c21 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 8 Mar 2011 21:16:47 -0800 Subject: [PATCH 120/400] make laws_tests more stand-alone --- src/gamecode.vcxproj | 5 +---- src/gamecode/laws.c | 10 +++------- src/gamecode/laws.h | 4 ++++ src/gamecode/laws_test.c | 17 +++++++++++++++++ src/tests.c | 11 +++++------ 5 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/gamecode.vcxproj b/src/gamecode.vcxproj index 78f231ff1..0872d49ec 100644 --- a/src/gamecode.vcxproj +++ b/src/gamecode.vcxproj @@ -97,10 +97,7 @@ - - true - true - + true diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 470ab9fda..5ef5fa739 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -205,7 +205,7 @@ enum { FOOD_IS_FREE = 4 }; -static void get_food(region * r) +void get_food(region * r) { plane *pl = rplane(r); unit *u; @@ -1614,7 +1614,7 @@ static int display_cmd(unit * u, struct order *ord) return 0; } -static boolean renamed_building(const building * b) +boolean renamed_building(const building * b) { const struct locale *lang = locales; for (; lang; lang = nextlocale(lang)) { @@ -1645,7 +1645,7 @@ static int rename_cmd(unit * u, order * ord, char **s, const char *s2) return 0; } -static int +int rename_building(unit * u, order * ord, building * b, const char *name) { unit *owner = b ? building_owner(b) : 0; @@ -4410,7 +4410,3 @@ int init_data(const char *filename, const char *catalog) } return 0; } - -#ifndef DISABLE_TESTS -#include "laws_test.c" -#endif diff --git a/src/gamecode/laws.h b/src/gamecode/laws.h index 83e3bacc6..2ea50b8eb 100644 --- a/src/gamecode/laws.h +++ b/src/gamecode/laws.h @@ -34,6 +34,10 @@ extern "C" { const char *s, struct unit *receiver); int init_data(const char *filename, const char *catalog); + boolean renamed_building(const struct building * b); + int rename_building(struct unit * u, struct order * ord, struct building * b, const char *name); + void get_food(struct region * r); + /* eressea-specific. put somewhere else, please. */ void processorders(void); extern struct attrib_type at_germs; diff --git a/src/gamecode/laws_test.c b/src/gamecode/laws_test.c index 9587117f4..476b1fab2 100644 --- a/src/gamecode/laws_test.c +++ b/src/gamecode/laws_test.c @@ -1,7 +1,24 @@ /* this file should only be included by laws.c, never compiled on its own * (it does not even include all the headers needed to do so). **/ +#include +#include +#include "laws.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + #include +#include static void test_new_building_can_be_renamed(CuTest * tc) { diff --git a/src/tests.c b/src/tests.c index a21a2a73d..d736a7444 100644 --- a/src/tests.c +++ b/src/tests.c @@ -8,10 +8,9 @@ #include #include #include +#include -CuSuite *get_curse_suite(void); CuSuite *get_market_suite(void); -CuSuite *get_laws_suite(void); #include #include @@ -102,12 +101,12 @@ void test_create_world(void) building_type *btype; ship_type *stype; - t_plain = calloc(1, sizeof(terrain_type)); + t_plain = (terrain_type*)calloc(1, sizeof(terrain_type)); t_plain->_name = strdup("plain"); t_plain->flags = LAND_REGION | FOREST_REGION | WALK_INTO; register_terrain(t_plain); - t_ocean = calloc(1, sizeof(terrain_type)); + t_ocean = (terrain_type*)calloc(1, sizeof(terrain_type)); t_ocean->_name = strdup("ocean"); t_ocean->flags = SEA_REGION | SAIL_INTO | SWIM_INTO; register_terrain(t_ocean); @@ -115,10 +114,10 @@ void test_create_world(void) island[0] = test_create_region(0, 0, t_plain); island[1] = test_create_region(1, 0, t_plain); for (i = 0; i != 2; ++i) { - direction_t j; + int j; region *r = island[i]; for (j = 0; j != MAXDIRECTIONS; ++j) { - region *rn = r_connect(r, j); + region *rn = r_connect(r, (direction_t)j); if (!rn) { rn = test_create_region(r->x + delta_x[j], r->y + delta_y[j], t_ocean); } From fa69da6de21300178b840ef73f79cf089e7d1859 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 9 Mar 2011 10:43:30 +0100 Subject: [PATCH 121/400] added missing move_test.c --- src/kernel/move_test.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/kernel/move_test.c b/src/kernel/move_test.c index cd4447f3e..ce2a1f221 100644 --- a/src/kernel/move_test.c +++ b/src/kernel/move_test.c @@ -1,7 +1,35 @@ +#include +#include +#include + +#include + #include +#include + +static void building_type_exists(CuTest * tc) +{ + region *r; + building *b; + building_type *btype; + building_type *btype2 = calloc(1, sizeof(building_type)); + + test_cleanup(); + test_create_world(); + + btype = bt_find("castle"); + + r = findregion(-1, 0); + b = new_building(btype, r, default_locale); + + CuAssertTrue(tc, buildingtype_exists(r, NULL, true) == false); + CuAssertTrue(tc, buildingtype_exists(r, btype, true) == true); + CuAssertTrue(tc, buildingtype_exists(r, btype2, true) == false); +} CuSuite *get_move_suite(void) { CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, building_type_exists); return suite; } From ff51fe6493801e86cc92c9d6fd1886da712e314a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 9 Mar 2011 14:44:31 +0100 Subject: [PATCH 122/400] added meropis buildings also fixed a bug that prevented tests with ATTACKs to be executed properly (NewbieImmunity) --- scripts/tests/common.lua | 4 +++- src/kernel/building.c | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index e2fe94daf..35f0101bd 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -42,6 +42,7 @@ function setup() write_game("free.dat") settings.set("nmr.removenewbie", "0") settings.set("nmr.timeout", "0") + settings.set("NewbieImmunity", "0") settings.set("rules.economy.food", "4") end @@ -67,6 +68,7 @@ function test_fleeing_units_can_be_transported() u1:add_order("ATTACKIEREN " .. itoa36(u2.id)) u2.number = 100 u2:add_order("FAHREN " .. itoa36(u3.id)) + u2:add_order("KAEMPFE FLIEHE") u3.number = 100 u3:add_order("KAEMPFE FLIEHE") u3:add_order("TRANSPORT " .. itoa36(u2.id)) @@ -1043,7 +1045,7 @@ function test_building_unique() assert_equal(h1, bs.name) end assert_equal(1, string.find(bs.name, "Hafen")) - if bs.size >= 25 then + if bs.size >= config.get_building(utype).maxsize then bcount = bcount + 1 end end diff --git a/src/kernel/building.c b/src/kernel/building.c index 45d6f84fe..f26e153bf 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -126,6 +126,7 @@ typedef struct building_typelist { quicklist *buildingtypes = NULL; +/* Returns a building type for the (internal) name */ building_type *bt_find(const char *name) { quicklist *ql; @@ -169,6 +170,9 @@ attrib_type at_building_generic_type = { ATF_UNIQUE }; +/* Returns the (internal) name for a building of given size and type. Especially, returns the correct + * name if it depends on the size (as for Eressea castles). + */ const char *buildingtype(const building_type * btype, const building * b, int bsize) { @@ -350,6 +354,8 @@ int wdw_pyramid_level(const struct building *b) static local_names *bnames; +/* Find the building type for a given localized name (as seen by the user). Useful for parsing + * orders. The inverse of locale_string(lang, btype->_name), sort of. */ const building_type *findbuildingtype(const char *name, const struct locale *lang) { @@ -391,10 +397,17 @@ static int eressea_building_protection(building * b, unit * u) return beff; } +static int meropis_building_protection(building * b, unit * u) +{ + return 2; +} + void register_buildings(void) { register_function((pf_generic) & eressea_building_protection, "eressea_building_protection"); + register_function((pf_generic) & meropis_building_protection, + "meropis_building_protection"); register_function((pf_generic) & init_smithy, "init_smithy"); register_function((pf_generic) & castle_name, "castle_name"); register_function((pf_generic) & castle_name_2, "castle_name_2"); From cf4e081179fa385ecb46ac39ddd05b636f37a527 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 9 Mar 2011 14:48:39 +0100 Subject: [PATCH 123/400] nobody ever profited from castle bonuses --- src/kernel/battle.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/kernel/battle.c b/src/kernel/battle.c index 5c1fa233f..2a7356a7c 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -3352,9 +3352,9 @@ fighter *make_fighter(battle * b, unit * u, side * s1, boolean attack) if (attack) { set_attacker(fig); } else { - building *b = u->building; - if (b && b->sizeleft >= u->number && playerrace(u->race)) { - fig->building = b; + building *bld = u->building; + if (bld && bld->sizeleft >= u->number && playerrace(u->race)) { + fig->building = bld; fig->building->sizeleft -= u->number; } } @@ -4062,6 +4062,11 @@ static boolean init_battle(region * r, battle ** bp) battle *b = NULL; unit *u; boolean fighting = false; + building *bu; + + /* Alle Mann raus aus der Burg! */ + for (bu = r->buildings; bu != NULL; bu = bu->next) + bu->sizeleft = bu->size; /* list_foreach geht nicht, wegen flucht */ for (u = r->units; u != NULL; u = u->next) { @@ -4428,7 +4433,6 @@ void do_battle(region * r) battle *b = NULL; boolean fighting = false; ship *sh; - building *bu; static int init_rules = 0; if (!init_rules) { @@ -4460,10 +4464,6 @@ void do_battle(region * r) join_allies(b); make_heroes(b); - /* Alle Mann raus aus der Burg! */ - for (bu = r->buildings; bu != NULL; bu = bu->next) - bu->sizeleft = bu->size; - /* make sure no ships are damaged initially */ for (sh = r->ships; sh; sh = sh->next) freset(sh, SF_DAMAGED); From f0039bc58fb69f805abb9821815798469f430ef6 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 9 Mar 2011 17:14:23 +0100 Subject: [PATCH 124/400] added spy to spy messages (see #1604) --- res/messages.xml | 4 ++++ src/gamecode/spy.c | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/res/messages.xml b/res/messages.xml index d0c2fcbe7..2a678313a 100644 --- a/res/messages.xml +++ b/res/messages.xml @@ -3561,6 +3561,7 @@ + @@ -3569,6 +3570,7 @@ + @@ -3577,6 +3579,7 @@ + @@ -3585,6 +3588,7 @@ + diff --git a/src/gamecode/spy.c b/src/gamecode/spy.c index 0eee13d5a..4be61f013 100644 --- a/src/gamecode/spy.c +++ b/src/gamecode/spy.c @@ -66,7 +66,7 @@ void spy_message(int spy, const unit * u, const unit * target) sc_mage *mage = get_mage(target); /* bei Magiern Zaubersprüche und Magiegebiet */ if (mage) { - ADDMSG(&u->faction->msgs, msg_message("spyreport_mage", "target type", + ADDMSG(&u->faction->msgs, msg_message("spyreport_mage", "target type", u, target, magic_school[mage->magietyp])); } } @@ -75,7 +75,7 @@ void spy_message(int spy, const unit * u, const unit * target) if (fv && fv != target->faction) { /* wahre Partei */ ADDMSG(&u->faction->msgs, msg_message("spyreport_faction", - "target faction", target, target->faction)); + "target faction", u, target, target->faction)); ql_set_insert(&u->faction->seen_factions, target->faction); } } @@ -102,12 +102,12 @@ void spy_message(int spy, const unit * u, const unit * target) } } if (found) { - ADDMSG(&u->faction->msgs, msg_message("spyreport_skills", "target skills", + ADDMSG(&u->faction->msgs, msg_message("spyreport_skills", "target skills", u, target, buf)); } if (target->items) { - ADDMSG(&u->faction->msgs, msg_message("spyreport_items", "target items", + ADDMSG(&u->faction->msgs, msg_message("spyreport_items", "target items", u, target, target->items)); } } From 2c02c38803f975edf47b894f76c5d062e775ce0d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 9 Mar 2011 20:49:55 +0100 Subject: [PATCH 125/400] insects trying to land in glaciers should not damage ships (cf. #1729) --- src/kernel/move.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/kernel/move.c b/src/kernel/move.c index 82a2a51cc..ed5aeb4c1 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -628,7 +628,12 @@ static boolean is_freezing(const unit * u) return true; } -static boolean ship_allowed(const struct ship *sh, const region * r) +#define SA_HARBOUR 1 +#define SA_COAST 1 +#define SA_NO_INSECT -1 +#define SA_NO_COAST -2 + +static int ship_allowed(const struct ship *sh, const region * r) { int c = 0; static const building_type *bt_harbour = NULL; @@ -651,19 +656,19 @@ static boolean ship_allowed(const struct ship *sh, const region * r) "unit region", u, r)); } - return false; + return SA_NO_INSECT; } } } if (buildingtype_exists(r, bt_harbour, true)) - return true; + return SA_HARBOUR; for (c = 0; sh->type->coasts[c] != NULL; ++c) { if (sh->type->coasts[c] == r->terrain) - return true; + return SA_COAST; } - return false; + return SA_NO_COAST; } static boolean flying_ship(const ship * sh) @@ -747,7 +752,7 @@ static void drifting_ships(region * r) region *rn; dir = (direction_t) ((d + d_offset) % MAXDIRECTIONS); rn = rconnect(r, dir); - if (rn != NULL && fval(rn->terrain, SAIL_INTO) && ship_allowed(sh, rn)) { + if (rn != NULL && fval(rn->terrain, SAIL_INTO) && ship_allowed(sh, rn) > 0) { rnext = rn; if (!fval(rnext->terrain, SEA_REGION)) break; @@ -1726,6 +1731,7 @@ sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) int stormchance; static int stormyness; static int gamecookie = -1; + int reason; if (gamecookie != global.cookie) { gamedate date; @@ -1813,9 +1819,10 @@ sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) } } - if (!ship_allowed(sh, next_point)) { + reason = ship_allowed(sh, next_point); + if (reason<0) { /* for some reason or another, we aren't allowed in there.. */ - if (check_leuchtturm(current_point, NULL)) { + if (check_leuchtturm(current_point, NULL) || reason == SA_NO_INSECT) { ADDMSG(&f->msgs, msg_message("sailnolandingstorm", "ship", sh)); } else { float dmg = From 3d98275d584ac83d8db2dc7cbf9fec502bbc7124 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 9 Mar 2011 20:51:11 +0100 Subject: [PATCH 126/400] we never checked if building maintenance was paid (see also #1740) --- src/kernel/move.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/kernel/move.c b/src/kernel/move.c index ed5aeb4c1..11aa94f86 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -1637,11 +1637,8 @@ buildingtype_exists(const region * r, const building_type * bt, boolean working) building *b; for (b = rbuildings(r); b; b = b->next) { - if (b->type == bt) { - if (b->size >= bt->maxsize) { - return true; - } - } + if (b->type == bt && b->size >= bt->maxsize && (!working || fval(b, BLD_WORKING))) + return true; } return false; From 8fca34e8248012e7bb46e715a3af03925039a986 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 12 Mar 2011 16:58:12 -0800 Subject: [PATCH 127/400] SUITE_ADD_TEST is a macro and doesn't want this syntax --- src/gamecode/laws_test.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/gamecode/laws_test.c b/src/gamecode/laws_test.c index 476b1fab2..367a9c629 100644 --- a/src/gamecode/laws_test.c +++ b/src/gamecode/laws_test.c @@ -214,13 +214,13 @@ static void test_cannot_create_unit_above_limit(CuTest * tc) CuSuite *get_laws_suite(void) { CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, &test_new_building_can_be_renamed); - SUITE_ADD_TEST(suite, &test_rename_building); - SUITE_ADD_TEST(suite, &test_rename_building_twice); - SUITE_ADD_TEST(suite, &test_fishing_feeds_2_people); - SUITE_ADD_TEST(suite, &test_fishing_does_not_give_goblins_money); - SUITE_ADD_TEST(suite, &test_fishing_gets_reset); - SUITE_ADD_TEST(suite, &test_unit_limit); - SUITE_ADD_TEST(suite, &test_cannot_create_unit_above_limit); + SUITE_ADD_TEST(suite, test_new_building_can_be_renamed); + SUITE_ADD_TEST(suite, test_rename_building); + SUITE_ADD_TEST(suite, test_rename_building_twice); + SUITE_ADD_TEST(suite, test_fishing_feeds_2_people); + SUITE_ADD_TEST(suite, test_fishing_does_not_give_goblins_money); + SUITE_ADD_TEST(suite, test_fishing_gets_reset); + SUITE_ADD_TEST(suite, test_unit_limit); + SUITE_ADD_TEST(suite, test_cannot_create_unit_above_limit); return suite; } From 315066309ad3e0c954a07f03eaae305790d100b7 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 12 Mar 2011 16:58:45 -0800 Subject: [PATCH 128/400] create races with a minimum of hitpoints so tests don't break. --- src/kernel/race.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/kernel/race.c b/src/kernel/race.c index dc35e62f1..3252f09b0 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -99,7 +99,9 @@ void racelist_insert(struct race_list **rl, const struct race *r) race *rc_new(const char *zName) { char zBuffer[80]; - race *rc = calloc(sizeof(race), 1); + race *rc = (race *)calloc(sizeof(race), 1); + + rc->hitpoints = 1; if (strchr(zName, ' ') != NULL) { log_error(("race '%s' has an invalid name. remove spaces\n", zName)); assert(strchr(zName, ' ') == NULL); From 5afb83c193680dd720f15c391244d37de79fc761 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 12 Mar 2011 16:59:32 -0800 Subject: [PATCH 129/400] Let tests clean up after/before themselves, so terrains can be created by each. --- src/kernel/terrain.c | 13 +++++++++++++ src/kernel/terrain.h | 6 +++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/kernel/terrain.c b/src/kernel/terrain.c index 2f5b677ea..6090f771c 100644 --- a/src/kernel/terrain.c +++ b/src/kernel/terrain.c @@ -63,6 +63,19 @@ const char *terraindata[MAXTERRAINS] = { static terrain_type *registered_terrains; +#ifndef DISABLE_TESTS +void test_clear_terrains(void) +{ + while (registered_terrains) { + terrain_type * t = registered_terrains; + registered_terrains = t->next; + free(t->_name); + free(t->production); + free(t); + } +} +#endif + const terrain_type *terrains(void) { return registered_terrains; diff --git a/src/kernel/terrain.h b/src/kernel/terrain.h index 64de714e7..fca223e01 100644 --- a/src/kernel/terrain.h +++ b/src/kernel/terrain.h @@ -67,7 +67,7 @@ extern "C" { struct terrain_production *production; const struct item_type **herbs; /* zero-terminated array of herbs */ const char *(*name) (const struct region * r); - const struct terrain_type *next; + struct terrain_type *next; } terrain_type; extern const terrain_type *terrains(void); @@ -77,6 +77,10 @@ extern "C" { extern void init_terrains(void); +#ifndef DISABLE_TESTS + void test_clear_terrains(void); +#endif + #ifdef __cplusplus } #endif From 31edf06d05e9e391f177f5e0832017b635fa2619 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 12 Mar 2011 17:00:16 -0800 Subject: [PATCH 130/400] just a bit of typecasting --- src/kernel/xmlreader.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 6cef9d00c..51b7084cb 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -192,7 +192,7 @@ xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, assert(*consPtr == NULL); - *consPtr = con = calloc(sizeof(construction), 1); + *consPtr = con = (construction *)calloc(sizeof(construction), 1); consPtr = &con->improvement; con->skill = sk; @@ -349,7 +349,7 @@ static int parse_buildings(xmlDocPtr doc) maintenance *mt; if (btype->maintenance == NULL) { - btype->maintenance = + btype->maintenance = (struct maintenance *) calloc(sizeof(struct maintenance), result->nodesetval->nodeNr + 1); } mt = btype->maintenance + k; From 89b3b3161f63915538816a581f8c20192cbd9ee1 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 12 Mar 2011 17:01:20 -0800 Subject: [PATCH 131/400] Add a test for the effect of buildings in battles, and a file to test pieces of the combat code from C in the future. Add some testing support for terrains and buildings. --- src/gamecode/market_test.c | 5 +-- src/kernel.vcxproj | 1 + src/kernel.vcxproj.filters | 3 ++ src/kernel/battle.c | 20 ++++++------ src/kernel/battle.h | 10 ++++-- src/kernel/battle_test.c | 64 ++++++++++++++++++++++++++++++++++++++ src/tests.c | 50 +++++++++++++++++++---------- src/tests.h | 2 ++ 8 files changed, 122 insertions(+), 33 deletions(-) create mode 100644 src/kernel/battle_test.c diff --git a/src/gamecode/market_test.c b/src/gamecode/market_test.c index edf27b2bb..b697ccc53 100644 --- a/src/gamecode/market_test.c +++ b/src/gamecode/market_test.c @@ -29,10 +29,7 @@ static void market_curse(CuTest * tc) btype->_name = "market"; bt_register(btype); - terrain = calloc(1, sizeof(terrain_type)); - terrain->_name = strdup("plain"); - register_terrain(terrain); - terrain->flags = LAND_REGION | WALK_INTO; + terrain = test_create_terrain("plain", LAND_REGION | WALK_INTO); for (x = 0; x != 3; ++x) { for (y = 0; y != 3; ++y) { diff --git a/src/kernel.vcxproj b/src/kernel.vcxproj index 1cce4c98b..81ea82887 100644 --- a/src/kernel.vcxproj +++ b/src/kernel.vcxproj @@ -90,6 +90,7 @@ + diff --git a/src/kernel.vcxproj.filters b/src/kernel.vcxproj.filters index 566a12419..caadb2064 100644 --- a/src/kernel.vcxproj.filters +++ b/src/kernel.vcxproj.filters @@ -295,6 +295,9 @@ kernel + + kernel + diff --git a/src/kernel/battle.c b/src/kernel/battle.c index 2a7356a7c..5e8e83cda 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -1892,7 +1892,7 @@ static void do_extra_spell(troop at, const att * a) } } -static int skilldiff(troop at, troop dt, int dist) +int skilldiff(troop at, troop dt, int dist) { fighter *af = at.fighter, *df = dt.fighter; unit *au = af->unit, *du = df->unit; @@ -2442,7 +2442,7 @@ double fleechance(unit * u) /** add a new army to the conflict * beware: armies need to be added _at the beginning_ of the list because * otherwise join_allies() will get into trouble */ -static side *make_side(battle * b, const faction * f, const group * g, +side *make_side(battle * b, const faction * f, const group * g, unsigned int flags, const faction * stealthfaction) { side *s1 = b->sides + b->nsides; @@ -3656,13 +3656,18 @@ static const char *simplename(region * r) return name; } -static battle *make_battle(region * r) +battle *make_battle(region * r) { - battle *b = calloc(1, sizeof(struct battle)); + battle *b = (battle *)calloc(1, sizeof(battle)); unit *u; bfaction *bf; + building * bld; static int max_fac_no = 0; /* need this only once */ + /* Alle Mann raus aus der Burg! */ + for (bld = r->buildings; bld != NULL; bld = bld->next) + bld->sizeleft = bld->size; + if (battledebug) { char zText[MAX_PATH]; char zFilename[MAX_PATH]; @@ -3693,7 +3698,7 @@ static battle *make_battle(region * r) break; } if (!bf) { - bf = calloc(sizeof(bfaction), 1); + bf = (bfaction *)calloc(sizeof(bfaction), 1); ++b->nfactions; bf->faction = u->faction; bf->next = b->factions; @@ -4062,11 +4067,6 @@ static boolean init_battle(region * r, battle ** bp) battle *b = NULL; unit *u; boolean fighting = false; - building *bu; - - /* Alle Mann raus aus der Burg! */ - for (bu = r->buildings; bu != NULL; bu = bu->next) - bu->sizeleft = bu->size; /* list_foreach geht nicht, wegen flucht */ for (u = r->units; u != NULL; u = u->next) { diff --git a/src/kernel/battle.h b/src/kernel/battle.h index 46cd3c4ce..b7fbf9f2f 100644 --- a/src/kernel/battle.h +++ b/src/kernel/battle.h @@ -261,14 +261,20 @@ extern "C" { extern struct region *fleeregion(const struct unit *u); #endif extern struct fighter *select_corpse(struct battle *b, struct fighter *af); - extern fighter *make_fighter(struct battle *b, struct unit *u, side * s, - boolean attack); extern int statusrow(int status); extern void drain_exp(struct unit *u, int d); extern void kill_troop(troop dt); extern void remove_troop(troop dt); /* not the same as the badly named rmtroop */ extern boolean is_attacker(const fighter * fig); + extern struct battle *make_battle(struct region * r); + extern fighter *make_fighter(struct battle *b, struct unit *u, side * s, + boolean attack); + extern struct side *make_side(struct battle * b, const struct faction * f, + const struct group * g, unsigned int flags, + const struct faction * stealthfaction); + extern int skilldiff(troop at, troop dt, int dist); + #ifdef __cplusplus } #endif diff --git a/src/kernel/battle_test.c b/src/kernel/battle_test.c new file mode 100644 index 000000000..34d9c9913 --- /dev/null +++ b/src/kernel/battle_test.c @@ -0,0 +1,64 @@ +#include +#include +#include "battle.h" +#include "building.h" +#include "faction.h" +#include "race.h" +#include "region.h" +#include "unit.h" +#include "tests.h" +#include + +static int add_two(building * b, unit * u) { + return 2; +} + +static void test_building_bonus(CuTest * tc) +{ + unit *du, *au; + region *r; + building * bld; + fighter *df, *af; + battle *b; + side *ds, *as; + int diff; + troop dt, at; + building_type * btype; + + test_cleanup(); + test_create_world(); + r = findregion(0, 0); + btype = bt_find("castle"); + btype->protection = &add_two; + bld = test_create_building(r, btype); + bld->size = 10; + + du = test_create_unit(test_create_faction(rc_find("human")), r); + du->building = bld; + + au = test_create_unit(test_create_faction(rc_find("human")), r); + + b = make_battle(r); + ds = make_side(b, du->faction, 0, 0, 0); + df = make_fighter(b, du, ds, false); + CuAssertPtrEquals(tc, bld, df->building); + + as = make_side(b, au->faction, 0, 0, 0); + af = make_fighter(b, au, as, true); + CuAssertPtrEquals(tc, 0, af->building); + + dt.fighter = df; + dt.index = 0; + at.fighter = af; + at.index = 0; + + diff = skilldiff(at, dt, 0); + CuAssertIntEquals(tc, -2, diff); +} + +CuSuite *get_battle_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_building_bonus); + return suite; +} diff --git a/src/tests.c b/src/tests.c index d736a7444..7224b4dbf 100644 --- a/src/tests.c +++ b/src/tests.c @@ -8,6 +8,7 @@ #include #include #include +#include #include CuSuite *get_market_suite(void); @@ -20,6 +21,8 @@ CuSuite *get_market_suite(void); #include #include #include +#include +#include #include int RunAllTests(void) @@ -37,6 +40,7 @@ int RunAllTests(void) CuSuiteAddSuite(suite, get_market_suite()); CuSuiteAddSuite(suite, get_move_suite()); CuSuiteAddSuite(suite, get_laws_suite()); + CuSuiteAddSuite(suite, get_battle_suite()); CuSuiteRun(suite); CuSuiteSummary(suite, output); @@ -49,12 +53,13 @@ int RunAllTests(void) struct race *test_create_race(const char *name) { - race *rc = rc_add(rc_new("human")); + race *rc = rc_add(rc_new(name)); + rc->flags |= RCF_PLAYERRACE; + rc->maintenance = 10; return rc; } -struct region *test_create_region(int x, int y, - const struct terrain_type *terrain) +struct region *test_create_region(int x, int y, const terrain_type *terrain) { region *r = new_region(x, y, NULL, 0); terraform_region(r, terrain); @@ -80,11 +85,31 @@ struct unit *test_create_unit(struct faction *f, struct region *r) void test_cleanup(void) { + test_clear_terrains(); global.functions.maintenance = NULL; global.functions.wage = NULL; free_gamedata(); } +terrain_type * +test_create_terrain(const char * name, unsigned int flags) +{ + terrain_type * t; + + assert(!get_terrain(name)); + t = (terrain_type*)calloc(1, sizeof(terrain_type)); + t->_name = strdup(name); + t->flags = flags; + register_terrain(t); + return t; +} + +building * test_create_building(region * r, const building_type * btype) +{ + building * b = new_building(btype, r, default_locale); + b->size = btype->maxsize>0?btype->maxsize:1; + return b; +} /** creates a small world and some stuff in it. * two terrains: 'plain' and 'ocean' * one race: 'human' @@ -101,15 +126,8 @@ void test_create_world(void) building_type *btype; ship_type *stype; - t_plain = (terrain_type*)calloc(1, sizeof(terrain_type)); - t_plain->_name = strdup("plain"); - t_plain->flags = LAND_REGION | FOREST_REGION | WALK_INTO; - register_terrain(t_plain); - - t_ocean = (terrain_type*)calloc(1, sizeof(terrain_type)); - t_ocean->_name = strdup("ocean"); - t_ocean->flags = SEA_REGION | SAIL_INTO | SWIM_INTO; - register_terrain(t_ocean); + t_plain = test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO); + t_ocean = test_create_terrain("ocean", SEA_REGION | SAIL_INTO | SWIM_INTO); island[0] = test_create_region(0, 0, t_plain); island[1] = test_create_region(1, 0, t_plain); @@ -124,17 +142,15 @@ void test_create_world(void) } } - rc_human = rc_add(rc_new("human")); - rc_human->maintenance = 10; + rc_human = test_create_race("human"); - btype = calloc(sizeof(building_type), 1); + btype = (building_type*)calloc(sizeof(building_type), 1); btype->flags = BTF_NAMECHANGE; btype->_name = strdup("castle"); bt_register(btype); - stype = calloc(sizeof(ship_type), 1); + stype = (ship_type*)calloc(sizeof(ship_type), 1); stype->name[0] = strdup("boat"); stype->name[1] = strdup("boat_p"); st_register(stype); - } diff --git a/src/tests.h b/src/tests.h index 51ee4aecb..01cef3516 100644 --- a/src/tests.h +++ b/src/tests.h @@ -5,12 +5,14 @@ extern "C" { #ifndef DISABLE_TESTS void test_cleanup(void); + struct terrain_type * test_create_terrain(const char * name, unsigned int flags); struct race *test_create_race(const char *name); struct region *test_create_region(int x, int y, const struct terrain_type *terrain); struct faction *test_create_faction(const struct race *rc); struct unit *test_create_unit(struct faction *f, struct region *r); void test_create_world(void); + struct building * test_create_building(struct region * r, const struct building_type * btype); int RunAllTests(void); #else From 3493c651f7524f86e9dee42f10dc0b7979feb1b0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 12 Mar 2011 17:54:57 -0800 Subject: [PATCH 132/400] test that attackers do not get a building bonus --- src/kernel/battle_test.c | 44 ++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/src/kernel/battle_test.c b/src/kernel/battle_test.c index 34d9c9913..89f2f15b4 100644 --- a/src/kernel/battle_test.c +++ b/src/kernel/battle_test.c @@ -13,7 +13,7 @@ static int add_two(building * b, unit * u) { return 2; } -static void test_building_bonus(CuTest * tc) +static void test_defenders_get_building_bonus(CuTest * tc) { unit *du, *au; region *r; @@ -34,17 +34,16 @@ static void test_building_bonus(CuTest * tc) bld->size = 10; du = test_create_unit(test_create_faction(rc_find("human")), r); - du->building = bld; - au = test_create_unit(test_create_faction(rc_find("human")), r); + du->building = bld; b = make_battle(r); ds = make_side(b, du->faction, 0, 0, 0); df = make_fighter(b, du, ds, false); - CuAssertPtrEquals(tc, bld, df->building); - as = make_side(b, au->faction, 0, 0, 0); af = make_fighter(b, au, as, true); + + CuAssertPtrEquals(tc, bld, df->building); CuAssertPtrEquals(tc, 0, af->building); dt.fighter = df; @@ -54,11 +53,44 @@ static void test_building_bonus(CuTest * tc) diff = skilldiff(at, dt, 0); CuAssertIntEquals(tc, -2, diff); + + diff = skilldiff(dt, at, 0); + CuAssertIntEquals(tc, 0, diff); +} + +static void test_attackers_get_no_building_bonus(CuTest * tc) +{ + unit *au; + region *r; + building * bld; + fighter *af; + battle *b; + side *as; + building_type * btype; + + test_cleanup(); + test_create_world(); + r = findregion(0, 0); + btype = bt_find("castle"); + btype->protection = &add_two; + bld = test_create_building(r, btype); + bld->size = 10; + + au = test_create_unit(test_create_faction(rc_find("human")), r); + au->building = bld; + + + b = make_battle(r); + as = make_side(b, au->faction, 0, 0, 0); + af = make_fighter(b, au, as, true); + + CuAssertPtrEquals(tc, 0, af->building); } CuSuite *get_battle_suite(void) { CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, test_building_bonus); + SUITE_ADD_TEST(suite, test_defenders_get_building_bonus); + SUITE_ADD_TEST(suite, test_attackers_get_no_building_bonus); return suite; } From 8d497e4b50d5fabbfb4d377aa427ead5dd1bbeac Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 15 Mar 2011 20:00:54 -0700 Subject: [PATCH 133/400] change the way the market tests are included. --- src/gamecode.vcxproj | 5 +---- src/gamecode/market.c | 4 ---- src/gamecode/market_test.c | 16 +++++++++++++++- src/tests.c | 3 +-- src/tests.h | 2 ++ 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/gamecode.vcxproj b/src/gamecode.vcxproj index 0872d49ec..17572c776 100644 --- a/src/gamecode.vcxproj +++ b/src/gamecode.vcxproj @@ -99,10 +99,7 @@ - - true - true - + diff --git a/src/gamecode/market.c b/src/gamecode/market.c index 569a29b37..d49e528b6 100644 --- a/src/gamecode/market.c +++ b/src/gamecode/market.c @@ -177,7 +177,3 @@ void do_markets(void) ql_free(traders); } } - -#ifndef DISABLE_TESTS -#include "market_test.c" -#endif diff --git a/src/gamecode/market_test.c b/src/gamecode/market_test.c index b697ccc53..d60c71982 100644 --- a/src/gamecode/market_test.c +++ b/src/gamecode/market_test.c @@ -1,7 +1,21 @@ #include -#include +#include "platform.h" +#include "market.h" +#include "tests.h" + +#include +#include +#include +#include +#include +#include #include +#include + +#include + +#include static void market_curse(CuTest * tc) { diff --git a/src/tests.c b/src/tests.c index 7224b4dbf..fa5b6e315 100644 --- a/src/tests.c +++ b/src/tests.c @@ -10,8 +10,7 @@ #include #include #include - -CuSuite *get_market_suite(void); +#include #include #include diff --git a/src/tests.h b/src/tests.h index 01cef3516..2a3c4f625 100644 --- a/src/tests.h +++ b/src/tests.h @@ -3,6 +3,8 @@ extern "C" { #endif #ifndef DISABLE_TESTS + struct building_type; + struct building; void test_cleanup(void); struct terrain_type * test_create_terrain(const char * name, unsigned int flags); From 36b58cca6e0ec798731c44fa0b032b74f6cfe447 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 15 Mar 2011 21:04:38 -0700 Subject: [PATCH 134/400] test that fighters get created properly. better test initialization code. --- src/kernel/battle_test.c | 80 ++++++++++++++++++++++++++++++++++++++++ src/kernel/item.c | 51 ++++++++++++++++++------- src/kernel/item.h | 5 ++- src/kernel/terrain.h | 2 +- src/tests.c | 21 ++++++++++- 5 files changed, 143 insertions(+), 16 deletions(-) diff --git a/src/kernel/battle_test.c b/src/kernel/battle_test.c index 89f2f15b4..ceac668c7 100644 --- a/src/kernel/battle_test.c +++ b/src/kernel/battle_test.c @@ -3,12 +3,54 @@ #include "battle.h" #include "building.h" #include "faction.h" +#include "item.h" #include "race.h" #include "region.h" +#include "skill.h" #include "unit.h" #include "tests.h" #include +static void test_make_fighter(CuTest * tc) +{ + unit *au; + region *r; + fighter *af; + battle *b; + side *as; + faction * f; + + test_cleanup(); + test_create_world(); + r = findregion(0, 0); + f = test_create_faction(rc_find("human")); + au = test_create_unit(f, r); + skill_enabled[SK_MAGIC] = 1; + skill_enabled[SK_RIDING] = 1; + set_level(au, SK_MAGIC, 3); + set_level(au, SK_RIDING, 3); + au->status = ST_BEHIND; + set_item(au, I_HORSE, 1); + + b = make_battle(r); + as = make_side(b, au->faction, 0, 0, 0); + af = make_fighter(b, au, as, false); + + CuAssertIntEquals(tc, 1, b->nfighters); + CuAssertPtrEquals(tc, 0, af->building); + CuAssertPtrEquals(tc, as, af->side); + CuAssertIntEquals(tc, 0, af->run.hp); + CuAssertIntEquals(tc, ST_BEHIND, af->status); + CuAssertIntEquals(tc, 0, af->run.number); + CuAssertIntEquals(tc, au->hp, af->person[0].hp); + CuAssertIntEquals(tc, 1, af->person[0].speed); + CuAssertIntEquals(tc, au->number, af->alive); + CuAssertIntEquals(tc, 0, af->removed); + CuAssertIntEquals(tc, 3, af->magic); + CuAssertIntEquals(tc, 1, af->horses); + CuAssertIntEquals(tc, 0, af->elvenhorses); +} + static int add_two(building * b, unit * u) { return 2; } @@ -87,10 +129,48 @@ static void test_attackers_get_no_building_bonus(CuTest * tc) CuAssertPtrEquals(tc, 0, af->building); } +static void test_building_bonus_respects_size(CuTest * tc) +{ + unit *au, *du; + region *r; + building * bld; + fighter *af, *df; + battle *b; + side *as; + building_type * btype; + faction * f; + + test_cleanup(); + test_create_world(); + r = findregion(0, 0); + btype = bt_find("castle"); + btype->protection = &add_two; + bld = test_create_building(r, btype); + bld->size = 10; + + f = test_create_faction(rc_find("human")); + au = test_create_unit(f, r); + scale_number(au, 9); + au->building = bld; + du = test_create_unit(f, r); + du->building = bld; + scale_number(du, 2); + + b = make_battle(r); + as = make_side(b, au->faction, 0, 0, 0); + af = make_fighter(b, au, as, false); + df = make_fighter(b, du, as, false); + + CuAssertPtrEquals(tc, bld, af->building); + CuAssertPtrEquals(tc, 0, df->building); +} + CuSuite *get_battle_suite(void) { CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_make_fighter); SUITE_ADD_TEST(suite, test_defenders_get_building_bonus); SUITE_ADD_TEST(suite, test_attackers_get_no_building_bonus); + SUITE_ADD_TEST(suite, test_building_bonus_respects_size); return suite; } diff --git a/src/kernel/item.c b/src/kernel/item.c index 72f21cac8..08d9b2ca4 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -151,7 +151,7 @@ resource_type *new_resourcetype(const char **names, const char **appearances, if (rtype == NULL) { int i; - rtype = calloc(sizeof(resource_type), 1); + rtype = (resource_type *)calloc(sizeof(resource_type), 1); for (i = 0; i != 2; ++i) { rtype->_name[i] = strdup(names[i]); @@ -284,7 +284,7 @@ potion_type *new_potiontype(item_type * itype, int level) assert(resource2potion(itype->rtype) == NULL); - ptype = calloc(sizeof(potion_type), 1); + ptype = (potion_type *)calloc(sizeof(potion_type), 1); ptype->itype = itype; ptype->level = level; pt_register(ptype); @@ -628,7 +628,10 @@ int get_item(const unit * u, item_t it) int set_item(unit * u, item_t it, int value) { const item_type *type = olditemtype[it]; - item *i = *i_find(&u->items, type); + item *i; + + assert(type); + i = *i_find(&u->items, type); if (!i) { i = i_add(&u->items, i_new(type, value)); } else { @@ -740,11 +743,6 @@ mod_dwarves_only(const unit * u, const region * r, skill_t sk, int value) static void init_olditems(void) { item_t i; -#if 0 - resource_type *rtype; - const struct locale *lang = find_locale("de"); - assert(lang); -#endif for (i = 0; i != MAXITEMS; ++i) { /* item is defined in XML file, but IT_XYZ enum still in use */ @@ -969,9 +967,8 @@ resource_type *r_silver; resource_type *r_aura; resource_type *r_permaura; resource_type *r_unit; -resource_type *r_hp; +static resource_type *r_hp; -resource_type *r_silver; item_type *i_silver; static const char *names[] = { @@ -986,10 +983,9 @@ static const char *names[] = { void init_resources(void) { - static boolean initialized = false; - if (initialized) + if (r_hp) { return; - initialized = true; + } /* silver was never an item: */ r_silver = new_resourcetype(&names[0], NULL, RTF_ITEM | RTF_POOLED); @@ -1199,6 +1195,35 @@ static item *default_spoil(const struct race *rc, int size) return itm; } +#ifndef DISABLE_TESTS +void test_clear_resources(void) +{ + int i; + + for (i=0;i!=IMAXHASH;++i) { + item_type * itype = itemtypes[i]; + if (itype) { + itemtypes[i] = 0; + free(itype->construction); + free(itype); + } + } + + while (resourcetypes) { + resource_type * rtype = resourcetypes; + resourcetypes = rtype->next; + free(rtype->_name[0]); + free(rtype->_name[1]); + free(rtype->_appearance[0]); + free(rtype->_appearance[1]); + free(rtype); + } + resourcetypes = 0; + r_hp = 0; + init_resources(); +} +#endif + void register_resources(void) { register_function((pf_generic) mod_elves_only, "mod_elves_only"); diff --git a/src/kernel/item.h b/src/kernel/item.h index d4ce242f2..b08ff2b35 100644 --- a/src/kernel/item.h +++ b/src/kernel/item.h @@ -273,7 +273,6 @@ extern "C" { extern resource_type *r_aura; extern resource_type *r_permaura; extern resource_type *r_unit; - extern resource_type *r_hp; enum { I_IRON, /* 0 */ @@ -363,6 +362,10 @@ extern "C" { extern struct item_type *i_silver; +#ifndef DISABLE_TESTS + void test_clear_resources(void); +#endif + #ifdef __cplusplus } #endif diff --git a/src/kernel/terrain.h b/src/kernel/terrain.h index fca223e01..355c66fd2 100644 --- a/src/kernel/terrain.h +++ b/src/kernel/terrain.h @@ -28,7 +28,7 @@ extern "C" { #define SEA_REGION (1<<1) /* hier braucht man ein Boot */ #define FOREST_REGION (1<<2) /* Elfen- und Kampfvorteil durch Bäume */ #define ARCTIC_REGION (1<<3) /* Gletscher & co = Keine Insekten! */ -#define CAVALRY_REGION (1<<4) /* Gletscher & co = Keine Insekten! */ +#define CAVALRY_REGION (1<<4) /* riding in combat is possible */ /* Achtung: SEA_REGION ist nicht das Gegenteil von LAND_REGION. Die zwei schliessen sich nichtmal aus! */ #define FORBIDDEN_REGION (1<<5) /* unpassierbare Blockade-struct region */ #define SAIL_INTO (1<<6) /* man darf hierhin segeln */ diff --git a/src/tests.c b/src/tests.c index fa5b6e315..118910c05 100644 --- a/src/tests.c +++ b/src/tests.c @@ -85,6 +85,7 @@ struct unit *test_create_unit(struct faction *f, struct region *r) void test_cleanup(void) { test_clear_terrains(); + test_clear_resources(); global.functions.maintenance = NULL; global.functions.wage = NULL; free_gamedata(); @@ -109,6 +110,17 @@ building * test_create_building(region * r, const building_type * btype) b->size = btype->maxsize>0?btype->maxsize:1; return b; } + +item_type * test_create_itemtype(const char ** names) { + resource_type * rtype; + item_type * itype; + + rtype = new_resourcetype(names, NULL, RTF_ITEM); + itype = new_itemtype(rtype, ITF_ANIMAL|ITF_BIG, 5000, 7000); + + return itype; +} + /** creates a small world and some stuff in it. * two terrains: 'plain' and 'ocean' * one race: 'human' @@ -124,9 +136,16 @@ void test_create_world(void) int i; building_type *btype; ship_type *stype; + item_type * itype; + const char * names[2] = { "horse", "horse_p" }; - t_plain = test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO); + itype = test_create_itemtype(names); + olditemtype[I_HORSE] = itype; + + t_plain = test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION); + t_plain->size = 1000; t_ocean = test_create_terrain("ocean", SEA_REGION | SAIL_INTO | SWIM_INTO); + t_ocean->size = 0; island[0] = test_create_region(0, 0, t_plain); island[1] = test_create_region(1, 0, t_plain); From 813d75f820cbc49cc67c17ab0837b12512789857 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 19 Mar 2011 11:06:03 -0700 Subject: [PATCH 135/400] fixing spy messages (wrong arguments cause crash). --- res/messages.xml | 3 --- src/gamecode/spy.c | 6 +++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/res/messages.xml b/res/messages.xml index 2a678313a..490a4ad96 100644 --- a/res/messages.xml +++ b/res/messages.xml @@ -3561,7 +3561,6 @@ - @@ -3570,7 +3569,6 @@ - @@ -3579,7 +3577,6 @@ - diff --git a/src/gamecode/spy.c b/src/gamecode/spy.c index 4be61f013..e54300826 100644 --- a/src/gamecode/spy.c +++ b/src/gamecode/spy.c @@ -66,7 +66,7 @@ void spy_message(int spy, const unit * u, const unit * target) sc_mage *mage = get_mage(target); /* bei Magiern Zaubersprüche und Magiegebiet */ if (mage) { - ADDMSG(&u->faction->msgs, msg_message("spyreport_mage", "target type", u, + ADDMSG(&u->faction->msgs, msg_message("spyreport_mage", "target type", target, magic_school[mage->magietyp])); } } @@ -102,12 +102,12 @@ void spy_message(int spy, const unit * u, const unit * target) } } if (found) { - ADDMSG(&u->faction->msgs, msg_message("spyreport_skills", "target skills", u, + ADDMSG(&u->faction->msgs, msg_message("spyreport_skills", "target skills", target, buf)); } if (target->items) { - ADDMSG(&u->faction->msgs, msg_message("spyreport_items", "target items", u, + ADDMSG(&u->faction->msgs, msg_message("spyreport_items", "target items", target, target->items)); } } From e7ab2b46ad6e631cf1a6422e362b432510da6f85 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 27 Mar 2011 21:05:22 +0200 Subject: [PATCH 136/400] do not assert on rich units, warn instead --- src/kernel/pool.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/kernel/pool.c b/src/kernel/pool.c index 9eb7b7ca1..4d280d4ef 100644 --- a/src/kernel/pool.c +++ b/src/kernel/pool.c @@ -79,7 +79,10 @@ int change_resource(unit * u, const resource_type * rtype, int change) i = change_maxspellpoints(u, change); else assert(!"undefined resource detected. rtype->uchange not initialized."); - assert(i >= 0 && (i < 100000000)); /* soft test to catch mischief */ + assert(i >= 0); + if (i >= 100000000) { + log_warning(("%s has %d %s\n", unitname(u), i, rtype->_name[0])); + } return i; } From 28a1e8d3cc6a746ff19e5c29805f7d4a1010ccd1 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 24 Apr 2011 11:42:19 -0700 Subject: [PATCH 137/400] E3 rule for dwarf castles should not be default. --- src/kernel/building.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/building.c b/src/kernel/building.c index f26e153bf..e0dd53908 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -576,7 +576,7 @@ int bt_effsize(const building_type * btype, const building * b, int bsize) const construction *cons = btype->construction; /* TECH DEBT: simplest thing that works for E3 dwarf/halfling faction rules */ - if (b && get_param_int(global.parameters, "rules.dwarf_castles", 1) + if (b && get_param_int(global.parameters, "rules.dwarf_castles", 0) && strcmp(btype->_name, "castle") == 0) { unit *u = building_owner(b); if (u && u->faction->race == new_race[RC_HALFLING]) { From ec9e7bf833c3aba3063a278b4e062eb6442d062a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 24 Apr 2011 12:19:34 -0700 Subject: [PATCH 138/400] new lighthouse behavior as described in http://bugs.eressea.de/view.php?id=1847 --- scripts/tests/common.lua | 27 +++++++++++++++++++++++ src/kernel/reports.c | 47 ++++++++++++++++++++++------------------ 2 files changed, 53 insertions(+), 21 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 35f0101bd..fd7a92a32 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -864,6 +864,33 @@ function test_coordinates_noname_plane() assert_true(find_in_report(f, r.name .. " %(0,0%), Berg")) end +function test_lighthouse() + local r = region.create(0, 0, "mountain") + local f = faction.create("noreply@eressea.de", "human", "de") + region.create(1, 0, "mountain") + region.create(2, 0, "ocean") + region.create(0, 1, "firewall") + region.create(3, 0, "mountain") + region.create(4, 0, "plain") + local u = unit.create(f, r, 1) + local b = building.create(r, "lighthouse") + b.size = 100 + u.building = b + u:set_skill("perception", 9) + u:add_item("money", 1000) + assert_not_nil(b) + + init_reports() + write_report(f) + assert_true(find_in_report(f, " %(1,0%) %(vom Turm erblickt%)")) + assert_true(find_in_report(f, " %(2,0%) %(vom Turm erblickt%)")) + assert_true(find_in_report(f, " %(3,0%) %(vom Turm erblickt%)")) + + assert_false(find_in_report(f, " %(0,0%) %(vom Turm erblickt%)")) + assert_false(find_in_report(f, " %(0,1%) %(vom Turm erblickt%)")) + assert_false(find_in_report(f, " %(4,0%) %(vom Turm erblickt%)")) +end + module("tests.parser", package.seeall, lunit.testcase) function setup() diff --git a/src/kernel/reports.c b/src/kernel/reports.c index 219660ca7..75b0905e0 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -1373,14 +1373,37 @@ static void view_regatta(struct seen_region **seen, region * r, faction * f) recurse_regatta(seen, r, r, f, skill / 2); } +static void prepare_lighthouse(building * b, faction * f) +{ + int range = lighthouse_range(b, f); + region_list *rlist = get_regions_distance(b->region, range); + region_list *rp = rlist; + + while (rp) { + region *rl = rp->data; + if (!fval(rl->terrain, FORBIDDEN_REGION)) { + int d; + add_seen(f->seen, rl, see_lighthouse, false); + for (d = 0; d != MAXDIRECTIONS; ++d) { + region *rn = rconnect(rl, d); + if (rn != NULL) { + add_seen(f->seen, rn, see_neighbour, false); + } + } + } + rp = rp->next; + } + free_regionlist(rlist); +} + static void prepare_reports(void) { region *r; faction *f; static const struct building_type *bt_lighthouse = NULL; - if (bt_lighthouse == NULL) + if (bt_lighthouse == NULL) { bt_lighthouse = bt_find("lighthouse"); - + } for (f = factions; f; f = f->next) { if (f->seen) seen_done(f->seen); @@ -1407,25 +1430,7 @@ static void prepare_reports(void) for (u = r->units; u; u = u->next) { if (u->building && u->building->type == bt_lighthouse) { /* we are in a lighthouse. add the regions we can see from here! */ - int range = lighthouse_range(u->building, u->faction); - region_list *rlist = get_regions_distance(r, range); - region_list *rp = rlist; - - while (rp) { - region *rl = rp->data; - if (fval(rl->terrain, SEA_REGION)) { - direction_t d; - add_seen(u->faction->seen, rl, see_lighthouse, false); - for (d = 0; d != MAXDIRECTIONS; ++d) { - region *rn = rconnect(rl, d); - if (rn != NULL) { - add_seen(u->faction->seen, rn, see_neighbour, false); - } - } - } - rp = rp->next; - } - free_regionlist(rlist); + prepare_lighthouse(u->building, u->faction); } if (u->race != new_race[RC_SPELL] || u->number == RS_FARVISION) { From 9802eecd7912a6ecc03af94d44cedb6eb80fedb8 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 24 Apr 2011 16:18:01 -0700 Subject: [PATCH 139/400] code prettyfication --- src/kernel/move.c | 2 +- src/kernel/reports.c | 27 +++++++++++++++++---------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/kernel/move.c b/src/kernel/move.c index 11aa94f86..6abfac711 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -101,7 +101,7 @@ get_followers(unit * target, region * r, const region_list * route_end, if (fval(uf, UFL_FOLLOWING) && !fval(uf, UFL_NOTMOVING)) { const attrib *a = a_findc(uf->attribs, &at_follow); if (a && a->data.v == target) { - follower *fnew = malloc(sizeof(follower)); + follower *fnew = (follower *)malloc(sizeof(follower)); fnew->uf = uf; fnew->ut = target; fnew->route_end = route_end; diff --git a/src/kernel/reports.c b/src/kernel/reports.c index 75b0905e0..4648a1d11 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -1243,7 +1243,7 @@ static report_type *report_types; void register_reporttype(const char *extension, report_fun write, int flag) { - report_type *type = malloc(sizeof(report_type)); + report_type *type = (report_type *)malloc(sizeof(report_type)); type->extension = extension; type->write = write; type->flag = flag; @@ -1259,7 +1259,8 @@ static region_list *get_regions_distance(region * root, int radius) fset(root, RF_MARK); while (*rp) { region_list *r = *rp; - direction_t d; + int d; + rp = &r->next; for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r->data, d); @@ -1277,7 +1278,7 @@ static region_list *get_regions_distance(region * root, int radius) static void view_default(struct seen_region **seen, region * r, faction * f) { - direction_t dir; + int dir; for (dir = 0; dir != MAXDIRECTIONS; ++dir) { region *r2 = rconnect(r, dir); if (r2) { @@ -1295,9 +1296,12 @@ static void view_default(struct seen_region **seen, region * r, faction * f) static void view_neighbours(struct seen_region **seen, region * r, faction * f) { - direction_t dir; - for (dir = 0; dir != MAXDIRECTIONS; ++dir) { - region *r2 = rconnect(r, dir); + int d; + region * nb[MAXDIRECTIONS]; + + get_neighbours(r, nb); + for (d = 0; d != MAXDIRECTIONS; ++d) { + region *r2 = nb[d]; if (r2) { connection *b = get_borders(r, r2); while (b) { @@ -1308,7 +1312,7 @@ static void view_neighbours(struct seen_region **seen, region * r, faction * f) if (!b) { if (add_seen(seen, r2, see_far, false)) { if (!(fval(r2->terrain, FORBIDDEN_REGION))) { - direction_t dir; + int dir; for (dir = 0; dir != MAXDIRECTIONS; ++dir) { region *r3 = rconnect(r2, dir); if (r3) { @@ -1333,10 +1337,13 @@ static void recurse_regatta(struct seen_region **seen, region * center, region * r, faction * f, int maxdist) { - direction_t dir; + int d; int dist = distance(center, r); - for (dir = 0; dir != MAXDIRECTIONS; ++dir) { - region *r2 = rconnect(r, dir); + region * nb[MAXDIRECTIONS]; + + get_neighbours(r, nb); + for (d = 0; d != MAXDIRECTIONS; ++d) { + region *r2 = nb[d]; if (r2) { int ndist = distance(center, r2); if (ndist > dist && fval(r2->terrain, SEA_REGION)) { From dbd338c284c63d2aebe134e4f4ec0c64f8717a72 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 25 Apr 2011 22:20:01 -0700 Subject: [PATCH 140/400] eliminate region_list usage from the monster pathfinder --- src/kernel/battle.c | 2 +- src/kernel/pathfinder.c | 9 +++++---- src/kernel/pathfinder.h | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/kernel/battle.c b/src/kernel/battle.c index 5e8e83cda..22781c80d 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -1761,7 +1761,7 @@ void do_combatmagic(battle * b, combatmagic_t was) if (power <= 0) { /* Effekt von Antimagie */ report_failed_spell(b, mage, sp); pay_spell(mage, sp, level, 1); - } else if (fumble(r, mage, sp, sp->level) == true) { + } else if (fumble(r, mage, sp, sp->level)) { report_failed_spell(b, mage, sp); pay_spell(mage, sp, level, 1); } else { diff --git a/src/kernel/pathfinder.c b/src/kernel/pathfinder.c index 26b4f62db..97cea3b98 100644 --- a/src/kernel/pathfinder.c +++ b/src/kernel/pathfinder.c @@ -18,6 +18,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +#include #include "pathfinder.h" #include "region.h" @@ -98,10 +99,10 @@ static void free_nodes(node * root) } } -struct region_list *regions_in_range(struct region *start, int maxdist, +struct quicklist *regions_in_range(struct region *start, int maxdist, boolean(*allowed) (const struct region *, const struct region *)) { - region_list *rlist = NULL; + quicklist * rlist = NULL; node *root = new_node(start, 0, NULL); node **end = &root->next; node *n = root; @@ -109,7 +110,7 @@ struct region_list *regions_in_range(struct region *start, int maxdist, while (n != NULL) { region *r = n->r; int depth = n->distance + 1; - direction_t d; + int d; if (n->distance >= maxdist) break; @@ -123,7 +124,7 @@ struct region_list *regions_in_range(struct region *start, int maxdist, continue; /* can't go there */ /* add the region to the list of available ones. */ - add_regionlist(&rlist, rn); + ql_push(&rlist, rn); /* make sure we don't go here again, and put the region into the set for further BFS'ing */ diff --git a/src/kernel/pathfinder.h b/src/kernel/pathfinder.h index 63f50b7d9..ac372dc34 100644 --- a/src/kernel/pathfinder.h +++ b/src/kernel/pathfinder.h @@ -39,7 +39,7 @@ extern "C" { const struct region *target); extern boolean allowed_walk(const struct region *src, const struct region *target); - extern struct region_list *regions_in_range(struct region *src, int maxdist, + extern struct quicklist *regions_in_range(struct region *src, int maxdist, boolean(*allowed) (const struct region *, const struct region *)); extern void pathfinder_cleanup(void); From c4cc06a80f57aac2a48bc16087b2962789ab2d9e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 25 Apr 2011 22:30:54 -0700 Subject: [PATCH 141/400] get_regions_distance converted to quicklist --- src/kernel/reports.c | 54 ++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/src/kernel/reports.c b/src/kernel/reports.c index 4648a1d11..c723124c7 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -1251,27 +1251,32 @@ void register_reporttype(const char *extension, report_fun write, int flag) report_types = type; } -static region_list *get_regions_distance(region * root, int radius) +static quicklist *get_regions_distance(region * root, int radius) { - region_list *rptr, *rlist = NULL; - region_list **rp = &rlist; - add_regionlist(rp, root); - fset(root, RF_MARK); - while (*rp) { - region_list *r = *rp; - int d; + quicklist *ql, *rlist = NULL; + int qi = 0; + + ql_push(&rlist, root); + fset(root, RF_MARK); + ql = rlist; + + while (ql) { + region *r = (region *)ql_get(ql, qi); + region * next[MAXDIRECTIONS]; + int d; + get_neighbours(r, next); - rp = &r->next; for (d = 0; d != MAXDIRECTIONS; ++d) { - region *rn = rconnect(r->data, d); - if (rn != NULL && !fval(rn, RF_MARK) && distance(rn, root) <= radius) { - add_regionlist(rp, rn); - fset(rn, RF_MARK); + if (next[d] && !fval(next[d], RF_MARK) && distance(next[d], root) <= radius) { + ql_push(&rlist, next[d]); + fset(next[d], RF_MARK); } } + ql_advance(&ql, &qi, 1); } - for (rptr = rlist; rptr; rptr = rptr->next) { - freset(rptr->data, RF_MARK); + for (ql=rlist,qi=0;ql;ql_advance(&ql, &qi, 1)) { + region *r = (region *)ql_get(ql, qi); + freset(r, RF_MARK); } return rlist; } @@ -1383,24 +1388,25 @@ static void view_regatta(struct seen_region **seen, region * r, faction * f) static void prepare_lighthouse(building * b, faction * f) { int range = lighthouse_range(b, f); - region_list *rlist = get_regions_distance(b->region, range); - region_list *rp = rlist; + quicklist *ql, *rlist = get_regions_distance(b->region, range); + int qi; - while (rp) { - region *rl = rp->data; + for (ql=rlist,qi=0;ql;ql_advance(&ql, &qi,1)) { + region *rl = (region *)ql_get(ql, qi); if (!fval(rl->terrain, FORBIDDEN_REGION)) { + region * next[MAXDIRECTIONS]; int d; + + get_neighbours(rl, next); add_seen(f->seen, rl, see_lighthouse, false); for (d = 0; d != MAXDIRECTIONS; ++d) { - region *rn = rconnect(rl, d); - if (rn != NULL) { - add_seen(f->seen, rn, see_neighbour, false); + if (next[d]) { + add_seen(f->seen, next[d], see_neighbour, false); } } } - rp = rp->next; } - free_regionlist(rlist); + ql_free(rlist); } static void prepare_reports(void) From 6798c497f81a771a23d7e390368c8f372be5b62e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 26 Apr 2011 21:22:30 -0700 Subject: [PATCH 142/400] eliminated region_list use from get_island --- src/modules/autoseed.c | 56 ++++++++++++++++++++++-------------------- src/modules/autoseed.h | 1 - 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c index dc8013e29..0e87db8c0 100644 --- a/src/modules/autoseed.c +++ b/src/modules/autoseed.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -364,35 +365,35 @@ static boolean virgin_region(const region * r) return true; } -void get_island(region * root, region_list ** rlist) +static quicklist * get_island(region * root) { - region_list **rnext = rlist; - while (*rnext) - rnext = &(*rnext)->next; + quicklist * ql, * result = 0; + int qi = 0; fset(root, RF_MARK); - add_regionlist(rnext, root); + ql_push(&result, root); - while (*rnext) { - direction_t dir; + for (ql=result,qi=0; ql; ql_advance(&ql, &qi, 1)) { + int dir; + region *r = (region *)ql_get(ql, qi); + region * next[MAXDIRECTIONS]; - region *rcurrent = (*rnext)->data; - rnext = &(*rnext)->next; + get_neighbours(r, next); for (dir = 0; dir != MAXDIRECTIONS; ++dir) { - region *r = rconnect(rcurrent, dir); - if (r != NULL && r->land && !fval(r, RF_MARK)) { - fset(r, RF_MARK); - add_regionlist(rnext, r); + region *rn = next[dir]; + if (rn != NULL && rn->land && !fval(rn, RF_MARK)) { + fset(rn, RF_MARK); + ql_push(&result, rn); } } } - rnext = rlist; - while (*rnext) { - region_list *rptr = *rnext; - freset(rptr->data, RF_MARK); - rnext = &rptr->next; + + for (ql=result,qi=0; ql; ql_advance(&ql, &qi, 1)) { + region *r = (region *)ql_get(ql, qi); + freset(r, RF_MARK); } + return result; } static void @@ -405,7 +406,7 @@ get_island_info(region * root, int *size_p, int *inhabited_p, int *maxage_p) island = rlist; fset(root, RF_MARK); while (rlist) { - direction_t d; + int d; region *r = rlist->data; if (r->units) { unit *u; @@ -572,11 +573,12 @@ int autoseed(newfaction ** players, int nsize, int max_agediff) } } if (rmin != NULL) { - region_list *rlist = NULL, *rptr; faction *f; - get_island(rmin, &rlist); - for (rptr = rlist; rptr; rptr = rptr->next) { - region *r = rlist->data; + quicklist *ql, *rlist = get_island(rmin); + int qi; + + for (ql=rlist,qi=0;ql;ql_advance(&ql, &qi, 1)) { + region *r = (region *)ql_get(ql, qi); unit *u; for (u = r->units; u; u = u->next) { f = u->faction; @@ -586,10 +588,12 @@ int autoseed(newfaction ** players, int nsize, int max_agediff) } } } - free_regionlist(rlist); - if (psize > 0) - for (f = factions; f; f = f->next) + ql_free(rlist); + if (psize > 0) { + for (f = factions; f; f = f->next) { freset(f, FFL_MARK); + } + } if (psize < PLAYERS_PER_ISLAND) { r = rmin; } diff --git a/src/modules/autoseed.h b/src/modules/autoseed.h index f5b38b01c..71bf68152 100644 --- a/src/modules/autoseed.h +++ b/src/modules/autoseed.h @@ -36,7 +36,6 @@ extern "C" { extern int autoseed(newfaction ** players, int nsize, int max_agediff); extern newfaction *read_newfactions(const char *filename); - extern void get_island(struct region *root, struct region_list **rlist); extern int fix_demand(struct region *r); extern const struct terrain_type *random_terrain(const struct terrain_type *terrains[], int distribution[], int size); From f00f5373363a8773f0f8dbdb0836a5c42cf78a3f Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 26 Apr 2011 21:25:47 -0700 Subject: [PATCH 143/400] eliminated region_list use from get_island_info --- src/modules/autoseed.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c index 0e87db8c0..22906eba2 100644 --- a/src/modules/autoseed.c +++ b/src/modules/autoseed.c @@ -399,15 +399,15 @@ static quicklist * get_island(region * root) static void get_island_info(region * root, int *size_p, int *inhabited_p, int *maxage_p) { - int size = 0, maxage = 0, inhabited = 0; - region_list *rlist = NULL; - region_list *island = NULL; - add_regionlist(&rlist, root); - island = rlist; + int qi, size = 0, maxage = 0, inhabited = 0; + quicklist *ql, *island = NULL; + + ql_push(&island, root); fset(root, RF_MARK); - while (rlist) { + + for (ql=island,qi=0; ql; ql_advance(&ql, &qi, 1)) { int d; - region *r = rlist->data; + region *r = (region *)ql_get(ql, qi); if (r->units) { unit *u; for (u = r->units; u; u = u->next) { @@ -421,19 +421,16 @@ get_island_info(region * root, int *size_p, int *inhabited_p, int *maxage_p) for (d = 0; d != MAXDIRECTIONS; ++d) { region *rn = rconnect(r, d); if (rn && !fval(rn, RF_MARK) && rn->land) { - region_list *rnew = malloc(sizeof(region_list)); - rnew->data = rn; - rnew->next = rlist->next; - rlist->next = rnew; + ql_push(&island, rn); fset(rn, RF_MARK); } } - rlist = rlist->next; } - for (rlist = island; rlist; rlist = rlist->next) { - freset(rlist->data, RF_MARK); + for (ql=island,qi=0; ql; ql_advance(&ql, &qi, 1)) { + region *r = (region *)ql_get(ql, qi); + freset(r, RF_MARK); } - free_regionlist(island); + ql_free(island); if (size_p) *size_p = size; if (inhabited_p) From 3abcbb4717cf25495fe06993ebb08aee5bc4e137 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 26 Apr 2011 21:30:06 -0700 Subject: [PATCH 144/400] eliminated region_list use from wormholes fixed a small memory leak --- src/modules/autoseed.h | 1 - src/modules/wormhole.c | 21 +++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/modules/autoseed.h b/src/modules/autoseed.h index 71bf68152..254608803 100644 --- a/src/modules/autoseed.h +++ b/src/modules/autoseed.h @@ -16,7 +16,6 @@ extern "C" { #endif - struct region_list; struct newfaction; typedef struct newfaction { diff --git a/src/modules/wormhole.c b/src/modules/wormhole.c index 4553d46b9..e606eab2f 100644 --- a/src/modules/wormhole.c +++ b/src/modules/wormhole.c @@ -27,9 +27,10 @@ /* util includes */ #include -#include -#include #include +#include +#include +#include #include /* libc includes */ @@ -175,9 +176,9 @@ void create_wormholes(void) { #define WORMHOLE_CHANCE 10000 const building_type *bt_wormhole = bt_find("wormhole"); - region_list *rptr, *rlist = NULL; + quicklist *ql, *rlist = 0; region *r = regions; - int i = 0, count = 0; + int qi, i = 0, count = 0; region **match; if (bt_wormhole == NULL) @@ -195,7 +196,7 @@ void create_wormholes(void) } if (r == NULL) break; - add_regionlist(&rlist, r); + ql_push(&rlist, r); ++count; r = r->next; } @@ -204,18 +205,18 @@ void create_wormholes(void) return; match = (region **) malloc(sizeof(region *) * count); - rptr = rlist; - while (i != count) { - match[i++] = rptr->data; - rptr = rptr->next; + + for (ql = rlist,qi = 0; i != count; ql_advance(&ql, &qi, 1)) { + match[i++] = (region *)ql_get(ql, qi); } qsort(match, count, sizeof(region *), cmp_age); - free_regionlist(rlist); + ql_free(rlist); count /= 2; for (i = 0; i != count; ++i) { make_wormhole(bt_wormhole, match[i], match[i + count]); } + free(match); } void register_wormholes(void) From ae02ef5caf9bfa5759ae3b7f5997a230ba967664 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 27 Apr 2011 06:39:56 +0200 Subject: [PATCH 145/400] fixed wrong skill name --- res/equipment.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/equipment.xml b/res/equipment.xml index 935de5806..a38004797 100644 --- a/res/equipment.xml +++ b/res/equipment.xml @@ -289,7 +289,7 @@ - + From 17d339b196601cb172df9e3f457f854d5e150f67 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 29 Apr 2011 21:50:12 -0700 Subject: [PATCH 146/400] http://bugs.eressea.de/view.php?id=1851 spy messages have too many arguments --- src/gamecode/spy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gamecode/spy.c b/src/gamecode/spy.c index e54300826..286a5c107 100644 --- a/src/gamecode/spy.c +++ b/src/gamecode/spy.c @@ -75,7 +75,7 @@ void spy_message(int spy, const unit * u, const unit * target) if (fv && fv != target->faction) { /* wahre Partei */ ADDMSG(&u->faction->msgs, msg_message("spyreport_faction", - "target faction", u, target, target->faction)); + "target faction", target, target->faction)); ql_set_insert(&u->faction->seen_factions, target->faction); } } @@ -94,10 +94,10 @@ void spy_message(int spy, const unit * u, const unit * target) } else { strncat(buf, ", ", sizeof(buf)); } - strncat(buf, (const char *)skillname(sv->id, u->faction->locale), + strncat(buf, (const char *)skillname((skill_t)sv->id, u->faction->locale), sizeof(buf)); strncat(buf, " ", sizeof(buf)); - strncat(buf, itoa10(eff_skill(target, sv->id, target->region)), + strncat(buf, itoa10(eff_skill(target, (skill_t)sv->id, target->region)), sizeof(buf)); } } From 817f396467b08a300f8d0b39f6237f76c96a136e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 29 Apr 2011 22:49:29 -0700 Subject: [PATCH 147/400] http://bugs.eressea.de/view.php?id=1844 Only use potions that we have the resources for. --- src/kernel/alchemy.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/kernel/alchemy.c b/src/kernel/alchemy.c index 3fff02206..1ee2daa9b 100644 --- a/src/kernel/alchemy.c +++ b/src/kernel/alchemy.c @@ -120,7 +120,7 @@ static void end_potion(unit * u, const potion_type * ptype, int amount) "unit potion", u, ptype->itype->rtype)); } -void do_potion(unit * u, const potion_type * ptype, int amount) +static int do_potion(unit * u, const potion_type * ptype, int amount) { if (ptype == oldpotiontype[P_LIFE]) { region *r = u->region; @@ -175,6 +175,7 @@ void do_potion(unit * u, const potion_type * ptype, int amount) } else { change_effect(u, ptype, 10 * amount); } + return amount; } int use_potion(unit * u, const item_type * itype, int amount, struct order *ord) @@ -187,7 +188,7 @@ int use_potion(unit * u, const item_type * itype, int amount, struct order *ord) int result = begin_potion(u, ptype, ord); if (result) return result; - do_potion(u, ptype, amount); + amount = do_potion(u, ptype, amount); end_potion(u, ptype, amount); } return 0; @@ -212,7 +213,7 @@ static void free_potiondelay(attrib * a) static int age_potiondelay(attrib * a) { potiondelay *pd = (potiondelay *) a->data.v; - do_potion(pd->u, pd->ptype, pd->amount); + pd->amount = do_potion(pd->u, pd->ptype, pd->amount); return AT_AGE_REMOVE; } From a2816f1528c822708ff2b331fced0c2c926d280f Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 2 May 2011 23:27:39 -0700 Subject: [PATCH 148/400] fix_familiars had a bug caused by quicklist --- src/kernel/equipment.c | 14 ++++++-------- src/util/quicklist.c | 10 +++++----- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index 150a70e65..bf3c354b2 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -142,15 +142,13 @@ void equip_unit_mask(struct unit *u, const struct equipment *eq, int mask) if (mask & EQUIP_SPELLS) { quicklist *ql = eq->spells; if (ql) { + int qi; sc_mage *m = get_mage(u); - if (m == NULL) { - assert(!"trying to equip spells on a non-mage!"); - } else { - int qi; - for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { - spell *sp = (spell *) ql_get(ql, qi); - add_spell(get_spelllist(m, u->faction), sp); - } + + assert(m || !"trying to equip spells on a non-mage!"); + for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { + spell *sp = (spell *) ql_get(ql, qi); + add_spell(&m->spells, sp); } } } diff --git a/src/util/quicklist.c b/src/util/quicklist.c index 42941f086..81bad276b 100644 --- a/src/util/quicklist.c +++ b/src/util/quicklist.c @@ -20,7 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #define QL_MAXSIZE 14 /* total struct is 64 bytes */ -#define QL_LIMIT 8 +#define QL_LIMIT 7 struct quicklist { struct quicklist *next; @@ -89,7 +89,7 @@ int ql_delete(quicklist ** qlp, int index) if (ql->num_elements == 0) { *qlp = ql->next; free(ql); - } else if (ql->next && ql->num_elements < QL_LIMIT) { + } else if (ql->next && ql->num_elements <= QL_LIMIT) { quicklist *qn = ql->next; if (ql->num_elements + qn->num_elements > QL_MAXSIZE) { memcpy(ql->elements + ql->num_elements, qn->elements, sizeof(void *)); @@ -124,10 +124,10 @@ int ql_insert(quicklist ** qlp, int index, void *data) quicklist *qn = (quicklist *) malloc(sizeof(quicklist)); qn->next = ql->next; ql->next = qn; - qn->num_elements = QL_LIMIT; - ql->num_elements -= QL_LIMIT; + qn->num_elements = ql->num_elements-QL_LIMIT; + ql->num_elements = QL_LIMIT; memcpy(qn->elements, ql->elements + ql->num_elements, - QL_LIMIT * sizeof(void *)); + qn->num_elements * sizeof(void *)); if (index <= ql->num_elements) { return ql_insert(qlp, index, data); } else { From 58208e0db57cab6c308852dad26dd00109de62cc Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 2 May 2011 23:34:35 -0700 Subject: [PATCH 149/400] Improve sailing messages to include the region. http://bugs.eressea.de/view.php?id=1729 --- res/messages.xml | 7 ++++--- src/kernel/move.c | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/res/messages.xml b/res/messages.xml index 490a4ad96..8db9c6fbf 100644 --- a/res/messages.xml +++ b/res/messages.xml @@ -2949,10 +2949,11 @@ + - "Die Mannschaft der $ship($ship) kann in letzter Sekunde verhindern, dass das Schiff auf Land aufläuft." - "In the very last moment, the crew of the $ship($ship) saved the ship from grounding." - "In the very last moment, the crew of the $ship($ship) saved the ship from grounding." + "Die Mannschaft der $ship($ship) kann in letzter Sekunde verhindern, dass das Schiff in $region($region) auf Land aufläuft." + "In the very last moment, the crew of the $ship($ship) saved the ship from grounding in $region($region)." + "In the very last moment, the crew of the $ship($ship) saved the ship from grounding in $region($region)." diff --git a/src/kernel/move.c b/src/kernel/move.c index 6abfac711..b22420224 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -1820,7 +1820,7 @@ sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) if (reason<0) { /* for some reason or another, we aren't allowed in there.. */ if (check_leuchtturm(current_point, NULL) || reason == SA_NO_INSECT) { - ADDMSG(&f->msgs, msg_message("sailnolandingstorm", "ship", sh)); + ADDMSG(&f->msgs, msg_message("sailnolandingstorm", "ship region", sh, next_point)); } else { float dmg = get_param_flt(global.parameters, "rules.ship.damage.nolanding", From ae4ca137586c6ead487aeb67ef47d627139af91c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 9 May 2011 21:37:40 -0700 Subject: [PATCH 150/400] fix an English error message. --- res/messages.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/messages.xml b/res/messages.xml index 8db9c6fbf..354209ceb 100644 --- a/res/messages.xml +++ b/res/messages.xml @@ -2354,7 +2354,7 @@ "$unit($unit) schafft es nicht, genug Kraft aufzubringen, um $spell($spell) auf Stufe $int($level) zu zaubern." - "$unit($unit) cannot muster enough energy to cast $spell($spell) on level $level($level)." + "$unit($unit) cannot muster enough energy to cast $spell($spell) on level $int($level)." From d4310b1b5177618306933ec00c81f5caa69b0b99 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 15 May 2011 15:01:09 -0700 Subject: [PATCH 151/400] bad magic resistance zone implemented. this fixes http://bugs.eressea.de/view.php?id=1854 --- src/kernel/magic.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/kernel/magic.c b/src/kernel/magic.c index fdc206731..9cad61cb1 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -1128,6 +1128,7 @@ double magic_resistance(unit * target) attrib *a; curse *c; int n; + const curse_type * ct_goodresist = 0, * ct_badresist = 0; /* Bonus durch Rassenmagieresistenz */ double probability = target->race->magres; @@ -1149,21 +1150,24 @@ double magic_resistance(unit * target) /* Auswirkungen von Zaubern auf der Region */ a = a_find(target->region->attribs, &at_curse); + if (a) { + ct_badresist = ct_find("badmagicresistancezone"); + ct_goodresist = ct_find("goodmagicresistancezone"); + } while (a && a->type == &at_curse) { curse *c = (curse *) a->data.v; unit *mage = c->magician; if (mage != NULL) { - if (c->type == ct_find("goodmagicresistancezone")) { + if (ct_goodresist && c->type == ct_goodresist) { if (alliedunit(mage, target->faction, HELP_GUARD)) { probability += curse_geteffect(c) * 0.01; - break; + ct_goodresist = 0; /* only one effect per region */ } - } else if (c->type == ct_find("badmagicresistancezone")) { + } else if (ct_badresist && c->type == ct_badresist) { if (alliedunit(mage, target->faction, HELP_GUARD)) { - /* TODO: hier sollte doch sicher was passieren? */ - a = a->next; - continue; + probability -= curse_geteffect(c) * 0.01; + ct_badresist = 0; /* only one effect per region */ } } } From 2aa3acf56aae1d17efa183cb1ce0a0ceb864e8de Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 4 Jun 2011 18:37:02 +0200 Subject: [PATCH 152/400] do not crash when terraforming land regions with road in them (oceans cannot have roads) --- src/gamecode/creport.c | 2 +- src/kernel/region.c | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index 4a0e767c8..154ceab55 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -1113,7 +1113,7 @@ cr_borders(seen_region ** seen, const region * r, const faction * f, if (!b->type->transparent(b, f)) fputs("1;opaque\n", F); /* hack: */ - if (b->type == &bt_road) { + if (b->type == &bt_road && r->terrain->max_road) { int p = rroad(r, d) * 100 / r->terrain->max_road; fprintf(F, "%d;prozent\n", p); } diff --git a/src/kernel/region.c b/src/kernel/region.c index aea63223f..2b96e4baa 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -773,17 +773,22 @@ void rsetroad(region * r, direction_t d, short val) connection *b; region *r2 = rconnect(r, d); - if (!r2) + if (!r2) { return; + } b = get_borders(r, r2); - while (b && b->type != &bt_road) + while (b && b->type != &bt_road) { b = b->next; - if (!b) + } + if (!b) { + if (!val) return; b = new_border(&bt_road, r, r2); - if (r == b->from) + } + if (r == b->from) { b->data.sa[0] = val; - else + } else { b->data.sa[1] = val; + } } short rroad(const region * r, direction_t d) @@ -1236,6 +1241,10 @@ void terraform_region(region * r, const terrain_type * terrain) } if (r->land) { + int d; + for (d=0;d!=MAXDIRECTIONS;++d) { + rsetroad(r, d, 0); + } i_freeall(&r->land->items); } else { static struct surround { From cc870c076c0da0be277d413d0488c4255a55e866 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 4 Jun 2011 11:19:44 -0700 Subject: [PATCH 153/400] http://bugs.eressea.de/view.php?id=1855 fixing delayed-action potions. --- src/kernel/alchemy.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/kernel/alchemy.c b/src/kernel/alchemy.c index 1ee2daa9b..6c9963007 100644 --- a/src/kernel/alchemy.c +++ b/src/kernel/alchemy.c @@ -120,10 +120,9 @@ static void end_potion(unit * u, const potion_type * ptype, int amount) "unit potion", u, ptype->itype->rtype)); } -static int do_potion(unit * u, const potion_type * ptype, int amount) +static int do_potion(unit * u, region *r, const potion_type * ptype, int amount) { if (ptype == oldpotiontype[P_LIFE]) { - region *r = u->region; int holz = 0; static int tree_type = -1; static int tree_count = -1; @@ -155,13 +154,11 @@ static int do_potion(unit * u, const potion_type * ptype, int amount) } else if (ptype == oldpotiontype[P_HEILWASSER]) { u->hp = MIN(unit_max_hp(u) * u->number, u->hp + 400 * amount); } else if (ptype == oldpotiontype[P_PEOPLE]) { - region *r = u->region; attrib *a = (attrib *) a_find(r->attribs, &at_peasantluck); if (!a) a = a_add(&r->attribs, a_new(&at_peasantluck)); a->data.i += amount; } else if (ptype == oldpotiontype[P_HORSE]) { - region *r = u->region; attrib *a = (attrib *) a_find(r->attribs, &at_horseluck); if (!a) a = a_add(&r->attribs, a_new(&at_horseluck)); @@ -188,7 +185,7 @@ int use_potion(unit * u, const item_type * itype, int amount, struct order *ord) int result = begin_potion(u, ptype, ord); if (result) return result; - amount = do_potion(u, ptype, amount); + amount = do_potion(u, u->region, ptype, amount); end_potion(u, ptype, amount); } return 0; @@ -196,6 +193,7 @@ int use_potion(unit * u, const item_type * itype, int amount, struct order *ord) typedef struct potiondelay { unit *u; + region *r; const potion_type *ptype; int amount; } potiondelay; @@ -213,7 +211,7 @@ static void free_potiondelay(attrib * a) static int age_potiondelay(attrib * a) { potiondelay *pd = (potiondelay *) a->data.v; - pd->amount = do_potion(pd->u, pd->ptype, pd->amount); + pd->amount = do_potion(pd->u, pd->r, pd->ptype, pd->amount); return AT_AGE_REMOVE; } @@ -233,6 +231,7 @@ static attrib *make_potiondelay(unit * u, const potion_type * ptype, int amount) attrib *a = a_new(&at_potiondelay); potiondelay *pd = (potiondelay *) a->data.v; pd->u = u; + pd->r = u->region; pd->ptype = ptype; pd->amount = amount; return a; From 21b8ab2d3120ea2c1243acdc0efb17758e7a8527 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 5 Jun 2011 12:21:49 -0700 Subject: [PATCH 154/400] be nice to your friends, but not your enemies --- src/kernel/magic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 9cad61cb1..50c9d579b 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -1165,7 +1165,7 @@ double magic_resistance(unit * target) ct_goodresist = 0; /* only one effect per region */ } } else if (ct_badresist && c->type == ct_badresist) { - if (alliedunit(mage, target->faction, HELP_GUARD)) { + if (!alliedunit(mage, target->faction, HELP_GUARD)) { probability -= curse_geteffect(c) * 0.01; ct_badresist = 0; /* only one effect per region */ } From edfa266a3284598c3e1364f35e93b1301a83775d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 6 Aug 2011 13:56:46 -0700 Subject: [PATCH 155/400] Fix a crash in turn 733: alps sometimes have weird messages (also, unitmessage is dumb) --- src/triggers/unitmessage.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/triggers/unitmessage.c b/src/triggers/unitmessage.c index 4fa83dff0..6c26fe6a5 100644 --- a/src/triggers/unitmessage.c +++ b/src/triggers/unitmessage.c @@ -63,8 +63,12 @@ static int unitmessage_handle(trigger * t, void *data) unitmessage_data *td = (unitmessage_data *) t->data.v; if (td->target && td->target->no) { struct faction *f = td->target->faction; - addmessage(td->target->region, f, LOC(f->locale, td->string), td->type, - td->level); + const char * str = LOC(f->locale, td->string); + /* bug found in turn 733: sometimes, alps have f*cked up messages */ + if (td->string && td->string[0]) { + addmessage(td->target->region, f, str, td->type, + td->level); + } } unused(data); return 0; From d55d62278ee7a1fcf977ce69431d74e1a7cc578b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 28 Aug 2011 06:51:21 +0200 Subject: [PATCH 156/400] fx an off-by-one memcpy error --- src/kernel/order.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/order.c b/src/kernel/order.c index 5ce1f5ffd..3738354b4 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -125,7 +125,7 @@ static char *get_command(const order * ord, char *sbuffer, size_t size) ++size; --bufp; } - memcpy(bufp + 1, "[...]", 6); /* TODO: make sure this only happens in eval_command */ + memcpy(bufp, "[...]", 6); /* TODO: make sure this only happens in eval_command */ bufp += 6; } } From e6c094922c779e0fefa45c535c4fa4d3cd8137e3 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 28 Oct 2011 23:53:28 -0700 Subject: [PATCH 157/400] update to sqllite 3.7.8 --- src/build/external.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/build/external.c b/src/build/external.c index a882ce3fe..a0f46ad89 100644 --- a/src/build/external.c +++ b/src/build/external.c @@ -3,6 +3,7 @@ #include "stdafx.h" #pragma warning(push) +#pragma warning(disable: 4706) #pragma warning(disable: 4244) #pragma warning(disable: 4127) #include From 9640ac19b375277620e04cd1f5ec57ff971dd6cc Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 4 Mar 2012 16:42:19 -0800 Subject: [PATCH 158/400] dragon names always contained 2 spaces after the article http://bugs.eressea.de/view.php?id=1884 --- src/kernel/names.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/names.c b/src/kernel/names.c index 7fddc01d5..f50289654 100644 --- a/src/kernel/names.c +++ b/src/kernel/names.c @@ -276,7 +276,7 @@ const char *dragon_name(const unit * u) const char *no_article = strchr((const char *)str, ' '); assert(no_article); /* TODO: GERMAN */ - sprintf(name, "Die %sn von %s", no_article, rname(u->region, + sprintf(name, "Die %sn von %s", no_article+1, rname(u->region, default_locale)); } else { char n[32]; From 52013f0e7c64aac57ecd62c4ef8a3a762c9bde28 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 4 Mar 2012 19:21:00 -0800 Subject: [PATCH 159/400] faction stealth is only selectively enabled in E3 --- src/gamecode/spy.c | 50 ++++++++++++++++++++++++++++----------------- src/kernel/config.c | 2 +- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/gamecode/spy.c b/src/gamecode/spy.c index 286a5c107..8341825a0 100644 --- a/src/gamecode/spy.c +++ b/src/gamecode/spy.c @@ -271,32 +271,44 @@ int setstealth_cmd(unit * u, struct order *ord) case P_FACTION: /* TARNE PARTEI [NICHT|NUMMER abcd] */ rule = rule_stealth_faction(); - if (!rule) + if (!rule) { + /* TARNE PARTEI is disabled */ break; + } s = getstrtoken(); - if (!s || *s == 0) { - fset(u, UFL_ANON_FACTION); - } else if (findparam(s, u->faction->locale) == P_NOT) { - freset(u, UFL_ANON_FACTION); - } else if (findkeyword(s, u->faction->locale) == K_NUMBER) { - const char *s2 = (const char *)getstrtoken(); - int nr = -1; + if (rule&1) { + if (!s || *s == 0) { + fset(u, UFL_ANON_FACTION); + break; + } else if (findparam(s, u->faction->locale) == P_NOT) { + freset(u, UFL_ANON_FACTION); + break; + } + } + if (rule&2) { + if (findkeyword(s, u->faction->locale) == K_NUMBER) { + const char *s2 = (const char *)getstrtoken(); + int nr = -1; - if (s2) - nr = atoi36(s2); - if (!s2 || *s2 == 0 || nr == u->faction->no) { - a_removeall(&u->attribs, &at_otherfaction); - } else { - struct faction *f = findfaction(nr); - if (f == NULL) { - cmistake(u, ord, 66, MSG_EVENT); + if (s2) { + nr = atoi36(s2); + } + if (!s2 || *s2 == 0 || nr == u->faction->no) { + a_removeall(&u->attribs, &at_otherfaction); + break; } else { - set_factionstealth(u, f); + struct faction *f = findfaction(nr); + if (f == NULL) { + cmistake(u, ord, 66, MSG_EVENT); + break; + } else { + set_factionstealth(u, f); + break; + } } } - } else { - cmistake(u, ord, 289, MSG_EVENT); } + cmistake(u, ord, 289, MSG_EVENT); break; case P_ANY: case P_NOT: diff --git a/src/kernel/config.c b/src/kernel/config.c index adaba27db..047b35da9 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -2743,7 +2743,7 @@ int rule_stealth_faction(void) static int gamecookie = -1; static int rule = -1; if (rule < 0 || gamecookie != global.cookie) { - rule = get_param_int(global.parameters, "rules.stealth.faction", 1); + rule = get_param_int(global.parameters, "rules.stealth.faction", 0xFF); gamecookie = global.cookie; assert(rule >= 0); } From 63799d823dcb372431977e760f16931fa1ba3fd3 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 4 Mar 2012 19:29:32 -0800 Subject: [PATCH 160/400] hack to ignore otherfaction attributes if faction stealth is not allowed. --- src/attributes/otherfaction.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/attributes/otherfaction.c b/src/attributes/otherfaction.c index 706660c34..bd0b501fc 100644 --- a/src/attributes/otherfaction.c +++ b/src/attributes/otherfaction.c @@ -38,10 +38,19 @@ void write_of(const struct attrib *a, const void *owner, struct storage *store) int read_of(struct attrib *a, void *owner, struct storage *store) { /* return 1 on success, 0 if attrib needs removal */ - int of = store->r_int(store); - a->data.v = findfaction(of); - if (a->data.v) - return AT_READ_OK; + int of; + static int rule = -1; + if (rule<0) { + rule = rule_stealth_faction(); + } + + of = store->r_int(store); + if (rule&2) { + a->data.v = findfaction(of); + if (a->data.v) { + return AT_READ_OK; + } + } return AT_READ_FAIL; } From 80a907d78f3d86180ff25aa6cef9b1bd31a86adf Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 7 Apr 2012 18:11:58 -0700 Subject: [PATCH 161/400] repair units that are toads without a time-limit. --- src/kernel/save.c | 27 +++++++++++++++++++++++++++ src/util/attrib.c | 4 ++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/kernel/save.c b/src/kernel/save.c index 0d7c534cd..e074554db 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -50,6 +50,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* attributes includes */ #include +#include /* util includes */ #include @@ -1391,6 +1392,31 @@ void writefaction(struct storage *store, const faction * f) write_spells(f->spellbook, store); } +static void repair_unit(unit * u) { + static const race * rctoad; + if (!rctoad) rctoad = rc_find("toad"); + + if (u->race==rctoad) { + int found = 0; + attrib * a = a_find(u->attribs, &at_eventhandler); + while (!found && a && a->type==&at_eventhandler) { + struct trigger ** tlist = get_triggers(a, "timer"); + while (!found && tlist && *tlist) { + trigger * t = *tlist; + if (strcmp("changerace", t->type->name)==0) { + found = 1; + } + tlist = &t->next; + } + a = a->next; + } + if (!found) { + u->race = u->faction->race; + log_warning(("This toad did not have a changerace trigger: %s\n", unitname(u))); + } + } +} + int readgame(const char *filename, int mode, int backup) { int i, n, p; @@ -1616,6 +1642,7 @@ int readgame(const char *filename, int mode, int backup) unit *u = read_unit(store); sc_mage *mage; + repair_unit(u); assert(u->region == NULL); u->region = r; *up = u; diff --git a/src/util/attrib.c b/src/util/attrib.c index 9c04c80d6..c5854348b 100644 --- a/src/util/attrib.c +++ b/src/util/attrib.c @@ -265,8 +265,8 @@ int a_read(struct storage *store, attrib ** attribs, void *owner) { int key, retval = AT_READ_OK; char zText[128]; - strcpy(zText, "unknown"); - + + zText[0] = 0; key = -1; store->r_tok_buf(store, zText, sizeof(zText)); if (strcmp(zText, "end") == 0) From ae31948dc5db8d08ac47cd64d5d3a773ab5ec672 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 16 Apr 2012 06:56:44 +0200 Subject: [PATCH 162/400] fix a crash when wolves are cast with too little force --- src/gamecode/economy.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index 4097b055f..dd417fcf4 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -510,9 +510,12 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders) if (recruitcost < 0) { rc = u->race; recruitcost = recruit_cost(f, rc); + if (recruitcost < 0) { + recruitcost = INT_MAX; + } } + assert(rc); u->race = rc; - assert(rc && recruitcost >= 0); #if GUARD_DISABLES_RECRUIT /* this is a very special case because the recruiting unit may be empty From c22f49ec369a12f718b192c27b9e86e482bed3af Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 9 May 2012 03:14:54 -0700 Subject: [PATCH 163/400] replace spellid_t with unsigned int fix finding spells by token make magic_t an enum --- res/equipment.xml | 48 +++++++------- src/bindings/bind_unit.c | 3 +- src/gamecode/items.c | 2 +- src/kernel.vcxproj | 1 + src/kernel.vcxproj.filters | 3 + src/kernel/equipment.c | 1 + src/kernel/magic.c | 47 +++++++++---- src/kernel/magic.h | 47 ++++++------- src/kernel/spell.c | 131 ++++++++++--------------------------- src/kernel/spell.h | 8 ++- src/kernel/spell_test.c | 29 ++++++++ src/kernel/types.h | 15 ++++- src/kernel/xmlreader.c | 16 +++-- src/tests.c | 2 + src/util/umlaut.c | 11 ++++ src/util/umlaut.h | 1 + 16 files changed, 193 insertions(+), 172 deletions(-) create mode 100644 src/kernel/spell_test.c diff --git a/res/equipment.xml b/res/equipment.xml index a38004797..1a38ab808 100644 --- a/res/equipment.xml +++ b/res/equipment.xml @@ -32,9 +32,9 @@ - - - + + + @@ -48,10 +48,10 @@ - - - - + + + + @@ -59,12 +59,12 @@ - - - - - - + + + + + + @@ -75,9 +75,9 @@ - - - + + + @@ -87,9 +87,9 @@ - - - + + + @@ -99,16 +99,16 @@ - - + + - - - + + + diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 49c65d786..c0aec9d92 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -493,7 +493,7 @@ static int tolua_unit_castspell(lua_State * L) static int unit_addspell(unit * u, const char *name) { sc_mage *m = get_mage(u); - spell *spadd = find_spell(m->magietyp, name); + spell *spadd = find_spell(name); if (!spadd) { log_error(("spell %s could not be found\n", name)); @@ -501,6 +501,7 @@ static int unit_addspell(unit * u, const char *name) } else { quicklist **starget = get_spelllist(m, u->faction); add_spell(starget, spadd); + add_spellname(m, spadd); } return 0; } diff --git a/src/gamecode/items.c b/src/gamecode/items.c index 3c2767278..4849ce144 100644 --- a/src/gamecode/items.c +++ b/src/gamecode/items.c @@ -118,7 +118,7 @@ use_antimagiccrystal(unit * u, const struct item_type *itype, int amount, for (i = 0; i != amount; ++i) { int effect, duration = 2; double force; - spell *sp = find_spell(M_NONE, "antimagiczone"); + spell *sp = find_spell("antimagiczone"); attrib **ap = &r->attribs; unused(ord); assert(sp); diff --git a/src/kernel.vcxproj b/src/kernel.vcxproj index 81ea82887..f71b97588 100644 --- a/src/kernel.vcxproj +++ b/src/kernel.vcxproj @@ -121,6 +121,7 @@ + diff --git a/src/kernel.vcxproj.filters b/src/kernel.vcxproj.filters index caadb2064..e5f59818f 100644 --- a/src/kernel.vcxproj.filters +++ b/src/kernel.vcxproj.filters @@ -298,6 +298,9 @@ kernel + + kernel + diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index bf3c354b2..740bf7703 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -149,6 +149,7 @@ void equip_unit_mask(struct unit *u, const struct equipment *eq, int mask) for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { spell *sp = (spell *) ql_get(ql, qi); add_spell(&m->spells, sp); + add_spellname(m, sp); } } } diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 50c9d579b..cb8dfae07 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -58,6 +58,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include @@ -213,14 +214,17 @@ void read_spells(struct quicklist **slistp, magic_t mtype, int i = store->r_int(store); if (i < 0) break; - sp = find_spellbyid(M_NONE, (spellid_t) i); + sp = find_spellbyid((unsigned int) i); } else { store->r_tok_buf(store, spname, sizeof(spname)); if (strcmp(spname, "end") == 0) break; - sp = find_spell(mtype, spname); + sp = find_spell(spname); + if (!sp) { + log_error(("read_spells: could not find spell '%s' in school '%s'\n", spname, magic_school[mtype])); + } } - if (sp != NULL) { + if (sp) { add_spell(slistp, sp); } } @@ -244,14 +248,17 @@ static int read_mage(attrib * a, void *owner, struct storage *store) spid = store->r_int(store); level = store->r_int(store); if (spid >= 0) { - sp = find_spellbyid(mage->magietyp, (spellid_t) spid); + sp = find_spellbyid((unsigned int) spid); } } else { store->r_tok_buf(store, spname, sizeof(spname)); level = store->r_int(store); if (strcmp("none", spname) != 0) { - sp = find_spell(mage->magietyp, spname); + sp = find_spell(spname); + if (!sp) { + log_error(("read_mage: could not find combat spell '%s' in school '%s'\n", spname, magic_school[mage->magietyp])); + } } } if (sp && level >= 0) { @@ -343,14 +350,16 @@ static int read_seenspell(attrib * a, void *owner, struct storage *store) store->r_tok_buf(store, token, sizeof(token)); i = atoi(token); if (i != 0) { - sp = find_spellbyid(M_NONE, (spellid_t) i); + sp = find_spellbyid((unsigned int) i); } else { int mtype; mtype = store->r_int(store); - sp = find_spell((magic_t) mtype, token); + sp = find_spell(token); + if (!sp) { + log_error(("read_seenspell: could not find spell '%s' in school '%s'\n", token, magic_school[mtype])); + } } - if (sp == NULL) { - /* log_error(("could not find seenspell '%s'\n", buf)); */ + if (!sp) { return AT_READ_FAIL; } a->data.v = sp; @@ -488,8 +497,10 @@ void updatespelllist(unit * u) || know_school(u->faction, sp->magietyp)) { faction *f = u->faction; - if (!know) + if (!know) { add_spell(dst, sp); + add_spellname(mage, sp); + } if (!ismonster && !already_seen(u->faction, sp)) { a_add(&f->attribs, a_new(&at_reportspell))->data.v = sp; a_add(&f->attribs, a_new(&at_seenspell))->data.v = sp; @@ -521,6 +532,18 @@ sc_mage *create_mage(unit * u, magic_t mtyp) /* ------------------------------------------------------------- */ /* Funktionen für die Bearbeitung der List-of-known-spells */ +void add_spellname(sc_mage * mage, const spell * sp) +{ + spell_names * names = mage->spellnames; + while (names) { + variant token; + const char *n = spell_name(sp, names->lang); + token.v = (void *)sp; + addtoken(names->tokens, n, token); + names = names->next; + } +} + void add_spell(struct quicklist **slistp, spell * sp) { if (ql_set_insert(slistp, sp) != 0) { @@ -2568,14 +2591,14 @@ static castorder *cast_cmd(unit * u, order * ord) /* Vertraute können auch Zauber sprechen, die sie selbst nicht * können. get_spellfromtoken findet aber nur jene Sprüche, die * die Einheit beherrscht. */ - if (sp == NULL && is_familiar(u)) { + if (!sp && is_familiar(u)) { familiar = u; mage = get_familiar_mage(u); if (mage != NULL) sp = get_spellfromtoken(mage, s, mage->faction->locale); } - if (sp == NULL) { + if (!sp) { /* Fehler 'Spell not found' */ cmistake(u, ord, 173, MSG_MAGIC); return 0; diff --git a/src/kernel/magic.h b/src/kernel/magic.h index 311024d54..3e88bba47 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -86,19 +86,6 @@ extern "C" { /* ------------------------------------------------------------- */ /* Magierichtungen */ -/* typedef unsigned char magic_t; */ - enum { - M_GRAY = 0, /* Gray */ - M_ILLAUN = 1, /* Illaun */ - M_TYBIED = 2, /* Tybied */ - M_CERDDOR = 3, /* Cerddor */ - M_GWYRRD = 4, /* Gwyrrd */ - M_DRAIG = 5, /* Draig */ - M_COMMON = 6, /* common spells */ - MAXMAGIETYP, - /* this enum is stored in the datafile, so do not change the numbers around */ - M_NONE = (magic_t) - 1 - }; extern const char *magic_school[MAXMAGIETYP]; /* ------------------------------------------------------------- */ @@ -113,19 +100,26 @@ extern "C" { * - Spruchliste */ - typedef struct combatspell { - int level; - const struct spell *sp; - } combatspell; +typedef struct combatspell { + int level; + const struct spell *sp; +} combatspell; - typedef struct sc_mage { - magic_t magietyp; - int spellpoints; - int spchange; - int spellcount; - combatspell combatspells[MAXCOMBATSPELLS]; - struct quicklist *spells; - } sc_mage; +typedef struct spell_names { + struct spell_names *next; + const struct locale *lang; + struct tnode * tokens; +} spell_names; + +typedef struct sc_mage { + magic_t magietyp; + int spellpoints; + int spchange; + int spellcount; + combatspell combatspells[MAXCOMBATSPELLS]; + struct quicklist *spells; + struct spell_names * spellnames; +} sc_mage; /* ------------------------------------------------------------- */ /* Zauberliste */ @@ -164,7 +158,7 @@ extern "C" { } spell_component; typedef struct spell { - spellid_t id; + unsigned int id; char *sname; char *syntax; char *parameter; @@ -278,6 +272,7 @@ extern "C" { void unset_combatspell(struct unit *u, spell * sp); /* löscht Kampfzauber */ void add_spell(struct quicklist **slistp, spell * sp); + void add_spellname(sc_mage * mage, const spell * sp); /* fügt den Spruch mit der Id spellid der Spruchliste der Einheit hinzu. */ boolean u_hasspell(const struct unit *u, const struct spell *sp); /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ diff --git a/src/kernel/spell.c b/src/kernel/spell.c index 5f9e6e8f8..cb5df21ca 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -35,12 +35,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include - /* Bitte die Sprüche nach Gebieten und Stufe ordnen, denn in derselben - * Reihenfolge wie in Spelldaten tauchen sie auch im Report auf - */ - quicklist *spells = NULL; +spell * create_spell(const char * name) +{ + spell * sp = (spell *) calloc(1, sizeof(spell)); + sp->sname = strdup(name); + return sp; +} + void register_spell(spell * sp) { if (sp->id == 0) { @@ -49,120 +52,56 @@ void register_spell(spell * sp) add_spell(&spells, sp); } -/** versucht einen Spruch über gebiet + name zu identifizieren. - * gibt ansonsten NULL zurück */ -spell *find_spell(magic_t mtype, const char *name) +spell *find_spell(const char *name) { quicklist *ql = spells; int qi; - spell *spx = NULL; for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { spell *sp = (spell *) ql_get(ql, qi); if (strcmp(name, sp->sname) == 0) { - if (mtype == M_NONE || sp->magietyp == mtype) - return sp; - spx = sp; + return sp; } } - if (spx == NULL) { - log_error(("cannot find spell by name: %s\n", name)); - } - return spx; + log_warning(("find_spell: could not find spell '%s'\n", name)); + return 0; } /* ------------------------------------------------------------- */ /* Spruch identifizieren */ -typedef struct spell_names { - struct spell_names *next; - const struct locale *lang; - magic_t mtype; - struct tnode names; -} spell_names; - -static spell_names *spellnames; - -static spell_names *init_spellnames(const struct locale *lang, magic_t mtype) -{ - quicklist *ql; - int qi; - spell_names *sn = (spell_names *) calloc(sizeof(spell_names), 1); - sn->next = spellnames; - sn->lang = lang; - sn->mtype = mtype; - for (qi = 0, ql = spells; ql; ql_advance(&ql, &qi, 1)) { - spell *sp = (spell *) ql_get(ql, qi); - if (sp->magietyp == mtype) { - const char *n = spell_name(sp, lang); - variant token; - token.v = sp; - addtoken(&sn->names, n, token); - } - } - return spellnames = sn; -} - -static spell_names *get_spellnames(const struct locale *lang, magic_t mtype) -{ - spell_names *sn = spellnames; - while (sn) { - if (sn->mtype == mtype && sn->lang == lang) - break; - sn = sn->next; - } - if (!sn) - return init_spellnames(lang, mtype); - return sn; -} - -static spell *get_spellfromtoken_i(const char *name, const struct locale *lang, - magic_t mtype) -{ - variant token = { 0 }; - spell_names *sn; - - sn = get_spellnames(lang, mtype); - if (findtoken(&sn->names, name, &token) == E_TOK_NOMATCH) { - magic_t mt; - /* if we could not find it in the main magic type, we look through all the others */ - for (mt = 0; mt != MAXMAGIETYP; ++mt) { - if (mt != mtype) { - sn = get_spellnames(lang, mt); - if (findtoken(&sn->names, name, &token) != E_TOK_NOMATCH) - break; - } - } - } - - if (token.v != NULL) - return (spell *) token.v; - if (lang == default_locale) - return NULL; - return get_spellfromtoken_i(name, default_locale, mtype); -} - spell *get_spellfromtoken(unit * u, const char *name, const struct locale * lang) { + variant token; sc_mage *m = get_mage(u); - spell *sp; - - if (m == NULL) - return NULL; - sp = get_spellfromtoken_i(name, lang, m->magietyp); - if (sp != NULL) { + struct spell_names * names = m->spellnames; + for (;names;names=names->next) { + if (names->lang==lang) break; + } + if (!names) { quicklist *ql = m->spells; int qi; - - if (ql_set_find(&ql, &qi, sp)) { - return sp; + names = (spell_names *)calloc(1, sizeof(spell_names)); + names->next = m->spellnames; + names->lang = lang; + names->tokens = (tnode *)calloc(1, sizeof(tnode)); + for (qi = 0, ql = m->spells; ql; ql_advance(&ql, &qi, 1)) { + spell *sp = (spell *) ql_get(ql, qi); + const char *n = spell_name(sp, lang); + token.v = sp; + addtoken(names->tokens, n, token); } + m->spellnames = names; } - return NULL; + + if (findtoken(names->tokens, name, &token) != E_TOK_NOMATCH) { + return (spell *) token.v; + } + return 0; } -spell *find_spellbyid(magic_t mtype, spellid_t id) +spell *find_spellbyid(unsigned int id) { quicklist *ql; int qi; @@ -180,9 +119,7 @@ spell *find_spellbyid(magic_t mtype, spellid_t id) spell *sp = (spell *) ql_get(ql, qi); unsigned int hashid = hashstring(sp->sname); if (hashid == id) { - if (sp->magietyp == mtype || mtype == M_NONE) { - return sp; - } + return sp; } } diff --git a/src/kernel/spell.h b/src/kernel/spell.h index e2c591128..c43aa8cc7 100644 --- a/src/kernel/spell.h +++ b/src/kernel/spell.h @@ -29,6 +29,8 @@ extern "C" { struct curse_type; struct castorder; struct curse; + struct region; + struct unit; /* Prototypen */ @@ -43,9 +45,11 @@ extern "C" { extern struct attrib_type at_wdwpyramid; extern struct quicklist *spells; + + extern struct spell * create_spell(const char * name); extern void register_spell(struct spell *sp); - extern struct spell *find_spell(magic_t mtype, const char *name); - extern struct spell *find_spellbyid(magic_t mtype, spellid_t i); + extern struct spell *find_spell(const char *name); + extern struct spell *find_spellbyid(unsigned int i); extern struct spell *get_spellfromtoken(struct unit *u, const char *s, const struct locale *lang); diff --git a/src/kernel/spell_test.c b/src/kernel/spell_test.c new file mode 100644 index 000000000..ebcb74dfe --- /dev/null +++ b/src/kernel/spell_test.c @@ -0,0 +1,29 @@ +#include +#include +#include + +#include +#include + +#include + +static void test_register_spell(CuTest * tc) +{ + spell * sp; + + CuAssertPtrEquals(tc, 0, find_spell("testspell")); + + CuAssertPtrEquals(tc, spells, 0); + sp = create_spell("testspell"); + sp->magietyp = 5; + register_spell(sp); + CuAssertIntEquals(tc, 1, ql_length(spells)); + CuAssertPtrEquals(tc, sp, find_spell("testspell")); +} + +CuSuite *get_spell_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_register_spell); + return suite; +} diff --git a/src/kernel/types.h b/src/kernel/types.h index 866a72cc2..2b2772564 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -31,10 +31,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include typedef short terrain_t; -typedef short magic_t; typedef short typ_t; typedef short item_t; -typedef unsigned int spellid_t; struct attrib; struct attrib_type; @@ -375,6 +373,19 @@ typedef enum { NODIRECTION = -1 } direction_t; +typedef enum { + M_GRAY = 0, /* Gray */ + M_ILLAUN = 1, /* Illaun */ + M_TYBIED = 2, /* Tybied */ + M_CERDDOR = 3, /* Cerddor */ + M_GWYRRD = 4, /* Gwyrrd */ + M_DRAIG = 5, /* Draig */ + M_COMMON = 6, /* common spells */ + MAXMAGIETYP, + /* this enum is stored in the datafile, so do not change the numbers around */ + M_NONE = -1 +} magic_t; + #define DONT_HELP 0 #define HELP_MONEY 1 /* Mitversorgen von Einheiten */ #define HELP_FIGHT 2 /* Bei Verteidigung mithelfen */ diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 51b7084cb..d2799feac 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -90,7 +90,7 @@ static const spell *xml_spell(xmlNode * node, const char *name) const spell *sp = NULL; xmlChar *propValue = xmlGetProp(node, BAD_CAST name); if (propValue != NULL) { - sp = find_spell(M_NONE, (const char *)propValue); + sp = find_spell((const char *)propValue); assert(sp); xmlFree(propValue); } @@ -1322,12 +1322,14 @@ static void add_spells(equipment * eq, xmlNodeSetPtr nsetItems) propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue != NULL); - sp = find_spell(mtype, (const char *)propValue); - assert(sp); - xmlFree(propValue); - if (sp != NULL) { + sp = find_spell((const char *)propValue); + if (!sp) { + log_error(("no spell '%s' in school '%s' for equipment-set '%s'\n", + (const char *)propValue, magic_school[mtype], eq->name)); + } else { equipment_addspell(eq, sp); } + xmlFree(propValue); } } } @@ -1492,13 +1494,13 @@ static int parse_spells(xmlDocPtr doc) xmlChar *propValue; int k; spell_component *component; - spell *sp = (spell *) calloc(1, sizeof(spell)); + spell *sp; static int modes[] = { 0, PRECOMBATSPELL, COMBATSPELL, POSTCOMBATSPELL }; /* spellname */ propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue != NULL); - sp->sname = strdup((const char *)propValue); + sp = create_spell((const char *)propValue); xmlFree(propValue); propValue = xmlGetProp(node, BAD_CAST "parameters"); diff --git a/src/tests.c b/src/tests.c index 118910c05..39d9cd0c9 100644 --- a/src/tests.c +++ b/src/tests.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,7 @@ int RunAllTests(void) CuSuiteAddSuite(suite, get_curse_suite()); CuSuiteAddSuite(suite, get_market_suite()); CuSuiteAddSuite(suite, get_move_suite()); + CuSuiteAddSuite(suite, get_spell_suite()); CuSuiteAddSuite(suite, get_laws_suite()); CuSuiteAddSuite(suite, get_battle_suite()); diff --git a/src/util/umlaut.c b/src/util/umlaut.c index cb3f22ea4..6904e91b5 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -61,6 +61,7 @@ void addtoken(tnode * root, const char *str, variant id) 0, ""} }; + assert(root); if (!*str) { root->id = id; root->flags |= LEAF; @@ -135,8 +136,18 @@ void addtoken(tnode * root, const char *str, variant id) } } +void freetokens(struct tnode *root) +{ + int i; + for (i=0;root && i!=NODEHASHSIZE;++i) { + freetokens(root->next[i]->node); + free(root->next[i]); + } +} + int findtoken(const tnode * tk, const char *str, variant * result) { + assert(tk); if (!str || *str == 0) return E_TOK_NOMATCH; diff --git a/src/util/umlaut.h b/src/util/umlaut.h index aeabccc39..d19f35b2d 100644 --- a/src/util/umlaut.h +++ b/src/util/umlaut.h @@ -38,6 +38,7 @@ extern "C" { int findtoken(const struct tnode *tk, const char *str, variant * result); void addtoken(struct tnode *root, const char *str, variant id); + void freetokens(struct tnode *root); typedef struct local_names { struct local_names *next; From c41d185cd6948d2f4ea2c0d6b5d2f05bf1f91477 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 9 May 2012 13:02:08 -0700 Subject: [PATCH 164/400] some cleanup --- src/kernel/xmlreader.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index d2799feac..1272fad79 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1870,10 +1870,7 @@ static int parse_races(xmlDocPtr doc) propValue = xmlGetProp(node, BAD_CAST "race"); assert(propValue != NULL); frc = rc_find((const char *)propValue); - if (frc == NULL) { -/* log_error(("%s not registered, is familiar for %s\n", */ -/* (const char*)propValue, rc->_name[0])); */ -/* assert(frc!=NULL); */ + if (!frc) { frc = rc_add(rc_new((const char *)propValue)); } if (xml_bvalue(node, "default", false)) { From c10e2552ad4cb4aa2c89dba72734b3d0ff159527 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 9 May 2012 13:06:16 -0700 Subject: [PATCH 165/400] get_spellfromtoken needs a mage, not any unit. --- src/bindings/bind_unit.c | 14 ++------------ src/gamecode/laws.c | 31 ++++++++++++++++++++----------- src/kernel/order.c | 3 ++- src/kernel/spell.c | 13 ++++++------- src/kernel/spell.h | 2 +- 5 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index c0aec9d92..ba7b692df 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -461,23 +461,13 @@ static void unit_castspell(unit * u, const char *name) for (ql = spells, qi = 0; ql; ql_advance(&ql, &qi, 1)) { spell *sp = (spell *) ql_get(ql, qi); if (strcmp(name, sp->sname) == 0) { - castorder *co = (castorder *) malloc(sizeof(castorder)); - co->distance = 0; - co->familiar = NULL; - co->force = sp->level; - co->level = sp->level; - co->magician.u = u; - co->order = NULL; - co->par = NULL; - co->rt = u->region; - co->sp = sp; if (sp->sp_function == NULL) { log_error(("spell '%s' has no function.\n", sp->sname)); - co->level = 0; } else { + castorder *co = new_castorder(u, 0, sp, u->region, sp->level, sp->level, 0, 0, 0); sp->sp_function(co); + free(co); } - free(co); } } } diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 5ef5fa739..4e6fd92be 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -2420,8 +2420,9 @@ static void reshow(unit * u, struct order *ord, const char *s, param_t p) int skill, c; const potion_type *ptype; const item_type *itype; - const spell *sp; + const spell *sp = 0; const race *rc; + sc_mage * mage; switch (p) { case P_ZAUBER: @@ -2452,13 +2453,18 @@ static void reshow(unit * u, struct order *ord, const char *s, param_t p) } } /* try for a spell */ - sp = get_spellfromtoken(u, s, u->faction->locale); - if (sp != NULL && u_hasspell(u, sp)) { + mage = get_mage(u); + if (mage) { + sp = get_spellfromtoken(mage, s, u->faction->locale); + } + if (sp) { attrib *a = a_find(u->faction->attribs, &at_seenspell); - while (a != NULL && a->type == &at_seenspell && a->data.v != sp) + while (a != NULL && a->type == &at_seenspell && a->data.v != sp) { a = a->next; - if (a != NULL) + } + if (a != NULL) { a_remove(&u->faction->attribs, a); + } break; } /* last, check if it's a race. */ @@ -2615,7 +2621,8 @@ static int combatspell_cmd(unit * u, struct order *ord) { const char *s; int level = 0; - spell *spell; + spell *sp = 0; + sc_mage * mage; init_tokens(ord); skip_token(); @@ -2635,9 +2642,11 @@ static int combatspell_cmd(unit * u, struct order *ord) s = getstrtoken(); } - spell = get_spellfromtoken(u, s, u->faction->locale); - - if (!spell) { + mage = get_mage(u); + if (mage) { + sp = get_spellfromtoken(mage, s, u->faction->locale); + } + if (!sp) { cmistake(u, ord, 173, MSG_MAGIC); return 0; } @@ -2647,11 +2656,11 @@ static int combatspell_cmd(unit * u, struct order *ord) if (findparam(s, u->faction->locale) == P_NOT) { /* KAMPFZAUBER "" NICHT löscht diesen speziellen * Kampfzauber */ - unset_combatspell(u, spell); + unset_combatspell(u, sp); return 0; } else { /* KAMPFZAUBER "" setzt diesen Kampfzauber */ - set_combatspell(u, spell, ord, level); + set_combatspell(u, sp, ord, level); } return 0; diff --git a/src/kernel/order.c b/src/kernel/order.c index 3738354b4..1ea62abf9 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -112,8 +112,9 @@ static char *get_command(const order * ord, char *sbuffer, size_t size) WARN_STATIC_BUFFER(); if (text) *bufp++ = ' '; - } else + } else { WARN_STATIC_BUFFER(); + } } if (text) { bytes = (int)strlcpy(bufp, (const char *)text, size); diff --git a/src/kernel/spell.c b/src/kernel/spell.c index cb5df21ca..4e183029f 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -70,29 +70,28 @@ spell *find_spell(const char *name) /* ------------------------------------------------------------- */ /* Spruch identifizieren */ -spell *get_spellfromtoken(unit * u, const char *name, +spell *get_spellfromtoken(sc_mage *mage, const char *name, const struct locale * lang) { variant token; - sc_mage *m = get_mage(u); - struct spell_names * names = m->spellnames; + struct spell_names * names = mage->spellnames; for (;names;names=names->next) { if (names->lang==lang) break; } if (!names) { - quicklist *ql = m->spells; + quicklist *ql = mage->spells; int qi; names = (spell_names *)calloc(1, sizeof(spell_names)); - names->next = m->spellnames; + names->next = mage->spellnames; names->lang = lang; names->tokens = (tnode *)calloc(1, sizeof(tnode)); - for (qi = 0, ql = m->spells; ql; ql_advance(&ql, &qi, 1)) { + for (qi = 0, ql = mage->spells; ql; ql_advance(&ql, &qi, 1)) { spell *sp = (spell *) ql_get(ql, qi); const char *n = spell_name(sp, lang); token.v = sp; addtoken(names->tokens, n, token); } - m->spellnames = names; + mage->spellnames = names; } if (findtoken(names->tokens, name, &token) != E_TOK_NOMATCH) { diff --git a/src/kernel/spell.h b/src/kernel/spell.h index c43aa8cc7..4e5daf1b5 100644 --- a/src/kernel/spell.h +++ b/src/kernel/spell.h @@ -50,7 +50,7 @@ extern "C" { extern void register_spell(struct spell *sp); extern struct spell *find_spell(const char *name); extern struct spell *find_spellbyid(unsigned int i); - extern struct spell *get_spellfromtoken(struct unit *u, const char *s, + extern struct spell *get_spellfromtoken(struct sc_mage *mage, const char *s, const struct locale *lang); #ifdef __cplusplus From 6dcf6669c33c477b0b045d6aa47ef5a6ae2397d0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 9 May 2012 13:18:02 -0700 Subject: [PATCH 166/400] get_spellfromtoken takes a mage clarify this code with regards to mages casting through a familiar --- src/kernel/magic.c | 52 +++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/src/kernel/magic.c b/src/kernel/magic.c index cb8dfae07..fcfadf2bd 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -2522,11 +2522,13 @@ static castorder *cast_cmd(unit * u, order * ord) region *r = u->region; region *target_r = r; int level, range; - unit *familiar = NULL, *mage = u; + unit *familiar = NULL; const char *s; - spell *sp; + spell *sp = 0; plane *pl; spellparameter *args = NULL; + unit * caster = u; + sc_mage * mage; if (LongHunger(u)) { cmistake(u, ord, 224, MSG_MAGIC); @@ -2563,8 +2565,8 @@ static castorder *cast_cmd(unit * u, order * ord) target_r = findregion(t_x, t_y); if (!target_r) { /* Fehler "Die Region konnte nicht verzaubert werden" */ - ADDMSG(&mage->faction->msgs, msg_message("spellregionresists", - "unit region command", mage, mage->region, ord)); + ADDMSG(&u->faction->msgs, msg_message("spellregionresists", + "unit region command", u, u->region, ord)); return 0; } s = getstrtoken(); @@ -2586,16 +2588,26 @@ static castorder *cast_cmd(unit * u, order * ord) cmistake(u, ord, 172, MSG_MAGIC); return 0; } - sp = get_spellfromtoken(u, s, u->faction->locale); + + mage = get_mage(u); + if (mage) { + sp = get_spellfromtoken(mage, s, u->faction->locale); + } /* Vertraute können auch Zauber sprechen, die sie selbst nicht * können. get_spellfromtoken findet aber nur jene Sprüche, die * die Einheit beherrscht. */ if (!sp && is_familiar(u)) { - familiar = u; - mage = get_familiar_mage(u); - if (mage != NULL) - sp = get_spellfromtoken(mage, s, mage->faction->locale); + caster = get_familiar_mage(u); + if (caster) { + mage = get_mage(caster); + familiar = u; + sp = get_spellfromtoken(mage, s, caster->faction->locale); + } else { + /* somehow, this familiar has no mage! */ + log_error(("cast_cmd: familiar %s is without a mage?\n", unitname(u))); + caster = u; + } } if (!sp) { @@ -2674,36 +2686,34 @@ static castorder *cast_cmd(unit * u, order * ord) * die des Vertrauten! * Der Spruch wirkt dann auf die Region des Vertrauten und * gilt nicht als Farcasting. */ - if (familiar || is_familiar(u)) { + if (familiar) { if ((sp->sptyp & NOTFAMILIARCAST)) { /* Fehler: "Diesen Spruch kann der Vertraute nicht zaubern" */ cmistake(u, ord, 177, MSG_MAGIC); return 0; } - if (!knowsspell(r, u, sp)) { /* Magier zaubert durch Vertrauten */ - mage = get_familiar_mage(u); + if (caster != familiar) { /* Magier zaubert durch Vertrauten */ if (range > 1) { /* Fehler! Versucht zu Farcasten */ ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_farcast", "mage", mage)); return 0; } - if (distance(mage->region, r) > eff_skill(mage, SK_MAGIC, mage->region)) { + if (distance(caster->region, r) > eff_skill(caster, SK_MAGIC, caster->region)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_toofar", - "mage", mage)); + "mage", caster)); return 0; } /* mage auf magier setzen, level anpassen, range für Erhöhung * der Spruchkosten nutzen, langen Befehl des Magiers * löschen, zaubern kann er noch */ range *= 2; - set_order(&mage->thisorder, NULL); - level = MIN(level, eff_skill(mage, SK_MAGIC, mage->region) / 2); - familiar = u; + set_order(&caster->thisorder, NULL); + level = MIN(level, eff_skill(caster, SK_MAGIC, caster->region) / 2); } } /* Weitere Argumente zusammenbasteln */ if (sp->parameter) { - char **params = malloc(2 * sizeof(char *)); + char **params = (char**)malloc(2 * sizeof(char *)); int p = 0, size = 2; for (;;) { s = getstrtoken(); @@ -2711,13 +2721,13 @@ static castorder *cast_cmd(unit * u, order * ord) break; if (p + 1 >= size) { size *= 2; - params = realloc(params, sizeof(char *) * size); + params = (char**)realloc(params, sizeof(char *) * size); } params[p++] = strdup(s); } params[p] = 0; args = - add_spellparameter(target_r, mage, sp->parameter, + add_spellparameter(target_r, caster, sp->parameter, (const char *const *)params, p, ord); for (p = 0; params[p]; ++p) free(params[p]); @@ -2727,7 +2737,7 @@ static castorder *cast_cmd(unit * u, order * ord) return 0; } } - return new_castorder(mage, familiar, sp, target_r, level, 0, range, ord, + return new_castorder(caster, familiar, sp, target_r, level, 0, range, ord, args); } From 02559f68697c07ed1f1017b5a3d593ba1506b953 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 9 May 2012 13:46:10 -0700 Subject: [PATCH 167/400] refactoring castorder, because it's a bit of a mess of units, fighters, familliars and casters. --- src/bindings/bind_unit.c | 7 ++++--- src/kernel/magic.c | 25 ++++++++++++++++++++++++- src/kernel/magic.h | 6 +++++- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index ba7b692df..bb1050aa5 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -464,9 +464,10 @@ static void unit_castspell(unit * u, const char *name) if (sp->sp_function == NULL) { log_error(("spell '%s' has no function.\n", sp->sname)); } else { - castorder *co = new_castorder(u, 0, sp, u->region, sp->level, sp->level, 0, 0, 0); - sp->sp_function(co); - free(co); + castorder co; + create_castorder(&co, u, 0, sp, u->region, sp->level, sp->level, 0, 0, 0); + sp->sp_function(&co); + free_castorder(&co); } } } diff --git a/src/kernel/magic.c b/src/kernel/magic.c index fcfadf2bd..bc4225a6c 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -2102,7 +2102,7 @@ castorder *new_castorder(void *u, unit * u2, const spell * sp, region * r, { castorder *corder; - corder = calloc(1, sizeof(castorder)); + corder = (castorder*)calloc(1, sizeof(castorder)); corder->magician.u = u; corder->familiar = u2; corder->sp = sp; @@ -2116,6 +2116,29 @@ castorder *new_castorder(void *u, unit * u2, const spell * sp, region * r, return corder; } +castorder *create_castorder(castorder * co, unit *caster, unit * familiar, const spell * sp, region * r, + int lev, double force, int range, struct order * ord, spellparameter * p) +{ + if (!co) co = (castorder*)calloc(1, sizeof(castorder)); + + co->magician.u = caster; + co->familiar = familiar; + co->sp = sp; + co->level = lev; + co->force = force; + co->rt = r; + co->distance = range; + co->order = copy_order(ord); + co->par = p; + + return co; +} + +void free_castorder(struct castorder *co) +{ + free_order(co->order); +} + /* Hänge c-order co an die letze c-order von cll an */ void add_castorder(spellrank * cll, castorder * co) { diff --git a/src/kernel/magic.h b/src/kernel/magic.h index 3e88bba47..d48926499 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -314,9 +314,13 @@ typedef struct sc_mage { struct castorder **end; } spellrank; - castorder *new_castorder(void *u, struct unit *familiar, const spell * sp, + struct castorder *new_castorder(void *u, struct unit *familiar, const spell * sp, struct region *r, int lev, double force, int distance, struct order *ord, spellparameter * p); + struct castorder *create_castorder(struct castorder * co, struct unit *caster, + struct unit * familiar, const struct spell * sp, struct region * r, + int lev, double force, int range, struct order * ord, struct spellparameter * p); + void free_castorder(struct castorder *co); /* Zwischenspreicher für Zauberbefehle, notwendig für Prioritäten */ void add_castorder(struct spellrank *cll, struct castorder *co); /* Hänge c-order co an die letze c-order von cll an */ From 06e0d2b3b6c43e620e5a32ecf4479cf5ef9605f6 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 9 May 2012 14:16:41 -0700 Subject: [PATCH 168/400] cleaning up castorder, unifying access to target region and caster. --- src/bindings/helpers.c | 11 ++++++----- src/kernel/magic.c | 30 ++++++++++++++++++------------ src/kernel/magic.h | 7 +++++-- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/bindings/helpers.c b/src/bindings/helpers.c index 7e8f5d5ba..c17ffeb55 100644 --- a/src/bindings/helpers.c +++ b/src/bindings/helpers.c @@ -190,7 +190,8 @@ static int lua_callspell(castorder * co) { lua_State *L = (lua_State *) global.vm_state; const char *fname = co->sp->sname; - unit *mage = co->familiar ? co->familiar : co->magician.u; + unit *caster = co_get_caster(co); + region * r = co_get_region(co); int result = -1; const char *hashpos = strchr(fname, '#'); char fbuf[64]; @@ -207,8 +208,8 @@ static int lua_callspell(castorder * co) lua_rawget(L, LUA_GLOBALSINDEX); if (lua_isfunction(L, 1)) { int nparam = 4; - tolua_pushusertype(L, co->rt, TOLUA_CAST "region"); - tolua_pushusertype(L, mage, TOLUA_CAST "unit"); + tolua_pushusertype(L, r, TOLUA_CAST "region"); + tolua_pushusertype(L, caster, TOLUA_CAST "unit"); tolua_pushnumber(L, (lua_Number) co->level); tolua_pushnumber(L, (lua_Number) co->force); if (co->sp->parameter && co->par->length) { @@ -232,7 +233,7 @@ static int lua_callspell(castorder * co) if (lua_pcall(L, nparam, 1, 0) != 0) { const char *error = lua_tostring(L, -1); log_error(("spell(%s) calling '%s': %s.\n", - unitname(mage), fname, error)); + unitname(caster), fname, error)); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); @@ -240,7 +241,7 @@ static int lua_callspell(castorder * co) } } else { log_error(("spell(%s) calling '%s': not a function.\n", - unitname(mage), fname)); + unitname(caster), fname)); lua_pop(L, 1); } diff --git a/src/kernel/magic.c b/src/kernel/magic.c index bc4225a6c..a422522ed 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -1365,7 +1365,7 @@ static void patzer(castorder * co) static void do_fumble(castorder * co) { curse *c; - region *r = co->rt; + region *r = co_get_region(co); unit *u = co->magician.u; const spell *sp = co->sp; int level = co->level; @@ -1664,7 +1664,7 @@ verify_targets(castorder * co, int *invalid, int *resist, int *success) { unit *mage = co->magician.u; const spell *sp = co->sp; - region *target_r = co->rt; + region *target_r = co_get_region(co); spellparameter *sa = co->par; int i; @@ -2040,7 +2040,7 @@ static spellparameter *add_spellparameter(region * target_r, unit * u, pword = findparam(param[i++], u->faction->locale); switch (pword) { case P_REGION: - spobj = malloc(sizeof(spllprm)); + spobj = (spllprm *)malloc(sizeof(spllprm)); spobj->flag = 0; spobj->typ = SPP_REGION; spobj->data.r = u->region; @@ -2095,20 +2095,26 @@ static spellparameter *add_spellparameter(region * target_r, unit * u, return par; } -/* ------------------------------------------------------------- */ +struct unit * co_get_caster(struct castorder * co) { + return co->_familiar ? co->_familiar : co->magician.u; +} -castorder *new_castorder(void *u, unit * u2, const spell * sp, region * r, +struct region * co_get_region(struct castorder * co) { + return co->_rtarget; +} + +castorder *new_castorder(void *caster, unit * familiar, const spell * sp, region * r, int lev, double force, int range, struct order * ord, spellparameter * p) { - castorder *corder; + castorder *corder = (castorder*)calloc(1, sizeof(castorder)); + unit * u = (unit *)caster; - corder = (castorder*)calloc(1, sizeof(castorder)); corder->magician.u = u; - corder->familiar = u2; + corder->_familiar = familiar; corder->sp = sp; corder->level = lev; corder->force = force; - corder->rt = r; + corder->_rtarget = r ? r : (familiar ? familiar->region : (u ? u->region : 0)); corder->distance = range; corder->order = copy_order(ord); corder->par = p; @@ -2122,11 +2128,11 @@ castorder *create_castorder(castorder * co, unit *caster, unit * familiar, const if (!co) co = (castorder*)calloc(1, sizeof(castorder)); co->magician.u = caster; - co->familiar = familiar; + co->_familiar = familiar; co->sp = sp; co->level = lev; co->force = force; - co->rt = r; + co->_rtarget = r ? r : (familiar ? familiar->region : (caster ? caster->region : 0)); co->distance = range; co->order = copy_order(ord); co->par = p; @@ -2834,7 +2840,7 @@ void magic(void) boolean fumbled = false; unit *u = co->magician.u; const spell *sp = co->sp; - region *target_r = co->rt; + region *target_r = co_get_region(co); /* reichen die Komponenten nicht, wird der Level reduziert. */ co->level = eff_spelllevel(u, sp, cast_level, co->distance); diff --git a/src/kernel/magic.h b/src/kernel/magic.h index d48926499..8679c0b63 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -130,17 +130,20 @@ typedef struct sc_mage { struct unit *u; struct fighter *fig; } magician; /* Magier (kann vom Typ struct unit oder fighter sein) */ - struct unit *familiar; /* Vertrauter, gesetzt, wenn der Spruch durch + struct unit *_familiar; /* Vertrauter, gesetzt, wenn der Spruch durch den Vertrauten gezaubert wird */ const struct spell *sp; /* Spruch */ int level; /* gewünschte Stufe oder Stufe des Magiers */ double force; /* Stärke des Zaubers */ - struct region *rt; /* Zielregion des Spruchs */ + struct region *_rtarget; /* Zielregion des Spruchs */ int distance; /* Entfernung zur Zielregion */ struct order *order; /* Befehl */ struct spellparameter *par; /* für weitere Parameter */ } castorder; + struct unit * co_get_caster(struct castorder * co); + struct region * co_get_region(struct castorder * co); + /* irgendwelche zauber: */ typedef void (*spell_f) (void *); /* normale zauber: */ From 67ef4c52a3ae74b9c01835917301bbcd1b065507 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 9 May 2012 18:28:33 -0700 Subject: [PATCH 169/400] combat spell functions have the same interface as spells now. --- src/bindings/bind_unit.c | 6 +-- src/bindings/bindings.c | 2 +- src/kernel/battle.c | 81 ++++++++++++++++++++++------------------ src/kernel/magic.c | 23 +++--------- src/kernel/magic.h | 17 +++------ src/kernel/xmlreader.c | 4 +- 6 files changed, 60 insertions(+), 73 deletions(-) diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index bb1050aa5..38c762c20 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -461,12 +461,12 @@ static void unit_castspell(unit * u, const char *name) for (ql = spells, qi = 0; ql; ql_advance(&ql, &qi, 1)) { spell *sp = (spell *) ql_get(ql, qi); if (strcmp(name, sp->sname) == 0) { - if (sp->sp_function == NULL) { + if (!sp->cast) { log_error(("spell '%s' has no function.\n", sp->sname)); } else { castorder co; - create_castorder(&co, u, 0, sp, u->region, sp->level, sp->level, 0, 0, 0); - sp->sp_function(&co); + create_castorder(&co, u, 0, sp, u->region, sp->level, sp->level * MagicPower(), 0, 0, 0); + sp->cast(&co); free_castorder(&co); } } diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index 0e13e7543..7236af01a 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -698,7 +698,7 @@ static int tolua_write_spells(lua_State * L) int qi; for (ql = spells, qi = 0; ql; ql_advance(&ql, &qi, 1)) { spell *sp = (spell *) ql_get(ql, qi); - if (sp->sp_function != fun) { + if (sp->cast != fun) { int combat = 0; xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "spell"); xmlNewProp(node, BAD_CAST "name", BAD_CAST sp->sname); diff --git a/src/kernel/battle.c b/src/kernel/battle.c index 22781c80d..1e36806ee 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -1776,12 +1776,11 @@ void do_combatmagic(battle * b, combatmagic_t was) fighter *fig = co->magician.fig; const spell *sp = co->sp; int level = co->level; - double power = co->force; - if (sp->sp_function == NULL) { + if (!sp->cast) { log_error(("spell '%s' has no function.\n", sp->sname)); } else { - level = ((cspell_f) sp->sp_function) (fig, level, power, sp); + level = sp->cast(co); if (level > 0) { pay_spell(fig->unit, sp, level, 1); } @@ -1793,19 +1792,34 @@ void do_combatmagic(battle * b, combatmagic_t was) } } -static void combat_action(fighter * af, int turn) +static void combat_action(fighter * af) { #ifndef SIMPLE_COMBAT af->action_counter++; - af->side->bf->lastturn = turn; + af->side->bf->lastturn = af->side->battle->turn; #endif } +static int cast_combatspell(troop at, const spell * sp, int level, double force) +{ + castorder co; + + create_castorder(&co, at.fighter->unit, 0, sp, at.fighter->unit->region, level, force, 0, 0, 0); + co.magician.fig = at.fighter; + level = sp->cast(&co); + free_castorder(&co); + if (level > 0) { + pay_spell(at.fighter->unit, sp, level, 1); + combat_action(at.fighter); + } + return level; +} + static void do_combatspell(troop at) { const spell *sp; fighter *fi = at.fighter; - unit *mage = fi->unit; + unit *caster = fi->unit; battle *b = fi->side->battle; region *r = b->region; quicklist *ql; @@ -1814,26 +1828,26 @@ static void do_combatspell(troop at) int fumblechance = 0; order *ord; int sl; - const struct locale *lang = mage->faction->locale; + const struct locale *lang = caster->faction->locale; - sp = get_combatspell(mage, 1); + sp = get_combatspell(caster, 1); if (sp == NULL) { fi->magic = 0; /* Hat keinen Kampfzauber, kämpft nichtmagisch weiter */ return; } ord = create_order(K_CAST, lang, "'%s'", spell_name(sp, lang)); - if (cancast(mage, sp, 1, 1, ord) == false) { + if (cancast(caster, sp, 1, 1, ord) == false) { fi->magic = 0; /* Kann nicht mehr Zaubern, kämpft nichtmagisch weiter */ return; } - level = eff_spelllevel(mage, sp, fi->magic, 1); - if ((sl = get_combatspelllevel(mage, 1)) > 0) + level = eff_spelllevel(caster, sp, fi->magic, 1); + if ((sl = get_combatspelllevel(caster, 1)) > 0) level = MIN(level, sl); - if (fumble(r, mage, sp, sp->level) == true) { - report_failed_spell(b, mage, sp); - pay_spell(mage, sp, level, 1); + if (fumble(r, caster, sp, sp->level) == true) { + report_failed_spell(b, caster, sp); + pay_spell(caster, sp, level, 1); return; } @@ -1849,27 +1863,23 @@ static void do_combatspell(troop at) /* Antimagie die Fehlschlag erhöht */ if (rng_int() % 100 < fumblechance) { - report_failed_spell(b, mage, sp); - pay_spell(mage, sp, level, 1); + report_failed_spell(b, caster, sp); + pay_spell(caster, sp, level, 1); free_order(ord); return; } - power = spellpower(r, mage, sp, level, ord); + power = spellpower(r, caster, sp, level, ord); free_order(ord); if (power <= 0) { /* Effekt von Antimagie */ - report_failed_spell(b, mage, sp); - pay_spell(mage, sp, level, 1); + report_failed_spell(b, caster, sp); + pay_spell(caster, sp, level, 1); return; } - if (sp->sp_function == NULL) { + if (!sp->cast) { log_error(("spell '%s' has no function.\n", sp->sname)); } else { - level = ((cspell_f) sp->sp_function) (fi, level, power, sp); - if (level > 0) { - pay_spell(mage, sp, level, 1); - combat_action(at.fighter, b->turn); - } + level = cast_combatspell(at, sp, level, power); } } @@ -1881,14 +1891,11 @@ static void do_combatspell(troop at) static void do_extra_spell(troop at, const att * a) { const spell *sp = a->data.sp; - fighter *fi = at.fighter; - double power; - power = sp->level * MagicPower(); - if (sp->sp_function == NULL) { + if (sp->cast == NULL) { log_error(("spell '%s' has no function.\n", sp->sname)); } else { - ((cspell_f) sp->sp_function) (fi, sp->level, power, sp); + cast_combatspell(at, sp, sp->level, sp->level * MagicPower()); } } @@ -2181,7 +2188,7 @@ static void attack(battle * b, troop ta, const att * a, int numattack) af->catmsg += dead; if (!standard_attack && af->person[ta.index].last_action < b->turn) { af->person[ta.index].last_action = b->turn; - combat_action(af, b->turn); + combat_action(af); } } if (standard_attack) { @@ -2197,7 +2204,7 @@ static void attack(battle * b, troop ta, const att * a, int numattack) return; if (ta.fighter->person[ta.index].last_action < b->turn) { ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); + combat_action(ta.fighter); } reload = true; if (hits(ta, td, wp)) { @@ -2230,7 +2237,7 @@ static void attack(battle * b, troop ta, const att * a, int numattack) return; if (ta.fighter->person[ta.index].last_action < b->turn) { ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); + combat_action(ta.fighter); } if (hits(ta, td, NULL)) { terminate(td, ta, a->type, a->data.dice, false); @@ -2242,7 +2249,7 @@ static void attack(battle * b, troop ta, const att * a, int numattack) return; if (ta.fighter->person[ta.index].last_action < b->turn) { ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); + combat_action(ta.fighter); } if (hits(ta, td, NULL)) { int c = dice_rand(a->data.dice); @@ -2262,7 +2269,7 @@ static void attack(battle * b, troop ta, const att * a, int numattack) return; if (ta.fighter->person[ta.index].last_action < b->turn) { ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); + combat_action(ta.fighter); } if (hits(ta, td, NULL)) { drain_exp(td.fighter->unit, dice_rand(a->data.dice)); @@ -2274,7 +2281,7 @@ static void attack(battle * b, troop ta, const att * a, int numattack) return; if (ta.fighter->person[ta.index].last_action < b->turn) { ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); + combat_action(ta.fighter); } if (hits(ta, td, NULL)) { dazzle(b, &td); @@ -2286,7 +2293,7 @@ static void attack(battle * b, troop ta, const att * a, int numattack) return; if (ta.fighter->person[ta.index].last_action < b->turn) { ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter, b->turn); + combat_action(ta.fighter); } if (td.fighter->unit->ship) { /* FIXME should use damage_ship here? */ diff --git a/src/kernel/magic.c b/src/kernel/magic.c index a422522ed..e048efc40 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -1432,11 +1432,7 @@ static void do_fumble(castorder * co) case 5: case 6: /* Spruch gelingt, aber alle Magiepunkte weg */ - if (sp->sp_function == NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); - } else { - ((nspell_f) sp->sp_function) (co); - } + sp->cast(co); set_spellpoints(u, 0); ADDMSG(&u->faction->msgs, msg_message("patzer4", "unit region spell", u, r, sp)); @@ -1447,11 +1443,7 @@ static void do_fumble(castorder * co) case 9: default: /* Spruch gelingt, alle nachfolgenden Sprüche werden 2^4 so teuer */ - if (sp->sp_function == NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); - } else { - ((nspell_f) sp->sp_function) (co); - } + sp->cast(co); ADDMSG(&u->faction->msgs, msg_message("patzer5", "unit region spell", u, r, sp)); countspells(u, 3); @@ -1788,7 +1780,7 @@ verify_targets(castorder * co, int *invalid, int *resist, int *success) * Magieresistenz der Region prüfen. */ if ((sp->sptyp & REGIONSPELL)) { /* Zielobjekt Region anlegen */ - spllprm *spobj = malloc(sizeof(spllprm)); + spllprm *spobj = (spllprm *)malloc(sizeof(spllprm)); spobj->flag = 0; spobj->typ = SPP_REGION; spobj->data.r = target_r; @@ -1908,7 +1900,7 @@ addparam_region(const char *const param[], spllprm ** spobjp, const unit * u, rt = findregion(x, y); if (rt != NULL) { - spllprm *spobj = *spobjp = malloc(sizeof(spllprm)); + spllprm *spobj = *spobjp = (spllprm *)malloc(sizeof(spllprm)); spobj->flag = 0; spobj->typ = SPP_REGION; @@ -2903,12 +2895,7 @@ void magic(void) /* zuerst bezahlen, dann evt in do_fumble alle Aura verlieren */ fumbled = true; } else { - if (sp->sp_function == NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); - co->level = 0; - } else { - co->level = ((nspell_f) sp->sp_function) (co); - } + co->level = sp->cast(co); if (co->level <= 0) { /* Kosten nur für real benötige Stufe berechnen */ continue; diff --git a/src/kernel/magic.h b/src/kernel/magic.h index 8679c0b63..eb0047e9f 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -144,22 +144,15 @@ typedef struct sc_mage { struct unit * co_get_caster(struct castorder * co); struct region * co_get_region(struct castorder * co); -/* irgendwelche zauber: */ - typedef void (*spell_f) (void *); -/* normale zauber: */ - typedef int (*nspell_f) (castorder *); -/* kampfzauber: */ - typedef int (*cspell_f) (struct fighter *, int, double, - const struct spell * sp); -/* zauber-patzer: */ - typedef void (*pspell_f) (castorder *); - typedef struct spell_component { const struct resource_type *type; int amount; int cost; } spell_component; + typedef int (*spell_f)(castorder * co); + typedef void(*fumble_f)(castorder * co); + typedef struct spell { unsigned int id; char *sname; @@ -170,8 +163,8 @@ typedef struct sc_mage { int rank; /* Reihenfolge der Zauber */ int level; /* Stufe des Zaubers */ struct spell_component *components; - spell_f sp_function; - void (*patzer) (castorder *); + spell_f cast; + fumble_f patzer; } spell; /* ------------------------------------------------------------- */ diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 1272fad79..7dd5363ac 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1568,9 +1568,9 @@ static int parse_spells(xmlDocPtr doc) } assert(propValue != NULL); if (strcmp((const char *)propValue, "cast") == 0) { - sp->sp_function = (spell_f) fun; + sp->cast = (spell_f) fun; } else if (strcmp((const char *)propValue, "fumble") == 0) { - sp->patzer = (pspell_f) fun; + sp->patzer = (fumble_f) fun; } else { log_error(("unknown function type '%s' for spell %s\n", (const char *)propValue, sp->sname)); From ee7a35f293afe77a3c00e7246c0c8503f20f9a4f Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 9 May 2012 18:42:20 -0700 Subject: [PATCH 170/400] new_castorder is history --- src/kernel/battle.c | 3 ++- src/kernel/magic.c | 30 ++++-------------------------- src/kernel/magic.h | 3 --- 3 files changed, 6 insertions(+), 30 deletions(-) diff --git a/src/kernel/battle.c b/src/kernel/battle.c index 1e36806ee..aa6315eb3 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -1765,7 +1765,8 @@ void do_combatmagic(battle * b, combatmagic_t was) report_failed_spell(b, mage, sp); pay_spell(mage, sp, level, 1); } else { - co = new_castorder(fig, 0, sp, r, level, power, 0, 0, 0); + co = create_castorder(0, fig->unit, 0, sp, r, level, power, 0, 0, 0); + co->magician.fig = fig; add_castorder(&spellranks[sp->rank], co); } } diff --git a/src/kernel/magic.c b/src/kernel/magic.c index e048efc40..44cdee276 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -2095,25 +2095,6 @@ struct region * co_get_region(struct castorder * co) { return co->_rtarget; } -castorder *new_castorder(void *caster, unit * familiar, const spell * sp, region * r, - int lev, double force, int range, struct order * ord, spellparameter * p) -{ - castorder *corder = (castorder*)calloc(1, sizeof(castorder)); - unit * u = (unit *)caster; - - corder->magician.u = u; - corder->_familiar = familiar; - corder->sp = sp; - corder->level = lev; - corder->force = force; - corder->_rtarget = r ? r : (familiar ? familiar->region : (u ? u->region : 0)); - corder->distance = range; - corder->order = copy_order(ord); - corder->par = p; - - return corder; -} - castorder *create_castorder(castorder * co, unit *caster, unit * familiar, const spell * sp, region * r, int lev, double force, int range, struct order * ord, spellparameter * p) { @@ -2134,7 +2115,8 @@ castorder *create_castorder(castorder * co, unit *caster, unit * familiar, const void free_castorder(struct castorder *co) { - free_order(co->order); + if (co->par) free_spellparameter(co->par); + if (co->order) free_order(co->order); } /* Hänge c-order co an die letze c-order von cll an */ @@ -2157,11 +2139,7 @@ void free_castorders(castorder * co) while (co) { co2 = co; co = co->next; - if (co2->par) { - free_spellparameter(co2->par); - } - if (co2->order) - free_order(co2->order); + free_castorder(co2); free(co2); } return; @@ -2758,7 +2736,7 @@ static castorder *cast_cmd(unit * u, order * ord) return 0; } } - return new_castorder(caster, familiar, sp, target_r, level, 0, range, ord, + return create_castorder(0, caster, familiar, sp, target_r, level, 0, range, ord, args); } diff --git a/src/kernel/magic.h b/src/kernel/magic.h index eb0047e9f..cbeb63316 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -310,9 +310,6 @@ typedef struct sc_mage { struct castorder **end; } spellrank; - struct castorder *new_castorder(void *u, struct unit *familiar, const spell * sp, - struct region *r, int lev, double force, int distance, struct order *ord, - spellparameter * p); struct castorder *create_castorder(struct castorder * co, struct unit *caster, struct unit * familiar, const struct spell * sp, struct region * r, int lev, double force, int range, struct order * ord, struct spellparameter * p); From 882ac9e8e95e1762aaaf69b72b1cc703adf15b95 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 9 May 2012 20:23:00 -0700 Subject: [PATCH 171/400] pick the correct target region for spells cast by familiars. --- src/kernel/magic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 44cdee276..72f49289d 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -2035,7 +2035,7 @@ static spellparameter *add_spellparameter(region * target_r, unit * u, spobj = (spllprm *)malloc(sizeof(spllprm)); spobj->flag = 0; spobj->typ = SPP_REGION; - spobj->data.r = u->region; + spobj->data.r = target_r; j = 0; ++c; break; From 12c03644c4cbafcb04b3a61f1ff8079122fdebae Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 9 May 2012 20:30:26 -0700 Subject: [PATCH 172/400] u_hasspell only needs a mage, not a unit --- src/kernel/magic.c | 23 +++++++++++------------ src/kernel/magic.h | 2 +- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 72f49289d..2f26cddbd 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -491,7 +491,7 @@ void updatespelllist(unit * u) for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { spell *sp = (spell *) ql_get(ql, qi); if (sp->level <= sk) { - boolean know = u_hasspell(u, sp); + boolean know = u_hasspell(mage, sp); if (know || sp->magietyp == M_COMMON || know_school(u->faction, sp->magietyp)) { @@ -552,11 +552,9 @@ void add_spell(struct quicklist **slistp, spell * sp) } } -boolean u_hasspell(const struct unit *u, const struct spell *sp) +int u_hasspell(const sc_mage *mage, const struct spell *sp) { - sc_mage *mage = get_mage(u); - - return (mage) ? has_spell(mage->spells, sp) : false; + return mage ? has_spell(mage->spells, sp) : 0; } /* ------------------------------------------------------------- */ @@ -594,10 +592,11 @@ const spell *get_combatspell(const unit * u, int nr) void set_combatspell(unit * u, spell * sp, struct order *ord, int level) { - sc_mage *m = get_mage(u); + sc_mage *mage = get_mage(u); int i = -1; - if (!m) + if (!mage) { return; + } /* knowsspell prüft auf ist_magier, ist_spruch, kennt_spruch */ if (knowsspell(u->region, u, sp) == false) { @@ -605,7 +604,7 @@ void set_combatspell(unit * u, spell * sp, struct order *ord, int level) cmistake(u, ord, 173, MSG_MAGIC); return; } - if (!u_hasspell(u, sp)) { + if (!u_hasspell(mage, sp)) { /* Diesen Zauber kennt die Einheit nicht */ cmistake(u, ord, 169, MSG_MAGIC); return; @@ -623,8 +622,8 @@ void set_combatspell(unit * u, spell * sp, struct order *ord, int level) else if (sp->sptyp & POSTCOMBATSPELL) i = 2; assert(i >= 0); - m->combatspells[i].sp = sp; - m->combatspells[i].level = level; + mage->combatspells[i].sp = sp; + mage->combatspells[i].level = level; return; } @@ -944,13 +943,13 @@ boolean knowsspell(const region * r, const unit * u, const spell * sp) } /* Magier? */ mage = get_mage(u); - if (mage == NULL) { + if (!mage) { log_warning(("%s ist kein Magier, versucht aber zu zaubern.\n", unitname(u))); return false; } /* steht der Spruch in der Spruchliste? */ - if (!u_hasspell(u, sp)) { + if (!u_hasspell(mage, sp)) { /* ist der Spruch aus einem anderen Magiegebiet? */ if (know_school(u->faction, sp->magietyp)) { return false; diff --git a/src/kernel/magic.h b/src/kernel/magic.h index cbeb63316..9521be7a6 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -270,7 +270,7 @@ typedef struct sc_mage { void add_spell(struct quicklist **slistp, spell * sp); void add_spellname(sc_mage * mage, const spell * sp); /* fügt den Spruch mit der Id spellid der Spruchliste der Einheit hinzu. */ - boolean u_hasspell(const struct unit *u, const struct spell *sp); + int u_hasspell(const sc_mage *mage, const struct spell *sp); /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ void update_spellbook(struct faction *f, int level); void updatespelllist(struct unit *u); From 88acf3963859626c2742d583786e413591811e76 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 9 May 2012 23:22:54 -0700 Subject: [PATCH 173/400] spells that have no function in the xml file get one from an array, cleaning up and simplifying that code. --- src/kernel/reports.c | 2 +- src/kernel/xmlreader.c | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/kernel/reports.c b/src/kernel/reports.c index c723124c7..f793af654 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -2034,7 +2034,7 @@ static void eval_race(struct opstack **stack, const void *userdata) static void eval_order(struct opstack **stack, const void *userdata) { /* order -> string */ const struct order *ord = (const struct order *)opop(stack).v; - static char buf[256]; + static char buf[512]; size_t len; variant var; diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 7dd5363ac..5793066d6 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -30,6 +30,7 @@ without prior permission by the authors of Eressea. /* util includes */ #include +#include #include #include #include @@ -51,7 +52,6 @@ without prior permission by the authors of Eressea. static boolean gamecode_enabled = false; -void (*set_spelldata_cb) (struct spell * sp) = 0; static building_type *bt_get_or_create(const char *name) { if (name != NULL) { @@ -1481,6 +1481,8 @@ static int parse_spells(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); xmlXPathObjectPtr spells; + char zText[32]; + strcpy(zText, "fumble_"); /* reading eressea/spells/spell */ spells = xmlXPathEvalExpression(BAD_CAST "/eressea/spells/spell", xpath); @@ -1547,13 +1549,19 @@ static int parse_spells(xmlDocPtr doc) if (gamecode_enabled) { /* reading eressea/spells/spell/function */ + pf_generic cast = 0; + pf_generic fumble = 0; + xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "function", xpath); if (result->nodesetval->nodeNr == 0) { - /* deprecated style: this spell gets its' function from a callback */ - if (set_spelldata_cb) - set_spelldata_cb(sp); + cast = get_function(sp->sname); + if (!cast) { + log_error(("no spell cast function registered for '%s'\n", sp->sname)); + } + strlcpy(zText+7, sp->sname, sizeof(zText)-7); + fumble = get_function(zText); } else { for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; @@ -1568,9 +1576,9 @@ static int parse_spells(xmlDocPtr doc) } assert(propValue != NULL); if (strcmp((const char *)propValue, "cast") == 0) { - sp->cast = (spell_f) fun; + cast = fun; } else if (strcmp((const char *)propValue, "fumble") == 0) { - sp->patzer = (fumble_f) fun; + fumble = fun; } else { log_error(("unknown function type '%s' for spell %s\n", (const char *)propValue, sp->sname)); @@ -1578,6 +1586,8 @@ static int parse_spells(xmlDocPtr doc) xmlFree(propValue); } } + sp->cast = (spell_f)cast; + sp->patzer = (fumble_f)fumble; xmlXPathFreeObject(result); } From 08fc39cca7544912360b3d53b1f8e059721cc429 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 12 May 2012 13:16:07 -0700 Subject: [PATCH 174/400] deal with invalid border types (wisps are getting deleted from Eressea) and disabled spells (again, wisps). --- src/kernel/connection.c | 3 +- src/kernel/xmlreader.c | 94 ++++++++++++++++++++++------------------- 2 files changed, 53 insertions(+), 44 deletions(-) diff --git a/src/kernel/connection.c b/src/kernel/connection.c index 816e42a84..69606884d 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -676,7 +676,8 @@ int read_borders(struct storage *store) if (result < 0) return result; } - if (!to || !from) { + if (!type->name || !to || !from) { + log_warning(("erase invalid border '%s' between '%s' and '%s'\n", type->__name, regionname(from, 0), regionname(to, 0))); erase_border(b); } } diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 5793066d6..d2b822882 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1497,6 +1497,7 @@ static int parse_spells(xmlDocPtr doc) int k; spell_component *component; spell *sp; + int valid = 1; static int modes[] = { 0, PRECOMBATSPELL, COMBATSPELL, POSTCOMBATSPELL }; /* spellname */ @@ -1559,6 +1560,7 @@ static int parse_spells(xmlDocPtr doc) cast = get_function(sp->sname); if (!cast) { log_error(("no spell cast function registered for '%s'\n", sp->sname)); + valid = 0; } strlcpy(zText+7, sp->sname, sizeof(zText)-7); fumble = get_function(zText); @@ -1568,19 +1570,20 @@ static int parse_spells(xmlDocPtr doc) pf_generic fun; parse_function(node, &fun, &propValue); - if (fun == NULL) { - log_error(("unknown function name '%s' for spell '%s'\n", - (const char *)propValue, sp->sname)); - xmlFree(propValue); - continue; - } assert(propValue != NULL); if (strcmp((const char *)propValue, "cast") == 0) { - cast = fun; - } else if (strcmp((const char *)propValue, "fumble") == 0) { + if (fun) { + cast = fun; + valid = 1; + } else { + log_error(("unknown function name '%s' for spell '%s'\n", + (const char *)propValue, sp->sname)); + valid = 0; + } + } else if (fun && strcmp((const char *)propValue, "fumble") == 0) { fumble = fun; } else { - log_error(("unknown function type '%s' for spell %s\n", + log_error(("unknown function type '%s' for spell '%s'\n", (const char *)propValue, sp->sname)); } xmlFree(propValue); @@ -1591,45 +1594,50 @@ static int parse_spells(xmlDocPtr doc) xmlXPathFreeObject(result); } - /* reading eressea/spells/spell/resource */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "resource", xpath); - if (result->nodesetval->nodeNr) { - sp->components = - (spell_component *) malloc(sizeof(spell_component) * - (result->nodesetval->nodeNr + 1)); - sp->components[result->nodesetval->nodeNr].type = 0; - } - for (component = sp->components, k = 0; k != result->nodesetval->nodeNr; - ++k) { - const resource_type *rtype; - xmlNodePtr node = result->nodesetval->nodeTab[k]; - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue); - rtype = rt_find((const char *)propValue); - if (!rtype) { - log_error(("spell %s uses unknown component %s.\n", sp->sname, - (const char *)propValue)); - xmlFree(propValue); - continue; + if (valid) { + /* reading eressea/spells/spell/resource */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "resource", xpath); + if (result->nodesetval->nodeNr) { + sp->components = + (spell_component *) malloc(sizeof(spell_component) * + (result->nodesetval->nodeNr + 1)); + sp->components[result->nodesetval->nodeNr].type = 0; } - component->type = rtype; - xmlFree(propValue); - component->amount = xml_ivalue(node, "amount", 1); - component->cost = SPC_FIX; - propValue = xmlGetProp(node, BAD_CAST "cost"); - if (propValue != NULL) { - if (strcmp((const char *)propValue, "linear") == 0) { - component->cost = SPC_LINEAR; - } else if (strcmp((const char *)propValue, "level") == 0) { - component->cost = SPC_LEVEL; + for (component = sp->components, k = 0; k != result->nodesetval->nodeNr; + ++k) { + const resource_type *rtype; + xmlNodePtr node = result->nodesetval->nodeTab[k]; + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue); + rtype = rt_find((const char *)propValue); + if (!rtype) { + log_error(("spell %s uses unknown component %s.\n", sp->sname, + (const char *)propValue)); + xmlFree(propValue); + continue; } + component->type = rtype; xmlFree(propValue); + component->amount = xml_ivalue(node, "amount", 1); + component->cost = SPC_FIX; + propValue = xmlGetProp(node, BAD_CAST "cost"); + if (propValue != NULL) { + if (strcmp((const char *)propValue, "linear") == 0) { + component->cost = SPC_LINEAR; + } else if (strcmp((const char *)propValue, "level") == 0) { + component->cost = SPC_LEVEL; + } + xmlFree(propValue); + } + component++; } - component++; + xmlXPathFreeObject(result); + } + + if (valid) { + register_spell(sp); } - xmlXPathFreeObject(result); - register_spell(sp); } } From cf6a52bde7d3efbf9cf5aa267bd3e71e748ac505 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 12 May 2012 15:51:28 -0700 Subject: [PATCH 175/400] log an error for missing resources --- src/kernel/item.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/kernel/item.c b/src/kernel/item.c index 08d9b2ca4..322fcb3c5 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -354,7 +354,9 @@ resource_type *rt_find(const char *name) if (rtype->hashkey == hash && !strcmp(rtype->_name[0], name)) break; } - + if (!rtype) { + log_error(("rt_find: unknown resource '%s'\n", name)); + } return rtype; } From 8636762e738ca1995f893af18e6a21d04c37e02a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 12 May 2012 15:55:48 -0700 Subject: [PATCH 176/400] Add the missing ring of regeneration, even if it doesn't do anything (yet) --- res/common/items.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/res/common/items.xml b/res/common/items.xml index 2a96de46d..d867a3126 100644 --- a/res/common/items.xml +++ b/res/common/items.xml @@ -13,6 +13,10 @@ + + + + From e272a00994582a178e02f2feaf14fa1a471410b4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 14 May 2012 13:09:57 -0700 Subject: [PATCH 177/400] add test for that weird function-lookup module before I refactor it. --- src/tests.c | 2 ++ src/util/functions.c | 10 ---------- src/util/functions.h | 1 - src/util/functions_test.c | 23 +++++++++++++++++++++++ 4 files changed, 25 insertions(+), 11 deletions(-) create mode 100644 src/util/functions_test.c diff --git a/src/tests.c b/src/tests.c index 39d9cd0c9..fb736c744 100644 --- a/src/tests.c +++ b/src/tests.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -36,6 +37,7 @@ int RunAllTests(void) CuSuiteAddSuite(suite, get_base36_suite()); CuSuiteAddSuite(suite, get_quicklist_suite()); + CuSuiteAddSuite(suite, get_functions_suite()); CuSuiteAddSuite(suite, get_curse_suite()); CuSuiteAddSuite(suite, get_market_suite()); CuSuiteAddSuite(suite, get_move_suite()); diff --git a/src/util/functions.c b/src/util/functions.c index be5e069c1..bb24d0448 100644 --- a/src/util/functions.c +++ b/src/util/functions.c @@ -61,13 +61,3 @@ void register_function(pf_generic fun, const char *name) fl->name = strdup(name); functionlist = fl; } - -void list_registered_functions(void) -{ - function_list *fl = functionlist; - - while (fl) { - printf("%s\n", fl->name); - fl = fl->next; - } -} diff --git a/src/util/functions.h b/src/util/functions.h index 6ca496044..15bfca009 100644 --- a/src/util/functions.h +++ b/src/util/functions.h @@ -27,7 +27,6 @@ extern "C" { extern const char *get_functionname(pf_generic fun); extern pf_generic get_function(const char *name); extern void register_function(pf_generic fun, const char *name); - extern void list_registered_functions(void); #ifdef __cplusplus } diff --git a/src/util/functions_test.c b/src/util/functions_test.c new file mode 100644 index 000000000..c4c203385 --- /dev/null +++ b/src/util/functions_test.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include "functions.h" + + +static void test_all(CuTest * tc) +{ + pf_generic fun; + + fun = get_function("herpderp"); + CuAssertTrue(tc, !fun); + register_function((pf_generic)test_all, "herpderp"); + fun = get_function("herpderp"); + CuAssertTrue(tc, fun==(pf_generic)test_all); +} + +CuSuite *get_functions_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_all); + return suite; +} From 53bc4eee11cedbca0d541cb29cc8a4cc888cfc14 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 14 May 2012 14:16:02 -0700 Subject: [PATCH 178/400] remove viewrange, because it's not used very much (was used for one quest only) add my crit-bit implementation. to be used soon. --- src/attributes/viewrange.c | 75 ---------- src/attributes/viewrange.h | 35 ----- src/build/gamecode.c | 3 - src/build/util.c | 1 + src/gamecode/report.c | 1 - src/kernel.vcxproj | 2 - src/kernel.vcxproj.filters | 6 - src/kernel/reports.c | 9 +- src/util.vcxproj | 3 + src/util.vcxproj.filters | 9 ++ src/util/critbit.c | 286 +++++++++++++++++++++++++++++++++++++ src/util/critbit.h | 55 +++++++ 12 files changed, 357 insertions(+), 128 deletions(-) delete mode 100644 src/attributes/viewrange.c delete mode 100644 src/attributes/viewrange.h create mode 100644 src/util/critbit.c create mode 100644 src/util/critbit.h diff --git a/src/attributes/viewrange.c b/src/attributes/viewrange.c deleted file mode 100644 index be21c0877..000000000 --- a/src/attributes/viewrange.c +++ /dev/null @@ -1,75 +0,0 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include -#include "viewrange.h" - -/* util includes */ -#include -#include -#include - -/* libc includes */ -#include - -static void -a_writefunction(const struct attrib *a, const void *owner, - struct storage *store) -{ - const char *str = get_functionname((pf_generic) a->data.f); - store->w_tok(store, str); -} - -static int a_readfunction(struct attrib *a, void *owner, struct storage *store) -/* return 1 on success, 0 if attrib needs removal */ -{ - char buf[64]; - store->r_tok_buf(store, buf, sizeof(buf)); - a->data.f = get_function(buf); - return AT_READ_OK; -} - -attrib_type at_viewrange = { - "viewrange", - NULL, - NULL, - NULL, - a_writefunction, - a_readfunction, -}; - -attrib *add_viewrange(attrib ** alist, const char *function) -{ - attrib *a = a_find(*alist, &at_viewrange); - if (a == NULL) - a = a_add(alist, make_viewrange(function)); - return a; -} - -attrib *make_viewrange(const char *function) -{ - attrib *a = a_new(&at_viewrange); - a->data.f = get_function(function); - assert(a->data.f); - return a; -} - -void init_viewrange(void) -{ - at_register(&at_viewrange); -} diff --git a/src/attributes/viewrange.h b/src/attributes/viewrange.h deleted file mode 100644 index d5e8d57d4..000000000 --- a/src/attributes/viewrange.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ATTRIBUTE_VIEWRANGE -#define H_ATTRIBUTE_VIEWRANGE -#ifdef __cplusplus -extern "C" { -#endif - - extern struct attrib_type at_viewrange; - - extern struct attrib *make_viewrange(const char *function); - extern struct attrib *add_viewrange(struct attrib **alist, - const char *function); - extern void init_viewrange(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/build/gamecode.c b/src/build/gamecode.c index 63120bde0..db0797b27 100644 --- a/src/build/gamecode.c +++ b/src/build/gamecode.c @@ -1,4 +1,3 @@ -#include #include #include "stdafx.h" @@ -54,8 +53,6 @@ #include #include #include -#include - #include #include #include diff --git a/src/build/util.c b/src/build/util.c index 8882b9dbc..daddfbcdd 100644 --- a/src/build/util.c +++ b/src/build/util.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff --git a/src/gamecode/report.c b/src/gamecode/report.c index 9907dc182..e0ec3cd34 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -26,7 +26,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* attributes includes */ #include -#include #include #include #include diff --git a/src/kernel.vcxproj b/src/kernel.vcxproj index f71b97588..01d47c948 100644 --- a/src/kernel.vcxproj +++ b/src/kernel.vcxproj @@ -180,7 +180,6 @@ - @@ -281,7 +280,6 @@ - diff --git a/src/kernel.vcxproj.filters b/src/kernel.vcxproj.filters index e5f59818f..5d877a81e 100644 --- a/src/kernel.vcxproj.filters +++ b/src/kernel.vcxproj.filters @@ -288,9 +288,6 @@ attributes - - attributes - kernel @@ -594,8 +591,5 @@ attributes - - attributes - \ No newline at end of file diff --git a/src/kernel/reports.c b/src/kernel/reports.c index f793af654..4a098a25b 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -67,7 +67,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include boolean nocr = false; boolean nonr = false; @@ -1485,13 +1484,11 @@ static seen_region **prepare_report(faction * f) if (sr->mode > see_neighbour) { region *r = sr->r; plane *p = rplane(r); - void (*view) (struct seen_region **, region *, faction *) = view_default; + if (p && fval(p, PFL_SEESPECIAL)) { - attrib *a = a_find(p->attribs, &at_viewrange); - if (a) - view = - (void (*)(struct seen_region **, region *, faction *))a->data.f; + /* TODO: this is not very customizable */ + view = (strcmp(p->name, "Regatta")==0) ? view_regatta : view_neighbours; } view(f->seen, r, f); } diff --git a/src/util.vcxproj b/src/util.vcxproj index db7f763dc..f0b67638d 100644 --- a/src/util.vcxproj +++ b/src/util.vcxproj @@ -91,6 +91,7 @@ + @@ -125,12 +126,14 @@ + + diff --git a/src/util.vcxproj.filters b/src/util.vcxproj.filters index 685e18404..5f24407e5 100644 --- a/src/util.vcxproj.filters +++ b/src/util.vcxproj.filters @@ -104,6 +104,9 @@ Header Files + + Header Files + @@ -196,5 +199,11 @@ Source Files + + Header Files + + + Source Files + \ No newline at end of file diff --git a/src/util/critbit.c b/src/util/critbit.c new file mode 100644 index 000000000..a9df274f9 --- /dev/null +++ b/src/util/critbit.c @@ -0,0 +1,286 @@ +/* +Copyright (c) 2012, Enno Rehling + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#include "critbit.h" +#include +#include +#include + +/* see http://cr.yp.to/critbit.html */ +struct critbit_node { + void * child[2]; + size_t byte; + unsigned char mask; +}; + +#define EXTERNAL_NODE 0 +#define INTERNAL_NODE 1 + +static int decode_pointer(void ** ptr) +{ + ptrdiff_t numvalue = (char*)*ptr - (char*)0; + if (numvalue&1) { + *ptr = (void*)(numvalue-1); + return EXTERNAL_NODE; + } + return INTERNAL_NODE; +} + +void * make_external_node(const void * key, size_t keylen) +{ + char * data = (char *)malloc(sizeof(size_t) + keylen + 1); +#ifndef NDEBUG + ptrdiff_t numvalue = (char *)data - (char*)0; + assert((numvalue&1)==0); +#endif + memcpy(data, &keylen, sizeof(size_t)); + memcpy(data+sizeof(size_t), key, keylen); + return (void*)(data+1); +} + +static void from_external_node(void * ptr, void **key, size_t *keylen) +{ + unsigned char * bytes = (unsigned char *)ptr; +#ifndef NDEBUG + ptrdiff_t numvalue = bytes - (unsigned char*)0; + assert(numvalue && (numvalue&1)==0); + assert(key && keylen); +#endif + memcpy(keylen, bytes, sizeof(size_t)); + *key = bytes+sizeof(size_t); +} + +struct critbit_node * make_internal_node(void) +{ + struct critbit_node *node = (struct critbit_node *)malloc(sizeof(struct critbit_node)); + return node; +} + +static void cb_free_node(void * ptr) +{ + if (decode_pointer(&ptr)==INTERNAL_NODE) { + struct critbit_node * node = (struct critbit_node *)ptr; + cb_free_node(node->child[0]); + cb_free_node(node->child[1]); + free(node); + } else { + free(ptr); + } +} + +void cb_clear(critbit_tree * cb) +{ + if (cb->root) { + cb_free_node(cb->root); + } +} + +static int cb_less(const struct critbit_node * a, const struct critbit_node * b) +{ + return a->bytebyte || (a->byte==b->byte && a->mask < b->mask); +} + +int cb_insert(critbit_tree * cb, const void * key, size_t keylen) +{ + assert(cb); + assert(key); + if (!cb->root) { + cb->root = make_external_node(key, keylen); + return 1; + } else { + void ** iter = &cb->root; + struct critbit_node * prev = 0; + for (;;) { + void * ptr = *iter; + if (decode_pointer(&ptr)==INTERNAL_NODE) { + struct critbit_node * node = (struct critbit_node *)ptr; + unsigned char * bytes = (unsigned char *)key; + int branch = (keylen<=node->byte) ? 0 : ((1+((bytes[node->byte]|node->mask)&0xFF))>>8); + iter = &node->child[branch]; + prev = node; + } else { + unsigned char *iptr, *bytes = (unsigned char *)key, *ikey = bytes; + unsigned int mask, branch; + unsigned int byte = 0; + size_t len; + struct critbit_node * node = make_internal_node(); + + from_external_node(ptr, (void**)&iptr, &len); + + while (bytebyte = byte; + mask = *ikey ^ *iptr; /* these are all the bits that differ */ + mask |= mask>>1; + mask |= mask>>2; + mask |= mask>>4; /* now, every bit up to the MSB is set to 1 */ + mask = (mask&~(mask>>1))^0xFF; + node->mask = (unsigned char)mask; + + /* find the right place to insert, iff prev's crit-bit is later in the string than new crit-bit */ + if (prev && cb_less(node, prev)) { + for (iter = &cb->root;;) { + ptr = *iter; + if (decode_pointer(&ptr)==INTERNAL_NODE) { + struct critbit_node * next = (struct critbit_node *)ptr; + if (cb_less(next, node)) { + branch = ((1+((bytes[next->byte]|next->mask)&0xFF))>>8); + iter = &next->child[branch]; + } else { + break; + } + } else { + assert(!"should never get here"); + } + } + } + + branch = ((1+((*ikey|node->mask)&0xFF))>>8); + node->child[branch] = make_external_node(key, keylen); + node->child[1-branch] = *iter; + *iter = (void *)node; + + return CB_SUCCESS; + } + } + } +} + +static int cb_find_prefix_i(void * ptr, const void * key, size_t keylen, const char ** results, int numresults, int * offset, int next) +{ + assert(next<=numresults); + if (next==numresults) { + return next; + } else if (decode_pointer(&ptr)==INTERNAL_NODE) { + struct critbit_node * node = (struct critbit_node *)ptr; + next = cb_find_prefix_i(node->child[0], key, keylen, results, numresults, offset, next); + if (nextchild[1], key, keylen, results, numresults, offset, next); + } + } else { + /* reached an external node */ + const char * str; + size_t len; + + from_external_node(ptr, (void**)&str, &len); + if (len>=keylen && memcmp(key, str, keylen)==0) { + if (*offset>0) { + --*offset; + } else { + results[next++] = str; + } + } + } + return next; +} + +int cb_find_prefix(critbit_tree * cb, const void * key, size_t keylen, const char ** results, int numresults, int offset) +{ + void *ptr, *top = 0; + assert(key); + + if (!cb->root || !numresults) { + return 0; + } + for (ptr=cb->root, top=cb->root;;) { + void * last = ptr; + if (decode_pointer(&ptr)==INTERNAL_NODE) { + struct critbit_node * node = (struct critbit_node *)ptr; + int branch; + if (keylen<=node->byte) { + break; + } else { + unsigned char * bytes = (unsigned char *)key; + top = last; + branch = (1+((bytes[node->byte]|node->mask)&0xFF))>>8; + ptr = node->child[branch]; + } + } else { + /* we reached an external node before exhausting the key length */ + top = last; + break; + } + } + if (top) { + /* recursively add all children except the ones from [0-offset) of top to the results */ + return cb_find_prefix_i(top, key, keylen, results, numresults, &offset, 0); + } + return 0; +} + +int cb_find(critbit_tree * cb, const void * key, size_t keylen) +{ + void * str; + size_t len; + unsigned char * bytes = (unsigned char *)key; + void * ptr; + + assert(cb); + assert(key); + if (!cb->root) return CB_ENOMORE; + for (ptr=cb->root;decode_pointer(&ptr)==INTERNAL_NODE;) { + struct critbit_node * node = (struct critbit_node *)ptr; + int branch = (keylen<=node->byte) ? 0 : ((1+((bytes[node->byte]|node->mask)&0xFF))>>8); + ptr = node->child[branch]; + } + from_external_node(ptr, &str, &len); + return len==keylen && memcmp(key, str, keylen)==0; +} + +int cb_erase(critbit_tree * cb, const void * key, size_t keylen) +{ + void **iter = &cb->root; + void *ptr = *iter; + unsigned char * bytes = (unsigned char *)key; + + if (!cb->root) return 0; + + if (decode_pointer(&ptr)==EXTERNAL_NODE) { + free(ptr); + cb->root = 0; + return CB_SUCCESS; + } + + for (;;) { + struct critbit_node *parent = (struct critbit_node *)ptr; + int branch, type; + + branch = (keylen<=parent->byte) ? 0 : ((1+((bytes[parent->byte]|parent->mask)&0xFF))>>8); + + ptr = parent->child[branch]; + type = decode_pointer(&ptr); + if (type==INTERNAL_NODE) { + iter = &parent->child[branch]; + } else { + void * str; + size_t len; + from_external_node(ptr, &str, &len); + if (len==keylen && memcmp(key, str, len)==0) { + free(ptr); + *iter = parent->child[1-branch]; + return CB_SUCCESS; + } + return 0; + } + } +} diff --git a/src/util/critbit.h b/src/util/critbit.h new file mode 100644 index 000000000..3eb2b4842 --- /dev/null +++ b/src/util/critbit.h @@ -0,0 +1,55 @@ +/* +Copyright (c) 2012, Enno Rehling + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef _CRITBITT_H +#define _CRITBITT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef struct critbit_tree { + void * root; +} critbit_tree; + +#define CB_ENOMORE 0 +#define CB_SUCCESS 1 + +#define CRITBIT_TREE() { 0 } + +int cb_insert(critbit_tree * cb, const void * key, size_t keylen); +int cb_find(critbit_tree * cb, const void * key, size_t keylen); +int cb_erase(critbit_tree * cb, const void * key, size_t keylen); +int cb_find_prefix(critbit_tree * cb, const void * key, size_t keylen, const char ** results, int numresults, int offset); +void cb_clear(critbit_tree * cb); + +#define cb_insert_str(cb, key) \ + cb_insert(cb, (void *)key, strlen(key)+1) +#define cb_find_str(cb, key) \ + cb_find(cb, (void *)key, strlen(key)+1) +#define cb_erase_str(cb, key) \ + cb_erase(cb, (void *)key, strlen(key)+1) +#define cb_find_prefix_str(cb, key, results, numresults, offset) \ + cb_find_prefix(cb, (void *)key, strlen(key), results, numresults, offset) + + + +#ifdef __cplusplus +} +#endif +#endif From 3a8f682bea2af91308df33b229b4e527ab0b3f3d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 14 May 2012 14:16:56 -0700 Subject: [PATCH 179/400] remove now-obsolete function --- src/util/functions.c | 10 ---------- src/util/functions.h | 1 - 2 files changed, 11 deletions(-) diff --git a/src/util/functions.c b/src/util/functions.c index bb24d0448..54d52444e 100644 --- a/src/util/functions.c +++ b/src/util/functions.c @@ -43,16 +43,6 @@ pf_generic get_function(const char *name) return NULL; } -const char *get_functionname(pf_generic fun) -{ - function_list *fl = functionlist; - while (fl && fl->fun != fun) - fl = fl->next; - if (fl) - return fl->name; - return NULL; -} - void register_function(pf_generic fun, const char *name) { function_list *fl = (function_list *) malloc(sizeof(function_list)); diff --git a/src/util/functions.h b/src/util/functions.h index 15bfca009..abff99d99 100644 --- a/src/util/functions.h +++ b/src/util/functions.h @@ -24,7 +24,6 @@ extern "C" { typedef void (*pf_generic) (void); - extern const char *get_functionname(pf_generic fun); extern pf_generic get_function(const char *name); extern void register_function(pf_generic fun, const char *name); From 53b9de957c2343f36e0192c56229df983512f6ce Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 14 May 2012 16:36:17 -0700 Subject: [PATCH 180/400] putting the crit-bit tree to use. finding special region resources is faster this way than doing individual strcmp calls. --- src/bindings/bind_region.c | 86 ++++++++++++++++++++++++++------------ src/kernel/item.c | 2 +- src/util/critbit.c | 31 +++++++++++--- src/util/critbit.h | 10 ++--- 4 files changed, 90 insertions(+), 39 deletions(-) diff --git a/src/bindings/bind_region.c b/src/bindings/bind_region.c index 1b4244d81..fe3d69ea0 100644 --- a/src/bindings/bind_region.c +++ b/src/bindings/bind_region.c @@ -33,6 +33,7 @@ without prior permission by the authors of Eressea. #include #include +#include #include #include @@ -309,32 +310,58 @@ static int tolua_region_get_resourcelevel(lua_State * L) } #define LUA_ASSERT(c, s) if (!(c)) { log_error(("%s(%d): %s\n", __FILE__, __LINE__, (s))); return 0; } + +static critbit_tree * special_resources(void) +{ + static critbit_tree cb = CRITBIT_TREE(); + if (!cb.root) { + const char * special[] = { "seed", "sapling", "tree", "grave", "chaos", 0 }; + char buffer[32]; + int i; + for (i=0;special[i];++i) { + cb_new_kv(special[i], &i, sizeof(int), buffer); + cb_insert(&cb, buffer, strlen(special[i])+1+sizeof(int)); + } + } + return &cb; +} + static int tolua_region_get_resource(lua_State * L) { region *r; const char *type; const resource_type *rtype; int result = 0; + const void * matches; + critbit_tree * cb = special_resources(); r = (region *) tolua_tousertype(L, 1, 0); LUA_ASSERT(r != NULL, "invalid parameter"); type = tolua_tostring(L, 2, 0); LUA_ASSERT(type != NULL, "invalid parameter"); - rtype = rt_find(type); - if (!rtype) { - if (strcmp(type, "seed") == 0) - result = rtrees(r, 0); - if (strcmp(type, "sapling") == 0) - result = rtrees(r, 1); - if (strcmp(type, "tree") == 0) - result = rtrees(r, 2); - if (strcmp(type, "grave") == 0) + if (cb_find_prefix(cb, type, strlen(type)+1, &matches, 1, 0)) { + cb_get_kv(matches, &result, sizeof(result)); + switch (result) { + case 0: + case 1: + case 2: + result = rtrees(r, result); + break; + case 3: result = deathcount(r); - if (strcmp(type, "chaos") == 0) + break; + case 4: result = chaoscount(r); + break; + } } else { - result = region_getresource(r, rtype); + rtype = rt_find(type); + if (rtype) { + result = region_getresource(r, rtype); + } else { + result = -1; + } } tolua_pushnumber(L, (lua_Number) result); @@ -345,24 +372,29 @@ static int tolua_region_set_resource(lua_State * L) { region *r = (region *) tolua_tousertype(L, 1, 0); const char *type = tolua_tostring(L, 2, 0); - int value = (int)tolua_tonumber(L, 3, 0); - const resource_type *rtype = rt_find(type); + int result, value = (int)tolua_tonumber(L, 3, 0); + critbit_tree * cb = special_resources(); + const void * matches; - if (rtype != NULL) { - region_setresource(r, rtype, value); + if (cb_find_prefix(cb, type, strlen(type)+1, &matches, 1, 0)) { + cb_get_kv(matches, &result, sizeof(result)); + switch (result) { + case 0: + case 1: + case 2: + rsettrees(r, result, value); + break; + case 3: + deathcounts(r, value - deathcount(r)); + break; + case 4: + chaoscounts(r, value - chaoscount(r)); + break; + } } else { - if (strcmp(type, "seed") == 0) { - rsettrees(r, 0, value); - } else if (strcmp(type, "sapling") == 0) { - rsettrees(r, 1, value); - } else if (strcmp(type, "tree") == 0) { - rsettrees(r, 2, value); - } else if (strcmp(type, "grave") == 0) { - int fallen = value - deathcount(r); - deathcounts(r, fallen); - } else if (strcmp(type, "chaos") == 0) { - int fallen = value - chaoscount(r); - chaoscounts(r, fallen); + const resource_type *rtype = rt_find(type); + if (rtype != NULL) { + region_setresource(r, rtype, value); } } return 0; diff --git a/src/kernel/item.c b/src/kernel/item.c index 322fcb3c5..acb03744e 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -355,7 +355,7 @@ resource_type *rt_find(const char *name) break; } if (!rtype) { - log_error(("rt_find: unknown resource '%s'\n", name)); + log_warning(("rt_find: unknown resource '%s'\n", name)); } return rtype; } diff --git a/src/util/critbit.c b/src/util/critbit.c index a9df274f9..a4e55950b 100644 --- a/src/util/critbit.c +++ b/src/util/critbit.c @@ -127,7 +127,7 @@ int cb_insert(critbit_tree * cb, const void * key, size_t keylen) } if (byte==keylen && byte==len) { - return CB_ENOMORE; /* duplicate entry */ + return 0; /* duplicate entry */ } node->byte = byte; mask = *ikey ^ *iptr; /* these are all the bits that differ */ @@ -166,7 +166,7 @@ int cb_insert(critbit_tree * cb, const void * key, size_t keylen) } } -static int cb_find_prefix_i(void * ptr, const void * key, size_t keylen, const char ** results, int numresults, int * offset, int next) +static int cb_find_prefix_i(void * ptr, const void * key, size_t keylen, const void ** results, int numresults, int * offset, int next) { assert(next<=numresults); if (next==numresults) { @@ -194,7 +194,7 @@ static int cb_find_prefix_i(void * ptr, const void * key, size_t keylen, const c return next; } -int cb_find_prefix(critbit_tree * cb, const void * key, size_t keylen, const char ** results, int numresults, int offset) +int cb_find_prefix(critbit_tree * cb, const void * key, size_t keylen, const void ** results, int numresults, int offset) { void *ptr, *top = 0; assert(key); @@ -228,7 +228,7 @@ int cb_find_prefix(critbit_tree * cb, const void * key, size_t keylen, const cha return 0; } -int cb_find(critbit_tree * cb, const void * key, size_t keylen) +const void * cb_find(critbit_tree * cb, const void * key, size_t keylen) { void * str; size_t len; @@ -237,14 +237,17 @@ int cb_find(critbit_tree * cb, const void * key, size_t keylen) assert(cb); assert(key); - if (!cb->root) return CB_ENOMORE; + if (!cb->root) return 0; for (ptr=cb->root;decode_pointer(&ptr)==INTERNAL_NODE;) { struct critbit_node * node = (struct critbit_node *)ptr; int branch = (keylen<=node->byte) ? 0 : ((1+((bytes[node->byte]|node->mask)&0xFF))>>8); ptr = node->child[branch]; } from_external_node(ptr, &str, &len); - return len==keylen && memcmp(key, str, keylen)==0; + if (len==keylen && memcmp(key, str, keylen)==0) { + return str; + } + return 0; } int cb_erase(critbit_tree * cb, const void * key, size_t keylen) @@ -284,3 +287,19 @@ int cb_erase(critbit_tree * cb, const void * key, size_t keylen) } } } + +void cb_new_kv(const char *key, void * value, size_t len, void * dst) +{ + size_t keylen = strlen(key)+1; + if (dst!=key) { + memcpy(dst, key, keylen); + } + memcpy((char*)dst+keylen, value, len); +} + +void cb_get_kv(const void *kv, void * value, size_t len) +{ + const char * key = (const char *)kv; + size_t keylen = strlen(key)+1; + memcpy(value, key+keylen, len); +} diff --git a/src/util/critbit.h b/src/util/critbit.h index 3eb2b4842..9240c582d 100644 --- a/src/util/critbit.h +++ b/src/util/critbit.h @@ -27,27 +27,27 @@ typedef struct critbit_tree { void * root; } critbit_tree; -#define CB_ENOMORE 0 #define CB_SUCCESS 1 #define CRITBIT_TREE() { 0 } int cb_insert(critbit_tree * cb, const void * key, size_t keylen); -int cb_find(critbit_tree * cb, const void * key, size_t keylen); +const void * cb_find(critbit_tree * cb, const void * key, size_t keylen); int cb_erase(critbit_tree * cb, const void * key, size_t keylen); -int cb_find_prefix(critbit_tree * cb, const void * key, size_t keylen, const char ** results, int numresults, int offset); +int cb_find_prefix(critbit_tree * cb, const void * key, size_t keylen, const void ** results, int numresults, int offset); void cb_clear(critbit_tree * cb); #define cb_insert_str(cb, key) \ cb_insert(cb, (void *)key, strlen(key)+1) #define cb_find_str(cb, key) \ - cb_find(cb, (void *)key, strlen(key)+1) + (const char *)cb_find(cb, (void *)key, strlen(key)+1) #define cb_erase_str(cb, key) \ cb_erase(cb, (void *)key, strlen(key)+1) #define cb_find_prefix_str(cb, key, results, numresults, offset) \ cb_find_prefix(cb, (void *)key, strlen(key), results, numresults, offset) - +void cb_new_kv(const char *key, void * value, size_t len, void * dst); +void cb_get_kv(const void *kv, void * value, size_t len); #ifdef __cplusplus } From 2638f42ecaf7be96702d81976a845292df336d9e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 14 May 2012 17:02:15 -0700 Subject: [PATCH 181/400] putting the crit-bit tree to use. findingfunctions is faster this way than that hand-rolled list --- src/util/functions.c | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/util/functions.c b/src/util/functions.c index 54d52444e..7e22e7293 100644 --- a/src/util/functions.c +++ b/src/util/functions.c @@ -19,35 +19,32 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include "functions.h" +#include + /* libc includes */ +#include #include #include -typedef struct function_list { - struct function_list *next; - pf_generic fun; - const char *name; -} function_list; - -static function_list *functionlist; +static critbit_tree cb_functions; pf_generic get_function(const char *name) { - function_list *fl = functionlist; - if (name == NULL) - return NULL; - while (fl && strcmp(fl->name, name) != 0) - fl = fl->next; - if (fl) - return fl->fun; + const void * matches; + pf_generic result; + if (cb_find_prefix(&cb_functions, name, strlen(name)+1, &matches, 1, 0)) { + cb_get_kv(matches, &result, sizeof(result)); + return result; + } return NULL; } void register_function(pf_generic fun, const char *name) { - function_list *fl = (function_list *) malloc(sizeof(function_list)); - fl->next = functionlist; - fl->fun = fun; - fl->name = strdup(name); - functionlist = fl; + char buffer[64]; + size_t len = strlen(name); + + assert(len Date: Mon, 14 May 2012 20:08:11 -0700 Subject: [PATCH 182/400] test suite for the crazy stuff that umlaut.c does. --- src/tests.c | 4 +++- src/util.vcxproj | 1 + src/util.vcxproj.filters | 3 +++ src/util/functions_test.c | 8 +++---- src/util/umlaut.c | 4 ++-- src/util/umlaut_test.c | 46 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 src/util/umlaut_test.c diff --git a/src/tests.c b/src/tests.c index fb736c744..914e23512 100644 --- a/src/tests.c +++ b/src/tests.c @@ -5,8 +5,9 @@ #include "tests.h" #include -#include #include +#include +#include #include #include #include @@ -38,6 +39,7 @@ int RunAllTests(void) CuSuiteAddSuite(suite, get_base36_suite()); CuSuiteAddSuite(suite, get_quicklist_suite()); CuSuiteAddSuite(suite, get_functions_suite()); + CuSuiteAddSuite(suite, get_umlaut_suite()); CuSuiteAddSuite(suite, get_curse_suite()); CuSuiteAddSuite(suite, get_market_suite()); CuSuiteAddSuite(suite, get_move_suite()); diff --git a/src/util.vcxproj b/src/util.vcxproj index f0b67638d..d1695aeac 100644 --- a/src/util.vcxproj +++ b/src/util.vcxproj @@ -151,6 +151,7 @@ + diff --git a/src/util.vcxproj.filters b/src/util.vcxproj.filters index 5f24407e5..e47bd8168 100644 --- a/src/util.vcxproj.filters +++ b/src/util.vcxproj.filters @@ -205,5 +205,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/src/util/functions_test.c b/src/util/functions_test.c index c4c203385..1392662ed 100644 --- a/src/util/functions_test.c +++ b/src/util/functions_test.c @@ -4,20 +4,20 @@ #include "functions.h" -static void test_all(CuTest * tc) +static void test_functions(CuTest * tc) { pf_generic fun; fun = get_function("herpderp"); CuAssertTrue(tc, !fun); - register_function((pf_generic)test_all, "herpderp"); + register_function((pf_generic)test_functions, "herpderp"); fun = get_function("herpderp"); - CuAssertTrue(tc, fun==(pf_generic)test_all); + CuAssertTrue(tc, fun==(pf_generic)test_functions); } CuSuite *get_functions_suite(void) { CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, test_all); + SUITE_ADD_TEST(suite, test_functions); return suite; } diff --git a/src/util/umlaut.c b/src/util/umlaut.c index 6904e91b5..484ef12a6 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -88,7 +88,7 @@ void addtoken(tnode * root, const char *str, variant id) next = next->nexthash; if (!next) { tref *ref; - tnode *node = calloc(1, sizeof(tnode)); + tnode *node = (tnode *)calloc(1, sizeof(tnode)); if (ucs < 'a' || ucs > 'z') { lcs = towlower((wint_t) ucs); @@ -97,7 +97,7 @@ void addtoken(tnode * root, const char *str, variant id) ucs = towupper((wint_t) ucs); } - ref = malloc(sizeof(tref)); + ref = (tref *)malloc(sizeof(tref)); ref->ucs = ucs; ref->node = node; ref->nexthash = root->next[index]; diff --git a/src/util/umlaut_test.c b/src/util/umlaut_test.c new file mode 100644 index 000000000..c137a7ab7 --- /dev/null +++ b/src/util/umlaut_test.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include "umlaut.h" + + +static void test_umlaut(CuTest * tc) +{ + char umlauts[] = { 0xc3, 0xa4, 0xc3, 0xb6, 0xc3, 0xbc, 0xc3, 0x9f, 0 }; /* auml ouml uuml szlig nul */ + tnode tokens = { 0 }; + variant id; + int result; + + id.i = 1; + addtoken(&tokens, "herp", id); + id.i = 2; + addtoken(&tokens, "derp", id); + id.i = 3; + addtoken(&tokens, umlauts, id); + + result = findtoken(&tokens, "herp", &id); + CuAssertIntEquals(tc, E_TOK_SUCCESS, result); + CuAssertIntEquals(tc, 1, id.i); + + result = findtoken(&tokens, "derp", &id); + CuAssertIntEquals(tc, E_TOK_SUCCESS, result); + CuAssertIntEquals(tc, 2, id.i); + + result = findtoken(&tokens, umlauts, &id); + CuAssertIntEquals(tc, E_TOK_SUCCESS, result); + CuAssertIntEquals(tc, 3, id.i); + + result = findtoken(&tokens, "AEoeUEss", &id); + CuAssertIntEquals(tc, E_TOK_SUCCESS, result); + CuAssertIntEquals(tc, 3, id.i); + + result = findtoken(&tokens, "herpderp", &id); + CuAssertIntEquals(tc, E_TOK_NOMATCH, result); +} + +CuSuite *get_umlaut_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_umlaut); + return suite; +} From 2d2f5666343f58878130f4f721b5a79262087ad5 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 15 May 2012 00:06:27 -0700 Subject: [PATCH 183/400] A function to transliterate German special characters, for future use. --- src/util/umlaut.c | 60 +++++++++++++++++++++++++++++++++++++++++- src/util/umlaut.h | 2 ++ src/util/umlaut_test.c | 30 ++++++++++++++++++--- 3 files changed, 87 insertions(+), 5 deletions(-) diff --git a/src/util/umlaut.c b/src/util/umlaut.c index 484ef12a6..cc638a732 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -22,11 +22,69 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "log.h" #include "unicode.h" +#include #include #include #include #include +char * transliterate(char * out, size_t size, const char * in) +{ + const char *src = in; + char *dst = out; + + --size; /* need space for a final 0-byte */ + while (*src && size) { + size_t len; + const char * p = src; + while ((p+size>src) && *src && (~*src & 0x80)) { + *dst++ = (char)tolower(*src++); + } + len = src-p; + size -= len; + while (size>=2 && *src && (*src & 0x80)) { + int advance = 2; + if (src[0]=='\xc3') { + if (src[1]=='\xa4' || src[1]=='\x84') { + memcpy(dst, "ae", 2); + } else if (src[1]=='\xb6' || src[1]=='\x96') { + memcpy(dst, "oe", 2); + } else if (src[1]=='\xbc' || src[1]=='\x9c') { + memcpy(dst, "ue", 2); + } else if (src[1]=='\x9f') { + memcpy(dst, "ss", 2); + } else { + *dst++='?'; + advance = 0; + } + } else if (src[0]=='\xe1') { + if (src[1]=='\xba' && src[2]=='\x9e') { + memcpy(dst, "ss", 2); + ++src; + } else { + advance = 0; + } + } else { + advance = 0; + } + + if (advance) { + src+=advance; + dst+=advance; + size-=advance; + } else { + ucs4_t ucs; + unicode_utf8_to_ucs4(&ucs, src, &len); + src+=len; + *dst++='?'; + --size; + } + } + } + *dst = 0; + return *src ? 0 : out; +} + typedef struct tref { struct tref *nexthash; ucs4_t ucs; @@ -110,7 +168,7 @@ void addtoken(tnode * root, const char *str, variant id) #else index = lcs % NODEHASHSIZE; #endif - ref = malloc(sizeof(tref)); + ref = (tref *)malloc(sizeof(tref)); ref->ucs = lcs; ref->node = node; ref->nexthash = root->next[index]; diff --git a/src/util/umlaut.h b/src/util/umlaut.h index d19f35b2d..2910d0d48 100644 --- a/src/util/umlaut.h +++ b/src/util/umlaut.h @@ -40,6 +40,8 @@ extern "C" { void addtoken(struct tnode *root, const char *str, variant id); void freetokens(struct tnode *root); + char * transliterate(char * out, size_t size, const char * in); + typedef struct local_names { struct local_names *next; const struct locale *lang; diff --git a/src/util/umlaut_test.c b/src/util/umlaut_test.c index c137a7ab7..3b3995abc 100644 --- a/src/util/umlaut_test.c +++ b/src/util/umlaut_test.c @@ -1,28 +1,48 @@ #include +#include #include #include #include "umlaut.h" +static void test_transliterate(CuTest * tc) +{ + char buffer[32]; + + CuAssertStrEquals(tc, "", transliterate(buffer, sizeof(buffer), "")); + CuAssertStrEquals(tc, "herpderp", transliterate(buffer, sizeof(buffer), "herpderp")); + CuAssertStrEquals(tc, "herpderp", buffer); + + CuAssertStrEquals(tc, "herpderp", transliterate(buffer, sizeof(buffer), "HERPDERP")); + CuAssertStrEquals(tc, "haerpdaerp", transliterate(buffer, sizeof(buffer), "h\xc3\xa4rpd\xc3\xa4rp")); + CuAssertStrEquals(tc, "aeoeuess", transliterate(buffer, sizeof(buffer), "\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x9f")); + CuAssertStrEquals(tc, "aeoeuess", transliterate(buffer, sizeof(buffer), "\xc3\x84\xc3\x96\xc3\x9c\xe1\xba\x9e")); + CuAssertStrEquals(tc, 0, transliterate(buffer, 4, "herpderp")); +} static void test_umlaut(CuTest * tc) { - char umlauts[] = { 0xc3, 0xa4, 0xc3, 0xb6, 0xc3, 0xbc, 0xc3, 0x9f, 0 }; /* auml ouml uuml szlig nul */ + const char * umlauts = "\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x9f"; /* auml ouml uuml szlig nul */ tnode tokens = { 0 }; variant id; int result; + /* don't crash on an empty set */ + result = findtoken(&tokens, "herpderp", &id); + CuAssertIntEquals(tc, E_TOK_NOMATCH, result); + id.i = 1; - addtoken(&tokens, "herp", id); + addtoken(&tokens, "herpderp", id); id.i = 2; addtoken(&tokens, "derp", id); id.i = 3; addtoken(&tokens, umlauts, id); + /* we can find substrings if they are significant */ result = findtoken(&tokens, "herp", &id); CuAssertIntEquals(tc, E_TOK_SUCCESS, result); CuAssertIntEquals(tc, 1, id.i); - result = findtoken(&tokens, "derp", &id); + result = findtoken(&tokens, "DERP", &id); CuAssertIntEquals(tc, E_TOK_SUCCESS, result); CuAssertIntEquals(tc, 2, id.i); @@ -30,11 +50,12 @@ static void test_umlaut(CuTest * tc) CuAssertIntEquals(tc, E_TOK_SUCCESS, result); CuAssertIntEquals(tc, 3, id.i); + /* transliteration is the real magic */ result = findtoken(&tokens, "AEoeUEss", &id); CuAssertIntEquals(tc, E_TOK_SUCCESS, result); CuAssertIntEquals(tc, 3, id.i); - result = findtoken(&tokens, "herpderp", &id); + result = findtoken(&tokens, "herp-a-derp", &id); CuAssertIntEquals(tc, E_TOK_NOMATCH, result); } @@ -42,5 +63,6 @@ CuSuite *get_umlaut_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_umlaut); + SUITE_ADD_TEST(suite, test_transliterate); return suite; } From 77110158f9c86abaa247dd4a7bee7fe47239d39c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 15 May 2012 00:19:25 -0700 Subject: [PATCH 184/400] find_function is one of our more frequently called functions, and it can probably do with a little more performance. Let's see if this helps. --- src/util/translation.c | 51 ++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/src/util/translation.c b/src/util/translation.c index 37c86c20a..b5ff01c70 100644 --- a/src/util/translation.c +++ b/src/util/translation.c @@ -12,8 +12,10 @@ #include #include "translation.h" -#include "log.h" + #include "bsdstring.h" +#include "critbit.h" +#include "log.h" /* libc includes */ #include @@ -146,43 +148,33 @@ static variable *find_variable(const char *symbol) ** constant values **/ -typedef struct function { - struct function *next; - const char *symbol; - evalfun parse; -} function; - -static function *functions; +static struct critbit_tree functions = { 0 }; static void free_functions(void) { - while (functions) { - function *fun = functions; - functions = fun->next; - free(fun); - } + cb_clear(&functions); + functions.root = 0; } void add_function(const char *symbol, evalfun parse) { - function *fun = (function *) malloc(sizeof(function)); - - fun->parse = parse; - fun->symbol = symbol; - - fun->next = functions; - functions = fun; + char buffer[64]; + size_t len = strlen(symbol); + + assert(len+1+sizeof(parse)<=sizeof(buffer)); + cb_new_kv(symbol, &parse, sizeof(parse), buffer); + cb_insert(&functions, buffer, len+1+sizeof(parse)); } -static function *find_function(const char *symbol) +static evalfun find_function(const char *symbol) { - function *fun = functions; - while (fun) { - if (!strcmp(fun->symbol, symbol)) - break; - fun = fun->next; + void * matches; + if (cb_find_prefix(&functions, symbol, strlen(symbol)+1, &matches, 1, 0)) { + evalfun result; + cb_get_kv(matches, &result, sizeof(result)); + return result; } - return fun; + return 0; } static const char *parse(opstack **, const char *in, const void *); @@ -208,7 +200,8 @@ static const char *parse_symbol(opstack ** stack, const char *in, /* symbol will now contain the symbol name */ if (*in == '(') { /* it's a function we need to parse, start by reading the parameters */ - function *foo; + evalfun foo; + while (*in != ')') { in = parse(stack, ++in, userdata); /* will push the result on the stack */ if (in == NULL) @@ -220,7 +213,7 @@ static const char *parse_symbol(opstack ** stack, const char *in, log_error(("parser does not know about \"%s\" function.\n", symbol)); return NULL; } - foo->parse(stack, userdata); /* will pop parameters from stack (reverse order!) and push the result */ + foo(stack, userdata); /* will pop parameters from stack (reverse order!) and push the result */ } else { variable *var = find_variable(symbol); if (braces && *in == '}') { From 116a1ee8bae218013df8af3e2d369a2a50a47cf7 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 15 May 2012 15:04:23 -0700 Subject: [PATCH 185/400] remove tnode from anywhere, and use a void* instead, in preparation for a new findtoken implementation. this needs to have a good testing. lots of warning fixes for high warning levels in visual studio also --- src/build/external.c | 17 ++++++++---- src/build/lib.c | 7 +++++ src/build/stdafx.c | 1 + src/build/stdafx.h | 12 ++++++++ src/gamecode/archetype.c | 6 ++-- src/gamecode/creport.c | 2 +- src/gamecode/laws.c | 4 +-- src/gamecode/study.c | 8 +++--- src/kernel/alliance.c | 37 ++++++++++++------------- src/kernel/building.c | 3 +- src/kernel/command.c | 11 ++++---- src/kernel/command.h | 12 ++++---- src/kernel/config.c | 38 ++++++++++++------------- src/kernel/item.c | 6 ++-- src/kernel/magic.c | 2 +- src/kernel/magic.h | 2 +- src/kernel/move.c | 12 +++++--- src/kernel/plane.c | 21 +++++++------- src/kernel/region.c | 27 ++++++++---------- src/kernel/ship.c | 2 +- src/kernel/spell.c | 5 ++-- src/modules/gmcmd.c | 38 ++++++++++++------------- src/platform.h | 4 ++- src/util/language.c | 4 +-- src/util/language.h | 2 +- src/util/umlaut.c | 60 +++++++++++++++++++++++++--------------- src/util/umlaut.h | 15 +++------- src/util/umlaut_test.c | 14 +++++----- 28 files changed, 203 insertions(+), 169 deletions(-) diff --git a/src/build/external.c b/src/build/external.c index a0f46ad89..fd759fbe8 100644 --- a/src/build/external.c +++ b/src/build/external.c @@ -3,17 +3,24 @@ #include "stdafx.h" #pragma warning(push) -#pragma warning(disable: 4706) -#pragma warning(disable: 4244) -#pragma warning(disable: 4127) +#pragma warning(disable: 4706) /* '__STDC_VERSION__' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +#pragma warning(disable: 4244) /* '-=' : conversion from 'int' to 'u16', possible loss of data */ +#pragma warning(disable: 4127) /* conditional expression is constant */ +#pragma warning(disable: 4820) /* 'sqlite3_index_constraint' : '2' bytes padding added after data member 'usable' */ +#pragma warning(disable: 4668) /* is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +#pragma warning(disable: 4242) /* '=' : conversion from 'int' to 'ynVar', possible loss of data */ #include #pragma warning(pop) -#include - +#pragma warning(push) +#pragma warning(disable: 4668) /* is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ #include +#pragma warning(pop) + #include +#include + #ifndef DISABLE_TESTS #include #endif diff --git a/src/build/lib.c b/src/build/lib.c index 18624376a..a5e6ff13d 100644 --- a/src/build/lib.c +++ b/src/build/lib.c @@ -2,6 +2,13 @@ #include #include "stdafx.h" +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4668) +#include +#pragma warning(pop) +#endif + #include #include #include diff --git a/src/build/stdafx.c b/src/build/stdafx.c index fd4f341c7..da835cf2b 100644 --- a/src/build/stdafx.c +++ b/src/build/stdafx.c @@ -1 +1,2 @@ +#pragma warning(disable: 4206) #include "stdafx.h" diff --git a/src/build/stdafx.h b/src/build/stdafx.h index b0d94063d..b67bed8c1 100644 --- a/src/build/stdafx.h +++ b/src/build/stdafx.h @@ -1,2 +1,14 @@ +#ifdef _MSC_VER +#define VC_EXTRALEAN +#define WIN32_LEAN_AND_MEAN +#pragma warning(disable: 4820) +#pragma warning(push) +#pragma warning(disable: 4668) +#pragma warning(disable: 4255) +#include +#include +#pragma warning(pop) +#endif /* _MSC_VER */ + #include #include diff --git a/src/gamecode/archetype.c b/src/gamecode/archetype.c index 7ac51f338..942e1eca4 100644 --- a/src/gamecode/archetype.c +++ b/src/gamecode/archetype.c @@ -32,10 +32,10 @@ struct attrib_type at_recruit = { const struct archetype *find_archetype(const char *s, const struct locale *lang) { - struct tnode *tokens = get_translations(lang, UT_ARCHETYPES); + void **tokens = get_translations(lang, UT_ARCHETYPES); variant token; - if (findtoken(tokens, s, &token) == E_TOK_SUCCESS) { + if (tokens && findtoken(*tokens, s, &token) == E_TOK_SUCCESS) { return (const struct archetype *)token.v; } return NULL; @@ -53,7 +53,7 @@ void init_archetypes(void) for (; lang; lang = nextlocale(lang)) { variant var; archetype *arch = archetypes; - struct tnode *tokens = get_translations(lang, UT_ARCHETYPES); + void *tokens = get_translations(lang, UT_ARCHETYPES); for (; arch; arch = arch->next) { const char *s1, *s2; var.v = arch; diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index 154ceab55..4bac2a04d 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -512,7 +512,7 @@ static void render_messages(FILE * F, faction * f, message_list * msgs) #ifdef RENDER_CRMESSAGES char nrbuffer[1024 * 32]; nrbuffer[0] = '\0'; - if (nr_render(m->msg, f->locale, nrbuffer, sizeof(nrbuffer), f) >= 0) { + if (nr_render(m->msg, f->locale, nrbuffer, sizeof(nrbuffer), f) > 0) { fprintf(F, "MESSAGE %u\n", messagehash(m->msg)); fprintf(F, "%d;type\n", hash); fwritestr(F, nrbuffer); diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 4e6fd92be..50d6d39de 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -1452,7 +1452,7 @@ static void init_prefixnames(void) variant var; const char *pname = locale_string(lang, mkname("prefix", race_prefixes[key])); - if (findtoken(&in->names, pname, &var) == E_TOK_NOMATCH || var.i != key) { + if (findtoken(in->names, pname, &var) == E_TOK_NOMATCH || var.i != key) { var.i = key; addtoken(&in->names, pname, var); addtoken(&in->names, locale_string(lang, mkname("prefix", @@ -1500,7 +1500,7 @@ static int prefix_cmd(unit * u, struct order *ord) return 0; } - if (findtoken(&in->names, s, &var) == E_TOK_NOMATCH) { + if (findtoken(in->names, s, &var) == E_TOK_NOMATCH) { return 0; } else if (race_prefixes[var.i] == NULL) { cmistake(u, ord, 299, MSG_EVENT); diff --git a/src/gamecode/study.c b/src/gamecode/study.c index e4592383e..ae057dec0 100644 --- a/src/gamecode/study.c +++ b/src/gamecode/study.c @@ -64,19 +64,19 @@ static skill_t getskill(const struct locale *lang) magic_t getmagicskill(const struct locale * lang) { - struct tnode *tokens = get_translations(lang, UT_MAGIC); + void **tokens = get_translations(lang, UT_MAGIC); variant token; const char *s = getstrtoken(); - if (s && s[0]) { - if (findtoken(tokens, s, &token) == E_TOK_SUCCESS) { + if (tokens && s && s[0]) { + if (findtoken(*tokens, s, &token) == E_TOK_SUCCESS) { return (magic_t) token.i; } else { char buffer[3]; buffer[0] = s[0]; buffer[1] = s[1]; buffer[2] = '\0'; - if (findtoken(tokens, buffer, &token) == E_TOK_SUCCESS) { + if (findtoken(*tokens, buffer, &token) == E_TOK_SUCCESS) { return (magic_t) token.i; } } diff --git a/src/kernel/alliance.c b/src/kernel/alliance.c index aca0c35a8..032a96016 100644 --- a/src/kernel/alliance.c +++ b/src/kernel/alliance.c @@ -122,32 +122,32 @@ static void create_transaction(int type, unit * u, order * ord) transactions[type] = tr; } -static void cmd_kick(const tnode * tnext, void *data, struct order *ord) +static void cmd_kick(const void *tnext, void *data, struct order *ord) { create_transaction(ALLIANCE_KICK, (unit *) data, ord); } -static void cmd_leave(const tnode * tnext, void *data, struct order *ord) +static void cmd_leave(const void *tnext, void *data, struct order *ord) { create_transaction(ALLIANCE_LEAVE, (unit *) data, ord); } -static void cmd_transfer(const tnode * tnext, void *data, struct order *ord) +static void cmd_transfer(const void *tnext, void *data, struct order *ord) { create_transaction(ALLIANCE_TRANSFER, (unit *) data, ord); } -static void cmd_new(const tnode * tnext, void *data, struct order *ord) +static void cmd_new(const void *tnext, void *data, struct order *ord) { create_transaction(ALLIANCE_NEW, (unit *) data, ord); } -static void cmd_invite(const tnode * tnext, void *data, struct order *ord) +static void cmd_invite(const void *tnext, void *data, struct order *ord) { create_transaction(ALLIANCE_INVITE, (unit *) data, ord); } -static void cmd_join(const tnode * tnext, void *data, struct order *ord) +static void cmd_join(const void *tnext, void *data, struct order *ord) { create_transaction(ALLIANCE_JOIN, (unit *) data, ord); } @@ -290,7 +290,7 @@ static void execute(const struct syntaxtree *syntax, keyword_t kwd) unit *u = *up; if (u->number) { const struct locale *lang = u->faction->locale; - tnode *root = stree_find(syntax, lang); + void *root = stree_find(syntax, lang); order *ord; for (ord = u->orders; ord; ord = ord->next) { if (get_keyword(ord) == kwd) { @@ -321,15 +321,13 @@ void alliance_cmd(void) if (stree == NULL) { syntaxtree *slang = stree = stree_create(); while (slang) { - /* struct tnode * root = calloc(sizeof(tnode), 1); */ - struct tnode *leaf = calloc(sizeof(tnode), 1); - /* add_command(root, leaf, LOC(slang->lang, "alliance"), NULL); */ - add_command(leaf, NULL, LOC(slang->lang, "new"), &cmd_new); - add_command(leaf, NULL, LOC(slang->lang, "invite"), &cmd_invite); - add_command(leaf, NULL, LOC(slang->lang, "join"), &cmd_join); - add_command(leaf, NULL, LOC(slang->lang, "kick"), &cmd_kick); - add_command(leaf, NULL, LOC(slang->lang, "leave"), &cmd_leave); - add_command(leaf, NULL, LOC(slang->lang, "command"), &cmd_transfer); + void *leaf = 0; + add_command(&leaf, NULL, LOC(slang->lang, "new"), &cmd_new); + add_command(&leaf, NULL, LOC(slang->lang, "invite"), &cmd_invite); + add_command(&leaf, NULL, LOC(slang->lang, "join"), &cmd_join); + add_command(&leaf, NULL, LOC(slang->lang, "kick"), &cmd_kick); + add_command(&leaf, NULL, LOC(slang->lang, "leave"), &cmd_leave); + add_command(&leaf, NULL, LOC(slang->lang, "command"), &cmd_transfer); slang->root = leaf; slang = slang->next; } @@ -344,10 +342,9 @@ void alliancejoin(void) if (stree == NULL) { syntaxtree *slang = stree = stree_create(); while (slang) { - struct tnode *root = calloc(sizeof(tnode), 1); - struct tnode *leaf = calloc(sizeof(tnode), 1); - add_command(root, leaf, LOC(slang->lang, "alliance"), NULL); - add_command(leaf, NULL, LOC(slang->lang, "join"), &cmd_join); + void *leaf = 0; + add_command(&leaf, NULL, LOC(slang->lang, "join"), &cmd_join); + add_command(&slang->root, leaf, LOC(slang->lang, "alliance"), NULL); slang = slang->next; } } diff --git a/src/kernel/building.c b/src/kernel/building.c index e0dd53908..f7ac73f00 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -39,6 +39,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include @@ -384,7 +385,7 @@ const building_type *findbuildingtype(const char *name, } bnames = bn; } - if (findtoken(&bn->names, name, &type) == E_TOK_NOMATCH) + if (findtoken(bn->names, name, &type) == E_TOK_NOMATCH) return NULL; return (const building_type *)type.v; } diff --git a/src/kernel/command.c b/src/kernel/command.c index b03d6679c..ca3e2f294 100644 --- a/src/kernel/command.c +++ b/src/kernel/command.c @@ -29,10 +29,10 @@ typedef struct command { parser fun; - struct tnode *nodes; + void *nodes; } command; -tnode *stree_find(const syntaxtree * stree, const struct locale *lang) +void *stree_find(const syntaxtree * stree, const struct locale *lang) { while (stree) { if (stree->lang == lang) @@ -50,6 +50,7 @@ syntaxtree *stree_create(void) syntaxtree *stree = (syntaxtree *) malloc(sizeof(syntaxtree)); stree->lang = lang; stree->next = sroot; + stree->root = 0; sroot = stree; lang = nextlocale(lang); } @@ -57,7 +58,7 @@ syntaxtree *stree_create(void) } void -add_command(struct tnode *keys, struct tnode *tnext, +add_command(void **keys, void *tnext, const char *str, parser fun) { command *cmd = (command *) malloc(sizeof(command)); @@ -69,7 +70,7 @@ add_command(struct tnode *keys, struct tnode *tnext, addtoken(keys, str, var); } -static int do_command_i(const struct tnode *keys, void *u, struct order *ord) +static int do_command_i(const void *keys, struct unit *u, struct order *ord) { const char *c; variant var; @@ -88,7 +89,7 @@ static int do_command_i(const struct tnode *keys, void *u, struct order *ord) return E_TOK_NOMATCH; } -void do_command(const struct tnode *keys, void *u, struct order *ord) +void do_command(const void *keys, struct unit *u, struct order *ord) { init_tokens(ord); skip_token(); diff --git a/src/kernel/command.h b/src/kernel/command.h index 8bdcac745..30f02a085 100644 --- a/src/kernel/command.h +++ b/src/kernel/command.h @@ -16,23 +16,23 @@ extern "C" { #endif - struct tnode; struct locale; struct order; + struct unit; typedef struct syntaxtree { const struct locale *lang; - struct tnode *root; + void *root; struct syntaxtree *next; } syntaxtree; - typedef void (*parser) (const struct tnode *, void *, struct order *); - extern void add_command(struct tnode *troot, struct tnode *tnext, + typedef void (*parser) (const void *nodes, struct unit * u, struct order *); + extern void add_command(void **troot, void *tnext, const char *str, parser fun); - extern void do_command(const struct tnode *troot, void *u, struct order *); + extern void do_command(const void *troot, struct unit *u, struct order *); extern struct syntaxtree *stree_create(void); - extern struct tnode *stree_find(const struct syntaxtree *stree, + extern void *stree_find(const struct syntaxtree *stree, const struct locale *lang); #ifdef __cplusplus diff --git a/src/kernel/config.c b/src/kernel/config.c index 047b35da9..c29b9d03a 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -1327,11 +1327,11 @@ int getint(void) const struct race *findrace(const char *s, const struct locale *lang) { - struct tnode *tokens = get_translations(lang, UT_RACES); + void **tokens = get_translations(lang, UT_RACES); variant token; assert(lang); - if (findtoken(tokens, s, &token) == E_TOK_SUCCESS) { + if (tokens && findtoken(*tokens, s, &token) == E_TOK_SUCCESS) { return (const struct race *)token.v; } return NULL; @@ -1339,16 +1339,16 @@ const struct race *findrace(const char *s, const struct locale *lang) int findoption(const char *s, const struct locale *lang) { - struct tnode *tokens = get_translations(lang, UT_OPTIONS); + void **tokens = get_translations(lang, UT_OPTIONS); variant token; - if (findtoken(tokens, s, &token) == E_TOK_SUCCESS) { + if (findtoken(*tokens, s, &token) == E_TOK_SUCCESS) { return (direction_t) token.i; } return NODIRECTION; } -#if PTRIES +#ifdef PTRIES static struct trie_node *ptries[UT_MAX][4]; static struct trie_node **get_ptrie(const struct locale *lang, int type) @@ -1456,7 +1456,7 @@ ptrie_insert(struct trie_node **ptrie, const char *name, void *data, skill_t findskill(const char *s, const struct locale * lang) { -#if PTRIES +#ifdef PTRIES char lowercase[256]; int res = unicode_utf8_tolower(lowercase, sizeof(lowercase), s); if (res == 0) { @@ -1468,10 +1468,10 @@ skill_t findskill(const char *s, const struct locale * lang) } return NOSKILL; #else - struct tnode *tokens = get_translations(lang, UT_SKILLS); + void **tokens = get_translations(lang, UT_SKILLS); variant token; - if (findtoken(tokens, s, &token) == E_TOK_NOMATCH) + if (findtoken(*tokens, s, &token) == E_TOK_NOMATCH) return NOSKILL; return (skill_t) token.i; #endif @@ -1479,12 +1479,12 @@ skill_t findskill(const char *s, const struct locale * lang) keyword_t findkeyword(const char *s, const struct locale * lang) { - struct tnode *tokens = get_translations(lang, UT_KEYWORDS); + void **tokens = get_translations(lang, UT_KEYWORDS); variant token; if (*s == '@') s++; - if (findtoken(tokens, s, &token) == E_TOK_NOMATCH) + if (findtoken(*tokens, s, &token) == E_TOK_NOMATCH) return NOKEYWORD; if (global.disabled[token.i]) return NOKEYWORD; @@ -1493,10 +1493,10 @@ keyword_t findkeyword(const char *s, const struct locale * lang) param_t findparam(const char *s, const struct locale * lang) { - struct tnode *tokens = get_translations(lang, UT_PARAMS); + void **tokens = get_translations(lang, UT_PARAMS); variant token; - if (findtoken(tokens, s, &token) == E_TOK_NOMATCH) { + if (findtoken(*tokens, s, &token) == E_TOK_NOMATCH) { const building_type *btype = findbuildingtype(s, lang); if (btype != NULL) return (param_t) P_GEBAEUDE; @@ -2005,7 +2005,7 @@ void *gc_add(void *p) return p; } -static void init_directions(tnode * root, const struct locale *lang) +static void init_directions(void ** root, const struct locale *lang) { /* mit dieser routine kann man mehrere namen für eine direction geben, * das ist für die hexes ideal. */ @@ -2030,7 +2030,7 @@ static void init_directions(tnode * root, const struct locale *lang) NULL, NODIRECTION} }; int i; - struct tnode *tokens = get_translations(lang, UT_DIRECTIONS); + void **tokens = get_translations(lang, UT_DIRECTIONS); for (i = 0; dirs[i].direction != NODIRECTION; ++i) { variant token; @@ -2041,10 +2041,10 @@ static void init_directions(tnode * root, const struct locale *lang) direction_t finddirection(const char *s, const struct locale *lang) { - struct tnode *tokens = get_translations(lang, UT_DIRECTIONS); + void **tokens = get_translations(lang, UT_DIRECTIONS); variant token; - if (findtoken(tokens, s, &token) == E_TOK_SUCCESS) { + if (findtoken(*tokens, s, &token) == E_TOK_SUCCESS) { return (direction_t) token.i; } return NODIRECTION; @@ -2055,9 +2055,9 @@ static void init_locale(const struct locale *lang) variant var; int i; const struct race *rc; - struct tnode *tokens; + void **tokens; const terrain_type *terrain; -#if PTRIES +#ifdef PTRIES trie_node **ptrie; #endif @@ -2099,7 +2099,7 @@ static void init_locale(const struct locale *lang) var.i = i; addtoken(tokens, LOC(lang, parameters[i]), var); } -#if PTRIES +#ifdef PTRIES ptrie = get_ptrie(lang, UT_SKILLS); for (i = 0; i != MAXSKILLS; ++i) { skill_t sk = (skill_t) i; diff --git a/src/kernel/item.c b/src/kernel/item.c index acb03744e..f123d8e98 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -1093,7 +1093,7 @@ const resource_type *findresourcetype(const char *name, rnames = rn; } - if (findtoken(&rn->names, name, &token) == E_TOK_NOMATCH) + if (findtoken(rn->names, name, &token) == E_TOK_NOMATCH) return NULL; return (const resource_type *)token.v; } @@ -1131,7 +1131,7 @@ void init_itemnames(void) for (itl = itemtypes[key]; itl; itl = itl->next) { variant var; const char *iname = locale_string(lang, itl->rtype->_name[0]); - if (findtoken(&in->names, iname, &var) == E_TOK_NOMATCH + if (findtoken(in->names, iname, &var) == E_TOK_NOMATCH || var.v != itl) { var.v = (void *)itl; addtoken(&in->names, iname, var); @@ -1159,7 +1159,7 @@ const item_type *finditemtype(const char *name, const struct locale *lang) init_itemnames(); for (in = inames; in->lang != lang; in = in->next) ; } - if (findtoken(&in->names, name, &var) == E_TOK_NOMATCH) + if (findtoken(in->names, name, &var) == E_TOK_NOMATCH) return NULL; return (const item_type *)var.v; } diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 2f26cddbd..e871a14e8 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -539,7 +539,7 @@ void add_spellname(sc_mage * mage, const spell * sp) variant token; const char *n = spell_name(sp, names->lang); token.v = (void *)sp; - addtoken(names->tokens, n, token); + addtoken(&names->tokens, n, token); names = names->next; } } diff --git a/src/kernel/magic.h b/src/kernel/magic.h index 9521be7a6..621992991 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -108,7 +108,7 @@ typedef struct combatspell { typedef struct spell_names { struct spell_names *next; const struct locale *lang; - struct tnode * tokens; + void * tokens; } spell_names; typedef struct sc_mage { diff --git a/src/kernel/move.c b/src/kernel/move.c index b22420224..a3c1fffaf 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -1027,10 +1027,14 @@ static void cycle_route(order * ord, unit * u, int gereist) const struct locale *lang = u->faction->locale; pause = false; token = getstrtoken(); - d = finddirection(token, lang); - if (d == D_PAUSE) { - pause = true; - } else if (d == NODIRECTION) { + if (token && *token) { + d = finddirection(token, lang); + if (d == D_PAUSE) { + pause = true; + } else if (d == NODIRECTION) { + break; + } + } else { break; } if (cm < gereist) { diff --git a/src/kernel/plane.c b/src/kernel/plane.c index 0a1c856c3..111ebb675 100644 --- a/src/kernel/plane.c +++ b/src/kernel/plane.c @@ -190,16 +190,16 @@ adjust_coordinates(const faction * f, int *x, int *y, const plane * pl, ny -= ursprung_y(f, pl, r); } if (pl) { - nx -= plane_center_x(pl); - ny -= plane_center_y(pl); - } - - if (pl) { + int plx = plane_center_x(pl); + int ply = plane_center_y(pl); int width = plane_width(pl); int height = plane_height(pl); int width_2 = width / 2; int height_2 = height / 2; + nx -= plx; + ny -= ply; + if (nx < 0) nx = (width - (-nx) % width); if (nx > width_2) @@ -208,12 +208,13 @@ adjust_coordinates(const faction * f, int *x, int *y, const plane * pl, ny = (height - (-ny) % height); if (ny > height_2) ny -= height; - } - assert(!pl || nx <= pl->maxx - plane_center_x(pl)); - assert(!pl || nx >= pl->minx - plane_center_x(pl)); - assert(!pl || ny <= pl->maxy - plane_center_y(pl)); - assert(!pl || ny >= pl->miny - plane_center_y(pl)); + assert(nx <= pl->maxx - plx); + assert(nx >= pl->minx - plx); + assert(ny <= pl->maxy - ply); + assert(ny >= pl->miny - ply); + + } *x = nx; *y = ny; diff --git a/src/kernel/region.c b/src/kernel/region.c index 2b96e4baa..0221e8ee9 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -64,7 +64,7 @@ extern int dice_rand(const char *s); region *regions; -int get_maxluxuries() +int get_maxluxuries(void) { static int maxluxuries = -1; if (maxluxuries == -1) { @@ -219,7 +219,7 @@ void register_special_direction(const char *name) char *str = strdup(name); for (lang = locales; lang; lang = nextlocale(lang)) { - tnode *tokens = get_translations(lang, UT_SPECDIR); + void **tokens = get_translations(lang, UT_SPECDIR); const char *token = LOC(lang, name); if (token) { @@ -311,9 +311,9 @@ region *find_special_direction(const region * r, const char *token, d = (spec_direction *) (a->data.v); if (d->active) { - tnode *tokens = get_translations(lang, UT_SPECDIR); + void **tokens = get_translations(lang, UT_SPECDIR); variant var; - if (findtoken(tokens, token, &var) == E_TOK_SUCCESS) { + if (findtoken(*tokens, token, &var) == E_TOK_SUCCESS) { if (strcmp((const char *)var.v, d->keyword) == 0) { return findregion(d->x, d->y); } @@ -451,24 +451,19 @@ boolean pnormalize(int *x, int *y, const plane * pl) static region *rfindhash(int x, int y) { - unsigned int rid; - - rid = coor_hashkey(x, y); + unsigned int rid = coor_hashkey(x, y); + int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); #if HASH_STATISTICS ++hash_requests; #endif - if (rid >= 0) { - int key = HASH1(rid, RMAXHASH), gk = HASH2(rid, RMAXHASH); - while (regionhash[key] != NULL && (regionhash[key] == DELMARKER - || regionhash[key]->x != x || regionhash[key]->y != y)) { - key = (key + gk) % RMAXHASH; + while (regionhash[key] != NULL && (regionhash[key] == DELMARKER + || regionhash[key]->x != x || regionhash[key]->y != y)) { + key = (key + gk) % RMAXHASH; #if HASH_STATISTICS - ++hash_misses; + ++hash_misses; #endif - } - return regionhash[key]; } - return NULL; + return regionhash[key]; } void rhash(region * r) diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 3ce64196f..1721174e2 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -76,7 +76,7 @@ const ship_type *findshiptype(const char *name, const struct locale *lang) } snames = sn; } - if (findtoken(&sn->names, name, &var) == E_TOK_NOMATCH) + if (findtoken(sn->names, name, &var) == E_TOK_NOMATCH) return NULL; return (const ship_type *)var.v; } diff --git a/src/kernel/spell.c b/src/kernel/spell.c index 4e183029f..7602c4874 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -84,12 +84,12 @@ spell *get_spellfromtoken(sc_mage *mage, const char *name, names = (spell_names *)calloc(1, sizeof(spell_names)); names->next = mage->spellnames; names->lang = lang; - names->tokens = (tnode *)calloc(1, sizeof(tnode)); + names->tokens = 0; for (qi = 0, ql = mage->spells; ql; ql_advance(&ql, &qi, 1)) { spell *sp = (spell *) ql_get(ql, qi); const char *n = spell_name(sp, lang); token.v = sp; - addtoken(names->tokens, n, token); + addtoken(&names->tokens, n, token); } mage->spellnames = names; } @@ -105,7 +105,6 @@ spell *find_spellbyid(unsigned int id) quicklist *ql; int qi; - assert(id >= 0); if (id == 0) return NULL; for (qi = 0, ql = spells; ql; ql_advance(&ql, &qi, 1)) { diff --git a/src/modules/gmcmd.c b/src/modules/gmcmd.c index a038ae39e..b4592ec9e 100644 --- a/src/modules/gmcmd.c +++ b/src/modules/gmcmd.c @@ -129,7 +129,7 @@ attrib *make_atgmcreate(const struct item_type * itype) return a; } -static void gm_create(const tnode * tnext, void *data, struct order *ord) +static void gm_create(const void *tnext,void *data, struct order *ord) { unit *u = (unit *) data; int i; @@ -168,7 +168,7 @@ static boolean has_permission(const attrib * permissions, unsigned int key) ** GM: GATE ** requires: permission-key "gmgate" **/ -static void gm_gate(const tnode * tnext, void *data, struct order *ord) +static void gm_gate(const void *tnext,void *data, struct order *ord) { unit *u = (unit *) data; const struct plane *pl = rplane(u->region); @@ -202,7 +202,7 @@ static void gm_gate(const tnode * tnext, void *data, struct order *ord) ** GM: TERRAFORM ** requires: permission-key "gmterf" **/ -static void gm_terraform(const tnode * tnext, void *data, struct order *ord) +static void gm_terraform(const void *tnext,void *data, struct order *ord) { unit *u = (unit *) data; const struct plane *p = rplane(u->region); @@ -210,7 +210,7 @@ static void gm_terraform(const tnode * tnext, void *data, struct order *ord) int y = rel_to_abs(p, u->faction, getint(), 1); const char *c = getstrtoken(); variant token; - tnode *tokens = get_translations(u->faction->locale, UT_TERRAINS); + void **tokens = get_translations(u->faction->locale, UT_TERRAINS); region *r; pnormalize(&x, &y, p); r = findregion(x, y); @@ -225,7 +225,7 @@ static void gm_terraform(const tnode * tnext, void *data, struct order *ord) return; } - if (findtoken(tokens, c, &token) != E_TOK_NOMATCH) { + if (findtoken(*tokens, c, &token) != E_TOK_NOMATCH) { const terrain_type *terrain = (const terrain_type *)token.v; terraform_region(r, terrain); } @@ -235,7 +235,7 @@ static void gm_terraform(const tnode * tnext, void *data, struct order *ord) ** GM: TELEPORT ** requires: permission-key "gmtele" **/ -static void gm_teleport(const tnode * tnext, void *data, struct order *ord) +static void gm_teleport(const void *tnext,void *data, struct order *ord) { unit *u = (unit *) data; const struct plane *p = rplane(u->region); @@ -266,7 +266,7 @@ static void gm_teleport(const tnode * tnext, void *data, struct order *ord) ** GM: TELL PLANE ** requires: permission-key "gmmsgr" **/ -static void gm_messageplane(const tnode * tnext, void *data, struct order *ord) +static void gm_messageplane(const void *tnext,void *data, struct order *ord) { unit *gm = (unit *) data; const struct plane *p = rplane(gm->region); @@ -302,7 +302,7 @@ static void gm_messageplane(const tnode * tnext, void *data, struct order *ord) } static void -gm_messagefaction(const tnode * tnext, void *data, struct order *ord) +gm_messagefaction(const void *tnext,void *data, struct order *ord) { unit *gm = (unit *) data; int n = getid(); @@ -333,7 +333,7 @@ gm_messagefaction(const tnode * tnext, void *data, struct order *ord) ** GM: TELL REGION ** requires: permission-key "gmmsgr" **/ -static void gm_messageregion(const tnode * tnext, void *data, struct order *ord) +static void gm_messageregion(const void *tnext,void *data, struct order *ord) { unit *u = (unit *) data; const struct plane *p = rplane(u->region); @@ -359,7 +359,7 @@ static void gm_messageregion(const tnode * tnext, void *data, struct order *ord) ** GM: KILL UNIT ** requires: permission-key "gmkill" **/ -static void gm_killunit(const tnode * tnext, void *data, struct order *ord) +static void gm_killunit(const void *tnext,void *data, struct order *ord) { unit *u = (unit *) data; const struct plane *p = rplane(u->region); @@ -386,7 +386,7 @@ static void gm_killunit(const tnode * tnext, void *data, struct order *ord) ** GM: KILL FACTION ** requires: permission-key "gmmsgr" **/ -static void gm_killfaction(const tnode * tnext, void *data, struct order *ord) +static void gm_killfaction(const void *tnext,void *data, struct order *ord) { unit *u = (unit *) data; int n = getid(); @@ -420,7 +420,7 @@ static void gm_killfaction(const tnode * tnext, void *data, struct order *ord) ** GM: TELL ** requires: permission-key "gmmsgr" **/ -static void gm_messageunit(const tnode * tnext, void *data, struct order *ord) +static void gm_messageunit(const void *tnext,void *data, struct order *ord) { unit *u = (unit *) data; const struct plane *p = rplane(u->region); @@ -454,7 +454,7 @@ static void gm_messageunit(const tnode * tnext, void *data, struct order *ord) ** GM: GIVE ** requires: permission-key "gmgive" **/ -static void gm_give(const tnode * tnext, void *data, struct order *ord) +static void gm_give(const void *tnext,void *data, struct order *ord) { unit *u = (unit *) data; unit *to = findunit(getid()); @@ -489,7 +489,7 @@ static void gm_give(const tnode * tnext, void *data, struct order *ord) ** GM: TAKE ** requires: permission-key "gmtake" **/ -static void gm_take(const tnode * tnext, void *data, struct order *ord) +static void gm_take(const void *tnext,void *data, struct order *ord) { unit *u = (unit *) data; unit *to = findunit(getid()); @@ -524,7 +524,7 @@ static void gm_take(const tnode * tnext, void *data, struct order *ord) ** GM: SKILL ** requires: permission-key "gmskil" **/ -static void gm_skill(const tnode * tnext, void *data, struct order *ord) +static void gm_skill(const void *tnext,void *data, struct order *ord) { unit *u = (unit *) data; unit *to = findunit(getid()); @@ -552,10 +552,10 @@ static void gm_skill(const tnode * tnext, void *data, struct order *ord) } } -static tnode g_keys; -static tnode g_root; -static tnode g_tell; -static tnode g_kill; +static void * g_keys; +static void * g_root; +static void * g_tell; +static void * g_kill; void register_gmcmd(void) { diff --git a/src/platform.h b/src/platform.h index cdf87ea37..53b96b4a8 100644 --- a/src/platform.h +++ b/src/platform.h @@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifdef _MSC_VER # define VC_EXTRALEAN # define WIN32_LEAN_AND_MEAN -# include +# include # undef MOUSE_MOVED # define STDIO_CP 1252 /* log.c, convert to console character set */ # pragma warning (disable: 4201 4214 4514 4115 4711) @@ -35,6 +35,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # pragma warning(disable: 4100) /* warning C4100: : unreferenced formal parameter */ # pragma warning(disable: 4996) +/* is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */ +# pragma warning(disable: 4668) /* warning C4100: was declared deprecated */ #ifndef _CRT_SECURE_NO_DEPRECATE diff --git a/src/util/language.c b/src/util/language.c index ae41b69ed..d38c0ba0b 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -233,12 +233,12 @@ locale *nextlocale(const struct locale * lang) } typedef struct lstr { - tnode tokens[UT_MAX]; + void * tokens[UT_MAX]; } lstr; static lstr lstrs[MAXLOCALES]; -struct tnode *get_translations(const struct locale *lang, int index) +void ** get_translations(const struct locale *lang, int index) { assert(lang); assert(lang->index < MAXLOCALES diff --git a/src/util/language.h b/src/util/language.h index 42e1c81c3..3953a5712 100644 --- a/src/util/language.h +++ b/src/util/language.h @@ -63,7 +63,7 @@ extern "C" { UT_MAX }; - struct tnode *get_translations(const struct locale *lang, int index); + void ** get_translations(const struct locale *lang, int index); #ifdef __cplusplus } diff --git a/src/util/umlaut.c b/src/util/umlaut.c index cc638a732..7c4b99b19 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -28,6 +28,21 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +typedef struct tref { + struct tref *nexthash; + ucs4_t ucs; + struct tnode *node; +} tref; + +#define LEAF 1 /* leaf node for a word. always matches */ +#define SHARED 2 /* at least two words share the node */ + +typedef struct tnode { + struct tref *next[NODEHASHSIZE]; + unsigned char flags; + variant id; +} tnode; + char * transliterate(char * out, size_t size, const char * in) { const char *src = in; @@ -85,17 +100,9 @@ char * transliterate(char * out, size_t size, const char * in) return *src ? 0 : out; } -typedef struct tref { - struct tref *nexthash; - ucs4_t ucs; - struct tnode *node; -} tref; - -#define LEAF 1 /* leaf node for a word. always matches */ -#define SHARED 2 /* at least two words share the node */ - -void addtoken(tnode * root, const char *str, variant id) +void addtoken(void ** root, const char *str, variant id) { + tnode * tk; static const struct replace { /* STATIC_CONST: constant value */ ucs4_t ucs; const char str[3]; @@ -120,9 +127,15 @@ void addtoken(tnode * root, const char *str, variant id) }; assert(root); + if (!*root) { + tk = *root = calloc(1, sizeof(tnode)); + } else { + tk = *root; + } + assert(tk && tk==*root); if (!*str) { - root->id = id; - root->flags |= LEAF; + tk->id = id; + tk->flags |= LEAF; } else { tref *next; int ret, index, i = 0; @@ -139,9 +152,9 @@ void addtoken(tnode * root, const char *str, variant id) index = ucs % NODEHASHSIZE; #endif assert(index >= 0); - next = root->next[index]; - if (!(root->flags & LEAF)) - root->id = id; + next = tk->next[index]; + if (!(tk->flags & LEAF)) + tk->id = id; while (next && next->ucs != ucs) next = next->nexthash; if (!next) { @@ -158,8 +171,8 @@ void addtoken(tnode * root, const char *str, variant id) ref = (tref *)malloc(sizeof(tref)); ref->ucs = ucs; ref->node = node; - ref->nexthash = root->next[index]; - root->next[index] = ref; + ref->nexthash = tk->next[index]; + tk->next[index] = ref; /* try lower/upper casing the character, and try again */ if (ucs != lcs) { @@ -171,8 +184,8 @@ void addtoken(tnode * root, const char *str, variant id) ref = (tref *)malloc(sizeof(tref)); ref->ucs = lcs; ref->node = node; - ref->nexthash = root->next[index]; - root->next[index] = ref; + ref->nexthash = tk->next[index]; + tk->next[index] = ref; } next = ref; } else { @@ -180,7 +193,7 @@ void addtoken(tnode * root, const char *str, variant id) if ((next->node->flags & LEAF) == 0) next->node->id.v = NULL; /* why? */ } - addtoken(next->node, str + len, id); + addtoken(&next->node, str + len, id); while (replace[i].str[0]) { if (lcs == replace[i].ucs) { char zText[1024]; @@ -203,10 +216,11 @@ void freetokens(struct tnode *root) } } -int findtoken(const tnode * tk, const char *str, variant * result) +int findtoken(void * root, const char *str, variant * result) { - assert(tk); - if (!str || *str == 0) + const tnode * tk = (const tnode *)root; + + if (!tk || !str || *str == 0) return E_TOK_NOMATCH; do { diff --git a/src/util/umlaut.h b/src/util/umlaut.h index 2910d0d48..42997b50f 100644 --- a/src/util/umlaut.h +++ b/src/util/umlaut.h @@ -28,24 +28,17 @@ extern "C" { #define E_TOK_NOMATCH (-1) #define E_TOK_SUCCESS 0 #define NODEHASHSIZE 8 - struct tref; - typedef struct tnode { - struct tref *next[NODEHASHSIZE]; - unsigned char flags; - variant id; - } tnode; - - int findtoken(const struct tnode *tk, const char *str, variant * result); - void addtoken(struct tnode *root, const char *str, variant id); - void freetokens(struct tnode *root); + int findtoken(const void *tk, const char *str, variant * result); + void addtoken(void **root, const char *str, variant id); + void freetokens(void *root); char * transliterate(char * out, size_t size, const char * in); typedef struct local_names { struct local_names *next; const struct locale *lang; - struct tnode names; + void * names; } local_names; #ifdef __cplusplus diff --git a/src/util/umlaut_test.c b/src/util/umlaut_test.c index 3b3995abc..50d708dca 100644 --- a/src/util/umlaut_test.c +++ b/src/util/umlaut_test.c @@ -22,12 +22,12 @@ static void test_transliterate(CuTest * tc) static void test_umlaut(CuTest * tc) { const char * umlauts = "\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x9f"; /* auml ouml uuml szlig nul */ - tnode tokens = { 0 }; + void * tokens = 0; variant id; int result; /* don't crash on an empty set */ - result = findtoken(&tokens, "herpderp", &id); + result = findtoken(tokens, "herpderp", &id); CuAssertIntEquals(tc, E_TOK_NOMATCH, result); id.i = 1; @@ -38,24 +38,24 @@ static void test_umlaut(CuTest * tc) addtoken(&tokens, umlauts, id); /* we can find substrings if they are significant */ - result = findtoken(&tokens, "herp", &id); + result = findtoken(tokens, "herp", &id); CuAssertIntEquals(tc, E_TOK_SUCCESS, result); CuAssertIntEquals(tc, 1, id.i); - result = findtoken(&tokens, "DERP", &id); + result = findtoken(tokens, "DERP", &id); CuAssertIntEquals(tc, E_TOK_SUCCESS, result); CuAssertIntEquals(tc, 2, id.i); - result = findtoken(&tokens, umlauts, &id); + result = findtoken(tokens, umlauts, &id); CuAssertIntEquals(tc, E_TOK_SUCCESS, result); CuAssertIntEquals(tc, 3, id.i); /* transliteration is the real magic */ - result = findtoken(&tokens, "AEoeUEss", &id); + result = findtoken(tokens, "AEoeUEss", &id); CuAssertIntEquals(tc, E_TOK_SUCCESS, result); CuAssertIntEquals(tc, 3, id.i); - result = findtoken(&tokens, "herp-a-derp", &id); + result = findtoken(tokens, "herp-a-derp", &id); CuAssertIntEquals(tc, E_TOK_NOMATCH, result); } From 64f1ceecf5ed6b73fb1921bcc44372a858615282 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 16 May 2012 01:56:25 +0200 Subject: [PATCH 186/400] logging has a debug/info option now fixed a bug in the umluaut_test, was not initializing the tnode. --- src/modules/autoseed.c | 2 +- src/util/log.c | 45 +++++++++++++++++++++++++++++++++++++++++- src/util/log.h | 7 ++++--- src/util/translation.c | 2 +- src/util/umlaut_test.c | 3 ++- 5 files changed, 52 insertions(+), 7 deletions(-) diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c index 22906eba2..384ae4c22 100644 --- a/src/modules/autoseed.c +++ b/src/modules/autoseed.c @@ -205,7 +205,7 @@ int fix_demand(region * rd) for (rl = rlist; rl; rl = rl->next) { region *r = rl->data; if (!fval(r, RF_CHAOTIC)) { - log_info((LOG_INFO1, "fixing demand in %s\n", regionname(r, NULL))); + log_debug("fixing demand in %s\n", regionname(r, NULL)); } sale = mlux[rng_int() % maxlux]; if (sale) diff --git a/src/util/log.c b/src/util/log.c index ec93d625c..ab7f503f9 100644 --- a/src/util/log.c +++ b/src/util/log.c @@ -20,7 +20,7 @@ without prior permission by the authors of Eressea. #include /* TODO: set from external function */ -int log_flags = LOG_FLUSH | LOG_CPERROR | LOG_CPWARNING; +int log_flags = LOG_FLUSH | LOG_CPERROR | LOG_CPWARNING | LOG_CPDEBUG; #ifdef STDIO_CP static int stdio_codepage = STDIO_CP; #else @@ -157,6 +157,49 @@ static int check_dupe(const char *format, const char *type) return 0; } +void _log_debug(const char *format, ...) +{ + if (log_flags & LOG_CPDEBUG) { + int dupe = check_dupe(format, "DEBUG"); + + fflush(stdout); + if (!logfile) + logfile = stderr; + if (logfile != stderr) { + va_list marker; + fputs("DEBUG: ", logfile); + va_start(marker, format); + vfprintf(logfile, format, marker); + va_end(marker); + } + if (!dupe) { + va_list marker; + fputs("DEBUG: ", stderr); + va_start(marker, format); + if (stdio_codepage) { + char buffer[MAXLENGTH]; + char converted[MAXLENGTH]; + + vsnprintf(buffer, sizeof(buffer), format, marker); + if (cp_convert(buffer, converted, MAXLENGTH, stdio_codepage) == 0) { + fputs(converted, stderr); + } else { + /* fall back to non-converted output */ + va_end(marker); + va_start(marker, format); + vfprintf(stderr, format, marker); + } + } else { + vfprintf(stderr, format, marker); + } + va_end(marker); + } + if (log_flags & LOG_FLUSH) { + log_flush(); + } + } +} + void _log_warn(const char *format, ...) { if (log_flags & LOG_CPWARNING) { diff --git a/src/util/log.h b/src/util/log.h index a9e8eabd3..d7228222b 100644 --- a/src/util/log.h +++ b/src/util/log.h @@ -25,18 +25,19 @@ extern "C" { #define log_warning(x) _log_warn x #define log_error(x) _log_error x #define log_info(x) _log_info x +#define log_debug _log_debug /* use macros above instead of these: */ extern void _log_warn(const char *format, ...); extern void _log_error(const char *format, ...); + extern void _log_debug(const char *format, ...); extern void _log_info(unsigned int flag, const char *format, ...); #define LOG_FLUSH 0x01 #define LOG_CPWARNING 0x02 #define LOG_CPERROR 0x04 -#define LOG_INFO1 0x08 -#define LOG_INFO2 0x10 -#define LOG_INFO3 0x20 +#define LOG_CPDEBUG 0x08 +#define LOG_CPINFO 0x10 extern int log_flags; #ifdef __cplusplus diff --git a/src/util/translation.c b/src/util/translation.c index b5ff01c70..9c329592d 100644 --- a/src/util/translation.c +++ b/src/util/translation.c @@ -168,7 +168,7 @@ void add_function(const char *symbol, evalfun parse) static evalfun find_function(const char *symbol) { - void * matches; + const void * matches; if (cb_find_prefix(&functions, symbol, strlen(symbol)+1, &matches, 1, 0)) { evalfun result; cb_get_kv(matches, &result, sizeof(result)); diff --git a/src/util/umlaut_test.c b/src/util/umlaut_test.c index 3b3995abc..900f47f67 100644 --- a/src/util/umlaut_test.c +++ b/src/util/umlaut_test.c @@ -22,10 +22,11 @@ static void test_transliterate(CuTest * tc) static void test_umlaut(CuTest * tc) { const char * umlauts = "\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x9f"; /* auml ouml uuml szlig nul */ - tnode tokens = { 0 }; + tnode tokens; variant id; int result; + memset(&tokens, 0, sizeof(tokens)); /* don't crash on an empty set */ result = findtoken(&tokens, "herpderp", &id); CuAssertIntEquals(tc, E_TOK_NOMATCH, result); From b0959398d8767369c6a28ad0e61ffcff29f3efcd Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 16 May 2012 07:21:59 +0200 Subject: [PATCH 187/400] log library refactoring, first steps --- src/gamecode/laws.c | 2 +- src/gamecode/randenc.c | 2 +- src/kernel/battle.c | 6 +- src/kernel/config.c | 6 +- src/kernel/reports.c | 6 +- src/kernel/save.c | 33 ++--- src/modules/autoseed.c | 2 +- src/util/listbox.c | 12 +- src/util/log.c | 329 ++++++++++++++++++----------------------- src/util/log.h | 8 +- src/util/umlaut.c | 13 +- 11 files changed, 187 insertions(+), 232 deletions(-) diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 4e6fd92be..34627f8fb 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -3998,7 +3998,7 @@ void process(void) printf("- Step %u\n", prio); while (proc && proc->priority == prio) { if (proc->name && verbosity >= 1) - log_stdio(stdout, " - %s\n", proc->name); + log_printf(stdout, " - %s\n", proc->name); proc = proc->next; } diff --git a/src/gamecode/randenc.c b/src/gamecode/randenc.c index 0bdfbcd94..db5e40bac 100644 --- a/src/gamecode/randenc.c +++ b/src/gamecode/randenc.c @@ -1137,7 +1137,7 @@ static void demon_skillchanges(void) } if (sv->old > sv->level) { if (verbosity >= 3) { - log_printf("%s dropped from %u to %u:%u in %s\n", + log_printf(stdout, "%s dropped from %u to %u:%u in %s\n", unitname(u), sv->old, sv->level, sv->weeks, skillname(sv->id, NULL)); } diff --git a/src/kernel/battle.c b/src/kernel/battle.c index aa6315eb3..fb7b279ae 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -3814,7 +3814,7 @@ static int battle_report(battle * b) } if (verbosity > 0) - log_stdio(stdout, " %d", b->turn); + log_printf(stdout, " %d", b->turn); fflush(stdout); for (bf = b->factions; bf; bf = bf->next) { @@ -4493,7 +4493,7 @@ void do_battle(region * r) print_stats(b); /* gibt die Kampfaufstellung aus */ if (verbosity > 0) - log_stdio(stdout, "%s (%d, %d) : ", rname(r, default_locale), r->x, r->y); + log_printf(stdout, "%s (%d, %d) : ", rname(r, default_locale), r->x, r->y); for (; battle_report(b) && b->turn <= max_turns; ++b->turn) { if (bdebug) { @@ -4506,7 +4506,7 @@ void do_battle(region * r) } if (verbosity > 0) - log_stdio(stdout, "\n"); + log_printf(stdout, "\n"); /* Auswirkungen berechnen: */ aftermath(b); diff --git a/src/kernel/config.c b/src/kernel/config.c index 047b35da9..a340ff4d1 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -611,7 +611,7 @@ int count_skill(faction * f, skill_t sk) return n; } -int verbosity = 0; +int verbosity = 1; FILE *debug; @@ -743,7 +743,7 @@ void verify_data(void) if (u->number > UNIT_MAXSIZE) { if (lf != f->no) { lf = f->no; - log_stdio(stdout, "Partei %s:\n", factionid(f)); + log_printf(stdout, "Partei %s:\n", factionid(f)); } log_warning(("Einheit %s hat %d Personen\n", unitid(u), u->number)); } @@ -2364,7 +2364,7 @@ void remove_empty_factions(void) while (ur && ur->id != 0) ur = ur->next; if (verbosity >= 2) - log_stdio(stdout, "\t%s\n", factionname(f)); + log_printf(stdout, "\t%s\n", factionname(f)); /* Einfach in eine Datei schreiben und später vermailen */ diff --git a/src/kernel/reports.c b/src/kernel/reports.c index 4a098a25b..5bb42ccb4 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -1521,7 +1521,7 @@ int write_reports(faction * f, time_t ltime) errno = 0; if (verbosity >= 2) { - log_stdio(stdout, "Reports for %s:", factionname(f)); + log_printf(stdout, "Reports for %s:", factionname(f)); } for (; rtype != NULL; rtype = rtype->next) { if (f->options & rtype->flag) { @@ -1660,7 +1660,7 @@ int reports(void) char path[MAX_PATH]; if (verbosity >= 1) { - log_stdio(stdout, "Writing reports for turn %d:", turn); + log_printf(stdout, "Writing reports for turn %d:", turn); } nmr_warnings(); report_donations(); @@ -2207,7 +2207,7 @@ static void log_orders(const struct message *msg) if (msg->type->types[i]->copy == &var_copy_order) { const char *section = nr_section(msg); nr_render(msg, f ? f->locale : default_locale, buffer, sizeof(buffer), f); - log_printf("MESSAGE [%s]: %s\n", section, buffer); + log_debug("MESSAGE [%s]: %s\n", section, buffer); break; } } diff --git a/src/kernel/save.c b/src/kernel/save.c index e074554db..fcfc02291 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -462,7 +462,7 @@ int readorders(const char *filename) fclose(F); if (verbosity >= 1) puts("\n"); - log_printf(" %d Befehlsdateien gelesen\n", nfactions); + log_printf(stdout, " %d Befehlsdateien gelesen\n", nfactions); return 0; } @@ -1234,7 +1234,7 @@ faction *readfaction(struct storage * store) f->name = store->r_str(store); f->banner = store->r_str(store); - log_info((3, " - Lese Partei %s (%s)\n", f->name, factionid(f))); + log_printf(stdout, " - Lese Partei %s (%s)\n", f->name, factionid(f)); store->r_str_buf(store, email, sizeof(email)); if (set_email(&f->email, email) != 0) { @@ -1433,7 +1433,7 @@ int readgame(const char *filename, int mode, int backup) storage *store = &my_store; sprintf(path, "%s/%s", datapath(), filename); - log_printf("- reading game data from %s\n", filename); + log_printf(stdout, "- reading game data from %s\n", filename); if (backup) create_backup(path); @@ -1463,7 +1463,7 @@ int readgame(const char *filename, int mode, int backup) } a_read(store, &global.attribs, NULL); global.data_turn = turn = store->r_int(store); - log_info((1, " - reading turn %d\n", turn)); + log_printf(stdout, " - reading turn %d\n", turn); rng_init(turn); ++global.cookie; store->r_int(store); /* max_unique_id = */ @@ -1523,7 +1523,7 @@ int readgame(const char *filename, int mode, int backup) read_alliances(store); } n = store->r_int(store); - log_info((1, " - Einzulesende Parteien: %d\n", n)); + log_printf(stdout, " - Einzulesende Parteien: %d\n", n); fp = &factions; while (*fp) fp = &(*fp)->next; @@ -1551,15 +1551,14 @@ int readgame(const char *filename, int mode, int backup) assert(n < MAXREGIONS); if (rmax < 0) rmax = n; - log_info((1, " - Einzulesende Regionen: %d/%d\r", rmax, n)); + log_printf(stdout, " - Einzulesende Regionen: %d/%d\r", rmax, n); while (--n >= 0) { unit **up; int x = store->r_int(store); int y = store->r_int(store); if ((n & 0x3FF) == 0) { /* das spart extrem Zeit */ - log_info((2, " - Einzulesende Regionen: %d/%d * %d,%d \r", rmax, n, x, - y)); + log_printf(stdout, " - Einzulesende Regionen: %d/%d * %d,%d \r", rmax, n, x, y); } --rmax; @@ -1668,16 +1667,16 @@ int readgame(const char *filename, int mode, int backup) } } } - log_info((1, "\n")); + log_printf(stdout, "\n"); read_borders(store); store->close(store); /* Unaufgeloeste Zeiger initialisieren */ - log_info((1, "fixing unresolved references.\n")); + log_printf(stdout, "fixing unresolved references.\n"); resolve(); - log_info((1, "updating area information for lighthouses.\n")); + log_printf(stdout, "updating area information for lighthouses.\n"); for (r = regions; r; r = r->next) { if (r->flags & RF_LIGHTHOUSE) { building *b; @@ -1685,7 +1684,7 @@ int readgame(const char *filename, int mode, int backup) update_lighthouse(b); } } - log_info((1, "marking factions as alive.\n")); + log_printf(stdout, "marking factions as alive.\n"); for (f = factions; f; f = f->next) { if (f->flags & FFL_NPC) { f->alive = 1; @@ -1708,7 +1707,7 @@ int readgame(const char *filename, int mode, int backup) if (loadplane || maxregions >= 0) { remove_empty_factions(); } - log_info((1, "Done loading turn %d.\n", turn)); + log_printf(stdout, "Done loading turn %d.\n", turn); return 0; } @@ -1809,7 +1808,7 @@ int writegame(const char *filename, int mode) store->w_int(store, n); store->w_brk(store); - log_info((1, " - Schreibe %d Parteien...\n", n)); + log_printf(stdout, " - Schreibe %d Parteien...\n", n); for (f = factions; f; f = f->next) { writefaction(store, f); store->w_brk(store); @@ -1820,12 +1819,12 @@ int writegame(const char *filename, int mode) n = listlen(regions); store->w_int(store, n); store->w_brk(store); - log_info((1, " - Schreibe Regionen: %d \r", n)); + log_printf(stdout, " - Schreibe Regionen: %d \r", n); for (r = regions; r; r = r->next, --n) { /* plus leerzeile */ if ((n % 1024) == 0) { /* das spart extrem Zeit */ - log_info((2, " - Schreibe Regionen: %d \r", n)); + log_printf(stdout, " - Schreibe Regionen: %d \r", n); fflush(stdout); } store->w_brk(store); @@ -1876,7 +1875,7 @@ int writegame(const char *filename, int mode) store->close(store); - log_info((1, "\nOk.\n")); + log_printf(stdout, "\nOk.\n"); return 0; } diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c index 384ae4c22..79fa5e478 100644 --- a/src/modules/autoseed.c +++ b/src/modules/autoseed.c @@ -688,7 +688,7 @@ int autoseed(newfaction ** players, int nsize, int max_agediff) f = u->faction; fset(f, FFL_ISNEW); f->alliance = nextf->allies; - log_printf("New faction (%s), %s at %s\n", itoa36(f->no), + log_printf(stdout, "New faction (%s), %s at %s\n", itoa36(f->no), f->email, regionname(r, NULL)); if (f->subscription) { sql_print( diff --git a/src/util/listbox.c b/src/util/listbox.c index 0f573a2f8..0b7403860 100644 --- a/src/util/listbox.c +++ b/src/util/listbox.c @@ -82,21 +82,23 @@ list_selection *do_selection(list_selection * sel, const char *title, int i; int height = 0, width = (int)strlen(title) + 8; for (s = sel; s; s = s->next) { - if ((int)strlen(s->str) > width) + if ((int)strlen(s->str) > width) { width = (int)strlen(s->str); + } ++height; - if (verbosity >= 5) - log_info((1, "s %s w %d h %d\n", s->str, width, height)); + if (verbosity >= 5) { + log_printf(stdout, "s %s w %d h %d\n", s->str, width, height); + } } if (height == 0 || width == 0) - return NULL; + return 0; if (width + 3 > SX) width = SX - 4; if (height + 2 > SY) height = SY - 2; if (verbosity >= 5) - log_info((1, "w %d h %d\n", width, height)); + log_printf(stdout, "w %d h %d\n", width, height); wn = newwin(height + 2, width + 4, (SY - height - 2) / 2, (SX - width - 4) / 2); diff --git a/src/util/log.c b/src/util/log.c index ab7f503f9..a65175ae9 100644 --- a/src/util/log.c +++ b/src/util/log.c @@ -21,6 +21,8 @@ without prior permission by the authors of Eressea. /* TODO: set from external function */ int log_flags = LOG_FLUSH | LOG_CPERROR | LOG_CPWARNING | LOG_CPDEBUG; +int log_stderr = LOG_FLUSH | LOG_CPERROR | LOG_CPWARNING; + #ifdef STDIO_CP static int stdio_codepage = STDIO_CP; #else @@ -37,9 +39,9 @@ void log_flush(void) void log_puts(const char *str) { fflush(stdout); - if (!logfile) - logfile = stderr; - fputs(str, logfile); + if (logfile) { + fputs(str, logfile); + } } static int @@ -68,47 +70,6 @@ cp_convert(const char *format, char *buffer, size_t length, int codepage) return 0; } -void log_printf(const char *format, ...) -{ - va_list marker; - if (!logfile) - logfile = stderr; - va_start(marker, format); - vfprintf(logfile, format, marker); - va_end(marker); - if (log_flags & LOG_FLUSH) { - log_flush(); - } -} - -void log_stdio(FILE * io, const char *format, ...) -{ - va_list marker; - if (!logfile) - logfile = stderr; - va_start(marker, format); - if (stdio_codepage) { - char buffer[MAXLENGTH]; - char converted[MAXLENGTH]; - - vsnprintf(buffer, sizeof(buffer), format, marker); - if (cp_convert(buffer, converted, MAXLENGTH, stdio_codepage) == 0) { - fputs(converted, stderr); - } else { - /* fall back to non-converted output */ - va_end(marker); - va_start(marker, format); - vfprintf(io, format, marker); - } - } else { - vfprintf(io, format, marker); - } - va_end(marker); - if (log_flags & LOG_FLUSH) { - log_flush(); - } -} - void log_open(const char *filename) { if (logfile) @@ -118,7 +79,7 @@ void log_open(const char *filename) /* Get UNIX-style time and display as number and string. */ time_t ltime; time(<ime); - log_printf("===\n=== Logfile started at %s===\n", ctime(<ime)); + fprintf(logfile, "===\n=== Logfile started at %s===\n", ctime(<ime)); } } @@ -130,9 +91,9 @@ void log_close(void) /* Get UNIX-style time and display as number and string. */ time_t ltime; time(<ime); - log_printf("===\n=== Logfile closed at %s===\n\n", ctime(<ime)); + fprintf(logfile, "===\n=== Logfile closed at %s===\n\n", ctime(<ime)); + fclose(logfile); } - fclose(logfile); logfile = 0; } @@ -157,175 +118,165 @@ static int check_dupe(const char *format, const char *type) return 0; } +static void _log_write(FILE * stream, int codepage, const char * prefix, const char *format, va_list args) +{ + if (stream) { + fprintf(stream, "%s: ", prefix); + if (codepage) { + char buffer[MAXLENGTH]; + char converted[MAXLENGTH]; + + vsnprintf(buffer, sizeof(buffer), format, args); + if (cp_convert(buffer, converted, MAXLENGTH, codepage) == 0) { + fputs(converted, stream); + } else { + /* fall back to non-converted output */ + vfprintf(stream, format, args); + } + } else { + vfprintf(stream, format, args); + } + } +} + void _log_debug(const char *format, ...) { - if (log_flags & LOG_CPDEBUG) { - int dupe = check_dupe(format, "DEBUG"); + const char * prefix = "DEBUG"; + const int mask = LOG_CPDEBUG; - fflush(stdout); - if (!logfile) - logfile = stderr; - if (logfile != stderr) { - va_list marker; - fputs("DEBUG: ", logfile); - va_start(marker, format); - vfprintf(logfile, format, marker); - va_end(marker); - } + /* write to the logfile, always */ + if (logfile && (log_flags & mask)) { + va_list args; + va_start(args, format); + _log_write(logfile, 0, prefix, format, args); + va_end(args); + } + + /* write to stderr, if that's not the logfile already */ + if (logfile!=stderr && (log_stderr & mask)) { + int dupe = check_dupe(format, prefix); if (!dupe) { - va_list marker; - fputs("DEBUG: ", stderr); - va_start(marker, format); - if (stdio_codepage) { - char buffer[MAXLENGTH]; - char converted[MAXLENGTH]; - - vsnprintf(buffer, sizeof(buffer), format, marker); - if (cp_convert(buffer, converted, MAXLENGTH, stdio_codepage) == 0) { - fputs(converted, stderr); - } else { - /* fall back to non-converted output */ - va_end(marker); - va_start(marker, format); - vfprintf(stderr, format, marker); - } - } else { - vfprintf(stderr, format, marker); - } - va_end(marker); - } - if (log_flags & LOG_FLUSH) { - log_flush(); + va_list args; + va_start(args, format); + _log_write(stderr, stdio_codepage, prefix, format, args); + va_end(args); } } + if (log_flags & LOG_FLUSH) { + log_flush(); + } } void _log_warn(const char *format, ...) { - if (log_flags & LOG_CPWARNING) { - int dupe = check_dupe(format, "WARNING"); + const char * prefix = "WARNING"; + const int mask = LOG_CPWARNING; - fflush(stdout); - if (!logfile) - logfile = stderr; - if (logfile != stderr) { - va_list marker; - fputs("WARNING: ", logfile); - va_start(marker, format); - vfprintf(logfile, format, marker); - va_end(marker); - } + /* write to the logfile, always */ + if (logfile && (log_flags & mask)) { + va_list args; + va_start(args, format); + _log_write(logfile, 0, prefix, format, args); + va_end(args); + } + + /* write to stderr, if that's not the logfile already */ + if (logfile!=stderr && (log_stderr & mask)) { + int dupe = check_dupe(format, prefix); if (!dupe) { - va_list marker; - fputs("WARNING: ", stderr); - va_start(marker, format); - if (stdio_codepage) { - char buffer[MAXLENGTH]; - char converted[MAXLENGTH]; - - vsnprintf(buffer, sizeof(buffer), format, marker); - if (cp_convert(buffer, converted, MAXLENGTH, stdio_codepage) == 0) { - fputs(converted, stderr); - } else { - /* fall back to non-converted output */ - va_end(marker); - va_start(marker, format); - vfprintf(stderr, format, marker); - } - } else { - vfprintf(stderr, format, marker); - } - va_end(marker); - } - if (log_flags & LOG_FLUSH) { - log_flush(); + va_list args; + va_start(args, format); + _log_write(stderr, stdio_codepage, prefix, format, args); + va_end(args); } } + if (log_flags & LOG_FLUSH) { + log_flush(); + } } void _log_error(const char *format, ...) { - int dupe = check_dupe(format, "ERROR"); - fflush(stdout); - if (!logfile) - logfile = stderr; + const char * prefix = "ERROR"; + const int mask = LOG_CPERROR; - if (logfile != stderr) { - va_list marker; - fputs("ERROR: ", logfile); - va_start(marker, format); - vfprintf(logfile, format, marker); - va_end(marker); + /* write to the logfile, always */ + if (logfile && (log_flags & mask)) { + va_list args; + va_start(args, format); + _log_write(logfile, 0, prefix, format, args); + va_end(args); } - if (!dupe) { - if (logfile != stderr) { - if (log_flags & LOG_CPERROR) { - va_list marker; - fputs("ERROR: ", stderr); - va_start(marker, format); - if (stdio_codepage) { - char buffer[MAXLENGTH]; - char converted[MAXLENGTH]; - - vsnprintf(buffer, sizeof(buffer), format, marker); - if (cp_convert(buffer, converted, MAXLENGTH, stdio_codepage) == 0) { - fputs(converted, stderr); - } else { - /* fall back to non-converted output */ - va_end(marker); - va_start(marker, format); - vfprintf(stderr, format, marker); - } - } else { - vfprintf(stderr, format, marker); - } - va_end(marker); - } - log_flush(); + /* write to stderr, if that's not the logfile already */ + if (logfile!=stderr && (log_stderr & mask)) { + int dupe = check_dupe(format, prefix); + if (!dupe) { + va_list args; + va_start(args, format); + _log_write(stderr, stdio_codepage, prefix, format, args); + va_end(args); } } + if (log_flags & LOG_FLUSH) { + log_flush(); + } } -static unsigned int logfile_level = 0; -static unsigned int stderr_level = 1; - -void _log_info(unsigned int level, const char *format, ...) +void _log_info(const char *format, ...) { - va_list marker; - fflush(stdout); - if (!logfile) - logfile = stderr; - if (logfile_level >= level) { - fprintf(logfile, "INFO[%u]: ", level); - va_start(marker, format); - vfprintf(logfile, format, marker); - va_end(marker); - if (logfile != stderr) { - if (stderr_level >= level) { - fprintf(stderr, "INFO[%u]: ", level); - va_start(marker, format); - if (stdio_codepage) { - char buffer[MAXLENGTH]; - char converted[MAXLENGTH]; + const char * prefix = "INFO"; + const int mask = LOG_CPINFO; - vsnprintf(buffer, sizeof(buffer), format, marker); - if (cp_convert(buffer, converted, MAXLENGTH, stdio_codepage) == 0) { - fputs(converted, stderr); - } else { - /* fall back to non-converted output */ - va_end(marker); - va_start(marker, format); - vfprintf(stderr, format, marker); - } - } else { - vfprintf(stderr, format, marker); - } - va_end(marker); - } - if (log_flags & LOG_FLUSH) { - log_flush(); - } + /* write to the logfile, always */ + if (logfile && (log_flags & mask)) { + va_list args; + va_start(args, format); + _log_write(logfile, 0, prefix, format, args); + va_end(args); + } + + /* write to stderr, if that's not the logfile already */ + if (logfile!=stderr && (log_stderr & mask)) { + int dupe = check_dupe(format, prefix); + if (!dupe) { + va_list args; + va_start(args, format); + _log_write(stderr, stdio_codepage, prefix, format, args); + va_end(args); } } + if (log_flags & LOG_FLUSH) { + log_flush(); + } } + +void log_printf(FILE * io, const char *format, ...) +{ + const char * prefix = "INFO"; + const int mask = LOG_CPINFO; + + /* write to the logfile, always */ + if (logfile && (log_flags & mask)) { + int codepage = (logfile==stderr || logfile==stdout) ? stdio_codepage : 0; + va_list args; + va_start(args, format); + _log_write(logfile, codepage, prefix, format, args); + va_end(args); + } + + /* write to io, if that's not the logfile already */ + if (logfile!=io && (log_stderr & mask)) { + int dupe = check_dupe(format, prefix); + if (!dupe) { + va_list args; + va_start(args, format); + _log_write(io, stdio_codepage, prefix, format, args); + va_end(args); + } + } + if (log_flags & LOG_FLUSH) { + log_flush(); + } +} + diff --git a/src/util/log.h b/src/util/log.h index d7228222b..301469e06 100644 --- a/src/util/log.h +++ b/src/util/log.h @@ -16,22 +16,19 @@ extern "C" { #endif extern void log_open(const char *filename); - extern void log_printf(const char *str, ...); - extern void log_puts(const char *str); extern void log_close(void); extern void log_flush(void); - extern void log_stdio(FILE * io, const char *format, ...); #define log_warning(x) _log_warn x #define log_error(x) _log_error x -#define log_info(x) _log_info x #define log_debug _log_debug /* use macros above instead of these: */ extern void _log_warn(const char *format, ...); extern void _log_error(const char *format, ...); extern void _log_debug(const char *format, ...); - extern void _log_info(unsigned int flag, const char *format, ...); + extern void log_info(const char *format, ...); + extern void log_printf(FILE * ios, const char *format, ...); #define LOG_FLUSH 0x01 #define LOG_CPWARNING 0x02 @@ -40,6 +37,7 @@ extern "C" { #define LOG_CPINFO 0x10 extern int log_flags; + extern int log_stderr; #ifdef __cplusplus } #endif diff --git a/src/util/umlaut.c b/src/util/umlaut.c index cc638a732..92c39c950 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -203,12 +203,13 @@ void freetokens(struct tnode *root) } } -int findtoken(const tnode * tk, const char *str, variant * result) +int findtoken(const tnode * tk, const char *key, variant * result) { + const char * str = key; assert(tk); - if (!str || *str == 0) + if (!str || *str == 0) { return E_TOK_NOMATCH; - + } do { int index; const tref *ref; @@ -218,6 +219,7 @@ int findtoken(const tnode * tk, const char *str, variant * result) if (ret != 0) { /* encoding is broken. youch */ + log_debug("findtoken | encoding error in '%s'\n", key); return E_TOK_NOMATCH; } #if NODEHASHSIZE == 8 @@ -229,13 +231,16 @@ int findtoken(const tnode * tk, const char *str, variant * result) while (ref && ref->ucs != ucs) ref = ref->nexthash; str += len; - if (!ref) + if (!ref) { + log_debug("findtoken | token not found '%s'\n", key); return E_TOK_NOMATCH; + } tk = ref->node; } while (*str); if (tk) { *result = tk->id; return E_TOK_SUCCESS; } + log_debug("findtoken | token not found '%s'\n", key); return E_TOK_NOMATCH; } From 21a49b16604e68684c357b1bfaa3bb865973637d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 16 May 2012 09:11:49 +0200 Subject: [PATCH 188/400] log_rotate function to fight the increasingly huge logfiles --- src/util/log.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/util/log.c b/src/util/log.c index a65175ae9..75571ee77 100644 --- a/src/util/log.c +++ b/src/util/log.c @@ -31,6 +31,7 @@ static int stdio_codepage = 0; static FILE *logfile; #define MAXLENGTH 4096 /* because I am lazy, CP437 output is limited to this many chars */ +#define LOG_MAXBACKUPS 5 void log_flush(void) { fflush(logfile); @@ -70,10 +71,38 @@ cp_convert(const char *format, char *buffer, size_t length, int codepage) return 0; } +void log_rotate(const char *filename, int maxindex) +{ + int n; + if (access(filename, R_OK)==0) { + char buffer[2][MAX_PATH]; + int src = 1; + assert(strlen(filename) Date: Wed, 16 May 2012 09:24:12 +0200 Subject: [PATCH 189/400] optimize the number of failed findparam calls a little bit --- src/kernel/order.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/kernel/order.c b/src/kernel/order.c index 1ea62abf9..d595ebf18 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -377,6 +377,7 @@ boolean is_repeated(const order * ord) { keyword_t kwd = ORD_KEYWORD(ord); const struct locale *lang = ORD_LOCALE(ord); + const char * s; param_t param; switch (kwd) { @@ -405,11 +406,14 @@ boolean is_repeated(const order * ord) parser_pushstate(); init_tokens(ord); skip_token(); - param = getparam(lang); - parser_popstate(); - - if (param == P_SHIP) - return true; + s = getstrtoken(); + if (s[0]>'9') { + param = findparam(s, lang); + parser_popstate(); + if (param == P_SHIP) { + return true; + } + } break; case K_MAKE: @@ -421,11 +425,12 @@ boolean is_repeated(const order * ord) parser_pushstate(); init_tokens(ord); /* initialize token-parser */ skip_token(); - param = getparam(lang); - parser_popstate(); - - if (param != P_TEMP) - return true; + s = getstrtoken(); + if (s[0]>'9') { + param = findparam(s, lang); + parser_popstate(); + return param != P_TEMP; + } break; default: return false; From 0a6e18f34d25a3fc2ed9e1c95f0fd7bb95e44a41 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 16 May 2012 09:18:25 -0700 Subject: [PATCH 190/400] Spiking on findparam to use critbit as a findtoken replacement --- src/kernel/config.c | 33 +++++++++++++++++++++++++-------- src/platform.h | 1 + 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/kernel/config.c b/src/kernel/config.c index 9cc601274..a7ded8550 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -54,6 +54,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include @@ -1494,17 +1495,22 @@ keyword_t findkeyword(const char *s, const struct locale * lang) param_t findparam(const char *s, const struct locale * lang) { void **tokens = get_translations(lang, UT_PARAMS); - variant token; + int i; + param_t result = NOPARAM; + void * match; + char buffer[64]; + char * str = transliterate(buffer, sizeof(buffer)-sizeof(int), s); + critbit_tree *cb = (critbit_tree *)*tokens; - if (findtoken(*tokens, s, &token) == E_TOK_NOMATCH) { + if (str && cb_find_prefix(cb, str, strlen(str), &match, 1, 0)) { + cb_get_kv(match, &i, sizeof(int)); + result = (param_t)i; + } else { const building_type *btype = findbuildingtype(s, lang); if (btype != NULL) return (param_t) P_GEBAEUDE; - return NOPARAM; } - if (token.i == P_BUILDING) - return P_GEBAEUDE; - return (param_t) token.i; + return (result == P_BUILDING) ? P_GEBAEUDE : result; } param_t getparam(const struct locale * lang) @@ -2057,6 +2063,7 @@ static void init_locale(const struct locale *lang) const struct race *rc; void **tokens; const terrain_type *terrain; + char buffer[256]; #ifdef PTRIES trie_node **ptrie; #endif @@ -2096,8 +2103,18 @@ static void init_locale(const struct locale *lang) tokens = get_translations(lang, UT_PARAMS); for (i = 0; i != MAXPARAMS; ++i) { - var.i = i; - addtoken(tokens, LOC(lang, parameters[i]), var); + const char * key = LOC(lang, parameters[i]); + char * str = transliterate(buffer, sizeof(buffer)-sizeof(int), key); + if (str) { + critbit_tree * cb = (critbit_tree *)*tokens; + if (!cb) { + *tokens = cb = (critbit_tree *)calloc(1, sizeof(critbit_tree *)); + } + cb_new_kv(str, &i, sizeof(int), buffer); + cb_insert(cb, buffer, strlen(str)+1+sizeof(int)); + } else { + log_error(("could not transliterate param '%s'\n", key)); + } } #ifdef PTRIES ptrie = get_ptrie(lang, UT_SKILLS); diff --git a/src/platform.h b/src/platform.h index 53b96b4a8..d72545cc6 100644 --- a/src/platform.h +++ b/src/platform.h @@ -164,6 +164,7 @@ typedef struct stat stat_type; /* MSVC has _access, not access */ #ifndef access +#include # define access(f, m) _access(f, m) #endif #define HAVE_ACCESS From 02ab10d7234e0050adaf57e29a8f26a7f9fcbd5e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 16 May 2012 18:21:07 +0200 Subject: [PATCH 191/400] fix const correctness --- src/kernel/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/config.c b/src/kernel/config.c index a7ded8550..1de9d135d 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -1497,7 +1497,7 @@ param_t findparam(const char *s, const struct locale * lang) void **tokens = get_translations(lang, UT_PARAMS); int i; param_t result = NOPARAM; - void * match; + const void * match; char buffer[64]; char * str = transliterate(buffer, sizeof(buffer)-sizeof(int), s); critbit_tree *cb = (critbit_tree *)*tokens; From 7b6a719a628dbc527657711e2d57611021082201 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 16 May 2012 12:06:44 -0700 Subject: [PATCH 192/400] findparam improvements! removed findbuildingtype from findparam separate isparam() function that I can optimize later --- src/gamecode/laws.c | 17 +++++++---- src/gamecode/study.c | 6 ++-- src/kernel/build.c | 4 ++- src/kernel/config.c | 46 ++++++++++++++++++++--------- src/kernel/config.h | 6 ++-- src/kernel/magic.c | 6 ++-- src/kernel/order.c | 70 ++++++++++++++++---------------------------- src/kernel/order.h | 8 ++--- src/kernel/save.c | 4 +-- 9 files changed, 87 insertions(+), 80 deletions(-) diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index fdb7e768c..efab59d62 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -1530,12 +1530,14 @@ static int display_cmd(unit * u, struct order *ord) { building *b = u->building; char **s = NULL; + const char *str; region *r = u->region; init_tokens(ord); skip_token(); - switch (getparam(u->faction->locale)) { + str = getstrtoken(); + switch (findparam_ex(str, u->faction->locale)) { case P_BUILDING: case P_GEBAEUDE: if (!b) { @@ -1695,14 +1697,17 @@ static int name_cmd(unit * u, struct order *ord) char **s = NULL; param_t p; boolean foreign = false; + const char *str; init_tokens(ord); skip_token(); - p = getparam(u->faction->locale); + str = getstrtoken(); + p = findparam_ex(str, u->faction->locale); if (p == P_FOREIGN) { + str = getstrtoken(); foreign = true; - p = getparam(u->faction->locale); + p = findparam_ex(str, u->faction->locale); } switch (p) { @@ -1951,7 +1956,7 @@ static int mail_cmd(unit * u, struct order *ord) do { cont = 0; - switch (findparam(s, u->faction->locale)) { + switch (findparam_ex(s, u->faction->locale)) { case P_REGION: /* können alle Einheiten in der Region sehen */ s = getstrtoken(); @@ -2991,7 +2996,7 @@ static int renumber_cmd(unit * u, order * ord) init_tokens(ord); skip_token(); s = getstrtoken(); - switch (findparam(s, u->faction->locale)) { + switch (findparam_ex(s, u->faction->locale)) { case P_FACTION: s = getstrtoken(); @@ -3374,7 +3379,7 @@ static void new_units(void) if (get_keyword(makeord) == K_MAKE) { init_tokens(makeord); skip_token(); - if (getparam(u->faction->locale) == P_TEMP) { + if (isparam(getstrtoken(), u->faction->locale, P_TEMP)) { const char *token; char *name = NULL; int alias; diff --git a/src/gamecode/study.c b/src/gamecode/study.c index ae057dec0..a317d4b4d 100644 --- a/src/gamecode/study.c +++ b/src/gamecode/study.c @@ -416,13 +416,13 @@ int teach_cmd(unit * u, struct order *ord) token = getstrtoken(); /* Beginne die Fehlermeldung */ - if (findparam(token, u->faction->locale) != P_TEMP) { - uid = token; - } else { + if (isparam(token, u->faction->locale, P_TEMP)) { token = getstrtoken(); sprintf(tbuf, "%s %s", LOC(u->faction->locale, parameters[P_TEMP]), token); uid = tbuf; + } else { + uid = token; } ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unitnotfound_id", "id", uid)); diff --git a/src/kernel/build.c b/src/kernel/build.c index 805c5ad32..8ad6caaeb 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -1341,10 +1341,12 @@ void do_misc(region * r, boolean lasttry) param_t p; int id; unit *ulast = NULL; + const char * s; init_tokens(ord); skip_token(); - p = getparam(u->faction->locale); + s = getstrtoken(); + p = findparam_ex(s, u->faction->locale); id = getid(); switch (p) { diff --git a/src/kernel/config.c b/src/kernel/config.c index 1de9d135d..1e90fc778 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -1494,25 +1494,44 @@ keyword_t findkeyword(const char *s, const struct locale * lang) param_t findparam(const char *s, const struct locale * lang) { - void **tokens = get_translations(lang, UT_PARAMS); - int i; param_t result = NOPARAM; - const void * match; char buffer[64]; char * str = transliterate(buffer, sizeof(buffer)-sizeof(int), s); - critbit_tree *cb = (critbit_tree *)*tokens; - if (str && cb_find_prefix(cb, str, strlen(str), &match, 1, 0)) { - cb_get_kv(match, &i, sizeof(int)); - result = (param_t)i; - } else { + if (str) { + int i; + const void * match; + void **tokens = get_translations(lang, UT_PARAMS); + critbit_tree *cb = (critbit_tree *)*tokens; + if (cb_find_prefix(cb, str, strlen(str), &match, 1, 0)) { + cb_get_kv(match, &i, sizeof(int)); + result = (param_t)i; + } + } + return result; +} + +param_t findparam_ex(const char *s, const struct locale * lang) +{ + param_t result = findparam(s, lang); + + if (result==NOPARAM) { const building_type *btype = findbuildingtype(s, lang); if (btype != NULL) - return (param_t) P_GEBAEUDE; + return P_GEBAEUDE; } return (result == P_BUILDING) ? P_GEBAEUDE : result; } +int isparam(const char *s, const struct locale * lang, param_t param) +{ + if (s[0]>'@') { + param_t p = (param==P_GEBAEUDE) ? findparam_ex(s, lang) : findparam(s, lang); + return p==param; + } + return 0; +} + param_t getparam(const struct locale * lang) { return findparam(getstrtoken(), lang); @@ -1588,18 +1607,17 @@ static int read_newunitid(const faction * f, const region * r) int read_unitid(const faction * f, const region * r) { const char *s = getstrtoken(); - param_t param; /* Da s nun nur einen string enthaelt, suchen wir ihn direkt in der * paramliste. machen wir das nicht, dann wird getnewunit in s nach der * nummer suchen, doch dort steht bei temp-units nur "temp" drinnen! */ - param = findparam(s, f->locale); - if (param == P_TEMP) { + if (!s || *s == 0) { + return -1; + } + if (isparam(s, f->locale, P_TEMP)) { return read_newunitid(f, r); } - if (!s || *s == 0) - return -1; return atoi36((const char *)s); } diff --git a/src/kernel/config.h b/src/kernel/config.h index 8d6715fd6..36731c1f5 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -179,8 +179,10 @@ extern "C" { extern keyword_t findkeyword(const char *s, const struct locale *lang); - extern param_t findparam(const char *s, const struct locale *lang); - extern param_t getparam(const struct locale *lang); + param_t findparam(const char *s, const struct locale *lang); + param_t findparam_ex(const char *s, const struct locale * lang); + int isparam(const char *s, const struct locale * lang, param_t param); + param_t getparam(const struct locale *lang); extern int getid(void); #define unitid(x) itoa36((x)->no) diff --git a/src/kernel/magic.c b/src/kernel/magic.c index e871a14e8..5da9bc57f 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -1922,7 +1922,7 @@ addparam_unit(const char *const param[], spllprm ** spobjp, const unit * u, sppobj_t otype = SPP_UNIT; *spobjp = NULL; - if (findparam(param[0], u->faction->locale) == P_TEMP) { + if (isparam(param[0], u->faction->locale, P_TEMP)) { if (param[1] == NULL) { /* Fehler: Ziel vergessen */ cmistake(u, ord, 203, MSG_MAGIC); @@ -1981,7 +1981,6 @@ static spellparameter *add_spellparameter(region * target_r, unit * u, while (!fail && *c && i < size && param[i] != NULL) { spllprm *spobj = NULL; - param_t pword; int j = -1; switch (*c) { case '?': @@ -2028,8 +2027,7 @@ static spellparameter *add_spellparameter(region * target_r, unit * u, break; case 'k': ++c; - pword = findparam(param[i++], u->faction->locale); - switch (pword) { + switch (findparam_ex(param[i++], u->faction->locale)) { case P_REGION: spobj = (spllprm *)malloc(sizeof(spllprm)); spobj->flag = 0; diff --git a/src/kernel/order.c b/src/kernel/order.c index d595ebf18..9547d4446 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -373,12 +373,12 @@ order *parse_order(const char *s, const struct locale * lang) * \return true if the order is long * \sa is_exclusive(), is_repeated(), is_persistent() */ -boolean is_repeated(const order * ord) +int is_repeated(const order * ord) { keyword_t kwd = ORD_KEYWORD(ord); const struct locale *lang = ORD_LOCALE(ord); const char * s; - param_t param; + int result = 0; switch (kwd) { case K_CAST: @@ -399,7 +399,8 @@ boolean is_repeated(const order * ord) case K_BREED: case K_PIRACY: case K_PLANT: - return true; + result = 1; + break; case K_FOLLOW: /* FOLLOW is only a long order if we are following a ship. */ @@ -407,13 +408,8 @@ boolean is_repeated(const order * ord) init_tokens(ord); skip_token(); s = getstrtoken(); - if (s[0]>'9') { - param = findparam(s, lang); - parser_popstate(); - if (param == P_SHIP) { - return true; - } - } + result = isparam(s, lang, P_SHIP); + parser_popstate(); break; case K_MAKE: @@ -426,16 +422,13 @@ boolean is_repeated(const order * ord) init_tokens(ord); /* initialize token-parser */ skip_token(); s = getstrtoken(); - if (s[0]>'9') { - param = findparam(s, lang); - parser_popstate(); - return param != P_TEMP; - } + result = !isparam(s, lang, P_TEMP); + parser_popstate(); break; default: - return false; + result = 0; } - return false; + return result; } /** @@ -446,11 +439,11 @@ boolean is_repeated(const order * ord) * \return true if the order is long * \sa is_exclusive(), is_repeated(), is_persistent() */ -boolean is_exclusive(const order * ord) +int is_exclusive(const order * ord) { keyword_t kwd = ORD_KEYWORD(ord); const struct locale *lang = ORD_LOCALE(ord); - param_t param; + int result = 0; switch (kwd) { case K_MOVE: @@ -471,18 +464,16 @@ boolean is_exclusive(const order * ord) case K_BREED: case K_PIRACY: case K_PLANT: - return true; + result = 1; + break; case K_FOLLOW: /* FOLLOW is only a long order if we are following a ship. */ parser_pushstate(); init_tokens(ord); skip_token(); - param = getparam(lang); + result = isparam(getstrtoken(), lang, P_SHIP); parser_popstate(); - - if (param == P_SHIP) - return true; break; case K_MAKE: @@ -494,16 +485,13 @@ boolean is_exclusive(const order * ord) parser_pushstate(); init_tokens(ord); /* initialize token-parser */ skip_token(); - param = getparam(lang); + result = !isparam(getstrtoken(), lang, P_TEMP); parser_popstate(); - - if (param != P_TEMP) - return true; break; default: - return false; + result = 0; } - return false; + return result; } /** @@ -514,11 +502,11 @@ boolean is_exclusive(const order * ord) * \return true if the order is long * \sa is_exclusive(), is_repeated(), is_persistent() */ -boolean is_long(const order * ord) +int is_long(const order * ord) { keyword_t kwd = ORD_KEYWORD(ord); const struct locale *lang = ORD_LOCALE(ord); - param_t param; + int result = 0; switch (kwd) { case K_CAST: @@ -548,11 +536,8 @@ boolean is_long(const order * ord) parser_pushstate(); init_tokens(ord); skip_token(); - param = getparam(lang); + result = isparam(getstrtoken(), lang, P_SHIP); parser_popstate(); - - if (param == P_SHIP) - return true; break; case K_MAKE: @@ -564,16 +549,13 @@ boolean is_long(const order * ord) parser_pushstate(); init_tokens(ord); /* initialize token-parser */ skip_token(); - param = getparam(lang); + result = !isparam(getstrtoken(), lang, P_TEMP); parser_popstate(); - - if (param != P_TEMP) - return true; break; default: - return false; + result = 0; } - return false; + return result; } /** @@ -585,10 +567,10 @@ boolean is_long(const order * ord) * \return true if the order is persistent * \sa is_exclusive(), is_repeated(), is_persistent() */ -boolean is_persistent(const order * ord) +int is_persistent(const order * ord) { keyword_t kwd = ORD_KEYWORD(ord); - boolean persist = ord->_persistent != 0; + int persist = ord->_persistent != 0; switch (kwd) { case K_MOVE: case K_WEREWOLF: diff --git a/src/kernel/order.h b/src/kernel/order.h index 3dd97bcae..9e0ebeef5 100644 --- a/src/kernel/order.h +++ b/src/kernel/order.h @@ -51,10 +51,10 @@ extern "C" { extern keyword_t get_keyword(const order * ord); extern void set_order(order ** destp, order * src); extern char *getcommand(const order * ord); - extern boolean is_persistent(const order * ord); - extern boolean is_exclusive(const order * ord); - extern boolean is_repeated(const order * ord); - extern boolean is_long(const order * ord); + extern int is_persistent(const order * ord); + extern int is_exclusive(const order * ord); + extern int is_repeated(const order * ord); + extern int is_long(const order * ord); extern char *write_order(const order * ord, char *buffer, size_t size); diff --git a/src/kernel/save.c b/src/kernel/save.c index fcfc02291..a05445ab1 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -291,7 +291,7 @@ static unit *unitorders(FILE * F, int enc, struct faction *f) if (s == NULL) break; - if (s[0]) { + if (s[0] && s[0]!='@') { const char *stok = s; stok = parse_token(&stok); @@ -436,7 +436,7 @@ int readorders(const char *filename) b = getbuf(F, enc_gamedata); if (!b) break; - p = igetparam(b, lang); + p = (b[0]=='@') ? NOPARAM : igetparam(b, lang); } while ((p != P_UNIT || !f) && p != P_FACTION && p != P_NEXT && p != P_GAMENAME); break; From 9065334677f61cf4f05378d0e124f761ef818958 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 16 May 2012 13:07:28 -0700 Subject: [PATCH 193/400] eressea-pbem.de no longer exists improve default_order generation, save memory. --- src/eressea.c | 1 - src/kernel/config.c | 21 ++++++++++++++++++++- src/settings.h | 2 +- src/util/language.c | 27 +++++---------------------- src/util/language.h | 5 +++-- src/util/language_struct.h | 3 +-- tools/atoi36.c | 2 +- tools/namegen.c | 2 +- 8 files changed, 32 insertions(+), 31 deletions(-) diff --git a/src/eressea.c b/src/eressea.c index e637d2292..f3620b2a5 100644 --- a/src/eressea.c +++ b/src/eressea.c @@ -137,7 +137,6 @@ static void game_init(void) register_cr(); register_xr(); - debug_language("locales.log"); register_names(); register_resources(); register_buildings(); diff --git a/src/kernel/config.c b/src/kernel/config.c index 1e90fc778..d2b5d4541 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -3238,9 +3238,21 @@ void kernel_init(void) } } +static order * defaults[MAXLOCALES]; + order *default_order(const struct locale *lang) { - return parse_order(locale_string(lang, "defaultorder"), lang); + int i = locale_index(lang); + order *result = 0; + assert(inext; diff --git a/src/settings.h b/src/settings.h index 3333ec8de..fd0607625 100644 --- a/src/settings.h +++ b/src/settings.h @@ -1,6 +1,6 @@ /* vi: set ts=2: +-------------------+ Christian Schlittchen - | | Enno Rehling + | | Enno Rehling | Eressea PBEM host | Katja Zedel | (c) 1998 - 2003 | Henning Peters | | Ingo Wilken diff --git a/src/util/language.c b/src/util/language.c index d38c0ba0b..0616bdba8 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -34,10 +34,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. locale *default_locale; locale *locales; -unsigned int locale_hashkey(const locale * lang) +unsigned int locale_index(const locale * lang) { assert(lang); - return lang->hashkey; + return lang->index; } locale *find_locale(const char *name) @@ -49,7 +49,7 @@ locale *find_locale(const char *name) return l; } -static int nextlocaleindex = 0; +static unsigned int nextlocaleindex = 0; locale *make_locale(const char *name) { @@ -95,14 +95,6 @@ void make_locales(const char *str) } } -static FILE *s_debug = NULL; -static char *s_logfile = NULL; - -void debug_language(const char *log) -{ - s_logfile = strdup(log); -} - const char *locale_getstring(const locale * lang, const char *key) { unsigned int hkey = hashstring(key); @@ -156,21 +148,12 @@ const char *locale_string(const locale * lang, const char *key) find = find->nexthash; } if (!find) { - const char *s = key; log_warning(("missing translation for \"%s\" in locale %s\n", key, lang->name)); if (lang != default_locale) { - s = locale_string(default_locale, key); + return locale_string(default_locale, key); } - if (s_logfile) { - s_debug = s_debug ? s_debug : fopen(s_logfile, "w"); - if (s_debug) { - fprintf(s_debug, "%s;%s;%s\n", key, lang->name, s); - fflush(s_debug); - locale_setstring((struct locale *)lang, key, s); - } - } - return s; + return 0; } return find->str; } diff --git a/src/util/language.h b/src/util/language.h index 3953a5712..e851865a0 100644 --- a/src/util/language.h +++ b/src/util/language.h @@ -22,6 +22,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif +#define MAXLOCALES 3 + struct locale; /** managing multiple locales: **/ @@ -34,13 +36,12 @@ extern "C" { extern const char *locale_getstring(const struct locale *lang, const char *key); extern const char *locale_string(const struct locale *lang, const char *key); /* does fallback */ - extern unsigned int locale_hashkey(const struct locale *lang); + extern unsigned int locale_index(const struct locale *lang); extern const char *locale_name(const struct locale *lang); extern const char *mkname(const char *namespc, const char *key); extern char *mkname_buf(const char *namespc, const char *key, char *buffer); - extern void debug_language(const char *log); extern void make_locales(const char *str); #define LOC(lang, s) (lang?locale_string(lang, s):s) diff --git a/src/util/language_struct.h b/src/util/language_struct.h index 3b1d0e9bc..616998213 100644 --- a/src/util/language_struct.h +++ b/src/util/language_struct.h @@ -5,7 +5,6 @@ * feel that you need to include it, it's a sure sign that you're trying to * do something BAD. */ -#define MAXLOCALES 3 #define SMAXHASH 2048 typedef struct locale_str { unsigned int hashkey; @@ -15,7 +14,7 @@ typedef struct locale_str { } locale_str; typedef struct locale { - int index; + unsigned int index; struct locale *next; unsigned int hashkey; const char *name; diff --git a/tools/atoi36.c b/tools/atoi36.c index 678fa248d..b93fab3a4 100644 --- a/tools/atoi36.c +++ b/tools/atoi36.c @@ -1,6 +1,6 @@ /* vi: set ts=2: +-------------------+ Christian Schlittchen - | | Enno Rehling + | | Enno Rehling | Eressea PBEM host | Katja Zedel | (c) 1998 - 2001 | Henning Peters | | Ingo Wilken diff --git a/tools/namegen.c b/tools/namegen.c index 175e1cbe0..924524179 100644 --- a/tools/namegen.c +++ b/tools/namegen.c @@ -1,6 +1,6 @@ /* vi: set ts=2: +-------------------+ Christian Schlittchen - | | Enno Rehling + | | Enno Rehling | Eressea PBEM host | Katja Zedel | (c) 1998 - 2001 | Henning Peters | | Ingo Wilken From 14d62afb0decbbf48b23e587c7c1be9d5ec292cb Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 16 May 2012 15:52:37 -0700 Subject: [PATCH 194/400] rename _log_warn to log_warning and get rid of the cumbersome #define --- src/bindings/helpers.c | 3 +-- src/gamecode/give.c | 3 +-- src/gamecode/laws.c | 8 +++----- src/kernel/command.c | 2 +- src/kernel/config.c | 5 ++--- src/kernel/connection.c | 2 +- src/kernel/item.c | 2 +- src/kernel/magic.c | 6 ++---- src/kernel/message.c | 4 ++-- src/kernel/pool.c | 2 +- src/kernel/reports.c | 5 ++--- src/kernel/save.c | 23 ++++++++++------------- src/kernel/spell.c | 4 ++-- src/kernel/terrain.c | 2 +- src/kernel/textstore.c | 4 ++-- src/kernel/unit.c | 2 +- src/kernel/xmlreader.c | 6 ++---- src/triggers/timeout.c | 5 ++--- src/util/attrib.c | 4 ++-- src/util/bsdstring.h | 2 +- src/util/filereader.c | 2 +- src/util/language.c | 3 +-- src/util/log.c | 2 +- src/util/log.h | 3 +-- src/util/nrmessage.c | 6 ++---- src/util/parser.c | 8 +++----- src/util/xml.c | 4 ++-- 27 files changed, 51 insertions(+), 71 deletions(-) diff --git a/src/bindings/helpers.c b/src/bindings/helpers.c index c17ffeb55..bc99cc108 100644 --- a/src/bindings/helpers.c +++ b/src/bindings/helpers.c @@ -271,8 +271,7 @@ static void lua_initfamiliar(unit * u) lua_pop(L, 1); } } else { - log_warning(("familiar(%s) calling '%s': not a function.\n", - unitname(u), fname)); + log_warning("familiar(%s) calling '%s': not a function.\n", unitname(u), fname); lua_pop(L, 1); } diff --git a/src/gamecode/give.c b/src/gamecode/give.c index 25e735812..bee31ab33 100644 --- a/src/gamecode/give.c +++ b/src/gamecode/give.c @@ -214,8 +214,7 @@ void give_men(int n, unit * u, unit * u2, struct order *ord) /* werewolves can't be given to non-werewolves and vice-versa */ error = 312; } else if (u2 && u2->number != 0 && u2->race != u->race) { - log_warning(("faction %s attempts to give %s to %s.\n", - itoa36(u->faction->no), u->race->_name[0], u2->race->_name[1])); + log_warning("faction %s attempts to give %s to %s.\n", itoa36(u->faction->no), u->race->_name[0], u2->race->_name[1]); error = 139; } else if (u2 != NULL && (get_racename(u2->attribs) || get_racename(u->attribs))) { diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index efab59d62..48998f647 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -1099,8 +1099,7 @@ static int restart_cmd(unit * u, struct order *ord) if (!checkpasswd(u->faction, (const char *)s_pass, false)) { cmistake(u, ord, 86, MSG_EVENT); - log_warning(("RESTART with wrong password, faction %s, pass %s\n", - factionid(u->faction), s_pass)); + log_warning("RESTART with wrong password, faction %s, pass %s\n", factionid(u->faction), s_pass); return 0; } restart_race(u, frace); @@ -1156,8 +1155,7 @@ static int quit_cmd(unit * u, struct order *ord) char buffer[64]; write_order(ord, buffer, sizeof(buffer)); cmistake(u, ord, 86, MSG_EVENT); - log_warning(("QUIT with illegal password for faction %s: %s\n", - factionid(f), buffer)); + log_warning("QUIT with illegal password for faction %s: %s\n", factionid(f), buffer); } return 0; } @@ -4382,7 +4380,7 @@ void update_subscriptions(void) strcat(strcpy(zText, basepath()), "/subscriptions"); F = fopen(zText, "r"); if (F == NULL) { - log_warning((0, "could not open %s.\n", zText)); + log_warning(0, "could not open %s.\n", zText); return; } for (;;) { diff --git a/src/kernel/command.c b/src/kernel/command.c index ca3e2f294..68d1fb75d 100644 --- a/src/kernel/command.c +++ b/src/kernel/command.c @@ -95,7 +95,7 @@ void do_command(const void *keys, struct unit *u, struct order *ord) skip_token(); if (do_command_i(keys, u, ord) != E_TOK_SUCCESS) { char *cmd = getcommand(ord); - log_warning(("%s failed command '%s'\n", unitname(u), cmd)); + log_warning("%s failed command '%s'\n", unitname(u), cmd); free(cmd); } } diff --git a/src/kernel/config.c b/src/kernel/config.c index d2b5d4541..f6f2d6352 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -746,7 +746,7 @@ void verify_data(void) lf = f->no; log_printf(stdout, "Partei %s:\n", factionid(f)); } - log_warning(("Einheit %s hat %d Personen\n", unitid(u), u->number)); + log_warning("Einheit %s hat %d Personen\n", unitid(u), u->number); } } if (f->no != 0 && ((mage > 3 && f->race != new_race[RC_ELF]) || mage > 4)) @@ -1143,8 +1143,7 @@ const char *strcheck(const char *s, size_t maxlen) static char buffer[16 * 1024]; if (strlen(s) > maxlen) { assert(maxlen < 16 * 1024); - log_warning(("[strcheck] String wurde auf %d Zeichen verkürzt:\n%s\n", - (int)maxlen, s)); + log_warning("[strcheck] String wurde auf %d Zeichen verkürzt:\n%s\n", (int)maxlen, s); strlcpy(buffer, s, maxlen); return buffer; } diff --git a/src/kernel/connection.c b/src/kernel/connection.c index 69606884d..ba49f1b54 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -677,7 +677,7 @@ int read_borders(struct storage *store) return result; } if (!type->name || !to || !from) { - log_warning(("erase invalid border '%s' between '%s' and '%s'\n", type->__name, regionname(from, 0), regionname(to, 0))); + log_warning("erase invalid border '%s' between '%s' and '%s'\n", type->__name, regionname(from, 0), regionname(to, 0)); erase_border(b); } } diff --git a/src/kernel/item.c b/src/kernel/item.c index f123d8e98..75eb19dea 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -355,7 +355,7 @@ resource_type *rt_find(const char *name) break; } if (!rtype) { - log_warning(("rt_find: unknown resource '%s'\n", name)); + log_warning("rt_find: unknown resource '%s'\n", name); } return rtype; } diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 5da9bc57f..da4ff2bb0 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -944,8 +944,7 @@ boolean knowsspell(const region * r, const unit * u, const spell * sp) /* Magier? */ mage = get_mage(u); if (!mage) { - log_warning(("%s ist kein Magier, versucht aber zu zaubern.\n", - unitname(u))); + log_warning("%s ist kein Magier, versucht aber zu zaubern.\n", unitname(u)); return false; } /* steht der Spruch in der Spruchliste? */ @@ -955,8 +954,7 @@ boolean knowsspell(const region * r, const unit * u, const spell * sp) return false; } if (eff_skill(u, SK_MAGIC, u->region) >= sp->level) { - log_warning(("%s ist hat die erforderliche Stufe, kennt aber %s nicht.\n", - unitname(u), spell_name(sp, default_locale))); + log_warning("%s ist hat die erforderliche Stufe, kennt aber %s nicht.\n", unitname(u), spell_name(sp, default_locale)); } return false; } diff --git a/src/kernel/message.c b/src/kernel/message.c index c7ca71b06..c83479b28 100644 --- a/src/kernel/message.c +++ b/src/kernel/message.c @@ -149,7 +149,7 @@ message *msg_message(const char *name, const char *sig, ...) memset(args, 0, sizeof(args)); if (!mtype) { - log_warning(("trying to create message of unknown type \"%s\"\n", name)); + log_warning("trying to create message of unknown type \"%s\"\n", name); if (strcmp(name, "missing_message") != 0) { return msg_message("missing_message", "name", name); } @@ -200,7 +200,7 @@ caddmessage(region * r, faction * f, const char *s, msg_t mtype, int level) #define LOG_ENGLISH #ifdef LOG_ENGLISH if (f && f->locale != default_locale) { - log_warning(("message for locale \"%s\": %s\n", locale_name(f->locale), s)); + log_warning("message for locale \"%s\": %s\n", locale_name(f->locale), s); } #endif unused(level); diff --git a/src/kernel/pool.c b/src/kernel/pool.c index 4d280d4ef..f5150851a 100644 --- a/src/kernel/pool.c +++ b/src/kernel/pool.c @@ -81,7 +81,7 @@ int change_resource(unit * u, const resource_type * rtype, int change) assert(!"undefined resource detected. rtype->uchange not initialized."); assert(i >= 0); if (i >= 100000000) { - log_warning(("%s has %d %s\n", unitname(u), i, rtype->_name[0])); + log_warning("%s has %d %s\n", unitname(u), i, rtype->_name[0]); } return i; } diff --git a/src/kernel/reports.c b/src/kernel/reports.c index 5bb42ccb4..3fef6cb51 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -837,8 +837,7 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, } } if (size <= 1) { - log_warning(("bufunit ran out of space after writing %u bytes.\n", - (bufp - buf))); + log_warning("bufunit ran out of space after writing %u bytes.\n", (bufp - buf)); } return dh; } @@ -1548,7 +1547,7 @@ int write_reports(faction * f, time_t ltime) } } while (errno); if (!gotit) { - log_warning(("No report for faction %s!\n", factionid(f))); + log_warning("No report for faction %s!\n", factionid(f)); } ql_free(ctx.addresses); seen_done(ctx.seen); diff --git a/src/kernel/save.c b/src/kernel/save.c index a05445ab1..c7132c5df 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -347,7 +347,7 @@ static faction *factionorders(void) const char *pass = getstrtoken(); if (!checkpasswd(f, (const char *)pass, true)) { - log_warning(("Invalid password for faction %s\n", itoa36(fid))); + log_warning("Invalid password for faction %s\n", itoa36(fid)); ADDMSG(&f->msgs, msg_message("wrongpasswd", "faction password", f->no, pass)); return 0; @@ -360,7 +360,7 @@ static faction *factionorders(void) f->lastorders = global.data_turn + 1; } else { - log_warning(("orders for invalid faction %s\n", itoa36(fid))); + log_warning("orders for invalid faction %s\n", itoa36(fid)); } return f; } @@ -806,7 +806,7 @@ unit *read_unit(struct storage *store) if ((u->flags & UFL_ANON_FACTION) && !rule_stealth_faction()) { /* if this rule is broken, then fix broken units */ u->flags -= UFL_ANON_FACTION; - log_warning(("%s was anonymous.\n", unitname(u))); + log_warning("%s was anonymous.\n", unitname(u)); } /* Persistente Befehle einlesen */ free_orders(&u->orders); @@ -823,11 +823,10 @@ unit *read_unit(struct storage *store) orderp = &ord->next; ord = NULL; } else if (p == MAXPERSISTENT) { - log_warning(("%s had %d or more persistent orders\n", unitname(u), - MAXPERSISTENT)); + log_warning("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT); } } else if (n == MAXORDERS) { - log_warning(("%s had %d or more orders\n", unitname(u), MAXORDERS)); + log_warning("%s had %d or more orders\n", unitname(u), MAXORDERS); } if (ord != NULL) free_order(ord); @@ -1238,8 +1237,7 @@ faction *readfaction(struct storage * store) store->r_str_buf(store, email, sizeof(email)); if (set_email(&f->email, email) != 0) { - log_warning(("Invalid email address for faction %s: %s\n", itoa36(f->no), - email)); + log_warning("Invalid email address for faction %s: %s\n", itoa36(f->no), email); set_email(&f->email, ""); } @@ -1412,7 +1410,7 @@ static void repair_unit(unit * u) { } if (!found) { u->race = u->faction->race; - log_warning(("This toad did not have a changerace trigger: %s\n", unitname(u))); + log_warning("This toad did not have a changerace trigger: %s\n", unitname(u)); } } } @@ -1454,8 +1452,7 @@ int readgame(const char *filename, int mode, int backup) char buffer[64]; snprintf(buffer, sizeof(buffer), "%s.xml", game_name); if (strcmp(basefile, buffer) != 0) { - log_warning(("game mismatch: datafile contains %s, game is %s\n", - basefile, game_name)); + log_warning("game mismatch: datafile contains %s, game is %s\n", basefile, game_name); printf("WARNING: any key to continue, Ctrl-C to stop\n"); getchar(); } @@ -1480,7 +1477,7 @@ int readgame(const char *filename, int mode, int backup) if (pl == NULL) { pl = calloc(1, sizeof(plane)); } else { - log_warning(("the plane with id=%d already exists.\n", id)); + log_warning("the plane with id=%d already exists.\n", id); } pl->id = id; pl->name = store->r_str(store); @@ -1692,7 +1689,7 @@ int readgame(const char *filename, int mode, int backup) int no = 666; while (findfaction(no)) ++no; - log_warning(("renum(monsters, %d)\n", no)); + log_warning("renum(monsters, %d)\n", no); renumber_faction(f, no); } } else { diff --git a/src/kernel/spell.c b/src/kernel/spell.c index 7602c4874..ea3e41cef 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -63,7 +63,7 @@ spell *find_spell(const char *name) return sp; } } - log_warning(("find_spell: could not find spell '%s'\n", name)); + log_warning("find_spell: could not find spell '%s'\n", name); return 0; } @@ -121,6 +121,6 @@ spell *find_spellbyid(unsigned int id) } } - log_warning(("cannot find spell by id: %u\n", id)); + log_warning("cannot find spell by id: %u\n", id); return NULL; } diff --git a/src/kernel/terrain.c b/src/kernel/terrain.c index 6090f771c..14c776e14 100644 --- a/src/kernel/terrain.c +++ b/src/kernel/terrain.c @@ -127,7 +127,7 @@ terrain_t oldterrain(const struct terrain_type * terrain) if (newterrains[t] == terrain) return t; } - log_warning(("%s is not a classic terrain.\n", terrain->_name)); + log_warning("%s is not a classic terrain.\n", terrain->_name); return NOTERRAIN; } diff --git a/src/kernel/textstore.c b/src/kernel/textstore.c index 4c812158b..0bbbd48c7 100644 --- a/src/kernel/textstore.c +++ b/src/kernel/textstore.c @@ -142,14 +142,14 @@ static int txt_open(struct storage *store, const char *filename, int mode) store->r_tok_buf(store, token, sizeof(token)); if (memcmp(token, utf8_bom, 3) == 0) { if (enc_gamedata != XML_CHAR_ENCODING_UTF8) { - log_warning(("Found UTF-8 BOM, assuming unicode game data.\n")); + log_warning("Found UTF-8 BOM, assuming unicode game data.\n"); store->encoding = XML_CHAR_ENCODING_UTF8; } store->version = atoi(token + 3); } else { if (store->encoding == XML_CHAR_ENCODING_NONE) { store->encoding = XML_CHAR_ENCODING_8859_1; - log_warning(("No BOM, assuming 8859-1 game data.\n")); + log_warning("No BOM, assuming 8859-1 game data.\n"); } store->version = atoi(token); } diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 2739aff0b..7344c4589 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1562,7 +1562,7 @@ int countheroes(const struct faction *f) #ifdef DEBUG_MAXHEROES int m = maxheroes(f); if (n > m) { - log_warning(("%s has %d of %d heroes\n", factionname(f), n, m)); + log_warning("%s has %d of %d heroes\n", factionname(f), n, m); } #endif return n; diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index d2b822882..40f32fe12 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -604,8 +604,7 @@ static int parse_ships(xmlDocPtr doc) if (st->coasts[c] != NULL) ++c; else { - log_warning(("ship %s mentions a non-existing terrain %s.\n", - st->name[0], propValue)); + log_warning("ship %s mentions a non-existing terrain %s.\n", st->name[0], propValue); } xmlFree(propValue); } @@ -2210,8 +2209,7 @@ xml_readstrings(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, } xmlFree(propText); } else { - log_warning(("string %s has no text in locale %s\n", - zName, locale_name(lang))); + log_warning("string %s has no text in locale %s\n", zName, locale_name(lang)); } } xmlXPathFreeObject(result); diff --git a/src/triggers/timeout.c b/src/triggers/timeout.c index 44226099d..65a1dc10f 100644 --- a/src/triggers/timeout.c +++ b/src/triggers/timeout.c @@ -78,10 +78,9 @@ static int timeout_read(trigger * t, struct storage *store) read_triggers(store, &td->triggers); if (td->timer > 20) { trigger *tr = td->triggers; - log_warning(("there is a timeout lasting for another %d turns\n", - td->timer)); + log_warning("there is a timeout lasting for another %d turns\n", td->timer); while (tr) { - log_warning((" timeout triggers: %s\n", tr->type->name)); + log_warning(" timeout triggers: %s\n", tr->type->name); tr = tr->next; } } diff --git a/src/util/attrib.c b/src/util/attrib.c index c5854348b..147b006b5 100644 --- a/src/util/attrib.c +++ b/src/util/attrib.c @@ -45,14 +45,14 @@ void at_register(attrib_type * at) attrib_type *find; if (at->read == NULL) { - log_warning(("registering non-persistent attribute %s.\n", at->name)); + log_warning("registering non-persistent attribute %s.\n", at->name); } at->hashkey = __at_hashkey(at->name); find = at_hash[at->hashkey % MAXATHASH]; while (find && at->hashkey != find->hashkey) find = find->nexthash; if (find && find == at) { - log_warning(("attribute '%s' was registered more than once\n", at->name)); + log_warning("attribute '%s' was registered more than once\n", at->name); return; } else { assert(!find || !"hashkey is already in use"); diff --git a/src/util/bsdstring.h b/src/util/bsdstring.h index 0ed276b61..dc9e2919b 100644 --- a/src/util/bsdstring.h +++ b/src/util/bsdstring.h @@ -9,7 +9,7 @@ extern size_t strlcat(char *dst, const char *src, size_t siz); extern int wrptr(char **ptr, size_t * size, int bytes); #endif -#define WARN_STATIC_BUFFER() log_warning(("static buffer too small in %s:%d\n", __FILE__, __LINE__)) +#define WARN_STATIC_BUFFER() log_warning("static buffer too small in %s:%d\n", __FILE__, __LINE__) #if !defined(HAVE_STRLPRINTF) # define HAVE_STRLPRINTF diff --git a/src/util/filereader.c b/src/util/filereader.c index a70457b70..81ce78110 100644 --- a/src/util/filereader.c +++ b/src/util/filereader.c @@ -17,7 +17,7 @@ static char fbuf[MAXLINE]; static void unicode_warning(const char *bp) { - log_warning(("invalid sequence in UTF-8 string: %s\n", bp)); + log_warning("invalid sequence in UTF-8 string: %s\n", bp); } INLINE_FUNCTION int eatwhite(const char *ptr, size_t * total_size) diff --git a/src/util/language.c b/src/util/language.c index 0616bdba8..a763ffe04 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -148,8 +148,7 @@ const char *locale_string(const locale * lang, const char *key) find = find->nexthash; } if (!find) { - log_warning(("missing translation for \"%s\" in locale %s\n", key, - lang->name)); + log_warning("missing translation for \"%s\" in locale %s\n", key, lang->name); if (lang != default_locale) { return locale_string(default_locale, key); } diff --git a/src/util/log.c b/src/util/log.c index 75571ee77..e09946c3c 100644 --- a/src/util/log.c +++ b/src/util/log.c @@ -196,7 +196,7 @@ void _log_debug(const char *format, ...) } } -void _log_warn(const char *format, ...) +void log_warning(const char *format, ...) { const char * prefix = "WARNING"; const int mask = LOG_CPWARNING; diff --git a/src/util/log.h b/src/util/log.h index 301469e06..88607a343 100644 --- a/src/util/log.h +++ b/src/util/log.h @@ -19,12 +19,11 @@ extern "C" { extern void log_close(void); extern void log_flush(void); -#define log_warning(x) _log_warn x #define log_error(x) _log_error x #define log_debug _log_debug /* use macros above instead of these: */ - extern void _log_warn(const char *format, ...); + extern void log_warning(const char *format, ...); extern void _log_error(const char *format, ...); extern void _log_debug(const char *format, ...); extern void log_info(const char *format, ...); diff --git a/src/util/nrmessage.c b/src/util/nrmessage.c index adb047df1..20b918ff4 100644 --- a/src/util/nrmessage.c +++ b/src/util/nrmessage.c @@ -56,12 +56,10 @@ nrmessage_type *nrt_find(const struct locale * lang, type = type->next; } if (!found) { - log_warning(("could not find nr-type %s for locale %s\n", - mtype->name, locale_name(lang))); + log_warning("could not find nr-type %s for locale %s\n", mtype->name, locale_name(lang)); } if (lang && found && found->lang != lang) { - log_warning(("could not find nr-type %s for locale %s, using %s\n", - mtype->name, locale_name(lang), locale_name(found->lang))); + log_warning("could not find nr-type %s for locale %s, using %s\n", mtype->name, locale_name(lang), locale_name(found->lang)); } return found; } diff --git a/src/util/parser.c b/src/util/parser.c index d6ae46c47..46d6ba8a8 100644 --- a/src/util/parser.c +++ b/src/util/parser.c @@ -36,7 +36,7 @@ static int eatwhitespace_c(const char **str_p) } else { ret = unicode_utf8_to_ucs4(&ucs, str, &len); if (ret != 0) { - log_warning(("illegal character sequence in UTF8 string: %s\n", str)); + log_warning("illegal character sequence in UTF8 string: %s\n", str); break; } if (!iswxspace((wint_t) ucs)) @@ -100,8 +100,7 @@ void skip_token(void) if (ret == 0) { state->current_token += len; } else { - log_warning(("illegal character sequence in UTF8 string: %s\n", - state->current_token)); + log_warning("illegal character sequence in UTF8 string: %s\n", state->current_token); } } if (iswxspace((wint_t) ucs) && quotechar == 0) { @@ -145,8 +144,7 @@ const char *parse_token(const char **str) } else { int ret = unicode_utf8_to_ucs4(&ucs, ctoken, &len); if (ret != 0) { - log_warning(("illegal character sequence in UTF8 string: %s\n", - ctoken)); + log_warning("illegal character sequence in UTF8 string: %s\n", ctoken); break; } } diff --git a/src/util/xml.c b/src/util/xml.c index cd1878206..bb6a9a302 100644 --- a/src/util/xml.c +++ b/src/util/xml.c @@ -57,10 +57,10 @@ boolean xml_bvalue(xmlNodePtr node, const char *name, boolean dflt) else if (strcmp((const char *)propValue, "true") == 0) result = true; else if (strcmp((const char *)propValue, "1") == 0) { - log_warning(("boolean value is '1': %s::%s\n", node->name, name)); + log_warning("boolean value is '1': %s::%s\n", node->name, name); result = true; } else if (strcmp((const char *)propValue, "0") == 0) { - log_warning(("boolean value is '0': %s::%s\n", node->name, name)); + log_warning("boolean value is '0': %s::%s\n", node->name, name); result = false; } xmlFree(propValue); From ecbe770fce452858b7a0c14fea050e1b3de5a490 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 16 May 2012 16:52:01 -0700 Subject: [PATCH 195/400] rename _log_error to log_error and get rid of the cumbersome #define --- src/bindings/bind_attrib.c | 7 ++- src/bindings/bind_faction.c | 2 +- src/bindings/bind_gmtool.c | 2 +- src/bindings/bind_region.c | 2 +- src/bindings/bind_unit.c | 6 +-- src/bindings/bindings.c | 2 +- src/bindings/helpers.c | 91 ++++++++++++++---------------------- src/gamecode/creport.c | 3 +- src/gamecode/laws.c | 6 +-- src/kernel/alchemy.c | 2 +- src/kernel/battle.c | 15 +++--- src/kernel/binarystore.c | 10 ++-- src/kernel/build.c | 4 +- src/kernel/config.c | 9 ++-- src/kernel/connection.c | 6 +-- src/kernel/curse.c | 5 +- src/kernel/faction.c | 3 +- src/kernel/item.c | 3 +- src/kernel/magic.c | 11 ++--- src/kernel/message.c | 8 ++-- src/kernel/pool.c | 2 +- src/kernel/race.c | 2 +- src/kernel/region.c | 10 ++-- src/kernel/reports.c | 12 ++--- src/kernel/save.c | 40 +++++++--------- src/kernel/skill.c | 2 +- src/kernel/sqlite.c | 3 +- src/kernel/teleport.c | 2 +- src/kernel/xmlreader.c | 73 ++++++++++------------------- src/modules/arena.c | 6 +-- src/modules/autoseed.c | 5 +- src/modules/gmcmd.c | 5 +- src/triggers/changefaction.c | 2 +- src/triggers/changerace.c | 2 +- src/triggers/clonedied.c | 2 +- src/triggers/createcurse.c | 2 +- src/triggers/createunit.c | 2 +- src/triggers/gate.c | 2 +- src/triggers/giveitem.c | 2 +- src/triggers/removecurse.c | 2 +- src/triggers/shock.c | 3 +- src/triggers/unguard.c | 2 +- src/util/crmessage.c | 3 +- src/util/filereader.c | 2 +- src/util/language.c | 2 +- src/util/log.c | 2 +- src/util/log.h | 3 +- src/util/message.c | 7 ++- src/util/nrmessage.c | 4 +- src/util/translation.c | 8 ++-- src/util/xml.c | 2 +- 51 files changed, 165 insertions(+), 248 deletions(-) diff --git a/src/bindings/bind_attrib.c b/src/bindings/bind_attrib.c index 9e8d1a9c2..af43c93d6 100644 --- a/src/bindings/bind_attrib.c +++ b/src/bindings/bind_attrib.c @@ -44,7 +44,7 @@ static void init_ext(attrib * a) lua_rawgeti(L, LUA_REGISTRYINDEX, a->data.i); if (lua_pcall(L, 1, 0, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("attrib_init '%d': %s.\n", a->data.i, error)); + log_error("attrib_init '%d': %s.\n", a->data.i, error); } } } @@ -140,7 +140,7 @@ static void write_ext_i(lua_State * L, const char *name, bson_buffer * bb) oid.ints[1] = b->no; bson_append_oid(bb, name, &oid); } else { - log_error(("unsuported type.\n")); + log_error("unsuported type.\n"); bson_append_null(bb, name); } } @@ -253,8 +253,7 @@ static int read_ext_i(lua_State * L, bson_iterator * it, bson_type type) else lua_pushnil(L); } else { - log_error(("unknown oid %d %d %d\n", oid->ints[0], oid->ints[1], - oid->ints[2])); + log_error("unknown oid %d %d %d\n", oid->ints[0], oid->ints[1], oid->ints[2]); lua_pushnil(L); } } diff --git a/src/bindings/bind_faction.c b/src/bindings/bind_faction.c index a9a181f78..40aa6b113 100644 --- a/src/bindings/bind_faction.c +++ b/src/bindings/bind_faction.c @@ -299,7 +299,7 @@ static int tolua_faction_create(lua_State * L) f = addfaction(email, NULL, frace, loc, 0); } if (!f) { - log_error(("faction.create(%s, %s, %s)\n", email, racename, lang)); + log_error("faction.create(%s, %s, %s)\n", email, racename, lang); } tolua_pushusertype(L, f, TOLUA_CAST "faction"); return 1; diff --git a/src/bindings/bind_gmtool.c b/src/bindings/bind_gmtool.c index 5fe23c6e6..a38e8d32c 100644 --- a/src/bindings/bind_gmtool.c +++ b/src/bindings/bind_gmtool.c @@ -167,7 +167,7 @@ static void lua_paint_info(struct window *wnd, const struct state *st) tolua_pushnumber(L, ny); if (lua_pcall(L, 2, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("paint function failed: %s\n", error)); + log_error("paint function failed: %s\n", error); lua_pop(L, 1); tolua_error(L, TOLUA_CAST "event handler call failed", NULL); } else { diff --git a/src/bindings/bind_region.c b/src/bindings/bind_region.c index fe3d69ea0..c98849dfa 100644 --- a/src/bindings/bind_region.c +++ b/src/bindings/bind_region.c @@ -309,7 +309,7 @@ static int tolua_region_get_resourcelevel(lua_State * L) return 0; } -#define LUA_ASSERT(c, s) if (!(c)) { log_error(("%s(%d): %s\n", __FILE__, __LINE__, (s))); return 0; } +#define LUA_ASSERT(c, s) if (!(c)) { log_error("%s(%d): %s\n", __FILE__, __LINE__, (s)); return 0; } static critbit_tree * special_resources(void) { diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 38c762c20..1760d414a 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -394,7 +394,7 @@ int fctr_handle(struct trigger *tp, void *data) tolua_pushusertype(L, &evt, TOLUA_CAST "event"); if (lua_pcall(L, 2, 0, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("event (%s): %s\n", unitname(u), error)); + log_error("event (%s): %s\n", unitname(u), error); lua_pop(L, 1); tolua_error(L, TOLUA_CAST "event handler call failed", NULL); } @@ -462,7 +462,7 @@ static void unit_castspell(unit * u, const char *name) spell *sp = (spell *) ql_get(ql, qi); if (strcmp(name, sp->sname) == 0) { if (!sp->cast) { - log_error(("spell '%s' has no function.\n", sp->sname)); + log_error("spell '%s' has no function.\n", sp->sname); } else { castorder co; create_castorder(&co, u, 0, sp, u->region, sp->level, sp->level * MagicPower(), 0, 0, 0); @@ -487,7 +487,7 @@ static int unit_addspell(unit * u, const char *name) spell *spadd = find_spell(name); if (!spadd) { - log_error(("spell %s could not be found\n", name)); + log_error("spell %s could not be found\n", name); return EINVAL; } else { quicklist **starget = get_spelllist(m, u->faction); diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index 7236af01a..964b2f588 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -71,7 +71,7 @@ without prior permission by the authors of Eressea. int log_lua_error(lua_State * L) { const char *error = lua_tostring(L, -1); - log_error(("LUA call failed.\n%s\n", error)); + log_error("LUA call failed.\n%s\n", error); lua_pop(L, 1); return 1; } diff --git a/src/bindings/helpers.c b/src/bindings/helpers.c index bc99cc108..b5eca0eb1 100644 --- a/src/bindings/helpers.c +++ b/src/bindings/helpers.c @@ -57,15 +57,14 @@ lua_giveitem(unit * s, unit * d, const item_type * itype, int n, if (lua_pcall(L, 4, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("unit %s calling '%s': %s.\n", unitname(s), fname, error)); + log_error("unit %s calling '%s': %s.\n", unitname(s), fname, error); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); lua_pop(L, 1); } } else { - log_error(("unit %s trying to call '%s' : not a function.\n", - unitname(s), fname)); + log_error("unit %s trying to call '%s' : not a function.\n", unitname(s), fname); lua_pop(L, 1); } @@ -87,16 +86,14 @@ static int limit_resource(const region * r, const resource_type * rtype) if (lua_pcall(L, 1, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("limit(%s) calling '%s': %s.\n", - regionname(r, NULL), fname, error)); + log_error("limit(%s) calling '%s': %s.\n", regionname(r, NULL), fname, error); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); lua_pop(L, 1); } } else { - log_error(("limit(%s) calling '%s': not a function.\n", - regionname(r, NULL), fname)); + log_error("limit(%s) calling '%s': not a function.\n", regionname(r, NULL), fname); lua_pop(L, 1); } @@ -118,13 +115,11 @@ produce_resource(region * r, const resource_type * rtype, int norders) if (lua_pcall(L, 2, 0, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("produce(%s) calling '%s': %s.\n", - regionname(r, NULL), fname, error)); + log_error("produce(%s) calling '%s': %s.\n", regionname(r, NULL), fname, error); lua_pop(L, 1); } } else { - log_error(("produce(%s) calling '%s': not a function.\n", - regionname(r, NULL), fname)); + log_error("produce(%s) calling '%s': not a function.\n", regionname(r, NULL), fname); lua_pop(L, 1); } } @@ -151,16 +146,14 @@ static int lc_age(struct attrib *a) if (lua_pcall(L, fparam ? 2 : 1, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("lc_age(%s) calling '%s': %s.\n", - buildingname(b), fname, error)); + log_error("lc_age(%s) calling '%s': %s.\n", buildingname(b), fname, error); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); lua_pop(L, 1); } } else { - log_error(("lc_age(%s) calling '%s': not a function.\n", - buildingname(b), fname)); + log_error("lc_age(%s) calling '%s': not a function.\n", buildingname(b), fname); lua_pop(L, 1); } } @@ -180,7 +173,7 @@ static void push_param(lua_State * L, char c, spllprm * param) else if (c == 'c') tolua_pushstring(L, param->data.s); else { - log_error(("unsupported syntax %c.\n", c)); + log_error("unsupported syntax %c.\n", c); lua_pushnil(L); } } @@ -232,16 +225,14 @@ static int lua_callspell(castorder * co) if (lua_pcall(L, nparam, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("spell(%s) calling '%s': %s.\n", - unitname(caster), fname, error)); + log_error("spell(%s) calling '%s': %s.\n", unitname(caster), fname, error); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); lua_pop(L, 1); } } else { - log_error(("spell(%s) calling '%s': not a function.\n", - unitname(caster), fname)); + log_error("spell(%s) calling '%s': not a function.\n", unitname(caster), fname); lua_pop(L, 1); } @@ -263,8 +254,7 @@ static void lua_initfamiliar(unit * u) if (lua_pcall(L, 1, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("familiar(%s) calling '%s': %s.\n", - unitname(u), fname, error)); + log_error("familiar(%s) calling '%s': %s.\n", unitname(u), fname, error); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); @@ -297,15 +287,14 @@ lua_changeresource(unit * u, const struct resource_type *rtype, int delta) if (lua_pcall(L, 2, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("change(%s) calling '%s': %s.\n", unitname(u), fname, error)); + log_error("change(%s) calling '%s': %s.\n", unitname(u), fname, error); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); lua_pop(L, 1); } } else { - log_error(("change(%s) calling '%s': not a function.\n", - unitname(u), fname)); + log_error("change(%s) calling '%s': not a function.\n", unitname(u), fname); lua_pop(L, 1); } @@ -326,14 +315,14 @@ static int lua_getresource(unit * u, const struct resource_type *rtype) if (lua_pcall(L, 1, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("get(%s) calling '%s': %s.\n", unitname(u), fname, error)); + log_error("get(%s) calling '%s': %s.\n", unitname(u), fname, error); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); lua_pop(L, 1); } } else { - log_error(("get(%s) calling '%s': not a function.\n", unitname(u), fname)); + log_error("get(%s) calling '%s': not a function.\n", unitname(u), fname); lua_pop(L, 1); } @@ -357,7 +346,7 @@ static boolean lua_canuse_item(const unit * u, const struct item_type *itype) if (lua_pcall(L, 2, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("get(%s) calling '%s': %s.\n", unitname(u), fname, error)); + log_error("get(%s) calling '%s': %s.\n", unitname(u), fname, error); lua_pop(L, 1); } else { result = lua_toboolean(L, -1); @@ -365,8 +354,7 @@ static boolean lua_canuse_item(const unit * u, const struct item_type *itype) } } else { function_exists = 0; - log_error(("get(%s) calling '%s': not a function.\n", - unitname(u), fname)); + log_error("get(%s) calling '%s': not a function.\n", unitname(u), fname); lua_pop(L, 1); } } @@ -390,16 +378,14 @@ lua_wage(const region * r, const faction * f, const race * rc, int in_turn) if (lua_pcall(L, 3, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("wage(%s) calling '%s': %s.\n", - regionname(r, NULL), fname, error)); + log_error("wage(%s) calling '%s': %s.\n", regionname(r, NULL), fname, error); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); lua_pop(L, 1); } } else { - log_error(("wage(%s) calling '%s': not a function.\n", - regionname(r, NULL), fname)); + log_error("wage(%s) calling '%s': not a function.\n", regionname(r, NULL), fname); lua_pop(L, 1); } @@ -420,13 +406,11 @@ static void lua_agebuilding(building * b) if (lua_pcall(L, 1, 0, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("agebuilding(%s) calling '%s': %s.\n", - buildingname(b), fname, error)); + log_error("agebuilding(%s) calling '%s': %s.\n", buildingname(b), fname, error); lua_pop(L, 1); } } else { - log_error(("agebuilding(%s) calling '%s': not a function.\n", - buildingname(b), fname)); + log_error("agebuilding(%s) calling '%s': not a function.\n", buildingname(b), fname); lua_pop(L, 1); } } @@ -445,16 +429,14 @@ static int lua_building_protection(building * b, unit * u) if (lua_pcall(L, 2, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("building_protection(%s, %s) calling '%s': %s.\n", - buildingname(b), unitname(u), fname, error)); + log_error("building_protection(%s, %s) calling '%s': %s.\n", buildingname(b), unitname(u), fname, error); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); lua_pop(L, 1); } } else { - log_error(("building_protection(%s, %s) calling '%s': not a function.\n", - buildingname(b), unitname(u), fname)); + log_error("building_protection(%s, %s) calling '%s': not a function.\n", buildingname(b), unitname(u), fname); lua_pop(L, 1); } return result; @@ -476,16 +458,14 @@ static double lua_building_taxes(building * b, int level) if (lua_pcall(L, 2, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("building_taxes(%s) calling '%s': %s.\n", - buildingname(b), fname, error)); + log_error("building_taxes(%s) calling '%s': %s.\n", buildingname(b), fname, error); lua_pop(L, 1); } else { result = (double)lua_tonumber(L, -1); lua_pop(L, 1); } } else { - log_error(("building_taxes(%s) calling '%s': not a function.\n", - buildingname(b), fname)); + log_error("building_taxes(%s) calling '%s': not a function.\n", buildingname(b), fname); lua_pop(L, 1); } return result; @@ -504,16 +484,14 @@ static int lua_maintenance(const unit * u) if (lua_pcall(L, 1, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("maintenance(%s) calling '%s': %s.\n", - unitname(u), fname, error)); + log_error("maintenance(%s) calling '%s': %s.\n", unitname(u), fname, error); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); lua_pop(L, 1); } } else { - log_error(("maintenance(%s) calling '%s': not a function.\n", - unitname(u), fname)); + log_error("maintenance(%s) calling '%s': not a function.\n", unitname(u), fname); lua_pop(L, 1); } @@ -534,15 +512,14 @@ static void lua_equipmentcallback(const struct equipment *eq, unit * u) if (lua_pcall(L, 1, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("equip(%s) calling '%s': %s.\n", unitname(u), fname, error)); + log_error("equip(%s) calling '%s': %s.\n", unitname(u), fname, error); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); lua_pop(L, 1); } } else { - log_error(("equip(%s) calling '%s': not a function.\n", - unitname(u), fname)); + log_error("equip(%s) calling '%s': not a function.\n", unitname(u), fname); lua_pop(L, 1); } } @@ -565,14 +542,14 @@ lua_useitem(struct unit *u, const struct item_type *itype, int amount, if (lua_pcall(L, 2, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("use(%s) calling '%s': %s.\n", unitname(u), fname, error)); + log_error("use(%s) calling '%s': %s.\n", unitname(u), fname, error); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); lua_pop(L, 1); } } else { - log_error(("use(%s) calling '%s': not a function.\n", unitname(u), fname)); + log_error("use(%s) calling '%s': not a function.\n", unitname(u), fname); lua_pop(L, 1); } @@ -594,14 +571,14 @@ static int lua_recruit(struct unit *u, const struct archetype *arch, int amount) if (lua_pcall(L, 2, 1, 0) != 0) { const char *error = lua_tostring(L, -1); - log_error(("use(%s) calling '%s': %s.\n", unitname(u), fname, error)); + log_error("use(%s) calling '%s': %s.\n", unitname(u), fname, error); lua_pop(L, 1); } else { result = (int)lua_tonumber(L, -1); lua_pop(L, 1); } } else { - log_error(("use(%s) calling '%s': not a function.\n", unitname(u), fname)); + log_error("use(%s) calling '%s': not a function.\n", unitname(u), fname); lua_pop(L, 1); } return result; diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index 4bac2a04d..1e50f99a4 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -527,8 +527,7 @@ static void render_messages(FILE * F, faction * f, message_list * msgs) if (crbuffer[0]) fputs(crbuffer, F); } else { - log_error(("could not render cr-message %p: %s\n", m->msg, - m->msg->type->name)); + log_error("could not render cr-message %p: %s\n", m->msg, m->msg->type->name); } if (printed) { unsigned int ihash = hash % MTMAXHASH; diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 48998f647..47205e098 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -2132,8 +2132,7 @@ static int email_cmd(unit * u, struct order *ord) } else { faction *f = u->faction; if (set_email(&f->email, (const char *)s) != 0) { - log_error(("Invalid email address for faction %s: %s\n", - itoa36(f->no), s)); + log_error("Invalid email address for faction %s: %s\n", itoa36(f->no), s); ADDMSG(&f->msgs, msg_message("changemail_invalid", "value", s)); } else { ADDMSG(&f->msgs, msg_message("changemail", "value", f->email)); @@ -3826,8 +3825,7 @@ static int use_cmd(unit * u, struct order *ord) int i = use_item(u, itype, n, ord); assert(i <= 0 || !"use_item should not return positive values."); if (i > 0) { - log_error(("use_item returned a value>0 for %s\n", - resourcename(itype->rtype, 0))); + log_error("use_item returned a value>0 for %s\n", resourcename(itype->rtype, 0)); } } else { cmistake(u, ord, 43, MSG_PRODUCE); diff --git a/src/kernel/alchemy.c b/src/kernel/alchemy.c index 6c9963007..4a6f17052 100644 --- a/src/kernel/alchemy.c +++ b/src/kernel/alchemy.c @@ -341,6 +341,6 @@ int change_effect(unit * u, const potion_type * effect, int delta) data->value = delta; return data->value; } - log_error(("change effect with delta==0 for unit %s\n", itoa36(u->no))); + log_error("change effect with delta==0 for unit %s\n", itoa36(u->no)); return 0; } diff --git a/src/kernel/battle.c b/src/kernel/battle.c index fb7b279ae..1abf5ad82 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -1585,7 +1585,7 @@ troop select_enemy(fighter * af, int minrow, int maxrow, int select) } } if (enemies != 0) { - log_error(("select_enemies has a bug.\n")); + log_error("select_enemies has a bug.\n"); } #ifdef DEBUG_SELECT return result; @@ -1779,7 +1779,7 @@ void do_combatmagic(battle * b, combatmagic_t was) int level = co->level; if (!sp->cast) { - log_error(("spell '%s' has no function.\n", sp->sname)); + log_error("spell '%s' has no function.\n", sp->sname); } else { level = sp->cast(co); if (level > 0) { @@ -1878,7 +1878,7 @@ static void do_combatspell(troop at) } if (!sp->cast) { - log_error(("spell '%s' has no function.\n", sp->sname)); + log_error("spell '%s' has no function.\n", sp->sname); } else { level = cast_combatspell(at, sp, level, power); } @@ -1894,7 +1894,7 @@ static void do_extra_spell(troop at, const att * a) const spell *sp = a->data.sp; if (sp->cast == NULL) { - log_error(("spell '%s' has no function.\n", sp->sname)); + log_error("spell '%s' has no function.\n", sp->sname); } else { cast_combatspell(at, sp, sp->level, sp->level * MagicPower()); } @@ -2133,7 +2133,7 @@ static void make_heroes(battle * b) if (fval(u, UFL_HERO)) { int i; if (!playerrace(u->race)) { - log_error(("Hero %s is a %s.\n", unitname(u), u->race->_name[0])); + log_error("Hero %s is a %s.\n", unitname(u), u->race->_name[0]); } for (i = 0; i != u->number; ++i) { fig->person[i].speed += (hero_speed - 1); @@ -2915,8 +2915,7 @@ static void aftermath(battle * b) dead_players += dead; } if (du->hp < du->number) { - log_error(("%s has less hitpoints (%u) than people (%u)\n", - itoa36(du->no), du->hp, du->number)); + log_error("%s has less hitpoints (%u) than people (%u)\n", itoa36(du->no), du->hp, du->number); du->hp = du->number; } } @@ -3684,7 +3683,7 @@ battle *make_battle(region * r) sprintf(zFilename, "%s/battle-%d-%s.log", zText, obs_count, simplename(r)); bdebug = fopen(zFilename, "w"); if (!bdebug) - log_error(("battles cannot be debugged\n")); + log_error("battles cannot be debugged\n"); else { const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf, 0 }; fwrite(utf8_bom, 1, 3, bdebug); diff --git a/src/kernel/binarystore.c b/src/kernel/binarystore.c index f74882fe7..2f750f4b4 100644 --- a/src/kernel/binarystore.c +++ b/src/kernel/binarystore.c @@ -156,8 +156,7 @@ static char *bin_r_str(struct storage *store) { char *p = strpbrk(result, "\n\r"); while (p) { - log_error(("Invalid character %d in input string \"%s\".\n", *p, - result)); + log_error("Invalid character %d in input string \"%s\".\n", *p, result); strcpy(p, p + 1); p = strpbrk(p, "\n\r"); } @@ -165,7 +164,7 @@ static char *bin_r_str(struct storage *store) #endif return result; } else if (len < 0) { - log_error(("invalid string-length %d in input.\n", len)); + log_error("invalid string-length %d in input.\n", len); } return NULL; } @@ -193,8 +192,7 @@ static void bin_r_str_buf(struct storage *store, char *result, size_t size) { char *p = strpbrk(result, "\n\r"); while (p) { - log_error(("Invalid character %d in input string \"%s\".\n", *p, - result)); + log_error("Invalid character %d in input string \"%s\".\n", *p, result); strcpy(p, p + 1); p = strpbrk(p, "\n\r"); } @@ -220,7 +218,7 @@ static void bin_r_bin(struct storage *store, void *result, size_t size) int len = store->r_int(store); if (len > 0) { if ((size_t) len > size) { - log_error(("destination buffer too small %d %u.\n", len, size)); + log_error("destination buffer too small %d %u.\n", len, size); fseek(file(store), len, SEEK_CUR); } else { fread(result, len, 1, file(store)); diff --git a/src/kernel/build.c b/src/kernel/build.c index 8ad6caaeb..c7b3ef7dc 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -420,9 +420,7 @@ int destroy_cmd(unit * u, struct order *ord) "unit region ship", u, r, sh)); } } else { - log_error( - ("Die Einheit %s von %s war owner eines objects, war aber weder in einer Burg noch in einem Schiff.\n", - unitname(u), u->faction->name, u->faction->email)); + log_error("Die Einheit %s von %s war owner eines objects, war aber weder in einer Burg noch in einem Schiff.\n", unitname(u), u->faction->name, u->faction->email); } if (con) { diff --git a/src/kernel/config.c b/src/kernel/config.c index f6f2d6352..8eb1c5b27 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -750,9 +750,9 @@ void verify_data(void) } } if (f->no != 0 && ((mage > 3 && f->race != new_race[RC_ELF]) || mage > 4)) - log_error(("Partei %s hat %d Magier.\n", factionid(f), mage)); + log_error("Partei %s hat %d Magier.\n", factionid(f), mage); if (alchemist > 3) - log_error(("Partei %s hat %d Alchemisten.\n", factionid(f), alchemist)); + log_error("Partei %s hat %d Alchemisten.\n", factionid(f), alchemist); } #endif } @@ -1224,8 +1224,7 @@ int count_all(const faction * f) } } if (f->num_people != n) { - log_error(("# of people in %s is != num_people: %d should be %d.\n", - factionid(f), f->num_people, n)); + log_error("# of people in %s is != num_people: %d should be %d.\n", factionid(f), f->num_people, n); } #endif return f->num_people; @@ -2130,7 +2129,7 @@ static void init_locale(const struct locale *lang) cb_new_kv(str, &i, sizeof(int), buffer); cb_insert(cb, buffer, strlen(str)+1+sizeof(int)); } else { - log_error(("could not transliterate param '%s'\n", key)); + log_error("could not transliterate param '%s'\n", key); } } #ifdef PTRIES diff --git a/src/kernel/connection.c b/src/kernel/connection.c index ba49f1b54..fa76da7a7 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -646,16 +646,14 @@ int read_borders(struct storage *store) type = find_bordertype(zText); if (type == NULL) { - log_error(("[read_borders] unknown connection type %s in %s\n", zText, - regionname(from, NULL))); + log_error("[read_borders] unknown connection type %s in %s\n", zText, regionname(from, NULL)); assert(type || !"connection type not registered"); } if (to == from && type && from) { direction_t dir = (direction_t) (rng_int() % MAXDIRECTIONS); region *r = rconnect(from, dir); - log_error(("[read_borders] invalid %s in %s\n", type->__name, - regionname(from, NULL))); + log_error("[read_borders] invalid %s in %s\n", type->__name, regionname(from, NULL)); if (r != NULL) to = r; } diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 0c3b74cd9..89b689e36 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -213,8 +213,7 @@ int curse_read(attrib * a, void *owner, struct storage *store) if (c->type == NULL) { int result = read_ccompat(cursename, store); if (result != 0) { - log_error(("missing curse %s, no compatibility code either.\n", - cursename)); + log_error("missing curse %s, no compatibility code either.\n", cursename); } assert(result == 0); return AT_READ_FAIL; @@ -766,7 +765,7 @@ message *cinfo_simple(const void *obj, typ_t typ, const struct curse * c, msg = msg_message(mkname("curseinfo", c->type->cname), "id", c->no); if (msg == NULL) { - log_error(("There is no curseinfo for %s.\n", c->type->cname)); + log_error("There is no curseinfo for %s.\n", c->type->cname); } return msg; } diff --git a/src/kernel/faction.c b/src/kernel/faction.c index 75aa7e26a..92cd0ac6a 100644 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -198,8 +198,7 @@ faction *addfaction(const char *email, const char *password, assert(frace); if (set_email(&f->email, email) != 0) { - log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), - email)); + log_error("Invalid email address for faction %s: %s\n", itoa36(f->no), email); } f->override = strdup(itoa36(rng_int())); diff --git a/src/kernel/item.c b/src/kernel/item.c index 75eb19dea..387112f71 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -494,8 +494,7 @@ item *i_change(item ** pi, const item_type * itype, int delta) item *i = *pi; i->number += delta; if (i->number < 0) { - log_error(("serious accounting error. number of items is %d.\n", - i->number)); + log_error("serious accounting error. number of items is %d.\n", i->number); /* FIXME what's this supposed to mean?? assert(i >= 0); */ diff --git a/src/kernel/magic.c b/src/kernel/magic.c index da4ff2bb0..0ab945981 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -221,7 +221,7 @@ void read_spells(struct quicklist **slistp, magic_t mtype, break; sp = find_spell(spname); if (!sp) { - log_error(("read_spells: could not find spell '%s' in school '%s'\n", spname, magic_school[mtype])); + log_error("read_spells: could not find spell '%s' in school '%s'\n", spname, magic_school[mtype]); } } if (sp) { @@ -257,7 +257,7 @@ static int read_mage(attrib * a, void *owner, struct storage *store) if (strcmp("none", spname) != 0) { sp = find_spell(spname); if (!sp) { - log_error(("read_mage: could not find combat spell '%s' in school '%s'\n", spname, magic_school[mage->magietyp])); + log_error("read_mage: could not find combat spell '%s' in school '%s'\n", spname, magic_school[mage->magietyp]); } } } @@ -356,7 +356,7 @@ static int read_seenspell(attrib * a, void *owner, struct storage *store) mtype = store->r_int(store); sp = find_spell(token); if (!sp) { - log_error(("read_seenspell: could not find spell '%s' in school '%s'\n", token, magic_school[mtype])); + log_error("read_seenspell: could not find spell '%s' in school '%s'\n", token, magic_school[mtype]); } } if (!sp) { @@ -547,8 +547,7 @@ void add_spellname(sc_mage * mage, const spell * sp) void add_spell(struct quicklist **slistp, spell * sp) { if (ql_set_insert(slistp, sp) != 0) { - log_error(("add_spell: the list already contains the spell '%s'.\n", - sp->sname)); + log_error("add_spell: the list already contains the spell '%s'.\n", sp->sname); } } @@ -2599,7 +2598,7 @@ static castorder *cast_cmd(unit * u, order * ord) sp = get_spellfromtoken(mage, s, caster->faction->locale); } else { /* somehow, this familiar has no mage! */ - log_error(("cast_cmd: familiar %s is without a mage?\n", unitname(u))); + log_error("cast_cmd: familiar %s is without a mage?\n", unitname(u)); caster = u; } } diff --git a/src/kernel/message.c b/src/kernel/message.c index c83479b28..b0c966522 100644 --- a/src/kernel/message.c +++ b/src/kernel/message.c @@ -90,7 +90,7 @@ struct message *msg_feedback(const struct unit *u, struct order *ord, ord = u->thisorder; if (!mtype) { - log_error(("trying to create message of unknown type \"%s\"\n", name)); + log_error("trying to create message of unknown type \"%s\"\n", name); return msg_message("missing_feedback", "unit region command name", u, u->region, ord, name); } @@ -126,8 +126,7 @@ struct message *msg_feedback(const struct unit *u, struct order *ord, assert(!"unknown variant type"); } } else { - log_error(("invalid parameter %s for message type %s\n", paramname, - mtype->name)); + log_error("invalid parameter %s for message type %s\n", paramname, mtype->name); assert(!"program aborted."); } while (*ic && !isalnum(*ic)) @@ -180,8 +179,7 @@ message *msg_message(const char *name, const char *sig, ...) assert(!"unknown variant type"); } } else { - log_error(("invalid parameter %s for message type %s\n", paramname, - mtype->name)); + log_error("invalid parameter %s for message type %s\n", paramname, mtype->name); assert(!"program aborted."); } while (*ic && !isalnum(*ic)) diff --git a/src/kernel/pool.c b/src/kernel/pool.c index f5150851a..e73bd4de0 100644 --- a/src/kernel/pool.c +++ b/src/kernel/pool.c @@ -63,7 +63,7 @@ int get_resource(const unit * u, const resource_type * rtype) return get_spellpoints(u); if (rtype == oldresourcetype[R_PERMAURA]) return max_spellpoints(u->region, u); - log_error(("trying to get unknown resource '%s'.\n", rtype->_name[0])); + log_error("trying to get unknown resource '%s'.\n", rtype->_name[0]); return 0; } diff --git a/src/kernel/race.c b/src/kernel/race.c index 3252f09b0..c89c5fb32 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -103,7 +103,7 @@ race *rc_new(const char *zName) rc->hitpoints = 1; if (strchr(zName, ' ') != NULL) { - log_error(("race '%s' has an invalid name. remove spaces\n", zName)); + log_error("race '%s' has an invalid name. remove spaces\n", zName); assert(strchr(zName, ' ') == NULL); } strcpy(zBuffer, zName); diff --git a/src/kernel/region.c b/src/kernel/region.c index 0221e8ee9..714180974 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -236,8 +236,7 @@ void register_special_direction(const char *name) dir_name_lookup = dl; } } else { - log_error(("no translation for spec_direction '%s' in locale '%s'\n", - name, locale_name(lang))); + log_error("no translation for spec_direction '%s' in locale '%s'\n", name, locale_name(lang)); } } } @@ -266,7 +265,7 @@ static int a_readdirection(attrib * a, void *owner, struct storage *store) } } if (dl == NULL) { - log_error(("unknown spec_direction '%s'\n", lbuf)); + log_error("unknown spec_direction '%s'\n", lbuf); assert(!"not implemented"); } } else { @@ -942,10 +941,9 @@ region *new_region(int x, int y, struct plane *pl, unsigned int uid) r = rfindhash(x, y); if (r) { - log_error(("duplicate region discovered: %s(%d,%d)\n", regionname(r, NULL), - x, y)); + log_error("duplicate region discovered: %s(%d,%d)\n", regionname(r, NULL), x, y); if (r->units) - log_error(("duplicate region contains units\n")); + log_error("duplicate region contains units\n"); return r; } r = calloc(1, sizeof(region)); diff --git a/src/kernel/reports.c b/src/kernel/reports.c index 3fef6cb51..aefcdae66 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -215,7 +215,7 @@ int update_nmrs(void) } else if (!is_monsters(f) && f->alive) { int nmr = turn - f->lastorders + 1; if (nmr < 0 || nmr > NMRTimeout()) { - log_error(("faction %s has %d NMRS\n", factionid(f), nmr)); + log_error("faction %s has %d NMRS\n", factionid(f), nmr); nmr = MAX(0, nmr); nmr = MIN(nmr, NMRTimeout()); } @@ -294,7 +294,7 @@ report_items(const item * items, item * result, int size, const unit * owner, } if (ishow == result + n) { if (n == size) { - log_error(("too many items to report, increase buffer size.\n")); + log_error("too many items to report, increase buffer size.\n"); return -1; } result[n].number = itm->number; @@ -988,11 +988,9 @@ struct message *msg_curse(const struct curse *c, const void *obj, typ_t typ, { "unit_unknown", "region_unknown", "building_unknown", "ship_unknown" }; msg = msg_message(mkname("curseinfo", unknown[typ]), "id", c->no); - log_error(("no curseinfo function for %s and no fallback either.\n", - c->type->cname)); + log_error("no curseinfo function for %s and no fallback either.\n", c->type->cname); } else { - log_error(("no curseinfo function for %s, using cinfo_simple fallback.\n", - c->type->cname)); + log_error("no curseinfo function for %s, using cinfo_simple fallback.\n", c->type->cname); } return msg; } @@ -1668,7 +1666,7 @@ int reports(void) sprintf(path, "%s/reports.txt", reportpath()); mailit = fopen(path, "w"); if (mailit == NULL) { - log_error(("%s could not be opened!\n", path)); + log_error("%s could not be opened!\n", path); } for (f = factions; f; f = f->next) { diff --git a/src/kernel/save.c b/src/kernel/save.c index c7132c5df..8f14c944c 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -180,7 +180,7 @@ int freadstr(FILE * F, int encoding, char *start, size_t size) if (ret > 0) str += ret; else { - log_error(("input data was not iso-8859-1! assuming utf-8\n")); + log_error("input data was not iso-8859-1! assuming utf-8\n"); encoding = XML_CHAR_ENCODING_ERROR; *str++ = (char)c; } @@ -200,7 +200,7 @@ int freadstr(FILE * F, int encoding, char *start, size_t size) if (ret > 0) str += ret; else { - log_error(("input data was not iso-8859-1! assuming utf-8\n")); + log_error("input data was not iso-8859-1! assuming utf-8\n"); encoding = XML_CHAR_ENCODING_ERROR; *str++ = (char)c; } @@ -538,8 +538,7 @@ void read_items(struct storage *store, item ** ilist) itype = it_find(ibuf); i = store->r_int(store); if (i <= 0) { - log_error(("data contains an entry with %d %s\n", i, - itype->rtype->_name[1])); + log_error("data contains an entry with %d %s\n", i, itype->rtype->_name[1]); } else { assert(itype != NULL); if (itype != NULL) { @@ -621,7 +620,7 @@ static int resolve_owner(variant id, void *address) if (id.i != 0) { f = findfaction(id.i); if (f == NULL) { - log_error(("region has an invalid owner (%s)\n", itoa36(id.i))); + log_error("region has an invalid owner (%s)\n", itoa36(id.i)); f = get_monsters(); } } @@ -782,7 +781,7 @@ unit *read_unit(struct storage *store) } } if (u->faction == NULL) { - log_error(("unit %s has faction == NULL\n", unitname(u))); + log_error("unit %s has faction == NULL\n", unitname(u)); u_setfaction(u, get_monsters()); set_number(u, 0); } @@ -857,8 +856,7 @@ unit *read_unit(struct storage *store) read_items(store, &u->items); u->hp = store->r_int(store); if (u->hp < u->number) { - log_error(("Einheit %s hat %u Personen, und %u Trefferpunkte\n", - itoa36(u->no), u->number, u->hp)); + log_error("Einheit %s hat %u Personen, und %u Trefferpunkte\n", itoa36(u->no), u->number, u->hp); u->hp = u->number; } @@ -888,8 +886,7 @@ void write_unit(struct storage *store, const unit * u) if (++p < MAXPERSISTENT) { writeorder(store, ord, u->faction->locale); } else { - log_error(("%s had %d or more persistent orders\n", unitname(u), - MAXPERSISTENT)); + log_error("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT); break; } } @@ -900,8 +897,7 @@ void write_unit(struct storage *store, const unit * u) if (++p < MAXPERSISTENT) { writeorder(store, ord, u->faction->locale); } else { - log_error(("%s had %d or more persistent orders\n", unitname(u), - MAXPERSISTENT)); + log_error("%s had %d or more persistent orders\n", unitname(u), MAXPERSISTENT); break; } } @@ -926,7 +922,7 @@ void write_unit(struct storage *store, const unit * u) write_items(store, u->items); store->w_brk(store); if (u->hp == 0) { - log_error(("unit %s has 0 hitpoints, adjusting.\n", itoa36(u->no))); + log_error("unit %s has 0 hitpoints, adjusting.\n", itoa36(u->no)); ((unit *) u)->hp = u->number; } store->w_int(store, u->hp); @@ -977,9 +973,7 @@ static region *readregion(struct storage *store, int x, int y) int ter = store->r_int(store); terrain = newterrain((terrain_t) ter); if (terrain == NULL) { - log_error( - ("while reading datafile from pre-TERRAIN_VERSION, could not find terrain #%d.\n", - ter)); + log_error("while reading datafile from pre-TERRAIN_VERSION, could not find terrain #%d.\n", ter); terrain = newterrain(T_PLAIN); } } else { @@ -987,7 +981,7 @@ static region *readregion(struct storage *store, int x, int y) store->r_str_buf(store, name, sizeof(name)); terrain = get_terrain(name); if (terrain == NULL) { - log_error(("Unknown terrain '%s'\n", name)); + log_error("Unknown terrain '%s'\n", name); assert(!"unknown terrain"); } } @@ -1006,20 +1000,19 @@ static region *readregion(struct storage *store, int x, int y) i = store->r_int(store); if (i < 0) { - log_error(("number of trees in %s is %d.\n", regionname(r, NULL), i)); + log_error("number of trees in %s is %d.\n", regionname(r, NULL), i); i = 0; } rsettrees(r, 0, i); i = store->r_int(store); if (i < 0) { - log_error(("number of young trees in %s is %d.\n", - regionname(r, NULL), i)); + log_error("number of young trees in %s is %d.\n", regionname(r, NULL), i); i = 0; } rsettrees(r, 1, i); i = store->r_int(store); if (i < 0) { - log_error(("number of seeds in %s is %d.\n", regionname(r, NULL), i)); + log_error("number of seeds in %s is %d.\n", regionname(r, NULL), i); i = 0; } rsettrees(r, 2, i); @@ -1035,7 +1028,7 @@ static region *readregion(struct storage *store, int x, int y) res = malloc(sizeof(rawmaterial)); res->type = rmt_find(token); if (res->type == NULL) { - log_error(("invalid resourcetype %s in data.\n", token)); + log_error("invalid resourcetype %s in data.\n", token); } assert(res->type != NULL); res->level = store->r_int(store); @@ -1650,8 +1643,7 @@ int readgame(const char *filename, int mode, int backup) faction *f = u->faction; int skl = effskill(u, SK_MAGIC); if (!is_monsters(f) && f->magiegebiet == M_GRAY) { - log_error(("faction %s had magic=gray, fixing (%s)\n", - factionname(f), magic_school[mage->magietyp])); + log_error("faction %s had magic=gray, fixing (%s)\n", factionname(f), magic_school[mage->magietyp]); f->magiegebiet = mage->magietyp; } if (f->max_spelllevel < skl) { diff --git a/src/kernel/skill.c b/src/kernel/skill.c index 7a41b8b33..238ac6378 100644 --- a/src/kernel/skill.c +++ b/src/kernel/skill.c @@ -92,7 +92,7 @@ void enable_skill(const char *skname, boolean value) return; } } - log_error(("Trying to set unknown skill %s to %u", skname, value)); + log_error("Trying to set unknown skill %s to %u", skname, value); } skill_t sk_find(const char *name) diff --git a/src/kernel/sqlite.c b/src/kernel/sqlite.c index 496a902d3..d8194e421 100644 --- a/src/kernel/sqlite.c +++ b/src/kernel/sqlite.c @@ -233,8 +233,7 @@ int db_update_factions(sqlite3 * db, boolean force) for (f = factions; f; f = f->next) { if (!fval(f, FFL_MARK)) { - log_error(("%s (sub=%d, email=%s) has no entry in the database\n", - factionname(f), f->subscription, f->email)); + log_error("%s (sub=%d, email=%s) has no entry in the database\n", factionname(f), f->subscription, f->email); } else { freset(f, FFL_MARK); } diff --git a/src/kernel/teleport.c b/src/kernel/teleport.c index 311f185ec..51428f7b8 100644 --- a/src/kernel/teleport.c +++ b/src/kernel/teleport.c @@ -68,7 +68,7 @@ region_list *astralregions(const region * r, boolean(*valid) (const region *)) assert(is_astral(r)); if (!is_astral(r)) { - log_error(("astralregions was called with a non-astral region.\n")); + log_error("astralregions was called with a non-astral region.\n"); return NULL; } r = r_astral_to_standard(r); diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 40f32fe12..c1ed36b76 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -182,8 +182,7 @@ xml_readconstruction(xmlXPathContextPtr xpath, xmlNodeSetPtr nodeSet, if (propValue != NULL) { sk = sk_find((const char *)propValue); if (sk == NOSKILL) { - log_error(("construction requires skill '%s' that does not exist.\n", - (const char *)propValue)); + log_error("construction requires skill '%s' that does not exist.\n", (const char *)propValue); xmlFree(propValue); continue; } @@ -313,8 +312,7 @@ static int parse_buildings(xmlDocPtr doc) parse_function(node, &fun, &propValue); if (fun == NULL) { - log_error(("unknown function name '%s' for building %s\n", - (const char *)propValue, btype->_name)); + log_error("unknown function name '%s' for building %s\n", (const char *)propValue, btype->_name); xmlFree(propValue); continue; } @@ -334,8 +332,7 @@ static int parse_buildings(xmlDocPtr doc) } else if (strcmp((const char *)propValue, "age") == 0) { btype->age = (void (*)(struct building *))fun; } else { - log_error(("unknown function type '%s' for building %s\n", - (const char *)propValue, btype->_name)); + log_error("unknown function type '%s' for building %s\n", (const char *)propValue, btype->_name); } xmlFree(propValue); } @@ -818,8 +815,7 @@ static weapon_type *xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) parse_function(node, &fun, &propValue); if (fun == NULL) { - log_error(("unknown function name '%s' for item '%s'\n", - (const char *)propValue, itype->rtype->_name[0])); + log_error("unknown function name '%s' for item '%s'\n", (const char *)propValue, itype->rtype->_name[0]); xmlFree(propValue); continue; } @@ -829,8 +825,7 @@ static weapon_type *xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) (boolean(*)(const struct troop *, const struct weapon_type *, int *))fun; } else { - log_error(("unknown function type '%s' for item '%s'\n", - (const char *)propValue, itype->rtype->_name[0])); + log_error("unknown function type '%s' for item '%s'\n", (const char *)propValue, itype->rtype->_name[0]); } xmlFree(propValue); } @@ -926,8 +921,7 @@ static item_type *xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) parse_function(node, &fun, &propValue); if (fun == NULL) { - log_error(("unknown function name '%s' for item '%s'\n", - (const char *)propValue, rtype->_name[0])); + log_error("unknown function name '%s' for item '%s'\n", (const char *)propValue, rtype->_name[0]); xmlFree(propValue); continue; } @@ -948,8 +942,7 @@ static item_type *xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) (int (*)(struct unit *, int, const struct item_type *, int, struct order *))fun; } else { - log_error(("unknown function type '%s' for item '%s'\n", - (const char *)propValue, rtype->_name[0])); + log_error("unknown function type '%s' for item '%s'\n", (const char *)propValue, rtype->_name[0]); } xmlFree(propValue); } @@ -977,8 +970,7 @@ static int parse_rules(xmlDocPtr doc) parse_function(node, &fun, &propValue); if (fun == NULL) { - log_error(("unknown function for rule '%s' %s\n", - (const char *)propValue)); + log_error("unknown function for rule '%s' %s\n", (const char *)propValue); xmlFree(propValue); continue; } @@ -990,7 +982,7 @@ static int parse_rules(xmlDocPtr doc) } else if (strcmp((const char *)propValue, "maintenance") == 0) { global.functions.maintenance = (int (*)(const struct unit *))fun; } else { - log_error(("unknown function for rule '%s'\n", (const char *)propValue)); + log_error("unknown function for rule '%s'\n", (const char *)propValue); } xmlFree(propValue); } @@ -1085,8 +1077,7 @@ static int parse_resources(xmlDocPtr doc) parse_function(node, &fun, &propValue); if (fun == NULL) { - log_error(("unknown function name '%s' for resource %s\n", - (const char *)propValue, rtype->_name[0])); + log_error("unknown function name '%s' for resource %s\n", (const char *)propValue, rtype->_name[0]); xmlFree(propValue); continue; } @@ -1099,8 +1090,7 @@ static int parse_resources(xmlDocPtr doc) } else if (strcmp((const char *)propValue, "name") == 0) { rtype->name = (rtype_name) fun; } else { - log_error(("unknown function type '%s' for resource %s\n", - (const char *)propValue, rtype->_name[0])); + log_error("unknown function type '%s' for resource %s\n", (const char *)propValue, rtype->_name[0]); } xmlFree(propValue); } @@ -1168,8 +1158,7 @@ static int parse_resources(xmlDocPtr doc) xmlFree(propBldg); } } else { - log_error(("unknown type '%s' for resourcelimit-modifier '%s'\n", - (const char *)propValue, rtype->_name[0])); + log_error("unknown type '%s' for resourcelimit-modifier '%s'\n", (const char *)propValue, rtype->_name[0]); } xmlFree(propValue); } @@ -1204,8 +1193,7 @@ static int parse_resources(xmlDocPtr doc) assert(propValue != NULL); fun = get_function((const char *)propValue); if (fun == NULL) { - log_error(("unknown limit '%s' for resource %s\n", - (const char *)propValue, rtype->_name[0])); + log_error("unknown limit '%s' for resource %s\n", (const char *)propValue, rtype->_name[0]); xmlFree(propValue); continue; } @@ -1218,8 +1206,7 @@ static int parse_resources(xmlDocPtr doc) } else if (strcmp((const char *)propValue, "limit") == 0) { rdata->limit = (rlimit_limit) fun; } else { - log_error(("unknown limit '%s' for resource %s\n", - (const char *)propValue, rtype->_name[0])); + log_error("unknown limit '%s' for resource %s\n", (const char *)propValue, rtype->_name[0]); } xmlFree(propValue); } @@ -1323,8 +1310,7 @@ static void add_spells(equipment * eq, xmlNodeSetPtr nsetItems) assert(propValue != NULL); sp = find_spell((const char *)propValue); if (!sp) { - log_error(("no spell '%s' in school '%s' for equipment-set '%s'\n", - (const char *)propValue, magic_school[mtype], eq->name)); + log_error("no spell '%s' in school '%s' for equipment-set '%s'\n", (const char *)propValue, magic_school[mtype], eq->name); } else { equipment_addspell(eq, sp); } @@ -1346,8 +1332,7 @@ static void add_skills(equipment * eq, xmlNodeSetPtr nsetSkills) assert(propValue != NULL); sk = sk_find((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, eq->name); xmlFree(propValue); } else { xmlFree(propValue); @@ -1410,8 +1395,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, eq->name); } } xmlXPathFreeObject(xpathResult); @@ -1558,7 +1542,7 @@ static int parse_spells(xmlDocPtr doc) if (result->nodesetval->nodeNr == 0) { cast = get_function(sp->sname); if (!cast) { - log_error(("no spell cast function registered for '%s'\n", sp->sname)); + log_error("no spell cast function registered for '%s'\n", sp->sname); valid = 0; } strlcpy(zText+7, sp->sname, sizeof(zText)-7); @@ -1575,15 +1559,13 @@ static int parse_spells(xmlDocPtr doc) cast = fun; valid = 1; } else { - log_error(("unknown function name '%s' for spell '%s'\n", - (const char *)propValue, sp->sname)); + log_error("unknown function name '%s' for spell '%s'\n", (const char *)propValue, sp->sname); valid = 0; } } else if (fun && strcmp((const char *)propValue, "fumble") == 0) { fumble = fun; } else { - log_error(("unknown function type '%s' for spell '%s'\n", - (const char *)propValue, sp->sname)); + log_error("unknown function type '%s' for spell '%s'\n", (const char *)propValue, sp->sname); } xmlFree(propValue); } @@ -1611,8 +1593,7 @@ static int parse_spells(xmlDocPtr doc) assert(propValue); rtype = rt_find((const char *)propValue); if (!rtype) { - log_error(("spell %s uses unknown component %s.\n", sp->sname, - (const char *)propValue)); + log_error("spell %s uses unknown component %s.\n", sp->sname, (const char *)propValue); xmlFree(propValue); continue; } @@ -1831,8 +1812,7 @@ static int parse_races(xmlDocPtr doc) rc->study_speed[sk] = (char)speed; } } else { - log_error(("unknown skill '%s' in race '%s'\n", - (const char *)propValue, rc->_name[0])); + log_error("unknown skill '%s' in race '%s'\n", (const char *)propValue, rc->_name[0]); } xmlFree(propValue); } @@ -1848,8 +1828,7 @@ static int parse_races(xmlDocPtr doc) parse_function(node, &fun, &propValue); if (fun == NULL) { - log_error(("unknown function name '%s' for race %s\n", - (const char *)propValue, rc->_name[0])); + log_error("unknown function name '%s' for race %s\n", (const char *)propValue, rc->_name[0]); xmlFree(propValue); continue; } @@ -1869,8 +1848,7 @@ static int parse_races(xmlDocPtr doc) } else if (strcmp((const char *)propValue, "initfamiliar") == 0) { rc->init_familiar = (void (*)(struct unit *))fun; } else { - log_error(("unknown function type '%s' for race %s\n", - (const char *)propValue, rc->_name[0])); + log_error("unknown function type '%s' for race %s\n", (const char *)propValue, rc->_name[0]); } xmlFree(propValue); } @@ -2320,8 +2298,7 @@ static int parse_main(xmlDocPtr doc) } } if (k == MAXKEYWORDS) { - log_error(("trying to disable unknown comand %s\n", - (const char *)propName)); + log_error("trying to disable unknown comand %s\n", (const char *)propName); } } xmlFree(propName); diff --git a/src/modules/arena.c b/src/modules/arena.c index 52e6e351f..f3acefddd 100644 --- a/src/modules/arena.c +++ b/src/modules/arena.c @@ -247,7 +247,7 @@ static int read_hurting(attrib * a, void *owner, struct storage *store) i = store->r_int(store); a->data.v = (void *)findbuilding(i); if (a->data.v == NULL) { - log_error(("temple of pain is broken\n")); + log_error("temple of pain is broken\n"); return AT_READ_FAIL; } return AT_READ_OK; @@ -263,7 +263,7 @@ static void make_temple(region * r) const building_type *btype = bt_find("temple"); building *b; if (btype == NULL) { - log_error(("could not find buildingtype 'temple'\n")); + log_error("could not find buildingtype 'temple'\n"); return; } @@ -428,7 +428,7 @@ static int caldera_handle(trigger * t, void *data) up = &u->next; } } else { - log_error(("could not perform caldera::handle()\n")); + log_error("could not perform caldera::handle()\n"); } unused(data); return 0; diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c index 79fa5e478..324eb98d8 100644 --- a/src/modules/autoseed.c +++ b/src/modules/autoseed.c @@ -266,8 +266,7 @@ newfaction *read_newfactions(const char *filename) continue; nf = calloc(sizeof(newfaction), 1); if (set_email(&nf->email, email) != 0) { - log_error(("Invalid email address for subscription %s: %s\n", - itoa36(subscription), email)); + log_error("Invalid email address for subscription %s: %s\n", itoa36(subscription), email); continue; } nf->password = strdup(password); @@ -296,7 +295,7 @@ newfaction *read_newfactions(const char *filename) buffer[outbytes] = 0; nf->race = findrace(buffer, default_locale); if (nf->race == NULL) { - log_error(("new faction has unknown race '%s'.\n", race)); + log_error("new faction has unknown race '%s'.\n", race); free(nf); continue; } diff --git a/src/modules/gmcmd.c b/src/modules/gmcmd.c index 4552172f5..5f6caeb0c 100644 --- a/src/modules/gmcmd.c +++ b/src/modules/gmcmd.c @@ -109,7 +109,7 @@ static int read_gmcreate(attrib * a, void *owner, struct storage *store) store->r_tok_buf(store, zText, sizeof(zText)); a->data.v = it_find(zText); if (a->data.v == NULL) { - log_error(("unknown itemtype %s in gmcreate attribute\n", zText)); + log_error("unknown itemtype %s in gmcreate attribute\n", zText); return AT_READ_FAIL; } return AT_READ_OK; @@ -667,8 +667,7 @@ faction *gm_addfaction(const char *email, plane * p, region * r) f->passw = strdup(itoa36(rng_int())); f->override = strdup(itoa36(rng_int())); if (set_email(&f->email, email) != 0) { - log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), - email)); + log_error("Invalid email address for faction %s: %s\n", itoa36(f->no), email); } f->race = new_race[RC_TEMPLATE]; f->age = 0; diff --git a/src/triggers/changefaction.c b/src/triggers/changefaction.c index a368bd567..60d821412 100644 --- a/src/triggers/changefaction.c +++ b/src/triggers/changefaction.c @@ -67,7 +67,7 @@ static int changefaction_handle(trigger * t, void *data) if (td->unit && td->faction) { u_setfaction(td->unit, td->faction); } else { - log_error(("could not perform changefaction::handle()\n")); + log_error("could not perform changefaction::handle()\n"); } unused(data); return 0; diff --git a/src/triggers/changerace.c b/src/triggers/changerace.c index b7bbd9859..122384fb4 100644 --- a/src/triggers/changerace.c +++ b/src/triggers/changerace.c @@ -70,7 +70,7 @@ static int changerace_handle(trigger * t, void *data) if (td->irace != NULL) td->u->irace = td->irace; } else { - log_error(("could not perform changerace::handle()\n")); + log_error("could not perform changerace::handle()\n"); } unused(data); return 0; diff --git a/src/triggers/clonedied.c b/src/triggers/clonedied.c index f861a54a2..665379ae7 100644 --- a/src/triggers/clonedied.c +++ b/src/triggers/clonedied.c @@ -54,7 +54,7 @@ static int clonedied_handle(trigger * t, void *data) if (a) a_remove(&u->attribs, a); } else - log_error(("could not perform clonedied::handle()\n")); + log_error("could not perform clonedied::handle()\n"); unused(data); return 0; } diff --git a/src/triggers/createcurse.c b/src/triggers/createcurse.c index 56e1d9d6f..01135f588 100644 --- a/src/triggers/createcurse.c +++ b/src/triggers/createcurse.c @@ -73,7 +73,7 @@ static int createcurse_handle(trigger * t, void *data) create_curse(td->mage, &td->target->attribs, td->type, td->vigour, td->duration, td->effect, td->men); } else { - log_error(("could not perform createcurse::handle()\n")); + log_error("could not perform createcurse::handle()\n"); } unused(data); return 0; diff --git a/src/triggers/createunit.c b/src/triggers/createunit.c index 9973b2385..45671735a 100644 --- a/src/triggers/createunit.c +++ b/src/triggers/createunit.c @@ -71,7 +71,7 @@ static int createunit_handle(trigger * t, void *data) if (td->r != NULL && td->f != NULL) { create_unit(td->r, td->f, td->number, td->race, 0, NULL, NULL); } else { - log_error(("could not perform createunit::handle()\n")); + log_error("could not perform createunit::handle()\n"); } unused(data); return 0; diff --git a/src/triggers/gate.c b/src/triggers/gate.c index 20be3ae4c..4859d929c 100644 --- a/src/triggers/gate.c +++ b/src/triggers/gate.c @@ -53,7 +53,7 @@ static int gate_handle(trigger * t, void *data) up = &u->next; } } else { - log_error(("could not perform gate::handle()\n")); + log_error("could not perform gate::handle()\n"); return -1; } unused(data); diff --git a/src/triggers/giveitem.c b/src/triggers/giveitem.c index 2aaf9b6b9..3cdefd63e 100644 --- a/src/triggers/giveitem.c +++ b/src/triggers/giveitem.c @@ -66,7 +66,7 @@ static int giveitem_handle(trigger * t, void *data) if (td->u && td->u->number) { i_change(&td->u->items, td->itype, td->number); } else { - log_error(("could not perform giveitem::handle()\n")); + log_error("could not perform giveitem::handle()\n"); } unused(data); return 0; diff --git a/src/triggers/removecurse.c b/src/triggers/removecurse.c index aa084ad61..80eb6c3c6 100644 --- a/src/triggers/removecurse.c +++ b/src/triggers/removecurse.c @@ -65,7 +65,7 @@ static int removecurse_handle(trigger * t, void *data) if (a) { a_remove(&td->target->attribs, a); } else - log_error(("could not perform removecurse::handle()\n")); + log_error("could not perform removecurse::handle()\n"); } unused(data); return 0; diff --git a/src/triggers/shock.c b/src/triggers/shock.c index 3b6b4a885..ec55ab7ff 100644 --- a/src/triggers/shock.c +++ b/src/triggers/shock.c @@ -111,8 +111,7 @@ static void shock_write(const trigger * t, struct storage *store) next = next->next; } if (next && u) { - log_error(("more than one shock-attribut for %s on a unit. FIXED.\n", - unitid(u))); + log_error("more than one shock-attribut for %s on a unit. FIXED.\n", unitid(u)); write_unit_reference(NULL, store); } else { write_unit_reference(u, store); diff --git a/src/triggers/unguard.c b/src/triggers/unguard.c index 2ff3302cf..5cdaf63d5 100644 --- a/src/triggers/unguard.c +++ b/src/triggers/unguard.c @@ -35,7 +35,7 @@ static int unguard_handle(trigger * t, void *data) if (b) { fset(b, BLD_UNGUARDED); } else { - log_error(("could not perform unguard::handle()\n")); + log_error("could not perform unguard::handle()\n"); return -1; } unused(data); diff --git a/src/util/crmessage.c b/src/util/crmessage.c index 886931c4c..f02c8d25d 100644 --- a/src/util/crmessage.c +++ b/src/util/crmessage.c @@ -119,8 +119,7 @@ int cr_render(const message * msg, char *buffer, const void *userdata) return -1; for (i = 0; i != msg->type->nparameters; ++i) { if (crt->renderers[i] == NULL) { - log_error(("No renderer for argument %s:%s of \"%s\"\n", - msg->type->pnames[i], msg->type->types[i]->name, msg->type->name)); + log_error("No renderer for argument %s:%s of \"%s\"\n", msg->type->pnames[i], msg->type->types[i]->name, msg->type->name); continue; /* strcpy(c, (const char*)msg->locale_string(u->faction->locale, parameters[i])); */ } else { if (crt->renderers[i] (msg->parameters[i], c, userdata) != 0) diff --git a/src/util/filereader.c b/src/util/filereader.c index 81ce78110..1b6f79488 100644 --- a/src/util/filereader.c +++ b/src/util/filereader.c @@ -160,7 +160,7 @@ static const char *getbuf_latin1(FILE * F) if (ret > 0) cp += ret; else { - log_error(("input data was not iso-8859-1! assuming utf-8\n")); + log_error("input data was not iso-8859-1! assuming utf-8\n"); return NULL; } diff --git a/src/util/language.c b/src/util/language.c index a763ffe04..9bb36cd2d 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -181,7 +181,7 @@ void locale_setstring(locale * lang, const char *key, const char *value) find->str = strdup(value); } else { if (strcmp(find->str, value) != 0) { - log_error(("duplicate translation '%s' for key %s\n", value, key)); + log_error("duplicate translation '%s' for key %s\n", value, key); } assert(!strcmp(find->str, value) || !"duplicate string for key"); } diff --git a/src/util/log.c b/src/util/log.c index e09946c3c..411f4d53c 100644 --- a/src/util/log.c +++ b/src/util/log.c @@ -224,7 +224,7 @@ void log_warning(const char *format, ...) } } -void _log_error(const char *format, ...) +void log_error(const char *format, ...) { const char * prefix = "ERROR"; const int mask = LOG_CPERROR; diff --git a/src/util/log.h b/src/util/log.h index 88607a343..9c49032f6 100644 --- a/src/util/log.h +++ b/src/util/log.h @@ -19,12 +19,11 @@ extern "C" { extern void log_close(void); extern void log_flush(void); -#define log_error(x) _log_error x #define log_debug _log_debug /* use macros above instead of these: */ extern void log_warning(const char *format, ...); - extern void _log_error(const char *format, ...); + extern void log_error(const char *format, ...); extern void _log_debug(const char *format, ...); extern void log_info(const char *format, ...); extern void log_printf(FILE * ios, const char *format, ...); diff --git a/src/util/message.c b/src/util/message.c index 9bf78821b..3476ac5a6 100644 --- a/src/util/message.c +++ b/src/util/message.c @@ -39,7 +39,7 @@ message_type *mt_new(const char *name, const char *args[]) assert(name != NULL); if (name == NULL) { - log_error(("Trying to create message_type with name=0x0\n")); + log_error("Trying to create message_type with name=0x0\n"); return NULL; } if (args != NULL) @@ -67,8 +67,7 @@ message_type *mt_new(const char *name, const char *args[]) mtype->pnames[i] = cp; mtype->types[i] = find_argtype(spos + 1); if (mtype->types[i] == NULL) { - log_error(("unknown argument type %s for message type %s\n", - spos + 1, mtype->name)); + log_error("unknown argument type %s for message type %s\n", spos + 1, mtype->name); } assert(mtype->types[i]); } @@ -141,7 +140,7 @@ message *msg_create(const struct message_type *mtype, variant args[]) assert(mtype != NULL); if (mtype == NULL) { - log_error(("Trying to create message with type=0x0\n")); + log_error("Trying to create message with type=0x0\n"); return NULL; } msg->type = mtype; diff --git a/src/util/nrmessage.c b/src/util/nrmessage.c index 20b918ff4..6acd14663 100644 --- a/src/util/nrmessage.c +++ b/src/util/nrmessage.c @@ -107,7 +107,7 @@ nrt_register(const struct message_type *mtype, const struct locale *lang, nrt = nrt->next; } if (nrt) { - log_error(("duplicate message-type %s\n", mtype->name)); + log_error("duplicate message-type %s\n", mtype->name); assert(!nrt || !"trying to register same nr-type twice"); } else { int i; @@ -151,7 +151,7 @@ nr_render(const struct message *msg, const struct locale *lang, char *buffer, if (m) { return strlcpy((char *)buffer, m, size); } else { - log_error(("Couldn't render message %s\n", nrt->mtype->name)); + log_error("Couldn't render message %s\n", nrt->mtype->name); } } if (size > 0 && buffer) diff --git a/src/util/translation.c b/src/util/translation.c index 9c329592d..365b463c1 100644 --- a/src/util/translation.c +++ b/src/util/translation.c @@ -210,7 +210,7 @@ static const char *parse_symbol(opstack ** stack, const char *in, ++in; foo = find_function(symbol); if (foo == NULL) { - log_error(("parser does not know about \"%s\" function.\n", symbol)); + log_error("parser does not know about \"%s\" function.\n", symbol); return NULL; } foo(stack, userdata); /* will pop parameters from stack (reverse order!) and push the result */ @@ -221,7 +221,7 @@ static const char *parse_symbol(opstack ** stack, const char *in, } /* it's a constant (variable is a misnomer, but heck, const was taken;)) */ if (var == NULL) { - log_error(("parser does not know about \"%s\" variable.\n", symbol)); + log_error("parser does not know about \"%s\" variable.\n", symbol); return NULL; } opush(stack, var->value); @@ -352,7 +352,7 @@ static const char *parse(opstack ** stack, const char *inn, ++b; } } - log_error(("could not parse \"%s\". Probably invalid message syntax.", inn)); + log_error("could not parse \"%s\". Probably invalid message syntax.", inn); return NULL; } @@ -390,7 +390,7 @@ const char *translate(const char *format, const void *userdata, } if (rv != NULL) { if (rv[0]) { - log_error(("residual data after parsing: %s\n", rv)); + log_error("residual data after parsing: %s\n", rv); } rv = (const char *)opop(&stack).v; free(stack->begin); diff --git a/src/util/xml.c b/src/util/xml.c index bb6a9a302..297d8c89b 100644 --- a/src/util/xml.c +++ b/src/util/xml.c @@ -118,7 +118,7 @@ int read_xml(const char *filename, const char *catalog) doc = xmlParseFile(filename); #endif if (doc == NULL) { - log_error(("could not open %s\n", filename)); + log_error("could not open %s\n", filename); return -1; } From ff5dc2534e4a359a55fed0cc92ca0c7a008e88ed Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 16 May 2012 16:56:07 -0700 Subject: [PATCH 196/400] rename _log_debug to log_debug and get rid of the cumbersome #define --- src/util/log.c | 2 +- src/util/log.h | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/util/log.c b/src/util/log.c index 411f4d53c..48155cde3 100644 --- a/src/util/log.c +++ b/src/util/log.c @@ -168,7 +168,7 @@ static void _log_write(FILE * stream, int codepage, const char * prefix, const c } } -void _log_debug(const char *format, ...) +void log_debug(const char *format, ...) { const char * prefix = "DEBUG"; const int mask = LOG_CPDEBUG; diff --git a/src/util/log.h b/src/util/log.h index 9c49032f6..ffc4a297b 100644 --- a/src/util/log.h +++ b/src/util/log.h @@ -19,12 +19,10 @@ extern "C" { extern void log_close(void); extern void log_flush(void); -#define log_debug _log_debug - /* use macros above instead of these: */ extern void log_warning(const char *format, ...); extern void log_error(const char *format, ...); - extern void _log_debug(const char *format, ...); + extern void log_debug(const char *format, ...); extern void log_info(const char *format, ...); extern void log_printf(FILE * ios, const char *format, ...); From d12fe2dbed54221983cbe62fad4638021a275d0c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 17 May 2012 00:13:30 -0700 Subject: [PATCH 197/400] begin making shipowner use ship->owner. fix a broken test caused by locale_string returning null. --- src/bindings/bind_ship.c | 2 +- src/bindings/bind_unit.c | 2 +- src/gamecode/creport.c | 2 +- src/gamecode/give.c | 4 +-- src/gamecode/laws.c | 74 ++++++-------------------------------- src/gamecode/laws_test.c | 12 +++---- src/gamecode/report.c | 2 +- src/gamecode/spy.c | 3 +- src/kernel.vcxproj | 1 + src/kernel.vcxproj.filters | 3 ++ src/kernel/build.c | 48 +++++++++++-------------- src/kernel/build.h | 4 +-- src/kernel/building.c | 2 +- src/kernel/building.h | 2 +- src/kernel/curse.c | 2 +- src/kernel/curse.h | 7 ++-- src/kernel/magic.h | 2 +- src/kernel/move.c | 4 +-- src/kernel/move_test.c | 5 ++- src/kernel/objtypes.h | 4 +-- src/kernel/reports.c | 2 +- src/kernel/reports.h | 3 +- src/kernel/save.c | 9 +++-- src/kernel/ship.c | 15 +++++--- src/kernel/ship.h | 5 +-- src/kernel/ship_test.c | 63 ++++++++++++++++++++++++++++++++ src/kernel/types.h | 1 - src/kernel/unit.c | 33 ++++++++++++----- src/kernel/unit.h | 5 +-- src/kernel/xmlreader.c | 2 +- src/modules/xecmd.c | 7 ++-- src/tests.c | 11 ++++++ src/tests.h | 2 +- 33 files changed, 193 insertions(+), 150 deletions(-) create mode 100644 src/kernel/ship_test.c diff --git a/src/bindings/bind_ship.c b/src/bindings/bind_ship.c index a72dec778..d5319dfe0 100644 --- a/src/bindings/bind_ship.c +++ b/src/bindings/bind_ship.c @@ -109,7 +109,7 @@ static int tolua_ship_create(lua_State * L) if (sname) { const ship_type *stype = st_find(sname); if (stype) { - ship *sh = new_ship(stype, default_locale, r); + ship *sh = new_ship(stype, r, default_locale); sh->size = stype->construction->maxsize; tolua_pushusertype(L, (void *)sh, TOLUA_CAST "ship"); return 1; diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 1760d414a..139740237 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -645,7 +645,7 @@ static void unit_setship(unit * u, ship * s) if (s && u->region != s->region) { move_unit(u, s->region, NULL); } - u->ship = s; + u_set_ship(u, s); } static int tolua_unit_set_ship(lua_State * L) diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index 1e50f99a4..9d67f2def 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -173,7 +173,7 @@ static void print_items(FILE * F, item * items, const struct locale *lang) } static void -cr_output_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ) +cr_output_curses(FILE * F, const faction * viewer, const void *obj, objtype_t typ) { boolean header = false; attrib *a = NULL; diff --git a/src/gamecode/give.c b/src/gamecode/give.c index bee31ab33..755b97c26 100644 --- a/src/gamecode/give.c +++ b/src/gamecode/give.c @@ -311,9 +311,9 @@ void give_men(int n, unit * u, unit * u2, struct order *ord) /* Einheiten von Schiffen können nicht NACH in von * Nicht-alliierten bewachten Regionen ausführen */ sh = leftship(u); - if (sh) + if (sh) { set_leftship(u2, sh); - + } transfermen(u, u2, n); if (u->faction != u2->faction) { u2->faction->newbies += n; diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 47205e098..ee13b8257 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -1617,11 +1617,14 @@ static int display_cmd(unit * u, struct order *ord) boolean renamed_building(const building * b) { const struct locale *lang = locales; + size_t len = strlen(b->name); for (; lang; lang = nextlocale(lang)) { const char *bdname = LOC(lang, b->type->_name); - size_t bdlen = strlen(bdname); - if (strlen(b->name) >= bdlen && strncmp(b->name, bdname, bdlen) == 0) { - return false; + if (bdname) { + size_t bdlen = strlen(bdname); + if (len >= bdlen && strncmp(b->name, bdname, bdlen) == 0) { + return false; + } } } return true; @@ -2926,64 +2929,6 @@ static void reorder(void) } } -#if 0 -/* Aus Gebäude weisen, VERBANNE */ -static void evict(void) -{ - region *r; - strlist *S; - unit *u; - - for (r = regions; r; r = r->next) { - for (u = r->units; u; u = u->next) { - for (S = u->orders; S; S = S->next) - if (get_keyword(ord) == K_EVICT) { - int id; - unit *u2; - /* Nur der Kapitän bzw Burgherr kann jemanden rausschmeißen */ - if (!fval(u, UFL_OWNER)) { - /* Die Einheit ist nicht der Eigentümer */ - cmistake(u, ord, 49, MSG_EVENT); - continue; - } - init_tokens(ord); - skip_token(); - id = getid(); - u2 = findunit(id); - - if (u2 == NULL) { - /* Einheit nicht gefunden */ - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, - "feedback_unit_not_found", "")); - continue; - } - - if (u->building) { - /* in der selben Burg? */ - if (u->building != u2->building) { - /* nicht in Burg */ - cmistake(u, ord, 33, MSG_EVENT); - continue; - } - leave_building(u2); - /* meldung an beide */ - } - - if (u->ship) { - if (u->ship != u2->ship) { - /* nicht an Bord */ - cmistake(u, ord, 32, MSG_EVENT); - continue; - } - leave_ship(u2); - /* meldung an beide */ - } - } - } - } -} -#endif - static int renumber_cmd(unit * u, order * ord) { const char *s; @@ -3422,8 +3367,9 @@ static void new_units(void) a_add(&u2->attribs, a_new(&at_alias))->data.i = alias; sh = leftship(u); - if (sh) + if (sh) { set_leftship(u2, sh); + } setstatus(u2, u->status); ordp = &makeord->next; @@ -4109,12 +4055,12 @@ void process(void) static void enter_1(region * r) { - do_misc(r, false); + do_misc(r, 0); } static void enter_2(region * r) { - do_misc(r, true); + do_misc(r, 1); } static void maintain_buildings_1(region * r) diff --git a/src/gamecode/laws_test.c b/src/gamecode/laws_test.c index 367a9c629..02af945dc 100644 --- a/src/gamecode/laws_test.c +++ b/src/gamecode/laws_test.c @@ -100,8 +100,8 @@ static void test_fishing_feeds_2_people(CuTest * tc) CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ f = test_create_faction(rc_find("human")); u = test_create_unit(f, r); - sh = new_ship(st_find("boat"), NULL, r); - u->ship = sh; + sh = new_ship(st_find("boat"), r, 0); + u_set_ship(u, sh); i_change(&u->items, it_find("money"), 42); scale_number(u, 1); @@ -140,8 +140,8 @@ static void test_fishing_does_not_give_goblins_money(CuTest * tc) CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ f = test_create_faction(rc_find("human")); u = test_create_unit(f, r); - sh = new_ship(st_find("boat"), NULL, r); - u->ship = sh; + sh = new_ship(st_find("boat"), r, 0); + u_set_ship(u, sh); i_change(&u->items, it_find("money"), 42); global.functions.maintenance = not_so_hungry; @@ -165,8 +165,8 @@ static void test_fishing_gets_reset(CuTest * tc) CuAssertStrEquals(tc, "ocean", r->terrain->_name); /* test_create_world needs coverage */ f = test_create_faction(rc_find("human")); u = test_create_unit(f, r); - sh = new_ship(st_find("boat"), NULL, r); - u->ship = sh; + sh = new_ship(st_find("boat"), r, 0); + u_set_ship(u, sh); i_change(&u->items, it_find("money"), 42); scale_number(u, 1); diff --git a/src/gamecode/report.c b/src/gamecode/report.c index e0ec3cd34..b1a58770c 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -576,7 +576,7 @@ int hat_in_region(item_t it, region * r, faction * f) } static void -nr_curses(FILE * F, const faction * viewer, const void *obj, typ_t typ, +nr_curses(FILE * F, const faction * viewer, const void *obj, objtype_t typ, int indent) { attrib *a = NULL; diff --git a/src/gamecode/spy.c b/src/gamecode/spy.c index 8341825a0..d8e608b59 100644 --- a/src/gamecode/spy.c +++ b/src/gamecode/spy.c @@ -443,8 +443,7 @@ static void sink_ship(region * r, ship * sh, const char *name, unit * saboteur) } else { msg = msg_message("sink_saved_msg", "region unit", safety, u); } - set_leftship(u, u->ship); - u->ship = 0; + leave_ship(u); if (r != safety) { setguard(u, GUARD_NONE); } diff --git a/src/kernel.vcxproj b/src/kernel.vcxproj index 01d47c948..97cda449a 100644 --- a/src/kernel.vcxproj +++ b/src/kernel.vcxproj @@ -119,6 +119,7 @@ + diff --git a/src/kernel.vcxproj.filters b/src/kernel.vcxproj.filters index 5d877a81e..9e2d9b3af 100644 --- a/src/kernel.vcxproj.filters +++ b/src/kernel.vcxproj.filters @@ -298,6 +298,9 @@ kernel + + kernel + diff --git a/src/kernel/build.c b/src/kernel/build.c index c7b3ef7dc..d2ca8c155 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -112,29 +112,27 @@ static int slipthru(const region * r, const unit * u, const building * b) return 1; } -boolean can_contact(const region * r, const unit * u, const unit * u2) +int can_contact(const region * r, const unit * u, const unit * u2) { /* hier geht es nur um die belagerung von burgen */ - if (u->building == u2->building) - return true; + if (u->building == u2->building) { + return 1; + } /* unit u is trying to contact u2 - unasked for contact. wenn u oder u2 * nicht in einer burg ist, oder die burg nicht belagert ist, ist * slipthru () == 1. ansonsten ist es nur 1, wenn man die belagerer */ - if (slipthru(u->region, u, u->building) - && slipthru(u->region, u2, u2->building)) - return true; + if (slipthru(u->region, u, u->building) && slipthru(u->region, u2, u2->building)) { + return 1; + } - if (alliedunit(u, u2->faction, HELP_GIVE)) - return true; - - return false; + return (alliedunit(u, u2->faction, HELP_GIVE)); } -static void contact_cmd(unit * u, order * ord, boolean tries) +static void contact_cmd(unit * u, order * ord, int final) { /* unit u kontaktiert unit u2. Dies setzt den contact einfach auf 1 - * ein richtiger toggle ist (noch?) nicht noetig. die region als @@ -150,7 +148,7 @@ static void contact_cmd(unit * u, order * ord, boolean tries) if (u2 != NULL) { if (!can_contact(r, u, u2)) { - if (tries) + if (final) cmistake(u, u->thisorder, 23, MSG_EVENT); return; } @@ -405,8 +403,7 @@ int destroy_cmd(unit * u, struct order *ord) /* all units leave the ship */ for (u2 = r->units; u2; u2 = u2->next) { if (u2->ship == sh) { - u2->ship = 0; - freset(u2, UFL_OWNER); + leave_ship(u2); } } ADDMSG(&u->faction->msgs, msg_message("shipdestroy", @@ -1092,12 +1089,11 @@ create_ship(region * r, unit * u, const struct ship_type *newtype, int want, else want = msize; - sh = new_ship(newtype, u->faction->locale, r); + sh = new_ship(newtype, r, u->faction->locale); if (leave(u, false)) { if (fval(u->race, RCF_CANSAIL)) { - u->ship = sh; - fset(u, UFL_OWNER); + u_set_ship(u, sh); } } new_order = @@ -1256,11 +1252,7 @@ static boolean enter_ship(unit * u, struct order *ord, int id, boolean report) } if (leave(u, false)) { - u->ship = sh; - - if (shipowner(sh) == NULL) { - fset(u, UFL_OWNER); - } + u_set_ship(u, sh); fset(u, UFL_ENTER); } return true; @@ -1315,7 +1307,7 @@ static boolean enter_building(unit * u, order * ord, int id, boolean report) return false; } -void do_misc(region * r, boolean lasttry) +void do_misc(region * r, int is_final_attempt) { unit **uptr, *uc; @@ -1324,7 +1316,7 @@ void do_misc(region * r, boolean lasttry) for (ord = uc->orders; ord; ord = ord->next) { keyword_t kwd = get_keyword(ord); if (kwd == K_CONTACT) { - contact_cmd(uc, ord, lasttry); + contact_cmd(uc, ord, is_final_attempt); } } } @@ -1352,7 +1344,7 @@ void do_misc(region * r, boolean lasttry) case P_GEBAEUDE: if (u->building && u->building->no == id) break; - if (enter_building(u, ord, id, lasttry)) { + if (enter_building(u, ord, id, is_final_attempt)) { unit *ub; for (ub = u; ub; ub = ub->next) { if (ub->building == u->building) { @@ -1365,7 +1357,7 @@ void do_misc(region * r, boolean lasttry) case P_SHIP: if (u->ship && u->ship->no == id) break; - if (enter_ship(u, ord, id, lasttry)) { + if (enter_ship(u, ord, id, is_final_attempt)) { unit *ub; ulast = u; for (ub = u; ub; ub = ub->next) { @@ -1377,9 +1369,9 @@ void do_misc(region * r, boolean lasttry) break; default: - if (lasttry) + if (is_final_attempt) { cmistake(u, ord, 79, MSG_MOVE); - + } } if (ulast != NULL) { /* Wenn wir hier angekommen sind, war der Befehl diff --git a/src/kernel/build.h b/src/kernel/build.h index 710f103f3..5407034bf 100644 --- a/src/kernel/build.h +++ b/src/kernel/build.h @@ -64,7 +64,7 @@ extern "C" { extern int destroy_cmd(struct unit *u, struct order *ord); extern int leave_cmd(struct unit *u, struct order *ord); - extern boolean can_contact(const struct region *r, const struct unit *u, + extern int can_contact(const struct region *r, const struct unit *u, const struct unit *u2); void do_siege(struct region *r); @@ -76,7 +76,7 @@ extern "C" { struct building *getbuilding(const struct region *r); struct ship *getship(const struct region *r); - void do_misc(struct region *r, boolean tries); + void do_misc(struct region *r, int is_final_attempt); void reportevent(struct region *r, char *s); diff --git a/src/kernel/building.c b/src/kernel/building.c index f7ac73f00..9bac38157 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -554,7 +554,7 @@ extern struct attrib_type at_icastle; /** returns the building's build stage (NOT size in people). * only makes sense for castles or similar buildings with multiple * stages */ -int buildingeffsize(const building * b, boolean img) +int buildingeffsize(const building * b, int img) { const struct building_type *btype = NULL; diff --git a/src/kernel/building.h b/src/kernel/building.h index 8055e3731..135b8a80b 100644 --- a/src/kernel/building.h +++ b/src/kernel/building.h @@ -128,7 +128,7 @@ extern "C" { /* Alte Gebäudetypen: */ /* old functions, still in build.c: */ - int buildingeffsize(const building * b, boolean img); + int buildingeffsize(const building * b, int imaginary); void bhash(struct building *b); void bunhash(struct building *b); int buildingcapacity(const struct building *b); diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 89b689e36..ce18998b6 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -754,7 +754,7 @@ const char *oldcursename(int id) } /* ------------------------------------------------------------- */ -message *cinfo_simple(const void *obj, typ_t typ, const struct curse * c, +message *cinfo_simple(const void *obj, objtype_t typ, const struct curse * c, int self) { struct message *msg; diff --git a/src/kernel/curse.h b/src/kernel/curse.h index b9af001e0..ee2f7899e 100644 --- a/src/kernel/curse.h +++ b/src/kernel/curse.h @@ -20,6 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define CURSE_H #include +#include "objtypes.h" #ifdef __cplusplus extern "C" { @@ -208,13 +209,13 @@ extern "C" { int typ; unsigned int flags; unsigned int mergeflags; - struct message *(*curseinfo) (const void *, typ_t, const struct curse *, + struct message *(*curseinfo) (const void *, objtype_t, const struct curse *, int); void (*change_vigour) (curse *, double); int (*read) (struct storage * store, curse * c, void *target); int (*write) (struct storage * store, const struct curse * c, const void *target); - int (*cansee) (const struct faction *, const void *, typ_t, + int (*cansee) (const struct faction *, const void *, objtype_t, const struct curse *, int); int (*age) (curse *); } curse_type; @@ -315,7 +316,7 @@ extern "C" { /*** COMPATIBILITY MACROS. DO NOT USE FOR NEW CODE, REPLACE IN OLD CODE: */ extern const char *oldcursename(int id); - extern struct message *cinfo_simple(const void *obj, typ_t typ, + extern struct message *cinfo_simple(const void *obj, objtype_t typ, const struct curse *c, int self); #define is_cursed(a, id, id2) \ diff --git a/src/kernel/magic.h b/src/kernel/magic.h index 621992991..931ccf8f6 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -45,7 +45,7 @@ extern "C" { * erst in verify_targets wird dann global gesucht, da in den meisten * Fällen das Zielobjekt lokal sein dürfte */ -/* siehe auch typ_t in objtypes.h */ +/* siehe auch objtype_t in objtypes.h */ typedef enum { SPP_REGION, /* "r" : findregion(x,y) -> *region */ SPP_UNIT, /* - : atoi36() -> int */ diff --git a/src/kernel/move.c b/src/kernel/move.c index a3c1fffaf..bf62587d7 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -603,10 +603,10 @@ ship *move_ship(ship * sh, region * from, region * to, region_list * route) if (route != NULL) mark_travelthru(u, from, route, NULL); if (from != to) { - u->ship = NULL; /* damit move_unit() kein leave() macht */ + u->ship = 0; /* temporary trick -- do not use u_set_ship here */ move_unit(u, to, ulist); ulist = &u->next; - u->ship = sh; + u->ship = sh; /* undo the trick -- do not use u_set_ship here */ } if (route && eff_skill(u, SK_SAILING, from) >= 1) { produceexp(u, SK_SAILING, u->number); diff --git a/src/kernel/move_test.c b/src/kernel/move_test.c index ce2a1f221..38e899aaf 100644 --- a/src/kernel/move_test.c +++ b/src/kernel/move_test.c @@ -1,3 +1,6 @@ +#include +#include + #include #include #include @@ -12,7 +15,7 @@ static void building_type_exists(CuTest * tc) region *r; building *b; building_type *btype; - building_type *btype2 = calloc(1, sizeof(building_type)); + building_type *btype2 = (building_type *)calloc(1, sizeof(building_type)); test_cleanup(); test_create_world(); diff --git a/src/kernel/objtypes.h b/src/kernel/objtypes.h index b676697f3..293158ecb 100644 --- a/src/kernel/objtypes.h +++ b/src/kernel/objtypes.h @@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif - enum { + typedef enum { TYP_UNIT, TYP_REGION, TYP_BUILDING, @@ -31,7 +31,7 @@ extern "C" { TYP_ACTION, TYP_TRIGGER, TYP_TIMEOUT - }; + } objtype_t; #ifdef __cplusplus } diff --git a/src/kernel/reports.c b/src/kernel/reports.c index aefcdae66..461833ef3 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -975,7 +975,7 @@ spunit(struct strlist **SP, const struct faction *f, const unit * u, int indent, (char)((u->faction == f) ? '*' : (dh ? '+' : '-'))); } -struct message *msg_curse(const struct curse *c, const void *obj, typ_t typ, +struct message *msg_curse(const struct curse *c, const void *obj, objtype_t typ, int self) { if (c->type->curseinfo) { diff --git a/src/kernel/reports.h b/src/kernel/reports.h index 632c3df86..b1de0f3dc 100644 --- a/src/kernel/reports.h +++ b/src/kernel/reports.h @@ -20,6 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define H_KRNL_REPORTS #include +#include "objtypes.h" #ifdef __cplusplus extern "C" { @@ -117,7 +118,7 @@ extern "C" { extern int *nmrs; extern struct message *msg_curse(const struct curse *c, const void *obj, - typ_t typ, int slef); + objtype_t typ, int slef); typedef struct arg_regions { int nregions; diff --git a/src/kernel/save.c b/src/kernel/save.c index 8f14c944c..d039e62b9 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -796,9 +796,12 @@ unit *read_unit(struct storage *store) u->building = findbuilding(n); n = store->r_id(store); - if (n > 0) - u->ship = findship(n); - + if (n > 0) { + ship * sh = findship(n); + if (sh) { + u_set_ship(u, sh); + } + } setstatus(u, store->r_int(store)); u->flags = store->r_int(store); u->flags &= UFL_SAVEMASK; diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 1721174e2..22311b919 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -174,7 +174,7 @@ unit *captain(ship * sh) /* Alte Schiffstypen: */ static ship *deleted_ships; -ship *new_ship(const ship_type * stype, const struct locale *lang, region * r) +ship *new_ship(const ship_type * stype, region * r, const struct locale *lang) { static char buffer[7 + IDSIZE + 1]; ship *sh = (ship *) calloc(1, sizeof(ship)); @@ -289,6 +289,7 @@ void getshipweight(const ship * sh, int *sweight, int *scabins) unit *shipowner(const ship * sh) { +#ifndef NDEBUG unit *u; unit *first = NULL; @@ -300,7 +301,7 @@ unit *shipowner(const ship * sh) if (!first && u->number > 0) first = u; if (fval(u, UFL_OWNER) && u->number > 0) - return u; + break; if (u->number == 0) freset(u, UFL_OWNER); } @@ -309,9 +310,13 @@ unit *shipowner(const ship * sh) /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit * nehmen. */ - if (first) - fset(first, UFL_OWNER); - return first; + if (first && !u) { + u = first; + fset(u, UFL_OWNER); + } + assert(u==sh->owner); +#endif + return sh->owner; } void write_ship_reference(const struct ship *sh, struct storage *store) diff --git a/src/kernel/ship.h b/src/kernel/ship.h index 12e501d80..4a33ac701 100644 --- a/src/kernel/ship.h +++ b/src/kernel/ship.h @@ -81,6 +81,7 @@ extern "C" { typedef struct ship { struct ship *next; struct ship *nexthash; + struct unit * owner; int no; struct region *region; char *name; @@ -100,8 +101,8 @@ extern "C" { extern int shipcapacity(const struct ship *sh); extern void getshipweight(const struct ship *sh, int *weight, int *cabins); - extern ship *new_ship(const struct ship_type *stype, - const struct locale *lang, struct region *r); + extern ship *new_ship(const struct ship_type *stype, struct region *r, + const struct locale *lang); extern const char *write_shipname(const struct ship *sh, char *buffer, size_t size); extern struct ship *findship(int n); diff --git a/src/kernel/ship_test.c b/src/kernel/ship_test.c new file mode 100644 index 000000000..eee901b05 --- /dev/null +++ b/src/kernel/ship_test.c @@ -0,0 +1,63 @@ +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static void test_register_ship(CuTest * tc) +{ + ship_type *stype; + + test_cleanup(); + + stype = (ship_type *)calloc(sizeof(ship_type), 1); + stype->name[0] = strdup("herp"); + st_register(stype); + + CuAssertPtrNotNull(tc, st_find("herp")); +} + +static void test_shipowner(CuTest * tc) +{ + struct region *r; + struct ship * sh; + struct unit * u; + struct faction * f; + const struct ship_type *stype; + const struct race *human; + + test_cleanup(); + test_create_world(); + + human = rc_find("human"); + CuAssertPtrNotNull(tc, human); + + stype = st_find("boat"); + CuAssertPtrNotNull(tc, stype); + + f = test_create_faction(human); + r = findregion(0, 0); + + sh = test_create_ship(r, stype); + CuAssertPtrNotNull(tc, sh); + + u = test_create_unit(f, r); + CuAssertPtrNotNull(tc, u); + u_set_ship(u, sh); + CuAssertPtrEquals(tc, u, shipowner(sh)); +} + +CuSuite *get_ship_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_register_ship); + SUITE_ADD_TEST(suite, test_shipowner); + return suite; +} diff --git a/src/kernel/types.h b/src/kernel/types.h index 2b2772564..ae53a79bd 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -31,7 +31,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include typedef short terrain_t; -typedef short typ_t; typedef short item_t; struct attrib; diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 7344c4589..2cc272539 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -774,12 +774,23 @@ ship *leftship(const unit * u) return NULL; } +void u_set_ship(unit * u, ship * sh) +{ + assert(!u->ship); /* you must leave_ship */ + if (sh) { + u->ship = sh; + if (!sh->owner) { + sh->owner = u; + fset(u, UFL_OWNER); + } + } +} + void leave_ship(unit * u) { struct ship *sh = u->ship; - if (sh == NULL) - return; - u->ship = NULL; + if (!sh) return; + u->ship = 0; set_leftship(u, sh); if (fval(u, UFL_OWNER)) { @@ -791,12 +802,15 @@ void leave_ship(unit * u) if (u2->faction == u->faction) { owner = u2; break; - } else if (owner == NULL) + } else if (!owner) { owner = u2; + } } } - if (owner != NULL) + if (owner) { + sh->owner = owner; fset(owner, UFL_OWNER); + } } } @@ -849,10 +863,11 @@ boolean leave(unit * u, boolean force) return false; } } - if (u->building) + if (u->building) { leave_building(u); - else if (u->ship) + } else if (u->ship) { leave_ship(u); + } return true; } @@ -1493,8 +1508,8 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace, /* erbt Gebäude/Schiff */ if (creator->region == r) { u->building = creator->building; - if (creator->ship != NULL && fval(u->race, RCF_CANSAIL)) { - u->ship = creator->ship; + if (creator->ship && fval(u->race, RCF_CANSAIL)) { + u_set_ship(u, creator->ship); } } diff --git a/src/kernel/unit.h b/src/kernel/unit.h index ab5ace449..0470ee7a7 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -182,8 +182,9 @@ extern "C" { extern boolean leave(struct unit *u, boolean force); extern boolean can_leave(struct unit *u); - extern void leave_ship(unit * u); - extern void leave_building(unit * u); + extern void u_set_ship(struct unit * u, struct ship * sh); + extern void leave_ship(struct unit * u); + extern void leave_building(struct unit * u); extern void set_leftship(struct unit *u, struct ship *sh); extern struct ship *leftship(const struct unit *); diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index c1ed36b76..8e488b115 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -534,7 +534,7 @@ static int parse_ships(xmlDocPtr doc) for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr child, node = nodes->nodeTab[i]; xmlChar *propValue; - ship_type *st = calloc(sizeof(ship_type), 1); + ship_type *st = (ship_type *)calloc(sizeof(ship_type), 1); xmlXPathObjectPtr result; int k, c; diff --git a/src/modules/xecmd.c b/src/modules/xecmd.c index 67ebeb094..e45c611cd 100644 --- a/src/modules/xecmd.c +++ b/src/modules/xecmd.c @@ -75,12 +75,11 @@ static void xe_giveballon(unit * u, struct order *ord) return; } - sh = new_ship(st_find("balloon"), u2->faction->locale, u2->region); + sh = new_ship(st_find("balloon"), u2->region, u2->faction->locale); sh->size = 5; ship_setname(sh, "Xontormia-Ballon"); - leave(u2, false); - u2->ship = sh; - fset(u2, UFL_OWNER); + leave(u2, true); + u_set_ship(u2, sh); } int xecmd(unit * u, order * ord) diff --git a/src/tests.c b/src/tests.c index 914e23512..229904c9a 100644 --- a/src/tests.c +++ b/src/tests.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ int RunAllTests(void) CuSuiteAddSuite(suite, get_curse_suite()); CuSuiteAddSuite(suite, get_market_suite()); CuSuiteAddSuite(suite, get_move_suite()); + CuSuiteAddSuite(suite, get_ship_suite()); CuSuiteAddSuite(suite, get_spell_suite()); CuSuiteAddSuite(suite, get_laws_suite()); CuSuiteAddSuite(suite, get_battle_suite()); @@ -117,6 +119,13 @@ building * test_create_building(region * r, const building_type * btype) return b; } +ship * test_create_ship(region * r, const ship_type * stype) +{ + ship * s = new_ship(stype, r, default_locale); + s->size = stype->construction?stype->construction->maxsize:1; + return s; +} + item_type * test_create_itemtype(const char ** names) { resource_type * rtype; item_type * itype; @@ -171,10 +180,12 @@ void test_create_world(void) btype = (building_type*)calloc(sizeof(building_type), 1); btype->flags = BTF_NAMECHANGE; btype->_name = strdup("castle"); + locale_setstring(default_locale, "castle", "castle"); bt_register(btype); stype = (ship_type*)calloc(sizeof(ship_type), 1); stype->name[0] = strdup("boat"); stype->name[1] = strdup("boat_p"); + locale_setstring(default_locale, "boat", "boat"); st_register(stype); } diff --git a/src/tests.h b/src/tests.h index 2a3c4f625..c35922c7c 100644 --- a/src/tests.h +++ b/src/tests.h @@ -15,7 +15,7 @@ extern "C" { struct unit *test_create_unit(struct faction *f, struct region *r); void test_create_world(void); struct building * test_create_building(struct region * r, const struct building_type * btype); - + struct ship * test_create_ship(struct region * r, const struct ship_type * stype); int RunAllTests(void); #else #define RunAllTests() 0 From 94ca9a1f98dfc1bdd58e18b59e91728110d79db2 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 17 May 2012 00:25:47 -0700 Subject: [PATCH 198/400] ship->owner not yet ready for primetime better tests written --- src/kernel/ship.c | 13 ++++-------- src/kernel/ship_test.c | 47 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 22311b919..e6a529ee3 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -289,7 +289,6 @@ void getshipweight(const ship * sh, int *sweight, int *scabins) unit *shipowner(const ship * sh) { -#ifndef NDEBUG unit *u; unit *first = NULL; @@ -301,7 +300,7 @@ unit *shipowner(const ship * sh) if (!first && u->number > 0) first = u; if (fval(u, UFL_OWNER) && u->number > 0) - break; + return u; if (u->number == 0) freset(u, UFL_OWNER); } @@ -310,13 +309,9 @@ unit *shipowner(const ship * sh) /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit * nehmen. */ - if (first && !u) { - u = first; - fset(u, UFL_OWNER); - } - assert(u==sh->owner); -#endif - return sh->owner; + if (first) + fset(first, UFL_OWNER); + return first; } void write_ship_reference(const struct ship *sh, struct storage *store) diff --git a/src/kernel/ship_test.c b/src/kernel/ship_test.c index eee901b05..33bbb3cd3 100644 --- a/src/kernel/ship_test.c +++ b/src/kernel/ship_test.c @@ -24,12 +24,46 @@ static void test_register_ship(CuTest * tc) CuAssertPtrNotNull(tc, st_find("herp")); } -static void test_shipowner(CuTest * tc) +static void test_shipowner_goes_to_next(CuTest * tc) { struct region *r; - struct ship * sh; - struct unit * u; - struct faction * f; + struct ship *sh; + struct unit *u, *u2; + struct faction *f; + const struct ship_type *stype; + const struct race *human; + + test_cleanup(); + test_create_world(); + + human = rc_find("human"); + CuAssertPtrNotNull(tc, human); + + stype = st_find("boat"); + CuAssertPtrNotNull(tc, stype); + + f = test_create_faction(human); + r = findregion(0, 0); + + sh = test_create_ship(r, stype); + CuAssertPtrNotNull(tc, sh); + + u = test_create_unit(f, r); + u2 = test_create_unit(f, r); + CuAssertPtrNotNull(tc, u); + u_set_ship(u, sh); + u_set_ship(u2, sh); + CuAssertPtrEquals(tc, u, shipowner(sh)); + u->number = 0; + CuAssertPtrEquals(tc, u2, shipowner(sh)); +} + +static void test_shipowner_resets_when_dead(CuTest * tc) +{ + struct region *r; + struct ship *sh; + struct unit *u; + struct faction *f; const struct ship_type *stype; const struct race *human; @@ -52,12 +86,15 @@ static void test_shipowner(CuTest * tc) CuAssertPtrNotNull(tc, u); u_set_ship(u, sh); CuAssertPtrEquals(tc, u, shipowner(sh)); + u->number = 0; + CuAssertPtrEquals(tc, 0, shipowner(sh)); } CuSuite *get_ship_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_register_ship); - SUITE_ADD_TEST(suite, test_shipowner); + SUITE_ADD_TEST(suite, test_shipowner_resets_when_dead); + SUITE_ADD_TEST(suite, test_shipowner_goes_to_next); return suite; } From 9cbdaea27f370b66d6a7ab8e29a44ee0c2803271 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 17 May 2012 01:14:43 -0700 Subject: [PATCH 199/400] More tests for ships. ship->owner is now in use, but there's an assert failing in shipspeed() during report writing. --- src/kernel/build.c | 2 +- src/kernel/magic.c | 2 +- src/kernel/move.c | 6 +- src/kernel/ship.c | 44 +++++---- src/kernel/ship.h | 2 +- src/kernel/ship_test.c | 196 ++++++++++++++++++++++++++++++++++++++++- src/kernel/unit.c | 2 +- 7 files changed, 226 insertions(+), 28 deletions(-) diff --git a/src/kernel/build.c b/src/kernel/build.c index d2ca8c155..7a05f2def 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -1167,7 +1167,7 @@ static boolean mayenter(region * r, unit * u, building * b) return false; } -static int mayboard(const unit * u, const ship * sh) +static int mayboard(const unit * u, ship * sh) { unit *u2 = shipowner(sh); diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 0ab945981..cc15fc53c 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -2494,7 +2494,7 @@ unit *get_clone_mage(const unit * u) return NULL; } -static boolean is_moving_ship(const region * r, const ship * sh) +static boolean is_moving_ship(const region * r, ship * sh) { const unit *u = shipowner(sh); diff --git a/src/kernel/move.c b/src/kernel/move.c index bf62587d7..99b6c27af 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -633,7 +633,7 @@ static boolean is_freezing(const unit * u) #define SA_NO_INSECT -1 #define SA_NO_COAST -2 -static int ship_allowed(const struct ship *sh, const region * r) +static int is_ship_allowed(struct ship *sh, const region * r) { int c = 0; static const building_type *bt_harbour = NULL; @@ -752,7 +752,7 @@ static void drifting_ships(region * r) region *rn; dir = (direction_t) ((d + d_offset) % MAXDIRECTIONS); rn = rconnect(r, dir); - if (rn != NULL && fval(rn->terrain, SAIL_INTO) && ship_allowed(sh, rn) > 0) { + if (rn != NULL && fval(rn->terrain, SAIL_INTO) && is_ship_allowed(sh, rn) > 0) { rnext = rn; if (!fval(rnext->terrain, SEA_REGION)) break; @@ -1820,7 +1820,7 @@ sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) } } - reason = ship_allowed(sh, next_point); + reason = is_ship_allowed(sh, next_point); if (reason<0) { /* for some reason or another, we aren't allowed in there.. */ if (check_leuchtturm(current_point, NULL) || reason == SA_NO_INSECT) { diff --git a/src/kernel/ship.c b/src/kernel/ship.c index e6a529ee3..d8aecfb23 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -287,31 +287,37 @@ void getshipweight(const ship * sh, int *sweight, int *scabins) } } -unit *shipowner(const ship * sh) +unit *shipowner(ship * sh) { - unit *u; - unit *first = NULL; + unit *owner = sh->owner; + if (owner && owner->number<=0) { + unit *u, *first = NULL; - const region *r = sh->region; - - /* Prüfen ob Eigentümer am leben. */ - for (u = r->units; u; u = u->next) { - if (u->ship == sh) { - if (!first && u->number > 0) - first = u; - if (fval(u, UFL_OWNER) && u->number > 0) - return u; - if (u->number == 0) - freset(u, UFL_OWNER); + owner->ship = 0; + freset(owner, UFL_OWNER); + /* Prüfen ob Eigentümer am leben. */ + for (u = sh->region->units; u; u = u->next) { + if (u->ship == sh) { + if (u->number > 0) { + if (u->faction==owner->faction) { + first = u; + break; + } + else if (!first) { + first = u; /* you'll do in an emergency */ + } + } + } + } + owner = first; + if (owner) { + fset(owner, UFL_OWNER); + sh->owner = owner; } } - /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit * nehmen. */ - - if (first) - fset(first, UFL_OWNER); - return first; + return owner; } void write_ship_reference(const struct ship *sh, struct storage *store) diff --git a/src/kernel/ship.h b/src/kernel/ship.h index 4a33ac701..517303d99 100644 --- a/src/kernel/ship.h +++ b/src/kernel/ship.h @@ -96,7 +96,7 @@ extern "C" { extern void damage_ship(ship * sh, double percent); extern struct unit *captain(ship * sh); - extern struct unit *shipowner(const struct ship *sh); + extern struct unit *shipowner(struct ship *sh); extern const char *shipname(const struct ship *self); extern int shipcapacity(const struct ship *sh); extern void getshipweight(const struct ship *sh, int *weight, int *cabins); diff --git a/src/kernel/ship_test.c b/src/kernel/ship_test.c index 33bbb3cd3..2fb172422 100644 --- a/src/kernel/ship_test.c +++ b/src/kernel/ship_test.c @@ -24,7 +24,7 @@ static void test_register_ship(CuTest * tc) CuAssertPtrNotNull(tc, st_find("herp")); } -static void test_shipowner_goes_to_next(CuTest * tc) +static void test_shipowner_goes_to_next_after_death(CuTest * tc) { struct region *r; struct ship *sh; @@ -58,6 +58,193 @@ static void test_shipowner_goes_to_next(CuTest * tc) CuAssertPtrEquals(tc, u2, shipowner(sh)); } +static void test_shipowner_goes_to_other_after_death(CuTest * tc) +{ + struct region *r; + struct ship *sh; + struct unit *u, *u2; + struct faction *f; + const struct ship_type *stype; + const struct race *human; + + test_cleanup(); + test_create_world(); + + human = rc_find("human"); + CuAssertPtrNotNull(tc, human); + + stype = st_find("boat"); + CuAssertPtrNotNull(tc, stype); + + f = test_create_faction(human); + r = findregion(0, 0); + + sh = test_create_ship(r, stype); + CuAssertPtrNotNull(tc, sh); + + u2 = test_create_unit(f, r); + u = test_create_unit(f, r); + CuAssertPtrNotNull(tc, u); + u_set_ship(u, sh); + u_set_ship(u2, sh); + CuAssertPtrEquals(tc, u, shipowner(sh)); + u->number = 0; + CuAssertPtrEquals(tc, u2, shipowner(sh)); +} + +static void test_shipowner_goes_to_same_faction_after_death(CuTest * tc) +{ + struct region *r; + struct ship *sh; + struct unit *u, *u2, *u3; + struct faction *f1, *f2; + const struct ship_type *stype; + const struct race *human; + + test_cleanup(); + test_create_world(); + + human = rc_find("human"); + CuAssertPtrNotNull(tc, human); + + stype = st_find("boat"); + CuAssertPtrNotNull(tc, stype); + + f1 = test_create_faction(human); + f2 = test_create_faction(human); + r = findregion(0, 0); + + sh = test_create_ship(r, stype); + CuAssertPtrNotNull(tc, sh); + + u2 = test_create_unit(f2, r); + u3 = test_create_unit(f1, r); + u = test_create_unit(f1, r); + CuAssertPtrNotNull(tc, u); + u_set_ship(u, sh); + u_set_ship(u2, sh); + u_set_ship(u3, sh); + CuAssertPtrEquals(tc, u, shipowner(sh)); + CuAssertTrue(tc, fval(u, UFL_OWNER)); + u->number = 0; + CuAssertPtrEquals(tc, u3, shipowner(sh)); + CuAssertTrue(tc, !fval(u, UFL_OWNER)); + CuAssertTrue(tc, fval(u3, UFL_OWNER)); + u3->number = 0; + CuAssertPtrEquals(tc, u2, shipowner(sh)); + CuAssertTrue(tc, !fval(u3, UFL_OWNER)); + CuAssertTrue(tc, fval(u2, UFL_OWNER)); +} + +static void test_shipowner_goes_to_next_after_leave(CuTest * tc) +{ + struct region *r; + struct ship *sh; + struct unit *u, *u2; + struct faction *f; + const struct ship_type *stype; + const struct race *human; + + test_cleanup(); + test_create_world(); + + human = rc_find("human"); + CuAssertPtrNotNull(tc, human); + + stype = st_find("boat"); + CuAssertPtrNotNull(tc, stype); + + f = test_create_faction(human); + r = findregion(0, 0); + + sh = test_create_ship(r, stype); + CuAssertPtrNotNull(tc, sh); + + u = test_create_unit(f, r); + u2 = test_create_unit(f, r); + CuAssertPtrNotNull(tc, u); + u_set_ship(u, sh); + u_set_ship(u2, sh); + CuAssertPtrEquals(tc, u, shipowner(sh)); + leave_ship(u); + CuAssertPtrEquals(tc, u2, shipowner(sh)); +} + +static void test_shipowner_goes_to_other_after_leave(CuTest * tc) +{ + struct region *r; + struct ship *sh; + struct unit *u, *u2; + struct faction *f; + const struct ship_type *stype; + const struct race *human; + + test_cleanup(); + test_create_world(); + + human = rc_find("human"); + CuAssertPtrNotNull(tc, human); + + stype = st_find("boat"); + CuAssertPtrNotNull(tc, stype); + + f = test_create_faction(human); + r = findregion(0, 0); + + sh = test_create_ship(r, stype); + CuAssertPtrNotNull(tc, sh); + + u2 = test_create_unit(f, r); + u = test_create_unit(f, r); + CuAssertPtrNotNull(tc, u); + u_set_ship(u, sh); + u_set_ship(u2, sh); + CuAssertPtrEquals(tc, u, shipowner(sh)); + leave_ship(u); + CuAssertPtrEquals(tc, u2, shipowner(sh)); +} + +static void test_shipowner_goes_to_same_faction_after_leave(CuTest * tc) +{ + struct region *r; + struct ship *sh; + struct unit *u, *u2, *u3; + struct faction *f1, *f2; + const struct ship_type *stype; + const struct race *human; + + test_cleanup(); + test_create_world(); + + human = rc_find("human"); + CuAssertPtrNotNull(tc, human); + + stype = st_find("boat"); + CuAssertPtrNotNull(tc, stype); + + f1 = test_create_faction(human); + f2 = test_create_faction(human); + r = findregion(0, 0); + + sh = test_create_ship(r, stype); + CuAssertPtrNotNull(tc, sh); + + u2 = test_create_unit(f2, r); + u3 = test_create_unit(f1, r); + u = test_create_unit(f1, r); + CuAssertPtrNotNull(tc, u); + u_set_ship(u, sh); + u_set_ship(u2, sh); + u_set_ship(u3, sh); + CuAssertPtrEquals(tc, u, shipowner(sh)); + leave_ship(u); + CuAssertPtrEquals(tc, u3, shipowner(sh)); + leave_ship(u3); + CuAssertPtrEquals(tc, u2, shipowner(sh)); + leave_ship(u2); + CuAssertPtrEquals(tc, 0, shipowner(sh)); +} + static void test_shipowner_resets_when_dead(CuTest * tc) { struct region *r; @@ -95,6 +282,11 @@ CuSuite *get_ship_suite(void) CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_register_ship); SUITE_ADD_TEST(suite, test_shipowner_resets_when_dead); - SUITE_ADD_TEST(suite, test_shipowner_goes_to_next); + SUITE_ADD_TEST(suite, test_shipowner_goes_to_next_after_death); + SUITE_ADD_TEST(suite, test_shipowner_goes_to_other_after_death); + SUITE_ADD_TEST(suite, test_shipowner_goes_to_same_faction_after_death); + SUITE_ADD_TEST(suite, test_shipowner_goes_to_next_after_leave); + SUITE_ADD_TEST(suite, test_shipowner_goes_to_other_after_leave); + SUITE_ADD_TEST(suite, test_shipowner_goes_to_same_faction_after_leave); return suite; } diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 2cc272539..58dba10df 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -807,8 +807,8 @@ void leave_ship(unit * u) } } } + sh->owner = owner; if (owner) { - sh->owner = owner; fset(owner, UFL_OWNER); } } From 43f57706947570ac1aa6669b25f29b8438e15104 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 17 May 2012 10:31:58 -0700 Subject: [PATCH 200/400] Fix ship-owners when control is given --- src/gamecode/economy.c | 3 +++ src/kernel/unit.c | 1 + 2 files changed, 4 insertions(+) diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index dd417fcf4..32c7e1182 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -638,6 +638,9 @@ static void give_control(unit * u, unit * u2) } } } + if (u->ship) { + u->ship->owner = u2; + } freset(u, UFL_OWNER); fset(u2, UFL_OWNER); } diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 58dba10df..820aef050 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -812,6 +812,7 @@ void leave_ship(unit * u) fset(owner, UFL_OWNER); } } + assert(sh->owner!=u); } void leave_building(unit * u) From 7789e0534e7c28070525fa66ff9a7d9f8e851bd3 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 17 May 2012 12:23:25 -0700 Subject: [PATCH 201/400] implement ship-ownership transfer as a function test the reorder_units function --- src/gamecode/creport.c | 4 +- src/gamecode/laws.c | 4 +- src/gamecode/randenc.c | 4 +- src/gamecode/report.c | 2 +- src/gamecode/spy.c | 2 +- src/kernel.vcxproj | 1 + src/kernel.vcxproj.filters | 3 ++ src/kernel/build.c | 2 +- src/kernel/building.c | 14 +++++ src/kernel/building.h | 1 + src/kernel/config.c | 101 ------------------------------------- src/kernel/config.h | 2 - src/kernel/magic.c | 2 +- src/kernel/move.c | 4 +- src/kernel/move_test.c | 4 +- src/kernel/reports.c | 101 +++++++++++++++++++++++++++++++++++++ src/kernel/reports.h | 1 + src/kernel/reports_test.c | 60 ++++++++++++++++++++++ src/kernel/save.c | 13 ++++- src/kernel/ship.c | 22 ++++---- src/kernel/ship.h | 6 +-- src/kernel/ship_test.c | 62 ++++++++++++++++------- src/kernel/unit.c | 17 ++++++- src/kernel/unit.h | 1 + src/modules/score.c | 2 +- src/tests.c | 4 +- 26 files changed, 284 insertions(+), 155 deletions(-) create mode 100644 src/kernel/reports_test.c diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index 9d67f2def..0f37b9685 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -187,7 +187,7 @@ cr_output_curses(FILE * F, const faction * viewer, const void *obj, objtype_t ty * bei jedem curse gesondert behandelt. */ if (typ == TYP_SHIP) { ship *sh = (ship *) obj; - unit *owner = shipowner(sh); + unit *owner = ship_owner(sh); a = sh->attribs; r = sh->region; if (owner != NULL) { @@ -1392,7 +1392,7 @@ static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr) /* ships */ for (sh = r->ships; sh; sh = sh->next) { int fno = -1; - u = shipowner(sh); + u = ship_owner(sh); if (u && !fval(u, UFL_ANON_FACTION)) { const faction *sf = visible_faction(f, u); fno = sf->no; diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index ee13b8257..8d1c4b229 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -1798,7 +1798,7 @@ static int name_cmd(unit * u, struct order *ord) break; } } - uo = shipowner(sh); + uo = ship_owner(sh); if (uo) { if (cansee(uo->faction, r, u, 0)) { ADDMSG(&uo->faction->msgs, @@ -2768,7 +2768,7 @@ static void sinkships(region * r) 0.30F); damage_ship(sh, dmg); } - if (shipowner(sh) == NULL) { + if (ship_owner(sh) == NULL) { float dmg = get_param_flt(global.parameters, "rules.ship.damage.nocrew", 0.05F); damage_ship(sh, dmg); diff --git a/src/gamecode/randenc.c b/src/gamecode/randenc.c index db5e40bac..a84f792b5 100644 --- a/src/gamecode/randenc.c +++ b/src/gamecode/randenc.c @@ -920,7 +920,7 @@ static void move_iceberg(region * r) for (sh = r->ships; sh;) { shn = sh->next; if (fval(sh, SF_SELECT)) { - u = captain(sh); + u = ship_owner(sh); if (sh->damage >= sh->size * DAMAGE_SCALE) { if (u != NULL) { ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg_des", @@ -1036,7 +1036,7 @@ static void godcurse(void) 0.10F); damage_ship(sh, dmg); if (sh->damage >= sh->size * DAMAGE_SCALE) { - unit *u = shipowner(sh); + unit *u = ship_owner(sh); if (u) ADDMSG(&u->faction->msgs, msg_message("godcurse_destroy_ship", "ship", sh)); diff --git a/src/gamecode/report.c b/src/gamecode/report.c index b1a58770c..79d2c8e54 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -590,7 +590,7 @@ nr_curses(FILE * F, const faction * viewer, const void *obj, objtype_t typ, * bei jedem curse gesondert behandelt. */ if (typ == TYP_SHIP) { ship *sh = (ship *) obj; - unit *owner = shipowner(sh); + unit *owner = ship_owner(sh); a = sh->attribs; r = sh->region; if (owner) { diff --git a/src/gamecode/spy.c b/src/gamecode/spy.c index d8e608b59..2b9c948a6 100644 --- a/src/gamecode/spy.c +++ b/src/gamecode/spy.c @@ -493,7 +493,7 @@ int sabotage_cmd(unit * u, struct order *ord) cmistake(u, u->thisorder, 144, MSG_EVENT); return 0; } - u2 = shipowner(sh); + u2 = ship_owner(sh); skdiff = eff_skill(u, SK_SPY, r) - crew_skill(r, u2->faction, sh, SK_PERCEPTION); if (try_destruction(u, u2, sh, skdiff)) { diff --git a/src/kernel.vcxproj b/src/kernel.vcxproj index 97cda449a..c998520ac 100644 --- a/src/kernel.vcxproj +++ b/src/kernel.vcxproj @@ -116,6 +116,7 @@ + diff --git a/src/kernel.vcxproj.filters b/src/kernel.vcxproj.filters index 9e2d9b3af..0239a0193 100644 --- a/src/kernel.vcxproj.filters +++ b/src/kernel.vcxproj.filters @@ -301,6 +301,9 @@ kernel + + kernel + diff --git a/src/kernel/build.c b/src/kernel/build.c index 7a05f2def..a3ab10b8c 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -1169,7 +1169,7 @@ static boolean mayenter(region * r, unit * u, building * b) static int mayboard(const unit * u, ship * sh) { - unit *u2 = shipowner(sh); + unit *u2 = ship_owner(sh); return (!u2 || ucontact(u2, u) || alliedunit(u2, u->faction, HELP_GUARD)); } diff --git a/src/kernel/building.c b/src/kernel/building.c index 9bac38157..f36636047 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -614,6 +614,20 @@ const char *buildingname(const building * b) return write_buildingname(b, ibuf, sizeof(name)); } +void building_set_owner(struct building *b, struct unit * owner) +{ + unit * u; + + assert(b && owner && owner->building==b); + + for (u = b->region->units; u; u = u->next) { + if (u->building == b) { + freset(owner, UFL_OWNER); + } + } + fset(owner, UFL_OWNER); +} + unit *building_owner(const building * b) { unit *u = NULL; diff --git a/src/kernel/building.h b/src/kernel/building.h index 135b8a80b..7fdbfaf1e 100644 --- a/src/kernel/building.h +++ b/src/kernel/building.h @@ -151,6 +151,7 @@ extern "C" { extern struct building *findbuilding(int n); extern struct unit *building_owner(const struct building *b); + extern void building_set_owner(struct building *b, struct unit * u); extern struct attrib_type at_building_action; void building_addaction(struct building *b, const char *fname, diff --git a/src/kernel/config.c b/src/kernel/config.c index 8eb1c5b27..eb4c5d18d 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -3040,107 +3040,6 @@ void add_income(unit * u, int type, int want, int qty) "unit region mode wanted amount", u, u->region, type, want, qty)); } -void reorder_units(region * r) -{ - unit **unext = &r->units; - - if (r->buildings) { - building *b = r->buildings; - while (*unext && b) { - unit **ufirst = unext; /* where the first unit in the building should go */ - unit **umove = unext; /* a unit we consider moving */ - unit *owner = NULL; - while (*umove) { - unit *u = *umove; - if (u->number && u->building == b) { - unit **uinsert = unext; - if (fval(u, UFL_OWNER)) { - uinsert = ufirst; - owner = u; - } - if (umove != uinsert) { - *umove = u->next; - u->next = *uinsert; - *uinsert = u; - } else { - /* no need to move, skip ahead */ - umove = &u->next; - } - if (unext == uinsert) { - /* we have a new well-placed unit. jump over it */ - unext = &u->next; - } - } else { - umove = &u->next; - } - } - if (!owner && ufirst != unext) { - owner = *ufirst; - fset(owner, UFL_OWNER); - } - b = b->next; - } - } - - if (r->ships) { - ship *sh = r->ships; - /* first, move all units up that are not on ships */ - unit **umove = unext; /* a unit we consider moving */ - while (*umove) { - unit *u = *umove; - if (u->number && !u->ship) { - if (umove != unext) { - *umove = u->next; - u->next = *unext; - *unext = u; - } else { - /* no need to move, skip ahead */ - umove = &u->next; - } - /* we have a new well-placed unit. jump over it */ - unext = &u->next; - } else { - umove = &u->next; - } - } - - while (*unext && sh) { - unit **ufirst = unext; /* where the first unit in the building should go */ - unit **umove = unext; /* a unit we consider moving */ - unit *owner = NULL; - while (*umove) { - unit *u = *umove; - if (u->number && u->ship == sh) { - unit **uinsert = unext; - if (fval(u, UFL_OWNER)) { - uinsert = ufirst; - owner = u; - } - if (umove != uinsert) { - *umove = u->next; - u->next = *uinsert; - *uinsert = u; - } else { - /* no need to move, skip ahead */ - umove = &u->next; - } - if (unext == uinsert) { - /* we have a new well-placed unit. jump over it */ - unext = &u->next; - } - } else { - umove = &u->next; - } - } - if (!owner && ufirst != unext) { - owner = *ufirst; - fset(owner, UFL_OWNER); - } - sh = sh->next; - } - } -} - int produceexp(struct unit *u, skill_t sk, int n) { if (global.producexpchance > 0.0F) { diff --git a/src/kernel/config.h b/src/kernel/config.h index 36731c1f5..30145886d 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -388,8 +388,6 @@ extern "C" { extern void kernel_init(void); extern void kernel_done(void); - extern void reorder_units(struct region *r); - extern const char *localenames[]; /** compatibility: **/ diff --git a/src/kernel/magic.c b/src/kernel/magic.c index cc15fc53c..4f2ab435e 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -2496,7 +2496,7 @@ unit *get_clone_mage(const unit * u) static boolean is_moving_ship(const region * r, ship * sh) { - const unit *u = shipowner(sh); + const unit *u = ship_owner(sh); if (u) switch (get_keyword(u->thisorder)) { diff --git a/src/kernel/move.c b/src/kernel/move.c index 99b6c27af..f0d484650 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -650,7 +650,7 @@ static int is_ship_allowed(struct ship *sh, const region * r) continue; if (is_freezing(u)) { - unit *captain = shipowner(sh); + unit *captain = ship_owner(sh); if (captain) { ADDMSG(&captain->faction->msgs, msg_message("detectforbidden", "unit region", u, r)); @@ -2274,7 +2274,7 @@ static void piracy_cmd(unit * u, struct order *ord) && check_takeoff(sh, r, rc) == true) { for (sh2 = rc->ships; sh2; sh2 = sh2->next) { - unit *cap = shipowner(sh2); + unit *cap = ship_owner(sh2); if (cap) { faction *f = visible_faction(cap->faction, cap); if (alliedunit(u, f, HELP_FIGHT)) diff --git a/src/kernel/move_test.c b/src/kernel/move_test.c index 38e899aaf..766366e59 100644 --- a/src/kernel/move_test.c +++ b/src/kernel/move_test.c @@ -10,7 +10,7 @@ #include #include -static void building_type_exists(CuTest * tc) +static void test_building_type_exists(CuTest * tc) { region *r; building *b; @@ -33,6 +33,6 @@ static void building_type_exists(CuTest * tc) CuSuite *get_move_suite(void) { CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, building_type_exists); + SUITE_ADD_TEST(suite, test_building_type_exists); return suite; } diff --git a/src/kernel/reports.c b/src/kernel/reports.c index 461833ef3..645ad0f56 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -1405,6 +1405,107 @@ static void prepare_lighthouse(building * b, faction * f) ql_free(rlist); } +void reorder_units(region * r) +{ + unit **unext = &r->units; + + if (r->buildings) { + building *b = r->buildings; + while (*unext && b) { + unit **ufirst = unext; /* where the first unit in the building should go */ + unit **umove = unext; /* a unit we consider moving */ + unit *owner = NULL; + while (*umove) { + unit *u = *umove; + if (u->number && u->building == b) { + unit **uinsert = unext; + if (fval(u, UFL_OWNER)) { + uinsert = ufirst; + owner = u; + } + if (umove != uinsert) { + *umove = u->next; + u->next = *uinsert; + *uinsert = u; + } else { + /* no need to move, skip ahead */ + umove = &u->next; + } + if (unext == uinsert) { + /* we have a new well-placed unit. jump over it */ + unext = &u->next; + } + } else { + umove = &u->next; + } + } + if (!owner && ufirst != unext) { + owner = *ufirst; + fset(owner, UFL_OWNER); + } + b = b->next; + } + } + + if (r->ships) { + ship *sh = r->ships; + /* first, move all units up that are not on ships */ + unit **umove = unext; /* a unit we consider moving */ + while (*umove) { + unit *u = *umove; + if (u->number && !u->ship) { + if (umove != unext) { + *umove = u->next; + u->next = *unext; + *unext = u; + } else { + /* no need to move, skip ahead */ + umove = &u->next; + } + /* we have a new well-placed unit. jump over it */ + unext = &u->next; + } else { + umove = &u->next; + } + } + + while (*unext && sh) { + unit **ufirst = unext; /* where the first unit in the building should go */ + unit **umove = unext; /* a unit we consider moving */ + unit *owner = NULL; + while (*umove) { + unit *u = *umove; + if (u->number && u->ship == sh) { + unit **uinsert = unext; + if (fval(u, UFL_OWNER)) { + uinsert = ufirst; + owner = u; + } + if (umove != uinsert) { + *umove = u->next; + u->next = *uinsert; + *uinsert = u; + } else { + /* no need to move, skip ahead */ + umove = &u->next; + } + if (unext == uinsert) { + /* we have a new well-placed unit. jump over it */ + unext = &u->next; + } + } else { + umove = &u->next; + } + } + if (!owner && ufirst != unext) { + owner = *ufirst; + fset(owner, UFL_OWNER); + } + sh = sh->next; + } + } +} + static void prepare_reports(void) { region *r; diff --git a/src/kernel/reports.h b/src/kernel/reports.h index b1de0f3dc..e2669de6f 100644 --- a/src/kernel/reports.h +++ b/src/kernel/reports.h @@ -52,6 +52,7 @@ extern "C" { extern int reports(void); extern int write_reports(struct faction *f, time_t ltime); extern int init_reports(void); + extern void reorder_units(struct region * r); extern const struct unit *ucansee(const struct faction *f, const struct unit *u, const struct unit *x); diff --git a/src/kernel/reports_test.c b/src/kernel/reports_test.c new file mode 100644 index 000000000..c35d704d2 --- /dev/null +++ b/src/kernel/reports_test.c @@ -0,0 +1,60 @@ +#include + +#include +#include +#include +#include +#include + +#include +#include + +static void test_reorder_units(CuTest * tc) +{ + region *r; + building *b; + ship * s; + unit *u0, *u1, *u2, *u3, *u4; + struct faction * f; + const building_type *btype; + const ship_type *stype; + + test_cleanup(); + test_create_world(); + + btype = bt_find("castle"); + stype = st_find("boat"); + + r = findregion(-1, 0); + b = test_create_building(r, btype); + s = test_create_ship(r, stype); + f = test_create_faction(0); + + u0 = test_create_unit(f, r); + u_set_ship(u0, s); + u1 = test_create_unit(f, r); + u_set_ship(u1, s); + ship_set_owner(s, u1); + u2 = test_create_unit(f, r); + u3 = test_create_unit(f, r); + u_set_building(u3, b); + u4 = test_create_unit(f, r); + u_set_building(u4, b); + building_set_owner(b, u4); + + reorder_units(r); + + CuAssertPtrEquals(tc, u4, r->units); + CuAssertPtrEquals(tc, u3, u4->next); + CuAssertPtrEquals(tc, u2, u3->next); + CuAssertPtrEquals(tc, u1, u2->next); + CuAssertPtrEquals(tc, u0, u1->next); + CuAssertPtrEquals(tc, 0, u0->next); +} + +CuSuite *get_reports_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_reorder_units); + return suite; +} diff --git a/src/kernel/save.c b/src/kernel/save.c index d039e62b9..066414b12 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -792,16 +792,25 @@ unit *read_unit(struct storage *store) set_number(u, number); n = store->r_id(store); - if (n > 0) - u->building = findbuilding(n); + if (n > 0) { + building * b = findbuilding(n); + if (b) { + u_set_building(u, b); + } else { + log_error("read_unit: unit in unkown building '%s'\n", itoa36(n)); + } + } n = store->r_id(store); if (n > 0) { ship * sh = findship(n); if (sh) { u_set_ship(u, sh); + } else { + log_error("read_unit: unit in unkown ship '%s'\n", itoa36(n)); } } + setstatus(u, store->r_int(store)); u->flags = store->r_int(store); u->flags &= UFL_SAVEMASK; diff --git a/src/kernel/ship.c b/src/kernel/ship.c index d8aecfb23..966074a27 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -160,17 +160,6 @@ void damage_ship(ship * sh, double percent) sh->damage = (int)damage; } -unit *captain(ship * sh) -{ - unit *u; - - for (u = sh->region->units; u; u = u->next) - if (u->ship == sh && fval(u, UFL_OWNER)) - return u; - - return NULL; -} - /* Alte Schiffstypen: */ static ship *deleted_ships; @@ -287,7 +276,16 @@ void getshipweight(const ship * sh, int *sweight, int *scabins) } } -unit *shipowner(ship * sh) +void ship_set_owner(ship * sh, unit * u) { + assert(u->ship==sh); + if (sh->owner && sh->owner!=u) { + freset(sh->owner, UFL_OWNER); + } + sh->owner = u; + fset(u, UFL_OWNER); +} + +unit *ship_owner(ship * sh) { unit *owner = sh->owner; if (owner && owner->number<=0) { diff --git a/src/kernel/ship.h b/src/kernel/ship.h index 517303d99..aedbff63c 100644 --- a/src/kernel/ship.h +++ b/src/kernel/ship.h @@ -94,9 +94,9 @@ extern "C" { direction_t coast; } ship; - extern void damage_ship(ship * sh, double percent); - extern struct unit *captain(ship * sh); - extern struct unit *shipowner(struct ship *sh); + extern void damage_ship(struct ship * sh, double percent); + extern void ship_set_owner(struct ship * sh, struct unit * u); + extern struct unit *ship_owner(struct ship *sh); extern const char *shipname(const struct ship *self); extern int shipcapacity(const struct ship *sh); extern void getshipweight(const struct ship *sh, int *weight, int *cabins); diff --git a/src/kernel/ship_test.c b/src/kernel/ship_test.c index 2fb172422..9eb6641a3 100644 --- a/src/kernel/ship_test.c +++ b/src/kernel/ship_test.c @@ -24,6 +24,33 @@ static void test_register_ship(CuTest * tc) CuAssertPtrNotNull(tc, st_find("herp")); } +static void test_ship_set_owner(CuTest * tc) +{ + struct region *r; + struct ship *sh; + struct unit *u1, *u2; + struct faction *f; + const struct ship_type *stype; + const struct race *human; + + test_cleanup(); + test_create_world(); + + human = rc_find("human"); + stype = st_find("boat"); + f = test_create_faction(human); + r = findregion(0, 0); + + sh = test_create_ship(r, stype); + u1 = test_create_unit(f, r); + u2 = test_create_unit(f, r); + u_set_ship(u1, sh); + u_set_ship(u2, sh); + CuAssertPtrEquals(tc, u1, ship_owner(sh)); + ship_set_owner(sh, u2); + CuAssertPtrEquals(tc, u2, ship_owner(sh)); +} + static void test_shipowner_goes_to_next_after_death(CuTest * tc) { struct region *r; @@ -53,9 +80,9 @@ static void test_shipowner_goes_to_next_after_death(CuTest * tc) CuAssertPtrNotNull(tc, u); u_set_ship(u, sh); u_set_ship(u2, sh); - CuAssertPtrEquals(tc, u, shipowner(sh)); + CuAssertPtrEquals(tc, u, ship_owner(sh)); u->number = 0; - CuAssertPtrEquals(tc, u2, shipowner(sh)); + CuAssertPtrEquals(tc, u2, ship_owner(sh)); } static void test_shipowner_goes_to_other_after_death(CuTest * tc) @@ -87,9 +114,9 @@ static void test_shipowner_goes_to_other_after_death(CuTest * tc) CuAssertPtrNotNull(tc, u); u_set_ship(u, sh); u_set_ship(u2, sh); - CuAssertPtrEquals(tc, u, shipowner(sh)); + CuAssertPtrEquals(tc, u, ship_owner(sh)); u->number = 0; - CuAssertPtrEquals(tc, u2, shipowner(sh)); + CuAssertPtrEquals(tc, u2, ship_owner(sh)); } static void test_shipowner_goes_to_same_faction_after_death(CuTest * tc) @@ -124,14 +151,14 @@ static void test_shipowner_goes_to_same_faction_after_death(CuTest * tc) u_set_ship(u, sh); u_set_ship(u2, sh); u_set_ship(u3, sh); - CuAssertPtrEquals(tc, u, shipowner(sh)); + CuAssertPtrEquals(tc, u, ship_owner(sh)); CuAssertTrue(tc, fval(u, UFL_OWNER)); u->number = 0; - CuAssertPtrEquals(tc, u3, shipowner(sh)); + CuAssertPtrEquals(tc, u3, ship_owner(sh)); CuAssertTrue(tc, !fval(u, UFL_OWNER)); CuAssertTrue(tc, fval(u3, UFL_OWNER)); u3->number = 0; - CuAssertPtrEquals(tc, u2, shipowner(sh)); + CuAssertPtrEquals(tc, u2, ship_owner(sh)); CuAssertTrue(tc, !fval(u3, UFL_OWNER)); CuAssertTrue(tc, fval(u2, UFL_OWNER)); } @@ -165,9 +192,9 @@ static void test_shipowner_goes_to_next_after_leave(CuTest * tc) CuAssertPtrNotNull(tc, u); u_set_ship(u, sh); u_set_ship(u2, sh); - CuAssertPtrEquals(tc, u, shipowner(sh)); + CuAssertPtrEquals(tc, u, ship_owner(sh)); leave_ship(u); - CuAssertPtrEquals(tc, u2, shipowner(sh)); + CuAssertPtrEquals(tc, u2, ship_owner(sh)); } static void test_shipowner_goes_to_other_after_leave(CuTest * tc) @@ -199,9 +226,9 @@ static void test_shipowner_goes_to_other_after_leave(CuTest * tc) CuAssertPtrNotNull(tc, u); u_set_ship(u, sh); u_set_ship(u2, sh); - CuAssertPtrEquals(tc, u, shipowner(sh)); + CuAssertPtrEquals(tc, u, ship_owner(sh)); leave_ship(u); - CuAssertPtrEquals(tc, u2, shipowner(sh)); + CuAssertPtrEquals(tc, u2, ship_owner(sh)); } static void test_shipowner_goes_to_same_faction_after_leave(CuTest * tc) @@ -236,13 +263,13 @@ static void test_shipowner_goes_to_same_faction_after_leave(CuTest * tc) u_set_ship(u, sh); u_set_ship(u2, sh); u_set_ship(u3, sh); - CuAssertPtrEquals(tc, u, shipowner(sh)); + CuAssertPtrEquals(tc, u, ship_owner(sh)); leave_ship(u); - CuAssertPtrEquals(tc, u3, shipowner(sh)); + CuAssertPtrEquals(tc, u3, ship_owner(sh)); leave_ship(u3); - CuAssertPtrEquals(tc, u2, shipowner(sh)); + CuAssertPtrEquals(tc, u2, ship_owner(sh)); leave_ship(u2); - CuAssertPtrEquals(tc, 0, shipowner(sh)); + CuAssertPtrEquals(tc, 0, ship_owner(sh)); } static void test_shipowner_resets_when_dead(CuTest * tc) @@ -272,15 +299,16 @@ static void test_shipowner_resets_when_dead(CuTest * tc) u = test_create_unit(f, r); CuAssertPtrNotNull(tc, u); u_set_ship(u, sh); - CuAssertPtrEquals(tc, u, shipowner(sh)); + CuAssertPtrEquals(tc, u, ship_owner(sh)); u->number = 0; - CuAssertPtrEquals(tc, 0, shipowner(sh)); + CuAssertPtrEquals(tc, 0, ship_owner(sh)); } CuSuite *get_ship_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_register_ship); + SUITE_ADD_TEST(suite, test_ship_set_owner); SUITE_ADD_TEST(suite, test_shipowner_resets_when_dead); SUITE_ADD_TEST(suite, test_shipowner_goes_to_next_after_death); SUITE_ADD_TEST(suite, test_shipowner_goes_to_other_after_death); diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 820aef050..07f80c410 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -774,6 +774,12 @@ ship *leftship(const unit * u) return NULL; } +void u_set_building(unit * u, building * b) +{ + assert(b && !u->building); /* you must leave first */ + u->building = b; +} + void u_set_ship(unit * u, ship * sh) { assert(!u->ship); /* you must leave_ship */ @@ -1446,8 +1452,15 @@ void name_unit(unit * u) } } else { char name[32]; - snprintf(name, sizeof(name), "%s %s", LOC(u->faction->locale, - "unitdefault"), itoa36(u->no)); + static const char * prefix[MAXLOCALES]; + int i = locale_index(u->faction->locale); + if (!prefix[i]) { + prefix[i] = LOC(u->faction->locale, "unitdefault"); + if (!prefix[i]) { + prefix[i] = parameters[P_UNIT]; + } + } + snprintf(name, sizeof(name), "%s %s", prefix[i], itoa36(u->no)); unit_setname(u, name); } } diff --git a/src/kernel/unit.h b/src/kernel/unit.h index 0470ee7a7..ee473230c 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -182,6 +182,7 @@ extern "C" { extern boolean leave(struct unit *u, boolean force); extern boolean can_leave(struct unit *u); + extern void u_set_building(struct unit * u, struct building * b); extern void u_set_ship(struct unit * u, struct ship * sh); extern void leave_ship(struct unit * u); extern void leave_building(struct unit * u); diff --git a/src/modules/score.c b/src/modules/score.c index c65dac5d9..c02d167c4 100644 --- a/src/modules/score.c +++ b/src/modules/score.c @@ -94,7 +94,7 @@ void score(void) } for (s = r->ships; s; s = s->next) { - unit *cap = shipowner(s); + unit *cap = ship_owner(s); if (cap && cap->faction) { cap->faction->score += s->size * 2; } diff --git a/src/tests.c b/src/tests.c index 229904c9a..e55f31825 100644 --- a/src/tests.c +++ b/src/tests.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,7 @@ int RunAllTests(void) CuSuiteAddSuite(suite, get_curse_suite()); CuSuiteAddSuite(suite, get_market_suite()); CuSuiteAddSuite(suite, get_move_suite()); + CuSuiteAddSuite(suite, get_reports_suite()); CuSuiteAddSuite(suite, get_ship_suite()); CuSuiteAddSuite(suite, get_spell_suite()); CuSuiteAddSuite(suite, get_laws_suite()); @@ -80,7 +82,7 @@ struct region *test_create_region(int x, int y, const terrain_type *terrain) struct faction *test_create_faction(const struct race *rc) { - faction *f = addfaction("nobody@eressea.de", NULL, rc, default_locale, 0); + faction *f = addfaction("nobody@eressea.de", NULL, rc?rc:rc_find("human"), default_locale, 0); return f; } From ff33af3c6577775a1e0369bc8e543041da4b30cf Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 17 May 2012 15:23:15 -0700 Subject: [PATCH 202/400] ship and building owners encapsulated in accessors tests added --- src/bindings/bind_unit.c | 24 +-- src/gamecode/economy.c | 4 +- src/gamecode/laws_test.c | 5 +- src/gamecode/market_test.c | 3 +- src/gamecode/randenc.c | 3 +- src/kernel.vcxproj | 1 + src/kernel.vcxproj.filters | 3 + src/kernel/battle_test.c | 9 +- src/kernel/build.c | 24 +-- src/kernel/building.c | 58 +++---- src/kernel/building.h | 1 + src/kernel/building_test.c | 324 +++++++++++++++++++++++++++++++++++++ src/kernel/ship.c | 26 +-- src/kernel/ship.h | 4 +- src/kernel/ship_test.c | 5 +- src/kernel/unit.c | 43 ++--- src/tests.c | 2 + 17 files changed, 425 insertions(+), 114 deletions(-) create mode 100644 src/kernel/building_test.c diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 139740237..3b0198d2c 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -614,20 +614,20 @@ static int tolua_unit_get_building(lua_State * L) return 1; } -static void unit_setbuilding(unit * u, building * b) -{ - leave(u, true); - if (b && u->region != b->region) { - move_unit(u, b->region, NULL); - } - u->building = b; -} - static int tolua_unit_set_building(lua_State * L) { - unit *self = (unit *) tolua_tousertype(L, 1, 0); - if (self->faction) { - unit_setbuilding(self, (building *) tolua_tousertype(L, 2, 0)); + unit *u = (unit *) tolua_tousertype(L, 1, 0); + if (u->faction) { + building * b = (building *) tolua_tousertype(L, 2, 0); + if (b!=u->building) { + leave(u, true); + if (b) { + if (u->region != b->region) { + move_unit(u, b->region, NULL); + } + u_set_building(u, b); + } + } } return 0; } diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index 32c7e1182..6b99573a8 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -639,10 +639,8 @@ static void give_control(unit * u, unit * u2) } } if (u->ship) { - u->ship->owner = u2; + ship_set_owner(u->ship, u2); } - freset(u, UFL_OWNER); - fset(u2, UFL_OWNER); } int give_control_cmd(unit * u, order * ord) diff --git a/src/gamecode/laws_test.c b/src/gamecode/laws_test.c index 02af945dc..e8fbd1895 100644 --- a/src/gamecode/laws_test.c +++ b/src/gamecode/laws_test.c @@ -53,7 +53,7 @@ static void test_rename_building(CuTest * tc) b = new_building(btype, r, default_locale); f = test_create_faction(rc_find("human")); u = test_create_unit(f, r); - u->building = b; + u_set_building(u, b); fset(u, UFL_OWNER); rename_building(u, NULL, b, "Villa Nagel"); @@ -77,8 +77,7 @@ static void test_rename_building_twice(CuTest * tc) b = new_building(btype, r, default_locale); f = test_create_faction(rc_find("human")); u = test_create_unit(f, r); - u->building = b; - fset(u, UFL_OWNER); + u_set_building(u, b); rename_building(u, NULL, b, "Villa Nagel"); CuAssertStrEquals(tc, "Villa Nagel", b->name); diff --git a/src/gamecode/market_test.c b/src/gamecode/market_test.c index d60c71982..c60876995 100644 --- a/src/gamecode/market_test.c +++ b/src/gamecode/market_test.c @@ -61,8 +61,7 @@ static void market_curse(CuTest * tc) f = addfaction("nobody@eressea.de", NULL, rc, default_locale, 0); u = create_unit(r, f, 1, f->race, 0, 0, 0); - u->building = b; - u->flags |= UFL_OWNER; + u_set_building(u, b); do_markets(); diff --git a/src/gamecode/randenc.c b/src/gamecode/randenc.c index a84f792b5..b0f422f0b 100644 --- a/src/gamecode/randenc.c +++ b/src/gamecode/randenc.c @@ -911,8 +911,9 @@ static void move_iceberg(region * r) while (rc->units) { building *b = rc->units->building; u = rc->units; + u->building = 0; /* prevent leaving in move_unit */ move_unit(rc->units, r, NULL); - u->building = b; /* move_unit macht ein leave() */ + u_set_building(u, b); /* undo leave-prevention */ } /* Beschädigte Schiffe können sinken */ diff --git a/src/kernel.vcxproj b/src/kernel.vcxproj index c998520ac..240cc1a6d 100644 --- a/src/kernel.vcxproj +++ b/src/kernel.vcxproj @@ -94,6 +94,7 @@ + diff --git a/src/kernel.vcxproj.filters b/src/kernel.vcxproj.filters index 0239a0193..8c6cdcdf1 100644 --- a/src/kernel.vcxproj.filters +++ b/src/kernel.vcxproj.filters @@ -304,6 +304,9 @@ kernel + + kernel + diff --git a/src/kernel/battle_test.c b/src/kernel/battle_test.c index ceac668c7..c86a7f0b8 100644 --- a/src/kernel/battle_test.c +++ b/src/kernel/battle_test.c @@ -77,7 +77,7 @@ static void test_defenders_get_building_bonus(CuTest * tc) du = test_create_unit(test_create_faction(rc_find("human")), r); au = test_create_unit(test_create_faction(rc_find("human")), r); - du->building = bld; + u_set_building(du, bld); b = make_battle(r); ds = make_side(b, du->faction, 0, 0, 0); @@ -119,8 +119,7 @@ static void test_attackers_get_no_building_bonus(CuTest * tc) bld->size = 10; au = test_create_unit(test_create_faction(rc_find("human")), r); - au->building = bld; - + u_set_building(au, bld); b = make_battle(r); as = make_side(b, au->faction, 0, 0, 0); @@ -151,9 +150,9 @@ static void test_building_bonus_respects_size(CuTest * tc) f = test_create_faction(rc_find("human")); au = test_create_unit(f, r); scale_number(au, 9); - au->building = bld; + u_set_building(au, bld); du = test_create_unit(f, r); - du->building = bld; + u_set_building(du, bld); scale_number(du, 2); b = make_battle(r); diff --git a/src/kernel/build.c b/src/kernel/build.c index a3ab10b8c..fcda6483f 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -360,14 +360,13 @@ int destroy_cmd(unit * u, struct order *ord) return 0; } - if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 138, MSG_PRODUCE); - return 0; - } - if (u->building) { building *b = u->building; + if (u!=building_owner(b)) { + cmistake(u, ord, 138, MSG_PRODUCE); + return 0; + } if (fval(b->type, BTF_INDESTRUCTIBLE)) { cmistake(u, ord, 138, MSG_PRODUCE); return 0; @@ -377,8 +376,8 @@ int destroy_cmd(unit * u, struct order *ord) /* all units leave the building */ for (u2 = r->units; u2; u2 = u2->next) { if (u2->building == b) { - u2->building = 0; freset(u2, UFL_OWNER); + leave_building(u2); } } ADDMSG(&u->faction->msgs, msg_message("destroy", "building unit", b, u)); @@ -393,6 +392,10 @@ int destroy_cmd(unit * u, struct order *ord) } else if (u->ship) { sh = u->ship; + if (u!=ship_owner(sh)) { + cmistake(u, ord, 138, MSG_PRODUCE); + return 0; + } if (fval(r->terrain, SEA_REGION)) { cmistake(u, ord, 14, MSG_EVENT); return 0; @@ -970,8 +973,8 @@ build_building(unit * u, const building_type * btype, int want, order * ord) /* Die Einheit befindet sich automatisch im Inneren der neuen Burg. */ if (leave(u, false)) { - u->building = b; - fset(u, UFL_OWNER); + u_set_building(u, b); + assert(building_owner(b)==u); } #ifdef WDW_PYRAMID if (b->type == bt_find("pyramid") && f_get_alliance(u->faction) != NULL) { @@ -1297,11 +1300,8 @@ static boolean enter_building(unit * u, order * ord, int id, boolean report) } if (leave(u, false)) { - if (building_owner(b) == 0) { - fset(u, UFL_OWNER); - } fset(u, UFL_ENTER); - u->building = b; + u_set_building(u, b); return true; } return false; diff --git a/src/kernel/building.c b/src/kernel/building.c index f36636047..1295d47b1 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -145,8 +145,9 @@ building_type *bt_find(const char *name) void bt_register(building_type * type) { - if (type->init) + if (type->init) { type->init(type); + } ql_push(&buildingtypes, (void *)type); } @@ -616,43 +617,44 @@ const char *buildingname(const building * b) void building_set_owner(struct building *b, struct unit * owner) { - unit * u; - assert(b && owner && owner->building==b); - - for (u = b->region->units; u; u = u->next) { - if (u->building == b) { - freset(owner, UFL_OWNER); - } + if (b->_owner && b->_owner!=owner) { + freset(b->_owner, UFL_OWNER); } + b->_owner = owner; fset(owner, UFL_OWNER); } -unit *building_owner(const building * b) +unit *building_owner(const building * bld) { - unit *u = NULL; - unit *first = NULL; - region *r = b->region; - /* Prüfen ob Eigentümer am leben. */ + unit *owner = bld->_owner; + if (owner && (owner->building!=bld || owner->number<=0)) { + unit *u, *heir = 0; - for (u = r->units; u; u = u->next) { - if (u->building == b) { - if (!first && u->number > 0) - first = u; - if (fval(u, UFL_OWNER) && u->number > 0) - return u; - if (u->number == 0) + /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit + * nehmen. */ + for (u = bld->region->units; u; u = u->next) { + if (u->building == bld) { + if (u->number > 0) { + if (u->faction==owner->faction) { + heir = u; + break; + } + else if (!heir) { + heir = u; /* you'll do in an emergency */ + } + } freset(u, UFL_OWNER); + } + } + freset(owner, UFL_OWNER); + owner->building = 0; + owner = heir; + if (owner) { + fset(owner, UFL_OWNER); } } - - /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit - * nehmen. */ - - if (first) { - fset(first, UFL_OWNER); - } - return first; + return owner; } const char *building_getname(const building * self) diff --git a/src/kernel/building.h b/src/kernel/building.h index 7fdbfaf1e..bacf91d93 100644 --- a/src/kernel/building.h +++ b/src/kernel/building.h @@ -104,6 +104,7 @@ extern "C" { const struct building_type *type; struct region *region; + struct unit *_owner; /* you should always use building_owner(), never this naked pointer */ char *name; char *display; struct attrib *attribs; diff --git a/src/kernel/building_test.c b/src/kernel/building_test.c new file mode 100644 index 000000000..0e09aa1c8 --- /dev/null +++ b/src/kernel/building_test.c @@ -0,0 +1,324 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static void test_register_building(CuTest * tc) +{ + building_type *btype; + + test_cleanup(); + + btype = (building_type *)calloc(sizeof(building_type), 1); + btype->_name = strdup("herp"); + bt_register(btype); + + CuAssertPtrNotNull(tc, bt_find("herp")); +} + +static void test_building_set_owner(CuTest * tc) +{ + struct region *r; + struct building *bld; + struct unit *u1, *u2; + struct faction *f; + const struct building_type *btype; + const struct race *human; + + test_cleanup(); + test_create_world(); + + human = rc_find("human"); + btype = bt_find("castle"); + f = test_create_faction(human); + r = findregion(0, 0); + + bld = test_create_building(r, btype); + u1 = test_create_unit(f, r); + u_set_building(u1, bld); + CuAssertPtrEquals(tc, u1, building_owner(bld)); + + u2 = test_create_unit(f, r); + u_set_building(u2, bld); + CuAssertPtrEquals(tc, u1, building_owner(bld)); + building_set_owner(bld, u2); + CuAssertPtrEquals(tc, u2, building_owner(bld)); +} + +static void test_buildingowner_goes_to_next_after_death(CuTest * tc) +{ + struct region *r; + struct building *bld; + struct unit *u, *u2; + struct faction *f; + const struct building_type *btype; + const struct race *human; + + test_cleanup(); + test_create_world(); + + human = rc_find("human"); + CuAssertPtrNotNull(tc, human); + + btype = bt_find("castle"); + CuAssertPtrNotNull(tc, btype); + + f = test_create_faction(human); + r = findregion(0, 0); + + bld = test_create_building(r, btype); + CuAssertPtrNotNull(tc, bld); + + u = test_create_unit(f, r); + u2 = test_create_unit(f, r); + CuAssertPtrNotNull(tc, u); + u_set_building(u, bld); + u_set_building(u2, bld); + CuAssertPtrEquals(tc, u, building_owner(bld)); + u->number = 0; + CuAssertPtrEquals(tc, u2, building_owner(bld)); +} + +static void test_buildingowner_goes_to_other_after_death(CuTest * tc) +{ + struct region *r; + struct building *bld; + struct unit *u, *u2; + struct faction *f; + const struct building_type *btype; + const struct race *human; + + test_cleanup(); + test_create_world(); + + human = rc_find("human"); + CuAssertPtrNotNull(tc, human); + + btype = bt_find("castle"); + CuAssertPtrNotNull(tc, btype); + + f = test_create_faction(human); + r = findregion(0, 0); + + bld = test_create_building(r, btype); + CuAssertPtrNotNull(tc, bld); + + u2 = test_create_unit(f, r); + u = test_create_unit(f, r); + CuAssertPtrNotNull(tc, u); + u_set_building(u, bld); + CuAssertPtrEquals(tc, u, building_owner(bld)); + u_set_building(u2, bld); + CuAssertPtrEquals(tc, u, building_owner(bld)); + u->number = 0; + CuAssertPtrEquals(tc, u2, building_owner(bld)); +} + +static void test_buildingowner_goes_to_same_faction_after_death(CuTest * tc) +{ + struct region *r; + struct building *bld; + struct unit *u, *u2, *u3; + struct faction *f1, *f2; + const struct building_type *btype; + const struct race *human; + + test_cleanup(); + test_create_world(); + + human = rc_find("human"); + CuAssertPtrNotNull(tc, human); + + btype = bt_find("castle"); + CuAssertPtrNotNull(tc, btype); + + f1 = test_create_faction(human); + f2 = test_create_faction(human); + r = findregion(0, 0); + + bld = test_create_building(r, btype); + CuAssertPtrNotNull(tc, bld); + + u2 = test_create_unit(f2, r); + u3 = test_create_unit(f1, r); + u = test_create_unit(f1, r); + CuAssertPtrNotNull(tc, u); + u_set_building(u, bld); + u_set_building(u2, bld); + u_set_building(u3, bld); + CuAssertPtrEquals(tc, u, building_owner(bld)); + CuAssertTrue(tc, fval(u, UFL_OWNER)); + u->number = 0; + CuAssertPtrEquals(tc, u3, building_owner(bld)); + CuAssertTrue(tc, !fval(u, UFL_OWNER)); + CuAssertTrue(tc, fval(u3, UFL_OWNER)); + u3->number = 0; + CuAssertPtrEquals(tc, u2, building_owner(bld)); + CuAssertTrue(tc, !fval(u3, UFL_OWNER)); + CuAssertTrue(tc, fval(u2, UFL_OWNER)); +} + +static void test_buildingowner_goes_to_next_after_leave(CuTest * tc) +{ + struct region *r; + struct building *bld; + struct unit *u, *u2; + struct faction *f; + const struct building_type *btype; + const struct race *human; + + test_cleanup(); + test_create_world(); + + human = rc_find("human"); + CuAssertPtrNotNull(tc, human); + + btype = bt_find("castle"); + CuAssertPtrNotNull(tc, btype); + + f = test_create_faction(human); + r = findregion(0, 0); + + bld = test_create_building(r, btype); + CuAssertPtrNotNull(tc, bld); + + u = test_create_unit(f, r); + u2 = test_create_unit(f, r); + CuAssertPtrNotNull(tc, u); + u_set_building(u, bld); + u_set_building(u2, bld); + CuAssertPtrEquals(tc, u, building_owner(bld)); + leave_building(u); + CuAssertPtrEquals(tc, u2, building_owner(bld)); +} + +static void test_buildingowner_goes_to_other_after_leave(CuTest * tc) +{ + struct region *r; + struct building *bld; + struct unit *u, *u2; + struct faction *f; + const struct building_type *btype; + const struct race *human; + + test_cleanup(); + test_create_world(); + + human = rc_find("human"); + CuAssertPtrNotNull(tc, human); + + btype = bt_find("castle"); + CuAssertPtrNotNull(tc, btype); + + f = test_create_faction(human); + r = findregion(0, 0); + + bld = test_create_building(r, btype); + CuAssertPtrNotNull(tc, bld); + + u2 = test_create_unit(f, r); + u = test_create_unit(f, r); + CuAssertPtrNotNull(tc, u); + u_set_building(u, bld); + u_set_building(u2, bld); + CuAssertPtrEquals(tc, u, building_owner(bld)); + leave_building(u); + CuAssertPtrEquals(tc, u2, building_owner(bld)); +} + +static void test_buildingowner_goes_to_same_faction_after_leave(CuTest * tc) +{ + struct region *r; + struct building *bld; + struct unit *u, *u2, *u3; + struct faction *f1, *f2; + const struct building_type *btype; + const struct race *human; + + test_cleanup(); + test_create_world(); + + human = rc_find("human"); + CuAssertPtrNotNull(tc, human); + + btype = bt_find("castle"); + CuAssertPtrNotNull(tc, btype); + + f1 = test_create_faction(human); + f2 = test_create_faction(human); + r = findregion(0, 0); + + bld = test_create_building(r, btype); + CuAssertPtrNotNull(tc, bld); + + u2 = test_create_unit(f2, r); + u3 = test_create_unit(f1, r); + u = test_create_unit(f1, r); + CuAssertPtrNotNull(tc, u); + u_set_building(u, bld); + u_set_building(u2, bld); + u_set_building(u3, bld); + CuAssertPtrEquals(tc, u, building_owner(bld)); + leave_building(u); + CuAssertPtrEquals(tc, u3, building_owner(bld)); + leave_building(u3); + CuAssertPtrEquals(tc, u2, building_owner(bld)); + leave_building(u2); + CuAssertPtrEquals(tc, 0, building_owner(bld)); +} + +static void test_buildingowner_resets_when_dead(CuTest * tc) +{ + struct region *r; + struct building *bld; + struct unit *u; + struct faction *f; + const struct building_type *btype; + const struct race *human; + + test_cleanup(); + test_create_world(); + + human = rc_find("human"); + CuAssertPtrNotNull(tc, human); + + btype = bt_find("castle"); + CuAssertPtrNotNull(tc, btype); + + f = test_create_faction(human); + r = findregion(0, 0); + + bld = test_create_building(r, btype); + CuAssertPtrNotNull(tc, bld); + + u = test_create_unit(f, r); + CuAssertPtrNotNull(tc, u); + u_set_building(u, bld); + CuAssertPtrEquals(tc, u, building_owner(bld)); + u->number = 0; + CuAssertPtrEquals(tc, 0, building_owner(bld)); +} + +CuSuite *get_building_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_register_building); + SUITE_ADD_TEST(suite, test_building_set_owner); + SUITE_ADD_TEST(suite, test_buildingowner_resets_when_dead); + SUITE_ADD_TEST(suite, test_buildingowner_goes_to_next_after_death); + SUITE_ADD_TEST(suite, test_buildingowner_goes_to_other_after_death); + SUITE_ADD_TEST(suite, test_buildingowner_goes_to_same_faction_after_death); + SUITE_ADD_TEST(suite, test_buildingowner_goes_to_next_after_leave); + SUITE_ADD_TEST(suite, test_buildingowner_goes_to_other_after_leave); + SUITE_ADD_TEST(suite, test_buildingowner_goes_to_same_faction_after_leave); + return suite; +} diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 966074a27..2d15bb52c 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -278,39 +278,39 @@ void getshipweight(const ship * sh, int *sweight, int *scabins) void ship_set_owner(ship * sh, unit * u) { assert(u->ship==sh); - if (sh->owner && sh->owner!=u) { - freset(sh->owner, UFL_OWNER); + if (sh->_owner && sh->_owner!=u) { + freset(sh->_owner, UFL_OWNER); } - sh->owner = u; + sh->_owner = u; fset(u, UFL_OWNER); } -unit *ship_owner(ship * sh) +unit *ship_owner(const ship * sh) { - unit *owner = sh->owner; - if (owner && owner->number<=0) { - unit *u, *first = NULL; + unit *owner = sh->_owner; + if (owner && (owner->ship!=sh || owner->number<=0)) { + unit *u, *heir = 0; owner->ship = 0; - freset(owner, UFL_OWNER); /* Prüfen ob Eigentümer am leben. */ for (u = sh->region->units; u; u = u->next) { if (u->ship == sh) { if (u->number > 0) { if (u->faction==owner->faction) { - first = u; + heir = u; break; } - else if (!first) { - first = u; /* you'll do in an emergency */ + else if (!heir) { + heir = u; /* you'll do in an emergency */ } } + freset(u, UFL_OWNER); } } - owner = first; + freset(owner, UFL_OWNER); + owner = heir; if (owner) { fset(owner, UFL_OWNER); - sh->owner = owner; } } /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit diff --git a/src/kernel/ship.h b/src/kernel/ship.h index aedbff63c..b4e95a302 100644 --- a/src/kernel/ship.h +++ b/src/kernel/ship.h @@ -81,7 +81,7 @@ extern "C" { typedef struct ship { struct ship *next; struct ship *nexthash; - struct unit * owner; + struct unit * _owner; /* never use directly, always use ship_owner() */ int no; struct region *region; char *name; @@ -96,7 +96,7 @@ extern "C" { extern void damage_ship(struct ship * sh, double percent); extern void ship_set_owner(struct ship * sh, struct unit * u); - extern struct unit *ship_owner(struct ship *sh); + extern struct unit *ship_owner(const struct ship *sh); extern const char *shipname(const struct ship *self); extern int shipcapacity(const struct ship *sh); extern void getshipweight(const struct ship *sh, int *weight, int *cabins); diff --git a/src/kernel/ship_test.c b/src/kernel/ship_test.c index 9eb6641a3..8e69a6bd4 100644 --- a/src/kernel/ship_test.c +++ b/src/kernel/ship_test.c @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -43,8 +44,10 @@ static void test_ship_set_owner(CuTest * tc) sh = test_create_ship(r, stype); u1 = test_create_unit(f, r); - u2 = test_create_unit(f, r); u_set_ship(u1, sh); + CuAssertPtrEquals(tc, u1, ship_owner(sh)); + + u2 = test_create_unit(f, r); u_set_ship(u2, sh); CuAssertPtrEquals(tc, u1, ship_owner(sh)); ship_set_owner(sh, u2); diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 07f80c410..3b1fdcf3b 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -778,17 +778,17 @@ void u_set_building(unit * u, building * b) { assert(b && !u->building); /* you must leave first */ u->building = b; + if (b && !b->_owner) { + building_set_owner(b, u); + } } void u_set_ship(unit * u, ship * sh) { assert(!u->ship); /* you must leave_ship */ - if (sh) { - u->ship = sh; - if (!sh->owner) { - sh->owner = u; - fset(u, UFL_OWNER); - } + u->ship = sh; + if (sh && !sh->_owner) { + ship_set_owner(sh, u); } } @@ -798,37 +798,14 @@ void leave_ship(unit * u) if (!sh) return; u->ship = 0; set_leftship(u, sh); - - if (fval(u, UFL_OWNER)) { - unit *u2, *owner = NULL; - freset(u, UFL_OWNER); - - for (u2 = u->region->units; u2; u2 = u2->next) { - if (u2->ship == sh) { - if (u2->faction == u->faction) { - owner = u2; - break; - } else if (!owner) { - owner = u2; - } - } - } - sh->owner = owner; - if (owner) { - fset(owner, UFL_OWNER); - } - } - assert(sh->owner!=u); } void leave_building(unit * u) { struct building *b = u->building; - if (!b) - return; - u->building = NULL; - if (fval(u, UFL_OWNER)) { + u->building = NULL; + if (b && fval(u, UFL_OWNER)) { unit *u2, *owner = NULL; freset(u, UFL_OWNER); @@ -1521,7 +1498,9 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace, /* erbt Gebäude/Schiff */ if (creator->region == r) { - u->building = creator->building; + if (creator->building) { + u_set_building(u, creator->building); + } if (creator->ship && fval(u->race, RCF_CANSAIL)) { u_set_ship(u, creator->ship); } diff --git a/src/tests.c b/src/tests.c index e55f31825..5219f9983 100644 --- a/src/tests.c +++ b/src/tests.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,7 @@ int RunAllTests(void) CuSuiteAddSuite(suite, get_move_suite()); CuSuiteAddSuite(suite, get_reports_suite()); CuSuiteAddSuite(suite, get_ship_suite()); + CuSuiteAddSuite(suite, get_building_suite()); CuSuiteAddSuite(suite, get_spell_suite()); CuSuiteAddSuite(suite, get_laws_suite()); CuSuiteAddSuite(suite, get_battle_suite()); From 95d120359407ea4adc6865f9b41f4fc3e6d955b5 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 17 May 2012 15:33:42 -0700 Subject: [PATCH 203/400] repair feedback for not woning anything when trying to destroy. --- src/kernel/build.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/kernel/build.c b/src/kernel/build.c index fcda6483f..4804c7d1c 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -420,7 +420,8 @@ int destroy_cmd(unit * u, struct order *ord) "unit region ship", u, r, sh)); } } else { - log_error("Die Einheit %s von %s war owner eines objects, war aber weder in einer Burg noch in einem Schiff.\n", unitname(u), u->faction->name, u->faction->email); + cmistake(u, ord, 138, MSG_PRODUCE); + return 0; } if (con) { From 775e8edae1bf41cd6c78c6edf055cc1aacd618c4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 17 May 2012 16:40:50 -0700 Subject: [PATCH 204/400] as much as possible, replace the UFL_OWNER flag with checking the owner the canonical way. --- src/bindings/bind_building.c | 8 +----- src/gamecode/creport.c | 26 +++++++++--------- src/gamecode/economy.c | 51 ------------------------------------ src/gamecode/laws.c | 48 ++++++++++++++------------------- src/gamecode/laws_test.c | 1 - src/gamecode/report.c | 8 +++--- src/kernel/build.c | 1 - src/kernel/config.h | 7 ----- src/kernel/move.c | 4 +-- src/kernel/unit.c | 27 ++++++------------- 10 files changed, 49 insertions(+), 132 deletions(-) diff --git a/src/bindings/bind_building.c b/src/bindings/bind_building.c index 1a220b4e5..97432bfca 100644 --- a/src/bindings/bind_building.c +++ b/src/bindings/bind_building.c @@ -170,13 +170,7 @@ static int tolua_building_set_owner(lua_State * L) { building *b = (building *) tolua_tousertype(L, 1, 0); unit *u = (unit *) tolua_tousertype(L, 2, 0); - unit *o = b ? building_owner(b) : NULL; - if (o && o != u) { - freset(o, UFL_OWNER); - } - if (u) { - fset(u, UFL_OWNER); - } + building_set_owner(b, u); return 0; } diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index 0f37b9685..8c63cd9e3 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -1351,24 +1351,26 @@ static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr) ru && ru->type == &at_travelunit; ru = ru->next) { unit *u = (unit *) ru->data.v; if (cansee_durchgezogen(f, r, u, 0) && r != u->region) { - if (!u->ship || !fval(u, UFL_OWNER)) - continue; - if (!seeships) - fprintf(F, "DURCHSCHIFFUNG\n"); - seeships = true; - fprintf(F, "\"%s\"\n", shipname(u->ship)); + if (u->ship && ship_owner(u->ship)==u) { + if (!seeships) { + fprintf(F, "DURCHSCHIFFUNG\n"); + } + seeships = true; + fprintf(F, "\"%s\"\n", shipname(u->ship)); + } } } for (ru = a_find(r->attribs, &at_travelunit); ru && ru->type == &at_travelunit; ru = ru->next) { unit *u = (unit *) ru->data.v; if (cansee_durchgezogen(f, r, u, 0) && r != u->region) { - if (u->ship) - continue; - if (!seeunits) - fprintf(F, "DURCHREISE\n"); - seeunits = true; - fprintf(F, "\"%s\"\n", unitname(u)); + if (!u->ship) { + if (!seeunits) { + fprintf(F, "DURCHREISE\n"); + } + seeunits = true; + fprintf(F, "\"%s\"\n", unitname(u)); + } } } } diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index 6b99573a8..0deab6870 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -1105,51 +1105,6 @@ static boolean maintain(building * b, boolean first) return true; } -#ifdef COLLAPSE_CHANCE -static void gebaeude_stuerzt_ein(region * r, building * b) -{ - unit *u; - int n, i; - int opfer = 0; - int road = 0; - struct message *msg; - - for (u = r->units; u; u = u->next) { - if (u->building == b) { - int loss = 0; - - fset(u->faction, FFL_MARK); - freset(u, UFL_OWNER); - leave(r, u); - n = u->number; -#ifdef COLLAPSE_SURVIVAL - for (i = 0; i < n; i++) { - if (rng_double() >= COLLAPSE_SURVIVAL) { - ++loss; - } - } -#endif - scale_number(u, u->number - loss); - opfer += loss; - } - } - - msg = - msg_message("buildingcrash", "region building opfer road", r, b, opfer, - road); - add_message(&r->msgs, msg); - for (u = r->units; u; u = u->next) { - faction *f = u->faction; - if (fval(f, FFL_MARK)) { - freset(u->faction, FFL_MARK); - add_message(&f->msgs, msg); - } - } - msg_release(msg); - remove_building(&r->buildings, b); -} -#endif - void maintain_buildings(region * r, boolean crash) { building **bp = &r->buildings; @@ -1159,12 +1114,6 @@ void maintain_buildings(region * r, boolean crash) /* the second time, send a message */ if (crash) { -#ifdef COLLAPSE_CHANCE - if (!maintained && (rng_double() < COLLAPSE_CHANCE)) { - gebaeude_stuerzt_ein(r, b); - continue; - } -#endif if (!fval(b, BLD_WORKING)) { unit *u = building_owner(b); const char *msgtype = diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 8d1c4b229..61e0989df 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -1203,7 +1203,7 @@ static void nmr_death(faction * f) if (rule) { unit *u; for (u = f->units; u; u = u->nextF) { - if (u->building && fval(u, UFL_OWNER)) { + if (u->building && building_owner(u->building)==u) { remove_building(&u->region->buildings, u->building); } } @@ -1526,7 +1526,6 @@ static cmp_building_cb get_cmp_region_owner(void) static int display_cmd(unit * u, struct order *ord) { - building *b = u->building; char **s = NULL; const char *str; region *r = u->region; @@ -1538,19 +1537,19 @@ static int display_cmd(unit * u, struct order *ord) switch (findparam_ex(str, u->faction->locale)) { case P_BUILDING: case P_GEBAEUDE: - if (!b) { + if (!u->building) { cmistake(u, ord, 145, MSG_PRODUCE); break; } - if (!fval(u, UFL_OWNER)) { + if (building_owner(u->building)!=u) { cmistake(u, ord, 5, MSG_PRODUCE); break; } - if (!fval(b->type, BTF_NAMECHANGE) && b->display && b->display[0] != 0) { + if (!fval(u->building->type, BTF_NAMECHANGE) && u->building->display && u->building->display[0]) { cmistake(u, ord, 278, MSG_EVENT); break; } - s = &b->display; + s = &u->building->display; break; case P_SHIP: @@ -1558,7 +1557,7 @@ static int display_cmd(unit * u, struct order *ord) cmistake(u, ord, 144, MSG_PRODUCE); break; } - if (!fval(u, UFL_OWNER)) { + if (ship_owner(u->ship)!=u) { cmistake(u, ord, 12, MSG_PRODUCE); break; } @@ -1581,15 +1580,15 @@ static int display_cmd(unit * u, struct order *ord) break; case P_REGION: - if (!b) { + if (!u->building) { cmistake(u, ord, 145, MSG_EVENT); break; } - if (!fval(u, UFL_OWNER)) { + if (building_owner(u->building)!=u) { cmistake(u, ord, 148, MSG_EVENT); break; } - if (b != largestbuilding(r, get_cmp_region_owner(), false)) { + if (u->building != largestbuilding(r, get_cmp_region_owner(), false)) { cmistake(u, ord, 147, MSG_EVENT); break; } @@ -1682,7 +1681,7 @@ rename_building(unit * u, order * ord, building * b, const char *name) } } } else { - if (!fval(u, UFL_OWNER)) { + if (owner!=u) { cmistake(u, ord, 148, MSG_PRODUCE); return -1; } @@ -1814,7 +1813,7 @@ static int name_cmd(unit * u, struct order *ord) cmistake(u, ord, 144, MSG_PRODUCE); break; } - if (!fval(u, UFL_OWNER)) { + if (ship_owner(u->ship)!=u) { cmistake(u, ord, 12, MSG_PRODUCE); break; } @@ -1857,7 +1856,7 @@ static int name_cmd(unit * u, struct order *ord) cmistake(u, ord, 145, MSG_EVENT); break; } - if (!fval(u, UFL_OWNER)) { + if (building_owner(b)!=u) { cmistake(u, ord, 148, MSG_EVENT); break; } @@ -2881,7 +2880,9 @@ static void reorder(void) cmistake(u, ord, 258, MSG_EVENT); } else if (v->building != u->building || v->ship != u->ship) { cmistake(u, ord, 259, MSG_EVENT); - } else if (fval(u, UFL_OWNER)) { + } else if (u->building && building_owner(u->building)==u) { + cmistake(u, ord, 260, MSG_EVENT); + } else if (u->ship && ship_owner(u->ship)==u) { cmistake(u, ord, 260, MSG_EVENT); } else if (v == u) { cmistake(u, ord, 10, MSG_EVENT); @@ -2895,7 +2896,9 @@ static void reorder(void) sorted = true; break; case P_BEFORE: - if (fval(v, UFL_OWNER)) { + if (v->ship && ship_owner(v->ship)==v) { + cmistake(v, ord, 261, MSG_EVENT); + } else if (v->building && building_owner(v->building)==v) { cmistake(v, ord, 261, MSG_EVENT); } else { unit **vp = &r->units; @@ -2990,7 +2993,7 @@ static int renumber_cmd(unit * u, order * ord) cmistake(u, ord, 116, MSG_EVENT); break; } - if (!fval(u, UFL_OWNER)) { + if (ship_owner(u->ship)!=u) { cmistake(u, ord, 146, MSG_EVENT); break; } @@ -3018,7 +3021,7 @@ static int renumber_cmd(unit * u, order * ord) cmistake(u, ord, 145, MSG_EVENT); break; } - if (!fval(u, UFL_OWNER)) { + if (building_owner(u->building)!=u) { cmistake(u, ord, 148, MSG_EVENT); break; } @@ -4068,12 +4071,6 @@ static void maintain_buildings_1(region * r) maintain_buildings(r, false); } -#ifdef COLLAPSE_CHANCE -static void maintain_buildings_2(region * r) -{ - maintain_buildings(r, true); -} -#endif static void reset_moved(unit * u) { freset(u, UFL_MOVED); @@ -4246,11 +4243,6 @@ void init_processor(void) } add_proc_global(p, &demographics, "Nahrung, Seuchen, Wachstum, Wanderung"); -#ifdef COLLAPSE_CHANCE - p += 10; - add_proc_region(p, &maintain_buildings_2, "Gebaeudeunterhalt (2. Versuch)"); -#endif - if (!global.disabled[K_SORT]) { p += 10; add_proc_global(p, &reorder, "Einheiten sortieren"); diff --git a/src/gamecode/laws_test.c b/src/gamecode/laws_test.c index e8fbd1895..fce2fa060 100644 --- a/src/gamecode/laws_test.c +++ b/src/gamecode/laws_test.c @@ -54,7 +54,6 @@ static void test_rename_building(CuTest * tc) f = test_create_faction(rc_find("human")); u = test_create_unit(f, r); u_set_building(u, b); - fset(u, UFL_OWNER); rename_building(u, NULL, b, "Villa Nagel"); CuAssertStrEquals(tc, "Villa Nagel", b->name); diff --git a/src/gamecode/report.c b/src/gamecode/report.c index 79d2c8e54..e08b198d5 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -1382,7 +1382,7 @@ static void durchreisende(FILE * F, const region * r, const faction * f) for (a = abegin; a && a->type == &at_travelunit; a = a->next) { unit *u = (unit *) a->data.v; - if (r != u->region && (u->ship == NULL || fval(u, UFL_OWNER))) { + if (r != u->region && (!u->ship || ship_owner(u->ship)==u)) { if (cansee_durchgezogen(f, r, u, 0)) { ++maxtravel; } @@ -1399,7 +1399,7 @@ static void durchreisende(FILE * F, const region * r, const faction * f) for (a = abegin; a && a->type == &at_travelunit; a = a->next) { unit *u = (unit *) a->data.v; - if (r != u->region && (u->ship == NULL || fval(u, UFL_OWNER))) { + if (r != u->region && (!u->ship || ship_owner(u->ship)==u)) { if (cansee_durchgezogen(f, r, u, 0)) { ++counter; if (u->ship != NULL) { @@ -1565,7 +1565,7 @@ report_template(const char *filename, report_context * ctx, const char *charset) unitid(u), u->name, u->number, get_money(u)); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - if (u->building != NULL && fval(u, UFL_OWNER)) { + if (u->building && building_owner(u->building)==u) { building *b = u->building; int cost = buildingmaintenance(b, r_silver); @@ -1578,7 +1578,7 @@ report_template(const char *filename, report_context * ctx, const char *charset) WARN_STATIC_BUFFER(); } } else if (u->ship) { - if (fval(u, UFL_OWNER)) { + if (ship_owner(u->ship)==u) { bytes = (int)strlcpy(bufp, ",S", size); } else { bytes = (int)strlcpy(bufp, ",s", size); diff --git a/src/kernel/build.c b/src/kernel/build.c index 4804c7d1c..e718ff5b2 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -376,7 +376,6 @@ int destroy_cmd(unit * u, struct order *ord) /* all units leave the building */ for (u2 = r->units; u2; u2 = u2->next) { if (u2->building == b) { - freset(u2, UFL_OWNER); leave_building(u2); } } diff --git a/src/kernel/config.h b/src/kernel/config.h index 30145886d..510678c27 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -68,13 +68,6 @@ extern "C" { /* Chance of a monster attack */ #define MONSTERATTACK 0.4F -/** Chance of an unmaintained building crashing */ -/* #define COLLAPSE_CHANCE 0.4F */ -#undef COLLAPSE_CHANCE -/** chance to survive the crash of a building */ -/* #define COLLAPSE_SURVIVAL 0.5F */ -#undef COLLAPSE_SURVIVAL - /* Bewegungsweiten: */ #define BP_WALKING 4 #define BP_RIDING 6 diff --git a/src/kernel/move.c b/src/kernel/move.c index f0d484650..d6600e05d 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -2597,13 +2597,13 @@ void movement(void) set_order(&u->thisorder, NULL); } else { if (ships) { - if (u->ship && fval(u, UFL_OWNER)) { + if (u->ship && ship_owner(u->ship)==u) { init_tokens(u->thisorder); skip_token(); move(u, false); } } else { - if (u->ship == NULL || !fval(u, UFL_OWNER)) { + if (!u->ship || ship_owner(u->ship)!=u) { init_tokens(u->thisorder); skip_token(); move(u, false); diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 3b1fdcf3b..f4dd38596 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -795,32 +795,21 @@ void u_set_ship(unit * u, ship * sh) void leave_ship(unit * u) { struct ship *sh = u->ship; - if (!sh) return; + u->ship = 0; + if (sh->_owner==u) { + sh->_owner = ship_owner(sh); + } set_leftship(u, sh); } void leave_building(unit * u) { - struct building *b = u->building; + building * b = u->building; - u->building = NULL; - if (b && fval(u, UFL_OWNER)) { - unit *u2, *owner = NULL; - freset(u, UFL_OWNER); - - for (u2 = u->region->units; u2; u2 = u2->next) { - if (u2->building == b) { - if (u2->faction == u->faction) { - owner = u2; - break; - } else if (owner == NULL) - owner = u2; - } - } - if (owner != NULL) { - fset(owner, UFL_OWNER); - } + u->building = 0; + if (b->_owner==u) { + b->_owner = building_owner(b); } } From ad05ec8c53cce2c56771f34683b85aa2872bac2d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 18 May 2012 02:08:29 +0200 Subject: [PATCH 205/400] fix an assert that was too picky --- src/kernel/unit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/unit.c b/src/kernel/unit.c index f4dd38596..e71834270 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -776,7 +776,7 @@ ship *leftship(const unit * u) void u_set_building(unit * u, building * b) { - assert(b && !u->building); /* you must leave first */ + assert(!u->building); /* you must leave first */ u->building = b; if (b && !b->_owner) { building_set_owner(b, u); From 8cd99bf88cd62254516285102e9a725f7203ecd4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 18 May 2012 09:19:46 -0700 Subject: [PATCH 206/400] fallback for generating building/ship names in tests, when no translations are available --- src/gamecode/market_test.c | 8 ++++---- src/kernel/building.c | 25 +++++++++++++++++-------- src/kernel/ship.c | 14 ++++++++++++-- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/gamecode/market_test.c b/src/gamecode/market_test.c index c60876995..1e7eefb8e 100644 --- a/src/gamecode/market_test.c +++ b/src/gamecode/market_test.c @@ -1,5 +1,3 @@ -#include - #include "platform.h" #include "market.h" #include "tests.h" @@ -15,6 +13,9 @@ #include +#include +#include + #include static void market_curse(CuTest * tc) @@ -33,7 +34,6 @@ static void market_curse(CuTest * tc) luxury_type *lux = new_luxurytype(ltype, 0); building_type *btype; race *rc = rc_add(rc_new("human")); - struct locale *lang = make_locale("en"); free_gamedata(); @@ -55,7 +55,7 @@ static void market_curse(CuTest * tc) } } r = findregion(1, 1); - b = new_building(btype, r, lang); + b = test_create_building(r, btype); b->flags |= BLD_WORKING; b->size = b->type->maxsize; diff --git a/src/kernel/building.c b/src/kernel/building.c index 1295d47b1..525bcff63 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -35,6 +35,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include #include +#include #include #include #include @@ -452,6 +453,8 @@ building *new_building(const struct building_type * btype, region * r, building *b = (building *) calloc(1, sizeof(building)); static boolean init_lighthouse = false; static const struct building_type *bt_lighthouse = 0; + const char *bname = 0; + char buffer[32]; if (!init_lighthouse) { bt_lighthouse = bt_find("lighthouse"); @@ -471,15 +474,21 @@ building *new_building(const struct building_type * btype, region * r, if (b->type == bt_lighthouse) { r->flags |= RF_LIGHTHOUSE; } - { - const char *bname; - if (b->type->name == NULL) { - bname = LOC(lang, btype->_name); - } else { - bname = LOC(lang, buildingtype(btype, b, 0)); - } - b->name = strdup(bname); + if (b->type->name) { + bname = LOC(lang, buildingtype(btype, b, 0)); } + if (!bname) { + bname = LOC(lang, btype->_name); + } + if (!bname) { + bname = LOC(lang, parameters[P_GEBAEUDE]); + } + if (!bname) { + bname = parameters[P_GEBAEUDE]; + } + assert(bname); + slprintf(buffer, sizeof(buffer), "%s %s", bname, buildingid(b)); + b->name = strdup(bname); return b; } diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 2d15bb52c..708665e91 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -31,6 +31,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include #include +#include #include #include #include @@ -165,8 +166,9 @@ static ship *deleted_ships; ship *new_ship(const ship_type * stype, region * r, const struct locale *lang) { - static char buffer[7 + IDSIZE + 1]; + static char buffer[32]; ship *sh = (ship *) calloc(1, sizeof(ship)); + const char *sname = 0; assert(stype); assert(r); @@ -175,7 +177,15 @@ ship *new_ship(const ship_type * stype, region * r, const struct locale *lang) sh->type = stype; sh->region = r; - sprintf(buffer, "%s %s", LOC(lang, stype->name[0]), shipid(sh)); + sname = LOC(lang, stype->name[0]); + if (!sname) { + sname = LOC(lang, parameters[P_SHIP]); + if (!sname) { + sname = parameters[P_SHIP]; + } + } + assert(sname); + slprintf(buffer, sizeof(buffer), "%s %s", sname, shipid(sh)); sh->name = strdup(buffer); shash(sh); addlist(&r->ships, sh); From 0616549ea5e892dd3c16bc49bd53eaf97b9c349f Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 18 May 2012 19:29:35 -0700 Subject: [PATCH 207/400] new gcc spouts more warnings, fix them. --- src/kernel/building_test.c | 5 +++++ src/kernel/move_test.c | 1 + src/tests.c | 3 +-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/kernel/building_test.c b/src/kernel/building_test.c index 0e09aa1c8..07f433e41 100644 --- a/src/kernel/building_test.c +++ b/src/kernel/building_test.c @@ -308,6 +308,10 @@ static void test_buildingowner_resets_when_dead(CuTest * tc) CuAssertPtrEquals(tc, 0, building_owner(bld)); } +void test_buildingowner_goes_to_empty_unit_if_no_other(CuTest * tc) +{ +} + CuSuite *get_building_suite(void) { CuSuite *suite = CuSuiteNew(); @@ -320,5 +324,6 @@ CuSuite *get_building_suite(void) SUITE_ADD_TEST(suite, test_buildingowner_goes_to_next_after_leave); SUITE_ADD_TEST(suite, test_buildingowner_goes_to_other_after_leave); SUITE_ADD_TEST(suite, test_buildingowner_goes_to_same_faction_after_leave); + SUITE_ADD_TEST(suite, test_buildingowner_goes_to_empty_unit_if_no_other); return suite; } diff --git a/src/kernel/move_test.c b/src/kernel/move_test.c index 766366e59..8b7bf4408 100644 --- a/src/kernel/move_test.c +++ b/src/kernel/move_test.c @@ -25,6 +25,7 @@ static void test_building_type_exists(CuTest * tc) r = findregion(-1, 0); b = new_building(btype, r, default_locale); + CuAssertPtrNotNull(tc, b); CuAssertTrue(tc, buildingtype_exists(r, NULL, true) == false); CuAssertTrue(tc, buildingtype_exists(r, btype, true) == true); CuAssertTrue(tc, buildingtype_exists(r, btype2, true) == false); diff --git a/src/tests.c b/src/tests.c index 5219f9983..193f3553a 100644 --- a/src/tests.c +++ b/src/tests.c @@ -151,7 +151,6 @@ void test_create_world(void) { terrain_type *t_plain, *t_ocean; region *island[2]; - race *rc_human; int i; building_type *btype; ship_type *stype; @@ -179,7 +178,7 @@ void test_create_world(void) } } - rc_human = test_create_race("human"); + test_create_race("human"); btype = (building_type*)calloc(sizeof(building_type), 1); btype->flags = BTF_NAMECHANGE; From 57fbc7809c225b757832e0c35eee74399ddea7dd Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 18 May 2012 21:26:41 -0700 Subject: [PATCH 208/400] more strictly define what it means to be the owner of the building, and when it is transferred. test coverage is a winderful thing. UFL_OWNER is probably entirely useless now, must fix --- src/gamecode/laws.c | 3 +- src/kernel/building.c | 56 ++++++++++++++++++--------------- src/kernel/building.h | 1 + src/kernel/building_test.c | 63 +++++++++++++++++++++++++++++--------- src/kernel/unit.c | 3 +- 5 files changed, 84 insertions(+), 42 deletions(-) diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 61e0989df..da86af7b2 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -3362,8 +3362,7 @@ static void new_units(void) if (token && token[0]) { name = strdup(token); } - u2 = - create_unit(r, u->faction, 0, u->faction->race, alias, name, u); + u2 = create_unit(r, u->faction, 0, u->faction->race, alias, name, u); if (name != NULL) free(name); fset(u2, UFL_ISNEW); diff --git a/src/kernel/building.c b/src/kernel/building.c index 525bcff63..3e4377d14 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -634,38 +634,44 @@ void building_set_owner(struct building *b, struct unit * owner) fset(owner, UFL_OWNER); } +static unit *building_owner_ex(const building * bld, const faction * last_owner) +{ + unit *u, *heir = 0; + + /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit + * nehmen. */ + for (u = bld->region->units; u; u = u->next) { + if (u->building == bld) { + if (u->number > 0) { + if (heir && last_owner && heir->faction!=last_owner && u->faction==last_owner) { + heir = u; + break; /* we found someone from the same faction who is not dead. let's take this guy */ + } + else if (!heir) { + heir = u; /* you'll do in an emergency */ + } + } + freset(u, UFL_OWNER); + } + } + return heir; +} + unit *building_owner(const building * bld) { unit *owner = bld->_owner; - if (owner && (owner->building!=bld || owner->number<=0)) { - unit *u, *heir = 0; - - /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit - * nehmen. */ - for (u = bld->region->units; u; u = u->next) { - if (u->building == bld) { - if (u->number > 0) { - if (u->faction==owner->faction) { - heir = u; - break; - } - else if (!heir) { - heir = u; /* you'll do in an emergency */ - } - } - freset(u, UFL_OWNER); - } - } - freset(owner, UFL_OWNER); - owner->building = 0; - owner = heir; - if (owner) { - fset(owner, UFL_OWNER); - } + if (!owner || (owner->building!=bld || owner->number<=0)) { + unit * heir = building_owner_ex(bld, owner?owner->faction:0); + return (heir && heir->number>0) ? heir : 0; } return owner; } +void building_update_owner(building * bld) { + unit * owner = bld->_owner; + bld->_owner = building_owner_ex(bld, owner?owner->faction:0); +} + const char *building_getname(const building * self) { return self->name; diff --git a/src/kernel/building.h b/src/kernel/building.h index bacf91d93..2c7cec522 100644 --- a/src/kernel/building.h +++ b/src/kernel/building.h @@ -153,6 +153,7 @@ extern "C" { extern struct unit *building_owner(const struct building *b); extern void building_set_owner(struct building *b, struct unit * u); + extern void building_update_owner(struct building * bld); extern struct attrib_type at_building_action; void building_addaction(struct building *b, const char *fname, diff --git a/src/kernel/building_test.c b/src/kernel/building_test.c index 07f433e41..6d2e7edc0 100644 --- a/src/kernel/building_test.c +++ b/src/kernel/building_test.c @@ -54,7 +54,7 @@ static void test_building_set_owner(CuTest * tc) CuAssertPtrEquals(tc, u2, building_owner(bld)); } -static void test_buildingowner_goes_to_next_after_death(CuTest * tc) +static void test_buildingowner_goes_to_next_when_empty(CuTest * tc) { struct region *r; struct building *bld; @@ -88,7 +88,7 @@ static void test_buildingowner_goes_to_next_after_death(CuTest * tc) CuAssertPtrEquals(tc, u2, building_owner(bld)); } -static void test_buildingowner_goes_to_other_after_death(CuTest * tc) +static void test_buildingowner_goes_to_other_when_empty(CuTest * tc) { struct region *r; struct building *bld; @@ -123,7 +123,7 @@ static void test_buildingowner_goes_to_other_after_death(CuTest * tc) CuAssertPtrEquals(tc, u2, building_owner(bld)); } -static void test_buildingowner_goes_to_same_faction_after_death(CuTest * tc) +static void test_buildingowner_goes_to_same_faction_when_empty(CuTest * tc) { struct region *r; struct building *bld; @@ -159,12 +159,8 @@ static void test_buildingowner_goes_to_same_faction_after_death(CuTest * tc) CuAssertTrue(tc, fval(u, UFL_OWNER)); u->number = 0; CuAssertPtrEquals(tc, u3, building_owner(bld)); - CuAssertTrue(tc, !fval(u, UFL_OWNER)); - CuAssertTrue(tc, fval(u3, UFL_OWNER)); u3->number = 0; CuAssertPtrEquals(tc, u2, building_owner(bld)); - CuAssertTrue(tc, !fval(u3, UFL_OWNER)); - CuAssertTrue(tc, fval(u2, UFL_OWNER)); } static void test_buildingowner_goes_to_next_after_leave(CuTest * tc) @@ -276,7 +272,7 @@ static void test_buildingowner_goes_to_same_faction_after_leave(CuTest * tc) CuAssertPtrEquals(tc, 0, building_owner(bld)); } -static void test_buildingowner_resets_when_dead(CuTest * tc) +static void test_buildingowner_resets_when_empty(CuTest * tc) { struct region *r; struct building *bld; @@ -306,10 +302,49 @@ static void test_buildingowner_resets_when_dead(CuTest * tc) CuAssertPtrEquals(tc, u, building_owner(bld)); u->number = 0; CuAssertPtrEquals(tc, 0, building_owner(bld)); + u->number = 1; + CuAssertPtrEquals(tc, u, building_owner(bld)); } -void test_buildingowner_goes_to_empty_unit_if_no_other(CuTest * tc) +void test_buildingowner_goes_to_empty_unit_after_leave(CuTest * tc) { + struct region *r; + struct building *bld; + struct unit *u1, *u2, *u3; + struct faction *f1; + const struct building_type *btype; + const struct race *human; + + test_cleanup(); + test_create_world(); + + human = rc_find("human"); + CuAssertPtrNotNull(tc, human); + + btype = bt_find("castle"); + CuAssertPtrNotNull(tc, btype); + + f1 = test_create_faction(human); + r = findregion(0, 0); + + bld = test_create_building(r, btype); + CuAssertPtrNotNull(tc, bld); + + u1 = test_create_unit(f1, r); + u2 = test_create_unit(f1, r); + u3 = test_create_unit(f1, r); + u_set_building(u1, bld); + u_set_building(u2, bld); + u_set_building(u3, bld); + + CuAssertPtrEquals(tc, u1, building_owner(bld)); + u2->number = 0; + leave_building(u1); + CuAssertPtrEquals(tc, u3, building_owner(bld)); + leave_building(u3); + CuAssertPtrEquals(tc, 0, building_owner(bld)); + u2->number = 1; + CuAssertPtrEquals(tc, u2, building_owner(bld)); } CuSuite *get_building_suite(void) @@ -317,13 +352,13 @@ CuSuite *get_building_suite(void) CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_register_building); SUITE_ADD_TEST(suite, test_building_set_owner); - SUITE_ADD_TEST(suite, test_buildingowner_resets_when_dead); - SUITE_ADD_TEST(suite, test_buildingowner_goes_to_next_after_death); - SUITE_ADD_TEST(suite, test_buildingowner_goes_to_other_after_death); - SUITE_ADD_TEST(suite, test_buildingowner_goes_to_same_faction_after_death); + SUITE_ADD_TEST(suite, test_buildingowner_resets_when_empty); + SUITE_ADD_TEST(suite, test_buildingowner_goes_to_next_when_empty); + SUITE_ADD_TEST(suite, test_buildingowner_goes_to_other_when_empty); + SUITE_ADD_TEST(suite, test_buildingowner_goes_to_same_faction_when_empty); SUITE_ADD_TEST(suite, test_buildingowner_goes_to_next_after_leave); SUITE_ADD_TEST(suite, test_buildingowner_goes_to_other_after_leave); SUITE_ADD_TEST(suite, test_buildingowner_goes_to_same_faction_after_leave); - SUITE_ADD_TEST(suite, test_buildingowner_goes_to_empty_unit_if_no_other); + SUITE_ADD_TEST(suite, test_buildingowner_goes_to_empty_unit_after_leave); return suite; } diff --git a/src/kernel/unit.c b/src/kernel/unit.c index e71834270..2e150ef37 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -809,7 +809,8 @@ void leave_building(unit * u) u->building = 0; if (b->_owner==u) { - b->_owner = building_owner(b); + building_update_owner(b); + assert(b->_owner!=u); } } From e501ed5bbd37edb1cd668f380e8cab4c27f16d00 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 18 May 2012 21:46:41 -0700 Subject: [PATCH 209/400] test that we are the owner of the building first. --- src/gamecode/laws.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index da86af7b2..8df1a71bc 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -2989,14 +2989,14 @@ static int renumber_cmd(unit * u, order * ord) cmistake(u, ord, 144, MSG_EVENT); break; } - if (u->ship->coast != NODIRECTION) { - cmistake(u, ord, 116, MSG_EVENT); - break; - } if (ship_owner(u->ship)!=u) { cmistake(u, ord, 146, MSG_EVENT); break; } + if (u->ship->coast != NODIRECTION) { + cmistake(u, ord, 116, MSG_EVENT); + break; + } s = getstrtoken(); if (s == NULL || *s == 0) { i = newcontainerid(); From 0c2531f2598bbab546b824be42f1177492e9605d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 18 May 2012 22:34:04 -0700 Subject: [PATCH 210/400] remove UFL_OWNER anywhere but in save.c --- src/gamecode/economy.c | 30 ++++++++++++++++++------------ src/gamecode/laws.c | 2 +- src/kernel/building.c | 5 ----- src/kernel/building_test.c | 1 - src/kernel/config.c | 2 +- src/kernel/message.c | 9 ++++++--- src/kernel/message.h | 2 +- src/kernel/move.c | 12 ++++++------ src/kernel/reports.c | 23 +++++++---------------- src/kernel/save.c | 12 +++++++++++- src/kernel/ship.c | 9 --------- src/kernel/ship_test.c | 5 ----- src/kernel/unit.h | 2 +- 13 files changed, 52 insertions(+), 62 deletions(-) diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index 0deab6870..e1eaaa217 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -658,22 +658,28 @@ int give_control_cmd(unit * u, order * ord) /* first, do all the ones that do not require HELP_GIVE or CONTACT */ if (p == P_CONTROL) { - message *msg; + message *msg = 0; if (!u2 || u2->number == 0) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", - "")); + msg = msg_feedback(u, ord, "feedback_unit_not_found", ""); + ADDMSG(&u->faction->msgs, msg); } else if (!u->building && !u->ship) { - cmistake(u, ord, 140, MSG_EVENT); - } else if (u->building && u2->building != u->building) { - cmistake(u, ord, 33, MSG_EVENT); - } else if (u->ship && u2->ship != u->ship) { - cmistake(u, ord, 32, MSG_EVENT); - } else if (!fval(u, UFL_OWNER)) { - cmistake(u, ord, 49, MSG_EVENT); - } else { + msg = cmistake(u, ord, 140, MSG_EVENT); + } else if (u->building) { + if (u!=building_owner(u->building)) { + msg = cmistake(u, ord, 49, MSG_EVENT); + } else if (u2->building != u->building) { + msg = cmistake(u, ord, 33, MSG_EVENT); + } + } else if (u->ship) { + if (u!=ship_owner(u->ship)) { + msg = cmistake(u, ord, 49, MSG_EVENT); + } else if (u2->ship != u->ship) { + msg = cmistake(u, ord, 32, MSG_EVENT); + } + } + if (!msg) { give_control(u, u2); - msg = msg_message("givecommand", "unit recipient", u, u2); add_message(&u->faction->msgs, msg); if (u->faction != u2->faction) { diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 8df1a71bc..d2096ae9c 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -2876,7 +2876,7 @@ static void reorder(void) id = getid(); v = findunit(id); - if (v == NULL || v->faction != u->faction || v->region != r) { + if (!v || v->faction != u->faction || v->region != r) { cmistake(u, ord, 258, MSG_EVENT); } else if (v->building != u->building || v->ship != u->ship) { cmistake(u, ord, 259, MSG_EVENT); diff --git a/src/kernel/building.c b/src/kernel/building.c index 3e4377d14..43dff12ef 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -627,11 +627,7 @@ const char *buildingname(const building * b) void building_set_owner(struct building *b, struct unit * owner) { assert(b && owner && owner->building==b); - if (b->_owner && b->_owner!=owner) { - freset(b->_owner, UFL_OWNER); - } b->_owner = owner; - fset(owner, UFL_OWNER); } static unit *building_owner_ex(const building * bld, const faction * last_owner) @@ -651,7 +647,6 @@ static unit *building_owner_ex(const building * bld, const faction * last_owner) heir = u; /* you'll do in an emergency */ } } - freset(u, UFL_OWNER); } } return heir; diff --git a/src/kernel/building_test.c b/src/kernel/building_test.c index 6d2e7edc0..42f68690d 100644 --- a/src/kernel/building_test.c +++ b/src/kernel/building_test.c @@ -156,7 +156,6 @@ static void test_buildingowner_goes_to_same_faction_when_empty(CuTest * tc) u_set_building(u2, bld); u_set_building(u3, bld); CuAssertPtrEquals(tc, u, building_owner(bld)); - CuAssertTrue(tc, fval(u, UFL_OWNER)); u->number = 0; CuAssertPtrEquals(tc, u3, building_owner(bld)); u3->number = 0; diff --git a/src/kernel/config.c b/src/kernel/config.c index eb4c5d18d..c837bb946 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -2367,7 +2367,7 @@ unsigned int getguard(const unit * u) { attrib *a; - assert((u->building && fval(u, UFL_OWNER)) || fval(u, UFL_GUARD) + assert(fval(u, UFL_GUARD) || (u->building && u==building_owner(u->building)) || !"you're doing it wrong! check is_guard first"); a = a_find(u->attribs, &at_guard); if (a) { diff --git a/src/kernel/message.c b/src/kernel/message.c index b0c966522..001e04004 100644 --- a/src/kernel/message.c +++ b/src/kernel/message.c @@ -251,15 +251,18 @@ void addmessage(region * r, faction * f, const char *s, msg_t mtype, int level) caddmessage(r, f, s, mtype, level); } -void cmistake(const unit * u, struct order *ord, int mno, int mtype) +message * cmistake(const unit * u, struct order *ord, int mno, int mtype) { + message * result; static char msgname[20]; unused(mtype); if (is_monsters(u->faction)) - return; + return 0; sprintf(msgname, "error%d", mno); - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, msgname, "")); + result = msg_feedback(u, ord, msgname, ""); + ADDMSG(&u->faction->msgs, result); + return result; } extern unsigned int new_hashstring(const char *s); diff --git a/src/kernel/message.h b/src/kernel/message.h index 6d81b417b..2623df169 100644 --- a/src/kernel/message.h +++ b/src/kernel/message.h @@ -56,7 +56,7 @@ extern "C" { #define ADDMSG(msgs, mcreate) { message * m = mcreate; if (m) { assert(m->refcount>=1); add_message(msgs, m); msg_release(m); } } - extern void cmistake(const struct unit *u, struct order *ord, int mno, + extern struct message * cmistake(const struct unit *u, struct order *ord, int mno, int mtype); #ifdef __cplusplus } diff --git a/src/kernel/move.c b/src/kernel/move.c index d6600e05d..528e9da64 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -894,7 +894,7 @@ static boolean is_guardian_r(const unit * guard) return false; /* if region_owners exist then they may be guardians: */ - if (guard->building && rule_region_owners() && fval(guard, UFL_OWNER)) { + if (guard->building && rule_region_owners() && guard==building_owner(guard->building)) { faction *owner = region_get_owner(guard->region); if (owner == guard->faction) { building *bowner = largestbuilding(guard->region, &cmp_taxes, false); @@ -1590,7 +1590,7 @@ static const region_list *travel_route(unit * u, static boolean ship_ready(const region * r, unit * u) { - if (!fval(u, UFL_OWNER)) { + if (!u->ship || u!=ship_owner(u->ship)) { cmistake(u, u->thisorder, 146, MSG_MOVE); return false; } @@ -2159,7 +2159,7 @@ static void move(unit * u, boolean move_on_land) region_list *route = NULL; assert(u->number); - if (u->ship && fval(u, UFL_OWNER)) { + if (u->ship && u==ship_owner(u->ship)) { sail(u, u->thisorder, move_on_land, &route); } else { travel(u, &route); @@ -2227,7 +2227,7 @@ static void piracy_cmd(unit * u, struct order *ord) return; } - if (!fval(u, UFL_OWNER)) { + if (!u->ship || u!=ship_owner(u->ship)) { cmistake(u, ord, 146, MSG_MOVE); return; } @@ -2370,11 +2370,11 @@ static int hunt(unit * u, order * ord) if (fval(u, UFL_NOTMOVING)) { return 0; - } else if (u->ship == NULL) { + } else if (!u->ship) { cmistake(u, ord, 144, MSG_MOVE); fset(u, UFL_LONGACTION | UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ return 0; - } else if (!fval(u, UFL_OWNER)) { + } else if (u!=ship_owner(u->ship)) { cmistake(u, ord, 146, MSG_MOVE); fset(u, UFL_LONGACTION | UFL_NOTMOVING); /* FOLGE SCHIFF ist immer lang */ return 0; diff --git a/src/kernel/reports.c b/src/kernel/reports.c index 645ad0f56..51855299b 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -1414,14 +1414,13 @@ void reorder_units(region * r) while (*unext && b) { unit **ufirst = unext; /* where the first unit in the building should go */ unit **umove = unext; /* a unit we consider moving */ - unit *owner = NULL; - while (*umove) { + unit *owner = building_owner(b); + while (owner && *umove) { unit *u = *umove; - if (u->number && u->building == b) { + if (u->building == b) { unit **uinsert = unext; - if (fval(u, UFL_OWNER)) { + if (u==owner) { uinsert = ufirst; - owner = u; } if (umove != uinsert) { *umove = u->next; @@ -1439,10 +1438,6 @@ void reorder_units(region * r) umove = &u->next; } } - if (!owner && ufirst != unext) { - owner = *ufirst; - fset(owner, UFL_OWNER); - } b = b->next; } } @@ -1472,12 +1467,12 @@ void reorder_units(region * r) while (*unext && sh) { unit **ufirst = unext; /* where the first unit in the building should go */ unit **umove = unext; /* a unit we consider moving */ - unit *owner = NULL; - while (*umove) { + unit *owner = ship_owner(sh); + while (owner && *umove) { unit *u = *umove; if (u->number && u->ship == sh) { unit **uinsert = unext; - if (fval(u, UFL_OWNER)) { + if (u==owner) { uinsert = ufirst; owner = u; } @@ -1497,10 +1492,6 @@ void reorder_units(region * r) umove = &u->next; } } - if (!owner && ufirst != unext) { - owner = *ufirst; - fset(owner, UFL_OWNER); - } sh = sh->next; } } diff --git a/src/kernel/save.c b/src/kernel/save.c index 066414b12..24c370a2b 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -796,6 +796,9 @@ unit *read_unit(struct storage *store) building * b = findbuilding(n); if (b) { u_set_building(u, b); + if (fval(u, UFL_OWNER)) { + building_set_owner(b, u); + } } else { log_error("read_unit: unit in unkown building '%s'\n", itoa36(n)); } @@ -806,6 +809,9 @@ unit *read_unit(struct storage *store) ship * sh = findship(n); if (sh) { u_set_ship(u, sh); + if (fval(u, UFL_OWNER)) { + ship_set_owner(sh, u); + } } else { log_error("read_unit: unit in unkown ship '%s'\n", itoa36(n)); } @@ -880,7 +886,9 @@ void write_unit(struct storage *store, const unit * u) { order *ord; int i, p = 0; + unsigned int flags = u->flags & UFL_SAVEMASK; const race *irace = u_irace(u); + write_unit_reference(u, store); write_faction_reference(u->faction, store); store->w_str(store, (const char *)u->name); @@ -892,7 +900,9 @@ void write_unit(struct storage *store, const unit * u) write_building_reference(u->building, store); write_ship_reference(u->ship, store); store->w_int(store, u->status); - store->w_int(store, u->flags & UFL_SAVEMASK); + if (u->building && u==building_owner(u->building)) flags |= UFL_OWNER; + if (u->ship && u==ship_owner(u->ship)) flags |= UFL_OWNER; + store->w_int(store, flags); store->w_brk(store); for (ord = u->old_orders; ord; ord = ord->next) { if (++p < MAXPERSISTENT) { diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 708665e91..d596e1873 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -288,11 +288,7 @@ void getshipweight(const ship * sh, int *sweight, int *scabins) void ship_set_owner(ship * sh, unit * u) { assert(u->ship==sh); - if (sh->_owner && sh->_owner!=u) { - freset(sh->_owner, UFL_OWNER); - } sh->_owner = u; - fset(u, UFL_OWNER); } unit *ship_owner(const ship * sh) @@ -314,14 +310,9 @@ unit *ship_owner(const ship * sh) heir = u; /* you'll do in an emergency */ } } - freset(u, UFL_OWNER); } } - freset(owner, UFL_OWNER); owner = heir; - if (owner) { - fset(owner, UFL_OWNER); - } } /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit * nehmen. */ diff --git a/src/kernel/ship_test.c b/src/kernel/ship_test.c index 8e69a6bd4..fc7c1be1f 100644 --- a/src/kernel/ship_test.c +++ b/src/kernel/ship_test.c @@ -155,15 +155,10 @@ static void test_shipowner_goes_to_same_faction_after_death(CuTest * tc) u_set_ship(u2, sh); u_set_ship(u3, sh); CuAssertPtrEquals(tc, u, ship_owner(sh)); - CuAssertTrue(tc, fval(u, UFL_OWNER)); u->number = 0; CuAssertPtrEquals(tc, u3, ship_owner(sh)); - CuAssertTrue(tc, !fval(u, UFL_OWNER)); - CuAssertTrue(tc, fval(u3, UFL_OWNER)); u3->number = 0; CuAssertPtrEquals(tc, u2, ship_owner(sh)); - CuAssertTrue(tc, !fval(u3, UFL_OWNER)); - CuAssertTrue(tc, fval(u2, UFL_OWNER)); } static void test_shipowner_goes_to_next_after_leave(CuTest * tc) diff --git a/src/kernel/unit.h b/src/kernel/unit.h index ee473230c..1aab73569 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -63,7 +63,7 @@ extern "C" { #define UFL_GROUP (1<<28) /* Flags, die gespeichert werden sollen: */ -#define UFL_SAVEMASK (UFL_DEFENDER|UFL_MOVED|UFL_NOAID|UFL_OWNER|UFL_ANON_FACTION|UFL_LOCKED|UFL_HUNGER|UFL_TAKEALL|UFL_GUARD|UFL_STEALTH|UFL_GROUP|UFL_HERO) +#define UFL_SAVEMASK (UFL_DEFENDER|UFL_MOVED|UFL_NOAID|UFL_ANON_FACTION|UFL_LOCKED|UFL_HUNGER|UFL_TAKEALL|UFL_GUARD|UFL_STEALTH|UFL_GROUP|UFL_HERO) #define UNIT_MAXSIZE 50000 extern int maxheroes(const struct faction *f); From b95f7ec139ab282d733e9a916dbcfcfafa5edcfb Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 18 May 2012 23:20:38 -0700 Subject: [PATCH 211/400] more strictly define what it means to be the owner of the show, and when it is transferred. mostly copied from building_owner. test coverage is a wonderful thing. --- src/kernel/building.c | 15 ++++++----- src/kernel/ship.c | 47 ++++++++++++++++++++------------- src/kernel/ship.h | 2 ++ src/kernel/ship_test.c | 60 ++++++++++++++++++++++++++++++++++++------ src/kernel/unit.c | 1 + 5 files changed, 92 insertions(+), 33 deletions(-) diff --git a/src/kernel/building.c b/src/kernel/building.c index 43dff12ef..77af096cb 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -500,7 +500,6 @@ static building *deleted_buildings; void remove_building(building ** blist, building * b) { unit *u; - direction_t d; static const struct building_type *bt_caravan, *bt_dam, *bt_tunnel; static boolean init = false; @@ -527,15 +526,19 @@ void remove_building(building ** blist, building * b) * gebaute Straße zur Hälfte vernichtet */ if (b->type == bt_caravan || b->type == bt_dam || b->type == bt_tunnel) { region *r = b->region; - for (d = 0; d != MAXDIRECTIONS; ++d) - if (rroad(r, d) > 0) { - rsetroad(r, d, rroad(r, d) / 2); + int d; + for (d = 0; d != MAXDIRECTIONS; ++d) { + direction_t dir = (direction_t)d; + if (rroad(r, dir) > 0) { + rsetroad(r, dir, rroad(r, dir) / 2); } + } } /* Stattdessen nur aus Liste entfernen, aber im Speicher halten. */ - while (*blist && *blist != b) + while (*blist && *blist != b) { blist = &(*blist)->next; + } *blist = b->next; b->region = NULL; b->next = deleted_buildings; @@ -630,7 +633,7 @@ void building_set_owner(struct building *b, struct unit * owner) b->_owner = owner; } -static unit *building_owner_ex(const building * bld, const faction * last_owner) +static unit *building_owner_ex(const building * bld, const struct faction * last_owner) { unit *u, *heir = 0; diff --git a/src/kernel/ship.c b/src/kernel/ship.c index d596e1873..46f75689d 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -291,31 +291,40 @@ void ship_set_owner(ship * sh, unit * u) { sh->_owner = u; } -unit *ship_owner(const ship * sh) +static unit * ship_owner_ex(const ship * sh, const struct faction * last_owner) { - unit *owner = sh->_owner; - if (owner && (owner->ship!=sh || owner->number<=0)) { - unit *u, *heir = 0; + unit *u, *heir = 0; - owner->ship = 0; - /* Prüfen ob Eigentümer am leben. */ - for (u = sh->region->units; u; u = u->next) { - if (u->ship == sh) { - if (u->number > 0) { - if (u->faction==owner->faction) { - heir = u; - break; - } - else if (!heir) { - heir = u; /* you'll do in an emergency */ - } + /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit + * nehmen. */ + for (u = sh->region->units; u; u = u->next) { + if (u->ship == sh) { + if (u->number > 0) { + if (heir && last_owner && heir->faction!=last_owner && u->faction==last_owner) { + heir = u; + break; /* we found someone from the same faction who is not dead. let's take this guy */ + } + else if (!heir) { + heir = u; /* you'll do in an emergency */ } } } - owner = heir; } - /* Eigentümer tot oder kein Eigentümer vorhanden. Erste lebende Einheit - * nehmen. */ + return heir; +} + +void ship_update_owner(ship * sh) { + unit * owner = sh->_owner; + sh->_owner = ship_owner_ex(sh, owner?owner->faction:0); +} + +unit *ship_owner(const ship * sh) +{ + unit *owner = sh->_owner; + if (!owner || (owner->ship!=sh || owner->number<=0)) { + unit * heir = ship_owner_ex(sh, owner?owner->faction:0); + return (heir && heir->number>0) ? heir : 0; + } return owner; } diff --git a/src/kernel/ship.h b/src/kernel/ship.h index b4e95a302..fe1322f47 100644 --- a/src/kernel/ship.h +++ b/src/kernel/ship.h @@ -97,6 +97,8 @@ extern "C" { extern void damage_ship(struct ship * sh, double percent); extern void ship_set_owner(struct ship * sh, struct unit * u); extern struct unit *ship_owner(const struct ship *sh); + extern void ship_update_owner(struct ship * sh); + extern const char *shipname(const struct ship *self); extern int shipcapacity(const struct ship *sh); extern void getshipweight(const struct ship *sh, int *weight, int *cabins); diff --git a/src/kernel/ship_test.c b/src/kernel/ship_test.c index fc7c1be1f..6b1d2e136 100644 --- a/src/kernel/ship_test.c +++ b/src/kernel/ship_test.c @@ -54,7 +54,7 @@ static void test_ship_set_owner(CuTest * tc) CuAssertPtrEquals(tc, u2, ship_owner(sh)); } -static void test_shipowner_goes_to_next_after_death(CuTest * tc) +static void test_shipowner_goes_to_next_when_empty(CuTest * tc) { struct region *r; struct ship *sh; @@ -88,7 +88,7 @@ static void test_shipowner_goes_to_next_after_death(CuTest * tc) CuAssertPtrEquals(tc, u2, ship_owner(sh)); } -static void test_shipowner_goes_to_other_after_death(CuTest * tc) +static void test_shipowner_goes_to_other_when_empty(CuTest * tc) { struct region *r; struct ship *sh; @@ -122,7 +122,7 @@ static void test_shipowner_goes_to_other_after_death(CuTest * tc) CuAssertPtrEquals(tc, u2, ship_owner(sh)); } -static void test_shipowner_goes_to_same_faction_after_death(CuTest * tc) +static void test_shipowner_goes_to_same_faction_when_empty(CuTest * tc) { struct region *r; struct ship *sh; @@ -270,7 +270,7 @@ static void test_shipowner_goes_to_same_faction_after_leave(CuTest * tc) CuAssertPtrEquals(tc, 0, ship_owner(sh)); } -static void test_shipowner_resets_when_dead(CuTest * tc) +static void test_shipowner_resets_when_empty(CuTest * tc) { struct region *r; struct ship *sh; @@ -300,6 +300,49 @@ static void test_shipowner_resets_when_dead(CuTest * tc) CuAssertPtrEquals(tc, u, ship_owner(sh)); u->number = 0; CuAssertPtrEquals(tc, 0, ship_owner(sh)); + u->number = 1; + CuAssertPtrEquals(tc, u, ship_owner(sh)); +} + +void test_shipowner_goes_to_empty_unit_after_leave(CuTest * tc) +{ + struct region *r; + struct ship *sh; + struct unit *u1, *u2, *u3; + struct faction *f1; + const struct ship_type *stype; + const struct race *human; + + test_cleanup(); + test_create_world(); + + human = rc_find("human"); + CuAssertPtrNotNull(tc, human); + + stype = st_find("boat"); + CuAssertPtrNotNull(tc, stype); + + f1 = test_create_faction(human); + r = findregion(0, 0); + + sh = test_create_ship(r, stype); + CuAssertPtrNotNull(tc, sh); + + u1 = test_create_unit(f1, r); + u2 = test_create_unit(f1, r); + u3 = test_create_unit(f1, r); + u_set_ship(u1, sh); + u_set_ship(u2, sh); + u_set_ship(u3, sh); + + CuAssertPtrEquals(tc, u1, ship_owner(sh)); + u2->number = 0; + leave_ship(u1); + CuAssertPtrEquals(tc, u3, ship_owner(sh)); + leave_ship(u3); + CuAssertPtrEquals(tc, 0, ship_owner(sh)); + u2->number = 1; + CuAssertPtrEquals(tc, u2, ship_owner(sh)); } CuSuite *get_ship_suite(void) @@ -307,12 +350,13 @@ CuSuite *get_ship_suite(void) CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_register_ship); SUITE_ADD_TEST(suite, test_ship_set_owner); - SUITE_ADD_TEST(suite, test_shipowner_resets_when_dead); - SUITE_ADD_TEST(suite, test_shipowner_goes_to_next_after_death); - SUITE_ADD_TEST(suite, test_shipowner_goes_to_other_after_death); - SUITE_ADD_TEST(suite, test_shipowner_goes_to_same_faction_after_death); + SUITE_ADD_TEST(suite, test_shipowner_resets_when_empty); + SUITE_ADD_TEST(suite, test_shipowner_goes_to_next_when_empty); + SUITE_ADD_TEST(suite, test_shipowner_goes_to_other_when_empty); + SUITE_ADD_TEST(suite, test_shipowner_goes_to_same_faction_when_empty); SUITE_ADD_TEST(suite, test_shipowner_goes_to_next_after_leave); SUITE_ADD_TEST(suite, test_shipowner_goes_to_other_after_leave); SUITE_ADD_TEST(suite, test_shipowner_goes_to_same_faction_after_leave); + SUITE_ADD_TEST(suite, test_shipowner_goes_to_empty_unit_after_leave); return suite; } diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 2e150ef37..cbda7e261 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -798,6 +798,7 @@ void leave_ship(unit * u) u->ship = 0; if (sh->_owner==u) { + ship_update_owner(sh); sh->_owner = ship_owner(sh); } set_leftship(u, sh); From 504a70a9c640a63b9abb30db82c3319078990426 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 18 May 2012 23:57:20 -0700 Subject: [PATCH 212/400] fix a serious issue where repeated orders were getting lost --- src/kernel/save.c | 55 +++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/src/kernel/save.c b/src/kernel/save.c index 24c370a2b..4dc41d37f 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -291,41 +291,44 @@ static unit *unitorders(FILE * F, int enc, struct faction *f) if (s == NULL) break; - if (s[0] && s[0]!='@') { - const char *stok = s; - stok = parse_token(&stok); + if (s[0]) { + if (s[0]!='@') { + const char *stok = s; + stok = parse_token(&stok); - if (stok) { - boolean 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) { + if (stok) { + boolean quit = false; + param_t param = findparam(stok, u->faction->locale); + switch (param) { + case P_UNIT: + case P_REGION: quit = true; break; - } else { - quit = false; + 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: + /* TODO: syntax error message */ + break; + } + if (quit) { + break; } - break; - default: - /* TODO: syntax error message */ - break; - } - if (quit) { - break; } } /* Nun wird der Befehl erzeut und eingehängt */ *ordp = parse_order(s, u->faction->locale); - if (*ordp) + if (*ordp) { ordp = &(*ordp)->next; + } } } From f47f83ceca2c6423e25de7d53295f8c3db4fd816 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 19 May 2012 00:18:23 -0700 Subject: [PATCH 213/400] a little bit of test coverage for rt_find --- src/kernel.vcxproj | 1 + src/kernel.vcxproj.filters | 3 +++ src/kernel/item_test.c | 30 ++++++++++++++++++++++++++++++ src/tests.c | 2 ++ 4 files changed, 36 insertions(+) create mode 100644 src/kernel/item_test.c diff --git a/src/kernel.vcxproj b/src/kernel.vcxproj index 240cc1a6d..8c46343d9 100644 --- a/src/kernel.vcxproj +++ b/src/kernel.vcxproj @@ -104,6 +104,7 @@ + diff --git a/src/kernel.vcxproj.filters b/src/kernel.vcxproj.filters index 8c6cdcdf1..f385b7c1f 100644 --- a/src/kernel.vcxproj.filters +++ b/src/kernel.vcxproj.filters @@ -307,6 +307,9 @@ kernel + + kernel + diff --git a/src/kernel/item_test.c b/src/kernel/item_test.c new file mode 100644 index 000000000..90a668386 --- /dev/null +++ b/src/kernel/item_test.c @@ -0,0 +1,30 @@ +#include + +#include + +#include +#include + +void test_resource_type(CuTest * tc) +{ + resource_type *rtype, *rherp; + const char *names[2] = { 0 , 0 }; + + CuAssertPtrEquals(tc, 0, rt_find("herpderp")); + + names[0] = "herpderp"; + rtype = new_resourcetype(names, NULL, RTF_NONE); + names[0] = "herp"; + rherp = new_resourcetype(names, NULL, RTF_NONE); + names[0] = "herpes"; + rtype = new_resourcetype(names, NULL, RTF_NONE); + + CuAssertPtrEquals(tc, rherp, rt_find("herp")); +} + +CuSuite *get_item_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_resource_type); + return suite; +} diff --git a/src/tests.c b/src/tests.c index 193f3553a..6b3ac59d1 100644 --- a/src/tests.c +++ b/src/tests.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,7 @@ int RunAllTests(void) CuSuiteAddSuite(suite, get_umlaut_suite()); CuSuiteAddSuite(suite, get_curse_suite()); CuSuiteAddSuite(suite, get_market_suite()); + CuSuiteAddSuite(suite, get_item_suite()); CuSuiteAddSuite(suite, get_move_suite()); CuSuiteAddSuite(suite, get_reports_suite()); CuSuiteAddSuite(suite, get_ship_suite()); From 7f7c883583f515d2946a265fb26d76e9e399f525 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 19 May 2012 11:26:46 -0700 Subject: [PATCH 214/400] rt_find and it_find use new improved critbit-tree critbit update testing the test suite --- src/gamecode/laws_test.c | 3 - src/gamecode/market_test.c | 37 +++--- src/kernel/item.c | 229 +++++++++++++++++-------------------- src/kernel/item.h | 9 +- src/kernel/item_test.c | 10 +- src/tests.c | 18 ++- src/tests_test.c | 26 +++++ src/util/critbit.c | 90 +++++++++++---- src/util/critbit.h | 1 + 9 files changed, 239 insertions(+), 184 deletions(-) create mode 100644 src/tests_test.c diff --git a/src/gamecode/laws_test.c b/src/gamecode/laws_test.c index fce2fa060..0a2bb952c 100644 --- a/src/gamecode/laws_test.c +++ b/src/gamecode/laws_test.c @@ -1,6 +1,3 @@ -/* this file should only be included by laws.c, never compiled on its own - * (it does not even include all the headers needed to do so). -**/ #include #include #include "laws.h" diff --git a/src/gamecode/market_test.c b/src/gamecode/market_test.c index 1e7eefb8e..985538368 100644 --- a/src/gamecode/market_test.c +++ b/src/gamecode/market_test.c @@ -18,7 +18,7 @@ #include -static void market_curse(CuTest * tc) +static void test_market_curse(CuTest * tc) { region *r; building *b; @@ -26,16 +26,21 @@ static void market_curse(CuTest * tc) faction *f; int x, y; const char *names[4] = { "herb", "herbs", "balm", "balms" }; - terrain_type *terrain; - resource_type *hres = new_resourcetype(names, 0, RTF_ITEM | RTF_POOLED); - item_type *htype = new_itemtype(hres, ITF_HERB, 0, 0); - resource_type *lres = new_resourcetype(names + 2, 0, RTF_ITEM | RTF_POOLED); - item_type *ltype = new_itemtype(lres, ITF_NONE, 0, 0); - luxury_type *lux = new_luxurytype(ltype, 0); + const terrain_type *terrain; + resource_type *hres, *lres; + item_type *htype, *ltype; + luxury_type *lux; building_type *btype; - race *rc = rc_add(rc_new("human")); free_gamedata(); + test_cleanup(); + test_create_world(); + + hres = new_resourcetype(names, 0, RTF_ITEM | RTF_POOLED); + htype = new_itemtype(hres, ITF_HERB, 0, 0); + lres = new_resourcetype(names + 2, 0, RTF_ITEM | RTF_POOLED); + ltype = new_itemtype(lres, ITF_NONE, 0, 0); + lux = new_luxurytype(ltype, 0); set_param(&global.parameters, "rules.region_owners", "1"); @@ -43,12 +48,16 @@ static void market_curse(CuTest * tc) btype->_name = "market"; bt_register(btype); - terrain = test_create_terrain("plain", LAND_REGION | WALK_INTO); + terrain = get_terrain("plain"); for (x = 0; x != 3; ++x) { for (y = 0; y != 3; ++y) { - r = new_region(x, y, NULL, 0); - terraform_region(r, terrain); + r = findregion(x, y); + if (!r) { + r = test_create_region(x, y, terrain); + } else { + terraform_region(r, terrain); + } rsetpeasants(r, 5000); r_setdemand(r, lux, 0); rsetherbtype(r, htype); @@ -59,8 +68,8 @@ static void market_curse(CuTest * tc) b->flags |= BLD_WORKING; b->size = b->type->maxsize; - f = addfaction("nobody@eressea.de", NULL, rc, default_locale, 0); - u = create_unit(r, f, 1, f->race, 0, 0, 0); + f = test_create_faction(0); + u = test_create_unit(f, r); u_set_building(u, b); do_markets(); @@ -72,6 +81,6 @@ static void market_curse(CuTest * tc) CuSuite *get_market_suite(void) { CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, market_curse); + SUITE_ADD_TEST(suite, test_market_curse); return suite; } diff --git a/src/kernel/item.c b/src/kernel/item.c index 387112f71..25c32fe14 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -41,6 +41,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include #include +#include #include #include #include @@ -55,13 +56,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -resource_type *resourcetypes; +static critbit_tree cb_resources; +static critbit_tree cb_items; luxury_type *luxurytypes; potion_type *potiontypes; -#define IMAXHASH 127 -static item_type *itemtypes[IMAXHASH]; - static int res_changeaura(unit * u, const resource_type * rtype, int delta) { assert(rtype != NULL); @@ -173,14 +172,13 @@ resource_type *new_resourcetype(const char **names, const char **appearances, void it_register(item_type * itype) { - int hash = hashstring(itype->rtype->_name[0]); - int key = hash % IMAXHASH; - item_type **p_itype = &itemtypes[key]; - while (*p_itype && *p_itype != itype) - p_itype = &(*p_itype)->next; - if (*p_itype == NULL) { - itype->rtype->itype = itype; - *p_itype = itype; + char buffer[64]; + const char * name = itype->rtype->_name[0]; + size_t len = strlen(name); + + assert(lenrtype); } } @@ -294,16 +292,13 @@ potion_type *new_potiontype(item_type * itype, int level) void rt_register(resource_type * rtype) { - resource_type **prtype = &resourcetypes; + char buffer[64]; + const char * name = rtype->_name[0]; + size_t len = strlen(name); - if (!rtype->hashkey) { - rtype->hashkey = hashstring(rtype->_name[0]); - } - while (*prtype && *prtype != rtype) - prtype = &(*prtype)->next; - if (*prtype == NULL) { - *prtype = rtype; - } + assert(lennext) { - if (rtype->hashkey == hash && !strcmp(rtype->_name[0], name)) - break; + if (cb_find_prefix(&cb_resources, name, strlen(name)+1, &matches, 1, 0)) { + cb_get_kv(matches, &result, sizeof(result)); } - if (!rtype) { - log_warning("rt_find: unknown resource '%s'\n", name); - } - return rtype; + return result; } static const char *it_aliases[][2] = { @@ -387,23 +378,13 @@ static const char *it_alias(const char *zname) item_type *it_find(const char *zname) { const char *name = it_alias(zname); - unsigned int hash = hashstring(name); - item_type *itype; - unsigned int key = hash % IMAXHASH; + const void * matches; + item_type *result = 0; - for (itype = itemtypes[key]; itype; itype = itype->next) { - if (itype->rtype->hashkey == hash - && strcmp(itype->rtype->_name[0], name) == 0) { - break; - } + if (cb_find_prefix(&cb_items, name, strlen(name)+1, &matches, 1, 0)) { + cb_get_kv(matches, &result, sizeof(result)); } - if (itype == NULL) { - for (itype = itemtypes[key]; itype; itype = itype->next) { - if (strcmp(itype->rtype->_name[1], name) == 0) - break; - } - } - return itype; + return result; } item **i_find(item ** i, const item_type * it) @@ -1066,10 +1047,11 @@ int change_money(unit * u, int v) } static local_names *rnames; - +#define CB_BATCHSIZE 16 const resource_type *findresourcetype(const char *name, const struct locale *lang) { + const void * matches[CB_BATCHSIZE]; local_names *rn = rnames; variant token; @@ -1079,21 +1061,30 @@ const resource_type *findresourcetype(const char *name, rn = rn->next; } if (!rn) { - const resource_type *rtl = resourcetypes; - rn = calloc(sizeof(local_names), 1); + int m, offset = 0; + rn = (local_names *)calloc(1, sizeof(local_names)); rn->next = rnames; rn->lang = lang; - while (rtl) { - token.v = (void *)rtl; - addtoken(&rn->names, locale_string(lang, rtl->_name[0]), token); - addtoken(&rn->names, locale_string(lang, rtl->_name[1]), token); - rtl = rtl->next; - } + do { + m = cb_find_prefix(&cb_resources, "", 1, matches, CB_BATCHSIZE, offset); + if (m) { + int i; + offset += m; + for (i=0;i!=m;++i) { + resource_type *rtype; + cb_get_kv(matches[i], &rtype, sizeof(rtype)); + token.v = (void *)rtype; + addtoken(&rn->names, locale_string(lang, rtype->_name[0]), token); + addtoken(&rn->names, locale_string(lang, rtype->_name[1]), token); + } + } + } while (m==CB_BATCHSIZE); rnames = rn; } - if (findtoken(rn->names, name, &token) == E_TOK_NOMATCH) - return NULL; + if (findtoken(rn->names, name, &token) == E_TOK_NOMATCH) { + return 0; + } return (const resource_type *)token.v; } @@ -1103,64 +1094,43 @@ attrib_type at_showitem = { static local_names *inames; -void init_itemnames(void) -{ - int i; - for (i = 0; localenames[i]; ++i) { - const struct locale *lang = find_locale(localenames[i]); - boolean exist = false; - local_names *in = inames; - - while (in != NULL) { - if (in->lang == lang) { - exist = true; - break; - } - in = in->next; - } - if (in == NULL) - in = calloc(sizeof(local_names), 1); - in->next = inames; - in->lang = lang; - - if (!exist) { - int key; - for (key = 0; key != IMAXHASH; ++key) { - const item_type *itl; - for (itl = itemtypes[key]; itl; itl = itl->next) { - variant var; - const char *iname = locale_string(lang, itl->rtype->_name[0]); - if (findtoken(in->names, iname, &var) == E_TOK_NOMATCH - || var.v != itl) { - var.v = (void *)itl; - addtoken(&in->names, iname, var); - addtoken(&in->names, locale_string(lang, itl->rtype->_name[1]), - var); - } - } - } - } - inames = in; - } -} - const item_type *finditemtype(const char *name, const struct locale *lang) { + const void * matches[CB_BATCHSIZE]; local_names *in = inames; - variant var; + variant token; - while (in != NULL) { + while (in) { if (in->lang == lang) break; in = in->next; } - if (in == NULL) { - init_itemnames(); - for (in = inames; in->lang != lang; in = in->next) ; + if (!in) { + int m, offset = 0; + in = (local_names *)calloc(1, sizeof(local_names)); + in->next = inames; + in->lang = lang; + do { + m = cb_find_prefix(&cb_items, "", 1, matches, CB_BATCHSIZE, offset); + if (m) { + int i; + offset += m; + for (i=0;i!=m;++i) { + item_type *itype; + cb_get_kv(matches[i], &itype, sizeof(itype)); + token.v = (void *)itype; + addtoken(&in->names, locale_string(lang, itype->rtype->_name[0]), token); + addtoken(&in->names, locale_string(lang, itype->rtype->_name[1]), token); + } + } + } while (m==CB_BATCHSIZE); + inames = in; } - if (findtoken(in->names, name, &var) == E_TOK_NOMATCH) - return NULL; - return (const item_type *)var.v; + + if (findtoken(in->names, name, &token) == E_TOK_NOMATCH) { + return 0; + } + return (const item_type *)token.v; } static void init_resourcelimit(attrib * a) @@ -1197,31 +1167,38 @@ static item *default_spoil(const struct race *rc, int size) } #ifndef DISABLE_TESTS +int free_itype_cb(const void * match, const void * key, size_t keylen, void *cbdata) { + item_type *itype; + cb_get_kv(match, &itype, sizeof(itype)); + free(itype->construction); + free(itype); + return 0; +} + +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)); + free(rtype->_name[0]); + free(rtype->_name[1]); + free(rtype->_appearance[0]); + free(rtype->_appearance[1]); + free(rtype); + return 0; +} + void test_clear_resources(void) { - int i; + memset((void *)olditemtype, 0, sizeof(olditemtype)); + memset((void *)oldresourcetype, 0, sizeof(oldresourcetype)); + memset((void *)oldpotiontype, 0, sizeof(oldpotiontype)); - for (i=0;i!=IMAXHASH;++i) { - item_type * itype = itemtypes[i]; - if (itype) { - itemtypes[i] = 0; - free(itype->construction); - free(itype); - } - } + cb_foreach(&cb_items, "", 0, free_itype_cb, 0); + cb_clear(&cb_items); + cb_foreach(&cb_resources, "", 0, free_rtype_cb, 0); + cb_clear(&cb_resources); - while (resourcetypes) { - resource_type * rtype = resourcetypes; - resourcetypes = rtype->next; - free(rtype->_name[0]); - free(rtype->_name[1]); - free(rtype->_appearance[0]); - free(rtype->_appearance[1]); - free(rtype); - } - resourcetypes = 0; - r_hp = 0; - init_resources(); + r_hp = r_silver = r_aura = r_permaura = r_unit = 0; + i_silver = 0; } #endif diff --git a/src/kernel/item.h b/src/kernel/item.h index b08ff2b35..7f70f57c8 100644 --- a/src/kernel/item.h +++ b/src/kernel/item.h @@ -69,15 +69,13 @@ extern "C" { rtype_name name; /* --- pointers --- */ struct attrib *attribs; - struct resource_type *next; - unsigned int hashkey; struct item_type *itype; struct potion_type *ptype; struct luxury_type *ltype; struct weapon_type *wtype; struct armor_type *atype; } resource_type; - extern resource_type *resourcetypes; + extern const char *resourcename(const resource_type * rtype, int flags); extern const resource_type *findresourcetype(const char *name, const struct locale *lang); @@ -142,12 +140,9 @@ extern "C" { #if SCORE_MODULE int score; #endif - struct item_type *next; } item_type; - extern const item_type *finditemtype(const char *name, - const struct locale *lang); - extern void init_itemnames(void); + extern const item_type *finditemtype(const char *name, const struct locale *lang); typedef struct luxury_type { struct luxury_type *next; diff --git a/src/kernel/item_test.c b/src/kernel/item_test.c index 90a668386..4ce7d8bf9 100644 --- a/src/kernel/item_test.c +++ b/src/kernel/item_test.c @@ -7,19 +7,19 @@ void test_resource_type(CuTest * tc) { - resource_type *rtype, *rherp; + resource_type *rtype; const char *names[2] = { 0 , 0 }; CuAssertPtrEquals(tc, 0, rt_find("herpderp")); names[0] = "herpderp"; - rtype = new_resourcetype(names, NULL, RTF_NONE); + new_resourcetype(names, NULL, RTF_NONE); names[0] = "herp"; - rherp = new_resourcetype(names, NULL, RTF_NONE); - names[0] = "herpes"; rtype = new_resourcetype(names, NULL, RTF_NONE); + names[0] = "herpes"; + new_resourcetype(names, NULL, RTF_NONE); - CuAssertPtrEquals(tc, rherp, rt_find("herp")); + CuAssertPtrEquals(tc, rtype, rt_find("herp")); } CuSuite *get_item_suite(void) diff --git a/src/tests.c b/src/tests.c index 6b3ac59d1..3da1d8096 100644 --- a/src/tests.c +++ b/src/tests.c @@ -4,6 +4,7 @@ #include #include "tests.h" +#include "tests_test.c" #include #include #include @@ -38,22 +39,26 @@ int RunAllTests(void) int flags = log_flags; log_flags = LOG_FLUSH | LOG_CPERROR; - init_resources(); + /* self-test */ + CuSuiteAddSuite(suite, get_tests_suite()); + /* util */ CuSuiteAddSuite(suite, get_base36_suite()); CuSuiteAddSuite(suite, get_quicklist_suite()); CuSuiteAddSuite(suite, get_functions_suite()); CuSuiteAddSuite(suite, get_umlaut_suite()); + /* kernel */ CuSuiteAddSuite(suite, get_curse_suite()); - CuSuiteAddSuite(suite, get_market_suite()); CuSuiteAddSuite(suite, get_item_suite()); CuSuiteAddSuite(suite, get_move_suite()); CuSuiteAddSuite(suite, get_reports_suite()); CuSuiteAddSuite(suite, get_ship_suite()); CuSuiteAddSuite(suite, get_building_suite()); CuSuiteAddSuite(suite, get_spell_suite()); - CuSuiteAddSuite(suite, get_laws_suite()); CuSuiteAddSuite(suite, get_battle_suite()); + /* gamecode */ + CuSuiteAddSuite(suite, get_market_suite()); + CuSuiteAddSuite(suite, get_laws_suite()); CuSuiteRun(suite); CuSuiteSummary(suite, output); @@ -157,9 +162,12 @@ void test_create_world(void) building_type *btype; ship_type *stype; item_type * itype; - const char * names[2] = { "horse", "horse_p" }; + const char * horses[2] = { "horse", "horse_p" }; - itype = test_create_itemtype(names); + init_resources(); + assert(!olditemtype[I_HORSE]); + + itype = test_create_itemtype(horses); olditemtype[I_HORSE] = itype; t_plain = test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION); diff --git a/src/tests_test.c b/src/tests_test.c new file mode 100644 index 000000000..65c678e14 --- /dev/null +++ b/src/tests_test.c @@ -0,0 +1,26 @@ +#include +#include + +#include + +static void test_recreate_world(CuTest * tc) +{ + test_cleanup(); + CuAssertPtrEquals(tc, 0, it_find("money")); + CuAssertPtrEquals(tc, 0, it_find("horse")); + test_create_world(); + CuAssertPtrNotNull(tc, it_find("money")); + CuAssertPtrNotNull(tc, it_find("horse")); + CuAssertPtrNotNull(tc, findregion(0, 0)); + test_cleanup(); + CuAssertPtrEquals(tc, 0, it_find("money")); + CuAssertPtrEquals(tc, 0, it_find("horse")); + CuAssertPtrEquals(tc, 0, findregion(0, 0)); +} + +CuSuite *get_tests_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_recreate_world); + return suite; +} diff --git a/src/util/critbit.c b/src/util/critbit.c index a4e55950b..cd902d6ee 100644 --- a/src/util/critbit.c +++ b/src/util/critbit.c @@ -85,6 +85,7 @@ void cb_clear(critbit_tree * cb) { if (cb->root) { cb_free_node(cb->root); + cb->root = 0; } } @@ -166,6 +167,36 @@ int cb_insert(critbit_tree * cb, const void * key, size_t keylen) } } +static void * cb_find_top_i(critbit_tree * cb, const void * key, size_t keylen) +{ + void *ptr, *top = 0; + assert(key); + + if (!cb->root) { + return 0; + } + for (ptr=cb->root, top=cb->root;;) { + void * last = ptr; + if (decode_pointer(&ptr)==INTERNAL_NODE) { + struct critbit_node * node = (struct critbit_node *)ptr; + int branch; + if (keylen<=node->byte) { + break; + } else { + unsigned char * bytes = (unsigned char *)key; + top = last; + branch = (1+((bytes[node->byte]|node->mask)&0xFF))>>8; + ptr = node->child[branch]; + } + } else { + /* we reached an external node before exhausting the key length */ + top = last; + break; + } + } + return top; +} + static int cb_find_prefix_i(void * ptr, const void * key, size_t keylen, const void ** results, int numresults, int * offset, int next) { assert(next<=numresults); @@ -196,34 +227,45 @@ static int cb_find_prefix_i(void * ptr, const void * key, size_t keylen, const v int cb_find_prefix(critbit_tree * cb, const void * key, size_t keylen, const void ** results, int numresults, int offset) { - void *ptr, *top = 0; - assert(key); - - if (!cb->root || !numresults) { - return 0; - } - for (ptr=cb->root, top=cb->root;;) { - void * last = ptr; - if (decode_pointer(&ptr)==INTERNAL_NODE) { - struct critbit_node * node = (struct critbit_node *)ptr; - int branch; - if (keylen<=node->byte) { - break; - } else { - unsigned char * bytes = (unsigned char *)key; - top = last; - branch = (1+((bytes[node->byte]|node->mask)&0xFF))>>8; - ptr = node->child[branch]; - } - } else { - /* we reached an external node before exhausting the key length */ - top = last; - break; + if (numresults>0) { + void *top = cb_find_top_i(cb, key, keylen); + if (top) { + /* recursively add all children except the ones from [0-offset) of top to the results */ + return cb_find_prefix_i(top, key, keylen, results, numresults, &offset, 0); } } + return 0; +} + +static int cb_foreach_i(void * ptr, const void * key, size_t keylen, int (*match_cb)(const void * match, const void * key, size_t keylen, void *), void *data) +{ + int result = 0; + + if (decode_pointer(&ptr)==INTERNAL_NODE) { + struct critbit_node * node = (struct critbit_node *)ptr; + result = cb_foreach_i(node->child[0], key, keylen, match_cb, data); + if (!result) { + result = cb_foreach_i(node->child[1], key, keylen, match_cb, data); + } + } else { + /* reached an external node */ + void * match; + size_t len; + + from_external_node(ptr, &match, &len); + if (len>=keylen && memcmp(key, match, keylen)==0) { + return match_cb(match, key, keylen, data); + } + } + return result; +} + +int cb_foreach(critbit_tree * cb, const void * key, size_t keylen, int (*match_cb)(const void * match, const void * key, size_t keylen, void *), void *data) +{ + void *top = cb_find_top_i(cb, key, keylen); if (top) { /* recursively add all children except the ones from [0-offset) of top to the results */ - return cb_find_prefix_i(top, key, keylen, results, numresults, &offset, 0); + return cb_foreach_i(top, key, keylen, match_cb, data); } return 0; } diff --git a/src/util/critbit.h b/src/util/critbit.h index 9240c582d..0d9c11c89 100644 --- a/src/util/critbit.h +++ b/src/util/critbit.h @@ -35,6 +35,7 @@ int cb_insert(critbit_tree * cb, const void * key, size_t keylen); const void * cb_find(critbit_tree * cb, const void * key, size_t keylen); int cb_erase(critbit_tree * cb, const void * key, size_t keylen); int cb_find_prefix(critbit_tree * cb, const void * key, size_t keylen, const void ** results, int numresults, int offset); +int cb_foreach(critbit_tree * cb, const void * key, size_t keylen, int (*match_cb)(const void * match, const void * key, size_t keylen, void *), void *data); void cb_clear(critbit_tree * cb); #define cb_insert_str(cb, key) \ From b44737387ab8f6a16204a5d227d4315f7ec71234 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 19 May 2012 20:49:47 +0200 Subject: [PATCH 215/400] fix broken tests and clear locales (badly) when clearing global stte --- src/kernel/item_test.c | 6 +++--- src/tests.c | 3 +++ src/tests_test.c | 4 ++++ src/util/language.c | 8 +++++++- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/kernel/item_test.c b/src/kernel/item_test.c index 4ce7d8bf9..f12845ab4 100644 --- a/src/kernel/item_test.c +++ b/src/kernel/item_test.c @@ -12,11 +12,11 @@ void test_resource_type(CuTest * tc) CuAssertPtrEquals(tc, 0, rt_find("herpderp")); - names[0] = "herpderp"; + names[0] = names[1] = "herpderp"; new_resourcetype(names, NULL, RTF_NONE); - names[0] = "herp"; + names[0] = names[1] = "herp"; rtype = new_resourcetype(names, NULL, RTF_NONE); - names[0] = "herpes"; + names[0] = names[1] = "herpes"; new_resourcetype(names, NULL, RTF_NONE); CuAssertPtrEquals(tc, rtype, rt_find("herp")); diff --git a/src/tests.c b/src/tests.c index 3da1d8096..ab345bd88 100644 --- a/src/tests.c +++ b/src/tests.c @@ -107,6 +107,8 @@ void test_cleanup(void) test_clear_resources(); global.functions.maintenance = NULL; global.functions.wage = NULL; + default_locale = 0; + locales = 0; /* TODO: this is evil and leaky */ free_gamedata(); } @@ -164,6 +166,7 @@ void test_create_world(void) item_type * itype; const char * horses[2] = { "horse", "horse_p" }; + make_locale("de"); init_resources(); assert(!olditemtype[I_HORSE]); diff --git a/src/tests_test.c b/src/tests_test.c index 65c678e14..3f8a65513 100644 --- a/src/tests_test.c +++ b/src/tests_test.c @@ -6,13 +6,17 @@ static void test_recreate_world(CuTest * tc) { test_cleanup(); + CuAssertPtrEquals(tc, 0, find_locale("de")); CuAssertPtrEquals(tc, 0, it_find("money")); CuAssertPtrEquals(tc, 0, it_find("horse")); test_create_world(); + CuAssertPtrEquals(tc, default_locale, find_locale("de")); + CuAssertPtrNotNull(tc, default_locale); CuAssertPtrNotNull(tc, it_find("money")); CuAssertPtrNotNull(tc, it_find("horse")); CuAssertPtrNotNull(tc, findregion(0, 0)); test_cleanup(); + CuAssertPtrEquals(tc, 0, find_locale("de")); CuAssertPtrEquals(tc, 0, it_find("money")); CuAssertPtrEquals(tc, 0, it_find("horse")); CuAssertPtrEquals(tc, 0, findregion(0, 0)); diff --git a/src/util/language.c b/src/util/language.c index 9bb36cd2d..2af939234 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -57,6 +57,10 @@ locale *make_locale(const char *name) locale *l = (locale *) calloc(sizeof(locale), 1); locale **lp = &locales; + if (!locales) { + nextlocaleindex = 0; + } + while (*lp && (*lp)->hashkey != hkey) lp = &(*lp)->next; if (*lp) { @@ -164,8 +168,10 @@ void locale_setstring(locale * lang, const char *key, const char *value) unsigned int hkey = hashstring(key); unsigned int id = hkey & (SMAXHASH - 1); struct locale_str *find; - if (lang == NULL) + if (!lang) { lang = default_locale; + } + assert(lang); find = lang->strings[id]; while (find) { if (find->hashkey == hkey && strcmp(key, find->key) == 0) From 71f1e35f6d6a5d35f91a4d2862ef6d0e432696fb Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 19 May 2012 13:10:19 -0700 Subject: [PATCH 216/400] fix an odd edge-case where there is only a byte left in the destination string, but we're parsing a utf8 character. --- src/util/umlaut.c | 7 +++---- src/util/umlaut_test.c | 9 ++++++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/util/umlaut.c b/src/util/umlaut.c index d1063b6d4..81f356a14 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -57,8 +57,8 @@ char * transliterate(char * out, size_t size, const char * in) } len = src-p; size -= len; - while (size>=2 && *src && (*src & 0x80)) { - int advance = 2; + while (size>0 && *src && (*src & 0x80)) { + unsigned int advance = 2; if (src[0]=='\xc3') { if (src[1]=='\xa4' || src[1]=='\x84') { memcpy(dst, "ae", 2); @@ -69,7 +69,6 @@ char * transliterate(char * out, size_t size, const char * in) } else if (src[1]=='\x9f') { memcpy(dst, "ss", 2); } else { - *dst++='?'; advance = 0; } } else if (src[0]=='\xe1') { @@ -83,7 +82,7 @@ char * transliterate(char * out, size_t size, const char * in) advance = 0; } - if (advance) { + if (advance && advance<=size) { src+=advance; dst+=advance; size-=advance; diff --git a/src/util/umlaut_test.c b/src/util/umlaut_test.c index 2b2b4e4e5..518c63930 100644 --- a/src/util/umlaut_test.c +++ b/src/util/umlaut_test.c @@ -16,7 +16,14 @@ static void test_transliterate(CuTest * tc) CuAssertStrEquals(tc, "haerpdaerp", transliterate(buffer, sizeof(buffer), "h\xc3\xa4rpd\xc3\xa4rp")); CuAssertStrEquals(tc, "aeoeuess", transliterate(buffer, sizeof(buffer), "\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x9f")); CuAssertStrEquals(tc, "aeoeuess", transliterate(buffer, sizeof(buffer), "\xc3\x84\xc3\x96\xc3\x9c\xe1\xba\x9e")); - CuAssertStrEquals(tc, 0, transliterate(buffer, 4, "herpderp")); + + /* handle buffer that is too small */ + CuAssertStrEquals(tc, 0, transliterate(buffer, 1, "herpderp")); + CuAssertStrEquals(tc, "", buffer); + CuAssertStrEquals(tc, 0, transliterate(buffer, 3, "herpderp")); + CuAssertStrEquals(tc, "he", buffer); + CuAssertStrEquals(tc, 0, transliterate(buffer, 3, "h\xc3\xa4rpd\xc3\xa4rp")); + CuAssertStrEquals(tc, "h?", buffer); } static void test_umlaut(CuTest * tc) From c8c1d8c27d1d2bd14a6ef5bf54319b90207df25c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 19 May 2012 13:10:19 -0700 Subject: [PATCH 217/400] fix an odd edge-case where there is only a byte left in the destination string, but we're parsing a utf8 character. --- src/util/umlaut.c | 7 +++---- src/util/umlaut_test.c | 9 ++++++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/util/umlaut.c b/src/util/umlaut.c index d1063b6d4..81f356a14 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -57,8 +57,8 @@ char * transliterate(char * out, size_t size, const char * in) } len = src-p; size -= len; - while (size>=2 && *src && (*src & 0x80)) { - int advance = 2; + while (size>0 && *src && (*src & 0x80)) { + unsigned int advance = 2; if (src[0]=='\xc3') { if (src[1]=='\xa4' || src[1]=='\x84') { memcpy(dst, "ae", 2); @@ -69,7 +69,6 @@ char * transliterate(char * out, size_t size, const char * in) } else if (src[1]=='\x9f') { memcpy(dst, "ss", 2); } else { - *dst++='?'; advance = 0; } } else if (src[0]=='\xe1') { @@ -83,7 +82,7 @@ char * transliterate(char * out, size_t size, const char * in) advance = 0; } - if (advance) { + if (advance && advance<=size) { src+=advance; dst+=advance; size-=advance; diff --git a/src/util/umlaut_test.c b/src/util/umlaut_test.c index 2b2b4e4e5..518c63930 100644 --- a/src/util/umlaut_test.c +++ b/src/util/umlaut_test.c @@ -16,7 +16,14 @@ static void test_transliterate(CuTest * tc) CuAssertStrEquals(tc, "haerpdaerp", transliterate(buffer, sizeof(buffer), "h\xc3\xa4rpd\xc3\xa4rp")); CuAssertStrEquals(tc, "aeoeuess", transliterate(buffer, sizeof(buffer), "\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x9f")); CuAssertStrEquals(tc, "aeoeuess", transliterate(buffer, sizeof(buffer), "\xc3\x84\xc3\x96\xc3\x9c\xe1\xba\x9e")); - CuAssertStrEquals(tc, 0, transliterate(buffer, 4, "herpderp")); + + /* handle buffer that is too small */ + CuAssertStrEquals(tc, 0, transliterate(buffer, 1, "herpderp")); + CuAssertStrEquals(tc, "", buffer); + CuAssertStrEquals(tc, 0, transliterate(buffer, 3, "herpderp")); + CuAssertStrEquals(tc, "he", buffer); + CuAssertStrEquals(tc, 0, transliterate(buffer, 3, "h\xc3\xa4rpd\xc3\xa4rp")); + CuAssertStrEquals(tc, "h?", buffer); } static void test_umlaut(CuTest * tc) From b57db72396a37df7345ca882498e201b53c5c208 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 19 May 2012 20:49:47 +0200 Subject: [PATCH 218/400] fix broken tests and clear locales (badly) when clearing global stte --- src/kernel/item_test.c | 30 ++++++++++++++++++++++++++++++ src/tests.c | 10 ++++++++-- src/tests_test.c | 30 ++++++++++++++++++++++++++++++ src/util/language.c | 8 +++++++- 4 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 src/kernel/item_test.c create mode 100644 src/tests_test.c diff --git a/src/kernel/item_test.c b/src/kernel/item_test.c new file mode 100644 index 000000000..f12845ab4 --- /dev/null +++ b/src/kernel/item_test.c @@ -0,0 +1,30 @@ +#include + +#include + +#include +#include + +void test_resource_type(CuTest * tc) +{ + resource_type *rtype; + const char *names[2] = { 0 , 0 }; + + CuAssertPtrEquals(tc, 0, rt_find("herpderp")); + + names[0] = names[1] = "herpderp"; + new_resourcetype(names, NULL, RTF_NONE); + names[0] = names[1] = "herp"; + rtype = new_resourcetype(names, NULL, RTF_NONE); + names[0] = names[1] = "herpes"; + new_resourcetype(names, NULL, RTF_NONE); + + CuAssertPtrEquals(tc, rtype, rt_find("herp")); +} + +CuSuite *get_item_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_resource_type); + return suite; +} diff --git a/src/tests.c b/src/tests.c index 193f3553a..f0d88806f 100644 --- a/src/tests.c +++ b/src/tests.c @@ -100,6 +100,8 @@ void test_cleanup(void) test_clear_resources(); global.functions.maintenance = NULL; global.functions.wage = NULL; + default_locale = 0; + locales = 0; /* TODO: this is evil and leaky */ free_gamedata(); } @@ -155,9 +157,13 @@ void test_create_world(void) building_type *btype; ship_type *stype; item_type * itype; - const char * names[2] = { "horse", "horse_p" }; + const char * horses[2] = { "horse", "horse_p" }; - itype = test_create_itemtype(names); + make_locale("de"); + init_resources(); + assert(!olditemtype[I_HORSE]); + + itype = test_create_itemtype(horses); olditemtype[I_HORSE] = itype; t_plain = test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION); diff --git a/src/tests_test.c b/src/tests_test.c new file mode 100644 index 000000000..3f8a65513 --- /dev/null +++ b/src/tests_test.c @@ -0,0 +1,30 @@ +#include +#include + +#include + +static void test_recreate_world(CuTest * tc) +{ + test_cleanup(); + CuAssertPtrEquals(tc, 0, find_locale("de")); + CuAssertPtrEquals(tc, 0, it_find("money")); + CuAssertPtrEquals(tc, 0, it_find("horse")); + test_create_world(); + CuAssertPtrEquals(tc, default_locale, find_locale("de")); + CuAssertPtrNotNull(tc, default_locale); + CuAssertPtrNotNull(tc, it_find("money")); + CuAssertPtrNotNull(tc, it_find("horse")); + CuAssertPtrNotNull(tc, findregion(0, 0)); + test_cleanup(); + CuAssertPtrEquals(tc, 0, find_locale("de")); + CuAssertPtrEquals(tc, 0, it_find("money")); + CuAssertPtrEquals(tc, 0, it_find("horse")); + CuAssertPtrEquals(tc, 0, findregion(0, 0)); +} + +CuSuite *get_tests_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_recreate_world); + return suite; +} diff --git a/src/util/language.c b/src/util/language.c index 9bb36cd2d..2af939234 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -57,6 +57,10 @@ locale *make_locale(const char *name) locale *l = (locale *) calloc(sizeof(locale), 1); locale **lp = &locales; + if (!locales) { + nextlocaleindex = 0; + } + while (*lp && (*lp)->hashkey != hkey) lp = &(*lp)->next; if (*lp) { @@ -164,8 +168,10 @@ void locale_setstring(locale * lang, const char *key, const char *value) unsigned int hkey = hashstring(key); unsigned int id = hkey & (SMAXHASH - 1); struct locale_str *find; - if (lang == NULL) + if (!lang) { lang = default_locale; + } + assert(lang); find = lang->strings[id]; while (find) { if (find->hashkey == hkey && strcmp(key, find->key) == 0) From ee2709e021339a5a93c7e8d5439c1e700c71395b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 19 May 2012 22:30:57 +0200 Subject: [PATCH 219/400] fix tests --- src/gamecode/market_test.c | 37 +++++++++++++++++++++++-------------- src/kernel/item.c | 4 ++++ 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/gamecode/market_test.c b/src/gamecode/market_test.c index 1e7eefb8e..985538368 100644 --- a/src/gamecode/market_test.c +++ b/src/gamecode/market_test.c @@ -18,7 +18,7 @@ #include -static void market_curse(CuTest * tc) +static void test_market_curse(CuTest * tc) { region *r; building *b; @@ -26,16 +26,21 @@ static void market_curse(CuTest * tc) faction *f; int x, y; const char *names[4] = { "herb", "herbs", "balm", "balms" }; - terrain_type *terrain; - resource_type *hres = new_resourcetype(names, 0, RTF_ITEM | RTF_POOLED); - item_type *htype = new_itemtype(hres, ITF_HERB, 0, 0); - resource_type *lres = new_resourcetype(names + 2, 0, RTF_ITEM | RTF_POOLED); - item_type *ltype = new_itemtype(lres, ITF_NONE, 0, 0); - luxury_type *lux = new_luxurytype(ltype, 0); + const terrain_type *terrain; + resource_type *hres, *lres; + item_type *htype, *ltype; + luxury_type *lux; building_type *btype; - race *rc = rc_add(rc_new("human")); free_gamedata(); + test_cleanup(); + test_create_world(); + + hres = new_resourcetype(names, 0, RTF_ITEM | RTF_POOLED); + htype = new_itemtype(hres, ITF_HERB, 0, 0); + lres = new_resourcetype(names + 2, 0, RTF_ITEM | RTF_POOLED); + ltype = new_itemtype(lres, ITF_NONE, 0, 0); + lux = new_luxurytype(ltype, 0); set_param(&global.parameters, "rules.region_owners", "1"); @@ -43,12 +48,16 @@ static void market_curse(CuTest * tc) btype->_name = "market"; bt_register(btype); - terrain = test_create_terrain("plain", LAND_REGION | WALK_INTO); + terrain = get_terrain("plain"); for (x = 0; x != 3; ++x) { for (y = 0; y != 3; ++y) { - r = new_region(x, y, NULL, 0); - terraform_region(r, terrain); + r = findregion(x, y); + if (!r) { + r = test_create_region(x, y, terrain); + } else { + terraform_region(r, terrain); + } rsetpeasants(r, 5000); r_setdemand(r, lux, 0); rsetherbtype(r, htype); @@ -59,8 +68,8 @@ static void market_curse(CuTest * tc) b->flags |= BLD_WORKING; b->size = b->type->maxsize; - f = addfaction("nobody@eressea.de", NULL, rc, default_locale, 0); - u = create_unit(r, f, 1, f->race, 0, 0, 0); + f = test_create_faction(0); + u = test_create_unit(f, r); u_set_building(u, b); do_markets(); @@ -72,6 +81,6 @@ static void market_curse(CuTest * tc) CuSuite *get_market_suite(void) { CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, market_curse); + SUITE_ADD_TEST(suite, test_market_curse); return suite; } diff --git a/src/kernel/item.c b/src/kernel/item.c index 387112f71..c06a603e1 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -1201,6 +1201,10 @@ void test_clear_resources(void) { int i; + memset((void *)olditemtype, 0, sizeof(olditemtype)); + memset((void *)oldresourcetype, 0, sizeof(oldresourcetype)); + memset((void *)oldpotiontype, 0, sizeof(oldpotiontype)); + for (i=0;i!=IMAXHASH;++i) { item_type * itype = itemtypes[i]; if (itype) { From 0fc37c9c59dac400d7df8197c3beffe567783b28 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 19 May 2012 16:54:19 -0700 Subject: [PATCH 220/400] complain properly when the orders are not readable! --- src/kernel/save.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/kernel/save.c b/src/kernel/save.c index 4dc41d37f..326e12188 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -387,10 +387,12 @@ int readorders(const char *filename) int nfactions = 0; struct faction *f = NULL; - if (filename) + if (filename) { F = cfopen(filename, "rb"); - if (F == NULL) - return 0; + } + if (!F) { + return -1; + } if (verbosity >= 1) puts(" - lese Befehlsdatei...\n"); From 671e976ad6f0faeced57635519f6eb75e4d7ce44 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 19 May 2012 16:54:41 -0700 Subject: [PATCH 221/400] Nobody needs to see empty messages in the CR --- src/gamecode/creport.c | 4 ++-- src/kernel/message.h | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index 8c63cd9e3..189645ffd 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -522,10 +522,10 @@ static void render_messages(FILE * F, faction * f, message_list * msgs) #endif crbuffer[0] = '\0'; if (cr_render(m->msg, crbuffer, (const void *)f) == 0) { - if (!printed) + if (crbuffer[0] && !printed) { fprintf(F, "MESSAGE %u\n", messagehash(m->msg)); - if (crbuffer[0]) fputs(crbuffer, F); + } } else { log_error("could not render cr-message %p: %s\n", m->msg, m->msg->type->name); } diff --git a/src/kernel/message.h b/src/kernel/message.h index 2623df169..e860bd996 100644 --- a/src/kernel/message.h +++ b/src/kernel/message.h @@ -30,11 +30,13 @@ extern "C" { struct message_type; + typedef struct mlist { + struct mlist *next; + struct message *msg; + }; + typedef struct message_list { - struct mlist { - struct mlist *next; - struct message *msg; - } *begin, **end; + struct mlist *begin, **end; } message_list; extern void free_messagelist(message_list * msgs); From a8a8dfbbb6cb3a34409ec687c71f19ce19157fc4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 19 May 2012 16:55:03 -0700 Subject: [PATCH 222/400] registering item types is hard. --- src/kernel/item.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/kernel/item.c b/src/kernel/item.c index 25c32fe14..8bc425078 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -159,7 +159,6 @@ resource_type *new_resourcetype(const char **names, const char **appearances, else rtype->_appearance[i] = NULL; } - rt_register(rtype); } #ifndef NDEBUG else { @@ -193,6 +192,7 @@ item_type *new_itemtype(resource_type * rtype, itype = calloc(sizeof(item_type), 1); itype->rtype = rtype; + rtype->itype = itype; itype->weight = weight; itype->capacity = capacity; itype->flags |= iflags; @@ -974,22 +974,25 @@ void init_resources(void) i_silver = new_itemtype(r_silver, ITF_NONE, 1 /*weight */ , 0); r_silver->uchange = res_changeitem; i_silver->give = give_money; + oldresourcetype[R_SILVER] = r_silver; r_permaura = new_resourcetype(&names[4], NULL, RTF_NONE); r_permaura->uchange = res_changepermaura; + rt_register(r_permaura); + oldresourcetype[R_PERMAURA] = r_permaura; r_hp = new_resourcetype(&names[6], NULL, RTF_NONE); r_hp->uchange = res_changehp; + rt_register(r_hp); r_aura = new_resourcetype(&names[10], NULL, RTF_NONE); r_aura->uchange = res_changeaura; + rt_register(r_aura); + oldresourcetype[R_AURA] = r_aura; r_unit = new_resourcetype(&names[12], NULL, RTF_NONE); r_unit->uchange = res_changeperson; - - oldresourcetype[R_SILVER] = r_silver; - oldresourcetype[R_AURA] = r_aura; - oldresourcetype[R_PERMAURA] = r_permaura; + rt_register(r_unit); /* alte typen registrieren: */ init_olditems(); From a342e846bc08c15e62121c431842410d8800a80b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 19 May 2012 17:23:57 -0700 Subject: [PATCH 223/400] improved some tests fixed some resource-related things, especially registration --- src/gamecode/market_test.c | 13 +++++++------ src/kernel/item.c | 5 +++++ src/kernel/item.h | 3 +++ src/kernel/item_test.c | 18 +++++++++++------- src/kernel/xmlreader.c | 7 ++++--- src/tests.h | 1 + 6 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/gamecode/market_test.c b/src/gamecode/market_test.c index 985538368..69726b9eb 100644 --- a/src/gamecode/market_test.c +++ b/src/gamecode/market_test.c @@ -27,7 +27,6 @@ static void test_market_curse(CuTest * tc) int x, y; const char *names[4] = { "herb", "herbs", "balm", "balms" }; const terrain_type *terrain; - resource_type *hres, *lres; item_type *htype, *ltype; luxury_type *lux; building_type *btype; @@ -36,15 +35,17 @@ static void test_market_curse(CuTest * tc) test_cleanup(); test_create_world(); - hres = new_resourcetype(names, 0, RTF_ITEM | RTF_POOLED); - htype = new_itemtype(hres, ITF_HERB, 0, 0); - lres = new_resourcetype(names + 2, 0, RTF_ITEM | RTF_POOLED); - ltype = new_itemtype(lres, ITF_NONE, 0, 0); + htype = test_create_itemtype(names); + htype->flags |= ITF_HERB; + htype->rtype->flags |= (RTF_ITEM | RTF_POOLED); + + ltype = test_create_itemtype(names + 2); + ltype->rtype->flags |= (RTF_ITEM | RTF_POOLED); lux = new_luxurytype(ltype, 0); set_param(&global.parameters, "rules.region_owners", "1"); - btype = calloc(sizeof(building_type), 1); + btype = (building_type *)calloc(1, sizeof(building_type)); btype->_name = "market"; bt_register(btype); diff --git a/src/kernel/item.c b/src/kernel/item.c index 8bc425078..507fe1adf 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -965,10 +965,15 @@ static const char *names[] = { void init_resources(void) { + resource_type *rtype; if (r_hp) { return; } + rtype = new_resourcetype(names + 8, NULL, RTF_NONE); + rtype->uchange = res_changepeasants; + rt_register(rtype); + /* silver was never an item: */ r_silver = new_resourcetype(&names[0], NULL, RTF_ITEM | RTF_POOLED); i_silver = new_itemtype(r_silver, ITF_NONE, 1 /*weight */ , 0); diff --git a/src/kernel/item.h b/src/kernel/item.h index 7f70f57c8..6cace8e99 100644 --- a/src/kernel/item.h +++ b/src/kernel/item.h @@ -18,6 +18,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifndef H_KRNL_ITEM #define H_KRNL_ITEM + +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/src/kernel/item_test.c b/src/kernel/item_test.c index f12845ab4..98a8188a0 100644 --- a/src/kernel/item_test.c +++ b/src/kernel/item_test.c @@ -1,5 +1,6 @@ #include +#include #include #include @@ -7,19 +8,22 @@ void test_resource_type(CuTest * tc) { - resource_type *rtype; + struct item_type *itype; const char *names[2] = { 0 , 0 }; CuAssertPtrEquals(tc, 0, rt_find("herpderp")); names[0] = names[1] = "herpderp"; - new_resourcetype(names, NULL, RTF_NONE); - names[0] = names[1] = "herp"; - rtype = new_resourcetype(names, NULL, RTF_NONE); - names[0] = names[1] = "herpes"; - new_resourcetype(names, NULL, RTF_NONE); + test_create_itemtype(names); - CuAssertPtrEquals(tc, rtype, rt_find("herp")); + names[0] = names[1] = "herp"; + itype = test_create_itemtype(names); + + names[0] = names[1] = "herpes"; + test_create_itemtype(names); + + CuAssertPtrEquals(tc, itype, it_find("herp")); + CuAssertPtrEquals(tc, itype->rtype, rt_find("herp")); } CuSuite *get_item_suite(void) diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 8e488b115..e57176d6c 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -132,6 +132,7 @@ static const resource_type *rt_findorcreate(const char *name) names[0] = name; names[1] = namep; rtype = new_resourcetype(names, NULL, RTF_NONE); + rt_register(rtype); free(namep); } return rtype; @@ -1045,12 +1046,12 @@ static int parse_resources(xmlDocPtr doc) if (appearance) { appearances[0] = (const char *)appearance; appearances[1] = appearancep; - rtype = - new_resourcetype((const char **)names, (const char **)appearances, - flags); + rtype = new_resourcetype((const char **)names, (const char **)appearances, flags); + rt_register(rtype); free(appearancep); } else { rtype = new_resourcetype(names, NULL, flags); + rt_register(rtype); } free(namep); } diff --git a/src/tests.h b/src/tests.h index c35922c7c..29a75ac4f 100644 --- a/src/tests.h +++ b/src/tests.h @@ -16,6 +16,7 @@ extern "C" { void test_create_world(void); struct building * test_create_building(struct region * r, const struct building_type * btype); struct ship * test_create_ship(struct region * r, const struct ship_type * stype); + struct item_type * test_create_itemtype(const char ** names); int RunAllTests(void); #else #define RunAllTests() 0 From 3fa4a31d147add8d88406a2b460e8b3c484b3c20 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 20 May 2012 03:21:38 +0200 Subject: [PATCH 224/400] trying to figure out why some run_tests tests are not working --- scripts/tests/common.lua | 6 +++--- src/gamecode/report.c | 1 + src/kernel/message.h | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index fd7a92a32..0ae776197 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -471,11 +471,11 @@ function test_mallorn() process_orders() - assert(u1:get_item("log")==2) - assert(u2:get_item("log")==2) + assert_equal(2, u1:get_item("log")) + assert_equal(2, u2:get_item("log")) local mallorn_cfg = config.get_resource("mallorn") if mallorn_cfg then - assert(u3:get_item("mallorn")==1) + assert_equal(1, u3:get_item("mallorn")) else assert_equal(-1, u3:get_item("mallorn")) assert_equal(0, u3:get_item("log")) diff --git a/src/gamecode/report.c b/src/gamecode/report.c index e08b198d5..c1bd48acc 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -162,6 +162,7 @@ rparagraph(FILE * F, const char *str, ptrdiff_t indent, int hanging_indent, size_t length = REPORTWIDTH; const char *end, *begin; + if (!str) return; /* find out if there's a mark + indent already encoded in the string. */ if (!mark) { const char *x = str; diff --git a/src/kernel/message.h b/src/kernel/message.h index e860bd996..9820950be 100644 --- a/src/kernel/message.h +++ b/src/kernel/message.h @@ -33,7 +33,7 @@ extern "C" { typedef struct mlist { struct mlist *next; struct message *msg; - }; + } mlist; typedef struct message_list { struct mlist *begin, **end; From bcd69917034c0ebdc59addc77e27b16d6db0ecff Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 19 May 2012 18:50:28 -0700 Subject: [PATCH 225/400] testing spells is a lot easier when you can disable fumbles all tun_tests tests pass --- scripts/tests/spells.lua | 1 + src/kernel/item.c | 4 +++- src/kernel/magic.c | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/scripts/tests/spells.lua b/scripts/tests/spells.lua index bad60c192..b5278e5f1 100644 --- a/scripts/tests/spells.lua +++ b/scripts/tests/spells.lua @@ -4,6 +4,7 @@ module("tests.spells", package.seeall, lunit.testcase) function setup() free_game() + settings.set("magic.fumble.enable", "0") end function test_roi() diff --git a/src/kernel/item.c b/src/kernel/item.c index 507fe1adf..525693a3c 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -1119,7 +1119,7 @@ const item_type *finditemtype(const char *name, const struct locale *lang) in->next = inames; in->lang = lang; do { - m = cb_find_prefix(&cb_items, "", 1, matches, CB_BATCHSIZE, offset); + m = cb_find_prefix(&cb_items, "", 0, matches, CB_BATCHSIZE, offset); if (m) { int i; offset += m; @@ -1207,6 +1207,8 @@ void test_clear_resources(void) r_hp = r_silver = r_aura = r_permaura = r_unit = 0; i_silver = 0; + + inames = 0; /* TODO: this is a terrible hack, the whole inames global state must die */ } #endif diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 4f2ab435e..120760378 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -1314,7 +1314,11 @@ boolean fumble(region * r, unit * u, const spell * sp, int cast_grade) int patzer = (int)(((double)x * 40.0) - 20.0); struct building *b = inside_building(u); const struct building_type *btype = b ? b->type : NULL; + int fumble_enabled = get_param_int(global.parameters, "magic.fumble.enable", 1); + if (!fumble_enabled) { + return false; + } if (btype) patzer -= btype->fumblebonus; /* CHAOSPATZERCHANCE 10 : +10% Chance zu Patzern */ From cc9a815eea919b1daef77267e6f427cad6aa8e50 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 19 May 2012 19:54:14 -0700 Subject: [PATCH 226/400] remove another fintoken warning from the logs --- src/gamecode/laws.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index d2096ae9c..a0b150ab3 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -2567,7 +2567,7 @@ static int reshow_cmd(unit * u, struct order *ord) skip_token(); s = getstrtoken(); - if (findparam(s, u->faction->locale) == P_ANY) { + if (isparam(s, u->faction->locale, P_ANY)) { p = getparam(u->faction->locale); s = NULL; } From bcb01742ae0a3ee10028ac0e87ad2df42849646e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 19 May 2012 20:00:54 -0700 Subject: [PATCH 227/400] remove yet another fintoken warning from the logs --- src/gamecode/laws.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index a0b150ab3..f3204ff17 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -3755,7 +3755,7 @@ static int use_cmd(unit * u, struct order *ord) t = getstrtoken(); n = atoi((const char *)t); if (n == 0) { - if (findparam(t, u->faction->locale) == P_ANY) { + if (isparam(t, u->faction->locale, P_ANY)) { /* BENUTZE ALLES Yanxspirit */ n = INT_MAX; t = getstrtoken(); From c9902a1d257a16861478c063e15c1563f7ca61ef Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 19 May 2012 21:01:25 -0700 Subject: [PATCH 228/400] move error handling for use_cmd into a single location --- src/gamecode/laws.c | 31 ++++++++++++++++++------------- src/kernel/item.h | 8 ++++---- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index f3204ff17..47a0d0727 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -2473,9 +2473,8 @@ static void reshow(unit * u, struct order *ord, const char *s, param_t p) } /* last, check if it's a race. */ rc = findrace(s, u->faction->locale); - if (rc != NULL) { - if (display_race(u->faction, u, rc)) - break; + if (rc != NULL && display_race(u->faction, u, rc)) { + break; } cmistake(u, ord, 21, MSG_EVENT); break; @@ -3529,19 +3528,16 @@ use_item(unit * u, const item_type * itype, int amount, struct order *ord) amount = i; } if (amount == 0) { - cmistake(u, ord, 43, MSG_PRODUCE); return ENOITEM; } if (target == -1) { if (itype->use == NULL) { - cmistake(u, ord, 76, MSG_PRODUCE); return EUNUSABLE; } return itype->use(u, itype, amount, ord); } else { if (itype->useonother == NULL) { - cmistake(u, ord, 76, MSG_PRODUCE); return EUNUSABLE; } return itype->useonother(u, target, itype, amount, ord); @@ -3746,7 +3742,7 @@ static void age_factions(void) static int use_cmd(unit * u, struct order *ord) { const char *t; - int n; + int n, err = ENOITEM; const item_type *itype; init_tokens(ord); @@ -3770,15 +3766,24 @@ static int use_cmd(unit * u, struct order *ord) itype = finditemtype(t, u->faction->locale); if (itype != NULL) { - int i = use_item(u, itype, n, ord); - assert(i <= 0 || !"use_item should not return positive values."); - if (i > 0) { + err = use_item(u, itype, n, ord); + assert(err <= 0 || !"use_item should not return positive values."); + if (err > 0) { log_error("use_item returned a value>0 for %s\n", resourcename(itype->rtype, 0)); } - } else { - cmistake(u, ord, 43, MSG_PRODUCE); } - return 0; + switch (err) { + case ENOITEM: + cmistake(u, ord, 43, MSG_PRODUCE); + break; + case EUNUSABLE: + cmistake(u, ord, 76, MSG_PRODUCE); + break; + case ENOSKILL: + cmistake(u, ord, 50, MSG_PRODUCE); + break; + } + return err; } static int pay_cmd(unit * u, struct order *ord) diff --git a/src/kernel/item.h b/src/kernel/item.h index 6cace8e99..f470381a7 100644 --- a/src/kernel/item.h +++ b/src/kernel/item.h @@ -119,10 +119,10 @@ extern "C" { #define ITF_VEHICLE 0x0100 /* a vehicle, drawn by two animals */ /* error codes for item_type::use */ -#define ECUSTOM -1; -#define ENOITEM -2; -#define ENOSKILL -3; -#define EUNUSABLE -4; +#define ECUSTOM -1 +#define ENOITEM -2 +#define ENOSKILL -3 +#define EUNUSABLE -4 typedef struct item_type { resource_type *rtype; From c6559414c683c3e9161a8972aa99c62c9d10ed75 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 20 May 2012 06:54:59 +0200 Subject: [PATCH 229/400] fewer findparam calls are better --- src/gamecode/economy.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index e1eaaa217..b3a47409d 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -819,13 +819,14 @@ static void give_cmd(unit * u, order * ord) } else if (p == P_ANY) { - const char *s = getstrtoken(); + const char *s; if (!check_give(u, u2, NULL, GIVE_ALLITEMS)) { feedback_give_not_allowed(u, ord); return; } - if (*s == 0) { /* Alle Gegenstände übergeben */ + s = getstrtoken(); + if (*s == 0) { /* GIVE ALL items that you have */ /* do these checks once, not for each item we have: */ if (!(u->race->ec_flags & GIVEITEM) && u2 != NULL) { @@ -859,9 +860,7 @@ static void give_cmd(unit * u, order * ord) } return; } else { - param_t p2 = findparam(s, u->faction->locale); - - if (p2 == P_PERSON) { + if (isparam(s, u->faction->locale, P_PERSON)) { if (!(u->race->ec_flags & GIVEPERSON)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_noregroup", "race", u->race)); From 7dea6457d18d1fbdcdec4cfe58099abdb6f866d9 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 19 May 2012 22:47:52 -0700 Subject: [PATCH 230/400] cleaning up GIVE, because there was too much parameter-searching going on here for the normal case of GIVE X N ITEM --- src/gamecode/economy.c | 54 +++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index b3a47409d..e37123e93 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -696,7 +696,7 @@ static void give_cmd(unit * u, order * ord) region *r = u->region; unit *u2; const char *s; - int i, n; + int n; const item_type *itype; param_t p; plane *pl; @@ -705,7 +705,8 @@ static void give_cmd(unit * u, order * ord) skip_token(); u2 = getunit(r, u->faction); s = getstrtoken(); - p = findparam(s, u->faction->locale); + n = atoip(s); + p = (n>0) ? NOPARAM : findparam(s, u->faction->locale); /* first, do all the ones that do not require HELP_GIVE or CONTACT */ if (p == P_CONTROL) { @@ -858,44 +859,37 @@ static void give_cmd(unit * u, order * ord) itmp = &itm->next; } } - return; } else { if (isparam(s, u->faction->locale, P_PERSON)) { if (!(u->race->ec_flags & GIVEPERSON)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_noregroup", "race", u->race)); - return; + } else { + n = u->number; + give_men(n, u, u2, ord); } - n = u->number; - give_men(n, u, u2, ord); - return; - } - - if (!(u->race->ec_flags & GIVEITEM) && u2 != NULL) { + } else if (!(u->race->ec_flags & GIVEITEM) && u2 != NULL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_nogive", "race", u->race)); - return; - } - if (u2 && !(u2->race->ec_flags & GETITEM)) { + } else if (u2 && !(u2->race->ec_flags & GETITEM)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_notake", "race", u2->race)); - return; - } - - itype = finditemtype(s, u->faction->locale); - if (itype != NULL) { - item *i = *i_find(&u->items, itype); - if (i != NULL) { - if (check_give(u, u2, itype, 0)) { - n = i->number - get_reservation(u, itype->rtype); - give_item(n, itype, u, u2, ord); - } else { - feedback_give_not_allowed(u, ord); + } else { + itype = finditemtype(s, u->faction->locale); + if (itype != NULL) { + item *i = *i_find(&u->items, itype); + if (i != NULL) { + if (check_give(u, u2, itype, 0)) { + n = i->number - get_reservation(u, itype->rtype); + give_item(n, itype, u, u2, ord); + } else { + feedback_give_not_allowed(u, ord); + } } - return; } } } + return; } else if (p == P_EACH) { if (u2 == NULL) { ADDMSG(&u->faction->msgs, @@ -903,10 +897,7 @@ static void give_cmd(unit * u, order * ord) return; } s = getstrtoken(); /* skip one ahead to get the amount. */ - } - - n = atoip((const char *)s); /* n: Anzahl */ - if (p == P_EACH) { + n = atoip(s); /* n: Anzahl */ n *= u2->number; } s = getstrtoken(); @@ -916,8 +907,7 @@ static void give_cmd(unit * u, order * ord) return; } - i = findparam(s, u->faction->locale); - if (i == P_PERSON) { + if (isparam(s, u->faction->locale, P_PERSON)) { if (!(u->race->ec_flags & GIVEPERSON)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_noregroup", "race", u->race)); From 08adc91534971a63de69e8cde6610c888f24d58d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 20 May 2012 00:16:12 -0700 Subject: [PATCH 231/400] gcc 4.6 is a lot more picky about unused variables, so I shall appease it. --- src/attributes/giveitem.c | 3 +-- src/bindings/helpers.c | 8 ++++---- src/gamecode/economy.c | 3 --- src/gamecode/study.c | 2 -- src/gmtool.c | 6 ++---- src/kernel/build.c | 2 -- src/kernel/move.c | 5 ----- src/kernel/region.c | 16 ++++++++-------- src/kernel/reports.c | 11 ++++++----- src/kernel/save.c | 18 ++++++++---------- src/kernel/sqlite.c | 8 ++++---- src/kernel/unit.c | 5 ----- src/modules/autoseed.c | 4 +--- 13 files changed, 34 insertions(+), 57 deletions(-) diff --git a/src/attributes/giveitem.c b/src/attributes/giveitem.c index b9ceb0f33..ed996ed93 100644 --- a/src/attributes/giveitem.c +++ b/src/attributes/giveitem.c @@ -95,11 +95,10 @@ static void a_finalizegive(struct attrib *a) static int a_giveitem(attrib * a) { give_data *gdata = (give_data *) a->data.v; - region *r; unit *u; + if (gdata->building == NULL || gdata->items == NULL) return 0; - r = gdata->building->region; u = building_owner(gdata->building); if (u == NULL) return 1; diff --git a/src/bindings/helpers.c b/src/bindings/helpers.c index b5eca0eb1..cb586cf9f 100644 --- a/src/bindings/helpers.c +++ b/src/bindings/helpers.c @@ -240,7 +240,7 @@ static int lua_callspell(castorder * co) } /** callback to initialize a familiar from lua. */ -static void lua_initfamiliar(unit * u) +static int lua_initfamiliar(unit * u) { lua_State *L = (lua_State *) global.vm_state; char fname[64]; @@ -269,6 +269,7 @@ static void lua_initfamiliar(unit * u) snprintf(fname, sizeof(fname), "%s_familiar", u->race->_name[0]); equip_unit(u, get_equipment(fname)); + return result; } static int @@ -447,11 +448,9 @@ static double lua_building_taxes(building * b, int level) lua_State *L = (lua_State *) global.vm_state; const char *fname = "building_taxes"; double result = 0.0F; - int type; lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); - type = lua_type(L, 1); if (lua_isfunction(L, 1)) { tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); tolua_pushnumber(L, level); @@ -498,7 +497,7 @@ static int lua_maintenance(const unit * u) return result; } -static void lua_equipmentcallback(const struct equipment *eq, unit * u) +static int lua_equipmentcallback(const struct equipment *eq, unit * u) { lua_State *L = (lua_State *) global.vm_state; char fname[64]; @@ -522,6 +521,7 @@ static void lua_equipmentcallback(const struct equipment *eq, unit * u) log_error("equip(%s) calling '%s': not a function.\n", unitname(u), fname); lua_pop(L, 1); } + return result; } /** callback for an item-use function written in lua. */ diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index e37123e93..11c0a9245 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -1432,7 +1432,6 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) { const item_type *itype = resource2item(rtype); region *r = u->region; - int busy = u->number; int dm = 0; allocation_list *alist; allocation *al; @@ -1555,8 +1554,6 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) if (want > 0 && want < amount) amount = want; - busy = (amount + skill - 1) / skill; /* wieviel leute tun etwas? */ - alist = allocations; while (alist && alist->type != rtype) alist = alist->next; diff --git a/src/gamecode/study.c b/src/gamecode/study.c index a317d4b4d..a25c56a52 100644 --- a/src/gamecode/study.c +++ b/src/gamecode/study.c @@ -276,7 +276,6 @@ int teach_cmd(unit * u, struct order *ord) plane *pl; region *r = u->region; int teaching, i, j, count, academy = 0; - unit *u2; skill_t sk = NOSKILL; if (gbdream_ct == 0) @@ -312,7 +311,6 @@ int teach_cmd(unit * u, struct order *ord) if (teaching == 0) return 0; - u2 = 0; count = 0; init_tokens(ord); diff --git a/src/gmtool.c b/src/gmtool.c index dfc48b1e2..57d715501 100644 --- a/src/gmtool.c +++ b/src/gmtool.c @@ -502,14 +502,13 @@ terraform_selection(selection * selected, const terrain_type * terrain) static faction *select_faction(state * st) { - list_selection *prev, *ilist = NULL, **iinsert; + list_selection *ilist = NULL, **iinsert; list_selection *selected = NULL; faction *f = factions; if (!f) return NULL; iinsert = &ilist; - prev = ilist; while (f) { char buffer[32]; @@ -530,14 +529,13 @@ static faction *select_faction(state * st) static const terrain_type *select_terrain(state * st, const terrain_type * default_terrain) { - list_selection *prev, *ilist = NULL, **iinsert; + list_selection *ilist = NULL, **iinsert; list_selection *selected = NULL; const terrain_type *terrain = terrains(); if (!terrain) return NULL; iinsert = &ilist; - prev = ilist; while (terrain) { insert_selection(iinsert, NULL, terrain->_name, (void *)terrain); diff --git a/src/kernel/build.c b/src/kernel/build.c index e718ff5b2..6b9746e24 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -847,7 +847,6 @@ void build_building(unit * u, const building_type * btype, int want, order * ord) { region *r = u->region; - boolean newbuilding = false; int n = want, built = 0, id; building *b = NULL; /* einmalige Korrektur */ @@ -983,7 +982,6 @@ build_building(unit * u, const building_type * btype, int want, order * ord) } #endif - newbuilding = true; } btname = LOC(lang, btype->_name); diff --git a/src/kernel/move.c b/src/kernel/move.c index 528e9da64..f43655a3a 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -1292,14 +1292,11 @@ static void make_route(unit * u, order * ord, region_list ** routep) } while (next != NULL) { - direction_t reldir; - if (current == next) { /* PAUSE */ break; } next = next_region(u, current, next); - reldir = reldirection(current, next); add_regionlist(iroute, next); iroute = &(*iroute)->next; @@ -1718,7 +1715,6 @@ sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) const terrain_type *tthis = current_point->terrain; /* these values need to be updated if next_point changes (due to storms): */ const terrain_type *tnext = next_point->terrain; - direction_t dir = reldirection(current_point, next_point); assert(sh == u->ship || !"ship has sunk, but we didn't notice it"); @@ -1781,7 +1777,6 @@ sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) next_point = rnext; /* these values need to be updated if next_point changes (due to storms): */ tnext = next_point->terrain; - dir = reldirection(current_point, next_point); } } } diff --git a/src/kernel/region.c b/src/kernel/region.c index 714180974..7b42495c0 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -787,21 +787,21 @@ void rsetroad(region * r, direction_t d, short val) short rroad(const region * r, direction_t d) { - int rval; connection *b; region *r2 = rconnect(r, d); - if (!r2) + if (!r2) { return 0; + } b = get_borders(r, r2); - while (b && b->type != &bt_road) + while (b && b->type != &bt_road) { b = b->next; - if (!b) + } + if (!b) { return 0; - rval = b->data.i; - if (r == b->from) - return b->data.sa[0]; - return b->data.sa[1]; + } + + return (r == b->from) ? b->data.sa[0] : b->data.sa[1]; } boolean r_isforest(const region * r) diff --git a/src/kernel/reports.c b/src/kernel/reports.c index 51855299b..6a7e4c81d 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -1744,7 +1744,6 @@ int reports(void) faction *f; FILE *mailit; time_t ltime = time(NULL); - const char *str; int retval = 0; char path[MAX_PATH]; @@ -1771,11 +1770,13 @@ int reports(void) if (mailit) fclose(mailit); free_seen(); - str = get_param(global.parameters, "globalreport"); #ifdef GLOBAL_REPORT - if (str != NULL) { - sprintf(path, "%s/%s.%u.cr", reportpath(), str, turn); - global_report(path); + { + const char *str = get_param(global.parameters, "globalreport"); + if (str != NULL) { + sprintf(path, "%s/%s.%u.cr", reportpath(), str, turn); + global_report(path); + } } #endif return retval; diff --git a/src/kernel/save.c b/src/kernel/save.c index 326e12188..65737396a 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -406,20 +406,19 @@ int readorders(const char *filename) while (b) { const struct locale *lang = f ? f->locale : default_locale; int p; - const char *s; - switch (igetparam(b, lang)) { - case P_LOCALE: - s = getstrtoken(); #undef LOCALE_CHANGE #ifdef LOCALE_CHANGE - if (f && find_locale(s)) { - f->locale = find_locale(s); + case P_LOCALE: + { + const char *s = getstrtoken(); + if (f && find_locale(s)) { + f->locale = find_locale(s); + } } -#endif - b = getbuf(F, enc_gamedata); break; +#endif case P_GAMENAME: case P_FACTION: f = factionorders(); @@ -1292,11 +1291,10 @@ faction *readfaction(struct storage * store) read_items(store, &f->items); } for (;;) { - int level; store->r_tok_buf(store, token, sizeof(token)); if (strcmp("end", token) == 0) break; - level = store->r_int(store); + store->r_int(store); /* there used to be a level here, which is now ignored */ } planes = store->r_int(store); while (--planes >= 0) { diff --git a/src/kernel/sqlite.c b/src/kernel/sqlite.c index d8194e421..6e6cc5014 100644 --- a/src/kernel/sqlite.c +++ b/src/kernel/sqlite.c @@ -38,12 +38,12 @@ static int cache_insert; static sqlite3_stmt *stmt_cache_get(sqlite3 * db, const char *sql) { - int i, res; + int i; for (i = 0; i != MAX_STMT_CACHE && cache[i].db; ++i) { if (cache[i].sql == sql && cache[i].db == db) { cache[i].inuse = 1; - res = sqlite3_reset(cache[i].stmt); + sqlite3_reset(cache[i].stmt); return cache[i].stmt; } } @@ -53,12 +53,12 @@ static sqlite3_stmt *stmt_cache_get(sqlite3 * db, const char *sql) cache_insert = (cache_insert + 1) & (MAX_STMT_CACHE - 1); } i = cache_insert; - res = sqlite3_finalize(cache[i].stmt); + sqlite3_finalize(cache[i].stmt); } cache[i].inuse = 1; cache[i].db = db; cache[i].sql = sql; - res = sqlite3_prepare_v2(db, sql, -1, &cache[i].stmt, NULL); + sqlite3_prepare_v2(db, sql, -1, &cache[i].stmt, NULL); return cache[i].stmt; } diff --git a/src/kernel/unit.c b/src/kernel/unit.c index cbda7e261..3cf2d78ef 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -873,14 +873,11 @@ boolean can_survive(const unit * u, const region * r) void move_unit(unit * u, region * r, unit ** ulist) { - int maxhp = 0; assert(u && r); assert(u->faction || !"this unit is dead"); if (u->region == r) return; - if (u->region != NULL) - maxhp = unit_max_hp(u); if (!ulist) ulist = (&r->units); if (u->region) { @@ -904,8 +901,6 @@ void move_unit(unit * u, region * r, unit ** ulist) update_interval(u->faction, r); #endif u->region = r; - /* keine automatische hp reduzierung bei bewegung */ - /* if (maxhp>0) u->hp = u->hp * unit_max_hp(u) / maxhp; */ } /* ist mist, aber wegen nicht skalierender attribute notwendig: */ diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c index 324eb98d8..d21ac4658 100644 --- a/src/modules/autoseed.c +++ b/src/modules/autoseed.c @@ -968,7 +968,6 @@ static void smooth_island(region_list * island) static void starting_region(region * r, region * rn[]) { - unit *u; int n; oceans_around(r, rn); @@ -978,8 +977,7 @@ static void starting_region(region * r, region * rn[]) } terraform_region(r, newterrain(T_PLAIN)); prepare_starting_region(r); - u = addplayer(r, addfaction("enno@eressea.de", itoa36(rng_int()), races, - default_locale, 0)); + addplayer(r, addfaction("enno@eressea.de", itoa36(rng_int()), races, default_locale, 0)); } /* E3A island generation */ From 52e323fef8b8e3264b6e47aefc137a358ef18bb5 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 20 May 2012 23:03:16 -0700 Subject: [PATCH 232/400] added a test that fails because of stupid static state in finditemtype --- src/kernel/item_test.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/kernel/item_test.c b/src/kernel/item_test.c index 98a8188a0..6c2704f13 100644 --- a/src/kernel/item_test.c +++ b/src/kernel/item_test.c @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -11,6 +12,8 @@ void test_resource_type(CuTest * tc) struct item_type *itype; const char *names[2] = { 0 , 0 }; + test_cleanup(); + CuAssertPtrEquals(tc, 0, rt_find("herpderp")); names[0] = names[1] = "herpderp"; @@ -26,9 +29,35 @@ void test_resource_type(CuTest * tc) CuAssertPtrEquals(tc, itype->rtype, rt_find("herp")); } +void test_finditemtype(CuTest * tc) +{ + struct item_type *itype; + const char *names[4] = { "herp" , "herp_p", "derp", "derp_p" }; + struct locale * lang = make_locale("de"); + + test_cleanup(); + + itype = test_create_itemtype(names); + CuAssertPtrNotNull(tc, itype); + locale_setstring(lang, names[0], "Foo"); + locale_setstring(lang, names[1], "Foos"); + + CuAssertPtrEquals(tc, (void*)itype, (void*)finditemtype("Foo", lang)); + CuAssertPtrEquals(tc, (void*)itype, (void*)finditemtype("Foos", lang)); + + itype = test_create_itemtype(names+2); + CuAssertPtrNotNull(tc, itype); + locale_setstring(lang, names[2], "Bar"); + locale_setstring(lang, names[3], "Bars"); + + CuAssertPtrEquals(tc, (void*)itype, (void*)finditemtype("Bar", lang)); + CuAssertPtrEquals(tc, (void*)itype, (void*)finditemtype("Bars", lang)); +} + CuSuite *get_item_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_resource_type); + SUITE_ADD_TEST(suite, test_finditemtype); return suite; } From 5ab1b2881a8d8c1f6fca572dbefd16620a479403 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 20 May 2012 23:06:12 -0700 Subject: [PATCH 233/400] This patches the failure of the test, but it is slow as heck. --- src/kernel/item.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/kernel/item.c b/src/kernel/item.c index 525693a3c..66a20f6bd 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -1100,10 +1100,11 @@ attrib_type at_showitem = { "showitem" }; -static local_names *inames; +/* static local_names *inames; */ const item_type *finditemtype(const char *name, const struct locale *lang) { + local_names *inames = 0; const void * matches[CB_BATCHSIZE]; local_names *in = inames; variant token; @@ -1208,7 +1209,7 @@ void test_clear_resources(void) r_hp = r_silver = r_aura = r_permaura = r_unit = 0; i_silver = 0; - inames = 0; /* TODO: this is a terrible hack, the whole inames global state must die */ + /* inames = 0; TODO: this is a terrible hack, the whole inames global state must die */ } #endif From 1e9c10fbe2544dded7e557399cef30a3dffef9b7 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 21 May 2012 13:18:05 -0700 Subject: [PATCH 234/400] finditemtype works as tested. starting to think about removing default_locale in lieu of a hierarchical system. --- src/kernel/item.c | 80 +++++++++++++++++++++----------------- src/kernel/item_test.c | 16 +++++--- src/util/critbit.c | 3 +- src/util/critbit.h | 2 +- src/util/language.c | 8 ++-- src/util/language_struct.h | 1 + src/util/umlaut.c | 2 +- 7 files changed, 63 insertions(+), 49 deletions(-) diff --git a/src/kernel/item.c b/src/kernel/item.c index 66a20f6bd..4b096ef81 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -56,6 +56,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +static critbit_tree inames[MAXLOCALES]; static critbit_tree cb_resources; static critbit_tree cb_items; luxury_type *luxurytypes; @@ -1100,46 +1101,49 @@ attrib_type at_showitem = { "showitem" }; -/* static local_names *inames; */ +static int add_itemname_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 = inames+i; + item_type *itype; + + cb_get_kv(match, &itype, sizeof(itype)); + for (i = 0; i!=2;++i) { + char buffer[64]; + const char * name = locale_string(lang, itype->rtype->_name[i]); + + if (name && transliterate(buffer, sizeof(buffer), name)) { + size_t len = strlen(buffer); + assert(len+sizeof(itype)lang == lang) - break; - in = in->next; + if (transliterate(buffer, sizeof(buffer), name)) { + const void * match; + if (!cb->root) { + /* first-time initialization of item names for this locale */ + cb_foreach(&cb_items, "", 0, add_itemname_cb, (void *)lang); + } + if (cb_find_prefix(cb, buffer, strlen(buffer), &match, 1, 0)) { + const item_type * itype = 0; + cb_get_kv(match, (void*)&itype, sizeof(itype)); + return itype; + } + } else { + log_debug("finditemtype: transliterate failed for '%s'\n", name); } - if (!in) { - int m, offset = 0; - in = (local_names *)calloc(1, sizeof(local_names)); - in->next = inames; - in->lang = lang; - do { - m = cb_find_prefix(&cb_items, "", 0, matches, CB_BATCHSIZE, offset); - if (m) { - int i; - offset += m; - for (i=0;i!=m;++i) { - item_type *itype; - cb_get_kv(matches[i], &itype, sizeof(itype)); - token.v = (void *)itype; - addtoken(&in->names, locale_string(lang, itype->rtype->_name[0]), token); - addtoken(&in->names, locale_string(lang, itype->rtype->_name[1]), token); - } - } - } while (m==CB_BATCHSIZE); - inames = in; - } - - if (findtoken(in->names, name, &token) == E_TOK_NOMATCH) { - return 0; - } - return (const item_type *)token.v; + return 0; } static void init_resourcelimit(attrib * a) @@ -1197,6 +1201,8 @@ int free_rtype_cb(const void * match, const void * key, size_t keylen, void *cbd void test_clear_resources(void) { + int i; + memset((void *)olditemtype, 0, sizeof(olditemtype)); memset((void *)oldresourcetype, 0, sizeof(oldresourcetype)); memset((void *)oldpotiontype, 0, sizeof(oldpotiontype)); @@ -1209,7 +1215,9 @@ void test_clear_resources(void) r_hp = r_silver = r_aura = r_permaura = r_unit = 0; i_silver = 0; - /* inames = 0; TODO: this is a terrible hack, the whole inames global state must die */ + for (i=0; i!=MAXLOCALES; ++i) { + cb_clear(inames+i); + } } #endif diff --git a/src/kernel/item_test.c b/src/kernel/item_test.c index 6c2704f13..a62208cd5 100644 --- a/src/kernel/item_test.c +++ b/src/kernel/item_test.c @@ -31,28 +31,34 @@ void test_resource_type(CuTest * tc) void test_finditemtype(CuTest * tc) { - struct item_type *itype; - const char *names[4] = { "herp" , "herp_p", "derp", "derp_p" }; + const item_type *itype, *iresult; + const char *names[] = { "herp" , "herp_p" }; struct locale * lang = make_locale("de"); test_cleanup(); + locale_setstring(lang, names[0], "Foo"); itype = test_create_itemtype(names); CuAssertPtrNotNull(tc, itype); - locale_setstring(lang, names[0], "Foo"); - locale_setstring(lang, names[1], "Foos"); + iresult = finditemtype("Foo", lang); + CuAssertPtrEquals(tc, (void*)itype, (void*)iresult); +} +#if 0 + locale_setstring(lang, names[1], "Foos"); CuAssertPtrEquals(tc, (void*)itype, (void*)finditemtype("Foo", lang)); CuAssertPtrEquals(tc, (void*)itype, (void*)finditemtype("Foos", lang)); + test_cleanup(); itype = test_create_itemtype(names+2); CuAssertPtrNotNull(tc, itype); locale_setstring(lang, names[2], "Bar"); locale_setstring(lang, names[3], "Bars"); + CuAssertPtrEquals(tc, (void*)0, (void*)finditemtype("Foo", lang)); CuAssertPtrEquals(tc, (void*)itype, (void*)finditemtype("Bar", lang)); - CuAssertPtrEquals(tc, (void*)itype, (void*)finditemtype("Bars", lang)); } +#endif CuSuite *get_item_suite(void) { diff --git a/src/util/critbit.c b/src/util/critbit.c index cd902d6ee..bfedfed7b 100644 --- a/src/util/critbit.c +++ b/src/util/critbit.c @@ -330,13 +330,14 @@ int cb_erase(critbit_tree * cb, const void * key, size_t keylen) } } -void cb_new_kv(const char *key, void * value, size_t len, void * dst) +size_t cb_new_kv(const char *key, void * value, size_t len, void * dst) { size_t keylen = strlen(key)+1; if (dst!=key) { memcpy(dst, key, keylen); } memcpy((char*)dst+keylen, value, len); + return len+keylen; } void cb_get_kv(const void *kv, void * value, size_t len) diff --git a/src/util/critbit.h b/src/util/critbit.h index 0d9c11c89..67534d83f 100644 --- a/src/util/critbit.h +++ b/src/util/critbit.h @@ -47,7 +47,7 @@ void cb_clear(critbit_tree * cb); #define cb_find_prefix_str(cb, key, results, numresults, offset) \ cb_find_prefix(cb, (void *)key, strlen(key), results, numresults, offset) -void cb_new_kv(const char *key, void * value, size_t len, void * dst); +size_t cb_new_kv(const char *key, void * value, size_t len, void * dst); void cb_get_kv(const void *kv, void * value, size_t len); #ifdef __cplusplus diff --git a/src/util/language.c b/src/util/language.c index 2af939234..917a51626 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -127,7 +127,7 @@ const char *locale_getstring(const locale * lang, const char *key) const char *locale_string(const locale * lang, const char *key) { - assert(lang != 0); + assert(lang); if (key != NULL) { unsigned int hkey = hashstring(key); @@ -136,8 +136,6 @@ const char *locale_string(const locale * lang, const char *key) if (*key == 0) return NULL; - if (lang == NULL) - return key; find = lang->strings[id]; while (find) { if (find->hashkey == hkey) { @@ -153,8 +151,8 @@ const char *locale_string(const locale * lang, const char *key) } if (!find) { log_warning("missing translation for \"%s\" in locale %s\n", key, lang->name); - if (lang != default_locale) { - return locale_string(default_locale, key); + if (lang->fallback) { + return locale_string(lang->fallback, key); } return 0; } diff --git a/src/util/language_struct.h b/src/util/language_struct.h index 616998213..fa79fdb57 100644 --- a/src/util/language_struct.h +++ b/src/util/language_struct.h @@ -19,6 +19,7 @@ typedef struct locale { unsigned int hashkey; const char *name; struct locale_str *strings[SMAXHASH]; + struct locale *fallback; } locale; extern locale *default_locale; diff --git a/src/util/umlaut.c b/src/util/umlaut.c index 81f356a14..443decfbd 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -125,7 +125,7 @@ void addtoken(void ** root, const char *str, variant id) 0, ""} }; - assert(root); + assert(root && str); if (!*root) { tk = *root = calloc(1, sizeof(tnode)); } else { From ad59fe96b0f6e5ec9cf1eac345b550fa347692b4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 21 May 2012 15:47:18 -0700 Subject: [PATCH 235/400] buffer size was too small for some special items --- src/kernel/item.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kernel/item.c b/src/kernel/item.c index 4b096ef81..5e842b26b 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -1110,7 +1110,7 @@ static int add_itemname_cb(const void * match, const void * key, size_t keylen, cb_get_kv(match, &itype, sizeof(itype)); for (i = 0; i!=2;++i) { - char buffer[64]; + char buffer[128]; const char * name = locale_string(lang, itype->rtype->_name[i]); if (name && transliterate(buffer, sizeof(buffer), name)) { @@ -1127,7 +1127,7 @@ const item_type *finditemtype(const char *name, const struct locale *lang) { int i = locale_index(lang); critbit_tree * cb = inames+i; - char buffer[64]; + char buffer[128]; if (transliterate(buffer, sizeof(buffer), name)) { const void * match; From a45eb5319106522f5acf58546deae5d346b96f17 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 21 May 2012 17:45:54 -0700 Subject: [PATCH 236/400] findskill uses critbits now killing old PTRIES code --- src/kernel/config.c | 220 ++++++++++++-------------------------------- 1 file changed, 57 insertions(+), 163 deletions(-) diff --git a/src/kernel/config.c b/src/kernel/config.c index c837bb946..f4551ce9b 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -1347,133 +1347,23 @@ int findoption(const char *s, const struct locale *lang) return NODIRECTION; } -#ifdef PTRIES -static struct trie_node *ptries[UT_MAX][4]; - -static struct trie_node **get_ptrie(const struct locale *lang, int type) -{ - int index = (strcmp(locale_name(lang), "de") == 0); - return &(ptries[type][index]); -} - -static int umlaut_substitution(const char *ip, char *op, size_t outlen) -{ -#define UMAX 7 - static struct replace { - ucs4_t ucs; - const char str[3]; - } replace[UMAX] = { - /* match lower-case (!) umlauts and others to transcriptions */ - { - 223, "ss"}, /* szlig */ - { - 228, "ae"}, /* auml */ - { - 229, "aa"}, /* norsk */ - { - 230, "ae"}, /* norsk */ - { - 246, "oe"}, /* ouml */ - { - 248, "oe"}, /* norsk */ - { - 252, "ue"}, /* uuml */ - }; - int subs = 0; - while (*ip) { - ucs4_t ucs = *ip; - size_t size = 1; - size_t cpsize = 1; - - if (ucs & 0x80) { - int ret = unicode_utf8_to_ucs4(&ucs, ip, &size); - if (ret != 0) { - return ret; - } - cpsize = size; - if (ucs >= replace[0].ucs && ucs <= replace[UMAX - 1].ucs) { - int i; - for (i = 0; i != UMAX; ++i) { - if (replace[i].ucs == ucs) { - cpsize = 0; - memcpy(op, replace[i].str, 2); - op += 2; - ++subs; - break; - } - } - } - } - if (cpsize) { - if (cpsize > outlen) { - return -1; - } - memcpy(op, ip, cpsize); - } - - ip += size; - op += cpsize; - outlen -= cpsize; - } - - if (outlen <= 0) { - return -1; - } - *op = 0; - return subs; -} - -static int -ptrie_find(struct trie_node *ptrie, const char *key, void *data, size_t size) -{ - trie_node *node = trie_find_prefix(ptrie, key); - if (node) { - void *result = trie_getdata(node); - memcpy(data, result, size); - return 0; - } - return -1; -} - -static int -ptrie_insert(struct trie_node **ptrie, const char *name, void *data, - size_t size) -{ - char converted[256]; - char simple[256]; - int ret = unicode_utf8_tolower(converted, 256, name); - if (ret == 0) { - int subs = umlaut_substitution(converted, simple, sizeof(simple)); - if (subs > 0) { - trie_insert(ptrie, simple, data, size); - } - trie_insert(ptrie, converted, data, size); - } - return ret; -} -#endif - skill_t findskill(const char *s, const struct locale * lang) { -#ifdef PTRIES - char lowercase[256]; - int res = unicode_utf8_tolower(lowercase, sizeof(lowercase), s); - if (res == 0) { - trie_node **ptrie = get_ptrie(lang, UT_SKILLS); - skill_t sk; - int result = ptrie_find(*ptrie, lowercase, &sk, sizeof(sk)); - if (result == 0) - return sk; - } - return NOSKILL; -#else - void **tokens = get_translations(lang, UT_SKILLS); - variant token; + param_t result = NOSKILL; + char buffer[64]; + char * str = transliterate(buffer, sizeof(buffer)-sizeof(int), s); - if (findtoken(*tokens, s, &token) == E_TOK_NOMATCH) - return NOSKILL; - return (skill_t) token.i; -#endif + if (str) { + int i; + const void * match; + void **tokens = get_translations(lang, UT_SKILLS); + critbit_tree *cb = (critbit_tree *)*tokens; + if (cb_find_prefix(cb, str, strlen(str), &match, 1, 0)) { + cb_get_kv(match, &i, sizeof(int)); + result = (skill_t)i; + } + } + return result; } keyword_t findkeyword(const char *s, const struct locale * lang) @@ -2072,17 +1962,53 @@ direction_t finddirection(const char *s, const struct locale *lang) return NODIRECTION; } +static void init_translations(const struct locale *lang, int ut, const char * (*string_cb)(int i), int maxstrings) +{ + char buffer[256]; + void **tokens; + int i; + + assert(string_cb); + assert(maxstrings>0); + tokens = get_translations(lang, ut); + for (i = 0; i != maxstrings; ++i) { + const char * s = string_cb(i); + const char * key = s ? locale_string(lang, s) : 0; + if (key) { + char * str = transliterate(buffer, sizeof(buffer)-sizeof(int), key); + if (str) { + critbit_tree * cb = (critbit_tree *)*tokens; + if (!cb) { + *tokens = cb = (critbit_tree *)calloc(1, sizeof(critbit_tree *)); + } + cb_new_kv(str, &i, sizeof(int), buffer); + cb_insert(cb, buffer, strlen(str)+1+sizeof(int)); + } else { + log_error("could not transliterate '%s'\n", key); + } + } + } +} + +static const char * parameter_key(int i) +{ + assert(i=0); + return parameters[i]; +} + +static const char * skill_key(int sk) +{ + assert(sk=0); + return skill_enabled[sk] ? mkname("skill", skillnames[sk]) : 0; +} + static void init_locale(const struct locale *lang) { variant var; int i; const struct race *rc; - void **tokens; const terrain_type *terrain; - char buffer[256]; -#ifdef PTRIES - trie_node **ptrie; -#endif + void **tokens; tokens = get_translations(lang, UT_MAGIC); if (tokens) { @@ -2117,40 +2043,8 @@ static void init_locale(const struct locale *lang) addtoken(tokens, LOC(lang, rc_name(rc, 0)), var); } - tokens = get_translations(lang, UT_PARAMS); - for (i = 0; i != MAXPARAMS; ++i) { - const char * key = LOC(lang, parameters[i]); - char * str = transliterate(buffer, sizeof(buffer)-sizeof(int), key); - if (str) { - critbit_tree * cb = (critbit_tree *)*tokens; - if (!cb) { - *tokens = cb = (critbit_tree *)calloc(1, sizeof(critbit_tree *)); - } - cb_new_kv(str, &i, sizeof(int), buffer); - cb_insert(cb, buffer, strlen(str)+1+sizeof(int)); - } else { - log_error("could not transliterate param '%s'\n", key); - } - } -#ifdef PTRIES - ptrie = get_ptrie(lang, UT_SKILLS); - for (i = 0; i != MAXSKILLS; ++i) { - skill_t sk = (skill_t) i; - const char *skname = skillname(sk, lang); - if (skname != NULL) { - ptrie_insert(ptrie, skname, &sk, sizeof(sk)); - } - } -#else - tokens = get_translations(lang, UT_SKILLS); - for (i = 0; i != MAXSKILLS; ++i) { - const char *skname = skillname((skill_t) i, lang); - if (skname != NULL) { - var.i = i; - addtoken(tokens, skname, var); - } - } -#endif + init_translations(lang, UT_PARAMS, parameter_key, MAXPARAMS); + init_translations(lang, UT_SKILLS, skill_key, MAXSKILLS); tokens = get_translations(lang, UT_KEYWORDS); for (i = 0; i != MAXKEYWORDS; ++i) { From 1b038a7eafd2860fb38ba8efbe2d9dcc0ec5bf7c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 21 May 2012 17:46:32 -0700 Subject: [PATCH 237/400] delete wisps, or any other border that can be read but not written --- src/kernel/connection.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/connection.c b/src/kernel/connection.c index fa76da7a7..32eb73a6b 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -674,7 +674,7 @@ int read_borders(struct storage *store) if (result < 0) return result; } - if (!type->name || !to || !from) { + if ((type->read && !type->write) || !to || !from) { log_warning("erase invalid border '%s' between '%s' and '%s'\n", type->__name, regionname(from, 0), regionname(to, 0)); erase_border(b); } From 3394766ab95cf639853cbca93a862acd7a915ea7 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 21 May 2012 17:46:59 -0700 Subject: [PATCH 238/400] double the buffer size for region names --- src/kernel/region.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/kernel/region.c b/src/kernel/region.c index 7b42495c0..fdcc2f39b 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -128,8 +128,10 @@ const char *write_regionname(const region * r, const faction * f, char *buffer, const char *regionname(const region * r, const faction * f) { - static char buf[NAMESIZE]; - return write_regionname(r, f, buf, sizeof(buf)); + static int index = 0; + static char buf[2][NAMESIZE]; + index = 1-index; + return write_regionname(r, f, buf[index], sizeof(buf[index])); } int deathcount(const region * r) From ad146602c75643366043fe51599a219b2dff0e4f Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 21 May 2012 17:56:27 -0700 Subject: [PATCH 239/400] change the order in which TARNE arguments are checked, to handle simple cases first. --- src/gamecode/spy.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/gamecode/spy.c b/src/gamecode/spy.c index 2b9c948a6..10b83f31a 100644 --- a/src/gamecode/spy.c +++ b/src/gamecode/spy.c @@ -224,6 +224,17 @@ int setstealth_cmd(unit * u, struct order *ord) return 0; } + if (isdigit(s[0])) { + /* Tarnungslevel setzen */ + level = atoi((const char *)s); + if (level > effskill(u, SK_STEALTH)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_lowstealth", "")); + return 0; + } + u_seteffstealth(u, level); + return 0; + } + trace = findrace(s, u->faction->locale); if (trace) { /* Dämonen können sich nur als andere Spielerrassen tarnen */ @@ -316,17 +327,10 @@ int setstealth_cmd(unit * u, struct order *ord) u_seteffstealth(u, -1); break; default: - if (isdigit(s[0])) { - /* Tarnungslevel setzen */ - level = atoi((const char *)s); - if (level > effskill(u, SK_STEALTH)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_lowstealth", - "")); - return 0; - } - u_seteffstealth(u, level); - } else if (u->race->flags & RCF_SHAPESHIFTANY) { + if (u->race->flags & RCF_SHAPESHIFTANY) { set_racename(&u->attribs, s); + } else { + cmistake(u, ord, 289, MSG_EVENT); } } return 0; From d7c2824ba954f27305fda2938f6706eb8a1e3de3 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 21 May 2012 18:09:30 -0700 Subject: [PATCH 240/400] keywords use critbits now --- src/kernel/config.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/kernel/config.c b/src/kernel/config.c index f4551ce9b..6d1d753fd 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -1368,16 +1368,27 @@ skill_t findskill(const char *s, const struct locale * lang) keyword_t findkeyword(const char *s, const struct locale * lang) { - void **tokens = get_translations(lang, UT_KEYWORDS); - variant token; + keyword_t result = NOKEYWORD; + char buffer[64]; - if (*s == '@') - s++; - if (findtoken(*tokens, s, &token) == E_TOK_NOMATCH) - return NOKEYWORD; - if (global.disabled[token.i]) - return NOKEYWORD; - return (keyword_t) token.i; + while (*s == '@') ++s; + + if (*s) { + char * str = transliterate(buffer, sizeof(buffer)-sizeof(int), s); + + if (str) { + int i; + const void * match; + void **tokens = get_translations(lang, UT_KEYWORDS); + critbit_tree *cb = (critbit_tree *)*tokens; + if (cb_find_prefix(cb, str, strlen(str), &match, 1, 0)) { + cb_get_kv(match, &i, sizeof(int)); + result = (keyword_t)i; + return global.disabled[result] ? NOKEYWORD : result; + } + } + } + return NOKEYWORD; } param_t findparam(const char *s, const struct locale * lang) @@ -1990,6 +2001,12 @@ static void init_translations(const struct locale *lang, int ut, const char * (* } } +static const char * keyword_key(int i) +{ + assert(i=0); + return keywords[i]; +} + static const char * parameter_key(int i) { assert(i=0); @@ -2045,13 +2062,7 @@ static void init_locale(const struct locale *lang) init_translations(lang, UT_PARAMS, parameter_key, MAXPARAMS); init_translations(lang, UT_SKILLS, skill_key, MAXSKILLS); - - tokens = get_translations(lang, UT_KEYWORDS); - for (i = 0; i != MAXKEYWORDS; ++i) { - var.i = i; - if (keywords[i]) - addtoken(tokens, LOC(lang, keywords[i]), var); - } + init_translations(lang, UT_KEYWORDS, keyword_key, MAXKEYWORDS); tokens = get_translations(lang, UT_OPTIONS); for (i = 0; i != MAXOPTIONS; ++i) { From bdb887c9fb3718ca19748dc1dce61c6cb8a8a850 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 21 May 2012 18:46:12 -0700 Subject: [PATCH 241/400] that typo has been bugging me --- scripts/default.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/default.lua b/scripts/default.lua index 7afd5fa8b..9b5e4c8a6 100644 --- a/scripts/default.lua +++ b/scripts/default.lua @@ -17,7 +17,7 @@ function dbupdate() edb:update_factions() edb:update_scores() else - print("could no open "..config.basepath.."/eressea.db") + print("could not open "..config.basepath.."/eressea.db") end end From 6c51013e14e7d0c88c249427fa51e69cd594b6bb Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 21 May 2012 21:00:04 -0700 Subject: [PATCH 242/400] Nachrichten haben keine Attribute: http://bugs.eressea.de/view.php?id=1912 --- src/gamecode/creport.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index 189645ffd..6bea30d8e 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -522,8 +522,10 @@ static void render_messages(FILE * F, faction * f, message_list * msgs) #endif crbuffer[0] = '\0'; if (cr_render(m->msg, crbuffer, (const void *)f) == 0) { - if (crbuffer[0] && !printed) { - fprintf(F, "MESSAGE %u\n", messagehash(m->msg)); + if (crbuffer[0]) { + if (!printed) { + fprintf(F, "MESSAGE %u\n", messagehash(m->msg)); + } fputs(crbuffer, F); } } else { From 2872dfa77289ec617dabc4cb21ddfd651ce333fd Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 21 May 2012 21:39:18 -0700 Subject: [PATCH 243/400] Added a test that fails for Bug 1909 (findresourcetype is borken) --- src/kernel/item_test.c | 36 +++++++++++++++++++----------------- src/tests_test.c | 18 +++++++++++++++++- 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/src/kernel/item_test.c b/src/kernel/item_test.c index a62208cd5..98c79de69 100644 --- a/src/kernel/item_test.c +++ b/src/kernel/item_test.c @@ -32,38 +32,40 @@ void test_resource_type(CuTest * tc) void test_finditemtype(CuTest * tc) { const item_type *itype, *iresult; - const char *names[] = { "herp" , "herp_p" }; - struct locale * lang = make_locale("de"); + struct locale * lang; test_cleanup(); + test_create_world(); - locale_setstring(lang, names[0], "Foo"); - itype = test_create_itemtype(names); - CuAssertPtrNotNull(tc, itype); - iresult = finditemtype("Foo", lang); + lang = find_locale("de"); + locale_setstring(lang, "horse", "Pferd"); + itype = it_find("horse"); + iresult = finditemtype("Pferd", lang); + CuAssertPtrNotNull(tc, iresult); CuAssertPtrEquals(tc, (void*)itype, (void*)iresult); } -#if 0 - locale_setstring(lang, names[1], "Foos"); - CuAssertPtrEquals(tc, (void*)itype, (void*)finditemtype("Foo", lang)); - CuAssertPtrEquals(tc, (void*)itype, (void*)finditemtype("Foos", lang)); +void test_findresourcetype(CuTest * tc) +{ + const resource_type *rtype, *rresult; + struct locale * lang; test_cleanup(); - itype = test_create_itemtype(names+2); - CuAssertPtrNotNull(tc, itype); - locale_setstring(lang, names[2], "Bar"); - locale_setstring(lang, names[3], "Bars"); + test_create_world(); - CuAssertPtrEquals(tc, (void*)0, (void*)finditemtype("Foo", lang)); - CuAssertPtrEquals(tc, (void*)itype, (void*)finditemtype("Bar", lang)); + lang = find_locale("de"); + locale_setstring(lang, "horse", "Pferd"); + rtype = rt_find("horse"); + rresult = findresourcetype("Pferd", lang); + CuAssertPtrNotNull(tc, rresult); + CuAssertPtrEquals(tc, (void*)rtype, (void*)rresult); } -#endif CuSuite *get_item_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_resource_type); SUITE_ADD_TEST(suite, test_finditemtype); + SUITE_ADD_TEST(suite, test_findresourcetype); return suite; } diff --git a/src/tests_test.c b/src/tests_test.c index 3f8a65513..3803ffa56 100644 --- a/src/tests_test.c +++ b/src/tests_test.c @@ -9,16 +9,32 @@ static void test_recreate_world(CuTest * tc) CuAssertPtrEquals(tc, 0, find_locale("de")); CuAssertPtrEquals(tc, 0, it_find("money")); CuAssertPtrEquals(tc, 0, it_find("horse")); + test_create_world(); CuAssertPtrEquals(tc, default_locale, find_locale("de")); CuAssertPtrNotNull(tc, default_locale); + CuAssertPtrNotNull(tc, findregion(0, 0)); CuAssertPtrNotNull(tc, it_find("money")); CuAssertPtrNotNull(tc, it_find("horse")); - CuAssertPtrNotNull(tc, findregion(0, 0)); + CuAssertPtrNotNull(tc, rt_find("horse")); + CuAssertPtrNotNull(tc, rt_find("hp")); + CuAssertPtrNotNull(tc, rt_find("money")); + CuAssertPtrNotNull(tc, rt_find("aura")); + CuAssertPtrNotNull(tc, rt_find("permaura")); + CuAssertPtrNotNull(tc, rt_find("peasant")); + CuAssertPtrNotNull(tc, rt_find("unit")); + test_cleanup(); CuAssertPtrEquals(tc, 0, find_locale("de")); CuAssertPtrEquals(tc, 0, it_find("money")); CuAssertPtrEquals(tc, 0, it_find("horse")); + CuAssertPtrEquals(tc, 0, rt_find("horse")); + CuAssertPtrEquals(tc, 0, rt_find("hp")); + CuAssertPtrEquals(tc, 0, rt_find("money")); + CuAssertPtrEquals(tc, 0, rt_find("aura")); + CuAssertPtrEquals(tc, 0, rt_find("permaura")); + CuAssertPtrEquals(tc, 0, rt_find("peasant")); + CuAssertPtrEquals(tc, 0, rt_find("unit")); CuAssertPtrEquals(tc, 0, findregion(0, 0)); } From 1672637b1788fa58dbed73f79f44e1b1ae1d5121 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 22 May 2012 14:53:46 -0700 Subject: [PATCH 244/400] better command line parsing fix compilation problem --- src/tests_test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests_test.c b/src/tests_test.c index 3f8a65513..79cc3224c 100644 --- a/src/tests_test.c +++ b/src/tests_test.c @@ -1,3 +1,4 @@ +#include #include #include From 31e4a8432bc227b0f00039c713b0a28602b6167e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 22 May 2012 18:44:54 -0700 Subject: [PATCH 245/400] fix find_spell and create_spell to only create each spell once. kill register_spell make some critbit changes (need to transfer them upstream) --- src/bindings/bind_region.c | 5 ++- src/kernel/config.c | 7 ++-- src/kernel/item.c | 12 +++--- src/kernel/spell.c | 61 +++++++++++++++++----------- src/kernel/spell.h | 23 +++-------- src/kernel/spell_test.c | 42 +++++++++++++++---- src/kernel/xmlreader.c | 83 +++++++++++++++++--------------------- src/tests.c | 1 + src/util/critbit.c | 12 +++--- src/util/critbit.h | 2 +- src/util/functions.c | 4 +- src/util/quicklist.c | 17 ++++---- src/util/translation.c | 4 +- 13 files changed, 152 insertions(+), 121 deletions(-) diff --git a/src/bindings/bind_region.c b/src/bindings/bind_region.c index c98849dfa..8404b2d92 100644 --- a/src/bindings/bind_region.c +++ b/src/bindings/bind_region.c @@ -319,8 +319,9 @@ static critbit_tree * special_resources(void) char buffer[32]; int i; for (i=0;special[i];++i) { - cb_new_kv(special[i], &i, sizeof(int), buffer); - cb_insert(&cb, buffer, strlen(special[i])+1+sizeof(int)); + size_t len = strlen(special[i]); + len = cb_new_kv(special[i], len, &i, sizeof(int), buffer); + cb_insert(&cb, buffer, len); } } return &cb; diff --git a/src/kernel/config.c b/src/kernel/config.c index 6d1d753fd..7033e4ba8 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -1989,11 +1989,12 @@ static void init_translations(const struct locale *lang, int ut, const char * (* char * str = transliterate(buffer, sizeof(buffer)-sizeof(int), key); if (str) { critbit_tree * cb = (critbit_tree *)*tokens; - if (!cb) { + size_t len = strlen(str); + if (!cb) { *tokens = cb = (critbit_tree *)calloc(1, sizeof(critbit_tree *)); } - cb_new_kv(str, &i, sizeof(int), buffer); - cb_insert(cb, buffer, strlen(str)+1+sizeof(int)); + len = cb_new_kv(str, len, &i, sizeof(int), buffer); + cb_insert(cb, buffer, len); } else { log_error("could not transliterate '%s'\n", key); } diff --git a/src/kernel/item.c b/src/kernel/item.c index 5e842b26b..a432b6226 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -177,8 +177,8 @@ void it_register(item_type * itype) size_t len = strlen(name); assert(lenrtype); } } @@ -298,8 +298,8 @@ void rt_register(resource_type * rtype) size_t len = strlen(name); assert(len -#include - /* util includes */ +#include #include #include #include #include #include -quicklist *spells = NULL; +/* libc includes */ +#include +#include -spell * create_spell(const char * name) -{ - spell * sp = (spell *) calloc(1, sizeof(spell)); - sp->sname = strdup(name); - return sp; +static critbit_tree cb_spells; +quicklist * spells; + +void free_spells(void) { + cb_clear(&cb_spells); + ql_free(spells); + spells = 0; } -void register_spell(spell * sp) +spell * create_spell(const char * name, unsigned int id) { - if (sp->id == 0) { - sp->id = hashstring(sp->sname); + spell * sp; + char buffer[64]; + size_t len = strlen(name); + + assert(len+sizeof(sp)id = id ? id : hashstring(name); + sp->sname = strdup(name); + add_spell(&spells, sp); + return sp; + } + free(sp); + return 0; } spell *find_spell(const char *name) { - quicklist *ql = spells; - int qi; + const char * match; + spell * sp = 0; - for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { - spell *sp = (spell *) ql_get(ql, qi); - if (strcmp(name, sp->sname) == 0) { - return sp; - } + match = cb_find_str(&cb_spells, name); + if (match) { + cb_get_kv(match, &sp, sizeof(sp)); + } else { + log_warning("find_spell: could not find spell '%s'\n", name); } - log_warning("find_spell: could not find spell '%s'\n", name); - return 0; + return sp; } /* ------------------------------------------------------------- */ diff --git a/src/kernel/spell.h b/src/kernel/spell.h index 4e5daf1b5..226de96e4 100644 --- a/src/kernel/spell.h +++ b/src/kernel/spell.h @@ -22,16 +22,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif - struct fighter; - struct spell; - struct border_type; - struct attrib_type; - struct curse_type; - struct castorder; - struct curse; - struct region; - struct unit; - /* Prototypen */ int use_item_power(struct region *r, struct unit *u); @@ -44,15 +34,14 @@ extern "C" { extern struct attrib_type at_unitdissolve; extern struct attrib_type at_wdwpyramid; - extern struct quicklist *spells; - - extern struct spell * create_spell(const char * name); - extern void register_spell(struct spell *sp); - extern struct spell *find_spell(const char *name); - extern struct spell *find_spellbyid(unsigned int i); - extern struct spell *get_spellfromtoken(struct sc_mage *mage, const char *s, + extern struct spell * create_spell(const char * name, unsigned int id); + extern struct spell * find_spell(const char *name); + extern struct spell * find_spellbyid(unsigned int i); + extern struct spell * get_spellfromtoken(struct sc_mage *mage, const char *s, const struct locale *lang); + extern void free_spells(void); + extern struct quicklist * spells; #ifdef __cplusplus } #endif diff --git a/src/kernel/spell_test.c b/src/kernel/spell_test.c index ebcb74dfe..dc8fc8d47 100644 --- a/src/kernel/spell_test.c +++ b/src/kernel/spell_test.c @@ -1,4 +1,7 @@ +#include + #include +#include #include #include @@ -7,23 +10,48 @@ #include -static void test_register_spell(CuTest * tc) +static void test_create_spell(CuTest * tc) { spell * sp; + test_cleanup(); + CuAssertPtrEquals(tc, 0, spells); CuAssertPtrEquals(tc, 0, find_spell("testspell")); - CuAssertPtrEquals(tc, spells, 0); - sp = create_spell("testspell"); - sp->magietyp = 5; - register_spell(sp); - CuAssertIntEquals(tc, 1, ql_length(spells)); + sp = create_spell("testspell", 0); CuAssertPtrEquals(tc, sp, find_spell("testspell")); + CuAssertPtrNotNull(tc, spells); +} + +static void test_create_duplicate_spell(CuTest * tc) +{ + spell *sp; + + test_cleanup(); + CuAssertPtrEquals(tc, 0, find_spell("testspell")); + + sp = create_spell("testspell", 0); + CuAssertPtrEquals(tc, 0, create_spell("testspell", 0)); + CuAssertPtrEquals(tc, sp, find_spell("testspell")); +} + +static void test_create_spell_with_id(CuTest * tc) +{ + spell *sp; + + test_cleanup(); + CuAssertPtrEquals(tc, 0, find_spellbyid(42)); + sp = create_spell("testspell", 42); + CuAssertPtrEquals(tc, sp, find_spellbyid(42)); + CuAssertPtrEquals(tc, 0, create_spell("testspell", 47)); + CuAssertPtrEquals(tc, 0, find_spellbyid(47)); } CuSuite *get_spell_suite(void) { CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, test_register_spell); + SUITE_ADD_TEST(suite, test_create_spell); + SUITE_ADD_TEST(suite, test_create_duplicate_spell); + SUITE_ADD_TEST(suite, test_create_spell_with_id); return suite; } diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index e57176d6c..123c1cf04 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1481,13 +1481,14 @@ static int parse_spells(xmlDocPtr doc) int k; spell_component *component; spell *sp; - int valid = 1; + unsigned int index; static int modes[] = { 0, PRECOMBATSPELL, COMBATSPELL, POSTCOMBATSPELL }; /* spellname */ + index = xml_ivalue(node, "index", 0); propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue != NULL); - sp = create_spell((const char *)propValue); + sp = create_spell((const char *)propValue, index); xmlFree(propValue); propValue = xmlGetProp(node, BAD_CAST "parameters"); @@ -1513,7 +1514,6 @@ static int parse_spells(xmlDocPtr doc) xmlFree(propValue); /* level, rank and flags */ - sp->id = xml_ivalue(node, "index", 0); sp->level = xml_ivalue(node, "level", -1); sp->rank = (char)xml_ivalue(node, "rank", -1); if (xml_bvalue(node, "los", false)) @@ -1544,7 +1544,6 @@ static int parse_spells(xmlDocPtr doc) cast = get_function(sp->sname); if (!cast) { log_error("no spell cast function registered for '%s'\n", sp->sname); - valid = 0; } strlcpy(zText+7, sp->sname, sizeof(zText)-7); fumble = get_function(zText); @@ -1558,10 +1557,8 @@ static int parse_spells(xmlDocPtr doc) if (strcmp((const char *)propValue, "cast") == 0) { if (fun) { cast = fun; - valid = 1; } else { log_error("unknown function name '%s' for spell '%s'\n", (const char *)propValue, sp->sname); - valid = 0; } } else if (fun && strcmp((const char *)propValue, "fumble") == 0) { fumble = fun; @@ -1576,49 +1573,43 @@ static int parse_spells(xmlDocPtr doc) xmlXPathFreeObject(result); } - if (valid) { - /* reading eressea/spells/spell/resource */ - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "resource", xpath); - if (result->nodesetval->nodeNr) { - sp->components = - (spell_component *) malloc(sizeof(spell_component) * - (result->nodesetval->nodeNr + 1)); - sp->components[result->nodesetval->nodeNr].type = 0; - } - for (component = sp->components, k = 0; k != result->nodesetval->nodeNr; - ++k) { - const resource_type *rtype; - xmlNodePtr node = result->nodesetval->nodeTab[k]; - propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue); - rtype = rt_find((const char *)propValue); - if (!rtype) { - log_error("spell %s uses unknown component %s.\n", sp->sname, (const char *)propValue); - xmlFree(propValue); - continue; - } - component->type = rtype; + /* reading eressea/spells/spell/resource */ + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "resource", xpath); + if (result->nodesetval->nodeNr) { + sp->components = + (spell_component *) malloc(sizeof(spell_component) * + (result->nodesetval->nodeNr + 1)); + sp->components[result->nodesetval->nodeNr].type = 0; + } + for (component = sp->components, k = 0; k != result->nodesetval->nodeNr; + ++k) { + const resource_type *rtype; + xmlNodePtr node = result->nodesetval->nodeTab[k]; + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue); + rtype = rt_find((const char *)propValue); + if (!rtype) { + log_error("spell %s uses unknown component %s.\n", sp->sname, (const char *)propValue); xmlFree(propValue); - component->amount = xml_ivalue(node, "amount", 1); - component->cost = SPC_FIX; - propValue = xmlGetProp(node, BAD_CAST "cost"); - if (propValue != NULL) { - if (strcmp((const char *)propValue, "linear") == 0) { - component->cost = SPC_LINEAR; - } else if (strcmp((const char *)propValue, "level") == 0) { - component->cost = SPC_LEVEL; - } - xmlFree(propValue); - } - component++; + continue; } - xmlXPathFreeObject(result); - } - - if (valid) { - register_spell(sp); + component->type = rtype; + xmlFree(propValue); + component->amount = xml_ivalue(node, "amount", 1); + component->cost = SPC_FIX; + propValue = xmlGetProp(node, BAD_CAST "cost"); + if (propValue != NULL) { + if (strcmp((const char *)propValue, "linear") == 0) { + component->cost = SPC_LINEAR; + } else if (strcmp((const char *)propValue, "level") == 0) { + component->cost = SPC_LEVEL; + } + xmlFree(propValue); + } + component++; } + xmlXPathFreeObject(result); } } diff --git a/src/tests.c b/src/tests.c index ab345bd88..46e5c4304 100644 --- a/src/tests.c +++ b/src/tests.c @@ -109,6 +109,7 @@ void test_cleanup(void) global.functions.wage = NULL; default_locale = 0; locales = 0; /* TODO: this is evil and leaky */ + free_spells(); /* TODO: this is just as bad! */ free_gamedata(); } diff --git a/src/util/critbit.c b/src/util/critbit.c index bfedfed7b..7474ec64b 100644 --- a/src/util/critbit.c +++ b/src/util/critbit.c @@ -46,6 +46,7 @@ void * make_external_node(const void * key, size_t keylen) ptrdiff_t numvalue = (char *)data - (char*)0; assert((numvalue&1)==0); #endif + assert(keylen); memcpy(data, &keylen, sizeof(size_t)); memcpy(data+sizeof(size_t), key, keylen); return (void*)(data+1); @@ -286,7 +287,7 @@ const void * cb_find(critbit_tree * cb, const void * key, size_t keylen) ptr = node->child[branch]; } from_external_node(ptr, &str, &len); - if (len==keylen && memcmp(key, str, keylen)==0) { + if (len>=keylen && memcmp(key, str, keylen)==0) { return str; } return 0; @@ -330,14 +331,15 @@ int cb_erase(critbit_tree * cb, const void * key, size_t keylen) } } -size_t cb_new_kv(const char *key, void * value, size_t len, void * dst) +size_t cb_new_kv(const char *key, size_t keylen, void * value, size_t len, void * out) { - size_t keylen = strlen(key)+1; + char * dst = (char*)out; if (dst!=key) { memcpy(dst, key, keylen); } - memcpy((char*)dst+keylen, value, len); - return len+keylen; + dst[keylen] = 0; + memcpy(dst+keylen+1, value, len); + return len+keylen+1; } void cb_get_kv(const void *kv, void * value, size_t len) diff --git a/src/util/critbit.h b/src/util/critbit.h index 67534d83f..9ce95599b 100644 --- a/src/util/critbit.h +++ b/src/util/critbit.h @@ -47,7 +47,7 @@ void cb_clear(critbit_tree * cb); #define cb_find_prefix_str(cb, key, results, numresults, offset) \ cb_find_prefix(cb, (void *)key, strlen(key), results, numresults, offset) -size_t cb_new_kv(const char *key, void * value, size_t len, void * dst); +size_t cb_new_kv(const char *key, size_t keylen, void * value, size_t len, void * out); void cb_get_kv(const void *kv, void * value, size_t len); #ifdef __cplusplus diff --git a/src/util/functions.c b/src/util/functions.c index 7e22e7293..a1605cea4 100644 --- a/src/util/functions.c +++ b/src/util/functions.c @@ -45,6 +45,6 @@ void register_function(pf_generic fun, const char *name) size_t len = strlen(name); assert(len #include -#define QL_MAXSIZE 14 /* total struct is 64 bytes */ -#define QL_LIMIT 7 +#define QL_MAXSIZE 14 /* max. number of elements unrolled into one node */ +#define QL_LIMIT 7 /* this many or fewer number in a node => attempt merge */ +/* The total size of this struct is 64 bytes on a 32-bit system with + * normal alignment. YMMV, so on a 64-bit system, twiddle the + * constants above */ struct quicklist { struct quicklist *next; int num_elements; @@ -170,11 +173,11 @@ int ql_advance(struct quicklist **iterator, int *index, int stride) void ql_free(struct quicklist *ql) { - if (!ql) - return; - if (ql->next) - ql_free(ql->next); - free(ql); + while (ql) { + quicklist * qn = ql; + ql = ql->next; + free(qn); + } } int ql_set_remove(struct quicklist **qlp, void *data) diff --git a/src/util/translation.c b/src/util/translation.c index 365b463c1..411b8aee0 100644 --- a/src/util/translation.c +++ b/src/util/translation.c @@ -162,8 +162,8 @@ void add_function(const char *symbol, evalfun parse) size_t len = strlen(symbol); assert(len+1+sizeof(parse)<=sizeof(buffer)); - cb_new_kv(symbol, &parse, sizeof(parse), buffer); - cb_insert(&functions, buffer, len+1+sizeof(parse)); + len = cb_new_kv(symbol, len, &parse, sizeof(parse), buffer); + cb_insert(&functions, buffer, len); } static evalfun find_function(const char *symbol) From 56083b1fcfec1975478d627c61a107b2f10e6a4d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 22 May 2012 22:01:48 -0700 Subject: [PATCH 246/400] fixing something. findresourcetype, I think? --- src/kernel/item.c | 74 ++++++++++++++++++++++-------------------- src/kernel/item_test.c | 4 +++ src/kernel/pool.c | 1 + src/tests_test.c | 1 + 4 files changed, 45 insertions(+), 35 deletions(-) diff --git a/src/kernel/item.c b/src/kernel/item.c index 5e842b26b..d7412ca9a 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -57,6 +57,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include static critbit_tree inames[MAXLOCALES]; +static critbit_tree rnames[MAXLOCALES]; static critbit_tree cb_resources; static critbit_tree cb_items; luxury_type *luxurytypes; @@ -1055,46 +1056,49 @@ int change_money(unit * u, int v) return 0; } -static local_names *rnames; -#define CB_BATCHSIZE 16 -const resource_type *findresourcetype(const char *name, - const struct locale *lang) +static int add_resourcename_cb(const void * match, const void * key, size_t keylen, void *data) { - const void * matches[CB_BATCHSIZE]; - local_names *rn = rnames; - variant token; + struct locale * lang = (struct locale *)data; + int i = locale_index(lang); + critbit_tree * cb = rnames+i; + resource_type *rtype; - while (rn) { - if (rn->lang == lang) - break; - rn = rn->next; - } - if (!rn) { - int m, offset = 0; - rn = (local_names *)calloc(1, sizeof(local_names)); - rn->next = rnames; - rn->lang = lang; - do { - m = cb_find_prefix(&cb_resources, "", 1, matches, CB_BATCHSIZE, offset); - if (m) { - int i; - offset += m; - for (i=0;i!=m;++i) { - resource_type *rtype; - cb_get_kv(matches[i], &rtype, sizeof(rtype)); - token.v = (void *)rtype; - addtoken(&rn->names, locale_string(lang, rtype->_name[0]), token); - addtoken(&rn->names, locale_string(lang, rtype->_name[1]), token); - } - } - } while (m==CB_BATCHSIZE); - rnames = rn; + cb_get_kv(match, &rtype, sizeof(rtype)); + for (i = 0; i!=2;++i) { + char buffer[128]; + const char * name = locale_string(lang, rtype->_name[i]); + + if (name && transliterate(buffer, sizeof(buffer), name)) { + size_t len = strlen(buffer); + assert(len+sizeof(rtype)names, name, &token) == E_TOK_NOMATCH) { - return 0; +const resource_type *findresourcetype(const char *name, const struct locale *lang) +{ + int i = locale_index(lang); + critbit_tree * cb = rnames+i; + char buffer[128]; + + if (transliterate(buffer, sizeof(buffer), name)) { + const void * match; + if (!cb->root) { + /* first-time initialization of resource names for this locale */ + cb_foreach(&cb_resources, "", 0, add_resourcename_cb, (void *)lang); + } + if (cb_find_prefix(cb, buffer, strlen(buffer), &match, 1, 0)) { + const resource_type * rtype = 0; + cb_get_kv(match, (void*)&rtype, sizeof(rtype)); + return rtype; + } + } else { + log_debug("findresourcetype: transliterate failed for '%s'\n", name); } - return (const resource_type *)token.v; + return 0; } attrib_type at_showitem = { diff --git a/src/kernel/item_test.c b/src/kernel/item_test.c index 98c79de69..d9c2172c3 100644 --- a/src/kernel/item_test.c +++ b/src/kernel/item_test.c @@ -55,10 +55,14 @@ void test_findresourcetype(CuTest * tc) lang = find_locale("de"); locale_setstring(lang, "horse", "Pferd"); + locale_setstring(lang, "peasant", "Bauer"); + rtype = rt_find("horse"); rresult = findresourcetype("Pferd", lang); CuAssertPtrNotNull(tc, rresult); CuAssertPtrEquals(tc, (void*)rtype, (void*)rresult); + + CuAssertPtrNotNull(tc, findresourcetype("Bauer", lang)); } CuSuite *get_item_suite(void) diff --git a/src/kernel/pool.c b/src/kernel/pool.c index e73bd4de0..3fc207b5d 100644 --- a/src/kernel/pool.c +++ b/src/kernel/pool.c @@ -271,6 +271,7 @@ int reserve_cmd(unit * u, struct order *ord) if (use) { new_set_resvalue(u, rtype, use); change_resource(u, rtype, use); + return use; } } return 0; diff --git a/src/tests_test.c b/src/tests_test.c index 3803ffa56..d89cccd39 100644 --- a/src/tests_test.c +++ b/src/tests_test.c @@ -1,3 +1,4 @@ +#include #include #include From eea6bdb888f061d288aac9a86d32f4875eab6389 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 23 May 2012 00:09:19 -0700 Subject: [PATCH 247/400] comparison to boolean values is bad form. --- src/gamecode/creport.c | 2 +- src/gamecode/laws.c | 16 ++++++++-------- src/items/phoenixcompass.c | 2 +- src/kernel/battle.c | 10 +++++----- src/kernel/curse.c | 2 +- src/kernel/item.c | 4 ++-- src/kernel/magic.c | 10 +++++----- src/kernel/move.c | 5 ++--- src/kernel/move_test.c | 6 +++--- src/kernel/spell.c | 3 ++- src/kernel/unit.c | 2 +- src/kernel/xmlreader.c | 3 +++ 12 files changed, 34 insertions(+), 31 deletions(-) diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index 6bea30d8e..bdeddc230 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -913,7 +913,7 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, pr = 0; if (f == u->faction || omniscient(f)) { show = u->items; - } else if (itemcloak == false && mode >= see_unit && !(a_fshidden + } else if (!itemcloak && mode >= see_unit && !(a_fshidden && a_fshidden->data.ca[1] == 1 && effskill(u, SK_STEALTH) >= 3)) { int n = report_items(u->items, result, MAX_INVENTORY, u, f); assert(n >= 0); diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 47a0d0727..7014f981e 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -1712,7 +1712,7 @@ static int name_cmd(unit * u, struct order *ord) switch (p) { case P_ALLIANCE: - if (foreign == false && f_get_alliance(u->faction)) { + if (!foreign && f_get_alliance(u->faction)) { alliance *al = u->faction->alliance; faction *lead = alliance_get_leader(al); if (lead == u->faction) { @@ -1729,7 +1729,7 @@ static int name_cmd(unit * u, struct order *ord) return rename_building(u, ord, b, getstrtoken()); case P_FACTION: - if (foreign == true) { + if (foreign) { faction *f; f = getfaction(); @@ -1767,7 +1767,7 @@ static int name_cmd(unit * u, struct order *ord) break; case P_SHIP: - if (foreign == true) { + if (foreign) { ship *sh = getship(r); unit *uo; @@ -1822,7 +1822,7 @@ static int name_cmd(unit * u, struct order *ord) break; case P_UNIT: - if (foreign == true) { + if (foreign) { unit *u2 = getunit(r, u->faction); if (!u2 || !cansee(u->faction, r, u2, 0)) { @@ -1981,7 +1981,7 @@ static int mail_cmd(unit * u, struct order *ord) } } - if (see == false) { + if (!see) { cmistake(u, ord, 66, MSG_MESSAGE); break; } @@ -2007,7 +2007,7 @@ static int mail_cmd(unit * u, struct order *ord) } } - if (see == false) { + if (!see) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); return 0; @@ -2171,7 +2171,7 @@ static int password_cmd(unit * u, struct order *ord) } } free(u->faction->passw); - if (pwok == false) { + if (!pwok) { cmistake(u, ord, 283, MSG_EVENT); u->faction->passw = strdup(itoa36(rng_int())); } else { @@ -3510,7 +3510,7 @@ static void setdefaults(unit * u) /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht * werden. */ - if (trade == true) { + if (trade) { /* fset(u, UFL_LONGACTION|UFL_NOTMOVING); */ set_order(&u->thisorder, NULL); } diff --git a/src/items/phoenixcompass.c b/src/items/phoenixcompass.c index fe35d444e..e26adfa8e 100644 --- a/src/items/phoenixcompass.c +++ b/src/items/phoenixcompass.c @@ -84,7 +84,7 @@ use_phoenixcompass(struct unit *u, const struct item_type *itype, * at the same distance was found and the device is confused */ if (closest_phoenix == NULL - || closest_phoenix->region == u->region || confusion == true) { + || closest_phoenix->region == u->region || confusion) { add_message(&u->faction->msgs, msg_message("phoenixcompass_confusion", "unit region command", u, u->region, ord)); return 0; diff --git a/src/kernel/battle.c b/src/kernel/battle.c index 1abf5ad82..ad01108b5 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -1742,7 +1742,7 @@ void do_combatmagic(battle * b, combatmagic_t was) continue; ord = create_order(K_CAST, lang, "'%s'", spell_name(sp, lang)); - if (cancast(mage, sp, 1, 1, ord) == false) { + if (!cancast(mage, sp, 1, 1, ord)) { free_order(ord); continue; } @@ -1761,7 +1761,7 @@ void do_combatmagic(battle * b, combatmagic_t was) if (power <= 0) { /* Effekt von Antimagie */ report_failed_spell(b, mage, sp); pay_spell(mage, sp, level, 1); - } else if (fumble(r, mage, sp, sp->level)) { + } else if (fumble(r, mage, sp, level)) { report_failed_spell(b, mage, sp); pay_spell(mage, sp, level, 1); } else { @@ -1837,7 +1837,7 @@ static void do_combatspell(troop at) return; } ord = create_order(K_CAST, lang, "'%s'", spell_name(sp, lang)); - if (cancast(caster, sp, 1, 1, ord) == false) { + if (!cancast(caster, sp, 1, 1, ord)) { fi->magic = 0; /* Kann nicht mehr Zaubern, kämpft nichtmagisch weiter */ return; } @@ -1846,7 +1846,7 @@ static void do_combatspell(troop at) if ((sl = get_combatspelllevel(caster, 1)) > 0) level = MIN(level, sl); - if (fumble(r, caster, sp, sp->level) == true) { + if (fumble(r, caster, sp, level)) { report_failed_spell(b, caster, sp); pay_spell(caster, sp, level, 1); return; @@ -3100,7 +3100,7 @@ static void print_header(battle * b) WARN_STATIC_BUFFER(); first = true; } - if (seematrix(f, s) == true) + if (seematrix(f, s)) lastf = sidename(s); else lastf = LOC(f->locale, "unknown_faction_dative"); diff --git a/src/kernel/curse.c b/src/kernel/curse.c index ce18998b6..016b96212 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -615,7 +615,7 @@ static void do_transfer_curse(curse * c, unit * u, unit * u2, int n) break; } - if (dogive == true) { + if (dogive) { curse *cnew = make_curse(c->magician, &u2->attribs, c->type, c->vigour, c->duration, c->effect, men); cnew->flags = c->flags; diff --git a/src/kernel/item.c b/src/kernel/item.c index f72bce744..e6380f400 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -1071,8 +1071,8 @@ static int add_resourcename_cb(const void * match, const void * key, size_t keyl if (name && transliterate(buffer, sizeof(buffer), name)) { size_t len = strlen(buffer); assert(len+sizeof(rtype)region, u, sp) == false) { + if (!knowsspell(u->region, u, sp)) { /* Fehler 'Spell not found' */ cmistake(u, ord, 173, MSG_MAGIC); return; @@ -976,7 +976,7 @@ cancast(unit * u, const spell * sp, int level, int range, struct order * ord) int itemanz; resource *reslist = NULL; - if (knowsspell(u->region, u, sp) == false) { + if (!knowsspell(u->region, u, sp)) { /* Diesen Zauber kennt die Einheit nicht */ cmistake(u, ord, 173, MSG_MAGIC); return false; @@ -1325,10 +1325,10 @@ boolean fumble(region * r, unit * u, const spell * sp, int cast_grade) if (sp->magietyp == M_DRAIG) { patzer += CHAOSPATZERCHANCE; } - if (is_cursed(u->attribs, C_MBOOST, 0) == true) { + if (is_cursed(u->attribs, C_MBOOST, 0)) { patzer += CHAOSPATZERCHANCE; } - if (is_cursed(u->attribs, C_FUMBLE, 0) == true) { + if (is_cursed(u->attribs, C_FUMBLE, 0)) { patzer += CHAOSPATZERCHANCE; } @@ -2830,7 +2830,7 @@ void magic(void) /* Prüfen, ob die realen Kosten für die gewünschten Stufe bezahlt * werden können */ - if (cancast(u, sp, co->level, co->distance, ord) == false) { + if (!cancast(u, sp, co->level, co->distance, ord)) { /* die Fehlermeldung wird in cancast generiert */ continue; } diff --git a/src/kernel/move.c b/src/kernel/move.c index f43655a3a..c7a669d9a 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -1790,7 +1790,7 @@ sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) break; } } else { - if (check_takeoff(sh, current_point, next_point) == false) { + if (!check_takeoff(sh, current_point, next_point)) { /* Schiff kann nicht ablegen */ cmistake(u, ord, 182, MSG_MOVE); break; @@ -2265,8 +2265,7 @@ static void piracy_cmd(unit * u, struct order *ord) region *rc = rconnect(r, dir); aff[dir].value = 0; aff[dir].target = 0; - if (rc && fval(rc->terrain, SWIM_INTO) - && check_takeoff(sh, r, rc) == true) { + if (rc && fval(rc->terrain, SWIM_INTO) && check_takeoff(sh, r, rc)) { for (sh2 = rc->ships; sh2; sh2 = sh2->next) { unit *cap = ship_owner(sh2); diff --git a/src/kernel/move_test.c b/src/kernel/move_test.c index 8b7bf4408..492722253 100644 --- a/src/kernel/move_test.c +++ b/src/kernel/move_test.c @@ -26,9 +26,9 @@ static void test_building_type_exists(CuTest * tc) b = new_building(btype, r, default_locale); CuAssertPtrNotNull(tc, b); - CuAssertTrue(tc, buildingtype_exists(r, NULL, true) == false); - CuAssertTrue(tc, buildingtype_exists(r, btype, true) == true); - CuAssertTrue(tc, buildingtype_exists(r, btype2, true) == false); + CuAssertTrue(tc, !buildingtype_exists(r, NULL, true)); + CuAssertTrue(tc, buildingtype_exists(r, btype, true)); + CuAssertTrue(tc, !buildingtype_exists(r, btype2, true)); } CuSuite *get_move_suite(void) diff --git a/src/kernel/spell.c b/src/kernel/spell.c index 36bdcaa10..654a2d19d 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -52,7 +52,8 @@ spell * create_spell(const char * name, unsigned int id) size_t len = strlen(name); assert(len+sizeof(sp)race, r, sk); skill += att_modification(u, sk); - if (noitem == false) { + if (!noitem) { skill = item_modification(u, sk, skill); } skill = skillmod(u->attribs, u, r, sk, skill, SMF_ALWAYS); diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 123c1cf04..84fbe5b19 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1490,6 +1490,9 @@ static int parse_spells(xmlDocPtr doc) assert(propValue != NULL); sp = create_spell((const char *)propValue, index); xmlFree(propValue); + if (!sp) { + continue; + } propValue = xmlGetProp(node, BAD_CAST "parameters"); if (propValue) { From db7ed24b3e4b43a0c2722f8bcb5f35e52dbf7f07 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 23 May 2012 12:42:14 -0700 Subject: [PATCH 248/400] adding spellbooks. spellbooks will take the level and magic school out of the spell definitions, and aggregate a list of spells with their minimum levels for learning from. factions will have a list of books they can learn from (different in E2 and E3 already). --- src/kernel.vcxproj | 4 ++++ src/kernel.vcxproj.filters | 12 ++++++++++ src/kernel/magic_test.c | 34 ++++++++++++++++++++++++++++ src/kernel/spellbook.c | 40 +++++++++++++++++++++++++++++++++ src/kernel/spellbook.h | 44 +++++++++++++++++++++++++++++++++++++ src/kernel/spellbook_test.c | 40 +++++++++++++++++++++++++++++++++ src/tests.c | 4 ++++ 7 files changed, 178 insertions(+) create mode 100644 src/kernel/magic_test.c create mode 100644 src/kernel/spellbook.c create mode 100644 src/kernel/spellbook.h create mode 100644 src/kernel/spellbook_test.c diff --git a/src/kernel.vcxproj b/src/kernel.vcxproj index 8c46343d9..6db6ea17b 100644 --- a/src/kernel.vcxproj +++ b/src/kernel.vcxproj @@ -106,6 +106,7 @@ + @@ -125,6 +126,8 @@ + + @@ -221,6 +224,7 @@ + diff --git a/src/kernel.vcxproj.filters b/src/kernel.vcxproj.filters index f385b7c1f..f09da757a 100644 --- a/src/kernel.vcxproj.filters +++ b/src/kernel.vcxproj.filters @@ -310,6 +310,15 @@ kernel + + kernel + + + kernel + + + kernel + @@ -603,5 +612,8 @@ attributes + + kernel + \ No newline at end of file diff --git a/src/kernel/magic_test.c b/src/kernel/magic_test.c new file mode 100644 index 000000000..c24c727c6 --- /dev/null +++ b/src/kernel/magic_test.c @@ -0,0 +1,34 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +void test_updatespells(CuTest * tc) +{ + struct faction * f; + spell * sp; + spellbook * book = 0; + + test_cleanup(); + + f = test_create_faction(0); + sp = create_spell("testspell", 0); + CuAssertPtrNotNull(tc, sp); + spellbook_add(&book, sp, 1); + + update_spellbook(f, 1); +} + +CuSuite *get_magic_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_updatespells); + return suite; +} diff --git a/src/kernel/spellbook.c b/src/kernel/spellbook.c new file mode 100644 index 000000000..00dd6de7a --- /dev/null +++ b/src/kernel/spellbook.c @@ -0,0 +1,40 @@ +#include +#include +#include + +#include "spellbook.h" + +void spellbook_add(spellbook **sbp, struct spell * sp, int level) +{ + spellbook_entry * sbe = (spellbook_entry *)malloc(sizeof(spellbook_entry)); + sbe->sp = sp; + sbe->level = level; + ql_push(sbp, sbe); +} + +void spellbook_free(spellbook *sb) +{ + quicklist *ql; + int qi; + + for (qi = 0, ql = sb; ql; ql_advance(&ql, &qi, 1)) { + spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi); + free(sbe); + } + ql_free(sb); +} + +int spellbook_foreach(spellbook *sb, int (*callback)(spellbook_entry *, void *), void * data) +{ + quicklist *ql; + int qi; + + for (qi = 0, ql = sb; ql; ql_advance(&ql, &qi, 1)) { + spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi); + int result = callback(sbe, data); + if (result) { + return result; + } + } + return 0; +} diff --git a/src/kernel/spellbook.h b/src/kernel/spellbook.h new file mode 100644 index 000000000..71eb427d2 --- /dev/null +++ b/src/kernel/spellbook.h @@ -0,0 +1,44 @@ +/* +Copyright (c) 1998-2012, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_SPELLBOOK_H +#define H_KRNL_SPELLBOOK_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct spell; + +typedef struct spellbook_entry { + struct spell * sp; + int level; +} spellbook_entry; + +typedef struct quicklist spellbook; + +spellbook * school_books[MAXMAGIETYP]; + +void spellbook_add(spellbook **sbp, struct spell * sp, int level); +int spellbook_foreach(spellbook *sb, int (*callback)(spellbook_entry *, void *), void * data); +void spellbook_free(spellbook *sb); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/kernel/spellbook_test.c b/src/kernel/spellbook_test.c new file mode 100644 index 000000000..c4adad24d --- /dev/null +++ b/src/kernel/spellbook_test.c @@ -0,0 +1,40 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + + +int count_spell_cb(spellbook_entry * sbe, void * ptr) +{ + int * counter = (int *)ptr; + ++*counter; + return 0; +} + +void test_spellbook(CuTest * tc) +{ + spell * sp; + spellbook * sb = 0; + int counter = 0; + + sp = create_spell("testspell", 0); + spellbook_add(&sb, sp, 1); + CuAssertPtrNotNull(tc, sb); + spellbook_foreach(sb, count_spell_cb, &counter); + CuAssertIntEquals(tc, 1, counter); + spellbook_free(sb); +} + +CuSuite *get_spellbook_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_spellbook); + return suite; +} diff --git a/src/tests.c b/src/tests.c index 46e5c4304..c73b2bb18 100644 --- a/src/tests.c +++ b/src/tests.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include #include #include @@ -50,9 +52,11 @@ int RunAllTests(void) /* kernel */ CuSuiteAddSuite(suite, get_curse_suite()); CuSuiteAddSuite(suite, get_item_suite()); + CuSuiteAddSuite(suite, get_magic_suite()); CuSuiteAddSuite(suite, get_move_suite()); CuSuiteAddSuite(suite, get_reports_suite()); CuSuiteAddSuite(suite, get_ship_suite()); + CuSuiteAddSuite(suite, get_spellbook_suite()); CuSuiteAddSuite(suite, get_building_suite()); CuSuiteAddSuite(suite, get_spell_suite()); CuSuiteAddSuite(suite, get_battle_suite()); From f45a49427780897e355f12a70fdbd5eafdde742b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 23 May 2012 15:19:21 -0700 Subject: [PATCH 249/400] new datafile version: spell names are now unique (or will be soon), and writing the magic school with each is irrelevant. --- src/kernel/magic.c | 12 ++++++------ src/kernel/magic.h | 6 ++++-- src/kernel/version.h | 3 ++- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 2d8382fb8..1da2e01b8 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -344,7 +344,7 @@ sc_mage *get_mage(const unit * u) static int read_seenspell(attrib * a, void *owner, struct storage *store) { int i; - spell *sp = NULL; + spell *sp = 0; char token[32]; store->r_tok_buf(store, token, sizeof(token)); @@ -352,11 +352,12 @@ static int read_seenspell(attrib * a, void *owner, struct storage *store) if (i != 0) { sp = find_spellbyid((unsigned int) i); } else { - int mtype; - mtype = store->r_int(store); + if (store->versionr_int(store); /* ignore mtype */ + } sp = find_spell(token); if (!sp) { - log_error("read_seenspell: could not find spell '%s' in school '%s'\n", token, magic_school[mtype]); + log_error("read_seenspell: could not find spell '%s'\n", token); } } if (!sp) { @@ -371,7 +372,6 @@ write_seenspell(const attrib * a, const void *owner, struct storage *store) { const spell *sp = (const spell *)a->data.v; store->w_tok(store, sp->sname); - store->w_int(store, sp->magietyp); } attrib_type at_seenspell = { @@ -423,7 +423,7 @@ static boolean has_spell(quicklist * ql, const spell * sp) } /** update the spellbook with a new level -* Written for Eressea 1.1 +* Written for E3 */ void update_spellbook(faction * f, int level) { diff --git a/src/kernel/magic.h b/src/kernel/magic.h index 931ccf8f6..152e7118e 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -158,13 +158,15 @@ typedef struct sc_mage { char *sname; char *syntax; char *parameter; - magic_t magietyp; int sptyp; int rank; /* Reihenfolge der Zauber */ - int level; /* Stufe des Zaubers */ struct spell_component *components; spell_f cast; fumble_f patzer; + + /* this is not so much the spell's data, but the school's studying data */ + magic_t magietyp; + int level; /* Stufe des Zaubers */ } spell; /* ------------------------------------------------------------- */ diff --git a/src/kernel/version.h b/src/kernel/version.h index d2b6ba3b9..c179b99fb 100644 --- a/src/kernel/version.h +++ b/src/kernel/version.h @@ -67,6 +67,7 @@ #define FOSS_VERSION 336 /* the open source release */ #define OWNER_2_VERSION 337 /* region owners contain an alliance */ #define FIX_WATCHERS_VERSION 338 /* fixed storage of watchers */ +#define UNIQUE_SPELLS_VERSION 339 /* turn 775, spell names are now unique globally, not just per school */ #define MIN_VERSION CURSETYPE_VERSION /* minimal datafile we support */ -#define RELEASE_VERSION FIX_WATCHERS_VERSION /* current datafile */ +#define RELEASE_VERSION UNIQUE_SPELLS_VERSION /* current datafile */ From 92e96689bb1e2cd1562d2820ef9e3022b33583ec Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 23 May 2012 20:22:12 -0700 Subject: [PATCH 250/400] spellbooks fully operational (and could be loaded from XML definitions if I had them) fixed the cleanup between tests to properly free locales --- src/bindings/bindings.c | 9 ++++++ src/build/kernel.c | 1 + src/kernel/magic.c | 28 ++++++++++++++++++ src/kernel/magic.h | 4 ++- src/kernel/magic_test.c | 38 ++++++++++++++++++++++-- src/kernel/spellbook.c | 38 ++++++++++++++++++++---- src/kernel/spellbook.h | 12 ++++++-- src/kernel/spellbook_test.c | 22 ++++++++++---- src/kernel/xmlreader.c | 58 +++++++++++++++++++++++++++++++++++-- src/tests.c | 5 ++-- src/util/language.c | 20 +++++++++++++ src/util/language.h | 3 +- 12 files changed, 217 insertions(+), 21 deletions(-) diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index 964b2f588..34cefe183 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -38,6 +38,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include #include #include @@ -684,6 +685,7 @@ static int tolua_set_alliance_name(lua_State * L) return 0; } +#ifdef WRITE_SPELLS #include #include #include @@ -755,6 +757,7 @@ static int tolua_write_spells(lua_State * L) xmlFreeDoc(doc); return 0; } +#endif static int config_get_ships(lua_State * L) { @@ -975,6 +978,7 @@ static int tolua_get_spell_text(lua_State * L) return 1; } +#ifdef TODO static int tolua_get_spell_school(lua_State * L) { spell *self = (spell *) tolua_tousertype(L, 1, 0); @@ -988,6 +992,7 @@ static int tolua_get_spell_level(lua_State * L) lua_pushnumber(L, self->level); return 1; } +#endif static int tolua_get_spell_name(lua_State * L) { @@ -1177,8 +1182,10 @@ int tolua_eressea_open(lua_State * L) { tolua_function(L, TOLUA_CAST "__tostring", tolua_get_spell_name); tolua_variable(L, TOLUA_CAST "name", tolua_get_spell_name, 0); +#ifdef TODO tolua_variable(L, TOLUA_CAST "school", tolua_get_spell_school, 0); tolua_variable(L, TOLUA_CAST "level", tolua_get_spell_level, 0); +#endif tolua_variable(L, TOLUA_CAST "text", tolua_get_spell_text, 0); } tolua_endmodule(L); tolua_module(L, TOLUA_CAST "eventbus", 1); @@ -1263,7 +1270,9 @@ int tolua_eressea_open(lua_State * L) tolua_function(L, TOLUA_CAST "translate", &tolua_translate); tolua_function(L, TOLUA_CAST "rng_int", tolua_rng_int); tolua_function(L, TOLUA_CAST "spells", tolua_get_spells); +#ifdef WRITE_SPELLS tolua_function(L, TOLUA_CAST "write_spells", tolua_write_spells); +#endif tolua_function(L, TOLUA_CAST "read_xml", tolua_read_xml); } tolua_endmodule(L); return 1; diff --git a/src/build/kernel.c b/src/build/kernel.c index 9ac333f94..22e8992b8 100644 --- a/src/build/kernel.c +++ b/src/build/kernel.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 1da2e01b8..78eabe9b3 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -18,6 +18,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +#include #include "magic.h" #include "building.h" @@ -35,6 +36,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "ship.h" #include "skill.h" #include "spell.h" +#include "spellbook.h" #include "teleport.h" #include "terrain.h" #include "unit.h" @@ -49,6 +51,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include +#include #include #include #include @@ -2924,3 +2927,28 @@ struct quicklist **get_spelllist(struct sc_mage *mage, struct faction *f) } return NULL; } + +static critbit_tree cb_spellbooks; + +spellbook * get_spellbook(const char * name) +{ + char buffer[64]; + spellbook * result; + const void * match; + + if (cb_find_prefix(&cb_spellbooks, name, strlen(name), &match, 1, 0)) { + cb_get_kv(match, &result, sizeof(result)); + } else { + size_t len = strlen(name); + result = create_spellbook(name); + assert(strlen(name)+sizeof(result)name); + CuAssertStrEquals(tc, "derp", derp->name); + + sp = create_spell(sname, 0); + spellbook_add(herp, sp, 1); + CuAssertPtrNotNull(tc, sp); + entry = spellbook_get(herp, sname); + CuAssertPtrNotNull(tc, entry); + CuAssertPtrEquals(tc, sp, entry->sp); + CuAssertPtrEquals(tc, 0, spellbook_get(derp, sname)); + + test_cleanup(); + herp = get_spellbook("herp"); + CuAssertPtrNotNull(tc, herp); + CuAssertPtrEquals(tc, 0, spellbook_get(herp, sname)); +} + CuSuite *get_magic_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_updatespells); + SUITE_ADD_TEST(suite, test_spellbooks); return suite; } diff --git a/src/kernel/spellbook.c b/src/kernel/spellbook.c index 00dd6de7a..3f32b12bb 100644 --- a/src/kernel/spellbook.c +++ b/src/kernel/spellbook.c @@ -1,15 +1,27 @@ #include #include +#include +#include #include #include "spellbook.h" -void spellbook_add(spellbook **sbp, struct spell * sp, int level) +spellbook * create_spellbook(const char * name) +{ + spellbook *result = (spellbook *)malloc(sizeof(spellbook)); + result->name = strdup(name); + result->spells = 0; + return result; +} + +void spellbook_add(spellbook *sb, struct spell * sp, int level) { spellbook_entry * sbe = (spellbook_entry *)malloc(sizeof(spellbook_entry)); + + assert(sb); sbe->sp = sp; sbe->level = level; - ql_push(sbp, sbe); + ql_push(&sb->spells, sbe); } void spellbook_free(spellbook *sb) @@ -17,11 +29,12 @@ void spellbook_free(spellbook *sb) quicklist *ql; int qi; - for (qi = 0, ql = sb; ql; ql_advance(&ql, &qi, 1)) { + assert(sb); + for (qi = 0, ql = sb->spells; ql; ql_advance(&ql, &qi, 1)) { spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi); free(sbe); } - ql_free(sb); + ql_free(sb->spells); } int spellbook_foreach(spellbook *sb, int (*callback)(spellbook_entry *, void *), void * data) @@ -29,7 +42,7 @@ int spellbook_foreach(spellbook *sb, int (*callback)(spellbook_entry *, void *), quicklist *ql; int qi; - for (qi = 0, ql = sb; ql; ql_advance(&ql, &qi, 1)) { + for (qi = 0, ql = sb->spells; ql; ql_advance(&ql, &qi, 1)) { spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi); int result = callback(sbe, data); if (result) { @@ -38,3 +51,18 @@ int spellbook_foreach(spellbook *sb, int (*callback)(spellbook_entry *, void *), } return 0; } + +spellbook_entry * spellbook_get(spellbook *sb, const char * name) +{ + quicklist *ql; + int qi; + + for (qi = 0, ql = sb->spells; ql; ql_advance(&ql, &qi, 1)) { + spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi); + if (strcmp(name, sbe->sp->sname)==0) { + return sbe; + } + } + return 0; +} + diff --git a/src/kernel/spellbook.h b/src/kernel/spellbook.h index 71eb427d2..f4724ec5b 100644 --- a/src/kernel/spellbook.h +++ b/src/kernel/spellbook.h @@ -24,19 +24,25 @@ extern "C" { #endif struct spell; +struct quicklist; typedef struct spellbook_entry { struct spell * sp; int level; } spellbook_entry; -typedef struct quicklist spellbook; +typedef struct spellbook +{ + char * name; + struct quicklist * spells; +} spellbook; -spellbook * school_books[MAXMAGIETYP]; +spellbook * create_spellbook(const char * name); -void spellbook_add(spellbook **sbp, struct spell * sp, int level); +void spellbook_add(spellbook *sbp, struct spell * sp, int level); int spellbook_foreach(spellbook *sb, int (*callback)(spellbook_entry *, void *), void * data); void spellbook_free(spellbook *sb); +spellbook_entry * spellbook_get(spellbook *sb, const char * name); #ifdef __cplusplus } diff --git a/src/kernel/spellbook_test.c b/src/kernel/spellbook_test.c index c4adad24d..62d8fa5ea 100644 --- a/src/kernel/spellbook_test.c +++ b/src/kernel/spellbook_test.c @@ -18,23 +18,35 @@ int count_spell_cb(spellbook_entry * sbe, void * ptr) return 0; } -void test_spellbook(CuTest * tc) +void test_named_spellbooks(CuTest * tc) { spell * sp; - spellbook * sb = 0; + spellbook * sb; int counter = 0; - sp = create_spell("testspell", 0); - spellbook_add(&sb, sp, 1); + sb = create_spellbook("spells"); CuAssertPtrNotNull(tc, sb); + CuAssertStrEquals(tc, "spells", sb->name); + + sp = create_spell("testspell", 0); + spellbook_add(sb, sp, 1); + CuAssertPtrNotNull(tc, sb->spells); + spellbook_foreach(sb, count_spell_cb, &counter); CuAssertIntEquals(tc, 1, counter); + +#ifdef TODO + /* try adding the same spell twice. that should fail */ + spellbook_add(sb, sp, 1); + spellbook_foreach(sb, count_spell_cb, &counter); + CuAssertIntEquals(tc, 1, counter); +#endif spellbook_free(sb); } CuSuite *get_spellbook_suite(void) { CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, test_spellbook); + SUITE_ADD_TEST(suite, test_named_spellbooks); return suite; } diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 84fbe5b19..d8fdfd1e7 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -26,6 +26,7 @@ without prior permission by the authors of Eressea. #include "terrain.h" #include "skill.h" #include "spell.h" +#include "spellbook.h" #include "calendar.h" /* util includes */ @@ -1461,6 +1462,58 @@ static int parse_equipment(xmlDocPtr doc) return 0; } +static int parse_spellbooks(xmlDocPtr doc) +{ + xmlXPathContextPtr xpath = xmlXPathNewContext(doc); + xmlXPathObjectPtr spellbooks; + + /* reading eressea/spells/spell */ + spellbooks = xmlXPathEvalExpression(BAD_CAST "/eressea/spells/spellbook", xpath); + + if (spellbooks->nodesetval != NULL) { + xmlNodeSetPtr nodes = spellbooks->nodesetval; + int i, k; + + for (i = 0; i != nodes->nodeNr; ++i) { + xmlXPathObjectPtr result; + xmlNodePtr node = nodes->nodeTab[i]; + xmlChar *propValue; + spellbook * sb; + + propValue = xmlGetProp(node, BAD_CAST "name"); + assert(propValue != NULL); + sb = get_spellbook((const char *)propValue); + xmlFree(propValue); + + xpath->node = node; + result = xmlXPathEvalExpression(BAD_CAST "entry", xpath); + + if (result->nodesetval->nodeNr > 0) { + for (k = 0; k != result->nodesetval->nodeNr; ++k) { + xmlNodePtr node = result->nodesetval->nodeTab[k]; + spell * sp = 0; + int level = xml_ivalue(node, "level", -1); + + propValue = xmlGetProp(node, BAD_CAST "name"); + if (propValue) { + sp = find_spell((const char *)propValue); + xmlFree(propValue); + } + if (sp && level>0) { + spellbook_add(sb, sp, level); + } else { + log_error("invalid entry at index '%d' in spellbook '%s'\n", k, sb->name); + } + } + } + xmlXPathFreeObject(result); + } + } + xmlXPathFreeObject(spellbooks); + xmlXPathFreeContext(xpath); + return 0; +} + static int parse_spells(xmlDocPtr doc) { xmlXPathContextPtr xpath = xmlXPathNewContext(doc); @@ -1505,7 +1558,7 @@ static int parse_spells(xmlDocPtr doc) sp->syntax = strdup((const char *)propValue); xmlFree(propValue); } - +#ifdef TODO /* no longer need it, spellbooks! */ /* magic type */ propValue = xmlGetProp(node, BAD_CAST "type"); assert(propValue != NULL); @@ -1515,7 +1568,7 @@ static int parse_spells(xmlDocPtr doc) } assert(sp->magietyp != MAXMAGIETYP); xmlFree(propValue); - +#endif /* level, rank and flags */ sp->level = xml_ivalue(node, "level", -1); sp->rank = (char)xml_ivalue(node, "rank", -1); @@ -2332,6 +2385,7 @@ void register_xmlreader(void) xml_register_callback(parse_buildings); /* requires resources */ xml_register_callback(parse_ships); /* requires terrains */ xml_register_callback(parse_spells); /* requires resources */ + xml_register_callback(parse_spellbooks); /* requires spells */ xml_register_callback(parse_equipment); /* requires spells */ xml_register_callback(parse_races); /* requires spells */ xml_register_callback(parse_calendar); diff --git a/src/tests.c b/src/tests.c index c73b2bb18..a78268590 100644 --- a/src/tests.c +++ b/src/tests.c @@ -112,8 +112,9 @@ void test_cleanup(void) global.functions.maintenance = NULL; global.functions.wage = NULL; default_locale = 0; - locales = 0; /* TODO: this is evil and leaky */ - free_spells(); /* TODO: this is just as bad! */ + free_locales(); /* TODO: this is evil and leaky */ + free_spells(); + free_spellbooks(); free_gamedata(); } diff --git a/src/util/language.c b/src/util/language.c index 917a51626..d50c55d6d 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -234,3 +234,23 @@ void ** get_translations(const struct locale *lang, int index) } return lstrs[0].tokens + index; } + +void free_locales(void) +{ + while (locales) { + int i; + locale * next = locales->next; + + for (i=0; i!=SMAXHASH; ++i) { + while (locales->strings[i]) { + struct locale_str * strings = locales->strings[i]; + free(strings->key); + free(strings->str); + locales->strings[i] = strings->nexthash; + free(strings); + } + } + free(locales); + locales = next; + } +} \ No newline at end of file diff --git a/src/util/language.h b/src/util/language.h index e851865a0..eb7c81986 100644 --- a/src/util/language.h +++ b/src/util/language.h @@ -29,8 +29,9 @@ extern "C" { /** managing multiple locales: **/ extern struct locale *find_locale(const char *name); extern struct locale *make_locale(const char *key); + extern void free_locales(void); -/** operations on locales: **/ + /** operations on locales: **/ extern void locale_setstring(struct locale *lang, const char *key, const char *value); extern const char *locale_getstring(const struct locale *lang, From 9b3234a067cd5031bd56354f9ca1f7f549d1b2ae Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 23 May 2012 21:06:19 -0700 Subject: [PATCH 251/400] fix the xmlreader to not assert on invalid data --- src/kernel/xmlreader.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index d8fdfd1e7..3f7422488 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1481,9 +1481,13 @@ static int parse_spellbooks(xmlDocPtr doc) spellbook * sb; propValue = xmlGetProp(node, BAD_CAST "name"); - assert(propValue != NULL); - sb = get_spellbook((const char *)propValue); - xmlFree(propValue); + if (propValue) { + sb = get_spellbook((const char *)propValue); + xmlFree(propValue); + } else { + log_error("spellbook at index '%d' has n name\n", i); + continue; + } xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "entry", xpath); @@ -1494,7 +1498,7 @@ static int parse_spellbooks(xmlDocPtr doc) spell * sp = 0; int level = xml_ivalue(node, "level", -1); - propValue = xmlGetProp(node, BAD_CAST "name"); + propValue = xmlGetProp(node, BAD_CAST "spell"); if (propValue) { sp = find_spell((const char *)propValue); xmlFree(propValue); From 9c7d2097a564327c1901c5ef8846e1a88ea584ab Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 23 May 2012 21:50:17 -0700 Subject: [PATCH 252/400] add xml spellbooks for the six magic schools this is being read, but not used by the code yet. --- res/de/strings.xml | 28 +++------------------------- res/spellbooks/cerddor.xml | 5 +++++ res/spellbooks/draig.xml | 5 +++++ res/spellbooks/gray.xml | 4 ++++ res/spellbooks/gwyrrd.xml | 4 ++++ res/spellbooks/illaun.xml | 6 ++++++ res/spellbooks/tybied.xml | 6 ++++++ res/spells.xml | 10 +++++++++- 8 files changed, 42 insertions(+), 26 deletions(-) create mode 100644 res/spellbooks/cerddor.xml create mode 100644 res/spellbooks/draig.xml create mode 100644 res/spellbooks/gray.xml create mode 100644 res/spellbooks/gwyrrd.xml create mode 100644 res/spellbooks/illaun.xml create mode 100644 res/spellbooks/tybied.xml diff --git a/res/de/strings.xml b/res/de/strings.xml index d3900f625..7c93018cb 100644 --- a/res/de/strings.xml +++ b/res/de/strings.xml @@ -3978,10 +3978,6 @@ Zeitdehnung Double Time - - Vertrauten rufen - Summon Familiar - Rüstschild Shield Shine @@ -4440,9 +4436,9 @@ Erschaffe ein Flammenschwert Create A Flamesword - + Vertrauten rufen - Call Familiar + Summon Familiar Chaossog @@ -4528,10 +4524,6 @@ Traumbilder entwirren Remove Dreams - - Vertrauten rufen - Call Familiar - Tod des Geistes Mental Death @@ -4713,13 +4705,6 @@ Kraft seines Gesangs ab. - - - Einem erfahrenen Magier wird irgendwann auf seinen Wanderungen ein - ungewöhnliches Exemplar einer Gattung begegnen, welches sich dem - Magier anschließen wird. - - Dieses Ritual ermöglicht es, eine Einheit, egal welcher Art, in die @@ -4906,13 +4891,6 @@ erkennen. - - - Einem erfahrenen Magier wird irgendwann auf seinen Wanderungen ein - ungewöhnliches Exemplar einer Gattung begegnen, welches sich dem - Magier anschließen wird. - - Dieses kräftezehrende Ritual beschwört mit Hilfe einer Kugel aus @@ -6127,7 +6105,7 @@ minor one of their kind to fulfill the sword with his power.' - + Einem erfahrenen Magier wird irgendwann auf seinen Wanderungen ein ungewöhnliches Exemplar einer Gattung begegnen, diff --git a/res/spellbooks/cerddor.xml b/res/spellbooks/cerddor.xml new file mode 100644 index 000000000..3d558e6d7 --- /dev/null +++ b/res/spellbooks/cerddor.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/res/spellbooks/draig.xml b/res/spellbooks/draig.xml new file mode 100644 index 000000000..1300a08b1 --- /dev/null +++ b/res/spellbooks/draig.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/res/spellbooks/gray.xml b/res/spellbooks/gray.xml new file mode 100644 index 000000000..9c3b9b797 --- /dev/null +++ b/res/spellbooks/gray.xml @@ -0,0 +1,4 @@ + + + + diff --git a/res/spellbooks/gwyrrd.xml b/res/spellbooks/gwyrrd.xml new file mode 100644 index 000000000..f2db419eb --- /dev/null +++ b/res/spellbooks/gwyrrd.xml @@ -0,0 +1,4 @@ + + + + diff --git a/res/spellbooks/illaun.xml b/res/spellbooks/illaun.xml new file mode 100644 index 000000000..f6238ccb5 --- /dev/null +++ b/res/spellbooks/illaun.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/spellbooks/tybied.xml b/res/spellbooks/tybied.xml new file mode 100644 index 000000000..5ed41e431 --- /dev/null +++ b/res/spellbooks/tybied.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/res/spells.xml b/res/spells.xml index 080365c55..246e1f6d5 100644 --- a/res/spells.xml +++ b/res/spells.xml @@ -1,5 +1,13 @@ - + + + + + + + + + From 5ddb77274ac056314bf017f1bcfbddd24d3a67b3 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 23 May 2012 22:24:31 -0700 Subject: [PATCH 253/400] fix spellbook data for example server remove duplicate spells --- res/de/strings.xml | 22 ---------- res/spellbooks/cerddor.xml | 12 +++--- res/spellbooks/draig.xml | 13 +++--- res/spellbooks/gray.xml | 11 +++-- res/spellbooks/gwyrrd.xml | 11 +++-- res/spellbooks/illaun.xml | 14 +++--- res/spellbooks/tybied.xml | 15 ++++--- res/spells.xml | 87 +++++--------------------------------- 8 files changed, 56 insertions(+), 129 deletions(-) diff --git a/res/de/strings.xml b/res/de/strings.xml index 7c93018cb..14a8c764f 100644 --- a/res/de/strings.xml +++ b/res/de/strings.xml @@ -4318,10 +4318,6 @@ Erwecke Ents Awakening Of The Ents - - Vertrauten binden - Bind Familiar - Segne Steinkreis Bless Stone Circle @@ -5735,15 +5731,6 @@ cause, but after a while they will sink back into their slumber. - - Einem erfahrenen Druidem wird - irgendwann auf seinen Wanderungen ein - ungewöhnliches Exemplar einer Gattung begegnen, - welches sich dem Druiden anschließen wird. - Once during his travels, the seasoned - druid will meet an extraordinary creature of its - species that will join him. - Dieses Ritual segnet einen Steinkreis, der zuvor aus Steinen und etwas Holz gebaut @@ -6404,15 +6391,6 @@ be packed to the brim and even the beggars will not go hungry. - - Einem erfahrenen Magier wird - irgendwann auf seinen Wanderungen ein ungewöhnliches - Exemplar einer Gattung begegnen, welches sich dem Magier - anschließen wird. - Once during his travels, the seasoned - magician will meet an extraordinary creature of its species - that will join him. - Mit diesem Zauber greift der Magier direkt den Geist seiner Gegner an. Ein Schlag aus diff --git a/res/spellbooks/cerddor.xml b/res/spellbooks/cerddor.xml index 3d558e6d7..50e1dbf0c 100644 --- a/res/spellbooks/cerddor.xml +++ b/res/spellbooks/cerddor.xml @@ -1,5 +1,7 @@ - - - - - + + + + + + + diff --git a/res/spellbooks/draig.xml b/res/spellbooks/draig.xml index 1300a08b1..592516d75 100644 --- a/res/spellbooks/draig.xml +++ b/res/spellbooks/draig.xml @@ -1,5 +1,8 @@ - - - - - + + + + + + + + diff --git a/res/spellbooks/gray.xml b/res/spellbooks/gray.xml index 9c3b9b797..6ce74e537 100644 --- a/res/spellbooks/gray.xml +++ b/res/spellbooks/gray.xml @@ -1,4 +1,7 @@ - - - - + + + + + + + diff --git a/res/spellbooks/gwyrrd.xml b/res/spellbooks/gwyrrd.xml index f2db419eb..264bc53e4 100644 --- a/res/spellbooks/gwyrrd.xml +++ b/res/spellbooks/gwyrrd.xml @@ -1,4 +1,7 @@ - - - - + + + + + + + diff --git a/res/spellbooks/illaun.xml b/res/spellbooks/illaun.xml index f6238ccb5..259fe68d8 100644 --- a/res/spellbooks/illaun.xml +++ b/res/spellbooks/illaun.xml @@ -1,6 +1,8 @@ - - - - - - + + + + + + + + diff --git a/res/spellbooks/tybied.xml b/res/spellbooks/tybied.xml index 5ed41e431..2965ec782 100644 --- a/res/spellbooks/tybied.xml +++ b/res/spellbooks/tybied.xml @@ -1,6 +1,9 @@ - - - - - - + + + + + + + + + diff --git a/res/spells.xml b/res/spells.xml index 246e1f6d5..b7866e016 100644 --- a/res/spells.xml +++ b/res/spells.xml @@ -8,26 +8,27 @@ - - + + + + + + + + + + - - - - - - - @@ -43,25 +44,11 @@ - - - - - - - - - - - - - - @@ -70,25 +57,11 @@ - - - - - - - - - - - - - - @@ -103,25 +76,11 @@ - - - - - - - - - - - - - - @@ -129,38 +88,12 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - From 3514218dbaacc03a00387a47814162e3036ce1a8 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 24 May 2012 00:56:54 -0700 Subject: [PATCH 254/400] factions have working spellbooks update of spellbooks for E3 should be functional old data file is getting read, and levels guessed? --- src/bindings/bind_faction.c | 7 +- src/gamecode/laws.c | 11 ++- src/kernel/faction.c | 5 +- src/kernel/faction.h | 2 +- src/kernel/magic.c | 188 ++++++++++++++++-------------------- src/kernel/magic.h | 4 +- src/kernel/magic_test.c | 15 ++- src/kernel/save.c | 57 ++++++++++- src/kernel/spell.c | 20 +++- src/kernel/spellbook.c | 6 +- src/kernel/spellbook.h | 2 +- src/kernel/spellbook_test.c | 14 ++- src/kernel/version.h | 7 +- src/kernel/xmlreader.c | 2 +- 14 files changed, 207 insertions(+), 133 deletions(-) diff --git a/src/bindings/bind_faction.c b/src/bindings/bind_faction.c index 40aa6b113..97abfa521 100644 --- a/src/bindings/bind_faction.c +++ b/src/bindings/bind_faction.c @@ -23,6 +23,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include #include #include @@ -448,11 +449,13 @@ static int tolua_faction_tostring(lua_State * L) return 1; } +#ifdef TODO /* these usertypes are undefined */ static int tolua_faction_get_spells(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); - return tolua_quicklist_push(L, "spell_list", "spell", self->spellbook); + return tolua_quicklist_push(L, "spellbook", "spellbook_entry", self->spellbook->spells); } +#endif void tolua_faction_open(lua_State * L) { @@ -479,7 +482,9 @@ void tolua_faction_open(lua_State * L) &tolua_faction_set_info); tolua_variable(L, TOLUA_CAST "units", tolua_faction_get_units, NULL); tolua_variable(L, TOLUA_CAST "heroes", tolua_faction_get_heroes, NULL); +#ifdef TODO tolua_variable(L, TOLUA_CAST "spells", tolua_faction_get_spells, 0); +#endif tolua_variable(L, TOLUA_CAST "maxheroes", tolua_faction_get_maxheroes, NULL); tolua_variable(L, TOLUA_CAST "password", tolua_faction_get_password, diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 7014f981e..9fdfd964a 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -57,6 +57,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include /* for volcanoes in emigration (needs a flag) */ @@ -3692,6 +3693,7 @@ static void defaultorders(void) /* GANZ WICHTIG! ALLE GEÄNDERTEN SPRÜCHE NEU ANZEIGEN */ /* GANZ WICHTIG! FÜGT AUCH NEUE ZAUBER IN DIE LISTE DER BEKANNTEN EIN */ /* ************************************************************ */ +#define COMMONSPELLS 1 /* number of new common spells per level */ #define MAXMAGES 128 /* should be enough */ static void update_spells(void) { @@ -3717,7 +3719,14 @@ static void update_spells(void) } if (FactionSpells() && maxlevel > f->max_spelllevel) { - update_spellbook(f, maxlevel); + static spellbook * common_spells; + if (!common_spells) { + const char *common_school = get_param(global.parameters, "rules.magic.common"); + common_spells = get_spellbook(common_school ? common_school : "common"); + } + if (common_spells) { + pick_random_spells(f, maxlevel, common_spells, COMMONSPELLS); + } } for (i = 0; i != n; ++i) { updatespelllist(mages[i]); diff --git a/src/kernel/faction.c b/src/kernel/faction.c index 92cd0ac6a..f477b0858 100644 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -28,6 +28,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "plane.h" #include "race.h" #include "region.h" +#include "spellbook.h" #include "terrain.h" #include "unit.h" #include "version.h" @@ -287,8 +288,8 @@ void destroyfaction(faction * f) return; fset(f, FFL_QUIT); - ql_free(f->spellbook); - f->spellbook = NULL; + spellbook_free(f->spellbook); + f->spellbook = 0; while (f->battles) { struct bmsg *bm = f->battles; diff --git a/src/kernel/faction.h b/src/kernel/faction.h index 377f4f305..ec82bbe51 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -73,7 +73,7 @@ extern "C" { char *passw; char *override; int max_spelllevel; - struct quicklist *spellbook; + struct spellbook *spellbook; const struct locale *locale; int lastorders; int age; diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 78eabe9b3..8d80846d5 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -393,30 +393,6 @@ static boolean already_seen(const faction * f, const spell * sp) return false; } -static boolean know_school(const faction * f, magic_t school) -{ - static int common = MAXMAGIETYP; - if (f->magiegebiet == school) - return true; - if (common == MAXMAGIETYP) { - const char *common_school = - get_param(global.parameters, "rules.magic.common"); - if (common_school) { - for (common = 0; common != MAXMAGIETYP; ++common) { - if (strcmp(common_school, magic_school[common]) == 0) - break; - } - if (common == MAXMAGIETYP) { - common = M_NONE; - } - } else { - return false; - } - } - return school == common; -} - -#define COMMONSPELLS 1 /* number of new common spells per level */ #define MAXSPELLS 256 static boolean has_spell(quicklist * ql, const spell * sp) @@ -425,93 +401,100 @@ static boolean has_spell(quicklist * ql, const spell * sp) return ql_set_find(&ql, &qi, sp) != 0; } -/** update the spellbook with a new level -* Written for E3 -*/ -void update_spellbook(faction * f, int level) +static void update_spells(faction * f, sc_mage * mage, int level, const spellbook *book) { - spell *commonspells[MAXSPELLS]; - int qi, numspells = 0; - quicklist *ql; + boolean ismonster = is_monsters(f); + quicklist **dst, *ql = book->spells; + int qi; - for (qi = 0, ql = spells; ql; ql_advance(&ql, &qi, 1)) { - spell *sp = (spell *) ql_get(ql, qi); - if (sp->magietyp == M_COMMON && level > f->max_spelllevel - && sp->level <= level) { - commonspells[numspells++] = sp; - } else { - if (know_school(f, sp->magietyp) && sp->level <= level) { - ql_set_insert(&f->spellbook, sp); + dst = get_spelllist(mage, f); + for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { + spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi); + if (sbe->level <= level) { + spell * sp = sbe->sp; + + if (!u_hasspell(mage, sp)) { + add_spell(dst, sp); + add_spellname(mage, sp); + } + if (!ismonster && !already_seen(f, sp)) { + a_add(&f->attribs, a_new(&at_reportspell))->data.v = sp; + a_add(&f->attribs, a_new(&at_seenspell))->data.v = sp; } } } - while (numspells > 0 && level > f->max_spelllevel) { - int i; - for (i = 0; i != COMMONSPELLS; ++i) { - int maxspell = numspells; - int spellno = -1; - spell *sp; - do { - if (spellno == maxspell) { - --maxspell; - } - spellno = rng_int() % maxspell; - sp = commonspells[spellno]; - } - while (maxspell > 0 && sp && sp->level <= f->max_spelllevel - && !has_spell(f->spellbook, sp)); - - if (sp) { - ql_set_insert(&f->spellbook, sp); - commonspells[spellno] = 0; - } - } - ++f->max_spelllevel; - } } void updatespelllist(unit * u) { int sk = eff_skill(u, SK_MAGIC, u->region); - quicklist *ql = spells; - int qi; struct sc_mage *mage = get_mage(u); - boolean ismonster = is_monsters(u->faction); - quicklist **dst; - if (mage->magietyp == M_GRAY) { - /* Magier mit M_GRAY bekommen weder Sprüche angezeigt noch - * neue Sprüche in ihre List-of-known-spells. Das sind zb alle alten - * Drachen, die noch den Skill Magie haben, und alle familiars */ + /* Magier mit M_GRAY bekommen weder Sprüche angezeigt noch + * neue Sprüche in ihre List-of-known-spells. Das sind zb alle alten + * Drachen, die noch den Skill Magie haben, und alle familiars */ + if (mage->magietyp != M_GRAY) { + spellbook * book; + book = get_spellbook(magic_school[mage->magietyp]); + update_spells(u->faction, mage, sk, book); + + if (FactionSpells()) { + update_spells(u->faction, mage, sk, u->faction->spellbook); + } + } +} + +/** update the spellbook with a new level +* Written for E3 +*/ +void pick_random_spells(faction * f, int level, spellbook * book, int num_spells) +{ + spell *commonspells[MAXSPELLS]; + int qi, numspells = 0; + quicklist *ql; + + if (level <= f->max_spelllevel) { return; } - if (FactionSpells()) { - ql = u->faction->spellbook; - } - dst = get_spelllist(mage, u->faction); - - for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { - spell *sp = (spell *) ql_get(ql, qi); - if (sp->level <= sk) { - boolean know = u_hasspell(mage, sp); - - if (know || sp->magietyp == M_COMMON - || know_school(u->faction, sp->magietyp)) { - faction *f = u->faction; - - if (!know) { - add_spell(dst, sp); - add_spellname(mage, sp); - } - if (!ismonster && !already_seen(u->faction, sp)) { - a_add(&f->attribs, a_new(&at_reportspell))->data.v = sp; - a_add(&f->attribs, a_new(&at_seenspell))->data.v = sp; - } - } + for (qi = 0, ql = book->spells; ql; ql_advance(&ql, &qi, 1)) { + spellbook_entry * sbe = (spellbook_entry *) ql_get(ql, qi); + spell * sp = sbe->sp; + if (sbe->level <= level) { + commonspells[numspells++] = sp; } } + while (numspells > 0 && level > f->max_spelllevel) { + int i; + + ++f->max_spelllevel; + for (i = 0; i < num_spells; ++i) { + int maxspell = numspells; + int spellno = -1; + spell *sp = 0; + while (!sp && maxspell>0) { + spellno = rng_int() % maxspell; + sp = commonspells[spellno]; + if (sp->level>f->max_spelllevel) { + commonspells[spellno] = commonspells[maxspell]; + commonspells[maxspell--] = sp; + sp = 0; + } else if (spellbook_get(f->spellbook, sp)) { + commonspells[spellno] = commonspells[numspells--]; + if (maxspell>numspells) { + maxspell = numspells; + } + sp = 0; + } + } + + if (spellnospellbook, sp, f->max_spelllevel); + commonspells[spellno] = commonspells[numspells--]; + } + } + } } /* ------------------------------------------------------------- */ @@ -950,19 +933,7 @@ boolean knowsspell(const region * r, const unit * u, const spell * sp) return false; } /* steht der Spruch in der Spruchliste? */ - if (!u_hasspell(mage, sp)) { - /* ist der Spruch aus einem anderen Magiegebiet? */ - if (know_school(u->faction, sp->magietyp)) { - return false; - } - if (eff_skill(u, SK_MAGIC, u->region) >= sp->level) { - log_warning("%s ist hat die erforderliche Stufe, kennt aber %s nicht.\n", unitname(u), spell_name(sp, default_locale)); - } - return false; - } - - /* hier sollten alle potentiellen Fehler abgefangen sein */ - return true; + return u_hasspell(mage, sp)!=0; } /* Um einen Spruch zu beherrschen, muss der Magier die Stufe des @@ -1318,14 +1289,17 @@ boolean fumble(region * r, unit * u, const spell * sp, int cast_grade) struct building *b = inside_building(u); const struct building_type *btype = b ? b->type : NULL; int fumble_enabled = get_param_int(global.parameters, "magic.fumble.enable", 1); + sc_mage * mage; if (!fumble_enabled) { return false; } if (btype) patzer -= btype->fumblebonus; + /* CHAOSPATZERCHANCE 10 : +10% Chance zu Patzern */ - if (sp->magietyp == M_DRAIG) { + mage = get_mage(u); + if (mage->magietyp == M_DRAIG) { patzer += CHAOSPATZERCHANCE; } if (is_cursed(u->attribs, C_MBOOST, 0)) { diff --git a/src/kernel/magic.h b/src/kernel/magic.h index b7c9d8a2b..b129368e9 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -165,7 +165,7 @@ typedef struct sc_mage { fumble_f patzer; /* this is not so much the spell's data, but the school's studying data */ - magic_t magietyp; + magic_t __magietyp; int level; /* Stufe des Zaubers */ } spell; @@ -274,7 +274,7 @@ typedef struct sc_mage { /* fügt den Spruch mit der Id spellid der Spruchliste der Einheit hinzu. */ int u_hasspell(const sc_mage *mage, const struct spell *sp); /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ - void update_spellbook(struct faction *f, int level); + void pick_random_spells(struct faction *f, int level, struct spellbook * book, int num_spells); void updatespelllist(struct unit *u); /* fügt alle Zauber des Magiegebietes der Einheit, deren Stufe kleiner * als das aktuelle Magietalent ist, in die Spruchliste der Einheit diff --git a/src/kernel/magic_test.c b/src/kernel/magic_test.c index 7f8994d18..49960933d 100644 --- a/src/kernel/magic_test.c +++ b/src/kernel/magic_test.c @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -12,7 +13,7 @@ void test_updatespells(CuTest * tc) { - struct faction * f; + faction * f; spell * sp; spellbook *book = 0; @@ -26,7 +27,11 @@ void test_updatespells(CuTest * tc) CuAssertPtrNotNull(tc, book); spellbook_add(book, sp, 1); - update_spellbook(f, 1); + CuAssertIntEquals(tc, 0, ql_length(f->spellbook->spells)); + pick_random_spells(f, 1, book, 1); + CuAssertPtrNotNull(tc, f->spellbook); + CuAssertIntEquals(tc, 1, ql_length(f->spellbook->spells)); + CuAssertPtrNotNull(tc, spellbook_get(f->spellbook, sp)); } void test_spellbooks(CuTest * tc) @@ -48,15 +53,15 @@ void test_spellbooks(CuTest * tc) sp = create_spell(sname, 0); spellbook_add(herp, sp, 1); CuAssertPtrNotNull(tc, sp); - entry = spellbook_get(herp, sname); + entry = spellbook_get(herp, sp); CuAssertPtrNotNull(tc, entry); CuAssertPtrEquals(tc, sp, entry->sp); - CuAssertPtrEquals(tc, 0, spellbook_get(derp, sname)); + /* CuAssertPtrEquals(tc, 0, spellbook_get(derp, sname)); */ test_cleanup(); herp = get_spellbook("herp"); CuAssertPtrNotNull(tc, herp); - CuAssertPtrEquals(tc, 0, spellbook_get(herp, sname)); + /* CuAssertPtrEquals(tc, 0, spellbook_get(herp, sname)); */ } CuSuite *get_magic_suite(void) diff --git a/src/kernel/save.c b/src/kernel/save.c index 65737396a..507592ab6 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -40,6 +40,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "ship.h" #include "skill.h" #include "spell.h" +#include "spellbook.h" #include "terrain.h" #include "terrainid.h" /* only for conversion code */ #include "unit.h" @@ -1203,6 +1204,56 @@ static ally **addally(const faction * f, ally ** sfp, int aid, int state) return &sf->next; } +static struct spellbook *read_spellbook(struct storage *store) +{ + spellbook * book = 0; + int level; + for (level=0;;++level) { + spell *sp; + char spname[64]; + + if (store->version < SPELLNAME_VERSION) { + int i = store->r_int(store); + if (i < 0) + break; + sp = find_spellbyid((unsigned int) i); + } else { + store->r_tok_buf(store, spname, sizeof(spname)); + if (strcmp(spname, "end") == 0) + break; + sp = find_spell(spname); + if (!sp) { + log_error("read_spells: could not find spell '%s'\n", spname); + } + } + if (store->version >= SPELLBOOK_VERSION) { + level = store->r_int(store); + } + if (sp) { + if (!book) { + book = create_spellbook(0); + } + spellbook_add(book, sp, level); + } + } + return book; +} + +static void write_spellbook(const struct spellbook *book, struct storage *store) +{ + quicklist *ql; + int qi; + + if (book) { + for (ql = book->spells, qi = 0; ql; ql_advance(&ql, &qi, 1)) { + spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi); + store->w_tok(store, sbe->sp->sname); + store->w_int(store, sbe->level); + } + } + store->w_tok(store, "end"); +} + /** Reads a faction from a file. * This function requires no context, can be called in any state. The * faction may not already exist, however. @@ -1340,9 +1391,9 @@ faction *readfaction(struct storage * store) } } read_groups(store, f); - f->spellbook = NULL; + f->spellbook = 0; if (store->version >= REGIONOWNER_VERSION) { - read_spells(&f->spellbook, f->magiegebiet, store); + f->spellbook = read_spellbook(store); } return f; } @@ -1405,7 +1456,7 @@ void writefaction(struct storage *store, const faction * f) store->w_id(store, 0); store->w_brk(store); write_groups(store, f->groups); - write_spells(f->spellbook, store); + write_spellbook(f->spellbook, store); } static void repair_unit(unit * u) { diff --git a/src/kernel/spell.c b/src/kernel/spell.c index 654a2d19d..e674796a5 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -69,12 +69,30 @@ spell * create_spell(const char * name, unsigned int id) return 0; } +static const char *sp_aliases[][2] = { + {"gwyrrdfamiliar", "summon_familiar"}, + {"illaunfamiliar", "summon_familiar"}, + {"draigfamiliar", "summon_familiar"}, + {NULL, NULL}, +}; + +static const char *sp_alias(const char *zname) +{ + int i; + for (i = 0; sp_aliases[i][0]; ++i) { + if (strcmp(sp_aliases[i][0], zname) == 0) + return sp_aliases[i][1]; + } + return zname; +} + spell *find_spell(const char *name) { const char * match; spell * sp = 0; + const char * alias = sp_alias(name); - match = cb_find_str(&cb_spells, name); + match = cb_find_str(&cb_spells, alias); if (match) { cb_get_kv(match, &sp, sizeof(sp)); } else { diff --git a/src/kernel/spellbook.c b/src/kernel/spellbook.c index 3f32b12bb..568096896 100644 --- a/src/kernel/spellbook.c +++ b/src/kernel/spellbook.c @@ -9,7 +9,7 @@ spellbook * create_spellbook(const char * name) { spellbook *result = (spellbook *)malloc(sizeof(spellbook)); - result->name = strdup(name); + result->name = name ? strdup(name) : 0; result->spells = 0; return result; } @@ -52,14 +52,14 @@ int spellbook_foreach(spellbook *sb, int (*callback)(spellbook_entry *, void *), return 0; } -spellbook_entry * spellbook_get(spellbook *sb, const char * name) +spellbook_entry * spellbook_get(spellbook *sb, struct spell * sp) { quicklist *ql; int qi; for (qi = 0, ql = sb->spells; ql; ql_advance(&ql, &qi, 1)) { spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi); - if (strcmp(name, sbe->sp->sname)==0) { + if (sp==sbe->sp) { return sbe; } } diff --git a/src/kernel/spellbook.h b/src/kernel/spellbook.h index f4724ec5b..6e5cc5ea3 100644 --- a/src/kernel/spellbook.h +++ b/src/kernel/spellbook.h @@ -42,7 +42,7 @@ spellbook * create_spellbook(const char * name); void spellbook_add(spellbook *sbp, struct spell * sp, int level); int spellbook_foreach(spellbook *sb, int (*callback)(spellbook_entry *, void *), void * data); void spellbook_free(spellbook *sb); -spellbook_entry * spellbook_get(spellbook *sb, const char * name); +spellbook_entry * spellbook_get(spellbook *sb, struct spell * sp); #ifdef __cplusplus } diff --git a/src/kernel/spellbook_test.c b/src/kernel/spellbook_test.c index 62d8fa5ea..29b3bd4b7 100644 --- a/src/kernel/spellbook_test.c +++ b/src/kernel/spellbook_test.c @@ -20,10 +20,15 @@ int count_spell_cb(spellbook_entry * sbe, void * ptr) void test_named_spellbooks(CuTest * tc) { - spell * sp; - spellbook * sb; + spell *sp; + spellbook *sb; + spellbook_entry *sbe; int counter = 0; + sb = create_spellbook(0); + CuAssertPtrNotNull(tc, sb); + CuAssertPtrEquals(tc, 0, sb->name); + sb = create_spellbook("spells"); CuAssertPtrNotNull(tc, sb); CuAssertStrEquals(tc, "spells", sb->name); @@ -32,6 +37,11 @@ void test_named_spellbooks(CuTest * tc) spellbook_add(sb, sp, 1); CuAssertPtrNotNull(tc, sb->spells); + sbe = spellbook_get(sb, sp); + CuAssertPtrNotNull(tc, sbe); + CuAssertIntEquals(tc, 1, sbe->level); + CuAssertPtrEquals(tc, sp, sbe->sp); + spellbook_foreach(sb, count_spell_cb, &counter); CuAssertIntEquals(tc, 1, counter); diff --git a/src/kernel/version.h b/src/kernel/version.h index c179b99fb..b7ec62b01 100644 --- a/src/kernel/version.h +++ b/src/kernel/version.h @@ -66,8 +66,9 @@ #define MOURNING_VERSION 335 /* mourning peasants */ #define FOSS_VERSION 336 /* the open source release */ #define OWNER_2_VERSION 337 /* region owners contain an alliance */ -#define FIX_WATCHERS_VERSION 338 /* fixed storage of watchers */ -#define UNIQUE_SPELLS_VERSION 339 /* turn 775, spell names are now unique globally, not just per school */ +#define FIX_WATCHERS_VERSION 338 /* fixed storage of watchers */ +#define UNIQUE_SPELLS_VERSION 339 /* turn 775, spell names are now unique globally, not just per school */ +#define SPELLBOOK_VERSION 340 /* turn 775, full spellbooks are stored for factions */ #define MIN_VERSION CURSETYPE_VERSION /* minimal datafile we support */ -#define RELEASE_VERSION UNIQUE_SPELLS_VERSION /* current datafile */ +#define RELEASE_VERSION SPELLBOOK_VERSION /* current datafile */ diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 3f7422488..bdeba293e 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1572,8 +1572,8 @@ static int parse_spells(xmlDocPtr doc) } assert(sp->magietyp != MAXMAGIETYP); xmlFree(propValue); -#endif /* level, rank and flags */ +#endif sp->level = xml_ivalue(node, "level", -1); sp->rank = (char)xml_ivalue(node, "rank", -1); if (xml_bvalue(node, "los", false)) From 6417f55ec6d7915d41351869e9e0ad5317f40402 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 24 May 2012 01:44:43 -0700 Subject: [PATCH 255/400] specify levels with magic attacks (step one to removing spell->level) --- res/spells.xml | 36 ++++++++++++++++++------------------ src/bindings/bind_unit.c | 8 +++++--- src/kernel/battle.c | 4 +++- src/kernel/magic.h | 1 - src/kernel/race.h | 1 + src/kernel/xmlreader.c | 4 ++++ 6 files changed, 31 insertions(+), 23 deletions(-) diff --git a/res/spells.xml b/res/spells.xml index b7866e016..4ec6f9fce 100644 --- a/res/spells.xml +++ b/res/spells.xml @@ -24,12 +24,12 @@ - + - + @@ -37,19 +37,19 @@ - + - + - + @@ -57,18 +57,18 @@ - + - + - + @@ -76,12 +76,12 @@ - + - + @@ -89,25 +89,25 @@ - + - + - + - + @@ -115,7 +115,7 @@ - + @@ -123,20 +123,20 @@ - + - + - + diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 3b0198d2c..1184617d8 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -453,7 +453,7 @@ static int tolua_unit_addnotice(lua_State * L) return 0; } -static void unit_castspell(unit * u, const char *name) +static void unit_castspell(unit * u, const char *name, int level) { quicklist *ql = spells; int qi; @@ -465,7 +465,7 @@ static void unit_castspell(unit * u, const char *name) log_error("spell '%s' has no function.\n", sp->sname); } else { castorder co; - create_castorder(&co, u, 0, sp, u->region, sp->level, sp->level * MagicPower(), 0, 0, 0); + create_castorder(&co, u, 0, sp, u->region, level, level * MagicPower(), 0, 0, 0); sp->cast(&co); free_castorder(&co); } @@ -477,7 +477,9 @@ static int tolua_unit_castspell(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); const char *str = tolua_tostring(L, 2, 0); - unit_castspell(self, str); + int level = (int)tolua_tonumber(L, 3, 1); + + unit_castspell(self, str, level); return 0; } diff --git a/src/kernel/battle.c b/src/kernel/battle.c index ad01108b5..d0d0f9a31 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -1896,7 +1896,9 @@ static void do_extra_spell(troop at, const att * a) if (sp->cast == NULL) { log_error("spell '%s' has no function.\n", sp->sname); } else { - cast_combatspell(at, sp, sp->level, sp->level * MagicPower()); + int level = a->level; + assert(a->level>0); + cast_combatspell(at, sp, level, level * MagicPower()); } } diff --git a/src/kernel/magic.h b/src/kernel/magic.h index b129368e9..5edefbd7d 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -165,7 +165,6 @@ typedef struct sc_mage { fumble_f patzer; /* this is not so much the spell's data, but the school's studying data */ - magic_t __magietyp; int level; /* Stufe des Zaubers */ } spell; diff --git a/src/kernel/race.h b/src/kernel/race.h index b1ec8f889..c2cafa01f 100644 --- a/src/kernel/race.h +++ b/src/kernel/race.h @@ -46,6 +46,7 @@ extern "C" { const struct spell *sp; } data; int flags; + int level; } att; struct param; diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index bdeba293e..008c6a4d1 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1956,6 +1956,10 @@ static int parse_races(xmlDocPtr doc) xmlFree(propValue); } else { attack->data.sp = xml_spell(node, "spell"); + if (attack->data.sp) { + attack->level = xml_ivalue(node, "level", 0); + assert(attack->level > 0 || attack->data.sp->level > 0); /* magical attacks need a level */ + } } attack->type = xml_ivalue(node, "type", 0); attack->flags = xml_ivalue(node, "flags", 0); From b8d8bac9ae7d98a304370e5c50f8effe0744fe3a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 24 May 2012 20:35:13 -0700 Subject: [PATCH 256/400] fix trying to add to null-spellbook. all unit tests pass. --- src/kernel/magic.c | 5 ++++- src/kernel/magic_test.c | 2 +- src/kernel/spellbook.c | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 8d80846d5..69166f220 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -480,7 +480,7 @@ void pick_random_spells(faction * f, int level, spellbook * book, int num_spells commonspells[spellno] = commonspells[maxspell]; commonspells[maxspell--] = sp; sp = 0; - } else if (spellbook_get(f->spellbook, sp)) { + } else if (f->spellbook && spellbook_get(f->spellbook, sp)) { commonspells[spellno] = commonspells[numspells--]; if (maxspell>numspells) { maxspell = numspells; @@ -490,6 +490,9 @@ void pick_random_spells(faction * f, int level, spellbook * book, int num_spells } if (spellnospellbook) { + f->spellbook = create_spellbook(0); + } spellbook_add(f->spellbook, sp, f->max_spelllevel); commonspells[spellno] = commonspells[numspells--]; } diff --git a/src/kernel/magic_test.c b/src/kernel/magic_test.c index 49960933d..ed6f1e684 100644 --- a/src/kernel/magic_test.c +++ b/src/kernel/magic_test.c @@ -27,7 +27,7 @@ void test_updatespells(CuTest * tc) CuAssertPtrNotNull(tc, book); spellbook_add(book, sp, 1); - CuAssertIntEquals(tc, 0, ql_length(f->spellbook->spells)); + CuAssertPtrEquals(tc, 0, f->spellbook); pick_random_spells(f, 1, book, 1); CuAssertPtrNotNull(tc, f->spellbook); CuAssertIntEquals(tc, 1, ql_length(f->spellbook->spells)); diff --git a/src/kernel/spellbook.c b/src/kernel/spellbook.c index 568096896..5002c14d1 100644 --- a/src/kernel/spellbook.c +++ b/src/kernel/spellbook.c @@ -57,6 +57,7 @@ spellbook_entry * spellbook_get(spellbook *sb, struct spell * sp) quicklist *ql; int qi; + assert(sb); for (qi = 0, ql = sb->spells; ql; ql_advance(&ql, &qi, 1)) { spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi); if (sp==sbe->sp) { From 6cb4322c1d9a57e89be3653201ad059f35cd6c22 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 24 May 2012 21:57:23 -0700 Subject: [PATCH 257/400] rename: spellbook_clear is more accurate --- src/kernel/faction.c | 3 ++- src/kernel/spellbook.c | 4 +++- src/kernel/spellbook.h | 2 +- src/kernel/spellbook_test.c | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/kernel/faction.c b/src/kernel/faction.c index f477b0858..d9c701a41 100644 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -288,7 +288,8 @@ void destroyfaction(faction * f) return; fset(f, FFL_QUIT); - spellbook_free(f->spellbook); + spellbook_clear(f->spellbook); + free(f->spellbook); f->spellbook = 0; while (f->battles) { diff --git a/src/kernel/spellbook.c b/src/kernel/spellbook.c index 5002c14d1..ad2a4c496 100644 --- a/src/kernel/spellbook.c +++ b/src/kernel/spellbook.c @@ -6,6 +6,8 @@ #include "spellbook.h" +#include + spellbook * create_spellbook(const char * name) { spellbook *result = (spellbook *)malloc(sizeof(spellbook)); @@ -24,7 +26,7 @@ void spellbook_add(spellbook *sb, struct spell * sp, int level) ql_push(&sb->spells, sbe); } -void spellbook_free(spellbook *sb) +void spellbook_clear(spellbook *sb) { quicklist *ql; int qi; diff --git a/src/kernel/spellbook.h b/src/kernel/spellbook.h index 6e5cc5ea3..81eb23a4b 100644 --- a/src/kernel/spellbook.h +++ b/src/kernel/spellbook.h @@ -41,7 +41,7 @@ spellbook * create_spellbook(const char * name); void spellbook_add(spellbook *sbp, struct spell * sp, int level); int spellbook_foreach(spellbook *sb, int (*callback)(spellbook_entry *, void *), void * data); -void spellbook_free(spellbook *sb); +void spellbook_clear(spellbook *sb); spellbook_entry * spellbook_get(spellbook *sb, struct spell * sp); #ifdef __cplusplus diff --git a/src/kernel/spellbook_test.c b/src/kernel/spellbook_test.c index 29b3bd4b7..c875a1941 100644 --- a/src/kernel/spellbook_test.c +++ b/src/kernel/spellbook_test.c @@ -51,7 +51,8 @@ void test_named_spellbooks(CuTest * tc) spellbook_foreach(sb, count_spell_cb, &counter); CuAssertIntEquals(tc, 1, counter); #endif - spellbook_free(sb); + spellbook_clear(sb); + free(sb); } CuSuite *get_spellbook_suite(void) From 707349d014d01fb34dbc61420e912189a321d9f4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 24 May 2012 22:10:18 -0700 Subject: [PATCH 258/400] at_reportspell is now a message about a spellbook-entry, not just a spell --- src/gamecode/creport.c | 9 +++++---- src/gamecode/report.c | 12 +++++++----- src/kernel/magic.c | 16 +++++++++++++--- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index bdeddc230..cbf0d3564 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -49,6 +49,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include #include #include #include @@ -1012,7 +1013,7 @@ static void cr_find_address(FILE * F, const faction * uf, quicklist * addresses) /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ -static void cr_reportspell(FILE * F, spell * sp, const struct locale *lang) +static void cr_reportspell(FILE * F, spell * sp, int level, const struct locale *lang) { int k; const char *name = @@ -1020,7 +1021,7 @@ static void cr_reportspell(FILE * F, spell * sp, const struct locale *lang) fprintf(F, "ZAUBER %d\n", hashstring(sp->sname)); fprintf(F, "\"%s\";name\n", name); - fprintf(F, "%d;level\n", sp->level); + fprintf(F, "%d;level\n", level); fprintf(F, "%d;rank\n", sp->rank); fprintf(F, "\"%s\";info\n", spell_info(sp, lang)); if (sp->parameter) @@ -1567,8 +1568,8 @@ report_computer(const char *filename, report_context * ctx, const char *charset) cr_find_address(F, f, ctx->addresses); a = a_find(f->attribs, &at_reportspell); while (a && a->type == &at_reportspell) { - spell *sp = (spell *) a->data.v; - cr_reportspell(F, sp, f->locale); + spellbook_entry *sbe = (spellbook_entry *) a->data.v; + cr_reportspell(F, sbe->sp, sbe->level, f->locale); a = a->next; } for (a = a_find(f->attribs, &at_showitem); a && a->type == &at_showitem; diff --git a/src/gamecode/report.c b/src/gamecode/report.c index c1bd48acc..fe58bf568 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -59,6 +59,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include @@ -214,13 +215,14 @@ rparagraph(FILE * F, const char *str, ptrdiff_t indent, int hanging_indent, } while (*begin); } -static void nr_spell(FILE * F, spell * sp, const struct locale *lang) +static void nr_spell(FILE * F, spellbook_entry * sbe, const struct locale *lang) { int bytes, k, itemanz, costtyp; int dh = 0; char buf[4096]; char *bufp = buf; size_t size = sizeof(buf) - 1; + spell * sp = sbe->sp; const char *params = sp->parameter; rnl(F); @@ -251,7 +253,7 @@ static void nr_spell(FILE * F, spell * sp, const struct locale *lang) *bufp = 0; rparagraph(F, buf, 0, 0, 0); - sprintf(buf, "%s %d", LOC(lang, "nr_spell_level"), sp->level); + sprintf(buf, "%s %d", LOC(lang, "nr_spell_level"), sbe->level); rparagraph(F, buf, 0, 0, 0); sprintf(buf, "%s %d", LOC(lang, "nr_spell_rank"), sp->rank); @@ -278,7 +280,7 @@ static void nr_spell(FILE * F, spell * sp, const struct locale *lang) } } else { if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR) { - itemanz *= sp->level; + itemanz *= sbe->level; } bytes = snprintf(bufp, size, "%d %s", itemanz, LOC(lang, resourcename(rtype, @@ -2301,8 +2303,8 @@ report_plaintext(const char *filename, report_context * ctx, rnl(F); centre(F, LOC(f->locale, "section_newspells"), true); while (a && a->type == &at_reportspell) { - spell *sp = (spell *) a->data.v; - nr_spell(F, sp, f->locale); + spellbook_entry *sbe = (spellbook_entry *) a->data.v; + nr_spell(F, sbe, f->locale); a = a->next; } } diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 69166f220..fff5008e3 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -86,10 +86,20 @@ const char *magic_school[MAXMAGIETYP] = { "common" }; -attrib_type at_reportspell = { - "reportspell", NULL, NULL, NULL, NO_WRITE, NO_READ -}; +static void a_init_reportspell(struct attrib *a) { + a->data.v = calloc(1, sizeof(spellbook_entry)); +} +static void a_finalize_reportspell(struct attrib *a) { + free(a->data.v); +} + +attrib_type at_reportspell = { + "reportspell", + a_init_reportspell, + a_finalize_reportspell, + 0, NO_WRITE, NO_READ +}; /** ** at_icastle ** TODO: separate castle-appearance from illusion-effects From 8ecda7b2030d42937e4c4129c5aa37635de2343e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 24 May 2012 22:26:05 -0700 Subject: [PATCH 259/400] factions have spellbooks and the read/write function for spellbooks is now accessible from other places (we'll need this for units) --- src/kernel/save.c | 4 ++-- src/kernel/save.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/kernel/save.c b/src/kernel/save.c index 507592ab6..545a45c6a 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1204,7 +1204,7 @@ static ally **addally(const faction * f, ally ** sfp, int aid, int state) return &sf->next; } -static struct spellbook *read_spellbook(struct storage *store) +struct spellbook *read_spellbook(struct storage *store) { spellbook * book = 0; int level; @@ -1239,7 +1239,7 @@ static struct spellbook *read_spellbook(struct storage *store) return book; } -static void write_spellbook(const struct spellbook *book, struct storage *store) +void write_spellbook(const struct spellbook *book, struct storage *store) { quicklist *ql; int qi; diff --git a/src/kernel/save.h b/src/kernel/save.h index 5d3770b26..41f1c4893 100644 --- a/src/kernel/save.h +++ b/src/kernel/save.h @@ -47,6 +47,9 @@ extern "C" { extern void read_items(struct storage *store, struct item **it); extern void write_items(struct storage *store, struct item *it); + extern struct spellbook *read_spellbook(struct storage *store); + extern void write_spellbook(const struct spellbook *book, struct storage *store); + extern void write_unit(struct storage *store, const struct unit *u); extern struct unit *read_unit(struct storage *store); From f5b35a9a2bdc0a60f68a73ad4e825019397d1fa9 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 24 May 2012 23:50:27 -0700 Subject: [PATCH 260/400] equipment sets that include spells now have levels on them and store in a spellbook. add some tests for equipment. --- res/equipment.xml | 48 +++++++++++++++---------------- src/kernel.vcxproj | 1 + src/kernel.vcxproj.filters | 3 ++ src/kernel/equipment.c | 33 ++++++++++++---------- src/kernel/equipment.h | 4 +-- src/kernel/equipment_test.c | 56 +++++++++++++++++++++++++++++++++++++ src/kernel/unit.c | 54 +++++++++++++++++------------------ src/kernel/xmlreader.c | 5 ++-- src/tests.c | 4 ++- 9 files changed, 136 insertions(+), 72 deletions(-) create mode 100644 src/kernel/equipment_test.c diff --git a/res/equipment.xml b/res/equipment.xml index 1a38ab808..a998ef712 100644 --- a/res/equipment.xml +++ b/res/equipment.xml @@ -32,9 +32,9 @@ - - - + + + @@ -48,10 +48,10 @@ - - - - + + + + @@ -59,12 +59,12 @@ - - - - - - + + + + + + @@ -75,9 +75,9 @@ - - - + + + @@ -87,9 +87,9 @@ - - - + + + @@ -99,16 +99,16 @@ - - + + - - - + + + diff --git a/src/kernel.vcxproj b/src/kernel.vcxproj index 6db6ea17b..78a213902 100644 --- a/src/kernel.vcxproj +++ b/src/kernel.vcxproj @@ -101,6 +101,7 @@ + diff --git a/src/kernel.vcxproj.filters b/src/kernel.vcxproj.filters index f09da757a..906d6566d 100644 --- a/src/kernel.vcxproj.filters +++ b/src/kernel.vcxproj.filters @@ -319,6 +319,9 @@ kernel + + kernel + diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index 740bf7703..44e275ce6 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -23,7 +23,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* kernel includes */ #include "item.h" #include "unit.h" +#include "faction.h" #include "race.h" +#include "spellbook.h" /* util includes */ #include @@ -43,13 +45,9 @@ equipment *create_equipment(const char *eqname) struct equipment *eq = *eqp; int i = eq ? strcmp(eq->name, eqname) : 1; if (i > 0) { - eq = malloc(sizeof(equipment)); + eq = (equipment *)calloc(1, sizeof(equipment)); eq->name = strdup(eqname); eq->next = *eqp; - eq->items = NULL; - eq->spells = NULL; - eq->subsets = NULL; - eq->callback = NULL; memset(eq->skills, 0, sizeof(eq->skills)); *eqp = eq; break; @@ -85,10 +83,13 @@ void equipment_setskill(equipment * eq, skill_t sk, const char *value) } } -void equipment_addspell(equipment * eq, spell * sp) +void equipment_addspell(equipment * eq, spell * sp, int level) { - if (eq != NULL) { - ql_set_insert(&eq->spells, sp); + if (eq) { + if (!eq->spellbook) { + eq->spellbook = create_spellbook(0); + } + spellbook_add(eq->spellbook, sp, level); } } @@ -140,16 +141,18 @@ void equip_unit_mask(struct unit *u, const struct equipment *eq, int mask) } if (mask & EQUIP_SPELLS) { - quicklist *ql = eq->spells; - if (ql) { - int qi; + if (eq->spellbook) { sc_mage *m = get_mage(u); + quicklist * ql = eq->spellbook->spells; + int qi; - assert(m || !"trying to equip spells on a non-mage!"); + if (!m) { + m = create_mage(u, u->faction?u->faction->magiegebiet:M_GRAY); + } for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { - spell *sp = (spell *) ql_get(ql, qi); - add_spell(&m->spells, sp); - add_spellname(m, sp); + spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi); + add_spell(&m->spells, sbe->sp); + add_spellname(m, sbe->sp); } } } diff --git a/src/kernel/equipment.h b/src/kernel/equipment.h index eae6a23c9..c6fd146c6 100644 --- a/src/kernel/equipment.h +++ b/src/kernel/equipment.h @@ -43,7 +43,7 @@ extern "C" { char *name; struct itemdata *items; char *skills[MAXSKILLS]; - struct quicklist *spells; + struct spellbook *spellbook; struct subset *subsets; struct equipment *next; void (*callback) (const struct equipment *, struct unit *); @@ -56,7 +56,7 @@ extern "C" { const struct item_type *itype, const char *value); extern void equipment_setskill(struct equipment *eq, skill_t sk, const char *value); - extern void equipment_addspell(struct equipment *eq, struct spell *sp); + extern void equipment_addspell(struct equipment *eq, struct spell *sp, int level); extern void equipment_setcallback(struct equipment *eq, void (*callback) (const struct equipment *, struct unit *)); diff --git a/src/kernel/equipment_test.c b/src/kernel/equipment_test.c new file mode 100644 index 000000000..d376ee644 --- /dev/null +++ b/src/kernel/equipment_test.c @@ -0,0 +1,56 @@ +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +void test_equipment(CuTest * tc) +{ + equipment * eq; + unit * u; + const item_type * it_horses; + const char * names[] = {"horse", "horse_p"}; + spell *sp; + sc_mage * mage; + + test_cleanup(); + skill_enabled[SK_MAGIC] = 1; + it_horses = test_create_itemtype(names); + CuAssertPtrNotNull(tc, it_horses); + sp = create_spell("testspell", 0); + CuAssertPtrNotNull(tc, sp); + + CuAssertPtrEquals(tc, 0, get_equipment("herpderp")); + eq = create_equipment("herpderp"); + CuAssertPtrEquals(tc, eq, get_equipment("herpderp")); + + equipment_setitem(eq, it_horses, "1"); + equipment_setskill(eq, SK_MAGIC, "5"); + equipment_addspell(eq, sp, 1); + + u = test_create_unit(0, 0); + equip_unit_mask(u, eq, EQUIP_ALL); + CuAssertIntEquals(tc, 1, i_get(u->items, it_horses)); + CuAssertIntEquals(tc, 5, get_level(u, SK_MAGIC)); + + mage = get_mage(u); + CuAssertPtrNotNull(tc, mage); + CuAssertPtrNotNull(tc, mage->spells); + CuAssertTrue(tc, u_hasspell(mage, sp)); +} + +CuSuite *get_equipment_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_equipment); + return suite; +} diff --git a/src/kernel/unit.c b/src/kernel/unit.c index e7844bd38..d868627ea 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1103,22 +1103,13 @@ void set_number(unit * u, int count) assert(count >= 0); assert(count <= UNIT_MAXSIZE); -#ifndef NDEBUG - assert(u->faction || count == 0); -#endif - if (count == 0) { u->flags &= ~(UFL_HERO); } - if (u->faction) { - if (playerrace(u->race)) { - u->faction->num_people += count - u->number; - } - u->number = (unsigned short)count; - } else if (u->number > 0) { - assert - (!"why doesn't this unit have a faction? this will fuck up num_people"); + if (u->faction && playerrace(u->race)) { + u->faction->num_people += count - u->number; } + u->number = (unsigned short)count; } boolean learn_skill(unit * u, skill_t sk, double chance) @@ -1415,15 +1406,22 @@ void name_unit(unit * u) } } else { char name[32]; - static const char * prefix[MAXLOCALES]; - int i = locale_index(u->faction->locale); - if (!prefix[i]) { - prefix[i] = LOC(u->faction->locale, "unitdefault"); + const char * result; + const struct locale * lang = u->faction ? u->faction->locale : default_locale; + if (lang) { + static const char * prefix[MAXLOCALES]; + int i = locale_index(lang); if (!prefix[i]) { - prefix[i] = parameters[P_UNIT]; + prefix[i] = LOC(lang, "unitdefault"); + if (!prefix[i]) { + prefix[i] = parameters[P_UNIT]; + } } + result = prefix[i]; + } else { + result = parameters[P_UNIT]; } - snprintf(name, sizeof(name), "%s %s", prefix[i], itoa36(u->no)); + snprintf(name, sizeof(name), "%s %s", result, itoa36(u->no)); unit_setname(u, name); } } @@ -1436,17 +1434,19 @@ void name_unit(unit * u) unit *create_unit(region * r, faction * f, int number, const struct race *urace, int id, const char *dname, unit * creator) { - unit *u = calloc(1, sizeof(unit)); + unit *u = (unit *)calloc(1, sizeof(unit)); assert(urace); - assert(f->alive); - u_setfaction(u, f); + if (f) { + assert(f->alive); + u_setfaction(u, f); - if (f->locale) { - order *deford = default_order(f->locale); - if (deford) { - set_order(&u->thisorder, NULL); - addlist(&u->orders, deford); + if (f->locale) { + order *deford = default_order(f->locale); + if (deford) { + set_order(&u->thisorder, NULL); + addlist(&u->orders, deford); + } } } u_seteffstealth(u, -1); @@ -1473,8 +1473,6 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace, } else { u->name = strdup(dname); } - if (count_unit(u)) - f->no_units++; if (creator) { attrib *a; diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 008c6a4d1..232ed917d 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1314,7 +1314,8 @@ static void add_spells(equipment * eq, xmlNodeSetPtr nsetItems) if (!sp) { log_error("no spell '%s' in school '%s' for equipment-set '%s'\n", (const char *)propValue, magic_school[mtype], eq->name); } else { - equipment_addspell(eq, sp); + int level = xml_ivalue(node, "level", sp->level); + equipment_addspell(eq, sp, level); } xmlFree(propValue); } @@ -1438,7 +1439,7 @@ static int parse_equipment(xmlDocPtr doc) xmlXPathFreeObject(xpathResult); xpathResult = xmlXPathEvalExpression(BAD_CAST "spell", xpath); - assert(!eq->spells); + assert(!eq->spellbook); add_spells(eq, xpathResult->nodesetval); xmlXPathFreeObject(xpathResult); diff --git a/src/tests.c b/src/tests.c index a78268590..e2ef1df7c 100644 --- a/src/tests.c +++ b/src/tests.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,7 @@ int RunAllTests(void) CuSuiteAddSuite(suite, get_umlaut_suite()); /* kernel */ CuSuiteAddSuite(suite, get_curse_suite()); + CuSuiteAddSuite(suite, get_equipment_suite()); CuSuiteAddSuite(suite, get_item_suite()); CuSuiteAddSuite(suite, get_magic_suite()); CuSuiteAddSuite(suite, get_move_suite()); @@ -101,7 +103,7 @@ struct faction *test_create_faction(const struct race *rc) struct unit *test_create_unit(struct faction *f, struct region *r) { - unit *u = create_unit(r, f, 1, f->race, 0, 0, 0); + unit *u = create_unit(r, f, 1, f?f->race:rc_find("human"), 0, 0, 0); return u; } From ae9f12c904f3e4154b82d5219fa60e58d71520e8 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 May 2012 12:46:00 -0700 Subject: [PATCH 261/400] added a test for pay_spell so I don't break it. --- src/bindings/bind_unit.c | 29 ++++++++++--------------- src/kernel/equipment.c | 12 ++++------- src/kernel/magic_test.c | 46 ++++++++++++++++++++++++++++++++++++++++ src/kernel/unit.c | 13 ++++++++++++ src/kernel/unit.h | 2 ++ 5 files changed, 76 insertions(+), 26 deletions(-) diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 1184617d8..e5fc11bf9 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -483,27 +483,20 @@ static int tolua_unit_castspell(lua_State * L) return 0; } -static int unit_addspell(unit * u, const char *name) -{ - sc_mage *m = get_mage(u); - spell *spadd = find_spell(name); - - if (!spadd) { - log_error("spell %s could not be found\n", name); - return EINVAL; - } else { - quicklist **starget = get_spelllist(m, u->faction); - add_spell(starget, spadd); - add_spellname(m, spadd); - } - return 0; -} - static int tolua_unit_addspell(lua_State * L) { - unit *self = (unit *) tolua_tousertype(L, 1, 0); + unit *u = (unit *) tolua_tousertype(L, 1, 0); const char *str = tolua_tostring(L, 2, 0); - int err = unit_addspell(self, str); + int err = 0; + spell *sp = find_spell(str); + + if (!sp) { + log_error("spell %s could not be found\n", str); + return EINVAL; + } else { + unit_add_spell(u, 0, sp); + } + lua_pushinteger(L, err); return 1; } diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index 44e275ce6..4e91cac81 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -130,29 +130,25 @@ void equip_unit_mask(struct unit *u, const struct equipment *eq, int mask) if (eq) { if (mask & EQUIP_SKILLS) { - skill_t sk; + int sk; for (sk = 0; sk != MAXSKILLS; ++sk) { if (eq->skills[sk] != NULL) { int i = dice_rand(eq->skills[sk]); if (i > 0) - set_level(u, sk, i); + set_level(u, (skill_t)sk, i); } } } if (mask & EQUIP_SPELLS) { if (eq->spellbook) { - sc_mage *m = get_mage(u); quicklist * ql = eq->spellbook->spells; int qi; + sc_mage * mage = get_mage(u); - if (!m) { - m = create_mage(u, u->faction?u->faction->magiegebiet:M_GRAY); - } for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi); - add_spell(&m->spells, sbe->sp); - add_spellname(m, sbe->sp); + unit_add_spell(u, mage, sbe->sp); } } } diff --git a/src/kernel/magic_test.c b/src/kernel/magic_test.c index ed6f1e684..4c41ef3e6 100644 --- a/src/kernel/magic_test.c +++ b/src/kernel/magic_test.c @@ -2,9 +2,13 @@ #include #include +#include #include +#include #include #include +#include +#include #include #include @@ -64,10 +68,52 @@ void test_spellbooks(CuTest * tc) /* CuAssertPtrEquals(tc, 0, spellbook_get(herp, sname)); */ } +void test_pay_spell(CuTest * tc) +{ + spell *sp; + unit * u; + faction * f; + region * r; + + test_cleanup(); + test_create_world(); + r = findregion(0, 0); + f = test_create_faction(0); + u = test_create_unit(f, r); + CuAssertPtrNotNull(tc, u); + + sp = create_spell("testspell", 0); + CuAssertPtrNotNull(tc, sp); + + sp->components = (spell_component *) calloc(4, sizeof(spell_component)); + sp->components[0].amount = 1; + sp->components[0].type = rt_find("money"); + sp->components[0].cost = SPC_FIX; + sp->components[1].amount = 1; + sp->components[1].type = rt_find("aura"); + sp->components[1].cost = SPC_LEVEL; + sp->components[2].amount = 1; + sp->components[2].type = rt_find("horse"); + sp->components[2].cost = SPC_LINEAR; + + set_level(u, SK_MAGIC, 5); + unit_add_spell(u, 0, sp); + + change_resource(u, rt_find("money"), 1); /* fix costs of 1 money */ + change_resource(u, rt_find("aura"), 3); /* leveled costs of 3 money */ + change_resource(u, rt_find("horse"), 3); /* leveled costs of 3 money */ + + pay_spell(u, sp, 3, 1); + CuAssertIntEquals(tc, 0, get_resource(u, rt_find("money"))); + CuAssertIntEquals(tc, 0, get_resource(u, rt_find("aura"))); + CuAssertIntEquals(tc, 0, get_resource(u, rt_find("horse"))); +} + CuSuite *get_magic_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_updatespells); SUITE_ADD_TEST(suite, test_spellbooks); + SUITE_ADD_TEST(suite, test_pay_spell); return suite; } diff --git a/src/kernel/unit.c b/src/kernel/unit.c index d868627ea..d7315df8d 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -30,6 +30,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "plane.h" #include "race.h" #include "region.h" +#include "spell.h" #include "save.h" #include "ship.h" #include "skill.h" @@ -1724,3 +1725,15 @@ const struct race *u_irace(const struct unit *u) } return u->race; } + +void unit_add_spell(unit * u, sc_mage * m, struct spell * sp) +{ + sc_mage *mage = m ? m : get_mage(u); + + if (!mage) { + log_debug("adding new spell %s to a previously non-mage unit %s\n", sp->sname, unitname(u)); + mage = create_mage(u, u->faction?u->faction->magiegebiet:M_GRAY); + } + add_spell(&mage->spells, sp); + add_spellname(mage, sp); +} diff --git a/src/kernel/unit.h b/src/kernel/unit.h index 1aab73569..cb0ab5f68 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -231,6 +231,8 @@ extern "C" { int unit_max_hp(const struct unit *u); void scale_number(struct unit *u, int n); + void unit_add_spell(struct unit * u, struct sc_mage * m, struct spell * sp); + extern struct attrib_type at_creator; #ifdef __cplusplus } From 88db0a8df7067f3204b65c84e8b5682e9fc95325 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 May 2012 15:35:11 -0700 Subject: [PATCH 262/400] change_resource did not return new value for some types --- src/kernel/item.c | 12 +++++------- src/kernel/pool.c | 1 + 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/kernel/item.c b/src/kernel/item.c index e6380f400..e9473ff10 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -66,36 +66,34 @@ potion_type *potiontypes; static int res_changeaura(unit * u, const resource_type * rtype, int delta) { assert(rtype != NULL); - change_spellpoints(u, delta); - return 0; + return change_spellpoints(u, delta); } static int res_changeperson(unit * u, const resource_type * rtype, int delta) { assert(rtype != NULL || !"not implemented"); scale_number(u, u->number + delta); - return 0; + return u->number; } static int res_changepermaura(unit * u, const resource_type * rtype, int delta) { assert(rtype != NULL); - change_maxspellpoints(u, delta); - return 0; + return change_maxspellpoints(u, delta); } static int res_changehp(unit * u, const resource_type * rtype, int delta) { assert(rtype != NULL); u->hp += delta; - return 0; + return u->hp; } static int res_changepeasants(unit * u, const resource_type * rtype, int delta) { assert(rtype != NULL && u->region->land); u->region->land->peasants += delta; - return 0; + return u->region->land->peasants; } int res_changeitem(unit * u, const resource_type * rtype, int delta) diff --git a/src/kernel/pool.c b/src/kernel/pool.c index 3fc207b5d..997bb3b30 100644 --- a/src/kernel/pool.c +++ b/src/kernel/pool.c @@ -79,6 +79,7 @@ int change_resource(unit * u, const resource_type * rtype, int change) i = change_maxspellpoints(u, change); else assert(!"undefined resource detected. rtype->uchange not initialized."); + assert(i==get_resource(u, rtype)); assert(i >= 0); if (i >= 100000000) { log_warning("%s has %d %s\n", unitname(u), i, rtype->_name[0]); From fef92e497105679ede8695dba8c29c55d115cecb Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 May 2012 15:38:24 -0700 Subject: [PATCH 263/400] added more test for pay_spell so I don't break it. --- src/kernel/magic_test.c | 92 +++++++++++++++++++++++++++++++++-------- 1 file changed, 75 insertions(+), 17 deletions(-) diff --git a/src/kernel/magic_test.c b/src/kernel/magic_test.c index 4c41ef3e6..b05c174b7 100644 --- a/src/kernel/magic_test.c +++ b/src/kernel/magic_test.c @@ -68,22 +68,10 @@ void test_spellbooks(CuTest * tc) /* CuAssertPtrEquals(tc, 0, spellbook_get(herp, sname)); */ } -void test_pay_spell(CuTest * tc) +static spell * test_magic_create_spell(void) { spell *sp; - unit * u; - faction * f; - region * r; - - test_cleanup(); - test_create_world(); - r = findregion(0, 0); - f = test_create_faction(0); - u = test_create_unit(f, r); - CuAssertPtrNotNull(tc, u); - sp = create_spell("testspell", 0); - CuAssertPtrNotNull(tc, sp); sp->components = (spell_component *) calloc(4, sizeof(spell_component)); sp->components[0].amount = 1; @@ -95,25 +83,95 @@ void test_pay_spell(CuTest * tc) sp->components[2].amount = 1; sp->components[2].type = rt_find("horse"); sp->components[2].cost = SPC_LINEAR; + return sp; +} + +void test_pay_spell(CuTest * tc) +{ + spell *sp; + unit * u; + faction * f; + region * r; + int level; + + test_cleanup(); + test_create_world(); + r = findregion(0, 0); + f = test_create_faction(0); + u = test_create_unit(f, r); + CuAssertPtrNotNull(tc, u); + + sp = test_magic_create_spell(); + CuAssertPtrNotNull(tc, sp); set_level(u, SK_MAGIC, 5); unit_add_spell(u, 0, sp); - change_resource(u, rt_find("money"), 1); /* fix costs of 1 money */ - change_resource(u, rt_find("aura"), 3); /* leveled costs of 3 money */ - change_resource(u, rt_find("horse"), 3); /* leveled costs of 3 money */ + change_resource(u, rt_find("money"), 1); + change_resource(u, rt_find("aura"), 3); + change_resource(u, rt_find("horse"), 3); - pay_spell(u, sp, 3, 1); + level = eff_spelllevel(u, sp, 3, 1); + CuAssertIntEquals(tc, 3, level); + pay_spell(u, sp, level, 1); CuAssertIntEquals(tc, 0, get_resource(u, rt_find("money"))); CuAssertIntEquals(tc, 0, get_resource(u, rt_find("aura"))); CuAssertIntEquals(tc, 0, get_resource(u, rt_find("horse"))); } +void test_pay_spell_failure(CuTest * tc) +{ + spell *sp; + unit * u; + faction * f; + region * r; + int level; + + test_cleanup(); + test_create_world(); + r = findregion(0, 0); + f = test_create_faction(0); + u = test_create_unit(f, r); + CuAssertPtrNotNull(tc, u); + + sp = test_magic_create_spell(); + CuAssertPtrNotNull(tc, sp); + + set_level(u, SK_MAGIC, 5); + unit_add_spell(u, 0, sp); + + CuAssertIntEquals(tc, 1, change_resource(u, rt_find("money"), 1)); + CuAssertIntEquals(tc, 2, change_resource(u, rt_find("aura"), 2)); + CuAssertIntEquals(tc, 3, change_resource(u, rt_find("horse"), 3)); + + level = eff_spelllevel(u, sp, 3, 1); + CuAssertIntEquals(tc, 2, level); + pay_spell(u, sp, level, 1); + CuAssertIntEquals(tc, 1, change_resource(u, rt_find("money"), 1)); + CuAssertIntEquals(tc, 3, change_resource(u, rt_find("aura"), 3)); + CuAssertIntEquals(tc, 2, change_resource(u, rt_find("horse"), 1)); + + level = eff_spelllevel(u, sp, 3, 1); + CuAssertIntEquals(tc, 0, level); + pay_spell(u, sp, level, 1); + CuAssertIntEquals(tc, 0, get_resource(u, rt_find("money"))); /* seems we even pay this at level 0 */ + CuAssertIntEquals(tc, 3, get_resource(u, rt_find("aura"))); + CuAssertIntEquals(tc, 2, get_resource(u, rt_find("horse"))); + + level = eff_spelllevel(u, sp, 2, 1); + CuAssertIntEquals(tc, 0, level); + pay_spell(u, sp, level, 1); + CuAssertIntEquals(tc, 0, get_resource(u, rt_find("money"))); + CuAssertIntEquals(tc, 3, get_resource(u, rt_find("aura"))); + CuAssertIntEquals(tc, 2, get_resource(u, rt_find("horse"))); +} + CuSuite *get_magic_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_updatespells); SUITE_ADD_TEST(suite, test_spellbooks); SUITE_ADD_TEST(suite, test_pay_spell); + SUITE_ADD_TEST(suite, test_pay_spell_failure); return suite; } From 3b05e2e09e8dea8d79ea86d0893f36c3a02c3031 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 May 2012 15:40:03 -0700 Subject: [PATCH 264/400] fix compilation on ubuntu --- src/kernel/unit.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/kernel/unit.h b/src/kernel/unit.h index cb0ab5f68..907e16e8c 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -28,6 +28,8 @@ extern "C" { struct skill; struct item; + struct sc_mage; + #define UFL_DEBUG (1<<0) #define UFL_ISNEW (1<<1) /* 2 */ #define UFL_LONGACTION (1<<2) /* 4 */ From 58cbc3ccbc1623729d7a75e3322e18f80bd23b03 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 May 2012 16:15:21 -0700 Subject: [PATCH 265/400] add some tests for pools, because I found a bug here and we don't want to have that happen again. --- src/items/xerewards.c | 5 +++-- src/kernel.vcxproj | 1 + src/kernel.vcxproj.filters | 3 +++ src/kernel/item.c | 2 +- src/kernel/item.h | 1 - src/kernel/magic.c | 3 ++- src/kernel/pool.c | 7 +++++++ src/kernel/pool_test.c | 43 ++++++++++++++++++++++++++++++++++++++ src/tests.c | 2 ++ 9 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 src/kernel/pool_test.c diff --git a/src/items/xerewards.c b/src/items/xerewards.c index f06a667ac..fb1a9595d 100644 --- a/src/items/xerewards.c +++ b/src/items/xerewards.c @@ -29,6 +29,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include /* util includes */ #include @@ -59,7 +60,7 @@ use_skillpotion(struct unit *u, const struct item_type *itype, int amount, } ADDMSG(&u->faction->msgs, msg_message("skillpotion_use", "unit", u)); - res_changeitem(u, itype->rtype, -amount); + change_resource(u, itype->rtype, -amount); return 0; } @@ -81,7 +82,7 @@ use_manacrystal(struct unit *u, const struct item_type *itype, int amount, ADDMSG(&u->faction->msgs, msg_message("manacrystal_use", "unit aura", u, sp)); - res_changeitem(u, itype->rtype, -amount); + change_resource(u, itype->rtype, -amount); return 0; } diff --git a/src/kernel.vcxproj b/src/kernel.vcxproj index 78a213902..24d6df48b 100644 --- a/src/kernel.vcxproj +++ b/src/kernel.vcxproj @@ -117,6 +117,7 @@ + diff --git a/src/kernel.vcxproj.filters b/src/kernel.vcxproj.filters index 906d6566d..c75975ed2 100644 --- a/src/kernel.vcxproj.filters +++ b/src/kernel.vcxproj.filters @@ -322,6 +322,9 @@ kernel + + kernel + diff --git a/src/kernel/item.c b/src/kernel/item.c index e9473ff10..c2ba35c65 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -96,7 +96,7 @@ static int res_changepeasants(unit * u, const resource_type * rtype, int delta) return u->region->land->peasants; } -int res_changeitem(unit * u, const resource_type * rtype, int delta) +static int res_changeitem(unit * u, const resource_type * rtype, int delta) { int num; if (rtype == oldresourcetype[R_STONE] && u->race == new_race[RC_STONEGOLEM] diff --git a/src/kernel/item.h b/src/kernel/item.h index f470381a7..7ff3b9454 100644 --- a/src/kernel/item.h +++ b/src/kernel/item.h @@ -343,7 +343,6 @@ extern "C" { int get_money(const struct unit *); int set_money(struct unit *, int); int change_money(struct unit *, int); - int res_changeitem(struct unit *u, const resource_type * rtype, int delta); extern struct attrib_type at_showitem; /* show this potion's description */ diff --git a/src/kernel/magic.c b/src/kernel/magic.c index fff5008e3..4e57bf5be 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -693,8 +693,9 @@ int change_spellpoints(unit * u, int mp) int sp; m = get_mage(u); - if (!m) + if (!m) { return 0; + } /* verhindere negative Magiepunkte */ sp = MAX(m->spellpoints + mp, 0); diff --git a/src/kernel/pool.c b/src/kernel/pool.c index 997bb3b30..b150f9f9f 100644 --- a/src/kernel/pool.c +++ b/src/kernel/pool.c @@ -41,12 +41,19 @@ int get_resource(const unit * u, const resource_type * rtype) { const item_type *itype = resource2item(rtype); + assert(rtype); if (rtype->uget) { /* this resource is probably special */ int i = rtype->uget(u, rtype); if (i >= 0) return i; } + else if (rtype->uchange) { + /* this resource is probably special */ + int i = rtype->uchange((unit *)u, rtype, 0); + if (i >= 0) + return i; + } if (itype != NULL) { if (itype == olditemtype[R_STONE] && (u->race->flags & RCF_STONEGOLEM)) { return u->number * GOLEM_STONE; diff --git a/src/kernel/pool_test.c b/src/kernel/pool_test.c new file mode 100644 index 000000000..28d2a827a --- /dev/null +++ b/src/kernel/pool_test.c @@ -0,0 +1,43 @@ +#include + +#include "pool.h" +#include "unit.h" +#include "item.h" +#include "region.h" +#include +#include + +void test_change_resource(CuTest * tc) +{ + struct unit * u; + struct faction * f; + struct region * r; + const char * names[] = { "money", "aura", "permaura", "horse", "hp", 0 }; + int i; + + test_cleanup(); + test_create_world(); + skill_enabled[SK_MAGIC] = 1; + + r = findregion(0, 0); + f = test_create_faction(0); + u = test_create_unit(f, r); + CuAssertPtrNotNull(tc, u); + set_level(u, SK_MAGIC, 5); + create_mage(u, M_DRAIG); + + for (i=0;names[i];++i) { + const struct resource_type *rtype = rt_find(names[i]); + int have = get_resource(u, rtype); + CuAssertIntEquals(tc, have+1, change_resource(u, rtype, 1)); + CuAssertIntEquals(tc, have+1, get_resource(u, rtype)); + } +} + +CuSuite *get_pool_suite(void) +{ + CuSuite *suite = CuSuiteNew(); +/* SUITE_ADD_TEST(suite, test_pool); */ + SUITE_ADD_TEST(suite, test_change_resource); + return suite; +} diff --git a/src/tests.c b/src/tests.c index e2ef1df7c..4dcdaa1b3 100644 --- a/src/tests.c +++ b/src/tests.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,7 @@ int RunAllTests(void) CuSuiteAddSuite(suite, get_functions_suite()); CuSuiteAddSuite(suite, get_umlaut_suite()); /* kernel */ + CuSuiteAddSuite(suite, get_pool_suite()); CuSuiteAddSuite(suite, get_curse_suite()); CuSuiteAddSuite(suite, get_equipment_suite()); CuSuiteAddSuite(suite, get_item_suite()); From fc259d232bbcc27f1b9550cf1167ed6e3b6f4926 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 May 2012 18:30:18 -0700 Subject: [PATCH 266/400] fix spellbook entries in at_reportspell (crash) --- src/gamecode/report.c | 2 +- src/kernel/magic.c | 6 +++++- src/kernel/xmlreader.c | 6 ++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/gamecode/report.c b/src/gamecode/report.c index fe58bf568..6de104b40 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -280,7 +280,7 @@ static void nr_spell(FILE * F, spellbook_entry * sbe, const struct locale *lang) } } else { if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR) { - itemanz *= sbe->level; + itemanz *= sp->level; } bytes = snprintf(bufp, size, "%d %s", itemanz, LOC(lang, resourcename(rtype, diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 4e57bf5be..85b7e9248 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -428,7 +428,11 @@ static void update_spells(faction * f, sc_mage * mage, int level, const spellboo add_spellname(mage, sp); } if (!ismonster && !already_seen(f, sp)) { - a_add(&f->attribs, a_new(&at_reportspell))->data.v = sp; + attrib * a = a_new(&at_reportspell); + spellbook_entry * entry = (spellbook_entry *)a->data.v; + entry->level = level; + entry->sp = sp; + a_add(&f->attribs, a); a_add(&f->attribs, a_new(&at_seenspell))->data.v = sp; } } diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 232ed917d..de0da42aa 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1662,8 +1662,14 @@ static int parse_spells(xmlDocPtr doc) propValue = xmlGetProp(node, BAD_CAST "cost"); if (propValue != NULL) { if (strcmp((const char *)propValue, "linear") == 0) { + if ((sp->sptyp&SPELLLEVEL)==0) { + log_error("spell '%s' has linear cost but fixed level\n", sp->sname); + } component->cost = SPC_LINEAR; } else if (strcmp((const char *)propValue, "level") == 0) { + if ((sp->sptyp&SPELLLEVEL)==0) { + log_error("spell '%s' has levelled cost but fixed level\n", sp->sname); + } component->cost = SPC_LEVEL; } xmlFree(propValue); From 071f67ea7c7324683768a09efba6a7bf778c517a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 May 2012 18:50:14 -0700 Subject: [PATCH 267/400] use the reportpath from the config file, do not build your own --- scripts/tests/common.lua | 2 +- src/bindings/bindings.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 0ae776197..6c98b19ac 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -814,7 +814,7 @@ end local function find_in_report(f, pattern, extension) extension = extension or "nr" - local filename = config.basepath .. "/reports/" .. get_turn() .. "-" .. itoa36(f.id) .. "." .. extension + local filename = config.reportpath .. "/" .. get_turn() .. "-" .. itoa36(f.id) .. "." .. extension local report = io.open(filename, 'rt'); assert_not_nil(report) t = report:read("*all") diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index 34cefe183..f633f7716 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -1142,6 +1142,9 @@ static void parse_inifile(lua_State * L, dictionary * d, const char *section) lua_pushstring(L, "basepath"); lua_pushstring(L, basepath()); lua_rawset(L, -3); + lua_pushstring(L, "reportpath"); + lua_pushstring(L, reportpath()); + lua_rawset(L, -3); } int tolua_eressea_open(lua_State * L) From 24cba1bea7236d7c18d79295dd077d8bc0fca8fc Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 May 2012 19:55:47 -0700 Subject: [PATCH 268/400] testing spells in the example server also WIP: create_roi is broken until mages have spellbooks --- scripts/tests/spells.lua | 45 +--------------------------------------- src/kernel/magic.c | 10 +++++++-- src/kernel/spellbook.c | 2 +- src/kernel/spellbook.h | 2 +- src/kernel/unit.c | 11 ++++++++++ src/kernel/unit.h | 1 + 6 files changed, 23 insertions(+), 48 deletions(-) diff --git a/scripts/tests/spells.lua b/scripts/tests/spells.lua index b5278e5f1..ce45c49c6 100644 --- a/scripts/tests/spells.lua +++ b/scripts/tests/spells.lua @@ -14,8 +14,6 @@ function test_roi() u.race = "elf" u:set_skill("magic", 10) u:add_item("money", 3010) - u:add_item("roi", 1) - assert_equal(1, u:get_item("roi")) u.magic = "tybied" u.aura = 200 u.ship = s1 @@ -25,46 +23,5 @@ function test_roi() u:add_order("ZAUBERE 'Erschaffe einen Ring der Unsichtbarkeit' ") process_orders() write_reports() - assert_equal(2, u:get_item("roi")) -end - -function test_blessedharvest_lasts_n_turn() - free_game() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "halfling", "de") - local u = unit.create(f, r) - local err = 0 - r:set_resource("peasant", 100) - r:set_resource("money", 0) - u:add_item("money", 1000) - u.magic = "gwyrrd" - u.race = "dwarf" - u:set_skill("magic", 20) - u.aura = 200 - err = err + u:add_spell("raindance") - err = err + u:add_spell("blessedharvest") - assert_equal(0, err) - - u:clear_orders() - local level = 5 - u:add_order("ZAUBERE STUFE " .. level .. " Regentanz") - assert_equal(0, r:get_resource("money"), 0) - - local m = 0 - local p = 100 - for i=1,level+2 do - process_orders() - local income = p * 12 - p = r:get_resource("peasant") - income = income - p * 10 - m = m + income - -- print(i, m, p, r:get_resource("money")) - if (i>level+1) then - assert_not_equal(m, r:get_resource("money")) - else - assert_equal(m, r:get_resource("money")) - end - u:clear_orders() - u:add_order("ARBEITEN") - end + assert_equal(1, u:get_item("roi")) end diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 85b7e9248..f1a857053 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -897,9 +897,15 @@ int eff_spelllevel(unit * u, const spell * sp, int cast_level, int range) /* Ein Spruch mit Fixkosten wird immer mit der Stufe des Spruchs und * nicht auf der Stufe des Magiers gezaubert */ if (costtyp == SPC_FIX) { - cast_level = MIN(cast_level, sp->level); + spellbook * spells = unit_get_spellbook(u); + if (spells) { + spellbook_entry * sbe = spellbook_get(spells, sp); + if (sbe) { + return MIN(cast_level, sbe->level); + } + } + log_error("spell %s is not in the spellbook for %s\n", sp->sname, unitname(u)); } - return cast_level; } diff --git a/src/kernel/spellbook.c b/src/kernel/spellbook.c index ad2a4c496..14482742a 100644 --- a/src/kernel/spellbook.c +++ b/src/kernel/spellbook.c @@ -54,7 +54,7 @@ int spellbook_foreach(spellbook *sb, int (*callback)(spellbook_entry *, void *), return 0; } -spellbook_entry * spellbook_get(spellbook *sb, struct spell * sp) +spellbook_entry * spellbook_get(spellbook *sb, const struct spell * sp) { quicklist *ql; int qi; diff --git a/src/kernel/spellbook.h b/src/kernel/spellbook.h index 81eb23a4b..94b3eb448 100644 --- a/src/kernel/spellbook.h +++ b/src/kernel/spellbook.h @@ -42,7 +42,7 @@ spellbook * create_spellbook(const char * name); void spellbook_add(spellbook *sbp, struct spell * sp, int level); int spellbook_foreach(spellbook *sb, int (*callback)(spellbook_entry *, void *), void * data); void spellbook_clear(spellbook *sb); -spellbook_entry * spellbook_get(spellbook *sb, struct spell * sp); +spellbook_entry * spellbook_get(spellbook *sb, const struct spell * sp); #ifdef __cplusplus } diff --git a/src/kernel/unit.c b/src/kernel/unit.c index d7315df8d..d8ca679d8 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1737,3 +1737,14 @@ void unit_add_spell(unit * u, sc_mage * m, struct spell * sp) add_spell(&mage->spells, sp); add_spellname(mage, sp); } + +struct spellbook * unit_get_spellbook(struct unit * u) +{ + sc_mage * mage = get_mage(u); + if (mage) { + if (u->faction->spellbook) { + return u->faction->spellbook; + } + } + return 0; +} \ No newline at end of file diff --git a/src/kernel/unit.h b/src/kernel/unit.h index 907e16e8c..d75a85aa9 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -233,6 +233,7 @@ extern "C" { int unit_max_hp(const struct unit *u); void scale_number(struct unit *u, int n); + struct spellbook * unit_get_spellbook(struct unit * u); void unit_add_spell(struct unit * u, struct sc_mage * m, struct spell * sp); extern struct attrib_type at_creator; From d58e8530740f247d6cc7b3eede44fb1fa0ce9ff3 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 May 2012 20:15:57 -0700 Subject: [PATCH 269/400] allow setting a faction's magic school from Lua --- scripts/tests/spells.lua | 5 +++-- src/bindings/bind_faction.c | 24 ++++++++++++++++++++++++ src/kernel/unit.c | 1 + 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/scripts/tests/spells.lua b/scripts/tests/spells.lua index ce45c49c6..763f67953 100644 --- a/scripts/tests/spells.lua +++ b/scripts/tests/spells.lua @@ -14,11 +14,12 @@ function test_roi() u.race = "elf" u:set_skill("magic", 10) u:add_item("money", 3010) + f.magic = "tybied" u.magic = "tybied" u.aura = 200 u.ship = s1 - local err = u:add_spell("create_roi") - assert_equal(0, err) +-- local err = u:add_spell("create_roi") +-- assert_equal(0, err) u:clear_orders() u:add_order("ZAUBERE 'Erschaffe einen Ring der Unsichtbarkeit' ") process_orders() diff --git a/src/bindings/bind_faction.c b/src/bindings/bind_faction.c index 97abfa521..665af06d6 100644 --- a/src/bindings/bind_faction.c +++ b/src/bindings/bind_faction.c @@ -117,6 +117,28 @@ static int tolua_faction_set_id(lua_State * L) return 1; } +static int tolua_faction_get_magic(lua_State * L) +{ + faction *self = (faction *) tolua_tousertype(L, 1, 0); + lua_pushstring(L, magic_school[self->magiegebiet]); + return 1; +} + +static int tolua_faction_set_magic(lua_State * L) +{ + faction *self = (faction *) tolua_tousertype(L, 1, 0); + const char *type = tolua_tostring(L, 2, 0); + magic_t mtype; + + for (mtype = 0; mtype != MAXMAGIETYP; ++mtype) { + if (strcmp(magic_school[mtype], type) == 0) { + self->magiegebiet = mtype; + break; + } + } + return 0; +} + static int tolua_faction_get_age(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); @@ -498,6 +520,8 @@ void tolua_faction_open(lua_State * L) tolua_variable(L, TOLUA_CAST "alliance", tolua_faction_get_alliance, tolua_faction_set_alliance); tolua_variable(L, TOLUA_CAST "score", tolua_faction_get_score, NULL); + tolua_variable(L, TOLUA_CAST "magic", &tolua_faction_get_magic, + tolua_faction_set_magic); tolua_variable(L, TOLUA_CAST "age", tolua_faction_get_age, tolua_faction_set_age); tolua_variable(L, TOLUA_CAST "options", tolua_faction_get_options, diff --git a/src/kernel/unit.c b/src/kernel/unit.c index d8ca679d8..f4b58fd59 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1745,6 +1745,7 @@ struct spellbook * unit_get_spellbook(struct unit * u) if (u->faction->spellbook) { return u->faction->spellbook; } + return get_spellbook(magic_school[u->faction->magiegebiet]); } return 0; } \ No newline at end of file From a015d72adda122a023e3e243606177e0e980932a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 May 2012 21:07:26 -0700 Subject: [PATCH 270/400] unit_add_spell gets a level added a test that fails for get_spellfromtoken if spell is not stored with the unit --- src/bindings/bind_unit.c | 3 +- src/gamecode/laws.c | 12 ++----- src/kernel/equipment.c | 2 +- src/kernel/magic.c | 11 ++----- src/kernel/magic_test.c | 68 +++++++++++++++++++++++++++++++++++++--- src/kernel/spell.c | 51 +++++++++++++++++------------- src/kernel/spell.h | 2 +- src/kernel/unit.c | 2 +- src/kernel/unit.h | 2 +- 9 files changed, 103 insertions(+), 50 deletions(-) diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index e5fc11bf9..79f2660e5 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -487,6 +487,7 @@ static int tolua_unit_addspell(lua_State * L) { unit *u = (unit *) tolua_tousertype(L, 1, 0); const char *str = tolua_tostring(L, 2, 0); + int level = (int)tolua_tonumber(L, 3, 1); int err = 0; spell *sp = find_spell(str); @@ -494,7 +495,7 @@ static int tolua_unit_addspell(lua_State * L) log_error("spell %s could not be found\n", str); return EINVAL; } else { - unit_add_spell(u, 0, sp); + unit_add_spell(u, 0, sp, level); } lua_pushinteger(L, err); diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 9fdfd964a..8b0875afc 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -2427,7 +2427,6 @@ static void reshow(unit * u, struct order *ord, const char *s, param_t p) const item_type *itype; const spell *sp = 0; const race *rc; - sc_mage * mage; switch (p) { case P_ZAUBER: @@ -2458,10 +2457,7 @@ static void reshow(unit * u, struct order *ord, const char *s, param_t p) } } /* try for a spell */ - mage = get_mage(u); - if (mage) { - sp = get_spellfromtoken(mage, s, u->faction->locale); - } + sp = get_spellfromtoken(u, s, u->faction->locale); if (sp) { attrib *a = a_find(u->faction->attribs, &at_seenspell); while (a != NULL && a->type == &at_seenspell && a->data.v != sp) { @@ -2626,7 +2622,6 @@ static int combatspell_cmd(unit * u, struct order *ord) const char *s; int level = 0; spell *sp = 0; - sc_mage * mage; init_tokens(ord); skip_token(); @@ -2646,10 +2641,7 @@ static int combatspell_cmd(unit * u, struct order *ord) s = getstrtoken(); } - mage = get_mage(u); - if (mage) { - sp = get_spellfromtoken(mage, s, u->faction->locale); - } + sp = get_spellfromtoken(u, s, u->faction->locale); if (!sp) { cmistake(u, ord, 173, MSG_MAGIC); return 0; diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index 4e91cac81..2ef21717c 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -148,7 +148,7 @@ void equip_unit_mask(struct unit *u, const struct equipment *eq, int mask) for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi); - unit_add_spell(u, mage, sbe->sp); + unit_add_spell(u, mage, sbe->sp, sbe->level); } } } diff --git a/src/kernel/magic.c b/src/kernel/magic.c index f1a857053..17dbd1218 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -2526,7 +2526,6 @@ static castorder *cast_cmd(unit * u, order * ord) plane *pl; spellparameter *args = NULL; unit * caster = u; - sc_mage * mage; if (LongHunger(u)) { cmistake(u, ord, 224, MSG_MAGIC); @@ -2587,10 +2586,7 @@ static castorder *cast_cmd(unit * u, order * ord) return 0; } - mage = get_mage(u); - if (mage) { - sp = get_spellfromtoken(mage, s, u->faction->locale); - } + sp = get_spellfromtoken(u, s, u->faction->locale); /* Vertraute können auch Zauber sprechen, die sie selbst nicht * können. get_spellfromtoken findet aber nur jene Sprüche, die @@ -2598,9 +2594,8 @@ static castorder *cast_cmd(unit * u, order * ord) if (!sp && is_familiar(u)) { caster = get_familiar_mage(u); if (caster) { - mage = get_mage(caster); familiar = u; - sp = get_spellfromtoken(mage, s, caster->faction->locale); + sp = get_spellfromtoken(caster, s, caster->faction->locale); } else { /* somehow, this familiar has no mage! */ log_error("cast_cmd: familiar %s is without a mage?\n", unitname(u)); @@ -2693,7 +2688,7 @@ static castorder *cast_cmd(unit * u, order * ord) if (caster != familiar) { /* Magier zaubert durch Vertrauten */ if (range > 1) { /* Fehler! Versucht zu Farcasten */ ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "familiar_farcast", - "mage", mage)); + "mage", caster)); return 0; } if (distance(caster->region, r) > eff_skill(caster, SK_MAGIC, caster->region)) { diff --git a/src/kernel/magic_test.c b/src/kernel/magic_test.c index b05c174b7..df343ebd1 100644 --- a/src/kernel/magic_test.c +++ b/src/kernel/magic_test.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -105,7 +106,7 @@ void test_pay_spell(CuTest * tc) CuAssertPtrNotNull(tc, sp); set_level(u, SK_MAGIC, 5); - unit_add_spell(u, 0, sp); + unit_add_spell(u, 0, sp, 1); change_resource(u, rt_find("money"), 1); change_resource(u, rt_find("aura"), 3); @@ -122,9 +123,9 @@ void test_pay_spell(CuTest * tc) void test_pay_spell_failure(CuTest * tc) { spell *sp; - unit * u; - faction * f; - region * r; + struct unit * u; + struct faction * f; + struct region * r; int level; test_cleanup(); @@ -138,7 +139,7 @@ void test_pay_spell_failure(CuTest * tc) CuAssertPtrNotNull(tc, sp); set_level(u, SK_MAGIC, 5); - unit_add_spell(u, 0, sp); + unit_add_spell(u, 0, sp, 1); CuAssertIntEquals(tc, 1, change_resource(u, rt_find("money"), 1)); CuAssertIntEquals(tc, 2, change_resource(u, rt_find("aura"), 2)); @@ -166,6 +167,61 @@ void test_pay_spell_failure(CuTest * tc) CuAssertIntEquals(tc, 2, get_resource(u, rt_find("horse"))); } +void test_get_spellfromtoken_unit(CuTest * tc) +{ + spell *sp; + struct unit * u; + struct faction * f; + struct region * r; + struct locale * lang; + + test_cleanup(); + test_create_world(); + r = findregion(0, 0); + f = test_create_faction(0); + u = test_create_unit(f, r); + skill_enabled[SK_MAGIC] = 1; + + set_level(u, SK_MAGIC, 1); + + lang = find_locale("de"); + sp = create_spell("testspell", 0); + locale_setstring(lang, mkname("spell", sp->sname), "Herp-a-derp"); + + CuAssertPtrEquals(tc, 0, get_spellfromtoken(u, "Herp-a-derp", lang)); + + unit_add_spell(u, 0, sp, 1); + CuAssertPtrNotNull(tc, get_spellfromtoken(u, "Herp-a-derp", lang)); +} + +void test_get_spellfromtoken_faction(CuTest * tc) +{ + spell *sp; + struct unit * u; + struct faction * f; + struct region * r; + struct locale * lang; + + test_cleanup(); + test_create_world(); + r = findregion(0, 0); + f = test_create_faction(0); + u = test_create_unit(f, r); + skill_enabled[SK_MAGIC] = 1; + + set_level(u, SK_MAGIC, 1); + + lang = find_locale("de"); + sp = create_spell("testspell", 0); + locale_setstring(lang, mkname("spell", sp->sname), "Herp-a-derp"); + + CuAssertPtrEquals(tc, 0, get_spellfromtoken(u, "Herp-a-derp", lang)); + + f->spellbook = create_spellbook(0); + spellbook_add(f->spellbook, sp, 1); + CuAssertPtrNotNull(tc, get_spellfromtoken(u, "Herp-a-derp", lang)); +} + CuSuite *get_magic_suite(void) { CuSuite *suite = CuSuiteNew(); @@ -173,5 +229,7 @@ CuSuite *get_magic_suite(void) SUITE_ADD_TEST(suite, test_spellbooks); SUITE_ADD_TEST(suite, test_pay_spell); SUITE_ADD_TEST(suite, test_pay_spell_failure); + SUITE_ADD_TEST(suite, test_get_spellfromtoken_unit); + SUITE_ADD_TEST(suite, test_get_spellfromtoken_faction); return suite; } diff --git a/src/kernel/spell.c b/src/kernel/spell.c index e674796a5..5af6793f4 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -104,32 +104,39 @@ spell *find_spell(const char *name) /* ------------------------------------------------------------- */ /* Spruch identifizieren */ -spell *get_spellfromtoken(sc_mage *mage, const char *name, +spell *get_spellfromtoken(struct unit *u, const char *name, const struct locale * lang) { - variant token; - struct spell_names * names = mage->spellnames; - for (;names;names=names->next) { - if (names->lang==lang) break; - } - if (!names) { - quicklist *ql = mage->spells; - int qi; - names = (spell_names *)calloc(1, sizeof(spell_names)); - names->next = mage->spellnames; - names->lang = lang; - names->tokens = 0; - for (qi = 0, ql = mage->spells; ql; ql_advance(&ql, &qi, 1)) { - spell *sp = (spell *) ql_get(ql, qi); - const char *n = spell_name(sp, lang); - token.v = sp; - addtoken(&names->tokens, n, token); + sc_mage * mage = get_mage(u); + if (mage) { + variant token; + struct spell_names * names = mage->spellnames; + for (;names;names=names->next) { + if (names->lang==lang) break; + } + if (!names) { + quicklist *ql = mage->spells; + int qi; + names = (spell_names *)calloc(1, sizeof(spell_names)); + names->next = mage->spellnames; + names->lang = lang; + names->tokens = 0; + for (qi = 0, ql = mage->spells; ql; ql_advance(&ql, &qi, 1)) { + spell *sp = (spell *) ql_get(ql, qi); + const char *n = spell_name(sp, lang); + if (!n) { + log_error("no translation in locae %s for spell $s\n", locale_name(lang), sp->sname); + } else { + token.v = sp; + addtoken(&names->tokens, n, token); + } + } + mage->spellnames = names; } - mage->spellnames = names; - } - if (findtoken(names->tokens, name, &token) != E_TOK_NOMATCH) { - return (spell *) token.v; + if (findtoken(names->tokens, name, &token) != E_TOK_NOMATCH) { + return (spell *) token.v; + } } return 0; } diff --git a/src/kernel/spell.h b/src/kernel/spell.h index 226de96e4..627a855d6 100644 --- a/src/kernel/spell.h +++ b/src/kernel/spell.h @@ -37,7 +37,7 @@ extern "C" { extern struct spell * create_spell(const char * name, unsigned int id); extern struct spell * find_spell(const char *name); extern struct spell * find_spellbyid(unsigned int i); - extern struct spell * get_spellfromtoken(struct sc_mage *mage, const char *s, + extern struct spell * get_spellfromtoken(struct unit *u, const char *s, const struct locale *lang); extern void free_spells(void); diff --git a/src/kernel/unit.c b/src/kernel/unit.c index f4b58fd59..6e19710f1 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1726,7 +1726,7 @@ const struct race *u_irace(const struct unit *u) return u->race; } -void unit_add_spell(unit * u, sc_mage * m, struct spell * sp) +void unit_add_spell(unit * u, sc_mage * m, struct spell * sp, int level) { sc_mage *mage = m ? m : get_mage(u); diff --git a/src/kernel/unit.h b/src/kernel/unit.h index d75a85aa9..93dc55ce7 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -234,7 +234,7 @@ extern "C" { void scale_number(struct unit *u, int n); struct spellbook * unit_get_spellbook(struct unit * u); - void unit_add_spell(struct unit * u, struct sc_mage * m, struct spell * sp); + void unit_add_spell(struct unit * u, struct sc_mage * m, struct spell * sp, int level); extern struct attrib_type at_creator; #ifdef __cplusplus From 8a4c71f430cdcccdcda2e17ac2900f5933c91fbb Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 May 2012 21:09:58 -0700 Subject: [PATCH 271/400] unit_add_spell gets a level added two tests that fail for get_spellfromtoken if spell is not stored with the unit --- src/kernel/magic_test.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/kernel/magic_test.c b/src/kernel/magic_test.c index df343ebd1..6e7be814a 100644 --- a/src/kernel/magic_test.c +++ b/src/kernel/magic_test.c @@ -219,7 +219,37 @@ void test_get_spellfromtoken_faction(CuTest * tc) f->spellbook = create_spellbook(0); spellbook_add(f->spellbook, sp, 1); - CuAssertPtrNotNull(tc, get_spellfromtoken(u, "Herp-a-derp", lang)); + CuAssertPtrEquals(tc, sp, get_spellfromtoken(u, "Herp-a-derp", lang)); +} + +void test_get_spellfromtoken_school(CuTest * tc) +{ + spell *sp; + struct unit * u; + struct faction * f; + struct region * r; + struct locale * lang; + struct spellbook * book; + + test_cleanup(); + test_create_world(); + r = findregion(0, 0); + f = test_create_faction(0); + f->magiegebiet = M_TYBIED; + u = test_create_unit(f, r); + skill_enabled[SK_MAGIC] = 1; + + set_level(u, SK_MAGIC, 1); + + lang = find_locale("de"); + sp = create_spell("testspell", 0); + locale_setstring(lang, mkname("spell", sp->sname), "Herp-a-derp"); + + CuAssertPtrEquals(tc, 0, get_spellfromtoken(u, "Herp-a-derp", lang)); + + book = get_spellbook(magic_school[f->magiegebiet]); + spellbook_add(book, sp, 1); + CuAssertPtrEquals(tc, sp, get_spellfromtoken(u, "Herp-a-derp", lang)); } CuSuite *get_magic_suite(void) @@ -231,5 +261,6 @@ CuSuite *get_magic_suite(void) SUITE_ADD_TEST(suite, test_pay_spell_failure); SUITE_ADD_TEST(suite, test_get_spellfromtoken_unit); SUITE_ADD_TEST(suite, test_get_spellfromtoken_faction); + SUITE_ADD_TEST(suite, test_get_spellfromtoken_school); return suite; } From faa72b66b172bac73a519341d187bf3447da899d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 May 2012 22:25:23 -0700 Subject: [PATCH 272/400] untangle the spaghetti a little bit struct spell is now in spell.h where it belongs some functions have moved as a result --- src/gamecode/laws.c | 4 ++-- src/kernel/battle.c | 1 + src/kernel/magic.c | 52 +++++++++++++++++++++++++++++++---------- src/kernel/magic.h | 45 +++++++++++------------------------ src/kernel/magic_test.c | 24 +++++++++---------- src/kernel/race.h | 7 +++--- src/kernel/spell.c | 51 ++++++---------------------------------- src/kernel/spell.h | 30 +++++++++++++++++------- 8 files changed, 102 insertions(+), 112 deletions(-) diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 8b0875afc..d4e591fd2 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -2457,7 +2457,7 @@ static void reshow(unit * u, struct order *ord, const char *s, param_t p) } } /* try for a spell */ - sp = get_spellfromtoken(u, s, u->faction->locale); + sp = unit_getspell(u, s, u->faction->locale); if (sp) { attrib *a = a_find(u->faction->attribs, &at_seenspell); while (a != NULL && a->type == &at_seenspell && a->data.v != sp) { @@ -2641,7 +2641,7 @@ static int combatspell_cmd(unit * u, struct order *ord) s = getstrtoken(); } - sp = get_spellfromtoken(u, s, u->faction->locale); + sp = unit_getspell(u, s, u->faction->locale); if (!sp) { cmistake(u, ord, 173, MSG_MAGIC); return 0; diff --git a/src/kernel/battle.c b/src/kernel/battle.c index d0d0f9a31..6c51ce01b 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -42,6 +42,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "reports.h" #include "ship.h" #include "skill.h" +#include "spell.h" #include "terrain.h" #include "unit.h" diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 17dbd1218..092c0abe8 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -74,8 +74,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -/* ------------------------------------------------------------- */ - const char *magic_school[MAXMAGIETYP] = { "gray", "illaun", @@ -547,13 +545,6 @@ void add_spellname(sc_mage * mage, const spell * sp) } } -void add_spell(struct quicklist **slistp, spell * sp) -{ - if (ql_set_insert(slistp, sp) != 0) { - log_error("add_spell: the list already contains the spell '%s'.\n", sp->sname); - } -} - int u_hasspell(const sc_mage *mage, const struct spell *sp) { return mage ? has_spell(mage->spells, sp) : 0; @@ -2586,16 +2577,16 @@ static castorder *cast_cmd(unit * u, order * ord) return 0; } - sp = get_spellfromtoken(u, s, u->faction->locale); + sp = unit_getspell(u, s, u->faction->locale); /* Vertraute können auch Zauber sprechen, die sie selbst nicht - * können. get_spellfromtoken findet aber nur jene Sprüche, die + * können. unit_getspell findet aber nur jene Sprüche, die * die Einheit beherrscht. */ if (!sp && is_familiar(u)) { caster = get_familiar_mage(u); if (caster) { familiar = u; - sp = get_spellfromtoken(caster, s, caster->faction->locale); + sp = unit_getspell(caster, s, caster->faction->locale); } else { /* somehow, this familiar has no mage! */ log_error("cast_cmd: familiar %s is without a mage?\n", unitname(u)); @@ -2913,6 +2904,43 @@ const char *curse_name(const curse_type * ctype, const struct locale *lang) return LOC(lang, mkname("spell", ctype->cname)); } +spell *unit_getspell(struct unit *u, const char *name, + const struct locale * lang) +{ + sc_mage * mage = get_mage(u); + if (mage) { + variant token; + struct spell_names * names = mage->spellnames; + for (;names;names=names->next) { + if (names->lang==lang) break; + } + if (!names) { + quicklist *ql = mage->spells; + int qi; + names = (spell_names *)calloc(1, sizeof(spell_names)); + names->next = mage->spellnames; + names->lang = lang; + names->tokens = 0; + for (qi = 0, ql = mage->spells; ql; ql_advance(&ql, &qi, 1)) { + spell *sp = (spell *) ql_get(ql, qi); + const char *n = spell_name(sp, lang); + if (!n) { + log_error("no translation in locae %s for spell $s\n", locale_name(lang), sp->sname); + } else { + token.v = sp; + addtoken(&names->tokens, n, token); + } + } + mage->spellnames = names; + } + + if (findtoken(names->tokens, name, &token) != E_TOK_NOMATCH) { + return (spell *) token.v; + } + } + return 0; +} + struct quicklist **get_spelllist(struct sc_mage *mage, struct faction *f) { if (mage) { diff --git a/src/kernel/magic.h b/src/kernel/magic.h index 5edefbd7d..73ef8018b 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -150,24 +150,6 @@ typedef struct sc_mage { int cost; } spell_component; - typedef int (*spell_f)(castorder * co); - typedef void(*fumble_f)(castorder * co); - - typedef struct spell { - unsigned int id; - char *sname; - char *syntax; - char *parameter; - int sptyp; - int rank; /* Reihenfolge der Zauber */ - struct spell_component *components; - spell_f cast; - fumble_f patzer; - - /* this is not so much the spell's data, but the school's studying data */ - int level; /* Stufe des Zaubers */ - } spell; - /* ------------------------------------------------------------- */ /* besondere Spruchtypen */ @@ -261,15 +243,14 @@ typedef struct sc_mage { int get_combatspelllevel(const struct unit *u, int nr); /* versucht, eine eingestellte maximale Kampfzauberstufe * zurückzugeben. 0 = Maximum, -1 u ist kein Magier. */ - const spell *get_combatspell(const struct unit *u, int nr); + const struct spell *get_combatspell(const struct unit *u, int nr); /* gibt den Kampfzauber nr [pre/kampf/post] oder NULL zurück */ - void set_combatspell(struct unit *u, spell * sp, struct order *ord, + void set_combatspell(struct unit *u, struct spell * sp, struct order *ord, int level); /* setzt Kampfzauber */ - void unset_combatspell(struct unit *u, spell * sp); + void unset_combatspell(struct unit *u, struct spell * sp); /* löscht Kampfzauber */ - void add_spell(struct quicklist **slistp, spell * sp); - void add_spellname(sc_mage * mage, const spell * sp); + void add_spellname(sc_mage * mage, const struct spell * sp); /* fügt den Spruch mit der Id spellid der Spruchliste der Einheit hinzu. */ int u_hasspell(const sc_mage *mage, const struct spell *sp); /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ @@ -279,7 +260,7 @@ typedef struct sc_mage { * als das aktuelle Magietalent ist, in die Spruchliste der Einheit * ein */ boolean knowsspell(const struct region *r, const struct unit *u, - const spell * sp); + const struct spell * sp); /* prüft, ob die Einheit diesen Spruch gerade beherrscht, dh * mindestens die erforderliche Stufe hat. Hier können auch Abfragen * auf spezielle Antimagiezauber auf Regionen oder Einheiten eingefügt @@ -299,10 +280,10 @@ typedef struct sc_mage { /* verändert die maximalen Magiepunkte einer Einheit */ /* Zaubern */ - extern double spellpower(struct region *r, struct unit *u, const spell * sp, + extern double spellpower(struct region *r, struct unit *u, const struct spell * sp, int cast_level, struct order *ord); /* ermittelt die Stärke eines Spruchs */ - boolean fumble(struct region *r, struct unit *u, const spell * sp, + boolean fumble(struct region *r, struct unit *u, const struct spell * sp, int cast_level); /* true, wenn der Zauber misslingt, bei false gelingt der Zauber */ @@ -325,19 +306,19 @@ typedef struct sc_mage { int countspells(struct unit *u, int step); /* erhöht den Counter für Zaubersprüche um 'step' und gibt die neue * Anzahl der gezauberten Sprüche zurück. */ - int spellcost(struct unit *u, const spell * sp); + int spellcost(struct unit *u, const struct spell * sp); /* gibt die für diesen Spruch derzeit notwendigen Magiepunkte auf der * geringstmöglichen Stufe zurück, schon um den Faktor der bereits * zuvor gezauberten Sprüche erhöht */ - boolean cancast(struct unit *u, const spell * spruch, int eff_stufe, + boolean cancast(struct unit *u, const struct spell * spruch, int eff_stufe, int distance, struct order *ord); /* true, wenn Einheit alle Komponenten des Zaubers (incl. MP) für die * geringstmögliche Stufe hat und den Spruch beherrscht */ - void pay_spell(struct unit *u, const spell * sp, int eff_stufe, int distance); + void pay_spell(struct unit *u, const struct spell * sp, int eff_stufe, int distance); /* zieht die Komponenten des Zaubers aus dem Inventory der Einheit * ab. Die effektive Stufe des gezauberten Spruchs ist wichtig für * die korrekte Bestimmung der Magiepunktkosten */ - int eff_spelllevel(struct unit *u, const spell * sp, int cast_level, + int eff_spelllevel(struct unit *u, const struct spell * sp, int cast_level, int distance); /* ermittelt die effektive Stufe des Zaubers. Dabei ist cast_level * die gewünschte maximale Stufe (im Normalfall Stufe des Magiers, @@ -352,8 +333,10 @@ typedef struct sc_mage { int resist_bonus); /* gibt false zurück, wenn der Zauber gelingt, true, wenn das Ziel * widersteht */ + extern struct spell * unit_getspell(struct unit *u, const char *s, + const struct locale *lang); -/* Sprüche in der struct region */ + /* 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); diff --git a/src/kernel/magic_test.c b/src/kernel/magic_test.c index 6e7be814a..716ce3a85 100644 --- a/src/kernel/magic_test.c +++ b/src/kernel/magic_test.c @@ -167,7 +167,7 @@ void test_pay_spell_failure(CuTest * tc) CuAssertIntEquals(tc, 2, get_resource(u, rt_find("horse"))); } -void test_get_spellfromtoken_unit(CuTest * tc) +void test_getspell_unit(CuTest * tc) { spell *sp; struct unit * u; @@ -188,13 +188,13 @@ void test_get_spellfromtoken_unit(CuTest * tc) sp = create_spell("testspell", 0); locale_setstring(lang, mkname("spell", sp->sname), "Herp-a-derp"); - CuAssertPtrEquals(tc, 0, get_spellfromtoken(u, "Herp-a-derp", lang)); + CuAssertPtrEquals(tc, 0, unit_getspell(u, "Herp-a-derp", lang)); unit_add_spell(u, 0, sp, 1); - CuAssertPtrNotNull(tc, get_spellfromtoken(u, "Herp-a-derp", lang)); + CuAssertPtrNotNull(tc, unit_getspell(u, "Herp-a-derp", lang)); } -void test_get_spellfromtoken_faction(CuTest * tc) +void test_getspell_faction(CuTest * tc) { spell *sp; struct unit * u; @@ -215,14 +215,14 @@ void test_get_spellfromtoken_faction(CuTest * tc) sp = create_spell("testspell", 0); locale_setstring(lang, mkname("spell", sp->sname), "Herp-a-derp"); - CuAssertPtrEquals(tc, 0, get_spellfromtoken(u, "Herp-a-derp", lang)); + CuAssertPtrEquals(tc, 0, unit_getspell(u, "Herp-a-derp", lang)); f->spellbook = create_spellbook(0); spellbook_add(f->spellbook, sp, 1); - CuAssertPtrEquals(tc, sp, get_spellfromtoken(u, "Herp-a-derp", lang)); + CuAssertPtrEquals(tc, sp, unit_getspell(u, "Herp-a-derp", lang)); } -void test_get_spellfromtoken_school(CuTest * tc) +void test_getspell_school(CuTest * tc) { spell *sp; struct unit * u; @@ -245,11 +245,11 @@ void test_get_spellfromtoken_school(CuTest * tc) sp = create_spell("testspell", 0); locale_setstring(lang, mkname("spell", sp->sname), "Herp-a-derp"); - CuAssertPtrEquals(tc, 0, get_spellfromtoken(u, "Herp-a-derp", lang)); + CuAssertPtrEquals(tc, 0, unit_getspell(u, "Herp-a-derp", lang)); book = get_spellbook(magic_school[f->magiegebiet]); spellbook_add(book, sp, 1); - CuAssertPtrEquals(tc, sp, get_spellfromtoken(u, "Herp-a-derp", lang)); + CuAssertPtrEquals(tc, sp, unit_getspell(u, "Herp-a-derp", lang)); } CuSuite *get_magic_suite(void) @@ -259,8 +259,8 @@ CuSuite *get_magic_suite(void) SUITE_ADD_TEST(suite, test_spellbooks); SUITE_ADD_TEST(suite, test_pay_spell); SUITE_ADD_TEST(suite, test_pay_spell_failure); - SUITE_ADD_TEST(suite, test_get_spellfromtoken_unit); - SUITE_ADD_TEST(suite, test_get_spellfromtoken_faction); - SUITE_ADD_TEST(suite, test_get_spellfromtoken_school); + SUITE_ADD_TEST(suite, test_getspell_unit); + SUITE_ADD_TEST(suite, test_getspell_faction); + SUITE_ADD_TEST(suite, test_getspell_school); return suite; } diff --git a/src/kernel/race.h b/src/kernel/race.h index c2cafa01f..c7c7c43fc 100644 --- a/src/kernel/race.h +++ b/src/kernel/race.h @@ -39,6 +39,9 @@ extern "C" { #define RACESPOILCHANCE 5 /* Chance auf rassentypische Beute */ + struct param; + struct spell; + typedef struct att { int type; union { @@ -49,8 +52,6 @@ extern "C" { int level; } att; - struct param; - extern int num_races; typedef struct race { @@ -75,7 +76,7 @@ extern "C" { int df_default; /* Verteidigungsskill Unbewaffnet (default: -2) */ int at_bonus; /* Verändert den Angriffsskill (default: 0) */ int df_bonus; /* Verändert den Verteidigungskill (default: 0) */ - const spell *precombatspell; + const struct spell *precombatspell; struct att attack[10]; char bonus[MAXSKILLS]; signed char *study_speed; /* study-speed-bonus in points/turn (0=30 Tage) */ diff --git a/src/kernel/spell.c b/src/kernel/spell.c index 5af6793f4..eb59a4f68 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -20,10 +20,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include "spell.h" -/* kernel includes */ -#include "magic.h" -#include "unit.h" - /* util includes */ #include #include @@ -45,6 +41,13 @@ void free_spells(void) { spells = 0; } +void add_spell(struct quicklist **slistp, spell * sp) +{ + if (ql_set_insert(slistp, sp) != 0) { + log_error("add_spell: the list already contains the spell '%s'.\n", sp->sname); + } +} + spell * create_spell(const char * name, unsigned int id) { spell * sp; @@ -101,46 +104,6 @@ spell *find_spell(const char *name) return sp; } -/* ------------------------------------------------------------- */ -/* Spruch identifizieren */ - -spell *get_spellfromtoken(struct unit *u, const char *name, - const struct locale * lang) -{ - sc_mage * mage = get_mage(u); - if (mage) { - variant token; - struct spell_names * names = mage->spellnames; - for (;names;names=names->next) { - if (names->lang==lang) break; - } - if (!names) { - quicklist *ql = mage->spells; - int qi; - names = (spell_names *)calloc(1, sizeof(spell_names)); - names->next = mage->spellnames; - names->lang = lang; - names->tokens = 0; - for (qi = 0, ql = mage->spells; ql; ql_advance(&ql, &qi, 1)) { - spell *sp = (spell *) ql_get(ql, qi); - const char *n = spell_name(sp, lang); - if (!n) { - log_error("no translation in locae %s for spell $s\n", locale_name(lang), sp->sname); - } else { - token.v = sp; - addtoken(&names->tokens, n, token); - } - } - mage->spellnames = names; - } - - if (findtoken(names->tokens, name, &token) != E_TOK_NOMATCH) { - return (spell *) token.v; - } - } - return 0; -} - spell *find_spellbyid(unsigned int id) { quicklist *ql; diff --git a/src/kernel/spell.h b/src/kernel/spell.h index 627a855d6..5a4df26e9 100644 --- a/src/kernel/spell.h +++ b/src/kernel/spell.h @@ -22,25 +22,39 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif - /* Prototypen */ + struct castorder; + typedef int (*spell_f)(struct castorder * co); + typedef void(*fumble_f)(struct castorder * co); + + typedef struct spell { + unsigned int id; + char *sname; + char *syntax; + char *parameter; + int sptyp; + int rank; /* Reihenfolge der Zauber */ + struct spell_component *components; + spell_f cast; + fumble_f patzer; + + /* this is not so much the spell's data, but the school's studying data */ + int level; /* Stufe des Zaubers */ + } spell; int use_item_power(struct region *r, struct unit *u); int use_item_regeneration(struct region *r, struct unit *u); void showspells(struct region *r, struct unit *u); int sp_antimagiczone(struct castorder *co); - /* ------------------------------------------------------------- */ - - extern struct attrib_type at_unitdissolve; - extern struct attrib_type at_wdwpyramid; - extern struct spell * create_spell(const char * name, unsigned int id); extern struct spell * find_spell(const char *name); extern struct spell * find_spellbyid(unsigned int i); - extern struct spell * get_spellfromtoken(struct unit *u, const char *s, - const struct locale *lang); + extern void add_spell(struct quicklist **slistp, spell * sp); extern void free_spells(void); + /** globals **/ + extern struct attrib_type at_unitdissolve; + extern struct attrib_type at_wdwpyramid; extern struct quicklist * spells; #ifdef __cplusplus } From 303dd7cc949d82a0ebee0dab70d2fb7ab54913dc Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 May 2012 22:54:18 -0700 Subject: [PATCH 273/400] creport will now print spellbooks --- src/gamecode/creport.c | 41 +++++++++++++++++++++++------------------ src/kernel/unit.c | 2 +- src/kernel/unit.h | 2 +- src/kernel/xmlreader.c | 1 - 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index cbf0d3564..705b862fb 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -49,6 +49,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include #include #include #include @@ -651,20 +652,24 @@ fwriteorder(FILE * F, const struct order *ord, const struct locale *lang, fputc('"', F); } -static void cr_output_spells(FILE * F, quicklist * slist, const faction * f, - int maxlevel) +static void cr_output_spells(FILE * F, const unit * u, int maxlevel) { - if (slist) { - quicklist *ql; - int qi; - fprintf(F, "SPRUECHE\n"); + spellbook * book = unit_get_spellbook(u); - for (ql = slist, qi = 0; ql; ql_advance(&ql, &qi, 1)) { - spell *sp = (spell *) ql_get(ql, qi); - if (sp->level <= maxlevel) { - const char *name = - add_translation(mkname("spell", sp->sname), spell_name(sp, - f->locale)); + if (book) { + const faction * f = u->faction; + quicklist *ql; + int qi, header = 0; + + for (ql = book->spells, qi = 0; ql; ql_advance(&ql, &qi, 1)) { + spellbook_entry * sbe = (spellbook_entry *)ql_get(ql, qi); + if (sbe->level <= maxlevel) { + spell * sp = sbe->sp; + const char *name = add_translation(mkname("spell", sp->sname), spell_name(sp, f->locale)); + if (!header) { + fputs("SPRUECHE\n", F); + header = 1; + } fprintf(F, "\"%s\"\n", name); } } @@ -818,6 +823,7 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, const char *xc; const char *c; int i; + sc_mage *mage; i = ualias(u); if (i > 0) @@ -889,13 +895,12 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, f->locale))); } } - /* spells */ - if (is_mage(u)) { - sc_mage *mage = get_mage(u); - quicklist **slistp = get_spelllist(mage, u->faction); - int i, maxlevel = effskill(u, SK_MAGIC); - cr_output_spells(F, *slistp, f, maxlevel); + /* spells that this unit can cast */ + mage = get_mage(u); + if (mage) { + int i, maxlevel = effskill(u, SK_MAGIC); + cr_output_spells(F, u, maxlevel); for (i = 0; i != MAXCOMBATSPELLS; ++i) { const spell *sp = mage->combatspells[i].sp; diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 6e19710f1..e73a9f617 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1738,7 +1738,7 @@ void unit_add_spell(unit * u, sc_mage * m, struct spell * sp, int level) add_spellname(mage, sp); } -struct spellbook * unit_get_spellbook(struct unit * u) +struct spellbook * unit_get_spellbook(const struct unit * u) { sc_mage * mage = get_mage(u); if (mage) { diff --git a/src/kernel/unit.h b/src/kernel/unit.h index 93dc55ce7..7c9e3d8d3 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -233,7 +233,7 @@ extern "C" { int unit_max_hp(const struct unit *u); void scale_number(struct unit *u, int n); - struct spellbook * unit_get_spellbook(struct unit * u); + struct spellbook * unit_get_spellbook(const struct unit * u); void unit_add_spell(struct unit * u, struct sc_mage * m, struct spell * sp, int level); extern struct attrib_type at_creator; diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index de0da42aa..e211ca660 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1575,7 +1575,6 @@ static int parse_spells(xmlDocPtr doc) xmlFree(propValue); /* level, rank and flags */ #endif - sp->level = xml_ivalue(node, "level", -1); sp->rank = (char)xml_ivalue(node, "rank", -1); if (xml_bvalue(node, "los", false)) sp->sptyp |= TESTCANSEE; /* must see or have contact */ From bc95ea80fb764a0c6b2a481325f6ed69a0d44ab2 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 May 2012 23:01:21 -0700 Subject: [PATCH 274/400] espionage messages will now report spellbooks --- src/gamecode/creport.c | 1 - src/kernel/reports.c | 48 ++++++++++++++++++++++-------------------- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index 705b862fb..cfd718985 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -38,7 +38,6 @@ without prior permission by the authors of Eressea. #include #include #include -#include #include #include #include diff --git a/src/kernel/reports.c b/src/kernel/reports.c index 6a7e4c81d..a7244d213 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -28,7 +28,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include #include #include #include @@ -38,6 +37,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include +#include #include #include @@ -700,32 +701,33 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, } if (u->faction == f || telepath_see) { - sc_mage *m = get_mage(u); + spellbook *book = unit_get_spellbook(u); - if (m != NULL) { - quicklist *ql = m->spells; - int qi, t = effskill(u, SK_MAGIC); - int bytes = - snprintf(bufp, size, ". Aura %d/%d", get_spellpoints(u), - max_spellpoints(u->region, u)); - if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0) + if (book) { + quicklist *ql = book->spells; + int qi, header, maxlevel = effskill(u, SK_MAGIC); + int bytes = snprintf(bufp, size, ". Aura %d/%d", get_spellpoints(u), max_spellpoints(u->region, u)); + if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0) { WARN_STATIC_BUFFER(); + } - for (dh = 0, qi = 0; ql; ql_advance(&ql, &qi, 1)) { - spell *sp = (spell *) ql_get(ql, qi); - if (sp->level > t) - continue; - if (!dh) { - bytes = snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_spells")); - dh = 1; - } else { - bytes = (int)strlcpy(bufp, ", ", size); + for (header = 0, qi = 0; ql; ql_advance(&ql, &qi, 1)) { + spellbook_entry * sbe = (spellbook_entry *) ql_get(ql, qi); + if (sbe->level <= maxlevel) { + if (!header) { + bytes = snprintf(bufp, size, ", %s: ", LOC(f->locale, "nr_spells")); + header = 1; + } else { + bytes = (int)strlcpy(bufp, ", ", size); + } + if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0) { + WARN_STATIC_BUFFER(); + } + bytes = (int)strlcpy(bufp, spell_name(sbe->sp, f->locale), size); + if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0) { + WARN_STATIC_BUFFER(); + } } - if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, spell_name(sp, f->locale), size); - if (bytes < 0 || wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); } for (i = 0; i != MAXCOMBATSPELLS; ++i) { From 6ffe9cac33dadd497834bd6436da54a6b2daf78f Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 May 2012 23:31:37 -0700 Subject: [PATCH 275/400] these spells are only in the E2 and E3 source --- res/de/strings.xml | 55 ------------------------------------------- src/gamecode/report.c | 1 + 2 files changed, 1 insertion(+), 55 deletions(-) diff --git a/res/de/strings.xml b/res/de/strings.xml index 14a8c764f..aea55a6a9 100644 --- a/res/de/strings.xml +++ b/res/de/strings.xml @@ -3902,10 +3902,6 @@ Lied der Verführung Song Of Seduction - - Schaler Wein - Hangover - Aushorchen sound_out @@ -4484,10 +4480,6 @@ Wiederbelebung Resurrection - - Traumbilder analysieren - Analyse Dreams - Schlechter Schlaf Insomnia @@ -4758,38 +4750,6 @@ erzählen, was sie selber sehen könnte. - - - Aufzeichung des Vortrags von Selen Ard'Ragorn in Bar'Glingal: - 'Es heiss, dieser Spruch wäre wohl in den Spelunken der Westgassen - entstanden, doch es kann genausogut in jedem andern verrufenen - Viertel gewesen sein. Seine wichtigste Zutat ist etwa ein Fass - schlechtesten Weines, je billiger und ungesunder, desto - wirkungsvoller wird die Essenz. Die Kunst, diesen Wein in pure - Essenz zu destillieren, die weitaus anspruchsvoller als das einfache - Rezeptmischen eines Alchemisten ist, und diese dergestalt zu binden - und konservieren, das sie sich nicht gleich wieder verflüchtigt, wie - es ihre Natur wäre, ja, dies ist etwas, das nur ein Meister des - Cerddor vollbringen kann. Nun besitzt Ihr eine kleine Phiola mit - einer rubinrotschimmernden - nun, nicht flüssig, doch auch nicht - ganz Dunst - nennen wir es einfach nur Elixier. Doch nicht dies ist - die wahre Herausforderung, sodann muss, da sich ihre Wirkung leicht - verflüchtigt, diese innerhalb weniger Tage unbemerkt in das Getränk - des Opfers geträufelt werden. Ihr Meister der Betöhrung und - Verführung, hier nun könnt Ihr Eure ganze Kunst unter Beweis - stellen. Doch gebt Acht, nicht unbedacht selbst von dem Elixier zu - kosten, denn wer einmal gekostet hat, der kann vom Weine nicht mehr - lassen, und er säuft sicherlich eine volle Woche lang. Jedoch nicht - die Verführung zum Trunke ist die wahre Gefahr, die dem Elixier - innewohnt, sondern das der Trunkenheit so sicher ein gar - fürchterliches Leid des Kopfes folgen wird, wie der Tag auf die - Nacht folgt. Und er wird gar sicherlich von seiner besten Fähigkeit - einige Tage bis hin zu den Studien zweier Wochen vergessen haben. - Noch ein Wort der Warnung: Dieses ist sehr aufwendig, und so Ihr - noch weitere Zauber in der selben Woche wirken wollt, so werden sie Euch - schwerer fallen.' - - Mit diesem Lied kann eine Einheit derartig betört werden, so dass @@ -6238,21 +6198,6 @@ physical injuries, but an affected person will survive the battle. - - Mit diesem Spruch kann der Traumweber - versuchen, die Verzauberungen einer einzelnen - Einheit zu erkennen. Von allen Sprüchen, die - seine eigenen Fähigkeiten nicht überschreiten, - wird er einen Eindruck ihres Wirkens erhalten - können. Bei stärkeren Sprüchen benötigt er ein - wenig Glück für eine gelungene Analyse. - With this spell the mentalist can - attempt to detect enchantments on a target unit. - He will get an idea of the effect of all spells - that don't exceed his own abilities. If a spell - is stronger, it takes a little luck for a - successful analysis. - Dieser Zauber führt in der betroffenen Region für einige Wochen zu Schlaflosigkeit und diff --git a/src/gamecode/report.c b/src/gamecode/report.c index 6de104b40..221b50f19 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -59,6 +59,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include From c73297ba44d3a31baa18f5aa15887de7ba111116 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 25 May 2012 23:47:24 -0700 Subject: [PATCH 276/400] fix an indexing error in pick_random_spell --- src/kernel/magic.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 092c0abe8..0518ea856 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -389,6 +389,14 @@ attrib_type at_seenspell = { "seenspell", NULL, NULL, NULL, write_seenspell, read_seenspell }; +#define MAXSPELLS 256 + +static boolean has_spell(quicklist * ql, const spell * sp) +{ + int qi; + return ql_set_find(&ql, &qi, sp) != 0; +} + static boolean already_seen(const faction * f, const spell * sp) { attrib *a; @@ -401,14 +409,6 @@ static boolean already_seen(const faction * f, const spell * sp) return false; } -#define MAXSPELLS 256 - -static boolean has_spell(quicklist * ql, const spell * sp) -{ - int qi; - return ql_set_find(&ql, &qi, sp) != 0; -} - static void update_spells(faction * f, sc_mage * mage, int level, const spellbook *book) { boolean ismonster = is_monsters(f); @@ -448,6 +448,7 @@ void updatespelllist(unit * u) if (mage->magietyp != M_GRAY) { spellbook * book; book = get_spellbook(magic_school[mage->magietyp]); + update_spells(u->faction, mage, sk, book); if (FactionSpells()) { @@ -489,11 +490,11 @@ void pick_random_spells(faction * f, int level, spellbook * book, int num_spells spellno = rng_int() % maxspell; sp = commonspells[spellno]; if (sp->level>f->max_spelllevel) { - commonspells[spellno] = commonspells[maxspell]; - commonspells[maxspell--] = sp; + commonspells[spellno] = commonspells[--maxspell]; + commonspells[maxspell] = sp; sp = 0; } else if (f->spellbook && spellbook_get(f->spellbook, sp)) { - commonspells[spellno] = commonspells[numspells--]; + commonspells[spellno] = commonspells[--numspells]; if (maxspell>numspells) { maxspell = numspells; } @@ -506,7 +507,7 @@ void pick_random_spells(faction * f, int level, spellbook * book, int num_spells f->spellbook = create_spellbook(0); } spellbook_add(f->spellbook, sp, f->max_spelllevel); - commonspells[spellno] = commonspells[numspells--]; + commonspells[spellno] = commonspells[--numspells]; } } } From 9d1b62d4633906396aaf548467c23dc8dc275ba0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 May 2012 00:33:55 -0700 Subject: [PATCH 277/400] updating spell-lists is a thing of the past now almost everything uses books, except sc_mage --- src/gamecode/laws.c | 64 +++++++++++++++++++++++++++-------------- src/kernel/faction.c | 11 +++++++ src/kernel/faction.h | 1 + src/kernel/magic.c | 59 +++++++++++-------------------------- src/kernel/magic.h | 1 + src/kernel/magic_test.c | 3 +- src/kernel/save.c | 4 +-- src/kernel/unit.c | 8 ++++-- 8 files changed, 81 insertions(+), 70 deletions(-) diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index d4e591fd2..6dd2af667 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -3687,6 +3687,32 @@ static void defaultorders(void) /* ************************************************************ */ #define COMMONSPELLS 1 /* number of new common spells per level */ #define MAXMAGES 128 /* should be enough */ + +static int faction_getmages(faction * f, unit ** results, int numresults) +{ + unit *u; + int maxlevel = 0, n = 0; + + for (u = f->units; u; u = u->nextF) { + if (u->number > 0) { + sc_mage *mage = get_mage(u); + if (mage) { + int level = eff_skill(u, SK_MAGIC, u->region); + if (level > maxlevel) { + maxlevel = level; + } + if (nnext) { if (f->magiegebiet != M_NONE && !is_monsters(f)) { unit *mages[MAXMAGES]; - unit *u; - int maxlevel = 0, n = 0, i; - - for (u = f->units; u; u = u->nextF) { - if (u->number > 0) { - sc_mage *mage = get_mage(u); - if (mage) { - int level = eff_skill(u, SK_MAGIC, u->region); - if (level > maxlevel) - maxlevel = level; - assert(n < MAXMAGES); - mages[n++] = u; - } - } - } + int i; + int maxlevel = faction_getmages(f, mages, MAXMAGES); if (FactionSpells() && maxlevel > f->max_spelllevel) { static spellbook * common_spells; if (!common_spells) { const char *common_school = get_param(global.parameters, "rules.magic.common"); - common_spells = get_spellbook(common_school ? common_school : "common"); - } - if (common_spells) { - pick_random_spells(f, maxlevel, common_spells, COMMONSPELLS); + if (!common_school) common_school = "common"; + common_spells = get_spellbook(common_school); + if (!common_spells) { + log_error("could not find a book of common spells: '%s'\n", common_school); + } } + pick_random_spells(f, maxlevel, common_spells, COMMONSPELLS); } - for (i = 0; i != n; ++i) { - updatespelllist(mages[i]); + show_new_spells(f, maxlevel, faction_get_spellbook(f)); + for (i=0; i!=MAXMAGES && mages[i]; ++i) { + sc_mage *mage = get_mage(mages[i]); + if (mage && mage->spells) { +#ifdef TODO + int level = effskill(mages[i], SK_MAGIC); + show_new_spells(f, level, mage->spellbook); +#endif + } } } } diff --git a/src/kernel/faction.c b/src/kernel/faction.c index d9c701a41..dcfa7b59a 100644 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -511,3 +511,14 @@ struct alliance *f_get_alliance(const struct faction *f) } return NULL; } + +struct spellbook * faction_get_spellbook(struct faction *f) +{ + if (f->spellbook) { + return f->spellbook; + } + if (f->magiegebiet!=M_GRAY) { + return get_spellbook(magic_school[f->magiegebiet]); + } + return 0; +} diff --git a/src/kernel/faction.h b/src/kernel/faction.h index ec82bbe51..a81d0545c 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -152,6 +152,7 @@ extern "C" { void faction_setpassword(struct faction *self, const char *password); boolean valid_race(const struct faction *f, const struct race *rc); + struct spellbook * faction_get_spellbook(struct faction *f); #ifdef __cplusplus } #endif diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 0518ea856..881ba67f0 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -409,50 +409,26 @@ static boolean already_seen(const faction * f, const spell * sp) return false; } -static void update_spells(faction * f, sc_mage * mage, int level, const spellbook *book) +void show_new_spells(faction * f, int level, const spellbook *book) { - boolean ismonster = is_monsters(f); - quicklist **dst, *ql = book->spells; - int qi; + if (book) { + quicklist *ql = book->spells; + int qi; - dst = get_spelllist(mage, f); - for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { - spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi); - if (sbe->level <= level) { - spell * sp = sbe->sp; + for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { + spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi); + if (sbe->level <= level) { + spell * sp = sbe->sp; - if (!u_hasspell(mage, sp)) { - add_spell(dst, sp); - add_spellname(mage, sp); + if (!already_seen(f, sp)) { + attrib * a = a_new(&at_reportspell); + spellbook_entry * entry = (spellbook_entry *)a->data.v; + entry->level = level; + entry->sp = sp; + a_add(&f->attribs, a); + a_add(&f->attribs, a_new(&at_seenspell))->data.v = sp; + } } - if (!ismonster && !already_seen(f, sp)) { - attrib * a = a_new(&at_reportspell); - spellbook_entry * entry = (spellbook_entry *)a->data.v; - entry->level = level; - entry->sp = sp; - a_add(&f->attribs, a); - a_add(&f->attribs, a_new(&at_seenspell))->data.v = sp; - } - } - } -} - -void updatespelllist(unit * u) -{ - int sk = eff_skill(u, SK_MAGIC, u->region); - struct sc_mage *mage = get_mage(u); - - /* Magier mit M_GRAY bekommen weder Sprüche angezeigt noch - * neue Sprüche in ihre List-of-known-spells. Das sind zb alle alten - * Drachen, die noch den Skill Magie haben, und alle familiars */ - if (mage->magietyp != M_GRAY) { - spellbook * book; - book = get_spellbook(magic_school[mage->magietyp]); - - update_spells(u->faction, mage, sk, book); - - if (FactionSpells()) { - update_spells(u->faction, mage, sk, u->faction->spellbook); } } } @@ -1522,9 +1498,6 @@ void regeneration_magiepunkte(void) "unit region amount", u, r, regen)); } set_spellpoints(u, MIN(aura, auramax)); - - /* Zum letzten Mal Spruchliste aktualisieren */ - /*updatespelllist(u); */ } } } diff --git a/src/kernel/magic.h b/src/kernel/magic.h index 73ef8018b..da0b693db 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -255,6 +255,7 @@ typedef struct sc_mage { int u_hasspell(const sc_mage *mage, const struct spell *sp); /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ void pick_random_spells(struct faction *f, int level, struct spellbook * book, int num_spells); + void show_new_spells(struct faction * f, int level, const struct spellbook *book); void updatespelllist(struct unit *u); /* fügt alle Zauber des Magiegebietes der Einheit, deren Stufe kleiner * als das aktuelle Magietalent ist, in die Spruchliste der Einheit diff --git a/src/kernel/magic_test.c b/src/kernel/magic_test.c index 716ce3a85..1989dac52 100644 --- a/src/kernel/magic_test.c +++ b/src/kernel/magic_test.c @@ -247,7 +247,8 @@ void test_getspell_school(CuTest * tc) CuAssertPtrEquals(tc, 0, unit_getspell(u, "Herp-a-derp", lang)); - book = get_spellbook(magic_school[f->magiegebiet]); + book = faction_get_spellbook(f); + CuAssertPtrNotNull(tc, book); spellbook_add(book, sp, 1); CuAssertPtrEquals(tc, sp, unit_getspell(u, "Herp-a-derp", lang)); } diff --git a/src/kernel/save.c b/src/kernel/save.c index 545a45c6a..0de9d337c 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1615,8 +1615,9 @@ int readgame(const char *filename, int mode, int backup) n = store->r_int(store); assert(n < MAXREGIONS); - if (rmax < 0) + if (rmax < 0) { rmax = n; + } log_printf(stdout, " - Einzulesende Regionen: %d/%d\r", rmax, n); while (--n >= 0) { unit **up; @@ -1727,7 +1728,6 @@ int readgame(const char *filename, int mode, int backup) } if (mage->spellcount < 0) { mage->spellcount = 0; - updatespelllist(u); } } } diff --git a/src/kernel/unit.c b/src/kernel/unit.c index e73a9f617..532543553 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1742,10 +1742,12 @@ struct spellbook * unit_get_spellbook(const struct unit * u) { sc_mage * mage = get_mage(u); if (mage) { - if (u->faction->spellbook) { - return u->faction->spellbook; + if (mage->spells) { +#ifdef TODO + return mage->spellbook; +#endif } - return get_spellbook(magic_school[u->faction->magiegebiet]); + return faction_get_spellbook(u->faction); } return 0; } \ No newline at end of file From d884446aea8f4f33a95aad8df5f20ab08d099eab Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 May 2012 00:38:52 -0700 Subject: [PATCH 278/400] we do not require spell-levels in the xmlreader --- src/kernel/xmlreader.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index e211ca660..22d62b0d1 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1295,27 +1295,20 @@ static void add_spells(equipment * eq, xmlNodeSetPtr nsetItems) for (i = 0; i != nsetItems->nodeNr; ++i) { xmlNodePtr node = nsetItems->nodeTab[i]; xmlChar *propValue; - magic_t mtype = M_NONE; struct spell *sp; - propValue = xmlGetProp(node, BAD_CAST "school"); - if (propValue != NULL) { - for (mtype = 0; mtype != MAXMAGIETYP; ++mtype) { - if (strcmp((const char *)propValue, magic_school[mtype]) == 0) - break; - } - assert(mtype != MAXMAGIETYP); - xmlFree(propValue); - } - propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue != NULL); sp = find_spell((const char *)propValue); if (!sp) { - log_error("no spell '%s' in school '%s' for equipment-set '%s'\n", (const char *)propValue, magic_school[mtype], eq->name); + log_error("no spell '%s' for equipment-set '%s'\n", (const char *)propValue, eq->name); } else { - int level = xml_ivalue(node, "level", sp->level); - equipment_addspell(eq, sp, level); + int level = xml_ivalue(node, "level", 0); + if (level>0) { + equipment_addspell(eq, sp, level); + } else { + log_error("spell '%s' for equipment-set '%s' has no level\n", sp->sname, eq->name); + } } xmlFree(propValue); } @@ -1964,7 +1957,9 @@ static int parse_races(xmlDocPtr doc) attack->data.sp = xml_spell(node, "spell"); if (attack->data.sp) { attack->level = xml_ivalue(node, "level", 0); - assert(attack->level > 0 || attack->data.sp->level > 0); /* magical attacks need a level */ + if (attack->level > 0) { + log_error("magical attack '%s' needs a level: %d\n", attack->data.sp->sname, attack->level); + } } } attack->type = xml_ivalue(node, "type", 0); From 3b3343ae722acb850ff7f4dcce07c1d1aa473588 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 May 2012 00:57:13 -0700 Subject: [PATCH 279/400] spells no longer have a level (or need one) --- src/gamecode/items.c | 4 ++-- src/gamecode/report.c | 10 +++------- src/gamecode/xmlreport.c | 4 ++++ src/kernel/magic.c | 25 ++++++++++++------------- src/kernel/spell.h | 3 --- src/kernel/spellbook.c | 15 ++++++++------- 6 files changed, 29 insertions(+), 32 deletions(-) diff --git a/src/gamecode/items.c b/src/gamecode/items.c index 4849ce144..8c6ec2688 100644 --- a/src/gamecode/items.c +++ b/src/gamecode/items.c @@ -124,12 +124,12 @@ use_antimagiccrystal(unit * u, const struct item_type *itype, int amount, assert(sp); /* Reduziert die Stärke jedes Spruchs um effect */ - effect = sp->level; + effect = 5; /* Hält Sprüche bis zu einem summierten Gesamtlevel von power aus. * Jeder Zauber reduziert die 'Lebenskraft' (vigour) der Antimagiezone * um seine Stufe */ - force = sp->level * 20; /* Stufe 5 =~ 100 */ + force = effect * 20; /* Stufe 5 =~ 100 */ /* Regionszauber auflösen */ while (*ap && force > 0) { diff --git a/src/gamecode/report.c b/src/gamecode/report.c index 221b50f19..72e5e4ab1 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -280,14 +280,10 @@ static void nr_spell(FILE * F, spellbook_entry * sbe, const struct locale *lang) WARN_STATIC_BUFFER(); } } else { - if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR) { - itemanz *= sp->level; - } - bytes = - snprintf(bufp, size, "%d %s", itemanz, LOC(lang, resourcename(rtype, - itemanz != 1))); - if (wrptr(&bufp, &size, bytes) != 0) + bytes = snprintf(bufp, size, "%d %s", itemanz, LOC(lang, resourcename(rtype, itemanz != 1))); + if (wrptr(&bufp, &size, bytes) != 0) { WARN_STATIC_BUFFER(); + } } *bufp = 0; rparagraph(F, buf, 2, 2, '-'); diff --git a/src/gamecode/xmlreport.c b/src/gamecode/xmlreport.c index fc4666f37..33a740a76 100644 --- a/src/gamecode/xmlreport.c +++ b/src/gamecode/xmlreport.c @@ -165,6 +165,7 @@ static xmlNodePtr xml_inventory(report_context * ctx, item * items, unit * u) return node; } +#ifdef TODO /*spellbooks */ static xmlNodePtr xml_spells(report_context * ctx, quicklist * slist, int maxlevel) { @@ -183,6 +184,7 @@ xml_spells(report_context * ctx, quicklist * slist, int maxlevel) } return node; } +#endif static xmlNodePtr xml_skills(report_context * ctx, unit * u) { @@ -342,6 +344,7 @@ static xmlNodePtr xml_unit(report_context * ctx, unit * u, int mode) xmlAddChild(node, xml_skills(ctx, u)); } +#ifdef TODO /*spellbooks */ /* spells */ if (is_mage(u)) { sc_mage *mage = get_mage(u); @@ -350,6 +353,7 @@ static xmlNodePtr xml_unit(report_context * ctx, unit * u, int mode) xmlAddChild(node, xml_spells(ctx, slist, effskill(u, SK_MAGIC))); } } +#endif } /* faction information w/ visibiility */ diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 881ba67f0..1f6bb42ee 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -438,7 +438,7 @@ void show_new_spells(faction * f, int level, const spellbook *book) */ void pick_random_spells(faction * f, int level, spellbook * book, int num_spells) { - spell *commonspells[MAXSPELLS]; + spellbook_entry *commonspells[MAXSPELLS]; int qi, numspells = 0; quicklist *ql; @@ -448,9 +448,8 @@ void pick_random_spells(faction * f, int level, spellbook * book, int num_spells for (qi = 0, ql = book->spells; ql; ql_advance(&ql, &qi, 1)) { spellbook_entry * sbe = (spellbook_entry *) ql_get(ql, qi); - spell * sp = sbe->sp; if (sbe->level <= level) { - commonspells[numspells++] = sp; + commonspells[numspells++] = sbe; } } @@ -461,20 +460,20 @@ void pick_random_spells(faction * f, int level, spellbook * book, int num_spells for (i = 0; i < num_spells; ++i) { int maxspell = numspells; int spellno = -1; - spell *sp = 0; - while (!sp && maxspell>0) { + spellbook_entry *sbe = 0; + while (!sbe && maxspell>0) { spellno = rng_int() % maxspell; - sp = commonspells[spellno]; - if (sp->level>f->max_spelllevel) { + sbe = commonspells[spellno]; + if (sbe->level>f->max_spelllevel) { commonspells[spellno] = commonspells[--maxspell]; - commonspells[maxspell] = sp; - sp = 0; - } else if (f->spellbook && spellbook_get(f->spellbook, sp)) { + commonspells[maxspell] = sbe; + sbe = 0; + } else if (f->spellbook && spellbook_get(f->spellbook, sbe->sp)) { commonspells[spellno] = commonspells[--numspells]; if (maxspell>numspells) { maxspell = numspells; } - sp = 0; + sbe = 0; } } @@ -482,7 +481,7 @@ void pick_random_spells(faction * f, int level, spellbook * book, int num_spells if (!f->spellbook) { f->spellbook = create_spellbook(0); } - spellbook_add(f->spellbook, sp, f->max_spelllevel); + spellbook_add(f->spellbook, sbe->sp, sbe->level); commonspells[spellno] = commonspells[--numspells]; } } @@ -948,7 +947,7 @@ cancast(unit * u, const spell * sp, int level, int range, struct order * ord) return false; } /* reicht die Stufe aus? */ - if (eff_skill(u, SK_MAGIC, u->region) < sp->level) { + if (eff_skill(u, SK_MAGIC, u->region) < level) { /* die Einheit ist nicht erfahren genug für diesen Zauber */ cmistake(u, ord, 169, MSG_MAGIC); return false; diff --git a/src/kernel/spell.h b/src/kernel/spell.h index 5a4df26e9..eb08a44f3 100644 --- a/src/kernel/spell.h +++ b/src/kernel/spell.h @@ -36,9 +36,6 @@ extern "C" { struct spell_component *components; spell_f cast; fumble_f patzer; - - /* this is not so much the spell's data, but the school's studying data */ - int level; /* Stufe des Zaubers */ } spell; int use_item_power(struct region *r, struct unit *u); diff --git a/src/kernel/spellbook.c b/src/kernel/spellbook.c index 14482742a..16e88b101 100644 --- a/src/kernel/spellbook.c +++ b/src/kernel/spellbook.c @@ -56,14 +56,15 @@ int spellbook_foreach(spellbook *sb, int (*callback)(spellbook_entry *, void *), spellbook_entry * spellbook_get(spellbook *sb, const struct spell * sp) { - quicklist *ql; - int qi; + if (sb) { + quicklist *ql; + int qi; - assert(sb); - for (qi = 0, ql = sb->spells; ql; ql_advance(&ql, &qi, 1)) { - spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi); - if (sp==sbe->sp) { - return sbe; + for (qi = 0, ql = sb->spells; ql; ql_advance(&ql, &qi, 1)) { + spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi); + if (sp==sbe->sp) { + return sbe; + } } } return 0; From 409328a9c2e1b31554af0d4ccbc57122c776a7f4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 May 2012 07:27:59 -0700 Subject: [PATCH 280/400] unit tests for setting combat spells --- src/kernel/magic.c | 5 +- src/kernel/magic_test.c | 100 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 101 insertions(+), 4 deletions(-) diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 1f6bb42ee..07d8cd9c0 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -563,9 +563,8 @@ void set_combatspell(unit * u, spell * sp, struct order *ord, int level) { sc_mage *mage = get_mage(u); int i = -1; - if (!mage) { - return; - } + + assert(mage || !"trying to set a combat spell for non-mage"); /* knowsspell prüft auf ist_magier, ist_spruch, kennt_spruch */ if (!knowsspell(u->region, u, sp)) { diff --git a/src/kernel/magic_test.c b/src/kernel/magic_test.c index 1989dac52..e908a3d59 100644 --- a/src/kernel/magic_test.c +++ b/src/kernel/magic_test.c @@ -238,7 +238,6 @@ void test_getspell_school(CuTest * tc) f->magiegebiet = M_TYBIED; u = test_create_unit(f, r); skill_enabled[SK_MAGIC] = 1; - set_level(u, SK_MAGIC, 1); lang = find_locale("de"); @@ -253,6 +252,102 @@ void test_getspell_school(CuTest * tc) CuAssertPtrEquals(tc, sp, unit_getspell(u, "Herp-a-derp", lang)); } +void test_set_pre_combatspell(CuTest * tc) +{ + spell *sp; + struct unit * u; + struct faction * f; + struct region * r; + const int index = 0; + + test_cleanup(); + test_create_world(); + r = findregion(0, 0); + f = test_create_faction(0); + f->magiegebiet = M_TYBIED; + u = test_create_unit(f, r); + skill_enabled[SK_MAGIC] = 1; + set_level(u, SK_MAGIC, 1); + sp = create_spell("testspell", 0); + sp->sptyp |= PRECOMBATSPELL; + + unit_add_spell(u, 0, sp, 1); + + set_combatspell(u, sp, 0, 2); + CuAssertPtrEquals(tc, sp, (spell *)get_combatspell(u, index)); + set_level(u, SK_MAGIC, 2); + CuAssertIntEquals(tc, 2, get_combatspelllevel(u, index)); + set_level(u, SK_MAGIC, 1); + CuAssertIntEquals(tc, 1, get_combatspelllevel(u, index)); + unset_combatspell(u, sp); + CuAssertIntEquals(tc, 0, get_combatspelllevel(u, index)); + CuAssertPtrEquals(tc, 0, (spell *)get_combatspell(u, index)); +} + +void test_set_main_combatspell(CuTest * tc) +{ + spell *sp; + struct unit * u; + struct faction * f; + struct region * r; + const int index = 1; + + test_cleanup(); + test_create_world(); + r = findregion(0, 0); + f = test_create_faction(0); + f->magiegebiet = M_TYBIED; + u = test_create_unit(f, r); + skill_enabled[SK_MAGIC] = 1; + set_level(u, SK_MAGIC, 1); + sp = create_spell("testspell", 0); + sp->sptyp |= COMBATSPELL; + + unit_add_spell(u, 0, sp, 1); + + set_combatspell(u, sp, 0, 2); + CuAssertPtrEquals(tc, sp, (spell *)get_combatspell(u, index)); + set_level(u, SK_MAGIC, 2); + CuAssertIntEquals(tc, 2, get_combatspelllevel(u, index)); + set_level(u, SK_MAGIC, 1); + CuAssertIntEquals(tc, 1, get_combatspelllevel(u, index)); + unset_combatspell(u, sp); + CuAssertIntEquals(tc, 0, get_combatspelllevel(u, index)); + CuAssertPtrEquals(tc, 0, (spell *)get_combatspell(u, index)); +} + +void test_set_post_combatspell(CuTest * tc) +{ + spell *sp; + struct unit * u; + struct faction * f; + struct region * r; + const int index = 2; + + test_cleanup(); + test_create_world(); + r = findregion(0, 0); + f = test_create_faction(0); + f->magiegebiet = M_TYBIED; + u = test_create_unit(f, r); + skill_enabled[SK_MAGIC] = 1; + set_level(u, SK_MAGIC, 1); + sp = create_spell("testspell", 0); + sp->sptyp |= POSTCOMBATSPELL; + + unit_add_spell(u, 0, sp, 1); + + set_combatspell(u, sp, 0, 2); + CuAssertPtrEquals(tc, sp, (spell *)get_combatspell(u, index)); + set_level(u, SK_MAGIC, 2); + CuAssertIntEquals(tc, 2, get_combatspelllevel(u, index)); + set_level(u, SK_MAGIC, 1); + CuAssertIntEquals(tc, 1, get_combatspelllevel(u, index)); + unset_combatspell(u, sp); + CuAssertIntEquals(tc, 0, get_combatspelllevel(u, index)); + CuAssertPtrEquals(tc, 0, (spell *)get_combatspell(u, index)); +} + CuSuite *get_magic_suite(void) { CuSuite *suite = CuSuiteNew(); @@ -263,5 +358,8 @@ CuSuite *get_magic_suite(void) SUITE_ADD_TEST(suite, test_getspell_unit); SUITE_ADD_TEST(suite, test_getspell_faction); SUITE_ADD_TEST(suite, test_getspell_school); + SUITE_ADD_TEST(suite, test_set_pre_combatspell); + SUITE_ADD_TEST(suite, test_set_main_combatspell); + SUITE_ADD_TEST(suite, test_set_post_combatspell); return suite; } From 998549e6879947c987a63421e16db0f590306881 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 May 2012 08:20:26 -0700 Subject: [PATCH 281/400] mages have spellbooks now --- src/bindings/bind_unit.c | 39 +++++++++-------- src/gamecode/laws.c | 9 ++-- src/kernel/equipment_test.c | 4 +- src/kernel/magic.c | 84 +++++++++++++++++-------------------- src/kernel/magic.h | 6 +-- src/kernel/magic_test.c | 30 +++++++++++++ src/kernel/skill.c | 18 ++++---- src/kernel/unit.c | 55 ++++++++++++------------ 8 files changed, 134 insertions(+), 111 deletions(-) diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 79f2660e5..1b4547932 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -502,22 +502,6 @@ static int tolua_unit_addspell(lua_State * L) return 1; } -static void unit_removespell(unit * u, spell * sp) -{ - quicklist **isptr; - - isptr = get_spelllist(get_mage(u), u->faction); - ql_set_remove(isptr, sp); -} - -static int tolua_unit_removespell(lua_State * L) -{ - unit *self = (unit *) tolua_tousertype(L, 1, 0); - spell *sp = (spell *) tolua_tousertype(L, 2, 0); - unit_removespell(self, sp); - return 0; -} - static int tolua_unit_set_racename(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); @@ -704,6 +688,7 @@ static int tolua_unit_get_items(lua_State * L) return 1; } +#ifdef TODO /* spellbooks */ static int tolua_unit_get_spells(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); @@ -720,6 +705,24 @@ static int tolua_unit_get_spells(lua_State * L) return tolua_quicklist_push(L, "spell_list", "spell", slist); } +static void unit_removespell(unit * u, spell * sp) +{ + quicklist **isptr; + + isptr = get_spelllist(get_mage(u), u->faction); + ql_set_remove(isptr, sp); +} + +static int tolua_unit_removespell(lua_State * L) +{ + unit *self = (unit *) tolua_tousertype(L, 1, 0); + spell *sp = (spell *) tolua_tousertype(L, 2, 0); + unit_removespell(self, sp); + return 0; +} + +#endif + static int tolua_unit_get_orders(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); @@ -953,7 +956,10 @@ void tolua_unit_open(lua_State * L) tolua_variable(L, TOLUA_CAST "race_name", &tolua_unit_get_racename, &tolua_unit_set_racename); tolua_function(L, TOLUA_CAST "add_spell", &tolua_unit_addspell); +#ifdef TODO /* spellbooks */ tolua_function(L, TOLUA_CAST "remove_spell", &tolua_unit_removespell); + tolua_variable(L, TOLUA_CAST "spells", &tolua_unit_get_spells, 0); +#endif tolua_function(L, TOLUA_CAST "cast_spell", &tolua_unit_castspell); tolua_variable(L, TOLUA_CAST "magic", &tolua_unit_get_magic, @@ -966,7 +972,6 @@ void tolua_unit_open(lua_State * L) tolua_unit_set_ship); tolua_variable(L, TOLUA_CAST "region", &tolua_unit_get_region, tolua_unit_set_region); - tolua_variable(L, TOLUA_CAST "spells", &tolua_unit_get_spells, 0); tolua_variable(L, TOLUA_CAST "number", &tolua_unit_get_number, tolua_unit_set_number); tolua_variable(L, TOLUA_CAST "race", &tolua_unit_get_race, diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 6dd2af667..26cb72b36 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -3737,12 +3737,11 @@ static void update_spells(void) } show_new_spells(f, maxlevel, faction_get_spellbook(f)); for (i=0; i!=MAXMAGES && mages[i]; ++i) { - sc_mage *mage = get_mage(mages[i]); - if (mage && mage->spells) { -#ifdef TODO - int level = effskill(mages[i], SK_MAGIC); + unit * u = mages[i]; + sc_mage *mage = get_mage(u); + if (mage && mage->spellbook) { + int level = effskill(u, SK_MAGIC); show_new_spells(f, level, mage->spellbook); -#endif } } } diff --git a/src/kernel/equipment_test.c b/src/kernel/equipment_test.c index d376ee644..5a97502a5 100644 --- a/src/kernel/equipment_test.c +++ b/src/kernel/equipment_test.c @@ -44,8 +44,8 @@ void test_equipment(CuTest * tc) mage = get_mage(u); CuAssertPtrNotNull(tc, mage); - CuAssertPtrNotNull(tc, mage->spells); - CuAssertTrue(tc, u_hasspell(mage, sp)); + CuAssertPtrNotNull(tc, mage->spellbook); + CuAssertTrue(tc, u_hasspell(u, sp)); } CuSuite *get_equipment_suite(void) diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 07d8cd9c0..7155d37de 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -33,6 +33,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "pool.h" #include "race.h" #include "region.h" +#include "save.h" #include "ship.h" #include "skill.h" #include "spell.h" @@ -200,7 +201,10 @@ static void init_mage(attrib * a) static void free_mage(attrib * a) { sc_mage *mage = (sc_mage *) a->data.v; - freelist(mage->spells); + if (mage->spellbook) { + spellbook_clear(mage->spellbook); + free(mage->spellbook); + } free(mage); } @@ -286,7 +290,7 @@ static int read_mage(attrib * a, void *owner, struct storage *store) } } } - read_spells(&mage->spells, mage->magietyp, store); + mage->spellbook = read_spellbook(store); return AT_READ_OK; } @@ -316,7 +320,7 @@ write_mage(const attrib * a, const void *owner, struct storage *store) mage->combatspells[i].sp ? mage->combatspells[i].sp->sname : "none"); store->w_int(store, mage->combatspells[i].level); } - write_spells(mage->spells, store); + write_spellbook(mage->spellbook, store); } attrib_type at_mage = { @@ -391,12 +395,6 @@ attrib_type at_seenspell = { #define MAXSPELLS 256 -static boolean has_spell(quicklist * ql, const spell * sp) -{ - int qi; - return ql_set_find(&ql, &qi, sp) != 0; -} - static boolean already_seen(const faction * f, const spell * sp) { attrib *a; @@ -521,9 +519,14 @@ void add_spellname(sc_mage * mage, const spell * sp) } } -int u_hasspell(const sc_mage *mage, const struct spell *sp) +int u_hasspell(const unit *u, const struct spell *sp) { - return mage ? has_spell(mage->spells, sp) : 0; + spellbook * book = unit_get_spellbook(u); + spellbook_entry * sbe = book ? spellbook_get(book, sp) : 0; + if (sbe) { + return sbe->level<=effskill(u, SK_MAGIC); + } + return 0; } /* ------------------------------------------------------------- */ @@ -572,7 +575,7 @@ void set_combatspell(unit * u, spell * sp, struct order *ord, int level) cmistake(u, ord, 173, MSG_MAGIC); return; } - if (!u_hasspell(mage, sp)) { + if (!u_hasspell(u, sp)) { /* Diesen Zauber kennt die Einheit nicht */ cmistake(u, ord, 169, MSG_MAGIC); return; @@ -911,19 +914,12 @@ void pay_spell(unit * u, const spell * sp, int cast_level, int range) */ boolean knowsspell(const region * r, const unit * u, const spell * sp) { - sc_mage *mage; /* Ist überhaupt ein gültiger Spruch angegeben? */ if (!sp || sp->id == 0) { return false; } - /* Magier? */ - mage = get_mage(u); - if (!mage) { - log_warning("%s ist kein Magier, versucht aber zu zaubern.\n", unitname(u)); - return false; - } /* steht der Spruch in der Spruchliste? */ - return u_hasspell(mage, sp)!=0; + return u_hasspell(u, sp)!=0; } /* Um einen Spruch zu beherrschen, muss der Magier die Stufe des @@ -2876,8 +2872,7 @@ const char *curse_name(const curse_type * ctype, const struct locale *lang) return LOC(lang, mkname("spell", ctype->cname)); } -spell *unit_getspell(struct unit *u, const char *name, - const struct locale * lang) +spell *unit_getspell(struct unit *u, const char *name, const struct locale * lang) { sc_mage * mage = get_mage(u); if (mage) { @@ -2887,40 +2882,37 @@ spell *unit_getspell(struct unit *u, const char *name, if (names->lang==lang) break; } if (!names) { - quicklist *ql = mage->spells; - int qi; - names = (spell_names *)calloc(1, sizeof(spell_names)); - names->next = mage->spellnames; - names->lang = lang; - names->tokens = 0; - for (qi = 0, ql = mage->spells; ql; ql_advance(&ql, &qi, 1)) { - spell *sp = (spell *) ql_get(ql, qi); - const char *n = spell_name(sp, lang); - if (!n) { - log_error("no translation in locae %s for spell $s\n", locale_name(lang), sp->sname); - } else { - token.v = sp; - addtoken(&names->tokens, n, token); + spellbook *sb = unit_get_spellbook(u); + if (sb) { + quicklist * ql; + int qi; + names = (spell_names *)calloc(1, sizeof(spell_names)); + names->next = mage->spellnames; + names->lang = lang; + names->tokens = 0; + + for (qi = 0, ql = sb->spells; ql; ql_advance(&ql, &qi, 1)) { + spellbook_entry *sbe = (spellbook_entry *)ql_get(ql, qi); + spell *sp = sbe->sp; + const char *n = spell_name(sp, lang); + if (!n) { + log_error("no translation in locale %s for spell %s\n", locale_name(lang), sp->sname); + } else { + token.v = sp; + addtoken(&names->tokens, n, token); + } } + mage->spellnames = names; } - mage->spellnames = names; } - if (findtoken(names->tokens, name, &token) != E_TOK_NOMATCH) { + if (names && findtoken(names->tokens, name, &token) != E_TOK_NOMATCH) { return (spell *) token.v; } } return 0; } -struct quicklist **get_spelllist(struct sc_mage *mage, struct faction *f) -{ - if (mage) { - return &mage->spells; - } - return NULL; -} - static critbit_tree cb_spellbooks; spellbook * get_spellbook(const char * name) diff --git a/src/kernel/magic.h b/src/kernel/magic.h index da0b693db..0ac519711 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -117,7 +117,7 @@ typedef struct sc_mage { int spchange; int spellcount; combatspell combatspells[MAXCOMBATSPELLS]; - struct quicklist *spells; + struct spellbook *spellbook; struct spell_names * spellnames; } sc_mage; @@ -252,7 +252,7 @@ typedef struct sc_mage { /* löscht Kampfzauber */ void add_spellname(sc_mage * mage, const struct spell * sp); /* fügt den Spruch mit der Id spellid der Spruchliste der Einheit hinzu. */ - int u_hasspell(const sc_mage *mage, const struct spell *sp); + int u_hasspell(const struct unit *u, const struct spell *sp); /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ void pick_random_spells(struct faction *f, int level, struct spellbook * book, int num_spells); void show_new_spells(struct faction * f, int level, const struct spellbook *book); @@ -360,8 +360,6 @@ typedef struct sc_mage { extern struct message *msg_unitnotfound(const struct unit *mage, struct order *ord, const struct spllprm *spobj); extern int FactionSpells(void); - extern struct quicklist **get_spelllist(struct sc_mage *mage, - struct faction *f); extern void write_spells(struct quicklist *slist, struct storage *store); extern void read_spells(struct quicklist **slistp, magic_t mtype, diff --git a/src/kernel/magic_test.c b/src/kernel/magic_test.c index e908a3d59..42e05a94c 100644 --- a/src/kernel/magic_test.c +++ b/src/kernel/magic_test.c @@ -348,6 +348,35 @@ void test_set_post_combatspell(CuTest * tc) CuAssertPtrEquals(tc, 0, (spell *)get_combatspell(u, index)); } +void test_hasspell(CuTest * tc) +{ + spell *sp; + struct unit * u; + struct faction * f; + struct region * r; + + test_cleanup(); + test_create_world(); + r = findregion(0, 0); + f = test_create_faction(0); + f->magiegebiet = M_TYBIED; + u = test_create_unit(f, r); + skill_enabled[SK_MAGIC] = 1; + sp = create_spell("testspell", 0); + sp->sptyp |= POSTCOMBATSPELL; + + unit_add_spell(u, 0, sp, 2); + + set_level(u, SK_MAGIC, 1); + CuAssertTrue(tc, !u_hasspell(u, sp)); + + set_level(u, SK_MAGIC, 2); + CuAssertTrue(tc, u_hasspell(u, sp)); + + set_level(u, SK_MAGIC, 1); + CuAssertTrue(tc, !u_hasspell(u, sp)); +} + CuSuite *get_magic_suite(void) { CuSuite *suite = CuSuiteNew(); @@ -361,5 +390,6 @@ CuSuite *get_magic_suite(void) SUITE_ADD_TEST(suite, test_set_pre_combatspell); SUITE_ADD_TEST(suite, test_set_main_combatspell); SUITE_ADD_TEST(suite, test_set_post_combatspell); + SUITE_ADD_TEST(suite, test_hasspell); return suite; } diff --git a/src/kernel/skill.c b/src/kernel/skill.c index 238ac6378..c25954182 100644 --- a/src/kernel/skill.c +++ b/src/kernel/skill.c @@ -221,7 +221,7 @@ static struct skillmods *init_skills(const race * rc) int rc_skillmod(const struct race *rc, const region * r, skill_t sk) { - int mods; + int mods = 0; if (!skill_enabled[sk]) { return 0; @@ -237,19 +237,15 @@ int rc_skillmod(const struct race *rc, const region * r, skill_t sk) } mods = (*imods)->mod[rterrain(r)].value[sk]; #else - mods = skill_mod(rc, sk, r->terrain); + if (r) { + mods = skill_mod(rc, sk, r->terrain); + } #endif - if (rc == new_race[RC_ELF] && r_isforest(r)) { - if (sk == SK_PERCEPTION) { + if (rc == new_race[RC_ELF] && r && r_isforest(r)) { + if (sk == SK_PERCEPTION || sk == SK_STEALTH) { ++mods; - } else if (sk == SK_STEALTH) { - if (r_isforest(r)) { - ++mods; - } } else if (sk == SK_TACTICS) { - if (r_isforest(r)) { - mods += 2; - } + mods += 2; } } return mods; diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 532543553..1697daf2b 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -31,6 +31,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "race.h" #include "region.h" #include "spell.h" +#include "spellbook.h" #include "save.h" #include "ship.h" #include "skill.h" @@ -1219,8 +1220,6 @@ static int item_modification(const unit * u, skill_t sk, int val) static int att_modification(const unit * u, skill_t sk) { - double bonus = 0, malus = 0; - attrib *a; double result = 0; static boolean init = false; static const curse_type *skillmod_ct, *gbdream_ct, *worse_ct; @@ -1251,27 +1250,30 @@ static int att_modification(const unit * u, skill_t sk) /* TODO hier kann nicht mit get/iscursed gearbeitet werden, da nur der * jeweils erste vom Typ C_GBDREAM zurückgegen wird, wir aber alle * durchsuchen und aufaddieren müssen */ - a = a_find(u->region->attribs, &at_curse); - while (a && a->type == &at_curse) { - curse *c = (curse *) a->data.v; - if (curse_active(c) && c->type == gbdream_ct) { - double mod = curse_geteffect(c); - unit *mage = c->magician; - /* wir suchen jeweils den größten Bonus und den größten Malus */ - if (mod > bonus) { - if (mage == NULL || mage->number == 0 - || alliedunit(mage, u->faction, HELP_GUARD)) { - bonus = mod; - } - } else if (mod < malus) { - if (mage == NULL || !alliedunit(mage, u->faction, HELP_GUARD)) { - malus = mod; + if (u->region) { + double bonus = 0, malus = 0; + attrib *a = a_find(u->region->attribs, &at_curse); + while (a && a->type == &at_curse) { + curse *c = (curse *) a->data.v; + if (curse_active(c) && c->type == gbdream_ct) { + double mod = curse_geteffect(c); + unit *mage = c->magician; + /* wir suchen jeweils den größten Bonus und den größten Malus */ + if (mod > bonus) { + if (mage == NULL || mage->number == 0 + || alliedunit(mage, u->faction, HELP_GUARD)) { + bonus = mod; + } + } else if (mod < malus) { + if (mage == NULL || !alliedunit(mage, u->faction, HELP_GUARD)) { + malus = mod; + } } } + a = a->next; } - a = a->next; + result = result + bonus + malus; } - result = result + bonus + malus; return (int)result; } @@ -1283,11 +1285,11 @@ get_modifier(const unit * u, skill_t sk, int level, const region * r, int bskill = level; int skill = bskill; - assert(r); - if (sk == SK_STEALTH) { + if (r && sk == SK_STEALTH) { plane *pl = rplane(r); - if (pl && fval(pl, PFL_NOSTEALTH)) + if (pl && fval(pl, PFL_NOSTEALTH)) { return 0; + } } skill += rc_skillmod(u->race, r, sk); @@ -1734,7 +1736,10 @@ void unit_add_spell(unit * u, sc_mage * m, struct spell * sp, int level) log_debug("adding new spell %s to a previously non-mage unit %s\n", sp->sname, unitname(u)); mage = create_mage(u, u->faction?u->faction->magiegebiet:M_GRAY); } - add_spell(&mage->spells, sp); + if (!mage->spellbook) { + mage->spellbook = create_spellbook(0); + } + spellbook_add(mage->spellbook, sp, level); add_spellname(mage, sp); } @@ -1742,10 +1747,8 @@ struct spellbook * unit_get_spellbook(const struct unit * u) { sc_mage * mage = get_mage(u); if (mage) { - if (mage->spells) { -#ifdef TODO + if (mage->spellbook) { return mage->spellbook; -#endif } return faction_get_spellbook(u->faction); } From 8619bd74a820cdecea0343b96845a068807877b0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 May 2012 09:05:03 -0700 Subject: [PATCH 282/400] slow but working solution for getspell. rebuilding that radix tree for every call is insanity. --- src/kernel/magic.c | 59 +++++++++++++++-------------------------- src/kernel/magic.h | 2 -- src/kernel/magic_test.c | 4 +++ src/kernel/unit.c | 1 - src/util/umlaut.c | 4 ++- src/util/umlaut_test.c | 3 ++- 6 files changed, 30 insertions(+), 43 deletions(-) diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 7155d37de..5cc8bba0d 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -507,18 +507,6 @@ sc_mage *create_mage(unit * u, magic_t mtyp) /* ------------------------------------------------------------- */ /* Funktionen für die Bearbeitung der List-of-known-spells */ -void add_spellname(sc_mage * mage, const spell * sp) -{ - spell_names * names = mage->spellnames; - while (names) { - variant token; - const char *n = spell_name(sp, names->lang); - token.v = (void *)sp; - addtoken(&names->tokens, n, token); - names = names->next; - } -} - int u_hasspell(const unit *u, const struct spell *sp) { spellbook * book = unit_get_spellbook(u); @@ -2877,37 +2865,32 @@ spell *unit_getspell(struct unit *u, const char *name, const struct locale * lan sc_mage * mage = get_mage(u); if (mage) { variant token; - struct spell_names * names = mage->spellnames; - for (;names;names=names->next) { - if (names->lang==lang) break; - } - if (!names) { - spellbook *sb = unit_get_spellbook(u); - if (sb) { - quicklist * ql; - int qi; - names = (spell_names *)calloc(1, sizeof(spell_names)); - names->next = mage->spellnames; - names->lang = lang; - names->tokens = 0; + void * tokens = 0; + spellbook *sb = unit_get_spellbook(u); - for (qi = 0, ql = sb->spells; ql; ql_advance(&ql, &qi, 1)) { - spellbook_entry *sbe = (spellbook_entry *)ql_get(ql, qi); - spell *sp = sbe->sp; - const char *n = spell_name(sp, lang); - if (!n) { - log_error("no translation in locale %s for spell %s\n", locale_name(lang), sp->sname); - } else { - token.v = sp; - addtoken(&names->tokens, n, token); - } + if (sb) { + quicklist * ql; + int qi; + + for (qi = 0, ql = sb->spells; ql; ql_advance(&ql, &qi, 1)) { + spellbook_entry *sbe = (spellbook_entry *)ql_get(ql, qi); + spell *sp = sbe->sp; + const char *n = spell_name(sp, lang); + if (!n) { + log_error("no translation in locale %s for spell %s\n", locale_name(lang), sp->sname); + } else { + token.v = sp; + addtoken(&tokens, n, token); } - mage->spellnames = names; } } - if (names && findtoken(names->tokens, name, &token) != E_TOK_NOMATCH) { - return (spell *) token.v; + if (tokens) { + if (findtoken(tokens, name, &token) != E_TOK_NOMATCH) { + freetokens(tokens); + return (spell *) token.v; + } + freetokens(tokens); } } return 0; diff --git a/src/kernel/magic.h b/src/kernel/magic.h index 0ac519711..f896be52d 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -118,7 +118,6 @@ typedef struct sc_mage { int spellcount; combatspell combatspells[MAXCOMBATSPELLS]; struct spellbook *spellbook; - struct spell_names * spellnames; } sc_mage; /* ------------------------------------------------------------- */ @@ -250,7 +249,6 @@ typedef struct sc_mage { /* setzt Kampfzauber */ void unset_combatspell(struct unit *u, struct spell * sp); /* löscht Kampfzauber */ - void add_spellname(sc_mage * mage, const struct spell * sp); /* fügt den Spruch mit der Id spellid der Spruchliste der Einheit hinzu. */ int u_hasspell(const struct unit *u, const struct spell *sp); /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ diff --git a/src/kernel/magic_test.c b/src/kernel/magic_test.c index 42e05a94c..9bcc1d117 100644 --- a/src/kernel/magic_test.c +++ b/src/kernel/magic_test.c @@ -180,6 +180,7 @@ void test_getspell_unit(CuTest * tc) r = findregion(0, 0); f = test_create_faction(0); u = test_create_unit(f, r); + create_mage(u, M_GRAY); skill_enabled[SK_MAGIC] = 1; set_level(u, SK_MAGIC, 1); @@ -206,7 +207,9 @@ void test_getspell_faction(CuTest * tc) test_create_world(); r = findregion(0, 0); f = test_create_faction(0); + f->magiegebiet = M_TYBIED; u = test_create_unit(f, r); + create_mage(u, f->magiegebiet); skill_enabled[SK_MAGIC] = 1; set_level(u, SK_MAGIC, 1); @@ -237,6 +240,7 @@ void test_getspell_school(CuTest * tc) f = test_create_faction(0); f->magiegebiet = M_TYBIED; u = test_create_unit(f, r); + create_mage(u, f->magiegebiet); skill_enabled[SK_MAGIC] = 1; set_level(u, SK_MAGIC, 1); diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 1697daf2b..4131e317b 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1740,7 +1740,6 @@ void unit_add_spell(unit * u, sc_mage * m, struct spell * sp, int level) mage->spellbook = create_spellbook(0); } spellbook_add(mage->spellbook, sp, level); - add_spellname(mage, sp); } struct spellbook * unit_get_spellbook(const struct unit * u) diff --git a/src/util/umlaut.c b/src/util/umlaut.c index 443decfbd..256ec2230 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -212,7 +212,9 @@ void freetokens(void * root) tnode * node = (tnode *)root; int i; for (i=0;node && i!=NODEHASHSIZE;++i) { - freetokens(node->next[i]->node); + if (node->next[i]) { + freetokens(node->next[i]->node); + } } free(node); } diff --git a/src/util/umlaut_test.c b/src/util/umlaut_test.c index 518c63930..7a70ccd5d 100644 --- a/src/util/umlaut_test.c +++ b/src/util/umlaut_test.c @@ -33,7 +33,6 @@ static void test_umlaut(CuTest * tc) variant id; int result; - memset(&tokens, 0, sizeof(tokens)); /* don't crash on an empty set */ result = findtoken(tokens, "herpderp", &id); CuAssertIntEquals(tc, E_TOK_NOMATCH, result); @@ -65,6 +64,8 @@ static void test_umlaut(CuTest * tc) result = findtoken(tokens, "herp-a-derp", &id); CuAssertIntEquals(tc, E_TOK_NOMATCH, result); + + freetokens(tokens); } CuSuite *get_umlaut_suite(void) From da345f0cea0ece5d924b2baa4e723f27d2eea1b4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 May 2012 09:36:32 -0700 Subject: [PATCH 283/400] only read spellbooks when they are specialized (familiars, monsters, E3 factions) --- src/kernel/magic.c | 6 +++++- src/kernel/save.c | 26 ++++++++++++++------------ src/kernel/save.h | 2 +- src/kernel/xmlreader.c | 4 ++-- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 5cc8bba0d..b5f7dbb70 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -290,7 +290,11 @@ static int read_mage(attrib * a, void *owner, struct storage *store) } } } - mage->spellbook = read_spellbook(store); + if (mage->magietyp==M_GRAY) { + read_spellbook(&mage->spellbook, store); + } else { + read_spellbook(0, store); + } return AT_READ_OK; } diff --git a/src/kernel/save.c b/src/kernel/save.c index 0de9d337c..3f1502478 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1204,39 +1204,41 @@ static ally **addally(const faction * f, ally ** sfp, int aid, int state) return &sf->next; } -struct spellbook *read_spellbook(struct storage *store) +void read_spellbook(spellbook **bookp, struct storage *store) { - spellbook * book = 0; int level; for (level=0;;++level) { - spell *sp; + spell *sp = 0; char spname[64]; if (store->version < SPELLNAME_VERSION) { int i = store->r_int(store); if (i < 0) break; - sp = find_spellbyid((unsigned int) i); + if (bookp) { + sp = find_spellbyid((unsigned int) i); + } } else { store->r_tok_buf(store, spname, sizeof(spname)); if (strcmp(spname, "end") == 0) break; - sp = find_spell(spname); - if (!sp) { - log_error("read_spells: could not find spell '%s'\n", spname); + if (bookp) { + sp = find_spell(spname); + if (!sp) { + log_error("read_spells: could not find spell '%s'\n", spname); + } } } if (store->version >= SPELLBOOK_VERSION) { level = store->r_int(store); } if (sp) { - if (!book) { - book = create_spellbook(0); + if (!*bookp) { + *bookp = create_spellbook(0); } - spellbook_add(book, sp, level); + spellbook_add(*bookp, sp, level); } } - return book; } void write_spellbook(const struct spellbook *book, struct storage *store) @@ -1393,7 +1395,7 @@ faction *readfaction(struct storage * store) read_groups(store, f); f->spellbook = 0; if (store->version >= REGIONOWNER_VERSION) { - f->spellbook = read_spellbook(store); + read_spellbook(FactionSpells() ? &f->spellbook : 0, store); } return f; } diff --git a/src/kernel/save.h b/src/kernel/save.h index 41f1c4893..58c7d5356 100644 --- a/src/kernel/save.h +++ b/src/kernel/save.h @@ -47,7 +47,7 @@ extern "C" { extern void read_items(struct storage *store, struct item **it); extern void write_items(struct storage *store, struct item *it); - extern struct spellbook *read_spellbook(struct storage *store); + extern void read_spellbook(struct spellbook **bookp, struct storage *store); extern void write_spellbook(const struct spellbook *book, struct storage *store); extern void write_unit(struct storage *store, const struct unit *u); diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 22d62b0d1..c87f7449a 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1957,8 +1957,8 @@ static int parse_races(xmlDocPtr doc) attack->data.sp = xml_spell(node, "spell"); if (attack->data.sp) { attack->level = xml_ivalue(node, "level", 0); - if (attack->level > 0) { - log_error("magical attack '%s' needs a level: %d\n", attack->data.sp->sname, attack->level); + if (attack->level <= 0) { + log_error("magical attack '%s' for race '%s' needs a level: %d\n", attack->data.sp->sname, rc->_name[0], attack->level); } } } From 81f08b31214f186c903a5e555c1c84ba6d6d48ec Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 May 2012 09:41:21 -0700 Subject: [PATCH 284/400] remove spell-levels from XML file, we no longer read these or need these. --- res/spells.xml | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/res/spells.xml b/res/spells.xml index 4ec6f9fce..cb7fcf911 100644 --- a/res/spells.xml +++ b/res/spells.xml @@ -24,12 +24,12 @@ - + - + @@ -37,19 +37,19 @@ - + - + - + @@ -57,18 +57,18 @@ - + - + - + @@ -76,12 +76,12 @@ - + - + @@ -89,25 +89,25 @@ - + - + - + - + @@ -115,7 +115,7 @@ - + @@ -123,20 +123,20 @@ - + - + - + From 8a27917f27955d3d270a2654c893935d984f9048 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 May 2012 09:57:07 -0700 Subject: [PATCH 285/400] we have one more famililar spell that got renamed --- src/kernel/spell.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/kernel/spell.c b/src/kernel/spell.c index eb59a4f68..6c2993a79 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -76,6 +76,7 @@ static const char *sp_aliases[][2] = { {"gwyrrdfamiliar", "summon_familiar"}, {"illaunfamiliar", "summon_familiar"}, {"draigfamiliar", "summon_familiar"}, + {"commonfamiliar", "summon_familiar"}, {NULL, NULL}, }; From 5547893be7fc619c9d2a8a788f43797bfe124ee8 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 May 2012 10:16:39 -0700 Subject: [PATCH 286/400] fix create_roi function in E3 --- scripts/tests/spells.lua | 1 + src/gamecode/laws.c | 42 ++++++++++++++++++++++++++++++---------- src/kernel/magic.c | 10 +++++++--- 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/scripts/tests/spells.lua b/scripts/tests/spells.lua index 763f67953..f790e58fd 100644 --- a/scripts/tests/spells.lua +++ b/scripts/tests/spells.lua @@ -18,6 +18,7 @@ function test_roi() u.magic = "tybied" u.aura = 200 u.ship = s1 + -- local err = u:add_spell("create_roi") -- assert_equal(0, err) u:clear_orders() diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 26cb72b36..317def2ca 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -78,6 +78,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include @@ -3713,6 +3714,20 @@ static int faction_getmages(faction * f, unit ** results, int numresults) return maxlevel; } +static void copy_spells(const spellbook * src, spellbook * dst, int maxlevel) +{ + assert(dst); + if (src && src->spells) { + quicklist *ql; + int qi; + for (qi = 0, ql = src->spells; ql; ql_advance(&ql, &qi, 1)) { + spellbook_entry * sbe = (spellbook_entry *)ql_get(ql, qi); + if (sbe->level<=maxlevel) { + spellbook_add(dst, sbe->sp, sbe->level); + } + } + } +} static void update_spells(void) { faction *f; @@ -3723,17 +3738,24 @@ static void update_spells(void) int i; int maxlevel = faction_getmages(f, mages, MAXMAGES); - if (FactionSpells() && maxlevel > f->max_spelllevel) { - static spellbook * common_spells; - if (!common_spells) { - const char *common_school = get_param(global.parameters, "rules.magic.common"); - if (!common_school) common_school = "common"; - common_spells = get_spellbook(common_school); - if (!common_spells) { - log_error("could not find a book of common spells: '%s'\n", common_school); - } + if (maxlevel && FactionSpells()) { + spellbook * book = get_spellbook(magic_school[f->magiegebiet]); + if (!f->spellbook) { + f->spellbook = create_spellbook(0); + } + copy_spells(book, f->spellbook, maxlevel); + if (maxlevel > f->max_spelllevel) { + static spellbook * common_spells; + if (!common_spells) { + const char *common_school = get_param(global.parameters, "rules.magic.common"); + if (!common_school) common_school = "common"; + common_spells = get_spellbook(common_school); + if (!common_spells) { + log_error("could not find a book of common spells: '%s'\n", common_school); + } + } + pick_random_spells(f, maxlevel, common_spells, COMMONSPELLS); } - pick_random_spells(f, maxlevel, common_spells, COMMONSPELLS); } show_new_spells(f, maxlevel, faction_get_spellbook(f)); for (i=0; i!=MAXMAGES && mages[i]; ++i) { diff --git a/src/kernel/magic.c b/src/kernel/magic.c index b5f7dbb70..9559e2316 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -2477,6 +2477,7 @@ static castorder *cast_cmd(unit * u, order * ord) plane *pl; spellparameter *args = NULL; unit * caster = u; + param_t param; if (LongHunger(u)) { cmistake(u, ord, 224, MSG_MAGIC); @@ -2492,8 +2493,9 @@ static castorder *cast_cmd(unit * u, order * ord) init_tokens(ord); skip_token(); s = getstrtoken(); + param = findparam(s, u->faction->locale); /* für Syntax ' STUFE x REGION y z ' */ - if (findparam(s, u->faction->locale) == P_LEVEL) { + if (param == P_LEVEL) { int p = getint(); level = MIN(p, level); if (level < 1) { @@ -2502,8 +2504,9 @@ static castorder *cast_cmd(unit * u, order * ord) return 0; } s = getstrtoken(); + param = findparam(s, u->faction->locale); } - if (findparam(s, u->faction->locale) == P_REGION) { + if (param == P_REGION) { int t_x = getint(); int t_y = getint(); plane *pl = getplane(u->region); @@ -2518,10 +2521,11 @@ static castorder *cast_cmd(unit * u, order * ord) return 0; } s = getstrtoken(); + param = findparam(s, u->faction->locale); } /* für Syntax ' REGION x y STUFE z ' * hier nach REGION nochmal auf STUFE prüfen */ - if (findparam(s, u->faction->locale) == P_LEVEL) { + if (param == P_LEVEL) { int p = getint(); level = MIN(p, level); if (level < 1) { From 707262c61daeeb8dd92da97abbebebb9ad21302b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 May 2012 10:43:05 -0700 Subject: [PATCH 287/400] fix region owner when a building transfers --- src/bindings/bind_building.c | 5 ++++- src/gamecode/economy.c | 6 +++++- src/kernel/building.c | 6 +++--- src/kernel/building.h | 2 +- src/kernel/building_test.c | 2 +- src/kernel/reports_test.c | 4 ++-- src/kernel/save.c | 4 ++-- src/kernel/ship.c | 6 +++--- src/kernel/ship.h | 2 +- src/kernel/ship_test.c | 2 +- src/kernel/unit.c | 4 ++-- 11 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/bindings/bind_building.c b/src/bindings/bind_building.c index 97432bfca..4e51a0a65 100644 --- a/src/bindings/bind_building.c +++ b/src/bindings/bind_building.c @@ -170,7 +170,10 @@ static int tolua_building_set_owner(lua_State * L) { building *b = (building *) tolua_tousertype(L, 1, 0); unit *u = (unit *) tolua_tousertype(L, 2, 0); - building_set_owner(b, u); + if (b!=u->building) { + u_set_building(u, b); + } + building_set_owner(u); return 0; } diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index 11c0a9245..2d0af734c 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -631,15 +631,19 @@ static void give_control(unit * u, unit * u2) if (u->building && u->faction != u2->faction && rule_region_owners()) { region *r = u->region; faction *f = region_get_owner(r); + + assert(u->building==u2->building); if (f == u->faction) { building *b = largestbuilding(r, &cmp_current_owner, false); if (b == u->building) { friendly_takeover(r, u2->faction); } } + building_set_owner(u2); } if (u->ship) { - ship_set_owner(u->ship, u2); + assert(u->ship==u2->ship); + ship_set_owner(u2); } } diff --git a/src/kernel/building.c b/src/kernel/building.c index 77af096cb..a5178a17d 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -627,10 +627,10 @@ const char *buildingname(const building * b) return write_buildingname(b, ibuf, sizeof(name)); } -void building_set_owner(struct building *b, struct unit * owner) +void building_set_owner(struct unit * owner) { - assert(b && owner && owner->building==b); - b->_owner = owner; + assert(owner && owner->building); + owner->building->_owner = owner; } static unit *building_owner_ex(const building * bld, const struct faction * last_owner) diff --git a/src/kernel/building.h b/src/kernel/building.h index 2c7cec522..f78ba1db8 100644 --- a/src/kernel/building.h +++ b/src/kernel/building.h @@ -152,7 +152,7 @@ extern "C" { extern struct building *findbuilding(int n); extern struct unit *building_owner(const struct building *b); - extern void building_set_owner(struct building *b, struct unit * u); + extern void building_set_owner(struct unit * u); extern void building_update_owner(struct building * bld); extern struct attrib_type at_building_action; diff --git a/src/kernel/building_test.c b/src/kernel/building_test.c index 42f68690d..956266715 100644 --- a/src/kernel/building_test.c +++ b/src/kernel/building_test.c @@ -50,7 +50,7 @@ static void test_building_set_owner(CuTest * tc) u2 = test_create_unit(f, r); u_set_building(u2, bld); CuAssertPtrEquals(tc, u1, building_owner(bld)); - building_set_owner(bld, u2); + building_set_owner(u2); CuAssertPtrEquals(tc, u2, building_owner(bld)); } diff --git a/src/kernel/reports_test.c b/src/kernel/reports_test.c index c35d704d2..29bc9f5d2 100644 --- a/src/kernel/reports_test.c +++ b/src/kernel/reports_test.c @@ -34,13 +34,13 @@ static void test_reorder_units(CuTest * tc) u_set_ship(u0, s); u1 = test_create_unit(f, r); u_set_ship(u1, s); - ship_set_owner(s, u1); + ship_set_owner(u1); u2 = test_create_unit(f, r); u3 = test_create_unit(f, r); u_set_building(u3, b); u4 = test_create_unit(f, r); u_set_building(u4, b); - building_set_owner(b, u4); + building_set_owner(u4); reorder_units(r); diff --git a/src/kernel/save.c b/src/kernel/save.c index 3f1502478..7fe3572e8 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -802,7 +802,7 @@ unit *read_unit(struct storage *store) if (b) { u_set_building(u, b); if (fval(u, UFL_OWNER)) { - building_set_owner(b, u); + building_set_owner(u); } } else { log_error("read_unit: unit in unkown building '%s'\n", itoa36(n)); @@ -815,7 +815,7 @@ unit *read_unit(struct storage *store) if (sh) { u_set_ship(u, sh); if (fval(u, UFL_OWNER)) { - ship_set_owner(sh, u); + ship_set_owner(u); } } else { log_error("read_unit: unit in unkown ship '%s'\n", itoa36(n)); diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 46f75689d..63787a3ab 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -286,9 +286,9 @@ void getshipweight(const ship * sh, int *sweight, int *scabins) } } -void ship_set_owner(ship * sh, unit * u) { - assert(u->ship==sh); - sh->_owner = u; +void ship_set_owner(unit * u) { + assert(u && u->ship); + u->ship->_owner = u; } static unit * ship_owner_ex(const ship * sh, const struct faction * last_owner) diff --git a/src/kernel/ship.h b/src/kernel/ship.h index fe1322f47..8249a1beb 100644 --- a/src/kernel/ship.h +++ b/src/kernel/ship.h @@ -95,7 +95,7 @@ extern "C" { } ship; extern void damage_ship(struct ship * sh, double percent); - extern void ship_set_owner(struct ship * sh, struct unit * u); + extern void ship_set_owner(struct unit * u); extern struct unit *ship_owner(const struct ship *sh); extern void ship_update_owner(struct ship * sh); diff --git a/src/kernel/ship_test.c b/src/kernel/ship_test.c index 6b1d2e136..488e61eef 100644 --- a/src/kernel/ship_test.c +++ b/src/kernel/ship_test.c @@ -50,7 +50,7 @@ static void test_ship_set_owner(CuTest * tc) u2 = test_create_unit(f, r); u_set_ship(u2, sh); CuAssertPtrEquals(tc, u1, ship_owner(sh)); - ship_set_owner(sh, u2); + ship_set_owner(u2); CuAssertPtrEquals(tc, u2, ship_owner(sh)); } diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 4131e317b..d67f42a43 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -781,7 +781,7 @@ void u_set_building(unit * u, building * b) assert(!u->building); /* you must leave first */ u->building = b; if (b && !b->_owner) { - building_set_owner(b, u); + building_set_owner(u); } } @@ -790,7 +790,7 @@ void u_set_ship(unit * u, ship * sh) assert(!u->ship); /* you must leave_ship */ u->ship = sh; if (sh && !sh->_owner) { - ship_set_owner(sh, u); + ship_set_owner(u); } } From 2103c1725ecaa7e6b726a1deea2156d2aad278bd Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 May 2012 11:29:27 -0700 Subject: [PATCH 288/400] Fix accidental parsing of empty strings (Bug 1917) --- src/gamecode/laws.c | 52 +++++++++++++++++++++++---------------------- src/kernel/config.c | 2 +- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 317def2ca..660fc1580 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -2445,34 +2445,36 @@ static void reshow(unit * u, struct order *ord, const char *s, param_t p) cmistake(u, ord, 285, MSG_EVENT); break; case NOPARAM: - /* check if it's an item */ - itype = finditemtype(s, u->faction->locale); - if (itype != NULL) { - ptype = resource2potion(item2resource(itype)); - if (ptype != NULL) { - if (display_potion(u->faction, u, ptype)) - break; - } else { - if (display_item(u->faction, u, itype)) - break; + if (s) { + /* check if it's an item */ + itype = finditemtype(s, u->faction->locale); + if (itype != NULL) { + ptype = resource2potion(item2resource(itype)); + if (ptype != NULL) { + if (display_potion(u->faction, u, ptype)) + break; + } else { + if (display_item(u->faction, u, itype)) + break; + } } - } - /* try for a spell */ - sp = unit_getspell(u, s, u->faction->locale); - if (sp) { - attrib *a = a_find(u->faction->attribs, &at_seenspell); - while (a != NULL && a->type == &at_seenspell && a->data.v != sp) { - a = a->next; + /* try for a spell */ + sp = unit_getspell(u, s, u->faction->locale); + if (sp) { + attrib *a = a_find(u->faction->attribs, &at_seenspell); + while (a != NULL && a->type == &at_seenspell && a->data.v != sp) { + a = a->next; + } + if (a != NULL) { + a_remove(&u->faction->attribs, a); + } + break; } - if (a != NULL) { - a_remove(&u->faction->attribs, a); + /* last, check if it's a race. */ + rc = findrace(s, u->faction->locale); + if (rc != NULL && display_race(u->faction, u, rc)) { + break; } - break; - } - /* last, check if it's a race. */ - rc = findrace(s, u->faction->locale); - if (rc != NULL && display_race(u->faction, u, rc)) { - break; } cmistake(u, ord, 21, MSG_EVENT); break; diff --git a/src/kernel/config.c b/src/kernel/config.c index 7033e4ba8..114e5cafb 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -1397,7 +1397,7 @@ param_t findparam(const char *s, const struct locale * lang) char buffer[64]; char * str = transliterate(buffer, sizeof(buffer)-sizeof(int), s); - if (str) { + if (str && *str) { int i; const void * match; void **tokens = get_translations(lang, UT_PARAMS); From 62a91f455821dbb428b30d6b9e4e4e8d94d0b63c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 May 2012 14:19:35 -0700 Subject: [PATCH 289/400] kill tybied in E3, make common spells the source for random choices --- scripts/tests/spells.lua | 4 ++-- src/gamecode/laws.c | 11 ++--------- src/kernel/magic.c | 21 ++++++++++++++------- src/kernel/save.c | 35 +++++++++++++++++++++++++++++++---- src/kernel/save.h | 2 +- src/kernel/spellbook.c | 2 +- 6 files changed, 51 insertions(+), 24 deletions(-) diff --git a/scripts/tests/spells.lua b/scripts/tests/spells.lua index f790e58fd..0101c2518 100644 --- a/scripts/tests/spells.lua +++ b/scripts/tests/spells.lua @@ -14,8 +14,8 @@ function test_roi() u.race = "elf" u:set_skill("magic", 10) u:add_item("money", 3010) - f.magic = "tybied" - u.magic = "tybied" + f.magic = "gwyrrd" + u.magic = "gwyrrd" u.aura = 200 u.ship = s1 diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 660fc1580..f4bc53952 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -3730,6 +3730,7 @@ static void copy_spells(const spellbook * src, spellbook * dst, int maxlevel) } } } + static void update_spells(void) { faction *f; @@ -3747,15 +3748,7 @@ static void update_spells(void) } copy_spells(book, f->spellbook, maxlevel); if (maxlevel > f->max_spelllevel) { - static spellbook * common_spells; - if (!common_spells) { - const char *common_school = get_param(global.parameters, "rules.magic.common"); - if (!common_school) common_school = "common"; - common_spells = get_spellbook(common_school); - if (!common_spells) { - log_error("could not find a book of common spells: '%s'\n", common_school); - } - } + spellbook * common_spells = get_spellbook(magic_school[M_COMMON]); pick_random_spells(f, maxlevel, common_spells, COMMONSPELLS); } } diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 9559e2316..783ef5cad 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -245,6 +245,14 @@ void read_spells(struct quicklist **slistp, magic_t mtype, } } +int get_spell_level_mage(const spell * sp, void * cbdata) +{ + sc_mage *mage = (sc_mage *)cbdata; + spellbook *book = get_spellbook(magic_school[mage->magietyp]); + spellbook_entry *sbe = spellbook_get(book, sp); + return sbe ? sbe->level : 0; +} + static int read_mage(attrib * a, void *owner, struct storage *store) { int i, mtype; @@ -291,9 +299,9 @@ static int read_mage(attrib * a, void *owner, struct storage *store) } } if (mage->magietyp==M_GRAY) { - read_spellbook(&mage->spellbook, store); + read_spellbook(&mage->spellbook, store, get_spell_level_mage, mage); } else { - read_spellbook(0, store); + read_spellbook(0, store, 0, mage); } return AT_READ_OK; } @@ -420,15 +428,14 @@ void show_new_spells(faction * f, int level, const spellbook *book) for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi); if (sbe->level <= level) { - spell * sp = sbe->sp; - if (!already_seen(f, sp)) { + if (!already_seen(f, sbe->sp)) { attrib * a = a_new(&at_reportspell); spellbook_entry * entry = (spellbook_entry *)a->data.v; - entry->level = level; - entry->sp = sp; + entry->level = sbe->level; + entry->sp = sbe->sp; a_add(&f->attribs, a); - a_add(&f->attribs, a_new(&at_seenspell))->data.v = sp; + a_add(&f->attribs, a_new(&at_seenspell))->data.v = sbe->sp; } } } diff --git a/src/kernel/save.c b/src/kernel/save.c index 7fe3572e8..4a7454a48 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1204,12 +1204,36 @@ static ally **addally(const faction * f, ally ** sfp, int aid, int state) return &sf->next; } -void read_spellbook(spellbook **bookp, struct storage *store) +int get_spell_level_faction(const spell * sp, void * cbdata) { - int level; - for (level=0;;++level) { + static spellbook * common = 0; + spellbook * book; + faction * f = (faction *)cbdata; + spellbook_entry * sbe; + + book = get_spellbook(magic_school[f->magiegebiet]); + if (book) { + sbe = spellbook_get(book, sp); + if (sbe) return sbe->level; + } + if (!common) { + common = get_spellbook(magic_school[M_COMMON]); + } + sbe = spellbook_get(common, sp); + if (sbe) { + return sbe->level; + } else { + log_error("read_spellbook: faction '%s' has a spell with unknown level: '%s'", factionname(f), sp->sname); + } + return 0; +} + +void read_spellbook(spellbook **bookp, struct storage *store, int (*get_level)(const spell * sp, void *), void * cbdata) +{ + for (;;) { spell *sp = 0; char spname[64]; + int level = 0; if (store->version < SPELLNAME_VERSION) { int i = store->r_int(store); @@ -1233,6 +1257,9 @@ void read_spellbook(spellbook **bookp, struct storage *store) level = store->r_int(store); } if (sp) { + if (level<=0 && get_level) { + level = get_level(sp, cbdata); + } if (!*bookp) { *bookp = create_spellbook(0); } @@ -1395,7 +1422,7 @@ faction *readfaction(struct storage * store) read_groups(store, f); f->spellbook = 0; if (store->version >= REGIONOWNER_VERSION) { - read_spellbook(FactionSpells() ? &f->spellbook : 0, store); + read_spellbook(FactionSpells() ? &f->spellbook : 0, store, get_spell_level_faction, (void *)f); } return f; } diff --git a/src/kernel/save.h b/src/kernel/save.h index 58c7d5356..cd1fd6533 100644 --- a/src/kernel/save.h +++ b/src/kernel/save.h @@ -47,7 +47,7 @@ extern "C" { extern void read_items(struct storage *store, struct item **it); extern void write_items(struct storage *store, struct item *it); - extern void read_spellbook(struct spellbook **bookp, struct storage *store); + extern void read_spellbook(struct spellbook **bookp, struct storage *store, int (*get_level)(const struct spell * sp, void *), void * cbdata); extern void write_spellbook(const struct spellbook *book, struct storage *store); extern void write_unit(struct storage *store, const struct unit *u); diff --git a/src/kernel/spellbook.c b/src/kernel/spellbook.c index 16e88b101..45d2f6d50 100644 --- a/src/kernel/spellbook.c +++ b/src/kernel/spellbook.c @@ -20,7 +20,7 @@ void spellbook_add(spellbook *sb, struct spell * sp, int level) { spellbook_entry * sbe = (spellbook_entry *)malloc(sizeof(spellbook_entry)); - assert(sb); + assert(sb && level>0); sbe->sp = sp; sbe->level = level; ql_push(&sb->spells, sbe); From e4244f6282f45c6657d052852f1e322230581ccf Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 May 2012 14:50:00 -0700 Subject: [PATCH 290/400] Familiars and monsters should not get spells from the faction's list. --- src/kernel/unit.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/kernel/unit.c b/src/kernel/unit.c index d67f42a43..a1c4bc50e 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1749,7 +1749,9 @@ struct spellbook * unit_get_spellbook(const struct unit * u) if (mage->spellbook) { return mage->spellbook; } - return faction_get_spellbook(u->faction); + if (mage->magietyp!=M_GRAY) { + return faction_get_spellbook(u->faction); + } } return 0; } \ No newline at end of file From 36ad7273940cada0245f7240c2fa6c95b26a8e1d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 26 May 2012 15:15:18 -0700 Subject: [PATCH 291/400] avoid duplicate spells in spellbooks (it's a bit hackish) --- src/gamecode/laws.c | 4 +++- src/kernel/save.c | 8 ++++++-- src/kernel/spellbook.c | 7 +++++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index f4bc53952..27f069345 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -3725,7 +3725,9 @@ static void copy_spells(const spellbook * src, spellbook * dst, int maxlevel) for (qi = 0, ql = src->spells; ql; ql_advance(&ql, &qi, 1)) { spellbook_entry * sbe = (spellbook_entry *)ql_get(ql, qi); if (sbe->level<=maxlevel) { - spellbook_add(dst, sbe->sp, sbe->level); + if (!spellbook_get(dst, sbe->sp)) { + spellbook_add(dst, sbe->sp, sbe->level); + } } } } diff --git a/src/kernel/save.c b/src/kernel/save.c index 4a7454a48..20f1eb39d 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1257,13 +1257,17 @@ void read_spellbook(spellbook **bookp, struct storage *store, int (*get_level)(c level = store->r_int(store); } if (sp) { + spellbook * sb = *bookp; if (level<=0 && get_level) { level = get_level(sp, cbdata); } - if (!*bookp) { + if (!sb) { *bookp = create_spellbook(0); + sb = *bookp; + } + if (store->version>=SPELLBOOK_VERSION || !spellbook_get(sb, sp)) { + spellbook_add(sb, sp, level); } - spellbook_add(*bookp, sp, level); } } } diff --git a/src/kernel/spellbook.c b/src/kernel/spellbook.c index 45d2f6d50..ab73bdd09 100644 --- a/src/kernel/spellbook.c +++ b/src/kernel/spellbook.c @@ -18,9 +18,12 @@ spellbook * create_spellbook(const char * name) void spellbook_add(spellbook *sb, struct spell * sp, int level) { - spellbook_entry * sbe = (spellbook_entry *)malloc(sizeof(spellbook_entry)); + spellbook_entry * sbe; - assert(sb && level>0); + assert(sb && sp && level>0); + assert(!spellbook_get(sb, sp)); + + sbe = (spellbook_entry *)malloc(sizeof(spellbook_entry)); sbe->sp = sp; sbe->level = level; ql_push(&sb->spells, sbe); From 131840054cb3c3b997e778aea716d2db75a2c8eb Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 27 May 2012 08:38:17 -0700 Subject: [PATCH 292/400] giving ownerships over buildings was broken by a recent refactoring --- src/gamecode.vcxproj | 1 + src/gamecode.vcxproj.filters | 3 ++ src/gamecode/economy.c | 20 ++++++------ src/gamecode/economy.h | 1 + src/gamecode/economy_test.c | 60 ++++++++++++++++++++++++++++++++++++ src/tests.c | 10 +++--- 6 files changed, 82 insertions(+), 13 deletions(-) create mode 100644 src/gamecode/economy_test.c diff --git a/src/gamecode.vcxproj b/src/gamecode.vcxproj index 17572c776..e9cd8c4be 100644 --- a/src/gamecode.vcxproj +++ b/src/gamecode.vcxproj @@ -92,6 +92,7 @@ + diff --git a/src/gamecode.vcxproj.filters b/src/gamecode.vcxproj.filters index 9105225f2..176c488c8 100644 --- a/src/gamecode.vcxproj.filters +++ b/src/gamecode.vcxproj.filters @@ -68,6 +68,9 @@ Source Files + + Source Files + diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index 2d0af734c..dcf4bdcc7 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -626,17 +626,19 @@ static void friendly_takeover(region * r, faction * f) } } -static void give_control(unit * u, unit * u2) +void give_control(unit * u, unit * u2) { - if (u->building && u->faction != u2->faction && rule_region_owners()) { - region *r = u->region; - faction *f = region_get_owner(r); + if (u->building) { + if (u->faction != u2->faction && rule_region_owners()) { + region *r = u->region; + faction *f = region_get_owner(r); - assert(u->building==u2->building); - if (f == u->faction) { - building *b = largestbuilding(r, &cmp_current_owner, false); - if (b == u->building) { - friendly_takeover(r, u2->faction); + assert(u->building==u2->building); + if (f == u->faction) { + building *b = largestbuilding(r, &cmp_current_owner, false); + if (b == u->building) { + friendly_takeover(r, u2->faction); + } } } building_set_owner(u2); diff --git a/src/gamecode/economy.h b/src/gamecode/economy.h index 9d931e433..b5ccac86d 100644 --- a/src/gamecode/economy.h +++ b/src/gamecode/economy.h @@ -55,6 +55,7 @@ extern "C" { extern void split_allocations(struct region *r); extern int recruit_archetypes(void); extern int give_control_cmd(struct unit *u, struct order *ord); + extern void give_control(struct unit * u, struct unit * u2); #ifdef __cplusplus } diff --git a/src/gamecode/economy_test.c b/src/gamecode/economy_test.c new file mode 100644 index 000000000..0d44c2dc1 --- /dev/null +++ b/src/gamecode/economy_test.c @@ -0,0 +1,60 @@ +#include "platform.h" +#include "economy.h" + +#include +#include +#include +#include + +#include +#include + +static void test_give_control_building(CuTest * tc) +{ + unit *u1, *u2; + building *b; + struct faction *f; + region *r; + + test_cleanup(); + test_create_world(); + f = test_create_faction(0); + r = findregion(0, 0); + b = test_create_building(r, 0); + u1 = test_create_unit(f, r); + u_set_building(u1, b); + u2 = test_create_unit(f, r); + u_set_building(u2, b); + CuAssertPtrEquals(tc, u1, building_owner(b)); + give_control(u1, u2); + CuAssertPtrEquals(tc, u2, building_owner(b)); +} + +static void test_give_control_ship(CuTest * tc) +{ + unit *u1, *u2; + ship *sh; + struct faction *f; + region *r; + + test_cleanup(); + test_create_world(); + f = test_create_faction(0); + r = findregion(0, 0); + sh = test_create_ship(r, 0); + u1 = test_create_unit(f, r); + u_set_ship(u1, sh); + u2 = test_create_unit(f, r); + u_set_ship(u2, sh); + CuAssertPtrEquals(tc, u1, ship_owner(sh)); + give_control(u1, u2); + CuAssertPtrEquals(tc, u2, ship_owner(sh)); +} + +CuSuite *get_economy_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_give_control_building); + SUITE_ADD_TEST(suite, test_give_control_ship); + return suite; +} diff --git a/src/tests.c b/src/tests.c index 4dcdaa1b3..1f6d4df38 100644 --- a/src/tests.c +++ b/src/tests.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -67,6 +68,7 @@ int RunAllTests(void) /* gamecode */ CuSuiteAddSuite(suite, get_market_suite()); CuSuiteAddSuite(suite, get_laws_suite()); + CuSuiteAddSuite(suite, get_economy_suite()); CuSuiteRun(suite); CuSuiteSummary(suite, output); @@ -137,15 +139,15 @@ test_create_terrain(const char * name, unsigned int flags) building * test_create_building(region * r, const building_type * btype) { - building * b = new_building(btype, r, default_locale); - b->size = btype->maxsize>0?btype->maxsize:1; + building * b = new_building(btype?btype:bt_find("castle"), r, default_locale); + b->size = b->type->maxsize>0?b->type->maxsize:1; return b; } ship * test_create_ship(region * r, const ship_type * stype) { - ship * s = new_ship(stype, r, default_locale); - s->size = stype->construction?stype->construction->maxsize:1; + ship * s = new_ship(stype?stype:st_find("boat"), r, default_locale); + s->size = s->type->construction?s->type->construction->maxsize:1; return s; } From 7152ffd40f39e2ff3882a0aa7743e5f0944ef5d8 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 27 May 2012 09:52:44 -0700 Subject: [PATCH 293/400] this spell school was misnamed. that's trouble. --- res/spellbooks/tybied.xml | 2 +- src/kernel/spellbook.c | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/res/spellbooks/tybied.xml b/res/spellbooks/tybied.xml index 2965ec782..f6db0bfd5 100644 --- a/res/spellbooks/tybied.xml +++ b/res/spellbooks/tybied.xml @@ -1,5 +1,5 @@ - + diff --git a/src/kernel/spellbook.c b/src/kernel/spellbook.c index ab73bdd09..7093fca84 100644 --- a/src/kernel/spellbook.c +++ b/src/kernel/spellbook.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "spellbook.h" @@ -21,8 +22,11 @@ void spellbook_add(spellbook *sb, struct spell * sp, int level) spellbook_entry * sbe; assert(sb && sp && level>0); - assert(!spellbook_get(sb, sp)); - +#ifndef NDEBUG + if (spellbook_get(sb, sp)) { + log_error("duplicate spell in spellbook '%s': '%s'\n", sb->name, sp->sname); + } +#endif sbe = (spellbook_entry *)malloc(sizeof(spellbook_entry)); sbe->sp = sp; sbe->level = level; From 131efac393bf8c9cd0713dcdd3b3a98c36c6d7a1 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 28 May 2012 23:31:46 -0700 Subject: [PATCH 294/400] add a test for f_regionid, catch missing zero-termination --- src/kernel/reports.c | 13 +++++++------ src/kernel/reports_test.c | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/kernel/reports.c b/src/kernel/reports.c index a7244d213..8fb83abd7 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -1858,8 +1858,9 @@ const char *trailinto(const region * r, const struct locale *lang) size_t f_regionid(const region * r, const faction * f, char *buffer, size_t size) { + size_t len; if (!r) { - strncpy(buffer, "(Chaos)", size); + len = strlcpy(buffer, "(Chaos)", size); } else { plane *pl = rplane(r); const char *name = pl ? pl->name : 0; @@ -1867,12 +1868,12 @@ f_regionid(const region * r, const faction * f, char *buffer, size_t size) int named = (name && name[0]); pnormalize(&nx, &ny, pl); adjust_coordinates(f, &nx, &ny, pl, r); - strncpy(buffer, rname(r, f->locale), size); - buffer[size - 1] = 0; - sprintf(buffer + strlen(buffer), " (%d,%d%s%s)", nx, ny, named ? "," : "", - (named) ? name : ""); + len = strlcpy(buffer, rname(r, f?f->locale:0), size); + snprintf(buffer + len, size-len, " (%d,%d%s%s)", nx, ny, named ? "," : "", (named) ? name : ""); + buffer[size-1] = 0; + len=strlen(buffer); } - return strlen(buffer); + return len; } static char *f_regionid_s(const region * r, const faction * f) diff --git a/src/kernel/reports_test.c b/src/kernel/reports_test.c index 29bc9f5d2..d07217ece 100644 --- a/src/kernel/reports_test.c +++ b/src/kernel/reports_test.c @@ -52,9 +52,32 @@ static void test_reorder_units(CuTest * tc) CuAssertPtrEquals(tc, 0, u0->next); } +static void test_regionid(CuTest * tc) { + size_t len; + const struct terrain_type * plain; + struct region * r; + char buffer[64]; + + test_cleanup(); + plain = test_create_terrain("plain", 0); + r = test_create_region(0, 0, plain); + + memset(buffer, 0xff, sizeof(buffer)); + len = f_regionid(r, 0, buffer, sizeof(buffer)); + CuAssertIntEquals(tc, 11, len); + CuAssertStrEquals(tc, "plain (0,0)", buffer); + + memset(buffer, -1, sizeof(buffer)); + len = f_regionid(r, 0, buffer, 11); + CuAssertIntEquals(tc, 10, len); + CuAssertStrEquals(tc, "plain (0,0", buffer); + CuAssertIntEquals(tc, -1, buffer[11]); +} + CuSuite *get_reports_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_reorder_units); + SUITE_ADD_TEST(suite, test_regionid); return suite; } From 330bc9c13b5e028679bcf241277f0af3a18b6598 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 29 May 2012 10:45:46 -0700 Subject: [PATCH 295/400] added slprintf and tests for the bsdstring functions --- src/build/util.c | 7 ++-- src/tests.c | 2 ++ src/util.vcxproj | 1 + src/util.vcxproj.filters | 3 ++ src/util/bsdstring.c | 35 ++++++++++++++++---- src/util/bsdstring.h | 21 ++++++------ src/util/bsdstring_test.c | 68 +++++++++++++++++++++++++++++++++++++++ src/util/strncpy.c | 23 ------------- 8 files changed, 116 insertions(+), 44 deletions(-) create mode 100644 src/util/bsdstring_test.c delete mode 100644 src/util/strncpy.c diff --git a/src/build/util.c b/src/build/util.c index daddfbcdd..7de1d97e9 100644 --- a/src/build/util.c +++ b/src/build/util.c @@ -5,6 +5,8 @@ #include #include +#include + #include #include #include @@ -33,10 +35,5 @@ #include #ifndef HAVE_INLINE -#include #include #endif - -#ifdef __GNUC__ -#include -#endif diff --git a/src/tests.c b/src/tests.c index 1f6d4df38..6e4bf6c4e 100644 --- a/src/tests.c +++ b/src/tests.c @@ -6,6 +6,7 @@ #include "tests_test.c" #include +#include #include #include #include @@ -49,6 +50,7 @@ int RunAllTests(void) CuSuiteAddSuite(suite, get_tests_suite()); /* util */ CuSuiteAddSuite(suite, get_base36_suite()); + CuSuiteAddSuite(suite, get_bsdstring_suite()); CuSuiteAddSuite(suite, get_quicklist_suite()); CuSuiteAddSuite(suite, get_functions_suite()); CuSuiteAddSuite(suite, get_umlaut_suite()); diff --git a/src/util.vcxproj b/src/util.vcxproj index d1695aeac..a0967f595 100644 --- a/src/util.vcxproj +++ b/src/util.vcxproj @@ -125,6 +125,7 @@ + diff --git a/src/util.vcxproj.filters b/src/util.vcxproj.filters index e47bd8168..43fb1d700 100644 --- a/src/util.vcxproj.filters +++ b/src/util.vcxproj.filters @@ -208,5 +208,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/src/util/bsdstring.c b/src/util/bsdstring.c index a2467229f..0b677525e 100644 --- a/src/util/bsdstring.c +++ b/src/util/bsdstring.c @@ -2,12 +2,11 @@ #include #include #include +#include -#ifndef HAVE_INLINE #include "bsdstring.h" -#endif -INLINE_FUNCTION int wrptr(char **ptr, size_t * size, int bytes) +int wrptr(char **ptr, size_t * size, int bytes) { assert(bytes >= 0 || !"you're not using snprintf right, maybe?"); @@ -29,8 +28,9 @@ INLINE_FUNCTION int wrptr(char **ptr, size_t * size, int bytes) return ENAMETOOLONG; } -#if !defined(HAVE_STRLCPY) -INLINE_FUNCTION size_t strlcpy(char *dst, const char *src, size_t siz) +#ifndef HAVE_STRLCPY +#define HAVE_STRLCPY +size_t strlcpy(char *dst, const char *src, size_t siz) { /* copied from OpenBSD source code */ register char *d = dst; register const char *s = src; @@ -53,8 +53,11 @@ INLINE_FUNCTION size_t strlcpy(char *dst, const char *src, size_t siz) return (s - src - 1); /* count does not include NUL */ } +#endif -INLINE_FUNCTION size_t strlcat(char *dst, const char *src, size_t siz) +#ifndef HAVE_STRLCAT +#define HAVE_STRLCAT +size_t strlcat(char *dst, const char *src, size_t siz) { register char *d = dst; register const char *s = src; @@ -81,3 +84,23 @@ INLINE_FUNCTION size_t strlcat(char *dst, const char *src, size_t siz) return (dlen + (s - src)); /* count does not include NUL */ } #endif + +#ifndef HAVE_SLPRINTF +#define HAVE_SLPRINTF +size_t slprintf(char * dst, size_t size, const char * format, ...) +{ + va_list args; + int result; + + va_start(args, format); + result = vsnprintf(dst, size, format, args); + if (result<0 || result>=(int)size) { + dst[size-1]='\0'; + return size; + } + va_start(args, format); + va_end(args); + + return (size_t)result; +} +#endif diff --git a/src/util/bsdstring.h b/src/util/bsdstring.h index dc9e2919b..b917baafa 100644 --- a/src/util/bsdstring.h +++ b/src/util/bsdstring.h @@ -1,19 +1,20 @@ #ifndef UTIL_BSDSTRING_H #define UTIL_BSDSTRING_H -#ifdef HAVE_INLINE -# include "bsdstring.c" -#else -extern size_t strlcpy(char *dst, const char *src, size_t siz); -extern size_t strlcat(char *dst, const char *src, size_t siz); extern int wrptr(char **ptr, size_t * size, int bytes); + +#ifndef HAVE_STRLCPY +extern size_t strlcpy(char *dst, const char *src, size_t siz); +#endif + +#ifndef HAVE_STRLCAT +extern size_t strlcat(char *dst, const char *src, size_t siz); +#endif + +#ifndef HAVE_SLPRINTF +extern size_t slprintf(char * dst, size_t size, const char * format, ...); #endif #define WARN_STATIC_BUFFER() log_warning("static buffer too small in %s:%d\n", __FILE__, __LINE__) -#if !defined(HAVE_STRLPRINTF) -# define HAVE_STRLPRINTF -# define slprintf snprintf -#endif - #endif diff --git a/src/util/bsdstring_test.c b/src/util/bsdstring_test.c new file mode 100644 index 000000000..b084e5c31 --- /dev/null +++ b/src/util/bsdstring_test.c @@ -0,0 +1,68 @@ +#include +#include "bsdstring.h" +#include + +static void test_strlcat(CuTest * tc) +{ + char buffer[32]; + + memset(buffer, -2, sizeof(buffer)); + + buffer[0] = '\0'; + CuAssertIntEquals(tc, 4, strlcat(buffer, "herp", 4)); + CuAssertStrEquals(tc, "her", buffer); + + buffer[0] = '\0'; + CuAssertIntEquals(tc, 4, strlcat(buffer, "herp", 8)); + CuAssertStrEquals(tc, "herp", buffer); + CuAssertIntEquals(tc, -2, buffer[5]); + + CuAssertIntEquals(tc, 8, strlcat(buffer, "derp", 8)); + CuAssertStrEquals(tc, "herpder", buffer); + CuAssertIntEquals(tc, -2, buffer[8]); +} + +static void test_strlcpy(CuTest * tc) +{ + char buffer[32]; + + memset(buffer, -2, sizeof(buffer)); + + CuAssertIntEquals(tc, 4, strlcpy(buffer, "herp", 4)); + CuAssertStrEquals(tc, "her", buffer); + + CuAssertIntEquals(tc, 4, strlcpy(buffer, "herp", 8)); + CuAssertStrEquals(tc, "herp", buffer); + CuAssertIntEquals(tc, -2, buffer[5]); + + CuAssertIntEquals(tc, 8, strlcpy(buffer, "herpderp", 8)); + CuAssertStrEquals(tc, "herpder", buffer); + CuAssertIntEquals(tc, -2, buffer[8]); +} + +static void test_slprintf(CuTest * tc) +{ + char buffer[32]; + + memset(buffer, -2, sizeof(buffer)); + + CuAssertTrue(tc, slprintf(buffer, 4, "%s", "herpderp")>3); + CuAssertStrEquals(tc, "her", buffer); + + CuAssertIntEquals(tc, 4, slprintf(buffer, 8, "%s", "herp")); + CuAssertStrEquals(tc, "herp", buffer); + CuAssertIntEquals(tc, -2, buffer[5]); + + CuAssertIntEquals(tc, 8, slprintf(buffer, 8, "%s", "herpderp")); + CuAssertStrEquals(tc, "herpder", buffer); + CuAssertIntEquals(tc, -2, buffer[8]); +} + +CuSuite *get_bsdstring_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_strlcat); + SUITE_ADD_TEST(suite, test_strlcpy); + SUITE_ADD_TEST(suite, test_slprintf); + return suite; +} diff --git a/src/util/strncpy.c b/src/util/strncpy.c deleted file mode 100644 index 954da8811..000000000 --- a/src/util/strncpy.c +++ /dev/null @@ -1,23 +0,0 @@ - -/* - * Faster replacement for ISO-C strncpy, does not pad with zeros - */ - -#include - -char *strncpy(char *to, const char *from, size_t size) -{ - char *t = to, *f = (char *)from; - int copied = 0; - - while (copied < size) { - *t = *f; - if (*f == '\0') - break; - t++; - f++; - copied++; - } - - return to; -} From 347ff0dd776259cef87b30ada6a499b56392f47e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 29 May 2012 12:17:25 -0700 Subject: [PATCH 296/400] snprintf is evil and dangerous. --- src/bindings/helpers.c | 40 +++++++++++++++++++++++++++++----------- src/gamecode/economy.c | 5 ++++- src/gamecode/laws.c | 8 ++++---- src/gamecode/randenc.c | 4 ++-- src/kernel/alliance.c | 4 ++-- src/kernel/battle.c | 11 ++--------- src/kernel/building.c | 3 +-- src/kernel/config.c | 3 +-- src/kernel/connection.c | 2 +- src/kernel/faction.c | 5 ++--- src/kernel/move.c | 4 +--- src/kernel/region.c | 6 +++--- src/kernel/save.c | 3 ++- src/kernel/ship.c | 3 +-- src/kernel/unit.c | 5 ++++- 15 files changed, 59 insertions(+), 47 deletions(-) diff --git a/src/bindings/helpers.c b/src/bindings/helpers.c index cb586cf9f..28ee984da 100644 --- a/src/bindings/helpers.c +++ b/src/bindings/helpers.c @@ -15,13 +15,14 @@ without prior permission by the authors of Eressea. #include #include +#include #include #include #include #include #include -#include +#include #include #include #include @@ -77,7 +78,8 @@ static int limit_resource(const region * r, const resource_type * rtype) int result = -1; lua_State *L = (lua_State *) global.vm_state; - snprintf(fname, sizeof(fname), "%s_limit", rtype->_name[0]); + strlcpy(fname, rtype->_name[0], sizeof(fname)); + strlcat(fname, "_limit", sizeof(fname)); lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); @@ -105,7 +107,9 @@ produce_resource(region * r, const resource_type * rtype, int norders) { lua_State *L = (lua_State *) global.vm_state; char fname[64]; - snprintf(fname, sizeof(fname), "%s_produce", rtype->_name[0]); + + strlcpy(fname, rtype->_name[0], sizeof(fname)); + strlcat(fname, "_produce", sizeof(fname)); lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); @@ -245,7 +249,9 @@ static int lua_initfamiliar(unit * u) lua_State *L = (lua_State *) global.vm_state; char fname[64]; int result = -1; - snprintf(fname, sizeof(fname), "initfamiliar_%s", u->race->_name[0]); + + strlcpy(fname, "initfamiliar_", sizeof(fname)); + strlcat(fname, u->race->_name[0], sizeof(fname)); lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); @@ -267,7 +273,8 @@ static int lua_initfamiliar(unit * u) create_mage(u, M_GRAY); - snprintf(fname, sizeof(fname), "%s_familiar", u->race->_name[0]); + strlcpy(fname, u->race->_name[0], sizeof(fname)); + strlcat(fname, "_familiar", sizeof(fname)); equip_unit(u, get_equipment(fname)); return result; } @@ -278,7 +285,9 @@ lua_changeresource(unit * u, const struct resource_type *rtype, int delta) lua_State *L = (lua_State *) global.vm_state; int result = -1; char fname[64]; - snprintf(fname, sizeof(fname), "%s_changeresource", rtype->_name[0]); + + strlcpy(fname, rtype->_name[0], sizeof(fname)); + strlcat(fname, "_changeresource", sizeof(fname)); lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); @@ -307,7 +316,9 @@ static int lua_getresource(unit * u, const struct resource_type *rtype) lua_State *L = (lua_State *) global.vm_state; int result = -1; char fname[64]; - snprintf(fname, sizeof(fname), "%s_getresource", rtype->_name[0]); + + strlcpy(fname, rtype->_name[0], sizeof(fname)); + strlcat(fname, "_getresource", sizeof(fname)); lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); @@ -398,7 +409,8 @@ static void lua_agebuilding(building * b) lua_State *L = (lua_State *) global.vm_state; char fname[64]; - snprintf(fname, sizeof(fname), "age_%s", b->type->_name); + strlcpy(fname, "age_", sizeof(fname)); + strlcat(fname, b->type->_name, sizeof(fname)); lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); @@ -502,7 +514,9 @@ static int lua_equipmentcallback(const struct equipment *eq, unit * u) lua_State *L = (lua_State *) global.vm_state; char fname[64]; int result = -1; - snprintf(fname, sizeof(fname), "equip_%s", eq->name); + + strlcpy(fname, "equip_", sizeof(fname)); + strlcat(fname, eq->name, sizeof(fname)); lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); @@ -532,7 +546,9 @@ lua_useitem(struct unit *u, const struct item_type *itype, int amount, lua_State *L = (lua_State *) global.vm_state; int result = 0; char fname[64]; - snprintf(fname, sizeof(fname), "use_%s", itype->rtype->_name[0]); + + strlcpy(fname, "use_", sizeof(fname)); + strlcat(fname, itype->rtype->_name[0], sizeof(fname)); lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); @@ -561,7 +577,9 @@ static int lua_recruit(struct unit *u, const struct archetype *arch, int amount) lua_State *L = (lua_State *) global.vm_state; int result = 0; char fname[64]; - snprintf(fname, sizeof(fname), "recruit_%s", arch->name[0]); + + strlcpy(fname, "recruit_", sizeof(fname)); + strlcat(fname, arch->name[0], sizeof(fname)); lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index dcf4bdcc7..cc516d784 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -55,6 +55,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include #include +#include #include #include #include @@ -264,7 +265,9 @@ static void add_recruits(unit * u, int number, int wanted) unew = create_unit(r, u->faction, number, u->race, 0, NULL, u); } - snprintf(equipment, sizeof(equipment), "new_%s_unit", u->race->_name[0]); + strlcpy(equipment, "new_", sizeof(equipment)); + strlcat(equipment, u->race->_name[0], sizeof(equipment)); + strlcat(equipment, "_unit", sizeof(equipment)); equip_unit(unew, get_equipment(equipment)); if (unew->race->ec_flags & ECF_REC_HORSES) { diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 27f069345..ab79b4122 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -2302,21 +2302,21 @@ static boolean display_race(faction * f, unit * u, const race * rc) /* hp_p : Trefferpunkte */ bytes = - snprintf(bufp, size, " %d %s", rc->hitpoints, LOC(f->locale, + slprintf(bufp, size, " %d %s", rc->hitpoints, LOC(f->locale, "stat_hitpoints")); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); /* b_attacke : Angriff */ bytes = - snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_attack"), + slprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_attack"), (rc->at_default + rc->at_bonus)); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); /* b_defense : Verteidigung */ bytes = - snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_defense"), + slprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_defense"), (rc->df_default + rc->df_bonus)); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -2324,7 +2324,7 @@ static boolean display_race(faction * f, unit * u, const race * rc) /* b_armor : Rüstung */ if (rc->armor > 0) { bytes = - snprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_armor"), rc->armor); + slprintf(bufp, size, ", %s: %d", LOC(f->locale, "stat_armor"), rc->armor); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } diff --git a/src/gamecode/randenc.c b/src/gamecode/randenc.c index b0f422f0b..a2d84f154 100644 --- a/src/gamecode/randenc.c +++ b/src/gamecode/randenc.c @@ -235,9 +235,9 @@ void find_manual(region * r, unit * u) break; } - snprintf(zLocation, sizeof(zLocation), "manual_location_%d", + slprintf(zLocation, sizeof(zLocation), "manual_location_%d", (int)(rng_int() % 4)); - snprintf(zBook, sizeof(zLocation), "manual_title_%s", skillnames[skill]); + slprintf(zBook, sizeof(zLocation), "manual_title_%s", skillnames[skill]); msg = msg_message("find_manual", "unit location book", u, zLocation, zBook); r_addmessage(r, u->faction, msg); diff --git a/src/kernel/alliance.c b/src/kernel/alliance.c index 15d4c7f6d..ddb92fcf4 100644 --- a/src/kernel/alliance.c +++ b/src/kernel/alliance.c @@ -31,6 +31,7 @@ without prior permission by the authors of Eressea. /* util includes */ #include #include +#include #include #include #include @@ -394,8 +395,7 @@ const char *alliancename(const alliance * al) char *ibuf = idbuf[(++nextbuf) % 8]; if (al && al->name) { - snprintf(ibuf, sizeof(name), "%s (%s)", al->name, itoa36(al->id)); - ibuf[sizeof(name) - 1] = 0; + slprintf(ibuf, sizeof(name), "%s (%s)", al->name, itoa36(al->id)); } else { return NULL; } diff --git a/src/kernel/battle.c b/src/kernel/battle.c index 6c51ce01b..36abba1b9 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -211,13 +211,7 @@ static char *sidename(side * s) static char sidename_buf[4][SIDENAMEBUFLEN]; /* STATIC_RESULT: used for return, not across calls */ bufno = bufno % 4; - if (s->stealthfaction) { - snprintf(sidename_buf[bufno], SIDENAMEBUFLEN, - "%s", factionname(s->stealthfaction)); - } else { - snprintf(sidename_buf[bufno], SIDENAMEBUFLEN, - "%s", factionname(s->faction)); - } + strlcpy(sidename_buf[bufno], factionname(s->stealthfaction?s->stealthfaction:s->faction), SIDENAMEBUFLEN); return sidename_buf[bufno++]; } @@ -3850,9 +3844,8 @@ static int battle_report(battle * b) if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } - snprintf(buffer, sizeof(buffer), "%s %2d(%s): ", + slprintf(buffer, sizeof(buffer), "%s %2d(%s): ", loc_army, army_index(s), abbrev); - buffer[sizeof(buffer) - 1] = 0; bytes = (int)strlcpy(bufp, buffer, size); if (wrptr(&bufp, &size, bytes) != 0) diff --git a/src/kernel/building.c b/src/kernel/building.c index a5178a17d..0edb9a6bc 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -613,8 +613,7 @@ int bt_effsize(const building_type * btype, const building * b, int bsize) const char *write_buildingname(const building * b, char *ibuf, size_t size) { - snprintf((char *)ibuf, size, "%s (%s)", b->name, itoa36(b->no)); - ibuf[size - 1] = 0; + slprintf(ibuf, size, "%s (%s)", b->name, itoa36(b->no)); return ibuf; } diff --git a/src/kernel/config.c b/src/kernel/config.c index 114e5cafb..d2eb422d6 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -1653,8 +1653,7 @@ building *largestbuilding(const region * r, cmp_building_cb cmp_gt, char *write_unitname(const unit * u, char *buffer, size_t size) { - snprintf((char *)buffer, size, "%s (%s)", (const char *)u->name, - itoa36(u->no)); + slprintf(buffer, size, "%s (%s)", (const char *)u->name, itoa36(u->no)); buffer[size - 1] = 0; return buffer; } diff --git a/src/kernel/connection.c b/src/kernel/connection.c index 32eb73a6b..98ac0234b 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -532,7 +532,7 @@ static const char *b_nameroad(const connection * b, const region * r, } else { int percent = MAX(1, 100 * local / r->terrain->max_road); if (local) { - snprintf(buffer, sizeof(buffer), LOC(f->locale, mkname("border", + slprintf(buffer, sizeof(buffer), LOC(f->locale, mkname("border", "a_road_percent")), percent); } else { return LOC(f->locale, mkname("border", "a_road_connection")); diff --git a/src/kernel/faction.c b/src/kernel/faction.c index dcfa7b59a..6c33d9dd7 100644 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -153,8 +153,7 @@ const char *factionname(const faction * f) char *ibuf = idbuf[(++nextbuf) % 8]; if (f && f->name) { - snprintf(ibuf, sizeof(name), "%s (%s)", f->name, itoa36(f->no)); - ibuf[sizeof(name) - 1] = 0; + slprintf(ibuf, sizeof(name), "%s (%s)", f->name, itoa36(f->no)); } else { strcpy(ibuf, "Unbekannte Partei (?)"); } @@ -226,7 +225,7 @@ faction *addfaction(const char *email, const char *password, addlist(&factions, f); fhash(f); - snprintf(buf, sizeof(buf), "%s %s", LOC(loc, "factiondefault"), factionid(f)); + slprintf(buf, sizeof(buf), "%s %s", LOC(loc, "factiondefault"), factionid(f)); f->name = strdup(buf); return f; diff --git a/src/kernel/move.c b/src/kernel/move.c index c7a669d9a..5c1f7b9fc 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -2398,9 +2398,7 @@ static int hunt(unit * u, order * ord) } bufp = command; - bytes = - snprintf(bufp, size, "%s %s", LOC(u->faction->locale, keywords[K_MOVE]), - LOC(u->faction->locale, directions[dir])); + bytes = slprintf(bufp, size, "%s %s", LOC(u->faction->locale, keywords[K_MOVE]), LOC(u->faction->locale, directions[dir])); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); diff --git a/src/kernel/region.c b/src/kernel/region.c index fdcc2f39b..6996d959f 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -41,6 +41,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include +#include #include #include #include @@ -114,15 +115,14 @@ const char *write_regionname(const region * r, const faction * f, char *buffer, char *buf = (char *)buffer; const struct locale *lang = f ? f->locale : 0; if (r == NULL) { - strcpy(buf, "(null)"); + strlcpy(buf, "(null)", size); } else { plane *pl = rplane(r); int nx = r->x, ny = r->y; pnormalize(&nx, &ny, pl); adjust_coordinates(f, &nx, &ny, pl, r); - snprintf(buf, size, "%s (%d,%d)", rname(r, lang), nx, ny); + slprintf(buf, size, "%s (%d,%d)", rname(r, lang), nx, ny); } - buf[size - 1] = 0; return buffer; } diff --git a/src/kernel/save.c b/src/kernel/save.c index 20f1eb39d..ccc28c895 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1552,7 +1552,8 @@ int readgame(const char *filename, int mode, int backup) store->r_str_buf(store, basefile, sizeof(basefile)); if (strcmp(game_name, basefile) != 0) { char buffer[64]; - snprintf(buffer, sizeof(buffer), "%s.xml", game_name); + strlcpy(buffer, game_name, sizeof(buffer)); + strlcat(buffer, ".xml", sizeof(buffer)); if (strcmp(basefile, buffer) != 0) { log_warning("game mismatch: datafile contains %s, game is %s\n", basefile, game_name); printf("WARNING: any key to continue, Ctrl-C to stop\n"); diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 63787a3ab..6c008dfd6 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -233,8 +233,7 @@ void free_ships(void) const char *write_shipname(const ship * sh, char *ibuf, size_t size) { - snprintf(ibuf, size, "%s (%s)", sh->name, itoa36(sh->no)); - ibuf[size - 1] = 0; + slprintf(ibuf, size, "%s (%s)", sh->name, itoa36(sh->no)); return ibuf; } diff --git a/src/kernel/unit.c b/src/kernel/unit.c index a1c4bc50e..585696e3f 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -44,6 +44,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include #include +#include #include #include #include @@ -1424,7 +1425,9 @@ void name_unit(unit * u) } else { result = parameters[P_UNIT]; } - snprintf(name, sizeof(name), "%s %s", result, itoa36(u->no)); + strlcpy(name, result, sizeof(name)); + strlcat(name, " ", sizeof(name)); + strlcat(name, itoa36(u->no), sizeof(name)); unit_setname(u, name); } } From cb0e406733f600a01b8555b793e3c3615a7851b4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 29 May 2012 18:08:56 -0700 Subject: [PATCH 297/400] repair lua spells (bad stack index) add a whole bunch more spell tests allow spell tests to disable fumbles --- scripts/tests/spells.lua | 122 ++++++++++++++++++++++++++++++++++----- src/bindings/bindings.c | 8 +-- src/bindings/helpers.c | 5 +- src/kernel/magic.c | 3 + 4 files changed, 116 insertions(+), 22 deletions(-) diff --git a/scripts/tests/spells.lua b/scripts/tests/spells.lua index 0101c2518..1538b4249 100644 --- a/scripts/tests/spells.lua +++ b/scripts/tests/spells.lua @@ -5,25 +5,117 @@ module("tests.spells", package.seeall, lunit.testcase) function setup() free_game() settings.set("magic.fumble.enable", "0") + settings.set("magic.regeneration.enable", "0") + settings.set("rules.economy.food", "0") end -function test_roi() +function test_create_firesword() local r = region.create(0,0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") + local f = faction.create("create_firesword@eressea.de", "human", "de") local u = unit.create(f, r, 1) - u.race = "elf" - u:set_skill("magic", 10) - u:add_item("money", 3010) - f.magic = "gwyrrd" - u.magic = "gwyrrd" - u.aura = 200 - u.ship = s1 + u:set_skill("magic", 12) + u:add_spell("create_firesword") --- local err = u:add_spell("create_roi") --- assert_equal(0, err) - u:clear_orders() - u:add_order("ZAUBERE 'Erschaffe einen Ring der Unsichtbarkeit' ") - process_orders() - write_reports() + u:cast_spell('create_firesword', 1) + assert_equal(1, u:get_item("firesword")) +end + +function test_create_roi() + local r = region.create(0,0, "plain") + local f = faction.create("create_roi@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u:set_skill("magic", 10) + + u:cast_spell('create_roi') assert_equal(1, u:get_item("roi")) end + +function test_create_roqf() + local r = region.create(0,0, "plain") + local f = faction.create("create_roqf@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u:set_skill("magic", 10) + + u:cast_spell('create_roqf') + assert_equal(1, u:get_item("roqf")) +end + +function test_create_aots() + local r = region.create(0,0, "plain") + local f = faction.create("create_aots@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u:set_skill("magic", 10) + + u:cast_spell('create_aots') + assert_equal(1, u:get_item("aots")) +end + +function test_create_ror() + local r = region.create(0,0, "plain") + local f = faction.create("create_ror@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u:set_skill("magic", 10) + + u:cast_spell('create_ror') + assert_equal(1, u:get_item("ror")) +end + +function test_create_magicherbbag() + local r = region.create(0,0, "plain") + local f = faction.create("create_magicherbbag@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u:set_skill("magic", 10) + + u:cast_spell('create_magicherbbag') + assert_equal(1, u:get_item("magicherbbag")) +end + +function test_create_trollbelt() + local r = region.create(0,0, "plain") + local f = faction.create("create_trollbelt@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u:set_skill("magic", 10) + + u:cast_spell('create_trollbelt') + assert_equal(1, u:get_item("trollbelt")) +end + +function test_create_dreameye() + local r = region.create(0,0, "plain") + local f = faction.create("create_dreameye@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u:set_skill("magic", 10) + + u:cast_spell('create_dreameye') + assert_equal(1, u:get_item("dreameye")) +end + +function test_create_antimagic() + local r = region.create(0,0, "plain") + local f = faction.create("create_antimagic@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u:set_skill("magic", 10) + + u:cast_spell('create_antimagic') + assert_equal(1, u:get_item("antimagic")) +end + +function test_create_runesword() + local r = region.create(0,0, "plain") + local f = faction.create("create_runesword@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u:set_skill("magic", 10) + + u:cast_spell('create_runesword') + assert_equal(1, u:get_item("runesword")) +end + +function test_create_rop() + local r = region.create(0,0, "plain") + local f = faction.create("create_rop@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u:set_skill("magic", 10) + + u:cast_spell('create_rop') + assert_equal(1, u:get_item("rop")) +end diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index f633f7716..228b94ada 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -1070,7 +1070,7 @@ static int tolua_eventbus_register(lua_State * L) { void *sender = tolua_tousertype(L, 1, 0); const char *event = tolua_tostring(L, 2, 0); - event_args *args = malloc(sizeof(event_args)); + event_args *args = (event_args *)malloc(sizeof(event_args)); args->sendertype = sender ? tolua_typename(L, 1) : NULL; lua_pushvalue(L, 3); args->hfunction = luaL_ref(L, LUA_REGISTRYINDEX); @@ -1259,10 +1259,8 @@ int tolua_eressea_open(lua_State * L) tolua_function(L, TOLUA_CAST "itoa36", tolua_itoa36); tolua_function(L, TOLUA_CAST "dice_roll", tolua_dice_rand); tolua_function(L, TOLUA_CAST "get_nmrs", tolua_get_nmrs); - tolua_function(L, TOLUA_CAST "remove_empty_units", - tolua_remove_empty_units); - tolua_function(L, TOLUA_CAST "update_subscriptions", - tolua_update_subscriptions); + tolua_function(L, TOLUA_CAST "remove_empty_units", tolua_remove_empty_units); + tolua_function(L, TOLUA_CAST "update_subscriptions", tolua_update_subscriptions); tolua_function(L, TOLUA_CAST "update_scores", tolua_update_scores); tolua_function(L, TOLUA_CAST "update_owners", tolua_update_owners); tolua_function(L, TOLUA_CAST "learn_skill", tolua_learn_skill); diff --git a/src/bindings/helpers.c b/src/bindings/helpers.c index 28ee984da..dec73f5f8 100644 --- a/src/bindings/helpers.c +++ b/src/bindings/helpers.c @@ -203,7 +203,7 @@ static int lua_callspell(castorder * co) lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { + if (lua_isfunction(L, -1)) { int nparam = 4; tolua_pushusertype(L, r, TOLUA_CAST "region"); tolua_pushusertype(L, caster, TOLUA_CAST "unit"); @@ -236,7 +236,8 @@ static int lua_callspell(castorder * co) lua_pop(L, 1); } } else { - log_error("spell(%s) calling '%s': not a function.\n", unitname(caster), fname); + int ltype = lua_type(L, -1); + log_error("spell(%s) calling '%s': not a function, has type %d.\n", unitname(caster), fname, ltype); lua_pop(L, 1); } diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 783ef5cad..581ef4988 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -1452,6 +1452,9 @@ void regeneration_magiepunkte(void) double reg_aura; int regen; double mod; + int regen_enabled = get_param_int(global.parameters, "magic.regeneration.enable", 1); + + if (!regen_enabled) return; for (r = regions; r; r = r->next) { for (u = r->units; u; u = u->next) { From 5e26d246a29797a330a8da29cd1d5f6712b407d6 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 29 May 2012 20:13:54 -0700 Subject: [PATCH 298/400] more Lua functions using the wrong stack index. --- src/bindings/helpers.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/bindings/helpers.c b/src/bindings/helpers.c index dec73f5f8..f2fbae090 100644 --- a/src/bindings/helpers.c +++ b/src/bindings/helpers.c @@ -37,8 +37,7 @@ without prior permission by the authors of Eressea. #include static int -lua_giveitem(unit * s, unit * d, const item_type * itype, int n, - struct order *ord) +lua_giveitem(unit * s, unit * d, const item_type * itype, int n, struct order *ord) { lua_State *L = (lua_State *) global.vm_state; char fname[64]; @@ -46,11 +45,12 @@ lua_giveitem(unit * s, unit * d, const item_type * itype, int n, const char *iname = itype->rtype->_name[0]; assert(s != NULL); - strcat(strcpy(fname, iname), "_give"); + strlcpy(fname, iname, sizeof(fname)); + strlcat(fname, "_give", sizeof(fname)); lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { + if (lua_isfunction(L, -1)) { tolua_pushusertype(L, s, TOLUA_CAST "unit"); tolua_pushusertype(L, d, TOLUA_CAST "unit"); tolua_pushstring(L, iname); @@ -83,7 +83,7 @@ static int limit_resource(const region * r, const resource_type * rtype) lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { + if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); if (lua_pcall(L, 1, 1, 0) != 0) { @@ -113,7 +113,7 @@ produce_resource(region * r, const resource_type * rtype, int norders) lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { + if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); tolua_pushnumber(L, (lua_Number) norders); @@ -142,7 +142,7 @@ static int lc_age(struct attrib *a) lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { + if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); if (fparam) { tolua_pushstring(L, fparam); @@ -256,7 +256,7 @@ static int lua_initfamiliar(unit * u) lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { + if (lua_isfunction(L, -1)) { tolua_pushusertype(L, u, TOLUA_CAST "unit"); if (lua_pcall(L, 1, 1, 0) != 0) { @@ -292,7 +292,7 @@ lua_changeresource(unit * u, const struct resource_type *rtype, int delta) lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { + if (lua_isfunction(L, -1)) { tolua_pushusertype(L, u, TOLUA_CAST "unit"); tolua_pushnumber(L, (lua_Number) delta); @@ -323,7 +323,7 @@ static int lua_getresource(unit * u, const struct resource_type *rtype) lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { + if (lua_isfunction(L, -1)) { tolua_pushusertype(L, u, TOLUA_CAST "unit"); if (lua_pcall(L, 1, 1, 0) != 0) { @@ -353,7 +353,7 @@ static boolean lua_canuse_item(const unit * u, const struct item_type *itype) lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { + if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); tolua_pushstring(L, itype->rtype->_name[0]); @@ -383,7 +383,7 @@ lua_wage(const region * r, const faction * f, const race * rc, int in_turn) lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { + if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); tolua_pushusertype(L, (void *)f, TOLUA_CAST "faction"); tolua_pushstring(L, rc ? rc->_name[0] : 0); @@ -415,7 +415,7 @@ static void lua_agebuilding(building * b) lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { + if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); if (lua_pcall(L, 1, 0, 0) != 0) { @@ -437,7 +437,7 @@ static int lua_building_protection(building * b, unit * u) lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { + if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); @@ -464,7 +464,7 @@ static double lua_building_taxes(building * b, int level) lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { + if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); tolua_pushnumber(L, level); @@ -491,7 +491,7 @@ static int lua_maintenance(const unit * u) lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { + if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); if (lua_pcall(L, 1, 1, 0) != 0) { @@ -521,7 +521,7 @@ static int lua_equipmentcallback(const struct equipment *eq, unit * u) lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { + if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); if (lua_pcall(L, 1, 1, 0) != 0) { @@ -553,7 +553,7 @@ lua_useitem(struct unit *u, const struct item_type *itype, int amount, lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { + if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); tolua_pushnumber(L, (lua_Number) amount); @@ -584,7 +584,7 @@ static int lua_recruit(struct unit *u, const struct archetype *arch, int amount) lua_pushstring(L, fname); lua_rawget(L, LUA_GLOBALSINDEX); - if (lua_isfunction(L, 1)) { + if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); tolua_pushnumber(L, (lua_Number) amount); From 44e5c60c96b13df30e37c6b4f72e6b31a6b2f54f Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 29 May 2012 20:44:25 -0700 Subject: [PATCH 299/400] test added: when a spell is not found, we do not have to pay for it --- scripts/tests/spells.lua | 44 +++++++++++++++++++++++++++++++++++++++- src/kernel/magic.c | 12 +++++++---- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/scripts/tests/spells.lua b/scripts/tests/spells.lua index 1538b4249..2d23d2efe 100644 --- a/scripts/tests/spells.lua +++ b/scripts/tests/spells.lua @@ -6,7 +6,49 @@ function setup() free_game() settings.set("magic.fumble.enable", "0") settings.set("magic.regeneration.enable", "0") - settings.set("rules.economy.food", "0") + settings.set("rules.economy.food", "4") +end + +function test_spell_payment() + local r = region.create(0,0, "plain") + local f = faction.create("spell_payment@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u:set_skill("magic", 12) + u.magic = "gwyrrd" -- calls create_mage + u:add_spell("create_roi") + + local permaura = u:get_pooled("permaura") + u:add_item("money", 3000) + u.aura = 50 + u:clear_orders() + u:add_order("ZAUBERE 'Erschaffe einen Ring der Unsichtbarkeit' ") + process_orders() + + assert_equal(1, u:get_item("roi")) + assert_equal(0, u:get_item("money")) + assert_equal(0, u.aura) + assert_equal(permaura-1, u:get_pooled("permaura")) +end + +function test_spell_not_found_no_payment() + local r = region.create(0,0, "plain") + local f = faction.create("spell_fails_no_payment@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + u:set_skill("magic", 12) + u.magic = "gwyrrd" -- calls create_mage + + local permaura = u:get_pooled("permaura") + u:add_item("money", 3000) + u.aura = 50 + + u:clear_orders() + u:add_order("ZAUBERE 'Erschaffe einen Ring der Unsichtbarkeit' ") + process_orders() + + assert_equal(0, u:get_item("roi")) + assert_equal(3000, u:get_item("money")) + assert_equal(50, u.aura) + assert_equal(permaura, u:get_pooled("permaura")) end function test_create_firesword() diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 581ef4988..f6b8360b9 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -889,6 +889,7 @@ void pay_spell(unit * u, const spell * sp, int cast_level, int range) int k; int resuse; + assert(cast_level>0); for (k = 0; sp->components[k].type; k++) { if (sp->components[k].type == r_aura) { resuse = spellcost(u, sp) * range; @@ -1394,7 +1395,7 @@ static void do_fumble(castorder * co) case 5: case 6: /* Spruch gelingt, aber alle Magiepunkte weg */ - sp->cast(co); + co->level = sp->cast(co); set_spellpoints(u, 0); ADDMSG(&u->faction->msgs, msg_message("patzer4", "unit region spell", u, r, sp)); @@ -1405,7 +1406,7 @@ static void do_fumble(castorder * co) case 9: default: /* Spruch gelingt, alle nachfolgenden Sprüche werden 2^4 so teuer */ - sp->cast(co); + co->level = sp->cast(co); ADDMSG(&u->faction->msgs, msg_message("patzer5", "unit region spell", u, r, sp)); countspells(u, 3); @@ -2839,10 +2840,13 @@ void magic(void) } } } - pay_spell(u, sp, co->level, co->distance); /* erst bezahlen, dann Kostenzähler erhöhen */ - if (fumbled) + if (fumbled) { do_fumble(co); + } + if (co->level>0) { + pay_spell(u, sp, co->level, co->distance); + } countspells(u, 1); } } From 3e67e7fb4e1d0e6c1036cf4a6b2644e0c8c49790 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 29 May 2012 20:50:20 -0700 Subject: [PATCH 300/400] Lua unit:cast_spell should only cast spells the unit knows. do not allow payment for spells cast at level <= 0 --- scripts/tests/spells.lua | 22 +++++++++++++++++++++- src/bindings/bind_unit.c | 10 +++++----- src/kernel/magic_test.c | 16 +++------------- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/scripts/tests/spells.lua b/scripts/tests/spells.lua index 2d23d2efe..d8b446ace 100644 --- a/scripts/tests/spells.lua +++ b/scripts/tests/spells.lua @@ -34,8 +34,8 @@ function test_spell_not_found_no_payment() local r = region.create(0,0, "plain") local f = faction.create("spell_fails_no_payment@eressea.de", "human", "de") local u = unit.create(f, r, 1) - u:set_skill("magic", 12) u.magic = "gwyrrd" -- calls create_mage + u:set_skill("magic", 12) local permaura = u:get_pooled("permaura") u:add_item("money", 3000) @@ -55,6 +55,7 @@ function test_create_firesword() local r = region.create(0,0, "plain") local f = faction.create("create_firesword@eressea.de", "human", "de") local u = unit.create(f, r, 1) + u.magic = "gwyrrd" -- calls create_mage u:set_skill("magic", 12) u:add_spell("create_firesword") @@ -66,8 +67,10 @@ function test_create_roi() local r = region.create(0,0, "plain") local f = faction.create("create_roi@eressea.de", "human", "de") local u = unit.create(f, r, 1) + u.magic = "gwyrrd" -- calls create_mage u:set_skill("magic", 10) + u:add_spell('create_roi') u:cast_spell('create_roi') assert_equal(1, u:get_item("roi")) end @@ -76,8 +79,10 @@ function test_create_roqf() local r = region.create(0,0, "plain") local f = faction.create("create_roqf@eressea.de", "human", "de") local u = unit.create(f, r, 1) + u.magic = "gwyrrd" -- calls create_mage u:set_skill("magic", 10) + u:add_spell('create_roqf') u:cast_spell('create_roqf') assert_equal(1, u:get_item("roqf")) end @@ -86,8 +91,10 @@ function test_create_aots() local r = region.create(0,0, "plain") local f = faction.create("create_aots@eressea.de", "human", "de") local u = unit.create(f, r, 1) + u.magic = "gwyrrd" -- calls create_mage u:set_skill("magic", 10) + u:add_spell('create_aots') u:cast_spell('create_aots') assert_equal(1, u:get_item("aots")) end @@ -96,8 +103,10 @@ function test_create_ror() local r = region.create(0,0, "plain") local f = faction.create("create_ror@eressea.de", "human", "de") local u = unit.create(f, r, 1) + u.magic = "gwyrrd" -- calls create_mage u:set_skill("magic", 10) + u:add_spell('create_ror') u:cast_spell('create_ror') assert_equal(1, u:get_item("ror")) end @@ -106,8 +115,10 @@ function test_create_magicherbbag() local r = region.create(0,0, "plain") local f = faction.create("create_magicherbbag@eressea.de", "human", "de") local u = unit.create(f, r, 1) + u.magic = "gwyrrd" -- calls create_mage u:set_skill("magic", 10) + u:add_spell('create_magicherbbag') u:cast_spell('create_magicherbbag') assert_equal(1, u:get_item("magicherbbag")) end @@ -116,8 +127,10 @@ function test_create_trollbelt() local r = region.create(0,0, "plain") local f = faction.create("create_trollbelt@eressea.de", "human", "de") local u = unit.create(f, r, 1) + u.magic = "gwyrrd" -- calls create_mage u:set_skill("magic", 10) + u:add_spell('create_trollbelt') u:cast_spell('create_trollbelt') assert_equal(1, u:get_item("trollbelt")) end @@ -126,8 +139,10 @@ function test_create_dreameye() local r = region.create(0,0, "plain") local f = faction.create("create_dreameye@eressea.de", "human", "de") local u = unit.create(f, r, 1) + u.magic = "gwyrrd" -- calls create_mage u:set_skill("magic", 10) + u:add_spell('create_dreameye') u:cast_spell('create_dreameye') assert_equal(1, u:get_item("dreameye")) end @@ -136,8 +151,10 @@ function test_create_antimagic() local r = region.create(0,0, "plain") local f = faction.create("create_antimagic@eressea.de", "human", "de") local u = unit.create(f, r, 1) + u.magic = "gwyrrd" -- calls create_mage u:set_skill("magic", 10) + u:add_spell('create_antimagic') u:cast_spell('create_antimagic') assert_equal(1, u:get_item("antimagic")) end @@ -146,8 +163,10 @@ function test_create_runesword() local r = region.create(0,0, "plain") local f = faction.create("create_runesword@eressea.de", "human", "de") local u = unit.create(f, r, 1) + u.magic = "gwyrrd" -- calls create_mage u:set_skill("magic", 10) + u:add_spell('create_runesword') u:cast_spell('create_runesword') assert_equal(1, u:get_item("runesword")) end @@ -158,6 +177,7 @@ function test_create_rop() local u = unit.create(f, r, 1) u:set_skill("magic", 10) + u:add_spell('create_rop') u:cast_spell('create_rop') assert_equal(1, u:get_item("rop")) end diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 1b4547932..50c588e78 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -32,6 +32,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include #include #include #include @@ -455,12 +456,11 @@ static int tolua_unit_addnotice(lua_State * L) static void unit_castspell(unit * u, const char *name, int level) { - quicklist *ql = spells; - int qi; + spell *sp = find_spell(name); - for (ql = spells, qi = 0; ql; ql_advance(&ql, &qi, 1)) { - spell *sp = (spell *) ql_get(ql, qi); - if (strcmp(name, sp->sname) == 0) { + if (sp) { + spellbook *book = unit_get_spellbook(u); + if (spellbook_get(book, sp)) { if (!sp->cast) { log_error("spell '%s' has no function.\n", sp->sname); } else { diff --git a/src/kernel/magic_test.c b/src/kernel/magic_test.c index 9bcc1d117..20899e32d 100644 --- a/src/kernel/magic_test.c +++ b/src/kernel/magic_test.c @@ -152,19 +152,9 @@ void test_pay_spell_failure(CuTest * tc) CuAssertIntEquals(tc, 3, change_resource(u, rt_find("aura"), 3)); CuAssertIntEquals(tc, 2, change_resource(u, rt_find("horse"), 1)); - level = eff_spelllevel(u, sp, 3, 1); - CuAssertIntEquals(tc, 0, level); - pay_spell(u, sp, level, 1); - CuAssertIntEquals(tc, 0, get_resource(u, rt_find("money"))); /* seems we even pay this at level 0 */ - CuAssertIntEquals(tc, 3, get_resource(u, rt_find("aura"))); - CuAssertIntEquals(tc, 2, get_resource(u, rt_find("horse"))); - - level = eff_spelllevel(u, sp, 2, 1); - CuAssertIntEquals(tc, 0, level); - pay_spell(u, sp, level, 1); - CuAssertIntEquals(tc, 0, get_resource(u, rt_find("money"))); - CuAssertIntEquals(tc, 3, get_resource(u, rt_find("aura"))); - CuAssertIntEquals(tc, 2, get_resource(u, rt_find("horse"))); + CuAssertIntEquals(tc, 0, eff_spelllevel(u, sp, 3, 1)); + CuAssertIntEquals(tc, 0, change_resource(u, rt_find("money"), -1)); + CuAssertIntEquals(tc, 0, eff_spelllevel(u, sp, 2, 1)); } void test_getspell_unit(CuTest * tc) From 9f2e1d475bcd0cf18215481ddefe787dd4ebc63d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 30 May 2012 19:17:08 -0700 Subject: [PATCH 301/400] Moving some things around in the external directory. I am deliberately breaking the VS2010 projects with this. I am probably breaking the Eressea server. --- src/bindings/bind_attrib.c | 3 ++- src/bindings/bindings.c | 2 +- src/build/external.c | 2 +- src/build/util.c | 4 ---- src/gamecode/economy_test.c | 2 +- src/gamecode/laws_test.c | 2 +- src/gamecode/market_test.c | 2 +- src/kernel/battle_test.c | 2 +- src/kernel/building_test.c | 2 +- src/kernel/config.c | 3 ++- src/kernel/curse_test.c | 2 +- src/kernel/equipment_test.c | 2 +- src/kernel/item_test.c | 2 +- src/kernel/magic_test.c | 2 +- src/kernel/move_test.c | 2 +- src/kernel/pool_test.c | 2 +- src/kernel/reports_test.c | 2 +- src/kernel/ship_test.c | 2 +- src/kernel/spell_test.c | 2 +- src/kernel/spellbook_test.c | 2 +- src/kernel/types.h | 1 + src/tests.c | 2 +- src/tests_test.c | 2 +- src/util/base36_test.c | 2 +- src/util/bsdstring_test.c | 2 +- src/util/functions_test.c | 2 +- src/util/quicklist_test.c | 2 +- src/util/umlaut_test.c | 2 +- 28 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/bindings/bind_attrib.c b/src/bindings/bind_attrib.c index af43c93d6..c3297248a 100644 --- a/src/bindings/bind_attrib.c +++ b/src/bindings/bind_attrib.c @@ -25,7 +25,8 @@ without prior permission by the authors of Eressea. #include #include -#include +/* external libraries */ +#include #include #include diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index 228b94ada..ed0c2fc40 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -62,7 +62,7 @@ without prior permission by the authors of Eressea. #include #include -#include +#include #include #include diff --git a/src/build/external.c b/src/build/external.c index fd759fbe8..47c3314a8 100644 --- a/src/build/external.c +++ b/src/build/external.c @@ -22,5 +22,5 @@ #include #ifndef DISABLE_TESTS -#include +#include #endif diff --git a/src/build/util.c b/src/build/util.c index 7de1d97e9..7175b9dec 100644 --- a/src/build/util.c +++ b/src/build/util.c @@ -2,15 +2,11 @@ #include #include "stdafx.h" -#include -#include - #include #include #include #include -#include #include #include #include diff --git a/src/gamecode/economy_test.c b/src/gamecode/economy_test.c index 0d44c2dc1..effe7e4e8 100644 --- a/src/gamecode/economy_test.c +++ b/src/gamecode/economy_test.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include static void test_give_control_building(CuTest * tc) diff --git a/src/gamecode/laws_test.c b/src/gamecode/laws_test.c index 0a2bb952c..e624d12ce 100644 --- a/src/gamecode/laws_test.c +++ b/src/gamecode/laws_test.c @@ -14,7 +14,7 @@ #include -#include +#include #include static void test_new_building_can_be_renamed(CuTest * tc) diff --git a/src/gamecode/market_test.c b/src/gamecode/market_test.c index 69726b9eb..7da1963c0 100644 --- a/src/gamecode/market_test.c +++ b/src/gamecode/market_test.c @@ -13,7 +13,7 @@ #include -#include +#include #include #include diff --git a/src/kernel/battle_test.c b/src/kernel/battle_test.c index c86a7f0b8..c8a558af1 100644 --- a/src/kernel/battle_test.c +++ b/src/kernel/battle_test.c @@ -9,7 +9,7 @@ #include "skill.h" #include "unit.h" #include "tests.h" -#include +#include static void test_make_fighter(CuTest * tc) { diff --git a/src/kernel/building_test.c b/src/kernel/building_test.c index 956266715..fa11cb2e4 100644 --- a/src/kernel/building_test.c +++ b/src/kernel/building_test.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/kernel/config.c b/src/kernel/config.c index d2eb422d6..9be2060ef 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -75,7 +75,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -#include +/* external libraries */ +#include /* libc includes */ #include diff --git a/src/kernel/curse_test.c b/src/kernel/curse_test.c index 7ccdd9a90..a7f88218b 100644 --- a/src/kernel/curse_test.c +++ b/src/kernel/curse_test.c @@ -4,7 +4,7 @@ #include -#include +#include static void test_curse(CuTest * tc) { diff --git a/src/kernel/equipment_test.c b/src/kernel/equipment_test.c index 5a97502a5..071cf3521 100644 --- a/src/kernel/equipment_test.c +++ b/src/kernel/equipment_test.c @@ -10,7 +10,7 @@ #include -#include +#include #include void test_equipment(CuTest * tc) diff --git a/src/kernel/item_test.c b/src/kernel/item_test.c index d9c2172c3..c59e47d33 100644 --- a/src/kernel/item_test.c +++ b/src/kernel/item_test.c @@ -4,7 +4,7 @@ #include #include -#include +#include #include void test_resource_type(CuTest * tc) diff --git a/src/kernel/magic_test.c b/src/kernel/magic_test.c index 20899e32d..bca8f6198 100644 --- a/src/kernel/magic_test.c +++ b/src/kernel/magic_test.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include void test_updatespells(CuTest * tc) diff --git a/src/kernel/move_test.c b/src/kernel/move_test.c index 492722253..172012e4d 100644 --- a/src/kernel/move_test.c +++ b/src/kernel/move_test.c @@ -7,7 +7,7 @@ #include -#include +#include #include static void test_building_type_exists(CuTest * tc) diff --git a/src/kernel/pool_test.c b/src/kernel/pool_test.c index 28d2a827a..5e521cff5 100644 --- a/src/kernel/pool_test.c +++ b/src/kernel/pool_test.c @@ -4,7 +4,7 @@ #include "unit.h" #include "item.h" #include "region.h" -#include +#include #include void test_change_resource(CuTest * tc) diff --git a/src/kernel/reports_test.c b/src/kernel/reports_test.c index d07217ece..c3ee0c3c1 100644 --- a/src/kernel/reports_test.c +++ b/src/kernel/reports_test.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include static void test_reorder_units(CuTest * tc) diff --git a/src/kernel/ship_test.c b/src/kernel/ship_test.c index 488e61eef..a1aefeed8 100644 --- a/src/kernel/ship_test.c +++ b/src/kernel/ship_test.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/kernel/spell_test.c b/src/kernel/spell_test.c index dc8fc8d47..e8bbeb328 100644 --- a/src/kernel/spell_test.c +++ b/src/kernel/spell_test.c @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include diff --git a/src/kernel/spellbook_test.c b/src/kernel/spellbook_test.c index c875a1941..6196d901c 100644 --- a/src/kernel/spellbook_test.c +++ b/src/kernel/spellbook_test.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include diff --git a/src/kernel/types.h b/src/kernel/types.h index ae53a79bd..ef5ee6013 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -56,6 +56,7 @@ struct ship; struct ship_type; struct skill; struct spell; +struct spellbook; struct storage; struct strlist; struct terrain_type; diff --git a/src/tests.c b/src/tests.c index 8ffd821b0..b41bdaaf3 100644 --- a/src/tests.c +++ b/src/tests.c @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/src/tests_test.c b/src/tests_test.c index d89cccd39..da4db4103 100644 --- a/src/tests_test.c +++ b/src/tests_test.c @@ -2,7 +2,7 @@ #include #include -#include +#include static void test_recreate_world(CuTest * tc) { diff --git a/src/util/base36_test.c b/src/util/base36_test.c index 25313cfe4..3d19f94df 100644 --- a/src/util/base36_test.c +++ b/src/util/base36_test.c @@ -1,4 +1,4 @@ -#include +#include #include "base36.h" #include #include diff --git a/src/util/bsdstring_test.c b/src/util/bsdstring_test.c index b084e5c31..25e7be60d 100644 --- a/src/util/bsdstring_test.c +++ b/src/util/bsdstring_test.c @@ -1,4 +1,4 @@ -#include +#include #include "bsdstring.h" #include diff --git a/src/util/functions_test.c b/src/util/functions_test.c index 1392662ed..cb229993d 100644 --- a/src/util/functions_test.c +++ b/src/util/functions_test.c @@ -1,4 +1,4 @@ -#include +#include #include #include #include "functions.h" diff --git a/src/util/quicklist_test.c b/src/util/quicklist_test.c index 7b8564909..36c95e5a2 100644 --- a/src/util/quicklist_test.c +++ b/src/util/quicklist_test.c @@ -1,4 +1,4 @@ -#include +#include #include #include #include "quicklist.h" diff --git a/src/util/umlaut_test.c b/src/util/umlaut_test.c index 7a70ccd5d..86b07f08e 100644 --- a/src/util/umlaut_test.c +++ b/src/util/umlaut_test.c @@ -1,4 +1,4 @@ -#include +#include #include #include #include From 6e106c9fc0e41aa2471c8b10f861e2f31e0b41aa Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 30 May 2012 19:43:11 -0700 Subject: [PATCH 302/400] out with the old critbit code, in with the new (submodule) --- src/bindings/bind_region.c | 2 +- src/kernel/config.c | 2 +- src/kernel/item.c | 2 +- src/kernel/magic.c | 2 +- src/kernel/spell.c | 2 +- src/util/critbit.c | 350 ------------------------------------- src/util/critbit.h | 56 ------ src/util/functions.c | 2 +- 8 files changed, 6 insertions(+), 412 deletions(-) delete mode 100644 src/util/critbit.c delete mode 100644 src/util/critbit.h diff --git a/src/bindings/bind_region.c b/src/bindings/bind_region.c index 8404b2d92..58f64203c 100644 --- a/src/bindings/bind_region.c +++ b/src/bindings/bind_region.c @@ -33,7 +33,7 @@ without prior permission by the authors of Eressea. #include #include -#include +#include #include #include diff --git a/src/kernel/config.c b/src/kernel/config.c index 9be2060ef..23124860b 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -54,7 +54,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include +#include #include #include #include diff --git a/src/kernel/item.c b/src/kernel/item.c index c2ba35c65..35d8451a0 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -41,7 +41,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include #include -#include +#include #include #include #include diff --git a/src/kernel/magic.c b/src/kernel/magic.c index f6b8360b9..f41c8eaa7 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -52,7 +52,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include -#include +#include #include #include #include diff --git a/src/kernel/spell.c b/src/kernel/spell.c index 6c2993a79..85cf35c40 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -21,7 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "spell.h" /* util includes */ -#include +#include #include #include #include diff --git a/src/util/critbit.c b/src/util/critbit.c deleted file mode 100644 index 7474ec64b..000000000 --- a/src/util/critbit.c +++ /dev/null @@ -1,350 +0,0 @@ -/* -Copyright (c) 2012, Enno Rehling - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include "critbit.h" -#include -#include -#include - -/* see http://cr.yp.to/critbit.html */ -struct critbit_node { - void * child[2]; - size_t byte; - unsigned char mask; -}; - -#define EXTERNAL_NODE 0 -#define INTERNAL_NODE 1 - -static int decode_pointer(void ** ptr) -{ - ptrdiff_t numvalue = (char*)*ptr - (char*)0; - if (numvalue&1) { - *ptr = (void*)(numvalue-1); - return EXTERNAL_NODE; - } - return INTERNAL_NODE; -} - -void * make_external_node(const void * key, size_t keylen) -{ - char * data = (char *)malloc(sizeof(size_t) + keylen + 1); -#ifndef NDEBUG - ptrdiff_t numvalue = (char *)data - (char*)0; - assert((numvalue&1)==0); -#endif - assert(keylen); - memcpy(data, &keylen, sizeof(size_t)); - memcpy(data+sizeof(size_t), key, keylen); - return (void*)(data+1); -} - -static void from_external_node(void * ptr, void **key, size_t *keylen) -{ - unsigned char * bytes = (unsigned char *)ptr; -#ifndef NDEBUG - ptrdiff_t numvalue = bytes - (unsigned char*)0; - assert(numvalue && (numvalue&1)==0); - assert(key && keylen); -#endif - memcpy(keylen, bytes, sizeof(size_t)); - *key = bytes+sizeof(size_t); -} - -struct critbit_node * make_internal_node(void) -{ - struct critbit_node *node = (struct critbit_node *)malloc(sizeof(struct critbit_node)); - return node; -} - -static void cb_free_node(void * ptr) -{ - if (decode_pointer(&ptr)==INTERNAL_NODE) { - struct critbit_node * node = (struct critbit_node *)ptr; - cb_free_node(node->child[0]); - cb_free_node(node->child[1]); - free(node); - } else { - free(ptr); - } -} - -void cb_clear(critbit_tree * cb) -{ - if (cb->root) { - cb_free_node(cb->root); - cb->root = 0; - } -} - -static int cb_less(const struct critbit_node * a, const struct critbit_node * b) -{ - return a->bytebyte || (a->byte==b->byte && a->mask < b->mask); -} - -int cb_insert(critbit_tree * cb, const void * key, size_t keylen) -{ - assert(cb); - assert(key); - if (!cb->root) { - cb->root = make_external_node(key, keylen); - return 1; - } else { - void ** iter = &cb->root; - struct critbit_node * prev = 0; - for (;;) { - void * ptr = *iter; - if (decode_pointer(&ptr)==INTERNAL_NODE) { - struct critbit_node * node = (struct critbit_node *)ptr; - unsigned char * bytes = (unsigned char *)key; - int branch = (keylen<=node->byte) ? 0 : ((1+((bytes[node->byte]|node->mask)&0xFF))>>8); - iter = &node->child[branch]; - prev = node; - } else { - unsigned char *iptr, *bytes = (unsigned char *)key, *ikey = bytes; - unsigned int mask, branch; - unsigned int byte = 0; - size_t len; - struct critbit_node * node = make_internal_node(); - - from_external_node(ptr, (void**)&iptr, &len); - - while (bytebyte = byte; - mask = *ikey ^ *iptr; /* these are all the bits that differ */ - mask |= mask>>1; - mask |= mask>>2; - mask |= mask>>4; /* now, every bit up to the MSB is set to 1 */ - mask = (mask&~(mask>>1))^0xFF; - node->mask = (unsigned char)mask; - - /* find the right place to insert, iff prev's crit-bit is later in the string than new crit-bit */ - if (prev && cb_less(node, prev)) { - for (iter = &cb->root;;) { - ptr = *iter; - if (decode_pointer(&ptr)==INTERNAL_NODE) { - struct critbit_node * next = (struct critbit_node *)ptr; - if (cb_less(next, node)) { - branch = ((1+((bytes[next->byte]|next->mask)&0xFF))>>8); - iter = &next->child[branch]; - } else { - break; - } - } else { - assert(!"should never get here"); - } - } - } - - branch = ((1+((*ikey|node->mask)&0xFF))>>8); - node->child[branch] = make_external_node(key, keylen); - node->child[1-branch] = *iter; - *iter = (void *)node; - - return CB_SUCCESS; - } - } - } -} - -static void * cb_find_top_i(critbit_tree * cb, const void * key, size_t keylen) -{ - void *ptr, *top = 0; - assert(key); - - if (!cb->root) { - return 0; - } - for (ptr=cb->root, top=cb->root;;) { - void * last = ptr; - if (decode_pointer(&ptr)==INTERNAL_NODE) { - struct critbit_node * node = (struct critbit_node *)ptr; - int branch; - if (keylen<=node->byte) { - break; - } else { - unsigned char * bytes = (unsigned char *)key; - top = last; - branch = (1+((bytes[node->byte]|node->mask)&0xFF))>>8; - ptr = node->child[branch]; - } - } else { - /* we reached an external node before exhausting the key length */ - top = last; - break; - } - } - return top; -} - -static int cb_find_prefix_i(void * ptr, const void * key, size_t keylen, const void ** results, int numresults, int * offset, int next) -{ - assert(next<=numresults); - if (next==numresults) { - return next; - } else if (decode_pointer(&ptr)==INTERNAL_NODE) { - struct critbit_node * node = (struct critbit_node *)ptr; - next = cb_find_prefix_i(node->child[0], key, keylen, results, numresults, offset, next); - if (nextchild[1], key, keylen, results, numresults, offset, next); - } - } else { - /* reached an external node */ - const char * str; - size_t len; - - from_external_node(ptr, (void**)&str, &len); - if (len>=keylen && memcmp(key, str, keylen)==0) { - if (*offset>0) { - --*offset; - } else { - results[next++] = str; - } - } - } - return next; -} - -int cb_find_prefix(critbit_tree * cb, const void * key, size_t keylen, const void ** results, int numresults, int offset) -{ - if (numresults>0) { - void *top = cb_find_top_i(cb, key, keylen); - if (top) { - /* recursively add all children except the ones from [0-offset) of top to the results */ - return cb_find_prefix_i(top, key, keylen, results, numresults, &offset, 0); - } - } - return 0; -} - -static int cb_foreach_i(void * ptr, const void * key, size_t keylen, int (*match_cb)(const void * match, const void * key, size_t keylen, void *), void *data) -{ - int result = 0; - - if (decode_pointer(&ptr)==INTERNAL_NODE) { - struct critbit_node * node = (struct critbit_node *)ptr; - result = cb_foreach_i(node->child[0], key, keylen, match_cb, data); - if (!result) { - result = cb_foreach_i(node->child[1], key, keylen, match_cb, data); - } - } else { - /* reached an external node */ - void * match; - size_t len; - - from_external_node(ptr, &match, &len); - if (len>=keylen && memcmp(key, match, keylen)==0) { - return match_cb(match, key, keylen, data); - } - } - return result; -} - -int cb_foreach(critbit_tree * cb, const void * key, size_t keylen, int (*match_cb)(const void * match, const void * key, size_t keylen, void *), void *data) -{ - void *top = cb_find_top_i(cb, key, keylen); - if (top) { - /* recursively add all children except the ones from [0-offset) of top to the results */ - return cb_foreach_i(top, key, keylen, match_cb, data); - } - return 0; -} - -const void * cb_find(critbit_tree * cb, const void * key, size_t keylen) -{ - void * str; - size_t len; - unsigned char * bytes = (unsigned char *)key; - void * ptr; - - assert(cb); - assert(key); - if (!cb->root) return 0; - for (ptr=cb->root;decode_pointer(&ptr)==INTERNAL_NODE;) { - struct critbit_node * node = (struct critbit_node *)ptr; - int branch = (keylen<=node->byte) ? 0 : ((1+((bytes[node->byte]|node->mask)&0xFF))>>8); - ptr = node->child[branch]; - } - from_external_node(ptr, &str, &len); - if (len>=keylen && memcmp(key, str, keylen)==0) { - return str; - } - return 0; -} - -int cb_erase(critbit_tree * cb, const void * key, size_t keylen) -{ - void **iter = &cb->root; - void *ptr = *iter; - unsigned char * bytes = (unsigned char *)key; - - if (!cb->root) return 0; - - if (decode_pointer(&ptr)==EXTERNAL_NODE) { - free(ptr); - cb->root = 0; - return CB_SUCCESS; - } - - for (;;) { - struct critbit_node *parent = (struct critbit_node *)ptr; - int branch, type; - - branch = (keylen<=parent->byte) ? 0 : ((1+((bytes[parent->byte]|parent->mask)&0xFF))>>8); - - ptr = parent->child[branch]; - type = decode_pointer(&ptr); - if (type==INTERNAL_NODE) { - iter = &parent->child[branch]; - } else { - void * str; - size_t len; - from_external_node(ptr, &str, &len); - if (len==keylen && memcmp(key, str, len)==0) { - free(ptr); - *iter = parent->child[1-branch]; - return CB_SUCCESS; - } - return 0; - } - } -} - -size_t cb_new_kv(const char *key, size_t keylen, void * value, size_t len, void * out) -{ - char * dst = (char*)out; - if (dst!=key) { - memcpy(dst, key, keylen); - } - dst[keylen] = 0; - memcpy(dst+keylen+1, value, len); - return len+keylen+1; -} - -void cb_get_kv(const void *kv, void * value, size_t len) -{ - const char * key = (const char *)kv; - size_t keylen = strlen(key)+1; - memcpy(value, key+keylen, len); -} diff --git a/src/util/critbit.h b/src/util/critbit.h deleted file mode 100644 index 9ce95599b..000000000 --- a/src/util/critbit.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -Copyright (c) 2012, Enno Rehling - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef _CRITBITT_H -#define _CRITBITT_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -typedef struct critbit_tree { - void * root; -} critbit_tree; - -#define CB_SUCCESS 1 - -#define CRITBIT_TREE() { 0 } - -int cb_insert(critbit_tree * cb, const void * key, size_t keylen); -const void * cb_find(critbit_tree * cb, const void * key, size_t keylen); -int cb_erase(critbit_tree * cb, const void * key, size_t keylen); -int cb_find_prefix(critbit_tree * cb, const void * key, size_t keylen, const void ** results, int numresults, int offset); -int cb_foreach(critbit_tree * cb, const void * key, size_t keylen, int (*match_cb)(const void * match, const void * key, size_t keylen, void *), void *data); -void cb_clear(critbit_tree * cb); - -#define cb_insert_str(cb, key) \ - cb_insert(cb, (void *)key, strlen(key)+1) -#define cb_find_str(cb, key) \ - (const char *)cb_find(cb, (void *)key, strlen(key)+1) -#define cb_erase_str(cb, key) \ - cb_erase(cb, (void *)key, strlen(key)+1) -#define cb_find_prefix_str(cb, key, results, numresults, offset) \ - cb_find_prefix(cb, (void *)key, strlen(key), results, numresults, offset) - -size_t cb_new_kv(const char *key, size_t keylen, void * value, size_t len, void * out); -void cb_get_kv(const void *kv, void * value, size_t len); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/util/functions.c b/src/util/functions.c index a1605cea4..3de812b7f 100644 --- a/src/util/functions.c +++ b/src/util/functions.c @@ -19,7 +19,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include "functions.h" -#include +#include /* libc includes */ #include From db094810fd899a7eec68646db2e2319f26b71337 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 30 May 2012 19:55:17 -0700 Subject: [PATCH 303/400] removing quicklist, importing it from a submodule --- src/bindings/bind_faction.c | 2 +- src/bindings/bind_unit.c | 2 +- src/bindings/bindings.c | 2 +- src/build/util.c | 1 - src/gamecode/creport.c | 2 +- src/gamecode/laws.c | 2 +- src/gamecode/market.c | 2 +- src/gamecode/report.c | 2 +- src/gamecode/spy.c | 2 +- src/gamecode/xmlreport.c | 2 +- src/kernel/alliance.c | 2 +- src/kernel/battle.c | 2 +- src/kernel/building.c | 2 +- src/kernel/config.c | 2 +- src/kernel/connection.c | 2 +- src/kernel/curse.c | 2 +- src/kernel/equipment.c | 2 +- src/kernel/equipment_test.c | 2 +- src/kernel/faction.c | 2 +- src/kernel/magic.c | 2 +- src/kernel/magic_test.c | 2 +- src/kernel/pathfinder.c | 2 +- src/kernel/reports.c | 2 +- src/kernel/save.c | 2 +- src/kernel/ship.c | 2 +- src/kernel/spell.c | 2 +- src/kernel/spell_test.c | 2 +- src/kernel/spellbook.c | 2 +- src/kernel/spellbook_test.c | 2 +- src/modules/autoseed.c | 2 +- src/modules/wormhole.c | 2 +- src/tests.c | 2 - src/util/quicklist.c | 256 ------------------------------------ src/util/quicklist.h | 45 ------- src/util/quicklist_test.c | 203 ---------------------------- 35 files changed, 30 insertions(+), 537 deletions(-) delete mode 100644 src/util/quicklist.c delete mode 100644 src/util/quicklist.h delete mode 100644 src/util/quicklist_test.c diff --git a/src/bindings/bind_faction.c b/src/bindings/bind_faction.c index 665af06d6..111b49f37 100644 --- a/src/bindings/bind_faction.c +++ b/src/bindings/bind_faction.c @@ -27,7 +27,7 @@ without prior permission by the authors of Eressea. #include #include -#include +#include #include #include diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 50c588e78..8949ddb66 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -44,7 +44,7 @@ without prior permission by the authors of Eressea. #include #include #include -#include +#include #include #include diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index ed0c2fc40..e12c1756b 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -57,7 +57,7 @@ without prior permission by the authors of Eressea. #include #include #include -#include +#include #include #include #include diff --git a/src/build/util.c b/src/build/util.c index 7175b9dec..3fa1e4f1c 100644 --- a/src/build/util.c +++ b/src/build/util.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index cfd718985..94abc0294 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -64,7 +64,7 @@ without prior permission by the authors of Eressea. #include #include #include -#include +#include #include diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index ab79b4122..2f1e0b252 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -78,7 +78,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include +#include #include #include #include diff --git a/src/gamecode/market.c b/src/gamecode/market.c index d49e528b6..2e812e9c0 100644 --- a/src/gamecode/market.c +++ b/src/gamecode/market.c @@ -17,7 +17,7 @@ without prior permission by the authors of Eressea. #include #include -#include +#include #include #include diff --git a/src/gamecode/report.c b/src/gamecode/report.c index 72e5e4ab1..03772de43 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -77,7 +77,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include +#include #include #include diff --git a/src/gamecode/spy.c b/src/gamecode/spy.c index 10b83f31a..76b0360b5 100644 --- a/src/gamecode/spy.c +++ b/src/gamecode/spy.c @@ -43,7 +43,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include +#include #include #include diff --git a/src/gamecode/xmlreport.c b/src/gamecode/xmlreport.c index 33a740a76..72025e98a 100644 --- a/src/gamecode/xmlreport.c +++ b/src/gamecode/xmlreport.c @@ -58,7 +58,7 @@ without prior permission by the authors of Eressea. #include #include #include -#include +#include #include #include diff --git a/src/kernel/alliance.c b/src/kernel/alliance.c index ddb92fcf4..ede4b0dfd 100644 --- a/src/kernel/alliance.c +++ b/src/kernel/alliance.c @@ -34,7 +34,7 @@ without prior permission by the authors of Eressea. #include #include #include -#include +#include #include #include diff --git a/src/kernel/battle.c b/src/kernel/battle.c index 36abba1b9..ab7a52db7 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -61,7 +61,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include +#include #include #include diff --git a/src/kernel/building.c b/src/kernel/building.c index 0edb9a6bc..0b695622d 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -40,7 +40,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include +#include #include #include #include diff --git a/src/kernel/config.c b/src/kernel/config.c index 23124860b..23b568579 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -62,7 +62,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include +#include #include #include #include diff --git a/src/kernel/connection.c b/src/kernel/connection.c index 98ac0234b..ec3c31b67 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -29,7 +29,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include +#include #include #include diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 016b96212..4a7403e69 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -284,7 +284,7 @@ attrib_type at_curse = { /* Spruch identifizieren */ #include -#include +#include static quicklist *cursetypes[256]; diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index 2ef21717c..956cc0626 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -28,7 +28,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "spellbook.h" /* util includes */ -#include +#include #include #include diff --git a/src/kernel/equipment_test.c b/src/kernel/equipment_test.c index 071cf3521..a526c5abc 100644 --- a/src/kernel/equipment_test.c +++ b/src/kernel/equipment_test.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include diff --git a/src/kernel/faction.c b/src/kernel/faction.c index 6c33d9dd7..ff011bc38 100644 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -41,7 +41,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include +#include #include #include #include diff --git a/src/kernel/magic.c b/src/kernel/magic.c index f41c8eaa7..a0bbef2a0 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -57,7 +57,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include +#include #include #include #include diff --git a/src/kernel/magic_test.c b/src/kernel/magic_test.c index bca8f6198..8a4a1ef69 100644 --- a/src/kernel/magic_test.c +++ b/src/kernel/magic_test.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/kernel/pathfinder.c b/src/kernel/pathfinder.c index 97cea3b98..c9adf3251 100644 --- a/src/kernel/pathfinder.c +++ b/src/kernel/pathfinder.c @@ -18,7 +18,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -#include +#include #include "pathfinder.h" #include "region.h" diff --git a/src/kernel/reports.c b/src/kernel/reports.c index 8fb83abd7..e6ae19581 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -53,7 +53,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include +#include /* libc includes */ #include diff --git a/src/kernel/save.c b/src/kernel/save.c index ccc28c895..cf7724a96 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -65,7 +65,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include +#include #include #include #include diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 6c008dfd6..141bd4ba9 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -36,7 +36,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include +#include #include #include diff --git a/src/kernel/spell.c b/src/kernel/spell.c index 85cf35c40..41966ef5d 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -26,7 +26,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include -#include +#include /* libc includes */ #include diff --git a/src/kernel/spell_test.c b/src/kernel/spell_test.c index e8bbeb328..90ab1cdf0 100644 --- a/src/kernel/spell_test.c +++ b/src/kernel/spell_test.c @@ -1,6 +1,6 @@ #include -#include +#include #include #include #include diff --git a/src/kernel/spellbook.c b/src/kernel/spellbook.c index 7093fca84..4f2b736b6 100644 --- a/src/kernel/spellbook.c +++ b/src/kernel/spellbook.c @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include "spellbook.h" diff --git a/src/kernel/spellbook_test.c b/src/kernel/spellbook_test.c index 6196d901c..277952e0c 100644 --- a/src/kernel/spellbook_test.c +++ b/src/kernel/spellbook_test.c @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c index d21ac4658..18ae8e51a 100644 --- a/src/modules/autoseed.c +++ b/src/modules/autoseed.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/modules/wormhole.c b/src/modules/wormhole.c index e606eab2f..d018c358f 100644 --- a/src/modules/wormhole.c +++ b/src/modules/wormhole.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include /* libc includes */ diff --git a/src/tests.c b/src/tests.c index b41bdaaf3..7c24bfb0f 100644 --- a/src/tests.c +++ b/src/tests.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -51,7 +50,6 @@ int RunAllTests(void) /* util */ CuSuiteAddSuite(suite, get_base36_suite()); CuSuiteAddSuite(suite, get_bsdstring_suite()); - CuSuiteAddSuite(suite, get_quicklist_suite()); CuSuiteAddSuite(suite, get_functions_suite()); CuSuiteAddSuite(suite, get_umlaut_suite()); /* kernel */ diff --git a/src/util/quicklist.c b/src/util/quicklist.c deleted file mode 100644 index 0e8842ccb..000000000 --- a/src/util/quicklist.c +++ /dev/null @@ -1,256 +0,0 @@ -/* -Copyright (c) 2010-2011, Enno Rehling - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#include "quicklist.h" -#include -#include -#include - -#define QL_MAXSIZE 14 /* max. number of elements unrolled into one node */ -#define QL_LIMIT 7 /* this many or fewer number in a node => attempt merge */ - -/* The total size of this struct is 64 bytes on a 32-bit system with - * normal alignment. YMMV, so on a 64-bit system, twiddle the - * constants above */ -struct quicklist { - struct quicklist *next; - int num_elements; - void *elements[QL_MAXSIZE]; -}; - -void *ql_get(const quicklist * ql, int index) -{ - return (ql - && index < ql->num_elements) ? ql->elements[index] : ql_get(ql->next, - index - ql->num_elements); -} - -void *ql_replace(quicklist * ql, int index, void *data) -{ - if (ql && index < ql->num_elements) { - void *orig = ql->elements[index]; - ql->elements[index] = data; - return orig; - } else { - return ql_replace(ql->next, index - ql->num_elements, data); - } -} - -int ql_length(const quicklist * ql) -{ - return ql ? ql->num_elements + ql_length(ql->next) : 0; -} - -int ql_empty(const quicklist * ql) -{ - return !ql; -} - -void ql_push(quicklist ** qlp, void *data) -{ - quicklist *ql = 0; - while (*qlp && ((*qlp)->next || (*qlp)->num_elements == QL_MAXSIZE)) { - qlp = &(*qlp)->next; - } - if (!*qlp) { - ql = (quicklist *) malloc(sizeof(quicklist)); - ql->num_elements = 0; - ql->next = 0; - *qlp = ql; - } else { - ql = *qlp; - } - ql->elements[ql->num_elements++] = data; -} - -int ql_delete(quicklist ** qlp, int index) -{ - quicklist *ql = *qlp; - if (index < 0) - return EINVAL; - if (ql && index >= ql->num_elements) { - return ql_delete(&ql->next, index - ql->num_elements); - } else if (ql) { - if (index + 1 < ql->num_elements) { - memmove(ql->elements + index, ql->elements + index + 1, - (ql->num_elements - index - 1) * sizeof(void *)); - } - --ql->num_elements; - if (ql->num_elements == 0) { - *qlp = ql->next; - free(ql); - } else if (ql->next && ql->num_elements <= QL_LIMIT) { - quicklist *qn = ql->next; - if (ql->num_elements + qn->num_elements > QL_MAXSIZE) { - memcpy(ql->elements + ql->num_elements, qn->elements, sizeof(void *)); - --qn->num_elements; - ++ql->num_elements; - memmove(qn->elements, qn->elements + 1, - qn->num_elements * sizeof(void *)); - } else { - memcpy(ql->elements + ql->num_elements, qn->elements, - qn->num_elements * sizeof(void *)); - ql->num_elements += qn->num_elements; - ql->next = qn->next; - free(qn); - } - } - } - return 0; -} - -int ql_insert(quicklist ** qlp, int index, void *data) -{ - quicklist *ql = *qlp; - if (ql) { - if (index >= QL_MAXSIZE) { - return ql_insert(&ql->next, index - ql->num_elements, data); - } else if (ql->num_elements < QL_MAXSIZE) { - memmove(ql->elements + index + 1, ql->elements + index, - (ql->num_elements - index) * sizeof(void *)); - ql->elements[index] = data; - ++ql->num_elements; - } else { - quicklist *qn = (quicklist *) malloc(sizeof(quicklist)); - qn->next = ql->next; - ql->next = qn; - qn->num_elements = ql->num_elements-QL_LIMIT; - ql->num_elements = QL_LIMIT; - memcpy(qn->elements, ql->elements + ql->num_elements, - qn->num_elements * sizeof(void *)); - if (index <= ql->num_elements) { - return ql_insert(qlp, index, data); - } else { - return ql_insert(&ql->next, index - ql->num_elements, data); - } - } - } else if (index == 0) { - ql_push(qlp, data); - } else { - return EINVAL; - } - return 0; -} - -void ql_foreach(struct quicklist *ql, void (*cb) (void *)) -{ - for (; ql; ql = ql->next) { - int i; - for (i = 0; i != ql->num_elements; ++i) { - cb(ql->elements[i]); - } - } -} - -int ql_advance(struct quicklist **iterator, int *index, int stride) -{ - quicklist *ql = *iterator; - int i = *index; - if (!ql || i < 0 || stride < 0) { - return ERANGE; - } else if (i + stride < ql->num_elements) { - *index = i + stride; - return 0; - } else { - *index = i - ql->num_elements + stride; - *iterator = ql->next; - return ql_advance(iterator, index, 0); - } -} - -void ql_free(struct quicklist *ql) -{ - while (ql) { - quicklist * qn = ql; - ql = ql->next; - free(qn); - } -} - -int ql_set_remove(struct quicklist **qlp, void *data) -{ - int qi; - quicklist *ql = *qlp; - - if (!ql) - return 0; - - for (qi = 0; qi != ql->num_elements; ++qi) { - void *qd = ql_get(ql, qi); - if (qd == data) { - return ql_delete(qlp, qi) == 0; - } - } - return ql_set_remove(&ql->next, data); -} - -int ql_set_insert(struct quicklist **qlp, void *data) -{ - if (*qlp) { - quicklist *ql = *qlp; - if (ql->num_elements > 0 && ql->elements[ql->num_elements - 1] < data) { - if (ql->num_elements == QL_MAXSIZE || (ql->next - && ql->next->elements[0] <= data)) { - return ql_set_insert(&ql->next, data); - } else { - ql->elements[ql->num_elements++] = data; - } - return 0; - } else { - int i; - /* TODO: OPT | binary search */ - for (i = 0; i != ql->num_elements; ++i) { - if (data < ql->elements[i]) { - ql_insert(qlp, i, data); - return 0; - } - if (data == ql->elements[i]) { - return 1; - } - } - } - } - ql_push(qlp, data); - return 0; -} - -int ql_set_find(struct quicklist **qlp, int *qip, const void *data) -{ - quicklist *ql = *qlp; - int qi; - - while (ql && ql->elements[ql->num_elements - 1] < data) { - ql = ql->next; - } - - if (!ql) - return 0; - - /* TODO: OPT | binary search */ - for (qi = 0; qi != ql->num_elements; ++qi) { - if (ql->elements[qi] > data) { - return 0; - } - if (ql->elements[qi] == data) { - if (qip) { - *qip = qi; - *qlp = ql; - } - return 1; - } - } - return 0; -} diff --git a/src/util/quicklist.h b/src/util/quicklist.h deleted file mode 100644 index 01b918543..000000000 --- a/src/util/quicklist.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright (c) 2010-2011, Enno Rehling - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef _QUICKLIST_H -#define _QUICKLIST_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* see http://en.wikipedia.org/wiki/Unrolled_linked_list */ - typedef struct quicklist quicklist; - void *ql_get(const struct quicklist *ql, int index); - int ql_length(const struct quicklist *ql); - int ql_empty(const struct quicklist *ql); - void ql_push(struct quicklist **qlp, void *data); - int ql_delete(struct quicklist **qlp, int index); - int ql_insert(struct quicklist **qlp, int index, void *data); - void ql_foreach(struct quicklist *ql, void (*cb) (void *)); - int ql_advance(struct quicklist **iterator, int *index, int stride); - void ql_free(struct quicklist *ql); - void *ql_replace(struct quicklist *ql, int index, void *data); - -/* you can use it as a set (sorted pointers)*/ - int ql_set_insert(struct quicklist **qlp, void *data); - int ql_set_find(struct quicklist **qlp, int *qip, const void *data); - int ql_set_remove(struct quicklist **qlp, void *data); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/util/quicklist_test.c b/src/util/quicklist_test.c deleted file mode 100644 index 36c95e5a2..000000000 --- a/src/util/quicklist_test.c +++ /dev/null @@ -1,203 +0,0 @@ -#include -#include -#include -#include "quicklist.h" - -static const char *hello = "Hello World"; - -static void test_insert(CuTest * tc) -{ - struct quicklist *ql = NULL; - int i; - for (i = 0; i != 32; ++i) { - CuAssertIntEquals(tc, i, ql_length(ql)); - ql_insert(&ql, 0, (void *)i); - } - for (i = 0; i != 32; ++i) { - CuAssertIntEquals(tc, 31 - i, (int)ql_get(ql, i)); - } -} - -static void test_insert_delete_gives_null(CuTest * tc) -{ - struct quicklist *ql = NULL; - CuAssertIntEquals(tc, 1, ql_empty(ql)); - ql_push(&ql, (void *)42); - CuAssertIntEquals(tc, 0, ql_empty(ql)); - ql_delete(&ql, 0); - CuAssertPtrEquals(tc, 0, ql); -} - -static void test_replace(CuTest * tc) -{ - struct quicklist *ql = NULL; - int a; - ql_push(&ql, (void *)42); - a = (int)ql_replace(ql, 0, (void *)43); - CuAssertIntEquals(tc, 42, a); - CuAssertIntEquals(tc, 43, (int)ql_get(ql, 0)); -} - -static void test_set_insert(CuTest * tc) -{ - struct quicklist *ql = NULL; - int a, qi; - a = ql_set_insert(&ql, (void *)42); - CuAssertIntEquals(tc, 1, ql_length(ql)); - CuAssertIntEquals(tc, 0, a); - a = ql_set_insert(&ql, (void *)43); - CuAssertIntEquals(tc, 2, ql_length(ql)); - CuAssertIntEquals(tc, 0, a); - a = ql_set_insert(&ql, (void *)42); - CuAssertIntEquals(tc, 2, ql_length(ql)); - CuAssertIntEquals(tc, 1, a); - a = ql_set_insert(&ql, (void *)41); - CuAssertIntEquals(tc, 0, a); - CuAssertIntEquals(tc, 3, ql_length(ql)); - CuAssertIntEquals(tc, 41, (int)ql_get(ql, 0)); - CuAssertIntEquals(tc, 42, (int)ql_get(ql, 1)); - CuAssertIntEquals(tc, 43, (int)ql_get(ql, 2)); - - a = ql_set_find(&ql, &qi, (void *)49); - CuAssertIntEquals(tc, 0, a); - a = ql_set_find(&ql, &qi, (void *)42); - CuAssertIntEquals(tc, 1, a); - CuAssertIntEquals(tc, 42, (int)ql_get(ql, qi)); -} - -static void test_set_remove(CuTest * tc) -{ - struct quicklist *ql = NULL, *q2; - int a; - - ql_set_insert(&ql, (void *)41); - ql_set_insert(&ql, (void *)42); - ql_set_insert(&ql, (void *)43); - - q2 = ql; - - a = ql_set_remove(&ql, (void *)42); - CuAssertPtrEquals(tc, q2, ql); - CuAssertIntEquals(tc, 1, a); - CuAssertIntEquals(tc, 41, (int)ql_get(ql, 0)); - CuAssertIntEquals(tc, 43, (int)ql_get(ql, 1)); - CuAssertIntEquals(tc, 2, ql_length(ql)); - - a = ql_set_remove(&ql, (void *)42); - CuAssertPtrEquals(tc, q2, ql); - CuAssertIntEquals(tc, 0, a); - - ql_set_remove(&ql, (void *)41); - ql_set_remove(&ql, (void *)43); - CuAssertPtrEquals(tc, 0, ql); -} - -static void test_set_find(CuTest * tc) -{ - struct quicklist *ql = NULL, *q2; - int a, qi; - - for (a = 0; a != 32; ++a) { - ql_set_insert(&ql, (void *)a); - } - - q2 = ql; - a = ql_set_find(&q2, 0, (void *)31); - CuAssertIntEquals(tc, 1, a); - CuAssertPtrEquals(tc, ql, q2); - - q2 = ql; - a = ql_set_find(&ql, &qi, (void *)0); - CuAssertIntEquals(tc, 1, a); - CuAssertIntEquals(tc, 0, qi); - CuAssertPtrEquals(tc, ql, q2); - - q2 = ql; - a = ql_set_find(&ql, &qi, (void *)31); - CuAssertIntEquals(tc, 1, a); - CuAssertIntEquals(tc, 31, (int)ql_get(ql, qi)); - CuAssertTrue(tc, ql != q2); -} - -static void test_advance(CuTest * tc) -{ - struct quicklist *ql = NULL, *qli; - int i, n = 31; - for (i = 0; i != 32; ++i) { - ql_insert(&ql, 0, (void *)i); - } - for (i = 0, qli = ql; qli; ql_advance(&qli, &i, 1), n--) { - int g = (int)ql_get(qli, i); - CuAssertIntEquals(tc, n, g); - } -} - -static void test_push(CuTest * tc) -{ - struct quicklist *ql = NULL; - CuAssertIntEquals(tc, 0, ql_length(ql)); - ql_push(&ql, (void *)hello); - CuAssertIntEquals(tc, 1, ql_length(ql)); - CuAssertStrEquals(tc, "Hello World", (const char *)ql_get(ql, 0)); - ql_delete(&ql, 0); - CuAssertPtrEquals(tc, 0, ql); -} - -static void test_delete_edgecases(CuTest * tc) -{ - struct quicklist *ql = NULL; - ql_delete(&ql, 0); - CuAssertPtrEquals(tc, 0, ql); - ql_push(&ql, (void *)hello); - ql_delete(&ql, -1); - ql_delete(&ql, 32); - CuAssertIntEquals(tc, 1, ql_length(ql)); -} - -static void test_insert_many(CuTest * tc) -{ - struct quicklist *ql = NULL; - int i; - for (i = 0; i != 32; ++i) { - ql_push(&ql, (void *)i); - } - for (i = 0; i != 32; ++i) { - CuAssertIntEquals(tc, 32 - i, ql_length(ql)); - CuAssertIntEquals(tc, i, (int)ql_get(ql, 0)); - CuAssertIntEquals(tc, 31, (int)ql_get(ql, ql_length(ql) - 1)); - ql_delete(&ql, 0); - } - CuAssertPtrEquals(tc, 0, ql); -} - -static void test_delete_rand(CuTest * tc) -{ - struct quicklist *ql = NULL; - int i; - for (i = 0; i != 32; ++i) { - ql_push(&ql, (void *)i); - } - CuAssertIntEquals(tc, 32, ql_length(ql)); - ql_delete(&ql, 0); - CuAssertIntEquals(tc, 1, (int)ql_get(ql, 0)); - CuAssertIntEquals(tc, 31, ql_length(ql)); - ql_delete(&ql, 30); - CuAssertIntEquals(tc, 30, ql_length(ql)); -} - -CuSuite *get_quicklist_suite(void) -{ - CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, test_advance); - SUITE_ADD_TEST(suite, test_replace); - SUITE_ADD_TEST(suite, test_push); - SUITE_ADD_TEST(suite, test_insert); - SUITE_ADD_TEST(suite, test_set_remove); - SUITE_ADD_TEST(suite, test_set_find); - SUITE_ADD_TEST(suite, test_insert_delete_gives_null); - SUITE_ADD_TEST(suite, test_insert_many); - SUITE_ADD_TEST(suite, test_delete_rand); - SUITE_ADD_TEST(suite, test_delete_edgecases); - SUITE_ADD_TEST(suite, test_set_insert); - return suite; -} From d9404447517488a8fdadd00647d00a97e7f34864 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 1 Jun 2012 16:36:50 -0700 Subject: [PATCH 304/400] license file --- .gitignore | 13 +++++++++++++ LICENSE | 15 +++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..1bf3ffbcb --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +bin/ +Debug/ +Release/ +*~ +*.user +*.pdb +*.suo +*.sdf +*.opensdf +*.ipch +*.sh +src/*.vcproj.*.user +tags diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..00ab17b3d --- /dev/null +++ b/LICENSE @@ -0,0 +1,15 @@ +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. From ab15f242413827f5b808046021bfad1768be49f0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 1 Jun 2012 18:05:07 -0700 Subject: [PATCH 305/400] fix some compilation issues --- src/tests.c | 3 +++ src/tests.h | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tests.c b/src/tests.c index 7c24bfb0f..2ea35d16e 100644 --- a/src/tests.c +++ b/src/tests.c @@ -36,6 +36,9 @@ #include #include #include +#include + +#include int RunAllTests(void) { diff --git a/src/tests.h b/src/tests.h index 29a75ac4f..ebf1434ae 100644 --- a/src/tests.h +++ b/src/tests.h @@ -3,8 +3,6 @@ extern "C" { #endif #ifndef DISABLE_TESTS - struct building_type; - struct building; void test_cleanup(void); struct terrain_type * test_create_terrain(const char * name, unsigned int flags); From 29cb6f2c7cc54a6e1125c512702146632617293e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 1 Jun 2012 21:09:11 -0700 Subject: [PATCH 306/400] Getting ready to build on VS2010 again. I still have to figure out a better way to include and build dependencies that are installed on most Linux systems. --- src/build/{external.c => dependencies.c} | 0 src/gamecode.vcproj | 352 --------- src/gmtool.vcproj | 314 -------- src/kernel.vcproj | 954 ----------------------- src/lua-bindings.vcproj | 272 ------- src/util.vcproj | 432 ---------- 6 files changed, 2324 deletions(-) rename src/build/{external.c => dependencies.c} (100%) delete mode 100644 src/gamecode.vcproj delete mode 100644 src/gmtool.vcproj delete mode 100644 src/kernel.vcproj delete mode 100644 src/lua-bindings.vcproj delete mode 100644 src/util.vcproj diff --git a/src/build/external.c b/src/build/dependencies.c similarity index 100% rename from src/build/external.c rename to src/build/dependencies.c diff --git a/src/gamecode.vcproj b/src/gamecode.vcproj deleted file mode 100644 index d852037e7..000000000 --- a/src/gamecode.vcproj +++ /dev/null @@ -1,352 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/gmtool.vcproj b/src/gmtool.vcproj deleted file mode 100644 index 467785f12..000000000 --- a/src/gmtool.vcproj +++ /dev/null @@ -1,314 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/kernel.vcproj b/src/kernel.vcproj deleted file mode 100644 index faa1240f4..000000000 --- a/src/kernel.vcproj +++ /dev/null @@ -1,954 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/lua-bindings.vcproj b/src/lua-bindings.vcproj deleted file mode 100644 index a43b73683..000000000 --- a/src/lua-bindings.vcproj +++ /dev/null @@ -1,272 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/util.vcproj b/src/util.vcproj deleted file mode 100644 index 6a4e95ef9..000000000 --- a/src/util.vcproj +++ /dev/null @@ -1,432 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 578334f2d032cd9ba44070329971cc57bf2bd889 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 2 Jun 2012 10:44:37 -0700 Subject: [PATCH 307/400] fix a warning about %u not being the right format for size_t --- src/kernel/textstore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/textstore.c b/src/kernel/textstore.c index 0bbbd48c7..643697bf9 100644 --- a/src/kernel/textstore.c +++ b/src/kernel/textstore.c @@ -98,7 +98,7 @@ static void txt_r_tok_buf(struct storage *store, char *result, size_t size) char format[16]; if (result && size > 0) { format[0] = '%'; - sprintf(format + 1, "%us", size); + sprintf(format + 1, "%lus", (unsigned long)size); fscanf((FILE *) store->userdata, format, result); if (result[0] == NULL_TOKEN) { result[0] = 0; From 533c267b9a191478d330ee500c9f4ae7e946f711 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 2 Jun 2012 12:49:48 -0700 Subject: [PATCH 308/400] Fixed a bug where a missing resource in E3 would crash the server --- scripts/spells.lua | 13 +++++++++---- src/bindings/bind_message.c | 9 +++++++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/scripts/spells.lua b/scripts/spells.lua index 8269e72e6..29991376c 100644 --- a/scripts/spells.lua +++ b/scripts/spells.lua @@ -1,9 +1,14 @@ function creation_message(mage, type, number) local msg = message.create("item_create_spell") - msg:set_unit("mage", mage) - msg:set_int("number", number) - msg:set_resource("item", type) - return msg + local err = 0 + err = err + msg:set_unit("mage", mage) + err = err + msg:set_int("number", number) + err = err + msg:set_resource("item", type) + if err ~= 0 then + return nil + else + return msg + end end local function create_item(mage, level, name, number) diff --git a/src/bindings/bind_message.c b/src/bindings/bind_message.c index ae27573d9..6ff30e98a 100644 --- a/src/bindings/bind_message.c +++ b/src/bindings/bind_message.c @@ -72,6 +72,7 @@ int msg_set_resource(lua_message * msg, const char *param, const char *resname) { if (msg->mtype) { int i = mtype_get_param(msg->mtype, param); + const resource_type * rtype; if (i == msg->mtype->nparameters) { return E_INVALID_PARAMETER_NAME; } @@ -79,8 +80,12 @@ int msg_set_resource(lua_message * msg, const char *param, const char *resname) return E_INVALID_PARAMETER_TYPE; } - msg->args[i].v = (void *)rt_find(resname); - + rtype = rt_find(resname); + if (rtype) { + msg->args[i].v = (void *)rtype; + } else { + return E_INVALID_PARAMETER_VALUE; + } return E_OK; } return E_INVALID_MESSAGE; From ee456c49b11741d0438758c95ee9c4912c97b5c8 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 3 Jun 2012 11:59:21 -0700 Subject: [PATCH 309/400] building new cmake files for the core (WIP) fixing a missign header in bsdstring.h (need size_t) --- src/CMakeLists.txt | 9 ++++++++ src/util/CMakeLists.txt | 48 +++++++++++++++++++++++++++++++++++++++++ src/util/bsdstring.h | 1 + 3 files changed, 58 insertions(+) create mode 100644 src/CMakeLists.txt create mode 100644 src/util/CMakeLists.txt diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 000000000..e74bd8a92 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 2.4) +project (eressea-core) + +enable_testing() + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/../../cmake/Modules/") + +add_subdirectory (../../dependencies "${CMAKE_CURRENT_BINARY_DIR}/dependencies") +add_subdirectory (util) diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt new file mode 100644 index 000000000..8d2a38123 --- /dev/null +++ b/src/util/CMakeLists.txt @@ -0,0 +1,48 @@ +cmake_minimum_required (VERSION 2.4) +project (util) + +find_package (Lua51 REQUIRED) +find_package (LibXml2 REQUIRED) +#find_package (CuTest REQUIRED HINTS ${DEPENDENCIES_DIR}) +#find_package (QuickList REQUIRED) +#find_package (CritBit REQUIRED) + +include_directories (${LUA_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR}) +include_directories (.. + ${CRITBIT_INCLUDE_DIR} + ${QUICKLIST_INCLUDE_DIR} + ${CUTEST_INCLUDE_DIR} + ) + +add_library (util attrib.c + base36.c + base36_test.c + bsdstring.c + bsdstring_test.c + console.c + crmessage.c + dice.c + eventbus.c + event.c + filereader.c + functions.c + functions_test.c + goodies.c + language.c + listbox.c + lists.c + log.c + message.c + nrmessage.c + os.c + parser.c + rand.c + resolve.c + sql.c + strings.c + translation.c + umlaut.c + umlaut_test.c + unicode.c + xml.c +) diff --git a/src/util/bsdstring.h b/src/util/bsdstring.h index b917baafa..91b89465d 100644 --- a/src/util/bsdstring.h +++ b/src/util/bsdstring.h @@ -1,6 +1,7 @@ #ifndef UTIL_BSDSTRING_H #define UTIL_BSDSTRING_H +#include extern int wrptr(char **ptr, size_t * size, int bytes); #ifndef HAVE_STRLCPY From 5cba331ad3c2e8eb429b8e5d4a9db745c1a743ea Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 3 Jun 2012 12:51:35 -0700 Subject: [PATCH 310/400] cmake files for uil and kernel fixing a bunch of files that do not compile on their own --- src/CMakeLists.txt | 1 + src/kernel/CMakeLists.txt | 71 +++++++++++++++++++++++++++++++++++++++ src/kernel/equipment.c | 2 +- src/kernel/item.c | 1 + src/kernel/magic.h | 5 --- src/kernel/pool_test.c | 2 ++ src/kernel/types.h | 2 ++ src/kernel/unit.c | 4 ++- 8 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 src/kernel/CMakeLists.txt diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e74bd8a92..7ee7758de 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,3 +7,4 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/../../cmake/Modu add_subdirectory (../../dependencies "${CMAKE_CURRENT_BINARY_DIR}/dependencies") add_subdirectory (util) +add_subdirectory (kernel) diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt new file mode 100644 index 000000000..d02f7dddc --- /dev/null +++ b/src/kernel/CMakeLists.txt @@ -0,0 +1,71 @@ +cmake_minimum_required (VERSION 2.4) +project (kernel) + +#find_package (Lua51 REQUIRED) +#find_package (LibXml2 REQUIRED) +#find_package (CuTest REQUIRED HINTS ${DEPENDENCIES_DIR}) +#find_package (QuickList REQUIRED) +#find_package (CritBit REQUIRED) + +include_directories (..) +#include_directories (${LUA_INCLUDE_DIR}) +include_directories (${LIBXML2_INCLUDE_DIR}) +include_directories (${CRITBIT_INCLUDE_DIR}) +include_directories (${QUICKLIST_INCLUDE_DIR}) +include_directories (${CUTEST_INCLUDE_DIR}) +include_directories (${INIPARSER_INCLUDE_DIR}) +include_directories (${CRYPTO_INCLUDE_DIR}) + +add_library (kernel + alchemy.c + alliance.c + battle.c + battle_test.c + binarystore.c + build.c + building.c + building_test.c + calendar.c + command.c + config.c + connection.c + curse.c + curse_test.c + equipment.c + equipment_test.c + faction.c + group.c + item.c + item_test.c + magic.c + magic_test.c + message.c + move.c + move_test.c + names.c + order.c + pathfinder.c + plane.c + player.c + pool.c + pool_test.c + race.c + region.c + reports.c + reports_test.c + resources.c + save.c + ship.c + ship_test.c + skill.c + spellbook.c + spellbook_test.c + spell.c + spell_test.c + sqlite.c + teleport.c + terrain.c + textstore.c + unit.c + xmlreader.c +) diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index 956cc0626..42c505499 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -83,7 +83,7 @@ void equipment_setskill(equipment * eq, skill_t sk, const char *value) } } -void equipment_addspell(equipment * eq, spell * sp, int level) +void equipment_addspell(equipment * eq, struct spell * sp, int level) { if (eq) { if (!eq->spellbook) { diff --git a/src/kernel/item.c b/src/kernel/item.c index 35d8451a0..c588fbeca 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -24,6 +24,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "alchemy.h" #include "build.h" +#include "curse.h" #include "faction.h" #include "message.h" #include "pool.h" diff --git a/src/kernel/magic.h b/src/kernel/magic.h index f896be52d..07ec04772 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -22,11 +22,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -#include "curse.h" - struct fighter; - struct building; - struct spellbook; - /* ------------------------------------------------------------- */ #define MAXCOMBATSPELLS 3 /* PRECOMBAT COMBAT POSTCOMBAT */ diff --git a/src/kernel/pool_test.c b/src/kernel/pool_test.c index 5e521cff5..38be7aaae 100644 --- a/src/kernel/pool_test.c +++ b/src/kernel/pool_test.c @@ -1,9 +1,11 @@ #include +#include #include "pool.h" #include "unit.h" #include "item.h" #include "region.h" +#include "skill.h" #include #include diff --git a/src/kernel/types.h b/src/kernel/types.h index ef5ee6013..23cef5f51 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -38,6 +38,7 @@ struct attrib_type; struct building; struct building_type; struct curse; +struct curse_type; struct equipment; struct faction; struct fighter; @@ -48,6 +49,7 @@ struct luxury_type; struct order; struct plane; struct potion_type; +struct quicklist; struct race; struct region; struct region_list; diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 585696e3f..c24902076 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -18,12 +18,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +#include #include "unit.h" #include "building.h" #include "faction.h" #include "group.h" #include "connection.h" +#include "curse.h" #include "item.h" #include "move.h" #include "order.h" @@ -1757,4 +1759,4 @@ struct spellbook * unit_get_spellbook(const struct unit * u) } } return 0; -} \ No newline at end of file +} From a928c6b45c6d7c9e67b94695a17b2c4d71950922 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 3 Jun 2012 13:39:42 -0700 Subject: [PATCH 311/400] cmake configuration for gamecode --- src/CMakeLists.txt | 1 + src/gamecode/CMakeLists.txt | 31 +++++++++++++++++++++++++++++++ src/gamecode/creport.c | 1 + src/gamecode/economy.c | 2 ++ src/gamecode/economy_test.c | 3 ++- src/gamecode/give.c | 1 + src/gamecode/laws.c | 1 + src/gamecode/market_test.c | 3 ++- src/gamecode/report.c | 1 + src/gamecode/study.c | 1 + src/gamecode/xmlreport.c | 1 + src/kernel/CMakeLists.txt | 7 ------- src/util/CMakeLists.txt | 15 ++++++--------- 13 files changed, 50 insertions(+), 18 deletions(-) create mode 100644 src/gamecode/CMakeLists.txt diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7ee7758de..fe436cb47 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,3 +8,4 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/../../cmake/Modu add_subdirectory (../../dependencies "${CMAKE_CURRENT_BINARY_DIR}/dependencies") add_subdirectory (util) add_subdirectory (kernel) +add_subdirectory (gamecode) diff --git a/src/gamecode/CMakeLists.txt b/src/gamecode/CMakeLists.txt new file mode 100644 index 000000000..dc74f267e --- /dev/null +++ b/src/gamecode/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required (VERSION 2.4) +project (gamecode) + +include_directories (..) +include_directories (${LIBXML2_INCLUDE_DIR}) +#include_directories (${CRITBIT_INCLUDE_DIR}) +include_directories (${QUICKLIST_INCLUDE_DIR}) +include_directories (${CUTEST_INCLUDE_DIR}) +#include_directories (${INIPARSER_INCLUDE_DIR}) +#include_directories (${CRYPTO_INCLUDE_DIR}) + +add_library (gamecode +# archetype.c + creation.c + creport.c + economy.c + economy_test.c + give.c + items.c + laws.c + laws_test.c + market.c + market_test.c + monster.c + randenc.c + report.c + spy.c + study.c + summary.c + xmlreport.c +) diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index 94abc0294..3f7d4fe1d 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -35,6 +35,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include #include #include #include diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index cc516d784..cd47f880a 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -20,6 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +#include #include "economy.h" /* gamecode includes */ @@ -33,6 +34,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include diff --git a/src/gamecode/economy_test.c b/src/gamecode/economy_test.c index effe7e4e8..61294b1da 100644 --- a/src/gamecode/economy_test.c +++ b/src/gamecode/economy_test.c @@ -1,4 +1,5 @@ -#include "platform.h" +#include +#include #include "economy.h" #include diff --git a/src/gamecode/give.c b/src/gamecode/give.c index 755b97c26..b9254c7c2 100644 --- a/src/gamecode/give.c +++ b/src/gamecode/give.c @@ -17,6 +17,7 @@ #include "economy.h" /* kernel includes */ +#include #include #include #include diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 2f1e0b252..6965a8f7d 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -39,6 +39,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include diff --git a/src/gamecode/market_test.c b/src/gamecode/market_test.c index 7da1963c0..71f9bcf24 100644 --- a/src/gamecode/market_test.c +++ b/src/gamecode/market_test.c @@ -1,4 +1,5 @@ -#include "platform.h" +#include +#include #include "market.h" #include "tests.h" diff --git a/src/gamecode/report.c b/src/gamecode/report.c index 03772de43..2127d2940 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -42,6 +42,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include diff --git a/src/gamecode/study.c b/src/gamecode/study.c index a25c56a52..2919e8b1f 100644 --- a/src/gamecode/study.c +++ b/src/gamecode/study.c @@ -25,6 +25,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +#include #include #include #include diff --git a/src/gamecode/xmlreport.c b/src/gamecode/xmlreport.c index 72025e98a..5b93dc887 100644 --- a/src/gamecode/xmlreport.c +++ b/src/gamecode/xmlreport.c @@ -32,6 +32,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include #include #include #include diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt index d02f7dddc..fc0a9369c 100644 --- a/src/kernel/CMakeLists.txt +++ b/src/kernel/CMakeLists.txt @@ -1,14 +1,7 @@ cmake_minimum_required (VERSION 2.4) project (kernel) -#find_package (Lua51 REQUIRED) -#find_package (LibXml2 REQUIRED) -#find_package (CuTest REQUIRED HINTS ${DEPENDENCIES_DIR}) -#find_package (QuickList REQUIRED) -#find_package (CritBit REQUIRED) - include_directories (..) -#include_directories (${LUA_INCLUDE_DIR}) include_directories (${LIBXML2_INCLUDE_DIR}) include_directories (${CRITBIT_INCLUDE_DIR}) include_directories (${QUICKLIST_INCLUDE_DIR}) diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 8d2a38123..dcdc1a3b1 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -3,16 +3,13 @@ project (util) find_package (Lua51 REQUIRED) find_package (LibXml2 REQUIRED) -#find_package (CuTest REQUIRED HINTS ${DEPENDENCIES_DIR}) -#find_package (QuickList REQUIRED) -#find_package (CritBit REQUIRED) -include_directories (${LUA_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR}) -include_directories (.. - ${CRITBIT_INCLUDE_DIR} - ${QUICKLIST_INCLUDE_DIR} - ${CUTEST_INCLUDE_DIR} - ) +include_directories (..) +include_directories (${CRITBIT_INCLUDE_DIR}) +include_directories (${QUICKLIST_INCLUDE_DIR}) +include_directories (${CUTEST_INCLUDE_DIR}) +include_directories (${LUA_INCLUDE_DIR}) +include_directories (${LIBXML2_INCLUDE_DIR}) add_library (util attrib.c base36.c From aeec7b94689778446ca5c92f83cc3a10ea46d303 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 3 Jun 2012 18:41:07 -0700 Subject: [PATCH 312/400] complete rewrite of cmake files --- CMakeLists.txt | 4 + src/CMakeLists.txt | 192 +++++++++++++++++++++++++++++++++-- src/bindings/bind_attrib.h | 2 + src/bindings/bind_gmtool.c | 1 + src/bindings/bindings.c | 1 + src/gamecode/CMakeLists.txt | 31 ------ src/items/studypotion.c | 59 ----------- src/items/studypotion.h | 30 ------ src/kernel/CMakeLists.txt | 64 ------------ src/kernel/names.c | 3 +- src/kernel/race.c | 5 +- src/modules/autoseed.c | 2 - src/tests.c | 1 + src/tests_test.c | 6 +- src/util/CMakeLists.txt | 45 --------- src/util/graph.c | 193 ------------------------------------ src/util/graph.h | 38 ------- src/util/log.c | 6 +- 18 files changed, 207 insertions(+), 476 deletions(-) create mode 100644 CMakeLists.txt delete mode 100644 src/gamecode/CMakeLists.txt delete mode 100644 src/items/studypotion.c delete mode 100644 src/items/studypotion.h delete mode 100644 src/kernel/CMakeLists.txt delete mode 100644 src/util/CMakeLists.txt delete mode 100644 src/util/graph.c delete mode 100644 src/util/graph.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..d526ed9a6 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 2.4) + +add_subdirectory (../dependencies "${CMAKE_CURRENT_BINARY_DIR}/dependencies") +add_subdirectory (src) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fe436cb47..ba3c05278 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,11 +1,189 @@ cmake_minimum_required(VERSION 2.4) -project (eressea-core) +project (eressea) -enable_testing() +set (CORE_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR} CACHE INTERNAL "Eressea Core headers") -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/../../cmake/Modules/") +find_package (Lua51 REQUIRED) +find_package (LibXml2 REQUIRED) -add_subdirectory (../../dependencies "${CMAKE_CURRENT_BINARY_DIR}/dependencies") -add_subdirectory (util) -add_subdirectory (kernel) -add_subdirectory (gamecode) +include_directories (${CORE_INCLUDE_DIR}) +include_directories (${CRITBIT_INCLUDE_DIR}) +include_directories (${CRYPTO_INCLUDE_DIR}) +include_directories (${QUICKLIST_INCLUDE_DIR}) +include_directories (${CUTEST_INCLUDE_DIR}) +include_directories (${LUA_INCLUDE_DIR}) +include_directories (${LIBXML2_INCLUDE_DIR}) +include_directories (${BSON_INCLUDE_DIR}) +include_directories (${INIPARSER_INCLUDE_DIR}) + +add_library(${PROJECT_NAME} + attributes/alliance.c + attributes/attributes.c + attributes/fleechance.c + attributes/follow.c + attributes/giveitem.c + attributes/gm.c + attributes/hate.c + attributes/iceberg.c + attributes/key.c + attributes/matmod.c + attributes/moved.c + attributes/movement.c + attributes/object.c + attributes/orcification.c + attributes/otherfaction.c + attributes/overrideroads.c + attributes/racename.c + attributes/raceprefix.c + attributes/reduceproduction.c + attributes/targetregion.c + bindings/bind_attrib.c + bindings/bind_building.c + bindings/bind_faction.c + bindings/bind_gmtool.c + bindings/bind_hashtable.c + bindings/bindings.c + bindings/bind_message.c + bindings/bind_region.c + bindings/bind_ship.c + bindings/bind_sqlite.c + bindings/bind_storage.c + bindings/bind_unit.c + bindings/helpers.c + eressea.c + gamecode/archetype.c + gamecode/creation.c + gamecode/creport.c + gamecode/economy.c + gamecode/economy_test.c + gamecode/give.c + gamecode/items.c + gamecode/laws.c + gamecode/laws_test.c + gamecode/market.c + gamecode/market_test.c + gamecode/monster.c + gamecode/randenc.c + gamecode/report.c + gamecode/spy.c + gamecode/study.c + gamecode/summary.c + gamecode/xmlreport.c + gmtool.c + items/artrewards.c + items/demonseye.c + items/itemtypes.c + items/phoenixcompass.c + items/seed.c + items/speedsail.c + items/weapons.c + items/xerewards.c + kernel/alchemy.c + kernel/alliance.c + kernel/battle.c + kernel/battle_test.c + kernel/binarystore.c + kernel/build.c + kernel/building.c + kernel/building_test.c + kernel/calendar.c + kernel/command.c + kernel/config.c + kernel/connection.c + kernel/curse.c + kernel/curse_test.c + kernel/equipment.c + kernel/equipment_test.c + kernel/faction.c + kernel/group.c + kernel/item.c + kernel/item_test.c + kernel/magic.c + kernel/magic_test.c + kernel/message.c + kernel/move.c + kernel/move_test.c + kernel/names.c + kernel/order.c + kernel/pathfinder.c + kernel/plane.c + kernel/player.c + kernel/pool.c + kernel/pool_test.c + kernel/race.c + kernel/region.c + kernel/reports.c + kernel/reports_test.c + kernel/resources.c + kernel/save.c + kernel/ship.c + kernel/ship_test.c + kernel/skill.c + kernel/spellbook.c + kernel/spellbook_test.c + kernel/spell.c + kernel/spell_test.c + kernel/sqlite.c + kernel/teleport.c + kernel/terrain.c + kernel/textstore.c + kernel/unit.c + kernel/xmlreader.c + modules/arena.c + modules/autoseed.c + modules/dungeon.c + modules/gmcmd.c + modules/museum.c + modules/score.c + modules/weather.c + modules/wormhole.c + modules/xecmd.c + modules/xmas.c + tests.c + tests_test.c + triggers/changefaction.c + triggers/changerace.c + triggers/clonedied.c + triggers/createcurse.c + triggers/createunit.c + triggers/gate.c + triggers/giveitem.c + triggers/killunit.c + triggers/removecurse.c + triggers/shock.c + triggers/timeout.c + triggers/triggers.c + triggers/unguard.c + triggers/unitmessage.c + util/attrib.c + util/base36.c + util/base36_test.c + util/bsdstring.c + util/bsdstring_test.c + util/console.c + util/crmessage.c + util/dice.c + util/eventbus.c + util/event.c + util/filereader.c + util/functions.c + util/functions_test.c + util/goodies.c + util/language.c + util/listbox.c + util/lists.c + util/log.c + util/message.c + util/nrmessage.c + util/os.c + util/parser.c + util/rand.c + util/resolve.c + util/sql.c + util/strings.c + util/translation.c + util/umlaut.c + util/umlaut_test.c + util/unicode.c + util/xml.c +) diff --git a/src/bindings/bind_attrib.h b/src/bindings/bind_attrib.h index 5ab8daad5..6195e109d 100644 --- a/src/bindings/bind_attrib.h +++ b/src/bindings/bind_attrib.h @@ -10,6 +10,8 @@ This program may not be used, modified or distributed without prior permission by the authors of Eressea. */ +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/src/bindings/bind_gmtool.c b/src/bindings/bind_gmtool.c index a38e8d32c..a55cb75b7 100644 --- a/src/bindings/bind_gmtool.c +++ b/src/bindings/bind_gmtool.c @@ -1,4 +1,5 @@ #include +#include #include #include "bind_gmtool.h" diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index e12c1756b..444997c19 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -21,6 +21,7 @@ without prior permission by the authors of Eressea. #include #include +#include #include #include #include diff --git a/src/gamecode/CMakeLists.txt b/src/gamecode/CMakeLists.txt deleted file mode 100644 index dc74f267e..000000000 --- a/src/gamecode/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -cmake_minimum_required (VERSION 2.4) -project (gamecode) - -include_directories (..) -include_directories (${LIBXML2_INCLUDE_DIR}) -#include_directories (${CRITBIT_INCLUDE_DIR}) -include_directories (${QUICKLIST_INCLUDE_DIR}) -include_directories (${CUTEST_INCLUDE_DIR}) -#include_directories (${INIPARSER_INCLUDE_DIR}) -#include_directories (${CRYPTO_INCLUDE_DIR}) - -add_library (gamecode -# archetype.c - creation.c - creport.c - economy.c - economy_test.c - give.c - items.c - laws.c - laws_test.c - market.c - market_test.c - monster.c - randenc.c - report.c - spy.c - study.c - summary.c - xmlreport.c -) diff --git a/src/items/studypotion.c b/src/items/studypotion.c deleted file mode 100644 index df77793e1..000000000 --- a/src/items/studypotion.c +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include -#include "studypotion.h" - -#include -#include -#include -#include -#include -#include - -#include -#include - -/* BEGIN it_studypotion */ -#define MAXGAIN 15 -static int -use_studypotion(struct unit *u, const struct item_type *itype, int amount, - struct order *ord) -{ - if (get_keyword(u->thisorder) == K_STUDY) { - skill_t sk; - skill *sv; - - init_tokens(u->thisorder); - skip_token(); - sk = findskill(getstrtoken(), u->faction->locale); - sv = get_skill(u, sk); - - if (sv && sv->level > 2) { - /* TODO: message */ - } else if (study_cost(u, sk) > 0) { - /* TODO: message */ - } else { - attrib *a = a_find(u->attribs, &at_learning); - teaching_info *teach; - if (a == NULL) { - a = a_add(&u->attribs, a_new(&at_learning)); - } - teach = (teaching_info *) a->data.v; - if (amount > MAXGAIN) - amount = MAXGAIN; - teach->value += amount * 30; - if (teach->value > MAXGAIN * 30) { - teach->value = MAXGAIN * 30; - } - i_change(&u->items, itype, -amount); - return 0; - } - } - return EUNUSABLE; -} - -void register_studypotion(void) -{ - register_function((pf_generic) use_studypotion, "use_studypotion"); -} - -/* END it_studypotion */ diff --git a/src/items/studypotion.h b/src/items/studypotion.h deleted file mode 100644 index 454f137c2..000000000 --- a/src/items/studypotion.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -Copyright (c) 1998-2010, Enno Rehling - Katja Zedel - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -**/ - -#ifndef H_ITM_STUDYPOTION -#define H_ITM_STUDYPOTION -#ifdef __cplusplus -extern "C" { -#endif - - extern void register_studypotion(void); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt deleted file mode 100644 index fc0a9369c..000000000 --- a/src/kernel/CMakeLists.txt +++ /dev/null @@ -1,64 +0,0 @@ -cmake_minimum_required (VERSION 2.4) -project (kernel) - -include_directories (..) -include_directories (${LIBXML2_INCLUDE_DIR}) -include_directories (${CRITBIT_INCLUDE_DIR}) -include_directories (${QUICKLIST_INCLUDE_DIR}) -include_directories (${CUTEST_INCLUDE_DIR}) -include_directories (${INIPARSER_INCLUDE_DIR}) -include_directories (${CRYPTO_INCLUDE_DIR}) - -add_library (kernel - alchemy.c - alliance.c - battle.c - battle_test.c - binarystore.c - build.c - building.c - building_test.c - calendar.c - command.c - config.c - connection.c - curse.c - curse_test.c - equipment.c - equipment_test.c - faction.c - group.c - item.c - item_test.c - magic.c - magic_test.c - message.c - move.c - move_test.c - names.c - order.c - pathfinder.c - plane.c - player.c - pool.c - pool_test.c - race.c - region.c - reports.c - reports_test.c - resources.c - save.c - ship.c - ship_test.c - skill.c - spellbook.c - spellbook_test.c - spell.c - spell_test.c - sqlite.c - teleport.c - terrain.c - textstore.c - unit.c - xmlreader.c -) diff --git a/src/kernel/names.c b/src/kernel/names.c index f50289654..d44c49132 100644 --- a/src/kernel/names.c +++ b/src/kernel/names.c @@ -38,6 +38,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* libc includes */ +#include #include #include #include @@ -466,7 +467,7 @@ const char *abkz(const char *s, char *buf, size_t buflen, size_t maxchars) void register_names(void) { register_function((pf_generic) describe_braineater, "describe_braineater"); - /* function name + /* function name * generate a name for a nonplayerunit * race->generate_name() */ register_function((pf_generic) undead_name, "nameundead"); diff --git a/src/kernel/race.c b/src/kernel/race.c index c89c5fb32..48c8b3a4a 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -50,11 +50,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include /* libc includes */ +#include +#include +#include #include #include #include -#include -#include /** external variables **/ race *races; diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c index 18ae8e51a..9a0b5d233 100644 --- a/src/modules/autoseed.c +++ b/src/modules/autoseed.c @@ -40,8 +40,6 @@ #include #include -#include - /* libc includes */ #include #include diff --git a/src/tests.c b/src/tests.c index 2ea35d16e..67df8c8ba 100644 --- a/src/tests.c +++ b/src/tests.c @@ -2,6 +2,7 @@ #include #include +#include #include "tests.h" #include "tests_test.c" diff --git a/src/tests_test.c b/src/tests_test.c index da4db4103..c685d8a50 100644 --- a/src/tests_test.c +++ b/src/tests_test.c @@ -1,7 +1,11 @@ -#include +#include + +#include #include #include +#include + #include static void test_recreate_world(CuTest * tc) diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt deleted file mode 100644 index dcdc1a3b1..000000000 --- a/src/util/CMakeLists.txt +++ /dev/null @@ -1,45 +0,0 @@ -cmake_minimum_required (VERSION 2.4) -project (util) - -find_package (Lua51 REQUIRED) -find_package (LibXml2 REQUIRED) - -include_directories (..) -include_directories (${CRITBIT_INCLUDE_DIR}) -include_directories (${QUICKLIST_INCLUDE_DIR}) -include_directories (${CUTEST_INCLUDE_DIR}) -include_directories (${LUA_INCLUDE_DIR}) -include_directories (${LIBXML2_INCLUDE_DIR}) - -add_library (util attrib.c - base36.c - base36_test.c - bsdstring.c - bsdstring_test.c - console.c - crmessage.c - dice.c - eventbus.c - event.c - filereader.c - functions.c - functions_test.c - goodies.c - language.c - listbox.c - lists.c - log.c - message.c - nrmessage.c - os.c - parser.c - rand.c - resolve.c - sql.c - strings.c - translation.c - umlaut.c - umlaut_test.c - unicode.c - xml.c -) diff --git a/src/util/graph.c b/src/util/graph.c deleted file mode 100644 index ec234aebf..000000000 --- a/src/util/graph.c +++ /dev/null @@ -1,193 +0,0 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - */ - -/* This is a very simple graph library. It is not optimized in any - way, and relies heavily on the vset and stack routines. */ - -#include -#include "vset.h" -#include "graph.h" - -void graph_init(graph * g) -{ - vset_init(&g->nodes); - vset_init(&g->edges); -} - -void graph_free(graph * g) -{ - vset_destroy(&g->nodes); - vset_destroy(&g->edges); -} - -void graph_add_node(graph * g, node * n) -{ - vset_add(&g->nodes, n); -} - -void graph_add_edge(graph * g, edge * v) -{ - vset_add(&g->nodes, v); -} - -void graph_remove_node(graph * g, node * n) -{ - unsigned int i; - - for (i = 0; i != g->edges.size; ++i) { - edge *v = g->edges.data[i]; - if (v->node1 == n || v->node2 == n) { - vset_erase(&g->nodes, v); - i--; - } - } - vset_erase(&g->nodes, n); -} - -node *graph_find_node(graph * g, void *object) -{ - unsigned int i; - - for (i = 0; i != g->nodes.size; ++i) { - node *node = g->nodes.data[i]; - if (node->object == object) { - return g->nodes.data[i]; - } - } - return NULL; -} - -/* The vset returned has to freed externally, else this will be a - memory leak. */ - -vset *graph_neighbours(graph * g, node * n) -{ - unsigned int i; - vset *vs = malloc(sizeof(vs)); - vset_init(vs); - for (i = 0; i != g->edges.size; ++i) { - edge *v = g->edges.data[i]; - if (v->node1 == n && vset_count(vs, v->node2) == 0) { - vset_add(vs, v->node2); - } else if (v->node2 == n && vset_count(vs, v->node1) == 0) { - vset_add(vs, v->node1); - } - } - - return vs; -} - -void graph_resetmarkers(graph * g) -{ - unsigned int i; - - for (i = 0; i != g->nodes.size; ++i) { - node *node = g->nodes.data[i]; - node->marker = 0; - } - for (i = 0; i != g->edges.size; ++i) { - edge *edge = g->edges.data[i]; - edge->marker = 0; - } -} - -/* The vset returned has to freed externally, else this will be a - memory leak. */ - -vset *graph_connected_nodes(graph * g, node * n) -{ - vset *vs = malloc(sizeof(vset)); - vset s; - - vset_init(vs); - vset_init(&s); - graph_resetmarkers(g); - vset_add(vs, n); - n->marker = 1; - vset_add(&s, n); - while (s.size > 0) { - node *n = vset_pop(&s); - vset *vs_nb = graph_neighbours(g, n); - unsigned int i; - for (i = 0; i != vs_nb->size; ++i) { - node *nb = vs_nb->data[i]; - if (nb->marker == 0) { - nb->marker = 1; - vset_add(vs, nb); - vset_add(&s, nb); - } - } - vset_destroy(vs_nb); - free(vs_nb); - } - - vset_destroy(&s); - - return vs; -} - -/* The vset returned has to freed externally, else this will be a - memory leak. */ - -vset *graph_disjunct_graphs(graph * g) -{ - vset *dg = malloc(sizeof(vset)); - vset nodes; - - vset_init(dg); - vset_init(&nodes); - vset_concat(&nodes, &g->nodes); - - while (nodes.size > 0) { - graph *gt = malloc(sizeof(graph)); - vset s; - unsigned int i; - node *start; - - graph_init(gt); - start = vset_pop(&nodes); - graph_resetmarkers(g); - graph_add_node(gt, start); - start->marker = 1; - vset_init(&s); - vset_add(&s, start); - while (s.size > 0) { - vset *nbs = graph_neighbours(g, vset_pop(&s)); - for (i = 0; i != nbs->size; ++i) { - node *nb = nbs->data[i]; - if (nb->marker == 0) { - nb->marker = 1; - graph_add_node(gt, nb); - vset_erase(&nodes, nb); - vset_add(&s, nb); - } - } - vset_destroy(nbs); - free(nbs); - } - - vset_destroy(&s); - - for (i = 0; i != g->edges.size; ++i) { - edge *v = g->edges.data[i]; - if (vset_count(&g->nodes, v->node1)) { - graph_add_edge(gt, v); - } - } - - vset_add(dg, gt); - } - - vset_destroy(&nodes); - - return dg; -} diff --git a/src/util/graph.h b/src/util/graph.h deleted file mode 100644 index 19303acc8..000000000 --- a/src/util/graph.h +++ /dev/null @@ -1,38 +0,0 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. - */ - -#ifndef GRAPH_H -#define GRAPH_H -#ifdef __cplusplus -extern "C" { -#endif - - typedef struct node { - int marker; - void *object; - } node; - - typedef struct edge { - int marker; - node *node1; - node *node2; - } edge; - - typedef struct graph { - vset nodes; - vset edges; - } graph; - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/util/log.c b/src/util/log.c index 48155cde3..40222bdd8 100644 --- a/src/util/log.c +++ b/src/util/log.c @@ -6,13 +6,14 @@ | | Ingo Wilken +-------------------+ Stefan Reich -This program may not be used, modified or distributed +This program may not be used, modified or distributed without prior permission by the authors of Eressea. */ #include #include "log.h" #include "unicode.h" +#include #include #include #include @@ -154,7 +155,7 @@ static void _log_write(FILE * stream, int codepage, const char * prefix, const c if (codepage) { char buffer[MAXLENGTH]; char converted[MAXLENGTH]; - + vsnprintf(buffer, sizeof(buffer), format, args); if (cp_convert(buffer, converted, MAXLENGTH, codepage) == 0) { fputs(converted, stream); @@ -308,4 +309,3 @@ void log_printf(FILE * io, const char *format, ...) log_flush(); } } - From 5b06f5d2c8650ded28127a5e857bf43876d8414a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 3 Jun 2012 18:56:30 -0700 Subject: [PATCH 313/400] complete rewrite of cmake files --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ba3c05278..08dd1d6e5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 2.4) -project (eressea) +project (eressea C) set (CORE_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR} CACHE INTERNAL "Eressea Core headers") From 9f04f80f45189c05120872adfd5d4049e2774f86 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 3 Jun 2012 20:07:51 -0700 Subject: [PATCH 314/400] stop comlaints about missing C++ compiler fix directory --- CMakeLists.txt | 3 ++- src/CMakeLists.txt | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d526ed9a6..a2548de17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,5 @@ cmake_minimum_required(VERSION 2.4) +project (core C) add_subdirectory (../dependencies "${CMAKE_CURRENT_BINARY_DIR}/dependencies") -add_subdirectory (src) +add_subdirectory (src eressea) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 08dd1d6e5..918ad54e3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 2.4) project (eressea C) -set (CORE_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR} CACHE INTERNAL "Eressea Core headers") +set (CORE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "Eressea Core headers") find_package (Lua51 REQUIRED) find_package (LibXml2 REQUIRED) From 0eae68f34ed6a5c600835563afca9ff376cf678e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 4 Jun 2012 03:41:34 +0000 Subject: [PATCH 315/400] fix compilation on ARM (differnt char type) --- src/kernel/reports_test.c | 6 +++--- src/util/bsdstring_test.c | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/kernel/reports_test.c b/src/kernel/reports_test.c index c3ee0c3c1..0bfa47e34 100644 --- a/src/kernel/reports_test.c +++ b/src/kernel/reports_test.c @@ -62,16 +62,16 @@ static void test_regionid(CuTest * tc) { plain = test_create_terrain("plain", 0); r = test_create_region(0, 0, plain); - memset(buffer, 0xff, sizeof(buffer)); + memset(buffer, -2, sizeof(buffer)); len = f_regionid(r, 0, buffer, sizeof(buffer)); CuAssertIntEquals(tc, 11, len); CuAssertStrEquals(tc, "plain (0,0)", buffer); - memset(buffer, -1, sizeof(buffer)); + memset(buffer, -2, sizeof(buffer)); len = f_regionid(r, 0, buffer, 11); CuAssertIntEquals(tc, 10, len); CuAssertStrEquals(tc, "plain (0,0", buffer); - CuAssertIntEquals(tc, -1, buffer[11]); + CuAssertIntEquals(tc, (char)-2, buffer[11]); } CuSuite *get_reports_suite(void) diff --git a/src/util/bsdstring_test.c b/src/util/bsdstring_test.c index 25e7be60d..0f9cdaeac 100644 --- a/src/util/bsdstring_test.c +++ b/src/util/bsdstring_test.c @@ -15,11 +15,11 @@ static void test_strlcat(CuTest * tc) buffer[0] = '\0'; CuAssertIntEquals(tc, 4, strlcat(buffer, "herp", 8)); CuAssertStrEquals(tc, "herp", buffer); - CuAssertIntEquals(tc, -2, buffer[5]); + CuAssertIntEquals(tc, (char)-2, buffer[5]); CuAssertIntEquals(tc, 8, strlcat(buffer, "derp", 8)); CuAssertStrEquals(tc, "herpder", buffer); - CuAssertIntEquals(tc, -2, buffer[8]); + CuAssertIntEquals(tc, (char)-2, buffer[8]); } static void test_strlcpy(CuTest * tc) @@ -33,11 +33,11 @@ static void test_strlcpy(CuTest * tc) CuAssertIntEquals(tc, 4, strlcpy(buffer, "herp", 8)); CuAssertStrEquals(tc, "herp", buffer); - CuAssertIntEquals(tc, -2, buffer[5]); + CuAssertIntEquals(tc, (char)-2, buffer[5]); CuAssertIntEquals(tc, 8, strlcpy(buffer, "herpderp", 8)); CuAssertStrEquals(tc, "herpder", buffer); - CuAssertIntEquals(tc, -2, buffer[8]); + CuAssertIntEquals(tc, (char)-2, buffer[8]); } static void test_slprintf(CuTest * tc) @@ -51,11 +51,11 @@ static void test_slprintf(CuTest * tc) CuAssertIntEquals(tc, 4, slprintf(buffer, 8, "%s", "herp")); CuAssertStrEquals(tc, "herp", buffer); - CuAssertIntEquals(tc, -2, buffer[5]); + CuAssertIntEquals(tc, (char)-2, buffer[5]); CuAssertIntEquals(tc, 8, slprintf(buffer, 8, "%s", "herpderp")); CuAssertStrEquals(tc, "herpder", buffer); - CuAssertIntEquals(tc, -2, buffer[8]); + CuAssertIntEquals(tc, (char)-2, buffer[8]); } CuSuite *get_bsdstring_suite(void) From a5a92fc9b4dde865efeb968062c44b77a662f081 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 3 Jun 2012 22:32:59 -0700 Subject: [PATCH 316/400] disable MSVC warnings with a macro --- .gitignore | 1 + CMakeLists.txt | 2 +- src/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 1bf3ffbcb..48f1b84a0 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ Release/ *.sh src/*.vcproj.*.user tags +build-vs2010 diff --git a/CMakeLists.txt b/CMakeLists.txt index a2548de17..81b64d256 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.4) +cmake_minimum_required(VERSION 2.6) project (core C) add_subdirectory (../dependencies "${CMAKE_CURRENT_BINARY_DIR}/dependencies") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 918ad54e3..07f926c5b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.4) +cmake_minimum_required(VERSION 2.6) project (eressea C) set (CORE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "Eressea Core headers") From dd30c9a6217d27872de0f58517397ac3ad202deb Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 3 Jun 2012 23:36:40 -0700 Subject: [PATCH 317/400] Make this stuff compile on MSVC Fix some missing headers I have to redo the tests --- src/CMakeLists.txt | 3 ++- src/kernel/connection.c | 1 + src/kernel/faction.c | 1 + src/kernel/pool_test.c | 2 ++ src/tests_test.c | 1 + 5 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 07f926c5b..951245cab 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,8 @@ set (CORE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "Eressea Core h find_package (Lua51 REQUIRED) find_package (LibXml2 REQUIRED) +find_package (Curses REQUIRED) +find_package (SQLite3 REQUIRED) include_directories (${CORE_INCLUDE_DIR}) include_directories (${CRITBIT_INCLUDE_DIR}) @@ -139,7 +141,6 @@ add_library(${PROJECT_NAME} modules/wormhole.c modules/xecmd.c modules/xmas.c - tests.c tests_test.c triggers/changefaction.c triggers/changerace.c diff --git a/src/kernel/connection.c b/src/kernel/connection.c index ec3c31b67..5d4d24d19 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -27,6 +27,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "version.h" #include +#include #include #include #include diff --git a/src/kernel/faction.c b/src/kernel/faction.c index ff011bc38..7cde125de 100644 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -36,6 +36,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include #include +#include #include #include #include diff --git a/src/kernel/pool_test.c b/src/kernel/pool_test.c index 38be7aaae..3b801a9b9 100644 --- a/src/kernel/pool_test.c +++ b/src/kernel/pool_test.c @@ -2,10 +2,12 @@ #include #include "pool.h" +#include "magic.h" #include "unit.h" #include "item.h" #include "region.h" #include "skill.h" + #include #include diff --git a/src/tests_test.c b/src/tests_test.c index c685d8a50..250ea5ec6 100644 --- a/src/tests_test.c +++ b/src/tests_test.c @@ -7,6 +7,7 @@ #include #include +#include static void test_recreate_world(CuTest * tc) { From ac5c892c52aac8182d485a91a60b9bdf6c14f49b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 4 Jun 2012 02:35:56 -0700 Subject: [PATCH 318/400] hammering these makefiles until everything works --- CMakeLists.txt | 2 ++ src/CMakeLists.txt | 75 ++++++++++++++++++++++++++++++++-------------- src/tests.c | 26 ++++------------ src/tests.h | 29 +++++++++++++++--- 4 files changed, 84 insertions(+), 48 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 81b64d256..b04b2a5ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,7 @@ cmake_minimum_required(VERSION 2.6) project (core C) +enable_testing() + add_subdirectory (../dependencies "${CMAKE_CURRENT_BINARY_DIR}/dependencies") add_subdirectory (src eressea) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 951245cab..4a0287d56 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,24 +1,65 @@ cmake_minimum_required(VERSION 2.6) project (eressea C) -set (CORE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "Eressea Core headers") +set (ERESSEA_LIBRARY ${PROJECT_NAME} CACHE INTERNAL "Eressea Core Library") +set (ERESSEA_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "Eressea Core headers") find_package (Lua51 REQUIRED) +find_package (ToLua REQUIRED) find_package (LibXml2 REQUIRED) find_package (Curses REQUIRED) find_package (SQLite3 REQUIRED) -include_directories (${CORE_INCLUDE_DIR}) +set (ERESSEA_LIBRARIES + ${BSON_LIBRARIES} + ${CUTEST_LIBRARIES} + ${CRITBIT_LIBRARIES} + ${QUICKLIST_LIBRARIES} + ${CRYPTO_LIBRARIES} + ${INIPARSER_LIBRARIES} + ${LUA_LIBRARIES} + ${LIBXML2_LIBRARIES} + ${SQLITE3_LIBRARIES} + ${CURSES_LIBRARIES} + CACHE STRING "Eressea Libraries" +) + +include_directories (${ERESSEA_INCLUDE_DIR}) include_directories (${CRITBIT_INCLUDE_DIR}) include_directories (${CRYPTO_INCLUDE_DIR}) include_directories (${QUICKLIST_INCLUDE_DIR}) include_directories (${CUTEST_INCLUDE_DIR}) include_directories (${LUA_INCLUDE_DIR}) +include_directories (${TOLUA_INCLUDE_DIR}) include_directories (${LIBXML2_INCLUDE_DIR}) include_directories (${BSON_INCLUDE_DIR}) include_directories (${INIPARSER_INCLUDE_DIR}) -add_library(${PROJECT_NAME} +set (TEST_SRC + tests.c + tests_test.c + gamecode/economy_test.c + gamecode/laws_test.c + gamecode/market_test.c + kernel/battle_test.c + kernel/building_test.c + kernel/curse_test.c + kernel/equipment_test.c + kernel/item_test.c + kernel/magic_test.c + kernel/move_test.c + kernel/pool_test.c + kernel/reports_test.c + kernel/ship_test.c + kernel/spellbook_test.c + kernel/spell_test.c + util/base36_test.c + util/bsdstring_test.c + util/functions_test.c + util/umlaut_test.c +) + +set (LIB_SRC attributes/alliance.c attributes/attributes.c attributes/fleechance.c @@ -57,13 +98,10 @@ add_library(${PROJECT_NAME} gamecode/creation.c gamecode/creport.c gamecode/economy.c - gamecode/economy_test.c gamecode/give.c gamecode/items.c gamecode/laws.c - gamecode/laws_test.c gamecode/market.c - gamecode/market_test.c gamecode/monster.c gamecode/randenc.c gamecode/report.c @@ -83,48 +121,36 @@ add_library(${PROJECT_NAME} kernel/alchemy.c kernel/alliance.c kernel/battle.c - kernel/battle_test.c kernel/binarystore.c kernel/build.c kernel/building.c - kernel/building_test.c kernel/calendar.c kernel/command.c kernel/config.c kernel/connection.c kernel/curse.c - kernel/curse_test.c kernel/equipment.c - kernel/equipment_test.c kernel/faction.c kernel/group.c kernel/item.c - kernel/item_test.c kernel/magic.c - kernel/magic_test.c kernel/message.c kernel/move.c - kernel/move_test.c kernel/names.c kernel/order.c kernel/pathfinder.c kernel/plane.c kernel/player.c kernel/pool.c - kernel/pool_test.c kernel/race.c kernel/region.c kernel/reports.c - kernel/reports_test.c kernel/resources.c kernel/save.c kernel/ship.c - kernel/ship_test.c kernel/skill.c kernel/spellbook.c - kernel/spellbook_test.c kernel/spell.c - kernel/spell_test.c kernel/sqlite.c kernel/teleport.c kernel/terrain.c @@ -141,7 +167,6 @@ add_library(${PROJECT_NAME} modules/wormhole.c modules/xecmd.c modules/xmas.c - tests_test.c triggers/changefaction.c triggers/changerace.c triggers/clonedied.c @@ -158,9 +183,7 @@ add_library(${PROJECT_NAME} triggers/unitmessage.c util/attrib.c util/base36.c - util/base36_test.c util/bsdstring.c - util/bsdstring_test.c util/console.c util/crmessage.c util/dice.c @@ -168,7 +191,6 @@ add_library(${PROJECT_NAME} util/event.c util/filereader.c util/functions.c - util/functions_test.c util/goodies.c util/language.c util/listbox.c @@ -184,7 +206,14 @@ add_library(${PROJECT_NAME} util/strings.c util/translation.c util/umlaut.c - util/umlaut_test.c util/unicode.c util/xml.c ) + +add_library(${ERESSEA_LIBRARY} ${LIB_SRC}) +target_link_libraries(${ERESSEA_LIBRARY} ${ERESSEA_LIBRARIES}) + +add_executable(${PROJECT_NAME}_test ${TEST_SRC}) +target_link_libraries(${PROJECT_NAME}_test ${ERESSEA_LIBRARY}) + +add_test(${PROJECT_NAME} ${PROJECT_NAME}_test) diff --git a/src/tests.c b/src/tests.c index 67df8c8ba..e5cf76a91 100644 --- a/src/tests.c +++ b/src/tests.c @@ -5,27 +5,7 @@ #include #include "tests.h" -#include "tests_test.c" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - +#include #include #include #include @@ -221,3 +201,7 @@ void test_create_world(void) locale_setstring(default_locale, "boat", "boat"); st_register(stype); } + +int main(int argc, char ** argv) { + return RunAllTests(); +} diff --git a/src/tests.h b/src/tests.h index ebf1434ae..2b6b91cce 100644 --- a/src/tests.h +++ b/src/tests.h @@ -1,8 +1,31 @@ +#ifndef ERESSEA_TESTS_H +#define ERESSEA_TESTS_H #ifdef __cplusplus extern "C" { #endif + #include + + CuSuite *get_tests_suite(void); + CuSuite *get_economy_suite(void); + CuSuite *get_laws_suite(void); + CuSuite *get_market_suite(void); + CuSuite *get_battle_suite(void); + CuSuite *get_building_suite(void); + CuSuite *get_curse_suite(void); + CuSuite *get_equipment_suite(void); + CuSuite *get_item_suite(void); + CuSuite *get_magic_suite(void); + CuSuite *get_move_suite(void); + CuSuite *get_pool_suite(void); + CuSuite *get_reports_suite(void); + CuSuite *get_ship_suite(void); + CuSuite *get_spellbook_suite(void); + CuSuite *get_spell_suite(void); + CuSuite *get_base36_suite(void); + CuSuite *get_bsdstring_suite(void); + CuSuite *get_functions_suite(void); + CuSuite *get_umlaut_suite(void); -#ifndef DISABLE_TESTS void test_cleanup(void); struct terrain_type * test_create_terrain(const char * name, unsigned int flags); @@ -16,10 +39,8 @@ extern "C" { struct ship * test_create_ship(struct region * r, const struct ship_type * stype); struct item_type * test_create_itemtype(const char ** names); int RunAllTests(void); -#else -#define RunAllTests() 0 -#endif #ifdef __cplusplus } #endif +#endif From c44ebad24e8d8946674be2b9567503e592c6543d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 4 Jun 2012 02:41:07 -0700 Subject: [PATCH 319/400] missing include files --- src/gamecode/randenc.c | 1 + src/tests.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/gamecode/randenc.c b/src/gamecode/randenc.c index a2d84f154..61ecf3ac5 100644 --- a/src/gamecode/randenc.c +++ b/src/gamecode/randenc.c @@ -52,6 +52,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include +#include #include #include #include diff --git a/src/tests.c b/src/tests.c index e5cf76a91..b269663dc 100644 --- a/src/tests.c +++ b/src/tests.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include #include From 86928b5c3172bd56db2d591252d1302feb5e8e09 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 4 Jun 2012 16:23:02 -0700 Subject: [PATCH 320/400] disable bson dependency, nobody is using that code --- src/CMakeLists.txt | 2 +- src/bindings/bind_unit.c | 8 +++++++- src/eressea.c | 6 +++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4a0287d56..e187bdc54 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -80,7 +80,7 @@ set (LIB_SRC attributes/raceprefix.c attributes/reduceproduction.c attributes/targetregion.c - bindings/bind_attrib.c +# bindings/bind_attrib.c bindings/bind_building.c bindings/bind_faction.c bindings/bind_gmtool.c diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 8949ddb66..3a016b900 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -13,7 +13,9 @@ without prior permission by the authors of Eressea. #include #include "bind_unit.h" -#include "bind_attrib.h" +#ifdef BSON_ATTRIB +# include "bind_attrib.h" +#endif #include "bindings.h" /* attributes includes */ @@ -60,6 +62,7 @@ static int tolua_unit_get_objects(lua_State * L) return 1; } +#ifdef BSON_ATTRIB static int tolua_unit_get_attribs(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); @@ -74,6 +77,7 @@ static int tolua_unit_get_attribs(lua_State * L) lua_pushcclosure(L, tolua_attriblist_next, 1); return 1; } +#endif int tolua_unitlist_nextf(lua_State * L) { @@ -979,7 +983,9 @@ void tolua_unit_open(lua_State * L) tolua_variable(L, TOLUA_CAST "hp_max", &tolua_unit_get_hpmax, 0); tolua_variable(L, TOLUA_CAST "objects", &tolua_unit_get_objects, 0); +#ifdef BSON_ATTRIB tolua_variable(L, TOLUA_CAST "attribs", &tolua_unit_get_attribs, 0); +#endif } tolua_endmodule(L); } diff --git a/src/eressea.c b/src/eressea.c index f3620b2a5..50ab01485 100644 --- a/src/eressea.c +++ b/src/eressea.c @@ -13,7 +13,9 @@ #include #include #include -#include +#ifdef BSON_ATTRIB +# include +#endif #include #include #include @@ -99,7 +101,9 @@ static lua_State *lua_init(void) tolua_ship_open(L); tolua_region_open(L); tolua_faction_open(L); +#ifdef BSON_ATTRIB tolua_attrib_open(L); +#endif tolua_unit_open(L); tolua_message_open(L); tolua_hashtable_open(L); From a6785c6b7b7773351c5229f5051a4cb8e17b8eae Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 5 Jun 2012 05:14:24 +0200 Subject: [PATCH 321/400] have the bson-attrib tests all in one place so we can choose not to use them --- scripts/tests/bson.lua | 26 ++++++++++++++++++++++++++ scripts/tests/common.lua | 26 -------------------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/scripts/tests/bson.lua b/scripts/tests/bson.lua index a7c12d75c..0ee6e6e2e 100644 --- a/scripts/tests/bson.lua +++ b/scripts/tests/bson.lua @@ -37,3 +37,29 @@ function test_bson_readwrite() assert_equal(a.data, 42) end end + +function test_bson() + local r = region.create(0, 0, "mountain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + assert_not_equal(nil, u) + assert_not_equal(nil, r) + assert_not_equal(nil, f) + attrib.create(r, 1) + assert_equal(attrib.get(r)().data, 1) + attrib.create(u, 3) + assert_equal(attrib.get(u)().data, 3) + attrib.create(f, 5) + assert_equal(attrib.get(f)().data, 5) +end + +function test_bson_with_multiple_attribs() + local r = region.create(0, 0, "mountain") + attrib.create(r, { a=1}) + attrib.create(r, { a=5}) + local total = 0 + for a in attrib.get(r) do + total = total + a.data.a; + end + assert_equal(6, total) +end diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 6c98b19ac..635b06f34 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -960,32 +960,6 @@ function test_bug_1679() assert_true(find_in_report(f, "entdeckt, dass es keinen Weg nach Westen gibt")) end -function test_bson() - local r = region.create(0, 0, "mountain") - local f = faction.create("noreply@eressea.de", "human", "de") - local u = unit.create(f, r, 1) - assert_not_equal(nil, u) - assert_not_equal(nil, r) - assert_not_equal(nil, f) - attrib.create(r, 1) - assert_equal(attrib.get(r)().data, 1) - attrib.create(u, 3) - assert_equal(attrib.get(u)().data, 3) - attrib.create(f, 5) - assert_equal(attrib.get(f)().data, 5) -end - -function test_bson_with_multiple_attribs() - local r = region.create(0, 0, "mountain") - attrib.create(r, { a=1}) - attrib.create(r, { a=5}) - local total = 0 - for a in attrib.get(r) do - total = total + a.data.a; - end - assert_equal(6, total) -end - function test_building_unique0() local r = region.create(0, 0, "mountain") local f = faction.create("noreply@eressea.de", "human", "de") From 6b57791acbe40b46392d178629b9fe805829ea71 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 4 Jun 2012 21:43:28 -0700 Subject: [PATCH 322/400] add another core type to the list --- src/kernel/types.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/kernel/types.h b/src/kernel/types.h index 23cef5f51..820f4b698 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -39,6 +39,7 @@ struct building; struct building_type; struct curse; struct curse_type; +struct castorder; struct equipment; struct faction; struct fighter; From 2bf3c840aee51bce17302d4140440325ffa4cb36 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 5 Jun 2012 07:36:05 -0700 Subject: [PATCH 323/400] beware: new directory layout, new server --- scripts/tests/attrib.lua | 53 +++++++++++++++++++ scripts/tests/bson.lua | 2 +- scripts/tests/common.lua | 2 +- scripts/tests/spells.lua | 108 ++++----------------------------------- src/CMakeLists.txt | 6 +++ 5 files changed, 72 insertions(+), 99 deletions(-) create mode 100644 scripts/tests/attrib.lua diff --git a/scripts/tests/attrib.lua b/scripts/tests/attrib.lua new file mode 100644 index 000000000..b86efa734 --- /dev/null +++ b/scripts/tests/attrib.lua @@ -0,0 +1,53 @@ +require "lunit" + +module("tests.eressea.attrib", package.seeall, lunit.testcase) + +function has_attrib(u, value) + for a in u.attribs do + if (a.data==value) then return true end + end + return false +end + +function test_attrib_global() + a = attrib.create('global', {}) + write_game('attrib.dat') + free_game() + read_game('attrib.dat') +end + +function test_attrib() + local r = region.create(0,0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + data = { arr = { 'a', 'b', 'c' }, name = 'familiar', events = { die = 'familiar_died' }, data = { mage = u2 } } + a = { 'a' } + b = { 'a' } + uno = u.id + u2no = u2.id + a = attrib.create(u, 12) + a = attrib.create(u, "enno") + a = attrib.create(u, u2) + a = attrib.create(u, data) + write_game("attrib.dat") + free_game() + read_game("attrib.dat") + u = get_unit(uno) + u2 = get_unit(u2no) + assert_false(has_attrib(u, 42)) + assert_true(has_attrib(u, "enno")) + assert_true(has_attrib(u, 12)) + + for a in u.attribs do + x = a.data + if (type(x)=="table") then + assert_equal('a', x.arr[1]) + assert_equal('familiar', x.name) + assert_equal('familiar_died', x.events.die) + assert_equal(u2, x.data.mage) + break + end + end +end + diff --git a/scripts/tests/bson.lua b/scripts/tests/bson.lua index 0ee6e6e2e..f199ee7d0 100644 --- a/scripts/tests/bson.lua +++ b/scripts/tests/bson.lua @@ -1,6 +1,6 @@ require "lunit" -module("tests.bson", package.seeall, lunit.testcase) +module("tests.eressea.bson", package.seeall, lunit.testcase) function setup() free_game() diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 635b06f34..59b9b68e9 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -35,7 +35,7 @@ local function two_factions() return f1, f2 end -module("tests.common", package.seeall, lunit.testcase) +module("tests.eressea.common", package.seeall, lunit.testcase) function setup() free_game() diff --git a/scripts/tests/spells.lua b/scripts/tests/spells.lua index d8b446ace..f27b18df7 100644 --- a/scripts/tests/spells.lua +++ b/scripts/tests/spells.lua @@ -1,20 +1,23 @@ require "lunit" -module("tests.spells", package.seeall, lunit.testcase) +module("tests.eressea.spells", package.seeall, lunit.testcase) + +local r, f, u function setup() free_game() - settings.set("magic.fumble.enable", "0") settings.set("magic.regeneration.enable", "0") + settings.set("magic.fumble.enable", "0") settings.set("rules.economy.food", "4") + + r = region.create(0, 0, "plain") + f = faction.create("spell_payment@eressea.de", "elf", "de") + u = unit.create(f, r, 1) + u.magic = "gray" + u:set_skill("magic", 12) end function test_spell_payment() - local r = region.create(0,0, "plain") - local f = faction.create("spell_payment@eressea.de", "human", "de") - local u = unit.create(f, r, 1) - u:set_skill("magic", 12) - u.magic = "gwyrrd" -- calls create_mage u:add_spell("create_roi") local permaura = u:get_pooled("permaura") @@ -23,7 +26,7 @@ function test_spell_payment() u:clear_orders() u:add_order("ZAUBERE 'Erschaffe einen Ring der Unsichtbarkeit' ") process_orders() - + write_reports() assert_equal(1, u:get_item("roi")) assert_equal(0, u:get_item("money")) assert_equal(0, u.aura) @@ -31,12 +34,6 @@ function test_spell_payment() end function test_spell_not_found_no_payment() - local r = region.create(0,0, "plain") - local f = faction.create("spell_fails_no_payment@eressea.de", "human", "de") - local u = unit.create(f, r, 1) - u.magic = "gwyrrd" -- calls create_mage - u:set_skill("magic", 12) - local permaura = u:get_pooled("permaura") u:add_item("money", 3000) u.aura = 50 @@ -51,132 +48,49 @@ function test_spell_not_found_no_payment() assert_equal(permaura, u:get_pooled("permaura")) end -function test_create_firesword() - local r = region.create(0,0, "plain") - local f = faction.create("create_firesword@eressea.de", "human", "de") - local u = unit.create(f, r, 1) - u.magic = "gwyrrd" -- calls create_mage - u:set_skill("magic", 12) - u:add_spell("create_firesword") - - u:cast_spell('create_firesword', 1) - assert_equal(1, u:get_item("firesword")) -end - function test_create_roi() - local r = region.create(0,0, "plain") - local f = faction.create("create_roi@eressea.de", "human", "de") - local u = unit.create(f, r, 1) - u.magic = "gwyrrd" -- calls create_mage - u:set_skill("magic", 10) - u:add_spell('create_roi') u:cast_spell('create_roi') assert_equal(1, u:get_item("roi")) end function test_create_roqf() - local r = region.create(0,0, "plain") - local f = faction.create("create_roqf@eressea.de", "human", "de") - local u = unit.create(f, r, 1) - u.magic = "gwyrrd" -- calls create_mage - u:set_skill("magic", 10) - u:add_spell('create_roqf') u:cast_spell('create_roqf') assert_equal(1, u:get_item("roqf")) end function test_create_aots() - local r = region.create(0,0, "plain") - local f = faction.create("create_aots@eressea.de", "human", "de") - local u = unit.create(f, r, 1) - u.magic = "gwyrrd" -- calls create_mage - u:set_skill("magic", 10) - u:add_spell('create_aots') u:cast_spell('create_aots') assert_equal(1, u:get_item("aots")) end function test_create_ror() - local r = region.create(0,0, "plain") - local f = faction.create("create_ror@eressea.de", "human", "de") - local u = unit.create(f, r, 1) - u.magic = "gwyrrd" -- calls create_mage - u:set_skill("magic", 10) - u:add_spell('create_ror') u:cast_spell('create_ror') assert_equal(1, u:get_item("ror")) end -function test_create_magicherbbag() - local r = region.create(0,0, "plain") - local f = faction.create("create_magicherbbag@eressea.de", "human", "de") - local u = unit.create(f, r, 1) - u.magic = "gwyrrd" -- calls create_mage - u:set_skill("magic", 10) - - u:add_spell('create_magicherbbag') - u:cast_spell('create_magicherbbag') - assert_equal(1, u:get_item("magicherbbag")) -end - function test_create_trollbelt() - local r = region.create(0,0, "plain") - local f = faction.create("create_trollbelt@eressea.de", "human", "de") - local u = unit.create(f, r, 1) - u.magic = "gwyrrd" -- calls create_mage - u:set_skill("magic", 10) - u:add_spell('create_trollbelt') u:cast_spell('create_trollbelt') assert_equal(1, u:get_item("trollbelt")) end function test_create_dreameye() - local r = region.create(0,0, "plain") - local f = faction.create("create_dreameye@eressea.de", "human", "de") - local u = unit.create(f, r, 1) - u.magic = "gwyrrd" -- calls create_mage - u:set_skill("magic", 10) - u:add_spell('create_dreameye') u:cast_spell('create_dreameye') assert_equal(1, u:get_item("dreameye")) end function test_create_antimagic() - local r = region.create(0,0, "plain") - local f = faction.create("create_antimagic@eressea.de", "human", "de") - local u = unit.create(f, r, 1) - u.magic = "gwyrrd" -- calls create_mage - u:set_skill("magic", 10) - u:add_spell('create_antimagic') u:cast_spell('create_antimagic') assert_equal(1, u:get_item("antimagic")) end -function test_create_runesword() - local r = region.create(0,0, "plain") - local f = faction.create("create_runesword@eressea.de", "human", "de") - local u = unit.create(f, r, 1) - u.magic = "gwyrrd" -- calls create_mage - u:set_skill("magic", 10) - - u:add_spell('create_runesword') - u:cast_spell('create_runesword') - assert_equal(1, u:get_item("runesword")) -end - function test_create_rop() - local r = region.create(0,0, "plain") - local f = faction.create("create_rop@eressea.de", "human", "de") - local u = unit.create(f, r, 1) - u:set_skill("magic", 10) - u:add_spell('create_rop') u:cast_spell('create_rop') assert_equal(1, u:get_item("rop")) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e187bdc54..72af6a1ee 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,12 @@ cmake_minimum_required(VERSION 2.6) project (eressea C) +IF(CMAKE_COMPILER_IS_GNUCC) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic -Wall -Werror -Wno-unknown-pragmas -Wstrict-prototypes -Wpointer-arith -Wno-char-subscripts -Wno-long-long") +ELSE(CMAKE_COMPILER_IS_GNUCC) + MESSAGE(STATUS "Unknown compiler ${CMAKE_C_COMPILER_ID}") +ENDIF(CMAKE_COMPILER_IS_GNUCC) + set (ERESSEA_LIBRARY ${PROJECT_NAME} CACHE INTERNAL "Eressea Core Library") set (ERESSEA_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "Eressea Core headers") From 74ddb1f881ae0c1def9fef6a3eac7e1778ebe55c Mon Sep 17 00:00:00 2001 From: Gerd Wellenreuther Date: Thu, 7 Jun 2012 20:59:26 +0200 Subject: [PATCH 324/400] Bugfix 1922 entering of RF_BLOCKED regions with ships --- scripts/tests/common.lua | 44 ++++++++++++++++++++++++++++++++++++++++ src/kernel/move.c | 3 ++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 59b9b68e9..06fe05807 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -917,6 +917,50 @@ function test_parser() assert_not_equal(0, u:get_skill("melee")) end +function test_bug_1922() + -- see http://bugs.eressea.de/view.php?id=1922 + local r = region.create(0, 0, "ocean") + local r2 = region.create(1, 0, "plain") + r2:set_flag(2) -- region should not be accessible + + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + + local s = _test_create_ship(r) + + settings.set("rules.ship.drifting","0") -- ships are not drifting + settings.set("rules.economy.food","4") -- does not need silver + + u.ship = s + u:clear_orders() + u:add_order("NACH O") + u:set_skill("sailing",120) -- supadupa captain able to drive a trireme + process_orders() + assert_not_equal(r2,u.region) -- unit should not reach r2. + +end + + +function test_bug_1922_by_foot() + -- see http://bugs.eressea.de/view.php?id=1922 + local r = region.create(0, 0, "plain") + local r2 = region.create(1, 0, "plain") + r2:set_flag(2) -- region should not be accessible + + local f = faction.create("noreply@eressea.de", "human", "de") + local u = unit.create(f, r, 1) + + settings.set("rules.economy.food","4") -- does not need silver + + u:clear_orders() + u:add_order("NACH O") + + process_orders() + assert_not_equal(r2,u.region) -- unit should not reach r2. + +end + + function test_bug_1814() -- see http://bugs.eressea.de/view.php?id=1814 local r = region.create(0, 0, "mountain") diff --git a/src/kernel/move.c b/src/kernel/move.c index 5c1f7b9fc..993125b43 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -704,6 +704,7 @@ static float damage_drift(void) static void drifting_ships(region * r) { direction_t d; + if (get_param_int(global.parameters, "rules.ship.drifting", 1)==0) return; if (fval(r->terrain, SEA_REGION)) { ship **shp = &r->ships; @@ -1718,7 +1719,7 @@ sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) assert(sh == u->ship || !"ship has sunk, but we didn't notice it"); - if (fval(next_point->terrain, FORBIDDEN_REGION)) { + if (fval(next_point->terrain, FORBIDDEN_REGION)||fval(next_point,RF_BLOCKED)) { ADDMSG(&f->msgs, msg_message("sailforbidden", "ship region", sh, next_point)); break; From 9d58f6540463fc35091d7d014311a8a28425c11c Mon Sep 17 00:00:00 2001 From: Steffen Mecke Date: Sat, 9 Jun 2012 00:13:13 +0200 Subject: [PATCH 325/400] fixed bug #1875: demons use their own peasantblood before other unit's --- scripts/tests/common.lua | 79 ++++++++++++++++++++++++++++++++++++++++ src/bindings/bind_unit.c | 22 +++++++++++ src/gamecode/laws.c | 44 ++++++++++------------ src/gamecode/randenc.c | 4 +- src/kernel/alchemy.h | 5 +++ 5 files changed, 128 insertions(+), 26 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 06fe05807..3e17d3414 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -1097,3 +1097,82 @@ function test_building_unique() assert_equal(1, bcount) -- only one should be completed end end + +function test_bug_1875_use_normal() + -- see http://bugs.eressea.de/view.php?id=1875 + local r = region.create(0, 0, "plain") + r:set_resource("peasant", 0) + + settings.set("rules.economy.food", "0") -- food is not free + + local f = faction.create("noreply@eressea.de", "demon", "de") + local u = unit.create(f, r, 1) + + u:add_item("peasantblood", 1) + u:add_order("BENUTZE 1 Bauernblut") + + assert_equal(1, u:get_item("peasantblood")) + assert_equal(0, u:get_potion("peasantblood")) + + process_orders() + + assert_equal(0, u:get_item("peasantblood")) + assert_equal(0, r:get_resource("peasant")) + assert_equal(99, u:get_potion("peasantblood")) -- unit used one peasantblood effect +end + +function test_bug_1875_use_help() + -- see http://bugs.eressea.de/view.php?id=1875 + local r = region.create(0, 0, "plain") + r:set_resource("peasant", 0) + + settings.set("rules.economy.food", "0") -- food is not free + + local f = faction.create("noreply@eressea.de", "demon", "de") + local u = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + + u:add_item("peasantblood", 1) + u:add_order("BENUTZE 1 Bauernblut") + + assert_equal(1, u:get_item("peasantblood")) + assert_equal(0, u:get_potion("peasantblood")) + assert_equal(0, u2:get_item("peasantblood")) + assert_equal(0, u2:get_potion("peasantblood")) + + process_orders() + + assert_equal(0, u:get_item("peasantblood")) + assert_equal(0, r:get_resource("peasant")) + assert_equal(0, u2:get_potion("peasantblood")) -- first unit helps this unit + assert_equal(98, u:get_potion("peasantblood")) -- unit uses one peasantblood effect +end + +function test_bug_1875_use_own_first() + -- see http://bugs.eressea.de/view.php?id=1875 + local r = region.create(0, 0, "plain") + r:set_resource("peasant", 0) + + settings.set("rules.economy.food", "0") -- food is not free + + local f = faction.create("noreply@eressea.de", "demon", "de") + local u = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + + u:add_item("peasantblood", 1) + u:add_order("BENUTZE 1 Bauernblut") + u2:add_item("peasantblood", 1) + u2:add_order("BENUTZE 1 Bauernblut") + + assert_equal(1, u:get_item("peasantblood")) + assert_equal(0, u:get_potion("peasantblood")) + assert_equal(1, u2:get_item("peasantblood")) + assert_equal(0, u2:get_potion("peasantblood")) + + process_orders() + + assert_equal(0, u:get_item("peasantblood")) + assert_equal(0, r:get_resource("peasant")) + assert_equal(99, u:get_potion("peasantblood")) -- unit uses one peasantblood effect + assert_equal(99, u2:get_potion("peasantblood")) -- u2 uses its own effect before u's +end diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 3a016b900..e2d6f5efd 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -23,6 +23,7 @@ without prior permission by the authors of Eressea. #include /* kernel includes */ +#include #include #include #include @@ -330,6 +331,24 @@ static int tolua_unit_get_item(lua_State * L) return 1; } +static int tolua_unit_get_effect(lua_State * L) +{ + const unit *self = (unit *)tolua_tousertype(L, 1, 0); + const char *potion_name = tolua_tostring(L, 2, 0); + int result = -1; + const potion_type *pt_potion; + const item_type *it_potion = it_find(potion_name); + + if (it_potion != NULL) { + pt_potion = it_potion->rtype->ptype; + if (pt_potion != NULL) + result = get_effect(self, pt_potion); + } + + lua_pushinteger(L, result); + return 1; +} + static int tolua_unit_add_item(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); @@ -947,6 +966,9 @@ void tolua_unit_open(lua_State * L) tolua_function(L, TOLUA_CAST "get_pooled", &tolua_unit_get_pooled); tolua_function(L, TOLUA_CAST "use_pooled", &tolua_unit_use_pooled); + /* effects */ + tolua_function(L, TOLUA_CAST "get_potion", &tolua_unit_get_effect); + /* skills: */ tolua_function(L, TOLUA_CAST "get_skill", &tolua_unit_getskill); tolua_function(L, TOLUA_CAST "eff_skill", &tolua_unit_effskill); diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 6965a8f7d..69e7efc45 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -333,20 +333,27 @@ void get_food(region * r) */ for (u = r->units; u; u = u->next) { if (u->race == new_race[RC_DAEMON]) { - unit *donor = r->units; int hungry = u->number; - while (donor != NULL && hungry > 0) { - /* always start with the first known unit that may have some blood */ - static const struct potion_type *pt_blood; - if (pt_blood == NULL) { - const item_type *it_blood = it_find("peasantblood"); - if (it_blood) - pt_blood = it_blood->rtype->ptype; - } - if (pt_blood != NULL) { + /* use peasantblood before eating the peasants themselves */ + static const struct potion_type *pt_blood; + if (pt_blood == NULL) { + const item_type *it_blood = it_find("peasantblood"); + if (it_blood) + pt_blood = it_blood->rtype->ptype; + } + if (pt_blood != NULL) { + /* always start with the unit itself, then the first known unit that may have some blood */ + unit *donor = u; + while (donor != NULL && hungry > 0) { + int blut = get_effect(donor, pt_blood); + blut = MIN(blut, hungry); + change_effect(donor, pt_blood, -blut); + hungry -= blut; + if (donor == u) + donor = r->units; while (donor != NULL) { - if (donor->race == new_race[RC_DAEMON]) { + if (donor->race == new_race[RC_DAEMON] && donor!=u) { if (get_effect(donor, pt_blood)) { /* if he's in our faction, drain him: */ if (donor->faction == u->faction) @@ -355,14 +362,9 @@ void get_food(region * r) } donor = donor->next; } - if (donor != NULL) { - int blut = get_effect(donor, pt_blood); - blut = MIN(blut, hungry); - change_effect(donor, pt_blood, -blut); - hungry -= blut; - } } } + /* remaining demons feed on peasants */ if (pl == NULL || !fval(pl, PFL_NOFEED)) { if (peasantfood >= hungry) { peasantfood -= hungry; @@ -377,15 +379,9 @@ void get_food(region * r) demon_hunger = get_param_int(global.parameters, "hunger.demons", 0); } if (demon_hunger == 0) { - /* nicht gefütterte dämonen hungern */ -#ifdef PEASANT_HUNGRY_DAEMONS_HAVE_FULL_SKILLS - /* wdw special rule */ - hunger(hungry, u); -#else + /* demons who don't feed are hungry */ if (hunger(hungry, u)) fset(u, UFL_HUNGER); -#endif - /* used to be: hunger(hungry, u); */ } else { /* no damage, but set the hungry-flag */ fset(u, UFL_HUNGER); diff --git a/src/gamecode/randenc.c b/src/gamecode/randenc.c index 61ecf3ac5..43d3370b2 100644 --- a/src/gamecode/randenc.c +++ b/src/gamecode/randenc.c @@ -1181,8 +1181,8 @@ static void rotting_herbs(void) for (r = regions; r; r = r->next) { unit *u; for (u = r->units; u; u = u->next) { - item **itmp = &u->items, *hbag = - *i_find(itmp, olditemtype[I_SACK_OF_CONSERVATION]); + item **itmp = &u->items; + item *hbag = *i_find(itmp, olditemtype[I_SACK_OF_CONSERVATION]); int rot_chance = rule_rot; if (hbag) diff --git a/src/kernel/alchemy.h b/src/kernel/alchemy.h index 2654c1a21..7444d49ab 100644 --- a/src/kernel/alchemy.h +++ b/src/kernel/alchemy.h @@ -18,6 +18,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifndef H_KRNL_ALCHEMY_H #define H_KRNL_ALCHEMY_H + +#include +#include + #ifdef __cplusplus extern "C" { #endif @@ -56,6 +60,7 @@ extern "C" { int amount, struct order *); extern void init_potions(void); + extern int get_effect(const struct unit *u, const struct potion_type *effect); extern int change_effect(struct unit *u, const struct potion_type *effect, int value); From 2292c616019cc664a03cf9f831d6fd0179c0ddd4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 9 Jun 2012 09:06:59 +0200 Subject: [PATCH 326/400] small changes from code-review --- src/bindings/bind_unit.c | 1 + src/kernel/alchemy.h | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index e2d6f5efd..afa42389b 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -11,6 +11,7 @@ without prior permission by the authors of Eressea. */ #include +#include #include "bind_unit.h" #ifdef BSON_ATTRIB diff --git a/src/kernel/alchemy.h b/src/kernel/alchemy.h index 7444d49ab..af7adf459 100644 --- a/src/kernel/alchemy.h +++ b/src/kernel/alchemy.h @@ -19,9 +19,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifndef H_KRNL_ALCHEMY_H #define H_KRNL_ALCHEMY_H -#include -#include - #ifdef __cplusplus extern "C" { #endif From 8327db65b8d64a259ab823abf39a457a626a33eb Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 9 Jun 2012 09:18:17 +0200 Subject: [PATCH 327/400] I have a slightly broken version of tolua installed which doesn't compare user types. Working around that bug by comparing integers instead. Sigh. --- scripts/tests/common.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 3e17d3414..79f4e0d1b 100644 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -936,7 +936,7 @@ function test_bug_1922() u:add_order("NACH O") u:set_skill("sailing",120) -- supadupa captain able to drive a trireme process_orders() - assert_not_equal(r2,u.region) -- unit should not reach r2. + assert_not_equal(r2.id, u.region.id) -- unit should not reach r2. end @@ -956,7 +956,7 @@ function test_bug_1922_by_foot() u:add_order("NACH O") process_orders() - assert_not_equal(r2,u.region) -- unit should not reach r2. + assert_not_equal(r2.id, u.region.id) -- unit should not reach r2. end From 8b3d735e8cd5583b0c214767a21673720511753c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 6 Jun 2012 19:29:36 -0700 Subject: [PATCH 328/400] Begin of massive changes to the Lua API. Everything will live in a single eressea module now, and the global namespace will no longer be polluted by all kinds of modules and functions. Also new: Bindings will be generated by tolua from .pkg files, starting with settings, eressea (read/write/free_game) and process in this commit. --- .gitignore | 1 + scripts/tests/attrib.lua | 12 +-- scripts/tests/bson.lua | 8 +- scripts/tests/common.lua | 50 +++++------ scripts/tests/orders.lua | 35 ++++++++ scripts/tests/spells.lua | 8 +- src/CMakeLists.txt | 17 +--- src/bindings/CMakeLists.txt | 78 ++++++++++++++++++ src/bindings/bind_eressea.c | 19 +++++ src/bindings/bind_eressea.h | 14 ++++ src/bindings/bind_process.c | 18 ++++ src/bindings/bind_process.h | 13 +++ src/bindings/bind_settings.c | 15 ++++ src/bindings/bind_settings.h | 13 +++ src/bindings/bindings.c | 155 +++++++++++++++++++++++++---------- src/bindings/bindings.h | 7 +- src/bindings/eressea.pkg | 7 ++ src/bindings/process.pkg | 8 ++ src/bindings/settings.pkg | 8 ++ src/eressea.c | 134 +----------------------------- src/eressea.h | 5 +- src/kernel/faction.c | 15 ++-- 22 files changed, 404 insertions(+), 236 deletions(-) mode change 100644 => 100755 scripts/tests/attrib.lua mode change 100644 => 100755 scripts/tests/bson.lua mode change 100644 => 100755 scripts/tests/common.lua create mode 100755 scripts/tests/orders.lua mode change 100644 => 100755 scripts/tests/spells.lua mode change 100644 => 100755 src/CMakeLists.txt create mode 100755 src/bindings/CMakeLists.txt create mode 100755 src/bindings/bind_eressea.c create mode 100755 src/bindings/bind_eressea.h create mode 100755 src/bindings/bind_process.c create mode 100755 src/bindings/bind_process.h create mode 100755 src/bindings/bind_settings.c create mode 100755 src/bindings/bind_settings.h mode change 100644 => 100755 src/bindings/bindings.c mode change 100644 => 100755 src/bindings/bindings.h create mode 100755 src/bindings/eressea.pkg create mode 100755 src/bindings/process.pkg create mode 100755 src/bindings/settings.pkg mode change 100644 => 100755 src/eressea.c mode change 100644 => 100755 src/eressea.h mode change 100644 => 100755 src/kernel/faction.c diff --git a/.gitignore b/.gitignore index f16be6bc9..98396d6f2 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ Release/ *.opensdf *.ipch *.sh +*.tmp src/*.vcproj.*.user tags build-vs2010 diff --git a/scripts/tests/attrib.lua b/scripts/tests/attrib.lua old mode 100644 new mode 100755 index b86efa734..73d961d94 --- a/scripts/tests/attrib.lua +++ b/scripts/tests/attrib.lua @@ -11,9 +11,9 @@ end function test_attrib_global() a = attrib.create('global', {}) - write_game('attrib.dat') - free_game() - read_game('attrib.dat') + eressea.write_game('attrib.dat') + eressea.free_game() + eressea.read_game('attrib.dat') end function test_attrib() @@ -30,9 +30,9 @@ function test_attrib() a = attrib.create(u, "enno") a = attrib.create(u, u2) a = attrib.create(u, data) - write_game("attrib.dat") - free_game() - read_game("attrib.dat") + eressea.write_game("attrib.dat") + eressea.free_game() + eressea.read_game("attrib.dat") u = get_unit(uno) u2 = get_unit(u2no) assert_false(has_attrib(u, 42)) diff --git a/scripts/tests/bson.lua b/scripts/tests/bson.lua old mode 100644 new mode 100755 index f199ee7d0..ec0966bcd --- a/scripts/tests/bson.lua +++ b/scripts/tests/bson.lua @@ -3,7 +3,7 @@ require "lunit" module("tests.eressea.bson", package.seeall, lunit.testcase) function setup() - free_game() + eressea.free_game() end function test_bson_create() @@ -24,12 +24,12 @@ end function test_bson_readwrite() local i, r = region.create(0, 0, "mountain") attrib.create(r, 42) - i = write_game("test_read_write.dat") + i = eressea.write_game("test_read_write.dat") assert_equal(0, i) - free_game() + eressea.free_game() r = get_region(0, 0) assert_equal(nil, r) - i = read_game("test_read_write.dat") + i = eressea.read_game("test_read_write.dat") assert_equal(0, i) r = get_region(0, 0) assert_not_equal(nil, r) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua old mode 100644 new mode 100755 index 79f4e0d1b..95984b443 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -38,12 +38,12 @@ end module("tests.eressea.common", package.seeall, lunit.testcase) function setup() - free_game() - write_game("free.dat") - settings.set("nmr.removenewbie", "0") - settings.set("nmr.timeout", "0") - settings.set("NewbieImmunity", "0") - settings.set("rules.economy.food", "4") + eressea.free_game() + eressea.write_game("free.dat") + eressea.settings.set("nmr.removenewbie", "0") + eressea.settings.set("nmr.timeout", "0") + eressea.settings.set("NewbieImmunity", "0") + eressea.settings.set("rules.economy.food", "4") end function DISABLE_test_eventbus_fire() @@ -112,7 +112,7 @@ function test_read_write() local uno = u.id local result = 0 assert_equal(r.terrain, "plain") - result = write_game("test_read_write.dat", "binary") + result = eressea.write_game("test_read_write.dat") assert_equal(result, 0) assert_not_equal(get_region(0, 0), nil) assert_not_equal(get_faction(fno), nil) @@ -120,11 +120,11 @@ function test_read_write() r = nil f = nil u = nil - free_game() + eressea.free_game() assert_equal(get_region(0, 0), nil) assert_equal(nil, get_faction(fno)) assert_equal(nil, get_unit(uno)) - result = read_game("test_read_write.dat", "binary") + result = eressea.read_game("test_read_write.dat") assert_equal(0, result) assert_not_equal(nil, get_region(0, 0)) assert_not_equal(nil, get_faction(fno)) @@ -388,7 +388,7 @@ function test_work() end function test_upkeep() - settings.set("rules.economy.food", "0") + eressea.settings.set("rules.economy.food", "0") local r = region.create(0, 0, "plain") local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r, 5) @@ -541,7 +541,7 @@ function test_store_unit() assert_not_equal(store, nil) store:write_unit(u) store:close() - free_game() + eressea.free_game() -- recreate world: r = region.create(0, 0, "plain") f = faction.create("noreply@eressea.de", "human", "de") @@ -668,7 +668,7 @@ function test_food_is_consumed() u:add_item("money", 100) u:clear_orders() u:add_order("LERNEN Reiten") -- don't work - settings.set("rules.economy.food", "4") + eressea.settings.set("rules.economy.food", "4") process_orders() assert_equal(100, u:get_item("money")) end @@ -680,7 +680,7 @@ function test_food_can_override() u:add_item("money", 100) u:clear_orders() u:add_order("LERNEN Reiten") -- don't work - settings.set("rules.economy.food", "0") + eressea.settings.set("rules.economy.food", "0") process_orders() assert_equal(90, u:get_item("money")) end @@ -806,10 +806,10 @@ end module("tests.report", package.seeall, lunit.testcase) function setup() - free_game() - settings.set("nmr.removenewbie", "0") - settings.set("nmr.timeout", "0") - settings.set("rules.economy.food", "4") + eressea.free_game() + eressea.settings.set("nmr.removenewbie", "0") + eressea.settings.set("nmr.timeout", "0") + eressea.settings.set("rules.economy.food", "4") end local function find_in_report(f, pattern, extension) @@ -894,9 +894,9 @@ end module("tests.parser", package.seeall, lunit.testcase) function setup() - free_game() - write_game("free.dat") - settings.set("rules.economy.food", "4") -- FOOD_IS_FREE + eressea.free_game() + eressea.write_game("free.dat") + eressea.settings.set("rules.economy.food", "4") -- FOOD_IS_FREE end function test_parser() @@ -909,12 +909,12 @@ function test_parser() assert_not_nil(file) file:write('ERESSEA ' .. itoa36(f.id) .. ' "' .. f.password .. '"\n') file:write('EINHEIT ' .. itoa36(u.id) .. "\n") - file:write("LERNEN Hiebwaffen\n") + file:write("BENENNEN EINHEIT 'Goldene Herde'\n") file:close() read_orders(filename) process_orders() - assert_not_equal(0, u:get_skill("melee")) + assert_equal("Goldene Herde", u.name) end function test_bug_1922() @@ -928,8 +928,8 @@ function test_bug_1922() local s = _test_create_ship(r) - settings.set("rules.ship.drifting","0") -- ships are not drifting - settings.set("rules.economy.food","4") -- does not need silver + eressea.settings.set("rules.ship.drifting","0") -- ships are not drifting + eressea.settings.set("rules.economy.food","4") -- does not need silver u.ship = s u:clear_orders() @@ -950,7 +950,7 @@ function test_bug_1922_by_foot() local f = faction.create("noreply@eressea.de", "human", "de") local u = unit.create(f, r, 1) - settings.set("rules.economy.food","4") -- does not need silver + eressea.settings.set("rules.economy.food","4") -- does not need silver u:clear_orders() u:add_order("NACH O") diff --git a/scripts/tests/orders.lua b/scripts/tests/orders.lua new file mode 100755 index 000000000..0fe64429a --- /dev/null +++ b/scripts/tests/orders.lua @@ -0,0 +1,35 @@ +require "lunit" + +local _G = _G +local eressea = eressea + +module("tests.orders", lunit.testcase) + +local r, f, u + +function setup() + eressea.free_game() + r = _G.region.create(0, 0, "mountain") + f = _G.faction.create("noreply@eressea.de", "human", "de") + u = _G.unit.create(f, r, 1) + u:clear_orders() + eressea.settings.set("rules.economy.food", "4") + eressea.settings.set("nmr.removenewbie", "0") + eressea.settings.set("nmr.timeout", "0") + eressea.settings.set("NewbieImmunity", "0") +end + +function test_learn() + u:add_order("LERNEN Hiebwaffen") + _G.process_orders() + assert_not_equal(0, u:get_skill("melee")) +end + +function test_give() + local u2 = _G.unit.create(f, r, 1) + u:add_item("money", 10) + u:add_order("GIB " .. u2.id .. "5 SILBER") + _G.process_orders() + assert_not_equal(5, u:get_item("money")) + assert_not_equal(5, u2:get_item("money")) +end diff --git a/scripts/tests/spells.lua b/scripts/tests/spells.lua old mode 100644 new mode 100755 index f27b18df7..14ad12c87 --- a/scripts/tests/spells.lua +++ b/scripts/tests/spells.lua @@ -5,10 +5,10 @@ module("tests.eressea.spells", package.seeall, lunit.testcase) local r, f, u function setup() - free_game() - settings.set("magic.regeneration.enable", "0") - settings.set("magic.fumble.enable", "0") - settings.set("rules.economy.food", "4") + eressea.free_game() + eressea.settings.set("magic.regeneration.enable", "0") + eressea.settings.set("magic.fumble.enable", "0") + eressea.settings.set("rules.economy.food", "4") r = region.create(0, 0, "plain") f = faction.create("spell_payment@eressea.de", "elf", "de") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt old mode 100644 new mode 100755 index f7bb33687..916850f56 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,8 @@ cmake_minimum_required(VERSION 2.6) project (eressea C) +add_subdirectory(bindings) + IF(CMAKE_COMPILER_IS_GNUCC) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic -Wall -Werror -Wno-unknown-pragmas -Wstrict-prototypes -Wpointer-arith -Wno-char-subscripts -Wno-long-long") ELSE(CMAKE_COMPILER_IS_GNUCC) @@ -88,19 +90,6 @@ set (LIB_SRC attributes/raceprefix.c attributes/reduceproduction.c attributes/targetregion.c -# bindings/bind_attrib.c - bindings/bind_building.c - bindings/bind_faction.c - bindings/bind_gmtool.c - bindings/bind_hashtable.c - bindings/bindings.c - bindings/bind_message.c - bindings/bind_region.c - bindings/bind_ship.c - bindings/bind_sqlite.c - bindings/bind_storage.c - bindings/bind_unit.c - bindings/helpers.c eressea.c gamecode/archetype.c gamecode/creation.c @@ -218,7 +207,7 @@ set (LIB_SRC util/xml.c ) -add_library(${ERESSEA_LIBRARY} ${LIB_SRC} ${LIB_HDR}) +add_library(${ERESSEA_LIBRARY} ${LIB_SRC} ${BIND_SRC} ${LIB_HDR}) target_link_libraries(${ERESSEA_LIBRARY} ${ERESSEA_LIBRARIES}) add_executable(${PROJECT_NAME}_test ${TEST_SRC}) diff --git a/src/bindings/CMakeLists.txt b/src/bindings/CMakeLists.txt new file mode 100755 index 000000000..821238b20 --- /dev/null +++ b/src/bindings/CMakeLists.txt @@ -0,0 +1,78 @@ +cmake_minimum_required(VERSION 2.6) +project (bindings C) + +IF(CMAKE_COMPILER_IS_GNUCC) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -pedantic -Wall -Werror -Wno-unknown-pragmas -Wstrict-prototypes -Wpointer-arith -Wno-char-subscripts -Wno-long-long") +ELSE(CMAKE_COMPILER_IS_GNUCC) + MESSAGE(STATUS "Unknown compiler ${CMAKE_C_COMPILER_ID}") +ENDIF(CMAKE_COMPILER_IS_GNUCC) + +set (BINDINGS_LIBRARY ${PROJECT_NAME} CACHE INTERNAL "Eressea Lua Bindings") + +find_package (Lua51 REQUIRED) +find_package (ToLua REQUIRED) +find_package (LibXml2 REQUIRED) +find_package (Curses REQUIRED) +find_package (SQLite3 REQUIRED) + +include_directories (${ERESSEA_INCLUDE_DIR}) +include_directories (${CRITBIT_INCLUDE_DIR}) +include_directories (${CRYPTO_INCLUDE_DIR}) +include_directories (${QUICKLIST_INCLUDE_DIR}) +include_directories (${CUTEST_INCLUDE_DIR}) +include_directories (${LUA_INCLUDE_DIR}) +include_directories (${TOLUA_INCLUDE_DIR}) +include_directories (${LIBXML2_INCLUDE_DIR}) +include_directories (${BSON_INCLUDE_DIR}) +include_directories (${INIPARSER_INCLUDE_DIR}) + +FILE (GLOB_RECURSE LIB_HDR *.h) + +MACRO(ADD_LUA_MODULE MODULE_NAME FILES) + ADD_LIBRARY (${MODULE_NAME} SHARED ${FILES}) + SET_TARGET_PROPERTIES(${MODULE_NAME} + PROPERTIES + PREFIX "" + ) +ENDMACRO(ADD_LUA_MODULE) + +MACRO(TOLUA_BINDING PKGFILE FILES) + ADD_CUSTOM_COMMAND( + OUTPUT ${PKGFILE}.c + DEPENDS ${FILES} ${PKGFILE} + COMMAND tolua + ARGS -o ${CMAKE_CURRENT_BINARY_DIR}/${PKGFILE}.c ${PKGFILE} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) +ENDMACRO(TOLUA_BINDING) + +TOLUA_BINDING(process.pkg bind_process.h) +TOLUA_BINDING(eressea.pkg bind_eressea.h) +TOLUA_BINDING(settings.pkg bind_settings.h) + +set (BIND_SRC + process.pkg.c + eressea.pkg.c + settings.pkg.c + + bind_process.c + bind_eressea.c + bind_settings.c + +# bind_attrib.c + bind_building.c + bind_faction.c + bind_gmtool.c + bind_hashtable.c + bindings.c + bind_message.c + bind_region.c + bind_ship.c + bind_sqlite.c + bind_storage.c + bind_unit.c + helpers.c +) + +add_library(${BINDINGS_LIBRARY} ${LIB_SRC} ${BIND_SRC} ${LIB_HDR}) +target_link_libraries(${BINDINGS_LIBRARY} ${ERESSEA_LIBRARY}) diff --git a/src/bindings/bind_eressea.c b/src/bindings/bind_eressea.c new file mode 100755 index 000000000..51c0537d3 --- /dev/null +++ b/src/bindings/bind_eressea.c @@ -0,0 +1,19 @@ +#include "bind_eressea.h" + +#include +#include +#include +#include +#include + +void eressea_free_game(void) { + free_gamedata(); +} + +int eressea_read_game(const char * filename) { + return readgame(filename, IO_BINARY, 0); +} + +int eressea_write_game(const char * filename) { + return writegame(filename, IO_BINARY); +} diff --git a/src/bindings/bind_eressea.h b/src/bindings/bind_eressea.h new file mode 100755 index 000000000..c50683765 --- /dev/null +++ b/src/bindings/bind_eressea.h @@ -0,0 +1,14 @@ +#ifndef BIND_ERESSEA_H +#define BIND_ERESSEA_H +#ifdef __cplusplus +extern "C" { +#endif + +void eressea_free_game(void); +int eressea_read_game(const char * filename); +int eressea_write_game(const char * filename); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/bindings/bind_process.c b/src/bindings/bind_process.c new file mode 100755 index 000000000..5a344c1c4 --- /dev/null +++ b/src/bindings/bind_process.c @@ -0,0 +1,18 @@ +#include "bind_process.h" + +#include +#include +#include +#include +#include + +void process_produce(void) { + struct region *r; + for (r = regions; r; r = r->next) { + produce(r); + } +} + +void process_markets(void) { + do_markets(); +} diff --git a/src/bindings/bind_process.h b/src/bindings/bind_process.h new file mode 100755 index 000000000..c7c7cab64 --- /dev/null +++ b/src/bindings/bind_process.h @@ -0,0 +1,13 @@ +#ifndef BIND_ERESSEA_PROCESS_H +#define BIND_ERESSEA_PROCESS_H +#ifdef __cplusplus +extern "C" { +#endif + +void process_produce(void); +void process_markets(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/bindings/bind_settings.c b/src/bindings/bind_settings.c new file mode 100755 index 000000000..a864a242f --- /dev/null +++ b/src/bindings/bind_settings.c @@ -0,0 +1,15 @@ +#include "bind_settings.h" + +#include +#include +#include + +const char * settings_get(const char *key) +{ + return get_param(global.parameters, key); +} + +void settings_set(const char *key, const char *value) +{ + set_param(&global.parameters, key, value); +} diff --git a/src/bindings/bind_settings.h b/src/bindings/bind_settings.h new file mode 100755 index 000000000..b935f33e0 --- /dev/null +++ b/src/bindings/bind_settings.h @@ -0,0 +1,13 @@ +#ifndef BIND_ERESSEA_PROCESS_H +#define BIND_ERESSEA_PROCESS_H +#ifdef __cplusplus +extern "C" { +#endif + +const char * settings_get(const char *key); +void settings_set(const char *key, const char *value); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c old mode 100644 new mode 100755 index 444997c19..0ec0bd9f7 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -13,7 +13,14 @@ without prior permission by the authors of Eressea. #include #include "bindings.h" #include "bind_unit.h" +#include "bind_storage.h" +#include "bind_building.h" +#include "bind_hashtable.h" +#include "bind_message.h" +#include "bind_building.h" #include "bind_faction.h" +#include "bind_ship.h" +#include "bind_gmtool.h" #include "bind_region.h" #include "helpers.h" @@ -54,6 +61,7 @@ without prior permission by the authors of Eressea. #include #include +#include #include #include #include @@ -66,10 +74,18 @@ without prior permission by the authors of Eressea. #include #include #include +#include +#include #include #include +#define TOLUA_PKG(NAME) extern void tolua_##NAME##_open(lua_State * L) + +TOLUA_PKG(eressea); +TOLUA_PKG(process); +TOLUA_PKG(settings); + int log_lua_error(lua_State * L) { const char *error = lua_tostring(L, -1); @@ -1016,21 +1032,6 @@ int tolua_read_xml(lua_State * L) return 0; } -int tolua_process_markets(lua_State * L) -{ - do_markets(); - return 0; -} - -int tolua_process_produce(lua_State * L) -{ - region *r; - for (r = regions; r; r = r->next) { - produce(r); - } - return 0; -} - typedef struct event_args { int hfunction; int hargs; @@ -1104,21 +1105,6 @@ static int tolua_report_unit(lua_State * L) return 1; } -static int tolua_settings_get(lua_State * L) -{ - const char *name = tolua_tostring(L, 1, 0); - tolua_pushstring(L, get_param(global.parameters, name)); - return 1; -} - -static int tolua_settings_set(lua_State * L) -{ - const char *name = tolua_tostring(L, 1, 0); - const char *value = tolua_tostring(L, 2, 0); - set_param(&global.parameters, name, value); - return 0; -} - static void parse_inifile(lua_State * L, dictionary * d, const char *section) { int i; @@ -1148,10 +1134,14 @@ static void parse_inifile(lua_State * L, dictionary * d, const char *section) lua_rawset(L, -3); } -int tolua_eressea_open(lua_State * L) +int tolua_bindings_open(lua_State * L) { tolua_open(L); + tolua_eressea_open(L); + tolua_process_open(L); + tolua_settings_open(L); + /* register user types */ tolua_usertype(L, TOLUA_CAST "spell"); tolua_usertype(L, TOLUA_CAST "spell_list"); @@ -1163,12 +1153,6 @@ int tolua_eressea_open(lua_State * L) tolua_module(L, NULL, 0); tolua_beginmodule(L, NULL); { - tolua_module(L, "process", 0); - tolua_beginmodule(L, "process"); - { - tolua_function(L, "markets", &tolua_process_markets); - tolua_function(L, "produce", &tolua_process_produce); - } tolua_endmodule(L); tolua_cclass(L, TOLUA_CAST "alliance", TOLUA_CAST "alliance", TOLUA_CAST "", NULL); tolua_beginmodule(L, TOLUA_CAST "alliance"); @@ -1198,12 +1182,6 @@ int tolua_eressea_open(lua_State * L) tolua_function(L, TOLUA_CAST "register", &tolua_eventbus_register); tolua_function(L, TOLUA_CAST "fire", &tolua_eventbus_fire); } tolua_endmodule(L); - tolua_module(L, TOLUA_CAST "settings", 1); - tolua_beginmodule(L, TOLUA_CAST "settings"); - { - tolua_function(L, TOLUA_CAST "set", &tolua_settings_set); - tolua_function(L, TOLUA_CAST "get", &tolua_settings_get); - } tolua_endmodule(L); tolua_module(L, TOLUA_CAST "report", 1); tolua_beginmodule(L, TOLUA_CAST "report"); { @@ -1279,3 +1257,94 @@ int tolua_eressea_open(lua_State * L) } tolua_endmodule(L); return 1; } + +static const struct { + const char *name; + int (*func) (lua_State *); +} lualibs[] = { + { + "", luaopen_base}, { + LUA_TABLIBNAME, luaopen_table}, { + LUA_IOLIBNAME, luaopen_io}, { + LUA_STRLIBNAME, luaopen_string}, { + LUA_MATHLIBNAME, luaopen_math}, { + LUA_LOADLIBNAME, luaopen_package}, { + LUA_DBLIBNAME, luaopen_debug}, +#if LUA_VERSION_NUM>=501 + { + LUA_OSLIBNAME, luaopen_os}, +#endif + { + NULL, NULL} +}; + +static void openlibs(lua_State * L) +{ + int i; + for (i = 0; lualibs[i].func; ++i) { + lua_pushcfunction(L, lualibs[i].func); + lua_pushstring(L, lualibs[i].name); + lua_call(L, 1, 0); + } +} + +void lua_done(lua_State * L) { + lua_close(L); +} + +lua_State *lua_init(void) { + lua_State *L = lua_open(); + + openlibs(L); +#ifdef BINDINGS_TOLUA + register_tolua_helpers(); + tolua_bindings_open(L); + tolua_eressea_open(L); + tolua_sqlite_open(L); + tolua_unit_open(L); + tolua_building_open(L); + tolua_ship_open(L); + tolua_region_open(L); + tolua_faction_open(L); +#ifdef BSON_ATTRIB + tolua_attrib_open(L); +#endif + tolua_unit_open(L); + tolua_message_open(L); + tolua_hashtable_open(L); + tolua_gmtool_open(L); + tolua_storage_open(L); +#endif + return L; +} + +int eressea_run(lua_State *L, const char *luafile, const char *entry_point) +{ + int err; + + global.vm_state = L; + /* run the main script */ + if (luafile) { + log_debug("executing script %s\n", luafile); + lua_getglobal(L, "dofile"); + lua_pushstring(L, luafile); + err = lua_pcall(L, 1, 0, 0); + if (err != 0) { + log_lua_error(L); + abort(); + return err; + } + } + if (entry_point) { + lua_getglobal(L, entry_point); + err = lua_pcall(L, 0, 1, 0); + if (err != 0) { + log_lua_error(L); + abort(); + return err; + } + } else { + err = lua_console(L); + } + return err; +} diff --git a/src/bindings/bindings.h b/src/bindings/bindings.h old mode 100644 new mode 100755 index d20e20555..1494a1d7c --- a/src/bindings/bindings.h +++ b/src/bindings/bindings.h @@ -18,7 +18,7 @@ extern "C" { struct quicklist; int tolua_sqlite_open(struct lua_State *L); - int tolua_eressea_open(struct lua_State *L); + int tolua_bindings_open(struct lua_State *L); int tolua_spelllist_next(struct lua_State *L); int tolua_itemlist_next(struct lua_State *L); int tolua_orderlist_next(struct lua_State *L); @@ -26,6 +26,11 @@ extern "C" { const char *elem_type, struct quicklist *list); int log_lua_error(struct lua_State *L); + + void lua_done(struct lua_State *L); + struct lua_State *lua_init(void); + int eressea_run(struct lua_State *L, const char *luafile, const char *entry_point); + #ifdef __cplusplus } #endif diff --git a/src/bindings/eressea.pkg b/src/bindings/eressea.pkg new file mode 100755 index 000000000..54e699520 --- /dev/null +++ b/src/bindings/eressea.pkg @@ -0,0 +1,7 @@ +$#include + +module eressea { + void eressea_free_game @ free_game(void); + int eressea_read_game @ read_game(const char * filename); + int eressea_write_game @ write_game(const char * filename); +} diff --git a/src/bindings/process.pkg b/src/bindings/process.pkg new file mode 100755 index 000000000..018d80459 --- /dev/null +++ b/src/bindings/process.pkg @@ -0,0 +1,8 @@ +$#include + +module eressea { + module process { + void process_markets @ markets(void); + void process_produce @ produce(void); + } +} diff --git a/src/bindings/settings.pkg b/src/bindings/settings.pkg new file mode 100755 index 000000000..8269dbd58 --- /dev/null +++ b/src/bindings/settings.pkg @@ -0,0 +1,8 @@ +$#include + +module eressea { + module settings { + void settings_set @ set(const char *key, const char *value); + const char * settings_get @ get(const char *key); + } +} diff --git a/src/eressea.c b/src/eressea.c old mode 100644 new mode 100755 index 50ab01485..d56fdfc9a --- a/src/eressea.c +++ b/src/eressea.c @@ -3,30 +3,8 @@ #include "eressea.h" #include -#include #include -/* lua includes */ -#ifdef BINDINGS_TOLUA -#include -#include -#include -#include -#include -#ifdef BSON_ATTRIB -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif /* BINDINGS_TOLUA */ - #if MUSEUM_MODULE #include #endif @@ -52,68 +30,7 @@ #include #include -static const struct { - const char *name; - int (*func) (lua_State *); -} lualibs[] = { - { - "", luaopen_base}, { - LUA_TABLIBNAME, luaopen_table}, { - LUA_IOLIBNAME, luaopen_io}, { - LUA_STRLIBNAME, luaopen_string}, { - LUA_MATHLIBNAME, luaopen_math}, { - LUA_LOADLIBNAME, luaopen_package}, { - LUA_DBLIBNAME, luaopen_debug}, -#if LUA_VERSION_NUM>=501 - { - LUA_OSLIBNAME, luaopen_os}, -#endif - { - NULL, NULL} -}; - -static void openlibs(lua_State * L) -{ - int i; - for (i = 0; lualibs[i].func; ++i) { - lua_pushcfunction(L, lualibs[i].func); - lua_pushstring(L, lualibs[i].name); - lua_call(L, 1, 0); - } -} - -static void lua_done(lua_State * L) -{ - lua_close(L); -} - -static lua_State *lua_init(void) -{ - lua_State *L = lua_open(); - - openlibs(L); -#ifdef BINDINGS_TOLUA - register_tolua_helpers(); - tolua_eressea_open(L); - tolua_sqlite_open(L); - tolua_unit_open(L); - tolua_building_open(L); - tolua_ship_open(L); - tolua_region_open(L); - tolua_faction_open(L); -#ifdef BSON_ATTRIB - tolua_attrib_open(L); -#endif - tolua_unit_open(L); - tolua_message_open(L); - tolua_hashtable_open(L); - tolua_gmtool_open(L); - tolua_storage_open(L); -#endif - return L; -} - -static void game_done(void) +void game_done(void) { #ifdef CLEANUP_CODE /* Diese Routine enfernt allen allokierten Speicher wieder. Das ist nur @@ -129,10 +46,12 @@ static void game_done(void) #endif calendar_cleanup(); #endif + kernel_done(); } -static void game_init(void) +void game_init(void) { + kernel_init(); register_triggers(); register_xmas(); @@ -165,48 +84,3 @@ static void game_init(void) register_gmcmd(); } - -int eressea_init(void) -{ - global.vm_state = lua_init(); - kernel_init(); - game_init(); - - return 0; -} - -void eressea_done(void) -{ - game_done(); - kernel_done(); - lua_done((lua_State *) global.vm_state); -} - -int eressea_run(const char *luafile, const char *entry_point) -{ - int err; - lua_State *L = (lua_State *) global.vm_state; - /* run the main script */ - if (luafile) { - lua_getglobal(L, "dofile"); - lua_pushstring(L, luafile); - err = lua_pcall(L, 1, 0, 0); - if (err != 0) { - log_lua_error(L); - abort(); - return err; - } - } - if (entry_point) { - lua_getglobal(L, entry_point); - err = lua_pcall(L, 0, 1, 0); - if (err != 0) { - log_lua_error(L); - abort(); - return err; - } - } else { - err = lua_console(L); - } - return err; -} diff --git a/src/eressea.h b/src/eressea.h old mode 100644 new mode 100755 index 692255a9b..3944bb090 --- a/src/eressea.h +++ b/src/eressea.h @@ -4,9 +4,8 @@ extern "C" { #endif - int eressea_init(void); - void eressea_done(void); - int eressea_run(const char *luafile, const char *entry_point); + void game_init(void); + void game_done(void); #ifdef __cplusplus } diff --git a/src/kernel/faction.c b/src/kernel/faction.c old mode 100644 new mode 100755 index 7cde125de..009922bca --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -284,19 +284,22 @@ void destroyfaction(faction * f) unit *u = f->units; faction *ff; - if (!f->alive) + if (!f->alive) { return; + } fset(f, FFL_QUIT); - spellbook_clear(f->spellbook); - free(f->spellbook); - f->spellbook = 0; - + if (f->spellbook) { + spellbook_clear(f->spellbook); + free(f->spellbook); + f->spellbook = 0; + } while (f->battles) { struct bmsg *bm = f->battles; f->battles = bm->next; - if (bm->msgs) + if (bm->msgs) { free_messagelist(bm->msgs); + } free(bm); } From d2cee21af5a83b7e9110f2c2b0e631e0dc4a9417 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 6 Jun 2012 20:33:15 -0700 Subject: [PATCH 329/400] include headers for MSVC --- .gitignore | 1 + src/CMakeLists.txt | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 48f1b84a0..f16be6bc9 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ Release/ src/*.vcproj.*.user tags build-vs2010 +config diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 72af6a1ee..f7bb33687 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -41,6 +41,8 @@ include_directories (${LIBXML2_INCLUDE_DIR}) include_directories (${BSON_INCLUDE_DIR}) include_directories (${INIPARSER_INCLUDE_DIR}) +FILE (GLOB_RECURSE LIB_HDR *.h) + set (TEST_SRC tests.c tests_test.c @@ -216,7 +218,7 @@ set (LIB_SRC util/xml.c ) -add_library(${ERESSEA_LIBRARY} ${LIB_SRC}) +add_library(${ERESSEA_LIBRARY} ${LIB_SRC} ${LIB_HDR}) target_link_libraries(${ERESSEA_LIBRARY} ${ERESSEA_LIBRARIES}) add_executable(${PROJECT_NAME}_test ${TEST_SRC}) From dafb2fc2ab76d071aee16e0b228dd18e589cec69 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 7 Jun 2012 09:47:02 -0700 Subject: [PATCH 330/400] adding a lot of test coverage extending the binding generation to more processing functions --- scripts/default.lua | 7 ++-- scripts/init.lua | 2 +- scripts/tests/bindings.lua | 28 +++++++++++++++ scripts/tests/common.lua | 12 +++---- scripts/tests/orders.lua | 72 +++++++++++++++++++++++++++++++++++++ src/bindings/bind_eressea.c | 5 +++ src/bindings/bind_eressea.h | 1 + src/bindings/bind_process.c | 61 +++++++++++++++++++++++++++++++ src/bindings/bind_process.h | 5 +++ src/bindings/bind_unit.c | 26 ++++++++++++-- src/bindings/bindings.c | 34 ------------------ src/bindings/eressea.pkg | 1 + src/bindings/process.pkg | 5 +++ src/gamecode/laws.c | 20 +++++------ src/gamecode/laws.h | 10 ++++++ src/kernel/group.c | 11 ++++++ src/kernel/group.h | 1 + 17 files changed, 242 insertions(+), 59 deletions(-) mode change 100644 => 100755 scripts/default.lua mode change 100644 => 100755 scripts/init.lua create mode 100755 scripts/tests/bindings.lua mode change 100644 => 100755 src/bindings/bind_unit.c mode change 100644 => 100755 src/gamecode/laws.c mode change 100644 => 100755 src/gamecode/laws.h mode change 100644 => 100755 src/kernel/group.c mode change 100644 => 100755 src/kernel/group.h diff --git a/scripts/default.lua b/scripts/default.lua old mode 100644 new mode 100755 index 9b5e4c8a6..6d22b4f32 --- a/scripts/default.lua +++ b/scripts/default.lua @@ -26,7 +26,7 @@ function nmr_check(maxnmrs) if nmrs >= maxnmrs then print("Shit. More than " .. maxnmrs .. " factions with 1 NMR (" .. nmrs .. ")") write_summary() - write_game("aborted.dat") + eressea.write_game("aborted.dat") return -1 end print (nmrs .. " Factions with 1 NMR") @@ -35,10 +35,7 @@ end function open_game(turn) file = "" .. get_turn() - if read_game(file .. ".dat", "binary")~=0 then - return read_game(file, "text") - end - return 0 + return eressea.read_game(file .. ".dat") end function write_emails(locales) diff --git a/scripts/init.lua b/scripts/init.lua old mode 100644 new mode 100755 index ae39c50b2..bafa3da63 --- a/scripts/init.lua +++ b/scripts/init.lua @@ -8,7 +8,7 @@ function run_editor() turn = read_turn() set_turn(turn) end - read_game(turn .. ".dat") + eressea.read_game(turn .. ".dat") gmtool.editor() end diff --git a/scripts/tests/bindings.lua b/scripts/tests/bindings.lua new file mode 100755 index 000000000..90be5e1a9 --- /dev/null +++ b/scripts/tests/bindings.lua @@ -0,0 +1,28 @@ +require "lunit" + +local eressea = eressea +local _G = _G + +module("tests.bindings", lunit.testcase) + +function test_eressea() + assert_equal("function", _G.type(eressea.free_game)) + assert_equal("function", _G.type(eressea.read_game)) + assert_equal("function", _G.type(eressea.write_game)) + assert_equal("function", _G.type(eressea.read_orders)) +end + +function test_process() + assert_equal("function", _G.type(eressea.process.markets)) + assert_equal("function", _G.type(eressea.process.produce)) + assert_equal("function", _G.type(eressea.process.make_temp)) + assert_equal("function", _G.type(eressea.process.settings)) + assert_equal("function", _G.type(eressea.process.set_group)) + assert_equal("function", _G.type(eressea.process.set_origin)) + assert_equal("function", _G.type(eressea.process.quit)) +end + +function test_settings() + assert_equal("function", _G.type(eressea.settings.set)) + assert_equal("function", _G.type(eressea.settings.get)) +end diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 95984b443..b1b69c211 100755 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -912,7 +912,7 @@ function test_parser() file:write("BENENNEN EINHEIT 'Goldene Herde'\n") file:close() - read_orders(filename) + eressea.read_orders(filename) process_orders() assert_equal("Goldene Herde", u.name) end @@ -975,7 +975,7 @@ function test_bug_1814() file:write("; ARBEITE\n") file:close() - read_orders(filename) + eressea.read_orders(filename) process_orders() init_reports() write_report(f) @@ -996,7 +996,7 @@ function test_bug_1679() file:write("ARBEITEN\n") file:close() - read_orders(filename) + eressea.read_orders(filename) process_orders() init_reports() write_report(f) @@ -1103,7 +1103,7 @@ function test_bug_1875_use_normal() local r = region.create(0, 0, "plain") r:set_resource("peasant", 0) - settings.set("rules.economy.food", "0") -- food is not free + eressea.settings.set("rules.economy.food", "0") -- food is not free local f = faction.create("noreply@eressea.de", "demon", "de") local u = unit.create(f, r, 1) @@ -1126,7 +1126,7 @@ function test_bug_1875_use_help() local r = region.create(0, 0, "plain") r:set_resource("peasant", 0) - settings.set("rules.economy.food", "0") -- food is not free + eressea.settings.set("rules.economy.food", "0") -- food is not free local f = faction.create("noreply@eressea.de", "demon", "de") local u = unit.create(f, r, 1) @@ -1153,7 +1153,7 @@ function test_bug_1875_use_own_first() local r = region.create(0, 0, "plain") r:set_resource("peasant", 0) - settings.set("rules.economy.food", "0") -- food is not free + eressea.settings.set("rules.economy.food", "0") -- food is not free local f = faction.create("noreply@eressea.de", "demon", "de") local u = unit.create(f, r, 1) diff --git a/scripts/tests/orders.lua b/scripts/tests/orders.lua index 0fe64429a..2fc1e5b77 100755 --- a/scripts/tests/orders.lua +++ b/scripts/tests/orders.lua @@ -33,3 +33,75 @@ function test_give() assert_not_equal(5, u:get_item("money")) assert_not_equal(5, u2:get_item("money")) end + +function test_make_temp() + u:add_order("MACHE TEMP 123 'Herpderp'") + u:add_order("// this comment will be copied") + u:add_order("ENDE") + eressea.process.make_temp() + + for x in f.units do + if x.name == 'Herpderp' then u=x end + end + assert_equal('Herpderp', u.name) + assert_equal(0, u.number) + local c = 0 + for o in u.orders do + assert_equal('// this comment will be copied', o) + c = c + 1 + end + assert_equal(1, c) +end + +function test_give_temp() + u.number = 2 + u:add_order("GIB TEMP 123 1 PERSON") + u:add_order("MACHE TEMP 123 'Herpderp'") + u:add_order("ENDE") + _G.process_orders() + assert_equal(1, u.number) + + for x in f.units do + if x.name == 'Herpderp' then u=x end + end + assert_equal('Herpderp', u.name) + assert_equal(1, u.number) +end + +function test_process_settings() + f.options = 0 + u:add_order("EMAIL herp@derp.com") + u:add_order("BANNER 'Herpderp'") + u:add_order("PASSWORT 'HerpDerp'") + u:add_order("OPTION AUSWERTUNG") + eressea.process.settings() + assert_equal("herp@derp.com", f.email) + assert_equal("Herpderp", f.info) + assert_equal("HerpDerp", f.password) + assert_equal(1, f.options) +end + +function test_process_group() + u:add_order("GRUPPE herp") + eressea.process.set_group() + assert_equal('herp', u.group) +end + +function test_process_origin() + u:add_order("URSPRUNG 1 2") + eressea.process.set_origin() + x, y = u.faction:get_origin() + assert_equal(1, x) + assert_equal(2, y) +end + +function test_process_quit() + fno = f.id + u:add_order("STIRB '" .. u.faction.password .. "'") + assert_not_equal(nil, _G.get_faction(fno)) + eressea.process.quit() + eressea.write_game('test.dat') + eressea.free_game() + eressea.read_game('test.dat') + assert_equal(nil, _G.get_faction(fno)) +end diff --git a/src/bindings/bind_eressea.c b/src/bindings/bind_eressea.c index 51c0537d3..1972bd0b1 100755 --- a/src/bindings/bind_eressea.c +++ b/src/bindings/bind_eressea.c @@ -15,5 +15,10 @@ int eressea_read_game(const char * filename) { } int eressea_write_game(const char * filename) { + remove_empty_factions(); return writegame(filename, IO_BINARY); } + +int eressea_read_orders(const char * filename) { + return readorders(filename); +} diff --git a/src/bindings/bind_eressea.h b/src/bindings/bind_eressea.h index c50683765..f8ba00d8c 100755 --- a/src/bindings/bind_eressea.h +++ b/src/bindings/bind_eressea.h @@ -7,6 +7,7 @@ extern "C" { void eressea_free_game(void); int eressea_read_game(const char * filename); int eressea_write_game(const char * filename); +int eressea_read_orders(const char * filename); #ifdef __cplusplus } diff --git a/src/bindings/bind_process.c b/src/bindings/bind_process.c index 5a344c1c4..4b68bc7bd 100755 --- a/src/bindings/bind_process.c +++ b/src/bindings/bind_process.c @@ -2,8 +2,11 @@ #include #include +#include #include +#include #include +#include #include void process_produce(void) { @@ -16,3 +19,61 @@ void process_produce(void) { void process_markets(void) { do_markets(); } + +void process_make_temp(void) { + new_units(); +} + +void process_settings(void) { + region * r; + for (r=regions; r; r=r->next) { + unit * u; + for (u=r->units; u; u=u->next) { + order * ord; + for (ord=u->orders; ord; ord=ord->next) { + keyword_t kwd = get_keyword(ord); + if (kwd==K_BANNER) { + banner_cmd(u, ord); + } + else if (kwd==K_EMAIL) { + email_cmd(u, ord); + } + else if (kwd==K_SEND) { + send_cmd(u, ord); + } + else if (kwd==K_PASSWORD) { + password_cmd(u, ord); + } + } + } + } +} + +static void process_cmd(keyword_t kwd, int (*callback)(unit *, order *)) +{ + region * r; + for (r=regions; r; r=r->next) { + unit * u; + for (u=r->units; u; u=u->next) { + order * ord; + for (ord=u->orders; ord; ord=ord->next) { + if (kwd == get_keyword(ord)) { + callback(u, ord); + } + } + } + } +} + +void process_group(void) { + process_cmd(K_GROUP, group_cmd); +} + +void process_origin(void) { + process_cmd(K_URSPRUNG, origin_cmd); +} + +void process_quit(void) { + process_cmd(K_QUIT, quit_cmd); + quit(); +} diff --git a/src/bindings/bind_process.h b/src/bindings/bind_process.h index c7c7cab64..bd42c63a1 100755 --- a/src/bindings/bind_process.h +++ b/src/bindings/bind_process.h @@ -6,6 +6,11 @@ extern "C" { void process_produce(void); void process_markets(void); +void process_make_temp(void); +void process_settings(void); +void process_group(void); +void process_origin(void); +void process_quit(void); #ifdef __cplusplus } diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c old mode 100644 new mode 100755 index afa42389b..543a9f9d5 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -28,6 +28,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include #include #include #include @@ -141,6 +142,25 @@ int tolua_unitlist_next(lua_State * L) return 0; /* no more values to return */ } +static int tolua_unit_get_group(lua_State * L) +{ + unit *u = (unit *) tolua_tousertype(L, 1, 0); + group *g = get_group(u); + if (g) { + tolua_pushstring(L, g->name); + return 1; + } + return 0; +} + +static int tolua_unit_set_group(lua_State * L) +{ + unit *self = (unit *) tolua_tousertype(L, 1, 0); + int result = join_group(self, tolua_tostring(L, 2, 0)); + tolua_pushnumber(L, result); + return 1; +} + static int tolua_unit_get_name(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); @@ -936,9 +956,9 @@ void tolua_unit_open(lua_State * L) tolua_unit_set_name); tolua_variable(L, TOLUA_CAST "faction", &tolua_unit_get_faction, tolua_unit_set_faction); - tolua_variable(L, TOLUA_CAST "id", &tolua_unit_get_id, tolua_unit_set_id); - tolua_variable(L, TOLUA_CAST "info", &tolua_unit_get_info, - tolua_unit_set_info); + tolua_variable(L, TOLUA_CAST "id", tolua_unit_get_id, tolua_unit_set_id); + tolua_variable(L, TOLUA_CAST "group", tolua_unit_get_group, tolua_unit_set_group); + tolua_variable(L, TOLUA_CAST "info", tolua_unit_get_info, tolua_unit_set_info); tolua_variable(L, TOLUA_CAST "hp", &tolua_unit_get_hp, tolua_unit_set_hp); tolua_variable(L, TOLUA_CAST "status", &tolua_unit_get_status, tolua_unit_set_status); diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index 0ec0bd9f7..ea86df4a0 100755 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -540,12 +540,6 @@ static int tolua_write_summary(lua_State * L) return 0; } -static int tolua_free_game(lua_State * L) -{ - free_gamedata(); - return 0; -} - static int tolua_write_map(lua_State * L) { const char *filename = tolua_tostring(L, 1, 0); @@ -555,31 +549,6 @@ static int tolua_write_map(lua_State * L) return 0; } -static int tolua_write_game(lua_State * L) -{ - const char *filename = tolua_tostring(L, 1, 0); - const char *mode = tolua_tostring(L, 2, 0); - int result, m = IO_BINARY; - if (mode && strcmp(mode, "text") == 0) - m = IO_TEXT; - remove_empty_factions(); - result = writegame(filename, m); - tolua_pushnumber(L, (lua_Number) result); - return 1; -} - -static int tolua_read_game(lua_State * L) -{ - const char *filename = tolua_tostring(L, 1, 0); - const char *mode = tolua_tostring(L, 2, 0); - int rv, m = IO_BINARY; - if (mode && strcmp(mode, "text") == 0) - m = IO_TEXT; - rv = readgame(filename, m, false); - tolua_pushnumber(L, (lua_Number) rv); - return 1; -} - static int tolua_read_turn(lua_State * L) { int cturn = current_turn(); @@ -1208,9 +1177,6 @@ int tolua_bindings_open(lua_State * L) tolua_function(L, TOLUA_CAST "factions", tolua_get_factions); tolua_function(L, TOLUA_CAST "regions", tolua_get_regions); tolua_function(L, TOLUA_CAST "read_turn", tolua_read_turn); - tolua_function(L, TOLUA_CAST "read_game", tolua_read_game); - tolua_function(L, TOLUA_CAST "write_game", tolua_write_game); - tolua_function(L, TOLUA_CAST "free_game", tolua_free_game); tolua_function(L, TOLUA_CAST "write_map", &tolua_write_map); tolua_function(L, TOLUA_CAST "read_orders", tolua_read_orders); tolua_function(L, TOLUA_CAST "process_orders", tolua_process_orders); diff --git a/src/bindings/eressea.pkg b/src/bindings/eressea.pkg index 54e699520..78740c485 100755 --- a/src/bindings/eressea.pkg +++ b/src/bindings/eressea.pkg @@ -4,4 +4,5 @@ module eressea { void eressea_free_game @ free_game(void); int eressea_read_game @ read_game(const char * filename); int eressea_write_game @ write_game(const char * filename); + int eressea_read_orders @ read_orders(const char * filename); } diff --git a/src/bindings/process.pkg b/src/bindings/process.pkg index 018d80459..662536caf 100755 --- a/src/bindings/process.pkg +++ b/src/bindings/process.pkg @@ -4,5 +4,10 @@ module eressea { module process { void process_markets @ markets(void); void process_produce @ produce(void); + void process_make_temp @ make_temp(void); + void process_settings @ settings(void); + void process_group @ set_group(void); + void process_origin @ set_origin(void); + void process_quit @ quit(void); } } diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c old mode 100644 new mode 100755 index 69e7efc45..fee370335 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -1117,7 +1117,7 @@ static boolean EnhancedQuit(void) return value; } -static int quit_cmd(unit * u, struct order *ord) +int quit_cmd(unit * u, struct order *ord) { faction *f = u->faction; const char *passwd; @@ -1159,7 +1159,7 @@ static int quit_cmd(unit * u, struct order *ord) return 0; } -static void quit(void) +void quit(void) { faction **fptr = &factions; while (*fptr) { @@ -2107,7 +2107,7 @@ static int mail_cmd(unit * u, struct order *ord) /* ------------------------------------------------------------- */ -static int banner_cmd(unit * u, struct order *ord) +int banner_cmd(unit * u, struct order *ord) { init_tokens(ord); skip_token(); @@ -2120,7 +2120,7 @@ static int banner_cmd(unit * u, struct order *ord) return 0; } -static int email_cmd(unit * u, struct order *ord) +int email_cmd(unit * u, struct order *ord) { const char *s; @@ -2142,7 +2142,7 @@ static int email_cmd(unit * u, struct order *ord) return 0; } -static int password_cmd(unit * u, struct order *ord) +int password_cmd(unit * u, struct order *ord) { char pwbuf[32]; int i; @@ -2182,7 +2182,7 @@ static int password_cmd(unit * u, struct order *ord) return 0; } -static int send_cmd(unit * u, struct order *ord) +int send_cmd(unit * u, struct order *ord) { const char *s; int option; @@ -2516,7 +2516,7 @@ static int promotion_cmd(unit * u, struct order *ord) return 0; } -static int group_cmd(unit * u, struct order *ord) +int group_cmd(unit * u, struct order *ord) { const char *s; @@ -2528,7 +2528,7 @@ static int group_cmd(unit * u, struct order *ord) return 0; } -static int origin_cmd(unit * u, struct order *ord) +int origin_cmd(unit * u, struct order *ord) { short px, py; @@ -3291,7 +3291,7 @@ int checkunitnumber(const faction * f, int add) return 0; } -static void new_units(void) +void new_units(void) { region *r; unit *u, *u2; @@ -4154,7 +4154,7 @@ void init_processor(void) p += 10; add_proc_unit(p, &setdefaults, "Default-Befehle"); - add_proc_order(p, K_BANNER, &banner_cmd, 0, NULL); + add_proc_order(p, K_BANNER, banner_cmd, 0, NULL); add_proc_order(p, K_EMAIL, &email_cmd, 0, NULL); add_proc_order(p, K_PASSWORD, &password_cmd, 0, NULL); add_proc_order(p, K_SEND, &send_cmd, 0, NULL); diff --git a/src/gamecode/laws.h b/src/gamecode/laws.h old mode 100644 new mode 100755 index 2ea50b8eb..228c84b6a --- a/src/gamecode/laws.h +++ b/src/gamecode/laws.h @@ -45,6 +45,16 @@ extern "C" { extern int dropouts[2]; extern int *age; + extern void new_units(void); + extern void quit(void); + extern int password_cmd(struct unit *u, struct order *ord); + extern int banner_cmd(struct unit *u, struct order *ord); + extern int email_cmd(struct unit *u, struct order *ord); + extern int send_cmd(struct unit *u, struct order *ord); + extern int origin_cmd(struct unit *u, struct order *ord); + extern int group_cmd(struct unit *u, struct order *ord); + extern int quit_cmd(struct unit *u, struct order *ord); + #ifdef __cplusplus } #endif diff --git a/src/kernel/group.c b/src/kernel/group.c old mode 100644 new mode 100755 index c61966968..a0b5821c5 --- a/src/kernel/group.c +++ b/src/kernel/group.c @@ -136,6 +136,17 @@ void free_group(group * g) free(g); } +group * get_group(const struct unit *u) +{ + if (fval(u, UFL_GROUP)) { + attrib * a = a_find(u->attribs, &at_group); + if (a) { + return (group *) a->data.v; + } + } + return 0; +} + void set_group(struct unit *u, struct group *g) { attrib *a = NULL; diff --git a/src/kernel/group.h b/src/kernel/group.h old mode 100644 new mode 100755 index bccbf4540..14dd119cd --- a/src/kernel/group.h +++ b/src/kernel/group.h @@ -40,6 +40,7 @@ extern "C" { extern struct attrib_type at_group; /* attribute for units assigned to a group */ extern boolean join_group(struct unit *u, const char *name); extern void set_group(struct unit *u, struct group *g); + extern struct group * get_group(const struct unit *u); extern void free_group(struct group *g); extern void write_groups(struct storage *F, struct group *g); From e23016f0f0ee2545a86697bf50ad91499502bb26 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 7 Jun 2012 12:26:27 -0700 Subject: [PATCH 331/400] killing old MSVC project files --- src/gamecode.vcxproj | 135 ------- src/gamecode.vcxproj.filters | 134 ------- src/kernel.vcxproj | 297 --------------- src/kernel.vcxproj.filters | 625 ------------------------------- src/lua-bindings.vcxproj | 121 ------ src/lua-bindings.vcxproj.filters | 92 ----- src/util.vcxproj | 162 -------- src/util.vcxproj.filters | 215 ----------- 8 files changed, 1781 deletions(-) delete mode 100644 src/gamecode.vcxproj delete mode 100644 src/gamecode.vcxproj.filters delete mode 100644 src/kernel.vcxproj delete mode 100644 src/kernel.vcxproj.filters delete mode 100644 src/lua-bindings.vcxproj delete mode 100644 src/lua-bindings.vcxproj.filters delete mode 100644 src/util.vcxproj delete mode 100644 src/util.vcxproj.filters diff --git a/src/gamecode.vcxproj b/src/gamecode.vcxproj deleted file mode 100644 index e9cd8c4be..000000000 --- a/src/gamecode.vcxproj +++ /dev/null @@ -1,135 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {1E8BFF9E-3044-0742-992F-C5765B80FE65} - gamecode - Win32Proj - - - - StaticLibrary - MultiByte - - - StaticLibrary - MultiByte - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - - - - /MP %(AdditionalOptions) - Disabled - .;../../external;../../external/lua/src;../../external/tolua/include;..\..\external\pdcurses;..\..\external\libxml2\include;%(AdditionalIncludeDirectories) - WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebugDLL - true - - - Level4 - true - EditAndContinue - - - WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - ..;.;%(AdditionalIncludeDirectories) - - - $(OutDir)gamecode.lib - - - - - Full - .;../../external;../../external/lua/src;../../external/tolua/include;..\..\external\pdcurses;..\..\external\libxml2\include;%(AdditionalIncludeDirectories) - WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) - true - MultiThreadedDLL - true - - - Level4 - - - - - WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) - ..;.;%(AdditionalIncludeDirectories) - - - $(OutDir)gamecode.lib - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/gamecode.vcxproj.filters b/src/gamecode.vcxproj.filters deleted file mode 100644 index 176c488c8..000000000 --- a/src/gamecode.vcxproj.filters +++ /dev/null @@ -1,134 +0,0 @@ - - - - - {d83e7c3e-0495-4145-86ea-a86b7d4d405b} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {7553a025-8a64-4b5a-90cb-a2eeae9190d3} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/src/kernel.vcxproj b/src/kernel.vcxproj deleted file mode 100644 index 24d6df48b..000000000 --- a/src/kernel.vcxproj +++ /dev/null @@ -1,297 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {6F104C0A-DDF5-A34B-A89C-0DC278DCEF6D} - kernel - Win32Proj - - - - StaticLibrary - MultiByte - - - StaticLibrary - MultiByte - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - - - - /MP %(AdditionalOptions) - Disabled - .;..\..\external;..\..\external\libxml2\include;%(AdditionalIncludeDirectories) - WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebugDLL - true - - - Level4 - true - EditAndContinue - - - WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - ..;.;%(AdditionalIncludeDirectories) - - - $(OutDir)kernel.lib - - - - - Full - .;..\..\external;..\..\external\libxml2\include;%(AdditionalIncludeDirectories) - WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) - true - MultiThreadedDLL - true - - - Level4 - - - - - WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) - ..;.;%(AdditionalIncludeDirectories) - - - $(OutDir)kernel.lib - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/kernel.vcxproj.filters b/src/kernel.vcxproj.filters deleted file mode 100644 index c75975ed2..000000000 --- a/src/kernel.vcxproj.filters +++ /dev/null @@ -1,625 +0,0 @@ - - - - - {0d7b749c-a7f2-4791-b356-6ae450020131} - - - {0ebbe376-a35f-44f6-97c6-9b449a839ddb} - - - {0f293992-e32e-49fb-a5f2-74686b0d042e} - - - {e12969f3-9de3-4f65-812d-1e120875a15c} - - - {c10dd4f8-3a6a-470b-8a04-bb652854e228} - - - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - items - - - items - - - items - - - items - - - items - - - items - - - items - - - items - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - kernel - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - triggers - - - items - - - items - - - items - - - items - - - items - - - items - - - items - - - items - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - modules - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - attributes - - - kernel - - - \ No newline at end of file diff --git a/src/lua-bindings.vcxproj b/src/lua-bindings.vcxproj deleted file mode 100644 index 5714a1cbd..000000000 --- a/src/lua-bindings.vcxproj +++ /dev/null @@ -1,121 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {75501170-51C2-E641-BA8B-EDC008184192} - lua-bindings - Win32Proj - - - - StaticLibrary - MultiByte - - - StaticLibrary - MultiByte - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - - - - /MP %(AdditionalOptions) - Disabled - .;../../external;../../external/lua/src;../../external/tolua/include;..\..\external\pdcurses;..\..\external\libxml2\include;%(AdditionalIncludeDirectories) - WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebugDLL - true - - - Level4 - true - EditAndContinue - - - WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - .;%(AdditionalIncludeDirectories) - - - $(OutDir)lua-bindings.lib - - - - - Full - .;../../external;../../external/lua/src;../../external/tolua/include;..\..\external\pdcurses;..\..\external\libxml2\include;%(AdditionalIncludeDirectories) - WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) - true - MultiThreadedDLL - true - - - Level4 - - - - - WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) - .;%(AdditionalIncludeDirectories) - - - $(OutDir)lua-bindings.lib - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/lua-bindings.vcxproj.filters b/src/lua-bindings.vcxproj.filters deleted file mode 100644 index 83b65c358..000000000 --- a/src/lua-bindings.vcxproj.filters +++ /dev/null @@ -1,92 +0,0 @@ - - - - - {1a17299b-610f-40df-864f-84b37b67ebe7} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {5135c52b-b087-4aab-8d89-2b06da54e8e7} - h;hpp;hxx;hm;inl;inc;xsd - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/src/util.vcxproj b/src/util.vcxproj deleted file mode 100644 index a0967f595..000000000 --- a/src/util.vcxproj +++ /dev/null @@ -1,162 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {F70CFB27-8A2F-E447-B452-4E1C590EDA6D} - util - Win32Proj - - - - StaticLibrary - MultiByte - - - StaticLibrary - MultiByte - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - $(Configuration)\$(ProjectName)\ - - - - /MP %(AdditionalOptions) - Disabled - .;../../external;../../external/lua/src;../../external/pdcurses;..\..\external\libxml2\include;%(AdditionalIncludeDirectories) - WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebugDLL - true - - - Level4 - true - EditAndContinue - - - WIN32;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) - ..;.;%(AdditionalIncludeDirectories) - - - $(OutDir)util.lib - - - - - Full - .;../../external;../../external/lua/src;../../external/pdcurses;..\..\external\libxml2\include;%(AdditionalIncludeDirectories) - WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) - true - MultiThreadedDLL - true - - - Level4 - - - - - WIN32;_CRT_SECURE_NO_DEPRECATE;NDEBUG;%(PreprocessorDefinitions) - ..;.;%(AdditionalIncludeDirectories) - - - $(OutDir)util.lib - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/util.vcxproj.filters b/src/util.vcxproj.filters deleted file mode 100644 index 43fb1d700..000000000 --- a/src/util.vcxproj.filters +++ /dev/null @@ -1,215 +0,0 @@ - - - - - {93caffaa-508e-4e78-b1ba-5a8d6aa4ab9a} - h;hpp;hxx;hm;inl;inc;xsd - - - {77dd9146-7564-475b-a364-b1610046b1bb} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Header Files - - - Source Files - - - Source Files - - - Source Files - - - \ No newline at end of file From 457c111da2ffda54ac1ff3e7758f5ba0ccc5bc26 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 7 Jun 2012 12:43:37 -0700 Subject: [PATCH 332/400] order of commands needs to be altered so bindings get the correct include directory. --- src/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 916850f56..6f0c4e115 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,8 +1,6 @@ cmake_minimum_required(VERSION 2.6) project (eressea C) -add_subdirectory(bindings) - IF(CMAKE_COMPILER_IS_GNUCC) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic -Wall -Werror -Wno-unknown-pragmas -Wstrict-prototypes -Wpointer-arith -Wno-char-subscripts -Wno-long-long") ELSE(CMAKE_COMPILER_IS_GNUCC) @@ -12,6 +10,8 @@ ENDIF(CMAKE_COMPILER_IS_GNUCC) set (ERESSEA_LIBRARY ${PROJECT_NAME} CACHE INTERNAL "Eressea Core Library") set (ERESSEA_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "Eressea Core headers") +add_subdirectory(bindings) + find_package (Lua51 REQUIRED) find_package (ToLua REQUIRED) find_package (LibXml2 REQUIRED) From 6aa08b60fd54e3b436768501239d24ec3d122c06 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 10 Jun 2012 05:28:19 -0700 Subject: [PATCH 333/400] more process-related bindings and tests --- scripts/tests/bindings.lua | 7 +++++++ src/bindings/bind_process.c | 30 ++++++++++++++++++++++++++++++ src/bindings/bind_process.h | 7 +++++++ src/bindings/process.pkg | 24 +++++++++++++++--------- src/gamecode/laws.c | 16 ++++++++-------- src/gamecode/laws.h | 11 +++++++++-- 6 files changed, 76 insertions(+), 19 deletions(-) diff --git a/scripts/tests/bindings.lua b/scripts/tests/bindings.lua index 90be5e1a9..eb81b21f6 100755 --- a/scripts/tests/bindings.lua +++ b/scripts/tests/bindings.lua @@ -13,10 +13,17 @@ function test_eressea() end function test_process() + assert_equal("function", _G.type(eressea.process.update_long_order)) assert_equal("function", _G.type(eressea.process.markets)) assert_equal("function", _G.type(eressea.process.produce)) + assert_equal("function", _G.type(eressea.process.make_temp)) assert_equal("function", _G.type(eressea.process.settings)) + assert_equal("function", _G.type(eressea.process.set_allies)) + assert_equal("function", _G.type(eressea.process.set_prefix)) + assert_equal("function", _G.type(eressea.process.set_stealth)) + assert_equal("function", _G.type(eressea.process.set_status)) + assert_equal("function", _G.type(eressea.process.set_description)) assert_equal("function", _G.type(eressea.process.set_group)) assert_equal("function", _G.type(eressea.process.set_origin)) assert_equal("function", _G.type(eressea.process.quit)) diff --git a/src/bindings/bind_process.c b/src/bindings/bind_process.c index 4b68bc7bd..105a68480 100755 --- a/src/bindings/bind_process.c +++ b/src/bindings/bind_process.c @@ -16,6 +16,16 @@ void process_produce(void) { } } +void process_update_long_order(void) { + region * r; + for (r=regions; r; r=r->next) { + unit * u; + for (u=r->units; u; u=u->next) { + update_long_order(u); + } + } +} + void process_markets(void) { do_markets(); } @@ -65,6 +75,26 @@ static void process_cmd(keyword_t kwd, int (*callback)(unit *, order *)) } } +void process_ally(void) { + process_cmd(K_ALLY, ally_cmd); +} + +void process_prefix(void) { + process_cmd(K_PREFIX, prefix_cmd); +} + +void process_setstealth(void) { + process_cmd(K_SETSTEALTH, setstealth_cmd); +} + +void process_status(void) { + process_cmd(K_STATUS, status_cmd); +} + +void process_display(void) { + process_cmd(K_DISPLAY, display_cmd); +} + void process_group(void) { process_cmd(K_GROUP, group_cmd); } diff --git a/src/bindings/bind_process.h b/src/bindings/bind_process.h index bd42c63a1..2cd754135 100755 --- a/src/bindings/bind_process.h +++ b/src/bindings/bind_process.h @@ -6,8 +6,15 @@ extern "C" { void process_produce(void); void process_markets(void); +void process_update_long_order(void); + void process_make_temp(void); void process_settings(void); +void process_ally(void); +void process_prefix(void); +void process_setstealth(void); +void process_status(void); +void process_display(void); void process_group(void); void process_origin(void); void process_quit(void); diff --git a/src/bindings/process.pkg b/src/bindings/process.pkg index 662536caf..37086e1cf 100755 --- a/src/bindings/process.pkg +++ b/src/bindings/process.pkg @@ -1,13 +1,19 @@ $#include module eressea { - module process { - void process_markets @ markets(void); - void process_produce @ produce(void); - void process_make_temp @ make_temp(void); - void process_settings @ settings(void); - void process_group @ set_group(void); - void process_origin @ set_origin(void); - void process_quit @ quit(void); - } + module process { + void process_update_long_order @ update_long_order(void); + void process_markets @ markets(void); /* operate the e3 markets */ + void process_produce @ produce(void); /* BUY/SELL/ENTERTAIN/WORK/TAX/STEAL/SPY/SABOTAGE/PLANT/BREED/RESEARCH */ + void process_make_temp @ make_temp(void); /* MAKE TEMP */ + void process_settings @ settings(void); /* EMAIL/PASSWORD/BANNER/OPTION */ + void process_ally @ set_allies(void); /* HELP */ + void process_prefix @ set_prefix(void); /* PREFIX */ + void process_setstealth @ set_stealth(void); /* STEALTH */ + void process_status @ set_status(void); /* STATUS */ + void process_display @ set_description(void); /* DESCRIBE */ + void process_group @ set_group(void); /* GROUP */ + void process_origin @ set_origin(void); /* ORIGIN */ + void process_quit @ quit(void); /* QUIT */ + } } diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index fee370335..4ad866a11 100755 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -1306,7 +1306,7 @@ static void parse_restart(void) /* HELFE partei [] [NICHT] */ -static int ally_cmd(unit * u, struct order *ord) +int ally_cmd(unit * u, struct order *ord) { ally *sf, **sfp; faction *f; @@ -1461,7 +1461,7 @@ static void init_prefixnames(void) } } -static int prefix_cmd(unit * u, struct order *ord) +int prefix_cmd(unit * u, struct order *ord) { attrib **ap; const char *s; @@ -1523,7 +1523,7 @@ static cmp_building_cb get_cmp_region_owner(void) } } -static int display_cmd(unit * u, struct order *ord) +int display_cmd(unit * u, struct order *ord) { char **s = NULL; const char *str; @@ -1689,7 +1689,7 @@ rename_building(unit * u, order * ord, building * b, const char *name) return rename_cmd(u, ord, &b->name, name); } -static int name_cmd(unit * u, struct order *ord) +int name_cmd(struct unit *u, struct order *ord) { building *b = u->building; region *r = u->region; @@ -2572,7 +2572,7 @@ static int reshow_cmd(unit * u, struct order *ord) return 0; } -static int status_cmd(unit * u, struct order *ord) +int status_cmd(unit * u, struct order *ord) { const char *param; @@ -3429,7 +3429,7 @@ void check_long_orders(unit * u) } } -static void setdefaults(unit * u) +void update_long_order(unit * u) { order *ord; boolean trade = false; @@ -4043,7 +4043,7 @@ void process(void) cmistake(u, ord, 224, MSG_MAGIC); ord = NULL; } else if (fval(u, UFL_LONGACTION)) { - /* this message was already given in laws.setdefaults + /* this message was already given in laws.update_long_order cmistake(u, ord, 52, MSG_PRODUCE); */ ord = NULL; @@ -4153,7 +4153,7 @@ void init_processor(void) add_proc_global(p, &new_units, "Neue Einheiten erschaffen"); p += 10; - add_proc_unit(p, &setdefaults, "Default-Befehle"); + add_proc_unit(p, update_long_order, "Langen Befehl aktualisieren"); add_proc_order(p, K_BANNER, banner_cmd, 0, NULL); add_proc_order(p, K_EMAIL, &email_cmd, 0, NULL); add_proc_order(p, K_PASSWORD, &password_cmd, 0, NULL); diff --git a/src/gamecode/laws.h b/src/gamecode/laws.h index 228c84b6a..2d9cc2ce7 100755 --- a/src/gamecode/laws.h +++ b/src/gamecode/laws.h @@ -47,14 +47,21 @@ extern "C" { extern void new_units(void); extern void quit(void); + extern void update_long_order(struct unit * u); extern int password_cmd(struct unit *u, struct order *ord); extern int banner_cmd(struct unit *u, struct order *ord); extern int email_cmd(struct unit *u, struct order *ord); extern int send_cmd(struct unit *u, struct order *ord); - extern int origin_cmd(struct unit *u, struct order *ord); + extern int ally_cmd(struct unit* u, struct order *ord); + extern int prefix_cmd(struct unit *u, struct order *ord); + extern int setstealth_cmd(struct unit *u, struct order *ord); + extern int status_cmd(struct unit *u, struct order *ord); + extern int display_cmd(struct unit *u, struct order *ord); extern int group_cmd(struct unit *u, struct order *ord); + extern int origin_cmd(struct unit *u, struct order *ord); extern int quit_cmd(struct unit *u, struct order *ord); - + extern int name_cmd(struct unit *u, struct order *ord); + #ifdef __cplusplus } #endif From 77575bad896a20a5f80cc883c3b4bc57c28204de Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 11 Jun 2012 22:24:50 -0700 Subject: [PATCH 334/400] remove bson dependency --- src/CMakeLists.txt | 2 -- src/bindings/CMakeLists.txt | 1 - 2 files changed, 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6f0c4e115..c4ae79c8d 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -19,7 +19,6 @@ find_package (Curses REQUIRED) find_package (SQLite3 REQUIRED) set (ERESSEA_LIBRARIES - ${BSON_LIBRARIES} ${CUTEST_LIBRARIES} ${CRITBIT_LIBRARIES} ${QUICKLIST_LIBRARIES} @@ -40,7 +39,6 @@ include_directories (${CUTEST_INCLUDE_DIR}) include_directories (${LUA_INCLUDE_DIR}) include_directories (${TOLUA_INCLUDE_DIR}) include_directories (${LIBXML2_INCLUDE_DIR}) -include_directories (${BSON_INCLUDE_DIR}) include_directories (${INIPARSER_INCLUDE_DIR}) FILE (GLOB_RECURSE LIB_HDR *.h) diff --git a/src/bindings/CMakeLists.txt b/src/bindings/CMakeLists.txt index 821238b20..94efddcb2 100755 --- a/src/bindings/CMakeLists.txt +++ b/src/bindings/CMakeLists.txt @@ -23,7 +23,6 @@ include_directories (${CUTEST_INCLUDE_DIR}) include_directories (${LUA_INCLUDE_DIR}) include_directories (${TOLUA_INCLUDE_DIR}) include_directories (${LIBXML2_INCLUDE_DIR}) -include_directories (${BSON_INCLUDE_DIR}) include_directories (${INIPARSER_INCLUDE_DIR}) FILE (GLOB_RECURSE LIB_HDR *.h) From d38c5f5cfb2249427b9f2a3e15dc8ba27bb7f0d4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 12 Jun 2012 22:36:29 -0700 Subject: [PATCH 335/400] fix production of items in produce() add use, move and study/teach to bindings --- scripts/tests/bindings.lua | 3 ++ scripts/tests/orders.lua | 37 +++++++++++++++++++ src/bindings/bind_process.c | 71 ++++++++++++++++++++++++++++--------- src/bindings/bind_process.h | 3 ++ src/bindings/process.pkg | 5 ++- src/gamecode/laws.c | 2 +- src/gamecode/laws.h | 1 + 7 files changed, 104 insertions(+), 18 deletions(-) diff --git a/scripts/tests/bindings.lua b/scripts/tests/bindings.lua index eb81b21f6..a6f8434a5 100755 --- a/scripts/tests/bindings.lua +++ b/scripts/tests/bindings.lua @@ -27,6 +27,9 @@ function test_process() assert_equal("function", _G.type(eressea.process.set_group)) assert_equal("function", _G.type(eressea.process.set_origin)) assert_equal("function", _G.type(eressea.process.quit)) + assert_equal("function", _G.type(eressea.process.study)) + assert_equal("function", _G.type(eressea.process.movement)) + assert_equal("function", _G.type(eressea.process.use)) end function test_settings() diff --git a/scripts/tests/orders.lua b/scripts/tests/orders.lua index 2fc1e5b77..84c02309a 100755 --- a/scripts/tests/orders.lua +++ b/scripts/tests/orders.lua @@ -105,3 +105,40 @@ function test_process_quit() eressea.read_game('test.dat') assert_equal(nil, _G.get_faction(fno)) end + +function test_process_make() + u.region:set_resource('tree', 100) + u:set_skill('forestry', 1) + u:add_order('MACHE HOLZ') + eressea.process.produce() + assert_equal(1, u:get_item('log')) +end + +function test_process_teach() + u:add_order("LERNEN Holzfaellen") + eressea.process.update_long_order() + eressea.process.study() + x, y = u.faction:get_origin() + assert_equal(1, u:get_skill('forestry')) +end + +function test_process_study() + u:set_skill('forestry', 3) + u2 = _G.unit.create(f, r, 10) + u2:clear_orders() + u2:set_skill('forestry', 1) + u2:add_order("LERNEN Holzfaellen") + u:add_order("LEHREN " .. _G.itoa36(u2.id)) + eressea.process.update_long_order() + eressea.process.study() + assert_equal(2, u2:get_skill('forestry')) +end + +function test_process_move() + r2 = _G.region.create(1, 0, 'plain') + u:add_order('NACH O') + eressea.process.update_long_order() + eressea.process.movement() + assert_equal(r2, u.region) +end + diff --git a/src/bindings/bind_process.c b/src/bindings/bind_process.c index 105a68480..6e739ec8d 100755 --- a/src/bindings/bind_process.c +++ b/src/bindings/bind_process.c @@ -5,14 +5,56 @@ #include #include #include +#include #include #include #include +#include + +static void process_cmd(keyword_t kwd, int (*callback)(unit *, order *)) +{ + region * r; + for (r=regions; r; r=r->next) { + unit * u; + for (u=r->units; u; u=u->next) { + order * ord; + for (ord=u->orders; ord; ord=ord->next) { + if (kwd == get_keyword(ord)) { + callback(u, ord); + } + } + } + } +} + +static void process_long_cmd(keyword_t kwd, int (*callback)(unit *, order *)) +{ + region * r; + for (r=regions; r; r=r->next) { + unit * u; + for (u=r->units; u; u=u->next) { + order * ord = u->thisorder; + if (kwd == get_keyword(ord)) { + callback(u, ord); + } + } + } +} void process_produce(void) { struct region *r; for (r = regions; r; r = r->next) { + unit * u; + for (u=r->units; u; u=u->next) { + order * ord; + for (ord=u->orders; ord; ord=ord->next) { + if (K_MAKE == get_keyword(ord)) { + make_cmd(u, ord); + } + } + } produce(r); + split_allocations(r); } } @@ -59,22 +101,6 @@ void process_settings(void) { } } -static void process_cmd(keyword_t kwd, int (*callback)(unit *, order *)) -{ - region * r; - for (r=regions; r; r=r->next) { - unit * u; - for (u=r->units; u; u=u->next) { - order * ord; - for (ord=u->orders; ord; ord=ord->next) { - if (kwd == get_keyword(ord)) { - callback(u, ord); - } - } - } - } -} - void process_ally(void) { process_cmd(K_ALLY, ally_cmd); } @@ -107,3 +133,16 @@ void process_quit(void) { process_cmd(K_QUIT, quit_cmd); quit(); } + +void process_study(void) { + process_long_cmd(K_TEACH, teach_cmd); + process_long_cmd(K_STUDY, learn_cmd); +} + +void process_movement(void) { + movement(); +} + +void process_use(void) { + process_cmd(K_USE, use_cmd); +} diff --git a/src/bindings/bind_process.h b/src/bindings/bind_process.h index 2cd754135..009a79325 100755 --- a/src/bindings/bind_process.h +++ b/src/bindings/bind_process.h @@ -18,6 +18,9 @@ void process_display(void); void process_group(void); void process_origin(void); void process_quit(void); +void process_study(void); +void process_movement(void); +void process_use(void); #ifdef __cplusplus } diff --git a/src/bindings/process.pkg b/src/bindings/process.pkg index 37086e1cf..ef123716c 100755 --- a/src/bindings/process.pkg +++ b/src/bindings/process.pkg @@ -4,7 +4,7 @@ module eressea { module process { void process_update_long_order @ update_long_order(void); void process_markets @ markets(void); /* operate the e3 markets */ - void process_produce @ produce(void); /* BUY/SELL/ENTERTAIN/WORK/TAX/STEAL/SPY/SABOTAGE/PLANT/BREED/RESEARCH */ + void process_produce @ produce(void); /* MAKE+BUY/SELL/ENTERTAIN/WORK/TAX/STEAL/SPY/SABOTAGE/PLANT/BREED/RESEARCH */ void process_make_temp @ make_temp(void); /* MAKE TEMP */ void process_settings @ settings(void); /* EMAIL/PASSWORD/BANNER/OPTION */ void process_ally @ set_allies(void); /* HELP */ @@ -15,5 +15,8 @@ module eressea { void process_group @ set_group(void); /* GROUP */ void process_origin @ set_origin(void); /* ORIGIN */ void process_quit @ quit(void); /* QUIT */ + void process_study @ study(void); /* LEARN/TEACH */ + void process_movement @ movement(void); /* MOVE/FOLLOW/ROUTE */ + void process_use @ use(void); /* USE */ } } diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 4ad866a11..7f4c9278d 100755 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -3777,7 +3777,7 @@ static void age_factions(void) } } -static int use_cmd(unit * u, struct order *ord) +int use_cmd(unit * u, struct order *ord) { const char *t; int n, err = ENOITEM; diff --git a/src/gamecode/laws.h b/src/gamecode/laws.h index 2d9cc2ce7..b3503f5d7 100755 --- a/src/gamecode/laws.h +++ b/src/gamecode/laws.h @@ -61,6 +61,7 @@ extern "C" { extern int origin_cmd(struct unit *u, struct order *ord); extern int quit_cmd(struct unit *u, struct order *ord); extern int name_cmd(struct unit *u, struct order *ord); + extern int use_cmd(struct unit *u, struct order *ord); #ifdef __cplusplus } From 09800b8387addbd76e6517821a4aeac3d78f8f70 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 13 Jun 2012 23:25:20 -0700 Subject: [PATCH 336/400] moving things into laws.c, where a lot of order processing happens now. --- src/gamecode/laws.c | 330 +++++++++++++++++++++++++++++++++++++++++++ src/gamecode/laws.h | 8 +- src/gamecode/spy.c | 2 +- src/kernel/build.c | 336 -------------------------------------------- src/kernel/build.h | 5 - 5 files changed, 338 insertions(+), 343 deletions(-) diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 7f4c9278d..95af2bfa3 100755 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -1063,6 +1063,112 @@ static void transfer_faction(faction * f, faction * f2) } } +/* test if the unit can slip through a siege undetected. + * returns 0 if siege is successful, or 1 if the building is either + * not besieged or the unit can slip through the siege due to better stealth. + */ +static int slipthru(const region * r, const unit * u, const building * b) +{ + unit *u2; + int n, o; + + /* b ist die burg, in die man hinein oder aus der man heraus will. */ + if (b == NULL || b->besieged < b->size * SIEGEFACTOR) { + return 1; + } + + /* u wird am hinein- oder herausschluepfen gehindert, wenn STEALTH <= + * OBSERVATION +2 der belagerer u2 ist */ + n = eff_skill(u, SK_STEALTH, r); + + for (u2 = r->units; u2; u2 = u2->next) { + if (usiege(u2) == b) { + + if (invisible(u, u2) >= u->number) + continue; + + o = eff_skill(u2, SK_PERCEPTION, r); + + if (o + 2 >= n) { + return 0; /* entdeckt! */ + } + } + } + return 1; +} + +int can_contact(const region * r, const unit * u, const unit * u2) { + + /* hier geht es nur um die belagerung von burgen */ + + if (u->building == u2->building) { + return 1; + } + + /* unit u is trying to contact u2 - unasked for contact. wenn u oder u2 + * nicht in einer burg ist, oder die burg nicht belagert ist, ist + * slipthru () == 1. ansonsten ist es nur 1, wenn man die belagerer */ + + if (slipthru(u->region, u, u->building) && slipthru(u->region, u2, u2->building)) { + return 1; + } + + return (alliedunit(u, u2->faction, HELP_GIVE)); +} + +void contact_cmd(unit * u, order * ord, int final) +{ + /* unit u kontaktiert unit u2. Dies setzt den contact einfach auf 1 - + * ein richtiger toggle ist (noch?) nicht noetig. die region als + * parameter ist nur deswegen wichtig, weil er an getunit () + * weitergegeben wird. dies wird fuer das auffinden von tempunits in + * getnewunit () verwendet! */ + unit *u2; + region *r = u->region; + + init_tokens(ord); + skip_token(); + u2 = getunitg(r, u->faction); + + if (u2 != NULL) { + if (!can_contact(r, u, u2)) { + if (final) { + cmistake(u, u->thisorder, 23, MSG_EVENT); + } + return; + } + usetcontact(u, u2); + } +} + +int leave_cmd(unit * u, struct order *ord) +{ + region *r = u->region; + + if (fval(u, UFL_ENTER)) { + /* if we just entered this round, then we don't leave again */ + return 0; + } + + if (fval(r->terrain, SEA_REGION) && u->ship) { + if (!fval(u->race, RCF_SWIM)) { + cmistake(u, ord, 11, MSG_MOVE); + return 0; + } + if (has_horses(u)) { + cmistake(u, ord, 231, MSG_MOVE); + return 0; + } + } + if (!slipthru(r, u, u->building)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "entrance_besieged", + "building", u->building)); + } else { + leave(u, true); + } + return 0; +} + static int restart_cmd(unit * u, struct order *ord) { init_tokens(ord); @@ -1159,6 +1265,230 @@ int quit_cmd(unit * u, struct order *ord) return 0; } +static boolean mayenter(region * r, unit * u, building * b) +{ + unit *u2; + if (fval(b, BLD_UNGUARDED)) + return true; + u2 = building_owner(b); + + if (u2 == NULL || ucontact(u2, u) + || alliedunit(u2, u->faction, HELP_GUARD)) + return true; + + return false; +} + +static int mayboard(const unit * u, ship * sh) +{ + unit *u2 = ship_owner(sh); + + return (!u2 || ucontact(u2, u) || alliedunit(u2, u->faction, HELP_GUARD)); +} + +static boolean CheckOverload(void) +{ + static int value = -1; + if (value < 0) { + value = get_param_int(global.parameters, "rules.check_overload", 0); + } + return value; +} + +int enter_ship(unit * u, struct order *ord, int id, int report) +{ + region *r = u->region; + ship *sh; + + /* Muß abgefangen werden, sonst könnten Schwimmer an + * Bord von Schiffen an Land gelangen. */ + if (!fval(u->race, RCF_CANSAIL) || (!fval(u->race, RCF_WALK) + && !fval(u->race, RCF_FLY))) { + cmistake(u, ord, 233, MSG_MOVE); + return 0; + } + + sh = findship(id); + if (sh == NULL || sh->region != r) { + if (report) + cmistake(u, ord, 20, MSG_MOVE); + return 0; + } + if (sh == u->ship) { + return 1; + } + if (!mayboard(u, sh)) { + if (report) + cmistake(u, ord, 34, MSG_MOVE); + return 0; + } + if (CheckOverload()) { + int sweight, scabins; + int mweight = shipcapacity(sh); + int mcabins = sh->type->cabins; + + if (mweight > 0) { + getshipweight(sh, &sweight, &scabins); + sweight += weight(u); + if (mcabins) { + int pweight = u->number * u->race->weight; + /* weight goes into number of cabins, not cargo */ + scabins += pweight; + sweight -= pweight; + } + + if (sweight > mweight || (mcabins && (scabins > mcabins))) { + if (report) + cmistake(u, ord, 34, MSG_MOVE); + return 0; + } + } + } + + if (leave(u, 0)) { + u_set_ship(u, sh); + fset(u, UFL_ENTER); + } + return 1; +} + +int enter_building(unit * u, order * ord, int id, int report) +{ + region *r = u->region; + building *b; + + /* Schwimmer können keine Gebäude betreten, außer diese sind + * auf dem Ozean */ + if (!fval(u->race, RCF_WALK) && !fval(u->race, RCF_FLY)) { + if (!fval(r->terrain, SEA_REGION)) { + if (report) { + cmistake(u, ord, 232, MSG_MOVE); + } + return 0; + } + } + + b = findbuilding(id); + if (b == NULL || b->region != r) { + if (report) { + cmistake(u, ord, 6, MSG_MOVE); + } + return 0; + } + if (!mayenter(r, u, b)) { + if (report) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "entrance_denied", + "building", b)); + } + return 0; + } + if (!slipthru(r, u, b)) { + if (report) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "entrance_besieged", + "building", b)); + } + return 0; + } + + if (leave(u, 0)) { + fset(u, UFL_ENTER); + u_set_building(u, b); + return 1; + } + return 0; +} + +static void do_misc(region * r, int is_final_attempt) +{ + unit **uptr, *uc; + + for (uc = r->units; uc; uc = uc->next) { + order *ord; + for (ord = uc->orders; ord; ord = ord->next) { + keyword_t kwd = get_keyword(ord); + if (kwd == K_CONTACT) { + contact_cmd(uc, ord, is_final_attempt); + } + } + } + + for (uptr = &r->units; *uptr;) { + unit *u = *uptr; + order **ordp = &u->orders; + + while (*ordp) { + order *ord = *ordp; + if (get_keyword(ord) == K_ENTER) { + param_t p; + int id; + unit *ulast = NULL; + const char * s; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + p = findparam_ex(s, u->faction->locale); + id = getid(); + + switch (p) { + case P_BUILDING: + case P_GEBAEUDE: + if (u->building && u->building->no == id) + break; + if (enter_building(u, ord, id, is_final_attempt)) { + unit *ub; + for (ub = u; ub; ub = ub->next) { + if (ub->building == u->building) { + ulast = ub; + } + } + } + break; + + case P_SHIP: + if (u->ship && u->ship->no == id) + break; + if (enter_ship(u, ord, id, is_final_attempt)) { + unit *ub; + ulast = u; + for (ub = u; ub; ub = ub->next) { + if (ub->ship == u->ship) { + ulast = ub; + } + } + } + break; + + default: + if (is_final_attempt) { + cmistake(u, ord, 79, MSG_MOVE); + } + } + if (ulast != NULL) { + /* Wenn wir hier angekommen sind, war der Befehl + * erfolgreich und wir löschen ihn, damit er im + * zweiten Versuch nicht nochmal ausgeführt wird. */ + *ordp = ord->next; + ord->next = NULL; + free_order(ord); + + if (ulast != u) { + /* put u behind ulast so it's the last unit in the building */ + *uptr = u->next; + u->next = ulast->next; + ulast->next = u; + } + break; + } + } + if (*ordp == ord) + ordp = &ord->next; + } + if (*uptr == u) + uptr = &u->next; + } +} + void quit(void) { faction **fptr = &factions; diff --git a/src/gamecode/laws.h b/src/gamecode/laws.h index b3503f5d7..d0ba9965e 100755 --- a/src/gamecode/laws.h +++ b/src/gamecode/laws.h @@ -37,6 +37,7 @@ extern "C" { boolean renamed_building(const struct building * b); int rename_building(struct unit * u, struct order * ord, struct building * b, const char *name); void get_food(struct region * r); + extern int can_contact(const struct region *r, const struct unit *u, const struct unit *u2); /* eressea-specific. put somewhere else, please. */ void processorders(void); @@ -45,9 +46,13 @@ extern "C" { extern int dropouts[2]; extern int *age; + extern int enter_building(struct unit *u, struct order *ord, int id, int report); + extern int enter_ship(struct unit *u, struct order *ord, int id, int report); + extern void contact_cmd(struct unit *u, struct order *ord, int final); + extern void new_units(void); extern void quit(void); - extern void update_long_order(struct unit * u); + extern void update_long_order(struct unit *u); extern int password_cmd(struct unit *u, struct order *ord); extern int banner_cmd(struct unit *u, struct order *ord); extern int email_cmd(struct unit *u, struct order *ord); @@ -62,6 +67,7 @@ extern "C" { extern int quit_cmd(struct unit *u, struct order *ord); extern int name_cmd(struct unit *u, struct order *ord); extern int use_cmd(struct unit *u, struct order *ord); + extern int leave_cmd(struct unit *u, struct order *ord); #ifdef __cplusplus } diff --git a/src/gamecode/spy.c b/src/gamecode/spy.c index 76b0360b5..43eb475cb 100644 --- a/src/gamecode/spy.c +++ b/src/gamecode/spy.c @@ -19,9 +19,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include "spy.h" +#include "laws.h" /* kernel includes */ -#include #include #include #include diff --git a/src/kernel/build.c b/src/kernel/build.c index 6b9746e24..a37265d23 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -69,99 +69,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* Name, MaxGroesse, MinBauTalent, Kapazitaet, {Eisen, Holz, Stein, BauSilber, * Laen, Mallorn}, UnterSilber, UnterSpezialTyp, UnterSpezial */ -static boolean CheckOverload(void) -{ - static int value = -1; - if (value < 0) { - value = get_param_int(global.parameters, "rules.check_overload", 0); - } - return value; -} - -/* test if the unit can slip through a siege undetected. - * returns 0 if siege is successful, or 1 if the building is either - * not besieged or the unit can slip through the siege due to better stealth. - */ -static int slipthru(const region * r, const unit * u, const building * b) -{ - unit *u2; - int n, o; - - /* b ist die burg, in die man hinein oder aus der man heraus will. */ - if (b == NULL || b->besieged < b->size * SIEGEFACTOR) { - return 1; - } - - /* u wird am hinein- oder herausschluepfen gehindert, wenn STEALTH <= - * OBSERVATION +2 der belagerer u2 ist */ - n = eff_skill(u, SK_STEALTH, r); - - for (u2 = r->units; u2; u2 = u2->next) { - if (usiege(u2) == b) { - - if (invisible(u, u2) >= u->number) - continue; - - o = eff_skill(u2, SK_PERCEPTION, r); - - if (o + 2 >= n) { - return 0; /* entdeckt! */ - } - } - } - return 1; -} - -int can_contact(const region * r, const unit * u, const unit * u2) -{ - - /* hier geht es nur um die belagerung von burgen */ - - if (u->building == u2->building) { - return 1; - } - - /* unit u is trying to contact u2 - unasked for contact. wenn u oder u2 - * nicht in einer burg ist, oder die burg nicht belagert ist, ist - * slipthru () == 1. ansonsten ist es nur 1, wenn man die belagerer */ - - if (slipthru(u->region, u, u->building) && slipthru(u->region, u2, u2->building)) { - return 1; - } - - return (alliedunit(u, u2->faction, HELP_GIVE)); -} - -static void contact_cmd(unit * u, order * ord, int final) -{ - /* unit u kontaktiert unit u2. Dies setzt den contact einfach auf 1 - - * ein richtiger toggle ist (noch?) nicht noetig. die region als - * parameter ist nur deswegen wichtig, weil er an getunit () - * weitergegeben wird. dies wird fuer das auffinden von tempunits in - * getnewunit () verwendet! */ - unit *u2; - region *r = u->region; - - init_tokens(ord); - skip_token(); - u2 = getunitg(r, u->faction); - - if (u2 != NULL) { - if (!can_contact(r, u, u2)) { - if (final) - cmistake(u, u->thisorder, 23, MSG_EVENT); - return; - } - usetcontact(u, u2); - } -} - -/* ------------------------------------------------------------- */ - -/* ------------------------------------------------------------- */ - -/* ------------------------------------------------------------- */ - struct building *getbuilding(const struct region *r) { building *b = findbuilding(getid()); @@ -1152,246 +1059,3 @@ void continue_ship(region * r, unit * u, int want) build_ship(u, sh, want); } -/* ------------------------------------------------------------- */ - -static boolean mayenter(region * r, unit * u, building * b) -{ - unit *u2; - if (fval(b, BLD_UNGUARDED)) - return true; - u2 = building_owner(b); - - if (u2 == NULL || ucontact(u2, u) - || alliedunit(u2, u->faction, HELP_GUARD)) - return true; - - return false; -} - -static int mayboard(const unit * u, ship * sh) -{ - unit *u2 = ship_owner(sh); - - return (!u2 || ucontact(u2, u) || alliedunit(u2, u->faction, HELP_GUARD)); -} - -int leave_cmd(unit * u, struct order *ord) -{ - region *r = u->region; - - if (fval(u, UFL_ENTER)) { - /* if we just entered this round, then we don't leave again */ - return 0; - } - - if (fval(r->terrain, SEA_REGION) && u->ship) { - if (!fval(u->race, RCF_SWIM)) { - cmistake(u, ord, 11, MSG_MOVE); - return 0; - } - if (has_horses(u)) { - cmistake(u, ord, 231, MSG_MOVE); - return 0; - } - } - if (!slipthru(r, u, u->building)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, "entrance_besieged", - "building", u->building)); - } else { - leave(u, true); - } - return 0; -} - -static boolean enter_ship(unit * u, struct order *ord, int id, boolean report) -{ - region *r = u->region; - ship *sh; - - /* Muß abgefangen werden, sonst könnten Schwimmer an - * Bord von Schiffen an Land gelangen. */ - if (!fval(u->race, RCF_CANSAIL) || (!fval(u->race, RCF_WALK) - && !fval(u->race, RCF_FLY))) { - cmistake(u, ord, 233, MSG_MOVE); - return false; - } - - sh = findship(id); - if (sh == NULL || sh->region != r) { - if (report) - cmistake(u, ord, 20, MSG_MOVE); - return false; - } - if (sh == u->ship) - return true; - if (!mayboard(u, sh)) { - if (report) - cmistake(u, ord, 34, MSG_MOVE); - return false; - } - if (CheckOverload()) { - int sweight, scabins; - int mweight = shipcapacity(sh); - int mcabins = sh->type->cabins; - - if (mweight > 0) { - getshipweight(sh, &sweight, &scabins); - sweight += weight(u); - if (mcabins) { - int pweight = u->number * u->race->weight; - /* weight goes into number of cabins, not cargo */ - scabins += pweight; - sweight -= pweight; - } - - if (sweight > mweight || (mcabins && (scabins > mcabins))) { - if (report) - cmistake(u, ord, 34, MSG_MOVE); - return false; - } - } - } - - if (leave(u, false)) { - u_set_ship(u, sh); - fset(u, UFL_ENTER); - } - return true; -} - -static boolean enter_building(unit * u, order * ord, int id, boolean report) -{ - region *r = u->region; - building *b; - - /* Schwimmer können keine Gebäude betreten, außer diese sind - * auf dem Ozean */ - if (!fval(u->race, RCF_WALK) && !fval(u->race, RCF_FLY)) { - if (!fval(r->terrain, SEA_REGION)) { - if (report) { - cmistake(u, ord, 232, MSG_MOVE); - } - return false; - } - } - - b = findbuilding(id); - if (b == NULL || b->region != r) { - if (report) { - cmistake(u, ord, 6, MSG_MOVE); - } - return false; - } - if (!mayenter(r, u, b)) { - if (report) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "entrance_denied", - "building", b)); - } - return false; - } - if (!slipthru(r, u, b)) { - if (report) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "entrance_besieged", - "building", b)); - } - return false; - } - - if (leave(u, false)) { - fset(u, UFL_ENTER); - u_set_building(u, b); - return true; - } - return false; -} - -void do_misc(region * r, int is_final_attempt) -{ - unit **uptr, *uc; - - for (uc = r->units; uc; uc = uc->next) { - order *ord; - for (ord = uc->orders; ord; ord = ord->next) { - keyword_t kwd = get_keyword(ord); - if (kwd == K_CONTACT) { - contact_cmd(uc, ord, is_final_attempt); - } - } - } - - for (uptr = &r->units; *uptr;) { - unit *u = *uptr; - order **ordp = &u->orders; - - while (*ordp) { - order *ord = *ordp; - if (get_keyword(ord) == K_ENTER) { - param_t p; - int id; - unit *ulast = NULL; - const char * s; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - p = findparam_ex(s, u->faction->locale); - id = getid(); - - switch (p) { - case P_BUILDING: - case P_GEBAEUDE: - if (u->building && u->building->no == id) - break; - if (enter_building(u, ord, id, is_final_attempt)) { - unit *ub; - for (ub = u; ub; ub = ub->next) { - if (ub->building == u->building) { - ulast = ub; - } - } - } - break; - - case P_SHIP: - if (u->ship && u->ship->no == id) - break; - if (enter_ship(u, ord, id, is_final_attempt)) { - unit *ub; - ulast = u; - for (ub = u; ub; ub = ub->next) { - if (ub->ship == u->ship) { - ulast = ub; - } - } - } - break; - - default: - if (is_final_attempt) { - cmistake(u, ord, 79, MSG_MOVE); - } - } - if (ulast != NULL) { - /* Wenn wir hier angekommen sind, war der Befehl - * erfolgreich und wir löschen ihn, damit er im - * zweiten Versuch nicht nochmal ausgeführt wird. */ - *ordp = ord->next; - ord->next = NULL; - free_order(ord); - - if (ulast != u) { - /* put u behind ulast so it's the last unit in the building */ - *uptr = u->next; - u->next = ulast->next; - ulast->next = u; - } - break; - } - } - if (*ordp == ord) - ordp = &ord->next; - } - if (*uptr == u) - uptr = &u->next; - } -} diff --git a/src/kernel/build.h b/src/kernel/build.h index 5407034bf..20577da8e 100644 --- a/src/kernel/build.h +++ b/src/kernel/build.h @@ -64,9 +64,6 @@ extern "C" { extern int destroy_cmd(struct unit *u, struct order *ord); extern int leave_cmd(struct unit *u, struct order *ord); - extern int can_contact(const struct region *r, const struct unit *u, - const struct unit *u2); - void do_siege(struct region *r); void build_road(struct region *r, struct unit *u, int size, direction_t d); void create_ship(struct region *r, struct unit *u, @@ -76,8 +73,6 @@ extern "C" { struct building *getbuilding(const struct region *r); struct ship *getship(const struct region *r); - void do_misc(struct region *r, int is_final_attempt); - void reportevent(struct region *r, char *s); void shash(struct ship *sh); From 483615c458927d5b90b913af484a87a19547b0d0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 13 Jun 2012 23:28:56 -0700 Subject: [PATCH 337/400] bindings for LEAVE command --- scripts/tests/bindings.lua | 1 + scripts/tests/orders.lua | 11 +++++++++++ src/bindings/bind_process.c | 4 ++++ src/bindings/bind_process.h | 1 + src/bindings/process.pkg | 1 + 5 files changed, 18 insertions(+) diff --git a/scripts/tests/bindings.lua b/scripts/tests/bindings.lua index a6f8434a5..a686b063f 100755 --- a/scripts/tests/bindings.lua +++ b/scripts/tests/bindings.lua @@ -30,6 +30,7 @@ function test_process() assert_equal("function", _G.type(eressea.process.study)) assert_equal("function", _G.type(eressea.process.movement)) assert_equal("function", _G.type(eressea.process.use)) + assert_equal("function", _G.type(eressea.process.leave)) end function test_settings() diff --git a/scripts/tests/orders.lua b/scripts/tests/orders.lua index 84c02309a..c2439fdb2 100755 --- a/scripts/tests/orders.lua +++ b/scripts/tests/orders.lua @@ -137,8 +137,19 @@ end function test_process_move() r2 = _G.region.create(1, 0, 'plain') u:add_order('NACH O') + assert_not_equal(r2, u.region) eressea.process.update_long_order() eressea.process.movement() assert_equal(r2, u.region) end +function test_process_leave() + r2 = _G.region.create(1, 0, 'plain') + b = _G.building.create(r, "castle") + u.building = b + assert_equal(b, u.building) + u:add_order('VERLASSEN') + eressea.process.leave() + assert_not_equal(b, u.building) +end + diff --git a/src/bindings/bind_process.c b/src/bindings/bind_process.c index 6e739ec8d..a3de48c29 100755 --- a/src/bindings/bind_process.c +++ b/src/bindings/bind_process.c @@ -146,3 +146,7 @@ void process_movement(void) { void process_use(void) { process_cmd(K_USE, use_cmd); } + +void process_leave(void) { + process_cmd(K_LEAVE, leave_cmd); +} diff --git a/src/bindings/bind_process.h b/src/bindings/bind_process.h index 009a79325..b2363c6d0 100755 --- a/src/bindings/bind_process.h +++ b/src/bindings/bind_process.h @@ -21,6 +21,7 @@ void process_quit(void); void process_study(void); void process_movement(void); void process_use(void); +void process_leave(void); #ifdef __cplusplus } diff --git a/src/bindings/process.pkg b/src/bindings/process.pkg index ef123716c..ed0d57520 100755 --- a/src/bindings/process.pkg +++ b/src/bindings/process.pkg @@ -18,5 +18,6 @@ module eressea { void process_study @ study(void); /* LEARN/TEACH */ void process_movement @ movement(void); /* MOVE/FOLLOW/ROUTE */ void process_use @ use(void); /* USE */ + void process_leave @ leave(void); /* LEAVE */ } } From 8dee09b0881bf2f5741917a9158673c32be7bbec Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 16 Jun 2012 09:17:29 -0700 Subject: [PATCH 338/400] reduce warnings --- src/gamecode/laws.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 6965a8f7d..d06167bfc 100644 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -3884,10 +3884,13 @@ enum { PROC_THISORDER = 1 << 0, PROC_LONGORDER = 1 << 1 }; + +typedef enum { PR_GLOBAL, PR_REGION_PRE, PR_UNIT, PR_ORDER, PR_REGION_POST } processor_t; + typedef struct processor { struct processor *next; int priority; - enum { PR_GLOBAL, PR_REGION_PRE, PR_UNIT, PR_ORDER, PR_REGION_POST } type; + processor_t type; unsigned int flags; union { struct { @@ -3909,7 +3912,7 @@ typedef struct processor { static processor *processors; -processor *add_proc(int priority, const char *name, int type) +static processor *add_proc(int priority, const char *name, processor_t type) { processor **pproc = &processors; processor *proc; @@ -3923,7 +3926,7 @@ processor *add_proc(int priority, const char *name, int type) pproc = &proc->next; } - proc = malloc(sizeof(processor)); + proc = (processor *)malloc(sizeof(processor)); proc->priority = priority; proc->type = type; proc->name = name; From c98612f44e1037f368c25ae531eeb86497ebe921 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 16 Jun 2012 19:14:23 -0700 Subject: [PATCH 339/400] adding battle and siege to the eressea.process module --- scripts/tests/bindings.lua | 2 + src/bindings/bind_process.c | 80 ++++++++++++++++++------------ src/bindings/bind_process.h | 2 + src/bindings/bindings.c | 2 +- src/bindings/process.pkg | 2 + src/gamecode/laws.c | 97 +++++++++++++++++++++++++++++++++++++ src/gamecode/laws.h | 1 + src/kernel/build.c | 96 ------------------------------------ src/kernel/build.h | 1 - 9 files changed, 154 insertions(+), 129 deletions(-) diff --git a/scripts/tests/bindings.lua b/scripts/tests/bindings.lua index a686b063f..614c7e414 100755 --- a/scripts/tests/bindings.lua +++ b/scripts/tests/bindings.lua @@ -30,6 +30,8 @@ function test_process() assert_equal("function", _G.type(eressea.process.study)) assert_equal("function", _G.type(eressea.process.movement)) assert_equal("function", _G.type(eressea.process.use)) + assert_equal("function", _G.type(eressea.process.battle)) + assert_equal("function", _G.type(eressea.process.siege)) assert_equal("function", _G.type(eressea.process.leave)) end diff --git a/src/bindings/bind_process.c b/src/bindings/bind_process.c index a3de48c29..3475b9765 100755 --- a/src/bindings/bind_process.c +++ b/src/bindings/bind_process.c @@ -3,7 +3,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -11,31 +13,36 @@ #include #include -static void process_cmd(keyword_t kwd, int (*callback)(unit *, order *)) -{ - region * r; - for (r=regions; r; r=r->next) { - unit * u; - for (u=r->units; u; u=u->next) { - order * ord; - for (ord=u->orders; ord; ord=ord->next) { - if (kwd == get_keyword(ord)) { - callback(u, ord); - } - } - } - } -} +#define PROC_LAND_REGION 0x0001 +#define PROC_LONG_ORDER 0x0002 -static void process_long_cmd(keyword_t kwd, int (*callback)(unit *, order *)) +static void process_cmd(keyword_t kwd, int (*callback)(unit *, order *), int flags) { region * r; for (r=regions; r; r=r->next) { unit * u; + + /* look for shortcuts */ + if (flags&PROC_LAND_REGION) { + /* only execute when we are on solid terrain */ + while (r && (r->terrain->flags&LAND_REGION)==0) { + r = r->next; + } + if (!r) break; + } + for (u=r->units; u; u=u->next) { - order * ord = u->thisorder; - if (kwd == get_keyword(ord)) { - callback(u, ord); + if (flags & PROC_LONG_ORDER) { + if (kwd == get_keyword(u->thisorder)) { + callback(u, u->thisorder); + } + } else { + order * ord; + for (ord=u->orders; ord; ord=ord->next) { + if (kwd == get_keyword(ord)) { + callback(u, ord); + } + } } } } @@ -58,6 +65,17 @@ void process_produce(void) { } } +void process_battle(void) { + struct region *r; + for (r = regions; r; r = r->next) { + do_battle(r); + } +} + +void process_siege(void) { + process_cmd(K_BESIEGE, siege_cmd, PROC_LAND_REGION); +} + void process_update_long_order(void) { region * r; for (r=regions; r; r=r->next) { @@ -102,41 +120,41 @@ void process_settings(void) { } void process_ally(void) { - process_cmd(K_ALLY, ally_cmd); + process_cmd(K_ALLY, ally_cmd, 0); } void process_prefix(void) { - process_cmd(K_PREFIX, prefix_cmd); + process_cmd(K_PREFIX, prefix_cmd, 0); } void process_setstealth(void) { - process_cmd(K_SETSTEALTH, setstealth_cmd); + process_cmd(K_SETSTEALTH, setstealth_cmd, 0); } void process_status(void) { - process_cmd(K_STATUS, status_cmd); + process_cmd(K_STATUS, status_cmd, 0); } void process_display(void) { - process_cmd(K_DISPLAY, display_cmd); + process_cmd(K_DISPLAY, display_cmd, 0); } void process_group(void) { - process_cmd(K_GROUP, group_cmd); + process_cmd(K_GROUP, group_cmd, 0); } void process_origin(void) { - process_cmd(K_URSPRUNG, origin_cmd); + process_cmd(K_URSPRUNG, origin_cmd, 0); } void process_quit(void) { - process_cmd(K_QUIT, quit_cmd); + process_cmd(K_QUIT, quit_cmd, 0); quit(); } void process_study(void) { - process_long_cmd(K_TEACH, teach_cmd); - process_long_cmd(K_STUDY, learn_cmd); + process_cmd(K_TEACH, teach_cmd, PROC_LONG_ORDER); + process_cmd(K_STUDY, learn_cmd, PROC_LONG_ORDER); } void process_movement(void) { @@ -144,9 +162,9 @@ void process_movement(void) { } void process_use(void) { - process_cmd(K_USE, use_cmd); + process_cmd(K_USE, use_cmd, 0); } void process_leave(void) { - process_cmd(K_LEAVE, leave_cmd); + process_cmd(K_LEAVE, leave_cmd, 0); } diff --git a/src/bindings/bind_process.h b/src/bindings/bind_process.h index b2363c6d0..b1a6638e0 100755 --- a/src/bindings/bind_process.h +++ b/src/bindings/bind_process.h @@ -21,6 +21,8 @@ void process_quit(void); void process_study(void); void process_movement(void); void process_use(void); +void process_battle(void); +void process_siege(void); void process_leave(void); #ifdef __cplusplus diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index ea86df4a0..c73136b44 100755 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -1313,4 +1313,4 @@ int eressea_run(lua_State *L, const char *luafile, const char *entry_point) err = lua_console(L); } return err; -} +} diff --git a/src/bindings/process.pkg b/src/bindings/process.pkg index ed0d57520..4bb8d9362 100755 --- a/src/bindings/process.pkg +++ b/src/bindings/process.pkg @@ -18,6 +18,8 @@ module eressea { void process_study @ study(void); /* LEARN/TEACH */ void process_movement @ movement(void); /* MOVE/FOLLOW/ROUTE */ void process_use @ use(void); /* USE */ + void process_battle @ battle(void); /* ATTACK */ + void process_siege @ siege(void); /* SIEGE */ void process_leave @ leave(void); /* LEAVE */ } } diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 565ae8aec..584e8ef94 100755 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -4431,6 +4431,103 @@ void process(void) } +int siege_cmd(unit * u, order * ord) +{ + region *r = u->region; + building *b; + int d, pooled; + int bewaffnete, katapultiere = 0; + static boolean init = false; + static const curse_type *magicwalls_ct; + static item_type *it_catapultammo = NULL; + static item_type *it_catapult = NULL; + if (!init) { + init = true; + magicwalls_ct = ct_find("magicwalls"); + it_catapultammo = it_find("catapultammo"); + it_catapult = it_find("catapult"); + } + /* gibt es ueberhaupt Burgen? */ + + init_tokens(ord); + skip_token(); + b = getbuilding(r); + + if (!b) { + cmistake(u, ord, 31, MSG_BATTLE); + return 31; + } + + if (!playerrace(u->race)) { + /* keine Drachen, Illusionen, Untote etc */ + cmistake(u, ord, 166, MSG_BATTLE); + return 166; + } + /* schaden durch katapulte */ + + d = i_get(u->items, it_catapult); + d = MIN(u->number, d); + pooled = get_pooled(u, it_catapultammo->rtype, GET_DEFAULT, d); + d = MIN(pooled, d); + if (eff_skill(u, SK_CATAPULT, r) >= 1) { + katapultiere = d; + d *= eff_skill(u, SK_CATAPULT, r); + } else { + d = 0; + } + + bewaffnete = armedmen(u, true); + if (d == 0 && bewaffnete == 0) { + /* abbruch, falls unbewaffnet oder unfaehig, katapulte zu benutzen */ + cmistake(u, ord, 80, MSG_EVENT); + return 80; + } + + if (!is_guard(u, GUARD_TRAVELTHRU)) { + /* abbruch, wenn die einheit nicht vorher die region bewacht - als + * warnung fuer alle anderen! */ + cmistake(u, ord, 81, MSG_EVENT); + return 81; + } + /* einheit und burg markieren - spart zeit beim behandeln der einheiten + * in der burg, falls die burg auch markiert ist und nicht alle + * einheiten wieder abgesucht werden muessen! */ + + usetsiege(u, b); + b->besieged += MAX(bewaffnete, katapultiere); + + /* definitiver schaden eingeschraenkt */ + + d = MIN(d, b->size - 1); + + /* meldung, schaden anrichten */ + if (d && !curse_active(get_curse(b->attribs, magicwalls_ct))) { + b->size -= d; + use_pooled(u, it_catapultammo->rtype, + GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, d); + /* send message to the entire region */ + ADDMSG(&r->msgs, msg_message("siege_catapults", + "unit building destruction", u, b, d)); + } else { + /* send message to the entire region */ + ADDMSG(&r->msgs, msg_message("siege", "unit building", u, b)); + } + return 0; +} + +void do_siege(region * r) +{ + if (fval(r->terrain, LAND_REGION)) { + unit *u; + + for (u = r->units; u; u = u->next) { + if (get_keyword(u->thisorder) == K_BESIEGE) { + siege_cmd(u, u->thisorder); + } + } + } +} + static void enter_1(region * r) { do_misc(r, 0); diff --git a/src/gamecode/laws.h b/src/gamecode/laws.h index d0ba9965e..23c727e18 100755 --- a/src/gamecode/laws.h +++ b/src/gamecode/laws.h @@ -67,6 +67,7 @@ extern "C" { extern int quit_cmd(struct unit *u, struct order *ord); extern int name_cmd(struct unit *u, struct order *ord); extern int use_cmd(struct unit *u, struct order *ord); + extern int siege_cmd(struct unit *u, struct order *ord); extern int leave_cmd(struct unit *u, struct order *ord); #ifdef __cplusplus diff --git a/src/kernel/build.c b/src/kernel/build.c index a37265d23..5726f4828 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -89,102 +89,6 @@ ship *getship(const struct region * r) /* ------------------------------------------------------------- */ -static void siege_cmd(unit * u, order * ord) -{ - region *r = u->region; - building *b; - int d, pooled; - int bewaffnete, katapultiere = 0; - static boolean init = false; - static const curse_type *magicwalls_ct; - static item_type *it_catapultammo = NULL; - static item_type *it_catapult = NULL; - if (!init) { - init = true; - magicwalls_ct = ct_find("magicwalls"); - it_catapultammo = it_find("catapultammo"); - it_catapult = it_find("catapult"); - } - /* gibt es ueberhaupt Burgen? */ - - init_tokens(ord); - skip_token(); - b = getbuilding(r); - - if (!b) { - cmistake(u, ord, 31, MSG_BATTLE); - return; - } - - if (!playerrace(u->race)) { - /* keine Drachen, Illusionen, Untote etc */ - cmistake(u, ord, 166, MSG_BATTLE); - return; - } - /* schaden durch katapulte */ - - d = i_get(u->items, it_catapult); - d = MIN(u->number, d); - pooled = get_pooled(u, it_catapultammo->rtype, GET_DEFAULT, d); - d = MIN(pooled, d); - if (eff_skill(u, SK_CATAPULT, r) >= 1) { - katapultiere = d; - d *= eff_skill(u, SK_CATAPULT, r); - } else { - d = 0; - } - - bewaffnete = armedmen(u, true); - if (d == 0 && bewaffnete == 0) { - /* abbruch, falls unbewaffnet oder unfaehig, katapulte zu benutzen */ - cmistake(u, ord, 80, MSG_EVENT); - return; - } - - if (!is_guard(u, GUARD_TRAVELTHRU)) { - /* abbruch, wenn die einheit nicht vorher die region bewacht - als - * warnung fuer alle anderen! */ - cmistake(u, ord, 81, MSG_EVENT); - return; - } - /* einheit und burg markieren - spart zeit beim behandeln der einheiten - * in der burg, falls die burg auch markiert ist und nicht alle - * einheiten wieder abgesucht werden muessen! */ - - usetsiege(u, b); - b->besieged += MAX(bewaffnete, katapultiere); - - /* definitiver schaden eingeschraenkt */ - - d = MIN(d, b->size - 1); - - /* meldung, schaden anrichten */ - if (d && !curse_active(get_curse(b->attribs, magicwalls_ct))) { - b->size -= d; - use_pooled(u, it_catapultammo->rtype, - GET_SLACK | GET_RESERVE | GET_POOLED_SLACK, d); - /* send message to the entire region */ - ADDMSG(&r->msgs, msg_message("siege_catapults", - "unit building destruction", u, b, d)); - } else { - /* send message to the entire region */ - ADDMSG(&r->msgs, msg_message("siege", "unit building", u, b)); - } -} - -void do_siege(region * r) -{ - if (fval(r->terrain, LAND_REGION)) { - unit *u; - - for (u = r->units; u; u = u->next) { - if (get_keyword(u->thisorder) == K_BESIEGE) { - siege_cmd(u, u->thisorder); - } - } - } -} - /* ------------------------------------------------------------- */ static void destroy_road(unit * u, int nmax, struct order *ord) diff --git a/src/kernel/build.h b/src/kernel/build.h index 20577da8e..1e7b7d623 100644 --- a/src/kernel/build.h +++ b/src/kernel/build.h @@ -64,7 +64,6 @@ extern "C" { extern int destroy_cmd(struct unit *u, struct order *ord); extern int leave_cmd(struct unit *u, struct order *ord); - void do_siege(struct region *r); void build_road(struct region *r, struct unit *u, int size, direction_t d); void create_ship(struct region *r, struct unit *u, const struct ship_type *newtype, int size, struct order *ord); From 7618dc588d7a6215f3f0e6ed077cfd21e51d8ee4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 16 Jun 2012 19:23:45 -0700 Subject: [PATCH 340/400] better handling of missing entry points --- src/bindings/bindings.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index ea86df4a0..f4832a727 100755 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -1286,7 +1286,7 @@ lua_State *lua_init(void) { int eressea_run(lua_State *L, const char *luafile, const char *entry_point) { - int err; + int err = 0; global.vm_state = L; /* run the main script */ @@ -1303,14 +1303,16 @@ int eressea_run(lua_State *L, const char *luafile, const char *entry_point) } if (entry_point) { lua_getglobal(L, entry_point); - err = lua_pcall(L, 0, 1, 0); - if (err != 0) { - log_lua_error(L); - abort(); + if (lua_isfunction(L, -1)) { + log_debug("calling entry-point: %s\n", entry_point); + err = lua_pcall(L, 0, 1, 0); + if (err != 0) { + log_lua_error(L); + } return err; + } else { + log_error("unknown entry-point: %s\n", entry_point); } - } else { - err = lua_console(L); } - return err; -} + return lua_console(L); +} From a662f88868a8d4da7741c44f5861dcb4d12fc8de Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 16 Jun 2012 22:38:44 -0700 Subject: [PATCH 341/400] kill the RESTART order make more parts of process_order their own function started writing process_order in Lua, to see how far I've gotten fix a bug in the logging library --- scripts/tests/bindings.lua | 2 +- scripts/tests/orders.lua | 32 ++++++++- src/bindings/bind_process.c | 27 +++++++- src/bindings/bind_process.h | 3 +- src/bindings/process.pkg | 3 +- src/gamecode/laws.c | 132 +++--------------------------------- src/gamecode/laws.h | 2 + src/kernel/config.c | 1 - src/kernel/types.h | 1 - src/util/log.c | 2 +- 10 files changed, 75 insertions(+), 130 deletions(-) diff --git a/scripts/tests/bindings.lua b/scripts/tests/bindings.lua index 614c7e414..15f3e040a 100755 --- a/scripts/tests/bindings.lua +++ b/scripts/tests/bindings.lua @@ -23,7 +23,7 @@ function test_process() assert_equal("function", _G.type(eressea.process.set_prefix)) assert_equal("function", _G.type(eressea.process.set_stealth)) assert_equal("function", _G.type(eressea.process.set_status)) - assert_equal("function", _G.type(eressea.process.set_description)) + assert_equal("function", _G.type(eressea.process.set_name)) assert_equal("function", _G.type(eressea.process.set_group)) assert_equal("function", _G.type(eressea.process.set_origin)) assert_equal("function", _G.type(eressea.process.quit)) diff --git a/scripts/tests/orders.lua b/scripts/tests/orders.lua index c2439fdb2..4afbe1ffc 100755 --- a/scripts/tests/orders.lua +++ b/scripts/tests/orders.lua @@ -2,6 +2,8 @@ require "lunit" local _G = _G local eressea = eressea +local default_ship = config.ships[1] +local default_building = config.buildings[1] module("tests.orders", lunit.testcase) @@ -145,7 +147,7 @@ end function test_process_leave() r2 = _G.region.create(1, 0, 'plain') - b = _G.building.create(r, "castle") + b = _G.building.create(r, default_building) u.building = b assert_equal(b, u.building) u:add_order('VERLASSEN') @@ -153,3 +155,31 @@ function test_process_leave() assert_not_equal(b, u.building) end +function test_process_name_unit() + u:add_order("BENENNE EINHEIT 'Weasel'") + u:add_order("BESCHREIBE EINHEIT 'Juanita'") + eressea.process.set_name() + assert_equal('Weasel', u.name) + assert_equal('Juanita', u.info) +end + +function test_process_name_faction() + u:add_order("BENENNE PARTEI 'Herpderp'") + eressea.process.set_name() + assert_equal('Herpderp', f.name) +end + +function test_process_name_building() + u:add_order("BENENNE GEBAEUDE 'Herpderp'") + u.building = _G.building.create(r, default_building) + eressea.process.set_name() + assert_equal('Herpderp', u.building.name) +end + +function test_process_name_ship() + u:add_order("BENENNE SCHIFF 'Herpderp'") + u.ship = _G.ship.create(r, default_ship) + eressea.process.set_name() + assert_equal('Herpderp', u.ship.name) +end + diff --git a/src/bindings/bind_process.c b/src/bindings/bind_process.c index 3475b9765..04d05dda2 100755 --- a/src/bindings/bind_process.c +++ b/src/bindings/bind_process.c @@ -135,7 +135,8 @@ void process_status(void) { process_cmd(K_STATUS, status_cmd, 0); } -void process_display(void) { +void process_name(void) { + process_cmd(K_NAME, name_cmd, 0); process_cmd(K_DISPLAY, display_cmd, 0); } @@ -158,7 +159,14 @@ void process_study(void) { } void process_movement(void) { + region * r; + movement(); + for (r=regions; r; r=r->next) { + if (r->ships) { + sinkships(r); + } + } } void process_use(void) { @@ -168,3 +176,20 @@ void process_use(void) { void process_leave(void) { process_cmd(K_LEAVE, leave_cmd, 0); } + +void process_maintenance(void) { + region * r; + for (r=regions; r; r=r->next) { + unit * u; + for (u=r->units; u; u=u->next) { + order * ord; + for (ord=u->orders; ord; ord=ord->next) { + keyword_t kwd = get_keyword(ord); + if (kwd==K_PAY) { + pay_cmd(u, ord); + } + } + } + maintain_buildings(r, 0); + } +} diff --git a/src/bindings/bind_process.h b/src/bindings/bind_process.h index b1a6638e0..a5aaedf8f 100755 --- a/src/bindings/bind_process.h +++ b/src/bindings/bind_process.h @@ -14,7 +14,7 @@ void process_ally(void); void process_prefix(void); void process_setstealth(void); void process_status(void); -void process_display(void); +void process_name(void); void process_group(void); void process_origin(void); void process_quit(void); @@ -24,6 +24,7 @@ void process_use(void); void process_battle(void); void process_siege(void); void process_leave(void); +void process_maintenance(void); #ifdef __cplusplus } diff --git a/src/bindings/process.pkg b/src/bindings/process.pkg index 4bb8d9362..510be6eb4 100755 --- a/src/bindings/process.pkg +++ b/src/bindings/process.pkg @@ -11,7 +11,7 @@ module eressea { void process_prefix @ set_prefix(void); /* PREFIX */ void process_setstealth @ set_stealth(void); /* STEALTH */ void process_status @ set_status(void); /* STATUS */ - void process_display @ set_description(void); /* DESCRIBE */ + void process_name @ set_name(void); /* NAME/DISPLAY */ void process_group @ set_group(void); /* GROUP */ void process_origin @ set_origin(void); /* ORIGIN */ void process_quit @ quit(void); /* QUIT */ @@ -21,5 +21,6 @@ module eressea { void process_battle @ battle(void); /* ATTACK */ void process_siege @ siege(void); /* SIEGE */ void process_leave @ leave(void); /* LEAVE */ + void process_maintenance @ maintenance(void); /* PAY */ } } diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 584e8ef94..22fd99549 100755 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -119,9 +119,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define DMRISEHAFEN 0.2F /* weekly chance that demand goes up with harbor */ /* - exported global symbols ----------------------------------- */ -boolean nobattle = false; -boolean nomonsters = false; -/* ------------------------------------------------------------- */ static int RemoveNMRNewbie(void) { @@ -135,40 +132,6 @@ static int RemoveNMRNewbie(void) return value; } -static void restart_race(unit * u, const race * rc) -{ - faction *oldf = u->faction; - faction *f = addfaction(oldf->email, oldf->passw, rc, oldf->locale, - oldf->subscription); - unit *nu = addplayer(u->region, f); - order **ordp = &u->orders; - f->subscription = u->faction->subscription; - f->age = u->faction->age; - fset(f, FFL_RESTART); - if (f->subscription) { - sql_print( - ("UPDATE subscriptions set faction='%s', race='%s' where id=%u;\n", - itoa36(f->no), dbrace(rc), f->subscription)); - } - f->magiegebiet = u->faction->magiegebiet; - f->options = u->faction->options; - free_orders(&nu->orders); - nu->orders = u->orders; - u->orders = NULL; - while (*ordp) { - order *ord = *ordp; - if (get_keyword(ord) != K_RESTART) { - *ordp = ord->next; - ord->next = NULL; - if (u->thisorder == ord) - set_order(&u->thisorder, NULL); - } else { - ordp = &ord->next; - } - } - destroyfaction(u->faction); -} - static void checkorders(void) { faction *f; @@ -1169,50 +1132,6 @@ int leave_cmd(unit * u, struct order *ord) return 0; } -static int restart_cmd(unit * u, struct order *ord) -{ - init_tokens(ord); - skip_token(); /* skip keyword */ - - if (!fval(u->region->terrain, LAND_REGION)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); - } else { - const char *s_race = getstrtoken(), *s_pass; - const race *frace = findrace(s_race, u->faction->locale); - - if (!frace) { - frace = u->faction->race; - s_pass = s_race; - } else { - s_pass = getstrtoken(); - } - - if (u->faction->age > 3 && fval(u->faction, FFL_RESTART)) { - cmistake(u, ord, 314, MSG_EVENT); - return 0; - } - - if ( /* frace != u->faction->race && */ u->faction->age < 81) { - cmistake(u, ord, 241, MSG_EVENT); - return 0; - } - - if (!playerrace(frace)) { - cmistake(u, ord, 243, MSG_EVENT); - return 0; - } - - if (!checkpasswd(u->faction, (const char *)s_pass, false)) { - cmistake(u, ord, 86, MSG_EVENT); - log_warning("RESTART with wrong password, faction %s, pass %s\n", factionid(u->faction), s_pass); - return 0; - } - restart_race(u, frace); - return -1; - } - return 0; -} - static boolean EnhancedQuit(void) { static int value = -1; @@ -1539,40 +1458,16 @@ static void nmr_death(faction * f) } } -static void parse_restart(void) +static void remove_idle_players(void) { - region *r; faction *f; - /* Sterben erst nachdem man allen anderen gegeben hat - bzw. man kann - * alles machen, was nicht ein dreißigtägiger Befehl ist. */ - - for (r = regions; r; r = r->next) { - unit *u, *un; - for (u = r->units; u;) { - order *ord; - - un = u->next; - for (ord = u->orders; ord != NULL; ord = ord->next) { - if (get_keyword(ord) == K_RESTART) { - if (u->number > 0) { - if (restart_cmd(u, ord) != 0) { - break; - } - } - } - } - u = un; - } - } - - if (verbosity >= 1) - puts - (" - beseitige Spieler, die sich zu lange nicht mehr gemeldet haben..."); + log_info(" - beseitige Spieler, die sich zu lange nicht mehr gemeldet haben..."); for (f = factions; f; f = f->next) { - if (fval(f, FFL_NOIDLEOUT)) + if (fval(f, FFL_NOIDLEOUT)) { f->lastorders = turn; + } if (NMRTimeout() > 0 && turn - f->lastorders >= NMRTimeout()) { nmr_death(f); destroyfaction(f); @@ -1606,10 +1501,7 @@ static void parse_restart(void) continue; } } - if (verbosity >= 1) { - puts(" - beseitige Spieler, die sich nach der Anmeldung nicht " - "gemeldet haben..."); - } + log_info(" - beseitige Spieler, die sich nach der Anmeldung nicht gemeldet haben..."); age = calloc(MAX(4, turn + 1), sizeof(int)); for (f = factions; f; f = f->next) @@ -3073,7 +2965,7 @@ static int guard_on_cmd(unit * u, struct order *ord) return 0; } -static void sinkships(region * r) +void sinkships(struct region * r) { ship **shp = &r->ships; @@ -4154,7 +4046,7 @@ int use_cmd(unit * u, struct order *ord) return err; } -static int pay_cmd(unit * u, struct order *ord) +int pay_cmd(unit * u, struct order *ord) { if (!u->building) { cmistake(u, ord, 6, MSG_EVENT); @@ -4627,9 +4519,7 @@ void init_processor(void) p += 10; /* in case it has any effects on alliance victories */ add_proc_order(p, K_LEAVE, &leave_cmd, 0, "Verlassen"); - if (!nobattle) { - add_proc_region(p, &do_battle, "Attackieren"); - } + add_proc_region(p, &do_battle, "Attackieren"); if (!global.disabled[K_BESIEGE]) { p += 10; @@ -4653,10 +4543,8 @@ void init_processor(void) "Gebaeudeunterhalt (1. Versuch)"); p += 10; /* QUIT fuer sich alleine */ - add_proc_global(p, &quit, "Sterben"); - if (!global.disabled[K_RESTART]) { - add_proc_global(p, &parse_restart, "Neustart"); - } + add_proc_global(p, quit, "Sterben"); + add_proc_global(p, remove_idle_players, "remove idle players"); if (!global.disabled[K_CAST]) { p += 10; diff --git a/src/gamecode/laws.h b/src/gamecode/laws.h index 23c727e18..b388520a7 100755 --- a/src/gamecode/laws.h +++ b/src/gamecode/laws.h @@ -53,6 +53,7 @@ extern "C" { extern void new_units(void); extern void quit(void); extern void update_long_order(struct unit *u); + extern void sinkships(struct region * r); extern int password_cmd(struct unit *u, struct order *ord); extern int banner_cmd(struct unit *u, struct order *ord); extern int email_cmd(struct unit *u, struct order *ord); @@ -69,6 +70,7 @@ extern "C" { extern int use_cmd(struct unit *u, struct order *ord); extern int siege_cmd(struct unit *u, struct order *ord); extern int leave_cmd(struct unit *u, struct order *ord); + extern int pay_cmd(struct unit *u, struct order *ord); #ifdef __cplusplus } diff --git a/src/kernel/config.c b/src/kernel/config.c index 23b568579..63b66f127 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -449,7 +449,6 @@ const char *keywords[MAXKEYWORDS] = { "URSPRUNG", "EMAIL", "PIRATERIE", - "NEUSTART", "GRUPPE", "OPFERE", "BETEN", diff --git a/src/kernel/types.h b/src/kernel/types.h index 820f4b698..ca4a3bc06 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -128,7 +128,6 @@ typedef enum { K_URSPRUNG, K_EMAIL, K_PIRACY, - K_RESTART, K_GROUP, K_SACRIFICE, K_PRAY, diff --git a/src/util/log.c b/src/util/log.c index 40222bdd8..0c14a6bd7 100644 --- a/src/util/log.c +++ b/src/util/log.c @@ -253,7 +253,7 @@ void log_error(const char *format, ...) } } -void _log_info(const char *format, ...) +void log_info(const char *format, ...) { const char * prefix = "INFO"; const int mask = LOG_CPINFO; From 9124fe2c6d6e365aac8bb5c95bbbaaecce28d837 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 16 Jun 2012 23:31:25 -0700 Subject: [PATCH 342/400] added promote, renumber, restack to eressea.process interface fixed a test that relied on no random skill progress --- scripts/tests/bindings.lua | 3 + scripts/tests/orders.lua | 219 +++++++++++++++++++----------------- src/bindings/bind_process.c | 13 +++ src/bindings/bind_process.h | 3 + src/bindings/process.pkg | 3 + src/gamecode/laws.c | 10 +- src/gamecode/laws.h | 4 + 7 files changed, 144 insertions(+), 111 deletions(-) diff --git a/scripts/tests/bindings.lua b/scripts/tests/bindings.lua index 15f3e040a..8f8209b13 100755 --- a/scripts/tests/bindings.lua +++ b/scripts/tests/bindings.lua @@ -33,6 +33,9 @@ function test_process() assert_equal("function", _G.type(eressea.process.battle)) assert_equal("function", _G.type(eressea.process.siege)) assert_equal("function", _G.type(eressea.process.leave)) + assert_equal("function", _G.type(eressea.process.promote)) + assert_equal("function", _G.type(eressea.process.renumber)) + assert_equal("function", _G.type(eressea.process.restack)) end function test_settings() diff --git a/scripts/tests/orders.lua b/scripts/tests/orders.lua index 4afbe1ffc..0e14e3653 100755 --- a/scripts/tests/orders.lua +++ b/scripts/tests/orders.lua @@ -14,7 +14,7 @@ function setup() r = _G.region.create(0, 0, "mountain") f = _G.faction.create("noreply@eressea.de", "human", "de") u = _G.unit.create(f, r, 1) - u:clear_orders() + u:clear_orders() eressea.settings.set("rules.economy.food", "4") eressea.settings.set("nmr.removenewbie", "0") eressea.settings.set("nmr.timeout", "0") @@ -22,164 +22,171 @@ function setup() end function test_learn() - u:add_order("LERNEN Hiebwaffen") - _G.process_orders() - assert_not_equal(0, u:get_skill("melee")) + u:add_order("LERNEN Hiebwaffen") + _G.process_orders() + assert_not_equal(0, u:get_skill("melee")) end function test_give() - local u2 = _G.unit.create(f, r, 1) - u:add_item("money", 10) - u:add_order("GIB " .. u2.id .. "5 SILBER") - _G.process_orders() - assert_not_equal(5, u:get_item("money")) - assert_not_equal(5, u2:get_item("money")) + local u2 = _G.unit.create(f, r, 1) + u:add_item("money", 10) + u:add_order("GIB " .. u2.id .. "5 SILBER") + _G.process_orders() + assert_not_equal(5, u:get_item("money")) + assert_not_equal(5, u2:get_item("money")) end function test_make_temp() - u:add_order("MACHE TEMP 123 'Herpderp'") - u:add_order("// this comment will be copied") - u:add_order("ENDE") - eressea.process.make_temp() + u:add_order("MACHE TEMP 123 'Herpderp'") + u:add_order("// this comment will be copied") + u:add_order("ENDE") + eressea.process.make_temp() - for x in f.units do - if x.name == 'Herpderp' then u=x end - end - assert_equal('Herpderp', u.name) - assert_equal(0, u.number) - local c = 0 - for o in u.orders do - assert_equal('// this comment will be copied', o) - c = c + 1 - end - assert_equal(1, c) + for x in f.units do + if x.name == 'Herpderp' then u=x end + end + assert_equal('Herpderp', u.name) + assert_equal(0, u.number) + local c = 0 + for o in u.orders do + assert_equal('// this comment will be copied', o) + c = c + 1 + end + assert_equal(1, c) end function test_give_temp() - u.number = 2 - u:add_order("GIB TEMP 123 1 PERSON") - u:add_order("MACHE TEMP 123 'Herpderp'") - u:add_order("ENDE") - _G.process_orders() - assert_equal(1, u.number) + u.number = 2 + u:add_order("GIB TEMP 123 1 PERSON") + u:add_order("MACHE TEMP 123 'Herpderp'") + u:add_order("ENDE") + _G.process_orders() + assert_equal(1, u.number) - for x in f.units do - if x.name == 'Herpderp' then u=x end - end - assert_equal('Herpderp', u.name) - assert_equal(1, u.number) + for x in f.units do + if x.name == 'Herpderp' then u=x end + end + assert_equal('Herpderp', u.name) + assert_equal(1, u.number) end function test_process_settings() - f.options = 0 - u:add_order("EMAIL herp@derp.com") - u:add_order("BANNER 'Herpderp'") - u:add_order("PASSWORT 'HerpDerp'") - u:add_order("OPTION AUSWERTUNG") - eressea.process.settings() - assert_equal("herp@derp.com", f.email) - assert_equal("Herpderp", f.info) - assert_equal("HerpDerp", f.password) - assert_equal(1, f.options) + f.options = 0 + u:add_order("EMAIL herp@derp.com") + u:add_order("BANNER 'Herpderp'") + u:add_order("PASSWORT 'HerpDerp'") + u:add_order("OPTION AUSWERTUNG") + eressea.process.settings() + assert_equal("herp@derp.com", f.email) + assert_equal("Herpderp", f.info) + assert_equal("HerpDerp", f.password) + assert_equal(1, f.options) end function test_process_group() - u:add_order("GRUPPE herp") - eressea.process.set_group() - assert_equal('herp', u.group) + u:add_order("GRUPPE herp") + eressea.process.set_group() + assert_equal('herp', u.group) end function test_process_origin() - u:add_order("URSPRUNG 1 2") - eressea.process.set_origin() - x, y = u.faction:get_origin() - assert_equal(1, x) - assert_equal(2, y) + u:add_order("URSPRUNG 1 2") + eressea.process.set_origin() + x, y = u.faction:get_origin() + assert_equal(1, x) + assert_equal(2, y) end function test_process_quit() - fno = f.id - u:add_order("STIRB '" .. u.faction.password .. "'") - assert_not_equal(nil, _G.get_faction(fno)) - eressea.process.quit() - eressea.write_game('test.dat') - eressea.free_game() - eressea.read_game('test.dat') - assert_equal(nil, _G.get_faction(fno)) + fno = f.id + u:add_order("STIRB '" .. u.faction.password .. "'") + assert_not_equal(nil, _G.get_faction(fno)) + eressea.process.quit() + eressea.write_game('test.dat') + eressea.free_game() + eressea.read_game('test.dat') + assert_equal(nil, _G.get_faction(fno)) end function test_process_make() u.region:set_resource('tree', 100) - u:set_skill('forestry', 1) - u:add_order('MACHE HOLZ') - eressea.process.produce() - assert_equal(1, u:get_item('log')) -end - -function test_process_teach() - u:add_order("LERNEN Holzfaellen") - eressea.process.update_long_order() - eressea.process.study() - x, y = u.faction:get_origin() - assert_equal(1, u:get_skill('forestry')) + u:set_skill('forestry', 1) + u:add_order('MACHE HOLZ') + eressea.process.produce() + assert_equal(1, u:get_item('log')) end function test_process_study() - u:set_skill('forestry', 3) - u2 = _G.unit.create(f, r, 10) + u:add_order("LERNEN Holzfaellen") + eressea.process.update_long_order() + eressea.process.study() + x, y = u.faction:get_origin() + assert_equal(1, u:get_skill('forestry')) +end + +function test_process_teach() + eressea.settings.set("study.random_progress", "0") + u:set_skill('forestry', 3) + u2 = _G.unit.create(f, r, 10) u2:clear_orders() - u2:set_skill('forestry', 1) - u2:add_order("LERNEN Holzfaellen") - u:add_order("LEHREN " .. _G.itoa36(u2.id)) - eressea.process.update_long_order() - eressea.process.study() - assert_equal(2, u2:get_skill('forestry')) + u2:set_skill('forestry', 1) + u2:add_order("LERNEN Holzfaellen") + u:add_order("LEHREN " .. _G.itoa36(u2.id)) + eressea.process.update_long_order() + eressea.process.study() + assert_equal(2, u2:get_skill('forestry')) end function test_process_move() r2 = _G.region.create(1, 0, 'plain') - u:add_order('NACH O') - assert_not_equal(r2, u.region) + u:add_order('NACH O') + assert_not_equal(r2, u.region) eressea.process.update_long_order() - eressea.process.movement() - assert_equal(r2, u.region) + eressea.process.movement() + assert_equal(r2, u.region) end function test_process_leave() r2 = _G.region.create(1, 0, 'plain') b = _G.building.create(r, default_building) u.building = b - assert_equal(b, u.building) - u:add_order('VERLASSEN') - eressea.process.leave() - assert_not_equal(b, u.building) + assert_equal(b, u.building) + u:add_order('VERLASSEN') + eressea.process.leave() + assert_not_equal(b, u.building) end function test_process_name_unit() - u:add_order("BENENNE EINHEIT 'Weasel'") - u:add_order("BESCHREIBE EINHEIT 'Juanita'") - eressea.process.set_name() - assert_equal('Weasel', u.name) - assert_equal('Juanita', u.info) + u:add_order("BENENNE EINHEIT 'Weasel'") + u:add_order("BESCHREIBE EINHEIT 'Juanita'") + eressea.process.set_name() + assert_equal('Weasel', u.name) + assert_equal('Juanita', u.info) end function test_process_name_faction() - u:add_order("BENENNE PARTEI 'Herpderp'") - eressea.process.set_name() - assert_equal('Herpderp', f.name) + u:add_order("BENENNE PARTEI 'Herpderp'") + eressea.process.set_name() + assert_equal('Herpderp', f.name) end function test_process_name_building() - u:add_order("BENENNE GEBAEUDE 'Herpderp'") - u.building = _G.building.create(r, default_building) - eressea.process.set_name() - assert_equal('Herpderp', u.building.name) + u:add_order("BENENNE GEBAEUDE 'Herpderp'") + u.building = _G.building.create(r, default_building) + eressea.process.set_name() + assert_equal('Herpderp', u.building.name) end function test_process_name_ship() - u:add_order("BENENNE SCHIFF 'Herpderp'") - u.ship = _G.ship.create(r, default_ship) - eressea.process.set_name() - assert_equal('Herpderp', u.ship.name) + u:add_order("BENENNE SCHIFF 'Herpderp'") + u.ship = _G.ship.create(r, default_ship) + eressea.process.set_name() + assert_equal('Herpderp', u.ship.name) +end + +function test_process_renumber() + u:add_order("NUMMER EINHEIT 'ii'") + eressea.process.renumber() + assert_equal(666, u.id) end diff --git a/src/bindings/bind_process.c b/src/bindings/bind_process.c index 04d05dda2..5e657fca4 100755 --- a/src/bindings/bind_process.c +++ b/src/bindings/bind_process.c @@ -177,6 +177,19 @@ void process_leave(void) { process_cmd(K_LEAVE, leave_cmd, 0); } +void process_promote(void) { + process_cmd(K_PROMOTION, promotion_cmd, 0); +} + +void process_renumber(void) { + process_cmd(K_NUMBER, renumber_cmd, 0); + renumber_factions(); +} + +void process_restack(void) { + restack_units(); +} + void process_maintenance(void) { region * r; for (r=regions; r; r=r->next) { diff --git a/src/bindings/bind_process.h b/src/bindings/bind_process.h index a5aaedf8f..29c90546a 100755 --- a/src/bindings/bind_process.h +++ b/src/bindings/bind_process.h @@ -25,6 +25,9 @@ void process_battle(void); void process_siege(void); void process_leave(void); void process_maintenance(void); +void process_promotion(void); +void process_renumber(void); +void process_restack(void); #ifdef __cplusplus } diff --git a/src/bindings/process.pkg b/src/bindings/process.pkg index 510be6eb4..146eb43c0 100755 --- a/src/bindings/process.pkg +++ b/src/bindings/process.pkg @@ -22,5 +22,8 @@ module eressea { void process_siege @ siege(void); /* SIEGE */ void process_leave @ leave(void); /* LEAVE */ void process_maintenance @ maintenance(void); /* PAY */ + void process_promote @ promote(void); /* PROMOTE */ + void process_renumber @ renumber(void); /* RENUMBER */ + void process_restack @ restack(void); /* SORT */ } } diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 22fd99549..dddbde16f 100755 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -2703,7 +2703,7 @@ static void reshow(unit * u, struct order *ord, const char *s, param_t p) } } -static int promotion_cmd(unit * u, struct order *ord) +int promotion_cmd(unit * u, struct order *ord) { int money, people; @@ -3005,7 +3005,7 @@ static attrib_type at_number = { ATF_UNIQUE }; -static void renumber_factions(void) +void renumber_factions(void) /* gibt parteien neue nummern */ { struct renum { @@ -3066,7 +3066,7 @@ static void renumber_factions(void) } } -static void reorder(void) +void restack_units(void) { region *r; for (r = regions; r; r = r->next) { @@ -3146,7 +3146,7 @@ static void reorder(void) } } -static int renumber_cmd(unit * u, order * ord) +int renumber_cmd(unit * u, order * ord) { const char *s; int i; @@ -4605,7 +4605,7 @@ void init_processor(void) if (!global.disabled[K_SORT]) { p += 10; - add_proc_global(p, &reorder, "Einheiten sortieren"); + add_proc_global(p, restack_units, "Einheiten sortieren"); } add_proc_order(p, K_PROMOTION, &promotion_cmd, 0, "Heldenbefoerderung"); if (!global.disabled[K_NUMBER]) { diff --git a/src/gamecode/laws.h b/src/gamecode/laws.h index b388520a7..35e94875c 100755 --- a/src/gamecode/laws.h +++ b/src/gamecode/laws.h @@ -52,6 +52,8 @@ extern "C" { extern void new_units(void); extern void quit(void); + extern void renumber_factions(void); + extern void restack_units(void); extern void update_long_order(struct unit *u); extern void sinkships(struct region * r); extern int password_cmd(struct unit *u, struct order *ord); @@ -71,6 +73,8 @@ extern "C" { extern int siege_cmd(struct unit *u, struct order *ord); extern int leave_cmd(struct unit *u, struct order *ord); extern int pay_cmd(struct unit *u, struct order *ord); + extern int promotion_cmd(struct unit *u, struct order *ord); + extern int renumber_cmd(struct unit *u, struct order *ord); #ifdef __cplusplus } From 1b24f14da0de20d17e1ce5979cff0b49161836f5 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 16 Jun 2012 23:39:03 -0700 Subject: [PATCH 343/400] typo fix --- src/bindings/bind_process.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bindings/bind_process.h b/src/bindings/bind_process.h index 29c90546a..8762ba510 100755 --- a/src/bindings/bind_process.h +++ b/src/bindings/bind_process.h @@ -25,7 +25,7 @@ void process_battle(void); void process_siege(void); void process_leave(void); void process_maintenance(void); -void process_promotion(void); +void process_promote(void); void process_renumber(void); void process_restack(void); From f11005c686f672db9cd7991a5d04e4072dace986 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 17 Jun 2012 11:08:48 -0700 Subject: [PATCH 344/400] remove the XONTORMIA & WEREWOLF commands. --- src/CMakeLists.txt | 1 - src/gamecode/laws.c | 19 ++------ src/items/xerewards.c | 2 +- src/kernel/config.c | 19 +------- src/kernel/config.h | 4 -- src/kernel/order.c | 4 -- src/kernel/types.h | 2 - src/modules/xecmd.c | 108 ------------------------------------------ src/modules/xecmd.h | 26 ---------- src/settings.h | 1 - src/util/attrib.c | 59 ++++++++++++++++------- src/util/attrib.h | 1 + 12 files changed, 50 insertions(+), 196 deletions(-) delete mode 100644 src/modules/xecmd.c delete mode 100644 src/modules/xecmd.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c4ae79c8d..c5166356c 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -160,7 +160,6 @@ set (LIB_SRC modules/score.c modules/weather.c modules/wormhole.c - modules/xecmd.c modules/xmas.c triggers/changefaction.c triggers/changerace.c diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index dddbde16f..57756a569 100755 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -88,7 +88,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -#include #include /* libc includes */ @@ -3639,8 +3638,6 @@ void check_long_orders(unit * u) cmistake(u, ord, 52, MSG_EVENT); } break; - case K_WEREWOLF: - /* don't know what WEREWOLF does... */ default: cmistake(u, ord, 52, MSG_EVENT); } @@ -3696,7 +3693,10 @@ void update_long_order(unit * u) case K_BUY: case K_SELL: /* Wenn die Einheit handelt, muß der Default-Befehl gelöscht - * werden. */ + * werden. + * Wird je diese Ausschliesslichkeit aufgehoben, muss man aufpassen + * mit der Reihenfolge von Kaufen, Verkaufen etc., damit es Spielern + * nicht moeglich ist, Schulden zu machen. */ trade = true; break; @@ -3706,13 +3706,6 @@ void update_long_order(unit * u) set_order(&u->thisorder, NULL); break; - case K_WEREWOLF: - set_order(&u->thisorder, copy_order(ord)); - break; - - /* Wird je diese Ausschliesslichkeit aufgehoben, muss man aufpassen - * mit der Reihenfolge von Kaufen, Verkaufen etc., damit es Spielern - * nicht moeglich ist, Schulden zu machen. */ default: break; } @@ -4580,10 +4573,6 @@ void init_processor(void) p += 10; add_proc_order(p, K_GUARD, &guard_on_cmd, 0, "Bewache (an)"); -#if XECMD_MODULE - /* can do together with guard */ - add_proc_order(p, K_XE, &xecmd, 0, "Zeitung"); -#endif p += 10; add_proc_global(p, &encounters, "Zufallsbegegnungen"); diff --git a/src/items/xerewards.c b/src/items/xerewards.c index fb1a9595d..26cd621bb 100644 --- a/src/items/xerewards.c +++ b/src/items/xerewards.c @@ -54,7 +54,7 @@ use_skillpotion(struct unit *u, const struct item_type *itype, int amount, while (sv != u->skills + u->skill_size) { int i; for (i = 0; i != 3; ++i) - learn_skill(u, sv->id, 1.0); + learn_skill(u, (skill_t)sv->id, 1.0); ++sv; } } diff --git a/src/kernel/config.c b/src/kernel/config.c index 63b66f127..eb7dd489e 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -99,18 +99,6 @@ boolean sqlpatch = false; boolean battledebug = false; int turn = 0; -#if XECMD_MODULE -attrib_type at_xontormiaexpress = { - "xontormiaexpress", - DEFAULT_INIT, - DEFAULT_FINALIZE, - DEFAULT_AGE, - a_writeint, - a_readint, - ATF_UNIQUE -}; -#endif - int NewbieImmunity(void) { static int value = -1; @@ -458,8 +446,6 @@ const char *keywords[MAXKEYWORDS] = { "INFO", "PRAEFIX", "PFLANZEN", - "WERWESEN", - "XONTORMIA", "ALLIANZ", "BEANSPRUCHEN", "PROMOTION", @@ -3021,9 +3007,8 @@ void attrib_init(void) register_function((pf_generic) & minimum_wage, "minimum_wage"); at_register(&at_germs); -#if XECMD_MODULE - at_register(&at_xontormiaexpress); /* required for old datafiles */ -#endif + + at_deprecate("xontormiaexpress", a_readint); /* required for old datafiles */ at_register(&at_speedup); at_register(&at_building_action); } diff --git a/src/kernel/config.h b/src/kernel/config.h index 510678c27..6e8a1a142 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -458,10 +458,6 @@ extern "C" { # define count_unit(u) 1 #endif -#if XECMD_MODULE - extern struct attrib_type at_xontormiaexpress; -#endif - #ifdef __cplusplus } #endif diff --git a/src/kernel/order.c b/src/kernel/order.c index 9547d4446..9004fd4db 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -447,8 +447,6 @@ int is_exclusive(const order * ord) switch (kwd) { case K_MOVE: - case K_WEREWOLF: - /* these should not become persistent */ case K_ROUTE: case K_DRIVE: case K_WORK: @@ -513,7 +511,6 @@ int is_long(const order * ord) case K_BUY: case K_SELL: case K_MOVE: - case K_WEREWOLF: case K_ROUTE: case K_DRIVE: case K_WORK: @@ -573,7 +570,6 @@ int is_persistent(const order * ord) int persist = ord->_persistent != 0; switch (kwd) { case K_MOVE: - case K_WEREWOLF: case NOKEYWORD: /* lang, aber niemals persistent! */ return false; diff --git a/src/kernel/types.h b/src/kernel/types.h index ca4a3bc06..3fec2174d 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -137,8 +137,6 @@ typedef enum { K_INFO, /* set player-info */ K_PREFIX, K_PLANT, - K_WEREWOLF, - K_XE, K_ALLIANCE, K_CLAIM, K_PROMOTION, diff --git a/src/modules/xecmd.c b/src/modules/xecmd.c deleted file mode 100644 index e45c611cd..000000000 --- a/src/modules/xecmd.c +++ /dev/null @@ -1,108 +0,0 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#include -#include - -#if XECMD_MODULE -#include "xecmd.h" - -#include - -#include "xecmd.h" - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* util includes */ -#include -#include -#include - -/* libc includes */ -#include -#include -#include - -static void xe_givelaen(unit * u, struct order *ord) -{ - unit *u2 = getunitg(u->region, u->faction); - - if (!u2) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", - "")); - return; - } - i_change(&u2->items, olditemtype[I_LAEN], 5); -} - -static void xe_givepotion(unit * u, struct order *ord) -{ - unit *u2 = getunitg(u->region, u->faction); - - if (!u2) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", - "")); - return; - } - i_change(&u2->items, it_find("skillpotion"), 1); -} - -static void xe_giveballon(unit * u, struct order *ord) -{ - unit *u2 = getunitg(u->region, u->faction); - ship *sh; - - if (!u2) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", - "")); - return; - } - - sh = new_ship(st_find("balloon"), u2->region, u2->faction->locale); - sh->size = 5; - ship_setname(sh, "Xontormia-Ballon"); - leave(u2, true); - u_set_ship(u2, sh); -} - -int xecmd(unit * u, order * ord) -{ - faction *f = u->faction; - - if (a_find(f->attribs, &at_xontormiaexpress)) { - if (get_keyword(ord) == K_XE) { - param_t param; - - init_tokens(ord); - skip_token(); - param = findparam(getstrtoken(), f->locale); - if (param == P_XEPOTION) { - xe_givepotion(u, ord); - } else if (param == P_XEBALLOON) { - xe_giveballon(u, ord); - } else if (param == P_XELAEN) { - xe_givelaen(u, ord); - } - } - } - return 0; -} - -#endif diff --git a/src/modules/xecmd.h b/src/modules/xecmd.h deleted file mode 100644 index cf1beef00..000000000 --- a/src/modules/xecmd.h +++ /dev/null @@ -1,26 +0,0 @@ -/* vi: set ts=2: - +-------------------+ Christian Schlittchen - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2003 | Henning Peters - | | Ingo Wilken - +-------------------+ Stefan Reich - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_MOD_XECMD_H -#define H_MOD_XECMD_H -#ifdef __cplusplus -extern "C" { -#endif - -#if XECMD_MODULE - int xecmd(struct unit *u, struct order *ord); -#endif - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/settings.h b/src/settings.h index fd0607625..087f37cae 100644 --- a/src/settings.h +++ b/src/settings.h @@ -44,7 +44,6 @@ #define SCORE_MODULE 1 #define MUSEUM_MODULE 1 #define ARENA_MODULE 1 -#define XECMD_MODULE 1 #define DUNGEON_MODULE 0 #define CHANGED_CROSSBOWS 0 /* use the WTF_ARMORPIERCING flag */ #undef GLOBAL_WARMING /* number of turns before global warming sets in */ diff --git a/src/util/attrib.c b/src/util/attrib.c index 147b006b5..f76b48427 100644 --- a/src/util/attrib.c +++ b/src/util/attrib.c @@ -22,6 +22,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "log.h" #include "storage.h" +#include + #include #include #include @@ -261,6 +263,16 @@ int a_age(attrib ** p) return (*p != NULL); } +static critbit_tree cb_deprecated = { 0 }; + +void at_deprecate(const char * name, int (*reader)(attrib *, void *, struct storage *)) +{ + char buffer[64]; + size_t len = strlen(name); + len = cb_new_kv(name, len, &reader, sizeof(reader), buffer); + cb_insert(&cb_deprecated, buffer, len); +} + int a_read(struct storage *store, attrib ** attribs, void *owner) { int key, retval = AT_READ_OK; @@ -275,25 +287,38 @@ int a_read(struct storage *store, attrib ** attribs, void *owner) key = __at_hashkey(zText); while (key != -1) { + int (*reader)(attrib *, void *, struct storage *) = 0; attrib_type *at = at_find(key); - if (!at) { - fprintf(stderr, "attribute hash: %d (%s)\n", key, zText); - assert(at || !"attribute not registered"); + attrib * na = 0; + + if (at) { + reader = at->read; + na = a_new(at); + } else { + const void * kv; + cb_find_prefix(&cb_deprecated, zText, strlen(zText)+1, &kv, 1, 0); + if (kv) { + cb_get_kv(kv, &reader, sizeof(reader)); + } else { + fprintf(stderr, "attribute hash: %d (%s)\n", key, zText); + assert(at || !"attribute not registered"); + } } - if (at->read) { - attrib *na = a_new(at); - int i = at->read(na, owner, store); - switch (i) { - case AT_READ_OK: - a_add(attribs, na); - break; - case AT_READ_FAIL: - retval = AT_READ_FAIL; - a_free(na); - break; - default: - assert(!"invalid return value"); - break; + if (reader) { + int i = reader(na, owner, store); + if (na) { + switch (i) { + case AT_READ_OK: + a_add(attribs, na); + break; + case AT_READ_FAIL: + retval = AT_READ_FAIL; + a_free(na); + break; + default: + assert(!"invalid return value"); + break; + } } } else { assert(!"fehler: keine laderoutine für attribut"); diff --git a/src/util/attrib.h b/src/util/attrib.h index a2805e8c7..47c0e29fd 100644 --- a/src/util/attrib.h +++ b/src/util/attrib.h @@ -61,6 +61,7 @@ extern "C" { } attrib_type; extern void at_register(attrib_type * at); + extern void at_deprecate(const char * name, int (*reader)(attrib *, void *, struct storage *)); extern attrib *a_select(attrib * a, const void *data, boolean(*compare) (const attrib *, const void *)); From 1230e2b96203df42d43eb053e6811d5b03515bb8 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 17 Jun 2012 11:28:03 -0700 Subject: [PATCH 345/400] removing PRAY and SACRIFICE orders --- src/kernel/config.c | 2 -- src/kernel/types.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/kernel/config.c b/src/kernel/config.c index eb7dd489e..000f0d5e3 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -438,8 +438,6 @@ const char *keywords[MAXKEYWORDS] = { "EMAIL", "PIRATERIE", "GRUPPE", - "OPFERE", - "BETEN", "SORTIEREN", "JIHAD", "GM", diff --git a/src/kernel/types.h b/src/kernel/types.h index 3fec2174d..3c5a11dcf 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -129,8 +129,6 @@ typedef enum { K_EMAIL, K_PIRACY, K_GROUP, - K_SACRIFICE, - K_PRAY, K_SORT, K_SETJIHAD, K_GM, /* perform GM commands */ From d880bf281a646d0e6b7cf0ae455d1e6849e48e02 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 17 Jun 2012 11:30:11 -0700 Subject: [PATCH 346/400] remove WAR, PEACE, JIHAD --- src/kernel/config.c | 3 --- src/kernel/types.h | 3 --- 2 files changed, 6 deletions(-) diff --git a/src/kernel/config.c b/src/kernel/config.c index 000f0d5e3..e66dc0f79 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -399,8 +399,6 @@ const char *keywords[MAXKEYWORDS] = { "ENDE", "FAHREN", "NUMMER", - "KRIEG", - "FRIEDEN", "FOLGEN", "FORSCHEN", "GIB", @@ -439,7 +437,6 @@ const char *keywords[MAXKEYWORDS] = { "PIRATERIE", "GRUPPE", "SORTIEREN", - "JIHAD", "GM", "INFO", "PRAEFIX", diff --git a/src/kernel/types.h b/src/kernel/types.h index 3c5a11dcf..ed895bfdd 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -90,8 +90,6 @@ typedef enum { K_END, K_DRIVE, K_NUMBER, - K_WAR, - K_PEACE, K_FOLLOW, K_RESEARCH, K_GIVE, @@ -130,7 +128,6 @@ typedef enum { K_PIRACY, K_GROUP, K_SORT, - K_SETJIHAD, K_GM, /* perform GM commands */ K_INFO, /* set player-info */ K_PREFIX, From d02857ebb9ff71b5946dfb1f0624472e8d6dcadd Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 17 Jun 2012 12:51:48 -0700 Subject: [PATCH 347/400] binding COMBATSPELL to Lua --- scripts/tests/bindings.lua | 1 + src/bindings/bind_process.c | 4 ++++ src/bindings/bind_process.h | 1 + src/bindings/process.pkg | 1 + src/gamecode/laws.c | 2 +- src/gamecode/laws.h | 1 + 6 files changed, 9 insertions(+), 1 deletion(-) diff --git a/scripts/tests/bindings.lua b/scripts/tests/bindings.lua index 8f8209b13..8715e501a 100755 --- a/scripts/tests/bindings.lua +++ b/scripts/tests/bindings.lua @@ -36,6 +36,7 @@ function test_process() assert_equal("function", _G.type(eressea.process.promote)) assert_equal("function", _G.type(eressea.process.renumber)) assert_equal("function", _G.type(eressea.process.restack)) + assert_equal("function", _G.type(eressea.process.set_spells)) end function test_settings() diff --git a/src/bindings/bind_process.c b/src/bindings/bind_process.c index 5e657fca4..eb7a72052 100755 --- a/src/bindings/bind_process.c +++ b/src/bindings/bind_process.c @@ -190,6 +190,10 @@ void process_restack(void) { restack_units(); } +void process_setspells(void) { + process_cmd(K_COMBATSPELL, combatspell_cmd, 0); +} + void process_maintenance(void) { region * r; for (r=regions; r; r=r->next) { diff --git a/src/bindings/bind_process.h b/src/bindings/bind_process.h index 8762ba510..804414795 100755 --- a/src/bindings/bind_process.h +++ b/src/bindings/bind_process.h @@ -28,6 +28,7 @@ void process_maintenance(void); void process_promote(void); void process_renumber(void); void process_restack(void); +void process_setspells(void); #ifdef __cplusplus } diff --git a/src/bindings/process.pkg b/src/bindings/process.pkg index 146eb43c0..7504773fa 100755 --- a/src/bindings/process.pkg +++ b/src/bindings/process.pkg @@ -25,5 +25,6 @@ module eressea { void process_promote @ promote(void); /* PROMOTE */ void process_renumber @ renumber(void); /* RENUMBER */ void process_restack @ restack(void); /* SORT */ + void process_setspells @ set_spells(void); /* COMBATSPELL */ } } diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 57756a569..6d0c50ad2 100755 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -2838,7 +2838,7 @@ int status_cmd(unit * u, struct order *ord) return 0; } -static int combatspell_cmd(unit * u, struct order *ord) +int combatspell_cmd(unit * u, struct order *ord) { const char *s; int level = 0; diff --git a/src/gamecode/laws.h b/src/gamecode/laws.h index 35e94875c..5a6664764 100755 --- a/src/gamecode/laws.h +++ b/src/gamecode/laws.h @@ -75,6 +75,7 @@ extern "C" { extern int pay_cmd(struct unit *u, struct order *ord); extern int promotion_cmd(struct unit *u, struct order *ord); extern int renumber_cmd(struct unit *u, struct order *ord); + extern int combatspell_cmd(struct unit *u, struct order *ord); #ifdef __cplusplus } From 573d4c3e97300c0553ba4f46a63087ce0b6f3854 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 17 Jun 2012 15:55:23 -0700 Subject: [PATCH 348/400] binding HELP to Lua --- scripts/tests/bindings.lua | 1 + src/bindings/bind_process.c | 5 +++++ src/bindings/bind_process.h | 1 + src/bindings/process.pkg | 1 + src/gamecode/laws.c | 7 +------ 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/scripts/tests/bindings.lua b/scripts/tests/bindings.lua index 8715e501a..bad3d454d 100755 --- a/scripts/tests/bindings.lua +++ b/scripts/tests/bindings.lua @@ -37,6 +37,7 @@ function test_process() assert_equal("function", _G.type(eressea.process.renumber)) assert_equal("function", _G.type(eressea.process.restack)) assert_equal("function", _G.type(eressea.process.set_spells)) + assert_equal("function", _G.type(eressea.process.set_help)) end function test_settings() diff --git a/src/bindings/bind_process.c b/src/bindings/bind_process.c index eb7a72052..ae25eb109 100755 --- a/src/bindings/bind_process.c +++ b/src/bindings/bind_process.c @@ -194,6 +194,11 @@ void process_setspells(void) { process_cmd(K_COMBATSPELL, combatspell_cmd, 0); } +void process_sethelp(void) { + process_cmd(K_ALLY, ally_cmd, 0); +} + + void process_maintenance(void) { region * r; for (r=regions; r; r=r->next) { diff --git a/src/bindings/bind_process.h b/src/bindings/bind_process.h index 804414795..b12cd0c24 100755 --- a/src/bindings/bind_process.h +++ b/src/bindings/bind_process.h @@ -29,6 +29,7 @@ void process_promote(void); void process_renumber(void); void process_restack(void); void process_setspells(void); +void process_sethelp(void); #ifdef __cplusplus } diff --git a/src/bindings/process.pkg b/src/bindings/process.pkg index 7504773fa..5ffab96d2 100755 --- a/src/bindings/process.pkg +++ b/src/bindings/process.pkg @@ -26,5 +26,6 @@ module eressea { void process_renumber @ renumber(void); /* RENUMBER */ void process_restack @ restack(void); /* SORT */ void process_setspells @ set_spells(void); /* COMBATSPELL */ + void process_sethelp @ set_help(void); /* HELP */ } } diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 6d0c50ad2..d1fb4a70a 100755 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -3654,6 +3654,7 @@ void update_long_order(unit * u) boolean trade = false; boolean hunger = LongHunger(u); + freset(u, UFL_MOVED); freset(u, UFL_LONGACTION); if (hunger) { /* Hungernde Einheiten führen NUR den default-Befehl aus */ @@ -4428,11 +4429,6 @@ static void maintain_buildings_1(region * r) maintain_buildings(r, false); } -static void reset_moved(unit * u) -{ - freset(u, UFL_MOVED); -} - /** warn about passwords that are not US ASCII. * even though passwords are technically UTF8 strings, the server receives * them as part of the Subject of an email when reports are requested. @@ -4476,7 +4472,6 @@ void init_processor(void) add_proc_order(p, K_GROUP, &group_cmd, 0, NULL); p += 10; - add_proc_unit(p, &reset_moved, "Instant-Befehle"); add_proc_order(p, K_QUIT, &quit_cmd, 0, NULL); add_proc_order(p, K_URSPRUNG, &origin_cmd, 0, NULL); add_proc_order(p, K_ALLY, &ally_cmd, 0, NULL); From 648de4d36cf3999c16dfe4d26f3a5deef5d3aa9e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 17 Jun 2012 17:24:23 -0700 Subject: [PATCH 349/400] Binding CAST, ENTER, CONTACT to Lua --- scripts/tests/bindings.lua | 3 + scripts/tests/orders.lua | 26 ++++++++ src/bindings/bind_process.c | 15 +++++ src/bindings/bind_process.h | 3 + src/bindings/process.pkg | 3 + src/gamecode/laws.c | 114 ++++++++++++++++++------------------ src/gamecode/laws.h | 4 +- 7 files changed, 109 insertions(+), 59 deletions(-) diff --git a/scripts/tests/bindings.lua b/scripts/tests/bindings.lua index bad3d454d..fc325c608 100755 --- a/scripts/tests/bindings.lua +++ b/scripts/tests/bindings.lua @@ -38,6 +38,9 @@ function test_process() assert_equal("function", _G.type(eressea.process.restack)) assert_equal("function", _G.type(eressea.process.set_spells)) assert_equal("function", _G.type(eressea.process.set_help)) + assert_equal("function", _G.type(eressea.process.contact)) + assert_equal("function", _G.type(eressea.process.enter)) + assert_equal("function", _G.type(eressea.process.magic)) end function test_settings() diff --git a/scripts/tests/orders.lua b/scripts/tests/orders.lua index 0e14e3653..076e27be6 100755 --- a/scripts/tests/orders.lua +++ b/scripts/tests/orders.lua @@ -190,3 +190,29 @@ function test_process_renumber() assert_equal(666, u.id) end +function test_process_enter() + b = _G.building.create(r, default_building) + u:add_order("BETRETEN GEBAEUDE " .. _G.itoa36(b.id)) + eressea.process.enter(1) + assert_equal(b, u.building) +end + +function test_process_restack() + eressea.process.restack() +end + +function test_process_setspells() + eressea.process.set_spells() +end + +function test_process_help() + eressea.process.set_help() +end + +function test_process_contact() + eressea.process.contact() +end + +function test_process_magic() + eressea.process.magic() +end diff --git a/src/bindings/bind_process.c b/src/bindings/bind_process.c index ae25eb109..5010bf2f9 100755 --- a/src/bindings/bind_process.c +++ b/src/bindings/bind_process.c @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -198,6 +199,20 @@ void process_sethelp(void) { process_cmd(K_ALLY, ally_cmd, 0); } +void process_contact(void) { + process_cmd(K_CONTACT, contact_cmd, 0); +} + +void process_magic(void) { + magic(); +} + +void process_enter(int final) { + region * r; + for (r=regions; r; r=r->next) { + do_enter(r, final); + } +} void process_maintenance(void) { region * r; diff --git a/src/bindings/bind_process.h b/src/bindings/bind_process.h index b12cd0c24..7fd9a1508 100755 --- a/src/bindings/bind_process.h +++ b/src/bindings/bind_process.h @@ -30,6 +30,9 @@ void process_renumber(void); void process_restack(void); void process_setspells(void); void process_sethelp(void); +void process_contact(void); +void process_enter(int final); +void process_magic(void); #ifdef __cplusplus } diff --git a/src/bindings/process.pkg b/src/bindings/process.pkg index 5ffab96d2..81a189633 100755 --- a/src/bindings/process.pkg +++ b/src/bindings/process.pkg @@ -27,5 +27,8 @@ module eressea { void process_restack @ restack(void); /* SORT */ void process_setspells @ set_spells(void); /* COMBATSPELL */ void process_sethelp @ set_help(void); /* HELP */ + void process_contact @ contact(void); /* CONTACT */ + void process_enter @ enter(int message); /* ENTER */ + void process_magic @ magic(void); /* CAST */ } } diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index d1fb4a70a..1d925f98f 100755 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -135,8 +135,7 @@ static void checkorders(void) { faction *f; - if (verbosity >= 1) - puts(" - Warne spaete Spieler..."); + log_info(" - Warne spaete Spieler..."); for (f = factions; f; f = f->next) if (!is_monsters(f) && turn - f->lastorders == NMRTimeout() - 1) ADDMSG(&f->msgs, msg_message("turnreminder", "")); @@ -966,8 +965,7 @@ void demographics(void) remove_empty_units(); - if (verbosity >= 1) - puts(" - Einwanderung..."); + log_info(" - Einwanderung..."); for (r = regions; r; r = r->next) { if (r->land && r->land->newpeasants) { int rp = rpeasants(r) + r->land->newpeasants; @@ -1078,7 +1076,7 @@ int can_contact(const region * r, const unit * u, const unit * u2) { return (alliedunit(u, u2->faction, HELP_GIVE)); } -void contact_cmd(unit * u, order * ord, int final) +int contact_cmd(unit * u, order * ord) { /* unit u kontaktiert unit u2. Dies setzt den contact einfach auf 1 - * ein richtiger toggle ist (noch?) nicht noetig. die region als @@ -1094,13 +1092,12 @@ void contact_cmd(unit * u, order * ord, int final) if (u2 != NULL) { if (!can_contact(r, u, u2)) { - if (final) { - cmistake(u, u->thisorder, 23, MSG_EVENT); - } - return; + cmistake(u, u->thisorder, 23, MSG_EVENT); + return -1; } usetcontact(u, u2); } + return 0; } int leave_cmd(unit * u, struct order *ord) @@ -1316,19 +1313,23 @@ int enter_building(unit * u, order * ord, int id, int report) return 0; } -static void do_misc(region * r, int is_final_attempt) +static void do_contact(region * r) { - unit **uptr, *uc; - - for (uc = r->units; uc; uc = uc->next) { + unit * u; + for (u = r->units; u; u = u->next) { order *ord; - for (ord = uc->orders; ord; ord = ord->next) { + for (ord = u->orders; ord; ord = ord->next) { keyword_t kwd = get_keyword(ord); if (kwd == K_CONTACT) { - contact_cmd(uc, ord, is_final_attempt); + contact_cmd(u, ord); } } } +} + +void do_enter(struct region *r, int is_final_attempt) +{ + unit **uptr; for (uptr = &r->units; *uptr;) { unit *u = *uptr; @@ -1407,38 +1408,6 @@ static void do_misc(region * r, int is_final_attempt) } } -void quit(void) -{ - faction **fptr = &factions; - while (*fptr) { - faction *f = *fptr; - if (f->flags & FFL_QUIT) { - if (EnhancedQuit()) { - /* this doesn't work well (use object_name()) */ - attrib *a = a_find(f->attribs, &at_object); - if (a) { - variant var; - object_type type; - var.i = 0; - object_get(a, &type, &var); - assert(var.i && type == TINTEGER); - if (var.i) { - int f2_id = var.i; - faction *f2 = findfaction(f2_id); - - assert(f2_id > 0); - assert(f2 != NULL); - transfer_faction(f, f2); - } - } - } - destroyfaction(f); - } - if (*fptr == f) - fptr = &f->next; - } -} - int dropouts[2]; int *age = NULL; @@ -1517,9 +1486,39 @@ static void remove_idle_players(void) } } } +} - if (verbosity >= 1) - puts(" - beseitige leere Einheiten und leere Parteien..."); +void quit(void) +{ + faction **fptr = &factions; + while (*fptr) { + faction *f = *fptr; + if (f->flags & FFL_QUIT) { + if (EnhancedQuit()) { + /* this doesn't work well (use object_name()) */ + attrib *a = a_find(f->attribs, &at_object); + if (a) { + variant var; + object_type type; + var.i = 0; + object_get(a, &type, &var); + assert(var.i && type == TINTEGER); + if (var.i) { + int f2_id = var.i; + faction *f2 = findfaction(f2_id); + + assert(f2_id > 0); + assert(f2 != NULL); + transfer_faction(f, f2); + } + } + } + destroyfaction(f); + } + if (*fptr == f) + fptr = &f->next; + } + remove_idle_players(); remove_empty_units(); } @@ -4416,12 +4415,12 @@ void do_siege(region * r) static void enter_1(region * r) { - do_misc(r, 0); + do_enter(r, 0); } static void enter_2(region * r) { - do_misc(r, 1); + do_enter(r, 1); } static void maintain_buildings_1(region * r) @@ -4492,9 +4491,10 @@ void init_processor(void) p += 10; add_proc_global(p, &age_factions, "Parteienalter++"); add_proc_order(p, K_MAIL, &mail_cmd, 0, "Botschaften"); + add_proc_order(p, K_CONTACT, &contact_cmd, 0, "Kontaktieren"); p += 10; /* all claims must be done before we can USE */ - add_proc_region(p, &enter_1, "Kontaktieren & Betreten (1. Versuch)"); + add_proc_region(p, &enter_1, "Betreten (1. Versuch)"); add_proc_order(p, K_USE, &use_cmd, 0, "Benutzen"); if (!global.disabled[K_GM]) { @@ -4515,7 +4515,7 @@ void init_processor(void) } p += 10; /* can't allow reserve before siege (weapons) */ - add_proc_region(p, &enter_1, "Kontaktieren & Betreten (2. Versuch)"); + add_proc_region(p, &enter_1, "Betreten (2. Versuch)"); add_proc_order(p, K_RESERVE, &reserve_cmd, 0, "Reservieren"); add_proc_order(p, K_CLAIM, &claim_cmd, 0, NULL); add_proc_unit(p, &follow_unit, "Folge auf Einheiten setzen"); @@ -4532,7 +4532,6 @@ void init_processor(void) p += 10; /* QUIT fuer sich alleine */ add_proc_global(p, quit, "Sterben"); - add_proc_global(p, remove_idle_players, "remove idle players"); if (!global.disabled[K_CAST]) { p += 10; @@ -4553,7 +4552,7 @@ void init_processor(void) add_proc_postregion(p, &split_allocations, "Produktion II"); p += 10; - add_proc_region(p, &enter_2, "Kontaktieren & Betreten (3. Versuch)"); + add_proc_region(p, &enter_2, "Betreten (3. Versuch)"); p += 10; add_proc_region(p, &sinkships, "Schiffe sinken"); @@ -4615,8 +4614,7 @@ void processorders(void) do_markets(); } - if (verbosity >= 1) - puts(" - Attribute altern"); + log_info(" - Attribute altern"); ageing(); remove_empty_units(); @@ -4640,7 +4638,7 @@ int writepasswd(void) F = cfopen(zText, "w"); if (F) { faction *f; - puts("writing passwords..."); + log_info("writing passwords..."); for (f = factions; f; f = f->next) { fprintf(F, "%s:%s:%s:%s:%u\n", diff --git a/src/gamecode/laws.h b/src/gamecode/laws.h index 5a6664764..3dd492153 100755 --- a/src/gamecode/laws.h +++ b/src/gamecode/laws.h @@ -48,7 +48,6 @@ extern "C" { extern int enter_building(struct unit *u, struct order *ord, int id, int report); extern int enter_ship(struct unit *u, struct order *ord, int id, int report); - extern void contact_cmd(struct unit *u, struct order *ord, int final); extern void new_units(void); extern void quit(void); @@ -56,6 +55,8 @@ extern "C" { extern void restack_units(void); extern void update_long_order(struct unit *u); extern void sinkships(struct region * r); + extern void do_enter(struct region *r, int is_final_attempt); + extern int password_cmd(struct unit *u, struct order *ord); extern int banner_cmd(struct unit *u, struct order *ord); extern int email_cmd(struct unit *u, struct order *ord); @@ -76,6 +77,7 @@ extern "C" { extern int promotion_cmd(struct unit *u, struct order *ord); extern int renumber_cmd(struct unit *u, struct order *ord); extern int combatspell_cmd(struct unit *u, struct order *ord); + extern int contact_cmd(struct unit *u, struct order *ord); #ifdef __cplusplus } From 1298684fd9623b5f8a6a5dc424b06ea0c6753255 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 17 Jun 2012 17:55:46 -0700 Subject: [PATCH 350/400] bind GIVE CONTROL to lua --- scripts/tests/bindings.lua | 1 + scripts/tests/orders.lua | 8 ++++++++ src/bindings/bind_process.c | 4 ++++ src/bindings/bind_process.h | 1 + src/bindings/process.pkg | 1 + 5 files changed, 15 insertions(+) diff --git a/scripts/tests/bindings.lua b/scripts/tests/bindings.lua index fc325c608..61c8ed93c 100755 --- a/scripts/tests/bindings.lua +++ b/scripts/tests/bindings.lua @@ -41,6 +41,7 @@ function test_process() assert_equal("function", _G.type(eressea.process.contact)) assert_equal("function", _G.type(eressea.process.enter)) assert_equal("function", _G.type(eressea.process.magic)) + assert_equal("function", _G.type(eressea.process.give_control)) end function test_settings() diff --git a/scripts/tests/orders.lua b/scripts/tests/orders.lua index 076e27be6..890c7b825 100755 --- a/scripts/tests/orders.lua +++ b/scripts/tests/orders.lua @@ -213,6 +213,14 @@ function test_process_contact() eressea.process.contact() end +function test_process_battle() + eressea.process.battle() +end + function test_process_magic() eressea.process.magic() end + +function test_process_give_control() + eressea.process.give_control() +end diff --git a/src/bindings/bind_process.c b/src/bindings/bind_process.c index 5010bf2f9..5244ef317 100755 --- a/src/bindings/bind_process.c +++ b/src/bindings/bind_process.c @@ -207,6 +207,10 @@ void process_magic(void) { magic(); } +void process_give_control(void) { + process_cmd(K_CONTACT, give_control_cmd, 0); +} + void process_enter(int final) { region * r; for (r=regions; r; r=r->next) { diff --git a/src/bindings/bind_process.h b/src/bindings/bind_process.h index 7fd9a1508..128692c49 100755 --- a/src/bindings/bind_process.h +++ b/src/bindings/bind_process.h @@ -33,6 +33,7 @@ void process_sethelp(void); void process_contact(void); void process_enter(int final); void process_magic(void); +void process_give_control(void); #ifdef __cplusplus } diff --git a/src/bindings/process.pkg b/src/bindings/process.pkg index 81a189633..339fa6a7c 100755 --- a/src/bindings/process.pkg +++ b/src/bindings/process.pkg @@ -30,5 +30,6 @@ module eressea { void process_contact @ contact(void); /* CONTACT */ void process_enter @ enter(int message); /* ENTER */ void process_magic @ magic(void); /* CAST */ + void process_give_control @ give_control(void); /* GIVE CONTROL */ } } From e579210fec9416caa37c471fde97ce7b7aae4d05 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 17 Jun 2012 18:52:51 -0700 Subject: [PATCH 351/400] kill the eventbus, it was never used --- scripts/tests/common.lua | 12 --------- src/CMakeLists.txt | 1 - src/bindings/bindings.c | 40 ---------------------------- src/util/eventbus.c | 57 ---------------------------------------- src/util/eventbus.h | 29 -------------------- 5 files changed, 139 deletions(-) delete mode 100644 src/util/eventbus.c delete mode 100644 src/util/eventbus.h diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index b1b69c211..3fe4a1ae8 100755 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -46,18 +46,6 @@ function setup() eressea.settings.set("rules.economy.food", "4") end -function DISABLE_test_eventbus_fire() - local r = region.create(0, 0, "plain") - local f = faction.create("noreply@eressea.de", "human", "de") - local u = unit.create(f, r) - - function compare_f(u, event, f) - assert_equal(u.faction, f) - end - eventbus.register(u, "weird", compare_f) - eventbus.fire(u, "weird", f) -end - function test_fleeing_units_can_be_transported() local r = region.create(0, 0, "plain") local r1 = region.create(1, 0, "plain") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c5166356c..1cc33a9b9 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -181,7 +181,6 @@ set (LIB_SRC util/console.c util/crmessage.c util/dice.c - util/eventbus.c util/event.c util/filereader.c util/functions.c diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index f4832a727..12480b8a5 100755 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -62,7 +62,6 @@ without prior permission by the authors of Eressea. #include #include #include -#include #include #include #include @@ -1031,39 +1030,6 @@ static void event_cb(void *sender, const char *event, void *udata) lua_pcall(L, nargs, 0, 0); } -/* arguments: - * 1: sender (usertype) - * 2: event (string) - * 3: handler (function) - * 4: arguments (any, *optional*) -**/ -static int tolua_eventbus_register(lua_State * L) -{ - void *sender = tolua_tousertype(L, 1, 0); - const char *event = tolua_tostring(L, 2, 0); - event_args *args = (event_args *)malloc(sizeof(event_args)); - args->sendertype = sender ? tolua_typename(L, 1) : NULL; - lua_pushvalue(L, 3); - args->hfunction = luaL_ref(L, LUA_REGISTRYINDEX); - if (lua_type(L, 4) != LUA_TNONE) { - lua_pushvalue(L, 4); - args->hargs = luaL_ref(L, LUA_REGISTRYINDEX); - } else { - args->hargs = 0; - } - eventbus_register(sender, event, &event_cb, &args_free, args); - return 0; -} - -static int tolua_eventbus_fire(lua_State * L) -{ - void *sender = tolua_tousertype(L, 1, 0); - const char *event = tolua_tostring(L, 2, 0); - void *args = NULL; - eventbus_fire(sender, event, args); - return 0; -} - static int tolua_report_unit(lua_State * L) { char buffer[512]; @@ -1145,12 +1111,6 @@ int tolua_bindings_open(lua_State * L) #endif tolua_variable(L, TOLUA_CAST "text", tolua_get_spell_text, 0); } tolua_endmodule(L); - tolua_module(L, TOLUA_CAST "eventbus", 1); - tolua_beginmodule(L, TOLUA_CAST "eventbus"); - { - tolua_function(L, TOLUA_CAST "register", &tolua_eventbus_register); - tolua_function(L, TOLUA_CAST "fire", &tolua_eventbus_fire); - } tolua_endmodule(L); tolua_module(L, TOLUA_CAST "report", 1); tolua_beginmodule(L, TOLUA_CAST "report"); { diff --git a/src/util/eventbus.c b/src/util/eventbus.c deleted file mode 100644 index d4c7829fd..000000000 --- a/src/util/eventbus.c +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include "eventbus.h" - -/* -** first iteration. it is slow, and a proof of the concept - the simplest -** thing that would work, a.k.a. should be refectored when required. -*/ - -typedef struct listener { - struct listener *next; - event_handler callback; - event_arg_free destroy; - void *sender; - char *event; - void *arguments; -} listener; - -static listener *listeners; - -void eventbus_fire(void *sender, const char *event, void *args) -{ - listener *lst = listeners; - while (lst) { - int i = strcmp(lst->event, event); - if (i > 0) - break; - if (i == 0) { - if (!lst->sender || lst->sender == sender) { - lst->callback(sender, event, args); - } - } - lst = lst->next; - } -} - -void -eventbus_register(void *sender, const char *event, event_handler cb, - event_arg_free arg_free, void *args) -{ - listener *lst; - listener **lstp = &listeners; - while (*lstp) { - lst = *lstp; - if (strcmp(lst->event, event) >= 0) { - break; - } - lstp = &lst->next; - } - lst = malloc(sizeof(listener)); - lst->sender = sender; - lst->arguments = args; - lst->callback = cb; - lst->destroy = arg_free; - lst->event = strdup(event); - lst->next = *lstp; - *lstp = lst; -} diff --git a/src/util/eventbus.h b/src/util/eventbus.h deleted file mode 100644 index 6bd266e51..000000000 --- a/src/util/eventbus.h +++ /dev/null @@ -1,29 +0,0 @@ -/* vi: set ts=2: - +-------------------+ - | | Enno Rehling - | Eressea PBEM host | Katja Zedel - | (c) 1998 - 2010 | Christian Schlittchen - | | - +-------------------+ - - This program may not be used, modified or distributed - without prior permission by the authors of Eressea. -*/ - -#ifndef H_UTIL_EVTBUS -#define H_UTIL_EVTBUS - -#ifdef __cplusplus -extern "C" { -#endif - - typedef void (*event_handler) (void *, const char *, void *); - typedef void (*event_arg_free) (void *); - void eventbus_fire(void *sender, const char *event, void *args); - void eventbus_register(void *sender, const char *event, - event_handler callback, event_arg_free arg_free, void *args); - -#ifdef __cplusplus -} -#endif -#endif From 64a91a75a1105dbb240eb68c7877cb57117bdc2b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 17 Jun 2012 22:31:30 -0700 Subject: [PATCH 352/400] bind regeneration (of health and aura) to Lua --- scripts/tests/bindings.lua | 1 + scripts/tests/orders.lua | 5 +++++ src/bindings/bind_process.c | 5 +++++ src/bindings/bind_process.h | 1 + src/bindings/process.pkg | 1 + src/gamecode/laws.c | 27 ++++++++++----------------- src/gamecode/laws.h | 1 + src/kernel/magic.c | 2 +- src/kernel/magic.h | 2 +- 9 files changed, 26 insertions(+), 19 deletions(-) diff --git a/scripts/tests/bindings.lua b/scripts/tests/bindings.lua index 61c8ed93c..9e937e985 100755 --- a/scripts/tests/bindings.lua +++ b/scripts/tests/bindings.lua @@ -42,6 +42,7 @@ function test_process() assert_equal("function", _G.type(eressea.process.enter)) assert_equal("function", _G.type(eressea.process.magic)) assert_equal("function", _G.type(eressea.process.give_control)) + assert_equal("function", _G.type(eressea.process.regeneration)) end function test_settings() diff --git a/scripts/tests/orders.lua b/scripts/tests/orders.lua index 890c7b825..d2d95b743 100755 --- a/scripts/tests/orders.lua +++ b/scripts/tests/orders.lua @@ -224,3 +224,8 @@ end function test_process_give_control() eressea.process.give_control() end + +function test_process_regeneration() + eressea.process.regeneration() +end + diff --git a/src/bindings/bind_process.c b/src/bindings/bind_process.c index 5244ef317..c52d66f8e 100755 --- a/src/bindings/bind_process.c +++ b/src/bindings/bind_process.c @@ -211,6 +211,11 @@ void process_give_control(void) { process_cmd(K_CONTACT, give_control_cmd, 0); } +void process_regeneration(void) { + monthly_healing(); + regenerate_aura(); +} + void process_enter(int final) { region * r; for (r=regions; r; r=r->next) { diff --git a/src/bindings/bind_process.h b/src/bindings/bind_process.h index 128692c49..61bc5e573 100755 --- a/src/bindings/bind_process.h +++ b/src/bindings/bind_process.h @@ -34,6 +34,7 @@ void process_contact(void); void process_enter(int final); void process_magic(void); void process_give_control(void); +void process_regeneration(void); #ifdef __cplusplus } diff --git a/src/bindings/process.pkg b/src/bindings/process.pkg index 339fa6a7c..5a86b632d 100755 --- a/src/bindings/process.pkg +++ b/src/bindings/process.pkg @@ -31,5 +31,6 @@ module eressea { void process_enter @ enter(int message); /* ENTER */ void process_magic @ magic(void); /* CAST */ void process_give_control @ give_control(void); /* GIVE CONTROL */ + void process_regeneration @ regeneration(void); /* regen health & aura */ } } diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 1d925f98f..313c68469 100755 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -1514,9 +1514,16 @@ void quit(void) } } destroyfaction(f); + } else { + ++f->age; + if (f->age + 1 < NewbieImmunity()) { + ADDMSG(&f->msgs, msg_message("newbieimmunity", "turns", + NewbieImmunity() - f->age - 1)); + } } - if (*fptr == f) + if (*fptr == f) { fptr = &f->next; + } } remove_idle_players(); remove_empty_units(); @@ -3773,7 +3780,7 @@ static double heal_factor(const unit * u) } } -static void monthly_healing(void) +void monthly_healing(void) { region *r; static const curse_type *heal_ct = NULL; @@ -3979,19 +3986,6 @@ static void update_spells(void) } } -static void age_factions(void) -{ - faction *f; - - for (f = factions; f; f = f->next) { - ++f->age; - if (f->age + 1 < NewbieImmunity()) { - ADDMSG(&f->msgs, msg_message("newbieimmunity", "turns", - NewbieImmunity() - f->age - 1)); - } - } -} - int use_cmd(unit * u, struct order *ord) { const char *t; @@ -4489,7 +4483,6 @@ void init_processor(void) } p += 10; - add_proc_global(p, &age_factions, "Parteienalter++"); add_proc_order(p, K_MAIL, &mail_cmd, 0, "Botschaften"); add_proc_order(p, K_CONTACT, &contact_cmd, 0, "Kontaktieren"); @@ -4580,7 +4573,7 @@ void init_processor(void) p += 10; add_proc_global(p, &monthly_healing, "Regeneration (HP)"); - add_proc_global(p, ®eneration_magiepunkte, "Regeneration (Aura)"); + add_proc_global(p, ®enerate_aura, "Regeneration (Aura)"); if (!global.disabled[K_DEFAULT]) { add_proc_global(p, &defaultorders, "Defaults setzen"); } diff --git a/src/gamecode/laws.h b/src/gamecode/laws.h index 3dd492153..583a07af3 100755 --- a/src/gamecode/laws.h +++ b/src/gamecode/laws.h @@ -51,6 +51,7 @@ extern "C" { extern void new_units(void); extern void quit(void); + extern void monthly_healing(void); extern void renumber_factions(void); extern void restack_units(void); extern void update_long_order(struct unit *u); diff --git a/src/kernel/magic.c b/src/kernel/magic.c index a0bbef2a0..e716528ce 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -1445,7 +1445,7 @@ static double regeneration(unit * u) return aura; } -void regeneration_magiepunkte(void) +void regenerate_aura(void) { region *r; unit *u; diff --git a/src/kernel/magic.h b/src/kernel/magic.h index 07ec04772..0f5b6b56d 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -192,7 +192,7 @@ typedef struct sc_mage { void magic(void); - void regeneration_magiepunkte(void); + void regenerate_aura(void); extern struct attrib_type at_seenspell; extern struct attrib_type at_mage; From 59665de7bae7b1da671409d23470cad879401f19 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 17 Jun 2012 23:13:58 -0700 Subject: [PATCH 353/400] binding GUARD to lua --- scripts/tests/bindings.lua | 2 ++ scripts/tests/orders.lua | 7 +++++++ src/bindings/bind_process.c | 8 ++++++++ src/bindings/bind_process.h | 2 ++ src/bindings/process.pkg | 2 ++ src/gamecode/laws.c | 4 ++-- src/gamecode/laws.h | 2 ++ 7 files changed, 25 insertions(+), 2 deletions(-) diff --git a/scripts/tests/bindings.lua b/scripts/tests/bindings.lua index 9e937e985..b37606530 100755 --- a/scripts/tests/bindings.lua +++ b/scripts/tests/bindings.lua @@ -43,6 +43,8 @@ function test_process() assert_equal("function", _G.type(eressea.process.magic)) assert_equal("function", _G.type(eressea.process.give_control)) assert_equal("function", _G.type(eressea.process.regeneration)) + assert_equal("function", _G.type(eressea.process.guard_on)) + assert_equal("function", _G.type(eressea.process.guard_off)) end function test_settings() diff --git a/scripts/tests/orders.lua b/scripts/tests/orders.lua index d2d95b743..b46e0c1c7 100755 --- a/scripts/tests/orders.lua +++ b/scripts/tests/orders.lua @@ -229,3 +229,10 @@ function test_process_regeneration() eressea.process.regeneration() end +function test_process_guard_on() + eressea.process.guard_on() +end + +function test_process_guard_off() + eressea.process.guard_off() +end diff --git a/src/bindings/bind_process.c b/src/bindings/bind_process.c index c52d66f8e..926655e66 100755 --- a/src/bindings/bind_process.c +++ b/src/bindings/bind_process.c @@ -211,6 +211,14 @@ void process_give_control(void) { process_cmd(K_CONTACT, give_control_cmd, 0); } +void process_guard_on(void) { + process_cmd(K_GUARD, guard_on_cmd, PROC_LAND_REGION); +} + +void process_guard_off(void) { + process_cmd(K_GUARD, guard_off_cmd, PROC_LAND_REGION); +} + void process_regeneration(void) { monthly_healing(); regenerate_aura(); diff --git a/src/bindings/bind_process.h b/src/bindings/bind_process.h index 61bc5e573..4a9ebc147 100755 --- a/src/bindings/bind_process.h +++ b/src/bindings/bind_process.h @@ -35,6 +35,8 @@ void process_enter(int final); void process_magic(void); void process_give_control(void); void process_regeneration(void); +void process_guard_on(void); +void process_guard_off(void); #ifdef __cplusplus } diff --git a/src/bindings/process.pkg b/src/bindings/process.pkg index 5a86b632d..bf6f4a83c 100755 --- a/src/bindings/process.pkg +++ b/src/bindings/process.pkg @@ -32,5 +32,7 @@ module eressea { void process_magic @ magic(void); /* CAST */ void process_give_control @ give_control(void); /* GIVE CONTROL */ void process_regeneration @ regeneration(void); /* regen health & aura */ + void process_guard_on @ guard_on(void); /* GUARD */ + void process_guard_off @ guard_off(void); /* GUARD NOT */ } } diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 313c68469..82ebc4034 100755 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -2769,7 +2769,7 @@ int origin_cmd(unit * u, struct order *ord) return 0; } -static int guard_off_cmd(unit * u, struct order *ord) +int guard_off_cmd(unit * u, struct order *ord) { assert(get_keyword(ord) == K_GUARD); init_tokens(ord); @@ -2930,7 +2930,7 @@ void update_guards(void) } } -static int guard_on_cmd(unit * u, struct order *ord) +int guard_on_cmd(unit * u, struct order *ord) { assert(get_keyword(ord) == K_GUARD); diff --git a/src/gamecode/laws.h b/src/gamecode/laws.h index 583a07af3..0d4cbd614 100755 --- a/src/gamecode/laws.h +++ b/src/gamecode/laws.h @@ -79,6 +79,8 @@ extern "C" { extern int renumber_cmd(struct unit *u, struct order *ord); extern int combatspell_cmd(struct unit *u, struct order *ord); extern int contact_cmd(struct unit *u, struct order *ord); + extern int guard_on_cmd(struct unit *u, struct order *ord); + extern int guard_off_cmd(struct unit *u, struct order *ord); #ifdef __cplusplus } From a08cb98fd2f18b8b4a448038a221dad3ba842f83 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 21 Jun 2012 21:42:11 -0700 Subject: [PATCH 354/400] remove unused code paths from combat code before refactoring it --- src/kernel/battle.c | 201 +------------------------------------------- src/kernel/battle.h | 29 ------- src/settings.h | 3 - 3 files changed, 3 insertions(+), 230 deletions(-) diff --git a/src/kernel/battle.c b/src/kernel/battle.c index ab7a52db7..6417c1b91 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -175,35 +175,6 @@ static int army_index(side * s) return s->index; } -#ifndef SIMPLE_ESCAPE -region *fleeregion(const unit * u) -{ - region *r = u->region; - region *neighbours[MAXDIRECTIONS]; - int c = 0; - direction_t i; - - if (u->ship && !fval(r->terrain, SEA_REGION)) - return NULL; - - if (u->ship && !(u->race->flags & RCF_SWIM) && !(u->race->flags & RCF_FLY)) { - return NULL; - } - - for (i = 0; i != MAXDIRECTIONS; ++i) { - region *r2 = rconnect(r, i); - if (r2) { - if (can_survive(u, r2) && !move_blocked(u, r, r2)) - neighbours[c++] = r2; - } - } - - if (!c) - return NULL; - return neighbours[rng_int() % c]; -} -#endif /* SIMPLE_ESCAPE */ - static char *sidename(side * s) { #define SIDENAMEBUFLEN 256 @@ -508,7 +479,6 @@ int get_unitrow(const fighter * af, const side * vs) break; return FIGHT_ROW + (row - i); } else { -#ifdef FASTROW battle *b = vs->battle; if (row != b->rowcache.row || b->alive != b->rowcache.alive || af->side != b->rowcache.as || vs != b->rowcache.vs) { @@ -526,9 +496,6 @@ int get_unitrow(const fighter * af, const side * vs) } #endif return b->rowcache.result; -#else - return get_row(af->side, row, vs); -#endif } } @@ -538,14 +505,6 @@ static void reportcasualties(battle * b, fighter * fig, int dead) region *r = NULL; if (fig->alive == fig->unit->number) return; -#ifndef SIMPLE_ESCAPE - if (fig->run.region == NULL) { - fig->run.region = fleeregion(fig->unit); - if (fig->run.region == NULL) - fig->run.region = b->region; - } - r = fig->run.region; -#endif /* SIMPLE_ESCAPE */ m = msg_message("casualties", "unit runto run alive fallen", fig->unit, r, fig->run.number, fig->alive, dead); message_all(b, m); @@ -973,12 +932,8 @@ void remove_troop(troop dt) fighter *df = dt.fighter; struct person p = df->person[dt.index]; battle *b = df->side->battle; -#ifdef FASTCOUNT b->fast.alive = -1; /* invalidate cached value */ -#endif -#ifdef FASTROW b->rowcache.alive = -1; /* invalidate cached value */ -#endif ++df->removed; ++df->side->removed; df->person[dt.index] = df->person[df->alive - df->removed]; @@ -1125,9 +1080,7 @@ terminate(troop dt, troop at, int type, const char *damage, boolean missile) int da = dice_rand(damage); assert(du->number > 0); -#ifdef SHOW_KILLS ++at.fighter->hits; -#endif switch (type) { case AT_STANDARD: @@ -1364,9 +1317,7 @@ terminate(troop dt, troop at, int type, const char *damage, boolean missile) return false; } } -#ifdef SHOW_KILLS ++at.fighter->kills; -#endif if (bdebug) { fprintf(bdebug, "Damage %d, armor %d, type %d: %d -> %d HP, tot.\n", @@ -1468,7 +1419,6 @@ int count_enemies(battle * b, const fighter * af, int minrow, int maxrow, int select) { -#ifdef FASTCOUNT int sr = statusrow(af->status); side *as = af->side; @@ -1497,12 +1447,9 @@ count_enemies(battle * b, const fighter * af, int minrow, int maxrow, b->fast.maxrow = maxrow; memset(b->fast.enemies, -1, sizeof(b->fast.enemies)); } -#endif if (maxrow >= FIRST_ROW) { int i = count_enemies_i(b, af, minrow, maxrow, select); -#ifdef FASTCOUNT b->fast.enemies[select] = i; -#endif return i; } return 0; @@ -1788,14 +1735,6 @@ void do_combatmagic(battle * b, combatmagic_t was) } } -static void combat_action(fighter * af) -{ -#ifndef SIMPLE_COMBAT - af->action_counter++; - af->side->bf->lastturn = af->side->battle->turn; -#endif -} - static int cast_combatspell(troop at, const spell * sp, int level, double force) { castorder co; @@ -1806,7 +1745,6 @@ static int cast_combatspell(troop at, const spell * sp, int level, double force) free_castorder(&co); if (level > 0) { pay_spell(at.fighter->unit, sp, level, 1); - combat_action(at.fighter); } return level; } @@ -2186,7 +2124,6 @@ static void attack(battle * b, troop ta, const att * a, int numattack) af->catmsg += dead; if (!standard_attack && af->person[ta.index].last_action < b->turn) { af->person[ta.index].last_action = b->turn; - combat_action(af); } } if (standard_attack) { @@ -2202,7 +2139,6 @@ static void attack(battle * b, troop ta, const att * a, int numattack) return; if (ta.fighter->person[ta.index].last_action < b->turn) { ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter); } reload = true; if (hits(ta, td, wp)) { @@ -2235,7 +2171,6 @@ static void attack(battle * b, troop ta, const att * a, int numattack) return; if (ta.fighter->person[ta.index].last_action < b->turn) { ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter); } if (hits(ta, td, NULL)) { terminate(td, ta, a->type, a->data.dice, false); @@ -2247,7 +2182,6 @@ static void attack(battle * b, troop ta, const att * a, int numattack) return; if (ta.fighter->person[ta.index].last_action < b->turn) { ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter); } if (hits(ta, td, NULL)) { int c = dice_rand(a->data.dice); @@ -2267,7 +2201,6 @@ static void attack(battle * b, troop ta, const att * a, int numattack) return; if (ta.fighter->person[ta.index].last_action < b->turn) { ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter); } if (hits(ta, td, NULL)) { drain_exp(td.fighter->unit, dice_rand(a->data.dice)); @@ -2279,7 +2212,6 @@ static void attack(battle * b, troop ta, const att * a, int numattack) return; if (ta.fighter->person[ta.index].last_action < b->turn) { ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter); } if (hits(ta, td, NULL)) { dazzle(b, &td); @@ -2291,7 +2223,6 @@ static void attack(battle * b, troop ta, const att * a, int numattack) return; if (ta.fighter->person[ta.index].last_action < b->turn) { ta.fighter->person[ta.index].last_action = b->turn; - combat_action(ta.fighter); } if (td.fighter->unit->ship) { /* FIXME should use damage_ship here? */ @@ -2453,7 +2384,6 @@ side *make_side(battle * b, const faction * f, const group * g, side *s1 = b->sides + b->nsides; bfaction *bf; -#ifdef SIMPLE_COMBAT if (fval(b->region->terrain, SEA_REGION)) { /* every fight in an ocean is short */ flags |= SIDE_HASGUARDS; @@ -2468,7 +2398,6 @@ side *make_side(battle * b, const faction * f, const group * g, } } } -#endif s1->battle = b; s1->group = g; @@ -2631,22 +2560,6 @@ static void loot_items(fighter * corpse) } } -#ifndef SIMPLE_ESCAPE -static void loot_fleeing(fighter * fig, unit * runner) -{ - /* TODO: Vernünftig fixen */ - runner->items = NULL; - assert(runner->items == NULL); - runner->items = fig->run.items; - fig->run.items = NULL; -} - -static void merge_fleeloot(fighter * fig, unit * u) -{ - i_merge(&u->items, &fig->run.items); -} -#endif /* SIMPLE_ESCAPE */ - static boolean seematrix(const faction * f, const side * s) { if (f == s->faction) @@ -2743,7 +2656,6 @@ static void aftermath(battle * b) if (playerrace(df->unit->race)) { s->casualties += dead; } -#ifdef SHOW_KILLS if (df->hits + df->kills) { struct message *m = msg_message("killsandhits", "unit hits kills", du, df->hits, @@ -2751,7 +2663,6 @@ static void aftermath(battle * b) message_faction(b, du->faction, m); msg_release(m); } -#endif } } @@ -2762,22 +2673,9 @@ static void aftermath(battle * b) int snumber = 0; fighter *df; boolean relevant = false; /* Kampf relevant für diese Partei? */ -#ifdef SIMPLE_COMBAT - if (fval(s, SIDE_HASGUARDS) == 0) + if (!fval(s, SIDE_HASGUARDS)) { relevant = true; -#else - if (s->bf->lastturn > 1) { - relevant = true; - } else if (s->bf->lastturn == 1 && b->has_tactics_turn) { - side *stac; - for (stac = b->sides; stac; stac = stac->next) { - if (stac->leader.value == b->max_tactics && helping(stac, s)) { - relevant = true; - break; - } - } } -#endif s->flee = 0; for (df = s->fighters; df; df = df->next) { @@ -2792,13 +2690,11 @@ static void aftermath(battle * b) } } snumber += du->number; -#ifdef SIMPLE_COMBAT if (relevant) { int flags = UFL_LONGACTION | UFL_NOTMOVING; -#ifdef SIMPLE_ESCAPE - if (du->status == ST_FLEE) + if (du->status == ST_FLEE) { flags -= UFL_NOTMOVING; -#endif /* SIMPLE_ESCAPE */ + } fset(du, flags); } if (sum_hp + df->run.hp < du->hp) { @@ -2807,17 +2703,6 @@ static void aftermath(battle * b) if (sh) fset(sh, SF_DAMAGED); } -#else - if (relevant) { - fset(du, UFL_NOTMOVING); /* unit cannot move this round */ - if (df->action_counter >= du->number) { - ship *sh = du->ship ? du->ship : leftship(du); - if (sh) - fset(sh, SF_DAMAGED); - fset(du, UFL_LONGACTION); - } - } -#endif if (df->alive == du->number) { du->hp = sum_hp; @@ -2830,18 +2715,9 @@ static void aftermath(battle * b) /* Zuerst dürfen die Feinde plündern, die mitgenommenen Items * stehen in fig->run.items. Dann werden die Fliehenden auf * die leere (tote) alte Einheit gemapt */ -#ifdef SIMPLE_ESCAPE if (!fval(df, FIG_NOLOOT)) { loot_items(df); } -#else - if (fval(df, FIG_NOLOOT)) { - merge_fleeloot(df, du); - } else { - loot_items(df); - loot_fleeing(df, du); - } -#endif /* SIMPLE_ESCAPE */ scale_number(du, df->run.number); du->hp = df->run.hp; setguard(du, GUARD_NONE); @@ -2850,13 +2726,6 @@ static void aftermath(battle * b) if (!fval(r->terrain, SEA_REGION)) { leave(du, true); /* even region owners have to flee */ } -#ifndef SIMPLE_ESCAPE - if (df->run.region) { - run_to(du, df->run.region); - df->run.region = du->region; - } - fset(du, UFL_LONGACTION | UFL_NOTMOVING); -#endif /* SIMPLE_ESCAPE */ fset(du, UFL_FLEEING); } else { /* nur teilweise geflohene Einheiten mergen sich wieder */ @@ -2865,9 +2734,6 @@ static void aftermath(battle * b) s->size[statusrow(df->status)] += df->run.number; s->alive += df->run.number; sum_hp += df->run.hp; -#ifndef SIMPLE_ESCAPE - merge_fleeloot(df, du); -#endif /* SIMPLE_ESCAPE */ df->run.number = 0; df->run.hp = 0; /* df->run.region = NULL; */ @@ -2882,9 +2748,6 @@ static void aftermath(battle * b) /* alle sind tot, niemand geflohen. Einheit auflösen */ df->run.number = 0; df->run.hp = 0; -#ifndef SIMPLE_ESCAPE - df->run.region = NULL; -#endif /* SIMPLE_ESCAPE */ /* Report the casualties */ reportcasualties(b, df, dead); @@ -3319,13 +3182,8 @@ fighter *make_fighter(battle * b, unit * u, side * s1, boolean attack) if (s1 == NULL) { for (s2 = b->sides; s2 != b->sides + b->nsides; ++s2) { if (s2->faction == u->faction && s2->group == g) { -#ifdef SIMPLE_COMBAT int s1flags = flags | SIDE_HASGUARDS; int s2flags = s2->flags | SIDE_HASGUARDS; -#else - int s1flags = flags; - int s2flags = s2->flags; -#endif if (rule_anon_battle && s2->stealthfaction != stealthfaction) { continue; } @@ -4010,53 +3868,6 @@ static void flee(const troop dt) fighter *fig = dt.fighter; unit *u = fig->unit; -#ifndef SIMPLE_ESCAPE - int carry = personcapacity(u) - u->race->weight; - int money; - - item **ip = &u->items; - - while (*ip) { - item *itm = *ip; - const item_type *itype = itm->type; - int keep = 0; - - if (fval(itype, ITF_ANIMAL)) { - /* Regeländerung: Man muß das Tier nicht reiten können, - * um es vom Schlachtfeld mitzunehmen, ist ja nur - * eine Region weit. * */ - keep = MIN(1, itm->number); - /* da ist das weight des tiers mit drin */ - carry += itype->capacity - itype->weight; - } else if (itm->type->weight <= 0) { - /* if it doesn'tactics weigh anything, it won'tactics slow us down */ - keep = itm->number; - } - /* jeder troop nimmt seinen eigenen Teil der Sachen mit */ - if (keep > 0) { - if (itm->number == keep) { - i_add(&fig->run.items, i_remove(ip, itm)); - } else { - item *run_itm = i_new(itype, keep); - i_add(&fig->run.items, run_itm); - i_change(ip, itype, -keep); - } - } - if (*ip == itm) - ip = &itm->next; - } - - /* we will take money with us */ - money = get_money(u); - /* nur ganzgeflohene/resttote Einheiten verlassen die Region */ - if (money > carry) - money = carry; - if (money > 0) { - i_change(&u->items, i_silver, -money); - i_change(&fig->run.items, i_silver, +money); - } -#endif /* SIMPLE_ESCAPE */ - fig->run.hp += fig->person[dt.index].hp; ++fig->run.number; @@ -4378,12 +4189,6 @@ static void battle_flee(battle * b) } dt.fighter = fig; -#ifndef SIMPLE_ESCAPE - if (!fig->run.region) - fig->run.region = fleeregion(u); - if (!fig->run.region) - continue; -#endif /* SIMPLE_ESCAPE */ dt.index = fig->alive - fig->removed; while (s->size[SUM_ROW] && dt.index != 0) { double ispaniced = 0.0; diff --git a/src/kernel/battle.h b/src/kernel/battle.h index b7fbf9f2f..bc8acc66f 100644 --- a/src/kernel/battle.h +++ b/src/kernel/battle.h @@ -22,9 +22,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif -#define SHOW_KILLS -#undef SMALL_BATTLE_MESSAGES - /** more defines **/ #define FS_ENEMY 1 #define FS_HELP 2 @@ -49,9 +46,6 @@ extern "C" { struct bfaction *next; struct side *sides; struct faction *faction; -#ifndef SIMPLE_COMBAT - int lastturn; /* last time this struct faction was involved in combat */ -#endif boolean attacker; } bfaction; @@ -61,9 +55,7 @@ extern "C" { } tactics; #define SIDE_STEALTH 1<<0 -#ifdef SIMPLE_COMBAT #define SIDE_HASGUARDS 1<<1 -#endif typedef struct side { struct side *nextF; /* next army of same faction */ struct battle *battle; @@ -106,11 +98,6 @@ extern "C" { int keeploot; boolean reelarrow; int alive; -#ifdef SMALL_BATTLE_MESSAGES - boolean small; -#endif -#define FASTROW -#ifdef FASTROW struct { const struct side *as; const struct side *vs; @@ -118,9 +105,6 @@ extern "C" { int row; int result; } rowcache; -#endif -#define FASTCOUNT -#ifdef FASTCOUNT struct { struct side *side; int status; @@ -128,7 +112,6 @@ extern "C" { int minrow, maxrow; int enemies[8]; } fast; -#endif } battle; typedef struct weapon { @@ -198,18 +181,9 @@ extern "C" { struct { int number; /* number of people who fled */ int hp; /* accumulated hp of fleeing people */ -#ifndef SIMPLE_ESCAPE - struct region *region; /* destination of fleeing people */ - struct item *items; /* items they take */ -#endif /* SIMPLE_ESCAPE */ } run; -#ifndef SIMPLE_COMBAT - int action_counter; /* number of active actions the struct unit did in the fight */ -#endif /* SIMPLE_COMBAT */ -#ifdef SHOW_KILLS int kills; int hits; -#endif } fighter; /* schilde */ @@ -257,9 +231,6 @@ extern "C" { extern int get_unitrow(const struct fighter *af, const struct side *vs); extern boolean helping(const struct side *as, const struct side *ds); extern void rmfighter(fighter * df, int i); -#ifndef SIMPLE_ESCAPE - extern struct region *fleeregion(const struct unit *u); -#endif extern struct fighter *select_corpse(struct battle *b, struct fighter *af); extern int statusrow(int status); extern void drain_exp(struct unit *u, int d); diff --git a/src/settings.h b/src/settings.h index 087f37cae..552e4c1c9 100644 --- a/src/settings.h +++ b/src/settings.h @@ -48,9 +48,6 @@ #define CHANGED_CROSSBOWS 0 /* use the WTF_ARMORPIERCING flag */ #undef GLOBAL_WARMING /* number of turns before global warming sets in */ -#define SIMPLE_COMBAT -#define SIMPLE_ESCAPE - #if defined(BINDINGS_LUABIND) # undef BINDINGS_TOLUA #elif defined(BINDINGS_TOLUA) From 8987d012144c91af8bddc45119b9c706becf27f7 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 24 Jun 2012 05:09:13 +0200 Subject: [PATCH 355/400] fix compilation on gcc --- src/bindings/bindings.c | 24 ------------------------ src/gamecode/laws.c | 2 +- src/util/os.c | 22 +++++++++------------- 3 files changed, 10 insertions(+), 38 deletions(-) diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index 12480b8a5..b452eb366 100755 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -1006,30 +1006,6 @@ typedef struct event_args { const char *sendertype; } event_args; -static void args_free(void *udata) -{ - free(udata); -} - -static void event_cb(void *sender, const char *event, void *udata) -{ - lua_State *L = (lua_State *) global.vm_state; - event_args *args = (event_args *) udata; - int nargs = 2; - lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); - if (sender && args->sendertype) { - tolua_pushusertype(L, sender, TOLUA_CAST args->sendertype); - } else { - lua_pushnil(L); - } - tolua_pushstring(L, event); - if (args->hargs) { - lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction); - ++nargs; - } - lua_pcall(L, nargs, 0, 0); -} - static int tolua_report_unit(lua_State * L) { char buffer[512]; diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 82ebc4034..d2485fadc 100755 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -4483,8 +4483,8 @@ void init_processor(void) } p += 10; + add_proc_region(p, do_contact, "Kontaktieren"); add_proc_order(p, K_MAIL, &mail_cmd, 0, "Botschaften"); - add_proc_order(p, K_CONTACT, &contact_cmd, 0, "Kontaktieren"); p += 10; /* all claims must be done before we can USE */ add_proc_region(p, &enter_1, "Betreten (1. Versuch)"); diff --git a/src/util/os.c b/src/util/os.c index 1278e0f7c..c2f947920 100644 --- a/src/util/os.c +++ b/src/util/os.c @@ -2,20 +2,16 @@ #if defined(WIN32) #include -#else /* */ +#else /* WIN32 */ #include -#endif /* */ - int os_mkdir(const char *path, int mode) -{ +#endif /* WIN32 */ +int os_mkdir(const char *path, int mode) +{ #ifdef WIN32 - mode = mode; - return _mkdir(path); - + mode = mode; + return _mkdir(path); #else /* POSIX is our last hope */ - return mkdir(path, (mode_t) mode); - -#endif /* */ -} - - + return mkdir(path, (mode_t) mode); +#endif /* WIN32 */ +} From 413edd9be6b5820c10bbfb06b43775efd495a412 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 24 Jun 2012 06:56:42 +0200 Subject: [PATCH 356/400] compilation fix for gcc C99 --- src/util/os.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/os.c b/src/util/os.c index c2f947920..5a7220e7d 100644 --- a/src/util/os.c +++ b/src/util/os.c @@ -3,6 +3,7 @@ #if defined(WIN32) #include #else /* WIN32 */ +#include #include #endif /* WIN32 */ int os_mkdir(const char *path, int mode) From 7359eea1846c53aded031e47c3cbfd752dd8104c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 24 Jun 2012 07:08:16 +0200 Subject: [PATCH 357/400] use bool type where it's available when using gcc, compile as C99 --- src/CMakeLists.txt | 1 + src/platform.h | 19 +++---------------- src/util/bool.h | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 16 deletions(-) create mode 100644 src/util/bool.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1cc33a9b9..9e9eb8d6c 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,6 +3,7 @@ project (eressea C) IF(CMAKE_COMPILER_IS_GNUCC) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic -Wall -Werror -Wno-unknown-pragmas -Wstrict-prototypes -Wpointer-arith -Wno-char-subscripts -Wno-long-long") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -DHAVE__BOOL") ELSE(CMAKE_COMPILER_IS_GNUCC) MESSAGE(STATUS "Unknown compiler ${CMAKE_C_COMPILER_ID}") ENDIF(CMAKE_COMPILER_IS_GNUCC) diff --git a/src/platform.h b/src/platform.h index d72545cc6..679737ec2 100644 --- a/src/platform.h +++ b/src/platform.h @@ -246,22 +246,9 @@ extern char *strdup(const char *s); # define unused(a) (a) #endif /* ghs || __GNUC__ || ..... */ -/**** **** - ** The Eressea boolean type ** - **** ****/ -#if defined(BOOLEAN) -# define boolean BOOLEAN -#else -typedef int boolean; /* not bool! wrong size. */ -#endif -#ifndef __cplusplus -# define false ((boolean)0) -# define true ((boolean)!false) -#endif -#ifdef __cplusplus -} -#endif - +#include "util/bool.h" +typedef bool boolean; + #ifndef INLINE_FUNCTION # define INLINE_FUNCTION #endif diff --git a/src/util/bool.h b/src/util/bool.h new file mode 100644 index 000000000..0bdebc9ec --- /dev/null +++ b/src/util/bool.h @@ -0,0 +1,15 @@ +#if HAVE_STDBOOL_H +# include +#else +# if ! HAVE__BOOL +# ifdef __cplusplus +typedef bool _Bool; +# else +typedef unsigned char _Bool; +# endif +# endif +# define bool _Bool +# define false 0 +# define true 1 +# define __bool_true_false_are_defined 1 +#endif From 186126810993fb01329f8f77fee7c3e0a265181b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 23 Jun 2012 22:41:07 -0700 Subject: [PATCH 358/400] remove custom boolean type use bool when we have C99, or our own typedef for bool --- src/attributes/moved.c | 2 +- src/attributes/moved.h | 2 +- src/attributes/movement.c | 2 +- src/attributes/movement.h | 2 +- src/bindings/bind_sqlite.c | 4 +- src/bindings/helpers.c | 4 +- src/gamecode/archetype.h | 2 +- src/gamecode/creport.c | 16 ++++---- src/gamecode/economy.c | 36 ++++++++--------- src/gamecode/economy.h | 2 +- src/gamecode/give.c | 4 +- src/gamecode/laws.c | 42 +++++++++---------- src/gamecode/laws.h | 2 +- src/gamecode/monster.c | 2 +- src/gamecode/monster.h | 2 +- src/gamecode/randenc.c | 8 ++-- src/gamecode/report.c | 34 ++++++++-------- src/gamecode/study.c | 10 ++--- src/gamecode/study.h | 2 +- src/gamecode/summary.c | 2 +- src/gamecode/summary.h | 2 +- src/gamecode/xmlreport.c | 6 +-- src/gmtool.c | 4 +- src/gmtool.h | 2 +- src/gmtool_structs.h | 4 +- src/items/phoenixcompass.c | 2 +- src/items/weapons.c | 4 +- src/kernel/alliance.c | 2 +- src/kernel/battle.c | 82 +++++++++++++++++++------------------- src/kernel/battle.h | 16 ++++---- src/kernel/building.c | 6 +-- src/kernel/config.c | 56 +++++++++++++------------- src/kernel/config.h | 48 +++++++++++----------- src/kernel/connection.c | 32 +++++++-------- src/kernel/connection.h | 34 ++++++++-------- src/kernel/curse.c | 14 +++---- src/kernel/curse.h | 12 +++--- src/kernel/faction.c | 6 +-- src/kernel/faction.h | 8 ++-- src/kernel/group.c | 2 +- src/kernel/group.h | 2 +- src/kernel/item.c | 2 +- src/kernel/item.h | 4 +- src/kernel/magic.c | 32 +++++++-------- src/kernel/magic.h | 16 ++++---- src/kernel/move.c | 60 ++++++++++++++-------------- src/kernel/move.h | 10 ++--- src/kernel/pathfinder.c | 18 ++++----- src/kernel/pathfinder.h | 14 +++---- src/kernel/plane.c | 2 +- src/kernel/plane.h | 2 +- src/kernel/race.c | 4 +- src/kernel/race.h | 8 ++-- src/kernel/region.c | 6 +-- src/kernel/region.h | 8 ++-- src/kernel/reports.c | 28 ++++++------- src/kernel/reports.h | 16 ++++---- src/kernel/resources.c | 2 +- src/kernel/save.c | 4 +- src/kernel/skill.c | 6 +-- src/kernel/skill.h | 4 +- src/kernel/sqlite.c | 10 ++--- src/kernel/teleport.c | 8 ++-- src/kernel/teleport.h | 8 ++-- src/kernel/unit.c | 18 ++++----- src/kernel/unit.h | 14 +++---- src/kernel/xmlreader.c | 16 ++++---- src/modules/autoseed.c | 6 +-- src/modules/autoseed.h | 2 +- src/modules/gmcmd.c | 6 +-- src/modules/wormhole.c | 2 +- src/platform.h | 1 - src/util/attrib.c | 2 +- src/util/attrib.h | 2 +- src/util/filereader.c | 16 ++++---- src/util/listbox.c | 2 +- src/util/parser.c | 6 +-- src/util/parser.h | 2 +- src/util/rand.c | 2 +- src/util/rand.h | 2 +- src/util/translation.c | 8 ++-- src/util/xml.c | 8 ++-- src/util/xml.h | 2 +- 83 files changed, 456 insertions(+), 457 deletions(-) diff --git a/src/attributes/moved.c b/src/attributes/moved.c index d73b3e541..6ddad1b17 100644 --- a/src/attributes/moved.c +++ b/src/attributes/moved.c @@ -48,7 +48,7 @@ attrib_type at_moved = { "moved", NULL, NULL, age_moved, write_moved, read_moved }; -boolean get_moved(attrib ** alist) +bool get_moved(attrib ** alist) { return a_find(*alist, &at_moved) ? true : false; } diff --git a/src/attributes/moved.h b/src/attributes/moved.h index cce9fe941..bad4dcdd5 100644 --- a/src/attributes/moved.h +++ b/src/attributes/moved.h @@ -25,7 +25,7 @@ extern "C" { struct attrib; struct attrib_type; - extern boolean get_moved(struct attrib **alist); + extern bool get_moved(struct attrib **alist); extern void set_moved(struct attrib **alist); extern struct attrib_type at_moved; diff --git a/src/attributes/movement.c b/src/attributes/movement.c index 8e2515854..1f3bf51c0 100644 --- a/src/attributes/movement.c +++ b/src/attributes/movement.c @@ -42,7 +42,7 @@ attrib_type at_movement = { "movement", NULL, NULL, NULL, write_movement, read_movement }; -boolean get_movement(attrib * const *alist, int type) +bool get_movement(attrib * const *alist, int type) { const attrib *a = a_findc(*alist, &at_movement); if (a == NULL) diff --git a/src/attributes/movement.h b/src/attributes/movement.h index b976a67ec..0fe4cfc83 100644 --- a/src/attributes/movement.h +++ b/src/attributes/movement.h @@ -22,7 +22,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif - extern boolean get_movement(struct attrib *const *alist, int type); + extern bool get_movement(struct attrib *const *alist, int type); extern void set_movement(struct attrib **alist, int type); extern struct attrib_type at_movement; diff --git a/src/bindings/bind_sqlite.c b/src/bindings/bind_sqlite.c index be1eacec7..0df9e530f 100644 --- a/src/bindings/bind_sqlite.c +++ b/src/bindings/bind_sqlite.c @@ -21,7 +21,7 @@ without prior permission by the authors of Eressea. #define LTYPE_DB TOLUA_CAST "db" -extern int db_update_factions(sqlite3 * db, boolean force); +extern int db_update_factions(sqlite3 * db, bool force); static int tolua_db_update_factions(lua_State * L) { sqlite3 *db = (sqlite3 *) tolua_tousertype(L, 1, 0); @@ -29,7 +29,7 @@ static int tolua_db_update_factions(lua_State * L) return 0; } -extern int db_update_scores(sqlite3 * db, boolean force); +extern int db_update_scores(sqlite3 * db, bool force); static int tolua_db_update_scores(lua_State * L) { sqlite3 *db = (sqlite3 *) tolua_tousertype(L, 1, 0); diff --git a/src/bindings/helpers.c b/src/bindings/helpers.c index f2fbae090..d6d73d7b2 100644 --- a/src/bindings/helpers.c +++ b/src/bindings/helpers.c @@ -342,10 +342,10 @@ static int lua_getresource(unit * u, const struct resource_type *rtype) return result; } -static boolean lua_canuse_item(const unit * u, const struct item_type *itype) +static bool lua_canuse_item(const unit * u, const struct item_type *itype) { static int function_exists = 1; - boolean result = true; + bool result = true; if (function_exists) { lua_State *L = (lua_State *) global.vm_state; diff --git a/src/gamecode/archetype.h b/src/gamecode/archetype.h index 963acd286..55c6896cc 100644 --- a/src/gamecode/archetype.h +++ b/src/gamecode/archetype.h @@ -18,7 +18,7 @@ extern "C" { #endif typedef struct rule { - boolean allow; + bool allow; char *property; char *value; } rule; diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index 3f7d4fe1d..0a4768097 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -80,7 +80,7 @@ without prior permission by the authors of Eressea. /* imports */ extern int verbosity; -boolean opt_cr_absolute_coords = false; +bool opt_cr_absolute_coords = false; /* globals */ #define C_REPORT_VERSION 66 @@ -177,7 +177,7 @@ static void print_items(FILE * F, item * items, const struct locale *lang) static void cr_output_curses(FILE * F, const faction * viewer, const void *obj, objtype_t typ) { - boolean header = false; + bool header = false; attrib *a = NULL; int self = 0; region *r; @@ -508,7 +508,7 @@ static void render_messages(FILE * F, faction * f, message_list * msgs) struct mlist *m = msgs->begin; while (m) { char crbuffer[BUFFERSIZE]; /* gross, wegen spionage-messages :-( */ - boolean printed = false; + bool printed = false; const struct message_type *mtype = m->msg->type; unsigned int hash = mtype->key; #ifdef RENDER_CRMESSAGES @@ -637,7 +637,7 @@ cr_output_ship(FILE * F, const ship * sh, const unit * u, int fcaptain, static void fwriteorder(FILE * F, const struct order *ord, const struct locale *lang, - boolean escape) + bool escape) { char ebuf[1024]; char obuf[1024]; @@ -690,9 +690,9 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, const char *pzTmp; skill *sv; const attrib *a_fshidden = NULL; - boolean itemcloak = false; + bool itemcloak = false; static const curse_type *itemcloak_ct = 0; - static boolean init = false; + static bool init = false; item result[MAX_INVENTORY]; if (fval(u->race, RCF_INVISIBLE)) @@ -1096,7 +1096,7 @@ cr_borders(seen_region ** seen, const region * r, const faction * f, } b = get_borders(r, r2); while (b) { - boolean cs = b->type->fvisible(b, f, r); + bool cs = b->type->fvisible(b, f, r); if (!cs) { cs = b->type->rvisible(b, r); @@ -1352,7 +1352,7 @@ static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr) /* describe both passed and inhabited regions */ show_active_spells(r); if (fval(r, RF_TRAVELUNIT)) { - boolean seeunits = false, seeships = false; + bool seeunits = false, seeships = false; const attrib *ru; /* show units pulled through region */ for (ru = a_find(r->attribs, &at_travelunit); diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index cd47f880a..6668c3a21 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -89,7 +89,7 @@ typedef struct request { int qty; int no; union { - boolean goblin; /* stealing */ + bool goblin; /* stealing */ const struct luxury_type *ltype; /* trading */ } type; } request; @@ -392,7 +392,7 @@ static void feedback_give_not_allowed(unit * u, order * ord) "")); } -static boolean check_give(unit * u, unit * u2, const item_type * itype, +static bool check_give(unit * u, unit * u2, const item_type * itype, int mask) { if (u2) { @@ -537,7 +537,7 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders) get_gamedate(turn, &date); if (date.season == 0 && r->terrain != newterrain(T_DESERT)) { #ifdef INSECT_POTION - boolean usepotion = false; + bool usepotion = false; unit *u2; for (u2 = r->units; u2; u2 = u2->next) @@ -769,7 +769,7 @@ static void give_cmd(unit * u, order * ord) } else if (p == P_HERBS) { - boolean given = false; + bool given = false; if (!(u->race->ec_flags & GIVEITEM) && u2 != NULL) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_nogive", "race", u->race)); @@ -996,12 +996,12 @@ void add_spende(faction * f1, faction * f2, int amount, region * r) r->donations = sp; } -static boolean maintain(building * b, boolean first) +static bool maintain(building * b, bool first) /* first==false -> take money from wherever you can */ { int c; region *r = b->region; - boolean paid = true, work = first; + bool paid = true, work = first; unit *u; if (fval(b, BLD_MAINTAINED) || b->type == NULL || b->type->maintenance == NULL || is_cursed(b->attribs, C_NOCOST, 0)) { @@ -1111,12 +1111,12 @@ static boolean maintain(building * b, boolean first) return true; } -void maintain_buildings(region * r, boolean crash) +void maintain_buildings(region * r, bool crash) { building **bp = &r->buildings; while (*bp) { building *b = *bp; - boolean maintained = maintain(b, !crash); + bool maintained = maintain(b, !crash); /* the second time, send a message */ if (crash) { @@ -1141,7 +1141,7 @@ void maintain_buildings(region * r, boolean crash) static int recruit_archetype(unit * u, order * ord) { - boolean merge = (u->number > 0); + bool merge = (u->number > 0); int want; const char *s; @@ -1178,7 +1178,7 @@ static int recruit_archetype(unit * u, order * ord) */ int k; for (k = 0; arch->rules[k].property; ++k) { - boolean match = false; + bool match = false; if (arch->rules[k].value[0] == '*') match = true; else if (strcmp(arch->rules[k].property, "race") == 0) { @@ -1296,7 +1296,7 @@ void economics(region * r) for (u = r->units; u; u = u->next) { order *ord; - boolean destroyed = false; + bool destroyed = false; if (u->number > 0) { for (ord = u->orders; ord; ord = ord->next) { keyword_t kwd = get_keyword(ord); @@ -1421,7 +1421,7 @@ typedef struct allocation_list { static allocation_list *allocations; -static boolean can_guard(const unit * guard, const unit * u) +static bool can_guard(const unit * guard, const unit * u) { if (fval(guard, UFL_ISNEW)) return false; @@ -1612,7 +1612,7 @@ leveled_allocation(const resource_type * rtype, region * r, allocation * alist) const item_type *itype = resource2item(rtype); rawmaterial *rm = rm_get(r, rtype); int need; - boolean first = true; + bool first = true; if (rm != NULL) { do { @@ -2373,9 +2373,9 @@ static void expandselling(region * r, request * sellorders, int limit) } } -static boolean sell(unit * u, request ** sellorders, struct order *ord) +static bool sell(unit * u, request ** sellorders, struct order *ord) { - boolean unlimited = true; + bool unlimited = true; const item_type *itype; const luxury_type *ltype = NULL; int n; @@ -2904,7 +2904,7 @@ static int max_skill(region * r, faction * f, skill_t sk) static void steal_cmd(unit * u, struct order *ord, request ** stealorders) { int n, i, id; - boolean goblin = false; + bool goblin = false; request *o; unit *u2 = NULL; region *r = u->region; @@ -3342,7 +3342,7 @@ void produce(struct region *r) unit *u; int todo; static int rule_autowork = -1; - boolean limited = true; + bool limited = true; request *nextworker = workers; assert(r); @@ -3378,7 +3378,7 @@ void produce(struct region *r) for (u = r->units; u; u = u->next) { order *ord; - boolean trader = false; + bool trader = false; if (u->race == new_race[RC_SPELL] || fval(u, UFL_LONGACTION)) continue; diff --git a/src/gamecode/economy.h b/src/gamecode/economy.h index b5ccac86d..8b44df380 100644 --- a/src/gamecode/economy.h +++ b/src/gamecode/economy.h @@ -48,7 +48,7 @@ extern "C" { enum { IC_WORK, IC_ENTERTAIN, IC_TAX, IC_TRADE, IC_TRADETAX, IC_STEAL, IC_MAGIC }; - void maintain_buildings(struct region *r, boolean crash); + void maintain_buildings(struct region *r, bool crash); extern void add_spende(struct faction *f1, struct faction *f2, int betrag, struct region *r); extern int make_cmd(struct unit *u, struct order *ord); diff --git a/src/gamecode/give.c b/src/gamecode/give.c index b9254c7c2..9c259f2cf 100644 --- a/src/gamecode/give.c +++ b/src/gamecode/give.c @@ -87,7 +87,7 @@ add_give(unit * u, unit * u2, int given, int received, } } -static boolean limited_give(const item_type * type) +static bool limited_give(const item_type * type) { /* trade only money 2:1, if at all */ return (type == i_silver); @@ -288,7 +288,7 @@ void give_men(int n, unit * u, unit * u2, struct order *ord) if (u2) { if (u2->number != 0 && recruit_archetypes()) { /* must have same set of skills */ - boolean okay = false; + bool okay = false; if (u->skill_size == u2->skill_size) { int i; for (i = 0; i != u->skill_size; ++i) { diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index d2485fadc..3b332fec7 100755 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -141,7 +141,7 @@ static void checkorders(void) ADDMSG(&f->msgs, msg_message("turnreminder", "")); } -static boolean help_money(const unit * u) +static bool help_money(const unit * u) { if (u->race->ec_flags & GIVEITEM) return true; @@ -1128,7 +1128,7 @@ int leave_cmd(unit * u, struct order *ord) return 0; } -static boolean EnhancedQuit(void) +static bool EnhancedQuit(void) { static int value = -1; if (value < 0) { @@ -1180,7 +1180,7 @@ int quit_cmd(unit * u, struct order *ord) return 0; } -static boolean mayenter(region * r, unit * u, building * b) +static bool mayenter(region * r, unit * u, building * b) { unit *u2; if (fval(b, BLD_UNGUARDED)) @@ -1201,7 +1201,7 @@ static int mayboard(const unit * u, ship * sh) return (!u2 || ucontact(u2, u) || alliedunit(u2, u->faction, HELP_GUARD)); } -static boolean CheckOverload(void) +static bool CheckOverload(void) { static int value = -1; if (value < 0) { @@ -1655,7 +1655,7 @@ static void init_prefixnames(void) int i; for (i = 0; localenames[i]; ++i) { const struct locale *lang = find_locale(localenames[i]); - boolean exist = false; + bool exist = false; struct local_names *in = pnames; while (in != NULL) { @@ -1839,7 +1839,7 @@ int display_cmd(unit * u, struct order *ord) return 0; } -boolean renamed_building(const building * b) +bool renamed_building(const building * b) { const struct locale *lang = locales; size_t len = strlen(b->name); @@ -1877,7 +1877,7 @@ int rename_building(unit * u, order * ord, building * b, const char *name) { unit *owner = b ? building_owner(b) : 0; - boolean foreign = !(owner && owner->faction == u->faction); + bool foreign = !(owner && owner->faction == u->faction); if (!b) { cmistake(u, ord, u->building ? 6 : 145, MSG_EVENT); @@ -1922,7 +1922,7 @@ int name_cmd(struct unit *u, struct order *ord) region *r = u->region; char **s = NULL; param_t p; - boolean foreign = false; + bool foreign = false; const char *str; init_tokens(ord); @@ -2196,7 +2196,7 @@ static int mail_cmd(unit * u, struct order *ord) case P_FACTION: { - boolean see = false; + bool see = false; n = getfactionid(); @@ -2223,7 +2223,7 @@ static int mail_cmd(unit * u, struct order *ord) case P_UNIT: { - boolean see = false; + bool see = false; n = getid(); for (u2 = r->units; u2; u2 = u2->next) { @@ -2374,7 +2374,7 @@ int password_cmd(unit * u, struct order *ord) char pwbuf[32]; int i; const char *s; - boolean pwok = true; + bool pwok = true; init_tokens(ord); skip_token(); @@ -2440,7 +2440,7 @@ int send_cmd(unit * u, struct order *ord) return 0; } -static boolean display_item(faction * f, unit * u, const item_type * itype) +static bool display_item(faction * f, unit * u, const item_type * itype) { const char *name; const char *key; @@ -2473,7 +2473,7 @@ static boolean display_item(faction * f, unit * u, const item_type * itype) return true; } -static boolean display_potion(faction * f, unit * u, const potion_type * ptype) +static bool display_potion(faction * f, unit * u, const potion_type * ptype) { attrib *a; @@ -2497,7 +2497,7 @@ static boolean display_potion(faction * f, unit * u, const potion_type * ptype) return true; } -static boolean display_race(faction * f, unit * u, const race * rc) +static bool display_race(faction * f, unit * u, const race * rc) { const char *name, *key; const char *info; @@ -3076,7 +3076,7 @@ void restack_units(void) region *r; for (r = regions; r; r = r->next) { unit **up = &r->units; - boolean sorted = false; + bool sorted = false; while (*up) { unit *u = *up; if (!fval(u, UFL_MARK)) { @@ -3271,7 +3271,7 @@ int renumber_cmd(unit * u, order * ord) static building *age_building(building * b) { - static boolean init = false; + static bool init = false; static const building_type *bt_blessed; static const curse_type *ct_astralblock; if (!init) { @@ -3657,8 +3657,8 @@ void check_long_orders(unit * u) void update_long_order(unit * u) { order *ord; - boolean trade = false; - boolean hunger = LongHunger(u); + bool trade = false; + bool hunger = LongHunger(u); freset(u, UFL_MOVED); freset(u, UFL_LONGACTION); @@ -3873,7 +3873,7 @@ static void defaultorders(void) for (r = regions; r; r = r->next) { unit *u; for (u = r->units; u; u = u->next) { - boolean neworders = false; + bool neworders = false; order **ordp = &u->orders; while (*ordp != NULL) { order *ord = *ordp; @@ -4316,7 +4316,7 @@ int siege_cmd(unit * u, order * ord) building *b; int d, pooled; int bewaffnete, katapultiere = 0; - static boolean init = false; + static bool init = false; static const curse_type *magicwalls_ct; static item_type *it_catapultammo = NULL; static item_type *it_catapult = NULL; @@ -4432,7 +4432,7 @@ static int warn_password(void) { faction *f = factions; while (f) { - boolean pwok = true; + bool pwok = true; const char *c = f->passw; while (*c && pwok) { if (!isalnum((unsigned char)*c)) diff --git a/src/gamecode/laws.h b/src/gamecode/laws.h index 0d4cbd614..3cc5882e5 100755 --- a/src/gamecode/laws.h +++ b/src/gamecode/laws.h @@ -34,7 +34,7 @@ extern "C" { const char *s, struct unit *receiver); int init_data(const char *filename, const char *catalog); - boolean renamed_building(const struct building * b); + bool renamed_building(const struct building * b); int rename_building(struct unit * u, struct order * ord, struct building * b, const char *name); void get_food(struct region * r); extern int can_contact(const struct region *r, const struct unit *u, const struct unit *u2); diff --git a/src/gamecode/monster.c b/src/gamecode/monster.c index 1c4911cd1..4fe9d9ec2 100644 --- a/src/gamecode/monster.c +++ b/src/gamecode/monster.c @@ -70,7 +70,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define MAXILLUSION_TEXTS 3 -boolean monster_is_waiting(const unit * u) +bool monster_is_waiting(const unit * u) { if (fval(u, UFL_ISNEW | UFL_MOVED)) return true; diff --git a/src/gamecode/monster.h b/src/gamecode/monster.h index 0ae45a6bf..27a8f23f7 100644 --- a/src/gamecode/monster.h +++ b/src/gamecode/monster.h @@ -23,7 +23,7 @@ extern "C" { #endif void monster_kills_peasants(struct unit *u); - boolean monster_is_waiting(const struct unit *u); + bool monster_is_waiting(const struct unit *u); #ifdef __cplusplus } diff --git a/src/gamecode/randenc.c b/src/gamecode/randenc.c index 43d3370b2..196fdd5a0 100644 --- a/src/gamecode/randenc.c +++ b/src/gamecode/randenc.c @@ -153,7 +153,7 @@ static void dissolve_units(void) static int improve_all(faction * f, skill_t sk, int by_weeks) { unit *u; - boolean ret = by_weeks; + bool ret = by_weeks; for (u = f->units; u; u = u->nextF) { if (has_skill(u, sk)) { @@ -596,7 +596,7 @@ static int nb_armor(const unit * u, int index) } static int -damage_unit(unit * u, const char *dam, boolean physical, boolean magic) +damage_unit(unit * u, const char *dam, bool physical, bool magic) { int *hp = malloc(u->number * sizeof(int)); int h; @@ -980,7 +980,7 @@ void create_icebergs(void) for (r = regions; r; r = r->next) { if (r->terrain == newterrain(T_ICEBERG_SLEEP) && chance(0.05)) { - boolean has_ocean_neighbour = false; + bool has_ocean_neighbour = false; direction_t dir; region *rc; unit *u; @@ -1062,7 +1062,7 @@ static void orc_growth(void) for (r = regions; r; r = r->next) { unit *u; for (u = r->units; u; u = u->next) { - static boolean init = false; + static bool init = false; static const curse_type *ct_orcish = 0; curse *c = 0; if (!init) { diff --git a/src/gamecode/report.c b/src/gamecode/report.c index 2127d2940..c01ea5089 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -134,7 +134,7 @@ void rnl(FILE * F) fputc('\n', F); } -static void centre(FILE * F, const char *s, boolean breaking) +static void centre(FILE * F, const char *s, bool breaking) { /* Bei Namen die genau 80 Zeichen lang sind, kann es hier Probleme * geben. Seltsamerweise wird i dann auf MAXINT oder aehnlich @@ -698,7 +698,7 @@ nr_unit(FILE * F, const faction * f, const unit * u, int indent, int mode) attrib *a_otherfaction; char marker; int dh; - boolean isbattle = (boolean) (mode == see_battle); + bool isbattle = (bool) (mode == see_battle); char buf[8192]; if (fval(u->race, RCF_INVISIBLE)) @@ -735,7 +735,7 @@ nr_unit(FILE * F, const faction * f, const unit * u, int indent, int mode) static void rp_messages(FILE * F, message_list * msgs, faction * viewer, int indent, - boolean categorized) + bool categorized) { nrsection *section; if (!msgs) @@ -866,9 +866,9 @@ static void prices(FILE * F, const region * r, const faction * f) } -boolean see_border(const connection * b, const faction * f, const region * r) +bool see_border(const connection * b, const faction * f, const region * r) { - boolean cs = b->type->fvisible(b, f, r); + bool cs = b->type->fvisible(b, f, r); if (!cs) { cs = b->type->rvisible(b, r); if (!cs) { @@ -890,7 +890,7 @@ static void describe(FILE * F, const seen_region * sr, faction * f) { const region *r = sr->r; int n; - boolean dh; + bool dh; direction_t d; int trees; int saplings; @@ -899,12 +899,12 @@ static void describe(FILE * F, const seen_region * sr, faction * f) struct edge { struct edge *next; char *name; - boolean transparent; - boolean block; - boolean exist[MAXDIRECTIONS]; + bool transparent; + bool block; + bool exist[MAXDIRECTIONS]; direction_t lastd; } *edges = NULL, *e; - boolean see[MAXDIRECTIONS]; + bool see[MAXDIRECTIONS]; char buf[8192]; char *bufp = buf; size_t size = sizeof(buf); @@ -919,7 +919,7 @@ static void describe(FILE * F, const seen_region * sr, faction * f) continue; for (b = get_borders(r, r2); b;) { struct edge *e = edges; - boolean transparent = b->type->transparent(b, f); + bool transparent = b->type->transparent(b, f); const char *name = b->type->name(b, r, f, GF_DETAILED | GF_ARTICLE); if (!transparent) @@ -1235,7 +1235,7 @@ static void describe(FILE * F, const seen_region * sr, faction * f) if (edges) rnl(F); for (e = edges; e; e = e->next) { - boolean first = true; + bool first = true; bufp = buf; size = sizeof(buf) - 1; for (d = 0; d != MAXDIRECTIONS; ++d) { @@ -1455,7 +1455,7 @@ static int buildingmaintenance(const building * b, const resource_type * rtype) { const building_type *bt = b->type; int c, cost = 0; - static boolean init = false; + static bool init = false; static const curse_type *nocost_ct; if (!init) { init = true; @@ -1775,7 +1775,7 @@ static void guards(FILE * F, const region * r, const faction * see) unit *u; int i; - boolean tarned = false; + bool tarned = false; /* Bewachung */ for (u = r->units; u; u = u->next) { @@ -2579,7 +2579,7 @@ static void add_find(faction * f, unit * u, faction * f2) static void update_find(void) { region *r; - static boolean initial = true; + static bool initial = true; if (initial) for (r = regions; r; r = r->next) { @@ -2601,10 +2601,10 @@ static void update_find(void) initial = false; } -boolean kann_finden(faction * f1, faction * f2) +bool kann_finden(faction * f1, faction * f2) { update_find(); - return (boolean) (can_find(f1, f2) != NULL); + return (bool) (can_find(f1, f2) != NULL); } /******* end summary ******/ diff --git a/src/gamecode/study.c b/src/gamecode/study.c index 2919e8b1f..653ef5bb9 100644 --- a/src/gamecode/study.c +++ b/src/gamecode/study.c @@ -87,7 +87,7 @@ magic_t getmagicskill(const struct locale * lang) /* ------------------------------------------------------------- */ /* Vertraute und Kröten sind keine Migranten */ -boolean is_migrant(unit * u) +bool is_migrant(unit * u) { if (u->race == u->faction->race) return false; @@ -103,7 +103,7 @@ boolean is_migrant(unit * u) } /* ------------------------------------------------------------- */ -boolean magic_lowskill(unit * u) +bool magic_lowskill(unit * u) { return (u->race == new_race[RC_TOAD]) ? true : false; } @@ -174,7 +174,7 @@ static int study_days(unit * student, skill_t sk) static int teach_unit(unit * teacher, unit * student, int nteaching, skill_t sk, - boolean report, int *academy) + bool report, int *academy) { teaching_info *teach = NULL; attrib *a; @@ -393,7 +393,7 @@ int teach_cmd(unit * u, struct order *ord) while (!parser_end()) { unit *u2 = getunit(r, u->faction); - boolean feedback; + bool feedback; ++count; /* Falls die Unit nicht gefunden wird, Fehler melden */ @@ -763,7 +763,7 @@ int learn_cmd(unit * u, order * ord) while (teach->teachers[index] && index != MAXTEACHERS) { unit *teacher = teach->teachers[index++]; if (teacher->faction != u->faction) { - boolean feedback = alliedunit(u, teacher->faction, HELP_GUARD); + bool feedback = alliedunit(u, teacher->faction, HELP_GUARD); if (feedback) { ADDMSG(&teacher->faction->msgs, msg_message("teach_teacher", "teacher student skill level", teacher, u, sk, diff --git a/src/gamecode/study.h b/src/gamecode/study.h index 3527e3cec..182e364ee 100644 --- a/src/gamecode/study.h +++ b/src/gamecode/study.h @@ -27,7 +27,7 @@ extern "C" { extern int learn_cmd(struct unit *u, struct order *ord); extern magic_t getmagicskill(const struct locale *lang); - extern boolean is_migrant(struct unit *u); + extern bool is_migrant(struct unit *u); extern int study_cost(struct unit *u, skill_t talent); #define MAXTEACHERS 4 diff --git a/src/gamecode/summary.c b/src/gamecode/summary.c index 03690dee7..1d3c73e2f 100644 --- a/src/gamecode/summary.c +++ b/src/gamecode/summary.c @@ -132,7 +132,7 @@ static void writeturn(void) fclose(f); } -void report_summary(summary * s, summary * o, boolean full) +void report_summary(summary * s, summary * o, bool full) { FILE *F = NULL; int i, newplayers = 0; diff --git a/src/gamecode/summary.h b/src/gamecode/summary.h index 5da62e688..bb2ae04b7 100644 --- a/src/gamecode/summary.h +++ b/src/gamecode/summary.h @@ -17,7 +17,7 @@ extern "C" { struct summary; extern void report_summary(struct summary *n, struct summary *o, - boolean full); + bool full); extern struct summary *make_summary(void); #ifdef __cplusplus diff --git a/src/gamecode/xmlreport.c b/src/gamecode/xmlreport.c index 5b93dc887..9ccf72a31 100644 --- a/src/gamecode/xmlreport.c +++ b/src/gamecode/xmlreport.c @@ -213,10 +213,10 @@ static xmlNodePtr xml_unit(report_context * ctx, unit * u, int mode) xml_context *xct = (xml_context *) ctx->userdata; xmlNodePtr node = xmlNewNode(xct->ns_atl, BAD_CAST "unit"); static const curse_type *itemcloak_ct = 0; - static boolean init = false; + static bool init = false; xmlNodePtr child; const char *str, *rcname, *rcillusion; - boolean disclosure = (ctx->f == u->faction || omniscient(ctx->f)); + bool disclosure = (ctx->f == u->faction || omniscient(ctx->f)); /* TODO: hitpoints, aura, combatspells, curses */ @@ -391,7 +391,7 @@ static xmlNodePtr xml_unit(report_context * ctx, unit * u, int mode) if (disclosure) { show = u->items; } else { - boolean see_items = (mode >= see_unit); + bool see_items = (mode >= see_unit); if (see_items) { if (itemcloak_ct && curse_active(get_curse(u->attribs, itemcloak_ct))) { see_items = false; diff --git a/src/gmtool.c b/src/gmtool.c index 57d715501..83d637d04 100644 --- a/src/gmtool.c +++ b/src/gmtool.c @@ -356,7 +356,7 @@ static void paint_status(window * wnd, const state * st) wclrtoeol(win); } -static boolean handle_info_region(window * wnd, state * st, int c) +static bool handle_info_region(window * wnd, state * st, int c) { return false; } @@ -1281,7 +1281,7 @@ curses_readline(struct lua_State *L, char *buffer, size_t size, return buffer[0] != 0; } -void seed_players(const char *filename, boolean new_island) +void seed_players(const char *filename, bool new_island) { newfaction *players = read_newfactions(filename); if (players != NULL) { diff --git a/src/gmtool.h b/src/gmtool.h index fa2df80e7..0359973b5 100644 --- a/src/gmtool.h +++ b/src/gmtool.h @@ -33,7 +33,7 @@ extern "C" { void state_close(struct state *); void make_block(int x, int y, int radius, const struct terrain_type *terrain); - void seed_players(const char *filename, boolean new_island); + void seed_players(const char *filename, bool new_island); #ifdef __cplusplus } diff --git a/src/gmtool_structs.h b/src/gmtool_structs.h index 49acbf526..1f3e4e9a7 100644 --- a/src/gmtool_structs.h +++ b/src/gmtool_structs.h @@ -70,13 +70,13 @@ extern "C" { } state; typedef struct window { - boolean(*handlekey) (struct window * win, struct state * st, int key); + bool(*handlekey) (struct window * win, struct state * st, int key); void (*paint) (struct window * win, const struct state * st); WINDOW *handle; struct window *next; struct window *prev; - boolean initialized; + bool initialized; int update; } window; diff --git a/src/items/phoenixcompass.c b/src/items/phoenixcompass.c index e26adfa8e..9787d4e9d 100644 --- a/src/items/phoenixcompass.c +++ b/src/items/phoenixcompass.c @@ -45,7 +45,7 @@ use_phoenixcompass(struct unit *u, const struct item_type *itype, region *r; unit *closest_phoenix = NULL; int closest_phoenix_distance = INT_MAX; - boolean confusion = false; + bool confusion = false; direction_t direction; unit *u2; direction_t closest_neighbour_direction = 0; diff --git a/src/items/weapons.c b/src/items/weapons.c index 05fbc31a5..7b817510a 100644 --- a/src/items/weapons.c +++ b/src/items/weapons.c @@ -38,7 +38,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* damage types */ -static boolean +static bool attack_firesword(const troop * at, const struct weapon_type *wtype, int *casualties) { @@ -83,7 +83,7 @@ attack_firesword(const troop * at, const struct weapon_type *wtype, #define CATAPULT_ATTACKS 6 -static boolean +static bool attack_catapult(const troop * at, const struct weapon_type *wtype, int *casualties) { diff --git a/src/kernel/alliance.c b/src/kernel/alliance.c index ede4b0dfd..afd31343d 100644 --- a/src/kernel/alliance.c +++ b/src/kernel/alliance.c @@ -452,7 +452,7 @@ int victorycondition(const alliance * al, const char *name) const struct item_type *itype = it_find(*igem); quicklist *flist = al->members; int qi; - boolean found = false; + bool found = false; assert(itype != NULL); for (qi = 0; flist && !found; ql_advance(&flist, &qi, 1)) { diff --git a/src/kernel/battle.c b/src/kernel/battle.c index 6417c1b91..7a4f1cd12 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -186,7 +186,7 @@ static char *sidename(side * s) return sidename_buf[bufno++]; } -static const char *sideabkz(side * s, boolean truename) +static const char *sideabkz(side * s, bool truename) { static char sideabkz_buf[8]; /* STATIC_RESULT: used for return, not across calls */ const faction *f = (s->stealthfaction @@ -214,7 +214,7 @@ static void message_faction(battle * b, faction * f, struct message *m) add_message(&f->battles->msgs, m); } -int armedmen(const unit * u, boolean siege_weapons) +int armedmen(const unit * u, bool siege_weapons) { item *itm; int n = 0; @@ -273,7 +273,7 @@ static void fbattlerecord(battle * b, faction * f, const char *s) #define enemy(as, ds) (as->relations[ds->index]&E_ENEMY) #define friendly(as, ds) (as->relations[ds->index]&E_FRIEND) -static boolean set_enemy(side * as, side * ds, boolean attacking) +static bool set_enemy(side * as, side * ds, bool attacking) { int i; for (i = 0; i != MAXSIDES; ++i) { @@ -366,11 +366,11 @@ fighter *select_corpse(battle * b, fighter * af) return NULL; } -boolean helping(const side * as, const side * ds) +bool helping(const side * as, const side * ds) { if (as->faction == ds->faction) return true; - return (boolean) (!enemy(as, ds) && allysf(as, ds->faction)); + return (bool) (!enemy(as, ds) && allysf(as, ds->faction)); } int statusrow(int status) @@ -414,7 +414,7 @@ static double hpflee(int status) static int get_row(const side * s, int row, const side * vs) { - boolean counted[MAXSIDES]; + bool counted[MAXSIDES]; int enemyfront = 0; int line, result; int retreat = 0; @@ -560,7 +560,7 @@ contest(int skdiff, const troop dt, const armor_type * ar, } } -static boolean is_riding(const troop t) +static bool is_riding(const troop t) { if (t.fighter->building != NULL) return false; @@ -569,7 +569,7 @@ static boolean is_riding(const troop t) return false; } -static weapon *preferred_weapon(const troop t, boolean attacking) +static weapon *preferred_weapon(const troop t, bool attacking) { weapon *missile = t.fighter->person[t.index].missile; weapon *melee = t.fighter->person[t.index].melee; @@ -586,8 +586,8 @@ static weapon *preferred_weapon(const troop t, boolean attacking) return melee; } -static weapon *select_weapon(const troop t, boolean attacking, - boolean ismissile) +static weapon *select_weapon(const troop t, bool attacking, + bool ismissile) /* select the primary weapon for this trooper */ { if (attacking) { @@ -604,7 +604,7 @@ static weapon *select_weapon(const troop t, boolean attacking, return preferred_weapon(t, attacking); } -static boolean i_canuse(const unit * u, const item_type * itype) +static bool i_canuse(const unit * u, const item_type * itype) { if (itype->canuse) { return itype->canuse(u, itype); @@ -613,7 +613,7 @@ static boolean i_canuse(const unit * u, const item_type * itype) } static int -weapon_skill(const weapon_type * wtype, const unit * u, boolean attacking) +weapon_skill(const weapon_type * wtype, const unit * u, bool attacking) /* the 'pure' skill when using this weapon to attack or defend. * only undiscriminate modifiers (not affected by troops or enemies) * are taken into account, e.g. no horses, magic, etc. */ @@ -729,8 +729,8 @@ static int CavalryBonus(const unit * u, troop enemy, int type) } static int -weapon_effskill(troop t, troop enemy, const weapon * w, boolean attacking, - boolean missile) +weapon_effskill(troop t, troop enemy, const weapon * w, bool attacking, + bool missile) /* effektiver Waffenskill während des Kampfes */ { /* In dieser Runde alle die Modifier berechnen, die fig durch die @@ -810,7 +810,7 @@ weapon_effskill(troop t, troop enemy, const weapon * w, boolean attacking, return skill; } -static const armor_type *select_armor(troop t, boolean shield) +static const armor_type *select_armor(troop t, bool shield) { unsigned int type = shield ? ATF_SHIELD : 0; unit *u = t.fighter->unit; @@ -858,7 +858,7 @@ int select_magicarmor(troop t) } /* Sind side ds und Magier des meffect verbündet, dann return 1*/ -boolean meffect_protection(battle * b, meffect * s, side * ds) +bool meffect_protection(battle * b, meffect * s, side * ds) { if (!s->magician->alive) return false; @@ -872,7 +872,7 @@ boolean meffect_protection(battle * b, meffect * s, side * ds) } /* Sind side as und Magier des meffect verfeindet, dann return 1*/ -boolean meffect_blocked(battle * b, meffect * s, side * as) +bool meffect_blocked(battle * b, meffect * s, side * as) { if (!s->magician->alive) return false; @@ -1051,8 +1051,8 @@ static int natural_armor(unit * du) return an; } -boolean -terminate(troop dt, troop at, int type, const char *damage, boolean missile) +bool +terminate(troop dt, troop at, int type, const char *damage, bool missile) { item **pitm; fighter *df = dt.fighter; @@ -1076,7 +1076,7 @@ terminate(troop dt, troop at, int type, const char *damage, boolean missile) const weapon *weapon; int rda, sk = 0, sd; - boolean magic = false; + bool magic = false; int da = dice_rand(damage); assert(du->number > 0); @@ -1864,7 +1864,7 @@ int skilldiff(troop at, troop dt, int dist) } if (df->building) { - boolean init = false; + bool init = false; static const curse_type *strongwall_ct, *magicwalls_ct; if (!init) { strongwall_ct = ct_find("strongwall"); @@ -1934,7 +1934,7 @@ int getreload(troop at) static void debug_hit(troop at, const weapon * awp, troop dt, const weapon * dwp, - int skdiff, int dist, boolean success) + int skdiff, int dist, bool success) { fprintf(bdebug, "%.4s/%d [%6s/%d] %s %.4s/%d [%6s/%d] with %d, distance %d\n", unitid(at.fighter->unit), at.index, @@ -2112,8 +2112,8 @@ static void attack(battle * b, troop ta, const att * a, int numattack) if (getreload(ta)) { ta.fighter->person[ta.index].reload--; } else { - boolean standard_attack = true; - boolean reload = false; + bool standard_attack = true; + bool reload = false; /* spezialattacken der waffe nur, wenn erste attacke in der runde. * sonst helden mit feuerschwertern zu mächtig */ if (numattack == 0 && wp && wp->type->attack) { @@ -2127,7 +2127,7 @@ static void attack(battle * b, troop ta, const att * a, int numattack) } } if (standard_attack) { - boolean missile = false; + bool missile = false; if (wp && fval(wp->type, WTF_MISSILE)) missile = true; if (missile) { @@ -2560,7 +2560,7 @@ static void loot_items(fighter * corpse) } } -static boolean seematrix(const faction * f, const side * s) +static bool seematrix(const faction * f, const side * s) { if (f == s->faction) return true; @@ -2626,7 +2626,7 @@ static void aftermath(battle * b) side *s; int dead_players = 0; bfaction *bf; - boolean ships_damaged = (boolean) (b->turn + (b->has_tactics_turn ? 1 : 0) > 2); /* only used for ship damage! */ + bool ships_damaged = (bool) (b->turn + (b->has_tactics_turn ? 1 : 0) > 2); /* only used for ship damage! */ for (s = b->sides; s != b->sides + b->nsides; ++s) { fighter *df; @@ -2672,7 +2672,7 @@ static void aftermath(battle * b) for (s = b->sides; s != b->sides + b->nsides; ++s) { int snumber = 0; fighter *df; - boolean relevant = false; /* Kampf relevant für diese Partei? */ + bool relevant = false; /* Kampf relevant für diese Partei? */ if (!fval(s, SIDE_HASGUARDS)) { relevant = true; } @@ -2920,7 +2920,7 @@ static void print_fighters(battle * b, const side * s) } } -boolean is_attacker(const fighter * fig) +bool is_attacker(const fighter * fig) { return fval(fig, FIG_ATTACKER) != 0; } @@ -2939,7 +2939,7 @@ static void print_header(battle * b) message *m; faction *f = bf->faction; const char *lastf = NULL; - boolean first = false; + bool first = false; side *s; char *bufp = zText; size_t size = sizeof(zText) - 1; @@ -3129,7 +3129,7 @@ static void print_stats(battle * b) } } -static int weapon_weight(const weapon * w, boolean missile) +static int weapon_weight(const weapon * w, bool missile) { if (missile == i2b(fval(w->type, WTF_MISSILE))) { return w->attackskill + w->defenseskill; @@ -3137,7 +3137,7 @@ static int weapon_weight(const weapon * w, boolean missile) return 0; } -fighter *make_fighter(battle * b, unit * u, side * s1, boolean attack) +fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) { #define WMAX 20 weapon weapons[WMAX]; @@ -3153,7 +3153,7 @@ fighter *make_fighter(battle * b, unit * u, side * s1, boolean attack) int berserk; int strongmen; int speeded = 0, speed = 1; - boolean pr_aid = false; + bool pr_aid = false; int rest; const group *g = NULL; const attrib *a = a_find(u->attribs, &at_otherfaction); @@ -3459,7 +3459,7 @@ fighter *make_fighter(battle * b, unit * u, side * s1, boolean attack) return fig; } -static int join_battle(battle * b, unit * u, boolean attack, fighter ** cp) +static int join_battle(battle * b, unit * u, bool attack, fighter ** cp) { side *s; fighter *c = NULL; @@ -3650,8 +3650,8 @@ static int *get_alive(side * s) static int battle_report(battle * b) { side *s, *s2; - boolean cont = false; - boolean komma; + bool cont = false; + bool komma; bfaction *bf; for (s = b->sides; s != b->sides + b->nsides; ++s) { @@ -3876,11 +3876,11 @@ static void flee(const troop dt) kill_troop(dt); } -static boolean init_battle(region * r, battle ** bp) +static bool init_battle(region * r, battle ** bp) { battle *b = NULL; unit *u; - boolean fighting = false; + bool fighting = false; /* list_foreach geht nicht, wegen flucht */ for (u = r->units; u != NULL; u = u->next) { @@ -3890,7 +3890,7 @@ static boolean init_battle(region * r, battle ** bp) order *ord; for (ord = u->orders; ord; ord = ord->next) { - static boolean init = false; + static bool init = false; static const curse_type *peace_ct, *slave_ct, *calm_ct; if (!init) { @@ -3989,7 +3989,7 @@ static boolean init_battle(region * r, battle ** bp) if (calm_ct) { attrib *a = a_find(u->attribs, &at_curse); - boolean calm = false; + bool calm = false; while (a && a->type == &at_curse) { curse *c = (curse *) a->data.v; if (c->type == calm_ct @@ -4239,7 +4239,7 @@ static void battle_flee(battle * b) void do_battle(region * r) { battle *b = NULL; - boolean fighting = false; + bool fighting = false; ship *sh; static int init_rules = 0; diff --git a/src/kernel/battle.h b/src/kernel/battle.h index bc8acc66f..c962e32bb 100644 --- a/src/kernel/battle.h +++ b/src/kernel/battle.h @@ -46,7 +46,7 @@ extern "C" { struct bfaction *next; struct side *sides; struct faction *faction; - boolean attacker; + bool attacker; } bfaction; typedef struct tactics { @@ -94,9 +94,9 @@ extern "C" { struct quicklist *meffects; int max_tactics; int turn; - boolean has_tactics_turn; + bool has_tactics_turn; int keeploot; - boolean reelarrow; + bool reelarrow; int alive; struct { const struct side *as; @@ -218,8 +218,8 @@ extern "C" { extern int count_enemies(struct battle *b, const struct fighter *af, int minrow, int maxrow, int select); - extern boolean terminate(troop dt, troop at, int type, const char *damage, - boolean missile); + extern bool terminate(troop dt, troop at, int type, const char *damage, + bool missile); extern void message_all(battle * b, struct message *m); extern int hits(troop at, troop dt, weapon * awp); extern void damage_building(struct battle *b, struct building *bldg, @@ -229,18 +229,18 @@ extern "C" { extern int count_allies(const struct side *as, int minrow, int maxrow, int select, int allytype); extern int get_unitrow(const struct fighter *af, const struct side *vs); - extern boolean helping(const struct side *as, const struct side *ds); + extern bool helping(const struct side *as, const struct side *ds); extern void rmfighter(fighter * df, int i); extern struct fighter *select_corpse(struct battle *b, struct fighter *af); extern int statusrow(int status); extern void drain_exp(struct unit *u, int d); extern void kill_troop(troop dt); extern void remove_troop(troop dt); /* not the same as the badly named rmtroop */ - extern boolean is_attacker(const fighter * fig); + extern bool is_attacker(const fighter * fig); extern struct battle *make_battle(struct region * r); extern fighter *make_fighter(struct battle *b, struct unit *u, side * s, - boolean attack); + bool attack); extern struct side *make_side(struct battle * b, const struct faction * f, const struct group * g, unsigned int flags, const struct faction * stealthfaction); diff --git a/src/kernel/building.c b/src/kernel/building.c index 0b695622d..4ba7cad10 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -180,7 +180,7 @@ const char *buildingtype(const building_type * btype, const building * b, int bsize) { const char *s = NULL; - static boolean init_generic = false; + static bool init_generic = false; static const struct building_type *bt_generic; if (!init_generic) { @@ -451,7 +451,7 @@ building *new_building(const struct building_type * btype, region * r, { building **bptr = &r->buildings; building *b = (building *) calloc(1, sizeof(building)); - static boolean init_lighthouse = false; + static bool init_lighthouse = false; static const struct building_type *bt_lighthouse = 0; const char *bname = 0; char buffer[32]; @@ -501,7 +501,7 @@ void remove_building(building ** blist, building * b) { unit *u; static const struct building_type *bt_caravan, *bt_dam, *bt_tunnel; - static boolean init = false; + static bool init = false; if (!init) { init = true; diff --git a/src/kernel/config.c b/src/kernel/config.c index e66dc0f79..08970f71b 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -95,8 +95,8 @@ struct settings global = { FILE *logfile; FILE *updatelog; const struct race *new_race[MAXRACES]; -boolean sqlpatch = false; -boolean battledebug = false; +bool sqlpatch = false; +bool battledebug = false; int turn = 0; int NewbieImmunity(void) @@ -110,7 +110,7 @@ int NewbieImmunity(void) return value; } -boolean IsImmune(const faction * f) +bool IsImmune(const faction * f) { return !fval(f, FFL_NPC) && f->age < NewbieImmunity(); } @@ -143,7 +143,7 @@ static int ally_flag(const char *s, int help_mask) return 0; } -boolean ExpensiveMigrants(void) +bool ExpensiveMigrants(void) { static int value = -1; static int gamecookie = -1; @@ -617,7 +617,7 @@ int shipspeed(const ship * sh, const unit * u) { double k = sh->type->range; static const curse_type *stormwind_ct, *nodrift_ct; - static boolean init; + static bool init; attrib *a; curse *c; @@ -829,7 +829,7 @@ int eff_stealth(const unit * u, const region * r) return e; } -boolean unit_has_cursed_item(unit * u) +bool unit_has_cursed_item(unit * u) { item *itm = u->items; while (itm) { @@ -855,7 +855,7 @@ static void init_gms(void) static int autoalliance(const plane * pl, const faction * sf, const faction * f2) { - static boolean init = false; + static bool init = false; if (!init) { init_gms(); init = true; @@ -959,7 +959,7 @@ int alliedunit(const unit * u, const faction * f2, int mode) return 0; } -boolean +bool seefaction(const faction * f, const region * r, const unit * u, int modifier) { if (((f == u->faction) || !fval(u, UFL_ANON_FACTION)) @@ -968,7 +968,7 @@ seefaction(const faction * f, const region * r, const unit * u, int modifier) return false; } -boolean +bool cansee(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 @@ -977,7 +977,7 @@ cansee(const faction * f, const region * r, const unit * u, int modifier) int stealth, rings; unit *u2 = r->units; static const item_type *itype_grail; - static boolean init; + static bool init; if (!init) { init = true; @@ -1037,7 +1037,7 @@ cansee(const faction * f, const region * r, const unit * u, int modifier) return false; } -boolean cansee_unit(const unit * u, const unit * target, int modifier) +bool cansee_unit(const unit * u, const unit * target, int modifier) /* target->region kann != u->region sein, wenn es um durchreisen geht */ { if (fval(target->race, RCF_INVISIBLE) || target->number == 0) @@ -1073,7 +1073,7 @@ boolean cansee_unit(const unit * u, const unit * target, int modifier) return false; } -boolean +bool cansee_durchgezogen(const faction * f, const region * r, const unit * u, int modifier) /* r kann != u->region sein, wenn es um durchreisen geht */ @@ -1144,7 +1144,7 @@ static attrib_type at_lighthouse = { */ void update_lighthouse(building * lh) { - static boolean init_lighthouse = false; + static bool init_lighthouse = false; static const struct building_type *bt_lighthouse = 0; if (!init_lighthouse) { @@ -1256,7 +1256,7 @@ void init_tokens(const struct order *ord) } void -parse(keyword_t kword, int (*dofun) (unit *, struct order *), boolean thisorder) +parse(keyword_t kword, int (*dofun) (unit *, struct order *), bool thisorder) { region *r; @@ -1502,7 +1502,7 @@ int read_unitid(const faction * f, const region * r) } /* exported symbol */ -boolean getunitpeasants; +bool getunitpeasants; unit *getunitg(const region * r, const faction * f) { int n = read_unitid(f, r); @@ -1565,7 +1565,7 @@ void freestrlist(strlist * s) /* - Meldungen und Fehler ------------------------------------------------- */ -boolean lomem = false; +bool lomem = false; /* - Namen der Strukturen -------------------------------------- */ typedef char name[OBJECTIDSIZE + 1]; @@ -1615,7 +1615,7 @@ char *cstring(const char *s) } building *largestbuilding(const region * r, cmp_building_cb cmp_gt, - boolean imaginary) + bool imaginary) { building *b, *best = NULL; @@ -1720,9 +1720,9 @@ unit *createunit(region * r, faction * f, int number, const struct race * rc) return create_unit(r, f, number, rc, 0, NULL, NULL); } -boolean idle(faction * f) +bool idle(faction * f) { - return (boolean) (f ? false : true); + return (bool) (f ? false : true); } int maxworkingpeasants(const struct region *r) @@ -1765,7 +1765,7 @@ int lighthouse_range(const building * b, const faction * f) return d; } -boolean check_leuchtturm(region * r, faction * f) +bool check_leuchtturm(region * r, faction * f) { attrib *a; @@ -2364,7 +2364,7 @@ void remove_empty_units(void) } } -boolean faction_id_is_unused(int id) +bool faction_id_is_unused(int id) { return findfaction(id) == NULL; } @@ -2461,7 +2461,7 @@ int lifestyle(const unit * u) return need; } -boolean has_horses(const struct unit * u) +bool has_horses(const struct unit * u) { item *itm = u->items; for (; itm; itm = itm->next) { @@ -2471,7 +2471,7 @@ boolean has_horses(const struct unit * u) return false; } -boolean hunger(int number, unit * u) +bool hunger(int number, unit * u) { region *r = u->region; int dead = 0, hpsub = 0; @@ -2520,7 +2520,7 @@ boolean hunger(int number, unit * u) return (dead || hpsub); } -void plagues(region * r, boolean ismagic) +void plagues(region * r, bool ismagic) { int peasants; int i; @@ -2584,7 +2584,7 @@ int cmp_wage(const struct building *b, const building * a) return -1; } -boolean is_owner_building(const struct building * b) +bool is_owner_building(const struct building * b) { region *r = b->region; if (b->type->taxes && r->land && r->land->ownership) { @@ -2754,7 +2754,7 @@ default_wage(const region * r, const faction * f, const race * rc, int in_turn) attrib *a; const building_type *artsculpture_type = bt_find("artsculpture"); static const curse_type *drought_ct, *blessedharvest_ct; - static boolean init; + static bool init; if (!init) { init = true; @@ -2895,7 +2895,7 @@ int movewhere(const unit * u, const char *token, region * r, region ** resultp) return E_MOVE_OK; } -boolean move_blocked(const unit * u, const region * r, const region * r2) +bool move_blocked(const unit * u, const region * r, const region * r2) { connection *b; curse *c; @@ -2944,7 +2944,7 @@ int lovar(double xpct_x2) return (rng_int() % n + rng_int() % n) / 1000; } -boolean has_limited_skills(const struct unit * u) +bool has_limited_skills(const struct unit * u) { if (has_skill(u, SK_MAGIC) || has_skill(u, SK_ALCHEMY) || has_skill(u, SK_TACTICS) || has_skill(u, SK_HERBALISM) || diff --git a/src/kernel/config.h b/src/kernel/config.h index 6e8a1a142..e85325bc1 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -111,7 +111,7 @@ extern "C" { extern int shipspeed(const struct ship *sh, const struct unit *u); -#define i2b(i) ((boolean)((i)?(true):(false))) +#define i2b(i) ((bool)((i)?(true):(false))) typedef struct ally { struct ally *next; @@ -136,10 +136,10 @@ extern "C" { extern int verbosity; /* parteinummern */ - extern boolean faction_id_is_unused(int); + extern bool faction_id_is_unused(int); /* leuchtturm */ - extern boolean check_leuchtturm(struct region *r, struct faction *f); + extern bool check_leuchtturm(struct region *r, struct faction *f); extern void update_lighthouse(struct building *lh); extern int lighthouse_range(const struct building *b, const struct faction *f); @@ -159,7 +159,7 @@ extern "C" { void addstrlist(strlist ** SP, const char *s); - int armedmen(const struct unit *u, boolean siege_weapons); + int armedmen(const struct unit *u, bool siege_weapons); unsigned int atoip(const char *s); unsigned int getuint(void); @@ -188,13 +188,13 @@ extern "C" { #define factionid(x) itoa36((x)->no) #define curseid(x) itoa36((x)->no) - extern boolean cansee(const struct faction *f, const struct region *r, + extern bool cansee(const struct faction *f, const struct region *r, const struct unit *u, int modifier); - boolean cansee_durchgezogen(const struct faction *f, const struct region *r, + bool cansee_durchgezogen(const struct faction *f, const struct region *r, const struct unit *u, int modifier); - extern boolean cansee_unit(const struct unit *u, const struct unit *target, + extern bool cansee_unit(const struct unit *u, const struct unit *target, int modifier); - boolean seefaction(const struct faction *f, const struct region *r, + bool seefaction(const struct faction *f, const struct region *r, const struct unit *u, int modifier); extern int effskill(const struct unit *u, skill_t sk); @@ -210,7 +210,7 @@ extern "C" { extern struct unit *createunit(struct region *r, struct faction *f, int number, const struct race *rc); extern void create_unitid(struct unit *u, int id); - extern boolean getunitpeasants; + extern bool getunitpeasants; extern struct unit *getunitg(const struct region *r, const struct faction *f); extern struct unit *getunit(const struct region *r, const struct faction *f); @@ -242,7 +242,7 @@ extern "C" { typedef int (*cmp_building_cb) (const struct building * b, const struct building * a); struct building *largestbuilding(const struct region *r, cmp_building_cb, - boolean imaginary); + bool imaginary); int cmp_wage(const struct building *b, const struct building *bother); int cmp_taxes(const struct building *b, const struct building *bother); int cmp_current_owner(const struct building *b, @@ -265,7 +265,7 @@ extern "C" { extern int count_migrants(const struct faction *f); extern int count_maxmigrants(const struct faction *f); - extern boolean has_limited_skills(const struct unit *u); + extern bool has_limited_skills(const struct unit *u); extern const struct race *findrace(const char *, const struct locale *); int eff_stealth(const struct unit *u, const struct region *r); @@ -273,7 +273,7 @@ extern "C" { int check_option(struct faction *f, int option); extern void parse(keyword_t kword, int (*dofun) (struct unit *, - struct order *), boolean thisorder); + struct order *), bool thisorder); /* Anzahl Personen in einer Einheit festlegen. NUR (!) mit dieser Routine, * sonst großes Unglück. Durch asserts an ein paar Stellen abgesichert. */ @@ -293,8 +293,8 @@ extern "C" { void fhash(struct faction *f); void funhash(struct faction *f); - boolean idle(struct faction *f); - boolean unit_has_cursed_item(struct unit *u); + bool idle(struct faction *f); + bool unit_has_cursed_item(struct unit *u); /* simple garbage collection: */ void *gc_add(void *p); @@ -344,18 +344,18 @@ extern "C" { */ unsigned int guard_flags(const struct unit *u); - extern boolean hunger(int number, struct unit *u); + extern bool hunger(int number, struct unit *u); extern int lifestyle(const struct unit *); extern int besieged(const struct unit *u); extern int maxworkingpeasants(const struct region *r); - extern boolean has_horses(const struct unit *u); + extern bool has_horses(const struct unit *u); extern int markets_module(void); extern int wage(const struct region *r, const struct faction *f, const struct race *rc, int in_turn); extern int maintenance_cost(const struct unit *u); extern struct message *movement_error(struct unit *u, const char *token, struct order *ord, int error_code); - extern boolean move_blocked(const struct unit *u, const struct region *src, + extern bool move_blocked(const struct unit *u, const struct region *src, const struct region *dest); extern void add_income(struct unit *u, int type, int want, int qty); @@ -392,7 +392,7 @@ extern "C" { const char *gamename; struct attrib *attribs; unsigned int data_turn; - boolean disabled[MAXKEYWORDS]; + bool disabled[MAXKEYWORDS]; struct param *parameters; void *vm_state; float producexpchance; @@ -409,9 +409,9 @@ extern "C" { extern int produceexp(struct unit *u, skill_t sk, int n); - extern boolean battledebug; - extern boolean sqlpatch; - extern boolean lomem; /* save memory */ + extern bool battledebug; + extern bool sqlpatch; + extern bool lomem; /* save memory */ extern const char *dbrace(const struct race *rc); @@ -421,19 +421,19 @@ extern "C" { extern float get_param_flt(const struct param *p, const char *name, float def); - extern boolean ExpensiveMigrants(void); + extern bool ExpensiveMigrants(void); extern int NMRTimeout(void); extern int LongHunger(const struct unit *u); extern int SkillCap(skill_t sk); extern int NewbieImmunity(void); - extern boolean IsImmune(const struct faction *f); + extern bool IsImmune(const struct faction *f); extern int AllianceAuto(void); /* flags that allied factions get automatically */ extern int AllianceRestricted(void); /* flags restricted to allied factions */ extern int HelpMask(void); /* flags restricted to allied factions */ extern struct order *default_order(const struct locale *lang); extern int entertainmoney(const struct region *r); - extern void plagues(struct region *r, boolean ismagic); + extern void plagues(struct region *r, bool ismagic); typedef struct helpmode { const char *name; int status; diff --git a/src/kernel/connection.c b/src/kernel/connection.c index 5d4d24d19..7bbb2e75a 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -224,21 +224,21 @@ void b_write(const connection * b, storage * store) } } -boolean b_transparent(const connection * b, const struct faction *f) +bool b_transparent(const connection * b, const struct faction *f) { unused(b); unused(f); return true; } -boolean b_opaque(const connection * b, const struct faction * f) +bool b_opaque(const connection * b, const struct faction * f) { unused(b); unused(f); return false; } -boolean b_blockall(const connection * b, const unit * u, const region * r) +bool b_blockall(const connection * b, const unit * u, const region * r) { unused(u); unused(r); @@ -246,7 +246,7 @@ boolean b_blockall(const connection * b, const unit * u, const region * r) return true; } -boolean b_blocknone(const connection * b, const unit * u, const region * r) +bool b_blocknone(const connection * b, const unit * u, const region * r) { unused(u); unused(r); @@ -254,12 +254,12 @@ boolean b_blocknone(const connection * b, const unit * u, const region * r) return false; } -boolean b_rvisible(const connection * b, const region * r) +bool b_rvisible(const connection * b, const region * r) { - return (boolean) (b->to == r || b->from == r); + return (bool) (b->to == r || b->from == r); } -boolean b_fvisible(const connection * b, const struct faction * f, +bool b_fvisible(const connection * b, const struct faction * f, const region * r) { unused(r); @@ -268,21 +268,21 @@ boolean b_fvisible(const connection * b, const struct faction * f, return true; } -boolean b_uvisible(const connection * b, const unit * u) +bool b_uvisible(const connection * b, const unit * u) { unused(u); unused(b); return true; } -boolean b_rinvisible(const connection * b, const region * r) +bool b_rinvisible(const connection * b, const region * r) { unused(r); unused(b); return false; } -boolean b_finvisible(const connection * b, const struct faction * f, +bool b_finvisible(const connection * b, const struct faction * f, const region * r) { unused(r); @@ -291,7 +291,7 @@ boolean b_finvisible(const connection * b, const struct faction * f, return false; } -boolean b_uinvisible(const connection * b, const unit * u) +bool b_uinvisible(const connection * b, const unit * u) { unused(u); unused(b); @@ -399,14 +399,14 @@ static const char *b_namefogwall(const connection * b, const region * r, return LOC(f->locale, mkname("border", "fogwall")); } -static boolean +static bool b_blockfogwall(const connection * b, const unit * u, const region * r) { unused(b); unused(r); if (!u) return true; - return (boolean) (effskill(u, SK_PERCEPTION) > 4); /* Das ist die alte Nebelwand */ + return (bool) (effskill(u, SK_PERCEPTION) > 4); /* Das ist die alte Nebelwand */ } /** Legacy type used in old Eressea games, no longer in use. */ @@ -458,7 +458,7 @@ border_type bt_illusionwall = { * special quest door ***/ -boolean b_blockquestportal(const connection * b, const unit * u, +bool b_blockquestportal(const connection * b, const unit * u, const region * r) { if (b->data.i > 0) @@ -558,14 +558,14 @@ static void b_writeroad(const connection * b, storage * store) store->w_int(store, b->data.sa[1]); } -static boolean b_validroad(const connection * b) +static bool b_validroad(const connection * b) { if (b->data.sa[0] == SHRT_MAX) return false; return true; } -static boolean b_rvisibleroad(const connection * b, const region * r) +static bool b_rvisibleroad(const connection * b, const region * r) { int x = b->data.i; x = (r == b->from) ? b->data.sa[0] : b->data.sa[1]; diff --git a/src/kernel/connection.h b/src/kernel/connection.h index 62e09771e..b582377c5 100644 --- a/src/kernel/connection.h +++ b/src/kernel/connection.h @@ -39,7 +39,7 @@ extern "C" { typedef struct border_type { const char *__name; /* internal use only */ variant_type datatype; - boolean(*transparent) (const connection *, const struct faction *); + bool(*transparent) (const connection *, const struct faction *); /* is it possible to see through this? */ void (*init) (connection *); /* constructor: initialize the connection. allocate extra memory if needed */ @@ -47,7 +47,7 @@ extern "C" { /* destructor: remove all extra memory for destruction */ void (*read) (connection *, struct storage *); void (*write) (const connection *, struct storage *); - boolean(*block) (const connection *, const struct unit *, + bool(*block) (const connection *, const struct unit *, const struct region * r); /* return true if it blocks movement of u from * r to the opposite struct region. @@ -59,11 +59,11 @@ extern "C" { * may depend on the struct faction, for example "a wall" may * turn out to be "an illusionary wall" */ - boolean(*rvisible) (const connection *, const struct region *); + bool(*rvisible) (const connection *, const struct region *); /* is it visible to everyone in r ? * if not, it may still be fvisible() for some f. */ - boolean(*fvisible) (const connection *, const struct faction *, + bool(*fvisible) (const connection *, const struct faction *, const struct region *); /* is it visible to units of f in r? * the function shall not check for @@ -73,16 +73,16 @@ extern "C" { * the reporting function will have to assure). * if not true, it may still be uvisible() for some u. */ - boolean(*uvisible) (const connection *, const struct unit *); + bool(*uvisible) (const connection *, const struct unit *); /* is it visible to u ? * a doorway may only be visible to a struct unit with perception > 5 */ - boolean(*valid) (const connection *); + bool(*valid) (const connection *); /* is the connection in a valid state, * or should it be erased at the end of this turn to save space? */ struct region *(*move) (const connection *, struct unit * u, - struct region * from, struct region * to, boolean routing); + struct region * from, struct region * to, bool routing); /* executed when the units traverses this connection */ int (*age) (struct connection *); /* return 0 if connection needs to be removed. >0 if still aging, <0 if not aging */ @@ -112,20 +112,20 @@ extern "C" { /* provide default implementations for some member functions: */ extern void b_read(connection * b, struct storage *store); extern void b_write(const connection * b, struct storage *store); - extern boolean b_blockall(const connection *, const struct unit *, + extern bool b_blockall(const connection *, const struct unit *, const struct region *); - extern boolean b_blocknone(const connection *, const struct unit *, + extern bool b_blocknone(const connection *, const struct unit *, const struct region *); - extern boolean b_rvisible(const connection *, const struct region *r); - extern boolean b_fvisible(const connection *, const struct faction *f, + extern bool b_rvisible(const connection *, const struct region *r); + extern bool b_fvisible(const connection *, const struct faction *f, const struct region *); - extern boolean b_uvisible(const connection *, const struct unit *u); - extern boolean b_rinvisible(const connection *, const struct region *r); - extern boolean b_finvisible(const connection *, const struct faction *f, + extern bool b_uvisible(const connection *, const struct unit *u); + extern bool b_rinvisible(const connection *, const struct region *r); + extern bool b_finvisible(const connection *, const struct faction *f, const struct region *); - extern boolean b_uinvisible(const connection *, const struct unit *u); - extern boolean b_transparent(const connection *, const struct faction *); - extern boolean b_opaque(const connection *, const struct faction *); /* !transparent */ + extern bool b_uinvisible(const connection *, const struct unit *u); + extern bool b_transparent(const connection *, const struct faction *); + extern bool b_opaque(const connection *, const struct faction *); /* !transparent */ extern border_type bt_fogwall; extern border_type bt_noway; diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 4a7403e69..5dfa9c3f1 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -322,7 +322,7 @@ const curse_type *ct_find(const char *c) * einen pointer auf die struct zurück. */ -boolean cmp_curse(const attrib * a, const void *data) +bool cmp_curse(const attrib * a, const void *data) { const curse *c = (const curse *)data; if (a->type->flags & ATF_CURSE) { @@ -332,7 +332,7 @@ boolean cmp_curse(const attrib * a, const void *data) return false; } -boolean cmp_cursetype(const attrib * a, const void *data) +bool cmp_cursetype(const attrib * a, const void *data) { const curse_type *ct = (const curse_type *)data; if (a->type->flags & ATF_CURSE) { @@ -343,7 +343,7 @@ boolean cmp_cursetype(const attrib * a, const void *data) } curse *get_cursex(attrib * ap, const curse_type * ctype, variant data, - boolean(*compare) (const curse *, variant)) + bool(*compare) (const curse *, variant)) { attrib *a = a_select(ap, ctype, cmp_cursetype); while (a) { @@ -582,7 +582,7 @@ static void do_transfer_curse(curse * c, unit * u, unit * u2, int n) { int cursedmen = 0; int men = get_cursedmen(u, c); - boolean dogive = false; + bool dogive = false; const curse_type *ct = c->type; switch ((ct->flags | c->flags) & CURSE_SPREADMASK) { @@ -639,7 +639,7 @@ void transfer_curse(unit * u, unit * u2, int n) /* ------------------------------------------------------------- */ -boolean curse_active(const curse * c) +bool curse_active(const curse * c) { if (!c) return false; @@ -651,7 +651,7 @@ boolean curse_active(const curse * c) return true; } -boolean is_cursed_internal(attrib * ap, const curse_type * ct) +bool is_cursed_internal(attrib * ap, const curse_type * ct) { curse *c = get_curse(ap, ct); @@ -661,7 +661,7 @@ boolean is_cursed_internal(attrib * ap, const curse_type * ct) return true; } -boolean is_cursed_with(const attrib * ap, const curse * c) +bool is_cursed_with(const attrib * ap, const curse * c) { const attrib *a = ap; diff --git a/src/kernel/curse.h b/src/kernel/curse.h index ee2f7899e..a4b2f9c80 100644 --- a/src/kernel/curse.h +++ b/src/kernel/curse.h @@ -248,7 +248,7 @@ extern "C" { extern void destroy_curse(curse * c); - boolean is_cursed_internal(struct attrib *ap, const curse_type * ctype); + bool is_cursed_internal(struct attrib *ap, const curse_type * ctype); /* ignoriert CURSE_ISNEW */ extern void remove_curse(struct attrib **ap, const struct curse *c); @@ -281,7 +281,7 @@ extern "C" { * */ extern struct curse *get_cursex(struct attrib *ap, const curse_type * ctype, - variant data, boolean(*compare) (const struct curse *, variant)); + variant data, bool(*compare) (const struct curse *, variant)); /* gibt pointer auf die erste curse-struct zurück, deren Typ ctype ist, * und für die compare() true liefert, oder einen NULL-pointer. * */ @@ -303,15 +303,15 @@ extern "C" { extern void curse_done(struct attrib *a); extern int curse_age(struct attrib *a); - extern boolean cmp_curse(const struct attrib *a, const void *data); - extern boolean cmp_cursetype(const struct attrib *a, const void *data); + extern bool cmp_curse(const struct attrib *a, const void *data); + extern bool cmp_cursetype(const struct attrib *a, const void *data); extern double destr_curse(struct curse *c, int cast_level, double force); extern int resolve_curse(variant data, void *address); - extern boolean is_cursed_with(const struct attrib *ap, const struct curse *c); + extern bool is_cursed_with(const struct attrib *ap, const struct curse *c); - extern boolean curse_active(const struct curse *c); + extern bool curse_active(const struct curse *c); /* gibt true, wenn der Curse nicht NULL oder inaktiv ist */ /*** COMPATIBILITY MACROS. DO NOT USE FOR NEW CODE, REPLACE IN OLD CODE: */ diff --git a/src/kernel/faction.c b/src/kernel/faction.c index 009922bca..8bf86e30a 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -258,7 +258,7 @@ unit *addplayer(region * r, faction * f) return u; } -boolean checkpasswd(const faction * f, const char *passwd, boolean shortp) +bool checkpasswd(const faction * f, const char *passwd, bool shortp) { if (unicode_utf8_strcasecmp(f->passw, passwd) == 0) return true; @@ -490,14 +490,14 @@ void faction_setpassword(faction * f, const char *passw) f->passw = strdup(itoa36(rng_int())); } -boolean valid_race(const struct faction *f, const struct race *rc) +bool valid_race(const struct faction *f, const struct race *rc) { if (f->race == rc) return true; else { const char *str = get_param(f->race->parameters, "other_race"); if (str) - return (boolean) (rc_find(str) == rc); + return (bool) (rc_find(str) == rc); return false; } } diff --git a/src/kernel/faction.h b/src/kernel/faction.h index a81d0545c..e68cf8bcd 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -87,7 +87,7 @@ extern "C" { int no_units; struct ally *allies; struct group *groups; - boolean alive; /* enno: sollte ein flag werden */ + bool alive; /* enno: sollte ein flag werden */ int nregions; int money; #if SCORE_MODULE @@ -118,8 +118,8 @@ extern "C" { extern struct unit *addplayer(struct region *r, faction * f); extern struct faction *addfaction(const char *email, const char *password, const struct race *frace, const struct locale *loc, int subscription); - extern boolean checkpasswd(const faction * f, const char *passwd, - boolean shortp); + extern bool checkpasswd(const faction * f, const char *passwd, + bool shortp); extern void destroyfaction(faction * f); extern void set_alliance(struct faction *a, struct faction *b, int status); @@ -150,7 +150,7 @@ extern "C" { const char *faction_getpassword(const struct faction *self); void faction_setpassword(struct faction *self, const char *password); - boolean valid_race(const struct faction *f, const struct race *rc); + bool valid_race(const struct faction *f, const struct race *rc); struct spellbook * faction_get_spellbook(struct faction *f); #ifdef __cplusplus diff --git a/src/kernel/group.c b/src/kernel/group.c index a0b5821c5..8b6144d82 100755 --- a/src/kernel/group.c +++ b/src/kernel/group.c @@ -175,7 +175,7 @@ void set_group(struct unit *u, struct group *g) } } -boolean join_group(unit * u, const char *name) +bool join_group(unit * u, const char *name) { group *g = NULL; diff --git a/src/kernel/group.h b/src/kernel/group.h index 14dd119cd..17b44ab3d 100755 --- a/src/kernel/group.h +++ b/src/kernel/group.h @@ -38,7 +38,7 @@ extern "C" { } group; extern struct attrib_type at_group; /* attribute for units assigned to a group */ - extern boolean join_group(struct unit *u, const char *name); + extern bool join_group(struct unit *u, const char *name); extern void set_group(struct unit *u, struct group *g); extern struct group * get_group(const struct unit *u); extern void free_group(struct group *g); diff --git a/src/kernel/item.c b/src/kernel/item.c index c588fbeca..fd35f0776 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -684,7 +684,7 @@ typedef struct t_item { const char *name; /* [0]: Einzahl für eigene; [1]: Mehrzahl für eigene; * [2]: Einzahl für Fremde; [3]: Mehrzahl für Fremde */ - boolean is_resource; + bool is_resource; skill_t skill; int minskill; int gewicht; diff --git a/src/kernel/item.h b/src/kernel/item.h index 7ff3b9454..be6d18272 100644 --- a/src/kernel/item.h +++ b/src/kernel/item.h @@ -132,7 +132,7 @@ extern "C" { int capacity; struct construction *construction; /* --- functions --- */ - boolean(*canuse) (const struct unit * user, + bool(*canuse) (const struct unit * user, const struct item_type * itype); int (*use) (struct unit * user, const struct item_type * itype, int amount, struct order * ord); @@ -220,7 +220,7 @@ extern "C" { int reload; /* time to reload this weapon */ weapon_mod *modifiers; /* --- functions --- */ - boolean(*attack) (const struct troop *, const struct weapon_type *, + bool(*attack) (const struct troop *, const struct weapon_type *, int *deaths); } weapon_type; diff --git a/src/kernel/magic.c b/src/kernel/magic.c index e716528ce..3f388450b 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -345,7 +345,7 @@ attrib_type at_mage = { ATF_UNIQUE }; -boolean is_mage(const unit * u) +bool is_mage(const unit * u) { return i2b(get_mage(u) != NULL); } @@ -407,7 +407,7 @@ attrib_type at_seenspell = { #define MAXSPELLS 256 -static boolean already_seen(const faction * f, const spell * sp) +static bool already_seen(const faction * f, const spell * sp) { attrib *a; @@ -912,7 +912,7 @@ void pay_spell(unit * u, const spell * sp, int cast_level, int range) * aber dann immer noch nicht können, vieleicht ist seine Stufe derzeit * nicht ausreichend oder die Komponenten fehlen. */ -boolean knowsspell(const region * r, const unit * u, const spell * sp) +bool knowsspell(const region * r, const unit * u, const spell * sp) { /* Ist überhaupt ein gültiger Spruch angegeben? */ if (!sp || sp->id == 0) { @@ -929,7 +929,7 @@ boolean knowsspell(const region * r, const unit * u, const spell * sp) * und sonstige Gegenstaende sein. */ -boolean +bool cancast(unit * u, const spell * sp, int level, int range, struct order * ord) { int k; @@ -1178,7 +1178,7 @@ double magic_resistance(unit * target) * true zurück */ -boolean +bool target_resists_magic(unit * magician, void *obj, int objtyp, int t_bonus) { double probability = 0.0; @@ -1244,9 +1244,9 @@ target_resists_magic(unit * magician, void *obj, int objtyp, int t_bonus) /* ------------------------------------------------------------- */ -boolean is_magic_resistant(unit * magician, unit * target, int resist_bonus) +bool is_magic_resistant(unit * magician, unit * target, int resist_bonus) { - return (boolean) target_resists_magic(magician, target, TYP_UNIT, + return (bool) target_resists_magic(magician, target, TYP_UNIT, resist_bonus); } @@ -1261,7 +1261,7 @@ boolean is_magic_resistant(unit * magician, unit * target, int resist_bonus) * eben) bis zu etwa 1% bei doppelt so gut wie notwendig */ -boolean fumble(region * r, unit * u, const spell * sp, int cast_grade) +bool fumble(region * r, unit * u, const spell * sp, int cast_grade) { /* X ergibt Zahl zwischen 1 und 0, je kleiner, desto besser der Magier. * 0,5*40-20=0, dh wenn der Magier doppelt so gut ist, wie der Spruch @@ -1500,7 +1500,7 @@ void regenerate_aura(void) } } -static boolean +static bool verify_ship(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) { @@ -1523,7 +1523,7 @@ verify_ship(region * r, unit * mage, const spell * sp, spllprm * spobj, return true; } -static boolean +static bool verify_building(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) { @@ -1564,7 +1564,7 @@ message *msg_unitnotfound(const struct unit * mage, struct order * ord, "unit region command id", mage, mage->region, ord, uid); } -static boolean +static bool verify_unit(region * r, unit * mage, const spell * sp, spllprm * spobj, order * ord) { @@ -1907,7 +1907,7 @@ addparam_unit(const char *const param[], spllprm ** spobjp, const unit * u, static spellparameter *add_spellparameter(region * target_r, unit * u, const char *syntax, const char *const param[], int size, struct order *ord) { - boolean fail = false; + bool fail = false; int i = 0; int p = 0; const char *c; @@ -2116,7 +2116,7 @@ typedef struct familiar_data { unit *familiar; } famililar_data; -boolean is_familiar(const unit * u) +bool is_familiar(const unit * u) { attrib *a = a_find(u->attribs, &at_familiarmage); return i2b(a != NULL); @@ -2200,7 +2200,7 @@ void remove_familiar(unit * mage) } } -boolean create_newfamiliar(unit * mage, unit * familiar) +bool create_newfamiliar(unit * mage, unit * familiar) { /* if the skill modifier for the mage does not yet exist, add it */ attrib *a; @@ -2461,7 +2461,7 @@ unit *get_clone_mage(const unit * u) return NULL; } -static boolean is_moving_ship(const region * r, ship * sh) +static bool is_moving_ship(const region * r, ship * sh) { const unit *u = ship_owner(sh); @@ -2767,7 +2767,7 @@ void magic(void) for (co = spellranks[rank].begin; co; co = co->next) { order *ord = co->order; int invalid, resist, success, cast_level = co->level; - boolean fumbled = false; + bool fumbled = false; unit *u = co->magician.u; const spell *sp = co->sp; region *target_r = co_get_region(co); diff --git a/src/kernel/magic.h b/src/kernel/magic.h index 0f5b6b56d..f2dfaa5ba 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -228,9 +228,9 @@ typedef struct sc_mage { * und initialisiert den Magiertypus mit mtyp. */ sc_mage *get_mage(const struct unit *u); /* gibt u->mage zurück, bei nicht-Magiern *NULL */ - boolean is_mage(const struct unit *u); + bool is_mage(const struct unit *u); /* gibt true, wenn u->mage gesetzt. */ - boolean is_familiar(const struct unit *u); + bool is_familiar(const struct unit *u); /* gibt true, wenn eine Familiar-Relation besteht. */ /* Sprüche */ @@ -253,7 +253,7 @@ typedef struct sc_mage { /* fügt alle Zauber des Magiegebietes der Einheit, deren Stufe kleiner * als das aktuelle Magietalent ist, in die Spruchliste der Einheit * ein */ - boolean knowsspell(const struct region *r, const struct unit *u, + bool knowsspell(const struct region *r, const struct unit *u, const struct spell * sp); /* prüft, ob die Einheit diesen Spruch gerade beherrscht, dh * mindestens die erforderliche Stufe hat. Hier können auch Abfragen @@ -277,7 +277,7 @@ typedef struct sc_mage { extern double spellpower(struct region *r, struct unit *u, const struct spell * sp, int cast_level, struct order *ord); /* ermittelt die Stärke eines Spruchs */ - boolean fumble(struct region *r, struct unit *u, const struct spell * sp, + bool fumble(struct region *r, struct unit *u, const struct spell * sp, int cast_level); /* true, wenn der Zauber misslingt, bei false gelingt der Zauber */ @@ -304,7 +304,7 @@ typedef struct sc_mage { /* gibt die für diesen Spruch derzeit notwendigen Magiepunkte auf der * geringstmöglichen Stufe zurück, schon um den Faktor der bereits * zuvor gezauberten Sprüche erhöht */ - boolean cancast(struct unit *u, const struct spell * spruch, int eff_stufe, + bool cancast(struct unit *u, const struct spell * spruch, int eff_stufe, int distance, struct order *ord); /* true, wenn Einheit alle Komponenten des Zaubers (incl. MP) für die * geringstmögliche Stufe hat und den Spruch beherrscht */ @@ -317,13 +317,13 @@ typedef struct sc_mage { /* ermittelt die effektive Stufe des Zaubers. Dabei ist cast_level * die gewünschte maximale Stufe (im Normalfall Stufe des Magiers, * bei Farcasting Stufe*2^Entfernung) */ - boolean is_magic_resistant(struct unit *magician, struct unit *target, int + bool is_magic_resistant(struct unit *magician, struct unit *target, int resist_bonus); /* Mapperfunktion für target_resists_magic() vom Typ struct unit. */ extern double magic_resistance(struct unit *target); /* gibt die Chance an, mit der einem Zauber widerstanden wird. Je * größer, desto resistenter ist da Opfer */ - boolean target_resists_magic(struct unit *magician, void *obj, int objtyp, + bool target_resists_magic(struct unit *magician, void *obj, int objtyp, int resist_bonus); /* gibt false zurück, wenn der Zauber gelingt, true, wenn das Ziel * widersteht */ @@ -339,7 +339,7 @@ typedef struct sc_mage { extern struct attrib_type at_familiar; extern struct attrib_type at_familiarmage; extern void remove_familiar(struct unit *mage); - extern boolean create_newfamiliar(struct unit *mage, struct unit *familiar); + 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); diff --git a/src/kernel/move.c b/src/kernel/move.c index 993125b43..7eed52d5f 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -187,7 +187,7 @@ static attrib_type at_driveweight = { "driveweight", NULL, NULL, NULL, NULL, NULL }; -static boolean entrance_allowed(const struct unit *u, const struct region *r) +static bool entrance_allowed(const struct unit *u, const struct region *r) { #ifdef REGIONOWNERS faction *owner = region_get_owner(r); @@ -372,7 +372,7 @@ static int canwalk(unit * u) return E_CANWALK_TOOHEAVY; } -boolean canfly(unit * u) +bool canfly(unit * u) { if (get_item(u, I_PEGASUS) >= u->number && effskill(u, SK_RIDING) >= 4) return true; @@ -386,7 +386,7 @@ boolean canfly(unit * u) return false; } -boolean canswim(unit * u) +bool canswim(unit * u) { if (get_item(u, I_DOLPHIN) >= u->number && effskill(u, SK_RIDING) >= 4) return true; @@ -448,7 +448,7 @@ static int canride(unit * u) return 0; } -static boolean cansail(const region * r, ship * sh) +static bool cansail(const region * r, ship * sh) { /* sonst ist construction:: size nicht ship_type::maxsize */ assert(!sh->type->construction @@ -584,7 +584,7 @@ ship *move_ship(ship * sh, region * from, region * to, region_list * route) { unit **iunit = &from->units; unit **ulist = &to->units; - boolean trail = (route == NULL); + bool trail = (route == NULL); if (from != to) { translist(&from->ships, &to->ships, sh); @@ -619,7 +619,7 @@ ship *move_ship(ship * sh, region * from, region * to, region_list * route) return sh; } -static boolean is_freezing(const unit * u) +static bool is_freezing(const unit * u) { if (u->race != new_race[RC_INSECT]) return false; @@ -671,7 +671,7 @@ static int is_ship_allowed(struct ship *sh, const region * r) return SA_NO_COAST; } -static boolean flying_ship(const ship * sh) +static bool flying_ship(const ship * sh) { if (sh->type->flags & SFL_FLY) return true; @@ -804,9 +804,9 @@ static void drifting_ships(region * r) } } -static boolean present(region * r, unit * u) +static bool present(region * r, unit * u) { - return (boolean) (u && u->region == r); + return (bool) (u && u->region == r); } static void caught_target(region * r, unit * u) @@ -837,7 +837,7 @@ static unit *bewegung_blockiert_von(unit * reisender, region * r) { unit *u; int perception = 0; - boolean contact = false; + bool contact = false; unit *guard = NULL; if (fval(reisender->race, RCF_ILLUSIONARY)) @@ -871,7 +871,7 @@ static unit *bewegung_blockiert_von(unit * reisender, region * r) return NULL; } -static boolean is_guardian_u(const unit * guard, unit * u, unsigned int mask) +static bool is_guardian_u(const unit * guard, unit * u, unsigned int mask) { if (guard->faction == u->faction) return false; @@ -887,7 +887,7 @@ static boolean is_guardian_u(const unit * guard, unit * u, unsigned int mask) return true; } -static boolean is_guardian_r(const unit * guard) +static bool is_guardian_r(const unit * guard) { if (guard->number == 0) return false; @@ -912,7 +912,7 @@ static boolean is_guardian_r(const unit * guard) return true; } -boolean is_guard(const struct unit * u, int mask) +bool is_guard(const struct unit * u, int mask) { return is_guardian_r(u) && (getguard(u) & mask) != 0; } @@ -1011,8 +1011,8 @@ static void cycle_route(order * ord, unit * u, int gereist) char neworder[2048]; const char *token; direction_t d = NODIRECTION; - boolean paused = false; - boolean pause; + bool paused = false; + bool pause; order *norder; size_t size = sizeof(tail) - 1; @@ -1086,7 +1086,7 @@ static void cycle_route(order * ord, unit * u, int gereist) free_order(norder); } -static boolean transport(unit * ut, unit * u) +static bool transport(unit * ut, unit * u) { order *ord; @@ -1106,7 +1106,7 @@ static boolean transport(unit * ut, unit * u) return false; } -static boolean can_move(const unit * u) +static bool can_move(const unit * u) { if (u->race->flags & RCF_CANNOTMOVE) return false; @@ -1185,7 +1185,7 @@ static void init_transportation(void) } } -static boolean roadto(const region * r, direction_t dir) +static bool roadto(const region * r, direction_t dir) { /* wenn es hier genug strassen gibt, und verbunden ist, und es dort * genug strassen gibt, dann existiert eine strasse in diese richtung */ @@ -1329,7 +1329,7 @@ static int movement_speed(unit * u) { int mp; static const curse_type *speed_ct; - static boolean init = false; + static bool init = false; double dk = u->race->speed; assert(u->number); @@ -1428,7 +1428,7 @@ static const region_list *travel_route(unit * u, region *current = u->region; const region_list *iroute = route_begin; int steps = 0; - boolean landing = false; /* aquarians have landed */ + bool landing = false; /* aquarians have landed */ while (iroute && iroute != route_end) { region *next = iroute->data; @@ -1586,7 +1586,7 @@ static const region_list *travel_route(unit * u, return iroute; } -static boolean ship_ready(const region * r, unit * u) +static bool ship_ready(const region * r, unit * u) { if (!u->ship || u!=ship_owner(u->ship)) { cmistake(u, u->thisorder, 146, MSG_MOVE); @@ -1633,8 +1633,8 @@ unit *owner_buildingtyp(const region * r, const building_type * bt) return NULL; } -boolean -buildingtype_exists(const region * r, const building_type * bt, boolean working) +bool +buildingtype_exists(const region * r, const building_type * bt, bool working) { building *b; @@ -1648,7 +1648,7 @@ buildingtype_exists(const region * r, const building_type * bt, boolean working) /* Prüft, ob Ablegen von einer Küste in eine der erlaubten Richtungen erfolgt. */ -static boolean check_takeoff(ship * sh, region * from, region * to) +static bool check_takeoff(ship * sh, region * from, region * to) { if (!fval(from->terrain, SEA_REGION) && sh->coast != NODIRECTION) { direction_t coast = sh->coast; @@ -1667,7 +1667,7 @@ static boolean check_takeoff(ship * sh, region * from, region * to) } static void -sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) +sail(unit * u, order * ord, bool move_on_land, region_list ** routep) { region *starting_point = u->region; region *current_point, *last_point; @@ -1747,7 +1747,7 @@ sail(unit * u, order * ord, boolean move_on_land, region_list ** routep) && fval(current_point->terrain, SEA_REGION)) { if (!is_cursed(sh->attribs, C_SHIP_NODRIFT, 0)) { region *rnext = NULL; - boolean storm = true; + bool storm = true; int d_offset = rng_int() % MAXDIRECTIONS; direction_t d; /* Sturm nur, wenn nächste Region Hochsee ist. */ @@ -2035,7 +2035,7 @@ static const region_list *travel_i(unit * u, const region_list * route_begin, } else if (!can_move(ut)) { cmistake(u, ord, 99, MSG_MOVE); } else { - boolean found = false; + bool found = false; if (!fval(ut, UFL_NOTMOVING) && !LongHunger(ut)) { init_tokens(ut->thisorder); @@ -2150,7 +2150,7 @@ static void travel(unit * u, region_list ** routep) } -static void move(unit * u, boolean move_on_land) +static void move(unit * u, bool move_on_land) { region_list *route = NULL; @@ -2556,7 +2556,7 @@ void movement(void) region *r = regions; while (r != NULL) { unit **up = &r->units; - boolean repeat = false; + bool repeat = false; while (*up) { unit *u = *up; @@ -2676,7 +2676,7 @@ void follow_unit(unit * u) if (a && !fval(u, UFL_MOVED | UFL_NOTMOVING)) { unit *u2 = a->data.v; - boolean follow = false; + bool follow = false; if (!u2 || u2->region != r || !cansee(u->faction, r, u2, 0)) { return; diff --git a/src/kernel/move.h b/src/kernel/move.h index e53764c29..621510d04 100644 --- a/src/kernel/move.h +++ b/src/kernel/move.h @@ -51,18 +51,18 @@ extern "C" { void movement(void); void run_to(struct unit *u, struct region *to); struct unit *is_guarded(struct region *r, struct unit *u, unsigned int mask); - boolean is_guard(const struct unit *u, int mask); + bool is_guard(const struct unit *u, int mask); int enoughsailors(const struct ship *sh, const struct region *r); - boolean canswim(struct unit *u); - boolean canfly(struct unit *u); + bool canswim(struct unit *u); + bool canfly(struct unit *u); struct unit *get_captain(const struct ship *sh); void travelthru(const struct unit *u, struct region *r); struct ship *move_ship(struct ship *sh, struct region *from, struct region *to, struct region_list *route); int walkingcapacity(const struct unit *u); void follow_unit(struct unit *u); - boolean buildingtype_exists(const struct region *r, - const struct building_type *bt, boolean working); + bool buildingtype_exists(const struct region *r, + const struct building_type *bt, bool working); struct unit *owner_buildingtyp(const struct region *r, const struct building_type *bt); diff --git a/src/kernel/pathfinder.c b/src/kernel/pathfinder.c index c9adf3251..875211deb 100644 --- a/src/kernel/pathfinder.c +++ b/src/kernel/pathfinder.c @@ -28,21 +28,21 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -boolean allowed_swim(const region * src, const region * r) +bool allowed_swim(const region * src, const region * r) { if (fval(r->terrain, SWIM_INTO)) return true; return false; } -boolean allowed_walk(const region * src, const region * r) +bool allowed_walk(const region * src, const region * r) { if (fval(r->terrain, WALK_INTO)) return true; return false; } -boolean allowed_fly(const region * src, const region * r) +bool allowed_fly(const region * src, const region * r) { if (fval(r->terrain, FLY_INTO)) return true; @@ -100,7 +100,7 @@ static void free_nodes(node * root) } struct quicklist *regions_in_range(struct region *start, int maxdist, - boolean(*allowed) (const struct region *, const struct region *)) + bool(*allowed) (const struct region *, const struct region *)) { quicklist * rlist = NULL; node *root = new_node(start, 0, NULL); @@ -140,14 +140,14 @@ struct quicklist *regions_in_range(struct region *start, int maxdist, } static region **internal_path_find(region * start, const region * target, - int maxlen, boolean(*allowed) (const region *, const region *)) + int maxlen, bool(*allowed) (const region *, const region *)) { static region *path[MAXDEPTH + 2]; /* STATIC_RETURN: used for return, not across calls */ direction_t d; node *root = new_node(start, 0, NULL); node **end = &root->next; node *n = root; - boolean found = false; + bool found = false; assert(maxlen <= MAXDEPTH); fset(start, RF_MARK); @@ -190,9 +190,9 @@ static region **internal_path_find(region * start, const region * target, return NULL; } -boolean +bool path_exists(region * start, const region * target, int maxlen, - boolean(*allowed) (const region *, const region *)) + bool(*allowed) (const region *, const region *)) { assert((!fval(start, RF_MARK) && !fval(target, RF_MARK)) || !"Some Algorithm did not clear its RF_MARKs!"); @@ -204,7 +204,7 @@ path_exists(region * start, const region * target, int maxlen, } region **path_find(region * start, const region * target, int maxlen, - boolean(*allowed) (const region *, const region *)) + bool(*allowed) (const region *, const region *)) { assert((!fval(start, RF_MARK) && !fval(target, RF_MARK)) || !"Did you call path_init()?"); diff --git a/src/kernel/pathfinder.h b/src/kernel/pathfinder.h index ac372dc34..6c9edb94e 100644 --- a/src/kernel/pathfinder.h +++ b/src/kernel/pathfinder.h @@ -29,18 +29,18 @@ extern "C" { extern struct region **path_find(struct region *start, const struct region *target, int maxlen, - boolean(*allowed) (const struct region *, const struct region *)); - extern boolean path_exists(struct region *start, const struct region *target, - int maxlen, boolean(*allowed) (const struct region *, + bool(*allowed) (const struct region *, const struct region *)); + extern bool path_exists(struct region *start, const struct region *target, + int maxlen, bool(*allowed) (const struct region *, const struct region *)); - extern boolean allowed_swim(const struct region *src, + extern bool allowed_swim(const struct region *src, const struct region *target); - extern boolean allowed_fly(const struct region *src, + extern bool allowed_fly(const struct region *src, const struct region *target); - extern boolean allowed_walk(const struct region *src, + extern bool allowed_walk(const struct region *src, const struct region *target); extern struct quicklist *regions_in_range(struct region *src, int maxdist, - boolean(*allowed) (const struct region *, const struct region *)); + bool(*allowed) (const struct region *, const struct region *)); extern void pathfinder_cleanup(void); diff --git a/src/kernel/plane.c b/src/kernel/plane.c index 111ebb675..13ea38ce9 100644 --- a/src/kernel/plane.c +++ b/src/kernel/plane.c @@ -309,7 +309,7 @@ int read_plane_reference(plane ** pp, struct storage *store) return AT_READ_OK; } -boolean is_watcher(const struct plane * p, const struct faction * f) +bool is_watcher(const struct plane * p, const struct faction * f) { struct watcher *w; if (!p) diff --git a/src/kernel/plane.h b/src/kernel/plane.h index 685a36c71..c573c096b 100644 --- a/src/kernel/plane.h +++ b/src/kernel/plane.h @@ -73,7 +73,7 @@ extern "C" { struct plane *get_homeplane(void); extern int rel_to_abs(const struct plane *pl, const struct faction *f, int rel, unsigned char index); - extern boolean is_watcher(const struct plane *p, const struct faction *f); + extern bool is_watcher(const struct plane *p, const struct faction *f); extern int resolve_plane(variant data, void *addr); extern void write_plane_reference(const plane * p, struct storage *store); extern int read_plane_reference(plane ** pp, struct storage *store); diff --git a/src/kernel/race.c b/src/kernel/race.c index 48c8b3a4a..95686c56f 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -153,7 +153,7 @@ race *rc_find(const char *name) } /** dragon movement **/ -boolean allowed_dragon(const region * src, const region * target) +bool allowed_dragon(const region * src, const region * target) { if (fval(src->terrain, ARCTIC_REGION) && fval(target->terrain, SEA_REGION)) return false; @@ -187,7 +187,7 @@ void set_show_item(faction * f, item_t i) a->data.v = (void *)olditemtype[i]; } -boolean r_insectstalled(const region * r) +bool r_insectstalled(const region * r) { return fval(r->terrain, ARCTIC_REGION); } diff --git a/src/kernel/race.h b/src/kernel/race.h index c7c7c43fc..c6f511d44 100644 --- a/src/kernel/race.h +++ b/src/kernel/race.h @@ -80,7 +80,7 @@ extern "C" { struct att attack[10]; char bonus[MAXSKILLS]; signed char *study_speed; /* study-speed-bonus in points/turn (0=30 Tage) */ - boolean __remove_me_nonplayer; + bool __remove_me_nonplayer; int flags; int battle_flags; int ec_flags; @@ -89,7 +89,7 @@ extern "C" { const char *(*generate_name) (const struct unit *); const char *(*describe) (const struct unit *, const struct locale *); void (*age) (struct unit * u); - boolean(*move_allowed) (const struct region *, const struct region *); + bool(*move_allowed) (const struct region *, const struct region *); struct item *(*itemdrop) (const struct race *, int size); void (*init_familiar) (struct unit *); @@ -176,10 +176,10 @@ extern "C" { #define humanoidrace(rc) (fval((rc), RCF_UNDEAD) || (rc)==new_race[RC_DRACOID] || playerrace(rc)) #define illusionaryrace(rc) (fval(rc, RCF_ILLUSIONARY)) - extern boolean allowed_dragon(const struct region *src, + extern bool allowed_dragon(const struct region *src, const struct region *target); - extern boolean r_insectstalled(const struct region *r); + extern bool r_insectstalled(const struct region *r); extern void add_raceprefix(const char *); extern char **race_prefixes; diff --git a/src/kernel/region.c b/src/kernel/region.c index 6996d959f..bfaaab804 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -431,7 +431,7 @@ static int hash_requests; static int hash_misses; #endif -boolean pnormalize(int *x, int *y, const plane * pl) +bool pnormalize(int *x, int *y, const plane * pl) { if (pl) { if (x) { @@ -806,7 +806,7 @@ short rroad(const region * r, direction_t d) return (r == b->from) ? b->data.sa[0] : b->data.sa[1]; } -boolean r_isforest(const region * r) +bool r_isforest(const region * r) { if (fval(r->terrain, FOREST_REGION)) { /* needs to be covered with at leas 48% trees */ @@ -1607,7 +1607,7 @@ int owner_change(const region * r) return -1; } -boolean is_mourning(const region * r, int in_turn) +bool is_mourning(const region * r, int in_turn) { int change = owner_change(r); return (change == in_turn - 1 diff --git a/src/kernel/region.h b/src/kernel/region.h index 4afbfa2f6..88764586a 100644 --- a/src/kernel/region.h +++ b/src/kernel/region.h @@ -157,7 +157,7 @@ extern "C" { typedef struct spec_direction { int x, y; int duration; - boolean active; + bool active; char *desc; char *keyword; } spec_direction; @@ -236,7 +236,7 @@ extern "C" { #define rherbs(r) ((r)->land?(r)->land->herbs:0) #define rsetherbs(r, value) if ((r)->land) ((r)->land->herbs=(short)(value)) - boolean r_isforest(const struct region *r); + bool r_isforest(const struct region *r); #define rterrain(r) (oldterrain((r)->terrain)) #define rsetterrain(r, t) ((r)->terrain = newterrain(t)) @@ -255,7 +255,7 @@ extern "C" { struct region *new_region(int x, int y, struct plane *pl, unsigned int uid); void remove_region(region ** rlist, region * r); void terraform_region(struct region *r, const struct terrain_type *terrain); - boolean pnormalize(int *x, int *y, const struct plane *pl); + bool pnormalize(int *x, int *y, const struct plane *pl); extern const int delta_x[MAXDIRECTIONS]; extern const int delta_y[MAXDIRECTIONS]; @@ -295,7 +295,7 @@ extern "C" { void region_setresource(struct region *r, const struct resource_type *rtype, int value); int owner_change(const region * r); - boolean is_mourning(const region * r, int in_turn); + bool is_mourning(const region * r, int in_turn); const struct item_type *r_luxury(struct region *r); void get_neighbours(const struct region *r, struct region **list); diff --git a/src/kernel/reports.c b/src/kernel/reports.c index e6ae19581..86995cb2d 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -69,9 +69,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -boolean nocr = false; -boolean nonr = false; -boolean noreports = false; +bool nocr = false; +bool nonr = false; +bool noreports = false; const char *visibility[] = { "none", @@ -141,7 +141,7 @@ const char *hp_status(const unit * u) void report_item(const unit * owner, const item * i, const faction * viewer, - const char **name, const char **basename, int *number, boolean singular) + const char **name, const char **basename, int *number, bool singular) { assert(!owner || owner->number); if (owner && owner->faction == viewer) { @@ -379,7 +379,7 @@ report_resources(const seen_region * sr, resource_report * result, int size, int horses = rhorses(r); int trees = rtrees(r, 2); int saplings = rtrees(r, 1); - boolean mallorn = fval(r, RF_MALLORN) != 0; + bool mallorn = fval(r, RF_MALLORN) != 0; if (money) { if (n >= size) @@ -457,16 +457,16 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, int getarnt = fval(u, UFL_ANON_FACTION); const char *pzTmp, *str; building *b; - boolean isbattle = (boolean) (mode == see_battle); + bool isbattle = (bool) (mode == see_battle); int telepath_see = 0; attrib *a_fshidden = NULL; item *itm; item *show; faction *fv = visible_faction(f, u); char *bufp = buf; - boolean itemcloak = false; + bool itemcloak = false; static const curse_type *itemcloak_ct = 0; - static boolean init = false; + static bool init = false; int bytes; item result[MAX_INVENTORY]; @@ -774,7 +774,7 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, } } if (!isbattle) { - boolean printed = 0; + bool printed = 0; order *ord;; for (ord = u->old_orders; ord; ord = ord->next) { if (is_repeated(ord)) { @@ -1095,7 +1095,7 @@ static void get_addresses(report_context * ctx) while (u != NULL) { if (u->faction != ctx->f) { faction *sf = visible_faction(ctx->f, u); - boolean ballied = sf && sf != ctx->f && sf != lastf + bool ballied = sf && sf != ctx->f && sf != lastf && !fval(u, UFL_ANON_FACTION) && cansee(ctx->f, r, u, stealthmod); if (ballied || ALLIED(ctx->f, sf)) { ql_set_insert(&flist, sf); @@ -1208,9 +1208,9 @@ static void get_seen_interval(report_context * ctx) link_seen(ctx->seen, ctx->first, ctx->last); } -boolean +bool add_seen(struct seen_region *seehash[], struct region *r, unsigned char mode, - boolean dis) + bool dis) { seen_region *find = find_seen(seehash, r); if (find == NULL) { @@ -1590,7 +1590,7 @@ static seen_region **prepare_report(faction * f) int write_reports(faction * f, time_t ltime) { int backup = 1, maxbackup = 128; - boolean gotit = false; + bool gotit = false; struct report_context ctx; const char *encoding = "UTF-8"; @@ -2321,7 +2321,7 @@ int report_action(region * r, unit * actor, message * msg, int flags) if (view) { for (u = r->units; u; u = u->next) { if (!fval(u->faction, FFL_SELECT)) { - boolean show = u->faction == actor->faction; + bool show = u->faction == actor->faction; fset(u->faction, FFL_SELECT); if (view == ACTION_CANSEE) { /* Bei Fernzaubern sieht nur die eigene Partei den Magier */ diff --git a/src/kernel/reports.h b/src/kernel/reports.h index e2669de6f..ffd4ee42c 100644 --- a/src/kernel/reports.h +++ b/src/kernel/reports.h @@ -33,12 +33,12 @@ extern "C" { extern const char *directions[]; extern const char *coasts[]; - extern boolean nonr; - extern boolean nocr; - extern boolean noreports; + extern bool nonr; + extern bool nocr; + extern bool noreports; /* kann_finden speedups */ - extern boolean kann_finden(struct faction *f1, struct faction *f2); + extern bool kann_finden(struct faction *f1, struct faction *f2); extern struct unit *can_find(struct faction *, struct faction *); /* funktionen zum schreiben eines reports */ @@ -77,13 +77,13 @@ extern "C" { struct seen_region *next; struct region *r; unsigned char mode; - boolean disbelieves; + bool disbelieves; } seen_region; extern struct seen_region *find_seen(struct seen_region *seehash[], const struct region *r); - extern boolean add_seen(struct seen_region *seehash[], struct region *r, - unsigned char mode, boolean dis); + extern bool add_seen(struct seen_region *seehash[], struct region *r, + unsigned char mode, bool dis); extern struct seen_region **seen_init(void); extern void seen_done(struct seen_region *seehash[]); extern void free_seen(void); @@ -137,7 +137,7 @@ extern "C" { const struct unit *owner, const struct faction *viewer); void report_item(const struct unit *owner, const struct item *i, const struct faction *viewer, const char **name, const char **basename, - int *number, boolean singular); + int *number, bool singular); void report_building(const struct building *b, const char **btype, const char **billusion); void report_race(const struct unit *u, const char **rcname, diff --git a/src/kernel/resources.c b/src/kernel/resources.c index 0cd731869..4a3607d7b 100644 --- a/src/kernel/resources.c +++ b/src/kernel/resources.c @@ -118,7 +118,7 @@ static void terraform_default(struct rawmaterial *res, const region * r) } #ifdef RANDOM_CHANGE -static void resource_random_change(int *pvalue, boolean used) +static void resource_random_change(int *pvalue, bool used) { int split = 5; int rnd = rng_int() % 100; diff --git a/src/kernel/save.c b/src/kernel/save.c index cf7724a96..c8c39b50f 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -132,7 +132,7 @@ FILE *cfopen(const char *filename, const char *mode) int freadstr(FILE * F, int encoding, char *start, size_t size) { char *str = start; - boolean quote = false; + bool quote = false; for (;;) { int c = fgetc(F); @@ -298,7 +298,7 @@ static unit *unitorders(FILE * F, int enc, struct faction *f) stok = parse_token(&stok); if (stok) { - boolean quit = false; + bool quit = false; param_t param = findparam(stok, u->faction->locale); switch (param) { case P_UNIT: diff --git a/src/kernel/skill.c b/src/kernel/skill.c index c25954182..2cdc3d25b 100644 --- a/src/kernel/skill.c +++ b/src/kernel/skill.c @@ -73,7 +73,7 @@ const char *skillnames[MAXSKILLS] = { "unarmed" }; -boolean skill_enabled[MAXSKILLS]; +bool skill_enabled[MAXSKILLS]; const char *skillname(skill_t sk, const struct locale *lang) { @@ -83,7 +83,7 @@ const char *skillname(skill_t sk, const struct locale *lang) return NULL; } -void enable_skill(const char *skname, boolean value) +void enable_skill(const char *skname, bool value) { skill_t sk; for (sk = 0; sk != MAXSKILLS; ++sk) { @@ -260,7 +260,7 @@ int level(int days) { int i; static int ldays[64]; - static boolean init = false; + static bool init = false; if (!init) { init = true; for (i = 0; i != 64; ++i) diff --git a/src/kernel/skill.h b/src/kernel/skill.h index dde1c0721..4db618f5a 100644 --- a/src/kernel/skill.h +++ b/src/kernel/skill.h @@ -48,7 +48,7 @@ extern "C" { extern const char *skillname(skill_t, const struct locale *); extern skill_t sk_find(const char *name); - extern void enable_skill(const char *name, boolean value); + extern void enable_skill(const char *name, bool value); extern int level_days(int level); extern int level(int days); @@ -60,7 +60,7 @@ extern "C" { extern void sk_set(skill * sv, int level); extern const char *skillnames[]; - extern boolean skill_enabled[]; + extern bool skill_enabled[]; #ifdef __cplusplus } diff --git a/src/kernel/sqlite.c b/src/kernel/sqlite.c index 6e6cc5014..b7c9951a3 100644 --- a/src/kernel/sqlite.c +++ b/src/kernel/sqlite.c @@ -73,9 +73,9 @@ typedef struct db_faction { static int db_update_email(sqlite3 * db, const faction * f, const db_faction * dbstate, - boolean force, /* [OUT] */ sqlite3_uint64 * id_email) + bool force, /* [OUT] */ sqlite3_uint64 * id_email) { - boolean update = force; + bool update = force; int res = SQLITE_OK; char email_lc[MAX_EMAIL_LENGTH]; @@ -129,7 +129,7 @@ db_update_email(sqlite3 * db, const faction * f, const db_faction * dbstate, return SQLITE_OK; } -int db_update_factions(sqlite3 * db, boolean force) +int db_update_factions(sqlite3 * db, bool force) { int game_id = 6; const char sql_select[] = @@ -172,7 +172,7 @@ int db_update_factions(sqlite3 * db, boolean force) int i; char passwd_md5[MD5_LENGTH_0]; sqlite3_uint64 id_email; - boolean update = force; + bool update = force; db_faction dbstate; const char *no_b36; @@ -241,7 +241,7 @@ int db_update_factions(sqlite3 * db, boolean force) return SQLITE_OK; } -int db_update_scores(sqlite3 * db, boolean force) +int db_update_scores(sqlite3 * db, bool force) { const char *sql_ins = "INSERT OR FAIL INTO score (value,faction_id,turn) VALUES (?,?,?)"; diff --git a/src/kernel/teleport.c b/src/kernel/teleport.c index 51428f7b8..db5cc646b 100644 --- a/src/kernel/teleport.c +++ b/src/kernel/teleport.c @@ -61,7 +61,7 @@ static region *tpregion(const region * r) return rt; } -region_list *astralregions(const region * r, boolean(*valid) (const region *)) +region_list *astralregions(const region * r, bool(*valid) (const region *)) { region_list *rlist = NULL; int x, y; @@ -116,7 +116,7 @@ region *r_astral_to_standard(const region * r) } region_list *all_in_range(const region * r, int n, - boolean(*valid) (const region *)) + bool(*valid) (const region *)) { int x, y; region_list *rlist = NULL; @@ -171,7 +171,7 @@ plane *get_normalplane(void) return NULL; } -boolean is_astral(const region * r) +bool is_astral(const region * r) { plane *pl = get_astralplane(); return (pl && rplane(r) == pl); @@ -227,7 +227,7 @@ void create_teleport_plane(void) } } -boolean inhabitable(const region * r) +bool inhabitable(const region * r) { return fval(r->terrain, LAND_REGION); } diff --git a/src/kernel/teleport.h b/src/kernel/teleport.h index 2f3a5bcc0..75be6b5d1 100644 --- a/src/kernel/teleport.h +++ b/src/kernel/teleport.h @@ -25,11 +25,11 @@ extern "C" { struct region *r_standard_to_astral(const struct region *r); struct region *r_astral_to_standard(const struct region *); extern struct region_list *astralregions(const struct region *rastral, - boolean(*valid) (const struct region *)); + bool(*valid) (const struct region *)); extern struct region_list *all_in_range(const struct region *r, int n, - boolean(*valid) (const struct region *)); - extern boolean inhabitable(const struct region *r); - extern boolean is_astral(const struct region *r); + bool(*valid) (const struct region *)); + extern bool inhabitable(const struct region *r); + extern bool is_astral(const struct region *r); extern struct plane *get_astralplane(void); extern struct plane *get_normalplane(void); diff --git a/src/kernel/unit.c b/src/kernel/unit.c index c24902076..5aee29ab7 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -612,7 +612,7 @@ void usetcontact(unit * u, const unit * u2) a_add(&u->attribs, a_new(&at_contact))->data.v = (void *)u2; } -boolean ucontact(const unit * u, const unit * u2) +bool ucontact(const unit * u, const unit * u2) /* Prüft, ob u den Kontaktiere-Befehl zu u2 gesetzt hat. */ { attrib *ru; @@ -820,7 +820,7 @@ void leave_building(unit * u) } } -boolean can_leave(unit * u) +bool can_leave(unit * u) { static int rule_leave = -1; @@ -836,7 +836,7 @@ boolean can_leave(unit * u) return true; } -boolean leave(unit * u, boolean force) +bool leave(unit * u, bool force) { if (!force) { if (!can_leave(u)) { @@ -856,7 +856,7 @@ const struct race *urace(const struct unit *u) return u->race; } -boolean can_survive(const unit * u, const region * r) +bool can_survive(const unit * u, const region * r) { if ((fval(r->terrain, WALK_INTO) && (u->race->flags & RCF_WALK)) || (fval(r->terrain, SWIM_INTO) && (u->race->flags & RCF_SWIM)) @@ -891,7 +891,7 @@ void move_unit(unit * u, region * r, unit ** ulist) if (u->ship || u->building) { /* can_leave must be checked in travel_i */ #ifndef NDEBUG - boolean result = leave(u, false); + bool result = leave(u, false); assert(result); #else leave(u, false); @@ -1117,7 +1117,7 @@ void set_number(unit * u, int count) u->number = (unsigned short)count; } -boolean learn_skill(unit * u, skill_t sk, double chance) +bool learn_skill(unit * u, skill_t sk, double chance) { skill *sv = u->skills; if (chance < 1.0 && rng_int() % 10000 >= chance * 10000) @@ -1183,7 +1183,7 @@ skill *get_skill(const unit * u, skill_t sk) return NULL; } -boolean has_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) { @@ -1224,7 +1224,7 @@ static int item_modification(const unit * u, skill_t sk, int val) static int att_modification(const unit * u, skill_t sk) { double result = 0; - static boolean init = false; + static bool init = false; static const curse_type *skillmod_ct, *gbdream_ct, *worse_ct; curse *c; @@ -1283,7 +1283,7 @@ static int att_modification(const unit * u, skill_t sk) int get_modifier(const unit * u, skill_t sk, int level, const region * r, - boolean noitem) + bool noitem) { int bskill = level; int skill = bskill; diff --git a/src/kernel/unit.h b/src/kernel/unit.h index 7c9e3d8d3..292e6a759 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -145,7 +145,7 @@ extern "C" { const struct potion_type *ugetpotionuse(const struct unit *u); /* benutzt u einein trank? */ void usetpotionuse(struct unit *u, const struct potion_type *p); /* u benutzt trank p (es darf halt nur einer pro runde) */ - boolean ucontact(const struct unit *u, const struct unit *u2); + bool ucontact(const struct unit *u, const struct unit *u2); void usetcontact(struct unit *u, const struct unit *c); struct unit *findnewunit(const struct region *r, const struct faction *f, @@ -155,7 +155,7 @@ extern "C" { extern struct skill *add_skill(struct unit *u, skill_t id); extern void remove_skill(struct unit *u, skill_t sk); extern struct skill *get_skill(const struct unit *u, skill_t id); - extern boolean has_skill(const unit * u, skill_t sk); + extern bool has_skill(const unit * u, skill_t sk); extern void set_level(struct unit *u, skill_t id, int level); extern int get_level(const struct unit *u, skill_t id); @@ -167,7 +167,7 @@ extern "C" { const struct region *r); extern int get_modifier(const struct unit *u, skill_t sk, int lvl, - const struct region *r, boolean noitem); + const struct region *r, bool noitem); extern int remove_unit(struct unit **ulist, struct unit *u); #define GIFT_SELF 1<<0 @@ -181,8 +181,8 @@ extern "C" { extern void write_unit_reference(const struct unit *u, struct storage *store); extern variant read_unit_reference(struct storage *store); - extern boolean leave(struct unit *u, boolean force); - extern boolean can_leave(struct unit *u); + extern bool leave(struct unit *u, bool force); + extern bool can_leave(struct unit *u); extern void u_set_building(struct unit * u, struct building * b); extern void u_set_ship(struct unit * u, struct ship * sh); @@ -191,7 +191,7 @@ extern "C" { extern void set_leftship(struct unit *u, struct ship *sh); extern struct ship *leftship(const struct unit *); - extern boolean can_survive(const struct unit *u, const struct region *r); + extern bool can_survive(const struct unit *u, const struct region *r); extern void move_unit(struct unit *u, struct region *target, struct unit **ulist); @@ -203,7 +203,7 @@ extern "C" { extern void u_setfaction(struct unit *u, struct faction *f); extern void set_number(struct unit *u, int count); - extern boolean learn_skill(struct unit *u, skill_t sk, double chance); + extern bool learn_skill(struct unit *u, skill_t sk, double chance); extern int invisible(const struct unit *target, const struct unit *viewer); extern void free_unit(struct unit *u); diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index c87f7449a..70da69915 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -51,7 +51,7 @@ without prior permission by the authors of Eressea. #include #include -static boolean gamecode_enabled = false; +static bool gamecode_enabled = false; static building_type *bt_get_or_create(const char *name) { @@ -824,7 +824,7 @@ static weapon_type *xml_readweapon(xmlXPathContextPtr xpath, item_type * itype) assert(propValue != NULL); if (strcmp((const char *)propValue, "attack") == 0) { wtype->attack = - (boolean(*)(const struct troop *, const struct weapon_type *, + (bool(*)(const struct troop *, const struct weapon_type *, int *))fun; } else { log_error("unknown function type '%s' for item '%s'\n", (const char *)propValue, itype->rtype->_name[0]); @@ -938,7 +938,7 @@ static item_type *xml_readitem(xmlXPathContextPtr xpath, resource_type * rtype) struct order *))fun; } else if (strcmp((const char *)propValue, "canuse") == 0) { itype->canuse = - (boolean(*)(const struct unit *, const struct item_type *))fun; + (bool(*)(const struct unit *, const struct item_type *))fun; } else if (strcmp((const char *)propValue, "useonother") == 0) { itype->useonother = (int (*)(struct unit *, int, const struct item_type *, int, @@ -1893,7 +1893,7 @@ static int parse_races(xmlDocPtr doc) rc->age = (void (*)(struct unit *))fun; } else if (strcmp((const char *)propValue, "move") == 0) { rc->move_allowed = - (boolean(*)(const struct region *, const struct region *))fun; + (bool(*)(const struct region *, const struct region *))fun; } else if (strcmp((const char *)propValue, "itemdrop") == 0) { rc->itemdrop = (struct item * (*)(const struct race *, int))fun; } else if (strcmp((const char *)propValue, "initfamiliar") == 0) { @@ -2206,7 +2206,7 @@ static int parse_messages(xmlDocPtr doc) static void xml_readstrings(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, - boolean names) + bool names) { int i; @@ -2274,7 +2274,7 @@ static int parse_strings(xmlDocPtr doc) static void xml_readprefixes(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, - boolean names) + bool names) { int i; @@ -2344,7 +2344,7 @@ static int parse_main(xmlDocPtr doc) for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; xmlChar *propName = xmlGetProp(node, BAD_CAST "name"); - boolean disable = xml_bvalue(node, "disable", false); + bool disable = xml_bvalue(node, "disable", false); if (disable) { int k; @@ -2369,7 +2369,7 @@ static int parse_main(xmlDocPtr doc) for (i = 0; i != nodes->nodeNr; ++i) { xmlNodePtr node = nodes->nodeTab[i]; xmlChar *propName = xmlGetProp(node, BAD_CAST "name"); - boolean enable = xml_bvalue(node, "enable", true); + bool enable = xml_bvalue(node, "enable", true); enable_skill((const char *)propName, enable); xmlFree(propName); } diff --git a/src/modules/autoseed.c b/src/modules/autoseed.c index 9a0b5d233..4a004a0ab 100644 --- a/src/modules/autoseed.c +++ b/src/modules/autoseed.c @@ -104,7 +104,7 @@ static int count_demand(const region * r) static int recurse_regions(region * r, region_list ** rlist, - boolean(*fun) (const region * r)) + bool(*fun) (const region * r)) { if (!fun(r)) return 0; @@ -125,7 +125,7 @@ recurse_regions(region * r, region_list ** rlist, } } -static boolean f_nolux(const region * r) +static bool f_nolux(const region * r) { if (r->land && count_demand(r) != get_maxluxuries()) return true; @@ -337,7 +337,7 @@ static const terrain_type *preferred_terrain(const struct race *rc) #define MINFACTIONS 1 #define VOLCANO_CHANCE 100 -static boolean virgin_region(const region * r) +static bool virgin_region(const region * r) { direction_t d; if (r == NULL) diff --git a/src/modules/autoseed.h b/src/modules/autoseed.h index 254608803..923534020 100644 --- a/src/modules/autoseed.h +++ b/src/modules/autoseed.h @@ -26,7 +26,7 @@ extern "C" { const struct race *race; int bonus; int subscription; - boolean oldregions; + bool oldregions; struct alliance *allies; } newfaction; diff --git a/src/modules/gmcmd.c b/src/modules/gmcmd.c index 5f6caeb0c..78c26e235 100644 --- a/src/modules/gmcmd.c +++ b/src/modules/gmcmd.c @@ -157,7 +157,7 @@ static void gm_create(const void *tnext, struct unit *u, struct order *ord) } } -static boolean has_permission(const attrib * permissions, unsigned int key) +static bool has_permission(const attrib * permissions, unsigned int key) { return (find_key((attrib *) permissions->data.v, key) || find_key((attrib *) permissions->data.v, atoi36("master"))); @@ -600,7 +600,7 @@ faction *gm_addquest(const char *email, const char *name, int radius, plane *pl; watcher *w = calloc(sizeof(watcher), 1); region *center; - boolean invalid = false; + bool invalid = false; int minx, miny, maxx, maxy, cx, cy; int x; faction *f; @@ -716,7 +716,7 @@ plane *gm_addplane(int radius, unsigned int flags, const char *name) { region *center; plane *pl; - boolean invalid = false; + bool invalid = false; int minx, miny, maxx, maxy, cx, cy; int x; diff --git a/src/modules/wormhole.c b/src/modules/wormhole.c index d018c358f..4a4730df3 100644 --- a/src/modules/wormhole.c +++ b/src/modules/wormhole.c @@ -37,7 +37,7 @@ #include #include -static boolean good_region(const region * r) +static bool good_region(const region * r) { return (!fval(r, RF_CHAOTIC) && r->age > 30 && rplane(r) == NULL && r->units != NULL && r->land != NULL); diff --git a/src/platform.h b/src/platform.h index 679737ec2..7e1fd72b4 100644 --- a/src/platform.h +++ b/src/platform.h @@ -247,7 +247,6 @@ extern char *strdup(const char *s); #endif /* ghs || __GNUC__ || ..... */ #include "util/bool.h" -typedef bool boolean; #ifndef INLINE_FUNCTION # define INLINE_FUNCTION diff --git a/src/util/attrib.c b/src/util/attrib.c index f76b48427..ef7674534 100644 --- a/src/util/attrib.c +++ b/src/util/attrib.c @@ -85,7 +85,7 @@ static attrib_type *at_find(unsigned int hk) } attrib *a_select(attrib * a, const void *data, - boolean(*compare) (const attrib *, const void *)) + bool(*compare) (const attrib *, const void *)) { while (a && !compare(a, data)) a = a->next; diff --git a/src/util/attrib.h b/src/util/attrib.h index 47c0e29fd..6096a4cbe 100644 --- a/src/util/attrib.h +++ b/src/util/attrib.h @@ -64,7 +64,7 @@ extern "C" { extern void at_deprecate(const char * name, int (*reader)(attrib *, void *, struct storage *)); extern attrib *a_select(attrib * a, const void *data, - boolean(*compare) (const attrib *, const void *)); + bool(*compare) (const attrib *, const void *)); extern attrib *a_find(attrib * a, const attrib_type * at); extern const attrib *a_findc(const attrib * a, const attrib_type * at); extern attrib *a_add(attrib ** pa, attrib * at); diff --git a/src/util/filereader.c b/src/util/filereader.c index 1b6f79488..12ef3add4 100644 --- a/src/util/filereader.c +++ b/src/util/filereader.c @@ -42,9 +42,9 @@ INLINE_FUNCTION int eatwhite(const char *ptr, size_t * total_size) static const char *getbuf_latin1(FILE * F) { - boolean cont = false; + bool cont = false; char quote = 0; - boolean comment = false; + bool comment = false; char *cp = fbuf; char *tail = lbuf + MAXLINE - 2; @@ -57,8 +57,8 @@ static const char *getbuf_latin1(FILE * F) while (*bp && isxspace(*(unsigned char *)bp)) ++bp; /* eatwhite */ - comment = (boolean) (comment && cont); - quote = (boolean) (quote && cont); + comment = (bool) (comment && cont); + quote = (bool) (quote && cont); if (tail[1] == 0) { /* we read he maximum number of bytes! */ @@ -178,9 +178,9 @@ static const char *getbuf_latin1(FILE * F) static const char *getbuf_utf8(FILE * F) { - boolean cont = false; + bool cont = false; char quote = 0; - boolean comment = false; + bool comment = false; char *cp = fbuf; char *tail = lbuf + MAXLINE - 2; @@ -195,8 +195,8 @@ static const char *getbuf_utf8(FILE * F) eatwhite(bp, &white); /* decoding errors will get caught later on, don't have to check */ bp += white; - comment = (boolean) (comment && cont); - quote = (boolean) (quote && cont); + comment = (bool) (comment && cont); + quote = (bool) (quote && cont); if (tail[1] == 0) { /* we read the maximum number of bytes! */ diff --git a/src/util/listbox.c b/src/util/listbox.c index 0b7403860..ab3dd9eb9 100644 --- a/src/util/listbox.c +++ b/src/util/listbox.c @@ -75,7 +75,7 @@ list_selection *do_selection(list_selection * sel, const char *title, void (*perform) (list_selection *, void *), void *data) { WINDOW *wn; - boolean update = true; + bool update = true; list_selection *s; list_selection *top = sel; list_selection *current = top; diff --git a/src/util/parser.c b/src/util/parser.c index 46d6ba8a8..3634ba541 100644 --- a/src/util/parser.c +++ b/src/util/parser.c @@ -76,7 +76,7 @@ void parser_popstate(void) state = new_state; } -boolean parser_end(void) +bool parser_end(void) { eatwhitespace_c(&state->current_token); return *state->current_token == 0; @@ -126,7 +126,7 @@ const char *parse_token(const char **str) static char lbuf[MAXTOKENSIZE]; /* STATIC_RESULT: used for return, not across calls */ char *cursor = lbuf; char quotechar = 0; - boolean escape = false; + bool escape = false; const char *ctoken = *str; assert(ctoken); @@ -135,7 +135,7 @@ const char *parse_token(const char **str) while (*ctoken && cursor - lbuf < MAXTOKENSIZE - 1) { ucs4_t ucs; size_t len; - boolean copy = false; + bool copy = false; unsigned char utf8_character = *(unsigned char *)ctoken; if (~utf8_character & 0x80) { diff --git a/src/util/parser.h b/src/util/parser.h index dc1ab3717..521987174 100644 --- a/src/util/parser.h +++ b/src/util/parser.h @@ -19,7 +19,7 @@ extern "C" { extern const char *parse_token(const char **str); extern void parser_pushstate(void); extern void parser_popstate(void); - extern boolean parser_end(void); + extern bool parser_end(void); extern const char *getstrtoken(void); #ifdef __cplusplus diff --git a/src/util/rand.c b/src/util/rand.c index ac02786b7..b26bf0c12 100644 --- a/src/util/rand.c +++ b/src/util/rand.c @@ -61,7 +61,7 @@ int ntimespprob(int n, double p, double mod) return count; } -boolean chance(double x) +bool chance(double x) { if (x >= 1.0) return true; diff --git a/src/util/rand.h b/src/util/rand.h index 2c9d6e96b..9223923b9 100644 --- a/src/util/rand.h +++ b/src/util/rand.h @@ -29,7 +29,7 @@ extern "C" { /* in rand.c: */ extern double normalvariate(double mu, double sigma); extern int ntimespprob(int n, double p, double mod); - extern boolean chance(double x); + extern bool chance(double x); #ifdef __cplusplus } diff --git a/src/util/translation.c b/src/util/translation.c index 411b8aee0..e3493f434 100644 --- a/src/util/translation.c +++ b/src/util/translation.c @@ -186,7 +186,7 @@ static const char *parse_symbol(opstack ** stack, const char *in, * result goes on the stack */ { - boolean braces = false; + bool braces = false; char symbol[32]; char *cp = symbol; /* current position */ @@ -239,8 +239,8 @@ static const char *parse_string(opstack ** stack, const char *in, const char *ic = in; char *oc = buffer; /* mode flags */ - boolean f_escape = false; - boolean bDone = false; + bool f_escape = false; + bool bDone = false; variant var; while (*ic && !bDone) { @@ -310,7 +310,7 @@ static const char *parse_int(opstack ** stack, const char *in) { int k = 0; int vz = 1; - boolean ok = false; + bool ok = false; variant var; do { switch (*in) { diff --git a/src/util/xml.c b/src/util/xml.c index 297d8c89b..31a1bb542 100644 --- a/src/util/xml.c +++ b/src/util/xml.c @@ -43,9 +43,9 @@ int xml_ivalue(xmlNodePtr node, const char *name, int dflt) return i; } -boolean xml_bvalue(xmlNodePtr node, const char *name, boolean dflt) +bool xml_bvalue(xmlNodePtr node, const char *name, bool dflt) { - boolean result = dflt; + bool result = dflt; xmlChar *propValue = xmlGetProp(node, BAD_CAST name); if (propValue != NULL) { if (strcmp((const char *)propValue, "no") == 0) @@ -57,10 +57,10 @@ boolean xml_bvalue(xmlNodePtr node, const char *name, boolean dflt) else if (strcmp((const char *)propValue, "true") == 0) result = true; else if (strcmp((const char *)propValue, "1") == 0) { - log_warning("boolean value is '1': %s::%s\n", node->name, name); + log_warning("bool value is '1': %s::%s\n", node->name, name); result = true; } else if (strcmp((const char *)propValue, "0") == 0) { - log_warning("boolean value is '0': %s::%s\n", node->name, name); + log_warning("bool value is '0': %s::%s\n", node->name, name); result = false; } xmlFree(propValue); diff --git a/src/util/xml.h b/src/util/xml.h index f14cbedeb..42b9178bb 100644 --- a/src/util/xml.h +++ b/src/util/xml.h @@ -25,7 +25,7 @@ extern "C" { extern int read_xml(const char *filename, const char *catalog); extern double xml_fvalue(xmlNodePtr node, const char *name, double dflt); extern int xml_ivalue(xmlNodePtr node, const char *name, int dflt); - extern boolean xml_bvalue(xmlNodePtr node, const char *name, boolean dflt); + extern bool xml_bvalue(xmlNodePtr node, const char *name, bool dflt); const xmlChar *xml_i(double number); From f893ea03b630cebf3e2f272ce5bad91a922ec24a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 23 Jun 2012 22:36:17 -0700 Subject: [PATCH 359/400] E4 combat prototype (WIP) --- src/gamecode/spy.c | 1 + src/kernel/battle.c | 50 +++++++++++++++++++++++++--------------- src/kernel/battle.h | 3 +++ src/kernel/battle_test.c | 3 ++- src/kernel/config.c | 11 ++++----- src/kernel/config.h | 3 ++- src/kernel/move.c | 7 ------ src/kernel/move.h | 1 - src/kernel/order.c | 6 +++++ src/kernel/order.h | 1 + src/kernel/region.c | 8 +++---- 11 files changed, 56 insertions(+), 38 deletions(-) diff --git a/src/gamecode/spy.c b/src/gamecode/spy.c index 43eb475cb..476aed8af 100644 --- a/src/gamecode/spy.c +++ b/src/gamecode/spy.c @@ -28,6 +28,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include #include diff --git a/src/kernel/battle.c b/src/kernel/battle.c index 7a4f1cd12..662c797c7 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -206,7 +206,7 @@ static void message_faction(battle * b, faction * f, struct message *m) region *r = b->region; if (f->battles == NULL || f->battles->r != r) { - struct bmsg *bm = calloc(1, sizeof(struct bmsg)); + struct bmsg *bm = (struct bmsg *)calloc(1, sizeof(struct bmsg)); bm->next = f->battles; f->battles = bm; bm->r = r; @@ -3203,7 +3203,7 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) /* Zu diesem Zeitpunkt ist attacked noch 0, da die Einheit für noch * keinen Kampf ausgewählt wurde (sonst würde ein fighter existieren) */ } - fig = calloc(1, sizeof(struct fighter)); + fig = (struct fighter*)calloc(1, sizeof(struct fighter)); fig->next = s1->fighters; s1->fighters = fig; @@ -3228,7 +3228,7 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) fig->catmsg = -1; /* Freigeben nicht vergessen! */ - fig->person = calloc(fig->alive, sizeof(struct person)); + fig->person = (struct person*)calloc(fig->alive, sizeof(struct person)); h = u->hp / u->number; assert(h); @@ -3542,7 +3542,7 @@ battle *make_battle(region * r) else { const unsigned char utf8_bom[4] = { 0xef, 0xbb, 0xbf, 0 }; fwrite(utf8_bom, 1, 3, bdebug); - fprintf(bdebug, "In %s findet ein Kampf stattactics:\n", rname(r, + fprintf(bdebug, "In %s findet ein Kampf statt:\n", rname(r, default_locale)); } obs_count++; @@ -3600,7 +3600,6 @@ static void free_fighter(fighter * fig) static void free_battle(battle * b) { - side *s; int max_fac_no = 0; if (bdebug) { @@ -3615,19 +3614,11 @@ static void free_battle(battle * b) free(bf); } - for (s = b->sides; s != b->sides + b->nsides; ++s) { - fighter *fnext = s->fighters; - while (fnext) { - fighter *fig = fnext; - fnext = fig->next; - free_fighter(fig); - free(fig); - } - free_side(s); - } ql_free(b->leaders); ql_foreach(b->meffects, free); ql_free(b->meffects); + + battle_free(b); } static int *get_alive(side * s) @@ -3876,7 +3867,7 @@ static void flee(const troop dt) kill_troop(dt); } -static bool init_battle(region * r, battle ** bp) +static bool start_battle(region * r, battle ** bp) { battle *b = NULL; unit *u; @@ -4091,7 +4082,7 @@ static void battle_stats(FILE * F, battle * b) } stat = *slist; if (stat == NULL || stat->wtype != wtype || stat->level != level) { - stat = calloc(1, sizeof(stat_info)); + stat = (stat_info*)calloc(1, sizeof(stat_info)); stat->wtype = wtype; stat->level = level; stat->next = *slist; @@ -4251,7 +4242,7 @@ void do_battle(region * r) msg_separator = msg_message("battle::section", ""); } - fighting = init_battle(r, &b); + fighting = start_battle(r, &b); if (b == NULL) return; @@ -4318,3 +4309,26 @@ void do_battle(region * r) free(b); } } + +void battle_init(battle * b) { + assert(b); + memset(b, 0, sizeof(battle)); +} + +void battle_free(battle * b) { + side *s; + + assert(b); + + for (s = b->sides; s != b->sides + b->nsides; ++s) { + fighter *fnext = s->fighters; + while (fnext) { + fighter *fig = fnext; + fnext = fig->next; + free_fighter(fig); + free(fig); + } + free_side(s); + } +} + diff --git a/src/kernel/battle.h b/src/kernel/battle.h index c962e32bb..59ced0967 100644 --- a/src/kernel/battle.h +++ b/src/kernel/battle.h @@ -114,6 +114,9 @@ extern "C" { } fast; } battle; + void battle_init(battle * b); + void battle_free(battle * b); + typedef struct weapon { int count, used; const struct weapon_type *type; diff --git a/src/kernel/battle_test.c b/src/kernel/battle_test.c index c8a558af1..8bdc50822 100644 --- a/src/kernel/battle_test.c +++ b/src/kernel/battle_test.c @@ -8,8 +8,9 @@ #include "region.h" #include "skill.h" #include "unit.h" -#include "tests.h" + #include +#include "tests.h" static void test_make_fighter(CuTest * tc) { diff --git a/src/kernel/config.c b/src/kernel/config.c index 08970f71b..92739609c 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -1249,12 +1249,6 @@ int count_maxmigrants(const faction * f) return migrants; } -void init_tokens(const struct order *ord) -{ - char *cmd = getcommand(ord); - init_tokens_str(cmd, cmd); -} - void parse(keyword_t kword, int (*dofun) (unit *, struct order *), bool thisorder) { @@ -1953,6 +1947,11 @@ direction_t finddirection(const char *s, const struct locale *lang) return NODIRECTION; } +direction_t getdirection(const struct locale * lang) +{ + return finddirection(getstrtoken(), lang); +} + static void init_translations(const struct locale *lang, int ut, const char * (*string_cb)(int i), int maxstrings) { char buffer[256]; diff --git a/src/kernel/config.h b/src/kernel/config.h index e85325bc1..559bcae2d 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -165,9 +165,10 @@ extern "C" { unsigned int getuint(void); int getint(void); + direction_t getdirection(const struct locale *); + extern const char *igetstrtoken(const char *s); - extern void init_tokens(const struct order *ord); /* initialize token parsing */ extern skill_t findskill(const char *s, const struct locale *lang); extern keyword_t findkeyword(const char *s, const struct locale *lang); diff --git a/src/kernel/move.c b/src/kernel/move.c index 7eed52d5f..21894c144 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -176,13 +176,6 @@ attrib_type at_speedup = { /* ------------------------------------------------------------- */ -direction_t getdirection(const struct locale * lang) -{ - return finddirection(getstrtoken(), lang); -} - -/* ------------------------------------------------------------- */ - static attrib_type at_driveweight = { "driveweight", NULL, NULL, NULL, NULL, NULL }; diff --git a/src/kernel/move.h b/src/kernel/move.h index 621510d04..80744ce9f 100644 --- a/src/kernel/move.h +++ b/src/kernel/move.h @@ -47,7 +47,6 @@ extern "C" { ** pferde, macht nur noch 100, aber samt eigenem gewicht (40) macht also 140. */ int personcapacity(const struct unit *u); - direction_t getdirection(const struct locale *); void movement(void); void run_to(struct unit *u, struct region *to); struct unit *is_guarded(struct region *r, struct unit *u, unsigned int mask); diff --git a/src/kernel/order.c b/src/kernel/order.c index 9004fd4db..9005330e4 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -606,3 +606,9 @@ void push_order(order ** ordp, order * ord) ordp = &(*ordp)->next; *ordp = ord; } + +void init_tokens(const struct order *ord) +{ + char *cmd = getcommand(ord); + init_tokens_str(cmd, cmd); +} diff --git a/src/kernel/order.h b/src/kernel/order.h index 9e0ebeef5..c86b98792 100644 --- a/src/kernel/order.h +++ b/src/kernel/order.h @@ -57,6 +57,7 @@ extern "C" { extern int is_long(const order * ord); extern char *write_order(const order * ord, char *buffer, size_t size); + extern void init_tokens(const struct order *ord); /* initialize token parsing */ #ifdef __cplusplus } diff --git a/src/kernel/region.c b/src/kernel/region.c index bfaaab804..b78bb6d1c 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -628,13 +628,13 @@ int distance(const region * r1, const region * r2) static direction_t koor_reldirection(int ax, int ay, int bx, int by, const struct plane *pl) { - direction_t dir; + int dir; for (dir = 0; dir != MAXDIRECTIONS; ++dir) { int x = ax + delta_x[dir]; int y = ay + delta_y[dir]; pnormalize(&x, &y, pl); if (bx == x && by == y) - return dir; + return (direction_t)dir; } return NODIRECTION; } @@ -1593,9 +1593,9 @@ void region_set_morale(region * r, int morale, int turn) void get_neighbours(const region * r, region ** list) { - direction_t dir; + int dir; for (dir = 0; dir != MAXDIRECTIONS; ++dir) { - list[dir] = rconnect(r, dir); + list[dir] = rconnect(r, (direction_t)dir); } } From a8324f16fd946e11d3417b298a82bbcb04c082df Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 24 Jun 2012 08:04:12 +0200 Subject: [PATCH 360/400] make some prototypes use bool, not int --- src/gamecode/laws.c | 2 +- src/gamecode/laws.h | 2 +- src/kernel/config.c | 4 ++-- src/kernel/config.h | 2 +- src/kernel/move.c | 2 +- src/kernel/order.c | 12 ++++++------ src/kernel/order.h | 8 ++++---- src/kernel/region.c | 6 +++--- src/kernel/region.h | 2 +- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 3b332fec7..3e7ca3595 100755 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -1327,7 +1327,7 @@ static void do_contact(region * r) } } -void do_enter(struct region *r, int is_final_attempt) +void do_enter(struct region *r, bool is_final_attempt) { unit **uptr; diff --git a/src/gamecode/laws.h b/src/gamecode/laws.h index 3cc5882e5..7f96db564 100755 --- a/src/gamecode/laws.h +++ b/src/gamecode/laws.h @@ -56,7 +56,7 @@ extern "C" { extern void restack_units(void); extern void update_long_order(struct unit *u); extern void sinkships(struct region * r); - extern void do_enter(struct region *r, int is_final_attempt); + extern void do_enter(struct region *r, bool is_final_attempt); extern int password_cmd(struct unit *u, struct order *ord); extern int banner_cmd(struct unit *u, struct order *ord); diff --git a/src/kernel/config.c b/src/kernel/config.c index 08970f71b..a6db38377 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -1403,13 +1403,13 @@ param_t findparam_ex(const char *s, const struct locale * lang) return (result == P_BUILDING) ? P_GEBAEUDE : result; } -int isparam(const char *s, const struct locale * lang, param_t param) +bool isparam(const char *s, const struct locale * lang, param_t param) { if (s[0]>'@') { param_t p = (param==P_GEBAEUDE) ? findparam_ex(s, lang) : findparam(s, lang); return p==param; } - return 0; + return false; } param_t getparam(const struct locale * lang) diff --git a/src/kernel/config.h b/src/kernel/config.h index e85325bc1..75be214e0 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -174,7 +174,7 @@ extern "C" { param_t findparam(const char *s, const struct locale *lang); param_t findparam_ex(const char *s, const struct locale * lang); - int isparam(const char *s, const struct locale * lang, param_t param); + bool isparam(const char *s, const struct locale * lang, param_t param); param_t getparam(const struct locale *lang); extern int getid(void); diff --git a/src/kernel/move.c b/src/kernel/move.c index 7eed52d5f..80bdfbd5a 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -633,7 +633,7 @@ static bool is_freezing(const unit * u) #define SA_NO_INSECT -1 #define SA_NO_COAST -2 -static int is_ship_allowed(struct ship *sh, const region * r) +static bool is_ship_allowed(struct ship *sh, const region * r) { int c = 0; static const building_type *bt_harbour = NULL; diff --git a/src/kernel/order.c b/src/kernel/order.c index 9004fd4db..d7105e8eb 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -373,7 +373,7 @@ order *parse_order(const char *s, const struct locale * lang) * \return true if the order is long * \sa is_exclusive(), is_repeated(), is_persistent() */ -int is_repeated(const order * ord) +bool is_repeated(const order * ord) { keyword_t kwd = ORD_KEYWORD(ord); const struct locale *lang = ORD_LOCALE(ord); @@ -439,7 +439,7 @@ int is_repeated(const order * ord) * \return true if the order is long * \sa is_exclusive(), is_repeated(), is_persistent() */ -int is_exclusive(const order * ord) +bool is_exclusive(const order * ord) { keyword_t kwd = ORD_KEYWORD(ord); const struct locale *lang = ORD_LOCALE(ord); @@ -500,11 +500,11 @@ int is_exclusive(const order * ord) * \return true if the order is long * \sa is_exclusive(), is_repeated(), is_persistent() */ -int is_long(const order * ord) +bool is_long(const order * ord) { keyword_t kwd = ORD_KEYWORD(ord); const struct locale *lang = ORD_LOCALE(ord); - int result = 0; + bool result = false; switch (kwd) { case K_CAST: @@ -550,7 +550,7 @@ int is_long(const order * ord) parser_popstate(); break; default: - result = 0; + result = false; } return result; } @@ -564,7 +564,7 @@ int is_long(const order * ord) * \return true if the order is persistent * \sa is_exclusive(), is_repeated(), is_persistent() */ -int is_persistent(const order * ord) +bool is_persistent(const order * ord) { keyword_t kwd = ORD_KEYWORD(ord); int persist = ord->_persistent != 0; diff --git a/src/kernel/order.h b/src/kernel/order.h index 9e0ebeef5..6e2159687 100644 --- a/src/kernel/order.h +++ b/src/kernel/order.h @@ -51,10 +51,10 @@ extern "C" { extern keyword_t get_keyword(const order * ord); extern void set_order(order ** destp, order * src); extern char *getcommand(const order * ord); - extern int is_persistent(const order * ord); - extern int is_exclusive(const order * ord); - extern int is_repeated(const order * ord); - extern int is_long(const order * ord); + extern bool is_persistent(const order * ord); + extern bool is_exclusive(const order * ord); + extern bool is_repeated(const order * ord); + extern bool is_long(const order * ord); extern char *write_order(const order * ord, char *buffer, size_t size); diff --git a/src/kernel/region.c b/src/kernel/region.c index bfaaab804..bdd16de12 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -817,17 +817,17 @@ bool r_isforest(const region * r) return false; } -int is_coastregion(region * r) +bool is_coastregion(region * r) { direction_t i; int res = 0; - for (i = 0; i < MAXDIRECTIONS; i++) { + for (i = 0; !res && i < MAXDIRECTIONS; i++) { region *rn = rconnect(r, i); if (rn && fval(rn->terrain, SEA_REGION)) res++; } - return res; + return res!=0; } int rpeasants(const region * r) diff --git a/src/kernel/region.h b/src/kernel/region.h index 88764586a..2cdd3dd95 100644 --- a/src/kernel/region.h +++ b/src/kernel/region.h @@ -210,7 +210,7 @@ extern "C" { short rroad(const struct region *r, direction_t d); void rsetroad(struct region *r, direction_t d, short value); - int is_coastregion(struct region *r); + bool is_coastregion(struct region *r); int rtrees(const struct region *r, int ageclass); enum { From 3cee3d14158e5a82c4f7e1ac53bd54867cc25587 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 1 Jul 2012 19:17:47 +0200 Subject: [PATCH 361/400] lua 5.2 compat changes --- scripts/tests/common.lua | 10 +++---- src/CMakeLists.txt | 2 +- src/bindings/CMakeLists.txt | 2 +- src/bindings/bind_building.c | 1 - src/bindings/bind_faction.c | 1 - src/bindings/bind_gmtool.c | 1 - src/bindings/bind_hashtable.c | 1 - src/bindings/bind_message.c | 1 - src/bindings/bind_region.c | 1 - src/bindings/bind_ship.c | 1 - src/bindings/bind_sqlite.c | 1 - src/bindings/bind_storage.c | 1 - src/bindings/bind_unit.c | 1 - src/bindings/bindings.c | 11 ++++++-- src/bindings/helpers.c | 53 ++++++++++++----------------------- src/util/console.c | 9 +++--- 16 files changed, 37 insertions(+), 60 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 3fe4a1ae8..34f46b169 100755 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -594,7 +594,7 @@ function test_guard_resources() end local function is_flag_set(flags, flag) - return math.mod(flags, flag*2) - math.mod(flags, flag) == flag; + return math.fmod(flags, flag*2) - math.fmod(flags, flag) == flag; end function test_hero_hero_transfer() @@ -803,7 +803,7 @@ end local function find_in_report(f, pattern, extension) extension = extension or "nr" local filename = config.reportpath .. "/" .. get_turn() .. "-" .. itoa36(f.id) .. "." .. extension - local report = io.open(filename, 'rt'); + local report = io.open(filename, 'r'); assert_not_nil(report) t = report:read("*all") report:close() @@ -893,7 +893,7 @@ function test_parser() local u = unit.create(f, r, 1) local filename = config.basepath .. "/data/orders.txt" - local file = io.open(filename, "w+") + local file = io.open(filename, "w") assert_not_nil(file) file:write('ERESSEA ' .. itoa36(f.id) .. ' "' .. f.password .. '"\n') file:write('EINHEIT ' .. itoa36(u.id) .. "\n") @@ -956,7 +956,7 @@ function test_bug_1814() local u = unit.create(f, r, 1) local filename = config.basepath .. "/data/1814.txt" - local file = io.open(filename, "w+") + local file = io.open(filename, "w") file:write('ERESSEA ' .. itoa36(f.id) .. ' "' .. f.password .. '"\n') file:write('EINHEIT ' .. itoa36(u.id) .. "\n") file:write("; parse error follows: '\n") @@ -977,7 +977,7 @@ function test_bug_1679() local u = unit.create(f, r, 1) local filename = config.basepath .. "/data/1679.txt" - local file = io.open(filename, "w+") + local file = io.open(filename, "w") file:write('ERESSEA ' .. itoa36(f.id) .. ' "' .. f.password .. '"\n') file:write('EINHEIT ' .. itoa36(u.id) .. "\n") file:write("NACH W\n") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8421e4692..99c318a95 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,7 +13,7 @@ set (ERESSEA_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "Eressea Cor add_subdirectory(bindings) -find_package (Lua51 REQUIRED) +find_package (Lua52 REQUIRED) find_package (ToLua REQUIRED) find_package (LibXml2 REQUIRED) find_package (Curses REQUIRED) diff --git a/src/bindings/CMakeLists.txt b/src/bindings/CMakeLists.txt index 94efddcb2..f3945b4f5 100755 --- a/src/bindings/CMakeLists.txt +++ b/src/bindings/CMakeLists.txt @@ -9,7 +9,7 @@ ENDIF(CMAKE_COMPILER_IS_GNUCC) set (BINDINGS_LIBRARY ${PROJECT_NAME} CACHE INTERNAL "Eressea Lua Bindings") -find_package (Lua51 REQUIRED) +find_package (Lua52 REQUIRED) find_package (ToLua REQUIRED) find_package (LibXml2 REQUIRED) find_package (Curses REQUIRED) diff --git a/src/bindings/bind_building.c b/src/bindings/bind_building.c index 4e51a0a65..230ba5b88 100644 --- a/src/bindings/bind_building.c +++ b/src/bindings/bind_building.c @@ -21,7 +21,6 @@ without prior permission by the authors of Eressea. #include -#include #include int tolua_buildinglist_next(lua_State * L) diff --git a/src/bindings/bind_faction.c b/src/bindings/bind_faction.c index 111b49f37..d5efd226c 100644 --- a/src/bindings/bind_faction.c +++ b/src/bindings/bind_faction.c @@ -29,7 +29,6 @@ without prior permission by the authors of Eressea. #include #include -#include #include int tolua_factionlist_next(lua_State * L) diff --git a/src/bindings/bind_gmtool.c b/src/bindings/bind_gmtool.c index a55cb75b7..654f16f30 100644 --- a/src/bindings/bind_gmtool.c +++ b/src/bindings/bind_gmtool.c @@ -11,7 +11,6 @@ #include #include -#include #include static int tolua_run_mapper(lua_State * L) diff --git a/src/bindings/bind_hashtable.c b/src/bindings/bind_hashtable.c index 2069e272b..17c6c4975 100644 --- a/src/bindings/bind_hashtable.c +++ b/src/bindings/bind_hashtable.c @@ -23,7 +23,6 @@ without prior permission by the authors of Eressea. #include #include -#include #include #include diff --git a/src/bindings/bind_message.c b/src/bindings/bind_message.c index 6ff30e98a..2959c6c5c 100644 --- a/src/bindings/bind_message.c +++ b/src/bindings/bind_message.c @@ -13,7 +13,6 @@ #include /* lua includes */ -#include #include #include diff --git a/src/bindings/bind_region.c b/src/bindings/bind_region.c index 58f64203c..b5fb16108 100644 --- a/src/bindings/bind_region.c +++ b/src/bindings/bind_region.c @@ -37,7 +37,6 @@ without prior permission by the authors of Eressea. #include #include -#include #include #include diff --git a/src/bindings/bind_ship.c b/src/bindings/bind_ship.c index d5319dfe0..ddfa883ad 100644 --- a/src/bindings/bind_ship.c +++ b/src/bindings/bind_ship.c @@ -22,7 +22,6 @@ without prior permission by the authors of Eressea. #include -#include #include int tolua_shiplist_next(lua_State * L) diff --git a/src/bindings/bind_sqlite.c b/src/bindings/bind_sqlite.c index 0df9e530f..6f6c5ea29 100644 --- a/src/bindings/bind_sqlite.c +++ b/src/bindings/bind_sqlite.c @@ -16,7 +16,6 @@ without prior permission by the authors of Eressea. #include "bindings.h" #include -#include #include #define LTYPE_DB TOLUA_CAST "db" diff --git a/src/bindings/bind_storage.c b/src/bindings/bind_storage.c index 5e7768d2d..e2b83b670 100644 --- a/src/bindings/bind_storage.c +++ b/src/bindings/bind_storage.c @@ -22,7 +22,6 @@ without prior permission by the authors of Eressea. #include #include -#include #include static int tolua_storage_create(lua_State * L) diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 543a9f9d5..5d4dd9b47 100755 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -51,7 +51,6 @@ without prior permission by the authors of Eressea. #include #include -#include #include #include diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index b452eb366..23f90cd8a 100755 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -1182,12 +1182,17 @@ static const struct { static void openlibs(lua_State * L) { - int i; + luaL_openlibs(L); +/* int i, err; for (i = 0; lualibs[i].func; ++i) { lua_pushcfunction(L, lualibs[i].func); lua_pushstring(L, lualibs[i].name); - lua_call(L, 1, 0); + err = lua_pcall(L, 1, 0, 0); + if (err != 0) { + log_lua_error(L); + } } +*/ } void lua_done(lua_State * L) { @@ -1195,7 +1200,7 @@ void lua_done(lua_State * L) { } lua_State *lua_init(void) { - lua_State *L = lua_open(); + lua_State *L = luaL_newstate(); openlibs(L); #ifdef BINDINGS_TOLUA diff --git a/src/bindings/helpers.c b/src/bindings/helpers.c index d6d73d7b2..5658f590c 100644 --- a/src/bindings/helpers.c +++ b/src/bindings/helpers.c @@ -31,8 +31,8 @@ without prior permission by the authors of Eressea. #include -#include #include +#include #include @@ -48,8 +48,7 @@ lua_giveitem(unit * s, unit * d, const item_type * itype, int n, struct order *o strlcpy(fname, iname, sizeof(fname)); strlcat(fname, "_give", sizeof(fname)); - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, fname); if (lua_isfunction(L, -1)) { tolua_pushusertype(L, s, TOLUA_CAST "unit"); tolua_pushusertype(L, d, TOLUA_CAST "unit"); @@ -81,8 +80,7 @@ static int limit_resource(const region * r, const resource_type * rtype) strlcpy(fname, rtype->_name[0], sizeof(fname)); strlcat(fname, "_limit", sizeof(fname)); - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, fname); if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); @@ -111,8 +109,7 @@ produce_resource(region * r, const resource_type * rtype, int norders) strlcpy(fname, rtype->_name[0], sizeof(fname)); strlcat(fname, "_produce", sizeof(fname)); - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, fname); if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); tolua_pushnumber(L, (lua_Number) norders); @@ -140,8 +137,7 @@ static int lc_age(struct attrib *a) if (fname != NULL) { lua_State *L = (lua_State *) global.vm_state; - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, fname); if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); if (fparam) { @@ -201,8 +197,7 @@ static int lua_callspell(castorder * co) fname = fbuf; } - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, fname); if (lua_isfunction(L, -1)) { int nparam = 4; tolua_pushusertype(L, r, TOLUA_CAST "region"); @@ -254,8 +249,7 @@ static int lua_initfamiliar(unit * u) strlcpy(fname, "initfamiliar_", sizeof(fname)); strlcat(fname, u->race->_name[0], sizeof(fname)); - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, fname); if (lua_isfunction(L, -1)) { tolua_pushusertype(L, u, TOLUA_CAST "unit"); @@ -290,8 +284,7 @@ lua_changeresource(unit * u, const struct resource_type *rtype, int delta) strlcpy(fname, rtype->_name[0], sizeof(fname)); strlcat(fname, "_changeresource", sizeof(fname)); - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, fname); if (lua_isfunction(L, -1)) { tolua_pushusertype(L, u, TOLUA_CAST "unit"); tolua_pushnumber(L, (lua_Number) delta); @@ -321,8 +314,7 @@ static int lua_getresource(unit * u, const struct resource_type *rtype) strlcpy(fname, rtype->_name[0], sizeof(fname)); strlcat(fname, "_getresource", sizeof(fname)); - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, fname); if (lua_isfunction(L, -1)) { tolua_pushusertype(L, u, TOLUA_CAST "unit"); @@ -351,8 +343,7 @@ static bool lua_canuse_item(const unit * u, const struct item_type *itype) lua_State *L = (lua_State *) global.vm_state; const char *fname = "item_canuse"; - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, fname); if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); tolua_pushstring(L, itype->rtype->_name[0]); @@ -381,8 +372,7 @@ lua_wage(const region * r, const faction * f, const race * rc, int in_turn) const char *fname = "wage"; int result = -1; - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, fname); if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)r, TOLUA_CAST "region"); tolua_pushusertype(L, (void *)f, TOLUA_CAST "faction"); @@ -413,8 +403,7 @@ static void lua_agebuilding(building * b) strlcpy(fname, "age_", sizeof(fname)); strlcat(fname, b->type->_name, sizeof(fname)); - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, fname); if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); @@ -435,8 +424,7 @@ static int lua_building_protection(building * b, unit * u) const char *fname = "building_protection"; int result = 0; - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, fname); if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); @@ -462,8 +450,7 @@ static double lua_building_taxes(building * b, int level) const char *fname = "building_taxes"; double result = 0.0F; - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, fname); if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)b, TOLUA_CAST "building"); tolua_pushnumber(L, level); @@ -489,8 +476,7 @@ static int lua_maintenance(const unit * u) const char *fname = "maintenance"; int result = -1; - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, fname); if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); @@ -519,8 +505,7 @@ static int lua_equipmentcallback(const struct equipment *eq, unit * u) strlcpy(fname, "equip_", sizeof(fname)); strlcat(fname, eq->name, sizeof(fname)); - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, fname); if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); @@ -551,8 +536,7 @@ lua_useitem(struct unit *u, const struct item_type *itype, int amount, strlcpy(fname, "use_", sizeof(fname)); strlcat(fname, itype->rtype->_name[0], sizeof(fname)); - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, fname); if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); tolua_pushnumber(L, (lua_Number) amount); @@ -582,8 +566,7 @@ static int lua_recruit(struct unit *u, const struct archetype *arch, int amount) strlcpy(fname, "recruit_", sizeof(fname)); strlcat(fname, arch->name[0], sizeof(fname)); - lua_pushstring(L, fname); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, fname); if (lua_isfunction(L, -1)) { tolua_pushusertype(L, (void *)u, TOLUA_CAST "unit"); tolua_pushnumber(L, (lua_Number) amount); diff --git a/src/util/console.c b/src/util/console.c index 28586f704..0ce3704a8 100644 --- a/src/util/console.c +++ b/src/util/console.c @@ -29,7 +29,7 @@ #include #define default_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) #define lua_saveline(L,idx) \ - if (lua_strlen(L,idx) > 0) /* non-empty line? */ \ + if (lua_rawlen(L,idx) > 0) /* non-empty line? */ \ add_history(lua_tostring(L, idx)); /* add it to history */ #define lua_freeline(L,b) ((void)L, free(b)) #else @@ -109,7 +109,7 @@ static int report(lua_State * L, int status) static int traceback(lua_State * L) { - lua_getfield(L, LUA_GLOBALSINDEX, "debug"); + lua_getglobal(L, "debug"); if (!lua_istable(L, -1)) { lua_pop(L, 1); return 1; @@ -149,8 +149,7 @@ static int docall(lua_State * L, int narg, int clear) static const char *get_prompt(lua_State * L, int firstline) { const char *p = NULL; - lua_pushstring(L, firstline ? "_PROMPT" : "_PROMPT2"); - lua_rawget(L, LUA_GLOBALSINDEX); + lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2"); p = lua_tostring(L, -1); if (p == NULL) p = (firstline ? PROMPT : PROMPT2); @@ -195,7 +194,7 @@ static int loadline(lua_State * L) if (!pushline(L, 1)) return -1; /* no input */ for (;;) { /* repeat until gets a complete line */ - status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); + status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_rawlen(L, 1), "=stdin"); if (!incomplete(L, status)) break; /* cannot try to add lines? */ if (!pushline(L, 0)) /* no more input? */ From cb14492ccde24443b69974b8b2af5221ac934961 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 1 Jul 2012 22:31:14 +0200 Subject: [PATCH 362/400] make cmake find the best Lua version that's installed --- src/CMakeLists.txt | 2 +- src/bindings/CMakeLists.txt | 2 +- src/bindings/bindings.c | 30 ------------------------------ 3 files changed, 2 insertions(+), 32 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 99c318a95..633509d2d 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,7 +13,7 @@ set (ERESSEA_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "Eressea Cor add_subdirectory(bindings) -find_package (Lua52 REQUIRED) +find_package (Lua 5 REQUIRED) find_package (ToLua REQUIRED) find_package (LibXml2 REQUIRED) find_package (Curses REQUIRED) diff --git a/src/bindings/CMakeLists.txt b/src/bindings/CMakeLists.txt index f3945b4f5..56310c2d3 100755 --- a/src/bindings/CMakeLists.txt +++ b/src/bindings/CMakeLists.txt @@ -9,7 +9,7 @@ ENDIF(CMAKE_COMPILER_IS_GNUCC) set (BINDINGS_LIBRARY ${PROJECT_NAME} CACHE INTERNAL "Eressea Lua Bindings") -find_package (Lua52 REQUIRED) +find_package (Lua 5 REQUIRED) find_package (ToLua REQUIRED) find_package (LibXml2 REQUIRED) find_package (Curses REQUIRED) diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index 23f90cd8a..904e3e015 100755 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -1160,39 +1160,9 @@ int tolua_bindings_open(lua_State * L) return 1; } -static const struct { - const char *name; - int (*func) (lua_State *); -} lualibs[] = { - { - "", luaopen_base}, { - LUA_TABLIBNAME, luaopen_table}, { - LUA_IOLIBNAME, luaopen_io}, { - LUA_STRLIBNAME, luaopen_string}, { - LUA_MATHLIBNAME, luaopen_math}, { - LUA_LOADLIBNAME, luaopen_package}, { - LUA_DBLIBNAME, luaopen_debug}, -#if LUA_VERSION_NUM>=501 - { - LUA_OSLIBNAME, luaopen_os}, -#endif - { - NULL, NULL} -}; - static void openlibs(lua_State * L) { luaL_openlibs(L); -/* int i, err; - for (i = 0; lualibs[i].func; ++i) { - lua_pushcfunction(L, lualibs[i].func); - lua_pushstring(L, lualibs[i].name); - err = lua_pcall(L, 1, 0, 0); - if (err != 0) { - log_lua_error(L); - } - } -*/ } void lua_done(lua_State * L) { From bd34cbd350dc1ca0a539b71fd18ed3d8b98152c8 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 26 Jun 2012 05:17:11 -0700 Subject: [PATCH 363/400] lua 5.1 and lua 5.2 side-by-side --- src/util/console.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/util/console.c b/src/util/console.c index 0ce3704a8..b850678c5 100644 --- a/src/util/console.c +++ b/src/util/console.c @@ -23,13 +23,17 @@ #define LUA_MAXINPUT 512 #endif +#if LUA_VERSION_NUM >= 502 +#define lua_strlen(L, idx) lua_rawlen(L, idx) +#endif + #if defined(LUA_USE_READLINE) #include #include #include #define default_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) #define lua_saveline(L,idx) \ - if (lua_rawlen(L,idx) > 0) /* non-empty line? */ \ + if (lua_strlen(L,idx) > 0) /* non-empty line? */ \ add_history(lua_tostring(L, idx)); /* add it to history */ #define lua_freeline(L,b) ((void)L, free(b)) #else @@ -194,7 +198,7 @@ static int loadline(lua_State * L) if (!pushline(L, 1)) return -1; /* no input */ for (;;) { /* repeat until gets a complete line */ - status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_rawlen(L, 1), "=stdin"); + status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin"); if (!incomplete(L, status)) break; /* cannot try to add lines? */ if (!pushline(L, 0)) /* no more input? */ From 5e3ce7ad4d4d844e7f38dff5e832d48c17fae8e7 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 26 Jun 2012 20:29:32 -0700 Subject: [PATCH 364/400] export more battle functions for e4 combat alliances have lists of diplomatic relations (enemies) --- src/kernel/alliance.h | 3 ++ src/kernel/battle.c | 81 +++++++++++++++++++++++++++++++------------ src/kernel/battle.h | 11 ++++-- src/kernel/config.h | 2 ++ src/kernel/faction.h | 2 +- src/kernel/types.h | 4 --- 6 files changed, 72 insertions(+), 31 deletions(-) diff --git a/src/kernel/alliance.h b/src/kernel/alliance.h index a97227ab0..04871c50a 100644 --- a/src/kernel/alliance.h +++ b/src/kernel/alliance.h @@ -40,6 +40,8 @@ extern "C" { #define ALF_NON_ALLIED (1<<0) /* this alliance is just a default for a non-allied faction */ +#define ALLY_ENEMY (1<<0) + typedef struct alliance { struct alliance *next; struct faction *_leader; @@ -47,6 +49,7 @@ extern "C" { unsigned int flags; int id; char *name; + struct ally *allies; } alliance; extern alliance *alliances; diff --git a/src/kernel/battle.c b/src/kernel/battle.c index 662c797c7..8dfd2357e 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -3137,6 +3137,45 @@ static int weapon_weight(const weapon * w, bool missile) return 0; } +side * get_side(battle * b, const const unit * u) +{ + side * s; + for (s = b->sides; s != b->sides + b->nsides; ++s) { + if (s->faction==u->faction) { + fighter * fig; + for (fig=s->fighters;fig;fig=fig->next) { + if (fig->unit==u) { + return s; + } + } + } + } + return 0; +} + +side * find_side(battle * b, const faction * f, const group * g, int flags, const faction * stealthfaction) +{ + side * s; + static int rule_anon_battle = -1; + + if (rule_anon_battle < 0) { + rule_anon_battle = get_param_int(global.parameters, "rules.stealth.anon_battle", 1); + } + for (s = b->sides; s != b->sides + b->nsides; ++s) { + if (s->faction == f && s->group == g) { + int s1flags = flags | SIDE_HASGUARDS; + int s2flags = s->flags | SIDE_HASGUARDS; + if (rule_anon_battle && s->stealthfaction != stealthfaction) { + continue; + } + if (s1flags == s2flags) { + return s; + } + } + } + return 0; +} + fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) { #define WMAX 20 @@ -3147,9 +3186,7 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) region *r = b->region; item *itm; fighter *fig = NULL; - int i, tactics = eff_skill(u, SK_TACTICS, r); - side *s2; - int h; + int h, i, tactics = eff_skill(u, SK_TACTICS, r); int berserk; int strongmen; int speeded = 0, speed = 1; @@ -3159,14 +3196,8 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) const attrib *a = a_find(u->attribs, &at_otherfaction); const faction *stealthfaction = a ? get_otherfaction(a) : NULL; unsigned int flags = 0; - static int rule_anon_battle = -1; assert(u->number); - - if (rule_anon_battle < 0) { - rule_anon_battle = - get_param_int(global.parameters, "rules.stealth.anon_battle", 1); - } if (fval(u, UFL_ANON_FACTION) != 0) flags |= SIDE_STEALTH; if (!(AllianceAuto() & HELP_FIGHT) && fval(u, UFL_GROUP)) { @@ -3180,20 +3211,7 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) return NULL; } if (s1 == NULL) { - for (s2 = b->sides; s2 != b->sides + b->nsides; ++s2) { - if (s2->faction == u->faction && s2->group == g) { - int s1flags = flags | SIDE_HASGUARDS; - int s2flags = s2->flags | SIDE_HASGUARDS; - if (rule_anon_battle && s2->stealthfaction != stealthfaction) { - continue; - } - if (s1flags == s2flags) { - s1 = s2; - break; - } - } - } - + s1 = find_side(b, u->faction, g, flags, stealthfaction); /* aliances are moved out of make_fighter and will be handled later */ if (!s1) { s1 = make_side(b, u->faction, g, flags, stealthfaction); @@ -3459,6 +3477,23 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) return fig; } +fighter * get_fighter(battle * b, const struct unit * u) +{ + side * s; + + for (s = b->sides; s != b->sides + b->nsides; ++s) { + fighter *fig; + if (s->faction == u->faction) { + for (fig = s->fighters; fig; fig = fig->next) { + if (fig->unit == u) { + return fig; + } + } + } + } + return 0; +} + static int join_battle(battle * b, unit * u, bool attack, fighter ** cp) { side *s; diff --git a/src/kernel/battle.h b/src/kernel/battle.h index 59ced0967..eb854caeb 100644 --- a/src/kernel/battle.h +++ b/src/kernel/battle.h @@ -114,9 +114,6 @@ extern "C" { } fast; } battle; - void battle_init(battle * b); - void battle_free(battle * b); - typedef struct weapon { int count, used; const struct weapon_type *type; @@ -208,6 +205,14 @@ extern "C" { extern const troop no_troop; + /* BEGIN battle interface */ + void battle_init(battle * b); + void battle_free(battle * b); + side * find_side(battle * b, const struct faction * f, const struct group * g, int flags, const struct faction * stealthfaction); + side * get_side(battle * b, const struct unit * u); + fighter * get_fighter(battle * b, const struct unit * u); + /* END battle interface */ + extern void do_battle(struct region *r); /* for combat spells and special attacks */ diff --git a/src/kernel/config.h b/src/kernel/config.h index 559bcae2d..4a3531444 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -119,6 +119,8 @@ extern "C" { int status; } ally; + ally * ally_find(const ally *al, const struct faction *f); + void remove_empty_units_in_region(struct region *r); void remove_empty_units(void); void remove_empty_factions(void); diff --git a/src/kernel/faction.h b/src/kernel/faction.h index e68cf8bcd..cc7239e82 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -125,7 +125,7 @@ extern "C" { extern void set_alliance(struct faction *a, struct faction *b, int status); extern int get_alliance(const struct faction *a, const struct faction *b); - extern struct alliance *f_get_alliance(const struct faction *a); + extern struct alliance *f_get_alliance(const struct faction *f); extern void write_faction_reference(const struct faction *f, struct storage *store); diff --git a/src/kernel/types.h b/src/kernel/types.h index ed895bfdd..130d576a0 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -394,10 +394,6 @@ typedef enum { /* ------------------------------------------------------------- */ /* Prototypen */ -#define ALLIED_TAX 1 -#define ALLIED_NOBLOCK 2 -#define ALLIED_HELP 4 - /* alle vierstelligen zahlen: */ #define MAX_UNIT_NR (36*36*36*36-1) #define MAX_CONTAINER_NR (36*36*36*36-1) From 6911af02b11a782e3ef363c0f341fd983e0b3d45 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 30 Jun 2012 11:07:28 -0700 Subject: [PATCH 365/400] moving the ally struct into a separate file, with interface and test coverage. --- src/CMakeLists.txt | 2 ++ src/gamecode/creport.c | 1 + src/gamecode/laws.c | 1 + src/gamecode/report.c | 1 + src/gamecode/xmlreport.c | 1 + src/kernel/ally.c | 39 +++++++++++++++++++++++++++++++++++++++ src/kernel/ally.h | 40 ++++++++++++++++++++++++++++++++++++++++ src/kernel/ally_test.c | 27 +++++++++++++++++++++++++++ src/kernel/config.c | 1 + src/kernel/config.h | 8 -------- src/kernel/faction.c | 1 + src/kernel/group.c | 3 ++- src/kernel/save.c | 1 + src/kernel/types.h | 1 + src/tests.c | 1 + src/tests.h | 1 + 16 files changed, 120 insertions(+), 9 deletions(-) create mode 100644 src/kernel/ally.c create mode 100644 src/kernel/ally.h create mode 100644 src/kernel/ally_test.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9e9eb8d6c..8421e4692 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -50,6 +50,7 @@ set (TEST_SRC gamecode/economy_test.c gamecode/laws_test.c gamecode/market_test.c + kernel/ally_test.c kernel/battle_test.c kernel/building_test.c kernel/curse_test.c @@ -116,6 +117,7 @@ set (LIB_SRC items/xerewards.c kernel/alchemy.c kernel/alliance.c + kernel/ally.c kernel/battle.c kernel/binarystore.c kernel/build.c diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index 0a4768097..90374cb4b 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -33,6 +33,7 @@ without prior permission by the authors of Eressea. /* kernel includes */ #include #include +#include #include #include #include diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 3e7ca3595..80a819f5c 100755 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -37,6 +37,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* kernel includes */ #include #include +#include #include #include #include diff --git a/src/gamecode/report.c b/src/gamecode/report.c index c01ea5089..898b06c20 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -38,6 +38,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* kernel includes */ #include +#include #include #include #include diff --git a/src/gamecode/xmlreport.c b/src/gamecode/xmlreport.c index 9ccf72a31..f4e4f9b6d 100644 --- a/src/gamecode/xmlreport.c +++ b/src/gamecode/xmlreport.c @@ -31,6 +31,7 @@ without prior permission by the authors of Eressea. /* kernel includes */ #include #include +#include #include #include #include diff --git a/src/kernel/ally.c b/src/kernel/ally.c new file mode 100644 index 000000000..cf5772fd6 --- /dev/null +++ b/src/kernel/ally.c @@ -0,0 +1,39 @@ +#include "types.h" +#include "ally.h" + +#include + +ally * ally_find(ally *al, const struct faction *f) { + for (;al;al=al->next) { + if (al->faction==f) return al; + } + return 0; +} + +ally * ally_add(ally **al_p, struct faction *f) { + ally * al; + while (*al_p) { + al = *al_p; + if (al->faction==f) return al; + al_p = &al->next; + } + al = (ally *)malloc(sizeof(ally)); + al->faction = f; + al->status = 0; + al->next = 0; + *al_p = al; + return al; +} + +void ally_remove(ally **al_p, struct faction *f) { + ally * al; + while (*al_p) { + al = *al_p; + if (al->faction==f) { + *al_p = al->next; + free(al); + break; + } + al_p = &al->next; + } +} diff --git a/src/kernel/ally.h b/src/kernel/ally.h new file mode 100644 index 000000000..5e09b721c --- /dev/null +++ b/src/kernel/ally.h @@ -0,0 +1,40 @@ +/* +Copyright (c) 1998-2010, Enno Rehling + Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef ALLY_H +#define ALLY_H + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct ally { + struct ally *next; + struct faction *faction; + int status; + } ally; + + 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); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/kernel/ally_test.c b/src/kernel/ally_test.c new file mode 100644 index 000000000..c7b8500ad --- /dev/null +++ b/src/kernel/ally_test.c @@ -0,0 +1,27 @@ +#include +#include "types.h" +#include "ally.h" + +#include +#include + +static void test_ally(CuTest * tc) +{ + ally * al = 0; + struct faction * f1 = test_create_faction(0); + + ally_add(&al, f1); + CuAssertPtrNotNull(tc, al); + CuAssertPtrEquals(tc, f1, ally_find(al, f1)->faction); + + ally_remove(&al, f1); + CuAssertPtrEquals(tc, 0, al); + CuAssertPtrEquals(tc, 0, ally_find(al, f1)); +} + +CuSuite *get_ally_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_ally); + return suite; +} diff --git a/src/kernel/config.c b/src/kernel/config.c index 7d84f396a..224923bf3 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -25,6 +25,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* kernel includes */ #include "alliance.h" +#include "ally.h" #include "alchemy.h" #include "battle.h" #include "connection.h" diff --git a/src/kernel/config.h b/src/kernel/config.h index c9c43f89b..23542caf5 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -113,14 +113,6 @@ extern "C" { #define i2b(i) ((bool)((i)?(true):(false))) - typedef struct ally { - struct ally *next; - struct faction *faction; - int status; - } ally; - - ally * ally_find(const ally *al, const struct faction *f); - void remove_empty_units_in_region(struct region *r); void remove_empty_units(void); void remove_empty_factions(void); diff --git a/src/kernel/faction.c b/src/kernel/faction.c index 8bf86e30a..ea02a62a1 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "faction.h" #include "alliance.h" +#include "ally.h" #include "equipment.h" #include "group.h" #include "item.h" diff --git a/src/kernel/group.c b/src/kernel/group.c index 8b6144d82..0e49fd4aa 100755 --- a/src/kernel/group.c +++ b/src/kernel/group.c @@ -21,9 +21,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "group.h" /* kernel includes */ -#include "unit.h" +#include "ally.h" #include "faction.h" #include "save.h" +#include "unit.h" #include "version.h" /* attrib includes */ diff --git a/src/kernel/save.c b/src/kernel/save.c index c8c39b50f..1ba845cc0 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -22,6 +22,7 @@ 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 "faction.h" diff --git a/src/kernel/types.h b/src/kernel/types.h index 130d576a0..f6f1e4099 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -35,6 +35,7 @@ typedef short item_t; struct attrib; struct attrib_type; +struct ally; struct building; struct building_type; struct curse; diff --git a/src/tests.c b/src/tests.c index b269663dc..a0c5dcd94 100644 --- a/src/tests.c +++ b/src/tests.c @@ -51,6 +51,7 @@ int RunAllTests(void) CuSuiteAddSuite(suite, get_building_suite()); CuSuiteAddSuite(suite, get_spell_suite()); CuSuiteAddSuite(suite, get_battle_suite()); + CuSuiteAddSuite(suite, get_ally_suite()); /* gamecode */ CuSuiteAddSuite(suite, get_market_suite()); CuSuiteAddSuite(suite, get_laws_suite()); diff --git a/src/tests.h b/src/tests.h index 2b6b91cce..2ea13633e 100644 --- a/src/tests.h +++ b/src/tests.h @@ -25,6 +25,7 @@ extern "C" { CuSuite *get_bsdstring_suite(void); CuSuite *get_functions_suite(void); CuSuite *get_umlaut_suite(void); + CuSuite *get_ally_suite(void); void test_cleanup(void); From 5f5b4a394767c50a27c2f309f37eed379d12f036 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 30 Jun 2012 20:29:04 +0200 Subject: [PATCH 366/400] there is an old version of tolua on gelbbaer that doesn't do comparisons of user types. ugh. --- scripts/tests/orders.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tests/orders.lua b/scripts/tests/orders.lua index b46e0c1c7..ac98a1d1b 100755 --- a/scripts/tests/orders.lua +++ b/scripts/tests/orders.lua @@ -140,7 +140,7 @@ end function test_process_move() r2 = _G.region.create(1, 0, 'plain') u:add_order('NACH O') - assert_not_equal(r2, u.region) + assert_not_equal(r2.id, u.region.id) eressea.process.update_long_order() eressea.process.movement() assert_equal(r2, u.region) From 9d8e02d094b2392f7e2f3c35efda982df6895839 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 1 Jul 2012 18:00:31 -0700 Subject: [PATCH 367/400] test that movement into coastal regions is blocked when no harbor exists, unless ship is allowed in this terrain. --- src/kernel/move.c | 15 +++++--------- src/kernel/move.h | 6 ++++++ src/kernel/move_test.c | 47 ++++++++++++++++++++++++++++++++++++++++++ src/kernel/ship.c | 5 +++-- src/tests.c | 39 +++++++++++++++++++++-------------- src/tests.h | 3 +++ 6 files changed, 88 insertions(+), 27 deletions(-) diff --git a/src/kernel/move.c b/src/kernel/move.c index b7c30a677..8b3572f6d 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -621,12 +621,7 @@ static bool is_freezing(const unit * u) return true; } -#define SA_HARBOUR 1 -#define SA_COAST 1 -#define SA_NO_INSECT -1 -#define SA_NO_COAST -2 - -static bool is_ship_allowed(struct ship *sh, const region * r) +int check_ship_allowed(struct ship *sh, const region * r) { int c = 0; static const building_type *bt_harbour = NULL; @@ -634,7 +629,7 @@ static bool is_ship_allowed(struct ship *sh, const region * r) if (bt_harbour == NULL) bt_harbour = bt_find("harbour"); - if (r_insectstalled(r)) { + if (sh->region && r_insectstalled(r)) { /* insekten dürfen nicht hier rein. haben wir welche? */ unit *u; @@ -654,7 +649,7 @@ static bool is_ship_allowed(struct ship *sh, const region * r) } } - if (buildingtype_exists(r, bt_harbour, true)) + if (bt_harbour && buildingtype_exists(r, bt_harbour, true)) return SA_HARBOUR; for (c = 0; sh->type->coasts[c] != NULL; ++c) { if (sh->type->coasts[c] == r->terrain) @@ -746,7 +741,7 @@ static void drifting_ships(region * r) region *rn; dir = (direction_t) ((d + d_offset) % MAXDIRECTIONS); rn = rconnect(r, dir); - if (rn != NULL && fval(rn->terrain, SAIL_INTO) && is_ship_allowed(sh, rn) > 0) { + if (rn != NULL && fval(rn->terrain, SAIL_INTO) && check_ship_allowed(sh, rn) > 0) { rnext = rn; if (!fval(rnext->terrain, SEA_REGION)) break; @@ -1809,7 +1804,7 @@ sail(unit * u, order * ord, bool move_on_land, region_list ** routep) } } - reason = is_ship_allowed(sh, next_point); + reason = check_ship_allowed(sh, next_point); if (reason<0) { /* for some reason or another, we aren't allowed in there.. */ if (check_leuchtturm(current_point, NULL) || reason == SA_NO_INSECT) { diff --git a/src/kernel/move.h b/src/kernel/move.h index 80744ce9f..c76c362c1 100644 --- a/src/kernel/move.h +++ b/src/kernel/move.h @@ -66,7 +66,13 @@ extern "C" { const struct building_type *bt); extern struct attrib_type at_speedup; + +#define SA_HARBOUR 2 +#define SA_COAST 1 +#define SA_NO_INSECT -1 +#define SA_NO_COAST -2 + extern int check_ship_allowed(struct ship *sh, const struct region * r); #ifdef __cplusplus } #endif diff --git a/src/kernel/move_test.c b/src/kernel/move_test.c index 172012e4d..3183d9a59 100644 --- a/src/kernel/move_test.c +++ b/src/kernel/move_test.c @@ -4,12 +4,57 @@ #include #include #include +#include +#include #include #include #include +static void test_ship_not_allowed_in_coast(CuTest * tc) +{ + region *r; + ship * sh; + terrain_type * ttype; + ship_type * stype; + char * names[] = { "derp", "derp_p" }; + + test_cleanup(); + test_create_world(); + + ttype = test_create_terrain("glacier", LAND_REGION|ARCTIC_REGION|WALK_INTO|SAIL_INTO); + stype = test_create_shiptype(names); + stype->coasts = (const struct terrain_type **)calloc(2, sizeof(const struct terrain_type *)); + + r = test_create_region(0, 0, ttype); + sh = test_create_ship(0, stype); + + CuAssertIntEquals(tc, SA_NO_COAST, check_ship_allowed(sh, r)); + stype->coasts[0] = ttype; + CuAssertIntEquals(tc, SA_COAST, check_ship_allowed(sh, r)); +} + +static void test_ship_allowed_with_harbor(CuTest * tc) +{ + region *r; + ship * sh; + terrain_type * ttype; + building_type * btype; + + test_cleanup(); + test_create_world(); + + ttype = test_create_terrain("glacier", LAND_REGION|ARCTIC_REGION|WALK_INTO|SAIL_INTO); + btype = test_create_buildingtype("harbour"); + + r = test_create_region(0, 0, ttype); + sh = test_create_ship(0, 0); + + test_create_building(r, btype); + CuAssertIntEquals(tc, SA_HARBOUR, check_ship_allowed(sh, r)); +} + static void test_building_type_exists(CuTest * tc) { region *r; @@ -35,5 +80,7 @@ CuSuite *get_move_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_building_type_exists); + SUITE_ADD_TEST(suite, test_ship_not_allowed_in_coast); + SUITE_ADD_TEST(suite, test_ship_allowed_with_harbor); return suite; } diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 141bd4ba9..96745c59e 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -171,7 +171,6 @@ ship *new_ship(const ship_type * stype, region * r, const struct locale *lang) const char *sname = 0; assert(stype); - assert(r); sh->no = newcontainerid(); sh->coast = NODIRECTION; sh->type = stype; @@ -188,7 +187,9 @@ ship *new_ship(const ship_type * stype, region * r, const struct locale *lang) slprintf(buffer, sizeof(buffer), "%s %s", sname, shipid(sh)); sh->name = strdup(buffer); shash(sh); - addlist(&r->ships, sh); + if (r) { + addlist(&r->ships, sh); + } return sh; } diff --git a/src/tests.c b/src/tests.c index a0c5dcd94..dd05c7d93 100644 --- a/src/tests.c +++ b/src/tests.c @@ -138,6 +138,26 @@ ship * test_create_ship(region * r, const ship_type * stype) return s; } +ship_type * test_create_shiptype(const char ** names) +{ + ship_type * stype = (ship_type*)calloc(sizeof(ship_type), 1); + stype->name[0] = strdup(names[0]); + stype->name[1] = strdup(names[1]); + locale_setstring(default_locale, names[0], names[0]); + st_register(stype); + return stype; +} + +building_type * test_create_buildingtype(const char * name) +{ + building_type * btype = (building_type*)calloc(sizeof(building_type), 1); + btype->flags = BTF_NAMECHANGE; + btype->_name = strdup(name); + locale_setstring(default_locale, name, name); + bt_register(btype); + return btype; +} + item_type * test_create_itemtype(const char ** names) { resource_type * rtype; item_type * itype; @@ -160,16 +180,14 @@ void test_create_world(void) terrain_type *t_plain, *t_ocean; region *island[2]; int i; - building_type *btype; - ship_type *stype; item_type * itype; - const char * horses[2] = { "horse", "horse_p" }; + const char * names[] = { "horse", "horse_p", "boat", "boat_p" }; make_locale("de"); init_resources(); assert(!olditemtype[I_HORSE]); - itype = test_create_itemtype(horses); + itype = test_create_itemtype(names); olditemtype[I_HORSE] = itype; t_plain = test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION); @@ -192,17 +210,8 @@ void test_create_world(void) test_create_race("human"); - btype = (building_type*)calloc(sizeof(building_type), 1); - btype->flags = BTF_NAMECHANGE; - btype->_name = strdup("castle"); - locale_setstring(default_locale, "castle", "castle"); - bt_register(btype); - - stype = (ship_type*)calloc(sizeof(ship_type), 1); - stype->name[0] = strdup("boat"); - stype->name[1] = strdup("boat_p"); - locale_setstring(default_locale, "boat", "boat"); - st_register(stype); + test_create_buildingtype("castle"); + test_create_shiptype(names+2); } int main(int argc, char ** argv) { diff --git a/src/tests.h b/src/tests.h index 2ea13633e..15aa7a230 100644 --- a/src/tests.h +++ b/src/tests.h @@ -39,6 +39,9 @@ extern "C" { struct building * test_create_building(struct region * r, const struct building_type * btype); struct ship * test_create_ship(struct region * r, const struct ship_type * stype); struct item_type * test_create_itemtype(const char ** names); + struct ship_type *test_create_shiptype(const char **names); + struct building_type *test_create_buildingtype(const char *name); + int RunAllTests(void); #ifdef __cplusplus From f3286cbd0a616817efa288bba72f993bd32e7dd4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 2 Jul 2012 03:36:16 +0200 Subject: [PATCH 368/400] gcc is picky Conflicts: src/kernel/move_test.c --- src/kernel/move_test.c | 43 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/kernel/move_test.c b/src/kernel/move_test.c index 172012e4d..cea15292e 100644 --- a/src/kernel/move_test.c +++ b/src/kernel/move_test.c @@ -10,6 +10,49 @@ #include #include +static void test_ship_not_allowed_in_coast(CuTest * tc) +{ + region *r; + ship * sh; + terrain_type * ttype; + ship_type * stype; + const char * names[] = { "derp", "derp_p" }; + + test_cleanup(); + test_create_world(); + + ttype = test_create_terrain("glacier", LAND_REGION|ARCTIC_REGION|WALK_INTO|SAIL_INTO); + stype = test_create_shiptype(names); + stype->coasts = (const struct terrain_type **)calloc(2, sizeof(const struct terrain_type *)); + + r = test_create_region(0, 0, ttype); + sh = test_create_ship(0, stype); + + CuAssertIntEquals(tc, SA_NO_COAST, check_ship_allowed(sh, r)); + stype->coasts[0] = ttype; + CuAssertIntEquals(tc, SA_COAST, check_ship_allowed(sh, r)); +} + +static void test_ship_allowed_with_harbor(CuTest * tc) +{ + region *r; + ship * sh; + terrain_type * ttype; + building_type * btype; + + test_cleanup(); + test_create_world(); + + ttype = test_create_terrain("glacier", LAND_REGION|ARCTIC_REGION|WALK_INTO|SAIL_INTO); + btype = test_create_buildingtype("harbour"); + + r = test_create_region(0, 0, ttype); + sh = test_create_ship(0, 0); + + test_create_building(r, btype); + CuAssertIntEquals(tc, SA_HARBOUR, check_ship_allowed(sh, r)); +} + static void test_building_type_exists(CuTest * tc) { region *r; From d4bd2bc7f7f7e1101dff49a189e822ed1c311851 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 8 Jul 2012 11:37:19 -0700 Subject: [PATCH 369/400] remove DELIVER translate hunger in the NR --- res/de/strings.xml | 8 +++++--- src/gamecode/economy.c | 2 +- src/kernel/order.c | 5 ----- src/kernel/reports.c | 10 ++++++---- src/kernel/types.h | 1 - 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/res/de/strings.xml b/res/de/strings.xml index aea55a6a9..d7f7039f6 100644 --- a/res/de/strings.xml +++ b/res/de/strings.xml @@ -2200,9 +2200,6 @@ LERNEN - - LIEFERE - MACHEN @@ -6980,6 +6977,11 @@ guards the region + + hungert + hungry + + und and diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index 6668c3a21..859cdd079 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -1306,7 +1306,7 @@ void economics(region * r) ord = NULL; destroyed = true; } - } else if (kwd == K_GIVE || kwd == K_LIEFERE) { + } else if (kwd == K_GIVE) { give_cmd(u, ord); } else if (kwd == K_FORGET) { forget_cmd(u, ord); diff --git a/src/kernel/order.c b/src/kernel/order.c index 4457a5c6b..13cd7dc6d 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -260,10 +260,6 @@ static order *create_order_i(keyword_t kwd, const char *sptr, int persistent, case K_KOMMENTAR: case NOKEYWORD: return NULL; - case K_LIEFERE: - kwd = K_GIVE; - persistent = 1; - break; default: break; } @@ -575,7 +571,6 @@ bool is_persistent(const order * ord) return false; case K_KOMMENTAR: - case K_LIEFERE: return true; default: diff --git a/src/kernel/reports.c b/src/kernel/reports.c index 86995cb2d..54cdbb011 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -620,10 +620,12 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, WARN_STATIC_BUFFER(); } if (fval(u, UFL_HUNGER)) { - if (c) - bytes = (int)strlcpy(bufp, ", hungert", size); - else - bytes = (int)strlcpy(bufp, "hungert", size); + if (c) { + bytes = (int)strlcpy(bufp, ", ", size); + if (wrptr(&bufp, &size, bytes) != 0) + WARN_STATIC_BUFFER(); + } + bytes = (int)strlcpy(bufp, LOC(f->locale, "unit_hungers"), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); } diff --git a/src/kernel/types.h b/src/kernel/types.h index f6f1e4099..f023e435a 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -101,7 +101,6 @@ typedef enum { K_CONTACT, K_TEACH, K_STUDY, - K_LIEFERE, K_MAKE, K_MOVE, K_PASSWORD, From 7b0bdd568d6e8c2d915dcaf0139020484cee1fa5 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 8 Jul 2012 11:44:57 -0700 Subject: [PATCH 370/400] fix previous commit --- src/kernel/config.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/kernel/config.c b/src/kernel/config.c index 224923bf3..caf72d6cb 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -410,7 +410,6 @@ const char *keywords[MAXKEYWORDS] = { "KONTAKTIEREN", "LEHREN", "LERNEN", - "LIEFERE", "MACHEN", "NACH", "PASSWORT", From 9812a8dc3408db83b5e035fa48722bdc4a356d3d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 8 Jul 2012 15:40:37 -0700 Subject: [PATCH 371/400] translate spell modifiers --- res/de/strings.xml | 25 +++++++++++++ src/gamecode/report.c | 81 +++++++++++++++++++------------------------ 2 files changed, 61 insertions(+), 45 deletions(-) diff --git a/res/de/strings.xml b/res/de/strings.xml index d7f7039f6..c0f770f37 100644 --- a/res/de/strings.xml +++ b/res/de/strings.xml @@ -6982,6 +6982,31 @@ hungry + + Fernzauber + far + + + + Seezauber + sea + + + + Schiffszauber + ship + + + + Magier exklusiv + magicians only + + + + Keine + none + + und and diff --git a/src/gamecode/report.c b/src/gamecode/report.c index 898b06c20..ee4f24608 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -218,12 +218,26 @@ rparagraph(FILE * F, const char *str, ptrdiff_t indent, int hanging_indent, } while (*begin); } +static size_t write_spell_modifier(spell * sp, int flag, const char * str, bool cont, char * bufp, size_t size) { + if (sp->sptyp & flag) { + size_t bytes = 0; + if (cont) { + bytes = strlcpy(bufp, ", ", size); + } else { + bytes = strlcpy(bufp, " ", size); + } + bytes += strlcpy(bufp+bytes, str, size-bytes); + return bytes; + } + return 0; +} + static void nr_spell(FILE * F, spellbook_entry * sbe, const struct locale *lang) { int bytes, k, itemanz, costtyp; int dh = 0; char buf[4096]; - char *bufp = buf; + char *startp, *bufp = buf; size_t size = sizeof(buf) - 1; spell * sp = sbe->sp; const char *params = sp->parameter; @@ -297,52 +311,29 @@ static void nr_spell(FILE * F, spellbook_entry * sbe, const struct locale *lang) bytes = (int)strlcpy(buf, LOC(lang, "nr_spell_modifiers"), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - if (sp->sptyp & FARCASTING) { - bytes = (int)strlcpy(bufp, " Fernzauber", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - dh = 1; + + startp = bufp; + bytes = (int)write_spell_modifier(sp, FARCASTING, LOC(lang, "smod_far"), startp!=bufp, bufp, size); + if (bytes && wrptr(&bufp, &size, bytes) != 0) { + WARN_STATIC_BUFFER(); } - if (sp->sptyp & OCEANCASTABLE) { - if (dh == 1) { - bytes = (int)strlcpy(bufp, ",", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + bytes = (int)write_spell_modifier(sp, OCEANCASTABLE, LOC(lang, "smod_sea"), startp!=bufp, bufp, size); + if (bytes && wrptr(&bufp, &size, bytes) != 0) { + WARN_STATIC_BUFFER(); + } + bytes = (int)write_spell_modifier(sp, ONSHIPCAST, LOC(lang, "smod_ship"), startp!=bufp, bufp, size); + if (bytes && wrptr(&bufp, &size, bytes) != 0) { + WARN_STATIC_BUFFER(); + } + bytes = (int)write_spell_modifier(sp, NOTFAMILIARCAST, LOC(lang, "smod_nofamiliar"), startp!=bufp, bufp, size); + if (bytes && wrptr(&bufp, &size, bytes) != 0) { + WARN_STATIC_BUFFER(); + } + if (startp==bufp) { + bytes = (int)write_spell_modifier(sp, NOTFAMILIARCAST, LOC(lang, "smod_none"), startp!=bufp, bufp, size); + if (bytes && wrptr(&bufp, &size, bytes) != 0) { + WARN_STATIC_BUFFER(); } - bytes = (int)strlcpy(bufp, " Seezauber", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - dh = 1; - } - if (sp->sptyp & ONSHIPCAST) { - if (dh == 1) { - bytes = (int)strlcpy(bufp, ",", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - } - bytes = (int)strlcpy(bufp, " Schiffszauber", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - dh = 1; - } - if (sp->sptyp & NOTFAMILIARCAST) { - if (dh == 1) { - bytes = (int)strlcpy(bufp, ", k", size); - } else { - bytes = (int)strlcpy(bufp, " K", size); - } - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = - (int)strlcpy(bufp, "ann nicht vom Vertrauten gezaubert werden", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - dh = 1; - } - if (dh == 0) { - bytes = (int)strlcpy(bufp, " Keine", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); } *bufp = 0; rparagraph(F, buf, 0, 0, 0); From e7f0650e4caa6e9b0c086b90a4afdb3ac7589ccf Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 8 Jul 2012 15:59:27 -0700 Subject: [PATCH 372/400] translate diplomatic status in the NR --- res/de/strings.xml | 20 ++++++++++++++++++++ src/gamecode/report.c | 8 ++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/res/de/strings.xml b/res/de/strings.xml index c0f770f37..72292a714 100644 --- a/res/de/strings.xml +++ b/res/de/strings.xml @@ -7007,6 +7007,26 @@ none + + Wir helfen der Partei + We are helping the faction + + + + Wir helfen den Parteien + We are helping the factions + + + + hilft der Partei + is helping the faction + + + + hilft den Parteien + is helping the factions + + und and diff --git a/src/gamecode/report.c b/src/gamecode/report.c index ee4f24608..c5a7346eb 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -1727,9 +1727,9 @@ static void allies(FILE * F, const faction * f) int bytes; size_t size = sizeof(buf); if (!f->allies->next) { - bytes = (int)strlcpy(buf, "Wir helfen der Partei ", size); + bytes = snprintf(buf, size, "%s ", LOC(f->locale, "faction_help_one")); } else { - bytes = (int)strlcpy(buf, "Wir helfen den Parteien ", size); + bytes = snprintf(buf, size, "%s ", LOC(f->locale, "faction_help_many")); } size -= bytes; show_allies(f, f->allies, buf + bytes, size); @@ -1742,9 +1742,9 @@ static void allies(FILE * F, const faction * f) int bytes; size_t size = sizeof(buf); if (!g->allies->next) { - bytes = snprintf(buf, size, "%s hilft der Partei ", g->name); + bytes = snprintf(buf, size, "%s %s ", g->name, LOC(f->locale, "group_help_one")); } else { - bytes = snprintf(buf, size, "%s hilft den Parteien ", g->name); + bytes = snprintf(buf, size, "%s %s ", g->name, LOC(f->locale, "group_help_many")); } size -= bytes; show_allies(f, g->allies, buf + bytes, size); From 9af5f08a8a63e61ea48dd02ab8aff042774a08ca Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 8 Jul 2012 16:04:45 -0700 Subject: [PATCH 373/400] translate region visibility in NR --- res/de/strings.xml | 15 +++++++++++++++ src/gamecode/report.c | 6 +++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/res/de/strings.xml b/res/de/strings.xml index 72292a714..2feb93f2a 100644 --- a/res/de/strings.xml +++ b/res/de/strings.xml @@ -7027,6 +7027,21 @@ is helping the factions + + durchgereist + travel + + + + benachbart + neighbour + + + + vom Turm erblickt + from lighthouse + + und and diff --git a/src/gamecode/report.c b/src/gamecode/report.c index c5a7346eb..1570a76b9 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -940,11 +940,11 @@ static void describe(FILE * F, const seen_region * sr, faction * f) WARN_STATIC_BUFFER(); if (sr->mode == see_travel) { - bytes = (int)strlcpy(bufp, " (durchgereist)", size); + bytes = snprintf(buf, size, " (%s)", LOC(f->locale, "see_travel")); } else if (sr->mode == see_neighbour) { - bytes = (int)strlcpy(bufp, " (benachbart)", size); + bytes = snprintf(buf, size, " (%s)", LOC(f->locale, "see_neighbour")); } else if (sr->mode == see_lighthouse) { - bytes = (int)strlcpy(bufp, " (vom Turm erblickt)", size); + bytes = snprintf(buf, size, " (%s)", LOC(f->locale, "see_lighthouse")); } else { bytes = 0; } From e01a420aa8edb53a72a926d952f7846ad780dfa0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 8 Jul 2012 16:10:48 -0700 Subject: [PATCH 374/400] translate travel-through message --- res/de/strings.xml | 10 ++++++++++ src/gamecode/report.c | 10 +++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/res/de/strings.xml b/res/de/strings.xml index 2feb93f2a..3b7b88f43 100644 --- a/res/de/strings.xml +++ b/res/de/strings.xml @@ -7027,6 +7027,16 @@ is helping the factions + + hat die Region durchquert + has traveled through the region + + + + haben die Region durchquert + have traveled through the region + + durchgereist travel diff --git a/src/gamecode/report.c b/src/gamecode/report.c index 1570a76b9..3c773edc6 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -940,11 +940,11 @@ static void describe(FILE * F, const seen_region * sr, faction * f) WARN_STATIC_BUFFER(); if (sr->mode == see_travel) { - bytes = snprintf(buf, size, " (%s)", LOC(f->locale, "see_travel")); + bytes = snprintf(bufp, size, " (%s)", LOC(f->locale, "see_travel")); } else if (sr->mode == see_neighbour) { - bytes = snprintf(buf, size, " (%s)", LOC(f->locale, "see_neighbour")); + bytes = snprintf(bufp, size, " (%s)", LOC(f->locale, "see_neighbour")); } else if (sr->mode == see_lighthouse) { - bytes = snprintf(buf, size, " (%s)", LOC(f->locale, "see_lighthouse")); + bytes = snprintf(bufp, size, " (%s)", LOC(f->locale, "see_lighthouse")); } else { bytes = 0; } @@ -1432,9 +1432,9 @@ static void durchreisende(FILE * F, const region * r, const faction * f) } /* TODO: finish localization */ if (maxtravel == 1) { - bytes = (int)strlcpy(bufp, " hat die Region durchquert.", size); + bytes = snprintf(bufp, size, " %s", LOC(f->locale, "has_moved_one")); } else { - bytes = (int)strlcpy(bufp, " haben die Region durchquert.", size); + bytes = snprintf(bufp, size, " %s", LOC(f->locale, "has_moved_many")); } if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); From cb56a820b5607906d07f89b72409e79fc60a62ca Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 9 Jul 2012 01:25:09 +0200 Subject: [PATCH 375/400] fix gcc compilation fix broken test for duplicate orders --- scripts/tests/common.lua | 4 ++-- src/gamecode/report.c | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 34f46b169..1b21a0390 100755 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -980,8 +980,8 @@ function test_bug_1679() local file = io.open(filename, "w") file:write('ERESSEA ' .. itoa36(f.id) .. ' "' .. f.password .. '"\n') file:write('EINHEIT ' .. itoa36(u.id) .. "\n") - file:write("NACH W\n") file:write("ARBEITEN\n") + file:write("NACH W\n") file:close() eressea.read_orders(filename) @@ -989,7 +989,7 @@ function test_bug_1679() init_reports() write_report(f) assert_true(find_in_report(f, "Die Einheit kann keine weiteren langen Befehle", "cr")) - assert_true(find_in_report(f, "entdeckt, dass es keinen Weg nach Westen gibt")) + assert_false(find_in_report(f, "entdeckt, dass es keinen Weg nach Westen gibt")) end function test_building_unique0() diff --git a/src/gamecode/report.c b/src/gamecode/report.c index 898b06c20..1a253cadb 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -221,7 +221,6 @@ rparagraph(FILE * F, const char *str, ptrdiff_t indent, int hanging_indent, static void nr_spell(FILE * F, spellbook_entry * sbe, const struct locale *lang) { int bytes, k, itemanz, costtyp; - int dh = 0; char buf[4096]; char *bufp = buf; size_t size = sizeof(buf) - 1; From 366f0feeaa27d48dde66d85854902120f6296326 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 8 Jul 2012 19:15:06 -0700 Subject: [PATCH 376/400] need to mark ships for fishing even if not drifting (this code is bad) --- src/kernel/move.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kernel/move.c b/src/kernel/move.c index 8b3572f6d..3113a1c58 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -692,7 +692,7 @@ static float damage_drift(void) static void drifting_ships(region * r) { direction_t d; - if (get_param_int(global.parameters, "rules.ship.drifting", 1)==0) return; + bool drift = get_param_int(global.parameters, "rules.ship.drifting", 1)!=0; if (fval(r->terrain, SEA_REGION)) { ship **shp = &r->ships; @@ -709,7 +709,7 @@ static void drifting_ships(region * r) } /* Schiff schon abgetrieben oder durch Zauber geschützt? */ - if (fval(sh, SF_DRIFTED) || is_cursed(sh->attribs, C_SHIP_NODRIFT, 0)) { + if (!drift || fval(sh, SF_DRIFTED) || is_cursed(sh->attribs, C_SHIP_NODRIFT, 0)) { shp = &sh->next; continue; } From 3fda0ab14461adf6d13fa6727c7bb2b64193069b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 8 Jul 2012 23:15:22 -0700 Subject: [PATCH 377/400] added an option to disable storms from configuration files --- src/kernel/move.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/kernel/move.c b/src/kernel/move.c index 3113a1c58..46a1cadfd 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -1720,9 +1720,12 @@ sail(unit * u, order * ord, bool move_on_land, region_list ** routep) int reason; if (gamecookie != global.cookie) { - gamedate date; - get_gamedate(turn, &date); - stormyness = storms[date.month] * 5; + bool storms_enabled = get_param_int(global.parameters, "rules.ship.storms", 1)!=0; + if (storms_enabled) { + gamedate date; + get_gamedate(turn, &date); + stormyness = storms[date.month] * 5; + } gamecookie = global.cookie; } From 5abfaad5281c82686ade64dc181a7aade5380de1 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 9 Jul 2012 08:27:41 +0200 Subject: [PATCH 378/400] fixing intermittent tests --- scripts/tests/common.lua | 7 +++++++ src/gamecode/laws.c | 7 +++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 1b21a0390..3a7193ed0 100755 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -44,6 +44,7 @@ function setup() eressea.settings.set("nmr.timeout", "0") eressea.settings.set("NewbieImmunity", "0") eressea.settings.set("rules.economy.food", "4") + eressea.settings.set("rules.encounters", "0") end function test_fleeing_units_can_be_transported() @@ -885,6 +886,7 @@ function setup() eressea.free_game() eressea.write_game("free.dat") eressea.settings.set("rules.economy.food", "4") -- FOOD_IS_FREE + eressea.settings.set("rules.encounters", "0") end function test_parser() @@ -1132,7 +1134,12 @@ function test_bug_1875_use_help() assert_equal(0, u:get_item("peasantblood")) assert_equal(0, r:get_resource("peasant")) + assert_equal(0, r:get_resource("peasant")) assert_equal(0, u2:get_potion("peasantblood")) -- first unit helps this unit + if 98~=u:get_potion("peasantblood") then + print(get_turn(), f, u) + write_reports() + end assert_equal(98, u:get_potion("peasantblood")) -- unit uses one peasantblood effect end diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 80a819f5c..7c0fc460c 100755 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -4562,8 +4562,11 @@ void init_processor(void) p += 10; add_proc_order(p, K_GUARD, &guard_on_cmd, 0, "Bewache (an)"); - p += 10; - add_proc_global(p, &encounters, "Zufallsbegegnungen"); + if (get_param_int(global.parameters, "rules.encounters", 1)) { + p += 10; + add_proc_global(p, &encounters, "Zufallsbegegnungen"); + } + p += 10; add_proc_unit(p, &monster_kills_peasants, "Monster fressen und vertreiben Bauern"); From ea618453f70f85aed68868b7335298023f4064c4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 24 Jul 2012 00:16:25 -0700 Subject: [PATCH 379/400] bind more processing functions to Lua (almost done) --- scripts/tests/bindings.lua | 8 +++++++ scripts/tests/orders.lua | 28 +++++++++++++++++++++++ src/bindings/bind_process.c | 45 +++++++++++++++++++++++++++++++++++++ src/bindings/bind_process.h | 8 +++++++ src/bindings/process.pkg | 8 +++++++ src/gamecode/laws.c | 42 ++++++++++++++++++++++++++++++---- src/gamecode/laws.h | 8 ++++++- src/kernel/pool.c | 43 +++++------------------------------ src/kernel/pool.h | 6 +---- src/kernel/unit.h | 12 +++++----- 10 files changed, 156 insertions(+), 52 deletions(-) diff --git a/scripts/tests/bindings.lua b/scripts/tests/bindings.lua index b37606530..189d34769 100755 --- a/scripts/tests/bindings.lua +++ b/scripts/tests/bindings.lua @@ -45,6 +45,14 @@ function test_process() assert_equal("function", _G.type(eressea.process.regeneration)) assert_equal("function", _G.type(eressea.process.guard_on)) assert_equal("function", _G.type(eressea.process.guard_off)) + assert_equal("function", _G.type(eressea.process.explain)) + assert_equal("function", _G.type(eressea.process.messages)) + assert_equal("function", _G.type(eressea.process.reserve)) + assert_equal("function", _G.type(eressea.process.claim)) + assert_equal("function", _G.type(eressea.process.follow)) + assert_equal("function", _G.type(eressea.process.alliance)) + assert_equal("function", _G.type(eressea.process.idle)) + assert_equal("function", _G.type(eressea.process.set_default)) end function test_settings() diff --git a/scripts/tests/orders.lua b/scripts/tests/orders.lua index b46e0c1c7..e3d30cdfa 100755 --- a/scripts/tests/orders.lua +++ b/scripts/tests/orders.lua @@ -236,3 +236,31 @@ end function test_process_guard_off() eressea.process.guard_off() end + +function test_process_explain() + eressea.process.explain() +end + +function test_process_messages() + eressea.process.messages() +end + +function test_process_reserve() + eressea.process.reserve() +end + +function test_process_claim() + eressea.process.claim() +end + +function test_process_follow() + eressea.process.follow() +end + +function test_process_idle() + eressea.process.idle() +end + +function test_process_set_default() + eressea.process.set_default() +end diff --git a/src/bindings/bind_process.c b/src/bindings/bind_process.c index 926655e66..83420578b 100755 --- a/src/bindings/bind_process.c +++ b/src/bindings/bind_process.c @@ -2,6 +2,8 @@ #include #include +#include +#include #include #include #include @@ -215,6 +217,32 @@ void process_guard_on(void) { process_cmd(K_GUARD, guard_on_cmd, PROC_LAND_REGION); } +void process_explain(void) { + process_cmd(K_RESHOW, reshow_cmd, 0); +} + +void process_reserve(void) { + process_cmd(K_RESERVE, reserve_cmd, 0); +} + +void process_claim(void) { + process_cmd(K_CLAIM, claim_cmd, 0); +} + +void process_follow(void) { + struct region *r; + for (r = regions; r; r = r->next) { + unit * u; + for (u=r->units; u; u=u->next) { + follow_unit(u); + } + } +} + +void process_messages(void) { + process_cmd(K_MAIL, mail_cmd, 0); +} + void process_guard_off(void) { process_cmd(K_GUARD, guard_off_cmd, PROC_LAND_REGION); } @@ -247,3 +275,20 @@ void process_maintenance(void) { maintain_buildings(r, 0); } } + +void process_alliance(void) { + alliance_cmd(); +} + +void process_idle(void) { + region * r; + for (r=regions; r; r=r->next) { + auto_work(r); + } +} + +void process_set_default(void) { + if (!global.disabled[K_DEFAULT]) { + defaultorders(); + } +} diff --git a/src/bindings/bind_process.h b/src/bindings/bind_process.h index 4a9ebc147..767c7eb77 100755 --- a/src/bindings/bind_process.h +++ b/src/bindings/bind_process.h @@ -37,6 +37,14 @@ void process_give_control(void); void process_regeneration(void); void process_guard_on(void); void process_guard_off(void); +void process_explain(void); +void process_messages(void); +void process_reserve(void); +void process_claim(void); +void process_follow(void); +void process_alliance(void); +void process_idle(void); +void process_set_default(void); #ifdef __cplusplus } diff --git a/src/bindings/process.pkg b/src/bindings/process.pkg index bf6f4a83c..fb68e3a42 100755 --- a/src/bindings/process.pkg +++ b/src/bindings/process.pkg @@ -34,5 +34,13 @@ module eressea { void process_regeneration @ regeneration(void); /* regen health & aura */ void process_guard_on @ guard_on(void); /* GUARD */ void process_guard_off @ guard_off(void); /* GUARD NOT */ + void process_explain @ explain(void); /* SHOW */ + void process_messages @ messages(void); /* MESSAGE */ + void process_reserve @ reserve(void); /* RESERVE */ + void process_claim @ claim(void); /* CLAIM */ + void process_follow @ follow(void); /* FOLLOW */ + void process_alliance @ alliance(void); /* FOLLOW */ + void process_idle @ idle(void); /* work.auto */ + void process_set_default @ set_default(void); /* work.auto */ } } diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 82ebc4034..0229b9e45 100755 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -2166,7 +2166,7 @@ static void mailfaction(unit * u, int n, struct order *ord, const char *s) cmistake(u, ord, 66, MSG_MESSAGE); } -static int mail_cmd(unit * u, struct order *ord) +int mail_cmd(unit * u, struct order *ord) { region *r = u->region; unit *u2; @@ -2781,7 +2781,7 @@ int guard_off_cmd(unit * u, struct order *ord) return 0; } -static int reshow_cmd(unit * u, struct order *ord) +int reshow_cmd(unit * u, struct order *ord) { const char *s; param_t p = NOPARAM; @@ -3867,9 +3867,11 @@ static void remove_exclusive(order ** ordp) } } -static void defaultorders(void) +void defaultorders(void) { region *r; + + assert(!global.disabled[K_DEFAULT]); for (r = regions; r; r = r->next) { unit *u; for (u = r->units; u; u = u->next) { @@ -4054,7 +4056,39 @@ int pay_cmd(unit * u, struct order *ord) return 0; } -static int claim_cmd(unit * u, struct order *ord) + +int reserve_cmd(unit * u, struct order *ord) +{ + if (u->number > 0 && (urace(u)->ec_flags & GETITEM)) { + int use, count; + const resource_type *rtype; + const char *s; + + init_tokens(ord); + skip_token(); + s = getstrtoken(); + count = atoip((const char *)s); + + if (count == 0 && findparam(s, u->faction->locale) == P_EACH) { + count = getint() * u->number; + } + + rtype = findresourcetype(getstrtoken(), u->faction->locale); + if (rtype == NULL) + return 0; + + set_resvalue(u, rtype, 0); /* make sure the pool is empty */ + use = use_pooled(u, rtype, GET_DEFAULT, count); + if (use) { + set_resvalue(u, rtype, use); + change_resource(u, rtype, use); + return use; + } + } + return 0; +} + +int claim_cmd(unit * u, struct order *ord) { const char *t; int n; diff --git a/src/gamecode/laws.h b/src/gamecode/laws.h index 0d4cbd614..e0faf47f8 100755 --- a/src/gamecode/laws.h +++ b/src/gamecode/laws.h @@ -50,6 +50,7 @@ extern "C" { extern int enter_ship(struct unit *u, struct order *ord, int id, int report); extern void new_units(void); + extern void defaultorders(void); extern void quit(void); extern void monthly_healing(void); extern void renumber_factions(void); @@ -81,7 +82,12 @@ extern "C" { extern int contact_cmd(struct unit *u, struct order *ord); extern int guard_on_cmd(struct unit *u, struct order *ord); extern int guard_off_cmd(struct unit *u, struct order *ord); - + extern int reshow_cmd(struct unit *u, struct order *ord); + extern int mail_cmd(struct unit *u, struct order *ord); + extern int reserve_cmd(struct unit *u, struct order *ord); + extern int claim_cmd(struct unit *u, struct order *ord); + extern int follow_cmd(struct unit *u, struct order *ord); + #ifdef __cplusplus } #endif diff --git a/src/kernel/pool.c b/src/kernel/pool.c index b150f9f9f..f738bc0d6 100644 --- a/src/kernel/pool.c +++ b/src/kernel/pool.c @@ -96,7 +96,7 @@ int change_resource(unit * u, const resource_type * rtype, int change) int get_reservation(const unit * u, const resource_type * rtype) { - struct reservation *res = u->reservations; + reservation *res = u->reservations; if (rtype == oldresourcetype[R_STONE] && (u->race->flags & RCF_STONEGOLEM)) return (u->number * GOLEM_STONE); @@ -111,7 +111,7 @@ int get_reservation(const unit * u, const resource_type * rtype) int change_reservation(unit * u, const resource_type * rtype, int value) { - struct reservation *res, **rp = &u->reservations; + reservation *res, **rp = &u->reservations; if (!value) return 0; @@ -120,7 +120,7 @@ int change_reservation(unit * u, const resource_type * rtype, int value) rp = &(*rp)->next; res = *rp; if (!res) { - *rp = res = calloc(sizeof(struct reservation), 1); + *rp = res = calloc(sizeof(reservation), 1); res->type = rtype; res->value = value; } else if (res && res->value + value <= 0) { @@ -133,9 +133,9 @@ int change_reservation(unit * u, const resource_type * rtype, int value) return res->value; } -static int new_set_resvalue(unit * u, const resource_type * rtype, int value) +int set_resvalue(unit * u, const resource_type * rtype, int value) { - struct reservation *res, **rp = &u->reservations; + reservation *res, **rp = &u->reservations; while (*rp && (*rp)->type != rtype) rp = &(*rp)->next; @@ -143,7 +143,7 @@ static int new_set_resvalue(unit * u, const resource_type * rtype, int value) if (!res) { if (!value) return 0; - *rp = res = calloc(sizeof(struct reservation), 1); + *rp = res = calloc(sizeof(reservation), 1); res->type = rtype; res->value = value; } else if (res && value <= 0) { @@ -253,34 +253,3 @@ use_pooled(unit * u, const resource_type * rtype, unsigned int mode, int count) } return count - use; } - -int reserve_cmd(unit * u, struct order *ord) -{ - if (u->number > 0 && (urace(u)->ec_flags & GETITEM)) { - int use, count; - const resource_type *rtype; - const char *s; - - init_tokens(ord); - skip_token(); - s = getstrtoken(); - count = atoip((const char *)s); - - if (count == 0 && findparam(s, u->faction->locale) == P_EACH) { - count = getint() * u->number; - } - - rtype = findresourcetype(getstrtoken(), u->faction->locale); - if (rtype == NULL) - return 0; - - new_set_resvalue(u, rtype, 0); /* make sure the pool is empty */ - use = use_pooled(u, rtype, GET_DEFAULT, count); - if (use) { - new_set_resvalue(u, rtype, use); - change_resource(u, rtype, use); - return use; - } - } - return 0; -} diff --git a/src/kernel/pool.h b/src/kernel/pool.h index b6a5e6833..6de15bf3c 100644 --- a/src/kernel/pool.h +++ b/src/kernel/pool.h @@ -54,11 +54,7 @@ extern "C" { int change_reservation(struct unit *u, const struct resource_type *res, int value); - int reserve_cmd(struct unit *u, struct order *ord); - -/** init_pool - * initialisiert den regionalen Pool. - */ + int set_resvalue(struct unit * u, const struct resource_type * rtype, int value); #ifdef __cplusplus } diff --git a/src/kernel/unit.h b/src/kernel/unit.h index 7c9e3d8d3..f94a1d4ee 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -71,6 +71,12 @@ extern "C" { extern int maxheroes(const struct faction *f); extern int countheroes(const struct faction *f); + typedef struct reservation { + struct reservation *next; + const struct resource_type *type; + int value; + } reservation; + typedef struct unit { struct unit *next; /* needs to be first entry, for region's unitlist */ struct unit *nextF; /* nächste Einheit der Partei */ @@ -90,11 +96,7 @@ extern "C" { short skill_size; struct skill *skills; struct item *items; - struct reservation { - struct reservation *next; - const struct resource_type *type; - int value; - } *reservations; + reservation *reservations; /* orders */ struct order *orders; From b02f275582e460ef026441ac1b90af32b69cfd64 Mon Sep 17 00:00:00 2001 From: Steffen Mecke Date: Wed, 25 Jul 2012 22:35:30 +0200 Subject: [PATCH 380/400] fixed bug #1879: CAST should not prevent FOLLOW UNIT --- scripts/tests/common.lua | 18 ++++++++++++++++++ src/gamecode/laws.c | 2 +- src/kernel/magic.c | 16 +++++++++------- src/kernel/move.c | 3 ++- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 3a7193ed0..df7fd97ca 100755 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -1171,3 +1171,21 @@ function test_bug_1875_use_own_first() assert_equal(99, u:get_potion("peasantblood")) -- unit uses one peasantblood effect assert_equal(99, u2:get_potion("peasantblood")) -- u2 uses its own effect before u's end + + +function test_bug_1879_follow_unit() + local r = region.create(0, 0, "plain") + local r1 = region.create(1, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u1, u2 = two_units(r, f, f) + u1:clear_orders() + u1:set_skill("magic", 10) + u1:add_order("ZAUBERE STUFE 1 Kleine Flüche") + u1:add_order("FOLGEN EINHEIT " .. itoa36(u2.id)) + u2:clear_orders() + u2:add_order("NACH o") + process_orders() + assert_equal(u1.region.id, r1.id) + assert_equal(u2.region.id, r1.id) +end + diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index b79a59233..ac77a3c97 100755 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -3711,7 +3711,7 @@ void update_long_order(unit * u) case K_CAST: /* dient dazu, das neben Zaubern kein weiterer Befehl * ausgeführt werden kann, Zaubern ist ein kurzer Befehl */ - set_order(&u->thisorder, NULL); + set_order(&u->thisorder, copy_order(ord)); break; default: diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 3f388450b..f062549bf 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -2743,13 +2743,15 @@ void magic(void) continue; } - for (ord = u->orders; ord; ord = ord->next) { - if (get_keyword(ord) == K_CAST) { - castorder *co = cast_cmd(u, ord); - fset(u, UFL_LONGACTION | UFL_NOTMOVING); - if (co) { - const spell *sp = co->sp; - add_castorder(&spellranks[sp->rank], co); + if (u->thisorder != NULL) { + for (ord = u->orders; ord; ord = ord->next) { + if (get_keyword(ord) == K_CAST) { + castorder *co = cast_cmd(u, ord); + fset(u, UFL_LONGACTION | UFL_NOTMOVING); + if (co) { + const spell *sp = co->sp; + add_castorder(&spellranks[sp->rank], co); + } } } } diff --git a/src/kernel/move.c b/src/kernel/move.c index 46a1cadfd..9821e92b5 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -2697,12 +2697,13 @@ void follow_unit(unit * u) attrib *a2 = a_find(u2->attribs, &at_follow); if (a2 != NULL) { unit *u3 = a2->data.v; - follow = (u3 && u2->region == u2->region); + follow = (u3 && u2->region == u3->region); } } if (follow) { fset(u, UFL_FOLLOWING); fset(u2, UFL_FOLLOWED); + /* FOLLOW unit on a (potentially) moving unit prevents long orders */ set_order(&u->thisorder, NULL); } } From f286c5186224ae8e08448812be971b9eb1a85ea0 Mon Sep 17 00:00:00 2001 From: Steffen Mecke Date: Wed, 25 Jul 2012 22:45:15 +0200 Subject: [PATCH 381/400] test effect of mine (hunting bug #1926) test that laen is processed correctly --- scripts/tests/common.lua | 68 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index df7fd97ca..a069c7f0a 100755 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -568,6 +568,73 @@ function test_config() assert_not_equal(nil, config.locales) end +local function _test_create_laen() + local r = region.create(0,0, "mountain") + local f1 = faction.create("noreply@eressea.de", "human", "de") + local u1 = unit.create(f1, r, 1) + + -- TODO this is a stupid way to create a laen region + for i = 1, 10000 do + r = region.create(i,0, "mountain") + if r:get_resource("laen") > 2 then + break + end + end + assert(r:get_resource("laen")>2, "could not run test properly, please try again") + + return r, u1 +end + +function test_laen1() + local r, u1 = _test_create_laen() + + u1:add_item("money", 1000) + u1:set_skill("mining", 14) + u1:clear_orders() + u1:add_order("MACHEN Laen") + + process_orders() + assert_equal(0, u1:get_item("laen")) +end + +function test_laen2() + local r, u1 = _test_create_laen() + + u1:add_item("money", 1000) + u1:set_skill("mining", 15) + u1:clear_orders() + u1:add_order("MACHEN Laen") + + local b = building.create(r, "mine") + b.size = 10 + u1.building = b + local laen = r:get_resource("laen") + + process_orders() + assert_equal(2, u1:get_item("laen")) + assert_equal(laen - 2, r:get_resource("laen")) +end + +function test_mine() + local r = region.create(0,0, "mountain") + local f1 = faction.create("noreply@eressea.de", "human", "de") + local u1 = unit.create(f1, r, 1) + + u1:add_item("money", 1000) + u1:set_skill("mining", 1) + u1:clear_orders() + u1:add_order("MACHEN Eisen") + + local b = building.create(r, "mine") + b.size = 10 + u1.building = b + local iron = r:get_resource("iron") + + process_orders() + assert_equal(2, u1:get_item("iron")) -- skill +1 + assert_equal(iron - 1, r:get_resource("iron")) -- only 1/2 is taken away +end + function test_guard_resources() -- this is not quite http://bugs.eressea.de/view.php?id=1756 local r = region.create(0,0, "mountain") @@ -590,6 +657,7 @@ function test_guard_resources() process_orders() local iron = u2:get_item("iron") + assert_true(iron > 0) process_orders() assert_equal(iron, u2:get_item("iron")) end From 69a51c4b2cb6b875b67d322e4dac4069a6e834c7 Mon Sep 17 00:00:00 2001 From: Steffen Mecke Date: Wed, 25 Jul 2012 23:07:30 +0200 Subject: [PATCH 382/400] add message if implicit leave of building owner fails (see bug #1870) --- scripts/tests/common.lua | 42 ++++++++++++++++++++++++++++++++++++++++ src/gamecode/laws.c | 6 +++++- src/kernel/unit.c | 6 +++++- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index a069c7f0a..8e6d66c9f 100755 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -955,6 +955,7 @@ function setup() eressea.write_game("free.dat") eressea.settings.set("rules.economy.food", "4") -- FOOD_IS_FREE eressea.settings.set("rules.encounters", "0") + eressea.settings.set("rules.move.owner_leave", "0") end function test_parser() @@ -1257,3 +1258,44 @@ function test_bug_1879_follow_unit() assert_equal(u2.region.id, r1.id) end +function test_bug_1870_leave_enter_e2() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u1, u2 = two_units(r, f, f) + local mine = building.create(r, "mine") + mine.size = 10 + u1.building = mine + + local b = building.create(r, "castle") + b.size = 10 + u2.building = b + + u1:clear_orders() + u1:add_order("LERNEN Burgenbau ") + u1:add_order("BETRETEN BURG " .. itoa36(b.id)) + + eressea.settings.set("rules.move.owner_leave", "0") + process_orders() + assert_equal(u1.building.id, b.id) +end + +function test_bug_1870_leave_enter_e3() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u1, u2 = two_units(r, f, f) + local mine = building.create(r, "mine") + mine.size = 10 + u1.building = mine + + local b = building.create(r, "castle") + b.size = 10 + u2.building = b + + u1:clear_orders() + u1:add_order("LERNEN Burgenbau ") + u1:add_order("BETRETEN BURG " .. itoa36(b.id)) + + eressea.settings.set("rules.move.owner_leave", "1") + process_orders() + assert_equal(u1.building.id, mine.id) +end diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index ac77a3c97..cf43535d8 100755 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -1261,9 +1261,11 @@ int enter_ship(unit * u, struct order *ord, int id, int report) } } - if (leave(u, 0)) { + if (leave(u, false)) { u_set_ship(u, sh); fset(u, UFL_ENTER); + } else if (report) { + cmistake(u, ord, 150, MSG_MOVE); } return 1; } @@ -1310,6 +1312,8 @@ int enter_building(unit * u, order * ord, int id, int report) fset(u, UFL_ENTER); u_set_building(u, b); return 1; + } else if (report) { + cmistake(u, ord, 150, MSG_MOVE); } return 0; } diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 5aee29ab7..16901d34b 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -822,14 +822,18 @@ void leave_building(unit * u) bool can_leave(unit * u) { + static int gamecookie = -1; static int rule_leave = -1; if (!u->building) { return true; } - if (rule_leave < 0) { + + if (rule_leave < 0 || gamecookie != global.cookie) { + gamecookie = global.cookie; rule_leave = get_param_int(global.parameters, "rules.move.owner_leave", 0); } + if (rule_leave && u->building && u == building_owner(u->building)) { return false; } From 379e1a8f3f853299b64ae25a0b13c3ddf8151f84 Mon Sep 17 00:00:00 2001 From: Steffen Mecke Date: Thu, 26 Jul 2012 10:35:09 +0200 Subject: [PATCH 383/400] fix bug #1795: demon recruitment limit --- scripts/tests/common.lua | 35 +++++++++++++++++++++++++++++++++++ src/gamecode/economy.c | 24 +++++++++++++++++------- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 8e6d66c9f..e6b3b8f4a 100755 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -1299,3 +1299,38 @@ function test_bug_1870_leave_enter_e3() process_orders() assert_equal(u1.building.id, mine.id) end + +function test_bug_1795_limit() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "human", "de") + local u1 = one_unit(r,f) + u1:add_item("money", 100000000) + u1:add_order("REKRUTIEREN 9999") + r:set_resource("peasant", 2000) -- no fractional growth! + local peasants = r:get_resource("peasant") + local limit,frac = math.modf(peasants/40) -- one day this should be a parameter + local growth = peasants * 0.001 + + process_orders() + + assert_equal(limit+1, u1.number, u1.number .. "!=" .. (limit+1)) + assert_equal(peasants+growth-limit, r:get_resource("peasant")) +end + +function test_bug_1795_demons() + local r = region.create(0, 0, "plain") + local f = faction.create("noreply@eressea.de", "demon", "de") + local u1 = one_unit(r,f) + r:set_resource("peasant", 2000) + local peasants = r:get_resource("peasant") + local limit,frac = math.modf(peasants/40) + local growth = peasants * 0.001 + + u1:add_item("money", 100000000) + u1:add_order("REKRUTIEREN 9999") + + process_orders() + + assert_equal(limit+1, u1.number, u1.number .. "!=" .. (limit+1)) + assert_equal(peasants+growth, r:get_resource("peasant")) +end diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index 859cdd079..10de6365d 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -215,6 +215,9 @@ typedef struct recruitment { int total, assigned; } recruitment; +/** Creates a list of recruitment structs, one for each faction. Adds every quantifyable request + * to the faction's struct and to total. + */ static recruitment *select_recruitment(request ** rop, int (*quantify) (const struct race *, int), int *total) { @@ -292,14 +295,14 @@ static int any_recruiters(const struct race *rc, int qty) return (int)(qty * 2 * rc->recruit_multi); } -static int peasant_recruiters(const struct race *rc, int qty) +/*static int peasant_recruiters(const struct race *rc, int qty) { if (rc->ec_flags & ECF_REC_ETHEREAL) return -1; if (rc->ec_flags & ECF_REC_HORSES) return -1; return (int)(qty * 2 * rc->recruit_multi); -} +}*/ static int horse_recruiters(const struct race *rc, int qty) { @@ -315,10 +318,12 @@ static int do_recruiting(recruitment * recruits, int available) recruitment *rec; int recruited = 0; + /* try to assign recruits to factions fairly */ while (available > 0) { int n = 0; int rest, mintotal = INT_MAX; + /* find smallest request */ for (rec = recruits; rec != NULL; rec = rec->next) { int want = rec->total - rec->assigned; if (want > 0) { @@ -334,6 +339,8 @@ static int do_recruiting(recruitment * recruits, int available) } rest = available - mintotal * n; + /* assign size of smallest request for everyone if possible; in the end roll dice to assign + * small rest */ for (rec = recruits; rec != NULL; rec = rec->next) { int want = rec->total - rec->assigned; @@ -350,6 +357,7 @@ static int do_recruiting(recruitment * recruits, int available) } } + /* do actual recruiting */ for (rec = recruits; rec != NULL; rec = rec->next) { request *req; int get = rec->assigned; @@ -365,8 +373,6 @@ static int do_recruiting(recruitment * recruits, int available) int afford = get_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, number * rc->recruitcost) / rc->recruitcost; number = MIN(number, afford); - use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, - rc->recruitcost * number); } if (u->number + number > UNIT_MAXSIZE) { ADDMSG(&u->faction->msgs, msg_feedback(u, req->ord, "error_unit_size", @@ -374,6 +380,10 @@ static int do_recruiting(recruitment * recruits, int available) number = UNIT_MAXSIZE - u->number; assert(number >= 0); } + if (rc->recruitcost) { + use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, + rc->recruitcost * number); + } add_recruits(u, number, req->qty); dec = (int)(number * multi); if ((rc->ec_flags & ECF_REC_ETHEREAL) == 0) { @@ -449,7 +459,7 @@ static void expandrecruit(region * r, request * recruitorders) } /* peasant limited: */ - recruits = select_recruitment(&recruitorders, peasant_recruiters, &orc_total); + recruits = select_recruitment(&recruitorders, any_recruiters, &orc_total); if (recruits) { int orc_recruited, orc_peasants = rpeasants(r) * 2; int orc_frac = orc_peasants / RECRUITFRACTION; /* anzahl orks. 2 ork = 1 bauer */ @@ -464,10 +474,10 @@ static void expandrecruit(region * r, request * recruitorders) /* no limit: */ recruits = select_recruitment(&recruitorders, any_recruiters, &orc_total); if (recruits) { - int recruited, peasants = rpeasants(r); + int recruited, peasants = rpeasants(r) * 2; recruited = do_recruiting(recruits, INT_MAX); if (recruited > 0) { - rsetpeasants(r, peasants - recruited / 2); + rsetpeasants(r, (peasants - recruited) / 2); } free_recruitments(recruits); } From dbc09d35ace029569c33413397cb6c180dad9bd7 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 29 Jul 2012 00:35:17 +0200 Subject: [PATCH 384/400] fix a crash caused by an old curse --- src/kernel/curse.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 4a7403e69..3b0d7c3e2 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -438,7 +438,10 @@ double curse_geteffect(const curse * c) int curse_geteffect_int(const curse * c) { double effect = curse_geteffect(c); - assert(effect - (int)effect == 0); + if (effect - (int)effect != 0) { + log_error("curse has an integer attribute with float value: '%s' = %lf", + c->type->cname, effect); + } return (int)effect; } From d056f6049e95a1ce459f748e1e22aea7a59edf08 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 2 Aug 2012 08:08:39 +0200 Subject: [PATCH 385/400] fix an intermittently segfaulting test --- src/kernel/region.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/region.c b/src/kernel/region.c index c2d5e6587..491efa290 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -1604,7 +1604,7 @@ int owner_change(const region * r) if (r->land && r->land->ownership) { return r->land->ownership->since_turn; } - return -1; + return INT_MIN; } bool is_mourning(const region * r, int in_turn) From 65e5a8250466f1792468006d87aedfd474b19560 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 1 Aug 2012 23:12:23 -0700 Subject: [PATCH 386/400] we can now compare regions, do not need to compare ids --- scripts/tests/common.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index e6b3b8f4a..84d614b1b 100755 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -329,7 +329,7 @@ function test_guard() u2:add_item("money", 100) u3:add_item("money", 100) process_orders() - assert_equal(r.id, u1.region.id, "unit may not move after combat") + assert_equal(r, u1.region, "unit may not move after combat") end function test_recruit() From 166d4ccc2cc187b15bcd40f7449fbfc98162f7af Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 1 Aug 2012 23:20:59 -0700 Subject: [PATCH 387/400] make the fighter in this test not die --- scripts/tests/common.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 84d614b1b..287736c66 100755 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -309,12 +309,13 @@ function test_guard() local r = region.create(0, 0, "plain") local f1 = faction.create("noreply@eressea.de", "human", "de") f1.age = 20 - local u1 = unit.create(f1, r, 1) + local u1 = unit.create(f1, r, 10) u1:add_item("sword", 10) u1:add_item("money", 10) u1:set_skill("melee", 10) u1:clear_orders() u1:add_order("NACH O") + u1.name="Kalle Pimp" local f2 = faction.create("noreply@eressea.de", "human", "de") f2.age = 20 From 1fe075e82d4f84c4e198389b4e85304e10557570 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 2 Aug 2012 00:06:03 -0700 Subject: [PATCH 388/400] laen test does not work. trying to make setresource add the raw material to fix it --- scripts/tests/common.lua | 21 ++++++--------------- src/kernel/region.c | 10 ++++++++++ 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 287736c66..f8f546e05 100755 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -570,20 +570,11 @@ function test_config() end local function _test_create_laen() - local r = region.create(0,0, "mountain") - local f1 = faction.create("noreply@eressea.de", "human", "de") - local u1 = unit.create(f1, r, 1) - - -- TODO this is a stupid way to create a laen region - for i = 1, 10000 do - r = region.create(i,0, "mountain") - if r:get_resource("laen") > 2 then - break - end - end - assert(r:get_resource("laen")>2, "could not run test properly, please try again") - - return r, u1 + local r = region.create(0,0, "mountain") + local f1 = faction.create("noreply@eressea.de", "human", "de") + local u1 = unit.create(f1, r, 1) + r:set_resource("laen", 3) + return r, u1 end function test_laen1() @@ -611,7 +602,7 @@ function test_laen2() u1.building = b local laen = r:get_resource("laen") - process_orders() + process_orders() assert_equal(2, u1:get_item("laen")) assert_equal(laen - 2, r:get_resource("laen")) end diff --git a/src/kernel/region.c b/src/kernel/region.c index 491efa290..e22e5ef62 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -1016,6 +1016,16 @@ void region_setresource(region * r, const resource_type * rtype, int value) rsetpeasants(r, value); else if (rtype == rt_find("horse")) rsethorses(r, value); + else { + int i; + for (i = 0; r->terrain->production[i].type; ++i) { + const terrain_production *production = r->terrain->production + i; + if (production->type==rtype) { + add_resource(r, 1, value, dice_rand(production->divisor), rtype); + break; + } + } + } } } From cde0ce07424e19db30c2d61ce6356cf58fa12ba8 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 3 Aug 2012 00:41:17 -0700 Subject: [PATCH 389/400] fix broken laen tests by hacking in another config setting --- scripts/tests/common.lua | 12 ++++++++---- src/kernel/resources.c | 11 ++++++++--- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index f8f546e05..0521e66e4 100755 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -570,10 +570,11 @@ function test_config() end local function _test_create_laen() + eressea.settings.set("rules.terraform.all", "1") local r = region.create(0,0, "mountain") local f1 = faction.create("noreply@eressea.de", "human", "de") local u1 = unit.create(f1, r, 1) - r:set_resource("laen", 3) + r:set_resource("laen", 50) return r, u1 end @@ -596,15 +597,18 @@ function test_laen2() u1:set_skill("mining", 15) u1:clear_orders() u1:add_order("MACHEN Laen") - + u1.name = "Laenmeister" + local b = building.create(r, "mine") b.size = 10 u1.building = b local laen = r:get_resource("laen") - process_orders() - assert_equal(2, u1:get_item("laen")) + process_orders() + init_reports() + write_report(u1.faction) assert_equal(laen - 2, r:get_resource("laen")) + assert_equal(2, u1:get_item("laen")) end function test_mine() diff --git a/src/kernel/resources.c b/src/kernel/resources.c index 4a3607d7b..5f3c14757 100644 --- a/src/kernel/resources.c +++ b/src/kernel/resources.c @@ -82,6 +82,10 @@ void terraform_resources(region * r) { int i; const terrain_type *terrain = r->terrain; + static int terraform_all = -1; + if (terraform_all<0) { + terraform_all = get_param_int(global.parameters, "rules.terraform.all", 0); + } if (terrain->production == NULL) return; @@ -94,10 +98,11 @@ void terraform_resources(region * r) if (rm->type->rtype == rtype) break; } - if (rm) + if (rm) { continue; - - if (chance(production->chance)) { + } + + if (terraform_all || chance(production->chance)) { add_resource(r, dice_rand(production->startlevel), dice_rand(production->base), dice_rand(production->divisor), production->type); From 5e58f3a881737f625c45e2cf0979ae4db431d752 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 21 Oct 2012 18:37:51 -0700 Subject: [PATCH 390/400] start adding test coverage for res_changeitem --- src/kernel/item.c | 4 ++++ src/kernel/item_test.c | 25 +++++++++++++++++++++++++ src/tests.c | 8 ++++---- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/kernel/item.c b/src/kernel/item.c index fd35f0776..2fd76ded3 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -1226,6 +1226,10 @@ void test_clear_resources(void) void register_resources(void) { + static bool registered = false; + if (registered) return; + registered = true; + register_function((pf_generic) mod_elves_only, "mod_elves_only"); register_function((pf_generic) mod_dwarves_only, "mod_dwarves_only"); register_function((pf_generic) res_changeitem, "changeitem"); diff --git a/src/kernel/item_test.c b/src/kernel/item_test.c index c59e47d33..6279bc0af 100644 --- a/src/kernel/item_test.c +++ b/src/kernel/item_test.c @@ -2,11 +2,35 @@ #include #include +#include #include +#include #include #include +void test_change_item(CuTest * tc) +{ + rtype_uchange res_changeitem; + const resource_type * rtype; + unit * u; + + register_resources(); + res_changeitem = (rtype_uchange)get_function("changeitem"); + CuAssertPtrNotNull(tc, res_changeitem); + + test_cleanup(); + test_create_world(); + rtype = olditemtype[I_IRON]->rtype; + + u = test_create_unit(0, 0); + CuAssertIntEquals(tc, 0, res_changeitem(u, rtype, 0)); + i_change(&u->items, rtype->itype, 4); + CuAssertIntEquals(tc, 4, res_changeitem(u, rtype, 0)); + CuAssertIntEquals(tc, 1, res_changeitem(u, rtype, -3)); + CuAssertIntEquals(tc, 1, i_get(u->items, rtype->itype)); +} + void test_resource_type(CuTest * tc) { struct item_type *itype; @@ -68,6 +92,7 @@ void test_findresourcetype(CuTest * tc) CuSuite *get_item_suite(void) { CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_change_item); SUITE_ADD_TEST(suite, test_resource_type); SUITE_ADD_TEST(suite, test_finditemtype); SUITE_ADD_TEST(suite, test_findresourcetype); diff --git a/src/tests.c b/src/tests.c index dd05c7d93..568e65ac4 100644 --- a/src/tests.c +++ b/src/tests.c @@ -180,15 +180,15 @@ void test_create_world(void) terrain_type *t_plain, *t_ocean; region *island[2]; int i; - item_type * itype; - const char * names[] = { "horse", "horse_p", "boat", "boat_p" }; + const char * names[] = { "horse", "horse_p", "boat", "boat_p", "iron", "iron_p", "stone", "stone_p" }; make_locale("de"); init_resources(); assert(!olditemtype[I_HORSE]); - itype = test_create_itemtype(names); - olditemtype[I_HORSE] = itype; + olditemtype[I_HORSE] = test_create_itemtype(names+0); + olditemtype[I_IRON] = test_create_itemtype(names+4); + olditemtype[I_STONE] = test_create_itemtype(names+6); t_plain = test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION); t_plain->size = 1000; From 79feb5723c075a45a1a94ed286c87993314ce8da Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 21 Oct 2012 19:42:59 -0700 Subject: [PATCH 391/400] also test changing persons --- src/kernel/item.c | 6 +++++- src/kernel/item_test.c | 42 ++++++++++++++++++++++++++++++------------ 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/kernel/item.c b/src/kernel/item.c index 2fd76ded3..db1da94ad 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -73,7 +73,11 @@ static int res_changeaura(unit * u, const resource_type * rtype, int delta) static int res_changeperson(unit * u, const resource_type * rtype, int delta) { assert(rtype != NULL || !"not implemented"); - scale_number(u, u->number + delta); + if (u->number + delta >=0) { + scale_number(u, u->number + delta); + } else { + scale_number(u, 0); + } return u->number; } diff --git a/src/kernel/item_test.c b/src/kernel/item_test.c index 6279bc0af..c9a144ede 100644 --- a/src/kernel/item_test.c +++ b/src/kernel/item_test.c @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -9,26 +10,42 @@ #include #include +static void test_uchange(CuTest * tc, unit * u, const resource_type * rtype) { + int n; + change_resource(u, rtype, 4); + n = get_resource(u, rtype); + CuAssertPtrNotNull(tc, rtype->uchange); + CuAssertIntEquals(tc, n, rtype->uchange(u, rtype, 0)); + CuAssertIntEquals(tc, n-3, rtype->uchange(u, rtype, -3)); + CuAssertIntEquals(tc, n-3, get_resource(u, rtype)); + CuAssertIntEquals(tc, 0, rtype->uchange(u, rtype, -n)); +} + void test_change_item(CuTest * tc) { - rtype_uchange res_changeitem; - const resource_type * rtype; unit * u; - register_resources(); - res_changeitem = (rtype_uchange)get_function("changeitem"); - CuAssertPtrNotNull(tc, res_changeitem); - test_cleanup(); + register_resources(); + init_resources(); test_create_world(); - rtype = olditemtype[I_IRON]->rtype; u = test_create_unit(0, 0); - CuAssertIntEquals(tc, 0, res_changeitem(u, rtype, 0)); - i_change(&u->items, rtype->itype, 4); - CuAssertIntEquals(tc, 4, res_changeitem(u, rtype, 0)); - CuAssertIntEquals(tc, 1, res_changeitem(u, rtype, -3)); - CuAssertIntEquals(tc, 1, i_get(u->items, rtype->itype)); + test_uchange(tc, u, olditemtype[I_IRON]->rtype); +} + +void test_change_person(CuTest * tc) +{ + unit * u; + + test_cleanup(); + + register_resources(); + init_resources(); + test_create_world(); + + u = test_create_unit(0, 0); + test_uchange(tc, u, r_unit); } void test_resource_type(CuTest * tc) @@ -93,6 +110,7 @@ CuSuite *get_item_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_change_item); + SUITE_ADD_TEST(suite, test_change_person); SUITE_ADD_TEST(suite, test_resource_type); SUITE_ADD_TEST(suite, test_finditemtype); SUITE_ADD_TEST(suite, test_findresourcetype); From 841876e3359e49d059704ee7b5aa7a138447f871 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 23 Feb 2013 17:23:47 -0800 Subject: [PATCH 392/400] bind faction.flags to Lua --- scripts/tests/common.lua | 7 +++++++ src/bindings/bind_faction.c | 10 +++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/scripts/tests/common.lua b/scripts/tests/common.lua index 0521e66e4..88dae3080 100755 --- a/scripts/tests/common.lua +++ b/scripts/tests/common.lua @@ -1330,3 +1330,10 @@ function test_bug_1795_demons() assert_equal(limit+1, u1.number, u1.number .. "!=" .. (limit+1)) assert_equal(peasants+growth, r:get_resource("peasant")) end + +function test_faction_flags() + f = faction.create("noreply@eressea.de", "human", "de") + assert_equal(0, f.flags) + f.flags = 42 + assert_equal(42, f.flags) +end diff --git a/src/bindings/bind_faction.c b/src/bindings/bind_faction.c index d5efd226c..775cb5ab8 100644 --- a/src/bindings/bind_faction.c +++ b/src/bindings/bind_faction.c @@ -160,6 +160,14 @@ static int tolua_faction_get_flags(lua_State * L) return 1; } +static int tolua_faction_set_flags(lua_State * L) +{ + faction *self = (faction *) tolua_tousertype(L, 1, 0); + int flags = (int)tolua_tonumber(L, 2, self->flags); + self->flags = flags; + return 1; +} + static int tolua_faction_get_options(lua_State * L) { faction *self = (faction *) tolua_tousertype(L, 1, 0); @@ -525,7 +533,7 @@ void tolua_faction_open(lua_State * L) tolua_faction_set_age); tolua_variable(L, TOLUA_CAST "options", tolua_faction_get_options, tolua_faction_set_options); - tolua_variable(L, TOLUA_CAST "flags", tolua_faction_get_flags, NULL); + tolua_variable(L, TOLUA_CAST "flags", tolua_faction_get_flags, tolua_faction_set_flags); tolua_variable(L, TOLUA_CAST "lastturn", tolua_faction_get_lastturn, tolua_faction_set_lastturn); From ed4c4aa3633f3587deb14c781405a48c7599d62b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 28 Apr 2013 03:13:40 +0200 Subject: [PATCH 393/400] Some crashes and other minor stuff. Just things that Eressea has changed in the past 2 months --- res/de/strings.xml | 1 + src/items/weapons.c | 5 +++-- src/kernel/reports.c | 2 +- src/util/translation.c | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/res/de/strings.xml b/res/de/strings.xml index 3b7b88f43..bb16c92fe 100644 --- a/res/de/strings.xml +++ b/res/de/strings.xml @@ -7290,6 +7290,7 @@ Es ist Spätherbst, und diese Woche ist die letzte vor dem Winter, in der Insekten rekrutieren können. + It is the last week before winter in which insects can still recruit. diff --git a/src/items/weapons.c b/src/items/weapons.c index 7b817510a..9eb3d8d72 100644 --- a/src/items/weapons.c +++ b/src/items/weapons.c @@ -72,9 +72,10 @@ attack_firesword(const troop * at, const struct weapon_type *wtype, do { dt = select_enemy(fi, 0, 1, SELECT_ADVANCE | SELECT_DISTANCE); - assert(dt.fighter); --force; - killed += terminate(dt, *at, AT_SPELL, damage, 1); + if (dt.fighter) { + killed += terminate(dt, *at, AT_SPELL, damage, 1); + } } while (force && killed < enemies); if (casualties) *casualties = killed; diff --git a/src/kernel/reports.c b/src/kernel/reports.c index 54cdbb011..78292451e 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -1788,7 +1788,7 @@ int reports(void) static variant var_copy_string(variant x) { - x.v = strdup((const char *)x.v); + x.v = x.v?strdup((const char *)x.v):0; return x; } diff --git a/src/util/translation.c b/src/util/translation.c index e3493f434..a96f0914f 100644 --- a/src/util/translation.c +++ b/src/util/translation.c @@ -283,7 +283,7 @@ static const char *parse_string(opstack ** stack, const char *in, if (ic == NULL) return NULL; c = (char *)opop_v(stack); - bytes = (int)strlcpy(oc, c, size); + bytes = (int)c?strlcpy(oc, c, size):0; if (bytes < (int)size) oc += bytes; else From cd4628421ad5b770257d6fdbdf44f4727218aedd Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 2 May 2013 03:42:20 +0200 Subject: [PATCH 394/400] u_race and u_setrace getter/setter moving towards making unit::race private --- src/bindings/bind_unit.c | 6 +- src/bindings/helpers.c | 4 +- src/gamecode/creport.c | 10 +-- src/gamecode/economy.c | 106 +++++++++++++++--------------- src/gamecode/give.c | 14 ++-- src/gamecode/laws.c | 62 +++++++++--------- src/gamecode/monster.c | 14 ++-- src/gamecode/randenc.c | 42 ++++++------ src/gamecode/report.c | 8 +-- src/gamecode/spy.c | 16 ++--- src/gamecode/study.c | 22 +++---- src/gamecode/summary.c | 2 +- src/items/phoenixcompass.c | 2 +- src/kernel/battle.c | 130 ++++++++++++++++++------------------- src/kernel/build.c | 6 +- src/kernel/config.c | 40 ++++++------ src/kernel/config.h | 2 +- src/kernel/faction.c | 6 +- src/kernel/item.c | 16 ++--- src/kernel/magic.c | 26 ++++---- src/kernel/move.c | 46 ++++++------- src/kernel/names.c | 4 +- src/kernel/pool.c | 12 ++-- src/kernel/reports.c | 20 +++--- src/kernel/save.c | 22 +++---- src/kernel/ship.c | 2 +- src/kernel/unit.c | 61 ++++++++++------- src/kernel/unit.h | 2 + src/modules/score.c | 8 +-- src/triggers/changerace.c | 4 +- 30 files changed, 364 insertions(+), 351 deletions(-) diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 5d4dd9b47..e19684bdc 100755 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -839,7 +839,7 @@ static int tolua_unit_set_faction(lua_State * L) static int tolua_unit_get_race(lua_State * L) { unit *self = (unit *) tolua_tousertype(L, 1, 0); - tolua_pushstring(L, self->race->_name[0]); + tolua_pushstring(L, u_race(self)->_name[0]); return 1; } @@ -851,9 +851,9 @@ static int tolua_unit_set_race(lua_State * L) if (rc != NULL) { if (count_unit(self)) --self->faction->no_units; - if (self->irace == self->race) + if (self->irace == u_race(self)) self->irace = NULL; - self->race = rc; + u_setrace(self, rc); if (count_unit(self)) --self->faction->no_units; } diff --git a/src/bindings/helpers.c b/src/bindings/helpers.c index 5658f590c..96407ca07 100644 --- a/src/bindings/helpers.c +++ b/src/bindings/helpers.c @@ -247,7 +247,7 @@ static int lua_initfamiliar(unit * u) int result = -1; strlcpy(fname, "initfamiliar_", sizeof(fname)); - strlcat(fname, u->race->_name[0], sizeof(fname)); + strlcat(fname, u_race(u)->_name[0], sizeof(fname)); lua_getglobal(L, fname); if (lua_isfunction(L, -1)) { @@ -268,7 +268,7 @@ static int lua_initfamiliar(unit * u) create_mage(u, M_GRAY); - strlcpy(fname, u->race->_name[0], sizeof(fname)); + strlcpy(fname, u_race(u)->_name[0], sizeof(fname)); strlcat(fname, "_familiar", sizeof(fname)); equip_unit(u, get_equipment(fname)); return result; diff --git a/src/gamecode/creport.c b/src/gamecode/creport.c index 90374cb4b..b7fe57358 100644 --- a/src/gamecode/creport.c +++ b/src/gamecode/creport.c @@ -696,7 +696,7 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, static bool init = false; item result[MAX_INVENTORY]; - if (fval(u->race, RCF_INVISIBLE)) + if (fval(u_race(u), RCF_INVISIBLE)) return; if (!init) { @@ -785,8 +785,8 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, pzTmp = get_racename(u->attribs); if (pzTmp) { fprintf(F, "\"%s\";Typ\n", pzTmp); - if (u->faction == f && fval(u->race, RCF_SHAPESHIFTANY)) { - const char *zRace = rc_name(u->race, 1); + if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) { + const char *zRace = rc_name(u_race(u), 1); fprintf(F, "\"%s\";wahrerTyp\n", add_translation(zRace, locale_string(f->locale, zRace))); } @@ -795,10 +795,10 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, const char *zRace = rc_name(irace, 1); fprintf(F, "\"%s\";Typ\n", add_translation(zRace, locale_string(f->locale, zRace))); - if (u->faction == f && irace != u->race) { + if (u->faction == f && irace != u_race(u)) { assert(skill_enabled[SK_STEALTH] || !"we're resetting this on load, so.. ircase should never be used"); - zRace = rc_name(u->race, 1); + zRace = rc_name(u_race(u), 1); fprintf(F, "\"%s\";wahrerTyp\n", add_translation(zRace, locale_string(f->locale, zRace))); } diff --git a/src/gamecode/economy.c b/src/gamecode/economy.c index 859cdd079..cbbde59af 100644 --- a/src/gamecode/economy.c +++ b/src/gamecode/economy.c @@ -126,7 +126,7 @@ static void recruit_init(void) int income(const unit * u) { - switch (old_race(u->race)) { + switch (old_race(u_race(u))) { case RC_FIREDRAGON: return 150 * u->number; case RC_DRAGON: @@ -224,7 +224,7 @@ static recruitment *select_recruitment(request ** rop, recruitment *rec = recruits; request *ro = *rop; unit *u = ro->unit; - const race *rc = u->race; + const race *rc = u_race(u); int qty = quantify(rc, ro->qty); if (qty < 0) { @@ -264,15 +264,15 @@ static void add_recruits(unit * u, int number, int wanted) u->hp = number * unit_max_hp(u); unew = u; } else { - unew = create_unit(r, u->faction, number, u->race, 0, NULL, u); + unew = create_unit(r, u->faction, number, u_race(u), 0, NULL, u); } strlcpy(equipment, "new_", sizeof(equipment)); - strlcat(equipment, u->race->_name[0], sizeof(equipment)); + strlcat(equipment, u_race(u)->_name[0], sizeof(equipment)); strlcat(equipment, "_unit", sizeof(equipment)); equip_unit(unew, get_equipment(equipment)); - if (unew->race->ec_flags & ECF_REC_HORSES) { + if (u_race(unew)->ec_flags & ECF_REC_HORSES) { change_level(unew, SK_RIDING, 1); } @@ -356,7 +356,7 @@ static int do_recruiting(recruitment * recruits, int available) for (req = rec->requests; req; req = req->next) { unit *u = req->unit; - const race *rc = u->race; /* race is set in recruit() */ + const race *rc = u_race(u); /* race is set in recruit() */ int number, dec; float multi = 2.0F * rc->recruit_multi; @@ -494,7 +494,7 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders) request *o; int recruitcost = -1; const faction *f = u->faction; - const struct race *rc = u->race; + const struct race *rc = u_race(u); const char *str; init_tokens(ord); @@ -513,14 +513,14 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders) } } if (recruitcost < 0) { - rc = u->race; + rc = u_race(u); recruitcost = recruit_cost(f, rc); if (recruitcost < 0) { recruitcost = INT_MAX; } } assert(rc); - u->race = rc; + u_setrace(u, rc); #if GUARD_DISABLES_RECRUIT /* this is a very special case because the recruiting unit may be empty @@ -757,7 +757,7 @@ static void give_cmd(unit * u, order * ord) return; } - if (u2 && u2->race == new_race[RC_SPELL]) { + if (u2 && u_race(u2) == new_race[RC_SPELL]) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); return; @@ -770,18 +770,18 @@ static void give_cmd(unit * u, order * ord) else if (p == P_HERBS) { bool given = false; - if (!(u->race->ec_flags & GIVEITEM) && u2 != NULL) { + if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) { ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_nogive", "race", u->race)); + msg_feedback(u, ord, "race_nogive", "race", u_race(u))); return; } if (!check_give(u, u2, NULL, GIVE_HERBS)) { feedback_give_not_allowed(u, ord); return; } - if (u2 && !(u2->race->ec_flags & GETITEM)) { + if (u2 && !(u_race(u2)->ec_flags & GETITEM)) { ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_notake", "race", u2->race)); + msg_feedback(u, ord, "race_notake", "race", u_race(u2))); return; } if (!u2) { @@ -821,7 +821,7 @@ static void give_cmd(unit * u, order * ord) } else if (p == P_UNIT) { /* Einheiten uebergeben */ - if (!(u->race->ec_flags & GIVEUNIT)) { + if (!(u_race(u)->ec_flags & GIVEUNIT)) { cmistake(u, ord, 167, MSG_COMMERCE); return; } @@ -841,14 +841,14 @@ static void give_cmd(unit * u, order * ord) if (*s == 0) { /* GIVE ALL items that you have */ /* do these checks once, not for each item we have: */ - if (!(u->race->ec_flags & GIVEITEM) && u2 != NULL) { + if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) { ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_nogive", "race", u->race)); + msg_feedback(u, ord, "race_nogive", "race", u_race(u))); return; } - if (u2 && !(u2->race->ec_flags & GETITEM)) { + if (u2 && !(u_race(u2)->ec_flags & GETITEM)) { ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_notake", "race", u2->race)); + msg_feedback(u, ord, "race_notake", "race", u_race(u2))); return; } @@ -872,19 +872,19 @@ static void give_cmd(unit * u, order * ord) } } else { if (isparam(s, u->faction->locale, P_PERSON)) { - if (!(u->race->ec_flags & GIVEPERSON)) { + if (!(u_race(u)->ec_flags & GIVEPERSON)) { ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_noregroup", "race", u->race)); + msg_feedback(u, ord, "race_noregroup", "race", u_race(u))); } else { n = u->number; give_men(n, u, u2, ord); } - } else if (!(u->race->ec_flags & GIVEITEM) && u2 != NULL) { + } else if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) { ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_nogive", "race", u->race)); - } else if (u2 && !(u2->race->ec_flags & GETITEM)) { + msg_feedback(u, ord, "race_nogive", "race", u_race(u))); + } else if (u2 && !(u_race(u2)->ec_flags & GETITEM)) { ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_notake", "race", u2->race)); + msg_feedback(u, ord, "race_notake", "race", u_race(u2))); } else { itype = finditemtype(s, u->faction->locale); if (itype != NULL) { @@ -919,9 +919,9 @@ static void give_cmd(unit * u, order * ord) } if (isparam(s, u->faction->locale, P_PERSON)) { - if (!(u->race->ec_flags & GIVEPERSON)) { + if (!(u_race(u)->ec_flags & GIVEPERSON)) { ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_noregroup", "race", u->race)); + msg_feedback(u, ord, "race_noregroup", "race", u_race(u))); return; } give_men(n, u, u2, ord); @@ -929,14 +929,14 @@ static void give_cmd(unit * u, order * ord) } if (u2 != NULL) { - if (!(u->race->ec_flags & GIVEITEM) && u2 != NULL) { + if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) { ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_nogive", "race", u->race)); + msg_feedback(u, ord, "race_nogive", "race", u_race(u))); return; } - if (!(u2->race->ec_flags & GETITEM)) { + if (!(u_race(u2)->ec_flags & GETITEM)) { ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_notake", "race", u2->race)); + msg_feedback(u, ord, "race_notake", "race", u_race(u2))); return; } } @@ -1184,7 +1184,7 @@ static int recruit_archetype(unit * u, order * ord) else if (strcmp(arch->rules[k].property, "race") == 0) { const race *rc = rc_find(arch->rules[k].value); assert(rc); - if (rc == u->race) + if (rc == u_race(u)) match = true; } else if (strcmp(arch->rules[k].property, "building") == 0) { const building_type *btype = bt_find(arch->rules[k].value); @@ -1232,7 +1232,7 @@ static int recruit_archetype(unit * u, order * ord) if (n > 0) { unit *u2; if (merge) { - u2 = create_unit(u->region, u->faction, 0, u->race, 0, 0, u); + u2 = create_unit(u->region, u->faction, 0, u_race(u), 0, 0, u); } else { u2 = u; } @@ -1250,7 +1250,7 @@ static int recruit_archetype(unit * u, order * ord) } ADDMSG(&u->faction->msgs, msg_message("recruit_archetype", "unit amount archetype", u, n, arch->name[n == 1])); - if (u != u2 && u->race == u2->race) { + if (u != u2 && u_race(u) == u_race(u2)) { transfermen(u2, u, u2->number); } return n; @@ -1427,7 +1427,7 @@ static bool can_guard(const unit * guard, const unit * u) return false; if (guard->number <= 0 || !cansee(guard->faction, guard->region, u, 0)) return false; - if (besieged(guard) || !(fval(guard->race, RCF_UNARMEDGUARD) + if (besieged(guard) || !(fval(u_race(guard), RCF_UNARMEDGUARD) || armedmen(guard, true))) return false; @@ -1536,7 +1536,7 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) for (; mod->flags != 0; ++mod) { if (mod->flags & RMF_SKILL) { if (mod->btype == NULL || mod->btype == btype) { - if (mod->race == NULL || mod->race == u->race) { + if (mod->race == NULL || mod->race == u_race(u)) { skill += mod->value.i; } } @@ -1589,7 +1589,7 @@ static void allocate_resource(unit * u, const resource_type * rtype, int want) for (; mod->flags != 0; ++mod) { if (mod->flags & RMF_SAVEMATERIAL) { if (mod->btype == NULL || mod->btype == btype) { - if (mod->race == NULL || mod->race == u->race) { + if (mod->race == NULL || mod->race == u_race(u)) { al->save *= mod->value.f; } } @@ -2113,7 +2113,7 @@ static void buy(unit * u, request ** buyorders, struct order *ord) return; } - if (u->race == new_race[RC_INSECT]) { + if (u_race(u) == new_race[RC_INSECT]) { /* entweder man ist insekt, oder... */ if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT) && !rbuildings(r)) { @@ -2418,7 +2418,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) } /* In der Region muß es eine Burg geben. */ - if (u->race == new_race[RC_INSECT]) { + if (u_race(u) == new_race[RC_INSECT]) { if (r->terrain != newterrain(T_SWAMP) && r->terrain != newterrain(T_DESERT) && !rbuildings(r)) { cmistake(u, ord, 119, MSG_COMMERCE); @@ -2913,13 +2913,13 @@ static void steal_cmd(unit * u, struct order *ord, request ** stealorders) assert(skill_enabled[SK_PERCEPTION] && skill_enabled[SK_STEALTH]); - if (!fval(u->race, RCF_CANSTEAL)) { + if (!fval(u_race(u), RCF_CANSTEAL)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_nosteal", "race", - u->race)); + u_race(u))); return; } - if (fval(r->terrain, SEA_REGION) && u->race != new_race[RC_AQUARIAN]) { + if (fval(r->terrain, SEA_REGION) && u_race(u) != new_race[RC_AQUARIAN]) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", "")); return; } @@ -2973,7 +2973,7 @@ static void steal_cmd(unit * u, struct order *ord, request ** stealorders) if (n <= 0) { /* Wahrnehmung == Tarnung */ - if (u->race != new_race[RC_GOBLIN] || eff_skill(u, SK_STEALTH, r) <= 3) { + if (u_race(u) != new_race[RC_GOBLIN] || eff_skill(u, SK_STEALTH, r) <= 3) { ADDMSG(&u->faction->msgs, msg_message("stealfail", "unit target", u, u2)); if (n == 0) { ADDMSG(&u2->faction->msgs, msg_message("stealdetect", "unit", u2)); @@ -3126,7 +3126,7 @@ expandwork(region * r, request * work_begin, request * work_end, int maxwork) assert(workers >= 0); - u->n = workers * wage(u->region, u->faction, u->race, turn); + u->n = workers * wage(u->region, u->faction, u_race(u), turn); jobs -= workers; assert(jobs >= 0); @@ -3159,7 +3159,7 @@ expandwork(region * r, request * work_begin, request * work_end, int maxwork) static int do_work(unit * u, order * ord, request * o) { - if (playerrace(u->race)) { + if (playerrace(u_race(u))) { region *r = u->region; int w; @@ -3178,7 +3178,7 @@ static int do_work(unit * u, order * ord, request * o) cmistake(u, ord, 69, MSG_INCOME); return -1; } - w = wage(r, u->faction, u->race, turn); + w = wage(r, u->faction, u_race(u), turn); u->wants = u->number * w; o->unit = u; o->qty = u->number * w; @@ -3186,7 +3186,7 @@ static int do_work(unit * u, order * ord, request * o) return 0; } else if (ord && !is_monsters(u->faction)) { ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_cantwork", "race", u->race)); + msg_feedback(u, ord, "race_cantwork", "race", u_race(u))); } return -1; } @@ -3224,7 +3224,7 @@ void tax_cmd(unit * u, struct order *ord, request ** taxorders) request *o; int max; - if (!humanoidrace(u->race) && !is_monsters(u->faction)) { + if (!humanoidrace(u_race(u)) && !is_monsters(u->faction)) { cmistake(u, ord, 228, MSG_INCOME); return; } @@ -3251,7 +3251,7 @@ void tax_cmd(unit * u, struct order *ord, request ** taxorders) if (max == 0) max = INT_MAX; - if (!playerrace(u->race)) { + if (!playerrace(u_race(u))) { u->wants = MIN(income(u), max); } else { u->wants = MIN(n * eff_skill(u, SK_TAXING, r) * 20, max); @@ -3380,10 +3380,10 @@ void produce(struct region *r) order *ord; bool trader = false; - if (u->race == new_race[RC_SPELL] || fval(u, UFL_LONGACTION)) + if (u_race(u) == new_race[RC_SPELL] || fval(u, UFL_LONGACTION)) continue; - if (u->race == new_race[RC_INSECT] && r_insectstalled(r) && + if (u_race(u) == new_race[RC_INSECT] && r_insectstalled(r) && !is_cursed(u->attribs, C_KAELTESCHUTZ, 0)) continue; @@ -3419,8 +3419,8 @@ void produce(struct region *r) if (todo == NOKEYWORD) continue; - if (fval(r->terrain, SEA_REGION) && u->race != new_race[RC_AQUARIAN] - && !(u->race->flags & RCF_SWIM) + if (fval(r->terrain, SEA_REGION) && u_race(u) != new_race[RC_AQUARIAN] + && !(u_race(u)->flags & RCF_SWIM) && todo != K_STEAL && todo != K_SPY && todo != K_SABOTAGE) continue; diff --git a/src/gamecode/give.c b/src/gamecode/give.c index 9c259f2cf..a2d0a83b3 100644 --- a/src/gamecode/give.c +++ b/src/gamecode/give.c @@ -189,7 +189,7 @@ void give_men(int n, unit * u, unit * u2, struct order *ord) return; } else if (u == u2) { error = 10; - } else if (!u2 && u->race == new_race[RC_SNOTLING]) { + } else if (!u2 && u_race(u) == new_race[RC_SNOTLING]) { /* snotlings may not be given to the peasants. */ error = 307; } else if (u2 && u2->number && (fval(u, UFL_HERO) != fval(u2, UFL_HERO))) { @@ -214,8 +214,8 @@ void give_men(int n, unit * u, unit * u2, struct order *ord) } else if (u2 && (fval(u, UFL_WERE) != fval(u2, UFL_WERE))) { /* werewolves can't be given to non-werewolves and vice-versa */ error = 312; - } else if (u2 && u2->number != 0 && u2->race != u->race) { - log_warning("faction %s attempts to give %s to %s.\n", itoa36(u->faction->no), u->race->_name[0], u2->race->_name[1]); + } else if (u2 && u2->number != 0 && u_race(u2) != u_race(u)) { + log_warning("faction %s attempts to give %s to %s.\n", itoa36(u->faction->no), u_race(u)->_name[0], u_race(u2)->_name[1]); error = 139; } else if (u2 != NULL && (get_racename(u2->attribs) || get_racename(u->attribs))) { @@ -236,7 +236,7 @@ void give_men(int n, unit * u, unit * u2, struct order *ord) } else if (u2 && u->faction != u2->faction) { if (u2->faction->newbies + n > MAXNEWBIES) { error = 129; - } else if (u->race != u2->faction->race) { + } else if (u_race(u) != u2->faction->race) { if (u2->faction->race != new_race[RC_HUMAN]) { error = 120; } else if (count_migrants(u2->faction) + n > @@ -277,7 +277,7 @@ void give_men(int n, unit * u, unit * u2, struct order *ord) if (error == 0) { if (u2 && u2->number == 0) { set_racename(&u2->attribs, get_racename(u->attribs)); - u2->race = u->race; + u_setrace(u2, u_race(u)); u2->irace = u->irace; if (fval(u, UFL_HERO)) fset(u2, UFL_HERO); @@ -322,7 +322,7 @@ void give_men(int n, unit * u, unit * u2, struct order *ord) } else { if (getunitpeasants) { #ifdef ORCIFICATION - if (u->race == new_race[RC_SNOTLING] && !fval(u->region, RF_ORCIFIED)) { + if (u_race(u) == new_race[RC_SNOTLING] && !fval(u->region, RF_ORCIFIED)) { attrib *a = a_find(u->region->attribs, &at_orcification); if (!a) a = a_add(&u->region->attribs, a_new(&at_orcification)); @@ -416,7 +416,7 @@ void give_unit(unit * u, unit * u2, order * ord) cmistake(u, ord, 129, MSG_COMMERCE); return; } - if (u->race != u2->faction->race) { + if (u_race(u) != u2->faction->race) { if (u2->faction->race != new_race[RC_HUMAN]) { cmistake(u, ord, 120, MSG_COMMERCE); return; diff --git a/src/gamecode/laws.c b/src/gamecode/laws.c index 7c0fc460c..433ba025b 100755 --- a/src/gamecode/laws.c +++ b/src/gamecode/laws.c @@ -144,7 +144,7 @@ static void checkorders(void) static bool help_money(const unit * u) { - if (u->race->ec_flags & GIVEITEM) + if (u_race(u)->ec_flags & GIVEITEM) return true; return false; } @@ -294,7 +294,7 @@ void get_food(region * r) * bei fehlenden Bauern den Dämon hungern lassen */ for (u = r->units; u; u = u->next) { - if (u->race == new_race[RC_DAEMON]) { + if (u_race(u) == new_race[RC_DAEMON]) { int hungry = u->number; /* use peasantblood before eating the peasants themselves */ @@ -315,7 +315,7 @@ void get_food(region * r) if (donor == u) donor = r->units; while (donor != NULL) { - if (donor->race == new_race[RC_DAEMON] && donor!=u) { + if (u_race(donor) == new_race[RC_DAEMON] && donor!=u) { if (get_effect(donor, pt_blood)) { /* if he's in our faction, drain him: */ if (donor->faction == u->faction) @@ -363,14 +363,14 @@ void get_food(region * r) static void age_unit(region * r, unit * u) { - if (u->race == new_race[RC_SPELL]) { + if (u_race(u) == new_race[RC_SPELL]) { if (--u->age <= 0) { remove_unit(&r->units, u); } } else { ++u->age; - if (u->number > 0 && u->race->age) { - u->race->age(u); + if (u->number > 0 && u_race(u)->age) { + u_race(u)->age(u); } } #ifdef ASTRAL_ITEM_RESTRICTIONS @@ -681,7 +681,7 @@ static int count_race(const region * r, const race * rc) int c = 0; for (u = r->units; u; u = u->next) - if (u->race == rc) + if (u_race(u) == rc) c += u->number; return c; @@ -1111,7 +1111,7 @@ int leave_cmd(unit * u, struct order *ord) } if (fval(r->terrain, SEA_REGION) && u->ship) { - if (!fval(u->race, RCF_SWIM)) { + if (!fval(u_race(u), RCF_SWIM)) { cmistake(u, ord, 11, MSG_MOVE); return 0; } @@ -1216,10 +1216,10 @@ int enter_ship(unit * u, struct order *ord, int id, int report) region *r = u->region; ship *sh; - /* Muß abgefangen werden, sonst könnten Schwimmer an + /* Muss abgefangen werden, sonst koennten Schwimmer an * Bord von Schiffen an Land gelangen. */ - if (!fval(u->race, RCF_CANSAIL) || (!fval(u->race, RCF_WALK) - && !fval(u->race, RCF_FLY))) { + if (!fval(u_race(u), RCF_CANSAIL) || (!fval(u_race(u), RCF_WALK) + && !fval(u_race(u), RCF_FLY))) { cmistake(u, ord, 233, MSG_MOVE); return 0; } @@ -1247,7 +1247,7 @@ int enter_ship(unit * u, struct order *ord, int id, int report) getshipweight(sh, &sweight, &scabins); sweight += weight(u); if (mcabins) { - int pweight = u->number * u->race->weight; + int pweight = u->number * u_race(u)->weight; /* weight goes into number of cabins, not cargo */ scabins += pweight; sweight -= pweight; @@ -1275,7 +1275,7 @@ int enter_building(unit * u, order * ord, int id, int report) /* Schwimmer können keine Gebäude betreten, außer diese sind * auf dem Ozean */ - if (!fval(u->race, RCF_WALK) && !fval(u->race, RCF_FLY)) { + if (!fval(u_race(u), RCF_WALK) && !fval(u_race(u), RCF_FLY)) { if (!fval(r->terrain, SEA_REGION)) { if (report) { cmistake(u, ord, 232, MSG_MOVE); @@ -2149,7 +2149,7 @@ mailunit(region * r, unit * u, int n, struct order *ord, const char *s) deliverMail(u2->faction, r, u, s, u2); /* now done in prepare_mail_cmd */ } else { - /* Immer eine Meldung - sonst könnte man so getarnte EHs enttarnen: + /* Immer eine Meldung - sonst koennte man so getarnte EHs enttarnen: * keine Meldung -> EH hier. */ ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); @@ -2507,7 +2507,7 @@ static bool display_race(faction * f, unit * u, const race * rc) size_t size = sizeof(buf) - 1; int bytes; - if (u && u->race != rc) + if (u && u_race(u) != rc) return false; name = rc_name(rc, 0); @@ -2724,9 +2724,9 @@ int promotion_cmd(unit * u, struct order *ord) maxheroes(u->faction), countheroes(u->faction))); return 0; } - if (!valid_race(u->faction, u->race)) { + if (!valid_race(u->faction, u_race(u))) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "heroes_race", "race", - u->race)); + u_race(u))); return 0; } people = count_all(u->faction) * u->number; @@ -2900,7 +2900,7 @@ static int can_start_guarding(const unit * u) { if (u->status >= ST_FLEE) return E_GUARD_FLEEING; - if (fval(u->race, RCF_UNARMEDGUARD)) + if (fval(u_race(u), RCF_UNARMEDGUARD)) return E_GUARD_OK; if (!armedmen(u, true)) return E_GUARD_UNARMED; @@ -2947,8 +2947,8 @@ int guard_on_cmd(unit * u, struct order *ord) } else { if (fval(u, UFL_MOVED)) { cmistake(u, ord, 187, MSG_EVENT); - } else if (fval(u->race, RCF_ILLUSIONARY) - || u->race == new_race[RC_SPELL]) { + } else if (fval(u_race(u), RCF_ILLUSIONARY) + || u_race(u) == new_race[RC_SPELL]) { cmistake(u, ord, 95, MSG_EVENT); } else { /* Monster der Monsterpartei dürfen immer bewachen */ @@ -3299,7 +3299,7 @@ static building *age_building(building * b) * find out if there's a magician in there. */ for (u = r->units; u; u = u->next) { if (b == u->building && inside_building(u)) { - if (!(u->race->ec_flags & GIVEITEM) == 0) { + if (!(u_race(u)->ec_flags & GIVEITEM) == 0) { int n, unicorns = 0; for (n = 0; n != u->number; ++n) { if (chance(0.02)) { @@ -3417,7 +3417,7 @@ static void ageing(void) if (is_cursed(u->attribs, C_OLDRACE, 0)) { curse *c = get_curse(u->attribs, ct_find("oldrace")); if (c->duration == 1 && !(c_flags(c) & CURSE_NOAGE)) { - u->race = new_race[curse_geteffect_int(c)]; + u_setrace(u, new_race[curse_geteffect_int(c)]); u->irace = NULL; } } @@ -3763,7 +3763,7 @@ use_item(unit * u, const item_type * itype, int amount, struct order *ord) static double heal_factor(const unit * u) { static float elf_regen = -1; - switch (old_race(u->race)) { + switch (old_race(u_race(u))) { case RC_TROLL: case RC_DAEMON: return 1.5; @@ -3771,7 +3771,7 @@ static double heal_factor(const unit * u) return 2.0; case RC_ELF: if (elf_regen < 0) - elf_regen = get_param_flt(u->race->parameters, "regen.forest", 1.0F); + elf_regen = get_param_flt(u_race(u)->parameters, "regen.forest", 1.0F); if (elf_regen != 1.0 && r_isforest(u->region)) { return elf_regen; } @@ -3812,7 +3812,7 @@ void monthly_healing(void) continue; } - if (u->race->flags & RCF_NOHEAL) + if (u_race(u)->flags & RCF_NOHEAL) continue; if (fval(u, UFL_HUNGER)) continue; @@ -3905,8 +3905,8 @@ static void defaultorders(void) } /* ************************************************************ */ -/* GANZ WICHTIG! ALLE GEÄNDERTEN SPRÜCHE NEU ANZEIGEN */ -/* GANZ WICHTIG! FÜGT AUCH NEUE ZAUBER IN DIE LISTE DER BEKANNTEN EIN */ +/* GANZ WICHTIG! ALLE GEAENDERTEN SPRUECHE NEU ANZEIGEN */ +/* GANZ WICHTIG! FUEGT AUCH NEUE ZAUBER IN DIE LISTE DER BEKANNTEN EIN */ /* ************************************************************ */ #define COMMONSPELLS 1 /* number of new common spells per level */ #define MAXMAGES 128 /* should be enough */ @@ -4248,7 +4248,7 @@ void process(void) if (porder->flags & PROC_LONGORDER) { if (u->number == 0) { ord = NULL; - } else if (u->race == new_race[RC_INSECT] + } else if (u_race(u) == new_race[RC_INSECT] && r_insectstalled(r) && !is_cursed(u->attribs, C_KAELTESCHUTZ, 0)) { ord = NULL; @@ -4261,8 +4261,8 @@ void process(void) */ ord = NULL; } else if (fval(r->terrain, SEA_REGION) - && u->race != new_race[RC_AQUARIAN] - && !(u->race->flags & RCF_SWIM)) { + && u_race(u) != new_race[RC_AQUARIAN] + && !(u_race(u)->flags & RCF_SWIM)) { /* error message disabled by popular demand */ ord = NULL; } @@ -4338,7 +4338,7 @@ int siege_cmd(unit * u, order * ord) return 31; } - if (!playerrace(u->race)) { + if (!playerrace(u_race(u))) { /* keine Drachen, Illusionen, Untote etc */ cmistake(u, ord, 166, MSG_BATTLE); return 166; diff --git a/src/gamecode/monster.c b/src/gamecode/monster.c index 4fe9d9ec2..ab016e5a5 100644 --- a/src/gamecode/monster.c +++ b/src/gamecode/monster.c @@ -88,7 +88,7 @@ static void eaten_by_monster(unit * u) multi = RESOURCE_QUANTITY * newterrain(T_PLAIN)->size / 10000.0; } - switch (old_race(u->race)) { + switch (old_race(u_race(u))) { case RC_FIREDRAGON: n = rng_int() % 80 * u->number; horse = get_item(u, I_HORSE); @@ -126,7 +126,7 @@ static void absorbed_by_monster(unit * u) { int n; - switch (old_race(u->race)) { + switch (old_race(u_race(u))) { default: n = rng_int() % (u->number / 20 + 1); } @@ -138,7 +138,7 @@ static void absorbed_by_monster(unit * u) rsetpeasants(u->region, rpeasants(u->region) - n); scale_number(u, u->number + n); ADDMSG(&u->region->msgs, msg_message("absorbpeasants", - "unit race amount", u, u->race, n)); + "unit race amount", u, u_race(u), n)); } } } @@ -179,7 +179,7 @@ static void scared_by_monster(unit * u) { int n; - switch (old_race(u->race)) { + switch (old_race(u_race(u))) { case RC_FIREDRAGON: n = rng_int() % 160 * u->number; break; @@ -209,13 +209,13 @@ static void scared_by_monster(unit * u) void monster_kills_peasants(unit * u) { if (!monster_is_waiting(u)) { - if (u->race->flags & RCF_SCAREPEASANTS) { + if (u_race(u)->flags & RCF_SCAREPEASANTS) { scared_by_monster(u); } - if (u->race->flags & RCF_KILLPEASANTS) { + if (u_race(u)->flags & RCF_KILLPEASANTS) { eaten_by_monster(u); } - if (u->race->flags & RCF_ABSORBPEASANTS) { + if (u_race(u)->flags & RCF_ABSORBPEASANTS) { absorbed_by_monster(u); } } diff --git a/src/gamecode/randenc.c b/src/gamecode/randenc.c index 196fdd5a0..f1e577477 100644 --- a/src/gamecode/randenc.c +++ b/src/gamecode/randenc.c @@ -113,30 +113,30 @@ static void dissolve_units(void) rsetpeasants(r, rpeasants(r) + n); msg = msg_message("dissolve_units_1", "unit region number race", u, r, - n, u->race); + n, u_race(u)); break; case 2: if (r->land && !fval(r, RF_MALLORN)) { rsettrees(r, 2, rtrees(r, 2) + n); msg = msg_message("dissolve_units_2", "unit region number race", u, r, - n, u->race); + n, u_race(u)); } else { msg = msg_message("dissolve_units_3", "unit region number race", u, r, - n, u->race); + n, u_race(u)); } break; default: - if (u->race == new_race[RC_STONEGOLEM] - || u->race == new_race[RC_IRONGOLEM]) { + if (u_race(u) == new_race[RC_STONEGOLEM] + || u_race(u) == new_race[RC_IRONGOLEM]) { msg = msg_message("dissolve_units_4", "unit region number race", u, r, - n, u->race); + n, u_race(u)); } else { msg = msg_message("dissolve_units_5", "unit region number race", u, r, - n, u->race); + n, u_race(u)); } break; } @@ -355,7 +355,7 @@ static void get_allies(region * r, unit * u) u_setfaction(newunit, u->faction); set_racename(&newunit->attribs, get_racename(u->attribs)); - if (u->race->flags & RCF_SHAPESHIFT) { + if (u_race(u)->flags & RCF_SHAPESHIFT) { newunit->irace = u->irace; } if (fval(u, UFL_ANON_FACTION)) @@ -445,7 +445,7 @@ static unit *random_unit(const region * r) unit *u; for (u = r->units; u; u = u->next) { - if (u->race != new_race[RC_SPELL]) { + if (u_race(u) != new_race[RC_SPELL]) { c += u->number; } } @@ -458,7 +458,7 @@ static unit *random_unit(const region * r) u = r->units; while (u && c < n) { - if (u->race != new_race[RC_SPELL]) { + if (u_race(u) != new_race[RC_SPELL]) { c += u->number; } u = u->next; @@ -474,10 +474,10 @@ void chaos(region * r) case 0: /* Untote */ if (!fval(r->terrain, SEA_REGION)) { unit *u = random_unit(r); - if (u && playerrace(u->race)) { + if (u && playerrace(u_race(u))) { ADDMSG(&u->faction->msgs, msg_message("chaos_disease", "unit", u)); u_setfaction(u, get_monsters()); - u->race = new_race[RC_GHOUL]; + u_setrace(u, new_race[RC_GHOUL]); } } break; @@ -536,7 +536,7 @@ void chaos(region * r) for (up = &r->units; *up;) { unit *u = *up; - if (u->race != new_race[RC_SPELL] && u->ship == 0 && !canfly(u)) { + if (u_race(u) != new_race[RC_SPELL] && u->ship == 0 && !canfly(u)) { ADDMSG(&u->faction->msgs, msg_message("tidalwave_kill", "region unit", r, u)); remove_unit(up, u); @@ -573,7 +573,7 @@ static int nb_armor(const unit * u, int index) int av = 0; int s = 0, a = 0; - if (!(u->race->battle_flags & BF_EQUIPMENT)) + if (!(u_race(u)->battle_flags & BF_EQUIPMENT)) return 0; /* Normale Rüstung */ @@ -604,7 +604,7 @@ damage_unit(unit * u, const char *dam, bool physical, bool magic) double magres = magic_resistance(u); assert(u->number); - if (fval(u->race, RCF_ILLUSIONARY) || u->race == new_race[RC_SPELL]) { + if (fval(u_race(u), RCF_ILLUSIONARY) || u_race(u) == new_race[RC_SPELL]) { return 0; } @@ -632,7 +632,7 @@ damage_unit(unit * u, const char *dam, bool physical, bool magic) heiltrank = 0; /* Sieben Leben */ - if (old_race(u->race) == RC_CAT && (chance(1.0 / 7))) { + if (old_race(u_race(u)) == RC_CAT && (chance(1.0 / 7))) { hp[i] = u->hp / u->number; hp_rem += hp[i]; continue; @@ -675,7 +675,7 @@ void drown(region * r) while (*up) { unit *u = *up; int amphibian_level = 0; - if (u->ship || u->race == new_race[RC_SPELL] || u->number == 0) { + if (u->ship || u_race(u) == new_race[RC_SPELL] || u->number == 0) { up = &u->next; continue; } @@ -1085,11 +1085,11 @@ static void orc_growth(void) } } if (increase) { - unit *u2 = create_unit(r, u->faction, increase, u->race, 0, NULL, u); + unit *u2 = create_unit(r, u->faction, increase, u_race(u), 0, NULL, u); transfermen(u2, u, u2->number); ADDMSG(&u->faction->msgs, msg_message("orcgrowth", - "unit amount race", u, increase, u->race)); + "unit amount race", u, increase, u_race(u))); } } } @@ -1105,7 +1105,7 @@ static void demon_skillchanges(void) for (r = regions; r; r = r->next) { unit *u; for (u = r->units; u; u = u->next) { - if (u->race == new_race[RC_DAEMON]) { + if (u_race(u) == new_race[RC_DAEMON]) { skill *sv = u->skills; int upchance = 15; int downchance = 10; @@ -1295,7 +1295,7 @@ void randomevents(void) for (u = r->units; u; u = u->next) { if (u->faction && !is_monsters(u->faction) - && (u->race->flags & RCF_DESERT)) { + && (u_race(u)->flags & RCF_DESERT)) { if (fval(u, UFL_ISNEW)) continue; if (rng_int() % 100 < 5) { diff --git a/src/gamecode/report.c b/src/gamecode/report.c index c8b3d1179..a9d4625e6 100644 --- a/src/gamecode/report.c +++ b/src/gamecode/report.c @@ -692,7 +692,7 @@ nr_unit(FILE * F, const faction * f, const unit * u, int indent, int mode) bool isbattle = (bool) (mode == see_battle); char buf[8192]; - if (fval(u->race, RCF_INVISIBLE)) + if (fval(u_race(u), RCF_INVISIBLE)) return; { @@ -1283,7 +1283,7 @@ static void statistics(FILE * F, const region * r, const faction * f) /* count */ for (u = r->units; u; u = u->next) { - if (u->faction == f && !fval(u->race, RCF_INVISIBLE)) { + if (u->faction == f && !fval(u_race(u), RCF_INVISIBLE)) { for (itm = u->items; itm; itm = itm->next) { i_change(&items, itm->type, itm->number); } @@ -1523,7 +1523,7 @@ report_template(const char *filename, report_context * ctx, const char *charset) continue; for (u = r->units; u; u = u->next) { - if (u->faction == f && !fval(u->race, RCF_INVISIBLE)) { + if (u->faction == f && !fval(u_race(u), RCF_INVISIBLE)) { order *ord; if (!dh) { plane *pl = getplane(r); @@ -2191,7 +2191,7 @@ report_plaintext(const char *filename, report_context * ctx, no_units = 0; no_people = 0; for (u = f->units; u; u = u->nextF) { - if (playerrace(u->race)) { + if (playerrace(u_race(u))) { ++no_people; no_units += u->number; assert(f == u->faction); diff --git a/src/gamecode/spy.c b/src/gamecode/spy.c index 476aed8af..fa5116060 100644 --- a/src/gamecode/spy.c +++ b/src/gamecode/spy.c @@ -239,7 +239,7 @@ int setstealth_cmd(unit * u, struct order *ord) trace = findrace(s, u->faction->locale); if (trace) { /* Dämonen können sich nur als andere Spielerrassen tarnen */ - if (u->race == new_race[RC_DAEMON]) { + if (u_race(u) == new_race[RC_DAEMON]) { race_t allowed[] = { RC_DWARF, RC_ELF, RC_ORC, RC_GOBLIN, RC_HUMAN, RC_TROLL, RC_DAEMON, RC_INSECT, RC_HALFLING, RC_CAT, RC_AQUARIAN, NORACE @@ -250,29 +250,29 @@ int setstealth_cmd(unit * u, struct order *ord) break; if (new_race[allowed[i]] == trace) { u->irace = trace; - if (u->race->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs)) + if (u_race(u)->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs)) set_racename(&u->attribs, NULL); } return 0; } /* Singdrachen können sich nur als Drachen tarnen */ - if (u->race == new_race[RC_SONGDRAGON] - || u->race == new_race[RC_BIRTHDAYDRAGON]) { + if (u_race(u) == new_race[RC_SONGDRAGON] + || u_race(u) == new_race[RC_BIRTHDAYDRAGON]) { if (trace == new_race[RC_SONGDRAGON] || trace == new_race[RC_FIREDRAGON] || trace == new_race[RC_DRAGON] || trace == new_race[RC_WYRM]) { u->irace = trace; - if (u->race->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs)) + if (u_race(u)->flags & RCF_SHAPESHIFTANY && get_racename(u->attribs)) set_racename(&u->attribs, NULL); } return 0; } /* Dämomen und Illusionsparteien können sich als andere race tarnen */ - if (u->race->flags & RCF_SHAPESHIFT) { + if (u_race(u)->flags & RCF_SHAPESHIFT) { if (playerrace(trace)) { u->irace = trace; - if ((u->race->flags & RCF_SHAPESHIFTANY) && get_racename(u->attribs)) + if ((u_race(u)->flags & RCF_SHAPESHIFTANY) && get_racename(u->attribs)) set_racename(&u->attribs, NULL); } } @@ -328,7 +328,7 @@ int setstealth_cmd(unit * u, struct order *ord) u_seteffstealth(u, -1); break; default: - if (u->race->flags & RCF_SHAPESHIFTANY) { + if (u_race(u)->flags & RCF_SHAPESHIFTANY) { set_racename(&u->attribs, s); } else { cmistake(u, ord, 289, MSG_EVENT); diff --git a/src/gamecode/study.c b/src/gamecode/study.c index 653ef5bb9..4c20dd090 100644 --- a/src/gamecode/study.c +++ b/src/gamecode/study.c @@ -89,14 +89,14 @@ magic_t getmagicskill(const struct locale * lang) /* Vertraute und Kröten sind keine Migranten */ bool is_migrant(unit * u) { - if (u->race == u->faction->race) + if (u_race(u) == u->faction->race) return false; - if (fval(u->race, RCF_UNDEAD | RCF_ILLUSIONARY)) + if (fval(u_race(u), RCF_UNDEAD | RCF_ILLUSIONARY)) return false; if (is_familiar(u)) return false; - if (u->race == new_race[RC_TOAD]) + if (u_race(u) == new_race[RC_TOAD]) return false; return true; @@ -105,7 +105,7 @@ bool is_migrant(unit * u) /* ------------------------------------------------------------- */ bool magic_lowskill(unit * u) { - return (u->race == new_race[RC_TOAD]) ? true : false; + return (u_race(u) == new_race[RC_TOAD]) ? true : false; } /* ------------------------------------------------------------- */ @@ -160,8 +160,8 @@ const attrib_type at_learning = { static int study_days(unit * student, skill_t sk) { int speed = 30; - if (student->race->study_speed) { - speed += student->race->study_speed[sk]; + if (u_race(student)->study_speed) { + speed += u_race(student)->study_speed[sk]; if (speed < 30) { skill *sv = get_skill(student, sk); if (sv == 0) { @@ -288,7 +288,7 @@ int teach_cmd(unit * u, struct order *ord) } } - if ((u->race->flags & RCF_NOTEACH) || fval(u, UFL_WERE)) { + if ((u_race(u)->flags & RCF_NOTEACH) || fval(u, UFL_WERE)) { cmistake(u, ord, 274, MSG_EVENT); return 0; } @@ -542,9 +542,9 @@ int learn_cmd(unit * u, order * ord) learn_newskills = 1; } - if ((u->race->flags & RCF_NOLEARN) || fval(u, UFL_WERE)) { + if ((u_race(u)->flags & RCF_NOLEARN) || fval(u, UFL_WERE)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_race_nolearn", "race", - u->race)); + u_race(u))); return 0; } @@ -561,7 +561,7 @@ int learn_cmd(unit * u, order * ord) return 0; } /* Hack: Talente mit Malus -99 können nicht gelernt werden */ - if (u->race->bonus[sk] == -99) { + if (u_race(u)->bonus[sk] == -99) { cmistake(u, ord, 771, MSG_EVENT); return 0; } @@ -575,7 +575,7 @@ int learn_cmd(unit * u, order * ord) } /* snotlings können Talente nur bis T8 lernen */ - if (u->race == new_race[RC_SNOTLING]) { + if (u_race(u) == new_race[RC_SNOTLING]) { if (get_level(u, sk) >= 8) { cmistake(u, ord, 308, MSG_EVENT); return 0; diff --git a/src/gamecode/summary.c b/src/gamecode/summary.c index 1d3c73e2f..ff19477f1 100644 --- a/src/gamecode/summary.c +++ b/src/gamecode/summary.c @@ -404,7 +404,7 @@ summary *make_summary(void) f->num_total += u->number; f->money += get_money(u); - s->poprace[old_race(u->race)] += u->number; + s->poprace[old_race(u_race(u))] += u->number; } } } diff --git a/src/items/phoenixcompass.c b/src/items/phoenixcompass.c index 9787d4e9d..1aa6b3d2e 100644 --- a/src/items/phoenixcompass.c +++ b/src/items/phoenixcompass.c @@ -61,7 +61,7 @@ use_phoenixcompass(struct unit *u, const struct item_type *itype, for (r = regions; r; r = r->next) { for (u2 = r->units; u2; u2 = u2->next) { - if (u2->race == rc_phoenix) { + if (u_race(u2) == rc_phoenix) { if (closest_phoenix == NULL) { closest_phoenix = u2; closest_phoenix_distance = diff --git a/src/kernel/battle.c b/src/kernel/battle.c index b69107524..9b249609d 100644 --- a/src/kernel/battle.c +++ b/src/kernel/battle.c @@ -351,7 +351,7 @@ fighter *select_corpse(battle * b, fighter * af) /* Geflohene haben auch 0 hp, dürfen hier aber nicht ausgewählt * werden! */ int dead = dead_fighters(df); - if (!playerrace(df->unit->race)) + if (!playerrace(u_race(df->unit))) continue; if (af && !helping(af->side, df->side)) @@ -624,39 +624,39 @@ weapon_skill(const weapon_type * wtype, const unit * u, bool attacking) skill = effskill(u, SK_WEAPONLESS); if (skill <= 0) { /* wenn kein waffenloser kampf, dann den rassen-defaultwert */ - if (u->race == new_race[RC_ORC]) { + if (u_race(u) == new_race[RC_ORC]) { int sword = effskill(u, SK_MELEE); int spear = effskill(u, SK_SPEAR); skill = MAX(sword, spear) - 3; if (attacking) { - skill = MAX(skill, u->race->at_default); + skill = MAX(skill, u_race(u)->at_default); } else { - skill = MAX(skill, u->race->df_default); + skill = MAX(skill, u_race(u)->df_default); } } else { if (attacking) { - skill = u->race->at_default; + skill = u_race(u)->at_default; } else { - skill = u->race->df_default; + skill = u_race(u)->df_default; } } } else { /* der rassen-defaultwert kann höher sein als der Talentwert von * waffenloser kampf */ if (attacking) { - if (skill < u->race->at_default) - skill = u->race->at_default; + if (skill < u_race(u)->at_default) + skill = u_race(u)->at_default; } else { - if (skill < u->race->df_default) - skill = u->race->df_default; + if (skill < u_race(u)->df_default) + skill = u_race(u)->df_default; } } if (attacking) { - skill += u->race->at_bonus; + skill += u_race(u)->at_bonus; if (fval(u->region->terrain, SEA_REGION) && u->ship) skill += u->ship->type->at_bonus; } else { - skill += u->race->df_bonus; + skill += u_race(u)->df_bonus; if (fval(u->region->terrain, SEA_REGION) && u->ship) skill += u->ship->type->df_bonus; } @@ -669,9 +669,9 @@ weapon_skill(const weapon_type * wtype, const unit * u, bool attacking) skill = 0; if (skill > 0) { if (attacking) { - skill += u->race->at_bonus; + skill += u_race(u)->at_bonus; } else { - skill += u->race->df_bonus; + skill += u_race(u)->df_bonus; } } if (attacking) { @@ -713,7 +713,7 @@ static int CavalryBonus(const unit * u, troop enemy, int type) if (skl > 0) { if (type == BONUS_DAMAGE) { int dmg = MIN(skl, 8); - if (enemy.fighter->unit->race == new_race[RC_TROLL]) { + if (u_race(enemy.fighter->unit) == new_race[RC_TROLL]) { dmg = dmg / 4; } else { dmg = dmg / 2; @@ -769,7 +769,7 @@ weapon_effskill(troop t, troop enemy, const weapon * w, bool attacking, race_list *rlist = wtype->modifiers[m].races; if (rlist != NULL) { while (rlist) { - if (rlist->data == tu->race) + if (rlist->data == u_race(tu)) break; rlist = rlist->next; } @@ -818,7 +818,7 @@ static const armor_type *select_armor(troop t, bool shield) int geschuetzt = 0; /* some monsters should not use armor (dragons in chainmail? ha!) */ - if (!(u->race->battle_flags & BF_EQUIPMENT)) + if (!(u_race(u)->battle_flags & BF_EQUIPMENT)) return NULL; /* ... neither do werewolves */ @@ -903,7 +903,7 @@ void rmfighter(fighter * df, int i) ds->size[statusrow(df->status)] -= i; /* Spezialwirkungen, z.B. Schattenritter */ - if (df->unit->race->battle_flags & BF_NOBLOCK) { + if (u_race(df->unit)->battle_flags & BF_NOBLOCK) { ds->nonblockers[SUM_ROW] -= i; ds->nonblockers[statusrow(df->status)] -= i; } @@ -949,14 +949,14 @@ void kill_troop(troop dt) if (!df->alive) { char eqname[64]; const struct equipment *eq; - if (du->race->itemdrop) { - item *drops = du->race->itemdrop(du->race, du->number - df->run.number); + if (u_race(du)->itemdrop) { + item *drops = u_race(du)->itemdrop(u_race(du), du->number - df->run.number); if (drops != NULL) { i_merge(&du->items, &drops); } } - sprintf(eqname, "%s_spoils", du->race->_name[0]); + sprintf(eqname, "%s_spoils", u_race(du)->_name[0]); eq = get_equipment(eqname); if (eq != NULL) { equip_items(&du->items, eq); @@ -1033,19 +1033,19 @@ static void vampirism(troop at, int damage) static int natural_armor(unit * du) { static int *bonus = 0; - int an = du->race->armor; + int an = u_race(du)->armor; if (bonus == 0) { bonus = calloc(sizeof(int), num_races); } - if (bonus[du->race->index] == 0) { - bonus[du->race->index] = - get_param_int(du->race->parameters, "armor.stamina", -1); - if (bonus[du->race->index] == 0) - bonus[du->race->index] = -1; + if (bonus[u_race(du)->index] == 0) { + bonus[u_race(du)->index] = + get_param_int(u_race(du)->parameters, "armor.stamina", -1); + if (bonus[u_race(du)->index] == 0) + bonus[u_race(du)->index] = -1; } - if (bonus[du->race->index] > 0) { + if (bonus[u_race(du)->index] > 0) { int sk = effskill(du, SK_STAMINA); - sk /= bonus[du->race->index]; + sk /= bonus[u_race(du)->index]; an += sk; } return an; @@ -1170,7 +1170,7 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile) } } - da += rc_specialdamage(au->race, du->race, awtype); + da += rc_specialdamage(u_race(au), u_race(du), awtype); if (awtype != NULL && fval(awtype, WTF_MISSILE)) { /* missile weapon bonus */ @@ -1202,7 +1202,7 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile) /* magic_resistance gib x% Resistenzbonus zurück */ res -= magic_resistance(du) * 3.0; - if (du->race->battle_flags & BF_EQUIPMENT) { + if (u_race(du)->battle_flags & BF_EQUIPMENT) { #ifdef TODO_RUNESWORD /* Runenschwert gibt im Kampf 80% Resistenzbonus */ if (dwp == WP_RUNESWORD) @@ -1226,18 +1226,18 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile) rda = MAX(da - ar, 0); - if ((du->race->battle_flags & BF_INV_NONMAGIC) && !magic) + if ((u_race(du)->battle_flags & BF_INV_NONMAGIC) && !magic) rda = 0; else { int qi; quicklist *ql; unsigned int i = 0; - if (du->race->battle_flags & BF_RES_PIERCE) + if (u_race(du)->battle_flags & BF_RES_PIERCE) i |= WTF_PIERCE; - if (du->race->battle_flags & BF_RES_CUT) + if (u_race(du)->battle_flags & BF_RES_CUT) i |= WTF_CUT; - if (du->race->battle_flags & BF_RES_BASH) + if (u_race(du)->battle_flags & BF_RES_BASH) i |= WTF_BLUNT; if (i && awtype && fval(awtype, i)) @@ -1266,7 +1266,7 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile) assert(dt.index < du->number); df->person[dt.index].hp -= rda; - if (au->race == new_race[RC_DAEMON]) { + if (u_race(au) == new_race[RC_DAEMON]) { vampirism(at, rda); } @@ -1275,7 +1275,7 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile) fprintf(bdebug, "Damage %d, armor %d: %d -> %d HP\n", da, ar, df->person[dt.index].hp + rda, df->person[dt.index].hp); } - if (au->race == new_race[RC_DAEMON]) { + if (u_race(au) == new_race[RC_DAEMON]) { #ifdef TODO_RUNESWORD if (select_weapon(dt, 0, -1) == WP_RUNESWORD) continue; @@ -1290,7 +1290,7 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile) } /* Sieben Leben */ - if (du->race == new_race[RC_CAT] && (chance(1.0 / 7))) { + if (u_race(du) == new_race[RC_CAT] && (chance(1.0 / 7))) { assert(dt.index >= 0 && dt.index < du->number); df->person[dt.index].hp = unit_max_hp(du); return false; @@ -1313,7 +1313,7 @@ terminate(troop dt, troop at, int type, const char *damage, bool missile) msg_release(m); } assert(dt.index >= 0 && dt.index < du->number); - df->person[dt.index].hp = du->race->hitpoints; + df->person[dt.index].hp = u_race(du)->hitpoints; return false; } } @@ -1464,7 +1464,7 @@ troop select_enemy(fighter * af, int minrow, int maxrow, int select) #ifdef DEBUG_SELECT troop result = no_troop; #endif - if (af->unit->race->flags & RCF_FLY) { + if (u_race(af->unit)->flags & RCF_FLY) { /* flying races ignore min- and maxrow and can attack anyone fighting * them */ minrow = FIGHT_ROW; @@ -1564,7 +1564,7 @@ static troop select_opponent(battle * b, troop at, int mindist, int maxdist) fighter *af = at.fighter; troop dt; - if (af->unit->race->flags & RCF_FLY) { + if (u_race(af->unit)->flags & RCF_FLY) { /* flying races ignore min- and maxrow and can attack anyone fighting * them */ dt = select_enemy(at.fighter, FIGHT_ROW, BEHIND_ROW, SELECT_ADVANCE); @@ -1849,11 +1849,11 @@ int skilldiff(troop at, troop dt, int dist) skdiff += 2; /* Effekte durch Rassen */ - if (awp != NULL && au->race == new_race[RC_HALFLING] && dragonrace(du->race)) { + if (awp != NULL && u_race(au) == new_race[RC_HALFLING] && dragonrace(u_race(du))) { skdiff += 5; } - if (au->race == new_race[RC_GOBLIN]) { + if (u_race(au) == new_race[RC_GOBLIN]) { static int goblin_bonus = -1; if (goblin_bonus < 0) goblin_bonus = @@ -2067,8 +2067,8 @@ static void make_heroes(battle * b) unit *u = fig->unit; if (fval(u, UFL_HERO)) { int i; - if (!playerrace(u->race)) { - log_error("Hero %s is a %s.\n", unitname(u), u->race->_name[0]); + if (!playerrace(u_race(u))) { + log_error("Hero %s is a %s.\n", unitname(u), u_race(u)->_name[0]); } for (i = 0; i != u->number; ++i) { fig->person[i].speed += (hero_speed - 1); @@ -2144,7 +2144,7 @@ static void attack(battle * b, troop ta, const att * a, int numattack) if (hits(ta, td, wp)) { const char *d; if (wp == NULL) - d = au->race->def_damage; + d = u_race(au)->def_damage; else if (is_riding(ta)) d = wp->type->damage[1]; else @@ -2260,11 +2260,11 @@ void do_attack(fighter * af) for (apr = 0; apr != attacks; ++apr) { int a; - for (a = 0; a != 10 && au->race->attack[a].type != AT_NONE; ++a) { + for (a = 0; a != 10 && u_race(au)->attack[a].type != AT_NONE; ++a) { if (apr > 0) { /* Wenn die Waffe nachladen muss, oder es sich nicht um einen * Waffen-Angriff handelt, dann gilt der Speed nicht. */ - if (au->race->attack[a].type != AT_STANDARD) + if (u_race(au)->attack[a].type != AT_STANDARD) continue; else { weapon *wp = preferred_weapon(ta, true); @@ -2272,7 +2272,7 @@ void do_attack(fighter * af) continue; } } - attack(b, ta, &(au->race->attack[a]), apr); + attack(b, ta, &(u_race(au)->attack[a]), apr); } } } @@ -2362,7 +2362,7 @@ double fleechance(unit * u) c += (eff_skill(u, SK_STEALTH, r) * 0.05); c += horsebonus(u); - if (u->race == new_race[RC_HALFLING]) { + if (u_race(u) == new_race[RC_HALFLING]) { c += 0.20; c = MIN(c, 0.90); } else { @@ -2652,8 +2652,8 @@ static void aftermath(battle * b) /* tote insgesamt: */ s->dead += dead; - /* Tote, die wiederbelebt werde können: */ - if (playerrace(df->unit->race)) { + /* Tote, die wiederbelebt werde koennen: */ + if (playerrace(u_race(df->unit))) { s->casualties += dead; } if (df->hits + df->kills) { @@ -2769,7 +2769,7 @@ static void aftermath(battle * b) } s->flee += df->run.number; - if (playerrace(du->race)) { + if (playerrace(u_race(du))) { /* tote im kampf werden zu regionsuntoten: * for each of them, a peasant will die as well */ dead_players += dead; @@ -3207,7 +3207,7 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) } /* Illusionen und Zauber kaempfen nicht */ - if (fval(u->race, RCF_ILLUSIONARY) || idle(u->faction) || u->number == 0) { + if (fval(u_race(u), RCF_ILLUSIONARY) || idle(u->faction) || u->number == 0) { return NULL; } if (s1 == NULL) { @@ -3233,7 +3233,7 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) set_attacker(fig); } else { building *bld = u->building; - if (bld && bld->sizeleft >= u->number && playerrace(u->race)) { + if (bld && bld->sizeleft >= u->number && playerrace(u_race(u))) { fig->building = bld; fig->building->sizeleft -= u->number; } @@ -3304,7 +3304,7 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) /* Für alle Waffengattungen wird bestimmt, wie viele der Personen mit * ihr kämpfen könnten, und was ihr Wert darin ist. */ - if (u->race->battle_flags & BF_EQUIPMENT) { + if (u_race(u)->battle_flags & BF_EQUIPMENT) { int oi = 0, di = 0; for (itm = u->items; itm && w != WMAX; itm = itm->next) { const weapon_type *wtype = resource2weapon(itm->type->rtype); @@ -3382,11 +3382,11 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) s1->size[statusrow(fig->status)] += u->number; s1->size[SUM_ROW] += u->number; - if (u->race->battle_flags & BF_NOBLOCK) { + if (u_race(u)->battle_flags & BF_NOBLOCK) { s1->nonblockers[statusrow(fig->status)] += u->number; } - if (fig->unit->race->flags & RCF_HORSE) { + if (u_race(fig->unit)->flags & RCF_HORSE) { fig->horses = fig->unit->number; fig->elvenhorses = 0; } else { @@ -3401,7 +3401,7 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) fig->elvenhorses = get_item(u, I_ELVENHORSE); } - if (u->race->battle_flags & BF_EQUIPMENT) { + if (u_race(u)->battle_flags & BF_EQUIPMENT) { for (itm = u->items; itm; itm = itm->next) { if (itm->type->rtype->atype) { if (i_canuse(u, itm->type)) { @@ -3430,18 +3430,18 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack) if (fig->horses) { if (!fval(r->terrain, CAVALRY_REGION) || r_isforest(r) || eff_skill(u, SK_RIDING, r) < CavalrySkill() - || u->race == new_race[RC_TROLL] || fval(u, UFL_WERE)) + || u_race(u) == new_race[RC_TROLL] || fval(u, UFL_WERE)) fig->horses = 0; } if (fig->elvenhorses) { - if (eff_skill(u, SK_RIDING, r) < 5 || u->race == new_race[RC_TROLL] + if (eff_skill(u, SK_RIDING, r) < 5 || u_race(u) == new_race[RC_TROLL] || fval(u, UFL_WERE)) fig->elvenhorses = 0; } /* Schauen, wie gut wir in Taktik sind. */ - if (tactics > 0 && u->race == new_race[RC_INSECT]) + if (tactics > 0 && u_race(u) == new_race[RC_INSECT]) tactics -= 1 - (int)log10(fig->side->size[SUM_ROW]); #ifdef TACTICS_MODIFIER if (tactics > 0 && statusrow(fig->status) == FIGHT_ROW) @@ -3936,9 +3936,9 @@ static bool start_battle(region * r, battle ** bp) continue; } - if ((u->race->battle_flags & BF_CANATTACK) == 0) { + if ((u_race(u)->battle_flags & BF_CANATTACK) == 0) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_no_attack", - "race", u->race)); + "race", u_race(u))); continue; } /** @@ -4209,7 +4209,7 @@ static void battle_flee(battle * b) /* keine Flucht von Schiffen auf hoher See */ continue; } - if (fval(u->race, RCF_UNDEAD) || u->race == new_race[RC_SHADOWKNIGHT]) { + if (fval(u_race(u), RCF_UNDEAD) || u_race(u) == new_race[RC_SHADOWKNIGHT]) { /* Untote fliehen nicht. Warum eigentlich? */ continue; } diff --git a/src/kernel/build.c b/src/kernel/build.c index 5726f4828..1a6f52a11 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -320,7 +320,7 @@ void build_road(region * r, unit * u, int size, direction_t d) if (size > 0) left = MIN(size, left); /* baumaximum anhand der rohstoffe */ - if (u->race == new_race[RC_STONEGOLEM]) { + if (u_race(u) == new_race[RC_STONEGOLEM]) { n = u->number * GOLEM_STONE; } else { n = get_pooled(u, oldresourcetype[R_STONE], GET_DEFAULT, left); @@ -360,7 +360,7 @@ void build_road(region * r, unit * u, int size, direction_t d) * maximum. */ rsetroad(r, d, rroad(r, d) + (short)n); - if (u->race == new_race[RC_STONEGOLEM]) { + if (u_race(u) == new_race[RC_STONEGOLEM]) { int golemsused = n / GOLEM_STONE; if (n % GOLEM_STONE != 0) { ++golemsused; @@ -904,7 +904,7 @@ create_ship(region * r, unit * u, const struct ship_type *newtype, int want, sh = new_ship(newtype, r, u->faction->locale); if (leave(u, false)) { - if (fval(u->race, RCF_CANSAIL)) { + if (fval(u_race(u), RCF_CANSAIL)) { u_set_ship(u, sh); } } diff --git a/src/kernel/config.c b/src/kernel/config.c index caf72d6cb..626043cc1 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -239,7 +239,7 @@ int LongHunger(const struct unit *u) if (!fval(u, UFL_HUNGER)) return false; #ifdef NEW_DAEMONHUNGER_RULE - if (u->race == new_race[RC_DAEMON]) + if (u_race(u) == new_race[RC_DAEMON]) return false; #endif } @@ -637,9 +637,9 @@ int shipspeed(const ship * sh, const unit * u) if (curse_active(get_curse(sh->attribs, nodrift_ct))) k += 1; - if (u->faction->race == u->race) { + if (u->faction->race == u_race(u)) { /* race bonus for this faction? */ - if (fval(u->race, RCF_SHIPSPEED)) { + if (fval(u_race(u), RCF_SHIPSPEED)) { k += 1; } } @@ -986,7 +986,7 @@ cansee(const faction * f, const region * r, const unit * u, int modifier) if (u->faction == f || omniscient(f)) { return true; - } else if (fval(u->race, RCF_INVISIBLE)) { + } else if (fval(u_race(u), RCF_INVISIBLE)) { return false; } else if (u->number == 0) { attrib *a = a_find(u->attribs, &at_creator); @@ -1040,7 +1040,7 @@ cansee(const faction * f, const region * r, const unit * u, int modifier) bool cansee_unit(const unit * u, const unit * target, int modifier) /* target->region kann != u->region sein, wenn es um durchreisen geht */ { - if (fval(target->race, RCF_INVISIBLE) || target->number == 0) + if (fval(u_race(target), RCF_INVISIBLE) || target->number == 0) return false; else if (target->faction == u->faction) return true; @@ -1083,7 +1083,7 @@ cansee_durchgezogen(const faction * f, const region * r, const unit * u, int n; unit *u2; - if (fval(u->race, RCF_INVISIBLE) || u->number == 0) + if (fval(u_race(u), RCF_INVISIBLE) || u->number == 0) return false; else if (u->faction == f) return true; @@ -1199,7 +1199,7 @@ int count_all(const faction * f) int n = 0; unit *u; for (u = f->units; u; u = u->nextF) { - if (playerrace(u->race)) { + if (playerrace(u_race(u))) { n += u->number; assert(f == u->faction); } @@ -1217,9 +1217,9 @@ int count_migrants(const faction * f) int n = 0; while (u) { assert(u->faction == f); - if (u->race != f->race && u->race != new_race[RC_ILLUSION] - && u->race != new_race[RC_SPELL] - && !!playerrace(u->race) && !(is_cursed(u->attribs, C_SLAVE, 0))) { + if (u_race(u) != f->race && u_race(u) != new_race[RC_ILLUSION] + && u_race(u) != new_race[RC_SPELL] + && !!playerrace(u_race(u)) && !(is_cursed(u->attribs, C_SLAVE, 0))) { n += u->number; } u = u->nextF; @@ -2345,8 +2345,8 @@ void remove_empty_units_in_region(region * r) } } } - if ((u->number == 0 && u->race != new_race[RC_SPELL]) || (u->age <= 0 - && u->race == new_race[RC_SPELL])) { + if ((u->number == 0 && u_race(u) != new_race[RC_SPELL]) || (u->age <= 0 + && u_race(u) == new_race[RC_SPELL])) { remove_unit(up, u); } if (*up == u) @@ -2380,7 +2380,7 @@ int weight(const unit * u) in_bag += w; } - n += u->number * u->race->weight; + n += u->number * u_race(u)->weight; w = get_item(u, I_BAG_OF_HOLDING) * BAGCAPACITY; if (w > in_bag) @@ -2407,9 +2407,9 @@ unsigned int guard_flags(const unit * u) #if GUARD_DISABLES_RECRUIT == 1 flags |= GUARD_RECRUIT; #endif - switch (old_race(u->race)) { + switch (old_race(u_race(u))) { case RC_ELF: - if (u->faction->race != u->race) + if (u->faction->race != u_race(u)) break; /* else fallthrough */ case RC_TREEMAN: @@ -2484,9 +2484,9 @@ bool hunger(int number, unit * u) if (damage == NULL) damage = "1d12+12"; } - if (rc != u->race) { - rcdamage = get_param(u->race->parameters, "hunger.damage"); - rc = u->race; + if (rc != u_race(u)) { + rcdamage = get_param(u_race(u)->parameters, "hunger.damage"); + rc = u_race(u); } while (number--) { @@ -2843,7 +2843,7 @@ int maintenance_cost(const struct unit *u) if (retval >= 0) return retval; } - return u->race->maintenance * u->number; + return u_race(u)->maintenance * u->number; } message *movement_error(unit * u, const char *token, order * ord, @@ -2928,7 +2928,7 @@ void add_income(unit * u, int type, int want, int qty) int produceexp(struct unit *u, skill_t sk, int n) { if (global.producexpchance > 0.0F) { - if (n == 0 || !playerrace(u->race)) + if (n == 0 || !playerrace(u_race(u))) return 0; learn_skill(u, sk, global.producexpchance); } diff --git a/src/kernel/config.h b/src/kernel/config.h index 23542caf5..acc67637b 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -448,7 +448,7 @@ extern "C" { extern struct attrib_type at_guard; extern void free_gamedata(void); #if 1 /* disable to count all units */ -# define count_unit(u) playerrace(u->race) +# define count_unit(u) playerrace(u_race(u)) #else # define count_unit(u) 1 #endif diff --git a/src/kernel/faction.c b/src/kernel/faction.c index ea02a62a1..e90a44264 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -243,7 +243,7 @@ unit *addplayer(region * r, faction * f) u = createunit(r, f, 1, f->race); equip_items(&u->faction->items, get_equipment("new_faction")); equip_unit(u, get_equipment("first_unit")); - sprintf(buffer, "first_%s", u->race->_name[0]); + sprintf(buffer, "first_%s", u_race(u)->_name[0]); equip_unit(u, get_equipment(buffer)); u->hp = unit_max_hp(u) * u->number; fset(u, UFL_ISNEW); @@ -314,8 +314,8 @@ void destroyfaction(faction * f) } else { region *r = u->region; - if (!fval(r->terrain, SEA_REGION) && !!playerrace(u->race)) { - const race *rc = u->race; + if (!fval(r->terrain, SEA_REGION) && !!playerrace(u_race(u))) { + const race *rc = u_race(u); int m = rmoney(r); if ((rc->ec_flags & ECF_REC_ETHEREAL) == 0) { diff --git a/src/kernel/item.c b/src/kernel/item.c index fd35f0776..38571ba08 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -100,7 +100,7 @@ static int res_changepeasants(unit * u, const resource_type * rtype, int delta) static int res_changeitem(unit * u, const resource_type * rtype, int delta) { int num; - if (rtype == oldresourcetype[R_STONE] && u->race == new_race[RC_STONEGOLEM] + if (rtype == oldresourcetype[R_STONE] && u_race(u) == new_race[RC_STONEGOLEM] && delta <= 0) { int reduce = delta / GOLEM_STONE; if (delta % GOLEM_STONE != 0) @@ -108,7 +108,7 @@ static int res_changeitem(unit * u, const resource_type * rtype, int delta) scale_number(u, u->number + reduce); num = u->number; } else if (rtype == oldresourcetype[R_IRON] - && u->race == new_race[RC_IRONGOLEM] && delta <= 0) { + && u_race(u) == new_race[RC_IRONGOLEM] && delta <= 0) { int reduce = delta / GOLEM_IRON; if (delta % GOLEM_IRON != 0) --reduce; @@ -708,7 +708,7 @@ const char *itemnames[MAXITEMS] = { static int mod_elves_only(const unit * u, const region * r, skill_t sk, int value) { - if (u->race == new_race[RC_ELF]) + if (u_race(u) == new_race[RC_ELF]) return value; unused(r); return -118; @@ -717,7 +717,7 @@ mod_elves_only(const unit * u, const region * r, skill_t sk, int value) static int mod_dwarves_only(const unit * u, const region * r, skill_t sk, int value) { - if (u->race == new_race[RC_DWARF]) + if (u_race(u) == new_race[RC_DWARF]) return value; unused(r); return -118; @@ -838,11 +838,11 @@ static int use_bloodpotion(struct unit *u, const struct item_type *itype, int amount, struct order *ord) { - if (u->race == new_race[RC_DAEMON]) { + if (u_race(u) == new_race[RC_DAEMON]) { change_effect(u, itype->rtype->ptype, 100 * amount); } else { const race *irace = u_irace(u); - if (irace == u->race) { + if (irace == u_race(u)) { static race *rcfailure; if (!rcfailure) { rcfailure = rc_find("smurf"); @@ -850,14 +850,14 @@ use_bloodpotion(struct unit *u, const struct item_type *itype, int amount, rcfailure = rc_find("toad"); } if (rcfailure) { - trigger *trestore = trigger_changerace(u, u->race, irace); + trigger *trestore = trigger_changerace(u, u_race(u), irace); if (trestore) { int duration = 2 + rng_int() % 8; add_trigger(&u->attribs, "timer", trigger_timeout(duration, trestore)); u->irace = NULL; - u->race = rcfailure; + u_setrace(u, rcfailure); } } } diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 3f388450b..2ba55455b 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -554,8 +554,8 @@ const spell *get_combatspell(const unit * u, int nr) m = get_mage(u); if (m) { return m->combatspells[nr].sp; - } else if (u->race->precombatspell != NULL) { - return u->race->precombatspell; + } else if (u_race(u)->precombatspell != NULL) { + return u_race(u)->precombatspell; } return NULL; @@ -706,7 +706,7 @@ static int use_item_aura(const region * r, const unit * u) int sk, n; sk = eff_skill(u, SK_MAGIC, r); - n = (int)(sk * sk * u->race->maxaura / 4); + n = (int)(sk * sk * u_race(u)->maxaura / 4); return n; } @@ -719,7 +719,7 @@ int max_spellpoints(const region * r, const unit * u) double divisor = 1.2; sk = eff_skill(u, SK_MAGIC, r); - msp = u->race->maxaura * (pow(sk, potenz) / divisor + 1) + get_spchange(u); + msp = u_race(u)->maxaura * (pow(sk, potenz) / divisor + 1) + get_spchange(u); if (get_item(u, I_AURAKULUM) > 0) { msp += use_item_aura(r, u); @@ -1025,7 +1025,7 @@ spellpower(region * r, unit * u, const spell * sp, int cast_level, if (elf_power < 0) { elf_power = get_param_int(global.parameters, "rules.magic.elfpower", 0); } - if (elf_power && u->race == new_race[RC_ELF] && r_isforest(r)) { + if (elf_power && u_race(u) == new_race[RC_ELF] && r_isforest(r)) { ++force; } @@ -1110,7 +1110,7 @@ double magic_resistance(unit * target) const curse_type * ct_goodresist = 0, * ct_badresist = 0; /* Bonus durch Rassenmagieresistenz */ - double probability = target->race->magres; + double probability = u_race(target)->magres; assert(target->number > 0); /* Magier haben einen Resistenzbonus vom Magietalent * 5% */ @@ -1354,7 +1354,7 @@ static void do_fumble(castorder * co) * The list of things to happen are attached to a timeout * trigger and that's added to the triggerlit of the mage gone toad. */ - trigger *trestore = trigger_changerace(u, u->race, u->irace); + trigger *trestore = trigger_changerace(u, u_race(u), u->irace); if (chance(0.7)) { const item_type *it_toadslime = it_find("toadslime"); @@ -1367,7 +1367,7 @@ static void do_fumble(castorder * co) if (duration < 2) duration = 2; add_trigger(&u->attribs, "timer", trigger_timeout(duration, trestore)); - u->race = new_race[RC_TOAD]; + u_setrace(u, new_race[RC_TOAD]); u->irace = NULL; ADDMSG(&r->msgs, msg_message("patzer6", "unit region spell", u, r, sp)); break; @@ -1431,7 +1431,7 @@ static double regeneration(unit * u) sk = effskill(u, SK_MAGIC); /* Rassenbonus/-malus */ - d = pow(sk, potenz) * u->race->regaura / divisor; + d = pow(sk, potenz) * u_race(u)->regaura / divisor; d++; /* Einfluss von Artefakten */ @@ -2594,8 +2594,8 @@ static castorder *cast_cmd(unit * u, order * ord) * normalerweise nur Meermenschen, ausgenommen explizit als * OCEANCASTABLE deklarierte Sprüche */ if (fval(r->terrain, SEA_REGION)) { - if (u->race != new_race[RC_AQUARIAN] - && !fval(u->race, RCF_SWIM) + if (u_race(u) != new_race[RC_AQUARIAN] + && !fval(u_race(u), RCF_SWIM) && !(sp->sptyp & OCEANCASTABLE)) { /* Fehlermeldung */ ADDMSG(&u->faction->msgs, msg_message("spellfail_onocean", @@ -2732,10 +2732,10 @@ void magic(void) for (u = r->units; u; u = u->next) { order *ord; - if (u->number <= 0 || u->race == new_race[RC_SPELL]) + if (u->number <= 0 || u_race(u) == new_race[RC_SPELL]) continue; - if (u->race == new_race[RC_INSECT] && r_insectstalled(r) && + if (u_race(u) == new_race[RC_INSECT] && r_insectstalled(r) && !is_cursed(u->attribs, C_KAELTESCHUTZ, 0)) continue; diff --git a/src/kernel/move.c b/src/kernel/move.c index 46a1cadfd..ed6131d94 100644 --- a/src/kernel/move.c +++ b/src/kernel/move.c @@ -196,7 +196,7 @@ static bool entrance_allowed(const struct unit *u, const struct region *r) int personcapacity(const unit * u) { - int cap = u->race->weight + u->race->capacity; + int cap = u_race(u)->weight + u_race(u)->capacity; return cap; } @@ -254,7 +254,7 @@ static int ridingcapacity(unit * u) ** von zwei Pferden gezogen wird */ animals = MIN(animals, effskill(u, SK_RIDING) * u->number * 2); - if (fval(u->race, RCF_HORSE)) + if (fval(u_race(u), RCF_HORSE)) animals += u->number; /* maximal diese Pferde können zum Ziehen benutzt werden */ @@ -276,7 +276,7 @@ int walkingcapacity(const struct unit *u) * die Leute tragen */ pferde_fuer_wagen = MIN(animals, effskill(u, SK_RIDING) * u->number * 4); - if (fval(u->race, RCF_HORSE)) { + if (fval(u_race(u), RCF_HORSE)) { animals += u->number; people = 0; } else { @@ -288,7 +288,7 @@ int walkingcapacity(const struct unit *u) n = wagen_mit_pferden * vcap; - if (u->race == new_race[RC_TROLL]) { + if (u_race(u) == new_race[RC_TROLL]) { /* 4 Trolle ziehen einen Wagen. */ /* Unbesetzte Wagen feststellen */ wagen_ohne_pferde = vehicles - wagen_mit_pferden; @@ -340,7 +340,7 @@ static int canwalk(unit * u) get_transporters(u->items, &animals, &acap, &vehicles, &vcap); maxwagen = effskill(u, SK_RIDING) * u->number * 2; - if (u->race == new_race[RC_TROLL]) { + if (u_race(u) == new_race[RC_TROLL]) { maxwagen = MAX(maxwagen, u->number / 4); } maxpferde = effskill(u, SK_RIDING) * u->number * 4 + u->number; @@ -370,7 +370,7 @@ bool canfly(unit * u) if (get_item(u, I_PEGASUS) >= u->number && effskill(u, SK_RIDING) >= 4) return true; - if (fval(u->race, RCF_FLY)) + if (fval(u_race(u), RCF_FLY)) return true; if (get_movement(&u->attribs, MV_FLY)) @@ -384,10 +384,10 @@ bool canswim(unit * u) if (get_item(u, I_DOLPHIN) >= u->number && effskill(u, SK_RIDING) >= 4) return true; - if (u->race->flags & RCF_FLY) + if (u_race(u)->flags & RCF_FLY) return true; - if (u->race->flags & RCF_SWIM) + if (u_race(u)->flags & RCF_SWIM) return true; if (get_movement(&u->attribs, MV_FLY)) @@ -425,14 +425,14 @@ static int canride(unit * u) maxunicorns = (skill / 5) * u->number; maxhorses = skill * u->number * 2; - if (!(u->race->flags & RCF_HORSE) + if (!(u_race(u)->flags & RCF_HORSE) && ((horses == 0 && unicorns == 0) || horses > maxhorses || unicorns > maxunicorns)) { return 0; } if (ridingcapacity(u) - eff_weight(u) >= 0) { - if (horses == 0 && unicorns >= u->number && !(u->race->flags & RCF_HORSE)) { + if (horses == 0 && unicorns >= u->number && !(u_race(u)->flags & RCF_HORSE)) { return 2; } return 1; @@ -614,7 +614,7 @@ ship *move_ship(ship * sh, region * from, region * to, region_list * route) static bool is_freezing(const unit * u) { - if (u->race != new_race[RC_INSECT]) + if (u_race(u) != new_race[RC_INSECT]) return false; if (is_cursed(u->attribs, C_KAELTESCHUTZ, 0)) return false; @@ -828,7 +828,7 @@ static unit *bewegung_blockiert_von(unit * reisender, region * r) bool contact = false; unit *guard = NULL; - if (fval(reisender->race, RCF_ILLUSIONARY)) + if (fval(u_race(reisender), RCF_ILLUSIONARY)) return NULL; for (u = r->units; u && !contact; u = u->next) { if (is_guard(u, GUARD_TRAVELTHRU)) { @@ -895,7 +895,7 @@ static bool is_guardian_r(const unit * guard) if ((guard->flags & UFL_GUARD) == 0) return false; - if (!armedmen(guard, true) && !fval(guard->race, RCF_UNARMEDGUARD)) + if (!armedmen(guard, true) && !fval(u_race(guard), RCF_UNARMEDGUARD)) return false; return true; } @@ -1096,7 +1096,7 @@ static bool transport(unit * ut, unit * u) static bool can_move(const unit * u) { - if (u->race->flags & RCF_CANNOTMOVE) + if (u_race(u)->flags & RCF_CANNOTMOVE) return false; if (get_movement(&u->attribs, MV_CANNOTMOVE)) return false; @@ -1318,11 +1318,11 @@ static int movement_speed(unit * u) int mp; static const curse_type *speed_ct; static bool init = false; - double dk = u->race->speed; + double dk = u_race(u)->speed; assert(u->number); /* dragons have a fixed speed, and no other effects work on them: */ - switch (old_race(u->race)) { + switch (old_race(u_race(u))) { case RC_DRAGON: case RC_WYRM: case RC_FIREDRAGON: @@ -1371,7 +1371,7 @@ static int movement_speed(unit * u) /* Im Astralraum sind Tyb und Ill-Magier doppelt so schnell. * Nicht kumulativ mit anderen Beschleunigungen! */ - if (mp * dk <= BP_WALKING * u->race->speed && is_astral(u->region) + 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) { @@ -1436,11 +1436,11 @@ static const region_list *travel_route(unit * u, /* check movement from/to oceans. * aquarian special, flying units, horses, the works */ - if ((u->race->flags & RCF_FLY) == 0) { + if ((u_race(u)->flags & RCF_FLY) == 0) { if (!fval(next->terrain, SEA_REGION)) { /* next region is land */ if (fval(current->terrain, SEA_REGION)) { - int moving = u->race->flags & (RCF_SWIM | RCF_WALK | RCF_COASTAL); + int moving = u_race(u)->flags & (RCF_SWIM | RCF_WALK | RCF_COASTAL); /* Die Einheit kann nicht fliegen, ist im Ozean, und will an Land */ if (moving != (RCF_SWIM | RCF_WALK) && (moving & RCF_COASTAL) == 0) { /* can't swim+walk and isn't allowed to enter coast from sea */ @@ -1449,7 +1449,7 @@ static const region_list *travel_route(unit * u, break; } landing = true; - } else if ((u->race->flags & RCF_WALK) == 0) { + } else if ((u_race(u)->flags & RCF_WALK) == 0) { /* Spezialeinheiten, die nicht laufen können. */ ADDMSG(&u->faction->msgs, msg_message("detectocean", "unit region", u, next)); @@ -1497,7 +1497,7 @@ static const region_list *travel_route(unit * u, } /* illusionary units disappear in antimagic zones */ - if (fval(u->race, RCF_ILLUSIONARY)) { + if (fval(u_race(u), RCF_ILLUSIONARY)) { curse *c = get_curse(next->attribs, ct_find("antimagiczone")); if (curse_active(c)) { curse_changevigour(&next->attribs, c, (float)-u->number); @@ -1515,7 +1515,7 @@ static const region_list *travel_route(unit * u, } /* unit is an insect and cannot move into a glacier */ - if (u->race == new_race[RC_INSECT]) { + if (u_race(u) == new_race[RC_INSECT]) { if (r_insectstalled(next) && is_freezing(u)) { ADDMSG(&u->faction->msgs, msg_message("detectforbidden", "unit region", u, next)); @@ -2097,7 +2097,7 @@ static void travel(unit * u, region_list ** routep) return; } } - if (u->ship && u->race->flags & RCF_SWIM) { + if (u->ship && u_race(u)->flags & RCF_SWIM) { cmistake(u, u->thisorder, 143, MSG_MOVE); return; } diff --git a/src/kernel/names.c b/src/kernel/names.c index d44c49132..a0089829b 100644 --- a/src/kernel/names.c +++ b/src/kernel/names.c @@ -215,9 +215,9 @@ const char *silbe3[SIL3] = { const char *generic_name(const unit * u) { if (u->no == 1) { - return LOC(u->faction->locale, mkname("race", u->race->_name[0])); + return LOC(u->faction->locale, mkname("race", u_race(u)->_name[0])); } - return LOC(u->faction->locale, mkname("race", u->race->_name[1])); + return LOC(u->faction->locale, mkname("race", u_race(u)->_name[1])); } const char *dragon_name(const unit * u) diff --git a/src/kernel/pool.c b/src/kernel/pool.c index b150f9f9f..5fdc88e1f 100644 --- a/src/kernel/pool.c +++ b/src/kernel/pool.c @@ -55,9 +55,9 @@ int get_resource(const unit * u, const resource_type * rtype) return i; } if (itype != NULL) { - if (itype == olditemtype[R_STONE] && (u->race->flags & RCF_STONEGOLEM)) { + if (itype == olditemtype[R_STONE] && (u_race(u)->flags & RCF_STONEGOLEM)) { return u->number * GOLEM_STONE; - } else if (itype == olditemtype[R_IRON] && (u->race->flags & RCF_IRONGOLEM)) { + } else if (itype == olditemtype[R_IRON] && (u_race(u)->flags & RCF_IRONGOLEM)) { return u->number * GOLEM_IRON; } else { const item *i = *i_findc(&u->items, itype); @@ -98,9 +98,9 @@ int get_reservation(const unit * u, const resource_type * rtype) { struct reservation *res = u->reservations; - if (rtype == oldresourcetype[R_STONE] && (u->race->flags & RCF_STONEGOLEM)) + if (rtype == oldresourcetype[R_STONE] && (u_race(u)->flags & RCF_STONEGOLEM)) return (u->number * GOLEM_STONE); - if (rtype == oldresourcetype[R_IRON] && (u->race->flags & RCF_IRONGOLEM)) + if (rtype == oldresourcetype[R_IRON] && (u_race(u)->flags & RCF_IRONGOLEM)) return (u->number * GOLEM_IRON); while (res && res->type != rtype) res = res->next; @@ -166,7 +166,7 @@ get_pooled(const unit * u, const resource_type * rtype, unsigned int mode, region *r = u->region; int have = get_resource(u, rtype); - if ((u->race->ec_flags & GETITEM) == 0) { + if ((u_race(u)->ec_flags & GETITEM) == 0) { mode &= (GET_SLACK | GET_RESERVE); } @@ -211,7 +211,7 @@ use_pooled(unit * u, const resource_type * rtype, unsigned int mode, int count) region *r = u->region; int n = 0, have = get_resource(u, rtype); - if ((u->race->ec_flags & GETITEM) == 0) { + if ((u_race(u)->ec_flags & GETITEM) == 0) { mode &= (GET_SLACK | GET_RESERVE); } diff --git a/src/kernel/reports.c b/src/kernel/reports.c index 54cdbb011..38c6fddae 100644 --- a/src/kernel/reports.c +++ b/src/kernel/reports.c @@ -157,7 +157,7 @@ report_item(const unit * owner, const item * i, const faction * viewer, int pp = i->number / owner->number; if (number) *number = 1; - if (pp > 50000 && dragonrace(owner->race)) { + if (pp > 50000 && dragonrace(u_race(owner))) { if (name) *name = locale_string(viewer->locale, "dragonhoard"); if (basename) @@ -323,15 +323,15 @@ void report_race(const struct unit *u, const char **name, const char **illusion) { if (illusion) { const race *irace = u_irace(u); - if (irace && irace != u->race) { + if (irace && irace != u_race(u)) { *illusion = irace->_name[0]; } else { *illusion = NULL; } } if (name) { - *name = u->race->_name[0]; - if (fval(u->race, RCF_SHAPESHIFTANY)) { + *name = u_race(u)->_name[0]; + if (fval(u_race(u), RCF_SHAPESHIFTANY)) { const char *str = get_racename(u->attribs); if (str) *name = str; @@ -561,11 +561,11 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, bytes = (int)strlcpy(bufp, pzTmp, size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - if (u->faction == f && fval(u->race, RCF_SHAPESHIFTANY)) { + if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) { bytes = (int)strlcpy(bufp, " (", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, racename(f->locale, u, u->race), size); + bytes = (int)strlcpy(bufp, racename(f->locale, u, u_race(u)), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); if (size > 1) { @@ -578,11 +578,11 @@ bufunit(const faction * f, const unit * u, int indent, int mode, char *buf, bytes = (int)strlcpy(bufp, racename(f->locale, u, irace), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - if (u->faction == f && irace != u->race) { + if (u->faction == f && irace != u_race(u)) { bytes = (int)strlcpy(bufp, " (", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, racename(f->locale, u, u->race), size); + bytes = (int)strlcpy(bufp, racename(f->locale, u, u_race(u)), size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); if (size > 1) { @@ -1538,7 +1538,7 @@ static void prepare_reports(void) prepare_lighthouse(u->building, u->faction); } - if (u->race != new_race[RC_SPELL] || u->number == RS_FARVISION) { + if (u_race(u) != new_race[RC_SPELL] || u->number == RS_FARVISION) { if (fval(u, UFL_DISBELIEVES)) { add_seen(u->faction->seen, r, see_unit, true); } else { @@ -1788,7 +1788,7 @@ int reports(void) static variant var_copy_string(variant x) { - x.v = strdup((const char *)x.v); + x.v = x.v ? strdup((const char *)x.v) : 0; return x; } diff --git a/src/kernel/save.c b/src/kernel/save.c index 1ba845cc0..e51ba4c9a 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -256,7 +256,7 @@ static unit *unitorders(FILE * F, int enc, struct faction *f) i = getid(); u = findunitg(i, NULL); - if (u && u->race == new_race[RC_SPELL]) + if (u && u_race(u) == new_race[RC_SPELL]) return NULL; if (u && u->faction == f) { order **ordp; @@ -764,8 +764,8 @@ unit *read_unit(struct storage *store) } else { store->r_tok_buf(store, rname, sizeof(rname)); } - u->race = rc_find(rname); - assert(u->race); + u_setrace(u, rc_find(rname)); + if (store->version < STORAGE_VERSION) { store->r_str_buf(store, rname, sizeof(rname)); } else { @@ -776,8 +776,8 @@ unit *read_unit(struct storage *store) else u->irace = NULL; - if (u->race->describe) { - const char *rcdisp = u->race->describe(u, u->faction->locale); + if (u_race(u)->describe) { + const char *rcdisp = u_race(u)->describe(u, u->faction->locale); if (u->display && rcdisp) { /* see if the data file contains old descriptions */ if (strcmp(rcdisp, u->display) == 0) { @@ -867,7 +867,7 @@ unit *read_unit(struct storage *store) } set_order(&u->thisorder, NULL); - assert(u->race); + assert(u_race(u)); while ((sk = (skill_t) store->r_int(store)) != NOSKILL) { int level = store->r_int(store); int weeks = store->r_int(store); @@ -901,8 +901,8 @@ void write_unit(struct storage *store, const unit * u) store->w_str(store, u->display ? (const char *)u->display : ""); store->w_int(store, u->number); store->w_int(store, u->age); - store->w_tok(store, u->race->_name[0]); - store->w_tok(store, (irace && irace != u->race) ? irace->_name[0] : ""); + store->w_tok(store, u_race(u)->_name[0]); + store->w_tok(store, (irace && irace != u_race(u)) ? irace->_name[0] : ""); write_building_reference(u->building, store); write_ship_reference(u->ship, store); store->w_int(store, u->status); @@ -934,7 +934,7 @@ void write_unit(struct storage *store, const unit * u) store->w_str(store, ""); store->w_brk(store); - assert(u->race); + assert(u_race(u)); for (i = 0; i != u->skill_size; ++i) { skill *sv = u->skills + i; @@ -1497,7 +1497,7 @@ static void repair_unit(unit * u) { static const race * rctoad; if (!rctoad) rctoad = rc_find("toad"); - if (u->race==rctoad) { + if (u_race(u)==rctoad) { int found = 0; attrib * a = a_find(u->attribs, &at_eventhandler); while (!found && a && a->type==&at_eventhandler) { @@ -1512,7 +1512,7 @@ static void repair_unit(unit * u) { a = a->next; } if (!found) { - u->race = u->faction->race; + u_setrace(u, u->faction->race); log_warning("This toad did not have a changerace trigger: %s\n", unitname(u)); } } diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 96745c59e..99e26b9a9 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -277,7 +277,7 @@ void getshipweight(const ship * sh, int *sweight, int *scabins) if (u->ship == sh) { *sweight += weight(u); if (sh->type->cabins) { - int pweight = u->number * u->race->weight; + int pweight = u->number * u_race(u)->weight; /* weight goes into number of cabins, not cargo */ *scabins += pweight; *sweight -= pweight; diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 5aee29ab7..5f7f093f5 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -183,7 +183,7 @@ static buddy *get_friends(const unit * u, int *numfriends) buddy *nf, **fr = &friends; /* some units won't take stuff: */ - if (u2->race->ec_flags & GETITEM) { + if (u_race(u2)->ec_flags & GETITEM) { while (*fr && (*fr)->faction->no < u2->faction->no) fr = &(*fr)->next; nf = *fr; @@ -195,9 +195,9 @@ static buddy *get_friends(const unit * u, int *numfriends) nf->number = 0; *fr = nf; } else if (nf->faction == u2->faction - && (u2->race->ec_flags & GIVEITEM)) { + && (u_race(u2)->ec_flags & GIVEITEM)) { /* we don't like to gift it to units that won't give it back */ - if ((nf->unit->race->ec_flags & GIVEITEM) == 0) { + if ((u_race(nf->unit)->ec_flags & GIVEITEM) == 0) { nf->unit = u2; } } @@ -234,9 +234,9 @@ int gift_items(unit * u, int flags) flags -= GIFT_SELF; } - if (u->items == NULL || fval(u->race, RCF_ILLUSIONARY)) + if (u->items == NULL || fval(u_race(u), RCF_ILLUSIONARY)) return 0; - if ((u->race->ec_flags & GIVEITEM) == 0) + if ((u_race(u)->ec_flags & GIVEITEM) == 0) return 0; /* at first, I should try giving my crap to my own units in this region */ @@ -245,9 +245,9 @@ int gift_items(unit * u, int flags) for (u2 = r->units; u2; u2 = u2->next) { if (u2 != u && u2->faction == u->faction && u2->number > 0) { /* some units won't take stuff: */ - if (u2->race->ec_flags & GETITEM) { + if (u_race(u2)->ec_flags & GETITEM) { /* we don't like to gift it to units that won't give it back */ - if (u2->race->ec_flags & GIVEITEM) { + if (u_race(u2)->ec_flags & GIVEITEM) { i_merge(&u2->items, &u->items); u->items = NULL; break; @@ -324,7 +324,7 @@ void make_zombie(unit * u) { u_setfaction(u, get_monsters()); scale_number(u, 1); - u->race = new_race[RC_ZOMBIE]; + u_setrace(u, new_race[RC_ZOMBIE]); u->irace = NULL; } @@ -438,8 +438,8 @@ const char *u_description(const unit * u, const struct locale *lang) { if (u->display && u->display[0]) { return u->display; - } else if (u->race->describe) { - return u->race->describe(u, lang); + } else if (u_race(u)->describe) { + return u_race(u)->describe(u, lang); } return NULL; } @@ -858,9 +858,9 @@ const struct race *urace(const struct unit *u) bool can_survive(const unit * u, const region * r) { - if ((fval(r->terrain, WALK_INTO) && (u->race->flags & RCF_WALK)) - || (fval(r->terrain, SWIM_INTO) && (u->race->flags & RCF_SWIM)) - || (fval(r->terrain, FLY_INTO) && (u->race->flags & RCF_FLY))) { + if ((fval(r->terrain, WALK_INTO) && (u_race(u)->flags & RCF_WALK)) + || (fval(r->terrain, SWIM_INTO) && (u_race(u)->flags & RCF_SWIM)) + || (fval(r->terrain, FLY_INTO) && (u_race(u)->flags & RCF_FLY))) { static const curse_type *ctype = NULL; if (has_horses(u) && !fval(r->terrain, WALK_INTO)) @@ -868,7 +868,7 @@ bool can_survive(const unit * u, const region * r) if (!ctype) ctype = ct_find("holyground"); - if (fval(u->race, RCF_UNDEAD) && curse_active(get_curse(r->attribs, ctype))) + if (fval(u_race(u), RCF_UNDEAD) && curse_active(get_curse(r->attribs, ctype))) return false; return true; @@ -1017,8 +1017,8 @@ void transfermen(unit * u, unit * u2, int n) a = an; } } else if (r->land) { - if ((u->race->ec_flags & ECF_REC_ETHEREAL) == 0) { - const race *rc = u->race; + if ((u_race(u)->ec_flags & ECF_REC_ETHEREAL) == 0) { + const race *rc = u_race(u); if (rc->ec_flags & ECF_REC_HORSES) { /* Zentauren an die Pferde */ int h = rhorses(r) + n; rsethorses(r, h); @@ -1111,7 +1111,7 @@ void set_number(unit * u, int count) if (count == 0) { u->flags &= ~(UFL_HERO); } - if (u->faction && playerrace(u->race)) { + if (u->faction && playerrace(u_race(u))) { u->faction->num_people += count - u->number; } u->number = (unsigned short)count; @@ -1295,7 +1295,7 @@ get_modifier(const unit * u, skill_t sk, int level, const region * r, } } - skill += rc_skillmod(u->race, r, sk); + skill += rc_skillmod(u_race(u), r, sk); skill += att_modification(u, sk); if (!noitem) { @@ -1403,12 +1403,12 @@ static void createunitid(unit * u, int id) void name_unit(unit * u) { - if (u->race->generate_name) { - const char *gen_name = u->race->generate_name(u); + if (u_race(u)->generate_name) { + const char *gen_name = u_race(u)->generate_name(u); if (gen_name) { unit_setname(u, gen_name); } else { - unit_setname(u, racename(u->faction->locale, u, u->race)); + unit_setname(u, racename(u->faction->locale, u, u_race(u))); } } else { char name[32]; @@ -1458,7 +1458,7 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace, } } u_seteffstealth(u, -1); - u->race = urace; + u_setrace(u, urace); u->irace = NULL; set_number(u, number); @@ -1493,7 +1493,7 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace, if (creator->building) { u_set_building(u, creator->building); } - if (creator->ship && fval(u->race, RCF_CANSAIL)) { + if (creator->ship && fval(u_race(u), RCF_CANSAIL)) { u_set_ship(u, creator->ship); } } @@ -1514,7 +1514,7 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace, } /* Daemonentarnung */ set_racename(&u->attribs, get_racename(creator->attribs)); - if (fval(u->race, RCF_SHAPESHIFT) && fval(creator->race, RCF_SHAPESHIFT)) { + if (fval(u_race(u), RCF_SHAPESHIFT) && fval(u_race(creator), RCF_SHAPESHIFT)) { u->irace = creator->irace; } @@ -1661,7 +1661,7 @@ int unit_max_hp(const unit * u) rules_stamina = get_param_int(global.parameters, "rules.stamina", STAMINA_AFFECTS_HP); } - h = u->race->hitpoints; + h = u_race(u)->hitpoints; if (heal_ct == NULL) heal_ct = ct_find("healingzone"); @@ -1733,6 +1733,17 @@ const struct race *u_irace(const struct unit *u) return u->race; } +const struct race *u_race(const struct unit *u) +{ + return u->race; +} + +void u_setrace(struct unit *u, const struct race *rc) +{ + assert(rc); + u->race = rc; +} + void unit_add_spell(unit * u, sc_mage * m, struct spell * sp, int level) { sc_mage *mage = m ? m : get_mage(u); diff --git a/src/kernel/unit.h b/src/kernel/unit.h index 292e6a759..ea290f8b1 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -128,6 +128,8 @@ extern "C" { void u_seteffstealth(struct unit *u, int value); int u_geteffstealth(const struct unit *u); const struct race *u_irace(const struct unit *u); + const struct race *u_race(const struct unit *u); + void u_setrace(struct unit *u, const struct race *); struct building *usiege(const struct unit *u); void usetsiege(struct unit *u, const struct building *b); diff --git a/src/modules/score.c b/src/modules/score.c index c02d167c4..062479432 100644 --- a/src/modules/score.c +++ b/src/modules/score.c @@ -106,13 +106,13 @@ void score(void) int i; faction *f = u->faction; - if (f == NULL || u->race == new_race[RC_SPELL] - || u->race == new_race[RC_BIRTHDAYDRAGON]) { + if (f == NULL || u_race(u) == new_race[RC_SPELL] + || u_race(u) == new_race[RC_BIRTHDAYDRAGON]) { continue; } - if (old_race(u->race) <= RC_AQUARIAN) { - f->score += (u->race->recruitcost * u->number) / 50; + if (old_race(u_race(u)) <= RC_AQUARIAN) { + f->score += (u_race(u)->recruitcost * u->number) / 50; } f->score += get_money(u) / 50; for (itm = u->items; itm; itm = itm->next) { diff --git a/src/triggers/changerace.c b/src/triggers/changerace.c index 122384fb4..a78ac2d55 100644 --- a/src/triggers/changerace.c +++ b/src/triggers/changerace.c @@ -66,7 +66,7 @@ static int changerace_handle(trigger * t, void *data) changerace_data *td = (changerace_data *) t->data.v; if (td->u) { if (td->race != NULL) - td->u->race = td->race; + u_setrace(td->u, td->race); if (td->irace != NULL) td->u->irace = td->irace; } else { @@ -108,7 +108,7 @@ trigger *trigger_changerace(struct unit * u, const struct race * prace, trigger *t = t_new(&tt_changerace); changerace_data *td = (changerace_data *) t->data.v; - assert(u->race == u_irace(u) || "!changerace-triggers cannot stack!"); + assert(u_race(u) == u_irace(u) || "!changerace-triggers cannot stack!"); td->u = u; td->race = prace; td->irace = irace; From d817345e3fc591c21b0c24fda052d1c91a35c74b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 2 May 2013 03:46:58 +0200 Subject: [PATCH 395/400] make unit::race private --- src/kernel/unit.c | 8 ++++---- src/kernel/unit.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 5f7f093f5..f1808f780 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -853,7 +853,7 @@ bool leave(unit * u, bool force) const struct race *urace(const struct unit *u) { - return u->race; + return u->race_; } bool can_survive(const unit * u, const region * r) @@ -1730,18 +1730,18 @@ const struct race *u_irace(const struct unit *u) if (u->irace && skill_enabled[SK_STEALTH]) { return u->irace; } - return u->race; + return u->race_; } const struct race *u_race(const struct unit *u) { - return u->race; + return u->race_; } void u_setrace(struct unit *u, const struct race *rc) { assert(rc); - u->race = rc; + u->race_ = rc; } void unit_add_spell(unit * u, sc_mage * m, struct spell * sp, int level) diff --git a/src/kernel/unit.h b/src/kernel/unit.h index ea290f8b1..ebaab56f5 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -102,7 +102,7 @@ extern "C" { struct order *old_orders; /* race and illusionary race */ - const struct race *race; + const struct race *race_; const struct race *irace; unsigned int flags; From ebf9fe2c67d17d23ab1a6e0395aedfbb3541f2d4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 2 May 2013 06:07:42 +0200 Subject: [PATCH 396/400] unit repair is broken, kill it http://bugs.eressea.de/view.php?id=1970 --- src/kernel/save.c | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/src/kernel/save.c b/src/kernel/save.c index e51ba4c9a..c2a0ac7a9 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1493,31 +1493,6 @@ void writefaction(struct storage *store, const faction * f) write_spellbook(f->spellbook, store); } -static void repair_unit(unit * u) { - static const race * rctoad; - if (!rctoad) rctoad = rc_find("toad"); - - if (u_race(u)==rctoad) { - int found = 0; - attrib * a = a_find(u->attribs, &at_eventhandler); - while (!found && a && a->type==&at_eventhandler) { - struct trigger ** tlist = get_triggers(a, "timer"); - while (!found && tlist && *tlist) { - trigger * t = *tlist; - if (strcmp("changerace", t->type->name)==0) { - found = 1; - } - tlist = &t->next; - } - a = a->next; - } - if (!found) { - u_setrace(u, u->faction->race); - log_warning("This toad did not have a changerace trigger: %s\n", unitname(u)); - } - } -} - int readgame(const char *filename, int mode, int backup) { int i, n, p; @@ -1743,7 +1718,6 @@ int readgame(const char *filename, int mode, int backup) unit *u = read_unit(store); sc_mage *mage; - repair_unit(u); assert(u->region == NULL); u->region = r; *up = u; From 1e433b9fa690572f1d68411395b1b1f6251a9c7b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 3 May 2013 09:53:06 -0700 Subject: [PATCH 397/400] this should not be doing the find_package, that happens in the server --- src/bindings/CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/bindings/CMakeLists.txt b/src/bindings/CMakeLists.txt index 56310c2d3..734c0cf71 100755 --- a/src/bindings/CMakeLists.txt +++ b/src/bindings/CMakeLists.txt @@ -11,9 +11,6 @@ set (BINDINGS_LIBRARY ${PROJECT_NAME} CACHE INTERNAL "Eressea Lua Bindings") find_package (Lua 5 REQUIRED) find_package (ToLua REQUIRED) -find_package (LibXml2 REQUIRED) -find_package (Curses REQUIRED) -find_package (SQLite3 REQUIRED) include_directories (${ERESSEA_INCLUDE_DIR}) include_directories (${CRITBIT_INCLUDE_DIR}) From f76dfc71c9da6a2eddaee886fff6b38d08372423 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 4 May 2013 11:26:51 +0200 Subject: [PATCH 398/400] find_package goes into the main CMakeLists.txt, not needed here. kill old top-level CMakeLists.txt, also --- CMakeLists.txt | 7 ------- src/CMakeLists.txt | 6 ------ 2 files changed, 13 deletions(-) delete mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index b04b2a5ab..000000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -cmake_minimum_required(VERSION 2.6) -project (core C) - -enable_testing() - -add_subdirectory (../dependencies "${CMAKE_CURRENT_BINARY_DIR}/dependencies") -add_subdirectory (src eressea) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 633509d2d..7591a9f25 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,12 +13,6 @@ set (ERESSEA_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "Eressea Cor add_subdirectory(bindings) -find_package (Lua 5 REQUIRED) -find_package (ToLua REQUIRED) -find_package (LibXml2 REQUIRED) -find_package (Curses REQUIRED) -find_package (SQLite3 REQUIRED) - set (ERESSEA_LIBRARIES ${CUTEST_LIBRARIES} ${CRITBIT_LIBRARIES} From fdd0a3673050ba6f98df2fe6ac93b990a47dff13 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 4 May 2013 14:17:12 -0700 Subject: [PATCH 399/400] moving the find_package calls out into the parent project(s). --- CMakeLists.txt | 7 ------- src/CMakeLists.txt | 10 +++++----- 2 files changed, 5 insertions(+), 12 deletions(-) delete mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index b04b2a5ab..000000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -cmake_minimum_required(VERSION 2.6) -project (core C) - -enable_testing() - -add_subdirectory (../dependencies "${CMAKE_CURRENT_BINARY_DIR}/dependencies") -add_subdirectory (src eressea) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 633509d2d..d35c2bd76 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,11 +13,11 @@ set (ERESSEA_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "Eressea Cor add_subdirectory(bindings) -find_package (Lua 5 REQUIRED) -find_package (ToLua REQUIRED) -find_package (LibXml2 REQUIRED) -find_package (Curses REQUIRED) -find_package (SQLite3 REQUIRED) +#find_package (Lua 5 REQUIRED) +#find_package (ToLua REQUIRED) +#find_package (LibXml2 REQUIRED) +#find_package (Curses REQUIRED) +#find_package (SQLite3 REQUIRED) set (ERESSEA_LIBRARIES ${CUTEST_LIBRARIES} From b0fb81640bbb6f1607546d6db1342253154f4f75 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 4 May 2013 17:28:08 -0700 Subject: [PATCH 400/400] set warning level for this part of eressea especially high --- src/CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7591a9f25..753846329 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,9 +3,6 @@ project (eressea C) IF(CMAKE_COMPILER_IS_GNUCC) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic -Wall -Werror -Wno-unknown-pragmas -Wstrict-prototypes -Wpointer-arith -Wno-char-subscripts -Wno-long-long") - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -DHAVE__BOOL") -ELSE(CMAKE_COMPILER_IS_GNUCC) - MESSAGE(STATUS "Unknown compiler ${CMAKE_C_COMPILER_ID}") ENDIF(CMAKE_COMPILER_IS_GNUCC) set (ERESSEA_LIBRARY ${PROJECT_NAME} CACHE INTERNAL "Eressea Core Library")